[
  {
    "path": ".dockerignore",
    "content": ".dockerignore\n.github\n.gitignore\nDockerfile*\ndocker-compose.yml\nshowdocdata/\n\n.git/\nApplication/Runtime/\nserver/Application/Runtime/\nweb_src/.DS_Store\nweb_src/node_modules/\nweb_src/dist/\nweb_src/npm-debug.log*\nweb_src/yarn-debug.log*\nweb_src/yarn-error.log*\nweb_src//test/unit/coverage/\nweb_src//test/e2e/reports/\nweb_src/selenium-debug.log\n\n# Editor directories and files\nweb_src/.idea\nweb_src/.vscode\nweb_src/*.suo\nweb_src/*.ntvs*\nweb_src/*.njsproj\nweb_src/*.sln\n"
  },
  {
    "path": ".github/workflows/docker-arm.yml",
    "content": "name: ci\n\non:\n  push:\n    branches:\n      - \"master\"\n\njobs:\n  docker:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v3\n      - name: Set up QEMU\n        uses: docker/setup-qemu-action@v2\n      - name: Set up Docker Buildx\n        uses: docker/setup-buildx-action@v2\n      - name: Login to DockerHub\n        uses: docker/login-action@v2\n        with:\n          username: ${{ secrets.DOCKERHUB_USERNAME }}\n          password: ${{ secrets.DOCKERHUB_TOKEN }}\n      - name: Build and push\n        uses: docker/build-push-action@v4\n        with:\n          context: .\n          push: true\n          tags: star7th/showdoc:arm-latest\n          file: Dockerfile.ARM\n          platforms: |\n            linux/arm/v7\n            linux/arm64\n"
  },
  {
    "path": ".github/workflows/docker-release.yml",
    "content": "﻿name: Build and push Docker image\non:\n  release:\n    types: [published]\n\njobs:\n  build-and-push:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v3\n      - name: Set up QEMU\n        uses: docker/setup-qemu-action@v2\n      - name: Set up Docker Buildx\n        uses: docker/setup-buildx-action@v2\n      - name: Login to DockerHub\n        uses: docker/login-action@v2\n        with:\n          username: ${{ secrets.DOCKERHUB_USERNAME }}\n          password: ${{ secrets.DOCKERHUB_TOKEN }}\n      - name: Build and push\n        uses: docker/build-push-action@v4\n        with:\n          context: .\n          push: true\n          tags: star7th/showdoc:${{ github.event.release.tag_name }}\n"
  },
  {
    "path": ".github/workflows/docker.yml",
    "content": "﻿name: ci\n\non:\n  push:\n    branches:\n      - \"master\"\n\njobs:\n  docker:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v3\n      - name: Set up QEMU\n        uses: docker/setup-qemu-action@v2\n      - name: Set up Docker Buildx\n        uses: docker/setup-buildx-action@v2\n      - name: Login to DockerHub\n        uses: docker/login-action@v2\n        with:\n          username: ${{ secrets.DOCKERHUB_USERNAME }}\n          password: ${{ secrets.DOCKERHUB_TOKEN }}\n      - name: Build and push\n        uses: docker/build-push-action@v4\n        with:\n          context: .\n          push: true\n          tags: star7th/showdoc:latest\n"
  },
  {
    "path": ".gitignore",
    "content": "Application/Runtime/\nserver/Application/Runtime/\n\nweb_src/.DS_Store\nweb_src/node_modules/\nweb_src/dist/\nweb_src/npm-debug.log*\nweb_src/yarn-debug.log*\nweb_src/yarn-error.log*\nweb_src//test/unit/coverage/\nweb_src//test/e2e/reports/\nweb_src/selenium-debug.log\n\n# Editor directories and files\nweb_src/.idea\nweb_src/.vscode\nweb_src/*.suo\nweb_src/*.ntvs*\nweb_src/*.njsproj\nweb_src/*.sln\n\nshowdocdata/\n/server/app/Runtime/mcp_rate_limit\n"
  },
  {
    "path": ".htaccess",
    "content": "<IfModule mod_rewrite.c>\n  Options +FollowSymlinks\n  RewriteEngine On\n\n  RewriteCond %{REQUEST_FILENAME} !-d\n  RewriteCond %{REQUEST_FILENAME} !-f\n  RewriteCond $1 !^(index\\.php|robots\\.txt|favicon\\.ico)\n  RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L]\n</IfModule>"
  },
  {
    "path": "Dockerfile",
    "content": "FROM  webdevops/php-nginx:8.3-alpine\n\n## 构建时环境变量 docker build --build-arg=IN_CHINA=true .\nARG IN_CHINA=false\n\n# 环境变量\nENV SHOWDOC_DOCKER_VERSION=3.4.1\nENV IN_CHINA=${IN_CHINA}\n\nWORKDIR /showdoc_data/html\nCOPY . .\n\nRUN bash docker.run.sh --build\n\nCMD [\"bash\", \"docker.run.sh\"]\n"
  },
  {
    "path": "Dockerfile.ARM",
    "content": "FROM wordpress:php8.1\n\nCOPY ./ /var/www/html/\nRUN mkdir -p /showdoc_data/html\nRUN cp -R /var/www/html/ /showdoc_data/\nRUN rm -rf /usr/src/wordpress\nCOPY ./ /usr/src/wordpress\nRUN echo \"<?php echo file_get_contents('index.html'); ?>\" > /var/www/html/web/index.php\nRUN chmod -R 777  /var/www/html/\n\n# 写环境变量\nENV SHOWDOC_DOCKER_VERSION 2.8\nENV SHOWDOC_DOCKER_ARM 1"
  },
  {
    "path": "LICENSE.txt",
    "content": "﻿\nShowDoc遵循Apache2开源协议发布。\nShowDoc在遵循Apache2开源协议之上有一条额外版权声明：\nshowdoc官方(https://www.showdoc.com.cn/)以及作者star7th ( https://github.com/star7th )拥有程序的版权和相应权利，\n在保留程序UI界面上的版权信息和链接的前提下，可免费使用或者二次开发\n如需更改版权信息或版权链接，需取得官方同意授权。\n\nApache Licence是著名的非盈利开源组织Apache采用的协议。\n该协议和BSD类似，鼓励代码共享和尊重原作者的著作权，\n允许代码修改，再作为开源或商业软件发布。需要满足\n的条件： \n1． 需要给代码的用户一份Apache Licence ；\n2． 如果你修改了代码，需要在被修改的文件中说明；\n3． 在延伸的代码中（修改和有源代码衍生的代码中）需要\n带有原来代码中的协议，商标，专利声明和其他原来作者规\n定需要包含的说明；\n4． 如果再发布的产品中包含一个Notice文件，则在Notice文\n件中需要带有本协议内容。你可以在Notice中增加自己的\n许可，但不可以表现为对Apache Licence构成更改。 \n具体的协议参考：http://www.apache.org/licenses/LICENSE-2.0\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\nFOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\nCOPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\nINCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\nBUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\nLIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\nANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE.\n\nShowdoc has an additional copyright notice on compliance with the Apache2 Open Source License:\nShowdoc official（ https://www.showdoc.com.cn/ ）And author star7th（ https://github.com/star7th ）Have the copyright and corresponding rights of the program,\nOn the premise of retaining the copyright information and links on the program UI interface, it can be used for free or secondary development\nIf you need to change copyright information or copyright links, you need to obtain official consent and authorization.\n\n"
  },
  {
    "path": "Public/README.md",
    "content": "﻿资源文件目录"
  },
  {
    "path": "Public/Uploads/index.html",
    "content": " "
  },
  {
    "path": "Public/css/index.css",
    "content": "body {\n  padding-top: 20px;\n  padding-bottom: 40px;\n}\n\n/* Custom container */\n.container-narrow {\n  margin: 0 auto;\n  max-width: 700px;\n}\n.container-narrow > hr {\n  margin: 30px 0;\n}\n\n/* Main marketing message and sign up button */\n.jumbotron {\n  margin: 60px 0;\n  text-align: center;\n}\n.jumbotron h1 {\n  font-size: 72px;\n  line-height: 1;\n}\n.jumbotron .btn {\n  font-size: 21px;\n  padding: 14px 24px;\n}\n\n/* Supporting marketing content */\n.marketing {\n  margin: 60px 0;\n}\n.marketing p + h4 {\n  margin-top: 28px;\n}\n.markdown-body pre {\n  background-color: #f0f0f0;\n}\n"
  },
  {
    "path": "Public/css/item/index.css",
    "content": "body {\n  padding-top: 20px;\n  padding-bottom: 40px;\n}\n\n/* Custom container */\n.container-narrow {\n  margin: 0 auto;\n  max-width: 700px;\n}\n.container-narrow > hr {\n  margin: 30px 0;\n}\n.my-item{\n  margin: 40px 10px;\n}\n\n.container-thumbnails{\nmargin-top: 60px;\n}\n.thumbnails li a{\n\tcolor: #777;\n\tfont-weight: bold;\n\theight: 100px;\n}\n.thumbnails li a:hover,\n.thumbnails li a:focus{\n\tborder-color:#f2f5e9;\n\t-webkit-box-shadow:none;\n\tbox-shadow:none;\n\ttext-decoration: none;\n\tbackground-color: #f2f5e9;\n}\n\n.masthead h3{\n  color: #333;\n}\n\n.item-setting{\n  float:right;\n  margin-right:15px;\n  margin-top:5px;\n  display: none;\n}\n\n.item-top{\n  float:right;\n  margin-right:5px;\n  margin-top:5px;\n  display: none;\n}\n"
  },
  {
    "path": "Public/css/item/show.css",
    "content": "  body,html,.doc-body{\n    height: 100%;\n  }\n  .doc-head{\n    padding-top: 5px;\n    padding-bottom: 5px;\n    padding-left: 10px;\n    border-bottom: 1px solid #eee;\n    position: fixed;\n    width: 100%;\n    background-color: #FFFFFF;\n    z-index: 999;\n    height: 40px;\n  }\n\n  .doc-head .left{\n    padding-left: 30px;\n    float: left;\n  }\n\n  .doc-head .right{\n    padding-top: 10px;\n    padding-right: 40px;\n  }\n  .doc-left{\n    width: 240px;\n    margin-top: 51px;\n    height: calc(100% - 60px);\n    border-right-color: rgb(221, 221, 221);\n    border-right-width: 1px;\n    border-right-style: solid;\n    overflow-y: auto;\n    display: block;\n    /*background: rgb(245, 245, 245);*/\n    position: fixed;\n  }\n  \n  .doc-left .form-search{\n    padding-top: 15px;\n  }\n\n  .doc-left ul li{\n    font-size: 16px;\n    line-height: 30px;\n  }\n  .doc-left ul li a{\n    color: #000;\n  }\n  .doc-left ul li a:hover ,.doc-left ul li a:focus{\n    color: #fff;\n    text-shadow: 0 -1px 0 rgba(0,0,0,0.2);\n    background-color: #08c;\n  }\n  .doc-right{\n    margin-top: 81px;\n    margin-left: 260px;\n  }\n  .child-ul{\n      list-style: none;\n      padding-left: 10px;\n  }\n  .child-ul li a {\n    padding: 3px 15px;\n    margin-right: -15px;\n    margin-left: -15px;\n    text-shadow: 0 1px 0 rgba(255,255,255,0.5);\n    display: block;\n    text-decoration: none;\n    font-size: 14px;\n    line-height: 25px;\n  }\n\n  .icon-blank{\n    padding-right: 4px;\n  }\n\n  .doc-left-newbar{\n    /*float: right;*/\n    margin-left: 180px;\n    margin-top: 10px;\n  }\n\n  .page-edit-link{\n    padding-top: 10px;\n  }\n  .iframe_content{\n    padding-left: 20px;\n    padding-right: 20px;\n    width: 80%;\n    max-width: 700px;\n    margin: 0 auto;\n  }\n\n  .search-query-input{\n    width: 140px;\n  }\n.third-child-catalog{\n  margin-left: -16px;\n}\n\n@media screen and (min-width:500px){\n  .doc-right{ width: 400px;} \n}\n\n@media screen and (min-width:600px){\n  .doc-right{ width: 500px;} \n}\n\n@media screen and (min-width:700px){\n  .doc-right{ width: 600px;} \n}\n\n@media screen and (min-width:800px){\n  .doc-right{ width: 700px;} \n}\n\n@media screen and (min-width:900px){\n  .doc-right{ width: 800px;} \n}\n\n@media screen and (min-width:1000px){\n  .doc-right{ width: 700px;} \n}\n\n@media screen and (min-width:1100px){\n  .doc-right{ width: 800px;} \n}\n\n@media screen and (min-width:1200px){\n  .doc-right{ width: 900px;} \n}\n@media screen and (min-width:1300px){\n  .doc-right{ width: 1000px;} \n}\n@media screen and (min-width:1400px){\n  .doc-right{ width: 1100px;} \n}\n@media screen and (min-width:1500px){\n  .doc-right{ width: 1200px;} \n}\n@media screen and (min-width:1600px){\n  .doc-right{ width: 1300px;} \n}\n@media screen and (min-width:1700px){\n  .doc-right{ width: 1400px;} \n}\n@media screen and (min-width:1800px){\n  .doc-right{ width: 1500px;} \n}\n@media screen and (min-width:1900px){\n  .doc-right{ width: 1600px;} \n}\n\n.page-edit-link .btn-link{\n  padding-right: 4px;\n  padding-left: 4px;\n  margin-right: 0px;\n  margin-left: 0px;\n}\n\n.show_cut_title{\n  white-space:nowrap;\n  text-overflow:ellipsis; \n  -o-text-overflow:ellipsis; \n  overflow:hidden\n}\n\n.left-dropdown-menu{\n  left: auto;\n   right: 0;\n}\n"
  },
  {
    "path": "Public/css/item/show_single_page.css",
    "content": "body{\n    background: #F1F0F1;\n    height: auto;\n    overflow: auto;\n    margin: 0 auto;\n}\n\n#page_content{\n  \n    padding: 11px 0 90px 0;\n    overflow: hidden;\n    font-size: 11pt;\n    line-height: 1.7;\n    color: #333;\n}\n#doc-body{\n  background-color: #fff;\n}\n\n.doc-container {\n    position: static;\n    -webkit-box-shadow: 0px 1px 6px #ccc;\n    -moz-box-shadow: 0px 1px 6px #ccc;\n    -ms-box-shadow: 0px 1px 6px #ccc;\n    -o-box-shadow: 0px 1px 6px #ccc;\n    box-shadow: 0px 1px 6px #ccc;\n    background-color: #fff;\n    border-bottom: 1px solid #d9d9d9;\n    margin-bottom: 20px;\n    width: 800px;\n    min-height: 500px;\n\n}\n\n#header{\n  height: 80px;\n}\n\n#doc-body{\n  width: 600px;\n  margin: 0 auto;\n}\n\n.doc-title-box{\n    height: auto;\n    margin: 30px 100px 10px 100px;\n    width: auto;\n    border-bottom: 1px solid #ebebeb;\n    padding-bottom: 10px;\n}\n#footer{\n    margin: 0 auto;\n    width: 180px;\n    font-size: 8px;\n    color: #959595;\n}\n\n#doc-title{\n  display: inline-block;\n}\n\n.tool-bar{\n  font-size: 14px;\n  padding-top: 15px;\n}\n\n.tool-bar .btn-link{\n  padding: 0px;\n}\n.linenums li {\n    list-style-type: none;\n    line-height: 20px;\n}\n\n.markdown-body pre {\n    background-color: #fcfcfc;\n    border: 1px solid #e1e1e8;\n}\n\n.hljs{\n  padding:0.2em;\n  background-color: #fcfcfc;\n}\n"
  },
  {
    "path": "Public/css/jquery.fullPage.css",
    "content": "/**\n * fullPage 2.4.6\n * https://github.com/alvarotrigo/fullPage.js\n * MIT licensed\n *\n * Copyright (C) 2013 alvarotrigo.com - A project by Alvaro Trigo\n */\nhtml, body {\n    margin: 0;\n    padding: 0;\n    overflow:hidden;\n\n    /*Avoid flicker on slides transitions for mobile phones #336 */\n    -webkit-tap-highlight-color: rgba(0,0,0,0);\n}\n#superContainer {\n    height: 100%;\n    position: relative;\n\n    /* Touch detection for Windows 8 */\n    -ms-touch-action: none;\n\n    /* IE 11 on Windows Phone 8.1*/\n    touch-action: none;\n}\n.fp-section {\n    position: relative;\n    -webkit-box-sizing: border-box; /* Safari<=5 Android<=3 */\n    -moz-box-sizing: border-box; /* <=28 */\n    box-sizing: border-box;\n}\n.fp-slide {\n    float: left;\n}\n.fp-slide, .fp-slidesContainer {\n    height: 100%;\n    display: block;\n}\n.fp-slides {\n    z-index:1;\n    height: 100%;\n    overflow: hidden;\n    position: relative;\n    -webkit-transition: all 0.3s ease-out; /* Safari<=6 Android<=4.3 */\n    transition: all 0.3s ease-out;\n}\n.fp-section.fp-table, .fp-slide.fp-table {\n    display: table;\n    table-layout:fixed;\n    width: 100%;\n}\n.fp-tableCell {\n    display: table-cell;\n    vertical-align: middle;\n    width: 100%;\n    height: 100%;\n}\n.fp-slidesContainer {\n    float: left;\n    position: relative;\n}\n.fp-controlArrow {\n    position: absolute;\n    z-index: 4;\n    top: 50%;\n    cursor: pointer;\n    width: 0;\n    height: 0;\n    border-style: solid;\n    margin-top: -38px;\n}\n.fp-controlArrow.fp-prev {\n    left: 15px;\n    width: 0;\n    border-width: 38.5px 34px 38.5px 0;\n    border-color: transparent #fff transparent transparent;\n}\n.fp-controlArrow.fp-next {\n    right: 15px;\n    border-width: 38.5px 0 38.5px 34px;\n    border-color: transparent transparent transparent #fff;\n}\n.fp-scrollable {\n    overflow: scroll;\n\n}\n.fp-notransition {\n    -webkit-transition: none !important;\n    transition: none !important;\n}\n#fp-nav {\n    position: fixed;\n    z-index: 100;\n    margin-top: -32px;\n    top: 50%;\n    opacity: 1;\n}\n#fp-nav.right {\n    right: 17px;\n}\n#fp-nav.left {\n    left: 17px;\n}\n.fp-slidesNav{\n    position: absolute;\n    z-index: 4;\n    left: 50%;\n    opacity: 1;\n}\n.fp-slidesNav.bottom {\n    bottom: 17px;\n}\n.fp-slidesNav.top {\n    top: 17px;\n}\n#fp-nav ul,\n.fp-slidesNav ul {\n  margin: 0;\n  padding: 0;\n}\n#fp-nav ul li,\n.fp-slidesNav ul li {\n    display: block;\n    width: 14px;\n    height: 13px;\n    margin: 7px;\n    position:relative;\n}\n.fp-slidesNav ul li {\n    display: inline-block;\n}\n#fp-nav ul li a,\n.fp-slidesNav ul li a {\n    display: block;\n    position: relative;\n    z-index: 1;\n    width: 100%;\n    height: 100%;\n    cursor: pointer;\n    text-decoration: none;\n}\n#fp-nav ul li a.active span,\n.fp-slidesNav ul li a.active span {\n    background: #333;\n}\n#fp-nav ul li a span,\n.fp-slidesNav ul li a span {\n    top: 2px;\n    left: 2px;\n    width: 8px;\n    height: 8px;\n    border: 1px solid #000;\n    background: rgba(0, 0, 0, 0);\n    border-radius: 50%;\n    position: absolute;\n    z-index: 1;\n}\n#fp-nav ul li .fp-tooltip {\n    position: absolute;\n    top: -2px;\n    color: #fff;\n    font-size: 14px;\n    font-family: arial, helvetica, sans-serif;\n    white-space: nowrap;\n    max-width: 220px;\n    overflow: hidden;\n    display: block;\n    opacity: 0;\n    width: 0;\n}\n#fp-nav ul li:hover .fp-tooltip {\n    -webkit-transition: opacity 0.2s ease-in;\n    transition: opacity 0.2s ease-in;\n    width: auto;\n    opacity: 1;\n}\n#fp-nav ul li .fp-tooltip.right {\n    right: 20px;\n}\n#fp-nav ul li .fp-tooltip.left {\n    left: 20px;\n}\n"
  },
  {
    "path": "Public/css/login.css",
    "content": "body {\n  padding-top: 40px;\n  padding-bottom: 40px;\n  background-color: #f5f5f5;\n}\n\n.form-signin {\n  max-width: 300px;\n  padding: 19px 29px 29px;\n  margin: 0 auto 20px;\n  background-color: #fff;\n  border: 1px solid #e5e5e5;\n  -webkit-border-radius: 5px;\n     -moz-border-radius: 5px;\n          border-radius: 5px;\n  -webkit-box-shadow: 0 1px 2px rgba(0,0,0,.05);\n     -moz-box-shadow: 0 1px 2px rgba(0,0,0,.05);\n          box-shadow: 0 1px 2px rgba(0,0,0,.05);\n}\n.form-signin .form-signin-heading,\n.form-signin .checkbox {\n  margin-bottom: 10px;\n}\n.form-signin input[type=\"text\"],\n.form-signin input[type=\"password\"] {\n  font-size: 16px;\n  height: auto;\n  margin-bottom: 15px;\n  padding: 7px 9px;\n}\n\n.container{\n  margin-top: 5%;\n}\n\n.card{\n    width: 330px;\n    position  : absolute;\n    top       : 50%;\n    left      : 50%;\n    transform : translate(-50%,-50%);\n    padding-top: 30px;\n    padding-left: 45px;\n    padding-right: 45px;\n    padding-bottom: 30px;\n    background-color: #fff;\n    box-sizing: border-box;\n}\n\n.heading{\n    text-align: center;\n    padding-bottom: 20px"
  },
  {
    "path": "Public/css/page/edit.css",
    "content": "﻿* {\n\n\n\n    padding: 0;\n\n\n\n    margin: 0;\n\n\n\n}\n\n\n\n\n\n\n\n*, *:before, *:after {\n\n\n\n    -webkit-box-sizing: border-box;\n\n\n\n    -moz-box-sizing: border-box;\n\n\n\n    box-sizing: border-box;\n\n\n\n}\n\n\n\n\t\tbody,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,textarea,p,blockquote,th,td,hr,button,article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{\n\n\n\n    margin: 0;\n\n\n\n    padding: 0;\n\n\n\n}\n\n\n\n\n\n\n\narticle, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section, summary {\n\n\n\n    display: block;\n\n\n\n}\n\n\n\n\n\n\n\naudio, canvas, video {\n\n\n\n    display: inline-block;\n\n\n\n}\n\n\n\n\n\n\n\nimg {\n\n\n\n    border: none;\n\n\n\n    vertical-align: middle;\n\n\n\n}\n\n\n\n\n\n\n\nul, ol {\n\n\n\n    /*list-style: none;*/\n\n\n\n}\n\n\n\n\n\n\n\n.clear {\n\n\n\n    *zoom: 1;           /* for IE 6/7 */\n\n\n\n}\n\n\n\n\n\n\n\n.clear:before, .clear:after {\n\n\n\n    height: 0; \n\n\n\n    content: \"\";\n\n\n\n    font-size: 0;\n\n\n\n    display: table;\n\n\n\n    line-height: 0;     /* for Opera */\n\n\n\n    visibility: hidden;\n\n\n\n}\n\n\n\n\n\n\n\n.clear:after {\n\n\n\n    clear: both;\n\n\n\n}\n\n\n\n\n\n\n\nbody {\n\n\n\n    font-size: 14px;\n\n\n\n    color: #666;\n\n\n\n    font-family: \"Microsoft YaHei\", \"微软雅黑\", Helvetica, Tahoma, STXihei, \"华文细黑\", STHeiti, \"Helvetica Neue\", Helvetica, Tahoma, \"Droid Sans\", \"wenquanyi micro hei\", FreeSans, Arimo, Arial, SimSun, \"宋体\", Heiti, \"黑体\", sans-serif; \n\n\n\n    background: #fff;\n\n\n\n    text-align: center;\n\n\n\n}\n\n\n\n\n\n\n\n#layout {\n\n\n\n    text-align: left;\n\n\n\n}\n\n\n\n\n\n\n\n#layout > header, .btns {\n\n\n\n    padding: 15px 0;\n\n\n\n    width: 90%;\n\n\n\n    margin: 0 auto;\n\n\n\n}\n\n\n\n\n\n\n\n.btns {\n\n\n\n    padding-top: 0;\n\n\n\n}\n\n\n\n\n\n\n\n.btns button {\n\n\n\n    padding: 2px 8px;\n\n\n\n}\n\n\n\n\n\n\n\n#layout > header > h1 {\n\n\n\n    font-size: 20px;\n\n\n\n    margin-bottom: 10px;\n\n\n\n}\n\n\n\n\n\n\n\n.btns button, .btn {\n\n\n\n    padding: 8px 10px;\n\n\n\n    background: #fff;\n\n\n\n    border: 1px solid #ddd;\n\n\n\n    -webkit-border-radius: 3px;\n\n\n\n    border-radius: 3px;\n\n\n\n    cursor: pointer;\n\n\n\n    -webkit-transition: background 300ms ease-out;\n\n\n\n    transition: background 300ms ease-out;\n\n\n\n}\n\n\n\n\n\n\n\n.btns button:hover, .btn:hover {\n\n\n\n    background: #f6f6f6;\n\n\n\n}\n\n\n\n\n\n\n\n#json-templ,#beautify-json-dialog{ position:fixed; float:left; top:100px; left:300px; border:2px solid #ccc; display:none; z-index:999999;}\n\n\n\n\n\n\n\n.markdown-body.editormd-preview-container table tr td{ max-width:300px;}\n\n\n\n\n\n\n\n.btn-primary {\n\n\n\n    background-color: #006dcc;\n\n\n\n}\n\n\n\n\n\n\n\n.btn-primary:hover {\n\n\n\n    background-color: #04c;\n\n\n\n}\n\n\n\n\n\n\n\n#page_title,\n\n\n\n#cat_id,\n\n\n\n#order {\n\n\n\n    height: 30px;\n\n\n\n}\n\n\n\n\n\n\n\n#cat_id ,#parent_cat_id {\n\n\n\n    width: 120px;\n\n\n\n}\n\n\n\n\n\n\n\n#s_number {\n\n\n\n    width: 120px;\n\n\n\n    margin-right: 20px;\n\n\n\n    height: 28px;\n\n\n\n}\n\nol.linenums li {\n    list-style-type: none !important;\n}\n\n\n"
  },
  {
    "path": "Public/css/page/index.css",
    "content": "\nh3{\n\tfont-size: 1.5em;\n}\n\nbody{\n\toverflow-x:hidden;overflow-y:hidden;\n\tfont-size: 1rem;\n\tline-height: 1.7em;\n}\n\np{\n\tmargin: 0 0 20px;\n}\n\nli{\n\tline-height: 30px;\n}\n\n.linenums li{\n\tlist-style-type:none;\n\tline-height: 20px;\n}\n\n#page_md_content{\n\tpadding-top:10px;\n\tword-break: break-all;\n}\n\n.hljs{\n\tpadding:0.2em;\n\tbackground-color: #fcfcfc;\n}\n\n\n#page_title{\n    text-align: left;\n    border-bottom: 1px solid #d9d9d9;\n    padding-top: 30px;\n    padding-bottom: 20px\n}\n\n.markdown-body pre {\n\tbackground-color: #fcfcfc;\n\tborder: 1px solid #e1e1e8;\n}"
  },
  {
    "path": "Public/css/showdoc.css",
    "content": "\n@charset \"utf-8\";\n  body {\n    font:14px/1.5 \"Microsoft Yahei\",\"微软雅黑\",Tahoma,Arial,Helvetica,STHeiti;\n}\n\n.btn-primary{\n    background-color: #08c !important;\n    background-image: linear-gradient(to bottom,#08c,#08c);\n}\n.btn-primary:active{\n  background-color: #07c !important;\n}\n.btn-primary:hover{\n  background-color: #07c !important;\n  background-image: linear-gradient(to bottom,#07c,#07c);\n}\n\n/*定义滚动条高宽及背景 高宽分别对应横竖滚动条的尺寸*/\n::-webkit-scrollbar\n{\n    width: 7px;\n    height: 10px;\n    background-color: rgba(0, 0, 0, 0.1);\n}\n/*定义滑块 内阴影+圆角*/\n::-webkit-scrollbar-thumb\n{\n    background-color: rgba(0, 0, 0, 0.3);\n    -webkit-border-radius:6px;\n    -moz-border-radius: 6px;\n    -ms-border-radius: 6px;\n    -o-border-radius: 6px;\n    border-radius: 6px;\n}"
  },
  {
    "path": "Public/css/tab-tpl.css",
    "content": "body{\n    background: #F1F0F1;\n    height: auto;\n    overflow: auto;\n    margin: 0 auto;\n}\n\n.tab-doc-content{\n  \n    padding: 11px 0 90px 0;\n    overflow: hidden;\n    font-size: 11pt;\n    line-height: 1.7;\n    color: #333;\n}\n.tab-doc-body{\n  background-color: #fff;\n  width: 600px;\n  margin: 0 auto;\n}\n\n.tab-doc-container {\n    position: static;\n    -webkit-box-shadow: 0px 1px 6px #ccc;\n    -moz-box-shadow: 0px 1px 6px #ccc;\n    -ms-box-shadow: 0px 1px 6px #ccc;\n    -o-box-shadow: 0px 1px 6px #ccc;\n    box-shadow: 0px 1px 6px #ccc;\n    background-color: #fff;\n    border-bottom: 1px solid #d9d9d9;\n    margin-bottom: 20px;\n    width: 800px;\n    min-height: 500px;\n}\n\n.tab-header{\n  height: 40px;\n}\n\n.tab-doc-title-box{\n    height: auto;\n    margin: 30px 100px 10px 100px;\n    width: auto;\n    /*border-bottom: 1px solid #ebebeb;*/\n    padding-bottom: 10px;\n}"
  },
  {
    "path": "Public/diff/difflib.js",
    "content": "/***\nThis is part of jsdifflib v1.0. <http://snowtide.com/jsdifflib>\n\nCopyright (c) 2007, Snowtide Informatics Systems, Inc.\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without modification,\nare permitted provided that the following conditions are met:\n\n\t* Redistributions of source code must retain the above copyright notice, this\n\t\tlist of conditions and the following disclaimer.\n\t* Redistributions in binary form must reproduce the above copyright notice,\n\t\tthis list of conditions and the following disclaimer in the documentation\n\t\tand/or other materials provided with the distribution.\n\t* Neither the name of the Snowtide Informatics Systems nor the names of its\n\t\tcontributors may be used to endorse or promote products derived from this\n\t\tsoftware without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY\nEXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\nOF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\nSHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\nINCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\nTO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR\nBUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\nCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\nANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH\nDAMAGE.\n***/\n/* Author: Chas Emerick <cemerick@snowtide.com> */\n__whitespace = {\" \":true, \"\\t\":true, \"\\n\":true, \"\\f\":true, \"\\r\":true};\n\ndifflib = {\n\tdefaultJunkFunction: function (c) {\n\t\treturn __whitespace.hasOwnProperty(c);\n\t},\n\t\n\tstripLinebreaks: function (str) { return str.replace(/^[\\n\\r]*|[\\n\\r]*$/g, \"\"); },\n\t\n\tstringAsLines: function (str) {\n\t\tvar lfpos = str.indexOf(\"\\n\");\n\t\tvar crpos = str.indexOf(\"\\r\");\n\t\tvar linebreak = ((lfpos > -1 && crpos > -1) || crpos < 0) ? \"\\n\" : \"\\r\";\n\t\t\n\t\tvar lines = str.split(linebreak);\n\t\tfor (var i = 0; i < lines.length; i++) {\n\t\t\tlines[i] = difflib.stripLinebreaks(lines[i]);\n\t\t}\n\t\t\n\t\treturn lines;\n\t},\n\t\n\t// iteration-based reduce implementation\n\t__reduce: function (func, list, initial) {\n\t\tif (initial != null) {\n\t\t\tvar value = initial;\n\t\t\tvar idx = 0;\n\t\t} else if (list) {\n\t\t\tvar value = list[0];\n\t\t\tvar idx = 1;\n\t\t} else {\n\t\t\treturn null;\n\t\t}\n\t\t\n\t\tfor (; idx < list.length; idx++) {\n\t\t\tvalue = func(value, list[idx]);\n\t\t}\n\t\t\n\t\treturn value;\n\t},\n\t\n\t// comparison function for sorting lists of numeric tuples\n\t__ntuplecomp: function (a, b) {\n\t\tvar mlen = Math.max(a.length, b.length);\n\t\tfor (var i = 0; i < mlen; i++) {\n\t\t\tif (a[i] < b[i]) return -1;\n\t\t\tif (a[i] > b[i]) return 1;\n\t\t}\n\t\t\n\t\treturn a.length == b.length ? 0 : (a.length < b.length ? -1 : 1);\n\t},\n\t\n\t__calculate_ratio: function (matches, length) {\n\t\treturn length ? 2.0 * matches / length : 1.0;\n\t},\n\t\n\t// returns a function that returns true if a key passed to the returned function\n\t// is in the dict (js object) provided to this function; replaces being able to\n\t// carry around dict.has_key in python...\n\t__isindict: function (dict) {\n\t\treturn function (key) { return dict.hasOwnProperty(key); };\n\t},\n\t\n\t// replacement for python's dict.get function -- need easy default values\n\t__dictget: function (dict, key, defaultValue) {\n\t\treturn dict.hasOwnProperty(key) ? dict[key] : defaultValue;\n\t},\t\n\t\n\tSequenceMatcher: function (a, b, isjunk) {\n\t\tthis.set_seqs = function (a, b) {\n\t\t\tthis.set_seq1(a);\n\t\t\tthis.set_seq2(b);\n\t\t}\n\t\t\n\t\tthis.set_seq1 = function (a) {\n\t\t\tif (a == this.a) return;\n\t\t\tthis.a = a;\n\t\t\tthis.matching_blocks = this.opcodes = null;\n\t\t}\n\t\t\n\t\tthis.set_seq2 = function (b) {\n\t\t\tif (b == this.b) return;\n\t\t\tthis.b = b;\n\t\t\tthis.matching_blocks = this.opcodes = this.fullbcount = null;\n\t\t\tthis.__chain_b();\n\t\t}\n\t\t\n\t\tthis.__chain_b = function () {\n\t\t\tvar b = this.b;\n\t\t\tvar n = b.length;\n\t\t\tvar b2j = this.b2j = {};\n\t\t\tvar populardict = {};\n\t\t\tfor (var i = 0; i < b.length; i++) {\n\t\t\t\tvar elt = b[i];\n\t\t\t\tif (b2j.hasOwnProperty(elt)) {\n\t\t\t\t\tvar indices = b2j[elt];\n\t\t\t\t\tif (n >= 200 && indices.length * 100 > n) {\n\t\t\t\t\t\tpopulardict[elt] = 1;\n\t\t\t\t\t\tdelete b2j[elt];\n\t\t\t\t\t} else {\n\t\t\t\t\t\tindices.push(i);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tb2j[elt] = [i];\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tfor (var elt in populardict) {\n\t\t\t\tif (populardict.hasOwnProperty(elt)) {\n\t\t\t\t\tdelete b2j[elt];\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tvar isjunk = this.isjunk;\n\t\t\tvar junkdict = {};\n\t\t\tif (isjunk) {\n\t\t\t\tfor (var elt in populardict) {\n\t\t\t\t\tif (populardict.hasOwnProperty(elt) && isjunk(elt)) {\n\t\t\t\t\t\tjunkdict[elt] = 1;\n\t\t\t\t\t\tdelete populardict[elt];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfor (var elt in b2j) {\n\t\t\t\t\tif (b2j.hasOwnProperty(elt) && isjunk(elt)) {\n\t\t\t\t\t\tjunkdict[elt] = 1;\n\t\t\t\t\t\tdelete b2j[elt];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tthis.isbjunk = difflib.__isindict(junkdict);\n\t\t\tthis.isbpopular = difflib.__isindict(populardict);\n\t\t}\n\t\t\n\t\tthis.find_longest_match = function (alo, ahi, blo, bhi) {\n\t\t\tvar a = this.a;\n\t\t\tvar b = this.b;\n\t\t\tvar b2j = this.b2j;\n\t\t\tvar isbjunk = this.isbjunk;\n\t\t\tvar besti = alo;\n\t\t\tvar bestj = blo;\n\t\t\tvar bestsize = 0;\n\t\t\tvar j = null;\n\t\n\t\t\tvar j2len = {};\n\t\t\tvar nothing = [];\n\t\t\tfor (var i = alo; i < ahi; i++) {\n\t\t\t\tvar newj2len = {};\n\t\t\t\tvar jdict = difflib.__dictget(b2j, a[i], nothing);\n\t\t\t\tfor (var jkey in jdict) {\n\t\t\t\t\tif (jdict.hasOwnProperty(jkey)) {\n\t\t\t\t\t\tj = jdict[jkey];\n\t\t\t\t\t\tif (j < blo) continue;\n\t\t\t\t\t\tif (j >= bhi) break;\n\t\t\t\t\t\tnewj2len[j] = k = difflib.__dictget(j2len, j - 1, 0) + 1;\n\t\t\t\t\t\tif (k > bestsize) {\n\t\t\t\t\t\t\tbesti = i - k + 1;\n\t\t\t\t\t\t\tbestj = j - k + 1;\n\t\t\t\t\t\t\tbestsize = k;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tj2len = newj2len;\n\t\t\t}\n\t\n\t\t\twhile (besti > alo && bestj > blo && !isbjunk(b[bestj - 1]) && a[besti - 1] == b[bestj - 1]) {\n\t\t\t\tbesti--;\n\t\t\t\tbestj--;\n\t\t\t\tbestsize++;\n\t\t\t}\n\t\t\t\t\n\t\t\twhile (besti + bestsize < ahi && bestj + bestsize < bhi &&\n\t\t\t\t\t!isbjunk(b[bestj + bestsize]) &&\n\t\t\t\t\ta[besti + bestsize] == b[bestj + bestsize]) {\n\t\t\t\tbestsize++;\n\t\t\t}\n\t\n\t\t\twhile (besti > alo && bestj > blo && isbjunk(b[bestj - 1]) && a[besti - 1] == b[bestj - 1]) {\n\t\t\t\tbesti--;\n\t\t\t\tbestj--;\n\t\t\t\tbestsize++;\n\t\t\t}\n\t\t\t\n\t\t\twhile (besti + bestsize < ahi && bestj + bestsize < bhi && isbjunk(b[bestj + bestsize]) &&\n\t\t\t\t\ta[besti + bestsize] == b[bestj + bestsize]) {\n\t\t\t\tbestsize++;\n\t\t\t}\n\t\n\t\t\treturn [besti, bestj, bestsize];\n\t\t}\n\t\t\n\t\tthis.get_matching_blocks = function () {\n\t\t\tif (this.matching_blocks != null) return this.matching_blocks;\n\t\t\tvar la = this.a.length;\n\t\t\tvar lb = this.b.length;\n\t\n\t\t\tvar queue = [[0, la, 0, lb]];\n\t\t\tvar matching_blocks = [];\n\t\t\tvar alo, ahi, blo, bhi, qi, i, j, k, x;\n\t\t\twhile (queue.length) {\n\t\t\t\tqi = queue.pop();\n\t\t\t\talo = qi[0];\n\t\t\t\tahi = qi[1];\n\t\t\t\tblo = qi[2];\n\t\t\t\tbhi = qi[3];\n\t\t\t\tx = this.find_longest_match(alo, ahi, blo, bhi);\n\t\t\t\ti = x[0];\n\t\t\t\tj = x[1];\n\t\t\t\tk = x[2];\n\t\n\t\t\t\tif (k) {\n\t\t\t\t\tmatching_blocks.push(x);\n\t\t\t\t\tif (alo < i && blo < j)\n\t\t\t\t\t\tqueue.push([alo, i, blo, j]);\n\t\t\t\t\tif (i+k < ahi && j+k < bhi)\n\t\t\t\t\t\tqueue.push([i + k, ahi, j + k, bhi]);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tmatching_blocks.sort(difflib.__ntuplecomp);\n\t\n\t\t\tvar i1 = j1 = k1 = block = 0;\n\t\t\tvar non_adjacent = [];\n\t\t\tfor (var idx in matching_blocks) {\n\t\t\t\tif (matching_blocks.hasOwnProperty(idx)) {\n\t\t\t\t\tblock = matching_blocks[idx];\n\t\t\t\t\ti2 = block[0];\n\t\t\t\t\tj2 = block[1];\n\t\t\t\t\tk2 = block[2];\n\t\t\t\t\tif (i1 + k1 == i2 && j1 + k1 == j2) {\n\t\t\t\t\t\tk1 += k2;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif (k1) non_adjacent.push([i1, j1, k1]);\n\t\t\t\t\t\ti1 = i2;\n\t\t\t\t\t\tj1 = j2;\n\t\t\t\t\t\tk1 = k2;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (k1) non_adjacent.push([i1, j1, k1]);\n\t\n\t\t\tnon_adjacent.push([la, lb, 0]);\n\t\t\tthis.matching_blocks = non_adjacent;\n\t\t\treturn this.matching_blocks;\n\t\t}\n\t\t\n\t\tthis.get_opcodes = function () {\n\t\t\tif (this.opcodes != null) return this.opcodes;\n\t\t\tvar i = 0;\n\t\t\tvar j = 0;\n\t\t\tvar answer = [];\n\t\t\tthis.opcodes = answer;\n\t\t\tvar block, ai, bj, size, tag;\n\t\t\tvar blocks = this.get_matching_blocks();\n\t\t\tfor (var idx in blocks) {\n\t\t\t\tif (blocks.hasOwnProperty(idx)) {\n\t\t\t\t\tblock = blocks[idx];\n\t\t\t\t\tai = block[0];\n\t\t\t\t\tbj = block[1];\n\t\t\t\t\tsize = block[2];\n\t\t\t\t\ttag = '';\n\t\t\t\t\tif (i < ai && j < bj) {\n\t\t\t\t\t\ttag = 'replace';\n\t\t\t\t\t} else if (i < ai) {\n\t\t\t\t\t\ttag = 'delete';\n\t\t\t\t\t} else if (j < bj) {\n\t\t\t\t\t\ttag = 'insert';\n\t\t\t\t\t}\n\t\t\t\t\tif (tag) answer.push([tag, i, ai, j, bj]);\n\t\t\t\t\ti = ai + size;\n\t\t\t\t\tj = bj + size;\n\t\t\t\t\t\n\t\t\t\t\tif (size) answer.push(['equal', ai, i, bj, j]);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn answer;\n\t\t}\n\t\t\n\t\t// this is a generator function in the python lib, which of course is not supported in javascript\n\t\t// the reimplementation builds up the grouped opcodes into a list in their entirety and returns that.\n\t\tthis.get_grouped_opcodes = function (n) {\n\t\t\tif (!n) n = 3;\n\t\t\tvar codes = this.get_opcodes();\n\t\t\tif (!codes) codes = [[\"equal\", 0, 1, 0, 1]];\n\t\t\tvar code, tag, i1, i2, j1, j2;\n\t\t\tif (codes[0][0] == 'equal') {\n\t\t\t\tcode = codes[0];\n\t\t\t\ttag = code[0];\n\t\t\t\ti1 = code[1];\n\t\t\t\ti2 = code[2];\n\t\t\t\tj1 = code[3];\n\t\t\t\tj2 = code[4];\n\t\t\t\tcodes[0] = [tag, Math.max(i1, i2 - n), i2, Math.max(j1, j2 - n), j2];\n\t\t\t}\n\t\t\tif (codes[codes.length - 1][0] == 'equal') {\n\t\t\t\tcode = codes[codes.length - 1];\n\t\t\t\ttag = code[0];\n\t\t\t\ti1 = code[1];\n\t\t\t\ti2 = code[2];\n\t\t\t\tj1 = code[3];\n\t\t\t\tj2 = code[4];\n\t\t\t\tcodes[codes.length - 1] = [tag, i1, Math.min(i2, i1 + n), j1, Math.min(j2, j1 + n)];\n\t\t\t}\n\t\n\t\t\tvar nn = n + n;\n\t\t\tvar group = [];\n\t\t\tvar groups = [];\n\t\t\tfor (var idx in codes) {\n\t\t\t\tif (codes.hasOwnProperty(idx)) {\n\t\t\t\t\tcode = codes[idx];\n\t\t\t\t\ttag = code[0];\n\t\t\t\t\ti1 = code[1];\n\t\t\t\t\ti2 = code[2];\n\t\t\t\t\tj1 = code[3];\n\t\t\t\t\tj2 = code[4];\n\t\t\t\t\tif (tag == 'equal' && i2 - i1 > nn) {\n\t\t\t\t\t\tgroup.push([tag, i1, Math.min(i2, i1 + n), j1, Math.min(j2, j1 + n)]);\n\t\t\t\t\t\tgroups.push(group);\n\t\t\t\t\t\tgroup = [];\n\t\t\t\t\t\ti1 = Math.max(i1, i2-n);\n\t\t\t\t\t\tj1 = Math.max(j1, j2-n);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tgroup.push([tag, i1, i2, j1, j2]);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (group && !(group.length == 1 && group[0][0] == 'equal')) groups.push(group)\n\t\t\t\n\t\t\treturn groups;\n\t\t}\n\t\t\n\t\tthis.ratio = function () {\n\t\t\tmatches = difflib.__reduce(\n\t\t\t\t\t\t\tfunction (sum, triple) { return sum + triple[triple.length - 1]; },\n\t\t\t\t\t\t\tthis.get_matching_blocks(), 0);\n\t\t\treturn difflib.__calculate_ratio(matches, this.a.length + this.b.length);\n\t\t}\n\t\t\n\t\tthis.quick_ratio = function () {\n\t\t\tvar fullbcount, elt;\n\t\t\tif (this.fullbcount == null) {\n\t\t\t\tthis.fullbcount = fullbcount = {};\n\t\t\t\tfor (var i = 0; i < this.b.length; i++) {\n\t\t\t\t\telt = this.b[i];\n\t\t\t\t\tfullbcount[elt] = difflib.__dictget(fullbcount, elt, 0) + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t\tfullbcount = this.fullbcount;\n\t\n\t\t\tvar avail = {};\n\t\t\tvar availhas = difflib.__isindict(avail);\n\t\t\tvar matches = numb = 0;\n\t\t\tfor (var i = 0; i < this.a.length; i++) {\n\t\t\t\telt = this.a[i];\n\t\t\t\tif (availhas(elt)) {\n\t\t\t\t\tnumb = avail[elt];\n\t\t\t\t} else {\n\t\t\t\t\tnumb = difflib.__dictget(fullbcount, elt, 0);\n\t\t\t\t}\n\t\t\t\tavail[elt] = numb - 1;\n\t\t\t\tif (numb > 0) matches++;\n\t\t\t}\n\t\t\t\n\t\t\treturn difflib.__calculate_ratio(matches, this.a.length + this.b.length);\n\t\t}\n\t\t\n\t\tthis.real_quick_ratio = function () {\n\t\t\tvar la = this.a.length;\n\t\t\tvar lb = this.b.length;\n\t\t\treturn _calculate_ratio(Math.min(la, lb), la + lb);\n\t\t}\n\t\t\n\t\tthis.isjunk = isjunk ? isjunk : difflib.defaultJunkFunction;\n\t\tthis.a = this.b = null;\n\t\tthis.set_seqs(a, b);\n\t}\n};\n\n"
  },
  {
    "path": "Public/diff/diffview.css",
    "content": "/*\nThis is part of jsdifflib v1.0. <http://github.com/cemerick/jsdifflib>\n\nCopyright 2007 - 2011 Chas Emerick <cemerick@snowtide.com>. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without modification, are\npermitted provided that the following conditions are met:\n\n   1. Redistributions of source code must retain the above copyright notice, this list of\n      conditions and the following disclaimer.\n\n   2. Redistributions in binary form must reproduce the above copyright notice, this list\n      of conditions and the following disclaimer in the documentation and/or other materials\n      provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY Chas Emerick ``AS IS'' AND ANY EXPRESS OR IMPLIED\nWARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND\nFITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Chas Emerick OR\nCONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\nCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\nANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\nNEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\nADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nThe views and conclusions contained in the software and documentation are those of the\nauthors and should not be interpreted as representing official policies, either expressed\nor implied, of Chas Emerick.\n*/\ntable.diff {\n\tborder-collapse:collapse;\n\tborder:1px solid darkgray;\n\twhite-space:pre-wrap\n}\ntable.diff tbody { \n\tfont-family:Courier, monospace\n}\ntable.diff tbody th {\n\tfont-family:verdana,arial,'Bitstream Vera Sans',helvetica,sans-serif;\n\tbackground:#EED;\n\tfont-size:11px;\n\tfont-weight:normal;\n\tborder:1px solid #BBC;\n\tcolor:#886;\n\tpadding:.3em .5em .1em 2em;\n\ttext-align:right;\n\tvertical-align:top\n}\ntable.diff thead {\n\tborder-bottom:1px solid #BBC;\n\tbackground:#EFEFEF;\n\tfont-family:Verdana\n}\ntable.diff thead th.texttitle {\n\ttext-align:left\n}\ntable.diff tbody td {\n\tpadding:0px .4em;\n\tpadding-top:.4em;\n\tvertical-align:top;\n}\ntable.diff .empty {\n\tbackground-color:#DDD;\n}\ntable.diff .replace {\n\tbackground-color:#FD8\n}\ntable.diff .delete {\n\tbackground-color:#E99;\n}\ntable.diff .skip {\n\tbackground-color:#EFEFEF;\n\tborder:1px solid #AAA;\n\tborder-right:1px solid #BBC;\n}\ntable.diff .insert {\n\tbackground-color:#9E9\n}\ntable.diff th.author {\n\ttext-align:right;\n\tborder-top:1px solid #BBC;\n\tbackground:#EFEFEF\n}"
  },
  {
    "path": "Public/diff/diffview.js",
    "content": "/*\nThis is part of jsdifflib v1.0. <http://github.com/cemerick/jsdifflib>\n\nCopyright 2007 - 2011 Chas Emerick <cemerick@snowtide.com>. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without modification, are\npermitted provided that the following conditions are met:\n\n   1. Redistributions of source code must retain the above copyright notice, this list of\n      conditions and the following disclaimer.\n\n   2. Redistributions in binary form must reproduce the above copyright notice, this list\n      of conditions and the following disclaimer in the documentation and/or other materials\n      provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY Chas Emerick ``AS IS'' AND ANY EXPRESS OR IMPLIED\nWARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND\nFITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Chas Emerick OR\nCONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\nCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\nANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\nNEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\nADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nThe views and conclusions contained in the software and documentation are those of the\nauthors and should not be interpreted as representing official policies, either expressed\nor implied, of Chas Emerick.\n*/\ndiffview = {\n\t/**\n\t * Builds and returns a visual diff view.  The single parameter, `params', should contain\n\t * the following values:\n\t *\n\t * - baseTextLines: the array of strings that was used as the base text input to SequenceMatcher\n\t * - newTextLines: the array of strings that was used as the new text input to SequenceMatcher\n\t * - opcodes: the array of arrays returned by SequenceMatcher.get_opcodes()\n\t * - baseTextName: the title to be displayed above the base text listing in the diff view; defaults\n\t *\t   to \"Base Text\"\n\t * - newTextName: the title to be displayed above the new text listing in the diff view; defaults\n\t *\t   to \"New Text\"\n\t * - contextSize: the number of lines of context to show around differences; by default, all lines\n\t *\t   are shown\n\t * - viewType: if 0, a side-by-side diff view is generated (default); if 1, an inline diff view is\n\t *\t   generated\n\t */\n\tbuildView: function (params) {\n\t\tvar baseTextLines = params.baseTextLines;\n\t\tvar newTextLines = params.newTextLines;\n\t\tvar opcodes = params.opcodes;\n\t\tvar baseTextName = params.baseTextName ? params.baseTextName : \"Base Text\";\n\t\tvar newTextName = params.newTextName ? params.newTextName : \"New Text\";\n\t\tvar contextSize = params.contextSize;\n\t\tvar inline = (params.viewType == 0 || params.viewType == 1) ? params.viewType : 0;\n\n\t\tif (baseTextLines == null)\n\t\t\tthrow \"Cannot build diff view; baseTextLines is not defined.\";\n\t\tif (newTextLines == null)\n\t\t\tthrow \"Cannot build diff view; newTextLines is not defined.\";\n\t\tif (!opcodes)\n\t\t\tthrow \"Canno build diff view; opcodes is not defined.\";\n\t\t\n\t\tfunction celt (name, clazz) {\n\t\t\tvar e = document.createElement(name);\n\t\t\te.className = clazz;\n\t\t\treturn e;\n\t\t}\n\t\t\n\t\tfunction telt (name, text) {\n\t\t\tvar e = document.createElement(name);\n\t\t\te.appendChild(document.createTextNode(text));\n\t\t\treturn e;\n\t\t}\n\t\t\n\t\tfunction ctelt (name, clazz, text) {\n\t\t\tvar e = document.createElement(name);\n\t\t\te.className = clazz;\n\t\t\te.appendChild(document.createTextNode(text));\n\t\t\treturn e;\n\t\t}\n\t\n\t\tvar tdata = document.createElement(\"thead\");\n\t\tvar node = document.createElement(\"tr\");\n\t\ttdata.appendChild(node);\n\t\tif (inline) {\n\t\t\tnode.appendChild(document.createElement(\"th\"));\n\t\t\tnode.appendChild(document.createElement(\"th\"));\n\t\t\tnode.appendChild(ctelt(\"th\", \"texttitle\", baseTextName + \" vs. \" + newTextName));\n\t\t} else {\n\t\t\tnode.appendChild(document.createElement(\"th\"));\n\t\t\tnode.appendChild(ctelt(\"th\", \"texttitle\", baseTextName));\n\t\t\tnode.appendChild(document.createElement(\"th\"));\n\t\t\tnode.appendChild(ctelt(\"th\", \"texttitle\", newTextName));\n\t\t}\n\t\ttdata = [tdata];\n\t\t\n\t\tvar rows = [];\n\t\tvar node2;\n\t\t\n\t\t/**\n\t\t * Adds two cells to the given row; if the given row corresponds to a real\n\t\t * line number (based on the line index tidx and the endpoint of the \n\t\t * range in question tend), then the cells will contain the line number\n\t\t * and the line of text from textLines at position tidx (with the class of\n\t\t * the second cell set to the name of the change represented), and tidx + 1 will\n\t\t * be returned.\t Otherwise, tidx is returned, and two empty cells are added\n\t\t * to the given row.\n\t\t */\n\t\tfunction addCells (row, tidx, tend, textLines, change) {\n\t\t\tif (tidx < tend) {\n\t\t\t\trow.appendChild(telt(\"th\", (tidx + 1).toString()));\n\t\t\t\trow.appendChild(ctelt(\"td\", change, textLines[tidx].replace(/\\t/g, \"\\u00a0\\u00a0\\u00a0\\u00a0\")));\n\t\t\t\treturn tidx + 1;\n\t\t\t} else {\n\t\t\t\trow.appendChild(document.createElement(\"th\"));\n\t\t\t\trow.appendChild(celt(\"td\", \"empty\"));\n\t\t\t\treturn tidx;\n\t\t\t}\n\t\t}\n\t\t\n\t\tfunction addCellsInline (row, tidx, tidx2, textLines, change) {\n\t\t\trow.appendChild(telt(\"th\", tidx == null ? \"\" : (tidx + 1).toString()));\n\t\t\trow.appendChild(telt(\"th\", tidx2 == null ? \"\" : (tidx2 + 1).toString()));\n\t\t\trow.appendChild(ctelt(\"td\", change, textLines[tidx != null ? tidx : tidx2].replace(/\\t/g, \"\\u00a0\\u00a0\\u00a0\\u00a0\")));\n\t\t}\n\t\t\n\t\tfor (var idx = 0; idx < opcodes.length; idx++) {\n\t\t\tcode = opcodes[idx];\n\t\t\tchange = code[0];\n\t\t\tvar b = code[1];\n\t\t\tvar be = code[2];\n\t\t\tvar n = code[3];\n\t\t\tvar ne = code[4];\n\t\t\tvar rowcnt = Math.max(be - b, ne - n);\n\t\t\tvar toprows = [];\n\t\t\tvar botrows = [];\n\t\t\tfor (var i = 0; i < rowcnt; i++) {\n\t\t\t\t// jump ahead if we've alredy provided leading context or if this is the first range\n\t\t\t\tif (contextSize && opcodes.length > 1 && ((idx > 0 && i == contextSize) || (idx == 0 && i == 0)) && change==\"equal\") {\n\t\t\t\t\tvar jump = rowcnt - ((idx == 0 ? 1 : 2) * contextSize);\n\t\t\t\t\tif (jump > 1) {\n\t\t\t\t\t\ttoprows.push(node = document.createElement(\"tr\"));\n\t\t\t\t\t\t\n\t\t\t\t\t\tb += jump;\n\t\t\t\t\t\tn += jump;\n\t\t\t\t\t\ti += jump - 1;\n\t\t\t\t\t\tnode.appendChild(telt(\"th\", \"...\"));\n\t\t\t\t\t\tif (!inline) node.appendChild(ctelt(\"td\", \"skip\", \"\"));\n\t\t\t\t\t\tnode.appendChild(telt(\"th\", \"...\"));\n\t\t\t\t\t\tnode.appendChild(ctelt(\"td\", \"skip\", \"\"));\n\t\t\t\t\t\t\n\t\t\t\t\t\t// skip last lines if they're all equal\n\t\t\t\t\t\tif (idx + 1 == opcodes.length) {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ttoprows.push(node = document.createElement(\"tr\"));\n\t\t\t\tif (inline) {\n\t\t\t\t\tif (change == \"insert\") {\n\t\t\t\t\t\taddCellsInline(node, null, n++, newTextLines, change);\n\t\t\t\t\t} else if (change == \"replace\") {\n\t\t\t\t\t\tbotrows.push(node2 = document.createElement(\"tr\"));\n\t\t\t\t\t\tif (b < be) addCellsInline(node, b++, null, baseTextLines, \"delete\");\n\t\t\t\t\t\tif (n < ne) addCellsInline(node2, null, n++, newTextLines, \"insert\");\n\t\t\t\t\t} else if (change == \"delete\") {\n\t\t\t\t\t\taddCellsInline(node, b++, null, baseTextLines, change);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// equal\n\t\t\t\t\t\taddCellsInline(node, b++, n++, baseTextLines, change);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tb = addCells(node, b, be, baseTextLines, change);\n\t\t\t\t\tn = addCells(node, n, ne, newTextLines, change);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (var i = 0; i < toprows.length; i++) rows.push(toprows[i]);\n\t\t\tfor (var i = 0; i < botrows.length; i++) rows.push(botrows[i]);\n\t\t}\n\t\t\n\t\trows.push(node = ctelt(\"th\", \"author\", \"diff view generated by \"));\n\t\tnode.setAttribute(\"colspan\", inline ? 3 : 4);\n\t\tnode.appendChild(node2 = telt(\"a\", \"jsdifflib\"));\n\t\tnode2.setAttribute(\"href\", \"http://github.com/cemerick/jsdifflib\");\n\t\t\n\t\ttdata.push(node = document.createElement(\"tbody\"));\n\t\tfor (var idx in rows) rows.hasOwnProperty(idx) && node.appendChild(rows[idx]);\n\t\t\n\t\tnode = celt(\"table\", \"diff\" + (inline ? \" inlinediff\" : \"\"));\n\t\tfor (var idx in tdata) tdata.hasOwnProperty(idx) && node.appendChild(tdata[idx]);\n\t\treturn node;\n\t}\n};\n\n"
  },
  {
    "path": "Public/editor.md/Gulpfile.js",
    "content": "\"use strict\";\n\nvar os           = require(\"os\");\nvar gulp         = require(\"gulp\");\nvar gutil        = require(\"gulp-util\");\nvar sass         = require(\"gulp-ruby-sass\");\nvar jshint       = require(\"gulp-jshint\");\nvar uglify       = require(\"gulp-uglifyjs\");\nvar rename       = require(\"gulp-rename\");\nvar concat       = require(\"gulp-concat\");\nvar notify       = require(\"gulp-notify\");\nvar header       = require(\"gulp-header\");\nvar minifycss    = require(\"gulp-minify-css\");\n//var jsdoc        = require(\"gulp-jsdoc\");\n//var jsdoc2md     = require(\"gulp-jsdoc-to-markdown\");\nvar pkg          = require(\"./package.json\");\nvar dateFormat   = require(\"dateformatter\").format;\nvar replace      = require(\"gulp-replace\");\n\npkg.name         = \"Editor.md\";\npkg.today        = dateFormat;\n\nvar headerComment = [\"/*\", \n\t\t\t\t\t\" * <%= pkg.name %>\",\n                    \" *\",\n\t\t\t\t\t\" * @file        <%= fileName(file) %> \",\n\t\t\t\t\t\" * @version     v<%= pkg.version %> \",\n\t\t\t\t\t\" * @description <%= pkg.description %>\",\n\t\t\t\t\t\" * @license     MIT License\",\n\t\t\t\t\t\" * @author      <%= pkg.author %>\",\n\t\t\t\t\t\" * {@link       <%= pkg.homepage %>}\",\n\t\t\t\t\t\" * @updateTime  <%= pkg.today('Y-m-d') %>\",\n\t\t\t\t\t\" */\", \n\t\t\t\t\t\"\\r\\n\"].join(\"\\r\\n\");\n\nvar headerMiniComment = \"/*! <%= pkg.name %> v<%= pkg.version %> | <%= fileName(file) %> | <%= pkg.description %> | MIT License | By: <%= pkg.author %> | <%= pkg.homepage %> | <%=pkg.today('Y-m-d') %> */\\r\\n\";\n\nvar scssTask = function(fileName, path) {\n    \n    path = path || \"scss/\";\n    \n    var distPath = \"css\";\n    \n    return sass(path + fileName + \".scss\", { style: \"expanded\", sourcemap: false, noCache : true })\n        .pipe(gulp.dest(distPath))\n        .pipe(header(headerComment, {pkg : pkg, fileName : function(file) { \n            var name = file.path.split(file.base);\n            return name[1].replace(\"\\\\\", \"\");\n        }}))\n       .pipe(gulp.dest(distPath)) \n       .pipe(rename({ suffix: \".min\" }))\n       .pipe(gulp.dest(distPath))\n       .pipe(minifycss())\n       .pipe(gulp.dest(distPath)) \n        .pipe(header(headerMiniComment, {pkg : pkg, fileName : function(file) { \n            var name = file.path.split(file.base);\n            return name[1].replace(\"\\\\\", \"\");\n        }}))\n       .pipe(gulp.dest(distPath)) \n       .pipe(notify({ message: fileName + \".scss task completed!\" }));\n};\n\ngulp.task(\"scss\", function() { \n\treturn scssTask(\"editormd\");\n}); \n\ngulp.task(\"scss2\", function() { \n\treturn scssTask(\"editormd.preview\");\n}); \n\ngulp.task(\"scss3\", function() {\n\treturn scssTask(\"editormd.logo\");\n}); \n\ngulp.task(\"js\", function() { \n  return gulp.src(\"./src/editormd.js\")\n            .pipe(jshint(\"./.jshintrc\"))\n            .pipe(jshint.reporter(\"default\"))\n            .pipe(header(headerComment, {pkg : pkg, fileName : function(file) { \n                var name = file.path.split(file.base);\n                return name[1].replace(/[\\\\\\/]?/, \"\");\n            }}))\n            .pipe(gulp.dest(\"./\"))\n            .pipe(rename({ suffix: \".min\" }))\n            .pipe(uglify())  // {outSourceMap: true, sourceRoot: './'}\n            .pipe(gulp.dest(\"./\"))\t\n            .pipe(header(headerMiniComment, {pkg : pkg, fileName : function(file) {\n                var name = file.path.split(file.base + ( (os.platform() === \"win32\") ? \"\\\\\" : \"/\") );\n                return name[1].replace(/[\\\\\\/]?/, \"\");\n            }}))\n            .pipe(gulp.dest(\"./\"))\n            .pipe(notify({ message: \"editormd.js task complete\" }));\n}); \n\ngulp.task(\"amd\", function() {\n    var replaceText1 = [\n        'var cmModePath  = \"codemirror/mode/\";',\n        '            var cmAddonPath = \"codemirror/addon/\";', \n        '',\n        '            var codeMirrorModules = [',\n        '                \"jquery\", \"marked\", \"prettify\",',\n        '                \"katex\", \"raphael\", \"underscore\", \"flowchart\",  \"jqueryflowchart\",  \"sequenceDiagram\",',\n        '',\n        '                \"codemirror/lib/codemirror\",',\n        '                cmModePath + \"css/css\",',\n        '                cmModePath + \"sass/sass\",', \n        '                cmModePath + \"shell/shell\",', \n        '                cmModePath + \"sql/sql\",',\n        '                cmModePath + \"clike/clike\",',\n        '                cmModePath + \"php/php\",',\n        '                cmModePath + \"xml/xml\",',\n        '                cmModePath + \"markdown/markdown\",', \n        '                cmModePath + \"javascript/javascript\",',\n        '                cmModePath + \"htmlmixed/htmlmixed\",',\n        '                cmModePath + \"gfm/gfm\",',\n        '                cmModePath + \"http/http\",',\n        '                cmModePath + \"go/go\",', \n        '                cmModePath + \"dart/dart\",', \n        '                cmModePath + \"coffeescript/coffeescript\",',\n        '                cmModePath + \"nginx/nginx\",',\n        '                cmModePath + \"python/python\",', \n        '                cmModePath + \"perl/perl\",',\n        '                cmModePath + \"lua/lua\",', \n        '                cmModePath + \"r/r\", ',\n        '                cmModePath + \"ruby/ruby\", ',\n        '                cmModePath + \"rst/rst\",',\n        '                cmModePath + \"smartymixed/smartymixed\",', \n        '                cmModePath + \"vb/vb\",',\n        '                cmModePath + \"vbscript/vbscript\",', \n        '                cmModePath + \"velocity/velocity\",',\n        '                cmModePath + \"xquery/xquery\",',\n        '                cmModePath + \"yaml/yaml\",',\n        '                cmModePath + \"erlang/erlang\",', \n        '                cmModePath + \"jade/jade\",',\n        '',\n        '                cmAddonPath + \"edit/trailingspace\", ',\n        '                cmAddonPath + \"dialog/dialog\", ',\n        '                cmAddonPath + \"search/searchcursor\", ',\n        '                cmAddonPath + \"search/search\", ',\n        '                cmAddonPath + \"scroll/annotatescrollbar\", ', \n        '                cmAddonPath + \"search/matchesonscrollbar\", ',\n        '                cmAddonPath + \"display/placeholder\", ',\n        '                cmAddonPath + \"edit/closetag\", ',\n        '                cmAddonPath + \"fold/foldcode\",',\n        '                cmAddonPath + \"fold/foldgutter\",',\n        '                cmAddonPath + \"fold/indent-fold\",',\n        '                cmAddonPath + \"fold/brace-fold\",',\n        '                cmAddonPath + \"fold/xml-fold\", ',\n        '                cmAddonPath + \"fold/markdown-fold\",',\n        '                cmAddonPath + \"fold/comment-fold\", ',\n        '                cmAddonPath + \"mode/overlay\", ',\n        '                cmAddonPath + \"selection/active-line\", ',\n        '                cmAddonPath + \"edit/closebrackets\", ',\n        '                cmAddonPath + \"display/fullscreen\",',\n        '                cmAddonPath + \"search/match-highlighter\"',\n        '            ];',\n        '',\n        '            define(codeMirrorModules, factory);'\n    ].join(\"\\r\\n\");\n    \n    var replaceText2 = [\n        \"if (typeof define == \\\"function\\\" && define.amd) {\",\n        \"       $          = arguments[0];\",\n        \"       marked     = arguments[1];\",\n        \"       prettify   = arguments[2];\",\n        \"       katex      = arguments[3];\",\n        \"       Raphael    = arguments[4];\",\n        \"       _          = arguments[5];\",\n        \"       flowchart  = arguments[6];\",\n        \"       CodeMirror = arguments[9];\",\n        \"   }\"\n    ].join(\"\\r\\n\");\n    \n    gulp.src(\"src/editormd.js\")\n        .pipe(rename({ suffix: \".amd\" }))\n        .pipe(gulp.dest('./'))\n        .pipe(header(headerComment, {pkg : pkg, fileName : function(file) { \n            var name = file.path.split(file.base);\n            return name[1].replace(/[\\\\\\/]?/, \"\");\n        }}))\n        .pipe(gulp.dest(\"./\"))\n        .pipe(replace(\"/* Require.js define replace */\", replaceText1))\n        .pipe(gulp.dest('./'))\n        .pipe(replace(\"/* Require.js assignment replace */\", replaceText2))\n        .pipe(gulp.dest('./'))\n        .pipe(rename({ suffix: \".min\" }))\n        .pipe(uglify()) //{outSourceMap: true, sourceRoot: './'}\n        .pipe(gulp.dest(\"./\"))\n        .pipe(header(headerMiniComment, {pkg : pkg, fileName : function(file) {\n            var name = file.path.split(file.base + ( (os.platform() === \"win32\") ? \"\\\\\" : \"/\") );\n            return name[1].replace(/[\\\\\\/]?/, \"\");\n        }}))\n        .pipe(gulp.dest(\"./\"))\n        .pipe(notify({ message: \"amd version task complete\"}));\n}); \n\n\nvar codeMirror = {\n    path : {\n        src : {\n            mode : \"lib/codemirror/mode\",\n            addon : \"lib/codemirror/addon\"\n        },\n        dist : \"lib/codemirror\"\n    },\n    modes : [\n        \"css\",\n        \"sass\",\n        \"shell\",\n        \"sql\",\n        \"clike\",\n        \"php\",\n        \"xml\",\n        \"markdown\",\n        \"javascript\",\n        \"htmlmixed\",\n        \"gfm\",\n        \"http\",\n        \"go\",\n        \"dart\",\n        \"coffeescript\",\n        \"nginx\",\n        \"python\",\n        \"perl\",\n        \"lua\",\n        \"r\", \n        \"ruby\", \n        \"rst\",\n        \"smartymixed\",\n        \"vb\",\n        \"vbscript\",\n        \"velocity\",\n        \"xquery\",\n        \"yaml\",\n        \"erlang\",\n        \"jade\",\n    ],\n\n    addons : [\n        \"edit/trailingspace\", \n        \"dialog/dialog\", \n        \"search/searchcursor\", \n        \"search/search\",\n        \"scroll/annotatescrollbar\", \n        \"search/matchesonscrollbar\", \n        \"display/placeholder\", \n        \"edit/closetag\", \n        \"fold/foldcode\",\n        \"fold/foldgutter\",\n        \"fold/indent-fold\",\n        \"fold/brace-fold\",\n        \"fold/xml-fold\", \n        \"fold/markdown-fold\",\n        \"fold/comment-fold\", \n        \"mode/overlay\", \n        \"selection/active-line\", \n        \"edit/closebrackets\", \n        \"display/fullscreen\", \n        \"search/match-highlighter\"\n    ]\n};\n\ngulp.task(\"cm-mode\", function() { \n    \n    var modes = [\n        codeMirror.path.src.mode + \"/meta.js\"\n    ];\n    \n    for(var i in codeMirror.modes) {\n        var mode = codeMirror.modes[i];\n        modes.push(codeMirror.path.src.mode + \"/\" + mode + \"/\" + mode + \".js\");\n    }\n    \n    return gulp.src(modes)\n                .pipe(concat(\"modes.min.js\"))\n                .pipe(gulp.dest(codeMirror.path.dist))\n                .pipe(uglify()) // {outSourceMap: true, sourceRoot: codeMirror.path.dist}\n                .pipe(gulp.dest(codeMirror.path.dist))\t\n                .pipe(header(headerMiniComment, {pkg : pkg, fileName : function(file) {\n                    var name = file.path.split(file.base + \"\\\\\"); \n                    return (name[1]?name[1]:name[0]).replace(/\\\\/g, \"\");\n                }}))\n                .pipe(gulp.dest(codeMirror.path.dist))\n                .pipe(notify({ message: \"codemirror-mode task complete!\" }));\n}); \n\ngulp.task(\"cm-addon\", function() { \n    \n    var addons = [];\n    \n    for(var i in codeMirror.addons) {\n        var addon = codeMirror.addons[i];\n        addons.push(codeMirror.path.src.addon + \"/\" + addon + \".js\");\n    }\n    \n    return gulp.src(addons)\n                .pipe(concat(\"addons.min.js\"))\n                .pipe(gulp.dest(codeMirror.path.dist))\n                .pipe(uglify()) //{outSourceMap: true, sourceRoot: codeMirror.path.dist}\n                .pipe(gulp.dest(codeMirror.path.dist))\t\n                .pipe(header(headerMiniComment, {pkg : pkg, fileName : function(file) {\n                    var name = file.path.split(file.base + \"\\\\\");\n                    return (name[1]?name[1]:name[0]).replace(/\\\\/g, \"\");\n                }}))\n                .pipe(gulp.dest(codeMirror.path.dist))\n                .pipe(notify({ message: \"codemirror-addon.js task complete\" }));\n}); \n/*\ngulp.task(\"jsdoc\", function(){\n    return gulp.src([\"./src/editormd.js\", \"README.md\"])\n               .pipe(jsdoc.parser())\n               .pipe(jsdoc.generator(\"./docs/html\"));\n});\n\ngulp.task(\"jsdoc2md\", function() {\n    return gulp.src(\"src/js/editormd.js\")\n            .pipe(jsdoc2md())\n            .on(\"error\", function(err){\n                gutil.log(gutil.colors.red(\"jsdoc2md failed\"), err.message);\n            })\n            .pipe(rename(function(path) {\n                path.extname = \".md\";\n            }))\n            .pipe(gulp.dest(\"docs/markdown\"));\n});\n*/\ngulp.task(\"watch\", function() {\n\tgulp.watch(\"scss/editormd.scss\", [\"scss\"]);\n\tgulp.watch(\"scss/editormd.preview.scss\", [\"scss\", \"scss2\"]);\n\tgulp.watch(\"scss/editormd.logo.scss\", [\"scss\", \"scss3\"]);\n\tgulp.watch(\"src/editormd.js\", [\"js\", \"amd\"]);\n});\n\ngulp.task(\"default\", function() {\n    gulp.run(\"scss\");\n    gulp.run(\"scss2\");\n    gulp.run(\"scss3\");\n    gulp.run(\"js\");\n    gulp.run(\"amd\");\n    gulp.run(\"cm-addon\");\n    gulp.run(\"cm-mode\");\n});"
  },
  {
    "path": "Public/editor.md/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2015 pandao\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n"
  },
  {
    "path": "Public/editor.md/README.md",
    "content": "# Editor.md\n\n![](https://pandao.github.io/editor.md/images/logos/editormd-logo-180x180.png)\n\n![](https://img.shields.io/github/stars/pandao/editor.md.svg)\n![](https://img.shields.io/github/forks/pandao/editor.md.svg)\n![](https://img.shields.io/github/tag/pandao/editor.md.svg)\n![](https://img.shields.io/github/release/pandao/editor.md.svg)\n![](https://img.shields.io/github/issues/pandao/editor.md.svg)\n![](https://img.shields.io/bower/v/editor.md.svg)\n\n**Editor.md** : The open source embeddable online markdown editor (component), based on CodeMirror & jQuery & Marked.\n\n### Features\n\n- Support Standard Markdown / CommonMark and GFM (GitHub Flavored Markdown);\n- Full-featured: Real-time Preview, Image (cross-domain) upload, Preformatted text/Code blocks/Tables insert, Code fold, Search replace, Read only, Themes, Multi-languages, L18n, HTML entities, Code syntax highlighting...;\n- Markdown Extras : Support [ToC (Table of Contents)](https://pandao.github.io/editor.md/examples/toc.html), [Emoji](https://pandao.github.io/editor.md/examples/emoji.html), [Task lists](https://pandao.github.io/editor.md/examples/task-lists.html), [@Links](https://pandao.github.io/editor.md/examples/@links.html)...;\n- Compatible with all major browsers (IE8+), compatible Zepto.js and iPad;\n- Support [decode & fliter of the HTML tags & attributes](https://pandao.github.io/editor.md/examples/html-tags-decode.html);\n- Support [TeX (LaTeX expressions, Based on KaTeX)](https://pandao.github.io/editor.md/examples/katex.html), [Flowchart](https://pandao.github.io/editor.md/examples/flowchart.html) and [Sequence Diagram](https://pandao.github.io/editor.md/examples/sequence-diagram.html) of Markdown extended syntax;\n- Support AMD/CMD (Require.js & Sea.js) Module Loader, and Custom/define editor plugins;\n\n[README & Examples (English)](https://pandao.github.io/editor.md/en.html)\n  \n\n--------\n\n**Editor.md** 是一款开源的、可嵌入的 Markdown 在线编辑器（组件），基于 CodeMirror、jQuery 和 Marked 构建。\n\n![editormd-screenshot](https://pandao.github.io/editor.md/examples/images/editormd-screenshot.png \"editormd-screenshot\")\n\n#### 主要特性\n\n- 支持通用 Markdown / CommonMark 和 GFM (GitHub Flavored Markdown) 风格的语法，也可[变身为代码编辑器](https://pandao.github.io/editor.md/examples/change-mode.html)；\n- 支持实时预览、图片（跨域）上传、预格式文本/代码/表格插入、代码折叠、跳转到行、搜索替换、只读模式、自定义样式主题和多语言语法高亮等功能；\n- 支持 [ToC（Table of Contents）](https://pandao.github.io/editor.md/examples/toc.html)、[Emoji表情](https://pandao.github.io/editor.md/examples/emoji.html)、[Task lists](https://pandao.github.io/editor.md/examples/task-lists.html)、[@链接](https://pandao.github.io/editor.md/examples/@links.html)等 Markdown 扩展语法；\n- 支持 TeX 科学公式（基于 [KaTeX](https://pandao.github.io/editor.md/examples/katex.html)）、流程图 [Flowchart](https://pandao.github.io/editor.md/examples/flowchart.html) 和 [时序图 Sequence Diagram](https://pandao.github.io/editor.md/examples/sequence-diagram.html);\n- 支持[识别和解析 HTML 标签，并且支持自定义过滤标签及属性解析](https://pandao.github.io/editor.md/examples/html-tags-decode.html)，具有可靠的安全性和几乎无限的扩展性；\n- 支持 AMD / CMD 模块化加载（支持 [Require.js](https://pandao.github.io/editor.md/examples/use-requirejs.html) & [Sea.js](https://pandao.github.io/editor.md/examples/use-seajs.html)），并且支持[自定义扩展插件](https://pandao.github.io/editor.md/examples/define-plugin.html)；\n- 兼容主流的浏览器（IE8+）和 [Zepto.js](https://pandao.github.io/editor.md/examples/use-zepto.html)，且支持 iPad 等平板设备；\n\n#### Examples\n\n[https://pandao.github.io/editor.md/examples/index.html](https://pandao.github.io/editor.md/examples/index.html)\n\n#### Download & install\n\n[Github download](https://github.com/pandao/editor.md/archive/master.zip)\n\nBower install :\n\n```shell\nbower install editor.md\n```\n\n#### Usages\n\nHTML：\n\n```html\n<link rel=\"stylesheet\" href=\"editormd.min.css\" />\n<div id=\"editormd\">\n    <textarea style=\"display:none;\">### Hello Editor.md !</textarea>\n</div>\n```\n\n> Tip: Editor.md can auto append `<textarea>` tag;\n\njavascript:\n\n```html\n<script src=\"jquery.min.js\"></script>\n<script src=\"editormd.min.js\"></script>\n<script type=\"text/javascript\">\n    $(function() {\n        var editor = editormd(\"editormd\", {\n            path : \"../lib/\" // Autoload modules mode, codemirror, marked... dependents libs path\n        });\n\n        /*\n        // or\n        var editor = editormd({\n            id   : \"editormd\",\n            path : \"../lib/\"\n        });\n        */\n    });\n</script>\n```\n\nUsing modular script loader :\n\n- [Using Require.js](https://github.com/pandao/editor.md/tree/master/examples/use-requirejs.html)\n- [Using Sea.js](https://github.com/pandao/editor.md/tree/master/examples/use-seajs.html)\n\n#### Dependents\n\n- [CodeMirror](http://codemirror.net/ \"CodeMirror\")\n- [marked](https://github.com/chjj/marked \"marked\")\n- [jQuery](http://jquery.com/ \"jQuery\")\n- [FontAwesome](http://fontawesome.io/ \"FontAwesome\")\n- [github-markdown.css](https://github.com/sindresorhus/github-markdown-css \"github-markdown.css\")\n- [KaTeX](http://khan.github.io/KaTeX/ \"KaTeX\")\n- [prettify.js](http://code.google.com/p/google-code-prettify/ \"prettify.js\")\n- [Rephael.js](http://raphaeljs.com/ \"Rephael.js\")\n- [flowchart.js](http://adrai.github.io/flowchart.js/ \"flowchart.js\")\n- [sequence-diagram.js](http://bramp.github.io/js-sequence-diagrams/ \"sequence-diagram.js\")\n- [Prefixes.scss](https://github.com/pandao/prefixes.scss \"Prefixes.scss\")\n\n#### Changes\n\n[Change logs](https://github.com/pandao/editor.md/blob/master/CHANGE.md)\n\n#### License\n\nThe MIT License.\n\nCopyright (c) 2015 Pandao\n"
  },
  {
    "path": "Public/editor.md/css/editormd.css",
    "content": "/*\n * Editor.md\n *\n * @file        editormd.css \n * @version     v1.5.0 \n * @description Open source online markdown editor.\n * @license     MIT License\n * @author      Pandao\n * {@link       https://github.com/pandao/editor.md}\n * @updateTime  2015-06-09\n */\n\n@charset \"UTF-8\";\n/*! prefixes.scss v0.1.0 | Author: Pandao | https://github.com/pandao/prefixes.scss | MIT license | Copyright (c) 2015 */\n.editormd {\n  width: 90%;\n  height: 640px;\n  margin: 0 auto;\n  text-align: left;\n  overflow: hidden;\n  position: relative;\n  margin-bottom: 15px;\n  border: 1px solid #ddd;\n  font-family: \"Meiryo UI\", \"Microsoft YaHei\", \"Malgun Gothic\", \"Segoe UI\", \"Trebuchet MS\", Helvetica, \"Monaco\", monospace, Tahoma, STXihei, \"华文细黑\", STHeiti, \"Helvetica Neue\", \"Droid Sans\", \"wenquanyi micro hei\", FreeSans, Arimo, Arial, SimSun, \"宋体\", Heiti, \"黑体\", sans-serif;\n}\n.editormd *, .editormd *:before, .editormd *:after {\n  -webkit-box-sizing: border-box;\n  -moz-box-sizing: border-box;\n  box-sizing: border-box;\n}\n.editormd a {\n  text-decoration: none;\n}\n.editormd img {\n  border: none;\n  vertical-align: middle;\n}\n.editormd > textarea,\n.editormd .editormd-html-textarea,\n.editormd .editormd-markdown-textarea {\n  width: 0;\n  height: 0;\n  outline: 0;\n  resize: none;\n}\n.editormd .editormd-html-textarea,\n.editormd .editormd-markdown-textarea {\n  display: none;\n}\n.editormd input[type=\"text\"],\n.editormd input[type=\"button\"],\n.editormd input[type=\"submit\"],\n.editormd select, .editormd textarea, .editormd button {\n  -webkit-appearance: none;\n  -moz-appearance: none;\n  -ms-appearance: none;\n  appearance: none;\n}\n.editormd ::-webkit-scrollbar {\n  height: 10px;\n  width: 7px;\n  background: rgba(0, 0, 0, 0.1);\n}\n.editormd ::-webkit-scrollbar:hover {\n  background: rgba(0, 0, 0, 0.2);\n}\n.editormd ::-webkit-scrollbar-thumb {\n  background: rgba(0, 0, 0, 0.3);\n  -webkit-border-radius: 6px;\n  -moz-border-radius: 6px;\n  -ms-border-radius: 6px;\n  -o-border-radius: 6px;\n  border-radius: 6px;\n}\n.editormd ::-webkit-scrollbar-thumb:hover {\n  -webkit-box-shadow: inset 1px 1px 1px rgba(0, 0, 0, 0.25);\n  /* Webkit browsers */\n  -moz-box-shadow: inset 1px 1px 1px rgba(0, 0, 0, 0.25);\n  /* Firefox */\n  -ms-box-shadow: inset 1px 1px 1px rgba(0, 0, 0, 0.25);\n  /* IE9 */\n  -o-box-shadow: inset 1px 1px 1px rgba(0, 0, 0, 0.25);\n  /* Opera(Old) */\n  box-shadow: inset 1px 1px 1px rgba(0, 0, 0, 0.25);\n  /* IE9+, News */\n  background-color: rgba(0, 0, 0, 0.4);\n}\n\n.editormd-user-unselect {\n  -webkit-user-select: none;\n  -moz-user-select: none;\n  -ms-user-select: none;\n  -o-user-select: none;\n  user-select: none;\n}\n\n.editormd-toolbar {\n  width: 100%;\n  min-height: 37px;\n  background: #fff;\n  display: none;\n  position: absolute;\n  top: 0;\n  left: 0;\n  z-index: 10;\n  border-bottom: 1px solid #ddd;\n}\n\n.editormd-toolbar-container {\n  padding: 0 8px;\n  min-height: 35px;\n  -webkit-user-select: none;\n  -moz-user-select: none;\n  -ms-user-select: none;\n  -o-user-select: none;\n  user-select: none;\n}\n\n.editormd-menu {\n  margin: 0;\n  padding: 0;\n  list-style: none;\n}\n.editormd-menu > li {\n  margin: 0;\n  padding: 5px 1px;\n  display: inline-block;\n  position: relative;\n}\n.editormd-menu > li.divider {\n  display: inline-block;\n  text-indent: -9999px;\n  margin: 0 5px;\n  height: 65%;\n  border-right: 1px solid #ddd;\n}\n.editormd-menu > li > a {\n  outline: 0;\n  color: #666;\n  display: inline-block;\n  min-width: 24px;\n  font-size: 16px;\n  text-decoration: none;\n  text-align: center;\n  -webkit-border-radius: 2px;\n  -moz-border-radius: 2px;\n  -ms-border-radius: 2px;\n  -o-border-radius: 2px;\n  border-radius: 2px;\n  border: 1px solid #fff;\n  -webkit-transition: all 300ms ease-out;\n  /* Safari, Chrome */\n  -moz-transition: all 300ms ease-out;\n  /* Firefox 4.0~16.0 */\n  transition: all 300ms ease-out;\n  /* IE >9, FF >15, Opera >12.0 */\n}\n.editormd-menu > li > a:hover, .editormd-menu > li > a.active {\n  border: 1px solid #ddd;\n  background: #eee;\n}\n.editormd-menu > li > a > .fa {\n  text-align: center;\n  display: block;\n  padding: 5px;\n}\n.editormd-menu > li > a > .editormd-bold {\n  padding: 5px 2px;\n  display: inline-block;\n  font-weight: bold;\n}\n.editormd-menu > li:hover .editormd-dropdown-menu {\n  display: block;\n}\n.editormd-menu > li + li > a {\n  margin-left: 3px;\n}\n\n.editormd-dropdown-menu {\n  display: none;\n  background: #fff;\n  border: 1px solid #ddd;\n  width: 148px;\n  list-style: none;\n  position: absolute;\n  top: 33px;\n  left: 0;\n  z-index: 100;\n  -webkit-box-shadow: 1px 2px 6px rgba(0, 0, 0, 0.15);\n  /* Webkit browsers */\n  -moz-box-shadow: 1px 2px 6px rgba(0, 0, 0, 0.15);\n  /* Firefox */\n  -ms-box-shadow: 1px 2px 6px rgba(0, 0, 0, 0.15);\n  /* IE9 */\n  -o-box-shadow: 1px 2px 6px rgba(0, 0, 0, 0.15);\n  /* Opera(Old) */\n  box-shadow: 1px 2px 6px rgba(0, 0, 0, 0.15);\n  /* IE9+, News */\n}\n.editormd-dropdown-menu:before, .editormd-dropdown-menu:after {\n  width: 0;\n  height: 0;\n  display: block;\n  content: \"\";\n  position: absolute;\n  top: -11px;\n  left: 8px;\n  border: 5px solid transparent;\n}\n.editormd-dropdown-menu:before {\n  border-bottom-color: #ccc;\n}\n.editormd-dropdown-menu:after {\n  border-bottom-color: #ffffff;\n  top: -10px;\n}\n.editormd-dropdown-menu > li > a {\n  color: #666;\n  display: block;\n  text-decoration: none;\n  padding: 8px 10px;\n}\n.editormd-dropdown-menu > li > a:hover {\n  background: #f6f6f6;\n  -webkit-transition: all 300ms ease-out;\n  /* Safari, Chrome */\n  -moz-transition: all 300ms ease-out;\n  /* Firefox 4.0~16.0 */\n  transition: all 300ms ease-out;\n  /* IE >9, FF >15, Opera >12.0 */\n}\n.editormd-dropdown-menu > li + li {\n  border-top: 1px solid #ddd;\n}\n\n.editormd-container {\n  margin: 0;\n  width: 100%;\n  height: 100%;\n  overflow: hidden;\n  padding: 35px 0 0;\n  position: relative;\n  background: #fff;\n  -webkit-box-sizing: border-box;\n  -moz-box-sizing: border-box;\n  box-sizing: border-box;\n}\n\n.editormd-dialog {\n  color: #666;\n  position: fixed;\n  z-index: 99999;\n  display: none;\n  -webkit-border-radius: 3px;\n  -moz-border-radius: 3px;\n  -ms-border-radius: 3px;\n  -o-border-radius: 3px;\n  border-radius: 3px;\n  -webkit-box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);\n  /* Webkit browsers */\n  -moz-box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);\n  /* Firefox */\n  -ms-box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);\n  /* IE9 */\n  -o-box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);\n  /* Opera(Old) */\n  box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);\n  /* IE9+, News */\n  background: #fff;\n  font-size: 14px;\n}\n\n.editormd-dialog-container {\n  position: relative;\n  padding: 20px;\n  line-height: 1.4;\n}\n.editormd-dialog-container h1 {\n  font-size: 24px;\n  margin-bottom: 10px;\n}\n.editormd-dialog-container h1 .fa {\n  color: #2C7EEA;\n  padding-right: 5px;\n}\n.editormd-dialog-container h1 small {\n  padding-left: 5px;\n  font-weight: normal;\n  font-size: 12px;\n  color: #999;\n}\n.editormd-dialog-container select {\n  color: #999;\n  padding: 3px 8px;\n  border: 1px solid #ddd;\n}\n\n.editormd-dialog-close {\n  position: absolute;\n  top: 12px;\n  right: 15px;\n  font-size: 18px;\n  color: #ccc;\n  -webkit-transition: color 300ms ease-out;\n  /* Safari, Chrome */\n  -moz-transition: color 300ms ease-out;\n  /* Firefox 4.0~16.0 */\n  transition: color 300ms ease-out;\n  /* IE >9, FF >15, Opera >12.0 */\n}\n.editormd-dialog-close:hover {\n  color: #999;\n}\n\n.editormd-dialog-header {\n  padding: 11px 20px;\n  border-bottom: 1px solid #eee;\n  -webkit-transition: background 300ms ease-out;\n  /* Safari, Chrome */\n  -moz-transition: background 300ms ease-out;\n  /* Firefox 4.0~16.0 */\n  transition: background 300ms ease-out;\n  /* IE >9, FF >15, Opera >12.0 */\n}\n.editormd-dialog-header:hover {\n  background: #f6f6f6;\n}\n\n.editormd-dialog-title {\n  font-size: 14px;\n}\n\n.editormd-dialog-footer {\n  padding: 10px 0 0 0;\n  text-align: right;\n}\n\n.editormd-dialog-info {\n  width: 420px;\n}\n.editormd-dialog-info h1 {\n  font-weight: normal;\n}\n.editormd-dialog-info .editormd-dialog-container {\n  padding: 20px 25px 25px;\n}\n.editormd-dialog-info .editormd-dialog-close {\n  top: 10px;\n  right: 10px;\n}\n.editormd-dialog-info p > a, .editormd-dialog-info .hover-link:hover {\n  color: #2196F3;\n}\n.editormd-dialog-info .hover-link {\n  color: #666;\n}\n.editormd-dialog-info a .fa-external-link {\n  display: none;\n}\n.editormd-dialog-info a:hover {\n  color: #2196F3;\n}\n.editormd-dialog-info a:hover .fa-external-link {\n  display: inline-block;\n}\n\n.editormd-mask,\n.editormd-container-mask,\n.editormd-dialog-mask {\n  display: none;\n  width: 100%;\n  height: 100%;\n  position: absolute;\n  top: 0;\n  left: 0;\n}\n\n.editormd-mask,\n.editormd-dialog-mask-bg {\n  background: #fff;\n  opacity: 0.5;\n  filter: alpha(opacity=50);\n}\n\n.editormd-mask {\n  position: fixed;\n  background: #000;\n  opacity: 0.2;\n  /* W3C */\n  filter: alpha(opacity=20);\n  /* IE */\n  z-index: 99998;\n}\n\n.editormd-container-mask,\n.editormd-dialog-mask-con {\n  background: url(../images/loading.gif) no-repeat center center;\n  -webkit-background-size: 32px 32px;\n  /* Chrome, iOS, Safari */\n  -moz-background-size: 32px 32px;\n  /* Firefox 3.6~4.0 */\n  -o-background-size: 32px 32px;\n  /* Opera 9.5 */\n  background-size: 32px 32px;\n  /* IE9+, New */\n}\n\n.editormd-container-mask {\n  z-index: 20;\n  display: block;\n  background-color: #fff;\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min-device-pixel-ratio: 2) {\n  .editormd-container-mask,\n  .editormd-dialog-mask-con {\n    background-image: url(../images/loading@2x.gif);\n  }\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 3), only screen and (min-device-pixel-ratio: 3) {\n  .editormd-container-mask,\n  .editormd-dialog-mask-con {\n    background-image: url(../images/loading@3x.gif);\n  }\n}\n.editormd-code-block-dialog textarea,\n.editormd-preformatted-text-dialog textarea {\n  width: 100%;\n  height: 400px;\n  margin-bottom: 6px;\n  overflow: auto;\n  border: 1px solid #eee;\n  background: #fff;\n  padding: 15px;\n  resize: none;\n}\n\n.editormd-code-toolbar {\n  color: #999;\n  font-size: 14px;\n  margin: -5px 0 10px;\n}\n\n.editormd-grid-table {\n  width: 99%;\n  display: table;\n  border: 1px solid #ddd;\n  border-collapse: collapse;\n}\n\n.editormd-grid-table-row {\n  width: 100%;\n  display: table-row;\n}\n.editormd-grid-table-row a {\n  font-size: 1.4em;\n  width: 5%;\n  height: 36px;\n  color: #999;\n  text-align: center;\n  display: table-cell;\n  vertical-align: middle;\n  border: 1px solid #ddd;\n  text-decoration: none;\n  -webkit-transition: background-color 300ms ease-out, color 100ms ease-in;\n  /* Safari, Chrome */\n  -moz-transition: background-color 300ms ease-out, color 100ms ease-in;\n  /* Firefox 4.0~16.0 */\n  transition: background-color 300ms ease-out, color 100ms ease-in;\n  /* IE >9, FF >15, Opera >12.0 */\n}\n.editormd-grid-table-row a.selected {\n  color: #666;\n  background-color: #eee;\n}\n.editormd-grid-table-row a:hover {\n  color: #777;\n  background-color: #f6f6f6;\n}\n\n.editormd-tab-head {\n  list-style: none;\n  border-bottom: 1px solid #ddd;\n}\n.editormd-tab-head li {\n  display: inline-block;\n}\n.editormd-tab-head li a {\n  color: #999;\n  display: block;\n  padding: 6px 12px 5px;\n  text-align: center;\n  text-decoration: none;\n  margin-bottom: -1px;\n  border: 1px solid #ddd;\n  -webkit-border-top-left-radius: 3px;\n  -moz-border-top-left-radius: 3px;\n  -ms-border-top-left-radius: 3px;\n  -o-border-top-left-radius: 3px;\n  border-top-left-radius: 3px;\n  -webkit-border-top-right-radius: 3px;\n  -moz-border-top-right-radius: 3px;\n  -ms-border-top-right-radius: 3px;\n  -o-border-top-right-radius: 3px;\n  border-top-right-radius: 3px;\n  background: #f6f6f6;\n  -webkit-transition: all 300ms ease-out;\n  /* Safari, Chrome */\n  -moz-transition: all 300ms ease-out;\n  /* Firefox 4.0~16.0 */\n  transition: all 300ms ease-out;\n  /* IE >9, FF >15, Opera >12.0 */\n}\n.editormd-tab-head li a:hover {\n  color: #666;\n  background: #eee;\n}\n.editormd-tab-head li.active a {\n  color: #666;\n  background: #fff;\n  border-bottom-color: #fff;\n}\n.editormd-tab-head li + li {\n  margin-left: 3px;\n}\n\n.editormd-tab-box {\n  padding: 20px 0;\n}\n\n.editormd-form {\n  color: #666;\n}\n.editormd-form label {\n  float: left;\n  display: block;\n  width: 75px;\n  text-align: left;\n  padding: 7px 0 15px 5px;\n  margin: 0 0 2px;\n  font-weight: normal;\n}\n.editormd-form br {\n  clear: both;\n}\n.editormd-form iframe {\n  display: none;\n}\n.editormd-form input:focus {\n  outline: 0;\n}\n.editormd-form input[type=\"text\"], .editormd-form input[type=\"number\"] {\n  color: #999;\n  padding: 8px;\n  border: 1px solid #ddd;\n}\n.editormd-form input[type=\"number\"] {\n  width: 40px;\n  display: inline-block;\n  padding: 6px 8px;\n}\n.editormd-form input[type=\"text\"] {\n  display: inline-block;\n  width: 264px;\n}\n.editormd-form .fa-btns {\n  display: inline-block;\n}\n.editormd-form .fa-btns a {\n  color: #999;\n  padding: 7px 10px 0 0;\n  display: inline-block;\n  text-decoration: none;\n  text-align: center;\n}\n.editormd-form .fa-btns .fa {\n  font-size: 1.3em;\n}\n.editormd-form .fa-btns label {\n  float: none;\n  display: inline-block;\n  width: auto;\n  text-align: left;\n  padding: 0 0 0 5px;\n  cursor: pointer;\n}\n\n.editormd-form input[type=\"submit\"], .editormd-form .editormd-btn, .editormd-form button,\n.editormd-dialog-container input[type=\"submit\"],\n.editormd-dialog-container .editormd-btn,\n.editormd-dialog-container button,\n.editormd-dialog-footer input[type=\"submit\"],\n.editormd-dialog-footer .editormd-btn,\n.editormd-dialog-footer button {\n  color: #666;\n  min-width: 75px;\n  cursor: pointer;\n  background: #fff;\n  padding: 7px 10px;\n  border: 1px solid #ddd;\n  -webkit-border-radius: 3px;\n  -moz-border-radius: 3px;\n  -ms-border-radius: 3px;\n  -o-border-radius: 3px;\n  border-radius: 3px;\n  -webkit-transition: background 300ms ease-out;\n  /* Safari, Chrome */\n  -moz-transition: background 300ms ease-out;\n  /* Firefox 4.0~16.0 */\n  transition: background 300ms ease-out;\n  /* IE >9, FF >15, Opera >12.0 */\n}\n.editormd-form input[type=\"submit\"]:hover, .editormd-form .editormd-btn:hover, .editormd-form button:hover,\n.editormd-dialog-container input[type=\"submit\"]:hover,\n.editormd-dialog-container .editormd-btn:hover,\n.editormd-dialog-container button:hover,\n.editormd-dialog-footer input[type=\"submit\"]:hover,\n.editormd-dialog-footer .editormd-btn:hover,\n.editormd-dialog-footer button:hover {\n  background: #eee;\n}\n.editormd-form .editormd-btn,\n.editormd-dialog-container .editormd-btn,\n.editormd-dialog-footer .editormd-btn {\n  padding: 5px 8px 4px\\0;\n}\n.editormd-form .editormd-btn + .editormd-btn,\n.editormd-dialog-container .editormd-btn + .editormd-btn,\n.editormd-dialog-footer .editormd-btn + .editormd-btn {\n  margin-left: 8px;\n}\n\n.editormd-file-input {\n  width: 75px;\n  height: 32px;\n  margin-left: 8px;\n  position: relative;\n  display: inline-block;\n}\n.editormd-file-input input[type=\"file\"] {\n  width: 75px;\n  height: 32px;\n  opacity: 0;\n  cursor: pointer;\n  background: #000;\n  display: inline-block;\n  position: absolute;\n  top: 0;\n  right: 0;\n}\n.editormd-file-input input[type=\"file\"]::-webkit-file-upload-button {\n  visibility: hidden;\n}\n.editormd-file-input:hover input[type=\"submit\"] {\n  background: #eee;\n}\n\n.editormd .CodeMirror, .editormd-preview {\n  display: inline-block;\n  width: 50%;\n  height: 100%;\n  vertical-align: top;\n  -webkit-box-sizing: border-box;\n  -moz-box-sizing: border-box;\n  box-sizing: border-box;\n  margin: 0;\n}\n\n.editormd-preview {\n  position: absolute;\n  top: 35px;\n  right: 0;\n  right: -1px\\0;\n  overflow: auto;\n  line-height: 1.6;\n  display: none;\n  background: #fff;\n}\n\n.editormd .CodeMirror {\n  z-index: 10;\n  float: left;\n  border-right: 1px solid #ddd;\n  font-size: 14px;\n  font-family: \"YaHei Consolas Hybrid\", Consolas, \"微软雅黑\", \"Meiryo UI\", \"Malgun Gothic\", \"Segoe UI\", \"Trebuchet MS\", Helvetica, \"Monaco\", courier, monospace;\n  line-height: 1.6;\n  margin-top: 35px;\n}\n.editormd .CodeMirror pre {\n  font-size: 14px;\n  padding: 0 12px;\n}\n.editormd .CodeMirror-linenumbers {\n  padding: 0 5px;\n}\n.editormd .CodeMirror-selected {\n  background: #70B7FF;\n}\n.editormd .CodeMirror-focused .CodeMirror-selected {\n  background: #70B7FF;\n}\n.editormd .CodeMirror, .editormd .CodeMirror-scroll, .editormd .editormd-preview {\n  -webkit-overflow-scrolling: touch;\n}\n.editormd .styled-background {\n  background-color: #ff7;\n}\n.editormd .CodeMirror-focused .cm-matchhighlight {\n  background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAFklEQVQI12NgYGBgkKzc8x9CMDAwAAAmhwSbidEoSQAAAABJRU5ErkJggg==);\n  background-position: bottom;\n  background-repeat: repeat-x;\n}\n.editormd .CodeMirror-empty.CodeMirror-focused {\n  outline: none;\n}\n.editormd .CodeMirror pre.CodeMirror-placeholder {\n  color: #999;\n}\n.editormd .cm-trailingspace {\n  background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAACCAYAAAB/qH1jAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3QUXCToH00Y1UgAAACFJREFUCNdjPMDBUc/AwNDAAAFMTAwMDA0OP34wQgX/AQBYgwYEx4f9lQAAAABJRU5ErkJggg==);\n  background-position: bottom left;\n  background-repeat: repeat-x;\n}\n.editormd .cm-tab {\n  background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAMCAYAAAAkuj5RAAAAAXNSR0IArs4c6QAAAGFJREFUSMft1LsRQFAQheHPowAKoACx3IgEKtaEHujDjORSgWTH/ZOdnZOcM/sgk/kFFWY0qV8foQwS4MKBCS3qR6ixBJvElOobYAtivseIE120FaowJPN75GMu8j/LfMwNjh4HUpwg4LUAAAAASUVORK5CYII=);\n  background-position: right;\n  background-repeat: no-repeat;\n}\n\n/*! prefixes.scss v0.1.0 | Author: Pandao | https://github.com/pandao/prefixes.scss | MIT license | Copyright (c) 2015 */\n/*!\n *  Font Awesome 4.3.0 by @davegandy - http://fontawesome.io - @fontawesome\n *  License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)\n */\n/* FONT PATH\n * -------------------------- */\n@font-face {\n  font-family: 'FontAwesome';\n  src: url(\"../fonts/fontawesome-webfont.eot?v=4.3.0\");\n  src: url(\"../fonts/fontawesome-webfont.eot?#iefix&v=4.3.0\") format(\"embedded-opentype\"), url(\"../fonts/fontawesome-webfont.woff2?v=4.3.0\") format(\"woff2\"), url(\"../fonts/fontawesome-webfont.woff?v=4.3.0\") format(\"woff\"), url(\"../fonts/fontawesome-webfont.ttf?v=4.3.0\") format(\"truetype\"), url(\"../fonts/fontawesome-webfont.svg?v=4.3.0#fontawesomeregular\") format(\"svg\");\n  font-weight: normal;\n  font-style: normal;\n}\n.fa {\n  display: inline-block;\n  font: normal normal normal 14px/1 FontAwesome;\n  font-size: inherit;\n  text-rendering: auto;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n  transform: translate(0, 0);\n}\n\n/* makes the font 33% larger relative to the icon container */\n.fa-lg {\n  font-size: 1.33333333em;\n  line-height: 0.75em;\n  vertical-align: -15%;\n}\n\n.fa-2x {\n  font-size: 2em;\n}\n\n.fa-3x {\n  font-size: 3em;\n}\n\n.fa-4x {\n  font-size: 4em;\n}\n\n.fa-5x {\n  font-size: 5em;\n}\n\n.fa-fw {\n  width: 1.28571429em;\n  text-align: center;\n}\n\n.fa-ul {\n  padding-left: 0;\n  margin-left: 2.14285714em;\n  list-style-type: none;\n}\n\n.fa-ul > li {\n  position: relative;\n}\n\n.fa-li {\n  position: absolute;\n  left: -2.14285714em;\n  width: 2.14285714em;\n  top: 0.14285714em;\n  text-align: center;\n}\n\n.fa-li.fa-lg {\n  left: -1.85714286em;\n}\n\n.fa-border {\n  padding: .2em .25em .15em;\n  border: solid 0.08em #eeeeee;\n  border-radius: .1em;\n}\n\n.pull-right {\n  float: right;\n}\n\n.pull-left {\n  float: left;\n}\n\n.fa.pull-left {\n  margin-right: .3em;\n}\n\n.fa.pull-right {\n  margin-left: .3em;\n}\n\n.fa-spin {\n  -webkit-animation: fa-spin 2s infinite linear;\n  animation: fa-spin 2s infinite linear;\n}\n\n.fa-pulse {\n  -webkit-animation: fa-spin 1s infinite steps(8);\n  animation: fa-spin 1s infinite steps(8);\n}\n\n@-webkit-keyframes fa-spin {\n  0% {\n    -webkit-transform: rotate(0deg);\n    transform: rotate(0deg);\n  }\n  100% {\n    -webkit-transform: rotate(359deg);\n    transform: rotate(359deg);\n  }\n}\n@keyframes fa-spin {\n  0% {\n    -webkit-transform: rotate(0deg);\n    transform: rotate(0deg);\n  }\n  100% {\n    -webkit-transform: rotate(359deg);\n    transform: rotate(359deg);\n  }\n}\n.fa-rotate-90 {\n  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1);\n  -webkit-transform: rotate(90deg);\n  -ms-transform: rotate(90deg);\n  transform: rotate(90deg);\n}\n\n.fa-rotate-180 {\n  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2);\n  -webkit-transform: rotate(180deg);\n  -ms-transform: rotate(180deg);\n  transform: rotate(180deg);\n}\n\n.fa-rotate-270 {\n  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3);\n  -webkit-transform: rotate(270deg);\n  -ms-transform: rotate(270deg);\n  transform: rotate(270deg);\n}\n\n.fa-flip-horizontal {\n  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);\n  -webkit-transform: scale(-1, 1);\n  -ms-transform: scale(-1, 1);\n  transform: scale(-1, 1);\n}\n\n.fa-flip-vertical {\n  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);\n  -webkit-transform: scale(1, -1);\n  -ms-transform: scale(1, -1);\n  transform: scale(1, -1);\n}\n\n:root .fa-rotate-90,\n:root .fa-rotate-180,\n:root .fa-rotate-270,\n:root .fa-flip-horizontal,\n:root .fa-flip-vertical {\n  filter: none;\n}\n\n.fa-stack {\n  position: relative;\n  display: inline-block;\n  width: 2em;\n  height: 2em;\n  line-height: 2em;\n  vertical-align: middle;\n}\n\n.fa-stack-1x,\n.fa-stack-2x {\n  position: absolute;\n  left: 0;\n  width: 100%;\n  text-align: center;\n}\n\n.fa-stack-1x {\n  line-height: inherit;\n}\n\n.fa-stack-2x {\n  font-size: 2em;\n}\n\n.fa-inverse {\n  color: #ffffff;\n}\n\n/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen\n   readers do not read off random characters that represent icons */\n.fa-glass:before {\n  content: \"\\f000\";\n}\n\n.fa-music:before {\n  content: \"\\f001\";\n}\n\n.fa-search:before {\n  content: \"\\f002\";\n}\n\n.fa-envelope-o:before {\n  content: \"\\f003\";\n}\n\n.fa-heart:before {\n  content: \"\\f004\";\n}\n\n.fa-star:before {\n  content: \"\\f005\";\n}\n\n.fa-star-o:before {\n  content: \"\\f006\";\n}\n\n.fa-user:before {\n  content: \"\\f007\";\n}\n\n.fa-film:before {\n  content: \"\\f008\";\n}\n\n.fa-th-large:before {\n  content: \"\\f009\";\n}\n\n.fa-th:before {\n  content: \"\\f00a\";\n}\n\n.fa-th-list:before {\n  content: \"\\f00b\";\n}\n\n.fa-check:before {\n  content: \"\\f00c\";\n}\n\n.fa-remove:before,\n.fa-close:before,\n.fa-times:before {\n  content: \"\\f00d\";\n}\n\n.fa-search-plus:before {\n  content: \"\\f00e\";\n}\n\n.fa-search-minus:before {\n  content: \"\\f010\";\n}\n\n.fa-power-off:before {\n  content: \"\\f011\";\n}\n\n.fa-signal:before {\n  content: \"\\f012\";\n}\n\n.fa-gear:before,\n.fa-cog:before {\n  content: \"\\f013\";\n}\n\n.fa-trash-o:before {\n  content: \"\\f014\";\n}\n\n.fa-home:before {\n  content: \"\\f015\";\n}\n\n.fa-file-o:before {\n  content: \"\\f016\";\n}\n\n.fa-clock-o:before {\n  content: \"\\f017\";\n}\n\n.fa-road:before {\n  content: \"\\f018\";\n}\n\n.fa-download:before {\n  content: \"\\f019\";\n}\n\n.fa-arrow-circle-o-down:before {\n  content: \"\\f01a\";\n}\n\n.fa-arrow-circle-o-up:before {\n  content: \"\\f01b\";\n}\n\n.fa-inbox:before {\n  content: \"\\f01c\";\n}\n\n.fa-play-circle-o:before {\n  content: \"\\f01d\";\n}\n\n.fa-rotate-right:before,\n.fa-repeat:before {\n  content: \"\\f01e\";\n}\n\n.fa-refresh:before {\n  content: \"\\f021\";\n}\n\n.fa-list-alt:before {\n  content: \"\\f022\";\n}\n\n.fa-lock:before {\n  content: \"\\f023\";\n}\n\n.fa-flag:before {\n  content: \"\\f024\";\n}\n\n.fa-headphones:before {\n  content: \"\\f025\";\n}\n\n.fa-volume-off:before {\n  content: \"\\f026\";\n}\n\n.fa-volume-down:before {\n  content: \"\\f027\";\n}\n\n.fa-volume-up:before {\n  content: \"\\f028\";\n}\n\n.fa-qrcode:before {\n  content: \"\\f029\";\n}\n\n.fa-barcode:before {\n  content: \"\\f02a\";\n}\n\n.fa-tag:before {\n  content: \"\\f02b\";\n}\n\n.fa-tags:before {\n  content: \"\\f02c\";\n}\n\n.fa-book:before {\n  content: \"\\f02d\";\n}\n\n.fa-bookmark:before {\n  content: \"\\f02e\";\n}\n\n.fa-print:before {\n  content: \"\\f02f\";\n}\n\n.fa-camera:before {\n  content: \"\\f030\";\n}\n\n.fa-font:before {\n  content: \"\\f031\";\n}\n\n.fa-bold:before {\n  content: \"\\f032\";\n}\n\n.fa-italic:before {\n  content: \"\\f033\";\n}\n\n.fa-text-height:before {\n  content: \"\\f034\";\n}\n\n.fa-text-width:before {\n  content: \"\\f035\";\n}\n\n.fa-align-left:before {\n  content: \"\\f036\";\n}\n\n.fa-align-center:before {\n  content: \"\\f037\";\n}\n\n.fa-align-right:before {\n  content: \"\\f038\";\n}\n\n.fa-align-justify:before {\n  content: \"\\f039\";\n}\n\n.fa-list:before {\n  content: \"\\f03a\";\n}\n\n.fa-dedent:before,\n.fa-outdent:before {\n  content: \"\\f03b\";\n}\n\n.fa-indent:before {\n  content: \"\\f03c\";\n}\n\n.fa-video-camera:before {\n  content: \"\\f03d\";\n}\n\n.fa-photo:before,\n.fa-image:before,\n.fa-picture-o:before {\n  content: \"\\f03e\";\n}\n\n.fa-pencil:before {\n  content: \"\\f040\";\n}\n\n.fa-map-marker:before {\n  content: \"\\f041\";\n}\n\n.fa-adjust:before {\n  content: \"\\f042\";\n}\n\n.fa-tint:before {\n  content: \"\\f043\";\n}\n\n.fa-edit:before,\n.fa-pencil-square-o:before {\n  content: \"\\f044\";\n}\n\n.fa-share-square-o:before {\n  content: \"\\f045\";\n}\n\n.fa-check-square-o:before {\n  content: \"\\f046\";\n}\n\n.fa-arrows:before {\n  content: \"\\f047\";\n}\n\n.fa-step-backward:before {\n  content: \"\\f048\";\n}\n\n.fa-fast-backward:before {\n  content: \"\\f049\";\n}\n\n.fa-backward:before {\n  content: \"\\f04a\";\n}\n\n.fa-play:before {\n  content: \"\\f04b\";\n}\n\n.fa-pause:before {\n  content: \"\\f04c\";\n}\n\n.fa-stop:before {\n  content: \"\\f04d\";\n}\n\n.fa-forward:before {\n  content: \"\\f04e\";\n}\n\n.fa-fast-forward:before {\n  content: \"\\f050\";\n}\n\n.fa-step-forward:before {\n  content: \"\\f051\";\n}\n\n.fa-eject:before {\n  content: \"\\f052\";\n}\n\n.fa-chevron-left:before {\n  content: \"\\f053\";\n}\n\n.fa-chevron-right:before {\n  content: \"\\f054\";\n}\n\n.fa-plus-circle:before {\n  content: \"\\f055\";\n}\n\n.fa-minus-circle:before {\n  content: \"\\f056\";\n}\n\n.fa-times-circle:before {\n  content: \"\\f057\";\n}\n\n.fa-check-circle:before {\n  content: \"\\f058\";\n}\n\n.fa-question-circle:before {\n  content: \"\\f059\";\n}\n\n.fa-info-circle:before {\n  content: \"\\f05a\";\n}\n\n.fa-crosshairs:before {\n  content: \"\\f05b\";\n}\n\n.fa-times-circle-o:before {\n  content: \"\\f05c\";\n}\n\n.fa-check-circle-o:before {\n  content: \"\\f05d\";\n}\n\n.fa-ban:before {\n  content: \"\\f05e\";\n}\n\n.fa-arrow-left:before {\n  content: \"\\f060\";\n}\n\n.fa-arrow-right:before {\n  content: \"\\f061\";\n}\n\n.fa-arrow-up:before {\n  content: \"\\f062\";\n}\n\n.fa-arrow-down:before {\n  content: \"\\f063\";\n}\n\n.fa-mail-forward:before,\n.fa-share:before {\n  content: \"\\f064\";\n}\n\n.fa-expand:before {\n  content: \"\\f065\";\n}\n\n.fa-compress:before {\n  content: \"\\f066\";\n}\n\n.fa-plus:before {\n  content: \"\\f067\";\n}\n\n.fa-minus:before {\n  content: \"\\f068\";\n}\n\n.fa-asterisk:before {\n  content: \"\\f069\";\n}\n\n.fa-exclamation-circle:before {\n  content: \"\\f06a\";\n}\n\n.fa-gift:before {\n  content: \"\\f06b\";\n}\n\n.fa-leaf:before {\n  content: \"\\f06c\";\n}\n\n.fa-fire:before {\n  content: \"\\f06d\";\n}\n\n.fa-eye:before {\n  content: \"\\f06e\";\n}\n\n.fa-eye-slash:before {\n  content: \"\\f070\";\n}\n\n.fa-warning:before,\n.fa-exclamation-triangle:before {\n  content: \"\\f071\";\n}\n\n.fa-plane:before {\n  content: \"\\f072\";\n}\n\n.fa-calendar:before {\n  content: \"\\f073\";\n}\n\n.fa-random:before {\n  content: \"\\f074\";\n}\n\n.fa-comment:before {\n  content: \"\\f075\";\n}\n\n.fa-magnet:before {\n  content: \"\\f076\";\n}\n\n.fa-chevron-up:before {\n  content: \"\\f077\";\n}\n\n.fa-chevron-down:before {\n  content: \"\\f078\";\n}\n\n.fa-retweet:before {\n  content: \"\\f079\";\n}\n\n.fa-shopping-cart:before {\n  content: \"\\f07a\";\n}\n\n.fa-folder:before {\n  content: \"\\f07b\";\n}\n\n.fa-folder-open:before {\n  content: \"\\f07c\";\n}\n\n.fa-arrows-v:before {\n  content: \"\\f07d\";\n}\n\n.fa-arrows-h:before {\n  content: \"\\f07e\";\n}\n\n.fa-bar-chart-o:before,\n.fa-bar-chart:before {\n  content: \"\\f080\";\n}\n\n.fa-twitter-square:before {\n  content: \"\\f081\";\n}\n\n.fa-facebook-square:before {\n  content: \"\\f082\";\n}\n\n.fa-camera-retro:before {\n  content: \"\\f083\";\n}\n\n.fa-key:before {\n  content: \"\\f084\";\n}\n\n.fa-gears:before,\n.fa-cogs:before {\n  content: \"\\f085\";\n}\n\n.fa-comments:before {\n  content: \"\\f086\";\n}\n\n.fa-thumbs-o-up:before {\n  content: \"\\f087\";\n}\n\n.fa-thumbs-o-down:before {\n  content: \"\\f088\";\n}\n\n.fa-star-half:before {\n  content: \"\\f089\";\n}\n\n.fa-heart-o:before {\n  content: \"\\f08a\";\n}\n\n.fa-sign-out:before {\n  content: \"\\f08b\";\n}\n\n.fa-linkedin-square:before {\n  content: \"\\f08c\";\n}\n\n.fa-thumb-tack:before {\n  content: \"\\f08d\";\n}\n\n.fa-external-link:before {\n  content: \"\\f08e\";\n}\n\n.fa-sign-in:before {\n  content: \"\\f090\";\n}\n\n.fa-trophy:before {\n  content: \"\\f091\";\n}\n\n.fa-github-square:before {\n  content: \"\\f092\";\n}\n\n.fa-upload:before {\n  content: \"\\f093\";\n}\n\n.fa-lemon-o:before {\n  content: \"\\f094\";\n}\n\n.fa-phone:before {\n  content: \"\\f095\";\n}\n\n.fa-square-o:before {\n  content: \"\\f096\";\n}\n\n.fa-bookmark-o:before {\n  content: \"\\f097\";\n}\n\n.fa-phone-square:before {\n  content: \"\\f098\";\n}\n\n.fa-twitter:before {\n  content: \"\\f099\";\n}\n\n.fa-facebook-f:before,\n.fa-facebook:before {\n  content: \"\\f09a\";\n}\n\n.fa-github:before {\n  content: \"\\f09b\";\n}\n\n.fa-unlock:before {\n  content: \"\\f09c\";\n}\n\n.fa-credit-card:before {\n  content: \"\\f09d\";\n}\n\n.fa-rss:before {\n  content: \"\\f09e\";\n}\n\n.fa-hdd-o:before {\n  content: \"\\f0a0\";\n}\n\n.fa-bullhorn:before {\n  content: \"\\f0a1\";\n}\n\n.fa-bell:before {\n  content: \"\\f0f3\";\n}\n\n.fa-certificate:before {\n  content: \"\\f0a3\";\n}\n\n.fa-hand-o-right:before {\n  content: \"\\f0a4\";\n}\n\n.fa-hand-o-left:before {\n  content: \"\\f0a5\";\n}\n\n.fa-hand-o-up:before {\n  content: \"\\f0a6\";\n}\n\n.fa-hand-o-down:before {\n  content: \"\\f0a7\";\n}\n\n.fa-arrow-circle-left:before {\n  content: \"\\f0a8\";\n}\n\n.fa-arrow-circle-right:before {\n  content: \"\\f0a9\";\n}\n\n.fa-arrow-circle-up:before {\n  content: \"\\f0aa\";\n}\n\n.fa-arrow-circle-down:before {\n  content: \"\\f0ab\";\n}\n\n.fa-globe:before {\n  content: \"\\f0ac\";\n}\n\n.fa-wrench:before {\n  content: \"\\f0ad\";\n}\n\n.fa-tasks:before {\n  content: \"\\f0ae\";\n}\n\n.fa-filter:before {\n  content: \"\\f0b0\";\n}\n\n.fa-briefcase:before {\n  content: \"\\f0b1\";\n}\n\n.fa-arrows-alt:before {\n  content: \"\\f0b2\";\n}\n\n.fa-group:before,\n.fa-users:before {\n  content: \"\\f0c0\";\n}\n\n.fa-chain:before,\n.fa-link:before {\n  content: \"\\f0c1\";\n}\n\n.fa-cloud:before {\n  content: \"\\f0c2\";\n}\n\n.fa-flask:before {\n  content: \"\\f0c3\";\n}\n\n.fa-cut:before,\n.fa-scissors:before {\n  content: \"\\f0c4\";\n}\n\n.fa-copy:before,\n.fa-files-o:before {\n  content: \"\\f0c5\";\n}\n\n.fa-paperclip:before {\n  content: \"\\f0c6\";\n}\n\n.fa-save:before,\n.fa-floppy-o:before {\n  content: \"\\f0c7\";\n}\n\n.fa-square:before {\n  content: \"\\f0c8\";\n}\n\n.fa-navicon:before,\n.fa-reorder:before,\n.fa-bars:before {\n  content: \"\\f0c9\";\n}\n\n.fa-list-ul:before {\n  content: \"\\f0ca\";\n}\n\n.fa-list-ol:before {\n  content: \"\\f0cb\";\n}\n\n.fa-strikethrough:before {\n  content: \"\\f0cc\";\n}\n\n.fa-underline:before {\n  content: \"\\f0cd\";\n}\n\n.fa-table:before {\n  content: \"\\f0ce\";\n}\n\n.fa-magic:before {\n  content: \"\\f0d0\";\n}\n\n.fa-truck:before {\n  content: \"\\f0d1\";\n}\n\n.fa-pinterest:before {\n  content: \"\\f0d2\";\n}\n\n.fa-pinterest-square:before {\n  content: \"\\f0d3\";\n}\n\n.fa-google-plus-square:before {\n  content: \"\\f0d4\";\n}\n\n.fa-google-plus:before {\n  content: \"\\f0d5\";\n}\n\n.fa-money:before {\n  content: \"\\f0d6\";\n}\n\n.fa-caret-down:before {\n  content: \"\\f0d7\";\n}\n\n.fa-caret-up:before {\n  content: \"\\f0d8\";\n}\n\n.fa-caret-left:before {\n  content: \"\\f0d9\";\n}\n\n.fa-caret-right:before {\n  content: \"\\f0da\";\n}\n\n.fa-columns:before {\n  content: \"\\f0db\";\n}\n\n.fa-unsorted:before,\n.fa-sort:before {\n  content: \"\\f0dc\";\n}\n\n.fa-sort-down:before,\n.fa-sort-desc:before {\n  content: \"\\f0dd\";\n}\n\n.fa-sort-up:before,\n.fa-sort-asc:before {\n  content: \"\\f0de\";\n}\n\n.fa-envelope:before {\n  content: \"\\f0e0\";\n}\n\n.fa-linkedin:before {\n  content: \"\\f0e1\";\n}\n\n.fa-rotate-left:before,\n.fa-undo:before {\n  content: \"\\f0e2\";\n}\n\n.fa-legal:before,\n.fa-gavel:before {\n  content: \"\\f0e3\";\n}\n\n.fa-dashboard:before,\n.fa-tachometer:before {\n  content: \"\\f0e4\";\n}\n\n.fa-comment-o:before {\n  content: \"\\f0e5\";\n}\n\n.fa-comments-o:before {\n  content: \"\\f0e6\";\n}\n\n.fa-flash:before,\n.fa-bolt:before {\n  content: \"\\f0e7\";\n}\n\n.fa-sitemap:before {\n  content: \"\\f0e8\";\n}\n\n.fa-umbrella:before {\n  content: \"\\f0e9\";\n}\n\n.fa-paste:before,\n.fa-clipboard:before {\n  content: \"\\f0ea\";\n}\n\n.fa-lightbulb-o:before {\n  content: \"\\f0eb\";\n}\n\n.fa-exchange:before {\n  content: \"\\f0ec\";\n}\n\n.fa-cloud-download:before {\n  content: \"\\f0ed\";\n}\n\n.fa-cloud-upload:before {\n  content: \"\\f0ee\";\n}\n\n.fa-user-md:before {\n  content: \"\\f0f0\";\n}\n\n.fa-stethoscope:before {\n  content: \"\\f0f1\";\n}\n\n.fa-suitcase:before {\n  content: \"\\f0f2\";\n}\n\n.fa-bell-o:before {\n  content: \"\\f0a2\";\n}\n\n.fa-coffee:before {\n  content: \"\\f0f4\";\n}\n\n.fa-cutlery:before {\n  content: \"\\f0f5\";\n}\n\n.fa-file-text-o:before {\n  content: \"\\f0f6\";\n}\n\n.fa-building-o:before {\n  content: \"\\f0f7\";\n}\n\n.fa-hospital-o:before {\n  content: \"\\f0f8\";\n}\n\n.fa-ambulance:before {\n  content: \"\\f0f9\";\n}\n\n.fa-medkit:before {\n  content: \"\\f0fa\";\n}\n\n.fa-fighter-jet:before {\n  content: \"\\f0fb\";\n}\n\n.fa-beer:before {\n  content: \"\\f0fc\";\n}\n\n.fa-h-square:before {\n  content: \"\\f0fd\";\n}\n\n.fa-plus-square:before {\n  content: \"\\f0fe\";\n}\n\n.fa-angle-double-left:before {\n  content: \"\\f100\";\n}\n\n.fa-angle-double-right:before {\n  content: \"\\f101\";\n}\n\n.fa-angle-double-up:before {\n  content: \"\\f102\";\n}\n\n.fa-angle-double-down:before {\n  content: \"\\f103\";\n}\n\n.fa-angle-left:before {\n  content: \"\\f104\";\n}\n\n.fa-angle-right:before {\n  content: \"\\f105\";\n}\n\n.fa-angle-up:before {\n  content: \"\\f106\";\n}\n\n.fa-angle-down:before {\n  content: \"\\f107\";\n}\n\n.fa-desktop:before {\n  content: \"\\f108\";\n}\n\n.fa-laptop:before {\n  content: \"\\f109\";\n}\n\n.fa-tablet:before {\n  content: \"\\f10a\";\n}\n\n.fa-mobile-phone:before,\n.fa-mobile:before {\n  content: \"\\f10b\";\n}\n\n.fa-circle-o:before {\n  content: \"\\f10c\";\n}\n\n.fa-quote-left:before {\n  content: \"\\f10d\";\n}\n\n.fa-quote-right:before {\n  content: \"\\f10e\";\n}\n\n.fa-spinner:before {\n  content: \"\\f110\";\n}\n\n.fa-circle:before {\n  content: \"\\f111\";\n}\n\n.fa-mail-reply:before,\n.fa-reply:before {\n  content: \"\\f112\";\n}\n\n.fa-github-alt:before {\n  content: \"\\f113\";\n}\n\n.fa-folder-o:before {\n  content: \"\\f114\";\n}\n\n.fa-folder-open-o:before {\n  content: \"\\f115\";\n}\n\n.fa-smile-o:before {\n  content: \"\\f118\";\n}\n\n.fa-frown-o:before {\n  content: \"\\f119\";\n}\n\n.fa-meh-o:before {\n  content: \"\\f11a\";\n}\n\n.fa-gamepad:before {\n  content: \"\\f11b\";\n}\n\n.fa-keyboard-o:before {\n  content: \"\\f11c\";\n}\n\n.fa-flag-o:before {\n  content: \"\\f11d\";\n}\n\n.fa-flag-checkered:before {\n  content: \"\\f11e\";\n}\n\n.fa-terminal:before {\n  content: \"\\f120\";\n}\n\n.fa-code:before {\n  content: \"\\f121\";\n}\n\n.fa-mail-reply-all:before,\n.fa-reply-all:before {\n  content: \"\\f122\";\n}\n\n.fa-star-half-empty:before,\n.fa-star-half-full:before,\n.fa-star-half-o:before {\n  content: \"\\f123\";\n}\n\n.fa-location-arrow:before {\n  content: \"\\f124\";\n}\n\n.fa-crop:before {\n  content: \"\\f125\";\n}\n\n.fa-code-fork:before {\n  content: \"\\f126\";\n}\n\n.fa-unlink:before,\n.fa-chain-broken:before {\n  content: \"\\f127\";\n}\n\n.fa-question:before {\n  content: \"\\f128\";\n}\n\n.fa-info:before {\n  content: \"\\f129\";\n}\n\n.fa-exclamation:before {\n  content: \"\\f12a\";\n}\n\n.fa-superscript:before {\n  content: \"\\f12b\";\n}\n\n.fa-subscript:before {\n  content: \"\\f12c\";\n}\n\n.fa-eraser:before {\n  content: \"\\f12d\";\n}\n\n.fa-puzzle-piece:before {\n  content: \"\\f12e\";\n}\n\n.fa-microphone:before {\n  content: \"\\f130\";\n}\n\n.fa-microphone-slash:before {\n  content: \"\\f131\";\n}\n\n.fa-shield:before {\n  content: \"\\f132\";\n}\n\n.fa-calendar-o:before {\n  content: \"\\f133\";\n}\n\n.fa-fire-extinguisher:before {\n  content: \"\\f134\";\n}\n\n.fa-rocket:before {\n  content: \"\\f135\";\n}\n\n.fa-maxcdn:before {\n  content: \"\\f136\";\n}\n\n.fa-chevron-circle-left:before {\n  content: \"\\f137\";\n}\n\n.fa-chevron-circle-right:before {\n  content: \"\\f138\";\n}\n\n.fa-chevron-circle-up:before {\n  content: \"\\f139\";\n}\n\n.fa-chevron-circle-down:before {\n  content: \"\\f13a\";\n}\n\n.fa-html5:before {\n  content: \"\\f13b\";\n}\n\n.fa-css3:before {\n  content: \"\\f13c\";\n}\n\n.fa-anchor:before {\n  content: \"\\f13d\";\n}\n\n.fa-unlock-alt:before {\n  content: \"\\f13e\";\n}\n\n.fa-bullseye:before {\n  content: \"\\f140\";\n}\n\n.fa-ellipsis-h:before {\n  content: \"\\f141\";\n}\n\n.fa-ellipsis-v:before {\n  content: \"\\f142\";\n}\n\n.fa-rss-square:before {\n  content: \"\\f143\";\n}\n\n.fa-play-circle:before {\n  content: \"\\f144\";\n}\n\n.fa-ticket:before {\n  content: \"\\f145\";\n}\n\n.fa-minus-square:before {\n  content: \"\\f146\";\n}\n\n.fa-minus-square-o:before {\n  content: \"\\f147\";\n}\n\n.fa-level-up:before {\n  content: \"\\f148\";\n}\n\n.fa-level-down:before {\n  content: \"\\f149\";\n}\n\n.fa-check-square:before {\n  content: \"\\f14a\";\n}\n\n.fa-pencil-square:before {\n  content: \"\\f14b\";\n}\n\n.fa-external-link-square:before {\n  content: \"\\f14c\";\n}\n\n.fa-share-square:before {\n  content: \"\\f14d\";\n}\n\n.fa-compass:before {\n  content: \"\\f14e\";\n}\n\n.fa-toggle-down:before,\n.fa-caret-square-o-down:before {\n  content: \"\\f150\";\n}\n\n.fa-toggle-up:before,\n.fa-caret-square-o-up:before {\n  content: \"\\f151\";\n}\n\n.fa-toggle-right:before,\n.fa-caret-square-o-right:before {\n  content: \"\\f152\";\n}\n\n.fa-euro:before,\n.fa-eur:before {\n  content: \"\\f153\";\n}\n\n.fa-gbp:before {\n  content: \"\\f154\";\n}\n\n.fa-dollar:before,\n.fa-usd:before {\n  content: \"\\f155\";\n}\n\n.fa-rupee:before,\n.fa-inr:before {\n  content: \"\\f156\";\n}\n\n.fa-cny:before,\n.fa-rmb:before,\n.fa-yen:before,\n.fa-jpy:before {\n  content: \"\\f157\";\n}\n\n.fa-ruble:before,\n.fa-rouble:before,\n.fa-rub:before {\n  content: \"\\f158\";\n}\n\n.fa-won:before,\n.fa-krw:before {\n  content: \"\\f159\";\n}\n\n.fa-bitcoin:before,\n.fa-btc:before {\n  content: \"\\f15a\";\n}\n\n.fa-file:before {\n  content: \"\\f15b\";\n}\n\n.fa-file-text:before {\n  content: \"\\f15c\";\n}\n\n.fa-sort-alpha-asc:before {\n  content: \"\\f15d\";\n}\n\n.fa-sort-alpha-desc:before {\n  content: \"\\f15e\";\n}\n\n.fa-sort-amount-asc:before {\n  content: \"\\f160\";\n}\n\n.fa-sort-amount-desc:before {\n  content: \"\\f161\";\n}\n\n.fa-sort-numeric-asc:before {\n  content: \"\\f162\";\n}\n\n.fa-sort-numeric-desc:before {\n  content: \"\\f163\";\n}\n\n.fa-thumbs-up:before {\n  content: \"\\f164\";\n}\n\n.fa-thumbs-down:before {\n  content: \"\\f165\";\n}\n\n.fa-youtube-square:before {\n  content: \"\\f166\";\n}\n\n.fa-youtube:before {\n  content: \"\\f167\";\n}\n\n.fa-xing:before {\n  content: \"\\f168\";\n}\n\n.fa-xing-square:before {\n  content: \"\\f169\";\n}\n\n.fa-youtube-play:before {\n  content: \"\\f16a\";\n}\n\n.fa-dropbox:before {\n  content: \"\\f16b\";\n}\n\n.fa-stack-overflow:before {\n  content: \"\\f16c\";\n}\n\n.fa-instagram:before {\n  content: \"\\f16d\";\n}\n\n.fa-flickr:before {\n  content: \"\\f16e\";\n}\n\n.fa-adn:before {\n  content: \"\\f170\";\n}\n\n.fa-bitbucket:before {\n  content: \"\\f171\";\n}\n\n.fa-bitbucket-square:before {\n  content: \"\\f172\";\n}\n\n.fa-tumblr:before {\n  content: \"\\f173\";\n}\n\n.fa-tumblr-square:before {\n  content: \"\\f174\";\n}\n\n.fa-long-arrow-down:before {\n  content: \"\\f175\";\n}\n\n.fa-long-arrow-up:before {\n  content: \"\\f176\";\n}\n\n.fa-long-arrow-left:before {\n  content: \"\\f177\";\n}\n\n.fa-long-arrow-right:before {\n  content: \"\\f178\";\n}\n\n.fa-apple:before {\n  content: \"\\f179\";\n}\n\n.fa-windows:before {\n  content: \"\\f17a\";\n}\n\n.fa-android:before {\n  content: \"\\f17b\";\n}\n\n.fa-linux:before {\n  content: \"\\f17c\";\n}\n\n.fa-dribbble:before {\n  content: \"\\f17d\";\n}\n\n.fa-skype:before {\n  content: \"\\f17e\";\n}\n\n.fa-foursquare:before {\n  content: \"\\f180\";\n}\n\n.fa-trello:before {\n  content: \"\\f181\";\n}\n\n.fa-female:before {\n  content: \"\\f182\";\n}\n\n.fa-male:before {\n  content: \"\\f183\";\n}\n\n.fa-gittip:before,\n.fa-gratipay:before {\n  content: \"\\f184\";\n}\n\n.fa-sun-o:before {\n  content: \"\\f185\";\n}\n\n.fa-moon-o:before {\n  content: \"\\f186\";\n}\n\n.fa-archive:before {\n  content: \"\\f187\";\n}\n\n.fa-bug:before {\n  content: \"\\f188\";\n}\n\n.fa-vk:before {\n  content: \"\\f189\";\n}\n\n.fa-weibo:before {\n  content: \"\\f18a\";\n}\n\n.fa-renren:before {\n  content: \"\\f18b\";\n}\n\n.fa-pagelines:before {\n  content: \"\\f18c\";\n}\n\n.fa-stack-exchange:before {\n  content: \"\\f18d\";\n}\n\n.fa-arrow-circle-o-right:before {\n  content: \"\\f18e\";\n}\n\n.fa-arrow-circle-o-left:before {\n  content: \"\\f190\";\n}\n\n.fa-toggle-left:before,\n.fa-caret-square-o-left:before {\n  content: \"\\f191\";\n}\n\n.fa-dot-circle-o:before {\n  content: \"\\f192\";\n}\n\n.fa-wheelchair:before {\n  content: \"\\f193\";\n}\n\n.fa-vimeo-square:before {\n  content: \"\\f194\";\n}\n\n.fa-turkish-lira:before,\n.fa-try:before {\n  content: \"\\f195\";\n}\n\n.fa-plus-square-o:before {\n  content: \"\\f196\";\n}\n\n.fa-space-shuttle:before {\n  content: \"\\f197\";\n}\n\n.fa-slack:before {\n  content: \"\\f198\";\n}\n\n.fa-envelope-square:before {\n  content: \"\\f199\";\n}\n\n.fa-wordpress:before {\n  content: \"\\f19a\";\n}\n\n.fa-openid:before {\n  content: \"\\f19b\";\n}\n\n.fa-institution:before,\n.fa-bank:before,\n.fa-university:before {\n  content: \"\\f19c\";\n}\n\n.fa-mortar-board:before,\n.fa-graduation-cap:before {\n  content: \"\\f19d\";\n}\n\n.fa-yahoo:before {\n  content: \"\\f19e\";\n}\n\n.fa-google:before {\n  content: \"\\f1a0\";\n}\n\n.fa-reddit:before {\n  content: \"\\f1a1\";\n}\n\n.fa-reddit-square:before {\n  content: \"\\f1a2\";\n}\n\n.fa-stumbleupon-circle:before {\n  content: \"\\f1a3\";\n}\n\n.fa-stumbleupon:before {\n  content: \"\\f1a4\";\n}\n\n.fa-delicious:before {\n  content: \"\\f1a5\";\n}\n\n.fa-digg:before {\n  content: \"\\f1a6\";\n}\n\n.fa-pied-piper:before {\n  content: \"\\f1a7\";\n}\n\n.fa-pied-piper-alt:before {\n  content: \"\\f1a8\";\n}\n\n.fa-drupal:before {\n  content: \"\\f1a9\";\n}\n\n.fa-joomla:before {\n  content: \"\\f1aa\";\n}\n\n.fa-language:before {\n  content: \"\\f1ab\";\n}\n\n.fa-fax:before {\n  content: \"\\f1ac\";\n}\n\n.fa-building:before {\n  content: \"\\f1ad\";\n}\n\n.fa-child:before {\n  content: \"\\f1ae\";\n}\n\n.fa-paw:before {\n  content: \"\\f1b0\";\n}\n\n.fa-spoon:before {\n  content: \"\\f1b1\";\n}\n\n.fa-cube:before {\n  content: \"\\f1b2\";\n}\n\n.fa-cubes:before {\n  content: \"\\f1b3\";\n}\n\n.fa-behance:before {\n  content: \"\\f1b4\";\n}\n\n.fa-behance-square:before {\n  content: \"\\f1b5\";\n}\n\n.fa-steam:before {\n  content: \"\\f1b6\";\n}\n\n.fa-steam-square:before {\n  content: \"\\f1b7\";\n}\n\n.fa-recycle:before {\n  content: \"\\f1b8\";\n}\n\n.fa-automobile:before,\n.fa-car:before {\n  content: \"\\f1b9\";\n}\n\n.fa-cab:before,\n.fa-taxi:before {\n  content: \"\\f1ba\";\n}\n\n.fa-tree:before {\n  content: \"\\f1bb\";\n}\n\n.fa-spotify:before {\n  content: \"\\f1bc\";\n}\n\n.fa-deviantart:before {\n  content: \"\\f1bd\";\n}\n\n.fa-soundcloud:before {\n  content: \"\\f1be\";\n}\n\n.fa-database:before {\n  content: \"\\f1c0\";\n}\n\n.fa-file-pdf-o:before {\n  content: \"\\f1c1\";\n}\n\n.fa-file-word-o:before {\n  content: \"\\f1c2\";\n}\n\n.fa-file-excel-o:before {\n  content: \"\\f1c3\";\n}\n\n.fa-file-powerpoint-o:before {\n  content: \"\\f1c4\";\n}\n\n.fa-file-photo-o:before,\n.fa-file-picture-o:before,\n.fa-file-image-o:before {\n  content: \"\\f1c5\";\n}\n\n.fa-file-zip-o:before,\n.fa-file-archive-o:before {\n  content: \"\\f1c6\";\n}\n\n.fa-file-sound-o:before,\n.fa-file-audio-o:before {\n  content: \"\\f1c7\";\n}\n\n.fa-file-movie-o:before,\n.fa-file-video-o:before {\n  content: \"\\f1c8\";\n}\n\n.fa-file-code-o:before {\n  content: \"\\f1c9\";\n}\n\n.fa-vine:before {\n  content: \"\\f1ca\";\n}\n\n.fa-codepen:before {\n  content: \"\\f1cb\";\n}\n\n.fa-jsfiddle:before {\n  content: \"\\f1cc\";\n}\n\n.fa-life-bouy:before,\n.fa-life-buoy:before,\n.fa-life-saver:before,\n.fa-support:before,\n.fa-life-ring:before {\n  content: \"\\f1cd\";\n}\n\n.fa-circle-o-notch:before {\n  content: \"\\f1ce\";\n}\n\n.fa-ra:before,\n.fa-rebel:before {\n  content: \"\\f1d0\";\n}\n\n.fa-ge:before,\n.fa-empire:before {\n  content: \"\\f1d1\";\n}\n\n.fa-git-square:before {\n  content: \"\\f1d2\";\n}\n\n.fa-git:before {\n  content: \"\\f1d3\";\n}\n\n.fa-hacker-news:before {\n  content: \"\\f1d4\";\n}\n\n.fa-tencent-weibo:before {\n  content: \"\\f1d5\";\n}\n\n.fa-qq:before {\n  content: \"\\f1d6\";\n}\n\n.fa-wechat:before,\n.fa-weixin:before {\n  content: \"\\f1d7\";\n}\n\n.fa-send:before,\n.fa-paper-plane:before {\n  content: \"\\f1d8\";\n}\n\n.fa-send-o:before,\n.fa-paper-plane-o:before {\n  content: \"\\f1d9\";\n}\n\n.fa-history:before {\n  content: \"\\f1da\";\n}\n\n.fa-genderless:before,\n.fa-circle-thin:before {\n  content: \"\\f1db\";\n}\n\n.fa-header:before {\n  content: \"\\f1dc\";\n}\n\n.fa-paragraph:before {\n  content: \"\\f1dd\";\n}\n\n.fa-sliders:before {\n  content: \"\\f1de\";\n}\n\n.fa-share-alt:before {\n  content: \"\\f1e0\";\n}\n\n.fa-share-alt-square:before {\n  content: \"\\f1e1\";\n}\n\n.fa-bomb:before {\n  content: \"\\f1e2\";\n}\n\n.fa-soccer-ball-o:before,\n.fa-futbol-o:before {\n  content: \"\\f1e3\";\n}\n\n.fa-tty:before {\n  content: \"\\f1e4\";\n}\n\n.fa-binoculars:before {\n  content: \"\\f1e5\";\n}\n\n.fa-plug:before {\n  content: \"\\f1e6\";\n}\n\n.fa-slideshare:before {\n  content: \"\\f1e7\";\n}\n\n.fa-twitch:before {\n  content: \"\\f1e8\";\n}\n\n.fa-yelp:before {\n  content: \"\\f1e9\";\n}\n\n.fa-newspaper-o:before {\n  content: \"\\f1ea\";\n}\n\n.fa-wifi:before {\n  content: \"\\f1eb\";\n}\n\n.fa-calculator:before {\n  content: \"\\f1ec\";\n}\n\n.fa-paypal:before {\n  content: \"\\f1ed\";\n}\n\n.fa-google-wallet:before {\n  content: \"\\f1ee\";\n}\n\n.fa-cc-visa:before {\n  content: \"\\f1f0\";\n}\n\n.fa-cc-mastercard:before {\n  content: \"\\f1f1\";\n}\n\n.fa-cc-discover:before {\n  content: \"\\f1f2\";\n}\n\n.fa-cc-amex:before {\n  content: \"\\f1f3\";\n}\n\n.fa-cc-paypal:before {\n  content: \"\\f1f4\";\n}\n\n.fa-cc-stripe:before {\n  content: \"\\f1f5\";\n}\n\n.fa-bell-slash:before {\n  content: \"\\f1f6\";\n}\n\n.fa-bell-slash-o:before {\n  content: \"\\f1f7\";\n}\n\n.fa-trash:before {\n  content: \"\\f1f8\";\n}\n\n.fa-copyright:before {\n  content: \"\\f1f9\";\n}\n\n.fa-at:before {\n  content: \"\\f1fa\";\n}\n\n.fa-eyedropper:before {\n  content: \"\\f1fb\";\n}\n\n.fa-paint-brush:before {\n  content: \"\\f1fc\";\n}\n\n.fa-birthday-cake:before {\n  content: \"\\f1fd\";\n}\n\n.fa-area-chart:before {\n  content: \"\\f1fe\";\n}\n\n.fa-pie-chart:before {\n  content: \"\\f200\";\n}\n\n.fa-line-chart:before {\n  content: \"\\f201\";\n}\n\n.fa-lastfm:before {\n  content: \"\\f202\";\n}\n\n.fa-lastfm-square:before {\n  content: \"\\f203\";\n}\n\n.fa-toggle-off:before {\n  content: \"\\f204\";\n}\n\n.fa-toggle-on:before {\n  content: \"\\f205\";\n}\n\n.fa-bicycle:before {\n  content: \"\\f206\";\n}\n\n.fa-bus:before {\n  content: \"\\f207\";\n}\n\n.fa-ioxhost:before {\n  content: \"\\f208\";\n}\n\n.fa-angellist:before {\n  content: \"\\f209\";\n}\n\n.fa-cc:before {\n  content: \"\\f20a\";\n}\n\n.fa-shekel:before,\n.fa-sheqel:before,\n.fa-ils:before {\n  content: \"\\f20b\";\n}\n\n.fa-meanpath:before {\n  content: \"\\f20c\";\n}\n\n.fa-buysellads:before {\n  content: \"\\f20d\";\n}\n\n.fa-connectdevelop:before {\n  content: \"\\f20e\";\n}\n\n.fa-dashcube:before {\n  content: \"\\f210\";\n}\n\n.fa-forumbee:before {\n  content: \"\\f211\";\n}\n\n.fa-leanpub:before {\n  content: \"\\f212\";\n}\n\n.fa-sellsy:before {\n  content: \"\\f213\";\n}\n\n.fa-shirtsinbulk:before {\n  content: \"\\f214\";\n}\n\n.fa-simplybuilt:before {\n  content: \"\\f215\";\n}\n\n.fa-skyatlas:before {\n  content: \"\\f216\";\n}\n\n.fa-cart-plus:before {\n  content: \"\\f217\";\n}\n\n.fa-cart-arrow-down:before {\n  content: \"\\f218\";\n}\n\n.fa-diamond:before {\n  content: \"\\f219\";\n}\n\n.fa-ship:before {\n  content: \"\\f21a\";\n}\n\n.fa-user-secret:before {\n  content: \"\\f21b\";\n}\n\n.fa-motorcycle:before {\n  content: \"\\f21c\";\n}\n\n.fa-street-view:before {\n  content: \"\\f21d\";\n}\n\n.fa-heartbeat:before {\n  content: \"\\f21e\";\n}\n\n.fa-venus:before {\n  content: \"\\f221\";\n}\n\n.fa-mars:before {\n  content: \"\\f222\";\n}\n\n.fa-mercury:before {\n  content: \"\\f223\";\n}\n\n.fa-transgender:before {\n  content: \"\\f224\";\n}\n\n.fa-transgender-alt:before {\n  content: \"\\f225\";\n}\n\n.fa-venus-double:before {\n  content: \"\\f226\";\n}\n\n.fa-mars-double:before {\n  content: \"\\f227\";\n}\n\n.fa-venus-mars:before {\n  content: \"\\f228\";\n}\n\n.fa-mars-stroke:before {\n  content: \"\\f229\";\n}\n\n.fa-mars-stroke-v:before {\n  content: \"\\f22a\";\n}\n\n.fa-mars-stroke-h:before {\n  content: \"\\f22b\";\n}\n\n.fa-neuter:before {\n  content: \"\\f22c\";\n}\n\n.fa-facebook-official:before {\n  content: \"\\f230\";\n}\n\n.fa-pinterest-p:before {\n  content: \"\\f231\";\n}\n\n.fa-whatsapp:before {\n  content: \"\\f232\";\n}\n\n.fa-server:before {\n  content: \"\\f233\";\n}\n\n.fa-user-plus:before {\n  content: \"\\f234\";\n}\n\n.fa-user-times:before {\n  content: \"\\f235\";\n}\n\n.fa-hotel:before,\n.fa-bed:before {\n  content: \"\\f236\";\n}\n\n.fa-viacoin:before {\n  content: \"\\f237\";\n}\n\n.fa-train:before {\n  content: \"\\f238\";\n}\n\n.fa-subway:before {\n  content: \"\\f239\";\n}\n\n.fa-medium:before {\n  content: \"\\f23a\";\n}\n\n/*! prefixes.scss v0.1.0 | Author: Pandao | https://github.com/pandao/prefixes.scss | MIT license | Copyright (c) 2015 */\n@font-face {\n  font-family: 'editormd-logo';\n  src: url(\"../fonts/editormd-logo.eot?-5y8q6h\");\n  src: url(\".../fonts/editormd-logo.eot?#iefix-5y8q6h\") format(\"embedded-opentype\"), url(\"../fonts/editormd-logo.woff?-5y8q6h\") format(\"woff\"), url(\"../fonts/editormd-logo.ttf?-5y8q6h\") format(\"truetype\"), url(\"../fonts/editormd-logo.svg?-5y8q6h#icomoon\") format(\"svg\");\n  font-weight: normal;\n  font-style: normal;\n}\n.editormd-logo,\n.editormd-logo-1x,\n.editormd-logo-2x,\n.editormd-logo-3x,\n.editormd-logo-4x,\n.editormd-logo-5x,\n.editormd-logo-6x,\n.editormd-logo-7x,\n.editormd-logo-8x {\n  font-family: 'editormd-logo';\n  speak: none;\n  font-style: normal;\n  font-weight: normal;\n  font-variant: normal;\n  text-transform: none;\n  font-size: inherit;\n  line-height: 1;\n  display: inline-block;\n  text-rendering: auto;\n  vertical-align: inherit;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n.editormd-logo:before,\n.editormd-logo-1x:before,\n.editormd-logo-2x:before,\n.editormd-logo-3x:before,\n.editormd-logo-4x:before,\n.editormd-logo-5x:before,\n.editormd-logo-6x:before,\n.editormd-logo-7x:before,\n.editormd-logo-8x:before {\n  content: \"\\e1987\";\n  /* \n  HTML Entity &#xe1987; \n  example: <span class=\"editormd-logo\">&#xe1987;</span>\n  */\n}\n\n.editormd-logo-1x {\n  font-size: 1em;\n}\n\n.editormd-logo-lg {\n  font-size: 1.2em;\n}\n\n.editormd-logo-2x {\n  font-size: 2em;\n}\n\n.editormd-logo-3x {\n  font-size: 3em;\n}\n\n.editormd-logo-4x {\n  font-size: 4em;\n}\n\n.editormd-logo-5x {\n  font-size: 5em;\n}\n\n.editormd-logo-6x {\n  font-size: 6em;\n}\n\n.editormd-logo-7x {\n  font-size: 7em;\n}\n\n.editormd-logo-8x {\n  font-size: 8em;\n}\n\n.editormd-logo-color {\n  color: #2196F3;\n}\n\n/*! github-markdown-css | The MIT License (MIT) | Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com) | https://github.com/sindresorhus/github-markdown-css */\n@font-face {\n  font-family: octicons-anchor;\n  src: url(data:font/woff;charset=utf-8;base64,d09GRgABAAAAAAYcAA0AAAAACjQAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRlRNAAABMAAAABwAAAAca8vGTk9TLzIAAAFMAAAARAAAAFZG1VHVY21hcAAAAZAAAAA+AAABQgAP9AdjdnQgAAAB0AAAAAQAAAAEACICiGdhc3AAAAHUAAAACAAAAAj//wADZ2x5ZgAAAdwAAADRAAABEKyikaNoZWFkAAACsAAAAC0AAAA2AtXoA2hoZWEAAALgAAAAHAAAACQHngNFaG10eAAAAvwAAAAQAAAAEAwAACJsb2NhAAADDAAAAAoAAAAKALIAVG1heHAAAAMYAAAAHwAAACABEAB2bmFtZQAAAzgAAALBAAAFu3I9x/Nwb3N0AAAF/AAAAB0AAAAvaoFvbwAAAAEAAAAAzBdyYwAAAADP2IQvAAAAAM/bz7t4nGNgZGFgnMDAysDB1Ml0hoGBoR9CM75mMGLkYGBgYmBlZsAKAtJcUxgcPsR8iGF2+O/AEMPsznAYKMwIkgMA5REMOXicY2BgYGaAYBkGRgYQsAHyGMF8FgYFIM0ChED+h5j//yEk/3KoSgZGNgYYk4GRCUgwMaACRoZhDwCs7QgGAAAAIgKIAAAAAf//AAJ4nHWMMQrCQBBF/0zWrCCIKUQsTDCL2EXMohYGSSmorScInsRGL2DOYJe0Ntp7BK+gJ1BxF1stZvjz/v8DRghQzEc4kIgKwiAppcA9LtzKLSkdNhKFY3HF4lK69ExKslx7Xa+vPRVS43G98vG1DnkDMIBUgFN0MDXflU8tbaZOUkXUH0+U27RoRpOIyCKjbMCVejwypzJJG4jIwb43rfl6wbwanocrJm9XFYfskuVC5K/TPyczNU7b84CXcbxks1Un6H6tLH9vf2LRnn8Ax7A5WQAAAHicY2BkYGAA4teL1+yI57f5ysDNwgAC529f0kOmWRiYVgEpDgYmEA8AUzEKsQAAAHicY2BkYGB2+O/AEMPCAAJAkpEBFbAAADgKAe0EAAAiAAAAAAQAAAAEAAAAAAAAKgAqACoAiAAAeJxjYGRgYGBhsGFgYgABEMkFhAwM/xn0QAIAD6YBhwB4nI1Ty07cMBS9QwKlQapQW3VXySvEqDCZGbGaHULiIQ1FKgjWMxknMfLEke2A+IJu+wntrt/QbVf9gG75jK577Lg8K1qQPCfnnnt8fX1NRC/pmjrk/zprC+8D7tBy9DHgBXoWfQ44Av8t4Bj4Z8CLtBL9CniJluPXASf0Lm4CXqFX8Q84dOLnMB17N4c7tBo1AS/Qi+hTwBH4rwHHwN8DXqQ30XXAS7QaLwSc0Gn8NuAVWou/gFmnjLrEaEh9GmDdDGgL3B4JsrRPDU2hTOiMSuJUIdKQQayiAth69r6akSSFqIJuA19TrzCIaY8sIoxyrNIrL//pw7A2iMygkX5vDj+G+kuoLdX4GlGK/8Lnlz6/h9MpmoO9rafrz7ILXEHHaAx95s9lsI7AHNMBWEZHULnfAXwG9/ZqdzLI08iuwRloXE8kfhXYAvE23+23DU3t626rbs8/8adv+9DWknsHp3E17oCf+Z48rvEQNZ78paYM38qfk3v/u3l3u3GXN2Dmvmvpf1Srwk3pB/VSsp512bA/GG5i2WJ7wu430yQ5K3nFGiOqgtmSB5pJVSizwaacmUZzZhXLlZTq8qGGFY2YcSkqbth6aW1tRmlaCFs2016m5qn36SbJrqosG4uMV4aP2PHBmB3tjtmgN2izkGQyLWprekbIntJFing32a5rKWCN/SdSoga45EJykyQ7asZvHQ8PTm6cslIpwyeyjbVltNikc2HTR7YKh9LBl9DADC0U/jLcBZDKrMhUBfQBvXRzLtFtjU9eNHKin0x5InTqb8lNpfKv1s1xHzTXRqgKzek/mb7nB8RZTCDhGEX3kK/8Q75AmUM/eLkfA+0Hi908Kx4eNsMgudg5GLdRD7a84npi+YxNr5i5KIbW5izXas7cHXIMAau1OueZhfj+cOcP3P8MNIWLyYOBuxL6DRylJ4cAAAB4nGNgYoAALjDJyIAOWMCiTIxMLDmZedkABtIBygAAAA==) format(\"woff\");\n}\n.markdown-body {\n  -ms-text-size-adjust: 100%;\n  -webkit-text-size-adjust: 100%;\n  color: #333;\n  overflow: hidden;\n  font-family: \"Microsoft YaHei\", Helvetica, \"Meiryo UI\", \"Malgun Gothic\", \"Segoe UI\", \"Trebuchet MS\", \"Monaco\", monospace, Tahoma, STXihei, \"华文细黑\", STHeiti, \"Helvetica Neue\", \"Droid Sans\", \"wenquanyi micro hei\", FreeSans, Arimo, Arial, SimSun, \"宋体\", Heiti, \"黑体\", sans-serif;\n  font-size: 16px;\n  line-height: 1.6;\n  word-wrap: break-word;\n}\n\n.markdown-body a {\n  background: transparent;\n}\n\n.markdown-body a:active,\n.markdown-body a:hover {\n  outline: 0;\n}\n\n.markdown-body strong {\n  font-weight: bold;\n}\n\n.markdown-body h1 {\n  font-size: 2em;\n  margin: 0.67em 0;\n}\n\n.markdown-body img {\n  border: 0;\n}\n\n.markdown-body hr {\n  -moz-box-sizing: content-box;\n  box-sizing: content-box;\n  height: 0;\n}\n\n.markdown-body pre {\n  overflow: auto;\n}\n\n.markdown-body code,\n.markdown-body kbd,\n.markdown-body pre {\n  font-family: \"Meiryo UI\", \"YaHei Consolas Hybrid\", Consolas, \"Malgun Gothic\", \"Segoe UI\", \"Trebuchet MS\", Helvetica, monospace, monospace;\n  font-size: 1em;\n}\n\n.markdown-body input {\n  color: inherit;\n  font: inherit;\n  margin: 0;\n}\n\n.markdown-body html input[disabled] {\n  cursor: default;\n}\n\n.markdown-body input {\n  line-height: normal;\n}\n\n.markdown-body input[type=\"checkbox\"] {\n  -moz-box-sizing: border-box;\n  box-sizing: border-box;\n  padding: 0;\n}\n\n.markdown-body table {\n  border-collapse: collapse;\n  border-spacing: 0;\n}\n\n.markdown-body td,\n.markdown-body th {\n  padding: 0;\n}\n\n.markdown-body * {\n  -moz-box-sizing: border-box;\n  box-sizing: border-box;\n}\n\n.markdown-body input {\n  font: 13px/1.4 Helvetica, arial, freesans, clean, sans-serif, \"Segoe UI Emoji\", \"Segoe UI Symbol\";\n}\n\n.markdown-body a {\n  color: #4183c4;\n  text-decoration: none;\n}\n\n.markdown-body a:hover,\n.markdown-body a:active {\n  text-decoration: underline;\n}\n\n.markdown-body hr {\n  height: 0;\n  margin: 15px 0;\n  overflow: hidden;\n  background: transparent;\n  border: 0;\n  border-bottom: 1px solid #ddd;\n}\n\n.markdown-body hr:before {\n  display: table;\n  content: \"\";\n}\n\n.markdown-body hr:after {\n  display: table;\n  clear: both;\n  content: \"\";\n}\n\n.markdown-body h1,\n.markdown-body h2,\n.markdown-body h3,\n.markdown-body h4,\n.markdown-body h5,\n.markdown-body h6 {\n  margin-top: 15px;\n  margin-bottom: 15px;\n  line-height: 1.1;\n}\n\n.markdown-body h1 {\n  font-size: 30px;\n}\n\n.markdown-body h2 {\n  font-size: 21px;\n}\n\n.markdown-body h3 {\n  font-size: 16px;\n}\n\n.markdown-body h4 {\n  font-size: 14px;\n}\n\n.markdown-body h5 {\n  font-size: 12px;\n}\n\n.markdown-body h6 {\n  font-size: 11px;\n}\n\n.markdown-body blockquote {\n  margin: 0;\n}\n\n.markdown-body ul,\n.markdown-body ol {\n  padding: 0;\n  margin-top: 0;\n  margin-bottom: 0;\n}\n\n.markdown-body ol ol,\n.markdown-body ul ol {\n  list-style-type: lower-roman;\n}\n\n.markdown-body ul ul ol,\n.markdown-body ul ol ol,\n.markdown-body ol ul ol,\n.markdown-body ol ol ol {\n  list-style-type: lower-alpha;\n}\n\n.markdown-body dd {\n  margin-left: 0;\n}\n\n.markdown-body code {\n  font-family: Consolas, \"Liberation Mono\", Menlo, Courier, monospace;\n  font-size: 12px;\n}\n\n.markdown-body pre {\n  margin-top: 0;\n  margin-bottom: 0;\n  font: 12px Consolas, \"Liberation Mono\", Menlo, Courier, monospace;\n}\n\n.markdown-body .octicon {\n  font: normal normal 16px octicons-anchor;\n  line-height: 1;\n  display: inline-block;\n  text-decoration: none;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n  -webkit-user-select: none;\n  -moz-user-select: none;\n  -ms-user-select: none;\n  user-select: none;\n}\n\n.markdown-body .octicon-link:before {\n  content: '\\f05c';\n}\n\n.markdown-body > *:first-child {\n  margin-top: 0 !important;\n}\n\n.markdown-body > *:last-child {\n  margin-bottom: 0 !important;\n}\n\n.markdown-body .anchor {\n  position: absolute;\n  top: 0;\n  left: 0;\n  display: block;\n  padding-right: 6px;\n  padding-left: 30px;\n  margin-left: -30px;\n}\n\n.markdown-body .anchor:focus {\n  outline: none;\n}\n\n.markdown-body h1,\n.markdown-body h2,\n.markdown-body h3,\n.markdown-body h4,\n.markdown-body h5,\n.markdown-body h6 {\n  position: relative;\n  margin-top: 1em;\n  margin-bottom: 16px;\n  font-weight: bold;\n  line-height: 1.4;\n}\n\n.markdown-body h1 .octicon-link,\n.markdown-body h2 .octicon-link,\n.markdown-body h3 .octicon-link,\n.markdown-body h4 .octicon-link,\n.markdown-body h5 .octicon-link,\n.markdown-body h6 .octicon-link {\n  display: none;\n  color: #000;\n  vertical-align: middle;\n}\n\n.markdown-body h1:hover .anchor,\n.markdown-body h2:hover .anchor,\n.markdown-body h3:hover .anchor,\n.markdown-body h4:hover .anchor,\n.markdown-body h5:hover .anchor,\n.markdown-body h6:hover .anchor {\n  padding-left: 8px;\n  margin-left: -30px;\n  text-decoration: none;\n}\n\n.markdown-body h1:hover .anchor .octicon-link,\n.markdown-body h2:hover .anchor .octicon-link,\n.markdown-body h3:hover .anchor .octicon-link,\n.markdown-body h4:hover .anchor .octicon-link,\n.markdown-body h5:hover .anchor .octicon-link,\n.markdown-body h6:hover .anchor .octicon-link {\n  display: inline-block;\n}\n\n.markdown-body h1 {\n  padding-bottom: 0.3em;\n  font-size: 2.25em;\n  line-height: 1.2;\n  border-bottom: 1px solid #eee;\n}\n\n.markdown-body h1 .anchor {\n  line-height: 1;\n}\n\n.markdown-body h2 {\n  padding-bottom: 0.3em;\n  font-size: 1.75em;\n  line-height: 1.225;\n  border-bottom: 1px solid #eee;\n}\n\n.markdown-body h2 .anchor {\n  line-height: 1;\n}\n\n.markdown-body h3 {\n  font-size: 1.5em;\n  line-height: 1.43;\n}\n\n.markdown-body h3 .anchor {\n  line-height: 1.2;\n}\n\n.markdown-body h4 {\n  font-size: 1.25em;\n}\n\n.markdown-body h4 .anchor {\n  line-height: 1.2;\n}\n\n.markdown-body h5 {\n  font-size: 1em;\n}\n\n.markdown-body h5 .anchor {\n  line-height: 1.1;\n}\n\n.markdown-body h6 {\n  font-size: 1em;\n  color: #777;\n}\n\n.markdown-body h6 .anchor {\n  line-height: 1.1;\n}\n\n.markdown-body p,\n.markdown-body blockquote,\n.markdown-body ul,\n.markdown-body ol,\n.markdown-body dl,\n.markdown-body table,\n.markdown-body pre {\n  margin-top: 0;\n  margin-bottom: 16px;\n}\n\n/*\n.markdown-body hr {\n  height: 4px;\n  padding: 0;\n  margin: 16px 0;\n  background-color: #e7e7e7;\n  border: 0 none;\n}*/\n.markdown-body ul,\n.markdown-body ol {\n  padding-left: 2em;\n}\n\n.markdown-body ul ul,\n.markdown-body ul ol,\n.markdown-body ol ol,\n.markdown-body ol ul {\n  margin-top: 0;\n  margin-bottom: 0;\n}\n\n.markdown-body li > p {\n  margin-top: 16px;\n}\n\n.markdown-body dl {\n  padding: 0;\n}\n\n.markdown-body dl dt {\n  padding: 0;\n  margin-top: 16px;\n  font-size: 1em;\n  font-style: italic;\n  font-weight: bold;\n}\n\n.markdown-body dl dd {\n  padding: 0 16px;\n  margin-bottom: 16px;\n}\n\n.markdown-body blockquote {\n  padding: 0 15px;\n  color: #777;\n  border-left: 4px solid #ddd;\n}\n\n.markdown-body blockquote > :first-child {\n  margin-top: 0;\n}\n\n.markdown-body blockquote > :last-child {\n  margin-bottom: 0;\n}\n\n.markdown-body table {\n  display: block;\n  width: 100%;\n  overflow: auto;\n  word-break: normal;\n  word-break: keep-all;\n}\n\n.markdown-body table th {\n  font-weight: bold;\n}\n\n.markdown-body table th,\n.markdown-body table td {\n  padding: 6px 13px;\n  border: 1px solid #ddd;\n}\n\n.markdown-body table tr {\n  background-color: #fff;\n  border-top: 1px solid #ccc;\n}\n\n.markdown-body table tr:nth-child(2n) {\n  background-color: #f8f8f8;\n}\n\n.markdown-body img {\n  max-width: 100%;\n  -moz-box-sizing: border-box;\n  box-sizing: border-box;\n}\n\n.markdown-body code {\n  padding: 0;\n  padding-top: 0.2em;\n  padding-bottom: 0.2em;\n  margin: 0;\n  font-size: 85%;\n  background-color: rgba(0, 0, 0, 0.04);\n  border-radius: 3px;\n}\n\n.markdown-body code:before,\n.markdown-body code:after {\n  letter-spacing: -0.2em;\n  content: \"\\00a0\";\n}\n\n.markdown-body pre > code {\n  padding: 0;\n  margin: 0;\n  font-size: 100%;\n  word-break: normal;\n  white-space: pre;\n  background: transparent;\n  border: 0;\n}\n\n.markdown-body .highlight {\n  margin-bottom: 16px;\n}\n\n.markdown-body .highlight pre,\n.markdown-body pre {\n  padding: 16px;\n  overflow: auto;\n  font-size: 85%;\n  line-height: 1.45;\n  background-color: #f7f7f7;\n  border-radius: 3px;\n}\n\n.markdown-body .highlight pre {\n  margin-bottom: 0;\n  word-break: normal;\n}\n\n.markdown-body pre {\n  word-wrap: normal;\n}\n\n.markdown-body pre code {\n  display: inline;\n  max-width: initial;\n  padding: 0;\n  margin: 0;\n  overflow: initial;\n  line-height: inherit;\n  word-wrap: normal;\n  background-color: transparent;\n  border: 0;\n}\n\n.markdown-body pre code:before,\n.markdown-body pre code:after {\n  content: normal;\n}\n\n.markdown-body kbd {\n  display: inline-block;\n  padding: 3px 5px;\n  font-size: 11px;\n  line-height: 10px;\n  color: #555;\n  vertical-align: middle;\n  background-color: #fcfcfc;\n  border: solid 1px #ccc;\n  border-bottom-color: #bbb;\n  border-radius: 3px;\n  box-shadow: inset 0 -1px 0 #bbb;\n}\n\n.markdown-body .pl-c {\n  color: #969896;\n}\n\n.markdown-body .pl-c1,\n.markdown-body .pl-mdh,\n.markdown-body .pl-mm,\n.markdown-body .pl-mp,\n.markdown-body .pl-mr,\n.markdown-body .pl-s1 .pl-v,\n.markdown-body .pl-s3,\n.markdown-body .pl-sc,\n.markdown-body .pl-sv {\n  color: #0086b3;\n}\n\n.markdown-body .pl-e,\n.markdown-body .pl-en {\n  color: #795da3;\n}\n\n.markdown-body .pl-s1 .pl-s2,\n.markdown-body .pl-smi,\n.markdown-body .pl-smp,\n.markdown-body .pl-stj,\n.markdown-body .pl-vo,\n.markdown-body .pl-vpf {\n  color: #333;\n}\n\n.markdown-body .pl-ent {\n  color: #63a35c;\n}\n\n.markdown-body .pl-k,\n.markdown-body .pl-s,\n.markdown-body .pl-st {\n  color: #a71d5d;\n}\n\n.markdown-body .pl-pds,\n.markdown-body .pl-s1,\n.markdown-body .pl-s1 .pl-pse .pl-s2,\n.markdown-body .pl-sr,\n.markdown-body .pl-sr .pl-cce,\n.markdown-body .pl-sr .pl-sra,\n.markdown-body .pl-sr .pl-sre,\n.markdown-body .pl-src {\n  color: #df5000;\n}\n\n.markdown-body .pl-mo,\n.markdown-body .pl-v {\n  color: #1d3e81;\n}\n\n.markdown-body .pl-id {\n  color: #b52a1d;\n}\n\n.markdown-body .pl-ii {\n  background-color: #b52a1d;\n  color: #f8f8f8;\n}\n\n.markdown-body .pl-sr .pl-cce {\n  color: #63a35c;\n  font-weight: bold;\n}\n\n.markdown-body .pl-ml {\n  color: #693a17;\n}\n\n.markdown-body .pl-mh,\n.markdown-body .pl-mh .pl-en,\n.markdown-body .pl-ms {\n  color: #1d3e81;\n  font-weight: bold;\n}\n\n.markdown-body .pl-mq {\n  color: #008080;\n}\n\n.markdown-body .pl-mi {\n  color: #333;\n  font-style: italic;\n}\n\n.markdown-body .pl-mb {\n  color: #333;\n  font-weight: bold;\n}\n\n.markdown-body .pl-md,\n.markdown-body .pl-mdhf {\n  background-color: #ffecec;\n  color: #bd2c00;\n}\n\n.markdown-body .pl-mdht,\n.markdown-body .pl-mi1 {\n  background-color: #eaffea;\n  color: #55a532;\n}\n\n.markdown-body .pl-mdr {\n  color: #795da3;\n  font-weight: bold;\n}\n\n.markdown-body kbd {\n  display: inline-block;\n  padding: 3px 5px;\n  font: 11px Consolas, \"Liberation Mono\", Menlo, Courier, monospace;\n  line-height: 10px;\n  color: #555;\n  vertical-align: middle;\n  background-color: #fcfcfc;\n  border: solid 1px #ccc;\n  border-bottom-color: #bbb;\n  border-radius: 3px;\n  box-shadow: inset 0 -1px 0 #bbb;\n}\n\n.markdown-body .task-list-item {\n  list-style-type: none;\n}\n\n.markdown-body .task-list-item + .task-list-item {\n  margin-top: 3px;\n}\n\n.markdown-body .task-list-item input {\n  float: left;\n  margin: 0.3em 0 0.25em -1.6em;\n  vertical-align: middle;\n}\n\n.markdown-body :checked + .radio-label {\n  z-index: 1;\n  position: relative;\n  border-color: #4183c4;\n}\n\n.editormd-preview-container, .editormd-html-preview {\n  text-align: left;\n  font-size: 14px;\n  line-height: 1.6;\n  padding: 20px;\n  overflow: auto;\n  width: 100%;\n  background-color: #fff;\n}\n.editormd-preview-container blockquote, .editormd-html-preview blockquote {\n  color: #666;\n  border-left: 4px solid #ddd;\n  padding-left: 20px;\n  margin-left: 0;\n  font-size: 14px;\n  font-style: italic;\n}\n.editormd-preview-container p code, .editormd-html-preview p code {\n  margin-left: 5px;\n  margin-right: 4px;\n}\n.editormd-preview-container abbr, .editormd-html-preview abbr {\n  background: #ffffdd;\n}\n.editormd-preview-container hr, .editormd-html-preview hr {\n  height: 1px;\n  border: none;\n  border-top: 1px solid #ddd;\n  background: none;\n}\n.editormd-preview-container code, .editormd-html-preview code {\n  border: 1px solid #ddd;\n  background: #f6f6f6;\n  padding: 3px;\n  border-radius: 3px;\n  font-size: 14px;\n}\n.editormd-preview-container pre, .editormd-html-preview pre {\n  border: 1px solid #ddd;\n  background: #f6f6f6;\n  padding: 10px;\n  -webkit-border-radius: 3px;\n  -moz-border-radius: 3px;\n  -ms-border-radius: 3px;\n  -o-border-radius: 3px;\n  border-radius: 3px;\n}\n.editormd-preview-container pre code, .editormd-html-preview pre code {\n  padding: 0;\n}\n.editormd-preview-container pre, .editormd-preview-container code, .editormd-preview-container kbd, .editormd-html-preview pre, .editormd-html-preview code, .editormd-html-preview kbd {\n  font-family: \"YaHei Consolas Hybrid\", Consolas, \"Meiryo UI\", \"Malgun Gothic\", \"Segoe UI\", \"Trebuchet MS\", Helvetica, monospace, monospace;\n}\n.editormd-preview-container table thead tr, .editormd-html-preview table thead tr {\n  background-color: #F8F8F8;\n}\n.editormd-preview-container p.editormd-tex, .editormd-html-preview p.editormd-tex {\n  text-align: center;\n}\n.editormd-preview-container span.editormd-tex, .editormd-html-preview span.editormd-tex {\n  margin: 0 5px;\n}\n.editormd-preview-container .emoji, .editormd-html-preview .emoji {\n  width: 24px;\n  height: 24px;\n}\n.editormd-preview-container .katex, .editormd-html-preview .katex {\n  font-size: 1.4em;\n}\n.editormd-preview-container .sequence-diagram, .editormd-preview-container .flowchart, .editormd-html-preview .sequence-diagram, .editormd-html-preview .flowchart {\n  margin: 0 auto;\n  text-align: center;\n}\n.editormd-preview-container .sequence-diagram svg, .editormd-preview-container .flowchart svg, .editormd-html-preview .sequence-diagram svg, .editormd-html-preview .flowchart svg {\n  margin: 0 auto;\n}\n.editormd-preview-container .sequence-diagram text, .editormd-preview-container .flowchart text, .editormd-html-preview .sequence-diagram text, .editormd-html-preview .flowchart text {\n  font-size: 15px !important;\n  font-family: \"YaHei Consolas Hybrid\", Consolas, \"Microsoft YaHei\", \"Malgun Gothic\", \"Segoe UI\", Helvetica, Arial !important;\n}\n\n/*! Pretty printing styles. Used with prettify.js. */\n/* SPAN elements with the classes below are added by prettyprint. */\n.pln {\n  color: #000;\n}\n\n/* plain text */\n@media screen {\n  .str {\n    color: #080;\n  }\n\n  /* string content */\n  .kwd {\n    color: #008;\n  }\n\n  /* a keyword */\n  .com {\n    color: #800;\n  }\n\n  /* a comment */\n  .typ {\n    color: #606;\n  }\n\n  /* a type name */\n  .lit {\n    color: #066;\n  }\n\n  /* a literal value */\n  /* punctuation, lisp open bracket, lisp close bracket */\n  .pun, .opn, .clo {\n    color: #660;\n  }\n\n  .tag {\n    color: #008;\n  }\n\n  /* a markup tag name */\n  .atn {\n    color: #606;\n  }\n\n  /* a markup attribute name */\n  .atv {\n    color: #080;\n  }\n\n  /* a markup attribute value */\n  .dec, .var {\n    color: #606;\n  }\n\n  /* a declaration; a variable name */\n  .fun {\n    color: red;\n  }\n\n  /* a function name */\n}\n/* Use higher contrast and text-weight for printable form. */\n@media print, projection {\n  .str {\n    color: #060;\n  }\n\n  .kwd {\n    color: #006;\n    font-weight: bold;\n  }\n\n  .com {\n    color: #600;\n    font-style: italic;\n  }\n\n  .typ {\n    color: #404;\n    font-weight: bold;\n  }\n\n  .lit {\n    color: #044;\n  }\n\n  .pun, .opn, .clo {\n    color: #440;\n  }\n\n  .tag {\n    color: #006;\n    font-weight: bold;\n  }\n\n  .atn {\n    color: #404;\n  }\n\n  .atv {\n    color: #060;\n  }\n}\n/* Put a border around prettyprinted code snippets. */\npre.prettyprint {\n  padding: 2px;\n  border: 1px solid #888;\n}\n\n/* Specify class=linenums on a pre to get line numbering */\nol.linenums {\n  margin-top: 0;\n  margin-bottom: 0;\n}\n\n/* IE indents via margin-left */\nli.L0,\nli.L1,\nli.L2,\nli.L3,\nli.L5,\nli.L6,\nli.L7,\nli.L8 {\n  list-style-type: none;\n}\n\n/* Alternate shading for lines */\nli.L1,\nli.L3,\nli.L5,\nli.L7,\nli.L9 {\n  background: #eee;\n}\n\n.editormd-preview-container pre.prettyprint, .editormd-html-preview pre.prettyprint {\n  padding: 10px;\n  border: 1px solid #ddd;\n  white-space: pre-wrap;\n  word-wrap: break-word;\n}\n.editormd-preview-container ol.linenums, .editormd-html-preview ol.linenums {\n  color: #999;\n  padding-left: 2.5em;\n}\n.editormd-preview-container ol.linenums li, .editormd-html-preview ol.linenums li {\n  list-style-type: decimal;\n}\n.editormd-preview-container ol.linenums li code, .editormd-html-preview ol.linenums li code {\n  border: none;\n  background: none;\n  padding: 0;\n}\n\n.editormd-preview-container .editormd-toc-menu, .editormd-html-preview .editormd-toc-menu {\n  margin: 8px 0 12px 0;\n  display: inline-block;\n}\n.editormd-preview-container .editormd-toc-menu > .markdown-toc, .editormd-html-preview .editormd-toc-menu > .markdown-toc {\n  position: relative;\n  -webkit-border-radius: 4px;\n  -moz-border-radius: 4px;\n  -ms-border-radius: 4px;\n  -o-border-radius: 4px;\n  border-radius: 4px;\n  border: 1px solid #ddd;\n  display: inline-block;\n  font-size: 1em;\n}\n.editormd-preview-container .editormd-toc-menu > .markdown-toc > ul, .editormd-html-preview .editormd-toc-menu > .markdown-toc > ul {\n  width: 160%;\n  min-width: 180px;\n  position: absolute;\n  left: -1px;\n  top: -2px;\n  z-index: 100;\n  padding: 0 10px 10px;\n  display: none;\n  background: #fff;\n  border: 1px solid #ddd;\n  -webkit-border-radius: 4px;\n  -moz-border-radius: 4px;\n  -ms-border-radius: 4px;\n  -o-border-radius: 4px;\n  border-radius: 4px;\n  -webkit-box-shadow: 0 3px 5px rgba(0, 0, 0, 0.2);\n  /* Webkit browsers */\n  -moz-box-shadow: 0 3px 5px rgba(0, 0, 0, 0.2);\n  /* Firefox */\n  -ms-box-shadow: 0 3px 5px rgba(0, 0, 0, 0.2);\n  /* IE9 */\n  -o-box-shadow: 0 3px 5px rgba(0, 0, 0, 0.2);\n  /* Opera(Old) */\n  box-shadow: 0 3px 5px rgba(0, 0, 0, 0.2);\n  /* IE9+, News */\n}\n.editormd-preview-container .editormd-toc-menu > .markdown-toc > ul > li ul, .editormd-html-preview .editormd-toc-menu > .markdown-toc > ul > li ul {\n  width: 100%;\n  min-width: 180px;\n  border: 1px solid #ddd;\n  display: none;\n  background: #fff;\n  -webkit-border-radius: 4px;\n  -moz-border-radius: 4px;\n  -ms-border-radius: 4px;\n  -o-border-radius: 4px;\n  border-radius: 4px;\n}\n.editormd-preview-container .editormd-toc-menu > .markdown-toc > ul > li a, .editormd-html-preview .editormd-toc-menu > .markdown-toc > ul > li a {\n  color: #666;\n  padding: 6px 10px;\n  display: block;\n  -webkit-transition: background-color 500ms ease-out;\n  /* Safari, Chrome */\n  -moz-transition: background-color 500ms ease-out;\n  /* Firefox 4.0~16.0 */\n  transition: background-color 500ms ease-out;\n  /* IE >9, FF >15, Opera >12.0 */\n}\n.editormd-preview-container .editormd-toc-menu > .markdown-toc > ul > li a:hover, .editormd-html-preview .editormd-toc-menu > .markdown-toc > ul > li a:hover {\n  background-color: #f6f6f6;\n}\n.editormd-preview-container .editormd-toc-menu > .markdown-toc li, .editormd-html-preview .editormd-toc-menu > .markdown-toc li {\n  position: relative;\n}\n.editormd-preview-container .editormd-toc-menu > .markdown-toc li > ul, .editormd-html-preview .editormd-toc-menu > .markdown-toc li > ul {\n  position: absolute;\n  top: 32px;\n  left: 10%;\n  display: none;\n  -webkit-box-shadow: 0 3px 5px rgba(0, 0, 0, 0.2);\n  /* Webkit browsers */\n  -moz-box-shadow: 0 3px 5px rgba(0, 0, 0, 0.2);\n  /* Firefox */\n  -ms-box-shadow: 0 3px 5px rgba(0, 0, 0, 0.2);\n  /* IE9 */\n  -o-box-shadow: 0 3px 5px rgba(0, 0, 0, 0.2);\n  /* Opera(Old) */\n  box-shadow: 0 3px 5px rgba(0, 0, 0, 0.2);\n  /* IE9+, News */\n}\n.editormd-preview-container .editormd-toc-menu > .markdown-toc li > ul:before, .editormd-preview-container .editormd-toc-menu > .markdown-toc li > ul:after, .editormd-html-preview .editormd-toc-menu > .markdown-toc li > ul:before, .editormd-html-preview .editormd-toc-menu > .markdown-toc li > ul:after {\n  pointer-events: pointer-events;\n  position: absolute;\n  left: 15px;\n  top: -6px;\n  display: block;\n  content: \"\";\n  width: 0;\n  height: 0;\n  border: 6px solid transparent;\n  border-width: 0 6px 6px;\n  z-index: 10;\n}\n.editormd-preview-container .editormd-toc-menu > .markdown-toc li > ul:before, .editormd-html-preview .editormd-toc-menu > .markdown-toc li > ul:before {\n  border-bottom-color: #ccc;\n}\n.editormd-preview-container .editormd-toc-menu > .markdown-toc li > ul:after, .editormd-html-preview .editormd-toc-menu > .markdown-toc li > ul:after {\n  border-bottom-color: #ffffff;\n  top: -5px;\n}\n.editormd-preview-container .editormd-toc-menu ul, .editormd-html-preview .editormd-toc-menu ul {\n  list-style: none;\n}\n.editormd-preview-container .editormd-toc-menu a, .editormd-html-preview .editormd-toc-menu a {\n  text-decoration: none;\n}\n.editormd-preview-container .editormd-toc-menu h1, .editormd-html-preview .editormd-toc-menu h1 {\n  font-size: 16px;\n  padding: 5px 0 10px 10px;\n  line-height: 1;\n  border-bottom: 1px solid #eee;\n}\n.editormd-preview-container .editormd-toc-menu h1 .fa, .editormd-html-preview .editormd-toc-menu h1 .fa {\n  padding-left: 10px;\n}\n.editormd-preview-container .editormd-toc-menu .toc-menu-btn, .editormd-html-preview .editormd-toc-menu .toc-menu-btn {\n  color: #666;\n  min-width: 180px;\n  padding: 5px 10px;\n  border-radius: 4px;\n  display: inline-block;\n  -webkit-transition: background-color 500ms ease-out;\n  /* Safari, Chrome */\n  -moz-transition: background-color 500ms ease-out;\n  /* Firefox 4.0~16.0 */\n  transition: background-color 500ms ease-out;\n  /* IE >9, FF >15, Opera >12.0 */\n}\n.editormd-preview-container .editormd-toc-menu .toc-menu-btn:hover, .editormd-html-preview .editormd-toc-menu .toc-menu-btn:hover {\n  background-color: #f6f6f6;\n}\n.editormd-preview-container .editormd-toc-menu .toc-menu-btn .fa, .editormd-html-preview .editormd-toc-menu .toc-menu-btn .fa {\n  float: right;\n  padding: 3px 0 0 10px;\n  font-size: 1.3em;\n}\n\n.markdown-body .editormd-toc-menu ul {\n  padding-left: 0;\n}\n.markdown-body .highlight pre, .markdown-body pre {\n  line-height: 1.6;\n}\n\nhr.editormd-page-break {\n  border: 1px dotted #ccc;\n  font-size: 0;\n  height: 2px;\n}\n\n@media only print {\n  hr.editormd-page-break {\n    background: none;\n    border: none;\n    height: 0;\n  }\n}\n.editormd-html-preview textarea {\n  display: none;\n}\n.editormd-html-preview hr.editormd-page-break {\n  background: none;\n  border: none;\n  height: 0;\n}\n\n.editormd-preview-close-btn {\n  color: #fff;\n  padding: 4px 6px;\n  font-size: 18px;\n  -webkit-border-radius: 500px;\n  -moz-border-radius: 500px;\n  -ms-border-radius: 500px;\n  -o-border-radius: 500px;\n  border-radius: 500px;\n  display: none;\n  background-color: #ccc;\n  position: absolute;\n  top: 25px;\n  right: 35px;\n  z-index: 19;\n  -webkit-transition: background-color 300ms ease-out;\n  /* Safari, Chrome */\n  -moz-transition: background-color 300ms ease-out;\n  /* Firefox 4.0~16.0 */\n  transition: background-color 300ms ease-out;\n  /* IE >9, FF >15, Opera >12.0 */\n}\n.editormd-preview-close-btn:hover {\n  background-color: #999;\n}\n\n.editormd-preview-active {\n  width: 100%;\n  padding: 40px;\n}\n\n/* Preview dark theme */\n.editormd-preview-theme-dark {\n  color: #777;\n  background: #2C2827;\n}\n.editormd-preview-theme-dark .editormd-preview-container {\n  color: #888;\n  background-color: #2C2827;\n}\n.editormd-preview-theme-dark .editormd-preview-container pre.prettyprint {\n  border: none;\n}\n.editormd-preview-theme-dark .editormd-preview-container blockquote {\n  color: #555;\n  padding: 0.5em;\n  background: #222;\n  border-color: #333;\n}\n.editormd-preview-theme-dark .editormd-preview-container abbr {\n  color: #fff;\n  padding: 1px 3px;\n  -webkit-border-radius: 3px;\n  -moz-border-radius: 3px;\n  -ms-border-radius: 3px;\n  -o-border-radius: 3px;\n  border-radius: 3px;\n  background: #ff9900;\n}\n.editormd-preview-theme-dark .editormd-preview-container code {\n  color: #fff;\n  border: none;\n  padding: 1px 3px;\n  -webkit-border-radius: 3px;\n  -moz-border-radius: 3px;\n  -ms-border-radius: 3px;\n  -o-border-radius: 3px;\n  border-radius: 3px;\n  background: #5A9600;\n}\n.editormd-preview-theme-dark .editormd-preview-container table {\n  border: none;\n}\n.editormd-preview-theme-dark .editormd-preview-container .fa-emoji {\n  color: #B4BF42;\n}\n.editormd-preview-theme-dark .editormd-preview-container .katex {\n  color: #FEC93F;\n}\n.editormd-preview-theme-dark .editormd-toc-menu > .markdown-toc {\n  background: #fff;\n  border: none;\n}\n.editormd-preview-theme-dark .editormd-toc-menu > .markdown-toc h1 {\n  border-color: #ddd;\n}\n.editormd-preview-theme-dark .markdown-body h1, .editormd-preview-theme-dark .markdown-body h2, .editormd-preview-theme-dark .markdown-body hr {\n  border-color: #222;\n}\n.editormd-preview-theme-dark pre {\n  color: #999;\n  background-color: #111;\n  background-color: rgba(0, 0, 0, 0.4);\n  /* plain text */\n}\n.editormd-preview-theme-dark pre .pln {\n  color: #999;\n}\n.editormd-preview-theme-dark li.L1, .editormd-preview-theme-dark li.L3, .editormd-preview-theme-dark li.L5, .editormd-preview-theme-dark li.L7, .editormd-preview-theme-dark li.L9 {\n  background: none;\n}\n.editormd-preview-theme-dark [class*=editormd-logo] {\n  color: #2196F3;\n}\n.editormd-preview-theme-dark .sequence-diagram text {\n  fill: #fff;\n}\n.editormd-preview-theme-dark .sequence-diagram rect, .editormd-preview-theme-dark .sequence-diagram path {\n  color: #fff;\n  fill: #64D1CB;\n  stroke: #64D1CB;\n}\n.editormd-preview-theme-dark .flowchart rect, .editormd-preview-theme-dark .flowchart path {\n  stroke: #A6C6FF;\n}\n.editormd-preview-theme-dark .flowchart rect {\n  fill: #A6C6FF;\n}\n.editormd-preview-theme-dark .flowchart text {\n  fill: #5879B4;\n}\n\n@media screen {\n  .editormd-preview-theme-dark {\n    /* string content */\n    /* a keyword */\n    /* a comment */\n    /* a type name */\n    /* a literal value */\n    /* punctuation, lisp open bracket, lisp close bracket */\n    /* a markup tag name */\n    /* a markup attribute name */\n    /* a markup attribute value */\n    /* a declaration; a variable name */\n    /* a function name */\n  }\n  .editormd-preview-theme-dark .str {\n    color: #080;\n  }\n  .editormd-preview-theme-dark .kwd {\n    color: #ff9900;\n  }\n  .editormd-preview-theme-dark .com {\n    color: #444444;\n  }\n  .editormd-preview-theme-dark .typ {\n    color: #606;\n  }\n  .editormd-preview-theme-dark .lit {\n    color: #066;\n  }\n  .editormd-preview-theme-dark .pun, .editormd-preview-theme-dark .opn, .editormd-preview-theme-dark .clo {\n    color: #660;\n  }\n  .editormd-preview-theme-dark .tag {\n    color: #ff9900;\n  }\n  .editormd-preview-theme-dark .atn {\n    color: #6C95F5;\n  }\n  .editormd-preview-theme-dark .atv {\n    color: #080;\n  }\n  .editormd-preview-theme-dark .dec, .editormd-preview-theme-dark .var {\n    color: #008BA7;\n  }\n  .editormd-preview-theme-dark .fun {\n    color: red;\n  }\n}\n.editormd-onlyread .editormd-toolbar {\n  display: none;\n}\n.editormd-onlyread .CodeMirror {\n  margin-top: 0;\n}\n.editormd-onlyread .editormd-preview {\n  top: 0;\n}\n\n.editormd-fullscreen {\n  position: fixed;\n  top: 0;\n  left: 0;\n  border: none;\n  margin: 0 auto;\n}\n\n/* Editor.md Dark theme */\n.editormd-theme-dark {\n  border-color: #1a1a17;\n}\n.editormd-theme-dark .editormd-toolbar {\n  background: #1A1A17;\n  border-color: #1a1a17;\n}\n.editormd-theme-dark .editormd-menu > li > a {\n  color: #777;\n  border-color: #1a1a17;\n}\n.editormd-theme-dark .editormd-menu > li > a:hover, .editormd-theme-dark .editormd-menu > li > a.active {\n  border-color: #333;\n  background: #333;\n}\n.editormd-theme-dark .editormd-menu > li.divider {\n  border-right: 1px solid #111;\n}\n.editormd-theme-dark .CodeMirror {\n  border-right: 1px solid rgba(0, 0, 0, 0.1);\n}\n"
  },
  {
    "path": "Public/editor.md/css/editormd.logo.css",
    "content": "/*\n * Editor.md\n *\n * @file        editormd.logo.css \n * @version     v1.5.0 \n * @description Open source online markdown editor.\n * @license     MIT License\n * @author      Pandao\n * {@link       https://github.com/pandao/editor.md}\n * @updateTime  2015-06-09\n */\n\n/*! prefixes.scss v0.1.0 | Author: Pandao | https://github.com/pandao/prefixes.scss | MIT license | Copyright (c) 2015 */\n@font-face {\n  font-family: 'editormd-logo';\n  src: url(\"../fonts/editormd-logo.eot?-5y8q6h\");\n  src: url(\".../fonts/editormd-logo.eot?#iefix-5y8q6h\") format(\"embedded-opentype\"), url(\"../fonts/editormd-logo.woff?-5y8q6h\") format(\"woff\"), url(\"../fonts/editormd-logo.ttf?-5y8q6h\") format(\"truetype\"), url(\"../fonts/editormd-logo.svg?-5y8q6h#icomoon\") format(\"svg\");\n  font-weight: normal;\n  font-style: normal;\n}\n.editormd-logo,\n.editormd-logo-1x,\n.editormd-logo-2x,\n.editormd-logo-3x,\n.editormd-logo-4x,\n.editormd-logo-5x,\n.editormd-logo-6x,\n.editormd-logo-7x,\n.editormd-logo-8x {\n  font-family: 'editormd-logo';\n  speak: none;\n  font-style: normal;\n  font-weight: normal;\n  font-variant: normal;\n  text-transform: none;\n  font-size: inherit;\n  line-height: 1;\n  display: inline-block;\n  text-rendering: auto;\n  vertical-align: inherit;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n.editormd-logo:before,\n.editormd-logo-1x:before,\n.editormd-logo-2x:before,\n.editormd-logo-3x:before,\n.editormd-logo-4x:before,\n.editormd-logo-5x:before,\n.editormd-logo-6x:before,\n.editormd-logo-7x:before,\n.editormd-logo-8x:before {\n  content: \"\\e1987\";\n  /* \n  HTML Entity &#xe1987; \n  example: <span class=\"editormd-logo\">&#xe1987;</span>\n  */\n}\n\n.editormd-logo-1x {\n  font-size: 1em;\n}\n\n.editormd-logo-lg {\n  font-size: 1.2em;\n}\n\n.editormd-logo-2x {\n  font-size: 2em;\n}\n\n.editormd-logo-3x {\n  font-size: 3em;\n}\n\n.editormd-logo-4x {\n  font-size: 4em;\n}\n\n.editormd-logo-5x {\n  font-size: 5em;\n}\n\n.editormd-logo-6x {\n  font-size: 6em;\n}\n\n.editormd-logo-7x {\n  font-size: 7em;\n}\n\n.editormd-logo-8x {\n  font-size: 8em;\n}\n\n.editormd-logo-color {\n  color: #2196F3;\n}\n"
  },
  {
    "path": "Public/editor.md/css/editormd.preview.css",
    "content": "/*\n * Editor.md\n *\n * @file        editormd.preview.css \n * @version     v1.5.0 \n * @description Open source online markdown editor.\n * @license     MIT License\n * @author      Pandao\n * {@link       https://github.com/pandao/editor.md}\n * @updateTime  2015-06-09\n */\n\n@charset \"UTF-8\";\n/*! prefixes.scss v0.1.0 | Author: Pandao | https://github.com/pandao/prefixes.scss | MIT license | Copyright (c) 2015 */\n/*!\n *  Font Awesome 4.3.0 by @davegandy - http://fontawesome.io - @fontawesome\n *  License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)\n */\n/* FONT PATH\n * -------------------------- */\n@font-face {\n  font-family: 'FontAwesome';\n  src: url(\"../fonts/fontawesome-webfont.eot?v=4.3.0\");\n  src: url(\"../fonts/fontawesome-webfont.eot?#iefix&v=4.3.0\") format(\"embedded-opentype\"), url(\"../fonts/fontawesome-webfont.woff2?v=4.3.0\") format(\"woff2\"), url(\"../fonts/fontawesome-webfont.woff?v=4.3.0\") format(\"woff\"), url(\"../fonts/fontawesome-webfont.ttf?v=4.3.0\") format(\"truetype\"), url(\"../fonts/fontawesome-webfont.svg?v=4.3.0#fontawesomeregular\") format(\"svg\");\n  font-weight: normal;\n  font-style: normal;\n}\n.fa {\n  display: inline-block;\n  font: normal normal normal 14px/1 FontAwesome;\n  font-size: inherit;\n  text-rendering: auto;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n  transform: translate(0, 0);\n}\n\n/* makes the font 33% larger relative to the icon container */\n.fa-lg {\n  font-size: 1.33333333em;\n  line-height: 0.75em;\n  vertical-align: -15%;\n}\n\n.fa-2x {\n  font-size: 2em;\n}\n\n.fa-3x {\n  font-size: 3em;\n}\n\n.fa-4x {\n  font-size: 4em;\n}\n\n.fa-5x {\n  font-size: 5em;\n}\n\n.fa-fw {\n  width: 1.28571429em;\n  text-align: center;\n}\n\n.fa-ul {\n  padding-left: 0;\n  margin-left: 2.14285714em;\n  list-style-type: none;\n}\n\n.fa-ul > li {\n  position: relative;\n}\n\n.fa-li {\n  position: absolute;\n  left: -2.14285714em;\n  width: 2.14285714em;\n  top: 0.14285714em;\n  text-align: center;\n}\n\n.fa-li.fa-lg {\n  left: -1.85714286em;\n}\n\n.fa-border {\n  padding: .2em .25em .15em;\n  border: solid 0.08em #eeeeee;\n  border-radius: .1em;\n}\n\n.pull-right {\n  float: right;\n}\n\n.pull-left {\n  float: left;\n}\n\n.fa.pull-left {\n  margin-right: .3em;\n}\n\n.fa.pull-right {\n  margin-left: .3em;\n}\n\n.fa-spin {\n  -webkit-animation: fa-spin 2s infinite linear;\n  animation: fa-spin 2s infinite linear;\n}\n\n.fa-pulse {\n  -webkit-animation: fa-spin 1s infinite steps(8);\n  animation: fa-spin 1s infinite steps(8);\n}\n\n@-webkit-keyframes fa-spin {\n  0% {\n    -webkit-transform: rotate(0deg);\n    transform: rotate(0deg);\n  }\n  100% {\n    -webkit-transform: rotate(359deg);\n    transform: rotate(359deg);\n  }\n}\n@keyframes fa-spin {\n  0% {\n    -webkit-transform: rotate(0deg);\n    transform: rotate(0deg);\n  }\n  100% {\n    -webkit-transform: rotate(359deg);\n    transform: rotate(359deg);\n  }\n}\n.fa-rotate-90 {\n  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1);\n  -webkit-transform: rotate(90deg);\n  -ms-transform: rotate(90deg);\n  transform: rotate(90deg);\n}\n\n.fa-rotate-180 {\n  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2);\n  -webkit-transform: rotate(180deg);\n  -ms-transform: rotate(180deg);\n  transform: rotate(180deg);\n}\n\n.fa-rotate-270 {\n  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3);\n  -webkit-transform: rotate(270deg);\n  -ms-transform: rotate(270deg);\n  transform: rotate(270deg);\n}\n\n.fa-flip-horizontal {\n  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);\n  -webkit-transform: scale(-1, 1);\n  -ms-transform: scale(-1, 1);\n  transform: scale(-1, 1);\n}\n\n.fa-flip-vertical {\n  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);\n  -webkit-transform: scale(1, -1);\n  -ms-transform: scale(1, -1);\n  transform: scale(1, -1);\n}\n\n:root .fa-rotate-90,\n:root .fa-rotate-180,\n:root .fa-rotate-270,\n:root .fa-flip-horizontal,\n:root .fa-flip-vertical {\n  filter: none;\n}\n\n.fa-stack {\n  position: relative;\n  display: inline-block;\n  width: 2em;\n  height: 2em;\n  line-height: 2em;\n  vertical-align: middle;\n}\n\n.fa-stack-1x,\n.fa-stack-2x {\n  position: absolute;\n  left: 0;\n  width: 100%;\n  text-align: center;\n}\n\n.fa-stack-1x {\n  line-height: inherit;\n}\n\n.fa-stack-2x {\n  font-size: 2em;\n}\n\n.fa-inverse {\n  color: #ffffff;\n}\n\n/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen\n   readers do not read off random characters that represent icons */\n.fa-glass:before {\n  content: \"\\f000\";\n}\n\n.fa-music:before {\n  content: \"\\f001\";\n}\n\n.fa-search:before {\n  content: \"\\f002\";\n}\n\n.fa-envelope-o:before {\n  content: \"\\f003\";\n}\n\n.fa-heart:before {\n  content: \"\\f004\";\n}\n\n.fa-star:before {\n  content: \"\\f005\";\n}\n\n.fa-star-o:before {\n  content: \"\\f006\";\n}\n\n.fa-user:before {\n  content: \"\\f007\";\n}\n\n.fa-film:before {\n  content: \"\\f008\";\n}\n\n.fa-th-large:before {\n  content: \"\\f009\";\n}\n\n.fa-th:before {\n  content: \"\\f00a\";\n}\n\n.fa-th-list:before {\n  content: \"\\f00b\";\n}\n\n.fa-check:before {\n  content: \"\\f00c\";\n}\n\n.fa-remove:before,\n.fa-close:before,\n.fa-times:before {\n  content: \"\\f00d\";\n}\n\n.fa-search-plus:before {\n  content: \"\\f00e\";\n}\n\n.fa-search-minus:before {\n  content: \"\\f010\";\n}\n\n.fa-power-off:before {\n  content: \"\\f011\";\n}\n\n.fa-signal:before {\n  content: \"\\f012\";\n}\n\n.fa-gear:before,\n.fa-cog:before {\n  content: \"\\f013\";\n}\n\n.fa-trash-o:before {\n  content: \"\\f014\";\n}\n\n.fa-home:before {\n  content: \"\\f015\";\n}\n\n.fa-file-o:before {\n  content: \"\\f016\";\n}\n\n.fa-clock-o:before {\n  content: \"\\f017\";\n}\n\n.fa-road:before {\n  content: \"\\f018\";\n}\n\n.fa-download:before {\n  content: \"\\f019\";\n}\n\n.fa-arrow-circle-o-down:before {\n  content: \"\\f01a\";\n}\n\n.fa-arrow-circle-o-up:before {\n  content: \"\\f01b\";\n}\n\n.fa-inbox:before {\n  content: \"\\f01c\";\n}\n\n.fa-play-circle-o:before {\n  content: \"\\f01d\";\n}\n\n.fa-rotate-right:before,\n.fa-repeat:before {\n  content: \"\\f01e\";\n}\n\n.fa-refresh:before {\n  content: \"\\f021\";\n}\n\n.fa-list-alt:before {\n  content: \"\\f022\";\n}\n\n.fa-lock:before {\n  content: \"\\f023\";\n}\n\n.fa-flag:before {\n  content: \"\\f024\";\n}\n\n.fa-headphones:before {\n  content: \"\\f025\";\n}\n\n.fa-volume-off:before {\n  content: \"\\f026\";\n}\n\n.fa-volume-down:before {\n  content: \"\\f027\";\n}\n\n.fa-volume-up:before {\n  content: \"\\f028\";\n}\n\n.fa-qrcode:before {\n  content: \"\\f029\";\n}\n\n.fa-barcode:before {\n  content: \"\\f02a\";\n}\n\n.fa-tag:before {\n  content: \"\\f02b\";\n}\n\n.fa-tags:before {\n  content: \"\\f02c\";\n}\n\n.fa-book:before {\n  content: \"\\f02d\";\n}\n\n.fa-bookmark:before {\n  content: \"\\f02e\";\n}\n\n.fa-print:before {\n  content: \"\\f02f\";\n}\n\n.fa-camera:before {\n  content: \"\\f030\";\n}\n\n.fa-font:before {\n  content: \"\\f031\";\n}\n\n.fa-bold:before {\n  content: \"\\f032\";\n}\n\n.fa-italic:before {\n  content: \"\\f033\";\n}\n\n.fa-text-height:before {\n  content: \"\\f034\";\n}\n\n.fa-text-width:before {\n  content: \"\\f035\";\n}\n\n.fa-align-left:before {\n  content: \"\\f036\";\n}\n\n.fa-align-center:before {\n  content: \"\\f037\";\n}\n\n.fa-align-right:before {\n  content: \"\\f038\";\n}\n\n.fa-align-justify:before {\n  content: \"\\f039\";\n}\n\n.fa-list:before {\n  content: \"\\f03a\";\n}\n\n.fa-dedent:before,\n.fa-outdent:before {\n  content: \"\\f03b\";\n}\n\n.fa-indent:before {\n  content: \"\\f03c\";\n}\n\n.fa-video-camera:before {\n  content: \"\\f03d\";\n}\n\n.fa-photo:before,\n.fa-image:before,\n.fa-picture-o:before {\n  content: \"\\f03e\";\n}\n\n.fa-pencil:before {\n  content: \"\\f040\";\n}\n\n.fa-map-marker:before {\n  content: \"\\f041\";\n}\n\n.fa-adjust:before {\n  content: \"\\f042\";\n}\n\n.fa-tint:before {\n  content: \"\\f043\";\n}\n\n.fa-edit:before,\n.fa-pencil-square-o:before {\n  content: \"\\f044\";\n}\n\n.fa-share-square-o:before {\n  content: \"\\f045\";\n}\n\n.fa-check-square-o:before {\n  content: \"\\f046\";\n}\n\n.fa-arrows:before {\n  content: \"\\f047\";\n}\n\n.fa-step-backward:before {\n  content: \"\\f048\";\n}\n\n.fa-fast-backward:before {\n  content: \"\\f049\";\n}\n\n.fa-backward:before {\n  content: \"\\f04a\";\n}\n\n.fa-play:before {\n  content: \"\\f04b\";\n}\n\n.fa-pause:before {\n  content: \"\\f04c\";\n}\n\n.fa-stop:before {\n  content: \"\\f04d\";\n}\n\n.fa-forward:before {\n  content: \"\\f04e\";\n}\n\n.fa-fast-forward:before {\n  content: \"\\f050\";\n}\n\n.fa-step-forward:before {\n  content: \"\\f051\";\n}\n\n.fa-eject:before {\n  content: \"\\f052\";\n}\n\n.fa-chevron-left:before {\n  content: \"\\f053\";\n}\n\n.fa-chevron-right:before {\n  content: \"\\f054\";\n}\n\n.fa-plus-circle:before {\n  content: \"\\f055\";\n}\n\n.fa-minus-circle:before {\n  content: \"\\f056\";\n}\n\n.fa-times-circle:before {\n  content: \"\\f057\";\n}\n\n.fa-check-circle:before {\n  content: \"\\f058\";\n}\n\n.fa-question-circle:before {\n  content: \"\\f059\";\n}\n\n.fa-info-circle:before {\n  content: \"\\f05a\";\n}\n\n.fa-crosshairs:before {\n  content: \"\\f05b\";\n}\n\n.fa-times-circle-o:before {\n  content: \"\\f05c\";\n}\n\n.fa-check-circle-o:before {\n  content: \"\\f05d\";\n}\n\n.fa-ban:before {\n  content: \"\\f05e\";\n}\n\n.fa-arrow-left:before {\n  content: \"\\f060\";\n}\n\n.fa-arrow-right:before {\n  content: \"\\f061\";\n}\n\n.fa-arrow-up:before {\n  content: \"\\f062\";\n}\n\n.fa-arrow-down:before {\n  content: \"\\f063\";\n}\n\n.fa-mail-forward:before,\n.fa-share:before {\n  content: \"\\f064\";\n}\n\n.fa-expand:before {\n  content: \"\\f065\";\n}\n\n.fa-compress:before {\n  content: \"\\f066\";\n}\n\n.fa-plus:before {\n  content: \"\\f067\";\n}\n\n.fa-minus:before {\n  content: \"\\f068\";\n}\n\n.fa-asterisk:before {\n  content: \"\\f069\";\n}\n\n.fa-exclamation-circle:before {\n  content: \"\\f06a\";\n}\n\n.fa-gift:before {\n  content: \"\\f06b\";\n}\n\n.fa-leaf:before {\n  content: \"\\f06c\";\n}\n\n.fa-fire:before {\n  content: \"\\f06d\";\n}\n\n.fa-eye:before {\n  content: \"\\f06e\";\n}\n\n.fa-eye-slash:before {\n  content: \"\\f070\";\n}\n\n.fa-warning:before,\n.fa-exclamation-triangle:before {\n  content: \"\\f071\";\n}\n\n.fa-plane:before {\n  content: \"\\f072\";\n}\n\n.fa-calendar:before {\n  content: \"\\f073\";\n}\n\n.fa-random:before {\n  content: \"\\f074\";\n}\n\n.fa-comment:before {\n  content: \"\\f075\";\n}\n\n.fa-magnet:before {\n  content: \"\\f076\";\n}\n\n.fa-chevron-up:before {\n  content: \"\\f077\";\n}\n\n.fa-chevron-down:before {\n  content: \"\\f078\";\n}\n\n.fa-retweet:before {\n  content: \"\\f079\";\n}\n\n.fa-shopping-cart:before {\n  content: \"\\f07a\";\n}\n\n.fa-folder:before {\n  content: \"\\f07b\";\n}\n\n.fa-folder-open:before {\n  content: \"\\f07c\";\n}\n\n.fa-arrows-v:before {\n  content: \"\\f07d\";\n}\n\n.fa-arrows-h:before {\n  content: \"\\f07e\";\n}\n\n.fa-bar-chart-o:before,\n.fa-bar-chart:before {\n  content: \"\\f080\";\n}\n\n.fa-twitter-square:before {\n  content: \"\\f081\";\n}\n\n.fa-facebook-square:before {\n  content: \"\\f082\";\n}\n\n.fa-camera-retro:before {\n  content: \"\\f083\";\n}\n\n.fa-key:before {\n  content: \"\\f084\";\n}\n\n.fa-gears:before,\n.fa-cogs:before {\n  content: \"\\f085\";\n}\n\n.fa-comments:before {\n  content: \"\\f086\";\n}\n\n.fa-thumbs-o-up:before {\n  content: \"\\f087\";\n}\n\n.fa-thumbs-o-down:before {\n  content: \"\\f088\";\n}\n\n.fa-star-half:before {\n  content: \"\\f089\";\n}\n\n.fa-heart-o:before {\n  content: \"\\f08a\";\n}\n\n.fa-sign-out:before {\n  content: \"\\f08b\";\n}\n\n.fa-linkedin-square:before {\n  content: \"\\f08c\";\n}\n\n.fa-thumb-tack:before {\n  content: \"\\f08d\";\n}\n\n.fa-external-link:before {\n  content: \"\\f08e\";\n}\n\n.fa-sign-in:before {\n  content: \"\\f090\";\n}\n\n.fa-trophy:before {\n  content: \"\\f091\";\n}\n\n.fa-github-square:before {\n  content: \"\\f092\";\n}\n\n.fa-upload:before {\n  content: \"\\f093\";\n}\n\n.fa-lemon-o:before {\n  content: \"\\f094\";\n}\n\n.fa-phone:before {\n  content: \"\\f095\";\n}\n\n.fa-square-o:before {\n  content: \"\\f096\";\n}\n\n.fa-bookmark-o:before {\n  content: \"\\f097\";\n}\n\n.fa-phone-square:before {\n  content: \"\\f098\";\n}\n\n.fa-twitter:before {\n  content: \"\\f099\";\n}\n\n.fa-facebook-f:before,\n.fa-facebook:before {\n  content: \"\\f09a\";\n}\n\n.fa-github:before {\n  content: \"\\f09b\";\n}\n\n.fa-unlock:before {\n  content: \"\\f09c\";\n}\n\n.fa-credit-card:before {\n  content: \"\\f09d\";\n}\n\n.fa-rss:before {\n  content: \"\\f09e\";\n}\n\n.fa-hdd-o:before {\n  content: \"\\f0a0\";\n}\n\n.fa-bullhorn:before {\n  content: \"\\f0a1\";\n}\n\n.fa-bell:before {\n  content: \"\\f0f3\";\n}\n\n.fa-certificate:before {\n  content: \"\\f0a3\";\n}\n\n.fa-hand-o-right:before {\n  content: \"\\f0a4\";\n}\n\n.fa-hand-o-left:before {\n  content: \"\\f0a5\";\n}\n\n.fa-hand-o-up:before {\n  content: \"\\f0a6\";\n}\n\n.fa-hand-o-down:before {\n  content: \"\\f0a7\";\n}\n\n.fa-arrow-circle-left:before {\n  content: \"\\f0a8\";\n}\n\n.fa-arrow-circle-right:before {\n  content: \"\\f0a9\";\n}\n\n.fa-arrow-circle-up:before {\n  content: \"\\f0aa\";\n}\n\n.fa-arrow-circle-down:before {\n  content: \"\\f0ab\";\n}\n\n.fa-globe:before {\n  content: \"\\f0ac\";\n}\n\n.fa-wrench:before {\n  content: \"\\f0ad\";\n}\n\n.fa-tasks:before {\n  content: \"\\f0ae\";\n}\n\n.fa-filter:before {\n  content: \"\\f0b0\";\n}\n\n.fa-briefcase:before {\n  content: \"\\f0b1\";\n}\n\n.fa-arrows-alt:before {\n  content: \"\\f0b2\";\n}\n\n.fa-group:before,\n.fa-users:before {\n  content: \"\\f0c0\";\n}\n\n.fa-chain:before,\n.fa-link:before {\n  content: \"\\f0c1\";\n}\n\n.fa-cloud:before {\n  content: \"\\f0c2\";\n}\n\n.fa-flask:before {\n  content: \"\\f0c3\";\n}\n\n.fa-cut:before,\n.fa-scissors:before {\n  content: \"\\f0c4\";\n}\n\n.fa-copy:before,\n.fa-files-o:before {\n  content: \"\\f0c5\";\n}\n\n.fa-paperclip:before {\n  content: \"\\f0c6\";\n}\n\n.fa-save:before,\n.fa-floppy-o:before {\n  content: \"\\f0c7\";\n}\n\n.fa-square:before {\n  content: \"\\f0c8\";\n}\n\n.fa-navicon:before,\n.fa-reorder:before,\n.fa-bars:before {\n  content: \"\\f0c9\";\n}\n\n.fa-list-ul:before {\n  content: \"\\f0ca\";\n}\n\n.fa-list-ol:before {\n  content: \"\\f0cb\";\n}\n\n.fa-strikethrough:before {\n  content: \"\\f0cc\";\n}\n\n.fa-underline:before {\n  content: \"\\f0cd\";\n}\n\n.fa-table:before {\n  content: \"\\f0ce\";\n}\n\n.fa-magic:before {\n  content: \"\\f0d0\";\n}\n\n.fa-truck:before {\n  content: \"\\f0d1\";\n}\n\n.fa-pinterest:before {\n  content: \"\\f0d2\";\n}\n\n.fa-pinterest-square:before {\n  content: \"\\f0d3\";\n}\n\n.fa-google-plus-square:before {\n  content: \"\\f0d4\";\n}\n\n.fa-google-plus:before {\n  content: \"\\f0d5\";\n}\n\n.fa-money:before {\n  content: \"\\f0d6\";\n}\n\n.fa-caret-down:before {\n  content: \"\\f0d7\";\n}\n\n.fa-caret-up:before {\n  content: \"\\f0d8\";\n}\n\n.fa-caret-left:before {\n  content: \"\\f0d9\";\n}\n\n.fa-caret-right:before {\n  content: \"\\f0da\";\n}\n\n.fa-columns:before {\n  content: \"\\f0db\";\n}\n\n.fa-unsorted:before,\n.fa-sort:before {\n  content: \"\\f0dc\";\n}\n\n.fa-sort-down:before,\n.fa-sort-desc:before {\n  content: \"\\f0dd\";\n}\n\n.fa-sort-up:before,\n.fa-sort-asc:before {\n  content: \"\\f0de\";\n}\n\n.fa-envelope:before {\n  content: \"\\f0e0\";\n}\n\n.fa-linkedin:before {\n  content: \"\\f0e1\";\n}\n\n.fa-rotate-left:before,\n.fa-undo:before {\n  content: \"\\f0e2\";\n}\n\n.fa-legal:before,\n.fa-gavel:before {\n  content: \"\\f0e3\";\n}\n\n.fa-dashboard:before,\n.fa-tachometer:before {\n  content: \"\\f0e4\";\n}\n\n.fa-comment-o:before {\n  content: \"\\f0e5\";\n}\n\n.fa-comments-o:before {\n  content: \"\\f0e6\";\n}\n\n.fa-flash:before,\n.fa-bolt:before {\n  content: \"\\f0e7\";\n}\n\n.fa-sitemap:before {\n  content: \"\\f0e8\";\n}\n\n.fa-umbrella:before {\n  content: \"\\f0e9\";\n}\n\n.fa-paste:before,\n.fa-clipboard:before {\n  content: \"\\f0ea\";\n}\n\n.fa-lightbulb-o:before {\n  content: \"\\f0eb\";\n}\n\n.fa-exchange:before {\n  content: \"\\f0ec\";\n}\n\n.fa-cloud-download:before {\n  content: \"\\f0ed\";\n}\n\n.fa-cloud-upload:before {\n  content: \"\\f0ee\";\n}\n\n.fa-user-md:before {\n  content: \"\\f0f0\";\n}\n\n.fa-stethoscope:before {\n  content: \"\\f0f1\";\n}\n\n.fa-suitcase:before {\n  content: \"\\f0f2\";\n}\n\n.fa-bell-o:before {\n  content: \"\\f0a2\";\n}\n\n.fa-coffee:before {\n  content: \"\\f0f4\";\n}\n\n.fa-cutlery:before {\n  content: \"\\f0f5\";\n}\n\n.fa-file-text-o:before {\n  content: \"\\f0f6\";\n}\n\n.fa-building-o:before {\n  content: \"\\f0f7\";\n}\n\n.fa-hospital-o:before {\n  content: \"\\f0f8\";\n}\n\n.fa-ambulance:before {\n  content: \"\\f0f9\";\n}\n\n.fa-medkit:before {\n  content: \"\\f0fa\";\n}\n\n.fa-fighter-jet:before {\n  content: \"\\f0fb\";\n}\n\n.fa-beer:before {\n  content: \"\\f0fc\";\n}\n\n.fa-h-square:before {\n  content: \"\\f0fd\";\n}\n\n.fa-plus-square:before {\n  content: \"\\f0fe\";\n}\n\n.fa-angle-double-left:before {\n  content: \"\\f100\";\n}\n\n.fa-angle-double-right:before {\n  content: \"\\f101\";\n}\n\n.fa-angle-double-up:before {\n  content: \"\\f102\";\n}\n\n.fa-angle-double-down:before {\n  content: \"\\f103\";\n}\n\n.fa-angle-left:before {\n  content: \"\\f104\";\n}\n\n.fa-angle-right:before {\n  content: \"\\f105\";\n}\n\n.fa-angle-up:before {\n  content: \"\\f106\";\n}\n\n.fa-angle-down:before {\n  content: \"\\f107\";\n}\n\n.fa-desktop:before {\n  content: \"\\f108\";\n}\n\n.fa-laptop:before {\n  content: \"\\f109\";\n}\n\n.fa-tablet:before {\n  content: \"\\f10a\";\n}\n\n.fa-mobile-phone:before,\n.fa-mobile:before {\n  content: \"\\f10b\";\n}\n\n.fa-circle-o:before {\n  content: \"\\f10c\";\n}\n\n.fa-quote-left:before {\n  content: \"\\f10d\";\n}\n\n.fa-quote-right:before {\n  content: \"\\f10e\";\n}\n\n.fa-spinner:before {\n  content: \"\\f110\";\n}\n\n.fa-circle:before {\n  content: \"\\f111\";\n}\n\n.fa-mail-reply:before,\n.fa-reply:before {\n  content: \"\\f112\";\n}\n\n.fa-github-alt:before {\n  content: \"\\f113\";\n}\n\n.fa-folder-o:before {\n  content: \"\\f114\";\n}\n\n.fa-folder-open-o:before {\n  content: \"\\f115\";\n}\n\n.fa-smile-o:before {\n  content: \"\\f118\";\n}\n\n.fa-frown-o:before {\n  content: \"\\f119\";\n}\n\n.fa-meh-o:before {\n  content: \"\\f11a\";\n}\n\n.fa-gamepad:before {\n  content: \"\\f11b\";\n}\n\n.fa-keyboard-o:before {\n  content: \"\\f11c\";\n}\n\n.fa-flag-o:before {\n  content: \"\\f11d\";\n}\n\n.fa-flag-checkered:before {\n  content: \"\\f11e\";\n}\n\n.fa-terminal:before {\n  content: \"\\f120\";\n}\n\n.fa-code:before {\n  content: \"\\f121\";\n}\n\n.fa-mail-reply-all:before,\n.fa-reply-all:before {\n  content: \"\\f122\";\n}\n\n.fa-star-half-empty:before,\n.fa-star-half-full:before,\n.fa-star-half-o:before {\n  content: \"\\f123\";\n}\n\n.fa-location-arrow:before {\n  content: \"\\f124\";\n}\n\n.fa-crop:before {\n  content: \"\\f125\";\n}\n\n.fa-code-fork:before {\n  content: \"\\f126\";\n}\n\n.fa-unlink:before,\n.fa-chain-broken:before {\n  content: \"\\f127\";\n}\n\n.fa-question:before {\n  content: \"\\f128\";\n}\n\n.fa-info:before {\n  content: \"\\f129\";\n}\n\n.fa-exclamation:before {\n  content: \"\\f12a\";\n}\n\n.fa-superscript:before {\n  content: \"\\f12b\";\n}\n\n.fa-subscript:before {\n  content: \"\\f12c\";\n}\n\n.fa-eraser:before {\n  content: \"\\f12d\";\n}\n\n.fa-puzzle-piece:before {\n  content: \"\\f12e\";\n}\n\n.fa-microphone:before {\n  content: \"\\f130\";\n}\n\n.fa-microphone-slash:before {\n  content: \"\\f131\";\n}\n\n.fa-shield:before {\n  content: \"\\f132\";\n}\n\n.fa-calendar-o:before {\n  content: \"\\f133\";\n}\n\n.fa-fire-extinguisher:before {\n  content: \"\\f134\";\n}\n\n.fa-rocket:before {\n  content: \"\\f135\";\n}\n\n.fa-maxcdn:before {\n  content: \"\\f136\";\n}\n\n.fa-chevron-circle-left:before {\n  content: \"\\f137\";\n}\n\n.fa-chevron-circle-right:before {\n  content: \"\\f138\";\n}\n\n.fa-chevron-circle-up:before {\n  content: \"\\f139\";\n}\n\n.fa-chevron-circle-down:before {\n  content: \"\\f13a\";\n}\n\n.fa-html5:before {\n  content: \"\\f13b\";\n}\n\n.fa-css3:before {\n  content: \"\\f13c\";\n}\n\n.fa-anchor:before {\n  content: \"\\f13d\";\n}\n\n.fa-unlock-alt:before {\n  content: \"\\f13e\";\n}\n\n.fa-bullseye:before {\n  content: \"\\f140\";\n}\n\n.fa-ellipsis-h:before {\n  content: \"\\f141\";\n}\n\n.fa-ellipsis-v:before {\n  content: \"\\f142\";\n}\n\n.fa-rss-square:before {\n  content: \"\\f143\";\n}\n\n.fa-play-circle:before {\n  content: \"\\f144\";\n}\n\n.fa-ticket:before {\n  content: \"\\f145\";\n}\n\n.fa-minus-square:before {\n  content: \"\\f146\";\n}\n\n.fa-minus-square-o:before {\n  content: \"\\f147\";\n}\n\n.fa-level-up:before {\n  content: \"\\f148\";\n}\n\n.fa-level-down:before {\n  content: \"\\f149\";\n}\n\n.fa-check-square:before {\n  content: \"\\f14a\";\n}\n\n.fa-pencil-square:before {\n  content: \"\\f14b\";\n}\n\n.fa-external-link-square:before {\n  content: \"\\f14c\";\n}\n\n.fa-share-square:before {\n  content: \"\\f14d\";\n}\n\n.fa-compass:before {\n  content: \"\\f14e\";\n}\n\n.fa-toggle-down:before,\n.fa-caret-square-o-down:before {\n  content: \"\\f150\";\n}\n\n.fa-toggle-up:before,\n.fa-caret-square-o-up:before {\n  content: \"\\f151\";\n}\n\n.fa-toggle-right:before,\n.fa-caret-square-o-right:before {\n  content: \"\\f152\";\n}\n\n.fa-euro:before,\n.fa-eur:before {\n  content: \"\\f153\";\n}\n\n.fa-gbp:before {\n  content: \"\\f154\";\n}\n\n.fa-dollar:before,\n.fa-usd:before {\n  content: \"\\f155\";\n}\n\n.fa-rupee:before,\n.fa-inr:before {\n  content: \"\\f156\";\n}\n\n.fa-cny:before,\n.fa-rmb:before,\n.fa-yen:before,\n.fa-jpy:before {\n  content: \"\\f157\";\n}\n\n.fa-ruble:before,\n.fa-rouble:before,\n.fa-rub:before {\n  content: \"\\f158\";\n}\n\n.fa-won:before,\n.fa-krw:before {\n  content: \"\\f159\";\n}\n\n.fa-bitcoin:before,\n.fa-btc:before {\n  content: \"\\f15a\";\n}\n\n.fa-file:before {\n  content: \"\\f15b\";\n}\n\n.fa-file-text:before {\n  content: \"\\f15c\";\n}\n\n.fa-sort-alpha-asc:before {\n  content: \"\\f15d\";\n}\n\n.fa-sort-alpha-desc:before {\n  content: \"\\f15e\";\n}\n\n.fa-sort-amount-asc:before {\n  content: \"\\f160\";\n}\n\n.fa-sort-amount-desc:before {\n  content: \"\\f161\";\n}\n\n.fa-sort-numeric-asc:before {\n  content: \"\\f162\";\n}\n\n.fa-sort-numeric-desc:before {\n  content: \"\\f163\";\n}\n\n.fa-thumbs-up:before {\n  content: \"\\f164\";\n}\n\n.fa-thumbs-down:before {\n  content: \"\\f165\";\n}\n\n.fa-youtube-square:before {\n  content: \"\\f166\";\n}\n\n.fa-youtube:before {\n  content: \"\\f167\";\n}\n\n.fa-xing:before {\n  content: \"\\f168\";\n}\n\n.fa-xing-square:before {\n  content: \"\\f169\";\n}\n\n.fa-youtube-play:before {\n  content: \"\\f16a\";\n}\n\n.fa-dropbox:before {\n  content: \"\\f16b\";\n}\n\n.fa-stack-overflow:before {\n  content: \"\\f16c\";\n}\n\n.fa-instagram:before {\n  content: \"\\f16d\";\n}\n\n.fa-flickr:before {\n  content: \"\\f16e\";\n}\n\n.fa-adn:before {\n  content: \"\\f170\";\n}\n\n.fa-bitbucket:before {\n  content: \"\\f171\";\n}\n\n.fa-bitbucket-square:before {\n  content: \"\\f172\";\n}\n\n.fa-tumblr:before {\n  content: \"\\f173\";\n}\n\n.fa-tumblr-square:before {\n  content: \"\\f174\";\n}\n\n.fa-long-arrow-down:before {\n  content: \"\\f175\";\n}\n\n.fa-long-arrow-up:before {\n  content: \"\\f176\";\n}\n\n.fa-long-arrow-left:before {\n  content: \"\\f177\";\n}\n\n.fa-long-arrow-right:before {\n  content: \"\\f178\";\n}\n\n.fa-apple:before {\n  content: \"\\f179\";\n}\n\n.fa-windows:before {\n  content: \"\\f17a\";\n}\n\n.fa-android:before {\n  content: \"\\f17b\";\n}\n\n.fa-linux:before {\n  content: \"\\f17c\";\n}\n\n.fa-dribbble:before {\n  content: \"\\f17d\";\n}\n\n.fa-skype:before {\n  content: \"\\f17e\";\n}\n\n.fa-foursquare:before {\n  content: \"\\f180\";\n}\n\n.fa-trello:before {\n  content: \"\\f181\";\n}\n\n.fa-female:before {\n  content: \"\\f182\";\n}\n\n.fa-male:before {\n  content: \"\\f183\";\n}\n\n.fa-gittip:before,\n.fa-gratipay:before {\n  content: \"\\f184\";\n}\n\n.fa-sun-o:before {\n  content: \"\\f185\";\n}\n\n.fa-moon-o:before {\n  content: \"\\f186\";\n}\n\n.fa-archive:before {\n  content: \"\\f187\";\n}\n\n.fa-bug:before {\n  content: \"\\f188\";\n}\n\n.fa-vk:before {\n  content: \"\\f189\";\n}\n\n.fa-weibo:before {\n  content: \"\\f18a\";\n}\n\n.fa-renren:before {\n  content: \"\\f18b\";\n}\n\n.fa-pagelines:before {\n  content: \"\\f18c\";\n}\n\n.fa-stack-exchange:before {\n  content: \"\\f18d\";\n}\n\n.fa-arrow-circle-o-right:before {\n  content: \"\\f18e\";\n}\n\n.fa-arrow-circle-o-left:before {\n  content: \"\\f190\";\n}\n\n.fa-toggle-left:before,\n.fa-caret-square-o-left:before {\n  content: \"\\f191\";\n}\n\n.fa-dot-circle-o:before {\n  content: \"\\f192\";\n}\n\n.fa-wheelchair:before {\n  content: \"\\f193\";\n}\n\n.fa-vimeo-square:before {\n  content: \"\\f194\";\n}\n\n.fa-turkish-lira:before,\n.fa-try:before {\n  content: \"\\f195\";\n}\n\n.fa-plus-square-o:before {\n  content: \"\\f196\";\n}\n\n.fa-space-shuttle:before {\n  content: \"\\f197\";\n}\n\n.fa-slack:before {\n  content: \"\\f198\";\n}\n\n.fa-envelope-square:before {\n  content: \"\\f199\";\n}\n\n.fa-wordpress:before {\n  content: \"\\f19a\";\n}\n\n.fa-openid:before {\n  content: \"\\f19b\";\n}\n\n.fa-institution:before,\n.fa-bank:before,\n.fa-university:before {\n  content: \"\\f19c\";\n}\n\n.fa-mortar-board:before,\n.fa-graduation-cap:before {\n  content: \"\\f19d\";\n}\n\n.fa-yahoo:before {\n  content: \"\\f19e\";\n}\n\n.fa-google:before {\n  content: \"\\f1a0\";\n}\n\n.fa-reddit:before {\n  content: \"\\f1a1\";\n}\n\n.fa-reddit-square:before {\n  content: \"\\f1a2\";\n}\n\n.fa-stumbleupon-circle:before {\n  content: \"\\f1a3\";\n}\n\n.fa-stumbleupon:before {\n  content: \"\\f1a4\";\n}\n\n.fa-delicious:before {\n  content: \"\\f1a5\";\n}\n\n.fa-digg:before {\n  content: \"\\f1a6\";\n}\n\n.fa-pied-piper:before {\n  content: \"\\f1a7\";\n}\n\n.fa-pied-piper-alt:before {\n  content: \"\\f1a8\";\n}\n\n.fa-drupal:before {\n  content: \"\\f1a9\";\n}\n\n.fa-joomla:before {\n  content: \"\\f1aa\";\n}\n\n.fa-language:before {\n  content: \"\\f1ab\";\n}\n\n.fa-fax:before {\n  content: \"\\f1ac\";\n}\n\n.fa-building:before {\n  content: \"\\f1ad\";\n}\n\n.fa-child:before {\n  content: \"\\f1ae\";\n}\n\n.fa-paw:before {\n  content: \"\\f1b0\";\n}\n\n.fa-spoon:before {\n  content: \"\\f1b1\";\n}\n\n.fa-cube:before {\n  content: \"\\f1b2\";\n}\n\n.fa-cubes:before {\n  content: \"\\f1b3\";\n}\n\n.fa-behance:before {\n  content: \"\\f1b4\";\n}\n\n.fa-behance-square:before {\n  content: \"\\f1b5\";\n}\n\n.fa-steam:before {\n  content: \"\\f1b6\";\n}\n\n.fa-steam-square:before {\n  content: \"\\f1b7\";\n}\n\n.fa-recycle:before {\n  content: \"\\f1b8\";\n}\n\n.fa-automobile:before,\n.fa-car:before {\n  content: \"\\f1b9\";\n}\n\n.fa-cab:before,\n.fa-taxi:before {\n  content: \"\\f1ba\";\n}\n\n.fa-tree:before {\n  content: \"\\f1bb\";\n}\n\n.fa-spotify:before {\n  content: \"\\f1bc\";\n}\n\n.fa-deviantart:before {\n  content: \"\\f1bd\";\n}\n\n.fa-soundcloud:before {\n  content: \"\\f1be\";\n}\n\n.fa-database:before {\n  content: \"\\f1c0\";\n}\n\n.fa-file-pdf-o:before {\n  content: \"\\f1c1\";\n}\n\n.fa-file-word-o:before {\n  content: \"\\f1c2\";\n}\n\n.fa-file-excel-o:before {\n  content: \"\\f1c3\";\n}\n\n.fa-file-powerpoint-o:before {\n  content: \"\\f1c4\";\n}\n\n.fa-file-photo-o:before,\n.fa-file-picture-o:before,\n.fa-file-image-o:before {\n  content: \"\\f1c5\";\n}\n\n.fa-file-zip-o:before,\n.fa-file-archive-o:before {\n  content: \"\\f1c6\";\n}\n\n.fa-file-sound-o:before,\n.fa-file-audio-o:before {\n  content: \"\\f1c7\";\n}\n\n.fa-file-movie-o:before,\n.fa-file-video-o:before {\n  content: \"\\f1c8\";\n}\n\n.fa-file-code-o:before {\n  content: \"\\f1c9\";\n}\n\n.fa-vine:before {\n  content: \"\\f1ca\";\n}\n\n.fa-codepen:before {\n  content: \"\\f1cb\";\n}\n\n.fa-jsfiddle:before {\n  content: \"\\f1cc\";\n}\n\n.fa-life-bouy:before,\n.fa-life-buoy:before,\n.fa-life-saver:before,\n.fa-support:before,\n.fa-life-ring:before {\n  content: \"\\f1cd\";\n}\n\n.fa-circle-o-notch:before {\n  content: \"\\f1ce\";\n}\n\n.fa-ra:before,\n.fa-rebel:before {\n  content: \"\\f1d0\";\n}\n\n.fa-ge:before,\n.fa-empire:before {\n  content: \"\\f1d1\";\n}\n\n.fa-git-square:before {\n  content: \"\\f1d2\";\n}\n\n.fa-git:before {\n  content: \"\\f1d3\";\n}\n\n.fa-hacker-news:before {\n  content: \"\\f1d4\";\n}\n\n.fa-tencent-weibo:before {\n  content: \"\\f1d5\";\n}\n\n.fa-qq:before {\n  content: \"\\f1d6\";\n}\n\n.fa-wechat:before,\n.fa-weixin:before {\n  content: \"\\f1d7\";\n}\n\n.fa-send:before,\n.fa-paper-plane:before {\n  content: \"\\f1d8\";\n}\n\n.fa-send-o:before,\n.fa-paper-plane-o:before {\n  content: \"\\f1d9\";\n}\n\n.fa-history:before {\n  content: \"\\f1da\";\n}\n\n.fa-genderless:before,\n.fa-circle-thin:before {\n  content: \"\\f1db\";\n}\n\n.fa-header:before {\n  content: \"\\f1dc\";\n}\n\n.fa-paragraph:before {\n  content: \"\\f1dd\";\n}\n\n.fa-sliders:before {\n  content: \"\\f1de\";\n}\n\n.fa-share-alt:before {\n  content: \"\\f1e0\";\n}\n\n.fa-share-alt-square:before {\n  content: \"\\f1e1\";\n}\n\n.fa-bomb:before {\n  content: \"\\f1e2\";\n}\n\n.fa-soccer-ball-o:before,\n.fa-futbol-o:before {\n  content: \"\\f1e3\";\n}\n\n.fa-tty:before {\n  content: \"\\f1e4\";\n}\n\n.fa-binoculars:before {\n  content: \"\\f1e5\";\n}\n\n.fa-plug:before {\n  content: \"\\f1e6\";\n}\n\n.fa-slideshare:before {\n  content: \"\\f1e7\";\n}\n\n.fa-twitch:before {\n  content: \"\\f1e8\";\n}\n\n.fa-yelp:before {\n  content: \"\\f1e9\";\n}\n\n.fa-newspaper-o:before {\n  content: \"\\f1ea\";\n}\n\n.fa-wifi:before {\n  content: \"\\f1eb\";\n}\n\n.fa-calculator:before {\n  content: \"\\f1ec\";\n}\n\n.fa-paypal:before {\n  content: \"\\f1ed\";\n}\n\n.fa-google-wallet:before {\n  content: \"\\f1ee\";\n}\n\n.fa-cc-visa:before {\n  content: \"\\f1f0\";\n}\n\n.fa-cc-mastercard:before {\n  content: \"\\f1f1\";\n}\n\n.fa-cc-discover:before {\n  content: \"\\f1f2\";\n}\n\n.fa-cc-amex:before {\n  content: \"\\f1f3\";\n}\n\n.fa-cc-paypal:before {\n  content: \"\\f1f4\";\n}\n\n.fa-cc-stripe:before {\n  content: \"\\f1f5\";\n}\n\n.fa-bell-slash:before {\n  content: \"\\f1f6\";\n}\n\n.fa-bell-slash-o:before {\n  content: \"\\f1f7\";\n}\n\n.fa-trash:before {\n  content: \"\\f1f8\";\n}\n\n.fa-copyright:before {\n  content: \"\\f1f9\";\n}\n\n.fa-at:before {\n  content: \"\\f1fa\";\n}\n\n.fa-eyedropper:before {\n  content: \"\\f1fb\";\n}\n\n.fa-paint-brush:before {\n  content: \"\\f1fc\";\n}\n\n.fa-birthday-cake:before {\n  content: \"\\f1fd\";\n}\n\n.fa-area-chart:before {\n  content: \"\\f1fe\";\n}\n\n.fa-pie-chart:before {\n  content: \"\\f200\";\n}\n\n.fa-line-chart:before {\n  content: \"\\f201\";\n}\n\n.fa-lastfm:before {\n  content: \"\\f202\";\n}\n\n.fa-lastfm-square:before {\n  content: \"\\f203\";\n}\n\n.fa-toggle-off:before {\n  content: \"\\f204\";\n}\n\n.fa-toggle-on:before {\n  content: \"\\f205\";\n}\n\n.fa-bicycle:before {\n  content: \"\\f206\";\n}\n\n.fa-bus:before {\n  content: \"\\f207\";\n}\n\n.fa-ioxhost:before {\n  content: \"\\f208\";\n}\n\n.fa-angellist:before {\n  content: \"\\f209\";\n}\n\n.fa-cc:before {\n  content: \"\\f20a\";\n}\n\n.fa-shekel:before,\n.fa-sheqel:before,\n.fa-ils:before {\n  content: \"\\f20b\";\n}\n\n.fa-meanpath:before {\n  content: \"\\f20c\";\n}\n\n.fa-buysellads:before {\n  content: \"\\f20d\";\n}\n\n.fa-connectdevelop:before {\n  content: \"\\f20e\";\n}\n\n.fa-dashcube:before {\n  content: \"\\f210\";\n}\n\n.fa-forumbee:before {\n  content: \"\\f211\";\n}\n\n.fa-leanpub:before {\n  content: \"\\f212\";\n}\n\n.fa-sellsy:before {\n  content: \"\\f213\";\n}\n\n.fa-shirtsinbulk:before {\n  content: \"\\f214\";\n}\n\n.fa-simplybuilt:before {\n  content: \"\\f215\";\n}\n\n.fa-skyatlas:before {\n  content: \"\\f216\";\n}\n\n.fa-cart-plus:before {\n  content: \"\\f217\";\n}\n\n.fa-cart-arrow-down:before {\n  content: \"\\f218\";\n}\n\n.fa-diamond:before {\n  content: \"\\f219\";\n}\n\n.fa-ship:before {\n  content: \"\\f21a\";\n}\n\n.fa-user-secret:before {\n  content: \"\\f21b\";\n}\n\n.fa-motorcycle:before {\n  content: \"\\f21c\";\n}\n\n.fa-street-view:before {\n  content: \"\\f21d\";\n}\n\n.fa-heartbeat:before {\n  content: \"\\f21e\";\n}\n\n.fa-venus:before {\n  content: \"\\f221\";\n}\n\n.fa-mars:before {\n  content: \"\\f222\";\n}\n\n.fa-mercury:before {\n  content: \"\\f223\";\n}\n\n.fa-transgender:before {\n  content: \"\\f224\";\n}\n\n.fa-transgender-alt:before {\n  content: \"\\f225\";\n}\n\n.fa-venus-double:before {\n  content: \"\\f226\";\n}\n\n.fa-mars-double:before {\n  content: \"\\f227\";\n}\n\n.fa-venus-mars:before {\n  content: \"\\f228\";\n}\n\n.fa-mars-stroke:before {\n  content: \"\\f229\";\n}\n\n.fa-mars-stroke-v:before {\n  content: \"\\f22a\";\n}\n\n.fa-mars-stroke-h:before {\n  content: \"\\f22b\";\n}\n\n.fa-neuter:before {\n  content: \"\\f22c\";\n}\n\n.fa-facebook-official:before {\n  content: \"\\f230\";\n}\n\n.fa-pinterest-p:before {\n  content: \"\\f231\";\n}\n\n.fa-whatsapp:before {\n  content: \"\\f232\";\n}\n\n.fa-server:before {\n  content: \"\\f233\";\n}\n\n.fa-user-plus:before {\n  content: \"\\f234\";\n}\n\n.fa-user-times:before {\n  content: \"\\f235\";\n}\n\n.fa-hotel:before,\n.fa-bed:before {\n  content: \"\\f236\";\n}\n\n.fa-viacoin:before {\n  content: \"\\f237\";\n}\n\n.fa-train:before {\n  content: \"\\f238\";\n}\n\n.fa-subway:before {\n  content: \"\\f239\";\n}\n\n.fa-medium:before {\n  content: \"\\f23a\";\n}\n\n/*! prefixes.scss v0.1.0 | Author: Pandao | https://github.com/pandao/prefixes.scss | MIT license | Copyright (c) 2015 */\n@font-face {\n  font-family: 'editormd-logo';\n  src: url(\"../fonts/editormd-logo.eot?-5y8q6h\");\n  src: url(\".../fonts/editormd-logo.eot?#iefix-5y8q6h\") format(\"embedded-opentype\"), url(\"../fonts/editormd-logo.woff?-5y8q6h\") format(\"woff\"), url(\"../fonts/editormd-logo.ttf?-5y8q6h\") format(\"truetype\"), url(\"../fonts/editormd-logo.svg?-5y8q6h#icomoon\") format(\"svg\");\n  font-weight: normal;\n  font-style: normal;\n}\n.editormd-logo,\n.editormd-logo-1x,\n.editormd-logo-2x,\n.editormd-logo-3x,\n.editormd-logo-4x,\n.editormd-logo-5x,\n.editormd-logo-6x,\n.editormd-logo-7x,\n.editormd-logo-8x {\n  font-family: 'editormd-logo';\n  speak: none;\n  font-style: normal;\n  font-weight: normal;\n  font-variant: normal;\n  text-transform: none;\n  font-size: inherit;\n  line-height: 1;\n  display: inline-block;\n  text-rendering: auto;\n  vertical-align: inherit;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n.editormd-logo:before,\n.editormd-logo-1x:before,\n.editormd-logo-2x:before,\n.editormd-logo-3x:before,\n.editormd-logo-4x:before,\n.editormd-logo-5x:before,\n.editormd-logo-6x:before,\n.editormd-logo-7x:before,\n.editormd-logo-8x:before {\n  content: \"\\e1987\";\n  /* \n  HTML Entity &#xe1987; \n  example: <span class=\"editormd-logo\">&#xe1987;</span>\n  */\n}\n\n.editormd-logo-1x {\n  font-size: 1em;\n}\n\n.editormd-logo-lg {\n  font-size: 1.2em;\n}\n\n.editormd-logo-2x {\n  font-size: 2em;\n}\n\n.editormd-logo-3x {\n  font-size: 3em;\n}\n\n.editormd-logo-4x {\n  font-size: 4em;\n}\n\n.editormd-logo-5x {\n  font-size: 5em;\n}\n\n.editormd-logo-6x {\n  font-size: 6em;\n}\n\n.editormd-logo-7x {\n  font-size: 7em;\n}\n\n.editormd-logo-8x {\n  font-size: 8em;\n}\n\n.editormd-logo-color {\n  color: #2196F3;\n}\n\n/*! github-markdown-css | The MIT License (MIT) | Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com) | https://github.com/sindresorhus/github-markdown-css */\n@font-face {\n  font-family: octicons-anchor;\n  src: url(data:font/woff;charset=utf-8;base64,d09GRgABAAAAAAYcAA0AAAAACjQAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRlRNAAABMAAAABwAAAAca8vGTk9TLzIAAAFMAAAARAAAAFZG1VHVY21hcAAAAZAAAAA+AAABQgAP9AdjdnQgAAAB0AAAAAQAAAAEACICiGdhc3AAAAHUAAAACAAAAAj//wADZ2x5ZgAAAdwAAADRAAABEKyikaNoZWFkAAACsAAAAC0AAAA2AtXoA2hoZWEAAALgAAAAHAAAACQHngNFaG10eAAAAvwAAAAQAAAAEAwAACJsb2NhAAADDAAAAAoAAAAKALIAVG1heHAAAAMYAAAAHwAAACABEAB2bmFtZQAAAzgAAALBAAAFu3I9x/Nwb3N0AAAF/AAAAB0AAAAvaoFvbwAAAAEAAAAAzBdyYwAAAADP2IQvAAAAAM/bz7t4nGNgZGFgnMDAysDB1Ml0hoGBoR9CM75mMGLkYGBgYmBlZsAKAtJcUxgcPsR8iGF2+O/AEMPsznAYKMwIkgMA5REMOXicY2BgYGaAYBkGRgYQsAHyGMF8FgYFIM0ChED+h5j//yEk/3KoSgZGNgYYk4GRCUgwMaACRoZhDwCs7QgGAAAAIgKIAAAAAf//AAJ4nHWMMQrCQBBF/0zWrCCIKUQsTDCL2EXMohYGSSmorScInsRGL2DOYJe0Ntp7BK+gJ1BxF1stZvjz/v8DRghQzEc4kIgKwiAppcA9LtzKLSkdNhKFY3HF4lK69ExKslx7Xa+vPRVS43G98vG1DnkDMIBUgFN0MDXflU8tbaZOUkXUH0+U27RoRpOIyCKjbMCVejwypzJJG4jIwb43rfl6wbwanocrJm9XFYfskuVC5K/TPyczNU7b84CXcbxks1Un6H6tLH9vf2LRnn8Ax7A5WQAAAHicY2BkYGAA4teL1+yI57f5ysDNwgAC529f0kOmWRiYVgEpDgYmEA8AUzEKsQAAAHicY2BkYGB2+O/AEMPCAAJAkpEBFbAAADgKAe0EAAAiAAAAAAQAAAAEAAAAAAAAKgAqACoAiAAAeJxjYGRgYGBhsGFgYgABEMkFhAwM/xn0QAIAD6YBhwB4nI1Ty07cMBS9QwKlQapQW3VXySvEqDCZGbGaHULiIQ1FKgjWMxknMfLEke2A+IJu+wntrt/QbVf9gG75jK577Lg8K1qQPCfnnnt8fX1NRC/pmjrk/zprC+8D7tBy9DHgBXoWfQ44Av8t4Bj4Z8CLtBL9CniJluPXASf0Lm4CXqFX8Q84dOLnMB17N4c7tBo1AS/Qi+hTwBH4rwHHwN8DXqQ30XXAS7QaLwSc0Gn8NuAVWou/gFmnjLrEaEh9GmDdDGgL3B4JsrRPDU2hTOiMSuJUIdKQQayiAth69r6akSSFqIJuA19TrzCIaY8sIoxyrNIrL//pw7A2iMygkX5vDj+G+kuoLdX4GlGK/8Lnlz6/h9MpmoO9rafrz7ILXEHHaAx95s9lsI7AHNMBWEZHULnfAXwG9/ZqdzLI08iuwRloXE8kfhXYAvE23+23DU3t626rbs8/8adv+9DWknsHp3E17oCf+Z48rvEQNZ78paYM38qfk3v/u3l3u3GXN2Dmvmvpf1Srwk3pB/VSsp512bA/GG5i2WJ7wu430yQ5K3nFGiOqgtmSB5pJVSizwaacmUZzZhXLlZTq8qGGFY2YcSkqbth6aW1tRmlaCFs2016m5qn36SbJrqosG4uMV4aP2PHBmB3tjtmgN2izkGQyLWprekbIntJFing32a5rKWCN/SdSoga45EJykyQ7asZvHQ8PTm6cslIpwyeyjbVltNikc2HTR7YKh9LBl9DADC0U/jLcBZDKrMhUBfQBvXRzLtFtjU9eNHKin0x5InTqb8lNpfKv1s1xHzTXRqgKzek/mb7nB8RZTCDhGEX3kK/8Q75AmUM/eLkfA+0Hi908Kx4eNsMgudg5GLdRD7a84npi+YxNr5i5KIbW5izXas7cHXIMAau1OueZhfj+cOcP3P8MNIWLyYOBuxL6DRylJ4cAAAB4nGNgYoAALjDJyIAOWMCiTIxMLDmZedkABtIBygAAAA==) format(\"woff\");\n}\n.markdown-body {\n  -ms-text-size-adjust: 100%;\n  -webkit-text-size-adjust: 100%;\n  color: #333;\n  overflow: hidden;\n  font-family: \"Microsoft YaHei\", Helvetica, \"Meiryo UI\", \"Malgun Gothic\", \"Segoe UI\", \"Trebuchet MS\", \"Monaco\", monospace, Tahoma, STXihei, \"华文细黑\", STHeiti, \"Helvetica Neue\", \"Droid Sans\", \"wenquanyi micro hei\", FreeSans, Arimo, Arial, SimSun, \"宋体\", Heiti, \"黑体\", sans-serif;\n  font-size: 16px;\n  line-height: 1.6;\n  word-wrap: break-word;\n}\n\n.markdown-body a {\n  background: transparent;\n}\n\n.markdown-body a:active,\n.markdown-body a:hover {\n  outline: 0;\n}\n\n.markdown-body strong {\n  font-weight: bold;\n}\n\n.markdown-body h1 {\n  font-size: 2em;\n  margin: 0.67em 0;\n}\n\n.markdown-body img {\n  border: 0;\n}\n\n.markdown-body hr {\n  -moz-box-sizing: content-box;\n  box-sizing: content-box;\n  height: 0;\n}\n\n.markdown-body pre {\n  overflow: auto;\n}\n\n.markdown-body code,\n.markdown-body kbd,\n.markdown-body pre {\n  font-family: \"Meiryo UI\", \"YaHei Consolas Hybrid\", Consolas, \"Malgun Gothic\", \"Segoe UI\", \"Trebuchet MS\", Helvetica, monospace, monospace;\n  font-size: 1em;\n}\n\n.markdown-body input {\n  color: inherit;\n  font: inherit;\n  margin: 0;\n}\n\n.markdown-body html input[disabled] {\n  cursor: default;\n}\n\n.markdown-body input {\n  line-height: normal;\n}\n\n.markdown-body input[type=\"checkbox\"] {\n  -moz-box-sizing: border-box;\n  box-sizing: border-box;\n  padding: 0;\n}\n\n.markdown-body table {\n  border-collapse: collapse;\n  border-spacing: 0;\n}\n\n.markdown-body td,\n.markdown-body th {\n  padding: 0;\n}\n\n.markdown-body * {\n  -moz-box-sizing: border-box;\n  box-sizing: border-box;\n}\n\n.markdown-body input {\n  font: 13px/1.4 Helvetica, arial, freesans, clean, sans-serif, \"Segoe UI Emoji\", \"Segoe UI Symbol\";\n}\n\n.markdown-body a {\n  color: #4183c4;\n  text-decoration: none;\n}\n\n.markdown-body a:hover,\n.markdown-body a:active {\n  text-decoration: underline;\n}\n\n.markdown-body hr {\n  height: 0;\n  margin: 15px 0;\n  overflow: hidden;\n  background: transparent;\n  border: 0;\n  border-bottom: 1px solid #ddd;\n}\n\n.markdown-body hr:before {\n  display: table;\n  content: \"\";\n}\n\n.markdown-body hr:after {\n  display: table;\n  clear: both;\n  content: \"\";\n}\n\n.markdown-body h1,\n.markdown-body h2,\n.markdown-body h3,\n.markdown-body h4,\n.markdown-body h5,\n.markdown-body h6 {\n  margin-top: 15px;\n  margin-bottom: 15px;\n  line-height: 1.1;\n}\n\n.markdown-body h1 {\n  font-size: 30px;\n}\n\n.markdown-body h2 {\n  font-size: 21px;\n}\n\n.markdown-body h3 {\n  font-size: 16px;\n}\n\n.markdown-body h4 {\n  font-size: 14px;\n}\n\n.markdown-body h5 {\n  font-size: 12px;\n}\n\n.markdown-body h6 {\n  font-size: 11px;\n}\n\n.markdown-body blockquote {\n  margin: 0;\n}\n\n.markdown-body ul,\n.markdown-body ol {\n  padding: 0;\n  margin-top: 0;\n  margin-bottom: 0;\n}\n\n.markdown-body ol ol,\n.markdown-body ul ol {\n  list-style-type: lower-roman;\n}\n\n.markdown-body ul ul ol,\n.markdown-body ul ol ol,\n.markdown-body ol ul ol,\n.markdown-body ol ol ol {\n  list-style-type: lower-alpha;\n}\n\n.markdown-body dd {\n  margin-left: 0;\n}\n\n.markdown-body code {\n  font-family: Consolas, \"Liberation Mono\", Menlo, Courier, monospace;\n  font-size: 12px;\n}\n\n.markdown-body pre {\n  margin-top: 0;\n  margin-bottom: 0;\n  font: 12px Consolas, \"Liberation Mono\", Menlo, Courier, monospace;\n}\n\n.markdown-body .octicon {\n  font: normal normal 16px octicons-anchor;\n  line-height: 1;\n  display: inline-block;\n  text-decoration: none;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n  -webkit-user-select: none;\n  -moz-user-select: none;\n  -ms-user-select: none;\n  user-select: none;\n}\n\n.markdown-body .octicon-link:before {\n  content: '\\f05c';\n}\n\n.markdown-body > *:first-child {\n  margin-top: 0 !important;\n}\n\n.markdown-body > *:last-child {\n  margin-bottom: 0 !important;\n}\n\n.markdown-body .anchor {\n  position: absolute;\n  top: 0;\n  left: 0;\n  display: block;\n  padding-right: 6px;\n  padding-left: 30px;\n  margin-left: -30px;\n}\n\n.markdown-body .anchor:focus {\n  outline: none;\n}\n\n.markdown-body h1,\n.markdown-body h2,\n.markdown-body h3,\n.markdown-body h4,\n.markdown-body h5,\n.markdown-body h6 {\n  position: relative;\n  margin-top: 1em;\n  margin-bottom: 16px;\n  font-weight: bold;\n  line-height: 1.4;\n}\n\n.markdown-body h1 .octicon-link,\n.markdown-body h2 .octicon-link,\n.markdown-body h3 .octicon-link,\n.markdown-body h4 .octicon-link,\n.markdown-body h5 .octicon-link,\n.markdown-body h6 .octicon-link {\n  display: none;\n  color: #000;\n  vertical-align: middle;\n}\n\n.markdown-body h1:hover .anchor,\n.markdown-body h2:hover .anchor,\n.markdown-body h3:hover .anchor,\n.markdown-body h4:hover .anchor,\n.markdown-body h5:hover .anchor,\n.markdown-body h6:hover .anchor {\n  padding-left: 8px;\n  margin-left: -30px;\n  text-decoration: none;\n}\n\n.markdown-body h1:hover .anchor .octicon-link,\n.markdown-body h2:hover .anchor .octicon-link,\n.markdown-body h3:hover .anchor .octicon-link,\n.markdown-body h4:hover .anchor .octicon-link,\n.markdown-body h5:hover .anchor .octicon-link,\n.markdown-body h6:hover .anchor .octicon-link {\n  display: inline-block;\n}\n\n.markdown-body h1 {\n  padding-bottom: 0.3em;\n  font-size: 2.25em;\n  line-height: 1.2;\n  border-bottom: 1px solid #eee;\n}\n\n.markdown-body h1 .anchor {\n  line-height: 1;\n}\n\n.markdown-body h2 {\n  padding-bottom: 0.3em;\n  font-size: 1.75em;\n  line-height: 1.225;\n  border-bottom: 1px solid #eee;\n}\n\n.markdown-body h2 .anchor {\n  line-height: 1;\n}\n\n.markdown-body h3 {\n  font-size: 1.5em;\n  line-height: 1.43;\n}\n\n.markdown-body h3 .anchor {\n  line-height: 1.2;\n}\n\n.markdown-body h4 {\n  font-size: 1.25em;\n}\n\n.markdown-body h4 .anchor {\n  line-height: 1.2;\n}\n\n.markdown-body h5 {\n  font-size: 1em;\n}\n\n.markdown-body h5 .anchor {\n  line-height: 1.1;\n}\n\n.markdown-body h6 {\n  font-size: 1em;\n  color: #777;\n}\n\n.markdown-body h6 .anchor {\n  line-height: 1.1;\n}\n\n.markdown-body p,\n.markdown-body blockquote,\n.markdown-body ul,\n.markdown-body ol,\n.markdown-body dl,\n.markdown-body table,\n.markdown-body pre {\n  margin-top: 0;\n  margin-bottom: 16px;\n}\n\n/*\n.markdown-body hr {\n  height: 4px;\n  padding: 0;\n  margin: 16px 0;\n  background-color: #e7e7e7;\n  border: 0 none;\n}*/\n.markdown-body ul,\n.markdown-body ol {\n  padding-left: 2em;\n}\n\n.markdown-body ul ul,\n.markdown-body ul ol,\n.markdown-body ol ol,\n.markdown-body ol ul {\n  margin-top: 0;\n  margin-bottom: 0;\n}\n\n.markdown-body li > p {\n  margin-top: 16px;\n}\n\n.markdown-body dl {\n  padding: 0;\n}\n\n.markdown-body dl dt {\n  padding: 0;\n  margin-top: 16px;\n  font-size: 1em;\n  font-style: italic;\n  font-weight: bold;\n}\n\n.markdown-body dl dd {\n  padding: 0 16px;\n  margin-bottom: 16px;\n}\n\n.markdown-body blockquote {\n  padding: 0 15px;\n  color: #777;\n  border-left: 4px solid #ddd;\n}\n\n.markdown-body blockquote > :first-child {\n  margin-top: 0;\n}\n\n.markdown-body blockquote > :last-child {\n  margin-bottom: 0;\n}\n\n.markdown-body table {\n  display: block;\n  width: 100%;\n  overflow: auto;\n  word-break: normal;\n  word-break: keep-all;\n}\n\n.markdown-body table th {\n  font-weight: bold;\n}\n\n.markdown-body table th,\n.markdown-body table td {\n  padding: 6px 13px;\n  border: 1px solid #ddd;\n}\n\n.markdown-body table tr {\n  background-color: #fff;\n  border-top: 1px solid #ccc;\n}\n\n.markdown-body table tr:nth-child(2n) {\n  background-color: #f8f8f8;\n}\n\n.markdown-body img {\n  max-width: 100%;\n  -moz-box-sizing: border-box;\n  box-sizing: border-box;\n}\n\n.markdown-body code {\n  padding: 0;\n  padding-top: 0.2em;\n  padding-bottom: 0.2em;\n  margin: 0;\n  font-size: 85%;\n  background-color: rgba(0, 0, 0, 0.04);\n  border-radius: 3px;\n}\n\n.markdown-body code:before,\n.markdown-body code:after {\n  letter-spacing: -0.2em;\n  content: \"\\00a0\";\n}\n\n.markdown-body pre > code {\n  padding: 0;\n  margin: 0;\n  font-size: 100%;\n  word-break: normal;\n  white-space: pre;\n  background: transparent;\n  border: 0;\n}\n\n.markdown-body .highlight {\n  margin-bottom: 16px;\n}\n\n.markdown-body .highlight pre,\n.markdown-body pre {\n  padding: 16px;\n  overflow: auto;\n  font-size: 85%;\n  line-height: 1.45;\n  background-color: #f7f7f7;\n  border-radius: 3px;\n}\n\n.markdown-body .highlight pre {\n  margin-bottom: 0;\n  word-break: normal;\n}\n\n.markdown-body pre {\n  word-wrap: normal;\n}\n\n.markdown-body pre code {\n  display: inline;\n  max-width: initial;\n  padding: 0;\n  margin: 0;\n  overflow: initial;\n  line-height: inherit;\n  word-wrap: normal;\n  background-color: transparent;\n  border: 0;\n}\n\n.markdown-body pre code:before,\n.markdown-body pre code:after {\n  content: normal;\n}\n\n.markdown-body kbd {\n  display: inline-block;\n  padding: 3px 5px;\n  font-size: 11px;\n  line-height: 10px;\n  color: #555;\n  vertical-align: middle;\n  background-color: #fcfcfc;\n  border: solid 1px #ccc;\n  border-bottom-color: #bbb;\n  border-radius: 3px;\n  box-shadow: inset 0 -1px 0 #bbb;\n}\n\n.markdown-body .pl-c {\n  color: #969896;\n}\n\n.markdown-body .pl-c1,\n.markdown-body .pl-mdh,\n.markdown-body .pl-mm,\n.markdown-body .pl-mp,\n.markdown-body .pl-mr,\n.markdown-body .pl-s1 .pl-v,\n.markdown-body .pl-s3,\n.markdown-body .pl-sc,\n.markdown-body .pl-sv {\n  color: #0086b3;\n}\n\n.markdown-body .pl-e,\n.markdown-body .pl-en {\n  color: #795da3;\n}\n\n.markdown-body .pl-s1 .pl-s2,\n.markdown-body .pl-smi,\n.markdown-body .pl-smp,\n.markdown-body .pl-stj,\n.markdown-body .pl-vo,\n.markdown-body .pl-vpf {\n  color: #333;\n}\n\n.markdown-body .pl-ent {\n  color: #63a35c;\n}\n\n.markdown-body .pl-k,\n.markdown-body .pl-s,\n.markdown-body .pl-st {\n  color: #a71d5d;\n}\n\n.markdown-body .pl-pds,\n.markdown-body .pl-s1,\n.markdown-body .pl-s1 .pl-pse .pl-s2,\n.markdown-body .pl-sr,\n.markdown-body .pl-sr .pl-cce,\n.markdown-body .pl-sr .pl-sra,\n.markdown-body .pl-sr .pl-sre,\n.markdown-body .pl-src {\n  color: #df5000;\n}\n\n.markdown-body .pl-mo,\n.markdown-body .pl-v {\n  color: #1d3e81;\n}\n\n.markdown-body .pl-id {\n  color: #b52a1d;\n}\n\n.markdown-body .pl-ii {\n  background-color: #b52a1d;\n  color: #f8f8f8;\n}\n\n.markdown-body .pl-sr .pl-cce {\n  color: #63a35c;\n  font-weight: bold;\n}\n\n.markdown-body .pl-ml {\n  color: #693a17;\n}\n\n.markdown-body .pl-mh,\n.markdown-body .pl-mh .pl-en,\n.markdown-body .pl-ms {\n  color: #1d3e81;\n  font-weight: bold;\n}\n\n.markdown-body .pl-mq {\n  color: #008080;\n}\n\n.markdown-body .pl-mi {\n  color: #333;\n  font-style: italic;\n}\n\n.markdown-body .pl-mb {\n  color: #333;\n  font-weight: bold;\n}\n\n.markdown-body .pl-md,\n.markdown-body .pl-mdhf {\n  background-color: #ffecec;\n  color: #bd2c00;\n}\n\n.markdown-body .pl-mdht,\n.markdown-body .pl-mi1 {\n  background-color: #eaffea;\n  color: #55a532;\n}\n\n.markdown-body .pl-mdr {\n  color: #795da3;\n  font-weight: bold;\n}\n\n.markdown-body kbd {\n  display: inline-block;\n  padding: 3px 5px;\n  font: 11px Consolas, \"Liberation Mono\", Menlo, Courier, monospace;\n  line-height: 10px;\n  color: #555;\n  vertical-align: middle;\n  background-color: #fcfcfc;\n  border: solid 1px #ccc;\n  border-bottom-color: #bbb;\n  border-radius: 3px;\n  box-shadow: inset 0 -1px 0 #bbb;\n}\n\n.markdown-body .task-list-item {\n  list-style-type: none;\n}\n\n.markdown-body .task-list-item + .task-list-item {\n  margin-top: 3px;\n}\n\n.markdown-body .task-list-item input {\n  float: left;\n  margin: 0.3em 0 0.25em -1.6em;\n  vertical-align: middle;\n}\n\n.markdown-body :checked + .radio-label {\n  z-index: 1;\n  position: relative;\n  border-color: #4183c4;\n}\n\n.editormd-preview-container, .editormd-html-preview {\n  text-align: left;\n  font-size: 14px;\n  line-height: 1.6;\n  padding: 20px;\n  overflow: auto;\n  width: 100%;\n  background-color: #fff;\n}\n.editormd-preview-container blockquote, .editormd-html-preview blockquote {\n  color: #666;\n  border-left: 4px solid #ddd;\n  padding-left: 20px;\n  margin-left: 0;\n  font-size: 14px;\n  font-style: italic;\n}\n.editormd-preview-container p code, .editormd-html-preview p code {\n  margin-left: 5px;\n  margin-right: 4px;\n}\n.editormd-preview-container abbr, .editormd-html-preview abbr {\n  background: #ffffdd;\n}\n.editormd-preview-container hr, .editormd-html-preview hr {\n  height: 1px;\n  border: none;\n  border-top: 1px solid #ddd;\n  background: none;\n}\n.editormd-preview-container code, .editormd-html-preview code {\n  border: 1px solid #ddd;\n  background: #f6f6f6;\n  padding: 3px;\n  border-radius: 3px;\n  font-size: 14px;\n}\n.editormd-preview-container pre, .editormd-html-preview pre {\n  border: 1px solid #ddd;\n  background: #f6f6f6;\n  padding: 10px;\n  -webkit-border-radius: 3px;\n  -moz-border-radius: 3px;\n  -ms-border-radius: 3px;\n  -o-border-radius: 3px;\n  border-radius: 3px;\n}\n.editormd-preview-container pre code, .editormd-html-preview pre code {\n  padding: 0;\n}\n.editormd-preview-container pre, .editormd-preview-container code, .editormd-preview-container kbd, .editormd-html-preview pre, .editormd-html-preview code, .editormd-html-preview kbd {\n  font-family: \"YaHei Consolas Hybrid\", Consolas, \"Meiryo UI\", \"Malgun Gothic\", \"Segoe UI\", \"Trebuchet MS\", Helvetica, monospace, monospace;\n}\n.editormd-preview-container table thead tr, .editormd-html-preview table thead tr {\n  background-color: #F8F8F8;\n}\n.editormd-preview-container p.editormd-tex, .editormd-html-preview p.editormd-tex {\n  text-align: center;\n}\n.editormd-preview-container span.editormd-tex, .editormd-html-preview span.editormd-tex {\n  margin: 0 5px;\n}\n.editormd-preview-container .emoji, .editormd-html-preview .emoji {\n  width: 24px;\n  height: 24px;\n}\n.editormd-preview-container .katex, .editormd-html-preview .katex {\n  font-size: 1.4em;\n}\n.editormd-preview-container .sequence-diagram, .editormd-preview-container .flowchart, .editormd-html-preview .sequence-diagram, .editormd-html-preview .flowchart {\n  margin: 0 auto;\n  text-align: center;\n}\n.editormd-preview-container .sequence-diagram svg, .editormd-preview-container .flowchart svg, .editormd-html-preview .sequence-diagram svg, .editormd-html-preview .flowchart svg {\n  margin: 0 auto;\n}\n.editormd-preview-container .sequence-diagram text, .editormd-preview-container .flowchart text, .editormd-html-preview .sequence-diagram text, .editormd-html-preview .flowchart text {\n  font-size: 15px !important;\n  font-family: \"YaHei Consolas Hybrid\", Consolas, \"Microsoft YaHei\", \"Malgun Gothic\", \"Segoe UI\", Helvetica, Arial !important;\n}\n\n/*! Pretty printing styles. Used with prettify.js. */\n/* SPAN elements with the classes below are added by prettyprint. */\n.pln {\n  color: #000;\n}\n\n/* plain text */\n@media screen {\n  .str {\n    color: #080;\n  }\n\n  /* string content */\n  .kwd {\n    color: #008;\n  }\n\n  /* a keyword */\n  .com {\n    color: #800;\n  }\n\n  /* a comment */\n  .typ {\n    color: #606;\n  }\n\n  /* a type name */\n  .lit {\n    color: #066;\n  }\n\n  /* a literal value */\n  /* punctuation, lisp open bracket, lisp close bracket */\n  .pun, .opn, .clo {\n    color: #660;\n  }\n\n  .tag {\n    color: #008;\n  }\n\n  /* a markup tag name */\n  .atn {\n    color: #606;\n  }\n\n  /* a markup attribute name */\n  .atv {\n    color: #080;\n  }\n\n  /* a markup attribute value */\n  .dec, .var {\n    color: #606;\n  }\n\n  /* a declaration; a variable name */\n  .fun {\n    color: red;\n  }\n\n  /* a function name */\n}\n/* Use higher contrast and text-weight for printable form. */\n@media print, projection {\n  .str {\n    color: #060;\n  }\n\n  .kwd {\n    color: #006;\n    font-weight: bold;\n  }\n\n  .com {\n    color: #600;\n    font-style: italic;\n  }\n\n  .typ {\n    color: #404;\n    font-weight: bold;\n  }\n\n  .lit {\n    color: #044;\n  }\n\n  .pun, .opn, .clo {\n    color: #440;\n  }\n\n  .tag {\n    color: #006;\n    font-weight: bold;\n  }\n\n  .atn {\n    color: #404;\n  }\n\n  .atv {\n    color: #060;\n  }\n}\n/* Put a border around prettyprinted code snippets. */\npre.prettyprint {\n  padding: 2px;\n  border: 1px solid #888;\n}\n\n/* Specify class=linenums on a pre to get line numbering */\nol.linenums {\n  margin-top: 0;\n  margin-bottom: 0;\n}\n\n/* IE indents via margin-left */\nli.L0,\nli.L1,\nli.L2,\nli.L3,\nli.L5,\nli.L6,\nli.L7,\nli.L8 {\n  list-style-type: none;\n}\n\n/* Alternate shading for lines */\nli.L1,\nli.L3,\nli.L5,\nli.L7,\nli.L9 {\n  background: #eee;\n}\n\n.editormd-preview-container pre.prettyprint, .editormd-html-preview pre.prettyprint {\n  padding: 10px;\n  border: 1px solid #ddd;\n  white-space: pre-wrap;\n  word-wrap: break-word;\n}\n.editormd-preview-container ol.linenums, .editormd-html-preview ol.linenums {\n  color: #999;\n  padding-left: 2.5em;\n}\n.editormd-preview-container ol.linenums li, .editormd-html-preview ol.linenums li {\n  list-style-type: decimal;\n}\n.editormd-preview-container ol.linenums li code, .editormd-html-preview ol.linenums li code {\n  border: none;\n  background: none;\n  padding: 0;\n}\n\n.editormd-preview-container .editormd-toc-menu, .editormd-html-preview .editormd-toc-menu {\n  margin: 8px 0 12px 0;\n  display: inline-block;\n}\n.editormd-preview-container .editormd-toc-menu > .markdown-toc, .editormd-html-preview .editormd-toc-menu > .markdown-toc {\n  position: relative;\n  -webkit-border-radius: 4px;\n  -moz-border-radius: 4px;\n  -ms-border-radius: 4px;\n  -o-border-radius: 4px;\n  border-radius: 4px;\n  border: 1px solid #ddd;\n  display: inline-block;\n  font-size: 1em;\n}\n.editormd-preview-container .editormd-toc-menu > .markdown-toc > ul, .editormd-html-preview .editormd-toc-menu > .markdown-toc > ul {\n  width: 160%;\n  min-width: 180px;\n  position: absolute;\n  left: -1px;\n  top: -2px;\n  z-index: 100;\n  padding: 0 10px 10px;\n  display: none;\n  background: #fff;\n  border: 1px solid #ddd;\n  -webkit-border-radius: 4px;\n  -moz-border-radius: 4px;\n  -ms-border-radius: 4px;\n  -o-border-radius: 4px;\n  border-radius: 4px;\n  -webkit-box-shadow: 0 3px 5px rgba(0, 0, 0, 0.2);\n  /* Webkit browsers */\n  -moz-box-shadow: 0 3px 5px rgba(0, 0, 0, 0.2);\n  /* Firefox */\n  -ms-box-shadow: 0 3px 5px rgba(0, 0, 0, 0.2);\n  /* IE9 */\n  -o-box-shadow: 0 3px 5px rgba(0, 0, 0, 0.2);\n  /* Opera(Old) */\n  box-shadow: 0 3px 5px rgba(0, 0, 0, 0.2);\n  /* IE9+, News */\n}\n.editormd-preview-container .editormd-toc-menu > .markdown-toc > ul > li ul, .editormd-html-preview .editormd-toc-menu > .markdown-toc > ul > li ul {\n  width: 100%;\n  min-width: 180px;\n  border: 1px solid #ddd;\n  display: none;\n  background: #fff;\n  -webkit-border-radius: 4px;\n  -moz-border-radius: 4px;\n  -ms-border-radius: 4px;\n  -o-border-radius: 4px;\n  border-radius: 4px;\n}\n.editormd-preview-container .editormd-toc-menu > .markdown-toc > ul > li a, .editormd-html-preview .editormd-toc-menu > .markdown-toc > ul > li a {\n  color: #666;\n  padding: 6px 10px;\n  display: block;\n  -webkit-transition: background-color 500ms ease-out;\n  /* Safari, Chrome */\n  -moz-transition: background-color 500ms ease-out;\n  /* Firefox 4.0~16.0 */\n  transition: background-color 500ms ease-out;\n  /* IE >9, FF >15, Opera >12.0 */\n}\n.editormd-preview-container .editormd-toc-menu > .markdown-toc > ul > li a:hover, .editormd-html-preview .editormd-toc-menu > .markdown-toc > ul > li a:hover {\n  background-color: #f6f6f6;\n}\n.editormd-preview-container .editormd-toc-menu > .markdown-toc li, .editormd-html-preview .editormd-toc-menu > .markdown-toc li {\n  position: relative;\n}\n.editormd-preview-container .editormd-toc-menu > .markdown-toc li > ul, .editormd-html-preview .editormd-toc-menu > .markdown-toc li > ul {\n  position: absolute;\n  top: 32px;\n  left: 10%;\n  display: none;\n  -webkit-box-shadow: 0 3px 5px rgba(0, 0, 0, 0.2);\n  /* Webkit browsers */\n  -moz-box-shadow: 0 3px 5px rgba(0, 0, 0, 0.2);\n  /* Firefox */\n  -ms-box-shadow: 0 3px 5px rgba(0, 0, 0, 0.2);\n  /* IE9 */\n  -o-box-shadow: 0 3px 5px rgba(0, 0, 0, 0.2);\n  /* Opera(Old) */\n  box-shadow: 0 3px 5px rgba(0, 0, 0, 0.2);\n  /* IE9+, News */\n}\n.editormd-preview-container .editormd-toc-menu > .markdown-toc li > ul:before, .editormd-preview-container .editormd-toc-menu > .markdown-toc li > ul:after, .editormd-html-preview .editormd-toc-menu > .markdown-toc li > ul:before, .editormd-html-preview .editormd-toc-menu > .markdown-toc li > ul:after {\n  pointer-events: pointer-events;\n  position: absolute;\n  left: 15px;\n  top: -6px;\n  display: block;\n  content: \"\";\n  width: 0;\n  height: 0;\n  border: 6px solid transparent;\n  border-width: 0 6px 6px;\n  z-index: 10;\n}\n.editormd-preview-container .editormd-toc-menu > .markdown-toc li > ul:before, .editormd-html-preview .editormd-toc-menu > .markdown-toc li > ul:before {\n  border-bottom-color: #ccc;\n}\n.editormd-preview-container .editormd-toc-menu > .markdown-toc li > ul:after, .editormd-html-preview .editormd-toc-menu > .markdown-toc li > ul:after {\n  border-bottom-color: #ffffff;\n  top: -5px;\n}\n.editormd-preview-container .editormd-toc-menu ul, .editormd-html-preview .editormd-toc-menu ul {\n  list-style: none;\n}\n.editormd-preview-container .editormd-toc-menu a, .editormd-html-preview .editormd-toc-menu a {\n  text-decoration: none;\n}\n.editormd-preview-container .editormd-toc-menu h1, .editormd-html-preview .editormd-toc-menu h1 {\n  font-size: 16px;\n  padding: 5px 0 10px 10px;\n  line-height: 1;\n  border-bottom: 1px solid #eee;\n}\n.editormd-preview-container .editormd-toc-menu h1 .fa, .editormd-html-preview .editormd-toc-menu h1 .fa {\n  padding-left: 10px;\n}\n.editormd-preview-container .editormd-toc-menu .toc-menu-btn, .editormd-html-preview .editormd-toc-menu .toc-menu-btn {\n  color: #666;\n  min-width: 180px;\n  padding: 5px 10px;\n  border-radius: 4px;\n  display: inline-block;\n  -webkit-transition: background-color 500ms ease-out;\n  /* Safari, Chrome */\n  -moz-transition: background-color 500ms ease-out;\n  /* Firefox 4.0~16.0 */\n  transition: background-color 500ms ease-out;\n  /* IE >9, FF >15, Opera >12.0 */\n}\n.editormd-preview-container .editormd-toc-menu .toc-menu-btn:hover, .editormd-html-preview .editormd-toc-menu .toc-menu-btn:hover {\n  background-color: #f6f6f6;\n}\n.editormd-preview-container .editormd-toc-menu .toc-menu-btn .fa, .editormd-html-preview .editormd-toc-menu .toc-menu-btn .fa {\n  float: right;\n  padding: 3px 0 0 10px;\n  font-size: 1.3em;\n}\n\n.markdown-body .editormd-toc-menu ul {\n  padding-left: 0;\n}\n.markdown-body .highlight pre, .markdown-body pre {\n  line-height: 1.6;\n}\n\nhr.editormd-page-break {\n  border: 1px dotted #ccc;\n  font-size: 0;\n  height: 2px;\n}\n\n@media only print {\n  hr.editormd-page-break {\n    background: none;\n    border: none;\n    height: 0;\n  }\n}\n.editormd-html-preview textarea {\n  display: none;\n}\n.editormd-html-preview hr.editormd-page-break {\n  background: none;\n  border: none;\n  height: 0;\n}\n\n.editormd-preview-close-btn {\n  color: #fff;\n  padding: 4px 6px;\n  font-size: 18px;\n  -webkit-border-radius: 500px;\n  -moz-border-radius: 500px;\n  -ms-border-radius: 500px;\n  -o-border-radius: 500px;\n  border-radius: 500px;\n  display: none;\n  background-color: #ccc;\n  position: absolute;\n  top: 25px;\n  right: 35px;\n  z-index: 19;\n  -webkit-transition: background-color 300ms ease-out;\n  /* Safari, Chrome */\n  -moz-transition: background-color 300ms ease-out;\n  /* Firefox 4.0~16.0 */\n  transition: background-color 300ms ease-out;\n  /* IE >9, FF >15, Opera >12.0 */\n}\n.editormd-preview-close-btn:hover {\n  background-color: #999;\n}\n\n.editormd-preview-active {\n  width: 100%;\n  padding: 40px;\n}\n"
  },
  {
    "path": "Public/editor.md/editormd.amd.js",
    "content": "/*\n * Editor.md\n *\n * @file        editormd.amd.js \n * @version     v1.5.0 \n * @description Open source online markdown editor.\n * @license     MIT License\n * @author      Pandao\n * {@link       https://github.com/pandao/editor.md}\n * @updateTime  2015-06-09\n */\n\n;(function(factory) {\n    \"use strict\";\n    \n\t// CommonJS/Node.js\n\tif (typeof require === \"function\" && typeof exports === \"object\" && typeof module === \"object\")\n    { \n        module.exports = factory;\n    }\n\telse if (typeof define === \"function\")  // AMD/CMD/Sea.js\n\t{\n        if (define.amd) // for Require.js\n        {\n            var cmModePath  = \"codemirror/mode/\";\n            var cmAddonPath = \"codemirror/addon/\";\n\n            var codeMirrorModules = [\n                \"jquery\", \"marked\", \"prettify\",\n                \"katex\", \"raphael\", \"underscore\", \"flowchart\",  \"jqueryflowchart\",  \"sequenceDiagram\",\n\n                \"codemirror/lib/codemirror\",\n                cmModePath + \"css/css\",\n                cmModePath + \"sass/sass\",\n                cmModePath + \"shell/shell\",\n                cmModePath + \"sql/sql\",\n                cmModePath + \"clike/clike\",\n                cmModePath + \"php/php\",\n                cmModePath + \"xml/xml\",\n                cmModePath + \"markdown/markdown\",\n                cmModePath + \"javascript/javascript\",\n                cmModePath + \"htmlmixed/htmlmixed\",\n                cmModePath + \"gfm/gfm\",\n                cmModePath + \"http/http\",\n                cmModePath + \"go/go\",\n                cmModePath + \"dart/dart\",\n                cmModePath + \"coffeescript/coffeescript\",\n                cmModePath + \"nginx/nginx\",\n                cmModePath + \"python/python\",\n                cmModePath + \"perl/perl\",\n                cmModePath + \"lua/lua\",\n                cmModePath + \"r/r\", \n                cmModePath + \"ruby/ruby\", \n                cmModePath + \"rst/rst\",\n                cmModePath + \"smartymixed/smartymixed\",\n                cmModePath + \"vb/vb\",\n                cmModePath + \"vbscript/vbscript\",\n                cmModePath + \"velocity/velocity\",\n                cmModePath + \"xquery/xquery\",\n                cmModePath + \"yaml/yaml\",\n                cmModePath + \"erlang/erlang\",\n                cmModePath + \"jade/jade\",\n\n                cmAddonPath + \"edit/trailingspace\", \n                cmAddonPath + \"dialog/dialog\", \n                cmAddonPath + \"search/searchcursor\", \n                cmAddonPath + \"search/search\", \n                cmAddonPath + \"scroll/annotatescrollbar\", \n                cmAddonPath + \"search/matchesonscrollbar\", \n                cmAddonPath + \"display/placeholder\", \n                cmAddonPath + \"edit/closetag\", \n                cmAddonPath + \"fold/foldcode\",\n                cmAddonPath + \"fold/foldgutter\",\n                cmAddonPath + \"fold/indent-fold\",\n                cmAddonPath + \"fold/brace-fold\",\n                cmAddonPath + \"fold/xml-fold\", \n                cmAddonPath + \"fold/markdown-fold\",\n                cmAddonPath + \"fold/comment-fold\", \n                cmAddonPath + \"mode/overlay\", \n                cmAddonPath + \"selection/active-line\", \n                cmAddonPath + \"edit/closebrackets\", \n                cmAddonPath + \"display/fullscreen\",\n                cmAddonPath + \"search/match-highlighter\"\n            ];\n\n            define(codeMirrorModules, factory);\n        } \n        else \n        {\n\t\t    define([\"jquery\"], factory);  // for Sea.js\n        }\n\t} \n\telse\n\t{ \n        window.editormd = factory();\n\t}\n    \n}(function() {    \n\n    if (typeof define == \"function\" && define.amd) {\n       $          = arguments[0];\n       marked     = arguments[1];\n       prettify   = arguments[2];\n       katex      = arguments[3];\n       Raphael    = arguments[4];\n       _          = arguments[5];\n       flowchart  = arguments[6];\n       CodeMirror = arguments[9];\n   }\n    \n    \"use strict\";\n    \n    var $ = (typeof (jQuery) !== \"undefined\") ? jQuery : Zepto;\n\n\tif (typeof ($) === \"undefined\") {\n\t\treturn ;\n\t}\n    \n    /**\n     * editormd\n     * \n     * @param   {String} id           编辑器的ID\n     * @param   {Object} options      配置选项 Key/Value\n     * @returns {Object} editormd     返回editormd对象\n     */\n    \n    var editormd         = function (id, options) {\n        return new editormd.fn.init(id, options);\n    };\n    \n    editormd.title        = editormd.$name = \"Editor.md\";\n    editormd.version      = \"1.5.0\";\n    editormd.homePage     = \"https://pandao.github.io/editor.md/\";\n    editormd.classPrefix  = \"editormd-\";\n    \n    editormd.toolbarModes = {\n        full : [\n            \"undo\", \"redo\", \"|\", \n            \"bold\", \"del\", \"italic\", \"quote\", \"ucwords\", \"uppercase\", \"lowercase\", \"|\", \n            \"h1\", \"h2\", \"h3\", \"h4\", \"h5\", \"h6\", \"|\", \n            \"list-ul\", \"list-ol\", \"hr\", \"|\",\n            \"link\", \"reference-link\", \"image\", \"code\", \"preformatted-text\", \"code-block\", \"table\", \"datetime\", \"emoji\", \"html-entities\", \"pagebreak\", \"|\",\n            \"goto-line\", \"watch\", \"preview\", \"fullscreen\", \"clear\", \"search\", \"|\",\n            \"help\", \"info\"\n        ],\n        simple : [\n            \"undo\", \"redo\", \"|\", \n            \"bold\", \"del\", \"italic\", \"quote\", \"uppercase\", \"lowercase\", \"|\", \n            \"h1\", \"h2\", \"h3\", \"h4\", \"h5\", \"h6\", \"|\", \n            \"list-ul\", \"list-ol\", \"hr\", \"|\",\n            \"watch\", \"preview\", \"fullscreen\", \"|\",\n            \"help\", \"info\"\n        ],\n        mini : [\n            \"undo\", \"redo\", \"|\",\n            \"watch\", \"preview\", \"|\",\n            \"help\", \"info\"\n        ]\n    };\n    \n    editormd.defaults     = {\n        mode                 : \"gfm\",          //gfm or markdown\n        name                 : \"\",             // Form element name\n        value                : \"\",             // value for CodeMirror, if mode not gfm/markdown\n        theme                : \"\",             // Editor.md self themes, before v1.5.0 is CodeMirror theme, default empty\n        editorTheme          : \"default\",      // Editor area, this is CodeMirror theme at v1.5.0\n        previewTheme         : \"\",             // Preview area theme, default empty\n        markdown             : \"\",             // Markdown source code\n        appendMarkdown       : \"\",             // if in init textarea value not empty, append markdown to textarea\n        width                : \"100%\",\n        height               : \"100%\",\n        path                 : \"./lib/\",       // Dependents module file directory\n        pluginPath           : \"\",             // If this empty, default use settings.path + \"../plugins/\"\n        delay                : 300,            // Delay parse markdown to html, Uint : ms\n        autoLoadModules      : true,           // Automatic load dependent module files\n        watch                : true,\n        placeholder          : \"Enjoy Markdown! coding now...\",\n        gotoLine             : true,\n        codeFold             : false,\n        autoHeight           : false,\n\t\tautoFocus            : true,\n        autoCloseTags        : true,\n        searchReplace        : true,\n        syncScrolling        : true,           // true | false | \"single\", default true\n        readOnly             : false,\n        tabSize              : 4,\n\t\tindentUnit           : 4,\n        lineNumbers          : true,\n\t\tlineWrapping         : true,\n\t\tautoCloseBrackets    : true,\n\t\tshowTrailingSpace    : true,\n\t\tmatchBrackets        : true,\n\t\tindentWithTabs       : true,\n\t\tstyleSelectedText    : true,\n        matchWordHighlight   : true,           // options: true, false, \"onselected\"\n        styleActiveLine      : true,           // Highlight the current line\n        dialogLockScreen     : true,\n        dialogShowMask       : true,\n        dialogDraggable      : true,\n        dialogMaskBgColor    : \"#fff\",\n        dialogMaskOpacity    : 0.1,\n        fontSize             : \"13px\",\n        saveHTMLToTextarea   : false,\n        disabledKeyMaps      : [],\n        \n        onload               : function() {},\n        onresize             : function() {},\n        onchange             : function() {},\n        onwatch              : null,\n        onunwatch            : null,\n        onpreviewing         : function() {},\n        onpreviewed          : function() {},\n        onfullscreen         : function() {},\n        onfullscreenExit     : function() {},\n        onscroll             : function() {},\n        onpreviewscroll      : function() {},\n        \n        imageUpload          : false,\n        imageFormats         : [\"jpg\", \"jpeg\", \"gif\", \"png\", \"bmp\", \"webp\"],\n        imageUploadURL       : \"\",\n        crossDomainUpload    : false,\n        uploadCallbackURL    : \"\",\n        \n        toc                  : true,           // Table of contents\n        tocm                 : false,           // Using [TOCM], auto create ToC dropdown menu\n        tocTitle             : \"\",             // for ToC dropdown menu btn\n        tocDropdown          : false,\n        tocContainer         : \"\",\n        tocStartLevel        : 1,              // Said from H1 to create ToC\n        htmlDecode           : false,          // Open the HTML tag identification \n        pageBreak            : true,           // Enable parse page break [========]\n        atLink               : true,           // for @link\n        emailLink            : true,           // for email address auto link\n        taskList             : false,          // Enable Github Flavored Markdown task lists\n        emoji                : false,          // :emoji: , Support Github emoji, Twitter Emoji (Twemoji);\n                                               // Support FontAwesome icon emoji :fa-xxx: > Using fontAwesome icon web fonts;\n                                               // Support Editor.md logo icon emoji :editormd-logo: :editormd-logo-1x: > 1~8x;\n        tex                  : false,          // TeX(LaTeX), based on KaTeX\n        flowChart            : false,          // flowChart.js only support IE9+\n        sequenceDiagram      : false,          // sequenceDiagram.js only support IE9+\n        previewCodeHighlight : true,\n                \n        toolbar              : true,           // show/hide toolbar\n        toolbarAutoFixed     : true,           // on window scroll auto fixed position\n        toolbarIcons         : \"full\",\n        toolbarTitles        : {},\n        toolbarHandlers      : {\n            ucwords : function() {\n                return editormd.toolbarHandlers.ucwords;\n            },\n            lowercase : function() {\n                return editormd.toolbarHandlers.lowercase;\n            }\n        },\n        toolbarCustomIcons   : {               // using html tag create toolbar icon, unused default <a> tag.\n            lowercase        : \"<a href=\\\"javascript:;\\\" title=\\\"Lowercase\\\" unselectable=\\\"on\\\"><i class=\\\"fa\\\" name=\\\"lowercase\\\" style=\\\"font-size:24px;margin-top: -10px;\\\">a</i></a>\",\n            \"ucwords\"        : \"<a href=\\\"javascript:;\\\" title=\\\"ucwords\\\" unselectable=\\\"on\\\"><i class=\\\"fa\\\" name=\\\"ucwords\\\" style=\\\"font-size:20px;margin-top: -3px;\\\">Aa</i></a>\"\n        }, \n        toolbarIconsClass    : {\n            undo             : \"fa-undo\",\n            redo             : \"fa-repeat\",\n            bold             : \"fa-bold\",\n            del              : \"fa-strikethrough\",\n            italic           : \"fa-italic\",\n            quote            : \"fa-quote-left\",\n            uppercase        : \"fa-font\",\n            h1               : editormd.classPrefix + \"bold\",\n            h2               : editormd.classPrefix + \"bold\",\n            h3               : editormd.classPrefix + \"bold\",\n            h4               : editormd.classPrefix + \"bold\",\n            h5               : editormd.classPrefix + \"bold\",\n            h6               : editormd.classPrefix + \"bold\",\n            \"list-ul\"        : \"fa-list-ul\",\n            \"list-ol\"        : \"fa-list-ol\",\n            hr               : \"fa-minus\",\n            link             : \"fa-link\",\n            \"reference-link\" : \"fa-anchor\",\n            image            : \"fa-picture-o\",\n            code             : \"fa-code\",\n            \"preformatted-text\" : \"fa-file-code-o\",\n            \"code-block\"     : \"fa-file-code-o\",\n            table            : \"fa-table\",\n            datetime         : \"fa-clock-o\",\n            emoji            : \"fa-smile-o\",\n            \"html-entities\"  : \"fa-copyright\",\n            pagebreak        : \"fa-newspaper-o\",\n            \"goto-line\"      : \"fa-terminal\", // fa-crosshairs\n            watch            : \"fa-eye-slash\",\n            unwatch          : \"fa-eye\",\n            preview          : \"fa-desktop\",\n            search           : \"fa-search\",\n            fullscreen       : \"fa-arrows-alt\",\n            clear            : \"fa-eraser\",\n            help             : \"fa-question-circle\",\n            info             : \"fa-info-circle\"\n        },        \n        toolbarIconTexts     : {},\n        \n        lang : {\n            name        : \"zh-cn\",\n            description : \"开源在线Markdown编辑器<br/>Open source online Markdown editor.\",\n            tocTitle    : \"目录\",\n            toolbar     : {\n                undo             : \"撤销（Ctrl+Z）\",\n                redo             : \"重做（Ctrl+Y）\",\n                bold             : \"粗体\",\n                del              : \"删除线\",\n                italic           : \"斜体\",\n                quote            : \"引用\",\n                ucwords          : \"将每个单词首字母转成大写\",\n                uppercase        : \"将所选转换成大写\",\n                lowercase        : \"将所选转换成小写\",\n                h1               : \"标题1\",\n                h2               : \"标题2\",\n                h3               : \"标题3\",\n                h4               : \"标题4\",\n                h5               : \"标题5\",\n                h6               : \"标题6\",\n                \"list-ul\"        : \"无序列表\",\n                \"list-ol\"        : \"有序列表\",\n                hr               : \"横线\",\n                link             : \"链接\",\n                \"reference-link\" : \"引用链接\",\n                image            : \"添加图片\",\n                code             : \"行内代码\",\n                \"preformatted-text\" : \"预格式文本 / 代码块（缩进风格）\",\n                \"code-block\"     : \"代码块（多语言风格）\",\n                table            : \"添加表格\",\n                datetime         : \"日期时间\",\n                emoji            : \"Emoji表情\",\n                \"html-entities\"  : \"HTML实体字符\",\n                pagebreak        : \"插入分页符\",\n                \"goto-line\"      : \"跳转到行\",\n                watch            : \"关闭实时预览\",\n                unwatch          : \"开启实时预览\",\n                preview          : \"全窗口预览HTML（按 Shift + ESC还原）\",\n                fullscreen       : \"全屏（按ESC还原）\",\n                clear            : \"清空\",\n                search           : \"搜索\",\n                help             : \"使用帮助\",\n                info             : \"关于\" + editormd.title\n            },\n            buttons : {\n                enter  : \"确定\",\n                cancel : \"取消\",\n                close  : \"关闭\"\n            },\n            dialog : {\n                link : {\n                    title    : \"添加链接\",\n                    url      : \"链接地址\",\n                    urlTitle : \"链接标题\",\n                    urlEmpty : \"错误：请填写链接地址。\"\n                },\n                referenceLink : {\n                    title    : \"添加引用链接\",\n                    name     : \"引用名称\",\n                    url      : \"链接地址\",\n                    urlId    : \"链接ID\",\n                    urlTitle : \"链接标题\",\n                    nameEmpty: \"错误：引用链接的名称不能为空。\",\n                    idEmpty  : \"错误：请填写引用链接的ID。\",\n                    urlEmpty : \"错误：请填写引用链接的URL地址。\"\n                },\n                image : {\n                    title    : \"添加图片\",\n                    url      : \"图片地址\",\n                    link     : \"图片链接\",\n                    alt      : \"图片描述\",\n                    uploadButton     : \"本地上传\",\n                    imageURLEmpty    : \"错误：图片地址不能为空。\",\n                    uploadFileEmpty  : \"错误：上传的图片不能为空。\",\n                    formatNotAllowed : \"错误：只允许上传图片文件，允许上传的图片文件格式有：\"\n                },\n                preformattedText : {\n                    title             : \"添加预格式文本或代码块\", \n                    emptyAlert        : \"错误：请填写预格式文本或代码的内容。\"\n                },\n                codeBlock : {\n                    title             : \"添加代码块\",                    \n                    selectLabel       : \"代码语言：\",\n                    selectDefaultText : \"请选择代码语言\",\n                    otherLanguage     : \"其他语言\",\n                    unselectedLanguageAlert : \"错误：请选择代码所属的语言类型。\",\n                    codeEmptyAlert    : \"错误：请填写代码内容。\"\n                },\n                htmlEntities : {\n                    title : \"HTML 实体字符\"\n                },\n                help : {\n                    title : \"使用帮助\"\n                }\n            }\n        }\n    };\n    \n    editormd.classNames  = {\n        tex : editormd.classPrefix + \"tex\"\n    };\n\n    editormd.dialogZindex = 99999;\n    \n    editormd.$katex       = null;\n    editormd.$marked      = null;\n    editormd.$CodeMirror  = null;\n    editormd.$prettyPrint = null;\n    \n    var timer, flowchartTimer;\n\n    editormd.prototype    = editormd.fn = {\n        state : {\n            watching   : false,\n            loaded     : false,\n            preview    : false,\n            fullscreen : false\n        },\n        \n        /**\n         * 构造函数/实例初始化\n         * Constructor / instance initialization\n         * \n         * @param   {String}   id            编辑器的ID\n         * @param   {Object}   [options={}]  配置选项 Key/Value\n         * @returns {editormd}               返回editormd的实例对象\n         */\n        \n        init : function (id, options) {\n            \n            options              = options || {};\n            \n            if (typeof id === \"object\")\n            {\n                options = id;\n            }\n            \n            var _this            = this;\n            var classPrefix      = this.classPrefix  = editormd.classPrefix; \n            var settings         = this.settings     = $.extend(true, editormd.defaults, options);\n            \n            id                   = (typeof id === \"object\") ? settings.id : id;\n            \n            var editor           = this.editor       = $(\"#\" + id);\n            \n            this.id              = id;\n            this.lang            = settings.lang;\n            \n            var classNames       = this.classNames   = {\n                textarea : {\n                    html     : classPrefix + \"html-textarea\",\n                    markdown : classPrefix + \"markdown-textarea\"\n                }\n            };\n            \n            settings.pluginPath = (settings.pluginPath === \"\") ? settings.path + \"../plugins/\" : settings.pluginPath; \n            \n            this.state.watching = (settings.watch) ? true : false;\n            \n            if ( !editor.hasClass(\"editormd\") ) {\n                editor.addClass(\"editormd\");\n            }\n            \n            editor.css({\n                width  : (typeof settings.width  === \"number\") ? settings.width  + \"px\" : settings.width,\n                height : (typeof settings.height === \"number\") ? settings.height + \"px\" : settings.height\n            });\n            \n            if (settings.autoHeight)\n            {\n                editor.css(\"height\", \"auto\");\n            }\n                        \n            var markdownTextarea = this.markdownTextarea = editor.children(\"textarea\");\n            \n            if (markdownTextarea.length < 1)\n            {\n                editor.append(\"<textarea></textarea>\");\n                markdownTextarea = this.markdownTextarea = editor.children(\"textarea\");\n            }\n            \n            markdownTextarea.addClass(classNames.textarea.markdown).attr(\"placeholder\", settings.placeholder);\n            \n            if (typeof markdownTextarea.attr(\"name\") === \"undefined\" || markdownTextarea.attr(\"name\") === \"\")\n            {\n                markdownTextarea.attr(\"name\", (settings.name !== \"\") ? settings.name : id + \"-markdown-doc\");\n            }\n            \n            var appendElements = [\n                (!settings.readOnly) ? \"<a href=\\\"javascript:;\\\" class=\\\"fa fa-close \" + classPrefix + \"preview-close-btn\\\"></a>\" : \"\",\n                ( (settings.saveHTMLToTextarea) ? \"<textarea class=\\\"\" + classNames.textarea.html + \"\\\" name=\\\"\" + id + \"-html-code\\\"></textarea>\" : \"\" ),\n                \"<div class=\\\"\" + classPrefix + \"preview\\\"><div class=\\\"markdown-body \" + classPrefix + \"preview-container\\\"></div></div>\",\n                \"<div class=\\\"\" + classPrefix + \"container-mask\\\" style=\\\"display:block;\\\"></div>\",\n                \"<div class=\\\"\" + classPrefix + \"mask\\\"></div>\"\n            ].join(\"\\n\");\n            \n            editor.append(appendElements).addClass(classPrefix + \"vertical\");\n            \n            if (settings.theme !== \"\") \n            {\n                editor.addClass(classPrefix + \"theme-\" + settings.theme);\n            }\n            \n            this.mask          = editor.children(\".\" + classPrefix + \"mask\");    \n            this.containerMask = editor.children(\".\" + classPrefix  + \"container-mask\");\n            \n            if (settings.markdown !== \"\")\n            {\n                markdownTextarea.val(settings.markdown);\n            }\n            \n            if (settings.appendMarkdown !== \"\")\n            {\n                markdownTextarea.val(markdownTextarea.val() + settings.appendMarkdown);\n            }\n            \n            this.htmlTextarea     = editor.children(\".\" + classNames.textarea.html);            \n            this.preview          = editor.children(\".\" + classPrefix + \"preview\");\n            this.previewContainer = this.preview.children(\".\" + classPrefix + \"preview-container\");\n            \n            if (settings.previewTheme !== \"\") \n            {\n                this.preview.addClass(classPrefix + \"preview-theme-\" + settings.previewTheme);\n            }\n            \n            if (typeof define === \"function\" && define.amd)\n            {\n                if (typeof katex !== \"undefined\") \n                {\n                    editormd.$katex = katex;\n                }\n                \n                if (settings.searchReplace && !settings.readOnly) \n                {\n                    editormd.loadCSS(settings.path + \"codemirror/addon/dialog/dialog\");\n                    editormd.loadCSS(settings.path + \"codemirror/addon/search/matchesonscrollbar\");\n                }\n            }\n            \n            if ((typeof define === \"function\" && define.amd) || !settings.autoLoadModules)\n            {\n                if (typeof CodeMirror !== \"undefined\") {\n                    editormd.$CodeMirror = CodeMirror;\n                }\n                \n                if (typeof marked     !== \"undefined\") {\n                    editormd.$marked     = marked;\n                }\n                \n                this.setCodeMirror().setToolbar().loadedDisplay();\n            } \n            else \n            {\n                this.loadQueues();\n            }\n\n            return this;\n        },\n        \n        /**\n         * 所需组件加载队列\n         * Required components loading queue\n         * \n         * @returns {editormd}  返回editormd的实例对象\n         */\n        \n        loadQueues : function() {\n            var _this        = this;\n            var settings     = this.settings;\n            var loadPath     = settings.path;\n                                \n            var loadFlowChartOrSequenceDiagram = function() {\n                \n                if (editormd.isIE8) \n                {\n                    _this.loadedDisplay();\n                    \n                    return ;\n                }\n\n                if (settings.flowChart || settings.sequenceDiagram) \n                {\n                    editormd.loadScript(loadPath + \"raphael.min\", function() {\n\n                        editormd.loadScript(loadPath + \"underscore.min\", function() {  \n\n                            if (!settings.flowChart && settings.sequenceDiagram) \n                            {\n                                editormd.loadScript(loadPath + \"sequence-diagram.min\", function() {\n                                    _this.loadedDisplay();\n                                });\n                            }\n                            else if (settings.flowChart && !settings.sequenceDiagram) \n                            {      \n                                editormd.loadScript(loadPath + \"flowchart.min\", function() {  \n                                    editormd.loadScript(loadPath + \"jquery.flowchart.min\", function() {\n                                        _this.loadedDisplay();\n                                    });\n                                });\n                            }\n                            else if (settings.flowChart && settings.sequenceDiagram) \n                            {  \n                                editormd.loadScript(loadPath + \"flowchart.min\", function() {  \n                                    editormd.loadScript(loadPath + \"jquery.flowchart.min\", function() {\n                                        editormd.loadScript(loadPath + \"sequence-diagram.min\", function() {\n                                            _this.loadedDisplay();\n                                        });\n                                    });\n                                });\n                            }\n                        });\n\n                    });\n                } \n                else\n                {\n                    _this.loadedDisplay();\n                }\n            }; \n\n            editormd.loadCSS(loadPath + \"codemirror/codemirror.min\");\n            \n            if (settings.searchReplace && !settings.readOnly)\n            {\n                editormd.loadCSS(loadPath + \"codemirror/addon/dialog/dialog\");\n                editormd.loadCSS(loadPath + \"codemirror/addon/search/matchesonscrollbar\");\n            }\n            \n            if (settings.codeFold)\n            {\n                editormd.loadCSS(loadPath + \"codemirror/addon/fold/foldgutter\");            \n            }\n            \n            editormd.loadScript(loadPath + \"codemirror/codemirror.min\", function() {\n                editormd.$CodeMirror = CodeMirror;\n                \n                editormd.loadScript(loadPath + \"codemirror/modes.min\", function() {\n                    \n                    editormd.loadScript(loadPath + \"codemirror/addons.min\", function() {\n                        \n                        _this.setCodeMirror();\n                        \n                        if (settings.mode !== \"gfm\" && settings.mode !== \"markdown\") \n                        {\n                            _this.loadedDisplay();\n                            \n                            return false;\n                        }\n                        \n                        _this.setToolbar();\n\n                        editormd.loadScript(loadPath + \"marked.min\", function() {\n\n                            editormd.$marked = marked;\n                                \n                            if (settings.previewCodeHighlight) \n                            {\n                                editormd.loadScript(loadPath + \"prettify.min\", function() {\n                                    loadFlowChartOrSequenceDiagram();\n                                });\n                            } \n                            else\n                            {                  \n                                loadFlowChartOrSequenceDiagram();\n                            }\n                        });\n                        \n                    });\n                    \n                });\n                \n            });\n\n            return this;\n        },\n        \n        /**\n         * 设置 Editor.md 的整体主题，主要是工具栏\n         * Setting Editor.md theme\n         * \n         * @returns {editormd}  返回editormd的实例对象\n         */\n        \n        setTheme : function(theme) {\n            var editor      = this.editor;\n            var oldTheme    = this.settings.theme;\n            var themePrefix = this.classPrefix + \"theme-\";\n            \n            editor.removeClass(themePrefix + oldTheme).addClass(themePrefix + theme);\n            \n            this.settings.theme = theme;\n            \n            return this;\n        },\n        \n        /**\n         * 设置 CodeMirror（编辑区）的主题\n         * Setting CodeMirror (Editor area) theme\n         * \n         * @returns {editormd}  返回editormd的实例对象\n         */\n        \n        setEditorTheme : function(theme) {  \n            var settings   = this.settings;  \n            settings.editorTheme = theme;  \n            \n            if (theme !== \"default\")\n            {\n                editormd.loadCSS(settings.path + \"codemirror/theme/\" + settings.editorTheme);\n            }\n            \n            this.cm.setOption(\"theme\", theme);\n            \n            return this;\n        },\n        \n        /**\n         * setEditorTheme() 的别名\n         * setEditorTheme() alias\n         * \n         * @returns {editormd}  返回editormd的实例对象\n         */\n        \n        setCodeMirrorTheme : function (theme) {            \n            this.setEditorTheme(theme);\n            \n            return this;\n        },\n        \n        /**\n         * 设置 Editor.md 的主题\n         * Setting Editor.md theme\n         * \n         * @returns {editormd}  返回editormd的实例对象\n         */\n        \n        setPreviewTheme : function(theme) {  \n            var preview     = this.preview;\n            var oldTheme    = this.settings.previewTheme;\n            var themePrefix = this.classPrefix + \"preview-theme-\";\n            \n            preview.removeClass(themePrefix + oldTheme).addClass(themePrefix + theme);\n            \n            this.settings.previewTheme = theme;\n            \n            return this;\n        },\n        \n        /**\n         * 配置和初始化CodeMirror组件\n         * CodeMirror initialization\n         * \n         * @returns {editormd}  返回editormd的实例对象\n         */\n        \n        setCodeMirror : function() { \n            var settings         = this.settings;\n            var editor           = this.editor;\n            \n            if (settings.editorTheme !== \"default\")\n            {\n                editormd.loadCSS(settings.path + \"codemirror/theme/\" + settings.editorTheme);\n            }\n            \n            var codeMirrorConfig = {\n                mode                      : settings.mode,\n                theme                     : settings.editorTheme,\n                tabSize                   : settings.tabSize,\n                dragDrop                  : false,\n                autofocus                 : settings.autoFocus,\n                autoCloseTags             : settings.autoCloseTags,\n                readOnly                  : (settings.readOnly) ? \"nocursor\" : false,\n                indentUnit                : settings.indentUnit,\n                lineNumbers               : settings.lineNumbers,\n                lineWrapping              : settings.lineWrapping,\n                extraKeys                 : {\n                                                \"Ctrl-Q\": function(cm) { \n                                                    cm.foldCode(cm.getCursor()); \n                                                }\n                                            },\n                foldGutter                : settings.codeFold,\n                gutters                   : [\"CodeMirror-linenumbers\", \"CodeMirror-foldgutter\"],\n                matchBrackets             : settings.matchBrackets,\n                indentWithTabs            : settings.indentWithTabs,\n                styleActiveLine           : settings.styleActiveLine,\n                styleSelectedText         : settings.styleSelectedText,\n                autoCloseBrackets         : settings.autoCloseBrackets,\n                showTrailingSpace         : settings.showTrailingSpace,\n                highlightSelectionMatches : ( (!settings.matchWordHighlight) ? false : { showToken: (settings.matchWordHighlight === \"onselected\") ? false : /\\w/ } )\n            };\n            \n            this.codeEditor = this.cm        = editormd.$CodeMirror.fromTextArea(this.markdownTextarea[0], codeMirrorConfig);\n            this.codeMirror = this.cmElement = editor.children(\".CodeMirror\");\n            \n            if (settings.value !== \"\")\n            {\n                this.cm.setValue(settings.value);\n            }\n\n            this.codeMirror.css({\n                fontSize : settings.fontSize,\n                width    : (!settings.watch) ? \"100%\" : \"50%\"\n            });\n            \n            if (settings.autoHeight)\n            {\n                this.codeMirror.css(\"height\", \"auto\");\n                this.cm.setOption(\"viewportMargin\", Infinity);\n            }\n            \n            if (!settings.lineNumbers)\n            {\n                this.codeMirror.find(\".CodeMirror-gutters\").css(\"border-right\", \"none\");\n            }\n\n            return this;\n        },\n        \n        /**\n         * 获取CodeMirror的配置选项\n         * Get CodeMirror setting options\n         * \n         * @returns {Mixed}                  return CodeMirror setting option value\n         */\n        \n        getCodeMirrorOption : function(key) {            \n            return this.cm.getOption(key);\n        },\n        \n        /**\n         * 配置和重配置CodeMirror的选项\n         * CodeMirror setting options / resettings\n         * \n         * @returns {editormd}  返回editormd的实例对象\n         */\n        \n        setCodeMirrorOption : function(key, value) {\n            \n            this.cm.setOption(key, value);\n            \n            return this;\n        },\n        \n        /**\n         * 添加 CodeMirror 键盘快捷键\n         * Add CodeMirror keyboard shortcuts key map\n         * \n         * @returns {editormd}  返回editormd的实例对象\n         */\n        \n        addKeyMap : function(map, bottom) {\n            this.cm.addKeyMap(map, bottom);\n            \n            return this;\n        },\n        \n        /**\n         * 移除 CodeMirror 键盘快捷键\n         * Remove CodeMirror keyboard shortcuts key map\n         * \n         * @returns {editormd}  返回editormd的实例对象\n         */\n        \n        removeKeyMap : function(map) {\n            this.cm.removeKeyMap(map);\n            \n            return this;\n        },\n        \n        /**\n         * 跳转到指定的行\n         * Goto CodeMirror line\n         * \n         * @param   {String|Intiger}   line      line number or \"first\"|\"last\"\n         * @returns {editormd}                   返回editormd的实例对象\n         */\n        \n        gotoLine : function (line) {\n            \n            var settings = this.settings;\n            \n            if (!settings.gotoLine)\n            {\n                return this;\n            }\n            \n            var cm       = this.cm;\n            var editor   = this.editor;\n            var count    = cm.lineCount();\n            var preview  = this.preview;\n            \n            if (typeof line === \"string\")\n            {\n                if(line === \"last\")\n                {\n                    line = count;\n                }\n            \n                if (line === \"first\")\n                {\n                    line = 1;\n                }\n            }\n            \n            if (typeof line !== \"number\") \n            {  \n                alert(\"Error: The line number must be an integer.\");\n                return this;\n            }\n            \n            line  = parseInt(line) - 1;\n            \n            if (line > count)\n            {\n                alert(\"Error: The line number range 1-\" + count);\n                \n                return this;\n            }\n            \n            cm.setCursor( {line : line, ch : 0} );\n            \n            var scrollInfo   = cm.getScrollInfo();\n            var clientHeight = scrollInfo.clientHeight; \n            var coords       = cm.charCoords({line : line, ch : 0}, \"local\");\n            \n            cm.scrollTo(null, (coords.top + coords.bottom - clientHeight) / 2);\n            \n            if (settings.watch)\n            {            \n                var cmScroll  = this.codeMirror.find(\".CodeMirror-scroll\")[0];\n                var height    = $(cmScroll).height(); \n                var scrollTop = cmScroll.scrollTop;         \n                var percent   = (scrollTop / cmScroll.scrollHeight);\n\n                if (scrollTop === 0)\n                {\n                    preview.scrollTop(0);\n                } \n                else if (scrollTop + height >= cmScroll.scrollHeight - 16)\n                { \n                    preview.scrollTop(preview[0].scrollHeight);                    \n                } \n                else\n                {                    \n                    preview.scrollTop(preview[0].scrollHeight * percent);\n                }\n            }\n\n            cm.focus();\n            \n            return this;\n        },\n        \n        /**\n         * 扩展当前实例对象，可同时设置多个或者只设置一个\n         * Extend editormd instance object, can mutil setting.\n         * \n         * @returns {editormd}                  this(editormd instance object.)\n         */\n        \n        extend : function() {\n            if (typeof arguments[1] !== \"undefined\")\n            {\n                if (typeof arguments[1] === \"function\")\n                {\n                    arguments[1] = $.proxy(arguments[1], this);\n                }\n\n                this[arguments[0]] = arguments[1];\n            }\n            \n            if (typeof arguments[0] === \"object\" && typeof arguments[0].length === \"undefined\")\n            {\n                $.extend(true, this, arguments[0]);\n            }\n\n            return this;\n        },\n        \n        /**\n         * 设置或扩展当前实例对象，单个设置\n         * Extend editormd instance object, one by one\n         * \n         * @param   {String|Object}   key       option key\n         * @param   {String|Object}   value     option value\n         * @returns {editormd}                  this(editormd instance object.)\n         */\n        \n        set : function (key, value) {\n            \n            if (typeof value !== \"undefined\" && typeof value === \"function\")\n            {\n                value = $.proxy(value, this);\n            }\n            \n            this[key] = value;\n\n            return this;\n        },\n        \n        /**\n         * 重新配置\n         * Resetting editor options\n         * \n         * @param   {String|Object}   key       option key\n         * @param   {String|Object}   value     option value\n         * @returns {editormd}                  this(editormd instance object.)\n         */\n        \n        config : function(key, value) {\n            var settings = this.settings;\n            \n            if (typeof key === \"object\")\n            {\n                settings = $.extend(true, settings, key);\n            }\n            \n            if (typeof key === \"string\")\n            {\n                settings[key] = value;\n            }\n            \n            this.settings = settings;\n            this.recreate();\n            \n            return this;\n        },\n        \n        /**\n         * 注册事件处理方法\n         * Bind editor event handle\n         * \n         * @param   {String}     eventType      event type\n         * @param   {Function}   callback       回调函数\n         * @returns {editormd}                  this(editormd instance object.)\n         */\n        \n        on : function(eventType, callback) {\n            var settings = this.settings;\n            \n            if (typeof settings[\"on\" + eventType] !== \"undefined\") \n            {                \n                settings[\"on\" + eventType] = $.proxy(callback, this);      \n            }\n\n            return this;\n        },\n        \n        /**\n         * 解除事件处理方法\n         * Unbind editor event handle\n         * \n         * @param   {String}   eventType          event type\n         * @returns {editormd}                    this(editormd instance object.)\n         */\n        \n        off : function(eventType) {\n            var settings = this.settings;\n            \n            if (typeof settings[\"on\" + eventType] !== \"undefined\") \n            {\n                settings[\"on\" + eventType] = function(){};\n            }\n            \n            return this;\n        },\n        \n        /**\n         * 显示工具栏\n         * Display toolbar\n         * \n         * @param   {Function} [callback=function(){}] 回调函数\n         * @returns {editormd}  返回editormd的实例对象\n         */\n        \n        showToolbar : function(callback) {\n            var settings = this.settings;\n            \n            if(settings.readOnly) {\n                return this;\n            }\n            \n            if (settings.toolbar && (this.toolbar.length < 1 || this.toolbar.find(\".\" + this.classPrefix + \"menu\").html() === \"\") )\n            {\n                this.setToolbar();\n            }\n            \n            settings.toolbar = true; \n            \n            this.toolbar.show();\n            this.resize();\n            \n            $.proxy(callback || function(){}, this)();\n\n            return this;\n        },\n        \n        /**\n         * 隐藏工具栏\n         * Hide toolbar\n         * \n         * @param   {Function} [callback=function(){}] 回调函数\n         * @returns {editormd}                         this(editormd instance object.)\n         */\n        \n        hideToolbar : function(callback) { \n            var settings = this.settings;\n            \n            settings.toolbar = false;  \n            this.toolbar.hide();\n            this.resize();\n            \n            $.proxy(callback || function(){}, this)();\n\n            return this;\n        },\n        \n        /**\n         * 页面滚动时工具栏的固定定位\n         * Set toolbar in window scroll auto fixed position\n         * \n         * @returns {editormd}  返回editormd的实例对象\n         */\n        \n        setToolbarAutoFixed : function(fixed) {\n            \n            var state    = this.state;\n            var editor   = this.editor;\n            var toolbar  = this.toolbar;\n            var settings = this.settings;\n            \n            if (typeof fixed !== \"undefined\")\n            {\n                settings.toolbarAutoFixed = fixed;\n            }\n            \n            var autoFixedHandle = function(){\n                var $window = $(window);\n                var top     = $window.scrollTop();\n                \n                if (!settings.toolbarAutoFixed)\n                {\n                    return false;\n                }\n\n                if (top - editor.offset().top > 10 && top < editor.height())\n                {\n                    toolbar.css({\n                        position : \"fixed\",\n                        width    : editor.width() + \"px\",\n                        left     : ($window.width() - editor.width()) / 2 + \"px\"\n                    });\n                }\n                else\n                {\n                    toolbar.css({\n                        position : \"absolute\",\n                        width    : \"100%\",\n                        left     : 0\n                    });\n                }\n            };\n            \n            if (!state.fullscreen && !state.preview && settings.toolbar && settings.toolbarAutoFixed)\n            {\n                $(window).bind(\"scroll\", autoFixedHandle);\n            }\n\n            return this;\n        },\n        \n        /**\n         * 配置和初始化工具栏\n         * Set toolbar and Initialization\n         * \n         * @returns {editormd}  返回editormd的实例对象\n         */\n        \n        setToolbar : function() {\n            var settings    = this.settings;  \n            \n            if(settings.readOnly) {\n                return this;\n            }\n            \n            var editor      = this.editor;\n            var preview     = this.preview;\n            var classPrefix = this.classPrefix;\n            \n            var toolbar     = this.toolbar = editor.children(\".\" + classPrefix + \"toolbar\");\n            \n            if (settings.toolbar && toolbar.length < 1)\n            {            \n                var toolbarHTML = \"<div class=\\\"\" + classPrefix + \"toolbar\\\"><div class=\\\"\" + classPrefix + \"toolbar-container\\\"><ul class=\\\"\" + classPrefix + \"menu\\\"></ul></div></div>\";\n                \n                editor.append(toolbarHTML);\n                toolbar = this.toolbar = editor.children(\".\" + classPrefix + \"toolbar\");\n            }\n            \n            if (!settings.toolbar) \n            {\n                toolbar.hide();\n                \n                return this;\n            }\n            \n            toolbar.show();\n            \n            var icons       = (typeof settings.toolbarIcons === \"function\") ? settings.toolbarIcons() \n                            : ((typeof settings.toolbarIcons === \"string\")  ? editormd.toolbarModes[settings.toolbarIcons] : settings.toolbarIcons);\n            \n            var toolbarMenu = toolbar.find(\".\" + this.classPrefix + \"menu\"), menu = \"\";\n            var pullRight   = false;\n            \n            for (var i = 0, len = icons.length; i < len; i++)\n            {\n                var name = icons[i];\n\n                if (name === \"||\") \n                { \n                    pullRight = true;\n                } \n                else if (name === \"|\")\n                {\n                    menu += \"<li class=\\\"divider\\\" unselectable=\\\"on\\\">|</li>\";\n                }\n                else\n                {\n                    var isHeader = (/h(\\d)/.test(name));\n                    var index    = name;\n                    \n                    if (name === \"watch\" && !settings.watch) {\n                        index = \"unwatch\";\n                    }\n                    \n                    var title     = settings.lang.toolbar[index];\n                    var iconTexts = settings.toolbarIconTexts[index];\n                    var iconClass = settings.toolbarIconsClass[index];\n                    \n                    title     = (typeof title     === \"undefined\") ? \"\" : title;\n                    iconTexts = (typeof iconTexts === \"undefined\") ? \"\" : iconTexts;\n                    iconClass = (typeof iconClass === \"undefined\") ? \"\" : iconClass;\n\n                    var menuItem = pullRight ? \"<li class=\\\"pull-right\\\">\" : \"<li>\";\n                    \n                    if (typeof settings.toolbarCustomIcons[name] !== \"undefined\" && typeof settings.toolbarCustomIcons[name] !== \"function\")\n                    {\n                        menuItem += settings.toolbarCustomIcons[name];\n                    }\n                    else \n                    {\n                        menuItem += \"<a href=\\\"javascript:;\\\" title=\\\"\" + title + \"\\\" unselectable=\\\"on\\\">\";\n                        menuItem += \"<i class=\\\"fa \" + iconClass + \"\\\" name=\\\"\"+name+\"\\\" unselectable=\\\"on\\\">\"+((isHeader) ? name.toUpperCase() : ( (iconClass === \"\") ? iconTexts : \"\") ) + \"</i>\";\n                        menuItem += \"</a>\";\n                    }\n\n                    menuItem += \"</li>\";\n\n                    menu = pullRight ? menuItem + menu : menu + menuItem;\n                }\n            }\n\n            toolbarMenu.html(menu);\n            \n            toolbarMenu.find(\"[title=\\\"Lowercase\\\"]\").attr(\"title\", settings.lang.toolbar.lowercase);\n            toolbarMenu.find(\"[title=\\\"ucwords\\\"]\").attr(\"title\", settings.lang.toolbar.ucwords);\n            \n            this.setToolbarHandler();\n            this.setToolbarAutoFixed();\n\n            return this;\n        },\n        \n        /**\n         * 工具栏图标事件处理对象序列\n         * Get toolbar icons event handlers\n         * \n         * @param   {Object}   cm    CodeMirror的实例对象\n         * @param   {String}   name  要获取的事件处理器名称\n         * @returns {Object}         返回处理对象序列\n         */\n            \n        dialogLockScreen : function() {\n            $.proxy(editormd.dialogLockScreen, this)();\n            \n            return this;\n        },\n\n        dialogShowMask : function(dialog) {\n            $.proxy(editormd.dialogShowMask, this)(dialog);\n            \n            return this;\n        },\n        \n        getToolbarHandles : function(name) {  \n            var toolbarHandlers = this.toolbarHandlers = editormd.toolbarHandlers;\n            \n            return (name && typeof toolbarIconHandlers[name] !== \"undefined\") ? toolbarHandlers[name] : toolbarHandlers;\n        },\n        \n        /**\n         * 工具栏图标事件处理器\n         * Bind toolbar icons event handle\n         * \n         * @returns {editormd}  返回editormd的实例对象\n         */\n        \n        setToolbarHandler : function() {\n            var _this               = this;\n            var settings            = this.settings;\n            \n            if (!settings.toolbar || settings.readOnly) {\n                return this;\n            }\n            \n            var toolbar             = this.toolbar;\n            var cm                  = this.cm;\n            var classPrefix         = this.classPrefix;           \n            var toolbarIcons        = this.toolbarIcons = toolbar.find(\".\" + classPrefix + \"menu > li > a\");  \n            var toolbarIconHandlers = this.getToolbarHandles();  \n                \n            toolbarIcons.bind(editormd.mouseOrTouch(\"click\", \"touchend\"), function(event) {\n\n                var icon                = $(this).children(\".fa\");\n                var name                = icon.attr(\"name\");\n                var cursor              = cm.getCursor();\n                var selection           = cm.getSelection();\n\n                if (name === \"\") {\n                    return ;\n                }\n                \n                _this.activeIcon = icon;\n\n                if (typeof toolbarIconHandlers[name] !== \"undefined\") \n                {\n                    $.proxy(toolbarIconHandlers[name], _this)(cm);\n                }\n                else \n                {\n                    if (typeof settings.toolbarHandlers[name] !== \"undefined\") \n                    {\n                        $.proxy(settings.toolbarHandlers[name], _this)(cm, icon, cursor, selection);\n                    }\n                }\n                \n                if (name !== \"link\" && name !== \"reference-link\" && name !== \"image\" && name !== \"code-block\" && \n                    name !== \"preformatted-text\" && name !== \"watch\" && name !== \"preview\" && name !== \"search\" && name !== \"fullscreen\" && name !== \"info\") \n                {\n                    cm.focus();\n                }\n\n                return false;\n\n            });\n\n            return this;\n        },\n        \n        /**\n         * 动态创建对话框\n         * Creating custom dialogs\n         * \n         * @param   {Object} options  配置项键值对 Key/Value\n         * @returns {dialog}          返回创建的dialog的jQuery实例对象\n         */\n        \n        createDialog : function(options) {            \n            return $.proxy(editormd.createDialog, this)(options);\n        },\n        \n        /**\n         * 创建关于Editor.md的对话框\n         * Create about Editor.md dialog\n         * \n         * @returns {editormd}  返回editormd的实例对象\n         */\n        \n        createInfoDialog : function() {\n            var _this        = this;\n\t\t\tvar editor       = this.editor;\n            var classPrefix  = this.classPrefix;  \n            \n            var infoDialogHTML = [\n                \"<div class=\\\"\" + classPrefix + \"dialog \" + classPrefix + \"dialog-info\\\" style=\\\"\\\">\",\n                \"<div class=\\\"\" + classPrefix + \"dialog-container\\\">\",\n                \"<h1><i class=\\\"editormd-logo editormd-logo-lg editormd-logo-color\\\"></i> \" + editormd.title + \"<small>v\" + editormd.version + \"</small></h1>\",\n                \"<p>\" + this.lang.description + \"</p>\",\n                \"<p style=\\\"margin: 10px 0 20px 0;\\\"><a href=\\\"\" + editormd.homePage + \"\\\" target=\\\"_blank\\\">\" + editormd.homePage + \" <i class=\\\"fa fa-external-link\\\"></i></a></p>\",\n                \"<p style=\\\"font-size: 0.85em;\\\">Copyright &copy; 2015 <a href=\\\"https://github.com/pandao\\\" target=\\\"_blank\\\" class=\\\"hover-link\\\">Pandao</a>, The <a href=\\\"https://github.com/pandao/editor.md/blob/master/LICENSE\\\" target=\\\"_blank\\\" class=\\\"hover-link\\\">MIT</a> License.</p>\",\n                \"</div>\",\n                \"<a href=\\\"javascript:;\\\" class=\\\"fa fa-close \" + classPrefix + \"dialog-close\\\"></a>\",\n                \"</div>\"\n            ].join(\"\\n\");\n\n            editor.append(infoDialogHTML);\n            \n            var infoDialog  = this.infoDialog = editor.children(\".\" + classPrefix + \"dialog-info\");\n\n            infoDialog.find(\".\" + classPrefix + \"dialog-close\").bind(editormd.mouseOrTouch(\"click\", \"touchend\"), function() {\n                _this.hideInfoDialog();\n            });\n            \n            infoDialog.css(\"border\", (editormd.isIE8) ? \"1px solid #ddd\" : \"\").css(\"z-index\", editormd.dialogZindex).show();\n            \n            this.infoDialogPosition();\n\n            return this;\n        },\n        \n        /**\n         * 关于Editor.md对话居中定位\n         * Editor.md dialog position handle\n         * \n         * @returns {editormd}  返回editormd的实例对象\n         */\n        \n        infoDialogPosition : function() {\n            var infoDialog = this.infoDialog;\n            \n\t\t\tvar _infoDialogPosition = function() {\n\t\t\t\tinfoDialog.css({\n\t\t\t\t\ttop  : ($(window).height() - infoDialog.height()) / 2 + \"px\",\n\t\t\t\t\tleft : ($(window).width()  - infoDialog.width()) / 2  + \"px\"\n\t\t\t\t});\n\t\t\t};\n\n\t\t\t_infoDialogPosition();\n\n\t\t\t$(window).resize(_infoDialogPosition);\n            \n            return this;\n        },\n        \n        /**\n         * 显示关于Editor.md\n         * Display about Editor.md dialog\n         * \n         * @returns {editormd}  返回editormd的实例对象\n         */\n        \n        showInfoDialog : function() {\n\n            $(\"html,body\").css(\"overflow-x\", \"hidden\");\n            \n            var _this       = this;\n\t\t\tvar editor      = this.editor;\n            var settings    = this.settings;         \n\t\t\tvar infoDialog  = this.infoDialog = editor.children(\".\" + this.classPrefix + \"dialog-info\");\n            \n            if (infoDialog.length < 1)\n            {\n                this.createInfoDialog();\n            }\n            \n            this.lockScreen(true);\n            \n            this.mask.css({\n\t\t\t\t\t\topacity         : settings.dialogMaskOpacity,\n\t\t\t\t\t\tbackgroundColor : settings.dialogMaskBgColor\n\t\t\t\t\t}).show();\n\n\t\t\tinfoDialog.css(\"z-index\", editormd.dialogZindex).show();\n\n\t\t\tthis.infoDialogPosition();\n\n            return this;\n        },\n        \n        /**\n         * 隐藏关于Editor.md\n         * Hide about Editor.md dialog\n         * \n         * @returns {editormd}  返回editormd的实例对象\n         */\n        \n        hideInfoDialog : function() {            \n            $(\"html,body\").css(\"overflow-x\", \"\");\n            this.infoDialog.hide();\n            this.mask.hide();\n            this.lockScreen(false);\n\n            return this;\n        },\n        \n        /**\n         * 锁屏\n         * lock screen\n         * \n         * @param   {Boolean}    lock    Boolean 布尔值，是否锁屏\n         * @returns {editormd}           返回editormd的实例对象\n         */\n        \n        lockScreen : function(lock) {\n            editormd.lockScreen(lock);\n            this.resize();\n\n            return this;\n        },\n        \n        /**\n         * 编辑器界面重建，用于动态语言包或模块加载等\n         * Recreate editor\n         * \n         * @returns {editormd}  返回editormd的实例对象\n         */\n        \n        recreate : function() {\n            var _this            = this;\n            var editor           = this.editor;\n            var settings         = this.settings;\n            \n            this.codeMirror.remove();\n            \n            this.setCodeMirror();\n\n            if (!settings.readOnly) \n            {\n                if (editor.find(\".editormd-dialog\").length > 0) {\n                    editor.find(\".editormd-dialog\").remove();\n                }\n                \n                if (settings.toolbar) \n                {  \n                    this.getToolbarHandles();                  \n                    this.setToolbar();\n                }\n            }\n            \n            this.loadedDisplay(true);\n\n            return this;\n        },\n        \n        /**\n         * 高亮预览HTML的pre代码部分\n         * highlight of preview codes\n         * \n         * @returns {editormd}             返回editormd的实例对象\n         */\n        \n        previewCodeHighlight : function() {    \n            var settings         = this.settings;\n            var previewContainer = this.previewContainer;\n            \n            if (settings.previewCodeHighlight) \n            {\n                previewContainer.find(\"pre\").addClass(\"prettyprint linenums\");\n                \n                if (typeof prettyPrint !== \"undefined\")\n                {                    \n                    prettyPrint();\n                }\n            }\n\n            return this;\n        },\n        \n        /**\n         * 解析TeX(KaTeX)科学公式\n         * TeX(KaTeX) Renderer\n         * \n         * @returns {editormd}             返回editormd的实例对象\n         */\n        \n        katexRender : function() {\n            \n            if (timer === null)\n            {\n                return this;\n            }\n            \n            this.previewContainer.find(\".\" + editormd.classNames.tex).each(function(){\n                var tex  = $(this);\n                editormd.$katex.render(tex.text(), tex[0]);\n                \n                tex.find(\".katex\").css(\"font-size\", \"1.6em\");\n            });   \n\n            return this;\n        },\n        \n        /**\n         * 解析和渲染流程图及时序图\n         * FlowChart and SequenceDiagram Renderer\n         * \n         * @returns {editormd}             返回editormd的实例对象\n         */\n        \n        flowChartAndSequenceDiagramRender : function() {\n            var $this            = this;\n            var settings         = this.settings;\n            var previewContainer = this.previewContainer;\n            \n            if (editormd.isIE8) {\n                return this;\n            }\n\n            if (settings.flowChart) {\n                if (flowchartTimer === null) {\n                    return this;\n                }\n                \n                previewContainer.find(\".flowchart\").flowChart(); \n            }\n\n            if (settings.sequenceDiagram) {\n                previewContainer.find(\".sequence-diagram\").sequenceDiagram({theme: \"simple\"});\n            }\n                    \n            var preview    = $this.preview;\n            var codeMirror = $this.codeMirror;\n            var codeView   = codeMirror.find(\".CodeMirror-scroll\");\n\n            var height    = codeView.height();\n            var scrollTop = codeView.scrollTop();                    \n            var percent   = (scrollTop / codeView[0].scrollHeight);\n            var tocHeight = 0;\n\n            preview.find(\".markdown-toc-list\").each(function(){\n                tocHeight += $(this).height();\n            });\n\n            var tocMenuHeight = preview.find(\".editormd-toc-menu\").height(); \n            tocMenuHeight = (!tocMenuHeight) ? 0 : tocMenuHeight;\n\n            if (scrollTop === 0) \n            {\n                preview.scrollTop(0);\n            } \n            else if (scrollTop + height >= codeView[0].scrollHeight - 16)\n            { \n                preview.scrollTop(preview[0].scrollHeight);                        \n            } \n            else\n            {                  \n                preview.scrollTop((preview[0].scrollHeight + tocHeight + tocMenuHeight) * percent);\n            }\n\n            return this;\n        },\n        \n        /**\n         * 注册键盘快捷键处理\n         * Register CodeMirror keyMaps (keyboard shortcuts).\n         * \n         * @param   {Object}    keyMap      KeyMap key/value {\"(Ctrl/Shift/Alt)-Key\" : function(){}}\n         * @returns {editormd}              return this\n         */\n        \n        registerKeyMaps : function(keyMap) {\n            \n            var _this           = this;\n            var cm              = this.cm;\n            var settings        = this.settings;\n            var toolbarHandlers = editormd.toolbarHandlers;\n            var disabledKeyMaps = settings.disabledKeyMaps;\n            \n            keyMap              = keyMap || null;\n            \n            if (keyMap)\n            {\n                for (var i in keyMap)\n                {\n                    if ($.inArray(i, disabledKeyMaps) < 0)\n                    {\n                        var map = {};\n                        map[i]  = keyMap[i];\n\n                        cm.addKeyMap(keyMap);\n                    }\n                }\n            }\n            else\n            {\n                for (var k in editormd.keyMaps)\n                {\n                    var _keyMap = editormd.keyMaps[k];\n                    var handle = (typeof _keyMap === \"string\") ? $.proxy(toolbarHandlers[_keyMap], _this) : $.proxy(_keyMap, _this);\n                    \n                    if ($.inArray(k, [\"F9\", \"F10\", \"F11\"]) < 0 && $.inArray(k, disabledKeyMaps) < 0)\n                    {\n                        var _map = {};\n                        _map[k] = handle;\n\n                        cm.addKeyMap(_map);\n                    }\n                }\n                \n                $(window).keydown(function(event) {\n                    \n                    var keymaps = {\n                        \"120\" : \"F9\",\n                        \"121\" : \"F10\",\n                        \"122\" : \"F11\"\n                    };\n                    \n                    if ( $.inArray(keymaps[event.keyCode], disabledKeyMaps) < 0 )\n                    {\n                        switch (event.keyCode)\n                        {\n                            case 120:\n                                    $.proxy(toolbarHandlers[\"watch\"], _this)();\n                                    return false;\n                                break;\n                                \n                            case 121:\n                                    $.proxy(toolbarHandlers[\"preview\"], _this)();\n                                    return false;\n                                break;\n                                \n                            case 122:\n                                    $.proxy(toolbarHandlers[\"fullscreen\"], _this)();                        \n                                    return false;\n                                break;\n                                \n                            default:\n                                break;\n                        }\n                    }\n                });\n            }\n\n            return this;\n        },\n        \n        /**\n         * 绑定同步滚动\n         * \n         * @returns {editormd} return this\n         */\n        \n        bindScrollEvent : function() {\n            \n            var _this            = this;\n            var preview          = this.preview;\n            var settings         = this.settings;\n            var codeMirror       = this.codeMirror;\n            var mouseOrTouch     = editormd.mouseOrTouch;\n            \n            if (!settings.syncScrolling) {\n                return this;\n            }\n                \n            var cmBindScroll = function() {    \n                codeMirror.find(\".CodeMirror-scroll\").bind(mouseOrTouch(\"scroll\", \"touchmove\"), function(event) {\n                    var height    = $(this).height();\n                    var scrollTop = $(this).scrollTop();                    \n                    var percent   = (scrollTop / $(this)[0].scrollHeight);\n                    \n                    var tocHeight = 0;\n                    \n                    preview.find(\".markdown-toc-list\").each(function(){\n                        tocHeight += $(this).height();\n                    });\n                    \n                    var tocMenuHeight = preview.find(\".editormd-toc-menu\").height();\n                    tocMenuHeight = (!tocMenuHeight) ? 0 : tocMenuHeight;\n\n                    if (scrollTop === 0) \n                    {\n                        preview.scrollTop(0);\n                    } \n                    else if (scrollTop + height >= $(this)[0].scrollHeight - 16)\n                    { \n                        preview.scrollTop(preview[0].scrollHeight);                        \n                    } \n                    else\n                    {\n                        preview.scrollTop((preview[0].scrollHeight  + tocHeight + tocMenuHeight) * percent);\n                    }\n                    \n                    $.proxy(settings.onscroll, _this)(event);\n                });\n            };\n\n            var cmUnbindScroll = function() {\n                codeMirror.find(\".CodeMirror-scroll\").unbind(mouseOrTouch(\"scroll\", \"touchmove\"));\n            };\n\n            var previewBindScroll = function() {\n                \n                preview.bind(mouseOrTouch(\"scroll\", \"touchmove\"), function(event) {\n                    var height    = $(this).height();\n                    var scrollTop = $(this).scrollTop();         \n                    var percent   = (scrollTop / $(this)[0].scrollHeight);\n                    var codeView  = codeMirror.find(\".CodeMirror-scroll\");\n\n                    if(scrollTop === 0) \n                    {\n                        codeView.scrollTop(0);\n                    }\n                    else if (scrollTop + height >= $(this)[0].scrollHeight)\n                    {\n                        codeView.scrollTop(codeView[0].scrollHeight);                        \n                    }\n                    else \n                    {\n                        codeView.scrollTop(codeView[0].scrollHeight * percent);\n                    }\n                    \n                    $.proxy(settings.onpreviewscroll, _this)(event);\n                });\n\n            };\n\n            var previewUnbindScroll = function() {\n                preview.unbind(mouseOrTouch(\"scroll\", \"touchmove\"));\n            }; \n\n\t\t\tcodeMirror.bind({\n\t\t\t\tmouseover  : cmBindScroll,\n\t\t\t\tmouseout   : cmUnbindScroll,\n\t\t\t\ttouchstart : cmBindScroll,\n\t\t\t\ttouchend   : cmUnbindScroll\n\t\t\t});\n            \n            if (settings.syncScrolling === \"single\") {\n                return this;\n            }\n            \n\t\t\tpreview.bind({\n\t\t\t\tmouseover  : previewBindScroll,\n\t\t\t\tmouseout   : previewUnbindScroll,\n\t\t\t\ttouchstart : previewBindScroll,\n\t\t\t\ttouchend   : previewUnbindScroll\n\t\t\t});\n\n            return this;\n        },\n        \n        bindChangeEvent : function() {\n            \n            var _this            = this;\n            var cm               = this.cm;\n            var settings         = this.settings;\n            \n            if (!settings.syncScrolling) {\n                return this;\n            }\n            \n            cm.on(\"change\", function(_cm, changeObj) {\n                \n                if (settings.watch)\n                {\n                    _this.previewContainer.css(\"padding\", settings.autoHeight ? \"20px 20px 50px 40px\" : \"20px\");\n                }\n                \n                timer = setTimeout(function() {\n                    clearTimeout(timer);\n                    _this.save();\n                    timer = null;\n                }, settings.delay);\n            });\n\n            return this;\n        },\n        \n        /**\n         * 加载队列完成之后的显示处理\n         * Display handle of the module queues loaded after.\n         * \n         * @param   {Boolean}   recreate   是否为重建编辑器\n         * @returns {editormd}             返回editormd的实例对象\n         */\n        \n        loadedDisplay : function(recreate) {\n            \n            recreate             = recreate || false;\n            \n            var _this            = this;\n            var editor           = this.editor;\n            var preview          = this.preview;\n            var settings         = this.settings;\n            \n            this.containerMask.hide();\n            \n            this.save();\n            \n            if (settings.watch) {\n                preview.show();\n            }\n            \n            editor.data(\"oldWidth\", editor.width()).data(\"oldHeight\", editor.height()); // 为了兼容Zepto\n            \n            this.resize();\n            this.registerKeyMaps();\n            \n            $(window).resize(function(){\n                _this.resize();\n            });\n            \n            this.bindScrollEvent().bindChangeEvent();\n            \n            if (!recreate)\n            {\n                $.proxy(settings.onload, this)();\n            }\n            \n            this.state.loaded = true;\n\n            return this;\n        },\n        \n        /**\n         * 设置编辑器的宽度\n         * Set editor width\n         * \n         * @param   {Number|String} width  编辑器宽度值\n         * @returns {editormd}             返回editormd的实例对象\n         */\n        \n        width : function(width) {\n                \n            this.editor.css(\"width\", (typeof width === \"number\") ? width  + \"px\" : width);            \n            this.resize();\n            \n            return this;\n        },\n        \n        /**\n         * 设置编辑器的高度\n         * Set editor height\n         * \n         * @param   {Number|String} height  编辑器高度值\n         * @returns {editormd}              返回editormd的实例对象\n         */\n        \n        height : function(height) {\n                \n            this.editor.css(\"height\", (typeof height === \"number\")  ? height  + \"px\" : height);            \n            this.resize();\n            \n            return this;\n        },\n        \n        /**\n         * 调整编辑器的尺寸和布局\n         * Resize editor layout\n         * \n         * @param   {Number|String} [width=null]  编辑器宽度值\n         * @param   {Number|String} [height=null] 编辑器高度值\n         * @returns {editormd}                    返回editormd的实例对象\n         */\n        \n        resize : function(width, height) {\n            \n            width  = width  || null;\n            height = height || null;\n            \n            var state      = this.state;\n            var editor     = this.editor;\n            var preview    = this.preview;\n            var toolbar    = this.toolbar;\n            var settings   = this.settings;\n            var codeMirror = this.codeMirror;\n            \n            if (width)\n            {\n                editor.css(\"width\", (typeof width  === \"number\") ? width  + \"px\" : width);\n            }\n            \n            if (settings.autoHeight && !state.fullscreen && !state.preview)\n            {\n                editor.css(\"height\", \"auto\");\n                codeMirror.css(\"height\", \"auto\");\n            } \n            else \n            {\n                if (height) \n                {\n                    editor.css(\"height\", (typeof height === \"number\") ? height + \"px\" : height);\n                }\n                \n                if (state.fullscreen)\n                {\n                    editor.height($(window).height());\n                }\n\n                if (settings.toolbar && !settings.readOnly) \n                {\n                    codeMirror.css(\"margin-top\", toolbar.height() + 1).height(editor.height() - toolbar.height());\n                } \n                else\n                {\n                    codeMirror.css(\"margin-top\", 0).height(editor.height());\n                }\n            }\n            \n            if(settings.watch) \n            {\n                codeMirror.width(editor.width() / 2);\n                preview.width((!state.preview) ? editor.width() / 2 : editor.width());\n                \n                this.previewContainer.css(\"padding\", settings.autoHeight ? \"20px 20px 50px 40px\" : \"20px\");\n                \n                if (settings.toolbar && !settings.readOnly) \n                {\n                    preview.css(\"top\", toolbar.height() + 1);\n                } \n                else \n                {\n                    preview.css(\"top\", 0);\n                }\n                \n                if (settings.autoHeight && !state.fullscreen && !state.preview)\n                {\n                    preview.height(\"\");\n                }\n                else\n                {                \n                    var previewHeight = (settings.toolbar && !settings.readOnly) ? editor.height() - toolbar.height() : editor.height();\n                    \n                    preview.height(previewHeight);\n                }\n            } \n            else \n            {\n                codeMirror.width(editor.width());\n                preview.hide();\n            }\n            \n            if (state.loaded) \n            {\n                $.proxy(settings.onresize, this)();\n            }\n\n            return this;\n        },\n        \n        /**\n         * 解析和保存Markdown代码\n         * Parse & Saving Markdown source code\n         * \n         * @returns {editormd}     返回editormd的实例对象\n         */\n        \n        save : function() {\n            \n            if (timer === null)\n            {\n                return this;\n            }\n            \n            var _this            = this;\n            var state            = this.state;\n            var settings         = this.settings;\n            var cm               = this.cm;            \n            var cmValue          = cm.getValue();\n            var previewContainer = this.previewContainer;\n\n            if (settings.mode !== \"gfm\" && settings.mode !== \"markdown\") \n            {\n                this.markdownTextarea.val(cmValue);\n                \n                return this;\n            }\n            \n            var marked          = editormd.$marked;\n            var markdownToC     = this.markdownToC = [];            \n            var rendererOptions = this.markedRendererOptions = {  \n                toc                  : settings.toc,\n                tocm                 : settings.tocm,\n                tocStartLevel        : settings.tocStartLevel,\n                pageBreak            : settings.pageBreak,\n                taskList             : settings.taskList,\n                emoji                : settings.emoji,\n                tex                  : settings.tex,\n                atLink               : settings.atLink,           // for @link\n                emailLink            : settings.emailLink,        // for mail address auto link\n                flowChart            : settings.flowChart,\n                sequenceDiagram      : settings.sequenceDiagram,\n                previewCodeHighlight : settings.previewCodeHighlight,\n            };\n            \n            var markedOptions = this.markedOptions = {\n                renderer    : editormd.markedRenderer(markdownToC, rendererOptions),\n                gfm         : true,\n                tables      : true,\n                breaks      : true,\n                pedantic    : false,\n                sanitize    : (settings.htmlDecode) ? false : true,  // 关闭忽略HTML标签，即开启识别HTML标签，默认为false\n                smartLists  : true,\n                smartypants : true\n            };\n            \n            marked.setOptions(markedOptions);\n                    \n            var newMarkdownDoc = editormd.$marked(cmValue, markedOptions);\n            \n            //console.info(\"cmValue\", cmValue, newMarkdownDoc);\n            \n            newMarkdownDoc = editormd.filterHTMLTags(newMarkdownDoc, settings.htmlDecode);\n            \n            //console.error(\"cmValue\", cmValue, newMarkdownDoc);\n            \n            this.markdownTextarea.text(cmValue);\n            \n            cm.save();\n            \n            if (settings.saveHTMLToTextarea) \n            {\n                this.htmlTextarea.text(newMarkdownDoc);\n            }\n            \n            if(settings.watch || (!settings.watch && state.preview))\n            {\n                previewContainer.html(newMarkdownDoc);\n\n                this.previewCodeHighlight();\n                \n                if (settings.toc) \n                {\n                    var tocContainer = (settings.tocContainer === \"\") ? previewContainer : $(settings.tocContainer);\n                    var tocMenu      = tocContainer.find(\".\" + this.classPrefix + \"toc-menu\");\n                    \n                    tocContainer.attr(\"previewContainer\", (settings.tocContainer === \"\") ? \"true\" : \"false\");\n                    \n                    if (settings.tocContainer !== \"\" && tocMenu.length > 0)\n                    {\n                        tocMenu.remove();\n                    }\n                    \n                    editormd.markdownToCRenderer(markdownToC, tocContainer, settings.tocDropdown, settings.tocStartLevel);\n            \n                    if (settings.tocDropdown || tocContainer.find(\".\" + this.classPrefix + \"toc-menu\").length > 0)\n                    {\n                        editormd.tocDropdownMenu(tocContainer, (settings.tocTitle !== \"\") ? settings.tocTitle : this.lang.tocTitle);\n                    }\n            \n                    if (settings.tocContainer !== \"\")\n                    {\n                        previewContainer.find(\".markdown-toc\").css(\"border\", \"none\");\n                    }\n                }\n                \n                if (settings.tex)\n                {\n                    if (!editormd.kaTeXLoaded && settings.autoLoadModules) \n                    {\n                        editormd.loadKaTeX(function() {\n                            editormd.$katex = katex;\n                            editormd.kaTeXLoaded = true;\n                            _this.katexRender();\n                        });\n                    } \n                    else \n                    {\n                        editormd.$katex = katex;\n                        this.katexRender();\n                    }\n                }                \n                \n                if (settings.flowChart || settings.sequenceDiagram)\n                {\n                    flowchartTimer = setTimeout(function(){\n                        clearTimeout(flowchartTimer);\n                        _this.flowChartAndSequenceDiagramRender();\n                        flowchartTimer = null;\n                    }, 10);\n                }\n\n                if (state.loaded) \n                {\n                    $.proxy(settings.onchange, this)();\n                }\n            }\n\n            return this;\n        },\n        \n        /**\n         * 聚焦光标位置\n         * Focusing the cursor position\n         * \n         * @returns {editormd}         返回editormd的实例对象\n         */\n        \n        focus : function() {\n            this.cm.focus();\n\n            return this;\n        },\n        \n        /**\n         * 设置光标的位置\n         * Set cursor position\n         * \n         * @param   {Object}    cursor 要设置的光标位置键值对象，例：{line:1, ch:0}\n         * @returns {editormd}         返回editormd的实例对象\n         */\n        \n        setCursor : function(cursor) {\n            this.cm.setCursor(cursor);\n\n            return this;\n        },\n        \n        /**\n         * 获取当前光标的位置\n         * Get the current position of the cursor\n         * \n         * @returns {Cursor}         返回一个光标Cursor对象\n         */\n        \n        getCursor : function() {\n            return this.cm.getCursor();\n        },\n        \n        /**\n         * 设置光标选中的范围\n         * Set cursor selected ranges\n         * \n         * @param   {Object}    from   开始位置的光标键值对象，例：{line:1, ch:0}\n         * @param   {Object}    to     结束位置的光标键值对象，例：{line:1, ch:0}\n         * @returns {editormd}         返回editormd的实例对象\n         */\n        \n        setSelection : function(from, to) {\n        \n            this.cm.setSelection(from, to);\n        \n            return this;\n        },\n        \n        /**\n         * 获取光标选中的文本\n         * Get the texts from cursor selected\n         * \n         * @returns {String}         返回选中文本的字符串形式\n         */\n        \n        getSelection : function() {\n            return this.cm.getSelection();\n        },\n        \n        /**\n         * 设置光标选中的文本范围\n         * Set the cursor selection ranges\n         * \n         * @param   {Array}    ranges  cursor selection ranges array\n         * @returns {Array}            return this\n         */\n        \n        setSelections : function(ranges) {\n            this.cm.setSelections(ranges);\n            \n            return this;\n        },\n        \n        /**\n         * 获取光标选中的文本范围\n         * Get the cursor selection ranges\n         * \n         * @returns {Array}         return selection ranges array\n         */\n        \n        getSelections : function() {\n            return this.cm.getSelections();\n        },\n        \n        /**\n         * 替换当前光标选中的文本或在当前光标处插入新字符\n         * Replace the text at the current cursor selected or insert a new character at the current cursor position\n         * \n         * @param   {String}    value  要插入的字符值\n         * @returns {editormd}         返回editormd的实例对象\n         */\n        \n        replaceSelection : function(value) {\n            this.cm.replaceSelection(value);\n\n            return this;\n        },\n        \n        /**\n         * 在当前光标处插入新字符\n         * Insert a new character at the current cursor position\n         *\n         * 同replaceSelection()方法\n         * With the replaceSelection() method\n         * \n         * @param   {String}    value  要插入的字符值\n         * @returns {editormd}         返回editormd的实例对象\n         */\n        \n        insertValue : function(value) {\n            this.replaceSelection(value);\n\n            return this;\n        },\n        \n        /**\n         * 追加markdown\n         * append Markdown to editor\n         * \n         * @param   {String}    md     要追加的markdown源文档\n         * @returns {editormd}         返回editormd的实例对象\n         */\n        \n        appendMarkdown : function(md) {\n            var settings = this.settings;\n            var cm       = this.cm;\n            \n            cm.setValue(cm.getValue() + md);\n            \n            return this;\n        },\n        \n        /**\n         * 设置和传入编辑器的markdown源文档\n         * Set Markdown source document\n         * \n         * @param   {String}    md     要传入的markdown源文档\n         * @returns {editormd}         返回editormd的实例对象\n         */\n        \n        setMarkdown : function(md) {\n            this.cm.setValue(md || this.settings.markdown);\n            \n            return this;\n        },\n        \n        /**\n         * 获取编辑器的markdown源文档\n         * Set Editor.md markdown/CodeMirror value\n         * \n         * @returns {editormd}         返回editormd的实例对象\n         */\n        \n        getMarkdown : function() {\n            return this.cm.getValue();\n        },\n        \n        /**\n         * 获取编辑器的源文档\n         * Get CodeMirror value\n         * \n         * @returns {editormd}         返回editormd的实例对象\n         */\n        \n        getValue : function() {\n            return this.cm.getValue();\n        },\n        \n        /**\n         * 设置编辑器的源文档\n         * Set CodeMirror value\n         * \n         * @param   {String}     value   set code/value/string/text\n         * @returns {editormd}           返回editormd的实例对象\n         */\n        \n        setValue : function(value) {\n            this.cm.setValue(value);\n            \n            return this;\n        },\n        \n        /**\n         * 清空编辑器\n         * Empty CodeMirror editor container\n         * \n         * @returns {editormd}         返回editormd的实例对象\n         */\n        \n        clear : function() {\n            this.cm.setValue(\"\");\n            \n            return this;\n        },\n        \n        /**\n         * 获取解析后存放在Textarea的HTML源码\n         * Get parsed html code from Textarea\n         * \n         * @returns {String}               返回HTML源码\n         */\n        \n        getHTML : function() {\n            if (!this.settings.saveHTMLToTextarea)\n            {\n                alert(\"Error: settings.saveHTMLToTextarea == false\");\n\n                return false;\n            }\n            \n            return this.htmlTextarea.val();\n        },\n        \n        /**\n         * getHTML()的别名\n         * getHTML (alias)\n         * \n         * @returns {String}           Return html code 返回HTML源码\n         */\n        \n        getTextareaSavedHTML : function() {\n            return this.getHTML();\n        },\n        \n        /**\n         * 获取预览窗口的HTML源码\n         * Get html from preview container\n         * \n         * @returns {editormd}         返回editormd的实例对象\n         */\n        \n        getPreviewedHTML : function() {\n            if (!this.settings.watch)\n            {\n                alert(\"Error: settings.watch == false\");\n\n                return false;\n            }\n            \n            return this.previewContainer.html();\n        },\n        \n        /**\n         * 开启实时预览\n         * Enable real-time watching\n         * \n         * @returns {editormd}         返回editormd的实例对象\n         */\n        \n        watch : function(callback) {     \n            var settings        = this.settings;\n            \n            if ($.inArray(settings.mode, [\"gfm\", \"markdown\"]) < 0)\n            {\n                return this;\n            }\n            \n            this.state.watching = settings.watch = true;\n            this.preview.show();\n            \n            if (this.toolbar)\n            {\n                var watchIcon   = settings.toolbarIconsClass.watch;\n                var unWatchIcon = settings.toolbarIconsClass.unwatch;\n                \n                var icon        = this.toolbar.find(\".fa[name=watch]\");\n                icon.parent().attr(\"title\", settings.lang.toolbar.watch);\n                icon.removeClass(unWatchIcon).addClass(watchIcon);\n            }\n            \n            this.codeMirror.css(\"border-right\", \"1px solid #ddd\").width(this.editor.width() / 2); \n            \n            timer = 0;\n            \n            this.save().resize();\n            \n            if (!settings.onwatch)\n            {\n                settings.onwatch = callback || function() {};\n            }\n            \n            $.proxy(settings.onwatch, this)();\n            \n            return this;\n        },\n        \n        /**\n         * 关闭实时预览\n         * Disable real-time watching\n         * \n         * @returns {editormd}         返回editormd的实例对象\n         */\n        \n        unwatch : function(callback) {\n            var settings        = this.settings;\n            this.state.watching = settings.watch = false;\n            this.preview.hide();\n            \n            if (this.toolbar) \n            {\n                var watchIcon   = settings.toolbarIconsClass.watch;\n                var unWatchIcon = settings.toolbarIconsClass.unwatch;\n                \n                var icon    = this.toolbar.find(\".fa[name=watch]\");\n                icon.parent().attr(\"title\", settings.lang.toolbar.unwatch);\n                icon.removeClass(watchIcon).addClass(unWatchIcon);\n            }\n            \n            this.codeMirror.css(\"border-right\", \"none\").width(this.editor.width());\n            \n            this.resize();\n            \n            if (!settings.onunwatch)\n            {\n                settings.onunwatch = callback || function() {};\n            }\n            \n            $.proxy(settings.onunwatch, this)();\n            \n            return this;\n        },\n        \n        /**\n         * 显示编辑器\n         * Show editor\n         * \n         * @param   {Function} [callback=function()] 回调函数\n         * @returns {editormd}                       返回editormd的实例对象\n         */\n        \n        show : function(callback) {\n            callback  = callback || function() {};\n            \n            var _this = this;\n            this.editor.show(0, function() {\n                $.proxy(callback, _this)();\n            });\n            \n            return this;\n        },\n        \n        /**\n         * 隐藏编辑器\n         * Hide editor\n         * \n         * @param   {Function} [callback=function()] 回调函数\n         * @returns {editormd}                       返回editormd的实例对象\n         */\n        \n        hide : function(callback) {\n            callback  = callback || function() {};\n            \n            var _this = this;\n            this.editor.hide(0, function() {\n                $.proxy(callback, _this)();\n            });\n            \n            return this;\n        },\n        \n        /**\n         * 隐藏编辑器部分，只预览HTML\n         * Enter preview html state\n         * \n         * @returns {editormd}         返回editormd的实例对象\n         */\n        \n        previewing : function() {\n            \n            var _this            = this;\n            var editor           = this.editor;\n            var preview          = this.preview;\n            var toolbar          = this.toolbar;\n            var settings         = this.settings;\n            var codeMirror       = this.codeMirror;\n            var previewContainer = this.previewContainer;\n            \n            if ($.inArray(settings.mode, [\"gfm\", \"markdown\"]) < 0) {\n                return this;\n            }\n            \n            if (settings.toolbar && toolbar) {\n                toolbar.toggle();\n                toolbar.find(\".fa[name=preview]\").toggleClass(\"active\");\n            }\n            \n            codeMirror.toggle();\n            \n            var escHandle = function(event) {\n                if (event.shiftKey && event.keyCode === 27) {\n                    _this.previewed();\n                }\n            };\n\n            if (codeMirror.css(\"display\") === \"none\") // 为了兼容Zepto，而不使用codeMirror.is(\":hidden\")\n            {\n                this.state.preview = true;\n\n                if (this.state.fullscreen) {\n                    preview.css(\"background\", \"#fff\");\n                }\n                \n                editor.find(\".\" + this.classPrefix + \"preview-close-btn\").show().bind(editormd.mouseOrTouch(\"click\", \"touchend\"), function(){\n                    _this.previewed();\n                });\n            \n                if (!settings.watch)\n                {\n                    this.save();\n                } \n                else \n                {\n                    previewContainer.css(\"padding\", \"\");\n                }\n                \n                previewContainer.addClass(this.classPrefix + \"preview-active\");\n\n                preview.show().css({\n                    position  : \"\",\n                    top       : 0,\n                    width     : editor.width(),\n                    height    : (settings.autoHeight && !this.state.fullscreen) ? \"auto\" : editor.height()\n                });\n                \n                if (this.state.loaded)\n                {\n                    $.proxy(settings.onpreviewing, this)();\n                }\n\n                $(window).bind(\"keyup\", escHandle);\n            } \n            else \n            {\n                $(window).unbind(\"keyup\", escHandle);\n                this.previewed();\n            }\n        },\n        \n        /**\n         * 显示编辑器部分，退出只预览HTML\n         * Exit preview html state\n         * \n         * @returns {editormd}         返回editormd的实例对象\n         */\n        \n        previewed : function() {\n            \n            var editor           = this.editor;\n            var preview          = this.preview;\n            var toolbar          = this.toolbar;\n            var settings         = this.settings;\n            var previewContainer = this.previewContainer;\n            var previewCloseBtn  = editor.find(\".\" + this.classPrefix + \"preview-close-btn\");\n\n            this.state.preview   = false;\n            \n            this.codeMirror.show();\n            \n            if (settings.toolbar) {\n                toolbar.show();\n            }\n            \n            preview[(settings.watch) ? \"show\" : \"hide\"]();\n            \n            previewCloseBtn.hide().unbind(editormd.mouseOrTouch(\"click\", \"touchend\"));\n                \n            previewContainer.removeClass(this.classPrefix + \"preview-active\");\n                \n            if (settings.watch)\n            {\n                previewContainer.css(\"padding\", \"20px\");\n            }\n            \n            preview.css({ \n                background : null,\n                position   : \"absolute\",\n                width      : editor.width() / 2,\n                height     : (settings.autoHeight && !this.state.fullscreen) ? \"auto\" : editor.height() - toolbar.height(),\n                top        : (settings.toolbar)    ? toolbar.height() : 0\n            });\n\n            if (this.state.loaded)\n            {\n                $.proxy(settings.onpreviewed, this)();\n            }\n            \n            return this;\n        },\n        \n        /**\n         * 编辑器全屏显示\n         * Fullscreen show\n         * \n         * @returns {editormd}         返回editormd的实例对象\n         */\n        \n        fullscreen : function() {\n            \n            var _this            = this;\n            var state            = this.state;\n            var editor           = this.editor;\n            var preview          = this.preview;\n            var toolbar          = this.toolbar;\n            var settings         = this.settings;\n            var fullscreenClass  = this.classPrefix + \"fullscreen\";\n            \n            if (toolbar) {\n                toolbar.find(\".fa[name=fullscreen]\").parent().toggleClass(\"active\"); \n            }\n            \n            var escHandle = function(event) {\n                if (!event.shiftKey && event.keyCode === 27) \n                {\n                    if (state.fullscreen)\n                    {\n                        _this.fullscreenExit();\n                    }\n                }\n            };\n\n            if (!editor.hasClass(fullscreenClass)) \n            {\n                state.fullscreen = true;\n\n                $(\"html,body\").css(\"overflow\", \"hidden\");\n                \n                editor.css({\n                    width    : $(window).width(),\n                    height   : $(window).height()\n                }).addClass(fullscreenClass);\n\n                this.resize();\n    \n                $.proxy(settings.onfullscreen, this)();\n\n                $(window).bind(\"keyup\", escHandle);\n            }\n            else\n            {           \n                $(window).unbind(\"keyup\", escHandle); \n                this.fullscreenExit();\n            }\n\n            return this;\n        },\n        \n        /**\n         * 编辑器退出全屏显示\n         * Exit fullscreen state\n         * \n         * @returns {editormd}         返回editormd的实例对象\n         */\n        \n        fullscreenExit : function() {\n            \n            var editor            = this.editor;\n            var settings          = this.settings;\n            var toolbar           = this.toolbar;\n            var fullscreenClass   = this.classPrefix + \"fullscreen\";  \n            \n            this.state.fullscreen = false;\n            \n            if (toolbar) {\n                toolbar.find(\".fa[name=fullscreen]\").parent().removeClass(\"active\"); \n            }\n\n            $(\"html,body\").css(\"overflow\", \"\");\n\n            editor.css({\n                width    : editor.data(\"oldWidth\"),\n                height   : editor.data(\"oldHeight\")\n            }).removeClass(fullscreenClass);\n\n            this.resize();\n            \n            $.proxy(settings.onfullscreenExit, this)();\n\n            return this;\n        },\n        \n        /**\n         * 加载并执行插件\n         * Load and execute the plugin\n         * \n         * @param   {String}     name    plugin name / function name\n         * @param   {String}     path    plugin load path\n         * @returns {editormd}           返回editormd的实例对象\n         */\n        \n        executePlugin : function(name, path) {\n            \n            var _this    = this;\n            var cm       = this.cm;\n            var settings = this.settings;\n            \n            path = settings.pluginPath + path;\n            \n            if (typeof define === \"function\") \n            {            \n                if (typeof this[name] === \"undefined\")\n                {\n                    alert(\"Error: \" + name + \" plugin is not found, you are not load this plugin.\");\n                    \n                    return this;\n                }\n                \n                this[name](cm);\n                \n                return this;\n            }\n            \n            if ($.inArray(path, editormd.loadFiles.plugin) < 0)\n            {\n                editormd.loadPlugin(path, function() {\n                    editormd.loadPlugins[name] = _this[name];\n                    _this[name](cm);\n                });\n            }\n            else\n            {\n                $.proxy(editormd.loadPlugins[name], this)(cm);\n            }\n            \n            return this;\n        },\n                \n        /**\n         * 搜索替换\n         * Search & replace\n         * \n         * @param   {String}     command    CodeMirror serach commands, \"find, fintNext, fintPrev, clearSearch, replace, replaceAll\"\n         * @returns {editormd}              return this\n         */\n        \n        search : function(command) {\n            var settings = this.settings;\n            \n            if (!settings.searchReplace)\n            {\n                alert(\"Error: settings.searchReplace == false\");\n                return this;\n            }\n            \n            if (!settings.readOnly)\n            {\n                this.cm.execCommand(command || \"find\");\n            }\n            \n            return this;\n        },\n        \n        searchReplace : function() {            \n            this.search(\"replace\");\n            \n            return this;\n        },\n        \n        searchReplaceAll : function() {          \n            this.search(\"replaceAll\");\n            \n            return this;\n        }\n    };\n    \n    editormd.fn.init.prototype = editormd.fn; \n   \n    /**\n     * 锁屏\n     * lock screen when dialog opening\n     * \n     * @returns {void}\n     */\n\n    editormd.dialogLockScreen = function() {\n        var settings = this.settings || {dialogLockScreen : true};\n        \n        if (settings.dialogLockScreen) \n        {            \n            $(\"html,body\").css(\"overflow\", \"hidden\");\n            this.resize();\n        }\n    };\n   \n    /**\n     * 显示透明背景层\n     * Display mask layer when dialog opening\n     * \n     * @param   {Object}     dialog    dialog jQuery object\n     * @returns {void}\n     */\n    \n    editormd.dialogShowMask = function(dialog) {\n        var editor   = this.editor;\n        var settings = this.settings || {dialogShowMask : true};\n        \n        dialog.css({\n            top  : ($(window).height() - dialog.height()) / 2 + \"px\",\n            left : ($(window).width()  - dialog.width())  / 2 + \"px\"\n        });\n\n        if (settings.dialogShowMask) {\n            editor.children(\".\" + this.classPrefix + \"mask\").css(\"z-index\", parseInt(dialog.css(\"z-index\")) - 1).show();\n        }\n    };\n\n    editormd.toolbarHandlers = {\n        undo : function() {\n            this.cm.undo();\n        },\n        \n        redo : function() {\n            this.cm.redo();\n        },\n        \n        bold : function() {\n            var cm        = this.cm;\n            var cursor    = cm.getCursor();\n            var selection = cm.getSelection();\n\n            cm.replaceSelection(\"**\" + selection + \"**\");\n\n            if(selection === \"\") {\n                cm.setCursor(cursor.line, cursor.ch + 2);\n            }\n        },\n        \n        del : function() {\n            var cm        = this.cm;\n            var cursor    = cm.getCursor();\n            var selection = cm.getSelection();\n\n            cm.replaceSelection(\"~~\" + selection + \"~~\");\n\n            if(selection === \"\") {\n                cm.setCursor(cursor.line, cursor.ch + 2);\n            }\n        },\n\n        italic : function() {\n            var cm        = this.cm;\n            var cursor    = cm.getCursor();\n            var selection = cm.getSelection();\n\n            cm.replaceSelection(\"*\" + selection + \"*\");\n\n            if(selection === \"\") {\n                cm.setCursor(cursor.line, cursor.ch + 1);\n            }\n        },\n\n        quote : function() {\n            var cm        = this.cm;\n            var cursor    = cm.getCursor();\n            var selection = cm.getSelection();\n\n            if (cursor.ch !== 0)\n            {\n                cm.setCursor(cursor.line, 0);\n                cm.replaceSelection(\"> \" + selection);\n                cm.setCursor(cursor.line, cursor.ch + 2);\n            }\n            else\n            {\n                cm.replaceSelection(\"> \" + selection);\n            }\n\n            //cm.replaceSelection(\"> \" + selection);\n            //cm.setCursor(cursor.line, (selection === \"\") ? cursor.ch + 2 : cursor.ch + selection.length + 2);\n        },\n        \n        ucfirst : function() {\n            var cm         = this.cm;\n            var selection  = cm.getSelection();\n            var selections = cm.listSelections();\n\n            cm.replaceSelection(editormd.firstUpperCase(selection));\n            cm.setSelections(selections);\n        },\n        \n        ucwords : function() {\n            var cm         = this.cm;\n            var selection  = cm.getSelection();\n            var selections = cm.listSelections();\n\n            cm.replaceSelection(editormd.wordsFirstUpperCase(selection));\n            cm.setSelections(selections);\n        },\n        \n        uppercase : function() {\n            var cm         = this.cm;\n            var selection  = cm.getSelection();\n            var selections = cm.listSelections();\n\n            cm.replaceSelection(selection.toUpperCase());\n            cm.setSelections(selections);\n        },\n        \n        lowercase : function() {\n            var cm         = this.cm;\n            var cursor     = cm.getCursor();\n            var selection  = cm.getSelection();\n            var selections = cm.listSelections();\n            \n            cm.replaceSelection(selection.toLowerCase());\n            cm.setSelections(selections);\n        },\n\n        h1 : function() {\n            var cm        = this.cm;\n            var cursor    = cm.getCursor();\n            var selection = cm.getSelection();\n\n            if (cursor.ch !== 0)\n            {\n                cm.setCursor(cursor.line, 0);\n                cm.replaceSelection(\"# \" + selection);\n                cm.setCursor(cursor.line, cursor.ch + 2);\n            }\n            else\n            {\n                cm.replaceSelection(\"# \" + selection);\n            }\n        },\n\n        h2 : function() {\n            var cm        = this.cm;\n            var cursor    = cm.getCursor();\n            var selection = cm.getSelection();\n\n            if (cursor.ch !== 0)\n            {\n                cm.setCursor(cursor.line, 0);\n                cm.replaceSelection(\"## \" + selection);\n                cm.setCursor(cursor.line, cursor.ch + 3);\n            }\n            else\n            {\n                cm.replaceSelection(\"## \" + selection);\n            }\n        },\n\n        h3 : function() {\n            var cm        = this.cm;\n            var cursor    = cm.getCursor();\n            var selection = cm.getSelection();\n\n            if (cursor.ch !== 0)\n            {\n                cm.setCursor(cursor.line, 0);\n                cm.replaceSelection(\"### \" + selection);\n                cm.setCursor(cursor.line, cursor.ch + 4);\n            }\n            else\n            {\n                cm.replaceSelection(\"### \" + selection);\n            }\n        },\n\n        h4 : function() {\n            var cm        = this.cm;\n            var cursor    = cm.getCursor();\n            var selection = cm.getSelection();\n\n            if (cursor.ch !== 0)\n            {\n                cm.setCursor(cursor.line, 0);\n                cm.replaceSelection(\"#### \" + selection);\n                cm.setCursor(cursor.line, cursor.ch + 5);\n            }\n            else\n            {\n                cm.replaceSelection(\"#### \" + selection);\n            }\n        },\n\n        h5 : function() {\n            var cm        = this.cm;\n            var cursor    = cm.getCursor();\n            var selection = cm.getSelection();\n\n            if (cursor.ch !== 0)\n            {\n                cm.setCursor(cursor.line, 0);\n                cm.replaceSelection(\"##### \" + selection);\n                cm.setCursor(cursor.line, cursor.ch + 6);\n            }\n            else\n            {\n                cm.replaceSelection(\"##### \" + selection);\n            }\n        },\n\n        h6 : function() {\n            var cm        = this.cm;\n            var cursor    = cm.getCursor();\n            var selection = cm.getSelection();\n\n            if (cursor.ch !== 0)\n            {\n                cm.setCursor(cursor.line, 0);\n                cm.replaceSelection(\"###### \" + selection);\n                cm.setCursor(cursor.line, cursor.ch + 7);\n            }\n            else\n            {\n                cm.replaceSelection(\"###### \" + selection);\n            }\n        },\n\n        \"list-ul\" : function() {\n            var cm        = this.cm;\n            var cursor    = cm.getCursor();\n            var selection = cm.getSelection();\n\n            if (selection === \"\") \n            {\n                cm.replaceSelection(\"- \" + selection);\n            } \n            else \n            {\n                var selectionText = selection.split(\"\\n\");\n\n                for (var i = 0, len = selectionText.length; i < len; i++) \n                {\n                    selectionText[i] = (selectionText[i] === \"\") ? \"\" : \"- \" + selectionText[i];\n                }\n\n                cm.replaceSelection(selectionText.join(\"\\n\"));\n            }\n        },\n\n        \"list-ol\" : function() {\n            var cm        = this.cm;\n            var cursor    = cm.getCursor();\n            var selection = cm.getSelection();\n\n            if(selection === \"\") \n            {\n                cm.replaceSelection(\"1. \" + selection);\n            }\n            else\n            {\n                var selectionText = selection.split(\"\\n\");\n\n                for (var i = 0, len = selectionText.length; i < len; i++) \n                {\n                    selectionText[i] = (selectionText[i] === \"\") ? \"\" : (i+1) + \". \" + selectionText[i];\n                }\n\n                cm.replaceSelection(selectionText.join(\"\\n\"));\n            }\n        },\n\n        hr : function() {\n            var cm        = this.cm;\n            var cursor    = cm.getCursor();\n            var selection = cm.getSelection();\n\n            cm.replaceSelection(((cursor.ch !== 0) ? \"\\n\\n\" : \"\\n\") + \"------------\\n\\n\");\n        },\n\n        tex : function() {\n            if (!this.settings.tex)\n            {\n                alert(\"settings.tex === false\");\n                return this;\n            }\n            \n            var cm        = this.cm;\n            var cursor    = cm.getCursor();\n            var selection = cm.getSelection();\n\n            cm.replaceSelection(\"$$\" + selection + \"$$\");\n\n            if(selection === \"\") {\n                cm.setCursor(cursor.line, cursor.ch + 2);\n            }\n        },\n\n        link : function() {\n            this.executePlugin(\"linkDialog\", \"link-dialog/link-dialog\");\n        },\n\n        \"reference-link\" : function() {\n            this.executePlugin(\"referenceLinkDialog\", \"reference-link-dialog/reference-link-dialog\");\n        },\n\n        pagebreak : function() {\n            if (!this.settings.pageBreak)\n            {\n                alert(\"settings.pageBreak === false\");\n                return this;\n            }\n            \n            var cm        = this.cm;\n            var selection = cm.getSelection();\n\n            cm.replaceSelection(\"\\r\\n[========]\\r\\n\");\n        },\n\n        image : function() {\n            this.executePlugin(\"imageDialog\", \"image-dialog/image-dialog\");\n        },\n        \n        code : function() {\n            var cm        = this.cm;\n            var cursor    = cm.getCursor();\n            var selection = cm.getSelection();\n\n            cm.replaceSelection(\"`\" + selection + \"`\");\n\n            if (selection === \"\") {\n                cm.setCursor(cursor.line, cursor.ch + 1);\n            }\n        },\n\n        \"code-block\" : function() {\n            this.executePlugin(\"codeBlockDialog\", \"code-block-dialog/code-block-dialog\");            \n        },\n\n        \"preformatted-text\" : function() {\n            this.executePlugin(\"preformattedTextDialog\", \"preformatted-text-dialog/preformatted-text-dialog\");\n        },\n        \n        table : function() {\n            this.executePlugin(\"tableDialog\", \"table-dialog/table-dialog\");         \n        },\n        \n        datetime : function() {\n            var cm        = this.cm;\n            var selection = cm.getSelection();\n            var date      = new Date();\n            var langName  = this.settings.lang.name;\n            var datefmt   = editormd.dateFormat() + \" \" + editormd.dateFormat((langName === \"zh-cn\" || langName === \"zh-tw\") ? \"cn-week-day\" : \"week-day\");\n\n            cm.replaceSelection(datefmt);\n        },\n        \n        emoji : function() {\n            this.executePlugin(\"emojiDialog\", \"emoji-dialog/emoji-dialog\");\n        },\n                \n        \"html-entities\" : function() {\n            this.executePlugin(\"htmlEntitiesDialog\", \"html-entities-dialog/html-entities-dialog\");\n        },\n                \n        \"goto-line\" : function() {\n            this.executePlugin(\"gotoLineDialog\", \"goto-line-dialog/goto-line-dialog\");\n        },\n\n        watch : function() {    \n            this[this.settings.watch ? \"unwatch\" : \"watch\"]();\n        },\n\n        preview : function() {\n            this.previewing();\n        },\n\n        fullscreen : function() {\n            this.fullscreen();\n        },\n\n        clear : function() {\n            this.clear();\n        },\n        \n        search : function() {\n            this.search();\n        },\n\n        help : function() {\n            this.executePlugin(\"helpDialog\", \"help-dialog/help-dialog\");\n        },\n\n        info : function() {\n            this.showInfoDialog();\n        }\n    };\n    \n    editormd.keyMaps = {\n        \"Ctrl-1\"       : \"h1\",\n        \"Ctrl-2\"       : \"h2\",\n        \"Ctrl-3\"       : \"h3\",\n        \"Ctrl-4\"       : \"h4\",\n        \"Ctrl-5\"       : \"h5\",\n        \"Ctrl-6\"       : \"h6\",\n        \"Ctrl-B\"       : \"bold\",  // if this is string ==  editormd.toolbarHandlers.xxxx\n        \"Ctrl-D\"       : \"datetime\",\n        \n        \"Ctrl-E\"       : function() { // emoji\n            var cm        = this.cm;\n            var cursor    = cm.getCursor();\n            var selection = cm.getSelection();\n            \n            if (!this.settings.emoji)\n            {\n                alert(\"Error: settings.emoji == false\");\n                return ;\n            }\n\n            cm.replaceSelection(\":\" + selection + \":\");\n\n            if (selection === \"\") {\n                cm.setCursor(cursor.line, cursor.ch + 1);\n            }\n        },\n        \"Ctrl-Alt-G\"   : \"goto-line\",\n        \"Ctrl-H\"       : \"hr\",\n        \"Ctrl-I\"       : \"italic\",\n        \"Ctrl-K\"       : \"code\",\n        \n        \"Ctrl-L\"        : function() {\n            var cm        = this.cm;\n            var cursor    = cm.getCursor();\n            var selection = cm.getSelection();\n            \n            var title = (selection === \"\") ? \"\" : \" \\\"\"+selection+\"\\\"\";\n\n            cm.replaceSelection(\"[\" + selection + \"](\"+title+\")\");\n\n            if (selection === \"\") {\n                cm.setCursor(cursor.line, cursor.ch + 1);\n            }\n        },\n        \"Ctrl-U\"         : \"list-ul\",\n        \n        \"Shift-Ctrl-A\"   : function() {\n            var cm        = this.cm;\n            var cursor    = cm.getCursor();\n            var selection = cm.getSelection();\n            \n            if (!this.settings.atLink)\n            {\n                alert(\"Error: settings.atLink == false\");\n                return ;\n            }\n\n            cm.replaceSelection(\"@\" + selection);\n\n            if (selection === \"\") {\n                cm.setCursor(cursor.line, cursor.ch + 1);\n            }\n        },\n        \n        \"Shift-Ctrl-C\"     : \"code\",\n        \"Shift-Ctrl-Q\"     : \"quote\",\n        \"Shift-Ctrl-S\"     : \"del\",\n        \"Shift-Ctrl-K\"     : \"tex\",  // KaTeX\n        \n        \"Shift-Alt-C\"      : function() {\n            var cm        = this.cm;\n            var cursor    = cm.getCursor();\n            var selection = cm.getSelection();\n            \n            cm.replaceSelection([\"```\", selection, \"```\"].join(\"\\n\"));\n\n            if (selection === \"\") {\n                cm.setCursor(cursor.line, cursor.ch + 3);\n            } \n        },\n        \n        \"Shift-Ctrl-Alt-C\" : \"code-block\",\n        \"Shift-Ctrl-H\"     : \"html-entities\",\n        \"Shift-Alt-H\"      : \"help\",\n        \"Shift-Ctrl-E\"     : \"emoji\",\n        \"Shift-Ctrl-U\"     : \"uppercase\",\n        \"Shift-Alt-U\"      : \"ucwords\",\n        \"Shift-Ctrl-Alt-U\" : \"ucfirst\",\n        \"Shift-Alt-L\"      : \"lowercase\",\n        \n        \"Shift-Ctrl-I\"     : function() {\n            var cm        = this.cm;\n            var cursor    = cm.getCursor();\n            var selection = cm.getSelection();\n            \n            var title = (selection === \"\") ? \"\" : \" \\\"\"+selection+\"\\\"\";\n\n            cm.replaceSelection(\"![\" + selection + \"](\"+title+\")\");\n\n            if (selection === \"\") {\n                cm.setCursor(cursor.line, cursor.ch + 4);\n            }\n        },\n        \n        \"Shift-Ctrl-Alt-I\" : \"image\",\n        \"Shift-Ctrl-L\"     : \"link\",\n        \"Shift-Ctrl-O\"     : \"list-ol\",\n        \"Shift-Ctrl-P\"     : \"preformatted-text\",\n        \"Shift-Ctrl-T\"     : \"table\",\n        \"Shift-Alt-P\"      : \"pagebreak\",\n        \"F9\"               : \"watch\",\n        \"F10\"              : \"preview\",\n        \"F11\"              : \"fullscreen\",\n    };\n    \n    /**\n     * 清除字符串两边的空格\n     * Clear the space of strings both sides.\n     * \n     * @param   {String}    str            string\n     * @returns {String}                   trimed string    \n     */\n    \n    var trim = function(str) {\n        return (!String.prototype.trim) ? str.replace(/^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g, \"\") : str.trim();\n    };\n    \n    editormd.trim = trim;\n    \n    /**\n     * 所有单词首字母大写\n     * Words first to uppercase\n     * \n     * @param   {String}    str            string\n     * @returns {String}                   string\n     */\n    \n    var ucwords = function (str) {\n        return str.toLowerCase().replace(/\\b(\\w)|\\s(\\w)/g, function($1) {  \n            return $1.toUpperCase();\n        });\n    };\n    \n    editormd.ucwords = editormd.wordsFirstUpperCase = ucwords;\n    \n    /**\n     * 字符串首字母大写\n     * Only string first char to uppercase\n     * \n     * @param   {String}    str            string\n     * @returns {String}                   string\n     */\n    \n    var firstUpperCase = function(str) {        \n        return str.toLowerCase().replace(/\\b(\\w)/, function($1){\n            return $1.toUpperCase();\n        });\n    };\n    \n    var ucfirst = firstUpperCase;\n    \n    editormd.firstUpperCase = editormd.ucfirst = firstUpperCase;\n    \n    editormd.urls = {\n        atLinkBase : \"https://github.com/\"\n    };\n    \n    editormd.regexs = {\n        atLink        : /@(\\w+)/g,\n        email         : /(\\w+)@(\\w+)\\.(\\w+)\\.?(\\w+)?/g,\n        emailLink     : /(mailto:)?([\\w\\.\\_]+)@(\\w+)\\.(\\w+)\\.?(\\w+)?/g,\n        emoji         : /:([\\w\\+-]+):/g,\n        emojiDatetime : /(\\d{2}:\\d{2}:\\d{2})/g,\n        twemoji       : /:(tw-([\\w]+)-?(\\w+)?):/g,\n        fontAwesome   : /:(fa-([\\w]+)(-(\\w+)){0,}):/g,\n        editormdLogo  : /:(editormd-logo-?(\\w+)?):/g,\n        pageBreak     : /^\\[[=]{8,}\\]$/\n    };\n\n    // Emoji graphics files url path\n    editormd.emoji     = {\n        path  : \"http://www.emoji-cheat-sheet.com/graphics/emojis/\",\n        ext   : \".png\"\n    };\n\n    // Twitter Emoji (Twemoji)  graphics files url path    \n    editormd.twemoji = {\n        path : \"http://twemoji.maxcdn.com/36x36/\",\n        ext  : \".png\"\n    };\n\n    /**\n     * 自定义marked的解析器\n     * Custom Marked renderer rules\n     * \n     * @param   {Array}    markdownToC     传入用于接收TOC的数组\n     * @returns {Renderer} markedRenderer  返回marked的Renderer自定义对象\n     */\n\n    editormd.markedRenderer = function(markdownToC, options) {\n        var defaults = {\n            toc                  : true,           // Table of contents\n            tocm                 : false,\n            tocStartLevel        : 1,              // Said from H1 to create ToC  \n            pageBreak            : true,\n            atLink               : true,           // for @link\n            emailLink            : true,           // for mail address auto link\n            taskList             : false,          // Enable Github Flavored Markdown task lists\n            emoji                : false,          // :emoji: , Support Twemoji, fontAwesome, Editor.md logo emojis.\n            tex                  : false,          // TeX(LaTeX), based on KaTeX\n            flowChart            : false,          // flowChart.js only support IE9+\n            sequenceDiagram      : false,          // sequenceDiagram.js only support IE9+\n        };\n        \n        var settings        = $.extend(defaults, options || {});    \n        var marked          = editormd.$marked;\n        var markedRenderer  = new marked.Renderer();\n        markdownToC         = markdownToC || [];        \n            \n        var regexs          = editormd.regexs;\n        var atLinkReg       = regexs.atLink;\n        var emojiReg        = regexs.emoji;\n        var emailReg        = regexs.email;\n        var emailLinkReg    = regexs.emailLink;\n        var twemojiReg      = regexs.twemoji;\n        var faIconReg       = regexs.fontAwesome;\n        var editormdLogoReg = regexs.editormdLogo;\n        var pageBreakReg    = regexs.pageBreak;\n\n        markedRenderer.emoji = function(text) {\n            \n            text = text.replace(editormd.regexs.emojiDatetime, function($1) {           \n                return $1.replace(/:/g, \"&#58;\");\n            });\n            \n            var matchs = text.match(emojiReg);\n\n            if (!matchs || !settings.emoji) {\n                return text;\n            }\n\n            for (var i = 0, len = matchs.length; i < len; i++)\n            {            \n                if (matchs[i] === \":+1:\") {\n                    matchs[i] = \":\\\\+1:\";\n                }\n\n                text = text.replace(new RegExp(matchs[i]), function($1, $2){\n                    var faMatchs = $1.match(faIconReg);\n                    var name     = $1.replace(/:/g, \"\");\n\n                    if (faMatchs)\n                    {                        \n                        for (var fa = 0, len1 = faMatchs.length; fa < len1; fa++)\n                        {\n                            var faName = faMatchs[fa].replace(/:/g, \"\");\n                            \n                            return \"<i class=\\\"fa \" + faName + \" fa-emoji\\\" title=\\\"\" + faName.replace(\"fa-\", \"\") + \"\\\"></i>\";\n                        }\n                    }\n                    else\n                    {\n                        var emdlogoMathcs = $1.match(editormdLogoReg);\n                        var twemojiMatchs = $1.match(twemojiReg);\n\n                        if (emdlogoMathcs)                                        \n                        {                            \n                            for (var x = 0, len2 = emdlogoMathcs.length; x < len2; x++)\n                            {\n                                var logoName = emdlogoMathcs[x].replace(/:/g, \"\");\n                                return \"<i class=\\\"\" + logoName + \"\\\" title=\\\"Editor.md logo (\" + logoName + \")\\\"></i>\";\n                            }\n                        }\n                        else if (twemojiMatchs) \n                        {\n                            for (var t = 0, len3 = twemojiMatchs.length; t < len3; t++)\n                            {\n                                var twe = twemojiMatchs[t].replace(/:/g, \"\").replace(\"tw-\", \"\");\n                                return \"<img src=\\\"\" + editormd.twemoji.path + twe + editormd.twemoji.ext + \"\\\" title=\\\"twemoji-\" + twe + \"\\\" alt=\\\"twemoji-\" + twe + \"\\\" class=\\\"emoji twemoji\\\" />\";\n                            }\n                        }\n                        else\n                        {\n                            var src = (name === \"+1\") ? \"plus1\" : name;\n                            src     = (src === \"black_large_square\") ? \"black_square\" : src;\n                            src     = (src === \"moon\") ? \"waxing_gibbous_moon\" : src;\n\n                            return \"<img src=\\\"\" + editormd.emoji.path + src + editormd.emoji.ext + \"\\\" class=\\\"emoji\\\" title=\\\"&#58;\" + name + \"&#58;\\\" alt=\\\"&#58;\" + name + \"&#58;\\\" />\";\n                        }\n                    }\n                });\n            }\n\n            return text;\n        };\n\n        markedRenderer.atLink = function(text) {\n\n            if (atLinkReg.test(text))\n            { \n                if (settings.atLink) \n                {\n                    text = text.replace(emailReg, function($1, $2, $3, $4) {\n                        return $1.replace(/@/g, \"_#_&#64;_#_\");\n                    });\n\n                    text = text.replace(atLinkReg, function($1, $2) {\n                        return \"<a href=\\\"\" + editormd.urls.atLinkBase + \"\" + $2 + \"\\\" title=\\\"&#64;\" + $2 + \"\\\" class=\\\"at-link\\\">\" + $1 + \"</a>\";\n                    }).replace(/_#_&#64;_#_/g, \"@\");\n                }\n                \n                if (settings.emailLink)\n                {\n                    text = text.replace(emailLinkReg, function($1, $2, $3, $4, $5) {\n                        return (!$2 && $.inArray($5, \"jpg|jpeg|png|gif|webp|ico|icon|pdf\".split(\"|\")) < 0) ? \"<a href=\\\"mailto:\" + $1 + \"\\\">\"+$1+\"</a>\" : $1;\n                    });\n                }\n\n                return text;\n            }\n\n            return text;\n        };\n                \n        markedRenderer.link = function (href, title, text) {\n\n            if (this.options.sanitize) {\n                try {\n                    var prot = decodeURIComponent(unescape(href)).replace(/[^\\w:]/g,\"\").toLowerCase();\n                } catch(e) {\n                    return \"\";\n                }\n\n                if (prot.indexOf(\"javascript:\") === 0) {\n                    return \"\";\n                }\n            }\n\n            var out = \"<a href=\\\"\" + href + \"\\\"\";\n            \n            if (atLinkReg.test(title) || atLinkReg.test(text))\n            {\n                if (title)\n                {\n                    out += \" title=\\\"\" + title.replace(/@/g, \"&#64;\");\n                }\n                \n                return out + \"\\\">\" + text.replace(/@/g, \"&#64;\") + \"</a>\";\n            }\n\n            if (title) {\n                out += \" title=\\\"\" + title + \"\\\"\";\n            }\n\n            out += \">\" + text + \"</a>\";\n\n            return out;\n        };\n        \n        markedRenderer.heading = function(text, level, raw) {\n                    \n            var linkText       = text;\n            var hasLinkReg     = /\\s*\\<a\\s*href\\=\\\"(.*)\\\"\\s*([^\\>]*)\\>(.*)\\<\\/a\\>\\s*/;\n            var getLinkTextReg = /\\s*\\<a\\s*([^\\>]+)\\>([^\\>]*)\\<\\/a\\>\\s*/g;\n\n            if (hasLinkReg.test(text)) \n            {\n                var tempText = [];\n                text         = text.split(/\\<a\\s*([^\\>]+)\\>([^\\>]*)\\<\\/a\\>/);\n\n                for (var i = 0, len = text.length; i < len; i++)\n                {\n                    tempText.push(text[i].replace(/\\s*href\\=\\\"(.*)\\\"\\s*/g, \"\"));\n                }\n\n                text = tempText.join(\" \");\n            }\n            \n            text = trim(text);\n            \n            var escapedText    = text.toLowerCase().replace(/[^\\w]+/g, \"-\");\n            var toc = {\n                text  : text,\n                level : level,\n                slug  : escapedText\n            };\n            \n            var isChinese = /^[\\u4e00-\\u9fa5]+$/.test(text);\n            var id        = (isChinese) ? escape(text).replace(/\\%/g, \"\") : text.toLowerCase().replace(/[^\\w]+/g, \"-\");\n\n            markdownToC.push(toc);\n            \n            var headingHTML = \"<h\" + level + \" id=\\\"h\"+ level + \"-\" + this.options.headerPrefix + id +\"\\\">\";\n            \n            headingHTML    += \"<a name=\\\"\" + text + \"\\\" class=\\\"reference-link\\\"></a>\";\n            headingHTML    += \"<span class=\\\"header-link octicon octicon-link\\\"></span>\";\n            headingHTML    += (hasLinkReg) ? this.atLink(this.emoji(linkText)) : this.atLink(this.emoji(text));\n            headingHTML    += \"</h\" + level + \">\";\n\n            return headingHTML;\n        };\n        \n        markedRenderer.pageBreak = function(text) {\n            if (pageBreakReg.test(text) && settings.pageBreak)\n            {\n                text = \"<hr style=\\\"page-break-after:always;\\\" class=\\\"page-break editormd-page-break\\\" />\";\n            }\n            \n            return text;\n        };\n\n        markedRenderer.paragraph = function(text) {\n            var isTeXInline     = /\\$\\$(.*)\\$\\$/g.test(text);\n            var isTeXLine       = /^\\$\\$(.*)\\$\\$$/.test(text);\n            var isTeXAddClass   = (isTeXLine)     ? \" class=\\\"\" + editormd.classNames.tex + \"\\\"\" : \"\";\n            var isToC           = (settings.tocm) ? /^(\\[TOC\\]|\\[TOCM\\])$/.test(text) : /^\\[TOC\\]$/.test(text);\n            var isToCMenu       = /^\\[TOCM\\]$/.test(text);\n            \n            if (!isTeXLine && isTeXInline) \n            {\n                text = text.replace(/(\\$\\$([^\\$]*)\\$\\$)+/g, function($1, $2) {\n                    return \"<span class=\\\"\" + editormd.classNames.tex + \"\\\">\" + $2.replace(/\\$/g, \"\") + \"</span>\";\n                });\n            } \n            else \n            {\n                text = (isTeXLine) ? text.replace(/\\$/g, \"\") : text;\n            }\n            \n            var tocHTML = \"<div class=\\\"markdown-toc editormd-markdown-toc\\\">\" + text + \"</div>\";\n            \n            return (isToC) ? ( (isToCMenu) ? \"<div class=\\\"editormd-toc-menu\\\">\" + tocHTML + \"</div><br/>\" : tocHTML )\n                           : ( (pageBreakReg.test(text)) ? this.pageBreak(text) : \"<p\" + isTeXAddClass + \">\" + this.atLink(this.emoji(text)) + \"</p>\\n\" );\n        };\n\n        markedRenderer.code = function (code, lang, escaped) { \n\n            if (lang === \"seq\" || lang === \"sequence\")\n            {\n                return \"<div class=\\\"sequence-diagram\\\">\" + code + \"</div>\";\n            } \n            else if ( lang === \"flow\")\n            {\n                return \"<div class=\\\"flowchart\\\">\" + code + \"</div>\";\n            } \n            else if ( lang === \"math\" || lang === \"latex\" || lang === \"katex\")\n            {\n                return \"<p class=\\\"\" + editormd.classNames.tex + \"\\\">\" + code + \"</p>\";\n            } \n            else \n            {\n\n                return marked.Renderer.prototype.code.apply(this, arguments);\n            }\n        };\n\n        markedRenderer.tablecell = function(content, flags) {\n            var type = (flags.header) ? \"th\" : \"td\";\n            var tag  = (flags.align)  ? \"<\" + type +\" style=\\\"text-align:\" + flags.align + \"\\\">\" : \"<\" + type + \">\";\n            \n            return tag + this.atLink(this.emoji(content)) + \"</\" + type + \">\\n\";\n        };\n\n        markedRenderer.listitem = function(text) {\n            if (settings.taskList && /^\\s*\\[[x\\s]\\]\\s*/.test(text)) \n            {\n                text = text.replace(/^\\s*\\[\\s\\]\\s*/, \"<input type=\\\"checkbox\\\" class=\\\"task-list-item-checkbox\\\" /> \")\n                           .replace(/^\\s*\\[x\\]\\s*/,  \"<input type=\\\"checkbox\\\" class=\\\"task-list-item-checkbox\\\" checked disabled /> \");\n\n                return \"<li style=\\\"list-style: none;\\\">\" + this.atLink(this.emoji(text)) + \"</li>\";\n            }\n            else \n            {\n                return \"<li>\" + this.atLink(this.emoji(text)) + \"</li>\";\n            }\n        };\n        \n        return markedRenderer;\n    };\n    \n    /**\n     *\n     * 生成TOC(Table of Contents)\n     * Creating ToC (Table of Contents)\n     * \n     * @param   {Array}    toc             从marked获取的TOC数组列表\n     * @param   {Element}  container       插入TOC的容器元素\n     * @param   {Integer}  startLevel      Hx 起始层级\n     * @returns {Object}   tocContainer    返回ToC列表容器层的jQuery对象元素\n     */\n    \n    editormd.markdownToCRenderer = function(toc, container, tocDropdown, startLevel) {\n        \n        var html        = \"\";    \n        var lastLevel   = 0;\n        var classPrefix = this.classPrefix;\n        \n        startLevel      = startLevel  || 1;\n        \n        for (var i = 0, len = toc.length; i < len; i++) \n        {\n            var text  = toc[i].text;\n            var level = toc[i].level;\n            \n            if (level < startLevel) {\n                continue;\n            }\n            \n            if (level > lastLevel) \n            {\n                html += \"\";\n            }\n            else if (level < lastLevel) \n            {\n                html += (new Array(lastLevel - level + 2)).join(\"</ul></li>\");\n            } \n            else \n            {\n                html += \"</ul></li>\";\n            }\n\n            html += \"<li><a class=\\\"toc-level-\" + level + \"\\\" href=\\\"#\" + text + \"\\\" level=\\\"\" + level + \"\\\">\" + text + \"</a><ul>\";\n            lastLevel = level;\n        }\n        \n        var tocContainer = container.find(\".markdown-toc\");\n        \n        if ((tocContainer.length < 1 && container.attr(\"previewContainer\") === \"false\"))\n        {\n            var tocHTML = \"<div class=\\\"markdown-toc \" + classPrefix + \"markdown-toc\\\"></div>\";\n            \n            tocHTML = (tocDropdown) ? \"<div class=\\\"\" + classPrefix + \"toc-menu\\\">\" + tocHTML + \"</div>\" : tocHTML;\n            \n            container.html(tocHTML);\n            \n            tocContainer = container.find(\".markdown-toc\");\n        }\n        \n        if (tocDropdown)\n        {\n            tocContainer.wrap(\"<div class=\\\"\" + classPrefix + \"toc-menu\\\"></div><br/>\");\n        }\n        \n        tocContainer.html(\"<ul class=\\\"markdown-toc-list\\\"></ul>\").children(\".markdown-toc-list\").html(html.replace(/\\r?\\n?\\<ul\\>\\<\\/ul\\>/g, \"\"));\n        \n        return tocContainer;\n    };\n    \n    /**\n     *\n     * 生成TOC下拉菜单\n     * Creating ToC dropdown menu\n     * \n     * @param   {Object}   container       插入TOC的容器jQuery对象元素\n     * @param   {String}   tocTitle        ToC title\n     * @returns {Object}                   return toc-menu object\n     */\n    \n    editormd.tocDropdownMenu = function(container, tocTitle) {\n        \n        tocTitle      = tocTitle || \"Table of Contents\";\n        \n        var zindex    = 400;\n        var tocMenus  = container.find(\".\" + this.classPrefix + \"toc-menu\");\n\n        tocMenus.each(function() {\n            var $this  = $(this);\n            var toc    = $this.children(\".markdown-toc\");\n            var icon   = \"<i class=\\\"fa fa-angle-down\\\"></i>\";\n            var btn    = \"<a href=\\\"javascript:;\\\" class=\\\"toc-menu-btn\\\">\" + icon + tocTitle + \"</a>\";\n            var menu   = toc.children(\"ul\");            \n            var list   = menu.find(\"li\");\n            \n            toc.append(btn);\n            \n            list.first().before(\"<li><h1>\" + tocTitle + \" \" + icon + \"</h1></li>\");\n            \n            $this.mouseover(function(){\n                menu.show();\n\n                list.each(function(){\n                    var li = $(this);\n                    var ul = li.children(\"ul\");\n\n                    if (ul.html() === \"\")\n                    {\n                        ul.remove();\n                    }\n\n                    if (ul.length > 0 && ul.html() !== \"\")\n                    {\n                        var firstA = li.children(\"a\").first();\n\n                        if (firstA.children(\".fa\").length < 1)\n                        {\n                            firstA.append( $(icon).css({ float:\"right\", paddingTop:\"4px\" }) );\n                        }\n                    }\n\n                    li.mouseover(function(){\n                        ul.css(\"z-index\", zindex).show();\n                        zindex += 1;\n                    }).mouseleave(function(){\n                        ul.hide();\n                    });\n                });\n            }).mouseleave(function(){\n                menu.hide();\n            }); \n        });       \n        \n        return tocMenus;\n    };\n    \n    /**\n     * 简单地过滤指定的HTML标签\n     * Filter custom html tags\n     * \n     * @param   {String}   html          要过滤HTML\n     * @param   {String}   filters       要过滤的标签\n     * @returns {String}   html          返回过滤的HTML\n     */\n    \n    editormd.filterHTMLTags = function(html, filters) {\n        \n        if (typeof html !== \"string\") {\n            html = new String(html);\n        }\n            \n        if (typeof filters !== \"string\") {\n            return html;\n        }\n\n        var expression = filters.split(\"|\");\n        var filterTags = expression[0].split(\",\");\n        var attrs      = expression[1];\n\n        for (var i = 0, len = filterTags.length; i < len; i++)\n        {\n            var tag = filterTags[i];\n\n            html = html.replace(new RegExp(\"\\<\\s*\" + tag + \"\\s*([^\\>]*)\\>([^\\>]*)\\<\\s*\\/\" + tag + \"\\s*\\>\", \"igm\"), \"\");\n        }\n        \n        //return html;\n\n        if (typeof attrs !== \"undefined\")\n        {\n            var htmlTagRegex = /\\<(\\w+)\\s*([^\\>]*)\\>([^\\>]*)\\<\\/(\\w+)\\>/ig;\n\n            if (attrs === \"*\")\n            {\n                html = html.replace(htmlTagRegex, function($1, $2, $3, $4, $5) {\n                    return \"<\" + $2 + \">\" + $4 + \"</\" + $5 + \">\";\n                });         \n            }\n            else if (attrs === \"on*\")\n            {\n                html = html.replace(htmlTagRegex, function($1, $2, $3, $4, $5) {\n                    var el = $(\"<\" + $2 + \">\" + $4 + \"</\" + $5 + \">\");\n                    var _attrs = $($1)[0].attributes;\n                    var $attrs = {};\n                    \n                    $.each(_attrs, function(i, e) {\n                        if (e.nodeName !== '\"') $attrs[e.nodeName] = e.nodeValue;\n                    });\n                    \n                    $.each($attrs, function(i) {                        \n                        if (i.indexOf(\"on\") === 0) {\n                            delete $attrs[i];\n                        }\n                    });\n                    \n                    el.attr($attrs);\n                    \n                    var text = (typeof el[1] !== \"undefined\") ? $(el[1]).text() : \"\";\n\n                    return el[0].outerHTML + text;\n                });\n            }\n            else\n            {\n                html = html.replace(htmlTagRegex, function($1, $2, $3, $4) {\n                    var filterAttrs = attrs.split(\",\");\n                    var el = $($1);\n                    el.html($4);\n\n                    $.each(filterAttrs, function(i) {\n                        el.attr(filterAttrs[i], null);\n                    });\n\n                    return el[0].outerHTML;\n                });\n            }\n        }\n        \n        return html;\n    };\n    \n    /**\n     * 将Markdown文档解析为HTML用于前台显示\n     * Parse Markdown to HTML for Font-end preview.\n     * \n     * @param   {String}   id            用于显示HTML的对象ID\n     * @param   {Object}   [options={}]  配置选项，可选\n     * @returns {Object}   div           返回jQuery对象元素\n     */\n    \n    editormd.markdownToHTML = function(id, options) {\n        var defaults = {\n            gfm                  : true,\n            toc                  : true,\n            tocm                 : false,\n            tocStartLevel        : 1,\n            tocTitle             : \"目录\",\n            tocDropdown          : false,\n            tocContainer         : \"\",\n            markdown             : \"\",\n            markdownSourceCode   : false,\n            htmlDecode           : false,\n            autoLoadKaTeX        : true,\n            pageBreak            : true,\n            atLink               : true,    // for @link\n            emailLink            : true,    // for mail address auto link\n            tex                  : false,\n            taskList             : false,   // Github Flavored Markdown task lists\n            emoji                : false,\n            flowChart            : false,\n            sequenceDiagram      : false,\n            previewCodeHighlight : true\n        };\n        \n        editormd.$marked  = marked;\n\n        var div           = $(\"#\" + id);\n        var settings      = div.settings = $.extend(true, defaults, options || {});\n        var saveTo        = div.find(\"textarea\");\n        \n        if (saveTo.length < 1)\n        {\n            div.append(\"<textarea></textarea>\");\n            saveTo        = div.find(\"textarea\");\n        }        \n        \n        var markdownDoc   = (settings.markdown === \"\") ? saveTo.val() : settings.markdown; \n        var markdownToC   = [];\n\n        var rendererOptions = {  \n            toc                  : settings.toc,\n            tocm                 : settings.tocm,\n            tocStartLevel        : settings.tocStartLevel,\n            taskList             : settings.taskList,\n            emoji                : settings.emoji,\n            tex                  : settings.tex,\n            pageBreak            : settings.pageBreak,\n            atLink               : settings.atLink,           // for @link\n            emailLink            : settings.emailLink,        // for mail address auto link\n            flowChart            : settings.flowChart,\n            sequenceDiagram      : settings.sequenceDiagram,\n            previewCodeHighlight : settings.previewCodeHighlight,\n        };\n\n        var markedOptions = {\n            renderer    : editormd.markedRenderer(markdownToC, rendererOptions),\n            gfm         : settings.gfm,\n            tables      : true,\n            breaks      : true,\n            pedantic    : false,\n            sanitize    : (settings.htmlDecode) ? false : true, // 是否忽略HTML标签，即是否开启HTML标签解析，为了安全性，默认不开启\n            smartLists  : true,\n            smartypants : true\n        };\n        \n\t\tmarkdownDoc = new String(markdownDoc);\n        \n        var markdownParsed = marked(markdownDoc, markedOptions);\n        \n        markdownParsed = editormd.filterHTMLTags(markdownParsed, settings.htmlDecode);\n        \n        if (settings.markdownSourceCode) {\n            saveTo.text(markdownDoc);\n        } else {\n            saveTo.remove();\n        }\n        \n        div.addClass(\"markdown-body \" + this.classPrefix + \"html-preview\").append(markdownParsed);\n        \n        var tocContainer = (settings.tocContainer !== \"\") ? $(settings.tocContainer) : div;\n        \n        if (settings.tocContainer !== \"\")\n        {\n            tocContainer.attr(\"previewContainer\", false);\n        }\n         \n        if (settings.toc) \n        {\n            div.tocContainer = this.markdownToCRenderer(markdownToC, tocContainer, settings.tocDropdown, settings.tocStartLevel);\n            \n            if (settings.tocDropdown || div.find(\".\" + this.classPrefix + \"toc-menu\").length > 0)\n            {\n                this.tocDropdownMenu(div, settings.tocTitle);\n            }\n            \n            if (settings.tocContainer !== \"\")\n            {\n                div.find(\".editormd-toc-menu, .editormd-markdown-toc\").remove();\n            }\n        }\n            \n        if (settings.previewCodeHighlight) \n        {\n            div.find(\"pre\").addClass(\"prettyprint linenums\");\n            prettyPrint();\n        }\n        \n        if (!editormd.isIE8) \n        {\n            if (settings.flowChart) {\n                div.find(\".flowchart\").flowChart(); \n            }\n\n            if (settings.sequenceDiagram) {\n                div.find(\".sequence-diagram\").sequenceDiagram({theme: \"simple\"});\n            }\n        }\n\n        if (settings.tex)\n        {\n            var katexHandle = function() {\n                div.find(\".\" + editormd.classNames.tex).each(function(){\n                    var tex  = $(this);                    \n                    katex.render(tex.html().replace(/&lt;/g, \"<\").replace(/&gt;/g, \">\"), tex[0]);                    \n                    tex.find(\".katex\").css(\"font-size\", \"1.6em\");\n                });\n            };\n            \n            if (settings.autoLoadKaTeX && !editormd.$katex && !editormd.kaTeXLoaded)\n            {\n                this.loadKaTeX(function() {\n                    editormd.$katex      = katex;\n                    editormd.kaTeXLoaded = true;\n                    katexHandle();\n                });\n            }\n            else\n            {\n                katexHandle();\n            }\n        }\n        \n        div.getMarkdown = function() {            \n            return saveTo.val();\n        };\n        \n        return div;\n    };\n    \n    // Editor.md themes, change toolbar themes etc.\n    // added @1.5.0\n    editormd.themes        = [\"default\", \"dark\"];\n    \n    // Preview area themes\n    // added @1.5.0\n    editormd.previewThemes = [\"default\", \"dark\"];\n    \n    // CodeMirror / editor area themes\n    // @1.5.0 rename -> editorThemes, old version -> themes\n    editormd.editorThemes = [\n        \"default\", \"3024-day\", \"3024-night\",\n        \"ambiance\", \"ambiance-mobile\",\n        \"base16-dark\", \"base16-light\", \"blackboard\",\n        \"cobalt\",\n        \"eclipse\", \"elegant\", \"erlang-dark\",\n        \"lesser-dark\",\n        \"mbo\", \"mdn-like\", \"midnight\", \"monokai\",\n        \"neat\", \"neo\", \"night\",\n        \"paraiso-dark\", \"paraiso-light\", \"pastel-on-dark\",\n        \"rubyblue\",\n        \"solarized\",\n        \"the-matrix\", \"tomorrow-night-eighties\", \"twilight\",\n        \"vibrant-ink\",\n        \"xq-dark\", \"xq-light\"\n    ];\n\n    editormd.loadPlugins = {};\n    \n    editormd.loadFiles = {\n        js     : [],\n        css    : [],\n        plugin : []\n    };\n    \n    /**\n     * 动态加载Editor.md插件，但不立即执行\n     * Load editor.md plugins\n     * \n     * @param {String}   fileName              插件文件路径\n     * @param {Function} [callback=function()] 加载成功后执行的回调函数\n     * @param {String}   [into=\"head\"]         嵌入页面的位置\n     */\n    \n    editormd.loadPlugin = function(fileName, callback, into) {\n        callback   = callback || function() {};\n        \n        this.loadScript(fileName, function() {\n            editormd.loadFiles.plugin.push(fileName);\n            callback();\n        }, into);\n    };\n    \n    /**\n     * 动态加载CSS文件的方法\n     * Load css file method\n     * \n     * @param {String}   fileName              CSS文件名\n     * @param {Function} [callback=function()] 加载成功后执行的回调函数\n     * @param {String}   [into=\"head\"]         嵌入页面的位置\n     */\n    \n    editormd.loadCSS   = function(fileName, callback, into) {\n        into       = into     || \"head\";        \n        callback   = callback || function() {};\n        \n        var css    = document.createElement(\"link\");\n        css.type   = \"text/css\";\n        css.rel    = \"stylesheet\";\n        css.onload = css.onreadystatechange = function() {\n            editormd.loadFiles.css.push(fileName);\n            callback();\n        };\n\n        css.href   = fileName + \".css\";\n\n        if(into === \"head\") {\n            document.getElementsByTagName(\"head\")[0].appendChild(css);\n        } else {\n            document.body.appendChild(css);\n        }\n    };\n    \n    editormd.isIE    = (navigator.appName == \"Microsoft Internet Explorer\");\n    editormd.isIE8   = (editormd.isIE && navigator.appVersion.match(/8./i) == \"8.\");\n\n    /**\n     * 动态加载JS文件的方法\n     * Load javascript file method\n     * \n     * @param {String}   fileName              JS文件名\n     * @param {Function} [callback=function()] 加载成功后执行的回调函数\n     * @param {String}   [into=\"head\"]         嵌入页面的位置\n     */\n\n    editormd.loadScript = function(fileName, callback, into) {\n        \n        into          = into     || \"head\";\n        callback      = callback || function() {};\n        \n        var script    = null; \n        script        = document.createElement(\"script\");\n        script.id     = fileName.replace(/[\\./]+/g, \"-\");\n        script.type   = \"text/javascript\";        \n        script.src    = fileName + \".js\";\n        \n        if (editormd.isIE8) \n        {            \n            script.onreadystatechange = function() {\n                if(script.readyState) \n                {\n                    if (script.readyState === \"loaded\" || script.readyState === \"complete\") \n                    {\n                        script.onreadystatechange = null; \n                        editormd.loadFiles.js.push(fileName);\n                        callback();\n                    }\n                } \n            };\n        }\n        else\n        {\n            script.onload = function() {\n                editormd.loadFiles.js.push(fileName);\n                callback();\n            };\n        }\n\n        if (into === \"head\") {\n            document.getElementsByTagName(\"head\")[0].appendChild(script);\n        } else {\n            document.body.appendChild(script);\n        }\n    };\n    \n    // 使用国外的CDN，加载速度有时会很慢，或者自定义URL\n    // You can custom KaTeX load url.\n    editormd.katexURL  = {\n        css : \"//cdnjs.cloudflare.com/ajax/libs/KaTeX/0.3.0/katex.min\",\n        js  : \"//cdnjs.cloudflare.com/ajax/libs/KaTeX/0.3.0/katex.min\"\n    };\n    \n    editormd.kaTeXLoaded = false;\n    \n    /**\n     * 加载KaTeX文件\n     * load KaTeX files\n     * \n     * @param {Function} [callback=function()]  加载成功后执行的回调函数\n     */\n    \n    editormd.loadKaTeX = function (callback) {\n        editormd.loadCSS(editormd.katexURL.css, function(){\n            editormd.loadScript(editormd.katexURL.js, callback || function(){});\n        });\n    };\n        \n    /**\n     * 锁屏\n     * lock screen\n     * \n     * @param   {Boolean}   lock   Boolean 布尔值，是否锁屏\n     * @returns {void}\n     */\n    \n    editormd.lockScreen = function(lock) {\n        $(\"html,body\").css(\"overflow\", (lock) ? \"hidden\" : \"\");\n    };\n        \n    /**\n     * 动态创建对话框\n     * Creating custom dialogs\n     * \n     * @param   {Object} options 配置项键值对 Key/Value\n     * @returns {dialog} 返回创建的dialog的jQuery实例对象\n     */\n\n    editormd.createDialog = function(options) {\n        var defaults = {\n            name : \"\",\n            width : 420,\n            height: 240,\n            title : \"\",\n            drag  : true,\n            closed : true,\n            content : \"\",\n            mask : true,\n            maskStyle : {\n                backgroundColor : \"#fff\",\n                opacity : 0.1\n            },\n            lockScreen : true,\n            footer : true,\n            buttons : false\n        };\n\n        options          = $.extend(true, defaults, options);\n        \n        var $this        = this;\n        var editor       = this.editor;\n        var classPrefix  = editormd.classPrefix;\n        var guid         = (new Date()).getTime();\n        var dialogName   = ( (options.name === \"\") ? classPrefix + \"dialog-\" + guid : options.name);\n        var mouseOrTouch = editormd.mouseOrTouch;\n\n        var html         = \"<div class=\\\"\" + classPrefix + \"dialog \" + dialogName + \"\\\">\";\n\n        if (options.title !== \"\")\n        {\n            html += \"<div class=\\\"\" + classPrefix + \"dialog-header\\\"\" + ( (options.drag) ? \" style=\\\"cursor: move;\\\"\" : \"\" ) + \">\";\n            html += \"<strong class=\\\"\" + classPrefix + \"dialog-title\\\">\" + options.title + \"</strong>\";\n            html += \"</div>\";\n        }\n\n        if (options.closed)\n        {\n            html += \"<a href=\\\"javascript:;\\\" class=\\\"fa fa-close \" + classPrefix + \"dialog-close\\\"></a>\";\n        }\n\n        html += \"<div class=\\\"\" + classPrefix + \"dialog-container\\\">\" + options.content;                    \n\n        if (options.footer || typeof options.footer === \"string\") \n        {\n            html += \"<div class=\\\"\" + classPrefix + \"dialog-footer\\\">\" + ( (typeof options.footer === \"boolean\") ? \"\" : options.footer) + \"</div>\";\n        }\n\n        html += \"</div>\";\n\n        html += \"<div class=\\\"\" + classPrefix + \"dialog-mask \" + classPrefix + \"dialog-mask-bg\\\"></div>\";\n        html += \"<div class=\\\"\" + classPrefix + \"dialog-mask \" + classPrefix + \"dialog-mask-con\\\"></div>\";\n        html += \"</div>\";\n\n        editor.append(html);\n\n        var dialog = editor.find(\".\" + dialogName);\n\n        dialog.lockScreen = function(lock) {\n            if (options.lockScreen)\n            {                \n                $(\"html,body\").css(\"overflow\", (lock) ? \"hidden\" : \"\");\n                $this.resize();\n            }\n\n            return dialog;\n        };\n\n        dialog.showMask = function() {\n            if (options.mask)\n            {\n                editor.find(\".\" + classPrefix + \"mask\").css(options.maskStyle).css(\"z-index\", editormd.dialogZindex - 1).show();\n            }\n            return dialog;\n        };\n\n        dialog.hideMask = function() {\n            if (options.mask)\n            {\n                editor.find(\".\" + classPrefix + \"mask\").hide();\n            }\n\n            return dialog;\n        };\n\n        dialog.loading = function(show) {                        \n            var loading = dialog.find(\".\" + classPrefix + \"dialog-mask\");\n            loading[(show) ? \"show\" : \"hide\"]();\n\n            return dialog;\n        };\n\n        dialog.lockScreen(true).showMask();\n\n        dialog.show().css({\n            zIndex : editormd.dialogZindex,\n            border : (editormd.isIE8) ? \"1px solid #ddd\" : \"\",\n            width  : (typeof options.width  === \"number\") ? options.width + \"px\"  : options.width,\n            height : (typeof options.height === \"number\") ? options.height + \"px\" : options.height\n        });\n\n        var dialogPosition = function(){\n            dialog.css({\n                top    : ($(window).height() - dialog.height()) / 2 + \"px\",\n                left   : ($(window).width() - dialog.width()) / 2 + \"px\"\n            });\n        };\n\n        dialogPosition();\n\n        $(window).resize(dialogPosition);\n\n        dialog.children(\".\" + classPrefix + \"dialog-close\").bind(mouseOrTouch(\"click\", \"touchend\"), function() {\n            dialog.hide().lockScreen(false).hideMask();\n        });\n\n        if (typeof options.buttons === \"object\")\n        {\n            var footer = dialog.footer = dialog.find(\".\" + classPrefix + \"dialog-footer\");\n\n            for (var key in options.buttons)\n            {\n                var btn = options.buttons[key];\n                var btnClassName = classPrefix + key + \"-btn\";\n\n                footer.append(\"<button class=\\\"\" + classPrefix + \"btn \" + btnClassName + \"\\\">\" + btn[0] + \"</button>\");\n                btn[1] = $.proxy(btn[1], dialog);\n                footer.children(\".\" + btnClassName).bind(mouseOrTouch(\"click\", \"touchend\"), btn[1]);\n            }\n        }\n\n        if (options.title !== \"\" && options.drag)\n        {                        \n            var posX, posY;\n            var dialogHeader = dialog.children(\".\" + classPrefix + \"dialog-header\");\n\n            if (!options.mask) {\n                dialogHeader.bind(mouseOrTouch(\"click\", \"touchend\"), function(){\n                    editormd.dialogZindex += 2;\n                    dialog.css(\"z-index\", editormd.dialogZindex);\n                });\n            }\n\n            dialogHeader.mousedown(function(e) {\n                e = e || window.event;  //IE\n                posX = e.clientX - parseInt(dialog[0].style.left);\n                posY = e.clientY - parseInt(dialog[0].style.top);\n\n                document.onmousemove = moveAction;                   \n            });\n\n            var userCanSelect = function (obj) {\n                obj.removeClass(classPrefix + \"user-unselect\").off(\"selectstart\");\n            };\n\n            var userUnselect = function (obj) {\n                obj.addClass(classPrefix + \"user-unselect\").on(\"selectstart\", function(event) { // selectstart for IE                        \n                    return false;\n                });\n            };\n\n            var moveAction = function (e) {\n                e = e || window.event;  //IE\n\n                var left, top, nowLeft = parseInt(dialog[0].style.left), nowTop = parseInt(dialog[0].style.top);\n\n                if( nowLeft >= 0 ) {\n                    if( nowLeft + dialog.width() <= $(window).width()) {\n                        left = e.clientX - posX;\n                    } else {\t\n                        left = $(window).width() - dialog.width();\n                        document.onmousemove = null;\n                    }\n                } else {\n                    left = 0;\n                    document.onmousemove = null;\n                }\n\n                if( nowTop >= 0 ) {\n                    top = e.clientY - posY;\n                } else {\n                    top = 0;\n                    document.onmousemove = null;\n                }\n\n\n                document.onselectstart = function() {\n                    return false;\n                };\n\n                userUnselect($(\"body\"));\n                userUnselect(dialog);\n                dialog[0].style.left = left + \"px\";\n                dialog[0].style.top  = top + \"px\";\n            };\n\n            document.onmouseup = function() {                            \n                userCanSelect($(\"body\"));\n                userCanSelect(dialog);\n\n                document.onselectstart = null;         \n                document.onmousemove = null;\n            };\n\n            dialogHeader.touchDraggable = function() {\n                var offset = null;\n                var start  = function(e) {\n                    var orig = e.originalEvent; \n                    var pos  = $(this).parent().position();\n\n                    offset = {\n                        x : orig.changedTouches[0].pageX - pos.left,\n                        y : orig.changedTouches[0].pageY - pos.top\n                    };\n                };\n\n                var move = function(e) {\n                    e.preventDefault();\n                    var orig = e.originalEvent;\n\n                    $(this).parent().css({\n                        top  : orig.changedTouches[0].pageY - offset.y,\n                        left : orig.changedTouches[0].pageX - offset.x\n                    });\n                };\n\n                this.bind(\"touchstart\", start).bind(\"touchmove\", move);\n            };\n\n            dialogHeader.touchDraggable();\n        }\n\n        editormd.dialogZindex += 2;\n\n        return dialog;\n    };\n    \n    /**\n     * 鼠标和触摸事件的判断/选择方法\n     * MouseEvent or TouchEvent type switch\n     * \n     * @param   {String} [mouseEventType=\"click\"]    供选择的鼠标事件\n     * @param   {String} [touchEventType=\"touchend\"] 供选择的触摸事件\n     * @returns {String} EventType                   返回事件类型名称\n     */\n    \n    editormd.mouseOrTouch = function(mouseEventType, touchEventType) {\n        mouseEventType = mouseEventType || \"click\";\n        touchEventType = touchEventType || \"touchend\";\n        \n        var eventType  = mouseEventType;\n\n        try {\n            document.createEvent(\"TouchEvent\");\n            eventType = touchEventType;\n        } catch(e) {}\n\n        return eventType;\n    };\n    \n    /**\n     * 日期时间的格式化方法\n     * Datetime format method\n     * \n     * @param   {String}   [format=\"\"]  日期时间的格式，类似PHP的格式\n     * @returns {String}   datefmt      返回格式化后的日期时间字符串\n     */\n    \n    editormd.dateFormat = function(format) {                \n        format      = format || \"\";\n\n        var addZero = function(d) {\n            return (d < 10) ? \"0\" + d : d;\n        };\n\n        var date    = new Date(); \n        var year    = date.getFullYear();\n        var year2   = year.toString().slice(2, 4);\n        var month   = addZero(date.getMonth() + 1);\n        var day     = addZero(date.getDate());\n        var weekDay = date.getDay();\n        var hour    = addZero(date.getHours());\n        var min     = addZero(date.getMinutes());\n        var second  = addZero(date.getSeconds());\n        var ms      = addZero(date.getMilliseconds()); \n        var datefmt = \"\";\n\n        var ymd     = year2 + \"-\" + month + \"-\" + day;\n        var fymd    = year  + \"-\" + month + \"-\" + day;\n        var hms     = hour  + \":\" + min   + \":\" + second;\n\n        switch (format) \n        {\n            case \"UNIX Time\" :\n                    datefmt = date.getTime();\n                break;\n\n            case \"UTC\" :\n                    datefmt = date.toUTCString();\n                break;\t\n\n            case \"yy\" :\n                    datefmt = year2;\n                break;\t\n\n            case \"year\" :\n            case \"yyyy\" :\n                    datefmt = year;\n                break;\n\n            case \"month\" :\n            case \"mm\" :\n                    datefmt = month;\n                break;                        \n\n            case \"cn-week-day\" :\n            case \"cn-wd\" :\n                    var cnWeekDays = [\"日\", \"一\", \"二\", \"三\", \"四\", \"五\", \"六\"];\n                    datefmt = \"星期\" + cnWeekDays[weekDay];\n                break;\n\n            case \"week-day\" :\n            case \"wd\" :\n                    var weekDays = [\"Sunday\", \"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\", \"Saturday\"];\n                    datefmt = weekDays[weekDay];\n                break;\n\n            case \"day\" :\n            case \"dd\" :\n                    datefmt = day;\n                break;\n\n            case \"hour\" :\n            case \"hh\" :\n                    datefmt = hour;\n                break;\n\n            case \"min\" :\n            case \"ii\" :\n                    datefmt = min;\n                break;\n\n            case \"second\" :\n            case \"ss\" :\n                    datefmt = second;\n                break;\n\n            case \"ms\" :\n                    datefmt = ms;\n                break;\n\n            case \"yy-mm-dd\" :\n                    datefmt = ymd;\n                break;\n\n            case \"yyyy-mm-dd\" :\n                    datefmt = fymd;\n                break;\n\n            case \"yyyy-mm-dd h:i:s ms\" :\n            case \"full + ms\" : \n                    datefmt = fymd + \" \" + hms + \" \" + ms;\n                break;\n\n            case \"full\" :\n            case \"yyyy-mm-dd h:i:s\" :\n                default:\n                    datefmt = fymd + \" \" + hms;\n                break;\n        }\n\n        return datefmt;\n    };\n\n    return editormd;\n\n}));\n"
  },
  {
    "path": "Public/editor.md/editormd.js",
    "content": "/*\n * Editor.md\n *\n * @file        editormd.js \n * @version     v1.5.0 \n * @description Open source online markdown editor.\n * @license     MIT License\n * @author      Pandao\n * {@link       https://github.com/pandao/editor.md}\n * @updateTime  2015-06-09\n */\n\n;(function(factory) {\n    \"use strict\";\n    \n\t// CommonJS/Node.js\n\tif (typeof require === \"function\" && typeof exports === \"object\" && typeof module === \"object\")\n    { \n        module.exports = factory;\n    }\n\telse if (typeof define === \"function\")  // AMD/CMD/Sea.js\n\t{\n        if (define.amd) // for Require.js\n        {\n            /* Require.js define replace */\n        } \n        else \n        {\n\t\t    define([\"jquery\"], factory);  // for Sea.js\n        }\n\t} \n\telse\n\t{ \n        window.editormd = factory();\n\t}\n    \n}(function() {    \n\n    /* Require.js assignment replace */\n    \n    \"use strict\";\n    \n    var $ = (typeof (jQuery) !== \"undefined\") ? jQuery : Zepto;\n\n\tif (typeof ($) === \"undefined\") {\n\t\treturn ;\n\t}\n    \n    /**\n     * editormd\n     * \n     * @param   {String} id           编辑器的ID\n     * @param   {Object} options      配置选项 Key/Value\n     * @returns {Object} editormd     返回editormd对象\n     */\n    \n    var editormd         = function (id, options) {\n        return new editormd.fn.init(id, options);\n    };\n    \n    editormd.title        = editormd.$name = \"Editor.md\";\n    editormd.version      = \"1.5.0\";\n    editormd.homePage     = \"https://pandao.github.io/editor.md/\";\n    editormd.classPrefix  = \"editormd-\";\n    \n    editormd.toolbarModes = {\n        full : [\n            \"undo\", \"redo\", \"|\", \n            \"bold\", \"del\", \"italic\", \"quote\", \"ucwords\", \"uppercase\", \"lowercase\", \"|\", \n            \"h1\", \"h2\", \"h3\", \"h4\", \"h5\", \"h6\", \"|\", \n            \"list-ul\", \"list-ol\", \"hr\", \"|\",\n            \"link\", \"reference-link\", \"image\", \"code\", \"preformatted-text\", \"code-block\", \"table\", \"datetime\", \"emoji\", \"html-entities\", \"pagebreak\", \"|\",\n            \"goto-line\", \"watch\", \"preview\", \"fullscreen\", \"clear\", \"search\", \"|\",\n            \"help\", \"info\"\n        ],\n        simple : [\n            \"undo\", \"redo\", \"|\", \n            \"bold\", \"del\", \"italic\", \"quote\", \"uppercase\", \"lowercase\", \"|\", \n            \"h1\", \"h2\", \"h3\", \"h4\", \"h5\", \"h6\", \"|\", \n            \"list-ul\", \"list-ol\", \"hr\", \"|\",\n            \"watch\", \"preview\", \"fullscreen\", \"|\",\n            \"help\", \"info\"\n        ],\n        mini : [\n            \"undo\", \"redo\", \"|\",\n            \"watch\", \"preview\", \"|\",\n            \"help\", \"info\"\n        ]\n    };\n    \n    editormd.defaults     = {\n        mode                 : \"gfm\",          //gfm or markdown\n        name                 : \"\",             // Form element name\n        value                : \"\",             // value for CodeMirror, if mode not gfm/markdown\n        theme                : \"\",             // Editor.md self themes, before v1.5.0 is CodeMirror theme, default empty\n        editorTheme          : \"default\",      // Editor area, this is CodeMirror theme at v1.5.0\n        previewTheme         : \"\",             // Preview area theme, default empty\n        markdown             : \"\",             // Markdown source code\n        appendMarkdown       : \"\",             // if in init textarea value not empty, append markdown to textarea\n        width                : \"100%\",\n        height               : \"100%\",\n        path                 : \"./lib/\",       // Dependents module file directory\n        pluginPath           : \"\",             // If this empty, default use settings.path + \"../plugins/\"\n        delay                : 300,            // Delay parse markdown to html, Uint : ms\n        autoLoadModules      : true,           // Automatic load dependent module files\n        watch                : true,\n        placeholder          : \"Enjoy Markdown! coding now...\",\n        gotoLine             : true,\n        codeFold             : false,\n        autoHeight           : false,\n\t\tautoFocus            : true,\n        autoCloseTags        : true,\n        searchReplace        : true,\n        syncScrolling        : true,           // true | false | \"single\", default true\n        readOnly             : false,\n        tabSize              : 4,\n\t\tindentUnit           : 4,\n        lineNumbers          : true,\n\t\tlineWrapping         : true,\n\t\tautoCloseBrackets    : true,\n\t\tshowTrailingSpace    : true,\n\t\tmatchBrackets        : true,\n\t\tindentWithTabs       : true,\n\t\tstyleSelectedText    : true,\n        matchWordHighlight   : true,           // options: true, false, \"onselected\"\n        styleActiveLine      : true,           // Highlight the current line\n        dialogLockScreen     : true,\n        dialogShowMask       : true,\n        dialogDraggable      : true,\n        dialogMaskBgColor    : \"#fff\",\n        dialogMaskOpacity    : 0.1,\n        fontSize             : \"13px\",\n        saveHTMLToTextarea   : false,\n        disabledKeyMaps      : [],\n        \n        onload               : function() {},\n        onresize             : function() {},\n        onchange             : function() {},\n        onwatch              : null,\n        onunwatch            : null,\n        onpreviewing         : function() {},\n        onpreviewed          : function() {},\n        onfullscreen         : function() {},\n        onfullscreenExit     : function() {},\n        onscroll             : function() {},\n        onpreviewscroll      : function() {},\n        \n        imageUpload          : false,\n        imageFormats         : [\"jpg\", \"jpeg\", \"gif\", \"png\", \"bmp\", \"webp\"],\n        imageUploadURL       : \"\",\n        crossDomainUpload    : false,\n        uploadCallbackURL    : \"\",\n        \n        toc                  : true,           // Table of contents\n        tocm                 : false,           // Using [TOCM], auto create ToC dropdown menu\n        tocTitle             : \"\",             // for ToC dropdown menu btn\n        tocDropdown          : false,\n        tocContainer         : \"\",\n        tocStartLevel        : 1,              // Said from H1 to create ToC\n        htmlDecode           : false,          // Open the HTML tag identification \n        pageBreak            : true,           // Enable parse page break [========]\n        atLink               : true,           // for @link\n        emailLink            : true,           // for email address auto link\n        taskList             : false,          // Enable Github Flavored Markdown task lists\n        emoji                : false,          // :emoji: , Support Github emoji, Twitter Emoji (Twemoji);\n                                               // Support FontAwesome icon emoji :fa-xxx: > Using fontAwesome icon web fonts;\n                                               // Support Editor.md logo icon emoji :editormd-logo: :editormd-logo-1x: > 1~8x;\n        tex                  : false,          // TeX(LaTeX), based on KaTeX\n        flowChart            : false,          // flowChart.js only support IE9+\n        sequenceDiagram      : false,          // sequenceDiagram.js only support IE9+\n        previewCodeHighlight : true,\n                \n        toolbar              : true,           // show/hide toolbar\n        toolbarAutoFixed     : true,           // on window scroll auto fixed position\n        toolbarIcons         : \"full\",\n        toolbarTitles        : {},\n        toolbarHandlers      : {\n            ucwords : function() {\n                return editormd.toolbarHandlers.ucwords;\n            },\n            lowercase : function() {\n                return editormd.toolbarHandlers.lowercase;\n            }\n        },\n        toolbarCustomIcons   : {               // using html tag create toolbar icon, unused default <a> tag.\n            lowercase        : \"<a href=\\\"javascript:;\\\" title=\\\"Lowercase\\\" unselectable=\\\"on\\\"><i class=\\\"fa\\\" name=\\\"lowercase\\\" style=\\\"font-size:24px;margin-top: -10px;\\\">a</i></a>\",\n            \"ucwords\"        : \"<a href=\\\"javascript:;\\\" title=\\\"ucwords\\\" unselectable=\\\"on\\\"><i class=\\\"fa\\\" name=\\\"ucwords\\\" style=\\\"font-size:20px;margin-top: -3px;\\\">Aa</i></a>\"\n        }, \n        toolbarIconsClass    : {\n            undo             : \"fa-undo\",\n            redo             : \"fa-repeat\",\n            bold             : \"fa-bold\",\n            del              : \"fa-strikethrough\",\n            italic           : \"fa-italic\",\n            quote            : \"fa-quote-left\",\n            uppercase        : \"fa-font\",\n            h1               : editormd.classPrefix + \"bold\",\n            h2               : editormd.classPrefix + \"bold\",\n            h3               : editormd.classPrefix + \"bold\",\n            h4               : editormd.classPrefix + \"bold\",\n            h5               : editormd.classPrefix + \"bold\",\n            h6               : editormd.classPrefix + \"bold\",\n            \"list-ul\"        : \"fa-list-ul\",\n            \"list-ol\"        : \"fa-list-ol\",\n            hr               : \"fa-minus\",\n            link             : \"fa-link\",\n            \"reference-link\" : \"fa-anchor\",\n            image            : \"fa-picture-o\",\n            code             : \"fa-code\",\n            \"preformatted-text\" : \"fa-file-code-o\",\n            \"code-block\"     : \"fa-file-code-o\",\n            table            : \"fa-table\",\n            datetime         : \"fa-clock-o\",\n            emoji            : \"fa-smile-o\",\n            \"html-entities\"  : \"fa-copyright\",\n            pagebreak        : \"fa-newspaper-o\",\n            \"goto-line\"      : \"fa-terminal\", // fa-crosshairs\n            watch            : \"fa-eye-slash\",\n            unwatch          : \"fa-eye\",\n            preview          : \"fa-desktop\",\n            search           : \"fa-search\",\n            fullscreen       : \"fa-arrows-alt\",\n            clear            : \"fa-eraser\",\n            help             : \"fa-question-circle\",\n            info             : \"fa-info-circle\"\n        },        \n        toolbarIconTexts     : {},\n        \n        lang : {\n            name        : \"zh-cn\",\n            description : \"开源在线Markdown编辑器<br/>Open source online Markdown editor.\",\n            tocTitle    : \"目录\",\n            toolbar     : {\n                undo             : \"撤销（Ctrl+Z）\",\n                redo             : \"重做（Ctrl+Y）\",\n                bold             : \"粗体\",\n                del              : \"删除线\",\n                italic           : \"斜体\",\n                quote            : \"引用\",\n                ucwords          : \"将每个单词首字母转成大写\",\n                uppercase        : \"将所选转换成大写\",\n                lowercase        : \"将所选转换成小写\",\n                h1               : \"标题1\",\n                h2               : \"标题2\",\n                h3               : \"标题3\",\n                h4               : \"标题4\",\n                h5               : \"标题5\",\n                h6               : \"标题6\",\n                \"list-ul\"        : \"无序列表\",\n                \"list-ol\"        : \"有序列表\",\n                hr               : \"横线\",\n                link             : \"链接\",\n                \"reference-link\" : \"引用链接\",\n                image            : \"添加图片\",\n                code             : \"行内代码\",\n                \"preformatted-text\" : \"预格式文本 / 代码块（缩进风格）\",\n                \"code-block\"     : \"代码块（多语言风格）\",\n                table            : \"添加表格\",\n                datetime         : \"日期时间\",\n                emoji            : \"Emoji表情\",\n                \"html-entities\"  : \"HTML实体字符\",\n                pagebreak        : \"插入分页符\",\n                \"goto-line\"      : \"跳转到行\",\n                watch            : \"关闭实时预览\",\n                unwatch          : \"开启实时预览\",\n                preview          : \"全窗口预览HTML（按 Shift + ESC还原）\",\n                fullscreen       : \"全屏（按ESC还原）\",\n                clear            : \"清空\",\n                search           : \"搜索\",\n                help             : \"使用帮助\",\n                info             : \"关于\" + editormd.title\n            },\n            buttons : {\n                enter  : \"确定\",\n                cancel : \"取消\",\n                close  : \"关闭\"\n            },\n            dialog : {\n                link : {\n                    title    : \"添加链接\",\n                    url      : \"链接地址\",\n                    urlTitle : \"链接标题\",\n                    urlEmpty : \"错误：请填写链接地址。\"\n                },\n                referenceLink : {\n                    title    : \"添加引用链接\",\n                    name     : \"引用名称\",\n                    url      : \"链接地址\",\n                    urlId    : \"链接ID\",\n                    urlTitle : \"链接标题\",\n                    nameEmpty: \"错误：引用链接的名称不能为空。\",\n                    idEmpty  : \"错误：请填写引用链接的ID。\",\n                    urlEmpty : \"错误：请填写引用链接的URL地址。\"\n                },\n                image : {\n                    title    : \"添加图片\",\n                    url      : \"图片地址\",\n                    link     : \"图片链接\",\n                    alt      : \"图片描述\",\n                    uploadButton     : \"本地上传\",\n                    imageURLEmpty    : \"错误：图片地址不能为空。\",\n                    uploadFileEmpty  : \"错误：上传的图片不能为空。\",\n                    formatNotAllowed : \"错误：只允许上传图片文件，允许上传的图片文件格式有：\"\n                },\n                preformattedText : {\n                    title             : \"添加预格式文本或代码块\", \n                    emptyAlert        : \"错误：请填写预格式文本或代码的内容。\"\n                },\n                codeBlock : {\n                    title             : \"添加代码块\",                    \n                    selectLabel       : \"代码语言：\",\n                    selectDefaultText : \"请选择代码语言\",\n                    otherLanguage     : \"其他语言\",\n                    unselectedLanguageAlert : \"错误：请选择代码所属的语言类型。\",\n                    codeEmptyAlert    : \"错误：请填写代码内容。\"\n                },\n                htmlEntities : {\n                    title : \"HTML 实体字符\"\n                },\n                help : {\n                    title : \"使用帮助\"\n                }\n            }\n        }\n    };\n    \n    editormd.classNames  = {\n        tex : editormd.classPrefix + \"tex\"\n    };\n\n    editormd.dialogZindex = 99999;\n    \n    editormd.$katex       = null;\n    editormd.$marked      = null;\n    editormd.$CodeMirror  = null;\n    editormd.$prettyPrint = null;\n    \n    var timer, flowchartTimer;\n\n    editormd.prototype    = editormd.fn = {\n        state : {\n            watching   : false,\n            loaded     : false,\n            preview    : false,\n            fullscreen : false\n        },\n        \n        /**\n         * 构造函数/实例初始化\n         * Constructor / instance initialization\n         * \n         * @param   {String}   id            编辑器的ID\n         * @param   {Object}   [options={}]  配置选项 Key/Value\n         * @returns {editormd}               返回editormd的实例对象\n         */\n        \n        init : function (id, options) {\n            \n            options              = options || {};\n            \n            if (typeof id === \"object\")\n            {\n                options = id;\n            }\n            \n            var _this            = this;\n            var classPrefix      = this.classPrefix  = editormd.classPrefix; \n            var settings         = this.settings     = $.extend(true, editormd.defaults, options);\n            \n            id                   = (typeof id === \"object\") ? settings.id : id;\n            \n            var editor           = this.editor       = $(\"#\" + id);\n            \n            this.id              = id;\n            this.lang            = settings.lang;\n            \n            var classNames       = this.classNames   = {\n                textarea : {\n                    html     : classPrefix + \"html-textarea\",\n                    markdown : classPrefix + \"markdown-textarea\"\n                }\n            };\n            \n            settings.pluginPath = (settings.pluginPath === \"\") ? settings.path + \"../plugins/\" : settings.pluginPath; \n            \n            this.state.watching = (settings.watch) ? true : false;\n            \n            if ( !editor.hasClass(\"editormd\") ) {\n                editor.addClass(\"editormd\");\n            }\n            \n            editor.css({\n                width  : (typeof settings.width  === \"number\") ? settings.width  + \"px\" : settings.width,\n                height : (typeof settings.height === \"number\") ? settings.height + \"px\" : settings.height\n            });\n            \n            if (settings.autoHeight)\n            {\n                editor.css(\"height\", \"auto\");\n            }\n                        \n            var markdownTextarea = this.markdownTextarea = editor.children(\"textarea\");\n            \n            if (markdownTextarea.length < 1)\n            {\n                editor.append(\"<textarea></textarea>\");\n                markdownTextarea = this.markdownTextarea = editor.children(\"textarea\");\n            }\n            \n            markdownTextarea.addClass(classNames.textarea.markdown).attr(\"placeholder\", settings.placeholder);\n            \n            if (typeof markdownTextarea.attr(\"name\") === \"undefined\" || markdownTextarea.attr(\"name\") === \"\")\n            {\n                markdownTextarea.attr(\"name\", (settings.name !== \"\") ? settings.name : id + \"-markdown-doc\");\n            }\n            \n            var appendElements = [\n                (!settings.readOnly) ? \"<a href=\\\"javascript:;\\\" class=\\\"fa fa-close \" + classPrefix + \"preview-close-btn\\\"></a>\" : \"\",\n                ( (settings.saveHTMLToTextarea) ? \"<textarea class=\\\"\" + classNames.textarea.html + \"\\\" name=\\\"\" + id + \"-html-code\\\"></textarea>\" : \"\" ),\n                \"<div class=\\\"\" + classPrefix + \"preview\\\"><div class=\\\"markdown-body \" + classPrefix + \"preview-container\\\"></div></div>\",\n                \"<div class=\\\"\" + classPrefix + \"container-mask\\\" style=\\\"display:block;\\\"></div>\",\n                \"<div class=\\\"\" + classPrefix + \"mask\\\"></div>\"\n            ].join(\"\\n\");\n            \n            editor.append(appendElements).addClass(classPrefix + \"vertical\");\n            \n            if (settings.theme !== \"\") \n            {\n                editor.addClass(classPrefix + \"theme-\" + settings.theme);\n            }\n            \n            this.mask          = editor.children(\".\" + classPrefix + \"mask\");    \n            this.containerMask = editor.children(\".\" + classPrefix  + \"container-mask\");\n            \n            if (settings.markdown !== \"\")\n            {\n                markdownTextarea.val(settings.markdown);\n            }\n            \n            if (settings.appendMarkdown !== \"\")\n            {\n                markdownTextarea.val(markdownTextarea.val() + settings.appendMarkdown);\n            }\n            \n            this.htmlTextarea     = editor.children(\".\" + classNames.textarea.html);            \n            this.preview          = editor.children(\".\" + classPrefix + \"preview\");\n            this.previewContainer = this.preview.children(\".\" + classPrefix + \"preview-container\");\n            \n            if (settings.previewTheme !== \"\") \n            {\n                this.preview.addClass(classPrefix + \"preview-theme-\" + settings.previewTheme);\n            }\n            \n            if (typeof define === \"function\" && define.amd)\n            {\n                if (typeof katex !== \"undefined\") \n                {\n                    editormd.$katex = katex;\n                }\n                \n                if (settings.searchReplace && !settings.readOnly) \n                {\n                    editormd.loadCSS(settings.path + \"codemirror/addon/dialog/dialog\");\n                    editormd.loadCSS(settings.path + \"codemirror/addon/search/matchesonscrollbar\");\n                }\n            }\n            \n            if ((typeof define === \"function\" && define.amd) || !settings.autoLoadModules)\n            {\n                if (typeof CodeMirror !== \"undefined\") {\n                    editormd.$CodeMirror = CodeMirror;\n                }\n                \n                if (typeof marked     !== \"undefined\") {\n                    editormd.$marked     = marked;\n                }\n                \n                this.setCodeMirror().setToolbar().loadedDisplay();\n            } \n            else \n            {\n                this.loadQueues();\n            }\n\n            return this;\n        },\n        \n        /**\n         * 所需组件加载队列\n         * Required components loading queue\n         * \n         * @returns {editormd}  返回editormd的实例对象\n         */\n        \n        loadQueues : function() {\n            var _this        = this;\n            var settings     = this.settings;\n            var loadPath     = settings.path;\n                                \n            var loadFlowChartOrSequenceDiagram = function() {\n                \n                if (editormd.isIE8) \n                {\n                    _this.loadedDisplay();\n                    \n                    return ;\n                }\n\n                if (settings.flowChart || settings.sequenceDiagram) \n                {\n                    editormd.loadScript(loadPath + \"raphael.min\", function() {\n\n                        editormd.loadScript(loadPath + \"underscore.min\", function() {  \n\n                            if (!settings.flowChart && settings.sequenceDiagram) \n                            {\n                                editormd.loadScript(loadPath + \"sequence-diagram.min\", function() {\n                                    _this.loadedDisplay();\n                                });\n                            }\n                            else if (settings.flowChart && !settings.sequenceDiagram) \n                            {      \n                                editormd.loadScript(loadPath + \"flowchart.min\", function() {  \n                                    editormd.loadScript(loadPath + \"jquery.flowchart.min\", function() {\n                                        _this.loadedDisplay();\n                                    });\n                                });\n                            }\n                            else if (settings.flowChart && settings.sequenceDiagram) \n                            {  \n                                editormd.loadScript(loadPath + \"flowchart.min\", function() {  \n                                    editormd.loadScript(loadPath + \"jquery.flowchart.min\", function() {\n                                        editormd.loadScript(loadPath + \"sequence-diagram.min\", function() {\n                                            _this.loadedDisplay();\n                                        });\n                                    });\n                                });\n                            }\n                        });\n\n                    });\n                } \n                else\n                {\n                    _this.loadedDisplay();\n                }\n            }; \n\n            editormd.loadCSS(loadPath + \"codemirror/codemirror.min\");\n            \n            if (settings.searchReplace && !settings.readOnly)\n            {\n                editormd.loadCSS(loadPath + \"codemirror/addon/dialog/dialog\");\n                editormd.loadCSS(loadPath + \"codemirror/addon/search/matchesonscrollbar\");\n            }\n            \n            if (settings.codeFold)\n            {\n                editormd.loadCSS(loadPath + \"codemirror/addon/fold/foldgutter\");            \n            }\n            \n            editormd.loadScript(loadPath + \"codemirror/codemirror.min\", function() {\n                editormd.$CodeMirror = CodeMirror;\n                \n                editormd.loadScript(loadPath + \"codemirror/modes.min\", function() {\n                    \n                    editormd.loadScript(loadPath + \"codemirror/addons.min\", function() {\n                        \n                        _this.setCodeMirror();\n                        \n                        if (settings.mode !== \"gfm\" && settings.mode !== \"markdown\") \n                        {\n                            _this.loadedDisplay();\n                            \n                            return false;\n                        }\n                        \n                        _this.setToolbar();\n\n                        editormd.loadScript(loadPath + \"marked.min\", function() {\n\n                            editormd.$marked = marked;\n                                \n                            if (settings.previewCodeHighlight) \n                            {\n                                editormd.loadScript(loadPath + \"prettify.min\", function() {\n                                    loadFlowChartOrSequenceDiagram();\n                                });\n                            } \n                            else\n                            {                  \n                                loadFlowChartOrSequenceDiagram();\n                            }\n                        });\n                        \n                    });\n                    \n                });\n                \n            });\n\n            return this;\n        },\n        \n        /**\n         * 设置 Editor.md 的整体主题，主要是工具栏\n         * Setting Editor.md theme\n         * \n         * @returns {editormd}  返回editormd的实例对象\n         */\n        \n        setTheme : function(theme) {\n            var editor      = this.editor;\n            var oldTheme    = this.settings.theme;\n            var themePrefix = this.classPrefix + \"theme-\";\n            \n            editor.removeClass(themePrefix + oldTheme).addClass(themePrefix + theme);\n            \n            this.settings.theme = theme;\n            \n            return this;\n        },\n        \n        /**\n         * 设置 CodeMirror（编辑区）的主题\n         * Setting CodeMirror (Editor area) theme\n         * \n         * @returns {editormd}  返回editormd的实例对象\n         */\n        \n        setEditorTheme : function(theme) {  \n            var settings   = this.settings;  \n            settings.editorTheme = theme;  \n            \n            if (theme !== \"default\")\n            {\n                editormd.loadCSS(settings.path + \"codemirror/theme/\" + settings.editorTheme);\n            }\n            \n            this.cm.setOption(\"theme\", theme);\n            \n            return this;\n        },\n        \n        /**\n         * setEditorTheme() 的别名\n         * setEditorTheme() alias\n         * \n         * @returns {editormd}  返回editormd的实例对象\n         */\n        \n        setCodeMirrorTheme : function (theme) {            \n            this.setEditorTheme(theme);\n            \n            return this;\n        },\n        \n        /**\n         * 设置 Editor.md 的主题\n         * Setting Editor.md theme\n         * \n         * @returns {editormd}  返回editormd的实例对象\n         */\n        \n        setPreviewTheme : function(theme) {  \n            var preview     = this.preview;\n            var oldTheme    = this.settings.previewTheme;\n            var themePrefix = this.classPrefix + \"preview-theme-\";\n            \n            preview.removeClass(themePrefix + oldTheme).addClass(themePrefix + theme);\n            \n            this.settings.previewTheme = theme;\n            \n            return this;\n        },\n        \n        /**\n         * 配置和初始化CodeMirror组件\n         * CodeMirror initialization\n         * \n         * @returns {editormd}  返回editormd的实例对象\n         */\n        \n        setCodeMirror : function() { \n            var settings         = this.settings;\n            var editor           = this.editor;\n            \n            if (settings.editorTheme !== \"default\")\n            {\n                editormd.loadCSS(settings.path + \"codemirror/theme/\" + settings.editorTheme);\n            }\n            \n            var codeMirrorConfig = {\n                mode                      : settings.mode,\n                theme                     : settings.editorTheme,\n                tabSize                   : settings.tabSize,\n                dragDrop                  : false,\n                autofocus                 : settings.autoFocus,\n                autoCloseTags             : settings.autoCloseTags,\n                readOnly                  : (settings.readOnly) ? \"nocursor\" : false,\n                indentUnit                : settings.indentUnit,\n                lineNumbers               : settings.lineNumbers,\n                lineWrapping              : settings.lineWrapping,\n                extraKeys                 : {\n                                                \"Ctrl-Q\": function(cm) { \n                                                    cm.foldCode(cm.getCursor()); \n                                                }\n                                            },\n                foldGutter                : settings.codeFold,\n                gutters                   : [\"CodeMirror-linenumbers\", \"CodeMirror-foldgutter\"],\n                matchBrackets             : settings.matchBrackets,\n                indentWithTabs            : settings.indentWithTabs,\n                styleActiveLine           : settings.styleActiveLine,\n                styleSelectedText         : settings.styleSelectedText,\n                autoCloseBrackets         : settings.autoCloseBrackets,\n                showTrailingSpace         : settings.showTrailingSpace,\n                highlightSelectionMatches : ( (!settings.matchWordHighlight) ? false : { showToken: (settings.matchWordHighlight === \"onselected\") ? false : /\\w/ } )\n            };\n            \n            this.codeEditor = this.cm        = editormd.$CodeMirror.fromTextArea(this.markdownTextarea[0], codeMirrorConfig);\n            this.codeMirror = this.cmElement = editor.children(\".CodeMirror\");\n            \n            if (settings.value !== \"\")\n            {\n                this.cm.setValue(settings.value);\n            }\n\n            this.codeMirror.css({\n                fontSize : settings.fontSize,\n                width    : (!settings.watch) ? \"100%\" : \"50%\"\n            });\n            \n            if (settings.autoHeight)\n            {\n                this.codeMirror.css(\"height\", \"auto\");\n                this.cm.setOption(\"viewportMargin\", Infinity);\n            }\n            \n            if (!settings.lineNumbers)\n            {\n                this.codeMirror.find(\".CodeMirror-gutters\").css(\"border-right\", \"none\");\n            }\n\n            return this;\n        },\n        \n        /**\n         * 获取CodeMirror的配置选项\n         * Get CodeMirror setting options\n         * \n         * @returns {Mixed}                  return CodeMirror setting option value\n         */\n        \n        getCodeMirrorOption : function(key) {            \n            return this.cm.getOption(key);\n        },\n        \n        /**\n         * 配置和重配置CodeMirror的选项\n         * CodeMirror setting options / resettings\n         * \n         * @returns {editormd}  返回editormd的实例对象\n         */\n        \n        setCodeMirrorOption : function(key, value) {\n            \n            this.cm.setOption(key, value);\n            \n            return this;\n        },\n        \n        /**\n         * 添加 CodeMirror 键盘快捷键\n         * Add CodeMirror keyboard shortcuts key map\n         * \n         * @returns {editormd}  返回editormd的实例对象\n         */\n        \n        addKeyMap : function(map, bottom) {\n            this.cm.addKeyMap(map, bottom);\n            \n            return this;\n        },\n        \n        /**\n         * 移除 CodeMirror 键盘快捷键\n         * Remove CodeMirror keyboard shortcuts key map\n         * \n         * @returns {editormd}  返回editormd的实例对象\n         */\n        \n        removeKeyMap : function(map) {\n            this.cm.removeKeyMap(map);\n            \n            return this;\n        },\n        \n        /**\n         * 跳转到指定的行\n         * Goto CodeMirror line\n         * \n         * @param   {String|Intiger}   line      line number or \"first\"|\"last\"\n         * @returns {editormd}                   返回editormd的实例对象\n         */\n        \n        gotoLine : function (line) {\n            \n            var settings = this.settings;\n            \n            if (!settings.gotoLine)\n            {\n                return this;\n            }\n            \n            var cm       = this.cm;\n            var editor   = this.editor;\n            var count    = cm.lineCount();\n            var preview  = this.preview;\n            \n            if (typeof line === \"string\")\n            {\n                if(line === \"last\")\n                {\n                    line = count;\n                }\n            \n                if (line === \"first\")\n                {\n                    line = 1;\n                }\n            }\n            \n            if (typeof line !== \"number\") \n            {  \n                alert(\"Error: The line number must be an integer.\");\n                return this;\n            }\n            \n            line  = parseInt(line) - 1;\n            \n            if (line > count)\n            {\n                alert(\"Error: The line number range 1-\" + count);\n                \n                return this;\n            }\n            \n            cm.setCursor( {line : line, ch : 0} );\n            \n            var scrollInfo   = cm.getScrollInfo();\n            var clientHeight = scrollInfo.clientHeight; \n            var coords       = cm.charCoords({line : line, ch : 0}, \"local\");\n            \n            cm.scrollTo(null, (coords.top + coords.bottom - clientHeight) / 2);\n            \n            if (settings.watch)\n            {            \n                var cmScroll  = this.codeMirror.find(\".CodeMirror-scroll\")[0];\n                var height    = $(cmScroll).height(); \n                var scrollTop = cmScroll.scrollTop;         \n                var percent   = (scrollTop / cmScroll.scrollHeight);\n\n                if (scrollTop === 0)\n                {\n                    preview.scrollTop(0);\n                } \n                else if (scrollTop + height >= cmScroll.scrollHeight - 16)\n                { \n                    preview.scrollTop(preview[0].scrollHeight);                    \n                } \n                else\n                {                    \n                    preview.scrollTop(preview[0].scrollHeight * percent);\n                }\n            }\n\n            cm.focus();\n            \n            return this;\n        },\n        \n        /**\n         * 扩展当前实例对象，可同时设置多个或者只设置一个\n         * Extend editormd instance object, can mutil setting.\n         * \n         * @returns {editormd}                  this(editormd instance object.)\n         */\n        \n        extend : function() {\n            if (typeof arguments[1] !== \"undefined\")\n            {\n                if (typeof arguments[1] === \"function\")\n                {\n                    arguments[1] = $.proxy(arguments[1], this);\n                }\n\n                this[arguments[0]] = arguments[1];\n            }\n            \n            if (typeof arguments[0] === \"object\" && typeof arguments[0].length === \"undefined\")\n            {\n                $.extend(true, this, arguments[0]);\n            }\n\n            return this;\n        },\n        \n        /**\n         * 设置或扩展当前实例对象，单个设置\n         * Extend editormd instance object, one by one\n         * \n         * @param   {String|Object}   key       option key\n         * @param   {String|Object}   value     option value\n         * @returns {editormd}                  this(editormd instance object.)\n         */\n        \n        set : function (key, value) {\n            \n            if (typeof value !== \"undefined\" && typeof value === \"function\")\n            {\n                value = $.proxy(value, this);\n            }\n            \n            this[key] = value;\n\n            return this;\n        },\n        \n        /**\n         * 重新配置\n         * Resetting editor options\n         * \n         * @param   {String|Object}   key       option key\n         * @param   {String|Object}   value     option value\n         * @returns {editormd}                  this(editormd instance object.)\n         */\n        \n        config : function(key, value) {\n            var settings = this.settings;\n            \n            if (typeof key === \"object\")\n            {\n                settings = $.extend(true, settings, key);\n            }\n            \n            if (typeof key === \"string\")\n            {\n                settings[key] = value;\n            }\n            \n            this.settings = settings;\n            this.recreate();\n            \n            return this;\n        },\n        \n        /**\n         * 注册事件处理方法\n         * Bind editor event handle\n         * \n         * @param   {String}     eventType      event type\n         * @param   {Function}   callback       回调函数\n         * @returns {editormd}                  this(editormd instance object.)\n         */\n        \n        on : function(eventType, callback) {\n            var settings = this.settings;\n            \n            if (typeof settings[\"on\" + eventType] !== \"undefined\") \n            {                \n                settings[\"on\" + eventType] = $.proxy(callback, this);      \n            }\n\n            return this;\n        },\n        \n        /**\n         * 解除事件处理方法\n         * Unbind editor event handle\n         * \n         * @param   {String}   eventType          event type\n         * @returns {editormd}                    this(editormd instance object.)\n         */\n        \n        off : function(eventType) {\n            var settings = this.settings;\n            \n            if (typeof settings[\"on\" + eventType] !== \"undefined\") \n            {\n                settings[\"on\" + eventType] = function(){};\n            }\n            \n            return this;\n        },\n        \n        /**\n         * 显示工具栏\n         * Display toolbar\n         * \n         * @param   {Function} [callback=function(){}] 回调函数\n         * @returns {editormd}  返回editormd的实例对象\n         */\n        \n        showToolbar : function(callback) {\n            var settings = this.settings;\n            \n            if(settings.readOnly) {\n                return this;\n            }\n            \n            if (settings.toolbar && (this.toolbar.length < 1 || this.toolbar.find(\".\" + this.classPrefix + \"menu\").html() === \"\") )\n            {\n                this.setToolbar();\n            }\n            \n            settings.toolbar = true; \n            \n            this.toolbar.show();\n            this.resize();\n            \n            $.proxy(callback || function(){}, this)();\n\n            return this;\n        },\n        \n        /**\n         * 隐藏工具栏\n         * Hide toolbar\n         * \n         * @param   {Function} [callback=function(){}] 回调函数\n         * @returns {editormd}                         this(editormd instance object.)\n         */\n        \n        hideToolbar : function(callback) { \n            var settings = this.settings;\n            \n            settings.toolbar = false;  \n            this.toolbar.hide();\n            this.resize();\n            \n            $.proxy(callback || function(){}, this)();\n\n            return this;\n        },\n        \n        /**\n         * 页面滚动时工具栏的固定定位\n         * Set toolbar in window scroll auto fixed position\n         * \n         * @returns {editormd}  返回editormd的实例对象\n         */\n        \n        setToolbarAutoFixed : function(fixed) {\n            \n            var state    = this.state;\n            var editor   = this.editor;\n            var toolbar  = this.toolbar;\n            var settings = this.settings;\n            \n            if (typeof fixed !== \"undefined\")\n            {\n                settings.toolbarAutoFixed = fixed;\n            }\n            \n            var autoFixedHandle = function(){\n                var $window = $(window);\n                var top     = $window.scrollTop();\n                \n                if (!settings.toolbarAutoFixed)\n                {\n                    return false;\n                }\n\n                if (top - editor.offset().top > 10 && top < editor.height())\n                {\n                    toolbar.css({\n                        position : \"fixed\",\n                        width    : editor.width() + \"px\",\n                        left     : ($window.width() - editor.width()) / 2 + \"px\"\n                    });\n                }\n                else\n                {\n                    toolbar.css({\n                        position : \"absolute\",\n                        width    : \"100%\",\n                        left     : 0\n                    });\n                }\n            };\n            \n            if (!state.fullscreen && !state.preview && settings.toolbar && settings.toolbarAutoFixed)\n            {\n                $(window).bind(\"scroll\", autoFixedHandle);\n            }\n\n            return this;\n        },\n        \n        /**\n         * 配置和初始化工具栏\n         * Set toolbar and Initialization\n         * \n         * @returns {editormd}  返回editormd的实例对象\n         */\n        \n        setToolbar : function() {\n            var settings    = this.settings;  \n            \n            if(settings.readOnly) {\n                return this;\n            }\n            \n            var editor      = this.editor;\n            var preview     = this.preview;\n            var classPrefix = this.classPrefix;\n            \n            var toolbar     = this.toolbar = editor.children(\".\" + classPrefix + \"toolbar\");\n            \n            if (settings.toolbar && toolbar.length < 1)\n            {            \n                var toolbarHTML = \"<div class=\\\"\" + classPrefix + \"toolbar\\\"><div class=\\\"\" + classPrefix + \"toolbar-container\\\"><ul class=\\\"\" + classPrefix + \"menu\\\"></ul></div></div>\";\n                \n                editor.append(toolbarHTML);\n                toolbar = this.toolbar = editor.children(\".\" + classPrefix + \"toolbar\");\n            }\n            \n            if (!settings.toolbar) \n            {\n                toolbar.hide();\n                \n                return this;\n            }\n            \n            toolbar.show();\n            \n            var icons       = (typeof settings.toolbarIcons === \"function\") ? settings.toolbarIcons() \n                            : ((typeof settings.toolbarIcons === \"string\")  ? editormd.toolbarModes[settings.toolbarIcons] : settings.toolbarIcons);\n            \n            var toolbarMenu = toolbar.find(\".\" + this.classPrefix + \"menu\"), menu = \"\";\n            var pullRight   = false;\n            \n            for (var i = 0, len = icons.length; i < len; i++)\n            {\n                var name = icons[i];\n\n                if (name === \"||\") \n                { \n                    pullRight = true;\n                } \n                else if (name === \"|\")\n                {\n                    menu += \"<li class=\\\"divider\\\" unselectable=\\\"on\\\">|</li>\";\n                }\n                else\n                {\n                    var isHeader = (/h(\\d)/.test(name));\n                    var index    = name;\n                    \n                    if (name === \"watch\" && !settings.watch) {\n                        index = \"unwatch\";\n                    }\n                    \n                    var title     = settings.lang.toolbar[index];\n                    var iconTexts = settings.toolbarIconTexts[index];\n                    var iconClass = settings.toolbarIconsClass[index];\n                    \n                    title     = (typeof title     === \"undefined\") ? \"\" : title;\n                    iconTexts = (typeof iconTexts === \"undefined\") ? \"\" : iconTexts;\n                    iconClass = (typeof iconClass === \"undefined\") ? \"\" : iconClass;\n\n                    var menuItem = pullRight ? \"<li class=\\\"pull-right\\\">\" : \"<li>\";\n                    \n                    if (typeof settings.toolbarCustomIcons[name] !== \"undefined\" && typeof settings.toolbarCustomIcons[name] !== \"function\")\n                    {\n                        menuItem += settings.toolbarCustomIcons[name];\n                    }\n                    else \n                    {\n                        menuItem += \"<a href=\\\"javascript:;\\\" title=\\\"\" + title + \"\\\" unselectable=\\\"on\\\">\";\n                        menuItem += \"<i class=\\\"fa \" + iconClass + \"\\\" name=\\\"\"+name+\"\\\" unselectable=\\\"on\\\">\"+((isHeader) ? name.toUpperCase() : ( (iconClass === \"\") ? iconTexts : \"\") ) + \"</i>\";\n                        menuItem += \"</a>\";\n                    }\n\n                    menuItem += \"</li>\";\n\n                    menu = pullRight ? menuItem + menu : menu + menuItem;\n                }\n            }\n\n            toolbarMenu.html(menu);\n            \n            toolbarMenu.find(\"[title=\\\"Lowercase\\\"]\").attr(\"title\", settings.lang.toolbar.lowercase);\n            toolbarMenu.find(\"[title=\\\"ucwords\\\"]\").attr(\"title\", settings.lang.toolbar.ucwords);\n            \n            this.setToolbarHandler();\n            this.setToolbarAutoFixed();\n\n            return this;\n        },\n        \n        /**\n         * 工具栏图标事件处理对象序列\n         * Get toolbar icons event handlers\n         * \n         * @param   {Object}   cm    CodeMirror的实例对象\n         * @param   {String}   name  要获取的事件处理器名称\n         * @returns {Object}         返回处理对象序列\n         */\n            \n        dialogLockScreen : function() {\n            $.proxy(editormd.dialogLockScreen, this)();\n            \n            return this;\n        },\n\n        dialogShowMask : function(dialog) {\n            $.proxy(editormd.dialogShowMask, this)(dialog);\n            \n            return this;\n        },\n        \n        getToolbarHandles : function(name) {  \n            var toolbarHandlers = this.toolbarHandlers = editormd.toolbarHandlers;\n            \n            return (name && typeof toolbarIconHandlers[name] !== \"undefined\") ? toolbarHandlers[name] : toolbarHandlers;\n        },\n        \n        /**\n         * 工具栏图标事件处理器\n         * Bind toolbar icons event handle\n         * \n         * @returns {editormd}  返回editormd的实例对象\n         */\n        \n        setToolbarHandler : function() {\n            var _this               = this;\n            var settings            = this.settings;\n            \n            if (!settings.toolbar || settings.readOnly) {\n                return this;\n            }\n            \n            var toolbar             = this.toolbar;\n            var cm                  = this.cm;\n            var classPrefix         = this.classPrefix;           \n            var toolbarIcons        = this.toolbarIcons = toolbar.find(\".\" + classPrefix + \"menu > li > a\");  \n            var toolbarIconHandlers = this.getToolbarHandles();  \n                \n            toolbarIcons.bind(editormd.mouseOrTouch(\"click\", \"touchend\"), function(event) {\n\n                var icon                = $(this).children(\".fa\");\n                var name                = icon.attr(\"name\");\n                var cursor              = cm.getCursor();\n                var selection           = cm.getSelection();\n\n                if (name === \"\") {\n                    return ;\n                }\n                \n                _this.activeIcon = icon;\n\n                if (typeof toolbarIconHandlers[name] !== \"undefined\") \n                {\n                    $.proxy(toolbarIconHandlers[name], _this)(cm);\n                }\n                else \n                {\n                    if (typeof settings.toolbarHandlers[name] !== \"undefined\") \n                    {\n                        $.proxy(settings.toolbarHandlers[name], _this)(cm, icon, cursor, selection);\n                    }\n                }\n                \n                if (name !== \"link\" && name !== \"reference-link\" && name !== \"image\" && name !== \"code-block\" && \n                    name !== \"preformatted-text\" && name !== \"watch\" && name !== \"preview\" && name !== \"search\" && name !== \"fullscreen\" && name !== \"info\") \n                {\n                    cm.focus();\n                }\n\n                return false;\n\n            });\n\n            return this;\n        },\n        \n        /**\n         * 动态创建对话框\n         * Creating custom dialogs\n         * \n         * @param   {Object} options  配置项键值对 Key/Value\n         * @returns {dialog}          返回创建的dialog的jQuery实例对象\n         */\n        \n        createDialog : function(options) {            \n            return $.proxy(editormd.createDialog, this)(options);\n        },\n        \n        /**\n         * 创建关于Editor.md的对话框\n         * Create about Editor.md dialog\n         * \n         * @returns {editormd}  返回editormd的实例对象\n         */\n        \n        createInfoDialog : function() {\n            var _this        = this;\n\t\t\tvar editor       = this.editor;\n            var classPrefix  = this.classPrefix;  \n            \n            var infoDialogHTML = [\n                \"<div class=\\\"\" + classPrefix + \"dialog \" + classPrefix + \"dialog-info\\\" style=\\\"\\\">\",\n                \"<div class=\\\"\" + classPrefix + \"dialog-container\\\">\",\n                \"<h1><i class=\\\"editormd-logo editormd-logo-lg editormd-logo-color\\\"></i> \" + editormd.title + \"<small>v\" + editormd.version + \"</small></h1>\",\n                \"<p>\" + this.lang.description + \"</p>\",\n                \"<p style=\\\"margin: 10px 0 20px 0;\\\"><a href=\\\"\" + editormd.homePage + \"\\\" target=\\\"_blank\\\">\" + editormd.homePage + \" <i class=\\\"fa fa-external-link\\\"></i></a></p>\",\n                \"<p style=\\\"font-size: 0.85em;\\\">Copyright &copy; 2015 <a href=\\\"https://github.com/pandao\\\" target=\\\"_blank\\\" class=\\\"hover-link\\\">Pandao</a>, The <a href=\\\"https://github.com/pandao/editor.md/blob/master/LICENSE\\\" target=\\\"_blank\\\" class=\\\"hover-link\\\">MIT</a> License.</p>\",\n                \"</div>\",\n                \"<a href=\\\"javascript:;\\\" class=\\\"fa fa-close \" + classPrefix + \"dialog-close\\\"></a>\",\n                \"</div>\"\n            ].join(\"\\n\");\n\n            editor.append(infoDialogHTML);\n            \n            var infoDialog  = this.infoDialog = editor.children(\".\" + classPrefix + \"dialog-info\");\n\n            infoDialog.find(\".\" + classPrefix + \"dialog-close\").bind(editormd.mouseOrTouch(\"click\", \"touchend\"), function() {\n                _this.hideInfoDialog();\n            });\n            \n            infoDialog.css(\"border\", (editormd.isIE8) ? \"1px solid #ddd\" : \"\").css(\"z-index\", editormd.dialogZindex).show();\n            \n            this.infoDialogPosition();\n\n            return this;\n        },\n        \n        /**\n         * 关于Editor.md对话居中定位\n         * Editor.md dialog position handle\n         * \n         * @returns {editormd}  返回editormd的实例对象\n         */\n        \n        infoDialogPosition : function() {\n            var infoDialog = this.infoDialog;\n            \n\t\t\tvar _infoDialogPosition = function() {\n\t\t\t\tinfoDialog.css({\n\t\t\t\t\ttop  : ($(window).height() - infoDialog.height()) / 2 + \"px\",\n\t\t\t\t\tleft : ($(window).width()  - infoDialog.width()) / 2  + \"px\"\n\t\t\t\t});\n\t\t\t};\n\n\t\t\t_infoDialogPosition();\n\n\t\t\t$(window).resize(_infoDialogPosition);\n            \n            return this;\n        },\n        \n        /**\n         * 显示关于Editor.md\n         * Display about Editor.md dialog\n         * \n         * @returns {editormd}  返回editormd的实例对象\n         */\n        \n        showInfoDialog : function() {\n\n            $(\"html,body\").css(\"overflow-x\", \"hidden\");\n            \n            var _this       = this;\n\t\t\tvar editor      = this.editor;\n            var settings    = this.settings;         \n\t\t\tvar infoDialog  = this.infoDialog = editor.children(\".\" + this.classPrefix + \"dialog-info\");\n            \n            if (infoDialog.length < 1)\n            {\n                this.createInfoDialog();\n            }\n            \n            this.lockScreen(true);\n            \n            this.mask.css({\n\t\t\t\t\t\topacity         : settings.dialogMaskOpacity,\n\t\t\t\t\t\tbackgroundColor : settings.dialogMaskBgColor\n\t\t\t\t\t}).show();\n\n\t\t\tinfoDialog.css(\"z-index\", editormd.dialogZindex).show();\n\n\t\t\tthis.infoDialogPosition();\n\n            return this;\n        },\n        \n        /**\n         * 隐藏关于Editor.md\n         * Hide about Editor.md dialog\n         * \n         * @returns {editormd}  返回editormd的实例对象\n         */\n        \n        hideInfoDialog : function() {            \n            $(\"html,body\").css(\"overflow-x\", \"\");\n            this.infoDialog.hide();\n            this.mask.hide();\n            this.lockScreen(false);\n\n            return this;\n        },\n        \n        /**\n         * 锁屏\n         * lock screen\n         * \n         * @param   {Boolean}    lock    Boolean 布尔值，是否锁屏\n         * @returns {editormd}           返回editormd的实例对象\n         */\n        \n        lockScreen : function(lock) {\n            editormd.lockScreen(lock);\n            this.resize();\n\n            return this;\n        },\n        \n        /**\n         * 编辑器界面重建，用于动态语言包或模块加载等\n         * Recreate editor\n         * \n         * @returns {editormd}  返回editormd的实例对象\n         */\n        \n        recreate : function() {\n            var _this            = this;\n            var editor           = this.editor;\n            var settings         = this.settings;\n            \n            this.codeMirror.remove();\n            \n            this.setCodeMirror();\n\n            if (!settings.readOnly) \n            {\n                if (editor.find(\".editormd-dialog\").length > 0) {\n                    editor.find(\".editormd-dialog\").remove();\n                }\n                \n                if (settings.toolbar) \n                {  \n                    this.getToolbarHandles();                  \n                    this.setToolbar();\n                }\n            }\n            \n            this.loadedDisplay(true);\n\n            return this;\n        },\n        \n        /**\n         * 高亮预览HTML的pre代码部分\n         * highlight of preview codes\n         * \n         * @returns {editormd}             返回editormd的实例对象\n         */\n        \n        previewCodeHighlight : function() {    \n            var settings         = this.settings;\n            var previewContainer = this.previewContainer;\n            \n            if (settings.previewCodeHighlight) \n            {\n                previewContainer.find(\"pre\").addClass(\"prettyprint linenums\");\n                \n                if (typeof prettyPrint !== \"undefined\")\n                {                    \n                    prettyPrint();\n                }\n            }\n\n            return this;\n        },\n        \n        /**\n         * 解析TeX(KaTeX)科学公式\n         * TeX(KaTeX) Renderer\n         * \n         * @returns {editormd}             返回editormd的实例对象\n         */\n        \n        katexRender : function() {\n            \n            if (timer === null)\n            {\n                return this;\n            }\n            \n            this.previewContainer.find(\".\" + editormd.classNames.tex).each(function(){\n                var tex  = $(this);\n                editormd.$katex.render(tex.text(), tex[0]);\n                \n                tex.find(\".katex\").css(\"font-size\", \"1.6em\");\n            });   \n\n            return this;\n        },\n        \n        /**\n         * 解析和渲染流程图及时序图\n         * FlowChart and SequenceDiagram Renderer\n         * \n         * @returns {editormd}             返回editormd的实例对象\n         */\n        \n        flowChartAndSequenceDiagramRender : function() {\n            var $this            = this;\n            var settings         = this.settings;\n            var previewContainer = this.previewContainer;\n            \n            if (editormd.isIE8) {\n                return this;\n            }\n\n            if (settings.flowChart) {\n                if (flowchartTimer === null) {\n                    return this;\n                }\n                \n                previewContainer.find(\".flowchart\").flowChart(); \n            }\n\n            if (settings.sequenceDiagram) {\n                previewContainer.find(\".sequence-diagram\").sequenceDiagram({theme: \"simple\"});\n            }\n                    \n            var preview    = $this.preview;\n            var codeMirror = $this.codeMirror;\n            var codeView   = codeMirror.find(\".CodeMirror-scroll\");\n\n            var height    = codeView.height();\n            var scrollTop = codeView.scrollTop();                    \n            var percent   = (scrollTop / codeView[0].scrollHeight);\n            var tocHeight = 0;\n\n            preview.find(\".markdown-toc-list\").each(function(){\n                tocHeight += $(this).height();\n            });\n\n            var tocMenuHeight = preview.find(\".editormd-toc-menu\").height(); \n            tocMenuHeight = (!tocMenuHeight) ? 0 : tocMenuHeight;\n\n            if (scrollTop === 0) \n            {\n                preview.scrollTop(0);\n            } \n            else if (scrollTop + height >= codeView[0].scrollHeight - 16)\n            { \n                preview.scrollTop(preview[0].scrollHeight);                        \n            } \n            else\n            {                  \n                preview.scrollTop((preview[0].scrollHeight + tocHeight + tocMenuHeight) * percent);\n            }\n\n            return this;\n        },\n        \n        /**\n         * 注册键盘快捷键处理\n         * Register CodeMirror keyMaps (keyboard shortcuts).\n         * \n         * @param   {Object}    keyMap      KeyMap key/value {\"(Ctrl/Shift/Alt)-Key\" : function(){}}\n         * @returns {editormd}              return this\n         */\n        \n        registerKeyMaps : function(keyMap) {\n            \n            var _this           = this;\n            var cm              = this.cm;\n            var settings        = this.settings;\n            var toolbarHandlers = editormd.toolbarHandlers;\n            var disabledKeyMaps = settings.disabledKeyMaps;\n            \n            keyMap              = keyMap || null;\n            \n            if (keyMap)\n            {\n                for (var i in keyMap)\n                {\n                    if ($.inArray(i, disabledKeyMaps) < 0)\n                    {\n                        var map = {};\n                        map[i]  = keyMap[i];\n\n                        cm.addKeyMap(keyMap);\n                    }\n                }\n            }\n            else\n            {\n                for (var k in editormd.keyMaps)\n                {\n                    var _keyMap = editormd.keyMaps[k];\n                    var handle = (typeof _keyMap === \"string\") ? $.proxy(toolbarHandlers[_keyMap], _this) : $.proxy(_keyMap, _this);\n                    \n                    if ($.inArray(k, [\"F9\", \"F10\", \"F11\"]) < 0 && $.inArray(k, disabledKeyMaps) < 0)\n                    {\n                        var _map = {};\n                        _map[k] = handle;\n\n                        cm.addKeyMap(_map);\n                    }\n                }\n                \n                $(window).keydown(function(event) {\n                    \n                    var keymaps = {\n                        \"120\" : \"F9\",\n                        \"121\" : \"F10\",\n                        \"122\" : \"F11\"\n                    };\n                    \n                    if ( $.inArray(keymaps[event.keyCode], disabledKeyMaps) < 0 )\n                    {\n                        switch (event.keyCode)\n                        {\n                            case 120:\n                                    $.proxy(toolbarHandlers[\"watch\"], _this)();\n                                    return false;\n                                break;\n                                \n                            case 121:\n                                    $.proxy(toolbarHandlers[\"preview\"], _this)();\n                                    return false;\n                                break;\n                                \n                            case 122:\n                                    $.proxy(toolbarHandlers[\"fullscreen\"], _this)();                        \n                                    return false;\n                                break;\n                                \n                            default:\n                                break;\n                        }\n                    }\n                });\n            }\n\n            return this;\n        },\n        \n        /**\n         * 绑定同步滚动\n         * \n         * @returns {editormd} return this\n         */\n        \n        bindScrollEvent : function() {\n            \n            var _this            = this;\n            var preview          = this.preview;\n            var settings         = this.settings;\n            var codeMirror       = this.codeMirror;\n            var mouseOrTouch     = editormd.mouseOrTouch;\n            \n            if (!settings.syncScrolling) {\n                return this;\n            }\n                \n            var cmBindScroll = function() {    \n                codeMirror.find(\".CodeMirror-scroll\").bind(mouseOrTouch(\"scroll\", \"touchmove\"), function(event) {\n                    var height    = $(this).height();\n                    var scrollTop = $(this).scrollTop();                    \n                    var percent   = (scrollTop / $(this)[0].scrollHeight);\n                    \n                    var tocHeight = 0;\n                    \n                    preview.find(\".markdown-toc-list\").each(function(){\n                        tocHeight += $(this).height();\n                    });\n                    \n                    var tocMenuHeight = preview.find(\".editormd-toc-menu\").height();\n                    tocMenuHeight = (!tocMenuHeight) ? 0 : tocMenuHeight;\n\n                    if (scrollTop === 0) \n                    {\n                        preview.scrollTop(0);\n                    } \n                    else if (scrollTop + height >= $(this)[0].scrollHeight - 16)\n                    { \n                        preview.scrollTop(preview[0].scrollHeight);                        \n                    } \n                    else\n                    {\n                        preview.scrollTop((preview[0].scrollHeight  + tocHeight + tocMenuHeight) * percent);\n                    }\n                    \n                    $.proxy(settings.onscroll, _this)(event);\n                });\n            };\n\n            var cmUnbindScroll = function() {\n                codeMirror.find(\".CodeMirror-scroll\").unbind(mouseOrTouch(\"scroll\", \"touchmove\"));\n            };\n\n            var previewBindScroll = function() {\n                \n                preview.bind(mouseOrTouch(\"scroll\", \"touchmove\"), function(event) {\n                    var height    = $(this).height();\n                    var scrollTop = $(this).scrollTop();         \n                    var percent   = (scrollTop / $(this)[0].scrollHeight);\n                    var codeView  = codeMirror.find(\".CodeMirror-scroll\");\n\n                    if(scrollTop === 0) \n                    {\n                        codeView.scrollTop(0);\n                    }\n                    else if (scrollTop + height >= $(this)[0].scrollHeight)\n                    {\n                        codeView.scrollTop(codeView[0].scrollHeight);                        \n                    }\n                    else \n                    {\n                        codeView.scrollTop(codeView[0].scrollHeight * percent);\n                    }\n                    \n                    $.proxy(settings.onpreviewscroll, _this)(event);\n                });\n\n            };\n\n            var previewUnbindScroll = function() {\n                preview.unbind(mouseOrTouch(\"scroll\", \"touchmove\"));\n            }; \n\n\t\t\tcodeMirror.bind({\n\t\t\t\tmouseover  : cmBindScroll,\n\t\t\t\tmouseout   : cmUnbindScroll,\n\t\t\t\ttouchstart : cmBindScroll,\n\t\t\t\ttouchend   : cmUnbindScroll\n\t\t\t});\n            \n            if (settings.syncScrolling === \"single\") {\n                return this;\n            }\n            \n\t\t\tpreview.bind({\n\t\t\t\tmouseover  : previewBindScroll,\n\t\t\t\tmouseout   : previewUnbindScroll,\n\t\t\t\ttouchstart : previewBindScroll,\n\t\t\t\ttouchend   : previewUnbindScroll\n\t\t\t});\n\n            return this;\n        },\n        \n        bindChangeEvent : function() {\n            \n            var _this            = this;\n            var cm               = this.cm;\n            var settings         = this.settings;\n            \n            if (!settings.syncScrolling) {\n                return this;\n            }\n            \n            cm.on(\"change\", function(_cm, changeObj) {\n                \n                if (settings.watch)\n                {\n                    _this.previewContainer.css(\"padding\", settings.autoHeight ? \"20px 20px 50px 40px\" : \"20px\");\n                }\n                \n                timer = setTimeout(function() {\n                    clearTimeout(timer);\n                    _this.save();\n                    timer = null;\n                }, settings.delay);\n            });\n\n            return this;\n        },\n        \n        /**\n         * 加载队列完成之后的显示处理\n         * Display handle of the module queues loaded after.\n         * \n         * @param   {Boolean}   recreate   是否为重建编辑器\n         * @returns {editormd}             返回editormd的实例对象\n         */\n        \n        loadedDisplay : function(recreate) {\n            \n            recreate             = recreate || false;\n            \n            var _this            = this;\n            var editor           = this.editor;\n            var preview          = this.preview;\n            var settings         = this.settings;\n            \n            this.containerMask.hide();\n            \n            this.save();\n            \n            if (settings.watch) {\n                preview.show();\n            }\n            \n            editor.data(\"oldWidth\", editor.width()).data(\"oldHeight\", editor.height()); // 为了兼容Zepto\n            \n            this.resize();\n            this.registerKeyMaps();\n            \n            $(window).resize(function(){\n                _this.resize();\n            });\n            \n            this.bindScrollEvent().bindChangeEvent();\n            \n            if (!recreate)\n            {\n                $.proxy(settings.onload, this)();\n            }\n            \n            this.state.loaded = true;\n\n            return this;\n        },\n        \n        /**\n         * 设置编辑器的宽度\n         * Set editor width\n         * \n         * @param   {Number|String} width  编辑器宽度值\n         * @returns {editormd}             返回editormd的实例对象\n         */\n        \n        width : function(width) {\n                \n            this.editor.css(\"width\", (typeof width === \"number\") ? width  + \"px\" : width);            \n            this.resize();\n            \n            return this;\n        },\n        \n        /**\n         * 设置编辑器的高度\n         * Set editor height\n         * \n         * @param   {Number|String} height  编辑器高度值\n         * @returns {editormd}              返回editormd的实例对象\n         */\n        \n        height : function(height) {\n                \n            this.editor.css(\"height\", (typeof height === \"number\")  ? height  + \"px\" : height);            \n            this.resize();\n            \n            return this;\n        },\n        \n        /**\n         * 调整编辑器的尺寸和布局\n         * Resize editor layout\n         * \n         * @param   {Number|String} [width=null]  编辑器宽度值\n         * @param   {Number|String} [height=null] 编辑器高度值\n         * @returns {editormd}                    返回editormd的实例对象\n         */\n        \n        resize : function(width, height) {\n            \n            width  = width  || null;\n            height = height || null;\n            \n            var state      = this.state;\n            var editor     = this.editor;\n            var preview    = this.preview;\n            var toolbar    = this.toolbar;\n            var settings   = this.settings;\n            var codeMirror = this.codeMirror;\n            \n            if (width)\n            {\n                editor.css(\"width\", (typeof width  === \"number\") ? width  + \"px\" : width);\n            }\n            \n            if (settings.autoHeight && !state.fullscreen && !state.preview)\n            {\n                editor.css(\"height\", \"auto\");\n                codeMirror.css(\"height\", \"auto\");\n            } \n            else \n            {\n                if (height) \n                {\n                    editor.css(\"height\", (typeof height === \"number\") ? height + \"px\" : height);\n                }\n                \n                if (state.fullscreen)\n                {\n                    editor.height($(window).height());\n                }\n\n                if (settings.toolbar && !settings.readOnly) \n                {\n                    codeMirror.css(\"margin-top\", toolbar.height() + 1).height(editor.height() - toolbar.height());\n                } \n                else\n                {\n                    codeMirror.css(\"margin-top\", 0).height(editor.height());\n                }\n            }\n            \n            if(settings.watch) \n            {\n                codeMirror.width(editor.width() / 2);\n                preview.width((!state.preview) ? editor.width() / 2 : editor.width());\n                \n                this.previewContainer.css(\"padding\", settings.autoHeight ? \"20px 20px 50px 40px\" : \"20px\");\n                \n                if (settings.toolbar && !settings.readOnly) \n                {\n                    preview.css(\"top\", toolbar.height() + 1);\n                } \n                else \n                {\n                    preview.css(\"top\", 0);\n                }\n                \n                if (settings.autoHeight && !state.fullscreen && !state.preview)\n                {\n                    preview.height(\"\");\n                }\n                else\n                {                \n                    var previewHeight = (settings.toolbar && !settings.readOnly) ? editor.height() - toolbar.height() : editor.height();\n                    \n                    preview.height(previewHeight);\n                }\n            } \n            else \n            {\n                codeMirror.width(editor.width());\n                preview.hide();\n            }\n            \n            if (state.loaded) \n            {\n                $.proxy(settings.onresize, this)();\n            }\n\n            return this;\n        },\n        \n        /**\n         * 解析和保存Markdown代码\n         * Parse & Saving Markdown source code\n         * \n         * @returns {editormd}     返回editormd的实例对象\n         */\n        \n        save : function() {\n            \n            if (timer === null)\n            {\n                return this;\n            }\n            \n            var _this            = this;\n            var state            = this.state;\n            var settings         = this.settings;\n            var cm               = this.cm;            \n            var cmValue          = cm.getValue();\n            var previewContainer = this.previewContainer;\n\n            if (settings.mode !== \"gfm\" && settings.mode !== \"markdown\") \n            {\n                this.markdownTextarea.val(cmValue);\n                \n                return this;\n            }\n            \n            var marked          = editormd.$marked;\n            var markdownToC     = this.markdownToC = [];            \n            var rendererOptions = this.markedRendererOptions = {  \n                toc                  : settings.toc,\n                tocm                 : settings.tocm,\n                tocStartLevel        : settings.tocStartLevel,\n                pageBreak            : settings.pageBreak,\n                taskList             : settings.taskList,\n                emoji                : settings.emoji,\n                tex                  : settings.tex,\n                atLink               : settings.atLink,           // for @link\n                emailLink            : settings.emailLink,        // for mail address auto link\n                flowChart            : settings.flowChart,\n                sequenceDiagram      : settings.sequenceDiagram,\n                previewCodeHighlight : settings.previewCodeHighlight,\n            };\n            \n            var markedOptions = this.markedOptions = {\n                renderer    : editormd.markedRenderer(markdownToC, rendererOptions),\n                gfm         : true,\n                tables      : true,\n                breaks      : true,\n                pedantic    : false,\n                sanitize    : (settings.htmlDecode) ? false : true,  // 关闭忽略HTML标签，即开启识别HTML标签，默认为false\n                smartLists  : true,\n                smartypants : true\n            };\n            \n            marked.setOptions(markedOptions);\n                    \n            var newMarkdownDoc = editormd.$marked(cmValue, markedOptions);\n            \n            //console.info(\"cmValue\", cmValue, newMarkdownDoc);\n            \n            newMarkdownDoc = editormd.filterHTMLTags(newMarkdownDoc, settings.htmlDecode);\n            \n            //console.error(\"cmValue\", cmValue, newMarkdownDoc);\n            \n            this.markdownTextarea.text(cmValue);\n            \n            cm.save();\n            \n            if (settings.saveHTMLToTextarea) \n            {\n                this.htmlTextarea.text(newMarkdownDoc);\n            }\n            \n            if(settings.watch || (!settings.watch && state.preview))\n            {\n                previewContainer.html(newMarkdownDoc);\n\n                this.previewCodeHighlight();\n                \n                if (settings.toc) \n                {\n                    var tocContainer = (settings.tocContainer === \"\") ? previewContainer : $(settings.tocContainer);\n                    var tocMenu      = tocContainer.find(\".\" + this.classPrefix + \"toc-menu\");\n                    \n                    tocContainer.attr(\"previewContainer\", (settings.tocContainer === \"\") ? \"true\" : \"false\");\n                    \n                    if (settings.tocContainer !== \"\" && tocMenu.length > 0)\n                    {\n                        tocMenu.remove();\n                    }\n                    \n                    editormd.markdownToCRenderer(markdownToC, tocContainer, settings.tocDropdown, settings.tocStartLevel);\n            \n                    if (settings.tocDropdown || tocContainer.find(\".\" + this.classPrefix + \"toc-menu\").length > 0)\n                    {\n                        editormd.tocDropdownMenu(tocContainer, (settings.tocTitle !== \"\") ? settings.tocTitle : this.lang.tocTitle);\n                    }\n            \n                    if (settings.tocContainer !== \"\")\n                    {\n                        previewContainer.find(\".markdown-toc\").css(\"border\", \"none\");\n                    }\n                }\n                \n                if (settings.tex)\n                {\n                    if (!editormd.kaTeXLoaded && settings.autoLoadModules) \n                    {\n                        editormd.loadKaTeX(function() {\n                            editormd.$katex = katex;\n                            editormd.kaTeXLoaded = true;\n                            _this.katexRender();\n                        });\n                    } \n                    else \n                    {\n                        editormd.$katex = katex;\n                        this.katexRender();\n                    }\n                }                \n                \n                if (settings.flowChart || settings.sequenceDiagram)\n                {\n                    flowchartTimer = setTimeout(function(){\n                        clearTimeout(flowchartTimer);\n                        _this.flowChartAndSequenceDiagramRender();\n                        flowchartTimer = null;\n                    }, 10);\n                }\n\n                if (state.loaded) \n                {\n                    $.proxy(settings.onchange, this)();\n                }\n            }\n\n            return this;\n        },\n        \n        /**\n         * 聚焦光标位置\n         * Focusing the cursor position\n         * \n         * @returns {editormd}         返回editormd的实例对象\n         */\n        \n        focus : function() {\n            this.cm.focus();\n\n            return this;\n        },\n        \n        /**\n         * 设置光标的位置\n         * Set cursor position\n         * \n         * @param   {Object}    cursor 要设置的光标位置键值对象，例：{line:1, ch:0}\n         * @returns {editormd}         返回editormd的实例对象\n         */\n        \n        setCursor : function(cursor) {\n            this.cm.setCursor(cursor);\n\n            return this;\n        },\n        \n        /**\n         * 获取当前光标的位置\n         * Get the current position of the cursor\n         * \n         * @returns {Cursor}         返回一个光标Cursor对象\n         */\n        \n        getCursor : function() {\n            return this.cm.getCursor();\n        },\n        \n        /**\n         * 设置光标选中的范围\n         * Set cursor selected ranges\n         * \n         * @param   {Object}    from   开始位置的光标键值对象，例：{line:1, ch:0}\n         * @param   {Object}    to     结束位置的光标键值对象，例：{line:1, ch:0}\n         * @returns {editormd}         返回editormd的实例对象\n         */\n        \n        setSelection : function(from, to) {\n        \n            this.cm.setSelection(from, to);\n        \n            return this;\n        },\n        \n        /**\n         * 获取光标选中的文本\n         * Get the texts from cursor selected\n         * \n         * @returns {String}         返回选中文本的字符串形式\n         */\n        \n        getSelection : function() {\n            return this.cm.getSelection();\n        },\n        \n        /**\n         * 设置光标选中的文本范围\n         * Set the cursor selection ranges\n         * \n         * @param   {Array}    ranges  cursor selection ranges array\n         * @returns {Array}            return this\n         */\n        \n        setSelections : function(ranges) {\n            this.cm.setSelections(ranges);\n            \n            return this;\n        },\n        \n        /**\n         * 获取光标选中的文本范围\n         * Get the cursor selection ranges\n         * \n         * @returns {Array}         return selection ranges array\n         */\n        \n        getSelections : function() {\n            return this.cm.getSelections();\n        },\n        \n        /**\n         * 替换当前光标选中的文本或在当前光标处插入新字符\n         * Replace the text at the current cursor selected or insert a new character at the current cursor position\n         * \n         * @param   {String}    value  要插入的字符值\n         * @returns {editormd}         返回editormd的实例对象\n         */\n        \n        replaceSelection : function(value) {\n            this.cm.replaceSelection(value);\n\n            return this;\n        },\n        \n        /**\n         * 在当前光标处插入新字符\n         * Insert a new character at the current cursor position\n         *\n         * 同replaceSelection()方法\n         * With the replaceSelection() method\n         * \n         * @param   {String}    value  要插入的字符值\n         * @returns {editormd}         返回editormd的实例对象\n         */\n        \n        insertValue : function(value) {\n            this.replaceSelection(value);\n\n            return this;\n        },\n        \n        /**\n         * 追加markdown\n         * append Markdown to editor\n         * \n         * @param   {String}    md     要追加的markdown源文档\n         * @returns {editormd}         返回editormd的实例对象\n         */\n        \n        appendMarkdown : function(md) {\n            var settings = this.settings;\n            var cm       = this.cm;\n            \n            cm.setValue(cm.getValue() + md);\n            \n            return this;\n        },\n        \n        /**\n         * 设置和传入编辑器的markdown源文档\n         * Set Markdown source document\n         * \n         * @param   {String}    md     要传入的markdown源文档\n         * @returns {editormd}         返回editormd的实例对象\n         */\n        \n        setMarkdown : function(md) {\n            this.cm.setValue(md || this.settings.markdown);\n            \n            return this;\n        },\n        \n        /**\n         * 获取编辑器的markdown源文档\n         * Set Editor.md markdown/CodeMirror value\n         * \n         * @returns {editormd}         返回editormd的实例对象\n         */\n        \n        getMarkdown : function() {\n            return this.cm.getValue();\n        },\n        \n        /**\n         * 获取编辑器的源文档\n         * Get CodeMirror value\n         * \n         * @returns {editormd}         返回editormd的实例对象\n         */\n        \n        getValue : function() {\n            return this.cm.getValue();\n        },\n        \n        /**\n         * 设置编辑器的源文档\n         * Set CodeMirror value\n         * \n         * @param   {String}     value   set code/value/string/text\n         * @returns {editormd}           返回editormd的实例对象\n         */\n        \n        setValue : function(value) {\n            this.cm.setValue(value);\n            \n            return this;\n        },\n        \n        /**\n         * 清空编辑器\n         * Empty CodeMirror editor container\n         * \n         * @returns {editormd}         返回editormd的实例对象\n         */\n        \n        clear : function() {\n            this.cm.setValue(\"\");\n            \n            return this;\n        },\n        \n        /**\n         * 获取解析后存放在Textarea的HTML源码\n         * Get parsed html code from Textarea\n         * \n         * @returns {String}               返回HTML源码\n         */\n        \n        getHTML : function() {\n            if (!this.settings.saveHTMLToTextarea)\n            {\n                alert(\"Error: settings.saveHTMLToTextarea == false\");\n\n                return false;\n            }\n            \n            return this.htmlTextarea.val();\n        },\n        \n        /**\n         * getHTML()的别名\n         * getHTML (alias)\n         * \n         * @returns {String}           Return html code 返回HTML源码\n         */\n        \n        getTextareaSavedHTML : function() {\n            return this.getHTML();\n        },\n        \n        /**\n         * 获取预览窗口的HTML源码\n         * Get html from preview container\n         * \n         * @returns {editormd}         返回editormd的实例对象\n         */\n        \n        getPreviewedHTML : function() {\n            if (!this.settings.watch)\n            {\n                alert(\"Error: settings.watch == false\");\n\n                return false;\n            }\n            \n            return this.previewContainer.html();\n        },\n        \n        /**\n         * 开启实时预览\n         * Enable real-time watching\n         * \n         * @returns {editormd}         返回editormd的实例对象\n         */\n        \n        watch : function(callback) {     \n            var settings        = this.settings;\n            \n            if ($.inArray(settings.mode, [\"gfm\", \"markdown\"]) < 0)\n            {\n                return this;\n            }\n            \n            this.state.watching = settings.watch = true;\n            this.preview.show();\n            \n            if (this.toolbar)\n            {\n                var watchIcon   = settings.toolbarIconsClass.watch;\n                var unWatchIcon = settings.toolbarIconsClass.unwatch;\n                \n                var icon        = this.toolbar.find(\".fa[name=watch]\");\n                icon.parent().attr(\"title\", settings.lang.toolbar.watch);\n                icon.removeClass(unWatchIcon).addClass(watchIcon);\n            }\n            \n            this.codeMirror.css(\"border-right\", \"1px solid #ddd\").width(this.editor.width() / 2); \n            \n            timer = 0;\n            \n            this.save().resize();\n            \n            if (!settings.onwatch)\n            {\n                settings.onwatch = callback || function() {};\n            }\n            \n            $.proxy(settings.onwatch, this)();\n            \n            return this;\n        },\n        \n        /**\n         * 关闭实时预览\n         * Disable real-time watching\n         * \n         * @returns {editormd}         返回editormd的实例对象\n         */\n        \n        unwatch : function(callback) {\n            var settings        = this.settings;\n            this.state.watching = settings.watch = false;\n            this.preview.hide();\n            \n            if (this.toolbar) \n            {\n                var watchIcon   = settings.toolbarIconsClass.watch;\n                var unWatchIcon = settings.toolbarIconsClass.unwatch;\n                \n                var icon    = this.toolbar.find(\".fa[name=watch]\");\n                icon.parent().attr(\"title\", settings.lang.toolbar.unwatch);\n                icon.removeClass(watchIcon).addClass(unWatchIcon);\n            }\n            \n            this.codeMirror.css(\"border-right\", \"none\").width(this.editor.width());\n            \n            this.resize();\n            \n            if (!settings.onunwatch)\n            {\n                settings.onunwatch = callback || function() {};\n            }\n            \n            $.proxy(settings.onunwatch, this)();\n            \n            return this;\n        },\n        \n        /**\n         * 显示编辑器\n         * Show editor\n         * \n         * @param   {Function} [callback=function()] 回调函数\n         * @returns {editormd}                       返回editormd的实例对象\n         */\n        \n        show : function(callback) {\n            callback  = callback || function() {};\n            \n            var _this = this;\n            this.editor.show(0, function() {\n                $.proxy(callback, _this)();\n            });\n            \n            return this;\n        },\n        \n        /**\n         * 隐藏编辑器\n         * Hide editor\n         * \n         * @param   {Function} [callback=function()] 回调函数\n         * @returns {editormd}                       返回editormd的实例对象\n         */\n        \n        hide : function(callback) {\n            callback  = callback || function() {};\n            \n            var _this = this;\n            this.editor.hide(0, function() {\n                $.proxy(callback, _this)();\n            });\n            \n            return this;\n        },\n        \n        /**\n         * 隐藏编辑器部分，只预览HTML\n         * Enter preview html state\n         * \n         * @returns {editormd}         返回editormd的实例对象\n         */\n        \n        previewing : function() {\n            \n            var _this            = this;\n            var editor           = this.editor;\n            var preview          = this.preview;\n            var toolbar          = this.toolbar;\n            var settings         = this.settings;\n            var codeMirror       = this.codeMirror;\n            var previewContainer = this.previewContainer;\n            \n            if ($.inArray(settings.mode, [\"gfm\", \"markdown\"]) < 0) {\n                return this;\n            }\n            \n            if (settings.toolbar && toolbar) {\n                toolbar.toggle();\n                toolbar.find(\".fa[name=preview]\").toggleClass(\"active\");\n            }\n            \n            codeMirror.toggle();\n            \n            var escHandle = function(event) {\n                if (event.shiftKey && event.keyCode === 27) {\n                    _this.previewed();\n                }\n            };\n\n            if (codeMirror.css(\"display\") === \"none\") // 为了兼容Zepto，而不使用codeMirror.is(\":hidden\")\n            {\n                this.state.preview = true;\n\n                if (this.state.fullscreen) {\n                    preview.css(\"background\", \"#fff\");\n                }\n                \n                editor.find(\".\" + this.classPrefix + \"preview-close-btn\").show().bind(editormd.mouseOrTouch(\"click\", \"touchend\"), function(){\n                    _this.previewed();\n                });\n            \n                if (!settings.watch)\n                {\n                    this.save();\n                } \n                else \n                {\n                    previewContainer.css(\"padding\", \"\");\n                }\n                \n                previewContainer.addClass(this.classPrefix + \"preview-active\");\n\n                preview.show().css({\n                    position  : \"\",\n                    top       : 0,\n                    width     : editor.width(),\n                    height    : (settings.autoHeight && !this.state.fullscreen) ? \"auto\" : editor.height()\n                });\n                \n                if (this.state.loaded)\n                {\n                    $.proxy(settings.onpreviewing, this)();\n                }\n\n                $(window).bind(\"keyup\", escHandle);\n            } \n            else \n            {\n                $(window).unbind(\"keyup\", escHandle);\n                this.previewed();\n            }\n        },\n        \n        /**\n         * 显示编辑器部分，退出只预览HTML\n         * Exit preview html state\n         * \n         * @returns {editormd}         返回editormd的实例对象\n         */\n        \n        previewed : function() {\n            \n            var editor           = this.editor;\n            var preview          = this.preview;\n            var toolbar          = this.toolbar;\n            var settings         = this.settings;\n            var previewContainer = this.previewContainer;\n            var previewCloseBtn  = editor.find(\".\" + this.classPrefix + \"preview-close-btn\");\n\n            this.state.preview   = false;\n            \n            this.codeMirror.show();\n            \n            if (settings.toolbar) {\n                toolbar.show();\n            }\n            \n            preview[(settings.watch) ? \"show\" : \"hide\"]();\n            \n            previewCloseBtn.hide().unbind(editormd.mouseOrTouch(\"click\", \"touchend\"));\n                \n            previewContainer.removeClass(this.classPrefix + \"preview-active\");\n                \n            if (settings.watch)\n            {\n                previewContainer.css(\"padding\", \"20px\");\n            }\n            \n            preview.css({ \n                background : null,\n                position   : \"absolute\",\n                width      : editor.width() / 2,\n                height     : (settings.autoHeight && !this.state.fullscreen) ? \"auto\" : editor.height() - toolbar.height(),\n                top        : (settings.toolbar)    ? toolbar.height() : 0\n            });\n\n            if (this.state.loaded)\n            {\n                $.proxy(settings.onpreviewed, this)();\n            }\n            \n            return this;\n        },\n        \n        /**\n         * 编辑器全屏显示\n         * Fullscreen show\n         * \n         * @returns {editormd}         返回editormd的实例对象\n         */\n        \n        fullscreen : function() {\n            \n            var _this            = this;\n            var state            = this.state;\n            var editor           = this.editor;\n            var preview          = this.preview;\n            var toolbar          = this.toolbar;\n            var settings         = this.settings;\n            var fullscreenClass  = this.classPrefix + \"fullscreen\";\n            \n            if (toolbar) {\n                toolbar.find(\".fa[name=fullscreen]\").parent().toggleClass(\"active\"); \n            }\n            \n            var escHandle = function(event) {\n                if (!event.shiftKey && event.keyCode === 27) \n                {\n                    if (state.fullscreen)\n                    {\n                        _this.fullscreenExit();\n                    }\n                }\n            };\n\n            if (!editor.hasClass(fullscreenClass)) \n            {\n                state.fullscreen = true;\n\n                $(\"html,body\").css(\"overflow\", \"hidden\");\n                \n                editor.css({\n                    width    : $(window).width(),\n                    height   : $(window).height()\n                }).addClass(fullscreenClass);\n\n                this.resize();\n    \n                $.proxy(settings.onfullscreen, this)();\n\n                $(window).bind(\"keyup\", escHandle);\n            }\n            else\n            {           \n                $(window).unbind(\"keyup\", escHandle); \n                this.fullscreenExit();\n            }\n\n            return this;\n        },\n        \n        /**\n         * 编辑器退出全屏显示\n         * Exit fullscreen state\n         * \n         * @returns {editormd}         返回editormd的实例对象\n         */\n        \n        fullscreenExit : function() {\n            \n            var editor            = this.editor;\n            var settings          = this.settings;\n            var toolbar           = this.toolbar;\n            var fullscreenClass   = this.classPrefix + \"fullscreen\";  \n            \n            this.state.fullscreen = false;\n            \n            if (toolbar) {\n                toolbar.find(\".fa[name=fullscreen]\").parent().removeClass(\"active\"); \n            }\n\n            $(\"html,body\").css(\"overflow\", \"\");\n\n            editor.css({\n                width    : editor.data(\"oldWidth\"),\n                height   : editor.data(\"oldHeight\")\n            }).removeClass(fullscreenClass);\n\n            this.resize();\n            \n            $.proxy(settings.onfullscreenExit, this)();\n\n            return this;\n        },\n        \n        /**\n         * 加载并执行插件\n         * Load and execute the plugin\n         * \n         * @param   {String}     name    plugin name / function name\n         * @param   {String}     path    plugin load path\n         * @returns {editormd}           返回editormd的实例对象\n         */\n        \n        executePlugin : function(name, path) {\n            \n            var _this    = this;\n            var cm       = this.cm;\n            var settings = this.settings;\n            \n            path = settings.pluginPath + path;\n            \n            if (typeof define === \"function\") \n            {            \n                if (typeof this[name] === \"undefined\")\n                {\n                    alert(\"Error: \" + name + \" plugin is not found, you are not load this plugin.\");\n                    \n                    return this;\n                }\n                \n                this[name](cm);\n                \n                return this;\n            }\n            \n            if ($.inArray(path, editormd.loadFiles.plugin) < 0)\n            {\n                editormd.loadPlugin(path, function() {\n                    editormd.loadPlugins[name] = _this[name];\n                    _this[name](cm);\n                });\n            }\n            else\n            {\n                $.proxy(editormd.loadPlugins[name], this)(cm);\n            }\n            \n            return this;\n        },\n                \n        /**\n         * 搜索替换\n         * Search & replace\n         * \n         * @param   {String}     command    CodeMirror serach commands, \"find, fintNext, fintPrev, clearSearch, replace, replaceAll\"\n         * @returns {editormd}              return this\n         */\n        \n        search : function(command) {\n            var settings = this.settings;\n            \n            if (!settings.searchReplace)\n            {\n                alert(\"Error: settings.searchReplace == false\");\n                return this;\n            }\n            \n            if (!settings.readOnly)\n            {\n                this.cm.execCommand(command || \"find\");\n            }\n            \n            return this;\n        },\n        \n        searchReplace : function() {            \n            this.search(\"replace\");\n            \n            return this;\n        },\n        \n        searchReplaceAll : function() {          \n            this.search(\"replaceAll\");\n            \n            return this;\n        }\n    };\n    \n    editormd.fn.init.prototype = editormd.fn; \n   \n    /**\n     * 锁屏\n     * lock screen when dialog opening\n     * \n     * @returns {void}\n     */\n\n    editormd.dialogLockScreen = function() {\n        var settings = this.settings || {dialogLockScreen : true};\n        \n        if (settings.dialogLockScreen) \n        {            \n            $(\"html,body\").css(\"overflow\", \"hidden\");\n            this.resize();\n        }\n    };\n   \n    /**\n     * 显示透明背景层\n     * Display mask layer when dialog opening\n     * \n     * @param   {Object}     dialog    dialog jQuery object\n     * @returns {void}\n     */\n    \n    editormd.dialogShowMask = function(dialog) {\n        var editor   = this.editor;\n        var settings = this.settings || {dialogShowMask : true};\n        \n        dialog.css({\n            top  : ($(window).height() - dialog.height()) / 2 + \"px\",\n            left : ($(window).width()  - dialog.width())  / 2 + \"px\"\n        });\n\n        if (settings.dialogShowMask) {\n            editor.children(\".\" + this.classPrefix + \"mask\").css(\"z-index\", parseInt(dialog.css(\"z-index\")) - 1).show();\n        }\n    };\n\n    editormd.toolbarHandlers = {\n        undo : function() {\n            this.cm.undo();\n        },\n        \n        redo : function() {\n            this.cm.redo();\n        },\n        \n        bold : function() {\n            var cm        = this.cm;\n            var cursor    = cm.getCursor();\n            var selection = cm.getSelection();\n\n            cm.replaceSelection(\"**\" + selection + \"**\");\n\n            if(selection === \"\") {\n                cm.setCursor(cursor.line, cursor.ch + 2);\n            }\n        },\n        \n        del : function() {\n            var cm        = this.cm;\n            var cursor    = cm.getCursor();\n            var selection = cm.getSelection();\n\n            cm.replaceSelection(\"~~\" + selection + \"~~\");\n\n            if(selection === \"\") {\n                cm.setCursor(cursor.line, cursor.ch + 2);\n            }\n        },\n\n        italic : function() {\n            var cm        = this.cm;\n            var cursor    = cm.getCursor();\n            var selection = cm.getSelection();\n\n            cm.replaceSelection(\"*\" + selection + \"*\");\n\n            if(selection === \"\") {\n                cm.setCursor(cursor.line, cursor.ch + 1);\n            }\n        },\n\n        quote : function() {\n            var cm        = this.cm;\n            var cursor    = cm.getCursor();\n            var selection = cm.getSelection();\n\n            if (cursor.ch !== 0)\n            {\n                cm.setCursor(cursor.line, 0);\n                cm.replaceSelection(\"> \" + selection);\n                cm.setCursor(cursor.line, cursor.ch + 2);\n            }\n            else\n            {\n                cm.replaceSelection(\"> \" + selection);\n            }\n\n            //cm.replaceSelection(\"> \" + selection);\n            //cm.setCursor(cursor.line, (selection === \"\") ? cursor.ch + 2 : cursor.ch + selection.length + 2);\n        },\n        \n        ucfirst : function() {\n            var cm         = this.cm;\n            var selection  = cm.getSelection();\n            var selections = cm.listSelections();\n\n            cm.replaceSelection(editormd.firstUpperCase(selection));\n            cm.setSelections(selections);\n        },\n        \n        ucwords : function() {\n            var cm         = this.cm;\n            var selection  = cm.getSelection();\n            var selections = cm.listSelections();\n\n            cm.replaceSelection(editormd.wordsFirstUpperCase(selection));\n            cm.setSelections(selections);\n        },\n        \n        uppercase : function() {\n            var cm         = this.cm;\n            var selection  = cm.getSelection();\n            var selections = cm.listSelections();\n\n            cm.replaceSelection(selection.toUpperCase());\n            cm.setSelections(selections);\n        },\n        \n        lowercase : function() {\n            var cm         = this.cm;\n            var cursor     = cm.getCursor();\n            var selection  = cm.getSelection();\n            var selections = cm.listSelections();\n            \n            cm.replaceSelection(selection.toLowerCase());\n            cm.setSelections(selections);\n        },\n\n        h1 : function() {\n            var cm        = this.cm;\n            var cursor    = cm.getCursor();\n            var selection = cm.getSelection();\n\n            if (cursor.ch !== 0)\n            {\n                cm.setCursor(cursor.line, 0);\n                cm.replaceSelection(\"# \" + selection);\n                cm.setCursor(cursor.line, cursor.ch + 2);\n            }\n            else\n            {\n                cm.replaceSelection(\"# \" + selection);\n            }\n        },\n\n        h2 : function() {\n            var cm        = this.cm;\n            var cursor    = cm.getCursor();\n            var selection = cm.getSelection();\n\n            if (cursor.ch !== 0)\n            {\n                cm.setCursor(cursor.line, 0);\n                cm.replaceSelection(\"## \" + selection);\n                cm.setCursor(cursor.line, cursor.ch + 3);\n            }\n            else\n            {\n                cm.replaceSelection(\"## \" + selection);\n            }\n        },\n\n        h3 : function() {\n            var cm        = this.cm;\n            var cursor    = cm.getCursor();\n            var selection = cm.getSelection();\n\n            if (cursor.ch !== 0)\n            {\n                cm.setCursor(cursor.line, 0);\n                cm.replaceSelection(\"### \" + selection);\n                cm.setCursor(cursor.line, cursor.ch + 4);\n            }\n            else\n            {\n                cm.replaceSelection(\"### \" + selection);\n            }\n        },\n\n        h4 : function() {\n            var cm        = this.cm;\n            var cursor    = cm.getCursor();\n            var selection = cm.getSelection();\n\n            if (cursor.ch !== 0)\n            {\n                cm.setCursor(cursor.line, 0);\n                cm.replaceSelection(\"#### \" + selection);\n                cm.setCursor(cursor.line, cursor.ch + 5);\n            }\n            else\n            {\n                cm.replaceSelection(\"#### \" + selection);\n            }\n        },\n\n        h5 : function() {\n            var cm        = this.cm;\n            var cursor    = cm.getCursor();\n            var selection = cm.getSelection();\n\n            if (cursor.ch !== 0)\n            {\n                cm.setCursor(cursor.line, 0);\n                cm.replaceSelection(\"##### \" + selection);\n                cm.setCursor(cursor.line, cursor.ch + 6);\n            }\n            else\n            {\n                cm.replaceSelection(\"##### \" + selection);\n            }\n        },\n\n        h6 : function() {\n            var cm        = this.cm;\n            var cursor    = cm.getCursor();\n            var selection = cm.getSelection();\n\n            if (cursor.ch !== 0)\n            {\n                cm.setCursor(cursor.line, 0);\n                cm.replaceSelection(\"###### \" + selection);\n                cm.setCursor(cursor.line, cursor.ch + 7);\n            }\n            else\n            {\n                cm.replaceSelection(\"###### \" + selection);\n            }\n        },\n\n        \"list-ul\" : function() {\n            var cm        = this.cm;\n            var cursor    = cm.getCursor();\n            var selection = cm.getSelection();\n\n            if (selection === \"\") \n            {\n                cm.replaceSelection(\"- \" + selection);\n            } \n            else \n            {\n                var selectionText = selection.split(\"\\n\");\n\n                for (var i = 0, len = selectionText.length; i < len; i++) \n                {\n                    selectionText[i] = (selectionText[i] === \"\") ? \"\" : \"- \" + selectionText[i];\n                }\n\n                cm.replaceSelection(selectionText.join(\"\\n\"));\n            }\n        },\n\n        \"list-ol\" : function() {\n            var cm        = this.cm;\n            var cursor    = cm.getCursor();\n            var selection = cm.getSelection();\n\n            if(selection === \"\") \n            {\n                cm.replaceSelection(\"1. \" + selection);\n            }\n            else\n            {\n                var selectionText = selection.split(\"\\n\");\n\n                for (var i = 0, len = selectionText.length; i < len; i++) \n                {\n                    selectionText[i] = (selectionText[i] === \"\") ? \"\" : (i+1) + \". \" + selectionText[i];\n                }\n\n                cm.replaceSelection(selectionText.join(\"\\n\"));\n            }\n        },\n\n        hr : function() {\n            var cm        = this.cm;\n            var cursor    = cm.getCursor();\n            var selection = cm.getSelection();\n\n            cm.replaceSelection(((cursor.ch !== 0) ? \"\\n\\n\" : \"\\n\") + \"------------\\n\\n\");\n        },\n\n        tex : function() {\n            if (!this.settings.tex)\n            {\n                alert(\"settings.tex === false\");\n                return this;\n            }\n            \n            var cm        = this.cm;\n            var cursor    = cm.getCursor();\n            var selection = cm.getSelection();\n\n            cm.replaceSelection(\"$$\" + selection + \"$$\");\n\n            if(selection === \"\") {\n                cm.setCursor(cursor.line, cursor.ch + 2);\n            }\n        },\n\n        link : function() {\n            this.executePlugin(\"linkDialog\", \"link-dialog/link-dialog\");\n        },\n\n        \"reference-link\" : function() {\n            this.executePlugin(\"referenceLinkDialog\", \"reference-link-dialog/reference-link-dialog\");\n        },\n\n        pagebreak : function() {\n            if (!this.settings.pageBreak)\n            {\n                alert(\"settings.pageBreak === false\");\n                return this;\n            }\n            \n            var cm        = this.cm;\n            var selection = cm.getSelection();\n\n            cm.replaceSelection(\"\\r\\n[========]\\r\\n\");\n        },\n\n        image : function() {\n            this.executePlugin(\"imageDialog\", \"image-dialog/image-dialog\");\n        },\n        \n        code : function() {\n            var cm        = this.cm;\n            var cursor    = cm.getCursor();\n            var selection = cm.getSelection();\n\n            cm.replaceSelection(\"`\" + selection + \"`\");\n\n            if (selection === \"\") {\n                cm.setCursor(cursor.line, cursor.ch + 1);\n            }\n        },\n\n        \"code-block\" : function() {\n            this.executePlugin(\"codeBlockDialog\", \"code-block-dialog/code-block-dialog\");            \n        },\n\n        \"preformatted-text\" : function() {\n            this.executePlugin(\"preformattedTextDialog\", \"preformatted-text-dialog/preformatted-text-dialog\");\n        },\n        \n        table : function() {\n            this.executePlugin(\"tableDialog\", \"table-dialog/table-dialog\");         \n        },\n        \n        datetime : function() {\n            var cm        = this.cm;\n            var selection = cm.getSelection();\n            var date      = new Date();\n            var langName  = this.settings.lang.name;\n            var datefmt   = editormd.dateFormat() + \" \" + editormd.dateFormat((langName === \"zh-cn\" || langName === \"zh-tw\") ? \"cn-week-day\" : \"week-day\");\n\n            cm.replaceSelection(datefmt);\n        },\n        \n        emoji : function() {\n            this.executePlugin(\"emojiDialog\", \"emoji-dialog/emoji-dialog\");\n        },\n                \n        \"html-entities\" : function() {\n            this.executePlugin(\"htmlEntitiesDialog\", \"html-entities-dialog/html-entities-dialog\");\n        },\n                \n        \"goto-line\" : function() {\n            this.executePlugin(\"gotoLineDialog\", \"goto-line-dialog/goto-line-dialog\");\n        },\n\n        watch : function() {    \n            this[this.settings.watch ? \"unwatch\" : \"watch\"]();\n        },\n\n        preview : function() {\n            this.previewing();\n        },\n\n        fullscreen : function() {\n            this.fullscreen();\n        },\n\n        clear : function() {\n            this.clear();\n        },\n        \n        search : function() {\n            this.search();\n        },\n\n        help : function() {\n            this.executePlugin(\"helpDialog\", \"help-dialog/help-dialog\");\n        },\n\n        info : function() {\n            this.showInfoDialog();\n        }\n    };\n    \n    editormd.keyMaps = {\n        \"Ctrl-1\"       : \"h1\",\n        \"Ctrl-2\"       : \"h2\",\n        \"Ctrl-3\"       : \"h3\",\n        \"Ctrl-4\"       : \"h4\",\n        \"Ctrl-5\"       : \"h5\",\n        \"Ctrl-6\"       : \"h6\",\n        \"Ctrl-B\"       : \"bold\",  // if this is string ==  editormd.toolbarHandlers.xxxx\n        \"Ctrl-D\"       : \"datetime\",\n        \n        \"Ctrl-E\"       : function() { // emoji\n            var cm        = this.cm;\n            var cursor    = cm.getCursor();\n            var selection = cm.getSelection();\n            \n            if (!this.settings.emoji)\n            {\n                alert(\"Error: settings.emoji == false\");\n                return ;\n            }\n\n            cm.replaceSelection(\":\" + selection + \":\");\n\n            if (selection === \"\") {\n                cm.setCursor(cursor.line, cursor.ch + 1);\n            }\n        },\n        \"Ctrl-Alt-G\"   : \"goto-line\",\n        \"Ctrl-H\"       : \"hr\",\n        \"Ctrl-I\"       : \"italic\",\n        \"Ctrl-K\"       : \"code\",\n        \n        \"Ctrl-L\"        : function() {\n            var cm        = this.cm;\n            var cursor    = cm.getCursor();\n            var selection = cm.getSelection();\n            \n            var title = (selection === \"\") ? \"\" : \" \\\"\"+selection+\"\\\"\";\n\n            cm.replaceSelection(\"[\" + selection + \"](\"+title+\")\");\n\n            if (selection === \"\") {\n                cm.setCursor(cursor.line, cursor.ch + 1);\n            }\n        },\n        \"Ctrl-U\"         : \"list-ul\",\n        \n        \"Shift-Ctrl-A\"   : function() {\n            var cm        = this.cm;\n            var cursor    = cm.getCursor();\n            var selection = cm.getSelection();\n            \n            if (!this.settings.atLink)\n            {\n                alert(\"Error: settings.atLink == false\");\n                return ;\n            }\n\n            cm.replaceSelection(\"@\" + selection);\n\n            if (selection === \"\") {\n                cm.setCursor(cursor.line, cursor.ch + 1);\n            }\n        },\n        \n        \"Shift-Ctrl-C\"     : \"code\",\n        \"Shift-Ctrl-Q\"     : \"quote\",\n        \"Shift-Ctrl-S\"     : \"del\",\n        \"Shift-Ctrl-K\"     : \"tex\",  // KaTeX\n        \n        \"Shift-Alt-C\"      : function() {\n            var cm        = this.cm;\n            var cursor    = cm.getCursor();\n            var selection = cm.getSelection();\n            \n            cm.replaceSelection([\"```\", selection, \"```\"].join(\"\\n\"));\n\n            if (selection === \"\") {\n                cm.setCursor(cursor.line, cursor.ch + 3);\n            } \n        },\n        \n        \"Shift-Ctrl-Alt-C\" : \"code-block\",\n        \"Shift-Ctrl-H\"     : \"html-entities\",\n        \"Shift-Alt-H\"      : \"help\",\n        \"Shift-Ctrl-E\"     : \"emoji\",\n        \"Shift-Ctrl-U\"     : \"uppercase\",\n        \"Shift-Alt-U\"      : \"ucwords\",\n        \"Shift-Ctrl-Alt-U\" : \"ucfirst\",\n        \"Shift-Alt-L\"      : \"lowercase\",\n        \n        \"Shift-Ctrl-I\"     : function() {\n            var cm        = this.cm;\n            var cursor    = cm.getCursor();\n            var selection = cm.getSelection();\n            \n            var title = (selection === \"\") ? \"\" : \" \\\"\"+selection+\"\\\"\";\n\n            cm.replaceSelection(\"![\" + selection + \"](\"+title+\")\");\n\n            if (selection === \"\") {\n                cm.setCursor(cursor.line, cursor.ch + 4);\n            }\n        },\n        \n        \"Shift-Ctrl-Alt-I\" : \"image\",\n        \"Shift-Ctrl-L\"     : \"link\",\n        \"Shift-Ctrl-O\"     : \"list-ol\",\n        \"Shift-Ctrl-P\"     : \"preformatted-text\",\n        \"Shift-Ctrl-T\"     : \"table\",\n        \"Shift-Alt-P\"      : \"pagebreak\",\n        \"F9\"               : \"watch\",\n        \"F10\"              : \"preview\",\n        \"F11\"              : \"fullscreen\",\n    };\n    \n    /**\n     * 清除字符串两边的空格\n     * Clear the space of strings both sides.\n     * \n     * @param   {String}    str            string\n     * @returns {String}                   trimed string    \n     */\n    \n    var trim = function(str) {\n        return (!String.prototype.trim) ? str.replace(/^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g, \"\") : str.trim();\n    };\n    \n    editormd.trim = trim;\n    \n    /**\n     * 所有单词首字母大写\n     * Words first to uppercase\n     * \n     * @param   {String}    str            string\n     * @returns {String}                   string\n     */\n    \n    var ucwords = function (str) {\n        return str.toLowerCase().replace(/\\b(\\w)|\\s(\\w)/g, function($1) {  \n            return $1.toUpperCase();\n        });\n    };\n    \n    editormd.ucwords = editormd.wordsFirstUpperCase = ucwords;\n    \n    /**\n     * 字符串首字母大写\n     * Only string first char to uppercase\n     * \n     * @param   {String}    str            string\n     * @returns {String}                   string\n     */\n    \n    var firstUpperCase = function(str) {        \n        return str.toLowerCase().replace(/\\b(\\w)/, function($1){\n            return $1.toUpperCase();\n        });\n    };\n    \n    var ucfirst = firstUpperCase;\n    \n    editormd.firstUpperCase = editormd.ucfirst = firstUpperCase;\n    \n    editormd.urls = {\n        atLinkBase : \"https://github.com/\"\n    };\n    \n    editormd.regexs = {\n        atLink        : /@(\\w+)/g,\n        email         : /(\\w+)@(\\w+)\\.(\\w+)\\.?(\\w+)?/g,\n        emailLink     : /(mailto:)?([\\w\\.\\_]+)@(\\w+)\\.(\\w+)\\.?(\\w+)?/g,\n        emoji         : /:([\\w\\+-]+):/g,\n        emojiDatetime : /(\\d{2}:\\d{2}:\\d{2})/g,\n        twemoji       : /:(tw-([\\w]+)-?(\\w+)?):/g,\n        fontAwesome   : /:(fa-([\\w]+)(-(\\w+)){0,}):/g,\n        editormdLogo  : /:(editormd-logo-?(\\w+)?):/g,\n        pageBreak     : /^\\[[=]{8,}\\]$/\n    };\n\n    // Emoji graphics files url path\n    editormd.emoji     = {\n        path  : \"http://www.emoji-cheat-sheet.com/graphics/emojis/\",\n        ext   : \".png\"\n    };\n\n    // Twitter Emoji (Twemoji)  graphics files url path    \n    editormd.twemoji = {\n        path : \"http://twemoji.maxcdn.com/36x36/\",\n        ext  : \".png\"\n    };\n\n    /**\n     * 自定义marked的解析器\n     * Custom Marked renderer rules\n     * \n     * @param   {Array}    markdownToC     传入用于接收TOC的数组\n     * @returns {Renderer} markedRenderer  返回marked的Renderer自定义对象\n     */\n\n    editormd.markedRenderer = function(markdownToC, options) {\n        var defaults = {\n            toc                  : true,           // Table of contents\n            tocm                 : false,\n            tocStartLevel        : 1,              // Said from H1 to create ToC  \n            pageBreak            : true,\n            atLink               : true,           // for @link\n            emailLink            : true,           // for mail address auto link\n            taskList             : false,          // Enable Github Flavored Markdown task lists\n            emoji                : false,          // :emoji: , Support Twemoji, fontAwesome, Editor.md logo emojis.\n            tex                  : false,          // TeX(LaTeX), based on KaTeX\n            flowChart            : false,          // flowChart.js only support IE9+\n            sequenceDiagram      : false,          // sequenceDiagram.js only support IE9+\n        };\n        \n        var settings        = $.extend(defaults, options || {});    \n        var marked          = editormd.$marked;\n        var markedRenderer  = new marked.Renderer();\n        markdownToC         = markdownToC || [];        \n            \n        var regexs          = editormd.regexs;\n        var atLinkReg       = regexs.atLink;\n        var emojiReg        = regexs.emoji;\n        var emailReg        = regexs.email;\n        var emailLinkReg    = regexs.emailLink;\n        var twemojiReg      = regexs.twemoji;\n        var faIconReg       = regexs.fontAwesome;\n        var editormdLogoReg = regexs.editormdLogo;\n        var pageBreakReg    = regexs.pageBreak;\n\n        markedRenderer.emoji = function(text) {\n            \n            text = text.replace(editormd.regexs.emojiDatetime, function($1) {           \n                return $1.replace(/:/g, \"&#58;\");\n            });\n            \n            var matchs = text.match(emojiReg);\n\n            if (!matchs || !settings.emoji) {\n                return text;\n            }\n\n            for (var i = 0, len = matchs.length; i < len; i++)\n            {            \n                if (matchs[i] === \":+1:\") {\n                    matchs[i] = \":\\\\+1:\";\n                }\n\n                text = text.replace(new RegExp(matchs[i]), function($1, $2){\n                    var faMatchs = $1.match(faIconReg);\n                    var name     = $1.replace(/:/g, \"\");\n\n                    if (faMatchs)\n                    {                        \n                        for (var fa = 0, len1 = faMatchs.length; fa < len1; fa++)\n                        {\n                            var faName = faMatchs[fa].replace(/:/g, \"\");\n                            \n                            return \"<i class=\\\"fa \" + faName + \" fa-emoji\\\" title=\\\"\" + faName.replace(\"fa-\", \"\") + \"\\\"></i>\";\n                        }\n                    }\n                    else\n                    {\n                        var emdlogoMathcs = $1.match(editormdLogoReg);\n                        var twemojiMatchs = $1.match(twemojiReg);\n\n                        if (emdlogoMathcs)                                        \n                        {                            \n                            for (var x = 0, len2 = emdlogoMathcs.length; x < len2; x++)\n                            {\n                                var logoName = emdlogoMathcs[x].replace(/:/g, \"\");\n                                return \"<i class=\\\"\" + logoName + \"\\\" title=\\\"Editor.md logo (\" + logoName + \")\\\"></i>\";\n                            }\n                        }\n                        else if (twemojiMatchs) \n                        {\n                            for (var t = 0, len3 = twemojiMatchs.length; t < len3; t++)\n                            {\n                                var twe = twemojiMatchs[t].replace(/:/g, \"\").replace(\"tw-\", \"\");\n                                return \"<img src=\\\"\" + editormd.twemoji.path + twe + editormd.twemoji.ext + \"\\\" title=\\\"twemoji-\" + twe + \"\\\" alt=\\\"twemoji-\" + twe + \"\\\" class=\\\"emoji twemoji\\\" />\";\n                            }\n                        }\n                        else\n                        {\n                            var src = (name === \"+1\") ? \"plus1\" : name;\n                            src     = (src === \"black_large_square\") ? \"black_square\" : src;\n                            src     = (src === \"moon\") ? \"waxing_gibbous_moon\" : src;\n\n                            return \"<img src=\\\"\" + editormd.emoji.path + src + editormd.emoji.ext + \"\\\" class=\\\"emoji\\\" title=\\\"&#58;\" + name + \"&#58;\\\" alt=\\\"&#58;\" + name + \"&#58;\\\" />\";\n                        }\n                    }\n                });\n            }\n\n            return text;\n        };\n\n        markedRenderer.atLink = function(text) {\n\n            if (atLinkReg.test(text))\n            { \n                if (settings.atLink) \n                {\n                    text = text.replace(emailReg, function($1, $2, $3, $4) {\n                        return $1.replace(/@/g, \"_#_&#64;_#_\");\n                    });\n\n                    text = text.replace(atLinkReg, function($1, $2) {\n                        return \"<a href=\\\"\" + editormd.urls.atLinkBase + \"\" + $2 + \"\\\" title=\\\"&#64;\" + $2 + \"\\\" class=\\\"at-link\\\">\" + $1 + \"</a>\";\n                    }).replace(/_#_&#64;_#_/g, \"@\");\n                }\n                \n                if (settings.emailLink)\n                {\n                    text = text.replace(emailLinkReg, function($1, $2, $3, $4, $5) {\n                        return (!$2 && $.inArray($5, \"jpg|jpeg|png|gif|webp|ico|icon|pdf\".split(\"|\")) < 0) ? \"<a href=\\\"mailto:\" + $1 + \"\\\">\"+$1+\"</a>\" : $1;\n                    });\n                }\n\n                return text;\n            }\n\n            return text;\n        };\n                \n        markedRenderer.link = function (href, title, text) {\n\n            if (this.options.sanitize) {\n                try {\n                    var prot = decodeURIComponent(unescape(href)).replace(/[^\\w:]/g,\"\").toLowerCase();\n                } catch(e) {\n                    return \"\";\n                }\n\n                if (prot.indexOf(\"javascript:\") === 0) {\n                    return \"\";\n                }\n            }\n\n            var out = \"<a href=\\\"\" + href + \"\\\"\";\n            \n            if (atLinkReg.test(title) || atLinkReg.test(text))\n            {\n                if (title)\n                {\n                    out += \" title=\\\"\" + title.replace(/@/g, \"&#64;\");\n                }\n                \n                return out + \"\\\">\" + text.replace(/@/g, \"&#64;\") + \"</a>\";\n            }\n\n            if (title) {\n                out += \" title=\\\"\" + title + \"\\\"\";\n            }\n\n            out += \">\" + text + \"</a>\";\n\n            return out;\n        };\n        \n        markedRenderer.heading = function(text, level, raw) {\n                    \n            var linkText       = text;\n            var hasLinkReg     = /\\s*\\<a\\s*href\\=\\\"(.*)\\\"\\s*([^\\>]*)\\>(.*)\\<\\/a\\>\\s*/;\n            var getLinkTextReg = /\\s*\\<a\\s*([^\\>]+)\\>([^\\>]*)\\<\\/a\\>\\s*/g;\n\n            if (hasLinkReg.test(text)) \n            {\n                var tempText = [];\n                text         = text.split(/\\<a\\s*([^\\>]+)\\>([^\\>]*)\\<\\/a\\>/);\n\n                for (var i = 0, len = text.length; i < len; i++)\n                {\n                    tempText.push(text[i].replace(/\\s*href\\=\\\"(.*)\\\"\\s*/g, \"\"));\n                }\n\n                text = tempText.join(\" \");\n            }\n            \n            text = trim(text);\n            \n            var escapedText    = text.toLowerCase().replace(/[^\\w]+/g, \"-\");\n            var toc = {\n                text  : text,\n                level : level,\n                slug  : escapedText\n            };\n            \n            var isChinese = /^[\\u4e00-\\u9fa5]+$/.test(text);\n            var id        = (isChinese) ? escape(text).replace(/\\%/g, \"\") : text.toLowerCase().replace(/[^\\w]+/g, \"-\");\n\n            markdownToC.push(toc);\n            \n            var headingHTML = \"<h\" + level + \" id=\\\"h\"+ level + \"-\" + this.options.headerPrefix + id +\"\\\">\";\n            \n            headingHTML    += \"<a name=\\\"\" + text + \"\\\" class=\\\"reference-link\\\"></a>\";\n            headingHTML    += \"<span class=\\\"header-link octicon octicon-link\\\"></span>\";\n            headingHTML    += (hasLinkReg) ? this.atLink(this.emoji(linkText)) : this.atLink(this.emoji(text));\n            headingHTML    += \"</h\" + level + \">\";\n\n            return headingHTML;\n        };\n        \n        markedRenderer.pageBreak = function(text) {\n            if (pageBreakReg.test(text) && settings.pageBreak)\n            {\n                text = \"<hr style=\\\"page-break-after:always;\\\" class=\\\"page-break editormd-page-break\\\" />\";\n            }\n            \n            return text;\n        };\n\n        markedRenderer.paragraph = function(text) {\n            var isTeXInline     = /\\$\\$(.*)\\$\\$/g.test(text);\n            var isTeXLine       = /^\\$\\$(.*)\\$\\$$/.test(text);\n            var isTeXAddClass   = (isTeXLine)     ? \" class=\\\"\" + editormd.classNames.tex + \"\\\"\" : \"\";\n            var isToC           = (settings.tocm) ? /^(\\[TOC\\]|\\[TOCM\\])$/.test(text) : /^\\[TOC\\]$/.test(text);\n            var isToCMenu       = /^\\[TOCM\\]$/.test(text);\n            \n            if (!isTeXLine && isTeXInline) \n            {\n                text = text.replace(/(\\$\\$([^\\$]*)\\$\\$)+/g, function($1, $2) {\n                    return \"<span class=\\\"\" + editormd.classNames.tex + \"\\\">\" + $2.replace(/\\$/g, \"\") + \"</span>\";\n                });\n            } \n            else \n            {\n                text = (isTeXLine) ? text.replace(/\\$/g, \"\") : text;\n            }\n            \n            var tocHTML = \"<div class=\\\"markdown-toc editormd-markdown-toc\\\">\" + text + \"</div>\";\n            \n            return (isToC) ? ( (isToCMenu) ? \"<div class=\\\"editormd-toc-menu\\\">\" + tocHTML + \"</div><br/>\" : tocHTML )\n                           : ( (pageBreakReg.test(text)) ? this.pageBreak(text) : \"<p\" + isTeXAddClass + \">\" + this.atLink(this.emoji(text)) + \"</p>\\n\" );\n        };\n\n        markedRenderer.code = function (code, lang, escaped) { \n\n            if (lang === \"seq\" || lang === \"sequence\")\n            {\n                return \"<div class=\\\"sequence-diagram\\\">\" + code + \"</div>\";\n            } \n            else if ( lang === \"flow\")\n            {\n                return \"<div class=\\\"flowchart\\\">\" + code + \"</div>\";\n            } \n            else if ( lang === \"math\" || lang === \"latex\" || lang === \"katex\")\n            {\n                return \"<p class=\\\"\" + editormd.classNames.tex + \"\\\">\" + code + \"</p>\";\n            } \n            else \n            {\n\n                return marked.Renderer.prototype.code.apply(this, arguments);\n            }\n        };\n\n        markedRenderer.tablecell = function(content, flags) {\n            var type = (flags.header) ? \"th\" : \"td\";\n            var tag  = (flags.align)  ? \"<\" + type +\" style=\\\"text-align:\" + flags.align + \"\\\">\" : \"<\" + type + \">\";\n            \n            return tag + this.atLink(this.emoji(content)) + \"</\" + type + \">\\n\";\n        };\n\n        markedRenderer.listitem = function(text) {\n            if (settings.taskList && /^\\s*\\[[x\\s]\\]\\s*/.test(text)) \n            {\n                text = text.replace(/^\\s*\\[\\s\\]\\s*/, \"<input type=\\\"checkbox\\\" class=\\\"task-list-item-checkbox\\\" /> \")\n                           .replace(/^\\s*\\[x\\]\\s*/,  \"<input type=\\\"checkbox\\\" class=\\\"task-list-item-checkbox\\\" checked disabled /> \");\n\n                return \"<li style=\\\"list-style: none;\\\">\" + this.atLink(this.emoji(text)) + \"</li>\";\n            }\n            else \n            {\n                return \"<li>\" + this.atLink(this.emoji(text)) + \"</li>\";\n            }\n        };\n        \n        return markedRenderer;\n    };\n    \n    /**\n     *\n     * 生成TOC(Table of Contents)\n     * Creating ToC (Table of Contents)\n     * \n     * @param   {Array}    toc             从marked获取的TOC数组列表\n     * @param   {Element}  container       插入TOC的容器元素\n     * @param   {Integer}  startLevel      Hx 起始层级\n     * @returns {Object}   tocContainer    返回ToC列表容器层的jQuery对象元素\n     */\n    \n    editormd.markdownToCRenderer = function(toc, container, tocDropdown, startLevel) {\n        \n        var html        = \"\";    \n        var lastLevel   = 0;\n        var classPrefix = this.classPrefix;\n        \n        startLevel      = startLevel  || 1;\n        \n        for (var i = 0, len = toc.length; i < len; i++) \n        {\n            var text  = toc[i].text;\n            var level = toc[i].level;\n            \n            if (level < startLevel) {\n                continue;\n            }\n            \n            if (level > lastLevel) \n            {\n                html += \"\";\n            }\n            else if (level < lastLevel) \n            {\n                html += (new Array(lastLevel - level + 2)).join(\"</ul></li>\");\n            } \n            else \n            {\n                html += \"</ul></li>\";\n            }\n\n            html += \"<li><a class=\\\"toc-level-\" + level + \"\\\" href=\\\"#\" + text + \"\\\" level=\\\"\" + level + \"\\\">\" + text + \"</a><ul>\";\n            lastLevel = level;\n        }\n        \n        var tocContainer = container.find(\".markdown-toc\");\n        \n        if ((tocContainer.length < 1 && container.attr(\"previewContainer\") === \"false\"))\n        {\n            var tocHTML = \"<div class=\\\"markdown-toc \" + classPrefix + \"markdown-toc\\\"></div>\";\n            \n            tocHTML = (tocDropdown) ? \"<div class=\\\"\" + classPrefix + \"toc-menu\\\">\" + tocHTML + \"</div>\" : tocHTML;\n            \n            container.html(tocHTML);\n            \n            tocContainer = container.find(\".markdown-toc\");\n        }\n        \n        if (tocDropdown)\n        {\n            tocContainer.wrap(\"<div class=\\\"\" + classPrefix + \"toc-menu\\\"></div><br/>\");\n        }\n        \n        tocContainer.html(\"<ul class=\\\"markdown-toc-list\\\"></ul>\").children(\".markdown-toc-list\").html(html.replace(/\\r?\\n?\\<ul\\>\\<\\/ul\\>/g, \"\"));\n        \n        return tocContainer;\n    };\n    \n    /**\n     *\n     * 生成TOC下拉菜单\n     * Creating ToC dropdown menu\n     * \n     * @param   {Object}   container       插入TOC的容器jQuery对象元素\n     * @param   {String}   tocTitle        ToC title\n     * @returns {Object}                   return toc-menu object\n     */\n    \n    editormd.tocDropdownMenu = function(container, tocTitle) {\n        \n        tocTitle      = tocTitle || \"Table of Contents\";\n        \n        var zindex    = 400;\n        var tocMenus  = container.find(\".\" + this.classPrefix + \"toc-menu\");\n\n        tocMenus.each(function() {\n            var $this  = $(this);\n            var toc    = $this.children(\".markdown-toc\");\n            var icon   = \"<i class=\\\"fa fa-angle-down\\\"></i>\";\n            var btn    = \"<a href=\\\"javascript:;\\\" class=\\\"toc-menu-btn\\\">\" + icon + tocTitle + \"</a>\";\n            var menu   = toc.children(\"ul\");            \n            var list   = menu.find(\"li\");\n            \n            toc.append(btn);\n            \n            list.first().before(\"<li><h1>\" + tocTitle + \" \" + icon + \"</h1></li>\");\n            \n            $this.mouseover(function(){\n                menu.show();\n\n                list.each(function(){\n                    var li = $(this);\n                    var ul = li.children(\"ul\");\n\n                    if (ul.html() === \"\")\n                    {\n                        ul.remove();\n                    }\n\n                    if (ul.length > 0 && ul.html() !== \"\")\n                    {\n                        var firstA = li.children(\"a\").first();\n\n                        if (firstA.children(\".fa\").length < 1)\n                        {\n                            firstA.append( $(icon).css({ float:\"right\", paddingTop:\"4px\" }) );\n                        }\n                    }\n\n                    li.mouseover(function(){\n                        ul.css(\"z-index\", zindex).show();\n                        zindex += 1;\n                    }).mouseleave(function(){\n                        ul.hide();\n                    });\n                });\n            }).mouseleave(function(){\n                menu.hide();\n            }); \n        });       \n        \n        return tocMenus;\n    };\n    \n    /**\n     * 简单地过滤指定的HTML标签\n     * Filter custom html tags\n     * \n     * @param   {String}   html          要过滤HTML\n     * @param   {String}   filters       要过滤的标签\n     * @returns {String}   html          返回过滤的HTML\n     */\n    \n    editormd.filterHTMLTags = function(html, filters) {\n        \n        if (typeof html !== \"string\") {\n            html = new String(html);\n        }\n            \n        if (typeof filters !== \"string\") {\n            return html;\n        }\n\n        var expression = filters.split(\"|\");\n        var filterTags = expression[0].split(\",\");\n        var attrs      = expression[1];\n\n        for (var i = 0, len = filterTags.length; i < len; i++)\n        {\n            var tag = filterTags[i];\n\n            html = html.replace(new RegExp(\"\\<\\s*\" + tag + \"\\s*([^\\>]*)\\>([^\\>]*)\\<\\s*\\/\" + tag + \"\\s*\\>\", \"igm\"), \"\");\n        }\n        \n        //return html;\n\n        if (typeof attrs !== \"undefined\")\n        {\n            var htmlTagRegex = /\\<(\\w+)\\s*([^\\>]*)\\>([^\\>]*)\\<\\/(\\w+)\\>/ig;\n\n            if (attrs === \"*\")\n            {\n                html = html.replace(htmlTagRegex, function($1, $2, $3, $4, $5) {\n                    return \"<\" + $2 + \">\" + $4 + \"</\" + $5 + \">\";\n                });         \n            }\n            else if (attrs === \"on*\")\n            {\n                html = html.replace(htmlTagRegex, function($1, $2, $3, $4, $5) {\n                    var el = $(\"<\" + $2 + \">\" + $4 + \"</\" + $5 + \">\");\n                    var _attrs = $($1)[0].attributes;\n                    var $attrs = {};\n                    \n                    $.each(_attrs, function(i, e) {\n                        if (e.nodeName !== '\"') $attrs[e.nodeName] = e.nodeValue;\n                    });\n                    \n                    $.each($attrs, function(i) {                        \n                        if (i.indexOf(\"on\") === 0) {\n                            delete $attrs[i];\n                        }\n                    });\n                    \n                    el.attr($attrs);\n                    \n                    var text = (typeof el[1] !== \"undefined\") ? $(el[1]).text() : \"\";\n\n                    return el[0].outerHTML + text;\n                });\n            }\n            else if (attrs === \"filterXSS\")\n            {\n                var tags = ['a','abbr','address',\n                'area','article','aside','audio','b','bdi','bdo','big','blockquote','br','caption','center','cite','code','col','colgroup','dd','del','details','div','dl','dt','em','font','footer','h1','h2','h3','h4','h5','h6','header','hr','i','img','ins','li','mark','nav','ol','p','pre','s','section','small','span','sub','sup','strong','table','tbody','td','tfoot','th','thead','tr','tt','u','ul','video','input'],\n                    tagAttrs = ['target','title','shape','coords','href','alt','autoplay','controls','loop','preload','src','dir','cite','align','valign','span','width','height','datetime','open','color','size','face','border','rowspan','colspan','style','class','id','name','type','checked','disabled'],\n                    whiteList = (function(){\n                        var result = {};\n                        for(var i=0,len=tags.length; i<len; i++){\n                            result[tags[i]] = tagAttrs;\n                        };\n                        return result;\n                    })();\n                html = filterXSS(html,{\n                    whiteList:whiteList\n                });\n            }\n            else\n            {\n                html = html.replace(htmlTagRegex, function($1, $2, $3, $4) {\n                    var filterAttrs = attrs.split(\",\");\n                    var el = $($1);\n                    el.html($4);\n\n                    $.each(filterAttrs, function(i) {\n                        el.attr(filterAttrs[i], null);\n                    });\n\n                    return el[0].outerHTML;\n                });\n            }\n        }\n        \n        return html;\n    };\n    \n    /**\n     * 将Markdown文档解析为HTML用于前台显示\n     * Parse Markdown to HTML for Font-end preview.\n     * \n     * @param   {String}   id            用于显示HTML的对象ID\n     * @param   {Object}   [options={}]  配置选项，可选\n     * @returns {Object}   div           返回jQuery对象元素\n     */\n    \n    editormd.markdownToHTML = function(id, options) {\n        var defaults = {\n            gfm                  : true,\n            toc                  : true,\n            tocm                 : false,\n            tocStartLevel        : 1,\n            tocTitle             : \"目录\",\n            tocDropdown          : false,\n            tocContainer         : \"\",\n            markdown             : \"\",\n            markdownSourceCode   : false,\n            htmlDecode           : false,\n            autoLoadKaTeX        : true,\n            pageBreak            : true,\n            atLink               : true,    // for @link\n            emailLink            : true,    // for mail address auto link\n            tex                  : false,\n            taskList             : false,   // Github Flavored Markdown task lists\n            emoji                : false,\n            flowChart            : false,\n            sequenceDiagram      : false,\n            previewCodeHighlight : true\n        };\n        \n        editormd.$marked  = marked;\n\n        var div           = $(\"#\" + id);\n        var settings      = div.settings = $.extend(true, defaults, options || {});\n        var saveTo        = div.find(\"textarea\");\n        \n        if (saveTo.length < 1)\n        {\n            div.append(\"<textarea></textarea>\");\n            saveTo        = div.find(\"textarea\");\n        }        \n        \n        var markdownDoc   = (settings.markdown === \"\") ? saveTo.val() : settings.markdown; \n        var markdownToC   = [];\n\n        var rendererOptions = {  \n            toc                  : settings.toc,\n            tocm                 : settings.tocm,\n            tocStartLevel        : settings.tocStartLevel,\n            taskList             : settings.taskList,\n            emoji                : settings.emoji,\n            tex                  : settings.tex,\n            pageBreak            : settings.pageBreak,\n            atLink               : settings.atLink,           // for @link\n            emailLink            : settings.emailLink,        // for mail address auto link\n            flowChart            : settings.flowChart,\n            sequenceDiagram      : settings.sequenceDiagram,\n            previewCodeHighlight : settings.previewCodeHighlight,\n        };\n\n        var markedOptions = {\n            renderer    : editormd.markedRenderer(markdownToC, rendererOptions),\n            gfm         : settings.gfm,\n            tables      : true,\n            breaks      : true,\n            pedantic    : false,\n            sanitize    : (settings.htmlDecode) ? false : true, // 是否忽略HTML标签，即是否开启HTML标签解析，为了安全性，默认不开启\n            smartLists  : true,\n            smartypants : true\n        };\n        \n\t\tmarkdownDoc = new String(markdownDoc);\n        \n        var markdownParsed = marked(markdownDoc, markedOptions);\n        \n        markdownParsed = editormd.filterHTMLTags(markdownParsed, settings.htmlDecode);\n        \n        if (settings.markdownSourceCode) {\n            saveTo.text(markdownDoc);\n        } else {\n            saveTo.remove();\n        }\n        \n        div.addClass(\"markdown-body \" + this.classPrefix + \"html-preview\").append(markdownParsed);\n        \n        var tocContainer = (settings.tocContainer !== \"\") ? $(settings.tocContainer) : div;\n        \n        if (settings.tocContainer !== \"\")\n        {\n            tocContainer.attr(\"previewContainer\", false);\n        }\n         \n        if (settings.toc) \n        {\n            div.tocContainer = this.markdownToCRenderer(markdownToC, tocContainer, settings.tocDropdown, settings.tocStartLevel);\n            \n            if (settings.tocDropdown || div.find(\".\" + this.classPrefix + \"toc-menu\").length > 0)\n            {\n                this.tocDropdownMenu(div, settings.tocTitle);\n            }\n            \n            if (settings.tocContainer !== \"\")\n            {\n                div.find(\".editormd-toc-menu, .editormd-markdown-toc\").remove();\n            }\n        }\n            \n        if (settings.previewCodeHighlight) \n        {\n            div.find(\"pre\").addClass(\"prettyprint linenums\");\n            prettyPrint();\n        }\n        \n        if (!editormd.isIE8) \n        {\n            if (settings.flowChart) {\n                div.find(\".flowchart\").flowChart(); \n            }\n\n            if (settings.sequenceDiagram) {\n                div.find(\".sequence-diagram\").sequenceDiagram({theme: \"simple\"});\n            }\n        }\n\n        if (settings.tex)\n        {\n            var katexHandle = function() {\n                div.find(\".\" + editormd.classNames.tex).each(function(){\n                    var tex  = $(this);                    \n                    katex.render(tex.html().replace(/&lt;/g, \"<\").replace(/&gt;/g, \">\"), tex[0]);                    \n                    tex.find(\".katex\").css(\"font-size\", \"1.6em\");\n                });\n            };\n            \n            if (settings.autoLoadKaTeX && !editormd.$katex && !editormd.kaTeXLoaded)\n            {\n                this.loadKaTeX(function() {\n                    editormd.$katex      = katex;\n                    editormd.kaTeXLoaded = true;\n                    katexHandle();\n                });\n            }\n            else\n            {\n                katexHandle();\n            }\n        }\n        \n        div.getMarkdown = function() {            \n            return saveTo.val();\n        };\n        \n        return div;\n    };\n    \n    // Editor.md themes, change toolbar themes etc.\n    // added @1.5.0\n    editormd.themes        = [\"default\", \"dark\"];\n    \n    // Preview area themes\n    // added @1.5.0\n    editormd.previewThemes = [\"default\", \"dark\"];\n    \n    // CodeMirror / editor area themes\n    // @1.5.0 rename -> editorThemes, old version -> themes\n    editormd.editorThemes = [\n        \"default\", \"3024-day\", \"3024-night\",\n        \"ambiance\", \"ambiance-mobile\",\n        \"base16-dark\", \"base16-light\", \"blackboard\",\n        \"cobalt\",\n        \"eclipse\", \"elegant\", \"erlang-dark\",\n        \"lesser-dark\",\n        \"mbo\", \"mdn-like\", \"midnight\", \"monokai\",\n        \"neat\", \"neo\", \"night\",\n        \"paraiso-dark\", \"paraiso-light\", \"pastel-on-dark\",\n        \"rubyblue\",\n        \"solarized\",\n        \"the-matrix\", \"tomorrow-night-eighties\", \"twilight\",\n        \"vibrant-ink\",\n        \"xq-dark\", \"xq-light\"\n    ];\n\n    editormd.loadPlugins = {};\n    \n    editormd.loadFiles = {\n        js     : [],\n        css    : [],\n        plugin : []\n    };\n    \n    /**\n     * 动态加载Editor.md插件，但不立即执行\n     * Load editor.md plugins\n     * \n     * @param {String}   fileName              插件文件路径\n     * @param {Function} [callback=function()] 加载成功后执行的回调函数\n     * @param {String}   [into=\"head\"]         嵌入页面的位置\n     */\n    \n    editormd.loadPlugin = function(fileName, callback, into) {\n        callback   = callback || function() {};\n        \n        this.loadScript(fileName, function() {\n            editormd.loadFiles.plugin.push(fileName);\n            callback();\n        }, into);\n    };\n    \n    /**\n     * 动态加载CSS文件的方法\n     * Load css file method\n     * \n     * @param {String}   fileName              CSS文件名\n     * @param {Function} [callback=function()] 加载成功后执行的回调函数\n     * @param {String}   [into=\"head\"]         嵌入页面的位置\n     */\n    \n    editormd.loadCSS   = function(fileName, callback, into) {\n        into       = into     || \"head\";        \n        callback   = callback || function() {};\n        \n        var css    = document.createElement(\"link\");\n        css.type   = \"text/css\";\n        css.rel    = \"stylesheet\";\n        css.onload = css.onreadystatechange = function() {\n            editormd.loadFiles.css.push(fileName);\n            callback();\n        };\n\n        css.href   = fileName + \".css\";\n\n        if(into === \"head\") {\n            document.getElementsByTagName(\"head\")[0].appendChild(css);\n        } else {\n            document.body.appendChild(css);\n        }\n    };\n    \n    editormd.isIE    = (navigator.appName == \"Microsoft Internet Explorer\");\n    editormd.isIE8   = (editormd.isIE && navigator.appVersion.match(/8./i) == \"8.\");\n\n    /**\n     * 动态加载JS文件的方法\n     * Load javascript file method\n     * \n     * @param {String}   fileName              JS文件名\n     * @param {Function} [callback=function()] 加载成功后执行的回调函数\n     * @param {String}   [into=\"head\"]         嵌入页面的位置\n     */\n\n    editormd.loadScript = function(fileName, callback, into) {\n        \n        into          = into     || \"head\";\n        callback      = callback || function() {};\n        \n        var script    = null; \n        script        = document.createElement(\"script\");\n        script.id     = fileName.replace(/[\\./]+/g, \"-\");\n        script.type   = \"text/javascript\";        \n        script.src    = fileName + \".js\";\n        \n        if (editormd.isIE8) \n        {            \n            script.onreadystatechange = function() {\n                if(script.readyState) \n                {\n                    if (script.readyState === \"loaded\" || script.readyState === \"complete\") \n                    {\n                        script.onreadystatechange = null; \n                        editormd.loadFiles.js.push(fileName);\n                        callback();\n                    }\n                } \n            };\n        }\n        else\n        {\n            script.onload = function() {\n                editormd.loadFiles.js.push(fileName);\n                callback();\n            };\n        }\n\n        if (into === \"head\") {\n            document.getElementsByTagName(\"head\")[0].appendChild(script);\n        } else {\n            document.body.appendChild(script);\n        }\n    };\n    \n    // 使用国外的CDN，加载速度有时会很慢，或者自定义URL\n    // You can custom KaTeX load url.\n    editormd.katexURL  = {\n        css: 'static/editor.md/katex/katex.min',\n        js: 'static/editor.md/katex/katex.min'\n    };\n    \n    editormd.kaTeXLoaded = false;\n    \n    /**\n     * 加载KaTeX文件\n     * load KaTeX files\n     * \n     * @param {Function} [callback=function()]  加载成功后执行的回调函数\n     */\n    \n    editormd.loadKaTeX = function (callback) {\n        editormd.loadCSS(editormd.katexURL.css, function(){\n            editormd.loadScript(editormd.katexURL.js, callback || function(){});\n        });\n    };\n        \n    /**\n     * 锁屏\n     * lock screen\n     * \n     * @param   {Boolean}   lock   Boolean 布尔值，是否锁屏\n     * @returns {void}\n     */\n    \n    editormd.lockScreen = function(lock) {\n        $(\"html,body\").css(\"overflow\", (lock) ? \"hidden\" : \"\");\n    };\n        \n    /**\n     * 动态创建对话框\n     * Creating custom dialogs\n     * \n     * @param   {Object} options 配置项键值对 Key/Value\n     * @returns {dialog} 返回创建的dialog的jQuery实例对象\n     */\n\n    editormd.createDialog = function(options) {\n        var defaults = {\n            name : \"\",\n            width : 420,\n            height: 240,\n            title : \"\",\n            drag  : true,\n            closed : true,\n            content : \"\",\n            mask : true,\n            maskStyle : {\n                backgroundColor : \"#fff\",\n                opacity : 0.1\n            },\n            lockScreen : true,\n            footer : true,\n            buttons : false\n        };\n\n        options          = $.extend(true, defaults, options);\n        \n        var $this        = this;\n        var editor       = this.editor;\n        var classPrefix  = editormd.classPrefix;\n        var guid         = (new Date()).getTime();\n        var dialogName   = ( (options.name === \"\") ? classPrefix + \"dialog-\" + guid : options.name);\n        var mouseOrTouch = editormd.mouseOrTouch;\n\n        var html         = \"<div class=\\\"\" + classPrefix + \"dialog \" + dialogName + \"\\\">\";\n\n        if (options.title !== \"\")\n        {\n            html += \"<div class=\\\"\" + classPrefix + \"dialog-header\\\"\" + ( (options.drag) ? \" style=\\\"cursor: move;\\\"\" : \"\" ) + \">\";\n            html += \"<strong class=\\\"\" + classPrefix + \"dialog-title\\\">\" + options.title + \"</strong>\";\n            html += \"</div>\";\n        }\n\n        if (options.closed)\n        {\n            html += \"<a href=\\\"javascript:;\\\" class=\\\"fa fa-close \" + classPrefix + \"dialog-close\\\"></a>\";\n        }\n\n        html += \"<div class=\\\"\" + classPrefix + \"dialog-container\\\">\" + options.content;                    \n\n        if (options.footer || typeof options.footer === \"string\") \n        {\n            html += \"<div class=\\\"\" + classPrefix + \"dialog-footer\\\">\" + ( (typeof options.footer === \"boolean\") ? \"\" : options.footer) + \"</div>\";\n        }\n\n        html += \"</div>\";\n\n        html += \"<div class=\\\"\" + classPrefix + \"dialog-mask \" + classPrefix + \"dialog-mask-bg\\\"></div>\";\n        html += \"<div class=\\\"\" + classPrefix + \"dialog-mask \" + classPrefix + \"dialog-mask-con\\\"></div>\";\n        html += \"</div>\";\n\n        editor.append(html);\n\n        var dialog = editor.find(\".\" + dialogName);\n\n        dialog.lockScreen = function(lock) {\n            if (options.lockScreen)\n            {                \n                $(\"html,body\").css(\"overflow\", (lock) ? \"hidden\" : \"\");\n                $this.resize();\n            }\n\n            return dialog;\n        };\n\n        dialog.showMask = function() {\n            if (options.mask)\n            {\n                editor.find(\".\" + classPrefix + \"mask\").css(options.maskStyle).css(\"z-index\", editormd.dialogZindex - 1).show();\n            }\n            return dialog;\n        };\n\n        dialog.hideMask = function() {\n            if (options.mask)\n            {\n                editor.find(\".\" + classPrefix + \"mask\").hide();\n            }\n\n            return dialog;\n        };\n\n        dialog.loading = function(show) {                        \n            var loading = dialog.find(\".\" + classPrefix + \"dialog-mask\");\n            loading[(show) ? \"show\" : \"hide\"]();\n\n            return dialog;\n        };\n\n        dialog.lockScreen(true).showMask();\n\n        dialog.show().css({\n            zIndex : editormd.dialogZindex,\n            border : (editormd.isIE8) ? \"1px solid #ddd\" : \"\",\n            width  : (typeof options.width  === \"number\") ? options.width + \"px\"  : options.width,\n            height : (typeof options.height === \"number\") ? options.height + \"px\" : options.height\n        });\n\n        var dialogPosition = function(){\n            dialog.css({\n                top    : ($(window).height() - dialog.height()) / 2 + \"px\",\n                left   : ($(window).width() - dialog.width()) / 2 + \"px\"\n            });\n        };\n\n        dialogPosition();\n\n        $(window).resize(dialogPosition);\n\n        dialog.children(\".\" + classPrefix + \"dialog-close\").bind(mouseOrTouch(\"click\", \"touchend\"), function() {\n            dialog.hide().lockScreen(false).hideMask();\n        });\n\n        if (typeof options.buttons === \"object\")\n        {\n            var footer = dialog.footer = dialog.find(\".\" + classPrefix + \"dialog-footer\");\n\n            for (var key in options.buttons)\n            {\n                var btn = options.buttons[key];\n                var btnClassName = classPrefix + key + \"-btn\";\n\n                footer.append(\"<button class=\\\"\" + classPrefix + \"btn \" + btnClassName + \"\\\">\" + btn[0] + \"</button>\");\n                btn[1] = $.proxy(btn[1], dialog);\n                footer.children(\".\" + btnClassName).bind(mouseOrTouch(\"click\", \"touchend\"), btn[1]);\n            }\n        }\n\n        if (options.title !== \"\" && options.drag)\n        {                        \n            var posX, posY;\n            var dialogHeader = dialog.children(\".\" + classPrefix + \"dialog-header\");\n\n            if (!options.mask) {\n                dialogHeader.bind(mouseOrTouch(\"click\", \"touchend\"), function(){\n                    editormd.dialogZindex += 2;\n                    dialog.css(\"z-index\", editormd.dialogZindex);\n                });\n            }\n\n            dialogHeader.mousedown(function(e) {\n                e = e || window.event;  //IE\n                posX = e.clientX - parseInt(dialog[0].style.left);\n                posY = e.clientY - parseInt(dialog[0].style.top);\n\n                document.onmousemove = moveAction;                   \n            });\n\n            var userCanSelect = function (obj) {\n                obj.removeClass(classPrefix + \"user-unselect\").off(\"selectstart\");\n            };\n\n            var userUnselect = function (obj) {\n                obj.addClass(classPrefix + \"user-unselect\").on(\"selectstart\", function(event) { // selectstart for IE                        \n                    return false;\n                });\n            };\n\n            var moveAction = function (e) {\n                e = e || window.event;  //IE\n\n                var left, top, nowLeft = parseInt(dialog[0].style.left), nowTop = parseInt(dialog[0].style.top);\n\n                if( nowLeft >= 0 ) {\n                    if( nowLeft + dialog.width() <= $(window).width()) {\n                        left = e.clientX - posX;\n                    } else {\t\n                        left = $(window).width() - dialog.width();\n                        document.onmousemove = null;\n                    }\n                } else {\n                    left = 0;\n                    document.onmousemove = null;\n                }\n\n                if( nowTop >= 0 ) {\n                    top = e.clientY - posY;\n                } else {\n                    top = 0;\n                    document.onmousemove = null;\n                }\n\n\n                document.onselectstart = function() {\n                    return false;\n                };\n\n                userUnselect($(\"body\"));\n                userUnselect(dialog);\n                dialog[0].style.left = left + \"px\";\n                dialog[0].style.top  = top + \"px\";\n            };\n\n            document.onmouseup = function() {                            \n                userCanSelect($(\"body\"));\n                userCanSelect(dialog);\n\n                document.onselectstart = null;         \n                document.onmousemove = null;\n            };\n\n            dialogHeader.touchDraggable = function() {\n                var offset = null;\n                var start  = function(e) {\n                    var orig = e.originalEvent; \n                    var pos  = $(this).parent().position();\n\n                    offset = {\n                        x : orig.changedTouches[0].pageX - pos.left,\n                        y : orig.changedTouches[0].pageY - pos.top\n                    };\n                };\n\n                var move = function(e) {\n                    e.preventDefault();\n                    var orig = e.originalEvent;\n\n                    $(this).parent().css({\n                        top  : orig.changedTouches[0].pageY - offset.y,\n                        left : orig.changedTouches[0].pageX - offset.x\n                    });\n                };\n\n                this.bind(\"touchstart\", start).bind(\"touchmove\", move);\n            };\n\n            dialogHeader.touchDraggable();\n        }\n\n        editormd.dialogZindex += 2;\n\n        return dialog;\n    };\n    \n    /**\n     * 鼠标和触摸事件的判断/选择方法\n     * MouseEvent or TouchEvent type switch\n     * \n     * @param   {String} [mouseEventType=\"click\"]    供选择的鼠标事件\n     * @param   {String} [touchEventType=\"touchend\"] 供选择的触摸事件\n     * @returns {String} EventType                   返回事件类型名称\n     */\n    \n    editormd.mouseOrTouch = function(mouseEventType, touchEventType) {\n        mouseEventType = mouseEventType || \"click\";\n        touchEventType = touchEventType || \"touchend\";\n        \n        var eventType  = mouseEventType;\n\n        var userAgentInfo = navigator.userAgent;\n        var Agents = new Array(\"Android\", \"iPhone\", \"SymbianOS\", \"Windows Phone\", \"iPad\", \"iPod\");\n        var flag = true;\n        for (var v = 0; v < Agents.length; v++) {\n            if (userAgentInfo.indexOf(Agents[v]) > 0) {\n                flag = false;\n                break;\n            }\n        }\n        if(!flag){\n            eventType = touchEventType;\n        }\n\n        return eventType;\n    };\n    \n    /**\n     * 日期时间的格式化方法\n     * Datetime format method\n     * \n     * @param   {String}   [format=\"\"]  日期时间的格式，类似PHP的格式\n     * @returns {String}   datefmt      返回格式化后的日期时间字符串\n     */\n    \n    editormd.dateFormat = function(format) {                \n        format      = format || \"\";\n\n        var addZero = function(d) {\n            return (d < 10) ? \"0\" + d : d;\n        };\n\n        var date    = new Date(); \n        var year    = date.getFullYear();\n        var year2   = year.toString().slice(2, 4);\n        var month   = addZero(date.getMonth() + 1);\n        var day     = addZero(date.getDate());\n        var weekDay = date.getDay();\n        var hour    = addZero(date.getHours());\n        var min     = addZero(date.getMinutes());\n        var second  = addZero(date.getSeconds());\n        var ms      = addZero(date.getMilliseconds()); \n        var datefmt = \"\";\n\n        var ymd     = year2 + \"-\" + month + \"-\" + day;\n        var fymd    = year  + \"-\" + month + \"-\" + day;\n        var hms     = hour  + \":\" + min   + \":\" + second;\n\n        switch (format) \n        {\n            case \"UNIX Time\" :\n                    datefmt = date.getTime();\n                break;\n\n            case \"UTC\" :\n                    datefmt = date.toUTCString();\n                break;\t\n\n            case \"yy\" :\n                    datefmt = year2;\n                break;\t\n\n            case \"year\" :\n            case \"yyyy\" :\n                    datefmt = year;\n                break;\n\n            case \"month\" :\n            case \"mm\" :\n                    datefmt = month;\n                break;                        \n\n            case \"cn-week-day\" :\n            case \"cn-wd\" :\n                    var cnWeekDays = [\"日\", \"一\", \"二\", \"三\", \"四\", \"五\", \"六\"];\n                    datefmt = \"星期\" + cnWeekDays[weekDay];\n                break;\n\n            case \"week-day\" :\n            case \"wd\" :\n                    var weekDays = [\"Sunday\", \"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\", \"Saturday\"];\n                    datefmt = weekDays[weekDay];\n                break;\n\n            case \"day\" :\n            case \"dd\" :\n                    datefmt = day;\n                break;\n\n            case \"hour\" :\n            case \"hh\" :\n                    datefmt = hour;\n                break;\n\n            case \"min\" :\n            case \"ii\" :\n                    datefmt = min;\n                break;\n\n            case \"second\" :\n            case \"ss\" :\n                    datefmt = second;\n                break;\n\n            case \"ms\" :\n                    datefmt = ms;\n                break;\n\n            case \"yy-mm-dd\" :\n                    datefmt = ymd;\n                break;\n\n            case \"yyyy-mm-dd\" :\n                    datefmt = fymd;\n                break;\n\n            case \"yyyy-mm-dd h:i:s ms\" :\n            case \"full + ms\" : \n                    datefmt = fymd + \" \" + hms + \" \" + ms;\n                break;\n\n            case \"full\" :\n            case \"yyyy-mm-dd h:i:s\" :\n                default:\n                    datefmt = fymd + \" \" + hms;\n                break;\n        }\n\n        return datefmt;\n    };\n\n    return editormd;\n\n}));\n"
  },
  {
    "path": "Public/editor.md/languages/en.js",
    "content": "(function(){\n    var factory = function (exports) {\n        var lang = {\n            name : \"en\",\n            description : \"Open source online Markdown editor.\",\n            tocTitle    : \"Table of Contents\",\n            toolbar : {\n                undo             : \"Undo(Ctrl+Z)\",\n                redo             : \"Redo(Ctrl+Y)\",\n                bold             : \"Bold\",\n                del              : \"Strikethrough\",\n                italic           : \"Italic\",\n                quote            : \"Block quote\",\n                ucwords          : \"Words first letter convert to uppercase\",\n                uppercase        : \"Selection text convert to uppercase\",\n                lowercase        : \"Selection text convert to lowercase\",\n                h1               : \"Heading 1\",\n                h2               : \"Heading 2\",\n                h3               : \"Heading 3\",\n                h4               : \"Heading 4\",\n                h5               : \"Heading 5\",\n                h6               : \"Heading 6\",\n                \"list-ul\"        : \"Unordered list\",\n                \"list-ol\"        : \"Ordered list\",\n                hr               : \"Horizontal rule\",\n                link             : \"Link\",\n                \"reference-link\" : \"Reference link\",\n                image            : \"Image\",\n                code             : \"Code inline\",\n                \"preformatted-text\" : \"Preformatted text / Code block (Tab indent)\",\n                \"code-block\"     : \"Code block (Multi-languages)\",\n                table            : \"Tables\",\n                datetime         : \"Datetime\",\n                emoji            : \"Emoji\",\n                \"html-entities\"  : \"HTML Entities\",\n                pagebreak        : \"Page break\",\n                watch            : \"Unwatch\",\n                unwatch          : \"Watch\",\n                preview          : \"HTML Preview (Press Shift + ESC exit)\",\n                fullscreen       : \"Fullscreen (Press ESC exit)\",\n                clear            : \"Clear\",\n                search           : \"Search\",\n                help             : \"Help\",\n                info             : \"About \" + exports.title\n            },\n            buttons : {\n                enter  : \"Enter\",\n                cancel : \"Cancel\",\n                close  : \"Close\"\n            },\n            dialog : {\n                link : {\n                    title    : \"Link\",\n                    url      : \"Address\",\n                    urlTitle : \"Title\",\n                    urlEmpty : \"Error: Please fill in the link address.\"\n                },\n                referenceLink : {\n                    title    : \"Reference link\",\n                    name     : \"Name\",\n                    url      : \"Address\",\n                    urlId    : \"ID\",\n                    urlTitle : \"Title\",\n                    nameEmpty: \"Error: Reference name can't be empty.\",\n                    idEmpty  : \"Error: Please fill in reference link id.\",\n                    urlEmpty : \"Error: Please fill in reference link url address.\"\n                },\n                image : {\n                    title    : \"Image\",\n                    url      : \"Address\",\n                    link     : \"Link\",\n                    alt      : \"Title\",\n                    uploadButton     : \"Upload\",\n                    imageURLEmpty    : \"Error: picture url address can't be empty.\",\n                    uploadFileEmpty  : \"Error: upload pictures cannot be empty!\",\n                    formatNotAllowed : \"Error: only allows to upload pictures file, upload allowed image file format:\"\n                },\n                preformattedText : {\n                    title             : \"Preformatted text / Codes\", \n                    emptyAlert        : \"Error: Please fill in the Preformatted text or content of the codes.\"\n                },\n                codeBlock : {\n                    title             : \"Code block\",         \n                    selectLabel       : \"Languages: \",\n                    selectDefaultText : \"select a code language...\",\n                    otherLanguage     : \"Other languages\",\n                    unselectedLanguageAlert : \"Error: Please select the code language.\",\n                    codeEmptyAlert    : \"Error: Please fill in the code content.\"\n                },\n                htmlEntities : {\n                    title : \"HTML Entities\"\n                },\n                help : {\n                    title : \"Help\"\n                }\n            }\n        };\n        \n        exports.defaults.lang = lang;\n    };\n    \n\t// CommonJS/Node.js\n\tif (typeof require === \"function\" && typeof exports === \"object\" && typeof module === \"object\")\n    { \n        module.exports = factory;\n    }\n\telse if (typeof define === \"function\")  // AMD/CMD/Sea.js\n    {\n\t\tif (define.amd) { // for Require.js\n\n\t\t\tdefine([\"editormd\"], function(editormd) {\n                factory(editormd);\n            });\n\n\t\t} else { // for Sea.js\n\t\t\tdefine(function(require) {\n                var editormd = require(\"../editormd\");\n                factory(editormd);\n            });\n\t\t}\n\t} \n\telse\n\t{\n        factory(window.editormd);\n\t}\n    \n})();"
  },
  {
    "path": "Public/editor.md/languages/zh-tw.js",
    "content": "(function(){\n    var factory = function (exports) {\n        var lang = {\n            name : \"zh-tw\",\n            description : \"開源在線Markdown編輯器<br/>Open source online Markdown editor.\",\n            tocTitle    : \"目錄\",\n            toolbar     : {\n                undo             : \"撤銷（Ctrl+Z）\",\n                redo             : \"重做（Ctrl+Y）\",\n                bold             : \"粗體\",\n                del              : \"刪除線\",\n                italic           : \"斜體\",\n                quote            : \"引用\",\n                ucwords          : \"將所選的每個單詞首字母轉成大寫\",\n                uppercase        : \"將所選文本轉成大寫\",\n                lowercase        : \"將所選文本轉成小寫\",\n                h1               : \"標題1\",\n                h2               : \"標題2\",\n                h3               : \"標題3\",\n                h4               : \"標題4\",\n                h5               : \"標題5\",\n                h6               : \"標題6\",\n                \"list-ul\"        : \"無序列表\",\n                \"list-ol\"        : \"有序列表\",\n                hr               : \"横线\",\n                link             : \"链接\",\n                \"reference-link\" : \"引用鏈接\",\n                image            : \"圖片\",\n                code             : \"行內代碼\",\n                \"preformatted-text\" : \"預格式文本 / 代碼塊（縮進風格）\",\n                \"code-block\"     : \"代碼塊（多語言風格）\",\n                table            : \"添加表格\",\n                datetime         : \"日期時間\",\n                emoji            : \"Emoji 表情\",\n                \"html-entities\"  : \"HTML 實體字符\",\n                pagebreak        : \"插入分頁符\",\n                watch            : \"關閉實時預覽\",\n                unwatch          : \"開啟實時預覽\",\n                preview          : \"全窗口預覽HTML（按 Shift + ESC 退出）\",\n                fullscreen       : \"全屏（按 ESC 退出）\",\n                clear            : \"清空\",\n                search           : \"搜尋\",\n                help             : \"使用幫助\",\n                info             : \"關於\" + exports.title\n            },\n            buttons : {\n                enter  : \"確定\",\n                cancel : \"取消\",\n                close  : \"關閉\"\n            },\n            dialog : {\n                link   : {\n                    title    : \"添加鏈接\",\n                    url      : \"鏈接地址\",\n                    urlTitle : \"鏈接標題\",\n                    urlEmpty : \"錯誤：請填寫鏈接地址。\"\n                },\n                referenceLink : {\n                    title    : \"添加引用鏈接\",\n                    name     : \"引用名稱\",\n                    url      : \"鏈接地址\",\n                    urlId    : \"鏈接ID\",\n                    urlTitle : \"鏈接標題\",\n                    nameEmpty: \"錯誤：引用鏈接的名稱不能為空。\",\n                    idEmpty  : \"錯誤：請填寫引用鏈接的ID。\",\n                    urlEmpty : \"錯誤：請填寫引用鏈接的URL地址。\"\n                },\n                image  : {\n                    title    : \"添加圖片\",\n                    url      : \"圖片地址\",\n                    link     : \"圖片鏈接\",\n                    alt      : \"圖片描述\",\n                    uploadButton     : \"本地上傳\",\n                    imageURLEmpty    : \"錯誤：圖片地址不能為空。\",\n                    uploadFileEmpty  : \"錯誤：上傳的圖片不能為空！\",\n                    formatNotAllowed : \"錯誤：只允許上傳圖片文件，允許上傳的圖片文件格式有：\"\n                },\n                preformattedText : {\n                    title             : \"添加預格式文本或代碼塊\", \n                    emptyAlert        : \"錯誤：請填寫預格式文本或代碼的內容。\"\n                },\n                codeBlock : {\n                    title             : \"添加代碼塊\",                 \n                    selectLabel       : \"代碼語言：\",\n                    selectDefaultText : \"請語言代碼語言\",\n                    otherLanguage     : \"其他語言\",\n                    unselectedLanguageAlert : \"錯誤：請選擇代碼所屬的語言類型。\",\n                    codeEmptyAlert    : \"錯誤：請填寫代碼內容。\"\n                },\n                htmlEntities : {\n                    title : \"HTML實體字符\"\n                },\n                help : {\n                    title : \"使用幫助\"\n                }\n            }\n        };\n        \n        exports.defaults.lang = lang;\n    };\n    \n\t// CommonJS/Node.js\n\tif (typeof require === \"function\" && typeof exports === \"object\" && typeof module === \"object\")\n    { \n        module.exports = factory;\n    }\n\telse if (typeof define === \"function\")  // AMD/CMD/Sea.js\n    {\n\t\tif (define.amd) { // for Require.js\n\n\t\t\tdefine([\"editormd\"], function(editormd) {\n                factory(editormd);\n            });\n\n\t\t} else { // for Sea.js\n\t\t\tdefine(function(require) {\n                var editormd = require(\"../editormd\");\n                factory(editormd);\n            });\n\t\t}\n\t} \n\telse\n\t{\n        factory(window.editormd);\n\t}\n    \n})();"
  },
  {
    "path": "Public/editor.md/lib/codemirror/AUTHORS",
    "content": "List of CodeMirror contributors. Updated before every release.\n\n4r2r\nAaron Brooks\nAbdelouahab\nAbe Fettig\nAdam Ahmed\nAdam King\nadanlobato\nAdán Lobato\nAdrian Aichner\naeroson\nAhmad Amireh\nAhmad M. Zawawi\nahoward\nAkeksandr Motsjonov\nAlberto González Palomo\nAlberto Pose\nAlbert Xing\nAlexander Pavlov\nAlexander Schepanovski\nAlexander Shvets\nAlexander Solovyov\nAlexandre Bique\nalexey-k\nAlex Piggott\nAliaksei Chapyzhenka\nAmsul\namuntean\nAmy\nAnanya Sen\nanaran\nAndersMad\nAnders Nawroth\nAnderson Mesquita\nAndrea G\nAndreas Reischuck\nAndre von Houck\nAndrey Fedorov\nAndrey Klyuchnikov\nAndrey Lushnikov\nAndy Joslin\nAndy Kimball\nAndy Li\nangelozerr\nangelo.zerr@gmail.com\nAnkit\nAnkit Ahuja\nAnsel Santosa\nAnthony Grimes\nAnton Kovalyov\nareos\nas3boyan\nAtomicPages LLC\nAtul Bhouraskar\nAurelian Oancea\nBastian Müller\nBem Jones-Bey\nbenbro\nBeni Cherniavsky-Paskin\nBenjamin DeCoste\nBen Keen\nBernhard Sirlinger\nBert Chang\nBilly Moon\nbinny\nB Krishna Chaitanya\nBlaine G\nblukat29\nboomyjee\nborawjm\nBrandon Frohs\nBrandon Wamboldt\nBrett Zamir\nBrian Grinstead\nBrian Sletten\nBruce Mitchener\nChandra Sekhar Pydi\nCharles Skelton\nCheah Chu Yeow\nChris Coyier\nChris Granger\nChris Houseknecht\nChris Morgan\nChristian Oyarzun\nChristian Petrov\nChristopher Brown\nciaranj\nCodeAnimal\nComFreek\nCurtis Gagliardi\ndagsta\ndaines\nDale Jung\nDan Bentley\nDan Heberden\nDaniel, Dao Quang Minh\nDaniele Di Sarli\nDaniel Faust\nDaniel Huigens\nDaniel KJ\nDaniel Neel\nDaniel Parnell\nDanny Yoo\ndarealshinji\nDarius Roberts\nDave Myers\nDavid Mignot\nDavid Pathakjee\nDavid Vázquez\ndeebugger\nDeep Thought\nDevon Carew\ndignifiedquire\nDimage Sapelkin\nDmitry Kiselyov\ndomagoj412\nDominator008\nDomizio Demichelis\nDoug Wikle\nDrew Bratcher\nDrew Hintz\nDrew Khoury\nDror BG\nduralog\neborden\nedsharp\nekhaled\nEnam Mijbah Noor\nEric Allam\neustas\nFabien O'Carroll\nFabio Zendhi Nagao\nFaiza Alsaied\nFauntleroy\nfbuchinger\nfeizhang365\nFelipe Lalanne\nFelix Raab\nFilip Noetzel\nflack\nForbesLindesay\nForbes Lindesay\nFord_Lawnmower\nForrest Oliphant\nFrank Wiegand\nGabriel Gheorghian\nGabriel Horner\nGabriel Nahmias\ngalambalazs\nGautam Mehta\ngekkoe\nGerard Braad\nGergely Hegykozi\nGiovanni Calò\nGlenn Jorde\nGlenn Ruehle\nGolevka\nGordon Smith\nGrant Skinner\ngreengiant\nGregory Koberger\nGuillaume Massé\nGuillaume Massé\nGustavo Rodrigues\nHakan Tunc\nHans Engel\nHardest\nHasan Karahan\nHerculano Campos\nHiroyuki Makino\nhitsthings\nHocdoc\nIan Beck\nIan Dickinson\nIan Wehrman\nIan Wetherbee\nIce White\nICHIKAWA, Yuji\nilvalle\nIngo Richter\nIrakli Gozalishvili\nIvan Kurnosov\nJacob Lee\nJakob Miland\nJakub Vrana\nJakub Vrána\nJames Campos\nJames Thorne\nJamie Hill\nJan Jongboom\njankeromnes\nJan Keromnes\nJan Odvarko\nJan T. Sott\nJared Forsyth\nJason\nJason Barnabe\nJason Grout\nJason Johnston\nJason San Jose\nJason Siefken\nJaydeep Solanki\nJean Boussier\njeffkenton\nJeff Pickhardt\njem (graphite)\nJeremy Parmenter\nJochen Berger\nJohan Ask\nJohn Connor\nJohn Lees-Miller\nJohn Snelson\nJohn Van Der Loo\nJonathan Malmaud\njongalloway\nJon Malmaud\nJon Sangster\nJoost-Wim Boekesteijn\nJoseph Pecoraro\nJoshua Newman\nJosh Watzman\njots\njsoojeon\nJuan Benavides Romero\nJucovschi Constantin\nJuho Vuori\nJustin Hileman\njwallers@gmail.com\nkaniga\nKen Newman\nKen Rockot\nKevin Sawicki\nKevin Ushey\nKlaus Silveira\nKoh Zi Han, Cliff\nkomakino\nKonstantin Lopuhin\nkoops\nks-ifware\nkubelsmieci\nKwanEsq\nLanfei\nLanny\nLaszlo Vidacs\nleaf corcoran\nLeonid Khachaturov\nLeon Sorokin\nLeonya Khachaturov\nLiam Newman\nLM\nlochel\nLorenzo Stoakes\nLuciano Longo\nLuke Stagner\nlynschinzer\nMaksim Lin\nMaksym Taran\nMalay Majithia\nManuel Rego Casasnovas\nMarat Dreizin\nMarcel Gerber\nMarco Aurélio\nMarco Munizaga\nMarcus Bointon\nMarek Rudnicki\nMarijn Haverbeke\nMário Gonçalves\nMario Pietsch\nMark Lentczner\nMarko Bonaci\nMartin Balek\nMartín Gaitán\nMartin Hasoň\nMason Malone\nMateusz Paprocki\nMathias Bynens\nmats cronqvist\nMatthew Beale\nMatthias Bussonnier\nMatthias BUSSONNIER\nMatt McDonald\nMatt Pass\nMatt Sacks\nmauricio\nMaximilian Hils\nMaxim Kraev\nMax Kirsch\nMax Xiantu\nmbarkhau\nMetatheos\nMicah Dubinko\nMichael Lehenbauer\nMichael Zhou\nMighty Guava\nMiguel Castillo\nmihailik\nMike\nMike Brevoort\nMike Diaz\nMike Ivanov\nMike Kadin\nMinRK\nMiraculix87\nmisfo\nmloginov\nMoritz Schwörer\nmps\nmtaran-google\nNarciso Jaramillo\nNathan Williams\nndr\nnerbert\nnextrevision\nngn\nnguillaumin\nNg Zhi An\nNicholas Bollweg\nNicholas Bollweg (Nick)\nNick Small\nNiels van Groningen\nnightwing\nNikita Beloglazov\nNikita Vasilyev\nNikolay Kostov\nnilp0inter\nNisarg Jhaveri\nnlwillia\nNorman Rzepka\npablo\nPage\nPanupong Pasupat\nparis\nPatil Arpith\nPatrick Stoica\nPatrick Strawderman\nPaul Garvin\nPaul Ivanov\nPavel Feldman\nPavel Strashkin\nPaweł Bartkiewicz\npeteguhl\nPeter Flynn\npeterkroon\nPeter Kroon\nprasanthj\nPrasanth J\nRadek Piórkowski\nRahul\nRandall Mason\nRandy Burden\nRandy Edmunds\nRasmus Erik Voel Jensen\nRay Ratchup\nRichard van der Meer\nRichard Z.H. Wang\nRobert Crossfield\nRoberto Abdelkader Martínez Pérez\nrobertop23\nRobert Plummer\nRuslan Osmanov\nRyan Prior\nsabaca\nSamuel Ainsworth\nsandeepshetty\nSander AKA Redsandro\nsantec\nSascha Peilicke\nsatchmorun\nsathyamoorthi\nSCLINIC\\jdecker\nScott Aikin\nScott Goodhew\nSebastian Zaha\nshaund\nshaun gilchrist\nShawn A\nsheopory\nShiv Deepak\nShmuel Englard\nShubham Jain\nsilverwind\nsnasa\nsoliton4\nsonson\nspastorelli\nsrajanpaliwal\nStanislav Oaserele\nStas Kobzar\nStefan Borsje\nSteffen Beyer\nSteve O'Hara\nstoskov\nTaha Jahangir\nTakuji Shimokawa\nTarmil\ntel\ntfjgeorge\nThaddee Tyl\nTheHowl\nthink\nThomas Dvornik\nThomas Schmid\nTim Alby\nTim Baumann\nTimothy Farrell\nTimothy Hatcher\nTobiasBg\nTomas-A\nTomas Varaneckas\nTom Erik Støwer\nTom MacWright\nTony Jian\nTravis Heppe\nTriangle717\ntwifkak\nVestimir Markov\nvf\nVincent Woo\nVolker Mische\nwenli\nWesley Wiser\nWill Binns-Smith\nWilliam Jamieson\nWilliam Stein\nWilly\nWojtek Ptak\nXavier Mendez\nYassin N. Hassan\nYNH Webdev\nYunchi Luo\nYuvi Panda\nZachary Dremann\nZhang Hao\nzziuni\n魏鹏刚\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/LICENSE",
    "content": "Copyright (C) 2014 by Marijn Haverbeke <marijnh@gmail.com> and others\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/README.md",
    "content": "# CodeMirror\n[![Build Status](https://travis-ci.org/codemirror/CodeMirror.svg)](https://travis-ci.org/codemirror/CodeMirror)\n[![NPM version](https://img.shields.io/npm/v/codemirror.svg)](https://www.npmjs.org/package/codemirror)  \n[Funding status: ![maintainer happiness](https://marijnhaverbeke.nl/fund/status_s.png)](https://marijnhaverbeke.nl/fund/)\n\nCodeMirror is a JavaScript component that provides a code editor in\nthe browser. When a mode is available for the language you are coding\nin, it will color your code, and optionally help with indentation.\n\nThe project page is http://codemirror.net  \nThe manual is at http://codemirror.net/doc/manual.html  \nThe contributing guidelines are in [CONTRIBUTING.md](https://github.com/codemirror/CodeMirror/blob/master/CONTRIBUTING.md)\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/comment/comment.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n\n  var noOptions = {};\n  var nonWS = /[^\\s\\u00a0]/;\n  var Pos = CodeMirror.Pos;\n\n  function firstNonWS(str) {\n    var found = str.search(nonWS);\n    return found == -1 ? 0 : found;\n  }\n\n  CodeMirror.commands.toggleComment = function(cm) {\n    var minLine = Infinity, ranges = cm.listSelections(), mode = null;\n    for (var i = ranges.length - 1; i >= 0; i--) {\n      var from = ranges[i].from(), to = ranges[i].to();\n      if (from.line >= minLine) continue;\n      if (to.line >= minLine) to = Pos(minLine, 0);\n      minLine = from.line;\n      if (mode == null) {\n        if (cm.uncomment(from, to)) mode = \"un\";\n        else { cm.lineComment(from, to); mode = \"line\"; }\n      } else if (mode == \"un\") {\n        cm.uncomment(from, to);\n      } else {\n        cm.lineComment(from, to);\n      }\n    }\n  };\n\n  CodeMirror.defineExtension(\"lineComment\", function(from, to, options) {\n    if (!options) options = noOptions;\n    var self = this, mode = self.getModeAt(from);\n    var commentString = options.lineComment || mode.lineComment;\n    if (!commentString) {\n      if (options.blockCommentStart || mode.blockCommentStart) {\n        options.fullLines = true;\n        self.blockComment(from, to, options);\n      }\n      return;\n    }\n    var firstLine = self.getLine(from.line);\n    if (firstLine == null) return;\n    var end = Math.min(to.ch != 0 || to.line == from.line ? to.line + 1 : to.line, self.lastLine() + 1);\n    var pad = options.padding == null ? \" \" : options.padding;\n    var blankLines = options.commentBlankLines || from.line == to.line;\n\n    self.operation(function() {\n      if (options.indent) {\n        var baseString = firstLine.slice(0, firstNonWS(firstLine));\n        for (var i = from.line; i < end; ++i) {\n          var line = self.getLine(i), cut = baseString.length;\n          if (!blankLines && !nonWS.test(line)) continue;\n          if (line.slice(0, cut) != baseString) cut = firstNonWS(line);\n          self.replaceRange(baseString + commentString + pad, Pos(i, 0), Pos(i, cut));\n        }\n      } else {\n        for (var i = from.line; i < end; ++i) {\n          if (blankLines || nonWS.test(self.getLine(i)))\n            self.replaceRange(commentString + pad, Pos(i, 0));\n        }\n      }\n    });\n  });\n\n  CodeMirror.defineExtension(\"blockComment\", function(from, to, options) {\n    if (!options) options = noOptions;\n    var self = this, mode = self.getModeAt(from);\n    var startString = options.blockCommentStart || mode.blockCommentStart;\n    var endString = options.blockCommentEnd || mode.blockCommentEnd;\n    if (!startString || !endString) {\n      if ((options.lineComment || mode.lineComment) && options.fullLines != false)\n        self.lineComment(from, to, options);\n      return;\n    }\n\n    var end = Math.min(to.line, self.lastLine());\n    if (end != from.line && to.ch == 0 && nonWS.test(self.getLine(end))) --end;\n\n    var pad = options.padding == null ? \" \" : options.padding;\n    if (from.line > end) return;\n\n    self.operation(function() {\n      if (options.fullLines != false) {\n        var lastLineHasText = nonWS.test(self.getLine(end));\n        self.replaceRange(pad + endString, Pos(end));\n        self.replaceRange(startString + pad, Pos(from.line, 0));\n        var lead = options.blockCommentLead || mode.blockCommentLead;\n        if (lead != null) for (var i = from.line + 1; i <= end; ++i)\n          if (i != end || lastLineHasText)\n            self.replaceRange(lead + pad, Pos(i, 0));\n      } else {\n        self.replaceRange(endString, to);\n        self.replaceRange(startString, from);\n      }\n    });\n  });\n\n  CodeMirror.defineExtension(\"uncomment\", function(from, to, options) {\n    if (!options) options = noOptions;\n    var self = this, mode = self.getModeAt(from);\n    var end = Math.min(to.ch != 0 || to.line == from.line ? to.line : to.line - 1, self.lastLine()), start = Math.min(from.line, end);\n\n    // Try finding line comments\n    var lineString = options.lineComment || mode.lineComment, lines = [];\n    var pad = options.padding == null ? \" \" : options.padding, didSomething;\n    lineComment: {\n      if (!lineString) break lineComment;\n      for (var i = start; i <= end; ++i) {\n        var line = self.getLine(i);\n        var found = line.indexOf(lineString);\n        if (found > -1 && !/comment/.test(self.getTokenTypeAt(Pos(i, found + 1)))) found = -1;\n        if (found == -1 && (i != end || i == start) && nonWS.test(line)) break lineComment;\n        if (found > -1 && nonWS.test(line.slice(0, found))) break lineComment;\n        lines.push(line);\n      }\n      self.operation(function() {\n        for (var i = start; i <= end; ++i) {\n          var line = lines[i - start];\n          var pos = line.indexOf(lineString), endPos = pos + lineString.length;\n          if (pos < 0) continue;\n          if (line.slice(endPos, endPos + pad.length) == pad) endPos += pad.length;\n          didSomething = true;\n          self.replaceRange(\"\", Pos(i, pos), Pos(i, endPos));\n        }\n      });\n      if (didSomething) return true;\n    }\n\n    // Try block comments\n    var startString = options.blockCommentStart || mode.blockCommentStart;\n    var endString = options.blockCommentEnd || mode.blockCommentEnd;\n    if (!startString || !endString) return false;\n    var lead = options.blockCommentLead || mode.blockCommentLead;\n    var startLine = self.getLine(start), endLine = end == start ? startLine : self.getLine(end);\n    var open = startLine.indexOf(startString), close = endLine.lastIndexOf(endString);\n    if (close == -1 && start != end) {\n      endLine = self.getLine(--end);\n      close = endLine.lastIndexOf(endString);\n    }\n    if (open == -1 || close == -1 ||\n        !/comment/.test(self.getTokenTypeAt(Pos(start, open + 1))) ||\n        !/comment/.test(self.getTokenTypeAt(Pos(end, close + 1))))\n      return false;\n\n    // Avoid killing block comments completely outside the selection.\n    // Positions of the last startString before the start of the selection, and the first endString after it.\n    var lastStart = startLine.lastIndexOf(startString, from.ch);\n    var firstEnd = lastStart == -1 ? -1 : startLine.slice(0, from.ch).indexOf(endString, lastStart + startString.length);\n    if (lastStart != -1 && firstEnd != -1 && firstEnd + endString.length != from.ch) return false;\n    // Positions of the first endString after the end of the selection, and the last startString before it.\n    firstEnd = endLine.indexOf(endString, to.ch);\n    var almostLastStart = endLine.slice(to.ch).lastIndexOf(startString, firstEnd - to.ch);\n    lastStart = (firstEnd == -1 || almostLastStart == -1) ? -1 : to.ch + almostLastStart;\n    if (firstEnd != -1 && lastStart != -1 && lastStart != to.ch) return false;\n\n    self.operation(function() {\n      self.replaceRange(\"\", Pos(end, close - (pad && endLine.slice(close - pad.length, close) == pad ? pad.length : 0)),\n                        Pos(end, close + endString.length));\n      var openEnd = open + startString.length;\n      if (pad && startLine.slice(openEnd, openEnd + pad.length) == pad) openEnd += pad.length;\n      self.replaceRange(\"\", Pos(start, open), Pos(start, openEnd));\n      if (lead) for (var i = start + 1; i <= end; ++i) {\n        var line = self.getLine(i), found = line.indexOf(lead);\n        if (found == -1 || nonWS.test(line.slice(0, found))) continue;\n        var foundEnd = found + lead.length;\n        if (pad && line.slice(foundEnd, foundEnd + pad.length) == pad) foundEnd += pad.length;\n        self.replaceRange(\"\", Pos(i, found), Pos(i, foundEnd));\n      }\n    });\n    return true;\n  });\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/comment/continuecomment.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  var modes = [\"clike\", \"css\", \"javascript\"];\n\n  for (var i = 0; i < modes.length; ++i)\n    CodeMirror.extendMode(modes[i], {blockCommentContinue: \" * \"});\n\n  function continueComment(cm) {\n    if (cm.getOption(\"disableInput\")) return CodeMirror.Pass;\n    var ranges = cm.listSelections(), mode, inserts = [];\n    for (var i = 0; i < ranges.length; i++) {\n      var pos = ranges[i].head, token = cm.getTokenAt(pos);\n      if (token.type != \"comment\") return CodeMirror.Pass;\n      var modeHere = CodeMirror.innerMode(cm.getMode(), token.state).mode;\n      if (!mode) mode = modeHere;\n      else if (mode != modeHere) return CodeMirror.Pass;\n\n      var insert = null;\n      if (mode.blockCommentStart && mode.blockCommentContinue) {\n        var end = token.string.indexOf(mode.blockCommentEnd);\n        var full = cm.getRange(CodeMirror.Pos(pos.line, 0), CodeMirror.Pos(pos.line, token.end)), found;\n        if (end != -1 && end == token.string.length - mode.blockCommentEnd.length && pos.ch >= end) {\n          // Comment ended, don't continue it\n        } else if (token.string.indexOf(mode.blockCommentStart) == 0) {\n          insert = full.slice(0, token.start);\n          if (!/^\\s*$/.test(insert)) {\n            insert = \"\";\n            for (var j = 0; j < token.start; ++j) insert += \" \";\n          }\n        } else if ((found = full.indexOf(mode.blockCommentContinue)) != -1 &&\n                   found + mode.blockCommentContinue.length > token.start &&\n                   /^\\s*$/.test(full.slice(0, found))) {\n          insert = full.slice(0, found);\n        }\n        if (insert != null) insert += mode.blockCommentContinue;\n      }\n      if (insert == null && mode.lineComment && continueLineCommentEnabled(cm)) {\n        var line = cm.getLine(pos.line), found = line.indexOf(mode.lineComment);\n        if (found > -1) {\n          insert = line.slice(0, found);\n          if (/\\S/.test(insert)) insert = null;\n          else insert += mode.lineComment + line.slice(found + mode.lineComment.length).match(/^\\s*/)[0];\n        }\n      }\n      if (insert == null) return CodeMirror.Pass;\n      inserts[i] = \"\\n\" + insert;\n    }\n\n    cm.operation(function() {\n      for (var i = ranges.length - 1; i >= 0; i--)\n        cm.replaceRange(inserts[i], ranges[i].from(), ranges[i].to(), \"+insert\");\n    });\n  }\n\n  function continueLineCommentEnabled(cm) {\n    var opt = cm.getOption(\"continueComments\");\n    if (opt && typeof opt == \"object\")\n      return opt.continueLineComment !== false;\n    return true;\n  }\n\n  CodeMirror.defineOption(\"continueComments\", null, function(cm, val, prev) {\n    if (prev && prev != CodeMirror.Init)\n      cm.removeKeyMap(\"continueComment\");\n    if (val) {\n      var key = \"Enter\";\n      if (typeof val == \"string\")\n        key = val;\n      else if (typeof val == \"object\" && val.key)\n        key = val.key;\n      var map = {name: \"continueComment\"};\n      map[key] = continueComment;\n      cm.addKeyMap(map);\n    }\n  });\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/dialog/dialog.css",
    "content": ".CodeMirror-dialog {\n  position: absolute;\n  left: 0; right: 0;\n  background: white;\n  z-index: 15;\n  padding: .1em .8em;\n  overflow: hidden;\n  color: #333;\n}\n\n.CodeMirror-dialog-top {\n  border-bottom: 1px solid #eee;\n  top: 0;\n}\n\n.CodeMirror-dialog-bottom {\n  border-top: 1px solid #eee;\n  bottom: 0;\n}\n\n.CodeMirror-dialog input {\n  border: none;\n  outline: none;\n  background: transparent;\n  width: 20em;\n  color: inherit;\n  font-family: monospace;\n}\n\n.CodeMirror-dialog button {\n  font-size: 70%;\n}\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/dialog/dialog.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n// Open simple dialogs on top of an editor. Relies on dialog.css.\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  function dialogDiv(cm, template, bottom) {\n    var wrap = cm.getWrapperElement();\n    var dialog;\n    dialog = wrap.appendChild(document.createElement(\"div\"));\n    if (bottom)\n      dialog.className = \"CodeMirror-dialog CodeMirror-dialog-bottom\";\n    else\n      dialog.className = \"CodeMirror-dialog CodeMirror-dialog-top\";\n\n    if (typeof template == \"string\") {\n      dialog.innerHTML = template;\n    } else { // Assuming it's a detached DOM element.\n      dialog.appendChild(template);\n    }\n    return dialog;\n  }\n\n  function closeNotification(cm, newVal) {\n    if (cm.state.currentNotificationClose)\n      cm.state.currentNotificationClose();\n    cm.state.currentNotificationClose = newVal;\n  }\n\n  CodeMirror.defineExtension(\"openDialog\", function(template, callback, options) {\n    if (!options) options = {};\n\n    closeNotification(this, null);\n\n    var dialog = dialogDiv(this, template, options.bottom);\n    var closed = false, me = this;\n    function close(newVal) {\n      if (typeof newVal == 'string') {\n        inp.value = newVal;\n      } else {\n        if (closed) return;\n        closed = true;\n        dialog.parentNode.removeChild(dialog);\n        me.focus();\n\n        if (options.onClose) options.onClose(dialog);\n      }\n    }\n\n    var inp = dialog.getElementsByTagName(\"input\")[0], button;\n    if (inp) {\n      if (options.value) {\n        inp.value = options.value;\n        inp.select();\n      }\n\n      if (options.onInput)\n        CodeMirror.on(inp, \"input\", function(e) { options.onInput(e, inp.value, close);});\n      if (options.onKeyUp)\n        CodeMirror.on(inp, \"keyup\", function(e) {options.onKeyUp(e, inp.value, close);});\n\n      CodeMirror.on(inp, \"keydown\", function(e) {\n        if (options && options.onKeyDown && options.onKeyDown(e, inp.value, close)) { return; }\n        if (e.keyCode == 27 || (options.closeOnEnter !== false && e.keyCode == 13)) {\n          inp.blur();\n          CodeMirror.e_stop(e);\n          close();\n        }\n        if (e.keyCode == 13) callback(inp.value, e);\n      });\n\n      if (options.closeOnBlur !== false) CodeMirror.on(inp, \"blur\", close);\n\n      inp.focus();\n    } else if (button = dialog.getElementsByTagName(\"button\")[0]) {\n      CodeMirror.on(button, \"click\", function() {\n        close();\n        me.focus();\n      });\n\n      if (options.closeOnBlur !== false) CodeMirror.on(button, \"blur\", close);\n\n      button.focus();\n    }\n    return close;\n  });\n\n  CodeMirror.defineExtension(\"openConfirm\", function(template, callbacks, options) {\n    closeNotification(this, null);\n    var dialog = dialogDiv(this, template, options && options.bottom);\n    var buttons = dialog.getElementsByTagName(\"button\");\n    var closed = false, me = this, blurring = 1;\n    function close() {\n      if (closed) return;\n      closed = true;\n      dialog.parentNode.removeChild(dialog);\n      me.focus();\n    }\n    buttons[0].focus();\n    for (var i = 0; i < buttons.length; ++i) {\n      var b = buttons[i];\n      (function(callback) {\n        CodeMirror.on(b, \"click\", function(e) {\n          CodeMirror.e_preventDefault(e);\n          close();\n          if (callback) callback(me);\n        });\n      })(callbacks[i]);\n      CodeMirror.on(b, \"blur\", function() {\n        --blurring;\n        setTimeout(function() { if (blurring <= 0) close(); }, 200);\n      });\n      CodeMirror.on(b, \"focus\", function() { ++blurring; });\n    }\n  });\n\n  /*\n   * openNotification\n   * Opens a notification, that can be closed with an optional timer\n   * (default 5000ms timer) and always closes on click.\n   *\n   * If a notification is opened while another is opened, it will close the\n   * currently opened one and open the new one immediately.\n   */\n  CodeMirror.defineExtension(\"openNotification\", function(template, options) {\n    closeNotification(this, close);\n    var dialog = dialogDiv(this, template, options && options.bottom);\n    var closed = false, doneTimer;\n    var duration = options && typeof options.duration !== \"undefined\" ? options.duration : 5000;\n\n    function close() {\n      if (closed) return;\n      closed = true;\n      clearTimeout(doneTimer);\n      dialog.parentNode.removeChild(dialog);\n    }\n\n    CodeMirror.on(dialog, 'click', function(e) {\n      CodeMirror.e_preventDefault(e);\n      close();\n    });\n\n    if (duration)\n      doneTimer = setTimeout(close, duration);\n\n    return close;\n  });\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/display/fullscreen.css",
    "content": ".CodeMirror-fullscreen {\n  position: fixed;\n  top: 0; left: 0; right: 0; bottom: 0;\n  height: auto;\n  z-index: 9;\n}\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/display/fullscreen.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n\n  CodeMirror.defineOption(\"fullScreen\", false, function(cm, val, old) {\n    if (old == CodeMirror.Init) old = false;\n    if (!old == !val) return;\n    if (val) setFullscreen(cm);\n    else setNormal(cm);\n  });\n\n  function setFullscreen(cm) {\n    var wrap = cm.getWrapperElement();\n    cm.state.fullScreenRestore = {scrollTop: window.pageYOffset, scrollLeft: window.pageXOffset,\n                                  width: wrap.style.width, height: wrap.style.height};\n    wrap.style.width = \"\";\n    wrap.style.height = \"auto\";\n    wrap.className += \" CodeMirror-fullscreen\";\n    document.documentElement.style.overflow = \"hidden\";\n    cm.refresh();\n  }\n\n  function setNormal(cm) {\n    var wrap = cm.getWrapperElement();\n    wrap.className = wrap.className.replace(/\\s*CodeMirror-fullscreen\\b/, \"\");\n    document.documentElement.style.overflow = \"\";\n    var info = cm.state.fullScreenRestore;\n    wrap.style.width = info.width; wrap.style.height = info.height;\n    window.scrollTo(info.scrollLeft, info.scrollTop);\n    cm.refresh();\n  }\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/display/panel.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  CodeMirror.defineExtension(\"addPanel\", function(node, options) {\n    if (!this.state.panels) initPanels(this);\n\n    var info = this.state.panels;\n    if (options && options.position == \"bottom\")\n      info.wrapper.appendChild(node);\n    else\n      info.wrapper.insertBefore(node, info.wrapper.firstChild);\n    var height = (options && options.height) || node.offsetHeight;\n    this._setSize(null, info.heightLeft -= height);\n    info.panels++;\n    return new Panel(this, node, options, height);\n  });\n\n  function Panel(cm, node, options, height) {\n    this.cm = cm;\n    this.node = node;\n    this.options = options;\n    this.height = height;\n    this.cleared = false;\n  }\n\n  Panel.prototype.clear = function() {\n    if (this.cleared) return;\n    this.cleared = true;\n    var info = this.cm.state.panels;\n    this.cm._setSize(null, info.heightLeft += this.height);\n    info.wrapper.removeChild(this.node);\n    if (--info.panels == 0) removePanels(this.cm);\n  };\n\n  Panel.prototype.changed = function(height) {\n    var newHeight = height == null ? this.node.offsetHeight : height;\n    var info = this.cm.state.panels;\n    this.cm._setSize(null, info.height += (newHeight - this.height));\n    this.height = newHeight;\n  };\n\n  function initPanels(cm) {\n    var wrap = cm.getWrapperElement();\n    var style = window.getComputedStyle ? window.getComputedStyle(wrap) : wrap.currentStyle;\n    var height = parseInt(style.height);\n    var info = cm.state.panels = {\n      setHeight: wrap.style.height,\n      heightLeft: height,\n      panels: 0,\n      wrapper: document.createElement(\"div\")\n    };\n    wrap.parentNode.insertBefore(info.wrapper, wrap);\n    var hasFocus = cm.hasFocus();\n    info.wrapper.appendChild(wrap);\n    if (hasFocus) cm.focus();\n\n    cm._setSize = cm.setSize;\n    if (height != null) cm.setSize = function(width, newHeight) {\n      if (newHeight == null) return this._setSize(width, newHeight);\n      info.setHeight = newHeight;\n      if (typeof newHeight != \"number\") {\n        var px = /^(\\d+\\.?\\d*)px$/.exec(newHeight);\n        if (px) {\n          newHeight = Number(px[1]);\n        } else {\n          info.wrapper.style.height = newHeight;\n          newHeight = info.wrapper.offsetHeight;\n          info.wrapper.style.height = \"\";\n        }\n      }\n      cm._setSize(width, info.heightLeft += (newHeight - height));\n      height = newHeight;\n    };\n  }\n\n  function removePanels(cm) {\n    var info = cm.state.panels;\n    cm.state.panels = null;\n\n    var wrap = cm.getWrapperElement();\n    info.wrapper.parentNode.replaceChild(wrap, info.wrapper);\n    wrap.style.height = info.setHeight;\n    cm.setSize = cm._setSize;\n    cm.setSize();\n  }\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/display/placeholder.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  CodeMirror.defineOption(\"placeholder\", \"\", function(cm, val, old) {\n    var prev = old && old != CodeMirror.Init;\n    if (val && !prev) {\n      cm.on(\"blur\", onBlur);\n      cm.on(\"change\", onChange);\n      onChange(cm);\n    } else if (!val && prev) {\n      cm.off(\"blur\", onBlur);\n      cm.off(\"change\", onChange);\n      clearPlaceholder(cm);\n      var wrapper = cm.getWrapperElement();\n      wrapper.className = wrapper.className.replace(\" CodeMirror-empty\", \"\");\n    }\n\n    if (val && !cm.hasFocus()) onBlur(cm);\n  });\n\n  function clearPlaceholder(cm) {\n    if (cm.state.placeholder) {\n      cm.state.placeholder.parentNode.removeChild(cm.state.placeholder);\n      cm.state.placeholder = null;\n    }\n  }\n  function setPlaceholder(cm) {\n    clearPlaceholder(cm);\n    var elt = cm.state.placeholder = document.createElement(\"pre\");\n    elt.style.cssText = \"height: 0; overflow: visible\";\n    elt.className = \"CodeMirror-placeholder\";\n    elt.appendChild(document.createTextNode(cm.getOption(\"placeholder\")));\n    cm.display.lineSpace.insertBefore(elt, cm.display.lineSpace.firstChild);\n  }\n\n  function onBlur(cm) {\n    if (isEmpty(cm)) setPlaceholder(cm);\n  }\n  function onChange(cm) {\n    var wrapper = cm.getWrapperElement(), empty = isEmpty(cm);\n    wrapper.className = wrapper.className.replace(\" CodeMirror-empty\", \"\") + (empty ? \" CodeMirror-empty\" : \"\");\n\n    if (empty) setPlaceholder(cm);\n    else clearPlaceholder(cm);\n  }\n\n  function isEmpty(cm) {\n    return (cm.lineCount() === 1) && (cm.getLine(0) === \"\");\n  }\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/display/rulers.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n\n  CodeMirror.defineOption(\"rulers\", false, function(cm, val, old) {\n    if (old && old != CodeMirror.Init) {\n      clearRulers(cm);\n      cm.off(\"refresh\", refreshRulers);\n    }\n    if (val && val.length) {\n      setRulers(cm);\n      cm.on(\"refresh\", refreshRulers);\n    }\n  });\n\n  function clearRulers(cm) {\n    for (var i = cm.display.lineSpace.childNodes.length - 1; i >= 0; i--) {\n      var node = cm.display.lineSpace.childNodes[i];\n      if (/(^|\\s)CodeMirror-ruler($|\\s)/.test(node.className))\n        node.parentNode.removeChild(node);\n    }\n  }\n\n  function setRulers(cm) {\n    var val = cm.getOption(\"rulers\");\n    var cw = cm.defaultCharWidth();\n    var left = cm.charCoords(CodeMirror.Pos(cm.firstLine(), 0), \"div\").left;\n    var minH = cm.display.scroller.offsetHeight + 30;\n    for (var i = 0; i < val.length; i++) {\n      var elt = document.createElement(\"div\");\n      elt.className = \"CodeMirror-ruler\";\n      var col, cls = null, conf = val[i];\n      if (typeof conf == \"number\") {\n        col = conf;\n      } else {\n        col = conf.column;\n        if (conf.className) elt.className += \" \" + conf.className;\n        if (conf.color) elt.style.borderColor = conf.color;\n        if (conf.lineStyle) elt.style.borderLeftStyle = conf.lineStyle;\n        if (conf.width) elt.style.borderLeftWidth = conf.width;\n        cls = val[i].className;\n      }\n      elt.style.left = (left + col * cw) + \"px\";\n      elt.style.top = \"-50px\";\n      elt.style.bottom = \"-20px\";\n      elt.style.minHeight = minH + \"px\";\n      cm.display.lineSpace.insertBefore(elt, cm.display.cursorDiv);\n    }\n  }\n\n  function refreshRulers(cm) {\n    clearRulers(cm);\n    setRulers(cm);\n  }\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/edit/closebrackets.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  var DEFAULT_BRACKETS = \"()[]{}''\\\"\\\"\";\n  var DEFAULT_TRIPLES = \"'\\\"\";\n  var DEFAULT_EXPLODE_ON_ENTER = \"[]{}\";\n  var SPACE_CHAR_REGEX = /\\s/;\n\n  var Pos = CodeMirror.Pos;\n\n  CodeMirror.defineOption(\"autoCloseBrackets\", false, function(cm, val, old) {\n    if (old != CodeMirror.Init && old)\n      cm.removeKeyMap(\"autoCloseBrackets\");\n    if (!val) return;\n    var pairs = DEFAULT_BRACKETS, triples = DEFAULT_TRIPLES, explode = DEFAULT_EXPLODE_ON_ENTER;\n    if (typeof val == \"string\") pairs = val;\n    else if (typeof val == \"object\") {\n      if (val.pairs != null) pairs = val.pairs;\n      if (val.triples != null) triples = val.triples;\n      if (val.explode != null) explode = val.explode;\n    }\n    var map = buildKeymap(pairs, triples);\n    if (explode) map.Enter = buildExplodeHandler(explode);\n    cm.addKeyMap(map);\n  });\n\n  function charsAround(cm, pos) {\n    var str = cm.getRange(Pos(pos.line, pos.ch - 1),\n                          Pos(pos.line, pos.ch + 1));\n    return str.length == 2 ? str : null;\n  }\n\n  // Project the token type that will exists after the given char is\n  // typed, and use it to determine whether it would cause the start\n  // of a string token.\n  function enteringString(cm, pos, ch) {\n    var line = cm.getLine(pos.line);\n    var token = cm.getTokenAt(pos);\n    if (/\\bstring2?\\b/.test(token.type)) return false;\n    var stream = new CodeMirror.StringStream(line.slice(0, pos.ch) + ch + line.slice(pos.ch), 4);\n    stream.pos = stream.start = token.start;\n    for (;;) {\n      var type1 = cm.getMode().token(stream, token.state);\n      if (stream.pos >= pos.ch + 1) return /\\bstring2?\\b/.test(type1);\n      stream.start = stream.pos;\n    }\n  }\n\n  function buildKeymap(pairs, triples) {\n    var map = {\n      name : \"autoCloseBrackets\",\n      Backspace: function(cm) {\n        if (cm.getOption(\"disableInput\")) return CodeMirror.Pass;\n        var ranges = cm.listSelections();\n        for (var i = 0; i < ranges.length; i++) {\n          if (!ranges[i].empty()) return CodeMirror.Pass;\n          var around = charsAround(cm, ranges[i].head);\n          if (!around || pairs.indexOf(around) % 2 != 0) return CodeMirror.Pass;\n        }\n        for (var i = ranges.length - 1; i >= 0; i--) {\n          var cur = ranges[i].head;\n          cm.replaceRange(\"\", Pos(cur.line, cur.ch - 1), Pos(cur.line, cur.ch + 1));\n        }\n      }\n    };\n    var closingBrackets = \"\";\n    for (var i = 0; i < pairs.length; i += 2) (function(left, right) {\n      closingBrackets += right;\n      map[\"'\" + left + \"'\"] = function(cm) {\n        if (cm.getOption(\"disableInput\")) return CodeMirror.Pass;\n        var ranges = cm.listSelections(), type, next;\n        for (var i = 0; i < ranges.length; i++) {\n          var range = ranges[i], cur = range.head, curType;\n          var next = cm.getRange(cur, Pos(cur.line, cur.ch + 1));\n          if (!range.empty()) {\n            curType = \"surround\";\n          } else if (left == right && next == right) {\n            if (cm.getRange(cur, Pos(cur.line, cur.ch + 3)) == left + left + left)\n              curType = \"skipThree\";\n            else\n              curType = \"skip\";\n          } else if (left == right && cur.ch > 1 && triples.indexOf(left) >= 0 &&\n                     cm.getRange(Pos(cur.line, cur.ch - 2), cur) == left + left &&\n                     (cur.ch <= 2 || cm.getRange(Pos(cur.line, cur.ch - 3), Pos(cur.line, cur.ch - 2)) != left)) {\n            curType = \"addFour\";\n          } else if (left == '\"' || left == \"'\") {\n            if (!CodeMirror.isWordChar(next) && enteringString(cm, cur, left)) curType = \"both\";\n            else return CodeMirror.Pass;\n          } else if (cm.getLine(cur.line).length == cur.ch || closingBrackets.indexOf(next) >= 0 || SPACE_CHAR_REGEX.test(next)) {\n            curType = \"both\";\n          } else {\n            return CodeMirror.Pass;\n          }\n          if (!type) type = curType;\n          else if (type != curType) return CodeMirror.Pass;\n        }\n\n        cm.operation(function() {\n          if (type == \"skip\") {\n            cm.execCommand(\"goCharRight\");\n          } else if (type == \"skipThree\") {\n            for (var i = 0; i < 3; i++)\n              cm.execCommand(\"goCharRight\");\n          } else if (type == \"surround\") {\n            var sels = cm.getSelections();\n            for (var i = 0; i < sels.length; i++)\n              sels[i] = left + sels[i] + right;\n            cm.replaceSelections(sels, \"around\");\n          } else if (type == \"both\") {\n            cm.replaceSelection(left + right, null);\n            cm.execCommand(\"goCharLeft\");\n          } else if (type == \"addFour\") {\n            cm.replaceSelection(left + left + left + left, \"before\");\n            cm.execCommand(\"goCharRight\");\n          }\n        });\n      };\n      if (left != right) map[\"'\" + right + \"'\"] = function(cm) {\n        var ranges = cm.listSelections();\n        for (var i = 0; i < ranges.length; i++) {\n          var range = ranges[i];\n          if (!range.empty() ||\n              cm.getRange(range.head, Pos(range.head.line, range.head.ch + 1)) != right)\n            return CodeMirror.Pass;\n        }\n        cm.execCommand(\"goCharRight\");\n      };\n    })(pairs.charAt(i), pairs.charAt(i + 1));\n    return map;\n  }\n\n  function buildExplodeHandler(pairs) {\n    return function(cm) {\n      if (cm.getOption(\"disableInput\")) return CodeMirror.Pass;\n      var ranges = cm.listSelections();\n      for (var i = 0; i < ranges.length; i++) {\n        if (!ranges[i].empty()) return CodeMirror.Pass;\n        var around = charsAround(cm, ranges[i].head);\n        if (!around || pairs.indexOf(around) % 2 != 0) return CodeMirror.Pass;\n      }\n      cm.operation(function() {\n        cm.replaceSelection(\"\\n\\n\", null);\n        cm.execCommand(\"goCharLeft\");\n        ranges = cm.listSelections();\n        for (var i = 0; i < ranges.length; i++) {\n          var line = ranges[i].head.line;\n          cm.indentLine(line, null, true);\n          cm.indentLine(line + 1, null, true);\n        }\n      });\n    };\n  }\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/edit/closetag.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n/**\n * Tag-closer extension for CodeMirror.\n *\n * This extension adds an \"autoCloseTags\" option that can be set to\n * either true to get the default behavior, or an object to further\n * configure its behavior.\n *\n * These are supported options:\n *\n * `whenClosing` (default true)\n *   Whether to autoclose when the '/' of a closing tag is typed.\n * `whenOpening` (default true)\n *   Whether to autoclose the tag when the final '>' of an opening\n *   tag is typed.\n * `dontCloseTags` (default is empty tags for HTML, none for XML)\n *   An array of tag names that should not be autoclosed.\n * `indentTags` (default is block tags for HTML, none for XML)\n *   An array of tag names that should, when opened, cause a\n *   blank line to be added inside the tag, and the blank line and\n *   closing line to be indented.\n *\n * See demos/closetag.html for a usage example.\n */\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"), require(\"../fold/xml-fold\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\", \"../fold/xml-fold\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  CodeMirror.defineOption(\"autoCloseTags\", false, function(cm, val, old) {\n    if (old != CodeMirror.Init && old)\n      cm.removeKeyMap(\"autoCloseTags\");\n    if (!val) return;\n    var map = {name: \"autoCloseTags\"};\n    if (typeof val != \"object\" || val.whenClosing)\n      map[\"'/'\"] = function(cm) { return autoCloseSlash(cm); };\n    if (typeof val != \"object\" || val.whenOpening)\n      map[\"'>'\"] = function(cm) { return autoCloseGT(cm); };\n    cm.addKeyMap(map);\n  });\n\n  var htmlDontClose = [\"area\", \"base\", \"br\", \"col\", \"command\", \"embed\", \"hr\", \"img\", \"input\", \"keygen\", \"link\", \"meta\", \"param\",\n                       \"source\", \"track\", \"wbr\"];\n  var htmlIndent = [\"applet\", \"blockquote\", \"body\", \"button\", \"div\", \"dl\", \"fieldset\", \"form\", \"frameset\", \"h1\", \"h2\", \"h3\", \"h4\",\n                    \"h5\", \"h6\", \"head\", \"html\", \"iframe\", \"layer\", \"legend\", \"object\", \"ol\", \"p\", \"select\", \"table\", \"ul\"];\n\n  function autoCloseGT(cm) {\n    if (cm.getOption(\"disableInput\")) return CodeMirror.Pass;\n    var ranges = cm.listSelections(), replacements = [];\n    for (var i = 0; i < ranges.length; i++) {\n      if (!ranges[i].empty()) return CodeMirror.Pass;\n      var pos = ranges[i].head, tok = cm.getTokenAt(pos);\n      var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state;\n      if (inner.mode.name != \"xml\" || !state.tagName) return CodeMirror.Pass;\n\n      var opt = cm.getOption(\"autoCloseTags\"), html = inner.mode.configuration == \"html\";\n      var dontCloseTags = (typeof opt == \"object\" && opt.dontCloseTags) || (html && htmlDontClose);\n      var indentTags = (typeof opt == \"object\" && opt.indentTags) || (html && htmlIndent);\n\n      var tagName = state.tagName;\n      if (tok.end > pos.ch) tagName = tagName.slice(0, tagName.length - tok.end + pos.ch);\n      var lowerTagName = tagName.toLowerCase();\n      // Don't process the '>' at the end of an end-tag or self-closing tag\n      if (!tagName ||\n          tok.type == \"string\" && (tok.end != pos.ch || !/[\\\"\\']/.test(tok.string.charAt(tok.string.length - 1)) || tok.string.length == 1) ||\n          tok.type == \"tag\" && state.type == \"closeTag\" ||\n          tok.string.indexOf(\"/\") == (tok.string.length - 1) || // match something like <someTagName />\n          dontCloseTags && indexOf(dontCloseTags, lowerTagName) > -1 ||\n          closingTagExists(cm, tagName, pos, state, true))\n        return CodeMirror.Pass;\n\n      var indent = indentTags && indexOf(indentTags, lowerTagName) > -1;\n      replacements[i] = {indent: indent,\n                         text: \">\" + (indent ? \"\\n\\n\" : \"\") + \"</\" + tagName + \">\",\n                         newPos: indent ? CodeMirror.Pos(pos.line + 1, 0) : CodeMirror.Pos(pos.line, pos.ch + 1)};\n    }\n\n    for (var i = ranges.length - 1; i >= 0; i--) {\n      var info = replacements[i];\n      cm.replaceRange(info.text, ranges[i].head, ranges[i].anchor, \"+insert\");\n      var sel = cm.listSelections().slice(0);\n      sel[i] = {head: info.newPos, anchor: info.newPos};\n      cm.setSelections(sel);\n      if (info.indent) {\n        cm.indentLine(info.newPos.line, null, true);\n        cm.indentLine(info.newPos.line + 1, null, true);\n      }\n    }\n  }\n\n  function autoCloseCurrent(cm, typingSlash) {\n    var ranges = cm.listSelections(), replacements = [];\n    var head = typingSlash ? \"/\" : \"</\";\n    for (var i = 0; i < ranges.length; i++) {\n      if (!ranges[i].empty()) return CodeMirror.Pass;\n      var pos = ranges[i].head, tok = cm.getTokenAt(pos);\n      var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state;\n      if (typingSlash && (tok.type == \"string\" || tok.string.charAt(0) != \"<\" ||\n                          tok.start != pos.ch - 1))\n        return CodeMirror.Pass;\n      // Kludge to get around the fact that we are not in XML mode\n      // when completing in JS/CSS snippet in htmlmixed mode. Does not\n      // work for other XML embedded languages (there is no general\n      // way to go from a mixed mode to its current XML state).\n      if (inner.mode.name != \"xml\") {\n        if (cm.getMode().name == \"htmlmixed\" && inner.mode.name == \"javascript\")\n          replacements[i] = head + \"script>\";\n        else if (cm.getMode().name == \"htmlmixed\" && inner.mode.name == \"css\")\n          replacements[i] = head + \"style>\";\n        else\n          return CodeMirror.Pass;\n      } else {\n        if (!state.context || !state.context.tagName ||\n            closingTagExists(cm, state.context.tagName, pos, state))\n          return CodeMirror.Pass;\n        replacements[i] = head + state.context.tagName + \">\";\n      }\n    }\n    cm.replaceSelections(replacements);\n    ranges = cm.listSelections();\n    for (var i = 0; i < ranges.length; i++)\n      if (i == ranges.length - 1 || ranges[i].head.line < ranges[i + 1].head.line)\n        cm.indentLine(ranges[i].head.line);\n  }\n\n  function autoCloseSlash(cm) {\n    if (cm.getOption(\"disableInput\")) return CodeMirror.Pass;\n    return autoCloseCurrent(cm, true);\n  }\n\n  CodeMirror.commands.closeTag = function(cm) { return autoCloseCurrent(cm); };\n\n  function indexOf(collection, elt) {\n    if (collection.indexOf) return collection.indexOf(elt);\n    for (var i = 0, e = collection.length; i < e; ++i)\n      if (collection[i] == elt) return i;\n    return -1;\n  }\n\n  // If xml-fold is loaded, we use its functionality to try and verify\n  // whether a given tag is actually unclosed.\n  function closingTagExists(cm, tagName, pos, state, newTag) {\n    if (!CodeMirror.scanForClosingTag) return false;\n    var end = Math.min(cm.lastLine() + 1, pos.line + 500);\n    var nextClose = CodeMirror.scanForClosingTag(cm, pos, null, end);\n    if (!nextClose || nextClose.tag != tagName) return false;\n    var cx = state.context;\n    // If the immediate wrapping context contains onCx instances of\n    // the same tag, a closing tag only exists if there are at least\n    // that many closing tags of that type following.\n    for (var onCx = newTag ? 1 : 0; cx && cx.tagName == tagName; cx = cx.prev) ++onCx;\n    pos = nextClose.to;\n    for (var i = 1; i < onCx; i++) {\n      var next = CodeMirror.scanForClosingTag(cm, pos, null, end);\n      if (!next || next.tag != tagName) return false;\n      pos = next.to;\n    }\n    return true;\n  }\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/edit/continuelist.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n\n  var listRE = /^(\\s*)(>[> ]*|[*+-]\\s|(\\d+)\\.)(\\s*)/,\n      emptyListRE = /^(\\s*)(>[> ]*|[*+-]|(\\d+)\\.)(\\s*)$/,\n      unorderedListRE = /[*+-]\\s/;\n\n  CodeMirror.commands.newlineAndIndentContinueMarkdownList = function(cm) {\n    if (cm.getOption(\"disableInput\")) return CodeMirror.Pass;\n    var ranges = cm.listSelections(), replacements = [];\n    for (var i = 0; i < ranges.length; i++) {\n      var pos = ranges[i].head, match;\n      var eolState = cm.getStateAfter(pos.line);\n      var inList = eolState.list !== false;\n      var inQuote = eolState.quote !== false;\n\n      if (!ranges[i].empty() || (!inList && !inQuote) || !(match = cm.getLine(pos.line).match(listRE))) {\n        cm.execCommand(\"newlineAndIndent\");\n        return;\n      }\n      if (cm.getLine(pos.line).match(emptyListRE)) {\n        cm.replaceRange(\"\", {\n          line: pos.line, ch: 0\n        }, {\n          line: pos.line, ch: pos.ch + 1\n        });\n        replacements[i] = \"\\n\";\n\n      } else {\n        var indent = match[1], after = match[4];\n        var bullet = unorderedListRE.test(match[2]) || match[2].indexOf(\">\") >= 0\n          ? match[2]\n          : (parseInt(match[3], 10) + 1) + \".\";\n\n        replacements[i] = \"\\n\" + indent + bullet + after;\n      }\n    }\n\n    cm.replaceSelections(replacements);\n  };\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/edit/matchbrackets.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  var ie_lt8 = /MSIE \\d/.test(navigator.userAgent) &&\n    (document.documentMode == null || document.documentMode < 8);\n\n  var Pos = CodeMirror.Pos;\n\n  var matching = {\"(\": \")>\", \")\": \"(<\", \"[\": \"]>\", \"]\": \"[<\", \"{\": \"}>\", \"}\": \"{<\"};\n\n  function findMatchingBracket(cm, where, strict, config) {\n    var line = cm.getLineHandle(where.line), pos = where.ch - 1;\n    var match = (pos >= 0 && matching[line.text.charAt(pos)]) || matching[line.text.charAt(++pos)];\n    if (!match) return null;\n    var dir = match.charAt(1) == \">\" ? 1 : -1;\n    if (strict && (dir > 0) != (pos == where.ch)) return null;\n    var style = cm.getTokenTypeAt(Pos(where.line, pos + 1));\n\n    var found = scanForBracket(cm, Pos(where.line, pos + (dir > 0 ? 1 : 0)), dir, style || null, config);\n    if (found == null) return null;\n    return {from: Pos(where.line, pos), to: found && found.pos,\n            match: found && found.ch == match.charAt(0), forward: dir > 0};\n  }\n\n  // bracketRegex is used to specify which type of bracket to scan\n  // should be a regexp, e.g. /[[\\]]/\n  //\n  // Note: If \"where\" is on an open bracket, then this bracket is ignored.\n  //\n  // Returns false when no bracket was found, null when it reached\n  // maxScanLines and gave up\n  function scanForBracket(cm, where, dir, style, config) {\n    var maxScanLen = (config && config.maxScanLineLength) || 10000;\n    var maxScanLines = (config && config.maxScanLines) || 1000;\n\n    var stack = [];\n    var re = config && config.bracketRegex ? config.bracketRegex : /[(){}[\\]]/;\n    var lineEnd = dir > 0 ? Math.min(where.line + maxScanLines, cm.lastLine() + 1)\n                          : Math.max(cm.firstLine() - 1, where.line - maxScanLines);\n    for (var lineNo = where.line; lineNo != lineEnd; lineNo += dir) {\n      var line = cm.getLine(lineNo);\n      if (!line) continue;\n      var pos = dir > 0 ? 0 : line.length - 1, end = dir > 0 ? line.length : -1;\n      if (line.length > maxScanLen) continue;\n      if (lineNo == where.line) pos = where.ch - (dir < 0 ? 1 : 0);\n      for (; pos != end; pos += dir) {\n        var ch = line.charAt(pos);\n        if (re.test(ch) && (style === undefined || cm.getTokenTypeAt(Pos(lineNo, pos + 1)) == style)) {\n          var match = matching[ch];\n          if ((match.charAt(1) == \">\") == (dir > 0)) stack.push(ch);\n          else if (!stack.length) return {pos: Pos(lineNo, pos), ch: ch};\n          else stack.pop();\n        }\n      }\n    }\n    return lineNo - dir == (dir > 0 ? cm.lastLine() : cm.firstLine()) ? false : null;\n  }\n\n  function matchBrackets(cm, autoclear, config) {\n    // Disable brace matching in long lines, since it'll cause hugely slow updates\n    var maxHighlightLen = cm.state.matchBrackets.maxHighlightLineLength || 1000;\n    var marks = [], ranges = cm.listSelections();\n    for (var i = 0; i < ranges.length; i++) {\n      var match = ranges[i].empty() && findMatchingBracket(cm, ranges[i].head, false, config);\n      if (match && cm.getLine(match.from.line).length <= maxHighlightLen) {\n        var style = match.match ? \"CodeMirror-matchingbracket\" : \"CodeMirror-nonmatchingbracket\";\n        marks.push(cm.markText(match.from, Pos(match.from.line, match.from.ch + 1), {className: style}));\n        if (match.to && cm.getLine(match.to.line).length <= maxHighlightLen)\n          marks.push(cm.markText(match.to, Pos(match.to.line, match.to.ch + 1), {className: style}));\n      }\n    }\n\n    if (marks.length) {\n      // Kludge to work around the IE bug from issue #1193, where text\n      // input stops going to the textare whever this fires.\n      if (ie_lt8 && cm.state.focused) cm.focus();\n\n      var clear = function() {\n        cm.operation(function() {\n          for (var i = 0; i < marks.length; i++) marks[i].clear();\n        });\n      };\n      if (autoclear) setTimeout(clear, 800);\n      else return clear;\n    }\n  }\n\n  var currentlyHighlighted = null;\n  function doMatchBrackets(cm) {\n    cm.operation(function() {\n      if (currentlyHighlighted) {currentlyHighlighted(); currentlyHighlighted = null;}\n      currentlyHighlighted = matchBrackets(cm, false, cm.state.matchBrackets);\n    });\n  }\n\n  CodeMirror.defineOption(\"matchBrackets\", false, function(cm, val, old) {\n    if (old && old != CodeMirror.Init)\n      cm.off(\"cursorActivity\", doMatchBrackets);\n    if (val) {\n      cm.state.matchBrackets = typeof val == \"object\" ? val : {};\n      cm.on(\"cursorActivity\", doMatchBrackets);\n    }\n  });\n\n  CodeMirror.defineExtension(\"matchBrackets\", function() {matchBrackets(this, true);});\n  CodeMirror.defineExtension(\"findMatchingBracket\", function(pos, strict, config){\n    return findMatchingBracket(this, pos, strict, config);\n  });\n  CodeMirror.defineExtension(\"scanForBracket\", function(pos, dir, style, config){\n    return scanForBracket(this, pos, dir, style, config);\n  });\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/edit/matchtags.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"), require(\"../fold/xml-fold\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\", \"../fold/xml-fold\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n\n  CodeMirror.defineOption(\"matchTags\", false, function(cm, val, old) {\n    if (old && old != CodeMirror.Init) {\n      cm.off(\"cursorActivity\", doMatchTags);\n      cm.off(\"viewportChange\", maybeUpdateMatch);\n      clear(cm);\n    }\n    if (val) {\n      cm.state.matchBothTags = typeof val == \"object\" && val.bothTags;\n      cm.on(\"cursorActivity\", doMatchTags);\n      cm.on(\"viewportChange\", maybeUpdateMatch);\n      doMatchTags(cm);\n    }\n  });\n\n  function clear(cm) {\n    if (cm.state.tagHit) cm.state.tagHit.clear();\n    if (cm.state.tagOther) cm.state.tagOther.clear();\n    cm.state.tagHit = cm.state.tagOther = null;\n  }\n\n  function doMatchTags(cm) {\n    cm.state.failedTagMatch = false;\n    cm.operation(function() {\n      clear(cm);\n      if (cm.somethingSelected()) return;\n      var cur = cm.getCursor(), range = cm.getViewport();\n      range.from = Math.min(range.from, cur.line); range.to = Math.max(cur.line + 1, range.to);\n      var match = CodeMirror.findMatchingTag(cm, cur, range);\n      if (!match) return;\n      if (cm.state.matchBothTags) {\n        var hit = match.at == \"open\" ? match.open : match.close;\n        if (hit) cm.state.tagHit = cm.markText(hit.from, hit.to, {className: \"CodeMirror-matchingtag\"});\n      }\n      var other = match.at == \"close\" ? match.open : match.close;\n      if (other)\n        cm.state.tagOther = cm.markText(other.from, other.to, {className: \"CodeMirror-matchingtag\"});\n      else\n        cm.state.failedTagMatch = true;\n    });\n  }\n\n  function maybeUpdateMatch(cm) {\n    if (cm.state.failedTagMatch) doMatchTags(cm);\n  }\n\n  CodeMirror.commands.toMatchingTag = function(cm) {\n    var found = CodeMirror.findMatchingTag(cm, cm.getCursor());\n    if (found) {\n      var other = found.at == \"close\" ? found.open : found.close;\n      if (other) cm.extendSelection(other.to, other.from);\n    }\n  };\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/edit/trailingspace.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  CodeMirror.defineOption(\"showTrailingSpace\", false, function(cm, val, prev) {\n    if (prev == CodeMirror.Init) prev = false;\n    if (prev && !val)\n      cm.removeOverlay(\"trailingspace\");\n    else if (!prev && val)\n      cm.addOverlay({\n        token: function(stream) {\n          for (var l = stream.string.length, i = l; i && /\\s/.test(stream.string.charAt(i - 1)); --i) {}\n          if (i > stream.pos) { stream.pos = i; return null; }\n          stream.pos = l;\n          return \"trailingspace\";\n        },\n        name: \"trailingspace\"\n      });\n  });\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/fold/brace-fold.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.registerHelper(\"fold\", \"brace\", function(cm, start) {\n  var line = start.line, lineText = cm.getLine(line);\n  var startCh, tokenType;\n\n  function findOpening(openCh) {\n    for (var at = start.ch, pass = 0;;) {\n      var found = at <= 0 ? -1 : lineText.lastIndexOf(openCh, at - 1);\n      if (found == -1) {\n        if (pass == 1) break;\n        pass = 1;\n        at = lineText.length;\n        continue;\n      }\n      if (pass == 1 && found < start.ch) break;\n      tokenType = cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1));\n      if (!/^(comment|string)/.test(tokenType)) return found + 1;\n      at = found - 1;\n    }\n  }\n\n  var startToken = \"{\", endToken = \"}\", startCh = findOpening(\"{\");\n  if (startCh == null) {\n    startToken = \"[\", endToken = \"]\";\n    startCh = findOpening(\"[\");\n  }\n\n  if (startCh == null) return;\n  var count = 1, lastLine = cm.lastLine(), end, endCh;\n  outer: for (var i = line; i <= lastLine; ++i) {\n    var text = cm.getLine(i), pos = i == line ? startCh : 0;\n    for (;;) {\n      var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, pos);\n      if (nextOpen < 0) nextOpen = text.length;\n      if (nextClose < 0) nextClose = text.length;\n      pos = Math.min(nextOpen, nextClose);\n      if (pos == text.length) break;\n      if (cm.getTokenTypeAt(CodeMirror.Pos(i, pos + 1)) == tokenType) {\n        if (pos == nextOpen) ++count;\n        else if (!--count) { end = i; endCh = pos; break outer; }\n      }\n      ++pos;\n    }\n  }\n  if (end == null || line == end && endCh == startCh) return;\n  return {from: CodeMirror.Pos(line, startCh),\n          to: CodeMirror.Pos(end, endCh)};\n});\n\nCodeMirror.registerHelper(\"fold\", \"import\", function(cm, start) {\n  function hasImport(line) {\n    if (line < cm.firstLine() || line > cm.lastLine()) return null;\n    var start = cm.getTokenAt(CodeMirror.Pos(line, 1));\n    if (!/\\S/.test(start.string)) start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1));\n    if (start.type != \"keyword\" || start.string != \"import\") return null;\n    // Now find closing semicolon, return its position\n    for (var i = line, e = Math.min(cm.lastLine(), line + 10); i <= e; ++i) {\n      var text = cm.getLine(i), semi = text.indexOf(\";\");\n      if (semi != -1) return {startCh: start.end, end: CodeMirror.Pos(i, semi)};\n    }\n  }\n\n  var start = start.line, has = hasImport(start), prev;\n  if (!has || hasImport(start - 1) || ((prev = hasImport(start - 2)) && prev.end.line == start - 1))\n    return null;\n  for (var end = has.end;;) {\n    var next = hasImport(end.line + 1);\n    if (next == null) break;\n    end = next.end;\n  }\n  return {from: cm.clipPos(CodeMirror.Pos(start, has.startCh + 1)), to: end};\n});\n\nCodeMirror.registerHelper(\"fold\", \"include\", function(cm, start) {\n  function hasInclude(line) {\n    if (line < cm.firstLine() || line > cm.lastLine()) return null;\n    var start = cm.getTokenAt(CodeMirror.Pos(line, 1));\n    if (!/\\S/.test(start.string)) start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1));\n    if (start.type == \"meta\" && start.string.slice(0, 8) == \"#include\") return start.start + 8;\n  }\n\n  var start = start.line, has = hasInclude(start);\n  if (has == null || hasInclude(start - 1) != null) return null;\n  for (var end = start;;) {\n    var next = hasInclude(end + 1);\n    if (next == null) break;\n    ++end;\n  }\n  return {from: CodeMirror.Pos(start, has + 1),\n          to: cm.clipPos(CodeMirror.Pos(end))};\n});\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/fold/comment-fold.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.registerGlobalHelper(\"fold\", \"comment\", function(mode) {\n  return mode.blockCommentStart && mode.blockCommentEnd;\n}, function(cm, start) {\n  var mode = cm.getModeAt(start), startToken = mode.blockCommentStart, endToken = mode.blockCommentEnd;\n  if (!startToken || !endToken) return;\n  var line = start.line, lineText = cm.getLine(line);\n\n  var startCh;\n  for (var at = start.ch, pass = 0;;) {\n    var found = at <= 0 ? -1 : lineText.lastIndexOf(startToken, at - 1);\n    if (found == -1) {\n      if (pass == 1) return;\n      pass = 1;\n      at = lineText.length;\n      continue;\n    }\n    if (pass == 1 && found < start.ch) return;\n    if (/comment/.test(cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1)))) {\n      startCh = found + startToken.length;\n      break;\n    }\n    at = found - 1;\n  }\n\n  var depth = 1, lastLine = cm.lastLine(), end, endCh;\n  outer: for (var i = line; i <= lastLine; ++i) {\n    var text = cm.getLine(i), pos = i == line ? startCh : 0;\n    for (;;) {\n      var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, pos);\n      if (nextOpen < 0) nextOpen = text.length;\n      if (nextClose < 0) nextClose = text.length;\n      pos = Math.min(nextOpen, nextClose);\n      if (pos == text.length) break;\n      if (pos == nextOpen) ++depth;\n      else if (!--depth) { end = i; endCh = pos; break outer; }\n      ++pos;\n    }\n  }\n  if (end == null || line == end && endCh == startCh) return;\n  return {from: CodeMirror.Pos(line, startCh),\n          to: CodeMirror.Pos(end, endCh)};\n});\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/fold/foldcode.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n\n  function doFold(cm, pos, options, force) {\n    if (options && options.call) {\n      var finder = options;\n      options = null;\n    } else {\n      var finder = getOption(cm, options, \"rangeFinder\");\n    }\n    if (typeof pos == \"number\") pos = CodeMirror.Pos(pos, 0);\n    var minSize = getOption(cm, options, \"minFoldSize\");\n\n    function getRange(allowFolded) {\n      var range = finder(cm, pos);\n      if (!range || range.to.line - range.from.line < minSize) return null;\n      var marks = cm.findMarksAt(range.from);\n      for (var i = 0; i < marks.length; ++i) {\n        if (marks[i].__isFold && force !== \"fold\") {\n          if (!allowFolded) return null;\n          range.cleared = true;\n          marks[i].clear();\n        }\n      }\n      return range;\n    }\n\n    var range = getRange(true);\n    if (getOption(cm, options, \"scanUp\")) while (!range && pos.line > cm.firstLine()) {\n      pos = CodeMirror.Pos(pos.line - 1, 0);\n      range = getRange(false);\n    }\n    if (!range || range.cleared || force === \"unfold\") return;\n\n    var myWidget = makeWidget(cm, options);\n    CodeMirror.on(myWidget, \"mousedown\", function(e) {\n      myRange.clear();\n      CodeMirror.e_preventDefault(e);\n    });\n    var myRange = cm.markText(range.from, range.to, {\n      replacedWith: myWidget,\n      clearOnEnter: true,\n      __isFold: true\n    });\n    myRange.on(\"clear\", function(from, to) {\n      CodeMirror.signal(cm, \"unfold\", cm, from, to);\n    });\n    CodeMirror.signal(cm, \"fold\", cm, range.from, range.to);\n  }\n\n  function makeWidget(cm, options) {\n    var widget = getOption(cm, options, \"widget\");\n    if (typeof widget == \"string\") {\n      var text = document.createTextNode(widget);\n      widget = document.createElement(\"span\");\n      widget.appendChild(text);\n      widget.className = \"CodeMirror-foldmarker\";\n    }\n    return widget;\n  }\n\n  // Clumsy backwards-compatible interface\n  CodeMirror.newFoldFunction = function(rangeFinder, widget) {\n    return function(cm, pos) { doFold(cm, pos, {rangeFinder: rangeFinder, widget: widget}); };\n  };\n\n  // New-style interface\n  CodeMirror.defineExtension(\"foldCode\", function(pos, options, force) {\n    doFold(this, pos, options, force);\n  });\n\n  CodeMirror.defineExtension(\"isFolded\", function(pos) {\n    var marks = this.findMarksAt(pos);\n    for (var i = 0; i < marks.length; ++i)\n      if (marks[i].__isFold) return true;\n  });\n\n  CodeMirror.commands.toggleFold = function(cm) {\n    cm.foldCode(cm.getCursor());\n  };\n  CodeMirror.commands.fold = function(cm) {\n    cm.foldCode(cm.getCursor(), null, \"fold\");\n  };\n  CodeMirror.commands.unfold = function(cm) {\n    cm.foldCode(cm.getCursor(), null, \"unfold\");\n  };\n  CodeMirror.commands.foldAll = function(cm) {\n    cm.operation(function() {\n      for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++)\n        cm.foldCode(CodeMirror.Pos(i, 0), null, \"fold\");\n    });\n  };\n  CodeMirror.commands.unfoldAll = function(cm) {\n    cm.operation(function() {\n      for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++)\n        cm.foldCode(CodeMirror.Pos(i, 0), null, \"unfold\");\n    });\n  };\n\n  CodeMirror.registerHelper(\"fold\", \"combine\", function() {\n    var funcs = Array.prototype.slice.call(arguments, 0);\n    return function(cm, start) {\n      for (var i = 0; i < funcs.length; ++i) {\n        var found = funcs[i](cm, start);\n        if (found) return found;\n      }\n    };\n  });\n\n  CodeMirror.registerHelper(\"fold\", \"auto\", function(cm, start) {\n    var helpers = cm.getHelpers(start, \"fold\");\n    for (var i = 0; i < helpers.length; i++) {\n      var cur = helpers[i](cm, start);\n      if (cur) return cur;\n    }\n  });\n\n  var defaultOptions = {\n    rangeFinder: CodeMirror.fold.auto,\n    widget: \"\\u2194\",\n    minFoldSize: 0,\n    scanUp: false\n  };\n\n  CodeMirror.defineOption(\"foldOptions\", null);\n\n  function getOption(cm, options, name) {\n    if (options && options[name] !== undefined)\n      return options[name];\n    var editorOptions = cm.options.foldOptions;\n    if (editorOptions && editorOptions[name] !== undefined)\n      return editorOptions[name];\n    return defaultOptions[name];\n  }\n\n  CodeMirror.defineExtension(\"foldOption\", function(options, name) {\n    return getOption(this, options, name);\n  });\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/fold/foldgutter.css",
    "content": ".CodeMirror-foldmarker {\n  color: blue;\n  text-shadow: #b9f 1px 1px 2px, #b9f -1px -1px 2px, #b9f 1px -1px 2px, #b9f -1px 1px 2px;\n  font-family: arial;\n  line-height: .3;\n  cursor: pointer;\n}\n.CodeMirror-foldgutter {\n  width: .7em;\n}\n.CodeMirror-foldgutter-open,\n.CodeMirror-foldgutter-folded {\n  cursor: pointer;\n}\n.CodeMirror-foldgutter-open:after {\n  content: \"\\25BE\";\n}\n.CodeMirror-foldgutter-folded:after {\n  content: \"\\25B8\";\n}\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/fold/foldgutter.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"), require(\"./foldcode\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\", \"./foldcode\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n\n  CodeMirror.defineOption(\"foldGutter\", false, function(cm, val, old) {\n    if (old && old != CodeMirror.Init) {\n      cm.clearGutter(cm.state.foldGutter.options.gutter);\n      cm.state.foldGutter = null;\n      cm.off(\"gutterClick\", onGutterClick);\n      cm.off(\"change\", onChange);\n      cm.off(\"viewportChange\", onViewportChange);\n      cm.off(\"fold\", onFold);\n      cm.off(\"unfold\", onFold);\n      cm.off(\"swapDoc\", updateInViewport);\n    }\n    if (val) {\n      cm.state.foldGutter = new State(parseOptions(val));\n      updateInViewport(cm);\n      cm.on(\"gutterClick\", onGutterClick);\n      cm.on(\"change\", onChange);\n      cm.on(\"viewportChange\", onViewportChange);\n      cm.on(\"fold\", onFold);\n      cm.on(\"unfold\", onFold);\n      cm.on(\"swapDoc\", updateInViewport);\n    }\n  });\n\n  var Pos = CodeMirror.Pos;\n\n  function State(options) {\n    this.options = options;\n    this.from = this.to = 0;\n  }\n\n  function parseOptions(opts) {\n    if (opts === true) opts = {};\n    if (opts.gutter == null) opts.gutter = \"CodeMirror-foldgutter\";\n    if (opts.indicatorOpen == null) opts.indicatorOpen = \"CodeMirror-foldgutter-open\";\n    if (opts.indicatorFolded == null) opts.indicatorFolded = \"CodeMirror-foldgutter-folded\";\n    return opts;\n  }\n\n  function isFolded(cm, line) {\n    var marks = cm.findMarksAt(Pos(line));\n    for (var i = 0; i < marks.length; ++i)\n      if (marks[i].__isFold && marks[i].find().from.line == line) return true;\n  }\n\n  function marker(spec) {\n    if (typeof spec == \"string\") {\n      var elt = document.createElement(\"div\");\n      elt.className = spec + \" CodeMirror-guttermarker-subtle\";\n      return elt;\n    } else {\n      return spec.cloneNode(true);\n    }\n  }\n\n  function updateFoldInfo(cm, from, to) {\n    var opts = cm.state.foldGutter.options, cur = from;\n    var minSize = cm.foldOption(opts, \"minFoldSize\");\n    var func = cm.foldOption(opts, \"rangeFinder\");\n    cm.eachLine(from, to, function(line) {\n      var mark = null;\n      if (isFolded(cm, cur)) {\n        mark = marker(opts.indicatorFolded);\n      } else {\n        var pos = Pos(cur, 0);\n        var range = func && func(cm, pos);\n        if (range && range.to.line - range.from.line >= minSize)\n          mark = marker(opts.indicatorOpen);\n      }\n      cm.setGutterMarker(line, opts.gutter, mark);\n      ++cur;\n    });\n  }\n\n  function updateInViewport(cm) {\n    var vp = cm.getViewport(), state = cm.state.foldGutter;\n    if (!state) return;\n    cm.operation(function() {\n      updateFoldInfo(cm, vp.from, vp.to);\n    });\n    state.from = vp.from; state.to = vp.to;\n  }\n\n  function onGutterClick(cm, line, gutter) {\n    var state = cm.state.foldGutter;\n    if (!state) return;\n    var opts = state.options;\n    if (gutter != opts.gutter) return;\n    cm.foldCode(Pos(line, 0), opts.rangeFinder);\n  }\n\n  function onChange(cm) {\n    var state = cm.state.foldGutter;\n    if (!state) return;\n    var opts = state.options;\n    state.from = state.to = 0;\n    clearTimeout(state.changeUpdate);\n    state.changeUpdate = setTimeout(function() { updateInViewport(cm); }, opts.foldOnChangeTimeSpan || 600);\n  }\n\n  function onViewportChange(cm) {\n    var state = cm.state.foldGutter;\n    if (!state) return;\n    var opts = state.options;\n    clearTimeout(state.changeUpdate);\n    state.changeUpdate = setTimeout(function() {\n      var vp = cm.getViewport();\n      if (state.from == state.to || vp.from - state.to > 20 || state.from - vp.to > 20) {\n        updateInViewport(cm);\n      } else {\n        cm.operation(function() {\n          if (vp.from < state.from) {\n            updateFoldInfo(cm, vp.from, state.from);\n            state.from = vp.from;\n          }\n          if (vp.to > state.to) {\n            updateFoldInfo(cm, state.to, vp.to);\n            state.to = vp.to;\n          }\n        });\n      }\n    }, opts.updateViewportTimeSpan || 400);\n  }\n\n  function onFold(cm, from) {\n    var state = cm.state.foldGutter;\n    if (!state) return;\n    var line = from.line;\n    if (line >= state.from && line < state.to)\n      updateFoldInfo(cm, line, line + 1);\n  }\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/fold/indent-fold.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.registerHelper(\"fold\", \"indent\", function(cm, start) {\n  var tabSize = cm.getOption(\"tabSize\"), firstLine = cm.getLine(start.line);\n  if (!/\\S/.test(firstLine)) return;\n  var getIndent = function(line) {\n    return CodeMirror.countColumn(line, null, tabSize);\n  };\n  var myIndent = getIndent(firstLine);\n  var lastLineInFold = null;\n  // Go through lines until we find a line that definitely doesn't belong in\n  // the block we're folding, or to the end.\n  for (var i = start.line + 1, end = cm.lastLine(); i <= end; ++i) {\n    var curLine = cm.getLine(i);\n    var curIndent = getIndent(curLine);\n    if (curIndent > myIndent) {\n      // Lines with a greater indent are considered part of the block.\n      lastLineInFold = i;\n    } else if (!/\\S/.test(curLine)) {\n      // Empty lines might be breaks within the block we're trying to fold.\n    } else {\n      // A non-empty line at an indent equal to or less than ours marks the\n      // start of another block.\n      break;\n    }\n  }\n  if (lastLineInFold) return {\n    from: CodeMirror.Pos(start.line, firstLine.length),\n    to: CodeMirror.Pos(lastLineInFold, cm.getLine(lastLineInFold).length)\n  };\n});\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/fold/markdown-fold.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.registerHelper(\"fold\", \"markdown\", function(cm, start) {\n  var maxDepth = 100;\n\n  function isHeader(lineNo) {\n    var tokentype = cm.getTokenTypeAt(CodeMirror.Pos(lineNo, 0));\n    return tokentype && /\\bheader\\b/.test(tokentype);\n  }\n\n  function headerLevel(lineNo, line, nextLine) {\n    var match = line && line.match(/^#+/);\n    if (match && isHeader(lineNo)) return match[0].length;\n    match = nextLine && nextLine.match(/^[=\\-]+\\s*$/);\n    if (match && isHeader(lineNo + 1)) return nextLine[0] == \"=\" ? 1 : 2;\n    return maxDepth;\n  }\n\n  var firstLine = cm.getLine(start.line), nextLine = cm.getLine(start.line + 1);\n  var level = headerLevel(start.line, firstLine, nextLine);\n  if (level === maxDepth) return undefined;\n\n  var lastLineNo = cm.lastLine();\n  var end = start.line, nextNextLine = cm.getLine(end + 2);\n  while (end < lastLineNo) {\n    if (headerLevel(end + 1, nextLine, nextNextLine) <= level) break;\n    ++end;\n    nextLine = nextNextLine;\n    nextNextLine = cm.getLine(end + 2);\n  }\n\n  return {\n    from: CodeMirror.Pos(start.line, firstLine.length),\n    to: CodeMirror.Pos(end, cm.getLine(end).length)\n  };\n});\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/fold/xml-fold.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n\n  var Pos = CodeMirror.Pos;\n  function cmp(a, b) { return a.line - b.line || a.ch - b.ch; }\n\n  var nameStartChar = \"A-Z_a-z\\\\u00C0-\\\\u00D6\\\\u00D8-\\\\u00F6\\\\u00F8-\\\\u02FF\\\\u0370-\\\\u037D\\\\u037F-\\\\u1FFF\\\\u200C-\\\\u200D\\\\u2070-\\\\u218F\\\\u2C00-\\\\u2FEF\\\\u3001-\\\\uD7FF\\\\uF900-\\\\uFDCF\\\\uFDF0-\\\\uFFFD\";\n  var nameChar = nameStartChar + \"\\-\\:\\.0-9\\\\u00B7\\\\u0300-\\\\u036F\\\\u203F-\\\\u2040\";\n  var xmlTagStart = new RegExp(\"<(/?)([\" + nameStartChar + \"][\" + nameChar + \"]*)\", \"g\");\n\n  function Iter(cm, line, ch, range) {\n    this.line = line; this.ch = ch;\n    this.cm = cm; this.text = cm.getLine(line);\n    this.min = range ? range.from : cm.firstLine();\n    this.max = range ? range.to - 1 : cm.lastLine();\n  }\n\n  function tagAt(iter, ch) {\n    var type = iter.cm.getTokenTypeAt(Pos(iter.line, ch));\n    return type && /\\btag\\b/.test(type);\n  }\n\n  function nextLine(iter) {\n    if (iter.line >= iter.max) return;\n    iter.ch = 0;\n    iter.text = iter.cm.getLine(++iter.line);\n    return true;\n  }\n  function prevLine(iter) {\n    if (iter.line <= iter.min) return;\n    iter.text = iter.cm.getLine(--iter.line);\n    iter.ch = iter.text.length;\n    return true;\n  }\n\n  function toTagEnd(iter) {\n    for (;;) {\n      var gt = iter.text.indexOf(\">\", iter.ch);\n      if (gt == -1) { if (nextLine(iter)) continue; else return; }\n      if (!tagAt(iter, gt + 1)) { iter.ch = gt + 1; continue; }\n      var lastSlash = iter.text.lastIndexOf(\"/\", gt);\n      var selfClose = lastSlash > -1 && !/\\S/.test(iter.text.slice(lastSlash + 1, gt));\n      iter.ch = gt + 1;\n      return selfClose ? \"selfClose\" : \"regular\";\n    }\n  }\n  function toTagStart(iter) {\n    for (;;) {\n      var lt = iter.ch ? iter.text.lastIndexOf(\"<\", iter.ch - 1) : -1;\n      if (lt == -1) { if (prevLine(iter)) continue; else return; }\n      if (!tagAt(iter, lt + 1)) { iter.ch = lt; continue; }\n      xmlTagStart.lastIndex = lt;\n      iter.ch = lt;\n      var match = xmlTagStart.exec(iter.text);\n      if (match && match.index == lt) return match;\n    }\n  }\n\n  function toNextTag(iter) {\n    for (;;) {\n      xmlTagStart.lastIndex = iter.ch;\n      var found = xmlTagStart.exec(iter.text);\n      if (!found) { if (nextLine(iter)) continue; else return; }\n      if (!tagAt(iter, found.index + 1)) { iter.ch = found.index + 1; continue; }\n      iter.ch = found.index + found[0].length;\n      return found;\n    }\n  }\n  function toPrevTag(iter) {\n    for (;;) {\n      var gt = iter.ch ? iter.text.lastIndexOf(\">\", iter.ch - 1) : -1;\n      if (gt == -1) { if (prevLine(iter)) continue; else return; }\n      if (!tagAt(iter, gt + 1)) { iter.ch = gt; continue; }\n      var lastSlash = iter.text.lastIndexOf(\"/\", gt);\n      var selfClose = lastSlash > -1 && !/\\S/.test(iter.text.slice(lastSlash + 1, gt));\n      iter.ch = gt + 1;\n      return selfClose ? \"selfClose\" : \"regular\";\n    }\n  }\n\n  function findMatchingClose(iter, tag) {\n    var stack = [];\n    for (;;) {\n      var next = toNextTag(iter), end, startLine = iter.line, startCh = iter.ch - (next ? next[0].length : 0);\n      if (!next || !(end = toTagEnd(iter))) return;\n      if (end == \"selfClose\") continue;\n      if (next[1]) { // closing tag\n        for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == next[2]) {\n          stack.length = i;\n          break;\n        }\n        if (i < 0 && (!tag || tag == next[2])) return {\n          tag: next[2],\n          from: Pos(startLine, startCh),\n          to: Pos(iter.line, iter.ch)\n        };\n      } else { // opening tag\n        stack.push(next[2]);\n      }\n    }\n  }\n  function findMatchingOpen(iter, tag) {\n    var stack = [];\n    for (;;) {\n      var prev = toPrevTag(iter);\n      if (!prev) return;\n      if (prev == \"selfClose\") { toTagStart(iter); continue; }\n      var endLine = iter.line, endCh = iter.ch;\n      var start = toTagStart(iter);\n      if (!start) return;\n      if (start[1]) { // closing tag\n        stack.push(start[2]);\n      } else { // opening tag\n        for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == start[2]) {\n          stack.length = i;\n          break;\n        }\n        if (i < 0 && (!tag || tag == start[2])) return {\n          tag: start[2],\n          from: Pos(iter.line, iter.ch),\n          to: Pos(endLine, endCh)\n        };\n      }\n    }\n  }\n\n  CodeMirror.registerHelper(\"fold\", \"xml\", function(cm, start) {\n    var iter = new Iter(cm, start.line, 0);\n    for (;;) {\n      var openTag = toNextTag(iter), end;\n      if (!openTag || iter.line != start.line || !(end = toTagEnd(iter))) return;\n      if (!openTag[1] && end != \"selfClose\") {\n        var start = Pos(iter.line, iter.ch);\n        var close = findMatchingClose(iter, openTag[2]);\n        return close && {from: start, to: close.from};\n      }\n    }\n  });\n  CodeMirror.findMatchingTag = function(cm, pos, range) {\n    var iter = new Iter(cm, pos.line, pos.ch, range);\n    if (iter.text.indexOf(\">\") == -1 && iter.text.indexOf(\"<\") == -1) return;\n    var end = toTagEnd(iter), to = end && Pos(iter.line, iter.ch);\n    var start = end && toTagStart(iter);\n    if (!end || !start || cmp(iter, pos) > 0) return;\n    var here = {from: Pos(iter.line, iter.ch), to: to, tag: start[2]};\n    if (end == \"selfClose\") return {open: here, close: null, at: \"open\"};\n\n    if (start[1]) { // closing tag\n      return {open: findMatchingOpen(iter, start[2]), close: here, at: \"close\"};\n    } else { // opening tag\n      iter = new Iter(cm, to.line, to.ch, range);\n      return {open: here, close: findMatchingClose(iter, start[2]), at: \"open\"};\n    }\n  };\n\n  CodeMirror.findEnclosingTag = function(cm, pos, range) {\n    var iter = new Iter(cm, pos.line, pos.ch, range);\n    for (;;) {\n      var open = findMatchingOpen(iter);\n      if (!open) break;\n      var forward = new Iter(cm, pos.line, pos.ch, range);\n      var close = findMatchingClose(forward, open.tag);\n      if (close) return {open: open, close: close};\n    }\n  };\n\n  // Used by addon/edit/closetag.js\n  CodeMirror.scanForClosingTag = function(cm, pos, name, end) {\n    var iter = new Iter(cm, pos.line, pos.ch, end ? {from: 0, to: end} : null);\n    return findMatchingClose(iter, name);\n  };\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/hint/anyword-hint.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n\n  var WORD = /[\\w$]+/, RANGE = 500;\n\n  CodeMirror.registerHelper(\"hint\", \"anyword\", function(editor, options) {\n    var word = options && options.word || WORD;\n    var range = options && options.range || RANGE;\n    var cur = editor.getCursor(), curLine = editor.getLine(cur.line);\n    var end = cur.ch, start = end;\n    while (start && word.test(curLine.charAt(start - 1))) --start;\n    var curWord = start != end && curLine.slice(start, end);\n\n    var list = [], seen = {};\n    var re = new RegExp(word.source, \"g\");\n    for (var dir = -1; dir <= 1; dir += 2) {\n      var line = cur.line, endLine = Math.min(Math.max(line + dir * range, editor.firstLine()), editor.lastLine()) + dir;\n      for (; line != endLine; line += dir) {\n        var text = editor.getLine(line), m;\n        while (m = re.exec(text)) {\n          if (line == cur.line && m[0] === curWord) continue;\n          if ((!curWord || m[0].lastIndexOf(curWord, 0) == 0) && !Object.prototype.hasOwnProperty.call(seen, m[0])) {\n            seen[m[0]] = true;\n            list.push(m[0]);\n          }\n        }\n      }\n    }\n    return {list: list, from: CodeMirror.Pos(cur.line, start), to: CodeMirror.Pos(cur.line, end)};\n  });\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/hint/css-hint.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"), require(\"../../mode/css/css\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\", \"../../mode/css/css\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n\n  var pseudoClasses = {link: 1, visited: 1, active: 1, hover: 1, focus: 1,\n                       \"first-letter\": 1, \"first-line\": 1, \"first-child\": 1,\n                       before: 1, after: 1, lang: 1};\n\n  CodeMirror.registerHelper(\"hint\", \"css\", function(cm) {\n    var cur = cm.getCursor(), token = cm.getTokenAt(cur);\n    var inner = CodeMirror.innerMode(cm.getMode(), token.state);\n    if (inner.mode.name != \"css\") return;\n\n    var start = token.start, end = cur.ch, word = token.string.slice(0, end - start);\n    if (/[^\\w$_-]/.test(word)) {\n      word = \"\"; start = end = cur.ch;\n    }\n\n    var spec = CodeMirror.resolveMode(\"text/css\");\n\n    var result = [];\n    function add(keywords) {\n      for (var name in keywords)\n        if (!word || name.lastIndexOf(word, 0) == 0)\n          result.push(name);\n    }\n\n    var st = inner.state.state;\n    if (st == \"pseudo\" || token.type == \"variable-3\") {\n      add(pseudoClasses);\n    } else if (st == \"block\" || st == \"maybeprop\") {\n      add(spec.propertyKeywords);\n    } else if (st == \"prop\" || st == \"parens\" || st == \"at\" || st == \"params\") {\n      add(spec.valueKeywords);\n      add(spec.colorKeywords);\n    } else if (st == \"media\" || st == \"media_parens\") {\n      add(spec.mediaTypes);\n      add(spec.mediaFeatures);\n    }\n\n    if (result.length) return {\n      list: result,\n      from: CodeMirror.Pos(cur.line, start),\n      to: CodeMirror.Pos(cur.line, end)\n    };\n  });\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/hint/html-hint.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"), require(\"./xml-hint\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\", \"./xml-hint\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n\n  var langs = \"ab aa af ak sq am ar an hy as av ae ay az bm ba eu be bn bh bi bs br bg my ca ch ce ny zh cv kw co cr hr cs da dv nl dz en eo et ee fo fj fi fr ff gl ka de el gn gu ht ha he hz hi ho hu ia id ie ga ig ik io is it iu ja jv kl kn kr ks kk km ki rw ky kv kg ko ku kj la lb lg li ln lo lt lu lv gv mk mg ms ml mt mi mr mh mn na nv nb nd ne ng nn no ii nr oc oj cu om or os pa pi fa pl ps pt qu rm rn ro ru sa sc sd se sm sg sr gd sn si sk sl so st es su sw ss sv ta te tg th ti bo tk tl tn to tr ts tt tw ty ug uk ur uz ve vi vo wa cy wo fy xh yi yo za zu\".split(\" \");\n  var targets = [\"_blank\", \"_self\", \"_top\", \"_parent\"];\n  var charsets = [\"ascii\", \"utf-8\", \"utf-16\", \"latin1\", \"latin1\"];\n  var methods = [\"get\", \"post\", \"put\", \"delete\"];\n  var encs = [\"application/x-www-form-urlencoded\", \"multipart/form-data\", \"text/plain\"];\n  var media = [\"all\", \"screen\", \"print\", \"embossed\", \"braille\", \"handheld\", \"print\", \"projection\", \"screen\", \"tty\", \"tv\", \"speech\",\n               \"3d-glasses\", \"resolution [>][<][=] [X]\", \"device-aspect-ratio: X/Y\", \"orientation:portrait\",\n               \"orientation:landscape\", \"device-height: [X]\", \"device-width: [X]\"];\n  var s = { attrs: {} }; // Simple tag, reused for a whole lot of tags\n\n  var data = {\n    a: {\n      attrs: {\n        href: null, ping: null, type: null,\n        media: media,\n        target: targets,\n        hreflang: langs\n      }\n    },\n    abbr: s,\n    acronym: s,\n    address: s,\n    applet: s,\n    area: {\n      attrs: {\n        alt: null, coords: null, href: null, target: null, ping: null,\n        media: media, hreflang: langs, type: null,\n        shape: [\"default\", \"rect\", \"circle\", \"poly\"]\n      }\n    },\n    article: s,\n    aside: s,\n    audio: {\n      attrs: {\n        src: null, mediagroup: null,\n        crossorigin: [\"anonymous\", \"use-credentials\"],\n        preload: [\"none\", \"metadata\", \"auto\"],\n        autoplay: [\"\", \"autoplay\"],\n        loop: [\"\", \"loop\"],\n        controls: [\"\", \"controls\"]\n      }\n    },\n    b: s,\n    base: { attrs: { href: null, target: targets } },\n    basefont: s,\n    bdi: s,\n    bdo: s,\n    big: s,\n    blockquote: { attrs: { cite: null } },\n    body: s,\n    br: s,\n    button: {\n      attrs: {\n        form: null, formaction: null, name: null, value: null,\n        autofocus: [\"\", \"autofocus\"],\n        disabled: [\"\", \"autofocus\"],\n        formenctype: encs,\n        formmethod: methods,\n        formnovalidate: [\"\", \"novalidate\"],\n        formtarget: targets,\n        type: [\"submit\", \"reset\", \"button\"]\n      }\n    },\n    canvas: { attrs: { width: null, height: null } },\n    caption: s,\n    center: s,\n    cite: s,\n    code: s,\n    col: { attrs: { span: null } },\n    colgroup: { attrs: { span: null } },\n    command: {\n      attrs: {\n        type: [\"command\", \"checkbox\", \"radio\"],\n        label: null, icon: null, radiogroup: null, command: null, title: null,\n        disabled: [\"\", \"disabled\"],\n        checked: [\"\", \"checked\"]\n      }\n    },\n    data: { attrs: { value: null } },\n    datagrid: { attrs: { disabled: [\"\", \"disabled\"], multiple: [\"\", \"multiple\"] } },\n    datalist: { attrs: { data: null } },\n    dd: s,\n    del: { attrs: { cite: null, datetime: null } },\n    details: { attrs: { open: [\"\", \"open\"] } },\n    dfn: s,\n    dir: s,\n    div: s,\n    dl: s,\n    dt: s,\n    em: s,\n    embed: { attrs: { src: null, type: null, width: null, height: null } },\n    eventsource: { attrs: { src: null } },\n    fieldset: { attrs: { disabled: [\"\", \"disabled\"], form: null, name: null } },\n    figcaption: s,\n    figure: s,\n    font: s,\n    footer: s,\n    form: {\n      attrs: {\n        action: null, name: null,\n        \"accept-charset\": charsets,\n        autocomplete: [\"on\", \"off\"],\n        enctype: encs,\n        method: methods,\n        novalidate: [\"\", \"novalidate\"],\n        target: targets\n      }\n    },\n    frame: s,\n    frameset: s,\n    h1: s, h2: s, h3: s, h4: s, h5: s, h6: s,\n    head: {\n      attrs: {},\n      children: [\"title\", \"base\", \"link\", \"style\", \"meta\", \"script\", \"noscript\", \"command\"]\n    },\n    header: s,\n    hgroup: s,\n    hr: s,\n    html: {\n      attrs: { manifest: null },\n      children: [\"head\", \"body\"]\n    },\n    i: s,\n    iframe: {\n      attrs: {\n        src: null, srcdoc: null, name: null, width: null, height: null,\n        sandbox: [\"allow-top-navigation\", \"allow-same-origin\", \"allow-forms\", \"allow-scripts\"],\n        seamless: [\"\", \"seamless\"]\n      }\n    },\n    img: {\n      attrs: {\n        alt: null, src: null, ismap: null, usemap: null, width: null, height: null,\n        crossorigin: [\"anonymous\", \"use-credentials\"]\n      }\n    },\n    input: {\n      attrs: {\n        alt: null, dirname: null, form: null, formaction: null,\n        height: null, list: null, max: null, maxlength: null, min: null,\n        name: null, pattern: null, placeholder: null, size: null, src: null,\n        step: null, value: null, width: null,\n        accept: [\"audio/*\", \"video/*\", \"image/*\"],\n        autocomplete: [\"on\", \"off\"],\n        autofocus: [\"\", \"autofocus\"],\n        checked: [\"\", \"checked\"],\n        disabled: [\"\", \"disabled\"],\n        formenctype: encs,\n        formmethod: methods,\n        formnovalidate: [\"\", \"novalidate\"],\n        formtarget: targets,\n        multiple: [\"\", \"multiple\"],\n        readonly: [\"\", \"readonly\"],\n        required: [\"\", \"required\"],\n        type: [\"hidden\", \"text\", \"search\", \"tel\", \"url\", \"email\", \"password\", \"datetime\", \"date\", \"month\",\n               \"week\", \"time\", \"datetime-local\", \"number\", \"range\", \"color\", \"checkbox\", \"radio\",\n               \"file\", \"submit\", \"image\", \"reset\", \"button\"]\n      }\n    },\n    ins: { attrs: { cite: null, datetime: null } },\n    kbd: s,\n    keygen: {\n      attrs: {\n        challenge: null, form: null, name: null,\n        autofocus: [\"\", \"autofocus\"],\n        disabled: [\"\", \"disabled\"],\n        keytype: [\"RSA\"]\n      }\n    },\n    label: { attrs: { \"for\": null, form: null } },\n    legend: s,\n    li: { attrs: { value: null } },\n    link: {\n      attrs: {\n        href: null, type: null,\n        hreflang: langs,\n        media: media,\n        sizes: [\"all\", \"16x16\", \"16x16 32x32\", \"16x16 32x32 64x64\"]\n      }\n    },\n    map: { attrs: { name: null } },\n    mark: s,\n    menu: { attrs: { label: null, type: [\"list\", \"context\", \"toolbar\"] } },\n    meta: {\n      attrs: {\n        content: null,\n        charset: charsets,\n        name: [\"viewport\", \"application-name\", \"author\", \"description\", \"generator\", \"keywords\"],\n        \"http-equiv\": [\"content-language\", \"content-type\", \"default-style\", \"refresh\"]\n      }\n    },\n    meter: { attrs: { value: null, min: null, low: null, high: null, max: null, optimum: null } },\n    nav: s,\n    noframes: s,\n    noscript: s,\n    object: {\n      attrs: {\n        data: null, type: null, name: null, usemap: null, form: null, width: null, height: null,\n        typemustmatch: [\"\", \"typemustmatch\"]\n      }\n    },\n    ol: { attrs: { reversed: [\"\", \"reversed\"], start: null, type: [\"1\", \"a\", \"A\", \"i\", \"I\"] } },\n    optgroup: { attrs: { disabled: [\"\", \"disabled\"], label: null } },\n    option: { attrs: { disabled: [\"\", \"disabled\"], label: null, selected: [\"\", \"selected\"], value: null } },\n    output: { attrs: { \"for\": null, form: null, name: null } },\n    p: s,\n    param: { attrs: { name: null, value: null } },\n    pre: s,\n    progress: { attrs: { value: null, max: null } },\n    q: { attrs: { cite: null } },\n    rp: s,\n    rt: s,\n    ruby: s,\n    s: s,\n    samp: s,\n    script: {\n      attrs: {\n        type: [\"text/javascript\"],\n        src: null,\n        async: [\"\", \"async\"],\n        defer: [\"\", \"defer\"],\n        charset: charsets\n      }\n    },\n    section: s,\n    select: {\n      attrs: {\n        form: null, name: null, size: null,\n        autofocus: [\"\", \"autofocus\"],\n        disabled: [\"\", \"disabled\"],\n        multiple: [\"\", \"multiple\"]\n      }\n    },\n    small: s,\n    source: { attrs: { src: null, type: null, media: null } },\n    span: s,\n    strike: s,\n    strong: s,\n    style: {\n      attrs: {\n        type: [\"text/css\"],\n        media: media,\n        scoped: null\n      }\n    },\n    sub: s,\n    summary: s,\n    sup: s,\n    table: s,\n    tbody: s,\n    td: { attrs: { colspan: null, rowspan: null, headers: null } },\n    textarea: {\n      attrs: {\n        dirname: null, form: null, maxlength: null, name: null, placeholder: null,\n        rows: null, cols: null,\n        autofocus: [\"\", \"autofocus\"],\n        disabled: [\"\", \"disabled\"],\n        readonly: [\"\", \"readonly\"],\n        required: [\"\", \"required\"],\n        wrap: [\"soft\", \"hard\"]\n      }\n    },\n    tfoot: s,\n    th: { attrs: { colspan: null, rowspan: null, headers: null, scope: [\"row\", \"col\", \"rowgroup\", \"colgroup\"] } },\n    thead: s,\n    time: { attrs: { datetime: null } },\n    title: s,\n    tr: s,\n    track: {\n      attrs: {\n        src: null, label: null, \"default\": null,\n        kind: [\"subtitles\", \"captions\", \"descriptions\", \"chapters\", \"metadata\"],\n        srclang: langs\n      }\n    },\n    tt: s,\n    u: s,\n    ul: s,\n    \"var\": s,\n    video: {\n      attrs: {\n        src: null, poster: null, width: null, height: null,\n        crossorigin: [\"anonymous\", \"use-credentials\"],\n        preload: [\"auto\", \"metadata\", \"none\"],\n        autoplay: [\"\", \"autoplay\"],\n        mediagroup: [\"movie\"],\n        muted: [\"\", \"muted\"],\n        controls: [\"\", \"controls\"]\n      }\n    },\n    wbr: s\n  };\n\n  var globalAttrs = {\n    accesskey: [\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\", \"i\", \"j\", \"k\", \"l\", \"m\", \"n\", \"o\", \"p\", \"q\", \"r\", \"s\", \"t\", \"u\", \"v\", \"w\", \"x\", \"y\", \"z\", \"0\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\"],\n    \"class\": null,\n    contenteditable: [\"true\", \"false\"],\n    contextmenu: null,\n    dir: [\"ltr\", \"rtl\", \"auto\"],\n    draggable: [\"true\", \"false\", \"auto\"],\n    dropzone: [\"copy\", \"move\", \"link\", \"string:\", \"file:\"],\n    hidden: [\"hidden\"],\n    id: null,\n    inert: [\"inert\"],\n    itemid: null,\n    itemprop: null,\n    itemref: null,\n    itemscope: [\"itemscope\"],\n    itemtype: null,\n    lang: [\"en\", \"es\"],\n    spellcheck: [\"true\", \"false\"],\n    style: null,\n    tabindex: [\"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\"],\n    title: null,\n    translate: [\"yes\", \"no\"],\n    onclick: null,\n    rel: [\"stylesheet\", \"alternate\", \"author\", \"bookmark\", \"help\", \"license\", \"next\", \"nofollow\", \"noreferrer\", \"prefetch\", \"prev\", \"search\", \"tag\"]\n  };\n  function populate(obj) {\n    for (var attr in globalAttrs) if (globalAttrs.hasOwnProperty(attr))\n      obj.attrs[attr] = globalAttrs[attr];\n  }\n\n  populate(s);\n  for (var tag in data) if (data.hasOwnProperty(tag) && data[tag] != s)\n    populate(data[tag]);\n\n  CodeMirror.htmlSchema = data;\n  function htmlHint(cm, options) {\n    var local = {schemaInfo: data};\n    if (options) for (var opt in options) local[opt] = options[opt];\n    return CodeMirror.hint.xml(cm, local);\n  }\n  CodeMirror.registerHelper(\"hint\", \"html\", htmlHint);\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/hint/javascript-hint.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  var Pos = CodeMirror.Pos;\n\n  function forEach(arr, f) {\n    for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]);\n  }\n\n  function arrayContains(arr, item) {\n    if (!Array.prototype.indexOf) {\n      var i = arr.length;\n      while (i--) {\n        if (arr[i] === item) {\n          return true;\n        }\n      }\n      return false;\n    }\n    return arr.indexOf(item) != -1;\n  }\n\n  function scriptHint(editor, keywords, getToken, options) {\n    // Find the token at the cursor\n    var cur = editor.getCursor(), token = getToken(editor, cur);\n    if (/\\b(?:string|comment)\\b/.test(token.type)) return;\n    token.state = CodeMirror.innerMode(editor.getMode(), token.state).state;\n\n    // If it's not a 'word-style' token, ignore the token.\n    if (!/^[\\w$_]*$/.test(token.string)) {\n      token = {start: cur.ch, end: cur.ch, string: \"\", state: token.state,\n               type: token.string == \".\" ? \"property\" : null};\n    } else if (token.end > cur.ch) {\n      token.end = cur.ch;\n      token.string = token.string.slice(0, cur.ch - token.start);\n    }\n\n    var tprop = token;\n    // If it is a property, find out what it is a property of.\n    while (tprop.type == \"property\") {\n      tprop = getToken(editor, Pos(cur.line, tprop.start));\n      if (tprop.string != \".\") return;\n      tprop = getToken(editor, Pos(cur.line, tprop.start));\n      if (!context) var context = [];\n      context.push(tprop);\n    }\n    return {list: getCompletions(token, context, keywords, options),\n            from: Pos(cur.line, token.start),\n            to: Pos(cur.line, token.end)};\n  }\n\n  function javascriptHint(editor, options) {\n    return scriptHint(editor, javascriptKeywords,\n                      function (e, cur) {return e.getTokenAt(cur);},\n                      options);\n  };\n  CodeMirror.registerHelper(\"hint\", \"javascript\", javascriptHint);\n\n  function getCoffeeScriptToken(editor, cur) {\n  // This getToken, it is for coffeescript, imitates the behavior of\n  // getTokenAt method in javascript.js, that is, returning \"property\"\n  // type and treat \".\" as indepenent token.\n    var token = editor.getTokenAt(cur);\n    if (cur.ch == token.start + 1 && token.string.charAt(0) == '.') {\n      token.end = token.start;\n      token.string = '.';\n      token.type = \"property\";\n    }\n    else if (/^\\.[\\w$_]*$/.test(token.string)) {\n      token.type = \"property\";\n      token.start++;\n      token.string = token.string.replace(/\\./, '');\n    }\n    return token;\n  }\n\n  function coffeescriptHint(editor, options) {\n    return scriptHint(editor, coffeescriptKeywords, getCoffeeScriptToken, options);\n  }\n  CodeMirror.registerHelper(\"hint\", \"coffeescript\", coffeescriptHint);\n\n  var stringProps = (\"charAt charCodeAt indexOf lastIndexOf substring substr slice trim trimLeft trimRight \" +\n                     \"toUpperCase toLowerCase split concat match replace search\").split(\" \");\n  var arrayProps = (\"length concat join splice push pop shift unshift slice reverse sort indexOf \" +\n                    \"lastIndexOf every some filter forEach map reduce reduceRight \").split(\" \");\n  var funcProps = \"prototype apply call bind\".split(\" \");\n  var javascriptKeywords = (\"break case catch continue debugger default delete do else false finally for function \" +\n                  \"if in instanceof new null return switch throw true try typeof var void while with\").split(\" \");\n  var coffeescriptKeywords = (\"and break catch class continue delete do else extends false finally for \" +\n                  \"if in instanceof isnt new no not null of off on or return switch then throw true try typeof until void while with yes\").split(\" \");\n\n  function getCompletions(token, context, keywords, options) {\n    var found = [], start = token.string, global = options && options.globalScope || window;\n    function maybeAdd(str) {\n      if (str.lastIndexOf(start, 0) == 0 && !arrayContains(found, str)) found.push(str);\n    }\n    function gatherCompletions(obj) {\n      if (typeof obj == \"string\") forEach(stringProps, maybeAdd);\n      else if (obj instanceof Array) forEach(arrayProps, maybeAdd);\n      else if (obj instanceof Function) forEach(funcProps, maybeAdd);\n      for (var name in obj) maybeAdd(name);\n    }\n\n    if (context && context.length) {\n      // If this is a property, see if it belongs to some object we can\n      // find in the current environment.\n      var obj = context.pop(), base;\n      if (obj.type && obj.type.indexOf(\"variable\") === 0) {\n        if (options && options.additionalContext)\n          base = options.additionalContext[obj.string];\n        if (!options || options.useGlobalScope !== false)\n          base = base || global[obj.string];\n      } else if (obj.type == \"string\") {\n        base = \"\";\n      } else if (obj.type == \"atom\") {\n        base = 1;\n      } else if (obj.type == \"function\") {\n        if (global.jQuery != null && (obj.string == '$' || obj.string == 'jQuery') &&\n            (typeof global.jQuery == 'function'))\n          base = global.jQuery();\n        else if (global._ != null && (obj.string == '_') && (typeof global._ == 'function'))\n          base = global._();\n      }\n      while (base != null && context.length)\n        base = base[context.pop().string];\n      if (base != null) gatherCompletions(base);\n    } else {\n      // If not, just look in the global object and any local scope\n      // (reading into JS mode internals to get at the local and global variables)\n      for (var v = token.state.localVars; v; v = v.next) maybeAdd(v.name);\n      for (var v = token.state.globalVars; v; v = v.next) maybeAdd(v.name);\n      if (!options || options.useGlobalScope !== false)\n        gatherCompletions(global);\n      forEach(keywords, maybeAdd);\n    }\n    return found;\n  }\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/hint/show-hint.css",
    "content": ".CodeMirror-hints {\n  position: absolute;\n  z-index: 10;\n  overflow: hidden;\n  list-style: none;\n\n  margin: 0;\n  padding: 2px;\n\n  -webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2);\n  -moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2);\n  box-shadow: 2px 3px 5px rgba(0,0,0,.2);\n  border-radius: 3px;\n  border: 1px solid silver;\n\n  background: white;\n  font-size: 90%;\n  font-family: monospace;\n\n  max-height: 20em;\n  overflow-y: auto;\n}\n\n.CodeMirror-hint {\n  margin: 0;\n  padding: 0 4px;\n  border-radius: 2px;\n  max-width: 19em;\n  overflow: hidden;\n  white-space: pre;\n  color: black;\n  cursor: pointer;\n}\n\nli.CodeMirror-hint-active {\n  background: #08f;\n  color: white;\n}\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/hint/show-hint.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n\n  var HINT_ELEMENT_CLASS        = \"CodeMirror-hint\";\n  var ACTIVE_HINT_ELEMENT_CLASS = \"CodeMirror-hint-active\";\n\n  // This is the old interface, kept around for now to stay\n  // backwards-compatible.\n  CodeMirror.showHint = function(cm, getHints, options) {\n    if (!getHints) return cm.showHint(options);\n    if (options && options.async) getHints.async = true;\n    var newOpts = {hint: getHints};\n    if (options) for (var prop in options) newOpts[prop] = options[prop];\n    return cm.showHint(newOpts);\n  };\n\n  var asyncRunID = 0;\n  function retrieveHints(getter, cm, options, then) {\n    if (getter.async) {\n      var id = ++asyncRunID;\n      getter(cm, function(hints) {\n        if (asyncRunID == id) then(hints);\n      }, options);\n    } else {\n      then(getter(cm, options));\n    }\n  }\n\n  CodeMirror.defineExtension(\"showHint\", function(options) {\n    // We want a single cursor position.\n    if (this.listSelections().length > 1 || this.somethingSelected()) return;\n\n    if (this.state.completionActive) this.state.completionActive.close();\n    var completion = this.state.completionActive = new Completion(this, options);\n    var getHints = completion.options.hint;\n    if (!getHints) return;\n\n    CodeMirror.signal(this, \"startCompletion\", this);\n    return retrieveHints(getHints, this, completion.options, function(hints) { completion.showHints(hints); });\n  });\n\n  function Completion(cm, options) {\n    this.cm = cm;\n    this.options = this.buildOptions(options);\n    this.widget = this.onClose = null;\n  }\n\n  Completion.prototype = {\n    close: function() {\n      if (!this.active()) return;\n      this.cm.state.completionActive = null;\n\n      if (this.widget) this.widget.close();\n      if (this.onClose) this.onClose();\n      CodeMirror.signal(this.cm, \"endCompletion\", this.cm);\n    },\n\n    active: function() {\n      return this.cm.state.completionActive == this;\n    },\n\n    pick: function(data, i) {\n      var completion = data.list[i];\n      if (completion.hint) completion.hint(this.cm, data, completion);\n      else this.cm.replaceRange(getText(completion), completion.from || data.from,\n                                completion.to || data.to, \"complete\");\n      CodeMirror.signal(data, \"pick\", completion);\n      this.close();\n    },\n\n    showHints: function(data) {\n      if (!data || !data.list.length || !this.active()) return this.close();\n\n      if (this.options.completeSingle && data.list.length == 1)\n        this.pick(data, 0);\n      else\n        this.showWidget(data);\n    },\n\n    showWidget: function(data) {\n      this.widget = new Widget(this, data);\n      CodeMirror.signal(data, \"shown\");\n\n      var debounce = 0, completion = this, finished;\n      var closeOn = this.options.closeCharacters;\n      var startPos = this.cm.getCursor(), startLen = this.cm.getLine(startPos.line).length;\n\n      var requestAnimationFrame = window.requestAnimationFrame || function(fn) {\n        return setTimeout(fn, 1000/60);\n      };\n      var cancelAnimationFrame = window.cancelAnimationFrame || clearTimeout;\n\n      function done() {\n        if (finished) return;\n        finished = true;\n        completion.close();\n        completion.cm.off(\"cursorActivity\", activity);\n        if (data) CodeMirror.signal(data, \"close\");\n      }\n\n      function update() {\n        if (finished) return;\n        CodeMirror.signal(data, \"update\");\n        retrieveHints(completion.options.hint, completion.cm, completion.options, finishUpdate);\n      }\n      function finishUpdate(data_) {\n        data = data_;\n        if (finished) return;\n        if (!data || !data.list.length) return done();\n        if (completion.widget) completion.widget.close();\n        completion.widget = new Widget(completion, data);\n      }\n\n      function clearDebounce() {\n        if (debounce) {\n          cancelAnimationFrame(debounce);\n          debounce = 0;\n        }\n      }\n\n      function activity() {\n        clearDebounce();\n        var pos = completion.cm.getCursor(), line = completion.cm.getLine(pos.line);\n        if (pos.line != startPos.line || line.length - pos.ch != startLen - startPos.ch ||\n            pos.ch < startPos.ch || completion.cm.somethingSelected() ||\n            (pos.ch && closeOn.test(line.charAt(pos.ch - 1)))) {\n          completion.close();\n        } else {\n          debounce = requestAnimationFrame(update);\n          if (completion.widget) completion.widget.close();\n        }\n      }\n      this.cm.on(\"cursorActivity\", activity);\n      this.onClose = done;\n    },\n\n    buildOptions: function(options) {\n      var editor = this.cm.options.hintOptions;\n      var out = {};\n      for (var prop in defaultOptions) out[prop] = defaultOptions[prop];\n      if (editor) for (var prop in editor)\n        if (editor[prop] !== undefined) out[prop] = editor[prop];\n      if (options) for (var prop in options)\n        if (options[prop] !== undefined) out[prop] = options[prop];\n      return out;\n    }\n  };\n\n  function getText(completion) {\n    if (typeof completion == \"string\") return completion;\n    else return completion.text;\n  }\n\n  function buildKeyMap(completion, handle) {\n    var baseMap = {\n      Up: function() {handle.moveFocus(-1);},\n      Down: function() {handle.moveFocus(1);},\n      PageUp: function() {handle.moveFocus(-handle.menuSize() + 1, true);},\n      PageDown: function() {handle.moveFocus(handle.menuSize() - 1, true);},\n      Home: function() {handle.setFocus(0);},\n      End: function() {handle.setFocus(handle.length - 1);},\n      Enter: handle.pick,\n      Tab: handle.pick,\n      Esc: handle.close\n    };\n    var custom = completion.options.customKeys;\n    var ourMap = custom ? {} : baseMap;\n    function addBinding(key, val) {\n      var bound;\n      if (typeof val != \"string\")\n        bound = function(cm) { return val(cm, handle); };\n      // This mechanism is deprecated\n      else if (baseMap.hasOwnProperty(val))\n        bound = baseMap[val];\n      else\n        bound = val;\n      ourMap[key] = bound;\n    }\n    if (custom)\n      for (var key in custom) if (custom.hasOwnProperty(key))\n        addBinding(key, custom[key]);\n    var extra = completion.options.extraKeys;\n    if (extra)\n      for (var key in extra) if (extra.hasOwnProperty(key))\n        addBinding(key, extra[key]);\n    return ourMap;\n  }\n\n  function getHintElement(hintsElement, el) {\n    while (el && el != hintsElement) {\n      if (el.nodeName.toUpperCase() === \"LI\" && el.parentNode == hintsElement) return el;\n      el = el.parentNode;\n    }\n  }\n\n  function Widget(completion, data) {\n    this.completion = completion;\n    this.data = data;\n    var widget = this, cm = completion.cm;\n\n    var hints = this.hints = document.createElement(\"ul\");\n    hints.className = \"CodeMirror-hints\";\n    this.selectedHint = data.selectedHint || 0;\n\n    var completions = data.list;\n    for (var i = 0; i < completions.length; ++i) {\n      var elt = hints.appendChild(document.createElement(\"li\")), cur = completions[i];\n      var className = HINT_ELEMENT_CLASS + (i != this.selectedHint ? \"\" : \" \" + ACTIVE_HINT_ELEMENT_CLASS);\n      if (cur.className != null) className = cur.className + \" \" + className;\n      elt.className = className;\n      if (cur.render) cur.render(elt, data, cur);\n      else elt.appendChild(document.createTextNode(cur.displayText || getText(cur)));\n      elt.hintId = i;\n    }\n\n    var pos = cm.cursorCoords(completion.options.alignWithWord ? data.from : null);\n    var left = pos.left, top = pos.bottom, below = true;\n    hints.style.left = left + \"px\";\n    hints.style.top = top + \"px\";\n    // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor.\n    var winW = window.innerWidth || Math.max(document.body.offsetWidth, document.documentElement.offsetWidth);\n    var winH = window.innerHeight || Math.max(document.body.offsetHeight, document.documentElement.offsetHeight);\n    (completion.options.container || document.body).appendChild(hints);\n    var box = hints.getBoundingClientRect(), overlapY = box.bottom - winH;\n    if (overlapY > 0) {\n      var height = box.bottom - box.top, curTop = pos.top - (pos.bottom - box.top);\n      if (curTop - height > 0) { // Fits above cursor\n        hints.style.top = (top = pos.top - height) + \"px\";\n        below = false;\n      } else if (height > winH) {\n        hints.style.height = (winH - 5) + \"px\";\n        hints.style.top = (top = pos.bottom - box.top) + \"px\";\n        var cursor = cm.getCursor();\n        if (data.from.ch != cursor.ch) {\n          pos = cm.cursorCoords(cursor);\n          hints.style.left = (left = pos.left) + \"px\";\n          box = hints.getBoundingClientRect();\n        }\n      }\n    }\n    var overlapX = box.right - winW;\n    if (overlapX > 0) {\n      if (box.right - box.left > winW) {\n        hints.style.width = (winW - 5) + \"px\";\n        overlapX -= (box.right - box.left) - winW;\n      }\n      hints.style.left = (left = pos.left - overlapX) + \"px\";\n    }\n\n    cm.addKeyMap(this.keyMap = buildKeyMap(completion, {\n      moveFocus: function(n, avoidWrap) { widget.changeActive(widget.selectedHint + n, avoidWrap); },\n      setFocus: function(n) { widget.changeActive(n); },\n      menuSize: function() { return widget.screenAmount(); },\n      length: completions.length,\n      close: function() { completion.close(); },\n      pick: function() { widget.pick(); },\n      data: data\n    }));\n\n    if (completion.options.closeOnUnfocus) {\n      var closingOnBlur;\n      cm.on(\"blur\", this.onBlur = function() { closingOnBlur = setTimeout(function() { completion.close(); }, 100); });\n      cm.on(\"focus\", this.onFocus = function() { clearTimeout(closingOnBlur); });\n    }\n\n    var startScroll = cm.getScrollInfo();\n    cm.on(\"scroll\", this.onScroll = function() {\n      var curScroll = cm.getScrollInfo(), editor = cm.getWrapperElement().getBoundingClientRect();\n      var newTop = top + startScroll.top - curScroll.top;\n      var point = newTop - (window.pageYOffset || (document.documentElement || document.body).scrollTop);\n      if (!below) point += hints.offsetHeight;\n      if (point <= editor.top || point >= editor.bottom) return completion.close();\n      hints.style.top = newTop + \"px\";\n      hints.style.left = (left + startScroll.left - curScroll.left) + \"px\";\n    });\n\n    CodeMirror.on(hints, \"dblclick\", function(e) {\n      var t = getHintElement(hints, e.target || e.srcElement);\n      if (t && t.hintId != null) {widget.changeActive(t.hintId); widget.pick();}\n    });\n\n    CodeMirror.on(hints, \"click\", function(e) {\n      var t = getHintElement(hints, e.target || e.srcElement);\n      if (t && t.hintId != null) {\n        widget.changeActive(t.hintId);\n        if (completion.options.completeOnSingleClick) widget.pick();\n      }\n    });\n\n    CodeMirror.on(hints, \"mousedown\", function() {\n      setTimeout(function(){cm.focus();}, 20);\n    });\n\n    CodeMirror.signal(data, \"select\", completions[0], hints.firstChild);\n    return true;\n  }\n\n  Widget.prototype = {\n    close: function() {\n      if (this.completion.widget != this) return;\n      this.completion.widget = null;\n      this.hints.parentNode.removeChild(this.hints);\n      this.completion.cm.removeKeyMap(this.keyMap);\n\n      var cm = this.completion.cm;\n      if (this.completion.options.closeOnUnfocus) {\n        cm.off(\"blur\", this.onBlur);\n        cm.off(\"focus\", this.onFocus);\n      }\n      cm.off(\"scroll\", this.onScroll);\n    },\n\n    pick: function() {\n      this.completion.pick(this.data, this.selectedHint);\n    },\n\n    changeActive: function(i, avoidWrap) {\n      if (i >= this.data.list.length)\n        i = avoidWrap ? this.data.list.length - 1 : 0;\n      else if (i < 0)\n        i = avoidWrap ? 0  : this.data.list.length - 1;\n      if (this.selectedHint == i) return;\n      var node = this.hints.childNodes[this.selectedHint];\n      node.className = node.className.replace(\" \" + ACTIVE_HINT_ELEMENT_CLASS, \"\");\n      node = this.hints.childNodes[this.selectedHint = i];\n      node.className += \" \" + ACTIVE_HINT_ELEMENT_CLASS;\n      if (node.offsetTop < this.hints.scrollTop)\n        this.hints.scrollTop = node.offsetTop - 3;\n      else if (node.offsetTop + node.offsetHeight > this.hints.scrollTop + this.hints.clientHeight)\n        this.hints.scrollTop = node.offsetTop + node.offsetHeight - this.hints.clientHeight + 3;\n      CodeMirror.signal(this.data, \"select\", this.data.list[this.selectedHint], node);\n    },\n\n    screenAmount: function() {\n      return Math.floor(this.hints.clientHeight / this.hints.firstChild.offsetHeight) || 1;\n    }\n  };\n\n  CodeMirror.registerHelper(\"hint\", \"auto\", function(cm, options) {\n    var helpers = cm.getHelpers(cm.getCursor(), \"hint\"), words;\n    if (helpers.length) {\n      for (var i = 0; i < helpers.length; i++) {\n        var cur = helpers[i](cm, options);\n        if (cur && cur.list.length) return cur;\n      }\n    } else if (words = cm.getHelper(cm.getCursor(), \"hintWords\")) {\n      if (words) return CodeMirror.hint.fromList(cm, {words: words});\n    } else if (CodeMirror.hint.anyword) {\n      return CodeMirror.hint.anyword(cm, options);\n    }\n  });\n\n  CodeMirror.registerHelper(\"hint\", \"fromList\", function(cm, options) {\n    var cur = cm.getCursor(), token = cm.getTokenAt(cur);\n    var found = [];\n    for (var i = 0; i < options.words.length; i++) {\n      var word = options.words[i];\n      if (word.slice(0, token.string.length) == token.string)\n        found.push(word);\n    }\n\n    if (found.length) return {\n      list: found,\n      from: CodeMirror.Pos(cur.line, token.start),\n            to: CodeMirror.Pos(cur.line, token.end)\n    };\n  });\n\n  CodeMirror.commands.autocomplete = CodeMirror.showHint;\n\n  var defaultOptions = {\n    hint: CodeMirror.hint.auto,\n    completeSingle: true,\n    alignWithWord: true,\n    closeCharacters: /[\\s()\\[\\]{};:>,]/,\n    closeOnUnfocus: true,\n    completeOnSingleClick: false,\n    container: null,\n    customKeys: null,\n    extraKeys: null\n  };\n\n  CodeMirror.defineOption(\"hintOptions\", null);\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/hint/sql-hint.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"), require(\"../../mode/sql/sql\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\", \"../../mode/sql/sql\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n\n  var tables;\n  var defaultTable;\n  var keywords;\n  var CONS = {\n    QUERY_DIV: \";\",\n    ALIAS_KEYWORD: \"AS\"\n  };\n  var Pos = CodeMirror.Pos;\n\n  function getKeywords(editor) {\n    var mode = editor.doc.modeOption;\n    if (mode === \"sql\") mode = \"text/x-sql\";\n    return CodeMirror.resolveMode(mode).keywords;\n  }\n\n  function getText(item) {\n    return typeof item == \"string\" ? item : item.text;\n  }\n\n  function getItem(list, item) {\n    if (!list.slice) return list[item];\n    for (var i = list.length - 1; i >= 0; i--) if (getText(list[i]) == item)\n      return list[i];\n  }\n\n  function shallowClone(object) {\n    var result = {};\n    for (var key in object) if (object.hasOwnProperty(key))\n      result[key] = object[key];\n    return result;\n  }\n\n  function match(string, word) {\n    var len = string.length;\n    var sub = getText(word).substr(0, len);\n    return string.toUpperCase() === sub.toUpperCase();\n  }\n\n  function addMatches(result, search, wordlist, formatter) {\n    for (var word in wordlist) {\n      if (!wordlist.hasOwnProperty(word)) continue;\n      if (Array.isArray(wordlist)) {\n        word = wordlist[word];\n      }\n      if (match(search, word)) {\n        result.push(formatter(word));\n      }\n    }\n  }\n\n  function cleanName(name) {\n    // Get rid name from backticks(`) and preceding dot(.)\n    if (name.charAt(0) == \".\") {\n      name = name.substr(1);\n    }\n    return name.replace(/`/g, \"\");\n  }\n\n  function insertBackticks(name) {\n    var nameParts = getText(name).split(\".\");\n    for (var i = 0; i < nameParts.length; i++)\n      nameParts[i] = \"`\" + nameParts[i] + \"`\";\n    var escaped = nameParts.join(\".\");\n    if (typeof name == \"string\") return escaped;\n    name = shallowClone(name);\n    name.text = escaped;\n    return name;\n  }\n\n  function nameCompletion(cur, token, result, editor) {\n    // Try to complete table, colunm names and return start position of completion\n    var useBacktick = false;\n    var nameParts = [];\n    var start = token.start;\n    var cont = true;\n    while (cont) {\n      cont = (token.string.charAt(0) == \".\");\n      useBacktick = useBacktick || (token.string.charAt(0) == \"`\");\n\n      start = token.start;\n      nameParts.unshift(cleanName(token.string));\n\n      token = editor.getTokenAt(Pos(cur.line, token.start));\n      if (token.string == \".\") {\n        cont = true;\n        token = editor.getTokenAt(Pos(cur.line, token.start));\n      }\n    }\n\n    // Try to complete table names\n    var string = nameParts.join(\".\");\n    addMatches(result, string, tables, function(w) {\n      return useBacktick ? insertBackticks(w) : w;\n    });\n\n    // Try to complete columns from defaultTable\n    addMatches(result, string, defaultTable, function(w) {\n      return useBacktick ? insertBackticks(w) : w;\n    });\n\n    // Try to complete columns\n    string = nameParts.pop();\n    var table = nameParts.join(\".\");\n\n    // Check if table is available. If not, find table by Alias\n    if (!getItem(tables, table))\n      table = findTableByAlias(table, editor);\n\n    var columns = getItem(tables, table);\n    if (columns && Array.isArray(tables) && columns.columns)\n      columns = columns.columns;\n\n    if (columns) {\n      addMatches(result, string, columns, function(w) {\n        if (typeof w == \"string\") {\n          w = table + \".\" + w;\n        } else {\n          w = shallowClone(w);\n          w.text = table + \".\" + w.text;\n        }\n        return useBacktick ? insertBackticks(w) : w;\n      });\n    }\n\n    return start;\n  }\n\n  function eachWord(lineText, f) {\n    if (!lineText) return;\n    var excepted = /[,;]/g;\n    var words = lineText.split(\" \");\n    for (var i = 0; i < words.length; i++) {\n      f(words[i]?words[i].replace(excepted, '') : '');\n    }\n  }\n\n  function convertCurToNumber(cur) {\n    // max characters of a line is 999,999.\n    return cur.line + cur.ch / Math.pow(10, 6);\n  }\n\n  function convertNumberToCur(num) {\n    return Pos(Math.floor(num), +num.toString().split('.').pop());\n  }\n\n  function findTableByAlias(alias, editor) {\n    var doc = editor.doc;\n    var fullQuery = doc.getValue();\n    var aliasUpperCase = alias.toUpperCase();\n    var previousWord = \"\";\n    var table = \"\";\n    var separator = [];\n    var validRange = {\n      start: Pos(0, 0),\n      end: Pos(editor.lastLine(), editor.getLineHandle(editor.lastLine()).length)\n    };\n\n    //add separator\n    var indexOfSeparator = fullQuery.indexOf(CONS.QUERY_DIV);\n    while(indexOfSeparator != -1) {\n      separator.push(doc.posFromIndex(indexOfSeparator));\n      indexOfSeparator = fullQuery.indexOf(CONS.QUERY_DIV, indexOfSeparator+1);\n    }\n    separator.unshift(Pos(0, 0));\n    separator.push(Pos(editor.lastLine(), editor.getLineHandle(editor.lastLine()).text.length));\n\n    //find valid range\n    var prevItem = 0;\n    var current = convertCurToNumber(editor.getCursor());\n    for (var i=0; i< separator.length; i++) {\n      var _v = convertCurToNumber(separator[i]);\n      if (current > prevItem && current <= _v) {\n        validRange = { start: convertNumberToCur(prevItem), end: convertNumberToCur(_v) };\n        break;\n      }\n      prevItem = _v;\n    }\n\n    var query = doc.getRange(validRange.start, validRange.end, false);\n\n    for (var i = 0; i < query.length; i++) {\n      var lineText = query[i];\n      eachWord(lineText, function(word) {\n        var wordUpperCase = word.toUpperCase();\n        if (wordUpperCase === aliasUpperCase && getItem(tables, previousWord))\n          table = previousWord;\n        if (wordUpperCase !== CONS.ALIAS_KEYWORD)\n          previousWord = word;\n      });\n      if (table) break;\n    }\n    return table;\n  }\n\n  CodeMirror.registerHelper(\"hint\", \"sql\", function(editor, options) {\n    tables = (options && options.tables) || {};\n    var defaultTableName = options && options.defaultTable;\n    defaultTable = (defaultTableName && getItem(tables, defaultTableName)) || [];\n    keywords = keywords || getKeywords(editor);\n\n    var cur = editor.getCursor();\n    var result = [];\n    var token = editor.getTokenAt(cur), start, end, search;\n    if (token.end > cur.ch) {\n      token.end = cur.ch;\n      token.string = token.string.slice(0, cur.ch - token.start);\n    }\n\n    if (token.string.match(/^[.`\\w@]\\w*$/)) {\n      search = token.string;\n      start = token.start;\n      end = token.end;\n    } else {\n      start = end = cur.ch;\n      search = \"\";\n    }\n    if (search.charAt(0) == \".\" || search.charAt(0) == \"`\") {\n      start = nameCompletion(cur, token, result, editor);\n    } else {\n      addMatches(result, search, tables, function(w) {return w;});\n      addMatches(result, search, defaultTable, function(w) {return w;});\n      addMatches(result, search, keywords, function(w) {return w.toUpperCase();});\n    }\n\n    return {list: result, from: Pos(cur.line, start), to: Pos(cur.line, end)};\n  });\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/hint/xml-hint.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n\n  var Pos = CodeMirror.Pos;\n\n  function getHints(cm, options) {\n    var tags = options && options.schemaInfo;\n    var quote = (options && options.quoteChar) || '\"';\n    if (!tags) return;\n    var cur = cm.getCursor(), token = cm.getTokenAt(cur);\n    if (token.end > cur.ch) {\n      token.end = cur.ch;\n      token.string = token.string.slice(0, cur.ch - token.start);\n    }\n    var inner = CodeMirror.innerMode(cm.getMode(), token.state);\n    if (inner.mode.name != \"xml\") return;\n    var result = [], replaceToken = false, prefix;\n    var tag = /\\btag\\b/.test(token.type) && !/>$/.test(token.string);\n    var tagName = tag && /^\\w/.test(token.string), tagStart;\n\n    if (tagName) {\n      var before = cm.getLine(cur.line).slice(Math.max(0, token.start - 2), token.start);\n      var tagType = /<\\/$/.test(before) ? \"close\" : /<$/.test(before) ? \"open\" : null;\n      if (tagType) tagStart = token.start - (tagType == \"close\" ? 2 : 1);\n    } else if (tag && token.string == \"<\") {\n      tagType = \"open\";\n    } else if (tag && token.string == \"</\") {\n      tagType = \"close\";\n    }\n\n    if (!tag && !inner.state.tagName || tagType) {\n      if (tagName)\n        prefix = token.string;\n      replaceToken = tagType;\n      var cx = inner.state.context, curTag = cx && tags[cx.tagName];\n      var childList = cx ? curTag && curTag.children : tags[\"!top\"];\n      if (childList && tagType != \"close\") {\n        for (var i = 0; i < childList.length; ++i) if (!prefix || childList[i].lastIndexOf(prefix, 0) == 0)\n          result.push(\"<\" + childList[i]);\n      } else if (tagType != \"close\") {\n        for (var name in tags)\n          if (tags.hasOwnProperty(name) && name != \"!top\" && name != \"!attrs\" && (!prefix || name.lastIndexOf(prefix, 0) == 0))\n            result.push(\"<\" + name);\n      }\n      if (cx && (!prefix || tagType == \"close\" && cx.tagName.lastIndexOf(prefix, 0) == 0))\n        result.push(\"</\" + cx.tagName + \">\");\n    } else {\n      // Attribute completion\n      var curTag = tags[inner.state.tagName], attrs = curTag && curTag.attrs;\n      var globalAttrs = tags[\"!attrs\"];\n      if (!attrs && !globalAttrs) return;\n      if (!attrs) {\n        attrs = globalAttrs;\n      } else if (globalAttrs) { // Combine tag-local and global attributes\n        var set = {};\n        for (var nm in globalAttrs) if (globalAttrs.hasOwnProperty(nm)) set[nm] = globalAttrs[nm];\n        for (var nm in attrs) if (attrs.hasOwnProperty(nm)) set[nm] = attrs[nm];\n        attrs = set;\n      }\n      if (token.type == \"string\" || token.string == \"=\") { // A value\n        var before = cm.getRange(Pos(cur.line, Math.max(0, cur.ch - 60)),\n                                 Pos(cur.line, token.type == \"string\" ? token.start : token.end));\n        var atName = before.match(/([^\\s\\u00a0=<>\\\"\\']+)=$/), atValues;\n        if (!atName || !attrs.hasOwnProperty(atName[1]) || !(atValues = attrs[atName[1]])) return;\n        if (typeof atValues == 'function') atValues = atValues.call(this, cm); // Functions can be used to supply values for autocomplete widget\n        if (token.type == \"string\") {\n          prefix = token.string;\n          var n = 0;\n          if (/['\"]/.test(token.string.charAt(0))) {\n            quote = token.string.charAt(0);\n            prefix = token.string.slice(1);\n            n++;\n          }\n          var len = token.string.length;\n          if (/['\"]/.test(token.string.charAt(len - 1))) {\n            quote = token.string.charAt(len - 1);\n            prefix = token.string.substr(n, len - 2);\n          }\n          replaceToken = true;\n        }\n        for (var i = 0; i < atValues.length; ++i) if (!prefix || atValues[i].lastIndexOf(prefix, 0) == 0)\n          result.push(quote + atValues[i] + quote);\n      } else { // An attribute name\n        if (token.type == \"attribute\") {\n          prefix = token.string;\n          replaceToken = true;\n        }\n        for (var attr in attrs) if (attrs.hasOwnProperty(attr) && (!prefix || attr.lastIndexOf(prefix, 0) == 0))\n          result.push(attr);\n      }\n    }\n    return {\n      list: result,\n      from: replaceToken ? Pos(cur.line, tagStart == null ? token.start : tagStart) : cur,\n      to: replaceToken ? Pos(cur.line, token.end) : cur\n    };\n  }\n\n  CodeMirror.registerHelper(\"hint\", \"xml\", getHints);\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/lint/coffeescript-lint.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n// Depends on coffeelint.js from http://www.coffeelint.org/js/coffeelint.js\n\n// declare global: coffeelint\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.registerHelper(\"lint\", \"coffeescript\", function(text) {\n  var found = [];\n  var parseError = function(err) {\n    var loc = err.lineNumber;\n    found.push({from: CodeMirror.Pos(loc-1, 0),\n                to: CodeMirror.Pos(loc, 0),\n                severity: err.level,\n                message: err.message});\n  };\n  try {\n    var res = coffeelint.lint(text);\n    for(var i = 0; i < res.length; i++) {\n      parseError(res[i]);\n    }\n  } catch(e) {\n    found.push({from: CodeMirror.Pos(e.location.first_line, 0),\n                to: CodeMirror.Pos(e.location.last_line, e.location.last_column),\n                severity: 'error',\n                message: e.message});\n  }\n  return found;\n});\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/lint/css-lint.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n// Depends on csslint.js from https://github.com/stubbornella/csslint\n\n// declare global: CSSLint\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.registerHelper(\"lint\", \"css\", function(text) {\n  var found = [];\n  if (!window.CSSLint) return found;\n  var results = CSSLint.verify(text), messages = results.messages, message = null;\n  for ( var i = 0; i < messages.length; i++) {\n    message = messages[i];\n    var startLine = message.line -1, endLine = message.line -1, startCol = message.col -1, endCol = message.col;\n    found.push({\n      from: CodeMirror.Pos(startLine, startCol),\n      to: CodeMirror.Pos(endLine, endCol),\n      message: message.message,\n      severity : message.type\n    });\n  }\n  return found;\n});\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/lint/javascript-lint.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n  // declare global: JSHINT\n\n  var bogus = [ \"Dangerous comment\" ];\n\n  var warnings = [ [ \"Expected '{'\",\n                     \"Statement body should be inside '{ }' braces.\" ] ];\n\n  var errors = [ \"Missing semicolon\", \"Extra comma\", \"Missing property name\",\n                 \"Unmatched \", \" and instead saw\", \" is not defined\",\n                 \"Unclosed string\", \"Stopping, unable to continue\" ];\n\n  function validator(text, options) {\n    if (!window.JSHINT) return [];\n    JSHINT(text, options);\n    var errors = JSHINT.data().errors, result = [];\n    if (errors) parseErrors(errors, result);\n    return result;\n  }\n\n  CodeMirror.registerHelper(\"lint\", \"javascript\", validator);\n\n  function cleanup(error) {\n    // All problems are warnings by default\n    fixWith(error, warnings, \"warning\", true);\n    fixWith(error, errors, \"error\");\n\n    return isBogus(error) ? null : error;\n  }\n\n  function fixWith(error, fixes, severity, force) {\n    var description, fix, find, replace, found;\n\n    description = error.description;\n\n    for ( var i = 0; i < fixes.length; i++) {\n      fix = fixes[i];\n      find = (typeof fix === \"string\" ? fix : fix[0]);\n      replace = (typeof fix === \"string\" ? null : fix[1]);\n      found = description.indexOf(find) !== -1;\n\n      if (force || found) {\n        error.severity = severity;\n      }\n      if (found && replace) {\n        error.description = replace;\n      }\n    }\n  }\n\n  function isBogus(error) {\n    var description = error.description;\n    for ( var i = 0; i < bogus.length; i++) {\n      if (description.indexOf(bogus[i]) !== -1) {\n        return true;\n      }\n    }\n    return false;\n  }\n\n  function parseErrors(errors, output) {\n    for ( var i = 0; i < errors.length; i++) {\n      var error = errors[i];\n      if (error) {\n        var linetabpositions, index;\n\n        linetabpositions = [];\n\n        // This next block is to fix a problem in jshint. Jshint\n        // replaces\n        // all tabs with spaces then performs some checks. The error\n        // positions (character/space) are then reported incorrectly,\n        // not taking the replacement step into account. Here we look\n        // at the evidence line and try to adjust the character position\n        // to the correct value.\n        if (error.evidence) {\n          // Tab positions are computed once per line and cached\n          var tabpositions = linetabpositions[error.line];\n          if (!tabpositions) {\n            var evidence = error.evidence;\n            tabpositions = [];\n            // ugggh phantomjs does not like this\n            // forEachChar(evidence, function(item, index) {\n            Array.prototype.forEach.call(evidence, function(item,\n                                                            index) {\n              if (item === '\\t') {\n                // First col is 1 (not 0) to match error\n                // positions\n                tabpositions.push(index + 1);\n              }\n            });\n            linetabpositions[error.line] = tabpositions;\n          }\n          if (tabpositions.length > 0) {\n            var pos = error.character;\n            tabpositions.forEach(function(tabposition) {\n              if (pos > tabposition) pos -= 1;\n            });\n            error.character = pos;\n          }\n        }\n\n        var start = error.character - 1, end = start + 1;\n        if (error.evidence) {\n          index = error.evidence.substring(start).search(/.\\b/);\n          if (index > -1) {\n            end += index;\n          }\n        }\n\n        // Convert to format expected by validation service\n        error.description = error.reason;// + \"(jshint)\";\n        error.start = error.character;\n        error.end = end;\n        error = cleanup(error);\n\n        if (error)\n          output.push({message: error.description,\n                       severity: error.severity,\n                       from: CodeMirror.Pos(error.line - 1, start),\n                       to: CodeMirror.Pos(error.line - 1, end)});\n      }\n    }\n  }\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/lint/json-lint.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n// Depends on jsonlint.js from https://github.com/zaach/jsonlint\n\n// declare global: jsonlint\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.registerHelper(\"lint\", \"json\", function(text) {\n  var found = [];\n  jsonlint.parseError = function(str, hash) {\n    var loc = hash.loc;\n    found.push({from: CodeMirror.Pos(loc.first_line - 1, loc.first_column),\n                to: CodeMirror.Pos(loc.last_line - 1, loc.last_column),\n                message: str});\n  };\n  try { jsonlint.parse(text); }\n  catch(e) {}\n  return found;\n});\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/lint/lint.css",
    "content": "/* The lint marker gutter */\n.CodeMirror-lint-markers {\n  width: 16px;\n}\n\n.CodeMirror-lint-tooltip {\n  background-color: infobackground;\n  border: 1px solid black;\n  border-radius: 4px 4px 4px 4px;\n  color: infotext;\n  font-family: monospace;\n  font-size: 10pt;\n  overflow: hidden;\n  padding: 2px 5px;\n  position: fixed;\n  white-space: pre;\n  white-space: pre-wrap;\n  z-index: 100;\n  max-width: 600px;\n  opacity: 0;\n  transition: opacity .4s;\n  -moz-transition: opacity .4s;\n  -webkit-transition: opacity .4s;\n  -o-transition: opacity .4s;\n  -ms-transition: opacity .4s;\n}\n\n.CodeMirror-lint-mark-error, .CodeMirror-lint-mark-warning {\n  background-position: left bottom;\n  background-repeat: repeat-x;\n}\n\n.CodeMirror-lint-mark-error {\n  background-image:\n  url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJDw4cOCW1/KIAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAHElEQVQI12NggIL/DAz/GdA5/xkY/qPKMDAwAADLZwf5rvm+LQAAAABJRU5ErkJggg==\")\n  ;\n}\n\n.CodeMirror-lint-mark-warning {\n  background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJFhQXEbhTg7YAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAMklEQVQI12NkgIIvJ3QXMjAwdDN+OaEbysDA4MPAwNDNwMCwiOHLCd1zX07o6kBVGQEAKBANtobskNMAAAAASUVORK5CYII=\");\n}\n\n.CodeMirror-lint-marker-error, .CodeMirror-lint-marker-warning {\n  background-position: center center;\n  background-repeat: no-repeat;\n  cursor: pointer;\n  display: inline-block;\n  height: 16px;\n  width: 16px;\n  vertical-align: middle;\n  position: relative;\n}\n\n.CodeMirror-lint-message-error, .CodeMirror-lint-message-warning {\n  padding-left: 18px;\n  background-position: top left;\n  background-repeat: no-repeat;\n}\n\n.CodeMirror-lint-marker-error, .CodeMirror-lint-message-error {\n  background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAHlBMVEW7AAC7AACxAAC7AAC7AAAAAAC4AAC5AAD///+7AAAUdclpAAAABnRSTlMXnORSiwCK0ZKSAAAATUlEQVR42mWPOQ7AQAgDuQLx/z8csYRmPRIFIwRGnosRrpamvkKi0FTIiMASR3hhKW+hAN6/tIWhu9PDWiTGNEkTtIOucA5Oyr9ckPgAWm0GPBog6v4AAAAASUVORK5CYII=\");\n}\n\n.CodeMirror-lint-marker-warning, .CodeMirror-lint-message-warning {\n  background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAANlBMVEX/uwDvrwD/uwD/uwD/uwD/uwD/uwD/uwD/uwD6twD/uwAAAADurwD2tQD7uAD+ugAAAAD/uwDhmeTRAAAADHRSTlMJ8mN1EYcbmiixgACm7WbuAAAAVklEQVR42n3PUQqAIBBFUU1LLc3u/jdbOJoW1P08DA9Gba8+YWJ6gNJoNYIBzAA2chBth5kLmG9YUoG0NHAUwFXwO9LuBQL1giCQb8gC9Oro2vp5rncCIY8L8uEx5ZkAAAAASUVORK5CYII=\");\n}\n\n.CodeMirror-lint-marker-multiple {\n  background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAMAAADzjKfhAAAACVBMVEUAAAAAAAC/v7914kyHAAAAAXRSTlMAQObYZgAAACNJREFUeNo1ioEJAAAIwmz/H90iFFSGJgFMe3gaLZ0od+9/AQZ0ADosbYraAAAAAElFTkSuQmCC\");\n  background-repeat: no-repeat;\n  background-position: right bottom;\n  width: 100%; height: 100%;\n}\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/lint/lint.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n  var GUTTER_ID = \"CodeMirror-lint-markers\";\n\n  function showTooltip(e, content) {\n    var tt = document.createElement(\"div\");\n    tt.className = \"CodeMirror-lint-tooltip\";\n    tt.appendChild(content.cloneNode(true));\n    document.body.appendChild(tt);\n\n    function position(e) {\n      if (!tt.parentNode) return CodeMirror.off(document, \"mousemove\", position);\n      tt.style.top = Math.max(0, e.clientY - tt.offsetHeight - 5) + \"px\";\n      tt.style.left = (e.clientX + 5) + \"px\";\n    }\n    CodeMirror.on(document, \"mousemove\", position);\n    position(e);\n    if (tt.style.opacity != null) tt.style.opacity = 1;\n    return tt;\n  }\n  function rm(elt) {\n    if (elt.parentNode) elt.parentNode.removeChild(elt);\n  }\n  function hideTooltip(tt) {\n    if (!tt.parentNode) return;\n    if (tt.style.opacity == null) rm(tt);\n    tt.style.opacity = 0;\n    setTimeout(function() { rm(tt); }, 600);\n  }\n\n  function showTooltipFor(e, content, node) {\n    var tooltip = showTooltip(e, content);\n    function hide() {\n      CodeMirror.off(node, \"mouseout\", hide);\n      if (tooltip) { hideTooltip(tooltip); tooltip = null; }\n    }\n    var poll = setInterval(function() {\n      if (tooltip) for (var n = node;; n = n.parentNode) {\n        if (n && n.nodeType == 11) n = n.host;\n        if (n == document.body) return;\n        if (!n) { hide(); break; }\n      }\n      if (!tooltip) return clearInterval(poll);\n    }, 400);\n    CodeMirror.on(node, \"mouseout\", hide);\n  }\n\n  function LintState(cm, options, hasGutter) {\n    this.marked = [];\n    this.options = options;\n    this.timeout = null;\n    this.hasGutter = hasGutter;\n    this.onMouseOver = function(e) { onMouseOver(cm, e); };\n  }\n\n  function parseOptions(cm, options) {\n    if (options instanceof Function) return {getAnnotations: options};\n    if (!options || options === true) options = {};\n    if (!options.getAnnotations) options.getAnnotations = cm.getHelper(CodeMirror.Pos(0, 0), \"lint\");\n    if (!options.getAnnotations) throw new Error(\"Required option 'getAnnotations' missing (lint addon)\");\n    return options;\n  }\n\n  function clearMarks(cm) {\n    var state = cm.state.lint;\n    if (state.hasGutter) cm.clearGutter(GUTTER_ID);\n    for (var i = 0; i < state.marked.length; ++i)\n      state.marked[i].clear();\n    state.marked.length = 0;\n  }\n\n  function makeMarker(labels, severity, multiple, tooltips) {\n    var marker = document.createElement(\"div\"), inner = marker;\n    marker.className = \"CodeMirror-lint-marker-\" + severity;\n    if (multiple) {\n      inner = marker.appendChild(document.createElement(\"div\"));\n      inner.className = \"CodeMirror-lint-marker-multiple\";\n    }\n\n    if (tooltips != false) CodeMirror.on(inner, \"mouseover\", function(e) {\n      showTooltipFor(e, labels, inner);\n    });\n\n    return marker;\n  }\n\n  function getMaxSeverity(a, b) {\n    if (a == \"error\") return a;\n    else return b;\n  }\n\n  function groupByLine(annotations) {\n    var lines = [];\n    for (var i = 0; i < annotations.length; ++i) {\n      var ann = annotations[i], line = ann.from.line;\n      (lines[line] || (lines[line] = [])).push(ann);\n    }\n    return lines;\n  }\n\n  function annotationTooltip(ann) {\n    var severity = ann.severity;\n    if (!severity) severity = \"error\";\n    var tip = document.createElement(\"div\");\n    tip.className = \"CodeMirror-lint-message-\" + severity;\n    tip.appendChild(document.createTextNode(ann.message));\n    return tip;\n  }\n\n  function startLinting(cm) {\n    var state = cm.state.lint, options = state.options;\n    var passOptions = options.options || options; // Support deprecated passing of `options` property in options\n    if (options.async || options.getAnnotations.async)\n      options.getAnnotations(cm.getValue(), updateLinting, passOptions, cm);\n    else\n      updateLinting(cm, options.getAnnotations(cm.getValue(), passOptions, cm));\n  }\n\n  function updateLinting(cm, annotationsNotSorted) {\n    clearMarks(cm);\n    var state = cm.state.lint, options = state.options;\n\n    var annotations = groupByLine(annotationsNotSorted);\n\n    for (var line = 0; line < annotations.length; ++line) {\n      var anns = annotations[line];\n      if (!anns) continue;\n\n      var maxSeverity = null;\n      var tipLabel = state.hasGutter && document.createDocumentFragment();\n\n      for (var i = 0; i < anns.length; ++i) {\n        var ann = anns[i];\n        var severity = ann.severity;\n        if (!severity) severity = \"error\";\n        maxSeverity = getMaxSeverity(maxSeverity, severity);\n\n        if (options.formatAnnotation) ann = options.formatAnnotation(ann);\n        if (state.hasGutter) tipLabel.appendChild(annotationTooltip(ann));\n\n        if (ann.to) state.marked.push(cm.markText(ann.from, ann.to, {\n          className: \"CodeMirror-lint-mark-\" + severity,\n          __annotation: ann\n        }));\n      }\n\n      if (state.hasGutter)\n        cm.setGutterMarker(line, GUTTER_ID, makeMarker(tipLabel, maxSeverity, anns.length > 1,\n                                                       state.options.tooltips));\n    }\n    if (options.onUpdateLinting) options.onUpdateLinting(annotationsNotSorted, annotations, cm);\n  }\n\n  function onChange(cm) {\n    var state = cm.state.lint;\n    clearTimeout(state.timeout);\n    state.timeout = setTimeout(function(){startLinting(cm);}, state.options.delay || 500);\n  }\n\n  function popupSpanTooltip(ann, e) {\n    var target = e.target || e.srcElement;\n    showTooltipFor(e, annotationTooltip(ann), target);\n  }\n\n  function onMouseOver(cm, e) {\n    var target = e.target || e.srcElement;\n    if (!/\\bCodeMirror-lint-mark-/.test(target.className)) return;\n    var box = target.getBoundingClientRect(), x = (box.left + box.right) / 2, y = (box.top + box.bottom) / 2;\n    var spans = cm.findMarksAt(cm.coordsChar({left: x, top: y}, \"client\"));\n    for (var i = 0; i < spans.length; ++i) {\n      var ann = spans[i].__annotation;\n      if (ann) return popupSpanTooltip(ann, e);\n    }\n  }\n\n  CodeMirror.defineOption(\"lint\", false, function(cm, val, old) {\n    if (old && old != CodeMirror.Init) {\n      clearMarks(cm);\n      cm.off(\"change\", onChange);\n      CodeMirror.off(cm.getWrapperElement(), \"mouseover\", cm.state.lint.onMouseOver);\n      delete cm.state.lint;\n    }\n\n    if (val) {\n      var gutters = cm.getOption(\"gutters\"), hasLintGutter = false;\n      for (var i = 0; i < gutters.length; ++i) if (gutters[i] == GUTTER_ID) hasLintGutter = true;\n      var state = cm.state.lint = new LintState(cm, parseOptions(cm, val), hasLintGutter);\n      cm.on(\"change\", onChange);\n      if (state.options.tooltips != false)\n        CodeMirror.on(cm.getWrapperElement(), \"mouseover\", state.onMouseOver);\n\n      startLinting(cm);\n    }\n  });\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/lint/yaml-lint.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\n// Depends on js-yaml.js from https://github.com/nodeca/js-yaml\n\n// declare global: jsyaml\n\nCodeMirror.registerHelper(\"lint\", \"yaml\", function(text) {\n  var found = [];\n  try { jsyaml.load(text); }\n  catch(e) {\n      var loc = e.mark;\n      found.push({ from: CodeMirror.Pos(loc.line, loc.column), to: CodeMirror.Pos(loc.line, loc.column), message: e.message });\n  }\n  return found;\n});\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/merge/merge.css",
    "content": ".CodeMirror-merge {\n  position: relative;\n  border: 1px solid #ddd;\n  white-space: pre;\n}\n\n.CodeMirror-merge, .CodeMirror-merge .CodeMirror {\n  height: 350px;\n}\n\n.CodeMirror-merge-2pane .CodeMirror-merge-pane { width: 47%; }\n.CodeMirror-merge-2pane .CodeMirror-merge-gap { width: 6%; }\n.CodeMirror-merge-3pane .CodeMirror-merge-pane { width: 31%; }\n.CodeMirror-merge-3pane .CodeMirror-merge-gap { width: 3.5%; }\n\n.CodeMirror-merge-pane {\n  display: inline-block;\n  white-space: normal;\n  vertical-align: top;\n}\n.CodeMirror-merge-pane-rightmost {\n  position: absolute;\n  right: 0px;\n  z-index: 1;\n}\n\n.CodeMirror-merge-gap {\n  z-index: 2;\n  display: inline-block;\n  height: 100%;\n  -moz-box-sizing: border-box;\n  box-sizing: border-box;\n  overflow: hidden;\n  border-left: 1px solid #ddd;\n  border-right: 1px solid #ddd;\n  position: relative;\n  background: #f8f8f8;\n}\n\n.CodeMirror-merge-scrolllock-wrap {\n  position: absolute;\n  bottom: 0; left: 50%;\n}\n.CodeMirror-merge-scrolllock {\n  position: relative;\n  left: -50%;\n  cursor: pointer;\n  color: #555;\n  line-height: 1;\n}\n\n.CodeMirror-merge-copybuttons-left, .CodeMirror-merge-copybuttons-right {\n  position: absolute;\n  left: 0; top: 0;\n  right: 0; bottom: 0;\n  line-height: 1;\n}\n\n.CodeMirror-merge-copy {\n  position: absolute;\n  cursor: pointer;\n  color: #44c;\n}\n\n.CodeMirror-merge-copy-reverse {\n  position: absolute;\n  cursor: pointer;\n  color: #44c;\n}\n\n.CodeMirror-merge-copybuttons-left .CodeMirror-merge-copy { left: 2px; }\n.CodeMirror-merge-copybuttons-right .CodeMirror-merge-copy { right: 2px; }\n\n.CodeMirror-merge-r-inserted, .CodeMirror-merge-l-inserted {\n  background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAACCAYAAACddGYaAAAAGUlEQVQI12MwuCXy3+CWyH8GBgYGJgYkAABZbAQ9ELXurwAAAABJRU5ErkJggg==);\n  background-position: bottom left;\n  background-repeat: repeat-x;\n}\n\n.CodeMirror-merge-r-deleted, .CodeMirror-merge-l-deleted {\n  background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAACCAYAAACddGYaAAAAGUlEQVQI12M4Kyb2/6yY2H8GBgYGJgYkAABURgPz6Ks7wQAAAABJRU5ErkJggg==);\n  background-position: bottom left;\n  background-repeat: repeat-x;\n}\n\n.CodeMirror-merge-r-chunk { background: #ffffe0; }\n.CodeMirror-merge-r-chunk-start { border-top: 1px solid #ee8; }\n.CodeMirror-merge-r-chunk-end { border-bottom: 1px solid #ee8; }\n.CodeMirror-merge-r-connect { fill: #ffffe0; stroke: #ee8; stroke-width: 1px; }\n\n.CodeMirror-merge-l-chunk { background: #eef; }\n.CodeMirror-merge-l-chunk-start { border-top: 1px solid #88e; }\n.CodeMirror-merge-l-chunk-end { border-bottom: 1px solid #88e; }\n.CodeMirror-merge-l-connect { fill: #eef; stroke: #88e; stroke-width: 1px; }\n\n.CodeMirror-merge-l-chunk.CodeMirror-merge-r-chunk { background: #dfd; }\n.CodeMirror-merge-l-chunk-start.CodeMirror-merge-r-chunk-start { border-top: 1px solid #4e4; }\n.CodeMirror-merge-l-chunk-end.CodeMirror-merge-r-chunk-end { border-bottom: 1px solid #4e4; }\n\n.CodeMirror-merge-collapsed-widget:before {\n  content: \"(...)\";\n}\n.CodeMirror-merge-collapsed-widget {\n  cursor: pointer;\n  color: #88b;\n  background: #eef;\n  border: 1px solid #ddf;\n  font-size: 90%;\n  padding: 0 3px;\n  border-radius: 4px;\n}\n.CodeMirror-merge-collapsed-line .CodeMirror-gutter-elt { display: none; }\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/merge/merge.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n// declare global: diff_match_patch, DIFF_INSERT, DIFF_DELETE, DIFF_EQUAL\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"), require(\"diff_match_patch\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\", \"diff_match_patch\"], mod);\n  else // Plain browser env\n    mod(CodeMirror, diff_match_patch);\n})(function(CodeMirror, diff_match_patch) {\n  \"use strict\";\n  var Pos = CodeMirror.Pos;\n  var svgNS = \"http://www.w3.org/2000/svg\";\n\n  function DiffView(mv, type) {\n    this.mv = mv;\n    this.type = type;\n    this.classes = type == \"left\"\n      ? {chunk: \"CodeMirror-merge-l-chunk\",\n         start: \"CodeMirror-merge-l-chunk-start\",\n         end: \"CodeMirror-merge-l-chunk-end\",\n         insert: \"CodeMirror-merge-l-inserted\",\n         del: \"CodeMirror-merge-l-deleted\",\n         connect: \"CodeMirror-merge-l-connect\"}\n      : {chunk: \"CodeMirror-merge-r-chunk\",\n         start: \"CodeMirror-merge-r-chunk-start\",\n         end: \"CodeMirror-merge-r-chunk-end\",\n         insert: \"CodeMirror-merge-r-inserted\",\n         del: \"CodeMirror-merge-r-deleted\",\n         connect: \"CodeMirror-merge-r-connect\"};\n  }\n\n  DiffView.prototype = {\n    constructor: DiffView,\n    init: function(pane, orig, options) {\n      this.edit = this.mv.edit;\n      this.orig = CodeMirror(pane, copyObj({value: orig, readOnly: !this.mv.options.allowEditingOriginals}, copyObj(options)));\n\n      this.diff = getDiff(asString(orig), asString(options.value));\n      this.chunks = getChunks(this.diff);\n      this.diffOutOfDate = this.dealigned = false;\n\n      this.showDifferences = options.showDifferences !== false;\n      this.forceUpdate = registerUpdate(this);\n      setScrollLock(this, true, false);\n      registerScroll(this);\n    },\n    setShowDifferences: function(val) {\n      val = val !== false;\n      if (val != this.showDifferences) {\n        this.showDifferences = val;\n        this.forceUpdate(\"full\");\n      }\n    }\n  };\n\n  function ensureDiff(dv) {\n    if (dv.diffOutOfDate) {\n      dv.diff = getDiff(dv.orig.getValue(), dv.edit.getValue());\n      dv.chunks = getChunks(dv.diff);\n      dv.diffOutOfDate = false;\n      CodeMirror.signal(dv.edit, \"updateDiff\", dv.diff);\n    }\n  }\n\n  var updating = false;\n  function registerUpdate(dv) {\n    var edit = {from: 0, to: 0, marked: []};\n    var orig = {from: 0, to: 0, marked: []};\n    var debounceChange, updatingFast = false;\n    function update(mode) {\n      updating = true;\n      updatingFast = false;\n      if (mode == \"full\") {\n        if (dv.svg) clear(dv.svg);\n        if (dv.copyButtons) clear(dv.copyButtons);\n        clearMarks(dv.edit, edit.marked, dv.classes);\n        clearMarks(dv.orig, orig.marked, dv.classes);\n        edit.from = edit.to = orig.from = orig.to = 0;\n      }\n      ensureDiff(dv);\n      if (dv.showDifferences) {\n        updateMarks(dv.edit, dv.diff, edit, DIFF_INSERT, dv.classes);\n        updateMarks(dv.orig, dv.diff, orig, DIFF_DELETE, dv.classes);\n      }\n      makeConnections(dv);\n\n      if (dv.mv.options.connect == \"align\")\n        alignChunks(dv);\n      updating = false;\n    }\n    function setDealign(fast) {\n      if (updating) return;\n      dv.dealigned = true;\n      set(fast);\n    }\n    function set(fast) {\n      if (updating || updatingFast) return;\n      clearTimeout(debounceChange);\n      if (fast === true) updatingFast = true;\n      debounceChange = setTimeout(update, fast === true ? 20 : 250);\n    }\n    function change(_cm, change) {\n      if (!dv.diffOutOfDate) {\n        dv.diffOutOfDate = true;\n        edit.from = edit.to = orig.from = orig.to = 0;\n      }\n      // Update faster when a line was added/removed\n      setDealign(change.text.length - 1 != change.to.line - change.from.line);\n    }\n    dv.edit.on(\"change\", change);\n    dv.orig.on(\"change\", change);\n    dv.edit.on(\"markerAdded\", setDealign);\n    dv.edit.on(\"markerCleared\", setDealign);\n    dv.orig.on(\"markerAdded\", setDealign);\n    dv.orig.on(\"markerCleared\", setDealign);\n    dv.edit.on(\"viewportChange\", function() { set(false); });\n    dv.orig.on(\"viewportChange\", function() { set(false); });\n    update();\n    return update;\n  }\n\n  function registerScroll(dv) {\n    dv.edit.on(\"scroll\", function() {\n      syncScroll(dv, DIFF_INSERT) && makeConnections(dv);\n    });\n    dv.orig.on(\"scroll\", function() {\n      syncScroll(dv, DIFF_DELETE) && makeConnections(dv);\n    });\n  }\n\n  function syncScroll(dv, type) {\n    // Change handler will do a refresh after a timeout when diff is out of date\n    if (dv.diffOutOfDate) return false;\n    if (!dv.lockScroll) return true;\n    var editor, other, now = +new Date;\n    if (type == DIFF_INSERT) { editor = dv.edit; other = dv.orig; }\n    else { editor = dv.orig; other = dv.edit; }\n    // Don't take action if the position of this editor was recently set\n    // (to prevent feedback loops)\n    if (editor.state.scrollSetBy == dv && (editor.state.scrollSetAt || 0) + 50 > now) return false;\n\n    var sInfo = editor.getScrollInfo();\n    if (dv.mv.options.connect == \"align\") {\n      targetPos = sInfo.top;\n    } else {\n      var halfScreen = .5 * sInfo.clientHeight, midY = sInfo.top + halfScreen;\n      var mid = editor.lineAtHeight(midY, \"local\");\n      var around = chunkBoundariesAround(dv.chunks, mid, type == DIFF_INSERT);\n      var off = getOffsets(editor, type == DIFF_INSERT ? around.edit : around.orig);\n      var offOther = getOffsets(other, type == DIFF_INSERT ? around.orig : around.edit);\n      var ratio = (midY - off.top) / (off.bot - off.top);\n      var targetPos = (offOther.top - halfScreen) + ratio * (offOther.bot - offOther.top);\n\n      var botDist, mix;\n      // Some careful tweaking to make sure no space is left out of view\n      // when scrolling to top or bottom.\n      if (targetPos > sInfo.top && (mix = sInfo.top / halfScreen) < 1) {\n        targetPos = targetPos * mix + sInfo.top * (1 - mix);\n      } else if ((botDist = sInfo.height - sInfo.clientHeight - sInfo.top) < halfScreen) {\n        var otherInfo = other.getScrollInfo();\n        var botDistOther = otherInfo.height - otherInfo.clientHeight - targetPos;\n        if (botDistOther > botDist && (mix = botDist / halfScreen) < 1)\n          targetPos = targetPos * mix + (otherInfo.height - otherInfo.clientHeight - botDist) * (1 - mix);\n      }\n    }\n\n    other.scrollTo(sInfo.left, targetPos);\n    other.state.scrollSetAt = now;\n    other.state.scrollSetBy = dv;\n    return true;\n  }\n\n  function getOffsets(editor, around) {\n    var bot = around.after;\n    if (bot == null) bot = editor.lastLine() + 1;\n    return {top: editor.heightAtLine(around.before || 0, \"local\"),\n            bot: editor.heightAtLine(bot, \"local\")};\n  }\n\n  function setScrollLock(dv, val, action) {\n    dv.lockScroll = val;\n    if (val && action != false) syncScroll(dv, DIFF_INSERT) && makeConnections(dv);\n    dv.lockButton.innerHTML = val ? \"\\u21db\\u21da\" : \"\\u21db&nbsp;&nbsp;\\u21da\";\n  }\n\n  // Updating the marks for editor content\n\n  function clearMarks(editor, arr, classes) {\n    for (var i = 0; i < arr.length; ++i) {\n      var mark = arr[i];\n      if (mark instanceof CodeMirror.TextMarker) {\n        mark.clear();\n      } else if (mark.parent) {\n        editor.removeLineClass(mark, \"background\", classes.chunk);\n        editor.removeLineClass(mark, \"background\", classes.start);\n        editor.removeLineClass(mark, \"background\", classes.end);\n      }\n    }\n    arr.length = 0;\n  }\n\n  // FIXME maybe add a margin around viewport to prevent too many updates\n  function updateMarks(editor, diff, state, type, classes) {\n    var vp = editor.getViewport();\n    editor.operation(function() {\n      if (state.from == state.to || vp.from - state.to > 20 || state.from - vp.to > 20) {\n        clearMarks(editor, state.marked, classes);\n        markChanges(editor, diff, type, state.marked, vp.from, vp.to, classes);\n        state.from = vp.from; state.to = vp.to;\n      } else {\n        if (vp.from < state.from) {\n          markChanges(editor, diff, type, state.marked, vp.from, state.from, classes);\n          state.from = vp.from;\n        }\n        if (vp.to > state.to) {\n          markChanges(editor, diff, type, state.marked, state.to, vp.to, classes);\n          state.to = vp.to;\n        }\n      }\n    });\n  }\n\n  function markChanges(editor, diff, type, marks, from, to, classes) {\n    var pos = Pos(0, 0);\n    var top = Pos(from, 0), bot = editor.clipPos(Pos(to - 1));\n    var cls = type == DIFF_DELETE ? classes.del : classes.insert;\n    function markChunk(start, end) {\n      var bfrom = Math.max(from, start), bto = Math.min(to, end);\n      for (var i = bfrom; i < bto; ++i) {\n        var line = editor.addLineClass(i, \"background\", classes.chunk);\n        if (i == start) editor.addLineClass(line, \"background\", classes.start);\n        if (i == end - 1) editor.addLineClass(line, \"background\", classes.end);\n        marks.push(line);\n      }\n      // When the chunk is empty, make sure a horizontal line shows up\n      if (start == end && bfrom == end && bto == end) {\n        if (bfrom)\n          marks.push(editor.addLineClass(bfrom - 1, \"background\", classes.end));\n        else\n          marks.push(editor.addLineClass(bfrom, \"background\", classes.start));\n      }\n    }\n\n    var chunkStart = 0;\n    for (var i = 0; i < diff.length; ++i) {\n      var part = diff[i], tp = part[0], str = part[1];\n      if (tp == DIFF_EQUAL) {\n        var cleanFrom = pos.line + (startOfLineClean(diff, i) ? 0 : 1);\n        moveOver(pos, str);\n        var cleanTo = pos.line + (endOfLineClean(diff, i) ? 1 : 0);\n        if (cleanTo > cleanFrom) {\n          if (i) markChunk(chunkStart, cleanFrom);\n          chunkStart = cleanTo;\n        }\n      } else {\n        if (tp == type) {\n          var end = moveOver(pos, str, true);\n          var a = posMax(top, pos), b = posMin(bot, end);\n          if (!posEq(a, b))\n            marks.push(editor.markText(a, b, {className: cls}));\n          pos = end;\n        }\n      }\n    }\n    if (chunkStart <= pos.line) markChunk(chunkStart, pos.line + 1);\n  }\n\n  // Updating the gap between editor and original\n\n  function makeConnections(dv) {\n    if (!dv.showDifferences) return;\n\n    if (dv.svg) {\n      clear(dv.svg);\n      var w = dv.gap.offsetWidth;\n      attrs(dv.svg, \"width\", w, \"height\", dv.gap.offsetHeight);\n    }\n    if (dv.copyButtons) clear(dv.copyButtons);\n\n    var vpEdit = dv.edit.getViewport(), vpOrig = dv.orig.getViewport();\n    var sTopEdit = dv.edit.getScrollInfo().top, sTopOrig = dv.orig.getScrollInfo().top;\n    for (var i = 0; i < dv.chunks.length; i++) {\n      var ch = dv.chunks[i];\n      if (ch.editFrom <= vpEdit.to && ch.editTo >= vpEdit.from &&\n          ch.origFrom <= vpOrig.to && ch.origTo >= vpOrig.from)\n        drawConnectorsForChunk(dv, ch, sTopOrig, sTopEdit, w);\n    }\n  }\n\n  function getMatchingOrigLine(editLine, chunks) {\n    var editStart = 0, origStart = 0;\n    for (var i = 0; i < chunks.length; i++) {\n      var chunk = chunks[i];\n      if (chunk.editTo > editLine && chunk.editFrom <= editLine) return null;\n      if (chunk.editFrom > editLine) break;\n      editStart = chunk.editTo;\n      origStart = chunk.origTo;\n    }\n    return origStart + (editLine - editStart);\n  }\n\n  function findAlignedLines(dv, other) {\n    var linesToAlign = [];\n    for (var i = 0; i < dv.chunks.length; i++) {\n      var chunk = dv.chunks[i];\n      linesToAlign.push([chunk.origTo, chunk.editTo, other ? getMatchingOrigLine(chunk.editTo, other.chunks) : null]);\n    }\n    if (other) {\n      for (var i = 0; i < other.chunks.length; i++) {\n        var chunk = other.chunks[i];\n        for (var j = 0; j < linesToAlign.length; j++) {\n          var align = linesToAlign[j];\n          if (align[1] == chunk.editTo) {\n            j = -1;\n            break;\n          } else if (align[1] > chunk.editTo) {\n            break;\n          }\n        }\n        if (j > -1)\n          linesToAlign.splice(j - 1, 0, [getMatchingOrigLine(chunk.editTo, dv.chunks), chunk.editTo, chunk.origTo]);\n      }\n    }\n    return linesToAlign;\n  }\n\n  function alignChunks(dv, force) {\n    if (!dv.dealigned && !force) return;\n    if (!dv.orig.curOp) return dv.orig.operation(function() {\n      alignChunks(dv, force);\n    });\n\n    dv.dealigned = false;\n    var other = dv.mv.left == dv ? dv.mv.right : dv.mv.left;\n    if (other) {\n      ensureDiff(other);\n      other.dealigned = false;\n    }\n    var linesToAlign = findAlignedLines(dv, other);\n\n    // Clear old aligners\n    var aligners = dv.mv.aligners;\n    for (var i = 0; i < aligners.length; i++)\n      aligners[i].clear();\n    aligners.length = 0;\n\n    var cm = [dv.orig, dv.edit], scroll = [];\n    if (other) cm.push(other.orig);\n    for (var i = 0; i < cm.length; i++)\n      scroll.push(cm[i].getScrollInfo().top);\n\n    for (var ln = 0; ln < linesToAlign.length; ln++)\n      alignLines(cm, linesToAlign[ln], aligners);\n\n    for (var i = 0; i < cm.length; i++)\n      cm[i].scrollTo(null, scroll[i]);\n  }\n\n  function alignLines(cm, lines, aligners) {\n    var maxOffset = 0, offset = [];\n    for (var i = 0; i < cm.length; i++) if (lines[i] != null) {\n      var off = cm[i].heightAtLine(lines[i], \"local\");\n      offset[i] = off;\n      maxOffset = Math.max(maxOffset, off);\n    }\n    for (var i = 0; i < cm.length; i++) if (lines[i] != null) {\n      var diff = maxOffset - offset[i];\n      if (diff > 1)\n        aligners.push(padAbove(cm[i], lines[i], diff));\n    }\n  }\n\n  function padAbove(cm, line, size) {\n    var above = true;\n    if (line > cm.lastLine()) {\n      line--;\n      above = false;\n    }\n    var elt = document.createElement(\"div\");\n    elt.className = \"CodeMirror-merge-spacer\";\n    elt.style.height = size + \"px\"; elt.style.minWidth = \"1px\";\n    return cm.addLineWidget(line, elt, {height: size, above: above});\n  }\n\n  function drawConnectorsForChunk(dv, chunk, sTopOrig, sTopEdit, w) {\n    var flip = dv.type == \"left\";\n    var top = dv.orig.heightAtLine(chunk.origFrom, \"local\") - sTopOrig;\n    if (dv.svg) {\n      var topLpx = top;\n      var topRpx = dv.edit.heightAtLine(chunk.editFrom, \"local\") - sTopEdit;\n      if (flip) { var tmp = topLpx; topLpx = topRpx; topRpx = tmp; }\n      var botLpx = dv.orig.heightAtLine(chunk.origTo, \"local\") - sTopOrig;\n      var botRpx = dv.edit.heightAtLine(chunk.editTo, \"local\") - sTopEdit;\n      if (flip) { var tmp = botLpx; botLpx = botRpx; botRpx = tmp; }\n      var curveTop = \" C \" + w/2 + \" \" + topRpx + \" \" + w/2 + \" \" + topLpx + \" \" + (w + 2) + \" \" + topLpx;\n      var curveBot = \" C \" + w/2 + \" \" + botLpx + \" \" + w/2 + \" \" + botRpx + \" -1 \" + botRpx;\n      attrs(dv.svg.appendChild(document.createElementNS(svgNS, \"path\")),\n            \"d\", \"M -1 \" + topRpx + curveTop + \" L \" + (w + 2) + \" \" + botLpx + curveBot + \" z\",\n            \"class\", dv.classes.connect);\n    }\n    if (dv.copyButtons) {\n      var copy = dv.copyButtons.appendChild(elt(\"div\", dv.type == \"left\" ? \"\\u21dd\" : \"\\u21dc\",\n                                                \"CodeMirror-merge-copy\"));\n      var editOriginals = dv.mv.options.allowEditingOriginals;\n      copy.title = editOriginals ? \"Push to left\" : \"Revert chunk\";\n      copy.chunk = chunk;\n      copy.style.top = top + \"px\";\n\n      if (editOriginals) {\n        var topReverse = dv.orig.heightAtLine(chunk.editFrom, \"local\") - sTopEdit;\n        var copyReverse = dv.copyButtons.appendChild(elt(\"div\", dv.type == \"right\" ? \"\\u21dd\" : \"\\u21dc\",\n                                                         \"CodeMirror-merge-copy-reverse\"));\n        copyReverse.title = \"Push to right\";\n        copyReverse.chunk = {editFrom: chunk.origFrom, editTo: chunk.origTo,\n                             origFrom: chunk.editFrom, origTo: chunk.editTo};\n        copyReverse.style.top = topReverse + \"px\";\n        dv.type == \"right\" ? copyReverse.style.left = \"2px\" : copyReverse.style.right = \"2px\";\n      }\n    }\n  }\n\n  function copyChunk(dv, to, from, chunk) {\n    if (dv.diffOutOfDate) return;\n    to.replaceRange(from.getRange(Pos(chunk.origFrom, 0), Pos(chunk.origTo, 0)),\n                         Pos(chunk.editFrom, 0), Pos(chunk.editTo, 0));\n  }\n\n  // Merge view, containing 0, 1, or 2 diff views.\n\n  var MergeView = CodeMirror.MergeView = function(node, options) {\n    if (!(this instanceof MergeView)) return new MergeView(node, options);\n\n    this.options = options;\n    var origLeft = options.origLeft, origRight = options.origRight == null ? options.orig : options.origRight;\n\n    var hasLeft = origLeft != null, hasRight = origRight != null;\n    var panes = 1 + (hasLeft ? 1 : 0) + (hasRight ? 1 : 0);\n    var wrap = [], left = this.left = null, right = this.right = null;\n    var self = this;\n\n    if (hasLeft) {\n      left = this.left = new DiffView(this, \"left\");\n      var leftPane = elt(\"div\", null, \"CodeMirror-merge-pane\");\n      wrap.push(leftPane);\n      wrap.push(buildGap(left));\n    }\n\n    var editPane = elt(\"div\", null, \"CodeMirror-merge-pane\");\n    wrap.push(editPane);\n\n    if (hasRight) {\n      right = this.right = new DiffView(this, \"right\");\n      wrap.push(buildGap(right));\n      var rightPane = elt(\"div\", null, \"CodeMirror-merge-pane\");\n      wrap.push(rightPane);\n    }\n\n    (hasRight ? rightPane : editPane).className += \" CodeMirror-merge-pane-rightmost\";\n\n    wrap.push(elt(\"div\", null, null, \"height: 0; clear: both;\"));\n\n    var wrapElt = this.wrap = node.appendChild(elt(\"div\", wrap, \"CodeMirror-merge CodeMirror-merge-\" + panes + \"pane\"));\n    this.edit = CodeMirror(editPane, copyObj(options));\n\n    if (left) left.init(leftPane, origLeft, options);\n    if (right) right.init(rightPane, origRight, options);\n\n    if (options.collapseIdentical) {\n      updating = true;\n      this.editor().operation(function() {\n        collapseIdenticalStretches(self, options.collapseIdentical);\n      });\n      updating = false;\n    }\n    if (options.connect == \"align\") {\n      this.aligners = [];\n      alignChunks(this.left || this.right, true);\n    }\n\n    var onResize = function() {\n      if (left) makeConnections(left);\n      if (right) makeConnections(right);\n    };\n    CodeMirror.on(window, \"resize\", onResize);\n    var resizeInterval = setInterval(function() {\n      for (var p = wrapElt.parentNode; p && p != document.body; p = p.parentNode) {}\n      if (!p) { clearInterval(resizeInterval); CodeMirror.off(window, \"resize\", onResize); }\n    }, 5000);\n  };\n\n  function buildGap(dv) {\n    var lock = dv.lockButton = elt(\"div\", null, \"CodeMirror-merge-scrolllock\");\n    lock.title = \"Toggle locked scrolling\";\n    var lockWrap = elt(\"div\", [lock], \"CodeMirror-merge-scrolllock-wrap\");\n    CodeMirror.on(lock, \"click\", function() { setScrollLock(dv, !dv.lockScroll); });\n    var gapElts = [lockWrap];\n    if (dv.mv.options.revertButtons !== false) {\n      dv.copyButtons = elt(\"div\", null, \"CodeMirror-merge-copybuttons-\" + dv.type);\n      CodeMirror.on(dv.copyButtons, \"click\", function(e) {\n        var node = e.target || e.srcElement;\n        if (!node.chunk) return;\n        if (node.className == \"CodeMirror-merge-copy-reverse\") {\n          copyChunk(dv, dv.orig, dv.edit, node.chunk);\n          return;\n        }\n        copyChunk(dv, dv.edit, dv.orig, node.chunk);\n      });\n      gapElts.unshift(dv.copyButtons);\n    }\n    if (dv.mv.options.connect != \"align\") {\n      var svg = document.createElementNS && document.createElementNS(svgNS, \"svg\");\n      if (svg && !svg.createSVGRect) svg = null;\n      dv.svg = svg;\n      if (svg) gapElts.push(svg);\n    }\n\n    return dv.gap = elt(\"div\", gapElts, \"CodeMirror-merge-gap\");\n  }\n\n  MergeView.prototype = {\n    constuctor: MergeView,\n    editor: function() { return this.edit; },\n    rightOriginal: function() { return this.right && this.right.orig; },\n    leftOriginal: function() { return this.left && this.left.orig; },\n    setShowDifferences: function(val) {\n      if (this.right) this.right.setShowDifferences(val);\n      if (this.left) this.left.setShowDifferences(val);\n    },\n    rightChunks: function() {\n      if (this.right) { ensureDiff(this.right); return this.right.chunks; }\n    },\n    leftChunks: function() {\n      if (this.left) { ensureDiff(this.left); return this.left.chunks; }\n    }\n  };\n\n  function asString(obj) {\n    if (typeof obj == \"string\") return obj;\n    else return obj.getValue();\n  }\n\n  // Operations on diffs\n\n  var dmp = new diff_match_patch();\n  function getDiff(a, b) {\n    var diff = dmp.diff_main(a, b);\n    dmp.diff_cleanupSemantic(diff);\n    // The library sometimes leaves in empty parts, which confuse the algorithm\n    for (var i = 0; i < diff.length; ++i) {\n      var part = diff[i];\n      if (!part[1]) {\n        diff.splice(i--, 1);\n      } else if (i && diff[i - 1][0] == part[0]) {\n        diff.splice(i--, 1);\n        diff[i][1] += part[1];\n      }\n    }\n    return diff;\n  }\n\n  function getChunks(diff) {\n    var chunks = [];\n    var startEdit = 0, startOrig = 0;\n    var edit = Pos(0, 0), orig = Pos(0, 0);\n    for (var i = 0; i < diff.length; ++i) {\n      var part = diff[i], tp = part[0];\n      if (tp == DIFF_EQUAL) {\n        var startOff = startOfLineClean(diff, i) ? 0 : 1;\n        var cleanFromEdit = edit.line + startOff, cleanFromOrig = orig.line + startOff;\n        moveOver(edit, part[1], null, orig);\n        var endOff = endOfLineClean(diff, i) ? 1 : 0;\n        var cleanToEdit = edit.line + endOff, cleanToOrig = orig.line + endOff;\n        if (cleanToEdit > cleanFromEdit) {\n          if (i) chunks.push({origFrom: startOrig, origTo: cleanFromOrig,\n                              editFrom: startEdit, editTo: cleanFromEdit});\n          startEdit = cleanToEdit; startOrig = cleanToOrig;\n        }\n      } else {\n        moveOver(tp == DIFF_INSERT ? edit : orig, part[1]);\n      }\n    }\n    if (startEdit <= edit.line || startOrig <= orig.line)\n      chunks.push({origFrom: startOrig, origTo: orig.line + 1,\n                   editFrom: startEdit, editTo: edit.line + 1});\n    return chunks;\n  }\n\n  function endOfLineClean(diff, i) {\n    if (i == diff.length - 1) return true;\n    var next = diff[i + 1][1];\n    if (next.length == 1 || next.charCodeAt(0) != 10) return false;\n    if (i == diff.length - 2) return true;\n    next = diff[i + 2][1];\n    return next.length > 1 && next.charCodeAt(0) == 10;\n  }\n\n  function startOfLineClean(diff, i) {\n    if (i == 0) return true;\n    var last = diff[i - 1][1];\n    if (last.charCodeAt(last.length - 1) != 10) return false;\n    if (i == 1) return true;\n    last = diff[i - 2][1];\n    return last.charCodeAt(last.length - 1) == 10;\n  }\n\n  function chunkBoundariesAround(chunks, n, nInEdit) {\n    var beforeE, afterE, beforeO, afterO;\n    for (var i = 0; i < chunks.length; i++) {\n      var chunk = chunks[i];\n      var fromLocal = nInEdit ? chunk.editFrom : chunk.origFrom;\n      var toLocal = nInEdit ? chunk.editTo : chunk.origTo;\n      if (afterE == null) {\n        if (fromLocal > n) { afterE = chunk.editFrom; afterO = chunk.origFrom; }\n        else if (toLocal > n) { afterE = chunk.editTo; afterO = chunk.origTo; }\n      }\n      if (toLocal <= n) { beforeE = chunk.editTo; beforeO = chunk.origTo; }\n      else if (fromLocal <= n) { beforeE = chunk.editFrom; beforeO = chunk.origFrom; }\n    }\n    return {edit: {before: beforeE, after: afterE}, orig: {before: beforeO, after: afterO}};\n  }\n\n  function collapseSingle(cm, from, to) {\n    cm.addLineClass(from, \"wrap\", \"CodeMirror-merge-collapsed-line\");\n    var widget = document.createElement(\"span\");\n    widget.className = \"CodeMirror-merge-collapsed-widget\";\n    widget.title = \"Identical text collapsed. Click to expand.\";\n    var mark = cm.markText(Pos(from, 0), Pos(to - 1), {\n      inclusiveLeft: true,\n      inclusiveRight: true,\n      replacedWith: widget,\n      clearOnEnter: true\n    });\n    function clear() {\n      mark.clear();\n      cm.removeLineClass(from, \"wrap\", \"CodeMirror-merge-collapsed-line\");\n    }\n    widget.addEventListener(\"click\", clear);\n    return {mark: mark, clear: clear};\n  }\n\n  function collapseStretch(size, editors) {\n    var marks = [];\n    function clear() {\n      for (var i = 0; i < marks.length; i++) marks[i].clear();\n    }\n    for (var i = 0; i < editors.length; i++) {\n      var editor = editors[i];\n      var mark = collapseSingle(editor.cm, editor.line, editor.line + size);\n      marks.push(mark);\n      mark.mark.on(\"clear\", clear);\n    }\n    return marks[0].mark;\n  }\n\n  function unclearNearChunks(dv, margin, off, clear) {\n    for (var i = 0; i < dv.chunks.length; i++) {\n      var chunk = dv.chunks[i];\n      for (var l = chunk.editFrom - margin; l < chunk.editTo + margin; l++) {\n        var pos = l + off;\n        if (pos >= 0 && pos < clear.length) clear[pos] = false;\n      }\n    }\n  }\n\n  function collapseIdenticalStretches(mv, margin) {\n    if (typeof margin != \"number\") margin = 2;\n    var clear = [], edit = mv.editor(), off = edit.firstLine();\n    for (var l = off, e = edit.lastLine(); l <= e; l++) clear.push(true);\n    if (mv.left) unclearNearChunks(mv.left, margin, off, clear);\n    if (mv.right) unclearNearChunks(mv.right, margin, off, clear);\n\n    for (var i = 0; i < clear.length; i++) {\n      if (clear[i]) {\n        var line = i + off;\n        for (var size = 1; i < clear.length - 1 && clear[i + 1]; i++, size++) {}\n        if (size > margin) {\n          var editors = [{line: line, cm: edit}];\n          if (mv.left) editors.push({line: getMatchingOrigLine(line, mv.left.chunks), cm: mv.left.orig});\n          if (mv.right) editors.push({line: getMatchingOrigLine(line, mv.right.chunks), cm: mv.right.orig});\n          var mark = collapseStretch(size, editors);\n          if (mv.options.onCollapse) mv.options.onCollapse(mv, line, size, mark);\n        }\n      }\n    }\n  }\n\n  // General utilities\n\n  function elt(tag, content, className, style) {\n    var e = document.createElement(tag);\n    if (className) e.className = className;\n    if (style) e.style.cssText = style;\n    if (typeof content == \"string\") e.appendChild(document.createTextNode(content));\n    else if (content) for (var i = 0; i < content.length; ++i) e.appendChild(content[i]);\n    return e;\n  }\n\n  function clear(node) {\n    for (var count = node.childNodes.length; count > 0; --count)\n      node.removeChild(node.firstChild);\n  }\n\n  function attrs(elt) {\n    for (var i = 1; i < arguments.length; i += 2)\n      elt.setAttribute(arguments[i], arguments[i+1]);\n  }\n\n  function copyObj(obj, target) {\n    if (!target) target = {};\n    for (var prop in obj) if (obj.hasOwnProperty(prop)) target[prop] = obj[prop];\n    return target;\n  }\n\n  function moveOver(pos, str, copy, other) {\n    var out = copy ? Pos(pos.line, pos.ch) : pos, at = 0;\n    for (;;) {\n      var nl = str.indexOf(\"\\n\", at);\n      if (nl == -1) break;\n      ++out.line;\n      if (other) ++other.line;\n      at = nl + 1;\n    }\n    out.ch = (at ? 0 : out.ch) + (str.length - at);\n    if (other) other.ch = (at ? 0 : other.ch) + (str.length - at);\n    return out;\n  }\n\n  function posMin(a, b) { return (a.line - b.line || a.ch - b.ch) < 0 ? a : b; }\n  function posMax(a, b) { return (a.line - b.line || a.ch - b.ch) > 0 ? a : b; }\n  function posEq(a, b) { return a.line == b.line && a.ch == b.ch; }\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/mode/loadmode.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"), \"cjs\");\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], function(CM) { mod(CM, \"amd\"); });\n  else // Plain browser env\n    mod(CodeMirror, \"plain\");\n})(function(CodeMirror, env) {\n  if (!CodeMirror.modeURL) CodeMirror.modeURL = \"../mode/%N/%N.js\";\n\n  var loading = {};\n  function splitCallback(cont, n) {\n    var countDown = n;\n    return function() { if (--countDown == 0) cont(); };\n  }\n  function ensureDeps(mode, cont) {\n    var deps = CodeMirror.modes[mode].dependencies;\n    if (!deps) return cont();\n    var missing = [];\n    for (var i = 0; i < deps.length; ++i) {\n      if (!CodeMirror.modes.hasOwnProperty(deps[i]))\n        missing.push(deps[i]);\n    }\n    if (!missing.length) return cont();\n    var split = splitCallback(cont, missing.length);\n    for (var i = 0; i < missing.length; ++i)\n      CodeMirror.requireMode(missing[i], split);\n  }\n\n  CodeMirror.requireMode = function(mode, cont) {\n    if (typeof mode != \"string\") mode = mode.name;\n    if (CodeMirror.modes.hasOwnProperty(mode)) return ensureDeps(mode, cont);\n    if (loading.hasOwnProperty(mode)) return loading[mode].push(cont);\n\n    var file = CodeMirror.modeURL.replace(/%N/g, mode);\n    if (env == \"plain\") {\n      var script = document.createElement(\"script\");\n      script.src = file;\n      var others = document.getElementsByTagName(\"script\")[0];\n      var list = loading[mode] = [cont];\n      CodeMirror.on(script, \"load\", function() {\n        ensureDeps(mode, function() {\n          for (var i = 0; i < list.length; ++i) list[i]();\n        });\n      });\n      others.parentNode.insertBefore(script, others);\n    } else if (env == \"cjs\") {\n      require(file);\n      cont();\n    } else if (env == \"amd\") {\n      requirejs([file], cont);\n    }\n  };\n\n  CodeMirror.autoLoadMode = function(instance, mode) {\n    if (!CodeMirror.modes.hasOwnProperty(mode))\n      CodeMirror.requireMode(mode, function() {\n        instance.setOption(\"mode\", instance.getOption(\"mode\"));\n      });\n  };\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/mode/multiplex.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.multiplexingMode = function(outer /*, others */) {\n  // Others should be {open, close, mode [, delimStyle] [, innerStyle]} objects\n  var others = Array.prototype.slice.call(arguments, 1);\n  var n_others = others.length;\n\n  function indexOf(string, pattern, from) {\n    if (typeof pattern == \"string\") return string.indexOf(pattern, from);\n    var m = pattern.exec(from ? string.slice(from) : string);\n    return m ? m.index + from : -1;\n  }\n\n  return {\n    startState: function() {\n      return {\n        outer: CodeMirror.startState(outer),\n        innerActive: null,\n        inner: null\n      };\n    },\n\n    copyState: function(state) {\n      return {\n        outer: CodeMirror.copyState(outer, state.outer),\n        innerActive: state.innerActive,\n        inner: state.innerActive && CodeMirror.copyState(state.innerActive.mode, state.inner)\n      };\n    },\n\n    token: function(stream, state) {\n      if (!state.innerActive) {\n        var cutOff = Infinity, oldContent = stream.string;\n        for (var i = 0; i < n_others; ++i) {\n          var other = others[i];\n          var found = indexOf(oldContent, other.open, stream.pos);\n          if (found == stream.pos) {\n            stream.match(other.open);\n            state.innerActive = other;\n            state.inner = CodeMirror.startState(other.mode, outer.indent ? outer.indent(state.outer, \"\") : 0);\n            return other.delimStyle;\n          } else if (found != -1 && found < cutOff) {\n            cutOff = found;\n          }\n        }\n        if (cutOff != Infinity) stream.string = oldContent.slice(0, cutOff);\n        var outerToken = outer.token(stream, state.outer);\n        if (cutOff != Infinity) stream.string = oldContent;\n        return outerToken;\n      } else {\n        var curInner = state.innerActive, oldContent = stream.string;\n        if (!curInner.close && stream.sol()) {\n          state.innerActive = state.inner = null;\n          return this.token(stream, state);\n        }\n        var found = curInner.close ? indexOf(oldContent, curInner.close, stream.pos) : -1;\n        if (found == stream.pos) {\n          stream.match(curInner.close);\n          state.innerActive = state.inner = null;\n          return curInner.delimStyle;\n        }\n        if (found > -1) stream.string = oldContent.slice(0, found);\n        var innerToken = curInner.mode.token(stream, state.inner);\n        if (found > -1) stream.string = oldContent;\n\n        if (curInner.innerStyle) {\n          if (innerToken) innerToken = innerToken + ' ' + curInner.innerStyle;\n          else innerToken = curInner.innerStyle;\n        }\n\n        return innerToken;\n      }\n    },\n\n    indent: function(state, textAfter) {\n      var mode = state.innerActive ? state.innerActive.mode : outer;\n      if (!mode.indent) return CodeMirror.Pass;\n      return mode.indent(state.innerActive ? state.inner : state.outer, textAfter);\n    },\n\n    blankLine: function(state) {\n      var mode = state.innerActive ? state.innerActive.mode : outer;\n      if (mode.blankLine) {\n        mode.blankLine(state.innerActive ? state.inner : state.outer);\n      }\n      if (!state.innerActive) {\n        for (var i = 0; i < n_others; ++i) {\n          var other = others[i];\n          if (other.open === \"\\n\") {\n            state.innerActive = other;\n            state.inner = CodeMirror.startState(other.mode, mode.indent ? mode.indent(state.outer, \"\") : 0);\n          }\n        }\n      } else if (state.innerActive.close === \"\\n\") {\n        state.innerActive = state.inner = null;\n      }\n    },\n\n    electricChars: outer.electricChars,\n\n    innerMode: function(state) {\n      return state.inner ? {state: state.inner, mode: state.innerActive.mode} : {state: state.outer, mode: outer};\n    }\n  };\n};\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/mode/multiplex_test.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function() {\n  CodeMirror.defineMode(\"markdown_with_stex\", function(){\n    var inner = CodeMirror.getMode({}, \"stex\");\n    var outer = CodeMirror.getMode({}, \"markdown\");\n\n    var innerOptions = {\n      open: '$',\n      close: '$',\n      mode: inner,\n      delimStyle: 'delim',\n      innerStyle: 'inner'\n    };\n\n    return CodeMirror.multiplexingMode(outer, innerOptions);\n  });\n\n  var mode = CodeMirror.getMode({}, \"markdown_with_stex\");\n\n  function MT(name) {\n    test.mode(\n      name,\n      mode,\n      Array.prototype.slice.call(arguments, 1),\n      'multiplexing');\n  }\n\n  MT(\n    \"stexInsideMarkdown\",\n    \"[strong **Equation:**] [delim $][inner&tag \\\\pi][delim $]\");\n})();\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/mode/overlay.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n// Utility function that allows modes to be combined. The mode given\n// as the base argument takes care of most of the normal mode\n// functionality, but a second (typically simple) mode is used, which\n// can override the style of text. Both modes get to parse all of the\n// text, but when both assign a non-null style to a piece of code, the\n// overlay wins, unless the combine argument was true and not overridden,\n// or state.overlay.combineTokens was true, in which case the styles are\n// combined.\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.overlayMode = function(base, overlay, combine) {\n  return {\n    startState: function() {\n      return {\n        base: CodeMirror.startState(base),\n        overlay: CodeMirror.startState(overlay),\n        basePos: 0, baseCur: null,\n        overlayPos: 0, overlayCur: null,\n        streamSeen: null\n      };\n    },\n    copyState: function(state) {\n      return {\n        base: CodeMirror.copyState(base, state.base),\n        overlay: CodeMirror.copyState(overlay, state.overlay),\n        basePos: state.basePos, baseCur: null,\n        overlayPos: state.overlayPos, overlayCur: null\n      };\n    },\n\n    token: function(stream, state) {\n      if (stream != state.streamSeen ||\n          Math.min(state.basePos, state.overlayPos) < stream.start) {\n        state.streamSeen = stream;\n        state.basePos = state.overlayPos = stream.start;\n      }\n\n      if (stream.start == state.basePos) {\n        state.baseCur = base.token(stream, state.base);\n        state.basePos = stream.pos;\n      }\n      if (stream.start == state.overlayPos) {\n        stream.pos = stream.start;\n        state.overlayCur = overlay.token(stream, state.overlay);\n        state.overlayPos = stream.pos;\n      }\n      stream.pos = Math.min(state.basePos, state.overlayPos);\n\n      // state.overlay.combineTokens always takes precedence over combine,\n      // unless set to null\n      if (state.overlayCur == null) return state.baseCur;\n      else if (state.baseCur != null &&\n               state.overlay.combineTokens ||\n               combine && state.overlay.combineTokens == null)\n        return state.baseCur + \" \" + state.overlayCur;\n      else return state.overlayCur;\n    },\n\n    indent: base.indent && function(state, textAfter) {\n      return base.indent(state.base, textAfter);\n    },\n    electricChars: base.electricChars,\n\n    innerMode: function(state) { return {state: state.base, mode: base}; },\n\n    blankLine: function(state) {\n      if (base.blankLine) base.blankLine(state.base);\n      if (overlay.blankLine) overlay.blankLine(state.overlay);\n    }\n  };\n};\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/mode/simple.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n\n  CodeMirror.defineSimpleMode = function(name, states) {\n    CodeMirror.defineMode(name, function(config) {\n      return CodeMirror.simpleMode(config, states);\n    });\n  };\n\n  CodeMirror.simpleMode = function(config, states) {\n    ensureState(states, \"start\");\n    var states_ = {}, meta = states.meta || {}, hasIndentation = false;\n    for (var state in states) if (state != meta && states.hasOwnProperty(state)) {\n      var list = states_[state] = [], orig = states[state];\n      for (var i = 0; i < orig.length; i++) {\n        var data = orig[i];\n        list.push(new Rule(data, states));\n        if (data.indent || data.dedent) hasIndentation = true;\n      }\n    }\n    var mode = {\n      startState: function() {\n        return {state: \"start\", pending: null,\n                local: null, localState: null,\n                indent: hasIndentation ? [] : null};\n      },\n      copyState: function(state) {\n        var s = {state: state.state, pending: state.pending,\n                 local: state.local, localState: null,\n                 indent: state.indent && state.indent.slice(0)};\n        if (state.localState)\n          s.localState = CodeMirror.copyState(state.local.mode, state.localState);\n        if (state.stack)\n          s.stack = state.stack.slice(0);\n        for (var pers = state.persistentStates; pers; pers = pers.next)\n          s.persistentStates = {mode: pers.mode,\n                                spec: pers.spec,\n                                state: pers.state == state.localState ? s.localState : CodeMirror.copyState(pers.mode, pers.state),\n                                next: s.persistentStates};\n        return s;\n      },\n      token: tokenFunction(states_, config),\n      innerMode: function(state) { return state.local && {mode: state.local.mode, state: state.localState}; },\n      indent: indentFunction(states_, meta)\n    };\n    if (meta) for (var prop in meta) if (meta.hasOwnProperty(prop))\n      mode[prop] = meta[prop];\n    return mode;\n  };\n\n  function ensureState(states, name) {\n    if (!states.hasOwnProperty(name))\n      throw new Error(\"Undefined state \" + name + \"in simple mode\");\n  }\n\n  function toRegex(val, caret) {\n    if (!val) return /(?:)/;\n    var flags = \"\";\n    if (val instanceof RegExp) {\n      if (val.ignoreCase) flags = \"i\";\n      val = val.source;\n    } else {\n      val = String(val);\n    }\n    return new RegExp((caret === false ? \"\" : \"^\") + \"(?:\" + val + \")\", flags);\n  }\n\n  function asToken(val) {\n    if (!val) return null;\n    if (typeof val == \"string\") return val.replace(/\\./g, \" \");\n    var result = [];\n    for (var i = 0; i < val.length; i++)\n      result.push(val[i] && val[i].replace(/\\./g, \" \"));\n    return result;\n  }\n\n  function Rule(data, states) {\n    if (data.next || data.push) ensureState(states, data.next || data.push);\n    this.regex = toRegex(data.regex);\n    this.token = asToken(data.token);\n    this.data = data;\n  }\n\n  function tokenFunction(states, config) {\n    return function(stream, state) {\n      if (state.pending) {\n        var pend = state.pending.shift();\n        if (state.pending.length == 0) state.pending = null;\n        stream.pos += pend.text.length;\n        return pend.token;\n      }\n\n      if (state.local) {\n        if (state.local.end && stream.match(state.local.end)) {\n          var tok = state.local.endToken || null;\n          state.local = state.localState = null;\n          return tok;\n        } else {\n          var tok = state.local.mode.token(stream, state.localState), m;\n          if (state.local.endScan && (m = state.local.endScan.exec(stream.current())))\n            stream.pos = stream.start + m.index;\n          return tok;\n        }\n      }\n\n      var curState = states[state.state];\n      for (var i = 0; i < curState.length; i++) {\n        var rule = curState[i];\n        var matches = (!rule.data.sol || stream.sol()) && stream.match(rule.regex);\n        if (matches) {\n          if (rule.data.next) {\n            state.state = rule.data.next;\n          } else if (rule.data.push) {\n            (state.stack || (state.stack = [])).push(state.state);\n            state.state = rule.data.push;\n          } else if (rule.data.pop && state.stack && state.stack.length) {\n            state.state = state.stack.pop();\n          }\n\n          if (rule.data.mode)\n            enterLocalMode(config, state, rule.data.mode, rule.token);\n          if (rule.data.indent)\n            state.indent.push(stream.indentation() + config.indentUnit);\n          if (rule.data.dedent)\n            state.indent.pop();\n          if (matches.length > 2) {\n            state.pending = [];\n            for (var j = 2; j < matches.length; j++)\n              if (matches[j])\n                state.pending.push({text: matches[j], token: rule.token[j - 1]});\n            stream.backUp(matches[0].length - (matches[1] ? matches[1].length : 0));\n            return rule.token[0];\n          } else if (rule.token && rule.token.join) {\n            return rule.token[0];\n          } else {\n            return rule.token;\n          }\n        }\n      }\n      stream.next();\n      return null;\n    };\n  }\n\n  function cmp(a, b) {\n    if (a === b) return true;\n    if (!a || typeof a != \"object\" || !b || typeof b != \"object\") return false;\n    var props = 0;\n    for (var prop in a) if (a.hasOwnProperty(prop)) {\n      if (!b.hasOwnProperty(prop) || !cmp(a[prop], b[prop])) return false;\n      props++;\n    }\n    for (var prop in b) if (b.hasOwnProperty(prop)) props--;\n    return props == 0;\n  }\n\n  function enterLocalMode(config, state, spec, token) {\n    var pers;\n    if (spec.persistent) for (var p = state.persistentStates; p && !pers; p = p.next)\n      if (spec.spec ? cmp(spec.spec, p.spec) : spec.mode == p.mode) pers = p;\n    var mode = pers ? pers.mode : spec.mode || CodeMirror.getMode(config, spec.spec);\n    var lState = pers ? pers.state : CodeMirror.startState(mode);\n    if (spec.persistent && !pers)\n      state.persistentStates = {mode: mode, spec: spec.spec, state: lState, next: state.persistentStates};\n\n    state.localState = lState;\n    state.local = {mode: mode,\n                   end: spec.end && toRegex(spec.end),\n                   endScan: spec.end && spec.forceEnd !== false && toRegex(spec.end, false),\n                   endToken: token && token.join ? token[token.length - 1] : token};\n  }\n\n  function indexOf(val, arr) {\n    for (var i = 0; i < arr.length; i++) if (arr[i] === val) return true;\n  }\n\n  function indentFunction(states, meta) {\n    return function(state, textAfter, line) {\n      if (state.local && state.local.mode.indent)\n        return state.local.mode.indent(state.localState, textAfter, line);\n      if (state.indent == null || state.local || meta.dontIndentStates && indexOf(state.state, meta.dontIndentStates) > -1)\n        return CodeMirror.Pass;\n\n      var pos = state.indent.length - 1, rules = states[state.state];\n      scan: for (;;) {\n        for (var i = 0; i < rules.length; i++) {\n          var rule = rules[i];\n          if (rule.data.dedent && rule.data.dedentIfLineStart !== false) {\n            var m = rule.regex.exec(textAfter);\n            if (m && m[0]) {\n              pos--;\n              if (rule.next || rule.push) rules = states[rule.next || rule.push];\n              textAfter = textAfter.slice(m[0].length);\n              continue scan;\n            }\n          }\n        }\n        break;\n      }\n      return pos < 0 ? 0 : state.indent[pos];\n    };\n  }\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/runmode/colorize.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"), require(\"./runmode\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\", \"./runmode\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n\n  var isBlock = /^(p|li|div|h\\\\d|pre|blockquote|td)$/;\n\n  function textContent(node, out) {\n    if (node.nodeType == 3) return out.push(node.nodeValue);\n    for (var ch = node.firstChild; ch; ch = ch.nextSibling) {\n      textContent(ch, out);\n      if (isBlock.test(node.nodeType)) out.push(\"\\n\");\n    }\n  }\n\n  CodeMirror.colorize = function(collection, defaultMode) {\n    if (!collection) collection = document.body.getElementsByTagName(\"pre\");\n\n    for (var i = 0; i < collection.length; ++i) {\n      var node = collection[i];\n      var mode = node.getAttribute(\"data-lang\") || defaultMode;\n      if (!mode) continue;\n\n      var text = [];\n      textContent(node, text);\n      node.innerHTML = \"\";\n      CodeMirror.runMode(text.join(\"\"), mode, node);\n\n      node.className += \" cm-s-default\";\n    }\n  };\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/runmode/runmode-standalone.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\nwindow.CodeMirror = {};\n\n(function() {\n\"use strict\";\n\nfunction splitLines(string){ return string.split(/\\r?\\n|\\r/); };\n\nfunction StringStream(string) {\n  this.pos = this.start = 0;\n  this.string = string;\n  this.lineStart = 0;\n}\nStringStream.prototype = {\n  eol: function() {return this.pos >= this.string.length;},\n  sol: function() {return this.pos == 0;},\n  peek: function() {return this.string.charAt(this.pos) || null;},\n  next: function() {\n    if (this.pos < this.string.length)\n      return this.string.charAt(this.pos++);\n  },\n  eat: function(match) {\n    var ch = this.string.charAt(this.pos);\n    if (typeof match == \"string\") var ok = ch == match;\n    else var ok = ch && (match.test ? match.test(ch) : match(ch));\n    if (ok) {++this.pos; return ch;}\n  },\n  eatWhile: function(match) {\n    var start = this.pos;\n    while (this.eat(match)){}\n    return this.pos > start;\n  },\n  eatSpace: function() {\n    var start = this.pos;\n    while (/[\\s\\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos;\n    return this.pos > start;\n  },\n  skipToEnd: function() {this.pos = this.string.length;},\n  skipTo: function(ch) {\n    var found = this.string.indexOf(ch, this.pos);\n    if (found > -1) {this.pos = found; return true;}\n  },\n  backUp: function(n) {this.pos -= n;},\n  column: function() {return this.start - this.lineStart;},\n  indentation: function() {return 0;},\n  match: function(pattern, consume, caseInsensitive) {\n    if (typeof pattern == \"string\") {\n      var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;};\n      var substr = this.string.substr(this.pos, pattern.length);\n      if (cased(substr) == cased(pattern)) {\n        if (consume !== false) this.pos += pattern.length;\n        return true;\n      }\n    } else {\n      var match = this.string.slice(this.pos).match(pattern);\n      if (match && match.index > 0) return null;\n      if (match && consume !== false) this.pos += match[0].length;\n      return match;\n    }\n  },\n  current: function(){return this.string.slice(this.start, this.pos);},\n  hideFirstChars: function(n, inner) {\n    this.lineStart += n;\n    try { return inner(); }\n    finally { this.lineStart -= n; }\n  }\n};\nCodeMirror.StringStream = StringStream;\n\nCodeMirror.startState = function (mode, a1, a2) {\n  return mode.startState ? mode.startState(a1, a2) : true;\n};\n\nvar modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {};\nCodeMirror.defineMode = function (name, mode) {\n  if (arguments.length > 2)\n    mode.dependencies = Array.prototype.slice.call(arguments, 2);\n  modes[name] = mode;\n};\nCodeMirror.defineMIME = function (mime, spec) { mimeModes[mime] = spec; };\nCodeMirror.resolveMode = function(spec) {\n  if (typeof spec == \"string\" && mimeModes.hasOwnProperty(spec)) {\n    spec = mimeModes[spec];\n  } else if (spec && typeof spec.name == \"string\" && mimeModes.hasOwnProperty(spec.name)) {\n    spec = mimeModes[spec.name];\n  }\n  if (typeof spec == \"string\") return {name: spec};\n  else return spec || {name: \"null\"};\n};\nCodeMirror.getMode = function (options, spec) {\n  spec = CodeMirror.resolveMode(spec);\n  var mfactory = modes[spec.name];\n  if (!mfactory) throw new Error(\"Unknown mode: \" + spec);\n  return mfactory(options, spec);\n};\nCodeMirror.registerHelper = CodeMirror.registerGlobalHelper = Math.min;\nCodeMirror.defineMode(\"null\", function() {\n  return {token: function(stream) {stream.skipToEnd();}};\n});\nCodeMirror.defineMIME(\"text/plain\", \"null\");\n\nCodeMirror.runMode = function (string, modespec, callback, options) {\n  var mode = CodeMirror.getMode({ indentUnit: 2 }, modespec);\n\n  if (callback.nodeType == 1) {\n    var tabSize = (options && options.tabSize) || 4;\n    var node = callback, col = 0;\n    node.innerHTML = \"\";\n    callback = function (text, style) {\n      if (text == \"\\n\") {\n        node.appendChild(document.createElement(\"br\"));\n        col = 0;\n        return;\n      }\n      var content = \"\";\n      // replace tabs\n      for (var pos = 0; ;) {\n        var idx = text.indexOf(\"\\t\", pos);\n        if (idx == -1) {\n          content += text.slice(pos);\n          col += text.length - pos;\n          break;\n        } else {\n          col += idx - pos;\n          content += text.slice(pos, idx);\n          var size = tabSize - col % tabSize;\n          col += size;\n          for (var i = 0; i < size; ++i) content += \" \";\n          pos = idx + 1;\n        }\n      }\n\n      if (style) {\n        var sp = node.appendChild(document.createElement(\"span\"));\n        sp.className = \"cm-\" + style.replace(/ +/g, \" cm-\");\n        sp.appendChild(document.createTextNode(content));\n      } else {\n        node.appendChild(document.createTextNode(content));\n      }\n    };\n  }\n\n  var lines = splitLines(string), state = (options && options.state) || CodeMirror.startState(mode);\n  for (var i = 0, e = lines.length; i < e; ++i) {\n    if (i) callback(\"\\n\");\n    var stream = new CodeMirror.StringStream(lines[i]);\n    if (!stream.string && mode.blankLine) mode.blankLine(state);\n    while (!stream.eol()) {\n      var style = mode.token(stream, state);\n      callback(stream.current(), style, i, stream.start, state);\n      stream.start = stream.pos;\n    }\n  }\n};\n})();\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/runmode/runmode.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.runMode = function(string, modespec, callback, options) {\n  var mode = CodeMirror.getMode(CodeMirror.defaults, modespec);\n  var ie = /MSIE \\d/.test(navigator.userAgent);\n  var ie_lt9 = ie && (document.documentMode == null || document.documentMode < 9);\n\n  if (callback.nodeType == 1) {\n    var tabSize = (options && options.tabSize) || CodeMirror.defaults.tabSize;\n    var node = callback, col = 0;\n    node.innerHTML = \"\";\n    callback = function(text, style) {\n      if (text == \"\\n\") {\n        // Emitting LF or CRLF on IE8 or earlier results in an incorrect display.\n        // Emitting a carriage return makes everything ok.\n        node.appendChild(document.createTextNode(ie_lt9 ? '\\r' : text));\n        col = 0;\n        return;\n      }\n      var content = \"\";\n      // replace tabs\n      for (var pos = 0;;) {\n        var idx = text.indexOf(\"\\t\", pos);\n        if (idx == -1) {\n          content += text.slice(pos);\n          col += text.length - pos;\n          break;\n        } else {\n          col += idx - pos;\n          content += text.slice(pos, idx);\n          var size = tabSize - col % tabSize;\n          col += size;\n          for (var i = 0; i < size; ++i) content += \" \";\n          pos = idx + 1;\n        }\n      }\n\n      if (style) {\n        var sp = node.appendChild(document.createElement(\"span\"));\n        sp.className = \"cm-\" + style.replace(/ +/g, \" cm-\");\n        sp.appendChild(document.createTextNode(content));\n      } else {\n        node.appendChild(document.createTextNode(content));\n      }\n    };\n  }\n\n  var lines = CodeMirror.splitLines(string), state = (options && options.state) || CodeMirror.startState(mode);\n  for (var i = 0, e = lines.length; i < e; ++i) {\n    if (i) callback(\"\\n\");\n    var stream = new CodeMirror.StringStream(lines[i]);\n    if (!stream.string && mode.blankLine) mode.blankLine(state);\n    while (!stream.eol()) {\n      var style = mode.token(stream, state);\n      callback(stream.current(), style, i, stream.start, state);\n      stream.start = stream.pos;\n    }\n  }\n};\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/runmode/runmode.node.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n/* Just enough of CodeMirror to run runMode under node.js */\n\n// declare global: StringStream\n\nfunction splitLines(string){ return string.split(/\\r?\\n|\\r/); };\n\nfunction StringStream(string) {\n  this.pos = this.start = 0;\n  this.string = string;\n  this.lineStart = 0;\n}\nStringStream.prototype = {\n  eol: function() {return this.pos >= this.string.length;},\n  sol: function() {return this.pos == 0;},\n  peek: function() {return this.string.charAt(this.pos) || null;},\n  next: function() {\n    if (this.pos < this.string.length)\n      return this.string.charAt(this.pos++);\n  },\n  eat: function(match) {\n    var ch = this.string.charAt(this.pos);\n    if (typeof match == \"string\") var ok = ch == match;\n    else var ok = ch && (match.test ? match.test(ch) : match(ch));\n    if (ok) {++this.pos; return ch;}\n  },\n  eatWhile: function(match) {\n    var start = this.pos;\n    while (this.eat(match)){}\n    return this.pos > start;\n  },\n  eatSpace: function() {\n    var start = this.pos;\n    while (/[\\s\\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos;\n    return this.pos > start;\n  },\n  skipToEnd: function() {this.pos = this.string.length;},\n  skipTo: function(ch) {\n    var found = this.string.indexOf(ch, this.pos);\n    if (found > -1) {this.pos = found; return true;}\n  },\n  backUp: function(n) {this.pos -= n;},\n  column: function() {return this.start - this.lineStart;},\n  indentation: function() {return 0;},\n  match: function(pattern, consume, caseInsensitive) {\n    if (typeof pattern == \"string\") {\n      var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;};\n      var substr = this.string.substr(this.pos, pattern.length);\n      if (cased(substr) == cased(pattern)) {\n        if (consume !== false) this.pos += pattern.length;\n        return true;\n      }\n    } else {\n      var match = this.string.slice(this.pos).match(pattern);\n      if (match && match.index > 0) return null;\n      if (match && consume !== false) this.pos += match[0].length;\n      return match;\n    }\n  },\n  current: function(){return this.string.slice(this.start, this.pos);},\n  hideFirstChars: function(n, inner) {\n    this.lineStart += n;\n    try { return inner(); }\n    finally { this.lineStart -= n; }\n  }\n};\nexports.StringStream = StringStream;\n\nexports.startState = function(mode, a1, a2) {\n  return mode.startState ? mode.startState(a1, a2) : true;\n};\n\nvar modes = exports.modes = {}, mimeModes = exports.mimeModes = {};\nexports.defineMode = function(name, mode) {\n  if (arguments.length > 2)\n    mode.dependencies = Array.prototype.slice.call(arguments, 2);\n  modes[name] = mode;\n};\nexports.defineMIME = function(mime, spec) { mimeModes[mime] = spec; };\n\nexports.defineMode(\"null\", function() {\n  return {token: function(stream) {stream.skipToEnd();}};\n});\nexports.defineMIME(\"text/plain\", \"null\");\n\nexports.resolveMode = function(spec) {\n  if (typeof spec == \"string\" && mimeModes.hasOwnProperty(spec)) {\n    spec = mimeModes[spec];\n  } else if (spec && typeof spec.name == \"string\" && mimeModes.hasOwnProperty(spec.name)) {\n    spec = mimeModes[spec.name];\n  }\n  if (typeof spec == \"string\") return {name: spec};\n  else return spec || {name: \"null\"};\n};\nexports.getMode = function(options, spec) {\n  spec = exports.resolveMode(spec);\n  var mfactory = modes[spec.name];\n  if (!mfactory) throw new Error(\"Unknown mode: \" + spec);\n  return mfactory(options, spec);\n};\nexports.registerHelper = exports.registerGlobalHelper = Math.min;\n\nexports.runMode = function(string, modespec, callback, options) {\n  var mode = exports.getMode({indentUnit: 2}, modespec);\n  var lines = splitLines(string), state = (options && options.state) || exports.startState(mode);\n  for (var i = 0, e = lines.length; i < e; ++i) {\n    if (i) callback(\"\\n\");\n    var stream = new exports.StringStream(lines[i]);\n    if (!stream.string && mode.blankLine) mode.blankLine(state);\n    while (!stream.eol()) {\n      var style = mode.token(stream, state);\n      callback(stream.current(), style, i, stream.start, state);\n      stream.start = stream.pos;\n    }\n  }\n};\n\nrequire.cache[require.resolve(\"../../lib/codemirror\")] = require.cache[require.resolve(\"./runmode.node\")];\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/scroll/annotatescrollbar.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n\n  CodeMirror.defineExtension(\"annotateScrollbar\", function(options) {\n    if (typeof options == \"string\") options = {className: options};\n    return new Annotation(this, options);\n  });\n\n  CodeMirror.defineOption(\"scrollButtonHeight\", 0);\n\n  function Annotation(cm, options) {\n    this.cm = cm;\n    this.options = options;\n    this.buttonHeight = options.scrollButtonHeight || cm.getOption(\"scrollButtonHeight\");\n    this.annotations = [];\n    this.doRedraw = this.doUpdate = null;\n    this.div = cm.getWrapperElement().appendChild(document.createElement(\"div\"));\n    this.div.style.cssText = \"position: absolute; right: 0; top: 0; z-index: 7; pointer-events: none\";\n    this.computeScale();\n\n    function scheduleRedraw(delay) {\n      clearTimeout(self.doRedraw);\n      self.doRedraw = setTimeout(function() { self.redraw(); }, delay);\n    }\n\n    var self = this;\n    cm.on(\"refresh\", this.resizeHandler = function() {\n      clearTimeout(self.doUpdate);\n      self.doUpdate = setTimeout(function() {\n        if (self.computeScale()) scheduleRedraw(20);\n      }, 100);\n    });\n    cm.on(\"markerAdded\", this.resizeHandler);\n    cm.on(\"markerCleared\", this.resizeHandler);\n    if (options.listenForChanges !== false)\n      cm.on(\"change\", this.changeHandler = function() {\n        scheduleRedraw(250);\n      });\n  }\n\n  Annotation.prototype.computeScale = function() {\n    var cm = this.cm;\n    var hScale = (cm.getWrapperElement().clientHeight - cm.display.barHeight - this.buttonHeight * 2) /\n      cm.heightAtLine(cm.lastLine() + 1, \"local\");\n    if (hScale != this.hScale) {\n      this.hScale = hScale;\n      return true;\n    }\n  };\n\n  Annotation.prototype.update = function(annotations) {\n    this.annotations = annotations;\n    this.redraw();\n  };\n\n  Annotation.prototype.redraw = function(compute) {\n    if (compute !== false) this.computeScale();\n    var cm = this.cm, hScale = this.hScale;\n\n    var frag = document.createDocumentFragment(), anns = this.annotations;\n    if (cm.display.barWidth) for (var i = 0, nextTop; i < anns.length; i++) {\n      var ann = anns[i];\n      var top = nextTop || cm.charCoords(ann.from, \"local\").top * hScale;\n      var bottom = cm.charCoords(ann.to, \"local\").bottom * hScale;\n      while (i < anns.length - 1) {\n        nextTop = cm.charCoords(anns[i + 1].from, \"local\").top * hScale;\n        if (nextTop > bottom + .9) break;\n        ann = anns[++i];\n        bottom = cm.charCoords(ann.to, \"local\").bottom * hScale;\n      }\n      if (bottom == top) continue;\n      var height = Math.max(bottom - top, 3);\n\n      var elt = frag.appendChild(document.createElement(\"div\"));\n      elt.style.cssText = \"position: absolute; right: 0px; width: \" + Math.max(cm.display.barWidth - 1, 2) + \"px; top: \"\n        + (top + this.buttonHeight) + \"px; height: \" + height + \"px\";\n      elt.className = this.options.className;\n    }\n    this.div.textContent = \"\";\n    this.div.appendChild(frag);\n  };\n\n  Annotation.prototype.clear = function() {\n    this.cm.off(\"refresh\", this.resizeHandler);\n    this.cm.off(\"markerAdded\", this.resizeHandler);\n    this.cm.off(\"markerCleared\", this.resizeHandler);\n    if (this.changeHandler) this.cm.off(\"change\", this.changeHandler);\n    this.div.parentNode.removeChild(this.div);\n  };\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/scroll/scrollpastend.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n\n  CodeMirror.defineOption(\"scrollPastEnd\", false, function(cm, val, old) {\n    if (old && old != CodeMirror.Init) {\n      cm.off(\"change\", onChange);\n      cm.off(\"refresh\", updateBottomMargin);\n      cm.display.lineSpace.parentNode.style.paddingBottom = \"\";\n      cm.state.scrollPastEndPadding = null;\n    }\n    if (val) {\n      cm.on(\"change\", onChange);\n      cm.on(\"refresh\", updateBottomMargin);\n      updateBottomMargin(cm);\n    }\n  });\n\n  function onChange(cm, change) {\n    if (CodeMirror.changeEnd(change).line == cm.lastLine())\n      updateBottomMargin(cm);\n  }\n\n  function updateBottomMargin(cm) {\n    var padding = \"\";\n    if (cm.lineCount() > 1) {\n      var totalH = cm.display.scroller.clientHeight - 30,\n          lastLineH = cm.getLineHandle(cm.lastLine()).height;\n      padding = (totalH - lastLineH) + \"px\";\n    }\n    if (cm.state.scrollPastEndPadding != padding) {\n      cm.state.scrollPastEndPadding = padding;\n      cm.display.lineSpace.parentNode.style.paddingBottom = padding;\n      cm.setSize();\n    }\n  }\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/scroll/simplescrollbars.css",
    "content": ".CodeMirror-simplescroll-horizontal div, .CodeMirror-simplescroll-vertical div {\n  position: absolute;\n  background: #ccc;\n  -moz-box-sizing: border-box;\n  box-sizing: border-box;\n  border: 1px solid #bbb;\n  border-radius: 2px;\n}\n\n.CodeMirror-simplescroll-horizontal, .CodeMirror-simplescroll-vertical {\n  position: absolute;\n  z-index: 6;\n  background: #eee;\n}\n\n.CodeMirror-simplescroll-horizontal {\n  bottom: 0; left: 0;\n  height: 8px;\n}\n.CodeMirror-simplescroll-horizontal div {\n  bottom: 0;\n  height: 100%;\n}\n\n.CodeMirror-simplescroll-vertical {\n  right: 0; top: 0;\n  width: 8px;\n}\n.CodeMirror-simplescroll-vertical div {\n  right: 0;\n  width: 100%;\n}\n\n\n.CodeMirror-overlayscroll .CodeMirror-scrollbar-filler, .CodeMirror-overlayscroll .CodeMirror-gutter-filler {\n  display: none;\n}\n\n.CodeMirror-overlayscroll-horizontal div, .CodeMirror-overlayscroll-vertical div {\n  position: absolute;\n  background: #bcd;\n  border-radius: 3px;\n}\n\n.CodeMirror-overlayscroll-horizontal, .CodeMirror-overlayscroll-vertical {\n  position: absolute;\n  z-index: 6;\n}\n\n.CodeMirror-overlayscroll-horizontal {\n  bottom: 0; left: 0;\n  height: 6px;\n}\n.CodeMirror-overlayscroll-horizontal div {\n  bottom: 0;\n  height: 100%;\n}\n\n.CodeMirror-overlayscroll-vertical {\n  right: 0; top: 0;\n  width: 6px;\n}\n.CodeMirror-overlayscroll-vertical div {\n  right: 0;\n  width: 100%;\n}\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/scroll/simplescrollbars.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n\n  function Bar(cls, orientation, scroll) {\n    this.orientation = orientation;\n    this.scroll = scroll;\n    this.screen = this.total = this.size = 1;\n    this.pos = 0;\n\n    this.node = document.createElement(\"div\");\n    this.node.className = cls + \"-\" + orientation;\n    this.inner = this.node.appendChild(document.createElement(\"div\"));\n\n    var self = this;\n    CodeMirror.on(this.inner, \"mousedown\", function(e) {\n      if (e.which != 1) return;\n      CodeMirror.e_preventDefault(e);\n      var axis = self.orientation == \"horizontal\" ? \"pageX\" : \"pageY\";\n      var start = e[axis], startpos = self.pos;\n      function done() {\n        CodeMirror.off(document, \"mousemove\", move);\n        CodeMirror.off(document, \"mouseup\", done);\n      }\n      function move(e) {\n        if (e.which != 1) return done();\n        self.moveTo(startpos + (e[axis] - start) * (self.total / self.size));\n      }\n      CodeMirror.on(document, \"mousemove\", move);\n      CodeMirror.on(document, \"mouseup\", done);\n    });\n\n    CodeMirror.on(this.node, \"click\", function(e) {\n      CodeMirror.e_preventDefault(e);\n      var innerBox = self.inner.getBoundingClientRect(), where;\n      if (self.orientation == \"horizontal\")\n        where = e.clientX < innerBox.left ? -1 : e.clientX > innerBox.right ? 1 : 0;\n      else\n        where = e.clientY < innerBox.top ? -1 : e.clientY > innerBox.bottom ? 1 : 0;\n      self.moveTo(self.pos + where * self.screen);\n    });\n\n    function onWheel(e) {\n      var moved = CodeMirror.wheelEventPixels(e)[self.orientation == \"horizontal\" ? \"x\" : \"y\"];\n      var oldPos = self.pos;\n      self.moveTo(self.pos + moved);\n      if (self.pos != oldPos) CodeMirror.e_preventDefault(e);\n    }\n    CodeMirror.on(this.node, \"mousewheel\", onWheel);\n    CodeMirror.on(this.node, \"DOMMouseScroll\", onWheel);\n  }\n\n  Bar.prototype.moveTo = function(pos, update) {\n    if (pos < 0) pos = 0;\n    if (pos > this.total - this.screen) pos = this.total - this.screen;\n    if (pos == this.pos) return;\n    this.pos = pos;\n    this.inner.style[this.orientation == \"horizontal\" ? \"left\" : \"top\"] =\n      (pos * (this.size / this.total)) + \"px\";\n    if (update !== false) this.scroll(pos, this.orientation);\n  };\n\n  Bar.prototype.update = function(scrollSize, clientSize, barSize) {\n    this.screen = clientSize;\n    this.total = scrollSize;\n    this.size = barSize;\n\n    // FIXME clip to min size?\n    this.inner.style[this.orientation == \"horizontal\" ? \"width\" : \"height\"] =\n      this.screen * (this.size / this.total) + \"px\";\n    this.inner.style[this.orientation == \"horizontal\" ? \"left\" : \"top\"] =\n      this.pos * (this.size / this.total) + \"px\";\n  };\n\n  function SimpleScrollbars(cls, place, scroll) {\n    this.addClass = cls;\n    this.horiz = new Bar(cls, \"horizontal\", scroll);\n    place(this.horiz.node);\n    this.vert = new Bar(cls, \"vertical\", scroll);\n    place(this.vert.node);\n    this.width = null;\n  }\n\n  SimpleScrollbars.prototype.update = function(measure) {\n    if (this.width == null) {\n      var style = window.getComputedStyle ? window.getComputedStyle(this.horiz.node) : this.horiz.node.currentStyle;\n      if (style) this.width = parseInt(style.height);\n    }\n    var width = this.width || 0;\n\n    var needsH = measure.scrollWidth > measure.clientWidth + 1;\n    var needsV = measure.scrollHeight > measure.clientHeight + 1;\n    this.vert.node.style.display = needsV ? \"block\" : \"none\";\n    this.horiz.node.style.display = needsH ? \"block\" : \"none\";\n\n    if (needsV) {\n      this.vert.update(measure.scrollHeight, measure.clientHeight,\n                       measure.viewHeight - (needsH ? width : 0));\n      this.vert.node.style.display = \"block\";\n      this.vert.node.style.bottom = needsH ? width + \"px\" : \"0\";\n    }\n    if (needsH) {\n      this.horiz.update(measure.scrollWidth, measure.clientWidth,\n                        measure.viewWidth - (needsV ? width : 0) - measure.barLeft);\n      this.horiz.node.style.right = needsV ? width + \"px\" : \"0\";\n      this.horiz.node.style.left = measure.barLeft + \"px\";\n    }\n\n    return {right: needsV ? width : 0, bottom: needsH ? width : 0};\n  };\n\n  SimpleScrollbars.prototype.setScrollTop = function(pos) {\n    this.vert.moveTo(pos, false);\n  };\n\n  SimpleScrollbars.prototype.setScrollLeft = function(pos) {\n    this.horiz.moveTo(pos, false);\n  };\n\n  SimpleScrollbars.prototype.clear = function() {\n    var parent = this.horiz.node.parentNode;\n    parent.removeChild(this.horiz.node);\n    parent.removeChild(this.vert.node);\n  };\n\n  CodeMirror.scrollbarModel.simple = function(place, scroll) {\n    return new SimpleScrollbars(\"CodeMirror-simplescroll\", place, scroll);\n  };\n  CodeMirror.scrollbarModel.overlay = function(place, scroll) {\n    return new SimpleScrollbars(\"CodeMirror-overlayscroll\", place, scroll);\n  };\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/search/match-highlighter.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n// Highlighting text that matches the selection\n//\n// Defines an option highlightSelectionMatches, which, when enabled,\n// will style strings that match the selection throughout the\n// document.\n//\n// The option can be set to true to simply enable it, or to a\n// {minChars, style, wordsOnly, showToken, delay} object to explicitly\n// configure it. minChars is the minimum amount of characters that should be\n// selected for the behavior to occur, and style is the token style to\n// apply to the matches. This will be prefixed by \"cm-\" to create an\n// actual CSS class name. If wordsOnly is enabled, the matches will be\n// highlighted only if the selected text is a word. showToken, when enabled,\n// will cause the current token to be highlighted when nothing is selected.\n// delay is used to specify how much time to wait, in milliseconds, before\n// highlighting the matches.\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n\n  var DEFAULT_MIN_CHARS = 2;\n  var DEFAULT_TOKEN_STYLE = \"matchhighlight\";\n  var DEFAULT_DELAY = 100;\n  var DEFAULT_WORDS_ONLY = false;\n\n  function State(options) {\n    if (typeof options == \"object\") {\n      this.minChars = options.minChars;\n      this.style = options.style;\n      this.showToken = options.showToken;\n      this.delay = options.delay;\n      this.wordsOnly = options.wordsOnly;\n    }\n    if (this.style == null) this.style = DEFAULT_TOKEN_STYLE;\n    if (this.minChars == null) this.minChars = DEFAULT_MIN_CHARS;\n    if (this.delay == null) this.delay = DEFAULT_DELAY;\n    if (this.wordsOnly == null) this.wordsOnly = DEFAULT_WORDS_ONLY;\n    this.overlay = this.timeout = null;\n  }\n\n  CodeMirror.defineOption(\"highlightSelectionMatches\", false, function(cm, val, old) {\n    if (old && old != CodeMirror.Init) {\n      var over = cm.state.matchHighlighter.overlay;\n      if (over) cm.removeOverlay(over);\n      clearTimeout(cm.state.matchHighlighter.timeout);\n      cm.state.matchHighlighter = null;\n      cm.off(\"cursorActivity\", cursorActivity);\n    }\n    if (val) {\n      cm.state.matchHighlighter = new State(val);\n      highlightMatches(cm);\n      cm.on(\"cursorActivity\", cursorActivity);\n    }\n  });\n\n  function cursorActivity(cm) {\n    var state = cm.state.matchHighlighter;\n    clearTimeout(state.timeout);\n    state.timeout = setTimeout(function() {highlightMatches(cm);}, state.delay);\n  }\n\n  function highlightMatches(cm) {\n    cm.operation(function() {\n      var state = cm.state.matchHighlighter;\n      if (state.overlay) {\n        cm.removeOverlay(state.overlay);\n        state.overlay = null;\n      }\n      if (!cm.somethingSelected() && state.showToken) {\n        var re = state.showToken === true ? /[\\w$]/ : state.showToken;\n        var cur = cm.getCursor(), line = cm.getLine(cur.line), start = cur.ch, end = start;\n        while (start && re.test(line.charAt(start - 1))) --start;\n        while (end < line.length && re.test(line.charAt(end))) ++end;\n        if (start < end)\n          cm.addOverlay(state.overlay = makeOverlay(line.slice(start, end), re, state.style));\n        return;\n      }\n      var from = cm.getCursor(\"from\"), to = cm.getCursor(\"to\");\n      if (from.line != to.line) return;\n      if (state.wordsOnly && !isWord(cm, from, to)) return;\n      var selection = cm.getRange(from, to).replace(/^\\s+|\\s+$/g, \"\");\n      if (selection.length >= state.minChars)\n        cm.addOverlay(state.overlay = makeOverlay(selection, false, state.style));\n    });\n  }\n\n  function isWord(cm, from, to) {\n    var str = cm.getRange(from, to);\n    if (str.match(/^\\w+$/) !== null) {\n        if (from.ch > 0) {\n            var pos = {line: from.line, ch: from.ch - 1};\n            var chr = cm.getRange(pos, from);\n            if (chr.match(/\\W/) === null) return false;\n        }\n        if (to.ch < cm.getLine(from.line).length) {\n            var pos = {line: to.line, ch: to.ch + 1};\n            var chr = cm.getRange(to, pos);\n            if (chr.match(/\\W/) === null) return false;\n        }\n        return true;\n    } else return false;\n  }\n\n  function boundariesAround(stream, re) {\n    return (!stream.start || !re.test(stream.string.charAt(stream.start - 1))) &&\n      (stream.pos == stream.string.length || !re.test(stream.string.charAt(stream.pos)));\n  }\n\n  function makeOverlay(query, hasBoundary, style) {\n    return {token: function(stream) {\n      if (stream.match(query) &&\n          (!hasBoundary || boundariesAround(stream, hasBoundary)))\n        return style;\n      stream.next();\n      stream.skipTo(query.charAt(0)) || stream.skipToEnd();\n    }};\n  }\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/search/matchesonscrollbar.css",
    "content": ".CodeMirror-search-match {\n  background: gold;\n  border-top: 1px solid orange;\n  border-bottom: 1px solid orange;\n  -moz-box-sizing: border-box;\n  box-sizing: border-box;\n  opacity: .5;\n}\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/search/matchesonscrollbar.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"), require(\"./searchcursor\"), require(\"../scroll/annotatescrollbar\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\", \"./searchcursor\", \"../scroll/annotatescrollbar\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n\n  CodeMirror.defineExtension(\"showMatchesOnScrollbar\", function(query, caseFold, options) {\n    if (typeof options == \"string\") options = {className: options};\n    if (!options) options = {};\n    return new SearchAnnotation(this, query, caseFold, options);\n  });\n\n  function SearchAnnotation(cm, query, caseFold, options) {\n    this.cm = cm;\n    var annotateOptions = {listenForChanges: false};\n    for (var prop in options) annotateOptions[prop] = options[prop];\n    if (!annotateOptions.className) annotateOptions.className = \"CodeMirror-search-match\";\n    this.annotation = cm.annotateScrollbar(annotateOptions);\n    this.query = query;\n    this.caseFold = caseFold;\n    this.gap = {from: cm.firstLine(), to: cm.lastLine() + 1};\n    this.matches = [];\n    this.update = null;\n\n    this.findMatches();\n    this.annotation.update(this.matches);\n\n    var self = this;\n    cm.on(\"change\", this.changeHandler = function(_cm, change) { self.onChange(change); });\n  }\n\n  var MAX_MATCHES = 1000;\n\n  SearchAnnotation.prototype.findMatches = function() {\n    if (!this.gap) return;\n    for (var i = 0; i < this.matches.length; i++) {\n      var match = this.matches[i];\n      if (match.from.line >= this.gap.to) break;\n      if (match.to.line >= this.gap.from) this.matches.splice(i--, 1);\n    }\n    var cursor = this.cm.getSearchCursor(this.query, CodeMirror.Pos(this.gap.from, 0), this.caseFold);\n    while (cursor.findNext()) {\n      var match = {from: cursor.from(), to: cursor.to()};\n      if (match.from.line >= this.gap.to) break;\n      this.matches.splice(i++, 0, match);\n      if (this.matches.length > MAX_MATCHES) break;\n    }\n    this.gap = null;\n  };\n\n  function offsetLine(line, changeStart, sizeChange) {\n    if (line <= changeStart) return line;\n    return Math.max(changeStart, line + sizeChange);\n  }\n\n  SearchAnnotation.prototype.onChange = function(change) {\n    var startLine = change.from.line;\n    var endLine = CodeMirror.changeEnd(change).line;\n    var sizeChange = endLine - change.to.line;\n    if (this.gap) {\n      this.gap.from = Math.min(offsetLine(this.gap.from, startLine, sizeChange), change.from.line);\n      this.gap.to = Math.max(offsetLine(this.gap.to, startLine, sizeChange), change.from.line);\n    } else {\n      this.gap = {from: change.from.line, to: endLine + 1};\n    }\n\n    if (sizeChange) for (var i = 0; i < this.matches.length; i++) {\n      var match = this.matches[i];\n      var newFrom = offsetLine(match.from.line, startLine, sizeChange);\n      if (newFrom != match.from.line) match.from = CodeMirror.Pos(newFrom, match.from.ch);\n      var newTo = offsetLine(match.to.line, startLine, sizeChange);\n      if (newTo != match.to.line) match.to = CodeMirror.Pos(newTo, match.to.ch);\n    }\n    clearTimeout(this.update);\n    var self = this;\n    this.update = setTimeout(function() { self.updateAfterChange(); }, 250);\n  };\n\n  SearchAnnotation.prototype.updateAfterChange = function() {\n    this.findMatches();\n    this.annotation.update(this.matches);\n  };\n\n  SearchAnnotation.prototype.clear = function() {\n    this.cm.off(\"change\", this.changeHandler);\n    this.annotation.clear();\n  };\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/search/search.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n// Define search commands. Depends on dialog.js or another\n// implementation of the openDialog method.\n\n// Replace works a little oddly -- it will do the replace on the next\n// Ctrl-G (or whatever is bound to findNext) press. You prevent a\n// replace by making sure the match is no longer selected when hitting\n// Ctrl-G.\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"), require(\"./searchcursor\"), require(\"../dialog/dialog\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\", \"./searchcursor\", \"../dialog/dialog\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n  function searchOverlay(query, caseInsensitive) {\n    if (typeof query == \"string\")\n      query = new RegExp(query.replace(/[\\-\\[\\]\\/\\{\\}\\(\\)\\*\\+\\?\\.\\\\\\^\\$\\|]/g, \"\\\\$&\"), caseInsensitive ? \"gi\" : \"g\");\n    else if (!query.global)\n      query = new RegExp(query.source, query.ignoreCase ? \"gi\" : \"g\");\n\n    return {token: function(stream) {\n      query.lastIndex = stream.pos;\n      var match = query.exec(stream.string);\n      if (match && match.index == stream.pos) {\n        stream.pos += match[0].length;\n        return \"searching\";\n      } else if (match) {\n        stream.pos = match.index;\n      } else {\n        stream.skipToEnd();\n      }\n    }};\n  }\n\n  function SearchState() {\n    this.posFrom = this.posTo = this.query = null;\n    this.overlay = null;\n  }\n  function getSearchState(cm) {\n    return cm.state.search || (cm.state.search = new SearchState());\n  }\n  function queryCaseInsensitive(query) {\n    return typeof query == \"string\" && query == query.toLowerCase();\n  }\n  function getSearchCursor(cm, query, pos) {\n    // Heuristic: if the query string is all lowercase, do a case insensitive search.\n    return cm.getSearchCursor(query, pos, queryCaseInsensitive(query));\n  }\n  function dialog(cm, text, shortText, deflt, f) {\n    if (cm.openDialog) cm.openDialog(text, f, {value: deflt});\n    else f(prompt(shortText, deflt));\n  }\n  function confirmDialog(cm, text, shortText, fs) {\n    if (cm.openConfirm) cm.openConfirm(text, fs);\n    else if (confirm(shortText)) fs[0]();\n  }\n  function parseQuery(query) {\n    var isRE = query.match(/^\\/(.*)\\/([a-z]*)$/);\n    if (isRE) {\n      try { query = new RegExp(isRE[1], isRE[2].indexOf(\"i\") == -1 ? \"\" : \"i\"); }\n      catch(e) {} // Not a regular expression after all, do a string search\n    }\n    if (typeof query == \"string\" ? query == \"\" : query.test(\"\"))\n      query = /x^/;\n    return query;\n  }\n  var queryDialog =\n    'Search: <input type=\"text\" style=\"width: 10em\" class=\"CodeMirror-search-field\"/> <span style=\"color: #888\" class=\"CodeMirror-search-hint\">(Use /re/ syntax for regexp search)</span>';\n  function doSearch(cm, rev) {\n    var state = getSearchState(cm);\n    if (state.query) return findNext(cm, rev);\n    dialog(cm, queryDialog, \"Search for:\", cm.getSelection(), function(query) {\n      cm.operation(function() {\n        if (!query || state.query) return;\n        state.query = parseQuery(query);\n        cm.removeOverlay(state.overlay, queryCaseInsensitive(state.query));\n        state.overlay = searchOverlay(state.query, queryCaseInsensitive(state.query));\n        cm.addOverlay(state.overlay);\n        if (cm.showMatchesOnScrollbar) {\n          if (state.annotate) { state.annotate.clear(); state.annotate = null; }\n          state.annotate = cm.showMatchesOnScrollbar(state.query, queryCaseInsensitive(state.query));\n        }\n        state.posFrom = state.posTo = cm.getCursor();\n        findNext(cm, rev);\n      });\n    });\n  }\n  function findNext(cm, rev) {cm.operation(function() {\n    var state = getSearchState(cm);\n    var cursor = getSearchCursor(cm, state.query, rev ? state.posFrom : state.posTo);\n    if (!cursor.find(rev)) {\n      cursor = getSearchCursor(cm, state.query, rev ? CodeMirror.Pos(cm.lastLine()) : CodeMirror.Pos(cm.firstLine(), 0));\n      if (!cursor.find(rev)) return;\n    }\n    cm.setSelection(cursor.from(), cursor.to());\n    cm.scrollIntoView({from: cursor.from(), to: cursor.to()});\n    state.posFrom = cursor.from(); state.posTo = cursor.to();\n  });}\n  function clearSearch(cm) {cm.operation(function() {\n    var state = getSearchState(cm);\n    if (!state.query) return;\n    state.query = null;\n    cm.removeOverlay(state.overlay);\n    if (state.annotate) { state.annotate.clear(); state.annotate = null; }\n  });}\n\n  var replaceQueryDialog =\n    'Replace: <input type=\"text\" style=\"width: 10em\" class=\"CodeMirror-search-field\"/> <span style=\"color: #888\" class=\"CodeMirror-search-hint\">(Use /re/ syntax for regexp search)</span>';\n  var replacementQueryDialog = 'With: <input type=\"text\" style=\"width: 10em\" class=\"CodeMirror-search-field\"/>';\n  var doReplaceConfirm = \"Replace? <button>Yes</button> <button>No</button> <button>Stop</button>\";\n  function replace(cm, all) {\n    if (cm.getOption(\"readOnly\")) return;\n    dialog(cm, replaceQueryDialog, \"Replace:\", cm.getSelection(), function(query) {\n      if (!query) return;\n      query = parseQuery(query);\n      dialog(cm, replacementQueryDialog, \"Replace with:\", \"\", function(text) {\n        if (all) {\n          cm.operation(function() {\n            for (var cursor = getSearchCursor(cm, query); cursor.findNext();) {\n              if (typeof query != \"string\") {\n                var match = cm.getRange(cursor.from(), cursor.to()).match(query);\n                cursor.replace(text.replace(/\\$(\\d)/g, function(_, i) {return match[i];}));\n              } else cursor.replace(text);\n            }\n          });\n        } else {\n          clearSearch(cm);\n          var cursor = getSearchCursor(cm, query, cm.getCursor());\n          var advance = function() {\n            var start = cursor.from(), match;\n            if (!(match = cursor.findNext())) {\n              cursor = getSearchCursor(cm, query);\n              if (!(match = cursor.findNext()) ||\n                  (start && cursor.from().line == start.line && cursor.from().ch == start.ch)) return;\n            }\n            cm.setSelection(cursor.from(), cursor.to());\n            cm.scrollIntoView({from: cursor.from(), to: cursor.to()});\n            confirmDialog(cm, doReplaceConfirm, \"Replace?\",\n                          [function() {doReplace(match);}, advance]);\n          };\n          var doReplace = function(match) {\n            cursor.replace(typeof query == \"string\" ? text :\n                           text.replace(/\\$(\\d)/g, function(_, i) {return match[i];}));\n            advance();\n          };\n          advance();\n        }\n      });\n    });\n  }\n\n  CodeMirror.commands.find = function(cm) {clearSearch(cm); doSearch(cm);};\n  CodeMirror.commands.findNext = doSearch;\n  CodeMirror.commands.findPrev = function(cm) {doSearch(cm, true);};\n  CodeMirror.commands.clearSearch = clearSearch;\n  CodeMirror.commands.replace = replace;\n  CodeMirror.commands.replaceAll = function(cm) {replace(cm, true);};\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/search/searchcursor.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n  var Pos = CodeMirror.Pos;\n\n  function SearchCursor(doc, query, pos, caseFold) {\n    this.atOccurrence = false; this.doc = doc;\n    if (caseFold == null && typeof query == \"string\") caseFold = false;\n\n    pos = pos ? doc.clipPos(pos) : Pos(0, 0);\n    this.pos = {from: pos, to: pos};\n\n    // The matches method is filled in based on the type of query.\n    // It takes a position and a direction, and returns an object\n    // describing the next occurrence of the query, or null if no\n    // more matches were found.\n    if (typeof query != \"string\") { // Regexp match\n      if (!query.global) query = new RegExp(query.source, query.ignoreCase ? \"ig\" : \"g\");\n      this.matches = function(reverse, pos) {\n        if (reverse) {\n          query.lastIndex = 0;\n          var line = doc.getLine(pos.line).slice(0, pos.ch), cutOff = 0, match, start;\n          for (;;) {\n            query.lastIndex = cutOff;\n            var newMatch = query.exec(line);\n            if (!newMatch) break;\n            match = newMatch;\n            start = match.index;\n            cutOff = match.index + (match[0].length || 1);\n            if (cutOff == line.length) break;\n          }\n          var matchLen = (match && match[0].length) || 0;\n          if (!matchLen) {\n            if (start == 0 && line.length == 0) {match = undefined;}\n            else if (start != doc.getLine(pos.line).length) {\n              matchLen++;\n            }\n          }\n        } else {\n          query.lastIndex = pos.ch;\n          var line = doc.getLine(pos.line), match = query.exec(line);\n          var matchLen = (match && match[0].length) || 0;\n          var start = match && match.index;\n          if (start + matchLen != line.length && !matchLen) matchLen = 1;\n        }\n        if (match && matchLen)\n          return {from: Pos(pos.line, start),\n                  to: Pos(pos.line, start + matchLen),\n                  match: match};\n      };\n    } else { // String query\n      var origQuery = query;\n      if (caseFold) query = query.toLowerCase();\n      var fold = caseFold ? function(str){return str.toLowerCase();} : function(str){return str;};\n      var target = query.split(\"\\n\");\n      // Different methods for single-line and multi-line queries\n      if (target.length == 1) {\n        if (!query.length) {\n          // Empty string would match anything and never progress, so\n          // we define it to match nothing instead.\n          this.matches = function() {};\n        } else {\n          this.matches = function(reverse, pos) {\n            if (reverse) {\n              var orig = doc.getLine(pos.line).slice(0, pos.ch), line = fold(orig);\n              var match = line.lastIndexOf(query);\n              if (match > -1) {\n                match = adjustPos(orig, line, match);\n                return {from: Pos(pos.line, match), to: Pos(pos.line, match + origQuery.length)};\n              }\n             } else {\n               var orig = doc.getLine(pos.line).slice(pos.ch), line = fold(orig);\n               var match = line.indexOf(query);\n               if (match > -1) {\n                 match = adjustPos(orig, line, match) + pos.ch;\n                 return {from: Pos(pos.line, match), to: Pos(pos.line, match + origQuery.length)};\n               }\n            }\n          };\n        }\n      } else {\n        var origTarget = origQuery.split(\"\\n\");\n        this.matches = function(reverse, pos) {\n          var last = target.length - 1;\n          if (reverse) {\n            if (pos.line - (target.length - 1) < doc.firstLine()) return;\n            if (fold(doc.getLine(pos.line).slice(0, origTarget[last].length)) != target[target.length - 1]) return;\n            var to = Pos(pos.line, origTarget[last].length);\n            for (var ln = pos.line - 1, i = last - 1; i >= 1; --i, --ln)\n              if (target[i] != fold(doc.getLine(ln))) return;\n            var line = doc.getLine(ln), cut = line.length - origTarget[0].length;\n            if (fold(line.slice(cut)) != target[0]) return;\n            return {from: Pos(ln, cut), to: to};\n          } else {\n            if (pos.line + (target.length - 1) > doc.lastLine()) return;\n            var line = doc.getLine(pos.line), cut = line.length - origTarget[0].length;\n            if (fold(line.slice(cut)) != target[0]) return;\n            var from = Pos(pos.line, cut);\n            for (var ln = pos.line + 1, i = 1; i < last; ++i, ++ln)\n              if (target[i] != fold(doc.getLine(ln))) return;\n            if (fold(doc.getLine(ln).slice(0, origTarget[last].length)) != target[last]) return;\n            return {from: from, to: Pos(ln, origTarget[last].length)};\n          }\n        };\n      }\n    }\n  }\n\n  SearchCursor.prototype = {\n    findNext: function() {return this.find(false);},\n    findPrevious: function() {return this.find(true);},\n\n    find: function(reverse) {\n      var self = this, pos = this.doc.clipPos(reverse ? this.pos.from : this.pos.to);\n      function savePosAndFail(line) {\n        var pos = Pos(line, 0);\n        self.pos = {from: pos, to: pos};\n        self.atOccurrence = false;\n        return false;\n      }\n\n      for (;;) {\n        if (this.pos = this.matches(reverse, pos)) {\n          this.atOccurrence = true;\n          return this.pos.match || true;\n        }\n        if (reverse) {\n          if (!pos.line) return savePosAndFail(0);\n          pos = Pos(pos.line-1, this.doc.getLine(pos.line-1).length);\n        }\n        else {\n          var maxLine = this.doc.lineCount();\n          if (pos.line == maxLine - 1) return savePosAndFail(maxLine);\n          pos = Pos(pos.line + 1, 0);\n        }\n      }\n    },\n\n    from: function() {if (this.atOccurrence) return this.pos.from;},\n    to: function() {if (this.atOccurrence) return this.pos.to;},\n\n    replace: function(newText) {\n      if (!this.atOccurrence) return;\n      var lines = CodeMirror.splitLines(newText);\n      this.doc.replaceRange(lines, this.pos.from, this.pos.to);\n      this.pos.to = Pos(this.pos.from.line + lines.length - 1,\n                        lines[lines.length - 1].length + (lines.length == 1 ? this.pos.from.ch : 0));\n    }\n  };\n\n  // Maps a position in a case-folded line back to a position in the original line\n  // (compensating for codepoints increasing in number during folding)\n  function adjustPos(orig, folded, pos) {\n    if (orig.length == folded.length) return pos;\n    for (var pos1 = Math.min(pos, orig.length);;) {\n      var len1 = orig.slice(0, pos1).toLowerCase().length;\n      if (len1 < pos) ++pos1;\n      else if (len1 > pos) --pos1;\n      else return pos1;\n    }\n  }\n\n  CodeMirror.defineExtension(\"getSearchCursor\", function(query, pos, caseFold) {\n    return new SearchCursor(this.doc, query, pos, caseFold);\n  });\n  CodeMirror.defineDocExtension(\"getSearchCursor\", function(query, pos, caseFold) {\n    return new SearchCursor(this, query, pos, caseFold);\n  });\n\n  CodeMirror.defineExtension(\"selectMatches\", function(query, caseFold) {\n    var ranges = [], next;\n    var cur = this.getSearchCursor(query, this.getCursor(\"from\"), caseFold);\n    while (next = cur.findNext()) {\n      if (CodeMirror.cmpPos(cur.to(), this.getCursor(\"to\")) > 0) break;\n      ranges.push({anchor: cur.from(), head: cur.to()});\n    }\n    if (ranges.length)\n      this.setSelections(ranges, 0);\n  });\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/selection/active-line.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n// Because sometimes you need to style the cursor's line.\n//\n// Adds an option 'styleActiveLine' which, when enabled, gives the\n// active line's wrapping <div> the CSS class \"CodeMirror-activeline\",\n// and gives its background <div> the class \"CodeMirror-activeline-background\".\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n  var WRAP_CLASS = \"CodeMirror-activeline\";\n  var BACK_CLASS = \"CodeMirror-activeline-background\";\n\n  CodeMirror.defineOption(\"styleActiveLine\", false, function(cm, val, old) {\n    var prev = old && old != CodeMirror.Init;\n    if (val && !prev) {\n      cm.state.activeLines = [];\n      updateActiveLines(cm, cm.listSelections());\n      cm.on(\"beforeSelectionChange\", selectionChange);\n    } else if (!val && prev) {\n      cm.off(\"beforeSelectionChange\", selectionChange);\n      clearActiveLines(cm);\n      delete cm.state.activeLines;\n    }\n  });\n\n  function clearActiveLines(cm) {\n    for (var i = 0; i < cm.state.activeLines.length; i++) {\n      cm.removeLineClass(cm.state.activeLines[i], \"wrap\", WRAP_CLASS);\n      cm.removeLineClass(cm.state.activeLines[i], \"background\", BACK_CLASS);\n    }\n  }\n\n  function sameArray(a, b) {\n    if (a.length != b.length) return false;\n    for (var i = 0; i < a.length; i++)\n      if (a[i] != b[i]) return false;\n    return true;\n  }\n\n  function updateActiveLines(cm, ranges) {\n    var active = [];\n    for (var i = 0; i < ranges.length; i++) {\n      var range = ranges[i];\n      if (!range.empty()) continue;\n      var line = cm.getLineHandleVisualStart(range.head.line);\n      if (active[active.length - 1] != line) active.push(line);\n    }\n    if (sameArray(cm.state.activeLines, active)) return;\n    cm.operation(function() {\n      clearActiveLines(cm);\n      for (var i = 0; i < active.length; i++) {\n        cm.addLineClass(active[i], \"wrap\", WRAP_CLASS);\n        cm.addLineClass(active[i], \"background\", BACK_CLASS);\n      }\n      cm.state.activeLines = active;\n    });\n  }\n\n  function selectionChange(cm, sel) {\n    updateActiveLines(cm, sel.ranges);\n  }\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/selection/mark-selection.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n// Because sometimes you need to mark the selected *text*.\n//\n// Adds an option 'styleSelectedText' which, when enabled, gives\n// selected text the CSS class given as option value, or\n// \"CodeMirror-selectedtext\" when the value is not a string.\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n\n  CodeMirror.defineOption(\"styleSelectedText\", false, function(cm, val, old) {\n    var prev = old && old != CodeMirror.Init;\n    if (val && !prev) {\n      cm.state.markedSelection = [];\n      cm.state.markedSelectionStyle = typeof val == \"string\" ? val : \"CodeMirror-selectedtext\";\n      reset(cm);\n      cm.on(\"cursorActivity\", onCursorActivity);\n      cm.on(\"change\", onChange);\n    } else if (!val && prev) {\n      cm.off(\"cursorActivity\", onCursorActivity);\n      cm.off(\"change\", onChange);\n      clear(cm);\n      cm.state.markedSelection = cm.state.markedSelectionStyle = null;\n    }\n  });\n\n  function onCursorActivity(cm) {\n    cm.operation(function() { update(cm); });\n  }\n\n  function onChange(cm) {\n    if (cm.state.markedSelection.length)\n      cm.operation(function() { clear(cm); });\n  }\n\n  var CHUNK_SIZE = 8;\n  var Pos = CodeMirror.Pos;\n  var cmp = CodeMirror.cmpPos;\n\n  function coverRange(cm, from, to, addAt) {\n    if (cmp(from, to) == 0) return;\n    var array = cm.state.markedSelection;\n    var cls = cm.state.markedSelectionStyle;\n    for (var line = from.line;;) {\n      var start = line == from.line ? from : Pos(line, 0);\n      var endLine = line + CHUNK_SIZE, atEnd = endLine >= to.line;\n      var end = atEnd ? to : Pos(endLine, 0);\n      var mark = cm.markText(start, end, {className: cls});\n      if (addAt == null) array.push(mark);\n      else array.splice(addAt++, 0, mark);\n      if (atEnd) break;\n      line = endLine;\n    }\n  }\n\n  function clear(cm) {\n    var array = cm.state.markedSelection;\n    for (var i = 0; i < array.length; ++i) array[i].clear();\n    array.length = 0;\n  }\n\n  function reset(cm) {\n    clear(cm);\n    var ranges = cm.listSelections();\n    for (var i = 0; i < ranges.length; i++)\n      coverRange(cm, ranges[i].from(), ranges[i].to());\n  }\n\n  function update(cm) {\n    if (!cm.somethingSelected()) return clear(cm);\n    if (cm.listSelections().length > 1) return reset(cm);\n\n    var from = cm.getCursor(\"start\"), to = cm.getCursor(\"end\");\n\n    var array = cm.state.markedSelection;\n    if (!array.length) return coverRange(cm, from, to);\n\n    var coverStart = array[0].find(), coverEnd = array[array.length - 1].find();\n    if (!coverStart || !coverEnd || to.line - from.line < CHUNK_SIZE ||\n        cmp(from, coverEnd.to) >= 0 || cmp(to, coverStart.from) <= 0)\n      return reset(cm);\n\n    while (cmp(from, coverStart.from) > 0) {\n      array.shift().clear();\n      coverStart = array[0].find();\n    }\n    if (cmp(from, coverStart.from) < 0) {\n      if (coverStart.to.line - from.line < CHUNK_SIZE) {\n        array.shift().clear();\n        coverRange(cm, from, coverStart.to, 0);\n      } else {\n        coverRange(cm, from, coverStart.from, 0);\n      }\n    }\n\n    while (cmp(to, coverEnd.to) < 0) {\n      array.pop().clear();\n      coverEnd = array[array.length - 1].find();\n    }\n    if (cmp(to, coverEnd.to) > 0) {\n      if (to.line - coverEnd.from.line < CHUNK_SIZE) {\n        array.pop().clear();\n        coverRange(cm, coverEnd.from, to);\n      } else {\n        coverRange(cm, coverEnd.to, to);\n      }\n    }\n  }\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/selection/selection-pointer.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n\n  CodeMirror.defineOption(\"selectionPointer\", false, function(cm, val) {\n    var data = cm.state.selectionPointer;\n    if (data) {\n      CodeMirror.off(cm.getWrapperElement(), \"mousemove\", data.mousemove);\n      CodeMirror.off(cm.getWrapperElement(), \"mouseout\", data.mouseout);\n      CodeMirror.off(window, \"scroll\", data.windowScroll);\n      cm.off(\"cursorActivity\", reset);\n      cm.off(\"scroll\", reset);\n      cm.state.selectionPointer = null;\n      cm.display.lineDiv.style.cursor = \"\";\n    }\n    if (val) {\n      data = cm.state.selectionPointer = {\n        value: typeof val == \"string\" ? val : \"default\",\n        mousemove: function(event) { mousemove(cm, event); },\n        mouseout: function(event) { mouseout(cm, event); },\n        windowScroll: function() { reset(cm); },\n        rects: null,\n        mouseX: null, mouseY: null,\n        willUpdate: false\n      };\n      CodeMirror.on(cm.getWrapperElement(), \"mousemove\", data.mousemove);\n      CodeMirror.on(cm.getWrapperElement(), \"mouseout\", data.mouseout);\n      CodeMirror.on(window, \"scroll\", data.windowScroll);\n      cm.on(\"cursorActivity\", reset);\n      cm.on(\"scroll\", reset);\n    }\n  });\n\n  function mousemove(cm, event) {\n    var data = cm.state.selectionPointer;\n    if (event.buttons == null ? event.which : event.buttons) {\n      data.mouseX = data.mouseY = null;\n    } else {\n      data.mouseX = event.clientX;\n      data.mouseY = event.clientY;\n    }\n    scheduleUpdate(cm);\n  }\n\n  function mouseout(cm, event) {\n    if (!cm.getWrapperElement().contains(event.relatedTarget)) {\n      var data = cm.state.selectionPointer;\n      data.mouseX = data.mouseY = null;\n      scheduleUpdate(cm);\n    }\n  }\n\n  function reset(cm) {\n    cm.state.selectionPointer.rects = null;\n    scheduleUpdate(cm);\n  }\n\n  function scheduleUpdate(cm) {\n    if (!cm.state.selectionPointer.willUpdate) {\n      cm.state.selectionPointer.willUpdate = true;\n      setTimeout(function() {\n        update(cm);\n        cm.state.selectionPointer.willUpdate = false;\n      }, 50);\n    }\n  }\n\n  function update(cm) {\n    var data = cm.state.selectionPointer;\n    if (!data) return;\n    if (data.rects == null && data.mouseX != null) {\n      data.rects = [];\n      if (cm.somethingSelected()) {\n        for (var sel = cm.display.selectionDiv.firstChild; sel; sel = sel.nextSibling)\n          data.rects.push(sel.getBoundingClientRect());\n      }\n    }\n    var inside = false;\n    if (data.mouseX != null) for (var i = 0; i < data.rects.length; i++) {\n      var rect = data.rects[i];\n      if (rect.left <= data.mouseX && rect.right >= data.mouseX &&\n          rect.top <= data.mouseY && rect.bottom >= data.mouseY)\n        inside = true;\n    }\n    var cursor = inside ? data.value : \"\";\n    if (cm.display.lineDiv.style.cursor != cursor)\n      cm.display.lineDiv.style.cursor = cursor;\n  }\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/tern/tern.css",
    "content": ".CodeMirror-Tern-completion {\n  padding-left: 22px;\n  position: relative;\n}\n.CodeMirror-Tern-completion:before {\n  position: absolute;\n  left: 2px;\n  bottom: 2px;\n  border-radius: 50%;\n  font-size: 12px;\n  font-weight: bold;\n  height: 15px;\n  width: 15px;\n  line-height: 16px;\n  text-align: center;\n  color: white;\n  -moz-box-sizing: border-box;\n  box-sizing: border-box;\n}\n.CodeMirror-Tern-completion-unknown:before {\n  content: \"?\";\n  background: #4bb;\n}\n.CodeMirror-Tern-completion-object:before {\n  content: \"O\";\n  background: #77c;\n}\n.CodeMirror-Tern-completion-fn:before {\n  content: \"F\";\n  background: #7c7;\n}\n.CodeMirror-Tern-completion-array:before {\n  content: \"A\";\n  background: #c66;\n}\n.CodeMirror-Tern-completion-number:before {\n  content: \"1\";\n  background: #999;\n}\n.CodeMirror-Tern-completion-string:before {\n  content: \"S\";\n  background: #999;\n}\n.CodeMirror-Tern-completion-bool:before {\n  content: \"B\";\n  background: #999;\n}\n\n.CodeMirror-Tern-completion-guess {\n  color: #999;\n}\n\n.CodeMirror-Tern-tooltip {\n  border: 1px solid silver;\n  border-radius: 3px;\n  color: #444;\n  padding: 2px 5px;\n  font-size: 90%;\n  font-family: monospace;\n  background-color: white;\n  white-space: pre-wrap;\n\n  max-width: 40em;\n  position: absolute;\n  z-index: 10;\n  -webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2);\n  -moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2);\n  box-shadow: 2px 3px 5px rgba(0,0,0,.2);\n\n  transition: opacity 1s;\n  -moz-transition: opacity 1s;\n  -webkit-transition: opacity 1s;\n  -o-transition: opacity 1s;\n  -ms-transition: opacity 1s;\n}\n\n.CodeMirror-Tern-hint-doc {\n  max-width: 25em;\n  margin-top: -3px;\n}\n\n.CodeMirror-Tern-fname { color: black; }\n.CodeMirror-Tern-farg { color: #70a; }\n.CodeMirror-Tern-farg-current { text-decoration: underline; }\n.CodeMirror-Tern-type { color: #07c; }\n.CodeMirror-Tern-fhint-guess { opacity: .7; }\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/tern/tern.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n// Glue code between CodeMirror and Tern.\n//\n// Create a CodeMirror.TernServer to wrap an actual Tern server,\n// register open documents (CodeMirror.Doc instances) with it, and\n// call its methods to activate the assisting functions that Tern\n// provides.\n//\n// Options supported (all optional):\n// * defs: An array of JSON definition data structures.\n// * plugins: An object mapping plugin names to configuration\n//   options.\n// * getFile: A function(name, c) that can be used to access files in\n//   the project that haven't been loaded yet. Simply do c(null) to\n//   indicate that a file is not available.\n// * fileFilter: A function(value, docName, doc) that will be applied\n//   to documents before passing them on to Tern.\n// * switchToDoc: A function(name, doc) that should, when providing a\n//   multi-file view, switch the view or focus to the named file.\n// * showError: A function(editor, message) that can be used to\n//   override the way errors are displayed.\n// * completionTip: Customize the content in tooltips for completions.\n//   Is passed a single argument—the completion's data as returned by\n//   Tern—and may return a string, DOM node, or null to indicate that\n//   no tip should be shown. By default the docstring is shown.\n// * typeTip: Like completionTip, but for the tooltips shown for type\n//   queries.\n// * responseFilter: A function(doc, query, request, error, data) that\n//   will be applied to the Tern responses before treating them\n//\n//\n// It is possible to run the Tern server in a web worker by specifying\n// these additional options:\n// * useWorker: Set to true to enable web worker mode. You'll probably\n//   want to feature detect the actual value you use here, for example\n//   !!window.Worker.\n// * workerScript: The main script of the worker. Point this to\n//   wherever you are hosting worker.js from this directory.\n// * workerDeps: An array of paths pointing (relative to workerScript)\n//   to the Acorn and Tern libraries and any Tern plugins you want to\n//   load. Or, if you minified those into a single script and included\n//   them in the workerScript, simply leave this undefined.\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n  // declare global: tern\n\n  CodeMirror.TernServer = function(options) {\n    var self = this;\n    this.options = options || {};\n    var plugins = this.options.plugins || (this.options.plugins = {});\n    if (!plugins.doc_comment) plugins.doc_comment = true;\n    if (this.options.useWorker) {\n      this.server = new WorkerServer(this);\n    } else {\n      this.server = new tern.Server({\n        getFile: function(name, c) { return getFile(self, name, c); },\n        async: true,\n        defs: this.options.defs || [],\n        plugins: plugins\n      });\n    }\n    this.docs = Object.create(null);\n    this.trackChange = function(doc, change) { trackChange(self, doc, change); };\n\n    this.cachedArgHints = null;\n    this.activeArgHints = null;\n    this.jumpStack = [];\n\n    this.getHint = function(cm, c) { return hint(self, cm, c); };\n    this.getHint.async = true;\n  };\n\n  CodeMirror.TernServer.prototype = {\n    addDoc: function(name, doc) {\n      var data = {doc: doc, name: name, changed: null};\n      this.server.addFile(name, docValue(this, data));\n      CodeMirror.on(doc, \"change\", this.trackChange);\n      return this.docs[name] = data;\n    },\n\n    delDoc: function(id) {\n      var found = resolveDoc(this, id);\n      if (!found) return;\n      CodeMirror.off(found.doc, \"change\", this.trackChange);\n      delete this.docs[found.name];\n      this.server.delFile(found.name);\n    },\n\n    hideDoc: function(id) {\n      closeArgHints(this);\n      var found = resolveDoc(this, id);\n      if (found && found.changed) sendDoc(this, found);\n    },\n\n    complete: function(cm) {\n      cm.showHint({hint: this.getHint});\n    },\n\n    showType: function(cm, pos, c) { showContextInfo(this, cm, pos, \"type\", c); },\n\n    showDocs: function(cm, pos, c) { showContextInfo(this, cm, pos, \"documentation\", c); },\n\n    updateArgHints: function(cm) { updateArgHints(this, cm); },\n\n    jumpToDef: function(cm) { jumpToDef(this, cm); },\n\n    jumpBack: function(cm) { jumpBack(this, cm); },\n\n    rename: function(cm) { rename(this, cm); },\n\n    selectName: function(cm) { selectName(this, cm); },\n\n    request: function (cm, query, c, pos) {\n      var self = this;\n      var doc = findDoc(this, cm.getDoc());\n      var request = buildRequest(this, doc, query, pos);\n\n      this.server.request(request, function (error, data) {\n        if (!error && self.options.responseFilter)\n          data = self.options.responseFilter(doc, query, request, error, data);\n        c(error, data);\n      });\n    },\n\n    destroy: function () {\n      if (this.worker) {\n        this.worker.terminate();\n        this.worker = null;\n      }\n    }\n  };\n\n  var Pos = CodeMirror.Pos;\n  var cls = \"CodeMirror-Tern-\";\n  var bigDoc = 250;\n\n  function getFile(ts, name, c) {\n    var buf = ts.docs[name];\n    if (buf)\n      c(docValue(ts, buf));\n    else if (ts.options.getFile)\n      ts.options.getFile(name, c);\n    else\n      c(null);\n  }\n\n  function findDoc(ts, doc, name) {\n    for (var n in ts.docs) {\n      var cur = ts.docs[n];\n      if (cur.doc == doc) return cur;\n    }\n    if (!name) for (var i = 0;; ++i) {\n      n = \"[doc\" + (i || \"\") + \"]\";\n      if (!ts.docs[n]) { name = n; break; }\n    }\n    return ts.addDoc(name, doc);\n  }\n\n  function resolveDoc(ts, id) {\n    if (typeof id == \"string\") return ts.docs[id];\n    if (id instanceof CodeMirror) id = id.getDoc();\n    if (id instanceof CodeMirror.Doc) return findDoc(ts, id);\n  }\n\n  function trackChange(ts, doc, change) {\n    var data = findDoc(ts, doc);\n\n    var argHints = ts.cachedArgHints;\n    if (argHints && argHints.doc == doc && cmpPos(argHints.start, change.to) <= 0)\n      ts.cachedArgHints = null;\n\n    var changed = data.changed;\n    if (changed == null)\n      data.changed = changed = {from: change.from.line, to: change.from.line};\n    var end = change.from.line + (change.text.length - 1);\n    if (change.from.line < changed.to) changed.to = changed.to - (change.to.line - end);\n    if (end >= changed.to) changed.to = end + 1;\n    if (changed.from > change.from.line) changed.from = change.from.line;\n\n    if (doc.lineCount() > bigDoc && change.to - changed.from > 100) setTimeout(function() {\n      if (data.changed && data.changed.to - data.changed.from > 100) sendDoc(ts, data);\n    }, 200);\n  }\n\n  function sendDoc(ts, doc) {\n    ts.server.request({files: [{type: \"full\", name: doc.name, text: docValue(ts, doc)}]}, function(error) {\n      if (error) window.console.error(error);\n      else doc.changed = null;\n    });\n  }\n\n  // Completion\n\n  function hint(ts, cm, c) {\n    ts.request(cm, {type: \"completions\", types: true, docs: true, urls: true}, function(error, data) {\n      if (error) return showError(ts, cm, error);\n      var completions = [], after = \"\";\n      var from = data.start, to = data.end;\n      if (cm.getRange(Pos(from.line, from.ch - 2), from) == \"[\\\"\" &&\n          cm.getRange(to, Pos(to.line, to.ch + 2)) != \"\\\"]\")\n        after = \"\\\"]\";\n\n      for (var i = 0; i < data.completions.length; ++i) {\n        var completion = data.completions[i], className = typeToIcon(completion.type);\n        if (data.guess) className += \" \" + cls + \"guess\";\n        completions.push({text: completion.name + after,\n                          displayText: completion.name,\n                          className: className,\n                          data: completion});\n      }\n\n      var obj = {from: from, to: to, list: completions};\n      var tooltip = null;\n      CodeMirror.on(obj, \"close\", function() { remove(tooltip); });\n      CodeMirror.on(obj, \"update\", function() { remove(tooltip); });\n      CodeMirror.on(obj, \"select\", function(cur, node) {\n        remove(tooltip);\n        var content = ts.options.completionTip ? ts.options.completionTip(cur.data) : cur.data.doc;\n        if (content) {\n          tooltip = makeTooltip(node.parentNode.getBoundingClientRect().right + window.pageXOffset,\n                                node.getBoundingClientRect().top + window.pageYOffset, content);\n          tooltip.className += \" \" + cls + \"hint-doc\";\n        }\n      });\n      c(obj);\n    });\n  }\n\n  function typeToIcon(type) {\n    var suffix;\n    if (type == \"?\") suffix = \"unknown\";\n    else if (type == \"number\" || type == \"string\" || type == \"bool\") suffix = type;\n    else if (/^fn\\(/.test(type)) suffix = \"fn\";\n    else if (/^\\[/.test(type)) suffix = \"array\";\n    else suffix = \"object\";\n    return cls + \"completion \" + cls + \"completion-\" + suffix;\n  }\n\n  // Type queries\n\n  function showContextInfo(ts, cm, pos, queryName, c) {\n    ts.request(cm, queryName, function(error, data) {\n      if (error) return showError(ts, cm, error);\n      if (ts.options.typeTip) {\n        var tip = ts.options.typeTip(data);\n      } else {\n        var tip = elt(\"span\", null, elt(\"strong\", null, data.type || \"not found\"));\n        if (data.doc)\n          tip.appendChild(document.createTextNode(\" — \" + data.doc));\n        if (data.url) {\n          tip.appendChild(document.createTextNode(\" \"));\n          var child = tip.appendChild(elt(\"a\", null, \"[docs]\"));\n          child.href = data.url;\n          child.target = \"_blank\";\n        }\n      }\n      tempTooltip(cm, tip);\n      if (c) c();\n    }, pos);\n  }\n\n  // Maintaining argument hints\n\n  function updateArgHints(ts, cm) {\n    closeArgHints(ts);\n\n    if (cm.somethingSelected()) return;\n    var state = cm.getTokenAt(cm.getCursor()).state;\n    var inner = CodeMirror.innerMode(cm.getMode(), state);\n    if (inner.mode.name != \"javascript\") return;\n    var lex = inner.state.lexical;\n    if (lex.info != \"call\") return;\n\n    var ch, argPos = lex.pos || 0, tabSize = cm.getOption(\"tabSize\");\n    for (var line = cm.getCursor().line, e = Math.max(0, line - 9), found = false; line >= e; --line) {\n      var str = cm.getLine(line), extra = 0;\n      for (var pos = 0;;) {\n        var tab = str.indexOf(\"\\t\", pos);\n        if (tab == -1) break;\n        extra += tabSize - (tab + extra) % tabSize - 1;\n        pos = tab + 1;\n      }\n      ch = lex.column - extra;\n      if (str.charAt(ch) == \"(\") {found = true; break;}\n    }\n    if (!found) return;\n\n    var start = Pos(line, ch);\n    var cache = ts.cachedArgHints;\n    if (cache && cache.doc == cm.getDoc() && cmpPos(start, cache.start) == 0)\n      return showArgHints(ts, cm, argPos);\n\n    ts.request(cm, {type: \"type\", preferFunction: true, end: start}, function(error, data) {\n      if (error || !data.type || !(/^fn\\(/).test(data.type)) return;\n      ts.cachedArgHints = {\n        start: pos,\n        type: parseFnType(data.type),\n        name: data.exprName || data.name || \"fn\",\n        guess: data.guess,\n        doc: cm.getDoc()\n      };\n      showArgHints(ts, cm, argPos);\n    });\n  }\n\n  function showArgHints(ts, cm, pos) {\n    closeArgHints(ts);\n\n    var cache = ts.cachedArgHints, tp = cache.type;\n    var tip = elt(\"span\", cache.guess ? cls + \"fhint-guess\" : null,\n                  elt(\"span\", cls + \"fname\", cache.name), \"(\");\n    for (var i = 0; i < tp.args.length; ++i) {\n      if (i) tip.appendChild(document.createTextNode(\", \"));\n      var arg = tp.args[i];\n      tip.appendChild(elt(\"span\", cls + \"farg\" + (i == pos ? \" \" + cls + \"farg-current\" : \"\"), arg.name || \"?\"));\n      if (arg.type != \"?\") {\n        tip.appendChild(document.createTextNode(\":\\u00a0\"));\n        tip.appendChild(elt(\"span\", cls + \"type\", arg.type));\n      }\n    }\n    tip.appendChild(document.createTextNode(tp.rettype ? \") ->\\u00a0\" : \")\"));\n    if (tp.rettype) tip.appendChild(elt(\"span\", cls + \"type\", tp.rettype));\n    var place = cm.cursorCoords(null, \"page\");\n    ts.activeArgHints = makeTooltip(place.right + 1, place.bottom, tip);\n  }\n\n  function parseFnType(text) {\n    var args = [], pos = 3;\n\n    function skipMatching(upto) {\n      var depth = 0, start = pos;\n      for (;;) {\n        var next = text.charAt(pos);\n        if (upto.test(next) && !depth) return text.slice(start, pos);\n        if (/[{\\[\\(]/.test(next)) ++depth;\n        else if (/[}\\]\\)]/.test(next)) --depth;\n        ++pos;\n      }\n    }\n\n    // Parse arguments\n    if (text.charAt(pos) != \")\") for (;;) {\n      var name = text.slice(pos).match(/^([^, \\(\\[\\{]+): /);\n      if (name) {\n        pos += name[0].length;\n        name = name[1];\n      }\n      args.push({name: name, type: skipMatching(/[\\),]/)});\n      if (text.charAt(pos) == \")\") break;\n      pos += 2;\n    }\n\n    var rettype = text.slice(pos).match(/^\\) -> (.*)$/);\n\n    return {args: args, rettype: rettype && rettype[1]};\n  }\n\n  // Moving to the definition of something\n\n  function jumpToDef(ts, cm) {\n    function inner(varName) {\n      var req = {type: \"definition\", variable: varName || null};\n      var doc = findDoc(ts, cm.getDoc());\n      ts.server.request(buildRequest(ts, doc, req), function(error, data) {\n        if (error) return showError(ts, cm, error);\n        if (!data.file && data.url) { window.open(data.url); return; }\n\n        if (data.file) {\n          var localDoc = ts.docs[data.file], found;\n          if (localDoc && (found = findContext(localDoc.doc, data))) {\n            ts.jumpStack.push({file: doc.name,\n                               start: cm.getCursor(\"from\"),\n                               end: cm.getCursor(\"to\")});\n            moveTo(ts, doc, localDoc, found.start, found.end);\n            return;\n          }\n        }\n        showError(ts, cm, \"Could not find a definition.\");\n      });\n    }\n\n    if (!atInterestingExpression(cm))\n      dialog(cm, \"Jump to variable\", function(name) { if (name) inner(name); });\n    else\n      inner();\n  }\n\n  function jumpBack(ts, cm) {\n    var pos = ts.jumpStack.pop(), doc = pos && ts.docs[pos.file];\n    if (!doc) return;\n    moveTo(ts, findDoc(ts, cm.getDoc()), doc, pos.start, pos.end);\n  }\n\n  function moveTo(ts, curDoc, doc, start, end) {\n    doc.doc.setSelection(start, end);\n    if (curDoc != doc && ts.options.switchToDoc) {\n      closeArgHints(ts);\n      ts.options.switchToDoc(doc.name, doc.doc);\n    }\n  }\n\n  // The {line,ch} representation of positions makes this rather awkward.\n  function findContext(doc, data) {\n    var before = data.context.slice(0, data.contextOffset).split(\"\\n\");\n    var startLine = data.start.line - (before.length - 1);\n    var start = Pos(startLine, (before.length == 1 ? data.start.ch : doc.getLine(startLine).length) - before[0].length);\n\n    var text = doc.getLine(startLine).slice(start.ch);\n    for (var cur = startLine + 1; cur < doc.lineCount() && text.length < data.context.length; ++cur)\n      text += \"\\n\" + doc.getLine(cur);\n    if (text.slice(0, data.context.length) == data.context) return data;\n\n    var cursor = doc.getSearchCursor(data.context, 0, false);\n    var nearest, nearestDist = Infinity;\n    while (cursor.findNext()) {\n      var from = cursor.from(), dist = Math.abs(from.line - start.line) * 10000;\n      if (!dist) dist = Math.abs(from.ch - start.ch);\n      if (dist < nearestDist) { nearest = from; nearestDist = dist; }\n    }\n    if (!nearest) return null;\n\n    if (before.length == 1)\n      nearest.ch += before[0].length;\n    else\n      nearest = Pos(nearest.line + (before.length - 1), before[before.length - 1].length);\n    if (data.start.line == data.end.line)\n      var end = Pos(nearest.line, nearest.ch + (data.end.ch - data.start.ch));\n    else\n      var end = Pos(nearest.line + (data.end.line - data.start.line), data.end.ch);\n    return {start: nearest, end: end};\n  }\n\n  function atInterestingExpression(cm) {\n    var pos = cm.getCursor(\"end\"), tok = cm.getTokenAt(pos);\n    if (tok.start < pos.ch && (tok.type == \"comment\" || tok.type == \"string\")) return false;\n    return /\\w/.test(cm.getLine(pos.line).slice(Math.max(pos.ch - 1, 0), pos.ch + 1));\n  }\n\n  // Variable renaming\n\n  function rename(ts, cm) {\n    var token = cm.getTokenAt(cm.getCursor());\n    if (!/\\w/.test(token.string)) return showError(ts, cm, \"Not at a variable\");\n    dialog(cm, \"New name for \" + token.string, function(newName) {\n      ts.request(cm, {type: \"rename\", newName: newName, fullDocs: true}, function(error, data) {\n        if (error) return showError(ts, cm, error);\n        applyChanges(ts, data.changes);\n      });\n    });\n  }\n\n  function selectName(ts, cm) {\n    var name = findDoc(ts, cm.doc).name;\n    ts.request(cm, {type: \"refs\"}, function(error, data) {\n      if (error) return showError(ts, cm, error);\n      var ranges = [], cur = 0;\n      for (var i = 0; i < data.refs.length; i++) {\n        var ref = data.refs[i];\n        if (ref.file == name) {\n          ranges.push({anchor: ref.start, head: ref.end});\n          if (cmpPos(cur, ref.start) >= 0 && cmpPos(cur, ref.end) <= 0)\n            cur = ranges.length - 1;\n        }\n      }\n      cm.setSelections(ranges, cur);\n    });\n  }\n\n  var nextChangeOrig = 0;\n  function applyChanges(ts, changes) {\n    var perFile = Object.create(null);\n    for (var i = 0; i < changes.length; ++i) {\n      var ch = changes[i];\n      (perFile[ch.file] || (perFile[ch.file] = [])).push(ch);\n    }\n    for (var file in perFile) {\n      var known = ts.docs[file], chs = perFile[file];;\n      if (!known) continue;\n      chs.sort(function(a, b) { return cmpPos(b.start, a.start); });\n      var origin = \"*rename\" + (++nextChangeOrig);\n      for (var i = 0; i < chs.length; ++i) {\n        var ch = chs[i];\n        known.doc.replaceRange(ch.text, ch.start, ch.end, origin);\n      }\n    }\n  }\n\n  // Generic request-building helper\n\n  function buildRequest(ts, doc, query, pos) {\n    var files = [], offsetLines = 0, allowFragments = !query.fullDocs;\n    if (!allowFragments) delete query.fullDocs;\n    if (typeof query == \"string\") query = {type: query};\n    query.lineCharPositions = true;\n    if (query.end == null) {\n      query.end = pos || doc.doc.getCursor(\"end\");\n      if (doc.doc.somethingSelected())\n        query.start = doc.doc.getCursor(\"start\");\n    }\n    var startPos = query.start || query.end;\n\n    if (doc.changed) {\n      if (doc.doc.lineCount() > bigDoc && allowFragments !== false &&\n          doc.changed.to - doc.changed.from < 100 &&\n          doc.changed.from <= startPos.line && doc.changed.to > query.end.line) {\n        files.push(getFragmentAround(doc, startPos, query.end));\n        query.file = \"#0\";\n        var offsetLines = files[0].offsetLines;\n        if (query.start != null) query.start = Pos(query.start.line - -offsetLines, query.start.ch);\n        query.end = Pos(query.end.line - offsetLines, query.end.ch);\n      } else {\n        files.push({type: \"full\",\n                    name: doc.name,\n                    text: docValue(ts, doc)});\n        query.file = doc.name;\n        doc.changed = null;\n      }\n    } else {\n      query.file = doc.name;\n    }\n    for (var name in ts.docs) {\n      var cur = ts.docs[name];\n      if (cur.changed && cur != doc) {\n        files.push({type: \"full\", name: cur.name, text: docValue(ts, cur)});\n        cur.changed = null;\n      }\n    }\n\n    return {query: query, files: files};\n  }\n\n  function getFragmentAround(data, start, end) {\n    var doc = data.doc;\n    var minIndent = null, minLine = null, endLine, tabSize = 4;\n    for (var p = start.line - 1, min = Math.max(0, p - 50); p >= min; --p) {\n      var line = doc.getLine(p), fn = line.search(/\\bfunction\\b/);\n      if (fn < 0) continue;\n      var indent = CodeMirror.countColumn(line, null, tabSize);\n      if (minIndent != null && minIndent <= indent) continue;\n      minIndent = indent;\n      minLine = p;\n    }\n    if (minLine == null) minLine = min;\n    var max = Math.min(doc.lastLine(), end.line + 20);\n    if (minIndent == null || minIndent == CodeMirror.countColumn(doc.getLine(start.line), null, tabSize))\n      endLine = max;\n    else for (endLine = end.line + 1; endLine < max; ++endLine) {\n      var indent = CodeMirror.countColumn(doc.getLine(endLine), null, tabSize);\n      if (indent <= minIndent) break;\n    }\n    var from = Pos(minLine, 0);\n\n    return {type: \"part\",\n            name: data.name,\n            offsetLines: from.line,\n            text: doc.getRange(from, Pos(endLine, 0))};\n  }\n\n  // Generic utilities\n\n  var cmpPos = CodeMirror.cmpPos;\n\n  function elt(tagname, cls /*, ... elts*/) {\n    var e = document.createElement(tagname);\n    if (cls) e.className = cls;\n    for (var i = 2; i < arguments.length; ++i) {\n      var elt = arguments[i];\n      if (typeof elt == \"string\") elt = document.createTextNode(elt);\n      e.appendChild(elt);\n    }\n    return e;\n  }\n\n  function dialog(cm, text, f) {\n    if (cm.openDialog)\n      cm.openDialog(text + \": <input type=text>\", f);\n    else\n      f(prompt(text, \"\"));\n  }\n\n  // Tooltips\n\n  function tempTooltip(cm, content) {\n    if (cm.state.ternTooltip) remove(cm.state.ternTooltip);\n    var where = cm.cursorCoords();\n    var tip = cm.state.ternTooltip = makeTooltip(where.right + 1, where.bottom, content);\n    function maybeClear() {\n      old = true;\n      if (!mouseOnTip) clear();\n    }\n    function clear() {\n      cm.state.ternTooltip = null;\n      if (!tip.parentNode) return;\n      cm.off(\"cursorActivity\", clear);\n      cm.off('blur', clear);\n      cm.off('scroll', clear);\n      fadeOut(tip);\n    }\n    var mouseOnTip = false, old = false;\n    CodeMirror.on(tip, \"mousemove\", function() { mouseOnTip = true; });\n    CodeMirror.on(tip, \"mouseout\", function(e) {\n      if (!CodeMirror.contains(tip, e.relatedTarget || e.toElement)) {\n        if (old) clear();\n        else mouseOnTip = false;\n      }\n    });\n    setTimeout(maybeClear, 1700);\n    cm.on(\"cursorActivity\", clear);\n    cm.on('blur', clear);\n    cm.on('scroll', clear);\n  }\n\n  function makeTooltip(x, y, content) {\n    var node = elt(\"div\", cls + \"tooltip\", content);\n    node.style.left = x + \"px\";\n    node.style.top = y + \"px\";\n    document.body.appendChild(node);\n    return node;\n  }\n\n  function remove(node) {\n    var p = node && node.parentNode;\n    if (p) p.removeChild(node);\n  }\n\n  function fadeOut(tooltip) {\n    tooltip.style.opacity = \"0\";\n    setTimeout(function() { remove(tooltip); }, 1100);\n  }\n\n  function showError(ts, cm, msg) {\n    if (ts.options.showError)\n      ts.options.showError(cm, msg);\n    else\n      tempTooltip(cm, String(msg));\n  }\n\n  function closeArgHints(ts) {\n    if (ts.activeArgHints) { remove(ts.activeArgHints); ts.activeArgHints = null; }\n  }\n\n  function docValue(ts, doc) {\n    var val = doc.doc.getValue();\n    if (ts.options.fileFilter) val = ts.options.fileFilter(val, doc.name, doc.doc);\n    return val;\n  }\n\n  // Worker wrapper\n\n  function WorkerServer(ts) {\n    var worker = ts.worker = new Worker(ts.options.workerScript);\n    worker.postMessage({type: \"init\",\n                        defs: ts.options.defs,\n                        plugins: ts.options.plugins,\n                        scripts: ts.options.workerDeps});\n    var msgId = 0, pending = {};\n\n    function send(data, c) {\n      if (c) {\n        data.id = ++msgId;\n        pending[msgId] = c;\n      }\n      worker.postMessage(data);\n    }\n    worker.onmessage = function(e) {\n      var data = e.data;\n      if (data.type == \"getFile\") {\n        getFile(ts, data.name, function(err, text) {\n          send({type: \"getFile\", err: String(err), text: text, id: data.id});\n        });\n      } else if (data.type == \"debug\") {\n        window.console.log(data.message);\n      } else if (data.id && pending[data.id]) {\n        pending[data.id](data.err, data.body);\n        delete pending[data.id];\n      }\n    };\n    worker.onerror = function(e) {\n      for (var id in pending) pending[id](e);\n      pending = {};\n    };\n\n    this.addFile = function(name, text) { send({type: \"add\", name: name, text: text}); };\n    this.delFile = function(name) { send({type: \"del\", name: name}); };\n    this.request = function(body, c) { send({type: \"req\", body: body}, c); };\n  }\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/tern/worker.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n// declare global: tern, server\n\nvar server;\n\nthis.onmessage = function(e) {\n  var data = e.data;\n  switch (data.type) {\n  case \"init\": return startServer(data.defs, data.plugins, data.scripts);\n  case \"add\": return server.addFile(data.name, data.text);\n  case \"del\": return server.delFile(data.name);\n  case \"req\": return server.request(data.body, function(err, reqData) {\n    postMessage({id: data.id, body: reqData, err: err && String(err)});\n  });\n  case \"getFile\":\n    var c = pending[data.id];\n    delete pending[data.id];\n    return c(data.err, data.text);\n  default: throw new Error(\"Unknown message type: \" + data.type);\n  }\n};\n\nvar nextId = 0, pending = {};\nfunction getFile(file, c) {\n  postMessage({type: \"getFile\", name: file, id: ++nextId});\n  pending[nextId] = c;\n}\n\nfunction startServer(defs, plugins, scripts) {\n  if (scripts) importScripts.apply(null, scripts);\n\n  server = new tern.Server({\n    getFile: getFile,\n    async: true,\n    defs: defs,\n    plugins: plugins\n  });\n}\n\nvar console = {\n  log: function(v) { postMessage({type: \"debug\", message: v}); }\n};\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/addon/wrap/hardwrap.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n\n  var Pos = CodeMirror.Pos;\n\n  function findParagraph(cm, pos, options) {\n    var startRE = options.paragraphStart || cm.getHelper(pos, \"paragraphStart\");\n    for (var start = pos.line, first = cm.firstLine(); start > first; --start) {\n      var line = cm.getLine(start);\n      if (startRE && startRE.test(line)) break;\n      if (!/\\S/.test(line)) { ++start; break; }\n    }\n    var endRE = options.paragraphEnd || cm.getHelper(pos, \"paragraphEnd\");\n    for (var end = pos.line + 1, last = cm.lastLine(); end <= last; ++end) {\n      var line = cm.getLine(end);\n      if (endRE && endRE.test(line)) { ++end; break; }\n      if (!/\\S/.test(line)) break;\n    }\n    return {from: start, to: end};\n  }\n\n  function findBreakPoint(text, column, wrapOn, killTrailingSpace) {\n    for (var at = column; at > 0; --at)\n      if (wrapOn.test(text.slice(at - 1, at + 1))) break;\n    if (at == 0) at = column;\n    var endOfText = at;\n    if (killTrailingSpace)\n      while (text.charAt(endOfText - 1) == \" \") --endOfText;\n    return {from: endOfText, to: at};\n  }\n\n  function wrapRange(cm, from, to, options) {\n    from = cm.clipPos(from); to = cm.clipPos(to);\n    var column = options.column || 80;\n    var wrapOn = options.wrapOn || /\\s\\S|-[^\\.\\d]/;\n    var killTrailing = options.killTrailingSpace !== false;\n    var changes = [], curLine = \"\", curNo = from.line;\n    var lines = cm.getRange(from, to, false);\n    if (!lines.length) return null;\n    var leadingSpace = lines[0].match(/^[ \\t]*/)[0];\n\n    for (var i = 0; i < lines.length; ++i) {\n      var text = lines[i], oldLen = curLine.length, spaceInserted = 0;\n      if (curLine && text && !wrapOn.test(curLine.charAt(curLine.length - 1) + text.charAt(0))) {\n        curLine += \" \";\n        spaceInserted = 1;\n      }\n      var spaceTrimmed = \"\";\n      if (i) {\n        spaceTrimmed = text.match(/^\\s*/)[0];\n        text = text.slice(spaceTrimmed.length);\n      }\n      curLine += text;\n      if (i) {\n        var firstBreak = curLine.length > column && leadingSpace == spaceTrimmed &&\n          findBreakPoint(curLine, column, wrapOn, killTrailing);\n        // If this isn't broken, or is broken at a different point, remove old break\n        if (!firstBreak || firstBreak.from != oldLen || firstBreak.to != oldLen + spaceInserted) {\n          changes.push({text: [spaceInserted ? \" \" : \"\"],\n                        from: Pos(curNo, oldLen),\n                        to: Pos(curNo + 1, spaceTrimmed.length)});\n        } else {\n          curLine = leadingSpace + text;\n          ++curNo;\n        }\n      }\n      while (curLine.length > column) {\n        var bp = findBreakPoint(curLine, column, wrapOn, killTrailing);\n        changes.push({text: [\"\", leadingSpace],\n                      from: Pos(curNo, bp.from),\n                      to: Pos(curNo, bp.to)});\n        curLine = leadingSpace + curLine.slice(bp.to);\n        ++curNo;\n      }\n    }\n    if (changes.length) cm.operation(function() {\n      for (var i = 0; i < changes.length; ++i) {\n        var change = changes[i];\n        cm.replaceRange(change.text, change.from, change.to);\n      }\n    });\n    return changes.length ? {from: changes[0].from, to: CodeMirror.changeEnd(changes[changes.length - 1])} : null;\n  }\n\n  CodeMirror.defineExtension(\"wrapParagraph\", function(pos, options) {\n    options = options || {};\n    if (!pos) pos = this.getCursor();\n    var para = findParagraph(this, pos, options);\n    return wrapRange(this, Pos(para.from, 0), Pos(para.to - 1), options);\n  });\n\n  CodeMirror.commands.wrapLines = function(cm) {\n    cm.operation(function() {\n      var ranges = cm.listSelections(), at = cm.lastLine() + 1;\n      for (var i = ranges.length - 1; i >= 0; i--) {\n        var range = ranges[i], span;\n        if (range.empty()) {\n          var para = findParagraph(cm, range.head, {});\n          span = {from: Pos(para.from, 0), to: Pos(para.to - 1)};\n        } else {\n          span = {from: range.from(), to: range.to()};\n        }\n        if (span.to.line >= at) continue;\n        at = span.from.line;\n        wrapRange(cm, span.from, span.to, {});\n      }\n    });\n  };\n\n  CodeMirror.defineExtension(\"wrapRange\", function(from, to, options) {\n    return wrapRange(this, from, to, options || {});\n  });\n\n  CodeMirror.defineExtension(\"wrapParagraphsInRange\", function(from, to, options) {\n    options = options || {};\n    var cm = this, paras = [];\n    for (var line = from.line; line <= to.line;) {\n      var para = findParagraph(cm, Pos(line, 0), options);\n      paras.push(para);\n      line = para.to;\n    }\n    var madeChange = false;\n    if (paras.length) cm.operation(function() {\n      for (var i = paras.length - 1; i >= 0; --i)\n        madeChange = madeChange || wrapRange(cm, Pos(paras[i].from, 0), Pos(paras[i].to - 1), options);\n    });\n    return madeChange;\n  });\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/bower.json",
    "content": "{\n  \"name\": \"codemirror\",\n  \"version\":\"5.0.0\",\n  \"main\": [\"lib/codemirror.js\", \"lib/codemirror.css\"],\n  \"ignore\": [\n    \"**/.*\",\n    \"node_modules\",\n    \"components\",\n    \"bin\",\n    \"demo\",\n    \"doc\",\n    \"test\",\n    \"index.html\",\n    \"package.json\"\n  ]\n}\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/lib/codemirror.css",
    "content": "/*!\n// CodeMirror v5.0, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n// This is CodeMirror (http://codemirror.net), a code editor\n// implemented in JavaScript on top of the browser's DOM.\n//\n// You can find some technical background for some of the code below\n// at http://marijnhaverbeke.nl/blog/#cm-internals .\n*/\n\n/* BASICS */\n\n.CodeMirror {\n  /* Set height, width, borders, and global font properties here */\n  font-family: monospace;\n  height: 300px;\n  color: black;\n}\n\n/* PADDING */\n\n.CodeMirror-lines {\n  padding: 4px 0; /* Vertical padding around content */\n}\n.CodeMirror pre {\n  padding: 0 4px; /* Horizontal padding of content */\n}\n\n.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {\n  background-color: white; /* The little square between H and V scrollbars */\n}\n\n/* GUTTER */\n\n.CodeMirror-gutters {\n  border-right: 1px solid #ddd;\n  background-color: #f7f7f7;\n  white-space: nowrap;\n}\n.CodeMirror-linenumbers {}\n.CodeMirror-linenumber {\n  padding: 0 3px 0 5px;\n  min-width: 20px;\n  text-align: right;\n  color: #999;\n  -moz-box-sizing: content-box;\n  box-sizing: content-box;\n}\n\n.CodeMirror-guttermarker { color: black; }\n.CodeMirror-guttermarker-subtle { color: #999; }\n\n/* CURSOR */\n\n.CodeMirror div.CodeMirror-cursor {\n  border-left: 1px solid black;\n}\n/* Shown when moving in bi-directional text */\n.CodeMirror div.CodeMirror-secondarycursor {\n  border-left: 1px solid silver;\n}\n.CodeMirror.cm-fat-cursor div.CodeMirror-cursor {\n  width: auto;\n  border: 0;\n  background: #7e7;\n}\n.CodeMirror.cm-fat-cursor div.CodeMirror-cursors {\n  z-index: 1;\n}\n\n.cm-animate-fat-cursor {\n  width: auto;\n  border: 0;\n  -webkit-animation: blink 1.06s steps(1) infinite;\n  -moz-animation: blink 1.06s steps(1) infinite;\n  animation: blink 1.06s steps(1) infinite;\n}\n@-moz-keyframes blink {\n  0% { background: #7e7; }\n  50% { background: none; }\n  100% { background: #7e7; }\n}\n@-webkit-keyframes blink {\n  0% { background: #7e7; }\n  50% { background: none; }\n  100% { background: #7e7; }\n}\n@keyframes blink {\n  0% { background: #7e7; }\n  50% { background: none; }\n  100% { background: #7e7; }\n}\n\n/* Can style cursor different in overwrite (non-insert) mode */\ndiv.CodeMirror-overwrite div.CodeMirror-cursor {}\n\n.cm-tab { display: inline-block; text-decoration: inherit; }\n\n.CodeMirror-ruler {\n  border-left: 1px solid #ccc;\n  position: absolute;\n}\n\n/* DEFAULT THEME */\n\n.cm-s-default .cm-keyword {color: #708;}\n.cm-s-default .cm-atom {color: #219;}\n.cm-s-default .cm-number {color: #164;}\n.cm-s-default .cm-def {color: #00f;}\n.cm-s-default .cm-variable,\n.cm-s-default .cm-punctuation,\n.cm-s-default .cm-property,\n.cm-s-default .cm-operator {}\n.cm-s-default .cm-variable-2 {color: #05a;}\n.cm-s-default .cm-variable-3 {color: #085;}\n.cm-s-default .cm-comment {color: #a50;}\n.cm-s-default .cm-string {color: #a11;}\n.cm-s-default .cm-string-2 {color: #f50;}\n.cm-s-default .cm-meta {color: #555;}\n.cm-s-default .cm-qualifier {color: #555;}\n.cm-s-default .cm-builtin {color: #30a;}\n.cm-s-default .cm-bracket {color: #997;}\n.cm-s-default .cm-tag {color: #170;}\n.cm-s-default .cm-attribute {color: #00c;}\n.cm-s-default .cm-header {color: blue;}\n.cm-s-default .cm-quote {color: #090;}\n.cm-s-default .cm-hr {color: #999;}\n.cm-s-default .cm-link {color: #00c;}\n\n.cm-negative {color: #d44;}\n.cm-positive {color: #292;}\n.cm-header, .cm-strong {font-weight: bold;}\n.cm-em {font-style: italic;}\n.cm-link {text-decoration: underline;}\n.cm-strikethrough {text-decoration: line-through;}\n\n.cm-s-default .cm-error {color: #f00;}\n.cm-invalidchar {color: #f00;}\n\n/* Default styles for common addons */\n\ndiv.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}\ndiv.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}\n.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }\n.CodeMirror-activeline-background {background: #e8f2ff;}\n\n/* STOP */\n\n/* The rest of this file contains styles related to the mechanics of\n   the editor. You probably shouldn't touch them. */\n\n.CodeMirror {\n  position: relative;\n  overflow: hidden;\n  background: white;\n}\n\n.CodeMirror-scroll {\n  overflow: scroll !important; /* Things will break if this is overridden */\n  /* 30px is the magic margin used to hide the element's real scrollbars */\n  /* See overflow: hidden in .CodeMirror */\n  margin-bottom: -30px; margin-right: -30px;\n  padding-bottom: 30px;\n  height: 100%;\n  outline: none; /* Prevent dragging from highlighting the element */\n  position: relative;\n  -moz-box-sizing: content-box;\n  box-sizing: content-box;\n}\n.CodeMirror-sizer {\n  position: relative;\n  border-right: 30px solid transparent;\n  -moz-box-sizing: content-box;\n  box-sizing: content-box;\n}\n\n/* The fake, visible scrollbars. Used to force redraw during scrolling\n   before actuall scrolling happens, thus preventing shaking and\n   flickering artifacts. */\n.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {\n  position: absolute;\n  z-index: 6;\n  display: none;\n}\n.CodeMirror-vscrollbar {\n  right: 0; top: 0;\n  overflow-x: hidden;\n  overflow-y: scroll;\n}\n.CodeMirror-hscrollbar {\n  bottom: 0; left: 0;\n  overflow-y: hidden;\n  overflow-x: scroll;\n}\n.CodeMirror-scrollbar-filler {\n  right: 0; bottom: 0;\n}\n.CodeMirror-gutter-filler {\n  left: 0; bottom: 0;\n}\n\n.CodeMirror-gutters {\n  position: absolute; left: 0; top: 0;\n  z-index: 3;\n}\n.CodeMirror-gutter {\n  white-space: normal;\n  height: 100%;\n  -moz-box-sizing: content-box;\n  box-sizing: content-box;\n  display: inline-block;\n  margin-bottom: -30px;\n  /* Hack to make IE7 behave */\n  *zoom:1;\n  *display:inline;\n}\n.CodeMirror-gutter-wrapper {\n  position: absolute;\n  z-index: 4;\n  height: 100%;\n}\n.CodeMirror-gutter-elt {\n  position: absolute;\n  cursor: default;\n  z-index: 4;\n}\n.CodeMirror-gutter-wrapper {\n  -webkit-user-select: none;\n  -moz-user-select: none;\n  user-select: none;\n}\n\n.CodeMirror-lines {\n  cursor: text;\n  min-height: 1px; /* prevents collapsing before first draw */\n}\n.CodeMirror pre {\n  /* Reset some styles that the rest of the page might have set */\n  -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;\n  border-width: 0;\n  background: transparent;\n  font-family: inherit;\n  font-size: inherit;\n  margin: 0;\n  white-space: pre;\n  word-wrap: normal;\n  line-height: inherit;\n  color: inherit;\n  z-index: 2;\n  position: relative;\n  overflow: visible;\n  -webkit-tap-highlight-color: transparent;\n}\n.CodeMirror-wrap pre {\n  word-wrap: break-word;\n  white-space: pre-wrap;\n  word-break: normal;\n}\n\n.CodeMirror-linebackground {\n  position: absolute;\n  left: 0; right: 0; top: 0; bottom: 0;\n  z-index: 0;\n}\n\n.CodeMirror-linewidget {\n  position: relative;\n  z-index: 2;\n  overflow: auto;\n}\n\n.CodeMirror-widget {}\n\n.CodeMirror-code {\n  outline: none;\n}\n\n.CodeMirror-measure {\n  position: absolute;\n  width: 100%;\n  height: 0;\n  overflow: hidden;\n  visibility: hidden;\n}\n.CodeMirror-measure pre { position: static; }\n\n.CodeMirror div.CodeMirror-cursor {\n  position: absolute;\n  border-right: none;\n  width: 0;\n}\n\ndiv.CodeMirror-cursors {\n  visibility: hidden;\n  position: relative;\n  z-index: 3;\n}\n.CodeMirror-focused div.CodeMirror-cursors {\n  visibility: visible;\n}\n\n.CodeMirror-selected { background: #d9d9d9; }\n.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }\n.CodeMirror-crosshair { cursor: crosshair; }\n.CodeMirror ::selection { background: #d7d4f0; }\n.CodeMirror ::-moz-selection { background: #d7d4f0; }\n\n.cm-searching {\n  background: #ffa;\n  background: rgba(255, 255, 0, .4);\n}\n\n/* IE7 hack to prevent it from returning funny offsetTops on the spans */\n.CodeMirror span { *vertical-align: text-bottom; }\n\n/* Used to force a border model for a node */\n.cm-force-border { padding-right: .1px; }\n\n@media print {\n  /* Hide the cursor when printing */\n  .CodeMirror div.CodeMirror-cursors {\n    visibility: hidden;\n  }\n}\n\n/* See issue #2901 */\n.cm-tab-wrap-hack:after { content: ''; }\n\n/* Help users use markselection to safely style text background */\nspan.CodeMirror-selectedtext { background: none; }\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/lib/codemirror.js",
    "content": "// CodeMirror v5.0, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n// This is CodeMirror (http://codemirror.net), a code editor\n// implemented in JavaScript on top of the browser's DOM.\n//\n// You can find some technical background for some of the code below\n// at http://marijnhaverbeke.nl/blog/#cm-internals .\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    module.exports = mod();\n  else if (typeof define == \"function\" && define.amd) // AMD\n    return define([], mod);\n  else // Plain browser env\n    this.CodeMirror = mod();\n})(function() {\n  \"use strict\";\n\n  // BROWSER SNIFFING\n\n  // Kludges for bugs and behavior differences that can't be feature\n  // detected are enabled based on userAgent etc sniffing.\n\n  var gecko = /gecko\\/\\d/i.test(navigator.userAgent);\n  var ie_upto10 = /MSIE \\d/.test(navigator.userAgent);\n  var ie_11up = /Trident\\/(?:[7-9]|\\d{2,})\\..*rv:(\\d+)/.exec(navigator.userAgent);\n  var ie = ie_upto10 || ie_11up;\n  var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : ie_11up[1]);\n  var webkit = /WebKit\\//.test(navigator.userAgent);\n  var qtwebkit = webkit && /Qt\\/\\d+\\.\\d+/.test(navigator.userAgent);\n  var chrome = /Chrome\\//.test(navigator.userAgent);\n  var presto = /Opera\\//.test(navigator.userAgent);\n  var safari = /Apple Computer/.test(navigator.vendor);\n  var mac_geMountainLion = /Mac OS X 1\\d\\D([8-9]|\\d\\d)\\D/.test(navigator.userAgent);\n  var phantom = /PhantomJS/.test(navigator.userAgent);\n\n  var ios = /AppleWebKit/.test(navigator.userAgent) && /Mobile\\/\\w+/.test(navigator.userAgent);\n  // This is woefully incomplete. Suggestions for alternative methods welcome.\n  var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(navigator.userAgent);\n  var mac = ios || /Mac/.test(navigator.platform);\n  var windows = /win/i.test(navigator.platform);\n\n  var presto_version = presto && navigator.userAgent.match(/Version\\/(\\d*\\.\\d*)/);\n  if (presto_version) presto_version = Number(presto_version[1]);\n  if (presto_version && presto_version >= 15) { presto = false; webkit = true; }\n  // Some browsers use the wrong event properties to signal cmd/ctrl on OS X\n  var flipCtrlCmd = mac && (qtwebkit || presto && (presto_version == null || presto_version < 12.11));\n  var captureRightClick = gecko || (ie && ie_version >= 9);\n\n  // Optimize some code when these features are not used.\n  var sawReadOnlySpans = false, sawCollapsedSpans = false;\n\n  // EDITOR CONSTRUCTOR\n\n  // A CodeMirror instance represents an editor. This is the object\n  // that user code is usually dealing with.\n\n  function CodeMirror(place, options) {\n    if (!(this instanceof CodeMirror)) return new CodeMirror(place, options);\n\n    this.options = options = options ? copyObj(options) : {};\n    // Determine effective options based on given values and defaults.\n    copyObj(defaults, options, false);\n    setGuttersForLineNumbers(options);\n\n    var doc = options.value;\n    if (typeof doc == \"string\") doc = new Doc(doc, options.mode);\n    this.doc = doc;\n\n    var input = new CodeMirror.inputStyles[options.inputStyle](this);\n    var display = this.display = new Display(place, doc, input);\n    display.wrapper.CodeMirror = this;\n    updateGutters(this);\n    themeChanged(this);\n    if (options.lineWrapping)\n      this.display.wrapper.className += \" CodeMirror-wrap\";\n    if (options.autofocus && !mobile) display.input.focus();\n    initScrollbars(this);\n\n    this.state = {\n      keyMaps: [],  // stores maps added by addKeyMap\n      overlays: [], // highlighting overlays, as added by addOverlay\n      modeGen: 0,   // bumped when mode/overlay changes, used to invalidate highlighting info\n      overwrite: false, focused: false,\n      suppressEdits: false, // used to disable editing during key handlers when in readOnly mode\n      pasteIncoming: false, cutIncoming: false, // help recognize paste/cut edits in input.poll\n      draggingText: false,\n      highlight: new Delayed(), // stores highlight worker timeout\n      keySeq: null  // Unfinished key sequence\n    };\n\n    var cm = this;\n\n    // Override magic textarea content restore that IE sometimes does\n    // on our hidden textarea on reload\n    if (ie && ie_version < 11) setTimeout(function() { cm.display.input.reset(true); }, 20);\n\n    registerEventHandlers(this);\n    ensureGlobalHandlers();\n\n    startOperation(this);\n    this.curOp.forceUpdate = true;\n    attachDoc(this, doc);\n\n    if ((options.autofocus && !mobile) || cm.hasFocus())\n      setTimeout(bind(onFocus, this), 20);\n    else\n      onBlur(this);\n\n    for (var opt in optionHandlers) if (optionHandlers.hasOwnProperty(opt))\n      optionHandlers[opt](this, options[opt], Init);\n    maybeUpdateLineNumberWidth(this);\n    if (options.finishInit) options.finishInit(this);\n    for (var i = 0; i < initHooks.length; ++i) initHooks[i](this);\n    endOperation(this);\n    // Suppress optimizelegibility in Webkit, since it breaks text\n    // measuring on line wrapping boundaries.\n    if (webkit && options.lineWrapping &&\n        getComputedStyle(display.lineDiv).textRendering == \"optimizelegibility\")\n      display.lineDiv.style.textRendering = \"auto\";\n  }\n\n  // DISPLAY CONSTRUCTOR\n\n  // The display handles the DOM integration, both for input reading\n  // and content drawing. It holds references to DOM nodes and\n  // display-related state.\n\n  function Display(place, doc, input) {\n    var d = this;\n    this.input = input;\n\n    // Covers bottom-right square when both scrollbars are present.\n    d.scrollbarFiller = elt(\"div\", null, \"CodeMirror-scrollbar-filler\");\n    d.scrollbarFiller.setAttribute(\"cm-not-content\", \"true\");\n    // Covers bottom of gutter when coverGutterNextToScrollbar is on\n    // and h scrollbar is present.\n    d.gutterFiller = elt(\"div\", null, \"CodeMirror-gutter-filler\");\n    d.gutterFiller.setAttribute(\"cm-not-content\", \"true\");\n    // Will contain the actual code, positioned to cover the viewport.\n    d.lineDiv = elt(\"div\", null, \"CodeMirror-code\");\n    // Elements are added to these to represent selection and cursors.\n    d.selectionDiv = elt(\"div\", null, null, \"position: relative; z-index: 1\");\n    d.cursorDiv = elt(\"div\", null, \"CodeMirror-cursors\");\n    // A visibility: hidden element used to find the size of things.\n    d.measure = elt(\"div\", null, \"CodeMirror-measure\");\n    // When lines outside of the viewport are measured, they are drawn in this.\n    d.lineMeasure = elt(\"div\", null, \"CodeMirror-measure\");\n    // Wraps everything that needs to exist inside the vertically-padded coordinate system\n    d.lineSpace = elt(\"div\", [d.measure, d.lineMeasure, d.selectionDiv, d.cursorDiv, d.lineDiv],\n                      null, \"position: relative; outline: none\");\n    // Moved around its parent to cover visible view.\n    d.mover = elt(\"div\", [elt(\"div\", [d.lineSpace], \"CodeMirror-lines\")], null, \"position: relative\");\n    // Set to the height of the document, allowing scrolling.\n    d.sizer = elt(\"div\", [d.mover], \"CodeMirror-sizer\");\n    d.sizerWidth = null;\n    // Behavior of elts with overflow: auto and padding is\n    // inconsistent across browsers. This is used to ensure the\n    // scrollable area is big enough.\n    d.heightForcer = elt(\"div\", null, null, \"position: absolute; height: \" + scrollerGap + \"px; width: 1px;\");\n    // Will contain the gutters, if any.\n    d.gutters = elt(\"div\", null, \"CodeMirror-gutters\");\n    d.lineGutter = null;\n    // Actual scrollable element.\n    d.scroller = elt(\"div\", [d.sizer, d.heightForcer, d.gutters], \"CodeMirror-scroll\");\n    d.scroller.setAttribute(\"tabIndex\", \"-1\");\n    // The element in which the editor lives.\n    d.wrapper = elt(\"div\", [d.scrollbarFiller, d.gutterFiller, d.scroller], \"CodeMirror\");\n\n    // Work around IE7 z-index bug (not perfect, hence IE7 not really being supported)\n    if (ie && ie_version < 8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; }\n    if (!webkit && !(gecko && mobile)) d.scroller.draggable = true;\n\n    if (place) {\n      if (place.appendChild) place.appendChild(d.wrapper);\n      else place(d.wrapper);\n    }\n\n    // Current rendered range (may be bigger than the view window).\n    d.viewFrom = d.viewTo = doc.first;\n    d.reportedViewFrom = d.reportedViewTo = doc.first;\n    // Information about the rendered lines.\n    d.view = [];\n    d.renderedView = null;\n    // Holds info about a single rendered line when it was rendered\n    // for measurement, while not in view.\n    d.externalMeasured = null;\n    // Empty space (in pixels) above the view\n    d.viewOffset = 0;\n    d.lastWrapHeight = d.lastWrapWidth = 0;\n    d.updateLineNumbers = null;\n\n    d.nativeBarWidth = d.barHeight = d.barWidth = 0;\n    d.scrollbarsClipped = false;\n\n    // Used to only resize the line number gutter when necessary (when\n    // the amount of lines crosses a boundary that makes its width change)\n    d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null;\n    // Set to true when a non-horizontal-scrolling line widget is\n    // added. As an optimization, line widget aligning is skipped when\n    // this is false.\n    d.alignWidgets = false;\n\n    d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;\n\n    // Tracks the maximum line length so that the horizontal scrollbar\n    // can be kept static when scrolling.\n    d.maxLine = null;\n    d.maxLineLength = 0;\n    d.maxLineChanged = false;\n\n    // Used for measuring wheel scrolling granularity\n    d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null;\n\n    // True when shift is held down.\n    d.shift = false;\n\n    // Used to track whether anything happened since the context menu\n    // was opened.\n    d.selForContextMenu = null;\n\n    d.activeTouch = null;\n\n    input.init(d);\n  }\n\n  // STATE UPDATES\n\n  // Used to get the editor into a consistent state again when options change.\n\n  function loadMode(cm) {\n    cm.doc.mode = CodeMirror.getMode(cm.options, cm.doc.modeOption);\n    resetModeState(cm);\n  }\n\n  function resetModeState(cm) {\n    cm.doc.iter(function(line) {\n      if (line.stateAfter) line.stateAfter = null;\n      if (line.styles) line.styles = null;\n    });\n    cm.doc.frontier = cm.doc.first;\n    startWorker(cm, 100);\n    cm.state.modeGen++;\n    if (cm.curOp) regChange(cm);\n  }\n\n  function wrappingChanged(cm) {\n    if (cm.options.lineWrapping) {\n      addClass(cm.display.wrapper, \"CodeMirror-wrap\");\n      cm.display.sizer.style.minWidth = \"\";\n      cm.display.sizerWidth = null;\n    } else {\n      rmClass(cm.display.wrapper, \"CodeMirror-wrap\");\n      findMaxLine(cm);\n    }\n    estimateLineHeights(cm);\n    regChange(cm);\n    clearCaches(cm);\n    setTimeout(function(){updateScrollbars(cm);}, 100);\n  }\n\n  // Returns a function that estimates the height of a line, to use as\n  // first approximation until the line becomes visible (and is thus\n  // properly measurable).\n  function estimateHeight(cm) {\n    var th = textHeight(cm.display), wrapping = cm.options.lineWrapping;\n    var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3);\n    return function(line) {\n      if (lineIsHidden(cm.doc, line)) return 0;\n\n      var widgetsHeight = 0;\n      if (line.widgets) for (var i = 0; i < line.widgets.length; i++) {\n        if (line.widgets[i].height) widgetsHeight += line.widgets[i].height;\n      }\n\n      if (wrapping)\n        return widgetsHeight + (Math.ceil(line.text.length / perLine) || 1) * th;\n      else\n        return widgetsHeight + th;\n    };\n  }\n\n  function estimateLineHeights(cm) {\n    var doc = cm.doc, est = estimateHeight(cm);\n    doc.iter(function(line) {\n      var estHeight = est(line);\n      if (estHeight != line.height) updateLineHeight(line, estHeight);\n    });\n  }\n\n  function themeChanged(cm) {\n    cm.display.wrapper.className = cm.display.wrapper.className.replace(/\\s*cm-s-\\S+/g, \"\") +\n      cm.options.theme.replace(/(^|\\s)\\s*/g, \" cm-s-\");\n    clearCaches(cm);\n  }\n\n  function guttersChanged(cm) {\n    updateGutters(cm);\n    regChange(cm);\n    setTimeout(function(){alignHorizontally(cm);}, 20);\n  }\n\n  // Rebuild the gutter elements, ensure the margin to the left of the\n  // code matches their width.\n  function updateGutters(cm) {\n    var gutters = cm.display.gutters, specs = cm.options.gutters;\n    removeChildren(gutters);\n    for (var i = 0; i < specs.length; ++i) {\n      var gutterClass = specs[i];\n      var gElt = gutters.appendChild(elt(\"div\", null, \"CodeMirror-gutter \" + gutterClass));\n      if (gutterClass == \"CodeMirror-linenumbers\") {\n        cm.display.lineGutter = gElt;\n        gElt.style.width = (cm.display.lineNumWidth || 1) + \"px\";\n      }\n    }\n    gutters.style.display = i ? \"\" : \"none\";\n    updateGutterSpace(cm);\n  }\n\n  function updateGutterSpace(cm) {\n    var width = cm.display.gutters.offsetWidth;\n    cm.display.sizer.style.marginLeft = width + \"px\";\n  }\n\n  // Compute the character length of a line, taking into account\n  // collapsed ranges (see markText) that might hide parts, and join\n  // other lines onto it.\n  function lineLength(line) {\n    if (line.height == 0) return 0;\n    var len = line.text.length, merged, cur = line;\n    while (merged = collapsedSpanAtStart(cur)) {\n      var found = merged.find(0, true);\n      cur = found.from.line;\n      len += found.from.ch - found.to.ch;\n    }\n    cur = line;\n    while (merged = collapsedSpanAtEnd(cur)) {\n      var found = merged.find(0, true);\n      len -= cur.text.length - found.from.ch;\n      cur = found.to.line;\n      len += cur.text.length - found.to.ch;\n    }\n    return len;\n  }\n\n  // Find the longest line in the document.\n  function findMaxLine(cm) {\n    var d = cm.display, doc = cm.doc;\n    d.maxLine = getLine(doc, doc.first);\n    d.maxLineLength = lineLength(d.maxLine);\n    d.maxLineChanged = true;\n    doc.iter(function(line) {\n      var len = lineLength(line);\n      if (len > d.maxLineLength) {\n        d.maxLineLength = len;\n        d.maxLine = line;\n      }\n    });\n  }\n\n  // Make sure the gutters options contains the element\n  // \"CodeMirror-linenumbers\" when the lineNumbers option is true.\n  function setGuttersForLineNumbers(options) {\n    var found = indexOf(options.gutters, \"CodeMirror-linenumbers\");\n    if (found == -1 && options.lineNumbers) {\n      options.gutters = options.gutters.concat([\"CodeMirror-linenumbers\"]);\n    } else if (found > -1 && !options.lineNumbers) {\n      options.gutters = options.gutters.slice(0);\n      options.gutters.splice(found, 1);\n    }\n  }\n\n  // SCROLLBARS\n\n  // Prepare DOM reads needed to update the scrollbars. Done in one\n  // shot to minimize update/measure roundtrips.\n  function measureForScrollbars(cm) {\n    var d = cm.display, gutterW = d.gutters.offsetWidth;\n    var docH = Math.round(cm.doc.height + paddingVert(cm.display));\n    return {\n      clientHeight: d.scroller.clientHeight,\n      viewHeight: d.wrapper.clientHeight,\n      scrollWidth: d.scroller.scrollWidth, clientWidth: d.scroller.clientWidth,\n      viewWidth: d.wrapper.clientWidth,\n      barLeft: cm.options.fixedGutter ? gutterW : 0,\n      docHeight: docH,\n      scrollHeight: docH + scrollGap(cm) + d.barHeight,\n      nativeBarWidth: d.nativeBarWidth,\n      gutterWidth: gutterW\n    };\n  }\n\n  function NativeScrollbars(place, scroll, cm) {\n    this.cm = cm;\n    var vert = this.vert = elt(\"div\", [elt(\"div\", null, null, \"min-width: 1px\")], \"CodeMirror-vscrollbar\");\n    var horiz = this.horiz = elt(\"div\", [elt(\"div\", null, null, \"height: 100%; min-height: 1px\")], \"CodeMirror-hscrollbar\");\n    place(vert); place(horiz);\n\n    on(vert, \"scroll\", function() {\n      if (vert.clientHeight) scroll(vert.scrollTop, \"vertical\");\n    });\n    on(horiz, \"scroll\", function() {\n      if (horiz.clientWidth) scroll(horiz.scrollLeft, \"horizontal\");\n    });\n\n    this.checkedOverlay = false;\n    // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).\n    if (ie && ie_version < 8) this.horiz.style.minHeight = this.vert.style.minWidth = \"18px\";\n  }\n\n  NativeScrollbars.prototype = copyObj({\n    update: function(measure) {\n      var needsH = measure.scrollWidth > measure.clientWidth + 1;\n      var needsV = measure.scrollHeight > measure.clientHeight + 1;\n      var sWidth = measure.nativeBarWidth;\n\n      if (needsV) {\n        this.vert.style.display = \"block\";\n        this.vert.style.bottom = needsH ? sWidth + \"px\" : \"0\";\n        var totalHeight = measure.viewHeight - (needsH ? sWidth : 0);\n        // A bug in IE8 can cause this value to be negative, so guard it.\n        this.vert.firstChild.style.height =\n          Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + \"px\";\n      } else {\n        this.vert.style.display = \"\";\n        this.vert.firstChild.style.height = \"0\";\n      }\n\n      if (needsH) {\n        this.horiz.style.display = \"block\";\n        this.horiz.style.right = needsV ? sWidth + \"px\" : \"0\";\n        this.horiz.style.left = measure.barLeft + \"px\";\n        var totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0);\n        this.horiz.firstChild.style.width =\n          (measure.scrollWidth - measure.clientWidth + totalWidth) + \"px\";\n      } else {\n        this.horiz.style.display = \"\";\n        this.horiz.firstChild.style.width = \"0\";\n      }\n\n      if (!this.checkedOverlay && measure.clientHeight > 0) {\n        if (sWidth == 0) this.overlayHack();\n        this.checkedOverlay = true;\n      }\n\n      return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0};\n    },\n    setScrollLeft: function(pos) {\n      if (this.horiz.scrollLeft != pos) this.horiz.scrollLeft = pos;\n    },\n    setScrollTop: function(pos) {\n      if (this.vert.scrollTop != pos) this.vert.scrollTop = pos;\n    },\n    overlayHack: function() {\n      var w = mac && !mac_geMountainLion ? \"12px\" : \"18px\";\n      this.horiz.style.minHeight = this.vert.style.minWidth = w;\n      var self = this;\n      var barMouseDown = function(e) {\n        if (e_target(e) != self.vert && e_target(e) != self.horiz)\n          operation(self.cm, onMouseDown)(e);\n      };\n      on(this.vert, \"mousedown\", barMouseDown);\n      on(this.horiz, \"mousedown\", barMouseDown);\n    },\n    clear: function() {\n      var parent = this.horiz.parentNode;\n      parent.removeChild(this.horiz);\n      parent.removeChild(this.vert);\n    }\n  }, NativeScrollbars.prototype);\n\n  function NullScrollbars() {}\n\n  NullScrollbars.prototype = copyObj({\n    update: function() { return {bottom: 0, right: 0}; },\n    setScrollLeft: function() {},\n    setScrollTop: function() {},\n    clear: function() {}\n  }, NullScrollbars.prototype);\n\n  CodeMirror.scrollbarModel = {\"native\": NativeScrollbars, \"null\": NullScrollbars};\n\n  function initScrollbars(cm) {\n    if (cm.display.scrollbars) {\n      cm.display.scrollbars.clear();\n      if (cm.display.scrollbars.addClass)\n        rmClass(cm.display.wrapper, cm.display.scrollbars.addClass);\n    }\n\n    cm.display.scrollbars = new CodeMirror.scrollbarModel[cm.options.scrollbarStyle](function(node) {\n      cm.display.wrapper.insertBefore(node, cm.display.scrollbarFiller);\n      // Prevent clicks in the scrollbars from killing focus\n      on(node, \"mousedown\", function() {\n        if (cm.state.focused) setTimeout(function() { cm.display.input.focus(); }, 0);\n      });\n      node.setAttribute(\"cm-not-content\", \"true\");\n    }, function(pos, axis) {\n      if (axis == \"horizontal\") setScrollLeft(cm, pos);\n      else setScrollTop(cm, pos);\n    }, cm);\n    if (cm.display.scrollbars.addClass)\n      addClass(cm.display.wrapper, cm.display.scrollbars.addClass);\n  }\n\n  function updateScrollbars(cm, measure) {\n    if (!measure) measure = measureForScrollbars(cm);\n    var startWidth = cm.display.barWidth, startHeight = cm.display.barHeight;\n    updateScrollbarsInner(cm, measure);\n    for (var i = 0; i < 4 && startWidth != cm.display.barWidth || startHeight != cm.display.barHeight; i++) {\n      if (startWidth != cm.display.barWidth && cm.options.lineWrapping)\n        updateHeightsInViewport(cm);\n      updateScrollbarsInner(cm, measureForScrollbars(cm));\n      startWidth = cm.display.barWidth; startHeight = cm.display.barHeight;\n    }\n  }\n\n  // Re-synchronize the fake scrollbars with the actual size of the\n  // content.\n  function updateScrollbarsInner(cm, measure) {\n    var d = cm.display;\n    var sizes = d.scrollbars.update(measure);\n\n    d.sizer.style.paddingRight = (d.barWidth = sizes.right) + \"px\";\n    d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + \"px\";\n\n    if (sizes.right && sizes.bottom) {\n      d.scrollbarFiller.style.display = \"block\";\n      d.scrollbarFiller.style.height = sizes.bottom + \"px\";\n      d.scrollbarFiller.style.width = sizes.right + \"px\";\n    } else d.scrollbarFiller.style.display = \"\";\n    if (sizes.bottom && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) {\n      d.gutterFiller.style.display = \"block\";\n      d.gutterFiller.style.height = sizes.bottom + \"px\";\n      d.gutterFiller.style.width = measure.gutterWidth + \"px\";\n    } else d.gutterFiller.style.display = \"\";\n  }\n\n  // Compute the lines that are visible in a given viewport (defaults\n  // the the current scroll position). viewport may contain top,\n  // height, and ensure (see op.scrollToPos) properties.\n  function visibleLines(display, doc, viewport) {\n    var top = viewport && viewport.top != null ? Math.max(0, viewport.top) : display.scroller.scrollTop;\n    top = Math.floor(top - paddingTop(display));\n    var bottom = viewport && viewport.bottom != null ? viewport.bottom : top + display.wrapper.clientHeight;\n\n    var from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom);\n    // Ensure is a {from: {line, ch}, to: {line, ch}} object, and\n    // forces those lines into the viewport (if possible).\n    if (viewport && viewport.ensure) {\n      var ensureFrom = viewport.ensure.from.line, ensureTo = viewport.ensure.to.line;\n      if (ensureFrom < from) {\n        from = ensureFrom;\n        to = lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight);\n      } else if (Math.min(ensureTo, doc.lastLine()) >= to) {\n        from = lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight);\n        to = ensureTo;\n      }\n    }\n    return {from: from, to: Math.max(to, from + 1)};\n  }\n\n  // LINE NUMBERS\n\n  // Re-align line numbers and gutter marks to compensate for\n  // horizontal scrolling.\n  function alignHorizontally(cm) {\n    var display = cm.display, view = display.view;\n    if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) return;\n    var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft;\n    var gutterW = display.gutters.offsetWidth, left = comp + \"px\";\n    for (var i = 0; i < view.length; i++) if (!view[i].hidden) {\n      if (cm.options.fixedGutter && view[i].gutter)\n        view[i].gutter.style.left = left;\n      var align = view[i].alignable;\n      if (align) for (var j = 0; j < align.length; j++)\n        align[j].style.left = left;\n    }\n    if (cm.options.fixedGutter)\n      display.gutters.style.left = (comp + gutterW) + \"px\";\n  }\n\n  // Used to ensure that the line number gutter is still the right\n  // size for the current document size. Returns true when an update\n  // is needed.\n  function maybeUpdateLineNumberWidth(cm) {\n    if (!cm.options.lineNumbers) return false;\n    var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display;\n    if (last.length != display.lineNumChars) {\n      var test = display.measure.appendChild(elt(\"div\", [elt(\"div\", last)],\n                                                 \"CodeMirror-linenumber CodeMirror-gutter-elt\"));\n      var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW;\n      display.lineGutter.style.width = \"\";\n      display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding);\n      display.lineNumWidth = display.lineNumInnerWidth + padding;\n      display.lineNumChars = display.lineNumInnerWidth ? last.length : -1;\n      display.lineGutter.style.width = display.lineNumWidth + \"px\";\n      updateGutterSpace(cm);\n      return true;\n    }\n    return false;\n  }\n\n  function lineNumberFor(options, i) {\n    return String(options.lineNumberFormatter(i + options.firstLineNumber));\n  }\n\n  // Computes display.scroller.scrollLeft + display.gutters.offsetWidth,\n  // but using getBoundingClientRect to get a sub-pixel-accurate\n  // result.\n  function compensateForHScroll(display) {\n    return display.scroller.getBoundingClientRect().left - display.sizer.getBoundingClientRect().left;\n  }\n\n  // DISPLAY DRAWING\n\n  function DisplayUpdate(cm, viewport, force) {\n    var display = cm.display;\n\n    this.viewport = viewport;\n    // Store some values that we'll need later (but don't want to force a relayout for)\n    this.visible = visibleLines(display, cm.doc, viewport);\n    this.editorIsHidden = !display.wrapper.offsetWidth;\n    this.wrapperHeight = display.wrapper.clientHeight;\n    this.wrapperWidth = display.wrapper.clientWidth;\n    this.oldDisplayWidth = displayWidth(cm);\n    this.force = force;\n    this.dims = getDimensions(cm);\n    this.events = [];\n  }\n\n  DisplayUpdate.prototype.signal = function(emitter, type) {\n    if (hasHandler(emitter, type))\n      this.events.push(arguments);\n  };\n  DisplayUpdate.prototype.finish = function() {\n    for (var i = 0; i < this.events.length; i++)\n      signal.apply(null, this.events[i]);\n  };\n\n  function maybeClipScrollbars(cm) {\n    var display = cm.display;\n    if (!display.scrollbarsClipped && display.scroller.offsetWidth) {\n      display.nativeBarWidth = display.scroller.offsetWidth - display.scroller.clientWidth;\n      display.heightForcer.style.height = scrollGap(cm) + \"px\";\n      display.sizer.style.marginBottom = -display.nativeBarWidth + \"px\";\n      display.sizer.style.borderRightWidth = scrollGap(cm) + \"px\";\n      display.scrollbarsClipped = true;\n    }\n  }\n\n  // Does the actual updating of the line display. Bails out\n  // (returning false) when there is nothing to be done and forced is\n  // false.\n  function updateDisplayIfNeeded(cm, update) {\n    var display = cm.display, doc = cm.doc;\n\n    if (update.editorIsHidden) {\n      resetView(cm);\n      return false;\n    }\n\n    // Bail out if the visible area is already rendered and nothing changed.\n    if (!update.force &&\n        update.visible.from >= display.viewFrom && update.visible.to <= display.viewTo &&\n        (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo) &&\n        display.renderedView == display.view && countDirtyView(cm) == 0)\n      return false;\n\n    if (maybeUpdateLineNumberWidth(cm)) {\n      resetView(cm);\n      update.dims = getDimensions(cm);\n    }\n\n    // Compute a suitable new viewport (from & to)\n    var end = doc.first + doc.size;\n    var from = Math.max(update.visible.from - cm.options.viewportMargin, doc.first);\n    var to = Math.min(end, update.visible.to + cm.options.viewportMargin);\n    if (display.viewFrom < from && from - display.viewFrom < 20) from = Math.max(doc.first, display.viewFrom);\n    if (display.viewTo > to && display.viewTo - to < 20) to = Math.min(end, display.viewTo);\n    if (sawCollapsedSpans) {\n      from = visualLineNo(cm.doc, from);\n      to = visualLineEndNo(cm.doc, to);\n    }\n\n    var different = from != display.viewFrom || to != display.viewTo ||\n      display.lastWrapHeight != update.wrapperHeight || display.lastWrapWidth != update.wrapperWidth;\n    adjustView(cm, from, to);\n\n    display.viewOffset = heightAtLine(getLine(cm.doc, display.viewFrom));\n    // Position the mover div to align with the current scroll position\n    cm.display.mover.style.top = display.viewOffset + \"px\";\n\n    var toUpdate = countDirtyView(cm);\n    if (!different && toUpdate == 0 && !update.force && display.renderedView == display.view &&\n        (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo))\n      return false;\n\n    // For big changes, we hide the enclosing element during the\n    // update, since that speeds up the operations on most browsers.\n    var focused = activeElt();\n    if (toUpdate > 4) display.lineDiv.style.display = \"none\";\n    patchDisplay(cm, display.updateLineNumbers, update.dims);\n    if (toUpdate > 4) display.lineDiv.style.display = \"\";\n    display.renderedView = display.view;\n    // There might have been a widget with a focused element that got\n    // hidden or updated, if so re-focus it.\n    if (focused && activeElt() != focused && focused.offsetHeight) focused.focus();\n\n    // Prevent selection and cursors from interfering with the scroll\n    // width and height.\n    removeChildren(display.cursorDiv);\n    removeChildren(display.selectionDiv);\n    display.gutters.style.height = 0;\n\n    if (different) {\n      display.lastWrapHeight = update.wrapperHeight;\n      display.lastWrapWidth = update.wrapperWidth;\n      startWorker(cm, 400);\n    }\n\n    display.updateLineNumbers = null;\n\n    return true;\n  }\n\n  function postUpdateDisplay(cm, update) {\n    var force = update.force, viewport = update.viewport;\n    for (var first = true;; first = false) {\n      if (first && cm.options.lineWrapping && update.oldDisplayWidth != displayWidth(cm)) {\n        force = true;\n      } else {\n        force = false;\n        // Clip forced viewport to actual scrollable area.\n        if (viewport && viewport.top != null)\n          viewport = {top: Math.min(cm.doc.height + paddingVert(cm.display) - displayHeight(cm), viewport.top)};\n        // Updated line heights might result in the drawn area not\n        // actually covering the viewport. Keep looping until it does.\n        update.visible = visibleLines(cm.display, cm.doc, viewport);\n        if (update.visible.from >= cm.display.viewFrom && update.visible.to <= cm.display.viewTo)\n          break;\n      }\n      if (!updateDisplayIfNeeded(cm, update)) break;\n      updateHeightsInViewport(cm);\n      var barMeasure = measureForScrollbars(cm);\n      updateSelection(cm);\n      setDocumentHeight(cm, barMeasure);\n      updateScrollbars(cm, barMeasure);\n    }\n\n    update.signal(cm, \"update\", cm);\n    if (cm.display.viewFrom != cm.display.reportedViewFrom || cm.display.viewTo != cm.display.reportedViewTo) {\n      update.signal(cm, \"viewportChange\", cm, cm.display.viewFrom, cm.display.viewTo);\n      cm.display.reportedViewFrom = cm.display.viewFrom; cm.display.reportedViewTo = cm.display.viewTo;\n    }\n  }\n\n  function updateDisplaySimple(cm, viewport) {\n    var update = new DisplayUpdate(cm, viewport);\n    if (updateDisplayIfNeeded(cm, update)) {\n      updateHeightsInViewport(cm);\n      postUpdateDisplay(cm, update);\n      var barMeasure = measureForScrollbars(cm);\n      updateSelection(cm);\n      setDocumentHeight(cm, barMeasure);\n      updateScrollbars(cm, barMeasure);\n      update.finish();\n    }\n  }\n\n  function setDocumentHeight(cm, measure) {\n    cm.display.sizer.style.minHeight = measure.docHeight + \"px\";\n    var total = measure.docHeight + cm.display.barHeight;\n    cm.display.heightForcer.style.top = total + \"px\";\n    cm.display.gutters.style.height = Math.max(total + scrollGap(cm), measure.clientHeight) + \"px\";\n  }\n\n  // Read the actual heights of the rendered lines, and update their\n  // stored heights to match.\n  function updateHeightsInViewport(cm) {\n    var display = cm.display;\n    var prevBottom = display.lineDiv.offsetTop;\n    for (var i = 0; i < display.view.length; i++) {\n      var cur = display.view[i], height;\n      if (cur.hidden) continue;\n      if (ie && ie_version < 8) {\n        var bot = cur.node.offsetTop + cur.node.offsetHeight;\n        height = bot - prevBottom;\n        prevBottom = bot;\n      } else {\n        var box = cur.node.getBoundingClientRect();\n        height = box.bottom - box.top;\n      }\n      var diff = cur.line.height - height;\n      if (height < 2) height = textHeight(display);\n      if (diff > .001 || diff < -.001) {\n        updateLineHeight(cur.line, height);\n        updateWidgetHeight(cur.line);\n        if (cur.rest) for (var j = 0; j < cur.rest.length; j++)\n          updateWidgetHeight(cur.rest[j]);\n      }\n    }\n  }\n\n  // Read and store the height of line widgets associated with the\n  // given line.\n  function updateWidgetHeight(line) {\n    if (line.widgets) for (var i = 0; i < line.widgets.length; ++i)\n      line.widgets[i].height = line.widgets[i].node.offsetHeight;\n  }\n\n  // Do a bulk-read of the DOM positions and sizes needed to draw the\n  // view, so that we don't interleave reading and writing to the DOM.\n  function getDimensions(cm) {\n    var d = cm.display, left = {}, width = {};\n    var gutterLeft = d.gutters.clientLeft;\n    for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) {\n      left[cm.options.gutters[i]] = n.offsetLeft + n.clientLeft + gutterLeft;\n      width[cm.options.gutters[i]] = n.clientWidth;\n    }\n    return {fixedPos: compensateForHScroll(d),\n            gutterTotalWidth: d.gutters.offsetWidth,\n            gutterLeft: left,\n            gutterWidth: width,\n            wrapperWidth: d.wrapper.clientWidth};\n  }\n\n  // Sync the actual display DOM structure with display.view, removing\n  // nodes for lines that are no longer in view, and creating the ones\n  // that are not there yet, and updating the ones that are out of\n  // date.\n  function patchDisplay(cm, updateNumbersFrom, dims) {\n    var display = cm.display, lineNumbers = cm.options.lineNumbers;\n    var container = display.lineDiv, cur = container.firstChild;\n\n    function rm(node) {\n      var next = node.nextSibling;\n      // Works around a throw-scroll bug in OS X Webkit\n      if (webkit && mac && cm.display.currentWheelTarget == node)\n        node.style.display = \"none\";\n      else\n        node.parentNode.removeChild(node);\n      return next;\n    }\n\n    var view = display.view, lineN = display.viewFrom;\n    // Loop over the elements in the view, syncing cur (the DOM nodes\n    // in display.lineDiv) with the view as we go.\n    for (var i = 0; i < view.length; i++) {\n      var lineView = view[i];\n      if (lineView.hidden) {\n      } else if (!lineView.node || lineView.node.parentNode != container) { // Not drawn yet\n        var node = buildLineElement(cm, lineView, lineN, dims);\n        container.insertBefore(node, cur);\n      } else { // Already drawn\n        while (cur != lineView.node) cur = rm(cur);\n        var updateNumber = lineNumbers && updateNumbersFrom != null &&\n          updateNumbersFrom <= lineN && lineView.lineNumber;\n        if (lineView.changes) {\n          if (indexOf(lineView.changes, \"gutter\") > -1) updateNumber = false;\n          updateLineForChanges(cm, lineView, lineN, dims);\n        }\n        if (updateNumber) {\n          removeChildren(lineView.lineNumber);\n          lineView.lineNumber.appendChild(document.createTextNode(lineNumberFor(cm.options, lineN)));\n        }\n        cur = lineView.node.nextSibling;\n      }\n      lineN += lineView.size;\n    }\n    while (cur) cur = rm(cur);\n  }\n\n  // When an aspect of a line changes, a string is added to\n  // lineView.changes. This updates the relevant part of the line's\n  // DOM structure.\n  function updateLineForChanges(cm, lineView, lineN, dims) {\n    for (var j = 0; j < lineView.changes.length; j++) {\n      var type = lineView.changes[j];\n      if (type == \"text\") updateLineText(cm, lineView);\n      else if (type == \"gutter\") updateLineGutter(cm, lineView, lineN, dims);\n      else if (type == \"class\") updateLineClasses(lineView);\n      else if (type == \"widget\") updateLineWidgets(cm, lineView, dims);\n    }\n    lineView.changes = null;\n  }\n\n  // Lines with gutter elements, widgets or a background class need to\n  // be wrapped, and have the extra elements added to the wrapper div\n  function ensureLineWrapped(lineView) {\n    if (lineView.node == lineView.text) {\n      lineView.node = elt(\"div\", null, null, \"position: relative\");\n      if (lineView.text.parentNode)\n        lineView.text.parentNode.replaceChild(lineView.node, lineView.text);\n      lineView.node.appendChild(lineView.text);\n      if (ie && ie_version < 8) lineView.node.style.zIndex = 2;\n    }\n    return lineView.node;\n  }\n\n  function updateLineBackground(lineView) {\n    var cls = lineView.bgClass ? lineView.bgClass + \" \" + (lineView.line.bgClass || \"\") : lineView.line.bgClass;\n    if (cls) cls += \" CodeMirror-linebackground\";\n    if (lineView.background) {\n      if (cls) lineView.background.className = cls;\n      else { lineView.background.parentNode.removeChild(lineView.background); lineView.background = null; }\n    } else if (cls) {\n      var wrap = ensureLineWrapped(lineView);\n      lineView.background = wrap.insertBefore(elt(\"div\", null, cls), wrap.firstChild);\n    }\n  }\n\n  // Wrapper around buildLineContent which will reuse the structure\n  // in display.externalMeasured when possible.\n  function getLineContent(cm, lineView) {\n    var ext = cm.display.externalMeasured;\n    if (ext && ext.line == lineView.line) {\n      cm.display.externalMeasured = null;\n      lineView.measure = ext.measure;\n      return ext.built;\n    }\n    return buildLineContent(cm, lineView);\n  }\n\n  // Redraw the line's text. Interacts with the background and text\n  // classes because the mode may output tokens that influence these\n  // classes.\n  function updateLineText(cm, lineView) {\n    var cls = lineView.text.className;\n    var built = getLineContent(cm, lineView);\n    if (lineView.text == lineView.node) lineView.node = built.pre;\n    lineView.text.parentNode.replaceChild(built.pre, lineView.text);\n    lineView.text = built.pre;\n    if (built.bgClass != lineView.bgClass || built.textClass != lineView.textClass) {\n      lineView.bgClass = built.bgClass;\n      lineView.textClass = built.textClass;\n      updateLineClasses(lineView);\n    } else if (cls) {\n      lineView.text.className = cls;\n    }\n  }\n\n  function updateLineClasses(lineView) {\n    updateLineBackground(lineView);\n    if (lineView.line.wrapClass)\n      ensureLineWrapped(lineView).className = lineView.line.wrapClass;\n    else if (lineView.node != lineView.text)\n      lineView.node.className = \"\";\n    var textClass = lineView.textClass ? lineView.textClass + \" \" + (lineView.line.textClass || \"\") : lineView.line.textClass;\n    lineView.text.className = textClass || \"\";\n  }\n\n  function updateLineGutter(cm, lineView, lineN, dims) {\n    if (lineView.gutter) {\n      lineView.node.removeChild(lineView.gutter);\n      lineView.gutter = null;\n    }\n    var markers = lineView.line.gutterMarkers;\n    if (cm.options.lineNumbers || markers) {\n      var wrap = ensureLineWrapped(lineView);\n      var gutterWrap = lineView.gutter = elt(\"div\", null, \"CodeMirror-gutter-wrapper\", \"left: \" +\n                                             (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) +\n                                             \"px; width: \" + dims.gutterTotalWidth + \"px\");\n      cm.display.input.setUneditable(gutterWrap);\n      wrap.insertBefore(gutterWrap, lineView.text);\n      if (lineView.line.gutterClass)\n        gutterWrap.className += \" \" + lineView.line.gutterClass;\n      if (cm.options.lineNumbers && (!markers || !markers[\"CodeMirror-linenumbers\"]))\n        lineView.lineNumber = gutterWrap.appendChild(\n          elt(\"div\", lineNumberFor(cm.options, lineN),\n              \"CodeMirror-linenumber CodeMirror-gutter-elt\",\n              \"left: \" + dims.gutterLeft[\"CodeMirror-linenumbers\"] + \"px; width: \"\n              + cm.display.lineNumInnerWidth + \"px\"));\n      if (markers) for (var k = 0; k < cm.options.gutters.length; ++k) {\n        var id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id];\n        if (found)\n          gutterWrap.appendChild(elt(\"div\", [found], \"CodeMirror-gutter-elt\", \"left: \" +\n                                     dims.gutterLeft[id] + \"px; width: \" + dims.gutterWidth[id] + \"px\"));\n      }\n    }\n  }\n\n  function updateLineWidgets(cm, lineView, dims) {\n    if (lineView.alignable) lineView.alignable = null;\n    for (var node = lineView.node.firstChild, next; node; node = next) {\n      var next = node.nextSibling;\n      if (node.className == \"CodeMirror-linewidget\")\n        lineView.node.removeChild(node);\n    }\n    insertLineWidgets(cm, lineView, dims);\n  }\n\n  // Build a line's DOM representation from scratch\n  function buildLineElement(cm, lineView, lineN, dims) {\n    var built = getLineContent(cm, lineView);\n    lineView.text = lineView.node = built.pre;\n    if (built.bgClass) lineView.bgClass = built.bgClass;\n    if (built.textClass) lineView.textClass = built.textClass;\n\n    updateLineClasses(lineView);\n    updateLineGutter(cm, lineView, lineN, dims);\n    insertLineWidgets(cm, lineView, dims);\n    return lineView.node;\n  }\n\n  // A lineView may contain multiple logical lines (when merged by\n  // collapsed spans). The widgets for all of them need to be drawn.\n  function insertLineWidgets(cm, lineView, dims) {\n    insertLineWidgetsFor(cm, lineView.line, lineView, dims, true);\n    if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++)\n      insertLineWidgetsFor(cm, lineView.rest[i], lineView, dims, false);\n  }\n\n  function insertLineWidgetsFor(cm, line, lineView, dims, allowAbove) {\n    if (!line.widgets) return;\n    var wrap = ensureLineWrapped(lineView);\n    for (var i = 0, ws = line.widgets; i < ws.length; ++i) {\n      var widget = ws[i], node = elt(\"div\", [widget.node], \"CodeMirror-linewidget\");\n      if (!widget.handleMouseEvents) node.setAttribute(\"cm-ignore-events\", \"true\");\n      positionLineWidget(widget, node, lineView, dims);\n      cm.display.input.setUneditable(node);\n      if (allowAbove && widget.above)\n        wrap.insertBefore(node, lineView.gutter || lineView.text);\n      else\n        wrap.appendChild(node);\n      signalLater(widget, \"redraw\");\n    }\n  }\n\n  function positionLineWidget(widget, node, lineView, dims) {\n    if (widget.noHScroll) {\n      (lineView.alignable || (lineView.alignable = [])).push(node);\n      var width = dims.wrapperWidth;\n      node.style.left = dims.fixedPos + \"px\";\n      if (!widget.coverGutter) {\n        width -= dims.gutterTotalWidth;\n        node.style.paddingLeft = dims.gutterTotalWidth + \"px\";\n      }\n      node.style.width = width + \"px\";\n    }\n    if (widget.coverGutter) {\n      node.style.zIndex = 5;\n      node.style.position = \"relative\";\n      if (!widget.noHScroll) node.style.marginLeft = -dims.gutterTotalWidth + \"px\";\n    }\n  }\n\n  // POSITION OBJECT\n\n  // A Pos instance represents a position within the text.\n  var Pos = CodeMirror.Pos = function(line, ch) {\n    if (!(this instanceof Pos)) return new Pos(line, ch);\n    this.line = line; this.ch = ch;\n  };\n\n  // Compare two positions, return 0 if they are the same, a negative\n  // number when a is less, and a positive number otherwise.\n  var cmp = CodeMirror.cmpPos = function(a, b) { return a.line - b.line || a.ch - b.ch; };\n\n  function copyPos(x) {return Pos(x.line, x.ch);}\n  function maxPos(a, b) { return cmp(a, b) < 0 ? b : a; }\n  function minPos(a, b) { return cmp(a, b) < 0 ? a : b; }\n\n  // INPUT HANDLING\n\n  function ensureFocus(cm) {\n    if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm); }\n  }\n\n  function isReadOnly(cm) {\n    return cm.options.readOnly || cm.doc.cantEdit;\n  }\n\n  // This will be set to an array of strings when copying, so that,\n  // when pasting, we know what kind of selections the copied text\n  // was made out of.\n  var lastCopied = null;\n\n  function applyTextInput(cm, inserted, deleted, sel) {\n    var doc = cm.doc;\n    cm.display.shift = false;\n    if (!sel) sel = doc.sel;\n\n    var textLines = splitLines(inserted), multiPaste = null;\n    // When pasing N lines into N selections, insert one line per selection\n    if (cm.state.pasteIncoming && sel.ranges.length > 1) {\n      if (lastCopied && lastCopied.join(\"\\n\") == inserted)\n        multiPaste = sel.ranges.length % lastCopied.length == 0 && map(lastCopied, splitLines);\n      else if (textLines.length == sel.ranges.length)\n        multiPaste = map(textLines, function(l) { return [l]; });\n    }\n\n    // Normal behavior is to insert the new text into every selection\n    for (var i = sel.ranges.length - 1; i >= 0; i--) {\n      var range = sel.ranges[i];\n      var from = range.from(), to = range.to();\n      if (range.empty()) {\n        if (deleted && deleted > 0) // Handle deletion\n          from = Pos(from.line, from.ch - deleted);\n        else if (cm.state.overwrite && !cm.state.pasteIncoming) // Handle overwrite\n          to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length));\n      }\n      var updateInput = cm.curOp.updateInput;\n      var changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i % multiPaste.length] : textLines,\n                         origin: cm.state.pasteIncoming ? \"paste\" : cm.state.cutIncoming ? \"cut\" : \"+input\"};\n      makeChange(cm.doc, changeEvent);\n      signalLater(cm, \"inputRead\", cm, changeEvent);\n      // When an 'electric' character is inserted, immediately trigger a reindent\n      if (inserted && !cm.state.pasteIncoming && cm.options.electricChars &&\n          cm.options.smartIndent && range.head.ch < 100 &&\n          (!i || sel.ranges[i - 1].head.line != range.head.line)) {\n        var mode = cm.getModeAt(range.head);\n        var end = changeEnd(changeEvent);\n        if (mode.electricChars) {\n          for (var j = 0; j < mode.electricChars.length; j++)\n            if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) {\n              indentLine(cm, end.line, \"smart\");\n              break;\n            }\n        } else if (mode.electricInput) {\n          if (mode.electricInput.test(getLine(doc, end.line).text.slice(0, end.ch)))\n            indentLine(cm, end.line, \"smart\");\n        }\n      }\n    }\n    ensureCursorVisible(cm);\n    cm.curOp.updateInput = updateInput;\n    cm.curOp.typing = true;\n    cm.state.pasteIncoming = cm.state.cutIncoming = false;\n  }\n\n  function copyableRanges(cm) {\n    var text = [], ranges = [];\n    for (var i = 0; i < cm.doc.sel.ranges.length; i++) {\n      var line = cm.doc.sel.ranges[i].head.line;\n      var lineRange = {anchor: Pos(line, 0), head: Pos(line + 1, 0)};\n      ranges.push(lineRange);\n      text.push(cm.getRange(lineRange.anchor, lineRange.head));\n    }\n    return {text: text, ranges: ranges};\n  }\n\n  function disableBrowserMagic(field) {\n    field.setAttribute(\"autocorrect\", \"off\");\n    field.setAttribute(\"autocapitalize\", \"off\");\n    field.setAttribute(\"spellcheck\", \"false\");\n  }\n\n  // TEXTAREA INPUT STYLE\n\n  function TextareaInput(cm) {\n    this.cm = cm;\n    // See input.poll and input.reset\n    this.prevInput = \"\";\n\n    // Flag that indicates whether we expect input to appear real soon\n    // now (after some event like 'keypress' or 'input') and are\n    // polling intensively.\n    this.pollingFast = false;\n    // Self-resetting timeout for the poller\n    this.polling = new Delayed();\n    // Tracks when input.reset has punted to just putting a short\n    // string into the textarea instead of the full selection.\n    this.inaccurateSelection = false;\n    // Used to work around IE issue with selection being forgotten when focus moves away from textarea\n    this.hasSelection = false;\n  };\n\n  function hiddenTextarea() {\n    var te = elt(\"textarea\", null, null, \"position: absolute; padding: 0; width: 1px; height: 1em; outline: none\");\n    var div = elt(\"div\", [te], null, \"overflow: hidden; position: relative; width: 3px; height: 0px;\");\n    // The textarea is kept positioned near the cursor to prevent the\n    // fact that it'll be scrolled into view on input from scrolling\n    // our fake cursor out of view. On webkit, when wrap=off, paste is\n    // very slow. So make the area wide instead.\n    if (webkit) te.style.width = \"1000px\";\n    else te.setAttribute(\"wrap\", \"off\");\n    // If border: 0; -- iOS fails to open keyboard (issue #1287)\n    if (ios) te.style.border = \"1px solid black\";\n    disableBrowserMagic(te);\n    return div;\n  }\n\n  TextareaInput.prototype = copyObj({\n    init: function(display) {\n      var input = this, cm = this.cm;\n\n      // Wraps and hides input textarea\n      var div = this.wrapper = hiddenTextarea();\n      // The semihidden textarea that is focused when the editor is\n      // focused, and receives input.\n      var te = this.textarea = div.firstChild;\n      display.wrapper.insertBefore(div, display.wrapper.firstChild);\n\n      // Needed to hide big blue blinking cursor on Mobile Safari (doesn't seem to work in iOS 8 anymore)\n      if (ios) te.style.width = \"0px\";\n\n      on(te, \"input\", function() {\n        if (ie && ie_version >= 9 && input.hasSelection) input.hasSelection = null;\n        input.poll();\n      });\n\n      on(te, \"paste\", function() {\n        // Workaround for webkit bug https://bugs.webkit.org/show_bug.cgi?id=90206\n        // Add a char to the end of textarea before paste occur so that\n        // selection doesn't span to the end of textarea.\n        if (webkit && !cm.state.fakedLastChar && !(new Date - cm.state.lastMiddleDown < 200)) {\n          var start = te.selectionStart, end = te.selectionEnd;\n          te.value += \"$\";\n          // The selection end needs to be set before the start, otherwise there\n          // can be an intermediate non-empty selection between the two, which\n          // can override the middle-click paste buffer on linux and cause the\n          // wrong thing to get pasted.\n          te.selectionEnd = end;\n          te.selectionStart = start;\n          cm.state.fakedLastChar = true;\n        }\n        cm.state.pasteIncoming = true;\n        input.fastPoll();\n      });\n\n      function prepareCopyCut(e) {\n        if (cm.somethingSelected()) {\n          lastCopied = cm.getSelections();\n          if (input.inaccurateSelection) {\n            input.prevInput = \"\";\n            input.inaccurateSelection = false;\n            te.value = lastCopied.join(\"\\n\");\n            selectInput(te);\n          }\n        } else {\n          var ranges = copyableRanges(cm);\n          lastCopied = ranges.text;\n          if (e.type == \"cut\") {\n            cm.setSelections(ranges.ranges, null, sel_dontScroll);\n          } else {\n            input.prevInput = \"\";\n            te.value = ranges.text.join(\"\\n\");\n            selectInput(te);\n          }\n        }\n        if (e.type == \"cut\") cm.state.cutIncoming = true;\n      }\n      on(te, \"cut\", prepareCopyCut);\n      on(te, \"copy\", prepareCopyCut);\n\n      on(display.scroller, \"paste\", function(e) {\n        if (eventInWidget(display, e)) return;\n        cm.state.pasteIncoming = true;\n        input.focus();\n      });\n\n      // Prevent normal selection in the editor (we handle our own)\n      on(display.lineSpace, \"selectstart\", function(e) {\n        if (!eventInWidget(display, e)) e_preventDefault(e);\n      });\n    },\n\n    prepareSelection: function() {\n      // Redraw the selection and/or cursor\n      var cm = this.cm, display = cm.display, doc = cm.doc;\n      var result = prepareSelection(cm);\n\n      // Move the hidden textarea near the cursor to prevent scrolling artifacts\n      if (cm.options.moveInputWithCursor) {\n        var headPos = cursorCoords(cm, doc.sel.primary().head, \"div\");\n        var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect();\n        result.teTop = Math.max(0, Math.min(display.wrapper.clientHeight - 10,\n                                            headPos.top + lineOff.top - wrapOff.top));\n        result.teLeft = Math.max(0, Math.min(display.wrapper.clientWidth - 10,\n                                             headPos.left + lineOff.left - wrapOff.left));\n      }\n\n      return result;\n    },\n\n    showSelection: function(drawn) {\n      var cm = this.cm, display = cm.display;\n      removeChildrenAndAdd(display.cursorDiv, drawn.cursors);\n      removeChildrenAndAdd(display.selectionDiv, drawn.selection);\n      if (drawn.teTop != null) {\n        this.wrapper.style.top = drawn.teTop + \"px\";\n        this.wrapper.style.left = drawn.teLeft + \"px\";\n      }\n    },\n\n    // Reset the input to correspond to the selection (or to be empty,\n    // when not typing and nothing is selected)\n    reset: function(typing) {\n      if (this.contextMenuPending) return;\n      var minimal, selected, cm = this.cm, doc = cm.doc;\n      if (cm.somethingSelected()) {\n        this.prevInput = \"\";\n        var range = doc.sel.primary();\n        minimal = hasCopyEvent &&\n          (range.to().line - range.from().line > 100 || (selected = cm.getSelection()).length > 1000);\n        var content = minimal ? \"-\" : selected || cm.getSelection();\n        this.textarea.value = content;\n        if (cm.state.focused) selectInput(this.textarea);\n        if (ie && ie_version >= 9) this.hasSelection = content;\n      } else if (!typing) {\n        this.prevInput = this.textarea.value = \"\";\n        if (ie && ie_version >= 9) this.hasSelection = null;\n      }\n      this.inaccurateSelection = minimal;\n    },\n\n    getField: function() { return this.textarea; },\n\n    supportsTouch: function() { return false; },\n\n    focus: function() {\n      if (this.cm.options.readOnly != \"nocursor\" && (!mobile || activeElt() != this.textarea)) {\n        try { this.textarea.focus(); }\n        catch (e) {} // IE8 will throw if the textarea is display: none or not in DOM\n      }\n    },\n\n    blur: function() { this.textarea.blur(); },\n\n    resetPosition: function() {\n      this.wrapper.style.top = this.wrapper.style.left = 0;\n    },\n\n    receivedFocus: function() { this.slowPoll(); },\n\n    // Poll for input changes, using the normal rate of polling. This\n    // runs as long as the editor is focused.\n    slowPoll: function() {\n      var input = this;\n      if (input.pollingFast) return;\n      input.polling.set(this.cm.options.pollInterval, function() {\n        input.poll();\n        if (input.cm.state.focused) input.slowPoll();\n      });\n    },\n\n    // When an event has just come in that is likely to add or change\n    // something in the input textarea, we poll faster, to ensure that\n    // the change appears on the screen quickly.\n    fastPoll: function() {\n      var missed = false, input = this;\n      input.pollingFast = true;\n      function p() {\n        var changed = input.poll();\n        if (!changed && !missed) {missed = true; input.polling.set(60, p);}\n        else {input.pollingFast = false; input.slowPoll();}\n      }\n      input.polling.set(20, p);\n    },\n\n    // Read input from the textarea, and update the document to match.\n    // When something is selected, it is present in the textarea, and\n    // selected (unless it is huge, in which case a placeholder is\n    // used). When nothing is selected, the cursor sits after previously\n    // seen text (can be empty), which is stored in prevInput (we must\n    // not reset the textarea when typing, because that breaks IME).\n    poll: function() {\n      var cm = this.cm, input = this.textarea, prevInput = this.prevInput;\n      // Since this is called a *lot*, try to bail out as cheaply as\n      // possible when it is clear that nothing happened. hasSelection\n      // will be the case when there is a lot of text in the textarea,\n      // in which case reading its value would be expensive.\n      if (!cm.state.focused || (hasSelection(input) && !prevInput) ||\n          isReadOnly(cm) || cm.options.disableInput || cm.state.keySeq)\n        return false;\n      // See paste handler for more on the fakedLastChar kludge\n      if (cm.state.pasteIncoming && cm.state.fakedLastChar) {\n        input.value = input.value.substring(0, input.value.length - 1);\n        cm.state.fakedLastChar = false;\n      }\n      var text = input.value;\n      // If nothing changed, bail.\n      if (text == prevInput && !cm.somethingSelected()) return false;\n      // Work around nonsensical selection resetting in IE9/10, and\n      // inexplicable appearance of private area unicode characters on\n      // some key combos in Mac (#2689).\n      if (ie && ie_version >= 9 && this.hasSelection === text ||\n          mac && /[\\uf700-\\uf7ff]/.test(text)) {\n        cm.display.input.reset();\n        return false;\n      }\n\n      if (text.charCodeAt(0) == 0x200b && cm.doc.sel == cm.display.selForContextMenu && !prevInput)\n        prevInput = \"\\u200b\";\n      // Find the part of the input that is actually new\n      var same = 0, l = Math.min(prevInput.length, text.length);\n      while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) ++same;\n\n      var self = this;\n      runInOp(cm, function() {\n        applyTextInput(cm, text.slice(same), prevInput.length - same);\n\n        // Don't leave long text in the textarea, since it makes further polling slow\n        if (text.length > 1000 || text.indexOf(\"\\n\") > -1) input.value = self.prevInput = \"\";\n        else self.prevInput = text;\n      });\n      return true;\n    },\n\n    ensurePolled: function() {\n      if (this.pollingFast && this.poll()) this.pollingFast = false;\n    },\n\n    onKeyPress: function() {\n      if (ie && ie_version >= 9) this.hasSelection = null;\n      this.fastPoll();\n    },\n\n    onContextMenu: function(e) {\n      var input = this, cm = input.cm, display = cm.display, te = input.textarea;\n      var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop;\n      if (!pos || presto) return; // Opera is difficult.\n\n      // Reset the current text selection only if the click is done outside of the selection\n      // and 'resetSelectionOnContextMenu' option is true.\n      var reset = cm.options.resetSelectionOnContextMenu;\n      if (reset && cm.doc.sel.contains(pos) == -1)\n        operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll);\n\n      var oldCSS = te.style.cssText;\n      input.wrapper.style.position = \"absolute\";\n      te.style.cssText = \"position: fixed; width: 30px; height: 30px; top: \" + (e.clientY - 5) +\n        \"px; left: \" + (e.clientX - 5) + \"px; z-index: 1000; background: \" +\n        (ie ? \"rgba(255, 255, 255, .05)\" : \"transparent\") +\n        \"; outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);\";\n      if (webkit) var oldScrollY = window.scrollY; // Work around Chrome issue (#2712)\n      display.input.focus();\n      if (webkit) window.scrollTo(null, oldScrollY);\n      display.input.reset();\n      // Adds \"Select all\" to context menu in FF\n      if (!cm.somethingSelected()) te.value = input.prevInput = \" \";\n      input.contextMenuPending = true;\n      display.selForContextMenu = cm.doc.sel;\n      clearTimeout(display.detectingSelectAll);\n\n      // Select-all will be greyed out if there's nothing to select, so\n      // this adds a zero-width space so that we can later check whether\n      // it got selected.\n      function prepareSelectAllHack() {\n        if (te.selectionStart != null) {\n          var selected = cm.somethingSelected();\n          var extval = te.value = \"\\u200b\" + (selected ? te.value : \"\");\n          input.prevInput = selected ? \"\" : \"\\u200b\";\n          te.selectionStart = 1; te.selectionEnd = extval.length;\n          // Re-set this, in case some other handler touched the\n          // selection in the meantime.\n          display.selForContextMenu = cm.doc.sel;\n        }\n      }\n      function rehide() {\n        input.contextMenuPending = false;\n        input.wrapper.style.position = \"relative\";\n        te.style.cssText = oldCSS;\n        if (ie && ie_version < 9) display.scrollbars.setScrollTop(display.scroller.scrollTop = scrollPos);\n\n        // Try to detect the user choosing select-all\n        if (te.selectionStart != null) {\n          if (!ie || (ie && ie_version < 9)) prepareSelectAllHack();\n          var i = 0, poll = function() {\n            if (display.selForContextMenu == cm.doc.sel && te.selectionStart == 0)\n              operation(cm, commands.selectAll)(cm);\n            else if (i++ < 10) display.detectingSelectAll = setTimeout(poll, 500);\n            else display.input.reset();\n          };\n          display.detectingSelectAll = setTimeout(poll, 200);\n        }\n      }\n\n      if (ie && ie_version >= 9) prepareSelectAllHack();\n      if (captureRightClick) {\n        e_stop(e);\n        var mouseup = function() {\n          off(window, \"mouseup\", mouseup);\n          setTimeout(rehide, 20);\n        };\n        on(window, \"mouseup\", mouseup);\n      } else {\n        setTimeout(rehide, 50);\n      }\n    },\n\n    setUneditable: nothing,\n\n    needsContentAttribute: false\n  }, TextareaInput.prototype);\n\n  // CONTENTEDITABLE INPUT STYLE\n\n  function ContentEditableInput(cm) {\n    this.cm = cm;\n    this.lastAnchorNode = this.lastAnchorOffset = this.lastFocusNode = this.lastFocusOffset = null;\n    this.polling = new Delayed();\n  }\n\n  ContentEditableInput.prototype = copyObj({\n    init: function(display) {\n      var input = this, cm = input.cm;\n      var div = input.div = display.lineDiv;\n      div.contentEditable = \"true\";\n      disableBrowserMagic(div);\n\n      on(div, \"paste\", function(e) {\n        var pasted = e.clipboardData && e.clipboardData.getData(\"text/plain\");\n        if (pasted) {\n          e.preventDefault();\n          cm.replaceSelection(pasted, null, \"paste\");\n        }\n      });\n\n      on(div, \"compositionstart\", function(e) {\n        var data = e.data;\n        input.composing = {sel: cm.doc.sel, data: data, startData: data};\n        if (!data) return;\n        var prim = cm.doc.sel.primary();\n        var line = cm.getLine(prim.head.line);\n        var found = line.indexOf(data, Math.max(0, prim.head.ch - data.length));\n        if (found > -1 && found <= prim.head.ch)\n          input.composing.sel = simpleSelection(Pos(prim.head.line, found),\n                                                Pos(prim.head.line, found + data.length));\n      });\n      on(div, \"compositionupdate\", function(e) {\n        input.composing.data = e.data;\n      });\n      on(div, \"compositionend\", function(e) {\n        var ours = input.composing;\n        if (!ours) return;\n        if (e.data != ours.startData && !/\\u200b/.test(e.data))\n          ours.data = e.data;\n        // Need a small delay to prevent other code (input event,\n        // selection polling) from doing damage when fired right after\n        // compositionend.\n        setTimeout(function() {\n          if (!ours.handled)\n            input.applyComposition(ours);\n          if (input.composing == ours)\n            input.composing = null;\n        }, 50);\n      });\n\n      on(div, \"touchstart\", function() {\n        input.forceCompositionEnd();\n      });\n\n      on(div, \"input\", function() {\n        if (input.composing) return;\n        if (!input.pollContent())\n          runInOp(input.cm, function() {regChange(cm);});\n      });\n\n      function onCopyCut(e) {\n        if (cm.somethingSelected()) {\n          lastCopied = cm.getSelections();\n          if (e.type == \"cut\") cm.replaceSelection(\"\", null, \"cut\");\n        } else {\n          var ranges = copyableRanges(cm);\n          lastCopied = ranges.text;\n          if (e.type == \"cut\") {\n            cm.operation(function() {\n              cm.setSelections(ranges.ranges, 0, sel_dontScroll);\n              cm.replaceSelection(\"\", null, \"cut\");\n            });\n          }\n        }\n        // iOS exposes the clipboard API, but seems to discard content inserted into it\n        if (e.clipboardData && !ios) {\n          e.preventDefault();\n          e.clipboardData.clearData();\n          e.clipboardData.setData(\"text/plain\", lastCopied.join(\"\\n\"));\n        } else {\n          // Old-fashioned briefly-focus-a-textarea hack\n          var kludge = hiddenTextarea(), te = kludge.firstChild;\n          cm.display.lineSpace.insertBefore(kludge, cm.display.lineSpace.firstChild);\n          te.value = lastCopied.join(\"\\n\");\n          var hadFocus = document.activeElement;\n          selectInput(te);\n          setTimeout(function() {\n            cm.display.lineSpace.removeChild(kludge);\n            hadFocus.focus();\n          }, 50);\n        }\n      }\n      on(div, \"copy\", onCopyCut);\n      on(div, \"cut\", onCopyCut);\n    },\n\n    prepareSelection: function() {\n      var result = prepareSelection(this.cm, false);\n      result.focus = this.cm.state.focused;\n      return result;\n    },\n\n    showSelection: function(info) {\n      if (!info || !this.cm.display.view.length) return;\n      if (info.focus) this.showPrimarySelection();\n      this.showMultipleSelections(info);\n    },\n\n    showPrimarySelection: function() {\n      var sel = window.getSelection(), prim = this.cm.doc.sel.primary();\n      var curAnchor = domToPos(this.cm, sel.anchorNode, sel.anchorOffset);\n      var curFocus = domToPos(this.cm, sel.focusNode, sel.focusOffset);\n      if (curAnchor && !curAnchor.bad && curFocus && !curFocus.bad &&\n          cmp(minPos(curAnchor, curFocus), prim.from()) == 0 &&\n          cmp(maxPos(curAnchor, curFocus), prim.to()) == 0)\n        return;\n\n      var start = posToDOM(this.cm, prim.from());\n      var end = posToDOM(this.cm, prim.to());\n      if (!start && !end) return;\n\n      var view = this.cm.display.view;\n      var old = sel.rangeCount && sel.getRangeAt(0);\n      if (!start) {\n        start = {node: view[0].measure.map[2], offset: 0};\n      } else if (!end) { // FIXME dangerously hacky\n        var measure = view[view.length - 1].measure;\n        var map = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map;\n        end = {node: map[map.length - 1], offset: map[map.length - 2] - map[map.length - 3]};\n      }\n\n      try { var rng = range(start.node, start.offset, end.offset, end.node); }\n      catch(e) {} // Our model of the DOM might be outdated, in which case the range we try to set can be impossible\n      if (rng) {\n        sel.removeAllRanges();\n        sel.addRange(rng);\n        if (old && sel.anchorNode == null) sel.addRange(old);\n      }\n      this.rememberSelection();\n    },\n\n    showMultipleSelections: function(info) {\n      removeChildrenAndAdd(this.cm.display.cursorDiv, info.cursors);\n      removeChildrenAndAdd(this.cm.display.selectionDiv, info.selection);\n    },\n\n    rememberSelection: function() {\n      var sel = window.getSelection();\n      this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset;\n      this.lastFocusNode = sel.focusNode; this.lastFocusOffset = sel.focusOffset;\n    },\n\n    selectionInEditor: function() {\n      var sel = window.getSelection();\n      if (!sel.rangeCount) return false;\n      var node = sel.getRangeAt(0).commonAncestorContainer;\n      return contains(this.div, node);\n    },\n\n    focus: function() {\n      if (this.cm.options.readOnly != \"nocursor\") this.div.focus();\n    },\n    blur: function() { this.div.blur(); },\n    getField: function() { return this.div; },\n\n    supportsTouch: function() { return true; },\n\n    receivedFocus: function() {\n      var input = this;\n      if (this.selectionInEditor())\n        this.pollSelection();\n      else\n        runInOp(this.cm, function() { input.cm.curOp.selectionChanged = true; });\n\n      function poll() {\n        if (input.cm.state.focused) {\n          input.pollSelection();\n          input.polling.set(input.cm.options.pollInterval, poll);\n        }\n      }\n      this.polling.set(this.cm.options.pollInterval, poll);\n    },\n\n    pollSelection: function() {\n      if (this.composing) return;\n\n      var sel = window.getSelection(), cm = this.cm;\n      if (sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset ||\n          sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset) {\n        this.rememberSelection();\n        var anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset);\n        var head = domToPos(cm, sel.focusNode, sel.focusOffset);\n        if (anchor && head) runInOp(cm, function() {\n          setSelection(cm.doc, simpleSelection(anchor, head), sel_dontScroll);\n          if (anchor.bad || head.bad) cm.curOp.selectionChanged = true;\n        });\n      }\n    },\n\n    pollContent: function() {\n      var cm = this.cm, display = cm.display, sel = cm.doc.sel.primary();\n      var from = sel.from(), to = sel.to();\n      if (from.line < display.viewFrom || to.line > display.viewTo - 1) return false;\n\n      var fromIndex;\n      if (from.line == display.viewFrom || (fromIndex = findViewIndex(cm, from.line)) == 0) {\n        var fromLine = lineNo(display.view[0].line);\n        var fromNode = display.view[0].node;\n      } else {\n        var fromLine = lineNo(display.view[fromIndex].line);\n        var fromNode = display.view[fromIndex - 1].node.nextSibling;\n      }\n      var toIndex = findViewIndex(cm, to.line);\n      if (toIndex == display.view.length - 1) {\n        var toLine = display.viewTo - 1;\n        var toNode = display.view[toIndex].node;\n      } else {\n        var toLine = lineNo(display.view[toIndex + 1].line) - 1;\n        var toNode = display.view[toIndex + 1].node.previousSibling;\n      }\n\n      var newText = splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine));\n      var oldText = getBetween(cm.doc, Pos(fromLine, 0), Pos(toLine, getLine(cm.doc, toLine).text.length));\n      while (newText.length > 1 && oldText.length > 1) {\n        if (lst(newText) == lst(oldText)) { newText.pop(); oldText.pop(); toLine--; }\n        else if (newText[0] == oldText[0]) { newText.shift(); oldText.shift(); fromLine++; }\n        else break;\n      }\n\n      var cutFront = 0, cutEnd = 0;\n      var newTop = newText[0], oldTop = oldText[0], maxCutFront = Math.min(newTop.length, oldTop.length);\n      while (cutFront < maxCutFront && newTop.charCodeAt(cutFront) == oldTop.charCodeAt(cutFront))\n        ++cutFront;\n      var newBot = lst(newText), oldBot = lst(oldText);\n      var maxCutEnd = Math.min(newBot.length - (newText.length == 1 ? cutFront : 0),\n                               oldBot.length - (oldText.length == 1 ? cutFront : 0));\n      while (cutEnd < maxCutEnd &&\n             newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1))\n        ++cutEnd;\n\n      newText[newText.length - 1] = newBot.slice(0, newBot.length - cutEnd);\n      newText[0] = newText[0].slice(cutFront);\n\n      var chFrom = Pos(fromLine, cutFront);\n      var chTo = Pos(toLine, oldText.length ? lst(oldText).length - cutEnd : 0);\n      if (newText.length > 1 || newText[0] || cmp(chFrom, chTo)) {\n        replaceRange(cm.doc, newText, chFrom, chTo, \"+input\");\n        return true;\n      }\n    },\n\n    ensurePolled: function() {\n      this.forceCompositionEnd();\n    },\n    reset: function() {\n      this.forceCompositionEnd();\n    },\n    forceCompositionEnd: function() {\n      if (!this.composing || this.composing.handled) return;\n      this.applyComposition(this.composing);\n      this.composing.handled = true;\n      this.div.blur();\n      this.div.focus();\n    },\n    applyComposition: function(composing) {\n      if (composing.data && composing.data != composing.startData)\n        operation(this.cm, applyTextInput)(this.cm, composing.data, 0, composing.sel);\n    },\n\n    setUneditable: function(node) {\n      node.setAttribute(\"contenteditable\", \"false\");\n    },\n\n    onKeyPress: function(e) {\n      e.preventDefault();\n      operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0);\n    },\n\n    onContextMenu: nothing,\n    resetPosition: nothing,\n\n    needsContentAttribute: true\n  }, ContentEditableInput.prototype);\n\n  function posToDOM(cm, pos) {\n    var view = findViewForLine(cm, pos.line);\n    if (!view || view.hidden) return null;\n    var line = getLine(cm.doc, pos.line);\n    var info = mapFromLineView(view, line, pos.line);\n\n    var order = getOrder(line), side = \"left\";\n    if (order) {\n      var partPos = getBidiPartAt(order, pos.ch);\n      side = partPos % 2 ? \"right\" : \"left\";\n    }\n    var result = nodeAndOffsetInLineMap(info.map, pos.ch, \"left\");\n    result.offset = result.collapse == \"right\" ? result.end : result.start;\n    return result;\n  }\n\n  function badPos(pos, bad) { if (bad) pos.bad = true; return pos; }\n\n  function domToPos(cm, node, offset) {\n    var lineNode;\n    if (node == cm.display.lineDiv) {\n      lineNode = cm.display.lineDiv.childNodes[offset];\n      if (!lineNode) return badPos(cm.clipPos(Pos(cm.display.viewTo - 1)), true);\n      node = null; offset = 0;\n    } else {\n      for (lineNode = node;; lineNode = lineNode.parentNode) {\n        if (!lineNode || lineNode == cm.display.lineDiv) return null;\n        if (lineNode.parentNode && lineNode.parentNode == cm.display.lineDiv) break;\n      }\n    }\n    for (var i = 0; i < cm.display.view.length; i++) {\n      var lineView = cm.display.view[i];\n      if (lineView.node == lineNode)\n        return locateNodeInLineView(lineView, node, offset);\n    }\n  }\n\n  function locateNodeInLineView(lineView, node, offset) {\n    var wrapper = lineView.text.firstChild, bad = false;\n    if (!node || !contains(wrapper, node)) return badPos(Pos(lineNo(lineView.line), 0), true);\n    if (node == wrapper) {\n      bad = true;\n      node = wrapper.childNodes[offset];\n      offset = 0;\n      if (!node) {\n        var line = lineView.rest ? lst(lineView.rest) : lineView.line;\n        return badPos(Pos(lineNo(line), line.text.length), bad);\n      }\n    }\n\n    var textNode = node.nodeType == 3 ? node : null, topNode = node;\n    if (!textNode && node.childNodes.length == 1 && node.firstChild.nodeType == 3) {\n      textNode = node.firstChild;\n      if (offset) offset = textNode.nodeValue.length;\n    }\n    while (topNode.parentNode != wrapper) topNode = topNode.parentNode;\n    var measure = lineView.measure, maps = measure.maps;\n\n    function find(textNode, topNode, offset) {\n      for (var i = -1; i < (maps ? maps.length : 0); i++) {\n        var map = i < 0 ? measure.map : maps[i];\n        for (var j = 0; j < map.length; j += 3) {\n          var curNode = map[j + 2];\n          if (curNode == textNode || curNode == topNode) {\n            var line = lineNo(i < 0 ? lineView.line : lineView.rest[i]);\n            var ch = map[j] + offset;\n            if (offset < 0 || curNode != textNode) ch = map[j + (offset ? 1 : 0)];\n            return Pos(line, ch);\n          }\n        }\n      }\n    }\n    var found = find(textNode, topNode, offset);\n    if (found) return badPos(found, bad);\n\n    // FIXME this is all really shaky. might handle the few cases it needs to handle, but likely to cause problems\n    for (var after = topNode.nextSibling, dist = textNode ? textNode.nodeValue.length - offset : 0; after; after = after.nextSibling) {\n      found = find(after, after.firstChild, 0);\n      if (found)\n        return badPos(Pos(found.line, found.ch - dist), bad);\n      else\n        dist += after.textContent.length;\n    }\n    for (var before = topNode.previousSibling, dist = offset; before; before = before.previousSibling) {\n      found = find(before, before.firstChild, -1);\n      if (found)\n        return badPos(Pos(found.line, found.ch + dist), bad);\n      else\n        dist += after.textContent.length;\n    }\n  }\n\n  function domTextBetween(cm, from, to, fromLine, toLine) {\n    var text = \"\", closing = false;\n    function recognizeMarker(id) { return function(marker) { return marker.id == id; }; }\n    function walk(node) {\n      if (node.nodeType == 1) {\n        var cmText = node.getAttribute(\"cm-text\");\n        if (cmText != null) {\n          if (cmText == \"\") cmText = node.textContent.replace(/\\u200b/g, \"\");\n          text += cmText;\n          return;\n        }\n        var markerID = node.getAttribute(\"cm-marker\"), range;\n        if (markerID) {\n          var found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID));\n          if (found.length && (range = found[0].find()))\n            text += getBetween(cm.doc, range.from, range.to).join(\"\\n\");\n          return;\n        }\n        if (node.getAttribute(\"contenteditable\") == \"false\") return;\n        for (var i = 0; i < node.childNodes.length; i++)\n          walk(node.childNodes[i]);\n        if (/^(pre|div|p)$/i.test(node.nodeName))\n          closing = true;\n      } else if (node.nodeType == 3) {\n        var val = node.nodeValue;\n        if (!val) return;\n        if (closing) {\n          text += \"\\n\";\n          closing = false;\n        }\n        text += val;\n      }\n    }\n    for (;;) {\n      walk(from);\n      if (from == to) break;\n      from = from.nextSibling;\n    }\n    return text;\n  }\n\n  CodeMirror.inputStyles = {\"textarea\": TextareaInput, \"contenteditable\": ContentEditableInput};\n\n  // SELECTION / CURSOR\n\n  // Selection objects are immutable. A new one is created every time\n  // the selection changes. A selection is one or more non-overlapping\n  // (and non-touching) ranges, sorted, and an integer that indicates\n  // which one is the primary selection (the one that's scrolled into\n  // view, that getCursor returns, etc).\n  function Selection(ranges, primIndex) {\n    this.ranges = ranges;\n    this.primIndex = primIndex;\n  }\n\n  Selection.prototype = {\n    primary: function() { return this.ranges[this.primIndex]; },\n    equals: function(other) {\n      if (other == this) return true;\n      if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) return false;\n      for (var i = 0; i < this.ranges.length; i++) {\n        var here = this.ranges[i], there = other.ranges[i];\n        if (cmp(here.anchor, there.anchor) != 0 || cmp(here.head, there.head) != 0) return false;\n      }\n      return true;\n    },\n    deepCopy: function() {\n      for (var out = [], i = 0; i < this.ranges.length; i++)\n        out[i] = new Range(copyPos(this.ranges[i].anchor), copyPos(this.ranges[i].head));\n      return new Selection(out, this.primIndex);\n    },\n    somethingSelected: function() {\n      for (var i = 0; i < this.ranges.length; i++)\n        if (!this.ranges[i].empty()) return true;\n      return false;\n    },\n    contains: function(pos, end) {\n      if (!end) end = pos;\n      for (var i = 0; i < this.ranges.length; i++) {\n        var range = this.ranges[i];\n        if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0)\n          return i;\n      }\n      return -1;\n    }\n  };\n\n  function Range(anchor, head) {\n    this.anchor = anchor; this.head = head;\n  }\n\n  Range.prototype = {\n    from: function() { return minPos(this.anchor, this.head); },\n    to: function() { return maxPos(this.anchor, this.head); },\n    empty: function() {\n      return this.head.line == this.anchor.line && this.head.ch == this.anchor.ch;\n    }\n  };\n\n  // Take an unsorted, potentially overlapping set of ranges, and\n  // build a selection out of it. 'Consumes' ranges array (modifying\n  // it).\n  function normalizeSelection(ranges, primIndex) {\n    var prim = ranges[primIndex];\n    ranges.sort(function(a, b) { return cmp(a.from(), b.from()); });\n    primIndex = indexOf(ranges, prim);\n    for (var i = 1; i < ranges.length; i++) {\n      var cur = ranges[i], prev = ranges[i - 1];\n      if (cmp(prev.to(), cur.from()) >= 0) {\n        var from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), cur.to());\n        var inv = prev.empty() ? cur.from() == cur.head : prev.from() == prev.head;\n        if (i <= primIndex) --primIndex;\n        ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to));\n      }\n    }\n    return new Selection(ranges, primIndex);\n  }\n\n  function simpleSelection(anchor, head) {\n    return new Selection([new Range(anchor, head || anchor)], 0);\n  }\n\n  // Most of the external API clips given positions to make sure they\n  // actually exist within the document.\n  function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1));}\n  function clipPos(doc, pos) {\n    if (pos.line < doc.first) return Pos(doc.first, 0);\n    var last = doc.first + doc.size - 1;\n    if (pos.line > last) return Pos(last, getLine(doc, last).text.length);\n    return clipToLen(pos, getLine(doc, pos.line).text.length);\n  }\n  function clipToLen(pos, linelen) {\n    var ch = pos.ch;\n    if (ch == null || ch > linelen) return Pos(pos.line, linelen);\n    else if (ch < 0) return Pos(pos.line, 0);\n    else return pos;\n  }\n  function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size;}\n  function clipPosArray(doc, array) {\n    for (var out = [], i = 0; i < array.length; i++) out[i] = clipPos(doc, array[i]);\n    return out;\n  }\n\n  // SELECTION UPDATES\n\n  // The 'scroll' parameter given to many of these indicated whether\n  // the new cursor position should be scrolled into view after\n  // modifying the selection.\n\n  // If shift is held or the extend flag is set, extends a range to\n  // include a given position (and optionally a second position).\n  // Otherwise, simply returns the range between the given positions.\n  // Used for cursor motion and such.\n  function extendRange(doc, range, head, other) {\n    if (doc.cm && doc.cm.display.shift || doc.extend) {\n      var anchor = range.anchor;\n      if (other) {\n        var posBefore = cmp(head, anchor) < 0;\n        if (posBefore != (cmp(other, anchor) < 0)) {\n          anchor = head;\n          head = other;\n        } else if (posBefore != (cmp(head, other) < 0)) {\n          head = other;\n        }\n      }\n      return new Range(anchor, head);\n    } else {\n      return new Range(other || head, head);\n    }\n  }\n\n  // Extend the primary selection range, discard the rest.\n  function extendSelection(doc, head, other, options) {\n    setSelection(doc, new Selection([extendRange(doc, doc.sel.primary(), head, other)], 0), options);\n  }\n\n  // Extend all selections (pos is an array of selections with length\n  // equal the number of selections)\n  function extendSelections(doc, heads, options) {\n    for (var out = [], i = 0; i < doc.sel.ranges.length; i++)\n      out[i] = extendRange(doc, doc.sel.ranges[i], heads[i], null);\n    var newSel = normalizeSelection(out, doc.sel.primIndex);\n    setSelection(doc, newSel, options);\n  }\n\n  // Updates a single range in the selection.\n  function replaceOneSelection(doc, i, range, options) {\n    var ranges = doc.sel.ranges.slice(0);\n    ranges[i] = range;\n    setSelection(doc, normalizeSelection(ranges, doc.sel.primIndex), options);\n  }\n\n  // Reset the selection to a single range.\n  function setSimpleSelection(doc, anchor, head, options) {\n    setSelection(doc, simpleSelection(anchor, head), options);\n  }\n\n  // Give beforeSelectionChange handlers a change to influence a\n  // selection update.\n  function filterSelectionChange(doc, sel) {\n    var obj = {\n      ranges: sel.ranges,\n      update: function(ranges) {\n        this.ranges = [];\n        for (var i = 0; i < ranges.length; i++)\n          this.ranges[i] = new Range(clipPos(doc, ranges[i].anchor),\n                                     clipPos(doc, ranges[i].head));\n      }\n    };\n    signal(doc, \"beforeSelectionChange\", doc, obj);\n    if (doc.cm) signal(doc.cm, \"beforeSelectionChange\", doc.cm, obj);\n    if (obj.ranges != sel.ranges) return normalizeSelection(obj.ranges, obj.ranges.length - 1);\n    else return sel;\n  }\n\n  function setSelectionReplaceHistory(doc, sel, options) {\n    var done = doc.history.done, last = lst(done);\n    if (last && last.ranges) {\n      done[done.length - 1] = sel;\n      setSelectionNoUndo(doc, sel, options);\n    } else {\n      setSelection(doc, sel, options);\n    }\n  }\n\n  // Set a new selection.\n  function setSelection(doc, sel, options) {\n    setSelectionNoUndo(doc, sel, options);\n    addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, options);\n  }\n\n  function setSelectionNoUndo(doc, sel, options) {\n    if (hasHandler(doc, \"beforeSelectionChange\") || doc.cm && hasHandler(doc.cm, \"beforeSelectionChange\"))\n      sel = filterSelectionChange(doc, sel);\n\n    var bias = options && options.bias ||\n      (cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1);\n    setSelectionInner(doc, skipAtomicInSelection(doc, sel, bias, true));\n\n    if (!(options && options.scroll === false) && doc.cm)\n      ensureCursorVisible(doc.cm);\n  }\n\n  function setSelectionInner(doc, sel) {\n    if (sel.equals(doc.sel)) return;\n\n    doc.sel = sel;\n\n    if (doc.cm) {\n      doc.cm.curOp.updateInput = doc.cm.curOp.selectionChanged = true;\n      signalCursorActivity(doc.cm);\n    }\n    signalLater(doc, \"cursorActivity\", doc);\n  }\n\n  // Verify that the selection does not partially select any atomic\n  // marked ranges.\n  function reCheckSelection(doc) {\n    setSelectionInner(doc, skipAtomicInSelection(doc, doc.sel, null, false), sel_dontScroll);\n  }\n\n  // Return a selection that does not partially select any atomic\n  // ranges.\n  function skipAtomicInSelection(doc, sel, bias, mayClear) {\n    var out;\n    for (var i = 0; i < sel.ranges.length; i++) {\n      var range = sel.ranges[i];\n      var newAnchor = skipAtomic(doc, range.anchor, bias, mayClear);\n      var newHead = skipAtomic(doc, range.head, bias, mayClear);\n      if (out || newAnchor != range.anchor || newHead != range.head) {\n        if (!out) out = sel.ranges.slice(0, i);\n        out[i] = new Range(newAnchor, newHead);\n      }\n    }\n    return out ? normalizeSelection(out, sel.primIndex) : sel;\n  }\n\n  // Ensure a given position is not inside an atomic range.\n  function skipAtomic(doc, pos, bias, mayClear) {\n    var flipped = false, curPos = pos;\n    var dir = bias || 1;\n    doc.cantEdit = false;\n    search: for (;;) {\n      var line = getLine(doc, curPos.line);\n      if (line.markedSpans) {\n        for (var i = 0; i < line.markedSpans.length; ++i) {\n          var sp = line.markedSpans[i], m = sp.marker;\n          if ((sp.from == null || (m.inclusiveLeft ? sp.from <= curPos.ch : sp.from < curPos.ch)) &&\n              (sp.to == null || (m.inclusiveRight ? sp.to >= curPos.ch : sp.to > curPos.ch))) {\n            if (mayClear) {\n              signal(m, \"beforeCursorEnter\");\n              if (m.explicitlyCleared) {\n                if (!line.markedSpans) break;\n                else {--i; continue;}\n              }\n            }\n            if (!m.atomic) continue;\n            var newPos = m.find(dir < 0 ? -1 : 1);\n            if (cmp(newPos, curPos) == 0) {\n              newPos.ch += dir;\n              if (newPos.ch < 0) {\n                if (newPos.line > doc.first) newPos = clipPos(doc, Pos(newPos.line - 1));\n                else newPos = null;\n              } else if (newPos.ch > line.text.length) {\n                if (newPos.line < doc.first + doc.size - 1) newPos = Pos(newPos.line + 1, 0);\n                else newPos = null;\n              }\n              if (!newPos) {\n                if (flipped) {\n                  // Driven in a corner -- no valid cursor position found at all\n                  // -- try again *with* clearing, if we didn't already\n                  if (!mayClear) return skipAtomic(doc, pos, bias, true);\n                  // Otherwise, turn off editing until further notice, and return the start of the doc\n                  doc.cantEdit = true;\n                  return Pos(doc.first, 0);\n                }\n                flipped = true; newPos = pos; dir = -dir;\n              }\n            }\n            curPos = newPos;\n            continue search;\n          }\n        }\n      }\n      return curPos;\n    }\n  }\n\n  // SELECTION DRAWING\n\n  function updateSelection(cm) {\n    cm.display.input.showSelection(cm.display.input.prepareSelection());\n  }\n\n  function prepareSelection(cm, primary) {\n    var doc = cm.doc, result = {};\n    var curFragment = result.cursors = document.createDocumentFragment();\n    var selFragment = result.selection = document.createDocumentFragment();\n\n    for (var i = 0; i < doc.sel.ranges.length; i++) {\n      if (primary === false && i == doc.sel.primIndex) continue;\n      var range = doc.sel.ranges[i];\n      var collapsed = range.empty();\n      if (collapsed || cm.options.showCursorWhenSelecting)\n        drawSelectionCursor(cm, range, curFragment);\n      if (!collapsed)\n        drawSelectionRange(cm, range, selFragment);\n    }\n    return result;\n  }\n\n  // Draws a cursor for the given range\n  function drawSelectionCursor(cm, range, output) {\n    var pos = cursorCoords(cm, range.head, \"div\", null, null, !cm.options.singleCursorHeightPerLine);\n\n    var cursor = output.appendChild(elt(\"div\", \"\\u00a0\", \"CodeMirror-cursor\"));\n    cursor.style.left = pos.left + \"px\";\n    cursor.style.top = pos.top + \"px\";\n    cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + \"px\";\n\n    if (pos.other) {\n      // Secondary cursor, shown when on a 'jump' in bi-directional text\n      var otherCursor = output.appendChild(elt(\"div\", \"\\u00a0\", \"CodeMirror-cursor CodeMirror-secondarycursor\"));\n      otherCursor.style.display = \"\";\n      otherCursor.style.left = pos.other.left + \"px\";\n      otherCursor.style.top = pos.other.top + \"px\";\n      otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + \"px\";\n    }\n  }\n\n  // Draws the given range as a highlighted selection\n  function drawSelectionRange(cm, range, output) {\n    var display = cm.display, doc = cm.doc;\n    var fragment = document.createDocumentFragment();\n    var padding = paddingH(cm.display), leftSide = padding.left;\n    var rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right;\n\n    function add(left, top, width, bottom) {\n      if (top < 0) top = 0;\n      top = Math.round(top);\n      bottom = Math.round(bottom);\n      fragment.appendChild(elt(\"div\", null, \"CodeMirror-selected\", \"position: absolute; left: \" + left +\n                               \"px; top: \" + top + \"px; width: \" + (width == null ? rightSide - left : width) +\n                               \"px; height: \" + (bottom - top) + \"px\"));\n    }\n\n    function drawForLine(line, fromArg, toArg) {\n      var lineObj = getLine(doc, line);\n      var lineLen = lineObj.text.length;\n      var start, end;\n      function coords(ch, bias) {\n        return charCoords(cm, Pos(line, ch), \"div\", lineObj, bias);\n      }\n\n      iterateBidiSections(getOrder(lineObj), fromArg || 0, toArg == null ? lineLen : toArg, function(from, to, dir) {\n        var leftPos = coords(from, \"left\"), rightPos, left, right;\n        if (from == to) {\n          rightPos = leftPos;\n          left = right = leftPos.left;\n        } else {\n          rightPos = coords(to - 1, \"right\");\n          if (dir == \"rtl\") { var tmp = leftPos; leftPos = rightPos; rightPos = tmp; }\n          left = leftPos.left;\n          right = rightPos.right;\n        }\n        if (fromArg == null && from == 0) left = leftSide;\n        if (rightPos.top - leftPos.top > 3) { // Different lines, draw top part\n          add(left, leftPos.top, null, leftPos.bottom);\n          left = leftSide;\n          if (leftPos.bottom < rightPos.top) add(left, leftPos.bottom, null, rightPos.top);\n        }\n        if (toArg == null && to == lineLen) right = rightSide;\n        if (!start || leftPos.top < start.top || leftPos.top == start.top && leftPos.left < start.left)\n          start = leftPos;\n        if (!end || rightPos.bottom > end.bottom || rightPos.bottom == end.bottom && rightPos.right > end.right)\n          end = rightPos;\n        if (left < leftSide + 1) left = leftSide;\n        add(left, rightPos.top, right - left, rightPos.bottom);\n      });\n      return {start: start, end: end};\n    }\n\n    var sFrom = range.from(), sTo = range.to();\n    if (sFrom.line == sTo.line) {\n      drawForLine(sFrom.line, sFrom.ch, sTo.ch);\n    } else {\n      var fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line);\n      var singleVLine = visualLine(fromLine) == visualLine(toLine);\n      var leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end;\n      var rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start;\n      if (singleVLine) {\n        if (leftEnd.top < rightStart.top - 2) {\n          add(leftEnd.right, leftEnd.top, null, leftEnd.bottom);\n          add(leftSide, rightStart.top, rightStart.left, rightStart.bottom);\n        } else {\n          add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom);\n        }\n      }\n      if (leftEnd.bottom < rightStart.top)\n        add(leftSide, leftEnd.bottom, null, rightStart.top);\n    }\n\n    output.appendChild(fragment);\n  }\n\n  // Cursor-blinking\n  function restartBlink(cm) {\n    if (!cm.state.focused) return;\n    var display = cm.display;\n    clearInterval(display.blinker);\n    var on = true;\n    display.cursorDiv.style.visibility = \"\";\n    if (cm.options.cursorBlinkRate > 0)\n      display.blinker = setInterval(function() {\n        display.cursorDiv.style.visibility = (on = !on) ? \"\" : \"hidden\";\n      }, cm.options.cursorBlinkRate);\n    else if (cm.options.cursorBlinkRate < 0)\n      display.cursorDiv.style.visibility = \"hidden\";\n  }\n\n  // HIGHLIGHT WORKER\n\n  function startWorker(cm, time) {\n    if (cm.doc.mode.startState && cm.doc.frontier < cm.display.viewTo)\n      cm.state.highlight.set(time, bind(highlightWorker, cm));\n  }\n\n  function highlightWorker(cm) {\n    var doc = cm.doc;\n    if (doc.frontier < doc.first) doc.frontier = doc.first;\n    if (doc.frontier >= cm.display.viewTo) return;\n    var end = +new Date + cm.options.workTime;\n    var state = copyState(doc.mode, getStateBefore(cm, doc.frontier));\n    var changedLines = [];\n\n    doc.iter(doc.frontier, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function(line) {\n      if (doc.frontier >= cm.display.viewFrom) { // Visible\n        var oldStyles = line.styles;\n        var highlighted = highlightLine(cm, line, state, true);\n        line.styles = highlighted.styles;\n        var oldCls = line.styleClasses, newCls = highlighted.classes;\n        if (newCls) line.styleClasses = newCls;\n        else if (oldCls) line.styleClasses = null;\n        var ischange = !oldStyles || oldStyles.length != line.styles.length ||\n          oldCls != newCls && (!oldCls || !newCls || oldCls.bgClass != newCls.bgClass || oldCls.textClass != newCls.textClass);\n        for (var i = 0; !ischange && i < oldStyles.length; ++i) ischange = oldStyles[i] != line.styles[i];\n        if (ischange) changedLines.push(doc.frontier);\n        line.stateAfter = copyState(doc.mode, state);\n      } else {\n        processLine(cm, line.text, state);\n        line.stateAfter = doc.frontier % 5 == 0 ? copyState(doc.mode, state) : null;\n      }\n      ++doc.frontier;\n      if (+new Date > end) {\n        startWorker(cm, cm.options.workDelay);\n        return true;\n      }\n    });\n    if (changedLines.length) runInOp(cm, function() {\n      for (var i = 0; i < changedLines.length; i++)\n        regLineChange(cm, changedLines[i], \"text\");\n    });\n  }\n\n  // Finds the line to start with when starting a parse. Tries to\n  // find a line with a stateAfter, so that it can start with a\n  // valid state. If that fails, it returns the line with the\n  // smallest indentation, which tends to need the least context to\n  // parse correctly.\n  function findStartLine(cm, n, precise) {\n    var minindent, minline, doc = cm.doc;\n    var lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100);\n    for (var search = n; search > lim; --search) {\n      if (search <= doc.first) return doc.first;\n      var line = getLine(doc, search - 1);\n      if (line.stateAfter && (!precise || search <= doc.frontier)) return search;\n      var indented = countColumn(line.text, null, cm.options.tabSize);\n      if (minline == null || minindent > indented) {\n        minline = search - 1;\n        minindent = indented;\n      }\n    }\n    return minline;\n  }\n\n  function getStateBefore(cm, n, precise) {\n    var doc = cm.doc, display = cm.display;\n    if (!doc.mode.startState) return true;\n    var pos = findStartLine(cm, n, precise), state = pos > doc.first && getLine(doc, pos-1).stateAfter;\n    if (!state) state = startState(doc.mode);\n    else state = copyState(doc.mode, state);\n    doc.iter(pos, n, function(line) {\n      processLine(cm, line.text, state);\n      var save = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo;\n      line.stateAfter = save ? copyState(doc.mode, state) : null;\n      ++pos;\n    });\n    if (precise) doc.frontier = pos;\n    return state;\n  }\n\n  // POSITION MEASUREMENT\n\n  function paddingTop(display) {return display.lineSpace.offsetTop;}\n  function paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight;}\n  function paddingH(display) {\n    if (display.cachedPaddingH) return display.cachedPaddingH;\n    var e = removeChildrenAndAdd(display.measure, elt(\"pre\", \"x\"));\n    var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle;\n    var data = {left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight)};\n    if (!isNaN(data.left) && !isNaN(data.right)) display.cachedPaddingH = data;\n    return data;\n  }\n\n  function scrollGap(cm) { return scrollerGap - cm.display.nativeBarWidth; }\n  function displayWidth(cm) {\n    return cm.display.scroller.clientWidth - scrollGap(cm) - cm.display.barWidth;\n  }\n  function displayHeight(cm) {\n    return cm.display.scroller.clientHeight - scrollGap(cm) - cm.display.barHeight;\n  }\n\n  // Ensure the lineView.wrapping.heights array is populated. This is\n  // an array of bottom offsets for the lines that make up a drawn\n  // line. When lineWrapping is on, there might be more than one\n  // height.\n  function ensureLineHeights(cm, lineView, rect) {\n    var wrapping = cm.options.lineWrapping;\n    var curWidth = wrapping && displayWidth(cm);\n    if (!lineView.measure.heights || wrapping && lineView.measure.width != curWidth) {\n      var heights = lineView.measure.heights = [];\n      if (wrapping) {\n        lineView.measure.width = curWidth;\n        var rects = lineView.text.firstChild.getClientRects();\n        for (var i = 0; i < rects.length - 1; i++) {\n          var cur = rects[i], next = rects[i + 1];\n          if (Math.abs(cur.bottom - next.bottom) > 2)\n            heights.push((cur.bottom + next.top) / 2 - rect.top);\n        }\n      }\n      heights.push(rect.bottom - rect.top);\n    }\n  }\n\n  // Find a line map (mapping character offsets to text nodes) and a\n  // measurement cache for the given line number. (A line view might\n  // contain multiple lines when collapsed ranges are present.)\n  function mapFromLineView(lineView, line, lineN) {\n    if (lineView.line == line)\n      return {map: lineView.measure.map, cache: lineView.measure.cache};\n    for (var i = 0; i < lineView.rest.length; i++)\n      if (lineView.rest[i] == line)\n        return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i]};\n    for (var i = 0; i < lineView.rest.length; i++)\n      if (lineNo(lineView.rest[i]) > lineN)\n        return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i], before: true};\n  }\n\n  // Render a line into the hidden node display.externalMeasured. Used\n  // when measurement is needed for a line that's not in the viewport.\n  function updateExternalMeasurement(cm, line) {\n    line = visualLine(line);\n    var lineN = lineNo(line);\n    var view = cm.display.externalMeasured = new LineView(cm.doc, line, lineN);\n    view.lineN = lineN;\n    var built = view.built = buildLineContent(cm, view);\n    view.text = built.pre;\n    removeChildrenAndAdd(cm.display.lineMeasure, built.pre);\n    return view;\n  }\n\n  // Get a {top, bottom, left, right} box (in line-local coordinates)\n  // for a given character.\n  function measureChar(cm, line, ch, bias) {\n    return measureCharPrepared(cm, prepareMeasureForLine(cm, line), ch, bias);\n  }\n\n  // Find a line view that corresponds to the given line number.\n  function findViewForLine(cm, lineN) {\n    if (lineN >= cm.display.viewFrom && lineN < cm.display.viewTo)\n      return cm.display.view[findViewIndex(cm, lineN)];\n    var ext = cm.display.externalMeasured;\n    if (ext && lineN >= ext.lineN && lineN < ext.lineN + ext.size)\n      return ext;\n  }\n\n  // Measurement can be split in two steps, the set-up work that\n  // applies to the whole line, and the measurement of the actual\n  // character. Functions like coordsChar, that need to do a lot of\n  // measurements in a row, can thus ensure that the set-up work is\n  // only done once.\n  function prepareMeasureForLine(cm, line) {\n    var lineN = lineNo(line);\n    var view = findViewForLine(cm, lineN);\n    if (view && !view.text)\n      view = null;\n    else if (view && view.changes)\n      updateLineForChanges(cm, view, lineN, getDimensions(cm));\n    if (!view)\n      view = updateExternalMeasurement(cm, line);\n\n    var info = mapFromLineView(view, line, lineN);\n    return {\n      line: line, view: view, rect: null,\n      map: info.map, cache: info.cache, before: info.before,\n      hasHeights: false\n    };\n  }\n\n  // Given a prepared measurement object, measures the position of an\n  // actual character (or fetches it from the cache).\n  function measureCharPrepared(cm, prepared, ch, bias, varHeight) {\n    if (prepared.before) ch = -1;\n    var key = ch + (bias || \"\"), found;\n    if (prepared.cache.hasOwnProperty(key)) {\n      found = prepared.cache[key];\n    } else {\n      if (!prepared.rect)\n        prepared.rect = prepared.view.text.getBoundingClientRect();\n      if (!prepared.hasHeights) {\n        ensureLineHeights(cm, prepared.view, prepared.rect);\n        prepared.hasHeights = true;\n      }\n      found = measureCharInner(cm, prepared, ch, bias);\n      if (!found.bogus) prepared.cache[key] = found;\n    }\n    return {left: found.left, right: found.right,\n            top: varHeight ? found.rtop : found.top,\n            bottom: varHeight ? found.rbottom : found.bottom};\n  }\n\n  var nullRect = {left: 0, right: 0, top: 0, bottom: 0};\n\n  function nodeAndOffsetInLineMap(map, ch, bias) {\n    var node, start, end, collapse;\n    // First, search the line map for the text node corresponding to,\n    // or closest to, the target character.\n    for (var i = 0; i < map.length; i += 3) {\n      var mStart = map[i], mEnd = map[i + 1];\n      if (ch < mStart) {\n        start = 0; end = 1;\n        collapse = \"left\";\n      } else if (ch < mEnd) {\n        start = ch - mStart;\n        end = start + 1;\n      } else if (i == map.length - 3 || ch == mEnd && map[i + 3] > ch) {\n        end = mEnd - mStart;\n        start = end - 1;\n        if (ch >= mEnd) collapse = \"right\";\n      }\n      if (start != null) {\n        node = map[i + 2];\n        if (mStart == mEnd && bias == (node.insertLeft ? \"left\" : \"right\"))\n          collapse = bias;\n        if (bias == \"left\" && start == 0)\n          while (i && map[i - 2] == map[i - 3] && map[i - 1].insertLeft) {\n            node = map[(i -= 3) + 2];\n            collapse = \"left\";\n          }\n        if (bias == \"right\" && start == mEnd - mStart)\n          while (i < map.length - 3 && map[i + 3] == map[i + 4] && !map[i + 5].insertLeft) {\n            node = map[(i += 3) + 2];\n            collapse = \"right\";\n          }\n        break;\n      }\n    }\n    return {node: node, start: start, end: end, collapse: collapse, coverStart: mStart, coverEnd: mEnd};\n  }\n\n  function measureCharInner(cm, prepared, ch, bias) {\n    var place = nodeAndOffsetInLineMap(prepared.map, ch, bias);\n    var node = place.node, start = place.start, end = place.end, collapse = place.collapse;\n\n    var rect;\n    if (node.nodeType == 3) { // If it is a text node, use a range to retrieve the coordinates.\n      for (var i = 0; i < 4; i++) { // Retry a maximum of 4 times when nonsense rectangles are returned\n        while (start && isExtendingChar(prepared.line.text.charAt(place.coverStart + start))) --start;\n        while (place.coverStart + end < place.coverEnd && isExtendingChar(prepared.line.text.charAt(place.coverStart + end))) ++end;\n        if (ie && ie_version < 9 && start == 0 && end == place.coverEnd - place.coverStart) {\n          rect = node.parentNode.getBoundingClientRect();\n        } else if (ie && cm.options.lineWrapping) {\n          var rects = range(node, start, end).getClientRects();\n          if (rects.length)\n            rect = rects[bias == \"right\" ? rects.length - 1 : 0];\n          else\n            rect = nullRect;\n        } else {\n          rect = range(node, start, end).getBoundingClientRect() || nullRect;\n        }\n        if (rect.left || rect.right || start == 0) break;\n        end = start;\n        start = start - 1;\n        collapse = \"right\";\n      }\n      if (ie && ie_version < 11) rect = maybeUpdateRectForZooming(cm.display.measure, rect);\n    } else { // If it is a widget, simply get the box for the whole widget.\n      if (start > 0) collapse = bias = \"right\";\n      var rects;\n      if (cm.options.lineWrapping && (rects = node.getClientRects()).length > 1)\n        rect = rects[bias == \"right\" ? rects.length - 1 : 0];\n      else\n        rect = node.getBoundingClientRect();\n    }\n    if (ie && ie_version < 9 && !start && (!rect || !rect.left && !rect.right)) {\n      var rSpan = node.parentNode.getClientRects()[0];\n      if (rSpan)\n        rect = {left: rSpan.left, right: rSpan.left + charWidth(cm.display), top: rSpan.top, bottom: rSpan.bottom};\n      else\n        rect = nullRect;\n    }\n\n    var rtop = rect.top - prepared.rect.top, rbot = rect.bottom - prepared.rect.top;\n    var mid = (rtop + rbot) / 2;\n    var heights = prepared.view.measure.heights;\n    for (var i = 0; i < heights.length - 1; i++)\n      if (mid < heights[i]) break;\n    var top = i ? heights[i - 1] : 0, bot = heights[i];\n    var result = {left: (collapse == \"right\" ? rect.right : rect.left) - prepared.rect.left,\n                  right: (collapse == \"left\" ? rect.left : rect.right) - prepared.rect.left,\n                  top: top, bottom: bot};\n    if (!rect.left && !rect.right) result.bogus = true;\n    if (!cm.options.singleCursorHeightPerLine) { result.rtop = rtop; result.rbottom = rbot; }\n\n    return result;\n  }\n\n  // Work around problem with bounding client rects on ranges being\n  // returned incorrectly when zoomed on IE10 and below.\n  function maybeUpdateRectForZooming(measure, rect) {\n    if (!window.screen || screen.logicalXDPI == null ||\n        screen.logicalXDPI == screen.deviceXDPI || !hasBadZoomedRects(measure))\n      return rect;\n    var scaleX = screen.logicalXDPI / screen.deviceXDPI;\n    var scaleY = screen.logicalYDPI / screen.deviceYDPI;\n    return {left: rect.left * scaleX, right: rect.right * scaleX,\n            top: rect.top * scaleY, bottom: rect.bottom * scaleY};\n  }\n\n  function clearLineMeasurementCacheFor(lineView) {\n    if (lineView.measure) {\n      lineView.measure.cache = {};\n      lineView.measure.heights = null;\n      if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++)\n        lineView.measure.caches[i] = {};\n    }\n  }\n\n  function clearLineMeasurementCache(cm) {\n    cm.display.externalMeasure = null;\n    removeChildren(cm.display.lineMeasure);\n    for (var i = 0; i < cm.display.view.length; i++)\n      clearLineMeasurementCacheFor(cm.display.view[i]);\n  }\n\n  function clearCaches(cm) {\n    clearLineMeasurementCache(cm);\n    cm.display.cachedCharWidth = cm.display.cachedTextHeight = cm.display.cachedPaddingH = null;\n    if (!cm.options.lineWrapping) cm.display.maxLineChanged = true;\n    cm.display.lineNumChars = null;\n  }\n\n  function pageScrollX() { return window.pageXOffset || (document.documentElement || document.body).scrollLeft; }\n  function pageScrollY() { return window.pageYOffset || (document.documentElement || document.body).scrollTop; }\n\n  // Converts a {top, bottom, left, right} box from line-local\n  // coordinates into another coordinate system. Context may be one of\n  // \"line\", \"div\" (display.lineDiv), \"local\"/null (editor), \"window\",\n  // or \"page\".\n  function intoCoordSystem(cm, lineObj, rect, context) {\n    if (lineObj.widgets) for (var i = 0; i < lineObj.widgets.length; ++i) if (lineObj.widgets[i].above) {\n      var size = widgetHeight(lineObj.widgets[i]);\n      rect.top += size; rect.bottom += size;\n    }\n    if (context == \"line\") return rect;\n    if (!context) context = \"local\";\n    var yOff = heightAtLine(lineObj);\n    if (context == \"local\") yOff += paddingTop(cm.display);\n    else yOff -= cm.display.viewOffset;\n    if (context == \"page\" || context == \"window\") {\n      var lOff = cm.display.lineSpace.getBoundingClientRect();\n      yOff += lOff.top + (context == \"window\" ? 0 : pageScrollY());\n      var xOff = lOff.left + (context == \"window\" ? 0 : pageScrollX());\n      rect.left += xOff; rect.right += xOff;\n    }\n    rect.top += yOff; rect.bottom += yOff;\n    return rect;\n  }\n\n  // Coverts a box from \"div\" coords to another coordinate system.\n  // Context may be \"window\", \"page\", \"div\", or \"local\"/null.\n  function fromCoordSystem(cm, coords, context) {\n    if (context == \"div\") return coords;\n    var left = coords.left, top = coords.top;\n    // First move into \"page\" coordinate system\n    if (context == \"page\") {\n      left -= pageScrollX();\n      top -= pageScrollY();\n    } else if (context == \"local\" || !context) {\n      var localBox = cm.display.sizer.getBoundingClientRect();\n      left += localBox.left;\n      top += localBox.top;\n    }\n\n    var lineSpaceBox = cm.display.lineSpace.getBoundingClientRect();\n    return {left: left - lineSpaceBox.left, top: top - lineSpaceBox.top};\n  }\n\n  function charCoords(cm, pos, context, lineObj, bias) {\n    if (!lineObj) lineObj = getLine(cm.doc, pos.line);\n    return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, bias), context);\n  }\n\n  // Returns a box for a given cursor position, which may have an\n  // 'other' property containing the position of the secondary cursor\n  // on a bidi boundary.\n  function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHeight) {\n    lineObj = lineObj || getLine(cm.doc, pos.line);\n    if (!preparedMeasure) preparedMeasure = prepareMeasureForLine(cm, lineObj);\n    function get(ch, right) {\n      var m = measureCharPrepared(cm, preparedMeasure, ch, right ? \"right\" : \"left\", varHeight);\n      if (right) m.left = m.right; else m.right = m.left;\n      return intoCoordSystem(cm, lineObj, m, context);\n    }\n    function getBidi(ch, partPos) {\n      var part = order[partPos], right = part.level % 2;\n      if (ch == bidiLeft(part) && partPos && part.level < order[partPos - 1].level) {\n        part = order[--partPos];\n        ch = bidiRight(part) - (part.level % 2 ? 0 : 1);\n        right = true;\n      } else if (ch == bidiRight(part) && partPos < order.length - 1 && part.level < order[partPos + 1].level) {\n        part = order[++partPos];\n        ch = bidiLeft(part) - part.level % 2;\n        right = false;\n      }\n      if (right && ch == part.to && ch > part.from) return get(ch - 1);\n      return get(ch, right);\n    }\n    var order = getOrder(lineObj), ch = pos.ch;\n    if (!order) return get(ch);\n    var partPos = getBidiPartAt(order, ch);\n    var val = getBidi(ch, partPos);\n    if (bidiOther != null) val.other = getBidi(ch, bidiOther);\n    return val;\n  }\n\n  // Used to cheaply estimate the coordinates for a position. Used for\n  // intermediate scroll updates.\n  function estimateCoords(cm, pos) {\n    var left = 0, pos = clipPos(cm.doc, pos);\n    if (!cm.options.lineWrapping) left = charWidth(cm.display) * pos.ch;\n    var lineObj = getLine(cm.doc, pos.line);\n    var top = heightAtLine(lineObj) + paddingTop(cm.display);\n    return {left: left, right: left, top: top, bottom: top + lineObj.height};\n  }\n\n  // Positions returned by coordsChar contain some extra information.\n  // xRel is the relative x position of the input coordinates compared\n  // to the found position (so xRel > 0 means the coordinates are to\n  // the right of the character position, for example). When outside\n  // is true, that means the coordinates lie outside the line's\n  // vertical range.\n  function PosWithInfo(line, ch, outside, xRel) {\n    var pos = Pos(line, ch);\n    pos.xRel = xRel;\n    if (outside) pos.outside = true;\n    return pos;\n  }\n\n  // Compute the character position closest to the given coordinates.\n  // Input must be lineSpace-local (\"div\" coordinate system).\n  function coordsChar(cm, x, y) {\n    var doc = cm.doc;\n    y += cm.display.viewOffset;\n    if (y < 0) return PosWithInfo(doc.first, 0, true, -1);\n    var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1;\n    if (lineN > last)\n      return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, true, 1);\n    if (x < 0) x = 0;\n\n    var lineObj = getLine(doc, lineN);\n    for (;;) {\n      var found = coordsCharInner(cm, lineObj, lineN, x, y);\n      var merged = collapsedSpanAtEnd(lineObj);\n      var mergedPos = merged && merged.find(0, true);\n      if (merged && (found.ch > mergedPos.from.ch || found.ch == mergedPos.from.ch && found.xRel > 0))\n        lineN = lineNo(lineObj = mergedPos.to.line);\n      else\n        return found;\n    }\n  }\n\n  function coordsCharInner(cm, lineObj, lineNo, x, y) {\n    var innerOff = y - heightAtLine(lineObj);\n    var wrongLine = false, adjust = 2 * cm.display.wrapper.clientWidth;\n    var preparedMeasure = prepareMeasureForLine(cm, lineObj);\n\n    function getX(ch) {\n      var sp = cursorCoords(cm, Pos(lineNo, ch), \"line\", lineObj, preparedMeasure);\n      wrongLine = true;\n      if (innerOff > sp.bottom) return sp.left - adjust;\n      else if (innerOff < sp.top) return sp.left + adjust;\n      else wrongLine = false;\n      return sp.left;\n    }\n\n    var bidi = getOrder(lineObj), dist = lineObj.text.length;\n    var from = lineLeft(lineObj), to = lineRight(lineObj);\n    var fromX = getX(from), fromOutside = wrongLine, toX = getX(to), toOutside = wrongLine;\n\n    if (x > toX) return PosWithInfo(lineNo, to, toOutside, 1);\n    // Do a binary search between these bounds.\n    for (;;) {\n      if (bidi ? to == from || to == moveVisually(lineObj, from, 1) : to - from <= 1) {\n        var ch = x < fromX || x - fromX <= toX - x ? from : to;\n        var xDiff = x - (ch == from ? fromX : toX);\n        while (isExtendingChar(lineObj.text.charAt(ch))) ++ch;\n        var pos = PosWithInfo(lineNo, ch, ch == from ? fromOutside : toOutside,\n                              xDiff < -1 ? -1 : xDiff > 1 ? 1 : 0);\n        return pos;\n      }\n      var step = Math.ceil(dist / 2), middle = from + step;\n      if (bidi) {\n        middle = from;\n        for (var i = 0; i < step; ++i) middle = moveVisually(lineObj, middle, 1);\n      }\n      var middleX = getX(middle);\n      if (middleX > x) {to = middle; toX = middleX; if (toOutside = wrongLine) toX += 1000; dist = step;}\n      else {from = middle; fromX = middleX; fromOutside = wrongLine; dist -= step;}\n    }\n  }\n\n  var measureText;\n  // Compute the default text height.\n  function textHeight(display) {\n    if (display.cachedTextHeight != null) return display.cachedTextHeight;\n    if (measureText == null) {\n      measureText = elt(\"pre\");\n      // Measure a bunch of lines, for browsers that compute\n      // fractional heights.\n      for (var i = 0; i < 49; ++i) {\n        measureText.appendChild(document.createTextNode(\"x\"));\n        measureText.appendChild(elt(\"br\"));\n      }\n      measureText.appendChild(document.createTextNode(\"x\"));\n    }\n    removeChildrenAndAdd(display.measure, measureText);\n    var height = measureText.offsetHeight / 50;\n    if (height > 3) display.cachedTextHeight = height;\n    removeChildren(display.measure);\n    return height || 1;\n  }\n\n  // Compute the default character width.\n  function charWidth(display) {\n    if (display.cachedCharWidth != null) return display.cachedCharWidth;\n    var anchor = elt(\"span\", \"xxxxxxxxxx\");\n    var pre = elt(\"pre\", [anchor]);\n    removeChildrenAndAdd(display.measure, pre);\n    var rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10;\n    if (width > 2) display.cachedCharWidth = width;\n    return width || 10;\n  }\n\n  // OPERATIONS\n\n  // Operations are used to wrap a series of changes to the editor\n  // state in such a way that each change won't have to update the\n  // cursor and display (which would be awkward, slow, and\n  // error-prone). Instead, display updates are batched and then all\n  // combined and executed at once.\n\n  var operationGroup = null;\n\n  var nextOpId = 0;\n  // Start a new operation.\n  function startOperation(cm) {\n    cm.curOp = {\n      cm: cm,\n      viewChanged: false,      // Flag that indicates that lines might need to be redrawn\n      startHeight: cm.doc.height, // Used to detect need to update scrollbar\n      forceUpdate: false,      // Used to force a redraw\n      updateInput: null,       // Whether to reset the input textarea\n      typing: false,           // Whether this reset should be careful to leave existing text (for compositing)\n      changeObjs: null,        // Accumulated changes, for firing change events\n      cursorActivityHandlers: null, // Set of handlers to fire cursorActivity on\n      cursorActivityCalled: 0, // Tracks which cursorActivity handlers have been called already\n      selectionChanged: false, // Whether the selection needs to be redrawn\n      updateMaxLine: false,    // Set when the widest line needs to be determined anew\n      scrollLeft: null, scrollTop: null, // Intermediate scroll position, not pushed to DOM yet\n      scrollToPos: null,       // Used to scroll to a specific position\n      id: ++nextOpId           // Unique ID\n    };\n    if (operationGroup) {\n      operationGroup.ops.push(cm.curOp);\n    } else {\n      cm.curOp.ownsGroup = operationGroup = {\n        ops: [cm.curOp],\n        delayedCallbacks: []\n      };\n    }\n  }\n\n  function fireCallbacksForOps(group) {\n    // Calls delayed callbacks and cursorActivity handlers until no\n    // new ones appear\n    var callbacks = group.delayedCallbacks, i = 0;\n    do {\n      for (; i < callbacks.length; i++)\n        callbacks[i]();\n      for (var j = 0; j < group.ops.length; j++) {\n        var op = group.ops[j];\n        if (op.cursorActivityHandlers)\n          while (op.cursorActivityCalled < op.cursorActivityHandlers.length)\n            op.cursorActivityHandlers[op.cursorActivityCalled++](op.cm);\n      }\n    } while (i < callbacks.length);\n  }\n\n  // Finish an operation, updating the display and signalling delayed events\n  function endOperation(cm) {\n    var op = cm.curOp, group = op.ownsGroup;\n    if (!group) return;\n\n    try { fireCallbacksForOps(group); }\n    finally {\n      operationGroup = null;\n      for (var i = 0; i < group.ops.length; i++)\n        group.ops[i].cm.curOp = null;\n      endOperations(group);\n    }\n  }\n\n  // The DOM updates done when an operation finishes are batched so\n  // that the minimum number of relayouts are required.\n  function endOperations(group) {\n    var ops = group.ops;\n    for (var i = 0; i < ops.length; i++) // Read DOM\n      endOperation_R1(ops[i]);\n    for (var i = 0; i < ops.length; i++) // Write DOM (maybe)\n      endOperation_W1(ops[i]);\n    for (var i = 0; i < ops.length; i++) // Read DOM\n      endOperation_R2(ops[i]);\n    for (var i = 0; i < ops.length; i++) // Write DOM (maybe)\n      endOperation_W2(ops[i]);\n    for (var i = 0; i < ops.length; i++) // Read DOM\n      endOperation_finish(ops[i]);\n  }\n\n  function endOperation_R1(op) {\n    var cm = op.cm, display = cm.display;\n    maybeClipScrollbars(cm);\n    if (op.updateMaxLine) findMaxLine(cm);\n\n    op.mustUpdate = op.viewChanged || op.forceUpdate || op.scrollTop != null ||\n      op.scrollToPos && (op.scrollToPos.from.line < display.viewFrom ||\n                         op.scrollToPos.to.line >= display.viewTo) ||\n      display.maxLineChanged && cm.options.lineWrapping;\n    op.update = op.mustUpdate &&\n      new DisplayUpdate(cm, op.mustUpdate && {top: op.scrollTop, ensure: op.scrollToPos}, op.forceUpdate);\n  }\n\n  function endOperation_W1(op) {\n    op.updatedDisplay = op.mustUpdate && updateDisplayIfNeeded(op.cm, op.update);\n  }\n\n  function endOperation_R2(op) {\n    var cm = op.cm, display = cm.display;\n    if (op.updatedDisplay) updateHeightsInViewport(cm);\n\n    op.barMeasure = measureForScrollbars(cm);\n\n    // If the max line changed since it was last measured, measure it,\n    // and ensure the document's width matches it.\n    // updateDisplay_W2 will use these properties to do the actual resizing\n    if (display.maxLineChanged && !cm.options.lineWrapping) {\n      op.adjustWidthTo = measureChar(cm, display.maxLine, display.maxLine.text.length).left + 3;\n      cm.display.sizerWidth = op.adjustWidthTo;\n      op.barMeasure.scrollWidth =\n        Math.max(display.scroller.clientWidth, display.sizer.offsetLeft + op.adjustWidthTo + scrollGap(cm) + cm.display.barWidth);\n      op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo - displayWidth(cm));\n    }\n\n    if (op.updatedDisplay || op.selectionChanged)\n      op.preparedSelection = display.input.prepareSelection();\n  }\n\n  function endOperation_W2(op) {\n    var cm = op.cm;\n\n    if (op.adjustWidthTo != null) {\n      cm.display.sizer.style.minWidth = op.adjustWidthTo + \"px\";\n      if (op.maxScrollLeft < cm.doc.scrollLeft)\n        setScrollLeft(cm, Math.min(cm.display.scroller.scrollLeft, op.maxScrollLeft), true);\n      cm.display.maxLineChanged = false;\n    }\n\n    if (op.preparedSelection)\n      cm.display.input.showSelection(op.preparedSelection);\n    if (op.updatedDisplay)\n      setDocumentHeight(cm, op.barMeasure);\n    if (op.updatedDisplay || op.startHeight != cm.doc.height)\n      updateScrollbars(cm, op.barMeasure);\n\n    if (op.selectionChanged) restartBlink(cm);\n\n    if (cm.state.focused && op.updateInput)\n      cm.display.input.reset(op.typing);\n  }\n\n  function endOperation_finish(op) {\n    var cm = op.cm, display = cm.display, doc = cm.doc;\n\n    if (op.updatedDisplay) postUpdateDisplay(cm, op.update);\n\n    // Abort mouse wheel delta measurement, when scrolling explicitly\n    if (display.wheelStartX != null && (op.scrollTop != null || op.scrollLeft != null || op.scrollToPos))\n      display.wheelStartX = display.wheelStartY = null;\n\n    // Propagate the scroll position to the actual DOM scroller\n    if (op.scrollTop != null && (display.scroller.scrollTop != op.scrollTop || op.forceScroll)) {\n      doc.scrollTop = Math.max(0, Math.min(display.scroller.scrollHeight - display.scroller.clientHeight, op.scrollTop));\n      display.scrollbars.setScrollTop(doc.scrollTop);\n      display.scroller.scrollTop = doc.scrollTop;\n    }\n    if (op.scrollLeft != null && (display.scroller.scrollLeft != op.scrollLeft || op.forceScroll)) {\n      doc.scrollLeft = Math.max(0, Math.min(display.scroller.scrollWidth - displayWidth(cm), op.scrollLeft));\n      display.scrollbars.setScrollLeft(doc.scrollLeft);\n      display.scroller.scrollLeft = doc.scrollLeft;\n      alignHorizontally(cm);\n    }\n    // If we need to scroll a specific position into view, do so.\n    if (op.scrollToPos) {\n      var coords = scrollPosIntoView(cm, clipPos(doc, op.scrollToPos.from),\n                                     clipPos(doc, op.scrollToPos.to), op.scrollToPos.margin);\n      if (op.scrollToPos.isCursor && cm.state.focused) maybeScrollWindow(cm, coords);\n    }\n\n    // Fire events for markers that are hidden/unidden by editing or\n    // undoing\n    var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers;\n    if (hidden) for (var i = 0; i < hidden.length; ++i)\n      if (!hidden[i].lines.length) signal(hidden[i], \"hide\");\n    if (unhidden) for (var i = 0; i < unhidden.length; ++i)\n      if (unhidden[i].lines.length) signal(unhidden[i], \"unhide\");\n\n    if (display.wrapper.offsetHeight)\n      doc.scrollTop = cm.display.scroller.scrollTop;\n\n    // Fire change events, and delayed event handlers\n    if (op.changeObjs)\n      signal(cm, \"changes\", cm, op.changeObjs);\n    if (op.update)\n      op.update.finish();\n  }\n\n  // Run the given function in an operation\n  function runInOp(cm, f) {\n    if (cm.curOp) return f();\n    startOperation(cm);\n    try { return f(); }\n    finally { endOperation(cm); }\n  }\n  // Wraps a function in an operation. Returns the wrapped function.\n  function operation(cm, f) {\n    return function() {\n      if (cm.curOp) return f.apply(cm, arguments);\n      startOperation(cm);\n      try { return f.apply(cm, arguments); }\n      finally { endOperation(cm); }\n    };\n  }\n  // Used to add methods to editor and doc instances, wrapping them in\n  // operations.\n  function methodOp(f) {\n    return function() {\n      if (this.curOp) return f.apply(this, arguments);\n      startOperation(this);\n      try { return f.apply(this, arguments); }\n      finally { endOperation(this); }\n    };\n  }\n  function docMethodOp(f) {\n    return function() {\n      var cm = this.cm;\n      if (!cm || cm.curOp) return f.apply(this, arguments);\n      startOperation(cm);\n      try { return f.apply(this, arguments); }\n      finally { endOperation(cm); }\n    };\n  }\n\n  // VIEW TRACKING\n\n  // These objects are used to represent the visible (currently drawn)\n  // part of the document. A LineView may correspond to multiple\n  // logical lines, if those are connected by collapsed ranges.\n  function LineView(doc, line, lineN) {\n    // The starting line\n    this.line = line;\n    // Continuing lines, if any\n    this.rest = visualLineContinued(line);\n    // Number of logical lines in this visual line\n    this.size = this.rest ? lineNo(lst(this.rest)) - lineN + 1 : 1;\n    this.node = this.text = null;\n    this.hidden = lineIsHidden(doc, line);\n  }\n\n  // Create a range of LineView objects for the given lines.\n  function buildViewArray(cm, from, to) {\n    var array = [], nextPos;\n    for (var pos = from; pos < to; pos = nextPos) {\n      var view = new LineView(cm.doc, getLine(cm.doc, pos), pos);\n      nextPos = pos + view.size;\n      array.push(view);\n    }\n    return array;\n  }\n\n  // Updates the display.view data structure for a given change to the\n  // document. From and to are in pre-change coordinates. Lendiff is\n  // the amount of lines added or subtracted by the change. This is\n  // used for changes that span multiple lines, or change the way\n  // lines are divided into visual lines. regLineChange (below)\n  // registers single-line changes.\n  function regChange(cm, from, to, lendiff) {\n    if (from == null) from = cm.doc.first;\n    if (to == null) to = cm.doc.first + cm.doc.size;\n    if (!lendiff) lendiff = 0;\n\n    var display = cm.display;\n    if (lendiff && to < display.viewTo &&\n        (display.updateLineNumbers == null || display.updateLineNumbers > from))\n      display.updateLineNumbers = from;\n\n    cm.curOp.viewChanged = true;\n\n    if (from >= display.viewTo) { // Change after\n      if (sawCollapsedSpans && visualLineNo(cm.doc, from) < display.viewTo)\n        resetView(cm);\n    } else if (to <= display.viewFrom) { // Change before\n      if (sawCollapsedSpans && visualLineEndNo(cm.doc, to + lendiff) > display.viewFrom) {\n        resetView(cm);\n      } else {\n        display.viewFrom += lendiff;\n        display.viewTo += lendiff;\n      }\n    } else if (from <= display.viewFrom && to >= display.viewTo) { // Full overlap\n      resetView(cm);\n    } else if (from <= display.viewFrom) { // Top overlap\n      var cut = viewCuttingPoint(cm, to, to + lendiff, 1);\n      if (cut) {\n        display.view = display.view.slice(cut.index);\n        display.viewFrom = cut.lineN;\n        display.viewTo += lendiff;\n      } else {\n        resetView(cm);\n      }\n    } else if (to >= display.viewTo) { // Bottom overlap\n      var cut = viewCuttingPoint(cm, from, from, -1);\n      if (cut) {\n        display.view = display.view.slice(0, cut.index);\n        display.viewTo = cut.lineN;\n      } else {\n        resetView(cm);\n      }\n    } else { // Gap in the middle\n      var cutTop = viewCuttingPoint(cm, from, from, -1);\n      var cutBot = viewCuttingPoint(cm, to, to + lendiff, 1);\n      if (cutTop && cutBot) {\n        display.view = display.view.slice(0, cutTop.index)\n          .concat(buildViewArray(cm, cutTop.lineN, cutBot.lineN))\n          .concat(display.view.slice(cutBot.index));\n        display.viewTo += lendiff;\n      } else {\n        resetView(cm);\n      }\n    }\n\n    var ext = display.externalMeasured;\n    if (ext) {\n      if (to < ext.lineN)\n        ext.lineN += lendiff;\n      else if (from < ext.lineN + ext.size)\n        display.externalMeasured = null;\n    }\n  }\n\n  // Register a change to a single line. Type must be one of \"text\",\n  // \"gutter\", \"class\", \"widget\"\n  function regLineChange(cm, line, type) {\n    cm.curOp.viewChanged = true;\n    var display = cm.display, ext = cm.display.externalMeasured;\n    if (ext && line >= ext.lineN && line < ext.lineN + ext.size)\n      display.externalMeasured = null;\n\n    if (line < display.viewFrom || line >= display.viewTo) return;\n    var lineView = display.view[findViewIndex(cm, line)];\n    if (lineView.node == null) return;\n    var arr = lineView.changes || (lineView.changes = []);\n    if (indexOf(arr, type) == -1) arr.push(type);\n  }\n\n  // Clear the view.\n  function resetView(cm) {\n    cm.display.viewFrom = cm.display.viewTo = cm.doc.first;\n    cm.display.view = [];\n    cm.display.viewOffset = 0;\n  }\n\n  // Find the view element corresponding to a given line. Return null\n  // when the line isn't visible.\n  function findViewIndex(cm, n) {\n    if (n >= cm.display.viewTo) return null;\n    n -= cm.display.viewFrom;\n    if (n < 0) return null;\n    var view = cm.display.view;\n    for (var i = 0; i < view.length; i++) {\n      n -= view[i].size;\n      if (n < 0) return i;\n    }\n  }\n\n  function viewCuttingPoint(cm, oldN, newN, dir) {\n    var index = findViewIndex(cm, oldN), diff, view = cm.display.view;\n    if (!sawCollapsedSpans || newN == cm.doc.first + cm.doc.size)\n      return {index: index, lineN: newN};\n    for (var i = 0, n = cm.display.viewFrom; i < index; i++)\n      n += view[i].size;\n    if (n != oldN) {\n      if (dir > 0) {\n        if (index == view.length - 1) return null;\n        diff = (n + view[index].size) - oldN;\n        index++;\n      } else {\n        diff = n - oldN;\n      }\n      oldN += diff; newN += diff;\n    }\n    while (visualLineNo(cm.doc, newN) != newN) {\n      if (index == (dir < 0 ? 0 : view.length - 1)) return null;\n      newN += dir * view[index - (dir < 0 ? 1 : 0)].size;\n      index += dir;\n    }\n    return {index: index, lineN: newN};\n  }\n\n  // Force the view to cover a given range, adding empty view element\n  // or clipping off existing ones as needed.\n  function adjustView(cm, from, to) {\n    var display = cm.display, view = display.view;\n    if (view.length == 0 || from >= display.viewTo || to <= display.viewFrom) {\n      display.view = buildViewArray(cm, from, to);\n      display.viewFrom = from;\n    } else {\n      if (display.viewFrom > from)\n        display.view = buildViewArray(cm, from, display.viewFrom).concat(display.view);\n      else if (display.viewFrom < from)\n        display.view = display.view.slice(findViewIndex(cm, from));\n      display.viewFrom = from;\n      if (display.viewTo < to)\n        display.view = display.view.concat(buildViewArray(cm, display.viewTo, to));\n      else if (display.viewTo > to)\n        display.view = display.view.slice(0, findViewIndex(cm, to));\n    }\n    display.viewTo = to;\n  }\n\n  // Count the number of lines in the view whose DOM representation is\n  // out of date (or nonexistent).\n  function countDirtyView(cm) {\n    var view = cm.display.view, dirty = 0;\n    for (var i = 0; i < view.length; i++) {\n      var lineView = view[i];\n      if (!lineView.hidden && (!lineView.node || lineView.changes)) ++dirty;\n    }\n    return dirty;\n  }\n\n  // EVENT HANDLERS\n\n  // Attach the necessary event handlers when initializing the editor\n  function registerEventHandlers(cm) {\n    var d = cm.display;\n    on(d.scroller, \"mousedown\", operation(cm, onMouseDown));\n    // Older IE's will not fire a second mousedown for a double click\n    if (ie && ie_version < 11)\n      on(d.scroller, \"dblclick\", operation(cm, function(e) {\n        if (signalDOMEvent(cm, e)) return;\n        var pos = posFromMouse(cm, e);\n        if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) return;\n        e_preventDefault(e);\n        var word = cm.findWordAt(pos);\n        extendSelection(cm.doc, word.anchor, word.head);\n      }));\n    else\n      on(d.scroller, \"dblclick\", function(e) { signalDOMEvent(cm, e) || e_preventDefault(e); });\n    // Some browsers fire contextmenu *after* opening the menu, at\n    // which point we can't mess with it anymore. Context menu is\n    // handled in onMouseDown for these browsers.\n    if (!captureRightClick) on(d.scroller, \"contextmenu\", function(e) {onContextMenu(cm, e);});\n\n    // Used to suppress mouse event handling when a touch happens\n    var touchFinished, prevTouch = {end: 0};\n    function finishTouch() {\n      if (d.activeTouch) {\n        touchFinished = setTimeout(function() {d.activeTouch = null;}, 1000);\n        prevTouch = d.activeTouch;\n        prevTouch.end = +new Date;\n      }\n    };\n    function isMouseLikeTouchEvent(e) {\n      if (e.touches.length != 1) return false;\n      var touch = e.touches[0];\n      return touch.radiusX <= 1 && touch.radiusY <= 1;\n    }\n    function farAway(touch, other) {\n      if (other.left == null) return true;\n      var dx = other.left - touch.left, dy = other.top - touch.top;\n      return dx * dx + dy * dy > 20 * 20;\n    }\n    on(d.scroller, \"touchstart\", function(e) {\n      if (!isMouseLikeTouchEvent(e)) {\n        clearTimeout(touchFinished);\n        var now = +new Date;\n        d.activeTouch = {start: now, moved: false,\n                         prev: now - prevTouch.end <= 300 ? prevTouch : null};\n        if (e.touches.length == 1) {\n          d.activeTouch.left = e.touches[0].pageX;\n          d.activeTouch.top = e.touches[0].pageY;\n        }\n      }\n    });\n    on(d.scroller, \"touchmove\", function() {\n      if (d.activeTouch) d.activeTouch.moved = true;\n    });\n    on(d.scroller, \"touchend\", function(e) {\n      var touch = d.activeTouch;\n      if (touch && !eventInWidget(d, e) && touch.left != null &&\n          !touch.moved && new Date - touch.start < 300) {\n        var pos = cm.coordsChar(d.activeTouch, \"page\"), range;\n        if (!touch.prev || farAway(touch, touch.prev)) // Single tap\n          range = new Range(pos, pos);\n        else if (!touch.prev.prev || farAway(touch, touch.prev.prev)) // Double tap\n          range = cm.findWordAt(pos);\n        else // Triple tap\n          range = new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0)));\n        cm.setSelection(range.anchor, range.head);\n        cm.focus();\n        e_preventDefault(e);\n      }\n      finishTouch();\n    });\n    on(d.scroller, \"touchcancel\", finishTouch);\n\n    // Sync scrolling between fake scrollbars and real scrollable\n    // area, ensure viewport is updated when scrolling.\n    on(d.scroller, \"scroll\", function() {\n      if (d.scroller.clientHeight) {\n        setScrollTop(cm, d.scroller.scrollTop);\n        setScrollLeft(cm, d.scroller.scrollLeft, true);\n        signal(cm, \"scroll\", cm);\n      }\n    });\n\n    // Listen to wheel events in order to try and update the viewport on time.\n    on(d.scroller, \"mousewheel\", function(e){onScrollWheel(cm, e);});\n    on(d.scroller, \"DOMMouseScroll\", function(e){onScrollWheel(cm, e);});\n\n    // Prevent wrapper from ever scrolling\n    on(d.wrapper, \"scroll\", function() { d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; });\n\n    function drag_(e) {\n      if (!signalDOMEvent(cm, e)) e_stop(e);\n    }\n    if (cm.options.dragDrop) {\n      on(d.scroller, \"dragstart\", function(e){onDragStart(cm, e);});\n      on(d.scroller, \"dragenter\", drag_);\n      on(d.scroller, \"dragover\", drag_);\n      on(d.scroller, \"drop\", operation(cm, onDrop));\n    }\n\n    var inp = d.input.getField();\n    on(inp, \"keyup\", function(e) { onKeyUp.call(cm, e); });\n    on(inp, \"keydown\", operation(cm, onKeyDown));\n    on(inp, \"keypress\", operation(cm, onKeyPress));\n    on(inp, \"focus\", bind(onFocus, cm));\n    on(inp, \"blur\", bind(onBlur, cm));\n  }\n\n  // Called when the window resizes\n  function onResize(cm) {\n    var d = cm.display;\n    if (d.lastWrapHeight == d.wrapper.clientHeight && d.lastWrapWidth == d.wrapper.clientWidth)\n      return;\n    // Might be a text scaling operation, clear size caches.\n    d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;\n    d.scrollbarsClipped = false;\n    cm.setSize();\n  }\n\n  // MOUSE EVENTS\n\n  // Return true when the given mouse event happened in a widget\n  function eventInWidget(display, e) {\n    for (var n = e_target(e); n != display.wrapper; n = n.parentNode) {\n      if (!n || (n.nodeType == 1 && n.getAttribute(\"cm-ignore-events\") == \"true\") ||\n          (n.parentNode == display.sizer && n != display.mover))\n        return true;\n    }\n  }\n\n  // Given a mouse event, find the corresponding position. If liberal\n  // is false, it checks whether a gutter or scrollbar was clicked,\n  // and returns null if it was. forRect is used by rectangular\n  // selections, and tries to estimate a character position even for\n  // coordinates beyond the right of the text.\n  function posFromMouse(cm, e, liberal, forRect) {\n    var display = cm.display;\n    if (!liberal && e_target(e).getAttribute(\"cm-not-content\") == \"true\") return null;\n\n    var x, y, space = display.lineSpace.getBoundingClientRect();\n    // Fails unpredictably on IE[67] when mouse is dragged around quickly.\n    try { x = e.clientX - space.left; y = e.clientY - space.top; }\n    catch (e) { return null; }\n    var coords = coordsChar(cm, x, y), line;\n    if (forRect && coords.xRel == 1 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) {\n      var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length;\n      coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff));\n    }\n    return coords;\n  }\n\n  // A mouse down can be a single click, double click, triple click,\n  // start of selection drag, start of text drag, new cursor\n  // (ctrl-click), rectangle drag (alt-drag), or xwin\n  // middle-click-paste. Or it might be a click on something we should\n  // not interfere with, such as a scrollbar or widget.\n  function onMouseDown(e) {\n    var cm = this, display = cm.display;\n    if (display.activeTouch && display.input.supportsTouch() || signalDOMEvent(cm, e)) return;\n    display.shift = e.shiftKey;\n\n    if (eventInWidget(display, e)) {\n      if (!webkit) {\n        // Briefly turn off draggability, to allow widgets to do\n        // normal dragging things.\n        display.scroller.draggable = false;\n        setTimeout(function(){display.scroller.draggable = true;}, 100);\n      }\n      return;\n    }\n    if (clickInGutter(cm, e)) return;\n    var start = posFromMouse(cm, e);\n    window.focus();\n\n    switch (e_button(e)) {\n    case 1:\n      if (start)\n        leftButtonDown(cm, e, start);\n      else if (e_target(e) == display.scroller)\n        e_preventDefault(e);\n      break;\n    case 2:\n      if (webkit) cm.state.lastMiddleDown = +new Date;\n      if (start) extendSelection(cm.doc, start);\n      setTimeout(function() {display.input.focus();}, 20);\n      e_preventDefault(e);\n      break;\n    case 3:\n      if (captureRightClick) onContextMenu(cm, e);\n      break;\n    }\n  }\n\n  var lastClick, lastDoubleClick;\n  function leftButtonDown(cm, e, start) {\n    if (ie) setTimeout(bind(ensureFocus, cm), 0);\n    else ensureFocus(cm);\n\n    var now = +new Date, type;\n    if (lastDoubleClick && lastDoubleClick.time > now - 400 && cmp(lastDoubleClick.pos, start) == 0) {\n      type = \"triple\";\n    } else if (lastClick && lastClick.time > now - 400 && cmp(lastClick.pos, start) == 0) {\n      type = \"double\";\n      lastDoubleClick = {time: now, pos: start};\n    } else {\n      type = \"single\";\n      lastClick = {time: now, pos: start};\n    }\n\n    var sel = cm.doc.sel, modifier = mac ? e.metaKey : e.ctrlKey, contained;\n    if (cm.options.dragDrop && dragAndDrop && !isReadOnly(cm) &&\n        type == \"single\" && (contained = sel.contains(start)) > -1 &&\n        !sel.ranges[contained].empty())\n      leftButtonStartDrag(cm, e, start, modifier);\n    else\n      leftButtonSelect(cm, e, start, type, modifier);\n  }\n\n  // Start a text drag. When it ends, see if any dragging actually\n  // happen, and treat as a click if it didn't.\n  function leftButtonStartDrag(cm, e, start, modifier) {\n    var display = cm.display;\n    var dragEnd = operation(cm, function(e2) {\n      if (webkit) display.scroller.draggable = false;\n      cm.state.draggingText = false;\n      off(document, \"mouseup\", dragEnd);\n      off(display.scroller, \"drop\", dragEnd);\n      if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) {\n        e_preventDefault(e2);\n        if (!modifier)\n          extendSelection(cm.doc, start);\n        display.input.focus();\n        // Work around unexplainable focus problem in IE9 (#2127)\n        if (ie && ie_version == 9)\n          setTimeout(function() {document.body.focus(); display.input.focus();}, 20);\n      }\n    });\n    // Let the drag handler handle this.\n    if (webkit) display.scroller.draggable = true;\n    cm.state.draggingText = dragEnd;\n    // IE's approach to draggable\n    if (display.scroller.dragDrop) display.scroller.dragDrop();\n    on(document, \"mouseup\", dragEnd);\n    on(display.scroller, \"drop\", dragEnd);\n  }\n\n  // Normal selection, as opposed to text dragging.\n  function leftButtonSelect(cm, e, start, type, addNew) {\n    var display = cm.display, doc = cm.doc;\n    e_preventDefault(e);\n\n    var ourRange, ourIndex, startSel = doc.sel, ranges = startSel.ranges;\n    if (addNew && !e.shiftKey) {\n      ourIndex = doc.sel.contains(start);\n      if (ourIndex > -1)\n        ourRange = ranges[ourIndex];\n      else\n        ourRange = new Range(start, start);\n    } else {\n      ourRange = doc.sel.primary();\n    }\n\n    if (e.altKey) {\n      type = \"rect\";\n      if (!addNew) ourRange = new Range(start, start);\n      start = posFromMouse(cm, e, true, true);\n      ourIndex = -1;\n    } else if (type == \"double\") {\n      var word = cm.findWordAt(start);\n      if (cm.display.shift || doc.extend)\n        ourRange = extendRange(doc, ourRange, word.anchor, word.head);\n      else\n        ourRange = word;\n    } else if (type == \"triple\") {\n      var line = new Range(Pos(start.line, 0), clipPos(doc, Pos(start.line + 1, 0)));\n      if (cm.display.shift || doc.extend)\n        ourRange = extendRange(doc, ourRange, line.anchor, line.head);\n      else\n        ourRange = line;\n    } else {\n      ourRange = extendRange(doc, ourRange, start);\n    }\n\n    if (!addNew) {\n      ourIndex = 0;\n      setSelection(doc, new Selection([ourRange], 0), sel_mouse);\n      startSel = doc.sel;\n    } else if (ourIndex == -1) {\n      ourIndex = ranges.length;\n      setSelection(doc, normalizeSelection(ranges.concat([ourRange]), ourIndex),\n                   {scroll: false, origin: \"*mouse\"});\n    } else if (ranges.length > 1 && ranges[ourIndex].empty() && type == \"single\") {\n      setSelection(doc, normalizeSelection(ranges.slice(0, ourIndex).concat(ranges.slice(ourIndex + 1)), 0));\n      startSel = doc.sel;\n    } else {\n      replaceOneSelection(doc, ourIndex, ourRange, sel_mouse);\n    }\n\n    var lastPos = start;\n    function extendTo(pos) {\n      if (cmp(lastPos, pos) == 0) return;\n      lastPos = pos;\n\n      if (type == \"rect\") {\n        var ranges = [], tabSize = cm.options.tabSize;\n        var startCol = countColumn(getLine(doc, start.line).text, start.ch, tabSize);\n        var posCol = countColumn(getLine(doc, pos.line).text, pos.ch, tabSize);\n        var left = Math.min(startCol, posCol), right = Math.max(startCol, posCol);\n        for (var line = Math.min(start.line, pos.line), end = Math.min(cm.lastLine(), Math.max(start.line, pos.line));\n             line <= end; line++) {\n          var text = getLine(doc, line).text, leftPos = findColumn(text, left, tabSize);\n          if (left == right)\n            ranges.push(new Range(Pos(line, leftPos), Pos(line, leftPos)));\n          else if (text.length > leftPos)\n            ranges.push(new Range(Pos(line, leftPos), Pos(line, findColumn(text, right, tabSize))));\n        }\n        if (!ranges.length) ranges.push(new Range(start, start));\n        setSelection(doc, normalizeSelection(startSel.ranges.slice(0, ourIndex).concat(ranges), ourIndex),\n                     {origin: \"*mouse\", scroll: false});\n        cm.scrollIntoView(pos);\n      } else {\n        var oldRange = ourRange;\n        var anchor = oldRange.anchor, head = pos;\n        if (type != \"single\") {\n          if (type == \"double\")\n            var range = cm.findWordAt(pos);\n          else\n            var range = new Range(Pos(pos.line, 0), clipPos(doc, Pos(pos.line + 1, 0)));\n          if (cmp(range.anchor, anchor) > 0) {\n            head = range.head;\n            anchor = minPos(oldRange.from(), range.anchor);\n          } else {\n            head = range.anchor;\n            anchor = maxPos(oldRange.to(), range.head);\n          }\n        }\n        var ranges = startSel.ranges.slice(0);\n        ranges[ourIndex] = new Range(clipPos(doc, anchor), head);\n        setSelection(doc, normalizeSelection(ranges, ourIndex), sel_mouse);\n      }\n    }\n\n    var editorSize = display.wrapper.getBoundingClientRect();\n    // Used to ensure timeout re-tries don't fire when another extend\n    // happened in the meantime (clearTimeout isn't reliable -- at\n    // least on Chrome, the timeouts still happen even when cleared,\n    // if the clear happens after their scheduled firing time).\n    var counter = 0;\n\n    function extend(e) {\n      var curCount = ++counter;\n      var cur = posFromMouse(cm, e, true, type == \"rect\");\n      if (!cur) return;\n      if (cmp(cur, lastPos) != 0) {\n        ensureFocus(cm);\n        extendTo(cur);\n        var visible = visibleLines(display, doc);\n        if (cur.line >= visible.to || cur.line < visible.from)\n          setTimeout(operation(cm, function(){if (counter == curCount) extend(e);}), 150);\n      } else {\n        var outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0;\n        if (outside) setTimeout(operation(cm, function() {\n          if (counter != curCount) return;\n          display.scroller.scrollTop += outside;\n          extend(e);\n        }), 50);\n      }\n    }\n\n    function done(e) {\n      counter = Infinity;\n      e_preventDefault(e);\n      display.input.focus();\n      off(document, \"mousemove\", move);\n      off(document, \"mouseup\", up);\n      doc.history.lastSelOrigin = null;\n    }\n\n    var move = operation(cm, function(e) {\n      if (!e_button(e)) done(e);\n      else extend(e);\n    });\n    var up = operation(cm, done);\n    on(document, \"mousemove\", move);\n    on(document, \"mouseup\", up);\n  }\n\n  // Determines whether an event happened in the gutter, and fires the\n  // handlers for the corresponding event.\n  function gutterEvent(cm, e, type, prevent, signalfn) {\n    try { var mX = e.clientX, mY = e.clientY; }\n    catch(e) { return false; }\n    if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) return false;\n    if (prevent) e_preventDefault(e);\n\n    var display = cm.display;\n    var lineBox = display.lineDiv.getBoundingClientRect();\n\n    if (mY > lineBox.bottom || !hasHandler(cm, type)) return e_defaultPrevented(e);\n    mY -= lineBox.top - display.viewOffset;\n\n    for (var i = 0; i < cm.options.gutters.length; ++i) {\n      var g = display.gutters.childNodes[i];\n      if (g && g.getBoundingClientRect().right >= mX) {\n        var line = lineAtHeight(cm.doc, mY);\n        var gutter = cm.options.gutters[i];\n        signalfn(cm, type, cm, line, gutter, e);\n        return e_defaultPrevented(e);\n      }\n    }\n  }\n\n  function clickInGutter(cm, e) {\n    return gutterEvent(cm, e, \"gutterClick\", true, signalLater);\n  }\n\n  // Kludge to work around strange IE behavior where it'll sometimes\n  // re-fire a series of drag-related events right after the drop (#1551)\n  var lastDrop = 0;\n\n  function onDrop(e) {\n    var cm = this;\n    if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e))\n      return;\n    e_preventDefault(e);\n    if (ie) lastDrop = +new Date;\n    var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files;\n    if (!pos || isReadOnly(cm)) return;\n    // Might be a file drop, in which case we simply extract the text\n    // and insert it.\n    if (files && files.length && window.FileReader && window.File) {\n      var n = files.length, text = Array(n), read = 0;\n      var loadFile = function(file, i) {\n        var reader = new FileReader;\n        reader.onload = operation(cm, function() {\n          text[i] = reader.result;\n          if (++read == n) {\n            pos = clipPos(cm.doc, pos);\n            var change = {from: pos, to: pos, text: splitLines(text.join(\"\\n\")), origin: \"paste\"};\n            makeChange(cm.doc, change);\n            setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change)));\n          }\n        });\n        reader.readAsText(file);\n      };\n      for (var i = 0; i < n; ++i) loadFile(files[i], i);\n    } else { // Normal drop\n      // Don't do a replace if the drop happened inside of the selected text.\n      if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) {\n        cm.state.draggingText(e);\n        // Ensure the editor is re-focused\n        setTimeout(function() {cm.display.input.focus();}, 20);\n        return;\n      }\n      try {\n        var text = e.dataTransfer.getData(\"Text\");\n        if (text) {\n          if (cm.state.draggingText && !(mac ? e.metaKey : e.ctrlKey))\n            var selected = cm.listSelections();\n          setSelectionNoUndo(cm.doc, simpleSelection(pos, pos));\n          if (selected) for (var i = 0; i < selected.length; ++i)\n            replaceRange(cm.doc, \"\", selected[i].anchor, selected[i].head, \"drag\");\n          cm.replaceSelection(text, \"around\", \"paste\");\n          cm.display.input.focus();\n        }\n      }\n      catch(e){}\n    }\n  }\n\n  function onDragStart(cm, e) {\n    if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return; }\n    if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) return;\n\n    e.dataTransfer.setData(\"Text\", cm.getSelection());\n\n    // Use dummy image instead of default browsers image.\n    // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there.\n    if (e.dataTransfer.setDragImage && !safari) {\n      var img = elt(\"img\", null, null, \"position: fixed; left: 0; top: 0;\");\n      img.src = \"data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\";\n      if (presto) {\n        img.width = img.height = 1;\n        cm.display.wrapper.appendChild(img);\n        // Force a relayout, or Opera won't use our image for some obscure reason\n        img._top = img.offsetTop;\n      }\n      e.dataTransfer.setDragImage(img, 0, 0);\n      if (presto) img.parentNode.removeChild(img);\n    }\n  }\n\n  // SCROLL EVENTS\n\n  // Sync the scrollable area and scrollbars, ensure the viewport\n  // covers the visible area.\n  function setScrollTop(cm, val) {\n    if (Math.abs(cm.doc.scrollTop - val) < 2) return;\n    cm.doc.scrollTop = val;\n    if (!gecko) updateDisplaySimple(cm, {top: val});\n    if (cm.display.scroller.scrollTop != val) cm.display.scroller.scrollTop = val;\n    cm.display.scrollbars.setScrollTop(val);\n    if (gecko) updateDisplaySimple(cm);\n    startWorker(cm, 100);\n  }\n  // Sync scroller and scrollbar, ensure the gutter elements are\n  // aligned.\n  function setScrollLeft(cm, val, isScroller) {\n    if (isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) return;\n    val = Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth);\n    cm.doc.scrollLeft = val;\n    alignHorizontally(cm);\n    if (cm.display.scroller.scrollLeft != val) cm.display.scroller.scrollLeft = val;\n    cm.display.scrollbars.setScrollLeft(val);\n  }\n\n  // Since the delta values reported on mouse wheel events are\n  // unstandardized between browsers and even browser versions, and\n  // generally horribly unpredictable, this code starts by measuring\n  // the scroll effect that the first few mouse wheel events have,\n  // and, from that, detects the way it can convert deltas to pixel\n  // offsets afterwards.\n  //\n  // The reason we want to know the amount a wheel event will scroll\n  // is that it gives us a chance to update the display before the\n  // actual scrolling happens, reducing flickering.\n\n  var wheelSamples = 0, wheelPixelsPerUnit = null;\n  // Fill in a browser-detected starting value on browsers where we\n  // know one. These don't have to be accurate -- the result of them\n  // being wrong would just be a slight flicker on the first wheel\n  // scroll (if it is large enough).\n  if (ie) wheelPixelsPerUnit = -.53;\n  else if (gecko) wheelPixelsPerUnit = 15;\n  else if (chrome) wheelPixelsPerUnit = -.7;\n  else if (safari) wheelPixelsPerUnit = -1/3;\n\n  var wheelEventDelta = function(e) {\n    var dx = e.wheelDeltaX, dy = e.wheelDeltaY;\n    if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) dx = e.detail;\n    if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) dy = e.detail;\n    else if (dy == null) dy = e.wheelDelta;\n    return {x: dx, y: dy};\n  };\n  CodeMirror.wheelEventPixels = function(e) {\n    var delta = wheelEventDelta(e);\n    delta.x *= wheelPixelsPerUnit;\n    delta.y *= wheelPixelsPerUnit;\n    return delta;\n  };\n\n  function onScrollWheel(cm, e) {\n    var delta = wheelEventDelta(e), dx = delta.x, dy = delta.y;\n\n    var display = cm.display, scroll = display.scroller;\n    // Quit if there's nothing to scroll here\n    if (!(dx && scroll.scrollWidth > scroll.clientWidth ||\n          dy && scroll.scrollHeight > scroll.clientHeight)) return;\n\n    // Webkit browsers on OS X abort momentum scrolls when the target\n    // of the scroll event is removed from the scrollable element.\n    // This hack (see related code in patchDisplay) makes sure the\n    // element is kept around.\n    if (dy && mac && webkit) {\n      outer: for (var cur = e.target, view = display.view; cur != scroll; cur = cur.parentNode) {\n        for (var i = 0; i < view.length; i++) {\n          if (view[i].node == cur) {\n            cm.display.currentWheelTarget = cur;\n            break outer;\n          }\n        }\n      }\n    }\n\n    // On some browsers, horizontal scrolling will cause redraws to\n    // happen before the gutter has been realigned, causing it to\n    // wriggle around in a most unseemly way. When we have an\n    // estimated pixels/delta value, we just handle horizontal\n    // scrolling entirely here. It'll be slightly off from native, but\n    // better than glitching out.\n    if (dx && !gecko && !presto && wheelPixelsPerUnit != null) {\n      if (dy)\n        setScrollTop(cm, Math.max(0, Math.min(scroll.scrollTop + dy * wheelPixelsPerUnit, scroll.scrollHeight - scroll.clientHeight)));\n      setScrollLeft(cm, Math.max(0, Math.min(scroll.scrollLeft + dx * wheelPixelsPerUnit, scroll.scrollWidth - scroll.clientWidth)));\n      e_preventDefault(e);\n      display.wheelStartX = null; // Abort measurement, if in progress\n      return;\n    }\n\n    // 'Project' the visible viewport to cover the area that is being\n    // scrolled into view (if we know enough to estimate it).\n    if (dy && wheelPixelsPerUnit != null) {\n      var pixels = dy * wheelPixelsPerUnit;\n      var top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight;\n      if (pixels < 0) top = Math.max(0, top + pixels - 50);\n      else bot = Math.min(cm.doc.height, bot + pixels + 50);\n      updateDisplaySimple(cm, {top: top, bottom: bot});\n    }\n\n    if (wheelSamples < 20) {\n      if (display.wheelStartX == null) {\n        display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop;\n        display.wheelDX = dx; display.wheelDY = dy;\n        setTimeout(function() {\n          if (display.wheelStartX == null) return;\n          var movedX = scroll.scrollLeft - display.wheelStartX;\n          var movedY = scroll.scrollTop - display.wheelStartY;\n          var sample = (movedY && display.wheelDY && movedY / display.wheelDY) ||\n            (movedX && display.wheelDX && movedX / display.wheelDX);\n          display.wheelStartX = display.wheelStartY = null;\n          if (!sample) return;\n          wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1);\n          ++wheelSamples;\n        }, 200);\n      } else {\n        display.wheelDX += dx; display.wheelDY += dy;\n      }\n    }\n  }\n\n  // KEY EVENTS\n\n  // Run a handler that was bound to a key.\n  function doHandleBinding(cm, bound, dropShift) {\n    if (typeof bound == \"string\") {\n      bound = commands[bound];\n      if (!bound) return false;\n    }\n    // Ensure previous input has been read, so that the handler sees a\n    // consistent view of the document\n    cm.display.input.ensurePolled();\n    var prevShift = cm.display.shift, done = false;\n    try {\n      if (isReadOnly(cm)) cm.state.suppressEdits = true;\n      if (dropShift) cm.display.shift = false;\n      done = bound(cm) != Pass;\n    } finally {\n      cm.display.shift = prevShift;\n      cm.state.suppressEdits = false;\n    }\n    return done;\n  }\n\n  function lookupKeyForEditor(cm, name, handle) {\n    for (var i = 0; i < cm.state.keyMaps.length; i++) {\n      var result = lookupKey(name, cm.state.keyMaps[i], handle, cm);\n      if (result) return result;\n    }\n    return (cm.options.extraKeys && lookupKey(name, cm.options.extraKeys, handle, cm))\n      || lookupKey(name, cm.options.keyMap, handle, cm);\n  }\n\n  var stopSeq = new Delayed;\n  function dispatchKey(cm, name, e, handle) {\n    var seq = cm.state.keySeq;\n    if (seq) {\n      if (isModifierKey(name)) return \"handled\";\n      stopSeq.set(50, function() {\n        if (cm.state.keySeq == seq) {\n          cm.state.keySeq = null;\n          cm.display.input.reset();\n        }\n      });\n      name = seq + \" \" + name;\n    }\n    var result = lookupKeyForEditor(cm, name, handle);\n\n    if (result == \"multi\")\n      cm.state.keySeq = name;\n    if (result == \"handled\")\n      signalLater(cm, \"keyHandled\", cm, name, e);\n\n    if (result == \"handled\" || result == \"multi\") {\n      e_preventDefault(e);\n      restartBlink(cm);\n    }\n\n    if (seq && !result && /\\'$/.test(name)) {\n      e_preventDefault(e);\n      return true;\n    }\n    return !!result;\n  }\n\n  // Handle a key from the keydown event.\n  function handleKeyBinding(cm, e) {\n    var name = keyName(e, true);\n    if (!name) return false;\n\n    if (e.shiftKey && !cm.state.keySeq) {\n      // First try to resolve full name (including 'Shift-'). Failing\n      // that, see if there is a cursor-motion command (starting with\n      // 'go') bound to the keyname without 'Shift-'.\n      return dispatchKey(cm, \"Shift-\" + name, e, function(b) {return doHandleBinding(cm, b, true);})\n          || dispatchKey(cm, name, e, function(b) {\n               if (typeof b == \"string\" ? /^go[A-Z]/.test(b) : b.motion)\n                 return doHandleBinding(cm, b);\n             });\n    } else {\n      return dispatchKey(cm, name, e, function(b) { return doHandleBinding(cm, b); });\n    }\n  }\n\n  // Handle a key from the keypress event\n  function handleCharBinding(cm, e, ch) {\n    return dispatchKey(cm, \"'\" + ch + \"'\", e,\n                       function(b) { return doHandleBinding(cm, b, true); });\n  }\n\n  var lastStoppedKey = null;\n  function onKeyDown(e) {\n    var cm = this;\n    ensureFocus(cm);\n    if (signalDOMEvent(cm, e)) return;\n    // IE does strange things with escape.\n    if (ie && ie_version < 11 && e.keyCode == 27) e.returnValue = false;\n    var code = e.keyCode;\n    cm.display.shift = code == 16 || e.shiftKey;\n    var handled = handleKeyBinding(cm, e);\n    if (presto) {\n      lastStoppedKey = handled ? code : null;\n      // Opera has no cut event... we try to at least catch the key combo\n      if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey))\n        cm.replaceSelection(\"\", null, \"cut\");\n    }\n\n    // Turn mouse into crosshair when Alt is held on Mac.\n    if (code == 18 && !/\\bCodeMirror-crosshair\\b/.test(cm.display.lineDiv.className))\n      showCrossHair(cm);\n  }\n\n  function showCrossHair(cm) {\n    var lineDiv = cm.display.lineDiv;\n    addClass(lineDiv, \"CodeMirror-crosshair\");\n\n    function up(e) {\n      if (e.keyCode == 18 || !e.altKey) {\n        rmClass(lineDiv, \"CodeMirror-crosshair\");\n        off(document, \"keyup\", up);\n        off(document, \"mouseover\", up);\n      }\n    }\n    on(document, \"keyup\", up);\n    on(document, \"mouseover\", up);\n  }\n\n  function onKeyUp(e) {\n    if (e.keyCode == 16) this.doc.sel.shift = false;\n    signalDOMEvent(this, e);\n  }\n\n  function onKeyPress(e) {\n    var cm = this;\n    if (eventInWidget(cm.display, e) || signalDOMEvent(cm, e) || e.ctrlKey && !e.altKey || mac && e.metaKey) return;\n    var keyCode = e.keyCode, charCode = e.charCode;\n    if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return;}\n    if ((presto && (!e.which || e.which < 10)) && handleKeyBinding(cm, e)) return;\n    var ch = String.fromCharCode(charCode == null ? keyCode : charCode);\n    if (handleCharBinding(cm, e, ch)) return;\n    cm.display.input.onKeyPress(e);\n  }\n\n  // FOCUS/BLUR EVENTS\n\n  function onFocus(cm) {\n    if (cm.options.readOnly == \"nocursor\") return;\n    if (!cm.state.focused) {\n      signal(cm, \"focus\", cm);\n      cm.state.focused = true;\n      addClass(cm.display.wrapper, \"CodeMirror-focused\");\n      // This test prevents this from firing when a context\n      // menu is closed (since the input reset would kill the\n      // select-all detection hack)\n      if (!cm.curOp && cm.display.selForContextMenu != cm.doc.sel) {\n        cm.display.input.reset();\n        if (webkit) setTimeout(function() { cm.display.input.reset(true); }, 20); // Issue #1730\n      }\n      cm.display.input.receivedFocus();\n    }\n    restartBlink(cm);\n  }\n  function onBlur(cm) {\n    if (cm.state.focused) {\n      signal(cm, \"blur\", cm);\n      cm.state.focused = false;\n      rmClass(cm.display.wrapper, \"CodeMirror-focused\");\n    }\n    clearInterval(cm.display.blinker);\n    setTimeout(function() {if (!cm.state.focused) cm.display.shift = false;}, 150);\n  }\n\n  // CONTEXT MENU HANDLING\n\n  // To make the context menu work, we need to briefly unhide the\n  // textarea (making it as unobtrusive as possible) to let the\n  // right-click take effect on it.\n  function onContextMenu(cm, e) {\n    if (eventInWidget(cm.display, e) || contextMenuInGutter(cm, e)) return;\n    cm.display.input.onContextMenu(e);\n  }\n\n  function contextMenuInGutter(cm, e) {\n    if (!hasHandler(cm, \"gutterContextMenu\")) return false;\n    return gutterEvent(cm, e, \"gutterContextMenu\", false, signal);\n  }\n\n  // UPDATING\n\n  // Compute the position of the end of a change (its 'to' property\n  // refers to the pre-change end).\n  var changeEnd = CodeMirror.changeEnd = function(change) {\n    if (!change.text) return change.to;\n    return Pos(change.from.line + change.text.length - 1,\n               lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0));\n  };\n\n  // Adjust a position to refer to the post-change position of the\n  // same text, or the end of the change if the change covers it.\n  function adjustForChange(pos, change) {\n    if (cmp(pos, change.from) < 0) return pos;\n    if (cmp(pos, change.to) <= 0) return changeEnd(change);\n\n    var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch;\n    if (pos.line == change.to.line) ch += changeEnd(change).ch - change.to.ch;\n    return Pos(line, ch);\n  }\n\n  function computeSelAfterChange(doc, change) {\n    var out = [];\n    for (var i = 0; i < doc.sel.ranges.length; i++) {\n      var range = doc.sel.ranges[i];\n      out.push(new Range(adjustForChange(range.anchor, change),\n                         adjustForChange(range.head, change)));\n    }\n    return normalizeSelection(out, doc.sel.primIndex);\n  }\n\n  function offsetPos(pos, old, nw) {\n    if (pos.line == old.line)\n      return Pos(nw.line, pos.ch - old.ch + nw.ch);\n    else\n      return Pos(nw.line + (pos.line - old.line), pos.ch);\n  }\n\n  // Used by replaceSelections to allow moving the selection to the\n  // start or around the replaced test. Hint may be \"start\" or \"around\".\n  function computeReplacedSel(doc, changes, hint) {\n    var out = [];\n    var oldPrev = Pos(doc.first, 0), newPrev = oldPrev;\n    for (var i = 0; i < changes.length; i++) {\n      var change = changes[i];\n      var from = offsetPos(change.from, oldPrev, newPrev);\n      var to = offsetPos(changeEnd(change), oldPrev, newPrev);\n      oldPrev = change.to;\n      newPrev = to;\n      if (hint == \"around\") {\n        var range = doc.sel.ranges[i], inv = cmp(range.head, range.anchor) < 0;\n        out[i] = new Range(inv ? to : from, inv ? from : to);\n      } else {\n        out[i] = new Range(from, from);\n      }\n    }\n    return new Selection(out, doc.sel.primIndex);\n  }\n\n  // Allow \"beforeChange\" event handlers to influence a change\n  function filterChange(doc, change, update) {\n    var obj = {\n      canceled: false,\n      from: change.from,\n      to: change.to,\n      text: change.text,\n      origin: change.origin,\n      cancel: function() { this.canceled = true; }\n    };\n    if (update) obj.update = function(from, to, text, origin) {\n      if (from) this.from = clipPos(doc, from);\n      if (to) this.to = clipPos(doc, to);\n      if (text) this.text = text;\n      if (origin !== undefined) this.origin = origin;\n    };\n    signal(doc, \"beforeChange\", doc, obj);\n    if (doc.cm) signal(doc.cm, \"beforeChange\", doc.cm, obj);\n\n    if (obj.canceled) return null;\n    return {from: obj.from, to: obj.to, text: obj.text, origin: obj.origin};\n  }\n\n  // Apply a change to a document, and add it to the document's\n  // history, and propagating it to all linked documents.\n  function makeChange(doc, change, ignoreReadOnly) {\n    if (doc.cm) {\n      if (!doc.cm.curOp) return operation(doc.cm, makeChange)(doc, change, ignoreReadOnly);\n      if (doc.cm.state.suppressEdits) return;\n    }\n\n    if (hasHandler(doc, \"beforeChange\") || doc.cm && hasHandler(doc.cm, \"beforeChange\")) {\n      change = filterChange(doc, change, true);\n      if (!change) return;\n    }\n\n    // Possibly split or suppress the update based on the presence\n    // of read-only spans in its range.\n    var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to);\n    if (split) {\n      for (var i = split.length - 1; i >= 0; --i)\n        makeChangeInner(doc, {from: split[i].from, to: split[i].to, text: i ? [\"\"] : change.text});\n    } else {\n      makeChangeInner(doc, change);\n    }\n  }\n\n  function makeChangeInner(doc, change) {\n    if (change.text.length == 1 && change.text[0] == \"\" && cmp(change.from, change.to) == 0) return;\n    var selAfter = computeSelAfterChange(doc, change);\n    addChangeToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN);\n\n    makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change));\n    var rebased = [];\n\n    linkedDocs(doc, function(doc, sharedHist) {\n      if (!sharedHist && indexOf(rebased, doc.history) == -1) {\n        rebaseHist(doc.history, change);\n        rebased.push(doc.history);\n      }\n      makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change));\n    });\n  }\n\n  // Revert a change stored in a document's history.\n  function makeChangeFromHistory(doc, type, allowSelectionOnly) {\n    if (doc.cm && doc.cm.state.suppressEdits) return;\n\n    var hist = doc.history, event, selAfter = doc.sel;\n    var source = type == \"undo\" ? hist.done : hist.undone, dest = type == \"undo\" ? hist.undone : hist.done;\n\n    // Verify that there is a useable event (so that ctrl-z won't\n    // needlessly clear selection events)\n    for (var i = 0; i < source.length; i++) {\n      event = source[i];\n      if (allowSelectionOnly ? event.ranges && !event.equals(doc.sel) : !event.ranges)\n        break;\n    }\n    if (i == source.length) return;\n    hist.lastOrigin = hist.lastSelOrigin = null;\n\n    for (;;) {\n      event = source.pop();\n      if (event.ranges) {\n        pushSelectionToHistory(event, dest);\n        if (allowSelectionOnly && !event.equals(doc.sel)) {\n          setSelection(doc, event, {clearRedo: false});\n          return;\n        }\n        selAfter = event;\n      }\n      else break;\n    }\n\n    // Build up a reverse change object to add to the opposite history\n    // stack (redo when undoing, and vice versa).\n    var antiChanges = [];\n    pushSelectionToHistory(selAfter, dest);\n    dest.push({changes: antiChanges, generation: hist.generation});\n    hist.generation = event.generation || ++hist.maxGeneration;\n\n    var filter = hasHandler(doc, \"beforeChange\") || doc.cm && hasHandler(doc.cm, \"beforeChange\");\n\n    for (var i = event.changes.length - 1; i >= 0; --i) {\n      var change = event.changes[i];\n      change.origin = type;\n      if (filter && !filterChange(doc, change, false)) {\n        source.length = 0;\n        return;\n      }\n\n      antiChanges.push(historyChangeFromChange(doc, change));\n\n      var after = i ? computeSelAfterChange(doc, change) : lst(source);\n      makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change));\n      if (!i && doc.cm) doc.cm.scrollIntoView({from: change.from, to: changeEnd(change)});\n      var rebased = [];\n\n      // Propagate to the linked documents\n      linkedDocs(doc, function(doc, sharedHist) {\n        if (!sharedHist && indexOf(rebased, doc.history) == -1) {\n          rebaseHist(doc.history, change);\n          rebased.push(doc.history);\n        }\n        makeChangeSingleDoc(doc, change, null, mergeOldSpans(doc, change));\n      });\n    }\n  }\n\n  // Sub-views need their line numbers shifted when text is added\n  // above or below them in the parent document.\n  function shiftDoc(doc, distance) {\n    if (distance == 0) return;\n    doc.first += distance;\n    doc.sel = new Selection(map(doc.sel.ranges, function(range) {\n      return new Range(Pos(range.anchor.line + distance, range.anchor.ch),\n                       Pos(range.head.line + distance, range.head.ch));\n    }), doc.sel.primIndex);\n    if (doc.cm) {\n      regChange(doc.cm, doc.first, doc.first - distance, distance);\n      for (var d = doc.cm.display, l = d.viewFrom; l < d.viewTo; l++)\n        regLineChange(doc.cm, l, \"gutter\");\n    }\n  }\n\n  // More lower-level change function, handling only a single document\n  // (not linked ones).\n  function makeChangeSingleDoc(doc, change, selAfter, spans) {\n    if (doc.cm && !doc.cm.curOp)\n      return operation(doc.cm, makeChangeSingleDoc)(doc, change, selAfter, spans);\n\n    if (change.to.line < doc.first) {\n      shiftDoc(doc, change.text.length - 1 - (change.to.line - change.from.line));\n      return;\n    }\n    if (change.from.line > doc.lastLine()) return;\n\n    // Clip the change to the size of this doc\n    if (change.from.line < doc.first) {\n      var shift = change.text.length - 1 - (doc.first - change.from.line);\n      shiftDoc(doc, shift);\n      change = {from: Pos(doc.first, 0), to: Pos(change.to.line + shift, change.to.ch),\n                text: [lst(change.text)], origin: change.origin};\n    }\n    var last = doc.lastLine();\n    if (change.to.line > last) {\n      change = {from: change.from, to: Pos(last, getLine(doc, last).text.length),\n                text: [change.text[0]], origin: change.origin};\n    }\n\n    change.removed = getBetween(doc, change.from, change.to);\n\n    if (!selAfter) selAfter = computeSelAfterChange(doc, change);\n    if (doc.cm) makeChangeSingleDocInEditor(doc.cm, change, spans);\n    else updateDoc(doc, change, spans);\n    setSelectionNoUndo(doc, selAfter, sel_dontScroll);\n  }\n\n  // Handle the interaction of a change to a document with the editor\n  // that this document is part of.\n  function makeChangeSingleDocInEditor(cm, change, spans) {\n    var doc = cm.doc, display = cm.display, from = change.from, to = change.to;\n\n    var recomputeMaxLength = false, checkWidthStart = from.line;\n    if (!cm.options.lineWrapping) {\n      checkWidthStart = lineNo(visualLine(getLine(doc, from.line)));\n      doc.iter(checkWidthStart, to.line + 1, function(line) {\n        if (line == display.maxLine) {\n          recomputeMaxLength = true;\n          return true;\n        }\n      });\n    }\n\n    if (doc.sel.contains(change.from, change.to) > -1)\n      signalCursorActivity(cm);\n\n    updateDoc(doc, change, spans, estimateHeight(cm));\n\n    if (!cm.options.lineWrapping) {\n      doc.iter(checkWidthStart, from.line + change.text.length, function(line) {\n        var len = lineLength(line);\n        if (len > display.maxLineLength) {\n          display.maxLine = line;\n          display.maxLineLength = len;\n          display.maxLineChanged = true;\n          recomputeMaxLength = false;\n        }\n      });\n      if (recomputeMaxLength) cm.curOp.updateMaxLine = true;\n    }\n\n    // Adjust frontier, schedule worker\n    doc.frontier = Math.min(doc.frontier, from.line);\n    startWorker(cm, 400);\n\n    var lendiff = change.text.length - (to.line - from.line) - 1;\n    // Remember that these lines changed, for updating the display\n    if (change.full)\n      regChange(cm);\n    else if (from.line == to.line && change.text.length == 1 && !isWholeLineUpdate(cm.doc, change))\n      regLineChange(cm, from.line, \"text\");\n    else\n      regChange(cm, from.line, to.line + 1, lendiff);\n\n    var changesHandler = hasHandler(cm, \"changes\"), changeHandler = hasHandler(cm, \"change\");\n    if (changeHandler || changesHandler) {\n      var obj = {\n        from: from, to: to,\n        text: change.text,\n        removed: change.removed,\n        origin: change.origin\n      };\n      if (changeHandler) signalLater(cm, \"change\", cm, obj);\n      if (changesHandler) (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push(obj);\n    }\n    cm.display.selForContextMenu = null;\n  }\n\n  function replaceRange(doc, code, from, to, origin) {\n    if (!to) to = from;\n    if (cmp(to, from) < 0) { var tmp = to; to = from; from = tmp; }\n    if (typeof code == \"string\") code = splitLines(code);\n    makeChange(doc, {from: from, to: to, text: code, origin: origin});\n  }\n\n  // SCROLLING THINGS INTO VIEW\n\n  // If an editor sits on the top or bottom of the window, partially\n  // scrolled out of view, this ensures that the cursor is visible.\n  function maybeScrollWindow(cm, coords) {\n    if (signalDOMEvent(cm, \"scrollCursorIntoView\")) return;\n\n    var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null;\n    if (coords.top + box.top < 0) doScroll = true;\n    else if (coords.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) doScroll = false;\n    if (doScroll != null && !phantom) {\n      var scrollNode = elt(\"div\", \"\\u200b\", null, \"position: absolute; top: \" +\n                           (coords.top - display.viewOffset - paddingTop(cm.display)) + \"px; height: \" +\n                           (coords.bottom - coords.top + scrollGap(cm) + display.barHeight) + \"px; left: \" +\n                           coords.left + \"px; width: 2px;\");\n      cm.display.lineSpace.appendChild(scrollNode);\n      scrollNode.scrollIntoView(doScroll);\n      cm.display.lineSpace.removeChild(scrollNode);\n    }\n  }\n\n  // Scroll a given position into view (immediately), verifying that\n  // it actually became visible (as line heights are accurately\n  // measured, the position of something may 'drift' during drawing).\n  function scrollPosIntoView(cm, pos, end, margin) {\n    if (margin == null) margin = 0;\n    for (var limit = 0; limit < 5; limit++) {\n      var changed = false, coords = cursorCoords(cm, pos);\n      var endCoords = !end || end == pos ? coords : cursorCoords(cm, end);\n      var scrollPos = calculateScrollPos(cm, Math.min(coords.left, endCoords.left),\n                                         Math.min(coords.top, endCoords.top) - margin,\n                                         Math.max(coords.left, endCoords.left),\n                                         Math.max(coords.bottom, endCoords.bottom) + margin);\n      var startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft;\n      if (scrollPos.scrollTop != null) {\n        setScrollTop(cm, scrollPos.scrollTop);\n        if (Math.abs(cm.doc.scrollTop - startTop) > 1) changed = true;\n      }\n      if (scrollPos.scrollLeft != null) {\n        setScrollLeft(cm, scrollPos.scrollLeft);\n        if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) changed = true;\n      }\n      if (!changed) break;\n    }\n    return coords;\n  }\n\n  // Scroll a given set of coordinates into view (immediately).\n  function scrollIntoView(cm, x1, y1, x2, y2) {\n    var scrollPos = calculateScrollPos(cm, x1, y1, x2, y2);\n    if (scrollPos.scrollTop != null) setScrollTop(cm, scrollPos.scrollTop);\n    if (scrollPos.scrollLeft != null) setScrollLeft(cm, scrollPos.scrollLeft);\n  }\n\n  // Calculate a new scroll position needed to scroll the given\n  // rectangle into view. Returns an object with scrollTop and\n  // scrollLeft properties. When these are undefined, the\n  // vertical/horizontal position does not need to be adjusted.\n  function calculateScrollPos(cm, x1, y1, x2, y2) {\n    var display = cm.display, snapMargin = textHeight(cm.display);\n    if (y1 < 0) y1 = 0;\n    var screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop;\n    var screen = displayHeight(cm), result = {};\n    if (y2 - y1 > screen) y2 = y1 + screen;\n    var docBottom = cm.doc.height + paddingVert(display);\n    var atTop = y1 < snapMargin, atBottom = y2 > docBottom - snapMargin;\n    if (y1 < screentop) {\n      result.scrollTop = atTop ? 0 : y1;\n    } else if (y2 > screentop + screen) {\n      var newTop = Math.min(y1, (atBottom ? docBottom : y2) - screen);\n      if (newTop != screentop) result.scrollTop = newTop;\n    }\n\n    var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft;\n    var screenw = displayWidth(cm) - (cm.options.fixedGutter ? display.gutters.offsetWidth : 0);\n    var tooWide = x2 - x1 > screenw;\n    if (tooWide) x2 = x1 + screenw;\n    if (x1 < 10)\n      result.scrollLeft = 0;\n    else if (x1 < screenleft)\n      result.scrollLeft = Math.max(0, x1 - (tooWide ? 0 : 10));\n    else if (x2 > screenw + screenleft - 3)\n      result.scrollLeft = x2 + (tooWide ? 0 : 10) - screenw;\n    return result;\n  }\n\n  // Store a relative adjustment to the scroll position in the current\n  // operation (to be applied when the operation finishes).\n  function addToScrollPos(cm, left, top) {\n    if (left != null || top != null) resolveScrollToPos(cm);\n    if (left != null)\n      cm.curOp.scrollLeft = (cm.curOp.scrollLeft == null ? cm.doc.scrollLeft : cm.curOp.scrollLeft) + left;\n    if (top != null)\n      cm.curOp.scrollTop = (cm.curOp.scrollTop == null ? cm.doc.scrollTop : cm.curOp.scrollTop) + top;\n  }\n\n  // Make sure that at the end of the operation the current cursor is\n  // shown.\n  function ensureCursorVisible(cm) {\n    resolveScrollToPos(cm);\n    var cur = cm.getCursor(), from = cur, to = cur;\n    if (!cm.options.lineWrapping) {\n      from = cur.ch ? Pos(cur.line, cur.ch - 1) : cur;\n      to = Pos(cur.line, cur.ch + 1);\n    }\n    cm.curOp.scrollToPos = {from: from, to: to, margin: cm.options.cursorScrollMargin, isCursor: true};\n  }\n\n  // When an operation has its scrollToPos property set, and another\n  // scroll action is applied before the end of the operation, this\n  // 'simulates' scrolling that position into view in a cheap way, so\n  // that the effect of intermediate scroll commands is not ignored.\n  function resolveScrollToPos(cm) {\n    var range = cm.curOp.scrollToPos;\n    if (range) {\n      cm.curOp.scrollToPos = null;\n      var from = estimateCoords(cm, range.from), to = estimateCoords(cm, range.to);\n      var sPos = calculateScrollPos(cm, Math.min(from.left, to.left),\n                                    Math.min(from.top, to.top) - range.margin,\n                                    Math.max(from.right, to.right),\n                                    Math.max(from.bottom, to.bottom) + range.margin);\n      cm.scrollTo(sPos.scrollLeft, sPos.scrollTop);\n    }\n  }\n\n  // API UTILITIES\n\n  // Indent the given line. The how parameter can be \"smart\",\n  // \"add\"/null, \"subtract\", or \"prev\". When aggressive is false\n  // (typically set to true for forced single-line indents), empty\n  // lines are not indented, and places where the mode returns Pass\n  // are left alone.\n  function indentLine(cm, n, how, aggressive) {\n    var doc = cm.doc, state;\n    if (how == null) how = \"add\";\n    if (how == \"smart\") {\n      // Fall back to \"prev\" when the mode doesn't have an indentation\n      // method.\n      if (!doc.mode.indent) how = \"prev\";\n      else state = getStateBefore(cm, n);\n    }\n\n    var tabSize = cm.options.tabSize;\n    var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize);\n    if (line.stateAfter) line.stateAfter = null;\n    var curSpaceString = line.text.match(/^\\s*/)[0], indentation;\n    if (!aggressive && !/\\S/.test(line.text)) {\n      indentation = 0;\n      how = \"not\";\n    } else if (how == \"smart\") {\n      indentation = doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text);\n      if (indentation == Pass || indentation > 150) {\n        if (!aggressive) return;\n        how = \"prev\";\n      }\n    }\n    if (how == \"prev\") {\n      if (n > doc.first) indentation = countColumn(getLine(doc, n-1).text, null, tabSize);\n      else indentation = 0;\n    } else if (how == \"add\") {\n      indentation = curSpace + cm.options.indentUnit;\n    } else if (how == \"subtract\") {\n      indentation = curSpace - cm.options.indentUnit;\n    } else if (typeof how == \"number\") {\n      indentation = curSpace + how;\n    }\n    indentation = Math.max(0, indentation);\n\n    var indentString = \"\", pos = 0;\n    if (cm.options.indentWithTabs)\n      for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += \"\\t\";}\n    if (pos < indentation) indentString += spaceStr(indentation - pos);\n\n    if (indentString != curSpaceString) {\n      replaceRange(doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), \"+input\");\n    } else {\n      // Ensure that, if the cursor was in the whitespace at the start\n      // of the line, it is moved to the end of that space.\n      for (var i = 0; i < doc.sel.ranges.length; i++) {\n        var range = doc.sel.ranges[i];\n        if (range.head.line == n && range.head.ch < curSpaceString.length) {\n          var pos = Pos(n, curSpaceString.length);\n          replaceOneSelection(doc, i, new Range(pos, pos));\n          break;\n        }\n      }\n    }\n    line.stateAfter = null;\n  }\n\n  // Utility for applying a change to a line by handle or number,\n  // returning the number and optionally registering the line as\n  // changed.\n  function changeLine(doc, handle, changeType, op) {\n    var no = handle, line = handle;\n    if (typeof handle == \"number\") line = getLine(doc, clipLine(doc, handle));\n    else no = lineNo(handle);\n    if (no == null) return null;\n    if (op(line, no) && doc.cm) regLineChange(doc.cm, no, changeType);\n    return line;\n  }\n\n  // Helper for deleting text near the selection(s), used to implement\n  // backspace, delete, and similar functionality.\n  function deleteNearSelection(cm, compute) {\n    var ranges = cm.doc.sel.ranges, kill = [];\n    // Build up a set of ranges to kill first, merging overlapping\n    // ranges.\n    for (var i = 0; i < ranges.length; i++) {\n      var toKill = compute(ranges[i]);\n      while (kill.length && cmp(toKill.from, lst(kill).to) <= 0) {\n        var replaced = kill.pop();\n        if (cmp(replaced.from, toKill.from) < 0) {\n          toKill.from = replaced.from;\n          break;\n        }\n      }\n      kill.push(toKill);\n    }\n    // Next, remove those actual ranges.\n    runInOp(cm, function() {\n      for (var i = kill.length - 1; i >= 0; i--)\n        replaceRange(cm.doc, \"\", kill[i].from, kill[i].to, \"+delete\");\n      ensureCursorVisible(cm);\n    });\n  }\n\n  // Used for horizontal relative motion. Dir is -1 or 1 (left or\n  // right), unit can be \"char\", \"column\" (like char, but doesn't\n  // cross line boundaries), \"word\" (across next word), or \"group\" (to\n  // the start of next group of word or non-word-non-whitespace\n  // chars). The visually param controls whether, in right-to-left\n  // text, direction 1 means to move towards the next index in the\n  // string, or towards the character to the right of the current\n  // position. The resulting position will have a hitSide=true\n  // property if it reached the end of the document.\n  function findPosH(doc, pos, dir, unit, visually) {\n    var line = pos.line, ch = pos.ch, origDir = dir;\n    var lineObj = getLine(doc, line);\n    var possible = true;\n    function findNextLine() {\n      var l = line + dir;\n      if (l < doc.first || l >= doc.first + doc.size) return (possible = false);\n      line = l;\n      return lineObj = getLine(doc, l);\n    }\n    function moveOnce(boundToLine) {\n      var next = (visually ? moveVisually : moveLogically)(lineObj, ch, dir, true);\n      if (next == null) {\n        if (!boundToLine && findNextLine()) {\n          if (visually) ch = (dir < 0 ? lineRight : lineLeft)(lineObj);\n          else ch = dir < 0 ? lineObj.text.length : 0;\n        } else return (possible = false);\n      } else ch = next;\n      return true;\n    }\n\n    if (unit == \"char\") moveOnce();\n    else if (unit == \"column\") moveOnce(true);\n    else if (unit == \"word\" || unit == \"group\") {\n      var sawType = null, group = unit == \"group\";\n      var helper = doc.cm && doc.cm.getHelper(pos, \"wordChars\");\n      for (var first = true;; first = false) {\n        if (dir < 0 && !moveOnce(!first)) break;\n        var cur = lineObj.text.charAt(ch) || \"\\n\";\n        var type = isWordChar(cur, helper) ? \"w\"\n          : group && cur == \"\\n\" ? \"n\"\n          : !group || /\\s/.test(cur) ? null\n          : \"p\";\n        if (group && !first && !type) type = \"s\";\n        if (sawType && sawType != type) {\n          if (dir < 0) {dir = 1; moveOnce();}\n          break;\n        }\n\n        if (type) sawType = type;\n        if (dir > 0 && !moveOnce(!first)) break;\n      }\n    }\n    var result = skipAtomic(doc, Pos(line, ch), origDir, true);\n    if (!possible) result.hitSide = true;\n    return result;\n  }\n\n  // For relative vertical movement. Dir may be -1 or 1. Unit can be\n  // \"page\" or \"line\". The resulting position will have a hitSide=true\n  // property if it reached the end of the document.\n  function findPosV(cm, pos, dir, unit) {\n    var doc = cm.doc, x = pos.left, y;\n    if (unit == \"page\") {\n      var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight);\n      y = pos.top + dir * (pageSize - (dir < 0 ? 1.5 : .5) * textHeight(cm.display));\n    } else if (unit == \"line\") {\n      y = dir > 0 ? pos.bottom + 3 : pos.top - 3;\n    }\n    for (;;) {\n      var target = coordsChar(cm, x, y);\n      if (!target.outside) break;\n      if (dir < 0 ? y <= 0 : y >= doc.height) { target.hitSide = true; break; }\n      y += dir * 5;\n    }\n    return target;\n  }\n\n  // EDITOR METHODS\n\n  // The publicly visible API. Note that methodOp(f) means\n  // 'wrap f in an operation, performed on its `this` parameter'.\n\n  // This is not the complete set of editor methods. Most of the\n  // methods defined on the Doc type are also injected into\n  // CodeMirror.prototype, for backwards compatibility and\n  // convenience.\n\n  CodeMirror.prototype = {\n    constructor: CodeMirror,\n    focus: function(){window.focus(); this.display.input.focus();},\n\n    setOption: function(option, value) {\n      var options = this.options, old = options[option];\n      if (options[option] == value && option != \"mode\") return;\n      options[option] = value;\n      if (optionHandlers.hasOwnProperty(option))\n        operation(this, optionHandlers[option])(this, value, old);\n    },\n\n    getOption: function(option) {return this.options[option];},\n    getDoc: function() {return this.doc;},\n\n    addKeyMap: function(map, bottom) {\n      this.state.keyMaps[bottom ? \"push\" : \"unshift\"](getKeyMap(map));\n    },\n    removeKeyMap: function(map) {\n      var maps = this.state.keyMaps;\n      for (var i = 0; i < maps.length; ++i)\n        if (maps[i] == map || maps[i].name == map) {\n          maps.splice(i, 1);\n          return true;\n        }\n    },\n\n    addOverlay: methodOp(function(spec, options) {\n      var mode = spec.token ? spec : CodeMirror.getMode(this.options, spec);\n      if (mode.startState) throw new Error(\"Overlays may not be stateful.\");\n      this.state.overlays.push({mode: mode, modeSpec: spec, opaque: options && options.opaque});\n      this.state.modeGen++;\n      regChange(this);\n    }),\n    removeOverlay: methodOp(function(spec) {\n      var overlays = this.state.overlays;\n      for (var i = 0; i < overlays.length; ++i) {\n        var cur = overlays[i].modeSpec;\n        if (cur == spec || typeof spec == \"string\" && cur.name == spec) {\n          overlays.splice(i, 1);\n          this.state.modeGen++;\n          regChange(this);\n          return;\n        }\n      }\n    }),\n\n    indentLine: methodOp(function(n, dir, aggressive) {\n      if (typeof dir != \"string\" && typeof dir != \"number\") {\n        if (dir == null) dir = this.options.smartIndent ? \"smart\" : \"prev\";\n        else dir = dir ? \"add\" : \"subtract\";\n      }\n      if (isLine(this.doc, n)) indentLine(this, n, dir, aggressive);\n    }),\n    indentSelection: methodOp(function(how) {\n      var ranges = this.doc.sel.ranges, end = -1;\n      for (var i = 0; i < ranges.length; i++) {\n        var range = ranges[i];\n        if (!range.empty()) {\n          var from = range.from(), to = range.to();\n          var start = Math.max(end, from.line);\n          end = Math.min(this.lastLine(), to.line - (to.ch ? 0 : 1)) + 1;\n          for (var j = start; j < end; ++j)\n            indentLine(this, j, how);\n          var newRanges = this.doc.sel.ranges;\n          if (from.ch == 0 && ranges.length == newRanges.length && newRanges[i].from().ch > 0)\n            replaceOneSelection(this.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll);\n        } else if (range.head.line > end) {\n          indentLine(this, range.head.line, how, true);\n          end = range.head.line;\n          if (i == this.doc.sel.primIndex) ensureCursorVisible(this);\n        }\n      }\n    }),\n\n    // Fetch the parser token for a given character. Useful for hacks\n    // that want to inspect the mode state (say, for completion).\n    getTokenAt: function(pos, precise) {\n      return takeToken(this, pos, precise);\n    },\n\n    getLineTokens: function(line, precise) {\n      return takeToken(this, Pos(line), precise, true);\n    },\n\n    getTokenTypeAt: function(pos) {\n      pos = clipPos(this.doc, pos);\n      var styles = getLineStyles(this, getLine(this.doc, pos.line));\n      var before = 0, after = (styles.length - 1) / 2, ch = pos.ch;\n      var type;\n      if (ch == 0) type = styles[2];\n      else for (;;) {\n        var mid = (before + after) >> 1;\n        if ((mid ? styles[mid * 2 - 1] : 0) >= ch) after = mid;\n        else if (styles[mid * 2 + 1] < ch) before = mid + 1;\n        else { type = styles[mid * 2 + 2]; break; }\n      }\n      var cut = type ? type.indexOf(\"cm-overlay \") : -1;\n      return cut < 0 ? type : cut == 0 ? null : type.slice(0, cut - 1);\n    },\n\n    getModeAt: function(pos) {\n      var mode = this.doc.mode;\n      if (!mode.innerMode) return mode;\n      return CodeMirror.innerMode(mode, this.getTokenAt(pos).state).mode;\n    },\n\n    getHelper: function(pos, type) {\n      return this.getHelpers(pos, type)[0];\n    },\n\n    getHelpers: function(pos, type) {\n      var found = [];\n      if (!helpers.hasOwnProperty(type)) return helpers;\n      var help = helpers[type], mode = this.getModeAt(pos);\n      if (typeof mode[type] == \"string\") {\n        if (help[mode[type]]) found.push(help[mode[type]]);\n      } else if (mode[type]) {\n        for (var i = 0; i < mode[type].length; i++) {\n          var val = help[mode[type][i]];\n          if (val) found.push(val);\n        }\n      } else if (mode.helperType && help[mode.helperType]) {\n        found.push(help[mode.helperType]);\n      } else if (help[mode.name]) {\n        found.push(help[mode.name]);\n      }\n      for (var i = 0; i < help._global.length; i++) {\n        var cur = help._global[i];\n        if (cur.pred(mode, this) && indexOf(found, cur.val) == -1)\n          found.push(cur.val);\n      }\n      return found;\n    },\n\n    getStateAfter: function(line, precise) {\n      var doc = this.doc;\n      line = clipLine(doc, line == null ? doc.first + doc.size - 1: line);\n      return getStateBefore(this, line + 1, precise);\n    },\n\n    cursorCoords: function(start, mode) {\n      var pos, range = this.doc.sel.primary();\n      if (start == null) pos = range.head;\n      else if (typeof start == \"object\") pos = clipPos(this.doc, start);\n      else pos = start ? range.from() : range.to();\n      return cursorCoords(this, pos, mode || \"page\");\n    },\n\n    charCoords: function(pos, mode) {\n      return charCoords(this, clipPos(this.doc, pos), mode || \"page\");\n    },\n\n    coordsChar: function(coords, mode) {\n      coords = fromCoordSystem(this, coords, mode || \"page\");\n      return coordsChar(this, coords.left, coords.top);\n    },\n\n    lineAtHeight: function(height, mode) {\n      height = fromCoordSystem(this, {top: height, left: 0}, mode || \"page\").top;\n      return lineAtHeight(this.doc, height + this.display.viewOffset);\n    },\n    heightAtLine: function(line, mode) {\n      var end = false, last = this.doc.first + this.doc.size - 1;\n      if (line < this.doc.first) line = this.doc.first;\n      else if (line > last) { line = last; end = true; }\n      var lineObj = getLine(this.doc, line);\n      return intoCoordSystem(this, lineObj, {top: 0, left: 0}, mode || \"page\").top +\n        (end ? this.doc.height - heightAtLine(lineObj) : 0);\n    },\n\n    defaultTextHeight: function() { return textHeight(this.display); },\n    defaultCharWidth: function() { return charWidth(this.display); },\n\n    setGutterMarker: methodOp(function(line, gutterID, value) {\n      return changeLine(this.doc, line, \"gutter\", function(line) {\n        var markers = line.gutterMarkers || (line.gutterMarkers = {});\n        markers[gutterID] = value;\n        if (!value && isEmpty(markers)) line.gutterMarkers = null;\n        return true;\n      });\n    }),\n\n    clearGutter: methodOp(function(gutterID) {\n      var cm = this, doc = cm.doc, i = doc.first;\n      doc.iter(function(line) {\n        if (line.gutterMarkers && line.gutterMarkers[gutterID]) {\n          line.gutterMarkers[gutterID] = null;\n          regLineChange(cm, i, \"gutter\");\n          if (isEmpty(line.gutterMarkers)) line.gutterMarkers = null;\n        }\n        ++i;\n      });\n    }),\n\n    addLineWidget: methodOp(function(handle, node, options) {\n      return addLineWidget(this, handle, node, options);\n    }),\n\n    removeLineWidget: function(widget) { widget.clear(); },\n\n    lineInfo: function(line) {\n      if (typeof line == \"number\") {\n        if (!isLine(this.doc, line)) return null;\n        var n = line;\n        line = getLine(this.doc, line);\n        if (!line) return null;\n      } else {\n        var n = lineNo(line);\n        if (n == null) return null;\n      }\n      return {line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers,\n              textClass: line.textClass, bgClass: line.bgClass, wrapClass: line.wrapClass,\n              widgets: line.widgets};\n    },\n\n    getViewport: function() { return {from: this.display.viewFrom, to: this.display.viewTo};},\n\n    addWidget: function(pos, node, scroll, vert, horiz) {\n      var display = this.display;\n      pos = cursorCoords(this, clipPos(this.doc, pos));\n      var top = pos.bottom, left = pos.left;\n      node.style.position = \"absolute\";\n      node.setAttribute(\"cm-ignore-events\", \"true\");\n      this.display.input.setUneditable(node);\n      display.sizer.appendChild(node);\n      if (vert == \"over\") {\n        top = pos.top;\n      } else if (vert == \"above\" || vert == \"near\") {\n        var vspace = Math.max(display.wrapper.clientHeight, this.doc.height),\n        hspace = Math.max(display.sizer.clientWidth, display.lineSpace.clientWidth);\n        // Default to positioning above (if specified and possible); otherwise default to positioning below\n        if ((vert == 'above' || pos.bottom + node.offsetHeight > vspace) && pos.top > node.offsetHeight)\n          top = pos.top - node.offsetHeight;\n        else if (pos.bottom + node.offsetHeight <= vspace)\n          top = pos.bottom;\n        if (left + node.offsetWidth > hspace)\n          left = hspace - node.offsetWidth;\n      }\n      node.style.top = top + \"px\";\n      node.style.left = node.style.right = \"\";\n      if (horiz == \"right\") {\n        left = display.sizer.clientWidth - node.offsetWidth;\n        node.style.right = \"0px\";\n      } else {\n        if (horiz == \"left\") left = 0;\n        else if (horiz == \"middle\") left = (display.sizer.clientWidth - node.offsetWidth) / 2;\n        node.style.left = left + \"px\";\n      }\n      if (scroll)\n        scrollIntoView(this, left, top, left + node.offsetWidth, top + node.offsetHeight);\n    },\n\n    triggerOnKeyDown: methodOp(onKeyDown),\n    triggerOnKeyPress: methodOp(onKeyPress),\n    triggerOnKeyUp: onKeyUp,\n\n    execCommand: function(cmd) {\n      if (commands.hasOwnProperty(cmd))\n        return commands[cmd](this);\n    },\n\n    findPosH: function(from, amount, unit, visually) {\n      var dir = 1;\n      if (amount < 0) { dir = -1; amount = -amount; }\n      for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) {\n        cur = findPosH(this.doc, cur, dir, unit, visually);\n        if (cur.hitSide) break;\n      }\n      return cur;\n    },\n\n    moveH: methodOp(function(dir, unit) {\n      var cm = this;\n      cm.extendSelectionsBy(function(range) {\n        if (cm.display.shift || cm.doc.extend || range.empty())\n          return findPosH(cm.doc, range.head, dir, unit, cm.options.rtlMoveVisually);\n        else\n          return dir < 0 ? range.from() : range.to();\n      }, sel_move);\n    }),\n\n    deleteH: methodOp(function(dir, unit) {\n      var sel = this.doc.sel, doc = this.doc;\n      if (sel.somethingSelected())\n        doc.replaceSelection(\"\", null, \"+delete\");\n      else\n        deleteNearSelection(this, function(range) {\n          var other = findPosH(doc, range.head, dir, unit, false);\n          return dir < 0 ? {from: other, to: range.head} : {from: range.head, to: other};\n        });\n    }),\n\n    findPosV: function(from, amount, unit, goalColumn) {\n      var dir = 1, x = goalColumn;\n      if (amount < 0) { dir = -1; amount = -amount; }\n      for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) {\n        var coords = cursorCoords(this, cur, \"div\");\n        if (x == null) x = coords.left;\n        else coords.left = x;\n        cur = findPosV(this, coords, dir, unit);\n        if (cur.hitSide) break;\n      }\n      return cur;\n    },\n\n    moveV: methodOp(function(dir, unit) {\n      var cm = this, doc = this.doc, goals = [];\n      var collapse = !cm.display.shift && !doc.extend && doc.sel.somethingSelected();\n      doc.extendSelectionsBy(function(range) {\n        if (collapse)\n          return dir < 0 ? range.from() : range.to();\n        var headPos = cursorCoords(cm, range.head, \"div\");\n        if (range.goalColumn != null) headPos.left = range.goalColumn;\n        goals.push(headPos.left);\n        var pos = findPosV(cm, headPos, dir, unit);\n        if (unit == \"page\" && range == doc.sel.primary())\n          addToScrollPos(cm, null, charCoords(cm, pos, \"div\").top - headPos.top);\n        return pos;\n      }, sel_move);\n      if (goals.length) for (var i = 0; i < doc.sel.ranges.length; i++)\n        doc.sel.ranges[i].goalColumn = goals[i];\n    }),\n\n    // Find the word at the given position (as returned by coordsChar).\n    findWordAt: function(pos) {\n      var doc = this.doc, line = getLine(doc, pos.line).text;\n      var start = pos.ch, end = pos.ch;\n      if (line) {\n        var helper = this.getHelper(pos, \"wordChars\");\n        if ((pos.xRel < 0 || end == line.length) && start) --start; else ++end;\n        var startChar = line.charAt(start);\n        var check = isWordChar(startChar, helper)\n          ? function(ch) { return isWordChar(ch, helper); }\n          : /\\s/.test(startChar) ? function(ch) {return /\\s/.test(ch);}\n          : function(ch) {return !/\\s/.test(ch) && !isWordChar(ch);};\n        while (start > 0 && check(line.charAt(start - 1))) --start;\n        while (end < line.length && check(line.charAt(end))) ++end;\n      }\n      return new Range(Pos(pos.line, start), Pos(pos.line, end));\n    },\n\n    toggleOverwrite: function(value) {\n      if (value != null && value == this.state.overwrite) return;\n      if (this.state.overwrite = !this.state.overwrite)\n        addClass(this.display.cursorDiv, \"CodeMirror-overwrite\");\n      else\n        rmClass(this.display.cursorDiv, \"CodeMirror-overwrite\");\n\n      signal(this, \"overwriteToggle\", this, this.state.overwrite);\n    },\n    hasFocus: function() { return this.display.input.getField() == activeElt(); },\n\n    scrollTo: methodOp(function(x, y) {\n      if (x != null || y != null) resolveScrollToPos(this);\n      if (x != null) this.curOp.scrollLeft = x;\n      if (y != null) this.curOp.scrollTop = y;\n    }),\n    getScrollInfo: function() {\n      var scroller = this.display.scroller;\n      return {left: scroller.scrollLeft, top: scroller.scrollTop,\n              height: scroller.scrollHeight - scrollGap(this) - this.display.barHeight,\n              width: scroller.scrollWidth - scrollGap(this) - this.display.barWidth,\n              clientHeight: displayHeight(this), clientWidth: displayWidth(this)};\n    },\n\n    scrollIntoView: methodOp(function(range, margin) {\n      if (range == null) {\n        range = {from: this.doc.sel.primary().head, to: null};\n        if (margin == null) margin = this.options.cursorScrollMargin;\n      } else if (typeof range == \"number\") {\n        range = {from: Pos(range, 0), to: null};\n      } else if (range.from == null) {\n        range = {from: range, to: null};\n      }\n      if (!range.to) range.to = range.from;\n      range.margin = margin || 0;\n\n      if (range.from.line != null) {\n        resolveScrollToPos(this);\n        this.curOp.scrollToPos = range;\n      } else {\n        var sPos = calculateScrollPos(this, Math.min(range.from.left, range.to.left),\n                                      Math.min(range.from.top, range.to.top) - range.margin,\n                                      Math.max(range.from.right, range.to.right),\n                                      Math.max(range.from.bottom, range.to.bottom) + range.margin);\n        this.scrollTo(sPos.scrollLeft, sPos.scrollTop);\n      }\n    }),\n\n    setSize: methodOp(function(width, height) {\n      var cm = this;\n      function interpret(val) {\n        return typeof val == \"number\" || /^\\d+$/.test(String(val)) ? val + \"px\" : val;\n      }\n      if (width != null) cm.display.wrapper.style.width = interpret(width);\n      if (height != null) cm.display.wrapper.style.height = interpret(height);\n      if (cm.options.lineWrapping) clearLineMeasurementCache(this);\n      var lineNo = cm.display.viewFrom;\n      cm.doc.iter(lineNo, cm.display.viewTo, function(line) {\n        if (line.widgets) for (var i = 0; i < line.widgets.length; i++)\n          if (line.widgets[i].noHScroll) { regLineChange(cm, lineNo, \"widget\"); break; }\n        ++lineNo;\n      });\n      cm.curOp.forceUpdate = true;\n      signal(cm, \"refresh\", this);\n    }),\n\n    operation: function(f){return runInOp(this, f);},\n\n    refresh: methodOp(function() {\n      var oldHeight = this.display.cachedTextHeight;\n      regChange(this);\n      this.curOp.forceUpdate = true;\n      clearCaches(this);\n      this.scrollTo(this.doc.scrollLeft, this.doc.scrollTop);\n      updateGutterSpace(this);\n      if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5)\n        estimateLineHeights(this);\n      signal(this, \"refresh\", this);\n    }),\n\n    swapDoc: methodOp(function(doc) {\n      var old = this.doc;\n      old.cm = null;\n      attachDoc(this, doc);\n      clearCaches(this);\n      this.display.input.reset();\n      this.scrollTo(doc.scrollLeft, doc.scrollTop);\n      this.curOp.forceScroll = true;\n      signalLater(this, \"swapDoc\", this, old);\n      return old;\n    }),\n\n    getInputField: function(){return this.display.input.getField();},\n    getWrapperElement: function(){return this.display.wrapper;},\n    getScrollerElement: function(){return this.display.scroller;},\n    getGutterElement: function(){return this.display.gutters;}\n  };\n  eventMixin(CodeMirror);\n\n  // OPTION DEFAULTS\n\n  // The default configuration options.\n  var defaults = CodeMirror.defaults = {};\n  // Functions to run when options are changed.\n  var optionHandlers = CodeMirror.optionHandlers = {};\n\n  function option(name, deflt, handle, notOnInit) {\n    CodeMirror.defaults[name] = deflt;\n    if (handle) optionHandlers[name] =\n      notOnInit ? function(cm, val, old) {if (old != Init) handle(cm, val, old);} : handle;\n  }\n\n  // Passed to option handlers when there is no old value.\n  var Init = CodeMirror.Init = {toString: function(){return \"CodeMirror.Init\";}};\n\n  // These two are, on init, called from the constructor because they\n  // have to be initialized before the editor can start at all.\n  option(\"value\", \"\", function(cm, val) {\n    cm.setValue(val);\n  }, true);\n  option(\"mode\", null, function(cm, val) {\n    cm.doc.modeOption = val;\n    loadMode(cm);\n  }, true);\n\n  option(\"indentUnit\", 2, loadMode, true);\n  option(\"indentWithTabs\", false);\n  option(\"smartIndent\", true);\n  option(\"tabSize\", 4, function(cm) {\n    resetModeState(cm);\n    clearCaches(cm);\n    regChange(cm);\n  }, true);\n  option(\"specialChars\", /[\\t\\u0000-\\u0019\\u00ad\\u200b-\\u200f\\u2028\\u2029\\ufeff]/g, function(cm, val) {\n    cm.options.specialChars = new RegExp(val.source + (val.test(\"\\t\") ? \"\" : \"|\\t\"), \"g\");\n    cm.refresh();\n  }, true);\n  option(\"specialCharPlaceholder\", defaultSpecialCharPlaceholder, function(cm) {cm.refresh();}, true);\n  option(\"electricChars\", true);\n  option(\"inputStyle\", mobile ? \"contenteditable\" : \"textarea\", function() {\n    throw new Error(\"inputStyle can not (yet) be changed in a running editor\"); // FIXME\n  }, true);\n  option(\"rtlMoveVisually\", !windows);\n  option(\"wholeLineUpdateBefore\", true);\n\n  option(\"theme\", \"default\", function(cm) {\n    themeChanged(cm);\n    guttersChanged(cm);\n  }, true);\n  option(\"keyMap\", \"default\", function(cm, val, old) {\n    var next = getKeyMap(val);\n    var prev = old != CodeMirror.Init && getKeyMap(old);\n    if (prev && prev.detach) prev.detach(cm, next);\n    if (next.attach) next.attach(cm, prev || null);\n  });\n  option(\"extraKeys\", null);\n\n  option(\"lineWrapping\", false, wrappingChanged, true);\n  option(\"gutters\", [], function(cm) {\n    setGuttersForLineNumbers(cm.options);\n    guttersChanged(cm);\n  }, true);\n  option(\"fixedGutter\", true, function(cm, val) {\n    cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + \"px\" : \"0\";\n    cm.refresh();\n  }, true);\n  option(\"coverGutterNextToScrollbar\", false, function(cm) {updateScrollbars(cm);}, true);\n  option(\"scrollbarStyle\", \"native\", function(cm) {\n    initScrollbars(cm);\n    updateScrollbars(cm);\n    cm.display.scrollbars.setScrollTop(cm.doc.scrollTop);\n    cm.display.scrollbars.setScrollLeft(cm.doc.scrollLeft);\n  }, true);\n  option(\"lineNumbers\", false, function(cm) {\n    setGuttersForLineNumbers(cm.options);\n    guttersChanged(cm);\n  }, true);\n  option(\"firstLineNumber\", 1, guttersChanged, true);\n  option(\"lineNumberFormatter\", function(integer) {return integer;}, guttersChanged, true);\n  option(\"showCursorWhenSelecting\", false, updateSelection, true);\n\n  option(\"resetSelectionOnContextMenu\", true);\n\n  option(\"readOnly\", false, function(cm, val) {\n    if (val == \"nocursor\") {\n      onBlur(cm);\n      cm.display.input.blur();\n      cm.display.disabled = true;\n    } else {\n      cm.display.disabled = false;\n      if (!val) cm.display.input.reset();\n    }\n  });\n  option(\"disableInput\", false, function(cm, val) {if (!val) cm.display.input.reset();}, true);\n  option(\"dragDrop\", true);\n\n  option(\"cursorBlinkRate\", 530);\n  option(\"cursorScrollMargin\", 0);\n  option(\"cursorHeight\", 1, updateSelection, true);\n  option(\"singleCursorHeightPerLine\", true, updateSelection, true);\n  option(\"workTime\", 100);\n  option(\"workDelay\", 100);\n  option(\"flattenSpans\", true, resetModeState, true);\n  option(\"addModeClass\", false, resetModeState, true);\n  option(\"pollInterval\", 100);\n  option(\"undoDepth\", 200, function(cm, val){cm.doc.history.undoDepth = val;});\n  option(\"historyEventDelay\", 1250);\n  option(\"viewportMargin\", 10, function(cm){cm.refresh();}, true);\n  option(\"maxHighlightLength\", 10000, resetModeState, true);\n  option(\"moveInputWithCursor\", true, function(cm, val) {\n    if (!val) cm.display.input.resetPosition();\n  });\n\n  option(\"tabindex\", null, function(cm, val) {\n    cm.display.input.getField().tabIndex = val || \"\";\n  });\n  option(\"autofocus\", null);\n\n  // MODE DEFINITION AND QUERYING\n\n  // Known modes, by name and by MIME\n  var modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {};\n\n  // Extra arguments are stored as the mode's dependencies, which is\n  // used by (legacy) mechanisms like loadmode.js to automatically\n  // load a mode. (Preferred mechanism is the require/define calls.)\n  CodeMirror.defineMode = function(name, mode) {\n    if (!CodeMirror.defaults.mode && name != \"null\") CodeMirror.defaults.mode = name;\n    if (arguments.length > 2)\n      mode.dependencies = Array.prototype.slice.call(arguments, 2);\n    modes[name] = mode;\n  };\n\n  CodeMirror.defineMIME = function(mime, spec) {\n    mimeModes[mime] = spec;\n  };\n\n  // Given a MIME type, a {name, ...options} config object, or a name\n  // string, return a mode config object.\n  CodeMirror.resolveMode = function(spec) {\n    if (typeof spec == \"string\" && mimeModes.hasOwnProperty(spec)) {\n      spec = mimeModes[spec];\n    } else if (spec && typeof spec.name == \"string\" && mimeModes.hasOwnProperty(spec.name)) {\n      var found = mimeModes[spec.name];\n      if (typeof found == \"string\") found = {name: found};\n      spec = createObj(found, spec);\n      spec.name = found.name;\n    } else if (typeof spec == \"string\" && /^[\\w\\-]+\\/[\\w\\-]+\\+xml$/.test(spec)) {\n      return CodeMirror.resolveMode(\"application/xml\");\n    }\n    if (typeof spec == \"string\") return {name: spec};\n    else return spec || {name: \"null\"};\n  };\n\n  // Given a mode spec (anything that resolveMode accepts), find and\n  // initialize an actual mode object.\n  CodeMirror.getMode = function(options, spec) {\n    var spec = CodeMirror.resolveMode(spec);\n    var mfactory = modes[spec.name];\n    if (!mfactory) return CodeMirror.getMode(options, \"text/plain\");\n    var modeObj = mfactory(options, spec);\n    if (modeExtensions.hasOwnProperty(spec.name)) {\n      var exts = modeExtensions[spec.name];\n      for (var prop in exts) {\n        if (!exts.hasOwnProperty(prop)) continue;\n        if (modeObj.hasOwnProperty(prop)) modeObj[\"_\" + prop] = modeObj[prop];\n        modeObj[prop] = exts[prop];\n      }\n    }\n    modeObj.name = spec.name;\n    if (spec.helperType) modeObj.helperType = spec.helperType;\n    if (spec.modeProps) for (var prop in spec.modeProps)\n      modeObj[prop] = spec.modeProps[prop];\n\n    return modeObj;\n  };\n\n  // Minimal default mode.\n  CodeMirror.defineMode(\"null\", function() {\n    return {token: function(stream) {stream.skipToEnd();}};\n  });\n  CodeMirror.defineMIME(\"text/plain\", \"null\");\n\n  // This can be used to attach properties to mode objects from\n  // outside the actual mode definition.\n  var modeExtensions = CodeMirror.modeExtensions = {};\n  CodeMirror.extendMode = function(mode, properties) {\n    var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {});\n    copyObj(properties, exts);\n  };\n\n  // EXTENSIONS\n\n  CodeMirror.defineExtension = function(name, func) {\n    CodeMirror.prototype[name] = func;\n  };\n  CodeMirror.defineDocExtension = function(name, func) {\n    Doc.prototype[name] = func;\n  };\n  CodeMirror.defineOption = option;\n\n  var initHooks = [];\n  CodeMirror.defineInitHook = function(f) {initHooks.push(f);};\n\n  var helpers = CodeMirror.helpers = {};\n  CodeMirror.registerHelper = function(type, name, value) {\n    if (!helpers.hasOwnProperty(type)) helpers[type] = CodeMirror[type] = {_global: []};\n    helpers[type][name] = value;\n  };\n  CodeMirror.registerGlobalHelper = function(type, name, predicate, value) {\n    CodeMirror.registerHelper(type, name, value);\n    helpers[type]._global.push({pred: predicate, val: value});\n  };\n\n  // MODE STATE HANDLING\n\n  // Utility functions for working with state. Exported because nested\n  // modes need to do this for their inner modes.\n\n  var copyState = CodeMirror.copyState = function(mode, state) {\n    if (state === true) return state;\n    if (mode.copyState) return mode.copyState(state);\n    var nstate = {};\n    for (var n in state) {\n      var val = state[n];\n      if (val instanceof Array) val = val.concat([]);\n      nstate[n] = val;\n    }\n    return nstate;\n  };\n\n  var startState = CodeMirror.startState = function(mode, a1, a2) {\n    return mode.startState ? mode.startState(a1, a2) : true;\n  };\n\n  // Given a mode and a state (for that mode), find the inner mode and\n  // state at the position that the state refers to.\n  CodeMirror.innerMode = function(mode, state) {\n    while (mode.innerMode) {\n      var info = mode.innerMode(state);\n      if (!info || info.mode == mode) break;\n      state = info.state;\n      mode = info.mode;\n    }\n    return info || {mode: mode, state: state};\n  };\n\n  // STANDARD COMMANDS\n\n  // Commands are parameter-less actions that can be performed on an\n  // editor, mostly used for keybindings.\n  var commands = CodeMirror.commands = {\n    selectAll: function(cm) {cm.setSelection(Pos(cm.firstLine(), 0), Pos(cm.lastLine()), sel_dontScroll);},\n    singleSelection: function(cm) {\n      cm.setSelection(cm.getCursor(\"anchor\"), cm.getCursor(\"head\"), sel_dontScroll);\n    },\n    killLine: function(cm) {\n      deleteNearSelection(cm, function(range) {\n        if (range.empty()) {\n          var len = getLine(cm.doc, range.head.line).text.length;\n          if (range.head.ch == len && range.head.line < cm.lastLine())\n            return {from: range.head, to: Pos(range.head.line + 1, 0)};\n          else\n            return {from: range.head, to: Pos(range.head.line, len)};\n        } else {\n          return {from: range.from(), to: range.to()};\n        }\n      });\n    },\n    deleteLine: function(cm) {\n      deleteNearSelection(cm, function(range) {\n        return {from: Pos(range.from().line, 0),\n                to: clipPos(cm.doc, Pos(range.to().line + 1, 0))};\n      });\n    },\n    delLineLeft: function(cm) {\n      deleteNearSelection(cm, function(range) {\n        return {from: Pos(range.from().line, 0), to: range.from()};\n      });\n    },\n    delWrappedLineLeft: function(cm) {\n      deleteNearSelection(cm, function(range) {\n        var top = cm.charCoords(range.head, \"div\").top + 5;\n        var leftPos = cm.coordsChar({left: 0, top: top}, \"div\");\n        return {from: leftPos, to: range.from()};\n      });\n    },\n    delWrappedLineRight: function(cm) {\n      deleteNearSelection(cm, function(range) {\n        var top = cm.charCoords(range.head, \"div\").top + 5;\n        var rightPos = cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, \"div\");\n        return {from: range.from(), to: rightPos };\n      });\n    },\n    undo: function(cm) {cm.undo();},\n    redo: function(cm) {cm.redo();},\n    undoSelection: function(cm) {cm.undoSelection();},\n    redoSelection: function(cm) {cm.redoSelection();},\n    goDocStart: function(cm) {cm.extendSelection(Pos(cm.firstLine(), 0));},\n    goDocEnd: function(cm) {cm.extendSelection(Pos(cm.lastLine()));},\n    goLineStart: function(cm) {\n      cm.extendSelectionsBy(function(range) { return lineStart(cm, range.head.line); },\n                            {origin: \"+move\", bias: 1});\n    },\n    goLineStartSmart: function(cm) {\n      cm.extendSelectionsBy(function(range) {\n        return lineStartSmart(cm, range.head);\n      }, {origin: \"+move\", bias: 1});\n    },\n    goLineEnd: function(cm) {\n      cm.extendSelectionsBy(function(range) { return lineEnd(cm, range.head.line); },\n                            {origin: \"+move\", bias: -1});\n    },\n    goLineRight: function(cm) {\n      cm.extendSelectionsBy(function(range) {\n        var top = cm.charCoords(range.head, \"div\").top + 5;\n        return cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, \"div\");\n      }, sel_move);\n    },\n    goLineLeft: function(cm) {\n      cm.extendSelectionsBy(function(range) {\n        var top = cm.charCoords(range.head, \"div\").top + 5;\n        return cm.coordsChar({left: 0, top: top}, \"div\");\n      }, sel_move);\n    },\n    goLineLeftSmart: function(cm) {\n      cm.extendSelectionsBy(function(range) {\n        var top = cm.charCoords(range.head, \"div\").top + 5;\n        var pos = cm.coordsChar({left: 0, top: top}, \"div\");\n        if (pos.ch < cm.getLine(pos.line).search(/\\S/)) return lineStartSmart(cm, range.head);\n        return pos;\n      }, sel_move);\n    },\n    goLineUp: function(cm) {cm.moveV(-1, \"line\");},\n    goLineDown: function(cm) {cm.moveV(1, \"line\");},\n    goPageUp: function(cm) {cm.moveV(-1, \"page\");},\n    goPageDown: function(cm) {cm.moveV(1, \"page\");},\n    goCharLeft: function(cm) {cm.moveH(-1, \"char\");},\n    goCharRight: function(cm) {cm.moveH(1, \"char\");},\n    goColumnLeft: function(cm) {cm.moveH(-1, \"column\");},\n    goColumnRight: function(cm) {cm.moveH(1, \"column\");},\n    goWordLeft: function(cm) {cm.moveH(-1, \"word\");},\n    goGroupRight: function(cm) {cm.moveH(1, \"group\");},\n    goGroupLeft: function(cm) {cm.moveH(-1, \"group\");},\n    goWordRight: function(cm) {cm.moveH(1, \"word\");},\n    delCharBefore: function(cm) {cm.deleteH(-1, \"char\");},\n    delCharAfter: function(cm) {cm.deleteH(1, \"char\");},\n    delWordBefore: function(cm) {cm.deleteH(-1, \"word\");},\n    delWordAfter: function(cm) {cm.deleteH(1, \"word\");},\n    delGroupBefore: function(cm) {cm.deleteH(-1, \"group\");},\n    delGroupAfter: function(cm) {cm.deleteH(1, \"group\");},\n    indentAuto: function(cm) {cm.indentSelection(\"smart\");},\n    indentMore: function(cm) {cm.indentSelection(\"add\");},\n    indentLess: function(cm) {cm.indentSelection(\"subtract\");},\n    insertTab: function(cm) {cm.replaceSelection(\"\\t\");},\n    insertSoftTab: function(cm) {\n      var spaces = [], ranges = cm.listSelections(), tabSize = cm.options.tabSize;\n      for (var i = 0; i < ranges.length; i++) {\n        var pos = ranges[i].from();\n        var col = countColumn(cm.getLine(pos.line), pos.ch, tabSize);\n        spaces.push(new Array(tabSize - col % tabSize + 1).join(\" \"));\n      }\n      cm.replaceSelections(spaces);\n    },\n    defaultTab: function(cm) {\n      if (cm.somethingSelected()) cm.indentSelection(\"add\");\n      else cm.execCommand(\"insertTab\");\n    },\n    transposeChars: function(cm) {\n      runInOp(cm, function() {\n        var ranges = cm.listSelections(), newSel = [];\n        for (var i = 0; i < ranges.length; i++) {\n          var cur = ranges[i].head, line = getLine(cm.doc, cur.line).text;\n          if (line) {\n            if (cur.ch == line.length) cur = new Pos(cur.line, cur.ch - 1);\n            if (cur.ch > 0) {\n              cur = new Pos(cur.line, cur.ch + 1);\n              cm.replaceRange(line.charAt(cur.ch - 1) + line.charAt(cur.ch - 2),\n                              Pos(cur.line, cur.ch - 2), cur, \"+transpose\");\n            } else if (cur.line > cm.doc.first) {\n              var prev = getLine(cm.doc, cur.line - 1).text;\n              if (prev)\n                cm.replaceRange(line.charAt(0) + \"\\n\" + prev.charAt(prev.length - 1),\n                                Pos(cur.line - 1, prev.length - 1), Pos(cur.line, 1), \"+transpose\");\n            }\n          }\n          newSel.push(new Range(cur, cur));\n        }\n        cm.setSelections(newSel);\n      });\n    },\n    newlineAndIndent: function(cm) {\n      runInOp(cm, function() {\n        var len = cm.listSelections().length;\n        for (var i = 0; i < len; i++) {\n          var range = cm.listSelections()[i];\n          cm.replaceRange(\"\\n\", range.anchor, range.head, \"+input\");\n          cm.indentLine(range.from().line + 1, null, true);\n          ensureCursorVisible(cm);\n        }\n      });\n    },\n    toggleOverwrite: function(cm) {cm.toggleOverwrite();}\n  };\n\n\n  // STANDARD KEYMAPS\n\n  var keyMap = CodeMirror.keyMap = {};\n\n  keyMap.basic = {\n    \"Left\": \"goCharLeft\", \"Right\": \"goCharRight\", \"Up\": \"goLineUp\", \"Down\": \"goLineDown\",\n    \"End\": \"goLineEnd\", \"Home\": \"goLineStartSmart\", \"PageUp\": \"goPageUp\", \"PageDown\": \"goPageDown\",\n    \"Delete\": \"delCharAfter\", \"Backspace\": \"delCharBefore\", \"Shift-Backspace\": \"delCharBefore\",\n    \"Tab\": \"defaultTab\", \"Shift-Tab\": \"indentAuto\",\n    \"Enter\": \"newlineAndIndent\", \"Insert\": \"toggleOverwrite\",\n    \"Esc\": \"singleSelection\"\n  };\n  // Note that the save and find-related commands aren't defined by\n  // default. User code or addons can define them. Unknown commands\n  // are simply ignored.\n  keyMap.pcDefault = {\n    \"Ctrl-A\": \"selectAll\", \"Ctrl-D\": \"deleteLine\", \"Ctrl-Z\": \"undo\", \"Shift-Ctrl-Z\": \"redo\", \"Ctrl-Y\": \"redo\",\n    \"Ctrl-Home\": \"goDocStart\", \"Ctrl-End\": \"goDocEnd\", \"Ctrl-Up\": \"goLineUp\", \"Ctrl-Down\": \"goLineDown\",\n    \"Ctrl-Left\": \"goGroupLeft\", \"Ctrl-Right\": \"goGroupRight\", \"Alt-Left\": \"goLineStart\", \"Alt-Right\": \"goLineEnd\",\n    \"Ctrl-Backspace\": \"delGroupBefore\", \"Ctrl-Delete\": \"delGroupAfter\", \"Ctrl-S\": \"save\", \"Ctrl-F\": \"find\",\n    \"Ctrl-G\": \"findNext\", \"Shift-Ctrl-G\": \"findPrev\", \"Shift-Ctrl-F\": \"replace\", \"Shift-Ctrl-R\": \"replaceAll\",\n    \"Ctrl-[\": \"indentLess\", \"Ctrl-]\": \"indentMore\",\n    \"Ctrl-U\": \"undoSelection\", \"Shift-Ctrl-U\": \"redoSelection\", \"Alt-U\": \"redoSelection\",\n    fallthrough: \"basic\"\n  };\n  // Very basic readline/emacs-style bindings, which are standard on Mac.\n  keyMap.emacsy = {\n    \"Ctrl-F\": \"goCharRight\", \"Ctrl-B\": \"goCharLeft\", \"Ctrl-P\": \"goLineUp\", \"Ctrl-N\": \"goLineDown\",\n    \"Alt-F\": \"goWordRight\", \"Alt-B\": \"goWordLeft\", \"Ctrl-A\": \"goLineStart\", \"Ctrl-E\": \"goLineEnd\",\n    \"Ctrl-V\": \"goPageDown\", \"Shift-Ctrl-V\": \"goPageUp\", \"Ctrl-D\": \"delCharAfter\", \"Ctrl-H\": \"delCharBefore\",\n    \"Alt-D\": \"delWordAfter\", \"Alt-Backspace\": \"delWordBefore\", \"Ctrl-K\": \"killLine\", \"Ctrl-T\": \"transposeChars\"\n  };\n  keyMap.macDefault = {\n    \"Cmd-A\": \"selectAll\", \"Cmd-D\": \"deleteLine\", \"Cmd-Z\": \"undo\", \"Shift-Cmd-Z\": \"redo\", \"Cmd-Y\": \"redo\",\n    \"Cmd-Home\": \"goDocStart\", \"Cmd-Up\": \"goDocStart\", \"Cmd-End\": \"goDocEnd\", \"Cmd-Down\": \"goDocEnd\", \"Alt-Left\": \"goGroupLeft\",\n    \"Alt-Right\": \"goGroupRight\", \"Cmd-Left\": \"goLineLeft\", \"Cmd-Right\": \"goLineRight\", \"Alt-Backspace\": \"delGroupBefore\",\n    \"Ctrl-Alt-Backspace\": \"delGroupAfter\", \"Alt-Delete\": \"delGroupAfter\", \"Cmd-S\": \"save\", \"Cmd-F\": \"find\",\n    \"Cmd-G\": \"findNext\", \"Shift-Cmd-G\": \"findPrev\", \"Cmd-Alt-F\": \"replace\", \"Shift-Cmd-Alt-F\": \"replaceAll\",\n    \"Cmd-[\": \"indentLess\", \"Cmd-]\": \"indentMore\", \"Cmd-Backspace\": \"delWrappedLineLeft\", \"Cmd-Delete\": \"delWrappedLineRight\",\n    \"Cmd-U\": \"undoSelection\", \"Shift-Cmd-U\": \"redoSelection\", \"Ctrl-Up\": \"goDocStart\", \"Ctrl-Down\": \"goDocEnd\",\n    fallthrough: [\"basic\", \"emacsy\"]\n  };\n  keyMap[\"default\"] = mac ? keyMap.macDefault : keyMap.pcDefault;\n\n  // KEYMAP DISPATCH\n\n  function normalizeKeyName(name) {\n    var parts = name.split(/-(?!$)/), name = parts[parts.length - 1];\n    var alt, ctrl, shift, cmd;\n    for (var i = 0; i < parts.length - 1; i++) {\n      var mod = parts[i];\n      if (/^(cmd|meta|m)$/i.test(mod)) cmd = true;\n      else if (/^a(lt)?$/i.test(mod)) alt = true;\n      else if (/^(c|ctrl|control)$/i.test(mod)) ctrl = true;\n      else if (/^s(hift)$/i.test(mod)) shift = true;\n      else throw new Error(\"Unrecognized modifier name: \" + mod);\n    }\n    if (alt) name = \"Alt-\" + name;\n    if (ctrl) name = \"Ctrl-\" + name;\n    if (cmd) name = \"Cmd-\" + name;\n    if (shift) name = \"Shift-\" + name;\n    return name;\n  }\n\n  // This is a kludge to keep keymaps mostly working as raw objects\n  // (backwards compatibility) while at the same time support features\n  // like normalization and multi-stroke key bindings. It compiles a\n  // new normalized keymap, and then updates the old object to reflect\n  // this.\n  CodeMirror.normalizeKeyMap = function(keymap) {\n    var copy = {};\n    for (var keyname in keymap) if (keymap.hasOwnProperty(keyname)) {\n      var value = keymap[keyname];\n      if (/^(name|fallthrough|(de|at)tach)$/.test(keyname)) continue;\n      if (value == \"...\") { delete keymap[keyname]; continue; }\n\n      var keys = map(keyname.split(\" \"), normalizeKeyName);\n      for (var i = 0; i < keys.length; i++) {\n        var val, name;\n        if (i == keys.length - 1) {\n          name = keyname;\n          val = value;\n        } else {\n          name = keys.slice(0, i + 1).join(\" \");\n          val = \"...\";\n        }\n        var prev = copy[name];\n        if (!prev) copy[name] = val;\n        else if (prev != val) throw new Error(\"Inconsistent bindings for \" + name);\n      }\n      delete keymap[keyname];\n    }\n    for (var prop in copy) keymap[prop] = copy[prop];\n    return keymap;\n  };\n\n  var lookupKey = CodeMirror.lookupKey = function(key, map, handle, context) {\n    map = getKeyMap(map);\n    var found = map.call ? map.call(key, context) : map[key];\n    if (found === false) return \"nothing\";\n    if (found === \"...\") return \"multi\";\n    if (found != null && handle(found)) return \"handled\";\n\n    if (map.fallthrough) {\n      if (Object.prototype.toString.call(map.fallthrough) != \"[object Array]\")\n        return lookupKey(key, map.fallthrough, handle, context);\n      for (var i = 0; i < map.fallthrough.length; i++) {\n        var result = lookupKey(key, map.fallthrough[i], handle, context);\n        if (result) return result;\n      }\n    }\n  };\n\n  // Modifier key presses don't count as 'real' key presses for the\n  // purpose of keymap fallthrough.\n  var isModifierKey = CodeMirror.isModifierKey = function(value) {\n    var name = typeof value == \"string\" ? value : keyNames[value.keyCode];\n    return name == \"Ctrl\" || name == \"Alt\" || name == \"Shift\" || name == \"Mod\";\n  };\n\n  // Look up the name of a key as indicated by an event object.\n  var keyName = CodeMirror.keyName = function(event, noShift) {\n    if (presto && event.keyCode == 34 && event[\"char\"]) return false;\n    var base = keyNames[event.keyCode], name = base;\n    if (name == null || event.altGraphKey) return false;\n    if (event.altKey && base != \"Alt\") name = \"Alt-\" + name;\n    if ((flipCtrlCmd ? event.metaKey : event.ctrlKey) && base != \"Ctrl\") name = \"Ctrl-\" + name;\n    if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) && base != \"Cmd\") name = \"Cmd-\" + name;\n    if (!noShift && event.shiftKey && base != \"Shift\") name = \"Shift-\" + name;\n    return name;\n  };\n\n  function getKeyMap(val) {\n    return typeof val == \"string\" ? keyMap[val] : val;\n  }\n\n  // FROMTEXTAREA\n\n  CodeMirror.fromTextArea = function(textarea, options) {\n    options = options ? copyObj(options) : {};\n    options.value = textarea.value;\n    if (!options.tabindex && textarea.tabIndex)\n      options.tabindex = textarea.tabIndex;\n    if (!options.placeholder && textarea.placeholder)\n      options.placeholder = textarea.placeholder;\n    // Set autofocus to true if this textarea is focused, or if it has\n    // autofocus and no other element is focused.\n    if (options.autofocus == null) {\n      var hasFocus = activeElt();\n      options.autofocus = hasFocus == textarea ||\n        textarea.getAttribute(\"autofocus\") != null && hasFocus == document.body;\n    }\n\n    function save() {textarea.value = cm.getValue();}\n    if (textarea.form) {\n      on(textarea.form, \"submit\", save);\n      // Deplorable hack to make the submit method do the right thing.\n      if (!options.leaveSubmitMethodAlone) {\n        var form = textarea.form, realSubmit = form.submit;\n        try {\n          var wrappedSubmit = form.submit = function() {\n            save();\n            form.submit = realSubmit;\n            form.submit();\n            form.submit = wrappedSubmit;\n          };\n        } catch(e) {}\n      }\n    }\n\n    options.finishInit = function(cm) {\n      cm.save = save;\n      cm.getTextArea = function() { return textarea; };\n      cm.toTextArea = function() {\n        cm.toTextArea = isNaN; // Prevent this from being ran twice\n        save();\n        textarea.parentNode.removeChild(cm.getWrapperElement());\n        textarea.style.display = \"\";\n        if (textarea.form) {\n          off(textarea.form, \"submit\", save);\n          if (typeof textarea.form.submit == \"function\")\n            textarea.form.submit = realSubmit;\n        }\n      };\n    };\n\n    textarea.style.display = \"none\";\n    var cm = CodeMirror(function(node) {\n      textarea.parentNode.insertBefore(node, textarea.nextSibling);\n    }, options);\n    return cm;\n  };\n\n  // STRING STREAM\n\n  // Fed to the mode parsers, provides helper functions to make\n  // parsers more succinct.\n\n  var StringStream = CodeMirror.StringStream = function(string, tabSize) {\n    this.pos = this.start = 0;\n    this.string = string;\n    this.tabSize = tabSize || 8;\n    this.lastColumnPos = this.lastColumnValue = 0;\n    this.lineStart = 0;\n  };\n\n  StringStream.prototype = {\n    eol: function() {return this.pos >= this.string.length;},\n    sol: function() {return this.pos == this.lineStart;},\n    peek: function() {return this.string.charAt(this.pos) || undefined;},\n    next: function() {\n      if (this.pos < this.string.length)\n        return this.string.charAt(this.pos++);\n    },\n    eat: function(match) {\n      var ch = this.string.charAt(this.pos);\n      if (typeof match == \"string\") var ok = ch == match;\n      else var ok = ch && (match.test ? match.test(ch) : match(ch));\n      if (ok) {++this.pos; return ch;}\n    },\n    eatWhile: function(match) {\n      var start = this.pos;\n      while (this.eat(match)){}\n      return this.pos > start;\n    },\n    eatSpace: function() {\n      var start = this.pos;\n      while (/[\\s\\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos;\n      return this.pos > start;\n    },\n    skipToEnd: function() {this.pos = this.string.length;},\n    skipTo: function(ch) {\n      var found = this.string.indexOf(ch, this.pos);\n      if (found > -1) {this.pos = found; return true;}\n    },\n    backUp: function(n) {this.pos -= n;},\n    column: function() {\n      if (this.lastColumnPos < this.start) {\n        this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue);\n        this.lastColumnPos = this.start;\n      }\n      return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0);\n    },\n    indentation: function() {\n      return countColumn(this.string, null, this.tabSize) -\n        (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0);\n    },\n    match: function(pattern, consume, caseInsensitive) {\n      if (typeof pattern == \"string\") {\n        var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;};\n        var substr = this.string.substr(this.pos, pattern.length);\n        if (cased(substr) == cased(pattern)) {\n          if (consume !== false) this.pos += pattern.length;\n          return true;\n        }\n      } else {\n        var match = this.string.slice(this.pos).match(pattern);\n        if (match && match.index > 0) return null;\n        if (match && consume !== false) this.pos += match[0].length;\n        return match;\n      }\n    },\n    current: function(){return this.string.slice(this.start, this.pos);},\n    hideFirstChars: function(n, inner) {\n      this.lineStart += n;\n      try { return inner(); }\n      finally { this.lineStart -= n; }\n    }\n  };\n\n  // TEXTMARKERS\n\n  // Created with markText and setBookmark methods. A TextMarker is a\n  // handle that can be used to clear or find a marked position in the\n  // document. Line objects hold arrays (markedSpans) containing\n  // {from, to, marker} object pointing to such marker objects, and\n  // indicating that such a marker is present on that line. Multiple\n  // lines may point to the same marker when it spans across lines.\n  // The spans will have null for their from/to properties when the\n  // marker continues beyond the start/end of the line. Markers have\n  // links back to the lines they currently touch.\n\n  var nextMarkerId = 0;\n\n  var TextMarker = CodeMirror.TextMarker = function(doc, type) {\n    this.lines = [];\n    this.type = type;\n    this.doc = doc;\n    this.id = ++nextMarkerId;\n  };\n  eventMixin(TextMarker);\n\n  // Clear the marker.\n  TextMarker.prototype.clear = function() {\n    if (this.explicitlyCleared) return;\n    var cm = this.doc.cm, withOp = cm && !cm.curOp;\n    if (withOp) startOperation(cm);\n    if (hasHandler(this, \"clear\")) {\n      var found = this.find();\n      if (found) signalLater(this, \"clear\", found.from, found.to);\n    }\n    var min = null, max = null;\n    for (var i = 0; i < this.lines.length; ++i) {\n      var line = this.lines[i];\n      var span = getMarkedSpanFor(line.markedSpans, this);\n      if (cm && !this.collapsed) regLineChange(cm, lineNo(line), \"text\");\n      else if (cm) {\n        if (span.to != null) max = lineNo(line);\n        if (span.from != null) min = lineNo(line);\n      }\n      line.markedSpans = removeMarkedSpan(line.markedSpans, span);\n      if (span.from == null && this.collapsed && !lineIsHidden(this.doc, line) && cm)\n        updateLineHeight(line, textHeight(cm.display));\n    }\n    if (cm && this.collapsed && !cm.options.lineWrapping) for (var i = 0; i < this.lines.length; ++i) {\n      var visual = visualLine(this.lines[i]), len = lineLength(visual);\n      if (len > cm.display.maxLineLength) {\n        cm.display.maxLine = visual;\n        cm.display.maxLineLength = len;\n        cm.display.maxLineChanged = true;\n      }\n    }\n\n    if (min != null && cm && this.collapsed) regChange(cm, min, max + 1);\n    this.lines.length = 0;\n    this.explicitlyCleared = true;\n    if (this.atomic && this.doc.cantEdit) {\n      this.doc.cantEdit = false;\n      if (cm) reCheckSelection(cm.doc);\n    }\n    if (cm) signalLater(cm, \"markerCleared\", cm, this);\n    if (withOp) endOperation(cm);\n    if (this.parent) this.parent.clear();\n  };\n\n  // Find the position of the marker in the document. Returns a {from,\n  // to} object by default. Side can be passed to get a specific side\n  // -- 0 (both), -1 (left), or 1 (right). When lineObj is true, the\n  // Pos objects returned contain a line object, rather than a line\n  // number (used to prevent looking up the same line twice).\n  TextMarker.prototype.find = function(side, lineObj) {\n    if (side == null && this.type == \"bookmark\") side = 1;\n    var from, to;\n    for (var i = 0; i < this.lines.length; ++i) {\n      var line = this.lines[i];\n      var span = getMarkedSpanFor(line.markedSpans, this);\n      if (span.from != null) {\n        from = Pos(lineObj ? line : lineNo(line), span.from);\n        if (side == -1) return from;\n      }\n      if (span.to != null) {\n        to = Pos(lineObj ? line : lineNo(line), span.to);\n        if (side == 1) return to;\n      }\n    }\n    return from && {from: from, to: to};\n  };\n\n  // Signals that the marker's widget changed, and surrounding layout\n  // should be recomputed.\n  TextMarker.prototype.changed = function() {\n    var pos = this.find(-1, true), widget = this, cm = this.doc.cm;\n    if (!pos || !cm) return;\n    runInOp(cm, function() {\n      var line = pos.line, lineN = lineNo(pos.line);\n      var view = findViewForLine(cm, lineN);\n      if (view) {\n        clearLineMeasurementCacheFor(view);\n        cm.curOp.selectionChanged = cm.curOp.forceUpdate = true;\n      }\n      cm.curOp.updateMaxLine = true;\n      if (!lineIsHidden(widget.doc, line) && widget.height != null) {\n        var oldHeight = widget.height;\n        widget.height = null;\n        var dHeight = widgetHeight(widget) - oldHeight;\n        if (dHeight)\n          updateLineHeight(line, line.height + dHeight);\n      }\n    });\n  };\n\n  TextMarker.prototype.attachLine = function(line) {\n    if (!this.lines.length && this.doc.cm) {\n      var op = this.doc.cm.curOp;\n      if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1)\n        (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this);\n    }\n    this.lines.push(line);\n  };\n  TextMarker.prototype.detachLine = function(line) {\n    this.lines.splice(indexOf(this.lines, line), 1);\n    if (!this.lines.length && this.doc.cm) {\n      var op = this.doc.cm.curOp;\n      (op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this);\n    }\n  };\n\n  // Collapsed markers have unique ids, in order to be able to order\n  // them, which is needed for uniquely determining an outer marker\n  // when they overlap (they may nest, but not partially overlap).\n  var nextMarkerId = 0;\n\n  // Create a marker, wire it up to the right lines, and\n  function markText(doc, from, to, options, type) {\n    // Shared markers (across linked documents) are handled separately\n    // (markTextShared will call out to this again, once per\n    // document).\n    if (options && options.shared) return markTextShared(doc, from, to, options, type);\n    // Ensure we are in an operation.\n    if (doc.cm && !doc.cm.curOp) return operation(doc.cm, markText)(doc, from, to, options, type);\n\n    var marker = new TextMarker(doc, type), diff = cmp(from, to);\n    if (options) copyObj(options, marker, false);\n    // Don't connect empty markers unless clearWhenEmpty is false\n    if (diff > 0 || diff == 0 && marker.clearWhenEmpty !== false)\n      return marker;\n    if (marker.replacedWith) {\n      // Showing up as a widget implies collapsed (widget replaces text)\n      marker.collapsed = true;\n      marker.widgetNode = elt(\"span\", [marker.replacedWith], \"CodeMirror-widget\");\n      if (!options.handleMouseEvents) marker.widgetNode.setAttribute(\"cm-ignore-events\", \"true\");\n      if (options.insertLeft) marker.widgetNode.insertLeft = true;\n    }\n    if (marker.collapsed) {\n      if (conflictingCollapsedRange(doc, from.line, from, to, marker) ||\n          from.line != to.line && conflictingCollapsedRange(doc, to.line, from, to, marker))\n        throw new Error(\"Inserting collapsed marker partially overlapping an existing one\");\n      sawCollapsedSpans = true;\n    }\n\n    if (marker.addToHistory)\n      addChangeToHistory(doc, {from: from, to: to, origin: \"markText\"}, doc.sel, NaN);\n\n    var curLine = from.line, cm = doc.cm, updateMaxLine;\n    doc.iter(curLine, to.line + 1, function(line) {\n      if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(line) == cm.display.maxLine)\n        updateMaxLine = true;\n      if (marker.collapsed && curLine != from.line) updateLineHeight(line, 0);\n      addMarkedSpan(line, new MarkedSpan(marker,\n                                         curLine == from.line ? from.ch : null,\n                                         curLine == to.line ? to.ch : null));\n      ++curLine;\n    });\n    // lineIsHidden depends on the presence of the spans, so needs a second pass\n    if (marker.collapsed) doc.iter(from.line, to.line + 1, function(line) {\n      if (lineIsHidden(doc, line)) updateLineHeight(line, 0);\n    });\n\n    if (marker.clearOnEnter) on(marker, \"beforeCursorEnter\", function() { marker.clear(); });\n\n    if (marker.readOnly) {\n      sawReadOnlySpans = true;\n      if (doc.history.done.length || doc.history.undone.length)\n        doc.clearHistory();\n    }\n    if (marker.collapsed) {\n      marker.id = ++nextMarkerId;\n      marker.atomic = true;\n    }\n    if (cm) {\n      // Sync editor state\n      if (updateMaxLine) cm.curOp.updateMaxLine = true;\n      if (marker.collapsed)\n        regChange(cm, from.line, to.line + 1);\n      else if (marker.className || marker.title || marker.startStyle || marker.endStyle || marker.css)\n        for (var i = from.line; i <= to.line; i++) regLineChange(cm, i, \"text\");\n      if (marker.atomic) reCheckSelection(cm.doc);\n      signalLater(cm, \"markerAdded\", cm, marker);\n    }\n    return marker;\n  }\n\n  // SHARED TEXTMARKERS\n\n  // A shared marker spans multiple linked documents. It is\n  // implemented as a meta-marker-object controlling multiple normal\n  // markers.\n  var SharedTextMarker = CodeMirror.SharedTextMarker = function(markers, primary) {\n    this.markers = markers;\n    this.primary = primary;\n    for (var i = 0; i < markers.length; ++i)\n      markers[i].parent = this;\n  };\n  eventMixin(SharedTextMarker);\n\n  SharedTextMarker.prototype.clear = function() {\n    if (this.explicitlyCleared) return;\n    this.explicitlyCleared = true;\n    for (var i = 0; i < this.markers.length; ++i)\n      this.markers[i].clear();\n    signalLater(this, \"clear\");\n  };\n  SharedTextMarker.prototype.find = function(side, lineObj) {\n    return this.primary.find(side, lineObj);\n  };\n\n  function markTextShared(doc, from, to, options, type) {\n    options = copyObj(options);\n    options.shared = false;\n    var markers = [markText(doc, from, to, options, type)], primary = markers[0];\n    var widget = options.widgetNode;\n    linkedDocs(doc, function(doc) {\n      if (widget) options.widgetNode = widget.cloneNode(true);\n      markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type));\n      for (var i = 0; i < doc.linked.length; ++i)\n        if (doc.linked[i].isParent) return;\n      primary = lst(markers);\n    });\n    return new SharedTextMarker(markers, primary);\n  }\n\n  function findSharedMarkers(doc) {\n    return doc.findMarks(Pos(doc.first, 0), doc.clipPos(Pos(doc.lastLine())),\n                         function(m) { return m.parent; });\n  }\n\n  function copySharedMarkers(doc, markers) {\n    for (var i = 0; i < markers.length; i++) {\n      var marker = markers[i], pos = marker.find();\n      var mFrom = doc.clipPos(pos.from), mTo = doc.clipPos(pos.to);\n      if (cmp(mFrom, mTo)) {\n        var subMark = markText(doc, mFrom, mTo, marker.primary, marker.primary.type);\n        marker.markers.push(subMark);\n        subMark.parent = marker;\n      }\n    }\n  }\n\n  function detachSharedMarkers(markers) {\n    for (var i = 0; i < markers.length; i++) {\n      var marker = markers[i], linked = [marker.primary.doc];;\n      linkedDocs(marker.primary.doc, function(d) { linked.push(d); });\n      for (var j = 0; j < marker.markers.length; j++) {\n        var subMarker = marker.markers[j];\n        if (indexOf(linked, subMarker.doc) == -1) {\n          subMarker.parent = null;\n          marker.markers.splice(j--, 1);\n        }\n      }\n    }\n  }\n\n  // TEXTMARKER SPANS\n\n  function MarkedSpan(marker, from, to) {\n    this.marker = marker;\n    this.from = from; this.to = to;\n  }\n\n  // Search an array of spans for a span matching the given marker.\n  function getMarkedSpanFor(spans, marker) {\n    if (spans) for (var i = 0; i < spans.length; ++i) {\n      var span = spans[i];\n      if (span.marker == marker) return span;\n    }\n  }\n  // Remove a span from an array, returning undefined if no spans are\n  // left (we don't store arrays for lines without spans).\n  function removeMarkedSpan(spans, span) {\n    for (var r, i = 0; i < spans.length; ++i)\n      if (spans[i] != span) (r || (r = [])).push(spans[i]);\n    return r;\n  }\n  // Add a span to a line.\n  function addMarkedSpan(line, span) {\n    line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span];\n    span.marker.attachLine(line);\n  }\n\n  // Used for the algorithm that adjusts markers for a change in the\n  // document. These functions cut an array of spans at a given\n  // character position, returning an array of remaining chunks (or\n  // undefined if nothing remains).\n  function markedSpansBefore(old, startCh, isInsert) {\n    if (old) for (var i = 0, nw; i < old.length; ++i) {\n      var span = old[i], marker = span.marker;\n      var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh);\n      if (startsBefore || span.from == startCh && marker.type == \"bookmark\" && (!isInsert || !span.marker.insertLeft)) {\n        var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh);\n        (nw || (nw = [])).push(new MarkedSpan(marker, span.from, endsAfter ? null : span.to));\n      }\n    }\n    return nw;\n  }\n  function markedSpansAfter(old, endCh, isInsert) {\n    if (old) for (var i = 0, nw; i < old.length; ++i) {\n      var span = old[i], marker = span.marker;\n      var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh);\n      if (endsAfter || span.from == endCh && marker.type == \"bookmark\" && (!isInsert || span.marker.insertLeft)) {\n        var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh);\n        (nw || (nw = [])).push(new MarkedSpan(marker, startsBefore ? null : span.from - endCh,\n                                              span.to == null ? null : span.to - endCh));\n      }\n    }\n    return nw;\n  }\n\n  // Given a change object, compute the new set of marker spans that\n  // cover the line in which the change took place. Removes spans\n  // entirely within the change, reconnects spans belonging to the\n  // same marker that appear on both sides of the change, and cuts off\n  // spans partially within the change. Returns an array of span\n  // arrays with one element for each line in (after) the change.\n  function stretchSpansOverChange(doc, change) {\n    if (change.full) return null;\n    var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans;\n    var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans;\n    if (!oldFirst && !oldLast) return null;\n\n    var startCh = change.from.ch, endCh = change.to.ch, isInsert = cmp(change.from, change.to) == 0;\n    // Get the spans that 'stick out' on both sides\n    var first = markedSpansBefore(oldFirst, startCh, isInsert);\n    var last = markedSpansAfter(oldLast, endCh, isInsert);\n\n    // Next, merge those two ends\n    var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0);\n    if (first) {\n      // Fix up .to properties of first\n      for (var i = 0; i < first.length; ++i) {\n        var span = first[i];\n        if (span.to == null) {\n          var found = getMarkedSpanFor(last, span.marker);\n          if (!found) span.to = startCh;\n          else if (sameLine) span.to = found.to == null ? null : found.to + offset;\n        }\n      }\n    }\n    if (last) {\n      // Fix up .from in last (or move them into first in case of sameLine)\n      for (var i = 0; i < last.length; ++i) {\n        var span = last[i];\n        if (span.to != null) span.to += offset;\n        if (span.from == null) {\n          var found = getMarkedSpanFor(first, span.marker);\n          if (!found) {\n            span.from = offset;\n            if (sameLine) (first || (first = [])).push(span);\n          }\n        } else {\n          span.from += offset;\n          if (sameLine) (first || (first = [])).push(span);\n        }\n      }\n    }\n    // Make sure we didn't create any zero-length spans\n    if (first) first = clearEmptySpans(first);\n    if (last && last != first) last = clearEmptySpans(last);\n\n    var newMarkers = [first];\n    if (!sameLine) {\n      // Fill gap with whole-line-spans\n      var gap = change.text.length - 2, gapMarkers;\n      if (gap > 0 && first)\n        for (var i = 0; i < first.length; ++i)\n          if (first[i].to == null)\n            (gapMarkers || (gapMarkers = [])).push(new MarkedSpan(first[i].marker, null, null));\n      for (var i = 0; i < gap; ++i)\n        newMarkers.push(gapMarkers);\n      newMarkers.push(last);\n    }\n    return newMarkers;\n  }\n\n  // Remove spans that are empty and don't have a clearWhenEmpty\n  // option of false.\n  function clearEmptySpans(spans) {\n    for (var i = 0; i < spans.length; ++i) {\n      var span = spans[i];\n      if (span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false)\n        spans.splice(i--, 1);\n    }\n    if (!spans.length) return null;\n    return spans;\n  }\n\n  // Used for un/re-doing changes from the history. Combines the\n  // result of computing the existing spans with the set of spans that\n  // existed in the history (so that deleting around a span and then\n  // undoing brings back the span).\n  function mergeOldSpans(doc, change) {\n    var old = getOldSpans(doc, change);\n    var stretched = stretchSpansOverChange(doc, change);\n    if (!old) return stretched;\n    if (!stretched) return old;\n\n    for (var i = 0; i < old.length; ++i) {\n      var oldCur = old[i], stretchCur = stretched[i];\n      if (oldCur && stretchCur) {\n        spans: for (var j = 0; j < stretchCur.length; ++j) {\n          var span = stretchCur[j];\n          for (var k = 0; k < oldCur.length; ++k)\n            if (oldCur[k].marker == span.marker) continue spans;\n          oldCur.push(span);\n        }\n      } else if (stretchCur) {\n        old[i] = stretchCur;\n      }\n    }\n    return old;\n  }\n\n  // Used to 'clip' out readOnly ranges when making a change.\n  function removeReadOnlyRanges(doc, from, to) {\n    var markers = null;\n    doc.iter(from.line, to.line + 1, function(line) {\n      if (line.markedSpans) for (var i = 0; i < line.markedSpans.length; ++i) {\n        var mark = line.markedSpans[i].marker;\n        if (mark.readOnly && (!markers || indexOf(markers, mark) == -1))\n          (markers || (markers = [])).push(mark);\n      }\n    });\n    if (!markers) return null;\n    var parts = [{from: from, to: to}];\n    for (var i = 0; i < markers.length; ++i) {\n      var mk = markers[i], m = mk.find(0);\n      for (var j = 0; j < parts.length; ++j) {\n        var p = parts[j];\n        if (cmp(p.to, m.from) < 0 || cmp(p.from, m.to) > 0) continue;\n        var newParts = [j, 1], dfrom = cmp(p.from, m.from), dto = cmp(p.to, m.to);\n        if (dfrom < 0 || !mk.inclusiveLeft && !dfrom)\n          newParts.push({from: p.from, to: m.from});\n        if (dto > 0 || !mk.inclusiveRight && !dto)\n          newParts.push({from: m.to, to: p.to});\n        parts.splice.apply(parts, newParts);\n        j += newParts.length - 1;\n      }\n    }\n    return parts;\n  }\n\n  // Connect or disconnect spans from a line.\n  function detachMarkedSpans(line) {\n    var spans = line.markedSpans;\n    if (!spans) return;\n    for (var i = 0; i < spans.length; ++i)\n      spans[i].marker.detachLine(line);\n    line.markedSpans = null;\n  }\n  function attachMarkedSpans(line, spans) {\n    if (!spans) return;\n    for (var i = 0; i < spans.length; ++i)\n      spans[i].marker.attachLine(line);\n    line.markedSpans = spans;\n  }\n\n  // Helpers used when computing which overlapping collapsed span\n  // counts as the larger one.\n  function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0; }\n  function extraRight(marker) { return marker.inclusiveRight ? 1 : 0; }\n\n  // Returns a number indicating which of two overlapping collapsed\n  // spans is larger (and thus includes the other). Falls back to\n  // comparing ids when the spans cover exactly the same range.\n  function compareCollapsedMarkers(a, b) {\n    var lenDiff = a.lines.length - b.lines.length;\n    if (lenDiff != 0) return lenDiff;\n    var aPos = a.find(), bPos = b.find();\n    var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b);\n    if (fromCmp) return -fromCmp;\n    var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b);\n    if (toCmp) return toCmp;\n    return b.id - a.id;\n  }\n\n  // Find out whether a line ends or starts in a collapsed span. If\n  // so, return the marker for that span.\n  function collapsedSpanAtSide(line, start) {\n    var sps = sawCollapsedSpans && line.markedSpans, found;\n    if (sps) for (var sp, i = 0; i < sps.length; ++i) {\n      sp = sps[i];\n      if (sp.marker.collapsed && (start ? sp.from : sp.to) == null &&\n          (!found || compareCollapsedMarkers(found, sp.marker) < 0))\n        found = sp.marker;\n    }\n    return found;\n  }\n  function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true); }\n  function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false); }\n\n  // Test whether there exists a collapsed span that partially\n  // overlaps (covers the start or end, but not both) of a new span.\n  // Such overlap is not allowed.\n  function conflictingCollapsedRange(doc, lineNo, from, to, marker) {\n    var line = getLine(doc, lineNo);\n    var sps = sawCollapsedSpans && line.markedSpans;\n    if (sps) for (var i = 0; i < sps.length; ++i) {\n      var sp = sps[i];\n      if (!sp.marker.collapsed) continue;\n      var found = sp.marker.find(0);\n      var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker);\n      var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker);\n      if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) continue;\n      if (fromCmp <= 0 && (cmp(found.to, from) > 0 || (sp.marker.inclusiveRight && marker.inclusiveLeft)) ||\n          fromCmp >= 0 && (cmp(found.from, to) < 0 || (sp.marker.inclusiveLeft && marker.inclusiveRight)))\n        return true;\n    }\n  }\n\n  // A visual line is a line as drawn on the screen. Folding, for\n  // example, can cause multiple logical lines to appear on the same\n  // visual line. This finds the start of the visual line that the\n  // given line is part of (usually that is the line itself).\n  function visualLine(line) {\n    var merged;\n    while (merged = collapsedSpanAtStart(line))\n      line = merged.find(-1, true).line;\n    return line;\n  }\n\n  // Returns an array of logical lines that continue the visual line\n  // started by the argument, or undefined if there are no such lines.\n  function visualLineContinued(line) {\n    var merged, lines;\n    while (merged = collapsedSpanAtEnd(line)) {\n      line = merged.find(1, true).line;\n      (lines || (lines = [])).push(line);\n    }\n    return lines;\n  }\n\n  // Get the line number of the start of the visual line that the\n  // given line number is part of.\n  function visualLineNo(doc, lineN) {\n    var line = getLine(doc, lineN), vis = visualLine(line);\n    if (line == vis) return lineN;\n    return lineNo(vis);\n  }\n  // Get the line number of the start of the next visual line after\n  // the given line.\n  function visualLineEndNo(doc, lineN) {\n    if (lineN > doc.lastLine()) return lineN;\n    var line = getLine(doc, lineN), merged;\n    if (!lineIsHidden(doc, line)) return lineN;\n    while (merged = collapsedSpanAtEnd(line))\n      line = merged.find(1, true).line;\n    return lineNo(line) + 1;\n  }\n\n  // Compute whether a line is hidden. Lines count as hidden when they\n  // are part of a visual line that starts with another line, or when\n  // they are entirely covered by collapsed, non-widget span.\n  function lineIsHidden(doc, line) {\n    var sps = sawCollapsedSpans && line.markedSpans;\n    if (sps) for (var sp, i = 0; i < sps.length; ++i) {\n      sp = sps[i];\n      if (!sp.marker.collapsed) continue;\n      if (sp.from == null) return true;\n      if (sp.marker.widgetNode) continue;\n      if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(doc, line, sp))\n        return true;\n    }\n  }\n  function lineIsHiddenInner(doc, line, span) {\n    if (span.to == null) {\n      var end = span.marker.find(1, true);\n      return lineIsHiddenInner(doc, end.line, getMarkedSpanFor(end.line.markedSpans, span.marker));\n    }\n    if (span.marker.inclusiveRight && span.to == line.text.length)\n      return true;\n    for (var sp, i = 0; i < line.markedSpans.length; ++i) {\n      sp = line.markedSpans[i];\n      if (sp.marker.collapsed && !sp.marker.widgetNode && sp.from == span.to &&\n          (sp.to == null || sp.to != span.from) &&\n          (sp.marker.inclusiveLeft || span.marker.inclusiveRight) &&\n          lineIsHiddenInner(doc, line, sp)) return true;\n    }\n  }\n\n  // LINE WIDGETS\n\n  // Line widgets are block elements displayed above or below a line.\n\n  var LineWidget = CodeMirror.LineWidget = function(cm, node, options) {\n    if (options) for (var opt in options) if (options.hasOwnProperty(opt))\n      this[opt] = options[opt];\n    this.cm = cm;\n    this.node = node;\n  };\n  eventMixin(LineWidget);\n\n  function adjustScrollWhenAboveVisible(cm, line, diff) {\n    if (heightAtLine(line) < ((cm.curOp && cm.curOp.scrollTop) || cm.doc.scrollTop))\n      addToScrollPos(cm, null, diff);\n  }\n\n  LineWidget.prototype.clear = function() {\n    var cm = this.cm, ws = this.line.widgets, line = this.line, no = lineNo(line);\n    if (no == null || !ws) return;\n    for (var i = 0; i < ws.length; ++i) if (ws[i] == this) ws.splice(i--, 1);\n    if (!ws.length) line.widgets = null;\n    var height = widgetHeight(this);\n    runInOp(cm, function() {\n      adjustScrollWhenAboveVisible(cm, line, -height);\n      regLineChange(cm, no, \"widget\");\n      updateLineHeight(line, Math.max(0, line.height - height));\n    });\n  };\n  LineWidget.prototype.changed = function() {\n    var oldH = this.height, cm = this.cm, line = this.line;\n    this.height = null;\n    var diff = widgetHeight(this) - oldH;\n    if (!diff) return;\n    runInOp(cm, function() {\n      cm.curOp.forceUpdate = true;\n      adjustScrollWhenAboveVisible(cm, line, diff);\n      updateLineHeight(line, line.height + diff);\n    });\n  };\n\n  function widgetHeight(widget) {\n    if (widget.height != null) return widget.height;\n    if (!contains(document.body, widget.node)) {\n      var parentStyle = \"position: relative;\";\n      if (widget.coverGutter)\n        parentStyle += \"margin-left: -\" + widget.cm.display.gutters.offsetWidth + \"px;\";\n      if (widget.noHScroll)\n        parentStyle += \"width: \" + widget.cm.display.wrapper.clientWidth + \"px;\";\n      removeChildrenAndAdd(widget.cm.display.measure, elt(\"div\", [widget.node], null, parentStyle));\n    }\n    return widget.height = widget.node.offsetHeight;\n  }\n\n  function addLineWidget(cm, handle, node, options) {\n    var widget = new LineWidget(cm, node, options);\n    if (widget.noHScroll) cm.display.alignWidgets = true;\n    changeLine(cm.doc, handle, \"widget\", function(line) {\n      var widgets = line.widgets || (line.widgets = []);\n      if (widget.insertAt == null) widgets.push(widget);\n      else widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget);\n      widget.line = line;\n      if (!lineIsHidden(cm.doc, line)) {\n        var aboveVisible = heightAtLine(line) < cm.doc.scrollTop;\n        updateLineHeight(line, line.height + widgetHeight(widget));\n        if (aboveVisible) addToScrollPos(cm, null, widget.height);\n        cm.curOp.forceUpdate = true;\n      }\n      return true;\n    });\n    return widget;\n  }\n\n  // LINE DATA STRUCTURE\n\n  // Line objects. These hold state related to a line, including\n  // highlighting info (the styles array).\n  var Line = CodeMirror.Line = function(text, markedSpans, estimateHeight) {\n    this.text = text;\n    attachMarkedSpans(this, markedSpans);\n    this.height = estimateHeight ? estimateHeight(this) : 1;\n  };\n  eventMixin(Line);\n  Line.prototype.lineNo = function() { return lineNo(this); };\n\n  // Change the content (text, markers) of a line. Automatically\n  // invalidates cached information and tries to re-estimate the\n  // line's height.\n  function updateLine(line, text, markedSpans, estimateHeight) {\n    line.text = text;\n    if (line.stateAfter) line.stateAfter = null;\n    if (line.styles) line.styles = null;\n    if (line.order != null) line.order = null;\n    detachMarkedSpans(line);\n    attachMarkedSpans(line, markedSpans);\n    var estHeight = estimateHeight ? estimateHeight(line) : 1;\n    if (estHeight != line.height) updateLineHeight(line, estHeight);\n  }\n\n  // Detach a line from the document tree and its markers.\n  function cleanUpLine(line) {\n    line.parent = null;\n    detachMarkedSpans(line);\n  }\n\n  function extractLineClasses(type, output) {\n    if (type) for (;;) {\n      var lineClass = type.match(/(?:^|\\s+)line-(background-)?(\\S+)/);\n      if (!lineClass) break;\n      type = type.slice(0, lineClass.index) + type.slice(lineClass.index + lineClass[0].length);\n      var prop = lineClass[1] ? \"bgClass\" : \"textClass\";\n      if (output[prop] == null)\n        output[prop] = lineClass[2];\n      else if (!(new RegExp(\"(?:^|\\s)\" + lineClass[2] + \"(?:$|\\s)\")).test(output[prop]))\n        output[prop] += \" \" + lineClass[2];\n    }\n    return type;\n  }\n\n  function callBlankLine(mode, state) {\n    if (mode.blankLine) return mode.blankLine(state);\n    if (!mode.innerMode) return;\n    var inner = CodeMirror.innerMode(mode, state);\n    if (inner.mode.blankLine) return inner.mode.blankLine(inner.state);\n  }\n\n  function readToken(mode, stream, state, inner) {\n    for (var i = 0; i < 10; i++) {\n      if (inner) inner[0] = CodeMirror.innerMode(mode, state).mode;\n      var style = mode.token(stream, state);\n      if (stream.pos > stream.start) return style;\n    }\n    throw new Error(\"Mode \" + mode.name + \" failed to advance stream.\");\n  }\n\n  // Utility for getTokenAt and getLineTokens\n  function takeToken(cm, pos, precise, asArray) {\n    function getObj(copy) {\n      return {start: stream.start, end: stream.pos,\n              string: stream.current(),\n              type: style || null,\n              state: copy ? copyState(doc.mode, state) : state};\n    }\n\n    var doc = cm.doc, mode = doc.mode, style;\n    pos = clipPos(doc, pos);\n    var line = getLine(doc, pos.line), state = getStateBefore(cm, pos.line, precise);\n    var stream = new StringStream(line.text, cm.options.tabSize), tokens;\n    if (asArray) tokens = [];\n    while ((asArray || stream.pos < pos.ch) && !stream.eol()) {\n      stream.start = stream.pos;\n      style = readToken(mode, stream, state);\n      if (asArray) tokens.push(getObj(true));\n    }\n    return asArray ? tokens : getObj();\n  }\n\n  // Run the given mode's parser over a line, calling f for each token.\n  function runMode(cm, text, mode, state, f, lineClasses, forceToEnd) {\n    var flattenSpans = mode.flattenSpans;\n    if (flattenSpans == null) flattenSpans = cm.options.flattenSpans;\n    var curStart = 0, curStyle = null;\n    var stream = new StringStream(text, cm.options.tabSize), style;\n    var inner = cm.options.addModeClass && [null];\n    if (text == \"\") extractLineClasses(callBlankLine(mode, state), lineClasses);\n    while (!stream.eol()) {\n      if (stream.pos > cm.options.maxHighlightLength) {\n        flattenSpans = false;\n        if (forceToEnd) processLine(cm, text, state, stream.pos);\n        stream.pos = text.length;\n        style = null;\n      } else {\n        style = extractLineClasses(readToken(mode, stream, state, inner), lineClasses);\n      }\n      if (inner) {\n        var mName = inner[0].name;\n        if (mName) style = \"m-\" + (style ? mName + \" \" + style : mName);\n      }\n      if (!flattenSpans || curStyle != style) {\n        while (curStart < stream.start) {\n          curStart = Math.min(stream.start, curStart + 50000);\n          f(curStart, curStyle);\n        }\n        curStyle = style;\n      }\n      stream.start = stream.pos;\n    }\n    while (curStart < stream.pos) {\n      // Webkit seems to refuse to render text nodes longer than 57444 characters\n      var pos = Math.min(stream.pos, curStart + 50000);\n      f(pos, curStyle);\n      curStart = pos;\n    }\n  }\n\n  // Compute a style array (an array starting with a mode generation\n  // -- for invalidation -- followed by pairs of end positions and\n  // style strings), which is used to highlight the tokens on the\n  // line.\n  function highlightLine(cm, line, state, forceToEnd) {\n    // A styles array always starts with a number identifying the\n    // mode/overlays that it is based on (for easy invalidation).\n    var st = [cm.state.modeGen], lineClasses = {};\n    // Compute the base array of styles\n    runMode(cm, line.text, cm.doc.mode, state, function(end, style) {\n      st.push(end, style);\n    }, lineClasses, forceToEnd);\n\n    // Run overlays, adjust style array.\n    for (var o = 0; o < cm.state.overlays.length; ++o) {\n      var overlay = cm.state.overlays[o], i = 1, at = 0;\n      runMode(cm, line.text, overlay.mode, true, function(end, style) {\n        var start = i;\n        // Ensure there's a token end at the current position, and that i points at it\n        while (at < end) {\n          var i_end = st[i];\n          if (i_end > end)\n            st.splice(i, 1, end, st[i+1], i_end);\n          i += 2;\n          at = Math.min(end, i_end);\n        }\n        if (!style) return;\n        if (overlay.opaque) {\n          st.splice(start, i - start, end, \"cm-overlay \" + style);\n          i = start + 2;\n        } else {\n          for (; start < i; start += 2) {\n            var cur = st[start+1];\n            st[start+1] = (cur ? cur + \" \" : \"\") + \"cm-overlay \" + style;\n          }\n        }\n      }, lineClasses);\n    }\n\n    return {styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null};\n  }\n\n  function getLineStyles(cm, line, updateFrontier) {\n    if (!line.styles || line.styles[0] != cm.state.modeGen) {\n      var result = highlightLine(cm, line, line.stateAfter = getStateBefore(cm, lineNo(line)));\n      line.styles = result.styles;\n      if (result.classes) line.styleClasses = result.classes;\n      else if (line.styleClasses) line.styleClasses = null;\n      if (updateFrontier === cm.doc.frontier) cm.doc.frontier++;\n    }\n    return line.styles;\n  }\n\n  // Lightweight form of highlight -- proceed over this line and\n  // update state, but don't save a style array. Used for lines that\n  // aren't currently visible.\n  function processLine(cm, text, state, startAt) {\n    var mode = cm.doc.mode;\n    var stream = new StringStream(text, cm.options.tabSize);\n    stream.start = stream.pos = startAt || 0;\n    if (text == \"\") callBlankLine(mode, state);\n    while (!stream.eol() && stream.pos <= cm.options.maxHighlightLength) {\n      readToken(mode, stream, state);\n      stream.start = stream.pos;\n    }\n  }\n\n  // Convert a style as returned by a mode (either null, or a string\n  // containing one or more styles) to a CSS style. This is cached,\n  // and also looks for line-wide styles.\n  var styleToClassCache = {}, styleToClassCacheWithMode = {};\n  function interpretTokenStyle(style, options) {\n    if (!style || /^\\s*$/.test(style)) return null;\n    var cache = options.addModeClass ? styleToClassCacheWithMode : styleToClassCache;\n    return cache[style] ||\n      (cache[style] = style.replace(/\\S+/g, \"cm-$&\"));\n  }\n\n  // Render the DOM representation of the text of a line. Also builds\n  // up a 'line map', which points at the DOM nodes that represent\n  // specific stretches of text, and is used by the measuring code.\n  // The returned object contains the DOM node, this map, and\n  // information about line-wide styles that were set by the mode.\n  function buildLineContent(cm, lineView) {\n    // The padding-right forces the element to have a 'border', which\n    // is needed on Webkit to be able to get line-level bounding\n    // rectangles for it (in measureChar).\n    var content = elt(\"span\", null, null, webkit ? \"padding-right: .1px\" : null);\n    var builder = {pre: elt(\"pre\", [content]), content: content, col: 0, pos: 0, cm: cm};\n    lineView.measure = {};\n\n    // Iterate over the logical lines that make up this visual line.\n    for (var i = 0; i <= (lineView.rest ? lineView.rest.length : 0); i++) {\n      var line = i ? lineView.rest[i - 1] : lineView.line, order;\n      builder.pos = 0;\n      builder.addToken = buildToken;\n      // Optionally wire in some hacks into the token-rendering\n      // algorithm, to deal with browser quirks.\n      if ((ie || webkit) && cm.getOption(\"lineWrapping\"))\n        builder.addToken = buildTokenSplitSpaces(builder.addToken);\n      if (hasBadBidiRects(cm.display.measure) && (order = getOrder(line)))\n        builder.addToken = buildTokenBadBidi(builder.addToken, order);\n      builder.map = [];\n      var allowFrontierUpdate = lineView != cm.display.externalMeasured && lineNo(line);\n      insertLineContent(line, builder, getLineStyles(cm, line, allowFrontierUpdate));\n      if (line.styleClasses) {\n        if (line.styleClasses.bgClass)\n          builder.bgClass = joinClasses(line.styleClasses.bgClass, builder.bgClass || \"\");\n        if (line.styleClasses.textClass)\n          builder.textClass = joinClasses(line.styleClasses.textClass, builder.textClass || \"\");\n      }\n\n      // Ensure at least a single node is present, for measuring.\n      if (builder.map.length == 0)\n        builder.map.push(0, 0, builder.content.appendChild(zeroWidthElement(cm.display.measure)));\n\n      // Store the map and a cache object for the current logical line\n      if (i == 0) {\n        lineView.measure.map = builder.map;\n        lineView.measure.cache = {};\n      } else {\n        (lineView.measure.maps || (lineView.measure.maps = [])).push(builder.map);\n        (lineView.measure.caches || (lineView.measure.caches = [])).push({});\n      }\n    }\n\n    // See issue #2901\n    if (webkit && /\\bcm-tab\\b/.test(builder.content.lastChild.className))\n      builder.content.className = \"cm-tab-wrap-hack\";\n\n    signal(cm, \"renderLine\", cm, lineView.line, builder.pre);\n    if (builder.pre.className)\n      builder.textClass = joinClasses(builder.pre.className, builder.textClass || \"\");\n\n    return builder;\n  }\n\n  function defaultSpecialCharPlaceholder(ch) {\n    var token = elt(\"span\", \"\\u2022\", \"cm-invalidchar\");\n    token.title = \"\\\\u\" + ch.charCodeAt(0).toString(16);\n    token.setAttribute(\"aria-label\", token.title);\n    return token;\n  }\n\n  // Build up the DOM representation for a single token, and add it to\n  // the line map. Takes care to render special characters separately.\n  function buildToken(builder, text, style, startStyle, endStyle, title, css) {\n    if (!text) return;\n    var special = builder.cm.options.specialChars, mustWrap = false;\n    if (!special.test(text)) {\n      builder.col += text.length;\n      var content = document.createTextNode(text);\n      builder.map.push(builder.pos, builder.pos + text.length, content);\n      if (ie && ie_version < 9) mustWrap = true;\n      builder.pos += text.length;\n    } else {\n      var content = document.createDocumentFragment(), pos = 0;\n      while (true) {\n        special.lastIndex = pos;\n        var m = special.exec(text);\n        var skipped = m ? m.index - pos : text.length - pos;\n        if (skipped) {\n          var txt = document.createTextNode(text.slice(pos, pos + skipped));\n          if (ie && ie_version < 9) content.appendChild(elt(\"span\", [txt]));\n          else content.appendChild(txt);\n          builder.map.push(builder.pos, builder.pos + skipped, txt);\n          builder.col += skipped;\n          builder.pos += skipped;\n        }\n        if (!m) break;\n        pos += skipped + 1;\n        if (m[0] == \"\\t\") {\n          var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize;\n          var txt = content.appendChild(elt(\"span\", spaceStr(tabWidth), \"cm-tab\"));\n          txt.setAttribute(\"role\", \"presentation\");\n          txt.setAttribute(\"cm-text\", \"\\t\");\n          builder.col += tabWidth;\n        } else {\n          var txt = builder.cm.options.specialCharPlaceholder(m[0]);\n          txt.setAttribute(\"cm-text\", m[0]);\n          if (ie && ie_version < 9) content.appendChild(elt(\"span\", [txt]));\n          else content.appendChild(txt);\n          builder.col += 1;\n        }\n        builder.map.push(builder.pos, builder.pos + 1, txt);\n        builder.pos++;\n      }\n    }\n    if (style || startStyle || endStyle || mustWrap || css) {\n      var fullStyle = style || \"\";\n      if (startStyle) fullStyle += startStyle;\n      if (endStyle) fullStyle += endStyle;\n      var token = elt(\"span\", [content], fullStyle, css);\n      if (title) token.title = title;\n      return builder.content.appendChild(token);\n    }\n    builder.content.appendChild(content);\n  }\n\n  function buildTokenSplitSpaces(inner) {\n    function split(old) {\n      var out = \" \";\n      for (var i = 0; i < old.length - 2; ++i) out += i % 2 ? \" \" : \"\\u00a0\";\n      out += \" \";\n      return out;\n    }\n    return function(builder, text, style, startStyle, endStyle, title) {\n      inner(builder, text.replace(/ {3,}/g, split), style, startStyle, endStyle, title);\n    };\n  }\n\n  // Work around nonsense dimensions being reported for stretches of\n  // right-to-left text.\n  function buildTokenBadBidi(inner, order) {\n    return function(builder, text, style, startStyle, endStyle, title) {\n      style = style ? style + \" cm-force-border\" : \"cm-force-border\";\n      var start = builder.pos, end = start + text.length;\n      for (;;) {\n        // Find the part that overlaps with the start of this text\n        for (var i = 0; i < order.length; i++) {\n          var part = order[i];\n          if (part.to > start && part.from <= start) break;\n        }\n        if (part.to >= end) return inner(builder, text, style, startStyle, endStyle, title);\n        inner(builder, text.slice(0, part.to - start), style, startStyle, null, title);\n        startStyle = null;\n        text = text.slice(part.to - start);\n        start = part.to;\n      }\n    };\n  }\n\n  function buildCollapsedSpan(builder, size, marker, ignoreWidget) {\n    var widget = !ignoreWidget && marker.widgetNode;\n    if (widget) builder.map.push(builder.pos, builder.pos + size, widget);\n    if (!ignoreWidget && builder.cm.display.input.needsContentAttribute) {\n      if (!widget)\n        widget = builder.content.appendChild(document.createElement(\"span\"));\n      widget.setAttribute(\"cm-marker\", marker.id);\n    }\n    if (widget) {\n      builder.cm.display.input.setUneditable(widget);\n      builder.content.appendChild(widget);\n    }\n    builder.pos += size;\n  }\n\n  // Outputs a number of spans to make up a line, taking highlighting\n  // and marked text into account.\n  function insertLineContent(line, builder, styles) {\n    var spans = line.markedSpans, allText = line.text, at = 0;\n    if (!spans) {\n      for (var i = 1; i < styles.length; i+=2)\n        builder.addToken(builder, allText.slice(at, at = styles[i]), interpretTokenStyle(styles[i+1], builder.cm.options));\n      return;\n    }\n\n    var len = allText.length, pos = 0, i = 1, text = \"\", style, css;\n    var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed;\n    for (;;) {\n      if (nextChange == pos) { // Update current marker set\n        spanStyle = spanEndStyle = spanStartStyle = title = css = \"\";\n        collapsed = null; nextChange = Infinity;\n        var foundBookmarks = [];\n        for (var j = 0; j < spans.length; ++j) {\n          var sp = spans[j], m = sp.marker;\n          if (sp.from <= pos && (sp.to == null || sp.to > pos)) {\n            if (sp.to != null && nextChange > sp.to) { nextChange = sp.to; spanEndStyle = \"\"; }\n            if (m.className) spanStyle += \" \" + m.className;\n            if (m.css) css = m.css;\n            if (m.startStyle && sp.from == pos) spanStartStyle += \" \" + m.startStyle;\n            if (m.endStyle && sp.to == nextChange) spanEndStyle += \" \" + m.endStyle;\n            if (m.title && !title) title = m.title;\n            if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0))\n              collapsed = sp;\n          } else if (sp.from > pos && nextChange > sp.from) {\n            nextChange = sp.from;\n          }\n          if (m.type == \"bookmark\" && sp.from == pos && m.widgetNode) foundBookmarks.push(m);\n        }\n        if (collapsed && (collapsed.from || 0) == pos) {\n          buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos,\n                             collapsed.marker, collapsed.from == null);\n          if (collapsed.to == null) return;\n        }\n        if (!collapsed && foundBookmarks.length) for (var j = 0; j < foundBookmarks.length; ++j)\n          buildCollapsedSpan(builder, 0, foundBookmarks[j]);\n      }\n      if (pos >= len) break;\n\n      var upto = Math.min(len, nextChange);\n      while (true) {\n        if (text) {\n          var end = pos + text.length;\n          if (!collapsed) {\n            var tokenText = end > upto ? text.slice(0, upto - pos) : text;\n            builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle,\n                             spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : \"\", title, css);\n          }\n          if (end >= upto) {text = text.slice(upto - pos); pos = upto; break;}\n          pos = end;\n          spanStartStyle = \"\";\n        }\n        text = allText.slice(at, at = styles[i++]);\n        style = interpretTokenStyle(styles[i++], builder.cm.options);\n      }\n    }\n  }\n\n  // DOCUMENT DATA STRUCTURE\n\n  // By default, updates that start and end at the beginning of a line\n  // are treated specially, in order to make the association of line\n  // widgets and marker elements with the text behave more intuitive.\n  function isWholeLineUpdate(doc, change) {\n    return change.from.ch == 0 && change.to.ch == 0 && lst(change.text) == \"\" &&\n      (!doc.cm || doc.cm.options.wholeLineUpdateBefore);\n  }\n\n  // Perform a change on the document data structure.\n  function updateDoc(doc, change, markedSpans, estimateHeight) {\n    function spansFor(n) {return markedSpans ? markedSpans[n] : null;}\n    function update(line, text, spans) {\n      updateLine(line, text, spans, estimateHeight);\n      signalLater(line, \"change\", line, change);\n    }\n    function linesFor(start, end) {\n      for (var i = start, result = []; i < end; ++i)\n        result.push(new Line(text[i], spansFor(i), estimateHeight));\n      return result;\n    }\n\n    var from = change.from, to = change.to, text = change.text;\n    var firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line);\n    var lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line;\n\n    // Adjust the line structure\n    if (change.full) {\n      doc.insert(0, linesFor(0, text.length));\n      doc.remove(text.length, doc.size - text.length);\n    } else if (isWholeLineUpdate(doc, change)) {\n      // This is a whole-line replace. Treated specially to make\n      // sure line objects move the way they are supposed to.\n      var added = linesFor(0, text.length - 1);\n      update(lastLine, lastLine.text, lastSpans);\n      if (nlines) doc.remove(from.line, nlines);\n      if (added.length) doc.insert(from.line, added);\n    } else if (firstLine == lastLine) {\n      if (text.length == 1) {\n        update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans);\n      } else {\n        var added = linesFor(1, text.length - 1);\n        added.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight));\n        update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));\n        doc.insert(from.line + 1, added);\n      }\n    } else if (text.length == 1) {\n      update(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), spansFor(0));\n      doc.remove(from.line + 1, nlines);\n    } else {\n      update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));\n      update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans);\n      var added = linesFor(1, text.length - 1);\n      if (nlines > 1) doc.remove(from.line + 1, nlines - 1);\n      doc.insert(from.line + 1, added);\n    }\n\n    signalLater(doc, \"change\", doc, change);\n  }\n\n  // The document is represented as a BTree consisting of leaves, with\n  // chunk of lines in them, and branches, with up to ten leaves or\n  // other branch nodes below them. The top node is always a branch\n  // node, and is the document object itself (meaning it has\n  // additional methods and properties).\n  //\n  // All nodes have parent links. The tree is used both to go from\n  // line numbers to line objects, and to go from objects to numbers.\n  // It also indexes by height, and is used to convert between height\n  // and line object, and to find the total height of the document.\n  //\n  // See also http://marijnhaverbeke.nl/blog/codemirror-line-tree.html\n\n  function LeafChunk(lines) {\n    this.lines = lines;\n    this.parent = null;\n    for (var i = 0, height = 0; i < lines.length; ++i) {\n      lines[i].parent = this;\n      height += lines[i].height;\n    }\n    this.height = height;\n  }\n\n  LeafChunk.prototype = {\n    chunkSize: function() { return this.lines.length; },\n    // Remove the n lines at offset 'at'.\n    removeInner: function(at, n) {\n      for (var i = at, e = at + n; i < e; ++i) {\n        var line = this.lines[i];\n        this.height -= line.height;\n        cleanUpLine(line);\n        signalLater(line, \"delete\");\n      }\n      this.lines.splice(at, n);\n    },\n    // Helper used to collapse a small branch into a single leaf.\n    collapse: function(lines) {\n      lines.push.apply(lines, this.lines);\n    },\n    // Insert the given array of lines at offset 'at', count them as\n    // having the given height.\n    insertInner: function(at, lines, height) {\n      this.height += height;\n      this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at));\n      for (var i = 0; i < lines.length; ++i) lines[i].parent = this;\n    },\n    // Used to iterate over a part of the tree.\n    iterN: function(at, n, op) {\n      for (var e = at + n; at < e; ++at)\n        if (op(this.lines[at])) return true;\n    }\n  };\n\n  function BranchChunk(children) {\n    this.children = children;\n    var size = 0, height = 0;\n    for (var i = 0; i < children.length; ++i) {\n      var ch = children[i];\n      size += ch.chunkSize(); height += ch.height;\n      ch.parent = this;\n    }\n    this.size = size;\n    this.height = height;\n    this.parent = null;\n  }\n\n  BranchChunk.prototype = {\n    chunkSize: function() { return this.size; },\n    removeInner: function(at, n) {\n      this.size -= n;\n      for (var i = 0; i < this.children.length; ++i) {\n        var child = this.children[i], sz = child.chunkSize();\n        if (at < sz) {\n          var rm = Math.min(n, sz - at), oldHeight = child.height;\n          child.removeInner(at, rm);\n          this.height -= oldHeight - child.height;\n          if (sz == rm) { this.children.splice(i--, 1); child.parent = null; }\n          if ((n -= rm) == 0) break;\n          at = 0;\n        } else at -= sz;\n      }\n      // If the result is smaller than 25 lines, ensure that it is a\n      // single leaf node.\n      if (this.size - n < 25 &&\n          (this.children.length > 1 || !(this.children[0] instanceof LeafChunk))) {\n        var lines = [];\n        this.collapse(lines);\n        this.children = [new LeafChunk(lines)];\n        this.children[0].parent = this;\n      }\n    },\n    collapse: function(lines) {\n      for (var i = 0; i < this.children.length; ++i) this.children[i].collapse(lines);\n    },\n    insertInner: function(at, lines, height) {\n      this.size += lines.length;\n      this.height += height;\n      for (var i = 0; i < this.children.length; ++i) {\n        var child = this.children[i], sz = child.chunkSize();\n        if (at <= sz) {\n          child.insertInner(at, lines, height);\n          if (child.lines && child.lines.length > 50) {\n            while (child.lines.length > 50) {\n              var spilled = child.lines.splice(child.lines.length - 25, 25);\n              var newleaf = new LeafChunk(spilled);\n              child.height -= newleaf.height;\n              this.children.splice(i + 1, 0, newleaf);\n              newleaf.parent = this;\n            }\n            this.maybeSpill();\n          }\n          break;\n        }\n        at -= sz;\n      }\n    },\n    // When a node has grown, check whether it should be split.\n    maybeSpill: function() {\n      if (this.children.length <= 10) return;\n      var me = this;\n      do {\n        var spilled = me.children.splice(me.children.length - 5, 5);\n        var sibling = new BranchChunk(spilled);\n        if (!me.parent) { // Become the parent node\n          var copy = new BranchChunk(me.children);\n          copy.parent = me;\n          me.children = [copy, sibling];\n          me = copy;\n        } else {\n          me.size -= sibling.size;\n          me.height -= sibling.height;\n          var myIndex = indexOf(me.parent.children, me);\n          me.parent.children.splice(myIndex + 1, 0, sibling);\n        }\n        sibling.parent = me.parent;\n      } while (me.children.length > 10);\n      me.parent.maybeSpill();\n    },\n    iterN: function(at, n, op) {\n      for (var i = 0; i < this.children.length; ++i) {\n        var child = this.children[i], sz = child.chunkSize();\n        if (at < sz) {\n          var used = Math.min(n, sz - at);\n          if (child.iterN(at, used, op)) return true;\n          if ((n -= used) == 0) break;\n          at = 0;\n        } else at -= sz;\n      }\n    }\n  };\n\n  var nextDocId = 0;\n  var Doc = CodeMirror.Doc = function(text, mode, firstLine) {\n    if (!(this instanceof Doc)) return new Doc(text, mode, firstLine);\n    if (firstLine == null) firstLine = 0;\n\n    BranchChunk.call(this, [new LeafChunk([new Line(\"\", null)])]);\n    this.first = firstLine;\n    this.scrollTop = this.scrollLeft = 0;\n    this.cantEdit = false;\n    this.cleanGeneration = 1;\n    this.frontier = firstLine;\n    var start = Pos(firstLine, 0);\n    this.sel = simpleSelection(start);\n    this.history = new History(null);\n    this.id = ++nextDocId;\n    this.modeOption = mode;\n\n    if (typeof text == \"string\") text = splitLines(text);\n    updateDoc(this, {from: start, to: start, text: text});\n    setSelection(this, simpleSelection(start), sel_dontScroll);\n  };\n\n  Doc.prototype = createObj(BranchChunk.prototype, {\n    constructor: Doc,\n    // Iterate over the document. Supports two forms -- with only one\n    // argument, it calls that for each line in the document. With\n    // three, it iterates over the range given by the first two (with\n    // the second being non-inclusive).\n    iter: function(from, to, op) {\n      if (op) this.iterN(from - this.first, to - from, op);\n      else this.iterN(this.first, this.first + this.size, from);\n    },\n\n    // Non-public interface for adding and removing lines.\n    insert: function(at, lines) {\n      var height = 0;\n      for (var i = 0; i < lines.length; ++i) height += lines[i].height;\n      this.insertInner(at - this.first, lines, height);\n    },\n    remove: function(at, n) { this.removeInner(at - this.first, n); },\n\n    // From here, the methods are part of the public interface. Most\n    // are also available from CodeMirror (editor) instances.\n\n    getValue: function(lineSep) {\n      var lines = getLines(this, this.first, this.first + this.size);\n      if (lineSep === false) return lines;\n      return lines.join(lineSep || \"\\n\");\n    },\n    setValue: docMethodOp(function(code) {\n      var top = Pos(this.first, 0), last = this.first + this.size - 1;\n      makeChange(this, {from: top, to: Pos(last, getLine(this, last).text.length),\n                        text: splitLines(code), origin: \"setValue\", full: true}, true);\n      setSelection(this, simpleSelection(top));\n    }),\n    replaceRange: function(code, from, to, origin) {\n      from = clipPos(this, from);\n      to = to ? clipPos(this, to) : from;\n      replaceRange(this, code, from, to, origin);\n    },\n    getRange: function(from, to, lineSep) {\n      var lines = getBetween(this, clipPos(this, from), clipPos(this, to));\n      if (lineSep === false) return lines;\n      return lines.join(lineSep || \"\\n\");\n    },\n\n    getLine: function(line) {var l = this.getLineHandle(line); return l && l.text;},\n\n    getLineHandle: function(line) {if (isLine(this, line)) return getLine(this, line);},\n    getLineNumber: function(line) {return lineNo(line);},\n\n    getLineHandleVisualStart: function(line) {\n      if (typeof line == \"number\") line = getLine(this, line);\n      return visualLine(line);\n    },\n\n    lineCount: function() {return this.size;},\n    firstLine: function() {return this.first;},\n    lastLine: function() {return this.first + this.size - 1;},\n\n    clipPos: function(pos) {return clipPos(this, pos);},\n\n    getCursor: function(start) {\n      var range = this.sel.primary(), pos;\n      if (start == null || start == \"head\") pos = range.head;\n      else if (start == \"anchor\") pos = range.anchor;\n      else if (start == \"end\" || start == \"to\" || start === false) pos = range.to();\n      else pos = range.from();\n      return pos;\n    },\n    listSelections: function() { return this.sel.ranges; },\n    somethingSelected: function() {return this.sel.somethingSelected();},\n\n    setCursor: docMethodOp(function(line, ch, options) {\n      setSimpleSelection(this, clipPos(this, typeof line == \"number\" ? Pos(line, ch || 0) : line), null, options);\n    }),\n    setSelection: docMethodOp(function(anchor, head, options) {\n      setSimpleSelection(this, clipPos(this, anchor), clipPos(this, head || anchor), options);\n    }),\n    extendSelection: docMethodOp(function(head, other, options) {\n      extendSelection(this, clipPos(this, head), other && clipPos(this, other), options);\n    }),\n    extendSelections: docMethodOp(function(heads, options) {\n      extendSelections(this, clipPosArray(this, heads, options));\n    }),\n    extendSelectionsBy: docMethodOp(function(f, options) {\n      extendSelections(this, map(this.sel.ranges, f), options);\n    }),\n    setSelections: docMethodOp(function(ranges, primary, options) {\n      if (!ranges.length) return;\n      for (var i = 0, out = []; i < ranges.length; i++)\n        out[i] = new Range(clipPos(this, ranges[i].anchor),\n                           clipPos(this, ranges[i].head));\n      if (primary == null) primary = Math.min(ranges.length - 1, this.sel.primIndex);\n      setSelection(this, normalizeSelection(out, primary), options);\n    }),\n    addSelection: docMethodOp(function(anchor, head, options) {\n      var ranges = this.sel.ranges.slice(0);\n      ranges.push(new Range(clipPos(this, anchor), clipPos(this, head || anchor)));\n      setSelection(this, normalizeSelection(ranges, ranges.length - 1), options);\n    }),\n\n    getSelection: function(lineSep) {\n      var ranges = this.sel.ranges, lines;\n      for (var i = 0; i < ranges.length; i++) {\n        var sel = getBetween(this, ranges[i].from(), ranges[i].to());\n        lines = lines ? lines.concat(sel) : sel;\n      }\n      if (lineSep === false) return lines;\n      else return lines.join(lineSep || \"\\n\");\n    },\n    getSelections: function(lineSep) {\n      var parts = [], ranges = this.sel.ranges;\n      for (var i = 0; i < ranges.length; i++) {\n        var sel = getBetween(this, ranges[i].from(), ranges[i].to());\n        if (lineSep !== false) sel = sel.join(lineSep || \"\\n\");\n        parts[i] = sel;\n      }\n      return parts;\n    },\n    replaceSelection: function(code, collapse, origin) {\n      var dup = [];\n      for (var i = 0; i < this.sel.ranges.length; i++)\n        dup[i] = code;\n      this.replaceSelections(dup, collapse, origin || \"+input\");\n    },\n    replaceSelections: docMethodOp(function(code, collapse, origin) {\n      var changes = [], sel = this.sel;\n      for (var i = 0; i < sel.ranges.length; i++) {\n        var range = sel.ranges[i];\n        changes[i] = {from: range.from(), to: range.to(), text: splitLines(code[i]), origin: origin};\n      }\n      var newSel = collapse && collapse != \"end\" && computeReplacedSel(this, changes, collapse);\n      for (var i = changes.length - 1; i >= 0; i--)\n        makeChange(this, changes[i]);\n      if (newSel) setSelectionReplaceHistory(this, newSel);\n      else if (this.cm) ensureCursorVisible(this.cm);\n    }),\n    undo: docMethodOp(function() {makeChangeFromHistory(this, \"undo\");}),\n    redo: docMethodOp(function() {makeChangeFromHistory(this, \"redo\");}),\n    undoSelection: docMethodOp(function() {makeChangeFromHistory(this, \"undo\", true);}),\n    redoSelection: docMethodOp(function() {makeChangeFromHistory(this, \"redo\", true);}),\n\n    setExtending: function(val) {this.extend = val;},\n    getExtending: function() {return this.extend;},\n\n    historySize: function() {\n      var hist = this.history, done = 0, undone = 0;\n      for (var i = 0; i < hist.done.length; i++) if (!hist.done[i].ranges) ++done;\n      for (var i = 0; i < hist.undone.length; i++) if (!hist.undone[i].ranges) ++undone;\n      return {undo: done, redo: undone};\n    },\n    clearHistory: function() {this.history = new History(this.history.maxGeneration);},\n\n    markClean: function() {\n      this.cleanGeneration = this.changeGeneration(true);\n    },\n    changeGeneration: function(forceSplit) {\n      if (forceSplit)\n        this.history.lastOp = this.history.lastSelOp = this.history.lastOrigin = null;\n      return this.history.generation;\n    },\n    isClean: function (gen) {\n      return this.history.generation == (gen || this.cleanGeneration);\n    },\n\n    getHistory: function() {\n      return {done: copyHistoryArray(this.history.done),\n              undone: copyHistoryArray(this.history.undone)};\n    },\n    setHistory: function(histData) {\n      var hist = this.history = new History(this.history.maxGeneration);\n      hist.done = copyHistoryArray(histData.done.slice(0), null, true);\n      hist.undone = copyHistoryArray(histData.undone.slice(0), null, true);\n    },\n\n    addLineClass: docMethodOp(function(handle, where, cls) {\n      return changeLine(this, handle, where == \"gutter\" ? \"gutter\" : \"class\", function(line) {\n        var prop = where == \"text\" ? \"textClass\"\n                 : where == \"background\" ? \"bgClass\"\n                 : where == \"gutter\" ? \"gutterClass\" : \"wrapClass\";\n        if (!line[prop]) line[prop] = cls;\n        else if (classTest(cls).test(line[prop])) return false;\n        else line[prop] += \" \" + cls;\n        return true;\n      });\n    }),\n    removeLineClass: docMethodOp(function(handle, where, cls) {\n      return changeLine(this, handle, where == \"gutter\" ? \"gutter\" : \"class\", function(line) {\n        var prop = where == \"text\" ? \"textClass\"\n                 : where == \"background\" ? \"bgClass\"\n                 : where == \"gutter\" ? \"gutterClass\" : \"wrapClass\";\n        var cur = line[prop];\n        if (!cur) return false;\n        else if (cls == null) line[prop] = null;\n        else {\n          var found = cur.match(classTest(cls));\n          if (!found) return false;\n          var end = found.index + found[0].length;\n          line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? \"\" : \" \") + cur.slice(end) || null;\n        }\n        return true;\n      });\n    }),\n\n    markText: function(from, to, options) {\n      return markText(this, clipPos(this, from), clipPos(this, to), options, \"range\");\n    },\n    setBookmark: function(pos, options) {\n      var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options),\n                      insertLeft: options && options.insertLeft,\n                      clearWhenEmpty: false, shared: options && options.shared};\n      pos = clipPos(this, pos);\n      return markText(this, pos, pos, realOpts, \"bookmark\");\n    },\n    findMarksAt: function(pos) {\n      pos = clipPos(this, pos);\n      var markers = [], spans = getLine(this, pos.line).markedSpans;\n      if (spans) for (var i = 0; i < spans.length; ++i) {\n        var span = spans[i];\n        if ((span.from == null || span.from <= pos.ch) &&\n            (span.to == null || span.to >= pos.ch))\n          markers.push(span.marker.parent || span.marker);\n      }\n      return markers;\n    },\n    findMarks: function(from, to, filter) {\n      from = clipPos(this, from); to = clipPos(this, to);\n      var found = [], lineNo = from.line;\n      this.iter(from.line, to.line + 1, function(line) {\n        var spans = line.markedSpans;\n        if (spans) for (var i = 0; i < spans.length; i++) {\n          var span = spans[i];\n          if (!(lineNo == from.line && from.ch > span.to ||\n                span.from == null && lineNo != from.line||\n                lineNo == to.line && span.from > to.ch) &&\n              (!filter || filter(span.marker)))\n            found.push(span.marker.parent || span.marker);\n        }\n        ++lineNo;\n      });\n      return found;\n    },\n    getAllMarks: function() {\n      var markers = [];\n      this.iter(function(line) {\n        var sps = line.markedSpans;\n        if (sps) for (var i = 0; i < sps.length; ++i)\n          if (sps[i].from != null) markers.push(sps[i].marker);\n      });\n      return markers;\n    },\n\n    posFromIndex: function(off) {\n      var ch, lineNo = this.first;\n      this.iter(function(line) {\n        var sz = line.text.length + 1;\n        if (sz > off) { ch = off; return true; }\n        off -= sz;\n        ++lineNo;\n      });\n      return clipPos(this, Pos(lineNo, ch));\n    },\n    indexFromPos: function (coords) {\n      coords = clipPos(this, coords);\n      var index = coords.ch;\n      if (coords.line < this.first || coords.ch < 0) return 0;\n      this.iter(this.first, coords.line, function (line) {\n        index += line.text.length + 1;\n      });\n      return index;\n    },\n\n    copy: function(copyHistory) {\n      var doc = new Doc(getLines(this, this.first, this.first + this.size), this.modeOption, this.first);\n      doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft;\n      doc.sel = this.sel;\n      doc.extend = false;\n      if (copyHistory) {\n        doc.history.undoDepth = this.history.undoDepth;\n        doc.setHistory(this.getHistory());\n      }\n      return doc;\n    },\n\n    linkedDoc: function(options) {\n      if (!options) options = {};\n      var from = this.first, to = this.first + this.size;\n      if (options.from != null && options.from > from) from = options.from;\n      if (options.to != null && options.to < to) to = options.to;\n      var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from);\n      if (options.sharedHist) copy.history = this.history;\n      (this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist});\n      copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}];\n      copySharedMarkers(copy, findSharedMarkers(this));\n      return copy;\n    },\n    unlinkDoc: function(other) {\n      if (other instanceof CodeMirror) other = other.doc;\n      if (this.linked) for (var i = 0; i < this.linked.length; ++i) {\n        var link = this.linked[i];\n        if (link.doc != other) continue;\n        this.linked.splice(i, 1);\n        other.unlinkDoc(this);\n        detachSharedMarkers(findSharedMarkers(this));\n        break;\n      }\n      // If the histories were shared, split them again\n      if (other.history == this.history) {\n        var splitIds = [other.id];\n        linkedDocs(other, function(doc) {splitIds.push(doc.id);}, true);\n        other.history = new History(null);\n        other.history.done = copyHistoryArray(this.history.done, splitIds);\n        other.history.undone = copyHistoryArray(this.history.undone, splitIds);\n      }\n    },\n    iterLinkedDocs: function(f) {linkedDocs(this, f);},\n\n    getMode: function() {return this.mode;},\n    getEditor: function() {return this.cm;}\n  });\n\n  // Public alias.\n  Doc.prototype.eachLine = Doc.prototype.iter;\n\n  // Set up methods on CodeMirror's prototype to redirect to the editor's document.\n  var dontDelegate = \"iter insert remove copy getEditor\".split(\" \");\n  for (var prop in Doc.prototype) if (Doc.prototype.hasOwnProperty(prop) && indexOf(dontDelegate, prop) < 0)\n    CodeMirror.prototype[prop] = (function(method) {\n      return function() {return method.apply(this.doc, arguments);};\n    })(Doc.prototype[prop]);\n\n  eventMixin(Doc);\n\n  // Call f for all linked documents.\n  function linkedDocs(doc, f, sharedHistOnly) {\n    function propagate(doc, skip, sharedHist) {\n      if (doc.linked) for (var i = 0; i < doc.linked.length; ++i) {\n        var rel = doc.linked[i];\n        if (rel.doc == skip) continue;\n        var shared = sharedHist && rel.sharedHist;\n        if (sharedHistOnly && !shared) continue;\n        f(rel.doc, shared);\n        propagate(rel.doc, doc, shared);\n      }\n    }\n    propagate(doc, null, true);\n  }\n\n  // Attach a document to an editor.\n  function attachDoc(cm, doc) {\n    if (doc.cm) throw new Error(\"This document is already in use.\");\n    cm.doc = doc;\n    doc.cm = cm;\n    estimateLineHeights(cm);\n    loadMode(cm);\n    if (!cm.options.lineWrapping) findMaxLine(cm);\n    cm.options.mode = doc.modeOption;\n    regChange(cm);\n  }\n\n  // LINE UTILITIES\n\n  // Find the line object corresponding to the given line number.\n  function getLine(doc, n) {\n    n -= doc.first;\n    if (n < 0 || n >= doc.size) throw new Error(\"There is no line \" + (n + doc.first) + \" in the document.\");\n    for (var chunk = doc; !chunk.lines;) {\n      for (var i = 0;; ++i) {\n        var child = chunk.children[i], sz = child.chunkSize();\n        if (n < sz) { chunk = child; break; }\n        n -= sz;\n      }\n    }\n    return chunk.lines[n];\n  }\n\n  // Get the part of a document between two positions, as an array of\n  // strings.\n  function getBetween(doc, start, end) {\n    var out = [], n = start.line;\n    doc.iter(start.line, end.line + 1, function(line) {\n      var text = line.text;\n      if (n == end.line) text = text.slice(0, end.ch);\n      if (n == start.line) text = text.slice(start.ch);\n      out.push(text);\n      ++n;\n    });\n    return out;\n  }\n  // Get the lines between from and to, as array of strings.\n  function getLines(doc, from, to) {\n    var out = [];\n    doc.iter(from, to, function(line) { out.push(line.text); });\n    return out;\n  }\n\n  // Update the height of a line, propagating the height change\n  // upwards to parent nodes.\n  function updateLineHeight(line, height) {\n    var diff = height - line.height;\n    if (diff) for (var n = line; n; n = n.parent) n.height += diff;\n  }\n\n  // Given a line object, find its line number by walking up through\n  // its parent links.\n  function lineNo(line) {\n    if (line.parent == null) return null;\n    var cur = line.parent, no = indexOf(cur.lines, line);\n    for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) {\n      for (var i = 0;; ++i) {\n        if (chunk.children[i] == cur) break;\n        no += chunk.children[i].chunkSize();\n      }\n    }\n    return no + cur.first;\n  }\n\n  // Find the line at the given vertical position, using the height\n  // information in the document tree.\n  function lineAtHeight(chunk, h) {\n    var n = chunk.first;\n    outer: do {\n      for (var i = 0; i < chunk.children.length; ++i) {\n        var child = chunk.children[i], ch = child.height;\n        if (h < ch) { chunk = child; continue outer; }\n        h -= ch;\n        n += child.chunkSize();\n      }\n      return n;\n    } while (!chunk.lines);\n    for (var i = 0; i < chunk.lines.length; ++i) {\n      var line = chunk.lines[i], lh = line.height;\n      if (h < lh) break;\n      h -= lh;\n    }\n    return n + i;\n  }\n\n\n  // Find the height above the given line.\n  function heightAtLine(lineObj) {\n    lineObj = visualLine(lineObj);\n\n    var h = 0, chunk = lineObj.parent;\n    for (var i = 0; i < chunk.lines.length; ++i) {\n      var line = chunk.lines[i];\n      if (line == lineObj) break;\n      else h += line.height;\n    }\n    for (var p = chunk.parent; p; chunk = p, p = chunk.parent) {\n      for (var i = 0; i < p.children.length; ++i) {\n        var cur = p.children[i];\n        if (cur == chunk) break;\n        else h += cur.height;\n      }\n    }\n    return h;\n  }\n\n  // Get the bidi ordering for the given line (and cache it). Returns\n  // false for lines that are fully left-to-right, and an array of\n  // BidiSpan objects otherwise.\n  function getOrder(line) {\n    var order = line.order;\n    if (order == null) order = line.order = bidiOrdering(line.text);\n    return order;\n  }\n\n  // HISTORY\n\n  function History(startGen) {\n    // Arrays of change events and selections. Doing something adds an\n    // event to done and clears undo. Undoing moves events from done\n    // to undone, redoing moves them in the other direction.\n    this.done = []; this.undone = [];\n    this.undoDepth = Infinity;\n    // Used to track when changes can be merged into a single undo\n    // event\n    this.lastModTime = this.lastSelTime = 0;\n    this.lastOp = this.lastSelOp = null;\n    this.lastOrigin = this.lastSelOrigin = null;\n    // Used by the isClean() method\n    this.generation = this.maxGeneration = startGen || 1;\n  }\n\n  // Create a history change event from an updateDoc-style change\n  // object.\n  function historyChangeFromChange(doc, change) {\n    var histChange = {from: copyPos(change.from), to: changeEnd(change), text: getBetween(doc, change.from, change.to)};\n    attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);\n    linkedDocs(doc, function(doc) {attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);}, true);\n    return histChange;\n  }\n\n  // Pop all selection events off the end of a history array. Stop at\n  // a change event.\n  function clearSelectionEvents(array) {\n    while (array.length) {\n      var last = lst(array);\n      if (last.ranges) array.pop();\n      else break;\n    }\n  }\n\n  // Find the top change event in the history. Pop off selection\n  // events that are in the way.\n  function lastChangeEvent(hist, force) {\n    if (force) {\n      clearSelectionEvents(hist.done);\n      return lst(hist.done);\n    } else if (hist.done.length && !lst(hist.done).ranges) {\n      return lst(hist.done);\n    } else if (hist.done.length > 1 && !hist.done[hist.done.length - 2].ranges) {\n      hist.done.pop();\n      return lst(hist.done);\n    }\n  }\n\n  // Register a change in the history. Merges changes that are within\n  // a single operation, ore are close together with an origin that\n  // allows merging (starting with \"+\") into a single event.\n  function addChangeToHistory(doc, change, selAfter, opId) {\n    var hist = doc.history;\n    hist.undone.length = 0;\n    var time = +new Date, cur;\n\n    if ((hist.lastOp == opId ||\n         hist.lastOrigin == change.origin && change.origin &&\n         ((change.origin.charAt(0) == \"+\" && doc.cm && hist.lastModTime > time - doc.cm.options.historyEventDelay) ||\n          change.origin.charAt(0) == \"*\")) &&\n        (cur = lastChangeEvent(hist, hist.lastOp == opId))) {\n      // Merge this change into the last event\n      var last = lst(cur.changes);\n      if (cmp(change.from, change.to) == 0 && cmp(change.from, last.to) == 0) {\n        // Optimized case for simple insertion -- don't want to add\n        // new changesets for every character typed\n        last.to = changeEnd(change);\n      } else {\n        // Add new sub-event\n        cur.changes.push(historyChangeFromChange(doc, change));\n      }\n    } else {\n      // Can not be merged, start a new event.\n      var before = lst(hist.done);\n      if (!before || !before.ranges)\n        pushSelectionToHistory(doc.sel, hist.done);\n      cur = {changes: [historyChangeFromChange(doc, change)],\n             generation: hist.generation};\n      hist.done.push(cur);\n      while (hist.done.length > hist.undoDepth) {\n        hist.done.shift();\n        if (!hist.done[0].ranges) hist.done.shift();\n      }\n    }\n    hist.done.push(selAfter);\n    hist.generation = ++hist.maxGeneration;\n    hist.lastModTime = hist.lastSelTime = time;\n    hist.lastOp = hist.lastSelOp = opId;\n    hist.lastOrigin = hist.lastSelOrigin = change.origin;\n\n    if (!last) signal(doc, \"historyAdded\");\n  }\n\n  function selectionEventCanBeMerged(doc, origin, prev, sel) {\n    var ch = origin.charAt(0);\n    return ch == \"*\" ||\n      ch == \"+\" &&\n      prev.ranges.length == sel.ranges.length &&\n      prev.somethingSelected() == sel.somethingSelected() &&\n      new Date - doc.history.lastSelTime <= (doc.cm ? doc.cm.options.historyEventDelay : 500);\n  }\n\n  // Called whenever the selection changes, sets the new selection as\n  // the pending selection in the history, and pushes the old pending\n  // selection into the 'done' array when it was significantly\n  // different (in number of selected ranges, emptiness, or time).\n  function addSelectionToHistory(doc, sel, opId, options) {\n    var hist = doc.history, origin = options && options.origin;\n\n    // A new event is started when the previous origin does not match\n    // the current, or the origins don't allow matching. Origins\n    // starting with * are always merged, those starting with + are\n    // merged when similar and close together in time.\n    if (opId == hist.lastSelOp ||\n        (origin && hist.lastSelOrigin == origin &&\n         (hist.lastModTime == hist.lastSelTime && hist.lastOrigin == origin ||\n          selectionEventCanBeMerged(doc, origin, lst(hist.done), sel))))\n      hist.done[hist.done.length - 1] = sel;\n    else\n      pushSelectionToHistory(sel, hist.done);\n\n    hist.lastSelTime = +new Date;\n    hist.lastSelOrigin = origin;\n    hist.lastSelOp = opId;\n    if (options && options.clearRedo !== false)\n      clearSelectionEvents(hist.undone);\n  }\n\n  function pushSelectionToHistory(sel, dest) {\n    var top = lst(dest);\n    if (!(top && top.ranges && top.equals(sel)))\n      dest.push(sel);\n  }\n\n  // Used to store marked span information in the history.\n  function attachLocalSpans(doc, change, from, to) {\n    var existing = change[\"spans_\" + doc.id], n = 0;\n    doc.iter(Math.max(doc.first, from), Math.min(doc.first + doc.size, to), function(line) {\n      if (line.markedSpans)\n        (existing || (existing = change[\"spans_\" + doc.id] = {}))[n] = line.markedSpans;\n      ++n;\n    });\n  }\n\n  // When un/re-doing restores text containing marked spans, those\n  // that have been explicitly cleared should not be restored.\n  function removeClearedSpans(spans) {\n    if (!spans) return null;\n    for (var i = 0, out; i < spans.length; ++i) {\n      if (spans[i].marker.explicitlyCleared) { if (!out) out = spans.slice(0, i); }\n      else if (out) out.push(spans[i]);\n    }\n    return !out ? spans : out.length ? out : null;\n  }\n\n  // Retrieve and filter the old marked spans stored in a change event.\n  function getOldSpans(doc, change) {\n    var found = change[\"spans_\" + doc.id];\n    if (!found) return null;\n    for (var i = 0, nw = []; i < change.text.length; ++i)\n      nw.push(removeClearedSpans(found[i]));\n    return nw;\n  }\n\n  // Used both to provide a JSON-safe object in .getHistory, and, when\n  // detaching a document, to split the history in two\n  function copyHistoryArray(events, newGroup, instantiateSel) {\n    for (var i = 0, copy = []; i < events.length; ++i) {\n      var event = events[i];\n      if (event.ranges) {\n        copy.push(instantiateSel ? Selection.prototype.deepCopy.call(event) : event);\n        continue;\n      }\n      var changes = event.changes, newChanges = [];\n      copy.push({changes: newChanges});\n      for (var j = 0; j < changes.length; ++j) {\n        var change = changes[j], m;\n        newChanges.push({from: change.from, to: change.to, text: change.text});\n        if (newGroup) for (var prop in change) if (m = prop.match(/^spans_(\\d+)$/)) {\n          if (indexOf(newGroup, Number(m[1])) > -1) {\n            lst(newChanges)[prop] = change[prop];\n            delete change[prop];\n          }\n        }\n      }\n    }\n    return copy;\n  }\n\n  // Rebasing/resetting history to deal with externally-sourced changes\n\n  function rebaseHistSelSingle(pos, from, to, diff) {\n    if (to < pos.line) {\n      pos.line += diff;\n    } else if (from < pos.line) {\n      pos.line = from;\n      pos.ch = 0;\n    }\n  }\n\n  // Tries to rebase an array of history events given a change in the\n  // document. If the change touches the same lines as the event, the\n  // event, and everything 'behind' it, is discarded. If the change is\n  // before the event, the event's positions are updated. Uses a\n  // copy-on-write scheme for the positions, to avoid having to\n  // reallocate them all on every rebase, but also avoid problems with\n  // shared position objects being unsafely updated.\n  function rebaseHistArray(array, from, to, diff) {\n    for (var i = 0; i < array.length; ++i) {\n      var sub = array[i], ok = true;\n      if (sub.ranges) {\n        if (!sub.copied) { sub = array[i] = sub.deepCopy(); sub.copied = true; }\n        for (var j = 0; j < sub.ranges.length; j++) {\n          rebaseHistSelSingle(sub.ranges[j].anchor, from, to, diff);\n          rebaseHistSelSingle(sub.ranges[j].head, from, to, diff);\n        }\n        continue;\n      }\n      for (var j = 0; j < sub.changes.length; ++j) {\n        var cur = sub.changes[j];\n        if (to < cur.from.line) {\n          cur.from = Pos(cur.from.line + diff, cur.from.ch);\n          cur.to = Pos(cur.to.line + diff, cur.to.ch);\n        } else if (from <= cur.to.line) {\n          ok = false;\n          break;\n        }\n      }\n      if (!ok) {\n        array.splice(0, i + 1);\n        i = 0;\n      }\n    }\n  }\n\n  function rebaseHist(hist, change) {\n    var from = change.from.line, to = change.to.line, diff = change.text.length - (to - from) - 1;\n    rebaseHistArray(hist.done, from, to, diff);\n    rebaseHistArray(hist.undone, from, to, diff);\n  }\n\n  // EVENT UTILITIES\n\n  // Due to the fact that we still support jurassic IE versions, some\n  // compatibility wrappers are needed.\n\n  var e_preventDefault = CodeMirror.e_preventDefault = function(e) {\n    if (e.preventDefault) e.preventDefault();\n    else e.returnValue = false;\n  };\n  var e_stopPropagation = CodeMirror.e_stopPropagation = function(e) {\n    if (e.stopPropagation) e.stopPropagation();\n    else e.cancelBubble = true;\n  };\n  function e_defaultPrevented(e) {\n    return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false;\n  }\n  var e_stop = CodeMirror.e_stop = function(e) {e_preventDefault(e); e_stopPropagation(e);};\n\n  function e_target(e) {return e.target || e.srcElement;}\n  function e_button(e) {\n    var b = e.which;\n    if (b == null) {\n      if (e.button & 1) b = 1;\n      else if (e.button & 2) b = 3;\n      else if (e.button & 4) b = 2;\n    }\n    if (mac && e.ctrlKey && b == 1) b = 3;\n    return b;\n  }\n\n  // EVENT HANDLING\n\n  // Lightweight event framework. on/off also work on DOM nodes,\n  // registering native DOM handlers.\n\n  var on = CodeMirror.on = function(emitter, type, f) {\n    if (emitter.addEventListener)\n      emitter.addEventListener(type, f, false);\n    else if (emitter.attachEvent)\n      emitter.attachEvent(\"on\" + type, f);\n    else {\n      var map = emitter._handlers || (emitter._handlers = {});\n      var arr = map[type] || (map[type] = []);\n      arr.push(f);\n    }\n  };\n\n  var off = CodeMirror.off = function(emitter, type, f) {\n    if (emitter.removeEventListener)\n      emitter.removeEventListener(type, f, false);\n    else if (emitter.detachEvent)\n      emitter.detachEvent(\"on\" + type, f);\n    else {\n      var arr = emitter._handlers && emitter._handlers[type];\n      if (!arr) return;\n      for (var i = 0; i < arr.length; ++i)\n        if (arr[i] == f) { arr.splice(i, 1); break; }\n    }\n  };\n\n  var signal = CodeMirror.signal = function(emitter, type /*, values...*/) {\n    var arr = emitter._handlers && emitter._handlers[type];\n    if (!arr) return;\n    var args = Array.prototype.slice.call(arguments, 2);\n    for (var i = 0; i < arr.length; ++i) arr[i].apply(null, args);\n  };\n\n  var orphanDelayedCallbacks = null;\n\n  // Often, we want to signal events at a point where we are in the\n  // middle of some work, but don't want the handler to start calling\n  // other methods on the editor, which might be in an inconsistent\n  // state or simply not expect any other events to happen.\n  // signalLater looks whether there are any handlers, and schedules\n  // them to be executed when the last operation ends, or, if no\n  // operation is active, when a timeout fires.\n  function signalLater(emitter, type /*, values...*/) {\n    var arr = emitter._handlers && emitter._handlers[type];\n    if (!arr) return;\n    var args = Array.prototype.slice.call(arguments, 2), list;\n    if (operationGroup) {\n      list = operationGroup.delayedCallbacks;\n    } else if (orphanDelayedCallbacks) {\n      list = orphanDelayedCallbacks;\n    } else {\n      list = orphanDelayedCallbacks = [];\n      setTimeout(fireOrphanDelayed, 0);\n    }\n    function bnd(f) {return function(){f.apply(null, args);};};\n    for (var i = 0; i < arr.length; ++i)\n      list.push(bnd(arr[i]));\n  }\n\n  function fireOrphanDelayed() {\n    var delayed = orphanDelayedCallbacks;\n    orphanDelayedCallbacks = null;\n    for (var i = 0; i < delayed.length; ++i) delayed[i]();\n  }\n\n  // The DOM events that CodeMirror handles can be overridden by\n  // registering a (non-DOM) handler on the editor for the event name,\n  // and preventDefault-ing the event in that handler.\n  function signalDOMEvent(cm, e, override) {\n    if (typeof e == \"string\")\n      e = {type: e, preventDefault: function() { this.defaultPrevented = true; }};\n    signal(cm, override || e.type, cm, e);\n    return e_defaultPrevented(e) || e.codemirrorIgnore;\n  }\n\n  function signalCursorActivity(cm) {\n    var arr = cm._handlers && cm._handlers.cursorActivity;\n    if (!arr) return;\n    var set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = []);\n    for (var i = 0; i < arr.length; ++i) if (indexOf(set, arr[i]) == -1)\n      set.push(arr[i]);\n  }\n\n  function hasHandler(emitter, type) {\n    var arr = emitter._handlers && emitter._handlers[type];\n    return arr && arr.length > 0;\n  }\n\n  // Add on and off methods to a constructor's prototype, to make\n  // registering events on such objects more convenient.\n  function eventMixin(ctor) {\n    ctor.prototype.on = function(type, f) {on(this, type, f);};\n    ctor.prototype.off = function(type, f) {off(this, type, f);};\n  }\n\n  // MISC UTILITIES\n\n  // Number of pixels added to scroller and sizer to hide scrollbar\n  var scrollerGap = 30;\n\n  // Returned or thrown by various protocols to signal 'I'm not\n  // handling this'.\n  var Pass = CodeMirror.Pass = {toString: function(){return \"CodeMirror.Pass\";}};\n\n  // Reused option objects for setSelection & friends\n  var sel_dontScroll = {scroll: false}, sel_mouse = {origin: \"*mouse\"}, sel_move = {origin: \"+move\"};\n\n  function Delayed() {this.id = null;}\n  Delayed.prototype.set = function(ms, f) {\n    clearTimeout(this.id);\n    this.id = setTimeout(f, ms);\n  };\n\n  // Counts the column offset in a string, taking tabs into account.\n  // Used mostly to find indentation.\n  var countColumn = CodeMirror.countColumn = function(string, end, tabSize, startIndex, startValue) {\n    if (end == null) {\n      end = string.search(/[^\\s\\u00a0]/);\n      if (end == -1) end = string.length;\n    }\n    for (var i = startIndex || 0, n = startValue || 0;;) {\n      var nextTab = string.indexOf(\"\\t\", i);\n      if (nextTab < 0 || nextTab >= end)\n        return n + (end - i);\n      n += nextTab - i;\n      n += tabSize - (n % tabSize);\n      i = nextTab + 1;\n    }\n  };\n\n  // The inverse of countColumn -- find the offset that corresponds to\n  // a particular column.\n  function findColumn(string, goal, tabSize) {\n    for (var pos = 0, col = 0;;) {\n      var nextTab = string.indexOf(\"\\t\", pos);\n      if (nextTab == -1) nextTab = string.length;\n      var skipped = nextTab - pos;\n      if (nextTab == string.length || col + skipped >= goal)\n        return pos + Math.min(skipped, goal - col);\n      col += nextTab - pos;\n      col += tabSize - (col % tabSize);\n      pos = nextTab + 1;\n      if (col >= goal) return pos;\n    }\n  }\n\n  var spaceStrs = [\"\"];\n  function spaceStr(n) {\n    while (spaceStrs.length <= n)\n      spaceStrs.push(lst(spaceStrs) + \" \");\n    return spaceStrs[n];\n  }\n\n  function lst(arr) { return arr[arr.length-1]; }\n\n  var selectInput = function(node) { node.select(); };\n  if (ios) // Mobile Safari apparently has a bug where select() is broken.\n    selectInput = function(node) { node.selectionStart = 0; node.selectionEnd = node.value.length; };\n  else if (ie) // Suppress mysterious IE10 errors\n    selectInput = function(node) { try { node.select(); } catch(_e) {} };\n\n  function indexOf(array, elt) {\n    for (var i = 0; i < array.length; ++i)\n      if (array[i] == elt) return i;\n    return -1;\n  }\n  function map(array, f) {\n    var out = [];\n    for (var i = 0; i < array.length; i++) out[i] = f(array[i], i);\n    return out;\n  }\n\n  function nothing() {}\n\n  function createObj(base, props) {\n    var inst;\n    if (Object.create) {\n      inst = Object.create(base);\n    } else {\n      nothing.prototype = base;\n      inst = new nothing();\n    }\n    if (props) copyObj(props, inst);\n    return inst;\n  };\n\n  function copyObj(obj, target, overwrite) {\n    if (!target) target = {};\n    for (var prop in obj)\n      if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop)))\n        target[prop] = obj[prop];\n    return target;\n  }\n\n  function bind(f) {\n    var args = Array.prototype.slice.call(arguments, 1);\n    return function(){return f.apply(null, args);};\n  }\n\n  var nonASCIISingleCaseWordChar = /[\\u00df\\u0590-\\u05f4\\u0600-\\u06ff\\u3040-\\u309f\\u30a0-\\u30ff\\u3400-\\u4db5\\u4e00-\\u9fcc\\uac00-\\ud7af]/;\n  var isWordCharBasic = CodeMirror.isWordChar = function(ch) {\n    return /\\w/.test(ch) || ch > \"\\x80\" &&\n      (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch));\n  };\n  function isWordChar(ch, helper) {\n    if (!helper) return isWordCharBasic(ch);\n    if (helper.source.indexOf(\"\\\\w\") > -1 && isWordCharBasic(ch)) return true;\n    return helper.test(ch);\n  }\n\n  function isEmpty(obj) {\n    for (var n in obj) if (obj.hasOwnProperty(n) && obj[n]) return false;\n    return true;\n  }\n\n  // Extending unicode characters. A series of a non-extending char +\n  // any number of extending chars is treated as a single unit as far\n  // as editing and measuring is concerned. This is not fully correct,\n  // since some scripts/fonts/browsers also treat other configurations\n  // of code points as a group.\n  var extendingChars = /[\\u0300-\\u036f\\u0483-\\u0489\\u0591-\\u05bd\\u05bf\\u05c1\\u05c2\\u05c4\\u05c5\\u05c7\\u0610-\\u061a\\u064b-\\u065e\\u0670\\u06d6-\\u06dc\\u06de-\\u06e4\\u06e7\\u06e8\\u06ea-\\u06ed\\u0711\\u0730-\\u074a\\u07a6-\\u07b0\\u07eb-\\u07f3\\u0816-\\u0819\\u081b-\\u0823\\u0825-\\u0827\\u0829-\\u082d\\u0900-\\u0902\\u093c\\u0941-\\u0948\\u094d\\u0951-\\u0955\\u0962\\u0963\\u0981\\u09bc\\u09be\\u09c1-\\u09c4\\u09cd\\u09d7\\u09e2\\u09e3\\u0a01\\u0a02\\u0a3c\\u0a41\\u0a42\\u0a47\\u0a48\\u0a4b-\\u0a4d\\u0a51\\u0a70\\u0a71\\u0a75\\u0a81\\u0a82\\u0abc\\u0ac1-\\u0ac5\\u0ac7\\u0ac8\\u0acd\\u0ae2\\u0ae3\\u0b01\\u0b3c\\u0b3e\\u0b3f\\u0b41-\\u0b44\\u0b4d\\u0b56\\u0b57\\u0b62\\u0b63\\u0b82\\u0bbe\\u0bc0\\u0bcd\\u0bd7\\u0c3e-\\u0c40\\u0c46-\\u0c48\\u0c4a-\\u0c4d\\u0c55\\u0c56\\u0c62\\u0c63\\u0cbc\\u0cbf\\u0cc2\\u0cc6\\u0ccc\\u0ccd\\u0cd5\\u0cd6\\u0ce2\\u0ce3\\u0d3e\\u0d41-\\u0d44\\u0d4d\\u0d57\\u0d62\\u0d63\\u0dca\\u0dcf\\u0dd2-\\u0dd4\\u0dd6\\u0ddf\\u0e31\\u0e34-\\u0e3a\\u0e47-\\u0e4e\\u0eb1\\u0eb4-\\u0eb9\\u0ebb\\u0ebc\\u0ec8-\\u0ecd\\u0f18\\u0f19\\u0f35\\u0f37\\u0f39\\u0f71-\\u0f7e\\u0f80-\\u0f84\\u0f86\\u0f87\\u0f90-\\u0f97\\u0f99-\\u0fbc\\u0fc6\\u102d-\\u1030\\u1032-\\u1037\\u1039\\u103a\\u103d\\u103e\\u1058\\u1059\\u105e-\\u1060\\u1071-\\u1074\\u1082\\u1085\\u1086\\u108d\\u109d\\u135f\\u1712-\\u1714\\u1732-\\u1734\\u1752\\u1753\\u1772\\u1773\\u17b7-\\u17bd\\u17c6\\u17c9-\\u17d3\\u17dd\\u180b-\\u180d\\u18a9\\u1920-\\u1922\\u1927\\u1928\\u1932\\u1939-\\u193b\\u1a17\\u1a18\\u1a56\\u1a58-\\u1a5e\\u1a60\\u1a62\\u1a65-\\u1a6c\\u1a73-\\u1a7c\\u1a7f\\u1b00-\\u1b03\\u1b34\\u1b36-\\u1b3a\\u1b3c\\u1b42\\u1b6b-\\u1b73\\u1b80\\u1b81\\u1ba2-\\u1ba5\\u1ba8\\u1ba9\\u1c2c-\\u1c33\\u1c36\\u1c37\\u1cd0-\\u1cd2\\u1cd4-\\u1ce0\\u1ce2-\\u1ce8\\u1ced\\u1dc0-\\u1de6\\u1dfd-\\u1dff\\u200c\\u200d\\u20d0-\\u20f0\\u2cef-\\u2cf1\\u2de0-\\u2dff\\u302a-\\u302f\\u3099\\u309a\\ua66f-\\ua672\\ua67c\\ua67d\\ua6f0\\ua6f1\\ua802\\ua806\\ua80b\\ua825\\ua826\\ua8c4\\ua8e0-\\ua8f1\\ua926-\\ua92d\\ua947-\\ua951\\ua980-\\ua982\\ua9b3\\ua9b6-\\ua9b9\\ua9bc\\uaa29-\\uaa2e\\uaa31\\uaa32\\uaa35\\uaa36\\uaa43\\uaa4c\\uaab0\\uaab2-\\uaab4\\uaab7\\uaab8\\uaabe\\uaabf\\uaac1\\uabe5\\uabe8\\uabed\\udc00-\\udfff\\ufb1e\\ufe00-\\ufe0f\\ufe20-\\ufe26\\uff9e\\uff9f]/;\n  function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch); }\n\n  // DOM UTILITIES\n\n  function elt(tag, content, className, style) {\n    var e = document.createElement(tag);\n    if (className) e.className = className;\n    if (style) e.style.cssText = style;\n    if (typeof content == \"string\") e.appendChild(document.createTextNode(content));\n    else if (content) for (var i = 0; i < content.length; ++i) e.appendChild(content[i]);\n    return e;\n  }\n\n  var range;\n  if (document.createRange) range = function(node, start, end, endNode) {\n    var r = document.createRange();\n    r.setEnd(endNode || node, end);\n    r.setStart(node, start);\n    return r;\n  };\n  else range = function(node, start, end) {\n    var r = document.body.createTextRange();\n    try { r.moveToElementText(node.parentNode); }\n    catch(e) { return r; }\n    r.collapse(true);\n    r.moveEnd(\"character\", end);\n    r.moveStart(\"character\", start);\n    return r;\n  };\n\n  function removeChildren(e) {\n    for (var count = e.childNodes.length; count > 0; --count)\n      e.removeChild(e.firstChild);\n    return e;\n  }\n\n  function removeChildrenAndAdd(parent, e) {\n    return removeChildren(parent).appendChild(e);\n  }\n\n  var contains = CodeMirror.contains = function(parent, child) {\n    if (child.nodeType == 3) // Android browser always returns false when child is a textnode\n      child = child.parentNode;\n    if (parent.contains)\n      return parent.contains(child);\n    do {\n      if (child.nodeType == 11) child = child.host;\n      if (child == parent) return true;\n    } while (child = child.parentNode);\n  };\n\n  function activeElt() { return document.activeElement; }\n  // Older versions of IE throws unspecified error when touching\n  // document.activeElement in some cases (during loading, in iframe)\n  if (ie && ie_version < 11) activeElt = function() {\n    try { return document.activeElement; }\n    catch(e) { return document.body; }\n  };\n\n  function classTest(cls) { return new RegExp(\"(^|\\\\s)\" + cls + \"(?:$|\\\\s)\\\\s*\"); }\n  var rmClass = CodeMirror.rmClass = function(node, cls) {\n    var current = node.className;\n    var match = classTest(cls).exec(current);\n    if (match) {\n      var after = current.slice(match.index + match[0].length);\n      node.className = current.slice(0, match.index) + (after ? match[1] + after : \"\");\n    }\n  };\n  var addClass = CodeMirror.addClass = function(node, cls) {\n    var current = node.className;\n    if (!classTest(cls).test(current)) node.className += (current ? \" \" : \"\") + cls;\n  };\n  function joinClasses(a, b) {\n    var as = a.split(\" \");\n    for (var i = 0; i < as.length; i++)\n      if (as[i] && !classTest(as[i]).test(b)) b += \" \" + as[i];\n    return b;\n  }\n\n  // WINDOW-WIDE EVENTS\n\n  // These must be handled carefully, because naively registering a\n  // handler for each editor will cause the editors to never be\n  // garbage collected.\n\n  function forEachCodeMirror(f) {\n    if (!document.body.getElementsByClassName) return;\n    var byClass = document.body.getElementsByClassName(\"CodeMirror\");\n    for (var i = 0; i < byClass.length; i++) {\n      var cm = byClass[i].CodeMirror;\n      if (cm) f(cm);\n    }\n  }\n\n  var globalsRegistered = false;\n  function ensureGlobalHandlers() {\n    if (globalsRegistered) return;\n    registerGlobalHandlers();\n    globalsRegistered = true;\n  }\n  function registerGlobalHandlers() {\n    // When the window resizes, we need to refresh active editors.\n    var resizeTimer;\n    on(window, \"resize\", function() {\n      if (resizeTimer == null) resizeTimer = setTimeout(function() {\n        resizeTimer = null;\n        forEachCodeMirror(onResize);\n      }, 100);\n    });\n    // When the window loses focus, we want to show the editor as blurred\n    on(window, \"blur\", function() {\n      forEachCodeMirror(onBlur);\n    });\n  }\n\n  // FEATURE DETECTION\n\n  // Detect drag-and-drop\n  var dragAndDrop = function() {\n    // There is *some* kind of drag-and-drop support in IE6-8, but I\n    // couldn't get it to work yet.\n    if (ie && ie_version < 9) return false;\n    var div = elt('div');\n    return \"draggable\" in div || \"dragDrop\" in div;\n  }();\n\n  var zwspSupported;\n  function zeroWidthElement(measure) {\n    if (zwspSupported == null) {\n      var test = elt(\"span\", \"\\u200b\");\n      removeChildrenAndAdd(measure, elt(\"span\", [test, document.createTextNode(\"x\")]));\n      if (measure.firstChild.offsetHeight != 0)\n        zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !(ie && ie_version < 8);\n    }\n    var node = zwspSupported ? elt(\"span\", \"\\u200b\") :\n      elt(\"span\", \"\\u00a0\", null, \"display: inline-block; width: 1px; margin-right: -1px\");\n    node.setAttribute(\"cm-text\", \"\");\n    return node;\n  }\n\n  // Feature-detect IE's crummy client rect reporting for bidi text\n  var badBidiRects;\n  function hasBadBidiRects(measure) {\n    if (badBidiRects != null) return badBidiRects;\n    var txt = removeChildrenAndAdd(measure, document.createTextNode(\"A\\u062eA\"));\n    var r0 = range(txt, 0, 1).getBoundingClientRect();\n    if (!r0 || r0.left == r0.right) return false; // Safari returns null in some cases (#2780)\n    var r1 = range(txt, 1, 2).getBoundingClientRect();\n    return badBidiRects = (r1.right - r0.right < 3);\n  }\n\n  // See if \"\".split is the broken IE version, if so, provide an\n  // alternative way to split lines.\n  var splitLines = CodeMirror.splitLines = \"\\n\\nb\".split(/\\n/).length != 3 ? function(string) {\n    var pos = 0, result = [], l = string.length;\n    while (pos <= l) {\n      var nl = string.indexOf(\"\\n\", pos);\n      if (nl == -1) nl = string.length;\n      var line = string.slice(pos, string.charAt(nl - 1) == \"\\r\" ? nl - 1 : nl);\n      var rt = line.indexOf(\"\\r\");\n      if (rt != -1) {\n        result.push(line.slice(0, rt));\n        pos += rt + 1;\n      } else {\n        result.push(line);\n        pos = nl + 1;\n      }\n    }\n    return result;\n  } : function(string){return string.split(/\\r\\n?|\\n/);};\n\n  var hasSelection = window.getSelection ? function(te) {\n    try { return te.selectionStart != te.selectionEnd; }\n    catch(e) { return false; }\n  } : function(te) {\n    try {var range = te.ownerDocument.selection.createRange();}\n    catch(e) {}\n    if (!range || range.parentElement() != te) return false;\n    return range.compareEndPoints(\"StartToEnd\", range) != 0;\n  };\n\n  var hasCopyEvent = (function() {\n    var e = elt(\"div\");\n    if (\"oncopy\" in e) return true;\n    e.setAttribute(\"oncopy\", \"return;\");\n    return typeof e.oncopy == \"function\";\n  })();\n\n  var badZoomedRects = null;\n  function hasBadZoomedRects(measure) {\n    if (badZoomedRects != null) return badZoomedRects;\n    var node = removeChildrenAndAdd(measure, elt(\"span\", \"x\"));\n    var normal = node.getBoundingClientRect();\n    var fromRange = range(node, 0, 1).getBoundingClientRect();\n    return badZoomedRects = Math.abs(normal.left - fromRange.left) > 1;\n  }\n\n  // KEY NAMES\n\n  var keyNames = {3: \"Enter\", 8: \"Backspace\", 9: \"Tab\", 13: \"Enter\", 16: \"Shift\", 17: \"Ctrl\", 18: \"Alt\",\n                  19: \"Pause\", 20: \"CapsLock\", 27: \"Esc\", 32: \"Space\", 33: \"PageUp\", 34: \"PageDown\", 35: \"End\",\n                  36: \"Home\", 37: \"Left\", 38: \"Up\", 39: \"Right\", 40: \"Down\", 44: \"PrintScrn\", 45: \"Insert\",\n                  46: \"Delete\", 59: \";\", 61: \"=\", 91: \"Mod\", 92: \"Mod\", 93: \"Mod\", 107: \"=\", 109: \"-\", 127: \"Delete\",\n                  173: \"-\", 186: \";\", 187: \"=\", 188: \",\", 189: \"-\", 190: \".\", 191: \"/\", 192: \"`\", 219: \"[\", 220: \"\\\\\",\n                  221: \"]\", 222: \"'\", 63232: \"Up\", 63233: \"Down\", 63234: \"Left\", 63235: \"Right\", 63272: \"Delete\",\n                  63273: \"Home\", 63275: \"End\", 63276: \"PageUp\", 63277: \"PageDown\", 63302: \"Insert\"};\n  CodeMirror.keyNames = keyNames;\n  (function() {\n    // Number keys\n    for (var i = 0; i < 10; i++) keyNames[i + 48] = keyNames[i + 96] = String(i);\n    // Alphabetic keys\n    for (var i = 65; i <= 90; i++) keyNames[i] = String.fromCharCode(i);\n    // Function keys\n    for (var i = 1; i <= 12; i++) keyNames[i + 111] = keyNames[i + 63235] = \"F\" + i;\n  })();\n\n  // BIDI HELPERS\n\n  function iterateBidiSections(order, from, to, f) {\n    if (!order) return f(from, to, \"ltr\");\n    var found = false;\n    for (var i = 0; i < order.length; ++i) {\n      var part = order[i];\n      if (part.from < to && part.to > from || from == to && part.to == from) {\n        f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? \"rtl\" : \"ltr\");\n        found = true;\n      }\n    }\n    if (!found) f(from, to, \"ltr\");\n  }\n\n  function bidiLeft(part) { return part.level % 2 ? part.to : part.from; }\n  function bidiRight(part) { return part.level % 2 ? part.from : part.to; }\n\n  function lineLeft(line) { var order = getOrder(line); return order ? bidiLeft(order[0]) : 0; }\n  function lineRight(line) {\n    var order = getOrder(line);\n    if (!order) return line.text.length;\n    return bidiRight(lst(order));\n  }\n\n  function lineStart(cm, lineN) {\n    var line = getLine(cm.doc, lineN);\n    var visual = visualLine(line);\n    if (visual != line) lineN = lineNo(visual);\n    var order = getOrder(visual);\n    var ch = !order ? 0 : order[0].level % 2 ? lineRight(visual) : lineLeft(visual);\n    return Pos(lineN, ch);\n  }\n  function lineEnd(cm, lineN) {\n    var merged, line = getLine(cm.doc, lineN);\n    while (merged = collapsedSpanAtEnd(line)) {\n      line = merged.find(1, true).line;\n      lineN = null;\n    }\n    var order = getOrder(line);\n    var ch = !order ? line.text.length : order[0].level % 2 ? lineLeft(line) : lineRight(line);\n    return Pos(lineN == null ? lineNo(line) : lineN, ch);\n  }\n  function lineStartSmart(cm, pos) {\n    var start = lineStart(cm, pos.line);\n    var line = getLine(cm.doc, start.line);\n    var order = getOrder(line);\n    if (!order || order[0].level == 0) {\n      var firstNonWS = Math.max(0, line.text.search(/\\S/));\n      var inWS = pos.line == start.line && pos.ch <= firstNonWS && pos.ch;\n      return Pos(start.line, inWS ? 0 : firstNonWS);\n    }\n    return start;\n  }\n\n  function compareBidiLevel(order, a, b) {\n    var linedir = order[0].level;\n    if (a == linedir) return true;\n    if (b == linedir) return false;\n    return a < b;\n  }\n  var bidiOther;\n  function getBidiPartAt(order, pos) {\n    bidiOther = null;\n    for (var i = 0, found; i < order.length; ++i) {\n      var cur = order[i];\n      if (cur.from < pos && cur.to > pos) return i;\n      if ((cur.from == pos || cur.to == pos)) {\n        if (found == null) {\n          found = i;\n        } else if (compareBidiLevel(order, cur.level, order[found].level)) {\n          if (cur.from != cur.to) bidiOther = found;\n          return i;\n        } else {\n          if (cur.from != cur.to) bidiOther = i;\n          return found;\n        }\n      }\n    }\n    return found;\n  }\n\n  function moveInLine(line, pos, dir, byUnit) {\n    if (!byUnit) return pos + dir;\n    do pos += dir;\n    while (pos > 0 && isExtendingChar(line.text.charAt(pos)));\n    return pos;\n  }\n\n  // This is needed in order to move 'visually' through bi-directional\n  // text -- i.e., pressing left should make the cursor go left, even\n  // when in RTL text. The tricky part is the 'jumps', where RTL and\n  // LTR text touch each other. This often requires the cursor offset\n  // to move more than one unit, in order to visually move one unit.\n  function moveVisually(line, start, dir, byUnit) {\n    var bidi = getOrder(line);\n    if (!bidi) return moveLogically(line, start, dir, byUnit);\n    var pos = getBidiPartAt(bidi, start), part = bidi[pos];\n    var target = moveInLine(line, start, part.level % 2 ? -dir : dir, byUnit);\n\n    for (;;) {\n      if (target > part.from && target < part.to) return target;\n      if (target == part.from || target == part.to) {\n        if (getBidiPartAt(bidi, target) == pos) return target;\n        part = bidi[pos += dir];\n        return (dir > 0) == part.level % 2 ? part.to : part.from;\n      } else {\n        part = bidi[pos += dir];\n        if (!part) return null;\n        if ((dir > 0) == part.level % 2)\n          target = moveInLine(line, part.to, -1, byUnit);\n        else\n          target = moveInLine(line, part.from, 1, byUnit);\n      }\n    }\n  }\n\n  function moveLogically(line, start, dir, byUnit) {\n    var target = start + dir;\n    if (byUnit) while (target > 0 && isExtendingChar(line.text.charAt(target))) target += dir;\n    return target < 0 || target > line.text.length ? null : target;\n  }\n\n  // Bidirectional ordering algorithm\n  // See http://unicode.org/reports/tr9/tr9-13.html for the algorithm\n  // that this (partially) implements.\n\n  // One-char codes used for character types:\n  // L (L):   Left-to-Right\n  // R (R):   Right-to-Left\n  // r (AL):  Right-to-Left Arabic\n  // 1 (EN):  European Number\n  // + (ES):  European Number Separator\n  // % (ET):  European Number Terminator\n  // n (AN):  Arabic Number\n  // , (CS):  Common Number Separator\n  // m (NSM): Non-Spacing Mark\n  // b (BN):  Boundary Neutral\n  // s (B):   Paragraph Separator\n  // t (S):   Segment Separator\n  // w (WS):  Whitespace\n  // N (ON):  Other Neutrals\n\n  // Returns null if characters are ordered as they appear\n  // (left-to-right), or an array of sections ({from, to, level}\n  // objects) in the order in which they occur visually.\n  var bidiOrdering = (function() {\n    // Character types for codepoints 0 to 0xff\n    var lowTypes = \"bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN\";\n    // Character types for codepoints 0x600 to 0x6ff\n    var arabicTypes = \"rrrrrrrrrrrr,rNNmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmrrrrrrrnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmNmmmm\";\n    function charType(code) {\n      if (code <= 0xf7) return lowTypes.charAt(code);\n      else if (0x590 <= code && code <= 0x5f4) return \"R\";\n      else if (0x600 <= code && code <= 0x6ed) return arabicTypes.charAt(code - 0x600);\n      else if (0x6ee <= code && code <= 0x8ac) return \"r\";\n      else if (0x2000 <= code && code <= 0x200b) return \"w\";\n      else if (code == 0x200c) return \"b\";\n      else return \"L\";\n    }\n\n    var bidiRE = /[\\u0590-\\u05f4\\u0600-\\u06ff\\u0700-\\u08ac]/;\n    var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/;\n    // Browsers seem to always treat the boundaries of block elements as being L.\n    var outerType = \"L\";\n\n    function BidiSpan(level, from, to) {\n      this.level = level;\n      this.from = from; this.to = to;\n    }\n\n    return function(str) {\n      if (!bidiRE.test(str)) return false;\n      var len = str.length, types = [];\n      for (var i = 0, type; i < len; ++i)\n        types.push(type = charType(str.charCodeAt(i)));\n\n      // W1. Examine each non-spacing mark (NSM) in the level run, and\n      // change the type of the NSM to the type of the previous\n      // character. If the NSM is at the start of the level run, it will\n      // get the type of sor.\n      for (var i = 0, prev = outerType; i < len; ++i) {\n        var type = types[i];\n        if (type == \"m\") types[i] = prev;\n        else prev = type;\n      }\n\n      // W2. Search backwards from each instance of a European number\n      // until the first strong type (R, L, AL, or sor) is found. If an\n      // AL is found, change the type of the European number to Arabic\n      // number.\n      // W3. Change all ALs to R.\n      for (var i = 0, cur = outerType; i < len; ++i) {\n        var type = types[i];\n        if (type == \"1\" && cur == \"r\") types[i] = \"n\";\n        else if (isStrong.test(type)) { cur = type; if (type == \"r\") types[i] = \"R\"; }\n      }\n\n      // W4. A single European separator between two European numbers\n      // changes to a European number. A single common separator between\n      // two numbers of the same type changes to that type.\n      for (var i = 1, prev = types[0]; i < len - 1; ++i) {\n        var type = types[i];\n        if (type == \"+\" && prev == \"1\" && types[i+1] == \"1\") types[i] = \"1\";\n        else if (type == \",\" && prev == types[i+1] &&\n                 (prev == \"1\" || prev == \"n\")) types[i] = prev;\n        prev = type;\n      }\n\n      // W5. A sequence of European terminators adjacent to European\n      // numbers changes to all European numbers.\n      // W6. Otherwise, separators and terminators change to Other\n      // Neutral.\n      for (var i = 0; i < len; ++i) {\n        var type = types[i];\n        if (type == \",\") types[i] = \"N\";\n        else if (type == \"%\") {\n          for (var end = i + 1; end < len && types[end] == \"%\"; ++end) {}\n          var replace = (i && types[i-1] == \"!\") || (end < len && types[end] == \"1\") ? \"1\" : \"N\";\n          for (var j = i; j < end; ++j) types[j] = replace;\n          i = end - 1;\n        }\n      }\n\n      // W7. Search backwards from each instance of a European number\n      // until the first strong type (R, L, or sor) is found. If an L is\n      // found, then change the type of the European number to L.\n      for (var i = 0, cur = outerType; i < len; ++i) {\n        var type = types[i];\n        if (cur == \"L\" && type == \"1\") types[i] = \"L\";\n        else if (isStrong.test(type)) cur = type;\n      }\n\n      // N1. A sequence of neutrals takes the direction of the\n      // surrounding strong text if the text on both sides has the same\n      // direction. European and Arabic numbers act as if they were R in\n      // terms of their influence on neutrals. Start-of-level-run (sor)\n      // and end-of-level-run (eor) are used at level run boundaries.\n      // N2. Any remaining neutrals take the embedding direction.\n      for (var i = 0; i < len; ++i) {\n        if (isNeutral.test(types[i])) {\n          for (var end = i + 1; end < len && isNeutral.test(types[end]); ++end) {}\n          var before = (i ? types[i-1] : outerType) == \"L\";\n          var after = (end < len ? types[end] : outerType) == \"L\";\n          var replace = before || after ? \"L\" : \"R\";\n          for (var j = i; j < end; ++j) types[j] = replace;\n          i = end - 1;\n        }\n      }\n\n      // Here we depart from the documented algorithm, in order to avoid\n      // building up an actual levels array. Since there are only three\n      // levels (0, 1, 2) in an implementation that doesn't take\n      // explicit embedding into account, we can build up the order on\n      // the fly, without following the level-based algorithm.\n      var order = [], m;\n      for (var i = 0; i < len;) {\n        if (countsAsLeft.test(types[i])) {\n          var start = i;\n          for (++i; i < len && countsAsLeft.test(types[i]); ++i) {}\n          order.push(new BidiSpan(0, start, i));\n        } else {\n          var pos = i, at = order.length;\n          for (++i; i < len && types[i] != \"L\"; ++i) {}\n          for (var j = pos; j < i;) {\n            if (countsAsNum.test(types[j])) {\n              if (pos < j) order.splice(at, 0, new BidiSpan(1, pos, j));\n              var nstart = j;\n              for (++j; j < i && countsAsNum.test(types[j]); ++j) {}\n              order.splice(at, 0, new BidiSpan(2, nstart, j));\n              pos = j;\n            } else ++j;\n          }\n          if (pos < i) order.splice(at, 0, new BidiSpan(1, pos, i));\n        }\n      }\n      if (order[0].level == 1 && (m = str.match(/^\\s+/))) {\n        order[0].from = m[0].length;\n        order.unshift(new BidiSpan(0, 0, m[0].length));\n      }\n      if (lst(order).level == 1 && (m = str.match(/\\s+$/))) {\n        lst(order).to -= m[0].length;\n        order.push(new BidiSpan(0, len - m[0].length, len));\n      }\n      if (order[0].level != lst(order).level)\n        order.push(new BidiSpan(order[0].level, len, len));\n\n      return order;\n    };\n  })();\n\n  // THE END\n\n  CodeMirror.version = \"5.0.0\";\n\n  return CodeMirror;\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/apl/apl.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"apl\", function() {\n  var builtInOps = {\n    \".\": \"innerProduct\",\n    \"\\\\\": \"scan\",\n    \"/\": \"reduce\",\n    \"⌿\": \"reduce1Axis\",\n    \"⍀\": \"scan1Axis\",\n    \"¨\": \"each\",\n    \"⍣\": \"power\"\n  };\n  var builtInFuncs = {\n    \"+\": [\"conjugate\", \"add\"],\n    \"−\": [\"negate\", \"subtract\"],\n    \"×\": [\"signOf\", \"multiply\"],\n    \"÷\": [\"reciprocal\", \"divide\"],\n    \"⌈\": [\"ceiling\", \"greaterOf\"],\n    \"⌊\": [\"floor\", \"lesserOf\"],\n    \"∣\": [\"absolute\", \"residue\"],\n    \"⍳\": [\"indexGenerate\", \"indexOf\"],\n    \"?\": [\"roll\", \"deal\"],\n    \"⋆\": [\"exponentiate\", \"toThePowerOf\"],\n    \"⍟\": [\"naturalLog\", \"logToTheBase\"],\n    \"○\": [\"piTimes\", \"circularFuncs\"],\n    \"!\": [\"factorial\", \"binomial\"],\n    \"⌹\": [\"matrixInverse\", \"matrixDivide\"],\n    \"<\": [null, \"lessThan\"],\n    \"≤\": [null, \"lessThanOrEqual\"],\n    \"=\": [null, \"equals\"],\n    \">\": [null, \"greaterThan\"],\n    \"≥\": [null, \"greaterThanOrEqual\"],\n    \"≠\": [null, \"notEqual\"],\n    \"≡\": [\"depth\", \"match\"],\n    \"≢\": [null, \"notMatch\"],\n    \"∈\": [\"enlist\", \"membership\"],\n    \"⍷\": [null, \"find\"],\n    \"∪\": [\"unique\", \"union\"],\n    \"∩\": [null, \"intersection\"],\n    \"∼\": [\"not\", \"without\"],\n    \"∨\": [null, \"or\"],\n    \"∧\": [null, \"and\"],\n    \"⍱\": [null, \"nor\"],\n    \"⍲\": [null, \"nand\"],\n    \"⍴\": [\"shapeOf\", \"reshape\"],\n    \",\": [\"ravel\", \"catenate\"],\n    \"⍪\": [null, \"firstAxisCatenate\"],\n    \"⌽\": [\"reverse\", \"rotate\"],\n    \"⊖\": [\"axis1Reverse\", \"axis1Rotate\"],\n    \"⍉\": [\"transpose\", null],\n    \"↑\": [\"first\", \"take\"],\n    \"↓\": [null, \"drop\"],\n    \"⊂\": [\"enclose\", \"partitionWithAxis\"],\n    \"⊃\": [\"diclose\", \"pick\"],\n    \"⌷\": [null, \"index\"],\n    \"⍋\": [\"gradeUp\", null],\n    \"⍒\": [\"gradeDown\", null],\n    \"⊤\": [\"encode\", null],\n    \"⊥\": [\"decode\", null],\n    \"⍕\": [\"format\", \"formatByExample\"],\n    \"⍎\": [\"execute\", null],\n    \"⊣\": [\"stop\", \"left\"],\n    \"⊢\": [\"pass\", \"right\"]\n  };\n\n  var isOperator = /[\\.\\/⌿⍀¨⍣]/;\n  var isNiladic = /⍬/;\n  var isFunction = /[\\+−×÷⌈⌊∣⍳\\?⋆⍟○!⌹<≤=>≥≠≡≢∈⍷∪∩∼∨∧⍱⍲⍴,⍪⌽⊖⍉↑↓⊂⊃⌷⍋⍒⊤⊥⍕⍎⊣⊢]/;\n  var isArrow = /←/;\n  var isComment = /[⍝#].*$/;\n\n  var stringEater = function(type) {\n    var prev;\n    prev = false;\n    return function(c) {\n      prev = c;\n      if (c === type) {\n        return prev === \"\\\\\";\n      }\n      return true;\n    };\n  };\n  return {\n    startState: function() {\n      return {\n        prev: false,\n        func: false,\n        op: false,\n        string: false,\n        escape: false\n      };\n    },\n    token: function(stream, state) {\n      var ch, funcName, word;\n      if (stream.eatSpace()) {\n        return null;\n      }\n      ch = stream.next();\n      if (ch === '\"' || ch === \"'\") {\n        stream.eatWhile(stringEater(ch));\n        stream.next();\n        state.prev = true;\n        return \"string\";\n      }\n      if (/[\\[{\\(]/.test(ch)) {\n        state.prev = false;\n        return null;\n      }\n      if (/[\\]}\\)]/.test(ch)) {\n        state.prev = true;\n        return null;\n      }\n      if (isNiladic.test(ch)) {\n        state.prev = false;\n        return \"niladic\";\n      }\n      if (/[¯\\d]/.test(ch)) {\n        if (state.func) {\n          state.func = false;\n          state.prev = false;\n        } else {\n          state.prev = true;\n        }\n        stream.eatWhile(/[\\w\\.]/);\n        return \"number\";\n      }\n      if (isOperator.test(ch)) {\n        return \"operator apl-\" + builtInOps[ch];\n      }\n      if (isArrow.test(ch)) {\n        return \"apl-arrow\";\n      }\n      if (isFunction.test(ch)) {\n        funcName = \"apl-\";\n        if (builtInFuncs[ch] != null) {\n          if (state.prev) {\n            funcName += builtInFuncs[ch][1];\n          } else {\n            funcName += builtInFuncs[ch][0];\n          }\n        }\n        state.func = true;\n        state.prev = false;\n        return \"function \" + funcName;\n      }\n      if (isComment.test(ch)) {\n        stream.skipToEnd();\n        return \"comment\";\n      }\n      if (ch === \"∘\" && stream.peek() === \".\") {\n        stream.next();\n        return \"function jot-dot\";\n      }\n      stream.eatWhile(/[\\w\\$_]/);\n      word = stream.current();\n      state.prev = true;\n      return \"keyword\";\n    }\n  };\n});\n\nCodeMirror.defineMIME(\"text/apl\", \"apl\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/apl/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: APL mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"../../addon/edit/matchbrackets.js\"></script>\n<script src=\"./apl.js\"></script>\n<style>\n\t.CodeMirror { border: 2px inset #dee; }\n    </style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">APL</a>\n  </ul>\n</div>\n\n<article>\n<h2>APL mode</h2>\n<form><textarea id=\"code\" name=\"code\">\n⍝ Conway's game of life\n\n⍝ This example was inspired by the impressive demo at\n⍝ http://www.youtube.com/watch?v=a9xAKttWgP4\n\n⍝ Create a matrix:\n⍝     0 1 1\n⍝     1 1 0\n⍝     0 1 0\ncreature ← (3 3 ⍴ ⍳ 9) ∈ 1 2 3 4 7   ⍝ Original creature from demo\ncreature ← (3 3 ⍴ ⍳ 9) ∈ 1 3 6 7 8   ⍝ Glider\n\n⍝ Place the creature on a larger board, near the centre\nboard ← ¯1 ⊖ ¯2 ⌽ 5 7 ↑ creature\n\n⍝ A function to move from one generation to the next\nlife ← {∨/ 1 ⍵ ∧ 3 4 = ⊂+/ +⌿ 1 0 ¯1 ∘.⊖ 1 0 ¯1 ⌽¨ ⊂⍵}\n\n⍝ Compute n-th generation and format it as a\n⍝ character matrix\ngen ← {' #'[(life ⍣ ⍵) board]}\n\n⍝ Show first three generations\n(gen 1) (gen 2) (gen 3)\n</textarea></form>\n\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        lineNumbers: true,\n        matchBrackets: true,\n        mode: \"text/apl\"\n      });\n    </script>\n\n    <p>Simple mode that tries to handle APL as well as it can.</p>\n    <p>It attempts to label functions/operators based upon\n    monadic/dyadic usage (but this is far from fully fleshed out).\n    This means there are meaningful classnames so hover states can\n    have popups etc.</p>\n\n    <p><strong>MIME types defined:</strong> <code>text/apl</code> (APL code)</p>\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/asterisk/asterisk.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n/*\n * =====================================================================================\n *\n *       Filename:  mode/asterisk/asterisk.js\n *\n *    Description:  CodeMirror mode for Asterisk dialplan\n *\n *        Created:  05/17/2012 09:20:25 PM\n *       Revision:  none\n *\n *         Author:  Stas Kobzar (stas@modulis.ca),\n *        Company:  Modulis.ca Inc.\n *\n * =====================================================================================\n */\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"asterisk\", function() {\n  var atoms    = [\"exten\", \"same\", \"include\",\"ignorepat\",\"switch\"],\n      dpcmd    = [\"#include\",\"#exec\"],\n      apps     = [\n                  \"addqueuemember\",\"adsiprog\",\"aelsub\",\"agentlogin\",\"agentmonitoroutgoing\",\"agi\",\n                  \"alarmreceiver\",\"amd\",\"answer\",\"authenticate\",\"background\",\"backgrounddetect\",\n                  \"bridge\",\"busy\",\"callcompletioncancel\",\"callcompletionrequest\",\"celgenuserevent\",\n                  \"changemonitor\",\"chanisavail\",\"channelredirect\",\"chanspy\",\"clearhash\",\"confbridge\",\n                  \"congestion\",\"continuewhile\",\"controlplayback\",\"dahdiacceptr2call\",\"dahdibarge\",\n                  \"dahdiras\",\"dahdiscan\",\"dahdisendcallreroutingfacility\",\"dahdisendkeypadfacility\",\n                  \"datetime\",\"dbdel\",\"dbdeltree\",\"deadagi\",\"dial\",\"dictate\",\"directory\",\"disa\",\n                  \"dumpchan\",\"eagi\",\"echo\",\"endwhile\",\"exec\",\"execif\",\"execiftime\",\"exitwhile\",\"extenspy\",\n                  \"externalivr\",\"festival\",\"flash\",\"followme\",\"forkcdr\",\"getcpeid\",\"gosub\",\"gosubif\",\n                  \"goto\",\"gotoif\",\"gotoiftime\",\"hangup\",\"iax2provision\",\"ices\",\"importvar\",\"incomplete\",\n                  \"ivrdemo\",\"jabberjoin\",\"jabberleave\",\"jabbersend\",\"jabbersendgroup\",\"jabberstatus\",\n                  \"jack\",\"log\",\"macro\",\"macroexclusive\",\"macroexit\",\"macroif\",\"mailboxexists\",\"meetme\",\n                  \"meetmeadmin\",\"meetmechanneladmin\",\"meetmecount\",\"milliwatt\",\"minivmaccmess\",\"minivmdelete\",\n                  \"minivmgreet\",\"minivmmwi\",\"minivmnotify\",\"minivmrecord\",\"mixmonitor\",\"monitor\",\"morsecode\",\n                  \"mp3player\",\"mset\",\"musiconhold\",\"nbscat\",\"nocdr\",\"noop\",\"odbc\",\"odbc\",\"odbcfinish\",\n                  \"originate\",\"ospauth\",\"ospfinish\",\"osplookup\",\"ospnext\",\"page\",\"park\",\"parkandannounce\",\n                  \"parkedcall\",\"pausemonitor\",\"pausequeuemember\",\"pickup\",\"pickupchan\",\"playback\",\"playtones\",\n                  \"privacymanager\",\"proceeding\",\"progress\",\"queue\",\"queuelog\",\"raiseexception\",\"read\",\"readexten\",\n                  \"readfile\",\"receivefax\",\"receivefax\",\"receivefax\",\"record\",\"removequeuemember\",\n                  \"resetcdr\",\"retrydial\",\"return\",\"ringing\",\"sayalpha\",\"saycountedadj\",\"saycountednoun\",\n                  \"saycountpl\",\"saydigits\",\"saynumber\",\"sayphonetic\",\"sayunixtime\",\"senddtmf\",\"sendfax\",\n                  \"sendfax\",\"sendfax\",\"sendimage\",\"sendtext\",\"sendurl\",\"set\",\"setamaflags\",\n                  \"setcallerpres\",\"setmusiconhold\",\"sipaddheader\",\"sipdtmfmode\",\"sipremoveheader\",\"skel\",\n                  \"slastation\",\"slatrunk\",\"sms\",\"softhangup\",\"speechactivategrammar\",\"speechbackground\",\n                  \"speechcreate\",\"speechdeactivategrammar\",\"speechdestroy\",\"speechloadgrammar\",\"speechprocessingsound\",\n                  \"speechstart\",\"speechunloadgrammar\",\"stackpop\",\"startmusiconhold\",\"stopmixmonitor\",\"stopmonitor\",\n                  \"stopmusiconhold\",\"stopplaytones\",\"system\",\"testclient\",\"testserver\",\"transfer\",\"tryexec\",\n                  \"trysystem\",\"unpausemonitor\",\"unpausequeuemember\",\"userevent\",\"verbose\",\"vmauthenticate\",\n                  \"vmsayname\",\"voicemail\",\"voicemailmain\",\"wait\",\"waitexten\",\"waitfornoise\",\"waitforring\",\n                  \"waitforsilence\",\"waitmusiconhold\",\"waituntil\",\"while\",\"zapateller\"\n                 ];\n\n  function basicToken(stream,state){\n    var cur = '';\n    var ch  = '';\n    ch = stream.next();\n    // comment\n    if(ch == \";\") {\n      stream.skipToEnd();\n      return \"comment\";\n    }\n    // context\n    if(ch == '[') {\n      stream.skipTo(']');\n      stream.eat(']');\n      return \"header\";\n    }\n    // string\n    if(ch == '\"') {\n      stream.skipTo('\"');\n      return \"string\";\n    }\n    if(ch == \"'\") {\n      stream.skipTo(\"'\");\n      return \"string-2\";\n    }\n    // dialplan commands\n    if(ch == '#') {\n      stream.eatWhile(/\\w/);\n      cur = stream.current();\n      if(dpcmd.indexOf(cur) !== -1) {\n        stream.skipToEnd();\n        return \"strong\";\n      }\n    }\n    // application args\n    if(ch == '$'){\n      var ch1 = stream.peek();\n      if(ch1 == '{'){\n        stream.skipTo('}');\n        stream.eat('}');\n        return \"variable-3\";\n      }\n    }\n    // extension\n    stream.eatWhile(/\\w/);\n    cur = stream.current();\n    if(atoms.indexOf(cur) !== -1) {\n      state.extenStart = true;\n      switch(cur) {\n        case 'same': state.extenSame = true; break;\n        case 'include':\n        case 'switch':\n        case 'ignorepat':\n          state.extenInclude = true;break;\n        default:break;\n      }\n      return \"atom\";\n    }\n  }\n\n  return {\n    startState: function() {\n      return {\n        extenStart: false,\n        extenSame:  false,\n        extenInclude: false,\n        extenExten: false,\n        extenPriority: false,\n        extenApplication: false\n      };\n    },\n    token: function(stream, state) {\n\n      var cur = '';\n      var ch  = '';\n      if(stream.eatSpace()) return null;\n      // extension started\n      if(state.extenStart){\n        stream.eatWhile(/[^\\s]/);\n        cur = stream.current();\n        if(/^=>?$/.test(cur)){\n          state.extenExten = true;\n          state.extenStart = false;\n          return \"strong\";\n        } else {\n          state.extenStart = false;\n          stream.skipToEnd();\n          return \"error\";\n        }\n      } else if(state.extenExten) {\n        // set exten and priority\n        state.extenExten = false;\n        state.extenPriority = true;\n        stream.eatWhile(/[^,]/);\n        if(state.extenInclude) {\n          stream.skipToEnd();\n          state.extenPriority = false;\n          state.extenInclude = false;\n        }\n        if(state.extenSame) {\n          state.extenPriority = false;\n          state.extenSame = false;\n          state.extenApplication = true;\n        }\n        return \"tag\";\n      } else if(state.extenPriority) {\n        state.extenPriority = false;\n        state.extenApplication = true;\n        ch = stream.next(); // get comma\n        if(state.extenSame) return null;\n        stream.eatWhile(/[^,]/);\n        return \"number\";\n      } else if(state.extenApplication) {\n        stream.eatWhile(/,/);\n        cur = stream.current();\n        if(cur === ',') return null;\n        stream.eatWhile(/\\w/);\n        cur = stream.current().toLowerCase();\n        state.extenApplication = false;\n        if(apps.indexOf(cur) !== -1){\n          return \"def strong\";\n        }\n      } else{\n        return basicToken(stream,state);\n      }\n\n      return null;\n    }\n  };\n});\n\nCodeMirror.defineMIME(\"text/x-asterisk\", \"asterisk\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/asterisk/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Asterisk dialplan mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"asterisk.js\"></script>\n<style>\n      .CodeMirror {border: 1px solid #999;}\n      .cm-s-default span.cm-arrow { color: red; }\n    </style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Asterisk dialplan</a>\n  </ul>\n</div>\n\n<article>\n<h2>Asterisk dialplan mode</h2>\n<form><textarea id=\"code\" name=\"code\">\n; extensions.conf - the Asterisk dial plan\n;\n\n[general]\n;\n; If static is set to no, or omitted, then the pbx_config will rewrite\n; this file when extensions are modified.  Remember that all comments\n; made in the file will be lost when that happens.\nstatic=yes\n\n#include \"/etc/asterisk/additional_general.conf\n\n[iaxprovider]\nswitch => IAX2/user:[key]@myserver/mycontext\n\n[dynamic]\n#exec /usr/bin/dynamic-peers.pl\n\n[trunkint]\n;\n; International long distance through trunk\n;\nexten => _9011.,1,Macro(dundi-e164,${EXTEN:4})\nexten => _9011.,n,Dial(${GLOBAL(TRUNK)}/${FILTER(0-9,${EXTEN:${GLOBAL(TRUNKMSD)}})})\n\n[local]\n;\n; Master context for local, toll-free, and iaxtel calls only\n;\nignorepat => 9\ninclude => default\n\n[demo]\ninclude => stdexten\n;\n; We start with what to do when a call first comes in.\n;\nexten => s,1,Wait(1)\t\t\t; Wait a second, just for fun\nsame  => n,Answer\t\t\t; Answer the line\nsame  => n,Set(TIMEOUT(digit)=5)\t; Set Digit Timeout to 5 seconds\nsame  => n,Set(TIMEOUT(response)=10)\t; Set Response Timeout to 10 seconds\nsame  => n(restart),BackGround(demo-congrats)\t; Play a congratulatory message\nsame  => n(instruct),BackGround(demo-instruct)\t; Play some instructions\nsame  => n,WaitExten\t\t\t; Wait for an extension to be dialed.\n\nexten => 2,1,BackGround(demo-moreinfo)\t; Give some more information.\nexten => 2,n,Goto(s,instruct)\n\nexten => 3,1,Set(LANGUAGE()=fr)\t\t; Set language to french\nexten => 3,n,Goto(s,restart)\t\t; Start with the congratulations\n\nexten => 1000,1,Goto(default,s,1)\n;\n; We also create an example user, 1234, who is on the console and has\n; voicemail, etc.\n;\nexten => 1234,1,Playback(transfer,skip)\t\t; \"Please hold while...\"\n\t\t\t\t\t; (but skip if channel is not up)\nexten => 1234,n,Gosub(${EXTEN},stdexten(${GLOBAL(CONSOLE)}))\nexten => 1234,n,Goto(default,s,1)\t\t; exited Voicemail\n\nexten => 1235,1,Voicemail(1234,u)\t\t; Right to voicemail\n\nexten => 1236,1,Dial(Console/dsp)\t\t; Ring forever\nexten => 1236,n,Voicemail(1234,b)\t\t; Unless busy\n\n;\n; # for when they're done with the demo\n;\nexten => #,1,Playback(demo-thanks)\t; \"Thanks for trying the demo\"\nexten => #,n,Hangup\t\t\t; Hang them up.\n\n;\n; A timeout and \"invalid extension rule\"\n;\nexten => t,1,Goto(#,1)\t\t\t; If they take too long, give up\nexten => i,1,Playback(invalid)\t\t; \"That's not valid, try again\"\n\n;\n; Create an extension, 500, for dialing the\n; Asterisk demo.\n;\nexten => 500,1,Playback(demo-abouttotry); Let them know what's going on\nexten => 500,n,Dial(IAX2/guest@pbx.digium.com/s@default)\t; Call the Asterisk demo\nexten => 500,n,Playback(demo-nogo)\t; Couldn't connect to the demo site\nexten => 500,n,Goto(s,6)\t\t; Return to the start over message.\n\n;\n; Create an extension, 600, for evaluating echo latency.\n;\nexten => 600,1,Playback(demo-echotest)\t; Let them know what's going on\nexten => 600,n,Echo\t\t\t; Do the echo test\nexten => 600,n,Playback(demo-echodone)\t; Let them know it's over\nexten => 600,n,Goto(s,6)\t\t; Start over\n\n;\n;\tYou can use the Macro Page to intercom a individual user\nexten => 76245,1,Macro(page,SIP/Grandstream1)\n; or if your peernames are the same as extensions\nexten => _7XXX,1,Macro(page,SIP/${EXTEN})\n;\n;\n; System Wide Page at extension 7999\n;\nexten => 7999,1,Set(TIMEOUT(absolute)=60)\nexten => 7999,2,Page(Local/Grandstream1@page&Local/Xlite1@page&Local/1234@page/n,d)\n\n; Give voicemail at extension 8500\n;\nexten => 8500,1,VoicemailMain\nexten => 8500,n,Goto(s,6)\n\n    </textarea></form>\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        mode: \"text/x-asterisk\",\n        matchBrackets: true,\n        lineNumber: true\n      });\n    </script>\n\n    <p><strong>MIME types defined:</strong> <code>text/x-asterisk</code>.</p>\n\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/clike/clike.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"clike\", function(config, parserConfig) {\n  var indentUnit = config.indentUnit,\n      statementIndentUnit = parserConfig.statementIndentUnit || indentUnit,\n      dontAlignCalls = parserConfig.dontAlignCalls,\n      keywords = parserConfig.keywords || {},\n      builtin = parserConfig.builtin || {},\n      blockKeywords = parserConfig.blockKeywords || {},\n      atoms = parserConfig.atoms || {},\n      hooks = parserConfig.hooks || {},\n      multiLineStrings = parserConfig.multiLineStrings,\n      indentStatements = parserConfig.indentStatements !== false;\n  var isOperatorChar = /[+\\-*&%=<>!?|\\/]/;\n\n  var curPunc;\n\n  function tokenBase(stream, state) {\n    var ch = stream.next();\n    if (hooks[ch]) {\n      var result = hooks[ch](stream, state);\n      if (result !== false) return result;\n    }\n    if (ch == '\"' || ch == \"'\") {\n      state.tokenize = tokenString(ch);\n      return state.tokenize(stream, state);\n    }\n    if (/[\\[\\]{}\\(\\),;\\:\\.]/.test(ch)) {\n      curPunc = ch;\n      return null;\n    }\n    if (/\\d/.test(ch)) {\n      stream.eatWhile(/[\\w\\.]/);\n      return \"number\";\n    }\n    if (ch == \"/\") {\n      if (stream.eat(\"*\")) {\n        state.tokenize = tokenComment;\n        return tokenComment(stream, state);\n      }\n      if (stream.eat(\"/\")) {\n        stream.skipToEnd();\n        return \"comment\";\n      }\n    }\n    if (isOperatorChar.test(ch)) {\n      stream.eatWhile(isOperatorChar);\n      return \"operator\";\n    }\n    stream.eatWhile(/[\\w\\$_\\xa1-\\uffff]/);\n    var cur = stream.current();\n    if (keywords.propertyIsEnumerable(cur)) {\n      if (blockKeywords.propertyIsEnumerable(cur)) curPunc = \"newstatement\";\n      return \"keyword\";\n    }\n    if (builtin.propertyIsEnumerable(cur)) {\n      if (blockKeywords.propertyIsEnumerable(cur)) curPunc = \"newstatement\";\n      return \"builtin\";\n    }\n    if (atoms.propertyIsEnumerable(cur)) return \"atom\";\n    return \"variable\";\n  }\n\n  function tokenString(quote) {\n    return function(stream, state) {\n      var escaped = false, next, end = false;\n      while ((next = stream.next()) != null) {\n        if (next == quote && !escaped) {end = true; break;}\n        escaped = !escaped && next == \"\\\\\";\n      }\n      if (end || !(escaped || multiLineStrings))\n        state.tokenize = null;\n      return \"string\";\n    };\n  }\n\n  function tokenComment(stream, state) {\n    var maybeEnd = false, ch;\n    while (ch = stream.next()) {\n      if (ch == \"/\" && maybeEnd) {\n        state.tokenize = null;\n        break;\n      }\n      maybeEnd = (ch == \"*\");\n    }\n    return \"comment\";\n  }\n\n  function Context(indented, column, type, align, prev) {\n    this.indented = indented;\n    this.column = column;\n    this.type = type;\n    this.align = align;\n    this.prev = prev;\n  }\n  function pushContext(state, col, type) {\n    var indent = state.indented;\n    if (state.context && state.context.type == \"statement\")\n      indent = state.context.indented;\n    return state.context = new Context(indent, col, type, null, state.context);\n  }\n  function popContext(state) {\n    var t = state.context.type;\n    if (t == \")\" || t == \"]\" || t == \"}\")\n      state.indented = state.context.indented;\n    return state.context = state.context.prev;\n  }\n\n  // Interface\n\n  return {\n    startState: function(basecolumn) {\n      return {\n        tokenize: null,\n        context: new Context((basecolumn || 0) - indentUnit, 0, \"top\", false),\n        indented: 0,\n        startOfLine: true\n      };\n    },\n\n    token: function(stream, state) {\n      var ctx = state.context;\n      if (stream.sol()) {\n        if (ctx.align == null) ctx.align = false;\n        state.indented = stream.indentation();\n        state.startOfLine = true;\n      }\n      if (stream.eatSpace()) return null;\n      curPunc = null;\n      var style = (state.tokenize || tokenBase)(stream, state);\n      if (style == \"comment\" || style == \"meta\") return style;\n      if (ctx.align == null) ctx.align = true;\n\n      if ((curPunc == \";\" || curPunc == \":\" || curPunc == \",\") && ctx.type == \"statement\") popContext(state);\n      else if (curPunc == \"{\") pushContext(state, stream.column(), \"}\");\n      else if (curPunc == \"[\") pushContext(state, stream.column(), \"]\");\n      else if (curPunc == \"(\") pushContext(state, stream.column(), \")\");\n      else if (curPunc == \"}\") {\n        while (ctx.type == \"statement\") ctx = popContext(state);\n        if (ctx.type == \"}\") ctx = popContext(state);\n        while (ctx.type == \"statement\") ctx = popContext(state);\n      }\n      else if (curPunc == ctx.type) popContext(state);\n      else if (indentStatements &&\n               (((ctx.type == \"}\" || ctx.type == \"top\") && curPunc != ';') ||\n                (ctx.type == \"statement\" && curPunc == \"newstatement\")))\n        pushContext(state, stream.column(), \"statement\");\n      state.startOfLine = false;\n      return style;\n    },\n\n    indent: function(state, textAfter) {\n      if (state.tokenize != tokenBase && state.tokenize != null) return CodeMirror.Pass;\n      var ctx = state.context, firstChar = textAfter && textAfter.charAt(0);\n      if (ctx.type == \"statement\" && firstChar == \"}\") ctx = ctx.prev;\n      var closing = firstChar == ctx.type;\n      if (ctx.type == \"statement\") return ctx.indented + (firstChar == \"{\" ? 0 : statementIndentUnit);\n      else if (ctx.align && (!dontAlignCalls || ctx.type != \")\")) return ctx.column + (closing ? 0 : 1);\n      else if (ctx.type == \")\" && !closing) return ctx.indented + statementIndentUnit;\n      else return ctx.indented + (closing ? 0 : indentUnit);\n    },\n\n    electricChars: \"{}\",\n    blockCommentStart: \"/*\",\n    blockCommentEnd: \"*/\",\n    lineComment: \"//\",\n    fold: \"brace\"\n  };\n});\n\n  function words(str) {\n    var obj = {}, words = str.split(\" \");\n    for (var i = 0; i < words.length; ++i) obj[words[i]] = true;\n    return obj;\n  }\n  var cKeywords = \"auto if break int case long char register continue return default short do sizeof \" +\n    \"double static else struct entry switch extern typedef float union for unsigned \" +\n    \"goto while enum void const signed volatile\";\n\n  function cppHook(stream, state) {\n    if (!state.startOfLine) return false;\n    for (;;) {\n      if (stream.skipTo(\"\\\\\")) {\n        stream.next();\n        if (stream.eol()) {\n          state.tokenize = cppHook;\n          break;\n        }\n      } else {\n        stream.skipToEnd();\n        state.tokenize = null;\n        break;\n      }\n    }\n    return \"meta\";\n  }\n\n  function cpp11StringHook(stream, state) {\n    stream.backUp(1);\n    // Raw strings.\n    if (stream.match(/(R|u8R|uR|UR|LR)/)) {\n      var match = stream.match(/\"([^\\s\\\\()]{0,16})\\(/);\n      if (!match) {\n        return false;\n      }\n      state.cpp11RawStringDelim = match[1];\n      state.tokenize = tokenRawString;\n      return tokenRawString(stream, state);\n    }\n    // Unicode strings/chars.\n    if (stream.match(/(u8|u|U|L)/)) {\n      if (stream.match(/[\"']/, /* eat */ false)) {\n        return \"string\";\n      }\n      return false;\n    }\n    // Ignore this hook.\n    stream.next();\n    return false;\n  }\n\n  // C#-style strings where \"\" escapes a quote.\n  function tokenAtString(stream, state) {\n    var next;\n    while ((next = stream.next()) != null) {\n      if (next == '\"' && !stream.eat('\"')) {\n        state.tokenize = null;\n        break;\n      }\n    }\n    return \"string\";\n  }\n\n  // C++11 raw string literal is <prefix>\"<delim>( anything )<delim>\", where\n  // <delim> can be a string up to 16 characters long.\n  function tokenRawString(stream, state) {\n    // Escape characters that have special regex meanings.\n    var delim = state.cpp11RawStringDelim.replace(/[^\\w\\s]/g, '\\\\$&');\n    var match = stream.match(new RegExp(\".*?\\\\)\" + delim + '\"'));\n    if (match)\n      state.tokenize = null;\n    else\n      stream.skipToEnd();\n    return \"string\";\n  }\n\n  function def(mimes, mode) {\n    if (typeof mimes == \"string\") mimes = [mimes];\n    var words = [];\n    function add(obj) {\n      if (obj) for (var prop in obj) if (obj.hasOwnProperty(prop))\n        words.push(prop);\n    }\n    add(mode.keywords);\n    add(mode.builtin);\n    add(mode.atoms);\n    if (words.length) {\n      mode.helperType = mimes[0];\n      CodeMirror.registerHelper(\"hintWords\", mimes[0], words);\n    }\n\n    for (var i = 0; i < mimes.length; ++i)\n      CodeMirror.defineMIME(mimes[i], mode);\n  }\n\n  def([\"text/x-csrc\", \"text/x-c\", \"text/x-chdr\"], {\n    name: \"clike\",\n    keywords: words(cKeywords),\n    blockKeywords: words(\"case do else for if switch while struct\"),\n    atoms: words(\"null\"),\n    hooks: {\"#\": cppHook},\n    modeProps: {fold: [\"brace\", \"include\"]}\n  });\n\n  def([\"text/x-c++src\", \"text/x-c++hdr\"], {\n    name: \"clike\",\n    keywords: words(cKeywords + \" asm dynamic_cast namespace reinterpret_cast try bool explicit new \" +\n                    \"static_cast typeid catch operator template typename class friend private \" +\n                    \"this using const_cast inline public throw virtual delete mutable protected \" +\n                    \"wchar_t alignas alignof constexpr decltype nullptr noexcept thread_local final \" +\n                    \"static_assert override\"),\n    blockKeywords: words(\"catch class do else finally for if struct switch try while\"),\n    atoms: words(\"true false null\"),\n    hooks: {\n      \"#\": cppHook,\n      \"u\": cpp11StringHook,\n      \"U\": cpp11StringHook,\n      \"L\": cpp11StringHook,\n      \"R\": cpp11StringHook\n    },\n    modeProps: {fold: [\"brace\", \"include\"]}\n  });\n\n  def(\"text/x-java\", {\n    name: \"clike\",\n    keywords: words(\"abstract assert boolean break byte case catch char class const continue default \" +\n                    \"do double else enum extends final finally float for goto if implements import \" +\n                    \"instanceof int interface long native new package private protected public \" +\n                    \"return short static strictfp super switch synchronized this throw throws transient \" +\n                    \"try void volatile while\"),\n    blockKeywords: words(\"catch class do else finally for if switch try while\"),\n    atoms: words(\"true false null\"),\n    hooks: {\n      \"@\": function(stream) {\n        stream.eatWhile(/[\\w\\$_]/);\n        return \"meta\";\n      }\n    },\n    modeProps: {fold: [\"brace\", \"import\"]}\n  });\n\n  def(\"text/x-csharp\", {\n    name: \"clike\",\n    keywords: words(\"abstract as base break case catch checked class const continue\" +\n                    \" default delegate do else enum event explicit extern finally fixed for\" +\n                    \" foreach goto if implicit in interface internal is lock namespace new\" +\n                    \" operator out override params private protected public readonly ref return sealed\" +\n                    \" sizeof stackalloc static struct switch this throw try typeof unchecked\" +\n                    \" unsafe using virtual void volatile while add alias ascending descending dynamic from get\" +\n                    \" global group into join let orderby partial remove select set value var yield\"),\n    blockKeywords: words(\"catch class do else finally for foreach if struct switch try while\"),\n    builtin: words(\"Boolean Byte Char DateTime DateTimeOffset Decimal Double\" +\n                    \" Guid Int16 Int32 Int64 Object SByte Single String TimeSpan UInt16 UInt32\" +\n                    \" UInt64 bool byte char decimal double short int long object\"  +\n                    \" sbyte float string ushort uint ulong\"),\n    atoms: words(\"true false null\"),\n    hooks: {\n      \"@\": function(stream, state) {\n        if (stream.eat('\"')) {\n          state.tokenize = tokenAtString;\n          return tokenAtString(stream, state);\n        }\n        stream.eatWhile(/[\\w\\$_]/);\n        return \"meta\";\n      }\n    }\n  });\n\n  function tokenTripleString(stream, state) {\n    var escaped = false;\n    while (!stream.eol()) {\n      if (!escaped && stream.match('\"\"\"')) {\n        state.tokenize = null;\n        break;\n      }\n      escaped = stream.next() == \"\\\\\" && !escaped;\n    }\n    return \"string\";\n  }\n\n  def(\"text/x-scala\", {\n    name: \"clike\",\n    keywords: words(\n\n      /* scala */\n      \"abstract case catch class def do else extends false final finally for forSome if \" +\n      \"implicit import lazy match new null object override package private protected return \" +\n      \"sealed super this throw trait try trye type val var while with yield _ : = => <- <: \" +\n      \"<% >: # @ \" +\n\n      /* package scala */\n      \"assert assume require print println printf readLine readBoolean readByte readShort \" +\n      \"readChar readInt readLong readFloat readDouble \" +\n\n      \"AnyVal App Application Array BufferedIterator BigDecimal BigInt Char Console Either \" +\n      \"Enumeration Equiv Error Exception Fractional Function IndexedSeq Integral Iterable \" +\n      \"Iterator List Map Numeric Nil NotNull Option Ordered Ordering PartialFunction PartialOrdering \" +\n      \"Product Proxy Range Responder Seq Serializable Set Specializable Stream StringBuilder \" +\n      \"StringContext Symbol Throwable Traversable TraversableOnce Tuple Unit Vector :: #:: \" +\n\n      /* package java.lang */\n      \"Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable \" +\n      \"Compiler Double Exception Float Integer Long Math Number Object Package Pair Process \" +\n      \"Runtime Runnable SecurityManager Short StackTraceElement StrictMath String \" +\n      \"StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void\"\n    ),\n    multiLineStrings: true,\n    blockKeywords: words(\"catch class do else finally for forSome if match switch try while\"),\n    atoms: words(\"true false null\"),\n    indentStatements: false,\n    hooks: {\n      \"@\": function(stream) {\n        stream.eatWhile(/[\\w\\$_]/);\n        return \"meta\";\n      },\n      '\"': function(stream, state) {\n        if (!stream.match('\"\"')) return false;\n        state.tokenize = tokenTripleString;\n        return state.tokenize(stream, state);\n      },\n      \"'\": function(stream) {\n        stream.eatWhile(/[\\w\\$_\\xa1-\\uffff]/);\n        return \"atom\";\n      }\n    }\n  });\n\n  def([\"x-shader/x-vertex\", \"x-shader/x-fragment\"], {\n    name: \"clike\",\n    keywords: words(\"float int bool void \" +\n                    \"vec2 vec3 vec4 ivec2 ivec3 ivec4 bvec2 bvec3 bvec4 \" +\n                    \"mat2 mat3 mat4 \" +\n                    \"sampler1D sampler2D sampler3D samplerCube \" +\n                    \"sampler1DShadow sampler2DShadow \" +\n                    \"const attribute uniform varying \" +\n                    \"break continue discard return \" +\n                    \"for while do if else struct \" +\n                    \"in out inout\"),\n    blockKeywords: words(\"for while do if else struct\"),\n    builtin: words(\"radians degrees sin cos tan asin acos atan \" +\n                    \"pow exp log exp2 sqrt inversesqrt \" +\n                    \"abs sign floor ceil fract mod min max clamp mix step smoothstep \" +\n                    \"length distance dot cross normalize ftransform faceforward \" +\n                    \"reflect refract matrixCompMult \" +\n                    \"lessThan lessThanEqual greaterThan greaterThanEqual \" +\n                    \"equal notEqual any all not \" +\n                    \"texture1D texture1DProj texture1DLod texture1DProjLod \" +\n                    \"texture2D texture2DProj texture2DLod texture2DProjLod \" +\n                    \"texture3D texture3DProj texture3DLod texture3DProjLod \" +\n                    \"textureCube textureCubeLod \" +\n                    \"shadow1D shadow2D shadow1DProj shadow2DProj \" +\n                    \"shadow1DLod shadow2DLod shadow1DProjLod shadow2DProjLod \" +\n                    \"dFdx dFdy fwidth \" +\n                    \"noise1 noise2 noise3 noise4\"),\n    atoms: words(\"true false \" +\n                \"gl_FragColor gl_SecondaryColor gl_Normal gl_Vertex \" +\n                \"gl_MultiTexCoord0 gl_MultiTexCoord1 gl_MultiTexCoord2 gl_MultiTexCoord3 \" +\n                \"gl_MultiTexCoord4 gl_MultiTexCoord5 gl_MultiTexCoord6 gl_MultiTexCoord7 \" +\n                \"gl_FogCoord gl_PointCoord \" +\n                \"gl_Position gl_PointSize gl_ClipVertex \" +\n                \"gl_FrontColor gl_BackColor gl_FrontSecondaryColor gl_BackSecondaryColor \" +\n                \"gl_TexCoord gl_FogFragCoord \" +\n                \"gl_FragCoord gl_FrontFacing \" +\n                \"gl_FragData gl_FragDepth \" +\n                \"gl_ModelViewMatrix gl_ProjectionMatrix gl_ModelViewProjectionMatrix \" +\n                \"gl_TextureMatrix gl_NormalMatrix gl_ModelViewMatrixInverse \" +\n                \"gl_ProjectionMatrixInverse gl_ModelViewProjectionMatrixInverse \" +\n                \"gl_TexureMatrixTranspose gl_ModelViewMatrixInverseTranspose \" +\n                \"gl_ProjectionMatrixInverseTranspose \" +\n                \"gl_ModelViewProjectionMatrixInverseTranspose \" +\n                \"gl_TextureMatrixInverseTranspose \" +\n                \"gl_NormalScale gl_DepthRange gl_ClipPlane \" +\n                \"gl_Point gl_FrontMaterial gl_BackMaterial gl_LightSource gl_LightModel \" +\n                \"gl_FrontLightModelProduct gl_BackLightModelProduct \" +\n                \"gl_TextureColor gl_EyePlaneS gl_EyePlaneT gl_EyePlaneR gl_EyePlaneQ \" +\n                \"gl_FogParameters \" +\n                \"gl_MaxLights gl_MaxClipPlanes gl_MaxTextureUnits gl_MaxTextureCoords \" +\n                \"gl_MaxVertexAttribs gl_MaxVertexUniformComponents gl_MaxVaryingFloats \" +\n                \"gl_MaxVertexTextureImageUnits gl_MaxTextureImageUnits \" +\n                \"gl_MaxFragmentUniformComponents gl_MaxCombineTextureImageUnits \" +\n                \"gl_MaxDrawBuffers\"),\n    hooks: {\"#\": cppHook},\n    modeProps: {fold: [\"brace\", \"include\"]}\n  });\n\n  def(\"text/x-nesc\", {\n    name: \"clike\",\n    keywords: words(cKeywords + \"as atomic async call command component components configuration event generic \" +\n                    \"implementation includes interface module new norace nx_struct nx_union post provides \" +\n                    \"signal task uses abstract extends\"),\n    blockKeywords: words(\"case do else for if switch while struct\"),\n    atoms: words(\"null\"),\n    hooks: {\"#\": cppHook},\n    modeProps: {fold: [\"brace\", \"include\"]}\n  });\n\n  def(\"text/x-objectivec\", {\n    name: \"clike\",\n    keywords: words(cKeywords + \"inline restrict _Bool _Complex _Imaginery BOOL Class bycopy byref id IMP in \" +\n                    \"inout nil oneway out Protocol SEL self super atomic nonatomic retain copy readwrite readonly\"),\n    atoms: words(\"YES NO NULL NILL ON OFF\"),\n    hooks: {\n      \"@\": function(stream) {\n        stream.eatWhile(/[\\w\\$]/);\n        return \"keyword\";\n      },\n      \"#\": cppHook\n    },\n    modeProps: {fold: \"brace\"}\n  });\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/clike/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: C-like mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"../../addon/edit/matchbrackets.js\"></script>\n<link rel=\"stylesheet\" href=\"../../addon/hint/show-hint.css\">\n<script src=\"../../addon/hint/show-hint.js\"></script>\n<script src=\"clike.js\"></script>\n<style>.CodeMirror {border: 2px inset #dee;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">C-like</a>\n  </ul>\n</div>\n\n<article>\n<h2>C-like mode</h2>\n\n<div><textarea id=\"c-code\">\n/* C demo code */\n\n#include <zmq.h>\n#include <pthread.h>\n#include <semaphore.h>\n#include <time.h>\n#include <stdio.h>\n#include <fcntl.h>\n#include <malloc.h>\n\ntypedef struct {\n  void* arg_socket;\n  zmq_msg_t* arg_msg;\n  char* arg_string;\n  unsigned long arg_len;\n  int arg_int, arg_command;\n\n  int signal_fd;\n  int pad;\n  void* context;\n  sem_t sem;\n} acl_zmq_context;\n\n#define p(X) (context->arg_##X)\n\nvoid* zmq_thread(void* context_pointer) {\n  acl_zmq_context* context = (acl_zmq_context*)context_pointer;\n  char ok = 'K', err = 'X';\n  int res;\n\n  while (1) {\n    while ((res = sem_wait(&amp;context->sem)) == EINTR);\n    if (res) {write(context->signal_fd, &amp;err, 1); goto cleanup;}\n    switch(p(command)) {\n    case 0: goto cleanup;\n    case 1: p(socket) = zmq_socket(context->context, p(int)); break;\n    case 2: p(int) = zmq_close(p(socket)); break;\n    case 3: p(int) = zmq_bind(p(socket), p(string)); break;\n    case 4: p(int) = zmq_connect(p(socket), p(string)); break;\n    case 5: p(int) = zmq_getsockopt(p(socket), p(int), (void*)p(string), &amp;p(len)); break;\n    case 6: p(int) = zmq_setsockopt(p(socket), p(int), (void*)p(string), p(len)); break;\n    case 7: p(int) = zmq_send(p(socket), p(msg), p(int)); break;\n    case 8: p(int) = zmq_recv(p(socket), p(msg), p(int)); break;\n    case 9: p(int) = zmq_poll(p(socket), p(int), p(len)); break;\n    }\n    p(command) = errno;\n    write(context->signal_fd, &amp;ok, 1);\n  }\n cleanup:\n  close(context->signal_fd);\n  free(context_pointer);\n  return 0;\n}\n\nvoid* zmq_thread_init(void* zmq_context, int signal_fd) {\n  acl_zmq_context* context = malloc(sizeof(acl_zmq_context));\n  pthread_t thread;\n\n  context->context = zmq_context;\n  context->signal_fd = signal_fd;\n  sem_init(&amp;context->sem, 1, 0);\n  pthread_create(&amp;thread, 0, &amp;zmq_thread, context);\n  pthread_detach(thread);\n  return context;\n}\n</textarea></div>\n\n<h2>C++ example</h2>\n\n<div><textarea id=\"cpp-code\">\n#include <iostream>\n#include \"mystuff/util.h\"\n\nnamespace {\nenum Enum {\n  VAL1, VAL2, VAL3\n};\n\nchar32_t unicode_string = U\"\\U0010FFFF\";\nstring raw_string = R\"delim(anything\nyou\nwant)delim\";\n\nint Helper(const MyType& param) {\n  return 0;\n}\n} // namespace\n\nclass ForwardDec;\n\ntemplate <class T, class V>\nclass Class : public BaseClass {\n  const MyType<T, V> member_;\n\n public:\n  const MyType<T, V>& Method() const {\n    return member_;\n  }\n\n  void Method2(MyType<T, V>* value);\n}\n\ntemplate <class T, class V>\nvoid Class::Method2(MyType<T, V>* value) {\n  std::out << 1 >> method();\n  value->Method3(member_);\n  member_ = value;\n}\n</textarea></div>\n\n<h2>Objective-C example</h2>\n\n<div><textarea id=\"objectivec-code\">\n/*\nThis is a longer comment\nThat spans two lines\n*/\n\n#import <Test/Test.h>\n@implementation YourAppDelegate\n\n// This is a one-line comment\n\n- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{\n  char myString[] = \"This is a C character array\";\n  int test = 5;\n  return YES;\n}\n</textarea></div>\n\n<h2>Java example</h2>\n\n<div><textarea id=\"java-code\">\nimport com.demo.util.MyType;\nimport com.demo.util.MyInterface;\n\npublic enum Enum {\n  VAL1, VAL2, VAL3\n}\n\npublic class Class<T, V> implements MyInterface {\n  public static final MyType<T, V> member;\n  \n  private class InnerClass {\n    public int zero() {\n      return 0;\n    }\n  }\n\n  @Override\n  public MyType method() {\n    return member;\n  }\n\n  public void method2(MyType<T, V> value) {\n    method();\n    value.method3();\n    member = value;\n  }\n}\n</textarea></div>\n\n<h2>Scala example</h2>\n\n<div><textarea id=\"scala-code\">\nobject FilterTest extends App {\n  def filter(xs: List[Int], threshold: Int) = {\n    def process(ys: List[Int]): List[Int] =\n      if (ys.isEmpty) ys\n      else if (ys.head < threshold) ys.head :: process(ys.tail)\n      else process(ys.tail)\n    process(xs)\n  }\n  println(filter(List(1, 9, 2, 8, 3, 7, 4), 5))\n}\n</textarea></div>\n\n    <script>\n      var cEditor = CodeMirror.fromTextArea(document.getElementById(\"c-code\"), {\n        lineNumbers: true,\n        matchBrackets: true,\n        mode: \"text/x-csrc\"\n      });\n      var cppEditor = CodeMirror.fromTextArea(document.getElementById(\"cpp-code\"), {\n        lineNumbers: true,\n        matchBrackets: true,\n        mode: \"text/x-c++src\"\n      });\n      var javaEditor = CodeMirror.fromTextArea(document.getElementById(\"java-code\"), {\n        lineNumbers: true,\n        matchBrackets: true,\n        mode: \"text/x-java\"\n      });\n      var objectivecEditor = CodeMirror.fromTextArea(document.getElementById(\"objectivec-code\"), {\n        lineNumbers: true,\n        matchBrackets: true,\n        mode: \"text/x-objectivec\"\n      });\n      var scalaEditor = CodeMirror.fromTextArea(document.getElementById(\"scala-code\"), {\n        lineNumbers: true,\n        matchBrackets: true,\n        mode: \"text/x-scala\"\n      });\n      var mac = CodeMirror.keyMap.default == CodeMirror.keyMap.macDefault;\n      CodeMirror.keyMap.default[(mac ? \"Cmd\" : \"Ctrl\") + \"-Space\"] = \"autocomplete\";\n    </script>\n\n    <p>Simple mode that tries to handle C-like languages as well as it\n    can. Takes two configuration parameters: <code>keywords</code>, an\n    object whose property names are the keywords in the language,\n    and <code>useCPP</code>, which determines whether C preprocessor\n    directives are recognized.</p>\n\n    <p><strong>MIME types defined:</strong> <code>text/x-csrc</code>\n    (C), <code>text/x-c++src</code> (C++), <code>text/x-java</code>\n    (Java), <code>text/x-csharp</code> (C#),\n    <code>text/x-objectivec</code> (Objective-C),\n    <code>text/x-scala</code> (Scala), <code>text/x-vertex</code>\n    and <code>x-shader/x-fragment</code> (shader programs).</p>\n</article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/clike/scala.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Scala mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<link rel=\"stylesheet\" href=\"../../theme/ambiance.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"../../addon/edit/matchbrackets.js\"></script>\n<script src=\"clike.js\"></script>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Scala</a>\n  </ul>\n</div>\n\n<article>\n<h2>Scala mode</h2>\n<form>\n<textarea id=\"code\" name=\"code\">\n\n  /*                     __                                               *\\\n  **     ________ ___   / /  ___     Scala API                            **\n  **    / __/ __// _ | / /  / _ |    (c) 2003-2011, LAMP/EPFL             **\n  **  __\\ \\/ /__/ __ |/ /__/ __ |    http://scala-lang.org/               **\n  ** /____/\\___/_/ |_/____/_/ | |                                         **\n  **                          |/                                          **\n  \\*                                                                      */\n\n  package scala.collection\n\n  import generic._\n  import mutable.{ Builder, ListBuffer }\n  import annotation.{tailrec, migration, bridge}\n  import annotation.unchecked.{ uncheckedVariance => uV }\n  import parallel.ParIterable\n\n  /** A template trait for traversable collections of type `Traversable[A]`.\n   *  \n   *  $traversableInfo\n   *  @define mutability\n   *  @define traversableInfo\n   *  This is a base trait of all kinds of $mutability Scala collections. It\n   *  implements the behavior common to all collections, in terms of a method\n   *  `foreach` with signature:\n   * {{{\n   *     def foreach[U](f: Elem => U): Unit\n   * }}}\n   *  Collection classes mixing in this trait provide a concrete \n   *  `foreach` method which traverses all the\n   *  elements contained in the collection, applying a given function to each.\n   *  They also need to provide a method `newBuilder`\n   *  which creates a builder for collections of the same kind.\n   *  \n   *  A traversable class might or might not have two properties: strictness\n   *  and orderedness. Neither is represented as a type.\n   *  \n   *  The instances of a strict collection class have all their elements\n   *  computed before they can be used as values. By contrast, instances of\n   *  a non-strict collection class may defer computation of some of their\n   *  elements until after the instance is available as a value.\n   *  A typical example of a non-strict collection class is a\n   *  <a href=\"../immutable/Stream.html\" target=\"ContentFrame\">\n   *  `scala.collection.immutable.Stream`</a>.\n   *  A more general class of examples are `TraversableViews`.\n   *  \n   *  If a collection is an instance of an ordered collection class, traversing\n   *  its elements with `foreach` will always visit elements in the\n   *  same order, even for different runs of the program. If the class is not\n   *  ordered, `foreach` can visit elements in different orders for\n   *  different runs (but it will keep the same order in the same run).'\n   * \n   *  A typical example of a collection class which is not ordered is a\n   *  `HashMap` of objects. The traversal order for hash maps will\n   *  depend on the hash codes of its elements, and these hash codes might\n   *  differ from one run to the next. By contrast, a `LinkedHashMap`\n   *  is ordered because it's `foreach` method visits elements in the\n   *  order they were inserted into the `HashMap`.\n   *\n   *  @author Martin Odersky\n   *  @version 2.8\n   *  @since   2.8\n   *  @tparam A    the element type of the collection\n   *  @tparam Repr the type of the actual collection containing the elements.\n   *\n   *  @define Coll Traversable\n   *  @define coll traversable collection\n   */\n  trait TraversableLike[+A, +Repr] extends HasNewBuilder[A, Repr] \n                                      with FilterMonadic[A, Repr]\n                                      with TraversableOnce[A]\n                                      with GenTraversableLike[A, Repr]\n                                      with Parallelizable[A, ParIterable[A]]\n  {\n    self =>\n\n    import Traversable.breaks._\n\n    /** The type implementing this traversable */\n    protected type Self = Repr\n\n    /** The collection of type $coll underlying this `TraversableLike` object.\n     *  By default this is implemented as the `TraversableLike` object itself,\n     *  but this can be overridden.\n     */\n    def repr: Repr = this.asInstanceOf[Repr]\n\n    /** The underlying collection seen as an instance of `$Coll`.\n     *  By default this is implemented as the current collection object itself,\n     *  but this can be overridden.\n     */\n    protected[this] def thisCollection: Traversable[A] = this.asInstanceOf[Traversable[A]]\n\n    /** A conversion from collections of type `Repr` to `$Coll` objects.\n     *  By default this is implemented as just a cast, but this can be overridden.\n     */\n    protected[this] def toCollection(repr: Repr): Traversable[A] = repr.asInstanceOf[Traversable[A]]\n\n    /** Creates a new builder for this collection type.\n     */\n    protected[this] def newBuilder: Builder[A, Repr]\n\n    protected[this] def parCombiner = ParIterable.newCombiner[A]\n\n    /** Applies a function `f` to all elements of this $coll.\n     *  \n     *    Note: this method underlies the implementation of most other bulk operations.\n     *    It's important to implement this method in an efficient way.\n     *  \n     *\n     *  @param  f   the function that is applied for its side-effect to every element.\n     *              The result of function `f` is discarded.\n     *              \n     *  @tparam  U  the type parameter describing the result of function `f`. \n     *              This result will always be ignored. Typically `U` is `Unit`,\n     *              but this is not necessary.\n     *\n     *  @usecase def foreach(f: A => Unit): Unit\n     */\n    def foreach[U](f: A => U): Unit\n\n    /** Tests whether this $coll is empty.\n     *\n     *  @return    `true` if the $coll contain no elements, `false` otherwise.\n     */\n    def isEmpty: Boolean = {\n      var result = true\n      breakable {\n        for (x <- this) {\n          result = false\n          break\n        }\n      }\n      result\n    }\n\n    /** Tests whether this $coll is known to have a finite size.\n     *  All strict collections are known to have finite size. For a non-strict collection\n     *  such as `Stream`, the predicate returns `true` if all elements have been computed.\n     *  It returns `false` if the stream is not yet evaluated to the end.\n     *\n     *  Note: many collection methods will not work on collections of infinite sizes. \n     *\n     *  @return  `true` if this collection is known to have finite size, `false` otherwise.\n     */\n    def hasDefiniteSize = true\n\n    def ++[B >: A, That](that: GenTraversableOnce[B])(implicit bf: CanBuildFrom[Repr, B, That]): That = {\n      val b = bf(repr)\n      if (that.isInstanceOf[IndexedSeqLike[_, _]]) b.sizeHint(this, that.seq.size)\n      b ++= thisCollection\n      b ++= that.seq\n      b.result\n    }\n\n    @bridge\n    def ++[B >: A, That](that: TraversableOnce[B])(implicit bf: CanBuildFrom[Repr, B, That]): That =\n      ++(that: GenTraversableOnce[B])(bf)\n\n    /** Concatenates this $coll with the elements of a traversable collection.\n     *  It differs from ++ in that the right operand determines the type of the\n     *  resulting collection rather than the left one.\n     * \n     *  @param that   the traversable to append.\n     *  @tparam B     the element type of the returned collection. \n     *  @tparam That  $thatinfo\n     *  @param bf     $bfinfo\n     *  @return       a new collection of type `That` which contains all elements\n     *                of this $coll followed by all elements of `that`.\n     * \n     *  @usecase def ++:[B](that: TraversableOnce[B]): $Coll[B]\n     *  \n     *  @return       a new $coll which contains all elements of this $coll\n     *                followed by all elements of `that`.\n     */\n    def ++:[B >: A, That](that: TraversableOnce[B])(implicit bf: CanBuildFrom[Repr, B, That]): That = {\n      val b = bf(repr)\n      if (that.isInstanceOf[IndexedSeqLike[_, _]]) b.sizeHint(this, that.size)\n      b ++= that\n      b ++= thisCollection\n      b.result\n    }\n\n    /** This overload exists because: for the implementation of ++: we should reuse\n     *  that of ++ because many collections override it with more efficient versions.\n     *  Since TraversableOnce has no '++' method, we have to implement that directly,\n     *  but Traversable and down can use the overload.\n     */\n    def ++:[B >: A, That](that: Traversable[B])(implicit bf: CanBuildFrom[Repr, B, That]): That =\n      (that ++ seq)(breakOut)\n\n    def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That = {\n      val b = bf(repr)\n      b.sizeHint(this) \n      for (x <- this) b += f(x)\n      b.result\n    }\n\n    def flatMap[B, That](f: A => GenTraversableOnce[B])(implicit bf: CanBuildFrom[Repr, B, That]): That = {\n      val b = bf(repr)\n      for (x <- this) b ++= f(x).seq\n      b.result\n    }\n\n    /** Selects all elements of this $coll which satisfy a predicate.\n     *\n     *  @param p     the predicate used to test elements.\n     *  @return      a new $coll consisting of all elements of this $coll that satisfy the given\n     *               predicate `p`. The order of the elements is preserved.\n     */\n    def filter(p: A => Boolean): Repr = {\n      val b = newBuilder\n      for (x <- this) \n        if (p(x)) b += x\n      b.result\n    }\n\n    /** Selects all elements of this $coll which do not satisfy a predicate.\n     *\n     *  @param p     the predicate used to test elements.\n     *  @return      a new $coll consisting of all elements of this $coll that do not satisfy the given\n     *               predicate `p`. The order of the elements is preserved.\n     */\n    def filterNot(p: A => Boolean): Repr = filter(!p(_))\n\n    def collect[B, That](pf: PartialFunction[A, B])(implicit bf: CanBuildFrom[Repr, B, That]): That = {\n      val b = bf(repr)\n      for (x <- this) if (pf.isDefinedAt(x)) b += pf(x)\n      b.result\n    }\n\n    /** Builds a new collection by applying an option-valued function to all\n     *  elements of this $coll on which the function is defined.\n     *\n     *  @param f      the option-valued function which filters and maps the $coll.\n     *  @tparam B     the element type of the returned collection.\n     *  @tparam That  $thatinfo\n     *  @param bf     $bfinfo\n     *  @return       a new collection of type `That` resulting from applying the option-valued function\n     *                `f` to each element and collecting all defined results.\n     *                The order of the elements is preserved.\n     *\n     *  @usecase def filterMap[B](f: A => Option[B]): $Coll[B]\n     *  \n     *  @param pf     the partial function which filters and maps the $coll.\n     *  @return       a new $coll resulting from applying the given option-valued function\n     *                `f` to each element and collecting all defined results.\n     *                The order of the elements is preserved.\n    def filterMap[B, That](f: A => Option[B])(implicit bf: CanBuildFrom[Repr, B, That]): That = {\n      val b = bf(repr)\n      for (x <- this) \n        f(x) match {\n          case Some(y) => b += y\n          case _ =>\n        }\n      b.result\n    }\n     */\n\n    /** Partitions this $coll in two ${coll}s according to a predicate.\n     *\n     *  @param p the predicate on which to partition.\n     *  @return  a pair of ${coll}s: the first $coll consists of all elements that \n     *           satisfy the predicate `p` and the second $coll consists of all elements\n     *           that don't. The relative order of the elements in the resulting ${coll}s\n     *           is the same as in the original $coll.\n     */\n    def partition(p: A => Boolean): (Repr, Repr) = {\n      val l, r = newBuilder\n      for (x <- this) (if (p(x)) l else r) += x\n      (l.result, r.result)\n    }\n\n    def groupBy[K](f: A => K): immutable.Map[K, Repr] = {\n      val m = mutable.Map.empty[K, Builder[A, Repr]]\n      for (elem <- this) {\n        val key = f(elem)\n        val bldr = m.getOrElseUpdate(key, newBuilder)\n        bldr += elem\n      }\n      val b = immutable.Map.newBuilder[K, Repr]\n      for ((k, v) <- m)\n        b += ((k, v.result))\n\n      b.result\n    }\n\n    /** Tests whether a predicate holds for all elements of this $coll.\n     *\n     *  $mayNotTerminateInf\n     *\n     *  @param   p     the predicate used to test elements.\n     *  @return        `true` if the given predicate `p` holds for all elements\n     *                 of this $coll, otherwise `false`.\n     */\n    def forall(p: A => Boolean): Boolean = {\n      var result = true\n      breakable {\n        for (x <- this)\n          if (!p(x)) { result = false; break }\n      }\n      result\n    }\n\n    /** Tests whether a predicate holds for some of the elements of this $coll.\n     *\n     *  $mayNotTerminateInf\n     *\n     *  @param   p     the predicate used to test elements.\n     *  @return        `true` if the given predicate `p` holds for some of the\n     *                 elements of this $coll, otherwise `false`.\n     */\n    def exists(p: A => Boolean): Boolean = {\n      var result = false\n      breakable {\n        for (x <- this)\n          if (p(x)) { result = true; break }\n      }\n      result\n    }\n\n    /** Finds the first element of the $coll satisfying a predicate, if any.\n     * \n     *  $mayNotTerminateInf\n     *  $orderDependent\n     *\n     *  @param p    the predicate used to test elements.\n     *  @return     an option value containing the first element in the $coll\n     *              that satisfies `p`, or `None` if none exists.\n     */\n    def find(p: A => Boolean): Option[A] = {\n      var result: Option[A] = None\n      breakable {\n        for (x <- this)\n          if (p(x)) { result = Some(x); break }\n      }\n      result\n    }\n\n    def scan[B >: A, That](z: B)(op: (B, B) => B)(implicit cbf: CanBuildFrom[Repr, B, That]): That = scanLeft(z)(op)\n\n    def scanLeft[B, That](z: B)(op: (B, A) => B)(implicit bf: CanBuildFrom[Repr, B, That]): That = {\n      val b = bf(repr)\n      b.sizeHint(this, 1)\n      var acc = z\n      b += acc\n      for (x <- this) { acc = op(acc, x); b += acc }\n      b.result\n    }\n\n    @migration(2, 9,\n      \"This scanRight definition has changed in 2.9.\\n\" +\n      \"The previous behavior can be reproduced with scanRight.reverse.\"\n    )\n    def scanRight[B, That](z: B)(op: (A, B) => B)(implicit bf: CanBuildFrom[Repr, B, That]): That = {\n      var scanned = List(z)\n      var acc = z\n      for (x <- reversed) {\n        acc = op(x, acc)\n        scanned ::= acc\n      }\n      val b = bf(repr)\n      for (elem <- scanned) b += elem\n      b.result\n    }\n\n    /** Selects the first element of this $coll.\n     *  $orderDependent\n     *  @return  the first element of this $coll.\n     *  @throws `NoSuchElementException` if the $coll is empty.\n     */\n    def head: A = {\n      var result: () => A = () => throw new NoSuchElementException\n      breakable {\n        for (x <- this) {\n          result = () => x\n          break\n        }\n      }\n      result()\n    }\n\n    /** Optionally selects the first element.\n     *  $orderDependent\n     *  @return  the first element of this $coll if it is nonempty, `None` if it is empty.\n     */\n    def headOption: Option[A] = if (isEmpty) None else Some(head)\n\n    /** Selects all elements except the first.\n     *  $orderDependent\n     *  @return  a $coll consisting of all elements of this $coll\n     *           except the first one.\n     *  @throws `UnsupportedOperationException` if the $coll is empty.\n     */ \n    override def tail: Repr = {\n      if (isEmpty) throw new UnsupportedOperationException(\"empty.tail\")\n      drop(1)\n    }\n\n    /** Selects the last element.\n      * $orderDependent\n      * @return The last element of this $coll.\n      * @throws NoSuchElementException If the $coll is empty.\n      */\n    def last: A = {\n      var lst = head\n      for (x <- this)\n        lst = x\n      lst\n    }\n\n    /** Optionally selects the last element.\n     *  $orderDependent\n     *  @return  the last element of this $coll$ if it is nonempty, `None` if it is empty.\n     */\n    def lastOption: Option[A] = if (isEmpty) None else Some(last)\n\n    /** Selects all elements except the last.\n     *  $orderDependent\n     *  @return  a $coll consisting of all elements of this $coll\n     *           except the last one.\n     *  @throws `UnsupportedOperationException` if the $coll is empty.\n     */\n    def init: Repr = {\n      if (isEmpty) throw new UnsupportedOperationException(\"empty.init\")\n      var lst = head\n      var follow = false\n      val b = newBuilder\n      b.sizeHint(this, -1)\n      for (x <- this.seq) {\n        if (follow) b += lst\n        else follow = true\n        lst = x\n      }\n      b.result\n    }\n\n    def take(n: Int): Repr = slice(0, n)\n\n    def drop(n: Int): Repr = \n      if (n <= 0) {\n        val b = newBuilder\n        b.sizeHint(this)\n        b ++= thisCollection result\n      }\n      else sliceWithKnownDelta(n, Int.MaxValue, -n)\n\n    def slice(from: Int, until: Int): Repr = sliceWithKnownBound(math.max(from, 0), until)\n\n    // Precondition: from >= 0, until > 0, builder already configured for building.\n    private[this] def sliceInternal(from: Int, until: Int, b: Builder[A, Repr]): Repr = {\n      var i = 0\n      breakable {\n        for (x <- this.seq) {\n          if (i >= from) b += x\n          i += 1\n          if (i >= until) break\n        }\n      }\n      b.result\n    }\n    // Precondition: from >= 0\n    private[scala] def sliceWithKnownDelta(from: Int, until: Int, delta: Int): Repr = {\n      val b = newBuilder\n      if (until <= from) b.result\n      else {\n        b.sizeHint(this, delta)\n        sliceInternal(from, until, b)\n      }\n    }\n    // Precondition: from >= 0\n    private[scala] def sliceWithKnownBound(from: Int, until: Int): Repr = {\n      val b = newBuilder\n      if (until <= from) b.result\n      else {\n        b.sizeHintBounded(until - from, this)      \n        sliceInternal(from, until, b)\n      }\n    }\n\n    def takeWhile(p: A => Boolean): Repr = {\n      val b = newBuilder\n      breakable {\n        for (x <- this) {\n          if (!p(x)) break\n          b += x\n        }\n      }\n      b.result\n    }\n\n    def dropWhile(p: A => Boolean): Repr = {\n      val b = newBuilder\n      var go = false\n      for (x <- this) {\n        if (!p(x)) go = true\n        if (go) b += x\n      }\n      b.result\n    }\n\n    def span(p: A => Boolean): (Repr, Repr) = {\n      val l, r = newBuilder\n      var toLeft = true\n      for (x <- this) {\n        toLeft = toLeft && p(x)\n        (if (toLeft) l else r) += x\n      }\n      (l.result, r.result)\n    }\n\n    def splitAt(n: Int): (Repr, Repr) = {\n      val l, r = newBuilder\n      l.sizeHintBounded(n, this)\n      if (n >= 0) r.sizeHint(this, -n)\n      var i = 0\n      for (x <- this) {\n        (if (i < n) l else r) += x\n        i += 1\n      }\n      (l.result, r.result)\n    }\n\n    /** Iterates over the tails of this $coll. The first value will be this\n     *  $coll and the final one will be an empty $coll, with the intervening\n     *  values the results of successive applications of `tail`.\n     *\n     *  @return   an iterator over all the tails of this $coll\n     *  @example  `List(1,2,3).tails = Iterator(List(1,2,3), List(2,3), List(3), Nil)`\n     */  \n    def tails: Iterator[Repr] = iterateUntilEmpty(_.tail)\n\n    /** Iterates over the inits of this $coll. The first value will be this\n     *  $coll and the final one will be an empty $coll, with the intervening\n     *  values the results of successive applications of `init`.\n     *\n     *  @return  an iterator over all the inits of this $coll\n     *  @example  `List(1,2,3).inits = Iterator(List(1,2,3), List(1,2), List(1), Nil)`\n     */\n    def inits: Iterator[Repr] = iterateUntilEmpty(_.init)\n\n    /** Copies elements of this $coll to an array.\n     *  Fills the given array `xs` with at most `len` elements of\n     *  this $coll, starting at position `start`.\n     *  Copying will stop once either the end of the current $coll is reached,\n     *  or the end of the array is reached, or `len` elements have been copied.\n     *\n     *  $willNotTerminateInf\n     * \n     *  @param  xs     the array to fill.\n     *  @param  start  the starting index.\n     *  @param  len    the maximal number of elements to copy.\n     *  @tparam B      the type of the elements of the array. \n     * \n     *\n     *  @usecase def copyToArray(xs: Array[A], start: Int, len: Int): Unit\n     */\n    def copyToArray[B >: A](xs: Array[B], start: Int, len: Int) {\n      var i = start\n      val end = (start + len) min xs.length\n      breakable {\n        for (x <- this) {\n          if (i >= end) break\n          xs(i) = x\n          i += 1\n        }\n      }\n    }\n\n    def toTraversable: Traversable[A] = thisCollection\n    def toIterator: Iterator[A] = toStream.iterator\n    def toStream: Stream[A] = toBuffer.toStream\n\n    /** Converts this $coll to a string.\n     *\n     *  @return   a string representation of this collection. By default this\n     *            string consists of the `stringPrefix` of this $coll,\n     *            followed by all elements separated by commas and enclosed in parentheses.\n     */\n    override def toString = mkString(stringPrefix + \"(\", \", \", \")\")\n\n    /** Defines the prefix of this object's `toString` representation.\n     *\n     *  @return  a string representation which starts the result of `toString`\n     *           applied to this $coll. By default the string prefix is the\n     *           simple name of the collection class $coll.\n     */\n    def stringPrefix : String = {\n      var string = repr.asInstanceOf[AnyRef].getClass.getName\n      val idx1 = string.lastIndexOf('.' : Int)\n      if (idx1 != -1) string = string.substring(idx1 + 1)\n      val idx2 = string.indexOf('$')\n      if (idx2 != -1) string = string.substring(0, idx2)\n      string\n    }\n\n    /** Creates a non-strict view of this $coll.\n     * \n     *  @return a non-strict view of this $coll.\n     */\n    def view = new TraversableView[A, Repr] {\n      protected lazy val underlying = self.repr\n      override def foreach[U](f: A => U) = self foreach f\n    }\n\n    /** Creates a non-strict view of a slice of this $coll.\n     *\n     *  Note: the difference between `view` and `slice` is that `view` produces\n     *        a view of the current $coll, whereas `slice` produces a new $coll.\n     * \n     *  Note: `view(from, to)` is equivalent to `view.slice(from, to)`\n     *  $orderDependent\n     * \n     *  @param from   the index of the first element of the view\n     *  @param until  the index of the element following the view\n     *  @return a non-strict view of a slice of this $coll, starting at index `from`\n     *  and extending up to (but not including) index `until`.\n     */\n    def view(from: Int, until: Int): TraversableView[A, Repr] = view.slice(from, until)\n\n    /** Creates a non-strict filter of this $coll.\n     *\n     *  Note: the difference between `c filter p` and `c withFilter p` is that\n     *        the former creates a new collection, whereas the latter only\n     *        restricts the domain of subsequent `map`, `flatMap`, `foreach`,\n     *        and `withFilter` operations.\n     *  $orderDependent\n     * \n     *  @param p   the predicate used to test elements.\n     *  @return    an object of class `WithFilter`, which supports\n     *             `map`, `flatMap`, `foreach`, and `withFilter` operations.\n     *             All these operations apply to those elements of this $coll which\n     *             satisfy the predicate `p`.\n     */\n    def withFilter(p: A => Boolean): FilterMonadic[A, Repr] = new WithFilter(p)\n\n    /** A class supporting filtered operations. Instances of this class are\n     *  returned by method `withFilter`.\n     */\n    class WithFilter(p: A => Boolean) extends FilterMonadic[A, Repr] {\n\n      /** Builds a new collection by applying a function to all elements of the\n       *  outer $coll containing this `WithFilter` instance that satisfy predicate `p`.\n       *\n       *  @param f      the function to apply to each element.\n       *  @tparam B     the element type of the returned collection.\n       *  @tparam That  $thatinfo\n       *  @param bf     $bfinfo\n       *  @return       a new collection of type `That` resulting from applying\n       *                the given function `f` to each element of the outer $coll\n       *                that satisfies predicate `p` and collecting the results.\n       *\n       *  @usecase def map[B](f: A => B): $Coll[B] \n       *  \n       *  @return       a new $coll resulting from applying the given function\n       *                `f` to each element of the outer $coll that satisfies\n       *                predicate `p` and collecting the results.\n       */\n      def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That = {\n        val b = bf(repr)\n        for (x <- self) \n          if (p(x)) b += f(x)\n        b.result\n      }\n\n      /** Builds a new collection by applying a function to all elements of the\n       *  outer $coll containing this `WithFilter` instance that satisfy\n       *  predicate `p` and concatenating the results. \n       *\n       *  @param f      the function to apply to each element.\n       *  @tparam B     the element type of the returned collection.\n       *  @tparam That  $thatinfo\n       *  @param bf     $bfinfo\n       *  @return       a new collection of type `That` resulting from applying\n       *                the given collection-valued function `f` to each element\n       *                of the outer $coll that satisfies predicate `p` and\n       *                concatenating the results.\n       *\n       *  @usecase def flatMap[B](f: A => TraversableOnce[B]): $Coll[B]\n       * \n       *  @return       a new $coll resulting from applying the given collection-valued function\n       *                `f` to each element of the outer $coll that satisfies predicate `p` and concatenating the results.\n       */\n      def flatMap[B, That](f: A => GenTraversableOnce[B])(implicit bf: CanBuildFrom[Repr, B, That]): That = {\n        val b = bf(repr)\n        for (x <- self) \n          if (p(x)) b ++= f(x).seq\n        b.result\n      }\n\n      /** Applies a function `f` to all elements of the outer $coll containing\n       *  this `WithFilter` instance that satisfy predicate `p`.\n       *\n       *  @param  f   the function that is applied for its side-effect to every element.\n       *              The result of function `f` is discarded.\n       *              \n       *  @tparam  U  the type parameter describing the result of function `f`. \n       *              This result will always be ignored. Typically `U` is `Unit`,\n       *              but this is not necessary.\n       *\n       *  @usecase def foreach(f: A => Unit): Unit\n       */   \n      def foreach[U](f: A => U): Unit = \n        for (x <- self) \n          if (p(x)) f(x)\n\n      /** Further refines the filter for this $coll.\n       *\n       *  @param q   the predicate used to test elements.\n       *  @return    an object of class `WithFilter`, which supports\n       *             `map`, `flatMap`, `foreach`, and `withFilter` operations.\n       *             All these operations apply to those elements of this $coll which\n       *             satisfy the predicate `q` in addition to the predicate `p`.\n       */\n      def withFilter(q: A => Boolean): WithFilter = \n        new WithFilter(x => p(x) && q(x))\n    }\n\n    // A helper for tails and inits.\n    private def iterateUntilEmpty(f: Traversable[A @uV] => Traversable[A @uV]): Iterator[Repr] = {\n      val it = Iterator.iterate(thisCollection)(f) takeWhile (x => !x.isEmpty)\n      it ++ Iterator(Nil) map (newBuilder ++= _ result)\n    }\n  }\n\n\n</textarea>\n</form>\n\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        lineNumbers: true,\n        matchBrackets: true,\n        theme: \"ambiance\",\n        mode: \"text/x-scala\"\n      });\n    </script>\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/clojure/clojure.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n/**\n * Author: Hans Engel\n * Branched from CodeMirror's Scheme mode (by Koh Zi Han, based on implementation by Koh Zi Chun)\n */\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"clojure\", function (options) {\n    var BUILTIN = \"builtin\", COMMENT = \"comment\", STRING = \"string\", CHARACTER = \"string-2\",\n        ATOM = \"atom\", NUMBER = \"number\", BRACKET = \"bracket\", KEYWORD = \"keyword\", VAR = \"variable\";\n    var INDENT_WORD_SKIP = options.indentUnit || 2;\n    var NORMAL_INDENT_UNIT = options.indentUnit || 2;\n\n    function makeKeywords(str) {\n        var obj = {}, words = str.split(\" \");\n        for (var i = 0; i < words.length; ++i) obj[words[i]] = true;\n        return obj;\n    }\n\n    var atoms = makeKeywords(\"true false nil\");\n\n    var keywords = makeKeywords(\n      \"defn defn- def def- defonce defmulti defmethod defmacro defstruct deftype defprotocol defrecord defproject deftest slice defalias defhinted defmacro- defn-memo defnk defnk defonce- defunbound defunbound- defvar defvar- let letfn do case cond condp for loop recur when when-not when-let when-first if if-let if-not . .. -> ->> doto and or dosync doseq dotimes dorun doall load import unimport ns in-ns refer try catch finally throw with-open with-local-vars binding gen-class gen-and-load-class gen-and-save-class handler-case handle\");\n\n    var builtins = makeKeywords(\n        \"* *' *1 *2 *3 *agent* *allow-unresolved-vars* *assert* *clojure-version* *command-line-args* *compile-files* *compile-path* *compiler-options* *data-readers* *e *err* *file* *flush-on-newline* *fn-loader* *in* *math-context* *ns* *out* *print-dup* *print-length* *print-level* *print-meta* *print-readably* *read-eval* *source-path* *unchecked-math* *use-context-classloader* *verbose-defrecords* *warn-on-reflection* + +' - -' -> ->> ->ArrayChunk ->Vec ->VecNode ->VecSeq -cache-protocol-fn -reset-methods .. / < <= = == > >= EMPTY-NODE accessor aclone add-classpath add-watch agent agent-error agent-errors aget alength alias all-ns alter alter-meta! alter-var-root amap ancestors and apply areduce array-map aset aset-boolean aset-byte aset-char aset-double aset-float aset-int aset-long aset-short assert assoc assoc! assoc-in associative? atom await await-for await1 bases bean bigdec bigint biginteger binding bit-and bit-and-not bit-clear bit-flip bit-not bit-or bit-set bit-shift-left bit-shift-right bit-test bit-xor boolean boolean-array booleans bound-fn bound-fn* bound? butlast byte byte-array bytes case cast char char-array char-escape-string char-name-string char? chars chunk chunk-append chunk-buffer chunk-cons chunk-first chunk-next chunk-rest chunked-seq? class class? clear-agent-errors clojure-version coll? comment commute comp comparator compare compare-and-set! compile complement concat cond condp conj conj! cons constantly construct-proxy contains? count counted? create-ns create-struct cycle dec dec' decimal? declare default-data-readers definline definterface defmacro defmethod defmulti defn defn- defonce defprotocol defrecord defstruct deftype delay delay? deliver denominator deref derive descendants destructure disj disj! dissoc dissoc! distinct distinct? doall dorun doseq dosync dotimes doto double double-array doubles drop drop-last drop-while empty empty? ensure enumeration-seq error-handler error-mode eval even? every-pred every? ex-data ex-info extend extend-protocol extend-type extenders extends? false? ffirst file-seq filter filterv find find-keyword find-ns find-protocol-impl find-protocol-method find-var first flatten float float-array float? floats flush fn fn? fnext fnil for force format frequencies future future-call future-cancel future-cancelled? future-done? future? gen-class gen-interface gensym get get-in get-method get-proxy-class get-thread-bindings get-validator group-by hash hash-combine hash-map hash-set identical? identity if-let if-not ifn? import in-ns inc inc' init-proxy instance? int int-array integer? interleave intern interpose into into-array ints io! isa? iterate iterator-seq juxt keep keep-indexed key keys keyword keyword? last lazy-cat lazy-seq let letfn line-seq list list* list? load load-file load-reader load-string loaded-libs locking long long-array longs loop macroexpand macroexpand-1 make-array make-hierarchy map map-indexed map? mapcat mapv max max-key memfn memoize merge merge-with meta method-sig methods min min-key mod munge name namespace namespace-munge neg? newline next nfirst nil? nnext not not-any? not-empty not-every? not= ns ns-aliases ns-imports ns-interns ns-map ns-name ns-publics ns-refers ns-resolve ns-unalias ns-unmap nth nthnext nthrest num number? numerator object-array odd? or parents partial partition partition-all partition-by pcalls peek persistent! pmap pop pop! pop-thread-bindings pos? pr pr-str prefer-method prefers primitives-classnames print print-ctor print-dup print-method print-simple print-str printf println println-str prn prn-str promise proxy proxy-call-with-super proxy-mappings proxy-name proxy-super push-thread-bindings pvalues quot rand rand-int rand-nth range ratio? rational? rationalize re-find re-groups re-matcher re-matches re-pattern re-seq read read-line read-string realized? reduce reduce-kv reductions ref ref-history-count ref-max-history ref-min-history ref-set refer refer-clojure reify release-pending-sends rem remove remove-all-methods remove-method remove-ns remove-watch repeat repeatedly replace replicate require reset! reset-meta! resolve rest restart-agent resultset-seq reverse reversible? rseq rsubseq satisfies? second select-keys send send-off seq seq? seque sequence sequential? set set-error-handler! set-error-mode! set-validator! set? short short-array shorts shuffle shutdown-agents slurp some some-fn sort sort-by sorted-map sorted-map-by sorted-set sorted-set-by sorted? special-symbol? spit split-at split-with str string? struct struct-map subs subseq subvec supers swap! symbol symbol? sync take take-last take-nth take-while test the-ns thread-bound? time to-array to-array-2d trampoline transient tree-seq true? type unchecked-add unchecked-add-int unchecked-byte unchecked-char unchecked-dec unchecked-dec-int unchecked-divide-int unchecked-double unchecked-float unchecked-inc unchecked-inc-int unchecked-int unchecked-long unchecked-multiply unchecked-multiply-int unchecked-negate unchecked-negate-int unchecked-remainder-int unchecked-short unchecked-subtract unchecked-subtract-int underive unquote unquote-splicing update-in update-proxy use val vals var-get var-set var? vary-meta vec vector vector-of vector? when when-first when-let when-not while with-bindings with-bindings* with-in-str with-loading-context with-local-vars with-meta with-open with-out-str with-precision with-redefs with-redefs-fn xml-seq zero? zipmap *default-data-reader-fn* as-> cond-> cond->> reduced reduced? send-via set-agent-send-executor! set-agent-send-off-executor! some-> some->>\");\n\n    var indentKeys = makeKeywords(\n        // Built-ins\n        \"ns fn def defn defmethod bound-fn if if-not case condp when while when-not when-first do future comment doto locking proxy with-open with-precision reify deftype defrecord defprotocol extend extend-protocol extend-type try catch \" +\n\n        // Binding forms\n        \"let letfn binding loop for doseq dotimes when-let if-let \" +\n\n        // Data structures\n        \"defstruct struct-map assoc \" +\n\n        // clojure.test\n        \"testing deftest \" +\n\n        // contrib\n        \"handler-case handle dotrace deftrace\");\n\n    var tests = {\n        digit: /\\d/,\n        digit_or_colon: /[\\d:]/,\n        hex: /[0-9a-f]/i,\n        sign: /[+-]/,\n        exponent: /e/i,\n        keyword_char: /[^\\s\\(\\[\\;\\)\\]]/,\n        symbol: /[\\w*+!\\-\\._?:<>\\/\\xa1-\\uffff]/\n    };\n\n    function stateStack(indent, type, prev) { // represents a state stack object\n        this.indent = indent;\n        this.type = type;\n        this.prev = prev;\n    }\n\n    function pushStack(state, indent, type) {\n        state.indentStack = new stateStack(indent, type, state.indentStack);\n    }\n\n    function popStack(state) {\n        state.indentStack = state.indentStack.prev;\n    }\n\n    function isNumber(ch, stream){\n        // hex\n        if ( ch === '0' && stream.eat(/x/i) ) {\n            stream.eatWhile(tests.hex);\n            return true;\n        }\n\n        // leading sign\n        if ( ( ch == '+' || ch == '-' ) && ( tests.digit.test(stream.peek()) ) ) {\n          stream.eat(tests.sign);\n          ch = stream.next();\n        }\n\n        if ( tests.digit.test(ch) ) {\n            stream.eat(ch);\n            stream.eatWhile(tests.digit);\n\n            if ( '.' == stream.peek() ) {\n                stream.eat('.');\n                stream.eatWhile(tests.digit);\n            }\n\n            if ( stream.eat(tests.exponent) ) {\n                stream.eat(tests.sign);\n                stream.eatWhile(tests.digit);\n            }\n\n            return true;\n        }\n\n        return false;\n    }\n\n    // Eat character that starts after backslash \\\n    function eatCharacter(stream) {\n        var first = stream.next();\n        // Read special literals: backspace, newline, space, return.\n        // Just read all lowercase letters.\n        if (first && first.match(/[a-z]/) && stream.match(/[a-z]+/, true)) {\n            return;\n        }\n        // Read unicode character: \\u1000 \\uA0a1\n        if (first === \"u\") {\n            stream.match(/[0-9a-z]{4}/i, true);\n        }\n    }\n\n    return {\n        startState: function () {\n            return {\n                indentStack: null,\n                indentation: 0,\n                mode: false\n            };\n        },\n\n        token: function (stream, state) {\n            if (state.indentStack == null && stream.sol()) {\n                // update indentation, but only if indentStack is empty\n                state.indentation = stream.indentation();\n            }\n\n            // skip spaces\n            if (stream.eatSpace()) {\n                return null;\n            }\n            var returnType = null;\n\n            switch(state.mode){\n                case \"string\": // multi-line string parsing mode\n                    var next, escaped = false;\n                    while ((next = stream.next()) != null) {\n                        if (next == \"\\\"\" && !escaped) {\n\n                            state.mode = false;\n                            break;\n                        }\n                        escaped = !escaped && next == \"\\\\\";\n                    }\n                    returnType = STRING; // continue on in string mode\n                    break;\n                default: // default parsing mode\n                    var ch = stream.next();\n\n                    if (ch == \"\\\"\") {\n                        state.mode = \"string\";\n                        returnType = STRING;\n                    } else if (ch == \"\\\\\") {\n                        eatCharacter(stream);\n                        returnType = CHARACTER;\n                    } else if (ch == \"'\" && !( tests.digit_or_colon.test(stream.peek()) )) {\n                        returnType = ATOM;\n                    } else if (ch == \";\") { // comment\n                        stream.skipToEnd(); // rest of the line is a comment\n                        returnType = COMMENT;\n                    } else if (isNumber(ch,stream)){\n                        returnType = NUMBER;\n                    } else if (ch == \"(\" || ch == \"[\" || ch == \"{\" ) {\n                        var keyWord = '', indentTemp = stream.column(), letter;\n                        /**\n                        Either\n                        (indent-word ..\n                        (non-indent-word ..\n                        (;something else, bracket, etc.\n                        */\n\n                        if (ch == \"(\") while ((letter = stream.eat(tests.keyword_char)) != null) {\n                            keyWord += letter;\n                        }\n\n                        if (keyWord.length > 0 && (indentKeys.propertyIsEnumerable(keyWord) ||\n                                                   /^(?:def|with)/.test(keyWord))) { // indent-word\n                            pushStack(state, indentTemp + INDENT_WORD_SKIP, ch);\n                        } else { // non-indent word\n                            // we continue eating the spaces\n                            stream.eatSpace();\n                            if (stream.eol() || stream.peek() == \";\") {\n                                // nothing significant after\n                                // we restart indentation the user defined spaces after\n                                pushStack(state, indentTemp + NORMAL_INDENT_UNIT, ch);\n                            } else {\n                                pushStack(state, indentTemp + stream.current().length, ch); // else we match\n                            }\n                        }\n                        stream.backUp(stream.current().length - 1); // undo all the eating\n\n                        returnType = BRACKET;\n                    } else if (ch == \")\" || ch == \"]\" || ch == \"}\") {\n                        returnType = BRACKET;\n                        if (state.indentStack != null && state.indentStack.type == (ch == \")\" ? \"(\" : (ch == \"]\" ? \"[\" :\"{\"))) {\n                            popStack(state);\n                        }\n                    } else if ( ch == \":\" ) {\n                        stream.eatWhile(tests.symbol);\n                        return ATOM;\n                    } else {\n                        stream.eatWhile(tests.symbol);\n\n                        if (keywords && keywords.propertyIsEnumerable(stream.current())) {\n                            returnType = KEYWORD;\n                        } else if (builtins && builtins.propertyIsEnumerable(stream.current())) {\n                            returnType = BUILTIN;\n                        } else if (atoms && atoms.propertyIsEnumerable(stream.current())) {\n                            returnType = ATOM;\n                        } else {\n                          returnType = VAR;\n                        }\n                    }\n            }\n\n            return returnType;\n        },\n\n        indent: function (state) {\n            if (state.indentStack == null) return state.indentation;\n            return state.indentStack.indent;\n        },\n\n        lineComment: \";;\"\n    };\n});\n\nCodeMirror.defineMIME(\"text/x-clojure\", \"clojure\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/clojure/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Clojure mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"clojure.js\"></script>\n<style>.CodeMirror {background: #f8f8f8;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Clojure</a>\n  </ul>\n</div>\n\n<article>\n<h2>Clojure mode</h2>\n<form><textarea id=\"code\" name=\"code\">\n; Conway's Game of Life, based on the work of:\n;; Laurent Petit https://gist.github.com/1200343\n;; Christophe Grand http://clj-me.cgrand.net/2011/08/19/conways-game-of-life\n\n(ns ^{:doc \"Conway's Game of Life.\"}\n game-of-life)\n\n;; Core game of life's algorithm functions\n\n(defn neighbours\n  \"Given a cell's coordinates, returns the coordinates of its neighbours.\"\n  [[x y]]\n  (for [dx [-1 0 1] dy (if (zero? dx) [-1 1] [-1 0 1])]\n    [(+ dx x) (+ dy y)]))\n\n(defn step\n  \"Given a set of living cells, computes the new set of living cells.\"\n  [cells]\n  (set (for [[cell n] (frequencies (mapcat neighbours cells))\n             :when (or (= n 3) (and (= n 2) (cells cell)))]\n         cell)))\n\n;; Utility methods for displaying game on a text terminal\n\n(defn print-board\n  \"Prints a board on *out*, representing a step in the game.\"\n  [board w h]\n  (doseq [x (range (inc w)) y (range (inc h))]\n    (if (= y 0) (print \"\\n\"))\n    (print (if (board [x y]) \"[X]\" \" . \"))))\n\n(defn display-grids\n  \"Prints a squence of boards on *out*, representing several steps.\"\n  [grids w h]\n  (doseq [board grids]\n    (print-board board w h)\n    (print \"\\n\")))\n\n;; Launches an example board\n\n(def\n  ^{:doc \"board represents the initial set of living cells\"}\n   board #{[2 1] [2 2] [2 3]})\n\n(display-grids (take 3 (iterate step board)) 5 5)\n\n;; Let's play with characters\n(println \\1 \\a \\# \\\\\n         \\\" \\( \\newline\n         \\} \\\" \\space\n         \\tab \\return \\backspace\n         \\u1000 \\uAaAa \\u9F9F)\n\n</textarea></form>\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {});\n    </script>\n\n    <p><strong>MIME types defined:</strong> <code>text/x-clojure</code>.</p>\n\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/cobol/cobol.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n/**\n * Author: Gautam Mehta\n * Branched from CodeMirror's Scheme mode\n */\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"cobol\", function () {\n  var BUILTIN = \"builtin\", COMMENT = \"comment\", STRING = \"string\",\n      ATOM = \"atom\", NUMBER = \"number\", KEYWORD = \"keyword\", MODTAG = \"header\",\n      COBOLLINENUM = \"def\", PERIOD = \"link\";\n  function makeKeywords(str) {\n    var obj = {}, words = str.split(\" \");\n    for (var i = 0; i < words.length; ++i) obj[words[i]] = true;\n    return obj;\n  }\n  var atoms = makeKeywords(\"TRUE FALSE ZEROES ZEROS ZERO SPACES SPACE LOW-VALUE LOW-VALUES \");\n  var keywords = makeKeywords(\n      \"ACCEPT ACCESS ACQUIRE ADD ADDRESS \" +\n      \"ADVANCING AFTER ALIAS ALL ALPHABET \" +\n      \"ALPHABETIC ALPHABETIC-LOWER ALPHABETIC-UPPER ALPHANUMERIC ALPHANUMERIC-EDITED \" +\n      \"ALSO ALTER ALTERNATE AND ANY \" +\n      \"ARE AREA AREAS ARITHMETIC ASCENDING \" +\n      \"ASSIGN AT ATTRIBUTE AUTHOR AUTO \" +\n      \"AUTO-SKIP AUTOMATIC B-AND B-EXOR B-LESS \" +\n      \"B-NOT B-OR BACKGROUND-COLOR BACKGROUND-COLOUR BEEP \" +\n      \"BEFORE BELL BINARY BIT BITS \" +\n      \"BLANK BLINK BLOCK BOOLEAN BOTTOM \" +\n      \"BY CALL CANCEL CD CF \" +\n      \"CH CHARACTER CHARACTERS CLASS CLOCK-UNITS \" +\n      \"CLOSE COBOL CODE CODE-SET COL \" +\n      \"COLLATING COLUMN COMMA COMMIT COMMITMENT \" +\n      \"COMMON COMMUNICATION COMP COMP-0 COMP-1 \" +\n      \"COMP-2 COMP-3 COMP-4 COMP-5 COMP-6 \" +\n      \"COMP-7 COMP-8 COMP-9 COMPUTATIONAL COMPUTATIONAL-0 \" +\n      \"COMPUTATIONAL-1 COMPUTATIONAL-2 COMPUTATIONAL-3 COMPUTATIONAL-4 COMPUTATIONAL-5 \" +\n      \"COMPUTATIONAL-6 COMPUTATIONAL-7 COMPUTATIONAL-8 COMPUTATIONAL-9 COMPUTE \" +\n      \"CONFIGURATION CONNECT CONSOLE CONTAINED CONTAINS \" +\n      \"CONTENT CONTINUE CONTROL CONTROL-AREA CONTROLS \" +\n      \"CONVERTING COPY CORR CORRESPONDING COUNT \" +\n      \"CRT CRT-UNDER CURRENCY CURRENT CURSOR \" +\n      \"DATA DATE DATE-COMPILED DATE-WRITTEN DAY \" +\n      \"DAY-OF-WEEK DB DB-ACCESS-CONTROL-KEY DB-DATA-NAME DB-EXCEPTION \" +\n      \"DB-FORMAT-NAME DB-RECORD-NAME DB-SET-NAME DB-STATUS DBCS \" +\n      \"DBCS-EDITED DE DEBUG-CONTENTS DEBUG-ITEM DEBUG-LINE \" +\n      \"DEBUG-NAME DEBUG-SUB-1 DEBUG-SUB-2 DEBUG-SUB-3 DEBUGGING \" +\n      \"DECIMAL-POINT DECLARATIVES DEFAULT DELETE DELIMITED \" +\n      \"DELIMITER DEPENDING DESCENDING DESCRIBED DESTINATION \" +\n      \"DETAIL DISABLE DISCONNECT DISPLAY DISPLAY-1 \" +\n      \"DISPLAY-2 DISPLAY-3 DISPLAY-4 DISPLAY-5 DISPLAY-6 \" +\n      \"DISPLAY-7 DISPLAY-8 DISPLAY-9 DIVIDE DIVISION \" +\n      \"DOWN DROP DUPLICATE DUPLICATES DYNAMIC \" +\n      \"EBCDIC EGI EJECT ELSE EMI \" +\n      \"EMPTY EMPTY-CHECK ENABLE END END. END-ACCEPT END-ACCEPT. \" +\n      \"END-ADD END-CALL END-COMPUTE END-DELETE END-DISPLAY \" +\n      \"END-DIVIDE END-EVALUATE END-IF END-INVOKE END-MULTIPLY \" +\n      \"END-OF-PAGE END-PERFORM END-READ END-RECEIVE END-RETURN \" +\n      \"END-REWRITE END-SEARCH END-START END-STRING END-SUBTRACT \" +\n      \"END-UNSTRING END-WRITE END-XML ENTER ENTRY \" +\n      \"ENVIRONMENT EOP EQUAL EQUALS ERASE \" +\n      \"ERROR ESI EVALUATE EVERY EXCEEDS \" +\n      \"EXCEPTION EXCLUSIVE EXIT EXTEND EXTERNAL \" +\n      \"EXTERNALLY-DESCRIBED-KEY FD FETCH FILE FILE-CONTROL \" +\n      \"FILE-STREAM FILES FILLER FINAL FIND \" +\n      \"FINISH FIRST FOOTING FOR FOREGROUND-COLOR \" +\n      \"FOREGROUND-COLOUR FORMAT FREE FROM FULL \" +\n      \"FUNCTION GENERATE GET GIVING GLOBAL \" +\n      \"GO GOBACK GREATER GROUP HEADING \" +\n      \"HIGH-VALUE HIGH-VALUES HIGHLIGHT I-O I-O-CONTROL \" +\n      \"ID IDENTIFICATION IF IN INDEX \" +\n      \"INDEX-1 INDEX-2 INDEX-3 INDEX-4 INDEX-5 \" +\n      \"INDEX-6 INDEX-7 INDEX-8 INDEX-9 INDEXED \" +\n      \"INDIC INDICATE INDICATOR INDICATORS INITIAL \" +\n      \"INITIALIZE INITIATE INPUT INPUT-OUTPUT INSPECT \" +\n      \"INSTALLATION INTO INVALID INVOKE IS \" +\n      \"JUST JUSTIFIED KANJI KEEP KEY \" +\n      \"LABEL LAST LD LEADING LEFT \" +\n      \"LEFT-JUSTIFY LENGTH LENGTH-CHECK LESS LIBRARY \" +\n      \"LIKE LIMIT LIMITS LINAGE LINAGE-COUNTER \" +\n      \"LINE LINE-COUNTER LINES LINKAGE LOCAL-STORAGE \" +\n      \"LOCALE LOCALLY LOCK \" +\n      \"MEMBER MEMORY MERGE MESSAGE METACLASS \" +\n      \"MODE MODIFIED MODIFY MODULES MOVE \" +\n      \"MULTIPLE MULTIPLY NATIONAL NATIVE NEGATIVE \" +\n      \"NEXT NO NO-ECHO NONE NOT \" +\n      \"NULL NULL-KEY-MAP NULL-MAP NULLS NUMBER \" +\n      \"NUMERIC NUMERIC-EDITED OBJECT OBJECT-COMPUTER OCCURS \" +\n      \"OF OFF OMITTED ON ONLY \" +\n      \"OPEN OPTIONAL OR ORDER ORGANIZATION \" +\n      \"OTHER OUTPUT OVERFLOW OWNER PACKED-DECIMAL \" +\n      \"PADDING PAGE PAGE-COUNTER PARSE PERFORM \" +\n      \"PF PH PIC PICTURE PLUS \" +\n      \"POINTER POSITION POSITIVE PREFIX PRESENT \" +\n      \"PRINTING PRIOR PROCEDURE PROCEDURE-POINTER PROCEDURES \" +\n      \"PROCEED PROCESS PROCESSING PROGRAM PROGRAM-ID \" +\n      \"PROMPT PROTECTED PURGE QUEUE QUOTE \" +\n      \"QUOTES RANDOM RD READ READY \" +\n      \"REALM RECEIVE RECONNECT RECORD RECORD-NAME \" +\n      \"RECORDS RECURSIVE REDEFINES REEL REFERENCE \" +\n      \"REFERENCE-MONITOR REFERENCES RELATION RELATIVE RELEASE \" +\n      \"REMAINDER REMOVAL RENAMES REPEATED REPLACE \" +\n      \"REPLACING REPORT REPORTING REPORTS REPOSITORY \" +\n      \"REQUIRED RERUN RESERVE RESET RETAINING \" +\n      \"RETRIEVAL RETURN RETURN-CODE RETURNING REVERSE-VIDEO \" +\n      \"REVERSED REWIND REWRITE RF RH \" +\n      \"RIGHT RIGHT-JUSTIFY ROLLBACK ROLLING ROUNDED \" +\n      \"RUN SAME SCREEN SD SEARCH \" +\n      \"SECTION SECURE SECURITY SEGMENT SEGMENT-LIMIT \" +\n      \"SELECT SEND SENTENCE SEPARATE SEQUENCE \" +\n      \"SEQUENTIAL SET SHARED SIGN SIZE \" +\n      \"SKIP1 SKIP2 SKIP3 SORT SORT-MERGE \" +\n      \"SORT-RETURN SOURCE SOURCE-COMPUTER SPACE-FILL \" +\n      \"SPECIAL-NAMES STANDARD STANDARD-1 STANDARD-2 \" +\n      \"START STARTING STATUS STOP STORE \" +\n      \"STRING SUB-QUEUE-1 SUB-QUEUE-2 SUB-QUEUE-3 SUB-SCHEMA \" +\n      \"SUBFILE SUBSTITUTE SUBTRACT SUM SUPPRESS \" +\n      \"SYMBOLIC SYNC SYNCHRONIZED SYSIN SYSOUT \" +\n      \"TABLE TALLYING TAPE TENANT TERMINAL \" +\n      \"TERMINATE TEST TEXT THAN THEN \" +\n      \"THROUGH THRU TIME TIMES TITLE \" +\n      \"TO TOP TRAILING TRAILING-SIGN TRANSACTION \" +\n      \"TYPE TYPEDEF UNDERLINE UNEQUAL UNIT \" +\n      \"UNSTRING UNTIL UP UPDATE UPON \" +\n      \"USAGE USAGE-MODE USE USING VALID \" +\n      \"VALIDATE VALUE VALUES VARYING VLR \" +\n      \"WAIT WHEN WHEN-COMPILED WITH WITHIN \" +\n      \"WORDS WORKING-STORAGE WRITE XML XML-CODE \" +\n      \"XML-EVENT XML-NTEXT XML-TEXT ZERO ZERO-FILL \" );\n\n  var builtins = makeKeywords(\"- * ** / + < <= = > >= \");\n  var tests = {\n    digit: /\\d/,\n    digit_or_colon: /[\\d:]/,\n    hex: /[0-9a-f]/i,\n    sign: /[+-]/,\n    exponent: /e/i,\n    keyword_char: /[^\\s\\(\\[\\;\\)\\]]/,\n    symbol: /[\\w*+\\-]/\n  };\n  function isNumber(ch, stream){\n    // hex\n    if ( ch === '0' && stream.eat(/x/i) ) {\n      stream.eatWhile(tests.hex);\n      return true;\n    }\n    // leading sign\n    if ( ( ch == '+' || ch == '-' ) && ( tests.digit.test(stream.peek()) ) ) {\n      stream.eat(tests.sign);\n      ch = stream.next();\n    }\n    if ( tests.digit.test(ch) ) {\n      stream.eat(ch);\n      stream.eatWhile(tests.digit);\n      if ( '.' == stream.peek()) {\n        stream.eat('.');\n        stream.eatWhile(tests.digit);\n      }\n      if ( stream.eat(tests.exponent) ) {\n        stream.eat(tests.sign);\n        stream.eatWhile(tests.digit);\n      }\n      return true;\n    }\n    return false;\n  }\n  return {\n    startState: function () {\n      return {\n        indentStack: null,\n        indentation: 0,\n        mode: false\n      };\n    },\n    token: function (stream, state) {\n      if (state.indentStack == null && stream.sol()) {\n        // update indentation, but only if indentStack is empty\n        state.indentation = 6 ; //stream.indentation();\n      }\n      // skip spaces\n      if (stream.eatSpace()) {\n        return null;\n      }\n      var returnType = null;\n      switch(state.mode){\n      case \"string\": // multi-line string parsing mode\n        var next = false;\n        while ((next = stream.next()) != null) {\n          if (next == \"\\\"\" || next == \"\\'\") {\n            state.mode = false;\n            break;\n          }\n        }\n        returnType = STRING; // continue on in string mode\n        break;\n      default: // default parsing mode\n        var ch = stream.next();\n        var col = stream.column();\n        if (col >= 0 && col <= 5) {\n          returnType = COBOLLINENUM;\n        } else if (col >= 72 && col <= 79) {\n          stream.skipToEnd();\n          returnType = MODTAG;\n        } else if (ch == \"*\" && col == 6) { // comment\n          stream.skipToEnd(); // rest of the line is a comment\n          returnType = COMMENT;\n        } else if (ch == \"\\\"\" || ch == \"\\'\") {\n          state.mode = \"string\";\n          returnType = STRING;\n        } else if (ch == \"'\" && !( tests.digit_or_colon.test(stream.peek()) )) {\n          returnType = ATOM;\n        } else if (ch == \".\") {\n          returnType = PERIOD;\n        } else if (isNumber(ch,stream)){\n          returnType = NUMBER;\n        } else {\n          if (stream.current().match(tests.symbol)) {\n            while (col < 71) {\n              if (stream.eat(tests.symbol) === undefined) {\n                break;\n              } else {\n                col++;\n              }\n            }\n          }\n          if (keywords && keywords.propertyIsEnumerable(stream.current().toUpperCase())) {\n            returnType = KEYWORD;\n          } else if (builtins && builtins.propertyIsEnumerable(stream.current().toUpperCase())) {\n            returnType = BUILTIN;\n          } else if (atoms && atoms.propertyIsEnumerable(stream.current().toUpperCase())) {\n            returnType = ATOM;\n          } else returnType = null;\n        }\n      }\n      return returnType;\n    },\n    indent: function (state) {\n      if (state.indentStack == null) return state.indentation;\n      return state.indentStack.indent;\n    }\n  };\n});\n\nCodeMirror.defineMIME(\"text/x-cobol\", \"cobol\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/cobol/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: COBOL mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<link rel=\"stylesheet\" href=\"../../theme/neat.css\">\n<link rel=\"stylesheet\" href=\"../../theme/elegant.css\">\n<link rel=\"stylesheet\" href=\"../../theme/erlang-dark.css\">\n<link rel=\"stylesheet\" href=\"../../theme/night.css\">\n<link rel=\"stylesheet\" href=\"../../theme/monokai.css\">\n<link rel=\"stylesheet\" href=\"../../theme/cobalt.css\">\n<link rel=\"stylesheet\" href=\"../../theme/eclipse.css\">\n<link rel=\"stylesheet\" href=\"../../theme/rubyblue.css\">\n<link rel=\"stylesheet\" href=\"../../theme/lesser-dark.css\">\n<link rel=\"stylesheet\" href=\"../../theme/xq-dark.css\">\n<link rel=\"stylesheet\" href=\"../../theme/xq-light.css\">\n<link rel=\"stylesheet\" href=\"../../theme/ambiance.css\">\n<link rel=\"stylesheet\" href=\"../../theme/blackboard.css\">\n<link rel=\"stylesheet\" href=\"../../theme/vibrant-ink.css\">\n<link rel=\"stylesheet\" href=\"../../theme/solarized.css\">\n<link rel=\"stylesheet\" href=\"../../theme/twilight.css\">\n<link rel=\"stylesheet\" href=\"../../theme/midnight.css\">\n<link rel=\"stylesheet\" href=\"../../addon/dialog/dialog.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"../../addon/edit/matchbrackets.js\"></script>\n<script src=\"cobol.js\"></script>\n<script src=\"../../addon/selection/active-line.js\"></script>\n<script src=\"../../addon/search/search.js\"></script>\n<script src=\"../../addon/dialog/dialog.js\"></script>\n<script src=\"../../addon/search/searchcursor.js\"></script>\n<style>\n        .CodeMirror {\n          border: 1px solid #eee;\n          font-size : 20px;\n          height : auto !important;\n        }\n        .CodeMirror-activeline-background {background: #555555 !important;}\n    </style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">COBOL</a>\n  </ul>\n</div>\n\n<article>\n<h2>COBOL mode</h2>\n\n    <p> Select Theme <select onchange=\"selectTheme()\" id=\"selectTheme\">\n        <option>default</option>\n        <option>ambiance</option>\n        <option>blackboard</option>\n        <option>cobalt</option>\n        <option>eclipse</option>\n        <option>elegant</option>\n        <option>erlang-dark</option>\n        <option>lesser-dark</option>\n        <option>midnight</option>\n        <option>monokai</option>\n        <option>neat</option>\n        <option>night</option>\n        <option>rubyblue</option>\n        <option>solarized dark</option>\n        <option>solarized light</option>\n        <option selected>twilight</option>\n        <option>vibrant-ink</option>\n        <option>xq-dark</option>\n        <option>xq-light</option>\n    </select>    Select Font Size <select onchange=\"selectFontsize()\" id=\"selectFontSize\">\n          <option value=\"13px\">13px</option>\n          <option value=\"14px\">14px</option>\n          <option value=\"16px\">16px</option>\n          <option value=\"18px\">18px</option>\n          <option value=\"20px\" selected=\"selected\">20px</option>\n          <option value=\"24px\">24px</option>\n          <option value=\"26px\">26px</option>\n          <option value=\"28px\">28px</option>\n          <option value=\"30px\">30px</option>\n          <option value=\"32px\">32px</option>\n          <option value=\"34px\">34px</option>\n          <option value=\"36px\">36px</option>\n        </select>\n<label for=\"checkBoxReadOnly\">Read-only</label>\n<input type=\"checkbox\" id=\"checkBoxReadOnly\" onchange=\"selectReadOnly()\">\n<label for=\"id_tabToIndentSpace\">Insert Spaces on Tab</label>\n<input type=\"checkbox\" id=\"id_tabToIndentSpace\" onchange=\"tabToIndentSpace()\">\n</p>\n<textarea id=\"code\" name=\"code\">\n---------1---------2---------3---------4---------5---------6---------7---------8\n12345678911234567892123456789312345678941234567895123456789612345678971234567898\n000010 IDENTIFICATION DIVISION.                                        MODTGHERE\n000020 PROGRAM-ID.       SAMPLE.\n000030 AUTHOR.           TEST SAM. \n000040 DATE-WRITTEN.     5 February 2013\n000041\n000042* A sample program just to show the form.\n000043* The program copies its input to the output,\n000044* and counts the number of records.\n000045* At the end this number is printed.\n000046\n000050 ENVIRONMENT DIVISION.\n000060 INPUT-OUTPUT SECTION.\n000070 FILE-CONTROL.\n000080     SELECT STUDENT-FILE     ASSIGN TO SYSIN\n000090         ORGANIZATION IS LINE SEQUENTIAL.\n000100     SELECT PRINT-FILE       ASSIGN TO SYSOUT\n000110         ORGANIZATION IS LINE SEQUENTIAL.\n000120\n000130 DATA DIVISION.\n000140 FILE SECTION.\n000150 FD  STUDENT-FILE\n000160     RECORD CONTAINS 43 CHARACTERS\n000170     DATA RECORD IS STUDENT-IN.\n000180 01  STUDENT-IN              PIC X(43).\n000190\n000200 FD  PRINT-FILE\n000210     RECORD CONTAINS 80 CHARACTERS\n000220     DATA RECORD IS PRINT-LINE.\n000230 01  PRINT-LINE              PIC X(80).\n000240\n000250 WORKING-STORAGE SECTION.\n000260 01  DATA-REMAINS-SWITCH     PIC X(2)      VALUE SPACES.\n000261 01  RECORDS-WRITTEN         PIC 99.\n000270\n000280 01  DETAIL-LINE.\n000290     05  FILLER              PIC X(7)      VALUE SPACES.\n000300     05  RECORD-IMAGE        PIC X(43).\n000310     05  FILLER              PIC X(30)     VALUE SPACES.\n000311 \n000312 01  SUMMARY-LINE.\n000313     05  FILLER              PIC X(7)      VALUE SPACES.\n000314     05  TOTAL-READ          PIC 99.\n000315     05  FILLER              PIC X         VALUE SPACE.\n000316     05  FILLER              PIC X(17)     \n000317                 VALUE  'Records were read'.\n000318     05  FILLER              PIC X(53)     VALUE SPACES.\n000319\n000320 PROCEDURE DIVISION.\n000321\n000330 PREPARE-SENIOR-REPORT.\n000340     OPEN INPUT  STUDENT-FILE\n000350          OUTPUT PRINT-FILE.\n000351     MOVE ZERO TO RECORDS-WRITTEN.\n000360     READ STUDENT-FILE\n000370         AT END MOVE 'NO' TO DATA-REMAINS-SWITCH\n000380     END-READ.\n000390     PERFORM PROCESS-RECORDS\n000410         UNTIL DATA-REMAINS-SWITCH = 'NO'.\n000411     PERFORM PRINT-SUMMARY.\n000420     CLOSE STUDENT-FILE\n000430           PRINT-FILE.\n000440     STOP RUN.\n000450\n000460 PROCESS-RECORDS.\n000470     MOVE STUDENT-IN TO RECORD-IMAGE.\n000480     MOVE DETAIL-LINE TO PRINT-LINE.\n000490     WRITE PRINT-LINE.\n000500     ADD 1 TO RECORDS-WRITTEN.\n000510     READ STUDENT-FILE\n000520         AT END MOVE 'NO' TO DATA-REMAINS-SWITCH\n000530     END-READ. \n000540\n000550 PRINT-SUMMARY.\n000560     MOVE RECORDS-WRITTEN TO TOTAL-READ.\n000570     MOVE SUMMARY-LINE TO PRINT-LINE.\n000571     WRITE PRINT-LINE. \n000572\n000580\n</textarea>\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        lineNumbers: true,\n        matchBrackets: true,\n        mode: \"text/x-cobol\",\n        theme : \"twilight\",\n        styleActiveLine: true,\n        showCursorWhenSelecting : true,  \n      });\n      function selectTheme() {\n        var themeInput = document.getElementById(\"selectTheme\");\n        var theme = themeInput.options[themeInput.selectedIndex].innerHTML;\n        editor.setOption(\"theme\", theme);\n      }\n      function selectFontsize() {\n        var fontSizeInput = document.getElementById(\"selectFontSize\");\n        var fontSize = fontSizeInput.options[fontSizeInput.selectedIndex].innerHTML;\n        editor.getWrapperElement().style.fontSize = fontSize;\n        editor.refresh();\n      }\n      function selectReadOnly() {\n        editor.setOption(\"readOnly\", document.getElementById(\"checkBoxReadOnly\").checked);\n      }\n      function tabToIndentSpace() {\n        if (document.getElementById(\"id_tabToIndentSpace\").checked) {\n            editor.setOption(\"extraKeys\", {Tab: function(cm) { cm.replaceSelection(\"    \", \"end\"); }});\n        } else {\n            editor.setOption(\"extraKeys\", {Tab: function(cm) { cm.replaceSelection(\"    \", \"end\"); }});\n        }\n      }\n    </script>\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/coffeescript/coffeescript.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n/**\n * Link to the project's GitHub page:\n * https://github.com/pickhardt/coffeescript-codemirror-mode\n */\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"coffeescript\", function(conf, parserConf) {\n  var ERRORCLASS = \"error\";\n\n  function wordRegexp(words) {\n    return new RegExp(\"^((\" + words.join(\")|(\") + \"))\\\\b\");\n  }\n\n  var operators = /^(?:->|=>|\\+[+=]?|-[\\-=]?|\\*[\\*=]?|\\/[\\/=]?|[=!]=|<[><]?=?|>>?=?|%=?|&=?|\\|=?|\\^=?|\\~|!|\\?|(or|and|\\|\\||&&|\\?)=)/;\n  var delimiters = /^(?:[()\\[\\]{},:`=;]|\\.\\.?\\.?)/;\n  var identifiers = /^[_A-Za-z$][_A-Za-z$0-9]*/;\n  var properties = /^(@|this\\.)[_A-Za-z$][_A-Za-z$0-9]*/;\n\n  var wordOperators = wordRegexp([\"and\", \"or\", \"not\",\n                                  \"is\", \"isnt\", \"in\",\n                                  \"instanceof\", \"typeof\"]);\n  var indentKeywords = [\"for\", \"while\", \"loop\", \"if\", \"unless\", \"else\",\n                        \"switch\", \"try\", \"catch\", \"finally\", \"class\"];\n  var commonKeywords = [\"break\", \"by\", \"continue\", \"debugger\", \"delete\",\n                        \"do\", \"in\", \"of\", \"new\", \"return\", \"then\",\n                        \"this\", \"@\", \"throw\", \"when\", \"until\", \"extends\"];\n\n  var keywords = wordRegexp(indentKeywords.concat(commonKeywords));\n\n  indentKeywords = wordRegexp(indentKeywords);\n\n\n  var stringPrefixes = /^('{3}|\\\"{3}|['\\\"])/;\n  var regexPrefixes = /^(\\/{3}|\\/)/;\n  var commonConstants = [\"Infinity\", \"NaN\", \"undefined\", \"null\", \"true\", \"false\", \"on\", \"off\", \"yes\", \"no\"];\n  var constants = wordRegexp(commonConstants);\n\n  // Tokenizers\n  function tokenBase(stream, state) {\n    // Handle scope changes\n    if (stream.sol()) {\n      if (state.scope.align === null) state.scope.align = false;\n      var scopeOffset = state.scope.offset;\n      if (stream.eatSpace()) {\n        var lineOffset = stream.indentation();\n        if (lineOffset > scopeOffset && state.scope.type == \"coffee\") {\n          return \"indent\";\n        } else if (lineOffset < scopeOffset) {\n          return \"dedent\";\n        }\n        return null;\n      } else {\n        if (scopeOffset > 0) {\n          dedent(stream, state);\n        }\n      }\n    }\n    if (stream.eatSpace()) {\n      return null;\n    }\n\n    var ch = stream.peek();\n\n    // Handle docco title comment (single line)\n    if (stream.match(\"####\")) {\n      stream.skipToEnd();\n      return \"comment\";\n    }\n\n    // Handle multi line comments\n    if (stream.match(\"###\")) {\n      state.tokenize = longComment;\n      return state.tokenize(stream, state);\n    }\n\n    // Single line comment\n    if (ch === \"#\") {\n      stream.skipToEnd();\n      return \"comment\";\n    }\n\n    // Handle number literals\n    if (stream.match(/^-?[0-9\\.]/, false)) {\n      var floatLiteral = false;\n      // Floats\n      if (stream.match(/^-?\\d*\\.\\d+(e[\\+\\-]?\\d+)?/i)) {\n        floatLiteral = true;\n      }\n      if (stream.match(/^-?\\d+\\.\\d*/)) {\n        floatLiteral = true;\n      }\n      if (stream.match(/^-?\\.\\d+/)) {\n        floatLiteral = true;\n      }\n\n      if (floatLiteral) {\n        // prevent from getting extra . on 1..\n        if (stream.peek() == \".\"){\n          stream.backUp(1);\n        }\n        return \"number\";\n      }\n      // Integers\n      var intLiteral = false;\n      // Hex\n      if (stream.match(/^-?0x[0-9a-f]+/i)) {\n        intLiteral = true;\n      }\n      // Decimal\n      if (stream.match(/^-?[1-9]\\d*(e[\\+\\-]?\\d+)?/)) {\n        intLiteral = true;\n      }\n      // Zero by itself with no other piece of number.\n      if (stream.match(/^-?0(?![\\dx])/i)) {\n        intLiteral = true;\n      }\n      if (intLiteral) {\n        return \"number\";\n      }\n    }\n\n    // Handle strings\n    if (stream.match(stringPrefixes)) {\n      state.tokenize = tokenFactory(stream.current(), false, \"string\");\n      return state.tokenize(stream, state);\n    }\n    // Handle regex literals\n    if (stream.match(regexPrefixes)) {\n      if (stream.current() != \"/\" || stream.match(/^.*\\//, false)) { // prevent highlight of division\n        state.tokenize = tokenFactory(stream.current(), true, \"string-2\");\n        return state.tokenize(stream, state);\n      } else {\n        stream.backUp(1);\n      }\n    }\n\n    // Handle operators and delimiters\n    if (stream.match(operators) || stream.match(wordOperators)) {\n      return \"operator\";\n    }\n    if (stream.match(delimiters)) {\n      return \"punctuation\";\n    }\n\n    if (stream.match(constants)) {\n      return \"atom\";\n    }\n\n    if (stream.match(keywords)) {\n      return \"keyword\";\n    }\n\n    if (stream.match(identifiers)) {\n      return \"variable\";\n    }\n\n    if (stream.match(properties)) {\n      return \"property\";\n    }\n\n    // Handle non-detected items\n    stream.next();\n    return ERRORCLASS;\n  }\n\n  function tokenFactory(delimiter, singleline, outclass) {\n    return function(stream, state) {\n      while (!stream.eol()) {\n        stream.eatWhile(/[^'\"\\/\\\\]/);\n        if (stream.eat(\"\\\\\")) {\n          stream.next();\n          if (singleline && stream.eol()) {\n            return outclass;\n          }\n        } else if (stream.match(delimiter)) {\n          state.tokenize = tokenBase;\n          return outclass;\n        } else {\n          stream.eat(/['\"\\/]/);\n        }\n      }\n      if (singleline) {\n        if (parserConf.singleLineStringErrors) {\n          outclass = ERRORCLASS;\n        } else {\n          state.tokenize = tokenBase;\n        }\n      }\n      return outclass;\n    };\n  }\n\n  function longComment(stream, state) {\n    while (!stream.eol()) {\n      stream.eatWhile(/[^#]/);\n      if (stream.match(\"###\")) {\n        state.tokenize = tokenBase;\n        break;\n      }\n      stream.eatWhile(\"#\");\n    }\n    return \"comment\";\n  }\n\n  function indent(stream, state, type) {\n    type = type || \"coffee\";\n    var offset = 0, align = false, alignOffset = null;\n    for (var scope = state.scope; scope; scope = scope.prev) {\n      if (scope.type === \"coffee\" || scope.type == \"}\") {\n        offset = scope.offset + conf.indentUnit;\n        break;\n      }\n    }\n    if (type !== \"coffee\") {\n      align = null;\n      alignOffset = stream.column() + stream.current().length;\n    } else if (state.scope.align) {\n      state.scope.align = false;\n    }\n    state.scope = {\n      offset: offset,\n      type: type,\n      prev: state.scope,\n      align: align,\n      alignOffset: alignOffset\n    };\n  }\n\n  function dedent(stream, state) {\n    if (!state.scope.prev) return;\n    if (state.scope.type === \"coffee\") {\n      var _indent = stream.indentation();\n      var matched = false;\n      for (var scope = state.scope; scope; scope = scope.prev) {\n        if (_indent === scope.offset) {\n          matched = true;\n          break;\n        }\n      }\n      if (!matched) {\n        return true;\n      }\n      while (state.scope.prev && state.scope.offset !== _indent) {\n        state.scope = state.scope.prev;\n      }\n      return false;\n    } else {\n      state.scope = state.scope.prev;\n      return false;\n    }\n  }\n\n  function tokenLexer(stream, state) {\n    var style = state.tokenize(stream, state);\n    var current = stream.current();\n\n    // Handle \".\" connected identifiers\n    if (current === \".\") {\n      style = state.tokenize(stream, state);\n      current = stream.current();\n      if (/^\\.[\\w$]+$/.test(current)) {\n        return \"variable\";\n      } else {\n        return ERRORCLASS;\n      }\n    }\n\n    // Handle scope changes.\n    if (current === \"return\") {\n      state.dedent = true;\n    }\n    if (((current === \"->\" || current === \"=>\") &&\n         !state.lambda &&\n         !stream.peek())\n        || style === \"indent\") {\n      indent(stream, state);\n    }\n    var delimiter_index = \"[({\".indexOf(current);\n    if (delimiter_index !== -1) {\n      indent(stream, state, \"])}\".slice(delimiter_index, delimiter_index+1));\n    }\n    if (indentKeywords.exec(current)){\n      indent(stream, state);\n    }\n    if (current == \"then\"){\n      dedent(stream, state);\n    }\n\n\n    if (style === \"dedent\") {\n      if (dedent(stream, state)) {\n        return ERRORCLASS;\n      }\n    }\n    delimiter_index = \"])}\".indexOf(current);\n    if (delimiter_index !== -1) {\n      while (state.scope.type == \"coffee\" && state.scope.prev)\n        state.scope = state.scope.prev;\n      if (state.scope.type == current)\n        state.scope = state.scope.prev;\n    }\n    if (state.dedent && stream.eol()) {\n      if (state.scope.type == \"coffee\" && state.scope.prev)\n        state.scope = state.scope.prev;\n      state.dedent = false;\n    }\n\n    return style;\n  }\n\n  var external = {\n    startState: function(basecolumn) {\n      return {\n        tokenize: tokenBase,\n        scope: {offset:basecolumn || 0, type:\"coffee\", prev: null, align: false},\n        lastToken: null,\n        lambda: false,\n        dedent: 0\n      };\n    },\n\n    token: function(stream, state) {\n      var fillAlign = state.scope.align === null && state.scope;\n      if (fillAlign && stream.sol()) fillAlign.align = false;\n\n      var style = tokenLexer(stream, state);\n      if (fillAlign && style && style != \"comment\") fillAlign.align = true;\n\n      state.lastToken = {style:style, content: stream.current()};\n\n      if (stream.eol() && stream.lambda) {\n        state.lambda = false;\n      }\n\n      return style;\n    },\n\n    indent: function(state, text) {\n      if (state.tokenize != tokenBase) return 0;\n      var scope = state.scope;\n      var closer = text && \"])}\".indexOf(text.charAt(0)) > -1;\n      if (closer) while (scope.type == \"coffee\" && scope.prev) scope = scope.prev;\n      var closes = closer && scope.type === text.charAt(0);\n      if (scope.align)\n        return scope.alignOffset - (closes ? 1 : 0);\n      else\n        return (closes ? scope.prev : scope).offset;\n    },\n\n    lineComment: \"#\",\n    fold: \"indent\"\n  };\n  return external;\n});\n\nCodeMirror.defineMIME(\"text/x-coffeescript\", \"coffeescript\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/coffeescript/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: CoffeeScript mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"coffeescript.js\"></script>\n<style>.CodeMirror {border-top: 1px solid silver; border-bottom: 1px solid silver;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">CoffeeScript</a>\n  </ul>\n</div>\n\n<article>\n<h2>CoffeeScript mode</h2>\n<form><textarea id=\"code\" name=\"code\">\n# CoffeeScript mode for CodeMirror\n# Copyright (c) 2011 Jeff Pickhardt, released under\n# the MIT License.\n#\n# Modified from the Python CodeMirror mode, which also is \n# under the MIT License Copyright (c) 2010 Timothy Farrell.\n#\n# The following script, Underscore.coffee, is used to \n# demonstrate CoffeeScript mode for CodeMirror.\n#\n# To download CoffeeScript mode for CodeMirror, go to:\n# https://github.com/pickhardt/coffeescript-codemirror-mode\n\n# **Underscore.coffee\n# (c) 2011 Jeremy Ashkenas, DocumentCloud Inc.**\n# Underscore is freely distributable under the terms of the\n# [MIT license](http://en.wikipedia.org/wiki/MIT_License).\n# Portions of Underscore are inspired by or borrowed from\n# [Prototype.js](http://prototypejs.org/api), Oliver Steele's\n# [Functional](http://osteele.com), and John Resig's\n# [Micro-Templating](http://ejohn.org).\n# For all details and documentation:\n# http://documentcloud.github.com/underscore/\n\n\n# Baseline setup\n# --------------\n\n# Establish the root object, `window` in the browser, or `global` on the server.\nroot = this\n\n\n# Save the previous value of the `_` variable.\npreviousUnderscore = root._\n\n### Multiline\n    comment\n###\n\n# Establish the object that gets thrown to break out of a loop iteration.\n# `StopIteration` is SOP on Mozilla.\nbreaker = if typeof(StopIteration) is 'undefined' then '__break__' else StopIteration\n\n\n#### Docco style single line comment (title)\n\n\n# Helper function to escape **RegExp** contents, because JS doesn't have one.\nescapeRegExp = (string) -> string.replace(/([.*+?^${}()|[\\]\\/\\\\])/g, '\\\\$1')\n\n\n# Save bytes in the minified (but not gzipped) version:\nArrayProto = Array.prototype\nObjProto = Object.prototype\n\n\n# Create quick reference variables for speed access to core prototypes.\nslice = ArrayProto.slice\nunshift = ArrayProto.unshift\ntoString = ObjProto.toString\nhasOwnProperty = ObjProto.hasOwnProperty\npropertyIsEnumerable = ObjProto.propertyIsEnumerable\n\n\n# All **ECMA5** native implementations we hope to use are declared here.\nnativeForEach = ArrayProto.forEach\nnativeMap = ArrayProto.map\nnativeReduce = ArrayProto.reduce\nnativeReduceRight = ArrayProto.reduceRight\nnativeFilter = ArrayProto.filter\nnativeEvery = ArrayProto.every\nnativeSome = ArrayProto.some\nnativeIndexOf = ArrayProto.indexOf\nnativeLastIndexOf = ArrayProto.lastIndexOf\nnativeIsArray = Array.isArray\nnativeKeys = Object.keys\n\n\n# Create a safe reference to the Underscore object for use below.\n_ = (obj) -> new wrapper(obj)\n\n\n# Export the Underscore object for **CommonJS**.\nif typeof(exports) != 'undefined' then exports._ = _\n\n\n# Export Underscore to global scope.\nroot._ = _\n\n\n# Current version.\n_.VERSION = '1.1.0'\n\n\n# Collection Functions\n# --------------------\n\n# The cornerstone, an **each** implementation.\n# Handles objects implementing **forEach**, arrays, and raw objects.\n_.each = (obj, iterator, context) ->\n  try\n    if nativeForEach and obj.forEach is nativeForEach\n      obj.forEach iterator, context\n    else if _.isNumber obj.length\n      iterator.call context, obj[i], i, obj for i in [0...obj.length]\n    else\n      iterator.call context, val, key, obj for own key, val of obj\n  catch e\n    throw e if e isnt breaker\n  obj\n\n\n# Return the results of applying the iterator to each element. Use JavaScript\n# 1.6's version of **map**, if possible.\n_.map = (obj, iterator, context) ->\n  return obj.map(iterator, context) if nativeMap and obj.map is nativeMap\n  results = []\n  _.each obj, (value, index, list) ->\n    results.push iterator.call context, value, index, list\n  results\n\n\n# **Reduce** builds up a single result from a list of values. Also known as\n# **inject**, or **foldl**. Uses JavaScript 1.8's version of **reduce**, if possible.\n_.reduce = (obj, iterator, memo, context) ->\n  if nativeReduce and obj.reduce is nativeReduce\n    iterator = _.bind iterator, context if context\n    return obj.reduce iterator, memo\n  _.each obj, (value, index, list) ->\n    memo = iterator.call context, memo, value, index, list\n  memo\n\n\n# The right-associative version of **reduce**, also known as **foldr**. Uses\n# JavaScript 1.8's version of **reduceRight**, if available.\n_.reduceRight = (obj, iterator, memo, context) ->\n  if nativeReduceRight and obj.reduceRight is nativeReduceRight\n    iterator = _.bind iterator, context if context\n    return obj.reduceRight iterator, memo\n  reversed = _.clone(_.toArray(obj)).reverse()\n  _.reduce reversed, iterator, memo, context\n\n\n# Return the first value which passes a truth test.\n_.detect = (obj, iterator, context) ->\n  result = null\n  _.each obj, (value, index, list) ->\n    if iterator.call context, value, index, list\n      result = value\n      _.breakLoop()\n  result\n\n\n# Return all the elements that pass a truth test. Use JavaScript 1.6's\n# **filter**, if it exists.\n_.filter = (obj, iterator, context) ->\n  return obj.filter iterator, context if nativeFilter and obj.filter is nativeFilter\n  results = []\n  _.each obj, (value, index, list) ->\n    results.push value if iterator.call context, value, index, list\n  results\n\n\n# Return all the elements for which a truth test fails.\n_.reject = (obj, iterator, context) ->\n  results = []\n  _.each obj, (value, index, list) ->\n    results.push value if not iterator.call context, value, index, list\n  results\n\n\n# Determine whether all of the elements match a truth test. Delegate to\n# JavaScript 1.6's **every**, if it is present.\n_.every = (obj, iterator, context) ->\n  iterator ||= _.identity\n  return obj.every iterator, context if nativeEvery and obj.every is nativeEvery\n  result = true\n  _.each obj, (value, index, list) ->\n    _.breakLoop() unless (result = result and iterator.call(context, value, index, list))\n  result\n\n\n# Determine if at least one element in the object matches a truth test. Use\n# JavaScript 1.6's **some**, if it exists.\n_.some = (obj, iterator, context) ->\n  iterator ||= _.identity\n  return obj.some iterator, context if nativeSome and obj.some is nativeSome\n  result = false\n  _.each obj, (value, index, list) ->\n    _.breakLoop() if (result = iterator.call(context, value, index, list))\n  result\n\n\n# Determine if a given value is included in the array or object,\n# based on `===`.\n_.include = (obj, target) ->\n  return _.indexOf(obj, target) isnt -1 if nativeIndexOf and obj.indexOf is nativeIndexOf\n  return true for own key, val of obj when val is target\n  false\n\n\n# Invoke a method with arguments on every item in a collection.\n_.invoke = (obj, method) ->\n  args = _.rest arguments, 2\n  (if method then val[method] else val).apply(val, args) for val in obj\n\n\n# Convenience version of a common use case of **map**: fetching a property.\n_.pluck = (obj, key) ->\n  _.map(obj, (val) -> val[key])\n\n\n# Return the maximum item or (item-based computation).\n_.max = (obj, iterator, context) ->\n  return Math.max.apply(Math, obj) if not iterator and _.isArray(obj)\n  result = computed: -Infinity\n  _.each obj, (value, index, list) ->\n    computed = if iterator then iterator.call(context, value, index, list) else value\n    computed >= result.computed and (result = {value: value, computed: computed})\n  result.value\n\n\n# Return the minimum element (or element-based computation).\n_.min = (obj, iterator, context) ->\n  return Math.min.apply(Math, obj) if not iterator and _.isArray(obj)\n  result = computed: Infinity\n  _.each obj, (value, index, list) ->\n    computed = if iterator then iterator.call(context, value, index, list) else value\n    computed < result.computed and (result = {value: value, computed: computed})\n  result.value\n\n\n# Sort the object's values by a criterion produced by an iterator.\n_.sortBy = (obj, iterator, context) ->\n  _.pluck(((_.map obj, (value, index, list) ->\n    {value: value, criteria: iterator.call(context, value, index, list)}\n  ).sort((left, right) ->\n    a = left.criteria; b = right.criteria\n    if a < b then -1 else if a > b then 1 else 0\n  )), 'value')\n\n\n# Use a comparator function to figure out at what index an object should\n# be inserted so as to maintain order. Uses binary search.\n_.sortedIndex = (array, obj, iterator) ->\n  iterator ||= _.identity\n  low = 0\n  high = array.length\n  while low < high\n    mid = (low + high) >> 1\n    if iterator(array[mid]) < iterator(obj) then low = mid + 1 else high = mid\n  low\n\n\n# Convert anything iterable into a real, live array.\n_.toArray = (iterable) ->\n  return [] if (!iterable)\n  return iterable.toArray() if (iterable.toArray)\n  return iterable if (_.isArray(iterable))\n  return slice.call(iterable) if (_.isArguments(iterable))\n  _.values(iterable)\n\n\n# Return the number of elements in an object.\n_.size = (obj) -> _.toArray(obj).length\n\n\n# Array Functions\n# ---------------\n\n# Get the first element of an array. Passing `n` will return the first N\n# values in the array. Aliased as **head**. The `guard` check allows it to work\n# with **map**.\n_.first = (array, n, guard) ->\n  if n and not guard then slice.call(array, 0, n) else array[0]\n\n\n# Returns everything but the first entry of the array. Aliased as **tail**.\n# Especially useful on the arguments object. Passing an `index` will return\n# the rest of the values in the array from that index onward. The `guard`\n# check allows it to work with **map**.\n_.rest = (array, index, guard) ->\n  slice.call(array, if _.isUndefined(index) or guard then 1 else index)\n\n\n# Get the last element of an array.\n_.last = (array) -> array[array.length - 1]\n\n\n# Trim out all falsy values from an array.\n_.compact = (array) -> item for item in array when item\n\n\n# Return a completely flattened version of an array.\n_.flatten = (array) ->\n  _.reduce array, (memo, value) ->\n    return memo.concat(_.flatten(value)) if _.isArray value\n    memo.push value\n    memo\n  , []\n\n\n# Return a version of the array that does not contain the specified value(s).\n_.without = (array) ->\n  values = _.rest arguments\n  val for val in _.toArray(array) when not _.include values, val\n\n\n# Produce a duplicate-free version of the array. If the array has already\n# been sorted, you have the option of using a faster algorithm.\n_.uniq = (array, isSorted) ->\n  memo = []\n  for el, i in _.toArray array\n    memo.push el if i is 0 || (if isSorted is true then _.last(memo) isnt el else not _.include(memo, el))\n  memo\n\n\n# Produce an array that contains every item shared between all the\n# passed-in arrays.\n_.intersect = (array) ->\n  rest = _.rest arguments\n  _.select _.uniq(array), (item) ->\n    _.all rest, (other) ->\n      _.indexOf(other, item) >= 0\n\n\n# Zip together multiple lists into a single array -- elements that share\n# an index go together.\n_.zip = ->\n  length = _.max _.pluck arguments, 'length'\n  results = new Array length\n  for i in [0...length]\n    results[i] = _.pluck arguments, String i\n  results\n\n\n# If the browser doesn't supply us with **indexOf** (I'm looking at you, MSIE),\n# we need this function. Return the position of the first occurrence of an\n# item in an array, or -1 if the item is not included in the array.\n_.indexOf = (array, item) ->\n  return array.indexOf item if nativeIndexOf and array.indexOf is nativeIndexOf\n  i = 0; l = array.length\n  while l - i\n    if array[i] is item then return i else i++\n  -1\n\n\n# Provide JavaScript 1.6's **lastIndexOf**, delegating to the native function,\n# if possible.\n_.lastIndexOf = (array, item) ->\n  return array.lastIndexOf(item) if nativeLastIndexOf and array.lastIndexOf is nativeLastIndexOf\n  i = array.length\n  while i\n    if array[i] is item then return i else i--\n  -1\n\n\n# Generate an integer Array containing an arithmetic progression. A port of\n# [the native Python **range** function](http://docs.python.org/library/functions.html#range).\n_.range = (start, stop, step) ->\n  a = arguments\n  solo = a.length <= 1\n  i = start = if solo then 0 else a[0]\n  stop = if solo then a[0] else a[1]\n  step = a[2] or 1\n  len = Math.ceil((stop - start) / step)\n  return [] if len <= 0\n  range = new Array len\n  idx = 0\n  loop\n    return range if (if step > 0 then i - stop else stop - i) >= 0\n    range[idx] = i\n    idx++\n    i+= step\n\n\n# Function Functions\n# ------------------\n\n# Create a function bound to a given object (assigning `this`, and arguments,\n# optionally). Binding with arguments is also known as **curry**.\n_.bind = (func, obj) ->\n  args = _.rest arguments, 2\n  -> func.apply obj or root, args.concat arguments\n\n\n# Bind all of an object's methods to that object. Useful for ensuring that\n# all callbacks defined on an object belong to it.\n_.bindAll = (obj) ->\n  funcs = if arguments.length > 1 then _.rest(arguments) else _.functions(obj)\n  _.each funcs, (f) -> obj[f] = _.bind obj[f], obj\n  obj\n\n\n# Delays a function for the given number of milliseconds, and then calls\n# it with the arguments supplied.\n_.delay = (func, wait) ->\n  args = _.rest arguments, 2\n  setTimeout((-> func.apply(func, args)), wait)\n\n\n# Memoize an expensive function by storing its results.\n_.memoize = (func, hasher) ->\n  memo = {}\n  hasher or= _.identity\n  ->\n    key = hasher.apply this, arguments\n    return memo[key] if key of memo\n    memo[key] = func.apply this, arguments\n\n\n# Defers a function, scheduling it to run after the current call stack has\n# cleared.\n_.defer = (func) ->\n  _.delay.apply _, [func, 1].concat _.rest arguments\n\n\n# Returns the first function passed as an argument to the second,\n# allowing you to adjust arguments, run code before and after, and\n# conditionally execute the original function.\n_.wrap = (func, wrapper) ->\n  -> wrapper.apply wrapper, [func].concat arguments\n\n\n# Returns a function that is the composition of a list of functions, each\n# consuming the return value of the function that follows.\n_.compose = ->\n  funcs = arguments\n  ->\n    args = arguments\n    for i in [funcs.length - 1..0] by -1\n      args = [funcs[i].apply(this, args)]\n    args[0]\n\n\n# Object Functions\n# ----------------\n\n# Retrieve the names of an object's properties.\n_.keys = nativeKeys or (obj) ->\n  return _.range 0, obj.length if _.isArray(obj)\n  key for key, val of obj\n\n\n# Retrieve the values of an object's properties.\n_.values = (obj) ->\n  _.map obj, _.identity\n\n\n# Return a sorted list of the function names available in Underscore.\n_.functions = (obj) ->\n  _.filter(_.keys(obj), (key) -> _.isFunction(obj[key])).sort()\n\n\n# Extend a given object with all of the properties in a source object.\n_.extend = (obj) ->\n  for source in _.rest(arguments)\n    obj[key] = val for key, val of source\n  obj\n\n\n# Create a (shallow-cloned) duplicate of an object.\n_.clone = (obj) ->\n  return obj.slice 0 if _.isArray obj\n  _.extend {}, obj\n\n\n# Invokes interceptor with the obj, and then returns obj.\n# The primary purpose of this method is to \"tap into\" a method chain,\n# in order to perform operations on intermediate results within\n the chain.\n_.tap = (obj, interceptor) ->\n  interceptor obj\n  obj\n\n\n# Perform a deep comparison to check if two objects are equal.\n_.isEqual = (a, b) ->\n  # Check object identity.\n  return true if a is b\n  # Different types?\n  atype = typeof(a); btype = typeof(b)\n  return false if atype isnt btype\n  # Basic equality test (watch out for coercions).\n  return true if `a == b`\n  # One is falsy and the other truthy.\n  return false if (!a and b) or (a and !b)\n  # One of them implements an `isEqual()`?\n  return a.isEqual(b) if a.isEqual\n  # Check dates' integer values.\n  return a.getTime() is b.getTime() if _.isDate(a) and _.isDate(b)\n  # Both are NaN?\n  return false if _.isNaN(a) and _.isNaN(b)\n  # Compare regular expressions.\n  if _.isRegExp(a) and _.isRegExp(b)\n    return a.source is b.source and\n           a.global is b.global and\n           a.ignoreCase is b.ignoreCase and\n           a.multiline is b.multiline\n  # If a is not an object by this point, we can't handle it.\n  return false if atype isnt 'object'\n  # Check for different array lengths before comparing contents.\n  return false if a.length and (a.length isnt b.length)\n  # Nothing else worked, deep compare the contents.\n  aKeys = _.keys(a); bKeys = _.keys(b)\n  # Different object sizes?\n  return false if aKeys.length isnt bKeys.length\n  # Recursive comparison of contents.\n  return false for key, val of a when !(key of b) or !_.isEqual(val, b[key])\n  true\n\n\n# Is a given array or object empty?\n_.isEmpty = (obj) ->\n  return obj.length is 0 if _.isArray(obj) or _.isString(obj)\n  return false for own key of obj\n  true\n\n\n# Is a given value a DOM element?\n_.isElement = (obj) -> obj and obj.nodeType is 1\n\n\n# Is a given value an array?\n_.isArray = nativeIsArray or (obj) -> !!(obj and obj.concat and obj.unshift and not obj.callee)\n\n\n# Is a given variable an arguments object?\n_.isArguments = (obj) -> obj and obj.callee\n\n\n# Is the given value a function?\n_.isFunction = (obj) -> !!(obj and obj.constructor and obj.call and obj.apply)\n\n\n# Is the given value a string?\n_.isString = (obj) -> !!(obj is '' or (obj and obj.charCodeAt and obj.substr))\n\n\n# Is a given value a number?\n_.isNumber = (obj) -> (obj is +obj) or toString.call(obj) is '[object Number]'\n\n\n# Is a given value a boolean?\n_.isBoolean = (obj) -> obj is true or obj is false\n\n\n# Is a given value a Date?\n_.isDate = (obj) -> !!(obj and obj.getTimezoneOffset and obj.setUTCFullYear)\n\n\n# Is the given value a regular expression?\n_.isRegExp = (obj) -> !!(obj and obj.exec and (obj.ignoreCase or obj.ignoreCase is false))\n\n\n# Is the given value NaN -- this one is interesting. `NaN != NaN`, and\n# `isNaN(undefined) == true`, so we make sure it's a number first.\n_.isNaN = (obj) -> _.isNumber(obj) and window.isNaN(obj)\n\n\n# Is a given value equal to null?\n_.isNull = (obj) -> obj is null\n\n\n# Is a given variable undefined?\n_.isUndefined = (obj) -> typeof obj is 'undefined'\n\n\n# Utility Functions\n# -----------------\n\n# Run Underscore.js in noConflict mode, returning the `_` variable to its\n# previous owner. Returns a reference to the Underscore object.\n_.noConflict = ->\n  root._ = previousUnderscore\n  this\n\n\n# Keep the identity function around for default iterators.\n_.identity = (value) -> value\n\n\n# Run a function `n` times.\n_.times = (n, iterator, context) ->\n  iterator.call context, i for i in [0...n]\n\n\n# Break out of the middle of an iteration.\n_.breakLoop = -> throw breaker\n\n\n# Add your own custom functions to the Underscore object, ensuring that\n# they're correctly added to the OOP wrapper as well.\n_.mixin = (obj) ->\n  for name in _.functions(obj)\n    addToWrapper name, _[name] = obj[name]\n\n\n# Generate a unique integer id (unique within the entire client session).\n# Useful for temporary DOM ids.\nidCounter = 0\n_.uniqueId = (prefix) ->\n  (prefix or '') + idCounter++\n\n\n# By default, Underscore uses **ERB**-style template delimiters, change the\n# following template settings to use alternative delimiters.\n_.templateSettings = {\n  start: '<%'\n  end: '%>'\n  interpolate: /<%=(.+?)%>/g\n}\n\n\n# JavaScript templating a-la **ERB**, pilfered from John Resig's\n# *Secrets of the JavaScript Ninja*, page 83.\n# Single-quote fix from Rick Strahl.\n# With alterations for arbitrary delimiters, and to preserve whitespace.\n_.template = (str, data) ->\n  c = _.templateSettings\n  endMatch = new RegExp(\"'(?=[^\"+c.end.substr(0, 1)+\"]*\"+escapeRegExp(c.end)+\")\",\"g\")\n  fn = new Function 'obj',\n    'var p=[],print=function(){p.push.apply(p,arguments);};' +\n    'with(obj||{}){p.push(\\'' +\n    str.replace(/\\r/g, '\\\\r')\n       .replace(/\\n/g, '\\\\n')\n       .replace(/\\t/g, '\\\\t')\n       .replace(endMatch,\"���\")\n       .split(\"'\").join(\"\\\\'\")\n       .split(\"���\").join(\"'\")\n       .replace(c.interpolate, \"',$1,'\")\n       .split(c.start).join(\"');\")\n       .split(c.end).join(\"p.push('\") +\n       \"');}return p.join('');\"\n  if data then fn(data) else fn\n\n\n# Aliases\n# -------\n\n_.forEach = _.each\n_.foldl = _.inject = _.reduce\n_.foldr = _.reduceRight\n_.select = _.filter\n_.all = _.every\n_.any = _.some\n_.contains = _.include\n_.head = _.first\n_.tail = _.rest\n_.methods = _.functions\n\n\n# Setup the OOP Wrapper\n# ---------------------\n\n# If Underscore is called as a function, it returns a wrapped object that\n# can be used OO-style. This wrapper holds altered versions of all the\n# underscore functions. Wrapped objects may be chained.\nwrapper = (obj) ->\n  this._wrapped = obj\n  this\n\n\n# Helper function to continue chaining intermediate results.\nresult = (obj, chain) ->\n  if chain then _(obj).chain() else obj\n\n\n# A method to easily add functions to the OOP wrapper.\naddToWrapper = (name, func) ->\n  wrapper.prototype[name] = ->\n    args = _.toArray arguments\n    unshift.call args, this._wrapped\n    result func.apply(_, args), this._chain\n\n\n# Add all ofthe Underscore functions to the wrapper object.\n_.mixin _\n\n\n# Add all mutator Array functions to the wrapper.\n_.each ['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], (name) ->\n  method = Array.prototype[name]\n  wrapper.prototype[name] = ->\n    method.apply(this._wrapped, arguments)\n    result(this._wrapped, this._chain)\n\n\n# Add all accessor Array functions to the wrapper.\n_.each ['concat', 'join', 'slice'], (name) ->\n  method = Array.prototype[name]\n  wrapper.prototype[name] = ->\n    result(method.apply(this._wrapped, arguments), this._chain)\n\n\n# Start chaining a wrapped Underscore object.\nwrapper::chain = ->\n  this._chain = true\n  this\n\n\n# Extracts the result from a wrapped and chained object.\nwrapper::value = -> this._wrapped\n</textarea></form>\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {});\n    </script>\n\n    <p><strong>MIME types defined:</strong> <code>text/x-coffeescript</code>.</p>\n\n    <p>The CoffeeScript mode was written by Jeff Pickhardt.</p>\n\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/commonlisp/commonlisp.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"commonlisp\", function (config) {\n  var specialForm = /^(block|let*|return-from|catch|load-time-value|setq|eval-when|locally|symbol-macrolet|flet|macrolet|tagbody|function|multiple-value-call|the|go|multiple-value-prog1|throw|if|progn|unwind-protect|labels|progv|let|quote)$/;\n  var assumeBody = /^with|^def|^do|^prog|case$|^cond$|bind$|when$|unless$/;\n  var numLiteral = /^(?:[+\\-]?(?:\\d+|\\d*\\.\\d+)(?:[efd][+\\-]?\\d+)?|[+\\-]?\\d+(?:\\/[+\\-]?\\d+)?|#b[+\\-]?[01]+|#o[+\\-]?[0-7]+|#x[+\\-]?[\\da-f]+)/;\n  var symbol = /[^\\s'`,@()\\[\\]\";]/;\n  var type;\n\n  function readSym(stream) {\n    var ch;\n    while (ch = stream.next()) {\n      if (ch == \"\\\\\") stream.next();\n      else if (!symbol.test(ch)) { stream.backUp(1); break; }\n    }\n    return stream.current();\n  }\n\n  function base(stream, state) {\n    if (stream.eatSpace()) {type = \"ws\"; return null;}\n    if (stream.match(numLiteral)) return \"number\";\n    var ch = stream.next();\n    if (ch == \"\\\\\") ch = stream.next();\n\n    if (ch == '\"') return (state.tokenize = inString)(stream, state);\n    else if (ch == \"(\") { type = \"open\"; return \"bracket\"; }\n    else if (ch == \")\" || ch == \"]\") { type = \"close\"; return \"bracket\"; }\n    else if (ch == \";\") { stream.skipToEnd(); type = \"ws\"; return \"comment\"; }\n    else if (/['`,@]/.test(ch)) return null;\n    else if (ch == \"|\") {\n      if (stream.skipTo(\"|\")) { stream.next(); return \"symbol\"; }\n      else { stream.skipToEnd(); return \"error\"; }\n    } else if (ch == \"#\") {\n      var ch = stream.next();\n      if (ch == \"[\") { type = \"open\"; return \"bracket\"; }\n      else if (/[+\\-=\\.']/.test(ch)) return null;\n      else if (/\\d/.test(ch) && stream.match(/^\\d*#/)) return null;\n      else if (ch == \"|\") return (state.tokenize = inComment)(stream, state);\n      else if (ch == \":\") { readSym(stream); return \"meta\"; }\n      else return \"error\";\n    } else {\n      var name = readSym(stream);\n      if (name == \".\") return null;\n      type = \"symbol\";\n      if (name == \"nil\" || name == \"t\" || name.charAt(0) == \":\") return \"atom\";\n      if (state.lastType == \"open\" && (specialForm.test(name) || assumeBody.test(name))) return \"keyword\";\n      if (name.charAt(0) == \"&\") return \"variable-2\";\n      return \"variable\";\n    }\n  }\n\n  function inString(stream, state) {\n    var escaped = false, next;\n    while (next = stream.next()) {\n      if (next == '\"' && !escaped) { state.tokenize = base; break; }\n      escaped = !escaped && next == \"\\\\\";\n    }\n    return \"string\";\n  }\n\n  function inComment(stream, state) {\n    var next, last;\n    while (next = stream.next()) {\n      if (next == \"#\" && last == \"|\") { state.tokenize = base; break; }\n      last = next;\n    }\n    type = \"ws\";\n    return \"comment\";\n  }\n\n  return {\n    startState: function () {\n      return {ctx: {prev: null, start: 0, indentTo: 0}, lastType: null, tokenize: base};\n    },\n\n    token: function (stream, state) {\n      if (stream.sol() && typeof state.ctx.indentTo != \"number\")\n        state.ctx.indentTo = state.ctx.start + 1;\n\n      type = null;\n      var style = state.tokenize(stream, state);\n      if (type != \"ws\") {\n        if (state.ctx.indentTo == null) {\n          if (type == \"symbol\" && assumeBody.test(stream.current()))\n            state.ctx.indentTo = state.ctx.start + config.indentUnit;\n          else\n            state.ctx.indentTo = \"next\";\n        } else if (state.ctx.indentTo == \"next\") {\n          state.ctx.indentTo = stream.column();\n        }\n        state.lastType = type;\n      }\n      if (type == \"open\") state.ctx = {prev: state.ctx, start: stream.column(), indentTo: null};\n      else if (type == \"close\") state.ctx = state.ctx.prev || state.ctx;\n      return style;\n    },\n\n    indent: function (state, _textAfter) {\n      var i = state.ctx.indentTo;\n      return typeof i == \"number\" ? i : state.ctx.start + 1;\n    },\n\n    lineComment: \";;\",\n    blockCommentStart: \"#|\",\n    blockCommentEnd: \"|#\"\n  };\n});\n\nCodeMirror.defineMIME(\"text/x-common-lisp\", \"commonlisp\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/commonlisp/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Common Lisp mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"commonlisp.js\"></script>\n<style>.CodeMirror {background: #f8f8f8;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Common Lisp</a>\n  </ul>\n</div>\n\n<article>\n<h2>Common Lisp mode</h2>\n<form><textarea id=\"code\" name=\"code\">(in-package :cl-postgres)\n\n;; These are used to synthesize reader and writer names for integer\n;; reading/writing functions when the amount of bytes and the\n;; signedness is known. Both the macro that creates the functions and\n;; some macros that use them create names this way.\n(eval-when (:compile-toplevel :load-toplevel :execute)\n  (defun integer-reader-name (bytes signed)\n    (intern (with-standard-io-syntax\n              (format nil \"~a~a~a~a\" '#:read- (if signed \"\" '#:u) '#:int bytes))))\n  (defun integer-writer-name (bytes signed)\n    (intern (with-standard-io-syntax\n              (format nil \"~a~a~a~a\" '#:write- (if signed \"\" '#:u) '#:int bytes)))))\n\n(defmacro integer-reader (bytes)\n  \"Create a function to read integers from a binary stream.\"\n  (let ((bits (* bytes 8)))\n    (labels ((return-form (signed)\n               (if signed\n                   `(if (logbitp ,(1- bits) result)\n                        (dpb result (byte ,(1- bits) 0) -1)\n                        result)\n                   `result))\n             (generate-reader (signed)\n               `(defun ,(integer-reader-name bytes signed) (socket)\n                  (declare (type stream socket)\n                           #.*optimize*)\n                  ,(if (= bytes 1)\n                       `(let ((result (the (unsigned-byte 8) (read-byte socket))))\n                          (declare (type (unsigned-byte 8) result))\n                          ,(return-form signed))\n                       `(let ((result 0))\n                          (declare (type (unsigned-byte ,bits) result))\n                          ,@(loop :for byte :from (1- bytes) :downto 0\n                                   :collect `(setf (ldb (byte 8 ,(* 8 byte)) result)\n                                                   (the (unsigned-byte 8) (read-byte socket))))\n                          ,(return-form signed))))))\n      `(progn\n;; This causes weird errors on SBCL in some circumstances. Disabled for now.\n;;         (declaim (inline ,(integer-reader-name bytes t)\n;;                          ,(integer-reader-name bytes nil)))\n         (declaim (ftype (function (t) (signed-byte ,bits))\n                         ,(integer-reader-name bytes t)))\n         ,(generate-reader t)\n         (declaim (ftype (function (t) (unsigned-byte ,bits))\n                         ,(integer-reader-name bytes nil)))\n         ,(generate-reader nil)))))\n\n(defmacro integer-writer (bytes)\n  \"Create a function to write integers to a binary stream.\"\n  (let ((bits (* 8 bytes)))\n    `(progn\n      (declaim (inline ,(integer-writer-name bytes t)\n                       ,(integer-writer-name bytes nil)))\n      (defun ,(integer-writer-name bytes nil) (socket value)\n        (declare (type stream socket)\n                 (type (unsigned-byte ,bits) value)\n                 #.*optimize*)\n        ,@(if (= bytes 1)\n              `((write-byte value socket))\n              (loop :for byte :from (1- bytes) :downto 0\n                    :collect `(write-byte (ldb (byte 8 ,(* byte 8)) value)\n                               socket)))\n        (values))\n      (defun ,(integer-writer-name bytes t) (socket value)\n        (declare (type stream socket)\n                 (type (signed-byte ,bits) value)\n                 #.*optimize*)\n        ,@(if (= bytes 1)\n              `((write-byte (ldb (byte 8 0) value) socket))\n              (loop :for byte :from (1- bytes) :downto 0\n                    :collect `(write-byte (ldb (byte 8 ,(* byte 8)) value)\n                               socket)))\n        (values)))))\n\n;; All the instances of the above that we need.\n\n(integer-reader 1)\n(integer-reader 2)\n(integer-reader 4)\n(integer-reader 8)\n\n(integer-writer 1)\n(integer-writer 2)\n(integer-writer 4)\n\n(defun write-bytes (socket bytes)\n  \"Write a byte-array to a stream.\"\n  (declare (type stream socket)\n           (type (simple-array (unsigned-byte 8)) bytes)\n           #.*optimize*)\n  (write-sequence bytes socket))\n\n(defun write-str (socket string)\n  \"Write a null-terminated string to a stream \\(encoding it when UTF-8\nsupport is enabled.).\"\n  (declare (type stream socket)\n           (type string string)\n           #.*optimize*)\n  (enc-write-string string socket)\n  (write-uint1 socket 0))\n\n(declaim (ftype (function (t unsigned-byte)\n                          (simple-array (unsigned-byte 8) (*)))\n                read-bytes))\n(defun read-bytes (socket length)\n  \"Read a byte array of the given length from a stream.\"\n  (declare (type stream socket)\n           (type fixnum length)\n           #.*optimize*)\n  (let ((result (make-array length :element-type '(unsigned-byte 8))))\n    (read-sequence result socket)\n    result))\n\n(declaim (ftype (function (t) string) read-str))\n(defun read-str (socket)\n  \"Read a null-terminated string from a stream. Takes care of encoding\nwhen UTF-8 support is enabled.\"\n  (declare (type stream socket)\n           #.*optimize*)\n  (enc-read-string socket :null-terminated t))\n\n(defun skip-bytes (socket length)\n  \"Skip a given number of bytes in a binary stream.\"\n  (declare (type stream socket)\n           (type (unsigned-byte 32) length)\n           #.*optimize*)\n  (dotimes (i length)\n    (read-byte socket)))\n\n(defun skip-str (socket)\n  \"Skip a null-terminated string.\"\n  (declare (type stream socket)\n           #.*optimize*)\n  (loop :for char :of-type fixnum = (read-byte socket)\n        :until (zerop char)))\n\n(defun ensure-socket-is-closed (socket &amp;key abort)\n  (when (open-stream-p socket)\n    (handler-case\n        (close socket :abort abort)\n      (error (error)\n        (warn \"Ignoring the error which happened while trying to close PostgreSQL socket: ~A\" error)))))\n</textarea></form>\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {lineNumbers: true});\n    </script>\n\n    <p><strong>MIME types defined:</strong> <code>text/x-common-lisp</code>.</p>\n\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/css/css.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"css\", function(config, parserConfig) {\n  if (!parserConfig.propertyKeywords) parserConfig = CodeMirror.resolveMode(\"text/css\");\n\n  var indentUnit = config.indentUnit,\n      tokenHooks = parserConfig.tokenHooks,\n      documentTypes = parserConfig.documentTypes || {},\n      mediaTypes = parserConfig.mediaTypes || {},\n      mediaFeatures = parserConfig.mediaFeatures || {},\n      propertyKeywords = parserConfig.propertyKeywords || {},\n      nonStandardPropertyKeywords = parserConfig.nonStandardPropertyKeywords || {},\n      fontProperties = parserConfig.fontProperties || {},\n      counterDescriptors = parserConfig.counterDescriptors || {},\n      colorKeywords = parserConfig.colorKeywords || {},\n      valueKeywords = parserConfig.valueKeywords || {},\n      allowNested = parserConfig.allowNested;\n\n  var type, override;\n  function ret(style, tp) { type = tp; return style; }\n\n  // Tokenizers\n\n  function tokenBase(stream, state) {\n    var ch = stream.next();\n    if (tokenHooks[ch]) {\n      var result = tokenHooks[ch](stream, state);\n      if (result !== false) return result;\n    }\n    if (ch == \"@\") {\n      stream.eatWhile(/[\\w\\\\\\-]/);\n      return ret(\"def\", stream.current());\n    } else if (ch == \"=\" || (ch == \"~\" || ch == \"|\") && stream.eat(\"=\")) {\n      return ret(null, \"compare\");\n    } else if (ch == \"\\\"\" || ch == \"'\") {\n      state.tokenize = tokenString(ch);\n      return state.tokenize(stream, state);\n    } else if (ch == \"#\") {\n      stream.eatWhile(/[\\w\\\\\\-]/);\n      return ret(\"atom\", \"hash\");\n    } else if (ch == \"!\") {\n      stream.match(/^\\s*\\w*/);\n      return ret(\"keyword\", \"important\");\n    } else if (/\\d/.test(ch) || ch == \".\" && stream.eat(/\\d/)) {\n      stream.eatWhile(/[\\w.%]/);\n      return ret(\"number\", \"unit\");\n    } else if (ch === \"-\") {\n      if (/[\\d.]/.test(stream.peek())) {\n        stream.eatWhile(/[\\w.%]/);\n        return ret(\"number\", \"unit\");\n      } else if (stream.match(/^-[\\w\\\\\\-]+/)) {\n        stream.eatWhile(/[\\w\\\\\\-]/);\n        if (stream.match(/^\\s*:/, false))\n          return ret(\"variable-2\", \"variable-definition\");\n        return ret(\"variable-2\", \"variable\");\n      } else if (stream.match(/^\\w+-/)) {\n        return ret(\"meta\", \"meta\");\n      }\n    } else if (/[,+>*\\/]/.test(ch)) {\n      return ret(null, \"select-op\");\n    } else if (ch == \".\" && stream.match(/^-?[_a-z][_a-z0-9-]*/i)) {\n      return ret(\"qualifier\", \"qualifier\");\n    } else if (/[:;{}\\[\\]\\(\\)]/.test(ch)) {\n      return ret(null, ch);\n    } else if ((ch == \"u\" && stream.match(/rl(-prefix)?\\(/)) ||\n               (ch == \"d\" && stream.match(\"omain(\")) ||\n               (ch == \"r\" && stream.match(\"egexp(\"))) {\n      stream.backUp(1);\n      state.tokenize = tokenParenthesized;\n      return ret(\"property\", \"word\");\n    } else if (/[\\w\\\\\\-]/.test(ch)) {\n      stream.eatWhile(/[\\w\\\\\\-]/);\n      return ret(\"property\", \"word\");\n    } else {\n      return ret(null, null);\n    }\n  }\n\n  function tokenString(quote) {\n    return function(stream, state) {\n      var escaped = false, ch;\n      while ((ch = stream.next()) != null) {\n        if (ch == quote && !escaped) {\n          if (quote == \")\") stream.backUp(1);\n          break;\n        }\n        escaped = !escaped && ch == \"\\\\\";\n      }\n      if (ch == quote || !escaped && quote != \")\") state.tokenize = null;\n      return ret(\"string\", \"string\");\n    };\n  }\n\n  function tokenParenthesized(stream, state) {\n    stream.next(); // Must be '('\n    if (!stream.match(/\\s*[\\\"\\')]/, false))\n      state.tokenize = tokenString(\")\");\n    else\n      state.tokenize = null;\n    return ret(null, \"(\");\n  }\n\n  // Context management\n\n  function Context(type, indent, prev) {\n    this.type = type;\n    this.indent = indent;\n    this.prev = prev;\n  }\n\n  function pushContext(state, stream, type) {\n    state.context = new Context(type, stream.indentation() + indentUnit, state.context);\n    return type;\n  }\n\n  function popContext(state) {\n    state.context = state.context.prev;\n    return state.context.type;\n  }\n\n  function pass(type, stream, state) {\n    return states[state.context.type](type, stream, state);\n  }\n  function popAndPass(type, stream, state, n) {\n    for (var i = n || 1; i > 0; i--)\n      state.context = state.context.prev;\n    return pass(type, stream, state);\n  }\n\n  // Parser\n\n  function wordAsValue(stream) {\n    var word = stream.current().toLowerCase();\n    if (valueKeywords.hasOwnProperty(word))\n      override = \"atom\";\n    else if (colorKeywords.hasOwnProperty(word))\n      override = \"keyword\";\n    else\n      override = \"variable\";\n  }\n\n  var states = {};\n\n  states.top = function(type, stream, state) {\n    if (type == \"{\") {\n      return pushContext(state, stream, \"block\");\n    } else if (type == \"}\" && state.context.prev) {\n      return popContext(state);\n    } else if (/@(media|supports|(-moz-)?document)/.test(type)) {\n      return pushContext(state, stream, \"atBlock\");\n    } else if (/@(font-face|counter-style)/.test(type)) {\n      state.stateArg = type;\n      return \"restricted_atBlock_before\";\n    } else if (/^@(-(moz|ms|o|webkit)-)?keyframes$/.test(type)) {\n      return \"keyframes\";\n    } else if (type && type.charAt(0) == \"@\") {\n      return pushContext(state, stream, \"at\");\n    } else if (type == \"hash\") {\n      override = \"builtin\";\n    } else if (type == \"word\") {\n      override = \"tag\";\n    } else if (type == \"variable-definition\") {\n      return \"maybeprop\";\n    } else if (type == \"interpolation\") {\n      return pushContext(state, stream, \"interpolation\");\n    } else if (type == \":\") {\n      return \"pseudo\";\n    } else if (allowNested && type == \"(\") {\n      return pushContext(state, stream, \"parens\");\n    }\n    return state.context.type;\n  };\n\n  states.block = function(type, stream, state) {\n    if (type == \"word\") {\n      var word = stream.current().toLowerCase();\n      if (propertyKeywords.hasOwnProperty(word)) {\n        override = \"property\";\n        return \"maybeprop\";\n      } else if (nonStandardPropertyKeywords.hasOwnProperty(word)) {\n        override = \"string-2\";\n        return \"maybeprop\";\n      } else if (allowNested) {\n        override = stream.match(/^\\s*:(?:\\s|$)/, false) ? \"property\" : \"tag\";\n        return \"block\";\n      } else {\n        override += \" error\";\n        return \"maybeprop\";\n      }\n    } else if (type == \"meta\") {\n      return \"block\";\n    } else if (!allowNested && (type == \"hash\" || type == \"qualifier\")) {\n      override = \"error\";\n      return \"block\";\n    } else {\n      return states.top(type, stream, state);\n    }\n  };\n\n  states.maybeprop = function(type, stream, state) {\n    if (type == \":\") return pushContext(state, stream, \"prop\");\n    return pass(type, stream, state);\n  };\n\n  states.prop = function(type, stream, state) {\n    if (type == \";\") return popContext(state);\n    if (type == \"{\" && allowNested) return pushContext(state, stream, \"propBlock\");\n    if (type == \"}\" || type == \"{\") return popAndPass(type, stream, state);\n    if (type == \"(\") return pushContext(state, stream, \"parens\");\n\n    if (type == \"hash\" && !/^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/.test(stream.current())) {\n      override += \" error\";\n    } else if (type == \"word\") {\n      wordAsValue(stream);\n    } else if (type == \"interpolation\") {\n      return pushContext(state, stream, \"interpolation\");\n    }\n    return \"prop\";\n  };\n\n  states.propBlock = function(type, _stream, state) {\n    if (type == \"}\") return popContext(state);\n    if (type == \"word\") { override = \"property\"; return \"maybeprop\"; }\n    return state.context.type;\n  };\n\n  states.parens = function(type, stream, state) {\n    if (type == \"{\" || type == \"}\") return popAndPass(type, stream, state);\n    if (type == \")\") return popContext(state);\n    if (type == \"(\") return pushContext(state, stream, \"parens\");\n    if (type == \"word\") wordAsValue(stream);\n    return \"parens\";\n  };\n\n  states.pseudo = function(type, stream, state) {\n    if (type == \"word\") {\n      override = \"variable-3\";\n      return state.context.type;\n    }\n    return pass(type, stream, state);\n  };\n\n  states.atBlock = function(type, stream, state) {\n    if (type == \"(\") return pushContext(state, stream, \"atBlock_parens\");\n    if (type == \"}\") return popAndPass(type, stream, state);\n    if (type == \"{\") return popContext(state) && pushContext(state, stream, allowNested ? \"block\" : \"top\");\n\n    if (type == \"word\") {\n      var word = stream.current().toLowerCase();\n      if (word == \"only\" || word == \"not\" || word == \"and\" || word == \"or\")\n        override = \"keyword\";\n      else if (documentTypes.hasOwnProperty(word))\n        override = \"tag\";\n      else if (mediaTypes.hasOwnProperty(word))\n        override = \"attribute\";\n      else if (mediaFeatures.hasOwnProperty(word))\n        override = \"property\";\n      else if (propertyKeywords.hasOwnProperty(word))\n        override = \"property\";\n      else if (nonStandardPropertyKeywords.hasOwnProperty(word))\n        override = \"string-2\";\n      else if (valueKeywords.hasOwnProperty(word))\n        override = \"atom\";\n      else\n        override = \"error\";\n    }\n    return state.context.type;\n  };\n\n  states.atBlock_parens = function(type, stream, state) {\n    if (type == \")\") return popContext(state);\n    if (type == \"{\" || type == \"}\") return popAndPass(type, stream, state, 2);\n    return states.atBlock(type, stream, state);\n  };\n\n  states.restricted_atBlock_before = function(type, stream, state) {\n    if (type == \"{\")\n      return pushContext(state, stream, \"restricted_atBlock\");\n    if (type == \"word\" && state.stateArg == \"@counter-style\") {\n      override = \"variable\";\n      return \"restricted_atBlock_before\";\n    }\n    return pass(type, stream, state);\n  };\n\n  states.restricted_atBlock = function(type, stream, state) {\n    if (type == \"}\") {\n      state.stateArg = null;\n      return popContext(state);\n    }\n    if (type == \"word\") {\n      if ((state.stateArg == \"@font-face\" && !fontProperties.hasOwnProperty(stream.current().toLowerCase())) ||\n          (state.stateArg == \"@counter-style\" && !counterDescriptors.hasOwnProperty(stream.current().toLowerCase())))\n        override = \"error\";\n      else\n        override = \"property\";\n      return \"maybeprop\";\n    }\n    return \"restricted_atBlock\";\n  };\n\n  states.keyframes = function(type, stream, state) {\n    if (type == \"word\") { override = \"variable\"; return \"keyframes\"; }\n    if (type == \"{\") return pushContext(state, stream, \"top\");\n    return pass(type, stream, state);\n  };\n\n  states.at = function(type, stream, state) {\n    if (type == \";\") return popContext(state);\n    if (type == \"{\" || type == \"}\") return popAndPass(type, stream, state);\n    if (type == \"word\") override = \"tag\";\n    else if (type == \"hash\") override = \"builtin\";\n    return \"at\";\n  };\n\n  states.interpolation = function(type, stream, state) {\n    if (type == \"}\") return popContext(state);\n    if (type == \"{\" || type == \";\") return popAndPass(type, stream, state);\n    if (type != \"variable\") override = \"error\";\n    return \"interpolation\";\n  };\n\n  return {\n    startState: function(base) {\n      return {tokenize: null,\n              state: \"top\",\n              stateArg: null,\n              context: new Context(\"top\", base || 0, null)};\n    },\n\n    token: function(stream, state) {\n      if (!state.tokenize && stream.eatSpace()) return null;\n      var style = (state.tokenize || tokenBase)(stream, state);\n      if (style && typeof style == \"object\") {\n        type = style[1];\n        style = style[0];\n      }\n      override = style;\n      state.state = states[state.state](type, stream, state);\n      return override;\n    },\n\n    indent: function(state, textAfter) {\n      var cx = state.context, ch = textAfter && textAfter.charAt(0);\n      var indent = cx.indent;\n      if (cx.type == \"prop\" && (ch == \"}\" || ch == \")\")) cx = cx.prev;\n      if (cx.prev &&\n          (ch == \"}\" && (cx.type == \"block\" || cx.type == \"top\" || cx.type == \"interpolation\" || cx.type == \"restricted_atBlock\") ||\n           ch == \")\" && (cx.type == \"parens\" || cx.type == \"atBlock_parens\") ||\n           ch == \"{\" && (cx.type == \"at\" || cx.type == \"atBlock\"))) {\n        indent = cx.indent - indentUnit;\n        cx = cx.prev;\n      }\n      return indent;\n    },\n\n    electricChars: \"}\",\n    blockCommentStart: \"/*\",\n    blockCommentEnd: \"*/\",\n    fold: \"brace\"\n  };\n});\n\n  function keySet(array) {\n    var keys = {};\n    for (var i = 0; i < array.length; ++i) {\n      keys[array[i]] = true;\n    }\n    return keys;\n  }\n\n  var documentTypes_ = [\n    \"domain\", \"regexp\", \"url\", \"url-prefix\"\n  ], documentTypes = keySet(documentTypes_);\n\n  var mediaTypes_ = [\n    \"all\", \"aural\", \"braille\", \"handheld\", \"print\", \"projection\", \"screen\",\n    \"tty\", \"tv\", \"embossed\"\n  ], mediaTypes = keySet(mediaTypes_);\n\n  var mediaFeatures_ = [\n    \"width\", \"min-width\", \"max-width\", \"height\", \"min-height\", \"max-height\",\n    \"device-width\", \"min-device-width\", \"max-device-width\", \"device-height\",\n    \"min-device-height\", \"max-device-height\", \"aspect-ratio\",\n    \"min-aspect-ratio\", \"max-aspect-ratio\", \"device-aspect-ratio\",\n    \"min-device-aspect-ratio\", \"max-device-aspect-ratio\", \"color\", \"min-color\",\n    \"max-color\", \"color-index\", \"min-color-index\", \"max-color-index\",\n    \"monochrome\", \"min-monochrome\", \"max-monochrome\", \"resolution\",\n    \"min-resolution\", \"max-resolution\", \"scan\", \"grid\"\n  ], mediaFeatures = keySet(mediaFeatures_);\n\n  var propertyKeywords_ = [\n    \"align-content\", \"align-items\", \"align-self\", \"alignment-adjust\",\n    \"alignment-baseline\", \"anchor-point\", \"animation\", \"animation-delay\",\n    \"animation-direction\", \"animation-duration\", \"animation-fill-mode\",\n    \"animation-iteration-count\", \"animation-name\", \"animation-play-state\",\n    \"animation-timing-function\", \"appearance\", \"azimuth\", \"backface-visibility\",\n    \"background\", \"background-attachment\", \"background-clip\", \"background-color\",\n    \"background-image\", \"background-origin\", \"background-position\",\n    \"background-repeat\", \"background-size\", \"baseline-shift\", \"binding\",\n    \"bleed\", \"bookmark-label\", \"bookmark-level\", \"bookmark-state\",\n    \"bookmark-target\", \"border\", \"border-bottom\", \"border-bottom-color\",\n    \"border-bottom-left-radius\", \"border-bottom-right-radius\",\n    \"border-bottom-style\", \"border-bottom-width\", \"border-collapse\",\n    \"border-color\", \"border-image\", \"border-image-outset\",\n    \"border-image-repeat\", \"border-image-slice\", \"border-image-source\",\n    \"border-image-width\", \"border-left\", \"border-left-color\",\n    \"border-left-style\", \"border-left-width\", \"border-radius\", \"border-right\",\n    \"border-right-color\", \"border-right-style\", \"border-right-width\",\n    \"border-spacing\", \"border-style\", \"border-top\", \"border-top-color\",\n    \"border-top-left-radius\", \"border-top-right-radius\", \"border-top-style\",\n    \"border-top-width\", \"border-width\", \"bottom\", \"box-decoration-break\",\n    \"box-shadow\", \"box-sizing\", \"break-after\", \"break-before\", \"break-inside\",\n    \"caption-side\", \"clear\", \"clip\", \"color\", \"color-profile\", \"column-count\",\n    \"column-fill\", \"column-gap\", \"column-rule\", \"column-rule-color\",\n    \"column-rule-style\", \"column-rule-width\", \"column-span\", \"column-width\",\n    \"columns\", \"content\", \"counter-increment\", \"counter-reset\", \"crop\", \"cue\",\n    \"cue-after\", \"cue-before\", \"cursor\", \"direction\", \"display\",\n    \"dominant-baseline\", \"drop-initial-after-adjust\",\n    \"drop-initial-after-align\", \"drop-initial-before-adjust\",\n    \"drop-initial-before-align\", \"drop-initial-size\", \"drop-initial-value\",\n    \"elevation\", \"empty-cells\", \"fit\", \"fit-position\", \"flex\", \"flex-basis\",\n    \"flex-direction\", \"flex-flow\", \"flex-grow\", \"flex-shrink\", \"flex-wrap\",\n    \"float\", \"float-offset\", \"flow-from\", \"flow-into\", \"font\", \"font-feature-settings\",\n    \"font-family\", \"font-kerning\", \"font-language-override\", \"font-size\", \"font-size-adjust\",\n    \"font-stretch\", \"font-style\", \"font-synthesis\", \"font-variant\",\n    \"font-variant-alternates\", \"font-variant-caps\", \"font-variant-east-asian\",\n    \"font-variant-ligatures\", \"font-variant-numeric\", \"font-variant-position\",\n    \"font-weight\", \"grid\", \"grid-area\", \"grid-auto-columns\", \"grid-auto-flow\",\n    \"grid-auto-position\", \"grid-auto-rows\", \"grid-column\", \"grid-column-end\",\n    \"grid-column-start\", \"grid-row\", \"grid-row-end\", \"grid-row-start\",\n    \"grid-template\", \"grid-template-areas\", \"grid-template-columns\",\n    \"grid-template-rows\", \"hanging-punctuation\", \"height\", \"hyphens\",\n    \"icon\", \"image-orientation\", \"image-rendering\", \"image-resolution\",\n    \"inline-box-align\", \"justify-content\", \"left\", \"letter-spacing\",\n    \"line-break\", \"line-height\", \"line-stacking\", \"line-stacking-ruby\",\n    \"line-stacking-shift\", \"line-stacking-strategy\", \"list-style\",\n    \"list-style-image\", \"list-style-position\", \"list-style-type\", \"margin\",\n    \"margin-bottom\", \"margin-left\", \"margin-right\", \"margin-top\",\n    \"marker-offset\", \"marks\", \"marquee-direction\", \"marquee-loop\",\n    \"marquee-play-count\", \"marquee-speed\", \"marquee-style\", \"max-height\",\n    \"max-width\", \"min-height\", \"min-width\", \"move-to\", \"nav-down\", \"nav-index\",\n    \"nav-left\", \"nav-right\", \"nav-up\", \"object-fit\", \"object-position\",\n    \"opacity\", \"order\", \"orphans\", \"outline\",\n    \"outline-color\", \"outline-offset\", \"outline-style\", \"outline-width\",\n    \"overflow\", \"overflow-style\", \"overflow-wrap\", \"overflow-x\", \"overflow-y\",\n    \"padding\", \"padding-bottom\", \"padding-left\", \"padding-right\", \"padding-top\",\n    \"page\", \"page-break-after\", \"page-break-before\", \"page-break-inside\",\n    \"page-policy\", \"pause\", \"pause-after\", \"pause-before\", \"perspective\",\n    \"perspective-origin\", \"pitch\", \"pitch-range\", \"play-during\", \"position\",\n    \"presentation-level\", \"punctuation-trim\", \"quotes\", \"region-break-after\",\n    \"region-break-before\", \"region-break-inside\", \"region-fragment\",\n    \"rendering-intent\", \"resize\", \"rest\", \"rest-after\", \"rest-before\", \"richness\",\n    \"right\", \"rotation\", \"rotation-point\", \"ruby-align\", \"ruby-overhang\",\n    \"ruby-position\", \"ruby-span\", \"shape-image-threshold\", \"shape-inside\", \"shape-margin\",\n    \"shape-outside\", \"size\", \"speak\", \"speak-as\", \"speak-header\",\n    \"speak-numeral\", \"speak-punctuation\", \"speech-rate\", \"stress\", \"string-set\",\n    \"tab-size\", \"table-layout\", \"target\", \"target-name\", \"target-new\",\n    \"target-position\", \"text-align\", \"text-align-last\", \"text-decoration\",\n    \"text-decoration-color\", \"text-decoration-line\", \"text-decoration-skip\",\n    \"text-decoration-style\", \"text-emphasis\", \"text-emphasis-color\",\n    \"text-emphasis-position\", \"text-emphasis-style\", \"text-height\",\n    \"text-indent\", \"text-justify\", \"text-outline\", \"text-overflow\", \"text-shadow\",\n    \"text-size-adjust\", \"text-space-collapse\", \"text-transform\", \"text-underline-position\",\n    \"text-wrap\", \"top\", \"transform\", \"transform-origin\", \"transform-style\",\n    \"transition\", \"transition-delay\", \"transition-duration\",\n    \"transition-property\", \"transition-timing-function\", \"unicode-bidi\",\n    \"vertical-align\", \"visibility\", \"voice-balance\", \"voice-duration\",\n    \"voice-family\", \"voice-pitch\", \"voice-range\", \"voice-rate\", \"voice-stress\",\n    \"voice-volume\", \"volume\", \"white-space\", \"widows\", \"width\", \"word-break\",\n    \"word-spacing\", \"word-wrap\", \"z-index\",\n    // SVG-specific\n    \"clip-path\", \"clip-rule\", \"mask\", \"enable-background\", \"filter\", \"flood-color\",\n    \"flood-opacity\", \"lighting-color\", \"stop-color\", \"stop-opacity\", \"pointer-events\",\n    \"color-interpolation\", \"color-interpolation-filters\",\n    \"color-rendering\", \"fill\", \"fill-opacity\", \"fill-rule\", \"image-rendering\",\n    \"marker\", \"marker-end\", \"marker-mid\", \"marker-start\", \"shape-rendering\", \"stroke\",\n    \"stroke-dasharray\", \"stroke-dashoffset\", \"stroke-linecap\", \"stroke-linejoin\",\n    \"stroke-miterlimit\", \"stroke-opacity\", \"stroke-width\", \"text-rendering\",\n    \"baseline-shift\", \"dominant-baseline\", \"glyph-orientation-horizontal\",\n    \"glyph-orientation-vertical\", \"text-anchor\", \"writing-mode\"\n  ], propertyKeywords = keySet(propertyKeywords_);\n\n  var nonStandardPropertyKeywords_ = [\n    \"scrollbar-arrow-color\", \"scrollbar-base-color\", \"scrollbar-dark-shadow-color\",\n    \"scrollbar-face-color\", \"scrollbar-highlight-color\", \"scrollbar-shadow-color\",\n    \"scrollbar-3d-light-color\", \"scrollbar-track-color\", \"shape-inside\",\n    \"searchfield-cancel-button\", \"searchfield-decoration\", \"searchfield-results-button\",\n    \"searchfield-results-decoration\", \"zoom\"\n  ], nonStandardPropertyKeywords = keySet(nonStandardPropertyKeywords_);\n\n  var fontProperties_ = [\n    \"font-family\", \"src\", \"unicode-range\", \"font-variant\", \"font-feature-settings\",\n    \"font-stretch\", \"font-weight\", \"font-style\"\n  ], fontProperties = keySet(fontProperties_);\n\n  var counterDescriptors_ = [\n    \"additive-symbols\", \"fallback\", \"negative\", \"pad\", \"prefix\", \"range\",\n    \"speak-as\", \"suffix\", \"symbols\", \"system\"\n  ], counterDescriptors = keySet(counterDescriptors_);\n\n  var colorKeywords_ = [\n    \"aliceblue\", \"antiquewhite\", \"aqua\", \"aquamarine\", \"azure\", \"beige\",\n    \"bisque\", \"black\", \"blanchedalmond\", \"blue\", \"blueviolet\", \"brown\",\n    \"burlywood\", \"cadetblue\", \"chartreuse\", \"chocolate\", \"coral\", \"cornflowerblue\",\n    \"cornsilk\", \"crimson\", \"cyan\", \"darkblue\", \"darkcyan\", \"darkgoldenrod\",\n    \"darkgray\", \"darkgreen\", \"darkkhaki\", \"darkmagenta\", \"darkolivegreen\",\n    \"darkorange\", \"darkorchid\", \"darkred\", \"darksalmon\", \"darkseagreen\",\n    \"darkslateblue\", \"darkslategray\", \"darkturquoise\", \"darkviolet\",\n    \"deeppink\", \"deepskyblue\", \"dimgray\", \"dodgerblue\", \"firebrick\",\n    \"floralwhite\", \"forestgreen\", \"fuchsia\", \"gainsboro\", \"ghostwhite\",\n    \"gold\", \"goldenrod\", \"gray\", \"grey\", \"green\", \"greenyellow\", \"honeydew\",\n    \"hotpink\", \"indianred\", \"indigo\", \"ivory\", \"khaki\", \"lavender\",\n    \"lavenderblush\", \"lawngreen\", \"lemonchiffon\", \"lightblue\", \"lightcoral\",\n    \"lightcyan\", \"lightgoldenrodyellow\", \"lightgray\", \"lightgreen\", \"lightpink\",\n    \"lightsalmon\", \"lightseagreen\", \"lightskyblue\", \"lightslategray\",\n    \"lightsteelblue\", \"lightyellow\", \"lime\", \"limegreen\", \"linen\", \"magenta\",\n    \"maroon\", \"mediumaquamarine\", \"mediumblue\", \"mediumorchid\", \"mediumpurple\",\n    \"mediumseagreen\", \"mediumslateblue\", \"mediumspringgreen\", \"mediumturquoise\",\n    \"mediumvioletred\", \"midnightblue\", \"mintcream\", \"mistyrose\", \"moccasin\",\n    \"navajowhite\", \"navy\", \"oldlace\", \"olive\", \"olivedrab\", \"orange\", \"orangered\",\n    \"orchid\", \"palegoldenrod\", \"palegreen\", \"paleturquoise\", \"palevioletred\",\n    \"papayawhip\", \"peachpuff\", \"peru\", \"pink\", \"plum\", \"powderblue\",\n    \"purple\", \"rebeccapurple\", \"red\", \"rosybrown\", \"royalblue\", \"saddlebrown\",\n    \"salmon\", \"sandybrown\", \"seagreen\", \"seashell\", \"sienna\", \"silver\", \"skyblue\",\n    \"slateblue\", \"slategray\", \"snow\", \"springgreen\", \"steelblue\", \"tan\",\n    \"teal\", \"thistle\", \"tomato\", \"turquoise\", \"violet\", \"wheat\", \"white\",\n    \"whitesmoke\", \"yellow\", \"yellowgreen\"\n  ], colorKeywords = keySet(colorKeywords_);\n\n  var valueKeywords_ = [\n    \"above\", \"absolute\", \"activeborder\", \"additive\", \"activecaption\", \"afar\",\n    \"after-white-space\", \"ahead\", \"alias\", \"all\", \"all-scroll\", \"alphabetic\", \"alternate\",\n    \"always\", \"amharic\", \"amharic-abegede\", \"antialiased\", \"appworkspace\",\n    \"arabic-indic\", \"armenian\", \"asterisks\", \"attr\", \"auto\", \"avoid\", \"avoid-column\", \"avoid-page\",\n    \"avoid-region\", \"background\", \"backwards\", \"baseline\", \"below\", \"bidi-override\", \"binary\",\n    \"bengali\", \"blink\", \"block\", \"block-axis\", \"bold\", \"bolder\", \"border\", \"border-box\",\n    \"both\", \"bottom\", \"break\", \"break-all\", \"break-word\", \"bullets\", \"button\", \"button-bevel\",\n    \"buttonface\", \"buttonhighlight\", \"buttonshadow\", \"buttontext\", \"calc\", \"cambodian\",\n    \"capitalize\", \"caps-lock-indicator\", \"caption\", \"captiontext\", \"caret\",\n    \"cell\", \"center\", \"checkbox\", \"circle\", \"cjk-decimal\", \"cjk-earthly-branch\",\n    \"cjk-heavenly-stem\", \"cjk-ideographic\", \"clear\", \"clip\", \"close-quote\",\n    \"col-resize\", \"collapse\", \"column\", \"compact\", \"condensed\", \"contain\", \"content\",\n    \"content-box\", \"context-menu\", \"continuous\", \"copy\", \"counter\", \"counters\", \"cover\", \"crop\",\n    \"cross\", \"crosshair\", \"currentcolor\", \"cursive\", \"cyclic\", \"dashed\", \"decimal\",\n    \"decimal-leading-zero\", \"default\", \"default-button\", \"destination-atop\",\n    \"destination-in\", \"destination-out\", \"destination-over\", \"devanagari\",\n    \"disc\", \"discard\", \"disclosure-closed\", \"disclosure-open\", \"document\",\n    \"dot-dash\", \"dot-dot-dash\",\n    \"dotted\", \"double\", \"down\", \"e-resize\", \"ease\", \"ease-in\", \"ease-in-out\", \"ease-out\",\n    \"element\", \"ellipse\", \"ellipsis\", \"embed\", \"end\", \"ethiopic\", \"ethiopic-abegede\",\n    \"ethiopic-abegede-am-et\", \"ethiopic-abegede-gez\", \"ethiopic-abegede-ti-er\",\n    \"ethiopic-abegede-ti-et\", \"ethiopic-halehame-aa-er\",\n    \"ethiopic-halehame-aa-et\", \"ethiopic-halehame-am-et\",\n    \"ethiopic-halehame-gez\", \"ethiopic-halehame-om-et\",\n    \"ethiopic-halehame-sid-et\", \"ethiopic-halehame-so-et\",\n    \"ethiopic-halehame-ti-er\", \"ethiopic-halehame-ti-et\", \"ethiopic-halehame-tig\",\n    \"ethiopic-numeric\", \"ew-resize\", \"expanded\", \"extends\", \"extra-condensed\",\n    \"extra-expanded\", \"fantasy\", \"fast\", \"fill\", \"fixed\", \"flat\", \"flex\", \"footnotes\",\n    \"forwards\", \"from\", \"geometricPrecision\", \"georgian\", \"graytext\", \"groove\",\n    \"gujarati\", \"gurmukhi\", \"hand\", \"hangul\", \"hangul-consonant\", \"hebrew\",\n    \"help\", \"hidden\", \"hide\", \"higher\", \"highlight\", \"highlighttext\",\n    \"hiragana\", \"hiragana-iroha\", \"horizontal\", \"hsl\", \"hsla\", \"icon\", \"ignore\",\n    \"inactiveborder\", \"inactivecaption\", \"inactivecaptiontext\", \"infinite\",\n    \"infobackground\", \"infotext\", \"inherit\", \"initial\", \"inline\", \"inline-axis\",\n    \"inline-block\", \"inline-flex\", \"inline-table\", \"inset\", \"inside\", \"intrinsic\", \"invert\",\n    \"italic\", \"japanese-formal\", \"japanese-informal\", \"justify\", \"kannada\",\n    \"katakana\", \"katakana-iroha\", \"keep-all\", \"khmer\",\n    \"korean-hangul-formal\", \"korean-hanja-formal\", \"korean-hanja-informal\",\n    \"landscape\", \"lao\", \"large\", \"larger\", \"left\", \"level\", \"lighter\",\n    \"line-through\", \"linear\", \"linear-gradient\", \"lines\", \"list-item\", \"listbox\", \"listitem\",\n    \"local\", \"logical\", \"loud\", \"lower\", \"lower-alpha\", \"lower-armenian\",\n    \"lower-greek\", \"lower-hexadecimal\", \"lower-latin\", \"lower-norwegian\",\n    \"lower-roman\", \"lowercase\", \"ltr\", \"malayalam\", \"match\", \"matrix\", \"matrix3d\",\n    \"media-controls-background\", \"media-current-time-display\",\n    \"media-fullscreen-button\", \"media-mute-button\", \"media-play-button\",\n    \"media-return-to-realtime-button\", \"media-rewind-button\",\n    \"media-seek-back-button\", \"media-seek-forward-button\", \"media-slider\",\n    \"media-sliderthumb\", \"media-time-remaining-display\", \"media-volume-slider\",\n    \"media-volume-slider-container\", \"media-volume-sliderthumb\", \"medium\",\n    \"menu\", \"menulist\", \"menulist-button\", \"menulist-text\",\n    \"menulist-textfield\", \"menutext\", \"message-box\", \"middle\", \"min-intrinsic\",\n    \"mix\", \"mongolian\", \"monospace\", \"move\", \"multiple\", \"myanmar\", \"n-resize\",\n    \"narrower\", \"ne-resize\", \"nesw-resize\", \"no-close-quote\", \"no-drop\",\n    \"no-open-quote\", \"no-repeat\", \"none\", \"normal\", \"not-allowed\", \"nowrap\",\n    \"ns-resize\", \"numbers\", \"numeric\", \"nw-resize\", \"nwse-resize\", \"oblique\", \"octal\", \"open-quote\",\n    \"optimizeLegibility\", \"optimizeSpeed\", \"oriya\", \"oromo\", \"outset\",\n    \"outside\", \"outside-shape\", \"overlay\", \"overline\", \"padding\", \"padding-box\",\n    \"painted\", \"page\", \"paused\", \"persian\", \"perspective\", \"plus-darker\", \"plus-lighter\",\n    \"pointer\", \"polygon\", \"portrait\", \"pre\", \"pre-line\", \"pre-wrap\", \"preserve-3d\",\n    \"progress\", \"push-button\", \"radial-gradient\", \"radio\", \"read-only\",\n    \"read-write\", \"read-write-plaintext-only\", \"rectangle\", \"region\",\n    \"relative\", \"repeat\", \"repeating-linear-gradient\",\n    \"repeating-radial-gradient\", \"repeat-x\", \"repeat-y\", \"reset\", \"reverse\",\n    \"rgb\", \"rgba\", \"ridge\", \"right\", \"rotate\", \"rotate3d\", \"rotateX\", \"rotateY\",\n    \"rotateZ\", \"round\", \"row-resize\", \"rtl\", \"run-in\", \"running\",\n    \"s-resize\", \"sans-serif\", \"scale\", \"scale3d\", \"scaleX\", \"scaleY\", \"scaleZ\",\n    \"scroll\", \"scrollbar\", \"se-resize\", \"searchfield\",\n    \"searchfield-cancel-button\", \"searchfield-decoration\",\n    \"searchfield-results-button\", \"searchfield-results-decoration\",\n    \"semi-condensed\", \"semi-expanded\", \"separate\", \"serif\", \"show\", \"sidama\",\n    \"simp-chinese-formal\", \"simp-chinese-informal\", \"single\",\n    \"skew\", \"skewX\", \"skewY\", \"skip-white-space\", \"slide\", \"slider-horizontal\",\n    \"slider-vertical\", \"sliderthumb-horizontal\", \"sliderthumb-vertical\", \"slow\",\n    \"small\", \"small-caps\", \"small-caption\", \"smaller\", \"solid\", \"somali\",\n    \"source-atop\", \"source-in\", \"source-out\", \"source-over\", \"space\", \"spell-out\", \"square\",\n    \"square-button\", \"start\", \"static\", \"status-bar\", \"stretch\", \"stroke\", \"sub\",\n    \"subpixel-antialiased\", \"super\", \"sw-resize\", \"symbolic\", \"symbols\", \"table\",\n    \"table-caption\", \"table-cell\", \"table-column\", \"table-column-group\",\n    \"table-footer-group\", \"table-header-group\", \"table-row\", \"table-row-group\",\n    \"tamil\",\n    \"telugu\", \"text\", \"text-bottom\", \"text-top\", \"textarea\", \"textfield\", \"thai\",\n    \"thick\", \"thin\", \"threeddarkshadow\", \"threedface\", \"threedhighlight\",\n    \"threedlightshadow\", \"threedshadow\", \"tibetan\", \"tigre\", \"tigrinya-er\",\n    \"tigrinya-er-abegede\", \"tigrinya-et\", \"tigrinya-et-abegede\", \"to\", \"top\",\n    \"trad-chinese-formal\", \"trad-chinese-informal\",\n    \"translate\", \"translate3d\", \"translateX\", \"translateY\", \"translateZ\",\n    \"transparent\", \"ultra-condensed\", \"ultra-expanded\", \"underline\", \"up\",\n    \"upper-alpha\", \"upper-armenian\", \"upper-greek\", \"upper-hexadecimal\",\n    \"upper-latin\", \"upper-norwegian\", \"upper-roman\", \"uppercase\", \"urdu\", \"url\",\n    \"var\", \"vertical\", \"vertical-text\", \"visible\", \"visibleFill\", \"visiblePainted\",\n    \"visibleStroke\", \"visual\", \"w-resize\", \"wait\", \"wave\", \"wider\",\n    \"window\", \"windowframe\", \"windowtext\", \"words\", \"x-large\", \"x-small\", \"xor\",\n    \"xx-large\", \"xx-small\"\n  ], valueKeywords = keySet(valueKeywords_);\n\n  var allWords = documentTypes_.concat(mediaTypes_).concat(mediaFeatures_).concat(propertyKeywords_)\n    .concat(nonStandardPropertyKeywords_).concat(colorKeywords_).concat(valueKeywords_);\n  CodeMirror.registerHelper(\"hintWords\", \"css\", allWords);\n\n  function tokenCComment(stream, state) {\n    var maybeEnd = false, ch;\n    while ((ch = stream.next()) != null) {\n      if (maybeEnd && ch == \"/\") {\n        state.tokenize = null;\n        break;\n      }\n      maybeEnd = (ch == \"*\");\n    }\n    return [\"comment\", \"comment\"];\n  }\n\n  function tokenSGMLComment(stream, state) {\n    if (stream.skipTo(\"-->\")) {\n      stream.match(\"-->\");\n      state.tokenize = null;\n    } else {\n      stream.skipToEnd();\n    }\n    return [\"comment\", \"comment\"];\n  }\n\n  CodeMirror.defineMIME(\"text/css\", {\n    documentTypes: documentTypes,\n    mediaTypes: mediaTypes,\n    mediaFeatures: mediaFeatures,\n    propertyKeywords: propertyKeywords,\n    nonStandardPropertyKeywords: nonStandardPropertyKeywords,\n    fontProperties: fontProperties,\n    counterDescriptors: counterDescriptors,\n    colorKeywords: colorKeywords,\n    valueKeywords: valueKeywords,\n    tokenHooks: {\n      \"<\": function(stream, state) {\n        if (!stream.match(\"!--\")) return false;\n        state.tokenize = tokenSGMLComment;\n        return tokenSGMLComment(stream, state);\n      },\n      \"/\": function(stream, state) {\n        if (!stream.eat(\"*\")) return false;\n        state.tokenize = tokenCComment;\n        return tokenCComment(stream, state);\n      }\n    },\n    name: \"css\"\n  });\n\n  CodeMirror.defineMIME(\"text/x-scss\", {\n    mediaTypes: mediaTypes,\n    mediaFeatures: mediaFeatures,\n    propertyKeywords: propertyKeywords,\n    nonStandardPropertyKeywords: nonStandardPropertyKeywords,\n    colorKeywords: colorKeywords,\n    valueKeywords: valueKeywords,\n    fontProperties: fontProperties,\n    allowNested: true,\n    tokenHooks: {\n      \"/\": function(stream, state) {\n        if (stream.eat(\"/\")) {\n          stream.skipToEnd();\n          return [\"comment\", \"comment\"];\n        } else if (stream.eat(\"*\")) {\n          state.tokenize = tokenCComment;\n          return tokenCComment(stream, state);\n        } else {\n          return [\"operator\", \"operator\"];\n        }\n      },\n      \":\": function(stream) {\n        if (stream.match(/\\s*\\{/))\n          return [null, \"{\"];\n        return false;\n      },\n      \"$\": function(stream) {\n        stream.match(/^[\\w-]+/);\n        if (stream.match(/^\\s*:/, false))\n          return [\"variable-2\", \"variable-definition\"];\n        return [\"variable-2\", \"variable\"];\n      },\n      \"#\": function(stream) {\n        if (!stream.eat(\"{\")) return false;\n        return [null, \"interpolation\"];\n      }\n    },\n    name: \"css\",\n    helperType: \"scss\"\n  });\n\n  CodeMirror.defineMIME(\"text/x-less\", {\n    mediaTypes: mediaTypes,\n    mediaFeatures: mediaFeatures,\n    propertyKeywords: propertyKeywords,\n    nonStandardPropertyKeywords: nonStandardPropertyKeywords,\n    colorKeywords: colorKeywords,\n    valueKeywords: valueKeywords,\n    fontProperties: fontProperties,\n    allowNested: true,\n    tokenHooks: {\n      \"/\": function(stream, state) {\n        if (stream.eat(\"/\")) {\n          stream.skipToEnd();\n          return [\"comment\", \"comment\"];\n        } else if (stream.eat(\"*\")) {\n          state.tokenize = tokenCComment;\n          return tokenCComment(stream, state);\n        } else {\n          return [\"operator\", \"operator\"];\n        }\n      },\n      \"@\": function(stream) {\n        if (stream.match(/^(charset|document|font-face|import|(-(moz|ms|o|webkit)-)?keyframes|media|namespace|page|supports)\\b/, false)) return false;\n        stream.eatWhile(/[\\w\\\\\\-]/);\n        if (stream.match(/^\\s*:/, false))\n          return [\"variable-2\", \"variable-definition\"];\n        return [\"variable-2\", \"variable\"];\n      },\n      \"&\": function() {\n        return [\"atom\", \"atom\"];\n      }\n    },\n    name: \"css\",\n    helperType: \"less\"\n  });\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/css/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: CSS mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<link rel=\"stylesheet\" href=\"../../addon/hint/show-hint.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"css.js\"></script>\n<script src=\"../../addon/hint/show-hint.js\"></script>\n<script src=\"../../addon/hint/css-hint.js\"></script>\n<style>.CodeMirror {background: #f8f8f8;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">CSS</a>\n  </ul>\n</div>\n\n<article>\n<h2>CSS mode</h2>\n<form><textarea id=\"code\" name=\"code\">\n/* Some example CSS */\n\n@import url(\"something.css\");\n\nbody {\n  margin: 0;\n  padding: 3em 6em;\n  font-family: tahoma, arial, sans-serif;\n  color: #000;\n}\n\n#navigation a {\n  font-weight: bold;\n  text-decoration: none !important;\n}\n\nh1 {\n  font-size: 2.5em;\n}\n\nh2 {\n  font-size: 1.7em;\n}\n\nh1:before, h2:before {\n  content: \"::\";\n}\n\ncode {\n  font-family: courier, monospace;\n  font-size: 80%;\n  color: #418A8A;\n}\n</textarea></form>\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        extraKeys: {\"Ctrl-Space\": \"autocomplete\"},\n      });\n    </script>\n\n    <p><strong>MIME types defined:</strong> <code>text/css</code>, <code>text/x-scss</code> (<a href=\"scss.html\">demo</a>), <code>text/x-less</code> (<a href=\"less.html\">demo</a>).</p>\n\n    <p><strong>Parsing/Highlighting Tests:</strong> <a href=\"../../test/index.html#css_*\">normal</a>,  <a href=\"../../test/index.html#verbose,css_*\">verbose</a>.</p>\n\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/css/less.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: LESS mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"../../addon/edit/matchbrackets.js\"></script>\n<script src=\"css.js\"></script>\n<style>.CodeMirror {border: 1px solid #ddd; line-height: 1.2;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">LESS</a>\n  </ul>\n</div>\n\n<article>\n<h2>LESS mode</h2>\n<form><textarea id=\"code\" name=\"code\">@media screen and (device-aspect-ratio: 16/9) { … }\n@media screen and (device-aspect-ratio: 1280/720) { … }\n@media screen and (device-aspect-ratio: 2560/1440) { … }\n\nhtml:lang(fr-be)\n\ntr:nth-child(2n+1) /* represents every odd row of an HTML table */\n\nimg:nth-of-type(2n+1) { float: right; }\nimg:nth-of-type(2n) { float: left; }\n\nbody > h2:not(:first-of-type):not(:last-of-type)\n\nhtml|*:not(:link):not(:visited)\n*|*:not(:hover)\np::first-line { text-transform: uppercase }\n\n@namespace foo url(http://www.example.com);\nfoo|h1 { color: blue }  /* first rule */\n\nspan[hello=\"Ocean\"][goodbye=\"Land\"]\n\nE[foo]{\n  padding:65px;\n}\n\ninput[type=\"search\"]::-webkit-search-decoration,\ninput[type=\"search\"]::-webkit-search-cancel-button {\n  -webkit-appearance: none; // Inner-padding issues in Chrome OSX, Safari 5\n}\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner { // Inner padding and border oddities in FF3/4\n  padding: 0;\n  border: 0;\n}\n.btn {\n  // reset here as of 2.0.3 due to Recess property order\n  border-color: #ccc;\n  border-color: rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25);\n}\nfieldset span button, fieldset span input[type=\"file\"] {\n  font-size:12px;\n\tfont-family:Arial, Helvetica, sans-serif;\n}\n\n.rounded-corners (@radius: 5px) {\n  border-radius: @radius;\n  -webkit-border-radius: @radius;\n  -moz-border-radius: @radius;\n}\n\n@import url(\"something.css\");\n\n@light-blue:   hsl(190, 50%, 65%);\n\n#menu {\n  position: absolute;\n  width: 100%;\n  z-index: 3;\n  clear: both;\n  display: block;\n  background-color: @blue;\n  height: 42px;\n  border-top: 2px solid lighten(@alpha-blue, 20%);\n  border-bottom: 2px solid darken(@alpha-blue, 25%);\n  .box-shadow(0, 1px, 8px, 0.6);\n  -moz-box-shadow: 0 0 0 #000; // Because firefox sucks.\n\n  &.docked {\n    background-color: hsla(210, 60%, 40%, 0.4);\n  }\n  &:hover {\n    background-color: @blue;\n  }\n\n  #dropdown {\n    margin: 0 0 0 117px;\n    padding: 0;\n    padding-top: 5px;\n    display: none;\n    width: 190px;\n    border-top: 2px solid @medium;\n    color: @highlight;\n    border: 2px solid darken(@medium, 25%);\n    border-left-color: darken(@medium, 15%);\n    border-right-color: darken(@medium, 15%);\n    border-top-width: 0;\n    background-color: darken(@medium, 10%);\n    ul {\n      padding: 0px;  \n    }\n    li {\n      font-size: 14px;\n      display: block;\n      text-align: left;\n      padding: 0;\n      border: 0;\n      a {\n        display: block;\n        padding: 0px 15px;  \n        text-decoration: none;\n        color: white;  \n        &:hover {\n          background-color: darken(@medium, 15%);\n          text-decoration: none;\n        }\n      }\n    }\n    .border-radius(5px, bottom);\n    .box-shadow(0, 6px, 8px, 0.5);\n  }\n}\n</textarea></form>\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        lineNumbers : true,\n        matchBrackets : true,\n        mode: \"text/x-less\"\n      });\n    </script>\n\n    <p>The LESS mode is a sub-mode of the <a href=\"index.html\">CSS mode</a> (defined in <code>css.js</code>.</p>\n\n    <p><strong>Parsing/Highlighting Tests:</strong> <a href=\"../../test/index.html#less_*\">normal</a>,  <a href=\"../../test/index.html#verbose,less_*\">verbose</a>.</p>\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/css/less_test.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function() {\n  \"use strict\";\n\n  var mode = CodeMirror.getMode({indentUnit: 2}, \"text/x-less\");\n  function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1), \"less\"); }\n\n  MT(\"variable\",\n     \"[variable-2 @base]: [atom #f04615];\",\n     \"[qualifier .class] {\",\n     \"  [property width]: [variable percentage]([number 0.5]); [comment // returns `50%`]\",\n     \"  [property color]: [variable saturate]([variable-2 @base], [number 5%]);\",\n     \"}\");\n\n  MT(\"amp\",\n     \"[qualifier .child], [qualifier .sibling] {\",\n     \"  [qualifier .parent] [atom &] {\",\n     \"    [property color]: [keyword black];\",\n     \"  }\",\n     \"  [atom &] + [atom &] {\",\n     \"    [property color]: [keyword red];\",\n     \"  }\",\n     \"}\");\n\n  MT(\"mixin\",\n     \"[qualifier .mixin] ([variable dark]; [variable-2 @color]) {\",\n     \"  [property color]: [variable darken]([variable-2 @color], [number 10%]);\",\n     \"}\",\n     \"[qualifier .mixin] ([variable light]; [variable-2 @color]) {\",\n     \"  [property color]: [variable lighten]([variable-2 @color], [number 10%]);\",\n     \"}\",\n     \"[qualifier .mixin] ([variable-2 @_]; [variable-2 @color]) {\",\n     \"  [property display]: [atom block];\",\n     \"}\",\n     \"[variable-2 @switch]: [variable light];\",\n     \"[qualifier .class] {\",\n     \"  [qualifier .mixin]([variable-2 @switch]; [atom #888]);\",\n     \"}\");\n\n  MT(\"nest\",\n     \"[qualifier .one] {\",\n     \"  [def @media] ([property width]: [number 400px]) {\",\n     \"    [property font-size]: [number 1.2em];\",\n     \"    [def @media] [attribute print] [keyword and] [property color] {\",\n     \"      [property color]: [keyword blue];\",\n     \"    }\",\n     \"  }\",\n     \"}\");\n})();\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/css/scss.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: SCSS mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"css.js\"></script>\n<style>.CodeMirror {background: #f8f8f8;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">SCSS</a>\n  </ul>\n</div>\n\n<article>\n<h2>SCSS mode</h2>\n<form><textarea id=\"code\" name=\"code\">\n/* Some example SCSS */\n\n@import \"compass/css3\";\n$variable: #333;\n\n$blue: #3bbfce;\n$margin: 16px;\n\n.content-navigation {\n  #nested {\n    background-color: black;\n  }\n  border-color: $blue;\n  color:\n    darken($blue, 9%);\n}\n\n.border {\n  padding: $margin / 2;\n  margin: $margin / 2;\n  border-color: $blue;\n}\n\n@mixin table-base {\n  th {\n    text-align: center;\n    font-weight: bold;\n  }\n  td, th {padding: 2px}\n}\n\ntable.hl {\n  margin: 2em 0;\n  td.ln {\n    text-align: right;\n  }\n}\n\nli {\n  font: {\n    family: serif;\n    weight: bold;\n    size: 1.2em;\n  }\n}\n\n@mixin left($dist) {\n  float: left;\n  margin-left: $dist;\n}\n\n#data {\n  @include left(10px);\n  @include table-base;\n}\n\n.source {\n  @include flow-into(target);\n  border: 10px solid green;\n  margin: 20px;\n  width: 200px; }\n\n.new-container {\n  @include flow-from(target);\n  border: 10px solid red;\n  margin: 20px;\n  width: 200px; }\n\nbody {\n  margin: 0;\n  padding: 3em 6em;\n  font-family: tahoma, arial, sans-serif;\n  color: #000;\n}\n\n@mixin yellow() {\n  background: yellow;\n}\n\n.big {\n  font-size: 14px;\n}\n\n.nested {\n  @include border-radius(3px);\n  @extend .big;\n  p {\n    background: whitesmoke;\n    a {\n      color: red;\n    }\n  }\n}\n\n#navigation a {\n  font-weight: bold;\n  text-decoration: none !important;\n}\n\nh1 {\n  font-size: 2.5em;\n}\n\nh2 {\n  font-size: 1.7em;\n}\n\nh1:before, h2:before {\n  content: \"::\";\n}\n\ncode {\n  font-family: courier, monospace;\n  font-size: 80%;\n  color: #418A8A;\n}\n</textarea></form>\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        lineNumbers: true,\n        matchBrackets: true,\n        mode: \"text/x-scss\"\n      });\n    </script>\n\n    <p>The SCSS mode is a sub-mode of the <a href=\"index.html\">CSS mode</a> (defined in <code>css.js</code>.</p>\n\n    <p><strong>Parsing/Highlighting Tests:</strong> <a href=\"../../test/index.html#scss_*\">normal</a>,  <a href=\"../../test/index.html#verbose,scss_*\">verbose</a>.</p>\n\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/css/scss_test.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function() {\n  var mode = CodeMirror.getMode({indentUnit: 2}, \"text/x-scss\");\n  function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1), \"scss\"); }\n\n  MT('url_with_quotation',\n    \"[tag foo] { [property background]:[atom url]([string test.jpg]) }\");\n\n  MT('url_with_double_quotes',\n    \"[tag foo] { [property background]:[atom url]([string \\\"test.jpg\\\"]) }\");\n\n  MT('url_with_single_quotes',\n    \"[tag foo] { [property background]:[atom url]([string \\'test.jpg\\']) }\");\n\n  MT('string',\n    \"[def @import] [string \\\"compass/css3\\\"]\");\n\n  MT('important_keyword',\n    \"[tag foo] { [property background]:[atom url]([string \\'test.jpg\\']) [keyword !important] }\");\n\n  MT('variable',\n    \"[variable-2 $blue]:[atom #333]\");\n\n  MT('variable_as_attribute',\n    \"[tag foo] { [property color]:[variable-2 $blue] }\");\n\n  MT('numbers',\n    \"[tag foo] { [property padding]:[number 10px] [number 10] [number 10em] [number 8in] }\");\n\n  MT('number_percentage',\n    \"[tag foo] { [property width]:[number 80%] }\");\n\n  MT('selector',\n    \"[builtin #hello][qualifier .world]{}\");\n\n  MT('singleline_comment',\n    \"[comment // this is a comment]\");\n\n  MT('multiline_comment',\n    \"[comment /*foobar*/]\");\n\n  MT('attribute_with_hyphen',\n    \"[tag foo] { [property font-size]:[number 10px] }\");\n\n  MT('string_after_attribute',\n    \"[tag foo] { [property content]:[string \\\"::\\\"] }\");\n\n  MT('directives',\n    \"[def @include] [qualifier .mixin]\");\n\n  MT('basic_structure',\n    \"[tag p] { [property background]:[keyword red]; }\");\n\n  MT('nested_structure',\n    \"[tag p] { [tag a] { [property color]:[keyword red]; } }\");\n\n  MT('mixin',\n    \"[def @mixin] [tag table-base] {}\");\n\n  MT('number_without_semicolon',\n    \"[tag p] {[property width]:[number 12]}\",\n    \"[tag a] {[property color]:[keyword red];}\");\n\n  MT('atom_in_nested_block',\n    \"[tag p] { [tag a] { [property color]:[atom #000]; } }\");\n\n  MT('interpolation_in_property',\n    \"[tag foo] { #{[variable-2 $hello]}:[number 2]; }\");\n\n  MT('interpolation_in_selector',\n    \"[tag foo]#{[variable-2 $hello]} { [property color]:[atom #000]; }\");\n\n  MT('interpolation_error',\n    \"[tag foo]#{[error foo]} { [property color]:[atom #000]; }\");\n\n  MT(\"divide_operator\",\n    \"[tag foo] { [property width]:[number 4] [operator /] [number 2] }\");\n\n  MT('nested_structure_with_id_selector',\n    \"[tag p] { [builtin #hello] { [property color]:[keyword red]; } }\");\n\n  MT('indent_mixin',\n     \"[def @mixin] [tag container] (\",\n     \"  [variable-2 $a]: [number 10],\",\n     \"  [variable-2 $b]: [number 10])\",\n     \"{}\");\n\n  MT('indent_nested',\n     \"[tag foo] {\",\n     \"  [tag bar] {\",\n     \"  }\",\n     \"}\");\n\n  MT('indent_parentheses',\n     \"[tag foo] {\",\n     \"  [property color]: [variable darken]([variable-2 $blue],\",\n     \"    [number 9%]);\",\n     \"}\");\n\n  MT('indent_vardef',\n     \"[variable-2 $name]:\",\n     \"  [string 'val'];\",\n     \"[tag tag] {\",\n     \"  [tag inner] {\",\n     \"    [property margin]: [number 3px];\",\n     \"  }\",\n     \"}\");\n})();\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/css/test.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function() {\n  var mode = CodeMirror.getMode({indentUnit: 2}, \"css\");\n  function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); }\n\n  // Error, because \"foobarhello\" is neither a known type or property, but\n  // property was expected (after \"and\"), and it should be in parenthese.\n  MT(\"atMediaUnknownType\",\n     \"[def @media] [attribute screen] [keyword and] [error foobarhello] { }\");\n\n  // Soft error, because \"foobarhello\" is not a known property or type.\n  MT(\"atMediaUnknownProperty\",\n     \"[def @media] [attribute screen] [keyword and] ([error foobarhello]) { }\");\n\n  // Make sure nesting works with media queries\n  MT(\"atMediaMaxWidthNested\",\n     \"[def @media] [attribute screen] [keyword and] ([property max-width]: [number 25px]) { [tag foo] { } }\");\n\n  MT(\"tagSelector\",\n     \"[tag foo] { }\");\n\n  MT(\"classSelector\",\n     \"[qualifier .foo-bar_hello] { }\");\n\n  MT(\"idSelector\",\n     \"[builtin #foo] { [error #foo] }\");\n\n  MT(\"tagSelectorUnclosed\",\n     \"[tag foo] { [property margin]: [number 0] } [tag bar] { }\");\n\n  MT(\"tagStringNoQuotes\",\n     \"[tag foo] { [property font-family]: [variable hello] [variable world]; }\");\n\n  MT(\"tagStringDouble\",\n     \"[tag foo] { [property font-family]: [string \\\"hello world\\\"]; }\");\n\n  MT(\"tagStringSingle\",\n     \"[tag foo] { [property font-family]: [string 'hello world']; }\");\n\n  MT(\"tagColorKeyword\",\n     \"[tag foo] {\",\n     \"  [property color]: [keyword black];\",\n     \"  [property color]: [keyword navy];\",\n     \"  [property color]: [keyword yellow];\",\n     \"}\");\n\n  MT(\"tagColorHex3\",\n     \"[tag foo] { [property background]: [atom #fff]; }\");\n\n  MT(\"tagColorHex6\",\n     \"[tag foo] { [property background]: [atom #ffffff]; }\");\n\n  MT(\"tagColorHex4\",\n     \"[tag foo] { [property background]: [atom&error #ffff]; }\");\n\n  MT(\"tagColorHexInvalid\",\n     \"[tag foo] { [property background]: [atom&error #ffg]; }\");\n\n  MT(\"tagNegativeNumber\",\n     \"[tag foo] { [property margin]: [number -5px]; }\");\n\n  MT(\"tagPositiveNumber\",\n     \"[tag foo] { [property padding]: [number 5px]; }\");\n\n  MT(\"tagVendor\",\n     \"[tag foo] { [meta -foo-][property box-sizing]: [meta -foo-][atom border-box]; }\");\n\n  MT(\"tagBogusProperty\",\n     \"[tag foo] { [property&error barhelloworld]: [number 0]; }\");\n\n  MT(\"tagTwoProperties\",\n     \"[tag foo] { [property margin]: [number 0]; [property padding]: [number 0]; }\");\n\n  MT(\"tagTwoPropertiesURL\",\n     \"[tag foo] { [property background]: [atom url]([string //example.com/foo.png]); [property padding]: [number 0]; }\");\n\n  MT(\"commentSGML\",\n     \"[comment <!--comment-->]\");\n\n  MT(\"commentSGML2\",\n     \"[comment <!--comment]\",\n     \"[comment -->] [tag div] {}\");\n\n  MT(\"indent_tagSelector\",\n     \"[tag strong], [tag em] {\",\n     \"  [property background]: [atom rgba](\",\n     \"    [number 255], [number 255], [number 0], [number .2]\",\n     \"  );\",\n     \"}\");\n\n  MT(\"indent_atMedia\",\n     \"[def @media] {\",\n     \"  [tag foo] {\",\n     \"    [property color]:\",\n     \"      [keyword yellow];\",\n     \"  }\",\n     \"}\");\n\n  MT(\"indent_comma\",\n     \"[tag foo] {\",\n     \"  [property font-family]: [variable verdana],\",\n     \"    [atom sans-serif];\",\n     \"}\");\n\n  MT(\"indent_parentheses\",\n     \"[tag foo]:[variable-3 before] {\",\n     \"  [property background]: [atom url](\",\n     \"[string     blahblah]\",\n     \"[string     etc]\",\n     \"[string   ]) [keyword !important];\",\n     \"}\");\n\n  MT(\"font_face\",\n     \"[def @font-face] {\",\n     \"  [property font-family]: [string 'myfont'];\",\n     \"  [error nonsense]: [string 'abc'];\",\n     \"  [property src]: [atom url]([string http://blah]),\",\n     \"    [atom url]([string http://foo]);\",\n     \"}\");\n\n  MT(\"empty_url\",\n     \"[def @import] [tag url]() [tag screen];\");\n\n  MT(\"parens\",\n     \"[qualifier .foo] {\",\n     \"  [property background-image]: [variable fade]([atom #000], [number 20%]);\",\n     \"  [property border-image]: [atom linear-gradient](\",\n     \"    [atom to] [atom bottom],\",\n     \"    [variable fade]([atom #000], [number 20%]) [number 0%],\",\n     \"    [variable fade]([atom #000], [number 20%]) [number 100%]\",\n     \"  );\",\n     \"}\");\n\n  MT(\"css_variable\",\n     \":[variable-3 root] {\",\n     \"  [variable-2 --main-color]: [atom #06c];\",\n     \"}\",\n     \"[tag h1][builtin #foo] {\",\n     \"  [property color]: [atom var]([variable-2 --main-color]);\",\n     \"}\");\n\n  MT(\"supports\",\n     \"[def @supports] ([keyword not] (([property text-align-last]: [atom justify]) [keyword or] ([meta -moz-][property text-align-last]: [atom justify])) {\",\n     \"  [property text-align-last]: [atom justify];\",\n     \"}\");\n\n   MT(\"document\",\n      \"[def @document] [tag url]([string http://blah]),\",\n      \"  [tag url-prefix]([string https://]),\",\n      \"  [tag domain]([string blah.com]),\",\n      \"  [tag regexp]([string \\\".*blah.+\\\"]) {\",\n      \"    [builtin #id] {\",\n      \"      [property background-color]: [keyword white];\",\n      \"    }\",\n      \"    [tag foo] {\",\n      \"      [property font-family]: [variable Verdana], [atom sans-serif];\",\n      \"    }\",\n      \"  }\");\n\n   MT(\"document_url\",\n      \"[def @document] [tag url]([string http://blah]) { [qualifier .class] { } }\");\n\n   MT(\"document_urlPrefix\",\n      \"[def @document] [tag url-prefix]([string https://]) { [builtin #id] { } }\");\n\n   MT(\"document_domain\",\n      \"[def @document] [tag domain]([string blah.com]) { [tag foo] { } }\");\n\n   MT(\"document_regexp\",\n      \"[def @document] [tag regexp]([string \\\".*blah.+\\\"]) { [builtin #id] { } }\");\n\n   MT(\"counter-style\",\n      \"[def @counter-style] [variable binary] {\",\n      \"  [property system]: [atom numeric];\",\n      \"  [property symbols]: [number 0] [number 1];\",\n      \"  [property suffix]: [string \\\".\\\"];\",\n      \"  [property range]: [atom infinite];\",\n      \"  [property speak-as]: [atom numeric];\",\n      \"}\");\n\n   MT(\"counter-style-additive-symbols\",\n      \"[def @counter-style] [variable simple-roman] {\",\n      \"  [property system]: [atom additive];\",\n      \"  [property additive-symbols]: [number 10] [variable X], [number 5] [variable V], [number 1] [variable I];\",\n      \"  [property range]: [number 1] [number 49];\",\n      \"}\");\n\n   MT(\"counter-style-use\",\n      \"[tag ol][qualifier .roman] { [property list-style]: [variable simple-roman]; }\");\n\n   MT(\"counter-style-symbols\",\n      \"[tag ol] { [property list-style]: [atom symbols]([atom cyclic] [string \\\"*\\\"] [string \\\"\\\\2020\\\"] [string \\\"\\\\2021\\\"] [string \\\"\\\\A7\\\"]); }\");\n})();\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/cypher/cypher.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n// By the Neo4j Team and contributors.\n// https://github.com/neo4j-contrib/CodeMirror\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n  var wordRegexp = function(words) {\n    return new RegExp(\"^(?:\" + words.join(\"|\") + \")$\", \"i\");\n  };\n\n  CodeMirror.defineMode(\"cypher\", function(config) {\n    var tokenBase = function(stream/*, state*/) {\n      var ch = stream.next(), curPunc = null;\n      if (ch === \"\\\"\" || ch === \"'\") {\n        stream.match(/.+?[\"']/);\n        return \"string\";\n      }\n      if (/[{}\\(\\),\\.;\\[\\]]/.test(ch)) {\n        curPunc = ch;\n        return \"node\";\n      } else if (ch === \"/\" && stream.eat(\"/\")) {\n        stream.skipToEnd();\n        return \"comment\";\n      } else if (operatorChars.test(ch)) {\n        stream.eatWhile(operatorChars);\n        return null;\n      } else {\n        stream.eatWhile(/[_\\w\\d]/);\n        if (stream.eat(\":\")) {\n          stream.eatWhile(/[\\w\\d_\\-]/);\n          return \"atom\";\n        }\n        var word = stream.current();\n        if (funcs.test(word)) return \"builtin\";\n        if (preds.test(word)) return \"def\";\n        if (keywords.test(word)) return \"keyword\";\n        return \"variable\";\n      }\n    };\n    var pushContext = function(state, type, col) {\n      return state.context = {\n        prev: state.context,\n        indent: state.indent,\n        col: col,\n        type: type\n      };\n    };\n    var popContext = function(state) {\n      state.indent = state.context.indent;\n      return state.context = state.context.prev;\n    };\n    var indentUnit = config.indentUnit;\n    var curPunc;\n    var funcs = wordRegexp([\"abs\", \"acos\", \"allShortestPaths\", \"asin\", \"atan\", \"atan2\", \"avg\", \"ceil\", \"coalesce\", \"collect\", \"cos\", \"cot\", \"count\", \"degrees\", \"e\", \"endnode\", \"exp\", \"extract\", \"filter\", \"floor\", \"haversin\", \"head\", \"id\", \"keys\", \"labels\", \"last\", \"left\", \"length\", \"log\", \"log10\", \"lower\", \"ltrim\", \"max\", \"min\", \"node\", \"nodes\", \"percentileCont\", \"percentileDisc\", \"pi\", \"radians\", \"rand\", \"range\", \"reduce\", \"rel\", \"relationship\", \"relationships\", \"replace\", \"right\", \"round\", \"rtrim\", \"shortestPath\", \"sign\", \"sin\", \"split\", \"sqrt\", \"startnode\", \"stdev\", \"stdevp\", \"str\", \"substring\", \"sum\", \"tail\", \"tan\", \"timestamp\", \"toFloat\", \"toInt\", \"trim\", \"type\", \"upper\"]);\n    var preds = wordRegexp([\"all\", \"and\", \"any\", \"has\", \"in\", \"none\", \"not\", \"or\", \"single\", \"xor\"]);\n    var keywords = wordRegexp([\"as\", \"asc\", \"ascending\", \"assert\", \"by\", \"case\", \"commit\", \"constraint\", \"create\", \"csv\", \"cypher\", \"delete\", \"desc\", \"descending\", \"distinct\", \"drop\", \"else\", \"end\", \"explain\", \"false\", \"fieldterminator\", \"foreach\", \"from\", \"headers\", \"in\", \"index\", \"is\", \"limit\", \"load\", \"match\", \"merge\", \"null\", \"on\", \"optional\", \"order\", \"periodic\", \"profile\", \"remove\", \"return\", \"scan\", \"set\", \"skip\", \"start\", \"then\", \"true\", \"union\", \"unique\", \"unwind\", \"using\", \"when\", \"where\", \"with\"]);\n    var operatorChars = /[*+\\-<>=&|~%^]/;\n\n    return {\n      startState: function(/*base*/) {\n        return {\n          tokenize: tokenBase,\n          context: null,\n          indent: 0,\n          col: 0\n        };\n      },\n      token: function(stream, state) {\n        if (stream.sol()) {\n          if (state.context && (state.context.align == null)) {\n            state.context.align = false;\n          }\n          state.indent = stream.indentation();\n        }\n        if (stream.eatSpace()) {\n          return null;\n        }\n        var style = state.tokenize(stream, state);\n        if (style !== \"comment\" && state.context && (state.context.align == null) && state.context.type !== \"pattern\") {\n          state.context.align = true;\n        }\n        if (curPunc === \"(\") {\n          pushContext(state, \")\", stream.column());\n        } else if (curPunc === \"[\") {\n          pushContext(state, \"]\", stream.column());\n        } else if (curPunc === \"{\") {\n          pushContext(state, \"}\", stream.column());\n        } else if (/[\\]\\}\\)]/.test(curPunc)) {\n          while (state.context && state.context.type === \"pattern\") {\n            popContext(state);\n          }\n          if (state.context && curPunc === state.context.type) {\n            popContext(state);\n          }\n        } else if (curPunc === \".\" && state.context && state.context.type === \"pattern\") {\n          popContext(state);\n        } else if (/atom|string|variable/.test(style) && state.context) {\n          if (/[\\}\\]]/.test(state.context.type)) {\n            pushContext(state, \"pattern\", stream.column());\n          } else if (state.context.type === \"pattern\" && !state.context.align) {\n            state.context.align = true;\n            state.context.col = stream.column();\n          }\n        }\n        return style;\n      },\n      indent: function(state, textAfter) {\n        var firstChar = textAfter && textAfter.charAt(0);\n        var context = state.context;\n        if (/[\\]\\}]/.test(firstChar)) {\n          while (context && context.type === \"pattern\") {\n            context = context.prev;\n          }\n        }\n        var closing = context && firstChar === context.type;\n        if (!context) return 0;\n        if (context.type === \"keywords\") return CodeMirror.commands.newlineAndIndent;\n        if (context.align) return context.col + (closing ? 0 : 1);\n        return context.indent + (closing ? 0 : indentUnit);\n      }\n    };\n  });\n\n  CodeMirror.modeExtensions[\"cypher\"] = {\n    autoFormatLineBreaks: function(text) {\n      var i, lines, reProcessedPortion;\n      var lines = text.split(\"\\n\");\n      var reProcessedPortion = /\\s+\\b(return|where|order by|match|with|skip|limit|create|delete|set)\\b\\s/g;\n      for (var i = 0; i < lines.length; i++)\n        lines[i] = lines[i].replace(reProcessedPortion, \" \\n$1 \").trim();\n      return lines.join(\"\\n\");\n    }\n  };\n\n  CodeMirror.defineMIME(\"application/x-cypher-query\", \"cypher\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/cypher/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Cypher Mode for CodeMirror</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\" />\n<link rel=\"stylesheet\" href=\"../../theme/neo.css\" />\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"cypher.js\"></script>\n<style>\n.CodeMirror {\n    border-top: 1px solid black;\n    border-bottom: 1px solid black;\n}\n        </style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Cypher Mode for CodeMirror</a>\n  </ul>\n</div>\n\n<article>\n<h2>Cypher Mode for CodeMirror</h2>\n<form>\n            <textarea id=\"code\" name=\"code\">// Cypher Mode for CodeMirror, using the neo theme\nMATCH (joe { name: 'Joe' })-[:knows*2..2]-(friend_of_friend)\nWHERE NOT (joe)-[:knows]-(friend_of_friend)\nRETURN friend_of_friend.name, COUNT(*)\nORDER BY COUNT(*) DESC , friend_of_friend.name\n</textarea>\n            </form>\n            <p><strong>MIME types defined:</strong> \n            <code><a href=\"?mime=application/x-cypher-query\">application/x-cypher-query</a></code>\n        </p>\n<script>\nwindow.onload = function() {\n  var mime = 'application/x-cypher-query';\n  // get mime type\n  if (window.location.href.indexOf('mime=') > -1) {\n    mime = window.location.href.substr(window.location.href.indexOf('mime=') + 5);\n  }\n  window.editor = CodeMirror.fromTextArea(document.getElementById('code'), {\n    mode: mime,\n    indentWithTabs: true,\n    smartIndent: true,\n    lineNumbers: true,\n    matchBrackets : true,\n    autofocus: true,\n    theme: 'neo'\n  });\n};\n</script>\n\n</article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/d/d.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"d\", function(config, parserConfig) {\n  var indentUnit = config.indentUnit,\n      statementIndentUnit = parserConfig.statementIndentUnit || indentUnit,\n      keywords = parserConfig.keywords || {},\n      builtin = parserConfig.builtin || {},\n      blockKeywords = parserConfig.blockKeywords || {},\n      atoms = parserConfig.atoms || {},\n      hooks = parserConfig.hooks || {},\n      multiLineStrings = parserConfig.multiLineStrings;\n  var isOperatorChar = /[+\\-*&%=<>!?|\\/]/;\n\n  var curPunc;\n\n  function tokenBase(stream, state) {\n    var ch = stream.next();\n    if (hooks[ch]) {\n      var result = hooks[ch](stream, state);\n      if (result !== false) return result;\n    }\n    if (ch == '\"' || ch == \"'\" || ch == \"`\") {\n      state.tokenize = tokenString(ch);\n      return state.tokenize(stream, state);\n    }\n    if (/[\\[\\]{}\\(\\),;\\:\\.]/.test(ch)) {\n      curPunc = ch;\n      return null;\n    }\n    if (/\\d/.test(ch)) {\n      stream.eatWhile(/[\\w\\.]/);\n      return \"number\";\n    }\n    if (ch == \"/\") {\n      if (stream.eat(\"+\")) {\n        state.tokenize = tokenComment;\n        return tokenNestedComment(stream, state);\n      }\n      if (stream.eat(\"*\")) {\n        state.tokenize = tokenComment;\n        return tokenComment(stream, state);\n      }\n      if (stream.eat(\"/\")) {\n        stream.skipToEnd();\n        return \"comment\";\n      }\n    }\n    if (isOperatorChar.test(ch)) {\n      stream.eatWhile(isOperatorChar);\n      return \"operator\";\n    }\n    stream.eatWhile(/[\\w\\$_\\xa1-\\uffff]/);\n    var cur = stream.current();\n    if (keywords.propertyIsEnumerable(cur)) {\n      if (blockKeywords.propertyIsEnumerable(cur)) curPunc = \"newstatement\";\n      return \"keyword\";\n    }\n    if (builtin.propertyIsEnumerable(cur)) {\n      if (blockKeywords.propertyIsEnumerable(cur)) curPunc = \"newstatement\";\n      return \"builtin\";\n    }\n    if (atoms.propertyIsEnumerable(cur)) return \"atom\";\n    return \"variable\";\n  }\n\n  function tokenString(quote) {\n    return function(stream, state) {\n      var escaped = false, next, end = false;\n      while ((next = stream.next()) != null) {\n        if (next == quote && !escaped) {end = true; break;}\n        escaped = !escaped && next == \"\\\\\";\n      }\n      if (end || !(escaped || multiLineStrings))\n        state.tokenize = null;\n      return \"string\";\n    };\n  }\n\n  function tokenComment(stream, state) {\n    var maybeEnd = false, ch;\n    while (ch = stream.next()) {\n      if (ch == \"/\" && maybeEnd) {\n        state.tokenize = null;\n        break;\n      }\n      maybeEnd = (ch == \"*\");\n    }\n    return \"comment\";\n  }\n\n  function tokenNestedComment(stream, state) {\n    var maybeEnd = false, ch;\n    while (ch = stream.next()) {\n      if (ch == \"/\" && maybeEnd) {\n        state.tokenize = null;\n        break;\n      }\n      maybeEnd = (ch == \"+\");\n    }\n    return \"comment\";\n  }\n\n  function Context(indented, column, type, align, prev) {\n    this.indented = indented;\n    this.column = column;\n    this.type = type;\n    this.align = align;\n    this.prev = prev;\n  }\n  function pushContext(state, col, type) {\n    var indent = state.indented;\n    if (state.context && state.context.type == \"statement\")\n      indent = state.context.indented;\n    return state.context = new Context(indent, col, type, null, state.context);\n  }\n  function popContext(state) {\n    var t = state.context.type;\n    if (t == \")\" || t == \"]\" || t == \"}\")\n      state.indented = state.context.indented;\n    return state.context = state.context.prev;\n  }\n\n  // Interface\n\n  return {\n    startState: function(basecolumn) {\n      return {\n        tokenize: null,\n        context: new Context((basecolumn || 0) - indentUnit, 0, \"top\", false),\n        indented: 0,\n        startOfLine: true\n      };\n    },\n\n    token: function(stream, state) {\n      var ctx = state.context;\n      if (stream.sol()) {\n        if (ctx.align == null) ctx.align = false;\n        state.indented = stream.indentation();\n        state.startOfLine = true;\n      }\n      if (stream.eatSpace()) return null;\n      curPunc = null;\n      var style = (state.tokenize || tokenBase)(stream, state);\n      if (style == \"comment\" || style == \"meta\") return style;\n      if (ctx.align == null) ctx.align = true;\n\n      if ((curPunc == \";\" || curPunc == \":\" || curPunc == \",\") && ctx.type == \"statement\") popContext(state);\n      else if (curPunc == \"{\") pushContext(state, stream.column(), \"}\");\n      else if (curPunc == \"[\") pushContext(state, stream.column(), \"]\");\n      else if (curPunc == \"(\") pushContext(state, stream.column(), \")\");\n      else if (curPunc == \"}\") {\n        while (ctx.type == \"statement\") ctx = popContext(state);\n        if (ctx.type == \"}\") ctx = popContext(state);\n        while (ctx.type == \"statement\") ctx = popContext(state);\n      }\n      else if (curPunc == ctx.type) popContext(state);\n      else if (((ctx.type == \"}\" || ctx.type == \"top\") && curPunc != ';') || (ctx.type == \"statement\" && curPunc == \"newstatement\"))\n        pushContext(state, stream.column(), \"statement\");\n      state.startOfLine = false;\n      return style;\n    },\n\n    indent: function(state, textAfter) {\n      if (state.tokenize != tokenBase && state.tokenize != null) return CodeMirror.Pass;\n      var ctx = state.context, firstChar = textAfter && textAfter.charAt(0);\n      if (ctx.type == \"statement\" && firstChar == \"}\") ctx = ctx.prev;\n      var closing = firstChar == ctx.type;\n      if (ctx.type == \"statement\") return ctx.indented + (firstChar == \"{\" ? 0 : statementIndentUnit);\n      else if (ctx.align) return ctx.column + (closing ? 0 : 1);\n      else return ctx.indented + (closing ? 0 : indentUnit);\n    },\n\n    electricChars: \"{}\"\n  };\n});\n\n  function words(str) {\n    var obj = {}, words = str.split(\" \");\n    for (var i = 0; i < words.length; ++i) obj[words[i]] = true;\n    return obj;\n  }\n\n  var blockKeywords = \"body catch class do else enum for foreach foreach_reverse if in interface mixin \" +\n                      \"out scope struct switch try union unittest version while with\";\n\n  CodeMirror.defineMIME(\"text/x-d\", {\n    name: \"d\",\n    keywords: words(\"abstract alias align asm assert auto break case cast cdouble cent cfloat const continue \" +\n                    \"debug default delegate delete deprecated export extern final finally function goto immutable \" +\n                    \"import inout invariant is lazy macro module new nothrow override package pragma private \" +\n                    \"protected public pure ref return shared short static super synchronized template this \" +\n                    \"throw typedef typeid typeof volatile __FILE__ __LINE__ __gshared __traits __vector __parameters \" +\n                    blockKeywords),\n    blockKeywords: words(blockKeywords),\n    builtin: words(\"bool byte char creal dchar double float idouble ifloat int ireal long real short ubyte \" +\n                   \"ucent uint ulong ushort wchar wstring void size_t sizediff_t\"),\n    atoms: words(\"exit failure success true false null\"),\n    hooks: {\n      \"@\": function(stream, _state) {\n        stream.eatWhile(/[\\w\\$_]/);\n        return \"meta\";\n      }\n    }\n  });\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/d/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: D mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"../../addon/edit/matchbrackets.js\"></script>\n<script src=\"d.js\"></script>\n<style>.CodeMirror {border: 2px inset #dee;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">D</a>\n  </ul>\n</div>\n\n<article>\n<h2>D mode</h2>\n<form><textarea id=\"code\" name=\"code\">\n/* D demo code // copied from phobos/sd/metastrings.d */\n// Written in the D programming language.\n\n/**\nTemplates with which to do compile-time manipulation of strings.\n\nMacros:\n WIKI = Phobos/StdMetastrings\n\nCopyright: Copyright Digital Mars 2007 - 2009.\nLicense:   <a href=\"http://www.boost.org/LICENSE_1_0.txt\">Boost License 1.0</a>.\nAuthors:   $(WEB digitalmars.com, Walter Bright),\n           Don Clugston\nSource:    $(PHOBOSSRC std/_metastrings.d)\n*/\n/*\n         Copyright Digital Mars 2007 - 2009.\nDistributed under the Boost Software License, Version 1.0.\n   (See accompanying file LICENSE_1_0.txt or copy at\n         http://www.boost.org/LICENSE_1_0.txt)\n */\nmodule std.metastrings;\n\n/**\nFormats constants into a string at compile time.  Analogous to $(XREF\nstring,format).\n\nParameters:\n\nA = tuple of constants, which can be strings, characters, or integral\n    values.\n\nFormats:\n *    The formats supported are %s for strings, and %%\n *    for the % character.\nExample:\n---\nimport std.metastrings;\nimport std.stdio;\n\nvoid main()\n{\n  string s = Format!(\"Arg %s = %s\", \"foo\", 27);\n  writefln(s); // \"Arg foo = 27\"\n}\n * ---\n */\n\ntemplate Format(A...)\n{\n    static if (A.length == 0)\n        enum Format = \"\";\n    else static if (is(typeof(A[0]) : const(char)[]))\n        enum Format = FormatString!(A[0], A[1..$]);\n    else\n        enum Format = toStringNow!(A[0]) ~ Format!(A[1..$]);\n}\n\ntemplate FormatString(const(char)[] F, A...)\n{\n    static if (F.length == 0)\n        enum FormatString = Format!(A);\n    else static if (F.length == 1)\n        enum FormatString = F[0] ~ Format!(A);\n    else static if (F[0..2] == \"%s\")\n        enum FormatString\n            = toStringNow!(A[0]) ~ FormatString!(F[2..$],A[1..$]);\n    else static if (F[0..2] == \"%%\")\n        enum FormatString = \"%\" ~ FormatString!(F[2..$],A);\n    else\n    {\n        static assert(F[0] != '%', \"unrecognized format %\" ~ F[1]);\n        enum FormatString = F[0] ~ FormatString!(F[1..$],A);\n    }\n}\n\nunittest\n{\n    auto s = Format!(\"hel%slo\", \"world\", -138, 'c', true);\n    assert(s == \"helworldlo-138ctrue\", \"[\" ~ s ~ \"]\");\n}\n\n/**\n * Convert constant argument to a string.\n */\n\ntemplate toStringNow(ulong v)\n{\n    static if (v < 10)\n        enum toStringNow = \"\" ~ cast(char)(v + '0');\n    else\n        enum toStringNow = toStringNow!(v / 10) ~ toStringNow!(v % 10);\n}\n\nunittest\n{\n    static assert(toStringNow!(1uL << 62) == \"4611686018427387904\");\n}\n\n/// ditto\ntemplate toStringNow(long v)\n{\n    static if (v < 0)\n        enum toStringNow = \"-\" ~ toStringNow!(cast(ulong) -v);\n    else\n        enum toStringNow = toStringNow!(cast(ulong) v);\n}\n\nunittest\n{\n    static assert(toStringNow!(0x100000000) == \"4294967296\");\n    static assert(toStringNow!(-138L) == \"-138\");\n}\n\n/// ditto\ntemplate toStringNow(uint U)\n{\n    enum toStringNow = toStringNow!(cast(ulong)U);\n}\n\n/// ditto\ntemplate toStringNow(int I)\n{\n    enum toStringNow = toStringNow!(cast(long)I);\n}\n\n/// ditto\ntemplate toStringNow(bool B)\n{\n    enum toStringNow = B ? \"true\" : \"false\";\n}\n\n/// ditto\ntemplate toStringNow(string S)\n{\n    enum toStringNow = S;\n}\n\n/// ditto\ntemplate toStringNow(char C)\n{\n    enum toStringNow = \"\" ~ C;\n}\n\n\n/********\n * Parse unsigned integer literal from the start of string s.\n * returns:\n *    .value = the integer literal as a string,\n *    .rest = the string following the integer literal\n * Otherwise:\n *    .value = null,\n *    .rest = s\n */\n\ntemplate parseUinteger(const(char)[] s)\n{\n    static if (s.length == 0)\n    {\n        enum value = \"\";\n        enum rest = \"\";\n    }\n    else static if (s[0] >= '0' && s[0] <= '9')\n    {\n        enum value = s[0] ~ parseUinteger!(s[1..$]).value;\n        enum rest = parseUinteger!(s[1..$]).rest;\n    }\n    else\n    {\n        enum value = \"\";\n        enum rest = s;\n    }\n}\n\n/********\nParse integer literal optionally preceded by $(D '-') from the start\nof string $(D s).\n\nReturns:\n   .value = the integer literal as a string,\n   .rest = the string following the integer literal\n\nOtherwise:\n   .value = null,\n   .rest = s\n*/\n\ntemplate parseInteger(const(char)[] s)\n{\n    static if (s.length == 0)\n    {\n        enum value = \"\";\n        enum rest = \"\";\n    }\n    else static if (s[0] >= '0' && s[0] <= '9')\n    {\n        enum value = s[0] ~ parseUinteger!(s[1..$]).value;\n        enum rest = parseUinteger!(s[1..$]).rest;\n    }\n    else static if (s.length >= 2 &&\n            s[0] == '-' && s[1] >= '0' && s[1] <= '9')\n    {\n        enum value = s[0..2] ~ parseUinteger!(s[2..$]).value;\n        enum rest = parseUinteger!(s[2..$]).rest;\n    }\n    else\n    {\n        enum value = \"\";\n        enum rest = s;\n    }\n}\n\nunittest\n{\n    assert(parseUinteger!(\"1234abc\").value == \"1234\");\n    assert(parseUinteger!(\"1234abc\").rest == \"abc\");\n    assert(parseInteger!(\"-1234abc\").value == \"-1234\");\n    assert(parseInteger!(\"-1234abc\").rest == \"abc\");\n}\n\n/**\nDeprecated aliases held for backward compatibility.\n*/\ndeprecated alias toStringNow ToString;\n/// Ditto\ndeprecated alias parseUinteger ParseUinteger;\n/// Ditto\ndeprecated alias parseUinteger ParseInteger;\n\n</textarea></form>\n\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        lineNumbers: true,\n        matchBrackets: true,\n        indentUnit: 4,\n        mode: \"text/x-d\"\n      });\n    </script>\n\n    <p>Simple mode that handle D-Syntax (<a href=\"http://www.dlang.org\">DLang Homepage</a>).</p>\n\n    <p><strong>MIME types defined:</strong> <code>text/x-d</code>\n    .</p>\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/dart/dart.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"), require(\"../clike/clike\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\", \"../clike/clike\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n\n  var keywords = (\"this super static final const abstract class extends external factory \" +\n    \"implements get native operator set typedef with enum throw rethrow \" +\n    \"assert break case continue default in return new deferred async await \" +\n    \"try catch finally do else for if switch while import library export \" +\n    \"part of show hide is\").split(\" \");\n  var blockKeywords = \"try catch finally do else for if switch while\".split(\" \");\n  var atoms = \"true false null\".split(\" \");\n  var builtins = \"void bool num int double dynamic var String\".split(\" \");\n\n  function set(words) {\n    var obj = {};\n    for (var i = 0; i < words.length; ++i) obj[words[i]] = true;\n    return obj;\n  }\n\n  CodeMirror.defineMIME(\"application/dart\", {\n    name: \"clike\",\n    keywords: set(keywords),\n    multiLineStrings: true,\n    blockKeywords: set(blockKeywords),\n    builtin: set(builtins),\n    atoms: set(atoms),\n    hooks: {\n      \"@\": function(stream) {\n        stream.eatWhile(/[\\w\\$_]/);\n        return \"meta\";\n      }\n    }\n  });\n\n  CodeMirror.registerHelper(\"hintWords\", \"application/dart\", keywords.concat(atoms).concat(builtins));\n\n  // This is needed to make loading through meta.js work.\n  CodeMirror.defineMode(\"dart\", function(conf) {\n    return CodeMirror.getMode(conf, \"application/dart\");\n  }, \"clike\");\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/dart/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Dart mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"../clike/clike.js\"></script>\n<script src=\"dart.js\"></script>\n<style>.CodeMirror {border: 1px solid #dee;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Dart</a>\n  </ul>\n</div>\n\n<article>\n<h2>Dart mode</h2>\n<form>\n<textarea id=\"code\" name=\"code\">\nimport 'dart:math' show Random;\n\nvoid main() {\n  print(new Die(n: 12).roll());\n}\n\n// Define a class.\nclass Die {\n  // Define a class variable.\n  static Random shaker = new Random();\n\n  // Define instance variables.\n  int sides, value;\n\n  // Define a method using shorthand syntax.\n  String toString() => '$value';\n\n  // Define a constructor.\n  Die({int n: 6}) {\n    if (4 <= n && n <= 20) {\n      sides = n;\n    } else {\n      // Support for errors and exceptions.\n      throw new ArgumentError(/* */);\n    }\n  }\n\n  // Define an instance method.\n  int roll() {\n    return value = shaker.nextInt(sides) + 1;\n  }\n}\n</textarea>\n</form>\n\n<script>\n  var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n    lineNumbers: true,\n    mode: \"application/dart\"\n  });\n</script>\n\n</article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/diff/diff.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"diff\", function() {\n\n  var TOKEN_NAMES = {\n    '+': 'positive',\n    '-': 'negative',\n    '@': 'meta'\n  };\n\n  return {\n    token: function(stream) {\n      var tw_pos = stream.string.search(/[\\t ]+?$/);\n\n      if (!stream.sol() || tw_pos === 0) {\n        stream.skipToEnd();\n        return (\"error \" + (\n          TOKEN_NAMES[stream.string.charAt(0)] || '')).replace(/ $/, '');\n      }\n\n      var token_name = TOKEN_NAMES[stream.peek()] || stream.skipToEnd();\n\n      if (tw_pos === -1) {\n        stream.skipToEnd();\n      } else {\n        stream.pos = tw_pos;\n      }\n\n      return token_name;\n    }\n  };\n});\n\nCodeMirror.defineMIME(\"text/x-diff\", \"diff\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/diff/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Diff mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"diff.js\"></script>\n<style>\n      .CodeMirror {border-top: 1px solid #ddd; border-bottom: 1px solid #ddd;}\n      span.cm-meta {color: #a0b !important;}\n      span.cm-error { background-color: black; opacity: 0.4;}\n      span.cm-error.cm-string { background-color: red; }\n      span.cm-error.cm-tag { background-color: #2b2; }\n    </style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Diff</a>\n  </ul>\n</div>\n\n<article>\n<h2>Diff mode</h2>\n<form><textarea id=\"code\" name=\"code\">\ndiff --git a/index.html b/index.html\nindex c1d9156..7764744 100644\n--- a/index.html\n+++ b/index.html\n@@ -95,7 +95,8 @@ StringStream.prototype = {\n     <script>\n       var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n         lineNumbers: true,\n-        autoMatchBrackets: true\n+        autoMatchBrackets: true,\n+      onGutterClick: function(x){console.log(x);}\n       });\n     </script>\n   </body>\ndiff --git a/lib/codemirror.js b/lib/codemirror.js\nindex 04646a9..9a39cc7 100644\n--- a/lib/codemirror.js\n+++ b/lib/codemirror.js\n@@ -399,10 +399,16 @@ var CodeMirror = (function() {\n     }\n \n     function onMouseDown(e) {\n-      var start = posFromMouse(e), last = start;    \n+      var start = posFromMouse(e), last = start, target = e.target();\n       if (!start) return;\n       setCursor(start.line, start.ch, false);\n       if (e.button() != 1) return;\n+      if (target.parentNode == gutter) {    \n+        if (options.onGutterClick)\n+          options.onGutterClick(indexOf(gutter.childNodes, target) + showingFrom);\n+        return;\n+      }\n+\n       if (!focused) onFocus();\n \n       e.stop();\n@@ -808,7 +814,7 @@ var CodeMirror = (function() {\n       for (var i = showingFrom; i < showingTo; ++i) {\n         var marker = lines[i].gutterMarker;\n         if (marker) html.push('<div class=\"' + marker.style + '\">' + htmlEscape(marker.text) + '</div>');\n-        else html.push(\"<div>\" + (options.lineNumbers ? i + 1 : \"\\u00a0\") + \"</div>\");\n+        else html.push(\"<div>\" + (options.lineNumbers ? i + options.firstLineNumber : \"\\u00a0\") + \"</div>\");\n       }\n       gutter.style.display = \"none\"; // TODO test whether this actually helps\n       gutter.innerHTML = html.join(\"\");\n@@ -1371,10 +1377,8 @@ var CodeMirror = (function() {\n         if (option == \"parser\") setParser(value);\n         else if (option === \"lineNumbers\") setLineNumbers(value);\n         else if (option === \"gutter\") setGutter(value);\n-        else if (option === \"readOnly\") options.readOnly = value;\n-        else if (option === \"indentUnit\") {options.indentUnit = indentUnit = value; setParser(options.parser);}\n-        else if (/^(?:enterMode|tabMode|indentWithTabs|readOnly|autoMatchBrackets|undoDepth)$/.test(option)) options[option] = value;\n-        else throw new Error(\"Can't set option \" + option);\n+        else if (option === \"indentUnit\") {options.indentUnit = value; setParser(options.parser);}\n+        else options[option] = value;\n       },\n       cursorCoords: cursorCoords,\n       undo: operation(undo),\n@@ -1402,7 +1406,8 @@ var CodeMirror = (function() {\n       replaceRange: operation(replaceRange),\n \n       operation: function(f){return operation(f)();},\n-      refresh: function(){updateDisplay([{from: 0, to: lines.length}]);}\n+      refresh: function(){updateDisplay([{from: 0, to: lines.length}]);},\n+      getInputField: function(){return input;}\n     };\n     return instance;\n   }\n@@ -1420,6 +1425,7 @@ var CodeMirror = (function() {\n     readOnly: false,\n     onChange: null,\n     onCursorActivity: null,\n+    onGutterClick: null,\n     autoMatchBrackets: false,\n     workTime: 200,\n     workDelay: 300,\n</textarea></form>\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {});\n    </script>\n\n    <p><strong>MIME types defined:</strong> <code>text/x-diff</code>.</p>\n\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/django/django.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"), require(\"../htmlmixed/htmlmixed\"),\n        require(\"../../addon/mode/overlay\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\", \"../htmlmixed/htmlmixed\",\n            \"../../addon/mode/overlay\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n\n  CodeMirror.defineMode(\"django:inner\", function() {\n    var keywords = [\"block\", \"endblock\", \"for\", \"endfor\", \"in\", \"true\", \"false\",\n                    \"loop\", \"none\", \"self\", \"super\", \"if\", \"endif\", \"as\", \"not\", \"and\",\n                    \"else\", \"import\", \"with\", \"endwith\", \"without\", \"context\", \"ifequal\", \"endifequal\",\n                    \"ifnotequal\", \"endifnotequal\", \"extends\", \"include\", \"load\", \"length\", \"comment\",\n                    \"endcomment\", \"empty\"];\n    keywords = new RegExp(\"^((\" + keywords.join(\")|(\") + \"))\\\\b\");\n\n    function tokenBase (stream, state) {\n      stream.eatWhile(/[^\\{]/);\n      var ch = stream.next();\n      if (ch == \"{\") {\n        if (ch = stream.eat(/\\{|%|#/)) {\n          state.tokenize = inTag(ch);\n          return \"tag\";\n        }\n      }\n    }\n    function inTag (close) {\n      if (close == \"{\") {\n        close = \"}\";\n      }\n      return function (stream, state) {\n        var ch = stream.next();\n        if ((ch == close) && stream.eat(\"}\")) {\n          state.tokenize = tokenBase;\n          return \"tag\";\n        }\n        if (stream.match(keywords)) {\n          return \"keyword\";\n        }\n        return close == \"#\" ? \"comment\" : \"string\";\n      };\n    }\n    return {\n      startState: function () {\n        return {tokenize: tokenBase};\n      },\n      token: function (stream, state) {\n        return state.tokenize(stream, state);\n      }\n    };\n  });\n\n  CodeMirror.defineMode(\"django\", function(config) {\n    var htmlBase = CodeMirror.getMode(config, \"text/html\");\n    var djangoInner = CodeMirror.getMode(config, \"django:inner\");\n    return CodeMirror.overlayMode(htmlBase, djangoInner);\n  });\n\n  CodeMirror.defineMIME(\"text/x-django\", \"django\");\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/django/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Django template mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"../../addon/mode/overlay.js\"></script>\n<script src=\"../xml/xml.js\"></script>\n<script src=\"../htmlmixed/htmlmixed.js\"></script>\n<script src=\"django.js\"></script>\n<style type=\"text/css\">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Django</a>\n  </ul>\n</div>\n\n<article>\n<h2>Django template mode</h2>\n<form><textarea id=\"code\" name=\"code\">\n<!doctype html>\n<html>\n    <head>\n        <title>My Django web application</title>\n    </head>\n    <body>\n        <h1>\n            {{ page.title }}\n        </h1>\n        <ul class=\"my-list\">\n            {% for item in items %}\n                <li>{% item.name %}</li>\n            {% empty %}\n                <li>You have no items in your list.</li>\n            {% endfor %}\n        </ul>\n    </body>\n</html>\n</textarea></form>\n\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        lineNumbers: true,\n        mode: \"django\",\n        indentUnit: 4,\n        indentWithTabs: true\n      });\n    </script>\n\n    <p>Mode for HTML with embedded Django template markup.</p>\n\n    <p><strong>MIME types defined:</strong> <code>text/x-django</code></p>\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/dockerfile/dockerfile.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"), require(\"../../addon/mode/simple\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\", \"../../addon/mode/simple\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n\n  // Collect all Dockerfile directives\n  var instructions = [\"from\", \"maintainer\", \"run\", \"cmd\", \"expose\", \"env\",\n                      \"add\", \"copy\", \"entrypoint\", \"volume\", \"user\",\n                      \"workdir\", \"onbuild\"],\n      instructionRegex = \"(\" + instructions.join('|') + \")\",\n      instructionOnlyLine = new RegExp(instructionRegex + \"\\\\s*$\", \"i\"),\n      instructionWithArguments = new RegExp(instructionRegex + \"(\\\\s+)\", \"i\");\n\n  CodeMirror.defineSimpleMode(\"dockerfile\", {\n    start: [\n      // Block comment: This is a line starting with a comment\n      {\n        regex: /#.*$/,\n        token: \"comment\"\n      },\n      // Highlight an instruction without any arguments (for convenience)\n      {\n        regex: instructionOnlyLine,\n        token: \"variable-2\"\n      },\n      // Highlight an instruction followed by arguments\n      {\n        regex: instructionWithArguments,\n        token: [\"variable-2\", null],\n        next: \"arguments\"\n      },\n      {\n        regex: /./,\n        token: null\n      }\n    ],\n    arguments: [\n      {\n        // Line comment without instruction arguments is an error\n        regex: /#.*$/,\n        token: \"error\",\n        next: \"start\"\n      },\n      {\n        regex: /[^#]+\\\\$/,\n        token: null\n      },\n      {\n        // Match everything except for the inline comment\n        regex: /[^#]+/,\n        token: null,\n        next: \"start\"\n      },\n      {\n        regex: /$/,\n        token: null,\n        next: \"start\"\n      },\n      // Fail safe return to start\n      {\n        token: null,\n        next: \"start\"\n      }\n    ]\n  });\n\n  CodeMirror.defineMIME(\"text/x-dockerfile\", \"dockerfile\");\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/dockerfile/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Dockerfile mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"../../addon/mode/simple.js\"></script>\n<script src=\"dockerfile.js\"></script>\n<style type=\"text/css\">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Dockerfile</a>\n  </ul>\n</div>\n\n<article>\n<h2>Dockerfile mode</h2>\n<form><textarea id=\"code\" name=\"code\"># Install Ghost blogging platform and run development environment\n#\n# VERSION 1.0.0\n\nFROM ubuntu:12.10\nMAINTAINER Amer Grgic \"amer@livebyt.es\"\nWORKDIR /data/ghost\n\n# Install dependencies for nginx installation\nRUN apt-get update\nRUN apt-get install -y python g++ make software-properties-common --force-yes\nRUN add-apt-repository ppa:chris-lea/node.js\nRUN apt-get update\n# Install unzip\nRUN apt-get install -y unzip\n# Install curl\nRUN apt-get install -y curl\n# Install nodejs & npm\nRUN apt-get install -y rlwrap\nRUN apt-get install -y nodejs \n# Download Ghost v0.4.1\nRUN curl -L https://ghost.org/zip/ghost-latest.zip -o /tmp/ghost.zip\n# Unzip Ghost zip to /data/ghost\nRUN unzip -uo /tmp/ghost.zip -d /data/ghost\n# Add custom config js to /data/ghost\nADD ./config.example.js /data/ghost/config.js\n# Install Ghost with NPM\nRUN cd /data/ghost/ && npm install --production\n# Expose port 2368\nEXPOSE 2368\n# Run Ghost\nCMD [\"npm\",\"start\"]\n</textarea></form>\n\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        lineNumbers: true,\n        mode: \"dockerfile\"\n      });\n    </script>\n\n    <p>Dockerfile syntax highlighting for CodeMirror. Depends on\n    the <a href=\"../../demo/simplemode.html\">simplemode</a> addon.</p>\n\n    <p><strong>MIME types defined:</strong> <code>text/x-dockerfile</code></p>\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/dtd/dtd.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n/*\n  DTD mode\n  Ported to CodeMirror by Peter Kroon <plakroon@gmail.com>\n  Report bugs/issues here: https://github.com/codemirror/CodeMirror/issues\n  GitHub: @peterkroon\n*/\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"dtd\", function(config) {\n  var indentUnit = config.indentUnit, type;\n  function ret(style, tp) {type = tp; return style;}\n\n  function tokenBase(stream, state) {\n    var ch = stream.next();\n\n    if (ch == \"<\" && stream.eat(\"!\") ) {\n      if (stream.eatWhile(/[\\-]/)) {\n        state.tokenize = tokenSGMLComment;\n        return tokenSGMLComment(stream, state);\n      } else if (stream.eatWhile(/[\\w]/)) return ret(\"keyword\", \"doindent\");\n    } else if (ch == \"<\" && stream.eat(\"?\")) { //xml declaration\n      state.tokenize = inBlock(\"meta\", \"?>\");\n      return ret(\"meta\", ch);\n    } else if (ch == \"#\" && stream.eatWhile(/[\\w]/)) return ret(\"atom\", \"tag\");\n    else if (ch == \"|\") return ret(\"keyword\", \"seperator\");\n    else if (ch.match(/[\\(\\)\\[\\]\\-\\.,\\+\\?>]/)) return ret(null, ch);//if(ch === \">\") return ret(null, \"endtag\"); else\n    else if (ch.match(/[\\[\\]]/)) return ret(\"rule\", ch);\n    else if (ch == \"\\\"\" || ch == \"'\") {\n      state.tokenize = tokenString(ch);\n      return state.tokenize(stream, state);\n    } else if (stream.eatWhile(/[a-zA-Z\\?\\+\\d]/)) {\n      var sc = stream.current();\n      if( sc.substr(sc.length-1,sc.length).match(/\\?|\\+/) !== null )stream.backUp(1);\n      return ret(\"tag\", \"tag\");\n    } else if (ch == \"%\" || ch == \"*\" ) return ret(\"number\", \"number\");\n    else {\n      stream.eatWhile(/[\\w\\\\\\-_%.{,]/);\n      return ret(null, null);\n    }\n  }\n\n  function tokenSGMLComment(stream, state) {\n    var dashes = 0, ch;\n    while ((ch = stream.next()) != null) {\n      if (dashes >= 2 && ch == \">\") {\n        state.tokenize = tokenBase;\n        break;\n      }\n      dashes = (ch == \"-\") ? dashes + 1 : 0;\n    }\n    return ret(\"comment\", \"comment\");\n  }\n\n  function tokenString(quote) {\n    return function(stream, state) {\n      var escaped = false, ch;\n      while ((ch = stream.next()) != null) {\n        if (ch == quote && !escaped) {\n          state.tokenize = tokenBase;\n          break;\n        }\n        escaped = !escaped && ch == \"\\\\\";\n      }\n      return ret(\"string\", \"tag\");\n    };\n  }\n\n  function inBlock(style, terminator) {\n    return function(stream, state) {\n      while (!stream.eol()) {\n        if (stream.match(terminator)) {\n          state.tokenize = tokenBase;\n          break;\n        }\n        stream.next();\n      }\n      return style;\n    };\n  }\n\n  return {\n    startState: function(base) {\n      return {tokenize: tokenBase,\n              baseIndent: base || 0,\n              stack: []};\n    },\n\n    token: function(stream, state) {\n      if (stream.eatSpace()) return null;\n      var style = state.tokenize(stream, state);\n\n      var context = state.stack[state.stack.length-1];\n      if (stream.current() == \"[\" || type === \"doindent\" || type == \"[\") state.stack.push(\"rule\");\n      else if (type === \"endtag\") state.stack[state.stack.length-1] = \"endtag\";\n      else if (stream.current() == \"]\" || type == \"]\" || (type == \">\" && context == \"rule\")) state.stack.pop();\n      else if (type == \"[\") state.stack.push(\"[\");\n      return style;\n    },\n\n    indent: function(state, textAfter) {\n      var n = state.stack.length;\n\n      if( textAfter.match(/\\]\\s+|\\]/) )n=n-1;\n      else if(textAfter.substr(textAfter.length-1, textAfter.length) === \">\"){\n        if(textAfter.substr(0,1) === \"<\")n;\n        else if( type == \"doindent\" && textAfter.length > 1 )n;\n        else if( type == \"doindent\")n--;\n        else if( type == \">\" && textAfter.length > 1)n;\n        else if( type == \"tag\" && textAfter !== \">\")n;\n        else if( type == \"tag\" && state.stack[state.stack.length-1] == \"rule\")n--;\n        else if( type == \"tag\")n++;\n        else if( textAfter === \">\" && state.stack[state.stack.length-1] == \"rule\" && type === \">\")n--;\n        else if( textAfter === \">\" && state.stack[state.stack.length-1] == \"rule\")n;\n        else if( textAfter.substr(0,1) !== \"<\" && textAfter.substr(0,1) === \">\" )n=n-1;\n        else if( textAfter === \">\")n;\n        else n=n-1;\n        //over rule them all\n        if(type == null || type == \"]\")n--;\n      }\n\n      return state.baseIndent + n * indentUnit;\n    },\n\n    electricChars: \"]>\"\n  };\n});\n\nCodeMirror.defineMIME(\"application/xml-dtd\", \"dtd\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/dtd/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: DTD mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"dtd.js\"></script>\n<style type=\"text/css\">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">DTD</a>\n  </ul>\n</div>\n\n<article>\n<h2>DTD mode</h2>\n<form><textarea id=\"code\" name=\"code\"><?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<!ATTLIST title\n  xmlns\tCDATA\t#FIXED\t\"http://docbook.org/ns/docbook\"\n  role\tCDATA\t#IMPLIED\n  %db.common.attributes;\n  %db.common.linking.attributes;\n>\n\n<!--\n  Try: http://docbook.org/xml/5.0/dtd/docbook.dtd\n-->\n\n<!DOCTYPE xsl:stylesheet\n  [\n    <!ENTITY nbsp   \"&amp;#160;\">\n    <!ENTITY copy   \"&amp;#169;\">\n    <!ENTITY reg    \"&amp;#174;\">\n    <!ENTITY trade  \"&amp;#8482;\">\n    <!ENTITY mdash  \"&amp;#8212;\">\n    <!ENTITY ldquo  \"&amp;#8220;\">\n    <!ENTITY rdquo  \"&amp;#8221;\">\n    <!ENTITY pound  \"&amp;#163;\">\n    <!ENTITY yen    \"&amp;#165;\">\n    <!ENTITY euro   \"&amp;#8364;\">\n    <!ENTITY mathml \"http://www.w3.org/1998/Math/MathML\">\n  ]\n>\n\n<!ELEMENT title (#PCDATA|inlinemediaobject|remark|superscript|subscript|xref|link|olink|anchor|biblioref|alt|annotation|indexterm|abbrev|acronym|date|emphasis|footnote|footnoteref|foreignphrase|phrase|quote|wordasword|firstterm|glossterm|coref|trademark|productnumber|productname|database|application|hardware|citation|citerefentry|citetitle|citebiblioid|author|person|personname|org|orgname|editor|jobtitle|replaceable|package|parameter|termdef|nonterminal|systemitem|option|optional|property|inlineequation|tag|markup|token|symbol|literal|code|constant|email|uri|guiicon|guibutton|guimenuitem|guimenu|guisubmenu|guilabel|menuchoice|mousebutton|keycombo|keycap|keycode|keysym|shortcut|accel|prompt|envar|filename|command|computeroutput|userinput|function|varname|returnvalue|type|classname|exceptionname|interfacename|methodname|modifier|initializer|ooclass|ooexception|oointerface|errorcode|errortext|errorname|errortype)*>\n\n<!ENTITY % db.common.attributes \"\n  xml:id\tID\t#IMPLIED\n  version\tCDATA\t#IMPLIED\n  xml:lang\tCDATA\t#IMPLIED\n  xml:base\tCDATA\t#IMPLIED\n  remap\tCDATA\t#IMPLIED\n  xreflabel\tCDATA\t#IMPLIED\n  revisionflag\t(changed|added|deleted|off)\t#IMPLIED\n  dir\t(ltr|rtl|lro|rlo)\t#IMPLIED\n  arch\tCDATA\t#IMPLIED\n  audience\tCDATA\t#IMPLIED\n  condition\tCDATA\t#IMPLIED\n  conformance\tCDATA\t#IMPLIED\n  os\tCDATA\t#IMPLIED\n  revision\tCDATA\t#IMPLIED\n  security\tCDATA\t#IMPLIED\n  userlevel\tCDATA\t#IMPLIED\n  vendor\tCDATA\t#IMPLIED\n  wordsize\tCDATA\t#IMPLIED\n  annotations\tCDATA\t#IMPLIED\n\n\"></textarea></form>\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        mode: {name: \"dtd\", alignCDATA: true},\n        lineNumbers: true,\n        lineWrapping: true\n      });\n    </script>\n\n    <p><strong>MIME types defined:</strong> <code>application/xml-dtd</code>.</p>\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/dylan/dylan.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"dylan\", function(_config) {\n  // Words\n  var words = {\n    // Words that introduce unnamed definitions like \"define interface\"\n    unnamedDefinition: [\"interface\"],\n\n    // Words that introduce simple named definitions like \"define library\"\n    namedDefinition: [\"module\", \"library\", \"macro\",\n                      \"C-struct\", \"C-union\",\n                      \"C-function\", \"C-callable-wrapper\"\n                     ],\n\n    // Words that introduce type definitions like \"define class\".\n    // These are also parameterized like \"define method\" and are\n    // appended to otherParameterizedDefinitionWords\n    typeParameterizedDefinition: [\"class\", \"C-subtype\", \"C-mapped-subtype\"],\n\n    // Words that introduce trickier definitions like \"define method\".\n    // These require special definitions to be added to startExpressions\n    otherParameterizedDefinition: [\"method\", \"function\",\n                                   \"C-variable\", \"C-address\"\n                                  ],\n\n    // Words that introduce module constant definitions.\n    // These must also be simple definitions and are\n    // appended to otherSimpleDefinitionWords\n    constantSimpleDefinition: [\"constant\"],\n\n    // Words that introduce module variable definitions.\n    // These must also be simple definitions and are\n    // appended to otherSimpleDefinitionWords\n    variableSimpleDefinition: [\"variable\"],\n\n    // Other words that introduce simple definitions\n    // (without implicit bodies).\n    otherSimpleDefinition: [\"generic\", \"domain\",\n                            \"C-pointer-type\",\n                            \"table\"\n                           ],\n\n    // Words that begin statements with implicit bodies.\n    statement: [\"if\", \"block\", \"begin\", \"method\", \"case\",\n                \"for\", \"select\", \"when\", \"unless\", \"until\",\n                \"while\", \"iterate\", \"profiling\", \"dynamic-bind\"\n               ],\n\n    // Patterns that act as separators in compound statements.\n    // This may include any general pattern that must be indented\n    // specially.\n    separator: [\"finally\", \"exception\", \"cleanup\", \"else\",\n                \"elseif\", \"afterwards\"\n               ],\n\n    // Keywords that do not require special indentation handling,\n    // but which should be highlighted\n    other: [\"above\", \"below\", \"by\", \"from\", \"handler\", \"in\",\n            \"instance\", \"let\", \"local\", \"otherwise\", \"slot\",\n            \"subclass\", \"then\", \"to\", \"keyed-by\", \"virtual\"\n           ],\n\n    // Condition signaling function calls\n    signalingCalls: [\"signal\", \"error\", \"cerror\",\n                     \"break\", \"check-type\", \"abort\"\n                    ]\n  };\n\n  words[\"otherDefinition\"] =\n    words[\"unnamedDefinition\"]\n    .concat(words[\"namedDefinition\"])\n    .concat(words[\"otherParameterizedDefinition\"]);\n\n  words[\"definition\"] =\n    words[\"typeParameterizedDefinition\"]\n    .concat(words[\"otherDefinition\"]);\n\n  words[\"parameterizedDefinition\"] =\n    words[\"typeParameterizedDefinition\"]\n    .concat(words[\"otherParameterizedDefinition\"]);\n\n  words[\"simpleDefinition\"] =\n    words[\"constantSimpleDefinition\"]\n    .concat(words[\"variableSimpleDefinition\"])\n    .concat(words[\"otherSimpleDefinition\"]);\n\n  words[\"keyword\"] =\n    words[\"statement\"]\n    .concat(words[\"separator\"])\n    .concat(words[\"other\"]);\n\n  // Patterns\n  var symbolPattern = \"[-_a-zA-Z?!*@<>$%]+\";\n  var symbol = new RegExp(\"^\" + symbolPattern);\n  var patterns = {\n    // Symbols with special syntax\n    symbolKeyword: symbolPattern + \":\",\n    symbolClass: \"<\" + symbolPattern + \">\",\n    symbolGlobal: \"\\\\*\" + symbolPattern + \"\\\\*\",\n    symbolConstant: \"\\\\$\" + symbolPattern\n  };\n  var patternStyles = {\n    symbolKeyword: \"atom\",\n    symbolClass: \"tag\",\n    symbolGlobal: \"variable-2\",\n    symbolConstant: \"variable-3\"\n  };\n\n  // Compile all patterns to regular expressions\n  for (var patternName in patterns)\n    if (patterns.hasOwnProperty(patternName))\n      patterns[patternName] = new RegExp(\"^\" + patterns[patternName]);\n\n  // Names beginning \"with-\" and \"without-\" are commonly\n  // used as statement macro\n  patterns[\"keyword\"] = [/^with(?:out)?-[-_a-zA-Z?!*@<>$%]+/];\n\n  var styles = {};\n  styles[\"keyword\"] = \"keyword\";\n  styles[\"definition\"] = \"def\";\n  styles[\"simpleDefinition\"] = \"def\";\n  styles[\"signalingCalls\"] = \"builtin\";\n\n  // protected words lookup table\n  var wordLookup = {};\n  var styleLookup = {};\n\n  [\n    \"keyword\",\n    \"definition\",\n    \"simpleDefinition\",\n    \"signalingCalls\"\n  ].forEach(function(type) {\n    words[type].forEach(function(word) {\n      wordLookup[word] = type;\n      styleLookup[word] = styles[type];\n    });\n  });\n\n\n  function chain(stream, state, f) {\n    state.tokenize = f;\n    return f(stream, state);\n  }\n\n  var type, content;\n\n  function ret(_type, style, _content) {\n    type = _type;\n    content = _content;\n    return style;\n  }\n\n  function tokenBase(stream, state) {\n    // String\n    var ch = stream.peek();\n    if (ch == \"'\" || ch == '\"') {\n      stream.next();\n      return chain(stream, state, tokenString(ch, \"string\", \"string\"));\n    }\n    // Comment\n    else if (ch == \"/\") {\n      stream.next();\n      if (stream.eat(\"*\")) {\n        return chain(stream, state, tokenComment);\n      } else if (stream.eat(\"/\")) {\n        stream.skipToEnd();\n        return ret(\"comment\", \"comment\");\n      } else {\n        stream.skipTo(\" \");\n        return ret(\"operator\", \"operator\");\n      }\n    }\n    // Decimal\n    else if (/\\d/.test(ch)) {\n      stream.match(/^\\d*(?:\\.\\d*)?(?:e[+\\-]?\\d+)?/);\n      return ret(\"number\", \"number\");\n    }\n    // Hash\n    else if (ch == \"#\") {\n      stream.next();\n      // Symbol with string syntax\n      ch = stream.peek();\n      if (ch == '\"') {\n        stream.next();\n        return chain(stream, state, tokenString('\"', \"symbol\", \"string-2\"));\n      }\n      // Binary number\n      else if (ch == \"b\") {\n        stream.next();\n        stream.eatWhile(/[01]/);\n        return ret(\"number\", \"number\");\n      }\n      // Hex number\n      else if (ch == \"x\") {\n        stream.next();\n        stream.eatWhile(/[\\da-f]/i);\n        return ret(\"number\", \"number\");\n      }\n      // Octal number\n      else if (ch == \"o\") {\n        stream.next();\n        stream.eatWhile(/[0-7]/);\n        return ret(\"number\", \"number\");\n      }\n      // Hash symbol\n      else {\n        stream.eatWhile(/[-a-zA-Z]/);\n        return ret(\"hash\", \"keyword\");\n      }\n    } else if (stream.match(\"end\")) {\n      return ret(\"end\", \"keyword\");\n    }\n    for (var name in patterns) {\n      if (patterns.hasOwnProperty(name)) {\n        var pattern = patterns[name];\n        if ((pattern instanceof Array && pattern.some(function(p) {\n          return stream.match(p);\n        })) || stream.match(pattern))\n          return ret(name, patternStyles[name], stream.current());\n      }\n    }\n    if (stream.match(\"define\")) {\n      return ret(\"definition\", \"def\");\n    } else {\n      stream.eatWhile(/[\\w\\-]/);\n      // Keyword\n      if (wordLookup[stream.current()]) {\n        return ret(wordLookup[stream.current()], styleLookup[stream.current()], stream.current());\n      } else if (stream.current().match(symbol)) {\n        return ret(\"variable\", \"variable\");\n      } else {\n        stream.next();\n        return ret(\"other\", \"variable-2\");\n      }\n    }\n  }\n\n  function tokenComment(stream, state) {\n    var maybeEnd = false,\n    ch;\n    while ((ch = stream.next())) {\n      if (ch == \"/\" && maybeEnd) {\n        state.tokenize = tokenBase;\n        break;\n      }\n      maybeEnd = (ch == \"*\");\n    }\n    return ret(\"comment\", \"comment\");\n  }\n\n  function tokenString(quote, type, style) {\n    return function(stream, state) {\n      var next, end = false;\n      while ((next = stream.next()) != null) {\n        if (next == quote) {\n          end = true;\n          break;\n        }\n      }\n      if (end)\n        state.tokenize = tokenBase;\n      return ret(type, style);\n    };\n  }\n\n  // Interface\n  return {\n    startState: function() {\n      return {\n        tokenize: tokenBase,\n        currentIndent: 0\n      };\n    },\n    token: function(stream, state) {\n      if (stream.eatSpace())\n        return null;\n      var style = state.tokenize(stream, state);\n      return style;\n    },\n    blockCommentStart: \"/*\",\n    blockCommentEnd: \"*/\"\n  };\n});\n\nCodeMirror.defineMIME(\"text/x-dylan\", \"dylan\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/dylan/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Dylan mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"../../addon/edit/matchbrackets.js\"></script>\n<script src=\"../../addon/comment/continuecomment.js\"></script>\n<script src=\"../../addon/comment/comment.js\"></script>\n<script src=\"dylan.js\"></script>\n<style type=\"text/css\">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Dylan</a>\n  </ul>\n</div>\n\n<article>\n<h2>Dylan mode</h2>\n\n\n<div><textarea id=\"code\" name=\"code\">\nModule:       locators-internals\nSynopsis:     Abstract modeling of locations\nAuthor:       Andy Armstrong\nCopyright:    Original Code is Copyright (c) 1995-2004 Functional Objects, Inc.\n              All rights reserved.\nLicense:      See License.txt in this distribution for details.\nWarranty:     Distributed WITHOUT WARRANTY OF ANY KIND\n\ndefine open generic locator-server\n    (locator :: <locator>) => (server :: false-or(<server-locator>));\ndefine open generic locator-host\n    (locator :: <locator>) => (host :: false-or(<string>));\ndefine open generic locator-volume\n    (locator :: <locator>) => (volume :: false-or(<string>));\ndefine open generic locator-directory\n    (locator :: <locator>) => (directory :: false-or(<directory-locator>));\ndefine open generic locator-relative?\n    (locator :: <locator>) => (relative? :: <boolean>);\ndefine open generic locator-path\n    (locator :: <locator>) => (path :: <sequence>);\ndefine open generic locator-base\n    (locator :: <locator>) => (base :: false-or(<string>));\ndefine open generic locator-extension\n    (locator :: <locator>) => (extension :: false-or(<string>));\n\n/// Locator classes\n\ndefine open abstract class <directory-locator> (<physical-locator>)\nend class <directory-locator>;\n\ndefine open abstract class <file-locator> (<physical-locator>)\nend class <file-locator>;\n\ndefine method as\n    (class == <directory-locator>, string :: <string>)\n => (locator :: <directory-locator>)\n  as(<native-directory-locator>, string)\nend method as;\n\ndefine method make\n    (class == <directory-locator>,\n     #key server :: false-or(<server-locator>) = #f,\n          path :: <sequence> = #[],\n          relative? :: <boolean> = #f,\n          name :: false-or(<string>) = #f)\n => (locator :: <directory-locator>)\n  make(<native-directory-locator>,\n       server:    server,\n       path:      path,\n       relative?: relative?,\n       name:      name)\nend method make;\n\ndefine method as\n    (class == <file-locator>, string :: <string>)\n => (locator :: <file-locator>)\n  as(<native-file-locator>, string)\nend method as;\n\ndefine method make\n    (class == <file-locator>,\n     #key directory :: false-or(<directory-locator>) = #f,\n          base :: false-or(<string>) = #f,\n          extension :: false-or(<string>) = #f,\n          name :: false-or(<string>) = #f)\n => (locator :: <file-locator>)\n  make(<native-file-locator>,\n       directory: directory,\n       base:      base,\n       extension: extension,\n       name:      name)\nend method make;\n\n/// Locator coercion\n\n//---*** andrewa: This caching scheme doesn't work yet, so disable it.\ndefine constant $cache-locators?        = #f;\ndefine constant $cache-locator-strings? = #f;\n\ndefine constant $locator-to-string-cache = make(<object-table>, weak: #\"key\");\ndefine constant $string-to-locator-cache = make(<string-table>, weak: #\"value\");\n\ndefine open generic locator-as-string\n    (class :: subclass(<string>), locator :: <locator>)\n => (string :: <string>);\n\ndefine open generic string-as-locator\n    (class :: subclass(<locator>), string :: <string>)\n => (locator :: <locator>);\n\ndefine sealed sideways method as\n    (class :: subclass(<string>), locator :: <locator>)\n => (string :: <string>)\n  let string = element($locator-to-string-cache, locator, default: #f);\n  if (string)\n    as(class, string)\n  else\n    let string = locator-as-string(class, locator);\n    if ($cache-locator-strings?)\n      element($locator-to-string-cache, locator) := string;\n    else\n      string\n    end\n  end\nend method as;\n\ndefine sealed sideways method as\n    (class :: subclass(<locator>), string :: <string>)\n => (locator :: <locator>)\n  let locator = element($string-to-locator-cache, string, default: #f);\n  if (instance?(locator, class))\n    locator\n  else\n    let locator = string-as-locator(class, string);\n    if ($cache-locators?)\n      element($string-to-locator-cache, string) := locator;\n    else\n      locator\n    end\n  end\nend method as;\n\n/// Locator conditions\n\ndefine class <locator-error> (<format-string-condition>, <error>)\nend class <locator-error>;\n\ndefine function locator-error\n    (format-string :: <string>, #rest format-arguments)\n  error(make(<locator-error>, \n             format-string:    format-string,\n             format-arguments: format-arguments))\nend function locator-error;\n\n/// Useful locator protocols\n\ndefine open generic locator-test\n    (locator :: <directory-locator>) => (test :: <function>);\n\ndefine method locator-test\n    (locator :: <directory-locator>) => (test :: <function>)\n  \\=\nend method locator-test;\n\ndefine open generic locator-might-have-links?\n    (locator :: <directory-locator>) => (links? :: <boolean>);\n\ndefine method locator-might-have-links?\n    (locator :: <directory-locator>) => (links? :: singleton(#f))\n  #f\nend method locator-might-have-links?;\n\ndefine method locator-relative?\n    (locator :: <file-locator>) => (relative? :: <boolean>)\n  let directory = locator.locator-directory;\n  ~directory | directory.locator-relative?\nend method locator-relative?;\n\ndefine method current-directory-locator?\n    (locator :: <directory-locator>) => (current-directory? :: <boolean>)\n  locator.locator-relative?\n    & locator.locator-path = #[#\"self\"]\nend method current-directory-locator?;\n\ndefine method locator-directory\n    (locator :: <directory-locator>) => (parent :: false-or(<directory-locator>))\n  let path = locator.locator-path;\n  unless (empty?(path))\n    make(object-class(locator),\n         server:    locator.locator-server,\n         path:      copy-sequence(path, end: path.size - 1),\n         relative?: locator.locator-relative?)\n  end\nend method locator-directory;\n\n/// Simplify locator\n\ndefine open generic simplify-locator\n    (locator :: <physical-locator>)\n => (simplified-locator :: <physical-locator>);\n\ndefine method simplify-locator\n    (locator :: <directory-locator>)\n => (simplified-locator :: <directory-locator>)\n  let path = locator.locator-path;\n  let relative? = locator.locator-relative?;\n  let resolve-parent? = ~locator.locator-might-have-links?;\n  let simplified-path\n    = simplify-path(path, \n                    resolve-parent?: resolve-parent?,\n                    relative?: relative?);\n  if (path ~= simplified-path)\n    make(object-class(locator),\n         server:    locator.locator-server,\n         path:      simplified-path,\n         relative?: locator.locator-relative?)\n  else\n    locator\n  end\nend method simplify-locator;\n\ndefine method simplify-locator\n    (locator :: <file-locator>) => (simplified-locator :: <file-locator>)\n  let directory = locator.locator-directory;\n  let simplified-directory = directory & simplify-locator(directory);\n  if (directory ~= simplified-directory)\n    make(object-class(locator),\n         directory: simplified-directory,\n         base:      locator.locator-base,\n         extension: locator.locator-extension)\n  else\n    locator\n  end\nend method simplify-locator;\n\n/// Subdirectory locator\n\ndefine open generic subdirectory-locator\n    (locator :: <directory-locator>, #rest sub-path)\n => (subdirectory :: <directory-locator>);\n\ndefine method subdirectory-locator\n    (locator :: <directory-locator>, #rest sub-path)\n => (subdirectory :: <directory-locator>)\n  let old-path = locator.locator-path;\n  let new-path = concatenate-as(<simple-object-vector>, old-path, sub-path);\n  make(object-class(locator),\n       server:    locator.locator-server,\n       path:      new-path,\n       relative?: locator.locator-relative?)\nend method subdirectory-locator;\n\n/// Relative locator\n\ndefine open generic relative-locator\n    (locator :: <physical-locator>, from-locator :: <physical-locator>)\n => (relative-locator :: <physical-locator>);\n\ndefine method relative-locator\n    (locator :: <directory-locator>, from-locator :: <directory-locator>)\n => (relative-locator :: <directory-locator>)\n  let path = locator.locator-path;\n  let from-path = from-locator.locator-path;\n  case\n    ~locator.locator-relative? & from-locator.locator-relative? =>\n      locator-error\n        (\"Cannot find relative path of absolute locator %= from relative locator %=\",\n         locator, from-locator);\n    locator.locator-server ~= from-locator.locator-server =>\n      locator;\n    path = from-path =>\n      make(object-class(locator),\n           path: vector(#\"self\"),\n           relative?: #t);\n    otherwise =>\n      make(object-class(locator),\n           path: relative-path(path, from-path, test: locator.locator-test),\n           relative?: #t);\n  end\nend method relative-locator;\n\ndefine method relative-locator\n    (locator :: <file-locator>, from-directory :: <directory-locator>)\n => (relative-locator :: <file-locator>)\n  let directory = locator.locator-directory;\n  let relative-directory = directory & relative-locator(directory, from-directory);\n  if (relative-directory ~= directory)\n    simplify-locator\n      (make(object-class(locator),\n            directory: relative-directory,\n            base:      locator.locator-base,\n            extension: locator.locator-extension))\n  else\n    locator\n  end\nend method relative-locator;\n\ndefine method relative-locator\n    (locator :: <physical-locator>, from-locator :: <file-locator>)\n => (relative-locator :: <physical-locator>)\n  let from-directory = from-locator.locator-directory;\n  case\n    from-directory =>\n      relative-locator(locator, from-directory);\n    ~locator.locator-relative? =>\n      locator-error\n        (\"Cannot find relative path of absolute locator %= from relative locator %=\",\n         locator, from-locator);\n    otherwise =>\n      locator;\n  end\nend method relative-locator;\n\n/// Merge locators\n\ndefine open generic merge-locators\n    (locator :: <physical-locator>, from-locator :: <physical-locator>)\n => (merged-locator :: <physical-locator>);\n\n/// Merge locators\n\ndefine method merge-locators\n    (locator :: <directory-locator>, from-locator :: <directory-locator>)\n => (merged-locator :: <directory-locator>)\n  if (locator.locator-relative?)\n    let path = concatenate(from-locator.locator-path, locator.locator-path);\n    simplify-locator\n      (make(object-class(locator),\n            server:    from-locator.locator-server,\n            path:      path,\n            relative?: from-locator.locator-relative?))\n  else\n    locator\n  end\nend method merge-locators;\n\ndefine method merge-locators\n    (locator :: <file-locator>, from-locator :: <directory-locator>)\n => (merged-locator :: <file-locator>)\n  let directory = locator.locator-directory;\n  let merged-directory \n    = if (directory)\n        merge-locators(directory, from-locator)\n      else\n        simplify-locator(from-locator)\n      end;\n  if (merged-directory ~= directory)\n    make(object-class(locator),\n         directory: merged-directory,\n         base:      locator.locator-base,\n         extension: locator.locator-extension)\n  else\n    locator\n  end\nend method merge-locators;\n\ndefine method merge-locators\n    (locator :: <physical-locator>, from-locator :: <file-locator>)\n => (merged-locator :: <physical-locator>)\n  let from-directory = from-locator.locator-directory;\n  if (from-directory)\n    merge-locators(locator, from-directory)\n  else\n    locator\n  end\nend method merge-locators;\n\n/// Locator protocols\n\ndefine sideways method supports-open-locator?\n    (locator :: <file-locator>) => (openable? :: <boolean>)\n  ~locator.locator-relative?\nend method supports-open-locator?;\n\ndefine sideways method open-locator\n    (locator :: <file-locator>, #rest keywords, #key, #all-keys)\n => (stream :: <stream>)\n  apply(open-file-stream, locator, keywords)\nend method open-locator;\n</textarea></div>\n\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        mode: \"text/x-dylan\",\n        lineNumbers: true,\n        matchBrackets: true,\n        continueComments: \"Enter\",\n        extraKeys: {\"Ctrl-Q\": \"toggleComment\"},\n        tabMode: \"indent\",\n        indentUnit: 2\n      });\n    </script>\n\n    <p><strong>MIME types defined:</strong> <code>text/x-dylan</code>.</p>\n</article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/ebnf/ebnf.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n\n  CodeMirror.defineMode(\"ebnf\", function (config) {\n    var commentType = {slash: 0, parenthesis: 1};\n    var stateType = {comment: 0, _string: 1, characterClass: 2};\n    var bracesMode = null;\n\n    if (config.bracesMode)\n      bracesMode = CodeMirror.getMode(config, config.bracesMode);\n\n    return {\n      startState: function () {\n        return {\n          stringType: null,\n          commentType: null,\n          braced: 0,\n          lhs: true,\n          localState: null,\n          stack: [],\n          inDefinition: false\n        };\n      },\n      token: function (stream, state) {\n        if (!stream) return;\n\n        //check for state changes\n        if (state.stack.length === 0) {\n          //strings\n          if ((stream.peek() == '\"') || (stream.peek() == \"'\")) {\n            state.stringType = stream.peek();\n            stream.next(); // Skip quote\n            state.stack.unshift(stateType._string);\n          } else if (stream.match(/^\\/\\*/)) { //comments starting with /*\n            state.stack.unshift(stateType.comment);\n            state.commentType = commentType.slash;\n          } else if (stream.match(/^\\(\\*/)) { //comments starting with (*\n            state.stack.unshift(stateType.comment);\n            state.commentType = commentType.parenthesis;\n          }\n        }\n\n        //return state\n        //stack has\n        switch (state.stack[0]) {\n        case stateType._string:\n          while (state.stack[0] === stateType._string && !stream.eol()) {\n            if (stream.peek() === state.stringType) {\n              stream.next(); // Skip quote\n              state.stack.shift(); // Clear flag\n            } else if (stream.peek() === \"\\\\\") {\n              stream.next();\n              stream.next();\n            } else {\n              stream.match(/^.[^\\\\\\\"\\']*/);\n            }\n          }\n          return state.lhs ? \"property string\" : \"string\"; // Token style\n\n        case stateType.comment:\n          while (state.stack[0] === stateType.comment && !stream.eol()) {\n            if (state.commentType === commentType.slash && stream.match(/\\*\\//)) {\n              state.stack.shift(); // Clear flag\n              state.commentType = null;\n            } else if (state.commentType === commentType.parenthesis && stream.match(/\\*\\)/)) {\n              state.stack.shift(); // Clear flag\n              state.commentType = null;\n            } else {\n              stream.match(/^.[^\\*]*/);\n            }\n          }\n          return \"comment\";\n\n        case stateType.characterClass:\n          while (state.stack[0] === stateType.characterClass && !stream.eol()) {\n            if (!(stream.match(/^[^\\]\\\\]+/) || stream.match(/^\\\\./))) {\n              state.stack.shift();\n            }\n          }\n          return \"operator\";\n        }\n\n        var peek = stream.peek();\n\n        if (bracesMode !== null && (state.braced || peek === \"{\")) {\n          if (state.localState === null)\n            state.localState = bracesMode.startState();\n\n          var token = bracesMode.token(stream, state.localState),\n          text = stream.current();\n\n          if (!token) {\n            for (var i = 0; i < text.length; i++) {\n              if (text[i] === \"{\") {\n                if (state.braced === 0) {\n                  token = \"matchingbracket\";\n                }\n                state.braced++;\n              } else if (text[i] === \"}\") {\n                state.braced--;\n                if (state.braced === 0) {\n                  token = \"matchingbracket\";\n                }\n              }\n            }\n          }\n          return token;\n        }\n\n        //no stack\n        switch (peek) {\n        case \"[\":\n          stream.next();\n          state.stack.unshift(stateType.characterClass);\n          return \"bracket\";\n        case \":\":\n        case \"|\":\n        case \";\":\n          stream.next();\n          return \"operator\";\n        case \"%\":\n          if (stream.match(\"%%\")) {\n            return \"header\";\n          } else if (stream.match(/[%][A-Za-z]+/)) {\n            return \"keyword\";\n          } else if (stream.match(/[%][}]/)) {\n            return \"matchingbracket\";\n          }\n          break;\n        case \"/\":\n          if (stream.match(/[\\/][A-Za-z]+/)) {\n          return \"keyword\";\n        }\n        case \"\\\\\":\n          if (stream.match(/[\\][a-z]+/)) {\n            return \"string-2\";\n          }\n        case \".\":\n          if (stream.match(\".\")) {\n            return \"atom\";\n          }\n        case \"*\":\n        case \"-\":\n        case \"+\":\n        case \"^\":\n          if (stream.match(peek)) {\n            return \"atom\";\n          }\n        case \"$\":\n          if (stream.match(\"$$\")) {\n            return \"builtin\";\n          } else if (stream.match(/[$][0-9]+/)) {\n            return \"variable-3\";\n          }\n        case \"<\":\n          if (stream.match(/<<[a-zA-Z_]+>>/)) {\n            return \"builtin\";\n          }\n        }\n\n        if (stream.match(/^\\/\\//)) {\n          stream.skipToEnd();\n          return \"comment\";\n        } else if (stream.match(/return/)) {\n          return \"operator\";\n        } else if (stream.match(/^[a-zA-Z_][a-zA-Z0-9_]*/)) {\n          if (stream.match(/(?=[\\(.])/)) {\n            return \"variable\";\n          } else if (stream.match(/(?=[\\s\\n]*[:=])/)) {\n            return \"def\";\n          }\n          return \"variable-2\";\n        } else if ([\"[\", \"]\", \"(\", \")\"].indexOf(stream.peek()) != -1) {\n          stream.next();\n          return \"bracket\";\n        } else if (!stream.eatSpace()) {\n          stream.next();\n        }\n        return null;\n      }\n    };\n  });\n\n  CodeMirror.defineMIME(\"text/x-ebnf\", \"ebnf\");\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/ebnf/index.html",
    "content": "<!doctype html>\n<html>\n  <head>\n    <title>CodeMirror: EBNF Mode</title>\n    <meta charset=\"utf-8\"/>\n    <link rel=stylesheet href=\"../../doc/docs.css\">\n\n    <link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n    <script src=\"../../lib/codemirror.js\"></script>\n    <script src=\"../javascript/javascript.js\"></script>\n    <script src=\"ebnf.js\"></script>\n    <style type=\"text/css\">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>\n  </head>\n  <body>\n    <div id=nav>\n      <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n      <ul>\n        <li><a href=\"../../index.html\">Home</a>\n        <li><a href=\"../../doc/manual.html\">Manual</a>\n        <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n      </ul>\n      <ul>\n        <li><a href=\"../index.html\">Language modes</a>\n        <li><a class=active href=\"#\">EBNF Mode</a>\n      </ul>\n    </div>\n\n    <article>\n      <h2>EBNF Mode (bracesMode setting = \"javascript\")</h2>\n      <form><textarea id=\"code\" name=\"code\">\n/* description: Parses end executes mathematical expressions. */\n\n/* lexical grammar */\n%lex\n\n%%\n\\s+                   /* skip whitespace */\n[0-9]+(\".\"[0-9]+)?\\b  return 'NUMBER';\n\"*\"                   return '*';\n\"/\"                   return '/';\n\"-\"                   return '-';\n\"+\"                   return '+';\n\"^\"                   return '^';\n\"(\"                   return '(';\n\")\"                   return ')';\n\"PI\"                  return 'PI';\n\"E\"                   return 'E';\n&lt;&lt;EOF&gt;&gt;               return 'EOF';\n\n/lex\n\n/* operator associations and precedence */\n\n%left '+' '-'\n%left '*' '/'\n%left '^'\n%left UMINUS\n\n%start expressions\n\n%% /* language grammar */\n\nexpressions\n: e EOF\n{print($1); return $1;}\n;\n\ne\n: e '+' e\n{$$ = $1+$3;}\n| e '-' e\n{$$ = $1-$3;}\n| e '*' e\n{$$ = $1*$3;}\n| e '/' e\n{$$ = $1/$3;}\n| e '^' e\n{$$ = Math.pow($1, $3);}\n| '-' e %prec UMINUS\n{$$ = -$2;}\n| '(' e ')'\n{$$ = $2;}\n| NUMBER\n{$$ = Number(yytext);}\n| E\n{$$ = Math.E;}\n| PI\n{$$ = Math.PI;}\n;</textarea></form>\n      <script>\n        var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n          mode: {name: \"ebnf\"},\n          lineNumbers: true,\n          bracesMode: 'javascript'\n        });\n      </script>\n      <h3>The EBNF Mode</h3>\n      <p> Created by <a href=\"https://github.com/robertleeplummerjr\">Robert Plummer</a></p>\n    </article>\n  </body>\n</html>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/ecl/ecl.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"ecl\", function(config) {\n\n  function words(str) {\n    var obj = {}, words = str.split(\" \");\n    for (var i = 0; i < words.length; ++i) obj[words[i]] = true;\n    return obj;\n  }\n\n  function metaHook(stream, state) {\n    if (!state.startOfLine) return false;\n    stream.skipToEnd();\n    return \"meta\";\n  }\n\n  var indentUnit = config.indentUnit;\n  var keyword = words(\"abs acos allnodes ascii asin asstring atan atan2 ave case choose choosen choosesets clustersize combine correlation cos cosh count covariance cron dataset dedup define denormalize distribute distributed distribution ebcdic enth error evaluate event eventextra eventname exists exp failcode failmessage fetch fromunicode getisvalid global graph group hash hash32 hash64 hashcrc hashmd5 having if index intformat isvalid iterate join keyunicode length library limit ln local log loop map matched matchlength matchposition matchtext matchunicode max merge mergejoin min nolocal nonempty normalize parse pipe power preload process project pull random range rank ranked realformat recordof regexfind regexreplace regroup rejected rollup round roundup row rowdiff sample set sin sinh sizeof soapcall sort sorted sqrt stepped stored sum table tan tanh thisnode topn tounicode transfer trim truncate typeof ungroup unicodeorder variance which workunit xmldecode xmlencode xmltext xmlunicode\");\n  var variable = words(\"apply assert build buildindex evaluate fail keydiff keypatch loadxml nothor notify output parallel sequential soapcall wait\");\n  var variable_2 = words(\"__compressed__ all and any as atmost before beginc++ best between case const counter csv descend encrypt end endc++ endmacro except exclusive expire export extend false few first flat from full function group header heading hole ifblock import in interface joined keep keyed last left limit load local locale lookup macro many maxcount maxlength min skew module named nocase noroot noscan nosort not of only opt or outer overwrite packed partition penalty physicallength pipe quote record relationship repeat return right scan self separator service shared skew skip sql store terminator thor threshold token transform trim true type unicodeorder unsorted validate virtual whole wild within xml xpath\");\n  var variable_3 = words(\"ascii big_endian boolean data decimal ebcdic integer pattern qstring real record rule set of string token udecimal unicode unsigned varstring varunicode\");\n  var builtin = words(\"checkpoint deprecated failcode failmessage failure global independent onwarning persist priority recovery stored success wait when\");\n  var blockKeywords = words(\"catch class do else finally for if switch try while\");\n  var atoms = words(\"true false null\");\n  var hooks = {\"#\": metaHook};\n  var multiLineStrings;\n  var isOperatorChar = /[+\\-*&%=<>!?|\\/]/;\n\n  var curPunc;\n\n  function tokenBase(stream, state) {\n    var ch = stream.next();\n    if (hooks[ch]) {\n      var result = hooks[ch](stream, state);\n      if (result !== false) return result;\n    }\n    if (ch == '\"' || ch == \"'\") {\n      state.tokenize = tokenString(ch);\n      return state.tokenize(stream, state);\n    }\n    if (/[\\[\\]{}\\(\\),;\\:\\.]/.test(ch)) {\n      curPunc = ch;\n      return null;\n    }\n    if (/\\d/.test(ch)) {\n      stream.eatWhile(/[\\w\\.]/);\n      return \"number\";\n    }\n    if (ch == \"/\") {\n      if (stream.eat(\"*\")) {\n        state.tokenize = tokenComment;\n        return tokenComment(stream, state);\n      }\n      if (stream.eat(\"/\")) {\n        stream.skipToEnd();\n        return \"comment\";\n      }\n    }\n    if (isOperatorChar.test(ch)) {\n      stream.eatWhile(isOperatorChar);\n      return \"operator\";\n    }\n    stream.eatWhile(/[\\w\\$_]/);\n    var cur = stream.current().toLowerCase();\n    if (keyword.propertyIsEnumerable(cur)) {\n      if (blockKeywords.propertyIsEnumerable(cur)) curPunc = \"newstatement\";\n      return \"keyword\";\n    } else if (variable.propertyIsEnumerable(cur)) {\n      if (blockKeywords.propertyIsEnumerable(cur)) curPunc = \"newstatement\";\n      return \"variable\";\n    } else if (variable_2.propertyIsEnumerable(cur)) {\n      if (blockKeywords.propertyIsEnumerable(cur)) curPunc = \"newstatement\";\n      return \"variable-2\";\n    } else if (variable_3.propertyIsEnumerable(cur)) {\n      if (blockKeywords.propertyIsEnumerable(cur)) curPunc = \"newstatement\";\n      return \"variable-3\";\n    } else if (builtin.propertyIsEnumerable(cur)) {\n      if (blockKeywords.propertyIsEnumerable(cur)) curPunc = \"newstatement\";\n      return \"builtin\";\n    } else { //Data types are of from KEYWORD##\n                var i = cur.length - 1;\n                while(i >= 0 && (!isNaN(cur[i]) || cur[i] == '_'))\n                        --i;\n\n                if (i > 0) {\n                        var cur2 = cur.substr(0, i + 1);\n                if (variable_3.propertyIsEnumerable(cur2)) {\n                        if (blockKeywords.propertyIsEnumerable(cur2)) curPunc = \"newstatement\";\n                        return \"variable-3\";\n                }\n            }\n    }\n    if (atoms.propertyIsEnumerable(cur)) return \"atom\";\n    return null;\n  }\n\n  function tokenString(quote) {\n    return function(stream, state) {\n      var escaped = false, next, end = false;\n      while ((next = stream.next()) != null) {\n        if (next == quote && !escaped) {end = true; break;}\n        escaped = !escaped && next == \"\\\\\";\n      }\n      if (end || !(escaped || multiLineStrings))\n        state.tokenize = tokenBase;\n      return \"string\";\n    };\n  }\n\n  function tokenComment(stream, state) {\n    var maybeEnd = false, ch;\n    while (ch = stream.next()) {\n      if (ch == \"/\" && maybeEnd) {\n        state.tokenize = tokenBase;\n        break;\n      }\n      maybeEnd = (ch == \"*\");\n    }\n    return \"comment\";\n  }\n\n  function Context(indented, column, type, align, prev) {\n    this.indented = indented;\n    this.column = column;\n    this.type = type;\n    this.align = align;\n    this.prev = prev;\n  }\n  function pushContext(state, col, type) {\n    return state.context = new Context(state.indented, col, type, null, state.context);\n  }\n  function popContext(state) {\n    var t = state.context.type;\n    if (t == \")\" || t == \"]\" || t == \"}\")\n      state.indented = state.context.indented;\n    return state.context = state.context.prev;\n  }\n\n  // Interface\n\n  return {\n    startState: function(basecolumn) {\n      return {\n        tokenize: null,\n        context: new Context((basecolumn || 0) - indentUnit, 0, \"top\", false),\n        indented: 0,\n        startOfLine: true\n      };\n    },\n\n    token: function(stream, state) {\n      var ctx = state.context;\n      if (stream.sol()) {\n        if (ctx.align == null) ctx.align = false;\n        state.indented = stream.indentation();\n        state.startOfLine = true;\n      }\n      if (stream.eatSpace()) return null;\n      curPunc = null;\n      var style = (state.tokenize || tokenBase)(stream, state);\n      if (style == \"comment\" || style == \"meta\") return style;\n      if (ctx.align == null) ctx.align = true;\n\n      if ((curPunc == \";\" || curPunc == \":\") && ctx.type == \"statement\") popContext(state);\n      else if (curPunc == \"{\") pushContext(state, stream.column(), \"}\");\n      else if (curPunc == \"[\") pushContext(state, stream.column(), \"]\");\n      else if (curPunc == \"(\") pushContext(state, stream.column(), \")\");\n      else if (curPunc == \"}\") {\n        while (ctx.type == \"statement\") ctx = popContext(state);\n        if (ctx.type == \"}\") ctx = popContext(state);\n        while (ctx.type == \"statement\") ctx = popContext(state);\n      }\n      else if (curPunc == ctx.type) popContext(state);\n      else if (ctx.type == \"}\" || ctx.type == \"top\" || (ctx.type == \"statement\" && curPunc == \"newstatement\"))\n        pushContext(state, stream.column(), \"statement\");\n      state.startOfLine = false;\n      return style;\n    },\n\n    indent: function(state, textAfter) {\n      if (state.tokenize != tokenBase && state.tokenize != null) return 0;\n      var ctx = state.context, firstChar = textAfter && textAfter.charAt(0);\n      if (ctx.type == \"statement\" && firstChar == \"}\") ctx = ctx.prev;\n      var closing = firstChar == ctx.type;\n      if (ctx.type == \"statement\") return ctx.indented + (firstChar == \"{\" ? 0 : indentUnit);\n      else if (ctx.align) return ctx.column + (closing ? 0 : 1);\n      else return ctx.indented + (closing ? 0 : indentUnit);\n    },\n\n    electricChars: \"{}\"\n  };\n});\n\nCodeMirror.defineMIME(\"text/x-ecl\", \"ecl\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/ecl/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: ECL mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"ecl.js\"></script>\n<style>.CodeMirror {border: 1px solid black;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">ECL</a>\n  </ul>\n</div>\n\n<article>\n<h2>ECL mode</h2>\n<form><textarea id=\"code\" name=\"code\">\n/*\nsample useless code to demonstrate ecl syntax highlighting\nthis is a multiline comment!\n*/\n\n//  this is a singleline comment!\n\nimport ut;\nr := \n  record\n   string22 s1 := '123';\n   integer4 i1 := 123;\n  end;\n#option('tmp', true);\nd := dataset('tmp::qb', r, thor);\noutput(d);\n</textarea></form>\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {});\n    </script>\n\n    <p>Based on CodeMirror's clike mode.  For more information see <a href=\"http://hpccsystems.com\">HPCC Systems</a> web site.</p>\n    <p><strong>MIME types defined:</strong> <code>text/x-ecl</code>.</p>\n\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/eiffel/eiffel.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"eiffel\", function() {\n  function wordObj(words) {\n    var o = {};\n    for (var i = 0, e = words.length; i < e; ++i) o[words[i]] = true;\n    return o;\n  }\n  var keywords = wordObj([\n    'note',\n    'across',\n    'when',\n    'variant',\n    'until',\n    'unique',\n    'undefine',\n    'then',\n    'strip',\n    'select',\n    'retry',\n    'rescue',\n    'require',\n    'rename',\n    'reference',\n    'redefine',\n    'prefix',\n    'once',\n    'old',\n    'obsolete',\n    'loop',\n    'local',\n    'like',\n    'is',\n    'inspect',\n    'infix',\n    'include',\n    'if',\n    'frozen',\n    'from',\n    'external',\n    'export',\n    'ensure',\n    'end',\n    'elseif',\n    'else',\n    'do',\n    'creation',\n    'create',\n    'check',\n    'alias',\n    'agent',\n    'separate',\n    'invariant',\n    'inherit',\n    'indexing',\n    'feature',\n    'expanded',\n    'deferred',\n    'class',\n    'Void',\n    'True',\n    'Result',\n    'Precursor',\n    'False',\n    'Current',\n    'create',\n    'attached',\n    'detachable',\n    'as',\n    'and',\n    'implies',\n    'not',\n    'or'\n  ]);\n  var operators = wordObj([\":=\", \"and then\",\"and\", \"or\",\"<<\",\">>\"]);\n  var curPunc;\n\n  function chain(newtok, stream, state) {\n    state.tokenize.push(newtok);\n    return newtok(stream, state);\n  }\n\n  function tokenBase(stream, state) {\n    curPunc = null;\n    if (stream.eatSpace()) return null;\n    var ch = stream.next();\n    if (ch == '\"'||ch == \"'\") {\n      return chain(readQuoted(ch, \"string\"), stream, state);\n    } else if (ch == \"-\"&&stream.eat(\"-\")) {\n      stream.skipToEnd();\n      return \"comment\";\n    } else if (ch == \":\"&&stream.eat(\"=\")) {\n      return \"operator\";\n    } else if (/[0-9]/.test(ch)) {\n      stream.eatWhile(/[xXbBCc0-9\\.]/);\n      stream.eat(/[\\?\\!]/);\n      return \"ident\";\n    } else if (/[a-zA-Z_0-9]/.test(ch)) {\n      stream.eatWhile(/[a-zA-Z_0-9]/);\n      stream.eat(/[\\?\\!]/);\n      return \"ident\";\n    } else if (/[=+\\-\\/*^%<>~]/.test(ch)) {\n      stream.eatWhile(/[=+\\-\\/*^%<>~]/);\n      return \"operator\";\n    } else {\n      return null;\n    }\n  }\n\n  function readQuoted(quote, style,  unescaped) {\n    return function(stream, state) {\n      var escaped = false, ch;\n      while ((ch = stream.next()) != null) {\n        if (ch == quote && (unescaped || !escaped)) {\n          state.tokenize.pop();\n          break;\n        }\n        escaped = !escaped && ch == \"%\";\n      }\n      return style;\n    };\n  }\n\n  return {\n    startState: function() {\n      return {tokenize: [tokenBase]};\n    },\n\n    token: function(stream, state) {\n      var style = state.tokenize[state.tokenize.length-1](stream, state);\n      if (style == \"ident\") {\n        var word = stream.current();\n        style = keywords.propertyIsEnumerable(stream.current()) ? \"keyword\"\n          : operators.propertyIsEnumerable(stream.current()) ? \"operator\"\n          : /^[A-Z][A-Z_0-9]*$/g.test(word) ? \"tag\"\n          : /^0[bB][0-1]+$/g.test(word) ? \"number\"\n          : /^0[cC][0-7]+$/g.test(word) ? \"number\"\n          : /^0[xX][a-fA-F0-9]+$/g.test(word) ? \"number\"\n          : /^([0-9]+\\.[0-9]*)|([0-9]*\\.[0-9]+)$/g.test(word) ? \"number\"\n          : /^[0-9]+$/g.test(word) ? \"number\"\n          : \"variable\";\n      }\n      return style;\n    },\n    lineComment: \"--\"\n  };\n});\n\nCodeMirror.defineMIME(\"text/x-eiffel\", \"eiffel\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/eiffel/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Eiffel mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<link rel=\"stylesheet\" href=\"../../theme/neat.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"eiffel.js\"></script>\n<style>\n      .CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}\n      .cm-s-default span.cm-arrow { color: red; }\n    </style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Eiffel</a>\n  </ul>\n</div>\n\n<article>\n<h2>Eiffel mode</h2>\n<form><textarea id=\"code\" name=\"code\">\nnote\n    description: \"[\n        Project-wide universal properties.\n        This class is an ancestor to all developer-written classes.\n        ANY may be customized for individual projects or teams.\n        ]\"\n\n    library: \"Free implementation of ELKS library\"\n    status: \"See notice at end of class.\"\n    legal: \"See notice at end of class.\"\n    date: \"$Date: 2013-01-25 11:49:00 -0800 (Fri, 25 Jan 2013) $\"\n    revision: \"$Revision: 712 $\"\n\nclass\n    ANY\n\nfeature -- Customization\n\nfeature -- Access\n\n    generator: STRING\n            -- Name of current object's generating class\n            -- (base class of the type of which it is a direct instance)\n        external\n            \"built_in\"\n        ensure\n            generator_not_void: Result /= Void\n            generator_not_empty: not Result.is_empty\n        end\n\n    generating_type: TYPE [detachable like Current]\n            -- Type of current object\n            -- (type of which it is a direct instance)\n        do\n            Result := {detachable like Current}\n        ensure\n            generating_type_not_void: Result /= Void\n        end\n\nfeature -- Status report\n\n    conforms_to (other: ANY): BOOLEAN\n            -- Does type of current object conform to type\n            -- of `other' (as per Eiffel: The Language, chapter 13)?\n        require\n            other_not_void: other /= Void\n        external\n            \"built_in\"\n        end\n\n    same_type (other: ANY): BOOLEAN\n            -- Is type of current object identical to type of `other'?\n        require\n            other_not_void: other /= Void\n        external\n            \"built_in\"\n        ensure\n            definition: Result = (conforms_to (other) and\n                                        other.conforms_to (Current))\n        end\n\nfeature -- Comparison\n\n    is_equal (other: like Current): BOOLEAN\n            -- Is `other' attached to an object considered\n            -- equal to current object?\n        require\n            other_not_void: other /= Void\n        external\n            \"built_in\"\n        ensure\n            symmetric: Result implies other ~ Current\n            consistent: standard_is_equal (other) implies Result\n        end\n\n    frozen standard_is_equal (other: like Current): BOOLEAN\n            -- Is `other' attached to an object of the same type\n            -- as current object, and field-by-field identical to it?\n        require\n            other_not_void: other /= Void\n        external\n            \"built_in\"\n        ensure\n            same_type: Result implies same_type (other)\n            symmetric: Result implies other.standard_is_equal (Current)\n        end\n\n    frozen equal (a: detachable ANY; b: like a): BOOLEAN\n            -- Are `a' and `b' either both void or attached\n            -- to objects considered equal?\n        do\n            if a = Void then\n                Result := b = Void\n            else\n                Result := b /= Void and then\n                            a.is_equal (b)\n            end\n        ensure\n            definition: Result = (a = Void and b = Void) or else\n                        ((a /= Void and b /= Void) and then\n                        a.is_equal (b))\n        end\n\n    frozen standard_equal (a: detachable ANY; b: like a): BOOLEAN\n            -- Are `a' and `b' either both void or attached to\n            -- field-by-field identical objects of the same type?\n            -- Always uses default object comparison criterion.\n        do\n            if a = Void then\n                Result := b = Void\n            else\n                Result := b /= Void and then\n                            a.standard_is_equal (b)\n            end\n        ensure\n            definition: Result = (a = Void and b = Void) or else\n                        ((a /= Void and b /= Void) and then\n                        a.standard_is_equal (b))\n        end\n\n    frozen is_deep_equal (other: like Current): BOOLEAN\n            -- Are `Current' and `other' attached to isomorphic object structures?\n        require\n            other_not_void: other /= Void\n        external\n            \"built_in\"\n        ensure\n            shallow_implies_deep: standard_is_equal (other) implies Result\n            same_type: Result implies same_type (other)\n            symmetric: Result implies other.is_deep_equal (Current)\n        end\n\n    frozen deep_equal (a: detachable ANY; b: like a): BOOLEAN\n            -- Are `a' and `b' either both void\n            -- or attached to isomorphic object structures?\n        do\n            if a = Void then\n                Result := b = Void\n            else\n                Result := b /= Void and then a.is_deep_equal (b)\n            end\n        ensure\n            shallow_implies_deep: standard_equal (a, b) implies Result\n            both_or_none_void: (a = Void) implies (Result = (b = Void))\n            same_type: (Result and (a /= Void)) implies (b /= Void and then a.same_type (b))\n            symmetric: Result implies deep_equal (b, a)\n        end\n\nfeature -- Duplication\n\n    frozen twin: like Current\n            -- New object equal to `Current'\n            -- `twin' calls `copy'; to change copying/twinning semantics, redefine `copy'.\n        external\n            \"built_in\"\n        ensure\n            twin_not_void: Result /= Void\n            is_equal: Result ~ Current\n        end\n\n    copy (other: like Current)\n            -- Update current object using fields of object attached\n            -- to `other', so as to yield equal objects.\n        require\n            other_not_void: other /= Void\n            type_identity: same_type (other)\n        external\n            \"built_in\"\n        ensure\n            is_equal: Current ~ other\n        end\n\n    frozen standard_copy (other: like Current)\n            -- Copy every field of `other' onto corresponding field\n            -- of current object.\n        require\n            other_not_void: other /= Void\n            type_identity: same_type (other)\n        external\n            \"built_in\"\n        ensure\n            is_standard_equal: standard_is_equal (other)\n        end\n\n    frozen clone (other: detachable ANY): like other\n            -- Void if `other' is void; otherwise new object\n            -- equal to `other'\n            --\n            -- For non-void `other', `clone' calls `copy';\n            -- to change copying/cloning semantics, redefine `copy'.\n        obsolete\n            \"Use `twin' instead.\"\n        do\n            if other /= Void then\n                Result := other.twin\n            end\n        ensure\n            equal: Result ~ other\n        end\n\n    frozen standard_clone (other: detachable ANY): like other\n            -- Void if `other' is void; otherwise new object\n            -- field-by-field identical to `other'.\n            -- Always uses default copying semantics.\n        obsolete\n            \"Use `standard_twin' instead.\"\n        do\n            if other /= Void then\n                Result := other.standard_twin\n            end\n        ensure\n            equal: standard_equal (Result, other)\n        end\n\n    frozen standard_twin: like Current\n            -- New object field-by-field identical to `other'.\n            -- Always uses default copying semantics.\n        external\n            \"built_in\"\n        ensure\n            standard_twin_not_void: Result /= Void\n            equal: standard_equal (Result, Current)\n        end\n\n    frozen deep_twin: like Current\n            -- New object structure recursively duplicated from Current.\n        external\n            \"built_in\"\n        ensure\n            deep_twin_not_void: Result /= Void\n            deep_equal: deep_equal (Current, Result)\n        end\n\n    frozen deep_clone (other: detachable ANY): like other\n            -- Void if `other' is void: otherwise, new object structure\n            -- recursively duplicated from the one attached to `other'\n        obsolete\n            \"Use `deep_twin' instead.\"\n        do\n            if other /= Void then\n                Result := other.deep_twin\n            end\n        ensure\n            deep_equal: deep_equal (other, Result)\n        end\n\n    frozen deep_copy (other: like Current)\n            -- Effect equivalent to that of:\n            --      `copy' (`other' . `deep_twin')\n        require\n            other_not_void: other /= Void\n        do\n            copy (other.deep_twin)\n        ensure\n            deep_equal: deep_equal (Current, other)\n        end\n\nfeature {NONE} -- Retrieval\n\n    frozen internal_correct_mismatch\n            -- Called from runtime to perform a proper dynamic dispatch on `correct_mismatch'\n            -- from MISMATCH_CORRECTOR.\n        local\n            l_msg: STRING\n            l_exc: EXCEPTIONS\n        do\n            if attached {MISMATCH_CORRECTOR} Current as l_corrector then\n                l_corrector.correct_mismatch\n            else\n                create l_msg.make_from_string (\"Mismatch: \")\n                create l_exc\n                l_msg.append (generating_type.name)\n                l_exc.raise_retrieval_exception (l_msg)\n            end\n        end\n\nfeature -- Output\n\n    io: STD_FILES\n            -- Handle to standard file setup\n        once\n            create Result\n            Result.set_output_default\n        ensure\n            io_not_void: Result /= Void\n        end\n\n    out: STRING\n            -- New string containing terse printable representation\n            -- of current object\n        do\n            Result := tagged_out\n        ensure\n            out_not_void: Result /= Void\n        end\n\n    frozen tagged_out: STRING\n            -- New string containing terse printable representation\n            -- of current object\n        external\n            \"built_in\"\n        ensure\n            tagged_out_not_void: Result /= Void\n        end\n\n    print (o: detachable ANY)\n            -- Write terse external representation of `o'\n            -- on standard output.\n        do\n            if o /= Void then\n                io.put_string (o.out)\n            end\n        end\n\nfeature -- Platform\n\n    Operating_environment: OPERATING_ENVIRONMENT\n            -- Objects available from the operating system\n        once\n            create Result\n        ensure\n            operating_environment_not_void: Result /= Void\n        end\n\nfeature {NONE} -- Initialization\n\n    default_create\n            -- Process instances of classes with no creation clause.\n            -- (Default: do nothing.)\n        do\n        end\n\nfeature -- Basic operations\n\n    default_rescue\n            -- Process exception for routines with no Rescue clause.\n            -- (Default: do nothing.)\n        do\n        end\n\n    frozen do_nothing\n            -- Execute a null action.\n        do\n        end\n\n    frozen default: detachable like Current\n            -- Default value of object's type\n        do\n        end\n\n    frozen default_pointer: POINTER\n            -- Default value of type `POINTER'\n            -- (Avoid the need to write `p'.`default' for\n            -- some `p' of type `POINTER'.)\n        do\n        ensure\n            -- Result = Result.default\n        end\n\n    frozen as_attached: attached like Current\n            -- Attached version of Current\n            -- (Can be used during transitional period to convert\n            -- non-void-safe classes to void-safe ones.)\n        do\n            Result := Current\n        end\n\ninvariant\n    reflexive_equality: standard_is_equal (Current)\n    reflexive_conformance: conforms_to (Current)\n\nnote\n    copyright: \"Copyright (c) 1984-2012, Eiffel Software and others\"\n    license:   \"Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)\"\n    source: \"[\n            Eiffel Software\n            5949 Hollister Ave., Goleta, CA 93117 USA\n            Telephone 805-685-1006, Fax 805-685-6869\n            Website http://www.eiffel.com\n            Customer support http://support.eiffel.com\n        ]\"\n\nend\n\n</textarea></form>\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        mode: \"text/x-eiffel\",\n        indentUnit: 4,\n        lineNumbers: true,\n        theme: \"neat\"\n      });\n    </script>\n\n    <p><strong>MIME types defined:</strong> <code>text/x-eiffel</code>.</p>\n \n <p> Created by <a href=\"https://github.com/ynh\">YNH</a>.</p>\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/erlang/erlang.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n/*jshint unused:true, eqnull:true, curly:true, bitwise:true */\n/*jshint undef:true, latedef:true, trailing:true */\n/*global CodeMirror:true */\n\n// erlang mode.\n// tokenizer -> token types -> CodeMirror styles\n// tokenizer maintains a parse stack\n// indenter uses the parse stack\n\n// TODO indenter:\n//   bit syntax\n//   old guard/bif/conversion clashes (e.g. \"float/1\")\n//   type/spec/opaque\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMIME(\"text/x-erlang\", \"erlang\");\n\nCodeMirror.defineMode(\"erlang\", function(cmCfg) {\n  \"use strict\";\n\n/////////////////////////////////////////////////////////////////////////////\n// constants\n\n  var typeWords = [\n    \"-type\", \"-spec\", \"-export_type\", \"-opaque\"];\n\n  var keywordWords = [\n    \"after\",\"begin\",\"catch\",\"case\",\"cond\",\"end\",\"fun\",\"if\",\n    \"let\",\"of\",\"query\",\"receive\",\"try\",\"when\"];\n\n  var separatorRE    = /[\\->,;]/;\n  var separatorWords = [\n    \"->\",\";\",\",\"];\n\n  var operatorAtomWords = [\n    \"and\",\"andalso\",\"band\",\"bnot\",\"bor\",\"bsl\",\"bsr\",\"bxor\",\n    \"div\",\"not\",\"or\",\"orelse\",\"rem\",\"xor\"];\n\n  var operatorSymbolRE    = /[\\+\\-\\*\\/<>=\\|:!]/;\n  var operatorSymbolWords = [\n    \"=\",\"+\",\"-\",\"*\",\"/\",\">\",\">=\",\"<\",\"=<\",\"=:=\",\"==\",\"=/=\",\"/=\",\"||\",\"<-\",\"!\"];\n\n  var openParenRE    = /[<\\(\\[\\{]/;\n  var openParenWords = [\n    \"<<\",\"(\",\"[\",\"{\"];\n\n  var closeParenRE    = /[>\\)\\]\\}]/;\n  var closeParenWords = [\n    \"}\",\"]\",\")\",\">>\"];\n\n  var guardWords = [\n    \"is_atom\",\"is_binary\",\"is_bitstring\",\"is_boolean\",\"is_float\",\n    \"is_function\",\"is_integer\",\"is_list\",\"is_number\",\"is_pid\",\n    \"is_port\",\"is_record\",\"is_reference\",\"is_tuple\",\n    \"atom\",\"binary\",\"bitstring\",\"boolean\",\"function\",\"integer\",\"list\",\n    \"number\",\"pid\",\"port\",\"record\",\"reference\",\"tuple\"];\n\n  var bifWords = [\n    \"abs\",\"adler32\",\"adler32_combine\",\"alive\",\"apply\",\"atom_to_binary\",\n    \"atom_to_list\",\"binary_to_atom\",\"binary_to_existing_atom\",\n    \"binary_to_list\",\"binary_to_term\",\"bit_size\",\"bitstring_to_list\",\n    \"byte_size\",\"check_process_code\",\"contact_binary\",\"crc32\",\n    \"crc32_combine\",\"date\",\"decode_packet\",\"delete_module\",\n    \"disconnect_node\",\"element\",\"erase\",\"exit\",\"float\",\"float_to_list\",\n    \"garbage_collect\",\"get\",\"get_keys\",\"group_leader\",\"halt\",\"hd\",\n    \"integer_to_list\",\"internal_bif\",\"iolist_size\",\"iolist_to_binary\",\n    \"is_alive\",\"is_atom\",\"is_binary\",\"is_bitstring\",\"is_boolean\",\n    \"is_float\",\"is_function\",\"is_integer\",\"is_list\",\"is_number\",\"is_pid\",\n    \"is_port\",\"is_process_alive\",\"is_record\",\"is_reference\",\"is_tuple\",\n    \"length\",\"link\",\"list_to_atom\",\"list_to_binary\",\"list_to_bitstring\",\n    \"list_to_existing_atom\",\"list_to_float\",\"list_to_integer\",\n    \"list_to_pid\",\"list_to_tuple\",\"load_module\",\"make_ref\",\"module_loaded\",\n    \"monitor_node\",\"node\",\"node_link\",\"node_unlink\",\"nodes\",\"notalive\",\n    \"now\",\"open_port\",\"pid_to_list\",\"port_close\",\"port_command\",\n    \"port_connect\",\"port_control\",\"pre_loaded\",\"process_flag\",\n    \"process_info\",\"processes\",\"purge_module\",\"put\",\"register\",\n    \"registered\",\"round\",\"self\",\"setelement\",\"size\",\"spawn\",\"spawn_link\",\n    \"spawn_monitor\",\"spawn_opt\",\"split_binary\",\"statistics\",\n    \"term_to_binary\",\"time\",\"throw\",\"tl\",\"trunc\",\"tuple_size\",\n    \"tuple_to_list\",\"unlink\",\"unregister\",\"whereis\"];\n\n// upper case: [A-Z] [Ø-Þ] [À-Ö]\n// lower case: [a-z] [ß-ö] [ø-ÿ]\n  var anumRE       = /[\\w@Ø-ÞÀ-Öß-öø-ÿ]/;\n  var escapesRE    =\n    /[0-7]{1,3}|[bdefnrstv\\\\\"']|\\^[a-zA-Z]|x[0-9a-zA-Z]{2}|x{[0-9a-zA-Z]+}/;\n\n/////////////////////////////////////////////////////////////////////////////\n// tokenizer\n\n  function tokenizer(stream,state) {\n    // in multi-line string\n    if (state.in_string) {\n      state.in_string = (!doubleQuote(stream));\n      return rval(state,stream,\"string\");\n    }\n\n    // in multi-line atom\n    if (state.in_atom) {\n      state.in_atom = (!singleQuote(stream));\n      return rval(state,stream,\"atom\");\n    }\n\n    // whitespace\n    if (stream.eatSpace()) {\n      return rval(state,stream,\"whitespace\");\n    }\n\n    // attributes and type specs\n    if (!peekToken(state) &&\n        stream.match(/-\\s*[a-zß-öø-ÿ][\\wØ-ÞÀ-Öß-öø-ÿ]*/)) {\n      if (is_member(stream.current(),typeWords)) {\n        return rval(state,stream,\"type\");\n      }else{\n        return rval(state,stream,\"attribute\");\n      }\n    }\n\n    var ch = stream.next();\n\n    // comment\n    if (ch == '%') {\n      stream.skipToEnd();\n      return rval(state,stream,\"comment\");\n    }\n\n    // colon\n    if (ch == \":\") {\n      return rval(state,stream,\"colon\");\n    }\n\n    // macro\n    if (ch == '?') {\n      stream.eatSpace();\n      stream.eatWhile(anumRE);\n      return rval(state,stream,\"macro\");\n    }\n\n    // record\n    if (ch == \"#\") {\n      stream.eatSpace();\n      stream.eatWhile(anumRE);\n      return rval(state,stream,\"record\");\n    }\n\n    // dollar escape\n    if (ch == \"$\") {\n      if (stream.next() == \"\\\\\" && !stream.match(escapesRE)) {\n        return rval(state,stream,\"error\");\n      }\n      return rval(state,stream,\"number\");\n    }\n\n    // dot\n    if (ch == \".\") {\n      return rval(state,stream,\"dot\");\n    }\n\n    // quoted atom\n    if (ch == '\\'') {\n      if (!(state.in_atom = (!singleQuote(stream)))) {\n        if (stream.match(/\\s*\\/\\s*[0-9]/,false)) {\n          stream.match(/\\s*\\/\\s*[0-9]/,true);\n          return rval(state,stream,\"fun\");      // 'f'/0 style fun\n        }\n        if (stream.match(/\\s*\\(/,false) || stream.match(/\\s*:/,false)) {\n          return rval(state,stream,\"function\");\n        }\n      }\n      return rval(state,stream,\"atom\");\n    }\n\n    // string\n    if (ch == '\"') {\n      state.in_string = (!doubleQuote(stream));\n      return rval(state,stream,\"string\");\n    }\n\n    // variable\n    if (/[A-Z_Ø-ÞÀ-Ö]/.test(ch)) {\n      stream.eatWhile(anumRE);\n      return rval(state,stream,\"variable\");\n    }\n\n    // atom/keyword/BIF/function\n    if (/[a-z_ß-öø-ÿ]/.test(ch)) {\n      stream.eatWhile(anumRE);\n\n      if (stream.match(/\\s*\\/\\s*[0-9]/,false)) {\n        stream.match(/\\s*\\/\\s*[0-9]/,true);\n        return rval(state,stream,\"fun\");      // f/0 style fun\n      }\n\n      var w = stream.current();\n\n      if (is_member(w,keywordWords)) {\n        return rval(state,stream,\"keyword\");\n      }else if (is_member(w,operatorAtomWords)) {\n        return rval(state,stream,\"operator\");\n      }else if (stream.match(/\\s*\\(/,false)) {\n        // 'put' and 'erlang:put' are bifs, 'foo:put' is not\n        if (is_member(w,bifWords) &&\n            ((peekToken(state).token != \":\") ||\n             (peekToken(state,2).token == \"erlang\"))) {\n          return rval(state,stream,\"builtin\");\n        }else if (is_member(w,guardWords)) {\n          return rval(state,stream,\"guard\");\n        }else{\n          return rval(state,stream,\"function\");\n        }\n      }else if (is_member(w,operatorAtomWords)) {\n        return rval(state,stream,\"operator\");\n      }else if (lookahead(stream) == \":\") {\n        if (w == \"erlang\") {\n          return rval(state,stream,\"builtin\");\n        } else {\n          return rval(state,stream,\"function\");\n        }\n      }else if (is_member(w,[\"true\",\"false\"])) {\n        return rval(state,stream,\"boolean\");\n      }else if (is_member(w,[\"true\",\"false\"])) {\n        return rval(state,stream,\"boolean\");\n      }else{\n        return rval(state,stream,\"atom\");\n      }\n    }\n\n    // number\n    var digitRE      = /[0-9]/;\n    var radixRE      = /[0-9a-zA-Z]/;         // 36#zZ style int\n    if (digitRE.test(ch)) {\n      stream.eatWhile(digitRE);\n      if (stream.eat('#')) {                // 36#aZ  style integer\n        if (!stream.eatWhile(radixRE)) {\n          stream.backUp(1);                 //\"36#\" - syntax error\n        }\n      } else if (stream.eat('.')) {       // float\n        if (!stream.eatWhile(digitRE)) {\n          stream.backUp(1);        // \"3.\" - probably end of function\n        } else {\n          if (stream.eat(/[eE]/)) {        // float with exponent\n            if (stream.eat(/[-+]/)) {\n              if (!stream.eatWhile(digitRE)) {\n                stream.backUp(2);            // \"2e-\" - syntax error\n              }\n            } else {\n              if (!stream.eatWhile(digitRE)) {\n                stream.backUp(1);            // \"2e\" - syntax error\n              }\n            }\n          }\n        }\n      }\n      return rval(state,stream,\"number\");   // normal integer\n    }\n\n    // open parens\n    if (nongreedy(stream,openParenRE,openParenWords)) {\n      return rval(state,stream,\"open_paren\");\n    }\n\n    // close parens\n    if (nongreedy(stream,closeParenRE,closeParenWords)) {\n      return rval(state,stream,\"close_paren\");\n    }\n\n    // separators\n    if (greedy(stream,separatorRE,separatorWords)) {\n      return rval(state,stream,\"separator\");\n    }\n\n    // operators\n    if (greedy(stream,operatorSymbolRE,operatorSymbolWords)) {\n      return rval(state,stream,\"operator\");\n    }\n\n    return rval(state,stream,null);\n  }\n\n/////////////////////////////////////////////////////////////////////////////\n// utilities\n  function nongreedy(stream,re,words) {\n    if (stream.current().length == 1 && re.test(stream.current())) {\n      stream.backUp(1);\n      while (re.test(stream.peek())) {\n        stream.next();\n        if (is_member(stream.current(),words)) {\n          return true;\n        }\n      }\n      stream.backUp(stream.current().length-1);\n    }\n    return false;\n  }\n\n  function greedy(stream,re,words) {\n    if (stream.current().length == 1 && re.test(stream.current())) {\n      while (re.test(stream.peek())) {\n        stream.next();\n      }\n      while (0 < stream.current().length) {\n        if (is_member(stream.current(),words)) {\n          return true;\n        }else{\n          stream.backUp(1);\n        }\n      }\n      stream.next();\n    }\n    return false;\n  }\n\n  function doubleQuote(stream) {\n    return quote(stream, '\"', '\\\\');\n  }\n\n  function singleQuote(stream) {\n    return quote(stream,'\\'','\\\\');\n  }\n\n  function quote(stream,quoteChar,escapeChar) {\n    while (!stream.eol()) {\n      var ch = stream.next();\n      if (ch == quoteChar) {\n        return true;\n      }else if (ch == escapeChar) {\n        stream.next();\n      }\n    }\n    return false;\n  }\n\n  function lookahead(stream) {\n    var m = stream.match(/([\\n\\s]+|%[^\\n]*\\n)*(.)/,false);\n    return m ? m.pop() : \"\";\n  }\n\n  function is_member(element,list) {\n    return (-1 < list.indexOf(element));\n  }\n\n  function rval(state,stream,type) {\n\n    // parse stack\n    pushToken(state,realToken(type,stream));\n\n    // map erlang token type to CodeMirror style class\n    //     erlang             -> CodeMirror tag\n    switch (type) {\n      case \"atom\":        return \"atom\";\n      case \"attribute\":   return \"attribute\";\n      case \"boolean\":     return \"atom\";\n      case \"builtin\":     return \"builtin\";\n      case \"close_paren\": return null;\n      case \"colon\":       return null;\n      case \"comment\":     return \"comment\";\n      case \"dot\":         return null;\n      case \"error\":       return \"error\";\n      case \"fun\":         return \"meta\";\n      case \"function\":    return \"tag\";\n      case \"guard\":       return \"property\";\n      case \"keyword\":     return \"keyword\";\n      case \"macro\":       return \"variable-2\";\n      case \"number\":      return \"number\";\n      case \"open_paren\":  return null;\n      case \"operator\":    return \"operator\";\n      case \"record\":      return \"bracket\";\n      case \"separator\":   return null;\n      case \"string\":      return \"string\";\n      case \"type\":        return \"def\";\n      case \"variable\":    return \"variable\";\n      default:            return null;\n    }\n  }\n\n  function aToken(tok,col,ind,typ) {\n    return {token:  tok,\n            column: col,\n            indent: ind,\n            type:   typ};\n  }\n\n  function realToken(type,stream) {\n    return aToken(stream.current(),\n                 stream.column(),\n                 stream.indentation(),\n                 type);\n  }\n\n  function fakeToken(type) {\n    return aToken(type,0,0,type);\n  }\n\n  function peekToken(state,depth) {\n    var len = state.tokenStack.length;\n    var dep = (depth ? depth : 1);\n\n    if (len < dep) {\n      return false;\n    }else{\n      return state.tokenStack[len-dep];\n    }\n  }\n\n  function pushToken(state,token) {\n\n    if (!(token.type == \"comment\" || token.type == \"whitespace\")) {\n      state.tokenStack = maybe_drop_pre(state.tokenStack,token);\n      state.tokenStack = maybe_drop_post(state.tokenStack);\n    }\n  }\n\n  function maybe_drop_pre(s,token) {\n    var last = s.length-1;\n\n    if (0 < last && s[last].type === \"record\" && token.type === \"dot\") {\n      s.pop();\n    }else if (0 < last && s[last].type === \"group\") {\n      s.pop();\n      s.push(token);\n    }else{\n      s.push(token);\n    }\n    return s;\n  }\n\n  function maybe_drop_post(s) {\n    var last = s.length-1;\n\n    if (s[last].type === \"dot\") {\n      return [];\n    }\n    if (s[last].type === \"fun\" && s[last-1].token === \"fun\") {\n      return s.slice(0,last-1);\n    }\n    switch (s[s.length-1].token) {\n      case \"}\":    return d(s,{g:[\"{\"]});\n      case \"]\":    return d(s,{i:[\"[\"]});\n      case \")\":    return d(s,{i:[\"(\"]});\n      case \">>\":   return d(s,{i:[\"<<\"]});\n      case \"end\":  return d(s,{i:[\"begin\",\"case\",\"fun\",\"if\",\"receive\",\"try\"]});\n      case \",\":    return d(s,{e:[\"begin\",\"try\",\"when\",\"->\",\n                                  \",\",\"(\",\"[\",\"{\",\"<<\"]});\n      case \"->\":   return d(s,{r:[\"when\"],\n                               m:[\"try\",\"if\",\"case\",\"receive\"]});\n      case \";\":    return d(s,{E:[\"case\",\"fun\",\"if\",\"receive\",\"try\",\"when\"]});\n      case \"catch\":return d(s,{e:[\"try\"]});\n      case \"of\":   return d(s,{e:[\"case\"]});\n      case \"after\":return d(s,{e:[\"receive\",\"try\"]});\n      default:     return s;\n    }\n  }\n\n  function d(stack,tt) {\n    // stack is a stack of Token objects.\n    // tt is an object; {type:tokens}\n    // type is a char, tokens is a list of token strings.\n    // The function returns (possibly truncated) stack.\n    // It will descend the stack, looking for a Token such that Token.token\n    //  is a member of tokens. If it does not find that, it will normally (but\n    //  see \"E\" below) return stack. If it does find a match, it will remove\n    //  all the Tokens between the top and the matched Token.\n    // If type is \"m\", that is all it does.\n    // If type is \"i\", it will also remove the matched Token and the top Token.\n    // If type is \"g\", like \"i\", but add a fake \"group\" token at the top.\n    // If type is \"r\", it will remove the matched Token, but not the top Token.\n    // If type is \"e\", it will keep the matched Token but not the top Token.\n    // If type is \"E\", it behaves as for type \"e\", except if there is no match,\n    //  in which case it will return an empty stack.\n\n    for (var type in tt) {\n      var len = stack.length-1;\n      var tokens = tt[type];\n      for (var i = len-1; -1 < i ; i--) {\n        if (is_member(stack[i].token,tokens)) {\n          var ss = stack.slice(0,i);\n          switch (type) {\n              case \"m\": return ss.concat(stack[i]).concat(stack[len]);\n              case \"r\": return ss.concat(stack[len]);\n              case \"i\": return ss;\n              case \"g\": return ss.concat(fakeToken(\"group\"));\n              case \"E\": return ss.concat(stack[i]);\n              case \"e\": return ss.concat(stack[i]);\n          }\n        }\n      }\n    }\n    return (type == \"E\" ? [] : stack);\n  }\n\n/////////////////////////////////////////////////////////////////////////////\n// indenter\n\n  function indenter(state,textAfter) {\n    var t;\n    var unit = cmCfg.indentUnit;\n    var wordAfter = wordafter(textAfter);\n    var currT = peekToken(state,1);\n    var prevT = peekToken(state,2);\n\n    if (state.in_string || state.in_atom) {\n      return CodeMirror.Pass;\n    }else if (!prevT) {\n      return 0;\n    }else if (currT.token == \"when\") {\n      return currT.column+unit;\n    }else if (wordAfter === \"when\" && prevT.type === \"function\") {\n      return prevT.indent+unit;\n    }else if (wordAfter === \"(\" && currT.token === \"fun\") {\n      return  currT.column+3;\n    }else if (wordAfter === \"catch\" && (t = getToken(state,[\"try\"]))) {\n      return t.column;\n    }else if (is_member(wordAfter,[\"end\",\"after\",\"of\"])) {\n      t = getToken(state,[\"begin\",\"case\",\"fun\",\"if\",\"receive\",\"try\"]);\n      return t ? t.column : CodeMirror.Pass;\n    }else if (is_member(wordAfter,closeParenWords)) {\n      t = getToken(state,openParenWords);\n      return t ? t.column : CodeMirror.Pass;\n    }else if (is_member(currT.token,[\",\",\"|\",\"||\"]) ||\n              is_member(wordAfter,[\",\",\"|\",\"||\"])) {\n      t = postcommaToken(state);\n      return t ? t.column+t.token.length : unit;\n    }else if (currT.token == \"->\") {\n      if (is_member(prevT.token, [\"receive\",\"case\",\"if\",\"try\"])) {\n        return prevT.column+unit+unit;\n      }else{\n        return prevT.column+unit;\n      }\n    }else if (is_member(currT.token,openParenWords)) {\n      return currT.column+currT.token.length;\n    }else{\n      t = defaultToken(state);\n      return truthy(t) ? t.column+unit : 0;\n    }\n  }\n\n  function wordafter(str) {\n    var m = str.match(/,|[a-z]+|\\}|\\]|\\)|>>|\\|+|\\(/);\n\n    return truthy(m) && (m.index === 0) ? m[0] : \"\";\n  }\n\n  function postcommaToken(state) {\n    var objs = state.tokenStack.slice(0,-1);\n    var i = getTokenIndex(objs,\"type\",[\"open_paren\"]);\n\n    return truthy(objs[i]) ? objs[i] : false;\n  }\n\n  function defaultToken(state) {\n    var objs = state.tokenStack;\n    var stop = getTokenIndex(objs,\"type\",[\"open_paren\",\"separator\",\"keyword\"]);\n    var oper = getTokenIndex(objs,\"type\",[\"operator\"]);\n\n    if (truthy(stop) && truthy(oper) && stop < oper) {\n      return objs[stop+1];\n    } else if (truthy(stop)) {\n      return objs[stop];\n    } else {\n      return false;\n    }\n  }\n\n  function getToken(state,tokens) {\n    var objs = state.tokenStack;\n    var i = getTokenIndex(objs,\"token\",tokens);\n\n    return truthy(objs[i]) ? objs[i] : false;\n  }\n\n  function getTokenIndex(objs,propname,propvals) {\n\n    for (var i = objs.length-1; -1 < i ; i--) {\n      if (is_member(objs[i][propname],propvals)) {\n        return i;\n      }\n    }\n    return false;\n  }\n\n  function truthy(x) {\n    return (x !== false) && (x != null);\n  }\n\n/////////////////////////////////////////////////////////////////////////////\n// this object defines the mode\n\n  return {\n    startState:\n      function() {\n        return {tokenStack: [],\n                in_string:  false,\n                in_atom:    false};\n      },\n\n    token:\n      function(stream, state) {\n        return tokenizer(stream, state);\n      },\n\n    indent:\n      function(state, textAfter) {\n        return indenter(state,textAfter);\n      },\n\n    lineComment: \"%\"\n  };\n});\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/erlang/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Erlang mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<link rel=\"stylesheet\" href=\"../../theme/erlang-dark.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"../../addon/edit/matchbrackets.js\"></script>\n<script src=\"erlang.js\"></script>\n<style type=\"text/css\">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Erlang</a>\n  </ul>\n</div>\n\n<article>\n<h2>Erlang mode</h2>\n<form><textarea id=\"code\" name=\"code\">\n%% -*- mode: erlang; erlang-indent-level: 2 -*-\n%%% Created :  7 May 2012 by mats cronqvist <masse@klarna.com>\n\n%% @doc\n%% Demonstrates how to print a record.\n%% @end\n\n-module('ex').\n-author('mats cronqvist').\n-export([demo/0,\n         rec_info/1]).\n\n-record(demo,{a=\"One\",b=\"Two\",c=\"Three\",d=\"Four\"}).\n\nrec_info(demo) -> record_info(fields,demo).\n\ndemo() -> expand_recs(?MODULE,#demo{a=\"A\",b=\"BB\"}).\n\nexpand_recs(M,List) when is_list(List) ->\n  [expand_recs(M,L)||L<-List];\nexpand_recs(M,Tup) when is_tuple(Tup) ->\n  case tuple_size(Tup) of\n    L when L < 1 -> Tup;\n    L ->\n      try\n        Fields = M:rec_info(element(1,Tup)),\n        L = length(Fields)+1,\n        lists:zip(Fields,expand_recs(M,tl(tuple_to_list(Tup))))\n      catch\n        _:_ -> list_to_tuple(expand_recs(M,tuple_to_list(Tup)))\n      end\n  end;\nexpand_recs(_,Term) ->\n  Term.\n</textarea></form>\n\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        lineNumbers: true,\n        matchBrackets: true,\n        extraKeys: {\"Tab\":  \"indentAuto\"},\n        theme: \"erlang-dark\"\n      });\n    </script>\n\n    <p><strong>MIME types defined:</strong> <code>text/x-erlang</code>.</p>\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/forth/forth.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n// Author: Aliaksei Chapyzhenka\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n\n  function toWordList(words) {\n    var ret = [];\n    words.split(' ').forEach(function(e){\n      ret.push({name: e});\n    });\n    return ret;\n  }\n\n  var coreWordList = toWordList(\n'INVERT AND OR XOR\\\n 2* 2/ LSHIFT RSHIFT\\\n 0= = 0< < > U< MIN MAX\\\n 2DROP 2DUP 2OVER 2SWAP ?DUP DEPTH DROP DUP OVER ROT SWAP\\\n >R R> R@\\\n + - 1+ 1- ABS NEGATE\\\n S>D * M* UM*\\\n FM/MOD SM/REM UM/MOD */ */MOD / /MOD MOD\\\n HERE , @ ! CELL+ CELLS C, C@ C! CHARS 2@ 2!\\\n ALIGN ALIGNED +! ALLOT\\\n CHAR [CHAR] [ ] BL\\\n FIND EXECUTE IMMEDIATE COUNT LITERAL STATE\\\n ; DOES> >BODY\\\n EVALUATE\\\n SOURCE >IN\\\n <# # #S #> HOLD SIGN BASE >NUMBER HEX DECIMAL\\\n FILL MOVE\\\n . CR EMIT SPACE SPACES TYPE U. .R U.R\\\n ACCEPT\\\n TRUE FALSE\\\n <> U> 0<> 0>\\\n NIP TUCK ROLL PICK\\\n 2>R 2R@ 2R>\\\n WITHIN UNUSED MARKER\\\n I J\\\n TO\\\n COMPILE, [COMPILE]\\\n SAVE-INPUT RESTORE-INPUT\\\n PAD ERASE\\\n 2LITERAL DNEGATE\\\n D- D+ D0< D0= D2* D2/ D< D= DMAX DMIN D>S DABS\\\n M+ M*/ D. D.R 2ROT DU<\\\n CATCH THROW\\\n FREE RESIZE ALLOCATE\\\n CS-PICK CS-ROLL\\\n GET-CURRENT SET-CURRENT FORTH-WORDLIST GET-ORDER SET-ORDER\\\n PREVIOUS SEARCH-WORDLIST WORDLIST FIND ALSO ONLY FORTH DEFINITIONS ORDER\\\n -TRAILING /STRING SEARCH COMPARE CMOVE CMOVE> BLANK SLITERAL');\n\n  var immediateWordList = toWordList('IF ELSE THEN BEGIN WHILE REPEAT UNTIL RECURSE [IF] [ELSE] [THEN] ?DO DO LOOP +LOOP UNLOOP LEAVE EXIT AGAIN CASE OF ENDOF ENDCASE');\n\n  CodeMirror.defineMode('forth', function() {\n    function searchWordList (wordList, word) {\n      var i;\n      for (i = wordList.length - 1; i >= 0; i--) {\n        if (wordList[i].name === word.toUpperCase()) {\n          return wordList[i];\n        }\n      }\n      return undefined;\n    }\n  return {\n    startState: function() {\n      return {\n        state: '',\n        base: 10,\n        coreWordList: coreWordList,\n        immediateWordList: immediateWordList,\n        wordList: []\n      };\n    },\n    token: function (stream, stt) {\n      var mat;\n      if (stream.eatSpace()) {\n        return null;\n      }\n      if (stt.state === '') { // interpretation\n        if (stream.match(/^(\\]|:NONAME)(\\s|$)/i)) {\n          stt.state = ' compilation';\n          return 'builtin compilation';\n        }\n        mat = stream.match(/^(\\:)\\s+(\\S+)(\\s|$)+/);\n        if (mat) {\n          stt.wordList.push({name: mat[2].toUpperCase()});\n          stt.state = ' compilation';\n          return 'def' + stt.state;\n        }\n        mat = stream.match(/^(VARIABLE|2VARIABLE|CONSTANT|2CONSTANT|CREATE|POSTPONE|VALUE|WORD)\\s+(\\S+)(\\s|$)+/i);\n        if (mat) {\n          stt.wordList.push({name: mat[2].toUpperCase()});\n          return 'def' + stt.state;\n        }\n        mat = stream.match(/^(\\'|\\[\\'\\])\\s+(\\S+)(\\s|$)+/);\n        if (mat) {\n          return 'builtin' + stt.state;\n        }\n        } else { // compilation\n        // ; [\n        if (stream.match(/^(\\;|\\[)(\\s)/)) {\n          stt.state = '';\n          stream.backUp(1);\n          return 'builtin compilation';\n        }\n        if (stream.match(/^(\\;|\\[)($)/)) {\n          stt.state = '';\n          return 'builtin compilation';\n        }\n        if (stream.match(/^(POSTPONE)\\s+\\S+(\\s|$)+/)) {\n          return 'builtin';\n        }\n      }\n\n      // dynamic wordlist\n      mat = stream.match(/^(\\S+)(\\s+|$)/);\n      if (mat) {\n        if (searchWordList(stt.wordList, mat[1]) !== undefined) {\n          return 'variable' + stt.state;\n        }\n\n        // comments\n        if (mat[1] === '\\\\') {\n          stream.skipToEnd();\n            return 'comment' + stt.state;\n          }\n\n          // core words\n          if (searchWordList(stt.coreWordList, mat[1]) !== undefined) {\n            return 'builtin' + stt.state;\n          }\n          if (searchWordList(stt.immediateWordList, mat[1]) !== undefined) {\n            return 'keyword' + stt.state;\n          }\n\n          if (mat[1] === '(') {\n            stream.eatWhile(function (s) { return s !== ')'; });\n            stream.eat(')');\n            return 'comment' + stt.state;\n          }\n\n          // // strings\n          if (mat[1] === '.(') {\n            stream.eatWhile(function (s) { return s !== ')'; });\n            stream.eat(')');\n            return 'string' + stt.state;\n          }\n          if (mat[1] === 'S\"' || mat[1] === '.\"' || mat[1] === 'C\"') {\n            stream.eatWhile(function (s) { return s !== '\"'; });\n            stream.eat('\"');\n            return 'string' + stt.state;\n          }\n\n          // numbers\n          if (mat[1] - 0xfffffffff) {\n            return 'number' + stt.state;\n          }\n          // if (mat[1].match(/^[-+]?[0-9]+\\.[0-9]*/)) {\n          //     return 'number' + stt.state;\n          // }\n\n          return 'atom' + stt.state;\n        }\n      }\n    };\n  });\n  CodeMirror.defineMIME(\"text/x-forth\", \"forth\");\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/forth/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Forth mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link href='http://fonts.googleapis.com/css?family=Droid+Sans+Mono' rel='stylesheet' type='text/css'>\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<link rel=stylesheet href=\"../../theme/colorforth.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"forth.js\"></script>\n<style>\n.CodeMirror {\n    font-family: 'Droid Sans Mono', monospace;\n    font-size: 14px;\n}\n</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Forth</a>\n  </ul>\n</div>\n\n<article>\n\n<h2>Forth mode</h2>\n\n<form><textarea id=\"code\" name=\"code\">\n\\ Insertion sort\n\n: cell-  1 cells - ;\n\n: insert ( start end -- start )\n  dup @ >r ( r: v )\n  begin\n    2dup <\n  while\n    r@ over cell- @ <\n  while\n    cell-\n    dup @ over cell+ !\n  repeat then\n  r> swap ! ;\n\n: sort ( array len -- )\n  1 ?do\n    dup i cells + insert\n  loop drop ;</textarea>\n  </form>\n\n<script>\n  var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n    lineNumbers: true,\n    lineWrapping: true,\n    indentUnit: 2,\n    tabSize: 2,\n    autofocus: true,\n    theme: \"colorforth\",\n    mode: \"text/x-forth\"\n  });\n</script>\n\n<p>Simple mode that handle Forth-Syntax (<a href=\"http://en.wikipedia.org/wiki/Forth_%28programming_language%29\">Forth on WikiPedia</a>).</p>\n\n<p><strong>MIME types defined:</strong> <code>text/x-forth</code>.</p>\n\n</article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/fortran/fortran.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"fortran\", function() {\n  function words(array) {\n    var keys = {};\n    for (var i = 0; i < array.length; ++i) {\n      keys[array[i]] = true;\n    }\n    return keys;\n  }\n\n  var keywords = words([\n                  \"abstract\", \"accept\", \"allocatable\", \"allocate\",\n                  \"array\", \"assign\", \"asynchronous\", \"backspace\",\n                  \"bind\", \"block\", \"byte\", \"call\", \"case\",\n                  \"class\", \"close\", \"common\", \"contains\",\n                  \"continue\", \"cycle\", \"data\", \"deallocate\",\n                  \"decode\", \"deferred\", \"dimension\", \"do\",\n                  \"elemental\", \"else\", \"encode\", \"end\",\n                  \"endif\", \"entry\", \"enumerator\", \"equivalence\",\n                  \"exit\", \"external\", \"extrinsic\", \"final\",\n                  \"forall\", \"format\", \"function\", \"generic\",\n                  \"go\", \"goto\", \"if\", \"implicit\", \"import\", \"include\",\n                  \"inquire\", \"intent\", \"interface\", \"intrinsic\",\n                  \"module\", \"namelist\", \"non_intrinsic\",\n                  \"non_overridable\", \"none\", \"nopass\",\n                  \"nullify\", \"open\", \"optional\", \"options\",\n                  \"parameter\", \"pass\", \"pause\", \"pointer\",\n                  \"print\", \"private\", \"program\", \"protected\",\n                  \"public\", \"pure\", \"read\", \"recursive\", \"result\",\n                  \"return\", \"rewind\", \"save\", \"select\", \"sequence\",\n                  \"stop\", \"subroutine\", \"target\", \"then\", \"to\", \"type\",\n                  \"use\", \"value\", \"volatile\", \"where\", \"while\",\n                  \"write\"]);\n  var builtins = words([\"abort\", \"abs\", \"access\", \"achar\", \"acos\",\n                          \"adjustl\", \"adjustr\", \"aimag\", \"aint\", \"alarm\",\n                          \"all\", \"allocated\", \"alog\", \"amax\", \"amin\",\n                          \"amod\", \"and\", \"anint\", \"any\", \"asin\",\n                          \"associated\", \"atan\", \"besj\", \"besjn\", \"besy\",\n                          \"besyn\", \"bit_size\", \"btest\", \"cabs\", \"ccos\",\n                          \"ceiling\", \"cexp\", \"char\", \"chdir\", \"chmod\",\n                          \"clog\", \"cmplx\", \"command_argument_count\",\n                          \"complex\", \"conjg\", \"cos\", \"cosh\", \"count\",\n                          \"cpu_time\", \"cshift\", \"csin\", \"csqrt\", \"ctime\",\n                          \"c_funloc\", \"c_loc\", \"c_associated\", \"c_null_ptr\",\n                          \"c_null_funptr\", \"c_f_pointer\", \"c_null_char\",\n                          \"c_alert\", \"c_backspace\", \"c_form_feed\",\n                          \"c_new_line\", \"c_carriage_return\",\n                          \"c_horizontal_tab\", \"c_vertical_tab\", \"dabs\",\n                          \"dacos\", \"dasin\", \"datan\", \"date_and_time\",\n                          \"dbesj\", \"dbesj\", \"dbesjn\", \"dbesy\", \"dbesy\",\n                          \"dbesyn\", \"dble\", \"dcos\", \"dcosh\", \"ddim\", \"derf\",\n                          \"derfc\", \"dexp\", \"digits\", \"dim\", \"dint\", \"dlog\",\n                          \"dlog\", \"dmax\", \"dmin\", \"dmod\", \"dnint\",\n                          \"dot_product\", \"dprod\", \"dsign\", \"dsinh\",\n                          \"dsin\", \"dsqrt\", \"dtanh\", \"dtan\", \"dtime\",\n                          \"eoshift\", \"epsilon\", \"erf\", \"erfc\", \"etime\",\n                          \"exit\", \"exp\", \"exponent\", \"extends_type_of\",\n                          \"fdate\", \"fget\", \"fgetc\", \"float\", \"floor\",\n                          \"flush\", \"fnum\", \"fputc\", \"fput\", \"fraction\",\n                          \"fseek\", \"fstat\", \"ftell\", \"gerror\", \"getarg\",\n                          \"get_command\", \"get_command_argument\",\n                          \"get_environment_variable\", \"getcwd\",\n                          \"getenv\", \"getgid\", \"getlog\", \"getpid\",\n                          \"getuid\", \"gmtime\", \"hostnm\", \"huge\", \"iabs\",\n                          \"iachar\", \"iand\", \"iargc\", \"ibclr\", \"ibits\",\n                          \"ibset\", \"ichar\", \"idate\", \"idim\", \"idint\",\n                          \"idnint\", \"ieor\", \"ierrno\", \"ifix\", \"imag\",\n                          \"imagpart\", \"index\", \"int\", \"ior\", \"irand\",\n                          \"isatty\", \"ishft\", \"ishftc\", \"isign\",\n                          \"iso_c_binding\", \"is_iostat_end\", \"is_iostat_eor\",\n                          \"itime\", \"kill\", \"kind\", \"lbound\", \"len\", \"len_trim\",\n                          \"lge\", \"lgt\", \"link\", \"lle\", \"llt\", \"lnblnk\", \"loc\",\n                          \"log\", \"logical\", \"long\", \"lshift\", \"lstat\", \"ltime\",\n                          \"matmul\", \"max\", \"maxexponent\", \"maxloc\", \"maxval\",\n                          \"mclock\", \"merge\", \"move_alloc\", \"min\", \"minexponent\",\n                          \"minloc\", \"minval\", \"mod\", \"modulo\", \"mvbits\",\n                          \"nearest\", \"new_line\", \"nint\", \"not\", \"or\", \"pack\",\n                          \"perror\", \"precision\", \"present\", \"product\", \"radix\",\n                          \"rand\", \"random_number\", \"random_seed\", \"range\",\n                          \"real\", \"realpart\", \"rename\", \"repeat\", \"reshape\",\n                          \"rrspacing\", \"rshift\", \"same_type_as\", \"scale\",\n                          \"scan\", \"second\", \"selected_int_kind\",\n                          \"selected_real_kind\", \"set_exponent\", \"shape\",\n                          \"short\", \"sign\", \"signal\", \"sinh\", \"sin\", \"sleep\",\n                          \"sngl\", \"spacing\", \"spread\", \"sqrt\", \"srand\", \"stat\",\n                          \"sum\", \"symlnk\", \"system\", \"system_clock\", \"tan\",\n                          \"tanh\", \"time\", \"tiny\", \"transfer\", \"transpose\",\n                          \"trim\", \"ttynam\", \"ubound\", \"umask\", \"unlink\",\n                          \"unpack\", \"verify\", \"xor\", \"zabs\", \"zcos\", \"zexp\",\n                          \"zlog\", \"zsin\", \"zsqrt\"]);\n\n    var dataTypes =  words([\"c_bool\", \"c_char\", \"c_double\", \"c_double_complex\",\n                     \"c_float\", \"c_float_complex\", \"c_funptr\", \"c_int\",\n                     \"c_int16_t\", \"c_int32_t\", \"c_int64_t\", \"c_int8_t\",\n                     \"c_int_fast16_t\", \"c_int_fast32_t\", \"c_int_fast64_t\",\n                     \"c_int_fast8_t\", \"c_int_least16_t\", \"c_int_least32_t\",\n                     \"c_int_least64_t\", \"c_int_least8_t\", \"c_intmax_t\",\n                     \"c_intptr_t\", \"c_long\", \"c_long_double\",\n                     \"c_long_double_complex\", \"c_long_long\", \"c_ptr\",\n                     \"c_short\", \"c_signed_char\", \"c_size_t\", \"character\",\n                     \"complex\", \"double\", \"integer\", \"logical\", \"real\"]);\n  var isOperatorChar = /[+\\-*&=<>\\/\\:]/;\n  var litOperator = new RegExp(\"(\\.and\\.|\\.or\\.|\\.eq\\.|\\.lt\\.|\\.le\\.|\\.gt\\.|\\.ge\\.|\\.ne\\.|\\.not\\.|\\.eqv\\.|\\.neqv\\.)\", \"i\");\n\n  function tokenBase(stream, state) {\n\n    if (stream.match(litOperator)){\n        return 'operator';\n    }\n\n    var ch = stream.next();\n    if (ch == \"!\") {\n      stream.skipToEnd();\n      return \"comment\";\n    }\n    if (ch == '\"' || ch == \"'\") {\n      state.tokenize = tokenString(ch);\n      return state.tokenize(stream, state);\n    }\n    if (/[\\[\\]\\(\\),]/.test(ch)) {\n      return null;\n    }\n    if (/\\d/.test(ch)) {\n      stream.eatWhile(/[\\w\\.]/);\n      return \"number\";\n    }\n    if (isOperatorChar.test(ch)) {\n      stream.eatWhile(isOperatorChar);\n      return \"operator\";\n    }\n    stream.eatWhile(/[\\w\\$_]/);\n    var word = stream.current().toLowerCase();\n\n    if (keywords.hasOwnProperty(word)){\n            return 'keyword';\n    }\n    if (builtins.hasOwnProperty(word) || dataTypes.hasOwnProperty(word)) {\n            return 'builtin';\n    }\n    return \"variable\";\n  }\n\n  function tokenString(quote) {\n    return function(stream, state) {\n      var escaped = false, next, end = false;\n      while ((next = stream.next()) != null) {\n        if (next == quote && !escaped) {\n            end = true;\n            break;\n        }\n        escaped = !escaped && next == \"\\\\\";\n      }\n      if (end || !escaped) state.tokenize = null;\n      return \"string\";\n    };\n  }\n\n  // Interface\n\n  return {\n    startState: function() {\n      return {tokenize: null};\n    },\n\n    token: function(stream, state) {\n      if (stream.eatSpace()) return null;\n      var style = (state.tokenize || tokenBase)(stream, state);\n      if (style == \"comment\" || style == \"meta\") return style;\n      return style;\n    }\n  };\n});\n\nCodeMirror.defineMIME(\"text/x-fortran\", \"fortran\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/fortran/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Fortran mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"fortran.js\"></script>\n<style type=\"text/css\">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Fortran</a>\n  </ul>\n</div>\n\n<article>\n<h2>Fortran mode</h2>\n\n\n<div><textarea id=\"code\" name=\"code\">\n! Example Fortran code\n  program average\n\n  ! Read in some numbers and take the average\n  ! As written, if there are no data points, an average of zero is returned\n  ! While this may not be desired behavior, it keeps this example simple\n\n  implicit none\n\n  real, dimension(:), allocatable :: points\n  integer                         :: number_of_points\n  real                            :: average_points=0., positive_average=0., negative_average=0.\n\n  write (*,*) \"Input number of points to average:\"\n  read  (*,*) number_of_points\n\n  allocate (points(number_of_points))\n\n  write (*,*) \"Enter the points to average:\"\n  read  (*,*) points\n\n  ! Take the average by summing points and dividing by number_of_points\n  if (number_of_points > 0) average_points = sum(points) / number_of_points\n\n  ! Now form average over positive and negative points only\n  if (count(points > 0.) > 0) then\n     positive_average = sum(points, points > 0.) / count(points > 0.)\n  end if\n\n  if (count(points < 0.) > 0) then\n     negative_average = sum(points, points < 0.) / count(points < 0.)\n  end if\n\n  deallocate (points)\n\n  ! Print result to terminal\n  write (*,'(a,g12.4)') 'Average = ', average_points\n  write (*,'(a,g12.4)') 'Average of positive points = ', positive_average\n  write (*,'(a,g12.4)') 'Average of negative points = ', negative_average\n\n  end program average\n</textarea></div>\n\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        lineNumbers: true,\n        mode: \"text/x-fortran\"\n      });\n    </script>\n\n    <p><strong>MIME types defined:</strong> <code>text/x-Fortran</code>.</p>\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/gas/gas.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"gas\", function(_config, parserConfig) {\n  'use strict';\n\n  // If an architecture is specified, its initialization function may\n  // populate this array with custom parsing functions which will be\n  // tried in the event that the standard functions do not find a match.\n  var custom = [];\n\n  // The symbol used to start a line comment changes based on the target\n  // architecture.\n  // If no architecture is pased in \"parserConfig\" then only multiline\n  // comments will have syntax support.\n  var lineCommentStartSymbol = \"\";\n\n  // These directives are architecture independent.\n  // Machine specific directives should go in their respective\n  // architecture initialization function.\n  // Reference:\n  // http://sourceware.org/binutils/docs/as/Pseudo-Ops.html#Pseudo-Ops\n  var directives = {\n    \".abort\" : \"builtin\",\n    \".align\" : \"builtin\",\n    \".altmacro\" : \"builtin\",\n    \".ascii\" : \"builtin\",\n    \".asciz\" : \"builtin\",\n    \".balign\" : \"builtin\",\n    \".balignw\" : \"builtin\",\n    \".balignl\" : \"builtin\",\n    \".bundle_align_mode\" : \"builtin\",\n    \".bundle_lock\" : \"builtin\",\n    \".bundle_unlock\" : \"builtin\",\n    \".byte\" : \"builtin\",\n    \".cfi_startproc\" : \"builtin\",\n    \".comm\" : \"builtin\",\n    \".data\" : \"builtin\",\n    \".def\" : \"builtin\",\n    \".desc\" : \"builtin\",\n    \".dim\" : \"builtin\",\n    \".double\" : \"builtin\",\n    \".eject\" : \"builtin\",\n    \".else\" : \"builtin\",\n    \".elseif\" : \"builtin\",\n    \".end\" : \"builtin\",\n    \".endef\" : \"builtin\",\n    \".endfunc\" : \"builtin\",\n    \".endif\" : \"builtin\",\n    \".equ\" : \"builtin\",\n    \".equiv\" : \"builtin\",\n    \".eqv\" : \"builtin\",\n    \".err\" : \"builtin\",\n    \".error\" : \"builtin\",\n    \".exitm\" : \"builtin\",\n    \".extern\" : \"builtin\",\n    \".fail\" : \"builtin\",\n    \".file\" : \"builtin\",\n    \".fill\" : \"builtin\",\n    \".float\" : \"builtin\",\n    \".func\" : \"builtin\",\n    \".global\" : \"builtin\",\n    \".gnu_attribute\" : \"builtin\",\n    \".hidden\" : \"builtin\",\n    \".hword\" : \"builtin\",\n    \".ident\" : \"builtin\",\n    \".if\" : \"builtin\",\n    \".incbin\" : \"builtin\",\n    \".include\" : \"builtin\",\n    \".int\" : \"builtin\",\n    \".internal\" : \"builtin\",\n    \".irp\" : \"builtin\",\n    \".irpc\" : \"builtin\",\n    \".lcomm\" : \"builtin\",\n    \".lflags\" : \"builtin\",\n    \".line\" : \"builtin\",\n    \".linkonce\" : \"builtin\",\n    \".list\" : \"builtin\",\n    \".ln\" : \"builtin\",\n    \".loc\" : \"builtin\",\n    \".loc_mark_labels\" : \"builtin\",\n    \".local\" : \"builtin\",\n    \".long\" : \"builtin\",\n    \".macro\" : \"builtin\",\n    \".mri\" : \"builtin\",\n    \".noaltmacro\" : \"builtin\",\n    \".nolist\" : \"builtin\",\n    \".octa\" : \"builtin\",\n    \".offset\" : \"builtin\",\n    \".org\" : \"builtin\",\n    \".p2align\" : \"builtin\",\n    \".popsection\" : \"builtin\",\n    \".previous\" : \"builtin\",\n    \".print\" : \"builtin\",\n    \".protected\" : \"builtin\",\n    \".psize\" : \"builtin\",\n    \".purgem\" : \"builtin\",\n    \".pushsection\" : \"builtin\",\n    \".quad\" : \"builtin\",\n    \".reloc\" : \"builtin\",\n    \".rept\" : \"builtin\",\n    \".sbttl\" : \"builtin\",\n    \".scl\" : \"builtin\",\n    \".section\" : \"builtin\",\n    \".set\" : \"builtin\",\n    \".short\" : \"builtin\",\n    \".single\" : \"builtin\",\n    \".size\" : \"builtin\",\n    \".skip\" : \"builtin\",\n    \".sleb128\" : \"builtin\",\n    \".space\" : \"builtin\",\n    \".stab\" : \"builtin\",\n    \".string\" : \"builtin\",\n    \".struct\" : \"builtin\",\n    \".subsection\" : \"builtin\",\n    \".symver\" : \"builtin\",\n    \".tag\" : \"builtin\",\n    \".text\" : \"builtin\",\n    \".title\" : \"builtin\",\n    \".type\" : \"builtin\",\n    \".uleb128\" : \"builtin\",\n    \".val\" : \"builtin\",\n    \".version\" : \"builtin\",\n    \".vtable_entry\" : \"builtin\",\n    \".vtable_inherit\" : \"builtin\",\n    \".warning\" : \"builtin\",\n    \".weak\" : \"builtin\",\n    \".weakref\" : \"builtin\",\n    \".word\" : \"builtin\"\n  };\n\n  var registers = {};\n\n  function x86(_parserConfig) {\n    lineCommentStartSymbol = \"#\";\n\n    registers.ax  = \"variable\";\n    registers.eax = \"variable-2\";\n    registers.rax = \"variable-3\";\n\n    registers.bx  = \"variable\";\n    registers.ebx = \"variable-2\";\n    registers.rbx = \"variable-3\";\n\n    registers.cx  = \"variable\";\n    registers.ecx = \"variable-2\";\n    registers.rcx = \"variable-3\";\n\n    registers.dx  = \"variable\";\n    registers.edx = \"variable-2\";\n    registers.rdx = \"variable-3\";\n\n    registers.si  = \"variable\";\n    registers.esi = \"variable-2\";\n    registers.rsi = \"variable-3\";\n\n    registers.di  = \"variable\";\n    registers.edi = \"variable-2\";\n    registers.rdi = \"variable-3\";\n\n    registers.sp  = \"variable\";\n    registers.esp = \"variable-2\";\n    registers.rsp = \"variable-3\";\n\n    registers.bp  = \"variable\";\n    registers.ebp = \"variable-2\";\n    registers.rbp = \"variable-3\";\n\n    registers.ip  = \"variable\";\n    registers.eip = \"variable-2\";\n    registers.rip = \"variable-3\";\n\n    registers.cs  = \"keyword\";\n    registers.ds  = \"keyword\";\n    registers.ss  = \"keyword\";\n    registers.es  = \"keyword\";\n    registers.fs  = \"keyword\";\n    registers.gs  = \"keyword\";\n  }\n\n  function armv6(_parserConfig) {\n    // Reference:\n    // http://infocenter.arm.com/help/topic/com.arm.doc.qrc0001l/QRC0001_UAL.pdf\n    // http://infocenter.arm.com/help/topic/com.arm.doc.ddi0301h/DDI0301H_arm1176jzfs_r0p7_trm.pdf\n    lineCommentStartSymbol = \"@\";\n    directives.syntax = \"builtin\";\n\n    registers.r0  = \"variable\";\n    registers.r1  = \"variable\";\n    registers.r2  = \"variable\";\n    registers.r3  = \"variable\";\n    registers.r4  = \"variable\";\n    registers.r5  = \"variable\";\n    registers.r6  = \"variable\";\n    registers.r7  = \"variable\";\n    registers.r8  = \"variable\";\n    registers.r9  = \"variable\";\n    registers.r10 = \"variable\";\n    registers.r11 = \"variable\";\n    registers.r12 = \"variable\";\n\n    registers.sp  = \"variable-2\";\n    registers.lr  = \"variable-2\";\n    registers.pc  = \"variable-2\";\n    registers.r13 = registers.sp;\n    registers.r14 = registers.lr;\n    registers.r15 = registers.pc;\n\n    custom.push(function(ch, stream) {\n      if (ch === '#') {\n        stream.eatWhile(/\\w/);\n        return \"number\";\n      }\n    });\n  }\n\n  var arch = (parserConfig.architecture || \"x86\").toLowerCase();\n  if (arch === \"x86\") {\n    x86(parserConfig);\n  } else if (arch === \"arm\" || arch === \"armv6\") {\n    armv6(parserConfig);\n  }\n\n  function nextUntilUnescaped(stream, end) {\n    var escaped = false, next;\n    while ((next = stream.next()) != null) {\n      if (next === end && !escaped) {\n        return false;\n      }\n      escaped = !escaped && next === \"\\\\\";\n    }\n    return escaped;\n  }\n\n  function clikeComment(stream, state) {\n    var maybeEnd = false, ch;\n    while ((ch = stream.next()) != null) {\n      if (ch === \"/\" && maybeEnd) {\n        state.tokenize = null;\n        break;\n      }\n      maybeEnd = (ch === \"*\");\n    }\n    return \"comment\";\n  }\n\n  return {\n    startState: function() {\n      return {\n        tokenize: null\n      };\n    },\n\n    token: function(stream, state) {\n      if (state.tokenize) {\n        return state.tokenize(stream, state);\n      }\n\n      if (stream.eatSpace()) {\n        return null;\n      }\n\n      var style, cur, ch = stream.next();\n\n      if (ch === \"/\") {\n        if (stream.eat(\"*\")) {\n          state.tokenize = clikeComment;\n          return clikeComment(stream, state);\n        }\n      }\n\n      if (ch === lineCommentStartSymbol) {\n        stream.skipToEnd();\n        return \"comment\";\n      }\n\n      if (ch === '\"') {\n        nextUntilUnescaped(stream, '\"');\n        return \"string\";\n      }\n\n      if (ch === '.') {\n        stream.eatWhile(/\\w/);\n        cur = stream.current().toLowerCase();\n        style = directives[cur];\n        return style || null;\n      }\n\n      if (ch === '=') {\n        stream.eatWhile(/\\w/);\n        return \"tag\";\n      }\n\n      if (ch === '{') {\n        return \"braket\";\n      }\n\n      if (ch === '}') {\n        return \"braket\";\n      }\n\n      if (/\\d/.test(ch)) {\n        if (ch === \"0\" && stream.eat(\"x\")) {\n          stream.eatWhile(/[0-9a-fA-F]/);\n          return \"number\";\n        }\n        stream.eatWhile(/\\d/);\n        return \"number\";\n      }\n\n      if (/\\w/.test(ch)) {\n        stream.eatWhile(/\\w/);\n        if (stream.eat(\":\")) {\n          return 'tag';\n        }\n        cur = stream.current().toLowerCase();\n        style = registers[cur];\n        return style || null;\n      }\n\n      for (var i = 0; i < custom.length; i++) {\n        style = custom[i](ch, stream, state);\n        if (style) {\n          return style;\n        }\n      }\n    },\n\n    lineComment: lineCommentStartSymbol,\n    blockCommentStart: \"/*\",\n    blockCommentEnd: \"*/\"\n  };\n});\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/gas/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Gas mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"gas.js\"></script>\n<style>.CodeMirror {border: 2px inset #dee;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Gas</a>\n  </ul>\n</div>\n\n<article>\n<h2>Gas mode</h2>\n<form>\n<textarea id=\"code\" name=\"code\">\n.syntax unified\n.global main\n\n/* \n *  A\n *  multi-line\n *  comment.\n */\n\n@ A single line comment.\n\nmain:\n        push    {sp, lr}\n        ldr     r0, =message\n        bl      puts\n        mov     r0, #0\n        pop     {sp, pc}\n\nmessage:\n        .asciz \"Hello world!<br />\"\n</textarea>\n        </form>\n\n        <script>\n            var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n                lineNumbers: true,\n                mode: {name: \"gas\", architecture: \"ARMv6\"},\n            });\n        </script>\n\n        <p>Handles AT&amp;T assembler syntax (more specifically this handles\n        the GNU Assembler (gas) syntax.)\n        It takes a single optional configuration parameter:\n        <code>architecture</code>, which can be one of <code>\"ARM\"</code>,\n        <code>\"ARMv6\"</code> or <code>\"x86\"</code>.\n        Including the parameter adds syntax for the registers and special\n        directives for the supplied architecture.\n\n        <p><strong>MIME types defined:</strong> <code>text/x-gas</code></p>\n    </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/gfm/gfm.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"), require(\"../markdown/markdown\"), require(\"../../addon/mode/overlay\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\", \"../markdown/markdown\", \"../../addon/mode/overlay\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"gfm\", function(config, modeConfig) {\n  var codeDepth = 0;\n  function blankLine(state) {\n    state.code = false;\n    return null;\n  }\n  var gfmOverlay = {\n    startState: function() {\n      return {\n        code: false,\n        codeBlock: false,\n        ateSpace: false\n      };\n    },\n    copyState: function(s) {\n      return {\n        code: s.code,\n        codeBlock: s.codeBlock,\n        ateSpace: s.ateSpace\n      };\n    },\n    token: function(stream, state) {\n      state.combineTokens = null;\n\n      // Hack to prevent formatting override inside code blocks (block and inline)\n      if (state.codeBlock) {\n        if (stream.match(/^```/)) {\n          state.codeBlock = false;\n          return null;\n        }\n        stream.skipToEnd();\n        return null;\n      }\n      if (stream.sol()) {\n        state.code = false;\n      }\n      if (stream.sol() && stream.match(/^```/)) {\n        stream.skipToEnd();\n        state.codeBlock = true;\n        return null;\n      }\n      // If this block is changed, it may need to be updated in Markdown mode\n      if (stream.peek() === '`') {\n        stream.next();\n        var before = stream.pos;\n        stream.eatWhile('`');\n        var difference = 1 + stream.pos - before;\n        if (!state.code) {\n          codeDepth = difference;\n          state.code = true;\n        } else {\n          if (difference === codeDepth) { // Must be exact\n            state.code = false;\n          }\n        }\n        return null;\n      } else if (state.code) {\n        stream.next();\n        return null;\n      }\n      // Check if space. If so, links can be formatted later on\n      if (stream.eatSpace()) {\n        state.ateSpace = true;\n        return null;\n      }\n      if (stream.sol() || state.ateSpace) {\n        state.ateSpace = false;\n        if(stream.match(/^(?:[a-zA-Z0-9\\-_]+\\/)?(?:[a-zA-Z0-9\\-_]+@)?(?:[a-f0-9]{7,40}\\b)/)) {\n          // User/Project@SHA\n          // User@SHA\n          // SHA\n          state.combineTokens = true;\n          return \"link\";\n        } else if (stream.match(/^(?:[a-zA-Z0-9\\-_]+\\/)?(?:[a-zA-Z0-9\\-_]+)?#[0-9]+\\b/)) {\n          // User/Project#Num\n          // User#Num\n          // #Num\n          state.combineTokens = true;\n          return \"link\";\n        }\n      }\n      if (stream.match(/^((?:[a-z][\\w-]+:(?:\\/{1,3}|[a-z0-9%])|www\\d{0,3}[.]|[a-z0-9.\\-]+[.][a-z]{2,4}\\/)(?:[^\\s()<>]|\\([^\\s()<>]*\\))+(?:\\([^\\s()<>]*\\)|[^\\s`*!()\\[\\]{};:'\".,<>?«»“”‘’]))/i) &&\n         stream.string.slice(stream.start - 2, stream.start) != \"](\") {\n        // URLs\n        // Taken from http://daringfireball.net/2010/07/improved_regex_for_matching_urls\n        // And then (issue #1160) simplified to make it not crash the Chrome Regexp engine\n        state.combineTokens = true;\n        return \"link\";\n      }\n      stream.next();\n      return null;\n    },\n    blankLine: blankLine\n  };\n\n  var markdownConfig = {\n    underscoresBreakWords: false,\n    taskLists: true,\n    fencedCodeBlocks: true,\n    strikethrough: true\n  };\n  for (var attr in modeConfig) {\n    markdownConfig[attr] = modeConfig[attr];\n  }\n  markdownConfig.name = \"markdown\";\n  CodeMirror.defineMIME(\"gfmBase\", markdownConfig);\n  return CodeMirror.overlayMode(CodeMirror.getMode(config, \"gfmBase\"), gfmOverlay);\n}, \"markdown\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/gfm/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: GFM mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"../../addon/mode/overlay.js\"></script>\n<script src=\"../xml/xml.js\"></script>\n<script src=\"../markdown/markdown.js\"></script>\n<script src=\"gfm.js\"></script>\n<script src=\"../javascript/javascript.js\"></script>\n<script src=\"../css/css.js\"></script>\n<script src=\"../htmlmixed/htmlmixed.js\"></script>\n<script src=\"../clike/clike.js\"></script>\n<script src=\"../meta.js\"></script>\n<style type=\"text/css\">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">GFM</a>\n  </ul>\n</div>\n\n<article>\n<h2>GFM mode</h2>\n<form><textarea id=\"code\" name=\"code\">\nGitHub Flavored Markdown\n========================\n\nEverything from markdown plus GFM features:\n\n## URL autolinking\n\nUnderscores_are_allowed_between_words.\n\n## Strikethrough text\n\nGFM adds syntax to strikethrough text, which is missing from standard Markdown.\n\n~~Mistaken text.~~\n~~**works with other fomatting**~~\n\n~~spans across\nlines~~\n\n## Fenced code blocks (and syntax highlighting)\n\n```javascript\nfor (var i = 0; i &lt; items.length; i++) {\n    console.log(items[i], i); // log them\n}\n```\n\n## Task Lists\n\n- [ ] Incomplete task list item\n- [x] **Completed** task list item\n\n## A bit of GitHub spice\n\n* SHA: be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd2\n* User@SHA ref: mojombo@be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd2\n* User/Project@SHA: mojombo/god@be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd2\n* \\#Num: #1\n* User/#Num: mojombo#1\n* User/Project#Num: mojombo/god#1\n\nSee http://github.github.com/github-flavored-markdown/.\n\n</textarea></form>\n\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        mode: 'gfm',\n        lineNumbers: true,\n        theme: \"default\"\n      });\n    </script>\n\n    <p>Optionally depends on other modes for properly highlighted code blocks.</p>\n\n    <p><strong>Parsing/Highlighting Tests:</strong> <a href=\"../../test/index.html#gfm_*\">normal</a>,  <a href=\"../../test/index.html#verbose,gfm_*\">verbose</a>.</p>\n\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/gfm/test.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function() {\n  var mode = CodeMirror.getMode({tabSize: 4}, \"gfm\");\n  function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); }\n  var modeHighlightFormatting = CodeMirror.getMode({tabSize: 4}, {name: \"gfm\", highlightFormatting: true});\n  function FT(name) { test.mode(name, modeHighlightFormatting, Array.prototype.slice.call(arguments, 1)); }\n\n  FT(\"codeBackticks\",\n     \"[comment&formatting&formatting-code `][comment foo][comment&formatting&formatting-code `]\");\n\n  FT(\"doubleBackticks\",\n     \"[comment&formatting&formatting-code ``][comment foo ` bar][comment&formatting&formatting-code ``]\");\n\n  FT(\"codeBlock\",\n     \"[comment&formatting&formatting-code-block ```css]\",\n     \"[tag foo]\",\n     \"[comment&formatting&formatting-code-block ```]\");\n\n  FT(\"taskList\",\n     \"[variable-2&formatting&formatting-list&formatting-list-ul - ][meta&formatting&formatting-task [ ]]][variable-2  foo]\",\n     \"[variable-2&formatting&formatting-list&formatting-list-ul - ][property&formatting&formatting-task [x]]][variable-2  foo]\");\n\n  FT(\"formatting_strikethrough\",\n     \"[strikethrough&formatting&formatting-strikethrough ~~][strikethrough foo][strikethrough&formatting&formatting-strikethrough ~~]\");\n\n  FT(\"formatting_strikethrough\",\n     \"foo [strikethrough&formatting&formatting-strikethrough ~~][strikethrough bar][strikethrough&formatting&formatting-strikethrough ~~]\");\n\n  MT(\"emInWordAsterisk\",\n     \"foo[em *bar*]hello\");\n\n  MT(\"emInWordUnderscore\",\n     \"foo_bar_hello\");\n\n  MT(\"emStrongUnderscore\",\n     \"[strong __][em&strong _foo__][em _] bar\");\n\n  MT(\"fencedCodeBlocks\",\n     \"[comment ```]\",\n     \"[comment foo]\",\n     \"\",\n     \"[comment ```]\",\n     \"bar\");\n\n  MT(\"fencedCodeBlockModeSwitching\",\n     \"[comment ```javascript]\",\n     \"[variable foo]\",\n     \"\",\n     \"[comment ```]\",\n     \"bar\");\n\n  MT(\"taskListAsterisk\",\n     \"[variable-2 * []] foo]\", // Invalid; must have space or x between []\n     \"[variable-2 * [ ]]bar]\", // Invalid; must have space after ]\n     \"[variable-2 * [x]]hello]\", // Invalid; must have space after ]\n     \"[variable-2 * ][meta [ ]]][variable-2  [world]]]\", // Valid; tests reference style links\n     \"    [variable-3 * ][property [x]]][variable-3  foo]\"); // Valid; can be nested\n\n  MT(\"taskListPlus\",\n     \"[variable-2 + []] foo]\", // Invalid; must have space or x between []\n     \"[variable-2 + [ ]]bar]\", // Invalid; must have space after ]\n     \"[variable-2 + [x]]hello]\", // Invalid; must have space after ]\n     \"[variable-2 + ][meta [ ]]][variable-2  [world]]]\", // Valid; tests reference style links\n     \"    [variable-3 + ][property [x]]][variable-3  foo]\"); // Valid; can be nested\n\n  MT(\"taskListDash\",\n     \"[variable-2 - []] foo]\", // Invalid; must have space or x between []\n     \"[variable-2 - [ ]]bar]\", // Invalid; must have space after ]\n     \"[variable-2 - [x]]hello]\", // Invalid; must have space after ]\n     \"[variable-2 - ][meta [ ]]][variable-2  [world]]]\", // Valid; tests reference style links\n     \"    [variable-3 - ][property [x]]][variable-3  foo]\"); // Valid; can be nested\n\n  MT(\"taskListNumber\",\n     \"[variable-2 1. []] foo]\", // Invalid; must have space or x between []\n     \"[variable-2 2. [ ]]bar]\", // Invalid; must have space after ]\n     \"[variable-2 3. [x]]hello]\", // Invalid; must have space after ]\n     \"[variable-2 4. ][meta [ ]]][variable-2  [world]]]\", // Valid; tests reference style links\n     \"    [variable-3 1. ][property [x]]][variable-3  foo]\"); // Valid; can be nested\n\n  MT(\"SHA\",\n     \"foo [link be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd2] bar\");\n\n  MT(\"SHAEmphasis\",\n     \"[em *foo ][em&link be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd2][em *]\");\n\n  MT(\"shortSHA\",\n     \"foo [link be6a8cc] bar\");\n\n  MT(\"tooShortSHA\",\n     \"foo be6a8c bar\");\n\n  MT(\"longSHA\",\n     \"foo be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd22 bar\");\n\n  MT(\"badSHA\",\n     \"foo be6a8cc1c1ecfe9489fb51e4869af15a13fc2cg2 bar\");\n\n  MT(\"userSHA\",\n     \"foo [link bar@be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd2] hello\");\n\n  MT(\"userSHAEmphasis\",\n     \"[em *foo ][em&link bar@be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd2][em *]\");\n\n  MT(\"userProjectSHA\",\n     \"foo [link bar/hello@be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd2] world\");\n\n  MT(\"userProjectSHAEmphasis\",\n     \"[em *foo ][em&link bar/hello@be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd2][em *]\");\n\n  MT(\"num\",\n     \"foo [link #1] bar\");\n\n  MT(\"numEmphasis\",\n     \"[em *foo ][em&link #1][em *]\");\n\n  MT(\"badNum\",\n     \"foo #1bar hello\");\n\n  MT(\"userNum\",\n     \"foo [link bar#1] hello\");\n\n  MT(\"userNumEmphasis\",\n     \"[em *foo ][em&link bar#1][em *]\");\n\n  MT(\"userProjectNum\",\n     \"foo [link bar/hello#1] world\");\n\n  MT(\"userProjectNumEmphasis\",\n     \"[em *foo ][em&link bar/hello#1][em *]\");\n\n  MT(\"vanillaLink\",\n     \"foo [link http://www.example.com/] bar\");\n\n  MT(\"vanillaLinkPunctuation\",\n     \"foo [link http://www.example.com/]. bar\");\n\n  MT(\"vanillaLinkExtension\",\n     \"foo [link http://www.example.com/index.html] bar\");\n\n  MT(\"vanillaLinkEmphasis\",\n     \"foo [em *][em&link http://www.example.com/index.html][em *] bar\");\n\n  MT(\"notALink\",\n     \"[comment ```css]\",\n     \"[tag foo] {[property color]:[keyword black];}\",\n     \"[comment ```][link http://www.example.com/]\");\n\n  MT(\"notALink\",\n     \"[comment ``foo `bar` http://www.example.com/``] hello\");\n\n  MT(\"notALink\",\n     \"[comment `foo]\",\n     \"[link http://www.example.com/]\",\n     \"[comment `foo]\",\n     \"\",\n     \"[link http://www.example.com/]\");\n\n  MT(\"headerCodeBlockGithub\",\n     \"[header&header-1 # heading]\",\n     \"\",\n     \"[comment ```]\",\n     \"[comment code]\",\n     \"[comment ```]\",\n     \"\",\n     \"Commit: [link be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd2]\",\n     \"Issue: [link #1]\",\n     \"Link: [link http://www.example.com/]\");\n\n  MT(\"strikethrough\",\n     \"[strikethrough ~~foo~~]\");\n\n  MT(\"strikethroughWithStartingSpace\",\n     \"~~ foo~~\");\n\n  MT(\"strikethroughUnclosedStrayTildes\",\n    \"[strikethrough ~~foo~~~]\");\n\n  MT(\"strikethroughUnclosedStrayTildes\",\n     \"[strikethrough ~~foo ~~]\");\n\n  MT(\"strikethroughUnclosedStrayTildes\",\n    \"[strikethrough ~~foo ~~ bar]\");\n\n  MT(\"strikethroughUnclosedStrayTildes\",\n    \"[strikethrough ~~foo ~~ bar~~]hello\");\n\n  MT(\"strikethroughOneLetter\",\n     \"[strikethrough ~~a~~]\");\n\n  MT(\"strikethroughWrapped\",\n     \"[strikethrough ~~foo]\",\n     \"[strikethrough foo~~]\");\n\n  MT(\"strikethroughParagraph\",\n     \"[strikethrough ~~foo]\",\n     \"\",\n     \"foo[strikethrough ~~bar]\");\n\n  MT(\"strikethroughEm\",\n     \"[strikethrough ~~foo][em&strikethrough *bar*][strikethrough ~~]\");\n\n  MT(\"strikethroughEm\",\n     \"[em *][em&strikethrough ~~foo~~][em *]\");\n\n  MT(\"strikethroughStrong\",\n     \"[strikethrough ~~][strong&strikethrough **foo**][strikethrough ~~]\");\n\n  MT(\"strikethroughStrong\",\n     \"[strong **][strong&strikethrough ~~foo~~][strong **]\");\n\n})();\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/gherkin/gherkin.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n/*\nGherkin mode - http://www.cukes.info/\nReport bugs/issues here: https://github.com/codemirror/CodeMirror/issues\n*/\n\n// Following Objs from Brackets implementation: https://github.com/tregusti/brackets-gherkin/blob/master/main.js\n//var Quotes = {\n//  SINGLE: 1,\n//  DOUBLE: 2\n//};\n\n//var regex = {\n//  keywords: /(Feature| {2}(Scenario|In order to|As|I)| {4}(Given|When|Then|And))/\n//};\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"gherkin\", function () {\n  return {\n    startState: function () {\n      return {\n        lineNumber: 0,\n        tableHeaderLine: false,\n        allowFeature: true,\n        allowBackground: false,\n        allowScenario: false,\n        allowSteps: false,\n        allowPlaceholders: false,\n        allowMultilineArgument: false,\n        inMultilineString: false,\n        inMultilineTable: false,\n        inKeywordLine: false\n      };\n    },\n    token: function (stream, state) {\n      if (stream.sol()) {\n        state.lineNumber++;\n        state.inKeywordLine = false;\n        if (state.inMultilineTable) {\n            state.tableHeaderLine = false;\n            if (!stream.match(/\\s*\\|/, false)) {\n              state.allowMultilineArgument = false;\n              state.inMultilineTable = false;\n            }\n        }\n      }\n\n      stream.eatSpace();\n\n      if (state.allowMultilineArgument) {\n\n        // STRING\n        if (state.inMultilineString) {\n          if (stream.match('\"\"\"')) {\n            state.inMultilineString = false;\n            state.allowMultilineArgument = false;\n          } else {\n            stream.match(/.*/);\n          }\n          return \"string\";\n        }\n\n        // TABLE\n        if (state.inMultilineTable) {\n          if (stream.match(/\\|\\s*/)) {\n            return \"bracket\";\n          } else {\n            stream.match(/[^\\|]*/);\n            return state.tableHeaderLine ? \"header\" : \"string\";\n          }\n        }\n\n        // DETECT START\n        if (stream.match('\"\"\"')) {\n          // String\n          state.inMultilineString = true;\n          return \"string\";\n        } else if (stream.match(\"|\")) {\n          // Table\n          state.inMultilineTable = true;\n          state.tableHeaderLine = true;\n          return \"bracket\";\n        }\n\n      }\n\n      // LINE COMMENT\n      if (stream.match(/#.*/)) {\n        return \"comment\";\n\n      // TAG\n      } else if (!state.inKeywordLine && stream.match(/@\\S+/)) {\n        return \"tag\";\n\n      // FEATURE\n      } else if (!state.inKeywordLine && state.allowFeature && stream.match(/(機能|功能|フィーチャ|기능|โครงหลัก|ความสามารถ|ความต้องการทางธุรกิจ|ಹೆಚ್ಚಳ|గుణము|ਮੁਹਾਂਦਰਾ|ਨਕਸ਼ ਨੁਹਾਰ|ਖਾਸੀਅਤ|रूप लेख|وِیژگی|خاصية|תכונה|Функціонал|Функция|Функционалност|Функционал|Үзенчәлеклелек|Свойство|Особина|Мөмкинлек|Могућност|Λειτουργία|Δυνατότητα|Właściwość|Vlastnosť|Trajto|Tính năng|Savybė|Pretty much|Požiadavka|Požadavek|Potrzeba biznesowa|Özellik|Osobina|Ominaisuus|Omadus|OH HAI|Mogućnost|Mogucnost|Jellemző|Hwæt|Hwaet|Funzionalità|Funktionalitéit|Funktionalität|Funkcja|Funkcionalnost|Funkcionalitāte|Funkcia|Fungsi|Functionaliteit|Funcționalitate|Funcţionalitate|Functionalitate|Funcionalitat|Funcionalidade|Fonctionnalité|Fitur|Fīča|Feature|Eiginleiki|Egenskap|Egenskab|Característica|Caracteristica|Business Need|Aspekt|Arwedd|Ahoy matey!|Ability):/)) {\n        state.allowScenario = true;\n        state.allowBackground = true;\n        state.allowPlaceholders = false;\n        state.allowSteps = false;\n        state.allowMultilineArgument = false;\n        state.inKeywordLine = true;\n        return \"keyword\";\n\n      // BACKGROUND\n      } else if (!state.inKeywordLine && state.allowBackground && stream.match(/(背景|배경|แนวคิด|ಹಿನ್ನೆಲೆ|నేపథ్యం|ਪਿਛੋਕੜ|पृष्ठभूमि|زمینه|الخلفية|רקע|Тарих|Предыстория|Предистория|Позадина|Передумова|Основа|Контекст|Кереш|Υπόβαθρο|Założenia|Yo\\-ho\\-ho|Tausta|Taust|Situācija|Rerefons|Pozadina|Pozadie|Pozadí|Osnova|Latar Belakang|Kontext|Konteksts|Kontekstas|Kontekst|Háttér|Hannergrond|Grundlage|Geçmiş|Fundo|Fono|First off|Dis is what went down|Dasar|Contexto|Contexte|Context|Contesto|Cenário de Fundo|Cenario de Fundo|Cefndir|Bối cảnh|Bakgrunnur|Bakgrunn|Bakgrund|Baggrund|Background|B4|Antecedents|Antecedentes|Ær|Aer|Achtergrond):/)) {\n        state.allowPlaceholders = false;\n        state.allowSteps = true;\n        state.allowBackground = false;\n        state.allowMultilineArgument = false;\n        state.inKeywordLine = true;\n        return \"keyword\";\n\n      // SCENARIO OUTLINE\n      } else if (!state.inKeywordLine && state.allowScenario && stream.match(/(場景大綱|场景大纲|劇本大綱|剧本大纲|テンプレ|シナリオテンプレート|シナリオテンプレ|シナリオアウトライン|시나리오 개요|สรุปเหตุการณ์|โครงสร้างของเหตุการณ์|ವಿವರಣೆ|కథనం|ਪਟਕਥਾ ਰੂਪ ਰੇਖਾ|ਪਟਕਥਾ ਢਾਂਚਾ|परिदृश्य रूपरेखा|سيناريو مخطط|الگوی سناریو|תבנית תרחיש|Сценарийның төзелеше|Сценарий структураси|Структура сценарію|Структура сценария|Структура сценарија|Скица|Рамка на сценарий|Концепт|Περιγραφή Σεναρίου|Wharrimean is|Template Situai|Template Senario|Template Keadaan|Tapausaihio|Szenariogrundriss|Szablon scenariusza|Swa hwær swa|Swa hwaer swa|Struktura scenarija|Structură scenariu|Structura scenariu|Skica|Skenario konsep|Shiver me timbers|Senaryo taslağı|Schema dello scenario|Scenariomall|Scenariomal|Scenario Template|Scenario Outline|Scenario Amlinellol|Scenārijs pēc parauga|Scenarijaus šablonas|Reckon it's like|Raamstsenaarium|Plang vum Szenario|Plan du Scénario|Plan du scénario|Osnova scénáře|Osnova Scenára|Náčrt Scenáru|Náčrt Scénáře|Náčrt Scenára|MISHUN SRSLY|Menggariskan Senario|Lýsing Dæma|Lýsing Atburðarásar|Konturo de la scenaro|Koncept|Khung tình huống|Khung kịch bản|Forgatókönyv vázlat|Esquema do Cenário|Esquema do Cenario|Esquema del escenario|Esquema de l'escenari|Esbozo do escenario|Delineação do Cenário|Delineacao do Cenario|All y'all|Abstrakt Scenario|Abstract Scenario):/)) {\n        state.allowPlaceholders = true;\n        state.allowSteps = true;\n        state.allowMultilineArgument = false;\n        state.inKeywordLine = true;\n        return \"keyword\";\n\n      // EXAMPLES\n      } else if (state.allowScenario && stream.match(/(例子|例|サンプル|예|ชุดของเหตุการณ์|ชุดของตัวอย่าง|ಉದಾಹರಣೆಗಳು|ఉదాహరణలు|ਉਦਾਹਰਨਾਂ|उदाहरण|نمونه ها|امثلة|דוגמאות|Үрнәкләр|Сценарији|Примеры|Примери|Приклади|Мисоллар|Мисаллар|Σενάρια|Παραδείγματα|You'll wanna|Voorbeelden|Variantai|Tapaukset|Se þe|Se the|Se ðe|Scenarios|Scenariji|Scenarijai|Przykłady|Primjeri|Primeri|Příklady|Príklady|Piemēri|Példák|Pavyzdžiai|Paraugs|Örnekler|Juhtumid|Exemplos|Exemples|Exemple|Exempel|EXAMPLZ|Examples|Esempi|Enghreifftiau|Ekzemploj|Eksempler|Ejemplos|Dữ liệu|Dead men tell no tales|Dæmi|Contoh|Cenários|Cenarios|Beispiller|Beispiele|Atburðarásir):/)) {\n        state.allowPlaceholders = false;\n        state.allowSteps = true;\n        state.allowBackground = false;\n        state.allowMultilineArgument = true;\n        return \"keyword\";\n\n      // SCENARIO\n      } else if (!state.inKeywordLine && state.allowScenario && stream.match(/(場景|场景|劇本|剧本|シナリオ|시나리오|เหตุการณ์|ಕಥಾಸಾರಾಂಶ|సన్నివేశం|ਪਟਕਥਾ|परिदृश्य|سيناريو|سناریو|תרחיש|Сценарій|Сценарио|Сценарий|Пример|Σενάριο|Tình huống|The thing of it is|Tapaus|Szenario|Swa|Stsenaarium|Skenario|Situai|Senaryo|Senario|Scenaro|Scenariusz|Scenariu|Scénario|Scenario|Scenarijus|Scenārijs|Scenarij|Scenarie|Scénář|Scenár|Primer|MISHUN|Kịch bản|Keadaan|Heave to|Forgatókönyv|Escenario|Escenari|Cenário|Cenario|Awww, look mate|Atburðarás):/)) {\n        state.allowPlaceholders = false;\n        state.allowSteps = true;\n        state.allowBackground = false;\n        state.allowMultilineArgument = false;\n        state.inKeywordLine = true;\n        return \"keyword\";\n\n      // STEPS\n      } else if (!state.inKeywordLine && state.allowSteps && stream.match(/(那麼|那么|而且|當|当|并且|同時|同时|前提|假设|假設|假定|假如|但是|但し|並且|もし|ならば|ただし|しかし|かつ|하지만|조건|먼저|만일|만약|단|그리고|그러면|และ |เมื่อ |แต่ |ดังนั้น |กำหนดให้ |ಸ್ಥಿತಿಯನ್ನು |ಮತ್ತು |ನೀಡಿದ |ನಂತರ |ಆದರೆ |మరియు |చెప్పబడినది |కాని |ఈ పరిస్థితిలో |అప్పుడు |ਪਰ |ਤਦ |ਜੇਕਰ |ਜਿਵੇਂ ਕਿ |ਜਦੋਂ |ਅਤੇ |यदि |परन्तु |पर |तब |तदा |तथा |जब |चूंकि |किन्तु |कदा |और |अगर |و |هنگامی |متى |لكن |عندما |ثم |بفرض |با فرض |اما |اذاً |آنگاه |כאשר |וגם |בהינתן |אזי |אז |אבל |Якщо |Һәм |Унда |Тоді |Тогда |То |Также |Та |Пусть |Припустимо, що |Припустимо |Онда |Но |Нехай |Нәтиҗәдә |Лекин |Ләкин |Коли |Когда |Когато |Када |Кад |К тому же |І |И |Задато |Задати |Задате |Если |Допустим |Дано |Дадено |Вә |Ва |Бирок |Әмма |Әйтик |Әгәр |Аммо |Али |Але |Агар |А також |А |Τότε |Όταν |Και |Δεδομένου |Αλλά |Þurh |Þegar |Þa þe |Þá |Þa |Zatati |Zakładając |Zadato |Zadate |Zadano |Zadani |Zadan |Za předpokladu |Za predpokladu |Youse know when youse got |Youse know like when |Yna |Yeah nah |Y'know |Y |Wun |Wtedy |When y'all |When |Wenn |WEN |wann |Ve |Và |Und |Un |ugeholl |Too right |Thurh |Thì |Then y'all |Then |Tha the |Tha |Tetapi |Tapi |Tak |Tada |Tad |Stel |Soit |Siis |Și |Şi |Si |Sed |Se |Så |Quando |Quand |Quan |Pryd |Potom |Pokud |Pokiaľ |Però |Pero |Pak |Oraz |Onda |Ond |Oletetaan |Og |Och |O zaman |Niin |Nhưng |När |Når |Mutta |Men |Mas |Maka |Majd |Mając |Mais |Maar |mä |Ma |Lorsque |Lorsqu'|Logo |Let go and haul |Kun |Kuid |Kui |Kiedy |Khi |Ketika |Kemudian |Keď |Když |Kaj |Kai |Kada |Kad |Jeżeli |Jeśli |Ja |It's just unbelievable |Ir |I CAN HAZ |I |Ha |Givun |Givet |Given y'all |Given |Gitt |Gegeven |Gegeben seien |Gegeben sei |Gdy |Gangway! |Fakat |Étant donnés |Etant donnés |Étant données |Etant données |Étant donnée |Etant donnée |Étant donné |Etant donné |Et |És |Entonces |Entón |Então |Entao |En |Eğer ki |Ef |Eeldades |E |Ðurh |Duota |Dun |Donitaĵo |Donat |Donada |Do |Diyelim ki |Diberi |Dengan |Den youse gotta |DEN |De |Dato |Dați fiind |Daţi fiind |Dati fiind |Dati |Date fiind |Date |Data |Dat fiind |Dar |Dann |dann |Dan |Dados |Dado |Dadas |Dada |Ða ðe |Ða |Cuando |Cho |Cando |Când |Cand |Cal |But y'all |But at the end of the day I reckon |BUT |But |Buh |Blimey! |Biết |Bet |Bagi |Aye |awer |Avast! |Atunci |Atesa |Atès |Apabila |Anrhegedig a |Angenommen |And y'all |And |AN |An |an |Amikor |Amennyiben |Ama |Als |Alors |Allora |Ali |Aleshores |Ale |Akkor |Ak |Adott |Ac |Aber |A zároveň |A tiež |A taktiež |A také |A |a |7 |\\* )/)) {\n        state.inStep = true;\n        state.allowPlaceholders = true;\n        state.allowMultilineArgument = true;\n        state.inKeywordLine = true;\n        return \"keyword\";\n\n      // INLINE STRING\n      } else if (stream.match(/\"[^\"]*\"?/)) {\n        return \"string\";\n\n      // PLACEHOLDER\n      } else if (state.allowPlaceholders && stream.match(/<[^>]*>?/)) {\n        return \"variable\";\n\n      // Fall through\n      } else {\n        stream.next();\n        stream.eatWhile(/[^@\"<#]/);\n        return null;\n      }\n    }\n  };\n});\n\nCodeMirror.defineMIME(\"text/x-feature\", \"gherkin\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/gherkin/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Gherkin mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"gherkin.js\"></script>\n<style>.CodeMirror { border-top: 1px solid #ddd; border-bottom: 1px solid #ddd; }</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Gherkin</a>\n  </ul>\n</div>\n\n<article>\n<h2>Gherkin mode</h2>\n<form><textarea id=\"code\" name=\"code\">\nFeature: Using Google\n  Background: \n    Something something\n    Something else\n  Scenario: Has a homepage\n    When I navigate to the google home page\n    Then the home page should contain the menu and the search form\n  Scenario: Searching for a term \n    When I navigate to the google home page\n    When I search for Tofu\n    Then the search results page is displayed\n    Then the search results page contains 10 individual search results\n    Then the search results contain a link to the wikipedia tofu page\n</textarea></form>\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {});\n    </script>\n\n    <p><strong>MIME types defined:</strong> <code>text/x-feature</code>.</p>\n\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/go/go.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"go\", function(config) {\n  var indentUnit = config.indentUnit;\n\n  var keywords = {\n    \"break\":true, \"case\":true, \"chan\":true, \"const\":true, \"continue\":true,\n    \"default\":true, \"defer\":true, \"else\":true, \"fallthrough\":true, \"for\":true,\n    \"func\":true, \"go\":true, \"goto\":true, \"if\":true, \"import\":true,\n    \"interface\":true, \"map\":true, \"package\":true, \"range\":true, \"return\":true,\n    \"select\":true, \"struct\":true, \"switch\":true, \"type\":true, \"var\":true,\n    \"bool\":true, \"byte\":true, \"complex64\":true, \"complex128\":true,\n    \"float32\":true, \"float64\":true, \"int8\":true, \"int16\":true, \"int32\":true,\n    \"int64\":true, \"string\":true, \"uint8\":true, \"uint16\":true, \"uint32\":true,\n    \"uint64\":true, \"int\":true, \"uint\":true, \"uintptr\":true\n  };\n\n  var atoms = {\n    \"true\":true, \"false\":true, \"iota\":true, \"nil\":true, \"append\":true,\n    \"cap\":true, \"close\":true, \"complex\":true, \"copy\":true, \"imag\":true,\n    \"len\":true, \"make\":true, \"new\":true, \"panic\":true, \"print\":true,\n    \"println\":true, \"real\":true, \"recover\":true\n  };\n\n  var isOperatorChar = /[+\\-*&^%:=<>!|\\/]/;\n\n  var curPunc;\n\n  function tokenBase(stream, state) {\n    var ch = stream.next();\n    if (ch == '\"' || ch == \"'\" || ch == \"`\") {\n      state.tokenize = tokenString(ch);\n      return state.tokenize(stream, state);\n    }\n    if (/[\\d\\.]/.test(ch)) {\n      if (ch == \".\") {\n        stream.match(/^[0-9]+([eE][\\-+]?[0-9]+)?/);\n      } else if (ch == \"0\") {\n        stream.match(/^[xX][0-9a-fA-F]+/) || stream.match(/^0[0-7]+/);\n      } else {\n        stream.match(/^[0-9]*\\.?[0-9]*([eE][\\-+]?[0-9]+)?/);\n      }\n      return \"number\";\n    }\n    if (/[\\[\\]{}\\(\\),;\\:\\.]/.test(ch)) {\n      curPunc = ch;\n      return null;\n    }\n    if (ch == \"/\") {\n      if (stream.eat(\"*\")) {\n        state.tokenize = tokenComment;\n        return tokenComment(stream, state);\n      }\n      if (stream.eat(\"/\")) {\n        stream.skipToEnd();\n        return \"comment\";\n      }\n    }\n    if (isOperatorChar.test(ch)) {\n      stream.eatWhile(isOperatorChar);\n      return \"operator\";\n    }\n    stream.eatWhile(/[\\w\\$_\\xa1-\\uffff]/);\n    var cur = stream.current();\n    if (keywords.propertyIsEnumerable(cur)) {\n      if (cur == \"case\" || cur == \"default\") curPunc = \"case\";\n      return \"keyword\";\n    }\n    if (atoms.propertyIsEnumerable(cur)) return \"atom\";\n    return \"variable\";\n  }\n\n  function tokenString(quote) {\n    return function(stream, state) {\n      var escaped = false, next, end = false;\n      while ((next = stream.next()) != null) {\n        if (next == quote && !escaped) {end = true; break;}\n        escaped = !escaped && next == \"\\\\\";\n      }\n      if (end || !(escaped || quote == \"`\"))\n        state.tokenize = tokenBase;\n      return \"string\";\n    };\n  }\n\n  function tokenComment(stream, state) {\n    var maybeEnd = false, ch;\n    while (ch = stream.next()) {\n      if (ch == \"/\" && maybeEnd) {\n        state.tokenize = tokenBase;\n        break;\n      }\n      maybeEnd = (ch == \"*\");\n    }\n    return \"comment\";\n  }\n\n  function Context(indented, column, type, align, prev) {\n    this.indented = indented;\n    this.column = column;\n    this.type = type;\n    this.align = align;\n    this.prev = prev;\n  }\n  function pushContext(state, col, type) {\n    return state.context = new Context(state.indented, col, type, null, state.context);\n  }\n  function popContext(state) {\n    if (!state.context.prev) return;\n    var t = state.context.type;\n    if (t == \")\" || t == \"]\" || t == \"}\")\n      state.indented = state.context.indented;\n    return state.context = state.context.prev;\n  }\n\n  // Interface\n\n  return {\n    startState: function(basecolumn) {\n      return {\n        tokenize: null,\n        context: new Context((basecolumn || 0) - indentUnit, 0, \"top\", false),\n        indented: 0,\n        startOfLine: true\n      };\n    },\n\n    token: function(stream, state) {\n      var ctx = state.context;\n      if (stream.sol()) {\n        if (ctx.align == null) ctx.align = false;\n        state.indented = stream.indentation();\n        state.startOfLine = true;\n        if (ctx.type == \"case\") ctx.type = \"}\";\n      }\n      if (stream.eatSpace()) return null;\n      curPunc = null;\n      var style = (state.tokenize || tokenBase)(stream, state);\n      if (style == \"comment\") return style;\n      if (ctx.align == null) ctx.align = true;\n\n      if (curPunc == \"{\") pushContext(state, stream.column(), \"}\");\n      else if (curPunc == \"[\") pushContext(state, stream.column(), \"]\");\n      else if (curPunc == \"(\") pushContext(state, stream.column(), \")\");\n      else if (curPunc == \"case\") ctx.type = \"case\";\n      else if (curPunc == \"}\" && ctx.type == \"}\") ctx = popContext(state);\n      else if (curPunc == ctx.type) popContext(state);\n      state.startOfLine = false;\n      return style;\n    },\n\n    indent: function(state, textAfter) {\n      if (state.tokenize != tokenBase && state.tokenize != null) return 0;\n      var ctx = state.context, firstChar = textAfter && textAfter.charAt(0);\n      if (ctx.type == \"case\" && /^(?:case|default)\\b/.test(textAfter)) {\n        state.context.type = \"}\";\n        return ctx.indented;\n      }\n      var closing = firstChar == ctx.type;\n      if (ctx.align) return ctx.column + (closing ? 0 : 1);\n      else return ctx.indented + (closing ? 0 : indentUnit);\n    },\n\n    electricChars: \"{}):\",\n    fold: \"brace\",\n    blockCommentStart: \"/*\",\n    blockCommentEnd: \"*/\",\n    lineComment: \"//\"\n  };\n});\n\nCodeMirror.defineMIME(\"text/x-go\", \"go\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/go/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Go mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<link rel=\"stylesheet\" href=\"../../theme/elegant.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"../../addon/edit/matchbrackets.js\"></script>\n<script src=\"go.js\"></script>\n<style>.CodeMirror {border:1px solid #999; background:#ffc}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Go</a>\n  </ul>\n</div>\n\n<article>\n<h2>Go mode</h2>\n<form><textarea id=\"code\" name=\"code\">\n// Prime Sieve in Go.\n// Taken from the Go specification.\n// Copyright © The Go Authors.\n\npackage main\n\nimport \"fmt\"\n\n// Send the sequence 2, 3, 4, ... to channel 'ch'.\nfunc generate(ch chan&lt;- int) {\n\tfor i := 2; ; i++ {\n\t\tch &lt;- i  // Send 'i' to channel 'ch'\n\t}\n}\n\n// Copy the values from channel 'src' to channel 'dst',\n// removing those divisible by 'prime'.\nfunc filter(src &lt;-chan int, dst chan&lt;- int, prime int) {\n\tfor i := range src {    // Loop over values received from 'src'.\n\t\tif i%prime != 0 {\n\t\t\tdst &lt;- i  // Send 'i' to channel 'dst'.\n\t\t}\n\t}\n}\n\n// The prime sieve: Daisy-chain filter processes together.\nfunc sieve() {\n\tch := make(chan int)  // Create a new channel.\n\tgo generate(ch)       // Start generate() as a subprocess.\n\tfor {\n\t\tprime := &lt;-ch\n\t\tfmt.Print(prime, \"\\n\")\n\t\tch1 := make(chan int)\n\t\tgo filter(ch, ch1, prime)\n\t\tch = ch1\n\t}\n}\n\nfunc main() {\n\tsieve()\n}\n</textarea></form>\n\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        theme: \"elegant\",\n        matchBrackets: true,\n        indentUnit: 8,\n        tabSize: 8,\n        indentWithTabs: true,\n        mode: \"text/x-go\"\n      });\n    </script>\n\n    <p><strong>MIME type:</strong> <code>text/x-go</code></p>\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/groovy/groovy.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"groovy\", function(config) {\n  function words(str) {\n    var obj = {}, words = str.split(\" \");\n    for (var i = 0; i < words.length; ++i) obj[words[i]] = true;\n    return obj;\n  }\n  var keywords = words(\n    \"abstract as assert boolean break byte case catch char class const continue def default \" +\n    \"do double else enum extends final finally float for goto if implements import in \" +\n    \"instanceof int interface long native new package private protected public return \" +\n    \"short static strictfp super switch synchronized threadsafe throw throws transient \" +\n    \"try void volatile while\");\n  var blockKeywords = words(\"catch class do else finally for if switch try while enum interface def\");\n  var atoms = words(\"null true false this\");\n\n  var curPunc;\n  function tokenBase(stream, state) {\n    var ch = stream.next();\n    if (ch == '\"' || ch == \"'\") {\n      return startString(ch, stream, state);\n    }\n    if (/[\\[\\]{}\\(\\),;\\:\\.]/.test(ch)) {\n      curPunc = ch;\n      return null;\n    }\n    if (/\\d/.test(ch)) {\n      stream.eatWhile(/[\\w\\.]/);\n      if (stream.eat(/eE/)) { stream.eat(/\\+\\-/); stream.eatWhile(/\\d/); }\n      return \"number\";\n    }\n    if (ch == \"/\") {\n      if (stream.eat(\"*\")) {\n        state.tokenize.push(tokenComment);\n        return tokenComment(stream, state);\n      }\n      if (stream.eat(\"/\")) {\n        stream.skipToEnd();\n        return \"comment\";\n      }\n      if (expectExpression(state.lastToken)) {\n        return startString(ch, stream, state);\n      }\n    }\n    if (ch == \"-\" && stream.eat(\">\")) {\n      curPunc = \"->\";\n      return null;\n    }\n    if (/[+\\-*&%=<>!?|\\/~]/.test(ch)) {\n      stream.eatWhile(/[+\\-*&%=<>|~]/);\n      return \"operator\";\n    }\n    stream.eatWhile(/[\\w\\$_]/);\n    if (ch == \"@\") { stream.eatWhile(/[\\w\\$_\\.]/); return \"meta\"; }\n    if (state.lastToken == \".\") return \"property\";\n    if (stream.eat(\":\")) { curPunc = \"proplabel\"; return \"property\"; }\n    var cur = stream.current();\n    if (atoms.propertyIsEnumerable(cur)) { return \"atom\"; }\n    if (keywords.propertyIsEnumerable(cur)) {\n      if (blockKeywords.propertyIsEnumerable(cur)) curPunc = \"newstatement\";\n      return \"keyword\";\n    }\n    return \"variable\";\n  }\n  tokenBase.isBase = true;\n\n  function startString(quote, stream, state) {\n    var tripleQuoted = false;\n    if (quote != \"/\" && stream.eat(quote)) {\n      if (stream.eat(quote)) tripleQuoted = true;\n      else return \"string\";\n    }\n    function t(stream, state) {\n      var escaped = false, next, end = !tripleQuoted;\n      while ((next = stream.next()) != null) {\n        if (next == quote && !escaped) {\n          if (!tripleQuoted) { break; }\n          if (stream.match(quote + quote)) { end = true; break; }\n        }\n        if (quote == '\"' && next == \"$\" && !escaped && stream.eat(\"{\")) {\n          state.tokenize.push(tokenBaseUntilBrace());\n          return \"string\";\n        }\n        escaped = !escaped && next == \"\\\\\";\n      }\n      if (end) state.tokenize.pop();\n      return \"string\";\n    }\n    state.tokenize.push(t);\n    return t(stream, state);\n  }\n\n  function tokenBaseUntilBrace() {\n    var depth = 1;\n    function t(stream, state) {\n      if (stream.peek() == \"}\") {\n        depth--;\n        if (depth == 0) {\n          state.tokenize.pop();\n          return state.tokenize[state.tokenize.length-1](stream, state);\n        }\n      } else if (stream.peek() == \"{\") {\n        depth++;\n      }\n      return tokenBase(stream, state);\n    }\n    t.isBase = true;\n    return t;\n  }\n\n  function tokenComment(stream, state) {\n    var maybeEnd = false, ch;\n    while (ch = stream.next()) {\n      if (ch == \"/\" && maybeEnd) {\n        state.tokenize.pop();\n        break;\n      }\n      maybeEnd = (ch == \"*\");\n    }\n    return \"comment\";\n  }\n\n  function expectExpression(last) {\n    return !last || last == \"operator\" || last == \"->\" || /[\\.\\[\\{\\(,;:]/.test(last) ||\n      last == \"newstatement\" || last == \"keyword\" || last == \"proplabel\";\n  }\n\n  function Context(indented, column, type, align, prev) {\n    this.indented = indented;\n    this.column = column;\n    this.type = type;\n    this.align = align;\n    this.prev = prev;\n  }\n  function pushContext(state, col, type) {\n    return state.context = new Context(state.indented, col, type, null, state.context);\n  }\n  function popContext(state) {\n    var t = state.context.type;\n    if (t == \")\" || t == \"]\" || t == \"}\")\n      state.indented = state.context.indented;\n    return state.context = state.context.prev;\n  }\n\n  // Interface\n\n  return {\n    startState: function(basecolumn) {\n      return {\n        tokenize: [tokenBase],\n        context: new Context((basecolumn || 0) - config.indentUnit, 0, \"top\", false),\n        indented: 0,\n        startOfLine: true,\n        lastToken: null\n      };\n    },\n\n    token: function(stream, state) {\n      var ctx = state.context;\n      if (stream.sol()) {\n        if (ctx.align == null) ctx.align = false;\n        state.indented = stream.indentation();\n        state.startOfLine = true;\n        // Automatic semicolon insertion\n        if (ctx.type == \"statement\" && !expectExpression(state.lastToken)) {\n          popContext(state); ctx = state.context;\n        }\n      }\n      if (stream.eatSpace()) return null;\n      curPunc = null;\n      var style = state.tokenize[state.tokenize.length-1](stream, state);\n      if (style == \"comment\") return style;\n      if (ctx.align == null) ctx.align = true;\n\n      if ((curPunc == \";\" || curPunc == \":\") && ctx.type == \"statement\") popContext(state);\n      // Handle indentation for {x -> \\n ... }\n      else if (curPunc == \"->\" && ctx.type == \"statement\" && ctx.prev.type == \"}\") {\n        popContext(state);\n        state.context.align = false;\n      }\n      else if (curPunc == \"{\") pushContext(state, stream.column(), \"}\");\n      else if (curPunc == \"[\") pushContext(state, stream.column(), \"]\");\n      else if (curPunc == \"(\") pushContext(state, stream.column(), \")\");\n      else if (curPunc == \"}\") {\n        while (ctx.type == \"statement\") ctx = popContext(state);\n        if (ctx.type == \"}\") ctx = popContext(state);\n        while (ctx.type == \"statement\") ctx = popContext(state);\n      }\n      else if (curPunc == ctx.type) popContext(state);\n      else if (ctx.type == \"}\" || ctx.type == \"top\" || (ctx.type == \"statement\" && curPunc == \"newstatement\"))\n        pushContext(state, stream.column(), \"statement\");\n      state.startOfLine = false;\n      state.lastToken = curPunc || style;\n      return style;\n    },\n\n    indent: function(state, textAfter) {\n      if (!state.tokenize[state.tokenize.length-1].isBase) return 0;\n      var firstChar = textAfter && textAfter.charAt(0), ctx = state.context;\n      if (ctx.type == \"statement\" && !expectExpression(state.lastToken)) ctx = ctx.prev;\n      var closing = firstChar == ctx.type;\n      if (ctx.type == \"statement\") return ctx.indented + (firstChar == \"{\" ? 0 : config.indentUnit);\n      else if (ctx.align) return ctx.column + (closing ? 0 : 1);\n      else return ctx.indented + (closing ? 0 : config.indentUnit);\n    },\n\n    electricChars: \"{}\",\n    fold: \"brace\"\n  };\n});\n\nCodeMirror.defineMIME(\"text/x-groovy\", \"groovy\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/groovy/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Groovy mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"../../addon/edit/matchbrackets.js\"></script>\n<script src=\"groovy.js\"></script>\n<style>.CodeMirror {border-top: 1px solid #500; border-bottom: 1px solid #500;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Groovy</a>\n  </ul>\n</div>\n\n<article>\n<h2>Groovy mode</h2>\n<form><textarea id=\"code\" name=\"code\">\n//Pattern for groovy script\ndef p = ~/.*\\.groovy/\nnew File( 'd:\\\\scripts' ).eachFileMatch(p) {f ->\n  // imports list\n  def imports = []\n  f.eachLine {\n    // condition to detect an import instruction\n    ln -> if ( ln =~ '^import .*' ) {\n      imports << \"${ln - 'import '}\"\n    }\n  }\n  // print thmen\n  if ( ! imports.empty ) {\n    println f\n    imports.each{ println \"   $it\" }\n  }\n}\n\n/* Coin changer demo code from http://groovy.codehaus.org */\n\nenum UsCoin {\n  quarter(25), dime(10), nickel(5), penny(1)\n  UsCoin(v) { value = v }\n  final value\n}\n\nenum OzzieCoin {\n  fifty(50), twenty(20), ten(10), five(5)\n  OzzieCoin(v) { value = v }\n  final value\n}\n\ndef plural(word, count) {\n  if (count == 1) return word\n  word[-1] == 'y' ? word[0..-2] + \"ies\" : word + \"s\"\n}\n\ndef change(currency, amount) {\n  currency.values().inject([]){ list, coin ->\n     int count = amount / coin.value\n     amount = amount % coin.value\n     list += \"$count ${plural(coin.toString(), count)}\"\n  }\n}\n</textarea></form>\n\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        lineNumbers: true,\n        matchBrackets: true,\n        mode: \"text/x-groovy\"\n      });\n    </script>\n\n    <p><strong>MIME types defined:</strong> <code>text/x-groovy</code></p>\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/haml/haml.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"), require(\"../htmlmixed/htmlmixed\"), require(\"../ruby/ruby\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\", \"../htmlmixed/htmlmixed\", \"../ruby/ruby\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\n  // full haml mode. This handled embeded ruby and html fragments too\n  CodeMirror.defineMode(\"haml\", function(config) {\n    var htmlMode = CodeMirror.getMode(config, {name: \"htmlmixed\"});\n    var rubyMode = CodeMirror.getMode(config, \"ruby\");\n\n    function rubyInQuote(endQuote) {\n      return function(stream, state) {\n        var ch = stream.peek();\n        if (ch == endQuote && state.rubyState.tokenize.length == 1) {\n          // step out of ruby context as it seems to complete processing all the braces\n          stream.next();\n          state.tokenize = html;\n          return \"closeAttributeTag\";\n        } else {\n          return ruby(stream, state);\n        }\n      };\n    }\n\n    function ruby(stream, state) {\n      if (stream.match(\"-#\")) {\n        stream.skipToEnd();\n        return \"comment\";\n      }\n      return rubyMode.token(stream, state.rubyState);\n    }\n\n    function html(stream, state) {\n      var ch = stream.peek();\n\n      // handle haml declarations. All declarations that cant be handled here\n      // will be passed to html mode\n      if (state.previousToken.style == \"comment\" ) {\n        if (state.indented > state.previousToken.indented) {\n          stream.skipToEnd();\n          return \"commentLine\";\n        }\n      }\n\n      if (state.startOfLine) {\n        if (ch == \"!\" && stream.match(\"!!\")) {\n          stream.skipToEnd();\n          return \"tag\";\n        } else if (stream.match(/^%[\\w:#\\.]+=/)) {\n          state.tokenize = ruby;\n          return \"hamlTag\";\n        } else if (stream.match(/^%[\\w:]+/)) {\n          return \"hamlTag\";\n        } else if (ch == \"/\" ) {\n          stream.skipToEnd();\n          return \"comment\";\n        }\n      }\n\n      if (state.startOfLine || state.previousToken.style == \"hamlTag\") {\n        if ( ch == \"#\" || ch == \".\") {\n          stream.match(/[\\w-#\\.]*/);\n          return \"hamlAttribute\";\n        }\n      }\n\n      // donot handle --> as valid ruby, make it HTML close comment instead\n      if (state.startOfLine && !stream.match(\"-->\", false) && (ch == \"=\" || ch == \"-\" )) {\n        state.tokenize = ruby;\n        return state.tokenize(stream, state);\n      }\n\n      if (state.previousToken.style == \"hamlTag\" ||\n          state.previousToken.style == \"closeAttributeTag\" ||\n          state.previousToken.style == \"hamlAttribute\") {\n        if (ch == \"(\") {\n          state.tokenize = rubyInQuote(\")\");\n          return state.tokenize(stream, state);\n        } else if (ch == \"{\") {\n          state.tokenize = rubyInQuote(\"}\");\n          return state.tokenize(stream, state);\n        }\n      }\n\n      return htmlMode.token(stream, state.htmlState);\n    }\n\n    return {\n      // default to html mode\n      startState: function() {\n        var htmlState = htmlMode.startState();\n        var rubyState = rubyMode.startState();\n        return {\n          htmlState: htmlState,\n          rubyState: rubyState,\n          indented: 0,\n          previousToken: { style: null, indented: 0},\n          tokenize: html\n        };\n      },\n\n      copyState: function(state) {\n        return {\n          htmlState : CodeMirror.copyState(htmlMode, state.htmlState),\n          rubyState: CodeMirror.copyState(rubyMode, state.rubyState),\n          indented: state.indented,\n          previousToken: state.previousToken,\n          tokenize: state.tokenize\n        };\n      },\n\n      token: function(stream, state) {\n        if (stream.sol()) {\n          state.indented = stream.indentation();\n          state.startOfLine = true;\n        }\n        if (stream.eatSpace()) return null;\n        var style = state.tokenize(stream, state);\n        state.startOfLine = false;\n        // dont record comment line as we only want to measure comment line with\n        // the opening comment block\n        if (style && style != \"commentLine\") {\n          state.previousToken = { style: style, indented: state.indented };\n        }\n        // if current state is ruby and the previous token is not `,` reset the\n        // tokenize to html\n        if (stream.eol() && state.tokenize == ruby) {\n          stream.backUp(1);\n          var ch = stream.peek();\n          stream.next();\n          if (ch && ch != \",\") {\n            state.tokenize = html;\n          }\n        }\n        // reprocess some of the specific style tag when finish setting previousToken\n        if (style == \"hamlTag\") {\n          style = \"tag\";\n        } else if (style == \"commentLine\") {\n          style = \"comment\";\n        } else if (style == \"hamlAttribute\") {\n          style = \"attribute\";\n        } else if (style == \"closeAttributeTag\") {\n          style = null;\n        }\n        return style;\n      }\n    };\n  }, \"htmlmixed\", \"ruby\");\n\n  CodeMirror.defineMIME(\"text/x-haml\", \"haml\");\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/haml/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: HAML mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"../xml/xml.js\"></script>\n<script src=\"../htmlmixed/htmlmixed.js\"></script>\n<script src=\"../javascript/javascript.js\"></script>\n<script src=\"../ruby/ruby.js\"></script>\n<script src=\"haml.js\"></script>\n<style>.CodeMirror {background: #f8f8f8;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">HAML</a>\n  </ul>\n</div>\n\n<article>\n<h2>HAML mode</h2>\n<form><textarea id=\"code\" name=\"code\">\n!!!\n#content\n.left.column(title=\"title\"){:href => \"/hello\", :test => \"#{hello}_#{world}\"}\n    <!-- This is a comment -->\n    %h2 Welcome to our site!\n    %p= puts \"HAML MODE\"\n  .right.column\n    = render :partial => \"sidebar\"\n\n.container\n  .row\n    .span8\n      %h1.title= @page_title\n%p.title= @page_title\n%p\n  /\n    The same as HTML comment\n    Hello multiline comment\n\n  -# haml comment\n      This wont be displayed\n      nor will this\n  Date/Time:\n  - now = DateTime.now\n  %strong= now\n  - if now > DateTime.parse(\"December 31, 2006\")\n    = \"Happy new \" + \"year!\"\n\n%title\n  = @title\n  \\= @title\n  <h1>Title</h1>\n  <h1 title=\"HELLO\">\n    Title\n  </h1>\n    </textarea></form>\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        lineNumbers: true,\n        mode: \"text/x-haml\"\n      });\n    </script>\n\n    <p><strong>MIME types defined:</strong> <code>text/x-haml</code>.</p>\n\n    <p><strong>Parsing/Highlighting Tests:</strong> <a href=\"../../test/index.html#haml_*\">normal</a>,  <a href=\"../../test/index.html#verbose,haml_*\">verbose</a>.</p>\n\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/haml/test.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function() {\n  var mode = CodeMirror.getMode({tabSize: 4, indentUnit: 2}, \"haml\");\n  function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); }\n\n  // Requires at least one media query\n  MT(\"elementName\",\n     \"[tag %h1] Hey There\");\n\n  MT(\"oneElementPerLine\",\n     \"[tag %h1] Hey There %h2\");\n\n  MT(\"idSelector\",\n     \"[tag %h1][attribute #test] Hey There\");\n\n  MT(\"classSelector\",\n     \"[tag %h1][attribute .hello] Hey There\");\n\n  MT(\"docType\",\n     \"[tag !!! XML]\");\n\n  MT(\"comment\",\n     \"[comment / Hello WORLD]\");\n\n  MT(\"notComment\",\n     \"[tag %h1] This is not a / comment \");\n\n  MT(\"attributes\",\n     \"[tag %a]([variable title][operator =][string \\\"test\\\"]){[atom :title] [operator =>] [string \\\"test\\\"]}\");\n\n  MT(\"htmlCode\",\n     \"[tag&bracket <][tag h1][tag&bracket >]Title[tag&bracket </][tag h1][tag&bracket >]\");\n\n  MT(\"rubyBlock\",\n     \"[operator =][variable-2 @item]\");\n\n  MT(\"selectorRubyBlock\",\n     \"[tag %a.selector=] [variable-2 @item]\");\n\n  MT(\"nestedRubyBlock\",\n      \"[tag %a]\",\n      \"   [operator =][variable puts] [string \\\"test\\\"]\");\n\n  MT(\"multilinePlaintext\",\n      \"[tag %p]\",\n      \"  Hello,\",\n      \"  World\");\n\n  MT(\"multilineRuby\",\n      \"[tag %p]\",\n      \"  [comment -# this is a comment]\",\n      \"     [comment and this is a comment too]\",\n      \"  Date/Time\",\n      \"  [operator -] [variable now] [operator =] [tag DateTime][operator .][property now]\",\n      \"  [tag %strong=] [variable now]\",\n      \"  [operator -] [keyword if] [variable now] [operator >] [tag DateTime][operator .][property parse]([string \\\"December 31, 2006\\\"])\",\n      \"     [operator =][string \\\"Happy\\\"]\",\n      \"     [operator =][string \\\"Belated\\\"]\",\n      \"     [operator =][string \\\"Birthday\\\"]\");\n\n  MT(\"multilineComment\",\n      \"[comment /]\",\n      \"  [comment Multiline]\",\n      \"  [comment Comment]\");\n\n  MT(\"hamlComment\",\n     \"[comment -# this is a comment]\");\n\n  MT(\"multilineHamlComment\",\n     \"[comment -# this is a comment]\",\n     \"   [comment and this is a comment too]\");\n\n  MT(\"multilineHTMLComment\",\n    \"[comment <!--]\",\n    \"  [comment what a comment]\",\n    \"  [comment -->]\");\n\n  MT(\"hamlAfterRubyTag\",\n    \"[attribute .block]\",\n    \"  [tag %strong=] [variable now]\",\n    \"  [attribute .test]\",\n    \"     [operator =][variable now]\",\n    \"  [attribute .right]\");\n\n  MT(\"stretchedRuby\",\n     \"[operator =] [variable puts] [string \\\"Hello\\\"],\",\n     \"   [string \\\"World\\\"]\");\n\n  MT(\"interpolationInHashAttribute\",\n     //\"[tag %div]{[atom :id] [operator =>] [string \\\"#{][variable test][string }_#{][variable ting][string }\\\"]} test\");\n     \"[tag %div]{[atom :id] [operator =>] [string \\\"#{][variable test][string }_#{][variable ting][string }\\\"]} test\");\n\n  MT(\"interpolationInHTMLAttribute\",\n     \"[tag %div]([variable title][operator =][string \\\"#{][variable test][string }_#{][variable ting]()[string }\\\"]) Test\");\n})();\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/haskell/haskell.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"haskell\", function(_config, modeConfig) {\n\n  function switchState(source, setState, f) {\n    setState(f);\n    return f(source, setState);\n  }\n\n  // These should all be Unicode extended, as per the Haskell 2010 report\n  var smallRE = /[a-z_]/;\n  var largeRE = /[A-Z]/;\n  var digitRE = /\\d/;\n  var hexitRE = /[0-9A-Fa-f]/;\n  var octitRE = /[0-7]/;\n  var idRE = /[a-z_A-Z0-9'\\xa1-\\uffff]/;\n  var symbolRE = /[-!#$%&*+.\\/<=>?@\\\\^|~:]/;\n  var specialRE = /[(),;[\\]`{}]/;\n  var whiteCharRE = /[ \\t\\v\\f]/; // newlines are handled in tokenizer\n\n  function normal(source, setState) {\n    if (source.eatWhile(whiteCharRE)) {\n      return null;\n    }\n\n    var ch = source.next();\n    if (specialRE.test(ch)) {\n      if (ch == '{' && source.eat('-')) {\n        var t = \"comment\";\n        if (source.eat('#')) {\n          t = \"meta\";\n        }\n        return switchState(source, setState, ncomment(t, 1));\n      }\n      return null;\n    }\n\n    if (ch == '\\'') {\n      if (source.eat('\\\\')) {\n        source.next();  // should handle other escapes here\n      }\n      else {\n        source.next();\n      }\n      if (source.eat('\\'')) {\n        return \"string\";\n      }\n      return \"error\";\n    }\n\n    if (ch == '\"') {\n      return switchState(source, setState, stringLiteral);\n    }\n\n    if (largeRE.test(ch)) {\n      source.eatWhile(idRE);\n      if (source.eat('.')) {\n        return \"qualifier\";\n      }\n      return \"variable-2\";\n    }\n\n    if (smallRE.test(ch)) {\n      source.eatWhile(idRE);\n      return \"variable\";\n    }\n\n    if (digitRE.test(ch)) {\n      if (ch == '0') {\n        if (source.eat(/[xX]/)) {\n          source.eatWhile(hexitRE); // should require at least 1\n          return \"integer\";\n        }\n        if (source.eat(/[oO]/)) {\n          source.eatWhile(octitRE); // should require at least 1\n          return \"number\";\n        }\n      }\n      source.eatWhile(digitRE);\n      var t = \"number\";\n      if (source.match(/^\\.\\d+/)) {\n        t = \"number\";\n      }\n      if (source.eat(/[eE]/)) {\n        t = \"number\";\n        source.eat(/[-+]/);\n        source.eatWhile(digitRE); // should require at least 1\n      }\n      return t;\n    }\n\n    if (ch == \".\" && source.eat(\".\"))\n      return \"keyword\";\n\n    if (symbolRE.test(ch)) {\n      if (ch == '-' && source.eat(/-/)) {\n        source.eatWhile(/-/);\n        if (!source.eat(symbolRE)) {\n          source.skipToEnd();\n          return \"comment\";\n        }\n      }\n      var t = \"variable\";\n      if (ch == ':') {\n        t = \"variable-2\";\n      }\n      source.eatWhile(symbolRE);\n      return t;\n    }\n\n    return \"error\";\n  }\n\n  function ncomment(type, nest) {\n    if (nest == 0) {\n      return normal;\n    }\n    return function(source, setState) {\n      var currNest = nest;\n      while (!source.eol()) {\n        var ch = source.next();\n        if (ch == '{' && source.eat('-')) {\n          ++currNest;\n        }\n        else if (ch == '-' && source.eat('}')) {\n          --currNest;\n          if (currNest == 0) {\n            setState(normal);\n            return type;\n          }\n        }\n      }\n      setState(ncomment(type, currNest));\n      return type;\n    };\n  }\n\n  function stringLiteral(source, setState) {\n    while (!source.eol()) {\n      var ch = source.next();\n      if (ch == '\"') {\n        setState(normal);\n        return \"string\";\n      }\n      if (ch == '\\\\') {\n        if (source.eol() || source.eat(whiteCharRE)) {\n          setState(stringGap);\n          return \"string\";\n        }\n        if (source.eat('&')) {\n        }\n        else {\n          source.next(); // should handle other escapes here\n        }\n      }\n    }\n    setState(normal);\n    return \"error\";\n  }\n\n  function stringGap(source, setState) {\n    if (source.eat('\\\\')) {\n      return switchState(source, setState, stringLiteral);\n    }\n    source.next();\n    setState(normal);\n    return \"error\";\n  }\n\n\n  var wellKnownWords = (function() {\n    var wkw = {};\n    function setType(t) {\n      return function () {\n        for (var i = 0; i < arguments.length; i++)\n          wkw[arguments[i]] = t;\n      };\n    }\n\n    setType(\"keyword\")(\n      \"case\", \"class\", \"data\", \"default\", \"deriving\", \"do\", \"else\", \"foreign\",\n      \"if\", \"import\", \"in\", \"infix\", \"infixl\", \"infixr\", \"instance\", \"let\",\n      \"module\", \"newtype\", \"of\", \"then\", \"type\", \"where\", \"_\");\n\n    setType(\"keyword\")(\n      \"\\.\\.\", \":\", \"::\", \"=\", \"\\\\\", \"\\\"\", \"<-\", \"->\", \"@\", \"~\", \"=>\");\n\n    setType(\"builtin\")(\n      \"!!\", \"$!\", \"$\", \"&&\", \"+\", \"++\", \"-\", \".\", \"/\", \"/=\", \"<\", \"<=\", \"=<<\",\n      \"==\", \">\", \">=\", \">>\", \">>=\", \"^\", \"^^\", \"||\", \"*\", \"**\");\n\n    setType(\"builtin\")(\n      \"Bool\", \"Bounded\", \"Char\", \"Double\", \"EQ\", \"Either\", \"Enum\", \"Eq\",\n      \"False\", \"FilePath\", \"Float\", \"Floating\", \"Fractional\", \"Functor\", \"GT\",\n      \"IO\", \"IOError\", \"Int\", \"Integer\", \"Integral\", \"Just\", \"LT\", \"Left\",\n      \"Maybe\", \"Monad\", \"Nothing\", \"Num\", \"Ord\", \"Ordering\", \"Rational\", \"Read\",\n      \"ReadS\", \"Real\", \"RealFloat\", \"RealFrac\", \"Right\", \"Show\", \"ShowS\",\n      \"String\", \"True\");\n\n    setType(\"builtin\")(\n      \"abs\", \"acos\", \"acosh\", \"all\", \"and\", \"any\", \"appendFile\", \"asTypeOf\",\n      \"asin\", \"asinh\", \"atan\", \"atan2\", \"atanh\", \"break\", \"catch\", \"ceiling\",\n      \"compare\", \"concat\", \"concatMap\", \"const\", \"cos\", \"cosh\", \"curry\",\n      \"cycle\", \"decodeFloat\", \"div\", \"divMod\", \"drop\", \"dropWhile\", \"either\",\n      \"elem\", \"encodeFloat\", \"enumFrom\", \"enumFromThen\", \"enumFromThenTo\",\n      \"enumFromTo\", \"error\", \"even\", \"exp\", \"exponent\", \"fail\", \"filter\",\n      \"flip\", \"floatDigits\", \"floatRadix\", \"floatRange\", \"floor\", \"fmap\",\n      \"foldl\", \"foldl1\", \"foldr\", \"foldr1\", \"fromEnum\", \"fromInteger\",\n      \"fromIntegral\", \"fromRational\", \"fst\", \"gcd\", \"getChar\", \"getContents\",\n      \"getLine\", \"head\", \"id\", \"init\", \"interact\", \"ioError\", \"isDenormalized\",\n      \"isIEEE\", \"isInfinite\", \"isNaN\", \"isNegativeZero\", \"iterate\", \"last\",\n      \"lcm\", \"length\", \"lex\", \"lines\", \"log\", \"logBase\", \"lookup\", \"map\",\n      \"mapM\", \"mapM_\", \"max\", \"maxBound\", \"maximum\", \"maybe\", \"min\", \"minBound\",\n      \"minimum\", \"mod\", \"negate\", \"not\", \"notElem\", \"null\", \"odd\", \"or\",\n      \"otherwise\", \"pi\", \"pred\", \"print\", \"product\", \"properFraction\",\n      \"putChar\", \"putStr\", \"putStrLn\", \"quot\", \"quotRem\", \"read\", \"readFile\",\n      \"readIO\", \"readList\", \"readLn\", \"readParen\", \"reads\", \"readsPrec\",\n      \"realToFrac\", \"recip\", \"rem\", \"repeat\", \"replicate\", \"return\", \"reverse\",\n      \"round\", \"scaleFloat\", \"scanl\", \"scanl1\", \"scanr\", \"scanr1\", \"seq\",\n      \"sequence\", \"sequence_\", \"show\", \"showChar\", \"showList\", \"showParen\",\n      \"showString\", \"shows\", \"showsPrec\", \"significand\", \"signum\", \"sin\",\n      \"sinh\", \"snd\", \"span\", \"splitAt\", \"sqrt\", \"subtract\", \"succ\", \"sum\",\n      \"tail\", \"take\", \"takeWhile\", \"tan\", \"tanh\", \"toEnum\", \"toInteger\",\n      \"toRational\", \"truncate\", \"uncurry\", \"undefined\", \"unlines\", \"until\",\n      \"unwords\", \"unzip\", \"unzip3\", \"userError\", \"words\", \"writeFile\", \"zip\",\n      \"zip3\", \"zipWith\", \"zipWith3\");\n\n    var override = modeConfig.overrideKeywords;\n    if (override) for (var word in override) if (override.hasOwnProperty(word))\n      wkw[word] = override[word];\n\n    return wkw;\n  })();\n\n\n\n  return {\n    startState: function ()  { return { f: normal }; },\n    copyState:  function (s) { return { f: s.f }; },\n\n    token: function(stream, state) {\n      var t = state.f(stream, function(s) { state.f = s; });\n      var w = stream.current();\n      return wellKnownWords.hasOwnProperty(w) ? wellKnownWords[w] : t;\n    },\n\n    blockCommentStart: \"{-\",\n    blockCommentEnd: \"-}\",\n    lineComment: \"--\"\n  };\n\n});\n\nCodeMirror.defineMIME(\"text/x-haskell\", \"haskell\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/haskell/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Haskell mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<link rel=\"stylesheet\" href=\"../../theme/elegant.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"../../addon/edit/matchbrackets.js\"></script>\n<script src=\"haskell.js\"></script>\n<style type=\"text/css\">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Haskell</a>\n  </ul>\n</div>\n\n<article>\n<h2>Haskell mode</h2>\n<form><textarea id=\"code\" name=\"code\">\nmodule UniquePerms (\n    uniquePerms\n    )\nwhere\n\n-- | Find all unique permutations of a list where there might be duplicates.\nuniquePerms :: (Eq a) => [a] -> [[a]]\nuniquePerms = permBag . makeBag\n\n-- | An unordered collection where duplicate values are allowed,\n-- but represented with a single value and a count.\ntype Bag a = [(a, Int)]\n\nmakeBag :: (Eq a) => [a] -> Bag a\nmakeBag [] = []\nmakeBag (a:as) = mix a $ makeBag as\n  where\n    mix a []                        = [(a,1)]\n    mix a (bn@(b,n):bs) | a == b    = (b,n+1):bs\n                        | otherwise = bn : mix a bs\n\npermBag :: Bag a -> [[a]]\npermBag [] = [[]]\npermBag bs = concatMap (\\(f,cs) -> map (f:) $ permBag cs) . oneOfEach $ bs\n  where\n    oneOfEach [] = []\n    oneOfEach (an@(a,n):bs) =\n        let bs' = if n == 1 then bs else (a,n-1):bs\n        in (a,bs') : mapSnd (an:) (oneOfEach bs)\n    \n    apSnd f (a,b) = (a, f b)\n    mapSnd = map . apSnd\n</textarea></form>\n\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        lineNumbers: true,\n        matchBrackets: true,\n        theme: \"elegant\"\n      });\n    </script>\n\n    <p><strong>MIME types defined:</strong> <code>text/x-haskell</code>.</p>\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/haxe/haxe.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"haxe\", function(config, parserConfig) {\n  var indentUnit = config.indentUnit;\n\n  // Tokenizer\n\n  var keywords = function(){\n    function kw(type) {return {type: type, style: \"keyword\"};}\n    var A = kw(\"keyword a\"), B = kw(\"keyword b\"), C = kw(\"keyword c\");\n    var operator = kw(\"operator\"), atom = {type: \"atom\", style: \"atom\"}, attribute = {type:\"attribute\", style: \"attribute\"};\n  var type = kw(\"typedef\");\n    return {\n      \"if\": A, \"while\": A, \"else\": B, \"do\": B, \"try\": B,\n      \"return\": C, \"break\": C, \"continue\": C, \"new\": C, \"throw\": C,\n      \"var\": kw(\"var\"), \"inline\":attribute, \"static\": attribute, \"using\":kw(\"import\"),\n    \"public\": attribute, \"private\": attribute, \"cast\": kw(\"cast\"), \"import\": kw(\"import\"), \"macro\": kw(\"macro\"),\n      \"function\": kw(\"function\"), \"catch\": kw(\"catch\"), \"untyped\": kw(\"untyped\"), \"callback\": kw(\"cb\"),\n      \"for\": kw(\"for\"), \"switch\": kw(\"switch\"), \"case\": kw(\"case\"), \"default\": kw(\"default\"),\n      \"in\": operator, \"never\": kw(\"property_access\"), \"trace\":kw(\"trace\"),\n    \"class\": type, \"abstract\":type, \"enum\":type, \"interface\":type, \"typedef\":type, \"extends\":type, \"implements\":type, \"dynamic\":type,\n      \"true\": atom, \"false\": atom, \"null\": atom\n    };\n  }();\n\n  var isOperatorChar = /[+\\-*&%=<>!?|]/;\n\n  function chain(stream, state, f) {\n    state.tokenize = f;\n    return f(stream, state);\n  }\n\n  function nextUntilUnescaped(stream, end) {\n    var escaped = false, next;\n    while ((next = stream.next()) != null) {\n      if (next == end && !escaped)\n        return false;\n      escaped = !escaped && next == \"\\\\\";\n    }\n    return escaped;\n  }\n\n  // Used as scratch variables to communicate multiple values without\n  // consing up tons of objects.\n  var type, content;\n  function ret(tp, style, cont) {\n    type = tp; content = cont;\n    return style;\n  }\n\n  function haxeTokenBase(stream, state) {\n    var ch = stream.next();\n    if (ch == '\"' || ch == \"'\")\n      return chain(stream, state, haxeTokenString(ch));\n    else if (/[\\[\\]{}\\(\\),;\\:\\.]/.test(ch))\n      return ret(ch);\n    else if (ch == \"0\" && stream.eat(/x/i)) {\n      stream.eatWhile(/[\\da-f]/i);\n      return ret(\"number\", \"number\");\n    }\n    else if (/\\d/.test(ch) || ch == \"-\" && stream.eat(/\\d/)) {\n      stream.match(/^\\d*(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?/);\n      return ret(\"number\", \"number\");\n    }\n    else if (state.reAllowed && (ch == \"~\" && stream.eat(/\\//))) {\n      nextUntilUnescaped(stream, \"/\");\n      stream.eatWhile(/[gimsu]/);\n      return ret(\"regexp\", \"string-2\");\n    }\n    else if (ch == \"/\") {\n      if (stream.eat(\"*\")) {\n        return chain(stream, state, haxeTokenComment);\n      }\n      else if (stream.eat(\"/\")) {\n        stream.skipToEnd();\n        return ret(\"comment\", \"comment\");\n      }\n      else {\n        stream.eatWhile(isOperatorChar);\n        return ret(\"operator\", null, stream.current());\n      }\n    }\n    else if (ch == \"#\") {\n        stream.skipToEnd();\n        return ret(\"conditional\", \"meta\");\n    }\n    else if (ch == \"@\") {\n      stream.eat(/:/);\n      stream.eatWhile(/[\\w_]/);\n      return ret (\"metadata\", \"meta\");\n    }\n    else if (isOperatorChar.test(ch)) {\n      stream.eatWhile(isOperatorChar);\n      return ret(\"operator\", null, stream.current());\n    }\n    else {\n    var word;\n    if(/[A-Z]/.test(ch))\n    {\n      stream.eatWhile(/[\\w_<>]/);\n      word = stream.current();\n      return ret(\"type\", \"variable-3\", word);\n    }\n    else\n    {\n        stream.eatWhile(/[\\w_]/);\n        var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word];\n        return (known && state.kwAllowed) ? ret(known.type, known.style, word) :\n                       ret(\"variable\", \"variable\", word);\n    }\n    }\n  }\n\n  function haxeTokenString(quote) {\n    return function(stream, state) {\n      if (!nextUntilUnescaped(stream, quote))\n        state.tokenize = haxeTokenBase;\n      return ret(\"string\", \"string\");\n    };\n  }\n\n  function haxeTokenComment(stream, state) {\n    var maybeEnd = false, ch;\n    while (ch = stream.next()) {\n      if (ch == \"/\" && maybeEnd) {\n        state.tokenize = haxeTokenBase;\n        break;\n      }\n      maybeEnd = (ch == \"*\");\n    }\n    return ret(\"comment\", \"comment\");\n  }\n\n  // Parser\n\n  var atomicTypes = {\"atom\": true, \"number\": true, \"variable\": true, \"string\": true, \"regexp\": true};\n\n  function HaxeLexical(indented, column, type, align, prev, info) {\n    this.indented = indented;\n    this.column = column;\n    this.type = type;\n    this.prev = prev;\n    this.info = info;\n    if (align != null) this.align = align;\n  }\n\n  function inScope(state, varname) {\n    for (var v = state.localVars; v; v = v.next)\n      if (v.name == varname) return true;\n  }\n\n  function parseHaxe(state, style, type, content, stream) {\n    var cc = state.cc;\n    // Communicate our context to the combinators.\n    // (Less wasteful than consing up a hundred closures on every call.)\n    cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc;\n\n    if (!state.lexical.hasOwnProperty(\"align\"))\n      state.lexical.align = true;\n\n    while(true) {\n      var combinator = cc.length ? cc.pop() : statement;\n      if (combinator(type, content)) {\n        while(cc.length && cc[cc.length - 1].lex)\n          cc.pop()();\n        if (cx.marked) return cx.marked;\n        if (type == \"variable\" && inScope(state, content)) return \"variable-2\";\n    if (type == \"variable\" && imported(state, content)) return \"variable-3\";\n        return style;\n      }\n    }\n  }\n\n  function imported(state, typename)\n  {\n  if (/[a-z]/.test(typename.charAt(0)))\n    return false;\n  var len = state.importedtypes.length;\n  for (var i = 0; i<len; i++)\n    if(state.importedtypes[i]==typename) return true;\n  }\n\n\n  function registerimport(importname) {\n  var state = cx.state;\n  for (var t = state.importedtypes; t; t = t.next)\n    if(t.name == importname) return;\n  state.importedtypes = { name: importname, next: state.importedtypes };\n  }\n  // Combinator utils\n\n  var cx = {state: null, column: null, marked: null, cc: null};\n  function pass() {\n    for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]);\n  }\n  function cont() {\n    pass.apply(null, arguments);\n    return true;\n  }\n  function register(varname) {\n    var state = cx.state;\n    if (state.context) {\n      cx.marked = \"def\";\n      for (var v = state.localVars; v; v = v.next)\n        if (v.name == varname) return;\n      state.localVars = {name: varname, next: state.localVars};\n    }\n  }\n\n  // Combinators\n\n  var defaultVars = {name: \"this\", next: null};\n  function pushcontext() {\n    if (!cx.state.context) cx.state.localVars = defaultVars;\n    cx.state.context = {prev: cx.state.context, vars: cx.state.localVars};\n  }\n  function popcontext() {\n    cx.state.localVars = cx.state.context.vars;\n    cx.state.context = cx.state.context.prev;\n  }\n  function pushlex(type, info) {\n    var result = function() {\n      var state = cx.state;\n      state.lexical = new HaxeLexical(state.indented, cx.stream.column(), type, null, state.lexical, info);\n    };\n    result.lex = true;\n    return result;\n  }\n  function poplex() {\n    var state = cx.state;\n    if (state.lexical.prev) {\n      if (state.lexical.type == \")\")\n        state.indented = state.lexical.indented;\n      state.lexical = state.lexical.prev;\n    }\n  }\n  poplex.lex = true;\n\n  function expect(wanted) {\n    function f(type) {\n      if (type == wanted) return cont();\n      else if (wanted == \";\") return pass();\n      else return cont(f);\n    };\n    return f;\n  }\n\n  function statement(type) {\n    if (type == \"@\") return cont(metadef);\n    if (type == \"var\") return cont(pushlex(\"vardef\"), vardef1, expect(\";\"), poplex);\n    if (type == \"keyword a\") return cont(pushlex(\"form\"), expression, statement, poplex);\n    if (type == \"keyword b\") return cont(pushlex(\"form\"), statement, poplex);\n    if (type == \"{\") return cont(pushlex(\"}\"), pushcontext, block, poplex, popcontext);\n    if (type == \";\") return cont();\n    if (type == \"attribute\") return cont(maybeattribute);\n    if (type == \"function\") return cont(functiondef);\n    if (type == \"for\") return cont(pushlex(\"form\"), expect(\"(\"), pushlex(\")\"), forspec1, expect(\")\"),\n                                      poplex, statement, poplex);\n    if (type == \"variable\") return cont(pushlex(\"stat\"), maybelabel);\n    if (type == \"switch\") return cont(pushlex(\"form\"), expression, pushlex(\"}\", \"switch\"), expect(\"{\"),\n                                         block, poplex, poplex);\n    if (type == \"case\") return cont(expression, expect(\":\"));\n    if (type == \"default\") return cont(expect(\":\"));\n    if (type == \"catch\") return cont(pushlex(\"form\"), pushcontext, expect(\"(\"), funarg, expect(\")\"),\n                                        statement, poplex, popcontext);\n    if (type == \"import\") return cont(importdef, expect(\";\"));\n    if (type == \"typedef\") return cont(typedef);\n    return pass(pushlex(\"stat\"), expression, expect(\";\"), poplex);\n  }\n  function expression(type) {\n    if (atomicTypes.hasOwnProperty(type)) return cont(maybeoperator);\n    if (type == \"function\") return cont(functiondef);\n    if (type == \"keyword c\") return cont(maybeexpression);\n    if (type == \"(\") return cont(pushlex(\")\"), maybeexpression, expect(\")\"), poplex, maybeoperator);\n    if (type == \"operator\") return cont(expression);\n    if (type == \"[\") return cont(pushlex(\"]\"), commasep(expression, \"]\"), poplex, maybeoperator);\n    if (type == \"{\") return cont(pushlex(\"}\"), commasep(objprop, \"}\"), poplex, maybeoperator);\n    return cont();\n  }\n  function maybeexpression(type) {\n    if (type.match(/[;\\}\\)\\],]/)) return pass();\n    return pass(expression);\n  }\n\n  function maybeoperator(type, value) {\n    if (type == \"operator\" && /\\+\\+|--/.test(value)) return cont(maybeoperator);\n    if (type == \"operator\" || type == \":\") return cont(expression);\n    if (type == \";\") return;\n    if (type == \"(\") return cont(pushlex(\")\"), commasep(expression, \")\"), poplex, maybeoperator);\n    if (type == \".\") return cont(property, maybeoperator);\n    if (type == \"[\") return cont(pushlex(\"]\"), expression, expect(\"]\"), poplex, maybeoperator);\n  }\n\n  function maybeattribute(type) {\n    if (type == \"attribute\") return cont(maybeattribute);\n    if (type == \"function\") return cont(functiondef);\n    if (type == \"var\") return cont(vardef1);\n  }\n\n  function metadef(type) {\n    if(type == \":\") return cont(metadef);\n    if(type == \"variable\") return cont(metadef);\n    if(type == \"(\") return cont(pushlex(\")\"), commasep(metaargs, \")\"), poplex, statement);\n  }\n  function metaargs(type) {\n    if(type == \"variable\") return cont();\n  }\n\n  function importdef (type, value) {\n  if(type == \"variable\" && /[A-Z]/.test(value.charAt(0))) { registerimport(value); return cont(); }\n  else if(type == \"variable\" || type == \"property\" || type == \".\" || value == \"*\") return cont(importdef);\n  }\n\n  function typedef (type, value)\n  {\n  if(type == \"variable\" && /[A-Z]/.test(value.charAt(0))) { registerimport(value); return cont(); }\n  else if (type == \"type\" && /[A-Z]/.test(value.charAt(0))) { return cont(); }\n  }\n\n  function maybelabel(type) {\n    if (type == \":\") return cont(poplex, statement);\n    return pass(maybeoperator, expect(\";\"), poplex);\n  }\n  function property(type) {\n    if (type == \"variable\") {cx.marked = \"property\"; return cont();}\n  }\n  function objprop(type) {\n    if (type == \"variable\") cx.marked = \"property\";\n    if (atomicTypes.hasOwnProperty(type)) return cont(expect(\":\"), expression);\n  }\n  function commasep(what, end) {\n    function proceed(type) {\n      if (type == \",\") return cont(what, proceed);\n      if (type == end) return cont();\n      return cont(expect(end));\n    }\n    return function(type) {\n      if (type == end) return cont();\n      else return pass(what, proceed);\n    };\n  }\n  function block(type) {\n    if (type == \"}\") return cont();\n    return pass(statement, block);\n  }\n  function vardef1(type, value) {\n    if (type == \"variable\"){register(value); return cont(typeuse, vardef2);}\n    return cont();\n  }\n  function vardef2(type, value) {\n    if (value == \"=\") return cont(expression, vardef2);\n    if (type == \",\") return cont(vardef1);\n  }\n  function forspec1(type, value) {\n  if (type == \"variable\") {\n    register(value);\n  }\n  return cont(pushlex(\")\"), pushcontext, forin, expression, poplex, statement, popcontext);\n  }\n  function forin(_type, value) {\n    if (value == \"in\") return cont();\n  }\n  function functiondef(type, value) {\n    if (type == \"variable\") {register(value); return cont(functiondef);}\n    if (value == \"new\") return cont(functiondef);\n    if (type == \"(\") return cont(pushlex(\")\"), pushcontext, commasep(funarg, \")\"), poplex, typeuse, statement, popcontext);\n  }\n  function typeuse(type) {\n    if(type == \":\") return cont(typestring);\n  }\n  function typestring(type) {\n    if(type == \"type\") return cont();\n    if(type == \"variable\") return cont();\n    if(type == \"{\") return cont(pushlex(\"}\"), commasep(typeprop, \"}\"), poplex);\n  }\n  function typeprop(type) {\n    if(type == \"variable\") return cont(typeuse);\n  }\n  function funarg(type, value) {\n    if (type == \"variable\") {register(value); return cont(typeuse);}\n  }\n\n  // Interface\n\n  return {\n    startState: function(basecolumn) {\n    var defaulttypes = [\"Int\", \"Float\", \"String\", \"Void\", \"Std\", \"Bool\", \"Dynamic\", \"Array\"];\n      return {\n        tokenize: haxeTokenBase,\n        reAllowed: true,\n        kwAllowed: true,\n        cc: [],\n        lexical: new HaxeLexical((basecolumn || 0) - indentUnit, 0, \"block\", false),\n        localVars: parserConfig.localVars,\n    importedtypes: defaulttypes,\n        context: parserConfig.localVars && {vars: parserConfig.localVars},\n        indented: 0\n      };\n    },\n\n    token: function(stream, state) {\n      if (stream.sol()) {\n        if (!state.lexical.hasOwnProperty(\"align\"))\n          state.lexical.align = false;\n        state.indented = stream.indentation();\n      }\n      if (stream.eatSpace()) return null;\n      var style = state.tokenize(stream, state);\n      if (type == \"comment\") return style;\n      state.reAllowed = !!(type == \"operator\" || type == \"keyword c\" || type.match(/^[\\[{}\\(,;:]$/));\n      state.kwAllowed = type != '.';\n      return parseHaxe(state, style, type, content, stream);\n    },\n\n    indent: function(state, textAfter) {\n      if (state.tokenize != haxeTokenBase) return 0;\n      var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical;\n      if (lexical.type == \"stat\" && firstChar == \"}\") lexical = lexical.prev;\n      var type = lexical.type, closing = firstChar == type;\n      if (type == \"vardef\") return lexical.indented + 4;\n      else if (type == \"form\" && firstChar == \"{\") return lexical.indented;\n      else if (type == \"stat\" || type == \"form\") return lexical.indented + indentUnit;\n      else if (lexical.info == \"switch\" && !closing)\n        return lexical.indented + (/^(?:case|default)\\b/.test(textAfter) ? indentUnit : 2 * indentUnit);\n      else if (lexical.align) return lexical.column + (closing ? 0 : 1);\n      else return lexical.indented + (closing ? 0 : indentUnit);\n    },\n\n    electricChars: \"{}\",\n    blockCommentStart: \"/*\",\n    blockCommentEnd: \"*/\",\n    lineComment: \"//\"\n  };\n});\n\nCodeMirror.defineMIME(\"text/x-haxe\", \"haxe\");\n\nCodeMirror.defineMode(\"hxml\", function () {\n\n  return {\n    startState: function () {\n      return {\n        define: false,\n        inString: false\n      };\n    },\n    token: function (stream, state) {\n      var ch = stream.peek();\n      var sol = stream.sol();\n\n      ///* comments */\n      if (ch == \"#\") {\n        stream.skipToEnd();\n        return \"comment\";\n      }\n      if (sol && ch == \"-\") {\n        var style = \"variable-2\";\n\n        stream.eat(/-/);\n\n        if (stream.peek() == \"-\") {\n          stream.eat(/-/);\n          style = \"keyword a\";\n        }\n\n        if (stream.peek() == \"D\") {\n          stream.eat(/[D]/);\n          style = \"keyword c\";\n          state.define = true;\n        }\n\n        stream.eatWhile(/[A-Z]/i);\n        return style;\n      }\n\n      var ch = stream.peek();\n\n      if (state.inString == false && ch == \"'\") {\n        state.inString = true;\n        ch = stream.next();\n      }\n\n      if (state.inString == true) {\n        if (stream.skipTo(\"'\")) {\n\n        } else {\n          stream.skipToEnd();\n        }\n\n        if (stream.peek() == \"'\") {\n          stream.next();\n          state.inString = false;\n        }\n\n        return \"string\";\n      }\n\n      stream.next();\n      return null;\n    },\n    lineComment: \"#\"\n  };\n});\n\nCodeMirror.defineMIME(\"text/x-hxml\", \"hxml\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/haxe/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Haxe mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"haxe.js\"></script>\n<style type=\"text/css\">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Haxe</a>\n  </ul>\n</div>\n\n<article>\n<h2>Haxe mode</h2>\n\n\n<div><p><textarea id=\"code-haxe\" name=\"code\">\nimport one.two.Three;\n\n@attr(\"test\")\nclass Foo&lt;T&gt; extends Three\n{\n\tpublic function new()\n\t{\n\t\tnoFoo = 12;\n\t}\n\t\n\tpublic static inline function doFoo(obj:{k:Int, l:Float}):Int\n\t{\n\t\tfor(i in 0...10)\n\t\t{\n\t\t\tobj.k++;\n\t\t\ttrace(i);\n\t\t\tvar var1 = new Array();\n\t\t\tif(var1.length > 1)\n\t\t\t\tthrow \"Error\";\n\t\t}\n\t\t// The following line should not be colored, the variable is scoped out\n\t\tvar1;\n\t\t/* Multi line\n\t\t * Comment test\n\t\t */\n\t\treturn obj.k;\n\t}\n\tprivate function bar():Void\n\t{\n\t\t#if flash\n\t\tvar t1:String = \"1.21\";\n\t\t#end\n\t\ttry {\n\t\t\tdoFoo({k:3, l:1.2});\n\t\t}\n\t\tcatch (e : String) {\n\t\t\ttrace(e);\n\t\t}\n\t\tvar t2:Float = cast(3.2);\n\t\tvar t3:haxe.Timer = new haxe.Timer();\n\t\tvar t4 = {k:Std.int(t2), l:Std.parseFloat(t1)};\n\t\tvar t5 = ~/123+.*$/i;\n\t\tdoFoo(t4);\n\t\tuntyped t1 = 4;\n\t\tbob = new Foo&lt;Int&gt;\n\t}\n\tpublic var okFoo(default, never):Float;\n\tvar noFoo(getFoo, null):Int;\n\tfunction getFoo():Int {\n\t\treturn noFoo;\n\t}\n\t\n\tpublic var three:Int;\n}\nenum Color\n{\n\tred;\n\tgreen;\n\tblue;\n\tgrey( v : Int );\n\trgb (r:Int,g:Int,b:Int);\n}\n</textarea></p>\n\n<p>Hxml mode:</p>\n\n<p><textarea id=\"code-hxml\">\n-cp test\n-js path/to/file.js\n#-remap nme:flash\n--next\n-D source-map-content\n-cmd 'test'\n-lib lime\n</textarea></p>\n</div>\n\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code-haxe\"), {\n      \tmode: \"haxe\",\n        lineNumbers: true,\n        indentUnit: 4,\n        indentWithTabs: true\n      });\n      \n      editor = CodeMirror.fromTextArea(document.getElementById(\"code-hxml\"), {\n      \tmode: \"hxml\",\n        lineNumbers: true,\n        indentUnit: 4,\n        indentWithTabs: true\n      });\n    </script>\n\n    <p><strong>MIME types defined:</strong> <code>text/x-haxe, text/x-hxml</code>.</p>\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/htmlembedded/htmlembedded.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"), require(\"../htmlmixed/htmlmixed\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\", \"../htmlmixed/htmlmixed\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"htmlembedded\", function(config, parserConfig) {\n\n  //config settings\n  var scriptStartRegex = parserConfig.scriptStartRegex || /^<%/i,\n      scriptEndRegex = parserConfig.scriptEndRegex || /^%>/i;\n\n  //inner modes\n  var scriptingMode, htmlMixedMode;\n\n  //tokenizer when in html mode\n  function htmlDispatch(stream, state) {\n      if (stream.match(scriptStartRegex, false)) {\n          state.token=scriptingDispatch;\n          return scriptingMode.token(stream, state.scriptState);\n          }\n      else\n          return htmlMixedMode.token(stream, state.htmlState);\n    }\n\n  //tokenizer when in scripting mode\n  function scriptingDispatch(stream, state) {\n      if (stream.match(scriptEndRegex, false))  {\n          state.token=htmlDispatch;\n          return htmlMixedMode.token(stream, state.htmlState);\n         }\n      else\n          return scriptingMode.token(stream, state.scriptState);\n         }\n\n\n  return {\n    startState: function() {\n      scriptingMode = scriptingMode || CodeMirror.getMode(config, parserConfig.scriptingModeSpec);\n      htmlMixedMode = htmlMixedMode || CodeMirror.getMode(config, \"htmlmixed\");\n      return {\n          token :  parserConfig.startOpen ? scriptingDispatch : htmlDispatch,\n          htmlState : CodeMirror.startState(htmlMixedMode),\n          scriptState : CodeMirror.startState(scriptingMode)\n      };\n    },\n\n    token: function(stream, state) {\n      return state.token(stream, state);\n    },\n\n    indent: function(state, textAfter) {\n      if (state.token == htmlDispatch)\n        return htmlMixedMode.indent(state.htmlState, textAfter);\n      else if (scriptingMode.indent)\n        return scriptingMode.indent(state.scriptState, textAfter);\n    },\n\n    copyState: function(state) {\n      return {\n       token : state.token,\n       htmlState : CodeMirror.copyState(htmlMixedMode, state.htmlState),\n       scriptState : CodeMirror.copyState(scriptingMode, state.scriptState)\n      };\n    },\n\n    innerMode: function(state) {\n      if (state.token == scriptingDispatch) return {state: state.scriptState, mode: scriptingMode};\n      else return {state: state.htmlState, mode: htmlMixedMode};\n    }\n  };\n}, \"htmlmixed\");\n\nCodeMirror.defineMIME(\"application/x-ejs\", { name: \"htmlembedded\", scriptingModeSpec:\"javascript\"});\nCodeMirror.defineMIME(\"application/x-aspx\", { name: \"htmlembedded\", scriptingModeSpec:\"text/x-csharp\"});\nCodeMirror.defineMIME(\"application/x-jsp\", { name: \"htmlembedded\", scriptingModeSpec:\"text/x-java\"});\nCodeMirror.defineMIME(\"application/x-erb\", { name: \"htmlembedded\", scriptingModeSpec:\"ruby\"});\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/htmlembedded/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Html Embedded Scripts mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"../xml/xml.js\"></script>\n<script src=\"../javascript/javascript.js\"></script>\n<script src=\"../css/css.js\"></script>\n<script src=\"../htmlmixed/htmlmixed.js\"></script>\n<script src=\"htmlembedded.js\"></script>\n<style type=\"text/css\">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Html Embedded Scripts</a>\n  </ul>\n</div>\n\n<article>\n<h2>Html Embedded Scripts mode</h2>\n<form><textarea id=\"code\" name=\"code\">\n<%\nfunction hello(who) {\n\treturn \"Hello \" + who;\n}\n%>\nThis is an example of EJS (embedded javascript)\n<p>The program says <%= hello(\"world\") %>.</p>\n<script>\n\talert(\"And here is some normal JS code\"); // also colored\n</script>\n</textarea></form>\n\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        lineNumbers: true,\n        mode: \"application/x-ejs\",\n        indentUnit: 4,\n        indentWithTabs: true\n      });\n    </script>\n\n    <p>Mode for html embedded scripts like JSP and ASP.NET. Depends on HtmlMixed which in turn depends on\n    JavaScript, CSS and XML.<br />Other dependancies include those of the scriping language chosen.</p>\n\n    <p><strong>MIME types defined:</strong> <code>application/x-aspx</code> (ASP.NET), \n    <code>application/x-ejs</code> (Embedded Javascript), <code>application/x-jsp</code> (JavaServer Pages)</p>\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/htmlmixed/htmlmixed.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"), require(\"../xml/xml\"), require(\"../javascript/javascript\"), require(\"../css/css\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\", \"../xml/xml\", \"../javascript/javascript\", \"../css/css\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"htmlmixed\", function(config, parserConfig) {\n  var htmlMode = CodeMirror.getMode(config, {name: \"xml\",\n                                             htmlMode: true,\n                                             multilineTagIndentFactor: parserConfig.multilineTagIndentFactor,\n                                             multilineTagIndentPastTag: parserConfig.multilineTagIndentPastTag});\n  var cssMode = CodeMirror.getMode(config, \"css\");\n\n  var scriptTypes = [], scriptTypesConf = parserConfig && parserConfig.scriptTypes;\n  scriptTypes.push({matches: /^(?:text|application)\\/(?:x-)?(?:java|ecma)script$|^$/i,\n                    mode: CodeMirror.getMode(config, \"javascript\")});\n  if (scriptTypesConf) for (var i = 0; i < scriptTypesConf.length; ++i) {\n    var conf = scriptTypesConf[i];\n    scriptTypes.push({matches: conf.matches, mode: conf.mode && CodeMirror.getMode(config, conf.mode)});\n  }\n  scriptTypes.push({matches: /./,\n                    mode: CodeMirror.getMode(config, \"text/plain\")});\n\n  function html(stream, state) {\n    var tagName = state.htmlState.tagName;\n    if (tagName) tagName = tagName.toLowerCase();\n    var style = htmlMode.token(stream, state.htmlState);\n    if (tagName == \"script\" && /\\btag\\b/.test(style) && stream.current() == \">\") {\n      // Script block: mode to change to depends on type attribute\n      var scriptType = stream.string.slice(Math.max(0, stream.pos - 100), stream.pos).match(/\\btype\\s*=\\s*(\"[^\"]+\"|'[^']+'|\\S+)[^<]*$/i);\n      scriptType = scriptType ? scriptType[1] : \"\";\n      if (scriptType && /[\\\"\\']/.test(scriptType.charAt(0))) scriptType = scriptType.slice(1, scriptType.length - 1);\n      for (var i = 0; i < scriptTypes.length; ++i) {\n        var tp = scriptTypes[i];\n        if (typeof tp.matches == \"string\" ? scriptType == tp.matches : tp.matches.test(scriptType)) {\n          if (tp.mode) {\n            state.token = script;\n            state.localMode = tp.mode;\n            state.localState = tp.mode.startState && tp.mode.startState(htmlMode.indent(state.htmlState, \"\"));\n          }\n          break;\n        }\n      }\n    } else if (tagName == \"style\" && /\\btag\\b/.test(style) && stream.current() == \">\") {\n      state.token = css;\n      state.localMode = cssMode;\n      state.localState = cssMode.startState(htmlMode.indent(state.htmlState, \"\"));\n    }\n    return style;\n  }\n  function maybeBackup(stream, pat, style) {\n    var cur = stream.current();\n    var close = cur.search(pat), m;\n    if (close > -1) stream.backUp(cur.length - close);\n    else if (m = cur.match(/<\\/?$/)) {\n      stream.backUp(cur.length);\n      if (!stream.match(pat, false)) stream.match(cur);\n    }\n    return style;\n  }\n  function script(stream, state) {\n    if (stream.match(/^<\\/\\s*script\\s*>/i, false)) {\n      state.token = html;\n      state.localState = state.localMode = null;\n      return null;\n    }\n    return maybeBackup(stream, /<\\/\\s*script\\s*>/,\n                       state.localMode.token(stream, state.localState));\n  }\n  function css(stream, state) {\n    if (stream.match(/^<\\/\\s*style\\s*>/i, false)) {\n      state.token = html;\n      state.localState = state.localMode = null;\n      return null;\n    }\n    return maybeBackup(stream, /<\\/\\s*style\\s*>/,\n                       cssMode.token(stream, state.localState));\n  }\n\n  return {\n    startState: function() {\n      var state = htmlMode.startState();\n      return {token: html, localMode: null, localState: null, htmlState: state};\n    },\n\n    copyState: function(state) {\n      if (state.localState)\n        var local = CodeMirror.copyState(state.localMode, state.localState);\n      return {token: state.token, localMode: state.localMode, localState: local,\n              htmlState: CodeMirror.copyState(htmlMode, state.htmlState)};\n    },\n\n    token: function(stream, state) {\n      return state.token(stream, state);\n    },\n\n    indent: function(state, textAfter) {\n      if (!state.localMode || /^\\s*<\\//.test(textAfter))\n        return htmlMode.indent(state.htmlState, textAfter);\n      else if (state.localMode.indent)\n        return state.localMode.indent(state.localState, textAfter);\n      else\n        return CodeMirror.Pass;\n    },\n\n    innerMode: function(state) {\n      return {state: state.localState || state.htmlState, mode: state.localMode || htmlMode};\n    }\n  };\n}, \"xml\", \"javascript\", \"css\");\n\nCodeMirror.defineMIME(\"text/html\", \"htmlmixed\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/htmlmixed/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: HTML mixed mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"../../addon/selection/selection-pointer.js\"></script>\n<script src=\"../xml/xml.js\"></script>\n<script src=\"../javascript/javascript.js\"></script>\n<script src=\"../css/css.js\"></script>\n<script src=\"../vbscript/vbscript.js\"></script>\n<script src=\"htmlmixed.js\"></script>\n<style>.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">HTML mixed</a>\n  </ul>\n</div>\n\n<article>\n<h2>HTML mixed mode</h2>\n<form><textarea id=\"code\" name=\"code\">\n<html style=\"color: green\">\n  <!-- this is a comment -->\n  <head>\n    <title>Mixed HTML Example</title>\n    <style type=\"text/css\">\n      h1 {font-family: comic sans; color: #f0f;}\n      div {background: yellow !important;}\n      body {\n        max-width: 50em;\n        margin: 1em 2em 1em 5em;\n      }\n    </style>\n  </head>\n  <body>\n    <h1>Mixed HTML Example</h1>\n    <script>\n      function jsFunc(arg1, arg2) {\n        if (arg1 && arg2) document.body.innerHTML = \"achoo\";\n      }\n    </script>\n  </body>\n</html>\n</textarea></form>\n    <script>\n      // Define an extended mixed-mode that understands vbscript and\n      // leaves mustache/handlebars embedded templates in html mode\n      var mixedMode = {\n        name: \"htmlmixed\",\n        scriptTypes: [{matches: /\\/x-handlebars-template|\\/x-mustache/i,\n                       mode: null},\n                      {matches: /(text|application)\\/(x-)?vb(a|script)/i,\n                       mode: \"vbscript\"}]\n      };\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        mode: mixedMode,\n        selectionPointer: true\n      });\n    </script>\n\n    <p>The HTML mixed mode depends on the XML, JavaScript, and CSS modes.</p>\n\n    <p>It takes an optional mode configuration\n    option, <code>scriptTypes</code>, which can be used to add custom\n    behavior for specific <code>&lt;script type=\"...\"></code> tags. If\n    given, it should hold an array of <code>{matches, mode}</code>\n    objects, where <code>matches</code> is a string or regexp that\n    matches the script type, and <code>mode</code> is\n    either <code>null</code>, for script types that should stay in\n    HTML mode, or a <a href=\"../../doc/manual.html#option_mode\">mode\n    spec</a> corresponding to the mode that should be used for the\n    script.</p>\n\n    <p><strong>MIME types defined:</strong> <code>text/html</code>\n    (redefined, only takes effect if you load this parser after the\n    XML parser).</p>\n\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/http/http.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"http\", function() {\n  function failFirstLine(stream, state) {\n    stream.skipToEnd();\n    state.cur = header;\n    return \"error\";\n  }\n\n  function start(stream, state) {\n    if (stream.match(/^HTTP\\/\\d\\.\\d/)) {\n      state.cur = responseStatusCode;\n      return \"keyword\";\n    } else if (stream.match(/^[A-Z]+/) && /[ \\t]/.test(stream.peek())) {\n      state.cur = requestPath;\n      return \"keyword\";\n    } else {\n      return failFirstLine(stream, state);\n    }\n  }\n\n  function responseStatusCode(stream, state) {\n    var code = stream.match(/^\\d+/);\n    if (!code) return failFirstLine(stream, state);\n\n    state.cur = responseStatusText;\n    var status = Number(code[0]);\n    if (status >= 100 && status < 200) {\n      return \"positive informational\";\n    } else if (status >= 200 && status < 300) {\n      return \"positive success\";\n    } else if (status >= 300 && status < 400) {\n      return \"positive redirect\";\n    } else if (status >= 400 && status < 500) {\n      return \"negative client-error\";\n    } else if (status >= 500 && status < 600) {\n      return \"negative server-error\";\n    } else {\n      return \"error\";\n    }\n  }\n\n  function responseStatusText(stream, state) {\n    stream.skipToEnd();\n    state.cur = header;\n    return null;\n  }\n\n  function requestPath(stream, state) {\n    stream.eatWhile(/\\S/);\n    state.cur = requestProtocol;\n    return \"string-2\";\n  }\n\n  function requestProtocol(stream, state) {\n    if (stream.match(/^HTTP\\/\\d\\.\\d$/)) {\n      state.cur = header;\n      return \"keyword\";\n    } else {\n      return failFirstLine(stream, state);\n    }\n  }\n\n  function header(stream) {\n    if (stream.sol() && !stream.eat(/[ \\t]/)) {\n      if (stream.match(/^.*?:/)) {\n        return \"atom\";\n      } else {\n        stream.skipToEnd();\n        return \"error\";\n      }\n    } else {\n      stream.skipToEnd();\n      return \"string\";\n    }\n  }\n\n  function body(stream) {\n    stream.skipToEnd();\n    return null;\n  }\n\n  return {\n    token: function(stream, state) {\n      var cur = state.cur;\n      if (cur != header && cur != body && stream.eatSpace()) return null;\n      return cur(stream, state);\n    },\n\n    blankLine: function(state) {\n      state.cur = body;\n    },\n\n    startState: function() {\n      return {cur: start};\n    }\n  };\n});\n\nCodeMirror.defineMIME(\"message/http\", \"http\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/http/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: HTTP mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"http.js\"></script>\n<style type=\"text/css\">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">HTTP</a>\n  </ul>\n</div>\n\n<article>\n<h2>HTTP mode</h2>\n\n\n<div><textarea id=\"code\" name=\"code\">\nPOST /somewhere HTTP/1.1\nHost: example.com\nIf-Modified-Since: Sat, 29 Oct 1994 19:43:31 GMT\nContent-Type: application/x-www-form-urlencoded;\n\tcharset=utf-8\nUser-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.11 (KHTML, like Gecko) Ubuntu/12.04 Chromium/20.0.1132.47 Chrome/20.0.1132.47 Safari/536.11\n\nThis is the request body!\n</textarea></div>\n\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {});\n    </script>\n\n    <p><strong>MIME types defined:</strong> <code>message/http</code>.</p>\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/idl/idl.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n\n  function wordRegexp(words) {\n    return new RegExp('^((' + words.join(')|(') + '))\\\\b', 'i');\n  };\n\n  var builtinArray = [\n    'a_correlate', 'abs', 'acos', 'adapt_hist_equal', 'alog',\n    'alog2', 'alog10', 'amoeba', 'annotate', 'app_user_dir',\n    'app_user_dir_query', 'arg_present', 'array_equal', 'array_indices',\n    'arrow', 'ascii_template', 'asin', 'assoc', 'atan',\n    'axis', 'axis', 'bandpass_filter', 'bandreject_filter', 'barplot',\n    'bar_plot', 'beseli', 'beselj', 'beselk', 'besely',\n    'beta', 'biginteger', 'bilinear', 'bin_date', 'binary_template',\n    'bindgen', 'binomial', 'bit_ffs', 'bit_population', 'blas_axpy',\n    'blk_con', 'boolarr', 'boolean', 'boxplot', 'box_cursor',\n    'breakpoint', 'broyden', 'bubbleplot', 'butterworth', 'bytarr',\n    'byte', 'byteorder', 'bytscl', 'c_correlate', 'calendar',\n    'caldat', 'call_external', 'call_function', 'call_method',\n    'call_procedure', 'canny', 'catch', 'cd', 'cdf', 'ceil',\n    'chebyshev', 'check_math', 'chisqr_cvf', 'chisqr_pdf', 'choldc',\n    'cholsol', 'cindgen', 'cir_3pnt', 'clipboard', 'close',\n    'clust_wts', 'cluster', 'cluster_tree', 'cmyk_convert', 'code_coverage',\n    'color_convert', 'color_exchange', 'color_quan', 'color_range_map',\n    'colorbar', 'colorize_sample', 'colormap_applicable',\n    'colormap_gradient', 'colormap_rotation', 'colortable',\n    'comfit', 'command_line_args', 'common', 'compile_opt', 'complex',\n    'complexarr', 'complexround', 'compute_mesh_normals', 'cond', 'congrid',\n    'conj', 'constrained_min', 'contour', 'contour', 'convert_coord',\n    'convol', 'convol_fft', 'coord2to3', 'copy_lun', 'correlate',\n    'cos', 'cosh', 'cpu', 'cramer', 'createboxplotdata',\n    'create_cursor', 'create_struct', 'create_view', 'crossp', 'crvlength',\n    'ct_luminance', 'cti_test', 'cursor', 'curvefit', 'cv_coord',\n    'cvttobm', 'cw_animate', 'cw_animate_getp', 'cw_animate_load',\n    'cw_animate_run', 'cw_arcball', 'cw_bgroup', 'cw_clr_index',\n    'cw_colorsel', 'cw_defroi', 'cw_field', 'cw_filesel', 'cw_form',\n    'cw_fslider', 'cw_light_editor', 'cw_light_editor_get',\n    'cw_light_editor_set', 'cw_orient', 'cw_palette_editor',\n    'cw_palette_editor_get', 'cw_palette_editor_set', 'cw_pdmenu',\n    'cw_rgbslider', 'cw_tmpl', 'cw_zoom', 'db_exists',\n    'dblarr', 'dcindgen', 'dcomplex', 'dcomplexarr', 'define_key',\n    'define_msgblk', 'define_msgblk_from_file', 'defroi', 'defsysv',\n    'delvar', 'dendro_plot', 'dendrogram', 'deriv', 'derivsig',\n    'determ', 'device', 'dfpmin', 'diag_matrix', 'dialog_dbconnect',\n    'dialog_message', 'dialog_pickfile', 'dialog_printersetup',\n    'dialog_printjob', 'dialog_read_image',\n    'dialog_write_image', 'dictionary', 'digital_filter', 'dilate', 'dindgen',\n    'dissolve', 'dist', 'distance_measure', 'dlm_load', 'dlm_register',\n    'doc_library', 'double', 'draw_roi', 'edge_dog', 'efont',\n    'eigenql', 'eigenvec', 'ellipse', 'elmhes', 'emboss',\n    'empty', 'enable_sysrtn', 'eof', 'eos', 'erase',\n    'erf', 'erfc', 'erfcx', 'erode', 'errorplot',\n    'errplot', 'estimator_filter', 'execute', 'exit', 'exp',\n    'expand', 'expand_path', 'expint', 'extrac', 'extract_slice',\n    'f_cvf', 'f_pdf', 'factorial', 'fft', 'file_basename',\n    'file_chmod', 'file_copy', 'file_delete', 'file_dirname',\n    'file_expand_path', 'file_gunzip', 'file_gzip', 'file_info',\n    'file_lines', 'file_link', 'file_mkdir', 'file_move',\n    'file_poll_input', 'file_readlink', 'file_same',\n    'file_search', 'file_tar', 'file_test', 'file_untar', 'file_unzip',\n    'file_which', 'file_zip', 'filepath', 'findgen', 'finite',\n    'fix', 'flick', 'float', 'floor', 'flow3',\n    'fltarr', 'flush', 'format_axis_values', 'forward_function', 'free_lun',\n    'fstat', 'fulstr', 'funct', 'function', 'fv_test',\n    'fx_root', 'fz_roots', 'gamma', 'gamma_ct', 'gauss_cvf',\n    'gauss_pdf', 'gauss_smooth', 'gauss2dfit', 'gaussfit',\n    'gaussian_function', 'gaussint', 'get_drive_list', 'get_dxf_objects',\n    'get_kbrd', 'get_login_info',\n    'get_lun', 'get_screen_size', 'getenv', 'getwindows', 'greg2jul',\n    'grib', 'grid_input', 'grid_tps', 'grid3', 'griddata',\n    'gs_iter', 'h_eq_ct', 'h_eq_int', 'hanning', 'hash',\n    'hdf', 'hdf5', 'heap_free', 'heap_gc', 'heap_nosave',\n    'heap_refcount', 'heap_save', 'help', 'hilbert', 'hist_2d',\n    'hist_equal', 'histogram', 'hls', 'hough', 'hqr',\n    'hsv', 'i18n_multibytetoutf8',\n    'i18n_multibytetowidechar', 'i18n_utf8tomultibyte',\n    'i18n_widechartomultibyte',\n    'ibeta', 'icontour', 'iconvertcoord', 'idelete', 'identity',\n    'idl_base64', 'idl_container', 'idl_validname',\n    'idlexbr_assistant', 'idlitsys_createtool',\n    'idlunit', 'iellipse', 'igamma', 'igetcurrent', 'igetdata',\n    'igetid', 'igetproperty', 'iimage', 'image', 'image_cont',\n    'image_statistics', 'image_threshold', 'imaginary', 'imap', 'indgen',\n    'int_2d', 'int_3d', 'int_tabulated', 'intarr', 'interpol',\n    'interpolate', 'interval_volume', 'invert', 'ioctl', 'iopen',\n    'ir_filter', 'iplot', 'ipolygon', 'ipolyline', 'iputdata',\n    'iregister', 'ireset', 'iresolve', 'irotate', 'isa',\n    'isave', 'iscale', 'isetcurrent', 'isetproperty', 'ishft',\n    'isocontour', 'isosurface', 'isurface', 'itext', 'itranslate',\n    'ivector', 'ivolume', 'izoom', 'journal', 'json_parse',\n    'json_serialize', 'jul2greg', 'julday', 'keyword_set', 'krig2d',\n    'kurtosis', 'kw_test', 'l64indgen', 'la_choldc', 'la_cholmprove',\n    'la_cholsol', 'la_determ', 'la_eigenproblem', 'la_eigenql', 'la_eigenvec',\n    'la_elmhes', 'la_gm_linear_model', 'la_hqr', 'la_invert',\n    'la_least_square_equality', 'la_least_squares', 'la_linear_equation',\n    'la_ludc', 'la_lumprove', 'la_lusol',\n    'la_svd', 'la_tridc', 'la_trimprove', 'la_triql', 'la_trired',\n    'la_trisol', 'label_date', 'label_region', 'ladfit', 'laguerre',\n    'lambda', 'lambdap', 'lambertw', 'laplacian', 'least_squares_filter',\n    'leefilt', 'legend', 'legendre', 'linbcg', 'lindgen',\n    'linfit', 'linkimage', 'list', 'll_arc_distance', 'lmfit',\n    'lmgr', 'lngamma', 'lnp_test', 'loadct', 'locale_get',\n    'logical_and', 'logical_or', 'logical_true', 'lon64arr', 'lonarr',\n    'long', 'long64', 'lsode', 'lu_complex', 'ludc',\n    'lumprove', 'lusol', 'm_correlate', 'machar', 'make_array',\n    'make_dll', 'make_rt', 'map', 'mapcontinents', 'mapgrid',\n    'map_2points', 'map_continents', 'map_grid', 'map_image', 'map_patch',\n    'map_proj_forward', 'map_proj_image', 'map_proj_info',\n    'map_proj_init', 'map_proj_inverse',\n    'map_set', 'matrix_multiply', 'matrix_power', 'max', 'md_test',\n    'mean', 'meanabsdev', 'mean_filter', 'median', 'memory',\n    'mesh_clip', 'mesh_decimate', 'mesh_issolid',\n    'mesh_merge', 'mesh_numtriangles',\n    'mesh_obj', 'mesh_smooth', 'mesh_surfacearea',\n    'mesh_validate', 'mesh_volume',\n    'message', 'min', 'min_curve_surf', 'mk_html_help', 'modifyct',\n    'moment', 'morph_close', 'morph_distance',\n    'morph_gradient', 'morph_hitormiss',\n    'morph_open', 'morph_thin', 'morph_tophat', 'multi', 'n_elements',\n    'n_params', 'n_tags', 'ncdf', 'newton', 'noise_hurl',\n    'noise_pick', 'noise_scatter', 'noise_slur', 'norm', 'obj_class',\n    'obj_destroy', 'obj_hasmethod', 'obj_isa', 'obj_new', 'obj_valid',\n    'objarr', 'on_error', 'on_ioerror', 'online_help', 'openr',\n    'openu', 'openw', 'oplot', 'oploterr', 'orderedhash',\n    'p_correlate', 'parse_url', 'particle_trace', 'path_cache', 'path_sep',\n    'pcomp', 'plot', 'plot3d', 'plot', 'plot_3dbox',\n    'plot_field', 'ploterr', 'plots', 'polar_contour', 'polar_surface',\n    'polyfill', 'polyshade', 'pnt_line', 'point_lun', 'polarplot',\n    'poly', 'poly_2d', 'poly_area', 'poly_fit', 'polyfillv',\n    'polygon', 'polyline', 'polywarp', 'popd', 'powell',\n    'pref_commit', 'pref_get', 'pref_set', 'prewitt', 'primes',\n    'print', 'printf', 'printd', 'pro', 'product',\n    'profile', 'profiler', 'profiles', 'project_vol', 'ps_show_fonts',\n    'psafm', 'pseudo', 'ptr_free', 'ptr_new', 'ptr_valid',\n    'ptrarr', 'pushd', 'qgrid3', 'qhull', 'qromb',\n    'qromo', 'qsimp', 'query_*', 'query_ascii', 'query_bmp',\n    'query_csv', 'query_dicom', 'query_gif', 'query_image', 'query_jpeg',\n    'query_jpeg2000', 'query_mrsid', 'query_pict', 'query_png', 'query_ppm',\n    'query_srf', 'query_tiff', 'query_video', 'query_wav', 'r_correlate',\n    'r_test', 'radon', 'randomn', 'randomu', 'ranks',\n    'rdpix', 'read', 'readf', 'read_ascii', 'read_binary',\n    'read_bmp', 'read_csv', 'read_dicom', 'read_gif', 'read_image',\n    'read_interfile', 'read_jpeg', 'read_jpeg2000', 'read_mrsid', 'read_pict',\n    'read_png', 'read_ppm', 'read_spr', 'read_srf', 'read_sylk',\n    'read_tiff', 'read_video', 'read_wav', 'read_wave', 'read_x11_bitmap',\n    'read_xwd', 'reads', 'readu', 'real_part', 'rebin',\n    'recall_commands', 'recon3', 'reduce_colors', 'reform', 'region_grow',\n    'register_cursor', 'regress', 'replicate',\n    'replicate_inplace', 'resolve_all',\n    'resolve_routine', 'restore', 'retall', 'return', 'reverse',\n    'rk4', 'roberts', 'rot', 'rotate', 'round',\n    'routine_filepath', 'routine_info', 'rs_test', 's_test', 'save',\n    'savgol', 'scale3', 'scale3d', 'scatterplot', 'scatterplot3d',\n    'scope_level', 'scope_traceback', 'scope_varfetch',\n    'scope_varname', 'search2d',\n    'search3d', 'sem_create', 'sem_delete', 'sem_lock', 'sem_release',\n    'set_plot', 'set_shading', 'setenv', 'sfit', 'shade_surf',\n    'shade_surf_irr', 'shade_volume', 'shift', 'shift_diff', 'shmdebug',\n    'shmmap', 'shmunmap', 'shmvar', 'show3', 'showfont',\n    'signum', 'simplex', 'sin', 'sindgen', 'sinh',\n    'size', 'skewness', 'skip_lun', 'slicer3', 'slide_image',\n    'smooth', 'sobel', 'socket', 'sort', 'spawn',\n    'sph_4pnt', 'sph_scat', 'spher_harm', 'spl_init', 'spl_interp',\n    'spline', 'spline_p', 'sprsab', 'sprsax', 'sprsin',\n    'sprstp', 'sqrt', 'standardize', 'stddev', 'stop',\n    'strarr', 'strcmp', 'strcompress', 'streamline', 'streamline',\n    'stregex', 'stretch', 'string', 'strjoin', 'strlen',\n    'strlowcase', 'strmatch', 'strmessage', 'strmid', 'strpos',\n    'strput', 'strsplit', 'strtrim', 'struct_assign', 'struct_hide',\n    'strupcase', 'surface', 'surface', 'surfr', 'svdc',\n    'svdfit', 'svsol', 'swap_endian', 'swap_endian_inplace', 'symbol',\n    'systime', 't_cvf', 't_pdf', 't3d', 'tag_names',\n    'tan', 'tanh', 'tek_color', 'temporary', 'terminal_size',\n    'tetra_clip', 'tetra_surface', 'tetra_volume', 'text', 'thin',\n    'thread', 'threed', 'tic', 'time_test2', 'timegen',\n    'timer', 'timestamp', 'timestamptovalues', 'tm_test', 'toc',\n    'total', 'trace', 'transpose', 'tri_surf', 'triangulate',\n    'trigrid', 'triql', 'trired', 'trisol', 'truncate_lun',\n    'ts_coef', 'ts_diff', 'ts_fcast', 'ts_smooth', 'tv',\n    'tvcrs', 'tvlct', 'tvrd', 'tvscl', 'typename',\n    'uindgen', 'uint', 'uintarr', 'ul64indgen', 'ulindgen',\n    'ulon64arr', 'ulonarr', 'ulong', 'ulong64', 'uniq',\n    'unsharp_mask', 'usersym', 'value_locate', 'variance', 'vector',\n    'vector_field', 'vel', 'velovect', 'vert_t3d', 'voigt',\n    'volume', 'voronoi', 'voxel_proj', 'wait', 'warp_tri',\n    'watershed', 'wdelete', 'wf_draw', 'where', 'widget_base',\n    'widget_button', 'widget_combobox', 'widget_control',\n    'widget_displaycontextmenu', 'widget_draw',\n    'widget_droplist', 'widget_event', 'widget_info',\n    'widget_label', 'widget_list',\n    'widget_propertysheet', 'widget_slider', 'widget_tab',\n    'widget_table', 'widget_text',\n    'widget_tree', 'widget_tree_move', 'widget_window',\n    'wiener_filter', 'window',\n    'window', 'write_bmp', 'write_csv', 'write_gif', 'write_image',\n    'write_jpeg', 'write_jpeg2000', 'write_nrif', 'write_pict', 'write_png',\n    'write_ppm', 'write_spr', 'write_srf', 'write_sylk', 'write_tiff',\n    'write_video', 'write_wav', 'write_wave', 'writeu', 'wset',\n    'wshow', 'wtn', 'wv_applet', 'wv_cwt', 'wv_cw_wavelet',\n    'wv_denoise', 'wv_dwt', 'wv_fn_coiflet',\n    'wv_fn_daubechies', 'wv_fn_gaussian',\n    'wv_fn_haar', 'wv_fn_morlet', 'wv_fn_paul',\n    'wv_fn_symlet', 'wv_import_data',\n    'wv_import_wavelet', 'wv_plot3d_wps', 'wv_plot_multires',\n    'wv_pwt', 'wv_tool_denoise',\n    'xbm_edit', 'xdisplayfile', 'xdxf', 'xfont', 'xinteranimate',\n    'xloadct', 'xmanager', 'xmng_tmpl', 'xmtool', 'xobjview',\n    'xobjview_rotate', 'xobjview_write_image',\n    'xpalette', 'xpcolor', 'xplot3d',\n    'xregistered', 'xroi', 'xsq_test', 'xsurface', 'xvaredit',\n    'xvolume', 'xvolume_rotate', 'xvolume_write_image',\n    'xyouts', 'zlib_compress', 'zlib_uncompress', 'zoom', 'zoom_24'\n  ];\n  var builtins = wordRegexp(builtinArray);\n\n  var keywordArray = [\n    'begin', 'end', 'endcase', 'endfor',\n    'endwhile', 'endif', 'endrep', 'endforeach',\n    'break', 'case', 'continue', 'for',\n    'foreach', 'goto', 'if', 'then', 'else',\n    'repeat', 'until', 'switch', 'while',\n    'do', 'pro', 'function'\n  ];\n  var keywords = wordRegexp(keywordArray);\n\n  CodeMirror.registerHelper(\"hintWords\", \"idl\", builtinArray.concat(keywordArray));\n\n  var identifiers = new RegExp('^[_a-z\\xa1-\\uffff][_a-z0-9\\xa1-\\uffff]*', 'i');\n\n  var singleOperators = /[+\\-*&=<>\\/@#~$]/;\n  var boolOperators = new RegExp('(and|or|eq|lt|le|gt|ge|ne|not)', 'i');\n\n  function tokenBase(stream) {\n    // whitespaces\n    if (stream.eatSpace()) return null;\n\n    // Handle one line Comments\n    if (stream.match(';')) {\n      stream.skipToEnd();\n      return 'comment';\n    }\n\n    // Handle Number Literals\n    if (stream.match(/^[0-9\\.+-]/, false)) {\n      if (stream.match(/^[+-]?0x[0-9a-fA-F]+/))\n        return 'number';\n      if (stream.match(/^[+-]?\\d*\\.\\d+([EeDd][+-]?\\d+)?/))\n        return 'number';\n      if (stream.match(/^[+-]?\\d+([EeDd][+-]?\\d+)?/))\n        return 'number';\n    }\n\n    // Handle Strings\n    if (stream.match(/^\"([^\"]|(\"\"))*\"/)) { return 'string'; }\n    if (stream.match(/^'([^']|(''))*'/)) { return 'string'; }\n\n    // Handle words\n    if (stream.match(keywords)) { return 'keyword'; }\n    if (stream.match(builtins)) { return 'builtin'; }\n    if (stream.match(identifiers)) { return 'variable'; }\n\n    if (stream.match(singleOperators) || stream.match(boolOperators)) {\n      return 'operator'; }\n\n    // Handle non-detected items\n    stream.next();\n    return null;\n  };\n\n  CodeMirror.defineMode('idl', function() {\n    return {\n      token: function(stream) {\n        return tokenBase(stream);\n      }\n    };\n  });\n\n  CodeMirror.defineMIME('text/x-idl', 'idl');\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/idl/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: IDL mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"idl.js\"></script>\n<style type=\"text/css\">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">IDL</a>\n  </ul>\n</div>\n\n<article>\n<h2>IDL mode</h2>\n\n    <div><textarea id=\"code\" name=\"code\">\n;; Example IDL code\nFUNCTION mean_and_stddev,array\n  ;; This program reads in an array of numbers\n  ;; and returns a structure containing the\n  ;; average and standard deviation\n\n  ave = 0.0\n  count = 0.0\n\n  for i=0,N_ELEMENTS(array)-1 do begin\n      ave = ave + array[i]\n      count = count + 1\n  endfor\n  \n  ave = ave/count\n\n  std = stddev(array)  \n\n  return, {average:ave,std:std}\n\nEND\n\n    </textarea></div>\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        mode: {name: \"idl\",\n               version: 1,\n               singleLineStringErrors: false},\n        lineNumbers: true,\n        indentUnit: 4,\n        matchBrackets: true\n      });\n    </script>\n\n    <p><strong>MIME types defined:</strong> <code>text/x-idl</code>.</p>\n</article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Language Modes</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../doc/docs.css\">\n\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../index.html\">Home</a>\n    <li><a href=\"../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a class=active href=\"#\">Language modes</a>\n  </ul>\n</div>\n\n<article>\n\n  <h2>Language modes</h2>\n\n  <p>This is a list of every mode in the distribution. Each mode lives\nin a subdirectory of the <code>mode/</code> directory, and typically\ndefines a single JavaScript file that implements the mode. Loading\nsuch file will make the language available to CodeMirror, through\nthe <a href=\"../doc/manual.html#option_mode\"><code>mode</code></a>\noption.</p>\n\n  <div style=\"-webkit-columns: 100px 2; -moz-columns: 100px 2; columns: 100px 2;\">\n    <ul style=\"margin-top: 0\">\n      <li><a href=\"apl/index.html\">APL</a></li>\n      <li><a href=\"asterisk/index.html\">Asterisk dialplan</a></li>\n      <li><a href=\"clike/index.html\">C, C++, C#</a></li>\n      <li><a href=\"clojure/index.html\">Clojure</a></li>\n      <li><a href=\"cobol/index.html\">COBOL</a></li>\n      <li><a href=\"coffeescript/index.html\">CoffeeScript</a></li>\n      <li><a href=\"commonlisp/index.html\">Common Lisp</a></li>\n      <li><a href=\"css/index.html\">CSS</a></li>\n      <li><a href=\"cypher/index.html\">Cypher</a></li>\n      <li><a href=\"python/index.html\">Cython</a></li>\n      <li><a href=\"d/index.html\">D</a></li>\n      <li><a href=\"dart/index.html\">Dart</a></li>\n      <li><a href=\"django/index.html\">Django</a> (templating language)</li>\n      <li><a href=\"dockerfile/index.html\">Dockerfile</a></li>\n      <li><a href=\"diff/index.html\">diff</a></li>\n      <li><a href=\"dtd/index.html\">DTD</a></li>\n      <li><a href=\"dylan/index.html\">Dylan</a></li>\n      <li><a href=\"ebnf/index.html\">EBNF</a></li>\n      <li><a href=\"ecl/index.html\">ECL</a></li>\n      <li><a href=\"eiffel/index.html\">Eiffel</a></li>\n      <li><a href=\"erlang/index.html\">Erlang</a></li>\n      <li><a href=\"forth/index.html\">Forth</a></li>\n      <li><a href=\"fortran/index.html\">Fortran</a></li>\n      <li><a href=\"mllike/index.html\">F#</a></li>\n      <li><a href=\"gas/index.html\">Gas</a> (AT&amp;T-style assembly)</li>\n      <li><a href=\"gherkin/index.html\">Gherkin</a></li>\n      <li><a href=\"go/index.html\">Go</a></li>\n      <li><a href=\"groovy/index.html\">Groovy</a></li>\n      <li><a href=\"haml/index.html\">HAML</a></li>\n      <li><a href=\"haskell/index.html\">Haskell</a></li>\n      <li><a href=\"haxe/index.html\">Haxe</a></li>\n      <li><a href=\"htmlembedded/index.html\">HTML embedded scripts</a></li>\n      <li><a href=\"htmlmixed/index.html\">HTML mixed-mode</a></li>\n      <li><a href=\"http/index.html\">HTTP</a></li>\n      <li><a href=\"idl/index.html\">IDL</a></li>\n      <li><a href=\"clike/index.html\">Java</a></li>\n      <li><a href=\"jade/index.html\">Jade</a></li>\n      <li><a href=\"javascript/index.html\">JavaScript</a></li>\n      <li><a href=\"jinja2/index.html\">Jinja2</a></li>\n      <li><a href=\"julia/index.html\">Julia</a></li>\n      <li><a href=\"kotlin/index.html\">Kotlin</a></li>\n      <li><a href=\"css/less.html\">LESS</a></li>\n      <li><a href=\"livescript/index.html\">LiveScript</a></li>\n      <li><a href=\"lua/index.html\">Lua</a></li>\n      <li><a href=\"markdown/index.html\">Markdown</a> (<a href=\"gfm/index.html\">GitHub-flavour</a>)</li>\n      <li><a href=\"mirc/index.html\">mIRC</a></li>\n      <li><a href=\"modelica/index.html\">Modelica</a></li>\n      <li><a href=\"nginx/index.html\">Nginx</a></li>\n      <li><a href=\"ntriples/index.html\">NTriples</a></li>\n      <li><a href=\"clike/index.html\">Objective C</a></li>\n      <li><a href=\"mllike/index.html\">OCaml</a></li>\n      <li><a href=\"octave/index.html\">Octave</a> (MATLAB)</li>\n      <li><a href=\"pascal/index.html\">Pascal</a></li>\n      <li><a href=\"pegjs/index.html\">PEG.js</a></li>\n      <li><a href=\"perl/index.html\">Perl</a></li>\n      <li><a href=\"php/index.html\">PHP</a></li>\n      <li><a href=\"pig/index.html\">Pig Latin</a></li>\n      <li><a href=\"properties/index.html\">Properties files</a></li>\n      <li><a href=\"puppet/index.html\">Puppet</a></li>\n      <li><a href=\"python/index.html\">Python</a></li>\n      <li><a href=\"q/index.html\">Q</a></li>\n      <li><a href=\"r/index.html\">R</a></li>\n      <li><a href=\"rpm/index.html\">RPM</a></li>\n      <li><a href=\"rst/index.html\">reStructuredText</a></li>\n      <li><a href=\"ruby/index.html\">Ruby</a></li>\n      <li><a href=\"rust/index.html\">Rust</a></li>\n      <li><a href=\"sass/index.html\">Sass</a></li>\n      <li><a href=\"spreadsheet/index.html\">Spreadsheet</a></li>\n      <li><a href=\"clike/scala.html\">Scala</a></li>\n      <li><a href=\"scheme/index.html\">Scheme</a></li>\n      <li><a href=\"css/scss.html\">SCSS</a></li>\n      <li><a href=\"shell/index.html\">Shell</a></li>\n      <li><a href=\"sieve/index.html\">Sieve</a></li>\n      <li><a href=\"slim/index.html\">Slim</a></li>\n      <li><a href=\"smalltalk/index.html\">Smalltalk</a></li>\n      <li><a href=\"smarty/index.html\">Smarty</a></li>\n      <li><a href=\"smartymixed/index.html\">Smarty/HTML mixed</a></li>\n      <li><a href=\"solr/index.html\">Solr</a></li>\n      <li><a href=\"soy/index.html\">Soy</a></li>\n      <li><a href=\"stylus/index.html\">Stylus</a></li>\n      <li><a href=\"sql/index.html\">SQL</a> (several dialects)</li>\n      <li><a href=\"sparql/index.html\">SPARQL</a></li>\n      <li><a href=\"stex/index.html\">sTeX, LaTeX</a></li>\n      <li><a href=\"tcl/index.html\">Tcl</a></li>\n      <li><a href=\"textile/index.html\">Textile</a></li>\n      <li><a href=\"tiddlywiki/index.html\">Tiddlywiki</a></li>\n      <li><a href=\"tiki/index.html\">Tiki wiki</a></li>\n      <li><a href=\"toml/index.html\">TOML</a></li>\n      <li><a href=\"tornado/index.html\">Tornado</a> (templating language)</li>\n      <li><a href=\"turtle/index.html\">Turtle</a></li>\n      <li><a href=\"vb/index.html\">VB.NET</a></li>\n      <li><a href=\"vbscript/index.html\">VBScript</a></li>\n      <li><a href=\"velocity/index.html\">Velocity</a></li>\n      <li><a href=\"verilog/index.html\">Verilog/SystemVerilog</a></li>\n      <li><a href=\"xml/index.html\">XML/HTML</a></li>\n      <li><a href=\"xquery/index.html\">XQuery</a></li>\n      <li><a href=\"yaml/index.html\">YAML</a></li>\n      <li><a href=\"z80/index.html\">Z80</a></li>\n    </ul>\n  </div>\n\n</article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/jade/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Jade Templating Mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"../javascript/javascript.js\"></script>\n<script src=\"../css/css.js\"></script>\n<script src=\"../xml/xml.js\"></script>\n<script src=\"../htmlmixed/htmlmixed.js\"></script>\n<script src=\"jade.js\"></script>\n<style type=\"text/css\">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Jade Templating Mode</a>\n  </ul>\n</div>\n\n<article>\n<h2>Jade Templating Mode</h2>\n<form><textarea id=\"code\" name=\"code\">\ndoctype html\n  html\n    head\n      title= \"Jade Templating CodeMirror Mode Example\"\n      link(rel='stylesheet', href='/css/bootstrap.min.css')\n      link(rel='stylesheet', href='/css/index.css')\n      script(type='text/javascript', src='/js/jquery-1.9.1.min.js')\n      script(type='text/javascript', src='/js/bootstrap.min.js')\n    body\n      div.header\n        h1 Welcome to this Example\n      div.spots\n        if locals.spots\n          each spot in spots\n            div.spot.well\n         div\n           if spot.logo\n             img.img-rounded.logo(src=spot.logo)\n           else\n             img.img-rounded.logo(src=\"img/placeholder.png\")\n         h3\n           a(href=spot.hash) ##{spot.hash}\n           if spot.title\n             span.title #{spot.title}\n           if spot.desc\n             div #{spot.desc}\n        else\n          h3 There are no spots currently available.\n</textarea></form>\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        mode: {name: \"jade\", alignCDATA: true},\n        lineNumbers: true\n      });\n    </script>\n    <h3>The Jade Templating Mode</h3>\n      <p> Created by Forbes Lindesay. Managed as part of a Brackets extension at <a href=\"https://github.com/ForbesLindesay/jade-brackets\">https://github.com/ForbesLindesay/jade-brackets</a>.</p>\n    <p><strong>MIME type defined:</strong> <code>text/x-jade</code>.</p>\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/jade/jade.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"), require(\"../javascript/javascript\"), require(\"../css/css\"), require(\"../htmlmixed/htmlmixed\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\", \"../javascript/javascript\", \"../css/css\", \"../htmlmixed/htmlmixed\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode('jade', function (config) {\n  // token types\n  var KEYWORD = 'keyword';\n  var DOCTYPE = 'meta';\n  var ID = 'builtin';\n  var CLASS = 'qualifier';\n\n  var ATTRS_NEST = {\n    '{': '}',\n    '(': ')',\n    '[': ']'\n  };\n\n  var jsMode = CodeMirror.getMode(config, 'javascript');\n\n  function State() {\n    this.javaScriptLine = false;\n    this.javaScriptLineExcludesColon = false;\n\n    this.javaScriptArguments = false;\n    this.javaScriptArgumentsDepth = 0;\n\n    this.isInterpolating = false;\n    this.interpolationNesting = 0;\n\n    this.jsState = jsMode.startState();\n\n    this.restOfLine = '';\n\n    this.isIncludeFiltered = false;\n    this.isEach = false;\n\n    this.lastTag = '';\n    this.scriptType = '';\n\n    // Attributes Mode\n    this.isAttrs = false;\n    this.attrsNest = [];\n    this.inAttributeName = true;\n    this.attributeIsType = false;\n    this.attrValue = '';\n\n    // Indented Mode\n    this.indentOf = Infinity;\n    this.indentToken = '';\n\n    this.innerMode = null;\n    this.innerState = null;\n\n    this.innerModeForLine = false;\n  }\n  /**\n   * Safely copy a state\n   *\n   * @return {State}\n   */\n  State.prototype.copy = function () {\n    var res = new State();\n    res.javaScriptLine = this.javaScriptLine;\n    res.javaScriptLineExcludesColon = this.javaScriptLineExcludesColon;\n    res.javaScriptArguments = this.javaScriptArguments;\n    res.javaScriptArgumentsDepth = this.javaScriptArgumentsDepth;\n    res.isInterpolating = this.isInterpolating;\n    res.interpolationNesting = this.intpolationNesting;\n\n    res.jsState = CodeMirror.copyState(jsMode, this.jsState);\n\n    res.innerMode = this.innerMode;\n    if (this.innerMode && this.innerState) {\n      res.innerState = CodeMirror.copyState(this.innerMode, this.innerState);\n    }\n\n    res.restOfLine = this.restOfLine;\n\n    res.isIncludeFiltered = this.isIncludeFiltered;\n    res.isEach = this.isEach;\n    res.lastTag = this.lastTag;\n    res.scriptType = this.scriptType;\n    res.isAttrs = this.isAttrs;\n    res.attrsNest = this.attrsNest.slice();\n    res.inAttributeName = this.inAttributeName;\n    res.attributeIsType = this.attributeIsType;\n    res.attrValue = this.attrValue;\n    res.indentOf = this.indentOf;\n    res.indentToken = this.indentToken;\n\n    res.innerModeForLine = this.innerModeForLine;\n\n    return res;\n  };\n\n  function javaScript(stream, state) {\n    if (stream.sol()) {\n      // if javaScriptLine was set at end of line, ignore it\n      state.javaScriptLine = false;\n      state.javaScriptLineExcludesColon = false;\n    }\n    if (state.javaScriptLine) {\n      if (state.javaScriptLineExcludesColon && stream.peek() === ':') {\n        state.javaScriptLine = false;\n        state.javaScriptLineExcludesColon = false;\n        return;\n      }\n      var tok = jsMode.token(stream, state.jsState);\n      if (stream.eol()) state.javaScriptLine = false;\n      return tok || true;\n    }\n  }\n  function javaScriptArguments(stream, state) {\n    if (state.javaScriptArguments) {\n      if (state.javaScriptArgumentsDepth === 0 && stream.peek() !== '(') {\n        state.javaScriptArguments = false;\n        return;\n      }\n      if (stream.peek() === '(') {\n        state.javaScriptArgumentsDepth++;\n      } else if (stream.peek() === ')') {\n        state.javaScriptArgumentsDepth--;\n      }\n      if (state.javaScriptArgumentsDepth === 0) {\n        state.javaScriptArguments = false;\n        return;\n      }\n\n      var tok = jsMode.token(stream, state.jsState);\n      return tok || true;\n    }\n  }\n\n  function yieldStatement(stream) {\n    if (stream.match(/^yield\\b/)) {\n        return 'keyword';\n    }\n  }\n\n  function doctype(stream) {\n    if (stream.match(/^(?:doctype) *([^\\n]+)?/)) {\n        return DOCTYPE;\n    }\n  }\n\n  function interpolation(stream, state) {\n    if (stream.match('#{')) {\n      state.isInterpolating = true;\n      state.interpolationNesting = 0;\n      return 'punctuation';\n    }\n  }\n\n  function interpolationContinued(stream, state) {\n    if (state.isInterpolating) {\n      if (stream.peek() === '}') {\n        state.interpolationNesting--;\n        if (state.interpolationNesting < 0) {\n          stream.next();\n          state.isInterpolating = false;\n          return 'puncutation';\n        }\n      } else if (stream.peek() === '{') {\n        state.interpolationNesting++;\n      }\n      return jsMode.token(stream, state.jsState) || true;\n    }\n  }\n\n  function caseStatement(stream, state) {\n    if (stream.match(/^case\\b/)) {\n      state.javaScriptLine = true;\n      return KEYWORD;\n    }\n  }\n\n  function when(stream, state) {\n    if (stream.match(/^when\\b/)) {\n      state.javaScriptLine = true;\n      state.javaScriptLineExcludesColon = true;\n      return KEYWORD;\n    }\n  }\n\n  function defaultStatement(stream) {\n    if (stream.match(/^default\\b/)) {\n      return KEYWORD;\n    }\n  }\n\n  function extendsStatement(stream, state) {\n    if (stream.match(/^extends?\\b/)) {\n      state.restOfLine = 'string';\n      return KEYWORD;\n    }\n  }\n\n  function append(stream, state) {\n    if (stream.match(/^append\\b/)) {\n      state.restOfLine = 'variable';\n      return KEYWORD;\n    }\n  }\n  function prepend(stream, state) {\n    if (stream.match(/^prepend\\b/)) {\n      state.restOfLine = 'variable';\n      return KEYWORD;\n    }\n  }\n  function block(stream, state) {\n    if (stream.match(/^block\\b *(?:(prepend|append)\\b)?/)) {\n      state.restOfLine = 'variable';\n      return KEYWORD;\n    }\n  }\n\n  function include(stream, state) {\n    if (stream.match(/^include\\b/)) {\n      state.restOfLine = 'string';\n      return KEYWORD;\n    }\n  }\n\n  function includeFiltered(stream, state) {\n    if (stream.match(/^include:([a-zA-Z0-9\\-]+)/, false) && stream.match('include')) {\n      state.isIncludeFiltered = true;\n      return KEYWORD;\n    }\n  }\n\n  function includeFilteredContinued(stream, state) {\n    if (state.isIncludeFiltered) {\n      var tok = filter(stream, state);\n      state.isIncludeFiltered = false;\n      state.restOfLine = 'string';\n      return tok;\n    }\n  }\n\n  function mixin(stream, state) {\n    if (stream.match(/^mixin\\b/)) {\n      state.javaScriptLine = true;\n      return KEYWORD;\n    }\n  }\n\n  function call(stream, state) {\n    if (stream.match(/^\\+([-\\w]+)/)) {\n      if (!stream.match(/^\\( *[-\\w]+ *=/, false)) {\n        state.javaScriptArguments = true;\n        state.javaScriptArgumentsDepth = 0;\n      }\n      return 'variable';\n    }\n    if (stream.match(/^\\+#{/, false)) {\n      stream.next();\n      state.mixinCallAfter = true;\n      return interpolation(stream, state);\n    }\n  }\n  function callArguments(stream, state) {\n    if (state.mixinCallAfter) {\n      state.mixinCallAfter = false;\n      if (!stream.match(/^\\( *[-\\w]+ *=/, false)) {\n        state.javaScriptArguments = true;\n        state.javaScriptArgumentsDepth = 0;\n      }\n      return true;\n    }\n  }\n\n  function conditional(stream, state) {\n    if (stream.match(/^(if|unless|else if|else)\\b/)) {\n      state.javaScriptLine = true;\n      return KEYWORD;\n    }\n  }\n\n  function each(stream, state) {\n    if (stream.match(/^(- *)?(each|for)\\b/)) {\n      state.isEach = true;\n      return KEYWORD;\n    }\n  }\n  function eachContinued(stream, state) {\n    if (state.isEach) {\n      if (stream.match(/^ in\\b/)) {\n        state.javaScriptLine = true;\n        state.isEach = false;\n        return KEYWORD;\n      } else if (stream.sol() || stream.eol()) {\n        state.isEach = false;\n      } else if (stream.next()) {\n        while (!stream.match(/^ in\\b/, false) && stream.next());\n        return 'variable';\n      }\n    }\n  }\n\n  function whileStatement(stream, state) {\n    if (stream.match(/^while\\b/)) {\n      state.javaScriptLine = true;\n      return KEYWORD;\n    }\n  }\n\n  function tag(stream, state) {\n    var captures;\n    if (captures = stream.match(/^(\\w(?:[-:\\w]*\\w)?)\\/?/)) {\n      state.lastTag = captures[1].toLowerCase();\n      if (state.lastTag === 'script') {\n        state.scriptType = 'application/javascript';\n      }\n      return 'tag';\n    }\n  }\n\n  function filter(stream, state) {\n    if (stream.match(/^:([\\w\\-]+)/)) {\n      var innerMode;\n      if (config && config.innerModes) {\n        innerMode = config.innerModes(stream.current().substring(1));\n      }\n      if (!innerMode) {\n        innerMode = stream.current().substring(1);\n      }\n      if (typeof innerMode === 'string') {\n        innerMode = CodeMirror.getMode(config, innerMode);\n      }\n      setInnerMode(stream, state, innerMode);\n      return 'atom';\n    }\n  }\n\n  function code(stream, state) {\n    if (stream.match(/^(!?=|-)/)) {\n      state.javaScriptLine = true;\n      return 'punctuation';\n    }\n  }\n\n  function id(stream) {\n    if (stream.match(/^#([\\w-]+)/)) {\n      return ID;\n    }\n  }\n\n  function className(stream) {\n    if (stream.match(/^\\.([\\w-]+)/)) {\n      return CLASS;\n    }\n  }\n\n  function attrs(stream, state) {\n    if (stream.peek() == '(') {\n      stream.next();\n      state.isAttrs = true;\n      state.attrsNest = [];\n      state.inAttributeName = true;\n      state.attrValue = '';\n      state.attributeIsType = false;\n      return 'punctuation';\n    }\n  }\n\n  function attrsContinued(stream, state) {\n    if (state.isAttrs) {\n      if (ATTRS_NEST[stream.peek()]) {\n        state.attrsNest.push(ATTRS_NEST[stream.peek()]);\n      }\n      if (state.attrsNest[state.attrsNest.length - 1] === stream.peek()) {\n        state.attrsNest.pop();\n      } else  if (stream.eat(')')) {\n        state.isAttrs = false;\n        return 'punctuation';\n      }\n      if (state.inAttributeName && stream.match(/^[^=,\\)!]+/)) {\n        if (stream.peek() === '=' || stream.peek() === '!') {\n          state.inAttributeName = false;\n          state.jsState = jsMode.startState();\n          if (state.lastTag === 'script' && stream.current().trim().toLowerCase() === 'type') {\n            state.attributeIsType = true;\n          } else {\n            state.attributeIsType = false;\n          }\n        }\n        return 'attribute';\n      }\n\n      var tok = jsMode.token(stream, state.jsState);\n      if (state.attributeIsType && tok === 'string') {\n        state.scriptType = stream.current().toString();\n      }\n      if (state.attrsNest.length === 0 && (tok === 'string' || tok === 'variable' || tok === 'keyword')) {\n        try {\n          Function('', 'var x ' + state.attrValue.replace(/,\\s*$/, '').replace(/^!/, ''));\n          state.inAttributeName = true;\n          state.attrValue = '';\n          stream.backUp(stream.current().length);\n          return attrsContinued(stream, state);\n        } catch (ex) {\n          //not the end of an attribute\n        }\n      }\n      state.attrValue += stream.current();\n      return tok || true;\n    }\n  }\n\n  function attributesBlock(stream, state) {\n    if (stream.match(/^&attributes\\b/)) {\n      state.javaScriptArguments = true;\n      state.javaScriptArgumentsDepth = 0;\n      return 'keyword';\n    }\n  }\n\n  function indent(stream) {\n    if (stream.sol() && stream.eatSpace()) {\n      return 'indent';\n    }\n  }\n\n  function comment(stream, state) {\n    if (stream.match(/^ *\\/\\/(-)?([^\\n]*)/)) {\n      state.indentOf = stream.indentation();\n      state.indentToken = 'comment';\n      return 'comment';\n    }\n  }\n\n  function colon(stream) {\n    if (stream.match(/^: */)) {\n      return 'colon';\n    }\n  }\n\n  function text(stream, state) {\n    if (stream.match(/^(?:\\| ?| )([^\\n]+)/)) {\n      return 'string';\n    }\n    if (stream.match(/^(<[^\\n]*)/, false)) {\n      // html string\n      setInnerMode(stream, state, 'htmlmixed');\n      state.innerModeForLine = true;\n      return innerMode(stream, state, true);\n    }\n  }\n\n  function dot(stream, state) {\n    if (stream.eat('.')) {\n      var innerMode = null;\n      if (state.lastTag === 'script' && state.scriptType.toLowerCase().indexOf('javascript') != -1) {\n        innerMode = state.scriptType.toLowerCase().replace(/\"|'/g, '');\n      } else if (state.lastTag === 'style') {\n        innerMode = 'css';\n      }\n      setInnerMode(stream, state, innerMode);\n      return 'dot';\n    }\n  }\n\n  function fail(stream) {\n    stream.next();\n    return null;\n  }\n\n\n  function setInnerMode(stream, state, mode) {\n    mode = CodeMirror.mimeModes[mode] || mode;\n    mode = config.innerModes ? config.innerModes(mode) || mode : mode;\n    mode = CodeMirror.mimeModes[mode] || mode;\n    mode = CodeMirror.getMode(config, mode);\n    state.indentOf = stream.indentation();\n\n    if (mode && mode.name !== 'null') {\n      state.innerMode = mode;\n    } else {\n      state.indentToken = 'string';\n    }\n  }\n  function innerMode(stream, state, force) {\n    if (stream.indentation() > state.indentOf || (state.innerModeForLine && !stream.sol()) || force) {\n      if (state.innerMode) {\n        if (!state.innerState) {\n          state.innerState = state.innerMode.startState ? state.innerMode.startState(stream.indentation()) : {};\n        }\n        return stream.hideFirstChars(state.indentOf + 2, function () {\n          return state.innerMode.token(stream, state.innerState) || true;\n        });\n      } else {\n        stream.skipToEnd();\n        return state.indentToken;\n      }\n    } else if (stream.sol()) {\n      state.indentOf = Infinity;\n      state.indentToken = null;\n      state.innerMode = null;\n      state.innerState = null;\n    }\n  }\n  function restOfLine(stream, state) {\n    if (stream.sol()) {\n      // if restOfLine was set at end of line, ignore it\n      state.restOfLine = '';\n    }\n    if (state.restOfLine) {\n      stream.skipToEnd();\n      var tok = state.restOfLine;\n      state.restOfLine = '';\n      return tok;\n    }\n  }\n\n\n  function startState() {\n    return new State();\n  }\n  function copyState(state) {\n    return state.copy();\n  }\n  /**\n   * Get the next token in the stream\n   *\n   * @param {Stream} stream\n   * @param {State} state\n   */\n  function nextToken(stream, state) {\n    var tok = innerMode(stream, state)\n      || restOfLine(stream, state)\n      || interpolationContinued(stream, state)\n      || includeFilteredContinued(stream, state)\n      || eachContinued(stream, state)\n      || attrsContinued(stream, state)\n      || javaScript(stream, state)\n      || javaScriptArguments(stream, state)\n      || callArguments(stream, state)\n\n      || yieldStatement(stream, state)\n      || doctype(stream, state)\n      || interpolation(stream, state)\n      || caseStatement(stream, state)\n      || when(stream, state)\n      || defaultStatement(stream, state)\n      || extendsStatement(stream, state)\n      || append(stream, state)\n      || prepend(stream, state)\n      || block(stream, state)\n      || include(stream, state)\n      || includeFiltered(stream, state)\n      || mixin(stream, state)\n      || call(stream, state)\n      || conditional(stream, state)\n      || each(stream, state)\n      || whileStatement(stream, state)\n      || tag(stream, state)\n      || filter(stream, state)\n      || code(stream, state)\n      || id(stream, state)\n      || className(stream, state)\n      || attrs(stream, state)\n      || attributesBlock(stream, state)\n      || indent(stream, state)\n      || text(stream, state)\n      || comment(stream, state)\n      || colon(stream, state)\n      || dot(stream, state)\n      || fail(stream, state);\n\n    return tok === true ? null : tok;\n  }\n  return {\n    startState: startState,\n    copyState: copyState,\n    token: nextToken\n  };\n});\n\nCodeMirror.defineMIME('text/x-jade', 'jade');\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/javascript/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: JavaScript mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"../../addon/edit/matchbrackets.js\"></script>\n<script src=\"../../addon/comment/continuecomment.js\"></script>\n<script src=\"../../addon/comment/comment.js\"></script>\n<script src=\"javascript.js\"></script>\n<style type=\"text/css\">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">JavaScript</a>\n  </ul>\n</div>\n\n<article>\n<h2>JavaScript mode</h2>\n\n\n<div><textarea id=\"code\" name=\"code\">\n// Demo code (the actual new parser character stream implementation)\n\nfunction StringStream(string) {\n  this.pos = 0;\n  this.string = string;\n}\n\nStringStream.prototype = {\n  done: function() {return this.pos >= this.string.length;},\n  peek: function() {return this.string.charAt(this.pos);},\n  next: function() {\n    if (this.pos &lt; this.string.length)\n      return this.string.charAt(this.pos++);\n  },\n  eat: function(match) {\n    var ch = this.string.charAt(this.pos);\n    if (typeof match == \"string\") var ok = ch == match;\n    else var ok = ch &amp;&amp; match.test ? match.test(ch) : match(ch);\n    if (ok) {this.pos++; return ch;}\n  },\n  eatWhile: function(match) {\n    var start = this.pos;\n    while (this.eat(match));\n    if (this.pos > start) return this.string.slice(start, this.pos);\n  },\n  backUp: function(n) {this.pos -= n;},\n  column: function() {return this.pos;},\n  eatSpace: function() {\n    var start = this.pos;\n    while (/\\s/.test(this.string.charAt(this.pos))) this.pos++;\n    return this.pos - start;\n  },\n  match: function(pattern, consume, caseInsensitive) {\n    if (typeof pattern == \"string\") {\n      function cased(str) {return caseInsensitive ? str.toLowerCase() : str;}\n      if (cased(this.string).indexOf(cased(pattern), this.pos) == this.pos) {\n        if (consume !== false) this.pos += str.length;\n        return true;\n      }\n    }\n    else {\n      var match = this.string.slice(this.pos).match(pattern);\n      if (match &amp;&amp; consume !== false) this.pos += match[0].length;\n      return match;\n    }\n  }\n};\n</textarea></div>\n\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        lineNumbers: true,\n        matchBrackets: true,\n        continueComments: \"Enter\",\n        extraKeys: {\"Ctrl-Q\": \"toggleComment\"}\n      });\n    </script>\n\n    <p>\n      JavaScript mode supports several configuration options:\n      <ul>\n        <li><code>json</code> which will set the mode to expect JSON\n        data rather than a JavaScript program.</li>\n        <li><code>jsonld</code> which will set the mode to expect\n        <a href=\"http://json-ld.org\">JSON-LD</a> linked data rather\n        than a JavaScript program (<a href=\"json-ld.html\">demo</a>).</li>\n        <li><code>typescript</code> which will activate additional\n        syntax highlighting and some other things for TypeScript code\n        (<a href=\"typescript.html\">demo</a>).</li>\n        <li><code>statementIndent</code> which (given a number) will\n        determine the amount of indentation to use for statements\n        continued on a new line.</li>\n        <li><code>wordCharacters</code>, a regexp that indicates which\n        characters should be considered part of an identifier.\n        Defaults to <code>/[\\w$]/</code>, which does not handle\n        non-ASCII identifiers. Can be set to something more elaborate\n        to improve Unicode support.</li>\n      </ul>\n    </p>\n\n    <p><strong>MIME types defined:</strong> <code>text/javascript</code>, <code>application/json</code>, <code>application/ld+json</code>, <code>text/typescript</code>, <code>application/typescript</code>.</p>\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/javascript/javascript.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n// TODO actually recognize syntax of TypeScript constructs\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"javascript\", function(config, parserConfig) {\n  var indentUnit = config.indentUnit;\n  var statementIndent = parserConfig.statementIndent;\n  var jsonldMode = parserConfig.jsonld;\n  var jsonMode = parserConfig.json || jsonldMode;\n  var isTS = parserConfig.typescript;\n  var wordRE = parserConfig.wordCharacters || /[\\w$\\xa1-\\uffff]/;\n\n  // Tokenizer\n\n  var keywords = function(){\n    function kw(type) {return {type: type, style: \"keyword\"};}\n    var A = kw(\"keyword a\"), B = kw(\"keyword b\"), C = kw(\"keyword c\");\n    var operator = kw(\"operator\"), atom = {type: \"atom\", style: \"atom\"};\n\n    var jsKeywords = {\n      \"if\": kw(\"if\"), \"while\": A, \"with\": A, \"else\": B, \"do\": B, \"try\": B, \"finally\": B,\n      \"return\": C, \"break\": C, \"continue\": C, \"new\": C, \"delete\": C, \"throw\": C, \"debugger\": C,\n      \"var\": kw(\"var\"), \"const\": kw(\"var\"), \"let\": kw(\"var\"),\n      \"function\": kw(\"function\"), \"catch\": kw(\"catch\"),\n      \"for\": kw(\"for\"), \"switch\": kw(\"switch\"), \"case\": kw(\"case\"), \"default\": kw(\"default\"),\n      \"in\": operator, \"typeof\": operator, \"instanceof\": operator,\n      \"true\": atom, \"false\": atom, \"null\": atom, \"undefined\": atom, \"NaN\": atom, \"Infinity\": atom,\n      \"this\": kw(\"this\"), \"module\": kw(\"module\"), \"class\": kw(\"class\"), \"super\": kw(\"atom\"),\n      \"yield\": C, \"export\": kw(\"export\"), \"import\": kw(\"import\"), \"extends\": C\n    };\n\n    // Extend the 'normal' keywords with the TypeScript language extensions\n    if (isTS) {\n      var type = {type: \"variable\", style: \"variable-3\"};\n      var tsKeywords = {\n        // object-like things\n        \"interface\": kw(\"interface\"),\n        \"extends\": kw(\"extends\"),\n        \"constructor\": kw(\"constructor\"),\n\n        // scope modifiers\n        \"public\": kw(\"public\"),\n        \"private\": kw(\"private\"),\n        \"protected\": kw(\"protected\"),\n        \"static\": kw(\"static\"),\n\n        // types\n        \"string\": type, \"number\": type, \"bool\": type, \"any\": type\n      };\n\n      for (var attr in tsKeywords) {\n        jsKeywords[attr] = tsKeywords[attr];\n      }\n    }\n\n    return jsKeywords;\n  }();\n\n  var isOperatorChar = /[+\\-*&%=<>!?|~^]/;\n  var isJsonldKeyword = /^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)\"/;\n\n  function readRegexp(stream) {\n    var escaped = false, next, inSet = false;\n    while ((next = stream.next()) != null) {\n      if (!escaped) {\n        if (next == \"/\" && !inSet) return;\n        if (next == \"[\") inSet = true;\n        else if (inSet && next == \"]\") inSet = false;\n      }\n      escaped = !escaped && next == \"\\\\\";\n    }\n  }\n\n  // Used as scratch variables to communicate multiple values without\n  // consing up tons of objects.\n  var type, content;\n  function ret(tp, style, cont) {\n    type = tp; content = cont;\n    return style;\n  }\n  function tokenBase(stream, state) {\n    var ch = stream.next();\n    if (ch == '\"' || ch == \"'\") {\n      state.tokenize = tokenString(ch);\n      return state.tokenize(stream, state);\n    } else if (ch == \".\" && stream.match(/^\\d+(?:[eE][+\\-]?\\d+)?/)) {\n      return ret(\"number\", \"number\");\n    } else if (ch == \".\" && stream.match(\"..\")) {\n      return ret(\"spread\", \"meta\");\n    } else if (/[\\[\\]{}\\(\\),;\\:\\.]/.test(ch)) {\n      return ret(ch);\n    } else if (ch == \"=\" && stream.eat(\">\")) {\n      return ret(\"=>\", \"operator\");\n    } else if (ch == \"0\" && stream.eat(/x/i)) {\n      stream.eatWhile(/[\\da-f]/i);\n      return ret(\"number\", \"number\");\n    } else if (/\\d/.test(ch)) {\n      stream.match(/^\\d*(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?/);\n      return ret(\"number\", \"number\");\n    } else if (ch == \"/\") {\n      if (stream.eat(\"*\")) {\n        state.tokenize = tokenComment;\n        return tokenComment(stream, state);\n      } else if (stream.eat(\"/\")) {\n        stream.skipToEnd();\n        return ret(\"comment\", \"comment\");\n      } else if (state.lastType == \"operator\" || state.lastType == \"keyword c\" ||\n               state.lastType == \"sof\" || /^[\\[{}\\(,;:]$/.test(state.lastType)) {\n        readRegexp(stream);\n        stream.match(/^\\b(([gimyu])(?![gimyu]*\\2))+\\b/);\n        return ret(\"regexp\", \"string-2\");\n      } else {\n        stream.eatWhile(isOperatorChar);\n        return ret(\"operator\", \"operator\", stream.current());\n      }\n    } else if (ch == \"`\") {\n      state.tokenize = tokenQuasi;\n      return tokenQuasi(stream, state);\n    } else if (ch == \"#\") {\n      stream.skipToEnd();\n      return ret(\"error\", \"error\");\n    } else if (isOperatorChar.test(ch)) {\n      stream.eatWhile(isOperatorChar);\n      return ret(\"operator\", \"operator\", stream.current());\n    } else if (wordRE.test(ch)) {\n      stream.eatWhile(wordRE);\n      var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word];\n      return (known && state.lastType != \".\") ? ret(known.type, known.style, word) :\n                     ret(\"variable\", \"variable\", word);\n    }\n  }\n\n  function tokenString(quote) {\n    return function(stream, state) {\n      var escaped = false, next;\n      if (jsonldMode && stream.peek() == \"@\" && stream.match(isJsonldKeyword)){\n        state.tokenize = tokenBase;\n        return ret(\"jsonld-keyword\", \"meta\");\n      }\n      while ((next = stream.next()) != null) {\n        if (next == quote && !escaped) break;\n        escaped = !escaped && next == \"\\\\\";\n      }\n      if (!escaped) state.tokenize = tokenBase;\n      return ret(\"string\", \"string\");\n    };\n  }\n\n  function tokenComment(stream, state) {\n    var maybeEnd = false, ch;\n    while (ch = stream.next()) {\n      if (ch == \"/\" && maybeEnd) {\n        state.tokenize = tokenBase;\n        break;\n      }\n      maybeEnd = (ch == \"*\");\n    }\n    return ret(\"comment\", \"comment\");\n  }\n\n  function tokenQuasi(stream, state) {\n    var escaped = false, next;\n    while ((next = stream.next()) != null) {\n      if (!escaped && (next == \"`\" || next == \"$\" && stream.eat(\"{\"))) {\n        state.tokenize = tokenBase;\n        break;\n      }\n      escaped = !escaped && next == \"\\\\\";\n    }\n    return ret(\"quasi\", \"string-2\", stream.current());\n  }\n\n  var brackets = \"([{}])\";\n  // This is a crude lookahead trick to try and notice that we're\n  // parsing the argument patterns for a fat-arrow function before we\n  // actually hit the arrow token. It only works if the arrow is on\n  // the same line as the arguments and there's no strange noise\n  // (comments) in between. Fallback is to only notice when we hit the\n  // arrow, and not declare the arguments as locals for the arrow\n  // body.\n  function findFatArrow(stream, state) {\n    if (state.fatArrowAt) state.fatArrowAt = null;\n    var arrow = stream.string.indexOf(\"=>\", stream.start);\n    if (arrow < 0) return;\n\n    var depth = 0, sawSomething = false;\n    for (var pos = arrow - 1; pos >= 0; --pos) {\n      var ch = stream.string.charAt(pos);\n      var bracket = brackets.indexOf(ch);\n      if (bracket >= 0 && bracket < 3) {\n        if (!depth) { ++pos; break; }\n        if (--depth == 0) break;\n      } else if (bracket >= 3 && bracket < 6) {\n        ++depth;\n      } else if (wordRE.test(ch)) {\n        sawSomething = true;\n      } else if (/[\"'\\/]/.test(ch)) {\n        return;\n      } else if (sawSomething && !depth) {\n        ++pos;\n        break;\n      }\n    }\n    if (sawSomething && !depth) state.fatArrowAt = pos;\n  }\n\n  // Parser\n\n  var atomicTypes = {\"atom\": true, \"number\": true, \"variable\": true, \"string\": true, \"regexp\": true, \"this\": true, \"jsonld-keyword\": true};\n\n  function JSLexical(indented, column, type, align, prev, info) {\n    this.indented = indented;\n    this.column = column;\n    this.type = type;\n    this.prev = prev;\n    this.info = info;\n    if (align != null) this.align = align;\n  }\n\n  function inScope(state, varname) {\n    for (var v = state.localVars; v; v = v.next)\n      if (v.name == varname) return true;\n    for (var cx = state.context; cx; cx = cx.prev) {\n      for (var v = cx.vars; v; v = v.next)\n        if (v.name == varname) return true;\n    }\n  }\n\n  function parseJS(state, style, type, content, stream) {\n    var cc = state.cc;\n    // Communicate our context to the combinators.\n    // (Less wasteful than consing up a hundred closures on every call.)\n    cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc; cx.style = style;\n\n    if (!state.lexical.hasOwnProperty(\"align\"))\n      state.lexical.align = true;\n\n    while(true) {\n      var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement;\n      if (combinator(type, content)) {\n        while(cc.length && cc[cc.length - 1].lex)\n          cc.pop()();\n        if (cx.marked) return cx.marked;\n        if (type == \"variable\" && inScope(state, content)) return \"variable-2\";\n        return style;\n      }\n    }\n  }\n\n  // Combinator utils\n\n  var cx = {state: null, column: null, marked: null, cc: null};\n  function pass() {\n    for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]);\n  }\n  function cont() {\n    pass.apply(null, arguments);\n    return true;\n  }\n  function register(varname) {\n    function inList(list) {\n      for (var v = list; v; v = v.next)\n        if (v.name == varname) return true;\n      return false;\n    }\n    var state = cx.state;\n    if (state.context) {\n      cx.marked = \"def\";\n      if (inList(state.localVars)) return;\n      state.localVars = {name: varname, next: state.localVars};\n    } else {\n      if (inList(state.globalVars)) return;\n      if (parserConfig.globalVars)\n        state.globalVars = {name: varname, next: state.globalVars};\n    }\n  }\n\n  // Combinators\n\n  var defaultVars = {name: \"this\", next: {name: \"arguments\"}};\n  function pushcontext() {\n    cx.state.context = {prev: cx.state.context, vars: cx.state.localVars};\n    cx.state.localVars = defaultVars;\n  }\n  function popcontext() {\n    cx.state.localVars = cx.state.context.vars;\n    cx.state.context = cx.state.context.prev;\n  }\n  function pushlex(type, info) {\n    var result = function() {\n      var state = cx.state, indent = state.indented;\n      if (state.lexical.type == \"stat\") indent = state.lexical.indented;\n      else for (var outer = state.lexical; outer && outer.type == \")\" && outer.align; outer = outer.prev)\n        indent = outer.indented;\n      state.lexical = new JSLexical(indent, cx.stream.column(), type, null, state.lexical, info);\n    };\n    result.lex = true;\n    return result;\n  }\n  function poplex() {\n    var state = cx.state;\n    if (state.lexical.prev) {\n      if (state.lexical.type == \")\")\n        state.indented = state.lexical.indented;\n      state.lexical = state.lexical.prev;\n    }\n  }\n  poplex.lex = true;\n\n  function expect(wanted) {\n    function exp(type) {\n      if (type == wanted) return cont();\n      else if (wanted == \";\") return pass();\n      else return cont(exp);\n    };\n    return exp;\n  }\n\n  function statement(type, value) {\n    if (type == \"var\") return cont(pushlex(\"vardef\", value.length), vardef, expect(\";\"), poplex);\n    if (type == \"keyword a\") return cont(pushlex(\"form\"), expression, statement, poplex);\n    if (type == \"keyword b\") return cont(pushlex(\"form\"), statement, poplex);\n    if (type == \"{\") return cont(pushlex(\"}\"), block, poplex);\n    if (type == \";\") return cont();\n    if (type == \"if\") {\n      if (cx.state.lexical.info == \"else\" && cx.state.cc[cx.state.cc.length - 1] == poplex)\n        cx.state.cc.pop()();\n      return cont(pushlex(\"form\"), expression, statement, poplex, maybeelse);\n    }\n    if (type == \"function\") return cont(functiondef);\n    if (type == \"for\") return cont(pushlex(\"form\"), forspec, statement, poplex);\n    if (type == \"variable\") return cont(pushlex(\"stat\"), maybelabel);\n    if (type == \"switch\") return cont(pushlex(\"form\"), expression, pushlex(\"}\", \"switch\"), expect(\"{\"),\n                                      block, poplex, poplex);\n    if (type == \"case\") return cont(expression, expect(\":\"));\n    if (type == \"default\") return cont(expect(\":\"));\n    if (type == \"catch\") return cont(pushlex(\"form\"), pushcontext, expect(\"(\"), funarg, expect(\")\"),\n                                     statement, poplex, popcontext);\n    if (type == \"module\") return cont(pushlex(\"form\"), pushcontext, afterModule, popcontext, poplex);\n    if (type == \"class\") return cont(pushlex(\"form\"), className, poplex);\n    if (type == \"export\") return cont(pushlex(\"form\"), afterExport, poplex);\n    if (type == \"import\") return cont(pushlex(\"form\"), afterImport, poplex);\n    return pass(pushlex(\"stat\"), expression, expect(\";\"), poplex);\n  }\n  function expression(type) {\n    return expressionInner(type, false);\n  }\n  function expressionNoComma(type) {\n    return expressionInner(type, true);\n  }\n  function expressionInner(type, noComma) {\n    if (cx.state.fatArrowAt == cx.stream.start) {\n      var body = noComma ? arrowBodyNoComma : arrowBody;\n      if (type == \"(\") return cont(pushcontext, pushlex(\")\"), commasep(pattern, \")\"), poplex, expect(\"=>\"), body, popcontext);\n      else if (type == \"variable\") return pass(pushcontext, pattern, expect(\"=>\"), body, popcontext);\n    }\n\n    var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma;\n    if (atomicTypes.hasOwnProperty(type)) return cont(maybeop);\n    if (type == \"function\") return cont(functiondef, maybeop);\n    if (type == \"keyword c\") return cont(noComma ? maybeexpressionNoComma : maybeexpression);\n    if (type == \"(\") return cont(pushlex(\")\"), maybeexpression, comprehension, expect(\")\"), poplex, maybeop);\n    if (type == \"operator\" || type == \"spread\") return cont(noComma ? expressionNoComma : expression);\n    if (type == \"[\") return cont(pushlex(\"]\"), arrayLiteral, poplex, maybeop);\n    if (type == \"{\") return contCommasep(objprop, \"}\", null, maybeop);\n    if (type == \"quasi\") { return pass(quasi, maybeop); }\n    return cont();\n  }\n  function maybeexpression(type) {\n    if (type.match(/[;\\}\\)\\],]/)) return pass();\n    return pass(expression);\n  }\n  function maybeexpressionNoComma(type) {\n    if (type.match(/[;\\}\\)\\],]/)) return pass();\n    return pass(expressionNoComma);\n  }\n\n  function maybeoperatorComma(type, value) {\n    if (type == \",\") return cont(expression);\n    return maybeoperatorNoComma(type, value, false);\n  }\n  function maybeoperatorNoComma(type, value, noComma) {\n    var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma;\n    var expr = noComma == false ? expression : expressionNoComma;\n    if (type == \"=>\") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext);\n    if (type == \"operator\") {\n      if (/\\+\\+|--/.test(value)) return cont(me);\n      if (value == \"?\") return cont(expression, expect(\":\"), expr);\n      return cont(expr);\n    }\n    if (type == \"quasi\") { return pass(quasi, me); }\n    if (type == \";\") return;\n    if (type == \"(\") return contCommasep(expressionNoComma, \")\", \"call\", me);\n    if (type == \".\") return cont(property, me);\n    if (type == \"[\") return cont(pushlex(\"]\"), maybeexpression, expect(\"]\"), poplex, me);\n  }\n  function quasi(type, value) {\n    if (type != \"quasi\") return pass();\n    if (value.slice(value.length - 2) != \"${\") return cont(quasi);\n    return cont(expression, continueQuasi);\n  }\n  function continueQuasi(type) {\n    if (type == \"}\") {\n      cx.marked = \"string-2\";\n      cx.state.tokenize = tokenQuasi;\n      return cont(quasi);\n    }\n  }\n  function arrowBody(type) {\n    findFatArrow(cx.stream, cx.state);\n    return pass(type == \"{\" ? statement : expression);\n  }\n  function arrowBodyNoComma(type) {\n    findFatArrow(cx.stream, cx.state);\n    return pass(type == \"{\" ? statement : expressionNoComma);\n  }\n  function maybelabel(type) {\n    if (type == \":\") return cont(poplex, statement);\n    return pass(maybeoperatorComma, expect(\";\"), poplex);\n  }\n  function property(type) {\n    if (type == \"variable\") {cx.marked = \"property\"; return cont();}\n  }\n  function objprop(type, value) {\n    if (type == \"variable\" || cx.style == \"keyword\") {\n      cx.marked = \"property\";\n      if (value == \"get\" || value == \"set\") return cont(getterSetter);\n      return cont(afterprop);\n    } else if (type == \"number\" || type == \"string\") {\n      cx.marked = jsonldMode ? \"property\" : (cx.style + \" property\");\n      return cont(afterprop);\n    } else if (type == \"jsonld-keyword\") {\n      return cont(afterprop);\n    } else if (type == \"[\") {\n      return cont(expression, expect(\"]\"), afterprop);\n    }\n  }\n  function getterSetter(type) {\n    if (type != \"variable\") return pass(afterprop);\n    cx.marked = \"property\";\n    return cont(functiondef);\n  }\n  function afterprop(type) {\n    if (type == \":\") return cont(expressionNoComma);\n    if (type == \"(\") return pass(functiondef);\n  }\n  function commasep(what, end) {\n    function proceed(type) {\n      if (type == \",\") {\n        var lex = cx.state.lexical;\n        if (lex.info == \"call\") lex.pos = (lex.pos || 0) + 1;\n        return cont(what, proceed);\n      }\n      if (type == end) return cont();\n      return cont(expect(end));\n    }\n    return function(type) {\n      if (type == end) return cont();\n      return pass(what, proceed);\n    };\n  }\n  function contCommasep(what, end, info) {\n    for (var i = 3; i < arguments.length; i++)\n      cx.cc.push(arguments[i]);\n    return cont(pushlex(end, info), commasep(what, end), poplex);\n  }\n  function block(type) {\n    if (type == \"}\") return cont();\n    return pass(statement, block);\n  }\n  function maybetype(type) {\n    if (isTS && type == \":\") return cont(typedef);\n  }\n  function typedef(type) {\n    if (type == \"variable\"){cx.marked = \"variable-3\"; return cont();}\n  }\n  function vardef() {\n    return pass(pattern, maybetype, maybeAssign, vardefCont);\n  }\n  function pattern(type, value) {\n    if (type == \"variable\") { register(value); return cont(); }\n    if (type == \"[\") return contCommasep(pattern, \"]\");\n    if (type == \"{\") return contCommasep(proppattern, \"}\");\n  }\n  function proppattern(type, value) {\n    if (type == \"variable\" && !cx.stream.match(/^\\s*:/, false)) {\n      register(value);\n      return cont(maybeAssign);\n    }\n    if (type == \"variable\") cx.marked = \"property\";\n    return cont(expect(\":\"), pattern, maybeAssign);\n  }\n  function maybeAssign(_type, value) {\n    if (value == \"=\") return cont(expressionNoComma);\n  }\n  function vardefCont(type) {\n    if (type == \",\") return cont(vardef);\n  }\n  function maybeelse(type, value) {\n    if (type == \"keyword b\" && value == \"else\") return cont(pushlex(\"form\", \"else\"), statement, poplex);\n  }\n  function forspec(type) {\n    if (type == \"(\") return cont(pushlex(\")\"), forspec1, expect(\")\"), poplex);\n  }\n  function forspec1(type) {\n    if (type == \"var\") return cont(vardef, expect(\";\"), forspec2);\n    if (type == \";\") return cont(forspec2);\n    if (type == \"variable\") return cont(formaybeinof);\n    return pass(expression, expect(\";\"), forspec2);\n  }\n  function formaybeinof(_type, value) {\n    if (value == \"in\" || value == \"of\") { cx.marked = \"keyword\"; return cont(expression); }\n    return cont(maybeoperatorComma, forspec2);\n  }\n  function forspec2(type, value) {\n    if (type == \";\") return cont(forspec3);\n    if (value == \"in\" || value == \"of\") { cx.marked = \"keyword\"; return cont(expression); }\n    return pass(expression, expect(\";\"), forspec3);\n  }\n  function forspec3(type) {\n    if (type != \")\") cont(expression);\n  }\n  function functiondef(type, value) {\n    if (value == \"*\") {cx.marked = \"keyword\"; return cont(functiondef);}\n    if (type == \"variable\") {register(value); return cont(functiondef);}\n    if (type == \"(\") return cont(pushcontext, pushlex(\")\"), commasep(funarg, \")\"), poplex, statement, popcontext);\n  }\n  function funarg(type) {\n    if (type == \"spread\") return cont(funarg);\n    return pass(pattern, maybetype);\n  }\n  function className(type, value) {\n    if (type == \"variable\") {register(value); return cont(classNameAfter);}\n  }\n  function classNameAfter(type, value) {\n    if (value == \"extends\") return cont(expression, classNameAfter);\n    if (type == \"{\") return cont(pushlex(\"}\"), classBody, poplex);\n  }\n  function classBody(type, value) {\n    if (type == \"variable\" || cx.style == \"keyword\") {\n      cx.marked = \"property\";\n      if (value == \"get\" || value == \"set\") return cont(classGetterSetter, functiondef, classBody);\n      return cont(functiondef, classBody);\n    }\n    if (value == \"*\") {\n      cx.marked = \"keyword\";\n      return cont(classBody);\n    }\n    if (type == \";\") return cont(classBody);\n    if (type == \"}\") return cont();\n  }\n  function classGetterSetter(type) {\n    if (type != \"variable\") return pass();\n    cx.marked = \"property\";\n    return cont();\n  }\n  function afterModule(type, value) {\n    if (type == \"string\") return cont(statement);\n    if (type == \"variable\") { register(value); return cont(maybeFrom); }\n  }\n  function afterExport(_type, value) {\n    if (value == \"*\") { cx.marked = \"keyword\"; return cont(maybeFrom, expect(\";\")); }\n    if (value == \"default\") { cx.marked = \"keyword\"; return cont(expression, expect(\";\")); }\n    return pass(statement);\n  }\n  function afterImport(type) {\n    if (type == \"string\") return cont();\n    return pass(importSpec, maybeFrom);\n  }\n  function importSpec(type, value) {\n    if (type == \"{\") return contCommasep(importSpec, \"}\");\n    if (type == \"variable\") register(value);\n    return cont();\n  }\n  function maybeFrom(_type, value) {\n    if (value == \"from\") { cx.marked = \"keyword\"; return cont(expression); }\n  }\n  function arrayLiteral(type) {\n    if (type == \"]\") return cont();\n    return pass(expressionNoComma, maybeArrayComprehension);\n  }\n  function maybeArrayComprehension(type) {\n    if (type == \"for\") return pass(comprehension, expect(\"]\"));\n    if (type == \",\") return cont(commasep(maybeexpressionNoComma, \"]\"));\n    return pass(commasep(expressionNoComma, \"]\"));\n  }\n  function comprehension(type) {\n    if (type == \"for\") return cont(forspec, comprehension);\n    if (type == \"if\") return cont(expression, comprehension);\n  }\n\n  function isContinuedStatement(state, textAfter) {\n    return state.lastType == \"operator\" || state.lastType == \",\" ||\n      isOperatorChar.test(textAfter.charAt(0)) ||\n      /[,.]/.test(textAfter.charAt(0));\n  }\n\n  // Interface\n\n  return {\n    startState: function(basecolumn) {\n      var state = {\n        tokenize: tokenBase,\n        lastType: \"sof\",\n        cc: [],\n        lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, \"block\", false),\n        localVars: parserConfig.localVars,\n        context: parserConfig.localVars && {vars: parserConfig.localVars},\n        indented: 0\n      };\n      if (parserConfig.globalVars && typeof parserConfig.globalVars == \"object\")\n        state.globalVars = parserConfig.globalVars;\n      return state;\n    },\n\n    token: function(stream, state) {\n      if (stream.sol()) {\n        if (!state.lexical.hasOwnProperty(\"align\"))\n          state.lexical.align = false;\n        state.indented = stream.indentation();\n        findFatArrow(stream, state);\n      }\n      if (state.tokenize != tokenComment && stream.eatSpace()) return null;\n      var style = state.tokenize(stream, state);\n      if (type == \"comment\") return style;\n      state.lastType = type == \"operator\" && (content == \"++\" || content == \"--\") ? \"incdec\" : type;\n      return parseJS(state, style, type, content, stream);\n    },\n\n    indent: function(state, textAfter) {\n      if (state.tokenize == tokenComment) return CodeMirror.Pass;\n      if (state.tokenize != tokenBase) return 0;\n      var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical;\n      // Kludge to prevent 'maybelse' from blocking lexical scope pops\n      if (!/^\\s*else\\b/.test(textAfter)) for (var i = state.cc.length - 1; i >= 0; --i) {\n        var c = state.cc[i];\n        if (c == poplex) lexical = lexical.prev;\n        else if (c != maybeelse) break;\n      }\n      if (lexical.type == \"stat\" && firstChar == \"}\") lexical = lexical.prev;\n      if (statementIndent && lexical.type == \")\" && lexical.prev.type == \"stat\")\n        lexical = lexical.prev;\n      var type = lexical.type, closing = firstChar == type;\n\n      if (type == \"vardef\") return lexical.indented + (state.lastType == \"operator\" || state.lastType == \",\" ? lexical.info + 1 : 0);\n      else if (type == \"form\" && firstChar == \"{\") return lexical.indented;\n      else if (type == \"form\") return lexical.indented + indentUnit;\n      else if (type == \"stat\")\n        return lexical.indented + (isContinuedStatement(state, textAfter) ? statementIndent || indentUnit : 0);\n      else if (lexical.info == \"switch\" && !closing && parserConfig.doubleIndentSwitch != false)\n        return lexical.indented + (/^(?:case|default)\\b/.test(textAfter) ? indentUnit : 2 * indentUnit);\n      else if (lexical.align) return lexical.column + (closing ? 0 : 1);\n      else return lexical.indented + (closing ? 0 : indentUnit);\n    },\n\n    electricInput: /^\\s*(?:case .*?:|default:|\\{|\\})$/,\n    blockCommentStart: jsonMode ? null : \"/*\",\n    blockCommentEnd: jsonMode ? null : \"*/\",\n    lineComment: jsonMode ? null : \"//\",\n    fold: \"brace\",\n\n    helperType: jsonMode ? \"json\" : \"javascript\",\n    jsonldMode: jsonldMode,\n    jsonMode: jsonMode\n  };\n});\n\nCodeMirror.registerHelper(\"wordChars\", \"javascript\", /[\\w$]/);\n\nCodeMirror.defineMIME(\"text/javascript\", \"javascript\");\nCodeMirror.defineMIME(\"text/ecmascript\", \"javascript\");\nCodeMirror.defineMIME(\"application/javascript\", \"javascript\");\nCodeMirror.defineMIME(\"application/x-javascript\", \"javascript\");\nCodeMirror.defineMIME(\"application/ecmascript\", \"javascript\");\nCodeMirror.defineMIME(\"application/json\", {name: \"javascript\", json: true});\nCodeMirror.defineMIME(\"application/x-json\", {name: \"javascript\", json: true});\nCodeMirror.defineMIME(\"application/ld+json\", {name: \"javascript\", jsonld: true});\nCodeMirror.defineMIME(\"text/typescript\", { name: \"javascript\", typescript: true });\nCodeMirror.defineMIME(\"application/typescript\", { name: \"javascript\", typescript: true });\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/javascript/json-ld.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: JSON-LD mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"../../addon/edit/matchbrackets.js\"></script>\n<script src=\"../../addon/comment/continuecomment.js\"></script>\n<script src=\"../../addon/comment/comment.js\"></script>\n<script src=\"javascript.js\"></script>\n<style type=\"text/css\">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>\n<div id=\"nav\">\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"/></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">JSON-LD</a>\n  </ul>\n</div>\n\n<article>\n<h2>JSON-LD mode</h2>\n\n\n<div><textarea id=\"code\" name=\"code\">\n{\n  \"@context\": {\n    \"name\": \"http://schema.org/name\",\n    \"description\": \"http://schema.org/description\",\n    \"image\": {\n      \"@id\": \"http://schema.org/image\",\n      \"@type\": \"@id\"\n    },\n    \"geo\": \"http://schema.org/geo\",\n    \"latitude\": {\n      \"@id\": \"http://schema.org/latitude\",\n      \"@type\": \"xsd:float\"\n    },\n    \"longitude\": {\n      \"@id\": \"http://schema.org/longitude\",\n      \"@type\": \"xsd:float\"\n    },\n    \"xsd\": \"http://www.w3.org/2001/XMLSchema#\"\n  },\n  \"name\": \"The Empire State Building\",\n  \"description\": \"The Empire State Building is a 102-story landmark in New York City.\",\n  \"image\": \"http://www.civil.usherbrooke.ca/cours/gci215a/empire-state-building.jpg\",\n  \"geo\": {\n    \"latitude\": \"40.75\",\n    \"longitude\": \"73.98\"\n  }\n}\n</textarea></div>\n\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        matchBrackets: true,\n        autoCloseBrackets: true,\n        mode: \"application/ld+json\",\n        lineWrapping: true\n      });\n    </script>\n    \n    <p>This is a specialization of the <a href=\"index.html\">JavaScript mode</a>.</p>\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/javascript/test.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function() {\n  var mode = CodeMirror.getMode({indentUnit: 2}, \"javascript\");\n  function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); }\n\n  MT(\"locals\",\n     \"[keyword function] [variable foo]([def a], [def b]) { [keyword var] [def c] [operator =] [number 10]; [keyword return] [variable-2 a] [operator +] [variable-2 c] [operator +] [variable d]; }\");\n\n  MT(\"comma-and-binop\",\n     \"[keyword function](){ [keyword var] [def x] [operator =] [number 1] [operator +] [number 2], [def y]; }\");\n\n  MT(\"destructuring\",\n     \"([keyword function]([def a], [[[def b], [def c] ]]) {\",\n     \"  [keyword let] {[def d], [property foo]: [def c][operator =][number 10], [def x]} [operator =] [variable foo]([variable-2 a]);\",\n     \"  [[[variable-2 c], [variable y] ]] [operator =] [variable-2 c];\",\n     \"})();\");\n\n  MT(\"class_body\",\n     \"[keyword class] [variable Foo] {\",\n     \"  [property constructor]() {}\",\n     \"  [property sayName]() {\",\n     \"    [keyword return] [string-2 `foo${][variable foo][string-2 }oo`];\",\n     \"  }\",\n     \"}\");\n\n  MT(\"class\",\n     \"[keyword class] [variable Point] [keyword extends] [variable SuperThing] {\",\n     \"  [property get] [property prop]() { [keyword return] [number 24]; }\",\n     \"  [property constructor]([def x], [def y]) {\",\n     \"    [keyword super]([string 'something']);\",\n     \"    [keyword this].[property x] [operator =] [variable-2 x];\",\n     \"  }\",\n     \"}\");\n\n  MT(\"module\",\n     \"[keyword module] [string 'foo'] {\",\n     \"  [keyword export] [keyword let] [def x] [operator =] [number 42];\",\n     \"  [keyword export] [keyword *] [keyword from] [string 'somewhere'];\",\n     \"}\");\n\n  MT(\"import\",\n     \"[keyword function] [variable foo]() {\",\n     \"  [keyword import] [def $] [keyword from] [string 'jquery'];\",\n     \"  [keyword module] [def crypto] [keyword from] [string 'crypto'];\",\n     \"  [keyword import] { [def encrypt], [def decrypt] } [keyword from] [string 'crypto'];\",\n     \"}\");\n\n  MT(\"const\",\n     \"[keyword function] [variable f]() {\",\n     \"  [keyword const] [[ [def a], [def b] ]] [operator =] [[ [number 1], [number 2] ]];\",\n     \"}\");\n\n  MT(\"for/of\",\n     \"[keyword for]([keyword let] [variable of] [keyword of] [variable something]) {}\");\n\n  MT(\"generator\",\n     \"[keyword function*] [variable repeat]([def n]) {\",\n     \"  [keyword for]([keyword var] [def i] [operator =] [number 0]; [variable-2 i] [operator <] [variable-2 n]; [operator ++][variable-2 i])\",\n     \"    [keyword yield] [variable-2 i];\",\n     \"}\");\n\n  MT(\"quotedStringAddition\",\n     \"[keyword let] [variable f] [operator =] [variable a] [operator +] [string 'fatarrow'] [operator +] [variable c];\");\n\n  MT(\"quotedFatArrow\",\n     \"[keyword let] [variable f] [operator =] [variable a] [operator +] [string '=>'] [operator +] [variable c];\");\n\n  MT(\"fatArrow\",\n     \"[variable array].[property filter]([def a] [operator =>] [variable-2 a] [operator +] [number 1]);\",\n     \"[variable a];\", // No longer in scope\n     \"[keyword let] [variable f] [operator =] ([[ [def a], [def b] ]], [def c]) [operator =>] [variable-2 a] [operator +] [variable-2 c];\",\n     \"[variable c];\");\n\n  MT(\"spread\",\n     \"[keyword function] [variable f]([def a], [meta ...][def b]) {\",\n     \"  [variable something]([variable-2 a], [meta ...][variable-2 b]);\",\n     \"}\");\n\n  MT(\"comprehension\",\n     \"[keyword function] [variable f]() {\",\n     \"  [[([variable x] [operator +] [number 1]) [keyword for] ([keyword var] [def x] [keyword in] [variable y]) [keyword if] [variable pred]([variable-2 x]) ]];\",\n     \"  ([variable u] [keyword for] ([keyword var] [def u] [keyword of] [variable generateValues]()) [keyword if] ([variable-2 u].[property color] [operator ===] [string 'blue']));\",\n     \"}\");\n\n  MT(\"quasi\",\n     \"[variable re][string-2 `fofdlakj${][variable x] [operator +] ([variable re][string-2 `foo`]) [operator +] [number 1][string-2 }fdsa`] [operator +] [number 2]\");\n\n  MT(\"quasi_no_function\",\n     \"[variable x] [operator =] [string-2 `fofdlakj${][variable x] [operator +] [string-2 `foo`] [operator +] [number 1][string-2 }fdsa`] [operator +] [number 2]\");\n\n  MT(\"indent_statement\",\n     \"[keyword var] [variable x] [operator =] [number 10]\",\n     \"[variable x] [operator +=] [variable y] [operator +]\",\n     \"  [atom Infinity]\",\n     \"[keyword debugger];\");\n\n  MT(\"indent_if\",\n     \"[keyword if] ([number 1])\",\n     \"  [keyword break];\",\n     \"[keyword else] [keyword if] ([number 2])\",\n     \"  [keyword continue];\",\n     \"[keyword else]\",\n     \"  [number 10];\",\n     \"[keyword if] ([number 1]) {\",\n     \"  [keyword break];\",\n     \"} [keyword else] [keyword if] ([number 2]) {\",\n     \"  [keyword continue];\",\n     \"} [keyword else] {\",\n     \"  [number 10];\",\n     \"}\");\n\n  MT(\"indent_for\",\n     \"[keyword for] ([keyword var] [variable i] [operator =] [number 0];\",\n     \"     [variable i] [operator <] [number 100];\",\n     \"     [variable i][operator ++])\",\n     \"  [variable doSomething]([variable i]);\",\n     \"[keyword debugger];\");\n\n  MT(\"indent_c_style\",\n     \"[keyword function] [variable foo]()\",\n     \"{\",\n     \"  [keyword debugger];\",\n     \"}\");\n\n  MT(\"indent_else\",\n     \"[keyword for] (;;)\",\n     \"  [keyword if] ([variable foo])\",\n     \"    [keyword if] ([variable bar])\",\n     \"      [number 1];\",\n     \"    [keyword else]\",\n     \"      [number 2];\",\n     \"  [keyword else]\",\n     \"    [number 3];\");\n\n  MT(\"indent_funarg\",\n     \"[variable foo]([number 10000],\",\n     \"    [keyword function]([def a]) {\",\n     \"  [keyword debugger];\",\n     \"};\");\n\n  MT(\"indent_below_if\",\n     \"[keyword for] (;;)\",\n     \"  [keyword if] ([variable foo])\",\n     \"    [number 1];\",\n     \"[number 2];\");\n\n  MT(\"multilinestring\",\n     \"[keyword var] [variable x] [operator =] [string 'foo\\\\]\",\n     \"[string bar'];\");\n\n  MT(\"scary_regexp\",\n     \"[string-2 /foo[[/]]bar/];\");\n\n  MT(\"indent_strange_array\",\n     \"[keyword var] [variable x] [operator =] [[\",\n     \"  [number 1],,\",\n     \"  [number 2],\",\n     \"]];\",\n     \"[number 10];\");\n\n  var jsonld_mode = CodeMirror.getMode(\n    {indentUnit: 2},\n    {name: \"javascript\", jsonld: true}\n  );\n  function LD(name) {\n    test.mode(name, jsonld_mode, Array.prototype.slice.call(arguments, 1));\n  }\n\n  LD(\"json_ld_keywords\",\n    '{',\n    '  [meta \"@context\"]: {',\n    '    [meta \"@base\"]: [string \"http://example.com\"],',\n    '    [meta \"@vocab\"]: [string \"http://xmlns.com/foaf/0.1/\"],',\n    '    [property \"likesFlavor\"]: {',\n    '      [meta \"@container\"]: [meta \"@list\"]',\n    '      [meta \"@reverse\"]: [string \"@beFavoriteOf\"]',\n    '    },',\n    '    [property \"nick\"]: { [meta \"@container\"]: [meta \"@set\"] },',\n    '    [property \"nick\"]: { [meta \"@container\"]: [meta \"@index\"] }',\n    '  },',\n    '  [meta \"@graph\"]: [[ {',\n    '    [meta \"@id\"]: [string \"http://dbpedia.org/resource/John_Lennon\"],',\n    '    [property \"name\"]: [string \"John Lennon\"],',\n    '    [property \"modified\"]: {',\n    '      [meta \"@value\"]: [string \"2010-05-29T14:17:39+02:00\"],',\n    '      [meta \"@type\"]: [string \"http://www.w3.org/2001/XMLSchema#dateTime\"]',\n    '    }',\n    '  } ]]',\n    '}');\n\n  LD(\"json_ld_fake\",\n    '{',\n    '  [property \"@fake\"]: [string \"@fake\"],',\n    '  [property \"@contextual\"]: [string \"@identifier\"],',\n    '  [property \"user@domain.com\"]: [string \"@graphical\"],',\n    '  [property \"@ID\"]: [string \"@@ID\"]',\n    '}');\n})();\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/javascript/typescript.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: TypeScript mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"javascript.js\"></script>\n<style type=\"text/css\">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">TypeScript</a>\n  </ul>\n</div>\n\n<article>\n<h2>TypeScript mode</h2>\n\n\n<div><textarea id=\"code\" name=\"code\">\nclass Greeter {\n\tgreeting: string;\n\tconstructor (message: string) {\n\t\tthis.greeting = message;\n\t}\n\tgreet() {\n\t\treturn \"Hello, \" + this.greeting;\n\t}\n}   \n\nvar greeter = new Greeter(\"world\");\n\nvar button = document.createElement('button')\nbutton.innerText = \"Say Hello\"\nbutton.onclick = function() {\n\talert(greeter.greet())\n}\n\ndocument.body.appendChild(button)\n\n</textarea></div>\n\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        lineNumbers: true,\n        matchBrackets: true,\n        mode: \"text/typescript\"\n      });\n    </script>\n\n    <p>This is a specialization of the <a href=\"index.html\">JavaScript mode</a>.</p>\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/jinja2/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Jinja2 mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"jinja2.js\"></script>\n<style type=\"text/css\">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Jinja2</a>\n  </ul>\n</div>\n\n<article>\n<h2>Jinja2 mode</h2>\n<form><textarea id=\"code\" name=\"code\">\n{# this is a comment #}\n{%- for item in li -%}\n  &lt;li&gt;{{ item.label }}&lt;/li&gt;\n{% endfor -%}\n{{ item.sand == true and item.keyword == false ? 1 : 0 }}\n{{ app.get(55, 1.2, true) }}\n{% if app.get(&#39;_route&#39;) == (&#39;_home&#39;) %}home{% endif %}\n{% if app.session.flashbag.has(&#39;message&#39;) %}\n  {% for message in app.session.flashbag.get(&#39;message&#39;) %}\n    {{ message.content }}\n  {% endfor %}\n{% endif %}\n{{ path(&#39;_home&#39;, {&#39;section&#39;: app.request.get(&#39;section&#39;)}) }}\n{{ path(&#39;_home&#39;, {\n    &#39;section&#39;: app.request.get(&#39;section&#39;),\n    &#39;boolean&#39;: true,\n    &#39;number&#39;: 55.33\n  })\n}}\n{% include (&#39;test.incl.html.twig&#39;) %}\n</textarea></form>\n    <script>\n      var editor =\n      CodeMirror.fromTextArea(document.getElementById(\"code\"), {mode:\n        {name: \"jinja2\", htmlMode: true}});\n    </script>\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/jinja2/jinja2.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n\n  CodeMirror.defineMode(\"jinja2\", function() {\n    var keywords = [\"and\", \"as\", \"block\", \"endblock\", \"by\", \"cycle\", \"debug\", \"else\", \"elif\",\n      \"extends\", \"filter\", \"endfilter\", \"firstof\", \"for\",\n      \"endfor\", \"if\", \"endif\", \"ifchanged\", \"endifchanged\",\n      \"ifequal\", \"endifequal\", \"ifnotequal\",\n      \"endifnotequal\", \"in\", \"include\", \"load\", \"not\", \"now\", \"or\",\n      \"parsed\", \"regroup\", \"reversed\", \"spaceless\",\n      \"endspaceless\", \"ssi\", \"templatetag\", \"openblock\",\n      \"closeblock\", \"openvariable\", \"closevariable\",\n      \"openbrace\", \"closebrace\", \"opencomment\",\n      \"closecomment\", \"widthratio\", \"url\", \"with\", \"endwith\",\n      \"get_current_language\", \"trans\", \"endtrans\", \"noop\", \"blocktrans\",\n      \"endblocktrans\", \"get_available_languages\",\n      \"get_current_language_bidi\", \"plural\"],\n    operator = /^[+\\-*&%=<>!?|~^]/,\n    sign = /^[:\\[\\(\\{]/,\n    atom = [\"true\", \"false\"],\n    number = /^(\\d[+\\-\\*\\/])?\\d+(\\.\\d+)?/;\n\n    keywords = new RegExp(\"((\" + keywords.join(\")|(\") + \"))\\\\b\");\n    atom = new RegExp(\"((\" + atom.join(\")|(\") + \"))\\\\b\");\n\n    function tokenBase (stream, state) {\n      var ch = stream.peek();\n\n      //Comment\n      if (state.incomment) {\n        if(!stream.skipTo(\"#}\")) {\n          stream.skipToEnd();\n        } else {\n          stream.eatWhile(/\\#|}/);\n          state.incomment = false;\n        }\n        return \"comment\";\n      //Tag\n      } else if (state.intag) {\n        //After operator\n        if(state.operator) {\n          state.operator = false;\n          if(stream.match(atom)) {\n            return \"atom\";\n          }\n          if(stream.match(number)) {\n            return \"number\";\n          }\n        }\n        //After sign\n        if(state.sign) {\n          state.sign = false;\n          if(stream.match(atom)) {\n            return \"atom\";\n          }\n          if(stream.match(number)) {\n            return \"number\";\n          }\n        }\n\n        if(state.instring) {\n          if(ch == state.instring) {\n            state.instring = false;\n          }\n          stream.next();\n          return \"string\";\n        } else if(ch == \"'\" || ch == '\"') {\n          state.instring = ch;\n          stream.next();\n          return \"string\";\n        } else if(stream.match(state.intag + \"}\") || stream.eat(\"-\") && stream.match(state.intag + \"}\")) {\n          state.intag = false;\n          return \"tag\";\n        } else if(stream.match(operator)) {\n          state.operator = true;\n          return \"operator\";\n        } else if(stream.match(sign)) {\n          state.sign = true;\n        } else {\n          if(stream.eat(\" \") || stream.sol()) {\n            if(stream.match(keywords)) {\n              return \"keyword\";\n            }\n            if(stream.match(atom)) {\n              return \"atom\";\n            }\n            if(stream.match(number)) {\n              return \"number\";\n            }\n            if(stream.sol()) {\n              stream.next();\n            }\n          } else {\n            stream.next();\n          }\n\n        }\n        return \"variable\";\n      } else if (stream.eat(\"{\")) {\n        if (ch = stream.eat(\"#\")) {\n          state.incomment = true;\n          if(!stream.skipTo(\"#}\")) {\n            stream.skipToEnd();\n          } else {\n            stream.eatWhile(/\\#|}/);\n            state.incomment = false;\n          }\n          return \"comment\";\n        //Open tag\n        } else if (ch = stream.eat(/\\{|%/)) {\n          //Cache close tag\n          state.intag = ch;\n          if(ch == \"{\") {\n            state.intag = \"}\";\n          }\n          stream.eat(\"-\");\n          return \"tag\";\n        }\n      }\n      stream.next();\n    };\n\n    return {\n      startState: function () {\n        return {tokenize: tokenBase};\n      },\n      token: function (stream, state) {\n        return state.tokenize(stream, state);\n      }\n    };\n  });\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/julia/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Julia mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"julia.js\"></script>\n<style type=\"text/css\">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Julia</a>\n  </ul>\n</div>\n\n<article>\n<h2>Julia mode</h2>\n\n    <div><textarea id=\"code\" name=\"code\">\n#numbers\n1234\n1234im\n.234\n.234im\n2.23im\n2.3f3\n23e2\n0x234\n\n#strings\n'a'\n\"asdf\"\nr\"regex\"\nb\"bytestring\"\n\n\"\"\"\nmultiline string\n\"\"\"\n\n#identifiers\na\nas123\nfunction_name!\n\n#unicode identifiers\n# a = x\\ddot\na⃗ = ẍ\n# a = v\\dot\na⃗ = v̇\n#F\\vec = m \\cdotp a\\vec\nF⃗ = m·a⃗\n\n#literal identifier multiples\n3x\n4[1, 2, 3]\n\n#dicts and indexing\nx=[1, 2, 3]\nx[end-1]\nx={\"julia\"=>\"language of technical computing\"}\n\n\n#exception handling\ntry\n  f()\ncatch\n  @printf \"Error\"\nfinally\n  g()\nend\n\n#types\nimmutable Color{T<:Number}\n  r::T\n  g::T\n  b::T\nend\n\n#functions\nfunction change!(x::Vector{Float64})\n  for i = 1:length(x)\n    x[i] *= 2\n  end\nend\n\n#function invocation\nf('b', (2, 3)...)\n\n#operators\n|=\n&=\n^=\n\\-\n%=\n*=\n+=\n-=\n<=\n>=\n!=\n==\n%\n*\n+\n-\n<\n>\n!\n=\n|\n&\n^\n\\\n?\n~\n:\n$\n<:\n.<\n.>\n<<\n<<=\n>>\n>>>>\n>>=\n>>>=\n<<=\n<<<=\n.<=\n.>=\n.==\n->\n//\nin\n...\n//\n:=\n.//=\n.*=\n./=\n.^=\n.%=\n.+=\n.-=\n\\=\n\\\\=\n||\n===\n&&\n|=\n.|=\n<:\n>:\n|>\n<|\n::\nx ? y : z\n\n#macros\n@spawnat 2 1+1\n@eval(:x)\n\n#keywords and operators\nif else elseif while for\n begin let end do\ntry catch finally return break continue\nglobal local const \nexport import importall using\nfunction macro module baremodule \ntype immutable quote\ntrue false enumerate\n\n\n    </textarea></div>\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        mode: {name: \"julia\",\n               },\n        lineNumbers: true,\n        indentUnit: 4,\n        matchBrackets: true\n      });\n    </script>\n\n    <p><strong>MIME types defined:</strong> <code>text/x-julia</code>.</p>\n</article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/julia/julia.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"julia\", function(_conf, parserConf) {\n  var ERRORCLASS = 'error';\n\n  function wordRegexp(words) {\n    return new RegExp(\"^((\" + words.join(\")|(\") + \"))\\\\b\");\n  }\n\n  var operators = parserConf.operators || /^\\.?[|&^\\\\%*+\\-<>!=\\/]=?|\\?|~|:|\\$|\\.[<>]|<<=?|>>>?=?|\\.[<>=]=|->?|\\/\\/|\\bin\\b/;\n  var delimiters = parserConf.delimiters || /^[;,()[\\]{}]/;\n  var identifiers = parserConf.identifiers|| /^[_A-Za-z\\u00A1-\\uFFFF][_A-Za-z0-9\\u00A1-\\uFFFF]*!*/;\n  var blockOpeners = [\"begin\", \"function\", \"type\", \"immutable\", \"let\", \"macro\", \"for\", \"while\", \"quote\", \"if\", \"else\", \"elseif\", \"try\", \"finally\", \"catch\", \"do\"];\n  var blockClosers = [\"end\", \"else\", \"elseif\", \"catch\", \"finally\"];\n  var keywordList = ['if', 'else', 'elseif', 'while', 'for', 'begin', 'let', 'end', 'do', 'try', 'catch', 'finally', 'return', 'break', 'continue', 'global', 'local', 'const', 'export', 'import', 'importall', 'using', 'function', 'macro', 'module', 'baremodule', 'type', 'immutable', 'quote', 'typealias', 'abstract', 'bitstype', 'ccall'];\n  var builtinList = ['true', 'false', 'enumerate', 'open', 'close', 'nothing', 'NaN', 'Inf', 'print', 'println', 'Int', 'Int8', 'Uint8', 'Int16', 'Uint16', 'Int32', 'Uint32', 'Int64', 'Uint64', 'Int128', 'Uint128', 'Bool', 'Char', 'Float16', 'Float32', 'Float64', 'Array', 'Vector', 'Matrix', 'String', 'UTF8String', 'ASCIIString', 'error', 'warn', 'info', '@printf'];\n\n  //var stringPrefixes = new RegExp(\"^[br]?('|\\\")\")\n  var stringPrefixes = /^(`|'|\"{3}|([br]?\"))/;\n  var keywords = wordRegexp(keywordList);\n  var builtins = wordRegexp(builtinList);\n  var openers = wordRegexp(blockOpeners);\n  var closers = wordRegexp(blockClosers);\n  var macro = /^@[_A-Za-z][_A-Za-z0-9]*/;\n  var symbol = /^:[_A-Za-z][_A-Za-z0-9]*/;\n  var indentInfo = null;\n\n  function in_array(state) {\n    var ch = cur_scope(state);\n    if(ch==\"[\" || ch==\"{\") {\n      return true;\n    }\n    else {\n      return false;\n    }\n  }\n\n  function cur_scope(state) {\n    if(state.scopes.length==0) {\n      return null;\n    }\n    return state.scopes[state.scopes.length - 1];\n  }\n\n  // tokenizers\n  function tokenBase(stream, state) {\n    // Handle scope changes\n    var leaving_expr = state.leaving_expr;\n    if(stream.sol()) {\n      leaving_expr = false;\n    }\n    state.leaving_expr = false;\n    if(leaving_expr) {\n      if(stream.match(/^'+/)) {\n        return 'operator';\n      }\n\n    }\n\n    if(stream.match(/^\\.{2,3}/)) {\n      return 'operator';\n    }\n\n    if (stream.eatSpace()) {\n      return null;\n    }\n\n    var ch = stream.peek();\n    // Handle Comments\n    if (ch === '#') {\n        stream.skipToEnd();\n        return 'comment';\n    }\n    if(ch==='[') {\n      state.scopes.push(\"[\");\n    }\n\n    if(ch==='{') {\n      state.scopes.push(\"{\");\n    }\n\n    var scope=cur_scope(state);\n\n    if(scope==='[' && ch===']') {\n      state.scopes.pop();\n      state.leaving_expr=true;\n    }\n\n    if(scope==='{' && ch==='}') {\n      state.scopes.pop();\n      state.leaving_expr=true;\n    }\n\n    if(ch===')') {\n      state.leaving_expr = true;\n    }\n\n    var match;\n    if(!in_array(state) && (match=stream.match(openers, false))) {\n      state.scopes.push(match);\n    }\n\n    if(!in_array(state) && stream.match(closers, false)) {\n      state.scopes.pop();\n    }\n\n    if(in_array(state)) {\n      if(stream.match(/^end/)) {\n        return 'number';\n      }\n\n    }\n\n    if(stream.match(/^=>/)) {\n      return 'operator';\n    }\n\n\n    // Handle Number Literals\n    if (stream.match(/^[0-9\\.]/, false)) {\n      var imMatcher = RegExp(/^im\\b/);\n      var floatLiteral = false;\n      // Floats\n      if (stream.match(/^\\d*\\.(?!\\.)\\d+([ef][\\+\\-]?\\d+)?/i)) { floatLiteral = true; }\n      if (stream.match(/^\\d+\\.(?!\\.)\\d*/)) { floatLiteral = true; }\n      if (stream.match(/^\\.\\d+/)) { floatLiteral = true; }\n      if (floatLiteral) {\n          // Float literals may be \"imaginary\"\n          stream.match(imMatcher);\n          state.leaving_expr = true;\n          return 'number';\n      }\n      // Integers\n      var intLiteral = false;\n      // Hex\n      if (stream.match(/^0x[0-9a-f]+/i)) { intLiteral = true; }\n      // Binary\n      if (stream.match(/^0b[01]+/i)) { intLiteral = true; }\n      // Octal\n      if (stream.match(/^0o[0-7]+/i)) { intLiteral = true; }\n      // Decimal\n      if (stream.match(/^[1-9]\\d*(e[\\+\\-]?\\d+)?/)) {\n          intLiteral = true;\n      }\n      // Zero by itself with no other piece of number.\n      if (stream.match(/^0(?![\\dx])/i)) { intLiteral = true; }\n      if (intLiteral) {\n          // Integer literals may be \"long\"\n          stream.match(imMatcher);\n          state.leaving_expr = true;\n          return 'number';\n      }\n    }\n\n    if(stream.match(/^(::)|(<:)/)) {\n      return 'operator';\n    }\n\n    // Handle symbols\n    if(!leaving_expr && stream.match(symbol)) {\n      return 'string';\n    }\n\n    // Handle operators and Delimiters\n    if (stream.match(operators)) {\n      return 'operator';\n    }\n\n\n    // Handle Strings\n    if (stream.match(stringPrefixes)) {\n      state.tokenize = tokenStringFactory(stream.current());\n      return state.tokenize(stream, state);\n    }\n\n    if (stream.match(macro)) {\n      return 'meta';\n    }\n\n\n    if (stream.match(delimiters)) {\n      return null;\n    }\n\n    if (stream.match(keywords)) {\n      return 'keyword';\n    }\n\n    if (stream.match(builtins)) {\n      return 'builtin';\n    }\n\n\n    if (stream.match(identifiers)) {\n      state.leaving_expr=true;\n      return 'variable';\n    }\n    // Handle non-detected items\n    stream.next();\n    return ERRORCLASS;\n  }\n\n  function tokenStringFactory(delimiter) {\n    while ('rub'.indexOf(delimiter.charAt(0).toLowerCase()) >= 0) {\n      delimiter = delimiter.substr(1);\n    }\n    var singleline = delimiter.length == 1;\n    var OUTCLASS = 'string';\n\n    function tokenString(stream, state) {\n      while (!stream.eol()) {\n        stream.eatWhile(/[^'\"\\\\]/);\n        if (stream.eat('\\\\')) {\n            stream.next();\n            if (singleline && stream.eol()) {\n              return OUTCLASS;\n            }\n        } else if (stream.match(delimiter)) {\n            state.tokenize = tokenBase;\n            return OUTCLASS;\n        } else {\n            stream.eat(/['\"]/);\n        }\n      }\n      if (singleline) {\n        if (parserConf.singleLineStringErrors) {\n            return ERRORCLASS;\n        } else {\n            state.tokenize = tokenBase;\n        }\n      }\n      return OUTCLASS;\n    }\n    tokenString.isString = true;\n    return tokenString;\n  }\n\n  function tokenLexer(stream, state) {\n    indentInfo = null;\n    var style = state.tokenize(stream, state);\n    var current = stream.current();\n\n    // Handle '.' connected identifiers\n    if (current === '.') {\n      style = stream.match(identifiers, false) ? null : ERRORCLASS;\n      if (style === null && state.lastStyle === 'meta') {\n          // Apply 'meta' style to '.' connected identifiers when\n          // appropriate.\n        style = 'meta';\n      }\n      return style;\n    }\n\n    return style;\n  }\n\n  var external = {\n    startState: function() {\n      return {\n        tokenize: tokenBase,\n        scopes: [],\n        leaving_expr: false\n      };\n    },\n\n    token: function(stream, state) {\n      var style = tokenLexer(stream, state);\n      state.lastStyle = style;\n      return style;\n    },\n\n    indent: function(state, textAfter) {\n      var delta = 0;\n      if(textAfter==\"end\" || textAfter==\"]\" || textAfter==\"}\" || textAfter==\"else\" || textAfter==\"elseif\" || textAfter==\"catch\" || textAfter==\"finally\") {\n        delta = -1;\n      }\n      return (state.scopes.length + delta) * 4;\n    },\n\n    lineComment: \"#\",\n    fold: \"indent\",\n    electricChars: \"edlsifyh]}\"\n  };\n  return external;\n});\n\n\nCodeMirror.defineMIME(\"text/x-julia\", \"julia\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/kotlin/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Kotlin mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"kotlin.js\"></script>\n<style type=\"text/css\">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Kotlin</a>\n  </ul>\n</div>\n\n<article>\n<h2>Kotlin mode</h2>\n\n\n<div><textarea id=\"code\" name=\"code\">\npackage org.wasabi.http\n\nimport java.util.concurrent.Executors\nimport java.net.InetSocketAddress\nimport org.wasabi.app.AppConfiguration\nimport io.netty.bootstrap.ServerBootstrap\nimport io.netty.channel.nio.NioEventLoopGroup\nimport io.netty.channel.socket.nio.NioServerSocketChannel\nimport org.wasabi.app.AppServer\n\npublic class HttpServer(private val appServer: AppServer) {\n\n    val bootstrap: ServerBootstrap\n    val primaryGroup: NioEventLoopGroup\n    val workerGroup:  NioEventLoopGroup\n\n    {\n        // Define worker groups\n        primaryGroup = NioEventLoopGroup()\n        workerGroup = NioEventLoopGroup()\n\n        // Initialize bootstrap of server\n        bootstrap = ServerBootstrap()\n\n        bootstrap.group(primaryGroup, workerGroup)\n        bootstrap.channel(javaClass<NioServerSocketChannel>())\n        bootstrap.childHandler(NettyPipelineInitializer(appServer))\n    }\n\n    public fun start(wait: Boolean = true) {\n        val channel = bootstrap.bind(appServer.configuration.port)?.sync()?.channel()\n\n        if (wait) {\n            channel?.closeFuture()?.sync()\n        }\n    }\n\n    public fun stop() {\n        // Shutdown all event loops\n        primaryGroup.shutdownGracefully()\n        workerGroup.shutdownGracefully()\n\n        // Wait till all threads are terminated\n        primaryGroup.terminationFuture().sync()\n        workerGroup.terminationFuture().sync()\n    }\n}\n</textarea></div>\n\n    <script>\n        var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n            mode: {name: \"kotlin\"},\n            lineNumbers: true,\n            indentUnit: 4\n        });\n    </script>\n    <h3>Mode for Kotlin (http://kotlin.jetbrains.org/)</h3>\n    <p>Developed by Hadi Hariri (https://github.com/hhariri).</p>\n    <p><strong>MIME type defined:</strong> <code>text/x-kotlin</code>.</p>\n</article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/kotlin/kotlin.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"kotlin\", function (config, parserConfig) {\n  function words(str) {\n    var obj = {}, words = str.split(\" \");\n    for (var i = 0; i < words.length; ++i) obj[words[i]] = true;\n    return obj;\n  }\n\n  var multiLineStrings = parserConfig.multiLineStrings;\n\n  var keywords = words(\n          \"package continue return object while break class data trait throw super\" +\n          \" when type this else This try val var fun for is in if do as true false null get set\");\n  var softKeywords = words(\"import\" +\n      \" where by get set abstract enum open annotation override private public internal\" +\n      \" protected catch out vararg inline finally final ref\");\n  var blockKeywords = words(\"catch class do else finally for if where try while enum\");\n  var atoms = words(\"null true false this\");\n\n  var curPunc;\n\n  function tokenBase(stream, state) {\n    var ch = stream.next();\n    if (ch == '\"' || ch == \"'\") {\n      return startString(ch, stream, state);\n    }\n    // Wildcard import w/o trailing semicolon (import smth.*)\n    if (ch == \".\" && stream.eat(\"*\")) {\n      return \"word\";\n    }\n    if (/[\\[\\]{}\\(\\),;\\:\\.]/.test(ch)) {\n      curPunc = ch;\n      return null;\n    }\n    if (/\\d/.test(ch)) {\n      if (stream.eat(/eE/)) {\n        stream.eat(/\\+\\-/);\n        stream.eatWhile(/\\d/);\n      }\n      return \"number\";\n    }\n    if (ch == \"/\") {\n      if (stream.eat(\"*\")) {\n        state.tokenize.push(tokenComment);\n        return tokenComment(stream, state);\n      }\n      if (stream.eat(\"/\")) {\n        stream.skipToEnd();\n        return \"comment\";\n      }\n      if (expectExpression(state.lastToken)) {\n        return startString(ch, stream, state);\n      }\n    }\n    // Commented\n    if (ch == \"-\" && stream.eat(\">\")) {\n      curPunc = \"->\";\n      return null;\n    }\n    if (/[\\-+*&%=<>!?|\\/~]/.test(ch)) {\n      stream.eatWhile(/[\\-+*&%=<>|~]/);\n      return \"operator\";\n    }\n    stream.eatWhile(/[\\w\\$_]/);\n\n    var cur = stream.current();\n    if (atoms.propertyIsEnumerable(cur)) {\n      return \"atom\";\n    }\n    if (softKeywords.propertyIsEnumerable(cur)) {\n      if (blockKeywords.propertyIsEnumerable(cur)) curPunc = \"newstatement\";\n      return \"softKeyword\";\n    }\n\n    if (keywords.propertyIsEnumerable(cur)) {\n      if (blockKeywords.propertyIsEnumerable(cur)) curPunc = \"newstatement\";\n      return \"keyword\";\n    }\n    return \"word\";\n  }\n\n  tokenBase.isBase = true;\n\n  function startString(quote, stream, state) {\n    var tripleQuoted = false;\n    if (quote != \"/\" && stream.eat(quote)) {\n      if (stream.eat(quote)) tripleQuoted = true;\n      else return \"string\";\n    }\n    function t(stream, state) {\n      var escaped = false, next, end = !tripleQuoted;\n\n      while ((next = stream.next()) != null) {\n        if (next == quote && !escaped) {\n          if (!tripleQuoted) {\n            break;\n          }\n          if (stream.match(quote + quote)) {\n            end = true;\n            break;\n          }\n        }\n\n        if (quote == '\"' && next == \"$\" && !escaped && stream.eat(\"{\")) {\n          state.tokenize.push(tokenBaseUntilBrace());\n          return \"string\";\n        }\n\n        if (next == \"$\" && !escaped && !stream.eat(\" \")) {\n          state.tokenize.push(tokenBaseUntilSpace());\n          return \"string\";\n        }\n        escaped = !escaped && next == \"\\\\\";\n      }\n      if (multiLineStrings)\n        state.tokenize.push(t);\n      if (end) state.tokenize.pop();\n      return \"string\";\n    }\n\n    state.tokenize.push(t);\n    return t(stream, state);\n  }\n\n  function tokenBaseUntilBrace() {\n    var depth = 1;\n\n    function t(stream, state) {\n      if (stream.peek() == \"}\") {\n        depth--;\n        if (depth == 0) {\n          state.tokenize.pop();\n          return state.tokenize[state.tokenize.length - 1](stream, state);\n        }\n      } else if (stream.peek() == \"{\") {\n        depth++;\n      }\n      return tokenBase(stream, state);\n    }\n\n    t.isBase = true;\n    return t;\n  }\n\n  function tokenBaseUntilSpace() {\n    function t(stream, state) {\n      if (stream.eat(/[\\w]/)) {\n        var isWord = stream.eatWhile(/[\\w]/);\n        if (isWord) {\n          state.tokenize.pop();\n          return \"word\";\n        }\n      }\n      state.tokenize.pop();\n      return \"string\";\n    }\n\n    t.isBase = true;\n    return t;\n  }\n\n  function tokenComment(stream, state) {\n    var maybeEnd = false, ch;\n    while (ch = stream.next()) {\n      if (ch == \"/\" && maybeEnd) {\n        state.tokenize.pop();\n        break;\n      }\n      maybeEnd = (ch == \"*\");\n    }\n    return \"comment\";\n  }\n\n  function expectExpression(last) {\n    return !last || last == \"operator\" || last == \"->\" || /[\\.\\[\\{\\(,;:]/.test(last) ||\n        last == \"newstatement\" || last == \"keyword\" || last == \"proplabel\";\n  }\n\n  function Context(indented, column, type, align, prev) {\n    this.indented = indented;\n    this.column = column;\n    this.type = type;\n    this.align = align;\n    this.prev = prev;\n  }\n\n  function pushContext(state, col, type) {\n    return state.context = new Context(state.indented, col, type, null, state.context);\n  }\n\n  function popContext(state) {\n    var t = state.context.type;\n    if (t == \")\" || t == \"]\" || t == \"}\")\n      state.indented = state.context.indented;\n    return state.context = state.context.prev;\n  }\n\n  // Interface\n\n  return {\n    startState: function (basecolumn) {\n      return {\n        tokenize: [tokenBase],\n        context: new Context((basecolumn || 0) - config.indentUnit, 0, \"top\", false),\n        indented: 0,\n        startOfLine: true,\n        lastToken: null\n      };\n    },\n\n    token: function (stream, state) {\n      var ctx = state.context;\n      if (stream.sol()) {\n        if (ctx.align == null) ctx.align = false;\n        state.indented = stream.indentation();\n        state.startOfLine = true;\n        // Automatic semicolon insertion\n        if (ctx.type == \"statement\" && !expectExpression(state.lastToken)) {\n          popContext(state);\n          ctx = state.context;\n        }\n      }\n      if (stream.eatSpace()) return null;\n      curPunc = null;\n      var style = state.tokenize[state.tokenize.length - 1](stream, state);\n      if (style == \"comment\") return style;\n      if (ctx.align == null) ctx.align = true;\n      if ((curPunc == \";\" || curPunc == \":\") && ctx.type == \"statement\") popContext(state);\n      // Handle indentation for {x -> \\n ... }\n      else if (curPunc == \"->\" && ctx.type == \"statement\" && ctx.prev.type == \"}\") {\n        popContext(state);\n        state.context.align = false;\n      }\n      else if (curPunc == \"{\") pushContext(state, stream.column(), \"}\");\n      else if (curPunc == \"[\") pushContext(state, stream.column(), \"]\");\n      else if (curPunc == \"(\") pushContext(state, stream.column(), \")\");\n      else if (curPunc == \"}\") {\n        while (ctx.type == \"statement\") ctx = popContext(state);\n        if (ctx.type == \"}\") ctx = popContext(state);\n        while (ctx.type == \"statement\") ctx = popContext(state);\n      }\n      else if (curPunc == ctx.type) popContext(state);\n      else if (ctx.type == \"}\" || ctx.type == \"top\" || (ctx.type == \"statement\" && curPunc == \"newstatement\"))\n        pushContext(state, stream.column(), \"statement\");\n      state.startOfLine = false;\n      state.lastToken = curPunc || style;\n      return style;\n    },\n\n    indent: function (state, textAfter) {\n      if (!state.tokenize[state.tokenize.length - 1].isBase) return 0;\n      var firstChar = textAfter && textAfter.charAt(0), ctx = state.context;\n      if (ctx.type == \"statement\" && !expectExpression(state.lastToken)) ctx = ctx.prev;\n      var closing = firstChar == ctx.type;\n      if (ctx.type == \"statement\") {\n        return ctx.indented + (firstChar == \"{\" ? 0 : config.indentUnit);\n      }\n      else if (ctx.align) return ctx.column + (closing ? 0 : 1);\n      else return ctx.indented + (closing ? 0 : config.indentUnit);\n    },\n\n    electricChars: \"{}\"\n  };\n});\n\nCodeMirror.defineMIME(\"text/x-kotlin\", \"kotlin\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/livescript/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: LiveScript mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<link rel=\"stylesheet\" href=\"../../theme/solarized.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"livescript.js\"></script>\n<style>.CodeMirror {font-size: 80%;border-top: 1px solid silver; border-bottom: 1px solid silver;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">LiveScript</a>\n  </ul>\n</div>\n\n<article>\n<h2>LiveScript mode</h2>\n<form><textarea id=\"code\" name=\"code\">\n# LiveScript mode for CodeMirror\n# The following script, prelude.ls, is used to\n# demonstrate LiveScript mode for CodeMirror.\n#   https://github.com/gkz/prelude-ls\n\nexport objToFunc = objToFunc = (obj) ->\n  (key) -> obj[key]\n\nexport each = (f, xs) -->\n  if typeof! xs is \\Object\n    for , x of xs then f x\n  else\n    for x in xs then f x\n  xs\n\nexport map = (f, xs) -->\n  f = objToFunc f if typeof! f isnt \\Function\n  type = typeof! xs\n  if type is \\Object\n    {[key, f x] for key, x of xs}\n  else\n    result = [f x for x in xs]\n    if type is \\String then result * '' else result\n\nexport filter = (f, xs) -->\n  f = objToFunc f if typeof! f isnt \\Function\n  type = typeof! xs\n  if type is \\Object\n    {[key, x] for key, x of xs when f x}\n  else\n    result = [x for x in xs when f x]\n    if type is \\String then result * '' else result\n\nexport reject = (f, xs) -->\n  f = objToFunc f if typeof! f isnt \\Function\n  type = typeof! xs\n  if type is \\Object\n    {[key, x] for key, x of xs when not f x}\n  else\n    result = [x for x in xs when not f x]\n    if type is \\String then result * '' else result\n\nexport partition = (f, xs) -->\n  f = objToFunc f if typeof! f isnt \\Function\n  type = typeof! xs\n  if type is \\Object\n    passed = {}\n    failed = {}\n    for key, x of xs\n      (if f x then passed else failed)[key] = x\n  else\n    passed = []\n    failed = []\n    for x in xs\n      (if f x then passed else failed)push x\n    if type is \\String\n      passed *= ''\n      failed *= ''\n  [passed, failed]\n\nexport find = (f, xs) -->\n  f = objToFunc f if typeof! f isnt \\Function\n  if typeof! xs is \\Object\n    for , x of xs when f x then return x\n  else\n    for x in xs when f x then return x\n  void\n\nexport head = export first = (xs) ->\n  return void if not xs.length\n  xs.0\n\nexport tail = (xs) ->\n  return void if not xs.length\n  xs.slice 1\n\nexport last = (xs) ->\n  return void if not xs.length\n  xs[*-1]\n\nexport initial = (xs) ->\n  return void if not xs.length\n  xs.slice 0 xs.length - 1\n\nexport empty = (xs) ->\n  if typeof! xs is \\Object\n    for x of xs then return false\n    return yes\n  not xs.length\n\nexport values = (obj) ->\n  [x for , x of obj]\n\nexport keys = (obj) ->\n  [x for x of obj]\n\nexport len = (xs) ->\n  xs = values xs if typeof! xs is \\Object\n  xs.length\n\nexport cons = (x, xs) -->\n  if typeof! xs is \\String then x + xs else [x] ++ xs\n\nexport append = (xs, ys) -->\n  if typeof! ys is \\String then xs + ys else xs ++ ys\n\nexport join = (sep, xs) -->\n  xs = values xs if typeof! xs is \\Object\n  xs.join sep\n\nexport reverse = (xs) ->\n  if typeof! xs is \\String\n  then (xs / '')reverse! * ''\n  else xs.slice!reverse!\n\nexport fold = export foldl = (f, memo, xs) -->\n  if typeof! xs is \\Object\n    for , x of xs then memo = f memo, x\n  else\n    for x in xs then memo = f memo, x\n  memo\n\nexport fold1 = export foldl1 = (f, xs) --> fold f, xs.0, xs.slice 1\n\nexport foldr = (f, memo, xs) --> fold f, memo, xs.slice!reverse!\n\nexport foldr1 = (f, xs) -->\n  xs.=slice!reverse!\n  fold f, xs.0, xs.slice 1\n\nexport unfoldr = export unfold = (f, b) -->\n  if (f b)?\n    [that.0] ++ unfoldr f, that.1\n  else\n    []\n\nexport andList = (xs) ->\n  for x in xs when not x\n    return false\n  true\n\nexport orList = (xs) ->\n  for x in xs when x\n    return true\n  false\n\nexport any = (f, xs) -->\n  f = objToFunc f if typeof! f isnt \\Function\n  for x in xs when f x\n    return yes\n  no\n\nexport all = (f, xs) -->\n  f = objToFunc f if typeof! f isnt \\Function\n  for x in xs when not f x\n    return no\n  yes\n\nexport unique = (xs) ->\n  result = []\n  if typeof! xs is \\Object\n    for , x of xs when x not in result then result.push x\n  else\n    for x   in xs when x not in result then result.push x\n  if typeof! xs is \\String then result * '' else result\n\nexport sort = (xs) ->\n  xs.concat!sort (x, y) ->\n    | x > y =>  1\n    | x < y => -1\n    | _     =>  0\n\nexport sortBy = (f, xs) -->\n  return [] unless xs.length\n  xs.concat!sort f\n\nexport compare = (f, x, y) -->\n  | (f x) > (f y) =>  1\n  | (f x) < (f y) => -1\n  | otherwise     =>  0\n\nexport sum = (xs) ->\n  result = 0\n  if typeof! xs is \\Object\n    for , x of xs then result += x\n  else\n    for x   in xs then result += x\n  result\n\nexport product = (xs) ->\n  result = 1\n  if typeof! xs is \\Object\n    for , x of xs then result *= x\n  else\n    for x   in xs then result *= x\n  result\n\nexport mean = export average = (xs) -> (sum xs) / len xs\n\nexport concat = (xss) -> fold append, [], xss\n\nexport concatMap = (f, xs) --> fold ((memo, x) -> append memo, f x), [], xs\n\nexport listToObj = (xs) ->\n  {[x.0, x.1] for x in xs}\n\nexport maximum = (xs) -> fold1 (>?), xs\n\nexport minimum = (xs) -> fold1 (<?), xs\n\nexport scan = export scanl = (f, memo, xs) -->\n  last = memo\n  if typeof! xs is \\Object\n  then [memo] ++ [last = f last, x for , x of xs]\n  else [memo] ++ [last = f last, x for x in xs]\n\nexport scan1 = export scanl1 = (f, xs) --> scan f, xs.0, xs.slice 1\n\nexport scanr = (f, memo, xs) -->\n  xs.=slice!reverse!\n  scan f, memo, xs .reverse!\n\nexport scanr1 = (f, xs) -->\n  xs.=slice!reverse!\n  scan f, xs.0, xs.slice 1 .reverse!\n\nexport replicate = (n, x) -->\n  result = []\n  i = 0\n  while i < n, ++i then result.push x\n  result\n\nexport take = (n, xs) -->\n  | n <= 0\n    if typeof! xs is \\String then '' else []\n  | not xs.length => xs\n  | otherwise     => xs.slice 0, n\n\nexport drop = (n, xs) -->\n  | n <= 0        => xs\n  | not xs.length => xs\n  | otherwise     => xs.slice n\n\nexport splitAt = (n, xs) --> [(take n, xs), (drop n, xs)]\n\nexport takeWhile = (p, xs) -->\n  return xs if not xs.length\n  p = objToFunc p if typeof! p isnt \\Function\n  result = []\n  for x in xs\n    break if not p x\n    result.push x\n  if typeof! xs is \\String then result * '' else result\n\nexport dropWhile = (p, xs) -->\n  return xs if not xs.length\n  p = objToFunc p if typeof! p isnt \\Function\n  i = 0\n  for x in xs\n    break if not p x\n    ++i\n  drop i, xs\n\nexport span = (p, xs) --> [(takeWhile p, xs), (dropWhile p, xs)]\n\nexport breakIt = (p, xs) --> span (not) << p, xs\n\nexport zip = (xs, ys) -->\n  result = []\n  for zs, i in [xs, ys]\n    for z, j in zs\n      result.push [] if i is 0\n      result[j]?push z\n  result\n\nexport zipWith = (f,xs, ys) -->\n  f = objToFunc f if typeof! f isnt \\Function\n  if not xs.length or not ys.length\n    []\n  else\n    [f.apply this, zs for zs in zip.call this, xs, ys]\n\nexport zipAll = (...xss) ->\n  result = []\n  for xs, i in xss\n    for x, j in xs\n      result.push [] if i is 0\n      result[j]?push x\n  result\n\nexport zipAllWith = (f, ...xss) ->\n  f = objToFunc f if typeof! f isnt \\Function\n  if not xss.0.length or not xss.1.length\n    []\n  else\n    [f.apply this, xs for xs in zipAll.apply this, xss]\n\nexport compose = (...funcs) ->\n  ->\n    args = arguments\n    for f in funcs\n      args = [f.apply this, args]\n    args.0\n\nexport curry = (f) ->\n  curry$ f # using util method curry$ from livescript\n\nexport id = (x) -> x\n\nexport flip = (f, x, y) --> f y, x\n\nexport fix = (f) ->\n  ( (g, x) -> -> f(g g) ...arguments ) do\n    (g, x) -> -> f(g g) ...arguments\n\nexport lines = (str) ->\n  return [] if not str.length\n  str / \\\\n\n\nexport unlines = (strs) -> strs * \\\\n\n\nexport words = (str) ->\n  return [] if not str.length\n  str / /[ ]+/\n\nexport unwords = (strs) -> strs * ' '\n\nexport max = (>?)\n\nexport min = (<?)\n\nexport negate = (x) -> -x\n\nexport abs = Math.abs\n\nexport signum = (x) ->\n  | x < 0     => -1\n  | x > 0     =>  1\n  | otherwise =>  0\n\nexport quot = (x, y) --> ~~(x / y)\n\nexport rem = (%)\n\nexport div = (x, y) --> Math.floor x / y\n\nexport mod = (%%)\n\nexport recip = (1 /)\n\nexport pi = Math.PI\n\nexport tau = pi * 2\n\nexport exp = Math.exp\n\nexport sqrt = Math.sqrt\n\n# changed from log as log is a\n# common function for logging things\nexport ln = Math.log\n\nexport pow = (^)\n\nexport sin = Math.sin\n\nexport tan = Math.tan\n\nexport cos = Math.cos\n\nexport asin = Math.asin\n\nexport acos = Math.acos\n\nexport atan = Math.atan\n\nexport atan2 = (x, y) --> Math.atan2 x, y\n\n# sinh\n# tanh\n# cosh\n# asinh\n# atanh\n# acosh\n\nexport truncate = (x) -> ~~x\n\nexport round = Math.round\n\nexport ceiling = Math.ceil\n\nexport floor = Math.floor\n\nexport isItNaN = (x) -> x isnt x\n\nexport even = (x) -> x % 2 == 0\n\nexport odd = (x) -> x % 2 != 0\n\nexport gcd = (x, y) -->\n  x = Math.abs x\n  y = Math.abs y\n  until y is 0\n    z = x % y\n    x = y\n    y = z\n  x\n\nexport lcm = (x, y) -->\n  Math.abs Math.floor (x / (gcd x, y) * y)\n\n# meta\nexport installPrelude = !(target) ->\n  unless target.prelude?isInstalled\n    target <<< out$ # using out$ generated by livescript\n    target <<< target.prelude.isInstalled = true\n\nexport prelude = out$\n</textarea></form>\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        theme: \"solarized light\",\n        lineNumbers: true\n      });\n    </script>\n\n    <p><strong>MIME types defined:</strong> <code>text/x-livescript</code>.</p>\n\n    <p>The LiveScript mode was written by Kenneth Bentley.</p>\n\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/livescript/livescript.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n/**\n * Link to the project's GitHub page:\n * https://github.com/duralog/CodeMirror\n */\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n\n  CodeMirror.defineMode('livescript', function(){\n    var tokenBase = function(stream, state) {\n      var next_rule = state.next || \"start\";\n      if (next_rule) {\n        state.next = state.next;\n        var nr = Rules[next_rule];\n        if (nr.splice) {\n          for (var i$ = 0; i$ < nr.length; ++i$) {\n            var r = nr[i$], m;\n            if (r.regex && (m = stream.match(r.regex))) {\n              state.next = r.next || state.next;\n              return r.token;\n            }\n          }\n          stream.next();\n          return 'error';\n        }\n        if (stream.match(r = Rules[next_rule])) {\n          if (r.regex && stream.match(r.regex)) {\n            state.next = r.next;\n            return r.token;\n          } else {\n            stream.next();\n            return 'error';\n          }\n        }\n      }\n      stream.next();\n      return 'error';\n    };\n    var external = {\n      startState: function(){\n        return {\n          next: 'start',\n          lastToken: null\n        };\n      },\n      token: function(stream, state){\n        while (stream.pos == stream.start)\n          var style = tokenBase(stream, state);\n        state.lastToken = {\n          style: style,\n          indent: stream.indentation(),\n          content: stream.current()\n        };\n        return style.replace(/\\./g, ' ');\n      },\n      indent: function(state){\n        var indentation = state.lastToken.indent;\n        if (state.lastToken.content.match(indenter)) {\n          indentation += 2;\n        }\n        return indentation;\n      }\n    };\n    return external;\n  });\n\n  var identifier = '(?![\\\\d\\\\s])[$\\\\w\\\\xAA-\\\\uFFDC](?:(?!\\\\s)[$\\\\w\\\\xAA-\\\\uFFDC]|-[A-Za-z])*';\n  var indenter = RegExp('(?:[({[=:]|[-~]>|\\\\b(?:e(?:lse|xport)|d(?:o|efault)|t(?:ry|hen)|finally|import(?:\\\\s*all)?|const|var|let|new|catch(?:\\\\s*' + identifier + ')?))\\\\s*$');\n  var keywordend = '(?![$\\\\w]|-[A-Za-z]|\\\\s*:(?![:=]))';\n  var stringfill = {\n    token: 'string',\n    regex: '.+'\n  };\n  var Rules = {\n    start: [\n      {\n        token: 'comment.doc',\n        regex: '/\\\\*',\n        next: 'comment'\n      }, {\n        token: 'comment',\n        regex: '#.*'\n      }, {\n        token: 'keyword',\n        regex: '(?:t(?:h(?:is|row|en)|ry|ypeof!?)|c(?:on(?:tinue|st)|a(?:se|tch)|lass)|i(?:n(?:stanceof)?|mp(?:ort(?:\\\\s+all)?|lements)|[fs])|d(?:e(?:fault|lete|bugger)|o)|f(?:or(?:\\\\s+own)?|inally|unction)|s(?:uper|witch)|e(?:lse|x(?:tends|port)|val)|a(?:nd|rguments)|n(?:ew|ot)|un(?:less|til)|w(?:hile|ith)|o[fr]|return|break|let|var|loop)' + keywordend\n      }, {\n        token: 'constant.language',\n        regex: '(?:true|false|yes|no|on|off|null|void|undefined)' + keywordend\n      }, {\n        token: 'invalid.illegal',\n        regex: '(?:p(?:ackage|r(?:ivate|otected)|ublic)|i(?:mplements|nterface)|enum|static|yield)' + keywordend\n      }, {\n        token: 'language.support.class',\n        regex: '(?:R(?:e(?:gExp|ferenceError)|angeError)|S(?:tring|yntaxError)|E(?:rror|valError)|Array|Boolean|Date|Function|Number|Object|TypeError|URIError)' + keywordend\n      }, {\n        token: 'language.support.function',\n        regex: '(?:is(?:NaN|Finite)|parse(?:Int|Float)|Math|JSON|(?:en|de)codeURI(?:Component)?)' + keywordend\n      }, {\n        token: 'variable.language',\n        regex: '(?:t(?:hat|il|o)|f(?:rom|allthrough)|it|by|e)' + keywordend\n      }, {\n        token: 'identifier',\n        regex: identifier + '\\\\s*:(?![:=])'\n      }, {\n        token: 'variable',\n        regex: identifier\n      }, {\n        token: 'keyword.operator',\n        regex: '(?:\\\\.{3}|\\\\s+\\\\?)'\n      }, {\n        token: 'keyword.variable',\n        regex: '(?:@+|::|\\\\.\\\\.)',\n        next: 'key'\n      }, {\n        token: 'keyword.operator',\n        regex: '\\\\.\\\\s*',\n        next: 'key'\n      }, {\n        token: 'string',\n        regex: '\\\\\\\\\\\\S[^\\\\s,;)}\\\\]]*'\n      }, {\n        token: 'string.doc',\n        regex: '\\'\\'\\'',\n        next: 'qdoc'\n      }, {\n        token: 'string.doc',\n        regex: '\"\"\"',\n        next: 'qqdoc'\n      }, {\n        token: 'string',\n        regex: '\\'',\n        next: 'qstring'\n      }, {\n        token: 'string',\n        regex: '\"',\n        next: 'qqstring'\n      }, {\n        token: 'string',\n        regex: '`',\n        next: 'js'\n      }, {\n        token: 'string',\n        regex: '<\\\\[',\n        next: 'words'\n      }, {\n        token: 'string.regex',\n        regex: '//',\n        next: 'heregex'\n      }, {\n        token: 'string.regex',\n        regex: '\\\\/(?:[^[\\\\/\\\\n\\\\\\\\]*(?:(?:\\\\\\\\.|\\\\[[^\\\\]\\\\n\\\\\\\\]*(?:\\\\\\\\.[^\\\\]\\\\n\\\\\\\\]*)*\\\\])[^[\\\\/\\\\n\\\\\\\\]*)*)\\\\/[gimy$]{0,4}',\n        next: 'key'\n      }, {\n        token: 'constant.numeric',\n        regex: '(?:0x[\\\\da-fA-F][\\\\da-fA-F_]*|(?:[2-9]|[12]\\\\d|3[0-6])r[\\\\da-zA-Z][\\\\da-zA-Z_]*|(?:\\\\d[\\\\d_]*(?:\\\\.\\\\d[\\\\d_]*)?|\\\\.\\\\d[\\\\d_]*)(?:e[+-]?\\\\d[\\\\d_]*)?[\\\\w$]*)'\n      }, {\n        token: 'lparen',\n        regex: '[({[]'\n      }, {\n        token: 'rparen',\n        regex: '[)}\\\\]]',\n        next: 'key'\n      }, {\n        token: 'keyword.operator',\n        regex: '\\\\S+'\n      }, {\n        token: 'text',\n        regex: '\\\\s+'\n      }\n    ],\n    heregex: [\n      {\n        token: 'string.regex',\n        regex: '.*?//[gimy$?]{0,4}',\n        next: 'start'\n      }, {\n        token: 'string.regex',\n        regex: '\\\\s*#{'\n      }, {\n        token: 'comment.regex',\n        regex: '\\\\s+(?:#.*)?'\n      }, {\n        token: 'string.regex',\n        regex: '\\\\S+'\n      }\n    ],\n    key: [\n      {\n        token: 'keyword.operator',\n        regex: '[.?@!]+'\n      }, {\n        token: 'identifier',\n        regex: identifier,\n        next: 'start'\n      }, {\n        token: 'text',\n        regex: '',\n        next: 'start'\n      }\n    ],\n    comment: [\n      {\n        token: 'comment.doc',\n        regex: '.*?\\\\*/',\n        next: 'start'\n      }, {\n        token: 'comment.doc',\n        regex: '.+'\n      }\n    ],\n    qdoc: [\n      {\n        token: 'string',\n        regex: \".*?'''\",\n        next: 'key'\n      }, stringfill\n    ],\n    qqdoc: [\n      {\n        token: 'string',\n        regex: '.*?\"\"\"',\n        next: 'key'\n      }, stringfill\n    ],\n    qstring: [\n      {\n        token: 'string',\n        regex: '[^\\\\\\\\\\']*(?:\\\\\\\\.[^\\\\\\\\\\']*)*\\'',\n        next: 'key'\n      }, stringfill\n    ],\n    qqstring: [\n      {\n        token: 'string',\n        regex: '[^\\\\\\\\\"]*(?:\\\\\\\\.[^\\\\\\\\\"]*)*\"',\n        next: 'key'\n      }, stringfill\n    ],\n    js: [\n      {\n        token: 'string',\n        regex: '[^\\\\\\\\`]*(?:\\\\\\\\.[^\\\\\\\\`]*)*`',\n        next: 'key'\n      }, stringfill\n    ],\n    words: [\n      {\n        token: 'string',\n        regex: '.*?\\\\]>',\n        next: 'key'\n      }, stringfill\n    ]\n  };\n  for (var idx in Rules) {\n    var r = Rules[idx];\n    if (r.splice) {\n      for (var i = 0, len = r.length; i < len; ++i) {\n        var rr = r[i];\n        if (typeof rr.regex === 'string') {\n          Rules[idx][i].regex = new RegExp('^' + rr.regex);\n        }\n      }\n    } else if (typeof rr.regex === 'string') {\n      Rules[idx].regex = new RegExp('^' + r.regex);\n    }\n  }\n\n  CodeMirror.defineMIME('text/x-livescript', 'livescript');\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/lua/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Lua mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<link rel=\"stylesheet\" href=\"../../theme/neat.css\">\n<script src=\"../../addon/edit/matchbrackets.js\"></script>\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"lua.js\"></script>\n<style>.CodeMirror {border: 1px solid black;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Lua</a>\n  </ul>\n</div>\n\n<article>\n<h2>Lua mode</h2>\n<form><textarea id=\"code\" name=\"code\">\n--[[\nexample useless code to show lua syntax highlighting\nthis is multiline comment\n]]\n\nfunction blahblahblah(x)\n\n  local table = {\n    \"asd\" = 123,\n    \"x\" = 0.34,  \n  }\n  if x ~= 3 then\n    print( x )\n  elseif x == \"string\"\n    my_custom_function( 0x34 )\n  else\n    unknown_function( \"some string\" )\n  end\n\n  --single line comment\n  \nend\n\nfunction blablabla3()\n\n  for k,v in ipairs( table ) do\n    --abcde..\n    y=[=[\n  x=[[\n      x is a multi line string\n   ]]\n  but its definition is iside a highest level string!\n  ]=]\n    print(\" \\\"\\\" \")\n\n    s = math.sin( x )\n  end\n\nend\n</textarea></form>\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        matchBrackets: true,\n        theme: \"neat\"\n      });\n    </script>\n\n    <p>Loosely based on Franciszek\n    Wawrzak's <a href=\"http://codemirror.net/1/contrib/lua\">CodeMirror\n    1 mode</a>. One configuration parameter is\n    supported, <code>specials</code>, to which you can provide an\n    array of strings to have those identifiers highlighted with\n    the <code>lua-special</code> style.</p>\n    <p><strong>MIME types defined:</strong> <code>text/x-lua</code>.</p>\n\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/lua/lua.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n// LUA mode. Ported to CodeMirror 2 from Franciszek Wawrzak's\n// CodeMirror 1 mode.\n// highlights keywords, strings, comments (no leveling supported! (\"[==[\")), tokens, basic indenting\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"lua\", function(config, parserConfig) {\n  var indentUnit = config.indentUnit;\n\n  function prefixRE(words) {\n    return new RegExp(\"^(?:\" + words.join(\"|\") + \")\", \"i\");\n  }\n  function wordRE(words) {\n    return new RegExp(\"^(?:\" + words.join(\"|\") + \")$\", \"i\");\n  }\n  var specials = wordRE(parserConfig.specials || []);\n\n  // long list of standard functions from lua manual\n  var builtins = wordRE([\n    \"_G\",\"_VERSION\",\"assert\",\"collectgarbage\",\"dofile\",\"error\",\"getfenv\",\"getmetatable\",\"ipairs\",\"load\",\n    \"loadfile\",\"loadstring\",\"module\",\"next\",\"pairs\",\"pcall\",\"print\",\"rawequal\",\"rawget\",\"rawset\",\"require\",\n    \"select\",\"setfenv\",\"setmetatable\",\"tonumber\",\"tostring\",\"type\",\"unpack\",\"xpcall\",\n\n    \"coroutine.create\",\"coroutine.resume\",\"coroutine.running\",\"coroutine.status\",\"coroutine.wrap\",\"coroutine.yield\",\n\n    \"debug.debug\",\"debug.getfenv\",\"debug.gethook\",\"debug.getinfo\",\"debug.getlocal\",\"debug.getmetatable\",\n    \"debug.getregistry\",\"debug.getupvalue\",\"debug.setfenv\",\"debug.sethook\",\"debug.setlocal\",\"debug.setmetatable\",\n    \"debug.setupvalue\",\"debug.traceback\",\n\n    \"close\",\"flush\",\"lines\",\"read\",\"seek\",\"setvbuf\",\"write\",\n\n    \"io.close\",\"io.flush\",\"io.input\",\"io.lines\",\"io.open\",\"io.output\",\"io.popen\",\"io.read\",\"io.stderr\",\"io.stdin\",\n    \"io.stdout\",\"io.tmpfile\",\"io.type\",\"io.write\",\n\n    \"math.abs\",\"math.acos\",\"math.asin\",\"math.atan\",\"math.atan2\",\"math.ceil\",\"math.cos\",\"math.cosh\",\"math.deg\",\n    \"math.exp\",\"math.floor\",\"math.fmod\",\"math.frexp\",\"math.huge\",\"math.ldexp\",\"math.log\",\"math.log10\",\"math.max\",\n    \"math.min\",\"math.modf\",\"math.pi\",\"math.pow\",\"math.rad\",\"math.random\",\"math.randomseed\",\"math.sin\",\"math.sinh\",\n    \"math.sqrt\",\"math.tan\",\"math.tanh\",\n\n    \"os.clock\",\"os.date\",\"os.difftime\",\"os.execute\",\"os.exit\",\"os.getenv\",\"os.remove\",\"os.rename\",\"os.setlocale\",\n    \"os.time\",\"os.tmpname\",\n\n    \"package.cpath\",\"package.loaded\",\"package.loaders\",\"package.loadlib\",\"package.path\",\"package.preload\",\n    \"package.seeall\",\n\n    \"string.byte\",\"string.char\",\"string.dump\",\"string.find\",\"string.format\",\"string.gmatch\",\"string.gsub\",\n    \"string.len\",\"string.lower\",\"string.match\",\"string.rep\",\"string.reverse\",\"string.sub\",\"string.upper\",\n\n    \"table.concat\",\"table.insert\",\"table.maxn\",\"table.remove\",\"table.sort\"\n  ]);\n  var keywords = wordRE([\"and\",\"break\",\"elseif\",\"false\",\"nil\",\"not\",\"or\",\"return\",\n                         \"true\",\"function\", \"end\", \"if\", \"then\", \"else\", \"do\",\n                         \"while\", \"repeat\", \"until\", \"for\", \"in\", \"local\" ]);\n\n  var indentTokens = wordRE([\"function\", \"if\",\"repeat\",\"do\", \"\\\\(\", \"{\"]);\n  var dedentTokens = wordRE([\"end\", \"until\", \"\\\\)\", \"}\"]);\n  var dedentPartial = prefixRE([\"end\", \"until\", \"\\\\)\", \"}\", \"else\", \"elseif\"]);\n\n  function readBracket(stream) {\n    var level = 0;\n    while (stream.eat(\"=\")) ++level;\n    stream.eat(\"[\");\n    return level;\n  }\n\n  function normal(stream, state) {\n    var ch = stream.next();\n    if (ch == \"-\" && stream.eat(\"-\")) {\n      if (stream.eat(\"[\") && stream.eat(\"[\"))\n        return (state.cur = bracketed(readBracket(stream), \"comment\"))(stream, state);\n      stream.skipToEnd();\n      return \"comment\";\n    }\n    if (ch == \"\\\"\" || ch == \"'\")\n      return (state.cur = string(ch))(stream, state);\n    if (ch == \"[\" && /[\\[=]/.test(stream.peek()))\n      return (state.cur = bracketed(readBracket(stream), \"string\"))(stream, state);\n    if (/\\d/.test(ch)) {\n      stream.eatWhile(/[\\w.%]/);\n      return \"number\";\n    }\n    if (/[\\w_]/.test(ch)) {\n      stream.eatWhile(/[\\w\\\\\\-_.]/);\n      return \"variable\";\n    }\n    return null;\n  }\n\n  function bracketed(level, style) {\n    return function(stream, state) {\n      var curlev = null, ch;\n      while ((ch = stream.next()) != null) {\n        if (curlev == null) {if (ch == \"]\") curlev = 0;}\n        else if (ch == \"=\") ++curlev;\n        else if (ch == \"]\" && curlev == level) { state.cur = normal; break; }\n        else curlev = null;\n      }\n      return style;\n    };\n  }\n\n  function string(quote) {\n    return function(stream, state) {\n      var escaped = false, ch;\n      while ((ch = stream.next()) != null) {\n        if (ch == quote && !escaped) break;\n        escaped = !escaped && ch == \"\\\\\";\n      }\n      if (!escaped) state.cur = normal;\n      return \"string\";\n    };\n  }\n\n  return {\n    startState: function(basecol) {\n      return {basecol: basecol || 0, indentDepth: 0, cur: normal};\n    },\n\n    token: function(stream, state) {\n      if (stream.eatSpace()) return null;\n      var style = state.cur(stream, state);\n      var word = stream.current();\n      if (style == \"variable\") {\n        if (keywords.test(word)) style = \"keyword\";\n        else if (builtins.test(word)) style = \"builtin\";\n        else if (specials.test(word)) style = \"variable-2\";\n      }\n      if ((style != \"comment\") && (style != \"string\")){\n        if (indentTokens.test(word)) ++state.indentDepth;\n        else if (dedentTokens.test(word)) --state.indentDepth;\n      }\n      return style;\n    },\n\n    indent: function(state, textAfter) {\n      var closing = dedentPartial.test(textAfter);\n      return state.basecol + indentUnit * (state.indentDepth - (closing ? 1 : 0));\n    },\n\n    lineComment: \"--\",\n    blockCommentStart: \"--[[\",\n    blockCommentEnd: \"]]\"\n  };\n});\n\nCodeMirror.defineMIME(\"text/x-lua\", \"lua\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/markdown/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Markdown mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"../../addon/edit/continuelist.js\"></script>\n<script src=\"../xml/xml.js\"></script>\n<script src=\"markdown.js\"></script>\n<style type=\"text/css\">\n      .CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}\n      .cm-s-default .cm-trailing-space-a:before,\n      .cm-s-default .cm-trailing-space-b:before {position: absolute; content: \"\\00B7\"; color: #777;}\n      .cm-s-default .cm-trailing-space-new-line:before {position: absolute; content: \"\\21B5\"; color: #777;}\n    </style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Markdown</a>\n  </ul>\n</div>\n\n<article>\n<h2>Markdown mode</h2>\n<form><textarea id=\"code\" name=\"code\">\nMarkdown: Basics\n================\n\n&lt;ul id=\"ProjectSubmenu\"&gt;\n    &lt;li&gt;&lt;a href=\"/projects/markdown/\" title=\"Markdown Project Page\"&gt;Main&lt;/a&gt;&lt;/li&gt;\n    &lt;li&gt;&lt;a class=\"selected\" title=\"Markdown Basics\"&gt;Basics&lt;/a&gt;&lt;/li&gt;\n    &lt;li&gt;&lt;a href=\"/projects/markdown/syntax\" title=\"Markdown Syntax Documentation\"&gt;Syntax&lt;/a&gt;&lt;/li&gt;\n    &lt;li&gt;&lt;a href=\"/projects/markdown/license\" title=\"Pricing and License Information\"&gt;License&lt;/a&gt;&lt;/li&gt;\n    &lt;li&gt;&lt;a href=\"/projects/markdown/dingus\" title=\"Online Markdown Web Form\"&gt;Dingus&lt;/a&gt;&lt;/li&gt;\n&lt;/ul&gt;\n\n\nGetting the Gist of Markdown's Formatting Syntax\n------------------------------------------------\n\nThis page offers a brief overview of what it's like to use Markdown.\nThe [syntax page] [s] provides complete, detailed documentation for\nevery feature, but Markdown should be very easy to pick up simply by\nlooking at a few examples of it in action. The examples on this page\nare written in a before/after style, showing example syntax and the\nHTML output produced by Markdown.\n\nIt's also helpful to simply try Markdown out; the [Dingus] [d] is a\nweb application that allows you type your own Markdown-formatted text\nand translate it to XHTML.\n\n**Note:** This document is itself written using Markdown; you\ncan [see the source for it by adding '.text' to the URL] [src].\n\n  [s]: /projects/markdown/syntax  \"Markdown Syntax\"\n  [d]: /projects/markdown/dingus  \"Markdown Dingus\"\n  [src]: /projects/markdown/basics.text\n\n\n## Paragraphs, Headers, Blockquotes ##\n\nA paragraph is simply one or more consecutive lines of text, separated\nby one or more blank lines. (A blank line is any line that looks like\na blank line -- a line containing nothing but spaces or tabs is\nconsidered blank.) Normal paragraphs should not be indented with\nspaces or tabs.\n\nMarkdown offers two styles of headers: *Setext* and *atx*.\nSetext-style headers for `&lt;h1&gt;` and `&lt;h2&gt;` are created by\n\"underlining\" with equal signs (`=`) and hyphens (`-`), respectively.\nTo create an atx-style header, you put 1-6 hash marks (`#`) at the\nbeginning of the line -- the number of hashes equals the resulting\nHTML header level.\n\nBlockquotes are indicated using email-style '`&gt;`' angle brackets.\n\nMarkdown:\n\n    A First Level Header\n    ====================\n    \n    A Second Level Header\n    ---------------------\n\n    Now is the time for all good men to come to\n    the aid of their country. This is just a\n    regular paragraph.\n\n    The quick brown fox jumped over the lazy\n    dog's back.\n    \n    ### Header 3\n\n    &gt; This is a blockquote.\n    &gt; \n    &gt; This is the second paragraph in the blockquote.\n    &gt;\n    &gt; ## This is an H2 in a blockquote\n\n\nOutput:\n\n    &lt;h1&gt;A First Level Header&lt;/h1&gt;\n    \n    &lt;h2&gt;A Second Level Header&lt;/h2&gt;\n    \n    &lt;p&gt;Now is the time for all good men to come to\n    the aid of their country. This is just a\n    regular paragraph.&lt;/p&gt;\n    \n    &lt;p&gt;The quick brown fox jumped over the lazy\n    dog's back.&lt;/p&gt;\n    \n    &lt;h3&gt;Header 3&lt;/h3&gt;\n    \n    &lt;blockquote&gt;\n        &lt;p&gt;This is a blockquote.&lt;/p&gt;\n        \n        &lt;p&gt;This is the second paragraph in the blockquote.&lt;/p&gt;\n        \n        &lt;h2&gt;This is an H2 in a blockquote&lt;/h2&gt;\n    &lt;/blockquote&gt;\n\n\n\n### Phrase Emphasis ###\n\nMarkdown uses asterisks and underscores to indicate spans of emphasis.\n\nMarkdown:\n\n    Some of these words *are emphasized*.\n    Some of these words _are emphasized also_.\n    \n    Use two asterisks for **strong emphasis**.\n    Or, if you prefer, __use two underscores instead__.\n\nOutput:\n\n    &lt;p&gt;Some of these words &lt;em&gt;are emphasized&lt;/em&gt;.\n    Some of these words &lt;em&gt;are emphasized also&lt;/em&gt;.&lt;/p&gt;\n    \n    &lt;p&gt;Use two asterisks for &lt;strong&gt;strong emphasis&lt;/strong&gt;.\n    Or, if you prefer, &lt;strong&gt;use two underscores instead&lt;/strong&gt;.&lt;/p&gt;\n   \n\n\n## Lists ##\n\nUnordered (bulleted) lists use asterisks, pluses, and hyphens (`*`,\n`+`, and `-`) as list markers. These three markers are\ninterchangable; this:\n\n    *   Candy.\n    *   Gum.\n    *   Booze.\n\nthis:\n\n    +   Candy.\n    +   Gum.\n    +   Booze.\n\nand this:\n\n    -   Candy.\n    -   Gum.\n    -   Booze.\n\nall produce the same output:\n\n    &lt;ul&gt;\n    &lt;li&gt;Candy.&lt;/li&gt;\n    &lt;li&gt;Gum.&lt;/li&gt;\n    &lt;li&gt;Booze.&lt;/li&gt;\n    &lt;/ul&gt;\n\nOrdered (numbered) lists use regular numbers, followed by periods, as\nlist markers:\n\n    1.  Red\n    2.  Green\n    3.  Blue\n\nOutput:\n\n    &lt;ol&gt;\n    &lt;li&gt;Red&lt;/li&gt;\n    &lt;li&gt;Green&lt;/li&gt;\n    &lt;li&gt;Blue&lt;/li&gt;\n    &lt;/ol&gt;\n\nIf you put blank lines between items, you'll get `&lt;p&gt;` tags for the\nlist item text. You can create multi-paragraph list items by indenting\nthe paragraphs by 4 spaces or 1 tab:\n\n    *   A list item.\n    \n        With multiple paragraphs.\n\n    *   Another item in the list.\n\nOutput:\n\n    &lt;ul&gt;\n    &lt;li&gt;&lt;p&gt;A list item.&lt;/p&gt;\n    &lt;p&gt;With multiple paragraphs.&lt;/p&gt;&lt;/li&gt;\n    &lt;li&gt;&lt;p&gt;Another item in the list.&lt;/p&gt;&lt;/li&gt;\n    &lt;/ul&gt;\n    \n\n\n### Links ###\n\nMarkdown supports two styles for creating links: *inline* and\n*reference*. With both styles, you use square brackets to delimit the\ntext you want to turn into a link.\n\nInline-style links use parentheses immediately after the link text.\nFor example:\n\n    This is an [example link](http://example.com/).\n\nOutput:\n\n    &lt;p&gt;This is an &lt;a href=\"http://example.com/\"&gt;\n    example link&lt;/a&gt;.&lt;/p&gt;\n\nOptionally, you may include a title attribute in the parentheses:\n\n    This is an [example link](http://example.com/ \"With a Title\").\n\nOutput:\n\n    &lt;p&gt;This is an &lt;a href=\"http://example.com/\" title=\"With a Title\"&gt;\n    example link&lt;/a&gt;.&lt;/p&gt;\n\nReference-style links allow you to refer to your links by names, which\nyou define elsewhere in your document:\n\n    I get 10 times more traffic from [Google][1] than from\n    [Yahoo][2] or [MSN][3].\n\n    [1]: http://google.com/        \"Google\"\n    [2]: http://search.yahoo.com/  \"Yahoo Search\"\n    [3]: http://search.msn.com/    \"MSN Search\"\n\nOutput:\n\n    &lt;p&gt;I get 10 times more traffic from &lt;a href=\"http://google.com/\"\n    title=\"Google\"&gt;Google&lt;/a&gt; than from &lt;a href=\"http://search.yahoo.com/\"\n    title=\"Yahoo Search\"&gt;Yahoo&lt;/a&gt; or &lt;a href=\"http://search.msn.com/\"\n    title=\"MSN Search\"&gt;MSN&lt;/a&gt;.&lt;/p&gt;\n\nThe title attribute is optional. Link names may contain letters,\nnumbers and spaces, but are *not* case sensitive:\n\n    I start my morning with a cup of coffee and\n    [The New York Times][NY Times].\n\n    [ny times]: http://www.nytimes.com/\n\nOutput:\n\n    &lt;p&gt;I start my morning with a cup of coffee and\n    &lt;a href=\"http://www.nytimes.com/\"&gt;The New York Times&lt;/a&gt;.&lt;/p&gt;\n\n\n### Images ###\n\nImage syntax is very much like link syntax.\n\nInline (titles are optional):\n\n    ![alt text](/path/to/img.jpg \"Title\")\n\nReference-style:\n\n    ![alt text][id]\n\n    [id]: /path/to/img.jpg \"Title\"\n\nBoth of the above examples produce the same output:\n\n    &lt;img src=\"/path/to/img.jpg\" alt=\"alt text\" title=\"Title\" /&gt;\n\n\n\n### Code ###\n\nIn a regular paragraph, you can create code span by wrapping text in\nbacktick quotes. Any ampersands (`&amp;`) and angle brackets (`&lt;` or\n`&gt;`) will automatically be translated into HTML entities. This makes\nit easy to use Markdown to write about HTML example code:\n\n    I strongly recommend against using any `&lt;blink&gt;` tags.\n\n    I wish SmartyPants used named entities like `&amp;mdash;`\n    instead of decimal-encoded entites like `&amp;#8212;`.\n\nOutput:\n\n    &lt;p&gt;I strongly recommend against using any\n    &lt;code&gt;&amp;lt;blink&amp;gt;&lt;/code&gt; tags.&lt;/p&gt;\n    \n    &lt;p&gt;I wish SmartyPants used named entities like\n    &lt;code&gt;&amp;amp;mdash;&lt;/code&gt; instead of decimal-encoded\n    entites like &lt;code&gt;&amp;amp;#8212;&lt;/code&gt;.&lt;/p&gt;\n\n\nTo specify an entire block of pre-formatted code, indent every line of\nthe block by 4 spaces or 1 tab. Just like with code spans, `&amp;`, `&lt;`,\nand `&gt;` characters will be escaped automatically.\n\nMarkdown:\n\n    If you want your page to validate under XHTML 1.0 Strict,\n    you've got to put paragraph tags in your blockquotes:\n\n        &lt;blockquote&gt;\n            &lt;p&gt;For example.&lt;/p&gt;\n        &lt;/blockquote&gt;\n\nOutput:\n\n    &lt;p&gt;If you want your page to validate under XHTML 1.0 Strict,\n    you've got to put paragraph tags in your blockquotes:&lt;/p&gt;\n    \n    &lt;pre&gt;&lt;code&gt;&amp;lt;blockquote&amp;gt;\n        &amp;lt;p&amp;gt;For example.&amp;lt;/p&amp;gt;\n    &amp;lt;/blockquote&amp;gt;\n    &lt;/code&gt;&lt;/pre&gt;\n</textarea></form>\n\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        mode: 'markdown',\n        lineNumbers: true,\n        theme: \"default\",\n        extraKeys: {\"Enter\": \"newlineAndIndentContinueMarkdownList\"}\n      });\n    </script>\n\n    <p>Optionally depends on the XML mode for properly highlighted inline XML blocks.</p>\n\n    <p><strong>MIME types defined:</strong> <code>text/x-markdown</code>.</p>\n\n    <p><strong>Parsing/Highlighting Tests:</strong> <a href=\"../../test/index.html#markdown_*\">normal</a>,  <a href=\"../../test/index.html#verbose,markdown_*\">verbose</a>.</p>\n\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/markdown/markdown.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"), require(\"../xml/xml\"), require(\"../meta\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\", \"../xml/xml\", \"../meta\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"markdown\", function(cmCfg, modeCfg) {\n\n  var htmlFound = CodeMirror.modes.hasOwnProperty(\"xml\");\n  var htmlMode = CodeMirror.getMode(cmCfg, htmlFound ? {name: \"xml\", htmlMode: true} : \"text/plain\");\n\n  function getMode(name) {\n    if (CodeMirror.findModeByName) {\n      var found = CodeMirror.findModeByName(name);\n      if (found) name = found.mime || found.mimes[0];\n    }\n    var mode = CodeMirror.getMode(cmCfg, name);\n    return mode.name == \"null\" ? null : mode;\n  }\n\n  // Should characters that affect highlighting be highlighted separate?\n  // Does not include characters that will be output (such as `1.` and `-` for lists)\n  if (modeCfg.highlightFormatting === undefined)\n    modeCfg.highlightFormatting = false;\n\n  // Maximum number of nested blockquotes. Set to 0 for infinite nesting.\n  // Excess `>` will emit `error` token.\n  if (modeCfg.maxBlockquoteDepth === undefined)\n    modeCfg.maxBlockquoteDepth = 0;\n\n  // Should underscores in words open/close em/strong?\n  if (modeCfg.underscoresBreakWords === undefined)\n    modeCfg.underscoresBreakWords = true;\n\n  // Turn on fenced code blocks? (\"```\" to start/end)\n  if (modeCfg.fencedCodeBlocks === undefined) modeCfg.fencedCodeBlocks = false;\n\n  // Turn on task lists? (\"- [ ] \" and \"- [x] \")\n  if (modeCfg.taskLists === undefined) modeCfg.taskLists = false;\n\n  // Turn on strikethrough syntax\n  if (modeCfg.strikethrough === undefined)\n    modeCfg.strikethrough = false;\n\n  var codeDepth = 0;\n\n  var header   = 'header'\n  ,   code     = 'comment'\n  ,   quote    = 'quote'\n  ,   list1    = 'variable-2'\n  ,   list2    = 'variable-3'\n  ,   list3    = 'keyword'\n  ,   hr       = 'hr'\n  ,   image    = 'tag'\n  ,   formatting = 'formatting'\n  ,   linkinline = 'link'\n  ,   linkemail = 'link'\n  ,   linktext = 'link'\n  ,   linkhref = 'string'\n  ,   em       = 'em'\n  ,   strong   = 'strong'\n  ,   strikethrough = 'strikethrough';\n\n  var hrRE = /^([*\\-=_])(?:\\s*\\1){2,}\\s*$/\n  ,   ulRE = /^[*\\-+]\\s+/\n  ,   olRE = /^[0-9]+\\.\\s+/\n  ,   taskListRE = /^\\[(x| )\\](?=\\s)/ // Must follow ulRE or olRE\n  ,   atxHeaderRE = /^#+/\n  ,   setextHeaderRE = /^(?:\\={1,}|-{1,})$/\n  ,   textRE = /^[^#!\\[\\]*_\\\\<>` \"'(~]+/;\n\n  function switchInline(stream, state, f) {\n    state.f = state.inline = f;\n    return f(stream, state);\n  }\n\n  function switchBlock(stream, state, f) {\n    state.f = state.block = f;\n    return f(stream, state);\n  }\n\n\n  // Blocks\n\n  function blankLine(state) {\n    // Reset linkTitle state\n    state.linkTitle = false;\n    // Reset EM state\n    state.em = false;\n    // Reset STRONG state\n    state.strong = false;\n    // Reset strikethrough state\n    state.strikethrough = false;\n    // Reset state.quote\n    state.quote = 0;\n    if (!htmlFound && state.f == htmlBlock) {\n      state.f = inlineNormal;\n      state.block = blockNormal;\n    }\n    // Reset state.trailingSpace\n    state.trailingSpace = 0;\n    state.trailingSpaceNewLine = false;\n    // Mark this line as blank\n    state.thisLineHasContent = false;\n    return null;\n  }\n\n  function blockNormal(stream, state) {\n\n    var sol = stream.sol();\n\n    var prevLineIsList = (state.list !== false);\n    if (state.list !== false && state.indentationDiff >= 0) { // Continued list\n      if (state.indentationDiff < 4) { // Only adjust indentation if *not* a code block\n        state.indentation -= state.indentationDiff;\n      }\n      state.list = null;\n    } else if (state.list !== false && state.indentation > 0) {\n      state.list = null;\n      state.listDepth = Math.floor(state.indentation / 4);\n    } else if (state.list !== false) { // No longer a list\n      state.list = false;\n      state.listDepth = 0;\n    }\n\n    var match = null;\n    if (state.indentationDiff >= 4) {\n      state.indentation -= 4;\n      stream.skipToEnd();\n      return code;\n    } else if (stream.eatSpace()) {\n      return null;\n    } else if (match = stream.match(atxHeaderRE)) {\n      state.header = match[0].length <= 6 ? match[0].length : 6;\n      if (modeCfg.highlightFormatting) state.formatting = \"header\";\n      state.f = state.inline;\n      return getType(state);\n    } else if (state.prevLineHasContent && (match = stream.match(setextHeaderRE))) {\n      state.header = match[0].charAt(0) == '=' ? 1 : 2;\n      if (modeCfg.highlightFormatting) state.formatting = \"header\";\n      state.f = state.inline;\n      return getType(state);\n    } else if (stream.eat('>')) {\n      state.indentation++;\n      state.quote = sol ? 1 : state.quote + 1;\n      if (modeCfg.highlightFormatting) state.formatting = \"quote\";\n      stream.eatSpace();\n      return getType(state);\n    } else if (stream.peek() === '[') {\n      return switchInline(stream, state, footnoteLink);\n    } else if (stream.match(hrRE, true)) {\n      return hr;\n    } else if ((!state.prevLineHasContent || prevLineIsList) && (stream.match(ulRE, false) || stream.match(olRE, false))) {\n      var listType = null;\n      if (stream.match(ulRE, true)) {\n        listType = 'ul';\n      } else {\n        stream.match(olRE, true);\n        listType = 'ol';\n      }\n      state.indentation += 4;\n      state.list = true;\n      state.listDepth++;\n      if (modeCfg.taskLists && stream.match(taskListRE, false)) {\n        state.taskList = true;\n      }\n      state.f = state.inline;\n      if (modeCfg.highlightFormatting) state.formatting = [\"list\", \"list-\" + listType];\n      return getType(state);\n    } else if (modeCfg.fencedCodeBlocks && stream.match(/^```[ \\t]*([\\w+#]*)/, true)) {\n      // try switching mode\n      state.localMode = getMode(RegExp.$1);\n      if (state.localMode) state.localState = state.localMode.startState();\n      state.f = state.block = local;\n      if (modeCfg.highlightFormatting) state.formatting = \"code-block\";\n      state.code = true;\n      return getType(state);\n    }\n\n    return switchInline(stream, state, state.inline);\n  }\n\n  function htmlBlock(stream, state) {\n    var style = htmlMode.token(stream, state.htmlState);\n    if ((htmlFound && state.htmlState.tagStart === null && !state.htmlState.context) ||\n        (state.md_inside && stream.current().indexOf(\">\") > -1)) {\n      state.f = inlineNormal;\n      state.block = blockNormal;\n      state.htmlState = null;\n    }\n    return style;\n  }\n\n  function local(stream, state) {\n    if (stream.sol() && stream.match(\"```\", false)) {\n      state.localMode = state.localState = null;\n      state.f = state.block = leavingLocal;\n      return null;\n    } else if (state.localMode) {\n      return state.localMode.token(stream, state.localState);\n    } else {\n      stream.skipToEnd();\n      return code;\n    }\n  }\n\n  function leavingLocal(stream, state) {\n    stream.match(\"```\");\n    state.block = blockNormal;\n    state.f = inlineNormal;\n    if (modeCfg.highlightFormatting) state.formatting = \"code-block\";\n    state.code = true;\n    var returnType = getType(state);\n    state.code = false;\n    return returnType;\n  }\n\n  // Inline\n  function getType(state) {\n    var styles = [];\n\n    if (state.formatting) {\n      styles.push(formatting);\n\n      if (typeof state.formatting === \"string\") state.formatting = [state.formatting];\n\n      for (var i = 0; i < state.formatting.length; i++) {\n        styles.push(formatting + \"-\" + state.formatting[i]);\n\n        if (state.formatting[i] === \"header\") {\n          styles.push(formatting + \"-\" + state.formatting[i] + \"-\" + state.header);\n        }\n\n        // Add `formatting-quote` and `formatting-quote-#` for blockquotes\n        // Add `error` instead if the maximum blockquote nesting depth is passed\n        if (state.formatting[i] === \"quote\") {\n          if (!modeCfg.maxBlockquoteDepth || modeCfg.maxBlockquoteDepth >= state.quote) {\n            styles.push(formatting + \"-\" + state.formatting[i] + \"-\" + state.quote);\n          } else {\n            styles.push(\"error\");\n          }\n        }\n      }\n    }\n\n    if (state.taskOpen) {\n      styles.push(\"meta\");\n      return styles.length ? styles.join(' ') : null;\n    }\n    if (state.taskClosed) {\n      styles.push(\"property\");\n      return styles.length ? styles.join(' ') : null;\n    }\n\n    if (state.linkHref) {\n      styles.push(linkhref);\n      return styles.length ? styles.join(' ') : null;\n    }\n\n    if (state.strong) { styles.push(strong); }\n    if (state.em) { styles.push(em); }\n    if (state.strikethrough) { styles.push(strikethrough); }\n\n    if (state.linkText) { styles.push(linktext); }\n\n    if (state.code) { styles.push(code); }\n\n    if (state.header) { styles.push(header); styles.push(header + \"-\" + state.header); }\n\n    if (state.quote) {\n      styles.push(quote);\n\n      // Add `quote-#` where the maximum for `#` is modeCfg.maxBlockquoteDepth\n      if (!modeCfg.maxBlockquoteDepth || modeCfg.maxBlockquoteDepth >= state.quote) {\n        styles.push(quote + \"-\" + state.quote);\n      } else {\n        styles.push(quote + \"-\" + modeCfg.maxBlockquoteDepth);\n      }\n    }\n\n    if (state.list !== false) {\n      var listMod = (state.listDepth - 1) % 3;\n      if (!listMod) {\n        styles.push(list1);\n      } else if (listMod === 1) {\n        styles.push(list2);\n      } else {\n        styles.push(list3);\n      }\n    }\n\n    if (state.trailingSpaceNewLine) {\n      styles.push(\"trailing-space-new-line\");\n    } else if (state.trailingSpace) {\n      styles.push(\"trailing-space-\" + (state.trailingSpace % 2 ? \"a\" : \"b\"));\n    }\n\n    return styles.length ? styles.join(' ') : null;\n  }\n\n  function handleText(stream, state) {\n    if (stream.match(textRE, true)) {\n      return getType(state);\n    }\n    return undefined;\n  }\n\n  function inlineNormal(stream, state) {\n    var style = state.text(stream, state);\n    if (typeof style !== 'undefined')\n      return style;\n\n    if (state.list) { // List marker (*, +, -, 1., etc)\n      state.list = null;\n      return getType(state);\n    }\n\n    if (state.taskList) {\n      var taskOpen = stream.match(taskListRE, true)[1] !== \"x\";\n      if (taskOpen) state.taskOpen = true;\n      else state.taskClosed = true;\n      if (modeCfg.highlightFormatting) state.formatting = \"task\";\n      state.taskList = false;\n      return getType(state);\n    }\n\n    state.taskOpen = false;\n    state.taskClosed = false;\n\n    if (state.header && stream.match(/^#+$/, true)) {\n      if (modeCfg.highlightFormatting) state.formatting = \"header\";\n      return getType(state);\n    }\n\n    // Get sol() value now, before character is consumed\n    var sol = stream.sol();\n\n    var ch = stream.next();\n\n    if (ch === '\\\\') {\n      stream.next();\n      if (modeCfg.highlightFormatting) {\n        var type = getType(state);\n        return type ? type + \" formatting-escape\" : \"formatting-escape\";\n      }\n    }\n\n    // Matches link titles present on next line\n    if (state.linkTitle) {\n      state.linkTitle = false;\n      var matchCh = ch;\n      if (ch === '(') {\n        matchCh = ')';\n      }\n      matchCh = (matchCh+'').replace(/([.?*+^$[\\]\\\\(){}|-])/g, \"\\\\$1\");\n      var regex = '^\\\\s*(?:[^' + matchCh + '\\\\\\\\]+|\\\\\\\\\\\\\\\\|\\\\\\\\.)' + matchCh;\n      if (stream.match(new RegExp(regex), true)) {\n        return linkhref;\n      }\n    }\n\n    // If this block is changed, it may need to be updated in GFM mode\n    if (ch === '`') {\n      var previousFormatting = state.formatting;\n      if (modeCfg.highlightFormatting) state.formatting = \"code\";\n      var t = getType(state);\n      var before = stream.pos;\n      stream.eatWhile('`');\n      var difference = 1 + stream.pos - before;\n      if (!state.code) {\n        codeDepth = difference;\n        state.code = true;\n        return getType(state);\n      } else {\n        if (difference === codeDepth) { // Must be exact\n          state.code = false;\n          return t;\n        }\n        state.formatting = previousFormatting;\n        return getType(state);\n      }\n    } else if (state.code) {\n      return getType(state);\n    }\n\n    if (ch === '!' && stream.match(/\\[[^\\]]*\\] ?(?:\\(|\\[)/, false)) {\n      stream.match(/\\[[^\\]]*\\]/);\n      state.inline = state.f = linkHref;\n      return image;\n    }\n\n    if (ch === '[' && stream.match(/.*\\](\\(.*\\)| ?\\[.*\\])/, false)) {\n      state.linkText = true;\n      if (modeCfg.highlightFormatting) state.formatting = \"link\";\n      return getType(state);\n    }\n\n    if (ch === ']' && state.linkText && stream.match(/\\(.*\\)| ?\\[.*\\]/, false)) {\n      if (modeCfg.highlightFormatting) state.formatting = \"link\";\n      var type = getType(state);\n      state.linkText = false;\n      state.inline = state.f = linkHref;\n      return type;\n    }\n\n    if (ch === '<' && stream.match(/^(https?|ftps?):\\/\\/(?:[^\\\\>]|\\\\.)+>/, false)) {\n      state.f = state.inline = linkInline;\n      if (modeCfg.highlightFormatting) state.formatting = \"link\";\n      var type = getType(state);\n      if (type){\n        type += \" \";\n      } else {\n        type = \"\";\n      }\n      return type + linkinline;\n    }\n\n    if (ch === '<' && stream.match(/^[^> \\\\]+@(?:[^\\\\>]|\\\\.)+>/, false)) {\n      state.f = state.inline = linkInline;\n      if (modeCfg.highlightFormatting) state.formatting = \"link\";\n      var type = getType(state);\n      if (type){\n        type += \" \";\n      } else {\n        type = \"\";\n      }\n      return type + linkemail;\n    }\n\n    if (ch === '<' && stream.match(/^\\w/, false)) {\n      if (stream.string.indexOf(\">\") != -1) {\n        var atts = stream.string.substring(1,stream.string.indexOf(\">\"));\n        if (/markdown\\s*=\\s*('|\"){0,1}1('|\"){0,1}/.test(atts)) {\n          state.md_inside = true;\n        }\n      }\n      stream.backUp(1);\n      state.htmlState = CodeMirror.startState(htmlMode);\n      return switchBlock(stream, state, htmlBlock);\n    }\n\n    if (ch === '<' && stream.match(/^\\/\\w*?>/)) {\n      state.md_inside = false;\n      return \"tag\";\n    }\n\n    var ignoreUnderscore = false;\n    if (!modeCfg.underscoresBreakWords) {\n      if (ch === '_' && stream.peek() !== '_' && stream.match(/(\\w)/, false)) {\n        var prevPos = stream.pos - 2;\n        if (prevPos >= 0) {\n          var prevCh = stream.string.charAt(prevPos);\n          if (prevCh !== '_' && prevCh.match(/(\\w)/, false)) {\n            ignoreUnderscore = true;\n          }\n        }\n      }\n    }\n    if (ch === '*' || (ch === '_' && !ignoreUnderscore)) {\n      if (sol && stream.peek() === ' ') {\n        // Do nothing, surrounded by newline and space\n      } else if (state.strong === ch && stream.eat(ch)) { // Remove STRONG\n        if (modeCfg.highlightFormatting) state.formatting = \"strong\";\n        var t = getType(state);\n        state.strong = false;\n        return t;\n      } else if (!state.strong && stream.eat(ch)) { // Add STRONG\n        state.strong = ch;\n        if (modeCfg.highlightFormatting) state.formatting = \"strong\";\n        return getType(state);\n      } else if (state.em === ch) { // Remove EM\n        if (modeCfg.highlightFormatting) state.formatting = \"em\";\n        var t = getType(state);\n        state.em = false;\n        return t;\n      } else if (!state.em) { // Add EM\n        state.em = ch;\n        if (modeCfg.highlightFormatting) state.formatting = \"em\";\n        return getType(state);\n      }\n    } else if (ch === ' ') {\n      if (stream.eat('*') || stream.eat('_')) { // Probably surrounded by spaces\n        if (stream.peek() === ' ') { // Surrounded by spaces, ignore\n          return getType(state);\n        } else { // Not surrounded by spaces, back up pointer\n          stream.backUp(1);\n        }\n      }\n    }\n\n    if (modeCfg.strikethrough) {\n      if (ch === '~' && stream.eatWhile(ch)) {\n        if (state.strikethrough) {// Remove strikethrough\n          if (modeCfg.highlightFormatting) state.formatting = \"strikethrough\";\n          var t = getType(state);\n          state.strikethrough = false;\n          return t;\n        } else if (stream.match(/^[^\\s]/, false)) {// Add strikethrough\n          state.strikethrough = true;\n          if (modeCfg.highlightFormatting) state.formatting = \"strikethrough\";\n          return getType(state);\n        }\n      } else if (ch === ' ') {\n        if (stream.match(/^~~/, true)) { // Probably surrounded by space\n          if (stream.peek() === ' ') { // Surrounded by spaces, ignore\n            return getType(state);\n          } else { // Not surrounded by spaces, back up pointer\n            stream.backUp(2);\n          }\n        }\n      }\n    }\n\n    if (ch === ' ') {\n      if (stream.match(/ +$/, false)) {\n        state.trailingSpace++;\n      } else if (state.trailingSpace) {\n        state.trailingSpaceNewLine = true;\n      }\n    }\n\n    return getType(state);\n  }\n\n  function linkInline(stream, state) {\n    var ch = stream.next();\n\n    if (ch === \">\") {\n      state.f = state.inline = inlineNormal;\n      if (modeCfg.highlightFormatting) state.formatting = \"link\";\n      var type = getType(state);\n      if (type){\n        type += \" \";\n      } else {\n        type = \"\";\n      }\n      return type + linkinline;\n    }\n\n    stream.match(/^[^>]+/, true);\n\n    return linkinline;\n  }\n\n  function linkHref(stream, state) {\n    // Check if space, and return NULL if so (to avoid marking the space)\n    if(stream.eatSpace()){\n      return null;\n    }\n    var ch = stream.next();\n    if (ch === '(' || ch === '[') {\n      state.f = state.inline = getLinkHrefInside(ch === \"(\" ? \")\" : \"]\");\n      if (modeCfg.highlightFormatting) state.formatting = \"link-string\";\n      state.linkHref = true;\n      return getType(state);\n    }\n    return 'error';\n  }\n\n  function getLinkHrefInside(endChar) {\n    return function(stream, state) {\n      var ch = stream.next();\n\n      if (ch === endChar) {\n        state.f = state.inline = inlineNormal;\n        if (modeCfg.highlightFormatting) state.formatting = \"link-string\";\n        var returnState = getType(state);\n        state.linkHref = false;\n        return returnState;\n      }\n\n      if (stream.match(inlineRE(endChar), true)) {\n        stream.backUp(1);\n      }\n\n      state.linkHref = true;\n      return getType(state);\n    };\n  }\n\n  function footnoteLink(stream, state) {\n    if (stream.match(/^[^\\]]*\\]:/, false)) {\n      state.f = footnoteLinkInside;\n      stream.next(); // Consume [\n      if (modeCfg.highlightFormatting) state.formatting = \"link\";\n      state.linkText = true;\n      return getType(state);\n    }\n    return switchInline(stream, state, inlineNormal);\n  }\n\n  function footnoteLinkInside(stream, state) {\n    if (stream.match(/^\\]:/, true)) {\n      state.f = state.inline = footnoteUrl;\n      if (modeCfg.highlightFormatting) state.formatting = \"link\";\n      var returnType = getType(state);\n      state.linkText = false;\n      return returnType;\n    }\n\n    stream.match(/^[^\\]]+/, true);\n\n    return linktext;\n  }\n\n  function footnoteUrl(stream, state) {\n    // Check if space, and return NULL if so (to avoid marking the space)\n    if(stream.eatSpace()){\n      return null;\n    }\n    // Match URL\n    stream.match(/^[^\\s]+/, true);\n    // Check for link title\n    if (stream.peek() === undefined) { // End of line, set flag to check next line\n      state.linkTitle = true;\n    } else { // More content on line, check if link title\n      stream.match(/^(?:\\s+(?:\"(?:[^\"\\\\]|\\\\\\\\|\\\\.)+\"|'(?:[^'\\\\]|\\\\\\\\|\\\\.)+'|\\((?:[^)\\\\]|\\\\\\\\|\\\\.)+\\)))?/, true);\n    }\n    state.f = state.inline = inlineNormal;\n    return linkhref;\n  }\n\n  var savedInlineRE = [];\n  function inlineRE(endChar) {\n    if (!savedInlineRE[endChar]) {\n      // Escape endChar for RegExp (taken from http://stackoverflow.com/a/494122/526741)\n      endChar = (endChar+'').replace(/([.?*+^$[\\]\\\\(){}|-])/g, \"\\\\$1\");\n      // Match any non-endChar, escaped character, as well as the closing\n      // endChar.\n      savedInlineRE[endChar] = new RegExp('^(?:[^\\\\\\\\]|\\\\\\\\.)*?(' + endChar + ')');\n    }\n    return savedInlineRE[endChar];\n  }\n\n  var mode = {\n    startState: function() {\n      return {\n        f: blockNormal,\n\n        prevLineHasContent: false,\n        thisLineHasContent: false,\n\n        block: blockNormal,\n        htmlState: null,\n        indentation: 0,\n\n        inline: inlineNormal,\n        text: handleText,\n\n        formatting: false,\n        linkText: false,\n        linkHref: false,\n        linkTitle: false,\n        em: false,\n        strong: false,\n        header: 0,\n        taskList: false,\n        list: false,\n        listDepth: 0,\n        quote: 0,\n        trailingSpace: 0,\n        trailingSpaceNewLine: false,\n        strikethrough: false\n      };\n    },\n\n    copyState: function(s) {\n      return {\n        f: s.f,\n\n        prevLineHasContent: s.prevLineHasContent,\n        thisLineHasContent: s.thisLineHasContent,\n\n        block: s.block,\n        htmlState: s.htmlState && CodeMirror.copyState(htmlMode, s.htmlState),\n        indentation: s.indentation,\n\n        localMode: s.localMode,\n        localState: s.localMode ? CodeMirror.copyState(s.localMode, s.localState) : null,\n\n        inline: s.inline,\n        text: s.text,\n        formatting: false,\n        linkTitle: s.linkTitle,\n        em: s.em,\n        strong: s.strong,\n        strikethrough: s.strikethrough,\n        header: s.header,\n        taskList: s.taskList,\n        list: s.list,\n        listDepth: s.listDepth,\n        quote: s.quote,\n        trailingSpace: s.trailingSpace,\n        trailingSpaceNewLine: s.trailingSpaceNewLine,\n        md_inside: s.md_inside\n      };\n    },\n\n    token: function(stream, state) {\n\n      // Reset state.formatting\n      state.formatting = false;\n\n      if (stream.sol()) {\n        var forceBlankLine = !!state.header;\n\n        // Reset state.header\n        state.header = 0;\n\n        if (stream.match(/^\\s*$/, true) || forceBlankLine) {\n          state.prevLineHasContent = false;\n          blankLine(state);\n          return forceBlankLine ? this.token(stream, state) : null;\n        } else {\n          state.prevLineHasContent = state.thisLineHasContent;\n          state.thisLineHasContent = true;\n        }\n\n        // Reset state.taskList\n        state.taskList = false;\n\n        // Reset state.code\n        state.code = false;\n\n        // Reset state.trailingSpace\n        state.trailingSpace = 0;\n        state.trailingSpaceNewLine = false;\n\n        state.f = state.block;\n        var indentation = stream.match(/^\\s*/, true)[0].replace(/\\t/g, '    ').length;\n        var difference = Math.floor((indentation - state.indentation) / 4) * 4;\n        if (difference > 4) difference = 4;\n        var adjustedIndentation = state.indentation + difference;\n        state.indentationDiff = adjustedIndentation - state.indentation;\n        state.indentation = adjustedIndentation;\n        if (indentation > 0) return null;\n      }\n      return state.f(stream, state);\n    },\n\n    innerMode: function(state) {\n      if (state.block == htmlBlock) return {state: state.htmlState, mode: htmlMode};\n      if (state.localState) return {state: state.localState, mode: state.localMode};\n      return {state: state, mode: mode};\n    },\n\n    blankLine: blankLine,\n\n    getType: getType,\n\n    fold: \"markdown\"\n  };\n  return mode;\n}, \"xml\");\n\nCodeMirror.defineMIME(\"text/x-markdown\", \"markdown\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/markdown/test.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function() {\n  var mode = CodeMirror.getMode({tabSize: 4}, \"markdown\");\n  function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); }\n  var modeHighlightFormatting = CodeMirror.getMode({tabSize: 4}, {name: \"markdown\", highlightFormatting: true});\n  function FT(name) { test.mode(name, modeHighlightFormatting, Array.prototype.slice.call(arguments, 1)); }\n\n  FT(\"formatting_emAsterisk\",\n     \"[em&formatting&formatting-em *][em foo][em&formatting&formatting-em *]\");\n\n  FT(\"formatting_emUnderscore\",\n     \"[em&formatting&formatting-em _][em foo][em&formatting&formatting-em _]\");\n\n  FT(\"formatting_strongAsterisk\",\n     \"[strong&formatting&formatting-strong **][strong foo][strong&formatting&formatting-strong **]\");\n\n  FT(\"formatting_strongUnderscore\",\n     \"[strong&formatting&formatting-strong __][strong foo][strong&formatting&formatting-strong __]\");\n\n  FT(\"formatting_codeBackticks\",\n     \"[comment&formatting&formatting-code `][comment foo][comment&formatting&formatting-code `]\");\n\n  FT(\"formatting_doubleBackticks\",\n     \"[comment&formatting&formatting-code ``][comment foo ` bar][comment&formatting&formatting-code ``]\");\n\n  FT(\"formatting_atxHeader\",\n     \"[header&header-1&formatting&formatting-header&formatting-header-1 #][header&header-1  foo # bar ][header&header-1&formatting&formatting-header&formatting-header-1 #]\");\n\n  FT(\"formatting_setextHeader\",\n     \"foo\",\n     \"[header&header-1&formatting&formatting-header&formatting-header-1 =]\");\n\n  FT(\"formatting_blockquote\",\n     \"[quote&quote-1&formatting&formatting-quote&formatting-quote-1 > ][quote&quote-1 foo]\");\n\n  FT(\"formatting_list\",\n     \"[variable-2&formatting&formatting-list&formatting-list-ul - ][variable-2 foo]\");\n  FT(\"formatting_list\",\n     \"[variable-2&formatting&formatting-list&formatting-list-ol 1. ][variable-2 foo]\");\n\n  FT(\"formatting_link\",\n     \"[link&formatting&formatting-link [][link foo][link&formatting&formatting-link ]]][string&formatting&formatting-link-string (][string http://example.com/][string&formatting&formatting-link-string )]\");\n\n  FT(\"formatting_linkReference\",\n     \"[link&formatting&formatting-link [][link foo][link&formatting&formatting-link ]]][string&formatting&formatting-link-string [][string bar][string&formatting&formatting-link-string ]]]\",\n     \"[link&formatting&formatting-link [][link bar][link&formatting&formatting-link ]]:] [string http://example.com/]\");\n\n  FT(\"formatting_linkWeb\",\n     \"[link&formatting&formatting-link <][link http://example.com/][link&formatting&formatting-link >]\");\n\n  FT(\"formatting_linkEmail\",\n     \"[link&formatting&formatting-link <][link user@example.com][link&formatting&formatting-link >]\");\n\n  FT(\"formatting_escape\",\n     \"[formatting-escape \\\\*]\");\n\n  MT(\"plainText\",\n     \"foo\");\n\n  // Don't style single trailing space\n  MT(\"trailingSpace1\",\n     \"foo \");\n\n  // Two or more trailing spaces should be styled with line break character\n  MT(\"trailingSpace2\",\n     \"foo[trailing-space-a  ][trailing-space-new-line  ]\");\n\n  MT(\"trailingSpace3\",\n     \"foo[trailing-space-a  ][trailing-space-b  ][trailing-space-new-line  ]\");\n\n  MT(\"trailingSpace4\",\n     \"foo[trailing-space-a  ][trailing-space-b  ][trailing-space-a  ][trailing-space-new-line  ]\");\n\n  // Code blocks using 4 spaces (regardless of CodeMirror.tabSize value)\n  MT(\"codeBlocksUsing4Spaces\",\n     \"    [comment foo]\");\n\n  // Code blocks using 4 spaces with internal indentation\n  MT(\"codeBlocksUsing4SpacesIndentation\",\n     \"    [comment bar]\",\n     \"        [comment hello]\",\n     \"            [comment world]\",\n     \"    [comment foo]\",\n     \"bar\");\n\n  // Code blocks using 4 spaces with internal indentation\n  MT(\"codeBlocksUsing4SpacesIndentation\",\n     \" foo\",\n     \"    [comment bar]\",\n     \"        [comment hello]\",\n     \"    [comment world]\");\n\n  // Code blocks should end even after extra indented lines\n  MT(\"codeBlocksWithTrailingIndentedLine\",\n     \"    [comment foo]\",\n     \"        [comment bar]\",\n     \"    [comment baz]\",\n     \"    \",\n     \"hello\");\n\n  // Code blocks using 1 tab (regardless of CodeMirror.indentWithTabs value)\n  MT(\"codeBlocksUsing1Tab\",\n     \"\\t[comment foo]\");\n\n  // Inline code using backticks\n  MT(\"inlineCodeUsingBackticks\",\n     \"foo [comment `bar`]\");\n\n  // Block code using single backtick (shouldn't work)\n  MT(\"blockCodeSingleBacktick\",\n     \"[comment `]\",\n     \"foo\",\n     \"[comment `]\");\n\n  // Unclosed backticks\n  // Instead of simply marking as CODE, it would be nice to have an\n  // incomplete flag for CODE, that is styled slightly different.\n  MT(\"unclosedBackticks\",\n     \"foo [comment `bar]\");\n\n  // Per documentation: \"To include a literal backtick character within a\n  // code span, you can use multiple backticks as the opening and closing\n  // delimiters\"\n  MT(\"doubleBackticks\",\n     \"[comment ``foo ` bar``]\");\n\n  // Tests based on Dingus\n  // http://daringfireball.net/projects/markdown/dingus\n  //\n  // Multiple backticks within an inline code block\n  MT(\"consecutiveBackticks\",\n     \"[comment `foo```bar`]\");\n\n  // Multiple backticks within an inline code block with a second code block\n  MT(\"consecutiveBackticks\",\n     \"[comment `foo```bar`] hello [comment `world`]\");\n\n  // Unclosed with several different groups of backticks\n  MT(\"unclosedBackticks\",\n     \"[comment ``foo ``` bar` hello]\");\n\n  // Closed with several different groups of backticks\n  MT(\"closedBackticks\",\n     \"[comment ``foo ``` bar` hello``] world\");\n\n  // atx headers\n  // http://daringfireball.net/projects/markdown/syntax#header\n\n  MT(\"atxH1\",\n     \"[header&header-1 # foo]\");\n\n  MT(\"atxH2\",\n     \"[header&header-2 ## foo]\");\n\n  MT(\"atxH3\",\n     \"[header&header-3 ### foo]\");\n\n  MT(\"atxH4\",\n     \"[header&header-4 #### foo]\");\n\n  MT(\"atxH5\",\n     \"[header&header-5 ##### foo]\");\n\n  MT(\"atxH6\",\n     \"[header&header-6 ###### foo]\");\n\n  // H6 - 7x '#' should still be H6, per Dingus\n  // http://daringfireball.net/projects/markdown/dingus\n  MT(\"atxH6NotH7\",\n     \"[header&header-6 ####### foo]\");\n\n  // Inline styles should be parsed inside headers\n  MT(\"atxH1inline\",\n     \"[header&header-1 # foo ][header&header-1&em *bar*]\");\n\n  // Setext headers - H1, H2\n  // Per documentation, \"Any number of underlining =’s or -’s will work.\"\n  // http://daringfireball.net/projects/markdown/syntax#header\n  // Ideally, the text would be marked as `header` as well, but this is\n  // not really feasible at the moment. So, instead, we're testing against\n  // what works today, to avoid any regressions.\n  //\n  // Check if single underlining = works\n  MT(\"setextH1\",\n     \"foo\",\n     \"[header&header-1 =]\");\n\n  // Check if 3+ ='s work\n  MT(\"setextH1\",\n     \"foo\",\n     \"[header&header-1 ===]\");\n\n  // Check if single underlining - works\n  MT(\"setextH2\",\n     \"foo\",\n     \"[header&header-2 -]\");\n\n  // Check if 3+ -'s work\n  MT(\"setextH2\",\n     \"foo\",\n     \"[header&header-2 ---]\");\n\n  // Single-line blockquote with trailing space\n  MT(\"blockquoteSpace\",\n     \"[quote&quote-1 > foo]\");\n\n  // Single-line blockquote\n  MT(\"blockquoteNoSpace\",\n     \"[quote&quote-1 >foo]\");\n\n  // No blank line before blockquote\n  MT(\"blockquoteNoBlankLine\",\n     \"foo\",\n     \"[quote&quote-1 > bar]\");\n\n  // Nested blockquote\n  MT(\"blockquoteSpace\",\n     \"[quote&quote-1 > foo]\",\n     \"[quote&quote-1 >][quote&quote-2 > foo]\",\n     \"[quote&quote-1 >][quote&quote-2 >][quote&quote-3 > foo]\");\n\n  // Single-line blockquote followed by normal paragraph\n  MT(\"blockquoteThenParagraph\",\n     \"[quote&quote-1 >foo]\",\n     \"\",\n     \"bar\");\n\n  // Multi-line blockquote (lazy mode)\n  MT(\"multiBlockquoteLazy\",\n     \"[quote&quote-1 >foo]\",\n     \"[quote&quote-1 bar]\");\n\n  // Multi-line blockquote followed by normal paragraph (lazy mode)\n  MT(\"multiBlockquoteLazyThenParagraph\",\n     \"[quote&quote-1 >foo]\",\n     \"[quote&quote-1 bar]\",\n     \"\",\n     \"hello\");\n\n  // Multi-line blockquote (non-lazy mode)\n  MT(\"multiBlockquote\",\n     \"[quote&quote-1 >foo]\",\n     \"[quote&quote-1 >bar]\");\n\n  // Multi-line blockquote followed by normal paragraph (non-lazy mode)\n  MT(\"multiBlockquoteThenParagraph\",\n     \"[quote&quote-1 >foo]\",\n     \"[quote&quote-1 >bar]\",\n     \"\",\n     \"hello\");\n\n  // Check list types\n\n  MT(\"listAsterisk\",\n     \"foo\",\n     \"bar\",\n     \"\",\n     \"[variable-2 * foo]\",\n     \"[variable-2 * bar]\");\n\n  MT(\"listPlus\",\n     \"foo\",\n     \"bar\",\n     \"\",\n     \"[variable-2 + foo]\",\n     \"[variable-2 + bar]\");\n\n  MT(\"listDash\",\n     \"foo\",\n     \"bar\",\n     \"\",\n     \"[variable-2 - foo]\",\n     \"[variable-2 - bar]\");\n\n  MT(\"listNumber\",\n     \"foo\",\n     \"bar\",\n     \"\",\n     \"[variable-2 1. foo]\",\n     \"[variable-2 2. bar]\");\n\n  // Lists require a preceding blank line (per Dingus)\n  MT(\"listBogus\",\n     \"foo\",\n     \"1. bar\",\n     \"2. hello\");\n\n  // List after header\n  MT(\"listAfterHeader\",\n     \"[header&header-1 # foo]\",\n     \"[variable-2 - bar]\");\n\n  // Formatting in lists (*)\n  MT(\"listAsteriskFormatting\",\n     \"[variable-2 * ][variable-2&em *foo*][variable-2  bar]\",\n     \"[variable-2 * ][variable-2&strong **foo**][variable-2  bar]\",\n     \"[variable-2 * ][variable-2&strong **][variable-2&em&strong *foo**][variable-2&em *][variable-2  bar]\",\n     \"[variable-2 * ][variable-2&comment `foo`][variable-2  bar]\");\n\n  // Formatting in lists (+)\n  MT(\"listPlusFormatting\",\n     \"[variable-2 + ][variable-2&em *foo*][variable-2  bar]\",\n     \"[variable-2 + ][variable-2&strong **foo**][variable-2  bar]\",\n     \"[variable-2 + ][variable-2&strong **][variable-2&em&strong *foo**][variable-2&em *][variable-2  bar]\",\n     \"[variable-2 + ][variable-2&comment `foo`][variable-2  bar]\");\n\n  // Formatting in lists (-)\n  MT(\"listDashFormatting\",\n     \"[variable-2 - ][variable-2&em *foo*][variable-2  bar]\",\n     \"[variable-2 - ][variable-2&strong **foo**][variable-2  bar]\",\n     \"[variable-2 - ][variable-2&strong **][variable-2&em&strong *foo**][variable-2&em *][variable-2  bar]\",\n     \"[variable-2 - ][variable-2&comment `foo`][variable-2  bar]\");\n\n  // Formatting in lists (1.)\n  MT(\"listNumberFormatting\",\n     \"[variable-2 1. ][variable-2&em *foo*][variable-2  bar]\",\n     \"[variable-2 2. ][variable-2&strong **foo**][variable-2  bar]\",\n     \"[variable-2 3. ][variable-2&strong **][variable-2&em&strong *foo**][variable-2&em *][variable-2  bar]\",\n     \"[variable-2 4. ][variable-2&comment `foo`][variable-2  bar]\");\n\n  // Paragraph lists\n  MT(\"listParagraph\",\n     \"[variable-2 * foo]\",\n     \"\",\n     \"[variable-2 * bar]\");\n\n  // Multi-paragraph lists\n  //\n  // 4 spaces\n  MT(\"listMultiParagraph\",\n     \"[variable-2 * foo]\",\n     \"\",\n     \"[variable-2 * bar]\",\n     \"\",\n     \"    [variable-2 hello]\");\n\n  // 4 spaces, extra blank lines (should still be list, per Dingus)\n  MT(\"listMultiParagraphExtra\",\n     \"[variable-2 * foo]\",\n     \"\",\n     \"[variable-2 * bar]\",\n     \"\",\n     \"\",\n     \"    [variable-2 hello]\");\n\n  // 4 spaces, plus 1 space (should still be list, per Dingus)\n  MT(\"listMultiParagraphExtraSpace\",\n     \"[variable-2 * foo]\",\n     \"\",\n     \"[variable-2 * bar]\",\n     \"\",\n     \"     [variable-2 hello]\",\n     \"\",\n     \"    [variable-2 world]\");\n\n  // 1 tab\n  MT(\"listTab\",\n     \"[variable-2 * foo]\",\n     \"\",\n     \"[variable-2 * bar]\",\n     \"\",\n     \"\\t[variable-2 hello]\");\n\n  // No indent\n  MT(\"listNoIndent\",\n     \"[variable-2 * foo]\",\n     \"\",\n     \"[variable-2 * bar]\",\n     \"\",\n     \"hello\");\n\n  // Blockquote\n  MT(\"blockquote\",\n     \"[variable-2 * foo]\",\n     \"\",\n     \"[variable-2 * bar]\",\n     \"\",\n     \"    [variable-2&quote&quote-1 > hello]\");\n\n  // Code block\n  MT(\"blockquoteCode\",\n     \"[variable-2 * foo]\",\n     \"\",\n     \"[variable-2 * bar]\",\n     \"\",\n     \"        [comment > hello]\",\n     \"\",\n     \"    [variable-2 world]\");\n\n  // Code block followed by text\n  MT(\"blockquoteCodeText\",\n     \"[variable-2 * foo]\",\n     \"\",\n     \"    [variable-2 bar]\",\n     \"\",\n     \"        [comment hello]\",\n     \"\",\n     \"    [variable-2 world]\");\n\n  // Nested list\n\n  MT(\"listAsteriskNested\",\n     \"[variable-2 * foo]\",\n     \"\",\n     \"    [variable-3 * bar]\");\n\n  MT(\"listPlusNested\",\n     \"[variable-2 + foo]\",\n     \"\",\n     \"    [variable-3 + bar]\");\n\n  MT(\"listDashNested\",\n     \"[variable-2 - foo]\",\n     \"\",\n     \"    [variable-3 - bar]\");\n\n  MT(\"listNumberNested\",\n     \"[variable-2 1. foo]\",\n     \"\",\n     \"    [variable-3 2. bar]\");\n\n  MT(\"listMixed\",\n     \"[variable-2 * foo]\",\n     \"\",\n     \"    [variable-3 + bar]\",\n     \"\",\n     \"        [keyword - hello]\",\n     \"\",\n     \"            [variable-2 1. world]\");\n\n  MT(\"listBlockquote\",\n     \"[variable-2 * foo]\",\n     \"\",\n     \"    [variable-3 + bar]\",\n     \"\",\n     \"        [quote&quote-1&variable-3 > hello]\");\n\n  MT(\"listCode\",\n     \"[variable-2 * foo]\",\n     \"\",\n     \"    [variable-3 + bar]\",\n     \"\",\n     \"            [comment hello]\");\n\n  // Code with internal indentation\n  MT(\"listCodeIndentation\",\n     \"[variable-2 * foo]\",\n     \"\",\n     \"        [comment bar]\",\n     \"            [comment hello]\",\n     \"                [comment world]\",\n     \"        [comment foo]\",\n     \"    [variable-2 bar]\");\n\n  // List nesting edge cases\n  MT(\"listNested\",\n    \"[variable-2 * foo]\",\n    \"\",\n    \"    [variable-3 * bar]\",\n    \"\",\n    \"       [variable-2 hello]\"\n  );\n  MT(\"listNested\",\n    \"[variable-2 * foo]\",\n    \"\",\n    \"    [variable-3 * bar]\",\n    \"\",\n    \"      [variable-3 * foo]\"\n  );\n\n  // Code followed by text\n  MT(\"listCodeText\",\n     \"[variable-2 * foo]\",\n     \"\",\n     \"        [comment bar]\",\n     \"\",\n     \"hello\");\n\n  // Following tests directly from official Markdown documentation\n  // http://daringfireball.net/projects/markdown/syntax#hr\n\n  MT(\"hrSpace\",\n     \"[hr * * *]\");\n\n  MT(\"hr\",\n     \"[hr ***]\");\n\n  MT(\"hrLong\",\n     \"[hr *****]\");\n\n  MT(\"hrSpaceDash\",\n     \"[hr - - -]\");\n\n  MT(\"hrDashLong\",\n     \"[hr ---------------------------------------]\");\n\n  // Inline link with title\n  MT(\"linkTitle\",\n     \"[link [[foo]]][string (http://example.com/ \\\"bar\\\")] hello\");\n\n  // Inline link without title\n  MT(\"linkNoTitle\",\n     \"[link [[foo]]][string (http://example.com/)] bar\");\n\n  // Inline link with image\n  MT(\"linkImage\",\n     \"[link [[][tag ![[foo]]][string (http://example.com/)][link ]]][string (http://example.com/)] bar\");\n\n  // Inline link with Em\n  MT(\"linkEm\",\n     \"[link [[][link&em *foo*][link ]]][string (http://example.com/)] bar\");\n\n  // Inline link with Strong\n  MT(\"linkStrong\",\n     \"[link [[][link&strong **foo**][link ]]][string (http://example.com/)] bar\");\n\n  // Inline link with EmStrong\n  MT(\"linkEmStrong\",\n     \"[link [[][link&strong **][link&em&strong *foo**][link&em *][link ]]][string (http://example.com/)] bar\");\n\n  // Image with title\n  MT(\"imageTitle\",\n     \"[tag ![[foo]]][string (http://example.com/ \\\"bar\\\")] hello\");\n\n  // Image without title\n  MT(\"imageNoTitle\",\n     \"[tag ![[foo]]][string (http://example.com/)] bar\");\n\n  // Image with asterisks\n  MT(\"imageAsterisks\",\n     \"[tag ![[*foo*]]][string (http://example.com/)] bar\");\n\n  // Not a link. Should be normal text due to square brackets being used\n  // regularly in text, especially in quoted material, and no space is allowed\n  // between square brackets and parentheses (per Dingus).\n  MT(\"notALink\",\n     \"[[foo]] (bar)\");\n\n  // Reference-style links\n  MT(\"linkReference\",\n     \"[link [[foo]]][string [[bar]]] hello\");\n\n  // Reference-style links with Em\n  MT(\"linkReferenceEm\",\n     \"[link [[][link&em *foo*][link ]]][string [[bar]]] hello\");\n\n  // Reference-style links with Strong\n  MT(\"linkReferenceStrong\",\n     \"[link [[][link&strong **foo**][link ]]][string [[bar]]] hello\");\n\n  // Reference-style links with EmStrong\n  MT(\"linkReferenceEmStrong\",\n     \"[link [[][link&strong **][link&em&strong *foo**][link&em *][link ]]][string [[bar]]] hello\");\n\n  // Reference-style links with optional space separator (per docuentation)\n  // \"You can optionally use a space to separate the sets of brackets\"\n  MT(\"linkReferenceSpace\",\n     \"[link [[foo]]] [string [[bar]]] hello\");\n\n  // Should only allow a single space (\"...use *a* space...\")\n  MT(\"linkReferenceDoubleSpace\",\n     \"[[foo]]  [[bar]] hello\");\n\n  // Reference-style links with implicit link name\n  MT(\"linkImplicit\",\n     \"[link [[foo]]][string [[]]] hello\");\n\n  // @todo It would be nice if, at some point, the document was actually\n  // checked to see if the referenced link exists\n\n  // Link label, for reference-style links (taken from documentation)\n\n  MT(\"labelNoTitle\",\n     \"[link [[foo]]:] [string http://example.com/]\");\n\n  MT(\"labelIndented\",\n     \"   [link [[foo]]:] [string http://example.com/]\");\n\n  MT(\"labelSpaceTitle\",\n     \"[link [[foo bar]]:] [string http://example.com/ \\\"hello\\\"]\");\n\n  MT(\"labelDoubleTitle\",\n     \"[link [[foo bar]]:] [string http://example.com/ \\\"hello\\\"] \\\"world\\\"\");\n\n  MT(\"labelTitleDoubleQuotes\",\n     \"[link [[foo]]:] [string http://example.com/  \\\"bar\\\"]\");\n\n  MT(\"labelTitleSingleQuotes\",\n     \"[link [[foo]]:] [string http://example.com/  'bar']\");\n\n  MT(\"labelTitleParenthese\",\n     \"[link [[foo]]:] [string http://example.com/  (bar)]\");\n\n  MT(\"labelTitleInvalid\",\n     \"[link [[foo]]:] [string http://example.com/] bar\");\n\n  MT(\"labelLinkAngleBrackets\",\n     \"[link [[foo]]:] [string <http://example.com/>  \\\"bar\\\"]\");\n\n  MT(\"labelTitleNextDoubleQuotes\",\n     \"[link [[foo]]:] [string http://example.com/]\",\n     \"[string \\\"bar\\\"] hello\");\n\n  MT(\"labelTitleNextSingleQuotes\",\n     \"[link [[foo]]:] [string http://example.com/]\",\n     \"[string 'bar'] hello\");\n\n  MT(\"labelTitleNextParenthese\",\n     \"[link [[foo]]:] [string http://example.com/]\",\n     \"[string (bar)] hello\");\n\n  MT(\"labelTitleNextMixed\",\n     \"[link [[foo]]:] [string http://example.com/]\",\n     \"(bar\\\" hello\");\n\n  MT(\"linkWeb\",\n     \"[link <http://example.com/>] foo\");\n\n  MT(\"linkWebDouble\",\n     \"[link <http://example.com/>] foo [link <http://example.com/>]\");\n\n  MT(\"linkEmail\",\n     \"[link <user@example.com>] foo\");\n\n  MT(\"linkEmailDouble\",\n     \"[link <user@example.com>] foo [link <user@example.com>]\");\n\n  MT(\"emAsterisk\",\n     \"[em *foo*] bar\");\n\n  MT(\"emUnderscore\",\n     \"[em _foo_] bar\");\n\n  MT(\"emInWordAsterisk\",\n     \"foo[em *bar*]hello\");\n\n  MT(\"emInWordUnderscore\",\n     \"foo[em _bar_]hello\");\n\n  // Per documentation: \"...surround an * or _ with spaces, it’ll be\n  // treated as a literal asterisk or underscore.\"\n\n  MT(\"emEscapedBySpaceIn\",\n     \"foo [em _bar _ hello_] world\");\n\n  MT(\"emEscapedBySpaceOut\",\n     \"foo _ bar[em _hello_]world\");\n\n  MT(\"emEscapedByNewline\",\n     \"foo\",\n     \"_ bar[em _hello_]world\");\n\n  // Unclosed emphasis characters\n  // Instead of simply marking as EM / STRONG, it would be nice to have an\n  // incomplete flag for EM and STRONG, that is styled slightly different.\n  MT(\"emIncompleteAsterisk\",\n     \"foo [em *bar]\");\n\n  MT(\"emIncompleteUnderscore\",\n     \"foo [em _bar]\");\n\n  MT(\"strongAsterisk\",\n     \"[strong **foo**] bar\");\n\n  MT(\"strongUnderscore\",\n     \"[strong __foo__] bar\");\n\n  MT(\"emStrongAsterisk\",\n     \"[em *foo][em&strong **bar*][strong hello**] world\");\n\n  MT(\"emStrongUnderscore\",\n     \"[em _foo][em&strong __bar_][strong hello__] world\");\n\n  // \"...same character must be used to open and close an emphasis span.\"\"\n  MT(\"emStrongMixed\",\n     \"[em _foo][em&strong **bar*hello__ world]\");\n\n  MT(\"emStrongMixed\",\n     \"[em *foo][em&strong __bar_hello** world]\");\n\n  // These characters should be escaped:\n  // \\   backslash\n  // `   backtick\n  // *   asterisk\n  // _   underscore\n  // {}  curly braces\n  // []  square brackets\n  // ()  parentheses\n  // #   hash mark\n  // +   plus sign\n  // -   minus sign (hyphen)\n  // .   dot\n  // !   exclamation mark\n\n  MT(\"escapeBacktick\",\n     \"foo \\\\`bar\\\\`\");\n\n  MT(\"doubleEscapeBacktick\",\n     \"foo \\\\\\\\[comment `bar\\\\\\\\`]\");\n\n  MT(\"escapeAsterisk\",\n     \"foo \\\\*bar\\\\*\");\n\n  MT(\"doubleEscapeAsterisk\",\n     \"foo \\\\\\\\[em *bar\\\\\\\\*]\");\n\n  MT(\"escapeUnderscore\",\n     \"foo \\\\_bar\\\\_\");\n\n  MT(\"doubleEscapeUnderscore\",\n     \"foo \\\\\\\\[em _bar\\\\\\\\_]\");\n\n  MT(\"escapeHash\",\n     \"\\\\# foo\");\n\n  MT(\"doubleEscapeHash\",\n     \"\\\\\\\\# foo\");\n\n  MT(\"escapeNewline\",\n     \"\\\\\",\n     \"[em *foo*]\");\n\n\n  // Tests to make sure GFM-specific things aren't getting through\n\n  MT(\"taskList\",\n     \"[variable-2 * [ ]] bar]\");\n\n  MT(\"fencedCodeBlocks\",\n     \"[comment ```]\",\n     \"foo\",\n     \"[comment ```]\");\n\n  // Tests that require XML mode\n\n  MT(\"xmlMode\",\n     \"[tag&bracket <][tag div][tag&bracket >]\",\n     \"*foo*\",\n     \"[tag&bracket <][tag http://github.com][tag&bracket />]\",\n     \"[tag&bracket </][tag div][tag&bracket >]\",\n     \"[link <http://github.com/>]\");\n\n  MT(\"xmlModeWithMarkdownInside\",\n     \"[tag&bracket <][tag div] [attribute markdown]=[string 1][tag&bracket >]\",\n     \"[em *foo*]\",\n     \"[link <http://github.com/>]\",\n     \"[tag </div>]\",\n     \"[link <http://github.com/>]\",\n     \"[tag&bracket <][tag div][tag&bracket >]\",\n     \"[tag&bracket </][tag div][tag&bracket >]\");\n\n})();\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/meta.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n\n  CodeMirror.modeInfo = [\n    {name: \"APL\", mime: \"text/apl\", mode: \"apl\", ext: [\"dyalog\", \"apl\"]},\n    {name: \"Asterisk\", mime: \"text/x-asterisk\", mode: \"asterisk\", file: /^extensions\\.conf$/i},\n    {name: \"C\", mime: \"text/x-csrc\", mode: \"clike\", ext: [\"c\", \"h\"]},\n    {name: \"C++\", mime: \"text/x-c++src\", mode: \"clike\", ext: [\"cpp\", \"c++\", \"cc\", \"cxx\", \"hpp\", \"h++\", \"hh\", \"hxx\"], alias: [\"cpp\"]},\n    {name: \"Cobol\", mime: \"text/x-cobol\", mode: \"cobol\", ext: [\"cob\", \"cpy\"]},\n    {name: \"C#\", mime: \"text/x-csharp\", mode: \"clike\", ext: [\"cs\"], alias: [\"csharp\"]},\n    {name: \"Clojure\", mime: \"text/x-clojure\", mode: \"clojure\", ext: [\"clj\"]},\n    {name: \"CoffeeScript\", mime: \"text/x-coffeescript\", mode: \"coffeescript\", ext: [\"coffee\"], alias: [\"coffee\", \"coffee-script\"]},\n    {name: \"Common Lisp\", mime: \"text/x-common-lisp\", mode: \"commonlisp\", ext: [\"cl\", \"lisp\", \"el\"], alias: [\"lisp\"]},\n    {name: \"Cypher\", mime: \"application/x-cypher-query\", mode: \"cypher\", ext: [\"cyp\", \"cypher\"]},\n    {name: \"Cython\", mime: \"text/x-cython\", mode: \"python\", ext: [\"pyx\", \"pxd\", \"pxi\"]},\n    {name: \"CSS\", mime: \"text/css\", mode: \"css\", ext: [\"css\"]},\n    {name: \"CQL\", mime: \"text/x-cassandra\", mode: \"sql\", ext: [\"cql\"]},\n    {name: \"D\", mime: \"text/x-d\", mode: \"d\", ext: [\"d\"]},\n    {name: \"Dart\", mimes: [\"application/dart\", \"text/x-dart\"], mode: \"dart\", ext: [\"dart\"]},\n    {name: \"diff\", mime: \"text/x-diff\", mode: \"diff\", ext: [\"diff\", \"patch\"]},\n    {name: \"Django\", mime: \"text/x-django\", mode: \"django\"},\n    {name: \"Dockerfile\", mime: \"text/x-dockerfile\", mode: \"dockerfile\", file: /^Dockerfile$/},\n    {name: \"DTD\", mime: \"application/xml-dtd\", mode: \"dtd\", ext: [\"dtd\"]},\n    {name: \"Dylan\", mime: \"text/x-dylan\", mode: \"dylan\", ext: [\"dylan\", \"dyl\", \"intr\"]},\n    {name: \"EBNF\", mime: \"text/x-ebnf\", mode: \"ebnf\"},\n    {name: \"ECL\", mime: \"text/x-ecl\", mode: \"ecl\", ext: [\"ecl\"]},\n    {name: \"Eiffel\", mime: \"text/x-eiffel\", mode: \"eiffel\", ext: [\"e\"]},\n    {name: \"Embedded Javascript\", mime: \"application/x-ejs\", mode: \"htmlembedded\", ext: [\"ejs\"]},\n    {name: \"Embedded Ruby\", mime: \"application/x-erb\", mode: \"htmlembedded\", ext: [\"erb\"]},\n    {name: \"Erlang\", mime: \"text/x-erlang\", mode: \"erlang\", ext: [\"erl\"]},\n    {name: \"Forth\", mime: \"text/x-forth\", mode: \"forth\", ext: [\"forth\", \"fth\", \"4th\"]},\n    {name: \"Fortran\", mime: \"text/x-fortran\", mode: \"fortran\", ext: [\"f\", \"for\", \"f77\", \"f90\"]},\n    {name: \"F#\", mime: \"text/x-fsharp\", mode: \"mllike\", ext: [\"fs\"], alias: [\"fsharp\"]},\n    {name: \"Gas\", mime: \"text/x-gas\", mode: \"gas\", ext: [\"s\"]},\n    {name: \"Gherkin\", mime: \"text/x-feature\", mode: \"gherkin\", ext: [\"feature\"]},\n    {name: \"GitHub Flavored Markdown\", mime: \"text/x-gfm\", mode: \"gfm\", file: /^(readme|contributing|history).md$/i},\n    {name: \"Go\", mime: \"text/x-go\", mode: \"go\", ext: [\"go\"]},\n    {name: \"Groovy\", mime: \"text/x-groovy\", mode: \"groovy\", ext: [\"groovy\"]},\n    {name: \"HAML\", mime: \"text/x-haml\", mode: \"haml\", ext: [\"haml\"]},\n    {name: \"Haskell\", mime: \"text/x-haskell\", mode: \"haskell\", ext: [\"hs\"]},\n    {name: \"Haxe\", mime: \"text/x-haxe\", mode: \"haxe\", ext: [\"hx\"]},\n    {name: \"HXML\", mime: \"text/x-hxml\", mode: \"haxe\", ext: [\"hxml\"]},\n    {name: \"ASP.NET\", mime: \"application/x-aspx\", mode: \"htmlembedded\", ext: [\"aspx\"], alias: [\"asp\", \"aspx\"]},\n    {name: \"HTML\", mime: \"text/html\", mode: \"htmlmixed\", ext: [\"html\", \"htm\"], alias: [\"xhtml\"]},\n    {name: \"HTTP\", mime: \"message/http\", mode: \"http\"},\n    {name: \"IDL\", mime: \"text/x-idl\", mode: \"idl\", ext: [\"pro\"]},\n    {name: \"Jade\", mime: \"text/x-jade\", mode: \"jade\", ext: [\"jade\"]},\n    {name: \"Java\", mime: \"text/x-java\", mode: \"clike\", ext: [\"java\"]},\n    {name: \"Java Server Pages\", mime: \"application/x-jsp\", mode: \"htmlembedded\", ext: [\"jsp\"], alias: [\"jsp\"]},\n    {name: \"JavaScript\", mimes: [\"text/javascript\", \"text/ecmascript\", \"application/javascript\", \"application/x-javascript\", \"application/ecmascript\"],\n     mode: \"javascript\", ext: [\"js\"], alias: [\"ecmascript\", \"js\", \"node\"]},\n    {name: \"JSON\", mimes: [\"application/json\", \"application/x-json\"], mode: \"javascript\", ext: [\"json\", \"map\"], alias: [\"json5\"]},\n    {name: \"JSON-LD\", mime: \"application/ld+json\", mode: \"javascript\", ext: [\"jsonld\"], alias: [\"jsonld\"]},\n    {name: \"Jinja2\", mime: \"null\", mode: \"jinja2\"},\n    {name: \"Julia\", mime: \"text/x-julia\", mode: \"julia\", ext: [\"jl\"]},\n    {name: \"Kotlin\", mime: \"text/x-kotlin\", mode: \"kotlin\", ext: [\"kt\"]},\n    {name: \"LESS\", mime: \"text/x-less\", mode: \"css\", ext: [\"less\"]},\n    {name: \"LiveScript\", mime: \"text/x-livescript\", mode: \"livescript\", ext: [\"ls\"], alias: [\"ls\"]},\n    {name: \"Lua\", mime: \"text/x-lua\", mode: \"lua\", ext: [\"lua\"]},\n    {name: \"Markdown\", mime: \"text/x-markdown\", mode: \"markdown\", ext: [\"markdown\", \"md\", \"mkd\"]},\n    {name: \"mIRC\", mime: \"text/mirc\", mode: \"mirc\"},\n    {name: \"MariaDB SQL\", mime: \"text/x-mariadb\", mode: \"sql\"},\n    {name: \"Modelica\", mime: \"text/x-modelica\", mode: \"modelica\", ext: [\"mo\"]},\n    {name: \"MS SQL\", mime: \"text/x-mssql\", mode: \"sql\"},\n    {name: \"MySQL\", mime: \"text/x-mysql\", mode: \"sql\"},\n    {name: \"Nginx\", mime: \"text/x-nginx-conf\", mode: \"nginx\", file: /nginx.*\\.conf$/i},\n    {name: \"NTriples\", mime: \"text/n-triples\", mode: \"ntriples\", ext: [\"nt\"]},\n    {name: \"Objective C\", mime: \"text/x-objectivec\", mode: \"clike\", ext: [\"m\", \"mm\"]},\n    {name: \"OCaml\", mime: \"text/x-ocaml\", mode: \"mllike\", ext: [\"ml\", \"mli\", \"mll\", \"mly\"]},\n    {name: \"Octave\", mime: \"text/x-octave\", mode: \"octave\", ext: [\"m\"]},\n    {name: \"Pascal\", mime: \"text/x-pascal\", mode: \"pascal\", ext: [\"p\", \"pas\"]},\n    {name: \"PEG.js\", mime: \"null\", mode: \"pegjs\", ext: [\"jsonld\"]},\n    {name: \"Perl\", mime: \"text/x-perl\", mode: \"perl\", ext: [\"pl\", \"pm\"]},\n    {name: \"PHP\", mime: \"application/x-httpd-php\", mode: \"php\", ext: [\"php\", \"php3\", \"php4\", \"php5\", \"phtml\"]},\n    {name: \"Pig\", mime: \"text/x-pig\", mode: \"pig\", ext: [\"pig\"]},\n    {name: \"Plain Text\", mime: \"text/plain\", mode: \"null\", ext: [\"txt\", \"text\", \"conf\", \"def\", \"list\", \"log\"]},\n    {name: \"PLSQL\", mime: \"text/x-plsql\", mode: \"sql\", ext: [\"pls\"]},\n    {name: \"Properties files\", mime: \"text/x-properties\", mode: \"properties\", ext: [\"properties\", \"ini\", \"in\"], alias: [\"ini\", \"properties\"]},\n    {name: \"Python\", mime: \"text/x-python\", mode: \"python\", ext: [\"py\", \"pyw\"]},\n    {name: \"Puppet\", mime: \"text/x-puppet\", mode: \"puppet\", ext: [\"pp\"]},\n    {name: \"Q\", mime: \"text/x-q\", mode: \"q\", ext: [\"q\"]},\n    {name: \"R\", mime: \"text/x-rsrc\", mode: \"r\", ext: [\"r\"], alias: [\"rscript\"]},\n    {name: \"reStructuredText\", mime: \"text/x-rst\", mode: \"rst\", ext: [\"rst\"], alias: [\"rst\"]},\n    {name: \"RPM Changes\", mime: \"text/x-rpm-changes\", mode: \"rpm\"},\n    {name: \"RPM Spec\", mime: \"text/x-rpm-spec\", mode: \"rpm\", ext: [\"spec\"]},\n    {name: \"Ruby\", mime: \"text/x-ruby\", mode: \"ruby\", ext: [\"rb\"], alias: [\"jruby\", \"macruby\", \"rake\", \"rb\", \"rbx\"]},\n    {name: \"Rust\", mime: \"text/x-rustsrc\", mode: \"rust\", ext: [\"rs\"]},\n    {name: \"Sass\", mime: \"text/x-sass\", mode: \"sass\", ext: [\"sass\"]},\n    {name: \"Scala\", mime: \"text/x-scala\", mode: \"clike\", ext: [\"scala\"]},\n    {name: \"Scheme\", mime: \"text/x-scheme\", mode: \"scheme\", ext: [\"scm\", \"ss\"]},\n    {name: \"SCSS\", mime: \"text/x-scss\", mode: \"css\", ext: [\"scss\"]},\n    {name: \"Shell\", mime: \"text/x-sh\", mode: \"shell\", ext: [\"sh\", \"ksh\", \"bash\"], alias: [\"bash\", \"sh\", \"zsh\"]},\n    {name: \"Sieve\", mime: \"application/sieve\", mode: \"sieve\", ext: [\"siv\", \"sieve\"]},\n    {name: \"Slim\", mimes: [\"text/x-slim\", \"application/x-slim\"], mode: \"slim\", ext: [\"slim\"]},\n    {name: \"Smalltalk\", mime: \"text/x-stsrc\", mode: \"smalltalk\", ext: [\"st\"]},\n    {name: \"Smarty\", mime: \"text/x-smarty\", mode: \"smarty\", ext: [\"tpl\"]},\n    {name: \"SmartyMixed\", mime: \"text/x-smarty\", mode: \"smartymixed\"},\n    {name: \"Solr\", mime: \"text/x-solr\", mode: \"solr\"},\n    {name: \"Soy\", mime: \"text/x-soy\", mode: \"soy\", ext: [\"soy\"], alias: [\"closure template\"]},\n    {name: \"SPARQL\", mime: \"application/sparql-query\", mode: \"sparql\", ext: [\"rq\", \"sparql\"], alias: [\"sparul\"]},\n    {name: \"Spreadsheet\", mime: \"text/x-spreadsheet\", mode: \"spreadsheet\", alias: [\"excel\", \"formula\"]},\n    {name: \"SQL\", mime: \"text/x-sql\", mode: \"sql\", ext: [\"sql\"]},\n    {name: \"MariaDB\", mime: \"text/x-mariadb\", mode: \"sql\"},\n    {name: \"sTeX\", mime: \"text/x-stex\", mode: \"stex\"},\n    {name: \"LaTeX\", mime: \"text/x-latex\", mode: \"stex\", ext: [\"text\", \"ltx\"], alias: [\"tex\"]},\n    {name: \"SystemVerilog\", mime: \"text/x-systemverilog\", mode: \"verilog\", ext: [\"v\"]},\n    {name: \"Tcl\", mime: \"text/x-tcl\", mode: \"tcl\", ext: [\"tcl\"]},\n    {name: \"Textile\", mime: \"text/x-textile\", mode: \"textile\", ext: [\"textile\"]},\n    {name: \"TiddlyWiki \", mime: \"text/x-tiddlywiki\", mode: \"tiddlywiki\"},\n    {name: \"Tiki wiki\", mime: \"text/tiki\", mode: \"tiki\"},\n    {name: \"TOML\", mime: \"text/x-toml\", mode: \"toml\", ext: [\"toml\"]},\n    {name: \"Tornado\", mime: \"text/x-tornado\", mode: \"tornado\"},\n    {name: \"Turtle\", mime: \"text/turtle\", mode: \"turtle\", ext: [\"ttl\"]},\n    {name: \"TypeScript\", mime: \"application/typescript\", mode: \"javascript\", ext: [\"ts\"], alias: [\"ts\"]},\n    {name: \"VB.NET\", mime: \"text/x-vb\", mode: \"vb\", ext: [\"vb\"]},\n    {name: \"VBScript\", mime: \"text/vbscript\", mode: \"vbscript\", ext: [\"vbs\"]},\n    {name: \"Velocity\", mime: \"text/velocity\", mode: \"velocity\", ext: [\"vtl\"]},\n    {name: \"Verilog\", mime: \"text/x-verilog\", mode: \"verilog\", ext: [\"v\"]},\n    {name: \"XML\", mimes: [\"application/xml\", \"text/xml\"], mode: \"xml\", ext: [\"xml\", \"xsl\", \"xsd\"], alias: [\"rss\", \"wsdl\", \"xsd\"]},\n    {name: \"XQuery\", mime: \"application/xquery\", mode: \"xquery\", ext: [\"xy\", \"xquery\"]},\n    {name: \"YAML\", mime: \"text/x-yaml\", mode: \"yaml\", ext: [\"yaml\"], alias: [\"yml\"]},\n    {name: \"Z80\", mime: \"text/x-z80\", mode: \"z80\", ext: [\"z80\"]}\n  ];\n  // Ensure all modes have a mime property for backwards compatibility\n  for (var i = 0; i < CodeMirror.modeInfo.length; i++) {\n    var info = CodeMirror.modeInfo[i];\n    if (info.mimes) info.mime = info.mimes[0];\n  }\n\n  CodeMirror.findModeByMIME = function(mime) {\n    mime = mime.toLowerCase();\n    for (var i = 0; i < CodeMirror.modeInfo.length; i++) {\n      var info = CodeMirror.modeInfo[i];\n      if (info.mime == mime) return info;\n      if (info.mimes) for (var j = 0; j < info.mimes.length; j++)\n        if (info.mimes[j] == mime) return info;\n    }\n  };\n\n  CodeMirror.findModeByExtension = function(ext) {\n    for (var i = 0; i < CodeMirror.modeInfo.length; i++) {\n      var info = CodeMirror.modeInfo[i];\n      if (info.ext) for (var j = 0; j < info.ext.length; j++)\n        if (info.ext[j] == ext) return info;\n    }\n  };\n\n  CodeMirror.findModeByFileName = function(filename) {\n    for (var i = 0; i < CodeMirror.modeInfo.length; i++) {\n      var info = CodeMirror.modeInfo[i];\n      if (info.file && info.file.test(filename)) return info;\n    }\n    var dot = filename.lastIndexOf(\".\");\n    var ext = dot > -1 && filename.substring(dot + 1, filename.length);\n    if (ext) return CodeMirror.findModeByExtension(ext);\n  };\n\n  CodeMirror.findModeByName = function(name) {\n    name = name.toLowerCase();\n    for (var i = 0; i < CodeMirror.modeInfo.length; i++) {\n      var info = CodeMirror.modeInfo[i];\n      if (info.name.toLowerCase() == name) return info;\n      if (info.alias) for (var j = 0; j < info.alias.length; j++)\n        if (info.alias[j].toLowerCase() == name) return info;\n    }\n  };\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/mirc/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: mIRC mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<link rel=\"stylesheet\" href=\"../../theme/twilight.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"mirc.js\"></script>\n<style>.CodeMirror {border: 1px solid black;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">mIRC</a>\n  </ul>\n</div>\n\n<article>\n<h2>mIRC mode</h2>\n<form><textarea id=\"code\" name=\"code\">\n;AKA Nick Tracker by Ford_Lawnmower irc.GeekShed.net #Script-Help\n;*****************************************************************************;\n;**Start Setup\n;Change JoinDisplay, below, for On Join AKA Display. On = 1 - Off = 0\nalias -l JoinDisplay { return 1 }\n;Change MaxNicks, below, to the number of nicknames you want to store for each hostmask. I wouldn't go over 400 with this ;/\nalias -l MaxNicks { return 20 }\n;Change AKALogo, below, To the text you want displayed before each AKA result.\nalias -l AKALogo { return \u000306\u0007 \u000305A\u000306K\u000307A \u000306\u0007 }\n;**End Setup\n;*****************************************************************************;\nOn *:Join:#: {\n  if ($nick == $me) { .timer 1 1 ialupdateCheck $chan }\n  NickNamesAdd $nick $+($network,$wildsite)\n  if ($JoinDisplay) { .timerNickNames $+ $nick 1 2 NickNames.display $nick $chan $network $wildsite }\n}\non *:Nick: { NickNamesAdd $newnick $+($network,$wildsite) $nick }\nalias -l NickNames.display {\n  if ($gettok($hget(NickNames,$+($3,$4)),0,126) > 1) {\n    echo -g $2 $AKALogo $+(\u000309,$1) $AKALogo \u000307 $mid($replace($hget(NickNames,$+($3,$4)),$chr(126),$chr(44)),2,-1)\n  }\n}\nalias -l NickNamesAdd {\n  if ($hget(NickNames,$2)) {\n    if (!$regex($hget(NickNames,$2),/~\\Q $+ $replacecs($1,\\E,\\E\\\\E\\Q) $+ \\E~/i)) {\n      if ($gettok($hget(NickNames,$2),0,126) <= $MaxNicks) {\n        hadd NickNames $2 $+($hget(NickNames,$2),$1,~)\n      }\n      else {\n        hadd NickNames $2 $+($mid($hget(NickNames,$2),$pos($hget(NickNames,$2),~,2)),$1,~)\n      }\n    }\n  }\n  else {\n    hadd -m NickNames $2 $+(~,$1,~,$iif($3,$+($3,~)))\n  }\n}\nalias -l Fix.All.MindUser {\n  var %Fix.Count = $hfind(NickNames,/[^~]+[0-9]{4}~/,0,r).data\n  while (%Fix.Count) {\n    if ($Fix.MindUser($hget(NickNames,$hfind(NickNames,/[^~]+[0-9]{4}~/,%Fix.Count,r).data))) {\n      echo -ag Record %Fix.Count - $v1 - Was Cleaned\n      hadd NickNames $hfind(NickNames,/[^~]+[0-9]{4}~/,%Fix.Count,r).data $v1\n    }\n    dec %Fix.Count\n  }\n}\nalias -l Fix.MindUser { return $regsubex($1,/[^~]+[0-9]{4}~/g,$null) }\nmenu nicklist,query {\n  -\n  .AKA\n  ..Check $$1: {\n    if ($gettok($hget(NickNames,$+($network,$address($1,2))),0,126) > 1) {\n      NickNames.display $1 $active $network $address($1,2)\n    }\n    else { echo -ag $AKALogo $+(\u000309,$1) \u000307has not been known by any other nicknames while I have been watching. }\n  }\n  ..Cleanup $$1:hadd NickNames $+($network,$address($1,2)) $fix.minduser($hget(NickNames,$+($network,$address($1,2))))\n  ..Clear $$1:hadd NickNames $+($network,$address($1,2)) $+(~,$1,~)\n  ..AKA Search Dialog:dialog $iif($dialog(AKA_Search),-v,-m) AKA_Search AKA_Search\n  -\n}\nmenu status,channel {\n  -\n  .AKA\n  ..AKA Search Dialog:dialog $iif($dialog(AKA_Search),-v,-m) AKA_Search AKA_Search\n  ..Clean All Records:Fix.All.Minduser\n  -\n}\ndialog AKA_Search {\n  title \"AKA Search Engine\"\n  size -1 -1 206 221\n  option dbu\n  edit \"\", 1, 8 5 149 10, autohs\n  button \"Search\", 2, 163 4 32 12\n  radio \"Search HostMask\", 4, 61 22 55 10\n  radio \"Search Nicknames\", 5, 123 22 56 10\n  list 6, 8 38 190 169, sort extsel vsbar\n  button \"Check Selected\", 7, 67 206 40 12\n  button \"Close\", 8, 160 206 38 12, cancel\n  box \"Search Type\", 3, 11 17 183 18\n  button \"Copy to Clipboard\", 9, 111 206 46 12\n}\nOn *:Dialog:Aka_Search:init:*: { did -c $dname 5 }\nOn *:Dialog:Aka_Search:Sclick:2,7,9: {\n  if ($did == 2) && ($did($dname,1)) {\n    did -r $dname 6\n    var %search $+(*,$v1,*), %type $iif($did($dname,5).state,data,item), %matches = $hfind(NickNames,%search,0,w). [ $+ [ %type ] ]\n    while (%matches) {\n      did -a $dname 6 $hfind(NickNames,%search,%matches,w). [ $+ [ %type ] ]\n      dec %matches\n    }\n    did -c $dname 6 1\n  }\n  elseif ($did == 7) && ($did($dname,6).seltext) { echo -ga $AKALogo \u000307 $mid($replace($hget(NickNames,$v1),$chr(126),$chr(44)),2,-1) }\n  elseif ($did == 9) && ($did($dname,6).seltext) { clipboard $mid($v1,$pos($v1,*,1)) }\n}\nOn *:Start:{\n  if (!$hget(NickNames)) { hmake NickNames 10 }\n  if ($isfile(NickNames.hsh)) { hload  NickNames NickNames.hsh }\n}\nOn *:Exit: { if ($hget(NickNames)) { hsave NickNames NickNames.hsh } }\nOn *:Disconnect: { if ($hget(NickNames)) { hsave NickNames NickNames.hsh } }\nOn *:Unload: { hfree NickNames }\nalias -l ialupdateCheck {\n  inc -z $+(%,ialupdateCheck,$network) $calc($nick($1,0) / 4)\n  ;If your ial is already being updated on join .who $1 out.\n  ;If you are using /names to update ial you will still need this line.\n  .who $1\n}\nRaw 352:*: {\n  if ($($+(%,ialupdateCheck,$network),2)) haltdef\n  NickNamesAdd $6 $+($network,$address($6,2))\n}\nRaw 315:*: {\n  if ($($+(%,ialupdateCheck,$network),2)) haltdef\n}\n\n</textarea></form>\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        theme: \"twilight\",\n        lineNumbers: true,\n        matchBrackets: true,\n        indentUnit: 4,\n        mode: \"text/mirc\"\n      });\n    </script>\n\n    <p><strong>MIME types defined:</strong> <code>text/mirc</code>.</p>\n\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/mirc/mirc.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n//mIRC mode by Ford_Lawnmower :: Based on Velocity mode by Steve O'Hara\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMIME(\"text/mirc\", \"mirc\");\nCodeMirror.defineMode(\"mirc\", function() {\n  function parseWords(str) {\n    var obj = {}, words = str.split(\" \");\n    for (var i = 0; i < words.length; ++i) obj[words[i]] = true;\n    return obj;\n  }\n  var specials = parseWords(\"$! $$ $& $? $+ $abook $abs $active $activecid \" +\n                            \"$activewid $address $addtok $agent $agentname $agentstat $agentver \" +\n                            \"$alias $and $anick $ansi2mirc $aop $appactive $appstate $asc $asctime \" +\n                            \"$asin $atan $avoice $away $awaymsg $awaytime $banmask $base $bfind \" +\n                            \"$binoff $biton $bnick $bvar $bytes $calc $cb $cd $ceil $chan $chanmodes \" +\n                            \"$chantypes $chat $chr $cid $clevel $click $cmdbox $cmdline $cnick $color \" +\n                            \"$com $comcall $comchan $comerr $compact $compress $comval $cos $count \" +\n                            \"$cr $crc $creq $crlf $ctime $ctimer $ctrlenter $date $day $daylight \" +\n                            \"$dbuh $dbuw $dccignore $dccport $dde $ddename $debug $decode $decompress \" +\n                            \"$deltok $devent $dialog $did $didreg $didtok $didwm $disk $dlevel $dll \" +\n                            \"$dllcall $dname $dns $duration $ebeeps $editbox $emailaddr $encode $error \" +\n                            \"$eval $event $exist $feof $ferr $fgetc $file $filename $filtered $finddir \" +\n                            \"$finddirn $findfile $findfilen $findtok $fline $floor $fopen $fread $fserve \" +\n                            \"$fulladdress $fulldate $fullname $fullscreen $get $getdir $getdot $gettok $gmt \" +\n                            \"$group $halted $hash $height $hfind $hget $highlight $hnick $hotline \" +\n                            \"$hotlinepos $ial $ialchan $ibl $idle $iel $ifmatch $ignore $iif $iil \" +\n                            \"$inelipse $ini $inmidi $inpaste $inpoly $input $inrect $inroundrect \" +\n                            \"$insong $instok $int $inwave $ip $isalias $isbit $isdde $isdir $isfile \" +\n                            \"$isid $islower $istok $isupper $keychar $keyrpt $keyval $knick $lactive \" +\n                            \"$lactivecid $lactivewid $left $len $level $lf $line $lines $link $lock \" +\n                            \"$lock $locked $log $logstamp $logstampfmt $longfn $longip $lower $ltimer \" +\n                            \"$maddress $mask $matchkey $matchtok $md5 $me $menu $menubar $menucontext \" +\n                            \"$menutype $mid $middir $mircdir $mircexe $mircini $mklogfn $mnick $mode \" +\n                            \"$modefirst $modelast $modespl $mouse $msfile $network $newnick $nick $nofile \" +\n                            \"$nopath $noqt $not $notags $notify $null $numeric $numok $oline $onpoly \" +\n                            \"$opnick $or $ord $os $passivedcc $pic $play $pnick $port $portable $portfree \" +\n                            \"$pos $prefix $prop $protect $puttok $qt $query $rand $r $rawmsg $read $readomo \" +\n                            \"$readn $regex $regml $regsub $regsubex $remove $remtok $replace $replacex \" +\n                            \"$reptok $result $rgb $right $round $scid $scon $script $scriptdir $scriptline \" +\n                            \"$sdir $send $server $serverip $sfile $sha1 $shortfn $show $signal $sin \" +\n                            \"$site $sline $snick $snicks $snotify $sock $sockbr $sockerr $sockname \" +\n                            \"$sorttok $sound $sqrt $ssl $sreq $sslready $status $strip $str $stripped \" +\n                            \"$syle $submenu $switchbar $tan $target $ticks $time $timer $timestamp \" +\n                            \"$timestampfmt $timezone $tip $titlebar $toolbar $treebar $trust $ulevel \" +\n                            \"$ulist $upper $uptime $url $usermode $v1 $v2 $var $vcmd $vcmdstat $vcmdver \" +\n                            \"$version $vnick $vol $wid $width $wildsite $wildtok $window $wrap $xor\");\n  var keywords = parseWords(\"abook ajinvite alias aline ame amsg anick aop auser autojoin avoice \" +\n                            \"away background ban bcopy beep bread break breplace bset btrunc bunset bwrite \" +\n                            \"channel clear clearall cline clipboard close cnick color comclose comopen \" +\n                            \"comreg continue copy creq ctcpreply ctcps dcc dccserver dde ddeserver \" +\n                            \"debug dec describe dialog did didtok disable disconnect dlevel dline dll \" +\n                            \"dns dqwindow drawcopy drawdot drawfill drawline drawpic drawrect drawreplace \" +\n                            \"drawrot drawsave drawscroll drawtext ebeeps echo editbox emailaddr enable \" +\n                            \"events exit fclose filter findtext finger firewall flash flist flood flush \" +\n                            \"flushini font fopen fseek fsend fserve fullname fwrite ghide gload gmove \" +\n                            \"gopts goto gplay gpoint gqreq groups gshow gsize gstop gtalk gunload hadd \" +\n                            \"halt haltdef hdec hdel help hfree hinc hload hmake hop hsave ial ialclear \" +\n                            \"ialmark identd if ignore iline inc invite iuser join kick linesep links list \" +\n                            \"load loadbuf localinfo log mdi me menubar mkdir mnick mode msg nick noop notice \" +\n                            \"notify omsg onotice part partall pdcc perform play playctrl pop protect pvoice \" +\n                            \"qme qmsg query queryn quit raw reload remini remote remove rename renwin \" +\n                            \"reseterror resetidle return rlevel rline rmdir run ruser save savebuf saveini \" +\n                            \"say scid scon server set showmirc signam sline sockaccept sockclose socklist \" +\n                            \"socklisten sockmark sockopen sockpause sockread sockrename sockudp sockwrite \" +\n                            \"sound speak splay sreq strip switchbar timer timestamp titlebar tnick tokenize \" +\n                            \"toolbar topic tray treebar ulist unload unset unsetall updatenl url uwho \" +\n                            \"var vcadd vcmd vcrem vol while whois window winhelp write writeint if isalnum \" +\n                            \"isalpha isaop isavoice isban ischan ishop isignore isin isincs isletter islower \" +\n                            \"isnotify isnum ison isop isprotect isreg isupper isvoice iswm iswmcs \" +\n                            \"elseif else goto menu nicklist status title icon size option text edit \" +\n                            \"button check radio box scroll list combo link tab item\");\n  var functions = parseWords(\"if elseif else and not or eq ne in ni for foreach while switch\");\n  var isOperatorChar = /[+\\-*&%=<>!?^\\/\\|]/;\n  function chain(stream, state, f) {\n    state.tokenize = f;\n    return f(stream, state);\n  }\n  function tokenBase(stream, state) {\n    var beforeParams = state.beforeParams;\n    state.beforeParams = false;\n    var ch = stream.next();\n    if (/[\\[\\]{}\\(\\),\\.]/.test(ch)) {\n      if (ch == \"(\" && beforeParams) state.inParams = true;\n      else if (ch == \")\") state.inParams = false;\n      return null;\n    }\n    else if (/\\d/.test(ch)) {\n      stream.eatWhile(/[\\w\\.]/);\n      return \"number\";\n    }\n    else if (ch == \"\\\\\") {\n      stream.eat(\"\\\\\");\n      stream.eat(/./);\n      return \"number\";\n    }\n    else if (ch == \"/\" && stream.eat(\"*\")) {\n      return chain(stream, state, tokenComment);\n    }\n    else if (ch == \";\" && stream.match(/ *\\( *\\(/)) {\n      return chain(stream, state, tokenUnparsed);\n    }\n    else if (ch == \";\" && !state.inParams) {\n      stream.skipToEnd();\n      return \"comment\";\n    }\n    else if (ch == '\"') {\n      stream.eat(/\"/);\n      return \"keyword\";\n    }\n    else if (ch == \"$\") {\n      stream.eatWhile(/[$_a-z0-9A-Z\\.:]/);\n      if (specials && specials.propertyIsEnumerable(stream.current().toLowerCase())) {\n        return \"keyword\";\n      }\n      else {\n        state.beforeParams = true;\n        return \"builtin\";\n      }\n    }\n    else if (ch == \"%\") {\n      stream.eatWhile(/[^,^\\s^\\(^\\)]/);\n      state.beforeParams = true;\n      return \"string\";\n    }\n    else if (isOperatorChar.test(ch)) {\n      stream.eatWhile(isOperatorChar);\n      return \"operator\";\n    }\n    else {\n      stream.eatWhile(/[\\w\\$_{}]/);\n      var word = stream.current().toLowerCase();\n      if (keywords && keywords.propertyIsEnumerable(word))\n        return \"keyword\";\n      if (functions && functions.propertyIsEnumerable(word)) {\n        state.beforeParams = true;\n        return \"keyword\";\n      }\n      return null;\n    }\n  }\n  function tokenComment(stream, state) {\n    var maybeEnd = false, ch;\n    while (ch = stream.next()) {\n      if (ch == \"/\" && maybeEnd) {\n        state.tokenize = tokenBase;\n        break;\n      }\n      maybeEnd = (ch == \"*\");\n    }\n    return \"comment\";\n  }\n  function tokenUnparsed(stream, state) {\n    var maybeEnd = 0, ch;\n    while (ch = stream.next()) {\n      if (ch == \";\" && maybeEnd == 2) {\n        state.tokenize = tokenBase;\n        break;\n      }\n      if (ch == \")\")\n        maybeEnd++;\n      else if (ch != \" \")\n        maybeEnd = 0;\n    }\n    return \"meta\";\n  }\n  return {\n    startState: function() {\n      return {\n        tokenize: tokenBase,\n        beforeParams: false,\n        inParams: false\n      };\n    },\n    token: function(stream, state) {\n      if (stream.eatSpace()) return null;\n      return state.tokenize(stream, state);\n    }\n  };\n});\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/mllike/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: ML-like mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=stylesheet href=../../lib/codemirror.css>\n<script src=../../lib/codemirror.js></script>\n<script src=../../addon/edit/matchbrackets.js></script>\n<script src=mllike.js></script>\n<style type=text/css>\n  .CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}\n</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">ML-like</a>\n  </ul>\n</div>\n\n<article>\n<h2>OCaml mode</h2>\n\n\n<textarea id=\"ocamlCode\">\n(* Summing a list of integers *)\nlet rec sum xs =\n  match xs with\n    | []       -&gt; 0\n    | x :: xs' -&gt; x + sum xs'\n\n(* Quicksort *)\nlet rec qsort = function\n   | [] -&gt; []\n   | pivot :: rest -&gt;\n       let is_less x = x &lt; pivot in\n       let left, right = List.partition is_less rest in\n       qsort left @ [pivot] @ qsort right\n\n(* Fibonacci Sequence *)\nlet rec fib_aux n a b =\n  match n with\n  | 0 -&gt; a\n  | _ -&gt; fib_aux (n - 1) (a + b) a\nlet fib n = fib_aux n 0 1\n\n(* Birthday paradox *)\nlet year_size = 365.\n\nlet rec birthday_paradox prob people =\n    let prob' = (year_size -. float people) /. year_size *. prob  in\n    if prob' &lt; 0.5 then\n        Printf.printf \"answer = %d\\n\" (people+1)\n    else\n        birthday_paradox prob' (people+1) ;;\n\nbirthday_paradox 1.0 1\n\n(* Church numerals *)\nlet zero f x = x\nlet succ n f x = f (n f x)\nlet one = succ zero\nlet two = succ (succ zero)\nlet add n1 n2 f x = n1 f (n2 f x)\nlet to_string n = n (fun k -&gt; \"S\" ^ k) \"0\"\nlet _ = to_string (add (succ two) two)\n\n(* Elementary functions *)\nlet square x = x * x;;\nlet rec fact x =\n  if x &lt;= 1 then 1 else x * fact (x - 1);;\n\n(* Automatic memory management *)\nlet l = 1 :: 2 :: 3 :: [];;\n[1; 2; 3];;\n5 :: l;;\n\n(* Polymorphism: sorting lists *)\nlet rec sort = function\n  | [] -&gt; []\n  | x :: l -&gt; insert x (sort l)\n\nand insert elem = function\n  | [] -&gt; [elem]\n  | x :: l -&gt;\n      if elem &lt; x then elem :: x :: l else x :: insert elem l;;\n\n(* Imperative features *)\nlet add_polynom p1 p2 =\n  let n1 = Array.length p1\n  and n2 = Array.length p2 in\n  let result = Array.create (max n1 n2) 0 in\n  for i = 0 to n1 - 1 do result.(i) &lt;- p1.(i) done;\n  for i = 0 to n2 - 1 do result.(i) &lt;- result.(i) + p2.(i) done;\n  result;;\nadd_polynom [| 1; 2 |] [| 1; 2; 3 |];;\n\n(* We may redefine fact using a reference cell and a for loop *)\nlet fact n =\n  let result = ref 1 in\n  for i = 2 to n do\n    result := i * !result\n   done;\n   !result;;\nfact 5;;\n\n(* Triangle (graphics) *)\nlet () =\n  ignore( Glut.init Sys.argv );\n  Glut.initDisplayMode ~double_buffer:true ();\n  ignore (Glut.createWindow ~title:\"OpenGL Demo\");\n  let angle t = 10. *. t *. t in\n  let render () =\n    GlClear.clear [ `color ];\n    GlMat.load_identity ();\n    GlMat.rotate ~angle: (angle (Sys.time ())) ~z:1. ();\n    GlDraw.begins `triangles;\n    List.iter GlDraw.vertex2 [-1., -1.; 0., 1.; 1., -1.];\n    GlDraw.ends ();\n    Glut.swapBuffers () in\n  GlMat.mode `modelview;\n  Glut.displayFunc ~cb:render;\n  Glut.idleFunc ~cb:(Some Glut.postRedisplay);\n  Glut.mainLoop ()\n\n(* A Hundred Lines of Caml - http://caml.inria.fr/about/taste.en.html *)\n(* OCaml page on Wikipedia - http://en.wikipedia.org/wiki/OCaml *)\n</textarea>\n\n<h2>F# mode</h2>\n<textarea id=\"fsharpCode\">\nmodule CodeMirror.FSharp\n\nlet rec fib = function\n    | 0 -> 0\n    | 1 -> 1\n    | n -> fib (n - 1) + fib (n - 2)\n\ntype Point =\n    {\n        x : int\n        y : int\n    }\n\ntype Color =\n    | Red\n    | Green\n    | Blue\n\n[0 .. 10]\n|> List.map ((+) 2)\n|> List.fold (fun x y -> x + y) 0\n|> printf \"%i\"\n</textarea>\n\n\n<script>\n  var ocamlEditor = CodeMirror.fromTextArea(document.getElementById('ocamlCode'), {\n    mode: 'text/x-ocaml',\n    lineNumbers: true,\n    matchBrackets: true\n  });\n\n  var fsharpEditor = CodeMirror.fromTextArea(document.getElementById('fsharpCode'), {\n    mode: 'text/x-fsharp',\n    lineNumbers: true,\n    matchBrackets: true\n  });\n</script>\n\n<p><strong>MIME types defined:</strong> <code>text/x-ocaml</code> (OCaml) and <code>text/x-fsharp</code> (F#).</p>\n</article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/mllike/mllike.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode('mllike', function(_config, parserConfig) {\n  var words = {\n    'let': 'keyword',\n    'rec': 'keyword',\n    'in': 'keyword',\n    'of': 'keyword',\n    'and': 'keyword',\n    'if': 'keyword',\n    'then': 'keyword',\n    'else': 'keyword',\n    'for': 'keyword',\n    'to': 'keyword',\n    'while': 'keyword',\n    'do': 'keyword',\n    'done': 'keyword',\n    'fun': 'keyword',\n    'function': 'keyword',\n    'val': 'keyword',\n    'type': 'keyword',\n    'mutable': 'keyword',\n    'match': 'keyword',\n    'with': 'keyword',\n    'try': 'keyword',\n    'open': 'builtin',\n    'ignore': 'builtin',\n    'begin': 'keyword',\n    'end': 'keyword'\n  };\n\n  var extraWords = parserConfig.extraWords || {};\n  for (var prop in extraWords) {\n    if (extraWords.hasOwnProperty(prop)) {\n      words[prop] = parserConfig.extraWords[prop];\n    }\n  }\n\n  function tokenBase(stream, state) {\n    var ch = stream.next();\n\n    if (ch === '\"') {\n      state.tokenize = tokenString;\n      return state.tokenize(stream, state);\n    }\n    if (ch === '(') {\n      if (stream.eat('*')) {\n        state.commentLevel++;\n        state.tokenize = tokenComment;\n        return state.tokenize(stream, state);\n      }\n    }\n    if (ch === '~') {\n      stream.eatWhile(/\\w/);\n      return 'variable-2';\n    }\n    if (ch === '`') {\n      stream.eatWhile(/\\w/);\n      return 'quote';\n    }\n    if (ch === '/' && parserConfig.slashComments && stream.eat('/')) {\n      stream.skipToEnd();\n      return 'comment';\n    }\n    if (/\\d/.test(ch)) {\n      stream.eatWhile(/[\\d]/);\n      if (stream.eat('.')) {\n        stream.eatWhile(/[\\d]/);\n      }\n      return 'number';\n    }\n    if ( /[+\\-*&%=<>!?|]/.test(ch)) {\n      return 'operator';\n    }\n    stream.eatWhile(/\\w/);\n    var cur = stream.current();\n    return words[cur] || 'variable';\n  }\n\n  function tokenString(stream, state) {\n    var next, end = false, escaped = false;\n    while ((next = stream.next()) != null) {\n      if (next === '\"' && !escaped) {\n        end = true;\n        break;\n      }\n      escaped = !escaped && next === '\\\\';\n    }\n    if (end && !escaped) {\n      state.tokenize = tokenBase;\n    }\n    return 'string';\n  };\n\n  function tokenComment(stream, state) {\n    var prev, next;\n    while(state.commentLevel > 0 && (next = stream.next()) != null) {\n      if (prev === '(' && next === '*') state.commentLevel++;\n      if (prev === '*' && next === ')') state.commentLevel--;\n      prev = next;\n    }\n    if (state.commentLevel <= 0) {\n      state.tokenize = tokenBase;\n    }\n    return 'comment';\n  }\n\n  return {\n    startState: function() {return {tokenize: tokenBase, commentLevel: 0};},\n    token: function(stream, state) {\n      if (stream.eatSpace()) return null;\n      return state.tokenize(stream, state);\n    },\n\n    blockCommentStart: \"(*\",\n    blockCommentEnd: \"*)\",\n    lineComment: parserConfig.slashComments ? \"//\" : null\n  };\n});\n\nCodeMirror.defineMIME('text/x-ocaml', {\n  name: 'mllike',\n  extraWords: {\n    'succ': 'keyword',\n    'trace': 'builtin',\n    'exit': 'builtin',\n    'print_string': 'builtin',\n    'print_endline': 'builtin',\n    'true': 'atom',\n    'false': 'atom',\n    'raise': 'keyword'\n  }\n});\n\nCodeMirror.defineMIME('text/x-fsharp', {\n  name: 'mllike',\n  extraWords: {\n    'abstract': 'keyword',\n    'as': 'keyword',\n    'assert': 'keyword',\n    'base': 'keyword',\n    'class': 'keyword',\n    'default': 'keyword',\n    'delegate': 'keyword',\n    'downcast': 'keyword',\n    'downto': 'keyword',\n    'elif': 'keyword',\n    'exception': 'keyword',\n    'extern': 'keyword',\n    'finally': 'keyword',\n    'global': 'keyword',\n    'inherit': 'keyword',\n    'inline': 'keyword',\n    'interface': 'keyword',\n    'internal': 'keyword',\n    'lazy': 'keyword',\n    'let!': 'keyword',\n    'member' : 'keyword',\n    'module': 'keyword',\n    'namespace': 'keyword',\n    'new': 'keyword',\n    'null': 'keyword',\n    'override': 'keyword',\n    'private': 'keyword',\n    'public': 'keyword',\n    'return': 'keyword',\n    'return!': 'keyword',\n    'select': 'keyword',\n    'static': 'keyword',\n    'struct': 'keyword',\n    'upcast': 'keyword',\n    'use': 'keyword',\n    'use!': 'keyword',\n    'val': 'keyword',\n    'when': 'keyword',\n    'yield': 'keyword',\n    'yield!': 'keyword',\n\n    'List': 'builtin',\n    'Seq': 'builtin',\n    'Map': 'builtin',\n    'Set': 'builtin',\n    'int': 'builtin',\n    'string': 'builtin',\n    'raise': 'builtin',\n    'failwith': 'builtin',\n    'not': 'builtin',\n    'true': 'builtin',\n    'false': 'builtin'\n  },\n  slashComments: true\n});\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/modelica/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Modelica mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"../../addon/edit/matchbrackets.js\"></script>\n<link rel=\"stylesheet\" href=\"../../addon/hint/show-hint.css\">\n<script src=\"../../addon/hint/show-hint.js\"></script>\n<script src=\"modelica.js\"></script>\n<style>.CodeMirror {border: 2px inset #dee;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Modelica</a>\n  </ul>\n</div>\n\n<article>\n<h2>Modelica mode</h2>\n\n<div><textarea id=\"modelica\">\nmodel BouncingBall\n  parameter Real e = 0.7;\n  parameter Real g = 9.81;\n  Real h(start=1);\n  Real v;\n  Boolean flying(start=true);\n  Boolean impact;\n  Real v_new;\nequation\n  impact = h <= 0.0;\n  der(v) = if flying then -g else 0;\n  der(h) = v;\n  when {h <= 0.0 and v <= 0.0, impact} then\n    v_new = if edge(impact) then -e*pre(v) else 0;\n    flying = v_new > 0;\n    reinit(v, v_new);\n  end when;\n  annotation (uses(Modelica(version=\"3.2\")));\nend BouncingBall;\n</textarea></div>\n\n    <script>\n      var modelicaEditor = CodeMirror.fromTextArea(document.getElementById(\"modelica\"), {\n        lineNumbers: true,\n        matchBrackets: true,\n        mode: \"text/x-modelica\"\n      });\n      var mac = CodeMirror.keyMap.default == CodeMirror.keyMap.macDefault;\n      CodeMirror.keyMap.default[(mac ? \"Cmd\" : \"Ctrl\") + \"-Space\"] = \"autocomplete\";\n    </script>\n\n    <p>Simple mode that tries to handle Modelica as well as it can.</p>\n\n    <p><strong>MIME types defined:</strong> <code>text/x-modelica</code>\n    (Modlica code).</p>\n</article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/modelica/modelica.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n// Modelica support for CodeMirror, copyright (c) by Lennart Ochel\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})\n\n(function(CodeMirror) {\n  \"use strict\";\n\n  CodeMirror.defineMode(\"modelica\", function(config, parserConfig) {\n\n    var indentUnit = config.indentUnit;\n    var keywords = parserConfig.keywords || {};\n    var builtin = parserConfig.builtin || {};\n    var atoms = parserConfig.atoms || {};\n\n    var isSingleOperatorChar = /[;=\\(:\\),{}.*<>+\\-\\/^\\[\\]]/;\n    var isDoubleOperatorChar = /(:=|<=|>=|==|<>|\\.\\+|\\.\\-|\\.\\*|\\.\\/|\\.\\^)/;\n    var isDigit = /[0-9]/;\n    var isNonDigit = /[_a-zA-Z]/;\n\n    function tokenLineComment(stream, state) {\n      stream.skipToEnd();\n      state.tokenize = null;\n      return \"comment\";\n    }\n\n    function tokenBlockComment(stream, state) {\n      var maybeEnd = false, ch;\n      while (ch = stream.next()) {\n        if (maybeEnd && ch == \"/\") {\n          state.tokenize = null;\n          break;\n        }\n        maybeEnd = (ch == \"*\");\n      }\n      return \"comment\";\n    }\n\n    function tokenString(stream, state) {\n      var escaped = false, ch;\n      while ((ch = stream.next()) != null) {\n        if (ch == '\"' && !escaped) {\n          state.tokenize = null;\n          state.sol = false;\n          break;\n        }\n        escaped = !escaped && ch == \"\\\\\";\n      }\n\n      return \"string\";\n    }\n\n    function tokenIdent(stream, state) {\n      stream.eatWhile(isDigit);\n      while (stream.eat(isDigit) || stream.eat(isNonDigit)) { }\n\n\n      var cur = stream.current();\n\n      if(state.sol && (cur == \"package\" || cur == \"model\" || cur == \"when\" || cur == \"connector\")) state.level++;\n      else if(state.sol && cur == \"end\" && state.level > 0) state.level--;\n\n      state.tokenize = null;\n      state.sol = false;\n\n      if (keywords.propertyIsEnumerable(cur)) return \"keyword\";\n      else if (builtin.propertyIsEnumerable(cur)) return \"builtin\";\n      else if (atoms.propertyIsEnumerable(cur)) return \"atom\";\n      else return \"variable\";\n    }\n\n    function tokenQIdent(stream, state) {\n      while (stream.eat(/[^']/)) { }\n\n      state.tokenize = null;\n      state.sol = false;\n\n      if(stream.eat(\"'\"))\n        return \"variable\";\n      else\n        return \"error\";\n    }\n\n    function tokenUnsignedNuber(stream, state) {\n      stream.eatWhile(isDigit);\n      if (stream.eat('.')) {\n        stream.eatWhile(isDigit);\n      }\n      if (stream.eat('e') || stream.eat('E')) {\n        if (!stream.eat('-'))\n          stream.eat('+');\n        stream.eatWhile(isDigit);\n      }\n\n      state.tokenize = null;\n      state.sol = false;\n      return \"number\";\n    }\n\n    // Interface\n    return {\n      startState: function() {\n        return {\n          tokenize: null,\n          level: 0,\n          sol: true\n        };\n      },\n\n      token: function(stream, state) {\n        if(state.tokenize != null) {\n          return state.tokenize(stream, state);\n        }\n\n        if(stream.sol()) {\n          state.sol = true;\n        }\n\n        // WHITESPACE\n        if(stream.eatSpace()) {\n          state.tokenize = null;\n          return null;\n        }\n\n        var ch = stream.next();\n\n        // LINECOMMENT\n        if(ch == '/' && stream.eat('/')) {\n          state.tokenize = tokenLineComment;\n        }\n        // BLOCKCOMMENT\n        else if(ch == '/' && stream.eat('*')) {\n          state.tokenize = tokenBlockComment;\n        }\n        // TWO SYMBOL TOKENS\n        else if(isDoubleOperatorChar.test(ch+stream.peek())) {\n          stream.next();\n          state.tokenize = null;\n          return \"operator\";\n        }\n        // SINGLE SYMBOL TOKENS\n        else if(isSingleOperatorChar.test(ch)) {\n          state.tokenize = null;\n          return \"operator\";\n        }\n        // IDENT\n        else if(isNonDigit.test(ch)) {\n          state.tokenize = tokenIdent;\n        }\n        // Q-IDENT\n        else if(ch == \"'\" && stream.peek() && stream.peek() != \"'\") {\n          state.tokenize = tokenQIdent;\n        }\n        // STRING\n        else if(ch == '\"') {\n          state.tokenize = tokenString;\n        }\n        // UNSIGNED_NUBER\n        else if(isDigit.test(ch)) {\n          state.tokenize = tokenUnsignedNuber;\n        }\n        // ERROR\n        else {\n          state.tokenize = null;\n          return \"error\";\n        }\n\n        return state.tokenize(stream, state);\n      },\n\n      indent: function(state, textAfter) {\n        if (state.tokenize != null) return CodeMirror.Pass;\n\n        var level = state.level;\n        if(/(algorithm)/.test(textAfter)) level--;\n        if(/(equation)/.test(textAfter)) level--;\n        if(/(initial algorithm)/.test(textAfter)) level--;\n        if(/(initial equation)/.test(textAfter)) level--;\n        if(/(end)/.test(textAfter)) level--;\n\n        if(level > 0)\n          return indentUnit*level;\n        else\n          return 0;\n      },\n\n      blockCommentStart: \"/*\",\n      blockCommentEnd: \"*/\",\n      lineComment: \"//\"\n    };\n  });\n\n  function words(str) {\n    var obj = {}, words = str.split(\" \");\n    for (var i=0; i<words.length; ++i)\n      obj[words[i]] = true;\n    return obj;\n  }\n\n  var modelicaKeywords = \"algorithm and annotation assert block break class connect connector constant constrainedby der discrete each else elseif elsewhen encapsulated end enumeration equation expandable extends external false final flow for function if import impure in initial inner input loop model not operator or outer output package parameter partial protected public pure record redeclare replaceable return stream then true type when while within\";\n  var modelicaBuiltin = \"abs acos actualStream asin atan atan2 cardinality ceil cos cosh delay div edge exp floor getInstanceName homotopy inStream integer log log10 mod pre reinit rem semiLinear sign sin sinh spatialDistribution sqrt tan tanh\";\n  var modelicaAtoms = \"Real Boolean Integer String\";\n\n  function def(mimes, mode) {\n    if (typeof mimes == \"string\")\n      mimes = [mimes];\n\n    var words = [];\n\n    function add(obj) {\n      if (obj)\n        for (var prop in obj)\n          if (obj.hasOwnProperty(prop))\n            words.push(prop);\n    }\n\n    add(mode.keywords);\n    add(mode.builtin);\n    add(mode.atoms);\n\n    if (words.length) {\n      mode.helperType = mimes[0];\n      CodeMirror.registerHelper(\"hintWords\", mimes[0], words);\n    }\n\n    for (var i=0; i<mimes.length; ++i)\n      CodeMirror.defineMIME(mimes[i], mode);\n  }\n\n  def([\"text/x-modelica\"], {\n    name: \"modelica\",\n    keywords: words(modelicaKeywords),\n    builtin: words(modelicaBuiltin),\n    atoms: words(modelicaAtoms)\n  });\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/nginx/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: NGINX mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"nginx.js\"></script>\n<style>.CodeMirror {background: #f8f8f8;}</style>\n    <link rel=\"stylesheet\" href=\"../../doc/docs.css\">\n  </head>\n\n  <style>\n    body {\n      margin: 0em auto;\n    }\n\n    .CodeMirror, .CodeMirror-scroll {\n      height: 600px;\n    }\n  </style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">NGINX</a>\n  </ul>\n</div>\n\n<article>\n<h2>NGINX mode</h2>\n<form><textarea id=\"code\" name=\"code\" style=\"height: 800px;\">\nserver {\n  listen 173.255.219.235:80;\n  server_name website.com.au;\n  rewrite / $scheme://www.$host$request_uri permanent; ## Forcibly prepend a www\n}\n\nserver {\n  listen 173.255.219.235:443;\n  server_name website.com.au;\n  rewrite / $scheme://www.$host$request_uri permanent; ## Forcibly prepend a www\n}\n\nserver {\n\n  listen      173.255.219.235:80;\n  server_name www.website.com.au;\n\n\n\n  root        /data/www;\n  index       index.html index.php;\n\n  location / {\n    index index.html index.php;     ## Allow a static html file to be shown first\n    try_files $uri $uri/ @handler;  ## If missing pass the URI to Magento's front handler\n    expires 30d;                    ## Assume all files are cachable\n  }\n\n  ## These locations would be hidden by .htaccess normally\n  location /app/                { deny all; }\n  location /includes/           { deny all; }\n  location /lib/                { deny all; }\n  location /media/downloadable/ { deny all; }\n  location /pkginfo/            { deny all; }\n  location /report/config.xml   { deny all; }\n  location /var/                { deny all; }\n\n  location /var/export/ { ## Allow admins only to view export folder\n    auth_basic           \"Restricted\"; ## Message shown in login window\n    auth_basic_user_file /rs/passwords/testfile; ## See /etc/nginx/htpassword\n    autoindex            on;\n  }\n\n  location  /. { ## Disable .htaccess and other hidden files\n    return 404;\n  }\n\n  location @handler { ## Magento uses a common front handler\n    rewrite / /index.php;\n  }\n\n  location ~ .php/ { ## Forward paths like /js/index.php/x.js to relevant handler\n    rewrite ^/(.*.php)/ /$1 last;\n  }\n\n  location ~ \\.php$ {\n    if (!-e $request_filename) { rewrite / /index.php last; } ## Catch 404s that try_files miss\n\n    fastcgi_pass   127.0.0.1:9000;\n    fastcgi_index  index.php;\n    fastcgi_param PATH_INFO $fastcgi_script_name;\n    fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;\n    include        /rs/confs/nginx/fastcgi_params;\n  }\n\n}\n\n\nserver {\n\n  listen              173.255.219.235:443;\n  server_name         website.com.au www.website.com.au;\n\n  root   /data/www;\n  index index.html index.php;\n\n  ssl                 on;\n  ssl_certificate     /rs/ssl/ssl.crt;\n  ssl_certificate_key /rs/ssl/ssl.key;\n\n  ssl_session_timeout  5m;\n\n  ssl_protocols  SSLv2 SSLv3 TLSv1;\n  ssl_ciphers  ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;\n  ssl_prefer_server_ciphers   on;\n\n\n\n  location / {\n    index index.html index.php; ## Allow a static html file to be shown first\n    try_files $uri $uri/ @handler; ## If missing pass the URI to Magento's front handler\n    expires 30d; ## Assume all files are cachable\n  }\n\n  ## These locations would be hidden by .htaccess normally\n  location /app/                { deny all; }\n  location /includes/           { deny all; }\n  location /lib/                { deny all; }\n  location /media/downloadable/ { deny all; }\n  location /pkginfo/            { deny all; }\n  location /report/config.xml   { deny all; }\n  location /var/                { deny all; }\n\n  location /var/export/ { ## Allow admins only to view export folder\n    auth_basic           \"Restricted\"; ## Message shown in login window\n    auth_basic_user_file htpasswd; ## See /etc/nginx/htpassword\n    autoindex            on;\n  }\n\n  location  /. { ## Disable .htaccess and other hidden files\n    return 404;\n  }\n\n  location @handler { ## Magento uses a common front handler\n    rewrite / /index.php;\n  }\n\n  location ~ .php/ { ## Forward paths like /js/index.php/x.js to relevant handler\n    rewrite ^/(.*.php)/ /$1 last;\n  }\n\n  location ~ .php$ { ## Execute PHP scripts\n    if (!-e $request_filename) { rewrite  /index.php last; } ## Catch 404s that try_files miss\n\n    fastcgi_pass 127.0.0.1:9000;\n    fastcgi_index  index.php;\n    fastcgi_param PATH_INFO $fastcgi_script_name;\n    fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;\n    include        /rs/confs/nginx/fastcgi_params;\n\n    fastcgi_param HTTPS on;\n  }\n\n}\n</textarea></form>\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {});\n    </script>\n\n    <p><strong>MIME types defined:</strong> <code>text/nginx</code>.</p>\n\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/nginx/nginx.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"nginx\", function(config) {\n\n  function words(str) {\n    var obj = {}, words = str.split(\" \");\n    for (var i = 0; i < words.length; ++i) obj[words[i]] = true;\n    return obj;\n  }\n\n  var keywords = words(\n    /* ngxDirectiveControl */ \"break return rewrite set\" +\n    /* ngxDirective */ \" accept_mutex accept_mutex_delay access_log add_after_body add_before_body add_header addition_types aio alias allow ancient_browser ancient_browser_value auth_basic auth_basic_user_file auth_http auth_http_header auth_http_timeout autoindex autoindex_exact_size autoindex_localtime charset charset_types client_body_buffer_size client_body_in_file_only client_body_in_single_buffer client_body_temp_path client_body_timeout client_header_buffer_size client_header_timeout client_max_body_size connection_pool_size create_full_put_path daemon dav_access dav_methods debug_connection debug_points default_type degradation degrade deny devpoll_changes devpoll_events directio directio_alignment empty_gif env epoll_events error_log eventport_events expires fastcgi_bind fastcgi_buffer_size fastcgi_buffers fastcgi_busy_buffers_size fastcgi_cache fastcgi_cache_key fastcgi_cache_methods fastcgi_cache_min_uses fastcgi_cache_path fastcgi_cache_use_stale fastcgi_cache_valid fastcgi_catch_stderr fastcgi_connect_timeout fastcgi_hide_header fastcgi_ignore_client_abort fastcgi_ignore_headers fastcgi_index fastcgi_intercept_errors fastcgi_max_temp_file_size fastcgi_next_upstream fastcgi_param fastcgi_pass_header fastcgi_pass_request_body fastcgi_pass_request_headers fastcgi_read_timeout fastcgi_send_lowat fastcgi_send_timeout fastcgi_split_path_info fastcgi_store fastcgi_store_access fastcgi_temp_file_write_size fastcgi_temp_path fastcgi_upstream_fail_timeout fastcgi_upstream_max_fails flv geoip_city geoip_country google_perftools_profiles gzip gzip_buffers gzip_comp_level gzip_disable gzip_hash gzip_http_version gzip_min_length gzip_no_buffer gzip_proxied gzip_static gzip_types gzip_vary gzip_window if_modified_since ignore_invalid_headers image_filter image_filter_buffer image_filter_jpeg_quality image_filter_transparency imap_auth imap_capabilities imap_client_buffer index ip_hash keepalive_requests keepalive_timeout kqueue_changes kqueue_events large_client_header_buffers limit_conn limit_conn_log_level limit_rate limit_rate_after limit_req limit_req_log_level limit_req_zone limit_zone lingering_time lingering_timeout lock_file log_format log_not_found log_subrequest map_hash_bucket_size map_hash_max_size master_process memcached_bind memcached_buffer_size memcached_connect_timeout memcached_next_upstream memcached_read_timeout memcached_send_timeout memcached_upstream_fail_timeout memcached_upstream_max_fails merge_slashes min_delete_depth modern_browser modern_browser_value msie_padding msie_refresh multi_accept open_file_cache open_file_cache_errors open_file_cache_events open_file_cache_min_uses open_file_cache_valid open_log_file_cache output_buffers override_charset perl perl_modules perl_require perl_set pid pop3_auth pop3_capabilities port_in_redirect postpone_gzipping postpone_output protocol proxy proxy_bind proxy_buffer proxy_buffer_size proxy_buffering proxy_buffers proxy_busy_buffers_size proxy_cache proxy_cache_key proxy_cache_methods proxy_cache_min_uses proxy_cache_path proxy_cache_use_stale proxy_cache_valid proxy_connect_timeout proxy_headers_hash_bucket_size proxy_headers_hash_max_size proxy_hide_header proxy_ignore_client_abort proxy_ignore_headers proxy_intercept_errors proxy_max_temp_file_size proxy_method proxy_next_upstream proxy_pass_error_message proxy_pass_header proxy_pass_request_body proxy_pass_request_headers proxy_read_timeout proxy_redirect proxy_send_lowat proxy_send_timeout proxy_set_body proxy_set_header proxy_ssl_session_reuse proxy_store proxy_store_access proxy_temp_file_write_size proxy_temp_path proxy_timeout proxy_upstream_fail_timeout proxy_upstream_max_fails random_index read_ahead real_ip_header recursive_error_pages request_pool_size reset_timedout_connection resolver resolver_timeout rewrite_log rtsig_overflow_events rtsig_overflow_test rtsig_overflow_threshold rtsig_signo satisfy secure_link_secret send_lowat send_timeout sendfile sendfile_max_chunk server_name_in_redirect server_names_hash_bucket_size server_names_hash_max_size server_tokens set_real_ip_from smtp_auth smtp_capabilities smtp_client_buffer smtp_greeting_delay so_keepalive source_charset ssi ssi_ignore_recycled_buffers ssi_min_file_chunk ssi_silent_errors ssi_types ssi_value_length ssl ssl_certificate ssl_certificate_key ssl_ciphers ssl_client_certificate ssl_crl ssl_dhparam ssl_engine ssl_prefer_server_ciphers ssl_protocols ssl_session_cache ssl_session_timeout ssl_verify_client ssl_verify_depth starttls stub_status sub_filter sub_filter_once sub_filter_types tcp_nodelay tcp_nopush thread_stack_size timeout timer_resolution types_hash_bucket_size types_hash_max_size underscores_in_headers uninitialized_variable_warn use user userid userid_domain userid_expires userid_mark userid_name userid_p3p userid_path userid_service valid_referers variables_hash_bucket_size variables_hash_max_size worker_connections worker_cpu_affinity worker_priority worker_processes worker_rlimit_core worker_rlimit_nofile worker_rlimit_sigpending worker_threads working_directory xclient xml_entities xslt_stylesheet xslt_typesdrew@li229-23\"\n    );\n\n  var keywords_block = words(\n    /* ngxDirectiveBlock */ \"http mail events server types location upstream charset_map limit_except if geo map\"\n    );\n\n  var keywords_important = words(\n    /* ngxDirectiveImportant */ \"include root server server_name listen internal proxy_pass memcached_pass fastcgi_pass try_files\"\n    );\n\n  var indentUnit = config.indentUnit, type;\n  function ret(style, tp) {type = tp; return style;}\n\n  function tokenBase(stream, state) {\n\n\n    stream.eatWhile(/[\\w\\$_]/);\n\n    var cur = stream.current();\n\n\n    if (keywords.propertyIsEnumerable(cur)) {\n      return \"keyword\";\n    }\n    else if (keywords_block.propertyIsEnumerable(cur)) {\n      return \"variable-2\";\n    }\n    else if (keywords_important.propertyIsEnumerable(cur)) {\n      return \"string-2\";\n    }\n    /**/\n\n    var ch = stream.next();\n    if (ch == \"@\") {stream.eatWhile(/[\\w\\\\\\-]/); return ret(\"meta\", stream.current());}\n    else if (ch == \"/\" && stream.eat(\"*\")) {\n      state.tokenize = tokenCComment;\n      return tokenCComment(stream, state);\n    }\n    else if (ch == \"<\" && stream.eat(\"!\")) {\n      state.tokenize = tokenSGMLComment;\n      return tokenSGMLComment(stream, state);\n    }\n    else if (ch == \"=\") ret(null, \"compare\");\n    else if ((ch == \"~\" || ch == \"|\") && stream.eat(\"=\")) return ret(null, \"compare\");\n    else if (ch == \"\\\"\" || ch == \"'\") {\n      state.tokenize = tokenString(ch);\n      return state.tokenize(stream, state);\n    }\n    else if (ch == \"#\") {\n      stream.skipToEnd();\n      return ret(\"comment\", \"comment\");\n    }\n    else if (ch == \"!\") {\n      stream.match(/^\\s*\\w*/);\n      return ret(\"keyword\", \"important\");\n    }\n    else if (/\\d/.test(ch)) {\n      stream.eatWhile(/[\\w.%]/);\n      return ret(\"number\", \"unit\");\n    }\n    else if (/[,.+>*\\/]/.test(ch)) {\n      return ret(null, \"select-op\");\n    }\n    else if (/[;{}:\\[\\]]/.test(ch)) {\n      return ret(null, ch);\n    }\n    else {\n      stream.eatWhile(/[\\w\\\\\\-]/);\n      return ret(\"variable\", \"variable\");\n    }\n  }\n\n  function tokenCComment(stream, state) {\n    var maybeEnd = false, ch;\n    while ((ch = stream.next()) != null) {\n      if (maybeEnd && ch == \"/\") {\n        state.tokenize = tokenBase;\n        break;\n      }\n      maybeEnd = (ch == \"*\");\n    }\n    return ret(\"comment\", \"comment\");\n  }\n\n  function tokenSGMLComment(stream, state) {\n    var dashes = 0, ch;\n    while ((ch = stream.next()) != null) {\n      if (dashes >= 2 && ch == \">\") {\n        state.tokenize = tokenBase;\n        break;\n      }\n      dashes = (ch == \"-\") ? dashes + 1 : 0;\n    }\n    return ret(\"comment\", \"comment\");\n  }\n\n  function tokenString(quote) {\n    return function(stream, state) {\n      var escaped = false, ch;\n      while ((ch = stream.next()) != null) {\n        if (ch == quote && !escaped)\n          break;\n        escaped = !escaped && ch == \"\\\\\";\n      }\n      if (!escaped) state.tokenize = tokenBase;\n      return ret(\"string\", \"string\");\n    };\n  }\n\n  return {\n    startState: function(base) {\n      return {tokenize: tokenBase,\n              baseIndent: base || 0,\n              stack: []};\n    },\n\n    token: function(stream, state) {\n      if (stream.eatSpace()) return null;\n      type = null;\n      var style = state.tokenize(stream, state);\n\n      var context = state.stack[state.stack.length-1];\n      if (type == \"hash\" && context == \"rule\") style = \"atom\";\n      else if (style == \"variable\") {\n        if (context == \"rule\") style = \"number\";\n        else if (!context || context == \"@media{\") style = \"tag\";\n      }\n\n      if (context == \"rule\" && /^[\\{\\};]$/.test(type))\n        state.stack.pop();\n      if (type == \"{\") {\n        if (context == \"@media\") state.stack[state.stack.length-1] = \"@media{\";\n        else state.stack.push(\"{\");\n      }\n      else if (type == \"}\") state.stack.pop();\n      else if (type == \"@media\") state.stack.push(\"@media\");\n      else if (context == \"{\" && type != \"comment\") state.stack.push(\"rule\");\n      return style;\n    },\n\n    indent: function(state, textAfter) {\n      var n = state.stack.length;\n      if (/^\\}/.test(textAfter))\n        n -= state.stack[state.stack.length-1] == \"rule\" ? 2 : 1;\n      return state.baseIndent + n * indentUnit;\n    },\n\n    electricChars: \"}\"\n  };\n});\n\nCodeMirror.defineMIME(\"text/nginx\", \"text/x-nginx-conf\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/ntriples/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: NTriples mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"ntriples.js\"></script>\n<style type=\"text/css\">\n      .CodeMirror {\n        border: 1px solid #eee;\n      }\n    </style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">NTriples</a>\n  </ul>\n</div>\n\n<article>\n<h2>NTriples mode</h2>\n<form>\n<textarea id=\"ntriples\" name=\"ntriples\">    \n<http://Sub1>     <http://pred1>     <http://obj> .\n<http://Sub2>     <http://pred2#an2> \"literal 1\" .\n<http://Sub3#an3> <http://pred3>     _:bnode3 .\n_:bnode4          <http://pred4>     \"literal 2\"@lang .\n_:bnode5          <http://pred5>     \"literal 3\"^^<http://type> .\n</textarea>\n</form>\n\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"ntriples\"), {});\n    </script>\n    <p><strong>MIME types defined:</strong> <code>text/n-triples</code>.</p>\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/ntriples/ntriples.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n/**********************************************************\n* This script provides syntax highlighting support for\n* the Ntriples format.\n* Ntriples format specification:\n*     http://www.w3.org/TR/rdf-testcases/#ntriples\n***********************************************************/\n\n/*\n    The following expression defines the defined ASF grammar transitions.\n\n    pre_subject ->\n        {\n        ( writing_subject_uri | writing_bnode_uri )\n            -> pre_predicate\n                -> writing_predicate_uri\n                    -> pre_object\n                        -> writing_object_uri | writing_object_bnode |\n                          (\n                            writing_object_literal\n                                -> writing_literal_lang | writing_literal_type\n                          )\n                            -> post_object\n                                -> BEGIN\n         } otherwise {\n             -> ERROR\n         }\n*/\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"ntriples\", function() {\n\n  var Location = {\n    PRE_SUBJECT         : 0,\n    WRITING_SUB_URI     : 1,\n    WRITING_BNODE_URI   : 2,\n    PRE_PRED            : 3,\n    WRITING_PRED_URI    : 4,\n    PRE_OBJ             : 5,\n    WRITING_OBJ_URI     : 6,\n    WRITING_OBJ_BNODE   : 7,\n    WRITING_OBJ_LITERAL : 8,\n    WRITING_LIT_LANG    : 9,\n    WRITING_LIT_TYPE    : 10,\n    POST_OBJ            : 11,\n    ERROR               : 12\n  };\n  function transitState(currState, c) {\n    var currLocation = currState.location;\n    var ret;\n\n    // Opening.\n    if     (currLocation == Location.PRE_SUBJECT && c == '<') ret = Location.WRITING_SUB_URI;\n    else if(currLocation == Location.PRE_SUBJECT && c == '_') ret = Location.WRITING_BNODE_URI;\n    else if(currLocation == Location.PRE_PRED    && c == '<') ret = Location.WRITING_PRED_URI;\n    else if(currLocation == Location.PRE_OBJ     && c == '<') ret = Location.WRITING_OBJ_URI;\n    else if(currLocation == Location.PRE_OBJ     && c == '_') ret = Location.WRITING_OBJ_BNODE;\n    else if(currLocation == Location.PRE_OBJ     && c == '\"') ret = Location.WRITING_OBJ_LITERAL;\n\n    // Closing.\n    else if(currLocation == Location.WRITING_SUB_URI     && c == '>') ret = Location.PRE_PRED;\n    else if(currLocation == Location.WRITING_BNODE_URI   && c == ' ') ret = Location.PRE_PRED;\n    else if(currLocation == Location.WRITING_PRED_URI    && c == '>') ret = Location.PRE_OBJ;\n    else if(currLocation == Location.WRITING_OBJ_URI     && c == '>') ret = Location.POST_OBJ;\n    else if(currLocation == Location.WRITING_OBJ_BNODE   && c == ' ') ret = Location.POST_OBJ;\n    else if(currLocation == Location.WRITING_OBJ_LITERAL && c == '\"') ret = Location.POST_OBJ;\n    else if(currLocation == Location.WRITING_LIT_LANG && c == ' ') ret = Location.POST_OBJ;\n    else if(currLocation == Location.WRITING_LIT_TYPE && c == '>') ret = Location.POST_OBJ;\n\n    // Closing typed and language literal.\n    else if(currLocation == Location.WRITING_OBJ_LITERAL && c == '@') ret = Location.WRITING_LIT_LANG;\n    else if(currLocation == Location.WRITING_OBJ_LITERAL && c == '^') ret = Location.WRITING_LIT_TYPE;\n\n    // Spaces.\n    else if( c == ' ' &&\n             (\n               currLocation == Location.PRE_SUBJECT ||\n               currLocation == Location.PRE_PRED    ||\n               currLocation == Location.PRE_OBJ     ||\n               currLocation == Location.POST_OBJ\n             )\n           ) ret = currLocation;\n\n    // Reset.\n    else if(currLocation == Location.POST_OBJ && c == '.') ret = Location.PRE_SUBJECT;\n\n    // Error\n    else ret = Location.ERROR;\n\n    currState.location=ret;\n  }\n\n  return {\n    startState: function() {\n       return {\n           location : Location.PRE_SUBJECT,\n           uris     : [],\n           anchors  : [],\n           bnodes   : [],\n           langs    : [],\n           types    : []\n       };\n    },\n    token: function(stream, state) {\n      var ch = stream.next();\n      if(ch == '<') {\n         transitState(state, ch);\n         var parsedURI = '';\n         stream.eatWhile( function(c) { if( c != '#' && c != '>' ) { parsedURI += c; return true; } return false;} );\n         state.uris.push(parsedURI);\n         if( stream.match('#', false) ) return 'variable';\n         stream.next();\n         transitState(state, '>');\n         return 'variable';\n      }\n      if(ch == '#') {\n        var parsedAnchor = '';\n        stream.eatWhile(function(c) { if(c != '>' && c != ' ') { parsedAnchor+= c; return true; } return false;});\n        state.anchors.push(parsedAnchor);\n        return 'variable-2';\n      }\n      if(ch == '>') {\n          transitState(state, '>');\n          return 'variable';\n      }\n      if(ch == '_') {\n          transitState(state, ch);\n          var parsedBNode = '';\n          stream.eatWhile(function(c) { if( c != ' ' ) { parsedBNode += c; return true; } return false;});\n          state.bnodes.push(parsedBNode);\n          stream.next();\n          transitState(state, ' ');\n          return 'builtin';\n      }\n      if(ch == '\"') {\n          transitState(state, ch);\n          stream.eatWhile( function(c) { return c != '\"'; } );\n          stream.next();\n          if( stream.peek() != '@' && stream.peek() != '^' ) {\n              transitState(state, '\"');\n          }\n          return 'string';\n      }\n      if( ch == '@' ) {\n          transitState(state, '@');\n          var parsedLang = '';\n          stream.eatWhile(function(c) { if( c != ' ' ) { parsedLang += c; return true; } return false;});\n          state.langs.push(parsedLang);\n          stream.next();\n          transitState(state, ' ');\n          return 'string-2';\n      }\n      if( ch == '^' ) {\n          stream.next();\n          transitState(state, '^');\n          var parsedType = '';\n          stream.eatWhile(function(c) { if( c != '>' ) { parsedType += c; return true; } return false;} );\n          state.types.push(parsedType);\n          stream.next();\n          transitState(state, '>');\n          return 'variable';\n      }\n      if( ch == ' ' ) {\n          transitState(state, ch);\n      }\n      if( ch == '.' ) {\n          transitState(state, ch);\n      }\n    }\n  };\n});\n\nCodeMirror.defineMIME(\"text/n-triples\", \"ntriples\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/octave/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Octave mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"octave.js\"></script>\n<style type=\"text/css\">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Octave</a>\n  </ul>\n</div>\n\n<article>\n<h2>Octave mode</h2>\n\n    <div><textarea id=\"code\" name=\"code\">\n%numbers\n[1234 1234i 1234j]\n[.234 .234j 2.23i]\n[23e2 12E1j 123D-4 0x234]\n\n%strings\n'asda''a'\n\"asda\"\"a\"\n\n%identifiers\na + as123 - __asd__\n\n%operators\n-\n+\n=\n==\n>\n<\n>=\n<=\n&\n~\n...\nbreak zeros default margin round ones rand\nceil floor size clear zeros eye mean std cov\nerror eval function\nabs acos atan asin cos cosh exp log prod sum\nlog10 max min sign sin sinh sqrt tan reshape\nreturn\ncase switch\nelse elseif end if otherwise\ndo for while\ntry catch\nclassdef properties events methods\nglobal persistent\n\n%one line comment\n%{ multi \nline commment %}\n\n    </textarea></div>\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        mode: {name: \"octave\",\n               version: 2,\n               singleLineStringErrors: false},\n        lineNumbers: true,\n        indentUnit: 4,\n        matchBrackets: true\n      });\n    </script>\n\n    <p><strong>MIME types defined:</strong> <code>text/x-octave</code>.</p>\n</article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/octave/octave.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"octave\", function() {\n  function wordRegexp(words) {\n    return new RegExp(\"^((\" + words.join(\")|(\") + \"))\\\\b\");\n  }\n\n  var singleOperators = new RegExp(\"^[\\\\+\\\\-\\\\*/&|\\\\^~<>!@'\\\\\\\\]\");\n  var singleDelimiters = new RegExp('^[\\\\(\\\\[\\\\{\\\\},:=;]');\n  var doubleOperators = new RegExp(\"^((==)|(~=)|(<=)|(>=)|(<<)|(>>)|(\\\\.[\\\\+\\\\-\\\\*/\\\\^\\\\\\\\]))\");\n  var doubleDelimiters = new RegExp(\"^((!=)|(\\\\+=)|(\\\\-=)|(\\\\*=)|(/=)|(&=)|(\\\\|=)|(\\\\^=))\");\n  var tripleDelimiters = new RegExp(\"^((>>=)|(<<=))\");\n  var expressionEnd = new RegExp(\"^[\\\\]\\\\)]\");\n  var identifiers = new RegExp(\"^[_A-Za-z\\xa1-\\uffff][_A-Za-z0-9\\xa1-\\uffff]*\");\n\n  var builtins = wordRegexp([\n    'error', 'eval', 'function', 'abs', 'acos', 'atan', 'asin', 'cos',\n    'cosh', 'exp', 'log', 'prod', 'sum', 'log10', 'max', 'min', 'sign', 'sin', 'sinh',\n    'sqrt', 'tan', 'reshape', 'break', 'zeros', 'default', 'margin', 'round', 'ones',\n    'rand', 'syn', 'ceil', 'floor', 'size', 'clear', 'zeros', 'eye', 'mean', 'std', 'cov',\n    'det', 'eig', 'inv', 'norm', 'rank', 'trace', 'expm', 'logm', 'sqrtm', 'linspace', 'plot',\n    'title', 'xlabel', 'ylabel', 'legend', 'text', 'grid', 'meshgrid', 'mesh', 'num2str',\n    'fft', 'ifft', 'arrayfun', 'cellfun', 'input', 'fliplr', 'flipud', 'ismember'\n  ]);\n\n  var keywords = wordRegexp([\n    'return', 'case', 'switch', 'else', 'elseif', 'end', 'endif', 'endfunction',\n    'if', 'otherwise', 'do', 'for', 'while', 'try', 'catch', 'classdef', 'properties', 'events',\n    'methods', 'global', 'persistent', 'endfor', 'endwhile', 'printf', 'sprintf', 'disp', 'until',\n    'continue', 'pkg'\n  ]);\n\n\n  // tokenizers\n  function tokenTranspose(stream, state) {\n    if (!stream.sol() && stream.peek() === '\\'') {\n      stream.next();\n      state.tokenize = tokenBase;\n      return 'operator';\n    }\n    state.tokenize = tokenBase;\n    return tokenBase(stream, state);\n  }\n\n\n  function tokenComment(stream, state) {\n    if (stream.match(/^.*%}/)) {\n      state.tokenize = tokenBase;\n      return 'comment';\n    };\n    stream.skipToEnd();\n    return 'comment';\n  }\n\n  function tokenBase(stream, state) {\n    // whitespaces\n    if (stream.eatSpace()) return null;\n\n    // Handle one line Comments\n    if (stream.match('%{')){\n      state.tokenize = tokenComment;\n      stream.skipToEnd();\n      return 'comment';\n    }\n\n    if (stream.match(/^[%#]/)){\n      stream.skipToEnd();\n      return 'comment';\n    }\n\n    // Handle Number Literals\n    if (stream.match(/^[0-9\\.+-]/, false)) {\n      if (stream.match(/^[+-]?0x[0-9a-fA-F]+[ij]?/)) {\n        stream.tokenize = tokenBase;\n        return 'number'; };\n      if (stream.match(/^[+-]?\\d*\\.\\d+([EeDd][+-]?\\d+)?[ij]?/)) { return 'number'; };\n      if (stream.match(/^[+-]?\\d+([EeDd][+-]?\\d+)?[ij]?/)) { return 'number'; };\n    }\n    if (stream.match(wordRegexp(['nan','NaN','inf','Inf']))) { return 'number'; };\n\n    // Handle Strings\n    if (stream.match(/^\"([^\"]|(\"\"))*\"/)) { return 'string'; } ;\n    if (stream.match(/^'([^']|(''))*'/)) { return 'string'; } ;\n\n    // Handle words\n    if (stream.match(keywords)) { return 'keyword'; } ;\n    if (stream.match(builtins)) { return 'builtin'; } ;\n    if (stream.match(identifiers)) { return 'variable'; } ;\n\n    if (stream.match(singleOperators) || stream.match(doubleOperators)) { return 'operator'; };\n    if (stream.match(singleDelimiters) || stream.match(doubleDelimiters) || stream.match(tripleDelimiters)) { return null; };\n\n    if (stream.match(expressionEnd)) {\n      state.tokenize = tokenTranspose;\n      return null;\n    };\n\n\n    // Handle non-detected items\n    stream.next();\n    return 'error';\n  };\n\n\n  return {\n    startState: function() {\n      return {\n        tokenize: tokenBase\n      };\n    },\n\n    token: function(stream, state) {\n      var style = state.tokenize(stream, state);\n      if (style === 'number' || style === 'variable'){\n        state.tokenize = tokenTranspose;\n      }\n      return style;\n    }\n  };\n});\n\nCodeMirror.defineMIME(\"text/x-octave\", \"octave\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/pascal/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Pascal mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"pascal.js\"></script>\n<style type=\"text/css\">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Pascal</a>\n  </ul>\n</div>\n\n<article>\n<h2>Pascal mode</h2>\n\n\n<div><textarea id=\"code\" name=\"code\">\n(* Example Pascal code *)\n\nwhile a <> b do writeln('Waiting');\n \nif a > b then \n  writeln('Condition met')\nelse \n  writeln('Condition not met');\n \nfor i := 1 to 10 do \n  writeln('Iteration: ', i:1);\n \nrepeat\n  a := a + 1\nuntil a = 10;\n \ncase i of\n  0: write('zero');\n  1: write('one');\n  2: write('two')\nend;\n</textarea></div>\n\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        lineNumbers: true,\n        mode: \"text/x-pascal\"\n      });\n    </script>\n\n    <p><strong>MIME types defined:</strong> <code>text/x-pascal</code>.</p>\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/pascal/pascal.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"pascal\", function() {\n  function words(str) {\n    var obj = {}, words = str.split(\" \");\n    for (var i = 0; i < words.length; ++i) obj[words[i]] = true;\n    return obj;\n  }\n  var keywords = words(\"and array begin case const div do downto else end file for forward integer \" +\n                       \"boolean char function goto if in label mod nil not of or packed procedure \" +\n                       \"program record repeat set string then to type until var while with\");\n  var atoms = {\"null\": true};\n\n  var isOperatorChar = /[+\\-*&%=<>!?|\\/]/;\n\n  function tokenBase(stream, state) {\n    var ch = stream.next();\n    if (ch == \"#\" && state.startOfLine) {\n      stream.skipToEnd();\n      return \"meta\";\n    }\n    if (ch == '\"' || ch == \"'\") {\n      state.tokenize = tokenString(ch);\n      return state.tokenize(stream, state);\n    }\n    if (ch == \"(\" && stream.eat(\"*\")) {\n      state.tokenize = tokenComment;\n      return tokenComment(stream, state);\n    }\n    if (/[\\[\\]{}\\(\\),;\\:\\.]/.test(ch)) {\n      return null;\n    }\n    if (/\\d/.test(ch)) {\n      stream.eatWhile(/[\\w\\.]/);\n      return \"number\";\n    }\n    if (ch == \"/\") {\n      if (stream.eat(\"/\")) {\n        stream.skipToEnd();\n        return \"comment\";\n      }\n    }\n    if (isOperatorChar.test(ch)) {\n      stream.eatWhile(isOperatorChar);\n      return \"operator\";\n    }\n    stream.eatWhile(/[\\w\\$_]/);\n    var cur = stream.current();\n    if (keywords.propertyIsEnumerable(cur)) return \"keyword\";\n    if (atoms.propertyIsEnumerable(cur)) return \"atom\";\n    return \"variable\";\n  }\n\n  function tokenString(quote) {\n    return function(stream, state) {\n      var escaped = false, next, end = false;\n      while ((next = stream.next()) != null) {\n        if (next == quote && !escaped) {end = true; break;}\n        escaped = !escaped && next == \"\\\\\";\n      }\n      if (end || !escaped) state.tokenize = null;\n      return \"string\";\n    };\n  }\n\n  function tokenComment(stream, state) {\n    var maybeEnd = false, ch;\n    while (ch = stream.next()) {\n      if (ch == \")\" && maybeEnd) {\n        state.tokenize = null;\n        break;\n      }\n      maybeEnd = (ch == \"*\");\n    }\n    return \"comment\";\n  }\n\n  // Interface\n\n  return {\n    startState: function() {\n      return {tokenize: null};\n    },\n\n    token: function(stream, state) {\n      if (stream.eatSpace()) return null;\n      var style = (state.tokenize || tokenBase)(stream, state);\n      if (style == \"comment\" || style == \"meta\") return style;\n      return style;\n    },\n\n    electricChars: \"{}\"\n  };\n});\n\nCodeMirror.defineMIME(\"text/x-pascal\", \"pascal\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/pegjs/index.html",
    "content": "<!doctype html>\n<html>\n  <head>\n    <title>CodeMirror: PEG.js Mode</title>\n    <meta charset=\"utf-8\"/>\n    <link rel=stylesheet href=\"../../doc/docs.css\">\n\n    <link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n    <script src=\"../../lib/codemirror.js\"></script>\n    <script src=\"../javascript/javascript.js\"></script>\n    <script src=\"pegjs.js\"></script>\n    <style type=\"text/css\">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>\n  </head>\n  <body>\n    <div id=nav>\n      <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n      <ul>\n        <li><a href=\"../../index.html\">Home</a>\n        <li><a href=\"../../doc/manual.html\">Manual</a>\n        <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n      </ul>\n      <ul>\n        <li><a href=\"../index.html\">Language modes</a>\n        <li><a class=active href=\"#\">PEG.js Mode</a>\n      </ul>\n    </div>\n\n    <article>\n      <h2>PEG.js Mode</h2>\n      <form><textarea id=\"code\" name=\"code\">\n/*\n * Classic example grammar, which recognizes simple arithmetic expressions like\n * \"2*(3+4)\". The parser generated from this grammar then computes their value.\n */\n\nstart\n  = additive\n\nadditive\n  = left:multiplicative \"+\" right:additive { return left + right; }\n  / multiplicative\n\nmultiplicative\n  = left:primary \"*\" right:multiplicative { return left * right; }\n  / primary\n\nprimary\n  = integer\n  / \"(\" additive:additive \")\" { return additive; }\n\ninteger \"integer\"\n  = digits:[0-9]+ { return parseInt(digits.join(\"\"), 10); }\n\nletter = [a-z]+</textarea></form>\n      <script>\n        var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n          mode: {name: \"pegjs\"},\n          lineNumbers: true\n        });\n      </script>\n      <h3>The PEG.js Mode</h3>\n      <p> Created by Forbes Lindesay.</p>\n    </article>\n  </body>\n</html>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/pegjs/pegjs.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"), require(\"../javascript/javascript\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\", \"../javascript/javascript\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"pegjs\", function (config) {\n  var jsMode = CodeMirror.getMode(config, \"javascript\");\n\n  function identifier(stream) {\n    return stream.match(/^[a-zA-Z_][a-zA-Z0-9_]*/);\n  }\n\n  return {\n    startState: function () {\n      return {\n        inString: false,\n        stringType: null,\n        inComment: false,\n        inChracterClass: false,\n        braced: 0,\n        lhs: true,\n        localState: null\n      };\n    },\n    token: function (stream, state) {\n      if (stream)\n\n      //check for state changes\n      if (!state.inString && !state.inComment && ((stream.peek() == '\"') || (stream.peek() == \"'\"))) {\n        state.stringType = stream.peek();\n        stream.next(); // Skip quote\n        state.inString = true; // Update state\n      }\n      if (!state.inString && !state.inComment && stream.match(/^\\/\\*/)) {\n        state.inComment = true;\n      }\n\n      //return state\n      if (state.inString) {\n        while (state.inString && !stream.eol()) {\n          if (stream.peek() === state.stringType) {\n            stream.next(); // Skip quote\n            state.inString = false; // Clear flag\n          } else if (stream.peek() === '\\\\') {\n            stream.next();\n            stream.next();\n          } else {\n            stream.match(/^.[^\\\\\\\"\\']*/);\n          }\n        }\n        return state.lhs ? \"property string\" : \"string\"; // Token style\n      } else if (state.inComment) {\n        while (state.inComment && !stream.eol()) {\n          if (stream.match(/\\*\\//)) {\n            state.inComment = false; // Clear flag\n          } else {\n            stream.match(/^.[^\\*]*/);\n          }\n        }\n        return \"comment\";\n      } else if (state.inChracterClass) {\n          while (state.inChracterClass && !stream.eol()) {\n            if (!(stream.match(/^[^\\]\\\\]+/) || stream.match(/^\\\\./))) {\n              state.inChracterClass = false;\n            }\n          }\n      } else if (stream.peek() === '[') {\n        stream.next();\n        state.inChracterClass = true;\n        return 'bracket';\n      } else if (stream.match(/^\\/\\//)) {\n        stream.skipToEnd();\n        return \"comment\";\n      } else if (state.braced || stream.peek() === '{') {\n        if (state.localState === null) {\n          state.localState = jsMode.startState();\n        }\n        var token = jsMode.token(stream, state.localState);\n        var text = stream.current();\n        if (!token) {\n          for (var i = 0; i < text.length; i++) {\n            if (text[i] === '{') {\n              state.braced++;\n            } else if (text[i] === '}') {\n              state.braced--;\n            }\n          };\n        }\n        return token;\n      } else if (identifier(stream)) {\n        if (stream.peek() === ':') {\n          return 'variable';\n        }\n        return 'variable-2';\n      } else if (['[', ']', '(', ')'].indexOf(stream.peek()) != -1) {\n        stream.next();\n        return 'bracket';\n      } else if (!stream.eatSpace()) {\n        stream.next();\n      }\n      return null;\n    }\n  };\n}, \"javascript\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/perl/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Perl mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"perl.js\"></script>\n<style type=\"text/css\">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Perl</a>\n  </ul>\n</div>\n\n<article>\n<h2>Perl mode</h2>\n\n\n<div><textarea id=\"code\" name=\"code\">\n#!/usr/bin/perl\n\nuse Something qw(func1 func2);\n\n# strings\nmy $s1 = qq'single line';\nour $s2 = q(multi-\n              line);\n\n=item Something\n\tExample.\n=cut\n\nmy $html=<<'HTML'\n<html>\n<title>hi!</title>\n</html>\nHTML\n\nprint \"first,\".join(',', 'second', qq~third~);\n\nif($s1 =~ m[(?<!\\s)(l.ne)\\z]o) {\n\t$h->{$1}=$$.' predefined variables';\n\t$s2 =~ s/\\-line//ox;\n\t$s1 =~ s[\n\t\t  line ]\n\t\t[\n\t\t  block\n\t\t]ox;\n}\n\n1; # numbers and comments\n\n__END__\nsomething...\n\n</textarea></div>\n\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        lineNumbers: true\n      });\n    </script>\n\n    <p><strong>MIME types defined:</strong> <code>text/x-perl</code>.</p>\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/perl/perl.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n// CodeMirror2 mode/perl/perl.js (text/x-perl) beta 0.10 (2011-11-08)\n// This is a part of CodeMirror from https://github.com/sabaca/CodeMirror_mode_perl (mail@sabaca.com)\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"perl\",function(){\n        // http://perldoc.perl.org\n        var PERL={                                      //   null - magic touch\n                                                        //   1 - keyword\n                                                        //   2 - def\n                                                        //   3 - atom\n                                                        //   4 - operator\n                                                        //   5 - variable-2 (predefined)\n                                                        //   [x,y] - x=1,2,3; y=must be defined if x{...}\n                                                //      PERL operators\n                '->'                            :   4,\n                '++'                            :   4,\n                '--'                            :   4,\n                '**'                            :   4,\n                                                        //   ! ~ \\ and unary + and -\n                '=~'                            :   4,\n                '!~'                            :   4,\n                '*'                             :   4,\n                '/'                             :   4,\n                '%'                             :   4,\n                'x'                             :   4,\n                '+'                             :   4,\n                '-'                             :   4,\n                '.'                             :   4,\n                '<<'                            :   4,\n                '>>'                            :   4,\n                                                        //   named unary operators\n                '<'                             :   4,\n                '>'                             :   4,\n                '<='                            :   4,\n                '>='                            :   4,\n                'lt'                            :   4,\n                'gt'                            :   4,\n                'le'                            :   4,\n                'ge'                            :   4,\n                '=='                            :   4,\n                '!='                            :   4,\n                '<=>'                           :   4,\n                'eq'                            :   4,\n                'ne'                            :   4,\n                'cmp'                           :   4,\n                '~~'                            :   4,\n                '&'                             :   4,\n                '|'                             :   4,\n                '^'                             :   4,\n                '&&'                            :   4,\n                '||'                            :   4,\n                '//'                            :   4,\n                '..'                            :   4,\n                '...'                           :   4,\n                '?'                             :   4,\n                ':'                             :   4,\n                '='                             :   4,\n                '+='                            :   4,\n                '-='                            :   4,\n                '*='                            :   4,  //   etc. ???\n                ','                             :   4,\n                '=>'                            :   4,\n                '::'                            :   4,\n                                                        //   list operators (rightward)\n                'not'                           :   4,\n                'and'                           :   4,\n                'or'                            :   4,\n                'xor'                           :   4,\n                                                //      PERL predefined variables (I know, what this is a paranoid idea, but may be needed for people, who learn PERL, and for me as well, ...and may be for you?;)\n                'BEGIN'                         :   [5,1],\n                'END'                           :   [5,1],\n                'PRINT'                         :   [5,1],\n                'PRINTF'                        :   [5,1],\n                'GETC'                          :   [5,1],\n                'READ'                          :   [5,1],\n                'READLINE'                      :   [5,1],\n                'DESTROY'                       :   [5,1],\n                'TIE'                           :   [5,1],\n                'TIEHANDLE'                     :   [5,1],\n                'UNTIE'                         :   [5,1],\n                'STDIN'                         :    5,\n                'STDIN_TOP'                     :    5,\n                'STDOUT'                        :    5,\n                'STDOUT_TOP'                    :    5,\n                'STDERR'                        :    5,\n                'STDERR_TOP'                    :    5,\n                '$ARG'                          :    5,\n                '$_'                            :    5,\n                '@ARG'                          :    5,\n                '@_'                            :    5,\n                '$LIST_SEPARATOR'               :    5,\n                '$\"'                            :    5,\n                '$PROCESS_ID'                   :    5,\n                '$PID'                          :    5,\n                '$$'                            :    5,\n                '$REAL_GROUP_ID'                :    5,\n                '$GID'                          :    5,\n                '$('                            :    5,\n                '$EFFECTIVE_GROUP_ID'           :    5,\n                '$EGID'                         :    5,\n                '$)'                            :    5,\n                '$PROGRAM_NAME'                 :    5,\n                '$0'                            :    5,\n                '$SUBSCRIPT_SEPARATOR'          :    5,\n                '$SUBSEP'                       :    5,\n                '$;'                            :    5,\n                '$REAL_USER_ID'                 :    5,\n                '$UID'                          :    5,\n                '$<'                            :    5,\n                '$EFFECTIVE_USER_ID'            :    5,\n                '$EUID'                         :    5,\n                '$>'                            :    5,\n                '$a'                            :    5,\n                '$b'                            :    5,\n                '$COMPILING'                    :    5,\n                '$^C'                           :    5,\n                '$DEBUGGING'                    :    5,\n                '$^D'                           :    5,\n                '${^ENCODING}'                  :    5,\n                '$ENV'                          :    5,\n                '%ENV'                          :    5,\n                '$SYSTEM_FD_MAX'                :    5,\n                '$^F'                           :    5,\n                '@F'                            :    5,\n                '${^GLOBAL_PHASE}'              :    5,\n                '$^H'                           :    5,\n                '%^H'                           :    5,\n                '@INC'                          :    5,\n                '%INC'                          :    5,\n                '$INPLACE_EDIT'                 :    5,\n                '$^I'                           :    5,\n                '$^M'                           :    5,\n                '$OSNAME'                       :    5,\n                '$^O'                           :    5,\n                '${^OPEN}'                      :    5,\n                '$PERLDB'                       :    5,\n                '$^P'                           :    5,\n                '$SIG'                          :    5,\n                '%SIG'                          :    5,\n                '$BASETIME'                     :    5,\n                '$^T'                           :    5,\n                '${^TAINT}'                     :    5,\n                '${^UNICODE}'                   :    5,\n                '${^UTF8CACHE}'                 :    5,\n                '${^UTF8LOCALE}'                :    5,\n                '$PERL_VERSION'                 :    5,\n                '$^V'                           :    5,\n                '${^WIN32_SLOPPY_STAT}'         :    5,\n                '$EXECUTABLE_NAME'              :    5,\n                '$^X'                           :    5,\n                '$1'                            :    5, // - regexp $1, $2...\n                '$MATCH'                        :    5,\n                '$&'                            :    5,\n                '${^MATCH}'                     :    5,\n                '$PREMATCH'                     :    5,\n                '$`'                            :    5,\n                '${^PREMATCH}'                  :    5,\n                '$POSTMATCH'                    :    5,\n                \"$'\"                            :    5,\n                '${^POSTMATCH}'                 :    5,\n                '$LAST_PAREN_MATCH'             :    5,\n                '$+'                            :    5,\n                '$LAST_SUBMATCH_RESULT'         :    5,\n                '$^N'                           :    5,\n                '@LAST_MATCH_END'               :    5,\n                '@+'                            :    5,\n                '%LAST_PAREN_MATCH'             :    5,\n                '%+'                            :    5,\n                '@LAST_MATCH_START'             :    5,\n                '@-'                            :    5,\n                '%LAST_MATCH_START'             :    5,\n                '%-'                            :    5,\n                '$LAST_REGEXP_CODE_RESULT'      :    5,\n                '$^R'                           :    5,\n                '${^RE_DEBUG_FLAGS}'            :    5,\n                '${^RE_TRIE_MAXBUF}'            :    5,\n                '$ARGV'                         :    5,\n                '@ARGV'                         :    5,\n                'ARGV'                          :    5,\n                'ARGVOUT'                       :    5,\n                '$OUTPUT_FIELD_SEPARATOR'       :    5,\n                '$OFS'                          :    5,\n                '$,'                            :    5,\n                '$INPUT_LINE_NUMBER'            :    5,\n                '$NR'                           :    5,\n                '$.'                            :    5,\n                '$INPUT_RECORD_SEPARATOR'       :    5,\n                '$RS'                           :    5,\n                '$/'                            :    5,\n                '$OUTPUT_RECORD_SEPARATOR'      :    5,\n                '$ORS'                          :    5,\n                '$\\\\'                           :    5,\n                '$OUTPUT_AUTOFLUSH'             :    5,\n                '$|'                            :    5,\n                '$ACCUMULATOR'                  :    5,\n                '$^A'                           :    5,\n                '$FORMAT_FORMFEED'              :    5,\n                '$^L'                           :    5,\n                '$FORMAT_PAGE_NUMBER'           :    5,\n                '$%'                            :    5,\n                '$FORMAT_LINES_LEFT'            :    5,\n                '$-'                            :    5,\n                '$FORMAT_LINE_BREAK_CHARACTERS' :    5,\n                '$:'                            :    5,\n                '$FORMAT_LINES_PER_PAGE'        :    5,\n                '$='                            :    5,\n                '$FORMAT_TOP_NAME'              :    5,\n                '$^'                            :    5,\n                '$FORMAT_NAME'                  :    5,\n                '$~'                            :    5,\n                '${^CHILD_ERROR_NATIVE}'        :    5,\n                '$EXTENDED_OS_ERROR'            :    5,\n                '$^E'                           :    5,\n                '$EXCEPTIONS_BEING_CAUGHT'      :    5,\n                '$^S'                           :    5,\n                '$WARNING'                      :    5,\n                '$^W'                           :    5,\n                '${^WARNING_BITS}'              :    5,\n                '$OS_ERROR'                     :    5,\n                '$ERRNO'                        :    5,\n                '$!'                            :    5,\n                '%OS_ERROR'                     :    5,\n                '%ERRNO'                        :    5,\n                '%!'                            :    5,\n                '$CHILD_ERROR'                  :    5,\n                '$?'                            :    5,\n                '$EVAL_ERROR'                   :    5,\n                '$@'                            :    5,\n                '$OFMT'                         :    5,\n                '$#'                            :    5,\n                '$*'                            :    5,\n                '$ARRAY_BASE'                   :    5,\n                '$['                            :    5,\n                '$OLD_PERL_VERSION'             :    5,\n                '$]'                            :    5,\n                                                //      PERL blocks\n                'if'                            :[1,1],\n                elsif                           :[1,1],\n                'else'                          :[1,1],\n                'while'                         :[1,1],\n                unless                          :[1,1],\n                'for'                           :[1,1],\n                foreach                         :[1,1],\n                                                //      PERL functions\n                'abs'                           :1,     // - absolute value function\n                accept                          :1,     // - accept an incoming socket connect\n                alarm                           :1,     // - schedule a SIGALRM\n                'atan2'                         :1,     // - arctangent of Y/X in the range -PI to PI\n                bind                            :1,     // - binds an address to a socket\n                binmode                         :1,     // - prepare binary files for I/O\n                bless                           :1,     // - create an object\n                bootstrap                       :1,     //\n                'break'                         :1,     // - break out of a \"given\" block\n                caller                          :1,     // - get context of the current subroutine call\n                chdir                           :1,     // - change your current working directory\n                chmod                           :1,     // - changes the permissions on a list of files\n                chomp                           :1,     // - remove a trailing record separator from a string\n                chop                            :1,     // - remove the last character from a string\n                chown                           :1,     // - change the owership on a list of files\n                chr                             :1,     // - get character this number represents\n                chroot                          :1,     // - make directory new root for path lookups\n                close                           :1,     // - close file (or pipe or socket) handle\n                closedir                        :1,     // - close directory handle\n                connect                         :1,     // - connect to a remote socket\n                'continue'                      :[1,1], // - optional trailing block in a while or foreach\n                'cos'                           :1,     // - cosine function\n                crypt                           :1,     // - one-way passwd-style encryption\n                dbmclose                        :1,     // - breaks binding on a tied dbm file\n                dbmopen                         :1,     // - create binding on a tied dbm file\n                'default'                       :1,     //\n                defined                         :1,     // - test whether a value, variable, or function is defined\n                'delete'                        :1,     // - deletes a value from a hash\n                die                             :1,     // - raise an exception or bail out\n                'do'                            :1,     // - turn a BLOCK into a TERM\n                dump                            :1,     // - create an immediate core dump\n                each                            :1,     // - retrieve the next key/value pair from a hash\n                endgrent                        :1,     // - be done using group file\n                endhostent                      :1,     // - be done using hosts file\n                endnetent                       :1,     // - be done using networks file\n                endprotoent                     :1,     // - be done using protocols file\n                endpwent                        :1,     // - be done using passwd file\n                endservent                      :1,     // - be done using services file\n                eof                             :1,     // - test a filehandle for its end\n                'eval'                          :1,     // - catch exceptions or compile and run code\n                'exec'                          :1,     // - abandon this program to run another\n                exists                          :1,     // - test whether a hash key is present\n                exit                            :1,     // - terminate this program\n                'exp'                           :1,     // - raise I to a power\n                fcntl                           :1,     // - file control system call\n                fileno                          :1,     // - return file descriptor from filehandle\n                flock                           :1,     // - lock an entire file with an advisory lock\n                fork                            :1,     // - create a new process just like this one\n                format                          :1,     // - declare a picture format with use by the write() function\n                formline                        :1,     // - internal function used for formats\n                getc                            :1,     // - get the next character from the filehandle\n                getgrent                        :1,     // - get next group record\n                getgrgid                        :1,     // - get group record given group user ID\n                getgrnam                        :1,     // - get group record given group name\n                gethostbyaddr                   :1,     // - get host record given its address\n                gethostbyname                   :1,     // - get host record given name\n                gethostent                      :1,     // - get next hosts record\n                getlogin                        :1,     // - return who logged in at this tty\n                getnetbyaddr                    :1,     // - get network record given its address\n                getnetbyname                    :1,     // - get networks record given name\n                getnetent                       :1,     // - get next networks record\n                getpeername                     :1,     // - find the other end of a socket connection\n                getpgrp                         :1,     // - get process group\n                getppid                         :1,     // - get parent process ID\n                getpriority                     :1,     // - get current nice value\n                getprotobyname                  :1,     // - get protocol record given name\n                getprotobynumber                :1,     // - get protocol record numeric protocol\n                getprotoent                     :1,     // - get next protocols record\n                getpwent                        :1,     // - get next passwd record\n                getpwnam                        :1,     // - get passwd record given user login name\n                getpwuid                        :1,     // - get passwd record given user ID\n                getservbyname                   :1,     // - get services record given its name\n                getservbyport                   :1,     // - get services record given numeric port\n                getservent                      :1,     // - get next services record\n                getsockname                     :1,     // - retrieve the sockaddr for a given socket\n                getsockopt                      :1,     // - get socket options on a given socket\n                given                           :1,     //\n                glob                            :1,     // - expand filenames using wildcards\n                gmtime                          :1,     // - convert UNIX time into record or string using Greenwich time\n                'goto'                          :1,     // - create spaghetti code\n                grep                            :1,     // - locate elements in a list test true against a given criterion\n                hex                             :1,     // - convert a string to a hexadecimal number\n                'import'                        :1,     // - patch a module's namespace into your own\n                index                           :1,     // - find a substring within a string\n                'int'                           :1,     // - get the integer portion of a number\n                ioctl                           :1,     // - system-dependent device control system call\n                'join'                          :1,     // - join a list into a string using a separator\n                keys                            :1,     // - retrieve list of indices from a hash\n                kill                            :1,     // - send a signal to a process or process group\n                last                            :1,     // - exit a block prematurely\n                lc                              :1,     // - return lower-case version of a string\n                lcfirst                         :1,     // - return a string with just the next letter in lower case\n                length                          :1,     // - return the number of bytes in a string\n                'link'                          :1,     // - create a hard link in the filesytem\n                listen                          :1,     // - register your socket as a server\n                local                           : 2,    // - create a temporary value for a global variable (dynamic scoping)\n                localtime                       :1,     // - convert UNIX time into record or string using local time\n                lock                            :1,     // - get a thread lock on a variable, subroutine, or method\n                'log'                           :1,     // - retrieve the natural logarithm for a number\n                lstat                           :1,     // - stat a symbolic link\n                m                               :null,  // - match a string with a regular expression pattern\n                map                             :1,     // - apply a change to a list to get back a new list with the changes\n                mkdir                           :1,     // - create a directory\n                msgctl                          :1,     // - SysV IPC message control operations\n                msgget                          :1,     // - get SysV IPC message queue\n                msgrcv                          :1,     // - receive a SysV IPC message from a message queue\n                msgsnd                          :1,     // - send a SysV IPC message to a message queue\n                my                              : 2,    // - declare and assign a local variable (lexical scoping)\n                'new'                           :1,     //\n                next                            :1,     // - iterate a block prematurely\n                no                              :1,     // - unimport some module symbols or semantics at compile time\n                oct                             :1,     // - convert a string to an octal number\n                open                            :1,     // - open a file, pipe, or descriptor\n                opendir                         :1,     // - open a directory\n                ord                             :1,     // - find a character's numeric representation\n                our                             : 2,    // - declare and assign a package variable (lexical scoping)\n                pack                            :1,     // - convert a list into a binary representation\n                'package'                       :1,     // - declare a separate global namespace\n                pipe                            :1,     // - open a pair of connected filehandles\n                pop                             :1,     // - remove the last element from an array and return it\n                pos                             :1,     // - find or set the offset for the last/next m//g search\n                print                           :1,     // - output a list to a filehandle\n                printf                          :1,     // - output a formatted list to a filehandle\n                prototype                       :1,     // - get the prototype (if any) of a subroutine\n                push                            :1,     // - append one or more elements to an array\n                q                               :null,  // - singly quote a string\n                qq                              :null,  // - doubly quote a string\n                qr                              :null,  // - Compile pattern\n                quotemeta                       :null,  // - quote regular expression magic characters\n                qw                              :null,  // - quote a list of words\n                qx                              :null,  // - backquote quote a string\n                rand                            :1,     // - retrieve the next pseudorandom number\n                read                            :1,     // - fixed-length buffered input from a filehandle\n                readdir                         :1,     // - get a directory from a directory handle\n                readline                        :1,     // - fetch a record from a file\n                readlink                        :1,     // - determine where a symbolic link is pointing\n                readpipe                        :1,     // - execute a system command and collect standard output\n                recv                            :1,     // - receive a message over a Socket\n                redo                            :1,     // - start this loop iteration over again\n                ref                             :1,     // - find out the type of thing being referenced\n                rename                          :1,     // - change a filename\n                require                         :1,     // - load in external functions from a library at runtime\n                reset                           :1,     // - clear all variables of a given name\n                'return'                        :1,     // - get out of a function early\n                reverse                         :1,     // - flip a string or a list\n                rewinddir                       :1,     // - reset directory handle\n                rindex                          :1,     // - right-to-left substring search\n                rmdir                           :1,     // - remove a directory\n                s                               :null,  // - replace a pattern with a string\n                say                             :1,     // - print with newline\n                scalar                          :1,     // - force a scalar context\n                seek                            :1,     // - reposition file pointer for random-access I/O\n                seekdir                         :1,     // - reposition directory pointer\n                select                          :1,     // - reset default output or do I/O multiplexing\n                semctl                          :1,     // - SysV semaphore control operations\n                semget                          :1,     // - get set of SysV semaphores\n                semop                           :1,     // - SysV semaphore operations\n                send                            :1,     // - send a message over a socket\n                setgrent                        :1,     // - prepare group file for use\n                sethostent                      :1,     // - prepare hosts file for use\n                setnetent                       :1,     // - prepare networks file for use\n                setpgrp                         :1,     // - set the process group of a process\n                setpriority                     :1,     // - set a process's nice value\n                setprotoent                     :1,     // - prepare protocols file for use\n                setpwent                        :1,     // - prepare passwd file for use\n                setservent                      :1,     // - prepare services file for use\n                setsockopt                      :1,     // - set some socket options\n                shift                           :1,     // - remove the first element of an array, and return it\n                shmctl                          :1,     // - SysV shared memory operations\n                shmget                          :1,     // - get SysV shared memory segment identifier\n                shmread                         :1,     // - read SysV shared memory\n                shmwrite                        :1,     // - write SysV shared memory\n                shutdown                        :1,     // - close down just half of a socket connection\n                'sin'                           :1,     // - return the sine of a number\n                sleep                           :1,     // - block for some number of seconds\n                socket                          :1,     // - create a socket\n                socketpair                      :1,     // - create a pair of sockets\n                'sort'                          :1,     // - sort a list of values\n                splice                          :1,     // - add or remove elements anywhere in an array\n                'split'                         :1,     // - split up a string using a regexp delimiter\n                sprintf                         :1,     // - formatted print into a string\n                'sqrt'                          :1,     // - square root function\n                srand                           :1,     // - seed the random number generator\n                stat                            :1,     // - get a file's status information\n                state                           :1,     // - declare and assign a state variable (persistent lexical scoping)\n                study                           :1,     // - optimize input data for repeated searches\n                'sub'                           :1,     // - declare a subroutine, possibly anonymously\n                'substr'                        :1,     // - get or alter a portion of a stirng\n                symlink                         :1,     // - create a symbolic link to a file\n                syscall                         :1,     // - execute an arbitrary system call\n                sysopen                         :1,     // - open a file, pipe, or descriptor\n                sysread                         :1,     // - fixed-length unbuffered input from a filehandle\n                sysseek                         :1,     // - position I/O pointer on handle used with sysread and syswrite\n                system                          :1,     // - run a separate program\n                syswrite                        :1,     // - fixed-length unbuffered output to a filehandle\n                tell                            :1,     // - get current seekpointer on a filehandle\n                telldir                         :1,     // - get current seekpointer on a directory handle\n                tie                             :1,     // - bind a variable to an object class\n                tied                            :1,     // - get a reference to the object underlying a tied variable\n                time                            :1,     // - return number of seconds since 1970\n                times                           :1,     // - return elapsed time for self and child processes\n                tr                              :null,  // - transliterate a string\n                truncate                        :1,     // - shorten a file\n                uc                              :1,     // - return upper-case version of a string\n                ucfirst                         :1,     // - return a string with just the next letter in upper case\n                umask                           :1,     // - set file creation mode mask\n                undef                           :1,     // - remove a variable or function definition\n                unlink                          :1,     // - remove one link to a file\n                unpack                          :1,     // - convert binary structure into normal perl variables\n                unshift                         :1,     // - prepend more elements to the beginning of a list\n                untie                           :1,     // - break a tie binding to a variable\n                use                             :1,     // - load in a module at compile time\n                utime                           :1,     // - set a file's last access and modify times\n                values                          :1,     // - return a list of the values in a hash\n                vec                             :1,     // - test or set particular bits in a string\n                wait                            :1,     // - wait for any child process to die\n                waitpid                         :1,     // - wait for a particular child process to die\n                wantarray                       :1,     // - get void vs scalar vs list context of current subroutine call\n                warn                            :1,     // - print debugging info\n                when                            :1,     //\n                write                           :1,     // - print a picture record\n                y                               :null}; // - transliterate a string\n\n        var RXstyle=\"string-2\";\n        var RXmodifiers=/[goseximacplud]/;              // NOTE: \"m\", \"s\", \"y\" and \"tr\" need to correct real modifiers for each regexp type\n\n        function tokenChain(stream,state,chain,style,tail){     // NOTE: chain.length > 2 is not working now (it's for s[...][...]geos;)\n                state.chain=null;                               //                                                          12   3tail\n                state.style=null;\n                state.tail=null;\n                state.tokenize=function(stream,state){\n                        var e=false,c,i=0;\n                        while(c=stream.next()){\n                                if(c===chain[i]&&!e){\n                                        if(chain[++i]!==undefined){\n                                                state.chain=chain[i];\n                                                state.style=style;\n                                                state.tail=tail;}\n                                        else if(tail)\n                                                stream.eatWhile(tail);\n                                        state.tokenize=tokenPerl;\n                                        return style;}\n                                e=!e&&c==\"\\\\\";}\n                        return style;};\n                return state.tokenize(stream,state);}\n\n        function tokenSOMETHING(stream,state,string){\n                state.tokenize=function(stream,state){\n                        if(stream.string==string)\n                                state.tokenize=tokenPerl;\n                        stream.skipToEnd();\n                        return \"string\";};\n                return state.tokenize(stream,state);}\n\n        function tokenPerl(stream,state){\n                if(stream.eatSpace())\n                        return null;\n                if(state.chain)\n                        return tokenChain(stream,state,state.chain,state.style,state.tail);\n                if(stream.match(/^\\-?[\\d\\.]/,false))\n                        if(stream.match(/^(\\-?(\\d*\\.\\d+(e[+-]?\\d+)?|\\d+\\.\\d*)|0x[\\da-fA-F]+|0b[01]+|\\d+(e[+-]?\\d+)?)/))\n                                return 'number';\n                if(stream.match(/^<<(?=\\w)/)){                  // NOTE: <<SOMETHING\\n...\\nSOMETHING\\n\n                        stream.eatWhile(/\\w/);\n                        return tokenSOMETHING(stream,state,stream.current().substr(2));}\n                if(stream.sol()&&stream.match(/^\\=item(?!\\w)/)){// NOTE: \\n=item...\\n=cut\\n\n                        return tokenSOMETHING(stream,state,'=cut');}\n                var ch=stream.next();\n                if(ch=='\"'||ch==\"'\"){                           // NOTE: ' or \" or <<'SOMETHING'\\n...\\nSOMETHING\\n or <<\"SOMETHING\"\\n...\\nSOMETHING\\n\n                        if(prefix(stream, 3)==\"<<\"+ch){\n                                var p=stream.pos;\n                                stream.eatWhile(/\\w/);\n                                var n=stream.current().substr(1);\n                                if(n&&stream.eat(ch))\n                                        return tokenSOMETHING(stream,state,n);\n                                stream.pos=p;}\n                        return tokenChain(stream,state,[ch],\"string\");}\n                if(ch==\"q\"){\n                        var c=look(stream, -2);\n                        if(!(c&&/\\w/.test(c))){\n                                c=look(stream, 0);\n                                if(c==\"x\"){\n                                        c=look(stream, 1);\n                                        if(c==\"(\"){\n                                                eatSuffix(stream, 2);\n                                                return tokenChain(stream,state,[\")\"],RXstyle,RXmodifiers);}\n                                        if(c==\"[\"){\n                                                eatSuffix(stream, 2);\n                                                return tokenChain(stream,state,[\"]\"],RXstyle,RXmodifiers);}\n                                        if(c==\"{\"){\n                                                eatSuffix(stream, 2);\n                                                return tokenChain(stream,state,[\"}\"],RXstyle,RXmodifiers);}\n                                        if(c==\"<\"){\n                                                eatSuffix(stream, 2);\n                                                return tokenChain(stream,state,[\">\"],RXstyle,RXmodifiers);}\n                                        if(/[\\^'\"!~\\/]/.test(c)){\n                                                eatSuffix(stream, 1);\n                                                return tokenChain(stream,state,[stream.eat(c)],RXstyle,RXmodifiers);}}\n                                else if(c==\"q\"){\n                                        c=look(stream, 1);\n                                        if(c==\"(\"){\n                                                eatSuffix(stream, 2);\n                                                return tokenChain(stream,state,[\")\"],\"string\");}\n                                        if(c==\"[\"){\n                                                eatSuffix(stream, 2);\n                                                return tokenChain(stream,state,[\"]\"],\"string\");}\n                                        if(c==\"{\"){\n                                                eatSuffix(stream, 2);\n                                                return tokenChain(stream,state,[\"}\"],\"string\");}\n                                        if(c==\"<\"){\n                                                eatSuffix(stream, 2);\n                                                return tokenChain(stream,state,[\">\"],\"string\");}\n                                        if(/[\\^'\"!~\\/]/.test(c)){\n                                                eatSuffix(stream, 1);\n                                                return tokenChain(stream,state,[stream.eat(c)],\"string\");}}\n                                else if(c==\"w\"){\n                                        c=look(stream, 1);\n                                        if(c==\"(\"){\n                                                eatSuffix(stream, 2);\n                                                return tokenChain(stream,state,[\")\"],\"bracket\");}\n                                        if(c==\"[\"){\n                                                eatSuffix(stream, 2);\n                                                return tokenChain(stream,state,[\"]\"],\"bracket\");}\n                                        if(c==\"{\"){\n                                                eatSuffix(stream, 2);\n                                                return tokenChain(stream,state,[\"}\"],\"bracket\");}\n                                        if(c==\"<\"){\n                                                eatSuffix(stream, 2);\n                                                return tokenChain(stream,state,[\">\"],\"bracket\");}\n                                        if(/[\\^'\"!~\\/]/.test(c)){\n                                                eatSuffix(stream, 1);\n                                                return tokenChain(stream,state,[stream.eat(c)],\"bracket\");}}\n                                else if(c==\"r\"){\n                                        c=look(stream, 1);\n                                        if(c==\"(\"){\n                                                eatSuffix(stream, 2);\n                                                return tokenChain(stream,state,[\")\"],RXstyle,RXmodifiers);}\n                                        if(c==\"[\"){\n                                                eatSuffix(stream, 2);\n                                                return tokenChain(stream,state,[\"]\"],RXstyle,RXmodifiers);}\n                                        if(c==\"{\"){\n                                                eatSuffix(stream, 2);\n                                                return tokenChain(stream,state,[\"}\"],RXstyle,RXmodifiers);}\n                                        if(c==\"<\"){\n                                                eatSuffix(stream, 2);\n                                                return tokenChain(stream,state,[\">\"],RXstyle,RXmodifiers);}\n                                        if(/[\\^'\"!~\\/]/.test(c)){\n                                                eatSuffix(stream, 1);\n                                                return tokenChain(stream,state,[stream.eat(c)],RXstyle,RXmodifiers);}}\n                                else if(/[\\^'\"!~\\/(\\[{<]/.test(c)){\n                                        if(c==\"(\"){\n                                                eatSuffix(stream, 1);\n                                                return tokenChain(stream,state,[\")\"],\"string\");}\n                                        if(c==\"[\"){\n                                                eatSuffix(stream, 1);\n                                                return tokenChain(stream,state,[\"]\"],\"string\");}\n                                        if(c==\"{\"){\n                                                eatSuffix(stream, 1);\n                                                return tokenChain(stream,state,[\"}\"],\"string\");}\n                                        if(c==\"<\"){\n                                                eatSuffix(stream, 1);\n                                                return tokenChain(stream,state,[\">\"],\"string\");}\n                                        if(/[\\^'\"!~\\/]/.test(c)){\n                                                return tokenChain(stream,state,[stream.eat(c)],\"string\");}}}}\n                if(ch==\"m\"){\n                        var c=look(stream, -2);\n                        if(!(c&&/\\w/.test(c))){\n                                c=stream.eat(/[(\\[{<\\^'\"!~\\/]/);\n                                if(c){\n                                        if(/[\\^'\"!~\\/]/.test(c)){\n                                                return tokenChain(stream,state,[c],RXstyle,RXmodifiers);}\n                                        if(c==\"(\"){\n                                                return tokenChain(stream,state,[\")\"],RXstyle,RXmodifiers);}\n                                        if(c==\"[\"){\n                                                return tokenChain(stream,state,[\"]\"],RXstyle,RXmodifiers);}\n                                        if(c==\"{\"){\n                                                return tokenChain(stream,state,[\"}\"],RXstyle,RXmodifiers);}\n                                        if(c==\"<\"){\n                                                return tokenChain(stream,state,[\">\"],RXstyle,RXmodifiers);}}}}\n                if(ch==\"s\"){\n                        var c=/[\\/>\\]})\\w]/.test(look(stream, -2));\n                        if(!c){\n                                c=stream.eat(/[(\\[{<\\^'\"!~\\/]/);\n                                if(c){\n                                        if(c==\"[\")\n                                                return tokenChain(stream,state,[\"]\",\"]\"],RXstyle,RXmodifiers);\n                                        if(c==\"{\")\n                                                return tokenChain(stream,state,[\"}\",\"}\"],RXstyle,RXmodifiers);\n                                        if(c==\"<\")\n                                                return tokenChain(stream,state,[\">\",\">\"],RXstyle,RXmodifiers);\n                                        if(c==\"(\")\n                                                return tokenChain(stream,state,[\")\",\")\"],RXstyle,RXmodifiers);\n                                        return tokenChain(stream,state,[c,c],RXstyle,RXmodifiers);}}}\n                if(ch==\"y\"){\n                        var c=/[\\/>\\]})\\w]/.test(look(stream, -2));\n                        if(!c){\n                                c=stream.eat(/[(\\[{<\\^'\"!~\\/]/);\n                                if(c){\n                                        if(c==\"[\")\n                                                return tokenChain(stream,state,[\"]\",\"]\"],RXstyle,RXmodifiers);\n                                        if(c==\"{\")\n                                                return tokenChain(stream,state,[\"}\",\"}\"],RXstyle,RXmodifiers);\n                                        if(c==\"<\")\n                                                return tokenChain(stream,state,[\">\",\">\"],RXstyle,RXmodifiers);\n                                        if(c==\"(\")\n                                                return tokenChain(stream,state,[\")\",\")\"],RXstyle,RXmodifiers);\n                                        return tokenChain(stream,state,[c,c],RXstyle,RXmodifiers);}}}\n                if(ch==\"t\"){\n                        var c=/[\\/>\\]})\\w]/.test(look(stream, -2));\n                        if(!c){\n                                c=stream.eat(\"r\");if(c){\n                                c=stream.eat(/[(\\[{<\\^'\"!~\\/]/);\n                                if(c){\n                                        if(c==\"[\")\n                                                return tokenChain(stream,state,[\"]\",\"]\"],RXstyle,RXmodifiers);\n                                        if(c==\"{\")\n                                                return tokenChain(stream,state,[\"}\",\"}\"],RXstyle,RXmodifiers);\n                                        if(c==\"<\")\n                                                return tokenChain(stream,state,[\">\",\">\"],RXstyle,RXmodifiers);\n                                        if(c==\"(\")\n                                                return tokenChain(stream,state,[\")\",\")\"],RXstyle,RXmodifiers);\n                                        return tokenChain(stream,state,[c,c],RXstyle,RXmodifiers);}}}}\n                if(ch==\"`\"){\n                        return tokenChain(stream,state,[ch],\"variable-2\");}\n                if(ch==\"/\"){\n                        if(!/~\\s*$/.test(prefix(stream)))\n                                return \"operator\";\n                        else\n                                return tokenChain(stream,state,[ch],RXstyle,RXmodifiers);}\n                if(ch==\"$\"){\n                        var p=stream.pos;\n                        if(stream.eatWhile(/\\d/)||stream.eat(\"{\")&&stream.eatWhile(/\\d/)&&stream.eat(\"}\"))\n                                return \"variable-2\";\n                        else\n                                stream.pos=p;}\n                if(/[$@%]/.test(ch)){\n                        var p=stream.pos;\n                        if(stream.eat(\"^\")&&stream.eat(/[A-Z]/)||!/[@$%&]/.test(look(stream, -2))&&stream.eat(/[=|\\\\\\-#?@;:&`~\\^!\\[\\]*'\"$+.,\\/<>()]/)){\n                                var c=stream.current();\n                                if(PERL[c])\n                                        return \"variable-2\";}\n                        stream.pos=p;}\n                if(/[$@%&]/.test(ch)){\n                        if(stream.eatWhile(/[\\w$\\[\\]]/)||stream.eat(\"{\")&&stream.eatWhile(/[\\w$\\[\\]]/)&&stream.eat(\"}\")){\n                                var c=stream.current();\n                                if(PERL[c])\n                                        return \"variable-2\";\n                                else\n                                        return \"variable\";}}\n                if(ch==\"#\"){\n                        if(look(stream, -2)!=\"$\"){\n                                stream.skipToEnd();\n                                return \"comment\";}}\n                if(/[:+\\-\\^*$&%@=<>!?|\\/~\\.]/.test(ch)){\n                        var p=stream.pos;\n                        stream.eatWhile(/[:+\\-\\^*$&%@=<>!?|\\/~\\.]/);\n                        if(PERL[stream.current()])\n                                return \"operator\";\n                        else\n                                stream.pos=p;}\n                if(ch==\"_\"){\n                        if(stream.pos==1){\n                                if(suffix(stream, 6)==\"_END__\"){\n                                        return tokenChain(stream,state,['\\0'],\"comment\");}\n                                else if(suffix(stream, 7)==\"_DATA__\"){\n                                        return tokenChain(stream,state,['\\0'],\"variable-2\");}\n                                else if(suffix(stream, 7)==\"_C__\"){\n                                        return tokenChain(stream,state,['\\0'],\"string\");}}}\n                if(/\\w/.test(ch)){\n                        var p=stream.pos;\n                        if(look(stream, -2)==\"{\"&&(look(stream, 0)==\"}\"||stream.eatWhile(/\\w/)&&look(stream, 0)==\"}\"))\n                                return \"string\";\n                        else\n                                stream.pos=p;}\n                if(/[A-Z]/.test(ch)){\n                        var l=look(stream, -2);\n                        var p=stream.pos;\n                        stream.eatWhile(/[A-Z_]/);\n                        if(/[\\da-z]/.test(look(stream, 0))){\n                                stream.pos=p;}\n                        else{\n                                var c=PERL[stream.current()];\n                                if(!c)\n                                        return \"meta\";\n                                if(c[1])\n                                        c=c[0];\n                                if(l!=\":\"){\n                                        if(c==1)\n                                                return \"keyword\";\n                                        else if(c==2)\n                                                return \"def\";\n                                        else if(c==3)\n                                                return \"atom\";\n                                        else if(c==4)\n                                                return \"operator\";\n                                        else if(c==5)\n                                                return \"variable-2\";\n                                        else\n                                                return \"meta\";}\n                                else\n                                        return \"meta\";}}\n                if(/[a-zA-Z_]/.test(ch)){\n                        var l=look(stream, -2);\n                        stream.eatWhile(/\\w/);\n                        var c=PERL[stream.current()];\n                        if(!c)\n                                return \"meta\";\n                        if(c[1])\n                                c=c[0];\n                        if(l!=\":\"){\n                                if(c==1)\n                                        return \"keyword\";\n                                else if(c==2)\n                                        return \"def\";\n                                else if(c==3)\n                                        return \"atom\";\n                                else if(c==4)\n                                        return \"operator\";\n                                else if(c==5)\n                                        return \"variable-2\";\n                                else\n                                        return \"meta\";}\n                        else\n                                return \"meta\";}\n                return null;}\n\n        return {\n            startState: function() {\n                return {\n                    tokenize: tokenPerl,\n                    chain: null,\n                    style: null,\n                    tail: null\n                };\n            },\n            token: function(stream, state) {\n                return (state.tokenize || tokenPerl)(stream, state);\n            },\n            lineComment: '#'\n        };\n});\n\nCodeMirror.registerHelper(\"wordChars\", \"perl\", /[\\w$]/);\n\nCodeMirror.defineMIME(\"text/x-perl\", \"perl\");\n\n// it's like \"peek\", but need for look-ahead or look-behind if index < 0\nfunction look(stream, c){\n  return stream.string.charAt(stream.pos+(c||0));\n}\n\n// return a part of prefix of current stream from current position\nfunction prefix(stream, c){\n  if(c){\n    var x=stream.pos-c;\n    return stream.string.substr((x>=0?x:0),c);}\n  else{\n    return stream.string.substr(0,stream.pos-1);\n  }\n}\n\n// return a part of suffix of current stream from current position\nfunction suffix(stream, c){\n  var y=stream.string.length;\n  var x=y-stream.pos+1;\n  return stream.string.substr(stream.pos,(c&&c<y?c:x));\n}\n\n// eating and vomiting a part of stream from current position\nfunction eatSuffix(stream, c){\n  var x=stream.pos+c;\n  var y;\n  if(x<=0)\n    stream.pos=0;\n  else if(x>=(y=stream.string.length-1))\n    stream.pos=y;\n  else\n    stream.pos=x;\n}\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/php/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: PHP mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"../../addon/edit/matchbrackets.js\"></script>\n<script src=\"../htmlmixed/htmlmixed.js\"></script>\n<script src=\"../xml/xml.js\"></script>\n<script src=\"../javascript/javascript.js\"></script>\n<script src=\"../css/css.js\"></script>\n<script src=\"../clike/clike.js\"></script>\n<script src=\"php.js\"></script>\n<style type=\"text/css\">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">PHP</a>\n  </ul>\n</div>\n\n<article>\n<h2>PHP mode</h2>\n<form><textarea id=\"code\" name=\"code\">\n<?php\n$a = array('a' => 1, 'b' => 2, 3 => 'c');\n\necho \"$a[a] ${a[3] /* } comment */} {$a[b]} \\$a[a]\";\n\nfunction hello($who) {\n\treturn \"Hello $who!\";\n}\n?>\n<p>The program says <?= hello(\"World\") ?>.</p>\n<script>\n\talert(\"And here is some JS code\"); // also colored\n</script>\n</textarea></form>\n\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        lineNumbers: true,\n        matchBrackets: true,\n        mode: \"application/x-httpd-php\",\n        indentUnit: 4,\n        indentWithTabs: true\n      });\n    </script>\n\n    <p>Simple HTML/PHP mode based on\n    the <a href=\"../clike/\">C-like</a> mode. Depends on XML,\n    JavaScript, CSS, HTMLMixed, and C-like modes.</p>\n\n    <p><strong>MIME types defined:</strong> <code>application/x-httpd-php</code> (HTML with PHP code), <code>text/x-php</code> (plain, non-wrapped PHP code).</p>\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/php/php.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"), require(\"../htmlmixed/htmlmixed\"), require(\"../clike/clike\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\", \"../htmlmixed/htmlmixed\", \"../clike/clike\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n\n  function keywords(str) {\n    var obj = {}, words = str.split(\" \");\n    for (var i = 0; i < words.length; ++i) obj[words[i]] = true;\n    return obj;\n  }\n\n  // Helper for stringWithEscapes\n  function matchSequence(list, end) {\n    if (list.length == 0) return stringWithEscapes(end);\n    return function (stream, state) {\n      var patterns = list[0];\n      for (var i = 0; i < patterns.length; i++) if (stream.match(patterns[i][0])) {\n        state.tokenize = matchSequence(list.slice(1), end);\n        return patterns[i][1];\n      }\n      state.tokenize = stringWithEscapes(end);\n      return \"string\";\n    };\n  }\n  function stringWithEscapes(closing) {\n    return function(stream, state) { return stringWithEscapes_(stream, state, closing); };\n  }\n  function stringWithEscapes_(stream, state, closing) {\n    // \"Complex\" syntax\n    if (stream.match(\"${\", false) || stream.match(\"{$\", false)) {\n      state.tokenize = null;\n      return \"string\";\n    }\n\n    // Simple syntax\n    if (stream.match(/^\\$[a-zA-Z_][a-zA-Z0-9_]*/)) {\n      // After the variable name there may appear array or object operator.\n      if (stream.match(\"[\", false)) {\n        // Match array operator\n        state.tokenize = matchSequence([\n          [[\"[\", null]],\n          [[/\\d[\\w\\.]*/, \"number\"],\n           [/\\$[a-zA-Z_][a-zA-Z0-9_]*/, \"variable-2\"],\n           [/[\\w\\$]+/, \"variable\"]],\n          [[\"]\", null]]\n        ], closing);\n      }\n      if (stream.match(/\\-\\>\\w/, false)) {\n        // Match object operator\n        state.tokenize = matchSequence([\n          [[\"->\", null]],\n          [[/[\\w]+/, \"variable\"]]\n        ], closing);\n      }\n      return \"variable-2\";\n    }\n\n    var escaped = false;\n    // Normal string\n    while (!stream.eol() &&\n           (escaped || (!stream.match(\"{$\", false) &&\n                        !stream.match(/^(\\$[a-zA-Z_][a-zA-Z0-9_]*|\\$\\{)/, false)))) {\n      if (!escaped && stream.match(closing)) {\n        state.tokenize = null;\n        state.tokStack.pop(); state.tokStack.pop();\n        break;\n      }\n      escaped = stream.next() == \"\\\\\" && !escaped;\n    }\n    return \"string\";\n  }\n\n  var phpKeywords = \"abstract and array as break case catch class clone const continue declare default \" +\n    \"do else elseif enddeclare endfor endforeach endif endswitch endwhile extends final \" +\n    \"for foreach function global goto if implements interface instanceof namespace \" +\n    \"new or private protected public static switch throw trait try use var while xor \" +\n    \"die echo empty exit eval include include_once isset list require require_once return \" +\n    \"print unset __halt_compiler self static parent yield insteadof finally\";\n  var phpAtoms = \"true false null TRUE FALSE NULL __CLASS__ __DIR__ __FILE__ __LINE__ __METHOD__ __FUNCTION__ __NAMESPACE__ __TRAIT__\";\n  var phpBuiltin = \"func_num_args func_get_arg func_get_args strlen strcmp strncmp strcasecmp strncasecmp each error_reporting define defined trigger_error user_error set_error_handler restore_error_handler get_declared_classes get_loaded_extensions extension_loaded get_extension_funcs debug_backtrace constant bin2hex hex2bin sleep usleep time mktime gmmktime strftime gmstrftime strtotime date gmdate getdate localtime checkdate flush wordwrap htmlspecialchars htmlentities html_entity_decode md5 md5_file crc32 getimagesize image_type_to_mime_type phpinfo phpversion phpcredits strnatcmp strnatcasecmp substr_count strspn strcspn strtok strtoupper strtolower strpos strrpos strrev hebrev hebrevc nl2br basename dirname pathinfo stripslashes stripcslashes strstr stristr strrchr str_shuffle str_word_count strcoll substr substr_replace quotemeta ucfirst ucwords strtr addslashes addcslashes rtrim str_replace str_repeat count_chars chunk_split trim ltrim strip_tags similar_text explode implode setlocale localeconv parse_str str_pad chop strchr sprintf printf vprintf vsprintf sscanf fscanf parse_url urlencode urldecode rawurlencode rawurldecode readlink linkinfo link unlink exec system escapeshellcmd escapeshellarg passthru shell_exec proc_open proc_close rand srand getrandmax mt_rand mt_srand mt_getrandmax base64_decode base64_encode abs ceil floor round is_finite is_nan is_infinite bindec hexdec octdec decbin decoct dechex base_convert number_format fmod ip2long long2ip getenv putenv getopt microtime gettimeofday getrusage uniqid quoted_printable_decode set_time_limit get_cfg_var magic_quotes_runtime set_magic_quotes_runtime get_magic_quotes_gpc get_magic_quotes_runtime import_request_variables error_log serialize unserialize memory_get_usage var_dump var_export debug_zval_dump print_r highlight_file show_source highlight_string ini_get ini_get_all ini_set ini_alter ini_restore get_include_path set_include_path restore_include_path setcookie header headers_sent connection_aborted connection_status ignore_user_abort parse_ini_file is_uploaded_file move_uploaded_file intval floatval doubleval strval gettype settype is_null is_resource is_bool is_long is_float is_int is_integer is_double is_real is_numeric is_string is_array is_object is_scalar ereg ereg_replace eregi eregi_replace split spliti join sql_regcase dl pclose popen readfile rewind rmdir umask fclose feof fgetc fgets fgetss fread fopen fpassthru ftruncate fstat fseek ftell fflush fwrite fputs mkdir rename copy tempnam tmpfile file file_get_contents stream_select stream_context_create stream_context_set_params stream_context_set_option stream_context_get_options stream_filter_prepend stream_filter_append fgetcsv flock get_meta_tags stream_set_write_buffer set_file_buffer set_socket_blocking stream_set_blocking socket_set_blocking stream_get_meta_data stream_register_wrapper stream_wrapper_register stream_set_timeout socket_set_timeout socket_get_status realpath fnmatch fsockopen pfsockopen pack unpack get_browser crypt opendir closedir chdir getcwd rewinddir readdir dir glob fileatime filectime filegroup fileinode filemtime fileowner fileperms filesize filetype file_exists is_writable is_writeable is_readable is_executable is_file is_dir is_link stat lstat chown touch clearstatcache mail ob_start ob_flush ob_clean ob_end_flush ob_end_clean ob_get_flush ob_get_clean ob_get_length ob_get_level ob_get_status ob_get_contents ob_implicit_flush ob_list_handlers ksort krsort natsort natcasesort asort arsort sort rsort usort uasort uksort shuffle array_walk count end prev next reset current key min max in_array array_search extract compact array_fill range array_multisort array_push array_pop array_shift array_unshift array_splice array_slice array_merge array_merge_recursive array_keys array_values array_count_values array_reverse array_reduce array_pad array_flip array_change_key_case array_rand array_unique array_intersect array_intersect_assoc array_diff array_diff_assoc array_sum array_filter array_map array_chunk array_key_exists pos sizeof key_exists assert assert_options version_compare ftok str_rot13 aggregate session_name session_module_name session_save_path session_id session_regenerate_id session_decode session_register session_unregister session_is_registered session_encode session_start session_destroy session_unset session_set_save_handler session_cache_limiter session_cache_expire session_set_cookie_params session_get_cookie_params session_write_close preg_match preg_match_all preg_replace preg_replace_callback preg_split preg_quote preg_grep overload ctype_alnum ctype_alpha ctype_cntrl ctype_digit ctype_lower ctype_graph ctype_print ctype_punct ctype_space ctype_upper ctype_xdigit virtual apache_request_headers apache_note apache_lookup_uri apache_child_terminate apache_setenv apache_response_headers apache_get_version getallheaders mysql_connect mysql_pconnect mysql_close mysql_select_db mysql_create_db mysql_drop_db mysql_query mysql_unbuffered_query mysql_db_query mysql_list_dbs mysql_list_tables mysql_list_fields mysql_list_processes mysql_error mysql_errno mysql_affected_rows mysql_insert_id mysql_result mysql_num_rows mysql_num_fields mysql_fetch_row mysql_fetch_array mysql_fetch_assoc mysql_fetch_object mysql_data_seek mysql_fetch_lengths mysql_fetch_field mysql_field_seek mysql_free_result mysql_field_name mysql_field_table mysql_field_len mysql_field_type mysql_field_flags mysql_escape_string mysql_real_escape_string mysql_stat mysql_thread_id mysql_client_encoding mysql_get_client_info mysql_get_host_info mysql_get_proto_info mysql_get_server_info mysql_info mysql mysql_fieldname mysql_fieldtable mysql_fieldlen mysql_fieldtype mysql_fieldflags mysql_selectdb mysql_createdb mysql_dropdb mysql_freeresult mysql_numfields mysql_numrows mysql_listdbs mysql_listtables mysql_listfields mysql_db_name mysql_dbname mysql_tablename mysql_table_name pg_connect pg_pconnect pg_close pg_connection_status pg_connection_busy pg_connection_reset pg_host pg_dbname pg_port pg_tty pg_options pg_ping pg_query pg_send_query pg_cancel_query pg_fetch_result pg_fetch_row pg_fetch_assoc pg_fetch_array pg_fetch_object pg_fetch_all pg_affected_rows pg_get_result pg_result_seek pg_result_status pg_free_result pg_last_oid pg_num_rows pg_num_fields pg_field_name pg_field_num pg_field_size pg_field_type pg_field_prtlen pg_field_is_null pg_get_notify pg_get_pid pg_result_error pg_last_error pg_last_notice pg_put_line pg_end_copy pg_copy_to pg_copy_from pg_trace pg_untrace pg_lo_create pg_lo_unlink pg_lo_open pg_lo_close pg_lo_read pg_lo_write pg_lo_read_all pg_lo_import pg_lo_export pg_lo_seek pg_lo_tell pg_escape_string pg_escape_bytea pg_unescape_bytea pg_client_encoding pg_set_client_encoding pg_meta_data pg_convert pg_insert pg_update pg_delete pg_select pg_exec pg_getlastoid pg_cmdtuples pg_errormessage pg_numrows pg_numfields pg_fieldname pg_fieldsize pg_fieldtype pg_fieldnum pg_fieldprtlen pg_fieldisnull pg_freeresult pg_result pg_loreadall pg_locreate pg_lounlink pg_loopen pg_loclose pg_loread pg_lowrite pg_loimport pg_loexport http_response_code get_declared_traits getimagesizefromstring socket_import_stream stream_set_chunk_size trait_exists header_register_callback class_uses session_status session_register_shutdown echo print global static exit array empty eval isset unset die include require include_once require_once json_decode json_encode json_last_error json_last_error_msg curl_close curl_copy_handle curl_errno curl_error curl_escape curl_exec curl_file_create curl_getinfo curl_init curl_multi_add_handle curl_multi_close curl_multi_exec curl_multi_getcontent curl_multi_info_read curl_multi_init curl_multi_remove_handle curl_multi_select curl_multi_setopt curl_multi_strerror curl_pause curl_reset curl_setopt_array curl_setopt curl_share_close curl_share_init curl_share_setopt curl_strerror curl_unescape curl_version mysqli_affected_rows mysqli_autocommit mysqli_change_user mysqli_character_set_name mysqli_close mysqli_commit mysqli_connect_errno mysqli_connect_error mysqli_connect mysqli_data_seek mysqli_debug mysqli_dump_debug_info mysqli_errno mysqli_error_list mysqli_error mysqli_fetch_all mysqli_fetch_array mysqli_fetch_assoc mysqli_fetch_field_direct mysqli_fetch_field mysqli_fetch_fields mysqli_fetch_lengths mysqli_fetch_object mysqli_fetch_row mysqli_field_count mysqli_field_seek mysqli_field_tell mysqli_free_result mysqli_get_charset mysqli_get_client_info mysqli_get_client_stats mysqli_get_client_version mysqli_get_connection_stats mysqli_get_host_info mysqli_get_proto_info mysqli_get_server_info mysqli_get_server_version mysqli_info mysqli_init mysqli_insert_id mysqli_kill mysqli_more_results mysqli_multi_query mysqli_next_result mysqli_num_fields mysqli_num_rows mysqli_options mysqli_ping mysqli_prepare mysqli_query mysqli_real_connect mysqli_real_escape_string mysqli_real_query mysqli_reap_async_query mysqli_refresh mysqli_rollback mysqli_select_db mysqli_set_charset mysqli_set_local_infile_default mysqli_set_local_infile_handler mysqli_sqlstate mysqli_ssl_set mysqli_stat mysqli_stmt_init mysqli_store_result mysqli_thread_id mysqli_thread_safe mysqli_use_result mysqli_warning_count\";\n  CodeMirror.registerHelper(\"hintWords\", \"php\", [phpKeywords, phpAtoms, phpBuiltin].join(\" \").split(\" \"));\n  CodeMirror.registerHelper(\"wordChars\", \"php\", /[\\w$]/);\n\n  var phpConfig = {\n    name: \"clike\",\n    helperType: \"php\",\n    keywords: keywords(phpKeywords),\n    blockKeywords: keywords(\"catch do else elseif for foreach if switch try while finally\"),\n    atoms: keywords(phpAtoms),\n    builtin: keywords(phpBuiltin),\n    multiLineStrings: true,\n    hooks: {\n      \"$\": function(stream) {\n        stream.eatWhile(/[\\w\\$_]/);\n        return \"variable-2\";\n      },\n      \"<\": function(stream, state) {\n        if (stream.match(/<</)) {\n          stream.eatWhile(/[\\w\\.]/);\n          var delim = stream.current().slice(3);\n          if (delim) {\n            (state.tokStack || (state.tokStack = [])).push(delim, 0);\n            state.tokenize = stringWithEscapes(delim);\n            return \"string\";\n          }\n        }\n        return false;\n      },\n      \"#\": function(stream) {\n        while (!stream.eol() && !stream.match(\"?>\", false)) stream.next();\n        return \"comment\";\n      },\n      \"/\": function(stream) {\n        if (stream.eat(\"/\")) {\n          while (!stream.eol() && !stream.match(\"?>\", false)) stream.next();\n          return \"comment\";\n        }\n        return false;\n      },\n      '\"': function(_stream, state) {\n        (state.tokStack || (state.tokStack = [])).push('\"', 0);\n        state.tokenize = stringWithEscapes('\"');\n        return \"string\";\n      },\n      \"{\": function(_stream, state) {\n        if (state.tokStack && state.tokStack.length)\n          state.tokStack[state.tokStack.length - 1]++;\n        return false;\n      },\n      \"}\": function(_stream, state) {\n        if (state.tokStack && state.tokStack.length > 0 &&\n            !--state.tokStack[state.tokStack.length - 1]) {\n          state.tokenize = stringWithEscapes(state.tokStack[state.tokStack.length - 2]);\n        }\n        return false;\n      }\n    }\n  };\n\n  CodeMirror.defineMode(\"php\", function(config, parserConfig) {\n    var htmlMode = CodeMirror.getMode(config, \"text/html\");\n    var phpMode = CodeMirror.getMode(config, phpConfig);\n\n    function dispatch(stream, state) {\n      var isPHP = state.curMode == phpMode;\n      if (stream.sol() && state.pending && state.pending != '\"' && state.pending != \"'\") state.pending = null;\n      if (!isPHP) {\n        if (stream.match(/^<\\?\\w*/)) {\n          state.curMode = phpMode;\n          state.curState = state.php;\n          return \"meta\";\n        }\n        if (state.pending == '\"' || state.pending == \"'\") {\n          while (!stream.eol() && stream.next() != state.pending) {}\n          var style = \"string\";\n        } else if (state.pending && stream.pos < state.pending.end) {\n          stream.pos = state.pending.end;\n          var style = state.pending.style;\n        } else {\n          var style = htmlMode.token(stream, state.curState);\n        }\n        if (state.pending) state.pending = null;\n        var cur = stream.current(), openPHP = cur.search(/<\\?/), m;\n        if (openPHP != -1) {\n          if (style == \"string\" && (m = cur.match(/[\\'\\\"]$/)) && !/\\?>/.test(cur)) state.pending = m[0];\n          else state.pending = {end: stream.pos, style: style};\n          stream.backUp(cur.length - openPHP);\n        }\n        return style;\n      } else if (isPHP && state.php.tokenize == null && stream.match(\"?>\")) {\n        state.curMode = htmlMode;\n        state.curState = state.html;\n        return \"meta\";\n      } else {\n        return phpMode.token(stream, state.curState);\n      }\n    }\n\n    return {\n      startState: function() {\n        var html = CodeMirror.startState(htmlMode), php = CodeMirror.startState(phpMode);\n        return {html: html,\n                php: php,\n                curMode: parserConfig.startOpen ? phpMode : htmlMode,\n                curState: parserConfig.startOpen ? php : html,\n                pending: null};\n      },\n\n      copyState: function(state) {\n        var html = state.html, htmlNew = CodeMirror.copyState(htmlMode, html),\n            php = state.php, phpNew = CodeMirror.copyState(phpMode, php), cur;\n        if (state.curMode == htmlMode) cur = htmlNew;\n        else cur = phpNew;\n        return {html: htmlNew, php: phpNew, curMode: state.curMode, curState: cur,\n                pending: state.pending};\n      },\n\n      token: dispatch,\n\n      indent: function(state, textAfter) {\n        if ((state.curMode != phpMode && /^\\s*<\\//.test(textAfter)) ||\n            (state.curMode == phpMode && /^\\?>/.test(textAfter)))\n          return htmlMode.indent(state.html, textAfter);\n        return state.curMode.indent(state.curState, textAfter);\n      },\n\n      blockCommentStart: \"/*\",\n      blockCommentEnd: \"*/\",\n      lineComment: \"//\",\n\n      innerMode: function(state) { return {state: state.curState, mode: state.curMode}; }\n    };\n  }, \"htmlmixed\", \"clike\");\n\n  CodeMirror.defineMIME(\"application/x-httpd-php\", \"php\");\n  CodeMirror.defineMIME(\"application/x-httpd-php-open\", {name: \"php\", startOpen: true});\n  CodeMirror.defineMIME(\"text/x-php\", phpConfig);\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/php/test.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function() {\n  var mode = CodeMirror.getMode({indentUnit: 2}, \"php\");\n  function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); }\n\n  MT('simple_test',\n     '[meta <?php] ' +\n     '[keyword echo] [string \"aaa\"]; ' +\n     '[meta ?>]');\n\n  MT('variable_interpolation_non_alphanumeric',\n     '[meta <?php]',\n     '[keyword echo] [string \"aaa$~$!$@$#$$$%$^$&$*$($)$.$<$>$/$\\\\$}$\\\\\\\"$:$;$?$|$[[$]]$+$=aaa\"]',\n     '[meta ?>]');\n\n  MT('variable_interpolation_digits',\n     '[meta <?php]',\n     '[keyword echo] [string \"aaa$1$2$3$4$5$6$7$8$9$0aaa\"]',\n     '[meta ?>]');\n\n  MT('variable_interpolation_simple_syntax_1',\n     '[meta <?php]',\n     '[keyword echo] [string \"aaa][variable-2 $aaa][string .aaa\"];',\n     '[meta ?>]');\n\n  MT('variable_interpolation_simple_syntax_2',\n     '[meta <?php]',\n     '[keyword echo] [string \"][variable-2 $aaaa][[','[number 2]',         ']][string aa\"];',\n     '[keyword echo] [string \"][variable-2 $aaaa][[','[number 2345]',      ']][string aa\"];',\n     '[keyword echo] [string \"][variable-2 $aaaa][[','[number 2.3]',       ']][string aa\"];',\n     '[keyword echo] [string \"][variable-2 $aaaa][[','[variable aaaaa]',   ']][string aa\"];',\n     '[keyword echo] [string \"][variable-2 $aaaa][[','[variable-2 $aaaaa]',']][string aa\"];',\n\n     '[keyword echo] [string \"1aaa][variable-2 $aaaa][[','[number 2]',         ']][string aa\"];',\n     '[keyword echo] [string \"aaa][variable-2 $aaaa][[','[number 2345]',      ']][string aa\"];',\n     '[keyword echo] [string \"aaa][variable-2 $aaaa][[','[number 2.3]',       ']][string aa\"];',\n     '[keyword echo] [string \"aaa][variable-2 $aaaa][[','[variable aaaaa]',   ']][string aa\"];',\n     '[keyword echo] [string \"aaa][variable-2 $aaaa][[','[variable-2 $aaaaa]',']][string aa\"];',\n     '[meta ?>]');\n\n  MT('variable_interpolation_simple_syntax_3',\n     '[meta <?php]',\n     '[keyword echo] [string \"aaa][variable-2 $aaaa]->[variable aaaaa][string .aaaaaa\"];',\n     '[keyword echo] [string \"aaa][variable-2 $aaaa][string ->][variable-2 $aaaaa][string .aaaaaa\"];',\n     '[keyword echo] [string \"aaa][variable-2 $aaaa]->[variable aaaaa][string [[2]].aaaaaa\"];',\n     '[keyword echo] [string \"aaa][variable-2 $aaaa]->[variable aaaaa][string ->aaaa2.aaaaaa\"];',\n     '[meta ?>]');\n\n  MT('variable_interpolation_escaping',\n     '[meta <?php] [comment /* Escaping */]',\n     '[keyword echo] [string \"aaa\\\\$aaaa->aaa.aaa\"];',\n     '[keyword echo] [string \"aaa\\\\$aaaa[[2]]aaa.aaa\"];',\n     '[keyword echo] [string \"aaa\\\\$aaaa[[asd]]aaa.aaa\"];',\n     '[keyword echo] [string \"aaa{\\\\$aaaa->aaa.aaa\"];',\n     '[keyword echo] [string \"aaa{\\\\$aaaa[[2]]aaa.aaa\"];',\n     '[keyword echo] [string \"aaa{\\\\aaaaa[[asd]]aaa.aaa\"];',\n     '[keyword echo] [string \"aaa\\\\${aaaa->aaa.aaa\"];',\n     '[keyword echo] [string \"aaa\\\\${aaaa[[2]]aaa.aaa\"];',\n     '[keyword echo] [string \"aaa\\\\${aaaa[[asd]]aaa.aaa\"];',\n     '[meta ?>]');\n\n  MT('variable_interpolation_complex_syntax_1',\n     '[meta <?php]',\n     '[keyword echo] [string \"aaa][variable-2 $]{[variable aaaa]}[string ->aaa.aaa\"];',\n     '[keyword echo] [string \"aaa][variable-2 $]{[variable-2 $aaaa]}[string ->aaa.aaa\"];',\n     '[keyword echo] [string \"aaa][variable-2 $]{[variable-2 $aaaa][[','  [number 42]',']]}[string ->aaa.aaa\"];',\n     '[keyword echo] [string \"aaa][variable-2 $]{[variable aaaa][meta ?>]aaaaaa');\n\n  MT('variable_interpolation_complex_syntax_2',\n     '[meta <?php] [comment /* Monsters */]',\n     '[keyword echo] [string \"][variable-2 $]{[variable aaa][comment /*}?>} $aaa<?php } */]}[string ->aaa.aaa\"];',\n     '[keyword echo] [string \"][variable-2 $]{[variable aaa][comment /*}?>*/][[','  [string \"aaa][variable-2 $aaa][string {}][variable-2 $]{[variable aaa]}[string \"]',']]}[string ->aaa.aaa\"];',\n     '[keyword echo] [string \"][variable-2 $]{[variable aaa][comment /*} } $aaa } */]}[string ->aaa.aaa\"];');\n\n\n  function build_recursive_monsters(nt, t, n){\n    var monsters = [t];\n    for (var i = 1; i <= n; ++i)\n      monsters[i] = nt.join(monsters[i - 1]);\n    return monsters;\n  }\n\n  var m1 = build_recursive_monsters(\n    ['[string \"][variable-2 $]{[variable aaa] [operator +] ', '}[string \"]'],\n    '[comment /* }?>} */] [string \"aaa][variable-2 $aaa][string .aaa\"]',\n    10\n  );\n\n  MT('variable_interpolation_complex_syntax_3_1',\n     '[meta <?php] [comment /* Recursive monsters */]',\n     '[keyword echo] ' + m1[4] + ';',\n     '[keyword echo] ' + m1[7] + ';',\n     '[keyword echo] ' + m1[8] + ';',\n     '[keyword echo] ' + m1[5] + ';',\n     '[keyword echo] ' + m1[1] + ';',\n     '[keyword echo] ' + m1[6] + ';',\n     '[keyword echo] ' + m1[9] + ';',\n     '[keyword echo] ' + m1[0] + ';',\n     '[keyword echo] ' + m1[10] + ';',\n     '[keyword echo] ' + m1[2] + ';',\n     '[keyword echo] ' + m1[3] + ';',\n     '[keyword echo] [string \"end\"];',\n     '[meta ?>]');\n\n  var m2 = build_recursive_monsters(\n    ['[string \"a][variable-2 $]{[variable aaa] [operator +] ', ' [operator +] ', '}[string .a\"]'],\n    '[comment /* }?>{{ */] [string \"a?>}{{aa][variable-2 $aaa][string .a}a?>a\"]',\n    5\n  );\n\n  MT('variable_interpolation_complex_syntax_3_2',\n     '[meta <?php] [comment /* Recursive monsters 2 */]',\n     '[keyword echo] ' + m2[0] + ';',\n     '[keyword echo] ' + m2[1] + ';',\n     '[keyword echo] ' + m2[5] + ';',\n     '[keyword echo] ' + m2[4] + ';',\n     '[keyword echo] ' + m2[2] + ';',\n     '[keyword echo] ' + m2[3] + ';',\n     '[keyword echo] [string \"end\"];',\n     '[meta ?>]');\n\n  function build_recursive_monsters_2(mf1, mf2, nt, t, n){\n    var monsters = [t];\n    for (var i = 1; i <= n; ++i)\n      monsters[i] = nt[0] + mf1[i - 1] + nt[1] + mf2[i - 1] + nt[2] + monsters[i - 1] + nt[3];\n    return monsters;\n  }\n\n  var m3 = build_recursive_monsters_2(\n    m1,\n    m2,\n    ['[string \"a][variable-2 $]{[variable aaa] [operator +] ', ' [operator +] ', ' [operator +] ', '}[string .a\"]'],\n    '[comment /* }?>{{ */] [string \"a?>}{{aa][variable-2 $aaa][string .a}a?>a\"]',\n    4\n  );\n\n  MT('variable_interpolation_complex_syntax_3_3',\n     '[meta <?php] [comment /* Recursive monsters 2 */]',\n     '[keyword echo] ' + m3[4] + ';',\n     '[keyword echo] ' + m3[0] + ';',\n     '[keyword echo] ' + m3[3] + ';',\n     '[keyword echo] ' + m3[1] + ';',\n     '[keyword echo] ' + m3[2] + ';',\n     '[keyword echo] [string \"end\"];',\n     '[meta ?>]');\n\n  MT(\"variable_interpolation_heredoc\",\n     \"[meta <?php]\",\n     \"[string <<<here]\",\n     \"[string doc ][variable-2 $]{[variable yay]}[string more]\",\n     \"[string here]; [comment // normal]\");\n})();\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/pig/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Pig Latin mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"pig.js\"></script>\n<style>.CodeMirror {border: 2px inset #dee;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Pig Latin</a>\n  </ul>\n</div>\n\n<article>\n<h2>Pig Latin mode</h2>\n<form><textarea id=\"code\" name=\"code\">\n-- Apache Pig (Pig Latin Language) Demo\n/* \nThis is a multiline comment.\n*/\na = LOAD \"\\path\\to\\input\" USING PigStorage('\\t') AS (x:long, y:chararray, z:bytearray);\nb = GROUP a BY (x,y,3+4);\nc = FOREACH b GENERATE flatten(group) as (x,y), SUM(group.$2) as z;\nSTORE c INTO \"\\path\\to\\output\";\n\n--\n</textarea></form>\n\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        lineNumbers: true,\n        indentUnit: 4,\n        mode: \"text/x-pig\"\n      });\n    </script>\n\n    <p>\n        Simple mode that handles Pig Latin language.\n    </p>\n\n    <p><strong>MIME type defined:</strong> <code>text/x-pig</code>\n    (PIG code)\n</html>\n</article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/pig/pig.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n/*\n *      Pig Latin Mode for CodeMirror 2\n *      @author Prasanth Jayachandran\n *      @link   https://github.com/prasanthj/pig-codemirror-2\n *  This implementation is adapted from PL/SQL mode in CodeMirror 2.\n */\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"pig\", function(_config, parserConfig) {\n  var keywords = parserConfig.keywords,\n  builtins = parserConfig.builtins,\n  types = parserConfig.types,\n  multiLineStrings = parserConfig.multiLineStrings;\n\n  var isOperatorChar = /[*+\\-%<>=&?:\\/!|]/;\n\n  function chain(stream, state, f) {\n    state.tokenize = f;\n    return f(stream, state);\n  }\n\n  var type;\n  function ret(tp, style) {\n    type = tp;\n    return style;\n  }\n\n  function tokenComment(stream, state) {\n    var isEnd = false;\n    var ch;\n    while(ch = stream.next()) {\n      if(ch == \"/\" && isEnd) {\n        state.tokenize = tokenBase;\n        break;\n      }\n      isEnd = (ch == \"*\");\n    }\n    return ret(\"comment\", \"comment\");\n  }\n\n  function tokenString(quote) {\n    return function(stream, state) {\n      var escaped = false, next, end = false;\n      while((next = stream.next()) != null) {\n        if (next == quote && !escaped) {\n          end = true; break;\n        }\n        escaped = !escaped && next == \"\\\\\";\n      }\n      if (end || !(escaped || multiLineStrings))\n        state.tokenize = tokenBase;\n      return ret(\"string\", \"error\");\n    };\n  }\n\n  function tokenBase(stream, state) {\n    var ch = stream.next();\n\n    // is a start of string?\n    if (ch == '\"' || ch == \"'\")\n      return chain(stream, state, tokenString(ch));\n    // is it one of the special chars\n    else if(/[\\[\\]{}\\(\\),;\\.]/.test(ch))\n      return ret(ch);\n    // is it a number?\n    else if(/\\d/.test(ch)) {\n      stream.eatWhile(/[\\w\\.]/);\n      return ret(\"number\", \"number\");\n    }\n    // multi line comment or operator\n    else if (ch == \"/\") {\n      if (stream.eat(\"*\")) {\n        return chain(stream, state, tokenComment);\n      }\n      else {\n        stream.eatWhile(isOperatorChar);\n        return ret(\"operator\", \"operator\");\n      }\n    }\n    // single line comment or operator\n    else if (ch==\"-\") {\n      if(stream.eat(\"-\")){\n        stream.skipToEnd();\n        return ret(\"comment\", \"comment\");\n      }\n      else {\n        stream.eatWhile(isOperatorChar);\n        return ret(\"operator\", \"operator\");\n      }\n    }\n    // is it an operator\n    else if (isOperatorChar.test(ch)) {\n      stream.eatWhile(isOperatorChar);\n      return ret(\"operator\", \"operator\");\n    }\n    else {\n      // get the while word\n      stream.eatWhile(/[\\w\\$_]/);\n      // is it one of the listed keywords?\n      if (keywords && keywords.propertyIsEnumerable(stream.current().toUpperCase())) {\n        if (stream.eat(\")\") || stream.eat(\".\")) {\n          //keywords can be used as variables like flatten(group), group.$0 etc..\n        }\n        else {\n          return (\"keyword\", \"keyword\");\n        }\n      }\n      // is it one of the builtin functions?\n      if (builtins && builtins.propertyIsEnumerable(stream.current().toUpperCase()))\n      {\n        return (\"keyword\", \"variable-2\");\n      }\n      // is it one of the listed types?\n      if (types && types.propertyIsEnumerable(stream.current().toUpperCase()))\n        return (\"keyword\", \"variable-3\");\n      // default is a 'variable'\n      return ret(\"variable\", \"pig-word\");\n    }\n  }\n\n  // Interface\n  return {\n    startState: function() {\n      return {\n        tokenize: tokenBase,\n        startOfLine: true\n      };\n    },\n\n    token: function(stream, state) {\n      if(stream.eatSpace()) return null;\n      var style = state.tokenize(stream, state);\n      return style;\n    }\n  };\n});\n\n(function() {\n  function keywords(str) {\n    var obj = {}, words = str.split(\" \");\n    for (var i = 0; i < words.length; ++i) obj[words[i]] = true;\n    return obj;\n  }\n\n  // builtin funcs taken from trunk revision 1303237\n  var pBuiltins = \"ABS ACOS ARITY ASIN ATAN AVG BAGSIZE BINSTORAGE BLOOM BUILDBLOOM CBRT CEIL \"\n    + \"CONCAT COR COS COSH COUNT COUNT_STAR COV CONSTANTSIZE CUBEDIMENSIONS DIFF DISTINCT DOUBLEABS \"\n    + \"DOUBLEAVG DOUBLEBASE DOUBLEMAX DOUBLEMIN DOUBLEROUND DOUBLESUM EXP FLOOR FLOATABS FLOATAVG \"\n    + \"FLOATMAX FLOATMIN FLOATROUND FLOATSUM GENERICINVOKER INDEXOF INTABS INTAVG INTMAX INTMIN \"\n    + \"INTSUM INVOKEFORDOUBLE INVOKEFORFLOAT INVOKEFORINT INVOKEFORLONG INVOKEFORSTRING INVOKER \"\n    + \"ISEMPTY JSONLOADER JSONMETADATA JSONSTORAGE LAST_INDEX_OF LCFIRST LOG LOG10 LOWER LONGABS \"\n    + \"LONGAVG LONGMAX LONGMIN LONGSUM MAX MIN MAPSIZE MONITOREDUDF NONDETERMINISTIC OUTPUTSCHEMA  \"\n    + \"PIGSTORAGE PIGSTREAMING RANDOM REGEX_EXTRACT REGEX_EXTRACT_ALL REPLACE ROUND SIN SINH SIZE \"\n    + \"SQRT STRSPLIT SUBSTRING SUM STRINGCONCAT STRINGMAX STRINGMIN STRINGSIZE TAN TANH TOBAG \"\n    + \"TOKENIZE TOMAP TOP TOTUPLE TRIM TEXTLOADER TUPLESIZE UCFIRST UPPER UTF8STORAGECONVERTER \";\n\n  // taken from QueryLexer.g\n  var pKeywords = \"VOID IMPORT RETURNS DEFINE LOAD FILTER FOREACH ORDER CUBE DISTINCT COGROUP \"\n    + \"JOIN CROSS UNION SPLIT INTO IF OTHERWISE ALL AS BY USING INNER OUTER ONSCHEMA PARALLEL \"\n    + \"PARTITION GROUP AND OR NOT GENERATE FLATTEN ASC DESC IS STREAM THROUGH STORE MAPREDUCE \"\n    + \"SHIP CACHE INPUT OUTPUT STDERROR STDIN STDOUT LIMIT SAMPLE LEFT RIGHT FULL EQ GT LT GTE LTE \"\n    + \"NEQ MATCHES TRUE FALSE DUMP\";\n\n  // data types\n  var pTypes = \"BOOLEAN INT LONG FLOAT DOUBLE CHARARRAY BYTEARRAY BAG TUPLE MAP \";\n\n  CodeMirror.defineMIME(\"text/x-pig\", {\n    name: \"pig\",\n    builtins: keywords(pBuiltins),\n    keywords: keywords(pKeywords),\n    types: keywords(pTypes)\n  });\n\n  CodeMirror.registerHelper(\"hintWords\", \"pig\", (pBuiltins + pTypes + pKeywords).split(\" \"));\n}());\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/properties/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Properties files mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"properties.js\"></script>\n<style>.CodeMirror {border-top: 1px solid #ddd; border-bottom: 1px solid #ddd;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Properties files</a>\n  </ul>\n</div>\n\n<article>\n<h2>Properties files mode</h2>\n<form><textarea id=\"code\" name=\"code\">\n# This is a properties file\na.key = A value\nanother.key = http://example.com\n! Exclamation mark as comment\nbut.not=Within ! A value # indeed\n   # Spaces at the beginning of a line\n   spaces.before.key=value\nbackslash=Used for multi\\\n          line entries,\\\n          that's convenient.\n# Unicode sequences\nunicode.key=This is \\u0020 Unicode\nno.multiline=here\n# Colons\ncolons : can be used too\n# Spaces\nspaces\\ in\\ keys=Not very common...\n</textarea></form>\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {});\n    </script>\n\n    <p><strong>MIME types defined:</strong> <code>text/x-properties</code>,\n    <code>text/x-ini</code>.</p>\n\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/properties/properties.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"properties\", function() {\n  return {\n    token: function(stream, state) {\n      var sol = stream.sol() || state.afterSection;\n      var eol = stream.eol();\n\n      state.afterSection = false;\n\n      if (sol) {\n        if (state.nextMultiline) {\n          state.inMultiline = true;\n          state.nextMultiline = false;\n        } else {\n          state.position = \"def\";\n        }\n      }\n\n      if (eol && ! state.nextMultiline) {\n        state.inMultiline = false;\n        state.position = \"def\";\n      }\n\n      if (sol) {\n        while(stream.eatSpace());\n      }\n\n      var ch = stream.next();\n\n      if (sol && (ch === \"#\" || ch === \"!\" || ch === \";\")) {\n        state.position = \"comment\";\n        stream.skipToEnd();\n        return \"comment\";\n      } else if (sol && ch === \"[\") {\n        state.afterSection = true;\n        stream.skipTo(\"]\"); stream.eat(\"]\");\n        return \"header\";\n      } else if (ch === \"=\" || ch === \":\") {\n        state.position = \"quote\";\n        return null;\n      } else if (ch === \"\\\\\" && state.position === \"quote\") {\n        if (stream.next() !== \"u\") {    // u = Unicode sequence \\u1234\n          // Multiline value\n          state.nextMultiline = true;\n        }\n      }\n\n      return state.position;\n    },\n\n    startState: function() {\n      return {\n        position : \"def\",       // Current position, \"def\", \"quote\" or \"comment\"\n        nextMultiline : false,  // Is the next line multiline value\n        inMultiline : false,    // Is the current line a multiline value\n        afterSection : false    // Did we just open a section\n      };\n    }\n\n  };\n});\n\nCodeMirror.defineMIME(\"text/x-properties\", \"properties\");\nCodeMirror.defineMIME(\"text/x-ini\", \"properties\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/puppet/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Puppet mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"../../addon/edit/matchbrackets.js\"></script>\n<script src=\"puppet.js\"></script>\n<style>\n      .CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}\n      .cm-s-default span.cm-arrow { color: red; }\n    </style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Puppet</a>\n  </ul>\n</div>\n\n<article>\n<h2>Puppet mode</h2>\n<form><textarea id=\"code\" name=\"code\">\n# == Class: automysqlbackup\n#\n# Puppet module to install AutoMySQLBackup for periodic MySQL backups.\n#\n# class { 'automysqlbackup':\n#   backup_dir => '/mnt/backups',\n# }\n#\n\nclass automysqlbackup (\n  $bin_dir = $automysqlbackup::params::bin_dir,\n  $etc_dir = $automysqlbackup::params::etc_dir,\n  $backup_dir = $automysqlbackup::params::backup_dir,\n  $install_multicore = undef,\n  $config = {},\n  $config_defaults = {},\n) inherits automysqlbackup::params {\n\n# Ensure valid paths are assigned\n  validate_absolute_path($bin_dir)\n  validate_absolute_path($etc_dir)\n  validate_absolute_path($backup_dir)\n\n# Create a subdirectory in /etc for config files\n  file { $etc_dir:\n    ensure => directory,\n    owner => 'root',\n    group => 'root',\n    mode => '0750',\n  }\n\n# Create an example backup file, useful for reference\n  file { \"${etc_dir}/automysqlbackup.conf.example\":\n    ensure => file,\n    owner => 'root',\n    group => 'root',\n    mode => '0660',\n    source => 'puppet:///modules/automysqlbackup/automysqlbackup.conf',\n  }\n\n# Add files from the developer\n  file { \"${etc_dir}/AMB_README\":\n    ensure => file,\n    source => 'puppet:///modules/automysqlbackup/AMB_README',\n  }\n  file { \"${etc_dir}/AMB_LICENSE\":\n    ensure => file,\n    source => 'puppet:///modules/automysqlbackup/AMB_LICENSE',\n  }\n\n# Install the actual binary file\n  file { \"${bin_dir}/automysqlbackup\":\n    ensure => file,\n    owner => 'root',\n    group => 'root',\n    mode => '0755',\n    source => 'puppet:///modules/automysqlbackup/automysqlbackup',\n  }\n\n# Create the base backup directory\n  file { $backup_dir:\n    ensure => directory,\n    owner => 'root',\n    group => 'root',\n    mode => '0755',\n  }\n\n# If you'd like to keep your config in hiera and pass it to this class\n  if !empty($config) {\n    create_resources('automysqlbackup::backup', $config, $config_defaults)\n  }\n\n# If using RedHat family, must have the RPMforge repo's enabled\n  if $install_multicore {\n    package { ['pigz', 'pbzip2']: ensure => installed }\n  }\n\n}\n</textarea></form>\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        mode: \"text/x-puppet\",\n        matchBrackets: true,\n        indentUnit: 4\n      });\n    </script>\n\n    <p><strong>MIME types defined:</strong> <code>text/x-puppet</code>.</p>\n\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/puppet/puppet.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"puppet\", function () {\n  // Stores the words from the define method\n  var words = {};\n  // Taken, mostly, from the Puppet official variable standards regex\n  var variable_regex = /({)?([a-z][a-z0-9_]*)?((::[a-z][a-z0-9_]*)*::)?[a-zA-Z0-9_]+(})?/;\n\n  // Takes a string of words separated by spaces and adds them as\n  // keys with the value of the first argument 'style'\n  function define(style, string) {\n    var split = string.split(' ');\n    for (var i = 0; i < split.length; i++) {\n      words[split[i]] = style;\n    }\n  }\n\n  // Takes commonly known puppet types/words and classifies them to a style\n  define('keyword', 'class define site node include import inherits');\n  define('keyword', 'case if else in and elsif default or');\n  define('atom', 'false true running present absent file directory undef');\n  define('builtin', 'action augeas burst chain computer cron destination dport exec ' +\n    'file filebucket group host icmp iniface interface jump k5login limit log_level ' +\n    'log_prefix macauthorization mailalias maillist mcx mount nagios_command ' +\n    'nagios_contact nagios_contactgroup nagios_host nagios_hostdependency ' +\n    'nagios_hostescalation nagios_hostextinfo nagios_hostgroup nagios_service ' +\n    'nagios_servicedependency nagios_serviceescalation nagios_serviceextinfo ' +\n    'nagios_servicegroup nagios_timeperiod name notify outiface package proto reject ' +\n    'resources router schedule scheduled_task selboolean selmodule service source ' +\n    'sport ssh_authorized_key sshkey stage state table tidy todest toports tosource ' +\n    'user vlan yumrepo zfs zone zpool');\n\n  // After finding a start of a string ('|\") this function attempts to find the end;\n  // If a variable is encountered along the way, we display it differently when it\n  // is encapsulated in a double-quoted string.\n  function tokenString(stream, state) {\n    var current, prev, found_var = false;\n    while (!stream.eol() && (current = stream.next()) != state.pending) {\n      if (current === '$' && prev != '\\\\' && state.pending == '\"') {\n        found_var = true;\n        break;\n      }\n      prev = current;\n    }\n    if (found_var) {\n      stream.backUp(1);\n    }\n    if (current == state.pending) {\n      state.continueString = false;\n    } else {\n      state.continueString = true;\n    }\n    return \"string\";\n  }\n\n  // Main function\n  function tokenize(stream, state) {\n    // Matches one whole word\n    var word = stream.match(/[\\w]+/, false);\n    // Matches attributes (i.e. ensure => present ; 'ensure' would be matched)\n    var attribute = stream.match(/(\\s+)?\\w+\\s+=>.*/, false);\n    // Matches non-builtin resource declarations\n    // (i.e. \"apache::vhost {\" or \"mycustomclasss {\" would be matched)\n    var resource = stream.match(/(\\s+)?[\\w:_]+(\\s+)?{/, false);\n    // Matches virtual and exported resources (i.e. @@user { ; and the like)\n    var special_resource = stream.match(/(\\s+)?[@]{1,2}[\\w:_]+(\\s+)?{/, false);\n\n    // Finally advance the stream\n    var ch = stream.next();\n\n    // Have we found a variable?\n    if (ch === '$') {\n      if (stream.match(variable_regex)) {\n        // If so, and its in a string, assign it a different color\n        return state.continueString ? 'variable-2' : 'variable';\n      }\n      // Otherwise return an invalid variable\n      return \"error\";\n    }\n    // Should we still be looking for the end of a string?\n    if (state.continueString) {\n      // If so, go through the loop again\n      stream.backUp(1);\n      return tokenString(stream, state);\n    }\n    // Are we in a definition (class, node, define)?\n    if (state.inDefinition) {\n      // If so, return def (i.e. for 'class myclass {' ; 'myclass' would be matched)\n      if (stream.match(/(\\s+)?[\\w:_]+(\\s+)?/)) {\n        return 'def';\n      }\n      // Match the rest it the next time around\n      stream.match(/\\s+{/);\n      state.inDefinition = false;\n    }\n    // Are we in an 'include' statement?\n    if (state.inInclude) {\n      // Match and return the included class\n      stream.match(/(\\s+)?\\S+(\\s+)?/);\n      state.inInclude = false;\n      return 'def';\n    }\n    // Do we just have a function on our hands?\n    // In 'ensure_resource(\"myclass\")', 'ensure_resource' is matched\n    if (stream.match(/(\\s+)?\\w+\\(/)) {\n      stream.backUp(1);\n      return 'def';\n    }\n    // Have we matched the prior attribute regex?\n    if (attribute) {\n      stream.match(/(\\s+)?\\w+/);\n      return 'tag';\n    }\n    // Do we have Puppet specific words?\n    if (word && words.hasOwnProperty(word)) {\n      // Negates the initial next()\n      stream.backUp(1);\n      // Acutally move the stream\n      stream.match(/[\\w]+/);\n      // We want to process these words differently\n      // do to the importance they have in Puppet\n      if (stream.match(/\\s+\\S+\\s+{/, false)) {\n        state.inDefinition = true;\n      }\n      if (word == 'include') {\n        state.inInclude = true;\n      }\n      // Returns their value as state in the prior define methods\n      return words[word];\n    }\n    // Is there a match on a reference?\n    if (/(^|\\s+)[A-Z][\\w:_]+/.test(word)) {\n      // Negate the next()\n      stream.backUp(1);\n      // Match the full reference\n      stream.match(/(^|\\s+)[A-Z][\\w:_]+/);\n      return 'def';\n    }\n    // Have we matched the prior resource regex?\n    if (resource) {\n      stream.match(/(\\s+)?[\\w:_]+/);\n      return 'def';\n    }\n    // Have we matched the prior special_resource regex?\n    if (special_resource) {\n      stream.match(/(\\s+)?[@]{1,2}/);\n      return 'special';\n    }\n    // Match all the comments. All of them.\n    if (ch == \"#\") {\n      stream.skipToEnd();\n      return \"comment\";\n    }\n    // Have we found a string?\n    if (ch == \"'\" || ch == '\"') {\n      // Store the type (single or double)\n      state.pending = ch;\n      // Perform the looping function to find the end\n      return tokenString(stream, state);\n    }\n    // Match all the brackets\n    if (ch == '{' || ch == '}') {\n      return 'bracket';\n    }\n    // Match characters that we are going to assume\n    // are trying to be regex\n    if (ch == '/') {\n      stream.match(/.*?\\//);\n      return 'variable-3';\n    }\n    // Match all the numbers\n    if (ch.match(/[0-9]/)) {\n      stream.eatWhile(/[0-9]+/);\n      return 'number';\n    }\n    // Match the '=' and '=>' operators\n    if (ch == '=') {\n      if (stream.peek() == '>') {\n          stream.next();\n      }\n      return \"operator\";\n    }\n    // Keep advancing through all the rest\n    stream.eatWhile(/[\\w-]/);\n    // Return a blank line for everything else\n    return null;\n  }\n  // Start it all\n  return {\n    startState: function () {\n      var state = {};\n      state.inDefinition = false;\n      state.inInclude = false;\n      state.continueString = false;\n      state.pending = false;\n      return state;\n    },\n    token: function (stream, state) {\n      // Strip the spaces, but regex will account for them eitherway\n      if (stream.eatSpace()) return null;\n      // Go through the main process\n      return tokenize(stream, state);\n    }\n  };\n});\n\nCodeMirror.defineMIME(\"text/x-puppet\", \"puppet\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/python/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Python mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"../../addon/edit/matchbrackets.js\"></script>\n<script src=\"python.js\"></script>\n<style type=\"text/css\">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Python</a>\n  </ul>\n</div>\n\n<article>\n<h2>Python mode</h2>\n\n    <div><textarea id=\"code\" name=\"code\">\n# Literals\n1234\n0.0e101\n.123\n0b01010011100\n0o01234567\n0x0987654321abcdef\n7\n2147483647\n3L\n79228162514264337593543950336L\n0x100000000L\n79228162514264337593543950336\n0xdeadbeef\n3.14j\n10.j\n10j\n.001j\n1e100j\n3.14e-10j\n\n\n# String Literals\n'For\\''\n\"God\\\"\"\n\"\"\"so loved\nthe world\"\"\"\n'''that he gave\nhis only begotten\\' '''\n'that whosoever believeth \\\nin him'\n''\n\n# Identifiers\n__a__\na.b\na.b.c\n\n#Unicode identifiers on Python3\n# a = x\\ddot\na⃗ = ẍ\n# a = v\\dot\na⃗ = v̇\n\n#F\\vec = m \\cdot a\\vec\nF⃗ = m•a⃗ \n\n# Operators\n+ - * / % & | ^ ~ < >\n== != <= >= <> << >> // **\nand or not in is\n\n#infix matrix multiplication operator (PEP 465)\nA @ B\n\n# Delimiters\n() [] {} , : ` = ; @ .  # Note that @ and . require the proper context on Python 2.\n+= -= *= /= %= &= |= ^=\n//= >>= <<= **=\n\n# Keywords\nas assert break class continue def del elif else except\nfinally for from global if import lambda pass raise\nreturn try while with yield\n\n# Python 2 Keywords (otherwise Identifiers)\nexec print\n\n# Python 3 Keywords (otherwise Identifiers)\nnonlocal\n\n# Types\nbool classmethod complex dict enumerate float frozenset int list object\nproperty reversed set slice staticmethod str super tuple type\n\n# Python 2 Types (otherwise Identifiers)\nbasestring buffer file long unicode xrange\n\n# Python 3 Types (otherwise Identifiers)\nbytearray bytes filter map memoryview open range zip\n\n# Some Example code\nimport os\nfrom package import ParentClass\n\n@nonsenseDecorator\ndef doesNothing():\n    pass\n\nclass ExampleClass(ParentClass):\n    @staticmethod\n    def example(inputStr):\n        a = list(inputStr)\n        a.reverse()\n        return ''.join(a)\n\n    def __init__(self, mixin = 'Hello'):\n        self.mixin = mixin\n\n</textarea></div>\n\n\n<h2>Cython mode</h2>\n\n<div><textarea id=\"code-cython\" name=\"code-cython\">\n\nimport numpy as np\ncimport cython\nfrom libc.math cimport sqrt\n\n@cython.boundscheck(False)\n@cython.wraparound(False)\ndef pairwise_cython(double[:, ::1] X):\n    cdef int M = X.shape[0]\n    cdef int N = X.shape[1]\n    cdef double tmp, d\n    cdef double[:, ::1] D = np.empty((M, M), dtype=np.float64)\n    for i in range(M):\n        for j in range(M):\n            d = 0.0\n            for k in range(N):\n                tmp = X[i, k] - X[j, k]\n                d += tmp * tmp\n            D[i, j] = sqrt(d)\n    return np.asarray(D)\n\n</textarea></div>\n\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        mode: {name: \"python\",\n               version: 3,\n               singleLineStringErrors: false},\n        lineNumbers: true,\n        indentUnit: 4,\n        matchBrackets: true\n    });\n\n    CodeMirror.fromTextArea(document.getElementById(\"code-cython\"), {\n        mode: {name: \"text/x-cython\",\n               version: 2,\n               singleLineStringErrors: false},\n        lineNumbers: true,\n        indentUnit: 4,\n        matchBrackets: true\n      });\n    </script>\n    <h2>Configuration Options for Python mode:</h2>\n    <ul>\n      <li>version - 2/3 - The version of Python to recognize.  Default is 2.</li>\n      <li>singleLineStringErrors - true/false - If you have a single-line string that is not terminated at the end of the line, this will show subsequent lines as errors if true, otherwise it will consider the newline as the end of the string. Default is false.</li>\n      <li>hangingIndent - int - If you want to write long arguments to a function starting on a new line, how much that line should be indented. Defaults to one normal indentation unit.</li>\n    </ul>\n    <h2>Advanced Configuration Options:</h2>\n    <p>Usefull for superset of python syntax like Enthought enaml, IPython magics and  questionmark help</p>\n    <ul>\n      <li>singleOperators - RegEx - Regular Expression for single operator matching,  default : <pre>^[\\\\+\\\\-\\\\*/%&amp;|\\\\^~&lt;&gt;!]</pre> including <pre>@</pre> on Python 3</li>\n      <li>singleDelimiters - RegEx - Regular Expression for single delimiter matching, default :  <pre>^[\\\\(\\\\)\\\\[\\\\]\\\\{\\\\}@,:`=;\\\\.]</pre></li>\n      <li>doubleOperators - RegEx - Regular Expression for double operators matching, default : <pre>^((==)|(!=)|(&lt;=)|(&gt;=)|(&lt;&gt;)|(&lt;&lt;)|(&gt;&gt;)|(//)|(\\\\*\\\\*))</pre></li>\n      <li>doubleDelimiters - RegEx - Regular Expressoin for double delimiters matching, default : <pre>^((\\\\+=)|(\\\\-=)|(\\\\*=)|(%=)|(/=)|(&amp;=)|(\\\\|=)|(\\\\^=))</pre></li>\n      <li>tripleDelimiters - RegEx - Regular Expression for triple delimiters matching, default : <pre>^((//=)|(&gt;&gt;=)|(&lt;&lt;=)|(\\\\*\\\\*=))</pre></li>\n      <li>identifiers - RegEx - Regular Expression for identifier, default : <pre>^[_A-Za-z][_A-Za-z0-9]*</pre> on Python 2 and <pre>^[_A-Za-z\\u00A1-\\uFFFF][_A-Za-z0-9\\u00A1-\\uFFFF]*</pre> on Python 3.</li>\n      <li>extra_keywords - list of string - List of extra words ton consider as keywords</li>\n      <li>extra_builtins - list of string - List of extra words ton consider as builtins</li>\n    </ul>\n\n\n    <p><strong>MIME types defined:</strong> <code>text/x-python</code> and <code>text/x-cython</code>.</p>\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/python/python.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n\n  function wordRegexp(words) {\n    return new RegExp(\"^((\" + words.join(\")|(\") + \"))\\\\b\");\n  }\n\n  var wordOperators = wordRegexp([\"and\", \"or\", \"not\", \"is\"]);\n  var commonKeywords = [\"as\", \"assert\", \"break\", \"class\", \"continue\",\n                        \"def\", \"del\", \"elif\", \"else\", \"except\", \"finally\",\n                        \"for\", \"from\", \"global\", \"if\", \"import\",\n                        \"lambda\", \"pass\", \"raise\", \"return\",\n                        \"try\", \"while\", \"with\", \"yield\", \"in\"];\n  var commonBuiltins = [\"abs\", \"all\", \"any\", \"bin\", \"bool\", \"bytearray\", \"callable\", \"chr\",\n                        \"classmethod\", \"compile\", \"complex\", \"delattr\", \"dict\", \"dir\", \"divmod\",\n                        \"enumerate\", \"eval\", \"filter\", \"float\", \"format\", \"frozenset\",\n                        \"getattr\", \"globals\", \"hasattr\", \"hash\", \"help\", \"hex\", \"id\",\n                        \"input\", \"int\", \"isinstance\", \"issubclass\", \"iter\", \"len\",\n                        \"list\", \"locals\", \"map\", \"max\", \"memoryview\", \"min\", \"next\",\n                        \"object\", \"oct\", \"open\", \"ord\", \"pow\", \"property\", \"range\",\n                        \"repr\", \"reversed\", \"round\", \"set\", \"setattr\", \"slice\",\n                        \"sorted\", \"staticmethod\", \"str\", \"sum\", \"super\", \"tuple\",\n                        \"type\", \"vars\", \"zip\", \"__import__\", \"NotImplemented\",\n                        \"Ellipsis\", \"__debug__\"];\n  var py2 = {builtins: [\"apply\", \"basestring\", \"buffer\", \"cmp\", \"coerce\", \"execfile\",\n                        \"file\", \"intern\", \"long\", \"raw_input\", \"reduce\", \"reload\",\n                        \"unichr\", \"unicode\", \"xrange\", \"False\", \"True\", \"None\"],\n             keywords: [\"exec\", \"print\"]};\n  var py3 = {builtins: [\"ascii\", \"bytes\", \"exec\", \"print\"],\n             keywords: [\"nonlocal\", \"False\", \"True\", \"None\"]};\n\n  CodeMirror.registerHelper(\"hintWords\", \"python\", commonKeywords.concat(commonBuiltins));\n\n  function top(state) {\n    return state.scopes[state.scopes.length - 1];\n  }\n\n  CodeMirror.defineMode(\"python\", function(conf, parserConf) {\n    var ERRORCLASS = \"error\";\n\n    var singleDelimiters = parserConf.singleDelimiters || new RegExp(\"^[\\\\(\\\\)\\\\[\\\\]\\\\{\\\\}@,:`=;\\\\.]\");\n    var doubleOperators = parserConf.doubleOperators || new RegExp(\"^((==)|(!=)|(<=)|(>=)|(<>)|(<<)|(>>)|(//)|(\\\\*\\\\*))\");\n    var doubleDelimiters = parserConf.doubleDelimiters || new RegExp(\"^((\\\\+=)|(\\\\-=)|(\\\\*=)|(%=)|(/=)|(&=)|(\\\\|=)|(\\\\^=))\");\n    var tripleDelimiters = parserConf.tripleDelimiters || new RegExp(\"^((//=)|(>>=)|(<<=)|(\\\\*\\\\*=))\");\n\n    if (parserConf.version && parseInt(parserConf.version, 10) == 3){\n        // since http://legacy.python.org/dev/peps/pep-0465/ @ is also an operator\n        var singleOperators = parserConf.singleOperators || new RegExp(\"^[\\\\+\\\\-\\\\*/%&|\\\\^~<>!@]\");\n        var identifiers = parserConf.identifiers|| new RegExp(\"^[_A-Za-z\\u00A1-\\uFFFF][_A-Za-z0-9\\u00A1-\\uFFFF]*\");\n    } else {\n        var singleOperators = parserConf.singleOperators || new RegExp(\"^[\\\\+\\\\-\\\\*/%&|\\\\^~<>!]\");\n        var identifiers = parserConf.identifiers|| new RegExp(\"^[_A-Za-z][_A-Za-z0-9]*\");\n    }\n\n    var hangingIndent = parserConf.hangingIndent || conf.indentUnit;\n\n    var myKeywords = commonKeywords, myBuiltins = commonBuiltins;\n    if(parserConf.extra_keywords != undefined){\n      myKeywords = myKeywords.concat(parserConf.extra_keywords);\n    }\n    if(parserConf.extra_builtins != undefined){\n      myBuiltins = myBuiltins.concat(parserConf.extra_builtins);\n    }\n    if (parserConf.version && parseInt(parserConf.version, 10) == 3) {\n      myKeywords = myKeywords.concat(py3.keywords);\n      myBuiltins = myBuiltins.concat(py3.builtins);\n      var stringPrefixes = new RegExp(\"^(([rb]|(br))?('{3}|\\\"{3}|['\\\"]))\", \"i\");\n    } else {\n      myKeywords = myKeywords.concat(py2.keywords);\n      myBuiltins = myBuiltins.concat(py2.builtins);\n      var stringPrefixes = new RegExp(\"^(([rub]|(ur)|(br))?('{3}|\\\"{3}|['\\\"]))\", \"i\");\n    }\n    var keywords = wordRegexp(myKeywords);\n    var builtins = wordRegexp(myBuiltins);\n\n    // tokenizers\n    function tokenBase(stream, state) {\n      // Handle scope changes\n      if (stream.sol() && top(state).type == \"py\") {\n        var scopeOffset = top(state).offset;\n        if (stream.eatSpace()) {\n          var lineOffset = stream.indentation();\n          if (lineOffset > scopeOffset)\n            pushScope(stream, state, \"py\");\n          else if (lineOffset < scopeOffset && dedent(stream, state))\n            state.errorToken = true;\n          return null;\n        } else {\n          var style = tokenBaseInner(stream, state);\n          if (scopeOffset > 0 && dedent(stream, state))\n            style += \" \" + ERRORCLASS;\n          return style;\n        }\n      }\n      return tokenBaseInner(stream, state);\n    }\n\n    function tokenBaseInner(stream, state) {\n      if (stream.eatSpace()) return null;\n\n      var ch = stream.peek();\n\n      // Handle Comments\n      if (ch == \"#\") {\n        stream.skipToEnd();\n        return \"comment\";\n      }\n\n      // Handle Number Literals\n      if (stream.match(/^[0-9\\.]/, false)) {\n        var floatLiteral = false;\n        // Floats\n        if (stream.match(/^\\d*\\.\\d+(e[\\+\\-]?\\d+)?/i)) { floatLiteral = true; }\n        if (stream.match(/^\\d+\\.\\d*/)) { floatLiteral = true; }\n        if (stream.match(/^\\.\\d+/)) { floatLiteral = true; }\n        if (floatLiteral) {\n          // Float literals may be \"imaginary\"\n          stream.eat(/J/i);\n          return \"number\";\n        }\n        // Integers\n        var intLiteral = false;\n        // Hex\n        if (stream.match(/^0x[0-9a-f]+/i)) intLiteral = true;\n        // Binary\n        if (stream.match(/^0b[01]+/i)) intLiteral = true;\n        // Octal\n        if (stream.match(/^0o[0-7]+/i)) intLiteral = true;\n        // Decimal\n        if (stream.match(/^[1-9]\\d*(e[\\+\\-]?\\d+)?/)) {\n          // Decimal literals may be \"imaginary\"\n          stream.eat(/J/i);\n          // TODO - Can you have imaginary longs?\n          intLiteral = true;\n        }\n        // Zero by itself with no other piece of number.\n        if (stream.match(/^0(?![\\dx])/i)) intLiteral = true;\n        if (intLiteral) {\n          // Integer literals may be \"long\"\n          stream.eat(/L/i);\n          return \"number\";\n        }\n      }\n\n      // Handle Strings\n      if (stream.match(stringPrefixes)) {\n        state.tokenize = tokenStringFactory(stream.current());\n        return state.tokenize(stream, state);\n      }\n\n      // Handle operators and Delimiters\n      if (stream.match(tripleDelimiters) || stream.match(doubleDelimiters))\n        return null;\n\n      if (stream.match(doubleOperators)\n          || stream.match(singleOperators)\n          || stream.match(wordOperators))\n        return \"operator\";\n\n      if (stream.match(singleDelimiters))\n        return null;\n\n      if (stream.match(keywords))\n        return \"keyword\";\n\n      if (stream.match(builtins))\n        return \"builtin\";\n\n      if (stream.match(/^(self|cls)\\b/))\n        return \"variable-2\";\n\n      if (stream.match(identifiers)) {\n        if (state.lastToken == \"def\" || state.lastToken == \"class\")\n          return \"def\";\n        return \"variable\";\n      }\n\n      // Handle non-detected items\n      stream.next();\n      return ERRORCLASS;\n    }\n\n    function tokenStringFactory(delimiter) {\n      while (\"rub\".indexOf(delimiter.charAt(0).toLowerCase()) >= 0)\n        delimiter = delimiter.substr(1);\n\n      var singleline = delimiter.length == 1;\n      var OUTCLASS = \"string\";\n\n      function tokenString(stream, state) {\n        while (!stream.eol()) {\n          stream.eatWhile(/[^'\"\\\\]/);\n          if (stream.eat(\"\\\\\")) {\n            stream.next();\n            if (singleline && stream.eol())\n              return OUTCLASS;\n          } else if (stream.match(delimiter)) {\n            state.tokenize = tokenBase;\n            return OUTCLASS;\n          } else {\n            stream.eat(/['\"]/);\n          }\n        }\n        if (singleline) {\n          if (parserConf.singleLineStringErrors)\n            return ERRORCLASS;\n          else\n            state.tokenize = tokenBase;\n        }\n        return OUTCLASS;\n      }\n      tokenString.isString = true;\n      return tokenString;\n    }\n\n    function pushScope(stream, state, type) {\n      var offset = 0, align = null;\n      if (type == \"py\") {\n        while (top(state).type != \"py\")\n          state.scopes.pop();\n      }\n      offset = top(state).offset + (type == \"py\" ? conf.indentUnit : hangingIndent);\n      if (type != \"py\" && !stream.match(/^(\\s|#.*)*$/, false))\n        align = stream.column() + 1;\n      state.scopes.push({offset: offset, type: type, align: align});\n    }\n\n    function dedent(stream, state) {\n      var indented = stream.indentation();\n      while (top(state).offset > indented) {\n        if (top(state).type != \"py\") return true;\n        state.scopes.pop();\n      }\n      return top(state).offset != indented;\n    }\n\n    function tokenLexer(stream, state) {\n      var style = state.tokenize(stream, state);\n      var current = stream.current();\n\n      // Handle '.' connected identifiers\n      if (current == \".\") {\n        style = stream.match(identifiers, false) ? null : ERRORCLASS;\n        if (style == null && state.lastStyle == \"meta\") {\n          // Apply 'meta' style to '.' connected identifiers when\n          // appropriate.\n          style = \"meta\";\n        }\n        return style;\n      }\n\n      // Handle decorators\n      if (current == \"@\"){\n        if(parserConf.version && parseInt(parserConf.version, 10) == 3){\n            return stream.match(identifiers, false) ? \"meta\" : \"operator\";\n        } else {\n            return stream.match(identifiers, false) ? \"meta\" : ERRORCLASS;\n        }\n      }\n\n      if ((style == \"variable\" || style == \"builtin\")\n          && state.lastStyle == \"meta\")\n        style = \"meta\";\n\n      // Handle scope changes.\n      if (current == \"pass\" || current == \"return\")\n        state.dedent += 1;\n\n      if (current == \"lambda\") state.lambda = true;\n      if (current == \":\" && !state.lambda && top(state).type == \"py\")\n        pushScope(stream, state, \"py\");\n\n      var delimiter_index = current.length == 1 ? \"[({\".indexOf(current) : -1;\n      if (delimiter_index != -1)\n        pushScope(stream, state, \"])}\".slice(delimiter_index, delimiter_index+1));\n\n      delimiter_index = \"])}\".indexOf(current);\n      if (delimiter_index != -1) {\n        if (top(state).type == current) state.scopes.pop();\n        else return ERRORCLASS;\n      }\n      if (state.dedent > 0 && stream.eol() && top(state).type == \"py\") {\n        if (state.scopes.length > 1) state.scopes.pop();\n        state.dedent -= 1;\n      }\n\n      return style;\n    }\n\n    var external = {\n      startState: function(basecolumn) {\n        return {\n          tokenize: tokenBase,\n          scopes: [{offset: basecolumn || 0, type: \"py\", align: null}],\n          lastStyle: null,\n          lastToken: null,\n          lambda: false,\n          dedent: 0\n        };\n      },\n\n      token: function(stream, state) {\n        var addErr = state.errorToken;\n        if (addErr) state.errorToken = false;\n        var style = tokenLexer(stream, state);\n\n        state.lastStyle = style;\n\n        var current = stream.current();\n        if (current && style)\n          state.lastToken = current;\n\n        if (stream.eol() && state.lambda)\n          state.lambda = false;\n        return addErr ? style + \" \" + ERRORCLASS : style;\n      },\n\n      indent: function(state, textAfter) {\n        if (state.tokenize != tokenBase)\n          return state.tokenize.isString ? CodeMirror.Pass : 0;\n\n        var scope = top(state);\n        var closing = textAfter && textAfter.charAt(0) == scope.type;\n        if (scope.align != null)\n          return scope.align - (closing ? 1 : 0);\n        else if (closing && state.scopes.length > 1)\n          return state.scopes[state.scopes.length - 2].offset;\n        else\n          return scope.offset;\n      },\n\n      lineComment: \"#\",\n      fold: \"indent\"\n    };\n    return external;\n  });\n\n  CodeMirror.defineMIME(\"text/x-python\", \"python\");\n\n  var words = function(str) { return str.split(\" \"); };\n\n  CodeMirror.defineMIME(\"text/x-cython\", {\n    name: \"python\",\n    extra_keywords: words(\"by cdef cimport cpdef ctypedef enum except\"+\n                          \"extern gil include nogil property public\"+\n                          \"readonly struct union DEF IF ELIF ELSE\")\n  });\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/q/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Q mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"../../addon/edit/matchbrackets.js\"></script>\n<script src=\"q.js\"></script>\n<style type=\"text/css\">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Q</a>\n  </ul>\n</div>\n\n<article>\n<h2>Q mode</h2>\n\n\n<div><textarea id=\"code\" name=\"code\">\n/ utilities to quickly load a csv file - for more exhaustive analysis of the csv contents see csvguess.q\n/ 2009.09.20 - updated to match latest csvguess.q \n\n/ .csv.colhdrs[file] - return a list of colhdrs from file\n/ info:.csv.info[file] - return a table of information about the file\n/ columns are: \n/\tc - column name; ci - column index; t - load type; mw - max width; \n/\tdchar - distinct characters in values; rule - rule that caught the type\n/\tmaybe - needs checking, _could_ be say a date, but perhaps just a float?\n/ .csv.info0[file;onlycols] - like .csv.info except that it only analyses <onlycols>\n/ example:\n/\tinfo:.csv.info0[file;(.csv.colhdrs file)like\"*price\"]\n/\tinfo:.csv.infolike[file;\"*price\"]\n/\tshow delete from info where t=\" \"\n/ .csv.data[file;info] - use the info from .csv.info to read the data\n/ .csv.data10[file;info] - like .csv.data but only returns the first 10 rows\n/ bulkload[file;info] - bulk loads file into table DATA (which must be already defined :: DATA:() )\n/ .csv.read[file]/read10[file] - for when you don't care about checking/tweaking the <info> before reading \n\n\\d .csv\nDELIM:\",\"\nZAPHDRS:0b / lowercase and remove _ from colhdrs (junk characters are always removed)\nWIDTHHDR:25000 / number of characters read to get the header\nREADLINES:222 / number of lines read and used to guess the types\nSYMMAXWIDTH:11 / character columns narrower than this are stored as symbols\nSYMMAXGR:10 / max symbol granularity% before we give up and keep as a * string\nFORCECHARWIDTH:30 / every field (of any type) with values this wide or more is forced to character \"*\"\nDISCARDEMPTY:0b / completely ignore empty columns if true else set them to \"C\"\nCHUNKSIZE:50000000 / used in fs2 (modified .Q.fs)\n\nk)nameltrim:{$[~@x;.z.s'x;~(*x)in aA:.Q.a,.Q.A;(+/&\\~x in aA)_x;x]}\nk)fs2:{[f;s]((-7!s)>){[f;s;x]i:1+last@&0xa=r:1:(s;x;CHUNKSIZE);f@`\\:i#r;x+i}[f;s]/0j}\ncleanhdrs:{{$[ZAPHDRS;lower x except\"_\";x]}x where x in DELIM,.Q.an}\ncancast:{nw:x$\"\";if[not x in\"BXCS\";nw:(min 0#;max 0#;::)@\\:nw];$[not any nw in x$(11&count y)#y;$[11<count y;not any nw in x$y;1b];0b]}\n\nread:{[file]data[file;info[file]]}  \nread10:{[file]data10[file;info[file]]}  \n\ncolhdrs:{[file]\n\t`$nameltrim DELIM vs cleanhdrs first read0(file;0;1+first where 0xa=read1(file;0;WIDTHHDR))}\ndata:{[file;info]\n\t(exec c from info where not t=\" \")xcol(exec t from info;enlist DELIM)0:file}\ndata10:{[file;info]\n\tdata[;info](file;0;1+last 11#where 0xa=read1(file;0;15*WIDTHHDR))}\ninfo0:{[file;onlycols]\n\tcolhdrs:`$nameltrim DELIM vs cleanhdrs first head:read0(file;0;1+last where 0xa=read1(file;0;WIDTHHDR));\n\tloadfmts:(count colhdrs)#\"S\";if[count onlycols;loadfmts[where not colhdrs in onlycols]:\"C\"];\n\tbreaks:where 0xa=read1(file;0;floor(10+READLINES)*WIDTHHDR%count head);\n\tnas:count as:colhdrs xcol(loadfmts;enlist DELIM)0:(file;0;1+last((1+READLINES)&count breaks)#breaks);\n\tinfo:([]c:key flip as;v:value flip as);as:();\n\treserved:key`.q;reserved,:.Q.res;reserved,:`i;\n\tinfo:update res:c in reserved from info;\n\tinfo:update ci:i,t:\"?\",ipa:0b,mdot:0,mw:0,rule:0,gr:0,ndv:0,maybe:0b,empty:0b,j10:0b,j12:0b from info;\n\tinfo:update ci:`s#ci from info;\n\tif[count onlycols;info:update t:\" \",rule:10 from info where not c in onlycols];\n\tinfo:update sdv:{string(distinct x)except`}peach v from info; \n\tinfo:update ndv:count each sdv from info;\n\tinfo:update gr:floor 0.5+100*ndv%nas,mw:{max count each x}peach sdv from info where 0<ndv;\n\tinfo:update t:\"*\",rule:20 from info where mw>.csv.FORCECHARWIDTH; / long values\n\tinfo:update t:\"C \"[.csv.DISCARDEMPTY],rule:30,empty:1b from info where t=\"?\",mw=0; / empty columns\n\tinfo:update dchar:{asc distinct raze x}peach sdv from info where t=\"?\";\n\tinfo:update mdot:{max sum each\".\"=x}peach sdv from info where t=\"?\",{\".\"in x}each dchar;\n\tinfo:update t:\"n\",rule:40 from info where t=\"?\",{any x in\"0123456789\"}each dchar; / vaguely numeric..\n\tinfo:update t:\"I\",rule:50,ipa:1b from info where t=\"n\",mw within 7 15,mdot=3,{all x in\".0123456789\"}each dchar,.csv.cancast[\"I\"]peach sdv; / ip-address\n\tinfo:update t:\"J\",rule:60 from info where t=\"n\",mdot=0,{all x in\"+-0123456789\"}each dchar,.csv.cancast[\"J\"]peach sdv;\n\tinfo:update t:\"I\",rule:70 from info where t=\"J\",mw<12,.csv.cancast[\"I\"]peach sdv;\n\tinfo:update t:\"H\",rule:80 from info where t=\"I\",mw<7,.csv.cancast[\"H\"]peach sdv;\n\tinfo:update t:\"F\",rule:90 from info where t=\"n\",mdot<2,mw>1,.csv.cancast[\"F\"]peach sdv;\n\tinfo:update t:\"E\",rule:100,maybe:1b from info where t=\"F\",mw<9;\n\tinfo:update t:\"M\",rule:110,maybe:1b from info where t in\"nIHEF\",mdot<2,mw within 4 7,.csv.cancast[\"M\"]peach sdv; \n\tinfo:update t:\"D\",rule:120,maybe:1b from info where t in\"nI\",mdot in 0 2,mw within 6 11,.csv.cancast[\"D\"]peach sdv; \n\tinfo:update t:\"V\",rule:130,maybe:1b from info where t=\"I\",mw in 5 6,7<count each dchar,{all x like\"*[0-9][0-5][0-9][0-5][0-9]\"}peach sdv,.csv.cancast[\"V\"]peach sdv; / 235959 12345        \n\tinfo:update t:\"U\",rule:140,maybe:1b from info where t=\"H\",mw in 3 4,7<count each dchar,{all x like\"*[0-9][0-5][0-9]\"}peach sdv,.csv.cancast[\"U\"]peach sdv; /2359\n\tinfo:update t:\"U\",rule:150,maybe:0b from info where t=\"n\",mw in 4 5,mdot=0,{all x like\"*[0-9]:[0-5][0-9]\"}peach sdv,.csv.cancast[\"U\"]peach sdv;\n\tinfo:update t:\"T\",rule:160,maybe:0b from info where t=\"n\",mw within 7 12,mdot<2,{all x like\"*[0-9]:[0-5][0-9]:[0-5][0-9]*\"}peach sdv,.csv.cancast[\"T\"]peach sdv;\n\tinfo:update t:\"V\",rule:170,maybe:0b from info where t=\"T\",mw in 7 8,mdot=0,.csv.cancast[\"V\"]peach sdv;\n\tinfo:update t:\"T\",rule:180,maybe:1b from info where t in\"EF\",mw within 7 10,mdot=1,{all x like\"*[0-9][0-5][0-9][0-5][0-9].*\"}peach sdv,.csv.cancast[\"T\"]peach sdv;\n\tinfo:update t:\"Z\",rule:190,maybe:0b from info where t=\"n\",mw within 11 24,mdot<4,.csv.cancast[\"Z\"]peach sdv;\n\tinfo:update t:\"P\",rule:200,maybe:1b from info where t=\"n\",mw within 12 29,mdot<4,{all x like\"[12]*\"}peach sdv,.csv.cancast[\"P\"]peach sdv;\n\tinfo:update t:\"N\",rule:210,maybe:1b from info where t=\"n\",mw within 3 28,mdot=1,.csv.cancast[\"N\"]peach sdv;\n\tinfo:update t:\"?\",rule:220,maybe:0b from info where t=\"n\"; / reset remaining maybe numeric\n\tinfo:update t:\"C\",rule:230,maybe:0b from info where t=\"?\",mw=1; / char\n\tinfo:update t:\"B\",rule:240,maybe:0b from info where t in\"HC\",mw=1,mdot=0,{$[all x in\"01tTfFyYnN\";(any\"0fFnN\"in x)and any\"1tTyY\"in x;0b]}each dchar; / boolean\n\tinfo:update t:\"B\",rule:250,maybe:1b from info where t in\"HC\",mw=1,mdot=0,{all x in\"01tTfFyYnN\"}each dchar; / boolean\n\tinfo:update t:\"X\",rule:260,maybe:0b from info where t=\"?\",mw=2,{$[all x in\"0123456789abcdefABCDEF\";(any .Q.n in x)and any\"abcdefABCDEF\"in x;0b]}each dchar; /hex\n\tinfo:update t:\"S\",rule:270,maybe:1b from info where t=\"?\",mw<.csv.SYMMAXWIDTH,mw>1,gr<.csv.SYMMAXGR; / symbols (max width permitting)\n\tinfo:update t:\"*\",rule:280,maybe:0b from info where t=\"?\"; / the rest as strings\n\t/ flag those S/* columns which could be encoded to integers (.Q.j10/x10/j12/x12) to avoid symbols\n\tinfo:update j12:1b from info where t in\"S*\",mw<13,{all x in .Q.nA}each dchar;\n\tinfo:update j10:1b from info where t in\"S*\",mw<11,{all x in .Q.b6}each dchar; \n\tselect c,ci,t,maybe,empty,res,j10,j12,ipa,mw,mdot,rule,gr,ndv,dchar from info}\ninfo:info0[;()] / by default don't restrict columns\ninfolike:{[file;pattern] info0[file;{x where x like y}[lower colhdrs[file];pattern]]} / .csv.infolike[file;\"*time\"]\n\n\\d .\n/ DATA:()\nbulkload:{[file;info]\n\tif[not`DATA in system\"v\";'`DATA.not.defined];\n\tif[count DATA;'`DATA.not.empty];\n\tloadhdrs:exec c from info where not t=\" \";loadfmts:exec t from info;\n\t.csv.fs2[{[file;loadhdrs;loadfmts] `DATA insert $[count DATA;flip loadhdrs!(loadfmts;.csv.DELIM)0:file;loadhdrs xcol(loadfmts;enlist .csv.DELIM)0:file]}[file;loadhdrs;loadfmts]];\n\tcount DATA}\n@[.:;\"\\\\l csvutil.custom.q\";::]; / save your custom settings in csvutil.custom.q to override those set at the beginning of the file \n</textarea></div>\n\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        lineNumbers: true,\n        matchBrackets: true\n      });\n    </script>\n\n    <p><strong>MIME type defined:</strong> <code>text/x-q</code>.</p>\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/q/q.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"q\",function(config){\n  var indentUnit=config.indentUnit,\n      curPunc,\n      keywords=buildRE([\"abs\",\"acos\",\"aj\",\"aj0\",\"all\",\"and\",\"any\",\"asc\",\"asin\",\"asof\",\"atan\",\"attr\",\"avg\",\"avgs\",\"bin\",\"by\",\"ceiling\",\"cols\",\"cor\",\"cos\",\"count\",\"cov\",\"cross\",\"csv\",\"cut\",\"delete\",\"deltas\",\"desc\",\"dev\",\"differ\",\"distinct\",\"div\",\"do\",\"each\",\"ej\",\"enlist\",\"eval\",\"except\",\"exec\",\"exit\",\"exp\",\"fby\",\"fills\",\"first\",\"fkeys\",\"flip\",\"floor\",\"from\",\"get\",\"getenv\",\"group\",\"gtime\",\"hclose\",\"hcount\",\"hdel\",\"hopen\",\"hsym\",\"iasc\",\"idesc\",\"if\",\"ij\",\"in\",\"insert\",\"inter\",\"inv\",\"key\",\"keys\",\"last\",\"like\",\"list\",\"lj\",\"load\",\"log\",\"lower\",\"lsq\",\"ltime\",\"ltrim\",\"mavg\",\"max\",\"maxs\",\"mcount\",\"md5\",\"mdev\",\"med\",\"meta\",\"min\",\"mins\",\"mmax\",\"mmin\",\"mmu\",\"mod\",\"msum\",\"neg\",\"next\",\"not\",\"null\",\"or\",\"over\",\"parse\",\"peach\",\"pj\",\"plist\",\"prd\",\"prds\",\"prev\",\"prior\",\"rand\",\"rank\",\"ratios\",\"raze\",\"read0\",\"read1\",\"reciprocal\",\"reverse\",\"rload\",\"rotate\",\"rsave\",\"rtrim\",\"save\",\"scan\",\"select\",\"set\",\"setenv\",\"show\",\"signum\",\"sin\",\"sqrt\",\"ss\",\"ssr\",\"string\",\"sublist\",\"sum\",\"sums\",\"sv\",\"system\",\"tables\",\"tan\",\"til\",\"trim\",\"txf\",\"type\",\"uj\",\"ungroup\",\"union\",\"update\",\"upper\",\"upsert\",\"value\",\"var\",\"view\",\"views\",\"vs\",\"wavg\",\"where\",\"where\",\"while\",\"within\",\"wj\",\"wj1\",\"wsum\",\"xasc\",\"xbar\",\"xcol\",\"xcols\",\"xdesc\",\"xexp\",\"xgroup\",\"xkey\",\"xlog\",\"xprev\",\"xrank\"]),\n      E=/[|/&^!+:\\\\\\-*%$=~#;@><,?_\\'\\\"\\[\\(\\]\\)\\s{}]/;\n  function buildRE(w){return new RegExp(\"^(\"+w.join(\"|\")+\")$\");}\n  function tokenBase(stream,state){\n    var sol=stream.sol(),c=stream.next();\n    curPunc=null;\n    if(sol)\n      if(c==\"/\")\n        return(state.tokenize=tokenLineComment)(stream,state);\n      else if(c==\"\\\\\"){\n        if(stream.eol()||/\\s/.test(stream.peek()))\n          return stream.skipToEnd(),/^\\\\\\s*$/.test(stream.current())?(state.tokenize=tokenCommentToEOF)(stream, state):state.tokenize=tokenBase,\"comment\";\n        else\n          return state.tokenize=tokenBase,\"builtin\";\n      }\n    if(/\\s/.test(c))\n      return stream.peek()==\"/\"?(stream.skipToEnd(),\"comment\"):\"whitespace\";\n    if(c=='\"')\n      return(state.tokenize=tokenString)(stream,state);\n    if(c=='`')\n      return stream.eatWhile(/[A-Z|a-z|\\d|_|:|\\/|\\.]/),\"symbol\";\n    if((\".\"==c&&/\\d/.test(stream.peek()))||/\\d/.test(c)){\n      var t=null;\n      stream.backUp(1);\n      if(stream.match(/^\\d{4}\\.\\d{2}(m|\\.\\d{2}([D|T](\\d{2}(:\\d{2}(:\\d{2}(\\.\\d{1,9})?)?)?)?)?)/)\n      || stream.match(/^\\d+D(\\d{2}(:\\d{2}(:\\d{2}(\\.\\d{1,9})?)?)?)/)\n      || stream.match(/^\\d{2}:\\d{2}(:\\d{2}(\\.\\d{1,9})?)?/)\n      || stream.match(/^\\d+[ptuv]{1}/))\n        t=\"temporal\";\n      else if(stream.match(/^0[NwW]{1}/)\n      || stream.match(/^0x[\\d|a-f|A-F]*/)\n      || stream.match(/^[0|1]+[b]{1}/)\n      || stream.match(/^\\d+[chijn]{1}/)\n      || stream.match(/-?\\d*(\\.\\d*)?(e[+\\-]?\\d+)?(e|f)?/))\n        t=\"number\";\n      return(t&&(!(c=stream.peek())||E.test(c)))?t:(stream.next(),\"error\");\n    }\n    if(/[A-Z|a-z]|\\./.test(c))\n      return stream.eatWhile(/[A-Z|a-z|\\.|_|\\d]/),keywords.test(stream.current())?\"keyword\":\"variable\";\n    if(/[|/&^!+:\\\\\\-*%$=~#;@><\\.,?_\\']/.test(c))\n      return null;\n    if(/[{}\\(\\[\\]\\)]/.test(c))\n      return null;\n    return\"error\";\n  }\n  function tokenLineComment(stream,state){\n    return stream.skipToEnd(),/\\/\\s*$/.test(stream.current())?(state.tokenize=tokenBlockComment)(stream,state):(state.tokenize=tokenBase),\"comment\";\n  }\n  function tokenBlockComment(stream,state){\n    var f=stream.sol()&&stream.peek()==\"\\\\\";\n    stream.skipToEnd();\n    if(f&&/^\\\\\\s*$/.test(stream.current()))\n      state.tokenize=tokenBase;\n    return\"comment\";\n  }\n  function tokenCommentToEOF(stream){return stream.skipToEnd(),\"comment\";}\n  function tokenString(stream,state){\n    var escaped=false,next,end=false;\n    while((next=stream.next())){\n      if(next==\"\\\"\"&&!escaped){end=true;break;}\n      escaped=!escaped&&next==\"\\\\\";\n    }\n    if(end)state.tokenize=tokenBase;\n    return\"string\";\n  }\n  function pushContext(state,type,col){state.context={prev:state.context,indent:state.indent,col:col,type:type};}\n  function popContext(state){state.indent=state.context.indent;state.context=state.context.prev;}\n  return{\n    startState:function(){\n      return{tokenize:tokenBase,\n             context:null,\n             indent:0,\n             col:0};\n    },\n    token:function(stream,state){\n      if(stream.sol()){\n        if(state.context&&state.context.align==null)\n          state.context.align=false;\n        state.indent=stream.indentation();\n      }\n      //if (stream.eatSpace()) return null;\n      var style=state.tokenize(stream,state);\n      if(style!=\"comment\"&&state.context&&state.context.align==null&&state.context.type!=\"pattern\"){\n        state.context.align=true;\n      }\n      if(curPunc==\"(\")pushContext(state,\")\",stream.column());\n      else if(curPunc==\"[\")pushContext(state,\"]\",stream.column());\n      else if(curPunc==\"{\")pushContext(state,\"}\",stream.column());\n      else if(/[\\]\\}\\)]/.test(curPunc)){\n        while(state.context&&state.context.type==\"pattern\")popContext(state);\n        if(state.context&&curPunc==state.context.type)popContext(state);\n      }\n      else if(curPunc==\".\"&&state.context&&state.context.type==\"pattern\")popContext(state);\n      else if(/atom|string|variable/.test(style)&&state.context){\n        if(/[\\}\\]]/.test(state.context.type))\n          pushContext(state,\"pattern\",stream.column());\n        else if(state.context.type==\"pattern\"&&!state.context.align){\n          state.context.align=true;\n          state.context.col=stream.column();\n        }\n      }\n      return style;\n    },\n    indent:function(state,textAfter){\n      var firstChar=textAfter&&textAfter.charAt(0);\n      var context=state.context;\n      if(/[\\]\\}]/.test(firstChar))\n        while (context&&context.type==\"pattern\")context=context.prev;\n      var closing=context&&firstChar==context.type;\n      if(!context)\n        return 0;\n      else if(context.type==\"pattern\")\n        return context.col;\n      else if(context.align)\n        return context.col+(closing?0:1);\n      else\n        return context.indent+(closing?0:indentUnit);\n    }\n  };\n});\nCodeMirror.defineMIME(\"text/x-q\",\"q\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/r/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: R mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"r.js\"></script>\n<style>\n      .CodeMirror { border-top: 1px solid silver; border-bottom: 1px solid silver; }\n      .cm-s-default span.cm-semi { color: blue; font-weight: bold; }\n      .cm-s-default span.cm-dollar { color: orange; font-weight: bold; }\n      .cm-s-default span.cm-arrow { color: brown; }\n      .cm-s-default span.cm-arg-is { color: brown; }\n    </style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">R</a>\n  </ul>\n</div>\n\n<article>\n<h2>R mode</h2>\n<form><textarea id=\"code\" name=\"code\">\n# Code from http://www.mayin.org/ajayshah/KB/R/\n\n# FIRST LEARN ABOUT LISTS --\nX = list(height=5.4, weight=54)\nprint(\"Use default printing --\")\nprint(X)\nprint(\"Accessing individual elements --\")\ncat(\"Your height is \", X$height, \" and your weight is \", X$weight, \"\\n\")\n\n# FUNCTIONS --\nsquare <- function(x) {\n  return(x*x)\n}\ncat(\"The square of 3 is \", square(3), \"\\n\")\n\n                 # default value of the arg is set to 5.\ncube <- function(x=5) {\n  return(x*x*x);\n}\ncat(\"Calling cube with 2 : \", cube(2), \"\\n\")    # will give 2^3\ncat(\"Calling cube        : \", cube(), \"\\n\")     # will default to 5^3.\n\n# LEARN ABOUT FUNCTIONS THAT RETURN MULTIPLE OBJECTS --\npowers <- function(x) {\n  parcel = list(x2=x*x, x3=x*x*x, x4=x*x*x*x);\n  return(parcel);\n}\n\nX = powers(3);\nprint(\"Showing powers of 3 --\"); print(X);\n\n# WRITING THIS COMPACTLY (4 lines instead of 7)\n\npowerful <- function(x) {\n  return(list(x2=x*x, x3=x*x*x, x4=x*x*x*x));\n}\nprint(\"Showing powers of 3 --\"); print(powerful(3));\n\n# In R, the last expression in a function is, by default, what is\n# returned. So you could equally just say:\npowerful <- function(x) {list(x2=x*x, x3=x*x*x, x4=x*x*x*x)}\n</textarea></form>\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {});\n    </script>\n\n    <p><strong>MIME types defined:</strong> <code>text/x-rsrc</code>.</p>\n\n    <p>Development of the CodeMirror R mode was kindly sponsored\n    by <a href=\"https://twitter.com/ubalo\">Ubalo</a>.</p>\n\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/r/r.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"r\", function(config) {\n  function wordObj(str) {\n    var words = str.split(\" \"), res = {};\n    for (var i = 0; i < words.length; ++i) res[words[i]] = true;\n    return res;\n  }\n  var atoms = wordObj(\"NULL NA Inf NaN NA_integer_ NA_real_ NA_complex_ NA_character_\");\n  var builtins = wordObj(\"list quote bquote eval return call parse deparse\");\n  var keywords = wordObj(\"if else repeat while function for in next break\");\n  var blockkeywords = wordObj(\"if else repeat while function for\");\n  var opChars = /[+\\-*\\/^<>=!&|~$:]/;\n  var curPunc;\n\n  function tokenBase(stream, state) {\n    curPunc = null;\n    var ch = stream.next();\n    if (ch == \"#\") {\n      stream.skipToEnd();\n      return \"comment\";\n    } else if (ch == \"0\" && stream.eat(\"x\")) {\n      stream.eatWhile(/[\\da-f]/i);\n      return \"number\";\n    } else if (ch == \".\" && stream.eat(/\\d/)) {\n      stream.match(/\\d*(?:e[+\\-]?\\d+)?/);\n      return \"number\";\n    } else if (/\\d/.test(ch)) {\n      stream.match(/\\d*(?:\\.\\d+)?(?:e[+\\-]\\d+)?L?/);\n      return \"number\";\n    } else if (ch == \"'\" || ch == '\"') {\n      state.tokenize = tokenString(ch);\n      return \"string\";\n    } else if (ch == \".\" && stream.match(/.[.\\d]+/)) {\n      return \"keyword\";\n    } else if (/[\\w\\.]/.test(ch) && ch != \"_\") {\n      stream.eatWhile(/[\\w\\.]/);\n      var word = stream.current();\n      if (atoms.propertyIsEnumerable(word)) return \"atom\";\n      if (keywords.propertyIsEnumerable(word)) {\n        // Block keywords start new blocks, except 'else if', which only starts\n        // one new block for the 'if', no block for the 'else'.\n        if (blockkeywords.propertyIsEnumerable(word) &&\n            !stream.match(/\\s*if(\\s+|$)/, false))\n          curPunc = \"block\";\n        return \"keyword\";\n      }\n      if (builtins.propertyIsEnumerable(word)) return \"builtin\";\n      return \"variable\";\n    } else if (ch == \"%\") {\n      if (stream.skipTo(\"%\")) stream.next();\n      return \"variable-2\";\n    } else if (ch == \"<\" && stream.eat(\"-\")) {\n      return \"arrow\";\n    } else if (ch == \"=\" && state.ctx.argList) {\n      return \"arg-is\";\n    } else if (opChars.test(ch)) {\n      if (ch == \"$\") return \"dollar\";\n      stream.eatWhile(opChars);\n      return \"operator\";\n    } else if (/[\\(\\){}\\[\\];]/.test(ch)) {\n      curPunc = ch;\n      if (ch == \";\") return \"semi\";\n      return null;\n    } else {\n      return null;\n    }\n  }\n\n  function tokenString(quote) {\n    return function(stream, state) {\n      if (stream.eat(\"\\\\\")) {\n        var ch = stream.next();\n        if (ch == \"x\") stream.match(/^[a-f0-9]{2}/i);\n        else if ((ch == \"u\" || ch == \"U\") && stream.eat(\"{\") && stream.skipTo(\"}\")) stream.next();\n        else if (ch == \"u\") stream.match(/^[a-f0-9]{4}/i);\n        else if (ch == \"U\") stream.match(/^[a-f0-9]{8}/i);\n        else if (/[0-7]/.test(ch)) stream.match(/^[0-7]{1,2}/);\n        return \"string-2\";\n      } else {\n        var next;\n        while ((next = stream.next()) != null) {\n          if (next == quote) { state.tokenize = tokenBase; break; }\n          if (next == \"\\\\\") { stream.backUp(1); break; }\n        }\n        return \"string\";\n      }\n    };\n  }\n\n  function push(state, type, stream) {\n    state.ctx = {type: type,\n                 indent: state.indent,\n                 align: null,\n                 column: stream.column(),\n                 prev: state.ctx};\n  }\n  function pop(state) {\n    state.indent = state.ctx.indent;\n    state.ctx = state.ctx.prev;\n  }\n\n  return {\n    startState: function() {\n      return {tokenize: tokenBase,\n              ctx: {type: \"top\",\n                    indent: -config.indentUnit,\n                    align: false},\n              indent: 0,\n              afterIdent: false};\n    },\n\n    token: function(stream, state) {\n      if (stream.sol()) {\n        if (state.ctx.align == null) state.ctx.align = false;\n        state.indent = stream.indentation();\n      }\n      if (stream.eatSpace()) return null;\n      var style = state.tokenize(stream, state);\n      if (style != \"comment\" && state.ctx.align == null) state.ctx.align = true;\n\n      var ctype = state.ctx.type;\n      if ((curPunc == \";\" || curPunc == \"{\" || curPunc == \"}\") && ctype == \"block\") pop(state);\n      if (curPunc == \"{\") push(state, \"}\", stream);\n      else if (curPunc == \"(\") {\n        push(state, \")\", stream);\n        if (state.afterIdent) state.ctx.argList = true;\n      }\n      else if (curPunc == \"[\") push(state, \"]\", stream);\n      else if (curPunc == \"block\") push(state, \"block\", stream);\n      else if (curPunc == ctype) pop(state);\n      state.afterIdent = style == \"variable\" || style == \"keyword\";\n      return style;\n    },\n\n    indent: function(state, textAfter) {\n      if (state.tokenize != tokenBase) return 0;\n      var firstChar = textAfter && textAfter.charAt(0), ctx = state.ctx,\n          closing = firstChar == ctx.type;\n      if (ctx.type == \"block\") return ctx.indent + (firstChar == \"{\" ? 0 : config.indentUnit);\n      else if (ctx.align) return ctx.column + (closing ? 0 : 1);\n      else return ctx.indent + (closing ? 0 : config.indentUnit);\n    },\n\n    lineComment: \"#\"\n  };\n});\n\nCodeMirror.defineMIME(\"text/x-rsrc\", \"r\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/rpm/changes/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: RPM changes mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n    <link rel=\"stylesheet\" href=\"../../../lib/codemirror.css\">\n    <script src=\"../../../lib/codemirror.js\"></script>\n    <script src=\"changes.js\"></script>\n    <link rel=\"stylesheet\" href=\"../../../doc/docs.css\">\n    <style type=\"text/css\">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>\n\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../../index.html\">Home</a>\n    <li><a href=\"../../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">RPM changes</a>\n  </ul>\n</div>\n\n<article>\n<h2>RPM changes mode</h2>\n\n    <div><textarea id=\"code\" name=\"code\">\n-------------------------------------------------------------------\nTue Oct 18 13:58:40 UTC 2011 - misterx@example.com\n\n- Update to r60.3\n- Fixes bug in the reflect package\n  * disallow Interface method on Value obtained via unexported name\n\n-------------------------------------------------------------------\nThu Oct  6 08:14:24 UTC 2011 - misterx@example.com\n\n- Update to r60.2\n- Fixes memory leak in certain map types\n\n-------------------------------------------------------------------\nWed Oct  5 14:34:10 UTC 2011 - misterx@example.com\n\n- Tweaks for gdb debugging\n- go.spec changes:\n  - move %go_arch definition to %prep section\n  - pass correct location of go specific gdb pretty printer and\n    functions to cpp as HOST_EXTRA_CFLAGS macro\n  - install go gdb functions & printer\n- gdb-printer.patch\n  - patch linker (src/cmd/ld/dwarf.c) to emit correct location of go\n    gdb functions and pretty printer\n</textarea></div>\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        mode: {name: \"changes\"},\n        lineNumbers: true,\n        indentUnit: 4\n      });\n    </script>\n\n    <p><strong>MIME types defined:</strong> <code>text/x-rpm-changes</code>.</p>\n</article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/rpm/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: RPM changes mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n    <link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n    <script src=\"../../lib/codemirror.js\"></script>\n    <script src=\"rpm.js\"></script>\n    <link rel=\"stylesheet\" href=\"../../doc/docs.css\">\n    <style type=\"text/css\">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>\n\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">RPM</a>\n  </ul>\n</div>\n\n<article>\n<h2>RPM changes mode</h2>\n\n    <div><textarea id=\"code\" name=\"code\">\n-------------------------------------------------------------------\nTue Oct 18 13:58:40 UTC 2011 - misterx@example.com\n\n- Update to r60.3\n- Fixes bug in the reflect package\n  * disallow Interface method on Value obtained via unexported name\n\n-------------------------------------------------------------------\nThu Oct  6 08:14:24 UTC 2011 - misterx@example.com\n\n- Update to r60.2\n- Fixes memory leak in certain map types\n\n-------------------------------------------------------------------\nWed Oct  5 14:34:10 UTC 2011 - misterx@example.com\n\n- Tweaks for gdb debugging\n- go.spec changes:\n  - move %go_arch definition to %prep section\n  - pass correct location of go specific gdb pretty printer and\n    functions to cpp as HOST_EXTRA_CFLAGS macro\n  - install go gdb functions & printer\n- gdb-printer.patch\n  - patch linker (src/cmd/ld/dwarf.c) to emit correct location of go\n    gdb functions and pretty printer\n</textarea></div>\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        mode: {name: \"rpm-changes\"},\n        lineNumbers: true,\n        indentUnit: 4\n      });\n    </script>\n\n<h2>RPM spec mode</h2>\n    \n    <div><textarea id=\"code2\" name=\"code2\">\n#\n# spec file for package minidlna\n#\n# Copyright (c) 2011, Sascha Peilicke <saschpe@gmx.de>\n#\n# All modifications and additions to the file contributed by third parties\n# remain the property of their copyright owners, unless otherwise agreed\n# upon. The license for this file, and modifications and additions to the\n# file, is the same license as for the pristine package itself (unless the\n# license for the pristine package is not an Open Source License, in which\n# case the license is the MIT License). An \"Open Source License\" is a\n# license that conforms to the Open Source Definition (Version 1.9)\n# published by the Open Source Initiative.\n\n\nName:           libupnp6\nVersion:        1.6.13\nRelease:        0\nSummary:        Portable Universal Plug and Play (UPnP) SDK\nGroup:          System/Libraries\nLicense:        BSD-3-Clause\nUrl:            http://sourceforge.net/projects/pupnp/\nSource0:        http://downloads.sourceforge.net/pupnp/libupnp-%{version}.tar.bz2\nBuildRoot:      %{_tmppath}/%{name}-%{version}-build\n\n%description\nThe portable Universal Plug and Play (UPnP) SDK provides support for building\nUPnP-compliant control points, devices, and bridges on several operating\nsystems.\n\n%package -n libupnp-devel\nSummary:        Portable Universal Plug and Play (UPnP) SDK\nGroup:          Development/Libraries/C and C++\nProvides:       pkgconfig(libupnp)\nRequires:       %{name} = %{version}\n\n%description -n libupnp-devel\nThe portable Universal Plug and Play (UPnP) SDK provides support for building\nUPnP-compliant control points, devices, and bridges on several operating\nsystems.\n\n%prep\n%setup -n libupnp-%{version}\n\n%build\n%configure --disable-static\nmake %{?_smp_mflags}\n\n%install\n%makeinstall\nfind %{buildroot} -type f -name '*.la' -exec rm -f {} ';'\n\n%post -p /sbin/ldconfig\n\n%postun -p /sbin/ldconfig\n\n%files\n%defattr(-,root,root,-)\n%doc ChangeLog NEWS README TODO\n%{_libdir}/libixml.so.*\n%{_libdir}/libthreadutil.so.*\n%{_libdir}/libupnp.so.*\n\n%files -n libupnp-devel\n%defattr(-,root,root,-)\n%{_libdir}/pkgconfig/libupnp.pc\n%{_libdir}/libixml.so\n%{_libdir}/libthreadutil.so\n%{_libdir}/libupnp.so\n%{_includedir}/upnp/\n\n%changelog</textarea></div>\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code2\"), {\n        mode: {name: \"rpm-spec\"},\n        lineNumbers: true,\n        indentUnit: 4\n      });\n    </script>\n\n    <p><strong>MIME types defined:</strong> <code>text/x-rpm-spec</code>, <code>text/x-rpm-changes</code>.</p>\n</article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/rpm/rpm.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"rpm-changes\", function() {\n  var headerSeperator = /^-+$/;\n  var headerLine = /^(Mon|Tue|Wed|Thu|Fri|Sat|Sun) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)  ?\\d{1,2} \\d{2}:\\d{2}(:\\d{2})? [A-Z]{3,4} \\d{4} - /;\n  var simpleEmail = /^[\\w+.-]+@[\\w.-]+/;\n\n  return {\n    token: function(stream) {\n      if (stream.sol()) {\n        if (stream.match(headerSeperator)) { return 'tag'; }\n        if (stream.match(headerLine)) { return 'tag'; }\n      }\n      if (stream.match(simpleEmail)) { return 'string'; }\n      stream.next();\n      return null;\n    }\n  };\n});\n\nCodeMirror.defineMIME(\"text/x-rpm-changes\", \"rpm-changes\");\n\n// Quick and dirty spec file highlighting\n\nCodeMirror.defineMode(\"rpm-spec\", function() {\n  var arch = /^(i386|i586|i686|x86_64|ppc64|ppc|ia64|s390x|s390|sparc64|sparcv9|sparc|noarch|alphaev6|alpha|hppa|mipsel)/;\n\n  var preamble = /^(Name|Version|Release|License|Summary|Url|Group|Source|BuildArch|BuildRequires|BuildRoot|AutoReqProv|Provides|Requires(\\(\\w+\\))?|Obsoletes|Conflicts|Recommends|Source\\d*|Patch\\d*|ExclusiveArch|NoSource|Supplements):/;\n  var section = /^%(debug_package|package|description|prep|build|install|files|clean|changelog|preinstall|preun|postinstall|postun|pre|post|triggerin|triggerun|pretrans|posttrans|verifyscript|check|triggerpostun|triggerprein|trigger)/;\n  var control_flow_complex = /^%(ifnarch|ifarch|if)/; // rpm control flow macros\n  var control_flow_simple = /^%(else|endif)/; // rpm control flow macros\n  var operators = /^(\\!|\\?|\\<\\=|\\<|\\>\\=|\\>|\\=\\=|\\&\\&|\\|\\|)/; // operators in control flow macros\n\n  return {\n    startState: function () {\n        return {\n          controlFlow: false,\n          macroParameters: false,\n          section: false\n        };\n    },\n    token: function (stream, state) {\n      var ch = stream.peek();\n      if (ch == \"#\") { stream.skipToEnd(); return \"comment\"; }\n\n      if (stream.sol()) {\n        if (stream.match(preamble)) { return \"preamble\"; }\n        if (stream.match(section)) { return \"section\"; }\n      }\n\n      if (stream.match(/^\\$\\w+/)) { return \"def\"; } // Variables like '$RPM_BUILD_ROOT'\n      if (stream.match(/^\\$\\{\\w+\\}/)) { return \"def\"; } // Variables like '${RPM_BUILD_ROOT}'\n\n      if (stream.match(control_flow_simple)) { return \"keyword\"; }\n      if (stream.match(control_flow_complex)) {\n        state.controlFlow = true;\n        return \"keyword\";\n      }\n      if (state.controlFlow) {\n        if (stream.match(operators)) { return \"operator\"; }\n        if (stream.match(/^(\\d+)/)) { return \"number\"; }\n        if (stream.eol()) { state.controlFlow = false; }\n      }\n\n      if (stream.match(arch)) { return \"number\"; }\n\n      // Macros like '%make_install' or '%attr(0775,root,root)'\n      if (stream.match(/^%[\\w]+/)) {\n        if (stream.match(/^\\(/)) { state.macroParameters = true; }\n        return \"macro\";\n      }\n      if (state.macroParameters) {\n        if (stream.match(/^\\d+/)) { return \"number\";}\n        if (stream.match(/^\\)/)) {\n          state.macroParameters = false;\n          return \"macro\";\n        }\n      }\n      if (stream.match(/^%\\{\\??[\\w \\-]+\\}/)) { return \"macro\"; } // Macros like '%{defined fedora}'\n\n      //TODO: Include bash script sub-parser (CodeMirror supports that)\n      stream.next();\n      return null;\n    }\n  };\n});\n\nCodeMirror.defineMIME(\"text/x-rpm-spec\", \"rpm-spec\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/rst/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: reStructuredText mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"../../addon/mode/overlay.js\"></script>\n<script src=\"rst.js\"></script>\n<style type=\"text/css\">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">reStructuredText</a>\n  </ul>\n</div>\n\n<article>\n<h2>reStructuredText mode</h2>\n<form><textarea id=\"code\" name=\"code\">\n.. This is an excerpt from Sphinx documentation: http://sphinx.pocoo.org/_sources/rest.txt\n\n.. highlightlang:: rest\n\n.. _rst-primer:\n\nreStructuredText Primer\n=======================\n\nThis section is a brief introduction to reStructuredText (reST) concepts and\nsyntax, intended to provide authors with enough information to author documents\nproductively.  Since reST was designed to be a simple, unobtrusive markup\nlanguage, this will not take too long.\n\n.. seealso::\n\n   The authoritative `reStructuredText User Documentation\n   &lt;http://docutils.sourceforge.net/rst.html&gt;`_.  The \"ref\" links in this\n   document link to the description of the individual constructs in the reST\n   reference.\n\n\nParagraphs\n----------\n\nThe paragraph (:duref:`ref &lt;paragraphs&gt;`) is the most basic block in a reST\ndocument.  Paragraphs are simply chunks of text separated by one or more blank\nlines.  As in Python, indentation is significant in reST, so all lines of the\nsame paragraph must be left-aligned to the same level of indentation.\n\n\n.. _inlinemarkup:\n\nInline markup\n-------------\n\nThe standard reST inline markup is quite simple: use\n\n* one asterisk: ``*text*`` for emphasis (italics),\n* two asterisks: ``**text**`` for strong emphasis (boldface), and\n* backquotes: ````text```` for code samples.\n\nIf asterisks or backquotes appear in running text and could be confused with\ninline markup delimiters, they have to be escaped with a backslash.\n\nBe aware of some restrictions of this markup:\n\n* it may not be nested,\n* content may not start or end with whitespace: ``* text*`` is wrong,\n* it must be separated from surrounding text by non-word characters.  Use a\n  backslash escaped space to work around that: ``thisis\\ *one*\\ word``.\n\nThese restrictions may be lifted in future versions of the docutils.\n\nreST also allows for custom \"interpreted text roles\"', which signify that the\nenclosed text should be interpreted in a specific way.  Sphinx uses this to\nprovide semantic markup and cross-referencing of identifiers, as described in\nthe appropriate section.  The general syntax is ``:rolename:`content```.\n\nStandard reST provides the following roles:\n\n* :durole:`emphasis` -- alternate spelling for ``*emphasis*``\n* :durole:`strong` -- alternate spelling for ``**strong**``\n* :durole:`literal` -- alternate spelling for ````literal````\n* :durole:`subscript` -- subscript text\n* :durole:`superscript` -- superscript text\n* :durole:`title-reference` -- for titles of books, periodicals, and other\n  materials\n\nSee :ref:`inline-markup` for roles added by Sphinx.\n\n\nLists and Quote-like blocks\n---------------------------\n\nList markup (:duref:`ref &lt;bullet-lists&gt;`) is natural: just place an asterisk at\nthe start of a paragraph and indent properly.  The same goes for numbered lists;\nthey can also be autonumbered using a ``#`` sign::\n\n   * This is a bulleted list.\n   * It has two items, the second\n     item uses two lines.\n\n   1. This is a numbered list.\n   2. It has two items too.\n\n   #. This is a numbered list.\n   #. It has two items too.\n\n\nNested lists are possible, but be aware that they must be separated from the\nparent list items by blank lines::\n\n   * this is\n   * a list\n\n     * with a nested list\n     * and some subitems\n\n   * and here the parent list continues\n\nDefinition lists (:duref:`ref &lt;definition-lists&gt;`) are created as follows::\n\n   term (up to a line of text)\n      Definition of the term, which must be indented\n\n      and can even consist of multiple paragraphs\n\n   next term\n      Description.\n\nNote that the term cannot have more than one line of text.\n\nQuoted paragraphs (:duref:`ref &lt;block-quotes&gt;`) are created by just indenting\nthem more than the surrounding paragraphs.\n\nLine blocks (:duref:`ref &lt;line-blocks&gt;`) are a way of preserving line breaks::\n\n   | These lines are\n   | broken exactly like in\n   | the source file.\n\nThere are also several more special blocks available:\n\n* field lists (:duref:`ref &lt;field-lists&gt;`)\n* option lists (:duref:`ref &lt;option-lists&gt;`)\n* quoted literal blocks (:duref:`ref &lt;quoted-literal-blocks&gt;`)\n* doctest blocks (:duref:`ref &lt;doctest-blocks&gt;`)\n\n\nSource Code\n-----------\n\nLiteral code blocks (:duref:`ref &lt;literal-blocks&gt;`) are introduced by ending a\nparagraph with the special marker ``::``.  The literal block must be indented\n(and, like all paragraphs, separated from the surrounding ones by blank lines)::\n\n   This is a normal text paragraph. The next paragraph is a code sample::\n\n      It is not processed in any way, except\n      that the indentation is removed.\n\n      It can span multiple lines.\n\n   This is a normal text paragraph again.\n\nThe handling of the ``::`` marker is smart:\n\n* If it occurs as a paragraph of its own, that paragraph is completely left\n  out of the document.\n* If it is preceded by whitespace, the marker is removed.\n* If it is preceded by non-whitespace, the marker is replaced by a single\n  colon.\n\nThat way, the second sentence in the above example's first paragraph would be\nrendered as \"The next paragraph is a code sample:\".\n\n\n.. _rst-tables:\n\nTables\n------\n\nTwo forms of tables are supported.  For *grid tables* (:duref:`ref\n&lt;grid-tables&gt;`), you have to \"paint\" the cell grid yourself.  They look like\nthis::\n\n   +------------------------+------------+----------+----------+\n   | Header row, column 1   | Header 2   | Header 3 | Header 4 |\n   | (header rows optional) |            |          |          |\n   +========================+============+==========+==========+\n   | body row 1, column 1   | column 2   | column 3 | column 4 |\n   +------------------------+------------+----------+----------+\n   | body row 2             | ...        | ...      |          |\n   +------------------------+------------+----------+----------+\n\n*Simple tables* (:duref:`ref &lt;simple-tables&gt;`) are easier to write, but\nlimited: they must contain more than one row, and the first column cannot\ncontain multiple lines.  They look like this::\n\n   =====  =====  =======\n   A      B      A and B\n   =====  =====  =======\n   False  False  False\n   True   False  False\n   False  True   False\n   True   True   True\n   =====  =====  =======\n\n\nHyperlinks\n----------\n\nExternal links\n^^^^^^^^^^^^^^\n\nUse ```Link text &lt;http://example.com/&gt;`_`` for inline web links.  If the link\ntext should be the web address, you don't need special markup at all, the parser\nfinds links and mail addresses in ordinary text.\n\nYou can also separate the link and the target definition (:duref:`ref\n&lt;hyperlink-targets&gt;`), like this::\n\n   This is a paragraph that contains `a link`_.\n\n   .. _a link: http://example.com/\n\n\nInternal links\n^^^^^^^^^^^^^^\n\nInternal linking is done via a special reST role provided by Sphinx, see the\nsection on specific markup, :ref:`ref-role`.\n\n\nSections\n--------\n\nSection headers (:duref:`ref &lt;sections&gt;`) are created by underlining (and\noptionally overlining) the section title with a punctuation character, at least\nas long as the text::\n\n   =================\n   This is a heading\n   =================\n\nNormally, there are no heading levels assigned to certain characters as the\nstructure is determined from the succession of headings.  However, for the\nPython documentation, this convention is used which you may follow:\n\n* ``#`` with overline, for parts\n* ``*`` with overline, for chapters\n* ``=``, for sections\n* ``-``, for subsections\n* ``^``, for subsubsections\n* ``\"``, for paragraphs\n\nOf course, you are free to use your own marker characters (see the reST\ndocumentation), and use a deeper nesting level, but keep in mind that most\ntarget formats (HTML, LaTeX) have a limited supported nesting depth.\n\n\nExplicit Markup\n---------------\n\n\"Explicit markup\" (:duref:`ref &lt;explicit-markup-blocks&gt;`) is used in reST for\nmost constructs that need special handling, such as footnotes,\nspecially-highlighted paragraphs, comments, and generic directives.\n\nAn explicit markup block begins with a line starting with ``..`` followed by\nwhitespace and is terminated by the next paragraph at the same level of\nindentation.  (There needs to be a blank line between explicit markup and normal\nparagraphs.  This may all sound a bit complicated, but it is intuitive enough\nwhen you write it.)\n\n\n.. _directives:\n\nDirectives\n----------\n\nA directive (:duref:`ref &lt;directives&gt;`) is a generic block of explicit markup.\nBesides roles, it is one of the extension mechanisms of reST, and Sphinx makes\nheavy use of it.\n\nDocutils supports the following directives:\n\n* Admonitions: :dudir:`attention`, :dudir:`caution`, :dudir:`danger`,\n  :dudir:`error`, :dudir:`hint`, :dudir:`important`, :dudir:`note`,\n  :dudir:`tip`, :dudir:`warning` and the generic :dudir:`admonition`.\n  (Most themes style only \"note\" and \"warning\" specially.)\n\n* Images:\n\n  - :dudir:`image` (see also Images_ below)\n  - :dudir:`figure` (an image with caption and optional legend)\n\n* Additional body elements:\n\n  - :dudir:`contents` (a local, i.e. for the current file only, table of\n    contents)\n  - :dudir:`container` (a container with a custom class, useful to generate an\n    outer ``&lt;div&gt;`` in HTML)\n  - :dudir:`rubric` (a heading without relation to the document sectioning)\n  - :dudir:`topic`, :dudir:`sidebar` (special highlighted body elements)\n  - :dudir:`parsed-literal` (literal block that supports inline markup)\n  - :dudir:`epigraph` (a block quote with optional attribution line)\n  - :dudir:`highlights`, :dudir:`pull-quote` (block quotes with their own\n    class attribute)\n  - :dudir:`compound` (a compound paragraph)\n\n* Special tables:\n\n  - :dudir:`table` (a table with title)\n  - :dudir:`csv-table` (a table generated from comma-separated values)\n  - :dudir:`list-table` (a table generated from a list of lists)\n\n* Special directives:\n\n  - :dudir:`raw` (include raw target-format markup)\n  - :dudir:`include` (include reStructuredText from another file)\n    -- in Sphinx, when given an absolute include file path, this directive takes\n    it as relative to the source directory\n  - :dudir:`class` (assign a class attribute to the next element) [1]_\n\n* HTML specifics:\n\n  - :dudir:`meta` (generation of HTML ``&lt;meta&gt;`` tags)\n  - :dudir:`title` (override document title)\n\n* Influencing markup:\n\n  - :dudir:`default-role` (set a new default role)\n  - :dudir:`role` (create a new role)\n\n  Since these are only per-file, better use Sphinx' facilities for setting the\n  :confval:`default_role`.\n\nDo *not* use the directives :dudir:`sectnum`, :dudir:`header` and\n:dudir:`footer`.\n\nDirectives added by Sphinx are described in :ref:`sphinxmarkup`.\n\nBasically, a directive consists of a name, arguments, options and content. (Keep\nthis terminology in mind, it is used in the next chapter describing custom\ndirectives.)  Looking at this example, ::\n\n   .. function:: foo(x)\n                 foo(y, z)\n      :module: some.module.name\n\n      Return a line of text input from the user.\n\n``function`` is the directive name.  It is given two arguments here, the\nremainder of the first line and the second line, as well as one option\n``module`` (as you can see, options are given in the lines immediately following\nthe arguments and indicated by the colons).  Options must be indented to the\nsame level as the directive content.\n\nThe directive content follows after a blank line and is indented relative to the\ndirective start.\n\n\nImages\n------\n\nreST supports an image directive (:dudir:`ref &lt;image&gt;`), used like so::\n\n   .. image:: gnu.png\n      (options)\n\nWhen used within Sphinx, the file name given (here ``gnu.png``) must either be\nrelative to the source file, or absolute which means that they are relative to\nthe top source directory.  For example, the file ``sketch/spam.rst`` could refer\nto the image ``images/spam.png`` as ``../images/spam.png`` or\n``/images/spam.png``.\n\nSphinx will automatically copy image files over to a subdirectory of the output\ndirectory on building (e.g. the ``_static`` directory for HTML output.)\n\nInterpretation of image size options (``width`` and ``height``) is as follows:\nif the size has no unit or the unit is pixels, the given size will only be\nrespected for output channels that support pixels (i.e. not in LaTeX output).\nOther units (like ``pt`` for points) will be used for HTML and LaTeX output.\n\nSphinx extends the standard docutils behavior by allowing an asterisk for the\nextension::\n\n   .. image:: gnu.*\n\nSphinx then searches for all images matching the provided pattern and determines\ntheir type.  Each builder then chooses the best image out of these candidates.\nFor instance, if the file name ``gnu.*`` was given and two files :file:`gnu.pdf`\nand :file:`gnu.png` existed in the source tree, the LaTeX builder would choose\nthe former, while the HTML builder would prefer the latter.\n\n.. versionchanged:: 0.4\n   Added the support for file names ending in an asterisk.\n\n.. versionchanged:: 0.6\n   Image paths can now be absolute.\n\n\nFootnotes\n---------\n\nFor footnotes (:duref:`ref &lt;footnotes&gt;`), use ``[#name]_`` to mark the footnote\nlocation, and add the footnote body at the bottom of the document after a\n\"Footnotes\" rubric heading, like so::\n\n   Lorem ipsum [#f1]_ dolor sit amet ... [#f2]_\n\n   .. rubric:: Footnotes\n\n   .. [#f1] Text of the first footnote.\n   .. [#f2] Text of the second footnote.\n\nYou can also explicitly number the footnotes (``[1]_``) or use auto-numbered\nfootnotes without names (``[#]_``).\n\n\nCitations\n---------\n\nStandard reST citations (:duref:`ref &lt;citations&gt;`) are supported, with the\nadditional feature that they are \"global\", i.e. all citations can be referenced\nfrom all files.  Use them like so::\n\n   Lorem ipsum [Ref]_ dolor sit amet.\n\n   .. [Ref] Book or article reference, URL or whatever.\n\nCitation usage is similar to footnote usage, but with a label that is not\nnumeric or begins with ``#``.\n\n\nSubstitutions\n-------------\n\nreST supports \"substitutions\" (:duref:`ref &lt;substitution-definitions&gt;`), which\nare pieces of text and/or markup referred to in the text by ``|name|``.  They\nare defined like footnotes with explicit markup blocks, like this::\n\n   .. |name| replace:: replacement *text*\n\nor this::\n\n   .. |caution| image:: warning.png\n                :alt: Warning!\n\nSee the :duref:`reST reference for substitutions &lt;substitution-definitions&gt;`\nfor details.\n\nIf you want to use some substitutions for all documents, put them into\n:confval:`rst_prolog` or put them into a separate file and include it into all\ndocuments you want to use them in, using the :rst:dir:`include` directive.  (Be\nsure to give the include file a file name extension differing from that of other\nsource files, to avoid Sphinx finding it as a standalone document.)\n\nSphinx defines some default substitutions, see :ref:`default-substitutions`.\n\n\nComments\n--------\n\nEvery explicit markup block which isn't a valid markup construct (like the\nfootnotes above) is regarded as a comment (:duref:`ref &lt;comments&gt;`).  For\nexample::\n\n   .. This is a comment.\n\nYou can indent text after a comment start to form multiline comments::\n\n   ..\n      This whole indented block\n      is a comment.\n\n      Still in the comment.\n\n\nSource encoding\n---------------\n\nSince the easiest way to include special characters like em dashes or copyright\nsigns in reST is to directly write them as Unicode characters, one has to\nspecify an encoding.  Sphinx assumes source files to be encoded in UTF-8 by\ndefault; you can change this with the :confval:`source_encoding` config value.\n\n\nGotchas\n-------\n\nThere are some problems one commonly runs into while authoring reST documents:\n\n* **Separation of inline markup:** As said above, inline markup spans must be\n  separated from the surrounding text by non-word characters, you have to use a\n  backslash-escaped space to get around that.  See `the reference\n  &lt;http://docutils.sf.net/docs/ref/rst/restructuredtext.html#inline-markup&gt;`_\n  for the details.\n\n* **No nested inline markup:** Something like ``*see :func:`foo`*`` is not\n  possible.\n\n\n.. rubric:: Footnotes\n\n.. [1] When the default domain contains a :rst:dir:`class` directive, this directive\n       will be shadowed.  Therefore, Sphinx re-exports it as :rst:dir:`rst-class`.\n</textarea></form>\n\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        lineNumbers: true,\n      });\n    </script>\n    <p>\n        The <code>python</code> mode will be used for highlighting blocks\n        containing Python/IPython terminal sessions: blocks starting with\n        <code>&gt;&gt;&gt;</code> (for Python) or <code>In [num]:</code> (for\n        IPython).\n\n        Further, the <code>stex</code> mode will be used for highlighting\n        blocks containing LaTex code.\n    </p>\n\n    <p><strong>MIME types defined:</strong> <code>text/x-rst</code>.</p>\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/rst/rst.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"), require(\"../python/python\"), require(\"../stex/stex\"), require(\"../../addon/mode/overlay\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\", \"../python/python\", \"../stex/stex\", \"../../addon/mode/overlay\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode('rst', function (config, options) {\n\n  var rx_strong = /^\\*\\*[^\\*\\s](?:[^\\*]*[^\\*\\s])?\\*\\*/;\n  var rx_emphasis = /^\\*[^\\*\\s](?:[^\\*]*[^\\*\\s])?\\*/;\n  var rx_literal = /^``[^`\\s](?:[^`]*[^`\\s])``/;\n\n  var rx_number = /^(?:[\\d]+(?:[\\.,]\\d+)*)/;\n  var rx_positive = /^(?:\\s\\+[\\d]+(?:[\\.,]\\d+)*)/;\n  var rx_negative = /^(?:\\s\\-[\\d]+(?:[\\.,]\\d+)*)/;\n\n  var rx_uri_protocol = \"[Hh][Tt][Tt][Pp][Ss]?://\";\n  var rx_uri_domain = \"(?:[\\\\d\\\\w.-]+)\\\\.(?:\\\\w{2,6})\";\n  var rx_uri_path = \"(?:/[\\\\d\\\\w\\\\#\\\\%\\\\&\\\\-\\\\.\\\\,\\\\/\\\\:\\\\=\\\\?\\\\~]+)*\";\n  var rx_uri = new RegExp(\"^\" + rx_uri_protocol + rx_uri_domain + rx_uri_path);\n\n  var overlay = {\n    token: function (stream) {\n\n      if (stream.match(rx_strong) && stream.match (/\\W+|$/, false))\n        return 'strong';\n      if (stream.match(rx_emphasis) && stream.match (/\\W+|$/, false))\n        return 'em';\n      if (stream.match(rx_literal) && stream.match (/\\W+|$/, false))\n        return 'string-2';\n      if (stream.match(rx_number))\n        return 'number';\n      if (stream.match(rx_positive))\n        return 'positive';\n      if (stream.match(rx_negative))\n        return 'negative';\n      if (stream.match(rx_uri))\n        return 'link';\n\n      while (stream.next() != null) {\n        if (stream.match(rx_strong, false)) break;\n        if (stream.match(rx_emphasis, false)) break;\n        if (stream.match(rx_literal, false)) break;\n        if (stream.match(rx_number, false)) break;\n        if (stream.match(rx_positive, false)) break;\n        if (stream.match(rx_negative, false)) break;\n        if (stream.match(rx_uri, false)) break;\n      }\n\n      return null;\n    }\n  };\n\n  var mode = CodeMirror.getMode(\n    config, options.backdrop || 'rst-base'\n  );\n\n  return CodeMirror.overlayMode(mode, overlay, true); // combine\n}, 'python', 'stex');\n\n///////////////////////////////////////////////////////////////////////////////\n///////////////////////////////////////////////////////////////////////////////\n\nCodeMirror.defineMode('rst-base', function (config) {\n\n  ///////////////////////////////////////////////////////////////////////////\n  ///////////////////////////////////////////////////////////////////////////\n\n  function format(string) {\n    var args = Array.prototype.slice.call(arguments, 1);\n    return string.replace(/{(\\d+)}/g, function (match, n) {\n      return typeof args[n] != 'undefined' ? args[n] : match;\n    });\n  }\n\n  ///////////////////////////////////////////////////////////////////////////\n  ///////////////////////////////////////////////////////////////////////////\n\n  var mode_python = CodeMirror.getMode(config, 'python');\n  var mode_stex = CodeMirror.getMode(config, 'stex');\n\n  ///////////////////////////////////////////////////////////////////////////\n  ///////////////////////////////////////////////////////////////////////////\n\n  var SEPA = \"\\\\s+\";\n  var TAIL = \"(?:\\\\s*|\\\\W|$)\",\n  rx_TAIL = new RegExp(format('^{0}', TAIL));\n\n  var NAME =\n    \"(?:[^\\\\W\\\\d_](?:[\\\\w!\\\"#$%&'()\\\\*\\\\+,\\\\-\\\\.\\/:;<=>\\\\?]*[^\\\\W_])?)\",\n  rx_NAME = new RegExp(format('^{0}', NAME));\n  var NAME_WWS =\n    \"(?:[^\\\\W\\\\d_](?:[\\\\w\\\\s!\\\"#$%&'()\\\\*\\\\+,\\\\-\\\\.\\/:;<=>\\\\?]*[^\\\\W_])?)\";\n  var REF_NAME = format('(?:{0}|`{1}`)', NAME, NAME_WWS);\n\n  var TEXT1 = \"(?:[^\\\\s\\\\|](?:[^\\\\|]*[^\\\\s\\\\|])?)\";\n  var TEXT2 = \"(?:[^\\\\`]+)\",\n  rx_TEXT2 = new RegExp(format('^{0}', TEXT2));\n\n  var rx_section = new RegExp(\n    \"^([!'#$%&\\\"()*+,-./:;<=>?@\\\\[\\\\\\\\\\\\]^_`{|}~])\\\\1{3,}\\\\s*$\");\n  var rx_explicit = new RegExp(\n    format('^\\\\.\\\\.{0}', SEPA));\n  var rx_link = new RegExp(\n    format('^_{0}:{1}|^__:{1}', REF_NAME, TAIL));\n  var rx_directive = new RegExp(\n    format('^{0}::{1}', REF_NAME, TAIL));\n  var rx_substitution = new RegExp(\n    format('^\\\\|{0}\\\\|{1}{2}::{3}', TEXT1, SEPA, REF_NAME, TAIL));\n  var rx_footnote = new RegExp(\n    format('^\\\\[(?:\\\\d+|#{0}?|\\\\*)]{1}', REF_NAME, TAIL));\n  var rx_citation = new RegExp(\n    format('^\\\\[{0}\\\\]{1}', REF_NAME, TAIL));\n\n  var rx_substitution_ref = new RegExp(\n    format('^\\\\|{0}\\\\|', TEXT1));\n  var rx_footnote_ref = new RegExp(\n    format('^\\\\[(?:\\\\d+|#{0}?|\\\\*)]_', REF_NAME));\n  var rx_citation_ref = new RegExp(\n    format('^\\\\[{0}\\\\]_', REF_NAME));\n  var rx_link_ref1 = new RegExp(\n    format('^{0}__?', REF_NAME));\n  var rx_link_ref2 = new RegExp(\n    format('^`{0}`_', TEXT2));\n\n  var rx_role_pre = new RegExp(\n    format('^:{0}:`{1}`{2}', NAME, TEXT2, TAIL));\n  var rx_role_suf = new RegExp(\n    format('^`{1}`:{0}:{2}', NAME, TEXT2, TAIL));\n  var rx_role = new RegExp(\n    format('^:{0}:{1}', NAME, TAIL));\n\n  var rx_directive_name = new RegExp(format('^{0}', REF_NAME));\n  var rx_directive_tail = new RegExp(format('^::{0}', TAIL));\n  var rx_substitution_text = new RegExp(format('^\\\\|{0}\\\\|', TEXT1));\n  var rx_substitution_sepa = new RegExp(format('^{0}', SEPA));\n  var rx_substitution_name = new RegExp(format('^{0}', REF_NAME));\n  var rx_substitution_tail = new RegExp(format('^::{0}', TAIL));\n  var rx_link_head = new RegExp(\"^_\");\n  var rx_link_name = new RegExp(format('^{0}|_', REF_NAME));\n  var rx_link_tail = new RegExp(format('^:{0}', TAIL));\n\n  var rx_verbatim = new RegExp('^::\\\\s*$');\n  var rx_examples = new RegExp('^\\\\s+(?:>>>|In \\\\[\\\\d+\\\\]:)\\\\s');\n\n  ///////////////////////////////////////////////////////////////////////////\n  ///////////////////////////////////////////////////////////////////////////\n\n  function to_normal(stream, state) {\n    var token = null;\n\n    if (stream.sol() && stream.match(rx_examples, false)) {\n      change(state, to_mode, {\n        mode: mode_python, local: CodeMirror.startState(mode_python)\n      });\n    } else if (stream.sol() && stream.match(rx_explicit)) {\n      change(state, to_explicit);\n      token = 'meta';\n    } else if (stream.sol() && stream.match(rx_section)) {\n      change(state, to_normal);\n      token = 'header';\n    } else if (phase(state) == rx_role_pre ||\n               stream.match(rx_role_pre, false)) {\n\n      switch (stage(state)) {\n      case 0:\n        change(state, to_normal, context(rx_role_pre, 1));\n        stream.match(/^:/);\n        token = 'meta';\n        break;\n      case 1:\n        change(state, to_normal, context(rx_role_pre, 2));\n        stream.match(rx_NAME);\n        token = 'keyword';\n\n        if (stream.current().match(/^(?:math|latex)/)) {\n          state.tmp_stex = true;\n        }\n        break;\n      case 2:\n        change(state, to_normal, context(rx_role_pre, 3));\n        stream.match(/^:`/);\n        token = 'meta';\n        break;\n      case 3:\n        if (state.tmp_stex) {\n          state.tmp_stex = undefined; state.tmp = {\n            mode: mode_stex, local: CodeMirror.startState(mode_stex)\n          };\n        }\n\n        if (state.tmp) {\n          if (stream.peek() == '`') {\n            change(state, to_normal, context(rx_role_pre, 4));\n            state.tmp = undefined;\n            break;\n          }\n\n          token = state.tmp.mode.token(stream, state.tmp.local);\n          break;\n        }\n\n        change(state, to_normal, context(rx_role_pre, 4));\n        stream.match(rx_TEXT2);\n        token = 'string';\n        break;\n      case 4:\n        change(state, to_normal, context(rx_role_pre, 5));\n        stream.match(/^`/);\n        token = 'meta';\n        break;\n      case 5:\n        change(state, to_normal, context(rx_role_pre, 6));\n        stream.match(rx_TAIL);\n        break;\n      default:\n        change(state, to_normal);\n      }\n    } else if (phase(state) == rx_role_suf ||\n               stream.match(rx_role_suf, false)) {\n\n      switch (stage(state)) {\n      case 0:\n        change(state, to_normal, context(rx_role_suf, 1));\n        stream.match(/^`/);\n        token = 'meta';\n        break;\n      case 1:\n        change(state, to_normal, context(rx_role_suf, 2));\n        stream.match(rx_TEXT2);\n        token = 'string';\n        break;\n      case 2:\n        change(state, to_normal, context(rx_role_suf, 3));\n        stream.match(/^`:/);\n        token = 'meta';\n        break;\n      case 3:\n        change(state, to_normal, context(rx_role_suf, 4));\n        stream.match(rx_NAME);\n        token = 'keyword';\n        break;\n      case 4:\n        change(state, to_normal, context(rx_role_suf, 5));\n        stream.match(/^:/);\n        token = 'meta';\n        break;\n      case 5:\n        change(state, to_normal, context(rx_role_suf, 6));\n        stream.match(rx_TAIL);\n        break;\n      default:\n        change(state, to_normal);\n      }\n    } else if (phase(state) == rx_role || stream.match(rx_role, false)) {\n\n      switch (stage(state)) {\n      case 0:\n        change(state, to_normal, context(rx_role, 1));\n        stream.match(/^:/);\n        token = 'meta';\n        break;\n      case 1:\n        change(state, to_normal, context(rx_role, 2));\n        stream.match(rx_NAME);\n        token = 'keyword';\n        break;\n      case 2:\n        change(state, to_normal, context(rx_role, 3));\n        stream.match(/^:/);\n        token = 'meta';\n        break;\n      case 3:\n        change(state, to_normal, context(rx_role, 4));\n        stream.match(rx_TAIL);\n        break;\n      default:\n        change(state, to_normal);\n      }\n    } else if (phase(state) == rx_substitution_ref ||\n               stream.match(rx_substitution_ref, false)) {\n\n      switch (stage(state)) {\n      case 0:\n        change(state, to_normal, context(rx_substitution_ref, 1));\n        stream.match(rx_substitution_text);\n        token = 'variable-2';\n        break;\n      case 1:\n        change(state, to_normal, context(rx_substitution_ref, 2));\n        if (stream.match(/^_?_?/)) token = 'link';\n        break;\n      default:\n        change(state, to_normal);\n      }\n    } else if (stream.match(rx_footnote_ref)) {\n      change(state, to_normal);\n      token = 'quote';\n    } else if (stream.match(rx_citation_ref)) {\n      change(state, to_normal);\n      token = 'quote';\n    } else if (stream.match(rx_link_ref1)) {\n      change(state, to_normal);\n      if (!stream.peek() || stream.peek().match(/^\\W$/)) {\n        token = 'link';\n      }\n    } else if (phase(state) == rx_link_ref2 ||\n               stream.match(rx_link_ref2, false)) {\n\n      switch (stage(state)) {\n      case 0:\n        if (!stream.peek() || stream.peek().match(/^\\W$/)) {\n          change(state, to_normal, context(rx_link_ref2, 1));\n        } else {\n          stream.match(rx_link_ref2);\n        }\n        break;\n      case 1:\n        change(state, to_normal, context(rx_link_ref2, 2));\n        stream.match(/^`/);\n        token = 'link';\n        break;\n      case 2:\n        change(state, to_normal, context(rx_link_ref2, 3));\n        stream.match(rx_TEXT2);\n        break;\n      case 3:\n        change(state, to_normal, context(rx_link_ref2, 4));\n        stream.match(/^`_/);\n        token = 'link';\n        break;\n      default:\n        change(state, to_normal);\n      }\n    } else if (stream.match(rx_verbatim)) {\n      change(state, to_verbatim);\n    }\n\n    else {\n      if (stream.next()) change(state, to_normal);\n    }\n\n    return token;\n  }\n\n  ///////////////////////////////////////////////////////////////////////////\n  ///////////////////////////////////////////////////////////////////////////\n\n  function to_explicit(stream, state) {\n    var token = null;\n\n    if (phase(state) == rx_substitution ||\n        stream.match(rx_substitution, false)) {\n\n      switch (stage(state)) {\n      case 0:\n        change(state, to_explicit, context(rx_substitution, 1));\n        stream.match(rx_substitution_text);\n        token = 'variable-2';\n        break;\n      case 1:\n        change(state, to_explicit, context(rx_substitution, 2));\n        stream.match(rx_substitution_sepa);\n        break;\n      case 2:\n        change(state, to_explicit, context(rx_substitution, 3));\n        stream.match(rx_substitution_name);\n        token = 'keyword';\n        break;\n      case 3:\n        change(state, to_explicit, context(rx_substitution, 4));\n        stream.match(rx_substitution_tail);\n        token = 'meta';\n        break;\n      default:\n        change(state, to_normal);\n      }\n    } else if (phase(state) == rx_directive ||\n               stream.match(rx_directive, false)) {\n\n      switch (stage(state)) {\n      case 0:\n        change(state, to_explicit, context(rx_directive, 1));\n        stream.match(rx_directive_name);\n        token = 'keyword';\n\n        if (stream.current().match(/^(?:math|latex)/))\n          state.tmp_stex = true;\n        else if (stream.current().match(/^python/))\n          state.tmp_py = true;\n        break;\n      case 1:\n        change(state, to_explicit, context(rx_directive, 2));\n        stream.match(rx_directive_tail);\n        token = 'meta';\n\n        if (stream.match(/^latex\\s*$/) || state.tmp_stex) {\n          state.tmp_stex = undefined; change(state, to_mode, {\n            mode: mode_stex, local: CodeMirror.startState(mode_stex)\n          });\n        }\n        break;\n      case 2:\n        change(state, to_explicit, context(rx_directive, 3));\n        if (stream.match(/^python\\s*$/) || state.tmp_py) {\n          state.tmp_py = undefined; change(state, to_mode, {\n            mode: mode_python, local: CodeMirror.startState(mode_python)\n          });\n        }\n        break;\n      default:\n        change(state, to_normal);\n      }\n    } else if (phase(state) == rx_link || stream.match(rx_link, false)) {\n\n      switch (stage(state)) {\n      case 0:\n        change(state, to_explicit, context(rx_link, 1));\n        stream.match(rx_link_head);\n        stream.match(rx_link_name);\n        token = 'link';\n        break;\n      case 1:\n        change(state, to_explicit, context(rx_link, 2));\n        stream.match(rx_link_tail);\n        token = 'meta';\n        break;\n      default:\n        change(state, to_normal);\n      }\n    } else if (stream.match(rx_footnote)) {\n      change(state, to_normal);\n      token = 'quote';\n    } else if (stream.match(rx_citation)) {\n      change(state, to_normal);\n      token = 'quote';\n    }\n\n    else {\n      stream.eatSpace();\n      if (stream.eol()) {\n        change(state, to_normal);\n      } else {\n        stream.skipToEnd();\n        change(state, to_comment);\n        token = 'comment';\n      }\n    }\n\n    return token;\n  }\n\n  ///////////////////////////////////////////////////////////////////////////\n  ///////////////////////////////////////////////////////////////////////////\n\n  function to_comment(stream, state) {\n    return as_block(stream, state, 'comment');\n  }\n\n  function to_verbatim(stream, state) {\n    return as_block(stream, state, 'meta');\n  }\n\n  function as_block(stream, state, token) {\n    if (stream.eol() || stream.eatSpace()) {\n      stream.skipToEnd();\n      return token;\n    } else {\n      change(state, to_normal);\n      return null;\n    }\n  }\n\n  ///////////////////////////////////////////////////////////////////////////\n  ///////////////////////////////////////////////////////////////////////////\n\n  function to_mode(stream, state) {\n\n    if (state.ctx.mode && state.ctx.local) {\n\n      if (stream.sol()) {\n        if (!stream.eatSpace()) change(state, to_normal);\n        return null;\n      }\n\n      return state.ctx.mode.token(stream, state.ctx.local);\n    }\n\n    change(state, to_normal);\n    return null;\n  }\n\n  ///////////////////////////////////////////////////////////////////////////\n  ///////////////////////////////////////////////////////////////////////////\n\n  function context(phase, stage, mode, local) {\n    return {phase: phase, stage: stage, mode: mode, local: local};\n  }\n\n  function change(state, tok, ctx) {\n    state.tok = tok;\n    state.ctx = ctx || {};\n  }\n\n  function stage(state) {\n    return state.ctx.stage || 0;\n  }\n\n  function phase(state) {\n    return state.ctx.phase;\n  }\n\n  ///////////////////////////////////////////////////////////////////////////\n  ///////////////////////////////////////////////////////////////////////////\n\n  return {\n    startState: function () {\n      return {tok: to_normal, ctx: context(undefined, 0)};\n    },\n\n    copyState: function (state) {\n      var ctx = state.ctx, tmp = state.tmp;\n      if (ctx.local)\n        ctx = {mode: ctx.mode, local: CodeMirror.copyState(ctx.mode, ctx.local)};\n      if (tmp)\n        tmp = {mode: tmp.mode, local: CodeMirror.copyState(tmp.mode, tmp.local)};\n      return {tok: state.tok, ctx: ctx, tmp: tmp};\n    },\n\n    innerMode: function (state) {\n      return state.tmp      ? {state: state.tmp.local, mode: state.tmp.mode}\n      : state.ctx.mode ? {state: state.ctx.local, mode: state.ctx.mode}\n      : null;\n    },\n\n    token: function (stream, state) {\n      return state.tok(stream, state);\n    }\n  };\n}, 'python', 'stex');\n\n///////////////////////////////////////////////////////////////////////////////\n///////////////////////////////////////////////////////////////////////////////\n\nCodeMirror.defineMIME('text/x-rst', 'rst');\n\n///////////////////////////////////////////////////////////////////////////////\n///////////////////////////////////////////////////////////////////////////////\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/ruby/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Ruby mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"../../addon/edit/matchbrackets.js\"></script>\n<script src=\"ruby.js\"></script>\n<style>\n      .CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}\n      .cm-s-default span.cm-arrow { color: red; }\n    </style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Ruby</a>\n  </ul>\n</div>\n\n<article>\n<h2>Ruby mode</h2>\n<form><textarea id=\"code\" name=\"code\">\n# Code from http://sandbox.mc.edu/~bennet/ruby/code/poly_rb.html\n#\n# This program evaluates polynomials.  It first asks for the coefficients\n# of a polynomial, which must be entered on one line, highest-order first.\n# It then requests values of x and will compute the value of the poly for\n# each x.  It will repeatly ask for x values, unless you the user enters\n# a blank line.  It that case, it will ask for another polynomial.  If the\n# user types quit for either input, the program immediately exits.\n#\n\n#\n# Function to evaluate a polynomial at x.  The polynomial is given\n# as a list of coefficients, from the greatest to the least.\ndef polyval(x, coef)\n    sum = 0\n    coef = coef.clone           # Don't want to destroy the original\n    while true\n        sum += coef.shift       # Add and remove the next coef\n        break if coef.empty?    # If no more, done entirely.\n        sum *= x                # This happens the right number of times.\n    end\n    return sum\nend\n\n#\n# Function to read a line containing a list of integers and return\n# them as an array of integers.  If the string conversion fails, it\n# throws TypeError.  If the input line is the word 'quit', then it\n# converts it to an end-of-file exception\ndef readints(prompt)\n    # Read a line\n    print prompt\n    line = readline.chomp\n    raise EOFError.new if line == 'quit' # You can also use a real EOF.\n            \n    # Go through each item on the line, converting each one and adding it\n    # to retval.\n    retval = [ ]\n    for str in line.split(/\\s+/)\n        if str =~ /^\\-?\\d+$/\n            retval.push(str.to_i)\n        else\n            raise TypeError.new\n        end\n    end\n\n    return retval\nend\n\n#\n# Take a coeff and an exponent and return the string representation, ignoring\n# the sign of the coefficient.\ndef term_to_str(coef, exp)\n    ret = \"\"\n\n    # Show coeff, unless it's 1 or at the right\n    coef = coef.abs\n    ret = coef.to_s     unless coef == 1 && exp > 0\n    ret += \"x\" if exp > 0                               # x if exponent not 0\n    ret += \"^\" + exp.to_s if exp > 1                    # ^exponent, if > 1.\n\n    return ret\nend\n\n#\n# Create a string of the polynomial in sort-of-readable form.\ndef polystr(p)\n    # Get the exponent of first coefficient, plus 1.\n    exp = p.length\n\n    # Assign exponents to each term, making pairs of coeff and exponent,\n    # Then get rid of the zero terms.\n    p = (p.map { |c| exp -= 1; [ c, exp ] }).select { |p| p[0] != 0 }\n\n    # If there's nothing left, it's a zero\n    return \"0\" if p.empty?\n\n    # *** Now p is a non-empty list of [ coef, exponent ] pairs. ***\n\n    # Convert the first term, preceded by a \"-\" if it's negative.\n    result = (if p[0][0] < 0 then \"-\" else \"\" end) + term_to_str(*p[0])\n\n    # Convert the rest of the terms, in each case adding the appropriate\n    # + or - separating them.  \n    for term in p[1...p.length]\n        # Add the separator then the rep. of the term.\n        result += (if term[0] < 0 then \" - \" else \" + \" end) + \n                term_to_str(*term)\n    end\n\n    return result\nend\n        \n#\n# Run until some kind of endfile.\nbegin\n    # Repeat until an exception or quit gets us out.\n    while true\n        # Read a poly until it works.  An EOF will except out of the\n        # program.\n        print \"\\n\"\n        begin\n            poly = readints(\"Enter a polynomial coefficients: \")\n        rescue TypeError\n            print \"Try again.\\n\"\n            retry\n        end\n        break if poly.empty?\n\n        # Read and evaluate x values until the user types a blank line.\n        # Again, an EOF will except out of the pgm.\n        while true\n            # Request an integer.\n            print \"Enter x value or blank line: \"\n            x = readline.chomp\n            break if x == ''\n            raise EOFError.new if x == 'quit'\n\n            # If it looks bad, let's try again.\n            if x !~ /^\\-?\\d+$/\n                print \"That doesn't look like an integer.  Please try again.\\n\"\n                next\n            end\n\n            # Convert to an integer and print the result.\n            x = x.to_i\n            print \"p(x) = \", polystr(poly), \"\\n\"\n            print \"p(\", x, \") = \", polyval(x, poly), \"\\n\"\n        end\n    end\nrescue EOFError\n    print \"\\n=== EOF ===\\n\"\nrescue Interrupt, SignalException\n    print \"\\n=== Interrupted ===\\n\"\nelse\n    print \"--- Bye ---\\n\"\nend\n</textarea></form>\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        mode: \"text/x-ruby\",\n        matchBrackets: true,\n        indentUnit: 4\n      });\n    </script>\n\n    <p><strong>MIME types defined:</strong> <code>text/x-ruby</code>.</p>\n\n    <p>Development of the CodeMirror Ruby mode was kindly sponsored\n    by <a href=\"http://ubalo.com/\">Ubalo</a>.</p>\n\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/ruby/ruby.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"ruby\", function(config) {\n  function wordObj(words) {\n    var o = {};\n    for (var i = 0, e = words.length; i < e; ++i) o[words[i]] = true;\n    return o;\n  }\n  var keywords = wordObj([\n    \"alias\", \"and\", \"BEGIN\", \"begin\", \"break\", \"case\", \"class\", \"def\", \"defined?\", \"do\", \"else\",\n    \"elsif\", \"END\", \"end\", \"ensure\", \"false\", \"for\", \"if\", \"in\", \"module\", \"next\", \"not\", \"or\",\n    \"redo\", \"rescue\", \"retry\", \"return\", \"self\", \"super\", \"then\", \"true\", \"undef\", \"unless\",\n    \"until\", \"when\", \"while\", \"yield\", \"nil\", \"raise\", \"throw\", \"catch\", \"fail\", \"loop\", \"callcc\",\n    \"caller\", \"lambda\", \"proc\", \"public\", \"protected\", \"private\", \"require\", \"load\",\n    \"require_relative\", \"extend\", \"autoload\", \"__END__\", \"__FILE__\", \"__LINE__\", \"__dir__\"\n  ]);\n  var indentWords = wordObj([\"def\", \"class\", \"case\", \"for\", \"while\", \"module\", \"then\",\n                             \"catch\", \"loop\", \"proc\", \"begin\"]);\n  var dedentWords = wordObj([\"end\", \"until\"]);\n  var matching = {\"[\": \"]\", \"{\": \"}\", \"(\": \")\"};\n  var curPunc;\n\n  function chain(newtok, stream, state) {\n    state.tokenize.push(newtok);\n    return newtok(stream, state);\n  }\n\n  function tokenBase(stream, state) {\n    curPunc = null;\n    if (stream.sol() && stream.match(\"=begin\") && stream.eol()) {\n      state.tokenize.push(readBlockComment);\n      return \"comment\";\n    }\n    if (stream.eatSpace()) return null;\n    var ch = stream.next(), m;\n    if (ch == \"`\" || ch == \"'\" || ch == '\"') {\n      return chain(readQuoted(ch, \"string\", ch == '\"' || ch == \"`\"), stream, state);\n    } else if (ch == \"/\") {\n      var currentIndex = stream.current().length;\n      if (stream.skipTo(\"/\")) {\n        var search_till = stream.current().length;\n        stream.backUp(stream.current().length - currentIndex);\n        var balance = 0;  // balance brackets\n        while (stream.current().length < search_till) {\n          var chchr = stream.next();\n          if (chchr == \"(\") balance += 1;\n          else if (chchr == \")\") balance -= 1;\n          if (balance < 0) break;\n        }\n        stream.backUp(stream.current().length - currentIndex);\n        if (balance == 0)\n          return chain(readQuoted(ch, \"string-2\", true), stream, state);\n      }\n      return \"operator\";\n    } else if (ch == \"%\") {\n      var style = \"string\", embed = true;\n      if (stream.eat(\"s\")) style = \"atom\";\n      else if (stream.eat(/[WQ]/)) style = \"string\";\n      else if (stream.eat(/[r]/)) style = \"string-2\";\n      else if (stream.eat(/[wxq]/)) { style = \"string\"; embed = false; }\n      var delim = stream.eat(/[^\\w\\s=]/);\n      if (!delim) return \"operator\";\n      if (matching.propertyIsEnumerable(delim)) delim = matching[delim];\n      return chain(readQuoted(delim, style, embed, true), stream, state);\n    } else if (ch == \"#\") {\n      stream.skipToEnd();\n      return \"comment\";\n    } else if (ch == \"<\" && (m = stream.match(/^<-?[\\`\\\"\\']?([a-zA-Z_?]\\w*)[\\`\\\"\\']?(?:;|$)/))) {\n      return chain(readHereDoc(m[1]), stream, state);\n    } else if (ch == \"0\") {\n      if (stream.eat(\"x\")) stream.eatWhile(/[\\da-fA-F]/);\n      else if (stream.eat(\"b\")) stream.eatWhile(/[01]/);\n      else stream.eatWhile(/[0-7]/);\n      return \"number\";\n    } else if (/\\d/.test(ch)) {\n      stream.match(/^[\\d_]*(?:\\.[\\d_]+)?(?:[eE][+\\-]?[\\d_]+)?/);\n      return \"number\";\n    } else if (ch == \"?\") {\n      while (stream.match(/^\\\\[CM]-/)) {}\n      if (stream.eat(\"\\\\\")) stream.eatWhile(/\\w/);\n      else stream.next();\n      return \"string\";\n    } else if (ch == \":\") {\n      if (stream.eat(\"'\")) return chain(readQuoted(\"'\", \"atom\", false), stream, state);\n      if (stream.eat('\"')) return chain(readQuoted('\"', \"atom\", true), stream, state);\n\n      // :> :>> :< :<< are valid symbols\n      if (stream.eat(/[\\<\\>]/)) {\n        stream.eat(/[\\<\\>]/);\n        return \"atom\";\n      }\n\n      // :+ :- :/ :* :| :& :! are valid symbols\n      if (stream.eat(/[\\+\\-\\*\\/\\&\\|\\:\\!]/)) {\n        return \"atom\";\n      }\n\n      // Symbols can't start by a digit\n      if (stream.eat(/[a-zA-Z$@_\\xa1-\\uffff]/)) {\n        stream.eatWhile(/[\\w$\\xa1-\\uffff]/);\n        // Only one ? ! = is allowed and only as the last character\n        stream.eat(/[\\?\\!\\=]/);\n        return \"atom\";\n      }\n      return \"operator\";\n    } else if (ch == \"@\" && stream.match(/^@?[a-zA-Z_\\xa1-\\uffff]/)) {\n      stream.eat(\"@\");\n      stream.eatWhile(/[\\w\\xa1-\\uffff]/);\n      return \"variable-2\";\n    } else if (ch == \"$\") {\n      if (stream.eat(/[a-zA-Z_]/)) {\n        stream.eatWhile(/[\\w]/);\n      } else if (stream.eat(/\\d/)) {\n        stream.eat(/\\d/);\n      } else {\n        stream.next(); // Must be a special global like $: or $!\n      }\n      return \"variable-3\";\n    } else if (/[a-zA-Z_\\xa1-\\uffff]/.test(ch)) {\n      stream.eatWhile(/[\\w\\xa1-\\uffff]/);\n      stream.eat(/[\\?\\!]/);\n      if (stream.eat(\":\")) return \"atom\";\n      return \"ident\";\n    } else if (ch == \"|\" && (state.varList || state.lastTok == \"{\" || state.lastTok == \"do\")) {\n      curPunc = \"|\";\n      return null;\n    } else if (/[\\(\\)\\[\\]{}\\\\;]/.test(ch)) {\n      curPunc = ch;\n      return null;\n    } else if (ch == \"-\" && stream.eat(\">\")) {\n      return \"arrow\";\n    } else if (/[=+\\-\\/*:\\.^%<>~|]/.test(ch)) {\n      var more = stream.eatWhile(/[=+\\-\\/*:\\.^%<>~|]/);\n      if (ch == \".\" && !more) curPunc = \".\";\n      return \"operator\";\n    } else {\n      return null;\n    }\n  }\n\n  function tokenBaseUntilBrace(depth) {\n    if (!depth) depth = 1;\n    return function(stream, state) {\n      if (stream.peek() == \"}\") {\n        if (depth == 1) {\n          state.tokenize.pop();\n          return state.tokenize[state.tokenize.length-1](stream, state);\n        } else {\n          state.tokenize[state.tokenize.length - 1] = tokenBaseUntilBrace(depth - 1);\n        }\n      } else if (stream.peek() == \"{\") {\n        state.tokenize[state.tokenize.length - 1] = tokenBaseUntilBrace(depth + 1);\n      }\n      return tokenBase(stream, state);\n    };\n  }\n  function tokenBaseOnce() {\n    var alreadyCalled = false;\n    return function(stream, state) {\n      if (alreadyCalled) {\n        state.tokenize.pop();\n        return state.tokenize[state.tokenize.length-1](stream, state);\n      }\n      alreadyCalled = true;\n      return tokenBase(stream, state);\n    };\n  }\n  function readQuoted(quote, style, embed, unescaped) {\n    return function(stream, state) {\n      var escaped = false, ch;\n\n      if (state.context.type === 'read-quoted-paused') {\n        state.context = state.context.prev;\n        stream.eat(\"}\");\n      }\n\n      while ((ch = stream.next()) != null) {\n        if (ch == quote && (unescaped || !escaped)) {\n          state.tokenize.pop();\n          break;\n        }\n        if (embed && ch == \"#\" && !escaped) {\n          if (stream.eat(\"{\")) {\n            if (quote == \"}\") {\n              state.context = {prev: state.context, type: 'read-quoted-paused'};\n            }\n            state.tokenize.push(tokenBaseUntilBrace());\n            break;\n          } else if (/[@\\$]/.test(stream.peek())) {\n            state.tokenize.push(tokenBaseOnce());\n            break;\n          }\n        }\n        escaped = !escaped && ch == \"\\\\\";\n      }\n      return style;\n    };\n  }\n  function readHereDoc(phrase) {\n    return function(stream, state) {\n      if (stream.match(phrase)) state.tokenize.pop();\n      else stream.skipToEnd();\n      return \"string\";\n    };\n  }\n  function readBlockComment(stream, state) {\n    if (stream.sol() && stream.match(\"=end\") && stream.eol())\n      state.tokenize.pop();\n    stream.skipToEnd();\n    return \"comment\";\n  }\n\n  return {\n    startState: function() {\n      return {tokenize: [tokenBase],\n              indented: 0,\n              context: {type: \"top\", indented: -config.indentUnit},\n              continuedLine: false,\n              lastTok: null,\n              varList: false};\n    },\n\n    token: function(stream, state) {\n      if (stream.sol()) state.indented = stream.indentation();\n      var style = state.tokenize[state.tokenize.length-1](stream, state), kwtype;\n      var thisTok = curPunc;\n      if (style == \"ident\") {\n        var word = stream.current();\n        style = state.lastTok == \".\" ? \"property\"\n          : keywords.propertyIsEnumerable(stream.current()) ? \"keyword\"\n          : /^[A-Z]/.test(word) ? \"tag\"\n          : (state.lastTok == \"def\" || state.lastTok == \"class\" || state.varList) ? \"def\"\n          : \"variable\";\n        if (style == \"keyword\") {\n          thisTok = word;\n          if (indentWords.propertyIsEnumerable(word)) kwtype = \"indent\";\n          else if (dedentWords.propertyIsEnumerable(word)) kwtype = \"dedent\";\n          else if ((word == \"if\" || word == \"unless\") && stream.column() == stream.indentation())\n            kwtype = \"indent\";\n          else if (word == \"do\" && state.context.indented < state.indented)\n            kwtype = \"indent\";\n        }\n      }\n      if (curPunc || (style && style != \"comment\")) state.lastTok = thisTok;\n      if (curPunc == \"|\") state.varList = !state.varList;\n\n      if (kwtype == \"indent\" || /[\\(\\[\\{]/.test(curPunc))\n        state.context = {prev: state.context, type: curPunc || style, indented: state.indented};\n      else if ((kwtype == \"dedent\" || /[\\)\\]\\}]/.test(curPunc)) && state.context.prev)\n        state.context = state.context.prev;\n\n      if (stream.eol())\n        state.continuedLine = (curPunc == \"\\\\\" || style == \"operator\");\n      return style;\n    },\n\n    indent: function(state, textAfter) {\n      if (state.tokenize[state.tokenize.length-1] != tokenBase) return 0;\n      var firstChar = textAfter && textAfter.charAt(0);\n      var ct = state.context;\n      var closing = ct.type == matching[firstChar] ||\n        ct.type == \"keyword\" && /^(?:end|until|else|elsif|when|rescue)\\b/.test(textAfter);\n      return ct.indented + (closing ? 0 : config.indentUnit) +\n        (state.continuedLine ? config.indentUnit : 0);\n    },\n\n    electricChars: \"}de\", // enD and rescuE\n    lineComment: \"#\"\n  };\n});\n\nCodeMirror.defineMIME(\"text/x-ruby\", \"ruby\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/ruby/test.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function() {\n  var mode = CodeMirror.getMode({indentUnit: 2}, \"ruby\");\n  function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); }\n\n  MT(\"divide_equal_operator\",\n     \"[variable bar] [operator /=] [variable foo]\");\n\n  MT(\"divide_equal_operator_no_spacing\",\n     \"[variable foo][operator /=][number 42]\");\n\n})();\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/rust/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Rust mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"rust.js\"></script>\n<style type=\"text/css\">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Rust</a>\n  </ul>\n</div>\n\n<article>\n<h2>Rust mode</h2>\n\n\n<div><textarea id=\"code\" name=\"code\">\n// Demo code.\n\ntype foo<T> = int;\nenum bar {\n    some(int, foo<float>),\n    none\n}\n\nfn check_crate(x: int) {\n    let v = 10;\n    alt foo {\n      1 to 3 {\n        print_foo();\n        if x {\n            blah() + 10;\n        }\n      }\n      (x, y) { \"bye\" }\n      _ { \"hi\" }\n    }\n}\n</textarea></div>\n\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        lineNumbers: true\n      });\n    </script>\n\n    <p><strong>MIME types defined:</strong> <code>text/x-rustsrc</code>.</p>\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/rust/rust.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"rust\", function() {\n  var indentUnit = 4, altIndentUnit = 2;\n  var valKeywords = {\n    \"if\": \"if-style\", \"while\": \"if-style\", \"loop\": \"else-style\", \"else\": \"else-style\",\n    \"do\": \"else-style\", \"ret\": \"else-style\", \"fail\": \"else-style\",\n    \"break\": \"atom\", \"cont\": \"atom\", \"const\": \"let\", \"resource\": \"fn\",\n    \"let\": \"let\", \"fn\": \"fn\", \"for\": \"for\", \"alt\": \"alt\", \"iface\": \"iface\",\n    \"impl\": \"impl\", \"type\": \"type\", \"enum\": \"enum\", \"mod\": \"mod\",\n    \"as\": \"op\", \"true\": \"atom\", \"false\": \"atom\", \"assert\": \"op\", \"check\": \"op\",\n    \"claim\": \"op\", \"native\": \"ignore\", \"unsafe\": \"ignore\", \"import\": \"else-style\",\n    \"export\": \"else-style\", \"copy\": \"op\", \"log\": \"op\", \"log_err\": \"op\",\n    \"use\": \"op\", \"bind\": \"op\", \"self\": \"atom\", \"struct\": \"enum\"\n  };\n  var typeKeywords = function() {\n    var keywords = {\"fn\": \"fn\", \"block\": \"fn\", \"obj\": \"obj\"};\n    var atoms = \"bool uint int i8 i16 i32 i64 u8 u16 u32 u64 float f32 f64 str char\".split(\" \");\n    for (var i = 0, e = atoms.length; i < e; ++i) keywords[atoms[i]] = \"atom\";\n    return keywords;\n  }();\n  var operatorChar = /[+\\-*&%=<>!?|\\.@]/;\n\n  // Tokenizer\n\n  // Used as scratch variable to communicate multiple values without\n  // consing up tons of objects.\n  var tcat, content;\n  function r(tc, style) {\n    tcat = tc;\n    return style;\n  }\n\n  function tokenBase(stream, state) {\n    var ch = stream.next();\n    if (ch == '\"') {\n      state.tokenize = tokenString;\n      return state.tokenize(stream, state);\n    }\n    if (ch == \"'\") {\n      tcat = \"atom\";\n      if (stream.eat(\"\\\\\")) {\n        if (stream.skipTo(\"'\")) { stream.next(); return \"string\"; }\n        else { return \"error\"; }\n      } else {\n        stream.next();\n        return stream.eat(\"'\") ? \"string\" : \"error\";\n      }\n    }\n    if (ch == \"/\") {\n      if (stream.eat(\"/\")) { stream.skipToEnd(); return \"comment\"; }\n      if (stream.eat(\"*\")) {\n        state.tokenize = tokenComment(1);\n        return state.tokenize(stream, state);\n      }\n    }\n    if (ch == \"#\") {\n      if (stream.eat(\"[\")) { tcat = \"open-attr\"; return null; }\n      stream.eatWhile(/\\w/);\n      return r(\"macro\", \"meta\");\n    }\n    if (ch == \":\" && stream.match(\":<\")) {\n      return r(\"op\", null);\n    }\n    if (ch.match(/\\d/) || (ch == \".\" && stream.eat(/\\d/))) {\n      var flp = false;\n      if (!stream.match(/^x[\\da-f]+/i) && !stream.match(/^b[01]+/)) {\n        stream.eatWhile(/\\d/);\n        if (stream.eat(\".\")) { flp = true; stream.eatWhile(/\\d/); }\n        if (stream.match(/^e[+\\-]?\\d+/i)) { flp = true; }\n      }\n      if (flp) stream.match(/^f(?:32|64)/);\n      else stream.match(/^[ui](?:8|16|32|64)/);\n      return r(\"atom\", \"number\");\n    }\n    if (ch.match(/[()\\[\\]{}:;,]/)) return r(ch, null);\n    if (ch == \"-\" && stream.eat(\">\")) return r(\"->\", null);\n    if (ch.match(operatorChar)) {\n      stream.eatWhile(operatorChar);\n      return r(\"op\", null);\n    }\n    stream.eatWhile(/\\w/);\n    content = stream.current();\n    if (stream.match(/^::\\w/)) {\n      stream.backUp(1);\n      return r(\"prefix\", \"variable-2\");\n    }\n    if (state.keywords.propertyIsEnumerable(content))\n      return r(state.keywords[content], content.match(/true|false/) ? \"atom\" : \"keyword\");\n    return r(\"name\", \"variable\");\n  }\n\n  function tokenString(stream, state) {\n    var ch, escaped = false;\n    while (ch = stream.next()) {\n      if (ch == '\"' && !escaped) {\n        state.tokenize = tokenBase;\n        return r(\"atom\", \"string\");\n      }\n      escaped = !escaped && ch == \"\\\\\";\n    }\n    // Hack to not confuse the parser when a string is split in\n    // pieces.\n    return r(\"op\", \"string\");\n  }\n\n  function tokenComment(depth) {\n    return function(stream, state) {\n      var lastCh = null, ch;\n      while (ch = stream.next()) {\n        if (ch == \"/\" && lastCh == \"*\") {\n          if (depth == 1) {\n            state.tokenize = tokenBase;\n            break;\n          } else {\n            state.tokenize = tokenComment(depth - 1);\n            return state.tokenize(stream, state);\n          }\n        }\n        if (ch == \"*\" && lastCh == \"/\") {\n          state.tokenize = tokenComment(depth + 1);\n          return state.tokenize(stream, state);\n        }\n        lastCh = ch;\n      }\n      return \"comment\";\n    };\n  }\n\n  // Parser\n\n  var cx = {state: null, stream: null, marked: null, cc: null};\n  function pass() {\n    for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]);\n  }\n  function cont() {\n    pass.apply(null, arguments);\n    return true;\n  }\n\n  function pushlex(type, info) {\n    var result = function() {\n      var state = cx.state;\n      state.lexical = {indented: state.indented, column: cx.stream.column(),\n                       type: type, prev: state.lexical, info: info};\n    };\n    result.lex = true;\n    return result;\n  }\n  function poplex() {\n    var state = cx.state;\n    if (state.lexical.prev) {\n      if (state.lexical.type == \")\")\n        state.indented = state.lexical.indented;\n      state.lexical = state.lexical.prev;\n    }\n  }\n  function typecx() { cx.state.keywords = typeKeywords; }\n  function valcx() { cx.state.keywords = valKeywords; }\n  poplex.lex = typecx.lex = valcx.lex = true;\n\n  function commasep(comb, end) {\n    function more(type) {\n      if (type == \",\") return cont(comb, more);\n      if (type == end) return cont();\n      return cont(more);\n    }\n    return function(type) {\n      if (type == end) return cont();\n      return pass(comb, more);\n    };\n  }\n\n  function stat_of(comb, tag) {\n    return cont(pushlex(\"stat\", tag), comb, poplex, block);\n  }\n  function block(type) {\n    if (type == \"}\") return cont();\n    if (type == \"let\") return stat_of(letdef1, \"let\");\n    if (type == \"fn\") return stat_of(fndef);\n    if (type == \"type\") return cont(pushlex(\"stat\"), tydef, endstatement, poplex, block);\n    if (type == \"enum\") return stat_of(enumdef);\n    if (type == \"mod\") return stat_of(mod);\n    if (type == \"iface\") return stat_of(iface);\n    if (type == \"impl\") return stat_of(impl);\n    if (type == \"open-attr\") return cont(pushlex(\"]\"), commasep(expression, \"]\"), poplex);\n    if (type == \"ignore\" || type.match(/[\\]\\);,]/)) return cont(block);\n    return pass(pushlex(\"stat\"), expression, poplex, endstatement, block);\n  }\n  function endstatement(type) {\n    if (type == \";\") return cont();\n    return pass();\n  }\n  function expression(type) {\n    if (type == \"atom\" || type == \"name\") return cont(maybeop);\n    if (type == \"{\") return cont(pushlex(\"}\"), exprbrace, poplex);\n    if (type.match(/[\\[\\(]/)) return matchBrackets(type, expression);\n    if (type.match(/[\\]\\)\\};,]/)) return pass();\n    if (type == \"if-style\") return cont(expression, expression);\n    if (type == \"else-style\" || type == \"op\") return cont(expression);\n    if (type == \"for\") return cont(pattern, maybetype, inop, expression, expression);\n    if (type == \"alt\") return cont(expression, altbody);\n    if (type == \"fn\") return cont(fndef);\n    if (type == \"macro\") return cont(macro);\n    return cont();\n  }\n  function maybeop(type) {\n    if (content == \".\") return cont(maybeprop);\n    if (content == \"::<\"){return cont(typarams, maybeop);}\n    if (type == \"op\" || content == \":\") return cont(expression);\n    if (type == \"(\" || type == \"[\") return matchBrackets(type, expression);\n    return pass();\n  }\n  function maybeprop() {\n    if (content.match(/^\\w+$/)) {cx.marked = \"variable\"; return cont(maybeop);}\n    return pass(expression);\n  }\n  function exprbrace(type) {\n    if (type == \"op\") {\n      if (content == \"|\") return cont(blockvars, poplex, pushlex(\"}\", \"block\"), block);\n      if (content == \"||\") return cont(poplex, pushlex(\"}\", \"block\"), block);\n    }\n    if (content == \"mutable\" || (content.match(/^\\w+$/) && cx.stream.peek() == \":\"\n                                 && !cx.stream.match(\"::\", false)))\n      return pass(record_of(expression));\n    return pass(block);\n  }\n  function record_of(comb) {\n    function ro(type) {\n      if (content == \"mutable\" || content == \"with\") {cx.marked = \"keyword\"; return cont(ro);}\n      if (content.match(/^\\w*$/)) {cx.marked = \"variable\"; return cont(ro);}\n      if (type == \":\") return cont(comb, ro);\n      if (type == \"}\") return cont();\n      return cont(ro);\n    }\n    return ro;\n  }\n  function blockvars(type) {\n    if (type == \"name\") {cx.marked = \"def\"; return cont(blockvars);}\n    if (type == \"op\" && content == \"|\") return cont();\n    return cont(blockvars);\n  }\n\n  function letdef1(type) {\n    if (type.match(/[\\]\\)\\};]/)) return cont();\n    if (content == \"=\") return cont(expression, letdef2);\n    if (type == \",\") return cont(letdef1);\n    return pass(pattern, maybetype, letdef1);\n  }\n  function letdef2(type) {\n    if (type.match(/[\\]\\)\\};,]/)) return pass(letdef1);\n    else return pass(expression, letdef2);\n  }\n  function maybetype(type) {\n    if (type == \":\") return cont(typecx, rtype, valcx);\n    return pass();\n  }\n  function inop(type) {\n    if (type == \"name\" && content == \"in\") {cx.marked = \"keyword\"; return cont();}\n    return pass();\n  }\n  function fndef(type) {\n    if (content == \"@\" || content == \"~\") {cx.marked = \"keyword\"; return cont(fndef);}\n    if (type == \"name\") {cx.marked = \"def\"; return cont(fndef);}\n    if (content == \"<\") return cont(typarams, fndef);\n    if (type == \"{\") return pass(expression);\n    if (type == \"(\") return cont(pushlex(\")\"), commasep(argdef, \")\"), poplex, fndef);\n    if (type == \"->\") return cont(typecx, rtype, valcx, fndef);\n    if (type == \";\") return cont();\n    return cont(fndef);\n  }\n  function tydef(type) {\n    if (type == \"name\") {cx.marked = \"def\"; return cont(tydef);}\n    if (content == \"<\") return cont(typarams, tydef);\n    if (content == \"=\") return cont(typecx, rtype, valcx);\n    return cont(tydef);\n  }\n  function enumdef(type) {\n    if (type == \"name\") {cx.marked = \"def\"; return cont(enumdef);}\n    if (content == \"<\") return cont(typarams, enumdef);\n    if (content == \"=\") return cont(typecx, rtype, valcx, endstatement);\n    if (type == \"{\") return cont(pushlex(\"}\"), typecx, enumblock, valcx, poplex);\n    return cont(enumdef);\n  }\n  function enumblock(type) {\n    if (type == \"}\") return cont();\n    if (type == \"(\") return cont(pushlex(\")\"), commasep(rtype, \")\"), poplex, enumblock);\n    if (content.match(/^\\w+$/)) cx.marked = \"def\";\n    return cont(enumblock);\n  }\n  function mod(type) {\n    if (type == \"name\") {cx.marked = \"def\"; return cont(mod);}\n    if (type == \"{\") return cont(pushlex(\"}\"), block, poplex);\n    return pass();\n  }\n  function iface(type) {\n    if (type == \"name\") {cx.marked = \"def\"; return cont(iface);}\n    if (content == \"<\") return cont(typarams, iface);\n    if (type == \"{\") return cont(pushlex(\"}\"), block, poplex);\n    return pass();\n  }\n  function impl(type) {\n    if (content == \"<\") return cont(typarams, impl);\n    if (content == \"of\" || content == \"for\") {cx.marked = \"keyword\"; return cont(rtype, impl);}\n    if (type == \"name\") {cx.marked = \"def\"; return cont(impl);}\n    if (type == \"{\") return cont(pushlex(\"}\"), block, poplex);\n    return pass();\n  }\n  function typarams() {\n    if (content == \">\") return cont();\n    if (content == \",\") return cont(typarams);\n    if (content == \":\") return cont(rtype, typarams);\n    return pass(rtype, typarams);\n  }\n  function argdef(type) {\n    if (type == \"name\") {cx.marked = \"def\"; return cont(argdef);}\n    if (type == \":\") return cont(typecx, rtype, valcx);\n    return pass();\n  }\n  function rtype(type) {\n    if (type == \"name\") {cx.marked = \"variable-3\"; return cont(rtypemaybeparam); }\n    if (content == \"mutable\") {cx.marked = \"keyword\"; return cont(rtype);}\n    if (type == \"atom\") return cont(rtypemaybeparam);\n    if (type == \"op\" || type == \"obj\") return cont(rtype);\n    if (type == \"fn\") return cont(fntype);\n    if (type == \"{\") return cont(pushlex(\"{\"), record_of(rtype), poplex);\n    return matchBrackets(type, rtype);\n  }\n  function rtypemaybeparam() {\n    if (content == \"<\") return cont(typarams);\n    return pass();\n  }\n  function fntype(type) {\n    if (type == \"(\") return cont(pushlex(\"(\"), commasep(rtype, \")\"), poplex, fntype);\n    if (type == \"->\") return cont(rtype);\n    return pass();\n  }\n  function pattern(type) {\n    if (type == \"name\") {cx.marked = \"def\"; return cont(patternmaybeop);}\n    if (type == \"atom\") return cont(patternmaybeop);\n    if (type == \"op\") return cont(pattern);\n    if (type.match(/[\\]\\)\\};,]/)) return pass();\n    return matchBrackets(type, pattern);\n  }\n  function patternmaybeop(type) {\n    if (type == \"op\" && content == \".\") return cont();\n    if (content == \"to\") {cx.marked = \"keyword\"; return cont(pattern);}\n    else return pass();\n  }\n  function altbody(type) {\n    if (type == \"{\") return cont(pushlex(\"}\", \"alt\"), altblock1, poplex);\n    return pass();\n  }\n  function altblock1(type) {\n    if (type == \"}\") return cont();\n    if (type == \"|\") return cont(altblock1);\n    if (content == \"when\") {cx.marked = \"keyword\"; return cont(expression, altblock2);}\n    if (type.match(/[\\]\\);,]/)) return cont(altblock1);\n    return pass(pattern, altblock2);\n  }\n  function altblock2(type) {\n    if (type == \"{\") return cont(pushlex(\"}\", \"alt\"), block, poplex, altblock1);\n    else return pass(altblock1);\n  }\n\n  function macro(type) {\n    if (type.match(/[\\[\\(\\{]/)) return matchBrackets(type, expression);\n    return pass();\n  }\n  function matchBrackets(type, comb) {\n    if (type == \"[\") return cont(pushlex(\"]\"), commasep(comb, \"]\"), poplex);\n    if (type == \"(\") return cont(pushlex(\")\"), commasep(comb, \")\"), poplex);\n    if (type == \"{\") return cont(pushlex(\"}\"), commasep(comb, \"}\"), poplex);\n    return cont();\n  }\n\n  function parse(state, stream, style) {\n    var cc = state.cc;\n    // Communicate our context to the combinators.\n    // (Less wasteful than consing up a hundred closures on every call.)\n    cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc;\n\n    while (true) {\n      var combinator = cc.length ? cc.pop() : block;\n      if (combinator(tcat)) {\n        while(cc.length && cc[cc.length - 1].lex)\n          cc.pop()();\n        return cx.marked || style;\n      }\n    }\n  }\n\n  return {\n    startState: function() {\n      return {\n        tokenize: tokenBase,\n        cc: [],\n        lexical: {indented: -indentUnit, column: 0, type: \"top\", align: false},\n        keywords: valKeywords,\n        indented: 0\n      };\n    },\n\n    token: function(stream, state) {\n      if (stream.sol()) {\n        if (!state.lexical.hasOwnProperty(\"align\"))\n          state.lexical.align = false;\n        state.indented = stream.indentation();\n      }\n      if (stream.eatSpace()) return null;\n      tcat = content = null;\n      var style = state.tokenize(stream, state);\n      if (style == \"comment\") return style;\n      if (!state.lexical.hasOwnProperty(\"align\"))\n        state.lexical.align = true;\n      if (tcat == \"prefix\") return style;\n      if (!content) content = stream.current();\n      return parse(state, stream, style);\n    },\n\n    indent: function(state, textAfter) {\n      if (state.tokenize != tokenBase) return 0;\n      var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical,\n          type = lexical.type, closing = firstChar == type;\n      if (type == \"stat\") return lexical.indented + indentUnit;\n      if (lexical.align) return lexical.column + (closing ? 0 : 1);\n      return lexical.indented + (closing ? 0 : (lexical.info == \"alt\" ? altIndentUnit : indentUnit));\n    },\n\n    electricChars: \"{}\",\n    blockCommentStart: \"/*\",\n    blockCommentEnd: \"*/\",\n    lineComment: \"//\",\n    fold: \"brace\"\n  };\n});\n\nCodeMirror.defineMIME(\"text/x-rustsrc\", \"rust\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/sass/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Sass mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"../../addon/edit/matchbrackets.js\"></script>\n<script src=\"sass.js\"></script>\n<style>.CodeMirror {border: 1px solid #ddd; font-size:12px; height: 400px}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Sass</a>\n  </ul>\n</div>\n\n<article>\n<h2>Sass mode</h2>\n<form><textarea id=\"code\" name=\"code\">// Variable Definitions\n\n$page-width:    800px\n$sidebar-width: 200px\n$primary-color: #eeeeee\n\n// Global Attributes\n\nbody\n  font:\n    family: sans-serif\n    size: 30em\n    weight: bold\n\n// Scoped Styles\n\n#contents\n  width: $page-width\n  #sidebar\n    float: right\n    width: $sidebar-width\n  #main\n    width: $page-width - $sidebar-width\n    background: $primary-color\n    h2\n      color: blue\n\n#footer\n  height: 200px\n</textarea></form>\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        lineNumbers : true,\n        matchBrackets : true\n      });\n    </script>\n\n    <p><strong>MIME types defined:</strong> <code>text/x-sass</code>.</p>\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/sass/sass.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"sass\", function(config) {\n  function tokenRegexp(words) {\n    return new RegExp(\"^\" + words.join(\"|\"));\n  }\n\n  var keywords = [\"true\", \"false\", \"null\", \"auto\"];\n  var keywordsRegexp = new RegExp(\"^\" + keywords.join(\"|\"));\n\n  var operators = [\"\\\\(\", \"\\\\)\", \"=\", \">\", \"<\", \"==\", \">=\", \"<=\", \"\\\\+\", \"-\",\n                   \"\\\\!=\", \"/\", \"\\\\*\", \"%\", \"and\", \"or\", \"not\", \";\",\"\\\\{\",\"\\\\}\",\":\"];\n  var opRegexp = tokenRegexp(operators);\n\n  var pseudoElementsRegexp = /^::?[a-zA-Z_][\\w\\-]*/;\n\n  function urlTokens(stream, state) {\n    var ch = stream.peek();\n\n    if (ch === \")\") {\n      stream.next();\n      state.tokenizer = tokenBase;\n      return \"operator\";\n    } else if (ch === \"(\") {\n      stream.next();\n      stream.eatSpace();\n\n      return \"operator\";\n    } else if (ch === \"'\" || ch === '\"') {\n      state.tokenizer = buildStringTokenizer(stream.next());\n      return \"string\";\n    } else {\n      state.tokenizer = buildStringTokenizer(\")\", false);\n      return \"string\";\n    }\n  }\n  function comment(indentation, multiLine) {\n    return function(stream, state) {\n      if (stream.sol() && stream.indentation() <= indentation) {\n        state.tokenizer = tokenBase;\n        return tokenBase(stream, state);\n      }\n\n      if (multiLine && stream.skipTo(\"*/\")) {\n        stream.next();\n        stream.next();\n        state.tokenizer = tokenBase;\n      } else {\n        stream.skipToEnd();\n      }\n\n      return \"comment\";\n    };\n  }\n\n  function buildStringTokenizer(quote, greedy) {\n    if (greedy == null) { greedy = true; }\n\n    function stringTokenizer(stream, state) {\n      var nextChar = stream.next();\n      var peekChar = stream.peek();\n      var previousChar = stream.string.charAt(stream.pos-2);\n\n      var endingString = ((nextChar !== \"\\\\\" && peekChar === quote) || (nextChar === quote && previousChar !== \"\\\\\"));\n\n      if (endingString) {\n        if (nextChar !== quote && greedy) { stream.next(); }\n        state.tokenizer = tokenBase;\n        return \"string\";\n      } else if (nextChar === \"#\" && peekChar === \"{\") {\n        state.tokenizer = buildInterpolationTokenizer(stringTokenizer);\n        stream.next();\n        return \"operator\";\n      } else {\n        return \"string\";\n      }\n    }\n\n    return stringTokenizer;\n  }\n\n  function buildInterpolationTokenizer(currentTokenizer) {\n    return function(stream, state) {\n      if (stream.peek() === \"}\") {\n        stream.next();\n        state.tokenizer = currentTokenizer;\n        return \"operator\";\n      } else {\n        return tokenBase(stream, state);\n      }\n    };\n  }\n\n  function indent(state) {\n    if (state.indentCount == 0) {\n      state.indentCount++;\n      var lastScopeOffset = state.scopes[0].offset;\n      var currentOffset = lastScopeOffset + config.indentUnit;\n      state.scopes.unshift({ offset:currentOffset });\n    }\n  }\n\n  function dedent(state) {\n    if (state.scopes.length == 1) return;\n\n    state.scopes.shift();\n  }\n\n  function tokenBase(stream, state) {\n    var ch = stream.peek();\n\n    // Comment\n    if (stream.match(\"/*\")) {\n      state.tokenizer = comment(stream.indentation(), true);\n      return state.tokenizer(stream, state);\n    }\n    if (stream.match(\"//\")) {\n      state.tokenizer = comment(stream.indentation(), false);\n      return state.tokenizer(stream, state);\n    }\n\n    // Interpolation\n    if (stream.match(\"#{\")) {\n      state.tokenizer = buildInterpolationTokenizer(tokenBase);\n      return \"operator\";\n    }\n\n    // Strings\n    if (ch === '\"' || ch === \"'\") {\n      stream.next();\n      state.tokenizer = buildStringTokenizer(ch);\n      return \"string\";\n    }\n\n    if(!state.cursorHalf){// state.cursorHalf === 0\n    // first half i.e. before : for key-value pairs\n    // including selectors\n\n      if (ch === \".\") {\n        stream.next();\n        if (stream.match(/^[\\w-]+/)) {\n          indent(state);\n          return \"atom\";\n        } else if (stream.peek() === \"#\") {\n          indent(state);\n          return \"atom\";\n        }\n      }\n\n      if (ch === \"#\") {\n        stream.next();\n        // ID selectors\n        if (stream.match(/^[\\w-]+/)) {\n          indent(state);\n          return \"atom\";\n        }\n        if (stream.peek() === \"#\") {\n          indent(state);\n          return \"atom\";\n        }\n      }\n\n      // Variables\n      if (ch === \"$\") {\n        stream.next();\n        stream.eatWhile(/[\\w-]/);\n        return \"variable-2\";\n      }\n\n      // Numbers\n      if (stream.match(/^-?[0-9\\.]+/))\n        return \"number\";\n\n      // Units\n      if (stream.match(/^(px|em|in)\\b/))\n        return \"unit\";\n\n      if (stream.match(keywordsRegexp))\n        return \"keyword\";\n\n      if (stream.match(/^url/) && stream.peek() === \"(\") {\n        state.tokenizer = urlTokens;\n        return \"atom\";\n      }\n\n      if (ch === \"=\") {\n        // Match shortcut mixin definition\n        if (stream.match(/^=[\\w-]+/)) {\n          indent(state);\n          return \"meta\";\n        }\n      }\n\n      if (ch === \"+\") {\n        // Match shortcut mixin definition\n        if (stream.match(/^\\+[\\w-]+/)){\n          return \"variable-3\";\n        }\n      }\n\n      if(ch === \"@\"){\n        if(stream.match(/@extend/)){\n          if(!stream.match(/\\s*[\\w]/))\n            dedent(state);\n        }\n      }\n\n\n      // Indent Directives\n      if (stream.match(/^@(else if|if|media|else|for|each|while|mixin|function)/)) {\n        indent(state);\n        return \"meta\";\n      }\n\n      // Other Directives\n      if (ch === \"@\") {\n        stream.next();\n        stream.eatWhile(/[\\w-]/);\n        return \"meta\";\n      }\n\n      if (stream.eatWhile(/[\\w-]/)){\n        if(stream.match(/ *: *[\\w-\\+\\$#!\\(\"']/,false)){\n          return \"propery\";\n        }\n        else if(stream.match(/ *:/,false)){\n          indent(state);\n          state.cursorHalf = 1;\n          return \"atom\";\n        }\n        else if(stream.match(/ *,/,false)){\n          return \"atom\";\n        }\n        else{\n          indent(state);\n          return \"atom\";\n        }\n      }\n\n      if(ch === \":\"){\n        if (stream.match(pseudoElementsRegexp)){ // could be a pseudo-element\n          return \"keyword\";\n        }\n        stream.next();\n        state.cursorHalf=1;\n        return \"operator\";\n      }\n\n    } // cursorHalf===0 ends here\n    else{\n\n      if (ch === \"#\") {\n        stream.next();\n        // Hex numbers\n        if (stream.match(/[0-9a-fA-F]{6}|[0-9a-fA-F]{3}/)){\n          if(!stream.peek()){\n            state.cursorHalf = 0;\n          }\n          return \"number\";\n        }\n      }\n\n      // Numbers\n      if (stream.match(/^-?[0-9\\.]+/)){\n        if(!stream.peek()){\n          state.cursorHalf = 0;\n        }\n        return \"number\";\n      }\n\n      // Units\n      if (stream.match(/^(px|em|in)\\b/)){\n        if(!stream.peek()){\n          state.cursorHalf = 0;\n        }\n        return \"unit\";\n      }\n\n      if (stream.match(keywordsRegexp)){\n        if(!stream.peek()){\n          state.cursorHalf = 0;\n        }\n        return \"keyword\";\n      }\n\n      if (stream.match(/^url/) && stream.peek() === \"(\") {\n        state.tokenizer = urlTokens;\n        if(!stream.peek()){\n          state.cursorHalf = 0;\n        }\n        return \"atom\";\n      }\n\n      // Variables\n      if (ch === \"$\") {\n        stream.next();\n        stream.eatWhile(/[\\w-]/);\n        if(!stream.peek()){\n          state.cursorHalf = 0;\n        }\n        return \"variable-3\";\n      }\n\n      // bang character for !important, !default, etc.\n      if (ch === \"!\") {\n        stream.next();\n        if(!stream.peek()){\n          state.cursorHalf = 0;\n        }\n        return stream.match(/^[\\w]+/) ? \"keyword\": \"operator\";\n      }\n\n      if (stream.match(opRegexp)){\n        if(!stream.peek()){\n          state.cursorHalf = 0;\n        }\n        return \"operator\";\n      }\n\n      // attributes\n      if (stream.eatWhile(/[\\w-]/)) {\n        if(!stream.peek()){\n          state.cursorHalf = 0;\n        }\n        return \"attribute\";\n      }\n\n      //stream.eatSpace();\n      if(!stream.peek()){\n        state.cursorHalf = 0;\n        return null;\n      }\n\n    } // else ends here\n\n    if (stream.match(opRegexp))\n      return \"operator\";\n\n    // If we haven't returned by now, we move 1 character\n    // and return an error\n    stream.next();\n    return null;\n  }\n\n  function tokenLexer(stream, state) {\n    if (stream.sol()) state.indentCount = 0;\n    var style = state.tokenizer(stream, state);\n    var current = stream.current();\n\n    if (current === \"@return\" || current === \"}\"){\n      dedent(state);\n    }\n\n    if (style !== null) {\n      var startOfToken = stream.pos - current.length;\n\n      var withCurrentIndent = startOfToken + (config.indentUnit * state.indentCount);\n\n      var newScopes = [];\n\n      for (var i = 0; i < state.scopes.length; i++) {\n        var scope = state.scopes[i];\n\n        if (scope.offset <= withCurrentIndent)\n          newScopes.push(scope);\n      }\n\n      state.scopes = newScopes;\n    }\n\n\n    return style;\n  }\n\n  return {\n    startState: function() {\n      return {\n        tokenizer: tokenBase,\n        scopes: [{offset: 0, type: \"sass\"}],\n        indentCount: 0,\n        cursorHalf: 0,  // cursor half tells us if cursor lies after (1)\n                        // or before (0) colon (well... more or less)\n        definedVars: [],\n        definedMixins: []\n      };\n    },\n    token: function(stream, state) {\n      var style = tokenLexer(stream, state);\n\n      state.lastToken = { style: style, content: stream.current() };\n\n      return style;\n    },\n\n    indent: function(state) {\n      return state.scopes[0].offset;\n    }\n  };\n});\n\nCodeMirror.defineMIME(\"text/x-sass\", \"sass\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/scheme/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Scheme mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"scheme.js\"></script>\n<style>.CodeMirror {background: #f8f8f8;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Scheme</a>\n  </ul>\n</div>\n\n<article>\n<h2>Scheme mode</h2>\n<form><textarea id=\"code\" name=\"code\">\n; See if the input starts with a given symbol.\n(define (match-symbol input pattern)\n  (cond ((null? (remain input)) #f)\n\t((eqv? (car (remain input)) pattern) (r-cdr input))\n\t(else #f)))\n\n; Allow the input to start with one of a list of patterns.\n(define (match-or input pattern)\n  (cond ((null? pattern) #f)\n\t((match-pattern input (car pattern)))\n\t(else (match-or input (cdr pattern)))))\n\n; Allow a sequence of patterns.\n(define (match-seq input pattern)\n  (if (null? pattern)\n      input\n      (let ((match (match-pattern input (car pattern))))\n\t(if match (match-seq match (cdr pattern)) #f))))\n\n; Match with the pattern but no problem if it does not match.\n(define (match-opt input pattern)\n  (let ((match (match-pattern input (car pattern))))\n    (if match match input)))\n\n; Match anything (other than '()), until pattern is found. The rather\n; clumsy form of requiring an ending pattern is needed to decide where\n; the end of the match is. If none is given, this will match the rest\n; of the sentence.\n(define (match-any input pattern)\n  (cond ((null? (remain input)) #f)\n\t((null? pattern) (f-cons (remain input) (clear-remain input)))\n\t(else\n\t (let ((accum-any (collector)))\n\t   (define (match-pattern-any input pattern)\n\t     (cond ((null? (remain input)) #f)\n\t\t   (else (accum-any (car (remain input)))\n\t\t\t (cond ((match-pattern (r-cdr input) pattern))\n\t\t\t       (else (match-pattern-any (r-cdr input) pattern))))))\n\t   (let ((retval (match-pattern-any input (car pattern))))\n\t     (if retval\n\t\t (f-cons (accum-any) retval)\n\t\t #f))))))\n</textarea></form>\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {});\n    </script>\n\n    <p><strong>MIME types defined:</strong> <code>text/x-scheme</code>.</p>\n\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/scheme/scheme.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n/**\n * Author: Koh Zi Han, based on implementation by Koh Zi Chun\n */\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"scheme\", function () {\n    var BUILTIN = \"builtin\", COMMENT = \"comment\", STRING = \"string\",\n        ATOM = \"atom\", NUMBER = \"number\", BRACKET = \"bracket\";\n    var INDENT_WORD_SKIP = 2;\n\n    function makeKeywords(str) {\n        var obj = {}, words = str.split(\" \");\n        for (var i = 0; i < words.length; ++i) obj[words[i]] = true;\n        return obj;\n    }\n\n    var keywords = makeKeywords(\"λ case-lambda call/cc class define-class exit-handler field import inherit init-field interface let*-values let-values let/ec mixin opt-lambda override protect provide public rename require require-for-syntax syntax syntax-case syntax-error unit/sig unless when with-syntax and begin call-with-current-continuation call-with-input-file call-with-output-file case cond define define-syntax delay do dynamic-wind else for-each if lambda let let* let-syntax letrec letrec-syntax map or syntax-rules abs acos angle append apply asin assoc assq assv atan boolean? caar cadr call-with-input-file call-with-output-file call-with-values car cdddar cddddr cdr ceiling char->integer char-alphabetic? char-ci<=? char-ci<? char-ci=? char-ci>=? char-ci>? char-downcase char-lower-case? char-numeric? char-ready? char-upcase char-upper-case? char-whitespace? char<=? char<? char=? char>=? char>? char? close-input-port close-output-port complex? cons cos current-input-port current-output-port denominator display eof-object? eq? equal? eqv? eval even? exact->inexact exact? exp expt #f floor force gcd imag-part inexact->exact inexact? input-port? integer->char integer? interaction-environment lcm length list list->string list->vector list-ref list-tail list? load log magnitude make-polar make-rectangular make-string make-vector max member memq memv min modulo negative? newline not null-environment null? number->string number? numerator odd? open-input-file open-output-file output-port? pair? peek-char port? positive? procedure? quasiquote quote quotient rational? rationalize read read-char real-part real? remainder reverse round scheme-report-environment set! set-car! set-cdr! sin sqrt string string->list string->number string->symbol string-append string-ci<=? string-ci<? string-ci=? string-ci>=? string-ci>? string-copy string-fill! string-length string-ref string-set! string<=? string<? string=? string>=? string>? string? substring symbol->string symbol? #t tan transcript-off transcript-on truncate values vector vector->list vector-fill! vector-length vector-ref vector-set! with-input-from-file with-output-to-file write write-char zero?\");\n    var indentKeys = makeKeywords(\"define let letrec let* lambda\");\n\n    function stateStack(indent, type, prev) { // represents a state stack object\n        this.indent = indent;\n        this.type = type;\n        this.prev = prev;\n    }\n\n    function pushStack(state, indent, type) {\n        state.indentStack = new stateStack(indent, type, state.indentStack);\n    }\n\n    function popStack(state) {\n        state.indentStack = state.indentStack.prev;\n    }\n\n    var binaryMatcher = new RegExp(/^(?:[-+]i|[-+][01]+#*(?:\\/[01]+#*)?i|[-+]?[01]+#*(?:\\/[01]+#*)?@[-+]?[01]+#*(?:\\/[01]+#*)?|[-+]?[01]+#*(?:\\/[01]+#*)?[-+](?:[01]+#*(?:\\/[01]+#*)?)?i|[-+]?[01]+#*(?:\\/[01]+#*)?)(?=[()\\s;\"]|$)/i);\n    var octalMatcher = new RegExp(/^(?:[-+]i|[-+][0-7]+#*(?:\\/[0-7]+#*)?i|[-+]?[0-7]+#*(?:\\/[0-7]+#*)?@[-+]?[0-7]+#*(?:\\/[0-7]+#*)?|[-+]?[0-7]+#*(?:\\/[0-7]+#*)?[-+](?:[0-7]+#*(?:\\/[0-7]+#*)?)?i|[-+]?[0-7]+#*(?:\\/[0-7]+#*)?)(?=[()\\s;\"]|$)/i);\n    var hexMatcher = new RegExp(/^(?:[-+]i|[-+][\\da-f]+#*(?:\\/[\\da-f]+#*)?i|[-+]?[\\da-f]+#*(?:\\/[\\da-f]+#*)?@[-+]?[\\da-f]+#*(?:\\/[\\da-f]+#*)?|[-+]?[\\da-f]+#*(?:\\/[\\da-f]+#*)?[-+](?:[\\da-f]+#*(?:\\/[\\da-f]+#*)?)?i|[-+]?[\\da-f]+#*(?:\\/[\\da-f]+#*)?)(?=[()\\s;\"]|$)/i);\n    var decimalMatcher = new RegExp(/^(?:[-+]i|[-+](?:(?:(?:\\d+#+\\.?#*|\\d+\\.\\d*#*|\\.\\d+#*|\\d+)(?:[esfdl][-+]?\\d+)?)|\\d+#*\\/\\d+#*)i|[-+]?(?:(?:(?:\\d+#+\\.?#*|\\d+\\.\\d*#*|\\.\\d+#*|\\d+)(?:[esfdl][-+]?\\d+)?)|\\d+#*\\/\\d+#*)@[-+]?(?:(?:(?:\\d+#+\\.?#*|\\d+\\.\\d*#*|\\.\\d+#*|\\d+)(?:[esfdl][-+]?\\d+)?)|\\d+#*\\/\\d+#*)|[-+]?(?:(?:(?:\\d+#+\\.?#*|\\d+\\.\\d*#*|\\.\\d+#*|\\d+)(?:[esfdl][-+]?\\d+)?)|\\d+#*\\/\\d+#*)[-+](?:(?:(?:\\d+#+\\.?#*|\\d+\\.\\d*#*|\\.\\d+#*|\\d+)(?:[esfdl][-+]?\\d+)?)|\\d+#*\\/\\d+#*)?i|(?:(?:(?:\\d+#+\\.?#*|\\d+\\.\\d*#*|\\.\\d+#*|\\d+)(?:[esfdl][-+]?\\d+)?)|\\d+#*\\/\\d+#*))(?=[()\\s;\"]|$)/i);\n\n    function isBinaryNumber (stream) {\n        return stream.match(binaryMatcher);\n    }\n\n    function isOctalNumber (stream) {\n        return stream.match(octalMatcher);\n    }\n\n    function isDecimalNumber (stream, backup) {\n        if (backup === true) {\n            stream.backUp(1);\n        }\n        return stream.match(decimalMatcher);\n    }\n\n    function isHexNumber (stream) {\n        return stream.match(hexMatcher);\n    }\n\n    return {\n        startState: function () {\n            return {\n                indentStack: null,\n                indentation: 0,\n                mode: false,\n                sExprComment: false\n            };\n        },\n\n        token: function (stream, state) {\n            if (state.indentStack == null && stream.sol()) {\n                // update indentation, but only if indentStack is empty\n                state.indentation = stream.indentation();\n            }\n\n            // skip spaces\n            if (stream.eatSpace()) {\n                return null;\n            }\n            var returnType = null;\n\n            switch(state.mode){\n                case \"string\": // multi-line string parsing mode\n                    var next, escaped = false;\n                    while ((next = stream.next()) != null) {\n                        if (next == \"\\\"\" && !escaped) {\n\n                            state.mode = false;\n                            break;\n                        }\n                        escaped = !escaped && next == \"\\\\\";\n                    }\n                    returnType = STRING; // continue on in scheme-string mode\n                    break;\n                case \"comment\": // comment parsing mode\n                    var next, maybeEnd = false;\n                    while ((next = stream.next()) != null) {\n                        if (next == \"#\" && maybeEnd) {\n\n                            state.mode = false;\n                            break;\n                        }\n                        maybeEnd = (next == \"|\");\n                    }\n                    returnType = COMMENT;\n                    break;\n                case \"s-expr-comment\": // s-expr commenting mode\n                    state.mode = false;\n                    if(stream.peek() == \"(\" || stream.peek() == \"[\"){\n                        // actually start scheme s-expr commenting mode\n                        state.sExprComment = 0;\n                    }else{\n                        // if not we just comment the entire of the next token\n                        stream.eatWhile(/[^/s]/); // eat non spaces\n                        returnType = COMMENT;\n                        break;\n                    }\n                default: // default parsing mode\n                    var ch = stream.next();\n\n                    if (ch == \"\\\"\") {\n                        state.mode = \"string\";\n                        returnType = STRING;\n\n                    } else if (ch == \"'\") {\n                        returnType = ATOM;\n                    } else if (ch == '#') {\n                        if (stream.eat(\"|\")) {                    // Multi-line comment\n                            state.mode = \"comment\"; // toggle to comment mode\n                            returnType = COMMENT;\n                        } else if (stream.eat(/[tf]/i)) {            // #t/#f (atom)\n                            returnType = ATOM;\n                        } else if (stream.eat(';')) {                // S-Expr comment\n                            state.mode = \"s-expr-comment\";\n                            returnType = COMMENT;\n                        } else {\n                            var numTest = null, hasExactness = false, hasRadix = true;\n                            if (stream.eat(/[ei]/i)) {\n                                hasExactness = true;\n                            } else {\n                                stream.backUp(1);       // must be radix specifier\n                            }\n                            if (stream.match(/^#b/i)) {\n                                numTest = isBinaryNumber;\n                            } else if (stream.match(/^#o/i)) {\n                                numTest = isOctalNumber;\n                            } else if (stream.match(/^#x/i)) {\n                                numTest = isHexNumber;\n                            } else if (stream.match(/^#d/i)) {\n                                numTest = isDecimalNumber;\n                            } else if (stream.match(/^[-+0-9.]/, false)) {\n                                hasRadix = false;\n                                numTest = isDecimalNumber;\n                            // re-consume the intial # if all matches failed\n                            } else if (!hasExactness) {\n                                stream.eat('#');\n                            }\n                            if (numTest != null) {\n                                if (hasRadix && !hasExactness) {\n                                    // consume optional exactness after radix\n                                    stream.match(/^#[ei]/i);\n                                }\n                                if (numTest(stream))\n                                    returnType = NUMBER;\n                            }\n                        }\n                    } else if (/^[-+0-9.]/.test(ch) && isDecimalNumber(stream, true)) { // match non-prefixed number, must be decimal\n                        returnType = NUMBER;\n                    } else if (ch == \";\") { // comment\n                        stream.skipToEnd(); // rest of the line is a comment\n                        returnType = COMMENT;\n                    } else if (ch == \"(\" || ch == \"[\") {\n                      var keyWord = ''; var indentTemp = stream.column(), letter;\n                        /**\n                        Either\n                        (indent-word ..\n                        (non-indent-word ..\n                        (;something else, bracket, etc.\n                        */\n\n                        while ((letter = stream.eat(/[^\\s\\(\\[\\;\\)\\]]/)) != null) {\n                            keyWord += letter;\n                        }\n\n                        if (keyWord.length > 0 && indentKeys.propertyIsEnumerable(keyWord)) { // indent-word\n\n                            pushStack(state, indentTemp + INDENT_WORD_SKIP, ch);\n                        } else { // non-indent word\n                            // we continue eating the spaces\n                            stream.eatSpace();\n                            if (stream.eol() || stream.peek() == \";\") {\n                                // nothing significant after\n                                // we restart indentation 1 space after\n                                pushStack(state, indentTemp + 1, ch);\n                            } else {\n                                pushStack(state, indentTemp + stream.current().length, ch); // else we match\n                            }\n                        }\n                        stream.backUp(stream.current().length - 1); // undo all the eating\n\n                        if(typeof state.sExprComment == \"number\") state.sExprComment++;\n\n                        returnType = BRACKET;\n                    } else if (ch == \")\" || ch == \"]\") {\n                        returnType = BRACKET;\n                        if (state.indentStack != null && state.indentStack.type == (ch == \")\" ? \"(\" : \"[\")) {\n                            popStack(state);\n\n                            if(typeof state.sExprComment == \"number\"){\n                                if(--state.sExprComment == 0){\n                                    returnType = COMMENT; // final closing bracket\n                                    state.sExprComment = false; // turn off s-expr commenting mode\n                                }\n                            }\n                        }\n                    } else {\n                        stream.eatWhile(/[\\w\\$_\\-!$%&*+\\.\\/:<=>?@\\^~]/);\n\n                        if (keywords && keywords.propertyIsEnumerable(stream.current())) {\n                            returnType = BUILTIN;\n                        } else returnType = \"variable\";\n                    }\n            }\n            return (typeof state.sExprComment == \"number\") ? COMMENT : returnType;\n        },\n\n        indent: function (state) {\n            if (state.indentStack == null) return state.indentation;\n            return state.indentStack.indent;\n        },\n\n        lineComment: \";;\"\n    };\n});\n\nCodeMirror.defineMIME(\"text/x-scheme\", \"scheme\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/shell/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Shell mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=stylesheet href=../../lib/codemirror.css>\n<script src=../../lib/codemirror.js></script>\n<script src=\"../../addon/edit/matchbrackets.js\"></script>\n<script src=shell.js></script>\n<style type=text/css>\n  .CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}\n</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Shell</a>\n  </ul>\n</div>\n\n<article>\n<h2>Shell mode</h2>\n\n\n<textarea id=code>\n#!/bin/bash\n\n# clone the repository\ngit clone http://github.com/garden/tree\n\n# generate HTTPS credentials\ncd tree\nopenssl genrsa -aes256 -out https.key 1024\nopenssl req -new -nodes -key https.key -out https.csr\nopenssl x509 -req -days 365 -in https.csr -signkey https.key -out https.crt\ncp https.key{,.orig}\nopenssl rsa -in https.key.orig -out https.key\n\n# start the server in HTTPS mode\ncd web\nsudo node ../server.js 443 'yes' &gt;&gt; ../node.log &amp;\n\n# here is how to stop the server\nfor pid in `ps aux | grep 'node ../server.js' | awk '{print $2}'` ; do\n  sudo kill -9 $pid 2&gt; /dev/null\ndone\n\nexit 0</textarea>\n\n<script>\n  var editor = CodeMirror.fromTextArea(document.getElementById('code'), {\n    mode: 'shell',\n    lineNumbers: true,\n    matchBrackets: true\n  });\n</script>\n\n<p><strong>MIME types defined:</strong> <code>text/x-sh</code>.</p>\n</article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/shell/shell.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode('shell', function() {\n\n  var words = {};\n  function define(style, string) {\n    var split = string.split(' ');\n    for(var i = 0; i < split.length; i++) {\n      words[split[i]] = style;\n    }\n  };\n\n  // Atoms\n  define('atom', 'true false');\n\n  // Keywords\n  define('keyword', 'if then do else elif while until for in esac fi fin ' +\n    'fil done exit set unset export function');\n\n  // Commands\n  define('builtin', 'ab awk bash beep cat cc cd chown chmod chroot clear cp ' +\n    'curl cut diff echo find gawk gcc get git grep kill killall ln ls make ' +\n    'mkdir openssl mv nc node npm ping ps restart rm rmdir sed service sh ' +\n    'shopt shred source sort sleep ssh start stop su sudo tee telnet top ' +\n    'touch vi vim wall wc wget who write yes zsh');\n\n  function tokenBase(stream, state) {\n    if (stream.eatSpace()) return null;\n\n    var sol = stream.sol();\n    var ch = stream.next();\n\n    if (ch === '\\\\') {\n      stream.next();\n      return null;\n    }\n    if (ch === '\\'' || ch === '\"' || ch === '`') {\n      state.tokens.unshift(tokenString(ch));\n      return tokenize(stream, state);\n    }\n    if (ch === '#') {\n      if (sol && stream.eat('!')) {\n        stream.skipToEnd();\n        return 'meta'; // 'comment'?\n      }\n      stream.skipToEnd();\n      return 'comment';\n    }\n    if (ch === '$') {\n      state.tokens.unshift(tokenDollar);\n      return tokenize(stream, state);\n    }\n    if (ch === '+' || ch === '=') {\n      return 'operator';\n    }\n    if (ch === '-') {\n      stream.eat('-');\n      stream.eatWhile(/\\w/);\n      return 'attribute';\n    }\n    if (/\\d/.test(ch)) {\n      stream.eatWhile(/\\d/);\n      if(stream.eol() || !/\\w/.test(stream.peek())) {\n        return 'number';\n      }\n    }\n    stream.eatWhile(/[\\w-]/);\n    var cur = stream.current();\n    if (stream.peek() === '=' && /\\w+/.test(cur)) return 'def';\n    return words.hasOwnProperty(cur) ? words[cur] : null;\n  }\n\n  function tokenString(quote) {\n    return function(stream, state) {\n      var next, end = false, escaped = false;\n      while ((next = stream.next()) != null) {\n        if (next === quote && !escaped) {\n          end = true;\n          break;\n        }\n        if (next === '$' && !escaped && quote !== '\\'') {\n          escaped = true;\n          stream.backUp(1);\n          state.tokens.unshift(tokenDollar);\n          break;\n        }\n        escaped = !escaped && next === '\\\\';\n      }\n      if (end || !escaped) {\n        state.tokens.shift();\n      }\n      return (quote === '`' || quote === ')' ? 'quote' : 'string');\n    };\n  };\n\n  var tokenDollar = function(stream, state) {\n    if (state.tokens.length > 1) stream.eat('$');\n    var ch = stream.next(), hungry = /\\w/;\n    if (ch === '{') hungry = /[^}]/;\n    if (ch === '(') {\n      state.tokens[0] = tokenString(')');\n      return tokenize(stream, state);\n    }\n    if (!/\\d/.test(ch)) {\n      stream.eatWhile(hungry);\n      stream.eat('}');\n    }\n    state.tokens.shift();\n    return 'def';\n  };\n\n  function tokenize(stream, state) {\n    return (state.tokens[0] || tokenBase) (stream, state);\n  };\n\n  return {\n    startState: function() {return {tokens:[]};},\n    token: function(stream, state) {\n      return tokenize(stream, state);\n    },\n    lineComment: '#',\n    fold: \"brace\"\n  };\n});\n\nCodeMirror.defineMIME('text/x-sh', 'shell');\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/shell/test.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function() {\n  var mode = CodeMirror.getMode({}, \"shell\");\n  function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); }\n\n  MT(\"var\",\n     \"text [def $var] text\");\n  MT(\"varBraces\",\n     \"text[def ${var}]text\");\n  MT(\"varVar\",\n     \"text [def $a$b] text\");\n  MT(\"varBracesVarBraces\",\n     \"text[def ${a}${b}]text\");\n\n  MT(\"singleQuotedVar\",\n     \"[string 'text $var text']\");\n  MT(\"singleQuotedVarBraces\",\n     \"[string 'text ${var} text']\");\n\n  MT(\"doubleQuotedVar\",\n     '[string \"text ][def $var][string  text\"]');\n  MT(\"doubleQuotedVarBraces\",\n     '[string \"text][def ${var}][string text\"]');\n  MT(\"doubleQuotedVarPunct\",\n     '[string \"text ][def $@][string  text\"]');\n  MT(\"doubleQuotedVarVar\",\n     '[string \"][def $a$b][string \"]');\n  MT(\"doubleQuotedVarBracesVarBraces\",\n     '[string \"][def ${a}${b}][string \"]');\n\n  MT(\"notAString\",\n     \"text\\\\'text\");\n  MT(\"escapes\",\n     \"outside\\\\'\\\\\\\"\\\\`\\\\\\\\[string \\\"inside\\\\`\\\\'\\\\\\\"\\\\\\\\`\\\\$notAVar\\\"]outside\\\\$\\\\(notASubShell\\\\)\");\n\n  MT(\"subshell\",\n     \"[builtin echo] [quote $(whoami)] s log, stardate [quote `date`].\");\n  MT(\"doubleQuotedSubshell\",\n     \"[builtin echo] [string \\\"][quote $(whoami)][string 's log, stardate `date`.\\\"]\");\n\n  MT(\"hashbang\",\n     \"[meta #!/bin/bash]\");\n  MT(\"comment\",\n     \"text [comment # Blurb]\");\n\n  MT(\"numbers\",\n     \"[number 0] [number 1] [number 2]\");\n  MT(\"keywords\",\n     \"[keyword while] [atom true]; [keyword do]\",\n     \"  [builtin sleep] [number 3]\",\n     \"[keyword done]\");\n  MT(\"options\",\n     \"[builtin ls] [attribute -l] [attribute --human-readable]\");\n  MT(\"operator\",\n     \"[def var][operator =]value\");\n})();\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/sieve/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Sieve (RFC5228) mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"sieve.js\"></script>\n<style>.CodeMirror {background: #f8f8f8;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Sieve (RFC5228)</a>\n  </ul>\n</div>\n\n<article>\n<h2>Sieve (RFC5228) mode</h2>\n<form><textarea id=\"code\" name=\"code\">\n#\n# Example Sieve Filter\n# Declare any optional features or extension used by the script\n#\n\nrequire [\"fileinto\", \"reject\"];\n\n#\n# Reject any large messages (note that the four leading dots get\n# \"stuffed\" to three)\n#\nif size :over 1M\n{\n  reject text:\nPlease do not send me large attachments.\nPut your file on a server and send me the URL.\nThank you.\n.... Fred\n.\n;\n  stop;\n}\n\n#\n# Handle messages from known mailing lists\n# Move messages from IETF filter discussion list to filter folder\n#\nif header :is \"Sender\" \"owner-ietf-mta-filters@imc.org\"\n{\n  fileinto \"filter\";  # move to \"filter\" folder\n}\n#\n# Keep all messages to or from people in my company\n#\nelsif address :domain :is [\"From\", \"To\"] \"example.com\"\n{\n  keep;               # keep in \"In\" folder\n}\n\n#\n# Try and catch unsolicited email.  If a message is not to me,\n# or it contains a subject known to be spam, file it away.\n#\nelsif anyof (not address :all :contains\n               [\"To\", \"Cc\", \"Bcc\"] \"me@example.com\",\n             header :matches \"subject\"\n               [\"*make*money*fast*\", \"*university*dipl*mas*\"])\n{\n  # If message header does not contain my address,\n  # it's from a list.\n  fileinto \"spam\";   # move to \"spam\" folder\n}\nelse\n{\n  # Move all other (non-company) mail to \"personal\"\n  # folder.\n  fileinto \"personal\";\n}\n</textarea></form>\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {});\n    </script>\n\n    <p><strong>MIME types defined:</strong> <code>application/sieve</code>.</p>\n\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/sieve/sieve.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"sieve\", function(config) {\n  function words(str) {\n    var obj = {}, words = str.split(\" \");\n    for (var i = 0; i < words.length; ++i) obj[words[i]] = true;\n    return obj;\n  }\n\n  var keywords = words(\"if elsif else stop require\");\n  var atoms = words(\"true false not\");\n  var indentUnit = config.indentUnit;\n\n  function tokenBase(stream, state) {\n\n    var ch = stream.next();\n    if (ch == \"/\" && stream.eat(\"*\")) {\n      state.tokenize = tokenCComment;\n      return tokenCComment(stream, state);\n    }\n\n    if (ch === '#') {\n      stream.skipToEnd();\n      return \"comment\";\n    }\n\n    if (ch == \"\\\"\") {\n      state.tokenize = tokenString(ch);\n      return state.tokenize(stream, state);\n    }\n\n    if (ch == \"(\") {\n      state._indent.push(\"(\");\n      // add virtual angel wings so that editor behaves...\n      // ...more sane incase of broken brackets\n      state._indent.push(\"{\");\n      return null;\n    }\n\n    if (ch === \"{\") {\n      state._indent.push(\"{\");\n      return null;\n    }\n\n    if (ch == \")\")  {\n      state._indent.pop();\n      state._indent.pop();\n    }\n\n    if (ch === \"}\") {\n      state._indent.pop();\n      return null;\n    }\n\n    if (ch == \",\")\n      return null;\n\n    if (ch == \";\")\n      return null;\n\n\n    if (/[{}\\(\\),;]/.test(ch))\n      return null;\n\n    // 1*DIGIT \"K\" / \"M\" / \"G\"\n    if (/\\d/.test(ch)) {\n      stream.eatWhile(/[\\d]/);\n      stream.eat(/[KkMmGg]/);\n      return \"number\";\n    }\n\n    // \":\" (ALPHA / \"_\") *(ALPHA / DIGIT / \"_\")\n    if (ch == \":\") {\n      stream.eatWhile(/[a-zA-Z_]/);\n      stream.eatWhile(/[a-zA-Z0-9_]/);\n\n      return \"operator\";\n    }\n\n    stream.eatWhile(/\\w/);\n    var cur = stream.current();\n\n    // \"text:\" *(SP / HTAB) (hash-comment / CRLF)\n    // *(multiline-literal / multiline-dotstart)\n    // \".\" CRLF\n    if ((cur == \"text\") && stream.eat(\":\"))\n    {\n      state.tokenize = tokenMultiLineString;\n      return \"string\";\n    }\n\n    if (keywords.propertyIsEnumerable(cur))\n      return \"keyword\";\n\n    if (atoms.propertyIsEnumerable(cur))\n      return \"atom\";\n\n    return null;\n  }\n\n  function tokenMultiLineString(stream, state)\n  {\n    state._multiLineString = true;\n    // the first line is special it may contain a comment\n    if (!stream.sol()) {\n      stream.eatSpace();\n\n      if (stream.peek() == \"#\") {\n        stream.skipToEnd();\n        return \"comment\";\n      }\n\n      stream.skipToEnd();\n      return \"string\";\n    }\n\n    if ((stream.next() == \".\")  && (stream.eol()))\n    {\n      state._multiLineString = false;\n      state.tokenize = tokenBase;\n    }\n\n    return \"string\";\n  }\n\n  function tokenCComment(stream, state) {\n    var maybeEnd = false, ch;\n    while ((ch = stream.next()) != null) {\n      if (maybeEnd && ch == \"/\") {\n        state.tokenize = tokenBase;\n        break;\n      }\n      maybeEnd = (ch == \"*\");\n    }\n    return \"comment\";\n  }\n\n  function tokenString(quote) {\n    return function(stream, state) {\n      var escaped = false, ch;\n      while ((ch = stream.next()) != null) {\n        if (ch == quote && !escaped)\n          break;\n        escaped = !escaped && ch == \"\\\\\";\n      }\n      if (!escaped) state.tokenize = tokenBase;\n      return \"string\";\n    };\n  }\n\n  return {\n    startState: function(base) {\n      return {tokenize: tokenBase,\n              baseIndent: base || 0,\n              _indent: []};\n    },\n\n    token: function(stream, state) {\n      if (stream.eatSpace())\n        return null;\n\n      return (state.tokenize || tokenBase)(stream, state);;\n    },\n\n    indent: function(state, _textAfter) {\n      var length = state._indent.length;\n      if (_textAfter && (_textAfter[0] == \"}\"))\n        length--;\n\n      if (length <0)\n        length = 0;\n\n      return length * indentUnit;\n    },\n\n    electricChars: \"}\"\n  };\n});\n\nCodeMirror.defineMIME(\"application/sieve\", \"sieve\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/slim/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: SLIM mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<link rel=\"stylesheet\" href=\"../../theme/ambiance.css\">\n<script src=\"https://code.jquery.com/jquery-1.11.1.min.js\"></script>\n<script src=\"https://code.jquery.com/ui/1.11.0/jquery-ui.min.js\"></script>\n<link rel=\"stylesheet\" href=\"https://code.jquery.com/ui/1.11.0/themes/smoothness/jquery-ui.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"../xml/xml.js\"></script>\n<script src=\"../htmlembedded/htmlembedded.js\"></script>\n<script src=\"../htmlmixed/htmlmixed.js\"></script>\n<script src=\"../coffeescript/coffeescript.js\"></script>\n<script src=\"../javascript/javascript.js\"></script>\n<script src=\"../ruby/ruby.js\"></script>\n<script src=\"../markdown/markdown.js\"></script>\n<script src=\"slim.js\"></script>\n<style>.CodeMirror {background: #f8f8f8;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">SLIM</a>\n  </ul>\n</div>\n\n<article>\n  <h2>SLIM mode</h2>\n  <form><textarea id=\"code\" name=\"code\">\nbody\n  table\n    - for user in users\n      td id=\"user_#{user.id}\" class=user.role\n        a href=user_action(user, :edit) Edit #{user.name}\n        a href=(path_to_user user) = user.name\nbody\n  h1(id=\"logo\") = page_logo\n  h2[id=\"tagline\" class=\"small tagline\"] = page_tagline\n\nh2[id=\"tagline\"\n   class=\"small tagline\"] = page_tagline\n\nh1 id = \"logo\" = page_logo\nh2 [ id = \"tagline\" ] = page_tagline\n\n/ comment\n  second line\n/! html comment\n   second line\n<!-- html comment -->\n<a href=\"#{'hello' if set}\">link</a>\na.slim href=\"work\" disabled=false running==:atom Text <b>bold</b>\n.clazz data-id=\"test\" == 'hello' unless quark\n | Text mode #{12}\n   Second line\n= x ||= :ruby_atom\n#menu.left\n  - @env.each do |x|\n    li: a = x\n*@dyntag attr=\"val\"\n.first *{:class => [:second, :third]} Text\n.second class=[\"text\",\"more\"]\n.third class=:text,:symbol\n\n  </textarea></form>\n  <script>\n    var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n      lineNumbers: true,\n      theme: \"ambiance\",\n      mode: \"application/x-slim\"\n    });\n    $('.CodeMirror').resizable({\n      resize: function() {\n        editor.setSize($(this).width(), $(this).height());\n        //editor.refresh();\n      }\n    });\n  </script>\n\n  <p><strong>MIME types defined:</strong> <code>application/x-slim</code>.</p>\n\n  <p>\n    <strong>Parsing/Highlighting Tests:</strong>\n    <a href=\"../../test/index.html#slim_*\">normal</a>,\n    <a href=\"../../test/index.html#verbose,slim_*\">verbose</a>.\n  </p>\n</article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/slim/slim.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n// Slim Highlighting for CodeMirror copyright (c) HicknHack Software Gmbh\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"), require(\"../htmlmixed/htmlmixed\"), require(\"../ruby/ruby\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\", \"../htmlmixed/htmlmixed\", \"../ruby/ruby\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\n  CodeMirror.defineMode(\"slim\", function(config) {\n    var htmlMode = CodeMirror.getMode(config, {name: \"htmlmixed\"});\n    var rubyMode = CodeMirror.getMode(config, \"ruby\");\n    var modes = { html: htmlMode, ruby: rubyMode };\n    var embedded = {\n      ruby: \"ruby\",\n      javascript: \"javascript\",\n      css: \"text/css\",\n      sass: \"text/x-sass\",\n      scss: \"text/x-scss\",\n      less: \"text/x-less\",\n      styl: \"text/x-styl\", // no highlighting so far\n      coffee: \"coffeescript\",\n      asciidoc: \"text/x-asciidoc\",\n      markdown: \"text/x-markdown\",\n      textile: \"text/x-textile\", // no highlighting so far\n      creole: \"text/x-creole\", // no highlighting so far\n      wiki: \"text/x-wiki\", // no highlighting so far\n      mediawiki: \"text/x-mediawiki\", // no highlighting so far\n      rdoc: \"text/x-rdoc\", // no highlighting so far\n      builder: \"text/x-builder\", // no highlighting so far\n      nokogiri: \"text/x-nokogiri\", // no highlighting so far\n      erb: \"application/x-erb\"\n    };\n    var embeddedRegexp = function(map){\n      var arr = [];\n      for(var key in map) arr.push(key);\n      return new RegExp(\"^(\"+arr.join('|')+\"):\");\n    }(embedded);\n\n    var styleMap = {\n      \"commentLine\": \"comment\",\n      \"slimSwitch\": \"operator special\",\n      \"slimTag\": \"tag\",\n      \"slimId\": \"attribute def\",\n      \"slimClass\": \"attribute qualifier\",\n      \"slimAttribute\": \"attribute\",\n      \"slimSubmode\": \"keyword special\",\n      \"closeAttributeTag\": null,\n      \"slimDoctype\": null,\n      \"lineContinuation\": null\n    };\n    var closing = {\n      \"{\": \"}\",\n      \"[\": \"]\",\n      \"(\": \")\"\n    };\n\n    var nameStartChar = \"_a-zA-Z\\xC0-\\xD6\\xD8-\\xF6\\xF8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD\";\n    var nameChar = nameStartChar + \"\\\\-0-9\\xB7\\u0300-\\u036F\\u203F-\\u2040\";\n    var nameRegexp = new RegExp(\"^[:\"+nameStartChar+\"](?::[\"+nameChar+\"]|[\"+nameChar+\"]*)\");\n    var attributeNameRegexp = new RegExp(\"^[:\"+nameStartChar+\"][:\\\\.\"+nameChar+\"]*(?=\\\\s*=)\");\n    var wrappedAttributeNameRegexp = new RegExp(\"^[:\"+nameStartChar+\"][:\\\\.\"+nameChar+\"]*\");\n    var classNameRegexp = /^\\.-?[_a-zA-Z]+[\\w\\-]*/;\n    var classIdRegexp = /^#[_a-zA-Z]+[\\w\\-]*/;\n\n    function backup(pos, tokenize, style) {\n      var restore = function(stream, state) {\n        state.tokenize = tokenize;\n        if (stream.pos < pos) {\n          stream.pos = pos;\n          return style;\n        }\n        return state.tokenize(stream, state);\n      };\n      return function(stream, state) {\n        state.tokenize = restore;\n        return tokenize(stream, state);\n      };\n    }\n\n    function maybeBackup(stream, state, pat, offset, style) {\n      var cur = stream.current();\n      var idx = cur.search(pat);\n      if (idx > -1) {\n        state.tokenize = backup(stream.pos, state.tokenize, style);\n        stream.backUp(cur.length - idx - offset);\n      }\n      return style;\n    }\n\n    function continueLine(state, column) {\n      state.stack = {\n        parent: state.stack,\n        style: \"continuation\",\n        indented: column,\n        tokenize: state.line\n      };\n      state.line = state.tokenize;\n    }\n    function finishContinue(state) {\n      if (state.line == state.tokenize) {\n        state.line = state.stack.tokenize;\n        state.stack = state.stack.parent;\n      }\n    }\n\n    function lineContinuable(column, tokenize) {\n      return function(stream, state) {\n        finishContinue(state);\n        if (stream.match(/^\\\\$/)) {\n          continueLine(state, column);\n          return \"lineContinuation\";\n        }\n        var style = tokenize(stream, state);\n        if (stream.eol() && stream.current().match(/(?:^|[^\\\\])(?:\\\\\\\\)*\\\\$/)) {\n          stream.backUp(1);\n        }\n        return style;\n      };\n    }\n    function commaContinuable(column, tokenize) {\n      return function(stream, state) {\n        finishContinue(state);\n        var style = tokenize(stream, state);\n        if (stream.eol() && stream.current().match(/,$/)) {\n          continueLine(state, column);\n        }\n        return style;\n      };\n    }\n\n    function rubyInQuote(endQuote, tokenize) {\n      // TODO: add multi line support\n      return function(stream, state) {\n        var ch = stream.peek();\n        if (ch == endQuote && state.rubyState.tokenize.length == 1) {\n          // step out of ruby context as it seems to complete processing all the braces\n          stream.next();\n          state.tokenize = tokenize;\n          return \"closeAttributeTag\";\n        } else {\n          return ruby(stream, state);\n        }\n      };\n    }\n    function startRubySplat(tokenize) {\n      var rubyState;\n      var runSplat = function(stream, state) {\n        if (state.rubyState.tokenize.length == 1 && !state.rubyState.context.prev) {\n          stream.backUp(1);\n          if (stream.eatSpace()) {\n            state.rubyState = rubyState;\n            state.tokenize = tokenize;\n            return tokenize(stream, state);\n          }\n          stream.next();\n        }\n        return ruby(stream, state);\n      };\n      return function(stream, state) {\n        rubyState = state.rubyState;\n        state.rubyState = rubyMode.startState();\n        state.tokenize = runSplat;\n        return ruby(stream, state);\n      };\n    }\n\n    function ruby(stream, state) {\n      return rubyMode.token(stream, state.rubyState);\n    }\n\n    function htmlLine(stream, state) {\n      if (stream.match(/^\\\\$/)) {\n        return \"lineContinuation\";\n      }\n      return html(stream, state);\n    }\n    function html(stream, state) {\n      if (stream.match(/^#\\{/)) {\n        state.tokenize = rubyInQuote(\"}\", state.tokenize);\n        return null;\n      }\n      return maybeBackup(stream, state, /[^\\\\]#\\{/, 1, htmlMode.token(stream, state.htmlState));\n    }\n\n    function startHtmlLine(lastTokenize) {\n      return function(stream, state) {\n        var style = htmlLine(stream, state);\n        if (stream.eol()) state.tokenize = lastTokenize;\n        return style;\n      };\n    }\n\n    function startHtmlMode(stream, state, offset) {\n      state.stack = {\n        parent: state.stack,\n        style: \"html\",\n        indented: stream.column() + offset, // pipe + space\n        tokenize: state.line\n      };\n      state.line = state.tokenize = html;\n      return null;\n    }\n\n    function comment(stream, state) {\n      stream.skipToEnd();\n      return state.stack.style;\n    }\n\n    function commentMode(stream, state) {\n      state.stack = {\n        parent: state.stack,\n        style: \"comment\",\n        indented: state.indented + 1,\n        tokenize: state.line\n      };\n      state.line = comment;\n      return comment(stream, state);\n    }\n\n    function attributeWrapper(stream, state) {\n      if (stream.eat(state.stack.endQuote)) {\n        state.line = state.stack.line;\n        state.tokenize = state.stack.tokenize;\n        state.stack = state.stack.parent;\n        return null;\n      }\n      if (stream.match(wrappedAttributeNameRegexp)) {\n        state.tokenize = attributeWrapperAssign;\n        return \"slimAttribute\";\n      }\n      stream.next();\n      return null;\n    }\n    function attributeWrapperAssign(stream, state) {\n      if (stream.match(/^==?/)) {\n        state.tokenize = attributeWrapperValue;\n        return null;\n      }\n      return attributeWrapper(stream, state);\n    }\n    function attributeWrapperValue(stream, state) {\n      var ch = stream.peek();\n      if (ch == '\"' || ch == \"\\'\") {\n        state.tokenize = readQuoted(ch, \"string\", true, false, attributeWrapper);\n        stream.next();\n        return state.tokenize(stream, state);\n      }\n      if (ch == '[') {\n        return startRubySplat(attributeWrapper)(stream, state);\n      }\n      if (stream.match(/^(true|false|nil)\\b/)) {\n        state.tokenize = attributeWrapper;\n        return \"keyword\";\n      }\n      return startRubySplat(attributeWrapper)(stream, state);\n    }\n\n    function startAttributeWrapperMode(state, endQuote, tokenize) {\n      state.stack = {\n        parent: state.stack,\n        style: \"wrapper\",\n        indented: state.indented + 1,\n        tokenize: tokenize,\n        line: state.line,\n        endQuote: endQuote\n      };\n      state.line = state.tokenize = attributeWrapper;\n      return null;\n    }\n\n    function sub(stream, state) {\n      if (stream.match(/^#\\{/)) {\n        state.tokenize = rubyInQuote(\"}\", state.tokenize);\n        return null;\n      }\n      var subStream = new CodeMirror.StringStream(stream.string.slice(state.stack.indented), stream.tabSize);\n      subStream.pos = stream.pos - state.stack.indented;\n      subStream.start = stream.start - state.stack.indented;\n      subStream.lastColumnPos = stream.lastColumnPos - state.stack.indented;\n      subStream.lastColumnValue = stream.lastColumnValue - state.stack.indented;\n      var style = state.subMode.token(subStream, state.subState);\n      stream.pos = subStream.pos + state.stack.indented;\n      return style;\n    }\n    function firstSub(stream, state) {\n      state.stack.indented = stream.column();\n      state.line = state.tokenize = sub;\n      return state.tokenize(stream, state);\n    }\n\n    function createMode(mode) {\n      var query = embedded[mode];\n      var spec = CodeMirror.mimeModes[query];\n      if (spec) {\n        return CodeMirror.getMode(config, spec);\n      }\n      var factory = CodeMirror.modes[query];\n      if (factory) {\n        return factory(config, {name: query});\n      }\n      return CodeMirror.getMode(config, \"null\");\n    }\n\n    function getMode(mode) {\n      if (!modes.hasOwnProperty(mode)) {\n        return modes[mode] = createMode(mode);\n      }\n      return modes[mode];\n    }\n\n    function startSubMode(mode, state) {\n      var subMode = getMode(mode);\n      var subState = subMode.startState && subMode.startState();\n\n      state.subMode = subMode;\n      state.subState = subState;\n\n      state.stack = {\n        parent: state.stack,\n        style: \"sub\",\n        indented: state.indented + 1,\n        tokenize: state.line\n      };\n      state.line = state.tokenize = firstSub;\n      return \"slimSubmode\";\n    }\n\n    function doctypeLine(stream, _state) {\n      stream.skipToEnd();\n      return \"slimDoctype\";\n    }\n\n    function startLine(stream, state) {\n      var ch = stream.peek();\n      if (ch == '<') {\n        return (state.tokenize = startHtmlLine(state.tokenize))(stream, state);\n      }\n      if (stream.match(/^[|']/)) {\n        return startHtmlMode(stream, state, 1);\n      }\n      if (stream.match(/^\\/(!|\\[\\w+])?/)) {\n        return commentMode(stream, state);\n      }\n      if (stream.match(/^(-|==?[<>]?)/)) {\n        state.tokenize = lineContinuable(stream.column(), commaContinuable(stream.column(), ruby));\n        return \"slimSwitch\";\n      }\n      if (stream.match(/^doctype\\b/)) {\n        state.tokenize = doctypeLine;\n        return \"keyword\";\n      }\n\n      var m = stream.match(embeddedRegexp);\n      if (m) {\n        return startSubMode(m[1], state);\n      }\n\n      return slimTag(stream, state);\n    }\n\n    function slim(stream, state) {\n      if (state.startOfLine) {\n        return startLine(stream, state);\n      }\n      return slimTag(stream, state);\n    }\n\n    function slimTag(stream, state) {\n      if (stream.eat('*')) {\n        state.tokenize = startRubySplat(slimTagExtras);\n        return null;\n      }\n      if (stream.match(nameRegexp)) {\n        state.tokenize = slimTagExtras;\n        return \"slimTag\";\n      }\n      return slimClass(stream, state);\n    }\n    function slimTagExtras(stream, state) {\n      if (stream.match(/^(<>?|><?)/)) {\n        state.tokenize = slimClass;\n        return null;\n      }\n      return slimClass(stream, state);\n    }\n    function slimClass(stream, state) {\n      if (stream.match(classIdRegexp)) {\n        state.tokenize = slimClass;\n        return \"slimId\";\n      }\n      if (stream.match(classNameRegexp)) {\n        state.tokenize = slimClass;\n        return \"slimClass\";\n      }\n      return slimAttribute(stream, state);\n    }\n    function slimAttribute(stream, state) {\n      if (stream.match(/^([\\[\\{\\(])/)) {\n        return startAttributeWrapperMode(state, closing[RegExp.$1], slimAttribute);\n      }\n      if (stream.match(attributeNameRegexp)) {\n        state.tokenize = slimAttributeAssign;\n        return \"slimAttribute\";\n      }\n      if (stream.peek() == '*') {\n        stream.next();\n        state.tokenize = startRubySplat(slimContent);\n        return null;\n      }\n      return slimContent(stream, state);\n    }\n    function slimAttributeAssign(stream, state) {\n      if (stream.match(/^==?/)) {\n        state.tokenize = slimAttributeValue;\n        return null;\n      }\n      // should never happen, because of forward lookup\n      return slimAttribute(stream, state);\n    }\n\n    function slimAttributeValue(stream, state) {\n      var ch = stream.peek();\n      if (ch == '\"' || ch == \"\\'\") {\n        state.tokenize = readQuoted(ch, \"string\", true, false, slimAttribute);\n        stream.next();\n        return state.tokenize(stream, state);\n      }\n      if (ch == '[') {\n        return startRubySplat(slimAttribute)(stream, state);\n      }\n      if (ch == ':') {\n        return startRubySplat(slimAttributeSymbols)(stream, state);\n      }\n      if (stream.match(/^(true|false|nil)\\b/)) {\n        state.tokenize = slimAttribute;\n        return \"keyword\";\n      }\n      return startRubySplat(slimAttribute)(stream, state);\n    }\n    function slimAttributeSymbols(stream, state) {\n      stream.backUp(1);\n      if (stream.match(/^[^\\s],(?=:)/)) {\n        state.tokenize = startRubySplat(slimAttributeSymbols);\n        return null;\n      }\n      stream.next();\n      return slimAttribute(stream, state);\n    }\n    function readQuoted(quote, style, embed, unescaped, nextTokenize) {\n      return function(stream, state) {\n        finishContinue(state);\n        var fresh = stream.current().length == 0;\n        if (stream.match(/^\\\\$/, fresh)) {\n          if (!fresh) return style;\n          continueLine(state, state.indented);\n          return \"lineContinuation\";\n        }\n        if (stream.match(/^#\\{/, fresh)) {\n          if (!fresh) return style;\n          state.tokenize = rubyInQuote(\"}\", state.tokenize);\n          return null;\n        }\n        var escaped = false, ch;\n        while ((ch = stream.next()) != null) {\n          if (ch == quote && (unescaped || !escaped)) {\n            state.tokenize = nextTokenize;\n            break;\n          }\n          if (embed && ch == \"#\" && !escaped) {\n            if (stream.eat(\"{\")) {\n              stream.backUp(2);\n              break;\n            }\n          }\n          escaped = !escaped && ch == \"\\\\\";\n        }\n        if (stream.eol() && escaped) {\n          stream.backUp(1);\n        }\n        return style;\n      };\n    }\n    function slimContent(stream, state) {\n      if (stream.match(/^==?/)) {\n        state.tokenize = ruby;\n        return \"slimSwitch\";\n      }\n      if (stream.match(/^\\/$/)) { // tag close hint\n        state.tokenize = slim;\n        return null;\n      }\n      if (stream.match(/^:/)) { // inline tag\n        state.tokenize = slimTag;\n        return \"slimSwitch\";\n      }\n      startHtmlMode(stream, state, 0);\n      return state.tokenize(stream, state);\n    }\n\n    var mode = {\n      // default to html mode\n      startState: function() {\n        var htmlState = htmlMode.startState();\n        var rubyState = rubyMode.startState();\n        return {\n          htmlState: htmlState,\n          rubyState: rubyState,\n          stack: null,\n          last: null,\n          tokenize: slim,\n          line: slim,\n          indented: 0\n        };\n      },\n\n      copyState: function(state) {\n        return {\n          htmlState : CodeMirror.copyState(htmlMode, state.htmlState),\n          rubyState: CodeMirror.copyState(rubyMode, state.rubyState),\n          subMode: state.subMode,\n          subState: state.subMode && CodeMirror.copyState(state.subMode, state.subState),\n          stack: state.stack,\n          last: state.last,\n          tokenize: state.tokenize,\n          line: state.line\n        };\n      },\n\n      token: function(stream, state) {\n        if (stream.sol()) {\n          state.indented = stream.indentation();\n          state.startOfLine = true;\n          state.tokenize = state.line;\n          while (state.stack && state.stack.indented > state.indented && state.last != \"slimSubmode\") {\n            state.line = state.tokenize = state.stack.tokenize;\n            state.stack = state.stack.parent;\n            state.subMode = null;\n            state.subState = null;\n          }\n        }\n        if (stream.eatSpace()) return null;\n        var style = state.tokenize(stream, state);\n        state.startOfLine = false;\n        if (style) state.last = style;\n        return styleMap.hasOwnProperty(style) ? styleMap[style] : style;\n      },\n\n      blankLine: function(state) {\n        if (state.subMode && state.subMode.blankLine) {\n          return state.subMode.blankLine(state.subState);\n        }\n      },\n\n      innerMode: function(state) {\n        if (state.subMode) return {state: state.subState, mode: state.subMode};\n        return {state: state, mode: mode};\n      }\n\n      //indent: function(state) {\n      //  return state.indented;\n      //}\n    };\n    return mode;\n  }, \"htmlmixed\", \"ruby\");\n\n  CodeMirror.defineMIME(\"text/x-slim\", \"slim\");\n  CodeMirror.defineMIME(\"application/x-slim\", \"slim\");\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/slim/test.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n// Slim Highlighting for CodeMirror copyright (c) HicknHack Software Gmbh\n\n(function() {\n  var mode = CodeMirror.getMode({tabSize: 4, indentUnit: 2}, \"slim\");\n  function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); }\n\n  // Requires at least one media query\n  MT(\"elementName\",\n     \"[tag h1] Hey There\");\n\n  MT(\"oneElementPerLine\",\n     \"[tag h1] Hey There .h2\");\n\n  MT(\"idShortcut\",\n     \"[attribute&def #test] Hey There\");\n\n  MT(\"tagWithIdShortcuts\",\n     \"[tag h1][attribute&def #test] Hey There\");\n\n  MT(\"classShortcut\",\n     \"[attribute&qualifier .hello] Hey There\");\n\n  MT(\"tagWithIdAndClassShortcuts\",\n     \"[tag h1][attribute&def #test][attribute&qualifier .hello] Hey There\");\n\n  MT(\"docType\",\n     \"[keyword doctype] xml\");\n\n  MT(\"comment\",\n     \"[comment / Hello WORLD]\");\n\n  MT(\"notComment\",\n     \"[tag h1] This is not a / comment \");\n\n  MT(\"attributes\",\n     \"[tag a]([attribute title]=[string \\\"test\\\"]) [attribute href]=[string \\\"link\\\"]}\");\n\n  MT(\"multiLineAttributes\",\n     \"[tag a]([attribute title]=[string \\\"test\\\"]\",\n     \"  ) [attribute href]=[string \\\"link\\\"]}\");\n\n  MT(\"htmlCode\",\n     \"[tag&bracket <][tag h1][tag&bracket >]Title[tag&bracket </][tag h1][tag&bracket >]\");\n\n  MT(\"rubyBlock\",\n     \"[operator&special =][variable-2 @item]\");\n\n  MT(\"selectorRubyBlock\",\n     \"[tag a][attribute&qualifier .test][operator&special =] [variable-2 @item]\");\n\n  MT(\"nestedRubyBlock\",\n      \"[tag a]\",\n      \"  [operator&special =][variable puts] [string \\\"test\\\"]\");\n\n  MT(\"multilinePlaintext\",\n      \"[tag p]\",\n      \"  | Hello,\",\n      \"    World\");\n\n  MT(\"multilineRuby\",\n      \"[tag p]\",\n      \"  [comment /# this is a comment]\",\n      \"     [comment and this is a comment too]\",\n      \"  | Date/Time\",\n      \"  [operator&special -] [variable now] [operator =] [tag DateTime][operator .][property now]\",\n      \"  [tag strong][operator&special =] [variable now]\",\n      \"  [operator&special -] [keyword if] [variable now] [operator >] [tag DateTime][operator .][property parse]([string \\\"December 31, 2006\\\"])\",\n      \"     [operator&special =][string \\\"Happy\\\"]\",\n      \"     [operator&special =][string \\\"Belated\\\"]\",\n      \"     [operator&special =][string \\\"Birthday\\\"]\");\n\n  MT(\"multilineComment\",\n      \"[comment /]\",\n      \"  [comment Multiline]\",\n      \"  [comment Comment]\");\n\n  MT(\"hamlAfterRubyTag\",\n    \"[attribute&qualifier .block]\",\n    \"  [tag strong][operator&special =] [variable now]\",\n    \"  [attribute&qualifier .test]\",\n    \"     [operator&special =][variable now]\",\n    \"  [attribute&qualifier .right]\");\n\n  MT(\"stretchedRuby\",\n     \"[operator&special =] [variable puts] [string \\\"Hello\\\"],\",\n     \"   [string \\\"World\\\"]\");\n\n  MT(\"interpolationInHashAttribute\",\n     \"[tag div]{[attribute id] = [string \\\"]#{[variable test]}[string _]#{[variable ting]}[string \\\"]} test\");\n\n  MT(\"interpolationInHTMLAttribute\",\n     \"[tag div]([attribute title]=[string \\\"]#{[variable test]}[string _]#{[variable ting]()}[string \\\"]) Test\");\n})();\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/smalltalk/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Smalltalk mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"../../addon/edit/matchbrackets.js\"></script>\n<script src=\"smalltalk.js\"></script>\n<style>\n      .CodeMirror {border: 2px solid #dee; border-right-width: 10px;}\n      .CodeMirror-gutter {border: none; background: #dee;}\n      .CodeMirror-gutter pre {color: white; font-weight: bold;}\n    </style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Smalltalk</a>\n  </ul>\n</div>\n\n<article>\n<h2>Smalltalk mode</h2>\n<form><textarea id=\"code\" name=\"code\">\n\" \n    This is a test of the Smalltalk code\n\"\nSeaside.WAComponent subclass: #MyCounter [\n    | count |\n    MyCounter class &gt;&gt; canBeRoot [ ^true ]\n\n    initialize [\n        super initialize.\n        count := 0.\n    ]\n    states [ ^{ self } ]\n    renderContentOn: html [\n        html heading: count.\n        html anchor callback: [ count := count + 1 ]; with: '++'.\n        html space.\n        html anchor callback: [ count := count - 1 ]; with: '--'.\n    ]\n]\n\nMyCounter registerAsApplication: 'mycounter'\n</textarea></form>\n\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        lineNumbers: true,\n        matchBrackets: true,\n        mode: \"text/x-stsrc\",\n        indentUnit: 4\n      });\n    </script>\n\n    <p>Simple Smalltalk mode.</p>\n\n    <p><strong>MIME types defined:</strong> <code>text/x-stsrc</code>.</p>\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/smalltalk/smalltalk.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode('smalltalk', function(config) {\n\n  var specialChars = /[+\\-\\/\\\\*~<>=@%|&?!.,:;^]/;\n  var keywords = /true|false|nil|self|super|thisContext/;\n\n  var Context = function(tokenizer, parent) {\n    this.next = tokenizer;\n    this.parent = parent;\n  };\n\n  var Token = function(name, context, eos) {\n    this.name = name;\n    this.context = context;\n    this.eos = eos;\n  };\n\n  var State = function() {\n    this.context = new Context(next, null);\n    this.expectVariable = true;\n    this.indentation = 0;\n    this.userIndentationDelta = 0;\n  };\n\n  State.prototype.userIndent = function(indentation) {\n    this.userIndentationDelta = indentation > 0 ? (indentation / config.indentUnit - this.indentation) : 0;\n  };\n\n  var next = function(stream, context, state) {\n    var token = new Token(null, context, false);\n    var aChar = stream.next();\n\n    if (aChar === '\"') {\n      token = nextComment(stream, new Context(nextComment, context));\n\n    } else if (aChar === '\\'') {\n      token = nextString(stream, new Context(nextString, context));\n\n    } else if (aChar === '#') {\n      if (stream.peek() === '\\'') {\n        stream.next();\n        token = nextSymbol(stream, new Context(nextSymbol, context));\n      } else {\n        if (stream.eatWhile(/[^\\s.{}\\[\\]()]/))\n          token.name = 'string-2';\n        else\n          token.name = 'meta';\n      }\n\n    } else if (aChar === '$') {\n      if (stream.next() === '<') {\n        stream.eatWhile(/[^\\s>]/);\n        stream.next();\n      }\n      token.name = 'string-2';\n\n    } else if (aChar === '|' && state.expectVariable) {\n      token.context = new Context(nextTemporaries, context);\n\n    } else if (/[\\[\\]{}()]/.test(aChar)) {\n      token.name = 'bracket';\n      token.eos = /[\\[{(]/.test(aChar);\n\n      if (aChar === '[') {\n        state.indentation++;\n      } else if (aChar === ']') {\n        state.indentation = Math.max(0, state.indentation - 1);\n      }\n\n    } else if (specialChars.test(aChar)) {\n      stream.eatWhile(specialChars);\n      token.name = 'operator';\n      token.eos = aChar !== ';'; // ; cascaded message expression\n\n    } else if (/\\d/.test(aChar)) {\n      stream.eatWhile(/[\\w\\d]/);\n      token.name = 'number';\n\n    } else if (/[\\w_]/.test(aChar)) {\n      stream.eatWhile(/[\\w\\d_]/);\n      token.name = state.expectVariable ? (keywords.test(stream.current()) ? 'keyword' : 'variable') : null;\n\n    } else {\n      token.eos = state.expectVariable;\n    }\n\n    return token;\n  };\n\n  var nextComment = function(stream, context) {\n    stream.eatWhile(/[^\"]/);\n    return new Token('comment', stream.eat('\"') ? context.parent : context, true);\n  };\n\n  var nextString = function(stream, context) {\n    stream.eatWhile(/[^']/);\n    return new Token('string', stream.eat('\\'') ? context.parent : context, false);\n  };\n\n  var nextSymbol = function(stream, context) {\n    stream.eatWhile(/[^']/);\n    return new Token('string-2', stream.eat('\\'') ? context.parent : context, false);\n  };\n\n  var nextTemporaries = function(stream, context) {\n    var token = new Token(null, context, false);\n    var aChar = stream.next();\n\n    if (aChar === '|') {\n      token.context = context.parent;\n      token.eos = true;\n\n    } else {\n      stream.eatWhile(/[^|]/);\n      token.name = 'variable';\n    }\n\n    return token;\n  };\n\n  return {\n    startState: function() {\n      return new State;\n    },\n\n    token: function(stream, state) {\n      state.userIndent(stream.indentation());\n\n      if (stream.eatSpace()) {\n        return null;\n      }\n\n      var token = state.context.next(stream, state.context, state);\n      state.context = token.context;\n      state.expectVariable = token.eos;\n\n      return token.name;\n    },\n\n    blankLine: function(state) {\n      state.userIndent(0);\n    },\n\n    indent: function(state, textAfter) {\n      var i = state.context.next === next && textAfter && textAfter.charAt(0) === ']' ? -1 : state.userIndentationDelta;\n      return (state.indentation + i) * config.indentUnit;\n    },\n\n    electricChars: ']'\n  };\n\n});\n\nCodeMirror.defineMIME('text/x-stsrc', {name: 'smalltalk'});\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/smarty/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Smarty mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"smarty.js\"></script>\n<style type=\"text/css\">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Smarty</a>\n  </ul>\n</div>\n\n<article>\n<h2>Smarty mode</h2>\n<form><textarea id=\"code\" name=\"code\">\n{extends file=\"parent.tpl\"}\n{include file=\"template.tpl\"}\n\n{* some example Smarty content *}\n{if isset($name) && $name == 'Blog'}\n  This is a {$var}.\n  {$integer = 451}, {$array[] = \"a\"}, {$stringvar = \"string\"}\n  {assign var='bob' value=$var.prop}\n{elseif $name == $foo}\n  {function name=menu level=0}\n    {foreach $data as $entry}\n      {if is_array($entry)}\n        - {$entry@key}\n        {menu data=$entry level=$level+1}\n      {else}\n        {$entry}\n      {/if}\n    {/foreach}\n  {/function}\n{/if}</textarea></form>\n\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        lineNumbers: true,\n        mode: \"smarty\"\n      });\n    </script>\n\n    <br />\n\n\t<h3>Smarty 2, custom delimiters</h3>\n    <form><textarea id=\"code2\" name=\"code2\">\n{--extends file=\"parent.tpl\"--}\n{--include file=\"template.tpl\"--}\n\n{--* some example Smarty content *--}\n{--if isset($name) && $name == 'Blog'--}\n  This is a {--$var--}.\n  {--$integer = 451--}, {--$array[] = \"a\"--}, {--$stringvar = \"string\"--}\n  {--assign var='bob' value=$var.prop--}\n{--elseif $name == $foo--}\n  {--function name=menu level=0--}\n    {--foreach $data as $entry--}\n      {--if is_array($entry)--}\n        - {--$entry@key--}\n        {--menu data=$entry level=$level+1--}\n      {--else--}\n        {--$entry--}\n      {--/if--}\n    {--/foreach--}\n  {--/function--}\n{--/if--}</textarea></form>\n\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code2\"), {\n        lineNumbers: true,\n        mode: {\n          name: \"smarty\",\n          leftDelimiter: \"{--\",\n          rightDelimiter: \"--}\"\n        }\n      });\n    </script>\n\n\t<br />\n\n\t<h3>Smarty 3</h3>\n\n\t<textarea id=\"code3\" name=\"code3\">\nNested tags {$foo={counter one=1 two={inception}}+3} are now valid in Smarty 3.\n\n<script>\nfunction test() {\n\tconsole.log(\"Smarty 3 permits single curly braces followed by whitespace to NOT slip into Smarty mode.\");\n}\n</script>\n\n{assign var=foo value=[1,2,3]}\n{assign var=foo value=['y'=>'yellow','b'=>'blue']}\n{assign var=foo value=[1,[9,8],3]}\n\n{$foo=$bar+2} {* a comment *}\n{$foo.bar=1}  {* another comment *}\n{$foo = myfunct(($x+$y)*3)}\n{$foo = strlen($bar)}\n{$foo.bar.baz=1}, {$foo[]=1}\n\nSmarty \"dot\" syntax (note: embedded {} are used to address ambiguities):\n\n{$foo.a.b.c}      => $foo['a']['b']['c']\n{$foo.a.$b.c}     => $foo['a'][$b]['c']\n{$foo.a.{$b+4}.c} => $foo['a'][$b+4]['c']\n{$foo.a.{$b.c}}   => $foo['a'][$b['c']]\n\n{$object->method1($x)->method2($y)}</textarea>\n\n\t<script>\n\t\tvar editor = CodeMirror.fromTextArea(document.getElementById(\"code3\"), {\n\t\t\tlineNumbers: true,\n\t\t\tmode: \"smarty\",\n\t\t\tsmartyVersion: 3\n\t\t});\n\t</script>\n\n\n    <p>A plain text/Smarty version 2 or 3 mode, which allows for custom delimiter tags.</p>\n\n    <p><strong>MIME types defined:</strong> <code>text/x-smarty</code></p>\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/smarty/smarty.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n/**\n * Smarty 2 and 3 mode.\n */\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"smarty\", function(config) {\n  \"use strict\";\n\n  // our default settings; check to see if they're overridden\n  var settings = {\n    rightDelimiter: '}',\n    leftDelimiter: '{',\n    smartyVersion: 2 // for backward compatibility\n  };\n  if (config.hasOwnProperty(\"leftDelimiter\")) {\n    settings.leftDelimiter = config.leftDelimiter;\n  }\n  if (config.hasOwnProperty(\"rightDelimiter\")) {\n    settings.rightDelimiter = config.rightDelimiter;\n  }\n  if (config.hasOwnProperty(\"smartyVersion\") && config.smartyVersion === 3) {\n    settings.smartyVersion = 3;\n  }\n\n  var keyFunctions = [\"debug\", \"extends\", \"function\", \"include\", \"literal\"];\n  var last;\n  var regs = {\n    operatorChars: /[+\\-*&%=<>!?]/,\n    validIdentifier: /[a-zA-Z0-9_]/,\n    stringChar: /['\"]/\n  };\n\n  var helpers = {\n    cont: function(style, lastType) {\n      last = lastType;\n      return style;\n    },\n    chain: function(stream, state, parser) {\n      state.tokenize = parser;\n      return parser(stream, state);\n    }\n  };\n\n\n  // our various parsers\n  var parsers = {\n\n    // the main tokenizer\n    tokenizer: function(stream, state) {\n      if (stream.match(settings.leftDelimiter, true)) {\n        if (stream.eat(\"*\")) {\n          return helpers.chain(stream, state, parsers.inBlock(\"comment\", \"*\" + settings.rightDelimiter));\n        } else {\n          // Smarty 3 allows { and } surrounded by whitespace to NOT slip into Smarty mode\n          state.depth++;\n          var isEol = stream.eol();\n          var isFollowedByWhitespace = /\\s/.test(stream.peek());\n          if (settings.smartyVersion === 3 && settings.leftDelimiter === \"{\" && (isEol || isFollowedByWhitespace)) {\n            state.depth--;\n            return null;\n          } else {\n            state.tokenize = parsers.smarty;\n            last = \"startTag\";\n            return \"tag\";\n          }\n        }\n      } else {\n        stream.next();\n        return null;\n      }\n    },\n\n    // parsing Smarty content\n    smarty: function(stream, state) {\n      if (stream.match(settings.rightDelimiter, true)) {\n        if (settings.smartyVersion === 3) {\n          state.depth--;\n          if (state.depth <= 0) {\n            state.tokenize = parsers.tokenizer;\n          }\n        } else {\n          state.tokenize = parsers.tokenizer;\n        }\n        return helpers.cont(\"tag\", null);\n      }\n\n      if (stream.match(settings.leftDelimiter, true)) {\n        state.depth++;\n        return helpers.cont(\"tag\", \"startTag\");\n      }\n\n      var ch = stream.next();\n      if (ch == \"$\") {\n        stream.eatWhile(regs.validIdentifier);\n        return helpers.cont(\"variable-2\", \"variable\");\n      } else if (ch == \"|\") {\n        return helpers.cont(\"operator\", \"pipe\");\n      } else if (ch == \".\") {\n        return helpers.cont(\"operator\", \"property\");\n      } else if (regs.stringChar.test(ch)) {\n        state.tokenize = parsers.inAttribute(ch);\n        return helpers.cont(\"string\", \"string\");\n      } else if (regs.operatorChars.test(ch)) {\n        stream.eatWhile(regs.operatorChars);\n        return helpers.cont(\"operator\", \"operator\");\n      } else if (ch == \"[\" || ch == \"]\") {\n        return helpers.cont(\"bracket\", \"bracket\");\n      } else if (ch == \"(\" || ch == \")\") {\n        return helpers.cont(\"bracket\", \"operator\");\n      } else if (/\\d/.test(ch)) {\n        stream.eatWhile(/\\d/);\n        return helpers.cont(\"number\", \"number\");\n      } else {\n\n        if (state.last == \"variable\") {\n          if (ch == \"@\") {\n            stream.eatWhile(regs.validIdentifier);\n            return helpers.cont(\"property\", \"property\");\n          } else if (ch == \"|\") {\n            stream.eatWhile(regs.validIdentifier);\n            return helpers.cont(\"qualifier\", \"modifier\");\n          }\n        } else if (state.last == \"pipe\") {\n          stream.eatWhile(regs.validIdentifier);\n          return helpers.cont(\"qualifier\", \"modifier\");\n        } else if (state.last == \"whitespace\") {\n          stream.eatWhile(regs.validIdentifier);\n          return helpers.cont(\"attribute\", \"modifier\");\n        } if (state.last == \"property\") {\n          stream.eatWhile(regs.validIdentifier);\n          return helpers.cont(\"property\", null);\n        } else if (/\\s/.test(ch)) {\n          last = \"whitespace\";\n          return null;\n        }\n\n        var str = \"\";\n        if (ch != \"/\") {\n          str += ch;\n        }\n        var c = null;\n        while (c = stream.eat(regs.validIdentifier)) {\n          str += c;\n        }\n        for (var i=0, j=keyFunctions.length; i<j; i++) {\n          if (keyFunctions[i] == str) {\n            return helpers.cont(\"keyword\", \"keyword\");\n          }\n        }\n        if (/\\s/.test(ch)) {\n          return null;\n        }\n        return helpers.cont(\"tag\", \"tag\");\n      }\n    },\n\n    inAttribute: function(quote) {\n      return function(stream, state) {\n        var prevChar = null;\n        var currChar = null;\n        while (!stream.eol()) {\n          currChar = stream.peek();\n          if (stream.next() == quote && prevChar !== '\\\\') {\n            state.tokenize = parsers.smarty;\n            break;\n          }\n          prevChar = currChar;\n        }\n        return \"string\";\n      };\n    },\n\n    inBlock: function(style, terminator) {\n      return function(stream, state) {\n        while (!stream.eol()) {\n          if (stream.match(terminator)) {\n            state.tokenize = parsers.tokenizer;\n            break;\n          }\n          stream.next();\n        }\n        return style;\n      };\n    }\n  };\n\n\n  // the public API for CodeMirror\n  return {\n    startState: function() {\n      return {\n        tokenize: parsers.tokenizer,\n        mode: \"smarty\",\n        last: null,\n        depth: 0\n      };\n    },\n    token: function(stream, state) {\n      var style = state.tokenize(stream, state);\n      state.last = last;\n      return style;\n    },\n    electricChars: \"\"\n  };\n});\n\nCodeMirror.defineMIME(\"text/x-smarty\", \"smarty\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/smartymixed/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Smarty mixed mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"../../mode/xml/xml.js\"></script>\n<script src=\"../../mode/javascript/javascript.js\"></script>\n<script src=\"../../mode/css/css.js\"></script>\n<script src=\"../../mode/htmlmixed/htmlmixed.js\"></script>\n<script src=\"../../mode/smarty/smarty.js\"></script>\n<script src=\"../../mode/smartymixed/smartymixed.js\"></script>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Smarty mixed</a>\n  </ul>\n</div>\n\n<article>\n<h2>Smarty mixed mode</h2>\n<form><textarea id=\"code\" name=\"code\">\n{**\n* @brief Smarty mixed mode\n* @author Ruslan Osmanov\n* @date 29.06.2013\n*}\n<html>\n<head>\n  <title>{$title|htmlspecialchars|truncate:30}</title>\n</head>\n<body class=\"{$bodyclass}\">\n  {* Multiline smarty\n  * comment, no {$variables} here\n  *}\n  {literal}\n  {literal} is just an HTML text.\n  <script type=\"text/javascript\">//<![CDATA[\n    var a = {$just_a_normal_js_object : \"value\"};\n    var myCodeMirror = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n      mode           : \"smartymixed\",\n      tabSize        : 2,\n      indentUnit     : 2,\n      indentWithTabs : false,\n      lineNumbers    : true,\n      smartyVersion  : 3\n    });\n    // ]]>\n  </script>\n  <style>\n    /* CSS content \n    {$no_smarty} */\n    .some-class { font-weight: bolder; color: \"orange\"; }\n  </style>\n  {/literal}\n\n  {extends file=\"parent.tpl\"}\n  {include file=\"template.tpl\"}\n\n  {* some example Smarty content *}\n  {if isset($name) && $name == 'Blog'}\n    This is a {$var}.\n    {$integer = 4511}, {$array[] = \"a\"}, {$stringvar = \"string\"}\n    {$integer = 4512} {$array[] = \"a\"} {$stringvar = \"string\"}\n    {assign var='bob' value=$var.prop}\n  {elseif $name == $foo}\n    {function name=menu level=0}\n    {foreach $data as $entry}\n      {if is_array($entry)}\n      - {$entry@key}\n      {menu data=$entry level=$level+1}\n      {else}\n      {$entry}\n      {* One\n      * Two\n      * Three\n      *}\n      {/if}\n    {/foreach}\n    {/function}\n  {/if}\n  </body>\n  <!-- R.O. -->\n</html>\n</textarea></form>\n\n    <script type=\"text/javascript\">\n      var myCodeMirror = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        mode           : \"smartymixed\",\n        tabSize        : 2,\n        indentUnit     : 2,\n        indentWithTabs : false,\n        lineNumbers    : true,\n        smartyVersion  : 3,\n        matchBrackets  : true,\n      });\n    </script>\n\n    <p>The Smarty mixed mode depends on the Smarty and HTML mixed modes. HTML\n    mixed mode itself depends on XML, JavaScript, and CSS modes.</p>\n\n    <p>It takes the same options, as Smarty and HTML mixed modes.</p>\n\n    <p><strong>MIME types defined:</strong> <code>text/x-smarty</code>.</p>\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/smartymixed/smartymixed.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n/**\n* @file smartymixed.js\n* @brief Smarty Mixed Codemirror mode (Smarty + Mixed HTML)\n* @author Ruslan Osmanov <rrosmanov at gmail dot com>\n* @version 3.0\n* @date 05.07.2013\n*/\n\n// Warning: Don't base other modes on this one. This here is a\n// terrible way to write a mixed mode.\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"), require(\"../htmlmixed/htmlmixed\"), require(\"../smarty/smarty\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\", \"../htmlmixed/htmlmixed\", \"../smarty/smarty\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"smartymixed\", function(config) {\n  var htmlMixedMode = CodeMirror.getMode(config, \"htmlmixed\");\n  var smartyMode = CodeMirror.getMode(config, \"smarty\");\n\n  var settings = {\n    rightDelimiter: '}',\n    leftDelimiter: '{'\n  };\n\n  if (config.hasOwnProperty(\"leftDelimiter\")) {\n    settings.leftDelimiter = config.leftDelimiter;\n  }\n  if (config.hasOwnProperty(\"rightDelimiter\")) {\n    settings.rightDelimiter = config.rightDelimiter;\n  }\n\n  function reEsc(str) { return str.replace(/[^\\s\\w]/g, \"\\\\$&\"); }\n\n  var reLeft = reEsc(settings.leftDelimiter), reRight = reEsc(settings.rightDelimiter);\n  var regs = {\n    smartyComment: new RegExp(\"^\" + reRight + \"\\\\*\"),\n    literalOpen: new RegExp(reLeft + \"literal\" + reRight),\n    literalClose: new RegExp(reLeft + \"\\/literal\" + reRight),\n    hasLeftDelimeter: new RegExp(\".*\" + reLeft),\n    htmlHasLeftDelimeter: new RegExp(\"[^<>]*\" + reLeft)\n  };\n\n  var helpers = {\n    chain: function(stream, state, parser) {\n      state.tokenize = parser;\n      return parser(stream, state);\n    },\n\n    cleanChain: function(stream, state, parser) {\n      state.tokenize = null;\n      state.localState = null;\n      state.localMode = null;\n      return (typeof parser == \"string\") ? (parser ? parser : null) : parser(stream, state);\n    },\n\n    maybeBackup: function(stream, pat, style) {\n      var cur = stream.current();\n      var close = cur.search(pat),\n      m;\n      if (close > - 1) stream.backUp(cur.length - close);\n      else if (m = cur.match(/<\\/?$/)) {\n        stream.backUp(cur.length);\n        if (!stream.match(pat, false)) stream.match(cur[0]);\n      }\n      return style;\n    }\n  };\n\n  var parsers = {\n    html: function(stream, state) {\n      var htmlTagName = state.htmlMixedState.htmlState.context && state.htmlMixedState.htmlState.context.tagName\n        ? state.htmlMixedState.htmlState.context.tagName\n        : null;\n\n      if (!state.inLiteral && stream.match(regs.htmlHasLeftDelimeter, false) && htmlTagName === null) {\n        state.tokenize = parsers.smarty;\n        state.localMode = smartyMode;\n        state.localState = smartyMode.startState(htmlMixedMode.indent(state.htmlMixedState, \"\"));\n        return helpers.maybeBackup(stream, settings.leftDelimiter, smartyMode.token(stream, state.localState));\n      } else if (!state.inLiteral && stream.match(settings.leftDelimiter, false)) {\n        state.tokenize = parsers.smarty;\n        state.localMode = smartyMode;\n        state.localState = smartyMode.startState(htmlMixedMode.indent(state.htmlMixedState, \"\"));\n        return helpers.maybeBackup(stream, settings.leftDelimiter, smartyMode.token(stream, state.localState));\n      }\n      return htmlMixedMode.token(stream, state.htmlMixedState);\n    },\n\n    smarty: function(stream, state) {\n      if (stream.match(settings.leftDelimiter, false)) {\n        if (stream.match(regs.smartyComment, false)) {\n          return helpers.chain(stream, state, parsers.inBlock(\"comment\", \"*\" + settings.rightDelimiter));\n        }\n      } else if (stream.match(settings.rightDelimiter, false)) {\n        stream.eat(settings.rightDelimiter);\n        state.tokenize = parsers.html;\n        state.localMode = htmlMixedMode;\n        state.localState = state.htmlMixedState;\n        return \"tag\";\n      }\n\n      return helpers.maybeBackup(stream, settings.rightDelimiter, smartyMode.token(stream, state.localState));\n    },\n\n    inBlock: function(style, terminator) {\n      return function(stream, state) {\n        while (!stream.eol()) {\n          if (stream.match(terminator)) {\n            helpers.cleanChain(stream, state, \"\");\n            break;\n          }\n          stream.next();\n        }\n        return style;\n      };\n    }\n  };\n\n  return {\n    startState: function() {\n      var state = htmlMixedMode.startState();\n      return {\n        token: parsers.html,\n        localMode: null,\n        localState: null,\n        htmlMixedState: state,\n        tokenize: null,\n        inLiteral: false\n      };\n    },\n\n    copyState: function(state) {\n      var local = null, tok = (state.tokenize || state.token);\n      if (state.localState) {\n        local = CodeMirror.copyState((tok != parsers.html ? smartyMode : htmlMixedMode), state.localState);\n      }\n      return {\n        token: state.token,\n        tokenize: state.tokenize,\n        localMode: state.localMode,\n        localState: local,\n        htmlMixedState: CodeMirror.copyState(htmlMixedMode, state.htmlMixedState),\n        inLiteral: state.inLiteral\n      };\n    },\n\n    token: function(stream, state) {\n      if (stream.match(settings.leftDelimiter, false)) {\n        if (!state.inLiteral && stream.match(regs.literalOpen, true)) {\n          state.inLiteral = true;\n          return \"keyword\";\n        } else if (state.inLiteral && stream.match(regs.literalClose, true)) {\n          state.inLiteral = false;\n          return \"keyword\";\n        }\n      }\n      if (state.inLiteral && state.localState != state.htmlMixedState) {\n        state.tokenize = parsers.html;\n        state.localMode = htmlMixedMode;\n        state.localState = state.htmlMixedState;\n      }\n\n      var style = (state.tokenize || state.token)(stream, state);\n      return style;\n    },\n\n    indent: function(state, textAfter) {\n      if (state.localMode == smartyMode\n          || (state.inLiteral && !state.localMode)\n         || regs.hasLeftDelimeter.test(textAfter)) {\n        return CodeMirror.Pass;\n      }\n      return htmlMixedMode.indent(state.htmlMixedState, textAfter);\n    },\n\n    innerMode: function(state) {\n      return {\n        state: state.localState || state.htmlMixedState,\n        mode: state.localMode || htmlMixedMode\n      };\n    }\n  };\n}, \"htmlmixed\", \"smarty\");\n\nCodeMirror.defineMIME(\"text/x-smarty\", \"smartymixed\");\n// vim: et ts=2 sts=2 sw=2\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/solr/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Solr mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"solr.js\"></script>\n<style type=\"text/css\">\n  .CodeMirror {\n    border-top: 1px solid black;\n    border-bottom: 1px solid black;\n  }\n\n  .CodeMirror .cm-operator {\n    color: orange;\n  }\n</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Solr</a>\n  </ul>\n</div>\n\n<article>\n  <h2>Solr mode</h2>\n\n  <div>\n    <textarea id=\"code\" name=\"code\">author:Camus\n\ntitle:\"The Rebel\" and author:Camus\n\nphilosophy:Existentialism -author:Kierkegaard\n\nhardToSpell:Dostoevsky~\n\npublished:[194* TO 1960] and author:(Sartre or \"Simone de Beauvoir\")</textarea>\n  </div>\n\n  <script>\n    var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n      mode: 'solr',\n      lineNumbers: true\n    });\n  </script>\n\n  <p><strong>MIME types defined:</strong> <code>text/x-solr</code>.</p>\n</article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/solr/solr.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"solr\", function() {\n  \"use strict\";\n\n  var isStringChar = /[^\\s\\|\\!\\+\\-\\*\\?\\~\\^\\&\\:\\(\\)\\[\\]\\{\\}\\^\\\"\\\\]/;\n  var isOperatorChar = /[\\|\\!\\+\\-\\*\\?\\~\\^\\&]/;\n  var isOperatorString = /^(OR|AND|NOT|TO)$/i;\n\n  function isNumber(word) {\n    return parseFloat(word, 10).toString() === word;\n  }\n\n  function tokenString(quote) {\n    return function(stream, state) {\n      var escaped = false, next;\n      while ((next = stream.next()) != null) {\n        if (next == quote && !escaped) break;\n        escaped = !escaped && next == \"\\\\\";\n      }\n\n      if (!escaped) state.tokenize = tokenBase;\n      return \"string\";\n    };\n  }\n\n  function tokenOperator(operator) {\n    return function(stream, state) {\n      var style = \"operator\";\n      if (operator == \"+\")\n        style += \" positive\";\n      else if (operator == \"-\")\n        style += \" negative\";\n      else if (operator == \"|\")\n        stream.eat(/\\|/);\n      else if (operator == \"&\")\n        stream.eat(/\\&/);\n      else if (operator == \"^\")\n        style += \" boost\";\n\n      state.tokenize = tokenBase;\n      return style;\n    };\n  }\n\n  function tokenWord(ch) {\n    return function(stream, state) {\n      var word = ch;\n      while ((ch = stream.peek()) && ch.match(isStringChar) != null) {\n        word += stream.next();\n      }\n\n      state.tokenize = tokenBase;\n      if (isOperatorString.test(word))\n        return \"operator\";\n      else if (isNumber(word))\n        return \"number\";\n      else if (stream.peek() == \":\")\n        return \"field\";\n      else\n        return \"string\";\n    };\n  }\n\n  function tokenBase(stream, state) {\n    var ch = stream.next();\n    if (ch == '\"')\n      state.tokenize = tokenString(ch);\n    else if (isOperatorChar.test(ch))\n      state.tokenize = tokenOperator(ch);\n    else if (isStringChar.test(ch))\n      state.tokenize = tokenWord(ch);\n\n    return (state.tokenize != tokenBase) ? state.tokenize(stream, state) : null;\n  }\n\n  return {\n    startState: function() {\n      return {\n        tokenize: tokenBase\n      };\n    },\n\n    token: function(stream, state) {\n      if (stream.eatSpace()) return null;\n      return state.tokenize(stream, state);\n    }\n  };\n});\n\nCodeMirror.defineMIME(\"text/x-solr\", \"solr\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/soy/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Soy (Closure Template) mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"../../addon/edit/matchbrackets.js\"></script>\n<script src=\"../htmlmixed/htmlmixed.js\"></script>\n<script src=\"../xml/xml.js\"></script>\n<script src=\"../javascript/javascript.js\"></script>\n<script src=\"../css/css.js\"></script>\n<script src=\"soy.js\"></script>\n<style type=\"text/css\">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Soy (Closure Template)</a>\n  </ul>\n</div>\n\n<article>\n<h2>Soy (Closure Template) mode</h2>\n<form><textarea id=\"code\" name=\"code\">\n{namespace example}\n\n/**\n * Says hello to the world.\n */\n{template .helloWorld}\n  {@param name: string}\n  {@param? score: number}\n  Hello <b>{$name}</b>!\n  <div>\n    {if $score}\n      <em>{$score} points</em>\n    {else}\n      no score\n    {/if}\n  </div>\n{/template}\n\n{template .alertHelloWorld kind=\"js\"}\n  alert('Hello World');\n{/template}\n</textarea></form>\n\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        lineNumbers: true,\n        matchBrackets: true,\n        mode: \"text/x-soy\",\n        indentUnit: 2,\n        indentWithTabs: false\n      });\n    </script>\n\n    <p>A mode for <a href=\"https://developers.google.com/closure/templates/\">Closure Templates</a> (Soy).</p>\n    <p><strong>MIME type defined:</strong> <code>text/x-soy</code>.</p>\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/soy/soy.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"), require(\"../htmlmixed/htmlmixed\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\", \"../htmlmixed/htmlmixed\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n\n  var indentingTags = [\"template\", \"literal\", \"msg\", \"fallbackmsg\", \"let\", \"if\", \"elseif\",\n                       \"else\", \"switch\", \"case\", \"default\", \"foreach\", \"ifempty\", \"for\",\n                       \"call\", \"param\", \"deltemplate\", \"delcall\", \"log\"];\n\n  CodeMirror.defineMode(\"soy\", function(config) {\n    var textMode = CodeMirror.getMode(config, \"text/plain\");\n    var modes = {\n      html: CodeMirror.getMode(config, {name: \"text/html\", multilineTagIndentFactor: 2, multilineTagIndentPastTag: false}),\n      attributes: textMode,\n      text: textMode,\n      uri: textMode,\n      css: CodeMirror.getMode(config, \"text/css\"),\n      js: CodeMirror.getMode(config, {name: \"text/javascript\", statementIndent: 2 * config.indentUnit})\n    };\n\n    function last(array) {\n      return array[array.length - 1];\n    }\n\n    function tokenUntil(stream, state, untilRegExp) {\n      var oldString = stream.string;\n      var match = untilRegExp.exec(oldString.substr(stream.pos));\n      if (match) {\n        // We don't use backUp because it backs up just the position, not the state.\n        // This uses an undocumented API.\n        stream.string = oldString.substr(0, stream.pos + match.index);\n      }\n      var result = stream.hideFirstChars(state.indent, function() {\n        return state.localMode.token(stream, state.localState);\n      });\n      stream.string = oldString;\n      return result;\n    }\n\n    return {\n      startState: function() {\n        return {\n          kind: [],\n          kindTag: [],\n          soyState: [],\n          indent: 0,\n          localMode: modes.html,\n          localState: CodeMirror.startState(modes.html)\n        };\n      },\n\n      copyState: function(state) {\n        return {\n          tag: state.tag, // Last seen Soy tag.\n          kind: state.kind.concat([]), // Values of kind=\"\" attributes.\n          kindTag: state.kindTag.concat([]), // Opened tags with kind=\"\" attributes.\n          soyState: state.soyState.concat([]),\n          indent: state.indent, // Indentation of the following line.\n          localMode: state.localMode,\n          localState: CodeMirror.copyState(state.localMode, state.localState)\n        };\n      },\n\n      token: function(stream, state) {\n        var match;\n\n        switch (last(state.soyState)) {\n          case \"comment\":\n            if (stream.match(/^.*?\\*\\//)) {\n              state.soyState.pop();\n            } else {\n              stream.skipToEnd();\n            }\n            return \"comment\";\n\n          case \"variable\":\n            if (stream.match(/^}/)) {\n              state.indent -= 2 * config.indentUnit;\n              state.soyState.pop();\n              return \"variable-2\";\n            }\n            stream.next();\n            return null;\n\n          case \"tag\":\n            if (stream.match(/^\\/?}/)) {\n              if (state.tag == \"/template\" || state.tag == \"/deltemplate\") state.indent = 0;\n              else state.indent -= (stream.current() == \"/}\" || indentingTags.indexOf(state.tag) == -1 ? 2 : 1) * config.indentUnit;\n              state.soyState.pop();\n              return \"keyword\";\n            } else if (stream.match(/^(\\w+)(?==)/)) {\n              if (stream.current() == \"kind\" && (match = stream.match(/^=\"([^\"]+)/, false))) {\n                var kind = match[1];\n                state.kind.push(kind);\n                state.kindTag.push(state.tag);\n                state.localMode = modes[kind] || modes.html;\n                state.localState = CodeMirror.startState(state.localMode);\n              }\n              return \"attribute\";\n            } else if (stream.match(/^\"/)) {\n              state.soyState.push(\"string\");\n              return \"string\";\n            }\n            stream.next();\n            return null;\n\n          case \"literal\":\n            if (stream.match(/^(?=\\{\\/literal})/)) {\n              state.indent -= config.indentUnit;\n              state.soyState.pop();\n              return this.token(stream, state);\n            }\n            return tokenUntil(stream, state, /\\{\\/literal}/);\n\n          case \"string\":\n            if (stream.match(/^.*?\"/)) {\n              state.soyState.pop();\n            } else {\n              stream.skipToEnd();\n            }\n            return \"string\";\n        }\n\n        if (stream.match(/^\\/\\*/)) {\n          state.soyState.push(\"comment\");\n          return \"comment\";\n        } else if (stream.match(stream.sol() ? /^\\s*\\/\\/.*/ : /^\\s+\\/\\/.*/)) {\n          return \"comment\";\n        } else if (stream.match(/^\\{\\$\\w*/)) {\n          state.indent += 2 * config.indentUnit;\n          state.soyState.push(\"variable\");\n          return \"variable-2\";\n        } else if (stream.match(/^\\{literal}/)) {\n          state.indent += config.indentUnit;\n          state.soyState.push(\"literal\");\n          return \"keyword\";\n        } else if (match = stream.match(/^\\{([\\/@\\\\]?\\w*)/)) {\n          if (match[1] != \"/switch\")\n            state.indent += (/^(\\/|(else|elseif|case|default)$)/.test(match[1]) && state.tag != \"switch\" ? 1 : 2) * config.indentUnit;\n          state.tag = match[1];\n          if (state.tag == \"/\" + last(state.kindTag)) {\n            // We found the tag that opened the current kind=\"\".\n            state.kind.pop();\n            state.kindTag.pop();\n            state.localMode = modes[last(state.kind)] || modes.html;\n            state.localState = CodeMirror.startState(state.localMode);\n          }\n          state.soyState.push(\"tag\");\n          return \"keyword\";\n        }\n\n        return tokenUntil(stream, state, /\\{|\\s+\\/\\/|\\/\\*/);\n      },\n\n      indent: function(state, textAfter) {\n        var indent = state.indent, top = last(state.soyState);\n        if (top == \"comment\") return CodeMirror.Pass;\n\n        if (top == \"literal\") {\n          if (/^\\{\\/literal}/.test(textAfter)) indent -= config.indentUnit;\n        } else {\n          if (/^\\s*\\{\\/(template|deltemplate)\\b/.test(textAfter)) return 0;\n          if (/^\\{(\\/|(fallbackmsg|elseif|else|ifempty)\\b)/.test(textAfter)) indent -= config.indentUnit;\n          if (state.tag != \"switch\" && /^\\{(case|default)\\b/.test(textAfter)) indent -= config.indentUnit;\n          if (/^\\{\\/switch\\b/.test(textAfter)) indent -= config.indentUnit;\n        }\n        if (indent && state.localMode.indent)\n          indent += state.localMode.indent(state.localState, textAfter);\n        return indent;\n      },\n\n      innerMode: function(state) {\n        if (state.soyState.length && last(state.soyState) != \"literal\") return null;\n        else return {state: state.localState, mode: state.localMode};\n      },\n\n      electricInput: /^\\s*\\{(\\/|\\/template|\\/deltemplate|\\/switch|fallbackmsg|elseif|else|case|default|ifempty|\\/literal\\})$/,\n      lineComment: \"//\",\n      blockCommentStart: \"/*\",\n      blockCommentEnd: \"*/\",\n      blockCommentContinue: \" * \",\n      fold: \"indent\"\n    };\n  }, \"htmlmixed\");\n\n  CodeMirror.registerHelper(\"hintWords\", \"soy\", indentingTags.concat(\n      [\"delpackage\", \"namespace\", \"alias\", \"print\", \"css\", \"debugger\"]));\n\n  CodeMirror.defineMIME(\"text/x-soy\", \"soy\");\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/sparql/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: SPARQL mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"../../addon/edit/matchbrackets.js\"></script>\n<script src=\"sparql.js\"></script>\n<style>.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">SPARQL</a>\n  </ul>\n</div>\n\n<article>\n<h2>SPARQL mode</h2>\n<form><textarea id=\"code\" name=\"code\">\nPREFIX a: &lt;http://www.w3.org/2000/10/annotation-ns#>\nPREFIX dc: &lt;http://purl.org/dc/elements/1.1/>\nPREFIX foaf: &lt;http://xmlns.com/foaf/0.1/>\nPREFIX rdfs: &lt;http://www.w3.org/2000/01/rdf-schema#>\n\n# Comment!\n\nSELECT ?given ?family\nWHERE {\n  {\n    ?annot a:annotates &lt;http://www.w3.org/TR/rdf-sparql-query/> .\n    ?annot dc:creator ?c .\n    OPTIONAL {?c foaf:givenName ?given ;\n                 foaf:familyName ?family }\n  } UNION {\n    ?c !foaf:knows/foaf:knows? ?thing.\n    ?thing rdfs\n  } MINUS {\n    ?thing rdfs:label \"剛柔流\"@jp\n  }\n  FILTER isBlank(?c)\n}\n</textarea></form>\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        mode: \"application/sparql-query\",\n        matchBrackets: true\n      });\n    </script>\n\n    <p><strong>MIME types defined:</strong> <code>application/sparql-query</code>.</p>\n\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/sparql/sparql.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"sparql\", function(config) {\n  var indentUnit = config.indentUnit;\n  var curPunc;\n\n  function wordRegexp(words) {\n    return new RegExp(\"^(?:\" + words.join(\"|\") + \")$\", \"i\");\n  }\n  var ops = wordRegexp([\"str\", \"lang\", \"langmatches\", \"datatype\", \"bound\", \"sameterm\", \"isiri\", \"isuri\",\n                        \"iri\", \"uri\", \"bnode\", \"count\", \"sum\", \"min\", \"max\", \"avg\", \"sample\",\n                        \"group_concat\", \"rand\", \"abs\", \"ceil\", \"floor\", \"round\", \"concat\", \"substr\", \"strlen\",\n                        \"replace\", \"ucase\", \"lcase\", \"encode_for_uri\", \"contains\", \"strstarts\", \"strends\",\n                        \"strbefore\", \"strafter\", \"year\", \"month\", \"day\", \"hours\", \"minutes\", \"seconds\",\n                        \"timezone\", \"tz\", \"now\", \"uuid\", \"struuid\", \"md5\", \"sha1\", \"sha256\", \"sha384\",\n                        \"sha512\", \"coalesce\", \"if\", \"strlang\", \"strdt\", \"isnumeric\", \"regex\", \"exists\",\n                        \"isblank\", \"isliteral\", \"a\"]);\n  var keywords = wordRegexp([\"base\", \"prefix\", \"select\", \"distinct\", \"reduced\", \"construct\", \"describe\",\n                             \"ask\", \"from\", \"named\", \"where\", \"order\", \"limit\", \"offset\", \"filter\", \"optional\",\n                             \"graph\", \"by\", \"asc\", \"desc\", \"as\", \"having\", \"undef\", \"values\", \"group\",\n                             \"minus\", \"in\", \"not\", \"service\", \"silent\", \"using\", \"insert\", \"delete\", \"union\",\n                             \"true\", \"false\", \"with\",\n                             \"data\", \"copy\", \"to\", \"move\", \"add\", \"create\", \"drop\", \"clear\", \"load\"]);\n  var operatorChars = /[*+\\-<>=&|\\^\\/!\\?]/;\n\n  function tokenBase(stream, state) {\n    var ch = stream.next();\n    curPunc = null;\n    if (ch == \"$\" || ch == \"?\") {\n      if(ch == \"?\" && stream.match(/\\s/, false)){\n        return \"operator\";\n      }\n      stream.match(/^[\\w\\d]*/);\n      return \"variable-2\";\n    }\n    else if (ch == \"<\" && !stream.match(/^[\\s\\u00a0=]/, false)) {\n      stream.match(/^[^\\s\\u00a0>]*>?/);\n      return \"atom\";\n    }\n    else if (ch == \"\\\"\" || ch == \"'\") {\n      state.tokenize = tokenLiteral(ch);\n      return state.tokenize(stream, state);\n    }\n    else if (/[{}\\(\\),\\.;\\[\\]]/.test(ch)) {\n      curPunc = ch;\n      return \"bracket\";\n    }\n    else if (ch == \"#\") {\n      stream.skipToEnd();\n      return \"comment\";\n    }\n    else if (operatorChars.test(ch)) {\n      stream.eatWhile(operatorChars);\n      return \"operator\";\n    }\n    else if (ch == \":\") {\n      stream.eatWhile(/[\\w\\d\\._\\-]/);\n      return \"atom\";\n    }\n    else if (ch == \"@\") {\n      stream.eatWhile(/[a-z\\d\\-]/i);\n      return \"meta\";\n    }\n    else {\n      stream.eatWhile(/[_\\w\\d]/);\n      if (stream.eat(\":\")) {\n        stream.eatWhile(/[\\w\\d_\\-]/);\n        return \"atom\";\n      }\n      var word = stream.current();\n      if (ops.test(word))\n        return \"builtin\";\n      else if (keywords.test(word))\n        return \"keyword\";\n      else\n        return \"variable\";\n    }\n  }\n\n  function tokenLiteral(quote) {\n    return function(stream, state) {\n      var escaped = false, ch;\n      while ((ch = stream.next()) != null) {\n        if (ch == quote && !escaped) {\n          state.tokenize = tokenBase;\n          break;\n        }\n        escaped = !escaped && ch == \"\\\\\";\n      }\n      return \"string\";\n    };\n  }\n\n  function pushContext(state, type, col) {\n    state.context = {prev: state.context, indent: state.indent, col: col, type: type};\n  }\n  function popContext(state) {\n    state.indent = state.context.indent;\n    state.context = state.context.prev;\n  }\n\n  return {\n    startState: function() {\n      return {tokenize: tokenBase,\n              context: null,\n              indent: 0,\n              col: 0};\n    },\n\n    token: function(stream, state) {\n      if (stream.sol()) {\n        if (state.context && state.context.align == null) state.context.align = false;\n        state.indent = stream.indentation();\n      }\n      if (stream.eatSpace()) return null;\n      var style = state.tokenize(stream, state);\n\n      if (style != \"comment\" && state.context && state.context.align == null && state.context.type != \"pattern\") {\n        state.context.align = true;\n      }\n\n      if (curPunc == \"(\") pushContext(state, \")\", stream.column());\n      else if (curPunc == \"[\") pushContext(state, \"]\", stream.column());\n      else if (curPunc == \"{\") pushContext(state, \"}\", stream.column());\n      else if (/[\\]\\}\\)]/.test(curPunc)) {\n        while (state.context && state.context.type == \"pattern\") popContext(state);\n        if (state.context && curPunc == state.context.type) popContext(state);\n      }\n      else if (curPunc == \".\" && state.context && state.context.type == \"pattern\") popContext(state);\n      else if (/atom|string|variable/.test(style) && state.context) {\n        if (/[\\}\\]]/.test(state.context.type))\n          pushContext(state, \"pattern\", stream.column());\n        else if (state.context.type == \"pattern\" && !state.context.align) {\n          state.context.align = true;\n          state.context.col = stream.column();\n        }\n      }\n\n      return style;\n    },\n\n    indent: function(state, textAfter) {\n      var firstChar = textAfter && textAfter.charAt(0);\n      var context = state.context;\n      if (/[\\]\\}]/.test(firstChar))\n        while (context && context.type == \"pattern\") context = context.prev;\n\n      var closing = context && firstChar == context.type;\n      if (!context)\n        return 0;\n      else if (context.type == \"pattern\")\n        return context.col;\n      else if (context.align)\n        return context.col + (closing ? 0 : 1);\n      else\n        return context.indent + (closing ? 0 : indentUnit);\n    }\n  };\n});\n\nCodeMirror.defineMIME(\"application/sparql-query\", \"sparql\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/spreadsheet/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Spreadsheet mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"../../addon/edit/matchbrackets.js\"></script>\n<script src=\"spreadsheet.js\"></script>\n<style type=\"text/css\">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Spreadsheet</a>\n  </ul>\n</div>\n\n<article>\n  <h2>Spreadsheet mode</h2>\n  <form><textarea id=\"code\" name=\"code\">=IF(A1:B2, TRUE, FALSE) / 100</textarea></form>\n\n  <script>\n    var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n      lineNumbers: true,\n      matchBrackets: true,\n      extraKeys: {\"Tab\":  \"indentAuto\"}\n    });\n  </script>\n\n  <p><strong>MIME types defined:</strong> <code>text/x-spreadsheet</code>.</p>\n  \n  <h3>The Spreadsheet Mode</h3>\n  <p> Created by <a href=\"https://github.com/robertleeplummerjr\">Robert Plummer</a></p>\n</article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/spreadsheet/spreadsheet.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n\n  CodeMirror.defineMode(\"spreadsheet\", function () {\n    return {\n      startState: function () {\n        return {\n          stringType: null,\n          stack: []\n        };\n      },\n      token: function (stream, state) {\n        if (!stream) return;\n\n        //check for state changes\n        if (state.stack.length === 0) {\n          //strings\n          if ((stream.peek() == '\"') || (stream.peek() == \"'\")) {\n            state.stringType = stream.peek();\n            stream.next(); // Skip quote\n            state.stack.unshift(\"string\");\n          }\n        }\n\n        //return state\n        //stack has\n        switch (state.stack[0]) {\n        case \"string\":\n          while (state.stack[0] === \"string\" && !stream.eol()) {\n            if (stream.peek() === state.stringType) {\n              stream.next(); // Skip quote\n              state.stack.shift(); // Clear flag\n            } else if (stream.peek() === \"\\\\\") {\n              stream.next();\n              stream.next();\n            } else {\n              stream.match(/^.[^\\\\\\\"\\']*/);\n            }\n          }\n          return \"string\";\n\n        case \"characterClass\":\n          while (state.stack[0] === \"characterClass\" && !stream.eol()) {\n            if (!(stream.match(/^[^\\]\\\\]+/) || stream.match(/^\\\\./)))\n              state.stack.shift();\n          }\n          return \"operator\";\n        }\n\n        var peek = stream.peek();\n\n        //no stack\n        switch (peek) {\n        case \"[\":\n          stream.next();\n          state.stack.unshift(\"characterClass\");\n          return \"bracket\";\n        case \":\":\n          stream.next();\n          return \"operator\";\n        case \"\\\\\":\n          if (stream.match(/\\\\[a-z]+/)) return \"string-2\";\n          else return null;\n        case \".\":\n        case \",\":\n        case \";\":\n        case \"*\":\n        case \"-\":\n        case \"+\":\n        case \"^\":\n        case \"<\":\n        case \"/\":\n        case \"=\":\n          stream.next();\n          return \"atom\";\n        case \"$\":\n          stream.next();\n          return \"builtin\";\n        }\n\n        if (stream.match(/\\d+/)) {\n          if (stream.match(/^\\w+/)) return \"error\";\n          return \"number\";\n        } else if (stream.match(/^[a-zA-Z_]\\w*/)) {\n          if (stream.match(/(?=[\\(.])/, false)) return \"keyword\";\n          return \"variable-2\";\n        } else if ([\"[\", \"]\", \"(\", \")\", \"{\", \"}\"].indexOf(peek) != -1) {\n          stream.next();\n          return \"bracket\";\n        } else if (!stream.eatSpace()) {\n          stream.next();\n        }\n        return null;\n      }\n    };\n  });\n\n  CodeMirror.defineMIME(\"text/x-spreadsheet\", \"spreadsheet\");\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/sql/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: SQL Mode for CodeMirror</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\" />\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"sql.js\"></script>\n<link rel=\"stylesheet\" href=\"../../addon/hint/show-hint.css\" />\n<script src=\"../../addon/hint/show-hint.js\"></script>\n<script src=\"../../addon/hint/sql-hint.js\"></script>\n<style>\n.CodeMirror {\n    border-top: 1px solid black;\n    border-bottom: 1px solid black;\n}\n        </style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">SQL Mode for CodeMirror</a>\n  </ul>\n</div>\n\n<article>\n<h2>SQL Mode for CodeMirror</h2>\n<form>\n            <textarea id=\"code\" name=\"code\">-- SQL Mode for CodeMirror\nSELECT SQL_NO_CACHE DISTINCT\n\t\t@var1 AS `val1`, @'val2', @global.'sql_mode',\n\t\t1.1 AS `float_val`, .14 AS `another_float`, 0.09e3 AS `int_with_esp`,\n\t\t0xFA5 AS `hex`, x'fa5' AS `hex2`, 0b101 AS `bin`, b'101' AS `bin2`,\n\t\tDATE '1994-01-01' AS `sql_date`, { T \"1994-01-01\" } AS `odbc_date`,\n\t\t'my string', _utf8'your string', N'her string',\n        TRUE, FALSE, UNKNOWN\n\tFROM DUAL\n\t-- space needed after '--'\n\t# 1 line comment\n\t/* multiline\n\tcomment! */\n\tLIMIT 1 OFFSET 0;\n</textarea>\n            </form>\n            <p><strong>MIME types defined:</strong> \n            <code><a href=\"?mime=text/x-sql\">text/x-sql</a></code>,\n            <code><a href=\"?mime=text/x-mysql\">text/x-mysql</a></code>,\n            <code><a href=\"?mime=text/x-mariadb\">text/x-mariadb</a></code>,\n            <code><a href=\"?mime=text/x-cassandra\">text/x-cassandra</a></code>,\n            <code><a href=\"?mime=text/x-plsql\">text/x-plsql</a></code>,\n            <code><a href=\"?mime=text/x-mssql\">text/x-mssql</a></code>,\n            <code><a href=\"?mime=text/x-hive\">text/x-hive</a></code>.\n        </p>\n<script>\nwindow.onload = function() {\n  var mime = 'text/x-mariadb';\n  // get mime type\n  if (window.location.href.indexOf('mime=') > -1) {\n    mime = window.location.href.substr(window.location.href.indexOf('mime=') + 5);\n  }\n  window.editor = CodeMirror.fromTextArea(document.getElementById('code'), {\n    mode: mime,\n    indentWithTabs: true,\n    smartIndent: true,\n    lineNumbers: true,\n    matchBrackets : true,\n    autofocus: true,\n    extraKeys: {\"Ctrl-Space\": \"autocomplete\"},\n    hintOptions: {tables: {\n      users: {name: null, score: null, birthDate: null},\n      countries: {name: null, population: null, size: null}\n    }}\n  });\n};\n</script>\n\n</article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/sql/sql.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"sql\", function(config, parserConfig) {\n  \"use strict\";\n\n  var client         = parserConfig.client || {},\n      atoms          = parserConfig.atoms || {\"false\": true, \"true\": true, \"null\": true},\n      builtin        = parserConfig.builtin || {},\n      keywords       = parserConfig.keywords || {},\n      operatorChars  = parserConfig.operatorChars || /^[*+\\-%<>!=&|~^]/,\n      support        = parserConfig.support || {},\n      hooks          = parserConfig.hooks || {},\n      dateSQL        = parserConfig.dateSQL || {\"date\" : true, \"time\" : true, \"timestamp\" : true};\n\n  function tokenBase(stream, state) {\n    var ch = stream.next();\n\n    // call hooks from the mime type\n    if (hooks[ch]) {\n      var result = hooks[ch](stream, state);\n      if (result !== false) return result;\n    }\n\n    if (support.hexNumber == true &&\n      ((ch == \"0\" && stream.match(/^[xX][0-9a-fA-F]+/))\n      || (ch == \"x\" || ch == \"X\") && stream.match(/^'[0-9a-fA-F]+'/))) {\n      // hex\n      // ref: http://dev.mysql.com/doc/refman/5.5/en/hexadecimal-literals.html\n      return \"number\";\n    } else if (support.binaryNumber == true &&\n      (((ch == \"b\" || ch == \"B\") && stream.match(/^'[01]+'/))\n      || (ch == \"0\" && stream.match(/^b[01]+/)))) {\n      // bitstring\n      // ref: http://dev.mysql.com/doc/refman/5.5/en/bit-field-literals.html\n      return \"number\";\n    } else if (ch.charCodeAt(0) > 47 && ch.charCodeAt(0) < 58) {\n      // numbers\n      // ref: http://dev.mysql.com/doc/refman/5.5/en/number-literals.html\n          stream.match(/^[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?/);\n      support.decimallessFloat == true && stream.eat('.');\n      return \"number\";\n    } else if (ch == \"?\" && (stream.eatSpace() || stream.eol() || stream.eat(\";\"))) {\n      // placeholders\n      return \"variable-3\";\n    } else if (ch == \"'\" || (ch == '\"' && support.doubleQuote)) {\n      // strings\n      // ref: http://dev.mysql.com/doc/refman/5.5/en/string-literals.html\n      state.tokenize = tokenLiteral(ch);\n      return state.tokenize(stream, state);\n    } else if ((((support.nCharCast == true && (ch == \"n\" || ch == \"N\"))\n        || (support.charsetCast == true && ch == \"_\" && stream.match(/[a-z][a-z0-9]*/i)))\n        && (stream.peek() == \"'\" || stream.peek() == '\"'))) {\n      // charset casting: _utf8'str', N'str', n'str'\n      // ref: http://dev.mysql.com/doc/refman/5.5/en/string-literals.html\n      return \"keyword\";\n    } else if (/^[\\(\\),\\;\\[\\]]/.test(ch)) {\n      // no highlightning\n      return null;\n    } else if (support.commentSlashSlash && ch == \"/\" && stream.eat(\"/\")) {\n      // 1-line comment\n      stream.skipToEnd();\n      return \"comment\";\n    } else if ((support.commentHash && ch == \"#\")\n        || (ch == \"-\" && stream.eat(\"-\") && (!support.commentSpaceRequired || stream.eat(\" \")))) {\n      // 1-line comments\n      // ref: https://kb.askmonty.org/en/comment-syntax/\n      stream.skipToEnd();\n      return \"comment\";\n    } else if (ch == \"/\" && stream.eat(\"*\")) {\n      // multi-line comments\n      // ref: https://kb.askmonty.org/en/comment-syntax/\n      state.tokenize = tokenComment;\n      return state.tokenize(stream, state);\n    } else if (ch == \".\") {\n      // .1 for 0.1\n      if (support.zerolessFloat == true && stream.match(/^(?:\\d+(?:e[+-]?\\d+)?)/i)) {\n        return \"number\";\n      }\n      // .table_name (ODBC)\n      // // ref: http://dev.mysql.com/doc/refman/5.6/en/identifier-qualifiers.html\n      if (support.ODBCdotTable == true && stream.match(/^[a-zA-Z_]+/)) {\n        return \"variable-2\";\n      }\n    } else if (operatorChars.test(ch)) {\n      // operators\n      stream.eatWhile(operatorChars);\n      return null;\n    } else if (ch == '{' &&\n        (stream.match(/^( )*(d|D|t|T|ts|TS)( )*'[^']*'( )*}/) || stream.match(/^( )*(d|D|t|T|ts|TS)( )*\"[^\"]*\"( )*}/))) {\n      // dates (weird ODBC syntax)\n      // ref: http://dev.mysql.com/doc/refman/5.5/en/date-and-time-literals.html\n      return \"number\";\n    } else {\n      stream.eatWhile(/^[_\\w\\d]/);\n      var word = stream.current().toLowerCase();\n      // dates (standard SQL syntax)\n      // ref: http://dev.mysql.com/doc/refman/5.5/en/date-and-time-literals.html\n      if (dateSQL.hasOwnProperty(word) && (stream.match(/^( )+'[^']*'/) || stream.match(/^( )+\"[^\"]*\"/)))\n        return \"number\";\n      if (atoms.hasOwnProperty(word)) return \"atom\";\n      if (builtin.hasOwnProperty(word)) return \"builtin\";\n      if (keywords.hasOwnProperty(word)) return \"keyword\";\n      if (client.hasOwnProperty(word)) return \"string-2\";\n      return null;\n    }\n  }\n\n  // 'string', with char specified in quote escaped by '\\'\n  function tokenLiteral(quote) {\n    return function(stream, state) {\n      var escaped = false, ch;\n      while ((ch = stream.next()) != null) {\n        if (ch == quote && !escaped) {\n          state.tokenize = tokenBase;\n          break;\n        }\n        escaped = !escaped && ch == \"\\\\\";\n      }\n      return \"string\";\n    };\n  }\n  function tokenComment(stream, state) {\n    while (true) {\n      if (stream.skipTo(\"*\")) {\n        stream.next();\n        if (stream.eat(\"/\")) {\n          state.tokenize = tokenBase;\n          break;\n        }\n      } else {\n        stream.skipToEnd();\n        break;\n      }\n    }\n    return \"comment\";\n  }\n\n  function pushContext(stream, state, type) {\n    state.context = {\n      prev: state.context,\n      indent: stream.indentation(),\n      col: stream.column(),\n      type: type\n    };\n  }\n\n  function popContext(state) {\n    state.indent = state.context.indent;\n    state.context = state.context.prev;\n  }\n\n  return {\n    startState: function() {\n      return {tokenize: tokenBase, context: null};\n    },\n\n    token: function(stream, state) {\n      if (stream.sol()) {\n        if (state.context && state.context.align == null)\n          state.context.align = false;\n      }\n      if (stream.eatSpace()) return null;\n\n      var style = state.tokenize(stream, state);\n      if (style == \"comment\") return style;\n\n      if (state.context && state.context.align == null)\n        state.context.align = true;\n\n      var tok = stream.current();\n      if (tok == \"(\")\n        pushContext(stream, state, \")\");\n      else if (tok == \"[\")\n        pushContext(stream, state, \"]\");\n      else if (state.context && state.context.type == tok)\n        popContext(state);\n      return style;\n    },\n\n    indent: function(state, textAfter) {\n      var cx = state.context;\n      if (!cx) return CodeMirror.Pass;\n      var closing = textAfter.charAt(0) == cx.type;\n      if (cx.align) return cx.col + (closing ? 0 : 1);\n      else return cx.indent + (closing ? 0 : config.indentUnit);\n    },\n\n    blockCommentStart: \"/*\",\n    blockCommentEnd: \"*/\",\n    lineComment: support.commentSlashSlash ? \"//\" : support.commentHash ? \"#\" : null\n  };\n});\n\n(function() {\n  \"use strict\";\n\n  // `identifier`\n  function hookIdentifier(stream) {\n    // MySQL/MariaDB identifiers\n    // ref: http://dev.mysql.com/doc/refman/5.6/en/identifier-qualifiers.html\n    var ch;\n    while ((ch = stream.next()) != null) {\n      if (ch == \"`\" && !stream.eat(\"`\")) return \"variable-2\";\n    }\n    stream.backUp(stream.current().length - 1);\n    return stream.eatWhile(/\\w/) ? \"variable-2\" : null;\n  }\n\n  // variable token\n  function hookVar(stream) {\n    // variables\n    // @@prefix.varName @varName\n    // varName can be quoted with ` or ' or \"\n    // ref: http://dev.mysql.com/doc/refman/5.5/en/user-variables.html\n    if (stream.eat(\"@\")) {\n      stream.match(/^session\\./);\n      stream.match(/^local\\./);\n      stream.match(/^global\\./);\n    }\n\n    if (stream.eat(\"'\")) {\n      stream.match(/^.*'/);\n      return \"variable-2\";\n    } else if (stream.eat('\"')) {\n      stream.match(/^.*\"/);\n      return \"variable-2\";\n    } else if (stream.eat(\"`\")) {\n      stream.match(/^.*`/);\n      return \"variable-2\";\n    } else if (stream.match(/^[0-9a-zA-Z$\\.\\_]+/)) {\n      return \"variable-2\";\n    }\n    return null;\n  };\n\n  // short client keyword token\n  function hookClient(stream) {\n    // \\N means NULL\n    // ref: http://dev.mysql.com/doc/refman/5.5/en/null-values.html\n    if (stream.eat(\"N\")) {\n        return \"atom\";\n    }\n    // \\g, etc\n    // ref: http://dev.mysql.com/doc/refman/5.5/en/mysql-commands.html\n    return stream.match(/^[a-zA-Z.#!?]/) ? \"variable-2\" : null;\n  }\n\n  // these keywords are used by all SQL dialects (however, a mode can still overwrite it)\n  var sqlKeywords = \"alter and as asc between by count create delete desc distinct drop from having in insert into is join like not on or order select set table union update values where \";\n\n  // turn a space-separated list into an array\n  function set(str) {\n    var obj = {}, words = str.split(\" \");\n    for (var i = 0; i < words.length; ++i) obj[words[i]] = true;\n    return obj;\n  }\n\n  // A generic SQL Mode. It's not a standard, it just try to support what is generally supported\n  CodeMirror.defineMIME(\"text/x-sql\", {\n    name: \"sql\",\n    keywords: set(sqlKeywords + \"begin\"),\n    builtin: set(\"bool boolean bit blob enum long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision real date datetime year unsigned signed decimal numeric\"),\n    atoms: set(\"false true null unknown\"),\n    operatorChars: /^[*+\\-%<>!=]/,\n    dateSQL: set(\"date time timestamp\"),\n    support: set(\"ODBCdotTable doubleQuote binaryNumber hexNumber\")\n  });\n\n  CodeMirror.defineMIME(\"text/x-mssql\", {\n    name: \"sql\",\n    client: set(\"charset clear connect edit ego exit go help nopager notee nowarning pager print prompt quit rehash source status system tee\"),\n    keywords: set(sqlKeywords + \"begin trigger proc view index for add constraint key primary foreign collate clustered nonclustered\"),\n    builtin: set(\"bigint numeric bit smallint decimal smallmoney int tinyint money float real char varchar text nchar nvarchar ntext binary varbinary image cursor timestamp hierarchyid uniqueidentifier sql_variant xml table \"),\n    atoms: set(\"false true null unknown\"),\n    operatorChars: /^[*+\\-%<>!=]/,\n    dateSQL: set(\"date datetimeoffset datetime2 smalldatetime datetime time\"),\n    hooks: {\n      \"@\":   hookVar\n    }\n  });\n\n  CodeMirror.defineMIME(\"text/x-mysql\", {\n    name: \"sql\",\n    client: set(\"charset clear connect edit ego exit go help nopager notee nowarning pager print prompt quit rehash source status system tee\"),\n    keywords: set(sqlKeywords + \"accessible action add after algorithm all analyze asensitive at authors auto_increment autocommit avg avg_row_length before binary binlog both btree cache call cascade cascaded case catalog_name chain change changed character check checkpoint checksum class_origin client_statistics close coalesce code collate collation collations column columns comment commit committed completion concurrent condition connection consistent constraint contains continue contributors convert cross current current_date current_time current_timestamp current_user cursor data database databases day_hour day_microsecond day_minute day_second deallocate dec declare default delay_key_write delayed delimiter des_key_file describe deterministic dev_pop dev_samp deviance diagnostics directory disable discard distinctrow div dual dumpfile each elseif enable enclosed end ends engine engines enum errors escape escaped even event events every execute exists exit explain extended fast fetch field fields first flush for force foreign found_rows full fulltext function general get global grant grants group groupby_concat handler hash help high_priority hosts hour_microsecond hour_minute hour_second if ignore ignore_server_ids import index index_statistics infile inner innodb inout insensitive insert_method install interval invoker isolation iterate key keys kill language last leading leave left level limit linear lines list load local localtime localtimestamp lock logs low_priority master master_heartbeat_period master_ssl_verify_server_cert masters match max max_rows maxvalue message_text middleint migrate min min_rows minute_microsecond minute_second mod mode modifies modify mutex mysql_errno natural next no no_write_to_binlog offline offset one online open optimize option optionally out outer outfile pack_keys parser partition partitions password phase plugin plugins prepare preserve prev primary privileges procedure processlist profile profiles purge query quick range read read_write reads real rebuild recover references regexp relaylog release remove rename reorganize repair repeatable replace require resignal restrict resume return returns revoke right rlike rollback rollup row row_format rtree savepoint schedule schema schema_name schemas second_microsecond security sensitive separator serializable server session share show signal slave slow smallint snapshot soname spatial specific sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_no_cache sql_small_result sqlexception sqlstate sqlwarning ssl start starting starts status std stddev stddev_pop stddev_samp storage straight_join subclass_origin sum suspend table_name table_statistics tables tablespace temporary terminated to trailing transaction trigger triggers truncate uncommitted undo uninstall unique unlock upgrade usage use use_frm user user_resources user_statistics using utc_date utc_time utc_timestamp value variables varying view views warnings when while with work write xa xor year_month zerofill begin do then else loop repeat\"),\n    builtin: set(\"bool boolean bit blob decimal double float long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision date datetime year unsigned signed numeric\"),\n    atoms: set(\"false true null unknown\"),\n    operatorChars: /^[*+\\-%<>!=&|^]/,\n    dateSQL: set(\"date time timestamp\"),\n    support: set(\"ODBCdotTable decimallessFloat zerolessFloat binaryNumber hexNumber doubleQuote nCharCast charsetCast commentHash commentSpaceRequired\"),\n    hooks: {\n      \"@\":   hookVar,\n      \"`\":   hookIdentifier,\n      \"\\\\\":  hookClient\n    }\n  });\n\n  CodeMirror.defineMIME(\"text/x-mariadb\", {\n    name: \"sql\",\n    client: set(\"charset clear connect edit ego exit go help nopager notee nowarning pager print prompt quit rehash source status system tee\"),\n    keywords: set(sqlKeywords + \"accessible action add after algorithm all always analyze asensitive at authors auto_increment autocommit avg avg_row_length before binary binlog both btree cache call cascade cascaded case catalog_name chain change changed character check checkpoint checksum class_origin client_statistics close coalesce code collate collation collations column columns comment commit committed completion concurrent condition connection consistent constraint contains continue contributors convert cross current current_date current_time current_timestamp current_user cursor data database databases day_hour day_microsecond day_minute day_second deallocate dec declare default delay_key_write delayed delimiter des_key_file describe deterministic dev_pop dev_samp deviance diagnostics directory disable discard distinctrow div dual dumpfile each elseif enable enclosed end ends engine engines enum errors escape escaped even event events every execute exists exit explain extended fast fetch field fields first flush for force foreign found_rows full fulltext function general generated get global grant grants group groupby_concat handler hard hash help high_priority hosts hour_microsecond hour_minute hour_second if ignore ignore_server_ids import index index_statistics infile inner innodb inout insensitive insert_method install interval invoker isolation iterate key keys kill language last leading leave left level limit linear lines list load local localtime localtimestamp lock logs low_priority master master_heartbeat_period master_ssl_verify_server_cert masters match max max_rows maxvalue message_text middleint migrate min min_rows minute_microsecond minute_second mod mode modifies modify mutex mysql_errno natural next no no_write_to_binlog offline offset one online open optimize option optionally out outer outfile pack_keys parser partition partitions password persistent phase plugin plugins prepare preserve prev primary privileges procedure processlist profile profiles purge query quick range read read_write reads real rebuild recover references regexp relaylog release remove rename reorganize repair repeatable replace require resignal restrict resume return returns revoke right rlike rollback rollup row row_format rtree savepoint schedule schema schema_name schemas second_microsecond security sensitive separator serializable server session share show shutdown signal slave slow smallint snapshot soft soname spatial specific sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_no_cache sql_small_result sqlexception sqlstate sqlwarning ssl start starting starts status std stddev stddev_pop stddev_samp storage straight_join subclass_origin sum suspend table_name table_statistics tables tablespace temporary terminated to trailing transaction trigger triggers truncate uncommitted undo uninstall unique unlock upgrade usage use use_frm user user_resources user_statistics using utc_date utc_time utc_timestamp value variables varying view views virtual warnings when while with work write xa xor year_month zerofill begin do then else loop repeat\"),\n    builtin: set(\"bool boolean bit blob decimal double float long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision date datetime year unsigned signed numeric\"),\n    atoms: set(\"false true null unknown\"),\n    operatorChars: /^[*+\\-%<>!=&|^]/,\n    dateSQL: set(\"date time timestamp\"),\n    support: set(\"ODBCdotTable decimallessFloat zerolessFloat binaryNumber hexNumber doubleQuote nCharCast charsetCast commentHash commentSpaceRequired\"),\n    hooks: {\n      \"@\":   hookVar,\n      \"`\":   hookIdentifier,\n      \"\\\\\":  hookClient\n    }\n  });\n\n  // the query language used by Apache Cassandra is called CQL, but this mime type\n  // is called Cassandra to avoid confusion with Contextual Query Language\n  CodeMirror.defineMIME(\"text/x-cassandra\", {\n    name: \"sql\",\n    client: { },\n    keywords: set(\"use select from using consistency where limit first reversed first and in insert into values using consistency ttl update set delete truncate begin batch apply create keyspace with columnfamily primary key index on drop alter type add any one quorum all local_quorum each_quorum\"),\n    builtin: set(\"ascii bigint blob boolean counter decimal double float int text timestamp uuid varchar varint\"),\n    atoms: set(\"false true\"),\n    operatorChars: /^[<>=]/,\n    dateSQL: { },\n    support: set(\"commentSlashSlash decimallessFloat\"),\n    hooks: { }\n  });\n\n  // this is based on Peter Raganitsch's 'plsql' mode\n  CodeMirror.defineMIME(\"text/x-plsql\", {\n    name:       \"sql\",\n    client:     set(\"appinfo arraysize autocommit autoprint autorecovery autotrace blockterminator break btitle cmdsep colsep compatibility compute concat copycommit copytypecheck define describe echo editfile embedded escape exec execute feedback flagger flush heading headsep instance linesize lno loboffset logsource long longchunksize markup native newpage numformat numwidth pagesize pause pno recsep recsepchar release repfooter repheader serveroutput shiftinout show showmode size spool sqlblanklines sqlcase sqlcode sqlcontinue sqlnumber sqlpluscompatibility sqlprefix sqlprompt sqlterminator suffix tab term termout time timing trimout trimspool ttitle underline verify version wrap\"),\n    keywords:   set(\"abort accept access add all alter and any array arraylen as asc assert assign at attributes audit authorization avg base_table begin between binary_integer body boolean by case cast char char_base check close cluster clusters colauth column comment commit compress connect connected constant constraint crash create current currval cursor data_base database date dba deallocate debugoff debugon decimal declare default definition delay delete desc digits dispose distinct do drop else elseif elsif enable end entry escape exception exception_init exchange exclusive exists exit external fast fetch file for force form from function generic goto grant group having identified if immediate in increment index indexes indicator initial initrans insert interface intersect into is key level library like limited local lock log logging long loop master maxextents maxtrans member minextents minus mislabel mode modify multiset new next no noaudit nocompress nologging noparallel not nowait number_base object of off offline on online only open option or order out package parallel partition pctfree pctincrease pctused pls_integer positive positiven pragma primary prior private privileges procedure public raise range raw read rebuild record ref references refresh release rename replace resource restrict return returning returns reverse revoke rollback row rowid rowlabel rownum rows run savepoint schema segment select separate session set share snapshot some space split sql start statement storage subtype successful synonym tabauth table tables tablespace task terminate then to trigger truncate type union unique unlimited unrecoverable unusable update use using validate value values variable view views when whenever where while with work\"),\n    builtin:    set(\"abs acos add_months ascii asin atan atan2 average bfile bfilename bigserial bit blob ceil character chartorowid chr clob concat convert cos cosh count dec decode deref dual dump dup_val_on_index empty error exp false float floor found glb greatest hextoraw initcap instr instrb int integer isopen last_day least lenght lenghtb ln lower lpad ltrim lub make_ref max min mlslabel mod months_between natural naturaln nchar nclob new_time next_day nextval nls_charset_decl_len nls_charset_id nls_charset_name nls_initcap nls_lower nls_sort nls_upper nlssort no_data_found notfound null number numeric nvarchar2 nvl others power rawtohex real reftohex round rowcount rowidtochar rowtype rpad rtrim serial sign signtype sin sinh smallint soundex sqlcode sqlerrm sqrt stddev string substr substrb sum sysdate tan tanh to_char text to_date to_label to_multi_byte to_number to_single_byte translate true trunc uid unlogged upper user userenv varchar varchar2 variance varying vsize xml\"),\n    operatorChars: /^[*+\\-%<>!=~]/,\n    dateSQL:    set(\"date time timestamp\"),\n    support:    set(\"doubleQuote nCharCast zerolessFloat binaryNumber hexNumber\")\n  });\n\n  // Created to support specific hive keywords\n  CodeMirror.defineMIME(\"text/x-hive\", {\n    name: \"sql\",\n    keywords: set(\"select alter $elem$ $key$ $value$ add after all analyze and archive as asc before between binary both bucket buckets by cascade case cast change cluster clustered clusterstatus collection column columns comment compute concatenate continue create cross cursor data database databases dbproperties deferred delete delimited desc describe directory disable distinct distribute drop else enable end escaped exclusive exists explain export extended external false fetch fields fileformat first format formatted from full function functions grant group having hold_ddltime idxproperties if import in index indexes inpath inputdriver inputformat insert intersect into is items join keys lateral left like limit lines load local location lock locks mapjoin materialized minus msck no_drop nocompress not of offline on option or order out outer outputdriver outputformat overwrite partition partitioned partitions percent plus preserve procedure purge range rcfile read readonly reads rebuild recordreader recordwriter recover reduce regexp rename repair replace restrict revoke right rlike row schema schemas semi sequencefile serde serdeproperties set shared show show_database sort sorted ssl statistics stored streamtable table tables tablesample tblproperties temporary terminated textfile then tmp to touch transform trigger true unarchive undo union uniquejoin unlock update use using utc utc_tmestamp view when where while with\"),\n    builtin: set(\"bool boolean long timestamp tinyint smallint bigint int float double date datetime unsigned string array struct map uniontype\"),\n    atoms: set(\"false true null unknown\"),\n    operatorChars: /^[*+\\-%<>!=]/,\n    dateSQL: set(\"date timestamp\"),\n    support: set(\"ODBCdotTable doubleQuote binaryNumber hexNumber\")\n  });\n}());\n\n});\n\n/*\n  How Properties of Mime Types are used by SQL Mode\n  =================================================\n\n  keywords:\n    A list of keywords you want to be highlighted.\n  builtin:\n    A list of builtin types you want to be highlighted (if you want types to be of class \"builtin\" instead of \"keyword\").\n  operatorChars:\n    All characters that must be handled as operators.\n  client:\n    Commands parsed and executed by the client (not the server).\n  support:\n    A list of supported syntaxes which are not common, but are supported by more than 1 DBMS.\n    * ODBCdotTable: .tableName\n    * zerolessFloat: .1\n    * doubleQuote\n    * nCharCast: N'string'\n    * charsetCast: _utf8'string'\n    * commentHash: use # char for comments\n    * commentSlashSlash: use // for comments\n    * commentSpaceRequired: require a space after -- for comments\n  atoms:\n    Keywords that must be highlighted as atoms,. Some DBMS's support more atoms than others:\n    UNKNOWN, INFINITY, UNDERFLOW, NaN...\n  dateSQL:\n    Used for date/time SQL standard syntax, because not all DBMS's support same temporal types.\n*/\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/stex/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: sTeX mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"stex.js\"></script>\n<style>.CodeMirror {background: #f8f8f8;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">sTeX</a>\n  </ul>\n</div>\n\n<article>\n<h2>sTeX mode</h2>\n<form><textarea id=\"code\" name=\"code\">\n\\begin{module}[id=bbt-size]\n\\importmodule[balanced-binary-trees]{balanced-binary-trees}\n\\importmodule[\\KWARCslides{dmath/en/cardinality}]{cardinality}\n\n\\begin{frame}\n  \\frametitle{Size Lemma for Balanced Trees}\n  \\begin{itemize}\n  \\item\n    \\begin{assertion}[id=size-lemma,type=lemma] \n    Let $G=\\tup{V,E}$ be a \\termref[cd=binary-trees]{balanced binary tree} \n    of \\termref[cd=graph-depth,name=vertex-depth]{depth}$n>i$, then the set\n     $\\defeq{\\livar{V}i}{\\setst{\\inset{v}{V}}{\\gdepth{v} = i}}$ of\n    \\termref[cd=graphs-intro,name=node]{nodes} at \n    \\termref[cd=graph-depth,name=vertex-depth]{depth} $i$ has\n    \\termref[cd=cardinality,name=cardinality]{cardinality} $\\power2i$.\n   \\end{assertion}\n  \\item\n    \\begin{sproof}[id=size-lemma-pf,proofend=,for=size-lemma]{via induction over the depth $i$.}\n      \\begin{spfcases}{We have to consider two cases}\n        \\begin{spfcase}{$i=0$}\n          \\begin{spfstep}[display=flow]\n            then $\\livar{V}i=\\set{\\livar{v}r}$, where $\\livar{v}r$ is the root, so\n            $\\eq{\\card{\\livar{V}0},\\card{\\set{\\livar{v}r}},1,\\power20}$.\n          \\end{spfstep}\n        \\end{spfcase}\n        \\begin{spfcase}{$i>0$}\n          \\begin{spfstep}[display=flow]\n           then $\\livar{V}{i-1}$ contains $\\power2{i-1}$ vertexes \n           \\begin{justification}[method=byIH](IH)\\end{justification}\n          \\end{spfstep}\n          \\begin{spfstep}\n           By the \\begin{justification}[method=byDef]definition of a binary\n              tree\\end{justification}, each $\\inset{v}{\\livar{V}{i-1}}$ is a leaf or has\n            two children that are at depth $i$.\n          \\end{spfstep}\n          \\begin{spfstep}\n           As $G$ is \\termref[cd=balanced-binary-trees,name=balanced-binary-tree]{balanced} and $\\gdepth{G}=n>i$, $\\livar{V}{i-1}$ cannot contain\n            leaves.\n          \\end{spfstep}\n          \\begin{spfstep}[type=conclusion]\n           Thus $\\eq{\\card{\\livar{V}i},{\\atimes[cdot]{2,\\card{\\livar{V}{i-1}}}},{\\atimes[cdot]{2,\\power2{i-1}}},\\power2i}$.\n          \\end{spfstep}\n        \\end{spfcase}\n      \\end{spfcases}\n    \\end{sproof}\n  \\item \n    \\begin{assertion}[id=fbbt,type=corollary]\t\n      A fully balanced tree of depth $d$ has $\\power2{d+1}-1$ nodes.\n    \\end{assertion}\n  \\item\n      \\begin{sproof}[for=fbbt,id=fbbt-pf]{}\n        \\begin{spfstep}\n          Let $\\defeq{G}{\\tup{V,E}}$ be a fully balanced tree\n        \\end{spfstep}\n        \\begin{spfstep}\n          Then $\\card{V}=\\Sumfromto{i}1d{\\power2i}= \\power2{d+1}-1$.\n        \\end{spfstep}\n      \\end{sproof}\n    \\end{itemize}\n  \\end{frame}\n\\begin{note}\n  \\begin{omtext}[type=conclusion,for=binary-tree]\n    This shows that balanced binary trees grow in breadth very quickly, a consequence of\n    this is that they are very shallow (and this compute very fast), which is the essence of\n    the next result.\n  \\end{omtext}\n\\end{note}\n\\end{module}\n\n%%% Local Variables: \n%%% mode: LaTeX\n%%% TeX-master: \"all\"\n%%% End: \\end{document}\n</textarea></form>\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {});\n    </script>\n\n    <p><strong>MIME types defined:</strong> <code>text/x-stex</code>.</p>\n\n    <p><strong>Parsing/Highlighting Tests:</strong> <a href=\"../../test/index.html#stex_*\">normal</a>,  <a href=\"../../test/index.html#verbose,stex_*\">verbose</a>.</p>\n\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/stex/stex.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n/*\n * Author: Constantin Jucovschi (c.jucovschi@jacobs-university.de)\n * Licence: MIT\n */\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n\n  CodeMirror.defineMode(\"stex\", function() {\n    \"use strict\";\n\n    function pushCommand(state, command) {\n      state.cmdState.push(command);\n    }\n\n    function peekCommand(state) {\n      if (state.cmdState.length > 0) {\n        return state.cmdState[state.cmdState.length - 1];\n      } else {\n        return null;\n      }\n    }\n\n    function popCommand(state) {\n      var plug = state.cmdState.pop();\n      if (plug) {\n        plug.closeBracket();\n      }\n    }\n\n    // returns the non-default plugin closest to the end of the list\n    function getMostPowerful(state) {\n      var context = state.cmdState;\n      for (var i = context.length - 1; i >= 0; i--) {\n        var plug = context[i];\n        if (plug.name == \"DEFAULT\") {\n          continue;\n        }\n        return plug;\n      }\n      return { styleIdentifier: function() { return null; } };\n    }\n\n    function addPluginPattern(pluginName, cmdStyle, styles) {\n      return function () {\n        this.name = pluginName;\n        this.bracketNo = 0;\n        this.style = cmdStyle;\n        this.styles = styles;\n        this.argument = null;   // \\begin and \\end have arguments that follow. These are stored in the plugin\n\n        this.styleIdentifier = function() {\n          return this.styles[this.bracketNo - 1] || null;\n        };\n        this.openBracket = function() {\n          this.bracketNo++;\n          return \"bracket\";\n        };\n        this.closeBracket = function() {};\n      };\n    }\n\n    var plugins = {};\n\n    plugins[\"importmodule\"] = addPluginPattern(\"importmodule\", \"tag\", [\"string\", \"builtin\"]);\n    plugins[\"documentclass\"] = addPluginPattern(\"documentclass\", \"tag\", [\"\", \"atom\"]);\n    plugins[\"usepackage\"] = addPluginPattern(\"usepackage\", \"tag\", [\"atom\"]);\n    plugins[\"begin\"] = addPluginPattern(\"begin\", \"tag\", [\"atom\"]);\n    plugins[\"end\"] = addPluginPattern(\"end\", \"tag\", [\"atom\"]);\n\n    plugins[\"DEFAULT\"] = function () {\n      this.name = \"DEFAULT\";\n      this.style = \"tag\";\n\n      this.styleIdentifier = this.openBracket = this.closeBracket = function() {};\n    };\n\n    function setState(state, f) {\n      state.f = f;\n    }\n\n    // called when in a normal (no environment) context\n    function normal(source, state) {\n      var plug;\n      // Do we look like '\\command' ?  If so, attempt to apply the plugin 'command'\n      if (source.match(/^\\\\[a-zA-Z@]+/)) {\n        var cmdName = source.current().slice(1);\n        plug = plugins[cmdName] || plugins[\"DEFAULT\"];\n        plug = new plug();\n        pushCommand(state, plug);\n        setState(state, beginParams);\n        return plug.style;\n      }\n\n      // escape characters\n      if (source.match(/^\\\\[$&%#{}_]/)) {\n        return \"tag\";\n      }\n\n      // white space control characters\n      if (source.match(/^\\\\[,;!\\/\\\\]/)) {\n        return \"tag\";\n      }\n\n      // find if we're starting various math modes\n      if (source.match(\"\\\\[\")) {\n        setState(state, function(source, state){ return inMathMode(source, state, \"\\\\]\"); });\n        return \"keyword\";\n      }\n      if (source.match(\"$$\")) {\n        setState(state, function(source, state){ return inMathMode(source, state, \"$$\"); });\n        return \"keyword\";\n      }\n      if (source.match(\"$\")) {\n        setState(state, function(source, state){ return inMathMode(source, state, \"$\"); });\n        return \"keyword\";\n      }\n\n      var ch = source.next();\n      if (ch == \"%\") {\n        source.skipToEnd();\n        return \"comment\";\n      } else if (ch == '}' || ch == ']') {\n        plug = peekCommand(state);\n        if (plug) {\n          plug.closeBracket(ch);\n          setState(state, beginParams);\n        } else {\n          return \"error\";\n        }\n        return \"bracket\";\n      } else if (ch == '{' || ch == '[') {\n        plug = plugins[\"DEFAULT\"];\n        plug = new plug();\n        pushCommand(state, plug);\n        return \"bracket\";\n      } else if (/\\d/.test(ch)) {\n        source.eatWhile(/[\\w.%]/);\n        return \"atom\";\n      } else {\n        source.eatWhile(/[\\w\\-_]/);\n        plug = getMostPowerful(state);\n        if (plug.name == 'begin') {\n          plug.argument = source.current();\n        }\n        return plug.styleIdentifier();\n      }\n    }\n\n    function inMathMode(source, state, endModeSeq) {\n      if (source.eatSpace()) {\n        return null;\n      }\n      if (source.match(endModeSeq)) {\n        setState(state, normal);\n        return \"keyword\";\n      }\n      if (source.match(/^\\\\[a-zA-Z@]+/)) {\n        return \"tag\";\n      }\n      if (source.match(/^[a-zA-Z]+/)) {\n        return \"variable-2\";\n      }\n      // escape characters\n      if (source.match(/^\\\\[$&%#{}_]/)) {\n        return \"tag\";\n      }\n      // white space control characters\n      if (source.match(/^\\\\[,;!\\/]/)) {\n        return \"tag\";\n      }\n      // special math-mode characters\n      if (source.match(/^[\\^_&]/)) {\n        return \"tag\";\n      }\n      // non-special characters\n      if (source.match(/^[+\\-<>|=,\\/@!*:;'\"`~#?]/)) {\n        return null;\n      }\n      if (source.match(/^(\\d+\\.\\d*|\\d*\\.\\d+|\\d+)/)) {\n        return \"number\";\n      }\n      var ch = source.next();\n      if (ch == \"{\" || ch == \"}\" || ch == \"[\" || ch == \"]\" || ch == \"(\" || ch == \")\") {\n        return \"bracket\";\n      }\n\n      if (ch == \"%\") {\n        source.skipToEnd();\n        return \"comment\";\n      }\n      return \"error\";\n    }\n\n    function beginParams(source, state) {\n      var ch = source.peek(), lastPlug;\n      if (ch == '{' || ch == '[') {\n        lastPlug = peekCommand(state);\n        lastPlug.openBracket(ch);\n        source.eat(ch);\n        setState(state, normal);\n        return \"bracket\";\n      }\n      if (/[ \\t\\r]/.test(ch)) {\n        source.eat(ch);\n        return null;\n      }\n      setState(state, normal);\n      popCommand(state);\n\n      return normal(source, state);\n    }\n\n    return {\n      startState: function() {\n        return {\n          cmdState: [],\n          f: normal\n        };\n      },\n      copyState: function(s) {\n        return {\n          cmdState: s.cmdState.slice(),\n          f: s.f\n        };\n      },\n      token: function(stream, state) {\n        return state.f(stream, state);\n      },\n      blankLine: function(state) {\n        state.f = normal;\n        state.cmdState.length = 0;\n      },\n      lineComment: \"%\"\n    };\n  });\n\n  CodeMirror.defineMIME(\"text/x-stex\", \"stex\");\n  CodeMirror.defineMIME(\"text/x-latex\", \"stex\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/stex/test.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function() {\n  var mode = CodeMirror.getMode({tabSize: 4}, \"stex\");\n  function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); }\n\n  MT(\"word\",\n     \"foo\");\n\n  MT(\"twoWords\",\n     \"foo bar\");\n\n  MT(\"beginEndDocument\",\n     \"[tag \\\\begin][bracket {][atom document][bracket }]\",\n     \"[tag \\\\end][bracket {][atom document][bracket }]\");\n\n  MT(\"beginEndEquation\",\n     \"[tag \\\\begin][bracket {][atom equation][bracket }]\",\n     \"  E=mc^2\",\n     \"[tag \\\\end][bracket {][atom equation][bracket }]\");\n\n  MT(\"beginModule\",\n     \"[tag \\\\begin][bracket {][atom module][bracket }[[]]]\");\n\n  MT(\"beginModuleId\",\n     \"[tag \\\\begin][bracket {][atom module][bracket }[[]id=bbt-size[bracket ]]]\");\n\n  MT(\"importModule\",\n     \"[tag \\\\importmodule][bracket [[][string b-b-t][bracket ]]{][builtin b-b-t][bracket }]\");\n\n  MT(\"importModulePath\",\n     \"[tag \\\\importmodule][bracket [[][tag \\\\KWARCslides][bracket {][string dmath/en/cardinality][bracket }]]{][builtin card][bracket }]\");\n\n  MT(\"psForPDF\",\n     \"[tag \\\\PSforPDF][bracket [[][atom 1][bracket ]]{]#1[bracket }]\");\n\n  MT(\"comment\",\n     \"[comment % foo]\");\n\n  MT(\"tagComment\",\n     \"[tag \\\\item][comment % bar]\");\n\n  MT(\"commentTag\",\n     \" [comment % \\\\item]\");\n\n  MT(\"commentLineBreak\",\n     \"[comment %]\",\n     \"foo\");\n\n  MT(\"tagErrorCurly\",\n     \"[tag \\\\begin][error }][bracket {]\");\n\n  MT(\"tagErrorSquare\",\n     \"[tag \\\\item][error ]]][bracket {]\");\n\n  MT(\"commentCurly\",\n     \"[comment % }]\");\n\n  MT(\"tagHash\",\n     \"the [tag \\\\#] key\");\n\n  MT(\"tagNumber\",\n     \"a [tag \\\\$][atom 5] stetson\");\n\n  MT(\"tagPercent\",\n     \"[atom 100][tag \\\\%] beef\");\n\n  MT(\"tagAmpersand\",\n     \"L [tag \\\\&] N\");\n\n  MT(\"tagUnderscore\",\n     \"foo[tag \\\\_]bar\");\n\n  MT(\"tagBracketOpen\",\n     \"[tag \\\\emph][bracket {][tag \\\\{][bracket }]\");\n\n  MT(\"tagBracketClose\",\n     \"[tag \\\\emph][bracket {][tag \\\\}][bracket }]\");\n\n  MT(\"tagLetterNumber\",\n     \"section [tag \\\\S][atom 1]\");\n\n  MT(\"textTagNumber\",\n     \"para [tag \\\\P][atom 2]\");\n\n  MT(\"thinspace\",\n     \"x[tag \\\\,]y\");\n\n  MT(\"thickspace\",\n     \"x[tag \\\\;]y\");\n\n  MT(\"negativeThinspace\",\n     \"x[tag \\\\!]y\");\n\n  MT(\"periodNotSentence\",\n     \"J.\\\\ L.\\\\ is\");\n\n  MT(\"periodSentence\",\n     \"X[tag \\\\@]. The\");\n\n  MT(\"italicCorrection\",\n     \"[bracket {][tag \\\\em] If[tag \\\\/][bracket }] I\");\n\n  MT(\"tagBracket\",\n     \"[tag \\\\newcommand][bracket {][tag \\\\pop][bracket }]\");\n\n  MT(\"inlineMathTagFollowedByNumber\",\n     \"[keyword $][tag \\\\pi][number 2][keyword $]\");\n\n  MT(\"inlineMath\",\n     \"[keyword $][number 3][variable-2 x][tag ^][number 2.45]-[tag \\\\sqrt][bracket {][tag \\\\$\\\\alpha][bracket }] = [number 2][keyword $] other text\");\n\n  MT(\"displayMath\",\n     \"More [keyword $$]\\t[variable-2 S][tag ^][variable-2 n][tag \\\\sum] [variable-2 i][keyword $$] other text\");\n\n  MT(\"mathWithComment\",\n     \"[keyword $][variable-2 x] [comment % $]\",\n     \"[variable-2 y][keyword $] other text\");\n\n  MT(\"lineBreakArgument\",\n    \"[tag \\\\\\\\][bracket [[][atom 1cm][bracket ]]]\");\n})();\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/stylus/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Stylus mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<link rel=\"stylesheet\" href=\"../../addon/hint/show-hint.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"stylus.js\"></script>\n<script src=\"../../addon/hint/show-hint.js\"></script>\n<script src=\"../../addon/hint/css-hint.js\"></script>\n<style>.CodeMirror {background: #f8f8f8;} form{margin-bottom: .7em;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Stylus</a>\n  </ul>\n</div>\n\n<article>\n<h2>Stylus mode</h2>\n<form><textarea id=\"code\" name=\"code\">\n/* Stylus mode */\n#id\n.class\narticle\n  font-family Arial, sans-serif\n\n#id,\n.class,\narticle {\n  font-family: Arial, sans-serif;\n}\n\n// Variables\nfont-size-base = 16px\nline-height-base = 1.5\nfont-family-base = \"Helvetica Neue\", Helvetica, Arial, sans-serif\ntext-color = lighten(#000, 20%)\n\nbody\n  font font-size-base/line-height-base font-family-base\n  color text-color\n\nbody {\n  font: 400 16px/1.5 \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  color: #333;\n}\n\n// Variables\nlink-color = darken(#428bca, 6.5%)\nlink-hover-color = darken(link-color, 15%)\nlink-decoration = none\nlink-hover-decoration = false\n\n// Mixin\ntab-focus()\n  outline thin dotted\n  outline 5px auto -webkit-focus-ring-color\n  outline-offset -2px\n\na\n  color link-color\n  if link-decoration\n    text-decoration link-decoration\n  &:hover\n  &:focus\n    color link-hover-color\n    if link-hover-decoration\n      text-decoration link-hover-decoration\n  &:focus\n    tab-focus()\n\na {\n  color: #3782c4;\n  text-decoration: none;\n}\na:hover,\na:focus {\n  color: #2f6ea7;\n}\na:focus {\n  outline: thin dotted;\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\n</textarea>\n</form>\n<script>\n  var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n    extraKeys: {\"Ctrl-Space\": \"autocomplete\"},\n  });\n</script>\n\n<p><strong>MIME types defined:</strong> <code>text/x-styl</code>.</p>\n\n</article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/stylus/stylus.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n\n  CodeMirror.defineMode(\"stylus\", function(config) {\n\n    var operatorsRegexp = /^(\\?:?|\\+[+=]?|-[\\-=]?|\\*[\\*=]?|\\/=?|[=!:\\?]?=|<=?|>=?|%=?|&&|\\|=?|\\~|!|\\^|\\\\)/,\n        delimitersRegexp = /^(?:[()\\[\\]{},:`=;]|\\.\\.?\\.?)/,\n        wordOperatorsRegexp = wordRegexp(wordOperators),\n        commonKeywordsRegexp = wordRegexp(commonKeywords),\n        commonAtomsRegexp = wordRegexp(commonAtoms),\n        commonDefRegexp = wordRegexp(commonDef),\n        vendorPrefixesRegexp = new RegExp(/^\\-(moz|ms|o|webkit)-/),\n        cssValuesWithBracketsRegexp = new RegExp(\"^(\" + cssValuesWithBrackets_.join(\"|\") + \")\\\\([\\\\w\\-\\\\#\\\\,\\\\.\\\\%\\\\s\\\\(\\\\)]*\\\\)\");\n\n    var tokenBase = function(stream, state) {\n\n      if (stream.eatSpace()) return null;\n\n      var ch = stream.peek();\n\n      // Single line Comment\n      if (stream.match('//')) {\n        stream.skipToEnd();\n        return \"comment\";\n      }\n\n      // Multiline Comment\n      if (stream.match('/*')) {\n        state.tokenizer = multilineComment;\n        return state.tokenizer(stream, state);\n      }\n\n      // Strings\n      if (ch === '\"' || ch === \"'\") {\n        stream.next();\n        state.tokenizer = buildStringTokenizer(ch);\n        return \"string\";\n      }\n\n      // Def\n      if (ch === \"@\") {\n        stream.next();\n        if (stream.match(/extend/)) {\n          dedent(state); // remove indentation after selectors\n        } else if (stream.match(/media[\\w-\\s]*[\\w-]/)) {\n          indent(state);\n        } else if(stream.eatWhile(/[\\w-]/)) {\n          if(stream.current().match(commonDefRegexp)) {\n            indent(state);\n          }\n        }\n        return \"def\";\n      }\n\n      // Number\n      if (stream.match(/^-?[0-9\\.]/, false)) {\n\n        // Floats\n        if (stream.match(/^-?\\d*\\.\\d+(e[\\+\\-]?\\d+)?/i) || stream.match(/^-?\\d+\\.\\d*/)) {\n\n          // Prevent from getting extra . on 1..\n          if (stream.peek() == \".\") {\n            stream.backUp(1);\n          }\n          // Units\n          stream.eatWhile(/[a-z%]/i);\n          return \"number\";\n        }\n        // Integers\n        if (stream.match(/^-?[1-9]\\d*(e[\\+\\-]?\\d+)?/) || stream.match(/^-?0(?![\\dx])/i)) {\n          // Units\n          stream.eatWhile(/[a-z%]/i);\n          return \"number\";\n        }\n      }\n\n      // Hex color and id selector\n      if (ch === \"#\") {\n        stream.next();\n\n        // Hex color\n        if (stream.match(/^[0-9a-f]{6}|[0-9a-f]{3}/i)) {\n          return \"atom\";\n        }\n\n        // ID selector\n        if (stream.match(/^[\\w-]+/i)) {\n          indent(state);\n          return \"builtin\";\n        }\n      }\n\n      // Vendor prefixes\n      if (stream.match(vendorPrefixesRegexp)) {\n        return \"meta\";\n      }\n\n      // Gradients and animation as CSS value\n      if (stream.match(cssValuesWithBracketsRegexp)) {\n        return \"atom\";\n      }\n\n      // Mixins / Functions with indentation\n      if (stream.sol() && stream.match(/^\\.?[a-z][\\w-]*\\(/i)) {\n        stream.backUp(1);\n        indent(state);\n        return \"keyword\";\n      }\n\n      // Mixins / Functions\n      if (stream.match(/^\\.?[a-z][\\w-]*\\(/i)) {\n        stream.backUp(1);\n        return \"keyword\";\n      }\n\n      // +Block mixins\n      if (stream.match(/^(\\+|\\-)[a-z][\\w-]+\\(/i)) {\n        stream.backUp(1);\n        indent(state);\n        return \"keyword\";\n      }\n\n      // url tokens\n      if (stream.match(/^url/) && stream.peek() === \"(\") {\n        state.tokenizer = urlTokens;\n        if(!stream.peek()) {\n          state.cursorHalf = 0;\n        }\n        return \"atom\";\n      }\n\n      // Class\n      if (stream.match(/^\\.[a-z][\\w-]*/i)) {\n        indent(state);\n        return \"qualifier\";\n      }\n\n      // & Parent Reference with BEM naming\n      if (stream.match(/^(_|__|-|--)[a-z0-9-]+/)) {\n        return \"qualifier\";\n      }\n\n      // Pseudo elements/classes\n      if (ch == ':' && stream.match(/^::?[\\w-]+/)) {\n        indent(state);\n        return \"variable-3\";\n      }\n\n      // Conditionals\n      if (stream.match(wordRegexp([\"for\", \"if\", \"else\", \"unless\"]))) {\n        indent(state);\n        return \"keyword\";\n      }\n\n      // Keywords\n      if (stream.match(commonKeywordsRegexp)) {\n        return \"keyword\";\n      }\n\n      // Atoms\n      if (stream.match(commonAtomsRegexp)) {\n        return \"atom\";\n      }\n\n      // Variables\n      if (stream.match(/^\\$?[a-z][\\w-]+\\s?=(\\s|[\\w-'\"\\$])/i)) {\n        stream.backUp(2);\n        var cssPropertie = stream.current().toLowerCase().match(/[\\w-]+/)[0];\n        return cssProperties[cssPropertie] === undefined ? \"variable-2\" : \"property\";\n      } else if (stream.match(/\\$[\\w-\\.]+/i)) {\n        return \"variable-2\";\n      } else if (stream.match(/\\$?[\\w-]+\\.[\\w-]+/i)) {\n        var cssTypeSelector = stream.current().toLowerCase().match(/[\\w]+/)[0];\n        if(cssTypeSelectors[cssTypeSelector] === undefined) {\n          return \"variable-2\";\n        } else stream.backUp(stream.current().length);\n      }\n\n      // !important\n      if (ch === \"!\") {\n        stream.next();\n        return stream.match(/^[\\w]+/) ? \"keyword\": \"operator\";\n      }\n\n      // / Root Reference\n      if (stream.match(/^\\/(:|\\.|#|[a-z])/)) {\n        stream.backUp(1);\n        return \"variable-3\";\n      }\n\n      // Operators and delimiters\n      if (stream.match(operatorsRegexp) || stream.match(wordOperatorsRegexp)) {\n        return \"operator\";\n      }\n      if (stream.match(delimitersRegexp)) {\n        return null;\n      }\n\n      // & Parent Reference\n      if (ch === \"&\") {\n        stream.next();\n        return \"variable-3\";\n      }\n\n      // Font family\n      if (stream.match(/^[A-Z][a-z0-9-]+/)) {\n        return \"string\";\n      }\n\n      // CSS rule\n      // NOTE: Some css selectors and property values have the same name\n      // (embed, menu, pre, progress, sub, table),\n      // so they will have the same color (.cm-atom).\n      if (stream.match(/[\\w-]*/i)) {\n\n        var word = stream.current().toLowerCase();\n\n        if(cssProperties[word] !== undefined) {\n          // CSS property\n          if(!stream.eol())\n            return \"property\";\n          else\n            return \"variable-2\";\n\n        } else if(cssValues[word] !== undefined) {\n          // CSS value\n          return \"atom\";\n\n        } else if(cssTypeSelectors[word] !== undefined) {\n          // CSS type selectors\n          indent(state);\n          return \"tag\";\n\n        } else if(word) {\n          // By default variable-2\n          return \"variable-2\";\n        }\n      }\n\n      // Handle non-detected items\n      stream.next();\n      return null;\n\n    };\n\n    var tokenLexer = function(stream, state) {\n\n      if (stream.sol()) {\n        state.indentCount = 0;\n      }\n\n      var style = state.tokenizer(stream, state);\n      var current = stream.current();\n\n      if (stream.eol() && (current === \"}\" || current === \",\")) {\n        dedent(state);\n      }\n\n      if (style !== null) {\n        var startOfToken = stream.pos - current.length;\n        var withCurrentIndent = startOfToken + (config.indentUnit * state.indentCount);\n\n        var newScopes = [];\n\n        for (var i = 0; i < state.scopes.length; i++) {\n          var scope = state.scopes[i];\n\n          if (scope.offset <= withCurrentIndent) {\n            newScopes.push(scope);\n          }\n        }\n\n        state.scopes = newScopes;\n      }\n\n      return style;\n    };\n\n    return {\n      startState: function() {\n        return {\n          tokenizer: tokenBase,\n          scopes: [{offset: 0, type: 'styl'}]\n        };\n      },\n\n      token: function(stream, state) {\n        var style = tokenLexer(stream, state);\n        state.lastToken = { style: style, content: stream.current() };\n        return style;\n      },\n\n      indent: function(state) {\n        return state.scopes[0].offset;\n      },\n\n      lineComment: \"//\",\n      fold: \"indent\"\n\n    };\n\n    function urlTokens(stream, state) {\n      var ch = stream.peek();\n\n      if (ch === \")\") {\n        stream.next();\n        state.tokenizer = tokenBase;\n        return \"operator\";\n      } else if (ch === \"(\") {\n        stream.next();\n        stream.eatSpace();\n\n        return \"operator\";\n      } else if (ch === \"'\" || ch === '\"') {\n        state.tokenizer = buildStringTokenizer(stream.next());\n        return \"string\";\n      } else {\n        state.tokenizer = buildStringTokenizer(\")\", false);\n        return \"string\";\n      }\n    }\n\n    function multilineComment(stream, state) {\n      if (stream.skipTo(\"*/\")) {\n        stream.next();\n        stream.next();\n        state.tokenizer = tokenBase;\n      } else {\n        stream.next();\n      }\n      return \"comment\";\n    }\n\n    function buildStringTokenizer(quote, greedy) {\n\n      if(greedy == null) {\n        greedy = true;\n      }\n\n      function stringTokenizer(stream, state) {\n        var nextChar = stream.next();\n        var peekChar = stream.peek();\n        var previousChar = stream.string.charAt(stream.pos-2);\n\n        var endingString = ((nextChar !== \"\\\\\" && peekChar === quote) ||\n                            (nextChar === quote && previousChar !== \"\\\\\"));\n\n        if (endingString) {\n          if (nextChar !== quote && greedy) {\n            stream.next();\n          }\n          state.tokenizer = tokenBase;\n          return \"string\";\n        } else if (nextChar === \"#\" && peekChar === \"{\") {\n          state.tokenizer = buildInterpolationTokenizer(stringTokenizer);\n          stream.next();\n          return \"operator\";\n        } else {\n          return \"string\";\n        }\n      }\n\n      return stringTokenizer;\n    }\n\n    function buildInterpolationTokenizer(currentTokenizer) {\n      return function(stream, state) {\n        if (stream.peek() === \"}\") {\n          stream.next();\n          state.tokenizer = currentTokenizer;\n          return \"operator\";\n        } else {\n          return tokenBase(stream, state);\n        }\n      };\n    }\n\n    function indent(state) {\n      if (state.indentCount == 0) {\n        state.indentCount++;\n        var lastScopeOffset = state.scopes[0].offset;\n        var currentOffset = lastScopeOffset + config.indentUnit;\n        state.scopes.unshift({ offset:currentOffset });\n      }\n    }\n\n    function dedent(state) {\n      if (state.scopes.length == 1) { return true; }\n      state.scopes.shift();\n    }\n\n  });\n\n  // https://developer.mozilla.org/en-US/docs/Web/HTML/Element\n  var cssTypeSelectors_ = [\"a\",\"abbr\",\"address\",\"area\",\"article\",\"aside\",\"audio\", \"b\", \"base\",\"bdi\",\"bdo\",\"bgsound\",\"blockquote\",\"body\",\"br\",\"button\",\"canvas\",\"caption\",\"cite\",\"code\",\"col\",\"colgroup\",\"data\",\"datalist\",\"dd\",\"del\",\"details\",\"dfn\",\"div\",\"dl\",\"dt\",\"em\",\"embed\",\"fieldset\",\"figcaption\",\"figure\",\"footer\",\"form\",\"h1\",\"h2\",\"h3\",\"h4\",\"h5\",\"h6\",\"head\",\"header\",\"hgroup\",\"hr\",\"html\",\"i\",\"iframe\",\"img\",\"input\",\"ins\",\"kbd\",\"keygen\",\"label\",\"legend\",\"li\",\"link\",\"main\",\"map\",\"mark\",\"marquee\",\"menu\",\"menuitem\",\"meta\",\"meter\",\"nav\",\"nobr\",\"noframes\",\"noscript\",\"object\",\"ol\",\"optgroup\",\"option\",\"output\",\"p\",\"param\",\"pre\",\"progress\",\"q\",\"rp\",\"rt\",\"ruby\",\"s\",\"samp\",\"script\",\"section\",\"select\",\"small\",\"source\",\"span\",\"strong\",\"style\",\"sub\",\"summary\",\"sup\",\"table\",\"tbody\",\"td\",\"textarea\",\"tfoot\",\"th\",\"thead\",\"time\",\"title\",\"tr\",\"track\",\"u\",\"ul\",\"var\",\"video\",\"wbr\"];\n  // https://github.com/csscomb/csscomb.js/blob/master/config/zen.json\n  var cssProperties_ = [\"position\",\"top\",\"right\",\"bottom\",\"left\",\"z-index\",\"display\",\"visibility\",\"flex-direction\",\"flex-order\",\"flex-pack\",\"float\",\"clear\",\"flex-align\",\"overflow\",\"overflow-x\",\"overflow-y\",\"overflow-scrolling\",\"clip\",\"box-sizing\",\"margin\",\"margin-top\",\"margin-right\",\"margin-bottom\",\"margin-left\",\"padding\",\"padding-top\",\"padding-right\",\"padding-bottom\",\"padding-left\",\"min-width\",\"min-height\",\"max-width\",\"max-height\",\"width\",\"height\",\"outline\",\"outline-width\",\"outline-style\",\"outline-color\",\"outline-offset\",\"border\",\"border-spacing\",\"border-collapse\",\"border-width\",\"border-style\",\"border-color\",\"border-top\",\"border-top-width\",\"border-top-style\",\"border-top-color\",\"border-right\",\"border-right-width\",\"border-right-style\",\"border-right-color\",\"border-bottom\",\"border-bottom-width\",\"border-bottom-style\",\"border-bottom-color\",\"border-left\",\"border-left-width\",\"border-left-style\",\"border-left-color\",\"border-radius\",\"border-top-left-radius\",\"border-top-right-radius\",\"border-bottom-right-radius\",\"border-bottom-left-radius\",\"border-image\",\"border-image-source\",\"border-image-slice\",\"border-image-width\",\"border-image-outset\",\"border-image-repeat\",\"border-top-image\",\"border-right-image\",\"border-bottom-image\",\"border-left-image\",\"border-corner-image\",\"border-top-left-image\",\"border-top-right-image\",\"border-bottom-right-image\",\"border-bottom-left-image\",\"background\",\"filter:progid:DXImageTransform\\\\.Microsoft\\\\.AlphaImageLoader\",\"background-color\",\"background-image\",\"background-attachment\",\"background-position\",\"background-position-x\",\"background-position-y\",\"background-clip\",\"background-origin\",\"background-size\",\"background-repeat\",\"box-decoration-break\",\"box-shadow\",\"color\",\"table-layout\",\"caption-side\",\"empty-cells\",\"list-style\",\"list-style-position\",\"list-style-type\",\"list-style-image\",\"quotes\",\"content\",\"counter-increment\",\"counter-reset\",\"writing-mode\",\"vertical-align\",\"text-align\",\"text-align-last\",\"text-decoration\",\"text-emphasis\",\"text-emphasis-position\",\"text-emphasis-style\",\"text-emphasis-color\",\"text-indent\",\"-ms-text-justify\",\"text-justify\",\"text-outline\",\"text-transform\",\"text-wrap\",\"text-overflow\",\"text-overflow-ellipsis\",\"text-overflow-mode\",\"text-size-adjust\",\"text-shadow\",\"white-space\",\"word-spacing\",\"word-wrap\",\"word-break\",\"tab-size\",\"hyphens\",\"letter-spacing\",\"font\",\"font-weight\",\"font-style\",\"font-variant\",\"font-size-adjust\",\"font-stretch\",\"font-size\",\"font-family\",\"src\",\"line-height\",\"opacity\",\"filter:\\\\\\\\\\\\\\\\'progid:DXImageTransform.Microsoft.Alpha\",\"filter:progid:DXImageTransform.Microsoft.Alpha\\\\(Opacity\",\"interpolation-mode\",\"filter\",\"resize\",\"cursor\",\"nav-index\",\"nav-up\",\"nav-right\",\"nav-down\",\"nav-left\",\"transition\",\"transition-delay\",\"transition-timing-function\",\"transition-duration\",\"transition-property\",\"transform\",\"transform-origin\",\"animation\",\"animation-name\",\"animation-duration\",\"animation-play-state\",\"animation-timing-function\",\"animation-delay\",\"animation-iteration-count\",\"animation-direction\",\"pointer-events\",\"unicode-bidi\",\"direction\",\"columns\",\"column-span\",\"column-width\",\"column-count\",\"column-fill\",\"column-gap\",\"column-rule\",\"column-rule-width\",\"column-rule-style\",\"column-rule-color\",\"break-before\",\"break-inside\",\"break-after\",\"page-break-before\",\"page-break-inside\",\"page-break-after\",\"orphans\",\"widows\",\"zoom\",\"max-zoom\",\"min-zoom\",\"user-zoom\",\"orientation\",\"text-rendering\",\"speak\",\"animation-fill-mode\",\"backface-visibility\",\"user-drag\",\"user-select\",\"appearance\"];\n  // https://github.com/codemirror/CodeMirror/blob/master/mode/css/css.js#L501\n  var cssValues_ = [\"above\",\"absolute\",\"activeborder\",\"activecaption\",\"afar\",\"after-white-space\",\"ahead\",\"alias\",\"all\",\"all-scroll\",\"alternate\",\"always\",\"amharic\",\"amharic-abegede\",\"antialiased\",\"appworkspace\",\"arabic-indic\",\"armenian\",\"asterisks\",\"auto\",\"avoid\",\"avoid-column\",\"avoid-page\",\"avoid-region\",\"background\",\"backwards\",\"baseline\",\"below\",\"bidi-override\",\"binary\",\"bengali\",\"block\",\"block-axis\",\"bold\",\"bolder\",\"border\",\"border-box\",\"both\",\"bottom\",\"break\",\"break-all\",\"break-word\",\"button-bevel\",\"buttonface\",\"buttonhighlight\",\"buttonshadow\",\"buttontext\",\"cambodian\",\"capitalize\",\"caps-lock-indicator\",\"captiontext\",\"caret\",\"cell\",\"center\",\"checkbox\",\"circle\",\"cjk-earthly-branch\",\"cjk-heavenly-stem\",\"cjk-ideographic\",\"clear\",\"clip\",\"close-quote\",\"col-resize\",\"collapse\",\"column\",\"compact\",\"condensed\",\"contain\",\"content\",\"content-box\",\"context-menu\",\"continuous\",\"copy\",\"cover\",\"crop\",\"cross\",\"crosshair\",\"currentcolor\",\"cursive\",\"dashed\",\"decimal\",\"decimal-leading-zero\",\"default\",\"default-button\",\"destination-atop\",\"destination-in\",\"destination-out\",\"destination-over\",\"devanagari\",\"disc\",\"discard\",\"document\",\"dot-dash\",\"dot-dot-dash\",\"dotted\",\"double\",\"down\",\"e-resize\",\"ease\",\"ease-in\",\"ease-in-out\",\"ease-out\",\"element\",\"ellipse\",\"ellipsis\",\"embed\",\"end\",\"ethiopic\",\"ethiopic-abegede\",\"ethiopic-abegede-am-et\",\"ethiopic-abegede-gez\",\"ethiopic-abegede-ti-er\",\"ethiopic-abegede-ti-et\",\"ethiopic-halehame-aa-er\",\"ethiopic-halehame-aa-et\",\"ethiopic-halehame-am-et\",\"ethiopic-halehame-gez\",\"ethiopic-halehame-om-et\",\"ethiopic-halehame-sid-et\",\"ethiopic-halehame-so-et\",\"ethiopic-halehame-ti-er\",\"ethiopic-halehame-ti-et\",\"ethiopic-halehame-tig\",\"ew-resize\",\"expanded\",\"extra-condensed\",\"extra-expanded\",\"fantasy\",\"fast\",\"fill\",\"fixed\",\"flat\",\"footnotes\",\"forwards\",\"from\",\"geometricPrecision\",\"georgian\",\"graytext\",\"groove\",\"gujarati\",\"gurmukhi\",\"hand\",\"hangul\",\"hangul-consonant\",\"hebrew\",\"help\",\"hidden\",\"hide\",\"higher\",\"highlight\",\"highlighttext\",\"hiragana\",\"hiragana-iroha\",\"horizontal\",\"hsl\",\"hsla\",\"icon\",\"ignore\",\"inactiveborder\",\"inactivecaption\",\"inactivecaptiontext\",\"infinite\",\"infobackground\",\"infotext\",\"inherit\",\"initial\",\"inline\",\"inline-axis\",\"inline-block\",\"inline-table\",\"inset\",\"inside\",\"intrinsic\",\"invert\",\"italic\",\"justify\",\"kannada\",\"katakana\",\"katakana-iroha\",\"keep-all\",\"khmer\",\"landscape\",\"lao\",\"large\",\"larger\",\"left\",\"level\",\"lighter\",\"line-through\",\"linear\",\"lines\",\"list-item\",\"listbox\",\"listitem\",\"local\",\"logical\",\"loud\",\"lower\",\"lower-alpha\",\"lower-armenian\",\"lower-greek\",\"lower-hexadecimal\",\"lower-latin\",\"lower-norwegian\",\"lower-roman\",\"lowercase\",\"ltr\",\"malayalam\",\"match\",\"media-controls-background\",\"media-current-time-display\",\"media-fullscreen-button\",\"media-mute-button\",\"media-play-button\",\"media-return-to-realtime-button\",\"media-rewind-button\",\"media-seek-back-button\",\"media-seek-forward-button\",\"media-slider\",\"media-sliderthumb\",\"media-time-remaining-display\",\"media-volume-slider\",\"media-volume-slider-container\",\"media-volume-sliderthumb\",\"medium\",\"menu\",\"menulist\",\"menulist-button\",\"menulist-text\",\"menulist-textfield\",\"menutext\",\"message-box\",\"middle\",\"min-intrinsic\",\"mix\",\"mongolian\",\"monospace\",\"move\",\"multiple\",\"myanmar\",\"n-resize\",\"narrower\",\"ne-resize\",\"nesw-resize\",\"no-close-quote\",\"no-drop\",\"no-open-quote\",\"no-repeat\",\"none\",\"normal\",\"not-allowed\",\"nowrap\",\"ns-resize\",\"nw-resize\",\"nwse-resize\",\"oblique\",\"octal\",\"open-quote\",\"optimizeLegibility\",\"optimizeSpeed\",\"oriya\",\"oromo\",\"outset\",\"outside\",\"outside-shape\",\"overlay\",\"overline\",\"padding\",\"padding-box\",\"painted\",\"page\",\"paused\",\"persian\",\"plus-darker\",\"plus-lighter\",\"pointer\",\"polygon\",\"portrait\",\"pre\",\"pre-line\",\"pre-wrap\",\"preserve-3d\",\"progress\",\"push-button\",\"radio\",\"read-only\",\"read-write\",\"read-write-plaintext-only\",\"rectangle\",\"region\",\"relative\",\"repeat\",\"repeat-x\",\"repeat-y\",\"reset\",\"reverse\",\"rgb\",\"rgba\",\"ridge\",\"right\",\"round\",\"row-resize\",\"rtl\",\"run-in\",\"running\",\"s-resize\",\"sans-serif\",\"scroll\",\"scrollbar\",\"se-resize\",\"searchfield\",\"searchfield-cancel-button\",\"searchfield-decoration\",\"searchfield-results-button\",\"searchfield-results-decoration\",\"semi-condensed\",\"semi-expanded\",\"separate\",\"serif\",\"show\",\"sidama\",\"single\",\"skip-white-space\",\"slide\",\"slider-horizontal\",\"slider-vertical\",\"sliderthumb-horizontal\",\"sliderthumb-vertical\",\"slow\",\"small-caps\",\"small-caption\",\"smaller\",\"solid\",\"somali\",\"source-atop\",\"source-in\",\"source-out\",\"source-over\",\"space\",\"square\",\"square-button\",\"start\",\"static\",\"status-bar\",\"stretch\",\"stroke\",\"sub\",\"subpixel-antialiased\",\"super\",\"sw-resize\",\"table\",\"table-caption\",\"table-cell\",\"table-column\",\"table-column-group\",\"table-footer-group\",\"table-header-group\",\"table-row\",\"table-row-group\",\"telugu\",\"text\",\"text-bottom\",\"text-top\",\"textfield\",\"thai\",\"thick\",\"thin\",\"threeddarkshadow\",\"threedface\",\"threedhighlight\",\"threedlightshadow\",\"threedshadow\",\"tibetan\",\"tigre\",\"tigrinya-er\",\"tigrinya-er-abegede\",\"tigrinya-et\",\"tigrinya-et-abegede\",\"to\",\"top\",\"transparent\",\"ultra-condensed\",\"ultra-expanded\",\"underline\",\"up\",\"upper-alpha\",\"upper-armenian\",\"upper-greek\",\"upper-hexadecimal\",\"upper-latin\",\"upper-norwegian\",\"upper-roman\",\"uppercase\",\"urdu\",\"url\",\"vertical\",\"vertical-text\",\"visible\",\"visibleFill\",\"visiblePainted\",\"visibleStroke\",\"visual\",\"w-resize\",\"wait\",\"wave\",\"wider\",\"window\",\"windowframe\",\"windowtext\",\"x-large\",\"x-small\",\"xor\",\"xx-large\",\"xx-small\",\"bicubic\",\"optimizespeed\",\"grayscale\"];\n  var cssColorValues_ = [\"aliceblue\",\"antiquewhite\",\"aqua\",\"aquamarine\",\"azure\",\"beige\",\"bisque\",\"black\",\"blanchedalmond\",\"blue\",\"blueviolet\",\"brown\",\"burlywood\",\"cadetblue\",\"chartreuse\",\"chocolate\",\"coral\",\"cornflowerblue\",\"cornsilk\",\"crimson\",\"cyan\",\"darkblue\",\"darkcyan\",\"darkgoldenrod\",\"darkgray\",\"darkgreen\",\"darkkhaki\",\"darkmagenta\",\"darkolivegreen\",\"darkorange\",\"darkorchid\",\"darkred\",\"darksalmon\",\"darkseagreen\",\"darkslateblue\",\"darkslategray\",\"darkturquoise\",\"darkviolet\",\"deeppink\",\"deepskyblue\",\"dimgray\",\"dodgerblue\",\"firebrick\",\"floralwhite\",\"forestgreen\",\"fuchsia\",\"gainsboro\",\"ghostwhite\",\"gold\",\"goldenrod\",\"gray\",\"grey\",\"green\",\"greenyellow\",\"honeydew\",\"hotpink\",\"indianred\",\"indigo\",\"ivory\",\"khaki\",\"lavender\",\"lavenderblush\",\"lawngreen\",\"lemonchiffon\",\"lightblue\",\"lightcoral\",\"lightcyan\",\"lightgoldenrodyellow\",\"lightgray\",\"lightgreen\",\"lightpink\",\"lightsalmon\",\"lightseagreen\",\"lightskyblue\",\"lightslategray\",\"lightsteelblue\",\"lightyellow\",\"lime\",\"limegreen\",\"linen\",\"magenta\",\"maroon\",\"mediumaquamarine\",\"mediumblue\",\"mediumorchid\",\"mediumpurple\",\"mediumseagreen\",\"mediumslateblue\",\"mediumspringgreen\",\"mediumturquoise\",\"mediumvioletred\",\"midnightblue\",\"mintcream\",\"mistyrose\",\"moccasin\",\"navajowhite\",\"navy\",\"oldlace\",\"olive\",\"olivedrab\",\"orange\",\"orangered\",\"orchid\",\"palegoldenrod\",\"palegreen\",\"paleturquoise\",\"palevioletred\",\"papayawhip\",\"peachpuff\",\"peru\",\"pink\",\"plum\",\"powderblue\",\"purple\",\"red\",\"rosybrown\",\"royalblue\",\"saddlebrown\",\"salmon\",\"sandybrown\",\"seagreen\",\"seashell\",\"sienna\",\"silver\",\"skyblue\",\"slateblue\",\"slategray\",\"snow\",\"springgreen\",\"steelblue\",\"tan\",\"teal\",\"thistle\",\"tomato\",\"turquoise\",\"violet\",\"wheat\",\"white\",\"whitesmoke\",\"yellow\",\"yellowgreen\"];\n  var cssValuesWithBrackets_ = [\"gradient\",\"linear-gradient\",\"radial-gradient\",\"repeating-linear-gradient\",\"repeating-radial-gradient\",\"cubic-bezier\",\"translateX\",\"translateY\",\"translate3d\",\"rotate3d\",\"scale\",\"scale3d\",\"perspective\",\"skewX\"];\n\n  var wordOperators = [\"in\", \"and\", \"or\", \"not\", \"is a\", \"is\", \"isnt\", \"defined\", \"if unless\"],\n      commonKeywords = [\"for\", \"if\", \"else\", \"unless\", \"return\"],\n      commonAtoms = [\"null\", \"true\", \"false\", \"href\", \"title\", \"type\", \"not-allowed\", \"readonly\", \"disabled\"],\n      commonDef = [\"@font-face\", \"@keyframes\", \"@media\", \"@viewport\", \"@page\", \"@host\", \"@supports\", \"@block\", \"@css\"],\n      cssTypeSelectors = keySet(cssTypeSelectors_),\n      cssProperties = keySet(cssProperties_),\n      cssValues = keySet(cssValues_.concat(cssColorValues_)),\n      hintWords = wordOperators.concat(commonKeywords,\n                                       commonAtoms,\n                                       commonDef,\n                                       cssTypeSelectors_,\n                                       cssProperties_,\n                                       cssValues_,\n                                       cssValuesWithBrackets_,\n                                       cssColorValues_);\n\n  function wordRegexp(words) {\n    return new RegExp(\"^((\" + words.join(\")|(\") + \"))\\\\b\");\n  };\n\n  function keySet(array) {\n    var keys = {};\n    for (var i = 0; i < array.length; ++i) {\n      keys[array[i]] = true;\n    }\n    return keys;\n  };\n\n  CodeMirror.registerHelper(\"hintWords\", \"stylus\", hintWords);\n  CodeMirror.defineMIME(\"text/x-styl\", \"stylus\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/tcl/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Tcl mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<link rel=\"stylesheet\" href=\"../../theme/night.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"tcl.js\"></script>\n<script src=\"../../addon/scroll/scrollpastend.js\"></script>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Tcl</a>\n  </ul>\n</div>\n\n<article>\n<h2>Tcl mode</h2>\n<form><textarea id=\"code\" name=\"code\">\n##############################################################################################\n##  ##     whois.tcl for eggdrop by Ford_Lawnmower irc.geekshed.net #Script-Help        ##  ##\n##############################################################################################\n## To use this script you must set channel flag +whois (ie .chanset #chan +whois)           ##\n##############################################################################################\n##      ____                __                 ###########################################  ##\n##     / __/___ _ ___ _ ___/ /____ ___   ___   ###########################################  ##\n##    / _/ / _ `// _ `// _  // __// _ \\ / _ \\  ###########################################  ##\n##   /___/ \\_, / \\_, / \\_,_//_/   \\___// .__/  ###########################################  ##\n##        /___/ /___/                 /_/      ###########################################  ##\n##                                             ###########################################  ##\n##############################################################################################\n##  ##                             Start Setup.                                         ##  ##\n##############################################################################################\nnamespace eval whois {\n## change cmdchar to the trigger you want to use                                        ##  ##\n  variable cmdchar \"!\"\n## change command to the word trigger you would like to use.                            ##  ##\n## Keep in mind, This will also change the .chanset +/-command                          ##  ##\n  variable command \"whois\"\n## change textf to the colors you want for the text.                                    ##  ##\n  variable textf \"\\017\\00304\"\n## change tagf to the colors you want for tags:                                         ##  ##\n  variable tagf \"\\017\\002\"\n## Change logo to the logo you want at the start of the line.                           ##  ##\n  variable logo \"\\017\\00304\\002\\[\\00306W\\003hois\\00304\\]\\017\"\n## Change lineout to the results you want. Valid results are channel users modes topic  ##  ##\n  variable lineout \"channel users modes topic\"\n##############################################################################################\n##  ##                           End Setup.                                              ## ##\n##############################################################################################\n  variable channel \"\"\n  setudef flag $whois::command\n  bind pub -|- [string trimleft $whois::cmdchar]${whois::command} whois::list\n  bind raw -|- \"311\" whois::311\n  bind raw -|- \"312\" whois::312\n  bind raw -|- \"319\" whois::319\n  bind raw -|- \"317\" whois::317\n  bind raw -|- \"313\" whois::multi\n  bind raw -|- \"310\" whois::multi\n  bind raw -|- \"335\" whois::multi\n  bind raw -|- \"301\" whois::301\n  bind raw -|- \"671\" whois::multi\n  bind raw -|- \"320\" whois::multi\n  bind raw -|- \"401\" whois::multi\n  bind raw -|- \"318\" whois::318\n  bind raw -|- \"307\" whois::307\n}\nproc whois::311 {from key text} {\n  if {[regexp -- {^[^\\s]+\\s(.+?)\\s(.+?)\\s(.+?)\\s\\*\\s\\:(.+)$} $text wholematch nick ident host realname]} {\n    putserv \"PRIVMSG $whois::channel :${whois::logo} ${whois::tagf}Host:${whois::textf} \\\n        $nick \\(${ident}@${host}\\) ${whois::tagf}Realname:${whois::textf} $realname\"\n  }\n}\nproc whois::multi {from key text} {\n  if {[regexp {\\:(.*)$} $text match $key]} {\n    putserv \"PRIVMSG $whois::channel :${whois::logo} ${whois::tagf}Note:${whois::textf} [subst $$key]\"\n        return 1\n  }\n}\nproc whois::312 {from key text} {\n  regexp {([^\\s]+)\\s\\:} $text match server\n  putserv \"PRIVMSG $whois::channel :${whois::logo} ${whois::tagf}Server:${whois::textf} $server\"\n}\nproc whois::319 {from key text} {\n  if {[regexp {.+\\:(.+)$} $text match channels]} {\n    putserv \"PRIVMSG $whois::channel :${whois::logo} ${whois::tagf}Channels:${whois::textf} $channels\"\n  }\n}\nproc whois::317 {from key text} {\n  if {[regexp -- {.*\\s(\\d+)\\s(\\d+)\\s\\:} $text wholematch idle signon]} {\n    putserv \"PRIVMSG $whois::channel :${whois::logo} ${whois::tagf}Connected:${whois::textf} \\\n        [ctime $signon] ${whois::tagf}Idle:${whois::textf} [duration $idle]\"\n  }\n}\nproc whois::301 {from key text} {\n  if {[regexp {^.+\\s[^\\s]+\\s\\:(.*)$} $text match awaymsg]} {\n    putserv \"PRIVMSG $whois::channel :${whois::logo} ${whois::tagf}Away:${whois::textf} $awaymsg\"\n  }\n}\nproc whois::318 {from key text} {\n  namespace eval whois {\n        variable channel \"\"\n  }\n  variable whois::channel \"\"\n}\nproc whois::307 {from key text} {\n  putserv \"PRIVMSG $whois::channel :${whois::logo} ${whois::tagf}Services:${whois::textf} Registered Nick\"\n}\nproc whois::list {nick host hand chan text} {\n  if {[lsearch -exact [channel info $chan] \"+${whois::command}\"] != -1} {\n    namespace eval whois {\n          variable channel \"\"\n        }\n    variable whois::channel $chan\n    putserv \"WHOIS $text\"\n  }\n}\nputlog \"\\002*Loaded* \\017\\00304\\002\\[\\00306W\\003hois\\00304\\]\\017 \\002by \\\nFord_Lawnmower irc.GeekShed.net #Script-Help\"\n</textarea></form>\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        theme: \"night\",\n        lineNumbers: true,\n        indentUnit: 2,\n        scrollPastEnd: true,\n        mode: \"text/x-tcl\"\n      });\n    </script>\n\n    <p><strong>MIME types defined:</strong> <code>text/x-tcl</code>.</p>\n\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/tcl/tcl.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n//tcl mode by Ford_Lawnmower :: Based on Velocity mode by Steve O'Hara\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"tcl\", function() {\n  function parseWords(str) {\n    var obj = {}, words = str.split(\" \");\n    for (var i = 0; i < words.length; ++i) obj[words[i]] = true;\n    return obj;\n  }\n  var keywords = parseWords(\"Tcl safe after append array auto_execok auto_import auto_load \" +\n        \"auto_mkindex auto_mkindex_old auto_qualify auto_reset bgerror \" +\n        \"binary break catch cd close concat continue dde eof encoding error \" +\n        \"eval exec exit expr fblocked fconfigure fcopy file fileevent filename \" +\n        \"filename flush for foreach format gets glob global history http if \" +\n        \"incr info interp join lappend lindex linsert list llength load lrange \" +\n        \"lreplace lsearch lset lsort memory msgcat namespace open package parray \" +\n        \"pid pkg::create pkg_mkIndex proc puts pwd re_syntax read regex regexp \" +\n        \"registry regsub rename resource return scan seek set socket source split \" +\n        \"string subst switch tcl_endOfWord tcl_findLibrary tcl_startOfNextWord \" +\n        \"tcl_wordBreakAfter tcl_startOfPreviousWord tcl_wordBreakBefore tcltest \" +\n        \"tclvars tell time trace unknown unset update uplevel upvar variable \" +\n    \"vwait\");\n    var functions = parseWords(\"if elseif else and not or eq ne in ni for foreach while switch\");\n    var isOperatorChar = /[+\\-*&%=<>!?^\\/\\|]/;\n    function chain(stream, state, f) {\n      state.tokenize = f;\n      return f(stream, state);\n    }\n    function tokenBase(stream, state) {\n      var beforeParams = state.beforeParams;\n      state.beforeParams = false;\n      var ch = stream.next();\n      if ((ch == '\"' || ch == \"'\") && state.inParams)\n        return chain(stream, state, tokenString(ch));\n      else if (/[\\[\\]{}\\(\\),;\\.]/.test(ch)) {\n        if (ch == \"(\" && beforeParams) state.inParams = true;\n        else if (ch == \")\") state.inParams = false;\n          return null;\n      }\n      else if (/\\d/.test(ch)) {\n        stream.eatWhile(/[\\w\\.]/);\n        return \"number\";\n      }\n      else if (ch == \"#\" && stream.eat(\"*\")) {\n        return chain(stream, state, tokenComment);\n      }\n      else if (ch == \"#\" && stream.match(/ *\\[ *\\[/)) {\n        return chain(stream, state, tokenUnparsed);\n      }\n      else if (ch == \"#\" && stream.eat(\"#\")) {\n        stream.skipToEnd();\n        return \"comment\";\n      }\n      else if (ch == '\"') {\n        stream.skipTo(/\"/);\n        return \"comment\";\n      }\n      else if (ch == \"$\") {\n        stream.eatWhile(/[$_a-z0-9A-Z\\.{:]/);\n        stream.eatWhile(/}/);\n        state.beforeParams = true;\n        return \"builtin\";\n      }\n      else if (isOperatorChar.test(ch)) {\n        stream.eatWhile(isOperatorChar);\n        return \"comment\";\n      }\n      else {\n        stream.eatWhile(/[\\w\\$_{}\\xa1-\\uffff]/);\n        var word = stream.current().toLowerCase();\n        if (keywords && keywords.propertyIsEnumerable(word))\n          return \"keyword\";\n        if (functions && functions.propertyIsEnumerable(word)) {\n          state.beforeParams = true;\n          return \"keyword\";\n        }\n        return null;\n      }\n    }\n    function tokenString(quote) {\n      return function(stream, state) {\n      var escaped = false, next, end = false;\n      while ((next = stream.next()) != null) {\n        if (next == quote && !escaped) {\n          end = true;\n          break;\n        }\n        escaped = !escaped && next == \"\\\\\";\n      }\n      if (end) state.tokenize = tokenBase;\n        return \"string\";\n      };\n    }\n    function tokenComment(stream, state) {\n      var maybeEnd = false, ch;\n      while (ch = stream.next()) {\n        if (ch == \"#\" && maybeEnd) {\n          state.tokenize = tokenBase;\n          break;\n        }\n        maybeEnd = (ch == \"*\");\n      }\n      return \"comment\";\n    }\n    function tokenUnparsed(stream, state) {\n      var maybeEnd = 0, ch;\n      while (ch = stream.next()) {\n        if (ch == \"#\" && maybeEnd == 2) {\n          state.tokenize = tokenBase;\n          break;\n        }\n        if (ch == \"]\")\n          maybeEnd++;\n        else if (ch != \" \")\n          maybeEnd = 0;\n      }\n      return \"meta\";\n    }\n    return {\n      startState: function() {\n        return {\n          tokenize: tokenBase,\n          beforeParams: false,\n          inParams: false\n        };\n      },\n      token: function(stream, state) {\n        if (stream.eatSpace()) return null;\n        return state.tokenize(stream, state);\n      }\n    };\n});\nCodeMirror.defineMIME(\"text/x-tcl\", \"tcl\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/textile/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Textile mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"textile.js\"></script>\n<style>.CodeMirror {background: #f8f8f8;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/marijnh/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=\"active\" href=\"#\">Textile</a>\n  </ul>\n</div>\n\n<article>\n    <h2>Textile mode</h2>\n    <form><textarea id=\"code\" name=\"code\">\nh1. Textile Mode\n\nA paragraph without formatting.\n\np. A simple Paragraph.\n\n\nh2. Phrase Modifiers\n\nHere are some simple phrase modifiers: *strong*, _emphasis_, **bold**, and __italic__.\n\nA ??citation??, -deleted text-, +inserted text+, some ^superscript^, and some ~subscript~.\n\nA %span element% and @code element@\n\nA \"link\":http://example.com, a \"link with (alt text)\":urlAlias\n\n[urlAlias]http://example.com/\n\nAn image: !http://example.com/image.png! and an image with a link: !http://example.com/image.png!:http://example.com\n\nA sentence with a footnote.[123]\n\nfn123. The footnote is defined here.\n\nRegistered(r), Trademark(tm), and Copyright(c)\n\n\nh2. Headers\n\nh1. Top level\nh2. Second level\nh3. Third level\nh4. Fourth level\nh5. Fifth level\nh6. Lowest level\n\n\nh2.  Lists\n\n* An unordered list\n** foo bar\n*** foo bar\n**** foo bar\n** foo bar\n\n# An ordered list\n## foo bar\n### foo bar\n#### foo bar\n## foo bar\n\n- definition list := description\n- another item    := foo bar\n- spanning ines   :=\n                     foo bar\n\n                     foo bar =:\n\n\nh2. Attributes\n\nLayouts and phrase modifiers can be modified with various kinds of attributes: alignment, CSS ID, CSS class names, language, padding, and CSS styles.\n\nh3. Alignment\n\ndiv<. left align\ndiv>. right align\n\nh3. CSS ID and class name\n\nYou are a %(my-id#my-classname) rad% person.\n\nh3. Language\n\np[en_CA]. Strange weather, eh?\n\nh3. Horizontal Padding\n\np(())). 2em left padding, 3em right padding\n\nh3. CSS styling\n\np{background: red}. Fire!\n\n\nh2. Table\n\n|_.              Header 1               |_.      Header 2        |\n|{background:#ddd}. Cell with background|         Normal         |\n|\\2.         Cell spanning 2 columns                             |\n|/2.         Cell spanning 2 rows       |(cell-class). one       |\n|                                                two             |\n|>.                  Right aligned cell |<. Left aligned cell    |\n\n\nh3. A table with attributes:\n\ntable(#prices).\n|Adults|$5|\n|Children|$2|\n\n\nh2. Code blocks\n\nbc.\nfunction factorial(n) {\n    if (n === 0) {\n        return 1;\n    }\n    return n * factorial(n - 1);\n}\n\npre..\n                ,,,,,,\n            o#'9MMHb':'-,o,\n         .oH\":HH$' \"' ' -*R&o,\n        dMMM*\"\"'`'      .oM\"HM?.\n       ,MMM'          \"HLbd< ?&H\\\n      .:MH .\"\\          ` MM  MM&b\n     . \"*H    -        &MMMMMMMMMH:\n     .    dboo        MMMMMMMMMMMM.\n     .   dMMMMMMb      *MMMMMMMMMP.\n     .    MMMMMMMP        *MMMMMP .\n          `#MMMMM           MM6P ,\n       '    `MMMP\"           HM*`,\n        '    :MM             .- ,\n         '.   `#?..  .       ..'\n            -.   .         .-\n              ''-.oo,oo.-''\n\n\\. _(9>\n \\==_)\n  -'=\n\nh2. Temporarily disabling textile markup\n\nnotextile. Don't __touch this!__\n\nSurround text with double-equals to disable textile inline. Example: Use ==*asterisks*== for *strong* text.\n\n\nh2. HTML\n\nSome block layouts are simply textile versions of HTML tags with the same name, like @div@, @pre@, and @p@. HTML tags can also exist on their own line:\n\n<section>\n  <h1>Title</h1>\n  <p>Hello!</p>\n</section>\n\n</textarea></form>\n    <script>\n        var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n            lineNumbers: true,\n            mode: \"text/x-textile\"\n        });\n    </script>\n\n    <p><strong>MIME types defined:</strong> <code>text/x-textile</code>.</p>\n\n    <p><strong>Parsing/Highlighting Tests:</strong> <a href=\"../../test/index.html#textile_*\">normal</a>,  <a href=\"../../test/index.html#verbose,textile_*\">verbose</a>.</p>\n\n</article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/textile/test.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function() {\n  var mode = CodeMirror.getMode({tabSize: 4}, 'textile');\n  function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); }\n\n  MT('simpleParagraphs',\n      'Some text.',\n      '',\n      'Some more text.');\n\n  /*\n   * Phrase Modifiers\n   */\n\n  MT('em',\n      'foo [em _bar_]');\n\n  MT('emBoogus',\n      'code_mirror');\n\n  MT('strong',\n      'foo [strong *bar*]');\n\n  MT('strongBogus',\n      '3 * 3 = 9');\n\n  MT('italic',\n      'foo [em __bar__]');\n\n  MT('italicBogus',\n      'code__mirror');\n\n  MT('bold',\n      'foo [strong **bar**]');\n\n  MT('boldBogus',\n      '3 ** 3 = 27');\n\n  MT('simpleLink',\n      '[link \"CodeMirror\":http://codemirror.net]');\n\n  MT('referenceLink',\n      '[link \"CodeMirror\":code_mirror]',\n      'Normal Text.',\n      '[link [[code_mirror]]http://codemirror.net]');\n\n  MT('footCite',\n      'foo bar[qualifier [[1]]]');\n\n  MT('footCiteBogus',\n      'foo bar[[1a2]]');\n\n  MT('special-characters',\n          'Registered [tag (r)], ' +\n          'Trademark [tag (tm)], and ' +\n          'Copyright [tag (c)] 2008');\n\n  MT('cite',\n      \"A book is [keyword ??The Count of Monte Cristo??] by Dumas.\");\n\n  MT('additionAndDeletion',\n      'The news networks declared [negative -Al Gore-] ' +\n        '[positive +George W. Bush+] the winner in Florida.');\n\n  MT('subAndSup',\n      'f(x, n) = log [builtin ~4~] x [builtin ^n^]');\n\n  MT('spanAndCode',\n      'A [quote %span element%] and [atom @code element@]');\n\n  MT('spanBogus',\n      'Percentage 25% is not a span.');\n\n  MT('citeBogus',\n      'Question? is not a citation.');\n\n  MT('codeBogus',\n      'user@example.com');\n\n  MT('subBogus',\n      '~username');\n\n  MT('supBogus',\n      'foo ^ bar');\n\n  MT('deletionBogus',\n      '3 - 3 = 0');\n\n  MT('additionBogus',\n      '3 + 3 = 6');\n\n  MT('image',\n      'An image: [string !http://www.example.com/image.png!]');\n\n  MT('imageWithAltText',\n      'An image: [string !http://www.example.com/image.png (Alt Text)!]');\n\n  MT('imageWithUrl',\n      'An image: [string !http://www.example.com/image.png!:http://www.example.com/]');\n\n  /*\n   * Headers\n   */\n\n  MT('h1',\n      '[header&header-1 h1. foo]');\n\n  MT('h2',\n      '[header&header-2 h2. foo]');\n\n  MT('h3',\n      '[header&header-3 h3. foo]');\n\n  MT('h4',\n      '[header&header-4 h4. foo]');\n\n  MT('h5',\n      '[header&header-5 h5. foo]');\n\n  MT('h6',\n      '[header&header-6 h6. foo]');\n\n  MT('h7Bogus',\n      'h7. foo');\n\n  MT('multipleHeaders',\n      '[header&header-1 h1. Heading 1]',\n      '',\n      'Some text.',\n      '',\n      '[header&header-2 h2. Heading 2]',\n      '',\n      'More text.');\n\n  MT('h1inline',\n      '[header&header-1 h1. foo ][header&header-1&em _bar_][header&header-1  baz]');\n\n  /*\n   * Lists\n   */\n\n  MT('ul',\n      'foo',\n      'bar',\n      '',\n      '[variable-2 * foo]',\n      '[variable-2 * bar]');\n\n  MT('ulNoBlank',\n      'foo',\n      'bar',\n      '[variable-2 * foo]',\n      '[variable-2 * bar]');\n\n  MT('ol',\n      'foo',\n      'bar',\n      '',\n      '[variable-2 # foo]',\n      '[variable-2 # bar]');\n\n  MT('olNoBlank',\n      'foo',\n      'bar',\n      '[variable-2 # foo]',\n      '[variable-2 # bar]');\n\n  MT('ulFormatting',\n      '[variable-2 * ][variable-2&em _foo_][variable-2  bar]',\n      '[variable-2 * ][variable-2&strong *][variable-2&em&strong _foo_]' +\n        '[variable-2&strong *][variable-2  bar]',\n      '[variable-2 * ][variable-2&strong *foo*][variable-2  bar]');\n\n  MT('olFormatting',\n      '[variable-2 # ][variable-2&em _foo_][variable-2  bar]',\n      '[variable-2 # ][variable-2&strong *][variable-2&em&strong _foo_]' +\n        '[variable-2&strong *][variable-2  bar]',\n      '[variable-2 # ][variable-2&strong *foo*][variable-2  bar]');\n\n  MT('ulNested',\n      '[variable-2 * foo]',\n      '[variable-3 ** bar]',\n      '[keyword *** bar]',\n      '[variable-2 **** bar]',\n      '[variable-3 ** bar]');\n\n  MT('olNested',\n      '[variable-2 # foo]',\n      '[variable-3 ## bar]',\n      '[keyword ### bar]',\n      '[variable-2 #### bar]',\n      '[variable-3 ## bar]');\n\n  MT('ulNestedWithOl',\n      '[variable-2 * foo]',\n      '[variable-3 ## bar]',\n      '[keyword *** bar]',\n      '[variable-2 #### bar]',\n      '[variable-3 ** bar]');\n\n  MT('olNestedWithUl',\n      '[variable-2 # foo]',\n      '[variable-3 ** bar]',\n      '[keyword ### bar]',\n      '[variable-2 **** bar]',\n      '[variable-3 ## bar]');\n\n  MT('definitionList',\n      '[number - coffee := Hot ][number&em _and_][number  black]',\n      '',\n      'Normal text.');\n\n  MT('definitionListSpan',\n      '[number - coffee :=]',\n      '',\n      '[number Hot ][number&em _and_][number  black =:]',\n      '',\n      'Normal text.');\n\n  MT('boo',\n      '[number - dog := woof woof]',\n      '[number - cat := meow meow]',\n      '[number - whale :=]',\n      '[number Whale noises.]',\n      '',\n      '[number Also, ][number&em _splashing_][number . =:]');\n\n  /*\n   * Attributes\n   */\n\n  MT('divWithAttribute',\n      '[punctuation div][punctuation&attribute (#my-id)][punctuation . foo bar]');\n\n  MT('divWithAttributeAnd2emRightPadding',\n      '[punctuation div][punctuation&attribute (#my-id)((][punctuation . foo bar]');\n\n  MT('divWithClassAndId',\n      '[punctuation div][punctuation&attribute (my-class#my-id)][punctuation . foo bar]');\n\n  MT('paragraphWithCss',\n      'p[attribute {color:red;}]. foo bar');\n\n  MT('paragraphNestedStyles',\n      'p. [strong *foo ][strong&em _bar_][strong *]');\n\n  MT('paragraphWithLanguage',\n      'p[attribute [[fr]]]. Parlez-vous français?');\n\n  MT('paragraphLeftAlign',\n      'p[attribute <]. Left');\n\n  MT('paragraphRightAlign',\n      'p[attribute >]. Right');\n\n  MT('paragraphRightAlign',\n      'p[attribute =]. Center');\n\n  MT('paragraphJustified',\n      'p[attribute <>]. Justified');\n\n  MT('paragraphWithLeftIndent1em',\n      'p[attribute (]. Left');\n\n  MT('paragraphWithRightIndent1em',\n      'p[attribute )]. Right');\n\n  MT('paragraphWithLeftIndent2em',\n      'p[attribute ((]. Left');\n\n  MT('paragraphWithRightIndent2em',\n      'p[attribute ))]. Right');\n\n  MT('paragraphWithLeftIndent3emRightIndent2em',\n      'p[attribute ((())]. Right');\n\n  MT('divFormatting',\n      '[punctuation div. ][punctuation&strong *foo ]' +\n        '[punctuation&strong&em _bar_][punctuation&strong *]');\n\n  MT('phraseModifierAttributes',\n      'p[attribute (my-class)]. This is a paragraph that has a class and' +\n      ' this [em _][em&attribute (#special-phrase)][em emphasized phrase_]' +\n      ' has an id.');\n\n  MT('linkWithClass',\n      '[link \"(my-class). This is a link with class\":http://redcloth.org]');\n\n  /*\n   * Layouts\n   */\n\n  MT('paragraphLayouts',\n      'p. This is one paragraph.',\n      '',\n      'p. This is another.');\n\n  MT('div',\n      '[punctuation div. foo bar]');\n\n  MT('pre',\n      '[operator pre. Text]');\n\n  MT('bq.',\n      '[bracket bq. foo bar]',\n      '',\n      'Normal text.');\n\n  MT('footnote',\n      '[variable fn123. foo ][variable&strong *bar*]');\n\n  /*\n   * Spanning Layouts\n   */\n\n  MT('bq..ThenParagraph',\n      '[bracket bq.. foo bar]',\n      '',\n      '[bracket More quote.]',\n      'p. Normal Text');\n\n  MT('bq..ThenH1',\n      '[bracket bq.. foo bar]',\n      '',\n      '[bracket More quote.]',\n      '[header&header-1 h1. Header Text]');\n\n  MT('bc..ThenParagraph',\n      '[atom bc.. # Some ruby code]',\n      '[atom obj = {foo: :bar}]',\n      '[atom puts obj]',\n      '',\n      '[atom obj[[:love]] = \"*love*\"]',\n      '[atom puts obj.love.upcase]',\n      '',\n      'p. Normal text.');\n\n  MT('fn1..ThenParagraph',\n      '[variable fn1.. foo bar]',\n      '',\n      '[variable More.]',\n      'p. Normal Text');\n\n  MT('pre..ThenParagraph',\n      '[operator pre.. foo bar]',\n      '',\n      '[operator More.]',\n      'p. Normal Text');\n\n  /*\n   * Tables\n   */\n\n  MT('table',\n      '[variable-3&operator |_. name |_. age|]',\n      '[variable-3 |][variable-3&strong *Walter*][variable-3 |   5  |]',\n      '[variable-3 |Florence|   6  |]',\n      '',\n      'p. Normal text.');\n\n  MT('tableWithAttributes',\n      '[variable-3&operator |_. name |_. age|]',\n      '[variable-3 |][variable-3&attribute /2.][variable-3  Jim |]',\n      '[variable-3 |][variable-3&attribute \\\\2{color: red}.][variable-3  Sam |]');\n\n  /*\n   * HTML\n   */\n\n  MT('html',\n      '[comment <div id=\"wrapper\">]',\n      '[comment <section id=\"introduction\">]',\n      '',\n      '[header&header-1 h1. Welcome]',\n      '',\n      '[variable-2 * Item one]',\n      '[variable-2 * Item two]',\n      '',\n      '[comment <a href=\"http://example.com\">Example</a>]',\n      '',\n      '[comment </section>]',\n      '[comment </div>]');\n\n  MT('inlineHtml',\n      'I can use HTML directly in my [comment <span class=\"youbetcha\">Textile</span>].');\n\n  /*\n   * No-Textile\n   */\n\n  MT('notextile',\n    '[string-2 notextile. *No* formatting]');\n\n  MT('notextileInline',\n      'Use [string-2 ==*asterisks*==] for [strong *strong*] text.');\n\n  MT('notextileWithPre',\n      '[operator pre. *No* formatting]');\n\n  MT('notextileWithSpanningPre',\n      '[operator pre.. *No* formatting]',\n      '',\n      '[operator *No* formatting]');\n\n  /* Only toggling phrases between non-word chars. */\n\n  MT('phrase-in-word',\n     'foo_bar_baz');\n\n  MT('phrase-non-word',\n     '[negative -x-] aaa-bbb ccc-ddd [negative -eee-] fff [negative -ggg-]');\n\n  MT('phrase-lone-dash',\n     'foo - bar - baz');\n})();\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/textile/textile.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") { // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  } else if (typeof define == \"function\" && define.amd) { // AMD\n    define([\"../../lib/codemirror\"], mod);\n  } else { // Plain browser env\n    mod(CodeMirror);\n  }\n})(function(CodeMirror) {\n  \"use strict\";\n\n  var TOKEN_STYLES = {\n    addition: \"positive\",\n    attributes: \"attribute\",\n    bold: \"strong\",\n    cite: \"keyword\",\n    code: \"atom\",\n    definitionList: \"number\",\n    deletion: \"negative\",\n    div: \"punctuation\",\n    em: \"em\",\n    footnote: \"variable\",\n    footCite: \"qualifier\",\n    header: \"header\",\n    html: \"comment\",\n    image: \"string\",\n    italic: \"em\",\n    link: \"link\",\n    linkDefinition: \"link\",\n    list1: \"variable-2\",\n    list2: \"variable-3\",\n    list3: \"keyword\",\n    notextile: \"string-2\",\n    pre: \"operator\",\n    p: \"property\",\n    quote: \"bracket\",\n    span: \"quote\",\n    specialChar: \"tag\",\n    strong: \"strong\",\n    sub: \"builtin\",\n    sup: \"builtin\",\n    table: \"variable-3\",\n    tableHeading: \"operator\"\n  };\n\n  function startNewLine(stream, state) {\n    state.mode = Modes.newLayout;\n    state.tableHeading = false;\n\n    if (state.layoutType === \"definitionList\" && state.spanningLayout &&\n        stream.match(RE(\"definitionListEnd\"), false))\n      state.spanningLayout = false;\n  }\n\n  function handlePhraseModifier(stream, state, ch) {\n    if (ch === \"_\") {\n      if (stream.eat(\"_\"))\n        return togglePhraseModifier(stream, state, \"italic\", /__/, 2);\n      else\n        return togglePhraseModifier(stream, state, \"em\", /_/, 1);\n    }\n\n    if (ch === \"*\") {\n      if (stream.eat(\"*\")) {\n        return togglePhraseModifier(stream, state, \"bold\", /\\*\\*/, 2);\n      }\n      return togglePhraseModifier(stream, state, \"strong\", /\\*/, 1);\n    }\n\n    if (ch === \"[\") {\n      if (stream.match(/\\d+\\]/)) state.footCite = true;\n      return tokenStyles(state);\n    }\n\n    if (ch === \"(\") {\n      var spec = stream.match(/^(r|tm|c)\\)/);\n      if (spec)\n        return tokenStylesWith(state, TOKEN_STYLES.specialChar);\n    }\n\n    if (ch === \"<\" && stream.match(/(\\w+)[^>]+>[^<]+<\\/\\1>/))\n      return tokenStylesWith(state, TOKEN_STYLES.html);\n\n    if (ch === \"?\" && stream.eat(\"?\"))\n      return togglePhraseModifier(stream, state, \"cite\", /\\?\\?/, 2);\n\n    if (ch === \"=\" && stream.eat(\"=\"))\n      return togglePhraseModifier(stream, state, \"notextile\", /==/, 2);\n\n    if (ch === \"-\" && !stream.eat(\"-\"))\n      return togglePhraseModifier(stream, state, \"deletion\", /-/, 1);\n\n    if (ch === \"+\")\n      return togglePhraseModifier(stream, state, \"addition\", /\\+/, 1);\n\n    if (ch === \"~\")\n      return togglePhraseModifier(stream, state, \"sub\", /~/, 1);\n\n    if (ch === \"^\")\n      return togglePhraseModifier(stream, state, \"sup\", /\\^/, 1);\n\n    if (ch === \"%\")\n      return togglePhraseModifier(stream, state, \"span\", /%/, 1);\n\n    if (ch === \"@\")\n      return togglePhraseModifier(stream, state, \"code\", /@/, 1);\n\n    if (ch === \"!\") {\n      var type = togglePhraseModifier(stream, state, \"image\", /(?:\\([^\\)]+\\))?!/, 1);\n      stream.match(/^:\\S+/); // optional Url portion\n      return type;\n    }\n    return tokenStyles(state);\n  }\n\n  function togglePhraseModifier(stream, state, phraseModifier, closeRE, openSize) {\n    var charBefore = stream.pos > openSize ? stream.string.charAt(stream.pos - openSize - 1) : null;\n    var charAfter = stream.peek();\n    if (state[phraseModifier]) {\n      if ((!charAfter || /\\W/.test(charAfter)) && charBefore && /\\S/.test(charBefore)) {\n        var type = tokenStyles(state);\n        state[phraseModifier] = false;\n        return type;\n      }\n    } else if ((!charBefore || /\\W/.test(charBefore)) && charAfter && /\\S/.test(charAfter) &&\n               stream.match(new RegExp(\"^.*\\\\S\" + closeRE.source + \"(?:\\\\W|$)\"), false)) {\n      state[phraseModifier] = true;\n      state.mode = Modes.attributes;\n    }\n    return tokenStyles(state);\n  };\n\n  function tokenStyles(state) {\n    var disabled = textileDisabled(state);\n    if (disabled) return disabled;\n\n    var styles = [];\n    if (state.layoutType) styles.push(TOKEN_STYLES[state.layoutType]);\n\n    styles = styles.concat(activeStyles(\n      state, \"addition\", \"bold\", \"cite\", \"code\", \"deletion\", \"em\", \"footCite\",\n      \"image\", \"italic\", \"link\", \"span\", \"strong\", \"sub\", \"sup\", \"table\", \"tableHeading\"));\n\n    if (state.layoutType === \"header\")\n      styles.push(TOKEN_STYLES.header + \"-\" + state.header);\n\n    return styles.length ? styles.join(\" \") : null;\n  }\n\n  function textileDisabled(state) {\n    var type = state.layoutType;\n\n    switch(type) {\n    case \"notextile\":\n    case \"code\":\n    case \"pre\":\n      return TOKEN_STYLES[type];\n    default:\n      if (state.notextile)\n        return TOKEN_STYLES.notextile + (type ? (\" \" + TOKEN_STYLES[type]) : \"\");\n      return null;\n    }\n  }\n\n  function tokenStylesWith(state, extraStyles) {\n    var disabled = textileDisabled(state);\n    if (disabled) return disabled;\n\n    var type = tokenStyles(state);\n    if (extraStyles)\n      return type ? (type + \" \" + extraStyles) : extraStyles;\n    else\n      return type;\n  }\n\n  function activeStyles(state) {\n    var styles = [];\n    for (var i = 1; i < arguments.length; ++i) {\n      if (state[arguments[i]])\n        styles.push(TOKEN_STYLES[arguments[i]]);\n    }\n    return styles;\n  }\n\n  function blankLine(state) {\n    var spanningLayout = state.spanningLayout, type = state.layoutType;\n\n    for (var key in state) if (state.hasOwnProperty(key))\n      delete state[key];\n\n    state.mode = Modes.newLayout;\n    if (spanningLayout) {\n      state.layoutType = type;\n      state.spanningLayout = true;\n    }\n  }\n\n  var REs = {\n    cache: {},\n    single: {\n      bc: \"bc\",\n      bq: \"bq\",\n      definitionList: /- [^(?::=)]+:=+/,\n      definitionListEnd: /.*=:\\s*$/,\n      div: \"div\",\n      drawTable: /\\|.*\\|/,\n      foot: /fn\\d+/,\n      header: /h[1-6]/,\n      html: /\\s*<(?:\\/)?(\\w+)(?:[^>]+)?>(?:[^<]+<\\/\\1>)?/,\n      link: /[^\"]+\":\\S/,\n      linkDefinition: /\\[[^\\s\\]]+\\]\\S+/,\n      list: /(?:#+|\\*+)/,\n      notextile: \"notextile\",\n      para: \"p\",\n      pre: \"pre\",\n      table: \"table\",\n      tableCellAttributes: /[\\/\\\\]\\d+/,\n      tableHeading: /\\|_\\./,\n      tableText: /[^\"_\\*\\[\\(\\?\\+~\\^%@|-]+/,\n      text: /[^!\"_=\\*\\[\\(<\\?\\+~\\^%@-]+/\n    },\n    attributes: {\n      align: /(?:<>|<|>|=)/,\n      selector: /\\([^\\(][^\\)]+\\)/,\n      lang: /\\[[^\\[\\]]+\\]/,\n      pad: /(?:\\(+|\\)+){1,2}/,\n      css: /\\{[^\\}]+\\}/\n    },\n    createRe: function(name) {\n      switch (name) {\n      case \"drawTable\":\n        return REs.makeRe(\"^\", REs.single.drawTable, \"$\");\n      case \"html\":\n        return REs.makeRe(\"^\", REs.single.html, \"(?:\", REs.single.html, \")*\", \"$\");\n      case \"linkDefinition\":\n        return REs.makeRe(\"^\", REs.single.linkDefinition, \"$\");\n      case \"listLayout\":\n        return REs.makeRe(\"^\", REs.single.list, RE(\"allAttributes\"), \"*\\\\s+\");\n      case \"tableCellAttributes\":\n        return REs.makeRe(\"^\", REs.choiceRe(REs.single.tableCellAttributes,\n                                            RE(\"allAttributes\")), \"+\\\\.\");\n      case \"type\":\n        return REs.makeRe(\"^\", RE(\"allTypes\"));\n      case \"typeLayout\":\n        return REs.makeRe(\"^\", RE(\"allTypes\"), RE(\"allAttributes\"),\n                          \"*\\\\.\\\\.?\", \"(\\\\s+|$)\");\n      case \"attributes\":\n        return REs.makeRe(\"^\", RE(\"allAttributes\"), \"+\");\n\n      case \"allTypes\":\n        return REs.choiceRe(REs.single.div, REs.single.foot,\n                            REs.single.header, REs.single.bc, REs.single.bq,\n                            REs.single.notextile, REs.single.pre, REs.single.table,\n                            REs.single.para);\n\n      case \"allAttributes\":\n        return REs.choiceRe(REs.attributes.selector, REs.attributes.css,\n                            REs.attributes.lang, REs.attributes.align, REs.attributes.pad);\n\n      default:\n        return REs.makeRe(\"^\", REs.single[name]);\n      }\n    },\n    makeRe: function() {\n      var pattern = \"\";\n      for (var i = 0; i < arguments.length; ++i) {\n        var arg = arguments[i];\n        pattern += (typeof arg === \"string\") ? arg : arg.source;\n      }\n      return new RegExp(pattern);\n    },\n    choiceRe: function() {\n      var parts = [arguments[0]];\n      for (var i = 1; i < arguments.length; ++i) {\n        parts[i * 2 - 1] = \"|\";\n        parts[i * 2] = arguments[i];\n      }\n\n      parts.unshift(\"(?:\");\n      parts.push(\")\");\n      return REs.makeRe.apply(null, parts);\n    }\n  };\n\n  function RE(name) {\n    return (REs.cache[name] || (REs.cache[name] = REs.createRe(name)));\n  }\n\n  var Modes = {\n    newLayout: function(stream, state) {\n      if (stream.match(RE(\"typeLayout\"), false)) {\n        state.spanningLayout = false;\n        return (state.mode = Modes.blockType)(stream, state);\n      }\n      var newMode;\n      if (!textileDisabled(state)) {\n        if (stream.match(RE(\"listLayout\"), false))\n          newMode = Modes.list;\n        else if (stream.match(RE(\"drawTable\"), false))\n          newMode = Modes.table;\n        else if (stream.match(RE(\"linkDefinition\"), false))\n          newMode = Modes.linkDefinition;\n        else if (stream.match(RE(\"definitionList\")))\n          newMode = Modes.definitionList;\n        else if (stream.match(RE(\"html\"), false))\n          newMode = Modes.html;\n      }\n      return (state.mode = (newMode || Modes.text))(stream, state);\n    },\n\n    blockType: function(stream, state) {\n      var match, type;\n      state.layoutType = null;\n\n      if (match = stream.match(RE(\"type\")))\n        type = match[0];\n      else\n        return (state.mode = Modes.text)(stream, state);\n\n      if (match = type.match(RE(\"header\"))) {\n        state.layoutType = \"header\";\n        state.header = parseInt(match[0][1]);\n      } else if (type.match(RE(\"bq\"))) {\n        state.layoutType = \"quote\";\n      } else if (type.match(RE(\"bc\"))) {\n        state.layoutType = \"code\";\n      } else if (type.match(RE(\"foot\"))) {\n        state.layoutType = \"footnote\";\n      } else if (type.match(RE(\"notextile\"))) {\n        state.layoutType = \"notextile\";\n      } else if (type.match(RE(\"pre\"))) {\n        state.layoutType = \"pre\";\n      } else if (type.match(RE(\"div\"))) {\n        state.layoutType = \"div\";\n      } else if (type.match(RE(\"table\"))) {\n        state.layoutType = \"table\";\n      }\n\n      state.mode = Modes.attributes;\n      return tokenStyles(state);\n    },\n\n    text: function(stream, state) {\n      if (stream.match(RE(\"text\"))) return tokenStyles(state);\n\n      var ch = stream.next();\n      if (ch === '\"')\n        return (state.mode = Modes.link)(stream, state);\n      return handlePhraseModifier(stream, state, ch);\n    },\n\n    attributes: function(stream, state) {\n      state.mode = Modes.layoutLength;\n\n      if (stream.match(RE(\"attributes\")))\n        return tokenStylesWith(state, TOKEN_STYLES.attributes);\n      else\n        return tokenStyles(state);\n    },\n\n    layoutLength: function(stream, state) {\n      if (stream.eat(\".\") && stream.eat(\".\"))\n        state.spanningLayout = true;\n\n      state.mode = Modes.text;\n      return tokenStyles(state);\n    },\n\n    list: function(stream, state) {\n      var match = stream.match(RE(\"list\"));\n      state.listDepth = match[0].length;\n      var listMod = (state.listDepth - 1) % 3;\n      if (!listMod)\n        state.layoutType = \"list1\";\n      else if (listMod === 1)\n        state.layoutType = \"list2\";\n      else\n        state.layoutType = \"list3\";\n\n      state.mode = Modes.attributes;\n      return tokenStyles(state);\n    },\n\n    link: function(stream, state) {\n      state.mode = Modes.text;\n      if (stream.match(RE(\"link\"))) {\n        stream.match(/\\S+/);\n        return tokenStylesWith(state, TOKEN_STYLES.link);\n      }\n      return tokenStyles(state);\n    },\n\n    linkDefinition: function(stream, state) {\n      stream.skipToEnd();\n      return tokenStylesWith(state, TOKEN_STYLES.linkDefinition);\n    },\n\n    definitionList: function(stream, state) {\n      stream.match(RE(\"definitionList\"));\n\n      state.layoutType = \"definitionList\";\n\n      if (stream.match(/\\s*$/))\n        state.spanningLayout = true;\n      else\n        state.mode = Modes.attributes;\n\n      return tokenStyles(state);\n    },\n\n    html: function(stream, state) {\n      stream.skipToEnd();\n      return tokenStylesWith(state, TOKEN_STYLES.html);\n    },\n\n    table: function(stream, state) {\n      state.layoutType = \"table\";\n      return (state.mode = Modes.tableCell)(stream, state);\n    },\n\n    tableCell: function(stream, state) {\n      if (stream.match(RE(\"tableHeading\")))\n        state.tableHeading = true;\n      else\n        stream.eat(\"|\");\n\n      state.mode = Modes.tableCellAttributes;\n      return tokenStyles(state);\n    },\n\n    tableCellAttributes: function(stream, state) {\n      state.mode = Modes.tableText;\n\n      if (stream.match(RE(\"tableCellAttributes\")))\n        return tokenStylesWith(state, TOKEN_STYLES.attributes);\n      else\n        return tokenStyles(state);\n    },\n\n    tableText: function(stream, state) {\n      if (stream.match(RE(\"tableText\")))\n        return tokenStyles(state);\n\n      if (stream.peek() === \"|\") { // end of cell\n        state.mode = Modes.tableCell;\n        return tokenStyles(state);\n      }\n      return handlePhraseModifier(stream, state, stream.next());\n    }\n  };\n\n  CodeMirror.defineMode(\"textile\", function() {\n    return {\n      startState: function() {\n        return { mode: Modes.newLayout };\n      },\n      token: function(stream, state) {\n        if (stream.sol()) startNewLine(stream, state);\n        return state.mode(stream, state);\n      },\n      blankLine: blankLine\n    };\n  });\n\n  CodeMirror.defineMIME(\"text/x-textile\", \"textile\");\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/tiddlywiki/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: TiddlyWiki mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<link rel=\"stylesheet\" href=\"tiddlywiki.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"../../addon/edit/matchbrackets.js\"></script>\n<script src=\"tiddlywiki.js\"></script>\n<style type=\"text/css\">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">TiddlyWiki</a>\n  </ul>\n</div>\n\n<article>\n<h2>TiddlyWiki mode</h2>\n\n\n<div><textarea id=\"code\" name=\"code\">\n!TiddlyWiki Formatting\n* Rendered versions can be found at: http://www.tiddlywiki.com/#Reference\n\n|!Option            | !Syntax            |\n|bold font          | ''bold''           |\n|italic type        | //italic//         |\n|underlined text    | __underlined__     |\n|strikethrough text | --strikethrough--  |\n|superscript text   | super^^script^^    |\n|subscript text     | sub~~script~~      |\n|highlighted text   | @@highlighted@@    |\n|preformatted text  | {{{preformatted}}} |\n\n!Block Elements\n<<<\n!Heading 1\n\n!!Heading 2\n\n!!!Heading 3\n\n!!!!Heading 4\n\n!!!!!Heading 5\n<<<\n\n!!Lists\n<<<\n* unordered list, level 1\n** unordered list, level 2\n*** unordered list, level 3\n\n# ordered list, level 1\n## ordered list, level 2\n### unordered list, level 3\n\n; definition list, term\n: definition list, description\n<<<\n\n!!Blockquotes\n<<<\n> blockquote, level 1\n>> blockquote, level 2\n>>> blockquote, level 3\n\n> blockquote\n<<<\n\n!!Preformatted Text\n<<<\n{{{\npreformatted (e.g. code)\n}}}\n<<<\n\n!!Code Sections\n<<<\n{{{\nText style code\n}}}\n\n//{{{\nJS styled code. TiddlyWiki mixed mode should support highlighter switching in the future.\n//}}}\n\n<!--{{{-->\nXML styled code. TiddlyWiki mixed mode should support highlighter switching in the future.\n<!--}}}-->\n<<<\n\n!!Tables\n<<<\n|CssClass|k\n|!heading column 1|!heading column 2|\n|row 1, column 1|row 1, column 2|\n|row 2, column 1|row 2, column 2|\n|>|COLSPAN|\n|ROWSPAN| ... |\n|~| ... |\n|CssProperty:value;...| ... |\n|caption|c\n\n''Annotation:''\n* The {{{>}}} marker creates a \"colspan\", causing the current cell to merge with the one to the right.\n* The {{{~}}} marker creates a \"rowspan\", causing the current cell to merge with the one above.\n<<<\n!!Images /% TODO %/\ncf. [[TiddlyWiki.com|http://www.tiddlywiki.com/#EmbeddedImages]]\n\n!Hyperlinks\n* [[WikiWords|WikiWord]] are automatically transformed to hyperlinks to the respective tiddler\n** the automatic transformation can be suppressed by preceding the respective WikiWord with a tilde ({{{~}}}): {{{~WikiWord}}}\n* [[PrettyLinks]] are enclosed in square brackets and contain the desired tiddler name: {{{[[tiddler name]]}}}\n** optionally, a custom title or description can be added, separated by a pipe character ({{{|}}}): {{{[[title|target]]}}}<br>'''N.B.:''' In this case, the target can also be any website (i.e. URL).\n\n!Custom Styling\n* {{{@@CssProperty:value;CssProperty:value;...@@}}}<br>''N.B.:'' CSS color definitions should use lowercase letters to prevent the inadvertent creation of WikiWords.\n* <html><code>{{customCssClass{...}}}</code></html>\n* raw HTML can be inserted by enclosing the respective code in HTML tags: {{{<html> ... </html>}}}\n\n!Special Markers\n* {{{<br>}}} forces a manual line break\n* {{{----}}} creates a horizontal ruler\n* [[HTML entities|http://www.tiddlywiki.com/#HtmlEntities]]\n* [[HTML entities local|HtmlEntities]]\n* {{{<<macroName>>}}} calls the respective [[macro|Macros]]\n* To hide text within a tiddler so that it is not displayed, it can be wrapped in {{{/%}}} and {{{%/}}}.<br/>This can be a useful trick for hiding drafts or annotating complex markup.\n* To prevent wiki markup from taking effect for a particular section, that section can be enclosed in three double quotes: e.g. {{{\"\"\"WikiWord\"\"\"}}}.\n</textarea></div>\n\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        mode: 'tiddlywiki',      \n        lineNumbers: true,\n        matchBrackets: true\n      });\n    </script>\n\n    <p>TiddlyWiki mode supports a single configuration.</p>\n\n    <p><strong>MIME types defined:</strong> <code>text/x-tiddlywiki</code>.</p>\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/tiddlywiki/tiddlywiki.css",
    "content": "span.cm-underlined {\n  text-decoration: underline;\n}\nspan.cm-strikethrough {\n  text-decoration: line-through;\n}\nspan.cm-brace {\n  color: #170;\n  font-weight: bold;\n}\nspan.cm-table {\n  color: blue;\n  font-weight: bold;\n}\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/tiddlywiki/tiddlywiki.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n/***\n    |''Name''|tiddlywiki.js|\n    |''Description''|Enables TiddlyWikiy syntax highlighting using CodeMirror|\n    |''Author''|PMario|\n    |''Version''|0.1.7|\n    |''Status''|''stable''|\n    |''Source''|[[GitHub|https://github.com/pmario/CodeMirror2/blob/tw-syntax/mode/tiddlywiki]]|\n    |''Documentation''|http://codemirror.tiddlyspace.com/|\n    |''License''|[[MIT License|http://www.opensource.org/licenses/mit-license.php]]|\n    |''CoreVersion''|2.5.0|\n    |''Requires''|codemirror.js|\n    |''Keywords''|syntax highlighting color code mirror codemirror|\n    ! Info\n    CoreVersion parameter is needed for TiddlyWiki only!\n***/\n//{{{\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"tiddlywiki\", function () {\n  // Tokenizer\n  var textwords = {};\n\n  var keywords = function () {\n    function kw(type) {\n      return { type: type, style: \"macro\"};\n    }\n    return {\n      \"allTags\": kw('allTags'), \"closeAll\": kw('closeAll'), \"list\": kw('list'),\n      \"newJournal\": kw('newJournal'), \"newTiddler\": kw('newTiddler'),\n      \"permaview\": kw('permaview'), \"saveChanges\": kw('saveChanges'),\n      \"search\": kw('search'), \"slider\": kw('slider'),   \"tabs\": kw('tabs'),\n      \"tag\": kw('tag'), \"tagging\": kw('tagging'),       \"tags\": kw('tags'),\n      \"tiddler\": kw('tiddler'), \"timeline\": kw('timeline'),\n      \"today\": kw('today'), \"version\": kw('version'),   \"option\": kw('option'),\n\n      \"with\": kw('with'),\n      \"filter\": kw('filter')\n    };\n  }();\n\n  var isSpaceName = /[\\w_\\-]/i,\n  reHR = /^\\-\\-\\-\\-+$/,                                 // <hr>\n  reWikiCommentStart = /^\\/\\*\\*\\*$/,            // /***\n  reWikiCommentStop = /^\\*\\*\\*\\/$/,             // ***/\n  reBlockQuote = /^<<<$/,\n\n  reJsCodeStart = /^\\/\\/\\{\\{\\{$/,                       // //{{{ js block start\n  reJsCodeStop = /^\\/\\/\\}\\}\\}$/,                        // //}}} js stop\n  reXmlCodeStart = /^<!--\\{\\{\\{-->$/,           // xml block start\n  reXmlCodeStop = /^<!--\\}\\}\\}-->$/,            // xml stop\n\n  reCodeBlockStart = /^\\{\\{\\{$/,                        // {{{ TW text div block start\n  reCodeBlockStop = /^\\}\\}\\}$/,                 // }}} TW text stop\n\n  reUntilCodeStop = /.*?\\}\\}\\}/;\n\n  function chain(stream, state, f) {\n    state.tokenize = f;\n    return f(stream, state);\n  }\n\n  // Used as scratch variables to communicate multiple values without\n  // consing up tons of objects.\n  var type, content;\n\n  function ret(tp, style, cont) {\n    type = tp;\n    content = cont;\n    return style;\n  }\n\n  function jsTokenBase(stream, state) {\n    var sol = stream.sol(), ch;\n\n    state.block = false;        // indicates the start of a code block.\n\n    ch = stream.peek();         // don't eat, to make matching simpler\n\n    // check start of  blocks\n    if (sol && /[<\\/\\*{}\\-]/.test(ch)) {\n      if (stream.match(reCodeBlockStart)) {\n        state.block = true;\n        return chain(stream, state, twTokenCode);\n      }\n      if (stream.match(reBlockQuote)) {\n        return ret('quote', 'quote');\n      }\n      if (stream.match(reWikiCommentStart) || stream.match(reWikiCommentStop)) {\n        return ret('code', 'comment');\n      }\n      if (stream.match(reJsCodeStart) || stream.match(reJsCodeStop) || stream.match(reXmlCodeStart) || stream.match(reXmlCodeStop)) {\n        return ret('code', 'comment');\n      }\n      if (stream.match(reHR)) {\n        return ret('hr', 'hr');\n      }\n    } // sol\n    ch = stream.next();\n\n    if (sol && /[\\/\\*!#;:>|]/.test(ch)) {\n      if (ch == \"!\") { // tw header\n        stream.skipToEnd();\n        return ret(\"header\", \"header\");\n      }\n      if (ch == \"*\") { // tw list\n        stream.eatWhile('*');\n        return ret(\"list\", \"comment\");\n      }\n      if (ch == \"#\") { // tw numbered list\n        stream.eatWhile('#');\n        return ret(\"list\", \"comment\");\n      }\n      if (ch == \";\") { // definition list, term\n        stream.eatWhile(';');\n        return ret(\"list\", \"comment\");\n      }\n      if (ch == \":\") { // definition list, description\n        stream.eatWhile(':');\n        return ret(\"list\", \"comment\");\n      }\n      if (ch == \">\") { // single line quote\n        stream.eatWhile(\">\");\n        return ret(\"quote\", \"quote\");\n      }\n      if (ch == '|') {\n        return ret('table', 'header');\n      }\n    }\n\n    if (ch == '{' && stream.match(/\\{\\{/)) {\n      return chain(stream, state, twTokenCode);\n    }\n\n    // rudimentary html:// file:// link matching. TW knows much more ...\n    if (/[hf]/i.test(ch)) {\n      if (/[ti]/i.test(stream.peek()) && stream.match(/\\b(ttps?|tp|ile):\\/\\/[\\-A-Z0-9+&@#\\/%?=~_|$!:,.;]*[A-Z0-9+&@#\\/%=~_|$]/i)) {\n        return ret(\"link\", \"link\");\n      }\n    }\n    // just a little string indicator, don't want to have the whole string covered\n    if (ch == '\"') {\n      return ret('string', 'string');\n    }\n    if (ch == '~') {    // _no_ CamelCase indicator should be bold\n      return ret('text', 'brace');\n    }\n    if (/[\\[\\]]/.test(ch)) { // check for [[..]]\n      if (stream.peek() == ch) {\n        stream.next();\n        return ret('brace', 'brace');\n      }\n    }\n    if (ch == \"@\") {    // check for space link. TODO fix @@...@@ highlighting\n      stream.eatWhile(isSpaceName);\n      return ret(\"link\", \"link\");\n    }\n    if (/\\d/.test(ch)) {        // numbers\n      stream.eatWhile(/\\d/);\n      return ret(\"number\", \"number\");\n    }\n    if (ch == \"/\") { // tw invisible comment\n      if (stream.eat(\"%\")) {\n        return chain(stream, state, twTokenComment);\n      }\n      else if (stream.eat(\"/\")) { //\n        return chain(stream, state, twTokenEm);\n      }\n    }\n    if (ch == \"_\") { // tw underline\n      if (stream.eat(\"_\")) {\n        return chain(stream, state, twTokenUnderline);\n      }\n    }\n    // strikethrough and mdash handling\n    if (ch == \"-\") {\n      if (stream.eat(\"-\")) {\n        // if strikethrough looks ugly, change CSS.\n        if (stream.peek() != ' ')\n          return chain(stream, state, twTokenStrike);\n        // mdash\n        if (stream.peek() == ' ')\n          return ret('text', 'brace');\n      }\n    }\n    if (ch == \"'\") { // tw bold\n      if (stream.eat(\"'\")) {\n        return chain(stream, state, twTokenStrong);\n      }\n    }\n    if (ch == \"<\") { // tw macro\n      if (stream.eat(\"<\")) {\n        return chain(stream, state, twTokenMacro);\n      }\n    }\n    else {\n      return ret(ch);\n    }\n\n    // core macro handling\n    stream.eatWhile(/[\\w\\$_]/);\n    var word = stream.current(),\n    known = textwords.propertyIsEnumerable(word) && textwords[word];\n\n    return known ? ret(known.type, known.style, word) : ret(\"text\", null, word);\n\n  } // jsTokenBase()\n\n  // tw invisible comment\n  function twTokenComment(stream, state) {\n    var maybeEnd = false,\n    ch;\n    while (ch = stream.next()) {\n      if (ch == \"/\" && maybeEnd) {\n        state.tokenize = jsTokenBase;\n        break;\n      }\n      maybeEnd = (ch == \"%\");\n    }\n    return ret(\"comment\", \"comment\");\n  }\n\n  // tw strong / bold\n  function twTokenStrong(stream, state) {\n    var maybeEnd = false,\n    ch;\n    while (ch = stream.next()) {\n      if (ch == \"'\" && maybeEnd) {\n        state.tokenize = jsTokenBase;\n        break;\n      }\n      maybeEnd = (ch == \"'\");\n    }\n    return ret(\"text\", \"strong\");\n  }\n\n  // tw code\n  function twTokenCode(stream, state) {\n    var ch, sb = state.block;\n\n    if (sb && stream.current()) {\n      return ret(\"code\", \"comment\");\n    }\n\n    if (!sb && stream.match(reUntilCodeStop)) {\n      state.tokenize = jsTokenBase;\n      return ret(\"code\", \"comment\");\n    }\n\n    if (sb && stream.sol() && stream.match(reCodeBlockStop)) {\n      state.tokenize = jsTokenBase;\n      return ret(\"code\", \"comment\");\n    }\n\n    ch = stream.next();\n    return (sb) ? ret(\"code\", \"comment\") : ret(\"code\", \"comment\");\n  }\n\n  // tw em / italic\n  function twTokenEm(stream, state) {\n    var maybeEnd = false,\n    ch;\n    while (ch = stream.next()) {\n      if (ch == \"/\" && maybeEnd) {\n        state.tokenize = jsTokenBase;\n        break;\n      }\n      maybeEnd = (ch == \"/\");\n    }\n    return ret(\"text\", \"em\");\n  }\n\n  // tw underlined text\n  function twTokenUnderline(stream, state) {\n    var maybeEnd = false,\n    ch;\n    while (ch = stream.next()) {\n      if (ch == \"_\" && maybeEnd) {\n        state.tokenize = jsTokenBase;\n        break;\n      }\n      maybeEnd = (ch == \"_\");\n    }\n    return ret(\"text\", \"underlined\");\n  }\n\n  // tw strike through text looks ugly\n  // change CSS if needed\n  function twTokenStrike(stream, state) {\n    var maybeEnd = false, ch;\n\n    while (ch = stream.next()) {\n      if (ch == \"-\" && maybeEnd) {\n        state.tokenize = jsTokenBase;\n        break;\n      }\n      maybeEnd = (ch == \"-\");\n    }\n    return ret(\"text\", \"strikethrough\");\n  }\n\n  // macro\n  function twTokenMacro(stream, state) {\n    var ch, word, known;\n\n    if (stream.current() == '<<') {\n      return ret('brace', 'macro');\n    }\n\n    ch = stream.next();\n    if (!ch) {\n      state.tokenize = jsTokenBase;\n      return ret(ch);\n    }\n    if (ch == \">\") {\n      if (stream.peek() == '>') {\n        stream.next();\n        state.tokenize = jsTokenBase;\n        return ret(\"brace\", \"macro\");\n      }\n    }\n\n    stream.eatWhile(/[\\w\\$_]/);\n    word = stream.current();\n    known = keywords.propertyIsEnumerable(word) && keywords[word];\n\n    if (known) {\n      return ret(known.type, known.style, word);\n    }\n    else {\n      return ret(\"macro\", null, word);\n    }\n  }\n\n  // Interface\n  return {\n    startState: function () {\n      return {\n        tokenize: jsTokenBase,\n        indented: 0,\n        level: 0\n      };\n    },\n\n    token: function (stream, state) {\n      if (stream.eatSpace()) return null;\n      var style = state.tokenize(stream, state);\n      return style;\n    },\n\n    electricChars: \"\"\n  };\n});\n\nCodeMirror.defineMIME(\"text/x-tiddlywiki\", \"tiddlywiki\");\n});\n\n//}}}\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/tiki/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Tiki wiki mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<link rel=\"stylesheet\" href=\"tiki.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"tiki.js\"></script>\n<style type=\"text/css\">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Tiki wiki</a>\n  </ul>\n</div>\n\n<article>\n<h2>Tiki wiki mode</h2>\n\n\n<div><textarea id=\"code\" name=\"code\">\nHeadings\n!Header 1\n!!Header 2\n!!!Header 3\n!!!!Header 4\n!!!!!Header 5\n!!!!!!Header 6\n\nStyling\n-=titlebar=-\n^^ Box on multi\nlines\nof content^^\n__bold__\n''italic''\n===underline===\n::center::\n--Line Through--\n\nOperators\n~np~No parse~/np~\n\nLink\n[link|desc|nocache]\n\nWiki\n((Wiki))\n((Wiki|desc))\n((Wiki|desc|timeout))\n\nTable\n||row1 col1|row1 col2|row1 col3\nrow2 col1|row2 col2|row2 col3\nrow3 col1|row3 col2|row3 col3||\n\nLists:\n*bla\n**bla-1\n++continue-bla-1\n***bla-2\n++continue-bla-1\n*bla\n+continue-bla\n#bla\n** tra-la-la\n+continue-bla\n#bla\n\nPlugin (standard):\n{PLUGIN(attr=\"my attr\")}\nPlugin Body\n{PLUGIN}\n\nPlugin (inline):\n{plugin attr=\"my attr\"}\n</textarea></div>\n\n<script type=\"text/javascript\">\n\tvar editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        mode: 'tiki',      \n        lineNumbers: true\n    });\n</script>\n\n</article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/tiki/tiki.css",
    "content": ".cm-tw-syntaxerror {\n\tcolor: #FFF;\n\tbackground-color: #900;\n}\n\n.cm-tw-deleted {\n\ttext-decoration: line-through;\n}\n\n.cm-tw-header5 {\n\tfont-weight: bold;\n}\n.cm-tw-listitem:first-child { /*Added first child to fix duplicate padding when highlighting*/\n\tpadding-left: 10px;\n}\n\n.cm-tw-box {\n\tborder-top-width: 0px ! important;\n\tborder-style: solid;\n\tborder-width: 1px;\n\tborder-color: inherit;\n}\n\n.cm-tw-underline {\n\ttext-decoration: underline;\n}"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/tiki/tiki.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode('tiki', function(config) {\n  function inBlock(style, terminator, returnTokenizer) {\n    return function(stream, state) {\n      while (!stream.eol()) {\n        if (stream.match(terminator)) {\n          state.tokenize = inText;\n          break;\n        }\n        stream.next();\n      }\n\n      if (returnTokenizer) state.tokenize = returnTokenizer;\n\n      return style;\n    };\n  }\n\n  function inLine(style) {\n    return function(stream, state) {\n      while(!stream.eol()) {\n        stream.next();\n      }\n      state.tokenize = inText;\n      return style;\n    };\n  }\n\n  function inText(stream, state) {\n    function chain(parser) {\n      state.tokenize = parser;\n      return parser(stream, state);\n    }\n\n    var sol = stream.sol();\n    var ch = stream.next();\n\n    //non start of line\n    switch (ch) { //switch is generally much faster than if, so it is used here\n    case \"{\": //plugin\n      stream.eat(\"/\");\n      stream.eatSpace();\n      var tagName = \"\";\n      var c;\n      while ((c = stream.eat(/[^\\s\\u00a0=\\\"\\'\\/?(}]/))) tagName += c;\n      state.tokenize = inPlugin;\n      return \"tag\";\n      break;\n    case \"_\": //bold\n      if (stream.eat(\"_\")) {\n        return chain(inBlock(\"strong\", \"__\", inText));\n      }\n      break;\n    case \"'\": //italics\n      if (stream.eat(\"'\")) {\n        // Italic text\n        return chain(inBlock(\"em\", \"''\", inText));\n      }\n      break;\n    case \"(\":// Wiki Link\n      if (stream.eat(\"(\")) {\n        return chain(inBlock(\"variable-2\", \"))\", inText));\n      }\n      break;\n    case \"[\":// Weblink\n      return chain(inBlock(\"variable-3\", \"]\", inText));\n      break;\n    case \"|\": //table\n      if (stream.eat(\"|\")) {\n        return chain(inBlock(\"comment\", \"||\"));\n      }\n      break;\n    case \"-\":\n      if (stream.eat(\"=\")) {//titleBar\n        return chain(inBlock(\"header string\", \"=-\", inText));\n      } else if (stream.eat(\"-\")) {//deleted\n        return chain(inBlock(\"error tw-deleted\", \"--\", inText));\n      }\n      break;\n    case \"=\": //underline\n      if (stream.match(\"==\")) {\n        return chain(inBlock(\"tw-underline\", \"===\", inText));\n      }\n      break;\n    case \":\":\n      if (stream.eat(\":\")) {\n        return chain(inBlock(\"comment\", \"::\"));\n      }\n      break;\n    case \"^\": //box\n      return chain(inBlock(\"tw-box\", \"^\"));\n      break;\n    case \"~\": //np\n      if (stream.match(\"np~\")) {\n        return chain(inBlock(\"meta\", \"~/np~\"));\n      }\n      break;\n    }\n\n    //start of line types\n    if (sol) {\n      switch (ch) {\n      case \"!\": //header at start of line\n        if (stream.match('!!!!!')) {\n          return chain(inLine(\"header string\"));\n        } else if (stream.match('!!!!')) {\n          return chain(inLine(\"header string\"));\n        } else if (stream.match('!!!')) {\n          return chain(inLine(\"header string\"));\n        } else if (stream.match('!!')) {\n          return chain(inLine(\"header string\"));\n        } else {\n          return chain(inLine(\"header string\"));\n        }\n        break;\n      case \"*\": //unordered list line item, or <li /> at start of line\n      case \"#\": //ordered list line item, or <li /> at start of line\n      case \"+\": //ordered list line item, or <li /> at start of line\n        return chain(inLine(\"tw-listitem bracket\"));\n        break;\n      }\n    }\n\n    //stream.eatWhile(/[&{]/); was eating up plugins, turned off to act less like html and more like tiki\n    return null;\n  }\n\n  var indentUnit = config.indentUnit;\n\n  // Return variables for tokenizers\n  var pluginName, type;\n  function inPlugin(stream, state) {\n    var ch = stream.next();\n    var peek = stream.peek();\n\n    if (ch == \"}\") {\n      state.tokenize = inText;\n      //type = ch == \")\" ? \"endPlugin\" : \"selfclosePlugin\"; inPlugin\n      return \"tag\";\n    } else if (ch == \"(\" || ch == \")\") {\n      return \"bracket\";\n    } else if (ch == \"=\") {\n      type = \"equals\";\n\n      if (peek == \">\") {\n        ch = stream.next();\n        peek = stream.peek();\n      }\n\n      //here we detect values directly after equal character with no quotes\n      if (!/[\\'\\\"]/.test(peek)) {\n        state.tokenize = inAttributeNoQuote();\n      }\n      //end detect values\n\n      return \"operator\";\n    } else if (/[\\'\\\"]/.test(ch)) {\n      state.tokenize = inAttribute(ch);\n      return state.tokenize(stream, state);\n    } else {\n      stream.eatWhile(/[^\\s\\u00a0=\\\"\\'\\/?]/);\n      return \"keyword\";\n    }\n  }\n\n  function inAttribute(quote) {\n    return function(stream, state) {\n      while (!stream.eol()) {\n        if (stream.next() == quote) {\n          state.tokenize = inPlugin;\n          break;\n        }\n      }\n      return \"string\";\n    };\n  }\n\n  function inAttributeNoQuote() {\n    return function(stream, state) {\n      while (!stream.eol()) {\n        var ch = stream.next();\n        var peek = stream.peek();\n        if (ch == \" \" || ch == \",\" || /[ )}]/.test(peek)) {\n      state.tokenize = inPlugin;\n      break;\n    }\n  }\n  return \"string\";\n};\n                     }\n\nvar curState, setStyle;\nfunction pass() {\n  for (var i = arguments.length - 1; i >= 0; i--) curState.cc.push(arguments[i]);\n}\n\nfunction cont() {\n  pass.apply(null, arguments);\n  return true;\n}\n\nfunction pushContext(pluginName, startOfLine) {\n  var noIndent = curState.context && curState.context.noIndent;\n  curState.context = {\n    prev: curState.context,\n    pluginName: pluginName,\n    indent: curState.indented,\n    startOfLine: startOfLine,\n    noIndent: noIndent\n  };\n}\n\nfunction popContext() {\n  if (curState.context) curState.context = curState.context.prev;\n}\n\nfunction element(type) {\n  if (type == \"openPlugin\") {curState.pluginName = pluginName; return cont(attributes, endplugin(curState.startOfLine));}\n  else if (type == \"closePlugin\") {\n    var err = false;\n    if (curState.context) {\n      err = curState.context.pluginName != pluginName;\n      popContext();\n    } else {\n      err = true;\n    }\n    if (err) setStyle = \"error\";\n    return cont(endcloseplugin(err));\n  }\n  else if (type == \"string\") {\n    if (!curState.context || curState.context.name != \"!cdata\") pushContext(\"!cdata\");\n    if (curState.tokenize == inText) popContext();\n    return cont();\n  }\n  else return cont();\n}\n\nfunction endplugin(startOfLine) {\n  return function(type) {\n    if (\n      type == \"selfclosePlugin\" ||\n        type == \"endPlugin\"\n    )\n      return cont();\n    if (type == \"endPlugin\") {pushContext(curState.pluginName, startOfLine); return cont();}\n    return cont();\n  };\n}\n\nfunction endcloseplugin(err) {\n  return function(type) {\n    if (err) setStyle = \"error\";\n    if (type == \"endPlugin\") return cont();\n    return pass();\n  };\n}\n\nfunction attributes(type) {\n  if (type == \"keyword\") {setStyle = \"attribute\"; return cont(attributes);}\n  if (type == \"equals\") return cont(attvalue, attributes);\n  return pass();\n}\nfunction attvalue(type) {\n  if (type == \"keyword\") {setStyle = \"string\"; return cont();}\n  if (type == \"string\") return cont(attvaluemaybe);\n  return pass();\n}\nfunction attvaluemaybe(type) {\n  if (type == \"string\") return cont(attvaluemaybe);\n  else return pass();\n}\nreturn {\n  startState: function() {\n    return {tokenize: inText, cc: [], indented: 0, startOfLine: true, pluginName: null, context: null};\n  },\n  token: function(stream, state) {\n    if (stream.sol()) {\n      state.startOfLine = true;\n      state.indented = stream.indentation();\n    }\n    if (stream.eatSpace()) return null;\n\n    setStyle = type = pluginName = null;\n    var style = state.tokenize(stream, state);\n    if ((style || type) && style != \"comment\") {\n      curState = state;\n      while (true) {\n        var comb = state.cc.pop() || element;\n        if (comb(type || style)) break;\n      }\n    }\n    state.startOfLine = false;\n    return setStyle || style;\n  },\n  indent: function(state, textAfter) {\n    var context = state.context;\n    if (context && context.noIndent) return 0;\n    if (context && /^{\\//.test(textAfter))\n        context = context.prev;\n        while (context && !context.startOfLine)\n          context = context.prev;\n        if (context) return context.indent + indentUnit;\n        else return 0;\n       },\n    electricChars: \"/\"\n  };\n});\n\nCodeMirror.defineMIME(\"text/tiki\", \"tiki\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/toml/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: TOML Mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"toml.js\"></script>\n<style type=\"text/css\">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">TOML Mode</a>\n  </ul>\n</div>\n\n<article>\n<h2>TOML Mode</h2>\n<form><textarea id=\"code\" name=\"code\">\n# This is a TOML document. Boom.\n\ntitle = \"TOML Example\"\n\n[owner]\nname = \"Tom Preston-Werner\"\norganization = \"GitHub\"\nbio = \"GitHub Cofounder &amp; CEO\\nLikes tater tots and beer.\"\ndob = 1979-05-27T07:32:00Z # First class dates? Why not?\n\n[database]\nserver = \"192.168.1.1\"\nports = [ 8001, 8001, 8002 ]\nconnection_max = 5000\nenabled = true\n\n[servers]\n\n  # You can indent as you please. Tabs or spaces. TOML don't care.\n  [servers.alpha]\n  ip = \"10.0.0.1\"\n  dc = \"eqdc10\"\n  \n  [servers.beta]\n  ip = \"10.0.0.2\"\n  dc = \"eqdc10\"\n  \n[clients]\ndata = [ [\"gamma\", \"delta\"], [1, 2] ]\n\n# Line breaks are OK when inside arrays\nhosts = [\n  \"alpha\",\n  \"omega\"\n]\n</textarea></form>\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        mode: {name: \"toml\"},\n        lineNumbers: true\n      });\n    </script>\n    <h3>The TOML Mode</h3>\n      <p> Created by Forbes Lindesay.</p>\n    <p><strong>MIME type defined:</strong> <code>text/x-toml</code>.</p>\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/toml/toml.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"toml\", function () {\n  return {\n    startState: function () {\n      return {\n        inString: false,\n        stringType: \"\",\n        lhs: true,\n        inArray: 0\n      };\n    },\n    token: function (stream, state) {\n      //check for state changes\n      if (!state.inString && ((stream.peek() == '\"') || (stream.peek() == \"'\"))) {\n        state.stringType = stream.peek();\n        stream.next(); // Skip quote\n        state.inString = true; // Update state\n      }\n      if (stream.sol() && state.inArray === 0) {\n        state.lhs = true;\n      }\n      //return state\n      if (state.inString) {\n        while (state.inString && !stream.eol()) {\n          if (stream.peek() === state.stringType) {\n            stream.next(); // Skip quote\n            state.inString = false; // Clear flag\n          } else if (stream.peek() === '\\\\') {\n            stream.next();\n            stream.next();\n          } else {\n            stream.match(/^.[^\\\\\\\"\\']*/);\n          }\n        }\n        return state.lhs ? \"property string\" : \"string\"; // Token style\n      } else if (state.inArray && stream.peek() === ']') {\n        stream.next();\n        state.inArray--;\n        return 'bracket';\n      } else if (state.lhs && stream.peek() === '[' && stream.skipTo(']')) {\n        stream.next();//skip closing ]\n        // array of objects has an extra open & close []\n        if (stream.peek() === ']') stream.next();\n        return \"atom\";\n      } else if (stream.peek() === \"#\") {\n        stream.skipToEnd();\n        return \"comment\";\n      } else if (stream.eatSpace()) {\n        return null;\n      } else if (state.lhs && stream.eatWhile(function (c) { return c != '=' && c != ' '; })) {\n        return \"property\";\n      } else if (state.lhs && stream.peek() === \"=\") {\n        stream.next();\n        state.lhs = false;\n        return null;\n      } else if (!state.lhs && stream.match(/^\\d\\d\\d\\d[\\d\\-\\:\\.T]*Z/)) {\n        return 'atom'; //date\n      } else if (!state.lhs && (stream.match('true') || stream.match('false'))) {\n        return 'atom';\n      } else if (!state.lhs && stream.peek() === '[') {\n        state.inArray++;\n        stream.next();\n        return 'bracket';\n      } else if (!state.lhs && stream.match(/^\\-?\\d+(?:\\.\\d+)?/)) {\n        return 'number';\n      } else if (!stream.eatSpace()) {\n        stream.next();\n      }\n      return null;\n    }\n  };\n});\n\nCodeMirror.defineMIME('text/x-toml', 'toml');\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/tornado/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Tornado template mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"../../addon/mode/overlay.js\"></script>\n<script src=\"../xml/xml.js\"></script>\n<script src=\"../htmlmixed/htmlmixed.js\"></script>\n<script src=\"tornado.js\"></script>\n<style type=\"text/css\">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/marijnh/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Tornado</a>\n  </ul>\n</div>\n\n<article>\n<h2>Tornado template mode</h2>\n<form><textarea id=\"code\" name=\"code\">\n<!doctype html>\n<html>\n    <head>\n        <title>My Tornado web application</title>\n    </head>\n    <body>\n        <h1>\n            {{ title }}\n        </h1>\n        <ul class=\"my-list\">\n            {% for item in items %}\n                <li>{% item.name %}</li>\n            {% empty %}\n                <li>You have no items in your list.</li>\n            {% end %}\n        </ul>\n    </body>\n</html>\n</textarea></form>\n\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        lineNumbers: true,\n        mode: \"tornado\",\n        indentUnit: 4,\n        indentWithTabs: true\n      });\n    </script>\n\n    <p>Mode for HTML with embedded Tornado template markup.</p>\n\n    <p><strong>MIME types defined:</strong> <code>text/x-tornado</code></p>\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/tornado/tornado.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"), require(\"../htmlmixed/htmlmixed\"),\n        require(\"../../addon/mode/overlay\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\", \"../htmlmixed/htmlmixed\",\n            \"../../addon/mode/overlay\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  \"use strict\";\n\n  CodeMirror.defineMode(\"tornado:inner\", function() {\n    var keywords = [\"and\",\"as\",\"assert\",\"autoescape\",\"block\",\"break\",\"class\",\"comment\",\"context\",\n                    \"continue\",\"datetime\",\"def\",\"del\",\"elif\",\"else\",\"end\",\"escape\",\"except\",\n                    \"exec\",\"extends\",\"false\",\"finally\",\"for\",\"from\",\"global\",\"if\",\"import\",\"in\",\n                    \"include\",\"is\",\"json_encode\",\"lambda\",\"length\",\"linkify\",\"load\",\"module\",\n                    \"none\",\"not\",\"or\",\"pass\",\"print\",\"put\",\"raise\",\"raw\",\"return\",\"self\",\"set\",\n                    \"squeeze\",\"super\",\"true\",\"try\",\"url_escape\",\"while\",\"with\",\"without\",\"xhtml_escape\",\"yield\"];\n    keywords = new RegExp(\"^((\" + keywords.join(\")|(\") + \"))\\\\b\");\n\n    function tokenBase (stream, state) {\n      stream.eatWhile(/[^\\{]/);\n      var ch = stream.next();\n      if (ch == \"{\") {\n        if (ch = stream.eat(/\\{|%|#/)) {\n          state.tokenize = inTag(ch);\n          return \"tag\";\n        }\n      }\n    }\n    function inTag (close) {\n      if (close == \"{\") {\n        close = \"}\";\n      }\n      return function (stream, state) {\n        var ch = stream.next();\n        if ((ch == close) && stream.eat(\"}\")) {\n          state.tokenize = tokenBase;\n          return \"tag\";\n        }\n        if (stream.match(keywords)) {\n          return \"keyword\";\n        }\n        return close == \"#\" ? \"comment\" : \"string\";\n      };\n    }\n    return {\n      startState: function () {\n        return {tokenize: tokenBase};\n      },\n      token: function (stream, state) {\n        return state.tokenize(stream, state);\n      }\n    };\n  });\n\n  CodeMirror.defineMode(\"tornado\", function(config) {\n    var htmlBase = CodeMirror.getMode(config, \"text/html\");\n    var tornadoInner = CodeMirror.getMode(config, \"tornado:inner\");\n    return CodeMirror.overlayMode(htmlBase, tornadoInner);\n  });\n\n  CodeMirror.defineMIME(\"text/x-tornado\", \"tornado\");\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/turtle/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Turtle mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"turtle.js\"></script>\n<style>.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Turtle</a>\n  </ul>\n</div>\n\n<article>\n<h2>Turtle mode</h2>\n<form><textarea id=\"code\" name=\"code\">\n@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n@prefix geo: <http://www.w3.org/2003/01/geo/wgs84_pos#> .\n@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .\n\n<http://purl.org/net/bsletten> \n    a foaf:Person;\n    foaf:interest <http://www.w3.org/2000/01/sw/>;\n    foaf:based_near [\n        geo:lat \"34.0736111\" ;\n        geo:lon \"-118.3994444\"\n   ]\n\n</textarea></form>\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        mode: \"text/turtle\",\n        matchBrackets: true\n      });\n    </script>\n\n    <p><strong>MIME types defined:</strong> <code>text/turtle</code>.</p>\n\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/turtle/turtle.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"turtle\", function(config) {\n  var indentUnit = config.indentUnit;\n  var curPunc;\n\n  function wordRegexp(words) {\n    return new RegExp(\"^(?:\" + words.join(\"|\") + \")$\", \"i\");\n  }\n  var ops = wordRegexp([]);\n  var keywords = wordRegexp([\"@prefix\", \"@base\", \"a\"]);\n  var operatorChars = /[*+\\-<>=&|]/;\n\n  function tokenBase(stream, state) {\n    var ch = stream.next();\n    curPunc = null;\n    if (ch == \"<\" && !stream.match(/^[\\s\\u00a0=]/, false)) {\n      stream.match(/^[^\\s\\u00a0>]*>?/);\n      return \"atom\";\n    }\n    else if (ch == \"\\\"\" || ch == \"'\") {\n      state.tokenize = tokenLiteral(ch);\n      return state.tokenize(stream, state);\n    }\n    else if (/[{}\\(\\),\\.;\\[\\]]/.test(ch)) {\n      curPunc = ch;\n      return null;\n    }\n    else if (ch == \"#\") {\n      stream.skipToEnd();\n      return \"comment\";\n    }\n    else if (operatorChars.test(ch)) {\n      stream.eatWhile(operatorChars);\n      return null;\n    }\n    else if (ch == \":\") {\n          return \"operator\";\n        } else {\n      stream.eatWhile(/[_\\w\\d]/);\n      if(stream.peek() == \":\") {\n        return \"variable-3\";\n      } else {\n             var word = stream.current();\n\n             if(keywords.test(word)) {\n                        return \"meta\";\n             }\n\n             if(ch >= \"A\" && ch <= \"Z\") {\n                    return \"comment\";\n                 } else {\n                        return \"keyword\";\n                 }\n      }\n      var word = stream.current();\n      if (ops.test(word))\n        return null;\n      else if (keywords.test(word))\n        return \"meta\";\n      else\n        return \"variable\";\n    }\n  }\n\n  function tokenLiteral(quote) {\n    return function(stream, state) {\n      var escaped = false, ch;\n      while ((ch = stream.next()) != null) {\n        if (ch == quote && !escaped) {\n          state.tokenize = tokenBase;\n          break;\n        }\n        escaped = !escaped && ch == \"\\\\\";\n      }\n      return \"string\";\n    };\n  }\n\n  function pushContext(state, type, col) {\n    state.context = {prev: state.context, indent: state.indent, col: col, type: type};\n  }\n  function popContext(state) {\n    state.indent = state.context.indent;\n    state.context = state.context.prev;\n  }\n\n  return {\n    startState: function() {\n      return {tokenize: tokenBase,\n              context: null,\n              indent: 0,\n              col: 0};\n    },\n\n    token: function(stream, state) {\n      if (stream.sol()) {\n        if (state.context && state.context.align == null) state.context.align = false;\n        state.indent = stream.indentation();\n      }\n      if (stream.eatSpace()) return null;\n      var style = state.tokenize(stream, state);\n\n      if (style != \"comment\" && state.context && state.context.align == null && state.context.type != \"pattern\") {\n        state.context.align = true;\n      }\n\n      if (curPunc == \"(\") pushContext(state, \")\", stream.column());\n      else if (curPunc == \"[\") pushContext(state, \"]\", stream.column());\n      else if (curPunc == \"{\") pushContext(state, \"}\", stream.column());\n      else if (/[\\]\\}\\)]/.test(curPunc)) {\n        while (state.context && state.context.type == \"pattern\") popContext(state);\n        if (state.context && curPunc == state.context.type) popContext(state);\n      }\n      else if (curPunc == \".\" && state.context && state.context.type == \"pattern\") popContext(state);\n      else if (/atom|string|variable/.test(style) && state.context) {\n        if (/[\\}\\]]/.test(state.context.type))\n          pushContext(state, \"pattern\", stream.column());\n        else if (state.context.type == \"pattern\" && !state.context.align) {\n          state.context.align = true;\n          state.context.col = stream.column();\n        }\n      }\n\n      return style;\n    },\n\n    indent: function(state, textAfter) {\n      var firstChar = textAfter && textAfter.charAt(0);\n      var context = state.context;\n      if (/[\\]\\}]/.test(firstChar))\n        while (context && context.type == \"pattern\") context = context.prev;\n\n      var closing = context && firstChar == context.type;\n      if (!context)\n        return 0;\n      else if (context.type == \"pattern\")\n        return context.col;\n      else if (context.align)\n        return context.col + (closing ? 0 : 1);\n      else\n        return context.indent + (closing ? 0 : indentUnit);\n    },\n\n    lineComment: \"#\"\n  };\n});\n\nCodeMirror.defineMIME(\"text/turtle\", \"turtle\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/vb/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: VB.NET mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<link href=\"http://fonts.googleapis.com/css?family=Inconsolata\" rel=\"stylesheet\" type=\"text/css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"vb.js\"></script>\n<script type=\"text/javascript\" src=\"../../addon/runmode/runmode.js\"></script>\n<style>\n      .CodeMirror {border: 1px solid #aaa; height:210px; height: auto;}\n      .CodeMirror-scroll { overflow-x: auto; overflow-y: hidden;}\n      .CodeMirror pre { font-family: Inconsolata; font-size: 14px}\n    </style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">VB.NET</a>\n  </ul>\n</div>\n\n<article>\n<h2>VB.NET mode</h2>\n\n<script type=\"text/javascript\">\nfunction test(golden, text) {\n  var ok = true;\n  var i = 0;\n  function callback(token, style, lineNo, pos){\n\t\t//console.log(String(token) + \" \" + String(style) + \" \" + String(lineNo) + \" \" + String(pos));\n    var result = [String(token), String(style)];\n    if (golden[i][0] != result[0] || golden[i][1] != result[1]){\n      return \"Error, expected: \" + String(golden[i]) + \", got: \" + String(result);\n      ok = false;\n    }\n    i++;\n  }\n  CodeMirror.runMode(text, \"text/x-vb\",callback); \n\n  if (ok) return \"Tests OK\";\n}\nfunction testTypes() {\n  var golden = [['Integer','keyword'],[' ','null'],['Float','keyword']]\n  var text =  \"Integer Float\";\n  return test(golden,text);\n}\nfunction testIf(){\n  var golden = [['If','keyword'],[' ','null'],['True','keyword'],[' ','null'],['End','keyword'],[' ','null'],['If','keyword']];\n  var text = 'If True End If';\n  return test(golden, text);\n}\nfunction testDecl(){\n   var golden = [['Dim','keyword'],[' ','null'],['x','variable'],[' ','null'],['as','keyword'],[' ','null'],['Integer','keyword']];\n   var text = 'Dim x as Integer';\n   return test(golden, text);\n}\nfunction testAll(){\n  var result = \"\";\n\n  result += testTypes() + \"\\n\";\n  result += testIf() + \"\\n\";\n  result += testDecl() + \"\\n\";\n  return result;\n\n}\nfunction initText(editor) {\n  var content = 'Class rocket\\nPrivate quality as Double\\nPublic Sub launch() as String\\nif quality > 0.8\\nlaunch = \"Successful\"\\nElse\\nlaunch = \"Failed\"\\nEnd If\\nEnd sub\\nEnd class\\n';\n  editor.setValue(content);\n  for (var i =0; i< editor.lineCount(); i++) editor.indentLine(i);\n}\nfunction init() {\n    editor = CodeMirror.fromTextArea(document.getElementById(\"solution\"), {\n        lineNumbers: true,\n        mode: \"text/x-vb\",\n        readOnly: false\n    });\n    runTest();\n}\nfunction runTest() {\n\tdocument.getElementById('testresult').innerHTML = testAll();\n  initText(editor);\n\t\n}\ndocument.body.onload = init;\n</script>\n\n  <div id=\"edit\">\n  <textarea style=\"width:95%;height:200px;padding:5px;\" name=\"solution\" id=\"solution\" ></textarea>\n  </div>\n  <pre id=\"testresult\"></pre>\n  <p>MIME type defined: <code>text/x-vb</code>.</p>\n\n</article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/vb/vb.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"vb\", function(conf, parserConf) {\n    var ERRORCLASS = 'error';\n\n    function wordRegexp(words) {\n        return new RegExp(\"^((\" + words.join(\")|(\") + \"))\\\\b\", \"i\");\n    }\n\n    var singleOperators = new RegExp(\"^[\\\\+\\\\-\\\\*/%&\\\\\\\\|\\\\^~<>!]\");\n    var singleDelimiters = new RegExp('^[\\\\(\\\\)\\\\[\\\\]\\\\{\\\\}@,:`=;\\\\.]');\n    var doubleOperators = new RegExp(\"^((==)|(<>)|(<=)|(>=)|(<>)|(<<)|(>>)|(//)|(\\\\*\\\\*))\");\n    var doubleDelimiters = new RegExp(\"^((\\\\+=)|(\\\\-=)|(\\\\*=)|(%=)|(/=)|(&=)|(\\\\|=)|(\\\\^=))\");\n    var tripleDelimiters = new RegExp(\"^((//=)|(>>=)|(<<=)|(\\\\*\\\\*=))\");\n    var identifiers = new RegExp(\"^[_A-Za-z][_A-Za-z0-9]*\");\n\n    var openingKeywords = ['class','module', 'sub','enum','select','while','if','function',  'get','set','property', 'try'];\n    var middleKeywords = ['else','elseif','case', 'catch'];\n    var endKeywords = ['next','loop'];\n\n    var wordOperators = wordRegexp(['and', 'or', 'not', 'xor', 'in']);\n    var commonkeywords = ['as', 'dim', 'break',  'continue','optional', 'then',  'until',\n                          'goto', 'byval','byref','new','handles','property', 'return',\n                          'const','private', 'protected', 'friend', 'public', 'shared', 'static', 'true','false'];\n    var commontypes = ['integer','string','double','decimal','boolean','short','char', 'float','single'];\n\n    var keywords = wordRegexp(commonkeywords);\n    var types = wordRegexp(commontypes);\n    var stringPrefixes = '\"';\n\n    var opening = wordRegexp(openingKeywords);\n    var middle = wordRegexp(middleKeywords);\n    var closing = wordRegexp(endKeywords);\n    var doubleClosing = wordRegexp(['end']);\n    var doOpening = wordRegexp(['do']);\n\n    var indentInfo = null;\n\n\n\n\n    function indent(_stream, state) {\n      state.currentIndent++;\n    }\n\n    function dedent(_stream, state) {\n      state.currentIndent--;\n    }\n    // tokenizers\n    function tokenBase(stream, state) {\n        if (stream.eatSpace()) {\n            return null;\n        }\n\n        var ch = stream.peek();\n\n        // Handle Comments\n        if (ch === \"'\") {\n            stream.skipToEnd();\n            return 'comment';\n        }\n\n\n        // Handle Number Literals\n        if (stream.match(/^((&H)|(&O))?[0-9\\.a-f]/i, false)) {\n            var floatLiteral = false;\n            // Floats\n            if (stream.match(/^\\d*\\.\\d+F?/i)) { floatLiteral = true; }\n            else if (stream.match(/^\\d+\\.\\d*F?/)) { floatLiteral = true; }\n            else if (stream.match(/^\\.\\d+F?/)) { floatLiteral = true; }\n\n            if (floatLiteral) {\n                // Float literals may be \"imaginary\"\n                stream.eat(/J/i);\n                return 'number';\n            }\n            // Integers\n            var intLiteral = false;\n            // Hex\n            if (stream.match(/^&H[0-9a-f]+/i)) { intLiteral = true; }\n            // Octal\n            else if (stream.match(/^&O[0-7]+/i)) { intLiteral = true; }\n            // Decimal\n            else if (stream.match(/^[1-9]\\d*F?/)) {\n                // Decimal literals may be \"imaginary\"\n                stream.eat(/J/i);\n                // TODO - Can you have imaginary longs?\n                intLiteral = true;\n            }\n            // Zero by itself with no other piece of number.\n            else if (stream.match(/^0(?![\\dx])/i)) { intLiteral = true; }\n            if (intLiteral) {\n                // Integer literals may be \"long\"\n                stream.eat(/L/i);\n                return 'number';\n            }\n        }\n\n        // Handle Strings\n        if (stream.match(stringPrefixes)) {\n            state.tokenize = tokenStringFactory(stream.current());\n            return state.tokenize(stream, state);\n        }\n\n        // Handle operators and Delimiters\n        if (stream.match(tripleDelimiters) || stream.match(doubleDelimiters)) {\n            return null;\n        }\n        if (stream.match(doubleOperators)\n            || stream.match(singleOperators)\n            || stream.match(wordOperators)) {\n            return 'operator';\n        }\n        if (stream.match(singleDelimiters)) {\n            return null;\n        }\n        if (stream.match(doOpening)) {\n            indent(stream,state);\n            state.doInCurrentLine = true;\n            return 'keyword';\n        }\n        if (stream.match(opening)) {\n            if (! state.doInCurrentLine)\n              indent(stream,state);\n            else\n              state.doInCurrentLine = false;\n            return 'keyword';\n        }\n        if (stream.match(middle)) {\n            return 'keyword';\n        }\n\n        if (stream.match(doubleClosing)) {\n            dedent(stream,state);\n            dedent(stream,state);\n            return 'keyword';\n        }\n        if (stream.match(closing)) {\n            dedent(stream,state);\n            return 'keyword';\n        }\n\n        if (stream.match(types)) {\n            return 'keyword';\n        }\n\n        if (stream.match(keywords)) {\n            return 'keyword';\n        }\n\n        if (stream.match(identifiers)) {\n            return 'variable';\n        }\n\n        // Handle non-detected items\n        stream.next();\n        return ERRORCLASS;\n    }\n\n    function tokenStringFactory(delimiter) {\n        var singleline = delimiter.length == 1;\n        var OUTCLASS = 'string';\n\n        return function(stream, state) {\n            while (!stream.eol()) {\n                stream.eatWhile(/[^'\"]/);\n                if (stream.match(delimiter)) {\n                    state.tokenize = tokenBase;\n                    return OUTCLASS;\n                } else {\n                    stream.eat(/['\"]/);\n                }\n            }\n            if (singleline) {\n                if (parserConf.singleLineStringErrors) {\n                    return ERRORCLASS;\n                } else {\n                    state.tokenize = tokenBase;\n                }\n            }\n            return OUTCLASS;\n        };\n    }\n\n\n    function tokenLexer(stream, state) {\n        var style = state.tokenize(stream, state);\n        var current = stream.current();\n\n        // Handle '.' connected identifiers\n        if (current === '.') {\n            style = state.tokenize(stream, state);\n            current = stream.current();\n            if (style === 'variable') {\n                return 'variable';\n            } else {\n                return ERRORCLASS;\n            }\n        }\n\n\n        var delimiter_index = '[({'.indexOf(current);\n        if (delimiter_index !== -1) {\n            indent(stream, state );\n        }\n        if (indentInfo === 'dedent') {\n            if (dedent(stream, state)) {\n                return ERRORCLASS;\n            }\n        }\n        delimiter_index = '])}'.indexOf(current);\n        if (delimiter_index !== -1) {\n            if (dedent(stream, state)) {\n                return ERRORCLASS;\n            }\n        }\n\n        return style;\n    }\n\n    var external = {\n        electricChars:\"dDpPtTfFeE \",\n        startState: function() {\n            return {\n              tokenize: tokenBase,\n              lastToken: null,\n              currentIndent: 0,\n              nextLineIndent: 0,\n              doInCurrentLine: false\n\n\n          };\n        },\n\n        token: function(stream, state) {\n            if (stream.sol()) {\n              state.currentIndent += state.nextLineIndent;\n              state.nextLineIndent = 0;\n              state.doInCurrentLine = 0;\n            }\n            var style = tokenLexer(stream, state);\n\n            state.lastToken = {style:style, content: stream.current()};\n\n\n\n            return style;\n        },\n\n        indent: function(state, textAfter) {\n            var trueText = textAfter.replace(/^\\s+|\\s+$/g, '') ;\n            if (trueText.match(closing) || trueText.match(doubleClosing) || trueText.match(middle)) return conf.indentUnit*(state.currentIndent-1);\n            if(state.currentIndent < 0) return 0;\n            return state.currentIndent * conf.indentUnit;\n        }\n\n    };\n    return external;\n});\n\nCodeMirror.defineMIME(\"text/x-vb\", \"vb\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/vbscript/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: VBScript mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"vbscript.js\"></script>\n<style type=\"text/css\">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">VBScript</a>\n  </ul>\n</div>\n\n<article>\n<h2>VBScript mode</h2>\n\n\n<div><textarea id=\"code\" name=\"code\">\n' Pete Guhl\n' 03-04-2012\n'\n' Basic VBScript support for codemirror2\n\nConst ForReading = 1, ForWriting = 2, ForAppending = 8\n\nCall Sub020_PostBroadcastToUrbanAirship(strUserName, strPassword, intTransmitID, strResponse)\n\nIf Not IsNull(strResponse) AND Len(strResponse) = 0 Then\n\tboolTransmitOkYN = False\nElse\n\t' WScript.Echo \"Oh Happy Day! Oh Happy DAY!\"\n\tboolTransmitOkYN = True\nEnd If\n</textarea></div>\n\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        lineNumbers: true,\n        indentUnit: 4\n      });\n    </script>\n\n    <p><strong>MIME types defined:</strong> <code>text/vbscript</code>.</p>\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/vbscript/vbscript.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n/*\nFor extra ASP classic objects, initialize CodeMirror instance with this option:\n    isASP: true\n\nE.G.:\n    var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        lineNumbers: true,\n        isASP: true\n      });\n*/\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"vbscript\", function(conf, parserConf) {\n    var ERRORCLASS = 'error';\n\n    function wordRegexp(words) {\n        return new RegExp(\"^((\" + words.join(\")|(\") + \"))\\\\b\", \"i\");\n    }\n\n    var singleOperators = new RegExp(\"^[\\\\+\\\\-\\\\*/&\\\\\\\\\\\\^<>=]\");\n    var doubleOperators = new RegExp(\"^((<>)|(<=)|(>=))\");\n    var singleDelimiters = new RegExp('^[\\\\.,]');\n    var brakets = new RegExp('^[\\\\(\\\\)]');\n    var identifiers = new RegExp(\"^[A-Za-z][_A-Za-z0-9]*\");\n\n    var openingKeywords = ['class','sub','select','while','if','function', 'property', 'with', 'for'];\n    var middleKeywords = ['else','elseif','case'];\n    var endKeywords = ['next','loop','wend'];\n\n    var wordOperators = wordRegexp(['and', 'or', 'not', 'xor', 'is', 'mod', 'eqv', 'imp']);\n    var commonkeywords = ['dim', 'redim', 'then',  'until', 'randomize',\n                          'byval','byref','new','property', 'exit', 'in',\n                          'const','private', 'public',\n                          'get','set','let', 'stop', 'on error resume next', 'on error goto 0', 'option explicit', 'call', 'me'];\n\n    //This list was from: http://msdn.microsoft.com/en-us/library/f8tbc79x(v=vs.84).aspx\n    var atomWords = ['true', 'false', 'nothing', 'empty', 'null'];\n    //This list was from: http://msdn.microsoft.com/en-us/library/3ca8tfek(v=vs.84).aspx\n    var builtinFuncsWords = ['abs', 'array', 'asc', 'atn', 'cbool', 'cbyte', 'ccur', 'cdate', 'cdbl', 'chr', 'cint', 'clng', 'cos', 'csng', 'cstr', 'date', 'dateadd', 'datediff', 'datepart',\n                        'dateserial', 'datevalue', 'day', 'escape', 'eval', 'execute', 'exp', 'filter', 'formatcurrency', 'formatdatetime', 'formatnumber', 'formatpercent', 'getlocale', 'getobject',\n                        'getref', 'hex', 'hour', 'inputbox', 'instr', 'instrrev', 'int', 'fix', 'isarray', 'isdate', 'isempty', 'isnull', 'isnumeric', 'isobject', 'join', 'lbound', 'lcase', 'left',\n                        'len', 'loadpicture', 'log', 'ltrim', 'rtrim', 'trim', 'maths', 'mid', 'minute', 'month', 'monthname', 'msgbox', 'now', 'oct', 'replace', 'rgb', 'right', 'rnd', 'round',\n                        'scriptengine', 'scriptenginebuildversion', 'scriptenginemajorversion', 'scriptengineminorversion', 'second', 'setlocale', 'sgn', 'sin', 'space', 'split', 'sqr', 'strcomp',\n                        'string', 'strreverse', 'tan', 'time', 'timer', 'timeserial', 'timevalue', 'typename', 'ubound', 'ucase', 'unescape', 'vartype', 'weekday', 'weekdayname', 'year'];\n\n    //This list was from: http://msdn.microsoft.com/en-us/library/ydz4cfk3(v=vs.84).aspx\n    var builtinConsts = ['vbBlack', 'vbRed', 'vbGreen', 'vbYellow', 'vbBlue', 'vbMagenta', 'vbCyan', 'vbWhite', 'vbBinaryCompare', 'vbTextCompare',\n                         'vbSunday', 'vbMonday', 'vbTuesday', 'vbWednesday', 'vbThursday', 'vbFriday', 'vbSaturday', 'vbUseSystemDayOfWeek', 'vbFirstJan1', 'vbFirstFourDays', 'vbFirstFullWeek',\n                         'vbGeneralDate', 'vbLongDate', 'vbShortDate', 'vbLongTime', 'vbShortTime', 'vbObjectError',\n                         'vbOKOnly', 'vbOKCancel', 'vbAbortRetryIgnore', 'vbYesNoCancel', 'vbYesNo', 'vbRetryCancel', 'vbCritical', 'vbQuestion', 'vbExclamation', 'vbInformation', 'vbDefaultButton1', 'vbDefaultButton2',\n                         'vbDefaultButton3', 'vbDefaultButton4', 'vbApplicationModal', 'vbSystemModal', 'vbOK', 'vbCancel', 'vbAbort', 'vbRetry', 'vbIgnore', 'vbYes', 'vbNo',\n                         'vbCr', 'VbCrLf', 'vbFormFeed', 'vbLf', 'vbNewLine', 'vbNullChar', 'vbNullString', 'vbTab', 'vbVerticalTab', 'vbUseDefault', 'vbTrue', 'vbFalse',\n                         'vbEmpty', 'vbNull', 'vbInteger', 'vbLong', 'vbSingle', 'vbDouble', 'vbCurrency', 'vbDate', 'vbString', 'vbObject', 'vbError', 'vbBoolean', 'vbVariant', 'vbDataObject', 'vbDecimal', 'vbByte', 'vbArray'];\n    //This list was from: http://msdn.microsoft.com/en-us/library/hkc375ea(v=vs.84).aspx\n    var builtinObjsWords = ['WScript', 'err', 'debug', 'RegExp'];\n    var knownProperties = ['description', 'firstindex', 'global', 'helpcontext', 'helpfile', 'ignorecase', 'length', 'number', 'pattern', 'source', 'value', 'count'];\n    var knownMethods = ['clear', 'execute', 'raise', 'replace', 'test', 'write', 'writeline', 'close', 'open', 'state', 'eof', 'update', 'addnew', 'end', 'createobject', 'quit'];\n\n    var aspBuiltinObjsWords = ['server', 'response', 'request', 'session', 'application'];\n    var aspKnownProperties = ['buffer', 'cachecontrol', 'charset', 'contenttype', 'expires', 'expiresabsolute', 'isclientconnected', 'pics', 'status', //response\n                              'clientcertificate', 'cookies', 'form', 'querystring', 'servervariables', 'totalbytes', //request\n                              'contents', 'staticobjects', //application\n                              'codepage', 'lcid', 'sessionid', 'timeout', //session\n                              'scripttimeout']; //server\n    var aspKnownMethods = ['addheader', 'appendtolog', 'binarywrite', 'end', 'flush', 'redirect', //response\n                           'binaryread', //request\n                           'remove', 'removeall', 'lock', 'unlock', //application\n                           'abandon', //session\n                           'getlasterror', 'htmlencode', 'mappath', 'transfer', 'urlencode']; //server\n\n    var knownWords = knownMethods.concat(knownProperties);\n\n    builtinObjsWords = builtinObjsWords.concat(builtinConsts);\n\n    if (conf.isASP){\n        builtinObjsWords = builtinObjsWords.concat(aspBuiltinObjsWords);\n        knownWords = knownWords.concat(aspKnownMethods, aspKnownProperties);\n    };\n\n    var keywords = wordRegexp(commonkeywords);\n    var atoms = wordRegexp(atomWords);\n    var builtinFuncs = wordRegexp(builtinFuncsWords);\n    var builtinObjs = wordRegexp(builtinObjsWords);\n    var known = wordRegexp(knownWords);\n    var stringPrefixes = '\"';\n\n    var opening = wordRegexp(openingKeywords);\n    var middle = wordRegexp(middleKeywords);\n    var closing = wordRegexp(endKeywords);\n    var doubleClosing = wordRegexp(['end']);\n    var doOpening = wordRegexp(['do']);\n    var noIndentWords = wordRegexp(['on error resume next', 'exit']);\n    var comment = wordRegexp(['rem']);\n\n\n    function indent(_stream, state) {\n      state.currentIndent++;\n    }\n\n    function dedent(_stream, state) {\n      state.currentIndent--;\n    }\n    // tokenizers\n    function tokenBase(stream, state) {\n        if (stream.eatSpace()) {\n            return 'space';\n            //return null;\n        }\n\n        var ch = stream.peek();\n\n        // Handle Comments\n        if (ch === \"'\") {\n            stream.skipToEnd();\n            return 'comment';\n        }\n        if (stream.match(comment)){\n            stream.skipToEnd();\n            return 'comment';\n        }\n\n\n        // Handle Number Literals\n        if (stream.match(/^((&H)|(&O))?[0-9\\.]/i, false) && !stream.match(/^((&H)|(&O))?[0-9\\.]+[a-z_]/i, false)) {\n            var floatLiteral = false;\n            // Floats\n            if (stream.match(/^\\d*\\.\\d+/i)) { floatLiteral = true; }\n            else if (stream.match(/^\\d+\\.\\d*/)) { floatLiteral = true; }\n            else if (stream.match(/^\\.\\d+/)) { floatLiteral = true; }\n\n            if (floatLiteral) {\n                // Float literals may be \"imaginary\"\n                stream.eat(/J/i);\n                return 'number';\n            }\n            // Integers\n            var intLiteral = false;\n            // Hex\n            if (stream.match(/^&H[0-9a-f]+/i)) { intLiteral = true; }\n            // Octal\n            else if (stream.match(/^&O[0-7]+/i)) { intLiteral = true; }\n            // Decimal\n            else if (stream.match(/^[1-9]\\d*F?/)) {\n                // Decimal literals may be \"imaginary\"\n                stream.eat(/J/i);\n                // TODO - Can you have imaginary longs?\n                intLiteral = true;\n            }\n            // Zero by itself with no other piece of number.\n            else if (stream.match(/^0(?![\\dx])/i)) { intLiteral = true; }\n            if (intLiteral) {\n                // Integer literals may be \"long\"\n                stream.eat(/L/i);\n                return 'number';\n            }\n        }\n\n        // Handle Strings\n        if (stream.match(stringPrefixes)) {\n            state.tokenize = tokenStringFactory(stream.current());\n            return state.tokenize(stream, state);\n        }\n\n        // Handle operators and Delimiters\n        if (stream.match(doubleOperators)\n            || stream.match(singleOperators)\n            || stream.match(wordOperators)) {\n            return 'operator';\n        }\n        if (stream.match(singleDelimiters)) {\n            return null;\n        }\n\n        if (stream.match(brakets)) {\n            return \"bracket\";\n        }\n\n        if (stream.match(noIndentWords)) {\n            state.doInCurrentLine = true;\n\n            return 'keyword';\n        }\n\n        if (stream.match(doOpening)) {\n            indent(stream,state);\n            state.doInCurrentLine = true;\n\n            return 'keyword';\n        }\n        if (stream.match(opening)) {\n            if (! state.doInCurrentLine)\n              indent(stream,state);\n            else\n              state.doInCurrentLine = false;\n\n            return 'keyword';\n        }\n        if (stream.match(middle)) {\n            return 'keyword';\n        }\n\n\n        if (stream.match(doubleClosing)) {\n            dedent(stream,state);\n            dedent(stream,state);\n\n            return 'keyword';\n        }\n        if (stream.match(closing)) {\n            if (! state.doInCurrentLine)\n              dedent(stream,state);\n            else\n              state.doInCurrentLine = false;\n\n            return 'keyword';\n        }\n\n        if (stream.match(keywords)) {\n            return 'keyword';\n        }\n\n        if (stream.match(atoms)) {\n            return 'atom';\n        }\n\n        if (stream.match(known)) {\n            return 'variable-2';\n        }\n\n        if (stream.match(builtinFuncs)) {\n            return 'builtin';\n        }\n\n        if (stream.match(builtinObjs)){\n            return 'variable-2';\n        }\n\n        if (stream.match(identifiers)) {\n            return 'variable';\n        }\n\n        // Handle non-detected items\n        stream.next();\n        return ERRORCLASS;\n    }\n\n    function tokenStringFactory(delimiter) {\n        var singleline = delimiter.length == 1;\n        var OUTCLASS = 'string';\n\n        return function(stream, state) {\n            while (!stream.eol()) {\n                stream.eatWhile(/[^'\"]/);\n                if (stream.match(delimiter)) {\n                    state.tokenize = tokenBase;\n                    return OUTCLASS;\n                } else {\n                    stream.eat(/['\"]/);\n                }\n            }\n            if (singleline) {\n                if (parserConf.singleLineStringErrors) {\n                    return ERRORCLASS;\n                } else {\n                    state.tokenize = tokenBase;\n                }\n            }\n            return OUTCLASS;\n        };\n    }\n\n\n    function tokenLexer(stream, state) {\n        var style = state.tokenize(stream, state);\n        var current = stream.current();\n\n        // Handle '.' connected identifiers\n        if (current === '.') {\n            style = state.tokenize(stream, state);\n\n            current = stream.current();\n            if (style && (style.substr(0, 8) === 'variable' || style==='builtin' || style==='keyword')){//|| knownWords.indexOf(current.substring(1)) > -1) {\n                if (style === 'builtin' || style === 'keyword') style='variable';\n                if (knownWords.indexOf(current.substr(1)) > -1) style='variable-2';\n\n                return style;\n            } else {\n                return ERRORCLASS;\n            }\n        }\n\n        return style;\n    }\n\n    var external = {\n        electricChars:\"dDpPtTfFeE \",\n        startState: function() {\n            return {\n              tokenize: tokenBase,\n              lastToken: null,\n              currentIndent: 0,\n              nextLineIndent: 0,\n              doInCurrentLine: false,\n              ignoreKeyword: false\n\n\n          };\n        },\n\n        token: function(stream, state) {\n            if (stream.sol()) {\n              state.currentIndent += state.nextLineIndent;\n              state.nextLineIndent = 0;\n              state.doInCurrentLine = 0;\n            }\n            var style = tokenLexer(stream, state);\n\n            state.lastToken = {style:style, content: stream.current()};\n\n            if (style==='space') style=null;\n\n            return style;\n        },\n\n        indent: function(state, textAfter) {\n            var trueText = textAfter.replace(/^\\s+|\\s+$/g, '') ;\n            if (trueText.match(closing) || trueText.match(doubleClosing) || trueText.match(middle)) return conf.indentUnit*(state.currentIndent-1);\n            if(state.currentIndent < 0) return 0;\n            return state.currentIndent * conf.indentUnit;\n        }\n\n    };\n    return external;\n});\n\nCodeMirror.defineMIME(\"text/vbscript\", \"vbscript\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/velocity/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Velocity mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<link rel=\"stylesheet\" href=\"../../theme/night.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"velocity.js\"></script>\n<style>.CodeMirror {border: 1px solid black;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Velocity</a>\n  </ul>\n</div>\n\n<article>\n<h2>Velocity mode</h2>\n<form><textarea id=\"code\" name=\"code\">\n## Velocity Code Demo\n#*\n   based on PL/SQL mode by Peter Raganitsch, adapted to Velocity by Steve O'Hara ( http://www.pivotal-solutions.co.uk )\n   August 2011\n*#\n\n#*\n   This is a multiline comment.\n   This is the second line\n*#\n\n#[[ hello steve\n   This has invalid syntax that would normally need \"poor man's escaping\" like:\n\n   #define()\n\n   ${blah\n]]#\n\n#include( \"disclaimer.txt\" \"opinion.txt\" )\n#include( $foo $bar )\n\n#parse( \"lecorbusier.vm\" )\n#parse( $foo )\n\n#evaluate( 'string with VTL #if(true)will be displayed#end' )\n\n#define( $hello ) Hello $who #end #set( $who = \"World!\") $hello ## displays Hello World!\n\n#foreach( $customer in $customerList )\n\n    $foreach.count $customer.Name\n\n    #if( $foo == ${bar})\n        it's true!\n        #break\n    #{else}\n        it's not!\n        #stop\n    #end\n\n    #if ($foreach.parent.hasNext)\n        $velocityCount\n    #end\n#end\n\n$someObject.getValues(\"this is a string split\n        across lines\")\n\n$someObject(\"This plus $something in the middle\").method(7567).property\n\n#macro( tablerows $color $somelist )\n    #foreach( $something in $somelist )\n        <tr><td bgcolor=$color>$something</td></tr>\n        <tr><td bgcolor=$color>$bodyContent</td></tr>\n    #end\n#end\n\n#tablerows(\"red\" [\"dadsdf\",\"dsa\"])\n#@tablerows(\"red\" [\"dadsdf\",\"dsa\"]) some body content #end\n\n   Variable reference: #set( $monkey = $bill )\n   String literal: #set( $monkey.Friend = 'monica' )\n   Property reference: #set( $monkey.Blame = $whitehouse.Leak )\n   Method reference: #set( $monkey.Plan = $spindoctor.weave($web) )\n   Number literal: #set( $monkey.Number = 123 )\n   Range operator: #set( $monkey.Numbers = [1..3] )\n   Object list: #set( $monkey.Say = [\"Not\", $my, \"fault\"] )\n   Object map: #set( $monkey.Map = {\"banana\" : \"good\", \"roast beef\" : \"bad\"})\n\nThe RHS can also be a simple arithmetic expression, such as:\nAddition: #set( $value = $foo + 1 )\n   Subtraction: #set( $value = $bar - 1 )\n   Multiplication: #set( $value = $foo * $bar )\n   Division: #set( $value = $foo / $bar )\n   Remainder: #set( $value = $foo % $bar )\n\n</textarea></form>\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        theme: \"night\",\n        lineNumbers: true,\n        indentUnit: 4,\n        mode: \"text/velocity\"\n      });\n    </script>\n\n    <p><strong>MIME types defined:</strong> <code>text/velocity</code>.</p>\n\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/velocity/velocity.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"velocity\", function() {\n    function parseWords(str) {\n        var obj = {}, words = str.split(\" \");\n        for (var i = 0; i < words.length; ++i) obj[words[i]] = true;\n        return obj;\n    }\n\n    var keywords = parseWords(\"#end #else #break #stop #[[ #]] \" +\n                              \"#{end} #{else} #{break} #{stop}\");\n    var functions = parseWords(\"#if #elseif #foreach #set #include #parse #macro #define #evaluate \" +\n                               \"#{if} #{elseif} #{foreach} #{set} #{include} #{parse} #{macro} #{define} #{evaluate}\");\n    var specials = parseWords(\"$foreach.count $foreach.hasNext $foreach.first $foreach.last $foreach.topmost $foreach.parent.count $foreach.parent.hasNext $foreach.parent.first $foreach.parent.last $foreach.parent $velocityCount $!bodyContent $bodyContent\");\n    var isOperatorChar = /[+\\-*&%=<>!?:\\/|]/;\n\n    function chain(stream, state, f) {\n        state.tokenize = f;\n        return f(stream, state);\n    }\n    function tokenBase(stream, state) {\n        var beforeParams = state.beforeParams;\n        state.beforeParams = false;\n        var ch = stream.next();\n        // start of unparsed string?\n        if ((ch == \"'\") && state.inParams) {\n            state.lastTokenWasBuiltin = false;\n            return chain(stream, state, tokenString(ch));\n        }\n        // start of parsed string?\n        else if ((ch == '\"')) {\n            state.lastTokenWasBuiltin = false;\n            if (state.inString) {\n                state.inString = false;\n                return \"string\";\n            }\n            else if (state.inParams)\n                return chain(stream, state, tokenString(ch));\n        }\n        // is it one of the special signs []{}().,;? Seperator?\n        else if (/[\\[\\]{}\\(\\),;\\.]/.test(ch)) {\n            if (ch == \"(\" && beforeParams)\n                state.inParams = true;\n            else if (ch == \")\") {\n                state.inParams = false;\n                state.lastTokenWasBuiltin = true;\n            }\n            return null;\n        }\n        // start of a number value?\n        else if (/\\d/.test(ch)) {\n            state.lastTokenWasBuiltin = false;\n            stream.eatWhile(/[\\w\\.]/);\n            return \"number\";\n        }\n        // multi line comment?\n        else if (ch == \"#\" && stream.eat(\"*\")) {\n            state.lastTokenWasBuiltin = false;\n            return chain(stream, state, tokenComment);\n        }\n        // unparsed content?\n        else if (ch == \"#\" && stream.match(/ *\\[ *\\[/)) {\n            state.lastTokenWasBuiltin = false;\n            return chain(stream, state, tokenUnparsed);\n        }\n        // single line comment?\n        else if (ch == \"#\" && stream.eat(\"#\")) {\n            state.lastTokenWasBuiltin = false;\n            stream.skipToEnd();\n            return \"comment\";\n        }\n        // variable?\n        else if (ch == \"$\") {\n            stream.eatWhile(/[\\w\\d\\$_\\.{}]/);\n            // is it one of the specials?\n            if (specials && specials.propertyIsEnumerable(stream.current())) {\n                return \"keyword\";\n            }\n            else {\n                state.lastTokenWasBuiltin = true;\n                state.beforeParams = true;\n                return \"builtin\";\n            }\n        }\n        // is it a operator?\n        else if (isOperatorChar.test(ch)) {\n            state.lastTokenWasBuiltin = false;\n            stream.eatWhile(isOperatorChar);\n            return \"operator\";\n        }\n        else {\n            // get the whole word\n            stream.eatWhile(/[\\w\\$_{}@]/);\n            var word = stream.current();\n            // is it one of the listed keywords?\n            if (keywords && keywords.propertyIsEnumerable(word))\n                return \"keyword\";\n            // is it one of the listed functions?\n            if (functions && functions.propertyIsEnumerable(word) ||\n                    (stream.current().match(/^#@?[a-z0-9_]+ *$/i) && stream.peek()==\"(\") &&\n                     !(functions && functions.propertyIsEnumerable(word.toLowerCase()))) {\n                state.beforeParams = true;\n                state.lastTokenWasBuiltin = false;\n                return \"keyword\";\n            }\n            if (state.inString) {\n                state.lastTokenWasBuiltin = false;\n                return \"string\";\n            }\n            if (stream.pos > word.length && stream.string.charAt(stream.pos-word.length-1)==\".\" && state.lastTokenWasBuiltin)\n                return \"builtin\";\n            // default: just a \"word\"\n            state.lastTokenWasBuiltin = false;\n            return null;\n        }\n    }\n\n    function tokenString(quote) {\n        return function(stream, state) {\n            var escaped = false, next, end = false;\n            while ((next = stream.next()) != null) {\n                if ((next == quote) && !escaped) {\n                    end = true;\n                    break;\n                }\n                if (quote=='\"' && stream.peek() == '$' && !escaped) {\n                    state.inString = true;\n                    end = true;\n                    break;\n                }\n                escaped = !escaped && next == \"\\\\\";\n            }\n            if (end) state.tokenize = tokenBase;\n            return \"string\";\n        };\n    }\n\n    function tokenComment(stream, state) {\n        var maybeEnd = false, ch;\n        while (ch = stream.next()) {\n            if (ch == \"#\" && maybeEnd) {\n                state.tokenize = tokenBase;\n                break;\n            }\n            maybeEnd = (ch == \"*\");\n        }\n        return \"comment\";\n    }\n\n    function tokenUnparsed(stream, state) {\n        var maybeEnd = 0, ch;\n        while (ch = stream.next()) {\n            if (ch == \"#\" && maybeEnd == 2) {\n                state.tokenize = tokenBase;\n                break;\n            }\n            if (ch == \"]\")\n                maybeEnd++;\n            else if (ch != \" \")\n                maybeEnd = 0;\n        }\n        return \"meta\";\n    }\n    // Interface\n\n    return {\n        startState: function() {\n            return {\n                tokenize: tokenBase,\n                beforeParams: false,\n                inParams: false,\n                inString: false,\n                lastTokenWasBuiltin: false\n            };\n        },\n\n        token: function(stream, state) {\n            if (stream.eatSpace()) return null;\n            return state.tokenize(stream, state);\n        },\n        blockCommentStart: \"#*\",\n        blockCommentEnd: \"*#\",\n        lineComment: \"##\",\n        fold: \"velocity\"\n    };\n});\n\nCodeMirror.defineMIME(\"text/velocity\", \"velocity\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/verilog/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Verilog/SystemVerilog mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"../../addon/edit/matchbrackets.js\"></script>\n<script src=\"verilog.js\"></script>\n<style type=\"text/css\">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Verilog/SystemVerilog</a>\n  </ul>\n</div>\n\n<article>\n<h2>SystemVerilog mode</h2>\n\n<div><textarea id=\"code\" name=\"code\">\n// Literals\n1'b0\n1'bx\n1'bz\n16'hDC78\n'hdeadbeef\n'b0011xxzz\n1234\n32'd5678\n3.4e6\n-128.7\n\n// Macro definition\n`define BUS_WIDTH = 8;\n\n// Module definition\nmodule block(\n  input                   clk,\n  input                   rst_n,\n  input  [`BUS_WIDTH-1:0] data_in,\n  output [`BUS_WIDTH-1:0] data_out\n);\n  \n  always @(posedge clk or negedge rst_n) begin\n\n    if (~rst_n) begin\n      data_out <= 8'b0;\n    end else begin\n      data_out <= data_in;\n    end\n    \n    if (~rst_n)\n      data_out <= 8'b0;\n    else\n      data_out <= data_in;\n    \n    if (~rst_n)\n      begin\n        data_out <= 8'b0;\n      end\n    else\n      begin\n        data_out <= data_in;\n      end\n\n  end\n  \nendmodule\n\n// Class definition\nclass test;\n\n  /**\n   * Sum two integers\n   */\n  function int sum(int a, int b);\n    int result = a + b;\n    string msg = $sformatf(\"%d + %d = %d\", a, b, result);\n    $display(msg);\n    return result;\n  endfunction\n  \n  task delay(int num_cycles);\n    repeat(num_cycles) #1;\n  endtask\n  \nendclass\n\n</textarea></div>\n\n<script>\n  var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n    lineNumbers: true,\n    matchBrackets: true,\n    mode: {\n      name: \"verilog\",\n      noIndentKeywords: [\"package\"]\n    }\n  });\n</script>\n\n<p>\nSyntax highlighting and indentation for the Verilog and SystemVerilog languages (IEEE 1800).\n<h2>Configuration options:</h2>\n  <ul>\n    <li><strong>noIndentKeywords</strong> - List of keywords which should not cause identation to increase. E.g. [\"package\", \"module\"]. Default: None</li>\n  </ul>\n</p>\n\n<p><strong>MIME types defined:</strong> <code>text/x-verilog</code> and <code>text/x-systemverilog</code>.</p>\n</article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/verilog/test.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function() {\n  var mode = CodeMirror.getMode({indentUnit: 4}, \"verilog\");\n  function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); }\n\n  MT(\"binary_literals\",\n     \"[number 1'b0]\",\n     \"[number 1'b1]\",\n     \"[number 1'bx]\",\n     \"[number 1'bz]\",\n     \"[number 1'bX]\",\n     \"[number 1'bZ]\",\n     \"[number 1'B0]\",\n     \"[number 1'B1]\",\n     \"[number 1'Bx]\",\n     \"[number 1'Bz]\",\n     \"[number 1'BX]\",\n     \"[number 1'BZ]\",\n     \"[number 1'b0]\",\n     \"[number 1'b1]\",\n     \"[number 2'b01]\",\n     \"[number 2'bxz]\",\n     \"[number 2'b11]\",\n     \"[number 2'b10]\",\n     \"[number 2'b1Z]\",\n     \"[number 12'b0101_0101_0101]\",\n     \"[number 1'b 0]\",\n     \"[number 'b0101]\"\n  );\n\n  MT(\"octal_literals\",\n     \"[number 3'o7]\",\n     \"[number 3'O7]\",\n     \"[number 3'so7]\",\n     \"[number 3'SO7]\"\n  );\n\n  MT(\"decimal_literals\",\n     \"[number 0]\",\n     \"[number 1]\",\n     \"[number 7]\",\n     \"[number 123_456]\",\n     \"[number 'd33]\",\n     \"[number 8'd255]\",\n     \"[number 8'D255]\",\n     \"[number 8'sd255]\",\n     \"[number 8'SD255]\",\n     \"[number 32'd123]\",\n     \"[number 32 'd123]\",\n     \"[number 32 'd 123]\"\n  );\n\n  MT(\"hex_literals\",\n     \"[number 4'h0]\",\n     \"[number 4'ha]\",\n     \"[number 4'hF]\",\n     \"[number 4'hx]\",\n     \"[number 4'hz]\",\n     \"[number 4'hX]\",\n     \"[number 4'hZ]\",\n     \"[number 32'hdc78]\",\n     \"[number 32'hDC78]\",\n     \"[number 32 'hDC78]\",\n     \"[number 32'h DC78]\",\n     \"[number 32 'h DC78]\",\n     \"[number 32'h44x7]\",\n     \"[number 32'hFFF?]\"\n  );\n\n  MT(\"real_number_literals\",\n     \"[number 1.2]\",\n     \"[number 0.1]\",\n     \"[number 2394.26331]\",\n     \"[number 1.2E12]\",\n     \"[number 1.2e12]\",\n     \"[number 1.30e-2]\",\n     \"[number 0.1e-0]\",\n     \"[number 23E10]\",\n     \"[number 29E-2]\",\n     \"[number 236.123_763_e-12]\"\n  );\n\n  MT(\"operators\",\n     \"[meta ^]\"\n  );\n\n  MT(\"keywords\",\n     \"[keyword logic]\",\n     \"[keyword logic] [variable foo]\",\n     \"[keyword reg] [variable abc]\"\n  );\n\n  MT(\"variables\",\n     \"[variable _leading_underscore]\",\n     \"[variable _if]\",\n     \"[number 12] [variable foo]\",\n     \"[variable foo] [number 14]\"\n  );\n\n  MT(\"tick_defines\",\n     \"[def `FOO]\",\n     \"[def `foo]\",\n     \"[def `FOO_bar]\"\n  );\n\n  MT(\"system_calls\",\n     \"[meta $display]\",\n     \"[meta $vpi_printf]\"\n  );\n\n  MT(\"line_comment\", \"[comment // Hello world]\");\n\n  // Alignment tests\n  MT(\"align_port_map_style1\",\n     /**\n      * mod mod(.a(a),\n      *         .b(b)\n      *        );\n      */\n     \"[variable mod] [variable mod][bracket (].[variable a][bracket (][variable a][bracket )],\",\n     \"        .[variable b][bracket (][variable b][bracket )]\",\n     \"       [bracket )];\",\n     \"\"\n  );\n\n  MT(\"align_port_map_style2\",\n     /**\n      * mod mod(\n      *     .a(a),\n      *     .b(b)\n      * );\n      */\n     \"[variable mod] [variable mod][bracket (]\",\n     \"    .[variable a][bracket (][variable a][bracket )],\",\n     \"    .[variable b][bracket (][variable b][bracket )]\",\n     \"[bracket )];\",\n     \"\"\n  );\n\n  // Indentation tests\n  MT(\"indent_single_statement_if\",\n      \"[keyword if] [bracket (][variable foo][bracket )]\",\n      \"    [keyword break];\",\n      \"\"\n  );\n\n  MT(\"no_indent_after_single_line_if\",\n      \"[keyword if] [bracket (][variable foo][bracket )] [keyword break];\",\n      \"\"\n  );\n\n  MT(\"indent_after_if_begin_same_line\",\n      \"[keyword if] [bracket (][variable foo][bracket )] [keyword begin]\",\n      \"    [keyword break];\",\n      \"    [keyword break];\",\n      \"[keyword end]\",\n      \"\"\n  );\n\n  MT(\"indent_after_if_begin_next_line\",\n      \"[keyword if] [bracket (][variable foo][bracket )]\",\n      \"    [keyword begin]\",\n      \"        [keyword break];\",\n      \"        [keyword break];\",\n      \"    [keyword end]\",\n      \"\"\n  );\n\n  MT(\"indent_single_statement_if_else\",\n      \"[keyword if] [bracket (][variable foo][bracket )]\",\n      \"    [keyword break];\",\n      \"[keyword else]\",\n      \"    [keyword break];\",\n      \"\"\n  );\n\n  MT(\"indent_if_else_begin_same_line\",\n      \"[keyword if] [bracket (][variable foo][bracket )] [keyword begin]\",\n      \"    [keyword break];\",\n      \"    [keyword break];\",\n      \"[keyword end] [keyword else] [keyword begin]\",\n      \"    [keyword break];\",\n      \"    [keyword break];\",\n      \"[keyword end]\",\n      \"\"\n  );\n\n  MT(\"indent_if_else_begin_next_line\",\n      \"[keyword if] [bracket (][variable foo][bracket )]\",\n      \"    [keyword begin]\",\n      \"        [keyword break];\",\n      \"        [keyword break];\",\n      \"    [keyword end]\",\n      \"[keyword else]\",\n      \"    [keyword begin]\",\n      \"        [keyword break];\",\n      \"        [keyword break];\",\n      \"    [keyword end]\",\n      \"\"\n  );\n\n  MT(\"indent_if_nested_without_begin\",\n      \"[keyword if] [bracket (][variable foo][bracket )]\",\n      \"    [keyword if] [bracket (][variable foo][bracket )]\",\n      \"        [keyword if] [bracket (][variable foo][bracket )]\",\n      \"            [keyword break];\",\n      \"\"\n  );\n\n  MT(\"indent_case\",\n      \"[keyword case] [bracket (][variable state][bracket )]\",\n      \"    [variable FOO]:\",\n      \"        [keyword break];\",\n      \"    [variable BAR]:\",\n      \"        [keyword break];\",\n      \"[keyword endcase]\",\n      \"\"\n  );\n\n  MT(\"unindent_after_end_with_preceding_text\",\n      \"[keyword begin]\",\n      \"    [keyword break]; [keyword end]\",\n      \"\"\n  );\n\n  MT(\"export_function_one_line_does_not_indent\",\n     \"[keyword export] [string \\\"DPI-C\\\"] [keyword function] [variable helloFromSV];\",\n     \"\"\n  );\n\n  MT(\"export_task_one_line_does_not_indent\",\n     \"[keyword export] [string \\\"DPI-C\\\"] [keyword task] [variable helloFromSV];\",\n     \"\"\n  );\n\n  MT(\"export_function_two_lines_indents_properly\",\n    \"[keyword export]\",\n    \"    [string \\\"DPI-C\\\"] [keyword function] [variable helloFromSV];\",\n    \"\"\n  );\n\n  MT(\"export_task_two_lines_indents_properly\",\n    \"[keyword export]\",\n    \"    [string \\\"DPI-C\\\"] [keyword task] [variable helloFromSV];\",\n    \"\"\n  );\n\n  MT(\"import_function_one_line_does_not_indent\",\n    \"[keyword import] [string \\\"DPI-C\\\"] [keyword function] [variable helloFromC];\",\n    \"\"\n  );\n\n  MT(\"import_task_one_line_does_not_indent\",\n    \"[keyword import] [string \\\"DPI-C\\\"] [keyword task] [variable helloFromC];\",\n    \"\"\n  );\n\n  MT(\"import_package_single_line_does_not_indent\",\n    \"[keyword import] [variable p]::[variable x];\",\n    \"[keyword import] [variable p]::[variable y];\",\n    \"\"\n  );\n\n  MT(\"covergoup_with_function_indents_properly\",\n    \"[keyword covergroup] [variable cg] [keyword with] [keyword function] [variable sample][bracket (][keyword bit] [variable b][bracket )];\",\n    \"    [variable c] : [keyword coverpoint] [variable c];\",\n    \"[keyword endgroup]: [variable cg]\",\n    \"\"\n  );\n\n})();\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/verilog/verilog.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"verilog\", function(config, parserConfig) {\n\n  var indentUnit = config.indentUnit,\n      statementIndentUnit = parserConfig.statementIndentUnit || indentUnit,\n      dontAlignCalls = parserConfig.dontAlignCalls,\n      noIndentKeywords = parserConfig.noIndentKeywords || [],\n      multiLineStrings = parserConfig.multiLineStrings,\n      hooks = parserConfig.hooks || {};\n\n  function words(str) {\n    var obj = {}, words = str.split(\" \");\n    for (var i = 0; i < words.length; ++i) obj[words[i]] = true;\n    return obj;\n  }\n\n  /**\n   * Keywords from IEEE 1800-2012\n   */\n  var keywords = words(\n    \"accept_on alias always always_comb always_ff always_latch and assert assign assume automatic before begin bind \" +\n    \"bins binsof bit break buf bufif0 bufif1 byte case casex casez cell chandle checker class clocking cmos config \" +\n    \"const constraint context continue cover covergroup coverpoint cross deassign default defparam design disable \" +\n    \"dist do edge else end endcase endchecker endclass endclocking endconfig endfunction endgenerate endgroup \" +\n    \"endinterface endmodule endpackage endprimitive endprogram endproperty endspecify endsequence endtable endtask \" +\n    \"enum event eventually expect export extends extern final first_match for force foreach forever fork forkjoin \" +\n    \"function generate genvar global highz0 highz1 if iff ifnone ignore_bins illegal_bins implements implies import \" +\n    \"incdir include initial inout input inside instance int integer interconnect interface intersect join join_any \" +\n    \"join_none large let liblist library local localparam logic longint macromodule matches medium modport module \" +\n    \"nand negedge nettype new nexttime nmos nor noshowcancelled not notif0 notif1 null or output package packed \" +\n    \"parameter pmos posedge primitive priority program property protected pull0 pull1 pulldown pullup \" +\n    \"pulsestyle_ondetect pulsestyle_onevent pure rand randc randcase randsequence rcmos real realtime ref reg \" +\n    \"reject_on release repeat restrict return rnmos rpmos rtran rtranif0 rtranif1 s_always s_eventually s_nexttime \" +\n    \"s_until s_until_with scalared sequence shortint shortreal showcancelled signed small soft solve specify \" +\n    \"specparam static string strong strong0 strong1 struct super supply0 supply1 sync_accept_on sync_reject_on \" +\n    \"table tagged task this throughout time timeprecision timeunit tran tranif0 tranif1 tri tri0 tri1 triand trior \" +\n    \"trireg type typedef union unique unique0 unsigned until until_with untyped use uwire var vectored virtual void \" +\n    \"wait wait_order wand weak weak0 weak1 while wildcard wire with within wor xnor xor\");\n\n  /** Operators from IEEE 1800-2012\n     unary_operator ::=\n       + | - | ! | ~ | & | ~& | | | ~| | ^ | ~^ | ^~\n     binary_operator ::=\n       + | - | * | / | % | == | != | === | !== | ==? | !=? | && | || | **\n       | < | <= | > | >= | & | | | ^ | ^~ | ~^ | >> | << | >>> | <<<\n       | -> | <->\n     inc_or_dec_operator ::= ++ | --\n     unary_module_path_operator ::=\n       ! | ~ | & | ~& | | | ~| | ^ | ~^ | ^~\n     binary_module_path_operator ::=\n       == | != | && | || | & | | | ^ | ^~ | ~^\n  */\n  var isOperatorChar = /[\\+\\-\\*\\/!~&|^%=?:]/;\n  var isBracketChar = /[\\[\\]{}()]/;\n\n  var unsignedNumber = /\\d[0-9_]*/;\n  var decimalLiteral = /\\d*\\s*'s?d\\s*\\d[0-9_]*/i;\n  var binaryLiteral = /\\d*\\s*'s?b\\s*[xz01][xz01_]*/i;\n  var octLiteral = /\\d*\\s*'s?o\\s*[xz0-7][xz0-7_]*/i;\n  var hexLiteral = /\\d*\\s*'s?h\\s*[0-9a-fxz?][0-9a-fxz?_]*/i;\n  var realLiteral = /(\\d[\\d_]*(\\.\\d[\\d_]*)?E-?[\\d_]+)|(\\d[\\d_]*\\.\\d[\\d_]*)/i;\n\n  var closingBracketOrWord = /^((\\w+)|[)}\\]])/;\n  var closingBracket = /[)}\\]]/;\n\n  var curPunc;\n  var curKeyword;\n\n  // Block openings which are closed by a matching keyword in the form of (\"end\" + keyword)\n  // E.g. \"task\" => \"endtask\"\n  var blockKeywords = words(\n    \"case checker class clocking config function generate interface module package\" +\n    \"primitive program property specify sequence table task\"\n  );\n\n  // Opening/closing pairs\n  var openClose = {};\n  for (var keyword in blockKeywords) {\n    openClose[keyword] = \"end\" + keyword;\n  }\n  openClose[\"begin\"] = \"end\";\n  openClose[\"casex\"] = \"endcase\";\n  openClose[\"casez\"] = \"endcase\";\n  openClose[\"do\"   ] = \"while\";\n  openClose[\"fork\" ] = \"join;join_any;join_none\";\n  openClose[\"covergroup\"] = \"endgroup\";\n\n  for (var i in noIndentKeywords) {\n    var keyword = noIndentKeywords[i];\n    if (openClose[keyword]) {\n      openClose[keyword] = undefined;\n    }\n  }\n\n  // Keywords which open statements that are ended with a semi-colon\n  var statementKeywords = words(\"always always_comb always_ff always_latch assert assign assume else export for foreach forever if import initial repeat while\");\n\n  function tokenBase(stream, state) {\n    var ch = stream.peek(), style;\n    if (hooks[ch] && (style = hooks[ch](stream, state)) != false) return style;\n    if (hooks.tokenBase && (style = hooks.tokenBase(stream, state)) != false)\n      return style;\n\n    if (/[,;:\\.]/.test(ch)) {\n      curPunc = stream.next();\n      return null;\n    }\n    if (isBracketChar.test(ch)) {\n      curPunc = stream.next();\n      return \"bracket\";\n    }\n    // Macros (tick-defines)\n    if (ch == '`') {\n      stream.next();\n      if (stream.eatWhile(/[\\w\\$_]/)) {\n        return \"def\";\n      } else {\n        return null;\n      }\n    }\n    // System calls\n    if (ch == '$') {\n      stream.next();\n      if (stream.eatWhile(/[\\w\\$_]/)) {\n        return \"meta\";\n      } else {\n        return null;\n      }\n    }\n    // Time literals\n    if (ch == '#') {\n      stream.next();\n      stream.eatWhile(/[\\d_.]/);\n      return \"def\";\n    }\n    // Strings\n    if (ch == '\"') {\n      stream.next();\n      state.tokenize = tokenString(ch);\n      return state.tokenize(stream, state);\n    }\n    // Comments\n    if (ch == \"/\") {\n      stream.next();\n      if (stream.eat(\"*\")) {\n        state.tokenize = tokenComment;\n        return tokenComment(stream, state);\n      }\n      if (stream.eat(\"/\")) {\n        stream.skipToEnd();\n        return \"comment\";\n      }\n      stream.backUp(1);\n    }\n\n    // Numeric literals\n    if (stream.match(realLiteral) ||\n        stream.match(decimalLiteral) ||\n        stream.match(binaryLiteral) ||\n        stream.match(octLiteral) ||\n        stream.match(hexLiteral) ||\n        stream.match(unsignedNumber) ||\n        stream.match(realLiteral)) {\n      return \"number\";\n    }\n\n    // Operators\n    if (stream.eatWhile(isOperatorChar)) {\n      return \"meta\";\n    }\n\n    // Keywords / plain variables\n    if (stream.eatWhile(/[\\w\\$_]/)) {\n      var cur = stream.current();\n      if (keywords[cur]) {\n        if (openClose[cur]) {\n          curPunc = \"newblock\";\n        }\n        if (statementKeywords[cur]) {\n          curPunc = \"newstatement\";\n        }\n        curKeyword = cur;\n        return \"keyword\";\n      }\n      return \"variable\";\n    }\n\n    stream.next();\n    return null;\n  }\n\n  function tokenString(quote) {\n    return function(stream, state) {\n      var escaped = false, next, end = false;\n      while ((next = stream.next()) != null) {\n        if (next == quote && !escaped) {end = true; break;}\n        escaped = !escaped && next == \"\\\\\";\n      }\n      if (end || !(escaped || multiLineStrings))\n        state.tokenize = tokenBase;\n      return \"string\";\n    };\n  }\n\n  function tokenComment(stream, state) {\n    var maybeEnd = false, ch;\n    while (ch = stream.next()) {\n      if (ch == \"/\" && maybeEnd) {\n        state.tokenize = tokenBase;\n        break;\n      }\n      maybeEnd = (ch == \"*\");\n    }\n    return \"comment\";\n  }\n\n  function Context(indented, column, type, align, prev) {\n    this.indented = indented;\n    this.column = column;\n    this.type = type;\n    this.align = align;\n    this.prev = prev;\n  }\n  function pushContext(state, col, type) {\n    var indent = state.indented;\n    var c = new Context(indent, col, type, null, state.context);\n    return state.context = c;\n  }\n  function popContext(state) {\n    var t = state.context.type;\n    if (t == \")\" || t == \"]\" || t == \"}\") {\n      state.indented = state.context.indented;\n    }\n    return state.context = state.context.prev;\n  }\n\n  function isClosing(text, contextClosing) {\n    if (text == contextClosing) {\n      return true;\n    } else {\n      // contextClosing may be mulitple keywords separated by ;\n      var closingKeywords = contextClosing.split(\";\");\n      for (var i in closingKeywords) {\n        if (text == closingKeywords[i]) {\n          return true;\n        }\n      }\n      return false;\n    }\n  }\n\n  function buildElectricInputRegEx() {\n    // Reindentation should occur on any bracket char: {}()[]\n    // or on a match of any of the block closing keywords, at\n    // the end of a line\n    var allClosings = [];\n    for (var i in openClose) {\n      if (openClose[i]) {\n        var closings = openClose[i].split(\";\");\n        for (var j in closings) {\n          allClosings.push(closings[j]);\n        }\n      }\n    }\n    var re = new RegExp(\"[{}()\\\\[\\\\]]|(\" + allClosings.join(\"|\") + \")$\");\n    return re;\n  }\n\n  // Interface\n  return {\n\n    // Regex to force current line to reindent\n    electricInput: buildElectricInputRegEx(),\n\n    startState: function(basecolumn) {\n      var state = {\n        tokenize: null,\n        context: new Context((basecolumn || 0) - indentUnit, 0, \"top\", false),\n        indented: 0,\n        startOfLine: true\n      };\n      if (hooks.startState) hooks.startState(state);\n      return state;\n    },\n\n    token: function(stream, state) {\n      var ctx = state.context;\n      if (stream.sol()) {\n        if (ctx.align == null) ctx.align = false;\n        state.indented = stream.indentation();\n        state.startOfLine = true;\n      }\n      if (hooks.token) hooks.token(stream, state);\n      if (stream.eatSpace()) return null;\n      curPunc = null;\n      curKeyword = null;\n      var style = (state.tokenize || tokenBase)(stream, state);\n      if (style == \"comment\" || style == \"meta\" || style == \"variable\") return style;\n      if (ctx.align == null) ctx.align = true;\n\n      if (curPunc == ctx.type) {\n        popContext(state);\n      } else if ((curPunc == \";\" && ctx.type == \"statement\") ||\n               (ctx.type && isClosing(curKeyword, ctx.type))) {\n        ctx = popContext(state);\n        while (ctx && ctx.type == \"statement\") ctx = popContext(state);\n      } else if (curPunc == \"{\") {\n        pushContext(state, stream.column(), \"}\");\n      } else if (curPunc == \"[\") {\n        pushContext(state, stream.column(), \"]\");\n      } else if (curPunc == \"(\") {\n        pushContext(state, stream.column(), \")\");\n      } else if (ctx && ctx.type == \"endcase\" && curPunc == \":\") {\n        pushContext(state, stream.column(), \"statement\");\n      } else if (curPunc == \"newstatement\") {\n        pushContext(state, stream.column(), \"statement\");\n      } else if (curPunc == \"newblock\") {\n        if (curKeyword == \"function\" && ctx && (ctx.type == \"statement\" || ctx.type == \"endgroup\")) {\n          // The 'function' keyword can appear in some other contexts where it actually does not\n          // indicate a function (import/export DPI and covergroup definitions).\n          // Do nothing in this case\n        } else if (curKeyword == \"task\" && ctx && ctx.type == \"statement\") {\n          // Same thing for task\n        } else {\n          var close = openClose[curKeyword];\n          pushContext(state, stream.column(), close);\n        }\n      }\n\n      state.startOfLine = false;\n      return style;\n    },\n\n    indent: function(state, textAfter) {\n      if (state.tokenize != tokenBase && state.tokenize != null) return CodeMirror.Pass;\n      if (hooks.indent) {\n        var fromHook = hooks.indent(state);\n        if (fromHook >= 0) return fromHook;\n      }\n      var ctx = state.context, firstChar = textAfter && textAfter.charAt(0);\n      if (ctx.type == \"statement\" && firstChar == \"}\") ctx = ctx.prev;\n      var closing = false;\n      var possibleClosing = textAfter.match(closingBracketOrWord);\n      if (possibleClosing)\n        closing = isClosing(possibleClosing[0], ctx.type);\n      if (ctx.type == \"statement\") return ctx.indented + (firstChar == \"{\" ? 0 : statementIndentUnit);\n      else if (closingBracket.test(ctx.type) && ctx.align && !dontAlignCalls) return ctx.column + (closing ? 0 : 1);\n      else if (ctx.type == \")\" && !closing) return ctx.indented + statementIndentUnit;\n      else return ctx.indented + (closing ? 0 : indentUnit);\n    },\n\n    blockCommentStart: \"/*\",\n    blockCommentEnd: \"*/\",\n    lineComment: \"//\"\n  };\n});\n\n  CodeMirror.defineMIME(\"text/x-verilog\", {\n    name: \"verilog\"\n  });\n\n  CodeMirror.defineMIME(\"text/x-systemverilog\", {\n    name: \"verilog\"\n  });\n\n  // SVXVerilog mode\n\n  var svxchScopePrefixes = {\n    \">\": \"property\", \"->\": \"property\", \"-\": \"hr\", \"|\": \"link\", \"?$\": \"qualifier\", \"?*\": \"qualifier\",\n    \"@-\": \"variable-3\", \"@\": \"variable-3\", \"?\": \"qualifier\"\n  };\n\n  function svxGenIndent(stream, state) {\n    var svxindentUnit = 2;\n    var rtnIndent = -1, indentUnitRq = 0, curIndent = stream.indentation();\n    switch (state.svxCurCtlFlowChar) {\n    case \"\\\\\":\n      curIndent = 0;\n      break;\n    case \"|\":\n      if (state.svxPrevPrevCtlFlowChar == \"@\") {\n        indentUnitRq = -2; //-2 new pipe rq after cur pipe\n        break;\n      }\n      if (svxchScopePrefixes[state.svxPrevCtlFlowChar])\n        indentUnitRq = 1; // +1 new scope\n      break;\n    case \"M\":  // m4\n      if (state.svxPrevPrevCtlFlowChar == \"@\") {\n        indentUnitRq = -2; //-2 new inst rq after  pipe\n        break;\n      }\n      if (svxchScopePrefixes[state.svxPrevCtlFlowChar])\n        indentUnitRq = 1; // +1 new scope\n      break;\n    case \"@\":\n      if (state.svxPrevCtlFlowChar == \"S\")\n        indentUnitRq = -1; // new pipe stage after stmts\n      if (state.svxPrevCtlFlowChar == \"|\")\n        indentUnitRq = 1; // 1st pipe stage\n      break;\n    case \"S\":\n      if (state.svxPrevCtlFlowChar == \"@\")\n        indentUnitRq = 1; // flow in pipe stage\n      if (svxchScopePrefixes[state.svxPrevCtlFlowChar])\n        indentUnitRq = 1; // +1 new scope\n      break;\n    }\n    var statementIndentUnit = svxindentUnit;\n    rtnIndent = curIndent + (indentUnitRq*statementIndentUnit);\n    return rtnIndent >= 0 ? rtnIndent : curIndent;\n  }\n\n  CodeMirror.defineMIME(\"text/x-svx\", {\n    name: \"verilog\",\n    hooks: {\n      \"\\\\\": function(stream, state) {\n        var vxIndent = 0, style = false;\n        var curPunc  = stream.string;\n        if ((stream.sol()) && (/\\\\SV/.test(stream.string))) {\n          curPunc = (/\\\\SVX_version/.test(stream.string))\n            ? \"\\\\SVX_version\" : stream.string;\n          stream.skipToEnd();\n          if (curPunc == \"\\\\SV\" && state.vxCodeActive) {state.vxCodeActive = false;};\n          if ((/\\\\SVX/.test(curPunc) && !state.vxCodeActive)\n            || (curPunc==\"\\\\SVX_version\" && state.vxCodeActive)) {state.vxCodeActive = true;};\n          style = \"keyword\";\n          state.svxCurCtlFlowChar  = state.svxPrevPrevCtlFlowChar\n            = state.svxPrevCtlFlowChar = \"\";\n          if (state.vxCodeActive == true) {\n            state.svxCurCtlFlowChar  = \"\\\\\";\n            vxIndent = svxGenIndent(stream, state);\n          }\n          state.vxIndentRq = vxIndent;\n        }\n        return style;\n      },\n      tokenBase: function(stream, state) {\n        var vxIndent = 0, style = false;\n        var svxisOperatorChar = /[\\[\\]=:]/;\n        var svxkpScopePrefixs = {\n          \"**\":\"variable-2\", \"*\":\"variable-2\", \"$$\":\"variable\", \"$\":\"variable\",\n          \"^^\":\"attribute\", \"^\":\"attribute\"};\n        var ch = stream.peek();\n        var vxCurCtlFlowCharValueAtStart = state.svxCurCtlFlowChar;\n        if (state.vxCodeActive == true) {\n          if (/[\\[\\]{}\\(\\);\\:]/.test(ch)) {\n            // bypass nesting and 1 char punc\n            style = \"meta\";\n            stream.next();\n          } else if (ch == \"/\") {\n            stream.next();\n            if (stream.eat(\"/\")) {\n              stream.skipToEnd();\n              style = \"comment\";\n              state.svxCurCtlFlowChar = \"S\";\n            } else {\n              stream.backUp(1);\n            }\n          } else if (ch == \"@\") {\n            // pipeline stage\n            style = svxchScopePrefixes[ch];\n            state.svxCurCtlFlowChar = \"@\";\n            stream.next();\n            stream.eatWhile(/[\\w\\$_]/);\n          } else if (stream.match(/\\b[mM]4+/, true)) { // match: function(pattern, consume, caseInsensitive)\n            // m4 pre proc\n            stream.skipTo(\"(\");\n            style = \"def\";\n            state.svxCurCtlFlowChar = \"M\";\n          } else if (ch == \"!\" && stream.sol()) {\n            // v stmt in svx region\n            // state.svxCurCtlFlowChar  = \"S\";\n            style = \"comment\";\n            stream.next();\n          } else if (svxisOperatorChar.test(ch)) {\n            // operators\n            stream.eatWhile(svxisOperatorChar);\n            style = \"operator\";\n          } else if (ch == \"#\") {\n            // phy hier\n            state.svxCurCtlFlowChar  = (state.svxCurCtlFlowChar == \"\")\n              ? ch : state.svxCurCtlFlowChar;\n            stream.next();\n            stream.eatWhile(/[+-]\\d/);\n            style = \"tag\";\n          } else if (svxkpScopePrefixs.propertyIsEnumerable(ch)) {\n            // special SVX operators\n            style = svxkpScopePrefixs[ch];\n            state.svxCurCtlFlowChar = state.svxCurCtlFlowChar == \"\" ? \"S\" : state.svxCurCtlFlowChar;  // stmt\n            stream.next();\n            stream.match(/[a-zA-Z_0-9]+/);\n          } else if (style = svxchScopePrefixes[ch] || false) {\n            // special SVX operators\n            state.svxCurCtlFlowChar = state.svxCurCtlFlowChar == \"\" ? ch : state.svxCurCtlFlowChar;\n            stream.next();\n            stream.match(/[a-zA-Z_0-9]+/);\n          }\n          if (state.svxCurCtlFlowChar != vxCurCtlFlowCharValueAtStart) { // flow change\n            vxIndent = svxGenIndent(stream, state);\n            state.vxIndentRq = vxIndent;\n          }\n        }\n        return style;\n      },\n      token: function(stream, state) {\n        if (state.vxCodeActive == true && stream.sol() && state.svxCurCtlFlowChar != \"\") {\n          state.svxPrevPrevCtlFlowChar = state.svxPrevCtlFlowChar;\n          state.svxPrevCtlFlowChar = state.svxCurCtlFlowChar;\n          state.svxCurCtlFlowChar = \"\";\n        }\n      },\n      indent: function(state) {\n        return (state.vxCodeActive == true) ? state.vxIndentRq : -1;\n      },\n      startState: function(state) {\n        state.svxCurCtlFlowChar = \"\";\n        state.svxPrevCtlFlowChar = \"\";\n        state.svxPrevPrevCtlFlowChar = \"\";\n        state.vxCodeActive = true;\n        state.vxIndentRq = 0;\n      }\n    }\n  });\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/xml/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: XML mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"xml.js\"></script>\n<style type=\"text/css\">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">XML</a>\n  </ul>\n</div>\n\n<article>\n<h2>XML mode</h2>\n<form><textarea id=\"code\" name=\"code\">\n&lt;html style=\"color: green\"&gt;\n  &lt;!-- this is a comment --&gt;\n  &lt;head&gt;\n    &lt;title&gt;HTML Example&lt;/title&gt;\n  &lt;/head&gt;\n  &lt;body&gt;\n    The indentation tries to be &lt;em&gt;somewhat &amp;quot;do what\n    I mean&amp;quot;&lt;/em&gt;... but might not match your style.\n  &lt;/body&gt;\n&lt;/html&gt;\n</textarea></form>\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        mode: \"text/html\",\n        lineNumbers: true\n      });\n    </script>\n    <p>The XML mode supports two configuration parameters:</p>\n    <dl>\n      <dt><code>htmlMode (boolean)</code></dt>\n      <dd>This switches the mode to parse HTML instead of XML. This\n      means attributes do not have to be quoted, and some elements\n      (such as <code>br</code>) do not require a closing tag.</dd>\n      <dt><code>alignCDATA (boolean)</code></dt>\n      <dd>Setting this to true will force the opening tag of CDATA\n      blocks to not be indented.</dd>\n    </dl>\n\n    <p><strong>MIME types defined:</strong> <code>application/xml</code>, <code>text/html</code>.</p>\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/xml/test.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function() {\n  var mode = CodeMirror.getMode({indentUnit: 2}, \"xml\"), mname = \"xml\";\n  function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1), mname); }\n\n  MT(\"matching\",\n     \"[tag&bracket <][tag top][tag&bracket >]\",\n     \"  text\",\n     \"  [tag&bracket <][tag inner][tag&bracket />]\",\n     \"[tag&bracket </][tag top][tag&bracket >]\");\n\n  MT(\"nonmatching\",\n     \"[tag&bracket <][tag top][tag&bracket >]\",\n     \"  [tag&bracket <][tag inner][tag&bracket />]\",\n     \"  [tag&bracket </][tag&error tip][tag&bracket&error >]\");\n\n  MT(\"doctype\",\n     \"[meta <!doctype foobar>]\",\n     \"[tag&bracket <][tag top][tag&bracket />]\");\n\n  MT(\"cdata\",\n     \"[tag&bracket <][tag top][tag&bracket >]\",\n     \"  [atom <![CDATA[foo]\",\n     \"[atom barbazguh]]]]>]\",\n     \"[tag&bracket </][tag top][tag&bracket >]\");\n\n  // HTML tests\n  mode = CodeMirror.getMode({indentUnit: 2}, \"text/html\");\n\n  MT(\"selfclose\",\n     \"[tag&bracket <][tag html][tag&bracket >]\",\n     \"  [tag&bracket <][tag link] [attribute rel]=[string stylesheet] [attribute href]=[string \\\"/foobar\\\"][tag&bracket >]\",\n     \"[tag&bracket </][tag html][tag&bracket >]\");\n\n  MT(\"list\",\n     \"[tag&bracket <][tag ol][tag&bracket >]\",\n     \"  [tag&bracket <][tag li][tag&bracket >]one\",\n     \"  [tag&bracket <][tag li][tag&bracket >]two\",\n     \"[tag&bracket </][tag ol][tag&bracket >]\");\n\n  MT(\"valueless\",\n     \"[tag&bracket <][tag input] [attribute type]=[string checkbox] [attribute checked][tag&bracket />]\");\n\n  MT(\"pThenArticle\",\n     \"[tag&bracket <][tag p][tag&bracket >]\",\n     \"  foo\",\n     \"[tag&bracket <][tag article][tag&bracket >]bar\");\n\n})();\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/xml/xml.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"xml\", function(config, parserConfig) {\n  var indentUnit = config.indentUnit;\n  var multilineTagIndentFactor = parserConfig.multilineTagIndentFactor || 1;\n  var multilineTagIndentPastTag = parserConfig.multilineTagIndentPastTag;\n  if (multilineTagIndentPastTag == null) multilineTagIndentPastTag = true;\n\n  var Kludges = parserConfig.htmlMode ? {\n    autoSelfClosers: {'area': true, 'base': true, 'br': true, 'col': true, 'command': true,\n                      'embed': true, 'frame': true, 'hr': true, 'img': true, 'input': true,\n                      'keygen': true, 'link': true, 'meta': true, 'param': true, 'source': true,\n                      'track': true, 'wbr': true, 'menuitem': true},\n    implicitlyClosed: {'dd': true, 'li': true, 'optgroup': true, 'option': true, 'p': true,\n                       'rp': true, 'rt': true, 'tbody': true, 'td': true, 'tfoot': true,\n                       'th': true, 'tr': true},\n    contextGrabbers: {\n      'dd': {'dd': true, 'dt': true},\n      'dt': {'dd': true, 'dt': true},\n      'li': {'li': true},\n      'option': {'option': true, 'optgroup': true},\n      'optgroup': {'optgroup': true},\n      'p': {'address': true, 'article': true, 'aside': true, 'blockquote': true, 'dir': true,\n            'div': true, 'dl': true, 'fieldset': true, 'footer': true, 'form': true,\n            'h1': true, 'h2': true, 'h3': true, 'h4': true, 'h5': true, 'h6': true,\n            'header': true, 'hgroup': true, 'hr': true, 'menu': true, 'nav': true, 'ol': true,\n            'p': true, 'pre': true, 'section': true, 'table': true, 'ul': true},\n      'rp': {'rp': true, 'rt': true},\n      'rt': {'rp': true, 'rt': true},\n      'tbody': {'tbody': true, 'tfoot': true},\n      'td': {'td': true, 'th': true},\n      'tfoot': {'tbody': true},\n      'th': {'td': true, 'th': true},\n      'thead': {'tbody': true, 'tfoot': true},\n      'tr': {'tr': true}\n    },\n    doNotIndent: {\"pre\": true},\n    allowUnquoted: true,\n    allowMissing: true,\n    caseFold: true\n  } : {\n    autoSelfClosers: {},\n    implicitlyClosed: {},\n    contextGrabbers: {},\n    doNotIndent: {},\n    allowUnquoted: false,\n    allowMissing: false,\n    caseFold: false\n  };\n  var alignCDATA = parserConfig.alignCDATA;\n\n  // Return variables for tokenizers\n  var type, setStyle;\n\n  function inText(stream, state) {\n    function chain(parser) {\n      state.tokenize = parser;\n      return parser(stream, state);\n    }\n\n    var ch = stream.next();\n    if (ch == \"<\") {\n      if (stream.eat(\"!\")) {\n        if (stream.eat(\"[\")) {\n          if (stream.match(\"CDATA[\")) return chain(inBlock(\"atom\", \"]]>\"));\n          else return null;\n        } else if (stream.match(\"--\")) {\n          return chain(inBlock(\"comment\", \"-->\"));\n        } else if (stream.match(\"DOCTYPE\", true, true)) {\n          stream.eatWhile(/[\\w\\._\\-]/);\n          return chain(doctype(1));\n        } else {\n          return null;\n        }\n      } else if (stream.eat(\"?\")) {\n        stream.eatWhile(/[\\w\\._\\-]/);\n        state.tokenize = inBlock(\"meta\", \"?>\");\n        return \"meta\";\n      } else {\n        type = stream.eat(\"/\") ? \"closeTag\" : \"openTag\";\n        state.tokenize = inTag;\n        return \"tag bracket\";\n      }\n    } else if (ch == \"&\") {\n      var ok;\n      if (stream.eat(\"#\")) {\n        if (stream.eat(\"x\")) {\n          ok = stream.eatWhile(/[a-fA-F\\d]/) && stream.eat(\";\");\n        } else {\n          ok = stream.eatWhile(/[\\d]/) && stream.eat(\";\");\n        }\n      } else {\n        ok = stream.eatWhile(/[\\w\\.\\-:]/) && stream.eat(\";\");\n      }\n      return ok ? \"atom\" : \"error\";\n    } else {\n      stream.eatWhile(/[^&<]/);\n      return null;\n    }\n  }\n\n  function inTag(stream, state) {\n    var ch = stream.next();\n    if (ch == \">\" || (ch == \"/\" && stream.eat(\">\"))) {\n      state.tokenize = inText;\n      type = ch == \">\" ? \"endTag\" : \"selfcloseTag\";\n      return \"tag bracket\";\n    } else if (ch == \"=\") {\n      type = \"equals\";\n      return null;\n    } else if (ch == \"<\") {\n      state.tokenize = inText;\n      state.state = baseState;\n      state.tagName = state.tagStart = null;\n      var next = state.tokenize(stream, state);\n      return next ? next + \" tag error\" : \"tag error\";\n    } else if (/[\\'\\\"]/.test(ch)) {\n      state.tokenize = inAttribute(ch);\n      state.stringStartCol = stream.column();\n      return state.tokenize(stream, state);\n    } else {\n      stream.match(/^[^\\s\\u00a0=<>\\\"\\']*[^\\s\\u00a0=<>\\\"\\'\\/]/);\n      return \"word\";\n    }\n  }\n\n  function inAttribute(quote) {\n    var closure = function(stream, state) {\n      while (!stream.eol()) {\n        if (stream.next() == quote) {\n          state.tokenize = inTag;\n          break;\n        }\n      }\n      return \"string\";\n    };\n    closure.isInAttribute = true;\n    return closure;\n  }\n\n  function inBlock(style, terminator) {\n    return function(stream, state) {\n      while (!stream.eol()) {\n        if (stream.match(terminator)) {\n          state.tokenize = inText;\n          break;\n        }\n        stream.next();\n      }\n      return style;\n    };\n  }\n  function doctype(depth) {\n    return function(stream, state) {\n      var ch;\n      while ((ch = stream.next()) != null) {\n        if (ch == \"<\") {\n          state.tokenize = doctype(depth + 1);\n          return state.tokenize(stream, state);\n        } else if (ch == \">\") {\n          if (depth == 1) {\n            state.tokenize = inText;\n            break;\n          } else {\n            state.tokenize = doctype(depth - 1);\n            return state.tokenize(stream, state);\n          }\n        }\n      }\n      return \"meta\";\n    };\n  }\n\n  function Context(state, tagName, startOfLine) {\n    this.prev = state.context;\n    this.tagName = tagName;\n    this.indent = state.indented;\n    this.startOfLine = startOfLine;\n    if (Kludges.doNotIndent.hasOwnProperty(tagName) || (state.context && state.context.noIndent))\n      this.noIndent = true;\n  }\n  function popContext(state) {\n    if (state.context) state.context = state.context.prev;\n  }\n  function maybePopContext(state, nextTagName) {\n    var parentTagName;\n    while (true) {\n      if (!state.context) {\n        return;\n      }\n      parentTagName = state.context.tagName;\n      if (!Kludges.contextGrabbers.hasOwnProperty(parentTagName) ||\n          !Kludges.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) {\n        return;\n      }\n      popContext(state);\n    }\n  }\n\n  function baseState(type, stream, state) {\n    if (type == \"openTag\") {\n      state.tagStart = stream.column();\n      return tagNameState;\n    } else if (type == \"closeTag\") {\n      return closeTagNameState;\n    } else {\n      return baseState;\n    }\n  }\n  function tagNameState(type, stream, state) {\n    if (type == \"word\") {\n      state.tagName = stream.current();\n      setStyle = \"tag\";\n      return attrState;\n    } else {\n      setStyle = \"error\";\n      return tagNameState;\n    }\n  }\n  function closeTagNameState(type, stream, state) {\n    if (type == \"word\") {\n      var tagName = stream.current();\n      if (state.context && state.context.tagName != tagName &&\n          Kludges.implicitlyClosed.hasOwnProperty(state.context.tagName))\n        popContext(state);\n      if (state.context && state.context.tagName == tagName) {\n        setStyle = \"tag\";\n        return closeState;\n      } else {\n        setStyle = \"tag error\";\n        return closeStateErr;\n      }\n    } else {\n      setStyle = \"error\";\n      return closeStateErr;\n    }\n  }\n\n  function closeState(type, _stream, state) {\n    if (type != \"endTag\") {\n      setStyle = \"error\";\n      return closeState;\n    }\n    popContext(state);\n    return baseState;\n  }\n  function closeStateErr(type, stream, state) {\n    setStyle = \"error\";\n    return closeState(type, stream, state);\n  }\n\n  function attrState(type, _stream, state) {\n    if (type == \"word\") {\n      setStyle = \"attribute\";\n      return attrEqState;\n    } else if (type == \"endTag\" || type == \"selfcloseTag\") {\n      var tagName = state.tagName, tagStart = state.tagStart;\n      state.tagName = state.tagStart = null;\n      if (type == \"selfcloseTag\" ||\n          Kludges.autoSelfClosers.hasOwnProperty(tagName)) {\n        maybePopContext(state, tagName);\n      } else {\n        maybePopContext(state, tagName);\n        state.context = new Context(state, tagName, tagStart == state.indented);\n      }\n      return baseState;\n    }\n    setStyle = \"error\";\n    return attrState;\n  }\n  function attrEqState(type, stream, state) {\n    if (type == \"equals\") return attrValueState;\n    if (!Kludges.allowMissing) setStyle = \"error\";\n    return attrState(type, stream, state);\n  }\n  function attrValueState(type, stream, state) {\n    if (type == \"string\") return attrContinuedState;\n    if (type == \"word\" && Kludges.allowUnquoted) {setStyle = \"string\"; return attrState;}\n    setStyle = \"error\";\n    return attrState(type, stream, state);\n  }\n  function attrContinuedState(type, stream, state) {\n    if (type == \"string\") return attrContinuedState;\n    return attrState(type, stream, state);\n  }\n\n  return {\n    startState: function() {\n      return {tokenize: inText,\n              state: baseState,\n              indented: 0,\n              tagName: null, tagStart: null,\n              context: null};\n    },\n\n    token: function(stream, state) {\n      if (!state.tagName && stream.sol())\n        state.indented = stream.indentation();\n\n      if (stream.eatSpace()) return null;\n      type = null;\n      var style = state.tokenize(stream, state);\n      if ((style || type) && style != \"comment\") {\n        setStyle = null;\n        state.state = state.state(type || style, stream, state);\n        if (setStyle)\n          style = setStyle == \"error\" ? style + \" error\" : setStyle;\n      }\n      return style;\n    },\n\n    indent: function(state, textAfter, fullLine) {\n      var context = state.context;\n      // Indent multi-line strings (e.g. css).\n      if (state.tokenize.isInAttribute) {\n        if (state.tagStart == state.indented)\n          return state.stringStartCol + 1;\n        else\n          return state.indented + indentUnit;\n      }\n      if (context && context.noIndent) return CodeMirror.Pass;\n      if (state.tokenize != inTag && state.tokenize != inText)\n        return fullLine ? fullLine.match(/^(\\s*)/)[0].length : 0;\n      // Indent the starts of attribute names.\n      if (state.tagName) {\n        if (multilineTagIndentPastTag)\n          return state.tagStart + state.tagName.length + 2;\n        else\n          return state.tagStart + indentUnit * multilineTagIndentFactor;\n      }\n      if (alignCDATA && /<!\\[CDATA\\[/.test(textAfter)) return 0;\n      var tagAfter = textAfter && /^<(\\/)?([\\w_:\\.-]*)/.exec(textAfter);\n      if (tagAfter && tagAfter[1]) { // Closing tag spotted\n        while (context) {\n          if (context.tagName == tagAfter[2]) {\n            context = context.prev;\n            break;\n          } else if (Kludges.implicitlyClosed.hasOwnProperty(context.tagName)) {\n            context = context.prev;\n          } else {\n            break;\n          }\n        }\n      } else if (tagAfter) { // Opening tag spotted\n        while (context) {\n          var grabbers = Kludges.contextGrabbers[context.tagName];\n          if (grabbers && grabbers.hasOwnProperty(tagAfter[2]))\n            context = context.prev;\n          else\n            break;\n        }\n      }\n      while (context && !context.startOfLine)\n        context = context.prev;\n      if (context) return context.indent + indentUnit;\n      else return 0;\n    },\n\n    electricInput: /<\\/[\\s\\w:]+>$/,\n    blockCommentStart: \"<!--\",\n    blockCommentEnd: \"-->\",\n\n    configuration: parserConfig.htmlMode ? \"html\" : \"xml\",\n    helperType: parserConfig.htmlMode ? \"html\" : \"xml\"\n  };\n});\n\nCodeMirror.defineMIME(\"text/xml\", \"xml\");\nCodeMirror.defineMIME(\"application/xml\", \"xml\");\nif (!CodeMirror.mimeModes.hasOwnProperty(\"text/html\"))\n  CodeMirror.defineMIME(\"text/html\", {name: \"xml\", htmlMode: true});\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/xquery/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: XQuery mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<link rel=\"stylesheet\" href=\"../../theme/xq-dark.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"xquery.js\"></script>\n<style type=\"text/css\">\n\t.CodeMirror {\n\t  border-top: 1px solid black; border-bottom: 1px solid black;\n\t  height:400px;\n\t}\n    </style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">XQuery</a>\n  </ul>\n</div>\n\n<article>\n<h2>XQuery mode</h2>\n \n \n<div class=\"cm-s-default\"> \n\t<textarea id=\"code\" name=\"code\"> \nxquery version &quot;1.0-ml&quot;;\n(: this is\n : a \n   \"comment\" :)\nlet $let := &lt;x attr=&quot;value&quot;&gt;&quot;test&quot;&lt;func&gt;function() $var {function()} {$var}&lt;/func&gt;&lt;/x&gt;\nlet $joe:=1\nreturn element element {\n\tattribute attribute { 1 },\n\telement test { &#39;a&#39; }, \n\tattribute foo { &quot;bar&quot; },\n\tfn:doc()[ foo/@bar eq $let ],\n\t//x }    \n \n(: a more 'evil' test :)\n(: Modified Blakeley example (: with nested comment :) ... :)\ndeclare private function local:declare() {()};\ndeclare private function local:private() {()};\ndeclare private function local:function() {()};\ndeclare private function local:local() {()};\nlet $let := &lt;let&gt;let $let := &quot;let&quot;&lt;/let&gt;\nreturn element element {\n\tattribute attribute { try { xdmp:version() } catch($e) { xdmp:log($e) } },\n\tattribute fn:doc { &quot;bar&quot; castable as xs:string },\n\telement text { text { &quot;text&quot; } },\n\tfn:doc()[ child::eq/(@bar | attribute::attribute) eq $let ],\n\t//fn:doc\n}\n\n\n\nxquery version &quot;1.0-ml&quot;;\n\n(: Copyright 2006-2010 Mark Logic Corporation. :)\n\n(:\n : Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);\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 &quot;AS IS&quot; 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\nmodule namespace json = &quot;http://marklogic.com/json&quot;;\ndeclare default function namespace &quot;http://www.w3.org/2005/xpath-functions&quot;;\n\n(: Need to backslash escape any double quotes, backslashes, and newlines :)\ndeclare function json:escape($s as xs:string) as xs:string {\n  let $s := replace($s, &quot;\\\\&quot;, &quot;\\\\\\\\&quot;)\n  let $s := replace($s, &quot;&quot;&quot;&quot;, &quot;\\\\&quot;&quot;&quot;)\n  let $s := replace($s, codepoints-to-string((13, 10)), &quot;\\\\n&quot;)\n  let $s := replace($s, codepoints-to-string(13), &quot;\\\\n&quot;)\n  let $s := replace($s, codepoints-to-string(10), &quot;\\\\n&quot;)\n  return $s\n};\n\ndeclare function json:atomize($x as element()) as xs:string {\n  if (count($x/node()) = 0) then 'null'\n  else if ($x/@type = &quot;number&quot;) then\n    let $castable := $x castable as xs:float or\n                     $x castable as xs:double or\n                     $x castable as xs:decimal\n    return\n    if ($castable) then xs:string($x)\n    else error(concat(&quot;Not a number: &quot;, xdmp:describe($x)))\n  else if ($x/@type = &quot;boolean&quot;) then\n    let $castable := $x castable as xs:boolean\n    return\n    if ($castable) then xs:string(xs:boolean($x))\n    else error(concat(&quot;Not a boolean: &quot;, xdmp:describe($x)))\n  else concat('&quot;', json:escape($x), '&quot;')\n};\n\n(: Print the thing that comes after the colon :)\ndeclare function json:print-value($x as element()) as xs:string {\n  if (count($x/*) = 0) then\n    json:atomize($x)\n  else if ($x/@quote = &quot;true&quot;) then\n    concat('&quot;', json:escape(xdmp:quote($x/node())), '&quot;')\n  else\n    string-join(('{',\n      string-join(for $i in $x/* return json:print-name-value($i), &quot;,&quot;),\n    '}'), &quot;&quot;)\n};\n\n(: Print the name and value both :)\ndeclare function json:print-name-value($x as element()) as xs:string? {\n  let $name := name($x)\n  let $first-in-array :=\n    count($x/preceding-sibling::*[name(.) = $name]) = 0 and\n    (count($x/following-sibling::*[name(.) = $name]) &gt; 0 or $x/@array = &quot;true&quot;)\n  let $later-in-array := count($x/preceding-sibling::*[name(.) = $name]) &gt; 0\n  return\n\n  if ($later-in-array) then\n    ()  (: I was handled previously :)\n  else if ($first-in-array) then\n    string-join(('&quot;', json:escape($name), '&quot;:[',\n      string-join((for $i in ($x, $x/following-sibling::*[name(.) = $name]) return json:print-value($i)), &quot;,&quot;),\n    ']'), &quot;&quot;)\n   else\n     string-join(('&quot;', json:escape($name), '&quot;:', json:print-value($x)), &quot;&quot;)\n};\n\n(:~\n  Transforms an XML element into a JSON string representation.  See http://json.org.\n  &lt;p/&gt;\n  Sample usage:\n  &lt;pre&gt;\n    xquery version &quot;1.0-ml&quot;;\n    import module namespace json=&quot;http://marklogic.com/json&quot; at &quot;json.xqy&quot;;\n    json:serialize(&amp;lt;foo&amp;gt;&amp;lt;bar&amp;gt;kid&amp;lt;/bar&amp;gt;&amp;lt;/foo&amp;gt;)\n  &lt;/pre&gt;\n  Sample transformations:\n  &lt;pre&gt;\n  &amp;lt;e/&amp;gt; becomes {&quot;e&quot;:null}\n  &amp;lt;e&amp;gt;text&amp;lt;/e&amp;gt; becomes {&quot;e&quot;:&quot;text&quot;}\n  &amp;lt;e&amp;gt;quote &quot; escaping&amp;lt;/e&amp;gt; becomes {&quot;e&quot;:&quot;quote \\&quot; escaping&quot;}\n  &amp;lt;e&amp;gt;backslash \\ escaping&amp;lt;/e&amp;gt; becomes {&quot;e&quot;:&quot;backslash \\\\ escaping&quot;}\n  &amp;lt;e&amp;gt;&amp;lt;a&amp;gt;text1&amp;lt;/a&amp;gt;&amp;lt;b&amp;gt;text2&amp;lt;/b&amp;gt;&amp;lt;/e&amp;gt; becomes {&quot;e&quot;:{&quot;a&quot;:&quot;text1&quot;,&quot;b&quot;:&quot;text2&quot;}}\n  &amp;lt;e&amp;gt;&amp;lt;a&amp;gt;text1&amp;lt;/a&amp;gt;&amp;lt;a&amp;gt;text2&amp;lt;/a&amp;gt;&amp;lt;/e&amp;gt; becomes {&quot;e&quot;:{&quot;a&quot;:[&quot;text1&quot;,&quot;text2&quot;]}}\n  &amp;lt;e&amp;gt;&amp;lt;a array=&quot;true&quot;&amp;gt;text1&amp;lt;/a&amp;gt;&amp;lt;/e&amp;gt; becomes {&quot;e&quot;:{&quot;a&quot;:[&quot;text1&quot;]}}\n  &amp;lt;e&amp;gt;&amp;lt;a type=&quot;boolean&quot;&amp;gt;false&amp;lt;/a&amp;gt;&amp;lt;/e&amp;gt; becomes {&quot;e&quot;:{&quot;a&quot;:false}}\n  &amp;lt;e&amp;gt;&amp;lt;a type=&quot;number&quot;&amp;gt;123.5&amp;lt;/a&amp;gt;&amp;lt;/e&amp;gt; becomes {&quot;e&quot;:{&quot;a&quot;:123.5}}\n  &amp;lt;e quote=&quot;true&quot;&amp;gt;&amp;lt;div attrib=&quot;value&quot;/&amp;gt;&amp;lt;/e&amp;gt; becomes {&quot;e&quot;:&quot;&amp;lt;div attrib=\\&quot;value\\&quot;/&amp;gt;&quot;}\n  &lt;/pre&gt;\n  &lt;p/&gt;\n  Namespace URIs are ignored.  Namespace prefixes are included in the JSON name.\n  &lt;p/&gt;\n  Attributes are ignored, except for the special attribute @array=&quot;true&quot; that\n  indicates the JSON serialization should write the node, even if single, as an\n  array, and the attribute @type that can be set to &quot;boolean&quot; or &quot;number&quot; to\n  dictate the value should be written as that type (unquoted).  There's also\n  an @quote attribute that when set to true writes the inner content as text\n  rather than as structured JSON, useful for sending some XHTML over the\n  wire.\n  &lt;p/&gt;\n  Text nodes within mixed content are ignored.\n\n  @param $x Element node to convert\n  @return String holding JSON serialized representation of $x\n\n  @author Jason Hunter\n  @version 1.0.1\n  \n  Ported to xquery 1.0-ml; double escaped backslashes in json:escape\n:)\ndeclare function json:serialize($x as element())  as xs:string {\n  string-join(('{', json:print-name-value($x), '}'), &quot;&quot;)\n};\n  </textarea> \n</div> \n \n    <script> \n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        lineNumbers: true,\n        matchBrackets: true,\n        theme: \"xq-dark\"\n      });\n    </script> \n \n    <p><strong>MIME types defined:</strong> <code>application/xquery</code>.</p> \n \n    <p>Development of the CodeMirror XQuery mode was sponsored by \n      <a href=\"http://marklogic.com\">MarkLogic</a> and developed by \n      <a href=\"https://twitter.com/mbrevoort\">Mike Brevoort</a>.\n    </p>\n \n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/xquery/test.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n// Don't take these too seriously -- the expected results appear to be\n// based on the results of actual runs without any serious manual\n// verification. If a change you made causes them to fail, the test is\n// as likely to wrong as the code.\n\n(function() {\n  var mode = CodeMirror.getMode({tabSize: 4}, \"xquery\");\n  function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); }\n\n  MT(\"eviltest\",\n     \"[keyword xquery] [keyword version] [variable &quot;1][keyword .][atom 0][keyword -][variable ml&quot;][def&variable ;]      [comment (: this is       : a          \\\"comment\\\" :)]\",\n     \"      [keyword let] [variable $let] [keyword :=] [variable &lt;x] [variable attr][keyword =][variable &quot;value&quot;&gt;&quot;test&quot;&lt;func&gt][def&variable ;function]() [variable $var] {[keyword function]()} {[variable $var]}[variable &lt;][keyword /][variable func&gt;&lt;][keyword /][variable x&gt;]\",\n     \"      [keyword let] [variable $joe][keyword :=][atom 1]\",\n     \"      [keyword return] [keyword element] [variable element] {\",\n     \"          [keyword attribute] [variable attribute] { [atom 1] },\",\n     \"          [keyword element] [variable test] { [variable &#39;a&#39;] },           [keyword attribute] [variable foo] { [variable &quot;bar&quot;] },\",\n     \"          [def&variable fn:doc]()[[ [variable foo][keyword /][variable @bar] [keyword eq] [variable $let] ]],\",\n     \"          [keyword //][variable x] }                 [comment (: a more 'evil' test :)]\",\n     \"      [comment (: Modified Blakeley example (: with nested comment :) ... :)]\",\n     \"      [keyword declare] [keyword private] [keyword function] [def&variable local:declare]() {()}[variable ;]\",\n     \"      [keyword declare] [keyword private] [keyword function] [def&variable local:private]() {()}[variable ;]\",\n     \"      [keyword declare] [keyword private] [keyword function] [def&variable local:function]() {()}[variable ;]\",\n     \"      [keyword declare] [keyword private] [keyword function] [def&variable local:local]() {()}[variable ;]\",\n     \"      [keyword let] [variable $let] [keyword :=] [variable &lt;let&gt;let] [variable $let] [keyword :=] [variable &quot;let&quot;&lt;][keyword /let][variable &gt;]\",\n     \"      [keyword return] [keyword element] [variable element] {\",\n     \"          [keyword attribute] [variable attribute] { [keyword try] { [def&variable xdmp:version]() } [keyword catch]([variable $e]) { [def&variable xdmp:log]([variable $e]) } },\",\n     \"          [keyword attribute] [variable fn:doc] { [variable &quot;bar&quot;] [variable castable] [keyword as] [atom xs:string] },\",\n     \"          [keyword element] [variable text] { [keyword text] { [variable &quot;text&quot;] } },\",\n     \"          [def&variable fn:doc]()[[ [qualifier child::][variable eq][keyword /]([variable @bar] [keyword |] [qualifier attribute::][variable attribute]) [keyword eq] [variable $let] ]],\",\n     \"          [keyword //][variable fn:doc]\",\n     \"      }\");\n\n  MT(\"testEmptySequenceKeyword\",\n     \"[string \\\"foo\\\"] [keyword instance] [keyword of] [keyword empty-sequence]()\");\n\n  MT(\"testMultiAttr\",\n     \"[tag <p ][attribute a1]=[string \\\"foo\\\"] [attribute a2]=[string \\\"bar\\\"][tag >][variable hello] [variable world][tag </p>]\");\n\n  MT(\"test namespaced variable\",\n     \"[keyword declare] [keyword namespace] [variable e] [keyword =] [string \\\"http://example.com/ANamespace\\\"][variable ;declare] [keyword variable] [variable $e:exampleComThisVarIsNotRecognized] [keyword as] [keyword element]([keyword *]) [variable external;]\");\n\n  MT(\"test EQName variable\",\n     \"[keyword declare] [keyword variable] [variable $\\\"http://www.example.com/ns/my\\\":var] [keyword :=] [atom 12][variable ;]\",\n     \"[tag <out>]{[variable $\\\"http://www.example.com/ns/my\\\":var]}[tag </out>]\");\n\n  MT(\"test EQName function\",\n     \"[keyword declare] [keyword function] [def&variable \\\"http://www.example.com/ns/my\\\":fn] ([variable $a] [keyword as] [atom xs:integer]) [keyword as] [atom xs:integer] {\",\n     \"   [variable $a] [keyword +] [atom 2]\",\n     \"}[variable ;]\",\n     \"[tag <out>]{[def&variable \\\"http://www.example.com/ns/my\\\":fn]([atom 12])}[tag </out>]\");\n\n  MT(\"test EQName function with single quotes\",\n     \"[keyword declare] [keyword function] [def&variable 'http://www.example.com/ns/my':fn] ([variable $a] [keyword as] [atom xs:integer]) [keyword as] [atom xs:integer] {\",\n     \"   [variable $a] [keyword +] [atom 2]\",\n     \"}[variable ;]\",\n     \"[tag <out>]{[def&variable 'http://www.example.com/ns/my':fn]([atom 12])}[tag </out>]\");\n\n  MT(\"testProcessingInstructions\",\n     \"[def&variable data]([comment&meta <?target content?>]) [keyword instance] [keyword of] [atom xs:string]\");\n\n  MT(\"testQuoteEscapeDouble\",\n     \"[keyword let] [variable $rootfolder] [keyword :=] [string \\\"c:\\\\builds\\\\winnt\\\\HEAD\\\\qa\\\\scripts\\\\\\\"]\",\n     \"[keyword let] [variable $keysfolder] [keyword :=] [def&variable concat]([variable $rootfolder], [string \\\"keys\\\\\\\"])\");\n})();\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/xquery/xquery.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"xquery\", function() {\n\n  // The keywords object is set to the result of this self executing\n  // function. Each keyword is a property of the keywords object whose\n  // value is {type: atype, style: astyle}\n  var keywords = function(){\n    // conveinence functions used to build keywords object\n    function kw(type) {return {type: type, style: \"keyword\"};}\n    var A = kw(\"keyword a\")\n      , B = kw(\"keyword b\")\n      , C = kw(\"keyword c\")\n      , operator = kw(\"operator\")\n      , atom = {type: \"atom\", style: \"atom\"}\n      , punctuation = {type: \"punctuation\", style: null}\n      , qualifier = {type: \"axis_specifier\", style: \"qualifier\"};\n\n    // kwObj is what is return from this function at the end\n    var kwObj = {\n      'if': A, 'switch': A, 'while': A, 'for': A,\n      'else': B, 'then': B, 'try': B, 'finally': B, 'catch': B,\n      'element': C, 'attribute': C, 'let': C, 'implements': C, 'import': C, 'module': C, 'namespace': C,\n      'return': C, 'super': C, 'this': C, 'throws': C, 'where': C, 'private': C,\n      ',': punctuation,\n      'null': atom, 'fn:false()': atom, 'fn:true()': atom\n    };\n\n    // a list of 'basic' keywords. For each add a property to kwObj with the value of\n    // {type: basic[i], style: \"keyword\"} e.g. 'after' --> {type: \"after\", style: \"keyword\"}\n    var basic = ['after','ancestor','ancestor-or-self','and','as','ascending','assert','attribute','before',\n    'by','case','cast','child','comment','declare','default','define','descendant','descendant-or-self',\n    'descending','document','document-node','element','else','eq','every','except','external','following',\n    'following-sibling','follows','for','function','if','import','in','instance','intersect','item',\n    'let','module','namespace','node','node','of','only','or','order','parent','precedes','preceding',\n    'preceding-sibling','processing-instruction','ref','return','returns','satisfies','schema','schema-element',\n    'self','some','sortby','stable','text','then','to','treat','typeswitch','union','variable','version','where',\n    'xquery', 'empty-sequence'];\n    for(var i=0, l=basic.length; i < l; i++) { kwObj[basic[i]] = kw(basic[i]);};\n\n    // a list of types. For each add a property to kwObj with the value of\n    // {type: \"atom\", style: \"atom\"}\n    var types = ['xs:string', 'xs:float', 'xs:decimal', 'xs:double', 'xs:integer', 'xs:boolean', 'xs:date', 'xs:dateTime',\n    'xs:time', 'xs:duration', 'xs:dayTimeDuration', 'xs:time', 'xs:yearMonthDuration', 'numeric', 'xs:hexBinary',\n    'xs:base64Binary', 'xs:anyURI', 'xs:QName', 'xs:byte','xs:boolean','xs:anyURI','xf:yearMonthDuration'];\n    for(var i=0, l=types.length; i < l; i++) { kwObj[types[i]] = atom;};\n\n    // each operator will add a property to kwObj with value of {type: \"operator\", style: \"keyword\"}\n    var operators = ['eq', 'ne', 'lt', 'le', 'gt', 'ge', ':=', '=', '>', '>=', '<', '<=', '.', '|', '?', 'and', 'or', 'div', 'idiv', 'mod', '*', '/', '+', '-'];\n    for(var i=0, l=operators.length; i < l; i++) { kwObj[operators[i]] = operator;};\n\n    // each axis_specifiers will add a property to kwObj with value of {type: \"axis_specifier\", style: \"qualifier\"}\n    var axis_specifiers = [\"self::\", \"attribute::\", \"child::\", \"descendant::\", \"descendant-or-self::\", \"parent::\",\n    \"ancestor::\", \"ancestor-or-self::\", \"following::\", \"preceding::\", \"following-sibling::\", \"preceding-sibling::\"];\n    for(var i=0, l=axis_specifiers.length; i < l; i++) { kwObj[axis_specifiers[i]] = qualifier; };\n\n    return kwObj;\n  }();\n\n  // Used as scratch variables to communicate multiple values without\n  // consing up tons of objects.\n  var type, content;\n\n  function ret(tp, style, cont) {\n    type = tp; content = cont;\n    return style;\n  }\n\n  function chain(stream, state, f) {\n    state.tokenize = f;\n    return f(stream, state);\n  }\n\n  // the primary mode tokenizer\n  function tokenBase(stream, state) {\n    var ch = stream.next(),\n        mightBeFunction = false,\n        isEQName = isEQNameAhead(stream);\n\n    // an XML tag (if not in some sub, chained tokenizer)\n    if (ch == \"<\") {\n      if(stream.match(\"!--\", true))\n        return chain(stream, state, tokenXMLComment);\n\n      if(stream.match(\"![CDATA\", false)) {\n        state.tokenize = tokenCDATA;\n        return ret(\"tag\", \"tag\");\n      }\n\n      if(stream.match(\"?\", false)) {\n        return chain(stream, state, tokenPreProcessing);\n      }\n\n      var isclose = stream.eat(\"/\");\n      stream.eatSpace();\n      var tagName = \"\", c;\n      while ((c = stream.eat(/[^\\s\\u00a0=<>\\\"\\'\\/?]/))) tagName += c;\n\n      return chain(stream, state, tokenTag(tagName, isclose));\n    }\n    // start code block\n    else if(ch == \"{\") {\n      pushStateStack(state,{ type: \"codeblock\"});\n      return ret(\"\", null);\n    }\n    // end code block\n    else if(ch == \"}\") {\n      popStateStack(state);\n      return ret(\"\", null);\n    }\n    // if we're in an XML block\n    else if(isInXmlBlock(state)) {\n      if(ch == \">\")\n        return ret(\"tag\", \"tag\");\n      else if(ch == \"/\" && stream.eat(\">\")) {\n        popStateStack(state);\n        return ret(\"tag\", \"tag\");\n      }\n      else\n        return ret(\"word\", \"variable\");\n    }\n    // if a number\n    else if (/\\d/.test(ch)) {\n      stream.match(/^\\d*(?:\\.\\d*)?(?:E[+\\-]?\\d+)?/);\n      return ret(\"number\", \"atom\");\n    }\n    // comment start\n    else if (ch === \"(\" && stream.eat(\":\")) {\n      pushStateStack(state, { type: \"comment\"});\n      return chain(stream, state, tokenComment);\n    }\n    // quoted string\n    else if (  !isEQName && (ch === '\"' || ch === \"'\"))\n      return chain(stream, state, tokenString(ch));\n    // variable\n    else if(ch === \"$\") {\n      return chain(stream, state, tokenVariable);\n    }\n    // assignment\n    else if(ch ===\":\" && stream.eat(\"=\")) {\n      return ret(\"operator\", \"keyword\");\n    }\n    // open paren\n    else if(ch === \"(\") {\n      pushStateStack(state, { type: \"paren\"});\n      return ret(\"\", null);\n    }\n    // close paren\n    else if(ch === \")\") {\n      popStateStack(state);\n      return ret(\"\", null);\n    }\n    // open paren\n    else if(ch === \"[\") {\n      pushStateStack(state, { type: \"bracket\"});\n      return ret(\"\", null);\n    }\n    // close paren\n    else if(ch === \"]\") {\n      popStateStack(state);\n      return ret(\"\", null);\n    }\n    else {\n      var known = keywords.propertyIsEnumerable(ch) && keywords[ch];\n\n      // if there's a EQName ahead, consume the rest of the string portion, it's likely a function\n      if(isEQName && ch === '\\\"') while(stream.next() !== '\"'){}\n      if(isEQName && ch === '\\'') while(stream.next() !== '\\''){}\n\n      // gobble up a word if the character is not known\n      if(!known) stream.eatWhile(/[\\w\\$_-]/);\n\n      // gobble a colon in the case that is a lib func type call fn:doc\n      var foundColon = stream.eat(\":\");\n\n      // if there's not a second colon, gobble another word. Otherwise, it's probably an axis specifier\n      // which should get matched as a keyword\n      if(!stream.eat(\":\") && foundColon) {\n        stream.eatWhile(/[\\w\\$_-]/);\n      }\n      // if the next non whitespace character is an open paren, this is probably a function (if not a keyword of other sort)\n      if(stream.match(/^[ \\t]*\\(/, false)) {\n        mightBeFunction = true;\n      }\n      // is the word a keyword?\n      var word = stream.current();\n      known = keywords.propertyIsEnumerable(word) && keywords[word];\n\n      // if we think it's a function call but not yet known,\n      // set style to variable for now for lack of something better\n      if(mightBeFunction && !known) known = {type: \"function_call\", style: \"variable def\"};\n\n      // if the previous word was element, attribute, axis specifier, this word should be the name of that\n      if(isInXmlConstructor(state)) {\n        popStateStack(state);\n        return ret(\"word\", \"variable\", word);\n      }\n      // as previously checked, if the word is element,attribute, axis specifier, call it an \"xmlconstructor\" and\n      // push the stack so we know to look for it on the next word\n      if(word == \"element\" || word == \"attribute\" || known.type == \"axis_specifier\") pushStateStack(state, {type: \"xmlconstructor\"});\n\n      // if the word is known, return the details of that else just call this a generic 'word'\n      return known ? ret(known.type, known.style, word) :\n                     ret(\"word\", \"variable\", word);\n    }\n  }\n\n  // handle comments, including nested\n  function tokenComment(stream, state) {\n    var maybeEnd = false, maybeNested = false, nestedCount = 0, ch;\n    while (ch = stream.next()) {\n      if (ch == \")\" && maybeEnd) {\n        if(nestedCount > 0)\n          nestedCount--;\n        else {\n          popStateStack(state);\n          break;\n        }\n      }\n      else if(ch == \":\" && maybeNested) {\n        nestedCount++;\n      }\n      maybeEnd = (ch == \":\");\n      maybeNested = (ch == \"(\");\n    }\n\n    return ret(\"comment\", \"comment\");\n  }\n\n  // tokenizer for string literals\n  // optionally pass a tokenizer function to set state.tokenize back to when finished\n  function tokenString(quote, f) {\n    return function(stream, state) {\n      var ch;\n\n      if(isInString(state) && stream.current() == quote) {\n        popStateStack(state);\n        if(f) state.tokenize = f;\n        return ret(\"string\", \"string\");\n      }\n\n      pushStateStack(state, { type: \"string\", name: quote, tokenize: tokenString(quote, f) });\n\n      // if we're in a string and in an XML block, allow an embedded code block\n      if(stream.match(\"{\", false) && isInXmlAttributeBlock(state)) {\n        state.tokenize = tokenBase;\n        return ret(\"string\", \"string\");\n      }\n\n\n      while (ch = stream.next()) {\n        if (ch ==  quote) {\n          popStateStack(state);\n          if(f) state.tokenize = f;\n          break;\n        }\n        else {\n          // if we're in a string and in an XML block, allow an embedded code block in an attribute\n          if(stream.match(\"{\", false) && isInXmlAttributeBlock(state)) {\n            state.tokenize = tokenBase;\n            return ret(\"string\", \"string\");\n          }\n\n        }\n      }\n\n      return ret(\"string\", \"string\");\n    };\n  }\n\n  // tokenizer for variables\n  function tokenVariable(stream, state) {\n    var isVariableChar = /[\\w\\$_-]/;\n\n    // a variable may start with a quoted EQName so if the next character is quote, consume to the next quote\n    if(stream.eat(\"\\\"\")) {\n      while(stream.next() !== '\\\"'){};\n      stream.eat(\":\");\n    } else {\n      stream.eatWhile(isVariableChar);\n      if(!stream.match(\":=\", false)) stream.eat(\":\");\n    }\n    stream.eatWhile(isVariableChar);\n    state.tokenize = tokenBase;\n    return ret(\"variable\", \"variable\");\n  }\n\n  // tokenizer for XML tags\n  function tokenTag(name, isclose) {\n    return function(stream, state) {\n      stream.eatSpace();\n      if(isclose && stream.eat(\">\")) {\n        popStateStack(state);\n        state.tokenize = tokenBase;\n        return ret(\"tag\", \"tag\");\n      }\n      // self closing tag without attributes?\n      if(!stream.eat(\"/\"))\n        pushStateStack(state, { type: \"tag\", name: name, tokenize: tokenBase});\n      if(!stream.eat(\">\")) {\n        state.tokenize = tokenAttribute;\n        return ret(\"tag\", \"tag\");\n      }\n      else {\n        state.tokenize = tokenBase;\n      }\n      return ret(\"tag\", \"tag\");\n    };\n  }\n\n  // tokenizer for XML attributes\n  function tokenAttribute(stream, state) {\n    var ch = stream.next();\n\n    if(ch == \"/\" && stream.eat(\">\")) {\n      if(isInXmlAttributeBlock(state)) popStateStack(state);\n      if(isInXmlBlock(state)) popStateStack(state);\n      return ret(\"tag\", \"tag\");\n    }\n    if(ch == \">\") {\n      if(isInXmlAttributeBlock(state)) popStateStack(state);\n      return ret(\"tag\", \"tag\");\n    }\n    if(ch == \"=\")\n      return ret(\"\", null);\n    // quoted string\n    if (ch == '\"' || ch == \"'\")\n      return chain(stream, state, tokenString(ch, tokenAttribute));\n\n    if(!isInXmlAttributeBlock(state))\n      pushStateStack(state, { type: \"attribute\", tokenize: tokenAttribute});\n\n    stream.eat(/[a-zA-Z_:]/);\n    stream.eatWhile(/[-a-zA-Z0-9_:.]/);\n    stream.eatSpace();\n\n    // the case where the attribute has not value and the tag was closed\n    if(stream.match(\">\", false) || stream.match(\"/\", false)) {\n      popStateStack(state);\n      state.tokenize = tokenBase;\n    }\n\n    return ret(\"attribute\", \"attribute\");\n  }\n\n  // handle comments, including nested\n  function tokenXMLComment(stream, state) {\n    var ch;\n    while (ch = stream.next()) {\n      if (ch == \"-\" && stream.match(\"->\", true)) {\n        state.tokenize = tokenBase;\n        return ret(\"comment\", \"comment\");\n      }\n    }\n  }\n\n\n  // handle CDATA\n  function tokenCDATA(stream, state) {\n    var ch;\n    while (ch = stream.next()) {\n      if (ch == \"]\" && stream.match(\"]\", true)) {\n        state.tokenize = tokenBase;\n        return ret(\"comment\", \"comment\");\n      }\n    }\n  }\n\n  // handle preprocessing instructions\n  function tokenPreProcessing(stream, state) {\n    var ch;\n    while (ch = stream.next()) {\n      if (ch == \"?\" && stream.match(\">\", true)) {\n        state.tokenize = tokenBase;\n        return ret(\"comment\", \"comment meta\");\n      }\n    }\n  }\n\n\n  // functions to test the current context of the state\n  function isInXmlBlock(state) { return isIn(state, \"tag\"); }\n  function isInXmlAttributeBlock(state) { return isIn(state, \"attribute\"); }\n  function isInXmlConstructor(state) { return isIn(state, \"xmlconstructor\"); }\n  function isInString(state) { return isIn(state, \"string\"); }\n\n  function isEQNameAhead(stream) {\n    // assume we've already eaten a quote (\")\n    if(stream.current() === '\"')\n      return stream.match(/^[^\\\"]+\\\"\\:/, false);\n    else if(stream.current() === '\\'')\n      return stream.match(/^[^\\\"]+\\'\\:/, false);\n    else\n      return false;\n  }\n\n  function isIn(state, type) {\n    return (state.stack.length && state.stack[state.stack.length - 1].type == type);\n  }\n\n  function pushStateStack(state, newState) {\n    state.stack.push(newState);\n  }\n\n  function popStateStack(state) {\n    state.stack.pop();\n    var reinstateTokenize = state.stack.length && state.stack[state.stack.length-1].tokenize;\n    state.tokenize = reinstateTokenize || tokenBase;\n  }\n\n  // the interface for the mode API\n  return {\n    startState: function() {\n      return {\n        tokenize: tokenBase,\n        cc: [],\n        stack: []\n      };\n    },\n\n    token: function(stream, state) {\n      if (stream.eatSpace()) return null;\n      var style = state.tokenize(stream, state);\n      return style;\n    },\n\n    blockCommentStart: \"(:\",\n    blockCommentEnd: \":)\"\n\n  };\n\n});\n\nCodeMirror.defineMIME(\"application/xquery\", \"xquery\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/yaml/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: YAML mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"yaml.js\"></script>\n<style>.CodeMirror { border-top: 1px solid #ddd; border-bottom: 1px solid #ddd; }</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">YAML</a>\n  </ul>\n</div>\n\n<article>\n<h2>YAML mode</h2>\n<form><textarea id=\"code\" name=\"code\">\n--- # Favorite movies\n- Casablanca\n- North by Northwest\n- The Man Who Wasn't There\n--- # Shopping list\n[milk, pumpkin pie, eggs, juice]\n--- # Indented Blocks, common in YAML data files, use indentation and new lines to separate the key: value pairs\n  name: John Smith\n  age: 33\n--- # Inline Blocks, common in YAML data streams, use commas to separate the key: value pairs between braces\n{name: John Smith, age: 33}\n---\nreceipt:     Oz-Ware Purchase Invoice\ndate:        2007-08-06\ncustomer:\n    given:   Dorothy\n    family:  Gale\n\nitems:\n    - part_no:   A4786\n      descrip:   Water Bucket (Filled)\n      price:     1.47\n      quantity:  4\n\n    - part_no:   E1628\n      descrip:   High Heeled \"Ruby\" Slippers\n      size:       8\n      price:     100.27\n      quantity:  1\n\nbill-to:  &id001\n    street: |\n            123 Tornado Alley\n            Suite 16\n    city:   East Centerville\n    state:  KS\n\nship-to:  *id001\n\nspecialDelivery:  >\n    Follow the Yellow Brick\n    Road to the Emerald City.\n    Pay no attention to the\n    man behind the curtain.\n...\n</textarea></form>\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {});\n    </script>\n\n    <p><strong>MIME types defined:</strong> <code>text/x-yaml</code>.</p>\n\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/yaml/yaml.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"yaml\", function() {\n\n  var cons = ['true', 'false', 'on', 'off', 'yes', 'no'];\n  var keywordRegex = new RegExp(\"\\\\b((\"+cons.join(\")|(\")+\"))$\", 'i');\n\n  return {\n    token: function(stream, state) {\n      var ch = stream.peek();\n      var esc = state.escaped;\n      state.escaped = false;\n      /* comments */\n      if (ch == \"#\" && (stream.pos == 0 || /\\s/.test(stream.string.charAt(stream.pos - 1)))) {\n        stream.skipToEnd();\n        return \"comment\";\n      }\n\n      if (stream.match(/^('([^']|\\\\.)*'?|\"([^\"]|\\\\.)*\"?)/))\n        return \"string\";\n\n      if (state.literal && stream.indentation() > state.keyCol) {\n        stream.skipToEnd(); return \"string\";\n      } else if (state.literal) { state.literal = false; }\n      if (stream.sol()) {\n        state.keyCol = 0;\n        state.pair = false;\n        state.pairStart = false;\n        /* document start */\n        if(stream.match(/---/)) { return \"def\"; }\n        /* document end */\n        if (stream.match(/\\.\\.\\./)) { return \"def\"; }\n        /* array list item */\n        if (stream.match(/\\s*-\\s+/)) { return 'meta'; }\n      }\n      /* inline pairs/lists */\n      if (stream.match(/^(\\{|\\}|\\[|\\])/)) {\n        if (ch == '{')\n          state.inlinePairs++;\n        else if (ch == '}')\n          state.inlinePairs--;\n        else if (ch == '[')\n          state.inlineList++;\n        else\n          state.inlineList--;\n        return 'meta';\n      }\n\n      /* list seperator */\n      if (state.inlineList > 0 && !esc && ch == ',') {\n        stream.next();\n        return 'meta';\n      }\n      /* pairs seperator */\n      if (state.inlinePairs > 0 && !esc && ch == ',') {\n        state.keyCol = 0;\n        state.pair = false;\n        state.pairStart = false;\n        stream.next();\n        return 'meta';\n      }\n\n      /* start of value of a pair */\n      if (state.pairStart) {\n        /* block literals */\n        if (stream.match(/^\\s*(\\||\\>)\\s*/)) { state.literal = true; return 'meta'; };\n        /* references */\n        if (stream.match(/^\\s*(\\&|\\*)[a-z0-9\\._-]+\\b/i)) { return 'variable-2'; }\n        /* numbers */\n        if (state.inlinePairs == 0 && stream.match(/^\\s*-?[0-9\\.\\,]+\\s?$/)) { return 'number'; }\n        if (state.inlinePairs > 0 && stream.match(/^\\s*-?[0-9\\.\\,]+\\s?(?=(,|}))/)) { return 'number'; }\n        /* keywords */\n        if (stream.match(keywordRegex)) { return 'keyword'; }\n      }\n\n      /* pairs (associative arrays) -> key */\n      if (!state.pair && stream.match(/^\\s*(?:[,\\[\\]{}&*!|>'\"%@`][^\\s'\":]|[^,\\[\\]{}#&*!|>'\"%@`])[^#]*?(?=\\s*:($|\\s))/)) {\n        state.pair = true;\n        state.keyCol = stream.indentation();\n        return \"atom\";\n      }\n      if (state.pair && stream.match(/^:\\s*/)) { state.pairStart = true; return 'meta'; }\n\n      /* nothing found, continue */\n      state.pairStart = false;\n      state.escaped = (ch == '\\\\');\n      stream.next();\n      return null;\n    },\n    startState: function() {\n      return {\n        pair: false,\n        pairStart: false,\n        keyCol: 0,\n        inlinePairs: 0,\n        inlineList: 0,\n        literal: false,\n        escaped: false\n      };\n    }\n  };\n});\n\nCodeMirror.defineMIME(\"text/x-yaml\", \"yaml\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/z80/index.html",
    "content": "<!doctype html>\n\n<title>CodeMirror: Z80 assembly mode</title>\n<meta charset=\"utf-8\"/>\n<link rel=stylesheet href=\"../../doc/docs.css\">\n\n<link rel=\"stylesheet\" href=\"../../lib/codemirror.css\">\n<script src=\"../../lib/codemirror.js\"></script>\n<script src=\"z80.js\"></script>\n<style type=\"text/css\">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>\n<div id=nav>\n  <a href=\"http://codemirror.net\"><h1>CodeMirror</h1><img id=logo src=\"../../doc/logo.png\"></a>\n\n  <ul>\n    <li><a href=\"../../index.html\">Home</a>\n    <li><a href=\"../../doc/manual.html\">Manual</a>\n    <li><a href=\"https://github.com/codemirror/codemirror\">Code</a>\n  </ul>\n  <ul>\n    <li><a href=\"../index.html\">Language modes</a>\n    <li><a class=active href=\"#\">Z80 assembly</a>\n  </ul>\n</div>\n\n<article>\n<h2>Z80 assembly mode</h2>\n\n\n<div><textarea id=\"code\" name=\"code\">\n#include    \"ti83plus.inc\"\n#define     progStart   $9D95\n.org        progStart-2\n.db         $BB,$6D\n    bcall(_ClrLCDFull)\n    ld  HL, 0\n    ld  (PenCol),   HL\n    ld  HL, Message\n    bcall(_PutS) ; Displays the string\n    bcall(_NewLine)\n    ret\nMessage:\n.db         \"Hello world!\",0\n</textarea></div>\n\n    <script>\n      var editor = CodeMirror.fromTextArea(document.getElementById(\"code\"), {\n        lineNumbers: true\n      });\n    </script>\n\n    <p><strong>MIME type defined:</strong> <code>text/x-z80</code>.</p>\n  </article>\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/mode/z80/z80.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode('z80', function() {\n  var keywords1 = /^(exx?|(ld|cp|in)([di]r?)?|pop|push|ad[cd]|cpl|daa|dec|inc|neg|sbc|sub|and|bit|[cs]cf|x?or|res|set|r[lr]c?a?|r[lr]d|s[lr]a|srl|djnz|nop|rst|[de]i|halt|im|ot[di]r|out[di]?)\\b/i;\n  var keywords2 = /^(call|j[pr]|ret[in]?)\\b/i;\n  var keywords3 = /^b_?(call|jump)\\b/i;\n  var variables1 = /^(af?|bc?|c|de?|e|hl?|l|i[xy]?|r|sp)\\b/i;\n  var variables2 = /^(n?[zc]|p[oe]?|m)\\b/i;\n  var errors = /^([hl][xy]|i[xy][hl]|slia|sll)\\b/i;\n  var numbers = /^([\\da-f]+h|[0-7]+o|[01]+b|\\d+)\\b/i;\n\n  return {\n    startState: function() {\n      return {context: 0};\n    },\n    token: function(stream, state) {\n      if (!stream.column())\n        state.context = 0;\n\n      if (stream.eatSpace())\n        return null;\n\n      var w;\n\n      if (stream.eatWhile(/\\w/)) {\n        w = stream.current();\n\n        if (stream.indentation()) {\n          if (state.context == 1 && variables1.test(w))\n            return 'variable-2';\n\n          if (state.context == 2 && variables2.test(w))\n            return 'variable-3';\n\n          if (keywords1.test(w)) {\n            state.context = 1;\n            return 'keyword';\n          } else if (keywords2.test(w)) {\n            state.context = 2;\n            return 'keyword';\n          } else if (keywords3.test(w)) {\n            state.context = 3;\n            return 'keyword';\n          }\n\n          if (errors.test(w))\n            return 'error';\n        } else if (numbers.test(w)) {\n          return 'number';\n        } else {\n          return null;\n        }\n      } else if (stream.eat(';')) {\n        stream.skipToEnd();\n        return 'comment';\n      } else if (stream.eat('\"')) {\n        while (w = stream.next()) {\n          if (w == '\"')\n            break;\n\n          if (w == '\\\\')\n            stream.next();\n        }\n        return 'string';\n      } else if (stream.eat('\\'')) {\n        if (stream.match(/\\\\?.'/))\n          return 'number';\n      } else if (stream.eat('.') || stream.sol() && stream.eat('#')) {\n        state.context = 4;\n\n        if (stream.eatWhile(/\\w/))\n          return 'def';\n      } else if (stream.eat('$')) {\n        if (stream.eatWhile(/[\\da-f]/i))\n          return 'number';\n      } else if (stream.eat('%')) {\n        if (stream.eatWhile(/[01]/))\n          return 'number';\n      } else {\n        stream.next();\n      }\n      return null;\n    }\n  };\n});\n\nCodeMirror.defineMIME(\"text/x-z80\", \"z80\");\n\n});\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/package.json",
    "content": "{\n    \"name\": \"codemirror\",\n    \"version\":\"5.0.0\",\n    \"main\": \"lib/codemirror.js\",\n    \"description\": \"In-browser code editing made bearable\",\n    \"licenses\": [{\"type\": \"MIT\",\n                  \"url\": \"http://codemirror.net/LICENSE\"}],\n    \"directories\": {\"lib\": \"./lib\"},\n    \"scripts\": {\"test\": \"node ./test/run.js\"},\n    \"devDependencies\": {\"node-static\": \"0.6.0\",\n                        \"phantomjs\": \"1.9.2-5\",\n                        \"blint\": \">=0.1.1\"},\n    \"bugs\": \"http://github.com/codemirror/CodeMirror/issues\",\n    \"keywords\": [\"JavaScript\", \"CodeMirror\", \"Editor\"],\n    \"homepage\": \"http://codemirror.net\",\n    \"maintainers\":[{\"name\": \"Marijn Haverbeke\",\n                    \"email\": \"marijnh@gmail.com\",\n                    \"web\": \"http://marijnhaverbeke.nl\"}],\n    \"repository\": {\"type\": \"git\",\n                   \"url\": \"https://github.com/codemirror/CodeMirror.git\"}\n}\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/theme/3024-day.css",
    "content": "/*\n\n    Name:       3024 day\n    Author:     Jan T. Sott (http://github.com/idleberg)\n\n    CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror)\n    Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)\n\n*/\n\n.cm-s-3024-day.CodeMirror {background: #f7f7f7; color: #3a3432;}\n.cm-s-3024-day div.CodeMirror-selected {background: #d6d5d4 !important;}\n.cm-s-3024-day.CodeMirror ::selection { background: #d6d5d4; }\n.cm-s-3024-day.CodeMirror ::-moz-selection { background: #d9d9d9; }\n\n.cm-s-3024-day .CodeMirror-gutters {background: #f7f7f7; border-right: 0px;}\n.cm-s-3024-day .CodeMirror-guttermarker { color: #db2d20; }\n.cm-s-3024-day .CodeMirror-guttermarker-subtle { color: #807d7c; }\n.cm-s-3024-day .CodeMirror-linenumber {color: #807d7c;}\n\n.cm-s-3024-day .CodeMirror-cursor {border-left: 1px solid #5c5855 !important;}\n\n.cm-s-3024-day span.cm-comment {color: #cdab53;}\n.cm-s-3024-day span.cm-atom {color: #a16a94;}\n.cm-s-3024-day span.cm-number {color: #a16a94;}\n\n.cm-s-3024-day span.cm-property, .cm-s-3024-day span.cm-attribute {color: #01a252;}\n.cm-s-3024-day span.cm-keyword {color: #db2d20;}\n.cm-s-3024-day span.cm-string {color: #fded02;}\n\n.cm-s-3024-day span.cm-variable {color: #01a252;}\n.cm-s-3024-day span.cm-variable-2 {color: #01a0e4;}\n.cm-s-3024-day span.cm-def {color: #e8bbd0;}\n.cm-s-3024-day span.cm-bracket {color: #3a3432;}\n.cm-s-3024-day span.cm-tag {color: #db2d20;}\n.cm-s-3024-day span.cm-link {color: #a16a94;}\n.cm-s-3024-day span.cm-error {background: #db2d20; color: #5c5855;}\n\n.cm-s-3024-day .CodeMirror-activeline-background {background: #e8f2ff !important;}\n.cm-s-3024-day .CodeMirror-matchingbracket { text-decoration: underline; color: #a16a94 !important;}\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/theme/3024-night.css",
    "content": "/*\n\n    Name:       3024 night\n    Author:     Jan T. Sott (http://github.com/idleberg)\n\n    CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror)\n    Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)\n\n*/\n\n.cm-s-3024-night.CodeMirror {background: #090300; color: #d6d5d4;}\n.cm-s-3024-night div.CodeMirror-selected {background: #3a3432 !important;}\n.cm-s-3024-night.CodeMirror ::selection { background: rgba(58, 52, 50, .99); }\n.cm-s-3024-night.CodeMirror ::-moz-selection { background: rgba(58, 52, 50, .99); }\n.cm-s-3024-night .CodeMirror-gutters {background: #090300; border-right: 0px;}\n.cm-s-3024-night .CodeMirror-guttermarker { color: #db2d20; }\n.cm-s-3024-night .CodeMirror-guttermarker-subtle { color: #5c5855; }\n.cm-s-3024-night .CodeMirror-linenumber {color: #5c5855;}\n\n.cm-s-3024-night .CodeMirror-cursor {border-left: 1px solid #807d7c !important;}\n\n.cm-s-3024-night span.cm-comment {color: #cdab53;}\n.cm-s-3024-night span.cm-atom {color: #a16a94;}\n.cm-s-3024-night span.cm-number {color: #a16a94;}\n\n.cm-s-3024-night span.cm-property, .cm-s-3024-night span.cm-attribute {color: #01a252;}\n.cm-s-3024-night span.cm-keyword {color: #db2d20;}\n.cm-s-3024-night span.cm-string {color: #fded02;}\n\n.cm-s-3024-night span.cm-variable {color: #01a252;}\n.cm-s-3024-night span.cm-variable-2 {color: #01a0e4;}\n.cm-s-3024-night span.cm-def {color: #e8bbd0;}\n.cm-s-3024-night span.cm-bracket {color: #d6d5d4;}\n.cm-s-3024-night span.cm-tag {color: #db2d20;}\n.cm-s-3024-night span.cm-link {color: #a16a94;}\n.cm-s-3024-night span.cm-error {background: #db2d20; color: #807d7c;}\n\n.cm-s-3024-night .CodeMirror-activeline-background {background: #2F2F2F !important;}\n.cm-s-3024-night .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;}\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/theme/ambiance-mobile.css",
    "content": ".cm-s-ambiance.CodeMirror {\n  -webkit-box-shadow: none;\n  -moz-box-shadow: none;\n  box-shadow: none;\n}\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/theme/ambiance.css",
    "content": "/* ambiance theme for codemirror */\n\n/* Color scheme */\n\n.cm-s-ambiance .cm-keyword { color: #cda869; }\n.cm-s-ambiance .cm-atom { color: #CF7EA9; }\n.cm-s-ambiance .cm-number { color: #78CF8A; }\n.cm-s-ambiance .cm-def { color: #aac6e3; }\n.cm-s-ambiance .cm-variable { color: #ffb795; }\n.cm-s-ambiance .cm-variable-2 { color: #eed1b3; }\n.cm-s-ambiance .cm-variable-3 { color: #faded3; }\n.cm-s-ambiance .cm-property { color: #eed1b3; }\n.cm-s-ambiance .cm-operator {color: #fa8d6a;}\n.cm-s-ambiance .cm-comment { color: #555; font-style:italic; }\n.cm-s-ambiance .cm-string { color: #8f9d6a; }\n.cm-s-ambiance .cm-string-2 { color: #9d937c; }\n.cm-s-ambiance .cm-meta { color: #D2A8A1; }\n.cm-s-ambiance .cm-qualifier { color: yellow; }\n.cm-s-ambiance .cm-builtin { color: #9999cc; }\n.cm-s-ambiance .cm-bracket { color: #24C2C7; }\n.cm-s-ambiance .cm-tag { color: #fee4ff }\n.cm-s-ambiance .cm-attribute {  color: #9B859D; }\n.cm-s-ambiance .cm-header {color: blue;}\n.cm-s-ambiance .cm-quote { color: #24C2C7; }\n.cm-s-ambiance .cm-hr { color: pink; }\n.cm-s-ambiance .cm-link { color: #F4C20B; }\n.cm-s-ambiance .cm-special { color: #FF9D00; }\n.cm-s-ambiance .cm-error { color: #AF2018; }\n\n.cm-s-ambiance .CodeMirror-matchingbracket { color: #0f0; }\n.cm-s-ambiance .CodeMirror-nonmatchingbracket { color: #f22; }\n\n.cm-s-ambiance .CodeMirror-selected { background: rgba(255, 255, 255, 0.15); }\n.cm-s-ambiance.CodeMirror-focused .CodeMirror-selected { background: rgba(255, 255, 255, 0.10); }\n.cm-s-ambiance.CodeMirror ::selection { background: rgba(255, 255, 255, 0.10); }\n.cm-s-ambiance.CodeMirror ::-moz-selection { background: rgba(255, 255, 255, 0.10); }\n\n/* Editor styling */\n\n.cm-s-ambiance.CodeMirror {\n  line-height: 1.40em;\n  color: #E6E1DC;\n  background-color: #202020;\n  -webkit-box-shadow: inset 0 0 10px black;\n  -moz-box-shadow: inset 0 0 10px black;\n  box-shadow: inset 0 0 10px black;\n}\n\n.cm-s-ambiance .CodeMirror-gutters {\n  background: #3D3D3D;\n  border-right: 1px solid #4D4D4D;\n  box-shadow: 0 10px 20px black;\n}\n\n.cm-s-ambiance .CodeMirror-linenumber {\n  text-shadow: 0px 1px 1px #4d4d4d;\n  color: #111;\n  padding: 0 5px;\n}\n\n.cm-s-ambiance .CodeMirror-guttermarker { color: #aaa; }\n.cm-s-ambiance .CodeMirror-guttermarker-subtle { color: #111; }\n\n.cm-s-ambiance .CodeMirror-lines .CodeMirror-cursor {\n  border-left: 1px solid #7991E8;\n}\n\n.cm-s-ambiance .CodeMirror-activeline-background {\n  background: none repeat scroll 0% 0% rgba(255, 255, 255, 0.031);\n}\n\n.cm-s-ambiance.CodeMirror,\n.cm-s-ambiance .CodeMirror-gutters {\n  background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAQAAAAHUWYVAABFFUlEQVQYGbzBCeDVU/74/6fj9HIcx/FRHx9JCFmzMyGRURhLZIkUsoeRfUjS2FNDtr6WkMhO9sm+S8maJfu+Jcsg+/o/c+Z4z/t97/vezy3z+z8ekGlnYICG/o7gdk+wmSHZ1z4pJItqapjoKXWahm8NmV6eOTbWUOp6/6a/XIg6GQqmenJ2lDHyvCFZ2cBDbmtHA043VFhHwXxClWmeYAdLhV00Bd85go8VmaFCkbVkzlQENzfBDZ5gtN7HwF0KDrTwJ0dypSOzpaKCMwQHKTIreYIxlmhXTzTWkVm+LTynZhiSBT3RZQ7aGfjGEd3qyXQ1FDymqbKxpspERQN2MiRjNZlFFQXfCNFm9nM1zpAsoYjmtRTc5ajwuaXc5xrWskT97RaKzAGe5ARHhVUsDbjKklziiX5WROcJwSNCNI+9w1Jwv4Zb2r7lCMZ4oq5C0EdTx+2GzNuKpJ+iFf38JEWkHJn9DNF7mmBDITrWEg0VWL3pHU20tSZnuqWu+R3BtYa8XxV1HO7GyD32UkOpL/yDloINFTmvtId+nmAjxRw40VMwVKiwrKLE4bK5UOVntYwhOcSSXKrJHKPJedocpGjVz/ZMIbnYUPB10/eKCrs5apqpgVmWzBYWpmtKHecJPjaUuEgRDDaU0oZghCJ6zNMQ5ZhDYx05r5v2muQdM0EILtXUsaKiQX9WMEUotagQzFbUNN6NUPC2nm5pxEWGCjMc3GdJHjSU2kORLK/JGSrkfGEIjncU/CYUnOipoYemwj8tST9NsJmB7TUVXtbUtXATJVZXBMvYeTXJfobgJUPmGMP/yFaWonaa6BcFO3nqcIqCozSZoZoSr1g4zJOzuyGnxTEX3lUEJ7WcZgme8ddaWvWJo2AJR9DZU3CUIbhCSG6ybSwN6qtJVnCU2svDTP2ZInOw2cBTrqtQahtNZn9NcJ4l2NaSmSkkP1noZWnVwkLmdUPOwLZEwy2Z3S3R+4rIG9hcbpPXHFVWcQdZkn2FOta3cKWQnNRC5g1LsJah4GCzSVsKnCOY5OAFRTBekyyryeyilhFKva75r4Mc0aWanGEaThcy31s439KKxTzJYY5WTHPU1FtIHjQU3Oip4xlNzj/lBw23dYZVliQa7WAXf4shetcQfatI+jWRDBPmyNeW6A1P5kdDgyYJlba0BIM8BZu1JfrFwItyjcAMR3K0BWOIrtMEXyhyrlVEx3ui5dUBjmB/Q3CXW85R4mBD0s7B+4q5tKUjOlb9qqmhi5AZ6GFIC5HXtOobdYGlVdMVbNJ8toNTFcHxnoL+muBagcctjWnbNMuR00uI7nQESwg5q2qqrKWIfrNUmeQocY6HuyxJV02wj36w00yhpmUFenv4p6fUkZYqLyuinx2RGOjhCXYyJF84oiU00YMOOhhquNdfbOB7gU88pY4xJO8LVdp6/q2voeB4R04vIdhSE40xZObx1HGGJ/ja0LBthFInKaLPPFzuCaYaoj8JjPME8yoyxo6zlBqkiUZYgq00OYMswbWO5NGmq+xhipxHLRW29ARjNKXO0wRnear8XSg4XFPLKEPUS1GqvyLwiuBUoa7zpZ0l5xxFwWmWZC1H5h5FwU8eQ7K+g8UcVY6TMQreVQT/8uQ8Z+ALIXnSEa2pYZQneE9RZbSBNYXfWYJzW/h/4j4Dp1tYVcFIC5019Vyi4ThPqSFCzjGWaHQTBU8q6vrVwgxP9Lkm840imWKpcLCjYTtrKuwvsKSnrvHCXGkSMk9p6lhckfRpIeis+N2PiszT+mFLspyGleUhDwcLrZqmyeylxwjBcKHEapqkmyangyLZRVOijwOtCY5SsG5zL0OwlCJ4y5KznF3EUNDDrinwiyLZRzOXtlBbK5ITHFGLp8Q0R6ab6mS7enI2cFrxOyHvOCFaT1HThS1krjCwqWeurCkk+willhCC+RSZnRXBiZaC5RXRIZYKp2lyfrHwiKPKR0JDzrdU2EFgpidawlFDR6FgXUMNa+g1FY3bUQh2cLCwosRdnuQTS/S+JVrGLeWIvtQUvONJxlqSQYYKpwoN2kaocLjdVsis4Mk80ESF2YpSkzwldjHkjFCUutI/r+EHDU8oCs6yzL3PhWiEooZdFMkymlas4AcI3KmoMMNSQ3tHzjGWCrcJJdYyZC7QFGwjRL9p+MrRkAGWzIaWCn9W0F3TsK01c2ZvQw0byvxuQU0r1lM0qJO7wW0kRIMdDTtXEdzi4VIh+EoIHm0mWtAtpCixlabgn83fKTI7anJe9ST7WIK1DMGpQmYeA58ImV6ezOGOzK2Kgq01pd60cKWiUi9Lievb/0vIDPHQ05Kzt4ddPckQBQtoaurjyHnek/nKzpQLrVgKPjIkh2v4uyezpv+Xoo7fPFXaGFp1vaLKxQ4uUpQQS5VuQs7BCq4xRJv7fwpVvvFEB3j+620haOuocqMhWd6TTPAEx+mdFNGHdranFe95WrWmIvlY4F1Dle2ECgc6cto7SryuqGGGha0tFQ5V53migUKmg6XKAo4qS3mik+0OZpAhOLeZKicacgaYcyx5hypYQE02ZA4xi/pNhOQxR4klNKyqacj+mpxnLTnnGSo85++3ZCZq6lrZkXlGEX3o+C9FieccJbZWVFjC0Yo1FZnJhoYMFoI1hEZ9r6hwg75HwzBNhbZCdJEfJwTPGzJvaKImw1yYX1HDAmpXR+ZJQ/SmgqMNVQb5vgamGwLtt7VwvP7Qk1xpiM5x5Cyv93E06MZmgs0Nya2azIKOYKCGBQQW97RmhKNKF02JZqHEJ4o58qp7X5EcZmc56trXEqzjCBZ1MFGR87Ql2tSTs6CGxS05PTzRQorkbw7aKoKXFDXsYW42VJih/q+FP2BdTzDTwVqOYB13liM50vG7wy28qagyuIXMeQI/Oqq8bcn5wJI50xH00CRntyfpL1T4hydYpoXgNiFzoIUTDZnLNRzh4TBHwbYGDvZkxmlyJloyr6tRihpeUG94GnKtIznREF0tzJG/OOr73JBcrSh1k6WuTprgLU+mnSGnv6Zge0NNz+kTDdH8nuAuTdJDCNb21LCiIuqlYbqGzT3RAoZofQfjFazkqeNWdYaGvYTM001EW2oKPvVk1ldUGSgUtHFwjKM1h9jnFcmy5lChoLNaQMGGDsYbKixlaMBmmsx1QjCfflwTfO/gckW0ruZ3jugKR3R5W9hGUWqCgxuFgsuaCHorotGKzGaeZB9DMsaTnKCpMtwTvOzhYk0rdrArKCqcaWmVk1+F372ur1YkKxgatI8Qfe1gIX9wE9FgS8ESmuABIXnRUbCapcKe+nO7slClSZFzpV/LkLncEb1qiO42fS3R855Su2mCLh62t1SYZZYVmKwIHjREF2uihTzB20JOkz7dkxzYQnK0UOU494wh+VWRc6Un2kpTaVgLDFEkJ/uhzRcI0YKGgpGWOlocBU/a4fKoJ/pEaNV6jip3+Es9VXY078rGnmAdf7t9ylPXS34RBSuYPs1UecZTU78WanhBCHpZ5sAoTz0LGZKjPf9TRypqWEiTvOFglL1fCEY3wY/++rbk7C8bWebA6p6om6PgOL2kp44TFJlVNBXae2rqqdZztOJpT87GQsE9jqCPIe9VReZuQ/CIgacsyZdCpIScSYqcZk8r+nsyCzhyfhOqHGOIvrLknC8wTpFcaYiGC/RU1NRbUeUpocQOnkRpGOrIOcNRx+1uA0UrzhSSt+VyS3SJpnFWkzNDqOFGIWcfR86DnmARTQ1HKIL33ExPiemeOhYSSjzlSUZZuE4TveoJLnBUOFof6KiysCbnAEcZgcUNTDOwkqWu3RWtmGpZwlHhJENdZ3miGz0lJlsKnjbwqSHQjpxnFDlTLLwqJPMZMjd7KrzkSG7VsxXBZE+F8YZkb01Oe00yyRK9psh5SYh29ySPKBo2ylNht7ZkZnsKenjKNJu9PNEyZpaCHv4Kt6RQsLvAVp7M9kIimmCUwGeWqLMmGuIotYMmWNpSahkhZw9FqZsVnKJhsjAHvtHMsTM9fCI06Dx/u3vfUXCqfsKRc4oFY2jMsoo/7DJDwZ1CsIKnJu+J9ldkpmiCxQx1rWjI+T9FwcWWzOuaYH0Hj7klNRVWEQpmaqosakiGNTFHdjS/qnUdmf0NJW5xsL0HhimCCZZSRzmSPTXJQ4aaztAwtZnoabebJ+htCaZ7Cm535ByoqXKbX1WRc4Eh2MkRXWzImVc96Cj4VdOKVxR84VdQsIUM8Psoou2byVHyZFuq7O8otbSQ2UAoeEWTudATLGSpZzVLlXVkPU2Jc+27lsw2jmg5T5VhbeE3BT083K9WsTTkFU/Osi0rC5lRlpwRHUiesNS0sOvmqGML1aRbPAxTJD9ZKtxuob+hhl8cwYGWpJ8nub7t5p6coYbMovZ1BTdaKn1jYD6h4GFDNFyT/Kqe1XCXphXHOKLZmuRSRdBPEfVUXQzJm5YGPGGJdvAEr7hHNdGZnuBvrpciGmopOLf5N0uVMy0FfYToJk90uUCbJupaVpO53UJXR2bVpoU00V2KOo4zMFrBd0Jtz2pa0clT5Q5L8IpQ177mWQejPMEJhuQjS10ref6HHjdEhy1P1EYR7GtO0uSsKJQYLiTnG1rVScj5lyazpqWGl5uBbRWl7m6ixGOOnEsMJR7z8J0n6KMnCdxhiNYQCoZ6CmYLnO8omC3MkW3bktlPmEt/VQQHejL3+dOE5FlPdK/Mq8hZxxJtLyRrepLThYKbLZxkSb5W52vYxNOaOxUF0yxMUPwBTYqCzy01XayYK0sJyWBLqX0MwU5CzoymRzV0EjjeUeLgDpTo6ij42ZAzvD01dHUUTPLU96MdLbBME8nFBn7zJCMtJcZokn8YoqU0FS5WFKyniHobguMcmW8N0XkWZjkyN3hqOMtS08r+/xTBwpZSZ3qiVRX8SzMHHjfUNFjgHEPmY9PL3ykEzxkSre/1ZD6z/NuznuB0RcE1TWTm9zRgfUWVJiG6yrzgmWPXC8EAR4Wxhlad0ZbgQyEz3pG5RVEwwDJH2mgKpjcTiCOzn1lfUWANFbZ2BA8balnEweJC9J0iuaeZoI+ippFCztEKVvckR2iice1JvhVytrQwUAZpgsubCPaU7xUe9vWnaOpaSBEspalykhC9bUlOMpT42ZHca6hyrqKmw/wMR8H5ZmdFoBVJb03O4UL0tSNnvIeRmkrLWqrs78gcrEn2tpcboh0UPOW3UUR9PMk4T4nnNKWmCjlrefhCwxRNztfmIQVdDElvS4m1/WuOujoZCs5XVOjtKPGokJzsYCtFYoWonSPT21DheU/wWhM19FcElwqNGOsp9Q8N/cwXaiND1MmeL1Q5XROtYYgGeFq1aTMsoMmcrKjQrOFQTQ1fmBYhmW6o8Jkjc7iDJRTBIo5kgJD5yMEYA3srCg7VFKwiVJkmRCc5ohGOKhsYMn/XBLdo5taZjlb9YAlGWRimqbCsoY7HFAXLa5I1HPRxMMsQDHFkWtRNniqT9UEeNjcE7RUlrCJ4R2CSJuqlKHWvJXjAUNcITYkenuBRB84TbeepcqTj3zZyFJzgYQdHnqfgI0ddUwS6GqWpsKWhjq9cV0vBAEMN2znq+EBfIWT+pClYw5xsTlJU6GeIBsjGmmANTzJZiIYpgrM0Oa8ZMjd7NP87jxhqGOhJlnQtjuQpB+8aEE00wZFznSJPyHxgH3HkPOsJFvYk8zqCHzTs1BYOa4J3PFU+UVRZxlHDM4YavlNUuMoRveiZA2d7grMNc2g+RbSCEKzmgYsUmWmazFJyoiOZ4KnyhKOGRzWJa0+moyV4TVHDzn51Awtqaphfk/lRQ08FX1iiqxTB/kLwd0VynKfEvI6cd4XMV5bMhZ7gZUWVzYQ6Nm2BYzxJbw3bGthEUUMfgbGeorae6DxHtJoZ6alhZ0+ytiVoK1R4z5PTrOECT/SugseEOlb1MMNR4VRNcJy+V1Hg9ONClSZFZjdHlc6W6FBLdJja2MC5hhpu0DBYEY1TFGwiFAxRRCsYkiM9JRb0JNMVkW6CZYT/2EiTGWmo8k+h4FhDNE7BvppoTSFnmCV5xZKzvcCdDo7VVPnIU+I+Rc68juApC90MwcFCsJ5hDqxgScYKreruyQwTqrzoqDCmhWi4IbhB0Yrt3RGa6GfDv52rKXWhh28dyZaWUvcZeMTBaZoSGyiCtRU5J8iviioHaErs7Jkj61syVzTTgOcUOQ8buFBTYWdL5g3T4qlpe0+wvD63heAXRfCCIed9RbCsp2CiI7raUOYOTU13N8PNHvpaGvayo4a3LLT1lDrVEPT2zLUlheB1R+ZTRfKWJ+dcocLJfi11vyJ51lLqJ0WD7tRwryezjiV5W28uJO9qykzX8JDe2lHl/9oyBwa2UMfOngpXCixvKdXTk3wrsKmiVYdZIqsoWEERjbcUNDuiaQomGoIbFdEHmsyWnuR+IeriKDVLnlawlyNHKwKlSU631PKep8J4Q+ayjkSLKYLhalNHlYvttb6fHm0p6OApsZ4l2VfdqZkjuysy6ysKLlckf1KUutCTs39bmCgEyyoasIWlVaMF7mgmWtBT8Kol5xpH9IGllo8cJdopcvZ2sImlDmMIbtDk3KIpeNiS08lQw11NFPTwVFlPP6pJ2gvRfI7gQUfmNAtf6Gs0wQxDsKGlVBdF8rCa3jzdwMaGHOsItrZk7hAyOzpK9VS06j5F49b0VNGOOfKs3lDToMsMBe9ZWtHFEgxTJLs7qrygKZjUnmCYoeAqeU6jqWuLJup4WghOdvCYJnrSkSzoyRkm5M2StQwVltPkfCAk58tET/CSg+8MUecmotMEnhBKfWBIZsg2ihruMJQaoIm+tkTLKEqspMh00w95gvFCQRtDwTT1gVDDSEVdlwqZfxoQRbK0g+tbiBZxzKlpnpypejdDwTaeOvorMk/IJE10h9CqRe28hhLbe0pMsdSwv4ZbhKivo2BjDWfL8UKJgeavwlwb5KlwhyE4u4XkGE2ytZCznKLCDZZq42VzT8HLCrpruFbIfOIINmh/qCdZ1ZBc65kLHR1Bkyf5zn6pN3SvGKIlFNGplhrO9QSXanLOMQTLCa0YJCRrCZm/CZmrLTm7WzCK4GJDiWUdFeYx1LCFg3NMd0XmCuF3Y5rITLDUsYS9zoHVzwnJoYpSTQoObyEzr4cFBNqYTopoaU/wkyLZ2lPhX/5Y95ulxGTV7KjhWrOZgl8MyUUafjYraNjNU1N3IWcjT5WzWqjwtoarHSUObGYO3GCJZpsBlnJGPd6ZYLyl1GdCA2625IwwJDP8GUKymbzuyPlZlvTUsaUh5zFDhRWFzPKKZLAlWdcQbObgF9tOqOsmB1dqcqYJmWstFbZRRI9poolmqiLnU0POvxScpah2iSL5UJNzgScY5+AuIbpO0YD3NCW+dLMszFSdFCWGqG6eVq2uYVNDdICGD6W7EPRWZEY5gpsE9rUkS3mijzzJnm6UpUFXG1hCUeVoS5WfNcFpblELL2qqrCvMvRfd45oalvKU2tiQ6ePJOVMRXase9iTtLJztPxJKLWpo2CRDcJwn2sWSLKIO1WQWNTCvpVUvOZhgSC40JD0dOctaSqzkCRbXsKlb11Oip6PCJ0IwSJM31j3akRxlP7Rwn6aGaUL0qiLnJkvB3xWZ2+Q1TfCwpQH3G0o92UzmX4o/oJNQMMSQc547wVHhdk+VCw01DFYEnTxzZKAm74QmeNNR1w6WzEhNK15VJzuCdxQ53dRUDws5KvwgBMOEgpcVNe0hZI6RXT1Jd0cyj5nsaEAHgVmGaJIlWdsc5Ui2ElrRR6jrRAttNMEAIWrTDFubkZaok7/AkzfIwfuWVq0jHzuCK4QabtLUMVPB3kJ0oyHTSVFlqMALilJf2Rf8k5aaHtMfayocLBS8L89oKoxpJvnAkDPa0qp5DAUTHKWmCcnthlou8iCKaFFLHWcINd1nyIwXqrSxMNmSs6KmoL2QrKuWtlQ5V0120xQ5vRyZS1rgFkWwhiOwiuQbR0OOVhQM9iS3tiXp4RawRPMp5tDletOOBL95MpM01dZTBM9pkn5qF010rIeHFcFZhmSGpYpTsI6nwhqe5C9ynhlpp5ophuRb6WcJFldkVnVEwwxVfrVkvnWUuNLCg5bgboFHPDlDPDmnK7hUrWiIbjadDclujlZcaokOFup4Ri1kacV6jmrrK1hN9bGwpKEBQ4Q6DvIUXOmo6U5LqQM6EPyiKNjVkPnJkDPNEaxhiFay5ExW1NXVUGqcpYYdPcGiCq7z/TSlbhL4pplWXKd7NZO5QQFrefhRQW/NHOsqcIglc4UhWklR8K0QzbAw08CBDnpbgqXdeD/QUsM4RZXDFBW6WJKe/mFPdH0LtBgiq57wFLzlyQzz82qYx5D5WJP5yVJDW01BfyHnS6HKO/reZqId1WGa4Hkh2kWodJ8i6KoIPlAj2hPt76CzXsVR6koPRzWTfKqIentatYpQw2me4AA3y1Kind3SwoOKZDcFXTwl9tWU6mfgRk9d71sKtlNwrjnYw5tC5n5LdKiGry3JKNlHEd3oaMCFHrazBPMp/uNJ+V7IudcSbeOIdjUEdwl0VHCOZo5t6YluEuaC9mQeMgSfOyKnYGFHcIeQ84yQWbuJYJpZw5CzglDH7gKnWqqM9ZTaXcN0TeYhR84eQtJT76JJ1lREe7WnnvsMmRc9FQ7SBBM9mV3lCUdmHk/S2RAMt0QjFNFqQpWjDPQ01DXWUdDBkXziKPjGEP3VP+zIWU2t7im41FOloyWzn/L6dkUy3VLDaZ6appgDLHPjJEsyvJngWEPUyVBiAaHCTEXwrLvSEbV1e1gKJniicWorC1MUrVjB3uDhJE/wgSOzk1DXpk0k73qCM8xw2UvD5kJmDUfOomqMpWCkJRlvKXGmoeBm18USjVIk04SClxTB6YrgLAPLWYK9HLUt5cmc0vYES8GnTeRc6skZbQkWdxRsIcyBRzx1DbTk9FbU0caTPOgJHhJKnOGIVhQqvKmo0llRw9sabrZkDtdg3PqaKi9oatjY8B+G371paMg6+mZFNNtQ04mWBq3rYLOmtWWQp8KJnpy9DdFensyjdqZ+yY40VJlH8wcdLzC8PZnvHMFUTZUrDTkLyQaGus5X5LzpYAf3i+e/ZlhqGqWhh6Ou6xTR9Z6oi5AZZtp7Mj2EEm8oSpxiYZCHU/1fbGdNNNRRoZMhmilEb2gqHOEJDtXkHK/JnG6IrvbPCwV3NhONVdS1thBMs1T4QOBcTWa2IzhMk2nW5Kyn9tXUtpv9RsG2msxk+ZsQzRQacJncpgke0+T8y5Fzj8BiGo7XlJjaTIlpQs7KFjpqGnKuoyEPeIKnFMkZHvopgh81ySxNFWvJWcKRs70j2FOT012IllEEO1n4pD1513Yg2ssQPOThOkvyrqHUdEXOSEsihmBbTbKX1kLBPWqWkLOqJbjB3GBIZmoa8qWl4CG/iZ7oiA72ZL7TJNeZUY7kFQftDcHHluBzRbCegzMtrRjVQpX2lgoPKKLJAkcbMl01XK2p7yhL8pCBbQ3BN2avJgKvttcrWDK3CiUOVxQ8ZP+pqXKyIxnmBymCg5vJjNfkPK4+c8cIfK8ocVt7kmfd/I5SR1hKvCzUtb+lhgc00ZaO6CyhIQP1Uv4yIZjload72PXX0OIJvnFU+0Zf6MhsJwTfW0r0UwQfW4LNLZl5HK261JCZ4qnBaAreVAS3WrjV0LBnNDUNNDToCEeFfwgcb4gOEqLRhirWkexrCEYKVV711DLYEE1XBEsp5tpTGjorkomKYF9FDXv7fR3BGwbettSxnyL53MBPjsxDZjMh+VUW9NRxq1DhVk+FSxQcaGjV9Pawv6eGByw5qzoy7xk4RsOShqjJwWKe/1pEEfzkobeD/dQJmpqedcyBTy2sr4nGNRH0c0SPWTLrqAc0OQcb/gemKgqucQT7ySWKCn2EUotoCvpZct7RO2sy/QW0IWcXd7pQRQyZVwT2USRO87uhjioTLKV2brpMUcMQRbKH/N2T+UlTpaMls6cmc6CCNy3JdYYSUzzJQ4oSD3oKLncULOiJvjBEC2oqnCJkJluCYy2ZQ5so9YYlZ1VLlQU1mXEW1jZERwj/MUSRc24TdexlqLKfQBtDTScJUV8FszXBEY5ktpD5Ur9hYB4Nb1iikw3JoYpkKX+RodRKFt53MMuRnKSpY31PwYaGaILh3wxJGz9TkTPEETxoCWZrgvOlmyMzxFEwVJE5xZKzvyJ4WxEc16Gd4Xe3Weq4XH2jKRikqOkGQ87hQnC7wBmGYLAnesX3M+S87eFATauuN+Qcrh7xIxXJbUIdMw3JGE3ylCWzrieaqCn4zhGM19TQ3z1oH1AX+pWEqIc7wNGAkULBo/ZxRaV9NNyh4Br3rCHZzbzmSfawBL0dNRwpW1kK9mxPXR9povcdrGSZK9c2k0xwFGzjuniCtRSZCZ6ccZ7gaktmgAOtKbG/JnOkJrjcQTdFMsxRQ2cLY3WTIrlCw1eWKn8R6pvt4GFDso3QoL4a3nLk3G6JrtME3dSenpx7PNFTmga0EaJTLQ061sEeQoWXhSo9LTXsaSjoJQRXeZLtDclbCrYzfzHHeaKjHCVOUkQHO3JeEepr56mhiyaYYKjjNU+Fed1wS5VlhWSqI/hYUdDOkaxiKehoyOnrCV5yBHtbWFqTHCCwtpDcYolesVR5yUzTZBb3RNMd0d6WP+SvhuBmRcGxnuQzT95IC285cr41cLGQ6aJJhmi4TMGempxeimBRQw1tFKV+8jd6KuzoSTqqDxzRtpZkurvKEHxlqXKRIjjfUNNXQsNOsRScoWFLT+YeRZVD3GRN0MdQcKqQjHDMrdGGVu3iYJpQx3WGUvfbmxwFfR20WBq0oYY7LMFhhgYtr8jpaEnaOzjawWWaTP8mMr0t/EPDPoqcnxTBI5o58L7uoWnMrpoqPwgVrlAUWE+V+TQl9rawoyP6QGAlQw2TPRX+YSkxyBC8Z6jhHkXBgQL7WII3DVFnRfCrBfxewv9D6xsyjys4VkhWb9pUU627JllV0YDNHMku/ldNMMXDEo4aFnAkk4U6frNEU4XgZUPmEKHUl44KrzmYamjAbh0JFvGnaTLPu1s9jPCwjFpYiN7z1DTOk/nc07CfDFzmCf7i+bfNHXhDtLeBXzTBT5rkMvWOIxpl4EMh2LGJBu2syDnAEx2naEhHDWMMzPZEhygyS1mS5RTJr5ZkoKbEUoYqr2kqdDUE8ztK7OaIntJkFrIECwv8LJTaVx5XJE86go8dFeZ3FN3rjabCAYpoYEeC9zzJVULBbmZhDyd7ko09ydpNZ3nm2Kee4FPPXHnYEF1nqOFEC08LUVcDvYXkJHW8gTaKCk9YGOeIJhqiE4ToPEepdp7IWFjdwnWaufGMwJJCMtUTTBBK9BGCOy2tGGrJTHIwyEOzp6aPzNMOtlZkDvcEWpP5SVNhfkvDxhmSazTJXYrM9U1E0xwFVwqZQwzJxw6+kGGGUj2FglGGmnb1/G51udRSMNlTw6GGnCcUwVcOpmsqTHa06o72sw1RL02p9z0VbnMLOaIX3QKaYKSCFQzBKEUNHTSc48k53RH9wxGMtpQa5KjjW0W0n6XCCCG4yxNNdhQ4R4l1Ff+2sSd6UFHiIEOyqqFgT01mEUMD+joy75jPhOA+oVVLm309FR4yVOlp4RhLiScNmSmaYF5Pw0STrOIoWMSR2UkRXOMp+M4SHW8o8Zoi6OZgjKOaFar8zZDzkWzvKOjkKBjmCXby8JahhjXULY4KlzgKLvAwxVGhvyd4zxB1d9T0piazmKLCVZY5sKiD0y2ZSYrkUEPUbIk+dlQ4SJHTR50k1DPaUWIdTZW9NJwnJMOECgd7ou/MnppMJ02O1VT4Wsh85MnZzcFTngpXGKo84qmwgKbCL/orR/SzJ2crA+t6Mp94KvxJUeIbT3CQu1uIdlQEOzlKfS3UMcrTiFmOuroocrZrT2AcmamOKg8YomeEKm/rlT2sociMaybaUlFhuqHCM2qIJ+rg4EcDFymiDSxzaHdPcpE62pD5kyM5SBMoA1PaUtfIthS85ig1VPiPPYXgYEMNk4Qq7TXBgo7oT57gPUdwgCHzhIVFPFU6OYJzHAX9m5oNrVjeE61miDrqQ4VSa1oiURTsKHC0IfjNwU2WzK6eqK8jWln4g15TVBnqmDteCJ501PGAocJhhqjZdtBEB6lnhLreFJKxmlKbeGrqLiSThVIbCdGzloasa6lpMQXHCME2boLpJgT7yWaemu6wBONbqGNVRS0PKIL7LckbjmQtR7K8I5qtqel+T/ChJTNIKLjdUMNIRyvOEko9YYl2cwQveBikCNawJKcLBbc7+JM92mysNvd/Fqp8a0k6CNEe7cnZrxlW0wQXaXjaktnRwNOGZKYiONwS7a1JVheq3WgJHlQUGKHKmp4KAxXR/ULURcNgoa4zhKSLpZR3kxRRb0NmD0OFn+UCS7CzI1nbP6+o4x47QZE5xRCt3ZagnYcvmpYQktXdk5YKXTzBC57kKEe0VVuiSYqapssMS3C9p2CKkHOg8B8Pa8p5atrIw3qezIWanMGa5HRDNF6RM9wcacl0N+Q8Z8hsIkSnaIIdHRUOEebAPy1zbCkhM062FCJtif7PU+UtoVXzWKqM1PxXO8cfdruhFQ/a6x3JKYagvVDhQEtNiyiiSQ7OsuRsZUku0CRNDs4Sog6KKjsZgk2bYJqijgsEenoKeniinRXBn/U3lgpPdyDZynQx8IiioMnCep5Ky8mjGs6Wty0l1hUQTcNWswS3WRp2kCNZwJG8omG8JphPUaFbC8lEfabwP7VtM9yoaNCAjpR41VNhrD9LkbN722v0CoZMByFzhaW+MyzRYEWFDQwN2M4/JiT76PuljT3VU/A36eaIThb+R9oZGOAJ9tewkgGvqOMNRWYjT/Cwu99Q8LqDE4TgbLWxJ1jaDDAERsFOFrobgjUsBScaguXU8kKm2RL19tRypSHnHNlHiIZqgufs4opgQdVdwxBNNFBR6kVFqb8ogimOzB6a6HTzrlDHEpYaxjiiA4TMQobkDg2vejjfwJGWmnbVFAw3H3hq2NyQfG7hz4aC+w3BbwbesG0swYayvpAs6++Ri1Vfzx93mFChvyN5xVHTS+0p9aqCAxyZ6ZacZyw5+7uuQkFPR9DDk9NOiE7X1PCYJVjVUqq7JlrHwWALF5nfHNGjApdpqgzx5OwilDhCiDYTgnc9waGW4BdLNNUQvOtpzDOWHDH8D7TR/A/85KljEQu3NREc4Pl/6B1Hhc8Umb5CsKMmGC9EPcxoT2amwHNCmeOEnOPbklnMkbOgIvO5UMOpQrS9UGVdt6iH/fURjhI/WOpaW9OKLYRod6HCUEdOX000wpDZQ6hwg6LgZfOqo1RfT/CrJzjekXOGhpc1VW71ZLbXyyp+93ILbC1kPtIEYx0FIx1VDrLoVzXRKRYWk809yYlC9ImcrinxtabKnzRJk3lAU1OLEN1j2zrYzr2myHRXJFf4h4QKT1qSTzTB5+ZNTzTRkAxX8FcLV2uS8eoQQ2aAkFzvCM72sJIcJET3WPjRk5wi32uSS9rfZajpWEvj9hW42F4o5NytSXYy8IKHay10VYdrcl4SkqscrXpMwyGOgtkajheSxdQqmpxP1L3t4R5PqasFnrQEjytq6qgp9Y09Qx9o4S1FzhUCn1kyHSzBWLemoSGvOqLNhZyBjmCaAUYpMgt4Ck7wBBMMwWKWgjsUwTaGVsxWC1mYoKiyqqeGKYqonSIRQ3KIkHO0pmAxTdBHkbOvfllfr+AA+7gnc50huVKYK393FOyg7rbPO/izI7hE4CnHHHnJ0ogNPRUGeUpsrZZTBJcrovUcJe51BPsr6GkJdhCCsZ6aTtMEb2pqWkqeVtDXE/QVggsU/Nl86d9RMF3DxvZTA58agu810RWawCiSzzXBeU3MMW9oyJUedvNEvQyNu1f10BSMddR1vaLCYpYa/mGocLSiYDcLbQz8aMn5iyF4xBNMs1P0QEOV7o5gaWGuzSeLue4tt3ro7y4Tgm4G/mopdZgl6q0o6KzJWE3mMksNr3r+a6CbT8g5wZNzT9O7fi/zpaOmnz3BRoqos+tv9zMbdpxsqDBOEewtJLt7cg5wtKKbvldpSzRRCD43VFheCI7yZLppggMVBS/KMAdHODJvOwq2NQSbKKKPLdFWQs7Fqo+mpl01JXYRgq8dnGLhTiFzqmWsUMdpllZdbKlyvSdYxhI9YghOtxR8LgSLWHK62mGGVoxzBE8LNWzqH9CUesQzFy5RQzTc56mhi6fgXEWwpKfE5Z7M05ZgZUPmo6auiv8YKzDYwWBLMErIbKHJvOwIrvEdhOBcQ9JdU1NHQ7CXn2XIDFBKU2WAgcX9UAUzDXWd5alwuyJ41Z9rjKLCL4aCp4WarhPm2rH+SaHUYE001JDZ2ZAzXPjdMpZWvC9wmqIB2lLhQ01D5jO06hghWMndbM7yRJMsoCj1vYbnFQVrW9jak3OlEJ3s/96+p33dEPRV5GxiqaGjIthUU6FFEZyqCa5qJrpBdzSw95IUnOPIrCUUjRZQFrbw5PR0R1qiYx3cb6nrWUMrBmmiBQxVHtTew5ICP/ip6g4hed/Akob/32wvBHsIOX83cI8hGeNeNPCIkPmXe8fPKx84OMSRM1MTdXSwjCZ4S30jVGhvqTRak/OVhgGazHuOCud5onEO1lJr6ecVyaOK6H7zqlBlIaHE0oroCgfvGJIdPcmfLNGLjpz7hZwZQpUbFME0A1cIJa7VNORkgfsMBatbKgwwJM9bSvQXeNOvbIjelg6WWvo5kvbKaJJNHexkKNHL9xRyFlH8Ti2riB5wVPhUk7nGkJnoCe428LR/wRGdYIlmWebCyxou1rCk4g/ShugBDX0V0ZQWkh0dOVsagkM0yV6OoLd5ye+pRlsCr0n+KiQrGuq5yJDzrTAXHtLUMduTDBVKrSm3eHL+6ijxhFDX9Z5gVU/wliHYTMiMFpKLNMEywu80wd3meoFmt6VbRMPenhrOc6DVe4pgXU8DnnHakLOIIrlF4FZPIw6R+zxBP0dyq6OOZ4Q5sLKCcz084ok+VsMMyQhNZmmBgX5xIXOEJTmi7VsGTvMTNdHHhpzdbE8Du2oKxgvBqQKdDDnTFOylCFaxR1syz2iqrOI/FEpNc3C6f11/7+ASS6l2inq2ciTrCCzgyemrCL5SVPjQkdPZUmGy2c9Sw9FtR1sS30RmsKPCS4rkIC/2U0MduwucYolGaPjKEyhzmiPYXagyWbYz8LWBDdzRimAXzxx4z8K9hpzlhLq+NiQ97HuKorMUfK/OVvC2JfiHUPCQI/q7J2gjK+tTDNxkCc4TMssqCs4TGtLVwQihyoAWgj9bosU80XGW6Ac9TJGziaUh5+hnFcHOnlaM1iRn29NaqGENTTTSUHCH2tWTeV0osUhH6psuVLjRUmGWhm6OZEshGeNowABHcJ2Bpy2ZszRcKkRXd2QuKVEeXnbfaEq825FguqfgfE2whlChSRMdron+LATTPQ2Z369t4B9C5gs/ylzv+CMmepIDPclFQl13W0rspPd1JOcbghGOEutqCv5qacURQl3dDKyvyJlqKXGPgcM9FfawJAMVmdcspcYKOZc4GjDYkFlK05olNMHyHn4zFNykyOxt99RkHlfwmiHo60l2EKI+mhreEKp080Tbug08BVPcgoqC5zWt+NLDTZ7oNSF51N1qie7Va3uCCwyZbkINf/NED6jzOsBdZjFN8oqG3wxVunqCSYYKf3EdhJyf9YWGf7tRU2oH3VHgPr1fe5J9hOgHd7xQ0y7qBwXr23aGErP0cm64JVjZwsOGqL+mhNgZmhJLW2oY4UhedsyBgzrCKrq7BmcpNVhR6jBPq64Vgi+kn6XE68pp8J5/+0wRHGOpsKenQn9DZntPzjRLZpDAdD2fnSgkG9tmIXnUwQ6WVighs7Yi2MxQ0N3CqYaCXkJ0oyOztMDJjmSSpcpvlrk0RMMOjmArQ04PRV1DO1FwhCVaUVPpKUM03JK5SxPsIWRu8/CGHi8UHChiqGFDTbSRJWeYUDDcH6vJWUxR4k1FXbMUwV6e4AJFXS8oMqsZKqzvYQ9DDQdZckY4aGsIhtlubbd2r3j4QBMoTamdPZk7O/Bf62lacZwneNjQoGcdVU7zJOd7ghsUHOkosagic6cnWc8+4gg285R6zZP5s1/LUbCKIznTwK36PkdwlOrl4U1LwfdCCa+IrvFkmgw1PCAUXKWo0sURXWcI2muKJlgyFzhynCY4RBOsqCjoI1R5zREco0n2Vt09BQtYSizgKNHfUmUrQ5UOCh51BFcLmY7umhYqXKQomOop8bUnWNNQcIiBcYaC6xzMNOS8JQQfeqKBmmglB+97ok/lfk3ygaHSyZaCRTzRxQo6GzLfa2jWBPepw+UmT7SQEJyiyRkhBLMVOfcoMjcK0eZChfUNzFAUzCsEN5vP/X1uP/n/aoMX+K+nw/Hjr/9xOo7j7Pju61tLcgvJpTWXNbfN5jLpi6VfCOviTktKlFusQixdEKWmEBUKNaIpjZRSSOXSgzaaKLdabrm1/9nZ+/f+vd/vz/v9+Xy+zZ7PRorYoZqyLrCwQdEAixxVOEXNNnjX2nUSRlkqGmWowk8lxR50JPy9Bo6qJXaXwNvREBvnThPEPrewryLhcAnj5WE15Fqi8W7R1sAuEu86S4ENikItFN4xkv9Af4nXSnUVcLiA9xzesFpivRRVeFKtsMRaKBhuSbjOELnAUtlSQUpXgdfB4Z1oSbnFEetbQ0IrAe+Y+pqnDcEJFj6S8LDZzZHwY4e3XONNlARraomNEt2bkvGsosA3ioyHm+6jCMbI59wqt4eeara28IzEmyPgoRaUOEDhTVdEJhmCoTWfC0p8aNkCp0oYqih2iqGi4yXeMkOsn4LdLLnmKfh/YogjNsPebeFGR4m9BJHLzB61XQ3BtpISfS2FugsK9FAtLWX1dCRcrCnUp44CNzuCowUZmxSRgYaE6Za0W2u/E7CVXCiI/UOR8aAm1+OSyE3mOUcwyc1zBBeoX1kiKy0Zfxck1Gsyulti11i83QTBF5Kg3pDQThFMVHiPSlK+0cSedng/VaS8bOZbtsBcTcZAR8JP5KeqQ1OYKAi20njdNNRpgnsU//K+JnaXJaGTomr7aYIphoRn9aeShJWKEq9LcozSF7QleEfDI5LYm5bgVkFkRwVDBCVu0DDIkGupo8TZBq+/pMQURYErJQmPKGKjNDkWOLx7Jd5QizdUweIaKrlP7SwJDhZvONjLkOsBBX9UpGxnydhXkfBLQ8IxgojQbLFnJf81JytSljclYYyEFyx0kVBvKWOFJmONpshGAcsduQY5giVNCV51eOdJYo/pLhbvM0uDHSevNKRcrKZIqnCtJeEsO95RoqcgGK4ocZcho1tTYtcZvH41pNQ7vA0WrhIfOSraIIntIAi+NXWCErdbkvrWwjRLrt0NKUdL6KSOscTOdMSOUtBHwL6OLA0vNSdynaWQEnCpIvKaIrJJEbvHkmuNhn6OjM8VkSGSqn1uYJCGHnq9I3aLhNME3t6GjIkO7xrNFumpyTNX/NrwX7CrIRiqqWijI9JO4d1iieykyfiposQIQ8YjjsjlBh6oHWbwRjgYJQn2NgSnNycmJAk3NiXhx44Sxykihxm8ybUwT1OVKySc7vi3OXVkdBJ4AyXBeksDXG0IhgtYY0lY5ahCD0ehborIk5aUWRJviMA7Xt5kyRjonrXENkm8yYqgs8VzgrJmClK20uMM3jRJ0FiQICQF9hdETlLQWRIb5ki6WDfWRPobvO6a4GP5mcOrNzDFELtTkONLh9dXE8xypEg7z8A9jkhrQ6Fhjlg/QVktJXxt4WXzT/03Q8IaQWSqIuEvloQ2mqC9Jfi7wRul4RX3pSPlzpoVlmCtI2jvKHCFhjcM3sN6lqF6HxnKelLjXWbwrpR4xzuCrTUZx2qq9oAh8p6ixCUGr78g8oyjRAtB5CZFwi80VerVpI0h+IeBxa6Zg6kWvpDHaioYYuEsRbDC3eOmC2JvGYLeioxGknL2UATNJN6hmtj1DlpLvDVmocYbrGCVJKOrg4X6DgddLA203BKMFngdJJFtFd7vJLm6KEpc5yjQrkk7M80SGe34X24nSex1Ra5Omgb71JKyg8SrU3i/kARKwWpH0kOGhKkObyfd0ZGjvyXlAkVZ4xRbYJ2irFMkFY1SwyWxr2oo4zlNiV+7zmaweFpT4kR3kaDAFW6xpSqzJay05FtYR4HmZhc9UxKbbfF2V8RG1MBmSaE+kmC6JnaRXK9gsiXhJHl/U0qM0WTcbyhwkYIvFGwjSbjfwhiJt8ZSQU+Bd5+marPMOkVkD0muxYLIfEuhh60x/J92itguihJSEMySVPQnTewnEm+620rTQEMsOfo4/kP/0ARvWjitlpSX7GxBgcMEsd3EEeYWvdytd+Saawi6aCIj1CkGb6Aj9rwhx16Cf3vAwFy5pyLhVonXzy51FDpdEblbkdJbUcEPDEFzQ8qNmhzzLTmmKWKbFCXeEuRabp6rxbvAtLF442QjQ+wEA9eL1xSR7Q0JXzlSHjJ4exq89yR0laScJ/FW6z4a73pFMEfDiRZvuvijIt86RaSFOl01riV2mD1UEvxGk/Geg5aWwGki1zgKPG9J2U8PEg8qYvMsZeytiTRXBMslCU8JSlxi8EabjwUldlDNLfzTUmCgxWsjqWCOHavYAqsknKFIO0yQ61VL5AVFxk6WhEaCAkdJgt9aSkzXlKNX2jEa79waYuc7gq0N3GDJGCBhoiTXUEPsdknCUE1CK0fwsiaylSF2uiDyO4XX3pFhNd7R4itFGc0k/ElBZwWvq+GC6szVeEoS/MZ+qylwpKNKv9Z469UOjqCjwlusicyTxG6VpNxcQ8IncoR4RhLbR+NdpGGmJWOcIzJGUuKPGpQg8rrG21dOMqQssJQ4RxH5jaUqnZuQ0F4Q+cjxLwPtpZbIAk3QTJHQWBE5S1BokoVtDd6lhqr9UpHSUxMcIYl9pojsb8h4SBOsMQcqvOWC2E8EVehqiJ1hrrAEbQxeK0NGZ0Gkq+guSRgniM23bIHVkqwx4hiHd7smaOyglyIyQuM978j4VS08J/A2G1KeMBRo4fBaSNhKUEZfQewVQ/C1I+MgfbEleEzCUw7mKXI0M3hd1EESVji8x5uQ41nxs1q4RMJCCXs7Iq9acpxn22oSDnQ/sJTxsCbHIYZiLyhY05TY0ZLIOQrGaSJDDN4t8pVaIrsqqFdEegtizc1iTew5Q4ayBDMUsQMkXocaYkc0hZua412siZ1rSXlR460zRJ5SlHGe5j801RLMlJTxtaOM3Q1pvxJ45zUlWFD7rsAbpfEm1JHxG0eh8w2R7QQVzBUw28FhFp5QZzq8t2rx2joqulYTWSuJdTYfWwqMFMcovFmSyJPNyLhE4E10pHzYjOC3huArRa571ZsGajQpQx38SBP5pyZB6lMU3khDnp0MBV51BE9o2E+TY5Ml2E8S7C0o6w1xvCZjf0HkVEHCzFoyNmqC+9wdcqN+Tp7jSDheE9ws8Y5V0NJCn2bk2tqSY4okdrEhx1iDN8cSudwepWmAGXKcJXK65H9to8jYQRH7SBF01ESUJdd0TayVInaWhLkOjlXE5irKGOnI6GSWGCJa482zBI9rCr0jyTVcEuzriC1vcr6mwFGSiqy5zMwxBH/TJHwjSPhL8+01kaaSUuMFKTcLEvaUePcrSmwn8DZrgikWb7CGPxkSjhQwrRk57tctmxLsb9sZvL9LSlyuSLlWkqOjwduo8b6Uv1DkmudIeFF2dHCgxVtk8dpIvHpBxhEOdhKk7OLIUSdJ+cSRY57B+0DgGUUlNfpthTfGkauzxrvTsUUaCVhlKeteTXCoJDCa2NOKhOmC4G1H8JBd4OBZReSRGkqcb/CO1PyLJTLB4j1q8JYaIutEjSLX8YKM+a6phdMsdLFUoV5RTm9JSkuDN8WcIon0NZMNZWh1q8C7SJEwV5HxrmnnTrf3KoJBlmCYI2ilSLlfEvlE4011NNgjgthzEua0oKK7JLE7HZHlEl60BLMVFewg4EWNt0ThrVNEVkkiTwpKXSWJzdRENgvKGq4IhjsiezgSFtsfCUq8qki5S1LRQeYQQ4nemmCkImWMw3tFUoUBZk4NOeZYEp4XRKTGa6wJjrWNHBVJR4m3FCnbuD6aak2WsMTh3SZImGCIPKNgsDpVwnsa70K31lCFJZYcwwSMFcQulGTsZuEaSdBXkPGZhu0FsdUO73RHjq8MPGGIfaGIbVTk6iuI3GFgucHrIQkmWSJdBd7BBu+uOryWAhY7+Lki9rK5wtEQzWwvtbqGhIMFwWRJsElsY4m9IIg9L6lCX0VklaPAYkfkZEGDnOWowlBJjtMUkcGK4Lg6EtoZInMUBVYLgn0UsdmCyCz7gIGHFfk+k1QwTh5We7A9x+IdJ6CvIkEagms0hR50eH9UnTQJ+2oiKyVlLFUE+8gBGu8MQ3CppUHesnjTHN4QB/UGPhCTHLFPHMFrCqa73gqObUJGa03wgbhHkrCfpEpzNLE7JDS25FMKhlhKKWKfCgqstLCPu1zBXy0J2ztwjtixBu8UTRn9LVtkmCN2iyFhtME70JHRQ1KVZXqKI/KNIKYMCYs1GUMEKbM1bKOI9LDXC7zbHS+bt+1MTWS9odA9DtrYtpbImQJ2VHh/lisEwaHqUk1kjKTAKknkBEXkbkdMGwq0dnhzLJF3NJH3JVwrqOB4Sca2hti75nmJN0WzxS6UxDYoEpxpa4htVlRjkYE7DZGzJVU72uC9IyhQL4i8YfGWSYLLNcHXloyz7QhNifmKSE9JgfGmuyLhc403Xm9vqcp6gXe3xuuv8F6VJNxkyTHEkHG2g0aKXL0MsXc1bGfgas2//dCONXiNLCX+5mB7eZIl1kHh7ajwpikyzlUUWOVOsjSQlsS+M0R+pPje/dzBXRZGO0rMtgQrLLG9VSu9n6CMXS3BhwYmSoIBhsjNBmZbgusE9BCPCP5triU4VhNbJfE+swSP27aayE8tuTpYYjtrYjMVGZdp2NpS1s6aBnKSHDsbKuplKbHM4a0wMFd/5/DmGyKrJSUaW4IBrqUhx0vyfzTBBLPIUcnZdrAkNsKR0sWRspumSns6Ch0v/qqIbBYUWKvPU/CFoyrDJGwSNFhbA/MlzKqjrO80hRbpKx0Jewsi/STftwGSlKc1JZyAzx05dhLEdnfQvhZOqiHWWEAHC7+30FuRcZUgaO5gpaIK+xsiHRUsqaPElTV40xQZQ107Q9BZE1nryDVGU9ZSQ47bmhBpLcYpUt7S+xuK/FiT8qKjwXYw5ypS2iuCv7q1gtgjhuBuB8LCFY5cUuCNtsQOFcT+4Ih9JX+k8Ea6v0iCIRZOtCT0Et00JW5UeC85Cg0ScK0k411HcG1zKtre3SeITBRk7WfwDhEvaYLTHP9le0m8By0JDwn4TlLW/aJOvGHxdjYUes+ScZigCkYQdNdEOhkiezgShqkx8ueKjI8lDfK2oNiOFvrZH1hS+tk7NV7nOmLHicGWEgubkXKdwdtZknCLJXaCpkrjZBtLZFsDP9CdxWsSr05Sxl6CMmoFbCOgryX40uDtamB7SVmXW4Ihlgpmq+00tBKUUa83WbjLUNkzDmY7cow1JDygyPGlhgGKYKz4vcV7QBNbJIgM11TUqZaMdwTeSguH6rOaw1JRKzaaGyxVm2EJ/uCIrVWUcZUkcp2grMsEjK+DMwS59jQk3Kd6SEq1d0S6uVmO4Bc1lDXTUcHjluCXEq+1OlBDj1pi9zgiXxnKuE0SqTXwhqbETW6RggMEnGl/q49UT2iCzgJvRwVXS2K/d6+ZkyUl7jawSVLit46EwxVljDZwoSQ20sDBihztHfk2yA8NVZghiXwrYHQdfKAOtzsayjhY9bY0yE2CWEeJ9xfzO423xhL5syS2TFJofO2pboHob0nY4GiAgRrvGQEDa/FWSsoaaYl0syRsEt3kWoH3B01shCXhTUWe9w3Bt44SC9QCh3eShQctwbaK2ApLroGCMlZrYqvlY3qYhM0aXpFkPOuoqJ3Dm6fxXrGwVF9gCWZagjPqznfkuMKQ8DPTQRO8ZqG1hPGKEm9IgpGW4DZDgTNriTxvFiq+Lz+0cKfp4wj6OCK9JSnzNSn9LFU7UhKZZMnYwcJ8s8yRsECScK4j5UOB95HFO0CzhY4xJxuCix0lDlEUeMdS6EZBkTsUkZ4K74dugyTXS7aNgL8aqjDfkCE0ZbwkCXpaWCKhl8P7VD5jxykivSyxyZrYERbe168LYu9ZYh86IkscgVLE7tWPKmJv11CgoyJltMEbrohtVAQfO4ImltiHEroYEs7RxAarVpY8AwXMcMReFOTYWe5iiLRQxJ5Q8DtJ8LQhWOhIeFESPGsILhbNDRljNbHzNRlTFbk2S3L0NOS6V1KFJYKUbSTcIIhM0wQ/s2TM0SRMNcQmSap3jCH4yhJZKSkwyRHpYYgsFeQ4U7xoCB7VVOExhXepo9ABBsYbvGWKXPME3lyH95YioZ0gssQRWWbI+FaSMkXijZXwgiTlYdPdkNLaETxlyDVIwqeaEus0aTcYcg0RVOkpR3CSJqIddK+90JCxzsDVloyrFd5ZAr4TBKfaWa6boEA7C7s6EpYaeFPjveooY72mjIccLHJ9HUwVlDhKkmutJDJBwnp1rvulJZggKDRfbXAkvC/4l3ozQOG9a8lxjx0i7nV4jSXc7vhe3OwIxjgSHjdEhhsif9YkPGlus3iLFDnWOFhtCZbJg0UbQcIaR67JjthoCyMEZRwhiXWyxO5QxI6w5NhT4U1WsJvDO60J34fW9hwzwlKij6ZAW9ne4L0s8C6XeBMEkd/LQy1VucBRot6QMlbivaBhoBgjqGiCJNhsqVp/S2SsG6DIONCR0dXhvWbJ+MRRZJkkuEjgDXJjFQW6SSL7GXK8Z2CZg7cVsbWGoKmEpzQ5elpiy8Ryg7dMkLLUEauzeO86CuwlSOlgYLojZWeJ9xM3S1PWfEfKl5ISLQ0MEKR8YOB2QfCxJBjrKPCN4f9MkaSsqoVXJBmP7EpFZ9UQfOoOFwSzBN4MQ8LsGrymlipcJQhmy0GaQjPqCHaXRwuCZwRbqK2Fg9wlClZqYicrIgMdZfxTQ0c7TBIbrChxmuzoKG8XRaSrIhhiyNFJkrC7oIAWMEOQa5aBekPCRknCo4IKPrYkvCDI8aYmY7WFtprgekcJZ3oLIqssCSMtFbQTJKwXYy3BY5oCh2iKPCpJOE+zRdpYgi6O2KmOAgvVCYaU4ySRek1sgyFhJ403QFHiVEmJHwtybO1gs8Hr5+BETQX3War0qZngYGgtVZtoqd6vFSk/UwdZElYqyjrF4HXUeFspIi9IGKf4j92pKGAdCYMVsbcV3kRF0N+R8LUd5PCsIGWoxDtBkCI0nKofdJQxT+LtZflvuc8Q3CjwWkq8KwUpHzkK/NmSsclCL0nseQdj5FRH5CNHSgtLiW80Of5HU9Hhlsga9bnBq3fEVltKfO5IaSTmGjjc4J0otcP7QsJUSQM8pEj5/wCuUuC2DWz8AAAAAElFTkSuQmCC\");\n}\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/theme/base16-dark.css",
    "content": "/*\n\n    Name:       Base16 Default Dark\n    Author:     Chris Kempson (http://chriskempson.com)\n\n    CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-chrome-devtools)\n    Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)\n\n*/\n\n.cm-s-base16-dark.CodeMirror {background: #151515; color: #e0e0e0;}\n.cm-s-base16-dark div.CodeMirror-selected {background: #303030 !important;}\n.cm-s-base16-dark.CodeMirror ::selection { background: rgba(48, 48, 48, .99); }\n.cm-s-base16-dark.CodeMirror ::-moz-selection { background: rgba(48, 48, 48, .99); }\n.cm-s-base16-dark .CodeMirror-gutters {background: #151515; border-right: 0px;}\n.cm-s-base16-dark .CodeMirror-guttermarker { color: #ac4142; }\n.cm-s-base16-dark .CodeMirror-guttermarker-subtle { color: #505050; }\n.cm-s-base16-dark .CodeMirror-linenumber {color: #505050;}\n.cm-s-base16-dark .CodeMirror-cursor {border-left: 1px solid #b0b0b0 !important;}\n\n.cm-s-base16-dark span.cm-comment {color: #8f5536;}\n.cm-s-base16-dark span.cm-atom {color: #aa759f;}\n.cm-s-base16-dark span.cm-number {color: #aa759f;}\n\n.cm-s-base16-dark span.cm-property, .cm-s-base16-dark span.cm-attribute {color: #90a959;}\n.cm-s-base16-dark span.cm-keyword {color: #ac4142;}\n.cm-s-base16-dark span.cm-string {color: #f4bf75;}\n\n.cm-s-base16-dark span.cm-variable {color: #90a959;}\n.cm-s-base16-dark span.cm-variable-2 {color: #6a9fb5;}\n.cm-s-base16-dark span.cm-def {color: #d28445;}\n.cm-s-base16-dark span.cm-bracket {color: #e0e0e0;}\n.cm-s-base16-dark span.cm-tag {color: #ac4142;}\n.cm-s-base16-dark span.cm-link {color: #aa759f;}\n.cm-s-base16-dark span.cm-error {background: #ac4142; color: #b0b0b0;}\n\n.cm-s-base16-dark .CodeMirror-activeline-background {background: #202020 !important;}\n.cm-s-base16-dark .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;}\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/theme/base16-light.css",
    "content": "/*\n\n    Name:       Base16 Default Light\n    Author:     Chris Kempson (http://chriskempson.com)\n\n    CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-chrome-devtools)\n    Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)\n\n*/\n\n.cm-s-base16-light.CodeMirror {background: #f5f5f5; color: #202020;}\n.cm-s-base16-light div.CodeMirror-selected {background: #e0e0e0 !important;}\n.cm-s-base16-light.CodeMirror ::selection { background: #e0e0e0; }\n.cm-s-base16-light.CodeMirror ::-moz-selection { background: #e0e0e0; }\n.cm-s-base16-light .CodeMirror-gutters {background: #f5f5f5; border-right: 0px;}\n.cm-s-base16-light .CodeMirror-guttermarker { color: #ac4142; }\n.cm-s-base16-light .CodeMirror-guttermarker-subtle { color: #b0b0b0; }\n.cm-s-base16-light .CodeMirror-linenumber {color: #b0b0b0;}\n.cm-s-base16-light .CodeMirror-cursor {border-left: 1px solid #505050 !important;}\n\n.cm-s-base16-light span.cm-comment {color: #8f5536;}\n.cm-s-base16-light span.cm-atom {color: #aa759f;}\n.cm-s-base16-light span.cm-number {color: #aa759f;}\n\n.cm-s-base16-light span.cm-property, .cm-s-base16-light span.cm-attribute {color: #90a959;}\n.cm-s-base16-light span.cm-keyword {color: #ac4142;}\n.cm-s-base16-light span.cm-string {color: #f4bf75;}\n\n.cm-s-base16-light span.cm-variable {color: #90a959;}\n.cm-s-base16-light span.cm-variable-2 {color: #6a9fb5;}\n.cm-s-base16-light span.cm-def {color: #d28445;}\n.cm-s-base16-light span.cm-bracket {color: #202020;}\n.cm-s-base16-light span.cm-tag {color: #ac4142;}\n.cm-s-base16-light span.cm-link {color: #aa759f;}\n.cm-s-base16-light span.cm-error {background: #ac4142; color: #505050;}\n\n.cm-s-base16-light .CodeMirror-activeline-background {background: #DDDCDC !important;}\n.cm-s-base16-light .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;}\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/theme/blackboard.css",
    "content": "/* Port of TextMate's Blackboard theme */\n\n.cm-s-blackboard.CodeMirror { background: #0C1021; color: #F8F8F8; }\n.cm-s-blackboard .CodeMirror-selected { background: #253B76 !important; }\n.cm-s-blackboard.CodeMirror ::selection { background: rgba(37, 59, 118, .99); }\n.cm-s-blackboard.CodeMirror ::-moz-selection { background: rgba(37, 59, 118, .99); }\n.cm-s-blackboard .CodeMirror-gutters { background: #0C1021; border-right: 0; }\n.cm-s-blackboard .CodeMirror-guttermarker { color: #FBDE2D; }\n.cm-s-blackboard .CodeMirror-guttermarker-subtle { color: #888; }\n.cm-s-blackboard .CodeMirror-linenumber { color: #888; }\n.cm-s-blackboard .CodeMirror-cursor { border-left: 1px solid #A7A7A7 !important; }\n\n.cm-s-blackboard .cm-keyword { color: #FBDE2D; }\n.cm-s-blackboard .cm-atom { color: #D8FA3C; }\n.cm-s-blackboard .cm-number { color: #D8FA3C; }\n.cm-s-blackboard .cm-def { color: #8DA6CE; }\n.cm-s-blackboard .cm-variable { color: #FF6400; }\n.cm-s-blackboard .cm-operator { color: #FBDE2D;}\n.cm-s-blackboard .cm-comment { color: #AEAEAE; }\n.cm-s-blackboard .cm-string { color: #61CE3C; }\n.cm-s-blackboard .cm-string-2 { color: #61CE3C; }\n.cm-s-blackboard .cm-meta { color: #D8FA3C; }\n.cm-s-blackboard .cm-builtin { color: #8DA6CE; }\n.cm-s-blackboard .cm-tag { color: #8DA6CE; }\n.cm-s-blackboard .cm-attribute { color: #8DA6CE; }\n.cm-s-blackboard .cm-header { color: #FF6400; }\n.cm-s-blackboard .cm-hr { color: #AEAEAE; }\n.cm-s-blackboard .cm-link { color: #8DA6CE; }\n.cm-s-blackboard .cm-error { background: #9D1E15; color: #F8F8F8; }\n\n.cm-s-blackboard .CodeMirror-activeline-background {background: #3C3636 !important;}\n.cm-s-blackboard .CodeMirror-matchingbracket {outline:1px solid grey;color:white !important}"
  },
  {
    "path": "Public/editor.md/lib/codemirror/theme/cobalt.css",
    "content": ".cm-s-cobalt.CodeMirror { background: #002240; color: white; }\n.cm-s-cobalt div.CodeMirror-selected { background: #b36539 !important; }\n.cm-s-cobalt.CodeMirror ::selection { background: rgba(179, 101, 57, .99); }\n.cm-s-cobalt.CodeMirror ::-moz-selection { background: rgba(179, 101, 57, .99); }\n.cm-s-cobalt .CodeMirror-gutters { background: #002240; border-right: 1px solid #aaa; }\n.cm-s-cobalt .CodeMirror-guttermarker { color: #ffee80; }\n.cm-s-cobalt .CodeMirror-guttermarker-subtle { color: #d0d0d0; }\n.cm-s-cobalt .CodeMirror-linenumber { color: #d0d0d0; }\n.cm-s-cobalt .CodeMirror-cursor { border-left: 1px solid white !important; }\n\n.cm-s-cobalt span.cm-comment { color: #08f; }\n.cm-s-cobalt span.cm-atom { color: #845dc4; }\n.cm-s-cobalt span.cm-number, .cm-s-cobalt span.cm-attribute { color: #ff80e1; }\n.cm-s-cobalt span.cm-keyword { color: #ffee80; }\n.cm-s-cobalt span.cm-string { color: #3ad900; }\n.cm-s-cobalt span.cm-meta { color: #ff9d00; }\n.cm-s-cobalt span.cm-variable-2, .cm-s-cobalt span.cm-tag { color: #9effff; }\n.cm-s-cobalt span.cm-variable-3, .cm-s-cobalt span.cm-def { color: white; }\n.cm-s-cobalt span.cm-bracket { color: #d8d8d8; }\n.cm-s-cobalt span.cm-builtin, .cm-s-cobalt span.cm-special { color: #ff9e59; }\n.cm-s-cobalt span.cm-link { color: #845dc4; }\n.cm-s-cobalt span.cm-error { color: #9d1e15; }\n\n.cm-s-cobalt .CodeMirror-activeline-background {background: #002D57 !important;}\n.cm-s-cobalt .CodeMirror-matchingbracket {outline:1px solid grey;color:white !important}\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/theme/colorforth.css",
    "content": ".cm-s-colorforth.CodeMirror { background: #000000; color: #f8f8f8; }\n.cm-s-colorforth .CodeMirror-gutters { background: #0a001f; border-right: 1px solid #aaa; }\n.cm-s-colorforth .CodeMirror-guttermarker { color: #FFBD40; }\n.cm-s-colorforth .CodeMirror-guttermarker-subtle { color: #78846f; }\n.cm-s-colorforth .CodeMirror-linenumber { color: #bababa; }\n.cm-s-colorforth .CodeMirror-cursor { border-left: 1px solid white !important; }\n\n.cm-s-colorforth span.cm-comment     { color: #ededed; }\n.cm-s-colorforth span.cm-def         { color: #ff1c1c; font-weight:bold; }\n.cm-s-colorforth span.cm-keyword     { color: #ffd900; }\n.cm-s-colorforth span.cm-builtin     { color: #00d95a; }\n.cm-s-colorforth span.cm-variable    { color: #73ff00; }\n.cm-s-colorforth span.cm-string      { color: #007bff; }\n.cm-s-colorforth span.cm-number      { color: #00c4ff; }\n.cm-s-colorforth span.cm-atom        { color: #606060; }\n\n.cm-s-colorforth span.cm-variable-2  { color: #EEE; }\n.cm-s-colorforth span.cm-variable-3  { color: #DDD; }\n.cm-s-colorforth span.cm-property    {}\n.cm-s-colorforth span.cm-operator    {}\n\n.cm-s-colorforth span.cm-meta        { color: yellow; }\n.cm-s-colorforth span.cm-qualifier   { color: #FFF700; }\n.cm-s-colorforth span.cm-bracket     { color: #cc7; }\n.cm-s-colorforth span.cm-tag         { color: #FFBD40; }\n.cm-s-colorforth span.cm-attribute   { color: #FFF700; }\n.cm-s-colorforth span.cm-error       { color: #f00; }\n\n.cm-s-colorforth .CodeMirror-selected { background: #333d53 !important; }\n\n.cm-s-colorforth span.cm-compilation { background: rgba(255, 255, 255, 0.12); }\n\n.cm-s-colorforth .CodeMirror-activeline-background {background: #253540 !important;}\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/theme/eclipse.css",
    "content": ".cm-s-eclipse span.cm-meta {color: #FF1717;}\n.cm-s-eclipse span.cm-keyword { line-height: 1em; font-weight: bold; color: #7F0055; }\n.cm-s-eclipse span.cm-atom {color: #219;}\n.cm-s-eclipse span.cm-number {color: #164;}\n.cm-s-eclipse span.cm-def {color: #00f;}\n.cm-s-eclipse span.cm-variable {color: black;}\n.cm-s-eclipse span.cm-variable-2 {color: #0000C0;}\n.cm-s-eclipse span.cm-variable-3 {color: #0000C0;}\n.cm-s-eclipse span.cm-property {color: black;}\n.cm-s-eclipse span.cm-operator {color: black;}\n.cm-s-eclipse span.cm-comment {color: #3F7F5F;}\n.cm-s-eclipse span.cm-string {color: #2A00FF;}\n.cm-s-eclipse span.cm-string-2 {color: #f50;}\n.cm-s-eclipse span.cm-qualifier {color: #555;}\n.cm-s-eclipse span.cm-builtin {color: #30a;}\n.cm-s-eclipse span.cm-bracket {color: #cc7;}\n.cm-s-eclipse span.cm-tag {color: #170;}\n.cm-s-eclipse span.cm-attribute {color: #00c;}\n.cm-s-eclipse span.cm-link {color: #219;}\n.cm-s-eclipse span.cm-error {color: #f00;}\n\n.cm-s-eclipse .CodeMirror-activeline-background {background: #e8f2ff !important;}\n.cm-s-eclipse .CodeMirror-matchingbracket {outline:1px solid grey; color:black !important;}\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/theme/elegant.css",
    "content": ".cm-s-elegant span.cm-number, .cm-s-elegant span.cm-string, .cm-s-elegant span.cm-atom {color: #762;}\n.cm-s-elegant span.cm-comment {color: #262; font-style: italic; line-height: 1em;}\n.cm-s-elegant span.cm-meta {color: #555; font-style: italic; line-height: 1em;}\n.cm-s-elegant span.cm-variable {color: black;}\n.cm-s-elegant span.cm-variable-2 {color: #b11;}\n.cm-s-elegant span.cm-qualifier {color: #555;}\n.cm-s-elegant span.cm-keyword {color: #730;}\n.cm-s-elegant span.cm-builtin {color: #30a;}\n.cm-s-elegant span.cm-link {color: #762;}\n.cm-s-elegant span.cm-error {background-color: #fdd;}\n\n.cm-s-elegant .CodeMirror-activeline-background {background: #e8f2ff !important;}\n.cm-s-elegant .CodeMirror-matchingbracket {outline:1px solid grey; color:black !important;}\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/theme/erlang-dark.css",
    "content": ".cm-s-erlang-dark.CodeMirror { background: #002240; color: white; }\n.cm-s-erlang-dark div.CodeMirror-selected { background: #b36539 !important; }\n.cm-s-erlang-dark.CodeMirror ::selection { background: rgba(179, 101, 57, .99); }\n.cm-s-erlang-dark.CodeMirror ::-moz-selection { background: rgba(179, 101, 57, .99); }\n.cm-s-erlang-dark .CodeMirror-gutters { background: #002240; border-right: 1px solid #aaa; }\n.cm-s-erlang-dark .CodeMirror-guttermarker { color: white; }\n.cm-s-erlang-dark .CodeMirror-guttermarker-subtle { color: #d0d0d0; }\n.cm-s-erlang-dark .CodeMirror-linenumber { color: #d0d0d0; }\n.cm-s-erlang-dark .CodeMirror-cursor { border-left: 1px solid white !important; }\n\n.cm-s-erlang-dark span.cm-atom       { color: #f133f1; }\n.cm-s-erlang-dark span.cm-attribute  { color: #ff80e1; }\n.cm-s-erlang-dark span.cm-bracket    { color: #ff9d00; }\n.cm-s-erlang-dark span.cm-builtin    { color: #eaa; }\n.cm-s-erlang-dark span.cm-comment    { color: #77f; }\n.cm-s-erlang-dark span.cm-def        { color: #e7a; }\n.cm-s-erlang-dark span.cm-keyword    { color: #ffee80; }\n.cm-s-erlang-dark span.cm-meta       { color: #50fefe; }\n.cm-s-erlang-dark span.cm-number     { color: #ffd0d0; }\n.cm-s-erlang-dark span.cm-operator   { color: #d55; }\n.cm-s-erlang-dark span.cm-property   { color: #ccc; }\n.cm-s-erlang-dark span.cm-qualifier  { color: #ccc; }\n.cm-s-erlang-dark span.cm-quote      { color: #ccc; }\n.cm-s-erlang-dark span.cm-special    { color: #ffbbbb; }\n.cm-s-erlang-dark span.cm-string     { color: #3ad900; }\n.cm-s-erlang-dark span.cm-string-2   { color: #ccc; }\n.cm-s-erlang-dark span.cm-tag        { color: #9effff; }\n.cm-s-erlang-dark span.cm-variable   { color: #50fe50; }\n.cm-s-erlang-dark span.cm-variable-2 { color: #e0e; }\n.cm-s-erlang-dark span.cm-variable-3 { color: #ccc; }\n.cm-s-erlang-dark span.cm-error      { color: #9d1e15; }\n\n.cm-s-erlang-dark .CodeMirror-activeline-background {background: #013461 !important;}\n.cm-s-erlang-dark .CodeMirror-matchingbracket {outline:1px solid grey; color:white !important;}\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/theme/lesser-dark.css",
    "content": "/*\nhttp://lesscss.org/ dark theme\nPorted to CodeMirror by Peter Kroon\n*/\n.cm-s-lesser-dark {\n  line-height: 1.3em;\n}\n.cm-s-lesser-dark.CodeMirror { background: #262626; color: #EBEFE7; text-shadow: 0 -1px 1px #262626; }\n.cm-s-lesser-dark div.CodeMirror-selected {background: #45443B !important;} /* 33322B*/\n.cm-s-lesser-dark.CodeMirror ::selection { background: rgba(69, 68, 59, .99); }\n.cm-s-lesser-dark.CodeMirror ::-moz-selection { background: rgba(69, 68, 59, .99); }\n.cm-s-lesser-dark .CodeMirror-cursor { border-left: 1px solid white !important; }\n.cm-s-lesser-dark pre { padding: 0 8px; }/*editable code holder*/\n\n.cm-s-lesser-dark.CodeMirror span.CodeMirror-matchingbracket { color: #7EFC7E; }/*65FC65*/\n\n.cm-s-lesser-dark .CodeMirror-gutters { background: #262626; border-right:1px solid #aaa; }\n.cm-s-lesser-dark .CodeMirror-guttermarker { color: #599eff; }\n.cm-s-lesser-dark .CodeMirror-guttermarker-subtle { color: #777; }\n.cm-s-lesser-dark .CodeMirror-linenumber { color: #777; }\n\n.cm-s-lesser-dark span.cm-keyword { color: #599eff; }\n.cm-s-lesser-dark span.cm-atom { color: #C2B470; }\n.cm-s-lesser-dark span.cm-number { color: #B35E4D; }\n.cm-s-lesser-dark span.cm-def {color: white;}\n.cm-s-lesser-dark span.cm-variable { color:#D9BF8C; }\n.cm-s-lesser-dark span.cm-variable-2 { color: #669199; }\n.cm-s-lesser-dark span.cm-variable-3 { color: white; }\n.cm-s-lesser-dark span.cm-property {color: #92A75C;}\n.cm-s-lesser-dark span.cm-operator {color: #92A75C;}\n.cm-s-lesser-dark span.cm-comment { color: #666; }\n.cm-s-lesser-dark span.cm-string { color: #BCD279; }\n.cm-s-lesser-dark span.cm-string-2 {color: #f50;}\n.cm-s-lesser-dark span.cm-meta { color: #738C73; }\n.cm-s-lesser-dark span.cm-qualifier {color: #555;}\n.cm-s-lesser-dark span.cm-builtin { color: #ff9e59; }\n.cm-s-lesser-dark span.cm-bracket { color: #EBEFE7; }\n.cm-s-lesser-dark span.cm-tag { color: #669199; }\n.cm-s-lesser-dark span.cm-attribute {color: #00c;}\n.cm-s-lesser-dark span.cm-header {color: #a0a;}\n.cm-s-lesser-dark span.cm-quote {color: #090;}\n.cm-s-lesser-dark span.cm-hr {color: #999;}\n.cm-s-lesser-dark span.cm-link {color: #00c;}\n.cm-s-lesser-dark span.cm-error { color: #9d1e15; }\n\n.cm-s-lesser-dark .CodeMirror-activeline-background {background: #3C3A3A !important;}\n.cm-s-lesser-dark .CodeMirror-matchingbracket {outline:1px solid grey; color:white !important;}\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/theme/mbo.css",
    "content": "/****************************************************************/\n/*   Based on mbonaci's Brackets mbo theme                      */\n/*   https://github.com/mbonaci/global/blob/master/Mbo.tmTheme  */\n/*   Create your own: http://tmtheme-editor.herokuapp.com       */\n/****************************************************************/\n\n.cm-s-mbo.CodeMirror {background: #2c2c2c; color: #ffffec;}\n.cm-s-mbo div.CodeMirror-selected {background: #716C62 !important;}\n.cm-s-mbo.CodeMirror ::selection { background: rgba(113, 108, 98, .99); }\n.cm-s-mbo.CodeMirror ::-moz-selection { background: rgba(113, 108, 98, .99); }\n.cm-s-mbo .CodeMirror-gutters {background: #4e4e4e; border-right: 0px;}\n.cm-s-mbo .CodeMirror-guttermarker { color: white; }\n.cm-s-mbo .CodeMirror-guttermarker-subtle { color: grey; }\n.cm-s-mbo .CodeMirror-linenumber {color: #dadada;}\n.cm-s-mbo .CodeMirror-cursor {border-left: 1px solid #ffffec !important;}\n\n.cm-s-mbo span.cm-comment {color: #95958a;}\n.cm-s-mbo span.cm-atom {color: #00a8c6;}\n.cm-s-mbo span.cm-number {color: #00a8c6;}\n\n.cm-s-mbo span.cm-property, .cm-s-mbo span.cm-attribute {color: #9ddfe9;}\n.cm-s-mbo span.cm-keyword {color: #ffb928;}\n.cm-s-mbo span.cm-string {color: #ffcf6c;}\n.cm-s-mbo span.cm-string.cm-property {color: #ffffec;}\n\n.cm-s-mbo span.cm-variable {color: #ffffec;}\n.cm-s-mbo span.cm-variable-2 {color: #00a8c6;}\n.cm-s-mbo span.cm-def {color: #ffffec;}\n.cm-s-mbo span.cm-bracket {color: #fffffc; font-weight: bold;}\n.cm-s-mbo span.cm-tag {color: #9ddfe9;}\n.cm-s-mbo span.cm-link {color: #f54b07;}\n.cm-s-mbo span.cm-error {border-bottom: #636363; color: #ffffec;}\n.cm-s-mbo span.cm-qualifier {color: #ffffec;}\n\n.cm-s-mbo .CodeMirror-activeline-background {background: #494b41 !important;}\n.cm-s-mbo .CodeMirror-matchingbracket {color: #222 !important;}\n.cm-s-mbo .CodeMirror-matchingtag {background: rgba(255, 255, 255, .37);}\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/theme/mdn-like.css",
    "content": "/*\n  MDN-LIKE Theme - Mozilla\n  Ported to CodeMirror by Peter Kroon <plakroon@gmail.com>\n  Report bugs/issues here: https://github.com/codemirror/CodeMirror/issues\n  GitHub: @peterkroon\n\n  The mdn-like theme is inspired on the displayed code examples at: https://developer.mozilla.org/en-US/docs/Web/CSS/animation\n\n*/\n.cm-s-mdn-like.CodeMirror { color: #999; background-color: #fff; }\n.cm-s-mdn-like .CodeMirror-selected { background: #cfc !important; }\n.cm-s-mdn-like.CodeMirror ::selection { background: #cfc; }\n.cm-s-mdn-like.CodeMirror ::-moz-selection { background: #cfc; }\n\n.cm-s-mdn-like .CodeMirror-gutters { background: #f8f8f8; border-left: 6px solid rgba(0,83,159,0.65); color: #333; }\n.cm-s-mdn-like .CodeMirror-linenumber { color: #aaa; margin-left: 3px; }\ndiv.cm-s-mdn-like .CodeMirror-cursor { border-left: 2px solid #222; }\n\n.cm-s-mdn-like .cm-keyword {  color: #6262FF; }\n.cm-s-mdn-like .cm-atom { color: #F90; }\n.cm-s-mdn-like .cm-number { color:  #ca7841; }\n.cm-s-mdn-like .cm-def { color: #8DA6CE; }\n.cm-s-mdn-like span.cm-variable-2, .cm-s-mdn-like span.cm-tag { color: #690; }\n.cm-s-mdn-like span.cm-variable-3, .cm-s-mdn-like span.cm-def { color: #07a; }\n\n.cm-s-mdn-like .cm-variable { color: #07a; }\n.cm-s-mdn-like .cm-property { color: #905; }\n.cm-s-mdn-like .cm-qualifier { color: #690; }\n\n.cm-s-mdn-like .cm-operator { color: #cda869; }\n.cm-s-mdn-like .cm-comment { color:#777; font-weight:normal; }\n.cm-s-mdn-like .cm-string { color:#07a; font-style:italic; }\n.cm-s-mdn-like .cm-string-2 { color:#bd6b18; } /*?*/\n.cm-s-mdn-like .cm-meta { color: #000; } /*?*/\n.cm-s-mdn-like .cm-builtin { color: #9B7536; } /*?*/\n.cm-s-mdn-like .cm-tag { color: #997643; }\n.cm-s-mdn-like .cm-attribute { color: #d6bb6d; } /*?*/\n.cm-s-mdn-like .cm-header { color: #FF6400; }\n.cm-s-mdn-like .cm-hr { color: #AEAEAE; }\n.cm-s-mdn-like .cm-link {   color:#ad9361; font-style:italic; text-decoration:none; }\n.cm-s-mdn-like .cm-error { border-bottom: 1px solid red; }\n\ndiv.cm-s-mdn-like .CodeMirror-activeline-background {background: #efefff;}\ndiv.cm-s-mdn-like span.CodeMirror-matchingbracket {outline:1px solid grey; color: inherit;}\n\n.cm-s-mdn-like.CodeMirror { background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFcAAAAyCAYAAAAp8UeFAAAHvklEQVR42s2b63bcNgyEQZCSHCdt2vd/0tWF7I+Q6XgMXiTtuvU5Pl57ZQKkKHzEAOtF5KeIJBGJ8uvL599FRFREZhFx8DeXv8trn68RuGaC8TRfo3SNp9dlDDHedyLyTUTeRWStXKPZrjtpZxaRw5hPqozRs1N8/enzIiQRWcCgy4MUA0f+XWliDhyL8Lfyvx7ei/Ae3iQFHyw7U/59pQVIMEEPEz0G7XiwdRjzSfC3UTtz9vchIntxvry5iMgfIhJoEflOz2CQr3F5h/HfeFe+GTdLaKcu9L8LTeQb/R/7GgbsfKedyNdoHsN31uRPWrfZ5wsj/NzzRQHuToIdU3ahwnsKPxXCjJITuOsi7XLc7SG/v5GdALs7wf8JjTFiB5+QvTEfRyGOfX3Lrx8wxyQi3sNq46O7QahQiCsRFgqddjBouVEHOKDgXAQHD9gJCr5sMKkEdjwsarG/ww3BMHBU7OBjXnzdyY7SfCxf5/z6ATccrwlKuwC/jhznnPF4CgVzhhVf4xp2EixcBActO75iZ8/fM9zAs2OMzKdslgXWJ9XG8PQoOAMA5fGcsvORgv0doBXyHrCwfLJAOwo71QLNkb8n2Pl6EWiR7OCibtkPaz4Kc/0NNAze2gju3zOwekALDaCFPI5vjPFmgGY5AZqyGEvH1x7QfIb8YtxMnA/b+QQ0aQDAwc6JMFg8CbQZ4qoYEEHbRwNojuK3EHwd7VALSgq+MNDKzfT58T8qdpADrgW0GmgcAS1lhzztJmkAzcPNOQbsWEALBDSlMKUG0Eq4CLAQWvEVQ9WU57gZJwZtgPO3r9oBTQ9WO8TjqXINx8R0EYpiZEUWOF3FxkbJkgU9B2f41YBrIj5ZfsQa0M5kTgiAAqM3ShXLgu8XMqcrQBvJ0CL5pnTsfMB13oB8athpAq2XOQmcGmoACCLydx7nToa23ATaSIY2ichfOdPTGxlasXMLaL0MLZAOwAKIM+y8CmicobGdCcbbK9DzN+yYGVoNNI5iUKTMyYOjPse4A8SM1MmcXgU0toOq1yO/v8FOxlASyc7TgeYaAMBJHcY1CcCwGI/TK4AmDbDyKYBBtFUkRwto8gygiQEaByFgJ00BH2M8JWwQS1nafDXQCidWyOI8AcjDCSjCLk8ngObuAm3JAHAdubAmOaK06V8MNEsKPJOhobSprwQa6gD7DclRQdqcwL4zxqgBrQcabUiBLclRDKAlWp+etPkBaNMA0AKlrHwTdEByZAA4GM+SNluSY6wAzcMNewxmgig5Ks0nkrSpBvSaQHMdKTBAnLojOdYyGpQ254602ZILPdTD1hdlggdIm74jbTp8vDwF5ZYUeLWGJpWsh6XNyXgcYwVoJQTEhhTYkxzZjiU5npU2TaB979TQehlaAVq4kaGpiPwwwLkYUuBbQwocyQTv1tA0+1UFWoJF3iv1oq+qoSk8EQdJmwHkziIF7oOZk14EGitibAdjLYYK78H5vZOhtWpoI0ATGHs0Q8OMb4Ey+2bU2UYztCtA0wFAs7TplGLRVQCcqaFdGSPCeTI1QNIC52iWNzof6Uib7xjEp07mNNoUYmVosVItHrHzRlLgBn9LFyRHaQCtVUMbtTNhoXWiTOO9k/V8BdAc1Oq0ArSQs6/5SU0hckNy9NnXqQY0PGYo5dWJ7nINaN6o958FWin27aBaWRka1r5myvLOAm0j30eBJqCxHLReVclxhxOEN2JfDWjxBtAC7MIH1fVaGdoOp4qJYDgKtKPSFNID2gSnGldrCqkFZ+5UeQXQBIRrSwocbdZYQT/2LwRahBPBXoHrB8nxaGROST62DKUbQOMMzZIC9abkuELfQzQALWTnDNAm8KHWFOJgJ5+SHIvTPcmx1xQyZRhNL5Qci689aXMEaN/uNIWkEwDAvFpOZmgsBaaGnbs1NPa1Jm32gBZAIh1pCtG7TSH4aE0y1uVY4uqoFPisGlpP2rSA5qTecWn5agK6BzSpgAyD+wFaqhnYoSZ1Vwr8CmlTQbrcO3ZaX0NAEyMbYaAlyquFoLKK3SPby9CeVUPThrSJmkCAE0CrKUQadi4DrdSlWhmah0YL9z9vClH59YGbHx1J8VZTyAjQepJjmXwAKTDQI3omc3p1U4gDUf6RfcdYfrUp5ClAi2J3Ba6UOXGo+K+bQrjjssitG2SJzshaLwMtXgRagUNpYYoVkMSBLM+9GGiJZMvduG6DRZ4qc04DMPtQQxOjEtACmhO7K1AbNbQDEggZyJwscFpAGwENhoBeUwh3bWolhe8BTYVKxQEWrSUn/uhcM5KhvUu/+eQu0Lzhi+VrK0PrZZNDQKs9cpYUuFYgMVpD4/NxenJTiMCNqdUEUf1qZWjppLT5qSkkUZbCwkbZMSuVnu80hfSkzRbQeqCZSAh6huR4VtoM2gHAlLf72smuWgE+VV7XpE25Ab2WFDgyhnSuKbs4GuGzCjR+tIoUuMFg3kgcWKLTwRqanJQ2W00hAsenfaApRC42hbCvK1SlE0HtE9BGgneJO+ELamitD1YjjOYnNYVcraGhtKkW0EqVVeDx733I2NH581k1NNxNLG0i0IJ8/NjVaOZ0tYZ2Vtr0Xv7tPV3hkWp9EFkgS/J0vosngTaSoaG06WHi+xObQkaAdlbanP8B2+2l0f90LmUAAAAASUVORK5CYII=); }\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/theme/midnight.css",
    "content": "/* Based on the theme at http://bonsaiden.github.com/JavaScript-Garden */\n\n/*<!--match-->*/\n.cm-s-midnight span.CodeMirror-matchhighlight { background: #494949; }\n.cm-s-midnight.CodeMirror-focused span.CodeMirror-matchhighlight { background: #314D67 !important; }\n\n/*<!--activeline-->*/\n.cm-s-midnight .CodeMirror-activeline-background {background: #253540 !important;}\n\n.cm-s-midnight.CodeMirror {\n    background: #0F192A;\n    color: #D1EDFF;\n}\n\n.cm-s-midnight.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}\n\n.cm-s-midnight div.CodeMirror-selected {background: #314D67 !important;}\n.cm-s-midnight.CodeMirror ::selection { background: rgba(49, 77, 103, .99); }\n.cm-s-midnight.CodeMirror ::-moz-selection { background: rgba(49, 77, 103, .99); }\n.cm-s-midnight .CodeMirror-gutters {background: #0F192A; border-right: 1px solid;}\n.cm-s-midnight .CodeMirror-guttermarker { color: white; }\n.cm-s-midnight .CodeMirror-guttermarker-subtle { color: #d0d0d0; }\n.cm-s-midnight .CodeMirror-linenumber {color: #D0D0D0;}\n.cm-s-midnight .CodeMirror-cursor {\n    border-left: 1px solid #F8F8F0 !important;\n}\n\n.cm-s-midnight span.cm-comment {color: #428BDD;}\n.cm-s-midnight span.cm-atom {color: #AE81FF;}\n.cm-s-midnight span.cm-number {color: #D1EDFF;}\n\n.cm-s-midnight span.cm-property, .cm-s-midnight span.cm-attribute {color: #A6E22E;}\n.cm-s-midnight span.cm-keyword {color: #E83737;}\n.cm-s-midnight span.cm-string {color: #1DC116;}\n\n.cm-s-midnight span.cm-variable {color: #FFAA3E;}\n.cm-s-midnight span.cm-variable-2 {color: #FFAA3E;}\n.cm-s-midnight span.cm-def {color: #4DD;}\n.cm-s-midnight span.cm-bracket {color: #D1EDFF;}\n.cm-s-midnight span.cm-tag {color: #449;}\n.cm-s-midnight span.cm-link {color: #AE81FF;}\n.cm-s-midnight span.cm-error {background: #F92672; color: #F8F8F0;}\n\n.cm-s-midnight .CodeMirror-matchingbracket {\n  text-decoration: underline;\n  color: white !important;\n}\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/theme/monokai.css",
    "content": "/* Based on Sublime Text's Monokai theme */\n\n.cm-s-monokai.CodeMirror {background: #272822; color: #f8f8f2;}\n.cm-s-monokai div.CodeMirror-selected {background: #49483E !important;}\n.cm-s-monokai.CodeMirror ::selection { background: rgba(73, 72, 62, .99); }\n.cm-s-monokai.CodeMirror ::-moz-selection { background: rgba(73, 72, 62, .99); }\n.cm-s-monokai .CodeMirror-gutters {background: #272822; border-right: 0px;}\n.cm-s-monokai .CodeMirror-guttermarker { color: white; }\n.cm-s-monokai .CodeMirror-guttermarker-subtle { color: #d0d0d0; }\n.cm-s-monokai .CodeMirror-linenumber {color: #d0d0d0;}\n.cm-s-monokai .CodeMirror-cursor {border-left: 1px solid #f8f8f0 !important;}\n\n.cm-s-monokai span.cm-comment {color: #75715e;}\n.cm-s-monokai span.cm-atom {color: #ae81ff;}\n.cm-s-monokai span.cm-number {color: #ae81ff;}\n\n.cm-s-monokai span.cm-property, .cm-s-monokai span.cm-attribute {color: #a6e22e;}\n.cm-s-monokai span.cm-keyword {color: #f92672;}\n.cm-s-monokai span.cm-string {color: #e6db74;}\n\n.cm-s-monokai span.cm-variable {color: #a6e22e;}\n.cm-s-monokai span.cm-variable-2 {color: #9effff;}\n.cm-s-monokai span.cm-def {color: #fd971f;}\n.cm-s-monokai span.cm-bracket {color: #f8f8f2;}\n.cm-s-monokai span.cm-tag {color: #f92672;}\n.cm-s-monokai span.cm-link {color: #ae81ff;}\n.cm-s-monokai span.cm-error {background: #f92672; color: #f8f8f0;}\n\n.cm-s-monokai .CodeMirror-activeline-background {background: #373831 !important;}\n.cm-s-monokai .CodeMirror-matchingbracket {\n  text-decoration: underline;\n  color: white !important;\n}\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/theme/neat.css",
    "content": ".cm-s-neat span.cm-comment { color: #a86; }\n.cm-s-neat span.cm-keyword { line-height: 1em; font-weight: bold; color: blue; }\n.cm-s-neat span.cm-string { color: #a22; }\n.cm-s-neat span.cm-builtin { line-height: 1em; font-weight: bold; color: #077; }\n.cm-s-neat span.cm-special { line-height: 1em; font-weight: bold; color: #0aa; }\n.cm-s-neat span.cm-variable { color: black; }\n.cm-s-neat span.cm-number, .cm-s-neat span.cm-atom { color: #3a3; }\n.cm-s-neat span.cm-meta {color: #555;}\n.cm-s-neat span.cm-link { color: #3a3; }\n\n.cm-s-neat .CodeMirror-activeline-background {background: #e8f2ff !important;}\n.cm-s-neat .CodeMirror-matchingbracket {outline:1px solid grey; color:black !important;}\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/theme/neo.css",
    "content": "/* neo theme for codemirror */\n\n/* Color scheme */\n\n.cm-s-neo.CodeMirror {\n  background-color:#ffffff;\n  color:#2e383c;\n  line-height:1.4375;\n}\n.cm-s-neo .cm-comment {color:#75787b}\n.cm-s-neo .cm-keyword, .cm-s-neo .cm-property {color:#1d75b3}\n.cm-s-neo .cm-atom,.cm-s-neo .cm-number {color:#75438a}\n.cm-s-neo .cm-node,.cm-s-neo .cm-tag {color:#9c3328}\n.cm-s-neo .cm-string {color:#b35e14}\n.cm-s-neo .cm-variable,.cm-s-neo .cm-qualifier {color:#047d65}\n\n\n/* Editor styling */\n\n.cm-s-neo pre {\n  padding:0;\n}\n\n.cm-s-neo .CodeMirror-gutters {\n  border:none;\n  border-right:10px solid transparent;\n  background-color:transparent;\n}\n\n.cm-s-neo .CodeMirror-linenumber {\n  padding:0;\n  color:#e0e2e5;\n}\n\n.cm-s-neo .CodeMirror-guttermarker { color: #1d75b3; }\n.cm-s-neo .CodeMirror-guttermarker-subtle { color: #e0e2e5; }\n\n.cm-s-neo div.CodeMirror-cursor {\n  width: auto;\n  border: 0;\n  background: rgba(155,157,162,0.37);\n  z-index: 1;\n}\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/theme/night.css",
    "content": "/* Loosely based on the Midnight Textmate theme */\n\n.cm-s-night.CodeMirror { background: #0a001f; color: #f8f8f8; }\n.cm-s-night div.CodeMirror-selected { background: #447 !important; }\n.cm-s-night.CodeMirror ::selection { background: rgba(68, 68, 119, .99); }\n.cm-s-night.CodeMirror ::-moz-selection { background: rgba(68, 68, 119, .99); }\n.cm-s-night .CodeMirror-gutters { background: #0a001f; border-right: 1px solid #aaa; }\n.cm-s-night .CodeMirror-guttermarker { color: white; }\n.cm-s-night .CodeMirror-guttermarker-subtle { color: #bbb; }\n.cm-s-night .CodeMirror-linenumber { color: #f8f8f8; }\n.cm-s-night .CodeMirror-cursor { border-left: 1px solid white !important; }\n\n.cm-s-night span.cm-comment { color: #6900a1; }\n.cm-s-night span.cm-atom { color: #845dc4; }\n.cm-s-night span.cm-number, .cm-s-night span.cm-attribute { color: #ffd500; }\n.cm-s-night span.cm-keyword { color: #599eff; }\n.cm-s-night span.cm-string { color: #37f14a; }\n.cm-s-night span.cm-meta { color: #7678e2; }\n.cm-s-night span.cm-variable-2, .cm-s-night span.cm-tag { color: #99b2ff; }\n.cm-s-night span.cm-variable-3, .cm-s-night span.cm-def { color: white; }\n.cm-s-night span.cm-bracket { color: #8da6ce; }\n.cm-s-night span.cm-comment { color: #6900a1; }\n.cm-s-night span.cm-builtin, .cm-s-night span.cm-special { color: #ff9e59; }\n.cm-s-night span.cm-link { color: #845dc4; }\n.cm-s-night span.cm-error { color: #9d1e15; }\n\n.cm-s-night .CodeMirror-activeline-background {background: #1C005A !important;}\n.cm-s-night .CodeMirror-matchingbracket {outline:1px solid grey; color:white !important;}\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/theme/paraiso-dark.css",
    "content": "/*\n\n    Name:       Paraíso (Dark)\n    Author:     Jan T. Sott\n\n    Color scheme by Jan T. Sott (https://github.com/idleberg/Paraiso-CodeMirror)\n    Inspired by the art of Rubens LP (http://www.rubenslp.com.br)\n\n*/\n\n.cm-s-paraiso-dark.CodeMirror {background: #2f1e2e; color: #b9b6b0;}\n.cm-s-paraiso-dark div.CodeMirror-selected {background: #41323f !important;}\n.cm-s-paraiso-dark.CodeMirror ::selection { background: rgba(65, 50, 63, .99); }\n.cm-s-paraiso-dark.CodeMirror ::-moz-selection { background: rgba(65, 50, 63, .99); }\n.cm-s-paraiso-dark .CodeMirror-gutters {background: #2f1e2e; border-right: 0px;}\n.cm-s-paraiso-dark .CodeMirror-guttermarker { color: #ef6155; }\n.cm-s-paraiso-dark .CodeMirror-guttermarker-subtle { color: #776e71; }\n.cm-s-paraiso-dark .CodeMirror-linenumber {color: #776e71;}\n.cm-s-paraiso-dark .CodeMirror-cursor {border-left: 1px solid #8d8687 !important;}\n\n.cm-s-paraiso-dark span.cm-comment {color: #e96ba8;}\n.cm-s-paraiso-dark span.cm-atom {color: #815ba4;}\n.cm-s-paraiso-dark span.cm-number {color: #815ba4;}\n\n.cm-s-paraiso-dark span.cm-property, .cm-s-paraiso-dark span.cm-attribute {color: #48b685;}\n.cm-s-paraiso-dark span.cm-keyword {color: #ef6155;}\n.cm-s-paraiso-dark span.cm-string {color: #fec418;}\n\n.cm-s-paraiso-dark span.cm-variable {color: #48b685;}\n.cm-s-paraiso-dark span.cm-variable-2 {color: #06b6ef;}\n.cm-s-paraiso-dark span.cm-def {color: #f99b15;}\n.cm-s-paraiso-dark span.cm-bracket {color: #b9b6b0;}\n.cm-s-paraiso-dark span.cm-tag {color: #ef6155;}\n.cm-s-paraiso-dark span.cm-link {color: #815ba4;}\n.cm-s-paraiso-dark span.cm-error {background: #ef6155; color: #8d8687;}\n\n.cm-s-paraiso-dark .CodeMirror-activeline-background {background: #4D344A !important;}\n.cm-s-paraiso-dark .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;}\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/theme/paraiso-light.css",
    "content": "/*\n\n    Name:       Paraíso (Light)\n    Author:     Jan T. Sott\n\n    Color scheme by Jan T. Sott (https://github.com/idleberg/Paraiso-CodeMirror)\n    Inspired by the art of Rubens LP (http://www.rubenslp.com.br)\n\n*/\n\n.cm-s-paraiso-light.CodeMirror {background: #e7e9db; color: #41323f;}\n.cm-s-paraiso-light div.CodeMirror-selected {background: #b9b6b0 !important;}\n.cm-s-paraiso-light.CodeMirror ::selection { background: #b9b6b0; }\n.cm-s-paraiso-light.CodeMirror ::-moz-selection { background: #b9b6b0; }\n.cm-s-paraiso-light .CodeMirror-gutters {background: #e7e9db; border-right: 0px;}\n.cm-s-paraiso-light .CodeMirror-guttermarker { color: black; }\n.cm-s-paraiso-light .CodeMirror-guttermarker-subtle { color: #8d8687; }\n.cm-s-paraiso-light .CodeMirror-linenumber {color: #8d8687;}\n.cm-s-paraiso-light .CodeMirror-cursor {border-left: 1px solid #776e71 !important;}\n\n.cm-s-paraiso-light span.cm-comment {color: #e96ba8;}\n.cm-s-paraiso-light span.cm-atom {color: #815ba4;}\n.cm-s-paraiso-light span.cm-number {color: #815ba4;}\n\n.cm-s-paraiso-light span.cm-property, .cm-s-paraiso-light span.cm-attribute {color: #48b685;}\n.cm-s-paraiso-light span.cm-keyword {color: #ef6155;}\n.cm-s-paraiso-light span.cm-string {color: #fec418;}\n\n.cm-s-paraiso-light span.cm-variable {color: #48b685;}\n.cm-s-paraiso-light span.cm-variable-2 {color: #06b6ef;}\n.cm-s-paraiso-light span.cm-def {color: #f99b15;}\n.cm-s-paraiso-light span.cm-bracket {color: #41323f;}\n.cm-s-paraiso-light span.cm-tag {color: #ef6155;}\n.cm-s-paraiso-light span.cm-link {color: #815ba4;}\n.cm-s-paraiso-light span.cm-error {background: #ef6155; color: #776e71;}\n\n.cm-s-paraiso-light .CodeMirror-activeline-background {background: #CFD1C4 !important;}\n.cm-s-paraiso-light .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;}\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/theme/pastel-on-dark.css",
    "content": "/**\n * Pastel On Dark theme ported from ACE editor\n * @license MIT\n * @copyright AtomicPages LLC 2014\n * @author Dennis Thompson, AtomicPages LLC\n * @version 1.1\n * @source https://github.com/atomicpages/codemirror-pastel-on-dark-theme\n */\n\n.cm-s-pastel-on-dark.CodeMirror {\n\tbackground: #2c2827;\n\tcolor: #8F938F;\n\tline-height: 1.5;\n\tfont-size: 14px;\n}\n.cm-s-pastel-on-dark div.CodeMirror-selected { background: rgba(221,240,255,0.2) !important; }\n.cm-s-pastel-on-dark.CodeMirror ::selection { background: rgba(221,240,255,0.2); }\n.cm-s-pastel-on-dark.CodeMirror ::-moz-selection { background: rgba(221,240,255,0.2); }\n\n.cm-s-pastel-on-dark .CodeMirror-gutters {\n\tbackground: #34302f;\n\tborder-right: 0px;\n\tpadding: 0 3px;\n}\n.cm-s-pastel-on-dark .CodeMirror-guttermarker { color: white; }\n.cm-s-pastel-on-dark .CodeMirror-guttermarker-subtle { color: #8F938F; }\n.cm-s-pastel-on-dark .CodeMirror-linenumber { color: #8F938F; }\n.cm-s-pastel-on-dark .CodeMirror-cursor { border-left: 1px solid #A7A7A7 !important; }\n.cm-s-pastel-on-dark span.cm-comment { color: #A6C6FF; }\n.cm-s-pastel-on-dark span.cm-atom { color: #DE8E30; }\n.cm-s-pastel-on-dark span.cm-number { color: #CCCCCC; }\n.cm-s-pastel-on-dark span.cm-property { color: #8F938F; }\n.cm-s-pastel-on-dark span.cm-attribute { color: #a6e22e; }\n.cm-s-pastel-on-dark span.cm-keyword { color: #AEB2F8; }\n.cm-s-pastel-on-dark span.cm-string { color: #66A968; }\n.cm-s-pastel-on-dark span.cm-variable { color: #AEB2F8; }\n.cm-s-pastel-on-dark span.cm-variable-2 { color: #BEBF55; }\n.cm-s-pastel-on-dark span.cm-variable-3 { color: #DE8E30; }\n.cm-s-pastel-on-dark span.cm-def { color: #757aD8; }\n.cm-s-pastel-on-dark span.cm-bracket { color: #f8f8f2; }\n.cm-s-pastel-on-dark span.cm-tag { color: #C1C144; }\n.cm-s-pastel-on-dark span.cm-link { color: #ae81ff; }\n.cm-s-pastel-on-dark span.cm-qualifier,.cm-s-pastel-on-dark span.cm-builtin { color: #C1C144; }\n.cm-s-pastel-on-dark span.cm-error {\n\tbackground: #757aD8;\n\tcolor: #f8f8f0;\n}\n.cm-s-pastel-on-dark .CodeMirror-activeline-background { background: rgba(255, 255, 255, 0.031) !important; }\n.cm-s-pastel-on-dark .CodeMirror-matchingbracket {\n\tborder: 1px solid rgba(255,255,255,0.25);\n\tcolor: #8F938F !important;\n\tmargin: -1px -1px 0 -1px;\n}\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/theme/rubyblue.css",
    "content": ".cm-s-rubyblue.CodeMirror { background: #112435; color: white; }\n.cm-s-rubyblue div.CodeMirror-selected { background: #38566F !important; }\n.cm-s-rubyblue.CodeMirror ::selection { background: rgba(56, 86, 111, 0.99); }\n.cm-s-rubyblue.CodeMirror ::-moz-selection { background: rgba(56, 86, 111, 0.99); }\n.cm-s-rubyblue .CodeMirror-gutters { background: #1F4661; border-right: 7px solid #3E7087; }\n.cm-s-rubyblue .CodeMirror-guttermarker { color: white; }\n.cm-s-rubyblue .CodeMirror-guttermarker-subtle { color: #3E7087; }\n.cm-s-rubyblue .CodeMirror-linenumber { color: white; }\n.cm-s-rubyblue .CodeMirror-cursor { border-left: 1px solid white !important; }\n\n.cm-s-rubyblue span.cm-comment { color: #999; font-style:italic; line-height: 1em; }\n.cm-s-rubyblue span.cm-atom { color: #F4C20B; }\n.cm-s-rubyblue span.cm-number, .cm-s-rubyblue span.cm-attribute { color: #82C6E0; }\n.cm-s-rubyblue span.cm-keyword { color: #F0F; }\n.cm-s-rubyblue span.cm-string { color: #F08047; }\n.cm-s-rubyblue span.cm-meta { color: #F0F; }\n.cm-s-rubyblue span.cm-variable-2, .cm-s-rubyblue span.cm-tag { color: #7BD827; }\n.cm-s-rubyblue span.cm-variable-3, .cm-s-rubyblue span.cm-def { color: white; }\n.cm-s-rubyblue span.cm-bracket { color: #F0F; }\n.cm-s-rubyblue span.cm-link { color: #F4C20B; }\n.cm-s-rubyblue span.CodeMirror-matchingbracket { color:#F0F !important; }\n.cm-s-rubyblue span.cm-builtin, .cm-s-rubyblue span.cm-special { color: #FF9D00; }\n.cm-s-rubyblue span.cm-error { color: #AF2018; }\n\n.cm-s-rubyblue .CodeMirror-activeline-background {background: #173047 !important;}\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/theme/solarized.css",
    "content": "/*\nSolarized theme for code-mirror\nhttp://ethanschoonover.com/solarized\n*/\n\n/*\nSolarized color pallet\nhttp://ethanschoonover.com/solarized/img/solarized-palette.png\n*/\n\n.solarized.base03 { color: #002b36; }\n.solarized.base02 { color: #073642; }\n.solarized.base01 { color: #586e75; }\n.solarized.base00 { color: #657b83; }\n.solarized.base0 { color: #839496; }\n.solarized.base1 { color: #93a1a1; }\n.solarized.base2 { color: #eee8d5; }\n.solarized.base3  { color: #fdf6e3; }\n.solarized.solar-yellow  { color: #b58900; }\n.solarized.solar-orange  { color: #cb4b16; }\n.solarized.solar-red { color: #dc322f; }\n.solarized.solar-magenta { color: #d33682; }\n.solarized.solar-violet  { color: #6c71c4; }\n.solarized.solar-blue { color: #268bd2; }\n.solarized.solar-cyan { color: #2aa198; }\n.solarized.solar-green { color: #859900; }\n\n/* Color scheme for code-mirror */\n\n.cm-s-solarized {\n  line-height: 1.45em;\n  color-profile: sRGB;\n  rendering-intent: auto;\n}\n.cm-s-solarized.cm-s-dark {\n  color: #839496;\n  background-color:  #002b36;\n  text-shadow: #002b36 0 1px;\n}\n.cm-s-solarized.cm-s-light {\n  background-color: #fdf6e3;\n  color: #657b83;\n  text-shadow: #eee8d5 0 1px;\n}\n\n.cm-s-solarized .CodeMirror-widget {\n  text-shadow: none;\n}\n\n\n.cm-s-solarized .cm-keyword { color: #cb4b16 }\n.cm-s-solarized .cm-atom { color: #d33682; }\n.cm-s-solarized .cm-number { color: #d33682; }\n.cm-s-solarized .cm-def { color: #2aa198; }\n\n.cm-s-solarized .cm-variable { color: #268bd2; }\n.cm-s-solarized .cm-variable-2 { color: #b58900; }\n.cm-s-solarized .cm-variable-3 { color: #6c71c4; }\n\n.cm-s-solarized .cm-property { color: #2aa198; }\n.cm-s-solarized .cm-operator {color: #6c71c4;}\n\n.cm-s-solarized .cm-comment { color: #586e75; font-style:italic; }\n\n.cm-s-solarized .cm-string { color: #859900; }\n.cm-s-solarized .cm-string-2 { color: #b58900; }\n\n.cm-s-solarized .cm-meta { color: #859900; }\n.cm-s-solarized .cm-qualifier { color: #b58900; }\n.cm-s-solarized .cm-builtin { color: #d33682; }\n.cm-s-solarized .cm-bracket { color: #cb4b16; }\n.cm-s-solarized .CodeMirror-matchingbracket { color: #859900; }\n.cm-s-solarized .CodeMirror-nonmatchingbracket { color: #dc322f; }\n.cm-s-solarized .cm-tag { color: #93a1a1 }\n.cm-s-solarized .cm-attribute {  color: #2aa198; }\n.cm-s-solarized .cm-header { color: #586e75; }\n.cm-s-solarized .cm-quote { color: #93a1a1; }\n.cm-s-solarized .cm-hr {\n  color: transparent;\n  border-top: 1px solid #586e75;\n  display: block;\n}\n.cm-s-solarized .cm-link { color: #93a1a1; cursor: pointer; }\n.cm-s-solarized .cm-special { color: #6c71c4; }\n.cm-s-solarized .cm-em {\n  color: #999;\n  text-decoration: underline;\n  text-decoration-style: dotted;\n}\n.cm-s-solarized .cm-strong { color: #eee; }\n.cm-s-solarized .cm-error,\n.cm-s-solarized .cm-invalidchar {\n  color: #586e75;\n  border-bottom: 1px dotted #dc322f;\n}\n\n.cm-s-solarized.cm-s-dark .CodeMirror-selected { background: #073642; }\n.cm-s-solarized.cm-s-dark.CodeMirror ::selection { background: rgba(7, 54, 66, 0.99); }\n.cm-s-solarized.cm-s-dark.CodeMirror ::-moz-selection { background: rgba(7, 54, 66, 0.99); }\n\n.cm-s-solarized.cm-s-light .CodeMirror-selected { background: #eee8d5; }\n.cm-s-solarized.cm-s-light.CodeMirror ::selection { background: #eee8d5; }\n.cm-s-solarized.cm-s-lightCodeMirror ::-moz-selection { background: #eee8d5; }\n\n/* Editor styling */\n\n\n\n/* Little shadow on the view-port of the buffer view */\n.cm-s-solarized.CodeMirror {\n  -moz-box-shadow: inset 7px 0 12px -6px #000;\n  -webkit-box-shadow: inset 7px 0 12px -6px #000;\n  box-shadow: inset 7px 0 12px -6px #000;\n}\n\n/* Gutter border and some shadow from it  */\n.cm-s-solarized .CodeMirror-gutters {\n  border-right: 1px solid;\n}\n\n/* Gutter colors and line number styling based of color scheme (dark / light) */\n\n/* Dark */\n.cm-s-solarized.cm-s-dark .CodeMirror-gutters {\n  background-color:  #002b36;\n  border-color: #00232c;\n}\n\n.cm-s-solarized.cm-s-dark .CodeMirror-linenumber {\n  text-shadow: #021014 0 -1px;\n}\n\n/* Light */\n.cm-s-solarized.cm-s-light .CodeMirror-gutters {\n  background-color: #fdf6e3;\n  border-color: #eee8d5;\n}\n\n/* Common */\n.cm-s-solarized .CodeMirror-linenumber {\n  color: #586e75;\n  padding: 0 5px;\n}\n.cm-s-solarized .CodeMirror-guttermarker-subtle { color: #586e75; }\n.cm-s-solarized.cm-s-dark .CodeMirror-guttermarker { color: #ddd; }\n.cm-s-solarized.cm-s-light .CodeMirror-guttermarker { color: #cb4b16; }\n\n.cm-s-solarized .CodeMirror-gutter .CodeMirror-gutter-text {\n  color: #586e75;\n}\n\n.cm-s-solarized .CodeMirror-lines .CodeMirror-cursor {\n  border-left: 1px solid #819090;\n}\n\n/*\nActive line. Negative margin compensates left padding of the text in the\nview-port\n*/\n.cm-s-solarized.cm-s-dark .CodeMirror-activeline-background {\n  background: rgba(255, 255, 255, 0.10);\n}\n.cm-s-solarized.cm-s-light .CodeMirror-activeline-background {\n  background: rgba(0, 0, 0, 0.10);\n}\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/theme/the-matrix.css",
    "content": ".cm-s-the-matrix.CodeMirror { background: #000000; color: #00FF00; }\n.cm-s-the-matrix div.CodeMirror-selected { background: #2D2D2D !important; }\n.cm-s-the-matrix.CodeMirror ::selection { background: rgba(45, 45, 45, 0.99); }\n.cm-s-the-matrix.CodeMirror ::-moz-selection { background: rgba(45, 45, 45, 0.99); }\n.cm-s-the-matrix .CodeMirror-gutters { background: #060; border-right: 2px solid #00FF00; }\n.cm-s-the-matrix .CodeMirror-guttermarker { color: #0f0; }\n.cm-s-the-matrix .CodeMirror-guttermarker-subtle { color: white; }\n.cm-s-the-matrix .CodeMirror-linenumber { color: #FFFFFF; }\n.cm-s-the-matrix .CodeMirror-cursor { border-left: 1px solid #00FF00 !important; }\n\n.cm-s-the-matrix span.cm-keyword {color: #008803; font-weight: bold;}\n.cm-s-the-matrix span.cm-atom {color: #3FF;}\n.cm-s-the-matrix span.cm-number {color: #FFB94F;}\n.cm-s-the-matrix span.cm-def {color: #99C;}\n.cm-s-the-matrix span.cm-variable {color: #F6C;}\n.cm-s-the-matrix span.cm-variable-2 {color: #C6F;}\n.cm-s-the-matrix span.cm-variable-3 {color: #96F;}\n.cm-s-the-matrix span.cm-property {color: #62FFA0;}\n.cm-s-the-matrix span.cm-operator {color: #999}\n.cm-s-the-matrix span.cm-comment {color: #CCCCCC;}\n.cm-s-the-matrix span.cm-string {color: #39C;}\n.cm-s-the-matrix span.cm-meta {color: #C9F;}\n.cm-s-the-matrix span.cm-qualifier {color: #FFF700;}\n.cm-s-the-matrix span.cm-builtin {color: #30a;}\n.cm-s-the-matrix span.cm-bracket {color: #cc7;}\n.cm-s-the-matrix span.cm-tag {color: #FFBD40;}\n.cm-s-the-matrix span.cm-attribute {color: #FFF700;}\n.cm-s-the-matrix span.cm-error {color: #FF0000;}\n\n.cm-s-the-matrix .CodeMirror-activeline-background {background: #040;}\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/theme/tomorrow-night-bright.css",
    "content": "/*\n\n    Name:       Tomorrow Night - Bright\n    Author:     Chris Kempson\n\n    Port done by Gerard Braad <me@gbraad.nl>\n\n*/\n\n.cm-s-tomorrow-night-bright.CodeMirror {background: #000000; color: #eaeaea;}\n.cm-s-tomorrow-night-bright div.CodeMirror-selected {background: #424242 !important;}\n.cm-s-tomorrow-night-bright .CodeMirror-gutters {background: #000000; border-right: 0px;}\n.cm-s-tomorrow-night-bright .CodeMirror-guttermarker { color: #e78c45; }\n.cm-s-tomorrow-night-bright .CodeMirror-guttermarker-subtle { color: #777; }\n.cm-s-tomorrow-night-bright .CodeMirror-linenumber {color: #424242;}\n.cm-s-tomorrow-night-bright .CodeMirror-cursor {border-left: 1px solid #6A6A6A !important;}\n\n.cm-s-tomorrow-night-bright span.cm-comment {color: #d27b53;}\n.cm-s-tomorrow-night-bright span.cm-atom {color: #a16a94;}\n.cm-s-tomorrow-night-bright span.cm-number {color: #a16a94;}\n\n.cm-s-tomorrow-night-bright span.cm-property, .cm-s-tomorrow-night-bright span.cm-attribute {color: #99cc99;}\n.cm-s-tomorrow-night-bright span.cm-keyword {color: #d54e53;}\n.cm-s-tomorrow-night-bright span.cm-string {color: #e7c547;}\n\n.cm-s-tomorrow-night-bright span.cm-variable {color: #b9ca4a;}\n.cm-s-tomorrow-night-bright span.cm-variable-2 {color: #7aa6da;}\n.cm-s-tomorrow-night-bright span.cm-def {color: #e78c45;}\n.cm-s-tomorrow-night-bright span.cm-bracket {color: #eaeaea;}\n.cm-s-tomorrow-night-bright span.cm-tag {color: #d54e53;}\n.cm-s-tomorrow-night-bright span.cm-link {color: #a16a94;}\n.cm-s-tomorrow-night-bright span.cm-error {background: #d54e53; color: #6A6A6A;}\n\n.cm-s-tomorrow-night-bright .CodeMirror-activeline-background {background: #2a2a2a !important;}\n.cm-s-tomorrow-night-bright .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;}\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/theme/tomorrow-night-eighties.css",
    "content": "/*\n\n    Name:       Tomorrow Night - Eighties\n    Author:     Chris Kempson\n\n    CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror)\n    Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)\n\n*/\n\n.cm-s-tomorrow-night-eighties.CodeMirror {background: #000000; color: #CCCCCC;}\n.cm-s-tomorrow-night-eighties div.CodeMirror-selected {background: #2D2D2D !important;}\n.cm-s-tomorrow-night-eighties.CodeMirror ::selection { background: rgba(45, 45, 45, 0.99); }\n.cm-s-tomorrow-night-eighties.CodeMirror ::-moz-selection { background: rgba(45, 45, 45, 0.99); }\n.cm-s-tomorrow-night-eighties .CodeMirror-gutters {background: #000000; border-right: 0px;}\n.cm-s-tomorrow-night-eighties .CodeMirror-guttermarker { color: #f2777a; }\n.cm-s-tomorrow-night-eighties .CodeMirror-guttermarker-subtle { color: #777; }\n.cm-s-tomorrow-night-eighties .CodeMirror-linenumber {color: #515151;}\n.cm-s-tomorrow-night-eighties .CodeMirror-cursor {border-left: 1px solid #6A6A6A !important;}\n\n.cm-s-tomorrow-night-eighties span.cm-comment {color: #d27b53;}\n.cm-s-tomorrow-night-eighties span.cm-atom {color: #a16a94;}\n.cm-s-tomorrow-night-eighties span.cm-number {color: #a16a94;}\n\n.cm-s-tomorrow-night-eighties span.cm-property, .cm-s-tomorrow-night-eighties span.cm-attribute {color: #99cc99;}\n.cm-s-tomorrow-night-eighties span.cm-keyword {color: #f2777a;}\n.cm-s-tomorrow-night-eighties span.cm-string {color: #ffcc66;}\n\n.cm-s-tomorrow-night-eighties span.cm-variable {color: #99cc99;}\n.cm-s-tomorrow-night-eighties span.cm-variable-2 {color: #6699cc;}\n.cm-s-tomorrow-night-eighties span.cm-def {color: #f99157;}\n.cm-s-tomorrow-night-eighties span.cm-bracket {color: #CCCCCC;}\n.cm-s-tomorrow-night-eighties span.cm-tag {color: #f2777a;}\n.cm-s-tomorrow-night-eighties span.cm-link {color: #a16a94;}\n.cm-s-tomorrow-night-eighties span.cm-error {background: #f2777a; color: #6A6A6A;}\n\n.cm-s-tomorrow-night-eighties .CodeMirror-activeline-background {background: #343600 !important;}\n.cm-s-tomorrow-night-eighties .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;}\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/theme/twilight.css",
    "content": ".cm-s-twilight.CodeMirror { background: #141414; color: #f7f7f7; } /**/\n.cm-s-twilight .CodeMirror-selected { background: #323232 !important; } /**/\n.cm-s-twilight.CodeMirror ::selection { background: rgba(50, 50, 50, 0.99); }\n.cm-s-twilight.CodeMirror ::-moz-selection { background: rgba(50, 50, 50, 0.99); }\n\n.cm-s-twilight .CodeMirror-gutters { background: #222; border-right: 1px solid #aaa; }\n.cm-s-twilight .CodeMirror-guttermarker { color: white; }\n.cm-s-twilight .CodeMirror-guttermarker-subtle { color: #aaa; }\n.cm-s-twilight .CodeMirror-linenumber { color: #aaa; }\n.cm-s-twilight .CodeMirror-cursor { border-left: 1px solid white !important; }\n\n.cm-s-twilight .cm-keyword {  color: #f9ee98; } /**/\n.cm-s-twilight .cm-atom { color: #FC0; }\n.cm-s-twilight .cm-number { color:  #ca7841; } /**/\n.cm-s-twilight .cm-def { color: #8DA6CE; }\n.cm-s-twilight span.cm-variable-2, .cm-s-twilight span.cm-tag { color: #607392; } /**/\n.cm-s-twilight span.cm-variable-3, .cm-s-twilight span.cm-def { color: #607392; } /**/\n.cm-s-twilight .cm-operator { color: #cda869; } /**/\n.cm-s-twilight .cm-comment { color:#777; font-style:italic; font-weight:normal; } /**/\n.cm-s-twilight .cm-string { color:#8f9d6a; font-style:italic; } /**/\n.cm-s-twilight .cm-string-2 { color:#bd6b18 } /*?*/\n.cm-s-twilight .cm-meta { background-color:#141414; color:#f7f7f7; } /*?*/\n.cm-s-twilight .cm-builtin { color: #cda869; } /*?*/\n.cm-s-twilight .cm-tag { color: #997643; } /**/\n.cm-s-twilight .cm-attribute { color: #d6bb6d; } /*?*/\n.cm-s-twilight .cm-header { color: #FF6400; }\n.cm-s-twilight .cm-hr { color: #AEAEAE; }\n.cm-s-twilight .cm-link {   color:#ad9361; font-style:italic; text-decoration:none; } /**/\n.cm-s-twilight .cm-error { border-bottom: 1px solid red; }\n\n.cm-s-twilight .CodeMirror-activeline-background {background: #27282E !important;}\n.cm-s-twilight .CodeMirror-matchingbracket {outline:1px solid grey; color:white !important;}\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/theme/vibrant-ink.css",
    "content": "/* Taken from the popular Visual Studio Vibrant Ink Schema */\n\n.cm-s-vibrant-ink.CodeMirror { background: black; color: white; }\n.cm-s-vibrant-ink .CodeMirror-selected { background: #35493c !important; }\n.cm-s-vibrant-ink.CodeMirror ::selection { background: rgba(53, 73, 60, 0.99); }\n.cm-s-vibrant-ink.CodeMirror ::-moz-selection { background: rgba(53, 73, 60, 0.99); }\n\n.cm-s-vibrant-ink .CodeMirror-gutters { background: #002240; border-right: 1px solid #aaa; }\n.cm-s-vibrant-ink .CodeMirror-guttermarker { color: white; }\n.cm-s-vibrant-ink .CodeMirror-guttermarker-subtle { color: #d0d0d0; }\n.cm-s-vibrant-ink .CodeMirror-linenumber { color: #d0d0d0; }\n.cm-s-vibrant-ink .CodeMirror-cursor { border-left: 1px solid white !important; }\n\n.cm-s-vibrant-ink .cm-keyword {  color: #CC7832; }\n.cm-s-vibrant-ink .cm-atom { color: #FC0; }\n.cm-s-vibrant-ink .cm-number { color:  #FFEE98; }\n.cm-s-vibrant-ink .cm-def { color: #8DA6CE; }\n.cm-s-vibrant-ink span.cm-variable-2, .cm-s-vibrant span.cm-tag { color: #FFC66D }\n.cm-s-vibrant-ink span.cm-variable-3, .cm-s-vibrant span.cm-def { color: #FFC66D }\n.cm-s-vibrant-ink .cm-operator { color: #888; }\n.cm-s-vibrant-ink .cm-comment { color: gray; font-weight: bold; }\n.cm-s-vibrant-ink .cm-string { color:  #A5C25C }\n.cm-s-vibrant-ink .cm-string-2 { color: red }\n.cm-s-vibrant-ink .cm-meta { color: #D8FA3C; }\n.cm-s-vibrant-ink .cm-builtin { color: #8DA6CE; }\n.cm-s-vibrant-ink .cm-tag { color: #8DA6CE; }\n.cm-s-vibrant-ink .cm-attribute { color: #8DA6CE; }\n.cm-s-vibrant-ink .cm-header { color: #FF6400; }\n.cm-s-vibrant-ink .cm-hr { color: #AEAEAE; }\n.cm-s-vibrant-ink .cm-link { color: blue; }\n.cm-s-vibrant-ink .cm-error { border-bottom: 1px solid red; }\n\n.cm-s-vibrant-ink .CodeMirror-activeline-background {background: #27282E !important;}\n.cm-s-vibrant-ink .CodeMirror-matchingbracket {outline:1px solid grey; color:white !important;}\n"
  },
  {
    "path": "Public/editor.md/lib/codemirror/theme/xq-dark.css",
    "content": "/*\nCopyright (C) 2011 by MarkLogic Corporation\nAuthor: Mike Brevoort <mike@brevoort.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n*/\n.cm-s-xq-dark.CodeMirror { background: #0a001f; color: #f8f8f8; }\n.cm-s-xq-dark .CodeMirror-selected { background: #27007A !important; }\n.cm-s-xq-dark.CodeMirror ::selection { background: rgba(39, 0, 122, 0.99); }\n.cm-s-xq-dark.CodeMirror ::-moz-selection { background: rgba(39, 0, 122, 0.99); }\n.cm-s-xq-dark .CodeMirror-gutters { background: #0a001f; border-right: 1px solid #aaa; }\n.cm-s-xq-dark .CodeMirror-guttermarker { color: #FFBD40; }\n.cm-s-xq-dark .CodeMirror-guttermarker-subtle { color: #f8f8f8; }\n.cm-s-xq-dark .CodeMirror-linenumber { color: #f8f8f8; }\n.cm-s-xq-dark .CodeMirror-cursor { border-left: 1px solid white !important; }\n\n.cm-s-xq-dark span.cm-keyword {color: #FFBD40;}\n.cm-s-xq-dark span.cm-atom {color: #6C8CD5;}\n.cm-s-xq-dark span.cm-number {color: #164;}\n.cm-s-xq-dark span.cm-def {color: #FFF; text-decoration:underline;}\n.cm-s-xq-dark span.cm-variable {color: #FFF;}\n.cm-s-xq-dark span.cm-variable-2 {color: #EEE;}\n.cm-s-xq-dark span.cm-variable-3 {color: #DDD;}\n.cm-s-xq-dark span.cm-property {}\n.cm-s-xq-dark span.cm-operator {}\n.cm-s-xq-dark span.cm-comment {color: gray;}\n.cm-s-xq-dark span.cm-string {color: #9FEE00;}\n.cm-s-xq-dark span.cm-meta {color: yellow;}\n.cm-s-xq-dark span.cm-qualifier {color: #FFF700;}\n.cm-s-xq-dark span.cm-builtin {color: #30a;}\n.cm-s-xq-dark span.cm-bracket {color: #cc7;}\n.cm-s-xq-dark span.cm-tag {color: #FFBD40;}\n.cm-s-xq-dark span.cm-attribute {color: #FFF700;}\n.cm-s-xq-dark span.cm-error {color: #f00;}\n\n.cm-s-xq-dark .CodeMirror-activeline-background {background: #27282E !important;}\n.cm-s-xq-dark .CodeMirror-matchingbracket {outline:1px solid grey; color:white !important;}"
  },
  {
    "path": "Public/editor.md/lib/codemirror/theme/xq-light.css",
    "content": "/*\nCopyright (C) 2011 by MarkLogic Corporation\nAuthor: Mike Brevoort <mike@brevoort.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n*/\n.cm-s-xq-light span.cm-keyword {line-height: 1em; font-weight: bold; color: #5A5CAD; }\n.cm-s-xq-light span.cm-atom {color: #6C8CD5;}\n.cm-s-xq-light span.cm-number {color: #164;}\n.cm-s-xq-light span.cm-def {text-decoration:underline;}\n.cm-s-xq-light span.cm-variable {color: black; }\n.cm-s-xq-light span.cm-variable-2 {color:black;}\n.cm-s-xq-light span.cm-variable-3 {color: black; }\n.cm-s-xq-light span.cm-property {}\n.cm-s-xq-light span.cm-operator {}\n.cm-s-xq-light span.cm-comment {color: #0080FF; font-style: italic;}\n.cm-s-xq-light span.cm-string {color: red;}\n.cm-s-xq-light span.cm-meta {color: yellow;}\n.cm-s-xq-light span.cm-qualifier {color: grey}\n.cm-s-xq-light span.cm-builtin {color: #7EA656;}\n.cm-s-xq-light span.cm-bracket {color: #cc7;}\n.cm-s-xq-light span.cm-tag {color: #3F7F7F;}\n.cm-s-xq-light span.cm-attribute {color: #7F007F;}\n.cm-s-xq-light span.cm-error {color: #f00;}\n\n.cm-s-xq-light .CodeMirror-activeline-background {background: #e8f2ff !important;}\n.cm-s-xq-light .CodeMirror-matchingbracket {outline:1px solid grey;color:black !important;background:yellow;}"
  },
  {
    "path": "Public/editor.md/lib/codemirror/theme/zenburn.css",
    "content": "/**\n * \"\n *  Using Zenburn color palette from the Emacs Zenburn Theme\n *  https://github.com/bbatsov/zenburn-emacs/blob/master/zenburn-theme.el\n *\n *  Also using parts of https://github.com/xavi/coderay-lighttable-theme\n * \"\n * From: https://github.com/wisenomad/zenburn-lighttable-theme/blob/master/zenburn.css\n */\n\n.cm-s-zenburn .CodeMirror-gutters { background: #3f3f3f !important; }\n.cm-s-zenburn .CodeMirror-foldgutter-open, .CodeMirror-foldgutter-folded { color: #999; }\n.cm-s-zenburn .CodeMirror-cursor { border-left: 1px solid white !important; }\n.cm-s-zenburn { background-color: #3f3f3f; color: #dcdccc; }\n.cm-s-zenburn span.cm-builtin { color: #dcdccc; font-weight: bold; }\n.cm-s-zenburn span.cm-comment { color: #7f9f7f; }\n.cm-s-zenburn span.cm-keyword { color: #f0dfaf; font-weight: bold; }\n.cm-s-zenburn span.cm-atom { color: #bfebbf; }\n.cm-s-zenburn span.cm-def { color: #dcdccc; }\n.cm-s-zenburn span.cm-variable { color: #dfaf8f; }\n.cm-s-zenburn span.cm-variable-2 { color: #dcdccc; }\n.cm-s-zenburn span.cm-string { color: #cc9393; }\n.cm-s-zenburn span.cm-string-2 { color: #cc9393; }\n.cm-s-zenburn span.cm-number { color: #dcdccc; }\n.cm-s-zenburn span.cm-tag { color: #93e0e3; }\n.cm-s-zenburn span.cm-property { color: #dfaf8f; }\n.cm-s-zenburn span.cm-attribute { color: #dfaf8f; }\n.cm-s-zenburn span.cm-qualifier { color: #7cb8bb; }\n.cm-s-zenburn span.cm-meta { color: #f0dfaf; }\n.cm-s-zenburn span.cm-header { color: #f0efd0; }\n.cm-s-zenburn span.cm-operator { color: #f0efd0; }\n.cm-s-zenburn span.CodeMirror-matchingbracket { box-sizing: border-box; background: transparent; border-bottom: 1px solid; }\n.cm-s-zenburn span.CodeMirror-nonmatchingbracket { border-bottom: 1px solid; background: none; }\n.cm-s-zenburn .CodeMirror-activeline { background: #000000; }\n.cm-s-zenburn .CodeMirror-activeline-background { background: #000000; }\n.cm-s-zenburn .CodeMirror-selected { background: #545454; }\n.cm-s-zenburn .CodeMirror-focused .CodeMirror-selected { background: #4f4f4f; }\n"
  },
  {
    "path": "Public/editor.md/package.json",
    "content": "{\n  \"name\": \"editor.md\",\n  \"version\": \"1.5.0\",\n  \"description\": \"Open source online markdown editor.\",\n  \"directories\": {\n    \"doc\": \"docs\",\n    \"example\": \"examples\",\n    \"test\": \"tests\"\n  },\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/pandao/editor.md.git\"\n  },\n  \"keywords\": [\n    \"editor.md\",\n    \"markdown\",\n    \"editor\"\n  ],\n  \"author\": \"Pandao\",\n  \"license\": \"MIT\",\n  \"bugs\": {\n    \"url\": \"https://github.com/pandao/editor.md/issues\"\n  },\n  \"homepage\": \"https://github.com/pandao/editor.md\",\n  \"devDependencies\": {\n    \"dateformatter\": \"^0.1.0\",\n    \"gulp\": \"^3.8.11\",\n    \"gulp-concat\": \"^2.4.2\",\n    \"gulp-header\": \"^1.2.2\",\n    \"gulp-jshint\": \"^1.9.0\",\n    \"gulp-minify-css\": \"^0.4.4\",\n    \"gulp-notify\": \"^2.1.0\",\n    \"gulp-rename\": \"^1.2.0\",\n    \"gulp-replace\": \"^0.5.3\",\n    \"gulp-ruby-sass\": \"^1.0.1\",\n    \"gulp-uglifyjs\": \"^0.6.1\",\n    \"gulp-util\": \"^3.0.1\"\n  }\n}\n"
  },
  {
    "path": "Public/editor.md/plugins/code-block-dialog/code-block-dialog.js",
    "content": "/*!\n * Code block dialog plugin for Editor.md\n *\n * @file        code-block-dialog.js\n * @author      pandao\n * @version     1.2.0\n * @updateTime  2015-03-07\n * {@link       https://github.com/pandao/editor.md}\n * @license     MIT\n */\n\n(function() {\n\n    var factory = function (exports) {\n\t\tvar cmEditor;\n\t\tvar pluginName    = \"code-block-dialog\";\n    \n\t\t// for CodeBlock dialog select\n\t\tvar codeLanguages = exports.codeLanguages = {\n\t\t\tasp           : [\"ASP\", \"vbscript\"],\n\t\t\tactionscript  : [\"ActionScript(3.0)/Flash/Flex\", \"clike\"],\n\t\t\tbash          : [\"Bash/Bat\", \"shell\"],\n\t\t\tcss           : [\"CSS\", \"css\"],\n\t\t\tc             : [\"C\", \"clike\"],\n\t\t\tcpp           : [\"C++\", \"clike\"],\n\t\t\tcsharp        : [\"C#\", \"clike\"],\n\t\t\tcoffeescript  : [\"CoffeeScript\", \"coffeescript\"],\n\t\t\td             : [\"D\", \"d\"],\n\t\t\tdart          : [\"Dart\", \"dart\"],\n\t\t\tdelphi        : [\"Delphi/Pascal\", \"pascal\"],\n\t\t\terlang        : [\"Erlang\", \"erlang\"],\n\t\t\tgo            : [\"Golang\", \"go\"],\n\t\t\tgroovy        : [\"Groovy\", \"groovy\"],\n\t\t\thtml          : [\"HTML\", \"text/html\"],\n\t\t\tjava          : [\"Java\", \"clike\"],\n\t\t\tjson          : [\"JSON\", \"text/json\"],\n\t\t\tjavascript    : [\"Javascript\", \"javascript\"],\n\t\t\tlua           : [\"Lua\", \"lua\"],\n\t\t\tless          : [\"LESS\", \"css\"],\n\t\t\tmarkdown      : [\"Markdown\", \"gfm\"],\n\t\t\t\"objective-c\" : [\"Objective-C\", \"clike\"],\n\t\t\tphp           : [\"PHP\", \"php\"],\n\t\t\tperl          : [\"Perl\", \"perl\"],\n\t\t\tpython        : [\"Python\", \"python\"],\n\t\t\tr             : [\"R\", \"r\"],\n\t\t\trst           : [\"reStructedText\", \"rst\"],\n\t\t\truby          : [\"Ruby\", \"ruby\"],\n\t\t\tsql           : [\"SQL\", \"sql\"],\n\t\t\tsass          : [\"SASS/SCSS\", \"sass\"],\n\t\t\tshell         : [\"Shell\", \"shell\"],\n\t\t\tscala         : [\"Scala\", \"clike\"],\n\t\t\tswift         : [\"Swift\", \"clike\"],\n\t\t\tvb            : [\"VB/VBScript\", \"vb\"],\n\t\t\txml           : [\"XML\", \"text/xml\"],\n\t\t\tyaml          : [\"YAML\", \"yaml\"]\n\t\t};\n\n\t\texports.fn.codeBlockDialog = function() {\n\n\t\t\tvar _this       = this;\n            var cm          = this.cm;\n            var lang        = this.lang;\n            var editor      = this.editor;\n            var settings    = this.settings;\n            var cursor      = cm.getCursor();\n            var selection   = cm.getSelection();\n            var classPrefix = this.classPrefix;\n\t\t\tvar dialogName  = classPrefix + pluginName, dialog;\n\t\t\tvar dialogLang  = lang.dialog.codeBlock;\n\n\t\t\tcm.focus();\n\n            if (editor.find(\".\" + dialogName).length > 0)\n            {\n                dialog = editor.find(\".\" + dialogName);\n                dialog.find(\"option:first\").attr(\"selected\", \"selected\");\n                dialog.find(\"textarea\").val(selection);\n\n                this.dialogShowMask(dialog);\n                this.dialogLockScreen();\n                dialog.show();\n            }\n            else \n            {      \n                var dialogHTML = \"<div class=\\\"\" + classPrefix + \"code-toolbar\\\">\" +\n                                        dialogLang.selectLabel + \"<select><option selected=\\\"selected\\\" value=\\\"\\\">\" + dialogLang.selectDefaultText + \"</option></select>\" +\n                                    \"</div>\" +\n                                    \"<textarea placeholder=\\\"coding now....\\\" style=\\\"display:none;\\\">\" + selection + \"</textarea>\";\n\n                dialog = this.createDialog({\n                    name   : dialogName,\n                    title  : dialogLang.title,\n                    width  : 780,\n                    height : 565,\n                    mask   : settings.dialogShowMask,\n                    drag   : settings.dialogDraggable,\n                    content    : dialogHTML,\n                    lockScreen : settings.dialogLockScreen,\n                    maskStyle  : {\n                        opacity         : settings.dialogMaskOpacity,\n                        backgroundColor : settings.dialogMaskBgColor\n                    },\n                    buttons : {\n                        enter  : [lang.buttons.enter, function() {\n                            var codeTexts  = this.find(\"textarea\").val();\n                            var langName   = this.find(\"select\").val();\n\n                            if (langName === \"\")\n                            {\n                                alert(lang.dialog.codeBlock.unselectedLanguageAlert);\n                                return false;\n                            }\n\n                            if (codeTexts === \"\")\n                            {\n                                alert(lang.dialog.codeBlock.codeEmptyAlert);\n                                return false;\n                            }\n\n                            langName = (langName === \"other\") ? \"\" : langName;\n\n                            cm.replaceSelection([\"```\" + langName, codeTexts, \"```\"].join(\"\\n\"));\n\n                            if (langName === \"\") {\n                                cm.setCursor(cursor.line, cursor.ch + 3);\n                            }\n\n                            this.hide().lockScreen(false).hideMask();\n\n                            return false;\n                        }],\n                        cancel : [lang.buttons.cancel, function() {                                   \n                            this.hide().lockScreen(false).hideMask();\n\n                            return false;\n                        }]\n                    }\n                });\n            }\n\n\t\t\tvar langSelect = dialog.find(\"select\");\n\n\t\t\tif (langSelect.find(\"option\").length === 1) \n\t\t\t{\n\t\t\t\tfor (var key in codeLanguages)\n\t\t\t\t{\n\t\t\t\t\tvar codeLang = codeLanguages[key];\n\t\t\t\t\tlangSelect.append(\"<option value=\\\"\" + key + \"\\\" mode=\\\"\" + codeLang[1] + \"\\\">\" + codeLang[0] + \"</option>\");\n\t\t\t\t}\n\n\t\t\t\tlangSelect.append(\"<option value=\\\"other\\\">\" + dialogLang.otherLanguage + \"</option>\");\n\t\t\t}\n\t\t\t\n\t\t\tvar mode   = langSelect.find(\"option:selected\").attr(\"mode\");\n\t\t\n\t\t\tvar cmConfig = {\n\t\t\t\tmode                      : (mode) ? mode : \"text/html\",\n\t\t\t\ttheme                     : settings.theme,\n\t\t\t\ttabSize                   : 4,\n\t\t\t\tautofocus                 : true,\n\t\t\t\tautoCloseTags             : true,\n\t\t\t\tindentUnit                : 4,\n\t\t\t\tlineNumbers               : true,\n\t\t\t\tlineWrapping              : true,\n\t\t\t\textraKeys                 : {\"Ctrl-Q\": function(cm){ cm.foldCode(cm.getCursor()); }},\n\t\t\t\tfoldGutter                : true,\n\t\t\t\tgutters                   : [\"CodeMirror-linenumbers\", \"CodeMirror-foldgutter\"],\n\t\t\t\tmatchBrackets             : true,\n\t\t\t\tindentWithTabs            : true,\n\t\t\t\tstyleActiveLine           : true,\n\t\t\t\tstyleSelectedText         : true,\n\t\t\t\tautoCloseBrackets         : true,\n\t\t\t\tshowTrailingSpace         : true,\n\t\t\t\thighlightSelectionMatches : true\n\t\t\t};\n\t\t\t\n\t\t\tvar textarea = dialog.find(\"textarea\");\n\t\t\tvar cmObj    = dialog.find(\".CodeMirror\");\n\n\t\t\tif (dialog.find(\".CodeMirror\").length < 1) \n\t\t\t{\n\t\t\t\tcmEditor = exports.$CodeMirror.fromTextArea(textarea[0], cmConfig);\n\t\t\t\tcmObj    = dialog.find(\".CodeMirror\");\n\n\t\t\t\tcmObj.css({\n\t\t\t\t\t\"float\"   : \"none\", \n\t\t\t\t\tmargin    : \"8px 0\",\n\t\t\t\t\tborder    : \"1px solid #ddd\",\n\t\t\t\t\tfontSize  : settings.fontSize,\n\t\t\t\t\twidth     : \"100%\",\n\t\t\t\t\theight    : \"390px\"\n\t\t\t\t});\n\n\t\t\t\tcmEditor.on(\"change\", function(cm) {\n\t\t\t\t\ttextarea.val(cm.getValue());\n\t\t\t\t});\n\t\t\t} \n\t\t\telse \n\t\t\t{\n\n\t\t\t\tcmEditor.setValue(cm.getSelection());\n\t\t\t}\n\n\t\t\tlangSelect.change(function(){\n\t\t\t\tvar _mode = $(this).find(\"option:selected\").attr(\"mode\");\n\t\t\t\tcmEditor.setOption(\"mode\", _mode);\n\t\t\t});\n\t\t};\n\n\t};\n    \n\t// CommonJS/Node.js\n\tif (typeof require === \"function\" && typeof exports === \"object\" && typeof module === \"object\")\n    { \n        module.exports = factory;\n    }\n\telse if (typeof define === \"function\")  // AMD/CMD/Sea.js\n    {\n\t\tif (define.amd) { // for Require.js\n\n\t\t\tdefine([\"editormd\"], function(editormd) {\n                factory(editormd);\n            });\n\n\t\t} else { // for Sea.js\n\t\t\tdefine(function(require) {\n                var editormd = require(\"./../../editormd\");\n                factory(editormd);\n            });\n\t\t}\n\t} \n\telse\n\t{\n        factory(window.editormd);\n\t}\n\n})();\n"
  },
  {
    "path": "Public/editor.md/plugins/emoji-dialog/emoji-dialog.js",
    "content": "/*!\n * Emoji dialog plugin for Editor.md\n *\n * @file        emoji-dialog.js\n * @author      pandao\n * @version     1.2.0\n * @updateTime  2015-03-08\n * {@link       https://github.com/pandao/editor.md}\n * @license     MIT\n */\n\n(function() {\n\n\tvar factory = function (exports) {\n\n\t\tvar $             = jQuery;\n\t\tvar pluginName    = \"emoji-dialog\";\n\t\tvar emojiTabIndex = 0;\n\t\tvar emojiData     = [];\n        var selecteds     = [];\n\n\t\tvar logoPrefix    = \"editormd-logo\";\n\t\tvar logos         = [\n\t\t\tlogoPrefix,\n\t\t\tlogoPrefix + \"-1x\",\n\t\t\tlogoPrefix + \"-2x\",\n\t\t\tlogoPrefix + \"-3x\",\n\t\t\tlogoPrefix + \"-4x\",\n\t\t\tlogoPrefix + \"-5x\",\n\t\t\tlogoPrefix + \"-6x\",\n\t\t\tlogoPrefix + \"-7x\",\n\t\t\tlogoPrefix + \"-8x\"\n\t\t];\n\n\t\tvar langs = {\n\t\t\t\"zh-cn\" : {\n\t\t\t\ttoolbar : {\n\t\t\t\t\temoji : \"Emoji 表情\"\n\t\t\t\t},\n\t\t\t\tdialog : {\n\t\t\t\t\temoji : {\n\t\t\t\t\t\ttitle : \"Emoji 表情\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"zh-tw\" : {\n\t\t\t\ttoolbar : {\n\t\t\t\t\temoji : \"Emoji 表情\"\n\t\t\t\t},\n\t\t\t\tdialog : {\n\t\t\t\t\temoji : {\n\t\t\t\t\t\ttitle : \"Emoji 表情\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"en\" : {\n\t\t\t\ttoolbar : {\n\t\t\t\t\temoji : \"Emoji\"\n\t\t\t\t},\n\t\t\t\tdialog : {\n\t\t\t\t\temoji : {\n\t\t\t\t\t\ttitle : \"Emoji\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\texports.fn.emojiDialog = function() {\n\t\t\tvar _this       = this;\n\t\t\tvar cm          = this.cm;\n\t\t\tvar settings    = _this.settings;\n            \n            if (!settings.emoji)\n            {\n                alert(\"settings.emoji == false\");\n                return ;\n            }\n            \n\t\t\tvar path        = settings.pluginPath + pluginName + \"/\";\n\t\t\tvar editor      = this.editor;\n\t\t\tvar cursor      = cm.getCursor();\n\t\t\tvar selection   = cm.getSelection();\n\t\t\tvar classPrefix = this.classPrefix;\n\n\t\t\t$.extend(true, this.lang, langs[this.lang.name]);\n\t\t\tthis.setToolbar();\n\n\t\t\tvar lang        = this.lang;\n\t\t\tvar dialogName  = classPrefix + pluginName, dialog;\n\t\t\tvar dialogLang  = lang.dialog.emoji;\n\t\t\t\n\t\t\tvar dialogContent = [\n\t\t\t\t\"<div class=\\\"\" + classPrefix + \"emoji-dialog-box\\\" style=\\\"width: 760px;height: 334px;margin-bottom: 8px;overflow: hidden;\\\">\",\n\t\t\t\t\"<div class=\\\"\" + classPrefix + \"tab\\\"></div>\",\n\t\t\t\t\"</div>\",\n\t\t\t].join(\"\\n\");\n\n\t\t\tcm.focus();\n\n\t\t\tif (editor.find(\".\" + dialogName).length > 0) \n\t\t\t{\n                dialog = editor.find(\".\" + dialogName);\n\n\t\t\t\tselecteds = [];\n\t\t\t\tdialog.find(\"a\").removeClass(\"selected\");\n\n\t\t\t\tthis.dialogShowMask(dialog);\n\t\t\t\tthis.dialogLockScreen();\n\t\t\t\tdialog.show();\n\t\t\t} \n\t\t\telse\n\t\t\t{\n\t\t\t\tdialog = this.createDialog({\n\t\t\t\t\tname       : dialogName,\n\t\t\t\t\ttitle      : dialogLang.title,\n\t\t\t\t\twidth      : 800,\n\t\t\t\t\theight     : 475,\n\t\t\t\t\tmask       : settings.dialogShowMask,\n\t\t\t\t\tdrag       : settings.dialogDraggable,\n\t\t\t\t\tcontent    : dialogContent,\n\t\t\t\t\tlockScreen : settings.dialogLockScreen,\n\t\t\t\t\tmaskStyle  : {\n\t\t\t\t\t\topacity         : settings.dialogMaskOpacity,\n\t\t\t\t\t\tbackgroundColor : settings.dialogMaskBgColor\n\t\t\t\t\t},\n\t\t\t\t\tbuttons    : {\n\t\t\t\t\t\tenter  : [lang.buttons.enter, function() {\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tcm.replaceSelection(selecteds.join(\" \"));\n\t\t\t\t\t\t\tthis.hide().lockScreen(false).hideMask();\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}],\n\t\t\t\t\t\tcancel : [lang.buttons.cancel, function() {                           \n\t\t\t\t\t\t\tthis.hide().lockScreen(false).hideMask();\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}]\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t\t\n\t\t\tvar category = [\"Github emoji\", \"Twemoji\", \"Font awesome\", \"Editor.md logo\"];\n\t\t\tvar tab      = dialog.find(\".\" + classPrefix + \"tab\");\n\n\t\t\tif (tab.html() === \"\") \n\t\t\t{\n\t\t\t\tvar head = \"<ul class=\\\"\" + classPrefix + \"tab-head\\\">\";\n\n\t\t\t\tfor (var i = 0; i<4; i++) {\n\t\t\t\t\tvar active = (i === 0) ? \" class=\\\"active\\\"\" : \"\";\n\t\t\t\t\thead += \"<li\" + active + \"><a href=\\\"javascript:;\\\">\" + category[i] + \"</a></li>\";\n\t\t\t\t}\n\n\t\t\t\thead += \"</ul>\";\n\n\t\t\t\ttab.append(head);\n\n\t\t\t\tvar container = \"<div class=\\\"\" + classPrefix + \"tab-container\\\">\";\n\n\t\t\t\tfor (var x = 0; x < 4; x++) \n                {\n\t\t\t\t\tvar display = (x === 0) ? \"\" : \"display:none;\";\n\t\t\t\t\tcontainer += \"<div class=\\\"\" + classPrefix + \"tab-box\\\" style=\\\"height: 260px;overflow: hidden;overflow-y: auto;\" + display + \"\\\"></div>\";\n\t\t\t\t}\n\n\t\t\t\tcontainer += \"</div>\";\n\n\t\t\t\ttab.append(container);  \n\t\t\t}\n            \n\t\t\tvar tabBoxs = tab.find(\".\" + classPrefix + \"tab-box\");\n            var emojiCategories = [\"github-emoji\", \"twemoji\", \"font-awesome\", logoPrefix];\n\n\t\t\tvar drawTable = function() {\n                var cname = emojiCategories[emojiTabIndex];\n\t\t\t\tvar $data = emojiData[cname];\n                var $tab  = tabBoxs.eq(emojiTabIndex);\n\n\t\t\t\tif ($tab.html() !== \"\") {\n                    //console.log(\"break =>\", cname);\n                    return ;\n                }\n                \n                var pagination = function(data, type) {\n                    var rowNumber = (type === \"editormd-logo\") ? \"5\" : 20;\n                    var pageTotal = Math.ceil(data.length / rowNumber);\n                    var table     = \"<div class=\\\"\" + classPrefix + \"grid-table\\\">\";\n\n                    for (var i = 0; i < pageTotal; i++)\n                    {\n                        var row = \"<div class=\\\"\" + classPrefix + \"grid-table-row\\\">\";\n\n                        for (var x = 0; x < rowNumber; x++)\n                        {\n                            var emoji = $.trim(data[(i * rowNumber) + x]);\n                            \n                            if (typeof emoji !== \"undefined\" && emoji !== \"\")\n                            {\n                                var img = \"\", icon = \"\";\n                                \n                                if (type === \"github-emoji\")\n                                {\n                                    var src = (emoji === \"+1\") ? \"plus1\" : emoji;\n                                    src     = (src === \"black_large_square\") ? \"black_square\" : src;\n                                    src     = (src === \"moon\") ? \"waxing_gibbous_moon\" : src;\n                                    \n                                    src     = exports.emoji.path + src + exports.emoji.ext;\n                                    img     = \"<img src=\\\"\" + src + \"\\\" width=\\\"24\\\" class=\\\"emoji\\\" title=\\\"&#58;\" + emoji + \"&#58;\\\" alt=\\\"&#58;\" + emoji + \"&#58;\\\" />\";\n                                    row += \"<a href=\\\"javascript:;\\\" value=\\\":\" + emoji + \":\\\" title=\\\":\" + emoji + \":\\\" class=\\\"\" + classPrefix + \"emoji-btn\\\">\" + img + \"</a>\";\n                                }\n                                else if (type === \"twemoji\")\n                                {\n                                    var twemojiSrc = exports.twemoji.path + emoji + exports.twemoji.ext;\n                                    img = \"<img src=\\\"\" + twemojiSrc + \"\\\" width=\\\"24\\\" title=\\\"twemoji-\" + emoji + \"\\\" alt=\\\"twemoji-\" + emoji + \"\\\" class=\\\"emoji twemoji\\\" />\";\n                                    row += \"<a href=\\\"javascript:;\\\" value=\\\":tw-\" + emoji + \":\\\" title=\\\":tw-\" + emoji + \":\\\" class=\\\"\" + classPrefix + \"emoji-btn\\\">\" + img + \"</a>\";\n                                }\n                                else if (type === \"font-awesome\")\n                                {\n                                    icon = \"<i class=\\\"fa fa-\" + emoji + \" fa-emoji\\\" title=\\\"\" + emoji + \"\\\"></i>\";\n                                    row += \"<a href=\\\"javascript:;\\\" value=\\\":fa-\" + emoji + \":\\\" title=\\\":fa-\" + emoji + \":\\\" class=\\\"\" + classPrefix + \"emoji-btn\\\">\" + icon + \"</a>\";\n                                }\n                                else if (type === \"editormd-logo\")\n                                {\n                                    icon = \"<i class=\\\"\" + emoji + \"\\\" title=\\\"Editor.md logo (\" + emoji + \")\\\"></i>\";\n                                    row += \"<a href=\\\"javascript:;\\\" value=\\\":\" + emoji + \":\\\" title=\\\":\" + emoji + \":\\\" style=\\\"width:20%;\\\" class=\\\"\" + classPrefix + \"emoji-btn\\\">\" + icon + \"</a>\";\n                                }\n                            }\n                            else\n                            {\n                                row += \"<a href=\\\"javascript:;\\\" value=\\\"\\\"></a>\";                        \n                            }\n                        }\n\n                        row += \"</div>\";\n\n                        table += row;\n                    }\n\n                    table += \"</div>\";\n                    \n                    return table;\n                };\n                \n                if (emojiTabIndex === 0)\n                {\n                    for (var i = 0, len = $data.length; i < len; i++)\n                    {\n                        var h4Style = (i === 0) ? \" style=\\\"margin: 0 0 10px;\\\"\" : \" style=\\\"margin: 10px 0;\\\"\";\n                        $tab.append(\"<h4\" + h4Style + \">\" + $data[i].category + \"</h4>\");\n                        $tab.append(pagination($data[i].list, cname));\n                    }\n                }\n                else\n                {\n                    $tab.append(pagination($data, cname));\n                }\n\n\t\t\t\t$tab.find(\".\" + classPrefix + \"emoji-btn\").bind(exports.mouseOrTouch(\"click\", \"touchend\"), function() {\n\t\t\t\t\t$(this).toggleClass(\"selected\");\n\n\t\t\t\t\tif ($(this).hasClass(\"selected\")) \n\t\t\t\t\t{\n\t\t\t\t\t\tselecteds.push($(this).attr(\"value\"));\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t};\n\t\t\t\n\t\t\tif (emojiData.length < 1) \n\t\t\t{            \n\t\t\t\tif (typeof dialog.loading === \"function\") {\n                    dialog.loading(true);\n                }\n\n\t\t\t\t$.getJSON(path + \"emoji.json?temp=\" + Math.random(), function(json) {\n\n\t\t\t\t\tif (typeof dialog.loading === \"function\") {\n                        dialog.loading(false);\n                    }\n\n\t\t\t\t\temojiData = json;\n                    emojiData[logoPrefix] = logos;\n\t\t\t\t\tdrawTable();\n\t\t\t\t});\n\t\t\t} \n\t\t\telse \n\t\t\t{\n\t\t\t\tdrawTable();\n\t\t\t}\n\n\t\t\ttab.find(\"li\").bind(exports.mouseOrTouch(\"click\", \"touchend\"), function() {\n\t\t\t\tvar $this     = $(this);\n\t\t\t\temojiTabIndex = $this.index();\n\n\t\t\t\t$this.addClass(\"active\").siblings().removeClass(\"active\");\n\t\t\t\ttabBoxs.eq(emojiTabIndex).show().siblings().hide();\n\t\t\t\tdrawTable();\n\t\t\t});\n\t\t};\n\n\t};\n    \n\t// CommonJS/Node.js\n\tif (typeof require === \"function\" && typeof exports === \"object\" && typeof module === \"object\")\n    { \n        module.exports = factory;\n    }\n\telse if (typeof define === \"function\")  // AMD/CMD/Sea.js\n    {\n\t\tif (define.amd) { // for Require.js\n\n\t\t\tdefine([\"editormd\"], function(editormd) {\n                factory(editormd);\n            });\n\n\t\t} else { // for Sea.js\n\t\t\tdefine(function(require) {\n                var editormd = require(\"./../../editormd\");\n                factory(editormd);\n            });\n\t\t}\n\t} \n\telse\n\t{\n        factory(window.editormd);\n\t}\n\n})();\n"
  },
  {
    "path": "Public/editor.md/plugins/emoji-dialog/emoji.json",
    "content": "{\n\t\"github-emoji\" : [\n\t\t{\n\t\t\t\"category\" :\"People\",\n\t\t\t\"list\" : [\"bowtie\",\"smile\",\"laughing\",\"blush\",\"smiley\",\"relaxed\",\"smirk\",\"heart_eyes\",\"kissing_heart\",\"kissing_closed_eyes\",\"flushed\",\"relieved\",\"satisfied\",\"grin\",\"wink\",\"stuck_out_tongue_winking_eye\",\"stuck_out_tongue_closed_eyes\",\"grinning\",\"kissing\",\"kissing_smiling_eyes\",\"stuck_out_tongue\",\"sleeping\",\"worried\",\"frowning\",\"anguished\",\"open_mouth\",\"grimacing\",\"confused\",\"hushed\",\"expressionless\",\"unamused\",\"sweat_smile\",\"sweat\",\"disappointed_relieved\",\"weary\",\"pensive\",\"disappointed\",\"confounded\",\"fearful\",\"cold_sweat\",\"persevere\",\"cry\",\"sob\",\"joy\",\"astonished\",\"scream\",\"neckbeard\",\"tired_face\",\"angry\",\"rage\",\"triumph\",\"sleepy\",\"yum\",\"mask\",\"sunglasses\",\"dizzy_face\",\"imp\",\"smiling_imp\",\"neutral_face\",\"no_mouth\",\"innocent\",\"alien\",\"yellow_heart\",\"blue_heart\",\"purple_heart\",\"heart\",\"green_heart\",\"broken_heart\",\"heartbeat\",\"heartpulse\",\"two_hearts\",\"revolving_hearts\",\"cupid\",\"sparkling_heart\",\"sparkles\",\"star\",\"star2\",\"dizzy\",\"boom\",\"collision\",\"anger\",\"exclamation\",\"question\",\"grey_exclamation\",\"grey_question\",\"zzz\",\"dash\",\"sweat_drops\",\"notes\",\"musical_note\",\"fire\",\"hankey\",\"poop\",\"shit\",\"+1\",\"thumbsup\",\"-1\",\"thumbsdown\",\"ok_hand\",\"punch\",\"facepunch\",\"fist\",\"v\",\"wave\",\"hand\",\"raised_hand\",\"open_hands\",\"point_up\",\"point_down\",\"point_left\",\"point_right\",\"raised_hands\",\"pray\",\"point_up_2\",\"clap\",\"muscle\",\"metal\",\"fu\",\"walking\",\"runner\",\"running\",\"couple\",\"family\",\"two_men_holding_hands\",\"two_women_holding_hands\",\"dancer\",\"dancers\",\"ok_woman\",\"no_good\",\"information_desk_person\",\"raising_hand\",\"bride_with_veil\",\"person_with_pouting_face\",\"person_frowning\",\"bow\",\"couplekiss\",\"couple_with_heart\",\"massage\",\"haircut\",\"nail_care\",\"boy\",\"girl\",\"woman\",\"man\",\"baby\",\"older_woman\",\"older_man\",\"person_with_blond_hair\",\"man_with_gua_pi_mao\",\"man_with_turban\",\"construction_worker\",\"cop\",\"angel\",\"princess\",\"smiley_cat\",\"smile_cat\",\"heart_eyes_cat\",\"kissing_cat\",\"smirk_cat\",\"scream_cat\",\"crying_cat_face\",\"joy_cat\",\"pouting_cat\",\"japanese_ogre\",\"japanese_goblin\",\"see_no_evil\",\"hear_no_evil\",\"speak_no_evil\",\"guardsman\",\"skull\",\"feet\",\"lips\",\"kiss\",\"droplet\",\"ear\",\"eyes\",\"nose\",\"tongue\",\"love_letter\",\"bust_in_silhouette\",\"busts_in_silhouette\",\"speech_balloon\",\"thought_balloon\",\"feelsgood\",\"finnadie\",\"goberserk\",\"godmode\",\"hurtrealbad\",\"rage1\",\"rage2\",\"rage3\",\"rage4\",\"suspect\",\"trollface\"]\n\t\t},\n\t\t{\n\t\t\t\"category\" :\"Nature\",\n\t\t\t\"list\" : [\"sunny\",\"umbrella\",\"cloud\",\"snowflake\",\"snowman\",\"zap\",\"cyclone\",\"foggy\",\"ocean\",\"cat\",\"dog\",\"mouse\",\"hamster\",\"rabbit\",\"wolf\",\"frog\",\"tiger\",\"koala\",\"bear\",\"pig\",\"pig_nose\",\"cow\",\"boar\",\"monkey_face\",\"monkey\",\"horse\",\"racehorse\",\"camel\",\"sheep\",\"elephant\",\"panda_face\",\"snake\",\"bird\",\"baby_chick\",\"hatched_chick\",\"hatching_chick\",\"chicken\",\"penguin\",\"turtle\",\"bug\",\"honeybee\",\"ant\",\"beetle\",\"snail\",\"octopus\",\"tropical_fish\",\"fish\",\"whale\",\"whale2\",\"dolphin\",\"cow2\",\"ram\",\"rat\",\"water_buffalo\",\"tiger2\",\"rabbit2\",\"dragon\",\"goat\",\"rooster\",\"dog2\",\"pig2\",\"mouse2\",\"ox\",\"dragon_face\",\"blowfish\",\"crocodile\",\"dromedary_camel\",\"leopard\",\"cat2\",\"poodle\",\"paw_prints\",\"bouquet\",\"cherry_blossom\",\"tulip\",\"four_leaf_clover\",\"rose\",\"sunflower\",\"hibiscus\",\"maple_leaf\",\"leaves\",\"fallen_leaf\",\"herb\",\"mushroom\",\"cactus\",\"palm_tree\",\"evergreen_tree\",\"deciduous_tree\",\"chestnut\",\"seedling\",\"blossom\",\"ear_of_rice\",\"shell\",\"globe_with_meridians\",\"sun_with_face\",\"full_moon_with_face\",\"new_moon_with_face\",\"new_moon\",\"waxing_crescent_moon\",\"first_quarter_moon\",\"waxing_gibbous_moon\",\"full_moon\",\"waning_gibbous_moon\",\"last_quarter_moon\",\"waning_crescent_moon\",\"last_quarter_moon_with_face\",\"first_quarter_moon_with_face\",\"moon\",\"earth_africa\",\"earth_americas\",\"earth_asia\",\"volcano\",\"milky_way\",\"partly_sunny\",\"octocat\",\"squirrel\"]\n\t\t},\n\t\t{\n\t\t\t\"category\" :\"Objects\",\n\t\t\t\"list\" : [\"bamboo\",\"gift_heart\",\"dolls\",\"school_satchel\",\"mortar_board\",\"flags\",\"fireworks\",\"sparkler\",\"wind_chime\",\"rice_scene\",\"jack_o_lantern\",\"ghost\",\"santa\",\"christmas_tree\",\"gift\",\"bell\",\"no_bell\",\"tanabata_tree\",\"tada\",\"confetti_ball\",\"balloon\",\"crystal_ball\",\"cd\",\"dvd\",\"floppy_disk\",\"camera\",\"video_camera\",\"movie_camera\",\"computer\",\"tv\",\"iphone\",\"phone\",\"telephone\",\"telephone_receiver\",\"pager\",\"fax\",\"minidisc\",\"vhs\",\"sound\",\"speaker\",\"mute\",\"loudspeaker\",\"mega\",\"hourglass\",\"hourglass_flowing_sand\",\"alarm_clock\",\"watch\",\"radio\",\"satellite\",\"loop\",\"mag\",\"mag_right\",\"unlock\",\"lock\",\"lock_with_ink_pen\",\"closed_lock_with_key\",\"key\",\"bulb\",\"flashlight\",\"high_brightness\",\"low_brightness\",\"electric_plug\",\"battery\",\"calling\",\"email\",\"mailbox\",\"postbox\",\"bath\",\"bathtub\",\"shower\",\"toilet\",\"wrench\",\"nut_and_bolt\",\"hammer\",\"seat\",\"moneybag\",\"yen\",\"dollar\",\"pound\",\"euro\",\"credit_card\",\"money_with_wings\",\"e-mail\",\"inbox_tray\",\"outbox_tray\",\"envelope\",\"incoming_envelope\",\"postal_horn\",\"mailbox_closed\",\"mailbox_with_mail\",\"mailbox_with_no_mail\",\"package\",\"door\",\"smoking\",\"bomb\",\"gun\",\"hocho\",\"pill\",\"syringe\",\"page_facing_up\",\"page_with_curl\",\"bookmark_tabs\",\"bar_chart\",\"chart_with_upwards_trend\",\"chart_with_downwards_trend\",\"scroll\",\"clipboard\",\"calendar\",\"date\",\"card_index\",\"file_folder\",\"open_file_folder\",\"scissors\",\"pushpin\",\"paperclip\",\"black_nib\",\"pencil2\",\"straight_ruler\",\"triangular_ruler\",\"closed_book\",\"green_book\",\"blue_book\",\"orange_book\",\"notebook\",\"notebook_with_decorative_cover\",\"ledger\",\"books\",\"bookmark\",\"name_badge\",\"microscope\",\"telescope\",\"newspaper\",\"football\",\"basketball\",\"soccer\",\"baseball\",\"tennis\",\"8ball\",\"rugby_football\",\"bowling\",\"golf\",\"mountain_bicyclist\",\"bicyclist\",\"horse_racing\",\"snowboarder\",\"swimmer\",\"surfer\",\"ski\",\"spades\",\"hearts\",\"clubs\",\"diamonds\",\"gem\",\"ring\",\"trophy\",\"musical_score\",\"musical_keyboard\",\"violin\",\"space_invader\",\"video_game\",\"black_joker\",\"flower_playing_cards\",\"game_die\",\"dart\",\"mahjong\",\"clapper\",\"memo\",\"pencil\",\"book\",\"art\",\"microphone\",\"headphones\",\"trumpet\",\"saxophone\",\"guitar\",\"shoe\",\"sandal\",\"high_heel\",\"lipstick\",\"boot\",\"shirt\",\"tshirt\",\"necktie\",\"womans_clothes\",\"dress\",\"running_shirt_with_sash\",\"jeans\",\"kimono\",\"bikini\",\"ribbon\",\"tophat\",\"crown\",\"womans_hat\",\"mans_shoe\",\"closed_umbrella\",\"briefcase\",\"handbag\",\"pouch\",\"purse\",\"eyeglasses\",\"fishing_pole_and_fish\",\"coffee\",\"tea\",\"sake\",\"baby_bottle\",\"beer\",\"beers\",\"cocktail\",\"tropical_drink\",\"wine_glass\",\"fork_and_knife\",\"pizza\",\"hamburger\",\"fries\",\"poultry_leg\",\"meat_on_bone\",\"spaghetti\",\"curry\",\"fried_shrimp\",\"bento\",\"sushi\",\"fish_cake\",\"rice_ball\",\"rice_cracker\",\"rice\",\"ramen\",\"stew\",\"oden\",\"dango\",\"egg\",\"bread\",\"doughnut\",\"custard\",\"icecream\",\"ice_cream\",\"shaved_ice\",\"birthday\",\"cake\",\"cookie\",\"chocolate_bar\",\"candy\",\"lollipop\",\"honey_pot\",\"apple\",\"green_apple\",\"tangerine\",\"lemon\",\"cherries\",\"grapes\",\"watermelon\",\"strawberry\",\"peach\",\"melon\",\"banana\",\"pear\",\"pineapple\",\"sweet_potato\",\"eggplant\",\"tomato\",\"corn\"]\n\t\t},\n\t\t{\n\t\t\t\"category\" :\"Places\",\n\t\t\t\"list\" : [\"house\",\"house_with_garden\",\"school\",\"office\",\"post_office\",\"hospital\",\"bank\",\"convenience_store\",\"love_hotel\",\"hotel\",\"wedding\",\"church\",\"department_store\",\"european_post_office\",\"city_sunrise\",\"city_sunset\",\"japanese_castle\",\"european_castle\",\"tent\",\"factory\",\"tokyo_tower\",\"japan\",\"mount_fuji\",\"sunrise_over_mountains\",\"sunrise\",\"stars\",\"statue_of_liberty\",\"bridge_at_night\",\"carousel_horse\",\"rainbow\",\"ferris_wheel\",\"fountain\",\"roller_coaster\",\"ship\",\"speedboat\",\"boat\",\"sailboat\",\"rowboat\",\"anchor\",\"rocket\",\"airplane\",\"helicopter\",\"steam_locomotive\",\"tram\",\"mountain_railway\",\"bike\",\"aerial_tramway\",\"suspension_railway\",\"mountain_cableway\",\"tractor\",\"blue_car\",\"oncoming_automobile\",\"car\",\"red_car\",\"taxi\",\"oncoming_taxi\",\"articulated_lorry\",\"bus\",\"oncoming_bus\",\"rotating_light\",\"police_car\",\"oncoming_police_car\",\"fire_engine\",\"ambulance\",\"minibus\",\"truck\",\"train\",\"station\",\"train2\",\"bullettrain_front\",\"bullettrain_side\",\"light_rail\",\"monorail\",\"railway_car\",\"trolleybus\",\"ticket\",\"fuelpump\",\"vertical_traffic_light\",\"traffic_light\",\"warning\",\"construction\",\"beginner\",\"atm\",\"slot_machine\",\"busstop\",\"barber\",\"hotsprings\",\"checkered_flag\",\"crossed_flags\",\"izakaya_lantern\",\"moyai\",\"circus_tent\",\"performing_arts\",\"round_pushpin\",\"triangular_flag_on_post\",\"jp\",\"kr\",\"cn\",\"us\",\"fr\",\"es\",\"it\",\"ru\",\"gb\",\"uk\",\"de\"]\n\t\t},\n\t\t{\n\t\t\t\"category\" :\"Symbols\",\n\t\t\t\"list\" : [\"one\",\"two\",\"three\",\"four\",\"five\",\"six\",\"seven\",\"eight\",\"nine\",\"keycap_ten\",\"1234\",\"zero\",\"hash\",\"symbols\",\"arrow_backward\",\"arrow_down\",\"arrow_forward\",\"arrow_left\",\"capital_abcd\",\"abcd\",\"abc\",\"arrow_lower_left\",\"arrow_lower_right\",\"arrow_right\",\"arrow_up\",\"arrow_upper_left\",\"arrow_upper_right\",\"arrow_double_down\",\"arrow_double_up\",\"arrow_down_small\",\"arrow_heading_down\",\"arrow_heading_up\",\"leftwards_arrow_with_hook\",\"arrow_right_hook\",\"left_right_arrow\",\"arrow_up_down\",\"arrow_up_small\",\"arrows_clockwise\",\"arrows_counterclockwise\",\"rewind\",\"fast_forward\",\"information_source\",\"ok\",\"twisted_rightwards_arrows\",\"repeat\",\"repeat_one\",\"new\",\"top\",\"up\",\"cool\",\"free\",\"ng\",\"cinema\",\"koko\",\"signal_strength\",\"u5272\",\"u5408\",\"u55b6\",\"u6307\",\"u6708\",\"u6709\",\"u6e80\",\"u7121\",\"u7533\",\"u7a7a\",\"u7981\",\"sa\",\"restroom\",\"mens\",\"womens\",\"baby_symbol\",\"no_smoking\",\"parking\",\"wheelchair\",\"metro\",\"baggage_claim\",\"accept\",\"wc\",\"potable_water\",\"put_litter_in_its_place\",\"secret\",\"congratulations\",\"m\",\"passport_control\",\"left_luggage\",\"customs\",\"ideograph_advantage\",\"cl\",\"sos\",\"id\",\"no_entry_sign\",\"underage\",\"no_mobile_phones\",\"do_not_litter\",\"non-potable_water\",\"no_bicycles\",\"no_pedestrians\",\"children_crossing\",\"no_entry\",\"eight_spoked_asterisk\",\"sparkle\",\"eight_pointed_black_star\",\"heart_decoration\",\"vs\",\"vibration_mode\",\"mobile_phone_off\",\"chart\",\"currency_exchange\",\"aries\",\"taurus\",\"gemini\",\"cancer\",\"leo\",\"virgo\",\"libra\",\"scorpius\",\"sagittarius\",\"capricorn\",\"aquarius\",\"pisces\",\"ophiuchus\",\"six_pointed_star\",\"negative_squared_cross_mark\",\"a\",\"b\",\"ab\",\"o2\",\"diamond_shape_with_a_dot_inside\",\"recycle\",\"end\",\"back\",\"on\",\"soon\",\"clock1\",\"clock130\",\"clock10\",\"clock1030\",\"clock11\",\"clock1130\",\"clock12\",\"clock1230\",\"clock2\",\"clock230\",\"clock3\",\"clock330\",\"clock4\",\"clock430\",\"clock5\",\"clock530\",\"clock6\",\"clock630\",\"clock7\",\"clock730\",\"clock8\",\"clock830\",\"clock9\",\"clock930\",\"heavy_dollar_sign\",\"copyright\",\"registered\",\"tm\",\"x\",\"heavy_exclamation_mark\",\"bangbang\",\"interrobang\",\"o\",\"heavy_multiplication_x\",\"heavy_plus_sign\",\"heavy_minus_sign\",\"heavy_division_sign\",\"white_flower\",\"100\",\"heavy_check_mark\",\"ballot_box_with_check\",\"radio_button\",\"link\",\"curly_loop\",\"wavy_dash\",\"part_alternation_mark\",\"trident\",\"black_small_square\",\"white_small_square\",\"black_medium_small_square\",\"white_medium_small_square\",\"black_medium_square\",\"white_medium_square\",\"black_large_square\",\"white_large_square\",\"white_check_mark\",\"black_square_button\",\"white_square_button\",\"black_circle\",\"white_circle\",\"red_circle\",\"large_blue_circle\",\"large_blue_diamond\",\"large_orange_diamond\",\"small_blue_diamond\",\"small_orange_diamond\",\"small_red_triangle\",\"small_red_triangle_down\",\"shipit\"]\n\t\t}\n\t],\n\n\t\"twemoji\" : [\"1f004\",\"1f0cf\",\"1f170\",\"1f171\",\"1f17e\",\"1f17f\",\"1f18e\",\"1f191\",\"1f192\",\"1f193\",\"1f194\",\"1f195\",\"1f196\",\"1f197\",\"1f198\",\"1f199\",\"1f19a\",\"1f1e6\",\"1f1e7\",\"1f1e8-1f1f3\",\"1f1e8\",\"1f1e9-1f1ea\",\"1f1e9\",\"1f1ea-1f1f8\",\"1f1ea\",\"1f1eb-1f1f7\",\"1f1eb\",\"1f1ec-1f1e7\",\"1f1ec\",\"1f1ed\",\"1f1ee-1f1f9\",\"1f1ee\",\"1f1ef-1f1f5\",\"1f1ef\",\"1f1f0-1f1f7\",\"1f1f0\",\"1f1f1\",\"1f1f2\",\"1f1f3\",\"1f1f4\",\"1f1f5\",\"1f1f6\",\"1f1f7-1f1fa\",\"1f1f7\",\"1f1f8\",\"1f1f9\",\"1f1fa-1f1f8\",\"1f1fa\",\"1f1fb\",\"1f1fc\",\"1f1fd\",\"1f1fe\",\"1f1ff\",\"1f201\",\"1f202\",\"1f21a\",\"1f22f\",\"1f232\",\"1f233\",\"1f234\",\"1f235\",\"1f236\",\"1f237\",\"1f238\",\"1f239\",\"1f23a\",\"1f250\",\"1f251\",\"1f300\",\"1f301\",\"1f302\",\"1f303\",\"1f304\",\"1f305\",\"1f306\",\"1f307\",\"1f308\",\"1f309\",\"1f30a\",\"1f30b\",\"1f30c\",\"1f30d\",\"1f30e\",\"1f30f\",\"1f310\",\"1f311\",\"1f312\",\"1f313\",\"1f314\",\"1f315\",\"1f316\",\"1f317\",\"1f318\",\"1f319\",\"1f31a\",\"1f31b\",\"1f31c\",\"1f31d\",\"1f31e\",\"1f31f\",\"1f320\",\"1f330\",\"1f331\",\"1f332\",\"1f333\",\"1f334\",\"1f335\",\"1f337\",\"1f338\",\"1f339\",\"1f33a\",\"1f33b\",\"1f33c\",\"1f33d\",\"1f33e\",\"1f33f\",\"1f340\",\"1f341\",\"1f342\",\"1f343\",\"1f344\",\"1f345\",\"1f346\",\"1f347\",\"1f348\",\"1f349\",\"1f34a\",\"1f34b\",\"1f34c\",\"1f34d\",\"1f34e\",\"1f34f\",\"1f350\",\"1f351\",\"1f352\",\"1f353\",\"1f354\",\"1f355\",\"1f356\",\"1f357\",\"1f358\",\"1f359\",\"1f35a\",\"1f35b\",\"1f35c\",\"1f35d\",\"1f35e\",\"1f35f\",\"1f360\",\"1f361\",\"1f362\",\"1f363\",\"1f364\",\"1f365\",\"1f366\",\"1f367\",\"1f368\",\"1f369\",\"1f36a\",\"1f36b\",\"1f36c\",\"1f36d\",\"1f36e\",\"1f36f\",\"1f370\",\"1f371\",\"1f372\",\"1f373\",\"1f374\",\"1f375\",\"1f376\",\"1f377\",\"1f378\",\"1f379\",\"1f37a\",\"1f37b\",\"1f37c\",\"1f380\",\"1f381\",\"1f382\",\"1f383\",\"1f384\",\"1f385\",\"1f386\",\"1f387\",\"1f388\",\"1f389\",\"1f38a\",\"1f38b\",\"1f38c\",\"1f38d\",\"1f38e\",\"1f38f\",\"1f390\",\"1f391\",\"1f392\",\"1f393\",\"1f3a0\",\"1f3a1\",\"1f3a2\",\"1f3a3\",\"1f3a4\",\"1f3a5\",\"1f3a6\",\"1f3a7\",\"1f3a8\",\"1f3a9\",\"1f3aa\",\"1f3ab\",\"1f3ac\",\"1f3ad\",\"1f3ae\",\"1f3af\",\"1f3b0\",\"1f3b1\",\"1f3b2\",\"1f3b3\",\"1f3b4\",\"1f3b5\",\"1f3b6\",\"1f3b7\",\"1f3b8\",\"1f3b9\",\"1f3ba\",\"1f3bb\",\"1f3bc\",\"1f3bd\",\"1f3be\",\"1f3bf\",\"1f3c0\",\"1f3c1\",\"1f3c2\",\"1f3c3\",\"1f3c4\",\"1f3c6\",\"1f3c7\",\"1f3c8\",\"1f3c9\",\"1f3ca\",\"1f3e0\",\"1f3e1\",\"1f3e2\",\"1f3e3\",\"1f3e4\",\"1f3e5\",\"1f3e6\",\"1f3e7\",\"1f3e8\",\"1f3e9\",\"1f3ea\",\"1f3eb\",\"1f3ec\",\"1f3ed\",\"1f3ee\",\"1f3ef\",\"1f3f0\",\"1f400\",\"1f401\",\"1f402\",\"1f403\",\"1f404\",\"1f405\",\"1f406\",\"1f407\",\"1f408\",\"1f409\",\"1f40a\",\"1f40b\",\"1f40c\",\"1f40d\",\"1f40e\",\"1f40f\",\"1f410\",\"1f411\",\"1f412\",\"1f413\",\"1f414\",\"1f415\",\"1f416\",\"1f417\",\"1f418\",\"1f419\",\"1f41a\",\"1f41b\",\"1f41c\",\"1f41d\",\"1f41e\",\"1f41f\",\"1f420\",\"1f421\",\"1f422\",\"1f423\",\"1f424\",\"1f425\",\"1f426\",\"1f427\",\"1f428\",\"1f429\",\"1f42a\",\"1f42b\",\"1f42c\",\"1f42d\",\"1f42e\",\"1f42f\",\"1f430\",\"1f431\",\"1f432\",\"1f433\",\"1f434\",\"1f435\",\"1f436\",\"1f437\",\"1f438\",\"1f439\",\"1f43a\",\"1f43b\",\"1f43c\",\"1f43d\",\"1f43e\",\"1f440\",\"1f442\",\"1f443\",\"1f444\",\"1f445\",\"1f446\",\"1f447\",\"1f448\",\"1f449\",\"1f44a\",\"1f44b\",\"1f44c\",\"1f44d\",\"1f44e\",\"1f44f\",\"1f450\",\"1f451\",\"1f452\",\"1f453\",\"1f454\",\"1f455\",\"1f456\",\"1f457\",\"1f458\",\"1f459\",\"1f45a\",\"1f45b\",\"1f45c\",\"1f45d\",\"1f45e\",\"1f45f\",\"1f460\",\"1f461\",\"1f462\",\"1f463\",\"1f464\",\"1f465\",\"1f466\",\"1f467\",\"1f468\",\"1f469\",\"1f46a\",\"1f46b\",\"1f46c\",\"1f46d\",\"1f46e\",\"1f46f\",\"1f470\",\"1f471\",\"1f472\",\"1f473\",\"1f474\",\"1f475\",\"1f476\",\"1f477\",\"1f478\",\"1f479\",\"1f47a\",\"1f47b\",\"1f47c\",\"1f47d\",\"1f47e\",\"1f47f\",\"1f480\",\"1f481\",\"1f482\",\"1f483\",\"1f484\",\"1f485\",\"1f486\",\"1f487\",\"1f488\",\"1f489\",\"1f48a\",\"1f48b\",\"1f48c\",\"1f48d\",\"1f48e\",\"1f48f\",\"1f490\",\"1f491\",\"1f492\",\"1f493\",\"1f494\",\"1f495\",\"1f496\",\"1f497\",\"1f498\",\"1f499\",\"1f49a\",\"1f49b\",\"1f49c\",\"1f49d\",\"1f49e\",\"1f49f\",\"1f4a0\",\"1f4a1\",\"1f4a2\",\"1f4a3\",\"1f4a4\",\"1f4a5\",\"1f4a6\",\"1f4a7\",\"1f4a8\",\"1f4a9\",\"1f4aa\",\"1f4ab\",\"1f4ac\",\"1f4ad\",\"1f4ae\",\"1f4af\",\"1f4b0\",\"1f4b1\",\"1f4b2\",\"1f4b3\",\"1f4b4\",\"1f4b5\",\"1f4b6\",\"1f4b7\",\"1f4b8\",\"1f4b9\",\"1f4ba\",\"1f4bb\",\"1f4bc\",\"1f4bd\",\"1f4be\",\"1f4bf\",\"1f4c0\",\"1f4c1\",\"1f4c2\",\"1f4c3\",\"1f4c4\",\"1f4c5\",\"1f4c6\",\"1f4c7\",\"1f4c8\",\"1f4c9\",\"1f4ca\",\"1f4cb\",\"1f4cc\",\"1f4cd\",\"1f4ce\",\"1f4cf\",\"1f4d0\",\"1f4d1\",\"1f4d2\",\"1f4d3\",\"1f4d4\",\"1f4d5\",\"1f4d6\",\"1f4d7\",\"1f4d8\",\"1f4d9\",\"1f4da\",\"1f4db\",\"1f4dc\",\"1f4dd\",\"1f4de\",\"1f4df\",\"1f4e0\",\"1f4e1\",\"1f4e2\",\"1f4e3\",\"1f4e4\",\"1f4e5\",\"1f4e6\",\"1f4e7\",\"1f4e8\",\"1f4e9\",\"1f4ea\",\"1f4eb\",\"1f4ec\",\"1f4ed\",\"1f4ee\",\"1f4ef\",\"1f4f0\",\"1f4f1\",\"1f4f2\",\"1f4f3\",\"1f4f4\",\"1f4f5\",\"1f4f6\",\"1f4f7\",\"1f4f9\",\"1f4fa\",\"1f4fb\",\"1f4fc\",\"1f500\",\"1f501\",\"1f502\",\"1f503\",\"1f504\",\"1f505\",\"1f506\",\"1f507\",\"1f508\",\"1f509\",\"1f50a\",\"1f50b\",\"1f50c\",\"1f50d\",\"1f50e\",\"1f50f\",\"1f510\",\"1f511\",\"1f512\",\"1f513\",\"1f514\",\"1f515\",\"1f516\",\"1f517\",\"1f518\",\"1f519\",\"1f51a\",\"1f51b\",\"1f51c\",\"1f51d\",\"1f51e\",\"1f51f\",\"1f520\",\"1f521\",\"1f522\",\"1f523\",\"1f524\",\"1f525\",\"1f526\",\"1f527\",\"1f528\",\"1f529\",\"1f52a\",\"1f52b\",\"1f52c\",\"1f52d\",\"1f52e\",\"1f52f\",\"1f530\",\"1f531\",\"1f532\",\"1f533\",\"1f534\",\"1f535\",\"1f536\",\"1f537\",\"1f538\",\"1f539\",\"1f53a\",\"1f53b\",\"1f53c\",\"1f53d\",\"1f550\",\"1f551\",\"1f552\",\"1f553\",\"1f554\",\"1f555\",\"1f556\",\"1f557\",\"1f558\",\"1f559\",\"1f55a\",\"1f55b\",\"1f55c\",\"1f55d\",\"1f55e\",\"1f55f\",\"1f560\",\"1f561\",\"1f562\",\"1f563\",\"1f564\",\"1f565\",\"1f566\",\"1f567\",\"1f5fb\",\"1f5fc\",\"1f5fd\",\"1f5fe\",\"1f5ff\",\"1f600\",\"1f601\",\"1f602\",\"1f603\",\"1f604\",\"1f605\",\"1f606\",\"1f607\",\"1f608\",\"1f609\",\"1f60a\",\"1f60b\",\"1f60c\",\"1f60d\",\"1f60e\",\"1f60f\",\"1f610\",\"1f611\",\"1f612\",\"1f613\",\"1f614\",\"1f615\",\"1f616\",\"1f617\",\"1f618\",\"1f619\",\"1f61a\",\"1f61b\",\"1f61c\",\"1f61d\",\"1f61e\",\"1f61f\",\"1f620\",\"1f621\",\"1f622\",\"1f623\",\"1f624\",\"1f625\",\"1f626\",\"1f627\",\"1f628\",\"1f629\",\"1f62a\",\"1f62b\",\"1f62c\",\"1f62d\",\"1f62e\",\"1f62f\",\"1f630\",\"1f631\",\"1f632\",\"1f633\",\"1f634\",\"1f635\",\"1f636\",\"1f637\",\"1f638\",\"1f639\",\"1f63a\",\"1f63b\",\"1f63c\",\"1f63d\",\"1f63e\",\"1f63f\",\"1f640\",\"1f645\",\"1f646\",\"1f647\",\"1f648\",\"1f649\",\"1f64a\",\"1f64b\",\"1f64c\",\"1f64d\",\"1f64e\",\"1f64f\",\"1f680\",\"1f681\",\"1f682\",\"1f683\",\"1f684\",\"1f685\",\"1f686\",\"1f687\",\"1f688\",\"1f689\",\"1f68a\",\"1f68b\",\"1f68c\",\"1f68d\",\"1f68e\",\"1f68f\",\"1f690\",\"1f691\",\"1f692\",\"1f693\",\"1f694\",\"1f695\",\"1f696\",\"1f697\",\"1f698\",\"1f699\",\"1f69a\",\"1f69b\",\"1f69c\",\"1f69d\",\"1f69e\",\"1f69f\",\"1f6a0\",\"1f6a1\",\"1f6a2\",\"1f6a3\",\"1f6a4\",\"1f6a5\",\"1f6a6\",\"1f6a7\",\"1f6a8\",\"1f6a9\",\"1f6aa\",\"1f6ab\",\"1f6ac\",\"1f6ad\",\"1f6ae\",\"1f6af\",\"1f6b0\",\"1f6b1\",\"1f6b2\",\"1f6b3\",\"1f6b4\",\"1f6b5\",\"1f6b6\",\"1f6b7\",\"1f6b8\",\"1f6b9\",\"1f6ba\",\"1f6bb\",\"1f6bc\",\"1f6bd\",\"1f6be\",\"1f6bf\",\"1f6c0\",\"1f6c1\",\"1f6c2\",\"1f6c3\",\"1f6c4\",\"1f6c5\",\"203c\",\"2049\",\"2122\",\"2139\",\"2194\",\"2195\",\"2196\",\"2197\",\"2198\",\"2199\",\"21a9\",\"21aa\",\"23-20e3\",\"231a\",\"231b\",\"23e9\",\"23ea\",\"23eb\",\"23ec\",\"23f0\",\"23f3\",\"24c2\",\"25aa\",\"25ab\",\"25b6\",\"25c0\",\"25fb\",\"25fc\",\"25fd\",\"25fe\",\"2600\",\"2601\",\"260e\",\"2611\",\"2614\",\"2615\",\"261d\",\"263a\",\"2648\",\"2649\",\"264a\",\"264b\",\"264c\",\"264d\",\"264e\",\"264f\",\"2650\",\"2651\",\"2652\",\"2653\",\"2660\",\"2663\",\"2665\",\"2666\",\"2668\",\"267b\",\"267f\",\"2693\",\"26a0\",\"26a1\",\"26aa\",\"26ab\",\"26bd\",\"26be\",\"26c4\",\"26c5\",\"26ce\",\"26d4\",\"26ea\",\"26f2\",\"26f3\",\"26f5\",\"26fa\",\"26fd\",\"2702\",\"2705\",\"2708\",\"2709\",\"270a\",\"270b\",\"270c\",\"270f\",\"2712\",\"2714\",\"2716\",\"2728\",\"2733\",\"2734\",\"2744\",\"2747\",\"274c\",\"274e\",\"2753\",\"2754\",\"2755\",\"2757\",\"2764\",\"2795\",\"2796\",\"2797\",\"27a1\",\"27b0\",\"27bf\",\"2934\",\"2935\",\"2b05\",\"2b06\",\"2b07\",\"2b1b\",\"2b1c\",\"2b50\",\"2b55\",\"30-20e3\",\"3030\",\"303d\",\"31-20e3\",\"32-20e3\",\"3297\",\"3299\",\"33-20e3\",\"34-20e3\",\"35-20e3\",\"36-20e3\",\"37-20e3\",\"38-20e3\",\"39-20e3\",\"a9\",\"ae\",\"e50a\"],\n\n\t\"font-awesome\" : [\"glass\",\"music\",\"search\",\"envelope-o\",\"heart\",\"star\",\"star-o\",\"user\",\"film\",\"th-large\",\"th\",\"th-list\",\"check\",\"times\",\"search-plus\",\"search-minus\",\"power-off\",\"signal\",\"cog\",\"trash-o\",\"home\",\"file-o\",\"clock-o\",\"road\",\"download\",\"arrow-circle-o-down\",\"arrow-circle-o-up\",\"inbox\",\"play-circle-o\",\"repeat\",\"refresh\",\"list-alt\",\"lock\",\"flag\",\"headphones\",\"volume-off\",\"volume-down\",\"volume-up\",\"qrcode\",\"barcode\",\"tag\",\"tags\",\"book\",\"bookmark\",\"print\",\"camera\",\"font\",\"bold\",\"italic\",\"text-height\",\"text-width\",\"align-left\",\"align-center\",\"align-right\",\"align-justify\",\"list\",\"outdent\",\"indent\",\"video-camera\",\"picture-o\",\"pencil\",\"map-marker\",\"adjust\",\"tint\",\"pencil-square-o\",\"share-square-o\",\"check-square-o\",\"arrows\",\"step-backward\",\"fast-backward\",\"backward\",\"play\",\"pause\",\"stop\",\"forward\",\"fast-forward\",\"step-forward\",\"eject\",\"chevron-left\",\"chevron-right\",\"plus-circle\",\"minus-circle\",\"times-circle\",\"check-circle\",\"question-circle\",\"info-circle\",\"crosshairs\",\"times-circle-o\",\"check-circle-o\",\"ban\",\"arrow-left\",\"arrow-right\",\"arrow-up\",\"arrow-down\",\"share\",\"expand\",\"compress\",\"plus\",\"minus\",\"asterisk\",\"exclamation-circle\",\"gift\",\"leaf\",\"fire\",\"eye\",\"eye-slash\",\"exclamation-triangle\",\"plane\",\"calendar\",\"random\",\"comment\",\"magnet\",\"chevron-up\",\"chevron-down\",\"retweet\",\"shopping-cart\",\"folder\",\"folder-open\",\"arrows-v\",\"arrows-h\",\"bar-chart\",\"twitter-square\",\"facebook-square\",\"camera-retro\",\"key\",\"cogs\",\"comments\",\"thumbs-o-up\",\"thumbs-o-down\",\"star-half\",\"heart-o\",\"sign-out\",\"linkedin-square\",\"thumb-tack\",\"external-link\",\"sign-in\",\"trophy\",\"github-square\",\"upload\",\"lemon-o\",\"phone\",\"square-o\",\"bookmark-o\",\"phone-square\",\"twitter\",\"facebook\",\"github\",\"unlock\",\"credit-card\",\"rss\",\"hdd-o\",\"bullhorn\",\"bell\",\"certificate\",\"hand-o-right\",\"hand-o-left\",\"hand-o-up\",\"hand-o-down\",\"arrow-circle-left\",\"arrow-circle-right\",\"arrow-circle-up\",\"arrow-circle-down\",\"globe\",\"wrench\",\"tasks\",\"filter\",\"briefcase\",\"arrows-alt\",\"users\",\"link\",\"cloud\",\"flask\",\"scissors\",\"files-o\",\"paperclip\",\"floppy-o\",\"square\",\"bars\",\"list-ul\",\"list-ol\",\"strikethrough\",\"underline\",\"table\",\"magic\",\"truck\",\"pinterest\",\"pinterest-square\",\"google-plus-square\",\"google-plus\",\"money\",\"caret-down\",\"caret-up\",\"caret-left\",\"caret-right\",\"columns\",\"sort\",\"sort-desc\",\"sort-asc\",\"envelope\",\"linkedin\",\"undo\",\"gavel\",\"tachometer\",\"comment-o\",\"comments-o\",\"bolt\",\"sitemap\",\"umbrella\",\"clipboard\",\"lightbulb-o\",\"exchange\",\"cloud-download\",\"cloud-upload\",\"user-md\",\"stethoscope\",\"suitcase\",\"bell-o\",\"coffee\",\"cutlery\",\"file-text-o\",\"building-o\",\"hospital-o\",\"ambulance\",\"medkit\",\"fighter-jet\",\"beer\",\"h-square\",\"plus-square\",\"angle-double-left\",\"angle-double-right\",\"angle-double-up\",\"angle-double-down\",\"angle-left\",\"angle-right\",\"angle-up\",\"angle-down\",\"desktop\",\"laptop\",\"tablet\",\"mobile\",\"circle-o\",\"quote-left\",\"quote-right\",\"spinner\",\"circle\",\"reply\",\"github-alt\",\"folder-o\",\"folder-open-o\",\"smile-o\",\"frown-o\",\"meh-o\",\"gamepad\",\"keyboard-o\",\"flag-o\",\"flag-checkered\",\"terminal\",\"code\",\"reply-all\",\"star-half-o\",\"location-arrow\",\"crop\",\"code-fork\",\"chain-broken\",\"question\",\"info\",\"exclamation\",\"superscript\",\"subscript\",\"eraser\",\"puzzle-piece\",\"microphone\",\"microphone-slash\",\"shield\",\"calendar-o\",\"fire-extinguisher\",\"rocket\",\"maxcdn\",\"chevron-circle-left\",\"chevron-circle-right\",\"chevron-circle-up\",\"chevron-circle-down\",\"html5\",\"css3\",\"anchor\",\"unlock-alt\",\"bullseye\",\"ellipsis-h\",\"ellipsis-v\",\"rss-square\",\"play-circle\",\"ticket\",\"minus-square\",\"minus-square-o\",\"level-up\",\"level-down\",\"check-square\",\"pencil-square\",\"share-square\",\"compass\",\"caret-square-o-down\",\"caret-square-o-up\",\"caret-square-o-right\",\"eur\",\"gbp\",\"usd\",\"inr\",\"jpy\",\"rub\",\"krw\",\"btc\",\"file\",\"file-text\",\"sort-alpha-asc\",\"sort-alpha-desc\",\"sort-amount-asc\",\"sort-amount-desc\",\"sort-numeric-asc\",\"sort-numeric-desc\",\"thumbs-up\",\"thumbs-down\",\"youtube-square\",\"youtube\",\"xing\",\"xing-square\",\"youtube-play\",\"dropbox\",\"stack-overflow\",\"instagram\",\"flickr\",\"adn\",\"bitbucket\",\"bitbucket-square\",\"tumblr\",\"tumblr-square\",\"long-arrow-down\",\"long-arrow-up\",\"long-arrow-left\",\"long-arrow-right\",\"apple\",\"windows\",\"android\",\"linux\",\"dribbble\",\"skype\",\"foursquare\",\"trello\",\"female\",\"male\",\"gratipay\",\"sun-o\",\"moon-o\",\"archive\",\"bug\",\"vk\",\"weibo\",\"renren\",\"pagelines\",\"stack-exchange\",\"arrow-circle-o-right\",\"arrow-circle-o-left\",\"caret-square-o-left\",\"dot-circle-o\",\"wheelchair\",\"vimeo-square\",\"try\",\"plus-square-o\",\"space-shuttle\",\"slack\",\"envelope-square\",\"wordpress\",\"openid\",\"university\",\"graduation-cap\",\"yahoo\",\"google\",\"reddit\",\"reddit-square\",\"stumbleupon-circle\",\"stumbleupon\",\"delicious\",\"digg\",\"pied-piper\",\"pied-piper-alt\",\"drupal\",\"joomla\",\"language\",\"fax\",\"building\",\"child\",\"paw\",\"spoon\",\"cube\",\"cubes\",\"behance\",\"behance-square\",\"steam\",\"steam-square\",\"recycle\",\"car\",\"taxi\",\"tree\",\"spotify\",\"deviantart\",\"soundcloud\",\"database\",\"file-pdf-o\",\"file-word-o\",\"file-excel-o\",\"file-powerpoint-o\",\"file-image-o\",\"file-archive-o\",\"file-audio-o\",\"file-video-o\",\"file-code-o\",\"vine\",\"codepen\",\"jsfiddle\",\"life-ring\",\"circle-o-notch\",\"rebel\",\"empire\",\"git-square\",\"git\",\"hacker-news\",\"tencent-weibo\",\"qq\",\"weixin\",\"paper-plane\",\"paper-plane-o\",\"history\",\"circle-thin\",\"header\",\"paragraph\",\"sliders\",\"share-alt\",\"share-alt-square\",\"bomb\",\"futbol-o\",\"tty\",\"binoculars\",\"plug\",\"slideshare\",\"twitch\",\"yelp\",\"newspaper-o\",\"wifi\",\"calculator\",\"paypal\",\"google-wallet\",\"cc-visa\",\"cc-mastercard\",\"cc-discover\",\"cc-amex\",\"cc-paypal\",\"cc-stripe\",\"bell-slash\",\"bell-slash-o\",\"trash\",\"copyright\",\"at\",\"eyedropper\",\"paint-brush\",\"birthday-cake\",\"area-chart\",\"pie-chart\",\"line-chart\",\"lastfm\",\"lastfm-square\",\"toggle-off\",\"toggle-on\",\"bicycle\",\"bus\",\"ioxhost\",\"angellist\",\"cc\",\"ils\",\"meanpath\",\"buysellads\",\"connectdevelop\",\"dashcube\",\"forumbee\",\"leanpub\",\"sellsy\",\"shirtsinbulk\",\"simplybuilt\",\"skyatlas\",\"cart-plus\",\"cart-arrow-down\",\"diamond\",\"ship\",\"user-secret\",\"motorcycle\",\"street-view\",\"heartbeat\",\"venus\",\"mars\",\"mercury\",\"transgender\",\"transgender-alt\",\"venus-double\",\"mars-double\",\"venus-mars\",\"mars-stroke\",\"mars-stroke-v\",\"mars-stroke-h\",\"neuter\",\"facebook-official\",\"pinterest-p\",\"whatsapp\",\"server\",\"user-plus\",\"user-times\",\"bed\",\"viacoin\",\"train\",\"subway\",\"medium\",\"GitHub\",\"bed\",\"buysellads\",\"cart-arrow-down\",\"cart-plus\",\"connectdevelop\",\"dashcube\",\"diamond\",\"facebook-official\",\"forumbee\",\"heartbeat\",\"hotel\",\"leanpub\",\"mars\",\"mars-double\",\"mars-stroke\",\"mars-stroke-h\",\"mars-stroke-v\",\"medium\",\"mercury\",\"motorcycle\",\"neuter\",\"pinterest-p\",\"sellsy\",\"server\",\"ship\",\"shirtsinbulk\",\"simplybuilt\",\"skyatlas\",\"street-view\",\"subway\",\"train\",\"transgender\",\"transgender-alt\",\"user-plus\",\"user-secret\",\"user-times\",\"venus\",\"venus-double\",\"venus-mars\",\"viacoin\",\"whatsapp\",\"adjust\",\"anchor\",\"archive\",\"area-chart\",\"arrows\",\"arrows-h\",\"arrows-v\",\"asterisk\",\"at\",\"automobile\",\"ban\",\"bank\",\"bar-chart\",\"bar-chart-o\",\"barcode\",\"bars\",\"bed\",\"beer\",\"bell\",\"bell-o\",\"bell-slash\",\"bell-slash-o\",\"bicycle\",\"binoculars\",\"birthday-cake\",\"bolt\",\"bomb\",\"book\",\"bookmark\",\"bookmark-o\",\"briefcase\",\"bug\",\"building\",\"building-o\",\"bullhorn\",\"bullseye\",\"bus\",\"cab\",\"calculator\",\"calendar\",\"calendar-o\",\"camera\",\"camera-retro\",\"car\",\"caret-square-o-down\",\"caret-square-o-left\",\"caret-square-o-right\",\"caret-square-o-up\",\"cart-arrow-down\",\"cart-plus\",\"cc\",\"certificate\",\"check\",\"check-circle\",\"check-circle-o\",\"check-square\",\"check-square-o\",\"child\",\"circle\",\"circle-o\",\"circle-o-notch\",\"circle-thin\",\"clock-o\",\"close\",\"cloud\",\"cloud-download\",\"cloud-upload\",\"code\",\"code-fork\",\"coffee\",\"cog\",\"cogs\",\"comment\",\"comment-o\",\"comments\",\"comments-o\",\"compass\",\"copyright\",\"credit-card\",\"crop\",\"crosshairs\",\"cube\",\"cubes\",\"cutlery\",\"dashboard\",\"database\",\"desktop\",\"diamond\",\"dot-circle-o\",\"download\",\"edit\",\"ellipsis-h\",\"ellipsis-v\",\"envelope\",\"envelope-o\",\"envelope-square\",\"eraser\",\"exchange\",\"exclamation\",\"exclamation-circle\",\"exclamation-triangle\",\"external-link\",\"external-link-square\",\"eye\",\"eye-slash\",\"eyedropper\",\"fax\",\"female\",\"fighter-jet\",\"file-archive-o\",\"file-audio-o\",\"file-code-o\",\"file-excel-o\",\"file-image-o\",\"file-movie-o\",\"file-pdf-o\",\"file-photo-o\",\"file-picture-o\",\"file-powerpoint-o\",\"file-sound-o\",\"file-video-o\",\"file-word-o\",\"file-zip-o\",\"film\",\"filter\",\"fire\",\"fire-extinguisher\",\"flag\",\"flag-checkered\",\"flag-o\",\"flash\",\"flask\",\"folder\",\"folder-o\",\"folder-open\",\"folder-open-o\",\"frown-o\",\"futbol-o\",\"gamepad\",\"gavel\",\"gear\",\"gears\",\"genderless\",\"gift\",\"glass\",\"globe\",\"graduation-cap\",\"group\",\"hdd-o\",\"headphones\",\"heart\",\"heart-o\",\"heartbeat\",\"history\",\"home\",\"hotel\",\"image\",\"inbox\",\"info\",\"info-circle\",\"institution\",\"key\",\"keyboard-o\",\"language\",\"laptop\",\"leaf\",\"legal\",\"lemon-o\",\"level-down\",\"level-up\",\"life-bouy\",\"life-buoy\",\"life-ring\",\"life-saver\",\"lightbulb-o\",\"line-chart\",\"location-arrow\",\"lock\",\"magic\",\"magnet\",\"mail-forward\",\"mail-reply\",\"mail-reply-all\",\"male\",\"map-marker\",\"meh-o\",\"microphone\",\"microphone-slash\",\"minus\",\"minus-circle\",\"minus-square\",\"minus-square-o\",\"mobile\",\"mobile-phone\",\"money\",\"moon-o\",\"mortar-board\",\"motorcycle\",\"music\",\"navicon\",\"newspaper-o\",\"paint-brush\",\"paper-plane\",\"paper-plane-o\",\"paw\",\"pencil\",\"pencil-square\",\"pencil-square-o\",\"phone\",\"phone-square\",\"photo\",\"picture-o\",\"pie-chart\",\"plane\",\"plug\",\"plus\",\"plus-circle\",\"plus-square\",\"plus-square-o\",\"power-off\",\"print\",\"puzzle-piece\",\"qrcode\",\"question\",\"question-circle\",\"quote-left\",\"quote-right\",\"random\",\"recycle\",\"refresh\",\"remove\",\"reorder\",\"reply\",\"reply-all\",\"retweet\",\"road\",\"rocket\",\"rss\",\"rss-square\",\"search\",\"search-minus\",\"search-plus\",\"send\",\"send-o\",\"server\",\"share\",\"share-alt\",\"share-alt-square\",\"share-square\",\"share-square-o\",\"shield\",\"ship\",\"shopping-cart\",\"sign-in\",\"sign-out\",\"signal\",\"sitemap\",\"sliders\",\"smile-o\",\"soccer-ball-o\",\"sort\",\"sort-alpha-asc\",\"sort-alpha-desc\",\"sort-amount-asc\",\"sort-amount-desc\",\"sort-asc\",\"sort-desc\",\"sort-down\",\"sort-numeric-asc\",\"sort-numeric-desc\",\"sort-up\",\"space-shuttle\",\"spinner\",\"spoon\",\"square\",\"square-o\",\"star\",\"star-half\",\"star-half-empty\",\"star-half-full\",\"star-half-o\",\"star-o\",\"street-view\",\"suitcase\",\"sun-o\",\"support\",\"tablet\",\"tachometer\",\"tag\",\"tags\",\"tasks\",\"taxi\",\"terminal\",\"thumb-tack\",\"thumbs-down\",\"thumbs-o-down\",\"thumbs-o-up\",\"thumbs-up\",\"ticket\",\"times\",\"times-circle\",\"times-circle-o\",\"tint\",\"toggle-down\",\"toggle-left\",\"toggle-off\",\"toggle-on\",\"toggle-right\",\"toggle-up\",\"trash\",\"trash-o\",\"tree\",\"trophy\",\"truck\",\"tty\",\"umbrella\",\"university\",\"unlock\",\"unlock-alt\",\"unsorted\",\"upload\",\"user\",\"user-plus\",\"user-secret\",\"user-times\",\"users\",\"video-camera\",\"volume-down\",\"volume-off\",\"volume-up\",\"warning\",\"wheelchair\",\"wifi\",\"wrench\",\"ambulance\",\"automobile\",\"bicycle\",\"bus\",\"cab\",\"car\",\"fighter-jet\",\"motorcycle\",\"plane\",\"rocket\",\"ship\",\"space-shuttle\",\"subway\",\"taxi\",\"train\",\"truck\",\"wheelchair\",\"circle-thin\",\"genderless\",\"mars\",\"mars-double\",\"mars-stroke\",\"mars-stroke-h\",\"mars-stroke-v\",\"mercury\",\"neuter\",\"transgender\",\"transgender-alt\",\"venus\",\"venus-double\",\"venus-mars\",\"file\",\"file-archive-o\",\"file-audio-o\",\"file-code-o\",\"file-excel-o\",\"file-image-o\",\"file-movie-o\",\"file-o\",\"file-pdf-o\",\"file-photo-o\",\"file-picture-o\",\"file-powerpoint-o\",\"file-sound-o\",\"file-text\",\"file-text-o\",\"file-video-o\",\"file-word-o\",\"file-zip-o\",\"circle-o-notch\",\"cog\",\"gear\",\"refresh\",\"spinner\",\"check-square\",\"check-square-o\",\"circle\",\"circle-o\",\"dot-circle-o\",\"minus-square\",\"minus-square-o\",\"plus-square\",\"plus-square-o\",\"square\",\"square-o\",\"cc-amex\",\"cc-discover\",\"cc-mastercard\",\"cc-paypal\",\"cc-stripe\",\"cc-visa\",\"credit-card\",\"google-wallet\",\"paypal\",\"area-chart\",\"bar-chart\",\"bar-chart-o\",\"line-chart\",\"pie-chart\",\"bitcoin\",\"btc\",\"cny\",\"dollar\",\"eur\",\"euro\",\"gbp\",\"ils\",\"inr\",\"jpy\",\"krw\",\"money\",\"rmb\",\"rouble\",\"rub\",\"ruble\",\"rupee\",\"shekel\",\"sheqel\",\"try\",\"turkish-lira\",\"usd\",\"won\",\"yen\",\"align-center\",\"align-justify\",\"align-left\",\"align-right\",\"bold\",\"chain\",\"chain-broken\",\"clipboard\",\"columns\",\"copy\",\"cut\",\"dedent\",\"eraser\",\"file\",\"file-o\",\"file-text\",\"file-text-o\",\"files-o\",\"floppy-o\",\"font\",\"header\",\"indent\",\"italic\",\"link\",\"list\",\"list-alt\",\"list-ol\",\"list-ul\",\"outdent\",\"paperclip\",\"paragraph\",\"paste\",\"repeat\",\"rotate-left\",\"rotate-right\",\"save\",\"scissors\",\"strikethrough\",\"subscript\",\"superscript\",\"table\",\"text-height\",\"text-width\",\"th\",\"th-large\",\"th-list\",\"underline\",\"undo\",\"unlink\",\"angle-double-down\",\"angle-double-left\",\"angle-double-right\",\"angle-double-up\",\"angle-down\",\"angle-left\",\"angle-right\",\"angle-up\",\"arrow-circle-down\",\"arrow-circle-left\",\"arrow-circle-o-down\",\"arrow-circle-o-left\",\"arrow-circle-o-right\",\"arrow-circle-o-up\",\"arrow-circle-right\",\"arrow-circle-up\",\"arrow-down\",\"arrow-left\",\"arrow-right\",\"arrow-up\",\"arrows\",\"arrows-alt\",\"arrows-h\",\"arrows-v\",\"caret-down\",\"caret-left\",\"caret-right\",\"caret-square-o-down\",\"caret-square-o-left\",\"caret-square-o-right\",\"caret-square-o-up\",\"caret-up\",\"chevron-circle-down\",\"chevron-circle-left\",\"chevron-circle-right\",\"chevron-circle-up\",\"chevron-down\",\"chevron-left\",\"chevron-right\",\"chevron-up\",\"hand-o-down\",\"hand-o-left\",\"hand-o-right\",\"hand-o-up\",\"long-arrow-down\",\"long-arrow-left\",\"long-arrow-right\",\"long-arrow-up\",\"toggle-down\",\"toggle-left\",\"toggle-right\",\"toggle-up\",\"arrows-alt\",\"backward\",\"compress\",\"eject\",\"expand\",\"fast-backward\",\"fast-forward\",\"forward\",\"pause\",\"play\",\"play-circle\",\"play-circle-o\",\"step-backward\",\"step-forward\",\"stop\",\"youtube-play\",\"report an issue with Adblock Plus\",\"adn\",\"android\",\"angellist\",\"apple\",\"behance\",\"behance-square\",\"bitbucket\",\"bitbucket-square\",\"bitcoin\",\"btc\",\"buysellads\",\"cc-amex\",\"cc-discover\",\"cc-mastercard\",\"cc-paypal\",\"cc-stripe\",\"cc-visa\",\"codepen\",\"connectdevelop\",\"css3\",\"dashcube\",\"delicious\",\"deviantart\",\"digg\",\"dribbble\",\"dropbox\",\"drupal\",\"empire\",\"facebook\",\"facebook-f\",\"facebook-official\",\"facebook-square\",\"flickr\",\"forumbee\",\"foursquare\",\"ge\",\"git\",\"git-square\",\"github\",\"github-alt\",\"github-square\",\"gittip\",\"google\",\"google-plus\",\"google-plus-square\",\"google-wallet\",\"gratipay\",\"hacker-news\",\"html5\",\"instagram\",\"ioxhost\",\"joomla\",\"jsfiddle\",\"lastfm\",\"lastfm-square\",\"leanpub\",\"linkedin\",\"linkedin-square\",\"linux\",\"maxcdn\",\"meanpath\",\"medium\",\"openid\",\"pagelines\",\"paypal\",\"pied-piper\",\"pied-piper-alt\",\"pinterest\",\"pinterest-p\",\"pinterest-square\",\"qq\",\"ra\",\"rebel\",\"reddit\",\"reddit-square\",\"renren\",\"sellsy\",\"share-alt\",\"share-alt-square\",\"shirtsinbulk\",\"simplybuilt\",\"skyatlas\",\"skype\",\"slack\",\"slideshare\",\"soundcloud\",\"spotify\",\"stack-exchange\",\"stack-overflow\",\"steam\",\"steam-square\",\"stumbleupon\",\"stumbleupon-circle\",\"tencent-weibo\",\"trello\",\"tumblr\",\"tumblr-square\",\"twitch\",\"twitter\",\"twitter-square\",\"viacoin\",\"vimeo-square\",\"vine\",\"vk\",\"wechat\",\"weibo\",\"weixin\",\"whatsapp\",\"windows\",\"wordpress\",\"xing\",\"xing-square\",\"yahoo\",\"yelp\",\"youtube\",\"youtube-play\",\"youtube-square\",\"ambulance\",\"h-square\",\"heart\",\"heart-o\",\"heartbeat\",\"hospital-o\",\"medkit\",\"plus-square\",\"stethoscope\",\"user-md\",\"wheelchair\"]\n}"
  },
  {
    "path": "Public/editor.md/plugins/goto-line-dialog/goto-line-dialog.js",
    "content": "/*!\n * Goto line dialog plugin for Editor.md\n *\n * @file        goto-line-dialog.js\n * @author      pandao\n * @version     1.2.1\n * @updateTime  2015-06-09\n * {@link       https://github.com/pandao/editor.md}\n * @license     MIT\n */\n\n(function() {\n\n\tvar factory = function (exports) {\n\n\t\tvar $            = jQuery;\n\t\tvar pluginName   = \"goto-line-dialog\";\n\n\t\tvar langs = {\n\t\t\t\"zh-cn\" : {\n\t\t\t\ttoolbar : {\n\t\t\t\t\t\"goto-line\" : \"跳转到行\"\n\t\t\t\t},\n\t\t\t\tdialog : {\n\t\t\t\t\t\"goto-line\" : {\n\t\t\t\t\t\ttitle  : \"跳转到行\",\n\t\t\t\t\t\tlabel  : \"请输入行号\",\n\t\t\t\t\t\terror  : \"错误：\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"zh-tw\" : {\n\t\t\t\ttoolbar : {\n\t\t\t\t\t\"goto-line\" : \"跳轉到行\"\n\t\t\t\t},\n\t\t\t\tdialog : {\n\t\t\t\t\t\"goto-line\" : {\n\t\t\t\t\t\ttitle  : \"跳轉到行\",\n\t\t\t\t\t\tlabel  : \"請輸入行號\",\n\t\t\t\t\t\terror  : \"錯誤：\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"en\" : {\n\t\t\t\ttoolbar : {\n\t\t\t\t\t\"goto-line\" : \"Goto line\"\n\t\t\t\t},\n\t\t\t\tdialog : {\n\t\t\t\t\t\"goto-line\" : {\n\t\t\t\t\t\ttitle  : \"Goto line\",\n\t\t\t\t\t\tlabel  : \"Enter a line number, range \",\n\t\t\t\t\t\terror  : \"Error: \"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\texports.fn.gotoLineDialog = function() {\n\t\t\tvar _this       = this;\n\t\t\tvar cm          = this.cm;\n\t\t\tvar editor      = this.editor;\n\t\t\tvar settings    = this.settings;\n\t\t\tvar path        = settings.pluginPath + pluginName +\"/\";\n\t\t\tvar classPrefix = this.classPrefix;\n\t\t\tvar dialogName  = classPrefix + pluginName, dialog;\n\n\t\t\t$.extend(true, this.lang, langs[this.lang.name]);\n\t\t\tthis.setToolbar();\n\n\t\t\tvar lang        = this.lang;\n\t\t\tvar dialogLang  = lang.dialog[\"goto-line\"];\n\t\t\tvar lineCount   = cm.lineCount();\n\n\t\t\tdialogLang.error += dialogLang.label + \" 1-\" + lineCount;\n\n\t\t\tif (editor.find(\".\" + dialogName).length < 1) \n\t\t\t{\t\t\t\n\t\t\t\tvar dialogContent = [\n\t\t\t\t\t\"<div class=\\\"editormd-form\\\" style=\\\"padding: 10px 0;\\\">\",\n\t\t\t\t\t\"<p style=\\\"margin: 0;\\\">\" + dialogLang.label + \" 1-\" + lineCount +\"&nbsp;&nbsp;&nbsp;<input type=\\\"number\\\" class=\\\"number-input\\\" style=\\\"width: 60px;height: 30px;\\\" value=\\\"1\\\" max=\\\"\" + lineCount + \"\\\" min=\\\"1\\\" data-line-number /></p>\",\n\t\t\t\t\t\"</div>\"\n\t\t\t\t].join(\"\\n\");\n\n\t\t\t\tdialog = this.createDialog({\n\t\t\t\t\tname       : dialogName,\n\t\t\t\t\ttitle      : dialogLang.title,\n\t\t\t\t\twidth      : 400,\n\t\t\t\t\theight     : 180,\n\t\t\t\t\tmask       : settings.dialogShowMask,\n\t\t\t\t\tdrag       : settings.dialogDraggable,\n\t\t\t\t\tcontent    : dialogContent,\n\t\t\t\t\tlockScreen : settings.dialogLockScreen,\n\t\t\t\t\tmaskStyle  : {\n\t\t\t\t\t\topacity         : settings.dialogMaskOpacity,\n\t\t\t\t\t\tbackgroundColor : settings.dialogMaskBgColor\n\t\t\t\t\t},\n\t\t\t\t\tbuttons    : {\n                        enter : [lang.buttons.enter, function() {\n\t\t\t\t\t\t\tvar line   = parseInt(this.find(\"[data-line-number]\").val());\n\n\t\t\t\t\t\t\tif (line < 1 || line > lineCount) {\n\t\t\t\t\t\t\t\talert(dialogLang.error);\n\n\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t_this.gotoLine(line);\n\n                            this.hide().lockScreen(false).hideMask();\n\n                            return false;\n                        }],\n\n                        cancel : [lang.buttons.cancel, function() {                                   \n                            this.hide().lockScreen(false).hideMask();\n\n                            return false;\n                        }]\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tdialog = editor.find(\".\" + dialogName);\n\n\t\t\tthis.dialogShowMask(dialog);\n\t\t\tthis.dialogLockScreen();\n\t\t\tdialog.show();\n\t\t};\n\n\t};\n    \n\t// CommonJS/Node.js\n\tif (typeof require === \"function\" && typeof exports === \"object\" && typeof module === \"object\")\n    { \n        module.exports = factory;\n    }\n\telse if (typeof define === \"function\")  // AMD/CMD/Sea.js\n    {\n\t\tif (define.amd) { // for Require.js\n\n\t\t\tdefine([\"editormd\"], function(editormd) {\n                factory(editormd);\n            });\n\n\t\t} else { // for Sea.js\n\t\t\tdefine(function(require) {\n                var editormd = require(\"./../../editormd\");\n                factory(editormd);\n            });\n\t\t}\n\t} \n\telse\n\t{\n        factory(window.editormd);\n\t}\n\n})();\n"
  },
  {
    "path": "Public/editor.md/plugins/help-dialog/help-dialog.js",
    "content": "/*!\n * Help dialog plugin for Editor.md\n *\n * @file        help-dialog.js\n * @author      pandao\n * @version     1.2.0\n * @updateTime  2015-03-08\n * {@link       https://github.com/pandao/editor.md}\n * @license     MIT\n */\n\n(function() {\n\n\tvar factory = function (exports) {\n\n\t\tvar $            = jQuery;\n\t\tvar pluginName   = \"help-dialog\";\n\n\t\texports.fn.helpDialog = function() {\n\t\t\tvar _this       = this;\n\t\t\tvar lang        = this.lang;\n\t\t\tvar editor      = this.editor;\n\t\t\tvar settings    = this.settings;\n\t\t\tvar path        = settings.pluginPath + pluginName + \"/\";\n\t\t\tvar classPrefix = this.classPrefix;\n\t\t\tvar dialogName  = classPrefix + pluginName, dialog;\n\t\t\tvar dialogLang  = lang.dialog.help;\n\n\t\t\tif (editor.find(\".\" + dialogName).length < 1)\n\t\t\t{\t\t\t\n\t\t\t\tvar dialogContent = \"<div class=\\\"markdown-body\\\" style=\\\"font-family:微软雅黑, Helvetica, Tahoma, STXihei,Arial;height:390px;overflow:auto;font-size:14px;border-bottom:1px solid #ddd;padding:0 20px 20px 0;\\\"></div>\";\n\n\t\t\t\tdialog = this.createDialog({\n\t\t\t\t\tname       : dialogName,\n\t\t\t\t\ttitle      : dialogLang.title,\n\t\t\t\t\twidth      : 840,\n\t\t\t\t\theight     : 540,\n\t\t\t\t\tmask       : settings.dialogShowMask,\n\t\t\t\t\tdrag       : settings.dialogDraggable,\n\t\t\t\t\tcontent    : dialogContent,\n\t\t\t\t\tlockScreen : settings.dialogLockScreen,\n\t\t\t\t\tmaskStyle  : {\n\t\t\t\t\t\topacity         : settings.dialogMaskOpacity,\n\t\t\t\t\t\tbackgroundColor : settings.dialogMaskBgColor\n\t\t\t\t\t},\n\t\t\t\t\tbuttons    : {\n\t\t\t\t\t\tclose : [lang.buttons.close, function() {      \n\t\t\t\t\t\t\tthis.hide().lockScreen(false).hideMask();\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}]\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tdialog = editor.find(\".\" + dialogName);\n\n\t\t\tthis.dialogShowMask(dialog);\n\t\t\tthis.dialogLockScreen();\n\t\t\tdialog.show();\n\n\t\t\tvar helpContent = dialog.find(\".markdown-body\");\n\n\t\t\tif (helpContent.html() === \"\") \n\t\t\t{\n\t\t\t\t$.get(path + \"help.md\", function(text) {\n\t\t\t\t\tvar md = exports.$marked(text);\n\t\t\t\t\thelpContent.html(md);\n                    \n                    helpContent.find(\"a\").attr(\"target\", \"_blank\");\n\t\t\t\t});\n\t\t\t}\n\t\t};\n\n\t};\n    \n\t// CommonJS/Node.js\n\tif (typeof require === \"function\" && typeof exports === \"object\" && typeof module === \"object\")\n    { \n        module.exports = factory;\n    }\n\telse if (typeof define === \"function\")  // AMD/CMD/Sea.js\n    {\n\t\tif (define.amd) { // for Require.js\n\n\t\t\tdefine([\"editormd\"], function(editormd) {\n                factory(editormd);\n            });\n\n\t\t} else { // for Sea.js\n\t\t\tdefine(function(require) {\n                var editormd = require(\"./../../editormd\");\n                factory(editormd);\n            });\n\t\t}\n\t} \n\telse\n\t{\n        factory(window.editormd);\n\t}\n\n})();\n"
  },
  {
    "path": "Public/editor.md/plugins/help-dialog/help.md",
    "content": "##### Markdown语法教程 (Markdown syntax tutorial)\n\n- [Markdown Syntax](http://daringfireball.net/projects/markdown/syntax/ \"Markdown Syntax\")\n- [Mastering Markdown](https://guides.github.com/features/mastering-markdown/ \"Mastering Markdown\")\n- [Markdown Basics](https://help.github.com/articles/markdown-basics/ \"Markdown Basics\")\n- [GitHub Flavored Markdown](https://help.github.com/articles/github-flavored-markdown/ \"GitHub Flavored Markdown\")\n- [Markdown 语法说明（简体中文）](http://www.markdown.cn/ \"Markdown 语法说明（简体中文）\")\n- [Markdown 語法說明（繁體中文）](http://markdown.tw/ \"Markdown 語法說明（繁體中文）\")\n\n##### 键盘快捷键 (Keyboard shortcuts)\n\n> If Editor.md code editor is on focus, you can use keyboard shortcuts.\n    \n| Keyboard shortcuts (键盘快捷键)                 |   说明                            | Description                                        |\n| :---------------------------------------------- |:--------------------------------- | :------------------------------------------------- |\n| F9                                              | 切换实时预览                      | Switch watch/unwatch                               |\n| F10                                             | 全屏HTML预览(按 Shift + ESC 退出) | Full preview HTML (Press Shift + ESC exit)         |\n| F11                                             | 切换全屏状态                      | Switch fullscreen (Press ESC exit)                 |\n| Ctrl + 1~6 / Command + 1~6                      | 插入标题1~6                       | Insert heading 1~6                                 |\n| Ctrl + A / Command + A                          | 全选                              | Select all                                         |\n| Ctrl + B / Command + B                          | 插入粗体                          | Insert bold                                        |\n| Ctrl + D / Command + D                          | 插入日期时间                      | Insert datetime                                    |\n| Ctrl + E / Command + E                          | 插入Emoji符号                     | Insert &#58;emoji&#58;                             |\n| Ctrl + F / Command + F                          | 查找/搜索                         | Start searching                                    |\n| Ctrl + G / Command + G                          | 切换到下一个搜索结果项            | Find next search results                           |\n| Ctrl + H / Command + H                          | 插入水平线                        | Insert horizontal rule                             |\n| Ctrl + I / Command + I                          | 插入斜体                          | Insert italic                                      |\n| Ctrl + K / Command + K                          | 插入行内代码                      | Insert inline code                                 |\n| Ctrl + L / Command + L                          | 插入链接                          | Insert link                                        |\n| Ctrl + U / Command + U                          | 插入无序列表                      | Insert unordered list                              |\n| Ctrl + Q                                        | 代码折叠切换                      | Switch code fold                                   |\n| Ctrl + Z / Command + Z                          | 撤销                              | Undo                                               |\n| Ctrl + Y / Command + Y                          | 重做                              | Redo                                               |\n| Ctrl + Shift + A                                | 插入@链接                         | Insert &#64;link                                   |\n| Ctrl + Shift + C                                | 插入行内代码                      | Insert inline code                                 |\n| Ctrl + Shift + E                                | 打开插入Emoji表情对话框           | Open emoji dialog                                  |\n| Ctrl + Shift + F / Command + Option + F         | 替换                              | Replace                                            |\n| Ctrl + Shift + G / Shift + Command + G          | 切换到上一个搜索结果项            | Find previous search results                       |\n| Ctrl + Shift + H                                | 打开HTML实体字符对话框            | Open HTML Entities dialog                          |\n| Ctrl + Shift + I                                | 插入图片                          | Insert image &#33;[]&#40;&#41;                     |\n| Ctrl + Shift + K                                | 插入TeX(KaTeX)公式符号            | Insert TeX(KaTeX) symbol &#36;&#36;TeX&#36;&#36;   |\n| Ctrl + Shift + L                                | 打开插入链接对话框                | Open link dialog                                   |\n| Ctrl + Shift + O                                | 插入有序列表                      | Insert ordered list                                |\n| Ctrl + Shift + P                                | 打开插入PRE对话框                 | Open Preformatted text dialog                      |\n| Ctrl + Shift + Q                                | 插入引用                          | Insert blockquotes                                 |\n| Ctrl + Shift + R / Shift + Command + Option + F | 全部替换                          | Replace all                                        |\n| Ctrl + Shift + S                                | 插入删除线                        | Insert strikethrough                               |\n| Ctrl + Shift + T                                | 打开插入表格对话框                | Open table dialog                                  |\n| Ctrl + Shift + U                                | 将所选文字转成大写                | Selection text convert to uppercase                |\n| Shift + Alt + C                                 | 插入```代码                       | Insert code blocks (```)                           |\n| Shift + Alt + H                                 | 打开使用帮助对话框                | Open help dialog                                   |\n| Shift + Alt + L                                 | 将所选文本转成小写                | Selection text convert to lowercase                |\n| Shift + Alt + P                                 | 插入分页符                        | Insert page break                                  |\n| Alt + L                                         | 将所选文本转成小写                | Selection text convert to lowercase                |\n| Shift + Alt + U                                 | 将所选的每个单词的首字母转成大写  | Selection words first letter convert to Uppercase  |\n| Ctrl + Shift + Alt + C                          | 打开插入代码块对话框层            | Open code blocks dialog                            |\n| Ctrl + Shift + Alt + I                          | 打开插入图片对话框层              | Open image dialog                                  |\n| Ctrl + Shift + Alt + U                          | 将所选文本的第一个首字母转成大写  | Selection text first letter convert to uppercase   |\n| Ctrl + Alt + G                                  | 跳转到指定的行                    | Goto line                                          |\n\n##### Emoji表情参考 (Emoji reference)\n\n- [Github emoji](http://www.emoji-cheat-sheet.com/ \"Github emoji\")\n- [Twitter Emoji \\(Twemoji\\)](http://twitter.github.io/twemoji/preview.html \"Twitter Emoji \\(Twemoji\\)\")\n- [FontAwesome icons emoji](http://fortawesome.github.io/Font-Awesome/icons/ \"FontAwesome icons emoji\")\n\n##### 流程图参考 (Flowchart reference)\n\n[http://adrai.github.io/flowchart.js/](http://adrai.github.io/flowchart.js/)\n\n##### 时序图参考 (SequenceDiagram reference)\n\n[http://bramp.github.io/js-sequence-diagrams/](http://bramp.github.io/js-sequence-diagrams/)\n\n##### TeX/LaTeX reference\n\n[http://meta.wikimedia.org/wiki/Help:Formula](http://meta.wikimedia.org/wiki/Help:Formula)\n"
  },
  {
    "path": "Public/editor.md/plugins/html-entities-dialog/html-entities-dialog.js",
    "content": "/*!\n * HTML entities dialog plugin for Editor.md\n *\n * @file        html-entities-dialog.js\n * @author      pandao\n * @version     1.2.0\n * @updateTime  2015-03-08\n * {@link       https://github.com/pandao/editor.md}\n * @license     MIT\n */\n\n(function() {\n\n\tvar factory = function (exports) {\n\n\t\tvar $            = jQuery;\n\t\tvar pluginName   = \"html-entities-dialog\";\n\t\tvar selecteds    = [];\n\t\tvar entitiesData = [];\n\n\t\texports.fn.htmlEntitiesDialog = function() {\n\t\t\tvar _this       = this;\n\t\t\tvar cm          = this.cm;\n\t\t\tvar lang        = _this.lang;\n\t\t\tvar settings    = _this.settings;\n\t\t\tvar path        = settings.pluginPath + pluginName + \"/\";\n\t\t\tvar editor      = this.editor;\n\t\t\tvar cursor      = cm.getCursor();\n\t\t\tvar selection   = cm.getSelection();\n\t\t\tvar classPrefix = _this.classPrefix;\n\n\t\t\tvar dialogName  = classPrefix + \"dialog-\" + pluginName, dialog;\n\t\t\tvar dialogLang  = lang.dialog.htmlEntities;\n\n\t\t\tvar dialogContent = [\n\t\t\t\t'<div class=\"' + classPrefix + 'html-entities-box\" style=\\\"width: 760px;height: 334px;margin-bottom: 8px;overflow: hidden;overflow-y: auto;\\\">',\n\t\t\t\t'<div class=\"' + classPrefix + 'grid-table\">',\n\t\t\t\t'</div>',\n\t\t\t\t'</div>',\n\t\t\t].join(\"\\r\\n\");\n\n\t\t\tcm.focus();\n\n\t\t\tif (editor.find(\".\" + dialogName).length > 0) \n\t\t\t{\n                dialog = editor.find(\".\" + dialogName);\n\n\t\t\t\tselecteds = [];\n\t\t\t\tdialog.find(\"a\").removeClass(\"selected\");\n\n\t\t\t\tthis.dialogShowMask(dialog);\n\t\t\t\tthis.dialogLockScreen();\n\t\t\t\tdialog.show();\n\t\t\t} \n\t\t\telse\n\t\t\t{\n\t\t\t\tdialog = this.createDialog({\n\t\t\t\t\tname       : dialogName,\n\t\t\t\t\ttitle      : dialogLang.title,\n\t\t\t\t\twidth      : 800,\n\t\t\t\t\theight     : 475,\n\t\t\t\t\tmask       : settings.dialogShowMask,\n\t\t\t\t\tdrag       : settings.dialogDraggable,\n\t\t\t\t\tcontent    : dialogContent,\n\t\t\t\t\tlockScreen : settings.dialogLockScreen,\n\t\t\t\t\tmaskStyle  : {\n\t\t\t\t\t\topacity         : settings.dialogMaskOpacity,\n\t\t\t\t\t\tbackgroundColor : settings.dialogMaskBgColor\n\t\t\t\t\t},\n\t\t\t\t\tbuttons    : {\n\t\t\t\t\t\tenter  : [lang.buttons.enter, function() {\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tcm.replaceSelection(selecteds.join(\" \"));\n\t\t\t\t\t\t\tthis.hide().lockScreen(false).hideMask();\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}],\n\t\t\t\t\t\tcancel : [lang.buttons.cancel, function() {                           \n\t\t\t\t\t\t\tthis.hide().lockScreen(false).hideMask();\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}]\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t\t\t\n\t\t\tvar table = dialog.find(\".\" + classPrefix + \"grid-table\");\n\n\t\t\tvar drawTable = function() {\n\n\t\t\t\tif (entitiesData.length < 1) return ;\n\n\t\t\t\tvar rowNumber = 20;\n\t\t\t\tvar pageTotal = Math.ceil(entitiesData.length / rowNumber);\n\n\t\t\t\ttable.html(\"\");\n\t\t\t\t\n\t\t\t\tfor (var i = 0; i < pageTotal; i++)\n\t\t\t\t{\n\t\t\t\t\tvar row = \"<div class=\\\"\" + classPrefix + \"grid-table-row\\\">\";\n\t\t\t\t\t\n\t\t\t\t\tfor (var x = 0; x < rowNumber; x++)\n\t\t\t\t\t{\n\t\t\t\t\t\tvar entity = entitiesData[(i * rowNumber) + x];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (typeof entity !== \"undefined\")\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tvar name = entity.name.replace(\"&amp;\", \"&\");\n\n\t\t\t\t\t\t\trow += \"<a href=\\\"javascript:;\\\" value=\\\"\" + entity.name + \"\\\" title=\\\"\" + name + \"\\\" class=\\\"\" + classPrefix + \"html-entity-btn\\\">\" + name + \"</a>\";\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\trow += \"</div>\";\n\t\t\t\t\t\n\t\t\t\t\ttable.append(row);\n\t\t\t\t}\n\n\t\t\t\tdialog.find(\".\" + classPrefix + \"html-entity-btn\").bind(exports.mouseOrTouch(\"click\", \"touchend\"), function() {\n\t\t\t\t\t$(this).toggleClass(\"selected\");\n\n\t\t\t\t\tif ($(this).hasClass(\"selected\")) \n\t\t\t\t\t{\n\t\t\t\t\t\tselecteds.push($(this).attr(\"value\"));\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t};\n\t\t\t\n\t\t\tif (entitiesData.length < 1) \n\t\t\t{            \n\t\t\t\tif (typeof (dialog.loading) == \"function\") dialog.loading(true);\n\n\t\t\t\t$.getJSON(path + pluginName.replace(\"-dialog\", \"\") + \".json\", function(json) {\n\n\t\t\t\t\tif (typeof (dialog.loading) == \"function\") dialog.loading(false);\n\n\t\t\t\t\tentitiesData = json;\n\t\t\t\t\tdrawTable();\n\t\t\t\t});\n\t\t\t}\n\t\t\telse\n\t\t\t{\t\t\n\t\t\t\tdrawTable();\n\t\t\t}\n\t\t};\n\n\t};\n    \n\t// CommonJS/Node.js\n\tif (typeof require === \"function\" && typeof exports === \"object\" && typeof module === \"object\")\n    { \n        module.exports = factory;\n    }\n\telse if (typeof define === \"function\")  // AMD/CMD/Sea.js\n    {\n\t\tif (define.amd) { // for Require.js\n\n\t\t\tdefine([\"editormd\"], function(editormd) {\n                factory(editormd);\n            });\n\n\t\t} else { // for Sea.js\n\t\t\tdefine(function(require) {\n                var editormd = require(\"./../../editormd\");\n                factory(editormd);\n            });\n\t\t}\n\t} \n\telse\n\t{\n        factory(window.editormd);\n\t}\n\n})();\n"
  },
  {
    "path": "Public/editor.md/plugins/html-entities-dialog/html-entities.json",
    "content": "[\n\t{\n\t\t\"name\" : \"&amp;#64;\",\n\t\t\"description\":\"at symbol\"\t\t\n\t},\n\t{\n\t\t\"name\":\"&amp;copy;\",\n\t\t\"description\":\"copyright symbol\"\n\t},\n\t{\n\t\t\"name\":\"&amp;reg;\",\n\t\t\"description\":\"registered symbol\"\n\t},\n\t{\n\t\t\"name\":\"&amp;trade;\",\n\t\t\"description\":\"trademark symbol\"\n\t},\n\t{\n\t\t\"name\":\"&amp;hearts;\",\n\t\t\"description\":\"heart\"\n\t},\n\t{\n\t\t\"name\":\"&amp;nbsp;\",\n\t\t\"description\":\"Inserts a non-breaking blank space\"\n\t},\n\t{\n\t\t\"name\":\"&amp;amp;\",\n\t\t\"description\":\"Ampersand\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#36;\",\n\t\t\"description\":\"dollar symbol\"\n\t},\n\t{\n\t\t\"name\":\"&amp;cent;\",\n\t\t\"description\":\"Cent symbol\"\n\t},\n\t{\n\t\t\"name\":\"&amp;pound;\",\n\t\t\"description\":\"Pound\"\n\t},\n\t{\n\t\t\"name\":\"&amp;yen;\",\n\t\t\"description\":\"Yen\"\n\t},\n\t{\n\t\t\"name\":\"&amp;euro;\",\n\t\t\"description\":\"Euro symbol\"\n\t},\n\t{\n\t\t\"name\":\"&amp;quot;\",\n\t\t\"description\":\"quotation mark\"\n\t},\n\t{\n\t\t\"name\":\"&amp;ldquo;\",\n\t\t\"description\":\"Opening Double Quotes \"\n\t},\n\t{\n\t\t\"name\":\"&amp;rdquo;\",\n\t\t\"description\":\"Closing Double Quotes \"\n\t},\n\t{\n\t\t\"name\":\"&amp;lsquo;\",\n\t\t\"description\":\"Opening Single Quote Mark \"\n\t},\n\t{\n\t\t\"name\":\"&amp;rsquo;\",\n\t\t\"description\":\"Closing Single Quote Mark \"\n\t},\n\t{\n\t\t\"name\":\"&amp;laquo;\",\n\t\t\"description\":\"angle quotation mark (left)\"\n\t},\n\t{\n\t\t\"name\":\"&amp;raquo;\",\n\t\t\"description\":\"angle quotation mark (right)\"\n\t},\n\t{\n\t\t\"name\":\"&amp;lsaquo;\",\n\t\t\"description\":\"single left angle quotation\"\n\t},\n\t{\n\t\t\"name\":\"&amp;rsaquo;\",\n\t\t\"description\":\"single right angle quotation\"\n\t},\n\t{\n\t\t\"name\":\"&amp;sect;\",\n\t\t\"description\":\"Section Symbol\"\n\t},\n\t{\n\t\t\"name\":\"&amp;micro;\",\n\t\t\"description\":\"micro sign\"\n\t},\n\t{\n\t\t\"name\":\"&amp;para;\",\n\t\t\"description\":\"Paragraph symbol\"\n\t},\n\t{\n\t\t\"name\":\"&amp;bull;\",\n\t\t\"description\":\"Big List Dot\"\n\t},\n\t{\n\t\t\"name\":\"&amp;middot;\",\n\t\t\"description\":\"Medium List Dot\"\n\t},\n\t{\n\t\t\"name\":\"&amp;hellip;\",\n\t\t\"description\":\"horizontal ellipsis\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#124;\",\n\t\t\"description\":\"vertical bar\"\n\t},\n\t{\n\t\t\"name\":\"&amp;brvbar;\",\n\t\t\"description\":\"broken vertical bar\"\n\t},\n\t{\n\t\t\"name\":\"&amp;ndash;\",\n\t\t\"description\":\"en-dash\"\n\t},\n\t{\n\t\t\"name\":\"&amp;mdash;\",\n\t\t\"description\":\"em-dash\"\n\t},\n\t{\n\t\t\"name\":\"&amp;curren;\",\n\t\t\"description\":\"Generic currency symbol\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#33;\",\n\t\t\"description\":\"exclamation point\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#35;\",\n\t\t\"description\":\"number sign\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#39;\",\n\t\t\"description\":\"single quote\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#40;\",\n\t\t\"description\":\"\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#41;\",\n\t\t\"description\":\"\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#42;\",\n\t\t\"description\":\"asterisk\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#43;\",\n\t\t\"description\":\"plus sign\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#44;\",\n\t\t\"description\":\"comma\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#45;\",\n\t\t\"description\":\"minus sign - hyphen\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#46;\",\n\t\t\"description\":\"period\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#47;\",\n\t\t\"description\":\"slash\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#48;\",\n\t\t\"description\":\"0\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#49;\",\n\t\t\"description\":\"1\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#50;\",\n\t\t\"description\":\"2\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#51;\",\n\t\t\"description\":\"3\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#52;\",\n\t\t\"description\":\"4\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#53;\",\n\t\t\"description\":\"5\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#54;\",\n\t\t\"description\":\"6\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#55;\",\n\t\t\"description\":\"7\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#56;\",\n\t\t\"description\":\"8\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#57;\",\n\t\t\"description\":\"9\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#58;\",\n\t\t\"description\":\"colon\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#59;\",\n\t\t\"description\":\"semicolon\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#61;\",\n\t\t\"description\":\"equal sign\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#63;\",\n\t\t\"description\":\"question mark\"\n\t},\n\t{\n\t\t\"name\":\"&amp;lt;\",\n\t\t\"description\":\"Less than\"\n\t},\n\t{\n\t\t\"name\":\"&amp;gt;\",\n\t\t\"description\":\"Greater than\"\n\t},\n\t{\n\t\t\"name\":\"&amp;le;\",\n\t\t\"description\":\"Less than or Equal to\"\n\t},\n\t{\n\t\t\"name\":\"&amp;ge;\",\n\t\t\"description\":\"Greater than or Equal to\"\n\t},\n\t{\n\t\t\"name\":\"&amp;times;\",\n\t\t\"description\":\"Multiplication symbol\"\n\t},\n\t{\n\t\t\"name\":\"&amp;divide;\",\n\t\t\"description\":\"Division symbol\"\n\t},\n\t{\n\t\t\"name\":\"&amp;minus;\",\n\t\t\"description\":\"Minus symbol\"\n\t},\n\t{\n\t\t\"name\":\"&amp;plusmn;\",\n\t\t\"description\":\"Plus/minus symbol\"\n\t},\n\t{\n\t\t\"name\":\"&amp;ne;\",\n\t\t\"description\":\"Not Equal\"\n\t},\n\t{\n\t\t\"name\":\"&amp;sup1;\",\n\t\t\"description\":\"Superscript 1\"\n\t},\n\t{\n\t\t\"name\":\"&amp;sup2;\",\n\t\t\"description\":\"Superscript 2\"\n\t},\n\t{\n\t\t\"name\":\"&amp;sup3;\",\n\t\t\"description\":\"Superscript 3\"\n\t},\n\t{\n\t\t\"name\":\"&amp;frac12;\",\n\t\t\"description\":\"Fraction ½\"\n\t},\n\t{\n\t\t\"name\":\"&amp;frac14;\",\n\t\t\"description\":\"Fraction ¼\"\n\t},\n\t{\n\t\t\"name\":\"&amp;frac34;\",\n\t\t\"description\":\"Fraction ¾\"\n\t},\n\t{\n\t\t\"name\":\"&amp;permil;\",\n\t\t\"description\":\"per mille\"\n\t},\n\t{\n\t\t\"name\":\"&amp;deg;\",\n\t\t\"description\":\"Degree symbol\"\n\t},\n\t{\n\t\t\"name\":\"&amp;radic;\",\n\t\t\"description\":\"square root\"\n\t},\n\t{\n\t\t\"name\":\"&amp;infin;\",\n\t\t\"description\":\"Infinity\"\n\t},\n\t{\n\t\t\"name\":\"&amp;larr;\",\n\t\t\"description\":\"left arrow\"\n\t},\n\t{\n\t\t\"name\":\"&amp;uarr;\",\n\t\t\"description\":\"up arrow\"\n\t},\n\t{\n\t\t\"name\":\"&amp;rarr;\",\n\t\t\"description\":\"right arrow\"\n\t},\n\t{\n\t\t\"name\":\"&amp;darr;\",\n\t\t\"description\":\"down arrow\"\n\t},\n\t{\n\t\t\"name\":\"&amp;harr;\",\n\t\t\"description\":\"left right arrow\"\n\t},\n\t{\n\t\t\"name\":\"&amp;crarr;\",\n\t\t\"description\":\"carriage return arrow\"\n\t},\n\t{\n\t\t\"name\":\"&amp;lceil;\",\n\t\t\"description\":\"left ceiling\"\n\t},\n\t{\n\t\t\"name\":\"&amp;rceil;\",\n\t\t\"description\":\"right ceiling\"\n\t},\n\t{\n\t\t\"name\":\"&amp;lfloor;\",\n\t\t\"description\":\"left floor\"\n\t},\n\t{\n\t\t\"name\":\"&amp;rfloor;\",\n\t\t\"description\":\"right floor\"\n\t},\n\t{\n\t\t\"name\":\"&amp;spades;\",\n\t\t\"description\":\"spade\"\n\t},\n\t{\n\t\t\"name\":\"&amp;clubs;\",\n\t\t\"description\":\"club\"\n\t},\n\t{\n\t\t\"name\":\"&amp;hearts;\",\n\t\t\"description\":\"heart\"\n\t},\n\t{\n\t\t\"name\":\"&amp;diams;\",\n\t\t\"description\":\"diamond\"\n\t},\n\t{\n\t\t\"name\":\"&amp;loz;\",\n\t\t\"description\":\"lozenge\"\n\t},\n\t{\n\t\t\"name\":\"&amp;dagger;\",\n\t\t\"description\":\"dagger\"\n\t},\n\t{\n\t\t\"name\":\"&amp;Dagger;\",\n\t\t\"description\":\"double dagger\"\n\t},\n\t{\n\t\t\"name\":\"&amp;iexcl;\",\n\t\t\"description\":\"inverted exclamation mark\"\n\t},\n\t{\n\t\t\"name\":\"&amp;iquest;\",\n\t\t\"description\":\"inverted question mark\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#338;\",\n\t\t\"description\":\"latin capital letter OE\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#339;\",\n\t\t\"description\":\"latin small letter oe\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#352;\",\n\t\t\"description\":\"latin capital letter S with caron\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#353;\",\n\t\t\"description\":\"latin small letter s with caron\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#376;\",\n\t\t\"description\":\"latin capital letter Y with diaeresis\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#402;\",\n\t\t\"description\":\"latin small f with hook - function\"\n\t},\n\t{\n\t\t\"name\":\"&amp;not;\",\n\t\t\"description\":\"not sign\"\n\t},\n\t{\n\t\t\"name\":\"&amp;ordf;\",\n\t\t\"description\":\"feminine ordinal indicator\"\n\t},\n\t{\n\t\t\"name\":\"&amp;uml;\",\n\t\t\"description\":\"spacing diaeresis - umlaut\"\n\t},\n\t{\n\t\t\"name\":\"&amp;macr;\",\n\t\t\"description\":\"spacing macron - overline\"\n\t},\n\t{\n\t\t\"name\":\"&amp;acute;\",\n\t\t\"description\":\"acute accent - spacing acute\"\n\t},\n\t{\n\t\t\"name\":\"&amp;Agrave;\",\n\t\t\"description\":\"latin capital letter A with grave\"\n\t},\n\t{\n\t\t\"name\":\"&amp;Aacute;\",\n\t\t\"description\":\"latin capital letter A with acute\"\n\t},\n\t{\n\t\t\"name\":\"&amp;Acirc;\",\n\t\t\"description\":\"latin capital letter A with circumflex\"\n\t},\n\t{\n\t\t\"name\":\"&amp;Atilde;\",\n\t\t\"description\":\"latin capital letter A with tilde\"\n\t},\n\t{\n\t\t\"name\":\"&amp;Auml;\",\n\t\t\"description\":\"latin capital letter A with diaeresis\"\n\t},\n\t{\n\t\t\"name\":\"&amp;Aring;\",\n\t\t\"description\":\"latin capital letter A with ring above\"\n\t},\n\t{\n\t\t\"name\":\"&amp;AElig;\",\n\t\t\"description\":\"latin capital letter AE\"\n\t},\n\t{\n\t\t\"name\":\"&amp;Ccedil;\",\n\t\t\"description\":\"latin capital letter C with cedilla\"\n\t},\n\t{\n\t\t\"name\":\"&amp;Egrave;\",\n\t\t\"description\":\"latin capital letter E with grave\"\n\t},\n\t{\n\t\t\"name\":\"&amp;Eacute;\",\n\t\t\"description\":\"latin capital letter E with acute\"\n\t},\n\t{\n\t\t\"name\":\"&amp;Ecirc;\",\n\t\t\"description\":\"latin capital letter E with circumflex\"\n\t},\n\t{\n\t\t\"name\":\"&amp;Euml;\",\n\t\t\"description\":\"latin capital letter E with diaeresis\"\n\t},\n\t{\n\t\t\"name\":\"&amp;Igrave;\",\n\t\t\"description\":\"latin capital letter I with grave\"\n\t},\n\t{\n\t\t\"name\":\"&amp;Iacute;\",\n\t\t\"description\":\"latin capital letter I with acute\"\n\t},\n\t{\n\t\t\"name\":\"&amp;Icirc;\",\n\t\t\"description\":\"latin capital letter I with circumflex\"\n\t},\n\t{\n\t\t\"name\":\"&amp;Iuml;\",\n\t\t\"description\":\"latin capital letter I with diaeresis\"\n\t},\n\n\t{\n\t\t\"name\":\"&amp;ETH;\",\n\t\t\"description\":\"latin capital letter ETH\"\n\t},\n\t{\n\t\t\"name\":\"&amp;Ntilde;\",\n\t\t\"description\":\"latin capital letter N with tilde\"\n\t},\n\t{\n\t\t\"name\":\"&amp;Ograve;\",\n\t\t\"description\":\"latin capital letter O with grave\"\n\t},\n\t{\n\t\t\"name\":\"&amp;Oacute;\",\n\t\t\"description\":\"latin capital letter O with acute\"\n\t},\n\t{\n\t\t\"name\":\"&amp;Ocirc;\",\n\t\t\"description\":\"latin capital letter O with circumflex\"\n\t},\n\t{\n\t\t\"name\":\"&amp;Otilde;\",\n\t\t\"description\":\"latin capital letter O with tilde\"\n\t},\n\t{\n\t\t\"name\":\"&amp;Ouml;\",\n\t\t\"description\":\"latin capital letter O with diaeresis\"\n\t},\n\t{\n\t\t\"name\":\"&amp;times;\",\n\t\t\"description\":\"multiplication sign\"\n\t},\n\t{\n\t\t\"name\":\"&amp;Oslash;\",\n\t\t\"description\":\"latin capital letter O with slash\"\n\t},\n\t{\n\t\t\"name\":\"&amp;Ugrave;\",\n\t\t\"description\":\"latin capital letter U with grave\"\n\t},\n\t{\n\t\t\"name\":\"&amp;Uacute;\",\n\t\t\"description\":\"latin capital letter U with acute\"\n\t},\n\t{\n\t\t\"name\":\"&amp;Ucirc;\",\n\t\t\"description\":\"latin capital letter U with circumflex\"\n\t},\n\t{\n\t\t\"name\":\"&amp;Uuml;\",\n\t\t\"description\":\"latin capital letter U with diaeresis\"\n\t},\n\t{\n\t\t\"name\":\"&amp;Yacute;\",\n\t\t\"description\":\"latin capital letter Y with acute\"\n\t},\n\t{\n\t\t\"name\":\"&amp;THORN;\",\n\t\t\"description\":\"latin capital letter THORN\"\n\t},\n\t{\n\t\t\"name\":\"&amp;szlig;\",\n\t\t\"description\":\"latin small letter sharp s - ess-zed\"\n\t},\n\n\n\t{\n\t\t\"name\":\"&amp;eth;\",\n\t\t\"description\":\"latin capital letter eth\"\n\t},\n\t{\n\t\t\"name\":\"&amp;ntilde;\",\n\t\t\"description\":\"latin capital letter n with tilde\"\n\t},\n\t{\n\t\t\"name\":\"&amp;ograve;\",\n\t\t\"description\":\"latin capital letter o with grave\"\n\t},\n\t{\n\t\t\"name\":\"&amp;oacute;\",\n\t\t\"description\":\"latin capital letter o with acute\"\n\t},\n\t{\n\t\t\"name\":\"&amp;ocirc;\",\n\t\t\"description\":\"latin capital letter o with circumflex\"\n\t},\n\t{\n\t\t\"name\":\"&amp;otilde;\",\n\t\t\"description\":\"latin capital letter o with tilde\"\n\t},\n\t{\n\t\t\"name\":\"&amp;ouml;\",\n\t\t\"description\":\"latin capital letter o with diaeresis\"\n\t},\n\t{\n\t\t\"name\":\"&amp;times;\",\n\t\t\"description\":\"multiplication sign\"\n\t},\n\t{\n\t\t\"name\":\"&amp;oslash;\",\n\t\t\"description\":\"latin capital letter o with slash\"\n\t},\n\t{\n\t\t\"name\":\"&amp;ugrave;\",\n\t\t\"description\":\"latin capital letter u with grave\"\n\t},\n\t{\n\t\t\"name\":\"&amp;uacute;\",\n\t\t\"description\":\"latin capital letter u with acute\"\n\t},\n\t{\n\t\t\"name\":\"&amp;ucirc;\",\n\t\t\"description\":\"latin capital letter u with circumflex\"\n\t},\n\t{\n\t\t\"name\":\"&amp;uuml;\",\n\t\t\"description\":\"latin capital letter u with diaeresis\"\n\t},\n\t{\n\t\t\"name\":\"&amp;yacute;\",\n\t\t\"description\":\"latin capital letter y with acute\"\n\t},\n\t{\n\t\t\"name\":\"&amp;thorn;\",\n\t\t\"description\":\"latin capital letter thorn\"\n\t},\n\t{\n\t\t\"name\":\"&amp;yuml;\",\n\t\t\"description\":\"latin small letter y with diaeresis\"\n\t},\n\n\t{\n\t\t\"name\":\"&amp;agrave;\",\n\t\t\"description\":\"latin capital letter a with grave\"\n\t},\n\t{\n\t\t\"name\":\"&amp;aacute;\",\n\t\t\"description\":\"latin capital letter a with acute\"\n\t},\n\t{\n\t\t\"name\":\"&amp;acirc;\",\n\t\t\"description\":\"latin capital letter a with circumflex\"\n\t},\n\t{\n\t\t\"name\":\"&amp;atilde;\",\n\t\t\"description\":\"latin capital letter a with tilde\"\n\t},\n\t{\n\t\t\"name\":\"&amp;auml;\",\n\t\t\"description\":\"latin capital letter a with diaeresis\"\n\t},\n\t{\n\t\t\"name\":\"&amp;aring;\",\n\t\t\"description\":\"latin capital letter a with ring above\"\n\t},\n\t{\n\t\t\"name\":\"&amp;aelig;\",\n\t\t\"description\":\"latin capital letter ae\"\n\t},\n\t{\n\t\t\"name\":\"&amp;ccedil;\",\n\t\t\"description\":\"latin capital letter c with cedilla\"\n\t},\n\t{\n\t\t\"name\":\"&amp;egrave;\",\n\t\t\"description\":\"latin capital letter e with grave\"\n\t},\n\t{\n\t\t\"name\":\"&amp;eacute;\",\n\t\t\"description\":\"latin capital letter e with acute\"\n\t},\n\t{\n\t\t\"name\":\"&amp;ecirc;\",\n\t\t\"description\":\"latin capital letter e with circumflex\"\n\t},\n\t{\n\t\t\"name\":\"&amp;euml;\",\n\t\t\"description\":\"latin capital letter e with diaeresis\"\n\t},\n\t{\n\t\t\"name\":\"&amp;igrave;\",\n\t\t\"description\":\"latin capital letter i with grave\"\n\t},\n\t{\n\t\t\"name\":\"&amp;Iacute;\",\n\t\t\"description\":\"latin capital letter i with acute\"\n\t},\n\t{\n\t\t\"name\":\"&amp;icirc;\",\n\t\t\"description\":\"latin capital letter i with circumflex\"\n\t},\n\t{\n\t\t\"name\":\"&amp;iuml;\",\n\t\t\"description\":\"latin capital letter i with diaeresis\"\n\t},\n\n\t{\n\t\t\"name\":\"&amp;#65;\",\n\t\t\"description\":\"A\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#66;\",\n\t\t\"description\":\"B\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#67;\",\n\t\t\"description\":\"C\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#68;\",\n\t\t\"description\":\"D\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#69;\",\n\t\t\"description\":\"E\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#70;\",\n\t\t\"description\":\"F\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#71;\",\n\t\t\"description\":\"G\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#72;\",\n\t\t\"description\":\"H\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#73;\",\n\t\t\"description\":\"I\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#74;\",\n\t\t\"description\":\"J\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#75;\",\n\t\t\"description\":\"K\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#76;\",\n\t\t\"description\":\"L\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#77;\",\n\t\t\"description\":\"M\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#78;\",\n\t\t\"description\":\"N\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#79;\",\n\t\t\"description\":\"O\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#80;\",\n\t\t\"description\":\"P\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#81;\",\n\t\t\"description\":\"Q\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#82;\",\n\t\t\"description\":\"R\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#83;\",\n\t\t\"description\":\"S\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#84;\",\n\t\t\"description\":\"T\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#85;\",\n\t\t\"description\":\"U\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#86;\",\n\t\t\"description\":\"V\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#87;\",\n\t\t\"description\":\"W\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#88;\",\n\t\t\"description\":\"X\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#89;\",\n\t\t\"description\":\"Y\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#90;\",\n\t\t\"description\":\"Z\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#91;\",\n\t\t\"description\":\"opening bracket\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#92;\",\n\t\t\"description\":\"backslash\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#93;\",\n\t\t\"description\":\"closing bracket\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#94;\",\n\t\t\"description\":\"caret - circumflex\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#95;\",\n\t\t\"description\":\"underscore\"\n\t},\n\n\t{\n\t\t\"name\":\"&amp;#96;\",\n\t\t\"description\":\"grave accent\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#97;\",\n\t\t\"description\":\"a\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#98;\",\n\t\t\"description\":\"b\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#99;\",\n\t\t\"description\":\"c\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#100;\",\n\t\t\"description\":\"d\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#101;\",\n\t\t\"description\":\"e\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#102;\",\n\t\t\"description\":\"f\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#103;\",\n\t\t\"description\":\"g\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#104;\",\n\t\t\"description\":\"h\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#105;\",\n\t\t\"description\":\"i\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#106;\",\n\t\t\"description\":\"j\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#107;\",\n\t\t\"description\":\"k\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#108;\",\n\t\t\"description\":\"l\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#109;\",\n\t\t\"description\":\"m\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#110;\",\n\t\t\"description\":\"n\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#111;\",\n\t\t\"description\":\"o\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#112;\",\n\t\t\"description\":\"p\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#113;\",\n\t\t\"description\":\"q\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#114;\",\n\t\t\"description\":\"r\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#115;\",\n\t\t\"description\":\"s\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#116;\",\n\t\t\"description\":\"t\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#117;\",\n\t\t\"description\":\"u\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#118;\",\n\t\t\"description\":\"v\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#119;\",\n\t\t\"description\":\"w\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#120;\",\n\t\t\"description\":\"x\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#121;\",\n\t\t\"description\":\"y\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#122;\",\n\t\t\"description\":\"z\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#123;\",\n\t\t\"description\":\"opening brace\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#124;\",\n\t\t\"description\":\"vertical bar\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#125;\",\n\t\t\"description\":\"closing brace\"\n\t},\n\t{\n\t\t\"name\":\"&amp;#126;\",\n\t\t\"description\":\"equivalency sign - tilde\"\n\t}\n]"
  },
  {
    "path": "Public/editor.md/plugins/image-dialog/image-dialog.js",
    "content": "/*!\n * Image (upload) dialog plugin for Editor.md\n *\n * @file        image-dialog.js\n * @author      pandao\n * @version     1.3.4\n * @updateTime  2015-06-09\n * {@link       https://github.com/pandao/editor.md}\n * @license     MIT\n */\n\n(function() {\n\n    var factory = function (exports) {\n\n\t\tvar pluginName   = \"image-dialog\";\n\n\t\texports.fn.imageDialog = function() {\n\n            var _this       = this;\n            var cm          = this.cm;\n            var lang        = this.lang;\n            var editor      = this.editor;\n            var settings    = this.settings;\n            var cursor      = cm.getCursor();\n            var selection   = cm.getSelection();\n            var imageLang   = lang.dialog.image;\n            var classPrefix = this.classPrefix;\n            var iframeName  = classPrefix + \"image-iframe\";\n\t\t\tvar dialogName  = classPrefix + pluginName, dialog;\n\n\t\t\tcm.focus();\n\n            var loading = function(show) {\n                var _loading = dialog.find(\".\" + classPrefix + \"dialog-mask\");\n                _loading[(show) ? \"show\" : \"hide\"]();\n            };\n\n            if (editor.find(\".\" + dialogName).length < 1)\n            {\n                var guid   = (new Date).getTime();\n                var action = settings.imageUploadURL + (settings.imageUploadURL.indexOf(\"?\") >= 0 ? \"&\" : \"?\") + \"guid=\" + guid;\n\n                if (settings.crossDomainUpload)\n                {\n                    action += \"&callback=\" + settings.uploadCallbackURL + \"&dialog_id=editormd-image-dialog-\" + guid;\n                }\n\n                var dialogContent = ( (settings.imageUpload) ? \"<form action=\\\"\" + action +\"\\\" target=\\\"\" + iframeName + \"\\\" method=\\\"post\\\" enctype=\\\"multipart/form-data\\\" class=\\\"\" + classPrefix + \"form\\\">\" : \"<div class=\\\"\" + classPrefix + \"form\\\">\" ) +\n                                        ( (settings.imageUpload) ? \"<iframe name=\\\"\" + iframeName + \"\\\" id=\\\"\" + iframeName + \"\\\" guid=\\\"\" + guid + \"\\\"></iframe>\" : \"\" ) +\n                                        \"<label>\" + imageLang.url + \"</label>\" +\n                                        \"<input type=\\\"text\\\" data-url />\" + (function(){\n                                            return (settings.imageUpload) ? \"<div class=\\\"\" + classPrefix + \"file-input\\\">\" +\n                                                                                \"<input type=\\\"file\\\" name=\\\"\" + classPrefix + \"image-file\\\" accept=\\\"image/*\\\" />\" +\n                                                                                \"<input type=\\\"submit\\\" value=\\\"\" + imageLang.uploadButton + \"\\\" />\" +\n                                                                            \"</div>\" : \"\";\n                                        })() +\n                                        \"<br/>\" +\n                                        \"<label>\" + imageLang.alt + \"</label>\" +\n                                        \"<input type=\\\"text\\\" value=\\\"\" + selection + \"\\\" data-alt />\" +\n                                        \"<br/>\" +\n                                        \"<label>\" + imageLang.link + \"</label>\" +\n                                        \"<input type=\\\"text\\\" value=\\\"http://\\\" data-link />\" +\n                                        \"<br/>\" +\n                                    ( (settings.imageUpload) ? \"</form>\" : \"</div>\");\n\n                //var imageFooterHTML = \"<button class=\\\"\" + classPrefix + \"btn \" + classPrefix + \"image-manager-btn\\\" style=\\\"float:left;\\\">\" + imageLang.managerButton + \"</button>\";\n\n                dialog = this.createDialog({\n                    title      : imageLang.title,\n                    width      : (settings.imageUpload) ? 465 : 380,\n                    height     : 254,\n                    name       : dialogName,\n                    content    : dialogContent,\n                    mask       : settings.dialogShowMask,\n                    drag       : settings.dialogDraggable,\n                    lockScreen : settings.dialogLockScreen,\n                    maskStyle  : {\n                        opacity         : settings.dialogMaskOpacity,\n                        backgroundColor : settings.dialogMaskBgColor\n                    },\n                    buttons : {\n                        enter : [lang.buttons.enter, function() {\n                            var url  = this.find(\"[data-url]\").val();\n                            var alt  = this.find(\"[data-alt]\").val();\n                            var link = this.find(\"[data-link]\").val();\n\n                            if (url === \"\")\n                            {\n                                alert(imageLang.imageURLEmpty);\n                                return false;\n                            }\n\n\t\t\t\t\t\t\tvar altAttr = (alt !== \"\") ? \" \\\"\" + alt + \"\\\"\" : \"\";\n\n                            if (link === \"\" || link === \"http://\")\n                            {\n                                cm.replaceSelection(\"![\" + alt + \"](\" + url + altAttr + \")\");\n                            }\n                            else\n                            {\n                                cm.replaceSelection(\"[![\" + alt + \"](\" + url + altAttr + \")](\" + link + altAttr + \")\");\n                            }\n\n                            if (alt === \"\") {\n                                cm.setCursor(cursor.line, cursor.ch + 2);\n                            }\n\n                            this.hide().lockScreen(false).hideMask();\n\n                            return false;\n                        }],\n\n                        cancel : [lang.buttons.cancel, function() {\n                            this.hide().lockScreen(false).hideMask();\n\n                            return false;\n                        }]\n                    }\n                });\n\n                dialog.attr(\"id\", classPrefix + \"image-dialog-\" + guid);\n\n\t\t\t\tif (!settings.imageUpload) {\n                    return ;\n                }\n\n\t\t\t\tvar fileInput  = dialog.find(\"[name=\\\"\" + classPrefix + \"image-file\\\"]\");\n\n\t\t\t\tfileInput.bind(\"change\", function() {\n\t\t\t\t\tvar fileName  = fileInput.val();\n\t\t\t\t\tvar isImage   = new RegExp(\"(\\\\.(\" + settings.imageFormats.join(\"|\") + \"))$\"); // /(\\.(webp|jpg|jpeg|gif|bmp|png))$/\n\n\t\t\t\t\tif (fileName === \"\")\n\t\t\t\t\t{\n\t\t\t\t\t\talert(imageLang.uploadFileEmpty);\n                        \n                        return false;\n\t\t\t\t\t}\n\t\t\t\t\t\n                    if (!isImage.test(fileName))\n\t\t\t\t\t{\n\t\t\t\t\t\talert(imageLang.formatNotAllowed + settings.imageFormats.join(\", \"));\n                        \n                        return false;\n\t\t\t\t\t}\n\n                    loading(true);\n\n                    var submitHandler = function() {\n\n                        var uploadIframe = document.getElementById(iframeName);\n\n                        uploadIframe.onload = function() {\n                            \n                            loading(false);\n\n                            var body = (uploadIframe.contentWindow ? uploadIframe.contentWindow : uploadIframe.contentDocument).document.body;\n                            var json = (body.innerText) ? body.innerText : ( (body.textContent) ? body.textContent : null);\n\n                            json = (typeof JSON.parse !== \"undefined\") ? JSON.parse(json) : eval(\"(\" + json + \")\");\n\n                            if (json.success === 1)\n                            {\n                                dialog.find(\"[data-url]\").val(json.url);\n                            }\n                            else\n                            {\n                                alert(json.message);\n                            }\n\n                            return false;\n                        };\n                    };\n\n                    dialog.find(\"[type=\\\"submit\\\"]\").bind(\"click\", submitHandler).trigger(\"click\");\n\t\t\t\t});\n            }\n\n\t\t\tdialog = editor.find(\".\" + dialogName);\n\t\t\tdialog.find(\"[type=\\\"text\\\"]\").val(\"\");\n\t\t\tdialog.find(\"[type=\\\"file\\\"]\").val(\"\");\n\t\t\tdialog.find(\"[data-link]\").val(\"http://\");\n\n\t\t\tthis.dialogShowMask(dialog);\n\t\t\tthis.dialogLockScreen();\n\t\t\tdialog.show();\n\n\t\t};\n\n\t};\n\n\t// CommonJS/Node.js\n\tif (typeof require === \"function\" && typeof exports === \"object\" && typeof module === \"object\")\n    {\n        module.exports = factory;\n    }\n\telse if (typeof define === \"function\")  // AMD/CMD/Sea.js\n    {\n\t\tif (define.amd) { // for Require.js\n\n\t\t\tdefine([\"editormd\"], function(editormd) {\n                factory(editormd);\n            });\n\n\t\t} else { // for Sea.js\n\t\t\tdefine(function(require) {\n                var editormd = require(\"./../../editormd\");\n                factory(editormd);\n            });\n\t\t}\n\t}\n\telse\n\t{\n        factory(window.editormd);\n\t}\n\n})();\n"
  },
  {
    "path": "Public/editor.md/plugins/link-dialog/link-dialog.js",
    "content": "/*!\n * Link dialog plugin for Editor.md\n *\n * @file        link-dialog.js\n * @author      pandao\n * @version     1.2.1\n * @updateTime  2015-06-09\n * {@link       https://github.com/pandao/editor.md}\n * @license     MIT\n */\n\n(function() {\n\n    var factory = function (exports) {\n\n\t\tvar pluginName   = \"link-dialog\";\n\n\t\texports.fn.linkDialog = function() {\n\n\t\t\tvar _this       = this;\n\t\t\tvar cm          = this.cm;\n            var editor      = this.editor;\n            var settings    = this.settings;\n            var selection   = cm.getSelection();\n            var lang        = this.lang;\n            var linkLang    = lang.dialog.link;\n            var classPrefix = this.classPrefix;\n\t\t\tvar dialogName  = classPrefix + pluginName, dialog;\n\n\t\t\tcm.focus();\n\n            if (editor.find(\".\" + dialogName).length > 0)\n            {\n                dialog = editor.find(\".\" + dialogName);\n                dialog.find(\"[data-url]\").val(\"http://\");\n                dialog.find(\"[data-title]\").val(selection);\n\n                this.dialogShowMask(dialog);\n                this.dialogLockScreen();\n                dialog.show();\n            }\n            else\n            {\n                var dialogHTML = \"<div class=\\\"\" + classPrefix + \"form\\\">\" + \n                                        \"<label>\" + linkLang.url + \"</label>\" + \n                                        \"<input type=\\\"text\\\" value=\\\"http://\\\" data-url />\" +\n                                        \"<br/>\" + \n                                        \"<label>\" + linkLang.urlTitle + \"</label>\" + \n                                        \"<input type=\\\"text\\\" value=\\\"\" + selection + \"\\\" data-title />\" + \n                                        \"<br/>\" +\n                                    \"</div>\";\n\n                dialog = this.createDialog({\n                    title      : linkLang.title,\n                    width      : 380,\n                    height     : 211,\n                    content    : dialogHTML,\n                    mask       : settings.dialogShowMask,\n                    drag       : settings.dialogDraggable,\n                    lockScreen : settings.dialogLockScreen,\n                    maskStyle  : {\n                        opacity         : settings.dialogMaskOpacity,\n                        backgroundColor : settings.dialogMaskBgColor\n                    },\n                    buttons    : {\n                        enter  : [lang.buttons.enter, function() {\n                            var url   = this.find(\"[data-url]\").val();\n                            var title = this.find(\"[data-title]\").val();\n\n                            if (url === \"http://\" || url === \"\")\n                            {\n                                alert(linkLang.urlEmpty);\n                                return false;\n                            }\n\n                            /*if (title === \"\")\n                            {\n                                alert(linkLang.titleEmpty);\n                                return false;\n                            }*/\n                            \n                            var str = \"[\" + title + \"](\" + url + \" \\\"\" + title + \"\\\")\";\n                            \n                            if (title == \"\")\n                            {\n                                str = \"[\" + url + \"](\" + url + \")\";\n                            }                                \n\n                            cm.replaceSelection(str);\n\n                            this.hide().lockScreen(false).hideMask();\n\n                            return false;\n                        }],\n\n                        cancel : [lang.buttons.cancel, function() {                                   \n                            this.hide().lockScreen(false).hideMask();\n\n                            return false;\n                        }]\n                    }\n                });\n\t\t\t}\n\t\t};\n\n\t};\n    \n\t// CommonJS/Node.js\n\tif (typeof require === \"function\" && typeof exports === \"object\" && typeof module === \"object\")\n    { \n        module.exports = factory;\n    }\n\telse if (typeof define === \"function\")  // AMD/CMD/Sea.js\n    {\n\t\tif (define.amd) { // for Require.js\n\n\t\t\tdefine([\"editormd\"], function(editormd) {\n                factory(editormd);\n            });\n\n\t\t} else { // for Sea.js\n\t\t\tdefine(function(require) {\n                var editormd = require(\"./../../editormd\");\n                factory(editormd);\n            });\n\t\t}\n\t} \n\telse\n\t{\n        factory(window.editormd);\n\t}\n\n})();\n"
  },
  {
    "path": "Public/editor.md/plugins/plugin-template.js",
    "content": "/*!\n * Link dialog plugin for Editor.md\n *\n * @file        link-dialog.js\n * @author      pandao\n * @version     1.2.0\n * @updateTime  2015-03-07\n * {@link       https://github.com/pandao/editor.md}\n * @license     MIT\n */\n\n(function() {\n\n    var factory = function (exports) {\n\n\t\tvar $            = jQuery;           // if using module loader(Require.js/Sea.js).\n\n\t\tvar langs = {\n\t\t\t\"zh-cn\" : {\n\t\t\t\ttoolbar : {\n\t\t\t\t\ttable : \"表格\"\n\t\t\t\t},\n\t\t\t\tdialog : {\n\t\t\t\t\ttable : {\n\t\t\t\t\t\ttitle      : \"添加表格\",\n\t\t\t\t\t\tcellsLabel : \"单元格数\",\n\t\t\t\t\t\talignLabel : \"对齐方式\",\n\t\t\t\t\t\trows       : \"行数\",\n\t\t\t\t\t\tcols       : \"列数\",\n\t\t\t\t\t\taligns     : [\"默认\", \"左对齐\", \"居中对齐\", \"右对齐\"]\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"zh-tw\" : {\n\t\t\t\ttoolbar : {\n\t\t\t\t\ttable : \"添加表格\"\n\t\t\t\t},\n\t\t\t\tdialog : {\n\t\t\t\t\ttable : {\n\t\t\t\t\t\ttitle      : \"添加表格\",\n\t\t\t\t\t\tcellsLabel : \"單元格數\",\n\t\t\t\t\t\talignLabel : \"對齊方式\",\n\t\t\t\t\t\trows       : \"行數\",\n\t\t\t\t\t\tcols       : \"列數\",\n\t\t\t\t\t\taligns     : [\"默認\", \"左對齊\", \"居中對齊\", \"右對齊\"]\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"en\" : {\n\t\t\t\ttoolbar : {\n\t\t\t\t\ttable : \"Tables\"\n\t\t\t\t},\n\t\t\t\tdialog : {\n\t\t\t\t\ttable : {\n\t\t\t\t\t\ttitle      : \"Tables\",\n\t\t\t\t\t\tcellsLabel : \"Cells\",\n\t\t\t\t\t\talignLabel : \"Align\",\n\t\t\t\t\t\trows       : \"Rows\",\n\t\t\t\t\t\tcols       : \"Cols\",\n\t\t\t\t\t\taligns     : [\"Default\", \"Left align\", \"Center align\", \"Right align\"]\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\texports.fn.htmlEntities = function() {\n\t\t\t/*\n\t\t\tvar _this       = this; // this == the current instance object of Editor.md\n\t\t\tvar lang        = _this.lang;\n\t\t\tvar settings    = _this.settings;\n\t\t\tvar editor      = this.editor;\n\t\t\tvar cursor      = cm.getCursor();\n\t\t\tvar selection   = cm.getSelection();\n\t\t\tvar classPrefix = this.classPrefix;\n\n\t\t\t$.extend(true, this.lang, langs[this.lang.name]); // l18n\n\t\t\tthis.setToolbar();\n\n\t\t\tcm.focus();\n\t\t\t*/\n\t\t\t//....\n\t\t};\n\n\t};\n    \n\t// CommonJS/Node.js\n\tif (typeof require === \"function\" && typeof exports === \"object\" && typeof module === \"object\")\n    { \n        module.exports = factory;\n    }\n\telse if (typeof define === \"function\")  // AMD/CMD/Sea.js\n    {\n\t\tif (define.amd) { // for Require.js\n\n\t\t\tdefine([\"editormd\"], function(editormd) {\n                factory(editormd);\n            });\n\n\t\t} else { // for Sea.js\n\t\t\tdefine(function(require) {\n                var editormd = require(\"./../../editormd\");\n                factory(editormd);\n            });\n\t\t}\n\t} \n\telse\n\t{\n        factory(window.editormd);\n\t}\n\n})();\n"
  },
  {
    "path": "Public/editor.md/plugins/preformatted-text-dialog/preformatted-text-dialog.js",
    "content": "/*!\n * Preformatted text dialog plugin for Editor.md\n *\n * @file        preformatted-text-dialog.js\n * @author      pandao\n * @version     1.2.0\n * @updateTime  2015-03-07\n * {@link       https://github.com/pandao/editor.md}\n * @license     MIT\n */\n\n(function() {\n\n    var factory = function (exports) {\n\t\tvar cmEditor;\n\t\tvar pluginName   = \"preformatted-text-dialog\";\n\n\t\texports.fn.preformattedTextDialog = function() {\n\n            var _this       = this;\n            var cm          = this.cm;\n            var lang        = this.lang;\n\t\t\tvar editor      = this.editor;\n            var settings    = this.settings;\n            var cursor      = cm.getCursor();\n            var selection   = cm.getSelection();\n            var classPrefix = this.classPrefix;\n\t\t\tvar dialogLang  = lang.dialog.preformattedText;\n\t\t\tvar dialogName  = classPrefix + pluginName, dialog;\n\n\t\t\tcm.focus();\n\n            if (editor.find(\".\" + dialogName).length > 0)\n            {\n                dialog = editor.find(\".\" + dialogName);\n                dialog.find(\"textarea\").val(selection);\n\n                this.dialogShowMask(dialog);\n                this.dialogLockScreen();\n                dialog.show();\n            }\n            else \n            {      \n                var dialogContent = \"<textarea placeholder=\\\"coding now....\\\" style=\\\"display:none;\\\">\" + selection + \"</textarea>\";\n\n                dialog = this.createDialog({\n                    name   : dialogName,\n                    title  : dialogLang.title,\n                    width  : 780,\n                    height : 540,\n                    mask   : settings.dialogShowMask,\n                    drag   : settings.dialogDraggable,\n                    content : dialogContent,\n                    lockScreen : settings.dialogLockScreen,\n                    maskStyle  : {\n                        opacity         : settings.dialogMaskOpacity,\n                        backgroundColor : settings.dialogMaskBgColor\n                    },\n                    buttons : {\n                        enter  : [lang.buttons.enter, function() {\n                            var codeTexts  = this.find(\"textarea\").val();\n\n                            if (codeTexts === \"\")\n                            {\n                                alert(dialogLang.emptyAlert);\n                                return false;\n                            }\n\n                            codeTexts = codeTexts.split(\"\\n\");\n\n                            for (var i in codeTexts)\n                            {\n                                codeTexts[i] = \"    \" + codeTexts[i];\n                            }\n                            \n                            codeTexts = codeTexts.join(\"\\n\");\n                            \n                            if (cursor.ch !== 0) {\n                                codeTexts = \"\\r\\n\\r\\n\" + codeTexts;\n                            }\n\n                            cm.replaceSelection(codeTexts);\n\n                            this.hide().lockScreen(false).hideMask();\n\n                            return false;\n                        }],\n                        cancel : [lang.buttons.cancel, function() {                                  \n                            this.hide().lockScreen(false).hideMask();\n\n                            return false;\n                        }]\n                    }\n                });\n            }\n\t\t\n\t\t\tvar cmConfig = {\n\t\t\t\tmode                      : \"text/html\",\n\t\t\t\ttheme                     : settings.theme,\n\t\t\t\ttabSize                   : 4,\n\t\t\t\tautofocus                 : true,\n\t\t\t\tautoCloseTags             : true,\n\t\t\t\tindentUnit                : 4,\n\t\t\t\tlineNumbers               : true,\n\t\t\t\tlineWrapping              : true,\n\t\t\t\textraKeys                 : {\"Ctrl-Q\": function(cm){ cm.foldCode(cm.getCursor()); }},\n\t\t\t\tfoldGutter                : true,\n\t\t\t\tgutters                   : [\"CodeMirror-linenumbers\", \"CodeMirror-foldgutter\"],\n\t\t\t\tmatchBrackets             : true,\n\t\t\t\tindentWithTabs            : true,\n\t\t\t\tstyleActiveLine           : true,\n\t\t\t\tstyleSelectedText         : true,\n\t\t\t\tautoCloseBrackets         : true,\n\t\t\t\tshowTrailingSpace         : true,\n\t\t\t\thighlightSelectionMatches : true\n\t\t\t};\n\t\t\t\n\t\t\tvar textarea = dialog.find(\"textarea\");\n\t\t\tvar cmObj    = dialog.find(\".CodeMirror\");\n\n\t\t\tif (dialog.find(\".CodeMirror\").length < 1) \n\t\t\t{\n\t\t\t\tcmEditor = exports.$CodeMirror.fromTextArea(textarea[0], cmConfig);\n\t\t\t\tcmObj    = dialog.find(\".CodeMirror\");\n\n\t\t\t\tcmObj.css({\n\t\t\t\t\t\"float\"   : \"none\", \n\t\t\t\t\tmargin    : \"0 0 5px\",\n\t\t\t\t\tborder    : \"1px solid #ddd\",\n\t\t\t\t\tfontSize  : settings.fontSize,\n\t\t\t\t\twidth     : \"100%\",\n\t\t\t\t\theight    : \"410px\"\n\t\t\t\t});\n\n\t\t\t\tcmEditor.on(\"change\", function(cm) {\n\t\t\t\t\ttextarea.val(cm.getValue());\n\t\t\t\t});\n\t\t\t} \n\t\t\telse \n\t\t\t{\n\t\t\t\tcmEditor.setValue(cm.getSelection());\n\t\t\t}\n\t\t};\n\n\t};\n\n\t// CommonJS/Node.js\n\tif (typeof require === \"function\" && typeof exports === \"object\" && typeof module === \"object\")\n    { \n        module.exports = factory;\n    }\n\telse if (typeof define === \"function\")  // AMD/CMD/Sea.js\n    {\n\t\tif (define.amd) { // for Require.js\n\n\t\t\tdefine([\"editormd\"], function(editormd) {\n                factory(editormd);\n            });\n\n\t\t} else { // for Sea.js\n\t\t\tdefine(function(require) {\n                var editormd = require(\"./../../editormd\");\n                factory(editormd);\n            });\n\t\t}\n\t} \n\telse\n\t{\n        factory(window.editormd);\n\t}\n\n})();\n"
  },
  {
    "path": "Public/editor.md/plugins/reference-link-dialog/reference-link-dialog.js",
    "content": "/*!\n * Reference link dialog plugin for Editor.md\n *\n * @file        reference-link-dialog.js\n * @author      pandao\n * @version     1.2.1\n * @updateTime  2015-06-09\n * {@link       https://github.com/pandao/editor.md}\n * @license     MIT\n */\n\n(function() {\n\n    var factory = function (exports) {\n\n\t\tvar pluginName   = \"reference-link-dialog\";\n\t\tvar ReLinkId     = 1;\n\n\t\texports.fn.referenceLinkDialog = function() {\n\n            var _this       = this;\n            var cm          = this.cm;\n            var lang        = this.lang;\n\t\t\tvar editor      = this.editor;\n            var settings    = this.settings;\n            var cursor      = cm.getCursor();\n            var selection   = cm.getSelection();\n            var dialogLang  = lang.dialog.referenceLink;\n            var classPrefix = this.classPrefix;\n\t\t\tvar dialogName  = classPrefix + pluginName, dialog;\n\n\t\t\tcm.focus();\n\n            if (editor.find(\".\" + dialogName).length < 1)\n            {      \n                var dialogHTML = \"<div class=\\\"\" + classPrefix + \"form\\\">\" +\n                                        \"<label>\" + dialogLang.name + \"</label>\" +\n                                        \"<input type=\\\"text\\\" value=\\\"[\" + ReLinkId + \"]\\\" data-name />\" +  \n                                        \"<br/>\" +\n                                        \"<label>\" + dialogLang.urlId + \"</label>\" +\n                                        \"<input type=\\\"text\\\" data-url-id />\" +\n                                        \"<br/>\" +\n                                        \"<label>\" + dialogLang.url + \"</label>\" +\n                                        \"<input type=\\\"text\\\" value=\\\"http://\\\" data-url />\" + \n                                        \"<br/>\" +\n                                        \"<label>\" + dialogLang.urlTitle + \"</label>\" +\n                                        \"<input type=\\\"text\\\" value=\\\"\" + selection + \"\\\" data-title />\" +\n                                        \"<br/>\" +\n                                    \"</div>\";\n\n                dialog = this.createDialog({   \n                    name       : dialogName,\n                    title      : dialogLang.title,\n                    width      : 380,\n                    height     : 296,\n                    content    : dialogHTML,\n                    mask       : settings.dialogShowMask,\n                    drag       : settings.dialogDraggable,\n                    lockScreen : settings.dialogLockScreen,\n                    maskStyle  : {\n                        opacity         : settings.dialogMaskOpacity,\n                        backgroundColor : settings.dialogMaskBgColor\n                    },\n                    buttons : {\n                        enter  : [lang.buttons.enter, function() {\n                            var name  = this.find(\"[data-name]\").val();\n                            var url   = this.find(\"[data-url]\").val();\n                            var rid   = this.find(\"[data-url-id]\").val();\n                            var title = this.find(\"[data-title]\").val();\n\n                            if (name === \"\")\n                            {\n                                alert(dialogLang.nameEmpty);\n                                return false;\n                            }\n\n                            if (rid === \"\")\n                            {\n                                alert(dialogLang.idEmpty);\n                                return false;\n                            }\n\n                            if (url === \"http://\" || url === \"\")\n                            {\n                                alert(dialogLang.urlEmpty);\n                                return false;\n                            }\n\n                            //cm.replaceSelection(\"[\" + title + \"][\" + name + \"]\\n[\" + name + \"]: \" + url + \"\");\n                            cm.replaceSelection(\"[\" + name + \"][\" + rid + \"]\");\n\n                            if (selection === \"\") {\n                                cm.setCursor(cursor.line, cursor.ch + 1);\n                            }\n\n\t\t\t\t\t\t\ttitle = (title === \"\") ? \"\" : \" \\\"\" + title + \"\\\"\";\n\n\t\t\t\t\t\t\tcm.setValue(cm.getValue() + \"\\n[\" + rid + \"]: \" + url + title + \"\");\n\n                            this.hide().lockScreen(false).hideMask();\n\n                            return false;\n                        }],\n                        cancel : [lang.buttons.cancel, function() {                                   \n                            this.hide().lockScreen(false).hideMask();\n\n                            return false;\n                        }]\n                    }\n                });\n            }\n\n\t\t\tdialog = editor.find(\".\" + dialogName);\n\t\t\tdialog.find(\"[data-name]\").val(\"[\" + ReLinkId + \"]\");\n\t\t\tdialog.find(\"[data-url-id]\").val(\"\");\n\t\t\tdialog.find(\"[data-url]\").val(\"http://\");\n\t\t\tdialog.find(\"[data-title]\").val(selection);\n\n\t\t\tthis.dialogShowMask(dialog);\n\t\t\tthis.dialogLockScreen();\n\t\t\tdialog.show();\n\n\t\t\tReLinkId++;\n\t\t};\n\n\t};\n    \n\t// CommonJS/Node.js\n\tif (typeof require === \"function\" && typeof exports === \"object\" && typeof module === \"object\")\n    { \n        module.exports = factory;\n    }\n\telse if (typeof define === \"function\")  // AMD/CMD/Sea.js\n    {\n\t\tif (define.amd) { // for Require.js\n\n\t\t\tdefine([\"editormd\"], function(editormd) {\n                factory(editormd);\n            });\n\n\t\t} else { // for Sea.js\n\t\t\tdefine(function(require) {\n                var editormd = require(\"./../../editormd\");\n                factory(editormd);\n            });\n\t\t}\n\t} \n\telse\n\t{\n        factory(window.editormd);\n\t}\n\n})();\n"
  },
  {
    "path": "Public/editor.md/plugins/table-dialog/table-dialog.js",
    "content": "/*!\n * Table dialog plugin for Editor.md\n *\n * @file        table-dialog.js\n * @author      pandao\n * @version     1.2.1\n * @updateTime  2015-06-09\n * {@link       https://github.com/pandao/editor.md}\n * @license     MIT\n */\n\n(function() {\n\n\tvar factory = function (exports) {\n\n\t\tvar $            = jQuery;\n\t\tvar pluginName   = \"table-dialog\";\n\n\t\tvar langs = {\n\t\t\t\"zh-cn\" : {\n\t\t\t\ttoolbar : {\n\t\t\t\t\ttable : \"表格\"\n\t\t\t\t},\n\t\t\t\tdialog : {\n\t\t\t\t\ttable : {\n\t\t\t\t\t\ttitle      : \"添加表格\",\n\t\t\t\t\t\tcellsLabel : \"单元格数\",\n\t\t\t\t\t\talignLabel : \"对齐方式\",\n\t\t\t\t\t\trows       : \"行数\",\n\t\t\t\t\t\tcols       : \"列数\",\n\t\t\t\t\t\taligns     : [\"默认\", \"左对齐\", \"居中对齐\", \"右对齐\"]\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"zh-tw\" : {\n\t\t\t\ttoolbar : {\n\t\t\t\t\ttable : \"添加表格\"\n\t\t\t\t},\n\t\t\t\tdialog : {\n\t\t\t\t\ttable : {\n\t\t\t\t\t\ttitle      : \"添加表格\",\n\t\t\t\t\t\tcellsLabel : \"單元格數\",\n\t\t\t\t\t\talignLabel : \"對齊方式\",\n\t\t\t\t\t\trows       : \"行數\",\n\t\t\t\t\t\tcols       : \"列數\",\n\t\t\t\t\t\taligns     : [\"默認\", \"左對齊\", \"居中對齊\", \"右對齊\"]\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"en\" : {\n\t\t\t\ttoolbar : {\n\t\t\t\t\ttable : \"Tables\"\n\t\t\t\t},\n\t\t\t\tdialog : {\n\t\t\t\t\ttable : {\n\t\t\t\t\t\ttitle      : \"Tables\",\n\t\t\t\t\t\tcellsLabel : \"Cells\",\n\t\t\t\t\t\talignLabel : \"Align\",\n\t\t\t\t\t\trows       : \"Rows\",\n\t\t\t\t\t\tcols       : \"Cols\",\n\t\t\t\t\t\taligns     : [\"Default\", \"Left align\", \"Center align\", \"Right align\"]\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\texports.fn.tableDialog = function() {\n\t\t\tvar _this       = this;\n\t\t\tvar cm          = this.cm;\n\t\t\tvar editor      = this.editor;\n\t\t\tvar settings    = this.settings;\n\t\t\tvar path        = settings.path + \"../plugins/\" + pluginName +\"/\";\n\t\t\tvar classPrefix = this.classPrefix;\n\t\t\tvar dialogName  = classPrefix + pluginName, dialog;\n\n\t\t\t$.extend(true, this.lang, langs[this.lang.name]);\n\t\t\tthis.setToolbar();\n\n\t\t\tvar lang        = this.lang;\n\t\t\tvar dialogLang  = lang.dialog.table;\n\t\t\t\n\t\t\tvar dialogContent = [\n\t\t\t\t\"<div class=\\\"editormd-form\\\" style=\\\"padding: 13px 0;\\\">\",\n\t\t\t\t\"<label>\" + dialogLang.cellsLabel + \"</label>\",\n\t\t\t\tdialogLang.rows + \" <input type=\\\"number\\\" value=\\\"3\\\" class=\\\"number-input\\\" style=\\\"width:40px;height: 30px;\\\" max=\\\"100\\\" min=\\\"2\\\" data-rows />&nbsp;&nbsp;\",\n\t\t\t\tdialogLang.cols + \" <input type=\\\"number\\\" value=\\\"2\\\" class=\\\"number-input\\\" style=\\\"width:40px;height: 30px;\\\" max=\\\"100\\\" min=\\\"1\\\" data-cols /><br/>\",\n\t\t\t\t\"<label>\" + dialogLang.alignLabel + \"</label>\",\n\t\t\t\t\"<div class=\\\"fa-btns\\\"></div>\",\n\t\t\t\t\"</div>\"\n\t\t\t].join(\"\\n\");\n\n\t\t\tif (editor.find(\".\" + dialogName).length > 0) \n\t\t\t{\n                dialog = editor.find(\".\" + dialogName);\n\n\t\t\t\tthis.dialogShowMask(dialog);\n\t\t\t\tthis.dialogLockScreen();\n\t\t\t\tdialog.show();\n\t\t\t} \n\t\t\telse\n\t\t\t{\n\t\t\t\tdialog = this.createDialog({\n\t\t\t\t\tname       : dialogName,\n\t\t\t\t\ttitle      : dialogLang.title,\n\t\t\t\t\twidth      : 360,\n\t\t\t\t\theight     : 226,\n\t\t\t\t\tmask       : settings.dialogShowMask,\n\t\t\t\t\tdrag       : settings.dialogDraggable,\n\t\t\t\t\tcontent    : dialogContent,\n\t\t\t\t\tlockScreen : settings.dialogLockScreen,\n\t\t\t\t\tmaskStyle  : {\n\t\t\t\t\t\topacity         : settings.dialogMaskOpacity,\n\t\t\t\t\t\tbackgroundColor : settings.dialogMaskBgColor\n\t\t\t\t\t},\n\t\t\t\t\tbuttons    : {\n                        enter : [lang.buttons.enter, function() {\n\t\t\t\t\t\t\tvar rows   = parseInt(this.find(\"[data-rows]\").val());\n\t\t\t\t\t\t\tvar cols   = parseInt(this.find(\"[data-cols]\").val());\n\t\t\t\t\t\t\tvar align  = this.find(\"[name=\\\"table-align\\\"]:checked\").val();\n\t\t\t\t\t\t\tvar table  = \"\";\n\t\t\t\t\t\t\tvar hrLine = \"------------\";\n\n\t\t\t\t\t\t\tvar alignSign = {\n\t\t\t\t\t\t\t\t_default : hrLine,\n\t\t\t\t\t\t\t\tleft     : \":\" + hrLine,\n\t\t\t\t\t\t\t\tcenter   : \":\" + hrLine + \":\",\n\t\t\t\t\t\t\t\tright    : hrLine + \":\"\n\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\tif ( rows > 1 && cols > 0) \n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfor (var r = 0, len = rows; r < len; r++) \n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tvar row = [];\n\t\t\t\t\t\t\t\t\tvar head = [];\n\n\t\t\t\t\t\t\t\t\tfor (var c = 0, len2 = cols; c < len2; c++) \n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tif (r === 1) {\n\t\t\t\t\t\t\t\t\t\t\thead.push(alignSign[align]);\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\trow.push(\" \");\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tif (r === 1) {\n\t\t\t\t\t\t\t\t\t\ttable += \"| \" + head.join(\" | \") + \" |\" + \"\\n\";\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\ttable += \"| \" + row.join( (cols === 1) ? \"\" : \" | \" ) + \" |\" + \"\\n\";\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tcm.replaceSelection(table);\n\n                            this.hide().lockScreen(false).hideMask();\n\n                            return false;\n                        }],\n\n                        cancel : [lang.buttons.cancel, function() {                                   \n                            this.hide().lockScreen(false).hideMask();\n\n                            return false;\n                        }]\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tvar faBtns = dialog.find(\".fa-btns\");\n\n\t\t\tif (faBtns.html() === \"\")\n\t\t\t{\n\t\t\t\tvar icons  = [\"align-justify\", \"align-left\", \"align-center\", \"align-right\"];\n\t\t\t\tvar _lang  = dialogLang.aligns;\n\t\t\t\tvar values = [\"_default\", \"left\", \"center\", \"right\"];\n\n\t\t\t\tfor (var i = 0, len = icons.length; i < len; i++) \n\t\t\t\t{\n\t\t\t\t\tvar checked = (i === 0) ? \" checked=\\\"checked\\\"\" : \"\";\n\t\t\t\t\tvar btn = \"<a href=\\\"javascript:;\\\"><label for=\\\"editormd-table-dialog-radio\"+i+\"\\\" title=\\\"\" + _lang[i] + \"\\\">\";\n\t\t\t\t\tbtn += \"<input type=\\\"radio\\\" name=\\\"table-align\\\" id=\\\"editormd-table-dialog-radio\"+i+\"\\\" value=\\\"\" + values[i] + \"\\\"\" +checked + \" />&nbsp;\";\n\t\t\t\t\tbtn += \"<i class=\\\"fa fa-\" + icons[i] + \"\\\"></i>\";\n\t\t\t\t\tbtn += \"</label></a>\";\n\n\t\t\t\t\tfaBtns.append(btn);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t};\n    \n\t// CommonJS/Node.js\n\tif (typeof require === \"function\" && typeof exports === \"object\" && typeof module === \"object\")\n    { \n        module.exports = factory;\n    }\n\telse if (typeof define === \"function\")  // AMD/CMD/Sea.js\n    {\n\t\tif (define.amd) { // for Require.js\n\n\t\t\tdefine([\"editormd\"], function(editormd) {\n                factory(editormd);\n            });\n\n\t\t} else { // for Sea.js\n\t\t\tdefine(function(require) {\n                var editormd = require(\"./../../editormd\");\n                factory(editormd);\n            });\n\t\t}\n\t} \n\telse\n\t{\n        factory(window.editormd);\n\t}\n\n})();\n"
  },
  {
    "path": "Public/editor.md/plugins/test-plugin/test-plugin.js",
    "content": "/*!\n * Test plugin for Editor.md\n *\n * @file        test-plugin.js\n * @author      pandao\n * @version     1.2.0\n * @updateTime  2015-03-07\n * {@link       https://github.com/pandao/editor.md}\n * @license     MIT\n */\n\n(function() {\n\n    var factory = function (exports) {\n\n\t\tvar $            = jQuery;           // if using module loader(Require.js/Sea.js).\n\n\t\texports.testPlugin = function(){\n\t\t\talert(\"testPlugin\");\n\t\t};\n\n\t\texports.fn.testPluginMethodA = function() {\n\t\t\t/*\n\t\t\tvar _this       = this; // this == the current instance object of Editor.md\n\t\t\tvar lang        = _this.lang;\n\t\t\tvar settings    = _this.settings;\n\t\t\tvar editor      = this.editor;\n\t\t\tvar cursor      = cm.getCursor();\n\t\t\tvar selection   = cm.getSelection();\n\t\t\tvar classPrefix = this.classPrefix;\n\n\t\t\tcm.focus();\n\t\t\t*/\n\t\t\t//....\n\n\t\t\talert(\"testPluginMethodA\");\n\t\t};\n\n\t};\n    \n\t// CommonJS/Node.js\n\tif (typeof require === \"function\" && typeof exports === \"object\" && typeof module === \"object\")\n    { \n        module.exports = factory;\n    }\n\telse if (typeof define === \"function\")  // AMD/CMD/Sea.js\n    {\n\t\tif (define.amd) { // for Require.js\n\n\t\t\tdefine([\"editormd\"], function(editormd) {\n                factory(editormd);\n            });\n\n\t\t} else { // for Sea.js\n\t\t\tdefine(function(require) {\n                var editormd = require(\"./../../editormd\");\n                factory(editormd);\n            });\n\t\t}\n\t} \n\telse\n\t{\n        factory(window.editormd);\n\t}\n\n})();\n"
  },
  {
    "path": "Public/exception.tpl",
    "content": "<?php\n    echo json_encode(\n    \tarray(\n    \t\t\"error_code\"=>999,\n    \t\t\"error_message\" =>strip_tags($e['message']).\" 。错误位置：\".$e['file'].\"  \".$e['line'] \n    \t\t)\n    )\n?>"
  },
  {
    "path": "Public/js/attorn/index.js",
    "content": "$(function(){\n  var item_id = $(\"#item_id\").val();\n\n  $('#edit-cat').modal({\n    \"backdrop\":'static'\n  });\n\n  //保存\n  $(\"#save-cat\").click(function(){\n      var username = $(\"#username\").val();\n      var password = $(\"#password\").val();\n      $.post(\n        \"?s=/home/attorn/save\",\n        {\"username\": username ,\"item_id\": item_id , \"password\": password  },\n        function(data){\n          if (data.error_code == 0) {\n            alert(lang['attorn_success']);\n            window.location.href=\"?s=/home/item/index\";\n          }else{\n            alert(data.error_message);\n\n          }\n        },\n        \"json\"\n\n        );\n      return false;\n  }); \n  \n  $(\".exist-cat\").click(function(){\n    window.location.href=\"?s=/home/item/show&item_id=\"+item_id;\n  });\n\n});\n\n\n\n\n\n"
  },
  {
    "path": "Public/js/catalog/edit.js",
    "content": "$(function(){\n\n  var item_id = $(\"#item_id\").val();\n\n  $('#edit-cat').modal({\n    \"backdrop\":'static'\n  });\n\n  getCatList();\n\n  function getCatList(){\n      $.get(\n        DocConfig.server+\"/api/catalog/catList\",\n        { \"item_id\": item_id },\n        function(data){\n          $(\"#show-second-cat\").html('');\n          $(\"#show-third-cat\").html('');\n          if (data.error_code == 0) {\n            json = data.data;\n            console.log(json);\n            for (var i = 0; i < json.length; i++) {\n                if (json[i].level == 2  ) {\n                  cat_html ='<a class=\"badge badge-info single-cat \" href=\"?s=home/catalog/edit&cat_id='+json[i].cat_id+'&item_id='+json[i].item_id+'\">'+json[i].cat_name+'&nbsp;<i class=\"icon-edit\"></i></a>';\n                  $(\"#show-second-cat\").append(cat_html);\n                };\n\n                if (json[i].level == 3  ) {\n                  cat_html ='<a class=\"badge badge-info single-cat \" href=\"?s=home/catalog/edit&cat_id='+json[i].cat_id+'&item_id='+json[i].item_id+'\">'+json[i].cat_name+'&nbsp;<i class=\"icon-edit\"></i></a>';\n                  $(\"#show-third-cat\").append(cat_html);\n                };\n\n            };\n\n\n          };\n          \n        },\n        \"json\"\n\n        );\n  }\n\n  /*加载二级目录，让用户选择上级目录*/\n  secondCatList();\n\n  function secondCatList() {\n    var default_parent_cat_id = $(\"#default_parent_cat_id\").val();\n    var item_id = $(\"#item_id\").val();\n    $.get(\n      DocConfig.server+\"/api/catalog/secondCatList\", \n      {\"item_id\": item_id},\n      function(data) {\n        $(\"#parent_cat_id\").html('<OPTION value=\"0\">'+lang[\"none\"]+'</OPTION>');\n        if (data.error_code == 0) {\n          json = data.data;\n          console.log(json);\n          for (var i = 0; i < json.length; i++) {\n            cat_html = '<OPTION value=\"' + json[i].cat_id + '\" ';\n            if (default_parent_cat_id == json[i].cat_id) {\n              cat_html += ' selected ';\n            }\n\n            cat_html += ' \">' + json[i].cat_name + '</OPTION>';\n            $(\"#parent_cat_id\").append(cat_html);\n          };\n        };\n\n      },\n      \"json\"\n\n    );\n  }\n\n\n  //保存目录\n  $(\"#save-cat\").click(function(){\n      var cat_name = $(\"#cat_name\").val();\n      var s_number = $(\"#s_number\").val();\n      var cat_id = $(\"#cat_id\").val();\n      var parent_cat_id = $(\"#parent_cat_id\").val();\n      $.post(\n        DocConfig.server+\"/api/catalog/save\",\n        {\"cat_name\": cat_name , \"s_number\": s_number , \"item_id\": item_id , \"cat_id\": cat_id, \"parent_cat_id\": parent_cat_id  },\n        function(data){\n          if (data.error_code == 0) {\n            $(\"#delete-cat\").hide();\n            $(\"#cat_name\").val('');\n            $(\"#s_number\").val('');\n            $(\"#cat_id\").val('');\n            $(\"#parent_cat_id\").val('');\n            secondCatList();\n            //alert(lang[\"save_success\"]);\n          }else{\n            $.alert(lang[\"save_fail\"]);\n          }\n          getCatList();\n        },\n        \"json\"\n\n        );\n      return false;\n  });\n\n  //删除目录\n  $(\"#delete-cat\").click(function(){\n    $.confirm(lang[\"confirm_to_delete\"],{},function(){\n        var cat_id = $(\"#cat_id\").val();\n        if (cat_id > 0 ) {\n            $.post(\n                DocConfig.server+\"/api/catalog/delete\",\n                { \"cat_id\": cat_id  },\n                function(data){\n                  if (data.error_code == 0) {\n                    //alert(lang[\"delete_success\"]);\n                    window.location.href=\"?s=home/catalog/edit&item_id=\"+item_id;\n                  }else{\n                    if (data.error_message) {\n                      $.alert(data.error_message);\n                    }else{\n                      $.alert(lang[\"delete_fail\"]);\n                    }\n                    \n                  }\n                },\n                \"json\"\n              );\n        }\n      });\n\n      return false;\n  })\n\n  $(\".exist-cat\").click(function(){\n    window.location.href=\"?s=home/item/show&item_id=\"+item_id;\n  });\n\n\n});\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "Public/js/common/showdoc.js",
    "content": "\n/*判断是否是移动设备*/\nfunction isMobile(){\nreturn navigator.userAgent.match(/iPhone|iPad|iPod|Android|android|BlackBerry|IEMobile/i) ? true : false; \n}\n\n//判断是否是在线ShowDoc\nfunction is_showdoc_online(){\n\tvar host = window.location.host;\n\tif(host.indexOf(\"showdoc.cc\") > -1 || host.indexOf(\"wu.com\") > -1){\n\t\treturn true;\n\t}else{\n\t\treturn false;\n\t}\n}\n\n//给文字加上颜色\nfunction set_text_color( id , color){\n\tvar cookie_key = \"is_\"+id+\"_click\";\n\n\tvar is_click = getCookie(cookie_key);\n\tif (!is_click) {\n\t\t$(\"#\"+id).css(\"color\",color);\n\t};\n\n\t$(\"#\"+id).click(function(){\n\t\tvar is_click = getCookie(cookie_key);\n\t\tif (!is_click) {\n\t\t\t$(this).css(\"color\",\"\");\n\t\t\tsetCookie(cookie_key , 1 , 900);\n\t\t};\n\t});\n}\n\n\n///设置cookie \nfunction setCookie(NameOfCookie, value, expiredays) \n{ \n\t//@参数:三个变量用来设置新的cookie: \n\t//cookie的名称,存储的Cookie值, \n\t// 以及Cookie过期的时间. \n\t// 这几行是把天数转换为合法的日期 \n\n\tvar ExpireDate = new Date (); \n\tExpireDate.setTime(ExpireDate.getTime() + (expiredays * 24 * 3600 * 1000)); \n\n\t// 下面这行是用来存储cookie的,只需简单的为\"document.cookie\"赋值即可. \n\t// 注意日期通过toGMTstring()函数被转换成了GMT时间。 \n\n\tdocument.cookie = NameOfCookie + \"=\" + escape(value) + \n\t  ((expiredays == null) ? \"\" : \"; expires=\" + ExpireDate.toGMTString()); \n} \n\n///获取cookie值 \nfunction getCookie(NameOfCookie) \n{ \n\n\t// 首先我们检查下cookie是否存在. \n\t// 如果不存在则document.cookie的长度为0 \n\n\tif (document.cookie.length > 0) \n\t{ \n\n\t// 接着我们检查下cookie的名字是否存在于document.cookie \n\n\t// 因为不止一个cookie值存储,所以即使document.cookie的长度不为0也不能保证我们想要的名字的cookie存在 \n\t//所以我们需要这一步看看是否有我们想要的cookie \n\t//如果begin的变量值得到的是-1那么说明不存在 \n\n\tbegin = document.cookie.indexOf(NameOfCookie+\"=\"); \n\tif (begin != -1)    \n\t{ \n\n\t// 说明存在我们的cookie. \n\n\tbegin += NameOfCookie.length+1;//cookie值的初始位置 \n\tend = document.cookie.indexOf(\";\", begin);//结束位置 \n\tif (end == -1) end = document.cookie.length;//没有;则end为字符串结束位置 \n\treturn unescape(document.cookie.substring(begin, end)); } \n\t} \n\n\treturn null; \n\n\t// cookie不存在返回null \n} \n\n///删除cookie \nfunction delCookie (NameOfCookie) \n{ \n\t// 该函数检查下cookie是否设置，如果设置了则将过期时间调到过去的时间; \n\t//剩下就交给操作系统适当时间清理cookie啦 \n\n\tif (getCookie(NameOfCookie)) { \n\tdocument.cookie = NameOfCookie + \"=\" + \n\t\"; expires=Thu, 01-Jan-70 00:00:01 GMT\"; \n\t} \n}\n\n function show_top_msg(msg,delay){\n  $.bootstrapGrowl(msg, {\n    ele: 'body', // which element to append to\n    type: 'info', // (null, 'info', 'error', 'success')\n    offset: {from: 'top', amount: 20}, // 'top', or 'bottom'\n    align: 'center', // ('left', 'right', or 'center')\n    width: 'auto', // (integer, or 'auto')\n    delay: delay,\n    allow_dismiss: true,\n    stackup_spacing: 10 // spacing between consecutively stacked growls.\n  });\n }\n\n//关闭Div\nfunction closeDiv(target) {\n\t$(target).hide();\n}\n"
  },
  {
    "path": "Public/js/dialog.js",
    "content": "/**\n *  将layer.js的一些方法封装为showdoc常用的对话框.\n *  调用方法如$.window(\"https://www.showdoc.cc/\",\"测试\",\"50%\",\"50%\");\n */\n$(document).ready(function(){\n    jQuery.extend({\n        dialog_self:null,\n        //加载url，弹出窗口\n        window:function(url ,title , width ,height ,callback){\n            if (!title) {\n                title = '';\n            };\n            if (!width) {\n                width = '40%';\n            };\n            if (!height) {\n                height = '40%' ;\n            };\n            return layer.open({\n              type: 2,\n              title: title,\n              shadeClose: true,\n              shade: 0.8,\n              area: [width, height],\n              content: url ,//iframe的url\n              end:callback\n            });\n        },\n        //这是对应上面window()的关闭函数。window里面的iframe页面可以调用此方法来关闭自身\n        close_self_window:function(){\n            //假设这是iframe页\n            var index = parent.layer.getFrameIndex(window.name); //先得到当前iframe层的索引\n            return parent.layer.close(index); //再执行关闭  \n        },\n\n        alert:function(content, options, yes){\n            return layer.alert(content, options, yes)\n        },\n\n        confirm:function(content, options, yes, cancel){\n            return layer.confirm(content, options, yes, cancel) ;\n        },\n\n        closeDialog:function(index){\n            return layer.close(index)  ;\n        },  \n\n        closeAll:function(type){\n            return layer.closeAll(type) ;\n        },\n    \n        prompt:function(options, yes){\n            return layer.prompt(options, yes);\n        },\n\n        msg:function(content, options, end){\n            return layer.msg(content, options, end);\n        },\n\n        photos:function(options){\n            return layer.photos(options);\n        },\n\n    });\n});\n"
  },
  {
    "path": "Public/js/item/delete.js",
    "content": "\n\n\n$(function(){\n  var item_id = $(\"#item_id\").val();\n\n  $('#edit-cat').modal({\n    \"backdrop\":'static'\n  });\n\n  //保存\n  $(\"#save-cat\").click(function(){\n      var password = $(\"#password\").val();\n      $.post(\n        \"?s=/home/item/ajaxDelete\",\n        {\"item_id\": item_id , \"password\": password  },\n        function(data){\n          if (data.error_code == 0) {\n            alert(lang[\"delete_success\"]);\n            window.location.href=\"?s=/home/item/index\";\n          }else{\n            alert(data.error_message);\n\n          }\n        },\n        \"json\"\n\n        );\n      return false;\n  });\n\n  $(\".exist-cat\").click(function(){\n    window.location.href=\"?s=/home/item/show&item_id=\"+item_id;\n  });\n\n});\n\n\n\n\n\n\n"
  },
  {
    "path": "Public/js/item/export.js",
    "content": "$(\".choose_type\").change(function(){\n    if ($(\"#item_type2\").is(\":checked\") ) {\n        $(\".level_2_directory\").removeAttr(\"disabled\");\n        $(\".level_3_directory\").removeAttr(\"disabled\");\n        $(\".page\").removeAttr(\"disabled\");\n    }else{\n        $(\".level_2_directory\").attr(\"disabled\",\"disabled\");\n        $(\".level_3_directory\").attr(\"disabled\",\"disabled\"); \n        $(\".page\").attr(\"disabled\",\"disabled\"); \n    }\n}).trigger(\"change\");\n\n/*加载二级目录*/\nsecondCatList();\n\n//监听是否选择了二级目录。如果选择了，则跟后台判断是否还子目录\n$(\".level_2_directory\").change(function() {\n    getChildCatList();\n});\n\nfunction secondCatList() {\n    var item_id = $(\"#item_id\").val();\n    $.post(\n      DocConfig.server+\"/api/catalog/secondCatList\", {\n        \"item_id\": item_id,\n      },\n      function(data) {\n        $(\".level_2_directory\").html('<OPTION value=\"0\">请选择</OPTION>');\n        if (data.error_code == 0) {\n          json = data.data;\n          for (var i = 0; i < json.length; i++) {\n            cat_html = '<OPTION value=\"' + json[i].cat_id + '\" ';\n            cat_html += ' \">' + json[i].cat_name + '</OPTION>';\n            $(\".level_2_directory\").append(cat_html);\n          };\n        };\n\n      },\n      \"json\"\n\n    );\n}\n\n/*加载三级目录*/\nfunction getChildCatList() {\n    var cat_id = $(\".level_2_directory\").val();\n    $.post(\n      DocConfig.server+\"/api/catalog/childCatList\", {\n        \"cat_id\": cat_id\n      },\n      function(data) {\n        $(\".level_3_directory\").html('<OPTION value=\"0\">全部</OPTION>');\n        if (data.error_code == 0) {\n          json = data.data;\n          for (var i = 0; i < json.length; i++) {\n            cat_html = '<OPTION value=\"' + json[i].cat_id + '\" ';\n            cat_html += ' \">' + json[i].cat_name + '</OPTION>';\n            $(\".level_3_directory\").append(cat_html);\n          };\n        } else {}\n\n      },\n      \"json\"\n\n    );\n}\n\n//提交\n$(\".export-submit\").click(function(){\n    var item_id = $(\"#item_id\").val();\n    var val=$('input:radio[name=\"item_type\"]:checked').val();\n    if (val == 1 ) {\n        var url = DocConfig.server+'/api/export/word&item_id='+item_id ;\n        window.location.href = url;\n    }\n    else if (val == 2) {\n        var cat_id2 = $(\".level_2_directory\").val();\n        var cat_id3 = $(\".level_3_directory\").val();\n\n        if (cat_id2 > 0 ) {\n            var cat_id = cat_id3 > 0 ? cat_id3 : cat_id2 ;\n            var url = DocConfig.server+'/api/export/word_cat&item_id='+item_id+'&cat_id='+cat_id ;\n            window.location.href = url;\n        }else{\n            $.alert(\"请选择要导出的目录\");\n        }\n    }\n\n    return false;\n});"
  },
  {
    "path": "Public/js/item/index.js",
    "content": "\nlayer_index = layer.load(1, {\n  shade: [0.1, '#fff'] //0.1透明度的白色背景\n});\n$.get(\n  DocConfig.server+\"/api/item/myList\",\n  {},\n  function(data){\n    var html = '';\n    if (data.error_code == 0) {\n        console.log(data.data);\n        var json = data.data;\n        for (var i = 0; i < json.length; i++) {\n             html += '<li class=\"span3 text-center\">' ;\n             html += '<a class=\"thumbnail item-thumbnail\" href=\"?s=home/item/show&item_id='+json[i]['item_id']+'\" title=\"'+json[i]['item_description']+'\">';\n             html +=  '<span class=\"item-setting\" data-src=\"?s=home/item/setting&item_id='+json[i]['item_id']+'\"  title=\"项目设置\">';\n             html +=  '<i class=\"icon-wrench\" ></i>';\n             html +=  '</span>';\n             if (json[i]['top'] > 0 ) {\n                html +=  '<span class=\"item-top\" data-action=\"cancel\" data-item_id=\"'+json[i]['item_id']+'\" title=\"取消置顶\"><i class=\"icon-arrow-down\" ></i></span>';\n             }else{\n                html +=  '<span class=\"item-top\" data-action=\"top\" data-item_id=\"'+json[i]['item_id']+'\" title=\"置顶项目\"><i class=\"icon-arrow-up\"  ></i></span>';\n             }\n             html +=  '<p class=\"my-item\">'+json[i]['item_name']+'</p>';\n             html +=  '</a>';\n             html +=  '</li> ';\n        };\n        html +=  '<li class=\"span3 text-center\" >';\n        html +=  '<a class=\"thumbnail\" href=\"?s=home/item/add\" title=\"'+lang[\"add_an_item\"]+'\">';\n        html +=  '<p class=\"my-item \">'+lang[\"new_item\"]+'&nbsp;<i class=\"icon-plus\"></i></p>';\n        html +=  '</a></li>';\n        $(\"#item-list\").html(html);\n        $(\"#add-item\").show();\n        layer.closeAll();\n        bind_events();\n    } else {\n      $.alert(lang[\"save_fail\"]);\n\n    }\n  },\n  \"json\"\n\n  );\n\n\nfunction bind_events(){\n\n  //当鼠标放在项目上时将浮现设置和置顶图标\n  $(\".item-thumbnail\").mouseover(function(){\n    $(this).find(\".item-setting\").show();\n    $(this).find(\".item-top\").show();\n    $(this).find(\".item-down\").show();\n  });\n\n  //当鼠标离开项目上时将隐藏设置和置顶图标\n  $(\".item-thumbnail\").mouseout(function(){\n    $(this).find(\".item-setting\").hide();\n    $(this).find(\".item-top\").hide();\n    $(this).find(\".item-down\").hide();\n  });\n\n  //点击项目设置图标时\n  $(\".item-setting\").click(function(){\n    var url = $(this).data(\"src\");\n    window.location.href = url ;\n    return false;\n  });\n\n  //点击项目置顶图标时\n  $(\".item-top\").click(function(){\n\n    var action = $(this).data(\"action\");\n    var item_id = $(this).data(\"item_id\");\n    $.post(\n      DocConfig.server+\"/api/item/top\",\n      {\"action\":action,\"item_id\":item_id},\n      function(data){\n        window.location.reload();\n      },\n      \"json\"\n      );\n    return false;\n  });\n\n  //点击取消置顶图标时\n  $(\".item-down\").click(function(){\n\n    var action = 'cancel';\n    var item_id = $(this).data(\"item_id\");\n    $.post(\n      DocConfig.server+\"/api/item/top\",\n      {\"action\":action,\"item_id\":item_id},\n      function(data){\n        window.location.reload();\n      },\n      \"json\"\n      );\n    return false;\n  });\n\n}"
  },
  {
    "path": "Public/js/item/setting.js",
    "content": "$(function(){\n  $('a[data-toggle=\"tab\"]').on('shown', function (e) {\n          //e.target // activated tab\n          //e.relatedTarget // previous tab\n          console.log($(e.target).attr(\"href\"));\n        })\n\n    //展示第一个tab\n    $(\"#myTab a:first\").tab(\"show\");\n\n    var item_id = $(\"#item_id\").val() ;\n\n    \n\n    //获取基础信息\n    get_base_info() ;\n    function get_base_info(){\n      $.get(\n        DocConfig.server+\"/api/item/detail\",\n        {\"item_id\":item_id},\n        function(data){\n          if (data.error_code === 0 ) {\n            //console.log(data.data);\n            $(\"#item_name\").val(data.data.item_name);\n            $(\"#item_description\").val(data.data.item_description);\n            $(\"#item_domain\").val(data.data.item_domain);\n            $(\"#password\").val(data.data.password);\n            $(\"#password\").attr('type','password');\n          }else{\n            $.alert(data.error_message);\n          }\n        },\n        \"json\"\n\n        );\n    }\n\n    //保存项目基础信息\n    $(\"#item_save\").click(function(){\n\n      var item_name = $(\"#item_name\").val();\n      var item_description = $(\"#item_description\").val();\n      var item_domain = $(\"#item_domain\").val();\n      var password = $(\"#password\").val();\n      $.post(\n        DocConfig.server+\"/api/item/update\",\n        {\"item_id\":item_id,\"item_name\":item_name,\"item_description\":item_description,\"item_domain\":item_domain,\"password\":password},\n        function(data){\n          if (data.error_code === 0 ) {\n            $.msg('保存成功',{\"time\":1000});\n            get_base_info() ;\n          }else{\n            $.alert(data.error_message);\n          }\n        },\n        \"json\"\n        );\n\n      return false;\n    });\n\n    //点击转让按钮，弹出modal\n    $(\"#attorn-btn\").click(function(){\n      $('#attorn-modal').modal({\n        \"backdrop\":'static'\n      });\n    });\n\n    //监听转让\n    $(\"#attorn_save\").click(function(){\n      var username = $(\"#attorn_username\").val();\n      var password = $(\"#attorn_password\").val();\n      $.post(\n        DocConfig.server+\"/api/item/attorn\",\n        {\"username\": username ,\"item_id\": item_id , \"password\": password  },\n        function(data){\n          if (data.error_code == 0) {\n            $.msg('转让成功，正在跳转回主页..',{\"time\":3000});\n            //跳转\n            setTimeout(function(){\n              window.location.href=\"?s=/home/item/index\";\n            },3000)\n            \n          }else{\n            $.alert(data.error_message);\n          }\n        },\n        \"json\"\n\n        );\n      return false;\n    });\n\n    //删除项目\n    $(\"#delete-item-btn\").click(function(){\n      $('#delete-item-modal').modal({\n        \"backdrop\":'static'\n      });\n    });\n\n    //监听删除\n    $(\"#delete_item_save\").click(function(){\n      var password = $(\"#delete_item_password\").val();\n      $.post(\n        DocConfig.server+\"/api/item/delete\",\n        {\"item_id\": item_id , \"password\": password  },\n        function(data){\n          if (data.error_code == 0) {\n            $.msg('删除成功，正在跳转回主页..',{\"time\":3000});\n            //跳转\n            setTimeout(function(){\n              window.location.href=\"?s=/home/item/index\";\n            },3000)\n            \n          }else{\n            $.alert(data.error_message);\n          }\n        },\n        \"json\"\n\n        );\n      return false;\n    });\n\n    //点击添加成员，弹出modal\n    $(\"#add-member-btn\").click(function(){\n      $('#member-modal').modal({\n        \"backdrop\":'static'\n      });\n    });\n\n\n    //获取成员列表\n    get_member_list();\n    function get_member_list(){\n      $.get(\n        DocConfig.server+\"/api/member/getList\",\n        {\"item_id\":item_id},\n        function(data){\n          $(\"#member-list\").html('');\n          if (data.error_code === 0 ) {\n            //console.log(data.data);\n            var json = data.data ;\n            if (json.length > 0 ) {\n              for (var i = 0; i < json.length; i++) {\n                var html = '<tr>'\n                  +'<td><div class=\"type-parent\">'+json[i].username+'</div></td>'\n                  +'<td><div class=\"type-parent\">'+json[i].addtime+'</div></td>'\n                  +'<td><div class=\"type-parent\">'+json[i].member_group+'</div></td>'\n                  +'<td><a href=\"#\" class=\"member-delete\" data-id=\"'+json[i].item_member_id+'\">删除</a></td>'\n                +'</tr>';\n                $(\"#member-list\").append(html);\n                \n              };\n\n            };\n          }else{\n            $.alert(data.error_message);\n          }\n        },\n        \"json\"\n\n        );\n    }\n\n    //添加成员\n    $(\"#member_save\").click(function(){\n      var username = $(\"#member_username\").val();\n      var member_group_id = $(\"#member_group_id\").is(':checked') ? 0 : 1 ;\n      $.post(\n        DocConfig.server+\"/api/member/save\",\n        {\"item_id\": item_id , \"username\": username ,\"member_group_id\":member_group_id  },\n        function(data){\n          if (data.error_code == 0) {\n            $('#member-modal').modal('hide');\n            $(\"#member_username\").val('');\n            $(\"#member_group_id\").removeAttr(\"checked\");\n            $.msg('添加成功',{\"time\":1000});\n            get_member_list();\n            \n          }else{\n            $.alert(data.error_message);\n          }\n        },\n        \"json\"\n\n        );\n      return false;\n    });\n\n    //删除成员\n    $(\"#member-list\").on(\"click\",'.member-delete',function(){\n      var item_member_id = $(this).data(\"id\");\n      $.confirm(\"确定删除成员吗\",{},function(){\n          $.post(\n            DocConfig.server+\"/api/member/delete\",\n            {\"item_id\": item_id , \"item_member_id\": item_member_id  },\n            function(data){\n              if (data.error_code == 0) {\n                $.msg('删除成功',{\"time\":1000});\n                get_member_list();\n                \n              }else{\n                $.alert(data.error_message);\n              }\n            },\n            \"json\"\n\n            );\n      });\n      return false;\n    });\n\n    //归档项目\n    $(\"#archive-item-btn\").click(function(){\n      $('#archive-item-modal').modal({\n        \"backdrop\":'static'\n      });\n    });\n\n    //监听归档\n    $(\"#archive_item_save\").click(function(){\n      var password = $(\"#archive_item_password\").val();\n      $.post(\n        DocConfig.server+\"/api/item/archive\",\n        {\"item_id\": item_id , \"password\": password  },\n        function(data){\n          if (data.error_code == 0) {\n            $.msg('归档成功',{\"time\":3000});\n            $('#archive-item-modal').modal('hide');\n          }else{\n            $.alert(data.error_message);\n          }\n        },\n        \"json\"\n\n        );\n      return false;\n    });\n\n    //获取item api_key信息\n    get_api_info() ;\n    function get_api_info(){\n      $.get(\n        DocConfig.server+\"/api/item/getKey\",\n        {\"item_id\":item_id},\n        function(data){\n          if (data.error_code === 0 ) {\n            //console.log(data.data);\n            $(\"#api_key\").html(data.data.api_key);\n            $(\"#api_token\").html(data.data.api_token);\n          }else{\n            $.alert(data.error_message);\n          }\n        },\n        \"json\"\n\n        );\n    }\n\n    $(\"#reset_api_token\").click(function(){\n      $.post(\n        DocConfig.server+\"/api/item/resetKey\",\n        {\"item_id\":item_id},\n        function(data){\n          if (data.error_code === 0 ) {\n            //console.log(data.data);\n            $(\"#api_key\").html(data.data.api_key);\n            $(\"#api_token\").html(data.data.api_token);\n          }else{\n            $.alert(data.error_message);\n          }\n        },\n        \"json\"\n\n        );\n      return false;\n    });\n\n  });\n"
  },
  {
    "path": "Public/js/item/show.js",
    "content": "//页面加载完就执行\n$(function(){\n\n  //自动根据url把当前菜单激活\n  var current_page_id = $(\"#current_page_id\").val();\n  //如果中没有指定page_id，则判断有没有父目录为0的页面，默认打开第一个\n  if(!current_page_id) {\n    current_page_id = $(\".doc-left li\").children(\"a\").attr(\"data-page-id\");\n  };\n  if(current_page_id !=null && current_page_id.toString().length>0)\n  {\n    $(\".doc-left li\").each(function(){\n      page_id = $(this).children(\"a\").attr(\"data-page-id\");\n      //如果链接中包含当前url的信息，两者相匹配\n      if (page_id !=null && page_id.toString().length>0 && page_id == current_page_id) {\n        //激活菜单\n        $(this).addClass(\"active\");\n        //如果该菜单是子菜单，则还需要把父菜单打开才行\n        if ($(this).parent('.child-ul')) {\n            $(this).parent('.child-ul').show();\n            $(this).parent('.child-ul').parent('li').children(\"a\").children('i').attr(\"class\",\"icon-chevron-down\");\n            if($(this).parent('.child-ul').parent().parent('.child-ul')){\n              $(this).parent('.child-ul').parent().parent('.child-ul').show(); \n              $(this).parent('.child-ul').parent().parent('.child-ul').parent('li').children(\"a\").children('i').attr(\"class\",\"icon-chevron-down\"); \n            }\n        };\n        page_title = $(this).children(\"a\")[0].innerText;\n        document.title = page_title + \" - ShowDoc\";\n        if (page_id != '' && page_id !='#') {\n            change_page(page_id)\n        };\n      };\n    })\n  }\n\n\n  //根据屏幕宽度进行响应(应对移动设备的访问)\n  if( isMobile() || $(window).width() < 1000){\n      AdaptToMobile();\n  }\n\n  $(window).resize(function(){\n    if( isMobile()){\n        AdaptToMobile();\n    }\n\n    else if($(window).width() < 1000){\n        AdaptToMobile();\n    }else{\n      window.location.reload();\n    }\n  });\n\n  //增加返回顶部按钮\n  $.goup({\n        trigger: 100,\n        bottomOffset: 150,\n        locationOffset: 100,\n        title: lang[\"back_to_top\"] ,\n        titleAsText: true,\n        containerColor:\"#08c\",\n    });\n\n\n  //js获取url参数\n  function GetQueryString(name)\n  {\n       var reg = new RegExp(\"(^|&)\"+ name +\"=([^&]*)(&|$)\");\n       var r = window.location.search.substr(1).match(reg);\n       if(r!=null)return  unescape(r[2]); return null;\n  }\n\n  function AdaptToMobile(){\n    $(\".doc-left\").removeClass(\"span3\");\n    $(\".doc-left\").css(\"width\",'100%');\n    $(\".doc-left\").css(\"height\",'initial');\n    $(\".doc-left\").css(\"min-height\",'0px');\n    $(\".doc-left\").css(\"position\",'static');\n    $(\".doc-right\").css(\"margin-top\",'0px');\n    $(\".doc-right\").css(\"margin-left\",'0px');\n    $(\".doc-right\").removeClass(\"span12\");\n    $(\".doc-head .right\").hide();\n    $(\".page-edit-link\").html('');\n    $(\".doc-left-newbar\").html('');\n    //$(\".iframe_content\").css(\"padding-left\",\"30px\");\n    $(\".iframe_content\").css(\"width\",'');\n    $(\".doc-left .nav-list li a i \").css(\"margin-left\" , '10px');\n    $(\".search-input-append\").css(\"width\",\"100%\");\n    $(\".search-query-input\").css(\"width\",\"70%\");\n\n\n\n  }\n\n  function mScroll(id){\n    $(\"html,body\").stop(true);\n    $(\"html,body\").animate(\n    {scrollTop: $(\"#\"+id).offset().top},\n      2000);\n  } \n\n  //点击左侧菜单事件\n  $(\".doc-left li\").click(function(){\n    //先把所有菜单的激活状态取消\n    $(\".doc-left li\").each(function(){\n      $(this).removeClass(\"active\");\n    });\n    //先判断是否存在子菜单\n    if ($(this).children('.child-ul').length != 0) {\n      //如果子菜单是隐藏的，则显示之；如果是显示状态的，则隐藏\n      if ($(this).children('.child-ul').css(\"display\") == \"none\") {\n        $(this).children('.child-ul').show();\n        $(this).children(\"a\").children('i').attr(\"class\",\"icon-chevron-down\");\n      }else{\n        $(this).children('.child-ul').hide();\n        $(this).children(\"a\").children('i').attr(\"class\",\"icon-chevron-right\");\n      }\n    };\n    //激活菜单\n    $(this).addClass(\"active\");\n    //获取对应的page_id\n    page_id = $(this).children(\"a\").attr(\"data-page-id\");\n    page_title = $(this).children(\"a\")[0].innerText;\n    if (page_id != '' && page_id != null  && page_id !='#') {\n        if (page_title != '' && page_title != null) {\n            document.title = page_title + \" - ShowDoc\";\n        }\n        change_page(page_id);\n        //如果是移动设备的话，则滚动页面\n        if( isMobile()){\n            mScroll(\"page-content\");\n        }\n    };\n    return false;//禁止原有的href链接\n  });\n\n  //切换页面；\n  function change_page(page_id){\n      if(!page_id)return;\n      var item_id = $(\"#item_id\").val();\n      var item_domain = $(\"#item_domain\").val();\n      var base_url = $(\"#base_url\").val();\n      var iframe_url =  base_url+\"/home/page/index/page_id/\"+page_id;\n\n      $(\".page-edit-link\").show();\n      //$(\"#page-content\").attr(\"src\" , iframe_url);\n      $(\"#edit-link\").attr(\"href\" , base_url+\"/home/page/edit/page_id/\"+page_id);\n      $(\"#copy-link\").attr(\"href\" , base_url+\"/home/page/edit/item_id/\"+item_id+\"/copy_page_id/\"+page_id);\n      $(\"#delete-link\").data(\"page_id\",page_id);\n      \n      var domain = item_domain ? item_domain : item_id ;\n      var cur_page_url =  window.location.protocol +\"//\"+window.location.host+base_url+\"/\"+domain;\n      if(base_url.length == 0){\n        cur_page_url += \"?page_id=\"+page_id;\n      }else{\n        cur_page_url += \"&page_id=\"+page_id;\n      }\n      $(\"#share-page-link\").html(cur_page_url);\n      history.replaceState(null, null, cur_page_url);\n      var single_page_url = window.location.protocol +\"//\"+window.location.host+base_url+\"/page/\"+page_id;\n      $(\"#share-single-link\").html(single_page_url);\n\n      $(\"#qr-page-link\").attr(\"src\",\"?s=home/common/qrcode&size=3&url=\"+encodeURIComponent(cur_page_url));\n      $(\"#qr-single-link\").attr(\"src\",\"?s=home/common/qrcode&size=3&url=\"+encodeURIComponent(single_page_url));\n      $(\".show_page_info\").data(\"page_id\",page_id);\n      var html = '<iframe id=\"page-content\" width=\"100%\" scrolling=\"yes\"  height=\"100%\" frameborder=\"0\" style=\" overflow:visible; height:100%;\" name=\"main\"  seamless =\"seamless\"src=\"'+iframe_url+'\"></iframe>';\n      $(\".iframe_content\").html(html);\n      iFrameHeight();\n      \n  }\n\n  //分享项目\n  $(\"#share\").click(function(){\n    $(\"#share-modal\").modal();\n      //延迟绑定分享事件\n        setTimeout(function(){\n          $('#copy-item-link').zclip(\n          {\n            path: DocConfig.pubile +'/jquery.zclip/ZeroClipboard.swf',\n            copy:function()\n            {\n              return $('#share-item-link').html();\n            },\n            afterCopy: function() {\n              show_top_msg(\"已经成功复制到剪切板\",2000);\n            }\n          });\n\n        },500);\n    return false;\n  });\n\n  //分享页面\n  $(\"#share-page\").click(function(){\n    $(\"#share-page-modal\").modal();\n      //延迟绑定分享事件\n        setTimeout(function(){\n          $('#copy-page-link').zclip(\n          {\n            path: DocConfig.pubile +'/jquery.zclip/ZeroClipboard.swf',\n            copy:function()\n            {\n              return $('#share-page-link').html();\n            },\n            afterCopy: function() {\n              show_top_msg(\"已经成功复制到剪切板\",2000);\n            }\n          });\n\n          $('#copy-single-link').zclip(\n          {\n            path:DocConfig.pubile +'/jquery.zclip/ZeroClipboard.swf',\n            copy:function()\n            {\n              return $('#share-single-link').html();\n            },\n            afterCopy: function() {\n              show_top_msg(\"已经成功复制到剪切板\",2000);\n            }\n          });\n        },500);\n\n    return false;\n  });\n\nfunction iFrameHeight() { \n  var ifr = document.getElementById('page-content');\n  ifr.onload = function() {\n      var iDoc = ifr.contentDocument || ifr.document;\n      var height = calcPageHeight(iDoc);\n      ifr.style.height = height + 'px'; \n  }\n }\n\n\n\n  // 计算页面的实际高度，iframe自适应会用到\n  function calcPageHeight(doc) {\n      var cHeight = Math.max(doc.body.clientHeight, doc.documentElement.clientHeight)\n      var sHeight = Math.max(doc.body.scrollHeight, doc.documentElement.scrollHeight)\n      var height  = Math.max(cHeight, sHeight)\n      return height\n  }\n\n  var keyMap = {\n    // 编辑\n    \"Ctrl+E\": function() {\n      location.href = $(\"#edit-link\").attr('href');\n    },\n    // 删除\n    \"Ctrl+D\": function() {\n      $(\"#delete-link\").click();\n    },\n    // 新建页面\n    \"Ctrl+F1\": function() {\n      location.href = $(\"#new-like\").attr('href');\n    },\n    // 新建目录\n    \"Ctrl+F2\": function() {\n      location.href = $(\"#dir-like\").attr('href');\n    }\n  };\n  if (!isMobile()) initKeys();\n  function initKeys() {\n    var $doc = $(document);\n    $.each(keyMap, function(key, fn) {\n      $doc.on('keydown', null, key, function(e) {\n        e.preventDefault();\n        fn();\n        return false;\n      });\n    });\n  }\n\n  $(\".show_page_info\").click(function(){\n    var page_id =  $(this).data(\"page_id\") ;\n    $.post(\n      DocConfig.server+\"/api/page/info\",\n      {\"page_id\":page_id},\n      function(data){\n        var html = \"<p>最后编辑时间：\"+data.data.addtime+\"</p><p>编辑人：\"+data.data.author_username+\"</p>\";\n         $.alert(html);\n      },\n      \"json\"\n\n      );\n    return false;\n  });\n\n  //删除页面\n  $(\"#delete-link\").click(function(){\n    var page_id =  $(this).data(\"page_id\") ;\n    $.confirm(lang[\"confirm_to_delete\"],{},function(){\n      $.post(\n        DocConfig.server+\"/api/page/delete\",\n        {\"page_id\":page_id},\n        function(data){\n                  if (data.error_code == 0) {\n                    $.alert(lang[\"delete_success\"],function(){\n                      window.location.reload();\n                    });\n                    \n                  }else{\n                    if (data.error_message) {\n                      $.alert(data.error_message);\n                    }else{\n                      $.alert(lang[\"delete_fail\"]);\n                    }\n                    \n                  }\n          \n        },\n        \"json\"\n\n        );\n    });\n\n    return false;\n  });\n\n  $(\"#delete-link\").click(function(){\n    var page_id =  $(this).data(\"page_id\") ;\n    $.confirm(lang[\"confirm_to_delete\"],{},function(){\n      $.post(\n        DocConfig.server+\"/api/page/delete\",\n        {\"page_id\":page_id},\n        function(data){\n                  if (data.error_code == 0) {\n                    $.alert(lang[\"delete_success\"],function(){\n                      window.location.reload();\n                    });\n                    \n                  }else{\n                    if (data.error_message) {\n                      $.alert(data.error_message);\n                    }else{\n                      $.alert(lang[\"delete_fail\"]);\n                    }\n                    \n                  }\n          \n        },\n        \"json\"\n\n        );\n    });\n\n    return false;\n  });\n    window.addEventListener('message', function(e){\n      if(e.origin != window.location.origin) return;\n      if (e.data.meessage_type != 'img_url') {\n        return ;\n      }\n     var img_url =e.data.img_url;\n      var json = {\n          \"title\": \"\", //相册标题\n          \"id\": 123, //相册id\n          \"start\": 0, //初始显示的图片序号，默认0\n          \"data\": [   //相册包含的图片，数组格式\n              {\n                \"alt\": \"\",\n                \"pid\": 666, //图片id\n                \"src\": img_url, //原图地址\n                \"thumb\": img_url //缩略图地址\n              }\n            ]\n          }\n        $.photos({\n          photos: json\n          ,anim: 5 //0-6的选择，指定弹出图片动画类型，默认随机（请注意，3.0之前的版本用shift参数）\n        });\n  }, false);\n\n})\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "Public/js/item/show_single_page.js",
    "content": "$(function() {\n  hljs.initHighlightingOnLoad();\n\n  var EditormdView = editormd.markdownToHTML(\"page_md_content\", {\n    htmlDecode: \"style,script,iframe\", // you can filter tags decode\n    emoji: true,\n    taskList: true,\n    tex: true, // 默认不解析\n    flowChart: true, // 默认不解析\n    sequenceDiagram: true, // 默认不解析\n  });\n\n  //为所有table标签添加bootstap支持的表格类\n  $(\"table\").addClass(\"table table-bordered table-hover\");\n  //当表格列数过长时将自动出现滚动条\n  $.each($('table'), function() {\n    $(this).prop('outerHTML', '<div style=\"width: 100%;overflow-x: auto;\">' + $(this).prop('outerHTML') + '</div>');\n  });\n\n  //超链接都在新窗口打开\n  $('a[href^=\"http\"]').each(function() {\n    $(this).attr('target', '_blank');\n  });\n  if (!isMobile()) {\n    $(\"th\").css(\"min-width\", \"77px\");\n  };\n\n  //lightbox\n  //增加返回顶部按钮\n  $.goup({\n    trigger: 100,\n    bottomOffset: 150,\n    locationOffset: 100,\n    title: lang[\"back_to_top\"],\n    titleAsText: true,\n    containerColor: \"#08c\",\n  });\n\n  if (isMobile() || $(window).width() < 1000) {\n    AdaptToMobile();\n  }\n\n  $(window).resize(function() {\n    if (isMobile()) {\n      AdaptToMobile();\n    } else if ($(window).width() < 1000) {\n      AdaptToMobile();\n    } else {\n      window.location.reload();\n    }\n  });\n\n  history.replaceState(null, null, $(\"#share-item-link\").html());\n\n  //分享项目\n  $(\"#share\").click(function() {\n    $(\"#share-modal\").modal();\n    //延迟绑定分享事件\n    setTimeout(function() {\n      $('#copy-item-link').zclip({\n        path: DocConfig.pubile + '/jquery.zclip/ZeroClipboard.swf',\n        copy: function() {\n          return $('#share-item-link').html();\n        },\n        afterCopy: function() {\n          show_top_msg(\"已经成功复制到剪切板\", 2000);\n        }\n      });\n\n    }, 500);\n    return false;\n  });\n\n  $(\"table thead tr\").css({\n    \"background-color\": \"#08c\",\n    \"color\": \"#fff\"\n  });\n  $(\"table tr\").each(function() {\n    if ($(this).find(\"td\").eq(1).html() == \"object\" || $(this).find(\"td\").eq(1).html() == \"array[object]\") {\n      $(this).css({\n        \"background-color\": \"#99CC99\",\n        \"color\": \"#000\"\n      });\n    }\n\n  });\n  \n  function AdaptToMobile() {\n    $(\".doc-container\").css(\"width\", \"90%\");\n    $(\"#doc-body\").css(\"width\", \"90%\");\n    $(\"#header\").css(\"height\", \"20px\");\n    $(\".doc-title-box\").css(\"margin\", \"20px 20px 0px 20px\");\n    $(\"#footer\").css(\"font-size\", \"11pt\");\n    $(\".tool-bar\").hide();\n  }\n\n  //图片点击放大\n  $(\"#page_md_content img\").click(function() {\n    var img_url = $(this).attr(\"src\");\n    //如果不在iframe里，则直接当前窗口打开\n    if (self == top) {\n      var json = {\n        \"title\": \"\", //相册标题\n        \"id\": 123, //相册id\n        \"start\": 0, //初始显示的图片序号，默认0\n        \"data\": [ //相册包含的图片，数组格式\n          {\n            \"alt\": \"\",\n            \"pid\": 666, //图片id\n            \"src\": img_url, //原图地址\n            \"thumb\": img_url //缩略图地址\n          }\n        ]\n      }\n\n      $.photos({\n        photos: json,\n        anim: 5 //0-6的选择，指定弹出图片动画类型，默认随机（请注意，3.0之前的版本用shift参数）\n      });\n\n    } else {\n      //如果在iframe里，则直接传url给父窗口\n      top.postMessage(img_url, '*');\n    }\n\n  });\n\n});"
  },
  {
    "path": "Public/js/jquery.hotkeys.js",
    "content": "/*jslint browser: true*/\n/*jslint jquery: true*/\n\n/*\n * jQuery Hotkeys Plugin\n * Copyright 2010, John Resig\n * Dual licensed under the MIT or GPL Version 2 licenses.\n *\n * Based upon the plugin by Tzury Bar Yochay:\n * https://github.com/tzuryby/jquery.hotkeys\n *\n * Original idea by:\n * Binny V A, http://www.openjs.com/scripts/events/keyboard_shortcuts/\n */\n\n/*\n * One small change is: now keys are passed by object { keys: '...' }\n * Might be useful, when you want to pass some other data to your handler\n */\n\n(function(jQuery) {\n\n  jQuery.hotkeys = {\n    version: \"0.2.0\",\n\n    specialKeys: {\n      8: \"backspace\",\n      9: \"tab\",\n      10: \"return\",\n      13: \"return\",\n      16: \"shift\",\n      17: \"ctrl\",\n      18: \"alt\",\n      19: \"pause\",\n      20: \"capslock\",\n      27: \"esc\",\n      32: \"space\",\n      33: \"pageup\",\n      34: \"pagedown\",\n      35: \"end\",\n      36: \"home\",\n      37: \"left\",\n      38: \"up\",\n      39: \"right\",\n      40: \"down\",\n      45: \"insert\",\n      46: \"del\",\n      59: \";\",\n      61: \"=\",\n      96: \"0\",\n      97: \"1\",\n      98: \"2\",\n      99: \"3\",\n      100: \"4\",\n      101: \"5\",\n      102: \"6\",\n      103: \"7\",\n      104: \"8\",\n      105: \"9\",\n      106: \"*\",\n      107: \"+\",\n      109: \"-\",\n      110: \".\",\n      111: \"/\",\n      112: \"f1\",\n      113: \"f2\",\n      114: \"f3\",\n      115: \"f4\",\n      116: \"f5\",\n      117: \"f6\",\n      118: \"f7\",\n      119: \"f8\",\n      120: \"f9\",\n      121: \"f10\",\n      122: \"f11\",\n      123: \"f12\",\n      144: \"numlock\",\n      145: \"scroll\",\n      173: \"-\",\n      186: \";\",\n      187: \"=\",\n      188: \",\",\n      189: \"-\",\n      190: \".\",\n      191: \"/\",\n      192: \"`\",\n      219: \"[\",\n      220: \"\\\\\",\n      221: \"]\",\n      222: \"'\"\n    },\n\n    shiftNums: {\n      \"`\": \"~\",\n      \"1\": \"!\",\n      \"2\": \"@\",\n      \"3\": \"#\",\n      \"4\": \"$\",\n      \"5\": \"%\",\n      \"6\": \"^\",\n      \"7\": \"&\",\n      \"8\": \"*\",\n      \"9\": \"(\",\n      \"0\": \")\",\n      \"-\": \"_\",\n      \"=\": \"+\",\n      \";\": \": \",\n      \"'\": \"\\\"\",\n      \",\": \"<\",\n      \".\": \">\",\n      \"/\": \"?\",\n      \"\\\\\": \"|\"\n    },\n\n    // excludes: button, checkbox, file, hidden, image, password, radio, reset, search, submit, url\n    textAcceptingInputTypes: [\n      \"text\", \"password\", \"number\", \"email\", \"url\", \"range\", \"date\", \"month\", \"week\", \"time\", \"datetime\",\n      \"datetime-local\", \"search\", \"color\", \"tel\"],\n\n    // default input types not to bind to unless bound directly\n    textInputTypes: /textarea|input|select/i,\n\n    options: {\n      filterInputAcceptingElements: true,\n      filterTextInputs: true,\n      filterContentEditable: true\n    }\n  };\n\n  function keyHandler(handleObj) {\n    if (typeof handleObj.data === \"string\") {\n      handleObj.data = {\n        keys: handleObj.data\n      };\n    }\n\n    // Only care when a possible input has been specified\n    if (!handleObj.data || !handleObj.data.keys || typeof handleObj.data.keys !== \"string\") {\n      return;\n    }\n\n    var origHandler = handleObj.handler,\n      keys = handleObj.data.keys.toLowerCase().split(\" \");\n\n    handleObj.handler = function(event) {\n      //      Don't fire in text-accepting inputs that we didn't directly bind to\n      if (this !== event.target &&\n        (jQuery.hotkeys.options.filterInputAcceptingElements &&\n          jQuery.hotkeys.textInputTypes.test(event.target.nodeName) ||\n          (jQuery.hotkeys.options.filterContentEditable && jQuery(event.target).attr('contenteditable')) ||\n          (jQuery.hotkeys.options.filterTextInputs &&\n            jQuery.inArray(event.target.type, jQuery.hotkeys.textAcceptingInputTypes) > -1))) {\n        return;\n      }\n\n      var special = event.type !== \"keypress\" && jQuery.hotkeys.specialKeys[event.which],\n        character = String.fromCharCode(event.which).toLowerCase(),\n        modif = \"\",\n        possible = {};\n\n      jQuery.each([\"alt\", \"ctrl\", \"shift\"], function(index, specialKey) {\n\n        if (event[specialKey + 'Key'] && special !== specialKey) {\n          modif += specialKey + '+';\n        }\n      });\n\n      // metaKey is triggered off ctrlKey erronously\n      if (event.metaKey && !event.ctrlKey && special !== \"meta\") {\n        modif += \"meta+\";\n      }\n\n      if (event.metaKey && special !== \"meta\" && modif.indexOf(\"alt+ctrl+shift+\") > -1) {\n        modif = modif.replace(\"alt+ctrl+shift+\", \"hyper+\");\n      }\n\n      if (special) {\n        possible[modif + special] = true;\n      }\n      else {\n        possible[modif + character] = true;\n        possible[modif + jQuery.hotkeys.shiftNums[character]] = true;\n\n        // \"$\" can be triggered as \"Shift+4\" or \"Shift+$\" or just \"$\"\n        if (modif === \"shift+\") {\n          possible[jQuery.hotkeys.shiftNums[character]] = true;\n        }\n      }\n\n      for (var i = 0, l = keys.length; i < l; i++) {\n        if (possible[keys[i]]) {\n          return origHandler.apply(this, arguments);\n        }\n      }\n    };\n  }\n\n  jQuery.each([\"keydown\", \"keyup\", \"keypress\"], function() {\n    jQuery.event.special[this] = {\n      add: keyHandler\n    };\n  });\n\n})(jQuery || this.jQuery || window.jQuery);\n"
  },
  {
    "path": "Public/js/lang.en-us.js",
    "content": "\nvar lang = new Array();\n\n//attorn\nlang['attorn_success'] = \"Attorn success\";\n\n//catalog\nlang[\"none\"] = \"none\";\nlang[\"save_success\"] = \"Save success\";\nlang[\"save_fail\"] = \"Save fail\";\nlang[\"confirm_to_delete\"] = \"Are you sure that you want to delete it?\";\nlang[\"delete_success\"] = \"Delete success\";\nlang[\"delete_fail\"] = \"Delete fail\";\n\n//item\nlang[\"back_to_top\"] = \"Back to top\";\nlang[\"new_item\"] = \"New item\";\nlang[\"add_an_item\"] = \"add an item\";\n\n//page/edite\nlang[\"params\"] = \"Params\";\nlang[\"type\"] = \"Type\";\nlang[\"description\"] = \"Description\";\nlang[\"editormd_placeholder\"] = \"Supports Markdown.the left side to edite, the right Preview\";\nlang[\"json_fail\"] = \"JSON import failed\";\nlang[\"filed\"] = \"filed\";\nlang[\"none\"] = \"none\";\nlang[\"save_templ_title\"] = \"Pealse set the title for the template you want to save\";\nlang[\"saved_templ_msg1\"] = \"Template'\";\nlang[\"saved_templ_msg2\"] = \"' is saved.When you create or edit a new page, click the 'More template' button, then you can use the template you save\";\nlang[\"save_time\"] = \"Save time\";\nlang[\"templ_title\"] = \"Template title\";\nlang[\"operation\"] = \"Operation\";\nlang[\"use_this_template\"] = \"Insert this template\";\nlang[\"delete_this_template\"] = \"Delete template\";\nlang[\"no_templ_msg\"] = \"You have not saved any templates.When you edit the page, click the 'save' button on the right click, select Save as template in the down menu .When you create or edit a new page, click the 'More template' button, then you can use the template that you save\";\nlang[\"add_page_comments_msg\"] = \"Please enter the page comments.It can be page update log , or other you want.It will be showed in page history version convenient for you to check the change of page\";\n\nlang[\"confirm_to_delete_member\"] = \"Sure to delete this member ?\";"
  },
  {
    "path": "Public/js/lang.zh-cn.js",
    "content": "\nvar lang = new Array();\n\n//attorn\nlang['attorn_success'] = \"转让成功！\";\n\n//catalog\nlang[\"none\"] = \"无\";\nlang[\"save_success\"] = \"保存成功！\";\nlang[\"save_fail\"] = \"保存失败！\";\nlang[\"confirm_to_delete\"] = \"确认删除吗？\";\nlang[\"delete_success\"] = \"删除成功！\";\nlang[\"delete_fail\"] = \"删除失败！\";\n\n//item\nlang[\"back_to_top\"] = \"回到顶部\";\nlang[\"new_item\"] = \"新建项目\";\nlang[\"add_an_item\"] = \"新建一个新的项目\";\n\n//page/edite\nlang[\"params\"] = \"参数名\";\nlang[\"type\"] = \"类型\";\nlang[\"description\"] = \"说明\";\nlang[\"editormd_placeholder\"] = \"本编辑器支持Markdown编辑，左边编写，右边预览\";\nlang[\"json_fail\"] = \"json导入失败\";\nlang[\"filed\"] = \"键\";\nlang[\"none\"] = \"无\";\nlang[\"save_templ_title\"] = \"请为要保存的模板设置标题\";\nlang[\"saved_templ_msg1\"] = \"已经保存好模板“\";\nlang[\"saved_templ_msg2\"] = \"”。你以后新建或者编辑编辑页面时，点击“更多模板”按钮，便可以使用你保存的模板\";\nlang[\"save_time\"] = \"保存时间\";\nlang[\"templ_title\"] = \"模板标题\";\nlang[\"operation\"] = \"操作\";\nlang[\"use_this_template\"] = \"插入此模板\";\nlang[\"delete_this_template\"] = \"删除模板\";\nlang[\"no_templ_msg\"] = \"你尚未保存过任何模板。你可以在编辑页面时，在“保存”按钮右边点击，在下拉菜单中选择“另存为模板”。把页面内容保存为模板后，你下次新建或者编辑页面时便可以使用你之前保存的模板\";\nlang[\"add_page_comments_msg\"] = \"请输入页面注释内容。可以填写你对页面的修改注释或者其它注释。添加后，在页面的历史版本处会显示每一个页面版本的注释，方便你查阅、追踪页面的修改\";\n\n\nlang[\"confirm_to_delete_member\"] = \"确认要删除该成员？\";"
  },
  {
    "path": "Public/js/member/edit.js",
    "content": "\n$(function(){\n  var item_id = $(\"#item_id\").val();\n\n  $('#edit-cat').modal({\n    \"backdrop\":'static'\n  });\n\n  getList();\n\n  function getList(){\n      $.get(\n        \"?s=/home/member/getList\",\n        { \"item_id\": item_id },\n        function(data){\n          $(\"#show-cat\").html('');\n          if (data.error_code == 0) {\n            json = data.data;\n            console.log(json);\n            for (var i = 0; i < json.length; i++) {\n                cat_html ='<a class=\"badge badge-important single-cat\" data-username=\"'+json[i].username+'\" >'+json[i].username+'&nbsp;x</a>';\n                $(\"#show-cat\").append(cat_html);\n            };\n\n\n          };\n          \n        },\n        \"json\"\n\n        );\n  }\n\n  //保存\n  $(\"#save-cat\").click(function(){\n      var username = $(\"#username\").val();\n      var member_group_id = $(\"#member_group_id\").is(':checked') ? 0 : 1 ;\n      $.post(\n        \"?s=/home/member/save\",\n        {\"username\": username ,\"item_id\": item_id,\"member_group_id\": member_group_id   },\n        function(data){\n          if (data.error_code == 0) {\n            $(\"#username\").val('');\n            alert(lang[\"save_success\"]);\n          }else{\n            alert(data.error_message);\n\n          }\n          getList();\n        },\n        \"json\"\n\n        );\n      return false;\n  });\n\n  //删除\n  $('#show-cat').delegate('.single-cat','click', function(){\n      var username = $(this).attr(\"data-username\");\n        if (!confirm(lang['confirm_to_delete_member'])) {\n            return false;\n        }\n      if (username) {\n          $.post(\n              \"?s=/home/member/delete\",\n              { \"username\": username, \"item_id\" :item_id },\n              function(data){\n                if (data.error_code == 0) {\n                  alert(lang[\"delete_success\"]);\n                  getList();\n                }else{\n                  alert(lang[\"delete_fail\"]);\n\n                }\n              },\n              \"json\"\n            );\n\n      }\n      return false;\n  });\n\n  $(\".exist-cat\").click(function(){\n    \n    window.location.href=\"?s=/home/item/show&item_id=\"+item_id;\n  });\n\n});\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "Public/js/page/edit.js",
    "content": "var editormd;\nvar template_list;\nvar json_table_data = '|' + lang[\"params\"] + '|' + lang[\"type\"] + '|' + lang[\"description\"] + '|\\n' +\n  '|:-------|:-------|:-------|\\n';\n\n$(function() {\n\n  //给按钮文字加上颜色，点击后则去掉颜色\n  if (is_showdoc_online()) {\n    set_text_color(\"runapi\", \"red\");\n  };\n\n  /*加载目录*/\n  secondCatList();\n\n  function secondCatList() {\n    var default_second_cat_id = $(\"#default_second_cat_id\").val();\n    var item_id = $(\"#item_id\").val();\n    $.post(\n      DocConfig.server+\"/api/catalog/secondCatList\", {\n        \"item_id\": item_id,\n      },\n      function(data) {\n        $(\"#cat_id\").html('<OPTION value=\"0\">' + lang[\"none\"] + '</OPTION>');\n        if (data.error_code == 0) {\n          json = data.data;\n          console.log(json);\n          for (var i = 0; i < json.length; i++) {\n            cat_html = '<OPTION value=\"' + json[i].cat_id + '\" ';\n            if (default_second_cat_id == json[i].cat_id) {\n              cat_html += ' selected ';\n            }\n\n            cat_html += ' \">' + json[i].cat_name + '</OPTION>';\n            $(\"#cat_id\").append(cat_html);\n          };\n          getChildCatList();\n        };\n\n      },\n      \"json\"\n\n    );\n  }\n\n  function getChildCatList() {\n    var cat_id = $(\"#cat_id\").val();\n    var default_child_cat_id = $(\"#default_child_cat_id\").val();\n    $.post(\n      DocConfig.server+\"/api/catalog/childCatList\", {\n        \"cat_id\": cat_id\n      },\n      function(data) {\n        $(\"#parent_cat_id\").html('<OPTION value=\"0\">' + lang[\"none\"] + '</OPTION>');\n        if (data.error_code == 0) {\n          json = data.data;\n          console.log(json);\n          for (var i = 0; i < json.length; i++) {\n            cat_html = '<OPTION value=\"' + json[i].cat_id + '\" ';\n            if (default_child_cat_id == json[i].cat_id) {\n              cat_html += ' selected ';\n            }\n\n            cat_html += ' \">' + json[i].cat_name + '</OPTION>';\n            $(\"#parent_cat_id\").append(cat_html);\n          };\n        } else {}\n\n      },\n      \"json\"\n\n    );\n  }\n  //监听是否选择了目录。如果选择了，则跟后台判断是否还子目录\n  $(\"#cat_id\").change(function() {\n    getChildCatList();\n  });\n\n  var keyMap = {\n    // 保存\n    \"Ctrl-S\": function() {\n      $(\"#save\").click();\n    }\n  };\n  initEditorOutsideKeys();\n\n  function initEditorOutsideKeys() {\n    if (!editormd) return;\n    var $doc = $(document);\n    $.each(keyMap, function(key, fn) {\n      $doc.on('keydown', null, key.replace('-', '+'), function(e) {\n        e.preventDefault();\n        fn();\n      });\n    });\n  }\n  // 如果是新增页面，则光标为标题文本框\n  if (location.href.indexOf('type=new') !== -1) {\n    setTimeout(function() {\n      $('#page_title').focus();\n    }, 1000);\n  }\n\n  /*初始化编辑器*/\n  editormd = editormd(\"editormd\", {\n    width: \"90%\",\n    height: 1000,\n    syncScrolling: \"single\",\n    path: DocConfig.pubile + \"/editor.md/lib/\",\n    placeholder: lang[\"editormd_placeholder\"],\n    taskList: true,\n    tex: true, // 默认不解析\n    flowChart: true, // 默认不解析\n    sequenceDiagram: true, // 默认不解析\n    htmlDecode : \"style,script,iframe|filterXSS\",//解析html\n    imageUpload: true,\n    imageFormats: [\"jpg\", \"jpeg\", \"gif\", \"png\", \"bmp\", \"webp\", \"JPG\", \"JPEG\", \"GIF\", \"PNG\", \"BMP\", \"WEBP\"],\n    imageUploadURL: \"?s=home/page/uploadImg\",\n    onload: function() {\n      this.addKeyMap(keyMap);\n    }\n  });\n\n  /*插入API接口模板*/\n  $(\"#api-doc\").click(function() {\n    var tmpl = $(\"#api-doc-templ\").html();\n    editormd.insertValue(tmpl);\n  });\n  /*插入数据字典模板*/\n  $(\"#database-doc\").click(function() {\n    var tmpl = $(\"#database-doc-templ\").html();\n    editormd.insertValue(tmpl);\n  });\n\n  /*JSON转参数表格*/\n  $(\"#jsons\").click(function() {\n\n    $(\"#json-templ\").show();\n\n  });\n\n  /*JSON格式美化*/\n  $(\"#beautify-json\").click(function() {\n\n    $(\"#beautify-json-dialog\").show();\n\n  });\n\n\n\n  $(\"#json-templ .editormd-enter-btn\").click(function() {\n\n\n    var datas = $(\"#json-templ .jsons\").val();\n\n    try {\n      Change($.parseJSON(datas));\n    } catch (e) {\n      alert(lang[\"json_fail\"] + e);\n    }\n\n    //datas=processJSONImport(datas);\n    //alert(datas);\n    /*var datas='|键|值|类型|空|注释|\\n'+\n    '|:-------|:-------|:-------|:-------|:-------|\\n'+\n    '|uid|int(10)|否|||\\n'+\n    '|username|varchar(20)|否||用户名|';*/\n\n    //alert(json_table_data);return;\n\n\n\n    editormd.insertValue(json_table_data);\n\n    json_table_data = '|' + lang[\"filed\"] + '|' + lang[\"type\"] + '|' + lang[\"description\"] + '|\\n' +\n      '|:-------|:-------|:-------|\\n';\n\n\n    $(\"#json-templ .jsons\").val(\"\");\n    $(\"#json-templ\").hide();\n\n  });\n\n\n  $(\"#beautify-json-dialog .editormd-enter-btn\").click(function() {\n    var data = $(\"#beautify-json-dialog .jsons\").val();\n    try {\n      data = data.replace(/(^\\s*)|(\\s*$)/g, \"\");\n      op1 = data.substr(0, 1) == \"[\" ? \"[\" : \"{\";\n      op2 = (op1 == \"[\") ? \"]\" : \"}\";\n      var text = \"\\n ``` \\n \" + op1 + \" \\n\" + dump(JSON.parse(data)) + \" \" + op2 + \" \\n\\n ```\\n\\n\"; //整体加个大括号\n      //$(\"#beautify-json-dialog .jsons\").val(text);\n      $(\"#beautify-json-dialog .jsons\").val(\"\");\n      editormd.insertValue(text);\n    } catch (e) {\n      //非json数据直接显示\n      //$(\"#beautify-json-dialog .jsons\").val(data);\n      $(\"#beautify-json-dialog .jsons\").val(\"\");\n      editormd.insertValue(data);\n    }\n    $(\"#beautify-json-dialog\").hide();\n\n  });\n  //{\"dgfgdfg\":\"gdfgdfg\"}\n\n  //格式化json数据\n  function dump(arr, level) {\n    var dumped_text = \"\";\n    if (!level) level = 0;\n\n    //The padding given at the beginning of the line. \n    var level_padding = \"\";\n    for (var j = 0; j < level + 1; j++) level_padding += \"     \";\n    if (typeof(arr) == 'object') { //Array/Hashes/Objects \n      var i = 0;\n      for (var item in arr) {\n        var value = arr[item];\n        if (typeof(value) == 'object') { //If it is an array, \n          dumped_text += level_padding + \"\\\"\" + item + \"\\\" : \\{ \\n\";\n          dumped_text += dump(value, level + 1);\n          dumped_text += level_padding + \"\\}\";\n        } else {\n          if (typeof(value) == \"number\") {\n            dumped_text += level_padding + \"\\\"\" + item + \"\\\" : \" + value ;\n          }else{\n            dumped_text += level_padding + \"\\\"\" + item + \"\\\" : \\\"\" + value + \"\\\"\";\n          }\n        }\n        if (i < Object.getOwnPropertyNames(arr).length - 1) {\n          dumped_text += \", \\n\";\n        } else {\n          dumped_text += \" \\n\";\n        }\n        i++;\n      }\n    } else { //Stings/Chars/Numbers etc. \n      dumped_text = \"===>\" + arr + \"<===(\" + typeof(arr) + \")\";\n    }\n    return dumped_text;\n  }\n\n  /*保存*/\n  $(\"#save\").click(function() {\n    var page_id = $(\"#page_id\").val();\n    var item_id = $(\"#item_id\").val();\n    var page_title = $(\"#page_title\").val();\n    var page_comments = $(\"#page_comments\").val();\n    var page_content = $(\"#page_content\").val();\n    var item_id = $(\"#item_id\").val();\n    var s_number = $(\"#s_number\").val();\n    var cat_id = $(\"#cat_id\").val();\n    var parent_cat_id = $(\"#parent_cat_id\").val();\n    if (parent_cat_id > 0) {\n      cat_id = parent_cat_id;\n    };\n    $(\"#save\").html('保存中...').attr('disabled','disabled');\n    $.post(\n      DocConfig.server+\"/api/page/save\", {\n        \"page_id\": page_id,\n        \"cat_id\": cat_id,\n        \"s_number\": s_number,\n        \"page_content\": page_content,\n        \"page_title\": page_title,\n        \"page_comments\": page_comments,\n        \"item_id\": item_id\n      },\n      function(data) {\n        if (data.error_code == 0) {\n          localStorage.removeItem(\"page_content\");\n          window.location.href = \"?s=home/item/show&page_id=\" + data.data.page_id + \"&item_id=\" + item_id;\n        } else {\n          $.alert(lang[\"save_fail\"]);\n          $(\"#save\").html('保存').removeAttr('disabled');\n\n        }\n      },\n      'json'\n    )\n  });\n\n\n\n  $(\".editormd-preview-container\").bind('DOMNodeInserted', function(e) {\n\n    $(\".editormd-preview-container table thead tr\").css({\n      \"background-color\": \"#08c\",\n      \"color\": \"#fff\"\n    });\n    $(\".editormd-preview-container table tr\").eq(0).css({\n      \"background-color\": \"#08c\",\n      \"color\": \"#fff\"\n    });\n    $(\".editormd-preview-container table tr\").each(function() {\n      if ($(this).find(\"td\").eq(1).html() == \"object\" || $(this).find(\"td\").eq(1).html() == \"array[object]\") {\n        $(this).css({\n          \"background-color\": \"#99CC99\",\n          \"color\": \"#000\"\n        });\n      }\n\n    });\n  });\n\n  function closeDiv(target) {\n    $(target).hide();\n  }\n\n  function Change(data) {\n    var level_str = \"- \";\n    if (arguments.length > 1) {\n      var level;\n      arguments[1] > 0 ? level = arguments[1] : level = 1;\n      for (var i = 0; i < level; i++) {\n        level_str += \"- \";\n      }\n    }\n\n    for (var key in data) {\n      var value = data[key];\n      var type = typeof(value);\n      if (type == \"object\") {\n        json_table_data += '| ' + level_str + key + ' |' + type + '  | ' + lang[\"none\"] + ' |\\n';\n        if (value instanceof Array) {\n          var j = level + 1;\n          Change(value[0], j);\n          continue;\n        }\n        //else\n        //{\n        Change(value, level);\n        //}\n\n      } else {\n        json_table_data += '| ' + key + ' | ' + type + '| ' + lang[\"none\"] + ' |\\n';\n      }\n    }\n  }\n\n  //{\"Result\":[{\"name\":\"test1\",\"list\":{\"pros\":\"prosfsf\",\"ppps\":{\"images\":[{\"22\":\"22\"}]}}}]}\n\n  $(\"#save-to-templ\").click(function() {\n    $.prompt({\n      title: lang[\"save_templ_title\"]\n    }, function(template_title, index) {\n      if (template_title != null && template_title != \"\") {\n        var template_content = $(\"#page_content\").val();\n        $.post(\n          \"?s=home/template/save\", {\n            \"template_title\": template_title,\n            \"template_content\": template_content\n          },\n          function(data) {\n            if (data.error_code == 0) {\n              $.closeDialog(index);\n              $.alert(lang[\"saved_templ_msg1\"] + template_title + lang[\"saved_templ_msg2\"]);\n            } else {\n              $.alert(lang[\"save_fail\"]);\n\n            }\n          },\n          \"json\"\n        );\n      }\n      $(\"#save-btn-group\").removeClass(\"open\");\n      return false;\n    });\n  });\n\n  $(\"#more-templ\").click(function() {\n    $.post(\n      \"?s=home/template/getList\", {},\n      function(data) {\n        if (data.error_code == 0) {\n          var html = '<TR><td>' + lang[\"save_time\"] + '</td><td>' + lang[\"templ_title\"] + '</td><td>' + lang[\"operation\"] + '</td></TR>';\n          template_list = data.data;\n          json = data.data;\n          for (var i = 0; i < json.length; i++) {\n            html += '<TR><td>' + json[i]['addtime'] + '</td>';\n            html += '<td>' + json[i]['template_title'] + '</td>';\n            html += '<td><a href=\"javascript:use_template(' + json[i]['id'] + ')\">' + lang[\"use_this_template\"] + '</a> | <a href=\"javascript:delete_template(' + json[i]['id'] + ')\">' + lang[\"delete_this_template\"] + '</a></td>';\n            html += '</TR>';\n          };\n          $(\"#templ-table\").html(html);\n          $(\"#more-templ-modal\").modal();\n        } else {\n          //$.alert(\"获取模板列表失败\");\n          $(\"#more-templ-modal\").modal(\"hide\");\n          $.alert(lang[\"no_templ_msg\"]);\n\n        }\n      },\n      \"json\"\n    );\n\n  });\n\n  $(\"#add-page-comments\").click(function() {\n    var page_comments = prompt(lang[\"add_page_comments_msg\"], \"\");\n    if (page_comments != null && page_comments != \"\") {\n      $(\"#page_comments\").val(page_comments);\n      $(\"#save\").click();\n    }\n    $(\"#save-btn-group\").removeClass(\"open\");\n    return false;\n  });\n\n  /** 粘贴上传图片 **/\n  document.getElementById(\"editormd\").addEventListener('paste', function(e) {\n    var clipboard = e.clipboardData;\n    for (var i = 0, len = clipboard.items.length; i < len; i++) {\n      if (clipboard.items[i].kind == 'file' || clipboard.items[i].type.indexOf('image') > -1) {\n        var imageFile = clipboard.items[i].getAsFile();\n        var form = new FormData;\n        form.append('t', 'ajax-uploadpic');\n        form.append('editormd-image-file', imageFile);\n        var layer_index = {};\n        var callback = function(type, data) {\n          type = type || 'before';\n          var $the = $('#content');\n          switch (type) {\n            // 开始上传\n            case 'before':\n              layer_index = layer.load(1, {\n                shade: [0.1, '#fff'] //0.1透明度的白色背景\n              });\n              break;\n              // 服务器返回错误\n            case 'error':\n              $the.attr('disabled', false);\n              $.closeDialog(layer_index);\n              $.alert('图片上传失败');\n              break;\n              // 上传成功\n            case 'success':\n              $the.attr('disabled', false);\n              $.closeDialog(layer_index);\n              if (data.success == 1) {\n                var value = '![](' + data.url + ')';\n                editormd.insertValue(value);\n              } else {\n                $.alert(data.message);\n              }\n\n              break;\n          }\n        };\n        $.ajax({\n          url: \"?s=home/page/uploadImg\",\n          type: \"POST\",\n          dataType: \"json\",\n          data: form,\n          processData: false,\n          contentType: false,\n          beforeSend: function() {\n            callback('before');\n          },\n          error: function() {\n            callback('error');\n          },\n          success: function(data) {\n            callback('success', data);\n          }\n        })\n        e.preventDefault();\n      }\n    }\n  });\n\n  //更改选择文件框的文件类型让它更快地弹出\n  $(\"#editormd\").on(\"mouseover\", '[name=editormd-image-file]', function(){\n    $(this).attr(\"accept\",\"image/png,image/jpg,image/jpeg,imge/bmp,image/gif\")\n  });\n\n  //定时保存文本内容到localStorage\n  setInterval(function(){\n      localStorage.page_content= $(\"#page_content\").val() ;\n  }, 60000);\n\n  //检测是否有定时保存的内容\n  if (localStorage.page_content && localStorage.page_content.length > 0) {\n    $.confirm(\"检测到有上次编辑时自动保存的草稿。是否自动填充上次的草稿内容？\",\n      {},\n      function(){\n        editormd.clear();\n        editormd.insertValue(localStorage.page_content);\n        $.closeAll();\n        localStorage.removeItem(\"page_content\");\n      },\n      function(){\n        localStorage.removeItem(\"page_content\");\n      }\n\n    )\n  };\n\n  \n});\n\n  //使用模板\n  function use_template(id) {\n    for (var i = 0; i < template_list.length; i++) {\n      if (id > 0 && id == template_list[i]['id']) {\n        editormd.insertValue(template_list[i]['template_content']);\n        $(\"#more-templ-modal\").modal(\"hide\");\n      };\n\n    };\n  }\n\n  //删除模板\n  function delete_template(id) {\n    $.post(\n      \"?s=home/template/delete\", {\n        \"id\": id\n      },\n      function(data) {\n        if (data.error_code == 0) {\n          $(\"#more-templ\").click();\n        } else {\n          $.alert(lang[\"save_fail\"]);\n        }\n      },\n      \"json\"\n    );\n  }\n"
  },
  {
    "path": "Public/js/page/index.js",
    "content": "\n$(function(){\n\n  var page_id = $(\"#page_id\").val() ;\n\n  layer_index = layer.load(1, {\n    shade: [0.1, '#fff'] //0.1透明度的白色背景\n  });\n\n    $.ajax({ \n        type: \"get\", \n        url: DocConfig.server+\"/api/page/info&page_id=\"+page_id, \n        cache:false, \n        async:false, \n        dataType:  \"json\" , \n        success: function(data){ \n          if (data.error_code === 0 ) {\n            $(\"#page_md_content textarea\").html(data.data.page_content);\n            $(\"#page_title\").html(data.data.page_title);\n            $(\"#doc-title\").html(data.data.page_title);\n          }else{\n            $.alert(data.error_message)\n          }\n          layer.closeAll();\n        } \n\n    });\n\n    hljs.initHighlightingOnLoad();\n    \n    var EditormdView = editormd.markdownToHTML(\"page_md_content\", {\n      htmlDecode      : \"style,script,iframe|filterXSS\",  // you can filter tags decode\n      emoji           : false,\n      taskList        : true,\n      tex             : true,  // 默认不解析\n      flowChart       : true,  // 默认不解析\n      sequenceDiagram : true,  // 默认不解析\n    });\n\n    //为所有table标签添加bootstap支持的表格类\n    $(\"table\").addClass(\"table table-bordered table-hover\");\n    $.each($('table'), function() {\n        $(this).prop('outerHTML', '<div style=\"width: 100%;overflow-x: auto;\">'+$(this).prop('outerHTML')+'</div>');\n    });\n\n      //不是本项目的超链接都在新窗口打开\n    $('a[href^=\"http\"]').each(function() {\n          $(this).attr('target', '_blank');\n          $(this).click(function(){\n            var target_url = $(this).attr(\"href\") ;\n            if (target_url.indexOf(window.top.location.host + window.top.location.pathname) > -1 ){\n                window.top.location.href = target_url;\n                return false;\n            }\n            \n          });\n\n    });\n\n    if (!isMobile()) {\n      $(\"th\").css(\"min-width\",\"77px\");\n    };\n\n    $(\"table thead tr\").css({\"background-color\":\"#08c\",\"color\":\"#fff\"});\n    $(\"table tr\").each(function(){\n    if($(this).find(\"td\").eq(1).html()==\"object\" || $(this).find(\"td\").eq(1).html()==\"array[object]\")\n    {\n      $(this).css({\"background-color\":\"#99CC99\",\"color\":\"#000\"});\n    }\n\n    });\n    \n    //图片点击放大\n    $(\"#page_md_content img\").click(function(){\n      var  img_url = $(this).attr(\"src\");\n      //如果不在iframe里，则直接当前窗口打开\n      if (self == top) {\n          var json = {\n              \"title\": \"\", //相册标题\n              \"id\": 123, //相册id\n              \"start\": 0, //初始显示的图片序号，默认0\n              \"data\": [   //相册包含的图片，数组格式\n                  {\n                    \"alt\": \"\",\n                    \"pid\": 666, //图片id\n                    \"src\": img_url, //原图地址\n                    \"thumb\": img_url //缩略图地址\n                  }\n                ]\n              }\n\n            layer.photos({\n              photos: json\n              ,anim: 5 //0-6的选择，指定弹出图片动画类型，默认随机（请注意，3.0之前的版本用shift参数）\n            });\n\n      }else{\n        //如果在iframe里，则直接传url给父窗口\n        var message ={\"img_url\":img_url,\"meessage_type\":\"img_url\"};\n        top.postMessage(message, window.location.origin);\n      }\n\n    });\n\n})\n"
  },
  {
    "path": "Public/layer/layer.js",
    "content": "/*! layer-v3.0.1 Web弹层组件 MIT License  http://layer.layui.com/  By 贤心 */\n ;!function(e,t){\"use strict\";var i,n,a=e.layui&&layui.define,o={getPath:function(){var e=document.scripts,t=e[e.length-1],i=t.src;if(!t.getAttribute(\"merge\"))return i.substring(0,i.lastIndexOf(\"/\")+1)}(),config:{},end:{},minIndex:0,minLeft:[],btn:[\"&#x786E;&#x5B9A;\",\"&#x53D6;&#x6D88;\"],type:[\"dialog\",\"page\",\"iframe\",\"loading\",\"tips\"]},r={v:\"3.0.1\",ie:function(){var t=navigator.userAgent.toLowerCase();return!!(e.ActiveXObject||\"ActiveXObject\"in e)&&((t.match(/msie\\s(\\d+)/)||[])[1]||\"11\")}(),index:e.layer&&e.layer.v?1e5:0,path:o.getPath,config:function(e,t){return e=e||{},r.cache=o.config=i.extend({},o.config,e),r.path=o.config.path||r.path,\"string\"==typeof e.extend&&(e.extend=[e.extend]),o.config.path&&r.ready(),e.extend?(a?layui.addcss(\"modules/layer/\"+e.extend):r.link(\"skin/\"+e.extend),this):this},link:function(t,n,a){if(r.path){var o=i(\"head\")[0],l=document.createElement(\"link\");\"string\"==typeof n&&(a=n);var s=(a||t).replace(/\\.|\\//g,\"\"),f=\"layuicss-\"+s,c=0;l.rel=\"stylesheet\",l.href=r.path+t,l.id=f,i(\"#\"+f)[0]||o.appendChild(l),\"function\"==typeof n&&!function d(){return++c>80?e.console&&console.error(\"layer.css: Invalid\"):void(1989===parseInt(i(\"#\"+f).css(\"width\"))?n():setTimeout(d,100))}()}},ready:function(e){var t=\"skinlayercss\",i=\"1110\";return a?layui.addcss(\"modules/layer/default/layer.css?v=\"+r.v+i,e,t):r.link(\"skin/default/layer.css?v=\"+r.v+i,e,t),this},alert:function(e,t,n){var a=\"function\"==typeof t;return a&&(n=t),r.open(i.extend({content:e,yes:n},a?{}:t))},confirm:function(e,t,n,a){var l=\"function\"==typeof t;return l&&(a=n,n=t),r.open(i.extend({content:e,btn:o.btn,yes:n,btn2:a},l?{}:t))},msg:function(e,n,a){var l=\"function\"==typeof n,f=o.config.skin,c=(f?f+\" \"+f+\"-msg\":\"\")||\"layui-layer-msg\",d=s.anim.length-1;return l&&(a=n),r.open(i.extend({content:e,time:3e3,shade:!1,skin:c,title:!1,closeBtn:!1,btn:!1,resize:!1,end:a},l&&!o.config.skin?{skin:c+\" layui-layer-hui\",anim:d}:function(){return n=n||{},(n.icon===-1||n.icon===t&&!o.config.skin)&&(n.skin=c+\" \"+(n.skin||\"layui-layer-hui\")),n}()))},load:function(e,t){return r.open(i.extend({type:3,icon:e||0,resize:!1,shade:.01},t))},tips:function(e,t,n){return r.open(i.extend({type:4,content:[e,t],closeBtn:!1,time:3e3,shade:!1,resize:!1,fixed:!1,maxWidth:210},n))}},l=function(e){var t=this;t.index=++r.index,t.config=i.extend({},t.config,o.config,e),document.body?t.creat():setTimeout(function(){t.creat()},50)};l.pt=l.prototype;var s=[\"layui-layer\",\".layui-layer-title\",\".layui-layer-main\",\".layui-layer-dialog\",\"layui-layer-iframe\",\"layui-layer-content\",\"layui-layer-btn\",\"layui-layer-close\"];s.anim=[\"layer-anim\",\"layer-anim-01\",\"layer-anim-02\",\"layer-anim-03\",\"layer-anim-04\",\"layer-anim-05\",\"layer-anim-06\"],l.pt.config={type:0,shade:.3,fixed:!0,move:s[1],title:\"&#x4FE1;&#x606F;\",offset:\"auto\",area:\"auto\",closeBtn:1,time:0,zIndex:19891014,maxWidth:360,anim:0,icon:-1,moveType:1,resize:!0,scrollbar:!0,tips:2},l.pt.vessel=function(e,t){var n=this,a=n.index,r=n.config,l=r.zIndex+a,f=\"object\"==typeof r.title,c=r.maxmin&&(1===r.type||2===r.type),d=r.title?'<div class=\"layui-layer-title\" style=\"'+(f?r.title[1]:\"\")+'\">'+(f?r.title[0]:r.title)+\"</div>\":\"\";return r.zIndex=l,t([r.shade?'<div class=\"layui-layer-shade\" id=\"layui-layer-shade'+a+'\" times=\"'+a+'\" style=\"'+(\"z-index:\"+(l-1)+\"; background-color:\"+(r.shade[1]||\"#000\")+\"; opacity:\"+(r.shade[0]||r.shade)+\"; filter:alpha(opacity=\"+(100*r.shade[0]||100*r.shade)+\");\")+'\"></div>':\"\",'<div class=\"'+s[0]+(\" layui-layer-\"+o.type[r.type])+(0!=r.type&&2!=r.type||r.shade?\"\":\" layui-layer-border\")+\" \"+(r.skin||\"\")+'\" id=\"'+s[0]+a+'\" type=\"'+o.type[r.type]+'\" times=\"'+a+'\" showtime=\"'+r.time+'\" conType=\"'+(e?\"object\":\"string\")+'\" style=\"z-index: '+l+\"; width:\"+r.area[0]+\";height:\"+r.area[1]+(r.fixed?\"\":\";position:absolute;\")+'\">'+(e&&2!=r.type?\"\":d)+'<div id=\"'+(r.id||\"\")+'\" class=\"layui-layer-content'+(0==r.type&&r.icon!==-1?\" layui-layer-padding\":\"\")+(3==r.type?\" layui-layer-loading\"+r.icon:\"\")+'\">'+(0==r.type&&r.icon!==-1?'<i class=\"layui-layer-ico layui-layer-ico'+r.icon+'\"></i>':\"\")+(1==r.type&&e?\"\":r.content||\"\")+'</div><span class=\"layui-layer-setwin\">'+function(){var e=c?'<a class=\"layui-layer-min\" href=\"javascript:;\"><cite></cite></a><a class=\"layui-layer-ico layui-layer-max\" href=\"javascript:;\"></a>':\"\";return r.closeBtn&&(e+='<a class=\"layui-layer-ico '+s[7]+\" \"+s[7]+(r.title?r.closeBtn:4==r.type?\"1\":\"2\")+'\" href=\"javascript:;\"></a>'),e}()+\"</span>\"+(r.btn?function(){var e=\"\";\"string\"==typeof r.btn&&(r.btn=[r.btn]);for(var t=0,i=r.btn.length;t<i;t++)e+='<a class=\"'+s[6]+t+'\">'+r.btn[t]+\"</a>\";return'<div class=\"'+s[6]+\" layui-layer-btn-\"+(r.btnAlign||\"\")+'\">'+e+\"</div>\"}():\"\")+(r.resize?'<span class=\"layui-layer-resize\"></span>':\"\")+\"</div>\"],d,i('<div class=\"layui-layer-move\"></div>')),n},l.pt.creat=function(){var e=this,t=e.config,a=e.index,l=t.content,f=\"object\"==typeof l,c=i(\"body\");if(!i(\"#\"+t.id)[0]){switch(\"string\"==typeof t.area&&(t.area=\"auto\"===t.area?[\"\",\"\"]:[t.area,\"\"]),t.shift&&(t.anim=t.shift),6==r.ie&&(t.fixed=!1),t.type){case 0:t.btn=\"btn\"in t?t.btn:o.btn[0],r.closeAll(\"dialog\");break;case 2:var l=t.content=f?t.content:[t.content||\"http://layer.layui.com\",\"auto\"];t.content='<iframe scrolling=\"'+(t.content[1]||\"auto\")+'\" allowtransparency=\"true\" id=\"'+s[4]+a+'\" name=\"'+s[4]+a+'\" onload=\"this.className=\\'\\';\" class=\"layui-layer-load\" frameborder=\"0\" src=\"'+t.content[0]+'\"></iframe>';break;case 3:delete t.title,delete t.closeBtn,t.icon===-1&&0===t.icon,r.closeAll(\"loading\");break;case 4:f||(t.content=[t.content,\"body\"]),t.follow=t.content[1],t.content=t.content[0]+'<i class=\"layui-layer-TipsG\"></i>',delete t.title,t.tips=\"object\"==typeof t.tips?t.tips:[t.tips,!0],t.tipsMore||r.closeAll(\"tips\")}e.vessel(f,function(n,r,d){c.append(n[0]),f?function(){2==t.type||4==t.type?function(){i(\"body\").append(n[1])}():function(){l.parents(\".\"+s[0])[0]||(l.data(\"display\",l.css(\"display\")).show().addClass(\"layui-layer-wrap\").wrap(n[1]),i(\"#\"+s[0]+a).find(\".\"+s[5]).before(r))}()}():c.append(n[1]),i(\".layui-layer-move\")[0]||c.append(o.moveElem=d),e.layero=i(\"#\"+s[0]+a),t.scrollbar||s.html.css(\"overflow\",\"hidden\").attr(\"layer-full\",a)}).auto(a),2==t.type&&6==r.ie&&e.layero.find(\"iframe\").attr(\"src\",l[0]),4==t.type?e.tips():e.offset(),t.fixed&&n.on(\"resize\",function(){e.offset(),(/^\\d+%$/.test(t.area[0])||/^\\d+%$/.test(t.area[1]))&&e.auto(a),4==t.type&&e.tips()}),t.time<=0||setTimeout(function(){r.close(e.index)},t.time),e.move().callback(),s.anim[t.anim]&&e.layero.addClass(s.anim[t.anim]).data(\"anim\",!0)}},l.pt.auto=function(e){function t(e){e=l.find(e),e.height(f[1]-c-d-2*(0|parseFloat(e.css(\"padding\"))))}var a=this,o=a.config,l=i(\"#\"+s[0]+e);\"\"===o.area[0]&&o.maxWidth>0&&(r.ie&&r.ie<8&&o.btn&&l.width(l.innerWidth()),l.outerWidth()>o.maxWidth&&l.width(o.maxWidth));var f=[l.innerWidth(),l.innerHeight()],c=l.find(s[1]).outerHeight()||0,d=l.find(\".\"+s[6]).outerHeight()||0;switch(o.type){case 2:t(\"iframe\");break;default:\"\"===o.area[1]?o.fixed&&f[1]>=n.height()&&(f[1]=n.height(),t(\".\"+s[5])):t(\".\"+s[5])}return a},l.pt.offset=function(){var e=this,t=e.config,i=e.layero,a=[i.outerWidth(),i.outerHeight()],o=\"object\"==typeof t.offset;e.offsetTop=(n.height()-a[1])/2,e.offsetLeft=(n.width()-a[0])/2,o?(e.offsetTop=t.offset[0],e.offsetLeft=t.offset[1]||e.offsetLeft):\"auto\"!==t.offset&&(\"t\"===t.offset?e.offsetTop=0:\"r\"===t.offset?e.offsetLeft=n.width()-a[0]:\"b\"===t.offset?e.offsetTop=n.height()-a[1]:\"l\"===t.offset?e.offsetLeft=0:\"lt\"===t.offset?(e.offsetTop=0,e.offsetLeft=0):\"lb\"===t.offset?(e.offsetTop=n.height()-a[1],e.offsetLeft=0):\"rt\"===t.offset?(e.offsetTop=0,e.offsetLeft=n.width()-a[0]):\"rb\"===t.offset?(e.offsetTop=n.height()-a[1],e.offsetLeft=n.width()-a[0]):e.offsetTop=t.offset),t.fixed||(e.offsetTop=/%$/.test(e.offsetTop)?n.height()*parseFloat(e.offsetTop)/100:parseFloat(e.offsetTop),e.offsetLeft=/%$/.test(e.offsetLeft)?n.width()*parseFloat(e.offsetLeft)/100:parseFloat(e.offsetLeft),e.offsetTop+=n.scrollTop(),e.offsetLeft+=n.scrollLeft()),i.attr(\"minLeft\")&&(e.offsetTop=n.height()-(i.find(s[1]).outerHeight()||0),e.offsetLeft=i.css(\"left\")),i.css({top:e.offsetTop,left:e.offsetLeft})},l.pt.tips=function(){var e=this,t=e.config,a=e.layero,o=[a.outerWidth(),a.outerHeight()],r=i(t.follow);r[0]||(r=i(\"body\"));var l={width:r.outerWidth(),height:r.outerHeight(),top:r.offset().top,left:r.offset().left},f=a.find(\".layui-layer-TipsG\"),c=t.tips[0];t.tips[1]||f.remove(),l.autoLeft=function(){l.left+o[0]-n.width()>0?(l.tipLeft=l.left+l.width-o[0],f.css({right:12,left:\"auto\"})):l.tipLeft=l.left},l.where=[function(){l.autoLeft(),l.tipTop=l.top-o[1]-10,f.removeClass(\"layui-layer-TipsB\").addClass(\"layui-layer-TipsT\").css(\"border-right-color\",t.tips[1])},function(){l.tipLeft=l.left+l.width+10,l.tipTop=l.top,f.removeClass(\"layui-layer-TipsL\").addClass(\"layui-layer-TipsR\").css(\"border-bottom-color\",t.tips[1])},function(){l.autoLeft(),l.tipTop=l.top+l.height+10,f.removeClass(\"layui-layer-TipsT\").addClass(\"layui-layer-TipsB\").css(\"border-right-color\",t.tips[1])},function(){l.tipLeft=l.left-o[0]-10,l.tipTop=l.top,f.removeClass(\"layui-layer-TipsR\").addClass(\"layui-layer-TipsL\").css(\"border-bottom-color\",t.tips[1])}],l.where[c-1](),1===c?l.top-(n.scrollTop()+o[1]+16)<0&&l.where[2]():2===c?n.width()-(l.left+l.width+o[0]+16)>0||l.where[3]():3===c?l.top-n.scrollTop()+l.height+o[1]+16-n.height()>0&&l.where[0]():4===c&&o[0]+16-l.left>0&&l.where[1](),a.find(\".\"+s[5]).css({\"background-color\":t.tips[1],\"padding-right\":t.closeBtn?\"30px\":\"\"}),a.css({left:l.tipLeft-(t.fixed?n.scrollLeft():0),top:l.tipTop-(t.fixed?n.scrollTop():0)})},l.pt.move=function(){var e=this,t=e.config,a=i(document),l=e.layero,s=l.find(t.move),f=l.find(\".layui-layer-resize\"),c={};return t.move&&s.css(\"cursor\",\"move\"),s.on(\"mousedown\",function(e){e.preventDefault(),t.move&&(c.moveStart=!0,c.offset=[e.clientX-parseFloat(l.css(\"left\")),e.clientY-parseFloat(l.css(\"top\"))],o.moveElem.css(\"cursor\",\"move\").show())}),f.on(\"mousedown\",function(e){e.preventDefault(),c.resizeStart=!0,c.offset=[e.clientX,e.clientY],c.area=[l.outerWidth(),l.outerHeight()],o.moveElem.css(\"cursor\",\"se-resize\").show()}),a.on(\"mousemove\",function(i){if(c.moveStart){var a=i.clientX-c.offset[0],o=i.clientY-c.offset[1],s=\"fixed\"===l.css(\"position\");if(i.preventDefault(),c.stX=s?0:n.scrollLeft(),c.stY=s?0:n.scrollTop(),!t.moveOut){var f=n.width()-l.outerWidth()+c.stX,d=n.height()-l.outerHeight()+c.stY;a<c.stX&&(a=c.stX),a>f&&(a=f),o<c.stY&&(o=c.stY),o>d&&(o=d)}l.css({left:a,top:o})}if(t.resize&&c.resizeStart){var a=i.clientX-c.offset[0],o=i.clientY-c.offset[1];i.preventDefault(),r.style(e.index,{width:c.area[0]+a,height:c.area[1]+o}),c.isResize=!0}}).on(\"mouseup\",function(e){c.moveStart&&(delete c.moveStart,o.moveElem.hide(),t.moveEnd&&t.moveEnd()),c.resizeStart&&(delete c.resizeStart,o.moveElem.hide())}),e},l.pt.callback=function(){function e(){var e=a.cancel&&a.cancel(t.index,n);e===!1||r.close(t.index)}var t=this,n=t.layero,a=t.config;t.openLayer(),a.success&&(2==a.type?n.find(\"iframe\").on(\"load\",function(){a.success(n,t.index)}):a.success(n,t.index)),6==r.ie&&t.IE6(n),n.find(\".\"+s[6]).children(\"a\").on(\"click\",function(){var e=i(this).index();if(0===e)a.yes?a.yes(t.index,n):a.btn1?a.btn1(t.index,n):r.close(t.index);else{var o=a[\"btn\"+(e+1)]&&a[\"btn\"+(e+1)](t.index,n);o===!1||r.close(t.index)}}),n.find(\".\"+s[7]).on(\"click\",e),a.shadeClose&&i(\"#layui-layer-shade\"+t.index).on(\"click\",function(){r.close(t.index)}),n.find(\".layui-layer-min\").on(\"click\",function(){var e=a.min&&a.min(n);e===!1||r.min(t.index,a)}),n.find(\".layui-layer-max\").on(\"click\",function(){i(this).hasClass(\"layui-layer-maxmin\")?(r.restore(t.index),a.restore&&a.restore(n)):(r.full(t.index,a),setTimeout(function(){a.full&&a.full(n)},100))}),a.end&&(o.end[t.index]=a.end)},o.reselect=function(){i.each(i(\"select\"),function(e,t){var n=i(this);n.parents(\".\"+s[0])[0]||1==n.attr(\"layer\")&&i(\".\"+s[0]).length<1&&n.removeAttr(\"layer\").show(),n=null})},l.pt.IE6=function(e){i(\"select\").each(function(e,t){var n=i(this);n.parents(\".\"+s[0])[0]||\"none\"===n.css(\"display\")||n.attr({layer:\"1\"}).hide(),n=null})},l.pt.openLayer=function(){var e=this;r.zIndex=e.config.zIndex,r.setTop=function(e){var t=function(){r.zIndex++,e.css(\"z-index\",r.zIndex+1)};return r.zIndex=parseInt(e[0].style.zIndex),e.on(\"mousedown\",t),r.zIndex}},o.record=function(e){var t=[e.width(),e.height(),e.position().top,e.position().left+parseFloat(e.css(\"margin-left\"))];e.find(\".layui-layer-max\").addClass(\"layui-layer-maxmin\"),e.attr({area:t})},o.rescollbar=function(e){s.html.attr(\"layer-full\")==e&&(s.html[0].style.removeProperty?s.html[0].style.removeProperty(\"overflow\"):s.html[0].style.removeAttribute(\"overflow\"),s.html.removeAttr(\"layer-full\"))},e.layer=r,r.getChildFrame=function(e,t){return t=t||i(\".\"+s[4]).attr(\"times\"),i(\"#\"+s[0]+t).find(\"iframe\").contents().find(e)},r.getFrameIndex=function(e){return i(\"#\"+e).parents(\".\"+s[4]).attr(\"times\")},r.iframeAuto=function(e){if(e){var t=r.getChildFrame(\"html\",e).outerHeight(),n=i(\"#\"+s[0]+e),a=n.find(s[1]).outerHeight()||0,o=n.find(\".\"+s[6]).outerHeight()||0;n.css({height:t+a+o}),n.find(\"iframe\").css({height:t})}},r.iframeSrc=function(e,t){i(\"#\"+s[0]+e).find(\"iframe\").attr(\"src\",t)},r.style=function(e,t,n){var a=i(\"#\"+s[0]+e),r=a.find(\".layui-layer-content\"),l=a.attr(\"type\"),f=a.find(s[1]).outerHeight()||0,c=a.find(\".\"+s[6]).outerHeight()||0;a.attr(\"minLeft\");l!==o.type[3]&&l!==o.type[4]&&(n||(parseFloat(t.width)<=260&&(t.width=260),parseFloat(t.height)-f-c<=64&&(t.height=64+f+c)),a.css(t),c=a.find(\".\"+s[6]).outerHeight(),l===o.type[2]?a.find(\"iframe\").css({height:parseFloat(t.height)-f-c}):r.css({height:parseFloat(t.height)-f-c-parseFloat(r.css(\"padding-top\"))-parseFloat(r.css(\"padding-bottom\"))}))},r.min=function(e,t){var a=i(\"#\"+s[0]+e),l=a.find(s[1]).outerHeight()||0,f=a.attr(\"minLeft\")||181*o.minIndex+\"px\",c=a.css(\"position\");o.record(a),o.minLeft[0]&&(f=o.minLeft[0],o.minLeft.shift()),a.attr(\"position\",c),r.style(e,{width:180,height:l,left:f,top:n.height()-l,position:\"fixed\",overflow:\"hidden\"},!0),a.find(\".layui-layer-min\").hide(),\"page\"===a.attr(\"type\")&&a.find(s[4]).hide(),o.rescollbar(e),a.attr(\"minLeft\")||o.minIndex++,a.attr(\"minLeft\",f)},r.restore=function(e){var t=i(\"#\"+s[0]+e),n=t.attr(\"area\").split(\",\");t.attr(\"type\");r.style(e,{width:parseFloat(n[0]),height:parseFloat(n[1]),top:parseFloat(n[2]),left:parseFloat(n[3]),position:t.attr(\"position\"),overflow:\"visible\"},!0),t.find(\".layui-layer-max\").removeClass(\"layui-layer-maxmin\"),t.find(\".layui-layer-min\").show(),\"page\"===t.attr(\"type\")&&t.find(s[4]).show(),o.rescollbar(e)},r.full=function(e){var t,a=i(\"#\"+s[0]+e);o.record(a),s.html.attr(\"layer-full\")||s.html.css(\"overflow\",\"hidden\").attr(\"layer-full\",e),clearTimeout(t),t=setTimeout(function(){var t=\"fixed\"===a.css(\"position\");r.style(e,{top:t?0:n.scrollTop(),left:t?0:n.scrollLeft(),width:n.width(),height:n.height()},!0),a.find(\".layui-layer-min\").hide()},100)},r.title=function(e,t){var n=i(\"#\"+s[0]+(t||r.index)).find(s[1]);n.html(e)},r.close=function(e){var t=i(\"#\"+s[0]+e),n=t.attr(\"type\"),a=\"layer-anim-close\";if(t[0]){var l=\"layui-layer-wrap\",f=function(){if(n===o.type[1]&&\"object\"===t.attr(\"conType\")){t.children(\":not(.\"+s[5]+\")\").remove();for(var a=t.find(\".\"+l),r=0;r<2;r++)a.unwrap();a.css(\"display\",a.data(\"display\")).removeClass(l)}else{if(n===o.type[2])try{var f=i(\"#\"+s[4]+e)[0];f.contentWindow.document.write(\"\"),f.contentWindow.close(),t.find(\".\"+s[5])[0].removeChild(f)}catch(c){}t[0].innerHTML=\"\",t.remove()}\"function\"==typeof o.end[e]&&o.end[e](),delete o.end[e]};t.data(\"anim\")&&t.addClass(a),i(\"#layui-layer-moves, #layui-layer-shade\"+e).remove(),6==r.ie&&o.reselect(),o.rescollbar(e),t.attr(\"minLeft\")&&(o.minIndex--,o.minLeft.push(t.attr(\"minLeft\"))),setTimeout(function(){f()},r.ie&&r.ie<10||!t.data(\"anim\")?0:200)}},r.closeAll=function(e){i.each(i(\".\"+s[0]),function(){var t=i(this),n=e?t.attr(\"type\")===e:1;n&&r.close(t.attr(\"times\")),n=null})};var f=r.cache||{},c=function(e){return f.skin?\" \"+f.skin+\" \"+f.skin+\"-\"+e:\"\"};r.prompt=function(e,t){var a=\"\";if(e=e||{},\"function\"==typeof e&&(t=e),e.area){var o=e.area;a='style=\"width: '+o[0]+\"; height: \"+o[1]+';\"',delete e.area}var l,s=2==e.formType?'<textarea class=\"layui-layer-input\"'+a+\">\"+(e.value||\"\")+\"</textarea>\":function(){return'<input type=\"'+(1==e.formType?\"password\":\"text\")+'\" class=\"layui-layer-input\" value=\"'+(e.value||\"\")+'\">'}();return r.open(i.extend({type:1,btn:[\"&#x786E;&#x5B9A;\",\"&#x53D6;&#x6D88;\"],content:s,skin:\"layui-layer-prompt\"+c(\"prompt\"),maxWidth:n.width(),success:function(e){l=e.find(\".layui-layer-input\"),l.focus()},resize:!1,yes:function(i){var n=l.val();\"\"===n?l.focus():n.length>(e.maxlength||500)?r.tips(\"&#x6700;&#x591A;&#x8F93;&#x5165;\"+(e.maxlength||500)+\"&#x4E2A;&#x5B57;&#x6570;\",l,{tips:1}):t&&t(n,i,l)}},e))},r.tab=function(e){e=e||{};var t=e.tab||{};return r.open(i.extend({type:1,skin:\"layui-layer-tab\"+c(\"tab\"),resize:!1,title:function(){var e=t.length,i=1,n=\"\";if(e>0)for(n='<span class=\"layui-layer-tabnow\">'+t[0].title+\"</span>\";i<e;i++)n+=\"<span>\"+t[i].title+\"</span>\";return n}(),content:'<ul class=\"layui-layer-tabmain\">'+function(){var e=t.length,i=1,n=\"\";if(e>0)for(n='<li class=\"layui-layer-tabli xubox_tab_layer\">'+(t[0].content||\"no content\")+\"</li>\";i<e;i++)n+='<li class=\"layui-layer-tabli\">'+(t[i].content||\"no  content\")+\"</li>\";return n}()+\"</ul>\",success:function(t){var n=t.find(\".layui-layer-title\").children(),a=t.find(\".layui-layer-tabmain\").children();n.on(\"mousedown\",function(t){t.stopPropagation?t.stopPropagation():t.cancelBubble=!0;var n=i(this),o=n.index();n.addClass(\"layui-layer-tabnow\").siblings().removeClass(\"layui-layer-tabnow\"),a.eq(o).show().siblings().hide(),\"function\"==typeof e.change&&e.change(o)})}},e))},r.photos=function(t,n,a){function o(e,t,i){var n=new Image;return n.src=e,n.complete?t(n):(n.onload=function(){n.onload=null,t(n)},void(n.onerror=function(e){n.onerror=null,i(e)}))}var l={};if(t=t||{},t.photos){var s=t.photos.constructor===Object,f=s?t.photos:{},d=f.data||[],u=f.start||0;if(l.imgIndex=(0|u)+1,t.img=t.img||\"img\",s){if(0===d.length)return r.msg(\"&#x6CA1;&#x6709;&#x56FE;&#x7247;\")}else{var y=i(t.photos),p=function(){d=[],y.find(t.img).each(function(e){var t=i(this);t.attr(\"layer-index\",e),d.push({alt:t.attr(\"alt\"),pid:t.attr(\"layer-pid\"),src:t.attr(\"layer-src\")||t.attr(\"src\"),thumb:t.attr(\"src\")})})};if(p(),0===d.length)return;if(n||y.on(\"click\",t.img,function(){var e=i(this),n=e.attr(\"layer-index\");r.photos(i.extend(t,{photos:{start:n,data:d,tab:t.tab},full:t.full}),!0),p()}),!n)return}l.imgprev=function(e){l.imgIndex--,l.imgIndex<1&&(l.imgIndex=d.length),l.tabimg(e)},l.imgnext=function(e,t){l.imgIndex++,l.imgIndex>d.length&&(l.imgIndex=1,t)||l.tabimg(e)},l.keyup=function(e){if(!l.end){var t=e.keyCode;e.preventDefault(),37===t?l.imgprev(!0):39===t?l.imgnext(!0):27===t&&r.close(l.index)}},l.tabimg=function(e){d.length<=1||(f.start=l.imgIndex-1,r.close(l.index),r.photos(t,!0,e))},l.event=function(){l.bigimg.hover(function(){l.imgsee.show()},function(){l.imgsee.hide()}),l.bigimg.find(\".layui-layer-imgprev\").on(\"click\",function(e){e.preventDefault(),l.imgprev()}),l.bigimg.find(\".layui-layer-imgnext\").on(\"click\",function(e){e.preventDefault(),l.imgnext()}),i(document).on(\"keyup\",l.keyup)},l.loadi=r.load(1,{shade:!(\"shade\"in t)&&.9,scrollbar:!1}),o(d[u].src,function(n){r.close(l.loadi),l.index=r.open(i.extend({type:1,area:function(){var a=[n.width,n.height],o=[i(e).width()-100,i(e).height()-100];if(!t.full&&(a[0]>o[0]||a[1]>o[1])){var r=[a[0]/o[0],a[1]/o[1]];r[0]>r[1]?(a[0]=a[0]/r[0],a[1]=a[1]/r[0]):r[0]<r[1]&&(a[0]=a[0]/r[1],a[1]=a[1]/r[1])}return[a[0]+\"px\",a[1]+\"px\"]}(),title:!1,shade:.9,shadeClose:!0,closeBtn:!1,move:\".layui-layer-phimg img\",moveType:1,scrollbar:!1,moveOut:!0,anim:5*Math.random()|0,skin:\"layui-layer-photos\"+c(\"photos\"),content:'<div class=\"layui-layer-phimg\"><img src=\"'+d[u].src+'\" alt=\"'+(d[u].alt||\"\")+'\" layer-pid=\"'+d[u].pid+'\"><div class=\"layui-layer-imgsee\">'+(d.length>1?'<span class=\"layui-layer-imguide\"><a href=\"javascript:;\" class=\"layui-layer-iconext layui-layer-imgprev\"></a><a href=\"javascript:;\" class=\"layui-layer-iconext layui-layer-imgnext\"></a></span>':\"\")+'<div class=\"layui-layer-imgbar\" style=\"display:'+(a?\"block\":\"\")+'\"><span class=\"layui-layer-imgtit\"><a href=\"javascript:;\">'+(d[u].alt||\"\")+\"</a><em>\"+l.imgIndex+\"/\"+d.length+\"</em></span></div></div></div>\",success:function(e,i){l.bigimg=e.find(\".layui-layer-phimg\"),l.imgsee=e.find(\".layui-layer-imguide,.layui-layer-imgbar\"),l.event(e),t.tab&&t.tab(d[u],e)},end:function(){l.end=!0,i(document).off(\"keyup\",l.keyup)}},t))},function(){r.close(l.loadi),r.msg(\"&#x5F53;&#x524D;&#x56FE;&#x7247;&#x5730;&#x5740;&#x5F02;&#x5E38;<br>&#x662F;&#x5426;&#x7EE7;&#x7EED;&#x67E5;&#x770B;&#x4E0B;&#x4E00;&#x5F20;&#xFF1F;\",{time:3e4,btn:[\"&#x4E0B;&#x4E00;&#x5F20;\",\"&#x4E0D;&#x770B;&#x4E86;\"],yes:function(){d.length>1&&l.imgnext(!0,!0)}})})}},o.run=function(t){i=t,n=i(e),s.html=i(\"html\"),r.open=function(e){var t=new l(e);return t.index}},e.layui&&layui.define?(r.ready(),layui.define(\"jquery\",function(t){r.path=layui.cache.dir,o.run(layui.jquery),e.layer=r,t(\"layer\",r)})):\"function\"==typeof define?define([\"jquery\"],function(){return o.run(e.jQuery),r}):function(){o.run(e.jQuery),r.ready()}()}(window);"
  },
  {
    "path": "Public/layer/mobile/layer.js",
    "content": "/*! layer mobile-v2.0.0 Web弹层组件 MIT License  http://layer.layui.com/mobile  By 贤心 */\n ;!function(e){\"use strict\";var t=document,n=\"querySelectorAll\",i=\"getElementsByClassName\",a=function(e){return t[n](e)},s={type:0,shade:!0,shadeClose:!0,fixed:!0,anim:\"scale\"},l={extend:function(e){var t=JSON.parse(JSON.stringify(s));for(var n in e)t[n]=e[n];return t},timer:{},end:{}};l.touch=function(e,t){e.addEventListener(\"click\",function(e){t.call(this,e)},!1)};var r=0,o=[\"layui-m-layer\"],c=function(e){var t=this;t.config=l.extend(e),t.view()};c.prototype.view=function(){var e=this,n=e.config,s=t.createElement(\"div\");e.id=s.id=o[0]+r,s.setAttribute(\"class\",o[0]+\" \"+o[0]+(n.type||0)),s.setAttribute(\"index\",r);var l=function(){var e=\"object\"==typeof n.title;return n.title?'<h3 style=\"'+(e?n.title[1]:\"\")+'\">'+(e?n.title[0]:n.title)+\"</h3>\":\"\"}(),c=function(){\"string\"==typeof n.btn&&(n.btn=[n.btn]);var e,t=(n.btn||[]).length;return 0!==t&&n.btn?(e='<span yes type=\"1\">'+n.btn[0]+\"</span>\",2===t&&(e='<span no type=\"0\">'+n.btn[1]+\"</span>\"+e),'<div class=\"layui-m-layerbtn\">'+e+\"</div>\"):\"\"}();if(n.fixed||(n.top=n.hasOwnProperty(\"top\")?n.top:100,n.style=n.style||\"\",n.style+=\" top:\"+(t.body.scrollTop+n.top)+\"px\"),2===n.type&&(n.content='<i></i><i class=\"layui-m-layerload\"></i><i></i><p>'+(n.content||\"\")+\"</p>\"),n.skin&&(n.anim=\"up\"),\"msg\"===n.skin&&(n.shade=!1),s.innerHTML=(n.shade?\"<div \"+(\"string\"==typeof n.shade?'style=\"'+n.shade+'\"':\"\")+' class=\"layui-m-layershade\"></div>':\"\")+'<div class=\"layui-m-layermain\" '+(n.fixed?\"\":'style=\"position:static;\"')+'><div class=\"layui-m-layersection\"><div class=\"layui-m-layerchild '+(n.skin?\"layui-m-layer-\"+n.skin+\" \":\"\")+(n.className?n.className:\"\")+\" \"+(n.anim?\"layui-m-anim-\"+n.anim:\"\")+'\" '+(n.style?'style=\"'+n.style+'\"':\"\")+\">\"+l+'<div class=\"layui-m-layercont\">'+n.content+\"</div>\"+c+\"</div></div></div>\",!n.type||2===n.type){var d=t[i](o[0]+n.type),y=d.length;y>=1&&layer.close(d[0].getAttribute(\"index\"))}document.body.appendChild(s);var u=e.elem=a(\"#\"+e.id)[0];n.success&&n.success(u),e.index=r++,e.action(n,u)},c.prototype.action=function(e,t){var n=this;e.time&&(l.timer[n.index]=setTimeout(function(){layer.close(n.index)},1e3*e.time));var a=function(){var t=this.getAttribute(\"type\");0==t?(e.no&&e.no(),layer.close(n.index)):e.yes?e.yes(n.index):layer.close(n.index)};if(e.btn)for(var s=t[i](\"layui-m-layerbtn\")[0].children,r=s.length,o=0;o<r;o++)l.touch(s[o],a);if(e.shade&&e.shadeClose){var c=t[i](\"layui-m-layershade\")[0];l.touch(c,function(){layer.close(n.index,e.end)})}e.end&&(l.end[n.index]=e.end)},e.layer={v:\"2.0\",index:r,open:function(e){var t=new c(e||{});return t.index},close:function(e){var n=a(\"#\"+o[0]+e)[0];n&&(n.innerHTML=\"\",t.body.removeChild(n),clearTimeout(l.timer[e]),delete l.timer[e],\"function\"==typeof l.end[e]&&l.end[e](),delete l.end[e])},closeAll:function(){for(var e=t[i](o[0]),n=0,a=e.length;n<a;n++)layer.close(0|e[0].getAttribute(\"index\"))}},\"function\"==typeof define?define(function(){return layer}):function(){var e=document.scripts,n=e[e.length-1],i=n.src,a=i.substring(0,i.lastIndexOf(\"/\")+1);n.getAttribute(\"merge\")||document.head.appendChild(function(){var e=t.createElement(\"link\");return e.href=a+\"need/layer.css?2.0\",e.type=\"text/css\",e.rel=\"styleSheet\",e.id=\"layermcss\",e}())}()}(window);"
  },
  {
    "path": "Public/layer/mobile/need/layer.css",
    "content": ".layui-m-layer{position:relative;z-index:19891014}.layui-m-layer *{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}.layui-m-layermain,.layui-m-layershade{position:fixed;left:0;top:0;width:100%;height:100%}.layui-m-layershade{background-color:rgba(0,0,0,.7);pointer-events:auto}.layui-m-layermain{display:table;font-family:Helvetica,arial,sans-serif;pointer-events:none}.layui-m-layermain .layui-m-layersection{display:table-cell;vertical-align:middle;text-align:center}.layui-m-layerchild{position:relative;display:inline-block;text-align:left;background-color:#fff;font-size:14px;border-radius:5px;box-shadow:0 0 8px rgba(0,0,0,.1);pointer-events:auto;-webkit-overflow-scrolling:touch;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-duration:.2s;animation-duration:.2s}@-webkit-keyframes layui-m-anim-scale{0%{opacity:0;-webkit-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}}@keyframes layui-m-anim-scale{0%{opacity:0;-webkit-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}}.layui-m-anim-scale{animation-name:layui-m-anim-scale;-webkit-animation-name:layui-m-anim-scale}@-webkit-keyframes layui-m-anim-up{0%{opacity:0;-webkit-transform:translateY(800px);transform:translateY(800px)}100%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes layui-m-anim-up{0%{opacity:0;-webkit-transform:translateY(800px);transform:translateY(800px)}100%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}.layui-m-anim-up{-webkit-animation-name:layui-m-anim-up;animation-name:layui-m-anim-up}.layui-m-layer0 .layui-m-layerchild{width:90%;max-width:640px}.layui-m-layer1 .layui-m-layerchild{border:none;border-radius:0}.layui-m-layer2 .layui-m-layerchild{width:auto;max-width:260px;min-width:40px;border:none;background:0 0;box-shadow:none;color:#fff}.layui-m-layerchild h3{padding:0 10px;height:60px;line-height:60px;font-size:16px;font-weight:400;border-radius:5px 5px 0 0;text-align:center}.layui-m-layerbtn span,.layui-m-layerchild h3{text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.layui-m-layercont{padding:50px 30px;line-height:22px;text-align:center}.layui-m-layer1 .layui-m-layercont{padding:0;text-align:left}.layui-m-layer2 .layui-m-layercont{text-align:center;padding:0;line-height:0}.layui-m-layer2 .layui-m-layercont i{width:25px;height:25px;margin-left:8px;display:inline-block;background-color:#fff;border-radius:100%;-webkit-animation:layui-m-anim-loading 1.4s infinite ease-in-out;animation:layui-m-anim-loading 1.4s infinite ease-in-out;-webkit-animation-fill-mode:both;animation-fill-mode:both}.layui-m-layerbtn,.layui-m-layerbtn span{position:relative;text-align:center;border-radius:0 0 5px 5px}.layui-m-layer2 .layui-m-layercont p{margin-top:20px}@-webkit-keyframes layui-m-anim-loading{0%,100%,80%{transform:scale(0);-webkit-transform:scale(0)}40%{transform:scale(1);-webkit-transform:scale(1)}}@keyframes layui-m-anim-loading{0%,100%,80%{transform:scale(0);-webkit-transform:scale(0)}40%{transform:scale(1);-webkit-transform:scale(1)}}.layui-m-layer2 .layui-m-layercont i:first-child{margin-left:0;-webkit-animation-delay:-.32s;animation-delay:-.32s}.layui-m-layer2 .layui-m-layercont i.layui-m-layerload{-webkit-animation-delay:-.16s;animation-delay:-.16s}.layui-m-layer2 .layui-m-layercont>div{line-height:22px;padding-top:7px;margin-bottom:20px;font-size:14px}.layui-m-layerbtn{display:box;display:-moz-box;display:-webkit-box;width:100%;height:50px;line-height:50px;font-size:0;border-top:1px solid #D0D0D0;background-color:#F2F2F2}.layui-m-layerbtn span{display:block;-moz-box-flex:1;box-flex:1;-webkit-box-flex:1;font-size:14px;cursor:pointer}.layui-m-layerbtn span[yes]{color:#40AFFE}.layui-m-layerbtn span[no]{border-right:1px solid #D0D0D0;border-radius:0 0 0 5px}.layui-m-layerbtn span:active{background-color:#F6F6F6}.layui-m-layerend{position:absolute;right:7px;top:10px;width:30px;height:30px;border:0;font-weight:400;background:0 0;cursor:pointer;-webkit-appearance:none;font-size:30px}.layui-m-layerend::after,.layui-m-layerend::before{position:absolute;left:5px;top:15px;content:'';width:18px;height:1px;background-color:#999;transform:rotate(45deg);-webkit-transform:rotate(45deg);border-radius:3px}.layui-m-layerend::after{transform:rotate(-45deg);-webkit-transform:rotate(-45deg)}body .layui-m-layer .layui-m-layer-footer{position:fixed;width:95%;max-width:100%;margin:0 auto;left:0;right:0;bottom:10px;background:0 0}.layui-m-layer-footer .layui-m-layercont{padding:20px;border-radius:5px 5px 0 0;background-color:rgba(255,255,255,.8)}.layui-m-layer-footer .layui-m-layerbtn{display:block;height:auto;background:0 0;border-top:none}.layui-m-layer-footer .layui-m-layerbtn span{background-color:rgba(255,255,255,.8)}.layui-m-layer-footer .layui-m-layerbtn span[no]{color:#FD482C;border-top:1px solid #c2c2c2;border-radius:0 0 5px 5px}.layui-m-layer-footer .layui-m-layerbtn span[yes]{margin-top:10px;border-radius:5px}body .layui-m-layer .layui-m-layer-msg{width:auto;max-width:90%;margin:0 auto;bottom:-150px;background-color:rgba(0,0,0,.7);color:#fff}.layui-m-layer-msg .layui-m-layercont{padding:10px 20px}"
  },
  {
    "path": "Public/layer/skin/default/layer.css",
    "content": ".layui-layer-imgbar,.layui-layer-imgtit a,.layui-layer-tab .layui-layer-title span,.layui-layer-title{text-overflow:ellipsis;white-space:nowrap}*html{background-image:url(about:blank);background-attachment:fixed}html #layuicss-skinlayercss{display:none;position:absolute;width:1989px}.layui-layer,.layui-layer-shade{position:fixed;_position:absolute;pointer-events:auto}.layui-layer-shade{top:0;left:0;width:100%;height:100%;_height:expression(document.body.offsetHeight+\"px\")}.layui-layer{-webkit-overflow-scrolling:touch;top:150px;left:0;margin:0;padding:0;background-color:#fff;-webkit-background-clip:content;box-shadow:1px 1px 50px rgba(0,0,0,.3)}.layui-layer-close{position:absolute}.layui-layer-content{position:relative}.layui-layer-border{border:1px solid #B2B2B2;border:1px solid rgba(0,0,0,.1);box-shadow:1px 1px 5px rgba(0,0,0,.2)}.layui-layer-load{background:url(loading-1.gif) center center no-repeat #eee}.layui-layer-ico{background:url(icon.png) no-repeat}.layui-layer-btn a,.layui-layer-dialog .layui-layer-ico,.layui-layer-setwin a{display:inline-block;*display:inline;*zoom:1;vertical-align:top}.layui-layer-move{display:none;position:fixed;*position:absolute;left:0;top:0;width:100%;height:100%;cursor:move;opacity:0;filter:alpha(opacity=0);background-color:#fff;z-index:2147483647}.layui-layer-resize{position:absolute;width:15px;height:15px;right:0;bottom:0;cursor:se-resize}.layui-layer{border-radius:2px;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-duration:.3s;animation-duration:.3s}@-webkit-keyframes bounceIn{0%{opacity:0;-webkit-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}}@keyframes bounceIn{0%{opacity:0;-webkit-transform:scale(.5);-ms-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}}.layer-anim{-webkit-animation-name:bounceIn;animation-name:bounceIn}@-webkit-keyframes zoomInDown{0%{opacity:0;-webkit-transform:scale(.1) translateY(-2000px);transform:scale(.1) translateY(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateY(60px);transform:scale(.475) translateY(60px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}@keyframes zoomInDown{0%{opacity:0;-webkit-transform:scale(.1) translateY(-2000px);-ms-transform:scale(.1) translateY(-2000px);transform:scale(.1) translateY(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateY(60px);-ms-transform:scale(.475) translateY(60px);transform:scale(.475) translateY(60px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}.layer-anim-01{-webkit-animation-name:zoomInDown;animation-name:zoomInDown}@-webkit-keyframes fadeInUpBig{0%{opacity:0;-webkit-transform:translateY(2000px);transform:translateY(2000px)}100%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes fadeInUpBig{0%{opacity:0;-webkit-transform:translateY(2000px);-ms-transform:translateY(2000px);transform:translateY(2000px)}100%{opacity:1;-webkit-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}}.layer-anim-02{-webkit-animation-name:fadeInUpBig;animation-name:fadeInUpBig}@-webkit-keyframes zoomInLeft{0%{opacity:0;-webkit-transform:scale(.1) translateX(-2000px);transform:scale(.1) translateX(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateX(48px);transform:scale(.475) translateX(48px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}@keyframes zoomInLeft{0%{opacity:0;-webkit-transform:scale(.1) translateX(-2000px);-ms-transform:scale(.1) translateX(-2000px);transform:scale(.1) translateX(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateX(48px);-ms-transform:scale(.475) translateX(48px);transform:scale(.475) translateX(48px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}.layer-anim-03{-webkit-animation-name:zoomInLeft;animation-name:zoomInLeft}@-webkit-keyframes rollIn{0%{opacity:0;-webkit-transform:translateX(-100%) rotate(-120deg);transform:translateX(-100%) rotate(-120deg)}100%{opacity:1;-webkit-transform:translateX(0) rotate(0);transform:translateX(0) rotate(0)}}@keyframes rollIn{0%{opacity:0;-webkit-transform:translateX(-100%) rotate(-120deg);-ms-transform:translateX(-100%) rotate(-120deg);transform:translateX(-100%) rotate(-120deg)}100%{opacity:1;-webkit-transform:translateX(0) rotate(0);-ms-transform:translateX(0) rotate(0);transform:translateX(0) rotate(0)}}.layer-anim-04{-webkit-animation-name:rollIn;animation-name:rollIn}@keyframes fadeIn{0%{opacity:0}100%{opacity:1}}.layer-anim-05{-webkit-animation-name:fadeIn;animation-name:fadeIn}@-webkit-keyframes shake{0%,100%{-webkit-transform:translateX(0);transform:translateX(0)}10%,30%,50%,70%,90%{-webkit-transform:translateX(-10px);transform:translateX(-10px)}20%,40%,60%,80%{-webkit-transform:translateX(10px);transform:translateX(10px)}}@keyframes shake{0%,100%{-webkit-transform:translateX(0);-ms-transform:translateX(0);transform:translateX(0)}10%,30%,50%,70%,90%{-webkit-transform:translateX(-10px);-ms-transform:translateX(-10px);transform:translateX(-10px)}20%,40%,60%,80%{-webkit-transform:translateX(10px);-ms-transform:translateX(10px);transform:translateX(10px)}}.layer-anim-06{-webkit-animation-name:shake;animation-name:shake}@-webkit-keyframes fadeIn{0%{opacity:0}100%{opacity:1}}@-webkit-keyframes bounceOut{100%{opacity:0;-webkit-transform:scale(.7);transform:scale(.7)}30%{-webkit-transform:scale(1.05);transform:scale(1.05)}0%{-webkit-transform:scale(1);transform:scale(1)}}@keyframes bounceOut{100%{opacity:0;-webkit-transform:scale(.7);-ms-transform:scale(.7);transform:scale(.7)}30%{-webkit-transform:scale(1.05);-ms-transform:scale(1.05);transform:scale(1.05)}0%{-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}}.layer-anim-close{-webkit-animation-name:bounceOut;animation-name:bounceOut;-webkit-animation-duration:.2s;animation-duration:.2s}.layui-layer-title{padding:0 80px 0 20px;height:42px;line-height:42px;border-bottom:1px solid #eee;font-size:14px;color:#333;overflow:hidden;background-color:#F8F8F8;border-radius:2px 2px 0 0}.layui-layer-setwin{position:absolute;right:15px;*right:0;top:15px;font-size:0;line-height:initial}.layui-layer-setwin a{position:relative;width:16px;height:16px;margin-left:10px;font-size:12px;_overflow:hidden}.layui-layer-setwin .layui-layer-min cite{position:absolute;width:14px;height:2px;left:0;top:50%;margin-top:-1px;background-color:#2E2D3C;cursor:pointer;_overflow:hidden}.layui-layer-setwin .layui-layer-min:hover cite{background-color:#2D93CA}.layui-layer-setwin .layui-layer-max{background-position:-32px -40px}.layui-layer-setwin .layui-layer-max:hover{background-position:-16px -40px}.layui-layer-setwin .layui-layer-maxmin{background-position:-65px -40px}.layui-layer-setwin .layui-layer-maxmin:hover{background-position:-49px -40px}.layui-layer-setwin .layui-layer-close1{background-position:0 -40px;cursor:pointer}.layui-layer-setwin .layui-layer-close1:hover{opacity:.7}.layui-layer-setwin .layui-layer-close2{position:absolute;right:-28px;top:-28px;width:30px;height:30px;margin-left:0;background-position:-149px -31px;*right:-18px;_display:none}.layui-layer-setwin .layui-layer-close2:hover{background-position:-180px -31px}.layui-layer-btn{text-align:right;padding:0 10px 12px;pointer-events:auto;user-select:none;-webkit-user-select:none}.layui-layer-btn a{height:28px;line-height:28px;margin:0 6px;padding:0 15px;border:1px solid #dedede;background-color:#f1f1f1;color:#333;border-radius:2px;font-weight:400;cursor:pointer;text-decoration:none}.layui-layer-btn a:hover{opacity:.9;text-decoration:none}.layui-layer-btn a:active{opacity:.8}.layui-layer-btn .layui-layer-btn0{border-color:#4898d5;background-color:#2e8ded;color:#fff}.layui-layer-btn-l{text-align:left}.layui-layer-btn-c{text-align:center}.layui-layer-dialog{min-width:260px}.layui-layer-dialog .layui-layer-content{position:relative;padding:20px;line-height:24px;word-break:break-all;overflow:hidden;font-size:14px;overflow-x:hidden;overflow-y:auto}.layui-layer-dialog .layui-layer-content .layui-layer-ico{position:absolute;top:16px;left:15px;_left:-40px;width:30px;height:30px}.layui-layer-ico1{background-position:-30px 0}.layui-layer-ico2{background-position:-60px 0}.layui-layer-ico3{background-position:-90px 0}.layui-layer-ico4{background-position:-120px 0}.layui-layer-ico5{background-position:-150px 0}.layui-layer-ico6{background-position:-180px 0}.layui-layer-rim{border:6px solid #8D8D8D;border:6px solid rgba(0,0,0,.3);border-radius:5px;box-shadow:none}.layui-layer-msg{min-width:180px;border:1px solid #D3D4D3;box-shadow:none}.layui-layer-hui{min-width:100px;background-color:#000;filter:alpha(opacity=60);background-color:rgba(0,0,0,.6);color:#fff;border:none}.layui-layer-hui .layui-layer-content{padding:12px 25px;text-align:center}.layui-layer-dialog .layui-layer-padding{padding:20px 20px 20px 55px;text-align:left}.layui-layer-page .layui-layer-content{position:relative;overflow:auto}.layui-layer-iframe .layui-layer-btn,.layui-layer-page .layui-layer-btn{padding-top:10px}.layui-layer-nobg{background:0 0}.layui-layer-iframe iframe{display:block;width:100%}.layui-layer-loading{border-radius:100%;background:0 0;box-shadow:none;border:none}.layui-layer-loading .layui-layer-content{width:60px;height:24px;background:url(loading-0.gif) no-repeat}.layui-layer-loading .layui-layer-loading1{width:37px;height:37px;background:url(loading-1.gif) no-repeat}.layui-layer-ico16,.layui-layer-loading .layui-layer-loading2{width:32px;height:32px;background:url(loading-2.gif) no-repeat}.layui-layer-tips{background:0 0;box-shadow:none;border:none}.layui-layer-tips .layui-layer-content{position:relative;line-height:22px;min-width:12px;padding:5px 10px;font-size:12px;_float:left;border-radius:2px;box-shadow:1px 1px 3px rgba(0,0,0,.2);background-color:#000;color:#fff}.layui-layer-tips .layui-layer-close{right:-2px;top:-1px}.layui-layer-tips i.layui-layer-TipsG{position:absolute;width:0;height:0;border-width:8px;border-color:transparent;border-style:dashed;*overflow:hidden}.layui-layer-tips i.layui-layer-TipsB,.layui-layer-tips i.layui-layer-TipsT{left:5px;border-right-style:solid;border-right-color:#000}.layui-layer-tips i.layui-layer-TipsT{bottom:-8px}.layui-layer-tips i.layui-layer-TipsB{top:-8px}.layui-layer-tips i.layui-layer-TipsL,.layui-layer-tips i.layui-layer-TipsR{top:1px;border-bottom-style:solid;border-bottom-color:#000}.layui-layer-tips i.layui-layer-TipsR{left:-8px}.layui-layer-tips i.layui-layer-TipsL{right:-8px}.layui-layer-lan[type=dialog]{min-width:280px}.layui-layer-lan .layui-layer-title{background:#4476A7;color:#fff;border:none}.layui-layer-lan .layui-layer-btn{padding:10px;text-align:right;border-top:1px solid #E9E7E7}.layui-layer-lan .layui-layer-btn a{background:#BBB5B5;border:none}.layui-layer-lan .layui-layer-btn .layui-layer-btn1{background:#C9C5C5}.layui-layer-molv .layui-layer-title{background:#009f95;color:#fff;border:none}.layui-layer-molv .layui-layer-btn a{background:#009f95}.layui-layer-molv .layui-layer-btn .layui-layer-btn1{background:#92B8B1}.layui-layer-iconext{background:url(icon-ext.png) no-repeat}.layui-layer-prompt .layui-layer-input{display:block;width:220px;height:30px;margin:0 auto;line-height:30px;padding:0 5px;border:1px solid #ccc;box-shadow:1px 1px 5px rgba(0,0,0,.1) inset;color:#333}.layui-layer-prompt textarea.layui-layer-input{width:300px;height:100px;line-height:20px}.layui-layer-prompt .layui-layer-content{padding:20px}.layui-layer-prompt .layui-layer-btn{padding-top:0}.layui-layer-tab{box-shadow:1px 1px 50px rgba(0,0,0,.4)}.layui-layer-tab .layui-layer-title{padding-left:0;border-bottom:1px solid #ccc;background-color:#eee;overflow:visible}.layui-layer-tab .layui-layer-title span{position:relative;float:left;min-width:80px;max-width:260px;padding:0 20px;text-align:center;cursor:default;overflow:hidden}.layui-layer-tab .layui-layer-title span.layui-layer-tabnow{height:43px;border-left:1px solid #ccc;border-right:1px solid #ccc;background-color:#fff;z-index:10}.layui-layer-tab .layui-layer-title span:first-child{border-left:none}.layui-layer-tabmain{line-height:24px;clear:both}.layui-layer-tabmain .layui-layer-tabli{display:none}.layui-layer-tabmain .layui-layer-tabli.xubox_tab_layer{display:block}.xubox_tabclose{position:absolute;right:10px;top:5px;cursor:pointer}.layui-layer-photos{-webkit-animation-duration:1s;animation-duration:1s}.layui-layer-photos .layui-layer-content{overflow:hidden;text-align:center}.layui-layer-photos .layui-layer-phimg img{position:relative;width:100%;display:inline-block;*display:inline;*zoom:1;vertical-align:top}.layui-layer-imgbar,.layui-layer-imguide{display:none}.layui-layer-imgnext,.layui-layer-imgprev{position:absolute;top:50%;width:27px;_width:44px;height:44px;margin-top:-22px;outline:0;blr:expression(this.onFocus=this.blur())}.layui-layer-imgprev{left:10px;background-position:-5px -5px;_background-position:-70px -5px}.layui-layer-imgprev:hover{background-position:-33px -5px;_background-position:-120px -5px}.layui-layer-imgnext{right:10px;_right:8px;background-position:-5px -50px;_background-position:-70px -50px}.layui-layer-imgnext:hover{background-position:-33px -50px;_background-position:-120px -50px}.layui-layer-imgbar{position:absolute;left:0;bottom:0;width:100%;height:32px;line-height:32px;background-color:rgba(0,0,0,.8);background-color:#000\\9;filter:Alpha(opacity=80);color:#fff;overflow:hidden;font-size:0}.layui-layer-imgtit *{display:inline-block;*display:inline;*zoom:1;vertical-align:top;font-size:12px}.layui-layer-imgtit a{max-width:65%;overflow:hidden;color:#fff}.layui-layer-imgtit a:hover{color:#fff;text-decoration:underline}.layui-layer-imgtit em{padding-left:10px;font-style:normal}@media screen and (max-width:1100px){.layui-layer-iframe{overflow-y:auto;-webkit-overflow-scrolling:touch}}"
  },
  {
    "path": "Public/verifyCode.php",
    "content": "<?php\nsession_start();\n//生成验证码图片\nHeader(\"Content-type: image/PNG\");\n$im = imagecreate(44,18); // 画一张指定宽高的图片\n$back = ImageColorAllocate($im, 245,245,245); // 定义背景颜色\nimagefill($im,0,0,$back); //把背景颜色填充到刚刚画出来的图片中\n$vcodes = \"\";\nsrand((double)microtime()*1000000);\n//生成4位数字\nfor($i=0;$i<4;$i++){\n$font = ImageColorAllocate($im, rand(100,255),rand(0,100),rand(100,255)); // 生成随机颜色\n$authnum=rand(1,9);\n$vcodes.=$authnum;\nimagestring($im, 5, 2+$i*10, 1, $authnum, $font);\n}\n\n$_SESSION['v_code'] = $vcodes;\n\nfor($i=0;$i<200;$i++) //加入干扰象素\n{\n      $randcolor = ImageColorallocate($im,rand(0,255),rand(0,255),rand(0,255));\n      imagesetpixel($im, rand()%70 , rand()%30 , $randcolor); // 画像素点函数\n}\nImagePNG($im);\nImageDestroy($im);\n?>"
  },
  {
    "path": "README.md",
    "content": "﻿# ShowDoc\n\n## [点击查看中文版教程](https://www.showdoc.com.cn/help)\n\n### What is ShowDoc?\n\nWhen we take over a module or project which has been developed by others, we always feel crazy watching at the codes without notes or comments.\n\nWhere is the document?! Where is the document?! **Show me the doc!!**\n\nProgrammers often want others to write technical documents, but not by themselves. Writing technical documents need lots of time and works, such as it needs to consider how to handle the format and layout of the documents. Beside, the man who writes the documents has to think all kinds of non-technical details. For example, which catalog should to be put in the newly-established word document.\n\nIn general, all kinds of the word documents are dispersively maintained by different people in a team.\n\nHow to get the latest documents? Here is a way.\n\nThe man gets the documents by shouting out, Lol. Then he will receive them from others through IMs or E-mail. This kind of communication is not so bad, but this is not the most effective way.\n\nSo, what is the most effective way? **ShowDoc comes out!**\n\nShowDoc is a tool greatly applicable for an IT team to share documents online. It can promote communication efficiency between members of a team.\n\n### What can it be used for?\n\n- #### API Document ([Demo](https://www.showdoc.com.cn/demo-en))\n\nWith the development of mobile Internet, BaaS (Backend as a Service) becomes more and more popular. The server side(backend) provides API, and the APP side or Webpage frontend can conveniently invoke data through the backend. Using ShowDoc can compile exquisite API documents in a very fast and convenient way.\n\n- #### Data Dictionary ([Demo](https://www.showdoc.com.cn/demo-en))\n\nA good Data Dictionary, such as database structure can be easily exhibited to others, shown the definition of each field of the database structure.\n\n- #### Explain Document ([Demo](https://www.showdoc.com.cn/help-en))\n\nYou can absolutely use ShowDoc to write instructions of some tools, or some technical specifications explanation documents for the team to query.\n\n### What functions does it have now?\n\n- #### Sharing and Exporting\n\nResponsive webpage design can share the project documents to computer or mobile devices for reading. It can also export the project into offline word document.\n\n- #### Permission Manage\n\n  - Public and Private Project\n\n    Projects on ShowDoc are divided into two categories including Public Project and Private Project. The Public Project can be visited by anyone, the Private Project need to login. The password is set by project owner.\n\n  - Project Transfer\n\n    The project owner can freely transfer the project to others.\n\n  - Project Members\n\n    You can easily add or delete project members. Members of the project can edit the documents, but they can't transfer or delete the project, only owner has the permission.\n\n- #### Edit Function\n\n  - Support Markdown\n\n    ShowDoc adopts Markdown Editor, it is excellent both in editing and reading. If you know nothing about Markdown, please google it by the keywords \"Learning and Introduction of Markdown\".\n\n  - Template Insert\n\n    On the editing page, a click on the button which is on the top of the Editor can easily insert API interface template and data dictionary template. After inserting the template, altering data is the only thing needs to be done, and this reduces lots of editing work.\n\n  - History Version\n\n    ShowDoc provides a function of History Version on the page, you can easily restore from the history.\n\n### Deploy it on your own server\n\n- ShowDoc Deploy\n\n  Please refer to: [AutoInstall.md](https://github.com/star7th/showdoc/blob/master/documentation/en/AutoInstall.md)\n\n- Development & Contribution\n\n  Please refer to: [Development&Contribution.md](https://github.com/star7th/showdoc/blob/master/documentation/en/Development&Contribution.md)\n\n### About the copyright\n\nShowDoc is issued complying with Apache2 Open Source License, and it is free.\nShowdoc has an additional copyright notice on compliance with the Apache2 Open Source License:\n[Showdoc official](https://www.showdoc.com.cn/ 'Showdoc official') And author [star7th](https://github.com/star7th 'star7th') Have the copyright and corresponding rights of the program,\nOn the premise of retaining the copyright information and links on the program UI interface, it can be used for free or secondary development\nIf you need to change copyright information or copyright links, you need to obtain official consent and authorization.\n"
  },
  {
    "path": "SECURITY.md",
    "content": "# Security Policy\n\n## Supported Versions\n\n\nThe latest version of the security report is currently accepted.\n\nBefore reporting, you can test the latest release or the latest master branch code of the project\n\n\n## Reporting a Vulnerability\n\nPlease contact email xing7th#gmail.com (change # into @)   report the vulnerability. We will reply to you by email\n\n\n# 安全策略\n\n## 支持的版本\n\n目前接受最新版本的安全报告。\n\n在报告之前，你可以测试项目的最新发行版本或最新master分支代码\n\n## 报告漏洞\n\n请联系电子邮件xing7th#gmail.com（将#更改为@）报告该漏洞。我们将通过电子邮件回复你\n"
  },
  {
    "path": "composer.json",
    "content": "{\n    \"name\": \"showdoc/showdoc\",\n    \"type\": \"project\",\n    \"description\": \"ShowDoc is a tool greatly applicable for an IT team to share documents online\",\n    \"keywords\": [\n        \"showdoc\",\n        \"documents\",\n        \"Api\"\n    ],\n    \"homepage\": \"https://github.com/star7th/showdoc\",\n    \"version\": \"v3.8.0\",\n    \"license\": \"Apache-2.0\",\n    \"authors\": [\n        {\n            \"name\": \"star7th\",\n            \"email\": \"xing7th@gmail.com\",\n            \"homepage\": \"http://blog.star7th.com/\",\n            \"role\": \"Developer\"\n        }\n    ],\n    \"require\": {\n        \"php\": \">=7.4\",\n        \"slim/slim\": \"^4.0\",\n        \"slim/psr7\": \"^1.6\",\n        \"php-di/php-di\": \"^6.4\",\n        \"illuminate/database\": \"^8.0\",\n        \"illuminate/events\": \"^8.0\",\n        \"league/oauth2-client\": \"^2.6\",\n        \"jasig/phpcas\": \"^1.3\",\n        \"gregwar/captcha\": \"1.*\",\n        \"async-aws/s3\": \"^1.10\",\n        \"greenlion/php-sql-parser\": \"^4.5\",\n        \"qcloud/cos-sdk-v5\": \"1.*\",\n        \"vlucas/phpdotenv\": \"^5.6\"\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"App\\\\\": \"server/app/\"\n        }\n    },\n    \"config\": {\n        \"vendor-dir\": \"./server/vendor\"\n    }\n}\n"
  },
  {
    "path": "docker-compose.yml",
    "content": "\nservices:\n  showdoc:\n    ## 方式1: 官方 image ################################\n    # image: star7th/showdoc\n\n    ## 方式2: 源码 build image ################################\n    ## 国内构建镜像方式1: docker compose build --build-arg IN_CHINA=true\n    ## 国内构建镜像方式2: IN_CHINA=true docker compose build\n    ## 启动: IN_CHINA=true docker compose up -d\n    build:\n      context: ./\n      args:\n        - IN_CHINA=${IN_CHINA:-false}\n    environment:\n      IN_CHINA: ${IN_CHINA:-false}\n    hostname: showdoc\n    ports:\n      - 4999:80\n    volumes:\n      ## 兼容历史版本文件\n      - /showdoc_data:/showdoc_data_old\n      - ./showdocdata/html:/var/www/html\n    restart: always\n    tty: true\n"
  },
  {
    "path": "docker.run.sh",
    "content": "#!/usr/bin/env bash\n\nset -o pipefail\npids=()\n\ncleanup() {\n    echo \"receive SIGTERM, kill ${pids[*]}\"\n    for pid in \"${pids[@]}\"; do\n        kill \"$pid\"\n        wait \"$pid\"\n    done\n}\n\nset_mirror() {\n    [ \"$IN_CHINA\" = true ] || return 0\n\n    if [ -f /etc/apk/repositories ]; then\n        sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/' /etc/apk/repositories\n    fi\n    if command -v npm >/dev/null 2>&1; then\n        npm config set registry https://registry.npmmirror.com/\n    fi\n    # if command -v composer >/dev/null 2>&1; then\n    #     composer config -g repo.packagist composer https://mirrors.aliyun.com/composer\n    # fi\n}\n\ndocker_build() {\n    set -xe\n    rm -rf /app\n    ln -sf $web_dir /app\n    ## sed 在第二行插入 user=root 解决 supervisor 告警\n    sed -i '2i user=root' /opt/docker/etc/supervisor.conf\n    ## php setting\n    (\n        echo \"upload_max_filesize=5120M;\"\n        echo \"post_max_size=5120M;\"\n    ) >>/opt/docker/etc/php/php.ini\n    (\n        echo \"client_max_body_size 5120m;\"\n    ) >/opt/docker/etc/nginx/vhost.common.d/10-general.conf\n\n    ## fix nginx warning\n    sed -i -e '1 s/^/#/' /opt/docker/etc/nginx/vhost.ssl.conf\n    sed -i -e '/443\\ default_server/s//443\\ default_server\\ ssl/' /opt/docker/etc/nginx/vhost.conf\n\n    ## disable service\n    mv /opt/docker/etc/supervisor.d/cron.conf{,.bak}\n    mv /opt/docker/etc/supervisor.d/dnsmasq.conf{,.bak}\n    # mv /opt/docker/etc/supervisor.d/nginx.conf{,.bak}\n    # mv /opt/docker/etc/supervisor.d/php-fpm.conf{,.bak}\n    mv /opt/docker/etc/supervisor.d/postfix.conf{,.bak}\n    mv /opt/docker/etc/supervisor.d/ssh.conf{,.bak}\n    mv /opt/docker/etc/supervisor.d/syslog.conf{,.bak}\n\n    set_mirror\n\n    apk update\n    apk add --update --no-cache nodejs npm sqlite sqlite-dev\n\n    mv $showdoc_dir_html/mock $showdoc_dir/\n    cd $showdoc_dir/mock || exit 1\n    ## fix old warn\n    # rm -f package-lock.json\n\n    npm install\n}\n\nbackup_dbfile() {\n    ## 数据库文件\n    db_file=$web_dir/Sqlite/showdoc.db.php\n    if [[ \"${IN_CHINA}\" == true ]]; then\n        backup_time=\"$(TZ='Asia/Shanghai' date +%F-%H-%M-%S)\"\n    else\n        backup_time=\"$(date +%F-%H-%M-%S)\"\n    fi\n    if [[ ! -f \"$db_file\" ]]; then\n        echo \"Database file $db_file not found, skip backup.\"\n        return\n    fi\n    backup_file=\"${db_file}.backup.full.${backup_time}.php\"\n    echo \"Backing up database file to $backup_file ...\"\n    if command -v sqlite3 >/dev/null 2>&1; then\n        echo \"Using sqlite3 for backup.\"\n        ## 更安全的备份方式\n        sqlite3 \"$db_file\" \".backup '${backup_file}'\"\n    else\n        echo \"command sqlite3 not found, backup database with copy.\"\n        ## 直接复制文件的备份方式（不推荐，可能导致备份文件损坏）\n        rsync -a $db_file \"$backup_file\"\n    fi\n    echo \"Completed backup to ${backup_file}\"\n    ## remove old files (15 days ago)\n    find ${db_file}.* -type f -ctime +15 -print0 |\n        xargs -t -r -0 -I % rm -f % >/dev/null\n}\n\ndocker_run() {\n    ## 首次启动需要拷贝程序文件到 $web_dir/ (/var/www/html)\n    if [ -f \"$web_dir/index.php\" ]; then\n        echo \"Found $web_dir/index.php, skip copy.\"\n    else\n        echo \"Not found $web_dir/index.php, copy from $showdoc_dir_html to $web_dir...\"\n        ## 兼容历史版本 宿主机/showdoc_data/挂载到容器内/showdoc_data_old/\n        if [[ -f $showdoc_dir_old/html/index.php && ! -f $showdoc_dir_old/.skip_old ]]; then\n            echo \"Found old version of \\\"showdoc_data\\\", copy...\"\n            rsync -a $showdoc_dir_old/html/ $web_dir/ &&\n                touch $showdoc_dir_old/.skip_old\n        else\n            rsync -a $showdoc_dir_html/ $web_dir/\n        fi\n    fi\n    echo \"Checking upgrade...\"\n    ## upgrade (通过 Dockerfile 的环境变量 SHOWDOC_DOCKER_VERSION 变更版本)\n    ## upgrade (通过 composer.json \"version\" 变更版本)\n    ver_file=$web_dir/.ver\n    version_local=\"$(cat $ver_file 2>/dev/null || echo \"none\")\"\n    version_json=$(grep -o '\"version\":.*\"' $showdoc_dir_html/composer.json | awk '{split($2,a,\"\\\"\"); print a[2]}')\n    # version_json=$(grep -o '\"version\":.*\"' $showdoc_dir_html/composer.json | awk '{print substr($2,2,6)}')\n\n    echo \"Local version: $version_local\"\n    echo \"composer.json version: $version_json\"\n    # if [[ \"$SHOWDOC_DOCKER_VERSION\" == \"$(cat $ver_file)\" ]]; then\n    if [[ \"${version_local}\" == \"${version_json}\" ]]; then\n        echo \"Same version, skip upgrade.\"\n    else\n        echo \"Found new version: ${version_local} => ${version_json}, upgrade...\"\n        ## 备份数据库文件\n        backup_dbfile\n        echo \"Upgrade application files...\"\n        ## 此处排除 Sqlite/ 和 Public/Uploads/ 目录，保留用户数据\n        rsync -a --exclude='Sqlite/' --exclude='Public/Uploads/' $showdoc_dir_html/ $web_dir/\n        ## revert lang if lang=en\n        if grep -q 'lang:.*en' $web_dir/web/index.html; then\n            sed -i -e \"/lang:.*zh-cn.*/s//lang: 'zh-cn'/\" $web_dir/web/index.html $web_dir/web_src/index.html\n        fi\n        # echo \"$SHOWDOC_DOCKER_VERSION\" >$ver_file\n        echo \"$version_json\" >$ver_file\n    fi\n\n    echo \"Checking file permission...\"\n    ## fix file permission\n    # find $web_dir -type f -exec chmod 644 {} \\;\n    # find $web_dir -type d -exec chmod 755 {} \\;\n    # find $web_dir -type f -iname '*.sh' -exec chmod 755 {} \\;\n    # 旧版 ThinkPHP 路径（兼容性保留）\n    runtime_dir=\"$web_dir/server/Application/Runtime\"\n    [[ -d $runtime_dir ]] || mkdir -p $runtime_dir\n    # 新版 Slim 4 路径\n    runtime_dir_new=\"$web_dir/server/app/Runtime\"\n    [[ -d $runtime_dir_new ]] || mkdir -p $runtime_dir_new\n    chown -R 1000:1000 \\\n        $web_dir/Sqlite \\\n        $web_dir/Public/Uploads \\\n        $web_dir/install \\\n        $runtime_dir \\\n        $runtime_dir_new\n    # 确保 install/ajax.php 中提到的文件有写入权限\n    chmod 666 \"$web_dir/server/Application/Home/Conf/config.php\"\n    chmod 666 \"$web_dir/web/index.html\"\n    chmod 666 \"$web_dir/web_src/index.html\"\n\n    ## 检查 web/ 目录是否有 index.php，如果没有则创建\n    if [ ! -f \"$web_dir/web/index.php\" ]; then\n        echo \"Creating $web_dir/web/index.php...\"\n        cat > \"$web_dir/web/index.php\" << 'EOF'\n<?php\necho file_get_contents('index.html');\nEOF\n    fi\n\n    ## backup sqlite file every day / 后台进程每日自动备份数据库\n    while true; do\n        # backup on (20:01 UTC) (04:01 Asia/Shanghai) every day\n        if [[ $(date -u +%H%M) == 2001 ]]; then\n            backup_dbfile\n            sleep 5\n        fi\n        ## 每小时修正一次上传目录权限（兜底方案，确保 nginx 可读）\n        if [[ $(date -u +%H%M) =~ 00$ ]]; then\n            upload_dir=\"$web_dir/Public/Uploads\"\n            if [[ -d \"$upload_dir\" ]]; then\n                chmod -R 755 \"$upload_dir\"\n                find \"$upload_dir\" -type f -exec chmod 644 {} \\;\n            fi\n        fi\n        sleep 55\n    done &\n    pids+=(\"$!\")\n\n    ## 启动 showdoc 服务\n    echo \"Starting showdoc server...\"\n    (\n        sleep 3\n        cd $showdoc_dir_html/server || exit 1\n        php index.php /api/update/dockerUpdateCode\n    )\n    ## 延迟启动 mock 服务\n    (\n        echo \"delay 30s start mock...\"\n        sleep 30\n        echo \"Starting mock server...\"\n        cd $showdoc_dir/mock/ || exit 1\n        npm run start\n    ) &\n    pids+=(\"$!\")\n\n    ## 启动 supervisor 服务\n    echo \"Starting nginx and php-fpm...\"\n    ## 在启动 supervisord 之前设置 umask，确保 nginx 和 php-fpm 都使用 0022\n    umask 0022\n    supervisord -c /opt/docker/etc/supervisor.conf &\n    pids+=(\"$!\")\n\n    wait\n}\n\nmain() {\n    showdoc_dir='/showdoc_data'\n    ## 兼容历史版本的目录\n    showdoc_dir_old='/showdoc_data_old'\n    ## 包含程序文件\n    showdoc_dir_html=\"$showdoc_dir/html\"\n    ## web site dir / 网站目录\n    web_dir='/var/www/html'\n\n    case $1 in\n    -b | --build)\n        docker_build\n        ;;\n    *)\n        ## 识别中断信号，停止进程\n        trap cleanup HUP INT QUIT TERM\n\n        docker_run\n        ;;\n    esac\n}\n\nmain \"$@\"\n"
  },
  {
    "path": "documentation/en/AutoInstall.md",
    "content": "### Foreword\r\n\r\nThe automatic script uses Docker to install the runtime environment for Linux servers. If your server does't have a Docker service, the script will try to install it. The process of installing Docker maybe a bit slow. If you have already installed Docker, the script will omit some of the steps to speed up the ShowDoc installation.\r\n\r\nWhen the script fails to install Docker, you should manually install Docker before executing the script. If you still have problem in installing Docker, you can (un/re-)install and debug it step by step according to this tutorial: [ByDocker.md](https://github.com/star7th/showdoc/blob/master/documentation/en/ByDocker.md)\r\n\r\nIf the server does't support Docker, you can only run ShowDoc by manually installing the PHP environment:  [DeployManual.md](https://github.com/star7th/showdoc/blob/master/documentation/en/DeployManual.md)\r\n\r\n### Instructions\r\n\r\n```bash\r\n# Download the script and run\r\ncurl -fL https://www.showdoc.cc/script/showdoc | bash\r\n\r\n# Default is the Chinese version. If you want to install the English version, please add the en parameter\r\ncurl -fL https://www.showdoc.cc/script/showdoc | bash -s en\r\n```\r\n\r\n\r\n### Post-installation instructions\r\n\r\nOnce installed, the ShowDoc data will be stored in the /showdoc_data/html directory.\r\n\r\nYou can open ShowDoc by opening http://your-domain.com:4999 (replace your-domain.com with your server domain name or IP-address).\r\n\r\nThe default admin account is: `showdoc`.\r\nThe default admin password is: `123456`.\r\n\r\nAfter logging in, you can see the management background entry in the upper right. It is recommended to change the password.\r\n\r\nFor issues or suggestions on ShowDoc, please go to https://github.com/star7th/showdoc for an issue.\r\n\r\n### Development & Contribution\r\n\r\nPlease refer to: [Development&Contribution.md](https://github.com/star7th/showdoc/blob/master/documentation/en/Development&Contribution.md)\r\n\r\n### Upgrade from manual mode to automatic script mode\r\n\r\nIf you have previously installed ShowDoc manually, consider upgrading to this automatic scripting method. After upgrading to the script mode, you can use the automation features of the script, such as upgrading to the latest version, restart, uninstall, etc.\r\n\r\nUpgrade method:\r\n\r\n1. First refer to the previous section (Post-installation instructions), then install ShowDoc on the server\r\n\r\n2. The original ShowDoc directory Sqlite/showdoc.db.php override /showdoc_data/html/Sqlite/showdoc.db.php, Public/Uploads override /showdoc_data/html/Public/Uploads\r\n\r\n3. Execute the command\r\n\r\n```bash\r\nchmod 777 -R /showdoc_data/html\r\ncurl -fL https://www.showdoc.cc/script/showdoc | bash -s update\r\n```\r\n\r\n\r\n### Other commands\r\n\r\n```bash\r\n# Attach the script to other commands, so you can use it when managing ShowDoc.\r\n# Stop ShowDoc\r\ncurl -fL https://www.showdoc.cc/script/showdoc | bash -s stop\r\n\r\n# Restart ShowDoc\r\ncurl -fL https://www.showdoc.cc/script/showdoc | bash -s restart\r\n\r\n# Update ShowDoc to the latest version\r\ncurl -fL https://www.showdoc.cc/script/showdoc | bash -s update\r\n\r\n# Uninstall ShowDoc\r\ncurl -fL https://www.showdoc.cc/script/showdoc | bash -s uninstall\r\n```\r\n"
  },
  {
    "path": "documentation/en/ByComposer.md",
    "content": "﻿Composer is a tool for dependency management in PHP. It allows you to declare the libraries your project depends on and it will manage (install/update) them for you.https://getcomposer.org/\nYou can install ShowDoc by Composer automatically.\n\n- New installation\n\n Change to web directory（e.g：/var/www/html/）and execute:\n\n ```\n composer create-project  showdoc/showdoc\n ```\nThere will be a folder name \"showdoc\".Open your browser and visit \nhttp://your-domain.com/showdoc/install/ (change to your servser's address) to initialize ShowDoc.\n\n- Upgrade\n\n Stop apache or nginx , and move showdoc folder to bakup\n ```\n mv showdoc  showdoc_backup \n ```\nThen flollow the \"New installation\" guide to install ShowDoc .After that ,move db file and pictures from old folder to new folder.\n```\nrm showdoc/Sqlite/showdoc.db.php\ncp showdoc_backup/Sqlite/showdoc.db.php  showdoc/Sqlite/showdoc.db.php\nrm -r showdoc/Public/Uploads/\ncp -r showdoc_backup/Public/Uploads/ showdoc/Public/\n```\nOpen your browser and visit \nhttp://your-domain.com/showdoc/index.php?s=/home/update/db (change to your servser's address) to update db.\n\n\n"
  },
  {
    "path": "documentation/en/ByDocker.md",
    "content": "## Basic installation\r\n\r\nMake sure your environment has Docker installed before installation. The Docker installation tutorial is more online, you can search for it. Here is a highlight of ShowDoc.\r\n\r\n```bash\r\n# The original official image installation command (Chinese mainland users do not recommend direct use of the original image, you can use the following accelerated image)\r\ndocker pull star7th/showdoc\r\n\r\n# Chinese Image Installation Command (Remember to execute the Docker tag command after installation to rename)\r\ndocker pull registry.docker-cn.com/star7th/showdoc\r\ndocker tag registry.docker-cn.com/star7th/showdoc:latest star7th/showdoc:latest\r\n\r\n## Follow-up commands need to be executed whether you use official image or accelerated image\r\n\r\n# New directory to store ShowDoc data\r\nmkdir -m 777 -p /showdoc_data/html\r\n\r\n# Start the ShowDoc container. Don't forget to follow the steps to transfer data after booting.\r\ndocker run -d --name showdoc -p 4999:80 -v /showdoc_data/html:/var/www/html/ star7th/showdoc\r\n\r\n# Move data When you execute here, pay attention to the error message that the command line interface has permission to prohibit.\r\n# If there is, check the permissions, or security restrictions (for example, selinux may prohibit the Docker process from writing files)\r\ndocker exec showdoc cp -fr /showdoc_data/html /var/www/\r\n# permission\r\nchmod 777 -R /showdoc_data\r\n\r\n```\r\n\r\nAccording to the above command, the data of ShowDoc will be stored in the /showdoc_data/html directory.\r\nYou can access ShowDoc by opening http://localhost:4999 (localhost can be changed to your server domain name or IP). The default admin account is Username: showdoc Password: 123456 . After logging in, you can see the management background entry in the upper right. It is recommended to change the password after login.\r\nFor issues or suggestions on ShowDoc, please go to https://github.com/star7th/showdoc to issue an issue. If you think that ShowDoc is easy to use, please star it.\r\n\r\n## How to upgrade\r\nThe upgrade here is an upgrade to the above Docker installation. If you used a non-Docker installation (such as PHP installation), please skip this section and go directly to the next section.\r\n\r\n```bash\r\n## Stop the container\r\ndocker stop showdoc\r\n\r\n## Download the latest code package\r\ncurl -fL https://github.com/star7th/showdoc/archive/master.tar.gz | tar -C /showdoc_data/ -zxv\r\n\r\nrm -rf /showdoc_data/html_bak\r\n## Backup. If possible, the html_bak in the command can also be date-suffixed to keep multiple backups of different dates.\r\nmv /showdoc_data/html /showdoc_data/html_bak\r\nmv /showdoc_data/showdoc-master /showdoc_data/html\r\n\r\n## Grant permissions\r\nchmod 777 -R /showdoc_data/html\r\n\r\n## Start the container\r\ndocker start showdoc\r\n\r\n## Perform the installation. The Chinese version is installed by default. If you want to install the English version, change the zh in the following parameters to en\r\ncurl http://localhost:4999/install/non_interactive.php?lang=en\r\n\r\n## Transfer the old database\r\n\\cp -f /showdoc_data/html_bak/Sqlite/showdoc.db.php /showdoc_data/html/Sqlite/showdoc.db.php\r\n\r\n## Transfer old attachment data\r\n\\cp -r -f /showdoc_data/html_bak/Public/Uploads /showdoc_data/html/Public/Uploads\r\n\r\n## Perform a database upgrade, see the word \"OK\" to prove success\r\ncurl http://localhost:4999?s=/home/update/db\r\n\r\n## If there is an error in the middle, please rename the original /showdoc_data/html_bak file to /showdoc_data/html and restart the container to recover.\r\n\r\n```\r\n\r\n\r\n### How to upgrade non-Docker installation method to Docker installation method\r\n\r\nFirst refer to the previous article, use Docker way to install a new ShowDoc, and do data persistence.\r\nNext, assuming that the old ShowDoc you originally installed has been uploaded to the /tmp/showdoc directory of the server, then\r\n```bash\r\n## Transfer the old database\r\n\\cp -r -f /tmp/showdoc/Sqlite/showdoc.db.php /showdoc_data/html/Sqlite/showdoc.db.php\r\n\r\n## Transfer old attachment data\r\n\\cp -r -f /tmp/showdoc/Public/Uploads /showdoc_data/html/Public/Uploads\r\n\r\n## Perform a database upgrade, see the word \"OK\" to prove success\r\ncurl http://localhost:4999?s=/home/update/db\r\n```\r\n\r\n### data backup\r\nJust back up the /showdoc_data/html directory. For example, execute the following command to compress and store\r\n```bash\r\nzip -r /showdoc_data/showdoc_bak.zip /showdoc_data/html\r\n## where showdoc_bak.zip can be named with a date suffix for multiple backups. You can also use timed tasks to implement scheduled backups.\r\n```\r\n### Other reference commands\r\n```bash\r\n docker stop showdoc ## stop the container\r\n docker restart showdoc ## restart the showdoc container\r\n docker rm showdoc ## delete showdoc container\r\n docker rmi star7th/showdoc ## delete showdoc image\r\n docker stop $(docker ps -a -q); docker rm $(docker ps -a -q)  ## Stop and delete all containers. Dangerous orders, do not know how to use.\r\n```\r\n"
  },
  {
    "path": "documentation/en/DeployManual.md",
    "content": "﻿### Introduction \n\n About ShowDoc , Please refer to [/README.md](README.md)\n \n### Environment dependence\n\n - Required environment\n  \n  `PHP5.3 or  above version ` ,`php-gd`,`php-pdo`\n \n### Install and configure\n\n- #### New installation\n \n - Manually download the code from https://github.com/star7th/showdoc/\n \n - Make these writable\n\n  Example: `sudo chmod -R 777 server/showdoc/install`\n  \n  `/install`, `/Application/Runtime ` ,`/Public/Uploads`,`/Sqlite`,`/Sqlite/showdoc.db.php`\n   \n - Windows sever\n    \n   Please entable `extension=php_sqlite.dll` ，`extension=php_pdo_sqlite.dll`and `php_mbstring.dll` in `php.ini` . Ignore it if you are on Linux.\n \n - Run installation\n \n     `http://your-domain.com/install/`\n   \n -  Default Admin \n\n   Username : showdoc\n   Password : 123456\n   \n- #### Upgrade \n\n - Manually download the code from https://github.com/star7th/showdoc/\n - Backup your codes via: `mv showdoc  showdoc_backup`\n - Dowload new codes and decompression it to a new directory.Copy `/Sqlite/*` and `/Public/Uploads/*` from old directory to new directory\n \n - Open `http://your-domain.com/index.php?s=/home/update/db`  in your brown to update database \n \n \n"
  },
  {
    "path": "documentation/en/Development&Contribution.md",
    "content": "#### Technical stack description\r\n\r\nFrontend: Vue + ElementUI\r\n\r\nBackend: PHP + Slim 4 + Illuminate/Database\r\n- Architecture: Slim 4 micro-framework + Illuminate/Database ORM\r\n- Core features: PSR-7 HTTP messages, PSR-11 dependency injection, PSR-15 middleware\r\n- PHP requirement: PHP 7.4+ (recommended 8.0+)\r\n- Compatibility: Fully compatible with existing API interfaces and URL formats (including `/server/index.php?s=...`)\r\n\r\nDatabase: ShowDoc comes with a file database (/Sqlite/showdoc.db.php), no need to manually install the database\r\n\r\n#### Preparation before development\r\n\r\nDeveloping a machine requires first installing the PHP environment and the NodeJS environment.\r\nDownload the code and place it in the www directory under the PHP environment\r\n\r\nFirst access in the browser through the address, in order to complete the initial installation of ShowDoc (if it has been installed, ignore it)\r\n\r\nGo to ShowDoc's web_src directory on the command line and execute npm install to install the dependencies. (If there is no npm, you must first install the NodeJS environment)\r\n\r\n\r\n#### Front-end development\r\n\r\nExecute npm run dev to enable the mode, and you can see the effect of the changes in real time by accessing localhost:8080. Please use a proxy to proxy to the PHP server when requesting the backend API.\r\n\r\nThe npm run build needs to be executed before the final package takes effect. The packaged static files will be in the /web directory.\r\n\r\nMainly related to the directories and files:\r\n\r\n```\r\nWeb_src/src/components //page components are basically placed here\r\n\r\nWeb_src/src/router // page routing. Can target components based on url\r\n\r\nWeb_src/static // static resource directory\r\n\r\nWeb_src/static/lang // front-end language pack\r\n\r\n```\r\n\r\n#### Backend development\r\n\r\nMainly related directories and files\r\n\r\n```\r\n\r\nServer/app/Api/Controller/ //API controllers directory, all background APIs are placed here\r\n\r\nServer/app/Common/Helper/ //Helper classes directory (Security, HttpHelper, FileHelper, etc.)\r\n\r\nServer/app/Model/ //Model classes directory (User, Item, Page, etc.)\r\n\r\nServer/app/Runtime/Logs/ //Error logs directory, errors will be printed to browser or logged here\r\n\r\nPublic/Uploads/ //Uploaded images are placed here\r\n\r\nServer/app/Api/Lang/ //Backend language pack\r\n\r\n```\r\n\r\n\r\n#### other instructions\r\n\r\nPlease respect the open-source agreement after the second development, retain the copyright-logo and link\r\nIf you have developed useful features, you may wish to contribute to the official GitHub code repository for sharing with everyone.\r\n\r\nThe upgrade of ShowDoc may overwrite your original secondary development. If you want to be compatible, it is best to submit it to the official warehouse to become an official function.\r\n"
  },
  {
    "path": "documentation/en/README.md",
    "content": "﻿## 中文版教程：https://www.showdoc.cc/help \n\n### What is ShowDoc ?\n\nWhenever we take over a module or project which has been developed by other people, we always feel crazy watching at those codes without notes. Where is the document?! Where is the document?! **Show me the doc !!**\n\nA programmer often hopes the others to write technical documents, with the hope of not writing them on his/her own. Because writing a technical document needs a lot of time to handle the format and layout, and the person who writes it has to think of all kinds of non-technical details such as which catalog to put in the newly-established word document\n\nAll kinds of the word documents are kept by different persons in a team dispersedly. The person who needs other documents gets the documents by shouting out. He/She gives a shout asking for the documents and then receives them from other people by IMs or the e-mail. This kind of communication is not bad, but the efficiency is not high.\n\nShowDoc is a tool greatly applicable for an IT team to share documents online. It can promote communication efficiency among members of the team.\n\n### What can it be used for?\n\n- #### API Document （ [Demo](https://www.showdoc.cc/demo-en)）\n \n With the development of mobile Internet, BaaS (Backend as a Service) becomes more and more popular. The Server end provides API, and the APP end or Webpage frontend can invoke data conveniently. Using ShowDoc can compile exquisite API documents in a very fast and convenient way.\n\n- #### Data Dictionary （ [Demo](https://www.showdoc.cc/demo-en)）\n \n A good Data Dictionary can easily exhibit database structure to other people, such as definition of each field and the like.\n\n- #### Explanation Document （ [Demo](https://www.showdoc.cc/help-en)）\n \n You can absolutely use ShowDoc to compile the explanation documents for some tools, as well as to compile some technical specifications explanation documents for the team to look up.\n \n### What functions does it have?\n\n- #### Sharing and Exporting\n\n Responsive webpage design can share the project documents to computer or mobile devices for reading. It can also export the project into word document for browsing offline.\n \n- #### Permission Management\n\n - Public Project and Private Project\n \n   Projects on ShowDoc are divided into two categories including Public Project and Private Project. Public Project can be visited by any user no matter he/she logs in or not, while inputting password for verification is needed for visiting the Private Project. The password is set by project creator. \n   \n  - Project Transfer\n  \n   The project creator can transfer the project to other users of the website freely.\n   \n  - Project Members\n  \n   You can easily add or delete project members in the project of ShowDoc. Members of the project can edit the project, but they can not transfer or delete the project (only creator of the project has the permission).\n   \n- #### Edit Function\n  - Markdown Edit\n  \n   ShowDoc adopts Markdown Editor, and it is excellent both in editing and reading experience. If you know nothing about Markdown, please search “Learning and Introduction of Markdown” on the search engine.\n   \n  - Template Insert\n  \n   On the editing page of ShowDoc, a click on the button which is on the top of the Editor can easily insert API interface template and data dictionary template. After inserting the template, altering data is the only thing that need to do and it reduces a lot of work in editing.\n   \n  - History Version\n  \n   ShowDoc provides a function of History Version on the page, and you can easily restore the page to the former version.\n   \n\n### Deploy It to Your Own Server\n - ShowDoc Deploy\n  \n     Please refer to: [AutoInstall.md](https://github.com/star7th/showdoc/blob/master/documentation/en/AutoInstall.md)\n\n - Development & Contribution\n\n   Please refer to: [Development&Contribution.md](https://github.com/star7th/showdoc/blob/master/documentation/en/Development&Contribution.md)\n  \n\n### Copyright \n\n ShowDoc is issued complying with Apache2 Open Source License, and it is for free use. \n \n Copyright ©  star7th \n \n \n E-mail: [xing7th](mailto:xing7th@gmail.com)\n \n All rights reserved. \n \n"
  },
  {
    "path": "documentation/zh-CN/README.md",
    "content": "﻿#### ShowDoc是什么\n\n- 每当接手一个他人开发好的模块或者项目，看着那些没有写注释的代码，我们都无比抓狂。文档呢？！文档呢？！**Show me the doc  ！！**   \n \n- 程序员都很希望别人能写技术文档，而自己却很不希望要写文档。因为写文档需要花大量的时间去处理格式排版，想着新建的word文档放在哪个目录等各种非技术细节。\n\n- word文档零零散散地放在团队不同人那里，需要文档的人基本靠吼，吼一声然后上qq或者邮箱接收对方丢过来的文档。这种沟通方式当然可以，只是效率不高。   \n \n- ShowDoc就是一个非常适合IT团队的在线文档分享工具，它可以加快团队之间沟通的效率。   \n\n#### 它可以用来做什么\n\n- ##### API文档（ [查看Demo](http://www.showdoc.cc/2)）  \n\n - 随着移动互联网的发展，BaaS（后端即服务）越来越流行。服务端提供API，APP端或者网页前端便可方便调用数据。用ShowDoc可以非常方便快速地编写出美观的API文档。\n\n- ##### 数据字典（ [查看Demo](http://www.showdoc.cc/1)）  \n\n - 一份好的数据字典可以很方便地向别人说明你的数据库结构，如各个字段的释义等。  \n- ##### 说明文档 （ [查看Demo](http://www.showdoc.cc/3)）  \n\n - 你完全可以使用showdoc来编写一些工具的说明书,也可以编写一些技术规范说明文档以供团队查阅\n\n#### 它都有些什么功能\n  \n- ##### 分享与导出\n  - 响应式网页设计，可将项目文档分享到电脑或移动设备查看。同时也可以将项目导出成word文件，以便离线浏览。\n\n- ##### 权限管理\n  - 公开项目与私密项目 \n   - ShowDoc上的项目有公开项目和私密项目两种。公开项目可供任何登录与非登录的用户访问，而私密项目则需要输入密码验证访问。密码由项目创建者设置。\n  - 项目转让  \n       - 项目创建者可以自由地把项目转让给网站的其他用户。 \n  - 项目成员    \n     - 你可以很方便地为ShowDoc的项目添加、删除项目成员。项目成员可以对项目进行编辑，但不可转让或删除项目（只有项目创建者才有权限）\n  - 团队管理\n   - 利用showdoc的团队功能你可以更好地进行团队协作\n   \n- ##### 编辑功能\n  - markdown编辑     \n     - ShowDoc采用markdown编辑器，无论是编辑还是阅读体验都极佳很棒。如果你不了解Markdown，请在搜索引擎搜索\"认识与入门 Markdown\"\n  \n  - 模板插入   \n     - 在ShowDoc的编辑页面，点击编辑器上方的按钮可方便地插入API接口模板和数据字典模板。插入模板后，剩下的就是改动数据了，省去了很多编辑的力气。 \n  - 历史版本   \n     - ShowDoc为页面提供历史版本功能，你可以方便地把页面恢复到之前的版本。\n\n\n#### 使用在线的ShowDoc\n\n- 如果你没有自己的服务器，但又想使用ShowDoc作为分档分享工具，你可以使用在线的ShowDoc   [http://www.showdoc.cc](http://www.showdoc.cc)\n- 在线showdoc作为在线服务会长期维护，请放心托管数据\n\n\n#### 部署到自己的服务器\n\n- ShowDoc部署手册请参考：[https://www.showdoc.cc/help?page_id=13732](https://www.showdoc.cc/help?page_id=13732)\n\n- 开源地址：https://github.com/star7th/showdoc 。若觉得showdoc好用，不妨点个star。良好的关注度和参与度有助于开源项目的长远发展。\n\n- 二次开发指引\n\n https://www.showdoc.cc/help?page_id=1385576954326448\n \n#### ShowDoc交流群\n\n- ShowDoc使用交流qq群\n 交流群①：564671853（已满）\n 交流群②：174709989（已满）\n 交流群③：667194478"
  },
  {
    "path": "index.php",
    "content": "<?php\n\n// PHP 版本检测（开源版要求 PHP >= 7.4）\nif (version_compare(PHP_VERSION, '7.4.0', '<')) {\n    die('ShowDoc requires PHP >= 7.4.0. Current version: ' . PHP_VERSION);\n}\n\n// ===== 禁止爬虫和搜索引擎访问 =====\nif (PHP_SAPI !== 'cli') {\n    require __DIR__ . '/server/app/Common/BotDetector.php';\n    \\App\\Common\\BotDetector::blockBot();\n}\n// ===== 爬虫拦截结束 =====\n\n// ===== 安装状态检测（参考旧版逻辑）=====\nif (PHP_SAPI !== 'cli') {\n    // 不存在安装文件夹的，表示已经安装过\n    if (!file_exists(\"./install\")) {\n        header(\"location:./web/#/\");\n        exit();\n    }\n\n    // 如果 install 存在 && install.lock 存在 && install 可写 && install.lock 可写\n    if (file_exists(\"./install\") && file_exists(\"./install/install.lock\") && newIsWriteable(\"./install\") && newIsWriteable(\"./install/install.lock\")) {\n        header(\"location:./web/#/\");\n        exit();\n    }\n    \n    // 其他情况都跳转到安装页面\n    header(\"location:./install/index.php\");\n    exit();\n}\n\n/**\n * 判断 文件/目录 是否可写（取代系统自带的 is_writeable 函数）\n * 参考旧版逻辑\n *\n * @param string $file 文件/目录\n * @return boolean\n */\nfunction newIsWriteable($file)\n{\n    if (is_dir($file)) {\n        $dir = $file;\n        if ($fp = @fopen(\"$dir/test.txt\", 'w')) {\n            @fclose($fp);\n            @unlink(\"$dir/test.txt\");\n            $writeable = 1;\n        } else {\n            $writeable = 0;\n        }\n    } else {\n        if ($fp = @fopen($file, 'a+')) {\n            @fclose($fp);\n            $writeable = 1;\n        } else {\n            $writeable = 0;\n        }\n    }\n\n    return $writeable;\n}\n\nrequire __DIR__ . '/server/vendor/autoload.php';\n\nuse DI\\Container;\nuse Slim\\Factory\\AppFactory;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\nuse Dotenv\\Dotenv;\n\n// CLI 模式下支持：php index.php / 或 /uid/xxx\nif (PHP_SAPI === 'cli') {\n    $path = $argv[1] ?? '/';\n    if ($path !== '' && $path[0] !== '/') {\n        $path = '/' . $path;\n    }\n    $_SERVER['REQUEST_METHOD'] = $_SERVER['REQUEST_METHOD'] ?? 'GET';\n    $_SERVER['REQUEST_URI'] = $path;\n    $scriptBase = basename(__FILE__);\n    $_SERVER['SCRIPT_NAME'] = '/' . $scriptBase;\n}\n\n// 兼容查询参数路由：?s=/user/login 形式的路由（仅限 Web 环境）\n// 开源版主要使用此方式\nif (PHP_SAPI !== 'cli' && isset($_GET['s']) && $_GET['s'] !== '') {\n    $path = $_GET['s'];\n    if ($path !== '' && $path[0] !== '/') {\n        $path = '/' . $path;\n    }\n    // 设置 REQUEST_URI、PATH_INFO 和 SCRIPT_NAME，确保 Slim 能正确解析路径\n    $_SERVER['REQUEST_URI'] = $path;\n    $_SERVER['PATH_INFO'] = $path;\n    $_SERVER['SCRIPT_NAME'] = '/index.php';\n    // 清除查询字符串，避免 Slim 重复处理\n    $_SERVER['QUERY_STRING'] = '';\n    unset($_GET['s']);\n}\n\n// 加载根目录 .env（如果存在），供 Database 等使用 getenv() 读取配置\nif (is_file(__DIR__ . '/.env')) {\n    Dotenv::createImmutable(__DIR__)->load();\n}\n\n// 设置默认时区，优先使用环境变量 APP_TIMEZONE，默认为上海时间\n$timezone = getenv('APP_TIMEZONE') ?: 'Asia/Shanghai';\n@date_default_timezone_set($timezone);\n\n// 定义日志路径常量（兼容旧代码，必须在命名空间之前定义）\nif (!defined('LOG_PATH')) {\n    // 计算 Runtime 目录路径（位于 app 目录下）\n    $appPath = __DIR__ . DIRECTORY_SEPARATOR . 'server' . DIRECTORY_SEPARATOR . 'app' . DIRECTORY_SEPARATOR;\n    $runtimePath = $appPath . 'Runtime' . DIRECTORY_SEPARATOR;\n    if (!is_dir($runtimePath)) {\n        @mkdir($runtimePath, 0755, true);\n    }\n    $logPath = $runtimePath . 'Logs' . DIRECTORY_SEPARATOR;\n    if (!is_dir($logPath)) {\n        @mkdir($logPath, 0755, true);\n    }\n    define('LOG_PATH', $logPath);\n}\n\n// 启用原生 Session，供验证码等接口使用（不依赖 ThinkPHP 的 session() 封装）\nif (session_status() === PHP_SESSION_NONE) {\n    session_start();\n}\n\n// 初始化 DI 容器\n$container = new Container();\n\n// 注册服务\nrequire __DIR__ . '/server/app/Common/bootstrap.php';\nrequire __DIR__ . '/server/app/Common/container.php';\n\nAppFactory::setContainer($container);\n$app = AppFactory::create();\n\n$app->addRoutingMiddleware();\n\n// 开源版开启错误显示，方便用户排查问题\n$errorMiddleware = $app->addErrorMiddleware(true, true, true);\n$errorHandler = $errorMiddleware->getDefaultErrorHandler();\n$errorHandler->forceContentType('text/html');\n\n// 首页：/\n$app->get('/', function (Request $request, Response $response) use ($container) {\n    $controller = $container->get(\\App\\Home\\Controller\\IndexController::class);\n    return $controller->index($request, $response);\n});\n\n// 项目页：/123\n$app->get('/{item_id:\\\\d+}', function (Request $request, Response $response, array $args) use ($container) {\n    $request = $request->withAttribute('item_id', (int) $args['item_id']);\n    $controller = $container->get(\\App\\Home\\Controller\\ItemController::class);\n    return $controller->show($request, $response);\n});\n\n// 单页：/page/456\n$app->get('/page/{page_id:\\\\d+}', function (Request $request, Response $response, array $args) use ($container) {\n    $request = $request->withAttribute('page_id', (int) $args['page_id']);\n    $controller = $container->get(\\App\\Home\\Controller\\PageController::class);\n    return $controller->show($request, $response);\n});\n\n// 用户主页：/uid/username\n$app->get('/uid/{username}', function (Request $request, Response $response, array $args) use ($container) {\n    $request = $request->withAttribute('username', $args['username']);\n    $controller = $container->get(\\App\\Home\\Controller\\UserController::class);\n    return $controller->profile($request, $response);\n});\n\n// 个性域名项目：/mydomain（只匹配单段路径，不包含斜杠）\n$app->get('/{domain:[a-zA-Z0-9_-]+}', function (Request $request, Response $response, array $args) use ($container) {\n    $request = $request->withAttribute('domain', $args['domain']);\n    $controller = $container->get(\\App\\Home\\Controller\\DomainController::class);\n    return $controller->show($request, $response);\n});\n\n// CLI 命令路由：home/common/repasswd（重置管理员密码）\n$app->any('/home/common/repasswd', function (Request $request, Response $response) use ($container) {\n    $controller = $container->get(\\App\\Home\\Controller\\CommonController::class);\n    return $controller->repasswd($request, $response);\n});\n\n// 兜底路由：所有其他路径（多段路径，如 /user/login）都返回 Vue 应用\n$app->any('/{path:.*}', function (Request $request, Response $response) {\n    // 开源版前端构建产物在 web/ 目录下，而不是使用主版的 web.html\n    // 这里统一把所有未被前面路由匹配的路径交给前端 SPA 处理\n    return $response\n        ->withHeader('Location', './web/#/')\n        ->withStatus(302);\n});\n\n$app->run();\n"
  },
  {
    "path": "install/ajax.php",
    "content": "<?php\n/**\n * ShowDoc安装脚本 - AJAX处理\n */\nini_set(\"display_errors\", \"Off\");\nerror_reporting(E_ALL | E_STRICT);\nheader(\"Content-type: text/html; charset=utf-8\"); \ninclude(\"common.php\");\n\n// 获取请求语言\n$lang = isset($_REQUEST['lang']) ? $_REQUEST['lang'] : \"zh\";\n\n// 检查安装锁\nif (is_install_locked()) {\n    ajax_out(L(\"lock\"), 10099);\n}\n\n// 检查环境\n$check_result = check_environment();\nif (!$check_result['status']) {\n    ajax_out(implode('<br>', $check_result['messages']), 10095);\n}\n\n// 额外检查英文环境下需要的文件权限\nif ($lang == 'en') {\n    $en_files = [\n        \"../web/index.html\" => L(\"not_writable_web_docconfig\"),\n        \"../web_src/index.html\" => L(\"not_writable_web_src_docconfig\")\n    ];\n    \n    foreach ($en_files as $file => $message) {\n        if (!new_is_writeable($file)) {\n            ajax_out($message, 10096);\n        }\n    }\n}\n\n// 设置安装配置\nif (!set_install_config($lang)) {\n    ajax_out(L(\"install_config_not_writable\"), 10001);\n}\n\n// 清除缓存\nclear_runtime();\n\n// 设置安装锁\nif (!set_install_lock()) {\n    ajax_out(L(\"install_config_not_writable\"), 10001);\n}\n\n// 安装成功\najax_out(L(\"install_success\"));\n\n\n"
  },
  {
    "path": "install/common.php",
    "content": "<?php\n\n/**\n * ShowDoc安装脚本 - 通用函数\n */\n\n/**\n * 获取语言设置\n * @return array 语言数组\n */\nfunction lang(){\n  $lang = isset($_REQUEST['lang']) ? $_REQUEST['lang'] : \"zh\";\n  if (in_array($lang, ['zh', 'en'])) {\n    return include(\"lang.\".$lang.\".php\");\n  }\n  return include(\"lang.zh.php\"); // 默认使用中文\n}\n\n/**\n * 获取语言字符串\n * @param string $field 语言键值\n * @return string 对应的语言文本\n */\nfunction L($field){\n  if (!isset($GLOBALS['lang_array'])) {\n    $GLOBALS['lang_array'] = lang();\n  }\n  return isset($GLOBALS['lang_array'][$field]) ? $GLOBALS['lang_array'][$field] : $field;\n}\n\n/**\n * 判断文件/目录是否可写\n * @param string $file 文件/目录路径\n * @return boolean 是否可写\n */\nfunction new_is_writeable($file) {\n  if (is_dir($file)){\n    $dir = $file;\n    if ($fp = @fopen(\"$dir/test.txt\", 'w')) {\n      @fclose($fp);\n      @unlink(\"$dir/test.txt\");\n      return true;\n    }\n    return false;\n  } else {\n    if ($fp = @fopen($file, 'a+')) {\n      @fclose($fp);\n      return true;\n    }\n    return false;\n  }\n}\n\n/**\n * 检查文件/目录权限并返回错误信息\n * @param string $path 路径\n * @param string $errorMessage 错误信息\n * @return array [bool $status, string $message]\n */\nfunction check_writable($path, $errorMessage) {\n  if (!new_is_writeable($path)) {\n    return [false, $errorMessage];\n  }\n  return [true, ''];\n}\n\n/**\n * 递归清除运行时缓存\n * @param string $path 目录路径\n * @return boolean 是否成功\n */\nfunction clear_runtime($path = \"../server/app/Runtime\"){  \n  if (!is_dir($path)) {  \n    return false;  \n  }  \n\n  $fh = opendir($path);  \n  while(($row = readdir($fh)) !== false){  \n    if ($row == '.' || $row == '..' || $row == 'index.html') {  \n      continue;  \n    }  \n\n    $fullPath = $path.'/'.$row;\n    if (!is_dir($fullPath)) {\n      unlink($fullPath);  \n    } else {\n      clear_runtime($fullPath);\n    }\n  }  \n  closedir($fh);\n  return true;  \n}\n\n/**\n * 输出JSON格式的响应并退出\n * @param string $message 消息\n * @param int $error_code 错误代码\n */\nfunction ajax_out($message, $error_code = 0) {\n  echo json_encode([\n    \"error_code\" => $error_code,\n    \"error_message\" => $message\n  ]);\n  exit();\n}\n\n/**\n * 替换文件内容\n * @param string $file 文件路径\n * @param string $from 要替换的内容\n * @param string $to 替换后的内容\n * @return boolean 是否成功\n */\nfunction replace_file_content($file, $from, $to) {\n  if (!file_exists($file)) {\n    return false;\n  }\n  \n  $content = file_get_contents($file);\n  $content = str_replace($from, $to, $content);\n  return file_put_contents($file, $content) !== false;\n}\n\n/**\n * 检查环境要求\n * @return array ['status' => bool, 'messages' => string[]]\n */\nfunction check_environment() {\n  $result = [\n    'status' => true,\n    'messages' => []\n  ];\n\n  // 检测PHP版本（开源版要求 PHP >= 7.4）\n  if (version_compare(PHP_VERSION, '7.4.0', '<')) {\n    $result['status'] = false;\n    $result['messages'][] = L('require_php_version');\n  }\n\n  // 检测目录权限\n  $directories = [\n    './' => L(\"not_writable_install\"),\n    '../Public/Uploads' => L(\"not_writable_upload\"),\n    '../server/app/Runtime' => L(\"not_writable_server_runtime\"),\n    '../Sqlite' => L(\"not_writable_sqlite\"),\n    '../Sqlite/showdoc.db.php' => L(\"not_writable_sqlite_db\")\n  ];\n\n  foreach ($directories as $dir => $message) {\n    if (!new_is_writeable($dir)) {\n      $result['status'] = false;\n      $result['messages'][] = $message;\n    }\n  }\n\n  // 检查扩展\n  $extensions = [\n    'gd' => '请安装php-gd',\n    'mbstring' => '请安装php-mbstring',\n    'zlib' => '请安装php-zlib',\n    'PDO' => '请安装php-pdo'\n  ];\n\n  foreach ($extensions as $ext => $message) {\n    if ($ext === 'PDO') {\n      if (!extension_loaded(\"PDO\") && !extension_loaded(\"pdo\")) {\n        $result['status'] = false;\n        $result['messages'][] = $message;\n      }\n    } else if (!extension_loaded($ext)) {\n      $result['status'] = false;\n      $result['messages'][] = $message;\n    }\n  }\n\n  return $result;\n}\n\n/**\n * 检查安装锁定状态\n * @return boolean 是否已锁定\n */\nfunction is_install_locked() {\n  return file_exists('./install.lock');\n}\n\n/**\n * 设置安装配置\n * @param string $lang 语言\n * @return boolean 是否成功\n */\nfunction set_install_config($lang = 'zh') {\n  $default_lang = ($lang == 'en') ? 'en-us' : 'zh-cn';\n  \n  // 1. 修改HTML文件中的语言设置\n  if ($lang == 'en') {\n    replace_file_content(\"../web/index.html\", \"zh-cn\", \"en\");\n    replace_file_content(\"../web_src/index.html\", \"zh-cn\", \"en\");\n    // 清除缓存\n    clear_runtime();\n    \n  }\n\n  return true;\n  \n\n}\n\n/**\n * 设置安装锁\n * @return boolean 是否成功\n */\nfunction set_install_lock() {\n  return file_put_contents(\"./install.lock\", \"https://www.showdoc.com.cn/\") !== false;\n}\n"
  },
  {
    "path": "install/index.php",
    "content": "<?php\n/**\n * ShowDoc安装脚本\n */\ninclude(\"common.php\");\n\n// 执行环境检查\n$checkResult = check_environment();\nif (!$checkResult['status']) {\n    echo implode('<br>', $checkResult['messages']);\n    exit();\n}\n?>\n\n<!DOCTYPE html>\n<html lang=\"zh\">\n  <head>\n    <meta charset=\"utf-8\">\n    <title>ShowDoc</title>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <meta name=\"description\" content=\"ShowDoc installation page\">\n    <meta name=\"author\" content=\"ShowDoc\">\n    <style>\n      :root {\n        --primary-color: #24292e;\n        --text-white: #fff;\n        --text-dark: #000;\n        --transition-time: 0.5s;\n      }\n      \n      * {\n        box-sizing: border-box;\n        margin: 0;\n        padding: 0;\n      }\n      \n      html, body {\n        height: 100%;\n        font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif;\n      }\n      \n      .container {\n        display: flex;\n        height: 100%;\n        width: 100%;\n        position: absolute;\n      }\n\n      .flex-item {\n        display: inline-flex;\n        justify-content: center;\n        align-items: center;\n        flex-direction: column;\n        height: 100%;\n        transition: all var(--transition-time) ease;\n      }\n        \n      .left {\n        width: 50%;\n        background-color: var(--text-white);\n      }\n      \n      .right {\n        width: 50%;\n        background-color: var(--primary-color);\n        color: var(--text-white);\n      }\n      \n      .lang-text {\n        font-size: 30px;\n        cursor: pointer;\n        padding: 20px;\n        border-radius: 4px;\n        transition: all 0.3s ease;\n      }\n      \n      .lang-text:hover {\n        transform: scale(1.05);\n      }\n      \n      .left a {\n        color: var(--text-dark);\n      }\n\n      .right a {\n        color: var(--text-white);\n      }\n      \n      .en-tips, .zh-tips {\n        display: none;\n        font-size: 20px;\n        line-height: 1.5;\n        text-align: center;\n        padding: 20px;\n      }\n      \n      a {\n        text-decoration: none;\n        font-weight: bold;\n      }\n      \n      a:hover {\n        text-decoration: underline;\n      }\n      \n      @media (max-width: 768px) {\n        .container {\n          flex-direction: column;\n        }\n        \n        .left, .right {\n          width: 100%;\n          height: 50%;\n        }\n      }\n    </style>\n  </head>\n  <body>\n    <div class=\"container\">\n      <div class=\"flex-item left\">\n        <div class=\"lang-text\" id=\"en\">\n          Choose language: English &nbsp; →\n        </div>\n\n        <div class=\"en-tips\">\n          Initialization successful. The default administrator account password is showdoc / 123456.<br>\n          After logging in, you can see the management background entrance in the upper right corner.<br>\n          <a href=\"../web/\">Click to enter the home page</a>\n        </div>\n      </div>\n      \n      <div class=\"flex-item right\">\n        <div class=\"lang-text\" id=\"zh\">\n          选择语言：中文 &nbsp; →\n        </div>\n        \n        <div class=\"zh-tips\">\n          初始化成功。默认管理员账户密码是showdoc/123456。<br>\n          登录后，在右上角可以看到管理后台入口。<a href=\"../web/\">点击进入首页</a>\n        </div>\n      </div>\n    </div>\n\n    <script>\n      document.addEventListener('DOMContentLoaded', function() {\n        // 获取DOM元素\n        const enButton = document.getElementById('en');\n        const zhButton = document.getElementById('zh');\n        const leftPane = document.querySelector('.left');\n        const rightPane = document.querySelector('.right');\n        const enTips = document.querySelector('.en-tips');\n        const zhTips = document.querySelector('.zh-tips');\n        \n        // 事件监听\n        enButton.addEventListener('click', function() {\n          handleInstall('en');\n        });\n        \n        zhButton.addEventListener('click', function() {\n          handleInstall('zh');\n        });\n        \n        /**\n         * 处理安装请求\n         * @param {string} lang - 语言代码\n         */\n        function handleInstall(lang) {\n          // 显示加载状态\n          const button = lang === 'en' ? enButton : zhButton;\n          const originalText = button.innerHTML;\n          button.innerHTML = lang === 'en' ? 'Installing...' : '正在安装...';\n          button.style.opacity = '0.7';\n          \n          // 创建XHR请求\n          const xhr = new XMLHttpRequest();\n          xhr.open('GET', `ajax.php?lang=${lang}`, true);\n          xhr.responseType = 'json';\n          \n          xhr.onload = function() {\n            if (xhr.status === 200) {\n              const data = xhr.response;\n              if (data.error_code === 0) {\n                lang === 'en' ? showEnTips() : showZhTips();\n              } else {\n                button.innerHTML = originalText;\n                button.style.opacity = '1';\n                alert(data.error_message);\n              }\n            } else {\n              button.innerHTML = originalText;\n              button.style.opacity = '1';\n              alert(lang === 'en' ? 'Request failed, please try again' : '请求失败，请重试');\n            }\n          };\n          \n          xhr.onerror = function() {\n            button.innerHTML = originalText;\n            button.style.opacity = '1';\n            alert(lang === 'en' ? 'Network error, please check your connection' : '网络错误，请检查连接');\n          };\n          \n          xhr.send();\n        }\n        \n        /**\n         * 显示英文提示\n         */\n        function showEnTips() {\n          rightPane.style.display = 'none';\n          leftPane.style.width = '100%';\n          enButton.style.display = 'none';\n          enTips.style.display = 'block';\n        }\n        \n        /**\n         * 显示中文提示\n         */\n        function showZhTips() {\n          leftPane.style.display = 'none';\n          rightPane.style.width = '100%';\n          zhButton.style.display = 'none';\n          zhTips.style.display = 'block';\n        }\n      });\n    </script>\n  </body>\n</html>"
  },
  {
    "path": "install/lang.en.php",
    "content": "<?php\nreturn array(\n  \n  \"install_title\"=>'Install ShowDoc',\n  \"use_sqlite\"=>'Use Sqlite Database',\n  \"use_mysql\"=>'Use Mysql Database',\n  \"server_address\"=>'Server address (e.g: localhost)',\n  \"server_port\"=>'Port(e.g:3306)',\n  \"db_name\"=>'Database Name(e.g:showdoc)',\n  \"db_user\"=>'Database Username',\n  \"db_password\"=>' Database Password',\n  \"sqlite_tips\"=>'Sqlite has supported by PHP and you just need to click the Go buttun',\n  \"go\"=>'Go',\n  \"install_success_help\"=>'Installation success!The password of the default administrator account is showdoc/123456 ,After login, you can see the management backstage access in the upper right corner.In addition, it is strongly recommended to modify the administrator password .<br>More help :<a href=\"https://www.showdoc.cc/help-en\" target=\"_blank\">https://www.showdoc.cc/help-en</a>',\n  \"home\"=>'Website Home',\n  \"FAQ\"=>'FAQ',\n\n  \n  \"lock\"=>'ShowDoc has been installed！If you want to reinstall,please delete file /install/install.lock ',\n  \"not_writable_install\"=>' Directory install is not writable !',\n  \"not_writable_upload\"=>'Directory Public/Uploads/  is not writable !',\n  \"not_writable_runtime\"=>'Directory server/app/Runtime is not writable !',\n  \"not_writable_server_runtime\"=>'Directory server/app/Runtime is not writable !',\n  \"not_writable_config\"=>'File server/app/Common/Conf/config.php is not writable !',\n  \"not_writable_sqlite\"=>'Directory Sqlite is not writable !',\n  \"not_writable_sqlite_db\"=>'File Sqlite/showdoc.db.php is not writable !',\n  \"not_writable_web_docconfig\"=>'File web/index.html is not writable !',\n  \"not_writable_web_src_docconfig\"=>'File web_src/index.html is not writable !',\n  \"install_success\"=>'Installation success!Please delete the /install directory, avoid the script to be executed again',\n  \"install_config_not_writable\"=>'Fail to write config file ',\n  \"db_wrong\"=>'Database connection error',\n  \"db_has_data\"=>'Database tables already exists,please clear up and try again',\n  \"create_table_fail\"=>'Fail to create table',\n  \"install_config_not_writable\"=>'Fail to write config file',\n\n  \"require_php_version\" => \"require PHP >= 7.4.0\",\n  );\n"
  },
  {
    "path": "install/lang.zh.php",
    "content": "<?php\nreturn array(\n\n  \"install_title\"=>'安装ShowDoc',\n  \"use_sqlite\"=>'使用Sqlite数据库',\n  \"use_mysql\"=>'使用Mysql数据库',\n  \"server_address\"=>'服务器地址，一般为localhost',\n  \"server_port\"=>'端口，一般为3306',\n  \"db_name\"=>'数据库名，建议数据库名为showdoc',\n  \"db_user\"=>'数据库用户名',\n  \"db_password\"=>'数据库密码',\n  \"sqlite_tips\"=>'PHP内置支持Sqlite数据库，你无须再配置数据库，直接点击开始即可',\n  \"go\"=>'开始',\n  \"install_success_help\"=>'安装成功！默认管理员账户密码是showdoc/123456。登录后，在右上角可以看到管理后台入口。此外，强烈建议修改管理员初始密码。若再遇到问题，可参考ShowDoc帮助文档：<a href=\"https://www.showdoc.cc/help\" target=\"_blank\">https://www.showdoc.cc/help</a>',\n  \"home\"=>'进入网站首页',\n  \"FAQ\"=>'常见问题',\n\n\n  \"lock\"=>'本程序已经安装过！如果要解除安装锁定，则可删除install目录下的install.lock文件后再重新访问本页面',\n  \"not_writable_install\"=>'请赋予 install 目录以可写权限！',\n  \"not_writable_upload\"=>'请赋予 Public/Uploads/ 目录以可写权限！',\n  \"not_writable_runtime\"=>'请赋予 server/app/Runtime 目录以可写权限！',\n  \"not_writable_server_runtime\"=>'请赋予 server/app/Runtime 目录以可写权限！',\n  \"not_writable_config\"=>'请赋予 server/app/Common/Conf/config.php 文件以可写权限！',\n  \"not_writable_sqlite\"=>'请赋予 Sqlite 目录以可写权限！',\n  \"not_writable_sqlite_db\"=>'请赋予 Sqlite/showdoc.db.php 以可写权限！',\n  \"not_writable_web_docconfig\"=>'请赋予 web/index.html 以可写权限！',\n  \"not_writable_web_src_docconfig\"=>'请赋予 web_src/index.html 以可写权限！',\n  \"install_success\"=>'安装成功！建议删除install目录，以免安装脚本被再次执行。',\n  \"install_config_not_writable\"=>'安装失败，配置文件写入错误！',\n  \"db_wrong\"=>'数据库链接错误，请检查配置信息是否填写正确',\n  \"db_has_data\"=>'检测到该数据库已经存在数据。请清理后再重试',\n  \"create_table_fail\"=>'创建数据库表失败！',\n  \"install_config_not_writable\"=>'安装失败，配置文件写入错误！',\n\n  \"require_php_version\" => \"需要PHP7.4.0以上版本\",\n  );"
  },
  {
    "path": "install/non_interactive.php",
    "content": "<?php\n/**\n * ShowDoc安装脚本 - 非交互式安装\n */\nini_set(\"display_errors\", \"Off\");\nerror_reporting(E_ALL | E_STRICT);\nheader(\"Content-type: text/html; charset=utf-8\"); \ninclude(\"common.php\");\n\n// 获取语言\n$lang = isset($_REQUEST['lang']) ? $_REQUEST['lang'] : \"zh\";\n\n// 检查是否已安装\nif (is_install_locked()) {\n  echo L(\"lock\").\"\\n\";\n  exit();\n}\n\n// 检查环境\n$check_result = check_environment();\nif (!$check_result['status']) {\n  echo implode(\"\\n\", $check_result['messages']).\"\\n\";\n  exit();\n}\n\n// 设置安装配置\nif (set_install_config($lang)) {\n  // 设置安装锁\n  if (set_install_lock()) {\n    echo 'install success !!!'.\"\\n\";\n  } else {\n    echo L(\"install_config_not_writable\").\"\\n\";\n  }\n} else {\n  echo L(\"install_config_not_writable\").\"\\n\";\n}\n\n\nfunction user_sqlite(){\n        clear_runtime();//清除缓存\n        write_js_lang();\n        \n        $ret = write_home_config();\n        if ($ret) {\n          file_put_contents(\"./install.lock\",\"https://www.showdoc.cc/\");\n            echo 'install success !!!'.\"\\n\";\n        }else{\n            echo \"\\n\".L(\"not_writable_home_config\").\"\\n\";\n        }\n}\n\n\nfunction write_home_config(){\n  $lang = $_REQUEST['lang'] ? $_REQUEST['lang'] :\"zh\";\n  if ($lang == 'en') {\n    $DEFAULT_LANG = 'en-us';\n  }else{\n    $DEFAULT_LANG = 'zh-cn';\n  }\n        $config = \"<?php \";\n        $config .= \"\nreturn array(\n  //'配置项'=>'配置值'\n    'DB_TYPE'   => 'Sqlite', \n    'DB_NAME'   => './Sqlite/showdoc.db.php', \n    'LANG_SWITCH_ON' => true,   // 开启语言包功能\n    'LANG_AUTO_DETECT' => false, // 自动侦测语言 开启多语言功能后有效\n    'DEFAULT_LANG' => '{$DEFAULT_LANG}', // 默认语言\n    'LANG_LIST'        => 'zh-cn,en-us', // 允许切换的语言列表 用逗号分隔\n    'VAR_LANGUAGE'     => 'l', // 默认语言切换变量\n);\";\n\n  // 新架构不再需要 Home/Conf/config.php，直接返回成功\n  $ret = true;\n    return $ret ;\n}\n\nfunction write_js_lang(){\n    $lang = $_REQUEST['lang'] ? $_REQUEST['lang'] :\"zh\";\n    if ($lang == 'en') {\n       replace_file_content(\"../web/index.html\",\"zh-cn\",\"en\") ;\n       replace_file_content(\"../web_src/index.html\",\"zh-cn\",\"en\") ;\n    }\n    \n}\n\n"
  },
  {
    "path": "mcp.php",
    "content": "<?php\n\n/**\n * ShowDoc MCP 独立入口\n * \n * MCP（Model Context Protocol）服务入口，用于 AI 编辑器集成。\n * 支持 Cursor、Windsurf、Cline、Claude Desktop 等 AI 编辑器。\n * \n * 访问地址：https://your-showdoc.com/mcp.php\n * \n * MCP 使用 JSON-RPC 2.0 协议，参数通过 HTTP POST 请求体传递：\n * {\n *   \"jsonrpc\": \"2.0\",\n *   \"id\": 1,\n *   \"method\": \"tools/call\",\n *   \"params\": {\n *     \"name\": \"get_page\",\n *     \"arguments\": { \"page_id\": 123 }\n *   }\n * }\n * \n * 认证方式：Authorization: Bearer user_abc123...\n * \n * @package ShowDoc\n * @author  ShowDoc Team\n * @since   2026-03-18\n */\n\n// MCP 独立入口，主版和开源版统一使用\n// 将请求路由到 MCP 控制器\n$_SERVER['REQUEST_URI'] = '/server/Api/Mcp/index';\n\n// --- 极简兼容：应付一下客户端的 GET 请求 ---\n$method = $_SERVER['REQUEST_METHOD'];\nif ($method === 'GET') {\n  header('Content-Type: text/event-stream');\n  header('Cache-Control: no-cache');\n  echo \": connected\\n\\n\"; // 发一个空注释就够了\n  ob_flush();\n  flush();\n  // 直接退出，不需要保持连接（视情况而定）\n  exit;\n}\n\n// 注意：不覆盖 REQUEST_METHOD，保持客户端原始方法（POST）\n// 注意：不覆盖 POST body，MCP 参数在请求体中传递\n\n// 加载主入口文件\nrequire __DIR__ . '/server/index.php';\n"
  },
  {
    "path": "mock/.gitignore",
    "content": "logs/\nnpm-debug.log\nyarn-error.log\nnode_modules/\nyarn.lock\ncoverage/\n.idea/\nrun/\n.DS_Store\n*.sw*\n*.un~\ntypings/\n.nyc_output/\n"
  },
  {
    "path": "mock/index.js",
    "content": "var http = require('http');\nvar fs = require('fs');\nvar path = require('path');\nvar url = require('url');\nvar querystring = require('querystring');\nvar server = http.createServer();\n\nvar Mock = require('mockjs');\nvar util = require('util');\n\n// 监听客服端请求\nserver.on('request',function (req,res) {\n    //console.log(req.url + req.method);\n\tif (req.url.indexOf('/mock') === 0 && req.method === 'POST') {\n\n        var postData = '';\n        // 18. 给req对象注册一个接收数据的事件\n        req.on('data',function (chuck) {  \n            /**data事件详解\n             * 浏览器每发送一次数据包（chuck），该函数会调用一次。\n             * 该函数会调用多次，调用的次数是由数据和网速限制的\n             */\n            // 19. 每次发送的都数据都叠加到postData里面\n            postData += chuck;\n        })\n        // 20. 到post请求数据发完了之后会执行一个end事件，这个事件只执行一次\n        req.on('end', function () {\n            // 21. 此时服务器成功接受了本次post请求的参数\n            // post请求最终获取到的数据就是url协议组成结构中的query部分\n            //console.log(postData);\n            // 22. 使用querystring模块来解析post请求\n            /**\n             * querystring详解\n             * 参数：要解析的字符串\n             * 返回值：解析之后的对象。\n             */\n            var postObjc = querystring.parse(postData);\n            // 23. 打印出post请求参数，\n            //console.log(postObjc.template);\n            var data ;\n\t\t    try{\n\t\t    \tdata = JSON.stringify( Mock.mock(JSON.parse(postObjc.template)) );\n\n\t\t    }catch(e){\n\t\t    \tdata = '为了服务器安全，只允许符合json语法的字符串'\n\t\t    }\n\t\t    res.end(data);\n        })\n    }\n})\n\n// n. 启用服务器\nserver.listen(7123,function () { console.log('mock服务启用成功'); })\n"
  },
  {
    "path": "mock/package.json",
    "content": "{\n  \"name\": \"mockServer\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"private\": true,\n  \"egg\": {\n    \"declarations\": true\n  },\n  \"dependencies\": {\n    \"mockjs\": \"^1.1.0\",\n    \"pm2\": \"^5.4.3\"\n  },\n  \"engines\": {\n    \"node\": \">=10.0.0\"\n  },\n  \"scripts\": {\n    \"start\": \"npm run pm2 start index.js  \",\n    \"stop\": \"npm run pm2 stop index.js  \",\n    \"pm2-docker\": \"node ./node_modules/pm2/bin/pm2-docker\",\n    \"pm2\": \"node ./node_modules/pm2/bin/pm2\"\n  },\n  \"ci\": {\n    \"version\": \"10\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"\"\n  },\n  \"author\": \"star7th\",\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "robots.txt",
    "content": "User-agent: * \nDisallow: /\n"
  },
  {
    "path": "server/Application/Api/Common/index.html",
    "content": " "
  },
  {
    "path": "server/Application/Api/Conf/config.php",
    "content": "<?php \nreturn array(\n\t//'配置项'=>'配置值'\n    'LANG_SWITCH_ON' => true,   // 开启语言包功能\n    'LANG_AUTO_DETECT' => true, // 自动侦测语言 开启多语言功能后有效\n    'DEFAULT_LANG' => 'zh-cn', // 默认语言\n    'LANG_LIST'        => 'zh-cn,en-us', // 允许切换的语言列表 用逗号分隔\n    'VAR_LANGUAGE'     => 'l', // 默认语言切换变量\n\t//错误信息配置\n\t'error_codes' => array(\n\n\t\t//通用性错误 ：'错误代码'=>'英文描述'\n\t\t10101 => '未知错误',\t\t\t\t//未知错误导致请求接口失败（可能是参数缺失等问题）\n\t\t10102 => '你尚未登录',\t\t\t//你尚未登录\n\t\t10103 => '没有权限',\t\t\t//权限不够\n\n\t\t//用户类错误\n\t\t10201 => 'Username has exist',\t\t\t\t//用户名已经存在\n\t\t10202 => 'The email has exist',\t\t\t\t//注册邮箱已经存在\n\t\t10204 => 'Username or password is wrong',\t//用户名或者密码错误\n\t\t10205 => 'Wrong mobile format',\t\t\t\t//错误的手机号码格式\n\t\t10206 => 'captcha wrong or expired',\t\t//验证码错误或者过期\n\t\t10207 => ' There is no such name',\t\t//该昵称不存在\n\t\t10208 => ' 密码错误',\t\t\n\t\t10209 => ' 该用户不存在或者尚未注册',\t\t\n\t\t10210 => ' Username or password is wrong',\t//用户名或者密码错误，并且输入错误次数过多\t\n\n\t\t//项目类错误\n\t\t10301 => '没有项目访问权限',\t\t\n\t\t10302 => '没有项目管理权限',\t\t\n\t\t10303 => '不是项目创建者',\t\t\n\t\t10304 => '个性域名已经存在',\t\t\n\t\t10305 => '个性域名只能是字母或数字的组合',\t\t\n\t\t10306 => 'api_key 或 api_token 不匹配',\t\t\n\t\t10307 => ' password is wrong',\t//输入项目密码错误\t\n\t\t10308 => ' password is wrong',\t//输入项目密码错误，并且输入错误次数过多\t\n\t\t10312 => 'force login',\t// 项目被要求强制登录\t\n\t\t\n\t\t//公开广场相关错误\n\t\t10501 => '公开广场功能未开启',\t//公开广场功能未开启\n\t\t\t\t\n\t\t),\n\t'API_LOG' => false ,  //是否开启API请求日志记录。如果开启，则记录每一个API请求的参数和返回结果，会生成很多日志\n);"
  },
  {
    "path": "server/Application/Api/Conf/index.html",
    "content": " "
  },
  {
    "path": "server/Application/Api/Conf/tags.php",
    "content": "<?php\nreturn array(\n    // 添加下面一行定义即可\n    'app_begin' => array('Behavior\\CheckLangBehavior'),\n);"
  },
  {
    "path": "server/Application/Api/Controller/AdminItemController.class.php",
    "content": "<?php\n\nnamespace Api\\Controller;\n\nuse Think\\Controller;\n\nclass AdminItemController extends BaseController\n{\n\n\n    //获取所有项目列表\n    public function getList()\n    {\n        $login_user = $this->checkLogin();\n        $this->checkAdmin();\n        $item_name = I(\"item_name\");\n        $page = I(\"page/d\");\n        $count = I(\"count/d\");\n        $username = I(\"username\");\n        $is_del = I(\"is_del/d\") ? I(\"is_del/d\") : 0; // 0: 正常；1: 已删除\n        $where = $is_del == 1 ? \" is_del = 1 \" : \" is_del = 0 \";\n        $params = array();\n        if ($item_name) {\n            $like_item = safe_like($item_name);\n            $where .= \" and item_name like '%s' \";\n            $params[] = $like_item;\n        }\n        if ($username) {\n            $like_user = safe_like($username);\n            $where .= \" and username like '%s' \";\n            $params[] = $like_user;\n        }\n        // 已删除项目按删除时间倒序（使用 last_update_time 作为删除时间），正常项目按创建时间倒序\n        $order = ($is_del == 1) ? \" last_update_time desc \" : \" addtime desc \";\n        $items = $params ? D(\"Item\")->where($where, $params)->order($order)->page($page, $count)->select() : D(\"Item\")->where($where)->order($order)->page($page, $count)->select();\n        $total = $params ? D(\"Item\")->where($where, $params)->count() : D(\"Item\")->where($where)->count();\n        $return = array();\n        $return['total'] = (int)$total;\n        if ($items) {\n            foreach ($items as $key => &$value) {\n                $value['addtime'] = date(\"Y-m-d H:i:s\", $value['addtime']);\n                if ($is_del == 1) {\n                    $value['del_time'] = date(\"Y-m-d H:i:s\", intval($value['last_update_time']));\n                }\n                $value['member_num'] = D(\"ItemMember\")->where(\" item_id = '%d' \", array($value['item_id']))->count()  + D(\"TeamItemMember\")->where(\" item_id = '%d' \", array($value['item_id']))->count();\n            }\n            $return['items'] = $items;\n            $this->sendResult($return);\n        } else {\n            $this->sendResult(array());\n        }\n    }\n\n\n    //删除项目\n    public function deleteItem()\n    {\n        $login_user = $this->checkLogin();\n        $this->checkAdmin();\n        $item_id = I(\"post.item_id/d\");\n        $return = D(\"Item\")->soft_delete_item($item_id);\n        if (!$return) {\n            $this->sendError(10101);\n        } else {\n            $this->sendResult($return);\n        }\n    }\n\n    // 恢复已删除项目\n    public function recoverItem()\n    {\n        $login_user = $this->checkLogin();\n        $this->checkAdmin();\n        $item_id = I(\"post.item_id/d\");\n        if ($item_id <= 0) {\n            $this->sendError(10101, '参数错误');\n            return;\n        }\n        $item = D(\"Item\")->where(\" item_id = '%d' \", array($item_id))->find();\n        if (!$item || intval($item['is_del']) !== 1) {\n            $this->sendError(10101, '项目不存在或未被删除');\n            return;\n        }\n        // 恢复项目与页面\n        D(\"Page\")->where(\" item_id = '%d' \", array($item_id))->save(array(\"is_del\" => 0));\n        $ret = D(\"Item\")->where(\" item_id = '%d' \", array($item_id))->save(array(\"is_del\" => 0, \"last_update_time\" => time()));\n        if (!$ret) {\n            $this->sendError(10101, '恢复失败');\n            return;\n        }\n        $this->sendResult(array());\n    }\n\n    // 永久删除项目（硬删除，不可恢复）\n    public function hardDeleteItem()\n    {\n        $login_user = $this->checkLogin();\n        $this->checkAdmin();\n        $item_id = I(\"post.item_id/d\");\n        if ($item_id <= 0) {\n            $this->sendError(10101, '参数错误');\n            return;\n        }\n        $item = D(\"Item\")->where(\" item_id = '%d' \", array($item_id))->find();\n        if (!$item || intval($item['is_del']) !== 1) {\n            $this->sendError(10101, '仅允许对已删除项目执行永久删除');\n            return;\n        }\n        $ret = D(\"Item\")->delete_item($item_id);\n        if (!$ret) {\n            $this->sendError(10101, '删除失败');\n            return;\n        }\n        $this->sendResult(array());\n    }\n\n    //转让项目\n    public function attorn()\n    {\n        $login_user = $this->checkLogin();\n        $this->checkAdmin();\n        $username = I(\"post.username\");\n        $item_id = I(\"post.item_id/d\");\n\n        $item  = D(\"Item\")->where(array('item_id' => $item_id))->find();\n\n\n        $member = D(\"User\")->where(\" username = '%s' \", array($username))->find();\n\n        if (!$member) {\n            $this->sendError(10209);\n            return;\n        }\n\n        $data['username'] = $member['username'];\n        $data['uid'] = $member['uid'];\n\n\n        $id = D(\"Item\")->where(array('item_id' => $item_id))->save($data);\n\n        $return = D(\"Item\")->where(array('item_id' => $item_id))->find();\n\n        if (!$return) {\n            $this->sendError(10101);\n            return;\n        }\n\n        $this->sendResult($return);\n    }\n}\n"
  },
  {
    "path": "server/Application/Api/Controller/AdminMessageController.class.php",
    "content": "<?php\n\nnamespace Api\\Controller;\n\nuse Think\\Controller;\n\nclass AdminMessageController extends BaseController\n{\n    // 管理员发布系统公告（开源版无分表）\n    public function addAnnouncement()\n    {\n        $login_user = $this->checkLogin();\n        $this->checkAdmin();\n\n        $message_content = I(\"post.message_content\");\n        // 公告类型：announce_web / announce_runapi / announce_all\n        $message_type = I(\"post.message_type/s\", '', 'trim');\n        $send_at = I(\"post.send_at\"); // 可选，格式：Y-m-d H:i:s\n\n        if (!$message_content) {\n            $this->sendError(10101, '参数错误：message_content 不能为空');\n            return;\n        }\n\n        // 公告类型白名单与默认值\n        $allow_types = array('announce_web', 'announce_runapi', 'announce_all');\n        if (!$message_type) {\n            // 兼容旧版：未传类型时默认为网页端公告\n            $message_type = 'announce_web';\n        }\n        if (!in_array($message_type, $allow_types)) {\n            $message_type = 'announce_web';\n        }\n\n        // 基础安全过滤：去除危险标签与协议\n        $message_content = $this->sanitizeHtml($message_content);\n        // 将换行转换为 <br>\n        $message_content = nl2br($message_content);\n\n        $addtime = $send_at ? $send_at : date(\"Y-m-d H:i:s\");\n\n        $insert = array(\n            \"from_uid\" => 0,\n            \"from_name\" => '系统公告',\n            // 提示：这里的 message_type 用于区分公告投放渠道\n            // announce_web：仅 ShowDoc 网页端\n            // announce_runapi：仅 RunApi 客户端\n            // announce_all：ShowDoc + RunApi\n            \"message_type\" => $message_type,\n            \"message_content\" => $message_content,\n            \"action_type\" => '',\n            \"object_type\" => '',\n            \"object_id\" => 0,\n            \"addtime\" => $addtime,\n        );\n\n        $id = D(\"MessageContent\")->add($insert);\n        if (!$id) {\n            $this->sendError(10101, '保存失败');\n            return;\n        }\n\n        $this->sendResult(array('id' => intval($id)));\n    }\n\n    // 管理员查看公告列表\n    public function listAnnouncements()\n    {\n        $login_user = $this->checkLogin();\n        $this->checkAdmin();\n\n        $page = I(\"page/d\") ? I(\"page/d\") : 1;\n        $count = I(\"count/d\") ? I(\"count/d\") : 20;\n\n        $list = D(\"MessageContent\")\n            // 管理后台列表：展示全部系统公告类型，包含旧版 announce\n            ->where(\" message_type in ('announce','announce_web','announce_runapi','announce_all') \")\n            ->order(\" id desc \")\n            ->page(\" $page , $count \")\n            ->select();\n\n        $this->sendResult((array)$list);\n    }\n\n    // 简单HTML过滤（保留少量安全标签，移除脚本协议）\n    private function sanitizeHtml($html)\n    {\n        $allowed = '<p><br><ul><ol><li><strong><b><em><i><code><pre><h1><h2><h3><h4><blockquote><a>';\n        $clean = strip_tags($html, $allowed);\n        // 去掉 a 标签中的 javascript: 协议\n        $clean = preg_replace('/javascript\\s*:/i', '', $clean);\n        return $clean;\n    }\n}\n\n\n"
  },
  {
    "path": "server/Application/Api/Controller/AdminSettingController.class.php",
    "content": "<?php\n\nnamespace Api\\Controller;\n\nuse Think\\Controller;\n\nclass AdminSettingController extends BaseController\n{\n\n    //保存配置\n    public function saveConfig()\n    {\n        $login_user = $this->checkLogin();\n        $this->checkAdmin();\n        $register_open = intval(I(\"register_open\"));\n        $history_version_count = intval(I(\"history_version_count\"));\n        $oss_open = intval(I(\"oss_open\"));\n        $home_page = intval(I(\"home_page\"));\n        $home_item = intval(I(\"home_item\"));\n        $oss_setting = I(\"oss_setting\");\n        $show_watermark = intval(I(\"show_watermark\"));\n        $beian = I(\"beian\");\n        $site_url = I(\"site_url\");\n        $open_api_key = I(\"open_api_key\");\n        $open_api_host = I(\"open_api_host\");\n        $ai_model_name = I(\"ai_model_name\");\n        $ai_service_url = I(\"ai_service_url\");\n        $ai_service_token = I(\"ai_service_token\");\n        $force_login = intval(I(\"force_login\"));\n        $enable_public_square = intval(I(\"enable_public_square\"));\n        $strong_password_enabled = intval(I(\"strong_password_enabled\"));\n        $session_expire_days = intval(I(\"session_expire_days\"));\n        // 验证登录态有效时长范围，最小1天，最大3650天（10年）\n        if ($session_expire_days < 1 || $session_expire_days > 3650) {\n            $session_expire_days = 180; // 使用默认值180天\n        }\n\n        D(\"Options\")->set(\"history_version_count\", $history_version_count);\n        D(\"Options\")->set(\"register_open\", $register_open);\n        D(\"Options\")->set(\"home_page\", $home_page);\n        D(\"Options\")->set(\"home_item\", $home_item);\n        D(\"Options\")->set(\"beian\", $beian);\n        D(\"Options\")->set(\"site_url\", $site_url);\n        D(\"Options\")->set(\"open_api_key\", $open_api_key);\n        D(\"Options\")->set(\"open_api_host\", $open_api_host);\n        D(\"Options\")->set(\"ai_model_name\", $ai_model_name);\n        D(\"Options\")->set(\"ai_service_url\", $ai_service_url);\n        D(\"Options\")->set(\"ai_service_token\", $ai_service_token);\n        D(\"Options\")->set(\"show_watermark\", $show_watermark);\n        D(\"Options\")->set(\"force_login\", $force_login);\n        D(\"Options\")->set(\"enable_public_square\", $enable_public_square);\n        D(\"Options\")->set(\"strong_password_enabled\", $strong_password_enabled);\n        D(\"Options\")->set(\"session_expire_days\", $session_expire_days);\n\n        if ($oss_open) {\n            $this->checkComposerPHPVersion();\n            D(\"Options\")->set(\"oss_setting\", json_encode($oss_setting));\n        }\n        D(\"Options\")->set(\"oss_open\", $oss_open);\n\n        $this->sendResult(array());\n    }\n\n    //加载配置\n    public function loadConfig()\n    {\n        $login_user = $this->checkLogin();\n        $this->checkAdmin();\n        $oss_open = D(\"Options\")->get(\"oss_open\");\n        $register_open = D(\"Options\")->get(\"register_open\");\n        $show_watermark = D(\"Options\")->get(\"show_watermark\");\n        $history_version_count = D(\"Options\")->get(\"history_version_count\");\n        $oss_setting = D(\"Options\")->get(\"oss_setting\");\n        $home_page = D(\"Options\")->get(\"home_page\");\n        $home_item = D(\"Options\")->get(\"home_item\");\n        $beian = D(\"Options\")->get(\"beian\");\n        $site_url = D(\"Options\")->get(\"site_url\");\n        $open_api_key = D(\"Options\")->get(\"open_api_key\");\n        $open_api_host = D(\"Options\")->get(\"open_api_host\");\n        $ai_model_name = D(\"Options\")->get(\"ai_model_name\");\n        $ai_service_url = D(\"Options\")->get(\"ai_service_url\");\n        $ai_service_token = D(\"Options\")->get(\"ai_service_token\");\n        $force_login = D(\"Options\")->get(\"force_login\");\n        $enable_public_square = D(\"Options\")->get(\"enable_public_square\");\n        $strong_password_enabled = D(\"Options\")->get(\"strong_password_enabled\");\n        $session_expire_days = D(\"Options\")->get(\"session_expire_days\");\n        $oss_setting = json_decode($oss_setting, 1);\n\n        //如果强等于false，那就是尚未有数据。关闭注册应该是有数据且数据为字符串0\n        if ($register_open === false) {\n            $this->sendResult(array());\n        } else {\n            $array = array(\n                \"oss_open\" => $oss_open,\n                \"register_open\" => $register_open,\n                \"show_watermark\" => $show_watermark,\n                \"history_version_count\" => $history_version_count,\n                \"home_page\" => $home_page,\n                \"home_item\" => $home_item,\n                \"beian\" => $beian,\n                \"site_url\" => $site_url,\n                \"oss_setting\" => $oss_setting,\n                \"open_api_key\" => $open_api_key,\n                \"open_api_host\" => $open_api_host,\n                \"ai_model_name\" => $ai_model_name,\n                \"ai_service_url\" => $ai_service_url,\n                \"ai_service_token\" => $ai_service_token,\n                \"force_login\" => $force_login,\n                \"enable_public_square\" => $enable_public_square,\n                \"strong_password_enabled\" => $strong_password_enabled,\n                \"session_expire_days\" => $session_expire_days,\n            );\n            $this->sendResult($array);\n        }\n    }\n\n    //保存Ldap配置\n    public function saveLdapConfig()\n    {\n        set_time_limit(60);\n        ini_set('memory_limit', '500M');\n        $login_user = $this->checkLogin();\n        $this->checkAdmin();\n        $ldap_open = intval(I(\"ldap_open\"));\n        $ldap_form = I(\"ldap_form\");\n\n        if ($ldap_open) {\n            if (!$ldap_form['user_field']) {\n                $ldap_form['user_field'] = 'cn';\n            }\n\n            $ldap_form['user_field'] = strtolower($ldap_form['user_field']);\n            \n            // 如果未配置姓名字段，则默认为空\n            if (!isset($ldap_form['name_field'])) {\n                $ldap_form['name_field'] = '';\n            }\n            \n            if ($ldap_form['name_field']) {\n                $ldap_form['name_field'] = strtolower($ldap_form['name_field']);\n            }\n\n            if (!extension_loaded('ldap')) {\n                $this->sendError(10011, \"你尚未安装php-ldap扩展。如果是普通PHP环境，请手动安装之。如果是使用之前官方docker镜像，则需要重新安装镜像。方法是：备份 /showdoc_data 整个目录，然后全新安装showdoc，接着用备份覆盖/showdoc_data 。然后递归赋予777可写权限。\");\n                return;\n            }\n\n            $ldap_conn = ldap_connect($ldap_form['host'], $ldap_form['port']); //建立与 LDAP 服务器的连接\n            if (!$ldap_conn) {\n                $this->sendError(10011, \"Can't connect to LDAP server\");\n                return;\n            }\n\n            $ldap_form['bind_password'] = htmlspecialchars_decode($ldap_form['bind_password']);\n\n            ldap_set_option($ldap_conn, LDAP_OPT_PROTOCOL_VERSION, $ldap_form['version']);\n            $rs = ldap_bind($ldap_conn, $ldap_form['bind_dn'], $ldap_form['bind_password']); //与服务器绑定 用户登录验证 成功返回1 \n            if (!$rs) {\n                $this->sendError(10011, \"Can't bind to LDAP server\");\n                return;\n            }\n\n            $ldap_form['search_filter'] = $ldap_form['search_filter'] ? $ldap_form['search_filter'] : '(cn=*)';\n            $ldap_form['search_filter'] = trim(htmlspecialchars_decode($ldap_form['search_filter']));\n            \n            // 检测search_filter中是否包含占位符 %(user)s\n            $has_placeholder = strpos($ldap_form['search_filter'], '%(user)s') !== false;\n            \n            // 确定用于同步的搜索条件\n            if ($has_placeholder) {\n                // 如果包含占位符，生成一个通用的搜索条件用于同步\n                // 例如: (sAMAccountName=%(user)s) -> (sAMAccountName=*)\n                // 例如: (&(objectClass=user)(sAMAccountName=%(user)s)) -> (&(objectClass=user)(sAMAccountName=*))\n                $sync_filter = preg_replace('/%\\(user\\)s/', '*', $ldap_form['search_filter']);\n            } else {\n                // 没有占位符时，直接使用原搜索条件\n                $sync_filter = $ldap_form['search_filter'];\n            }\n            \n            // 检查是否已经包含 objectClass 相关的过滤条件\n            // 如果不包含，自动添加用户过滤条件，防止同步计算机、组等非用户对象\n            $has_objectclass = preg_match('/objectclass/i', $sync_filter);\n            if (!$has_objectclass) {\n                // 智能包装：自动添加用户过滤条件\n                // 兼容 AD (objectClass=user) 和 OpenLDAP (objectClass=person/inetOrgPerson)\n                // 同时显式排除计算机、组、OU等非用户对象\n                $user_filter = '(|(objectClass=user)(objectClass=person)(objectClass=inetOrgPerson))';\n                $exclude_filter = '(!(objectClass=computer))(!(objectClass=group))(!(objectClass=organizationalUnit))';\n                \n                if (preg_match('/^\\([^&|!]/', $sync_filter)) {\n                    // 简单条件，例如 (sAMAccountName=*) \n                    // 包装成：(&(用户过滤器)(排除过滤器)(原条件))\n                    $sync_filter = '(&' . $user_filter . $exclude_filter . $sync_filter . ')';\n                } else if (preg_match('/^\\(&/', $sync_filter)) {\n                    // 已经是 AND 条件，例如 (&(cn=*)(mail=*))\n                    // 插入到开头：(&(用户过滤器)(排除过滤器)(cn=*)(mail=*))\n                    $sync_filter = preg_replace('/^\\(&/', '(&' . $user_filter . $exclude_filter, $sync_filter);\n                } else if (preg_match('/^\\(\\|/', $sync_filter)) {\n                    // 是 OR 条件，例如 (|(cn=*)(uid=*))\n                    // 包装成 AND：(&(用户过滤器)(排除过滤器)(|(cn=*)(uid=*)))\n                    $sync_filter = '(&' . $user_filter . $exclude_filter . $sync_filter . ')';\n                }\n            }\n            \n            // 执行用户同步操作\n            $result = ldap_search($ldap_conn, $ldap_form['base_dn'], $sync_filter);\n            \n            if (!$result) {\n                $this->sendError(10011, \"LDAP搜索失败，请检查 search filter 配置是否正确\");\n                return;\n            }\n            \n            $data = ldap_get_entries($ldap_conn, $result);\n            \n            // 改进用户字段获取逻辑，支持大小写不敏感\n            $user_field_lower = strtolower($ldap_form['user_field']);\n\n            for ($i = 0; $i < $data[\"count\"]; $i++) {\n                // 因为LDAP属性可能大小写不同，遍历所有属性找到匹配的\n                $ldap_user = null;\n                foreach ($data[$i] as $key => $value) {\n                    if (strtolower($key) === $user_field_lower && isset($value['count']) && $value['count'] > 0) {\n                        $ldap_user = $value[0];\n                        break;\n                    }\n                }\n                \n                if (!$ldap_user) {\n                    continue;\n                }\n                \n                // 获取用户姓名\n                $ldap_name = '';\n                if ($ldap_form['name_field']) {\n                    $name_field_lower = strtolower($ldap_form['name_field']);\n                    foreach ($data[$i] as $key => $value) {\n                        if (strtolower($key) === $name_field_lower && isset($value['count']) && $value['count'] > 0) {\n                            $ldap_name = $value[0];\n                            break;\n                        }\n                    }\n                }\n                \n                //如果该用户不在数据库里，则帮助其注册\n                $userInfo = D(\"User\")->isExist($ldap_user);\n                if (!$userInfo) {\n                    $uid = D(\"User\")->register($ldap_user, $ldap_user . get_rand_str());\n                    // 如果有姓名字段，则更新用户姓名\n                    if ($ldap_name) {\n                        D(\"User\")->where(\"uid = '%d'\", array($uid))->save(array(\"name\" => $ldap_name));\n                    }\n                } else if ($ldap_name) {\n                    // 如果用户已存在且有姓名字段，则更新用户姓名\n                    D(\"User\")->where(\"uid = '%d'\", array($userInfo['uid']))->save(array(\"name\" => $ldap_name));\n                }\n            }\n\n            D(\"Options\")->set(\"ldap_form\", json_encode($ldap_form));\n        }\n        D(\"Options\")->set(\"ldap_open\", $ldap_open);\n        $this->sendResult(array());\n    }\n\n    //加载Ldap配置\n    public function loadLdapConfig()\n    {\n        $login_user = $this->checkLogin();\n        $this->checkAdmin();\n        $ldap_open = D(\"Options\")->get(\"ldap_open\");\n        $ldap_form = D(\"Options\")->get(\"ldap_form\");\n        $ldap_form = json_decode($ldap_form, 1);\n\n        if ($ldap_form && $ldap_form['host'] && !$ldap_form['search_filter']) {\n            $ldap_form['search_filter'] = '(cn=*)';\n        }\n        \n        // 确保name_field字段存在\n        if ($ldap_form && !isset($ldap_form['name_field'])) {\n            $ldap_form['name_field'] = '';\n        }\n        \n        $array = array(\n            \"ldap_open\" => $ldap_open,\n            \"ldap_form\" => $ldap_form,\n        );\n        $this->sendResult($array);\n    }\n\n    //保存Oauth2配置\n    public function saveOauth2Config()\n    {\n        $login_user = $this->checkLogin();\n        $this->checkAdmin();\n        $this->checkComposerPHPVersion();\n        $oauth2_open = intval(I(\"oauth2_open\"));\n        $oauth2_form = I(\"oauth2_form\");\n        D(\"Options\")->set(\"oauth2_form\", json_encode($oauth2_form));\n        D(\"Options\")->set(\"oauth2_open\", $oauth2_open);\n        $this->sendResult(array());\n    }\n\n    //加载Oauth2配置\n    public function loadOauth2Config()\n    {\n        $login_user = $this->checkLogin();\n        $this->checkAdmin();\n        $oauth2_open = D(\"Options\")->get(\"oauth2_open\");\n        $oauth2_form = D(\"Options\")->get(\"oauth2_form\");\n        $oauth2_form = htmlspecialchars_decode($oauth2_form);\n        $oauth2_form = json_decode($oauth2_form, 1);\n\n        $array = array(\n            \"oauth2_open\" => $oauth2_open,\n            \"oauth2_form\" => $oauth2_form,\n        );\n        $this->sendResult($array);\n    }\n\n    public function getLoginSecretKey()\n    {\n        $login_user = $this->checkLogin();\n        $this->checkAdmin();\n        $login_secret_key = D(\"Options\")->get(\"login_secret_key\");\n        if (!$login_secret_key) {\n            $login_secret_key = get_rand_str();\n            D(\"Options\")->set(\"login_secret_key\", $login_secret_key);\n        }\n        $this->sendResult(array(\"login_secret_key\" => $login_secret_key));\n    }\n\n    public function resetLoginSecretKey()\n    {\n        $login_user = $this->checkLogin();\n        $this->checkAdmin();\n        $login_secret_key = get_rand_str();\n        D(\"Options\")->set(\"login_secret_key\", $login_secret_key);\n        $this->sendResult(array(\"login_secret_key\" => $login_secret_key));\n    }\n\n\n    public function checkLdapLogin()\n    {\n        set_time_limit(60);\n        ini_set('memory_limit', '500M');\n        $username = 'admin';\n        $password = '123456';\n\n        $ldap_open = D(\"Options\")->get(\"ldap_open\");\n        $ldap_form = D(\"Options\")->get(\"ldap_form\");\n        $ldap_form = json_decode($ldap_form, 1);\n        if (!$ldap_open) {\n            return;\n        }\n        if (!$ldap_form['user_field']) {\n            $ldap_form['user_field'] = 'cn';\n        }\n        $ldap_conn = ldap_connect($ldap_form['host'], $ldap_form['port']); //建立与 LDAP 服务器的连接\n        if (!$ldap_conn) {\n            $this->sendError(10011, \"Can't connect to LDAP server\");\n            return;\n        }\n        ldap_set_option($ldap_conn, LDAP_OPT_PROTOCOL_VERSION, $ldap_form['version']);\n        $rs = ldap_bind($ldap_conn, $ldap_form['bind_dn'], $ldap_form['bind_password']); //与服务器绑定 用户登录验证 成功返回1 \n        if (!$rs) {\n            $this->sendError(10011, \"Can't bind to LDAP server\");\n            return;\n        }\n        $ldap_form['search_filter'] = $ldap_form['search_filter'] ? $ldap_form['search_filter'] : '(cn=*)';\n        \n        // 支持占位符 %(user)s，用于精确匹配登录用户\n        $search_filter = str_replace('%(user)s', ldap_escape($username, '', LDAP_ESCAPE_FILTER), $ldap_form['search_filter']);\n        \n        $result = ldap_search($ldap_conn, $ldap_form['base_dn'], $search_filter);\n        if (!$result) {\n            $this->sendError(10011, \"LDAP搜索失败，请检查 search filter 配置是否正确\");\n            return;\n        }\n        $data = ldap_get_entries($ldap_conn, $result);\n        for ($i = 0; $i < $data[\"count\"]; $i++) {\n            $ldap_user = $data[$i][$ldap_form['user_field']][0];\n            $dn = $data[$i][\"dn\"];\n            if ($ldap_user == $username) {\n                // 获取用户姓名\n                $ldap_name = '';\n                if (isset($ldap_form['name_field']) && $ldap_form['name_field'] && \n                    isset($data[$i][$ldap_form['name_field']]) && \n                    $data[$i][$ldap_form['name_field']]['count'] > 0) {\n                    $ldap_name = $data[$i][$ldap_form['name_field']][0];\n                }\n                \n                //如果该用户不在数据库里，则帮助其注册\n                $userInfo = D(\"User\")->isExist($username);\n                if (!$userInfo) {\n                    $uid = D(\"User\")->register($ldap_user, $ldap_user . get_rand_str());\n                    // 如果有姓名字段，则设置用户姓名\n                    if ($ldap_name) {\n                        D(\"User\")->where(\"uid = '%d'\", array($uid))->save(array(\"name\" => $ldap_name));\n                    }\n                } else if ($ldap_name) {\n                    // 如果用户已存在且有姓名字段，则更新用户姓名\n                    D(\"User\")->where(\"uid = '%d'\", array($userInfo['uid']))->save(array(\"name\" => $ldap_name));\n                }\n                \n                $rs2 = ldap_bind($ldap_conn, $dn, $password);\n                if ($rs2) {\n                    D(\"User\")->updatePwd($userInfo['uid'], $password);\n                    $this->sendResult(array());\n                    return;\n                }\n            }\n        }\n        $this->sendError(10011, \"用户名或者密码错误\");\n    }\n\n    /**\n     * 测试 AI 服务连接\n     */\n    public function testAiService()\n    {\n        $login_user = $this->checkLogin();\n        $this->checkAdmin();\n\n        $ai_service_url = I(\"ai_service_url\");\n        $ai_service_token = I(\"ai_service_token\");\n\n        if (!$ai_service_url || !$ai_service_token) {\n            $this->sendError(10101, 'AI 服务地址和 Token 不能为空');\n            return;\n        }\n\n        // 调用 AI 服务的健康检查接口\n        $url = rtrim($ai_service_url, '/') . '/api/health';\n        $result = \\Api\\Helper\\AiHelper::callService($url, null, $ai_service_token, 'GET', 10);\n\n        if ($result === false) {\n            $this->sendError(10101, '无法连接到 AI 服务，请检查服务地址和网络连接');\n            return;\n        }\n\n        // 如果返回了错误信息\n        if (isset($result['error_code']) && $result['error_code'] != 0) {\n            $this->sendError(10101, isset($result['error_message']) ? $result['error_message'] : 'AI 服务返回错误');\n            return;\n        }\n\n        $this->sendResult(array(\n            'success' => true,\n            'message' => 'AI 服务连接成功',\n            'service_info' => $result\n        ));\n    }\n}\n"
  },
  {
    "path": "server/Application/Api/Controller/AdminUpdateController.class.php",
    "content": "<?php\n\nnamespace Api\\Controller;\n\nuse Think\\Controller;\n\nclass AdminUpdateController extends BaseController\n{\n\n    //检测showdoc版本更新\n    public function checkUpdate()\n    {\n        //获取当前版本\n        $text = file_get_contents(\"../composer.json\");\n        $composer = json_decode($text, true);\n        $version = $composer['version'];\n        $url = \"https://www.showdoc.cc/server/api/open/checkUpdate\";\n        $ch = curl_init();\n        $timeout = 2;\n        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);\n        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);\n        curl_setopt($ch, CURLOPT_POST, true);\n        curl_setopt($ch, CURLOPT_POSTFIELDS, \"version={$version}\");\n        curl_setopt($ch, CURLOPT_URL, $url);\n        $sContent = curl_exec($ch);\n        curl_close($ch);\n        echo $sContent;\n    }\n\n    // 下载更新代码包\n    public function download()\n    {\n        $this->checkLogin();\n        $this->checkAdmin();\n        set_time_limit(1000);\n        ini_set('memory_limit', '500M');\n        //获取当前版本\n        $text = file_get_contents(\"../composer.json\");\n        $composer = json_decode($text, true);\n        $version = $composer['version'];\n        $url = \"https://www.showdoc.cc/server/api/open/checkUpdate\";\n        $res = http_post($url, array(\"version\" => $version));\n        $res_array = json_decode($res, true);\n        $new_version = $res_array['data']['new_version'];\n        $file_url = $res_array['data']['file_url'];\n\n        if (!$file_url) {\n            $this->sendError(10101, '检测更新时异常');\n            return;\n        }\n\n        $version_num = str_replace(\"v\", \"\", $new_version);\n\n        $showdoc_path = \"../\";\n\n        // 进行文件读写权限检查\n        if (\n            !$this->new_is_writeable($showdoc_path)\n            || !$this->new_is_writeable($showdoc_path . \"Sqlite/\")\n            || !$this->new_is_writeable($showdoc_path . \"web/\")\n            || !$this->new_is_writeable($showdoc_path . \"web/index.php\")\n            || !$this->new_is_writeable($showdoc_path . \"server/\")\n            || !$this->new_is_writeable($showdoc_path . \"server/vendor/autoload.php\")\n            || !$this->new_is_writeable($showdoc_path . \"server/Application/Api\")\n        ) {\n            $this->sendError(10101, '请手动给showdoc安装目录下的所有文件可写权限，否则程序无法覆盖旧文件');\n            return;\n        }\n\n        $temp_dir = sys_get_temp_dir() . \"/showdoc_update/\";\n        $zip_file = $temp_dir . 'showdoc-' . $version_num . '.zip';\n        mkdir($temp_dir);\n        unlink($zip_file);\n        $file = file_get_contents($file_url);\n        file_put_contents($zip_file, $file);\n\n        $zip = new \\ZipArchive();\n        $flag = $zip->open($zip_file);\n        if ($flag !== true) {\n            $this->sendError(10101, '下载更新压缩包失败');\n            return;\n        }\n        $zip->extractTo($temp_dir);\n        $flag = $zip->close();\n\n        $zip_file_subpath = $temp_dir . 'showdoc-' . $version_num . \"/\";\n\n        if (file_exists($zip_file_subpath . 'composer.json') && file_exists($zip_file_subpath . 'web/index.php') && file_exists($zip_file_subpath . 'server/vendor/autoload.php')) {\n            //echo $zip_file_subpath.'存在';\n            // 移动目录到upload/update\n            $this->copydir($zip_file_subpath, $showdoc_path . 'Public/Uploads/update/');\n            $this->deldir($temp_dir);\n            $this->sendResult(array());\n        } else {\n            $this->sendError(10101, '下载更新压缩包后，解压的文件缺失');\n            return;\n        }\n    }\n\n    // 执行升级操作，升级覆盖文件\n    public function updateFiles()\n    {\n        $this->checkLogin();\n        $this->checkAdmin();\n        set_time_limit(1000);\n        ini_set('memory_limit', '500M');\n\n        $showdoc_path = \"../\";\n\n        // 进行文件读写权限检查\n        if (\n            !$this->new_is_writeable($showdoc_path)\n            || !$this->new_is_writeable($showdoc_path . \"Sqlite/\")\n            || !$this->new_is_writeable($showdoc_path . \"web/\")\n            || !$this->new_is_writeable($showdoc_path . \"web/index.php\")\n            || !$this->new_is_writeable($showdoc_path . \"server/\")\n            || !$this->new_is_writeable($showdoc_path . \"server/vendor/autoload.php\")\n            || !$this->new_is_writeable($showdoc_path . \"server/Application/Api\")\n        ) {\n            $this->sendError(10101, '请手动给showdoc安装目录下的所有文件可写权限，否则程序无法覆盖旧文件');\n            return;\n        }\n\n        if (file_exists($showdoc_path . 'Public/Uploads/update/composer.json') && file_exists($showdoc_path . 'Public/Uploads/update/server/vendor/autoload.php')) {\n\n            $text = file_get_contents($showdoc_path . \"composer.json\");\n            $composer = json_decode($text, true);\n            $cur_version = $composer['version'];\n            $cur_version = str_replace(\"v\", \"\", $cur_version);\n\n            $text = file_get_contents($showdoc_path . \"Public/Uploads/update/composer.json\");\n            $composer = json_decode($text, true);\n            $update_version = $composer['version'];\n            $update_version = str_replace(\"v\", \"\", $update_version);\n\n            if (version_compare($update_version, $cur_version) > 0) {\n                //复制数据库文件备份\n                $bak_name = $showdoc_path . 'Sqlite/showdoc.db.bak.' . date(\"Y-m-d-H-i-s\") . '.php';\n                copy($showdoc_path . 'Sqlite/showdoc.db.php', $bak_name);\n\n                // 获取原来的语言设置\n                $lang = get_lang($showdoc_path . \"web/index.html\") ;\n\n                // 目录覆盖\n                $this->copydir($showdoc_path . 'Public/Uploads/update/', $showdoc_path);\n                // 用备份的数据库还原\n                copy($bak_name, $showdoc_path . 'Sqlite/showdoc.db.php');\n\n                // 恢复语言设置\n                if ($lang == 'en') {\n                   $this->replace_file_content($showdoc_path . \"web/index.html\",\"zh-cn\",\"en\") ;\n                   $this->replace_file_content($showdoc_path . \"web_src/index.html\",\"zh-cn\",\"en\") ;\n                }\n\n                $this->deldir($showdoc_path . 'Public/Uploads/update/');\n\n                // echo '升级成功！' ;\n                $this->sendResult(array());\n            } else {\n                // echo '不需要升级';\n                $this->sendError(10101, '版本号显示不需要升级');\n            }\n        } else {\n            $this->sendError(10101, '升级文件不存在');\n        }\n    }\n\n    /**\n     * 复制到目录\n     * $dirsrc  原目录\n     * $dirto  目标目录\n     *\n     */\n    private function copydir($dirsrc, $dirto)\n    {\n        //如果原来的文件存在， 是不是一个目录\n\n        if (file_exists($dirto)) {\n            if (!is_dir($dirto)) {\n                echo \"目标不是一个目录， 不能copy进去<br>\";\n                exit;\n            }\n        } else {\n            mkdir($dirto);\n        }\n\n\n        $dir = opendir($dirsrc);\n\n        while ($filename = readdir($dir)) {\n            if ($filename != \".\" && $filename != \"..\") {\n                $srcfile = $dirsrc . \"/\" . $filename;  //原文件\n                $tofile = $dirto . \"/\" . $filename;    //目标文件\n\n                if (is_dir($srcfile)) {\n                    $this->copydir($srcfile, $tofile);  //递归处理所有子目录\n                } else {\n                    copy($srcfile, $tofile);\n                }\n            }\n        }\n    }\n\n    // 删除文件夹及文件夹下所有的文件\n    private function deldir($dir)\n    {\n        //先删除目录下的文件：\n        $dh = opendir($dir);\n        while ($file = readdir($dh)) {\n            if ($file != \".\" && $file != \"..\") {\n                $fullpath = $dir . \"/\" . $file;\n                if (!is_dir($fullpath)) {\n                    unlink($fullpath);\n                } else {\n                    $this->deldir($fullpath);\n                }\n            }\n        }\n        closedir($dh);\n\n        //删除当前文件夹：\n        if (rmdir($dir)) {\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n\n    /**\n     * 判断 文件/目录 是否可写（取代系统自带的 is_writeable 函数）\n     *\n     * @param string $file 文件/目录\n     * @return boolean\n     */\n    private function new_is_writeable($file)\n    {\n        if (is_dir($file)) {\n            $dir = $file;\n            if ($fp = @fopen(\"$dir/test.txt\", 'w')) {\n                @fclose($fp);\n                @unlink(\"$dir/test.txt\");\n                $writeable = 1;\n            } else {\n                $writeable = 0;\n            }\n        } else {\n            if ($fp = @fopen($file, 'a+')) {\n                @fclose($fp);\n                $writeable = 1;\n            } else {\n                $writeable = 0;\n            }\n        }\n\n        return $writeable;\n    }\n\n    private function replace_file_content($file , $from ,$to )\n    {\n        $content = file_get_contents($file);\n        $content2 = str_replace($from,$to,$content);\n        if ($content2) {\n            file_put_contents($file,$content2);\n        }\n    }\n}\n"
  },
  {
    "path": "server/Application/Api/Controller/AdminUserController.class.php",
    "content": "<?php\n\nnamespace Api\\Controller;\n\nuse Think\\Controller;\n\nclass AdminUserController extends BaseController\n{\n\n\n    //获取所有用户列表\n    public function getList()\n    {\n        $login_user = $this->checkLogin();\n        $this->checkAdmin();\n        $page = I(\"page/d\");\n        $count = I(\"count/d\");\n        $username = I(\"username\");\n        $where = \" 1 = 1 \";\n        if ($username) {\n            $like = safe_like($username);\n            $where .= \" and username like '%s' \";\n            $like_param = array($like);\n        }\n        $Users = $like_param ? D(\"User\")->where($where, $like_param)->page($page, $count)->order(\" uid desc  \")->select() : D(\"User\")->where($where)->page($page, $count)->order(\" uid desc  \")->select();\n        $total = $like_param ? D(\"User\")->where($where, $like_param)->count() : D(\"User\")->where($where)->count();\n        $return = array();\n        $return['total'] = (int)$total;\n        if ($Users) {\n            foreach ($Users as $key => &$value) {\n                $value['reg_time'] = date(\"Y-m-d H:i:s\", $value['reg_time']);\n                if ($value['last_login_time']) {\n                    $value['last_login_time'] = date(\"Y-m-d H:i:s\", $value['last_login_time']);\n                } else {\n                    $value['last_login_time'] = '';\n                }\n            }\n            $return['users'] = $Users;\n            $this->sendResult($return);\n        } else {\n            $this->sendResult(array());\n        }\n    }\n\n    //删除用户\n    public function deleteUser()\n    {\n        $login_user = $this->checkLogin();\n        $this->checkAdmin();\n        $uid = I(\"post.uid/d\");\n\n        if (D(\"Item\")->where(\"uid = '%d' and is_del = 0 \", array($uid))->find()) {\n            $this->sendError(10101, \"该用户名下还有项目，不允许删除。请先将其项目删除或者重新分配/转让\");\n            return;\n        }\n        $return = D(\"User\")->delete_user($uid);\n        if (!$return) {\n            $this->sendError(10101);\n        } else {\n            $this->sendResult($return);\n        }\n    }\n\n    //修改密码\n    public function changePassword()\n    {\n        $login_user = $this->checkLogin();\n        $this->checkAdmin();\n        $uid = I(\"post.uid/d\");\n        $new_password = I(\"new_password\");\n\n        $return = D(\"User\")->updatePwd($uid, $new_password);\n        if (!$return) {\n            $this->sendError(10101);\n        } else {\n            $this->sendResult($return);\n        }\n    }\n\n\n    //新增用户\n    public function addUser()\n    {\n        $login_user = $this->checkLogin();\n        $this->checkAdmin();\n        $username = I(\"post.username\");\n        $password = I(\"post.password\");\n        $uid = I(\"post.uid/d\");\n        $name = I(\"post.name\");\n        if (!$username) {\n            $this->sendError(10101, '用户名不允许为空');\n            return;\n        }\n        if ($uid) {\n            if ($password) {\n                D(\"User\")->updatePwd($uid, $password);\n            }\n            if ($name) {\n                D(\"User\")->where(\" uid = '%d' \", array($uid))->save(array(\"name\" => $name));\n            }\n            $this->sendResult(array());\n        } else {\n            if (D(\"User\")->isExist($username)) {\n                $this->sendError(10101, L('username_exists'));\n                return;\n            }\n            $new_uid = D(\"User\")->register($username, $password);\n            if (!$new_uid) {\n                $this->sendError(10101);\n            } else {\n                if ($name) {\n                    D(\"User\")->where(\" uid = '%d' \", array($new_uid))->save(array(\"name\" => $name));\n                }\n                $this->sendResult(array());\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "server/Application/Api/Controller/AiController.class.php",
    "content": "<?php\n\nnamespace Api\\Controller;\n\nuse Think\\Controller;\nuse EasyWeChat\\Factory;\n\nclass AiController extends BaseController\n{\n\n    private $open_api_key = '';\n    private $ai_service_url = '';\n    private $ai_service_token = '';\n\n    public function __construct()\n    {\n        parent::__construct();\n        $this->open_api_key = D(\"Options\")->get(\"open_api_key\");\n        $this->ai_service_url = D(\"Options\")->get(\"ai_service_url\");\n        $this->ai_service_token = D(\"Options\")->get(\"ai_service_token\");\n    }\n\n    /**\n     * 检查 AI 知识库功能是否可用\n     * @param int $item_id 项目ID\n     * @return array 返回 ['enabled' => bool, 'message' => string, 'config' => array]\n     */\n    private function checkAiKnowledgeBaseEnabled($item_id)\n    {\n        // 检查系统级配置：是否配置了 AI 服务地址和 Token\n        if (!$this->ai_service_url || !$this->ai_service_token) {\n            return array(\n                'enabled' => false,\n                'message' => 'AI 服务未配置，请联系管理员'\n            );\n        }\n\n        // 检查项目是否存在\n        $item = D(\"Item\")->where(array('item_id' => $item_id))->find();\n        if (!$item) {\n            return array(\n                'enabled' => false,\n                'message' => '项目不存在'\n            );\n        }\n\n        // 检查项目级配置（使用新表）\n        $config = D(\"ItemAiConfig\")->getConfig($item_id);\n        if (empty($config['enabled'])) {\n            return array(\n                'enabled' => false,\n                'message' => '当前项目未启用 AI 知识库功能'\n            );\n        }\n\n        return array(\n            'enabled' => true,\n            'message' => '',\n            'config' => $config  // 返回完整配置\n        );\n    }\n\n    public function create()\n    {\n        $content = I(\"post.content\");\n        $login_user = $this->checkLogin();\n        if (!$this->open_api_key) {\n            $this->sendError(10101, '管理员没有在管理后台配置AI助手认证KEY,因此你无法使用AI功能。请联系管理员');\n            return;\n        }\n        $res = $this->send($content);\n    }\n\n    public function send($content)\n    {\n        header(\"Content-Type: text/event-stream\");\n        header(\"X-Accel-Buffering: no\");\n\n        // 检查连接是否已断开\n        if (connection_aborted()) {\n            return false;\n        }\n\n        $ai_model_name = D(\"Options\")->get(\"ai_model_name\");\n        $ai_model_name = $ai_model_name ? $ai_model_name : 'gpt-4o';\n        $postData = json_encode(array(\n            \"model\" => $ai_model_name,\n            \"messages\" => array(\n                array(\n                    \"role\" => 'system',\n                    \"content\" => \"你是文档工具 showdoc 的AI助手，主要是职责是协助用户生成各种各样的文档/代码/文案，提高用户的写作效率。用户提出要求，你应该帮助用户生成文字。如果用户不懂，你可以引导用户怎么使用怎么提问，或者让用户点击当前网页左下角的帮助说明链接查看一些使用例子\",\n                ),\n                array(\n                    \"role\" => 'user',\n                    \"content\" => $content,\n                ),\n            ),\n            \"stream\" => true,\n        ));\n        $open_api_host = D(\"Options\")->get(\"open_api_host\");\n        if (!$open_api_host) {\n            $open_api_host = 'https://api.openai.com';\n        }\n        if (!strstr($open_api_host, 'http')) {\n            $open_api_host = 'https://' . $open_api_host;\n        }\n        if (substr($open_api_host, -1) === '/') { // 如果字符串以 / 符号结尾:\n            $open_api_host = substr($open_api_host, 0, -1); // 将字符串的最后一个字符剪切掉\n        }\n\n        // 参考 https://github.com/dirk1983/chatgpt/blob/main/stream.php\n        $callback = function ($ch, $data) {\n            // 检查连接是否已断开\n            if (connection_aborted()) {\n                return -1; // 返回-1会中断curl执行\n            }\n\n            $complete = json_decode($data);\n            if (isset($complete->error)) {\n                setcookie(\"errcode\", $complete->error->code);\n                setcookie(\"errmsg\", $data);\n                if (strpos($complete->error->message, \"Rate limit reached\") === 0) { //访问频率超限错误返回的code为空，特殊处理一下\n                    setcookie(\"errcode\", \"rate_limit_reached\");\n                }\n                if (strpos($complete->error->message, \"Your access was terminated\") === 0) { //违规使用，被封禁，特殊处理一下\n                    setcookie(\"errcode\", \"access_terminated\");\n                }\n                if (strpos($complete->error->message, \"You didn't provide an API key\") === 0) { //未提供API-KEY\n                    setcookie(\"errcode\", \"no_api_key\");\n                }\n                if (strpos($complete->error->message, \"You exceeded your current quota\") === 0) { //API-KEY余额不足\n                    setcookie(\"errcode\", \"insufficient_quota\");\n                }\n                if (strpos($complete->error->message, \"That model is currently overloaded\") === 0) { //OpenAI模型超负荷\n                    setcookie(\"errcode\", \"model_overloaded\");\n                }\n            } else {\n                echo $data;\n                flush();\n            }\n            return strlen($data);\n        };\n\n        $curl = curl_init();  //初始化\n        curl_setopt($curl, CURLOPT_ENCODING, '');\n        curl_setopt($curl, CURLOPT_URL, $open_api_host . '/v1/chat/completions');  //设置url\n        curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);  //设置http验证方法\n\n        // 设置合理的超时时间\n        curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 30);  // 连接超时30秒\n        curl_setopt($curl, CURLOPT_TIMEOUT, 480);        // 总超时8分钟\n\n        // 关键：防止连接复用，确保每次请求都是独立的\n        curl_setopt($curl, CURLOPT_FRESH_CONNECT, true);  // 强制使用新的连接\n        curl_setopt($curl, CURLOPT_FORBID_REUSE, true);   // 禁止复用连接\n\n\n        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);  //设置curl_exec获取的信息的返回方式\n        curl_setopt($curl, CURLOPT_POST, 1);  //设置发送方式为post请求\n        curl_setopt($curl, CURLOPT_POSTFIELDS, $postData);  //设置post的数据\n        curl_setopt($curl, CURLOPT_WRITEFUNCTION, $callback);\n        curl_setopt(\n            $curl,\n            CURLOPT_HTTPHEADER,\n            array(\n                'Content-Type: application/json',\n                \"Authorization: Bearer {$this->open_api_key}\",\n                'Content-Length: ' . strlen($postData)\n            )\n        );\n        curl_setopt($curl, CURLOPT_MAXREDIRS, 3); // 设置最大重定向次数为3次\n        curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); // 允许自动重定向\n        curl_setopt($curl, CURLOPT_AUTOREFERER, true); // 自动设置Referer\n\n        $result = curl_exec($curl);\n        // 检查curl执行结果\n        if ($result === false) {\n            $error = curl_error($curl);\n            $errno = curl_errno($curl);\n            curl_close($curl);\n\n            // 返回错误信息\n            echo \"data: \" . json_encode(array(\"error\" => \"网络请求失败: \" . $error)) . \"\\n\\n\";\n            flush();\n            return false;\n        }\n\n        curl_close($curl);\n        return $result;\n    }\n\n    /**\n     * 知识库对话接口\n     */\n    public function chat()\n    {\n        $item_id = I(\"item_id/d\");\n        $question = I(\"question\");\n        $conversation_id = I(\"conversation_id\");\n        $stream = I(\"stream/d\", 1); // 默认流式返回\n\n        // 对于流式输出，需要特殊处理错误，不能使用 sendError\n        if ($stream == 1) {\n            // 清除所有输出缓冲区，确保直接输出\n            while (ob_get_level()) {\n                ob_end_clean();\n            }\n\n            // 提前设置流式输出的 headers\n            // 确保 UTF-8 编码，移除可能存在的其他 Content-Type 设置\n            header_remove('Content-Type');\n            header(\"Content-Type: text/event-stream; charset=utf-8\");\n            header(\"Cache-Control: no-cache\");\n            header(\"X-Accel-Buffering: no\");\n\n            // 确保内部编码和输出编码都是 UTF-8\n            if (function_exists('mb_internal_encoding')) {\n                mb_internal_encoding('UTF-8');\n            }\n            if (function_exists('mb_http_output')) {\n                mb_http_output('UTF-8');\n            }\n\n            // 禁用 ThinkPHP 的模板渲染\n            if (class_exists('Think\\\\View')) {\n                $this->view = null;\n            }\n\n            if (!$item_id) {\n                echo \"data: \" . json_encode(array('type' => 'error', 'message' => '项目ID不能为空'), JSON_UNESCAPED_UNICODE) . \"\\n\\n\";\n                flush();\n                exit;\n            }\n\n            if (!$question) {\n                echo \"data: \" . json_encode(array('type' => 'error', 'message' => '问题不能为空'), JSON_UNESCAPED_UNICODE) . \"\\n\\n\";\n                flush();\n                exit;\n            }\n\n            // 检查登录状态（允许游客访问公开项目）\n            $login_user = $this->checkLogin(false);\n            $uid = $login_user ? $login_user['uid'] : 0;\n\n            // 检查项目访问权限\n            if (!$this->checkItemVisit($uid, $item_id)) {\n                echo \"data: \" . json_encode(array('type' => 'error', 'message' => '您没有访问该项目的权限'), JSON_UNESCAPED_UNICODE) . \"\\n\\n\";\n                flush();\n                exit;\n            }\n\n            // 检查 AI 知识库功能是否可用\n            $ai_check = $this->checkAiKnowledgeBaseEnabled($item_id);\n            if (!$ai_check['enabled']) {\n                echo \"data: \" . json_encode(array('type' => 'error', 'message' => $ai_check['message']), JSON_UNESCAPED_UNICODE) . \"\\n\\n\";\n                flush();\n                exit;\n            }\n        } else {\n            // 非流式输出使用正常的错误处理\n            if (!$item_id) {\n                $this->sendError(10101, '项目ID不能为空');\n                return;\n            }\n\n            if (!$question) {\n                $this->sendError(10101, '问题不能为空');\n                return;\n            }\n\n            // 检查登录状态（允许游客访问公开项目）\n            $login_user = $this->checkLogin(false);\n            $uid = $login_user ? $login_user['uid'] : 0;\n\n            // 检查项目访问权限\n            if (!$this->checkItemVisit($uid, $item_id)) {\n                $this->sendError(10303, '您没有访问该项目的权限');\n                return;\n            }\n\n            // 检查 AI 知识库功能是否可用\n            $ai_check = $this->checkAiKnowledgeBaseEnabled($item_id);\n            if (!$ai_check['enabled']) {\n                $this->sendError(10101, $ai_check['message']);\n                return;\n            }\n        }\n\n        // 调用 AI 服务\n        if ($stream == 1) {\n            // 流式返回\n            $url = rtrim($this->ai_service_url, '/') . '/api/chat/stream';\n        } else {\n            // 非流式返回\n            $url = rtrim($this->ai_service_url, '/') . '/api/chat';\n        }\n        $postData = array(\n            'item_id' => $item_id,\n            'user_id' => $uid,\n            'question' => $question\n        );\n        if ($conversation_id) {\n            $postData['conversation_id'] = $conversation_id;\n        }\n\n        if ($stream == 1) {\n            // 流式返回（headers 已在前面设置）\n            \\Api\\Helper\\AiHelper::callServiceStream($url, $postData, $this->ai_service_token);\n            // 流式输出完毕后必须退出，防止框架继续渲染模板\n            exit;\n        } else {\n            // 非流式返回\n            $result = \\Api\\Helper\\AiHelper::callService($url, $postData, $this->ai_service_token);\n            if ($result === false) {\n                $this->sendError(10101, 'AI 服务调用失败');\n                return;\n            }\n            $this->sendResult($result);\n        }\n    }\n\n    /**\n     * 获取索引状态\n     */\n    public function getIndexStatus()\n    {\n        $item_id = I(\"item_id/d\");\n        if (!$item_id) {\n            $this->sendError(10101, '项目ID不能为空');\n            return;\n        }\n\n        $login_user = $this->checkLogin(false);\n        $uid = $login_user ? $login_user['uid'] : 0;\n\n        // 检查项目访问权限\n        if (!$this->checkItemVisit($uid, $item_id)) {\n            $this->sendError(10303, '您没有访问该项目的权限');\n            return;\n        }\n\n        // 检查 AI 知识库功能是否可用\n        $ai_check = $this->checkAiKnowledgeBaseEnabled($item_id);\n        if (!$ai_check['enabled']) {\n            $this->sendResult(array(\n                'status' => 'not_configured',\n                'message' => $ai_check['message']\n            ));\n            return;\n        }\n\n        // 调用 AI 服务获取索引状态\n        $url = rtrim($this->ai_service_url, '/') . '/api/index/status?item_id=' . $item_id;\n        $result = \\Api\\Helper\\AiHelper::callService($url, null, $this->ai_service_token, 'GET');\n\n        if ($result === false) {\n            // 返回错误状态，但不使用 sendError，而是返回状态信息\n            $this->sendResult(array(\n                'status' => 'error',\n                'message' => '无法连接到 AI 服务，请检查服务地址和网络连接'\n            ));\n            return;\n        }\n\n        // 如果 AI 服务返回了错误信息，也要正确处理\n        if (isset($result['error_code']) && $result['error_code'] != 0) {\n            $this->sendResult(array(\n                'status' => 'error',\n                'message' => isset($result['error_message']) ? $result['error_message'] : '获取索引状态失败'\n            ));\n            return;\n        }\n\n        // 转换 AI 服务返回的数据格式为前端期望的格式\n        // AI 服务返回: indexed (bool), status (string), document_count (int)\n        // 前端期望: status (string: 'indexed'/'indexing'/'not_configured'/'error'), document_count (int)\n        $response = array(\n            'status' => isset($result['status']) ? $result['status'] : (isset($result['indexed']) && $result['indexed'] ? 'indexed' : 'unknown'),\n            'document_count' => isset($result['document_count']) ? intval($result['document_count']) : 0,\n            'last_update_time' => isset($result['last_update_time']) ? $result['last_update_time'] : null\n        );\n\n        $this->sendResult($response);\n    }\n\n    /**\n     * 重新索引项目\n     */\n    public function rebuildIndex()\n    {\n        $item_id = I(\"item_id/d\");\n        if (!$item_id) {\n            $this->sendError(10101, '项目ID不能为空');\n            return;\n        }\n\n        $login_user = $this->checkLogin();\n        $uid = $login_user['uid'];\n\n        // 检查项目管理权限\n        if (!$this->checkItemManage($uid, $item_id)) {\n            $this->sendError(10101, '您没有管理该项目的权限');\n            return;\n        }\n\n        // 检查 AI 知识库功能是否可用\n        $ai_check = $this->checkAiKnowledgeBaseEnabled($item_id);\n        if (!$ai_check['enabled']) {\n            $this->sendError(10101, $ai_check['message']);\n            return;\n        }\n\n        $result = \\Api\\Helper\\AiHelper::rebuild($item_id, $this->ai_service_url, $this->ai_service_token);\n        if ($result === false) {\n            $this->sendError(10101, '重新索引失败');\n            return;\n        }\n\n        $this->sendResult($result);\n    }\n}\n"
  },
  {
    "path": "server/Application/Api/Controller/AttachmentController.class.php",
    "content": "<?php\n//附件/图片等等\nnamespace Api\\Controller;\n\nuse Think\\Controller;\n\nclass AttachmentController extends BaseController\n{\n\n    public function index()\n    {\n\n        echo 'Attachment';\n    }\n\n    // 管理员：获取未被使用的附件列表（分页）\n    public function getUnusedList()\n    {\n        $login_user = $this->checkLogin();\n        $this->checkAdmin(); // 仅管理员可用\n\n        $page = I(\"page/d\") ? I(\"page/d\") : 1;\n        $count = I(\"count/d\") ? I(\"count/d\") : 10;\n        $display_name = I(\"display_name\"); // 可选过滤\n        $username = I(\"username\"); // 可选过滤：上传者\n\n        $where = ' 1 = 1 ';\n        $params = array();\n        if ($display_name) {\n            $like = safe_like($display_name);\n            $where .= \" and display_name  like '%s' \";\n            $params[] = $like;\n        }\n        if ($username) {\n            $uid = D(\"User\")->where(array('username' => $username))->getField('uid');\n            $uid = $uid ? $uid  : -99;\n            $where .= \" and uid  = '%d' \";\n            $params[] = $uid;\n        }\n\n        // 获取所有附件，通过检查page.page_content来判断是否被使用\n        // 开源版无分表，直接检查page.page_content\n        $candidates = isset($params)\n            ? D(\"UploadFile\")->where($where, $params)->order(\"addtime desc\")->select()\n            : D(\"UploadFile\")->where($where)->order(\"addtime desc\")->select();\n\n        $unused = array();\n        if ($candidates) {\n            foreach ($candidates as $value) {\n                // 在页面内容中进行like匹配：sign是MD5加密串，重复率很小，直接搜索即可\n                $referenced = false;\n                if (!empty($value['sign'])) {\n                    $sign = $value['sign'];\n                    $likeSign = safe_like($sign);\n                    \n                    // 直接搜索sign字符串（MD5加密串重复率很小）\n                    $cnt = M(\"Page\")->where(\" page_content like '%s' \", array('%' . $likeSign . '%'))->count();\n                    if ($cnt > 0) {\n                        $referenced = true;\n                    }\n                    \n                    // 也检查页面历史版本（开源版无分表，直接查询）\n                    if (!$referenced) {\n                        $cnt = M(\"PageHistory\")->where(\" page_content like '%s' \", array('%' . $likeSign . '%'))->count();\n                        if ($cnt > 0) {\n                            $referenced = true;\n                        }\n                    }\n                }\n                \n                // 如果sign检测未找到，再检测real_url\n                if (!$referenced && !empty($value['real_url'])) {\n                    $realUrl = $value['real_url'];\n                    $likeUrl = safe_like($realUrl);\n                    $cnt2 = M(\"Page\")->where(\" page_content like '%s' \", array('%' . $likeUrl . '%'))->count();\n                    if ($cnt2 > 0) {\n                        $referenced = true;\n                    }\n                    \n                    // 也检查页面历史版本中的real_url（开源版无分表，直接查询）\n                    if (!$referenced) {\n                        $cnt2 = M(\"PageHistory\")->where(\" page_content like '%s' \", array('%' . $likeUrl . '%'))->count();\n                        if ($cnt2 > 0) {\n                            $referenced = true;\n                        }\n                    }\n                }\n\n                if ($referenced) {\n                    continue; // 被内容引用，跳过\n                }\n\n                // 视为未使用\n                $username_text = '';\n                if ($value['uid']) {\n                    $username_text = D(\"User\")->where(\" uid = '%d' \", array($value['uid']))->getField('username');\n                }\n                $url = '';\n                if ($value['sign']) {\n                    $url =  server_url(\"api/attachment/visitFile\", array(\"sign\" => $value['sign']));\n                } else {\n                    $url =  $value['real_url'];\n                }\n                $unused[] = array(\n                    \"file_id\" => $value['file_id'],\n                    \"username\" => $username_text,\n                    \"uid\" => $value['uid'],\n                    \"file_type\" => $value['file_type'],\n                    \"visit_times\" => $value['visit_times'],\n                    \"file_size\" => $value['file_size'],\n                    \"file_size_m\" => round($value['file_size'] / (1024 * 1024), 3),\n                    \"display_name\" => $value['display_name'] ? $value['display_name'] : '',\n                    \"url\" => $url,\n                    \"addtime\" => date(\"Y-m-d H:i:s\", $value['addtime']),\n                    \"last_visit_time\" => date(\"Y-m-d H:i:s\", $value['last_visit_time']),\n                );\n            }\n        }\n\n        $total = count($unused);\n        // 简单分页（内存切片）\n        $offset = max(0, ($page - 1) * $count);\n        $list = array_slice($unused, $offset, $count);\n\n        $return = array();\n        $return['list'] = $list;\n        $return['total'] = $total;\n        $used = 0;\n        foreach ($unused as $f) {\n            $used += intval($f['file_size']);\n        }\n        $return['used'] = $used;\n        $return['used_m'] = round($used / (1024 * 1024), 3);\n        $this->sendResult($return);\n    }\n\n    // 管理员：批量删除附件（用于清理未使用）\n    public function batchDeleteAttachments()\n    {\n        $login_user = $this->checkLogin();\n        $this->checkAdmin();\n\n        // 支持 file_ids 数组或逗号分隔字符串\n        $file_ids = I(\"post.file_ids\");\n        if (!$file_ids) {\n            $this->sendError(10101, '缺少参数');\n            return;\n        }\n\n        if (is_string($file_ids)) {\n            $file_ids = explode(',', $file_ids);\n        }\n        if (!is_array($file_ids)) {\n            $file_ids = array();\n        }\n\n        $success = 0;\n        $failed = 0;\n        foreach ($file_ids as $fid) {\n            $fid = intval($fid);\n            if ($fid <= 0) continue;\n            $ret = D(\"Attachment\")->deleteFile($fid);\n            if ($ret) {\n                $success++;\n            } else {\n                $failed++;\n            }\n        }\n\n        $this->sendResult(array('success' => $success, 'failed' => $failed));\n    }\n\n    //浏览附件\n    public function visitFile()\n    {\n        $sign = I(\"sign\");\n        $imageView2 = I(\"imageView2\");\n        $d = D(\"UploadFile\");\n        $ret = $d->where(array('sign' => $sign))->find();\n        if ($ret) {\n            $beyond_the_quota = 0;\n            $days = ceil((time() - $ret['addtime']) / 86400); //自添加图片以来的天数\n            $adv_day_times = $ret['visit_times'] / $days; //平均每天的访问次数\n            $flow_rate = ($ret['file_size'] * $ret['visit_times']) / $days; //日均流量\n\n\n            //如果是apk文件且在微信浏览器中打开\n            if (strpos($_SERVER['HTTP_USER_AGENT'], 'MicroMessenger') !== false  && strpos($ret['real_url'], '.apk') !== false) {\n                header(\"Content-type: text/html; charset=utf-8\");\n                echo \"<head><title>温馨提示</title></head>\";\n                echo \"<br><h1>微信不支持直接下载，请点击右上角“---”在外部浏览器中打开</h1>\";\n                return;\n            }\n\n            $d->where(array('sign' => $sign))->save(array(\"visit_times\" => $ret['visit_times'] + 1, \"last_visit_time\" => time()));\n            //记录用户流量\n            D(\"Attachment\")->recordUserFlow($ret['uid'], $ret['file_size']);\n\n            //$ret['cache_url'] = '' ; //把这个变量赋值为空，禁用掉cache_url;\n            if ($ret['cache_url']) {\n                $url = $ret['cache_url'];\n            } else {\n                $url = $ret['real_url'];\n            }\n\n            $array = explode(\"/Public/Uploads/\", $url);\n            $file_path = \"../Public/Uploads/\" . $array[1];\n            $oss_open = D(\"Options\")->get(\"oss_open\");\n            if (\n                !$oss_open\n                && file_exists($file_path)\n                && $ret['display_name']\n                && !strstr(strtolower($file_path), '.bmp')\n                && !strstr(strtolower($file_path), '.jpg')\n                && !strstr(strtolower($file_path), '.png')\n                && !strstr(strtolower($file_path), '.pdf')\n                && !strstr(strtolower($file_path), '.doc')\n                && !strstr(strtolower($file_path), '.xls')\n                && !strstr(strtolower($file_path), '.ppt')\n            ) {\n                $this->_downloadFile($file_path, $ret['display_name']);\n            } else {\n                header(\"location:{$url}\");\n            }\n        } else {\n            echo \"www.showdoc.cc\";\n        }\n    }\n\n    //上传图片\n    public function uploadImg()\n    {\n        $login_user = $this->checkLogin();\n        $item_id = I(\"item_id/d\") ? I(\"item_id/d\") : 0;\n        $page_id = I(\"page_id/d\") ? I(\"page_id/d\") : 0;\n\n\n        if ($_FILES['editormd-image-file']['name'] == 'blob') {\n            $_FILES['editormd-image-file']['name'] .= '.jpg';\n        }\n\n        if (!$_FILES['editormd-image-file']) {\n            return false;\n        }\n\n        if (!D(\"Attachment\")->isAllowedFilename($_FILES['editormd-image-file']['name'])) {\n            $message = \"不支持上传该文件类型。如有需要请联系网站管理员\";\n            echo json_encode(array(\"message\" => $message, \"success\" => 0));\n            return false;\n        }\n\n        $url = D(\"Attachment\")->upload($_FILES, 'editormd-image-file', $login_user['uid'], $item_id, $page_id);\n        if ($url) {\n            echo json_encode(array(\"url\" => $url, \"success\" => 1));\n        }\n    }\n\n    //上传附件\n    public function attachmentUpload()\n    {\n        $login_user = $this->checkLogin();\n        $item_id = I(\"item_id/d\") ? I(\"item_id/d\") : 0;\n        $page_id = I(\"page_id/d\") ? I(\"page_id/d\") : 0;\n        $uploadFile = $_FILES['file'];\n\n        // 如果附件是要上传绑定到某个页面，那么检验项目权限。如果不绑定，只是上传到自己的文件库，则不需要校验项目权限\n        if ($page_id > 0 || $item_id > 0) {\n            if (!$this->checkItemEdit($login_user['uid'], $item_id)) {\n                $this->sendError(10103);\n                return;\n            }\n        }\n\n        if (!$uploadFile) {\n            return false;\n        }\n\n        if (!D(\"Attachment\")->isAllowedFilename($uploadFile['name'])) {\n            $this->sendError(10101, '为了安全考虑，不支持上传该文件类型。你可以将文件压缩到压缩包后再上传');\n            return false;\n        }\n\n        $url = D(\"Attachment\")->upload($_FILES, 'file', $login_user['uid'], $item_id, $page_id);\n        if ($url) {\n            echo json_encode(array(\"url\" => $url, \"success\" => 1));\n        }\n    }\n    //页面的上传附件列表\n    public function pageAttachmentUploadList()\n    {\n        $login_user = $this->checkLogin(false);\n        $item_id = I(\"item_id/d\") ? I(\"item_id/d\") : 0;\n        $page_id = I(\"page_id/d\") ? I(\"page_id/d\") : 0;\n        if (!$page_id) {\n            $this->sendError(10103, \"请至少先保存一次页面内容\");\n            return;\n        }\n        $return = array();\n        $files = D(\"UploadFile\")->join(\" file_page on file_page.file_id = upload_file.file_id\")->field(\"upload_file.* , file_page.item_id as item_id ,file_page.page_id as page_id  \")->where(\"file_page.page_id = '%d' \", array($page_id))->order(\"file_page.addtime desc\")->select();\n        if ($files) {\n            $item_id = $files[0]['item_id'];\n            if (!$this->checkItemVisit($login_user['uid'], $item_id)) {\n                $this->sendError(10103);\n                return;\n            }\n            foreach ($files as $key => $value) {\n                $url = '';\n                if ($value['sign']) {\n                    $url =  server_url(\"api/attachment/visitFile\", array(\"sign\" => $value['sign']));\n                } else {\n                    $url =  $value['real_url'];\n                }\n                $return[] = array(\n                    \"file_id\" => $value['file_id'],\n                    \"display_name\" => $value['display_name'],\n                    \"url\" => $url,\n                    \"addtime\" => date(\"Y-m-d H:i:s\", $value['addtime']),\n                );\n            }\n        }\n        $this->sendResult($return);\n    }\n\n    //删除页面中已上传文件\n    public function deletePageUploadFile()\n    {\n        $login_user = $this->checkLogin();\n        $file_id = I(\"file_id/d\") ? I(\"file_id/d\") : 0;\n        $page_id = I(\"page_id/d\") ? I(\"page_id/d\") : 0;\n        $count = D(\"FilePage\")->where(\" file_id = '%d' and page_id > 0   \", array($file_id))->count();\n        if ($count <= 1) {\n            $this->deleteMyAttachment();\n        } else {\n            $page = M(\"Page\")->where(array('page_id' => $page_id))->find();\n            if (!$this->checkItemEdit($login_user['uid'], $page['item_id'])) {\n                $this->sendError(10103);\n                return;\n            }\n            $res = D(\"FilePage\")->where(\" file_id = '%d' and page_id = '%d'   \", array($file_id, $page_id))->delete();\n            if ($res) {\n                $this->sendResult(array());\n            } else {\n                $this->sendError(10101, \"删除失败\");\n            }\n        }\n    }\n\n    //获取全站的附件列表。给管理员查看附件用\n    public function getAllList()\n    {\n        $login_user = $this->checkLogin();\n        $this->checkAdmin(); //重要，校验管理员身份\n        $page = I(\"page/d\");\n        $count = I(\"count/d\");\n        $attachment_type = I(\"attachment_type/d\");\n        $display_name = I(\"display_name\");\n        $username = I(\"username\");\n        $return = array();\n        $where = ' 1 = 1 ';\n        if ($attachment_type == 1) {\n            $where .= \" and file_type like '%image%' \";\n        }\n        if ($attachment_type == 2) {\n            $where .= \" and file_type not like '%image%' \";\n        }\n        if ($display_name) {\n            $like = safe_like($display_name);\n            $where .= \" and display_name  like '%s' \";\n            $params[] = $like;\n        }\n        if ($username) {\n            $uid = D(\"User\")->where(array('username' => $username))->getField('uid');\n            $uid = $uid ? $uid  : -99;\n            $where .= \" and uid  = '%d' \";\n            $params[] = $uid;\n        }\n        $files = isset($params) ? D(\"UploadFile\")->where($where, $params)->order(\"addtime desc\")->page($page, $count)->select() : D(\"UploadFile\")->where($where)->order(\"addtime desc\")->page($page, $count)->select();\n        if ($files) {\n            foreach ($files as $key => $value) {\n                $username = '';\n                if ($value['uid']) {\n                    $username = D(\"User\")->where(\" uid = '%d' \", array($value['uid']))->getField('username');\n                }\n                $url = '';\n                if ($value['sign']) {\n                    $url =  server_url(\"api/attachment/visitFile\", array(\"sign\" => $value['sign']));\n                } else {\n                    $url =  $value['real_url'];\n                }\n                $return['list'][] = array(\n                    \"file_id\" => $value['file_id'],\n                    \"username\" => $username,\n                    \"uid\" => $value['uid'],\n                    \"file_type\" => $value['file_type'],\n                    \"visit_times\" => $value['visit_times'],\n                    \"file_size\" => $value['file_size'],\n                    \"item_id\" => $value['item_id'],\n                    \"page_id\" => $value['page_id'],\n                    \"file_size_m\" => round($value['file_size'] / (1024 * 1024), 3),\n                    \"display_name\" => $value['display_name'] ? $value['display_name'] : '',\n                    \"url\" => $url,\n                    \"addtime\" => date(\"Y-m-d H:i:s\", $value['addtime']),\n                    \"last_visit_time\" => date(\"Y-m-d H:i:s\", $value['last_visit_time']),\n                );\n            }\n        }\n        $return['total'] = isset($params) ? D(\"UploadFile\")->where($where, $params)->count() : D(\"UploadFile\")->where($where)->count();\n        $used = D(\"UploadFile\")->where($where)->getField('sum(file_size)');\n        $return['used'] = $used;\n        $return['used_m'] = round($used / (1024 * 1024), 3);\n        $this->sendResult($return);\n    }\n\n    //删除附件\n    public function deleteAttachment()\n    {\n        $login_user = $this->checkLogin();\n        $this->checkAdmin(); //重要，校验管理员身份\n        $file_id = I(\"file_id/d\") ? I(\"file_id/d\") : 0;\n\n        $file = D(\"UploadFile\")->where(array('file_id' => $file_id))->find();\n\n        $ret = D(\"Attachment\")->deleteFile($file_id);\n        if ($ret) {\n            $this->sendResult(array());\n        } else {\n            $this->sendError(10101, \"删除失败\");\n        }\n    }\n\n    //获取我的附件列表\n    public function getMyList()\n    {\n        $login_user = $this->checkLogin();\n        $page = I(\"page/d\");\n        $count = I(\"count/d\");\n        $attachment_type = I(\"attachment_type/d\");\n        $display_name = I(\"display_name\");\n        $username = I(\"username\");\n        $return = array();\n        $where = \" uid  = {$login_user['uid']} \";\n        if ($attachment_type == 1) {\n            $where .= \" and file_type like '%image%' \";\n        }\n        if ($attachment_type == 2) {\n            $where .= \" and file_type not like '%image%' \";\n        }\n        if ($display_name) {\n            $like = safe_like($display_name);\n            $where .= \" and display_name  like '%s' \";\n            $params[] = $like;\n        }\n        $files = isset($params) ? D(\"UploadFile\")->where($where, $params)->order(\"addtime desc\")->page($page, $count)->select() : D(\"UploadFile\")->where($where)->order(\"addtime desc\")->page($page, $count)->select();\n        if ($files) {\n            foreach ($files as $key => $value) {\n                $username = '';\n                $return['list'][] = array(\n                    \"file_id\" => $value['file_id'],\n                    \"uid\" => $value['uid'],\n                    \"file_type\" => $value['file_type'],\n                    \"visit_times\" => $value['visit_times'],\n                    \"file_size\" => $value['file_size'],\n                    \"item_id\" => $value['item_id'],\n                    \"page_id\" => $value['page_id'],\n                    \"file_size_m\" => round($value['file_size'] / (1024 * 1024), 3),\n                    \"display_name\" => $value['display_name'] ? $value['display_name'] : '',\n                    \"url\" => server_url(\"api/attachment/visitFile\", array(\"sign\" => $value['sign'])),\n                    \"addtime\" => date(\"Y-m-d H:i:s\", $value['addtime']),\n                    \"last_visit_time\" => date(\"Y-m-d H:i:s\", $value['last_visit_time']),\n                );\n            }\n        }\n        $return['total'] = isset($params) ? D(\"UploadFile\")->where($where, $params)->count() : D(\"UploadFile\")->where($where)->count();\n        $used = D(\"UploadFile\")->where($where)->getField('sum(file_size)');\n        $return['used'] = $used;\n        $return['used_m'] = round($used / (1024 * 1024), 3);\n        $used_flow =  D(\"Attachment\")->getUserFlow($login_user['uid']);; //该用户的本月使用流量\n        $return['used_flow_m'] = round($used_flow / (1024 * 1024), 3);\n\n        $this->sendResult($return);\n    }\n\n    //删除附件\n    public function deleteMyAttachment()\n    {\n        $login_user = $this->checkLogin();\n        $file_id = I(\"file_id/d\") ? I(\"file_id/d\") : 0;\n\n        $file = D(\"UploadFile\")->where(\"file_id = '%d' and uid ='%d' \", array($file_id, $login_user['uid']))->find();\n\n        if ($file) {\n            $ret = D(\"Page\")->deleteFile($file_id);\n            if ($ret) {\n                $this->sendResult(array());\n                return;\n            }\n        }\n        $this->sendError(10101, \"删除失败\");\n    }\n\n    //将已上传文件绑定到页面中\n    public function bindingPage()\n    {\n        $login_user = $this->checkLogin();\n        $file_id = I(\"file_id/d\") ? I(\"file_id/d\") : 0;\n        $page_id = I(\"page_id/d\");\n        $file = D(\"UploadFile\")->where(\"file_id = '%d' and uid ='%d' \", array($file_id, $login_user['uid']))->find();\n        $page = M(\"Page\")->where(array('page_id' => $page_id))->find();\n        if (!$this->checkItemEdit($login_user['uid'], $page['item_id'])) {\n            $this->sendError(10103);\n            return;\n        }\n        $insert = array(\n            \"file_id\" => $file_id,\n            \"item_id\" => $page['item_id'],\n            \"page_id\" => $page_id,\n            \"addtime\" => time(),\n        );\n        $ret = D(\"FilePage\")->add($insert);\n        if ($ret) {\n            $this->sendResult(array());\n        } else {\n            $this->sendError(10101);\n        }\n    }\n\n    //输出本地文件到浏览器\n    public function _downloadFile($filename, $rename = 'showdoc')\n    {\n\n\n        //设置脚本的最大执行时间，设置为0则无时间限制\n        set_time_limit(3000);\n        ini_set('max_execution_time', '0');\n\n        //通过header()发送头信息\n        //因为不知道文件是什么类型的，告诉浏览器输出的是字节流\n        header('content-type:application/octet-stream');\n\n        //告诉浏览器返回的文件大小类型是字节\n        header('Accept-Ranges:bytes');\n\n        //获得文件大小\n        $filesize = filesize($filename); //(此方法无法获取到远程文件大小)，远程文件用下面get_headers方法\n        //$header_array = get_headers($filename, true);\n        //$filesize = $header_array['Content-Length'];\n        //var_dump($header_array);exit();\n        //告诉浏览器返回的文件大小\n        header('Accept-Length:' . $filesize);\n        //告诉浏览器文件作为附件处理并且设定最终下载完成的文件名称\n        header('content-disposition:attachment;filename=' . basename($rename));\n\n        //针对大文件，规定每次读取文件的字节数为4096字节，直接输出数据\n        $read_buffer = 4096;\n        $handle = fopen($filename, 'rb');\n        //总的缓冲的字节数\n        $sum_buffer = 0;\n        //只要没到文件尾，就一直读取\n        while (!feof($handle) && $sum_buffer < $filesize) {\n            echo fread($handle, $read_buffer);\n            $sum_buffer += $read_buffer;\n        }\n\n        //关闭句柄\n        fclose($handle);\n    }\n}\n"
  },
  {
    "path": "server/Application/Api/Controller/BaseController.class.php",
    "content": "<?php\n\nnamespace Api\\Controller;\n\nuse Think\\Controller;\n\nclass BaseController extends Controller\n{\n\n\t//是否开启本地调试\n\tprivate $is_local_debug;\n\n\tpublic function __construct()\n\t{\n\t\t//是否开启本地调试。\n\t\t$this->is_local_debug = 0;\n\n\t\t//做一个检测，以免这个配置更新到线上。\n\t\tif (\n\t\t\t$this->is_local_debug > 0\n\t\t\t&& strpos($_SERVER['HTTP_HOST'], '127.0.0.1') === false\n\t\t\t&& $_SERVER['HTTP_HOST'] != 'wu.com'\n\t\t\t&& strpos($_SERVER['HTTP_HOST'], \"192.168\") == false\n\t\t) {\n\t\t\t$this->sendError(\"-1001\", \"非本地环境禁止开通调试。请通知管理员关闭调试模式\");\n\t\t\texit();\n\t\t}\n\n\t\t//检测数据库文件是否有可写权限\n\t\t$this->checkDbWhitable();\n\n\t\t//为了兼容纯json请求\n\t\tif (strstr($_SERVER['CONTENT_TYPE'], \"json\")) {\n\t\t\t$json = file_get_contents('php://input');\n\t\t\t$array = json_decode($json, 1);\n\t\t\t$_POST = array_merge($_POST, $array);\n\t\t}\n\n\t\tD(\"Update\")->checkDb();\n\t}\n\n\n\tpublic function checkLogin($redirect = true)\n\t{\n\n\t\tif (!session(\"login_user\")) {\n\t\t\t$user_token = I(\"user_token\") ? I(\"user_token\") : cookie('cookie_token');\n\t\t\t$user_token = $user_token ? $user_token : $_REQUEST['user_token'];\n\t\t\tif ($user_token) {\n\t\t\t\t$ret = D(\"UserToken\")->getToken($user_token);\n\t\t\t\tif ($ret && $ret['token_expire'] > time()) {\n\t\t\t\t\tD(\"UserToken\")->setLastTime($user_token);\n\t\t\t\t\t$login_user = D(\"User\")->where(array('uid' => $ret['uid']))->find();\n\t\t\t\t\tunset($ret['password']);\n\t\t\t\t\tsession(\"login_user\", $login_user);\n\t\t\t\t\treturn $login_user;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif ($redirect) {\n\t\t\t\t$this->sendError(10102);\n\t\t\t\texit();\n\t\t\t}\n\t\t} else {\n\t\t\treturn  session(\"login_user\");\n\t\t}\n\t}\n\n\t//检查是否是管理员\n\tpublic function checkAdmin($redirect = true)\n\t{\n\t\t$login_user = session(\"login_user\");\n\t\tif ($login_user) {\n\t\t\tif ($login_user['groupid'] == 1) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\tif ($redirect) {\n\t\t\t$this->sendError(10103);\n\t\t\texit();\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * 返回json结果\n\t */\n\tprotected function sendResult($array)\n\t{\n\t\tif (isset($array['error_code'])) {\n\t\t\t$result['error_code'] = $array['error_code'];\n\t\t\t$result['error_message'] = $array['error_message'];\n\t\t} else {\n\t\t\t$result['error_code'] = 0;\n\t\t\t$result['data'] = $array;\n\t\t}\n\n\n\t\techo json_encode($result);\n\n\t\t//如果开启API调试模式，则记录请求参数和返回结果\n\t\tif (C('API_LOG')) {\n\t\t\t$info = '';\n\t\t\t$info .= \"\\n\\n【★★★★★★★★★★★】\";\n\t\t\t$info .= \"\\n请求接口：\" . MODULE_NAME  . \"/\" . CONTROLLER_NAME . \"/\" . ACTION_NAME . \"\";\n\t\t\t$info .= \"\\n请求\" . '$_REQUEST' . \"：\\n\";\n\t\t\t$info .= json_encode($_REQUEST);\n\t\t\t$info .= \"\\n返回结果：\\n\";\n\t\t\t$info .= json_encode($result) . \"\\n\";\n\t\t\t$info .= \"【★★★★★★★★★★★】\\n\";\n\t\t\t\\Think\\log::record($info, 'INFO');\n\t\t}\n\t}\n\n\t//返回错误提示\n\tprotected function sendError($error_code, $error_message = '')\n\t{\n\t\t$error_code = $error_code ? $error_code : 10103;\n\n\t\tif (!$error_message) {\n\t\t\t$error_codes = C(\"error_codes\");\n\t\t\tforeach ($error_codes as $key => $value) {\n\t\t\t\tif ($key == $error_code) {\n\t\t\t\t\t$error_message = $value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t$array['error_code'] = $error_code;\n\t\t$array['error_message'] = $error_message;\n\t\t$this->sendResult($array);\n\t}\n\n\t//判断某用户是否有项目编辑权限（项目成员member_group_id为1，是项目所在团队的成员并且成员权限为1 ，以及 项目管理着，创建者和系统管理员）\n\tprotected function checkItemEdit($uid, $item_id)\n\t{\n\n\t\tif (!$uid) {\n\t\t\treturn false;\n\t\t}\n\n\t\t$item = D(\"Item\")->where(\"item_id = '%d' \", array($item_id))->find();\n\t\tif ($item['uid'] && $item['uid'] == $uid) {\n\t\t\treturn true;\n\t\t}\n\t\t$ItemMember = D(\"ItemMember\")->where(\"item_id = '%d' and uid = '%d' and member_group_id = 1 \", array($item_id, $uid))->find();\n\t\tif ($ItemMember) {\n\t\t\treturn true;\n\t\t}\n\n\t\t$ItemMember = D(\"TeamItemMember\")->where(\"item_id = '%d' and member_uid = '%d' and member_group_id = 1 \", array($item_id, $uid))->find();\n\t\tif ($ItemMember) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif ($this->checkItemManage($uid, $item_id)) {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t//判断某用户是否有项目管理权限（项目创建者、项目管理员、系统管理员）\n\tprotected function checkItemManage($uid, $item_id)\n\t{\n\n\t\tif (!$uid) {\n\t\t\treturn false;\n\t\t}\n\t\t$uid = intval($uid);\n\t\t$item_id = intval($item_id);\n\n\t\t$item = D(\"Item\")->where(\"item_id = '%d' \", array($item_id))->find();\n\t\tif ($item['uid'] && $item['uid'] == $uid) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif (D(\"ItemMember\")->where(\"item_id = '%d'  and member_group_id = 2 and uid = '%d' \", array($item_id, $uid))->find()) {\n\t\t\treturn true;\n\t\t}\n\t\tif (D(\"TeamItemMember\")->where(\"item_id = '%d'  and member_group_id = 2 and member_uid = '%d' \", array($item_id, $uid))->find()) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif ($this->checkAdmin(false)) {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t//判断某用户是否为项目创建者\n\tprotected function checkItemCreator($uid, $item_id)\n\t{\n\t\tif (!$uid) {\n\t\t\treturn false;\n\t\t}\n\t\tif (session(\"creat_item_\" . $item_id)) {\n\t\t\treturn true;\n\t\t}\n\n\t\t$item = D(\"Item\")->where(\"item_id = '%d' \", array($item_id))->find();\n\t\tif ($item['uid'] && $item['uid'] == $uid) {\n\t\t\tsession(\"creat_item_\" . $item_id, 1);\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\t//判断某用户是否有项目访问权限（公开项目的话所有人可访问，私有项目则项目成员、项目创建者和访问密码输入者可访问）\n\tprotected function checkItemVisit($uid, $item_id, $refer_url = '')\n\t{\n\n\t\t// 这个session会在item/pwd那里设置\n\t\tif (session(\"visit_item_\" . $item_id)) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif ($this->checkItemManage($uid, $item_id)) {\n\t\t\treturn true;\n\t\t}\n\n\t\t$ItemMember = D(\"ItemMember\")->where(\"item_id = '%d' and uid = '%d'  \", array($item_id, $uid))->find();\n\t\tif ($ItemMember) {\n\t\t\treturn true;\n\t\t}\n\n\t\t$TeamItemMember = D(\"TeamItemMember\")->where(\"item_id = '%d' and member_uid = '%d'  \", array($item_id, $uid))->find();\n\t\tif ($TeamItemMember) {\n\t\t\treturn true;\n\t\t}\n\n\t\t$item = D(\"Item\")->where(\"item_id = '%d' \", array($item_id))->find();\n\t\tif ($item['password'] && $item['password'] != I('_item_pwd')) { // _item_pwd参数的作用在于：跨域请求的时候无法带cooies，自然无法记住session。用这个参数使记住用户输入过项目密码。\n\t\t\treturn false;\n\t\t} else {\n\t\t\treturn true;\n\t\t}\n\t}\n\t//检查数据库文件是否可写\n\tprotected function checkDbWhitable()\n\t{\n\t\t$file = C(\"DB_NAME\");\n\t\tif ($fp = @fopen($file, 'a+')) {\n\t\t\t@fclose($fp);\n\t\t\treturn true;\n\t\t} else {\n\t\t\t$this->sendError(\"10103\", \"Sqlite/showdoc.db.php文件不可写\");\n\t\t\texit();\n\t\t}\n\t}\n\n\t//检查使用composer包是否满足php版本需求\n\tpublic function checkComposerPHPVersion()\n\t{\n\t\tif (version_compare(PHP_VERSION, COMPOSER_PHP_VERSION, '<=')) {\n\t\t\t$this->sendError(10101, \"该功能需要php版本\" . COMPOSER_PHP_VERSION . \"以上，你所使用的php版本\" . PHP_VERSION . \"已滞后。请联系管理员进行升级\");\n\t\t\texit();\n\t\t}\n\t}\n\n\t//判断某用户是否有团队管理权限（团队创建者、团队管理员）\n\tprotected function checkTeamManage($uid, $team_id)\n\t{\n\n\t\tif (!$uid) {\n\t\t\treturn false;\n\t\t}\n\n\t\t$team = D(\"Team\")->where(\"id = '%d' \", array($team_id))->find();\n\t\tif ($team['uid'] && $team['uid'] == $uid) {\n\t\t\treturn true;\n\t\t}\n\n\t\t$team_member = D(\"TeamMember\")->where(\"team_id = '%d' and member_uid = '%d' and team_member_group_id = 2  \", array($team_id, $uid))->find();\n\t\tif ($team_member) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif ($this->checkAdmin(false)) {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n}\n"
  },
  {
    "path": "server/Application/Api/Controller/CatalogController.class.php",
    "content": "<?php\n\nnamespace Api\\Controller;\n\nuse Think\\Controller;\n\nclass CatalogController extends BaseController\n{\n\n    //获取目录列表\n    public function catList()\n    {\n        $login_user = $this->checkLogin();\n        $item_id = I(\"item_id/d\");\n        if (!$this->checkItemVisit($login_user['uid'], $item_id)) {\n            $this->sendError(10103);\n            return;\n        }\n        if ($item_id > 0) {\n            $ret = D(\"Catalog\")->getList($item_id);\n            $ret = D(\"Catalog\")->filteMemberCat($login_user['uid'], $ret);\n        }\n        if ($ret) {\n            $this->sendResult($ret);\n        } else {\n            $this->sendResult(array());\n        }\n    }\n\n    //获取目录列表\n    public function catListGroup()\n    {\n        $login_user = $this->checkLogin();\n        $item_id = I(\"item_id/d\");\n        if (!$this->checkItemVisit($login_user['uid'], $item_id)) {\n            $this->sendError(10103);\n            return;\n        }\n        if ($item_id > 0) {\n            $ret = D(\"Catalog\")->getList($item_id, true);\n            $ret = D(\"Catalog\")->filteMemberCat($login_user['uid'], $ret);\n        }\n        if ($ret) {\n            $this->sendResult($ret);\n        } else {\n            $this->sendResult(array());\n        }\n    }\n\n\n    //获取目录列表，其中目录名将按层级描述。比如某个目录的名字为\"我的项目/用户接口/用户登录\"\n    public function catListName()\n    {\n        $login_user = $this->checkLogin();\n        $item_id = I(\"item_id/d\");\n        if (!$this->checkItemVisit($login_user['uid'], $item_id)) {\n            $this->sendError(10103);\n            return;\n        }\n        if ($item_id > 0) {\n            $ret = D(\"Catalog\")->getList($item_id, true);\n            $ret = D(\"Catalog\")->filteMemberCat($login_user['uid'], $ret);\n        }\n        if ($ret) {\n            $return = array();\n\n            //匿名递归函数，准备递归改名\n            // uee 指令后面引用参数转递。方便函数内部中使用。\n            $rename = function ($catalog, $p_cat_name) use (&$return, &$rename) {\n                if ($catalog) {\n                    foreach ($catalog as $key => $value) {\n                        $value['cat_name'] = $p_cat_name . '/' . $value['cat_name'];\n                        $sub = $value['sub'];\n                        unset($value['sub']);\n                        $return[] = $value;\n                        if ($sub) {\n                            $rename($sub, $value['cat_name']);\n                        }\n                    }\n                }\n            };\n\n            foreach ($ret as $key => $value) {\n                $sub = $value['sub'];\n                unset($value['sub']);\n                $return[] = $value;\n                if ($sub) {\n                    $rename($sub, $value['cat_name']);\n                }\n            }\n            $this->sendResult($return);\n        } else {\n            $this->sendResult(array());\n        }\n    }\n\n\n    //获取二级目录列表\n    public function secondCatList()\n    {\n        $login_user = $this->checkLogin();\n        $item_id = I(\"item_id/d\");\n        if (!$this->checkItemVisit($login_user['uid'], $item_id)) {\n            $this->sendError(10103);\n            return;\n        }\n        if ($item_id > 0) {\n            $ret = D(\"Catalog\")->getListByLevel($item_id, 2);\n        }\n        if ($ret) {\n            $this->sendResult($ret);\n        } else {\n            $this->sendResult(array());\n        }\n    }\n\n    //获取二级目录的子目录列表，即三级目录列表（如果存在的话）\n    public function childCatList()\n    {\n        $login_user = $this->checkLogin();\n        $cat_id = I(\"cat_id/d\");\n        if ($cat_id > 0) {\n            $row = D(\"Catalog\")->where(array('cat_id' => $cat_id))->find();\n            $item_id = $row['item_id'];\n            if (!$this->checkItemVisit($login_user['uid'], $item_id)) {\n                $this->sendError(10103);\n                return;\n            }\n            $ret =  D(\"Catalog\")->getChlid($item_id, $cat_id);\n        }\n        if ($ret) {\n            $this->sendResult($ret);\n        } else {\n            $this->sendResult(array());\n        }\n    }\n\n    //保存目录\n    public function save()\n    {\n        $cat_name = I(\"cat_name\");\n        $s_number = I(\"s_number/d\") ? I(\"s_number/d\") : '';\n        $cat_id = I(\"cat_id/d\") ? I(\"cat_id/d\") : 0;\n        $parent_cat_id = I(\"parent_cat_id/d\") ? I(\"parent_cat_id/d\") : 0;\n        $item_id =  I(\"item_id/d\");\n\n        $login_user = $this->checkLogin();\n        if (!$this->checkItemEdit($login_user['uid'], $item_id)) {\n            $this->sendError(10103);\n            return;\n        }\n        //禁止空目录的生成\n        if (!$cat_name) {\n            return;\n        }\n\n        if ($parent_cat_id &&  $parent_cat_id == $cat_id) {\n            $this->sendError(10101, \"上级目录不能选择自身\");\n            return;\n        }\n\n        $data['cat_name'] = $cat_name;\n        if ($s_number) $data['s_number'] = $s_number;\n        $data['item_id'] = $item_id;\n        $data['parent_cat_id'] = $parent_cat_id;\n        if ($parent_cat_id > 0) {\n            $row = D(\"Catalog\")->where(array('cat_id' => $parent_cat_id))->find();\n            $data['level'] = $row['level'] + 1;\n        } else {\n            $data['level'] = 2;\n        }\n\n        if ($cat_id > 0) {\n            $cat = D(\"Catalog\")->where(array('cat_id' => $cat_id))->find();\n            $item_id = $cat['item_id'];\n            if (!$this->checkItemEdit($login_user['uid'], $item_id)) {\n                $this->sendError(10103);\n                return;\n            }\n            //如果一个目录已经是别的目录的父目录，那么它将无法再转为level4目录\n            //if (D(\"Catalog\")->where(array('parent_cat_id' => $cat_id))->find() && $data['level'] == 4 ) {\n            //$this->sendError(10101,\"该目录含有子目录，不允许转为底层目录。\");\n            //return;\n            //}\n\n            $ret = D(\"Catalog\")->where(array('cat_id' => $cat_id))->save($data);\n            $return = D(\"Catalog\")->where(array('cat_id' => $cat_id))->find();\n            D(\"ItemChangeLog\")->addLog($login_user['uid'], $item_id, 'update', 'catalog', $cat_id, $cat_name);\n        } else {\n            $data['addtime'] = time();\n            $cat_id = D(\"Catalog\")->add($data);\n            $return = D(\"Catalog\")->where(array('cat_id' => $cat_id))->find();\n            D(\"ItemChangeLog\")->addLog($login_user['uid'], $item_id, 'create', 'catalog', $cat_id, $cat_name);\n        }\n        if (!$return) {\n            $return['error_code'] = 10103;\n            $return['error_message'] = 'request  fail';\n        }\n        //$this->sendResult($return);\n        // 这里返回了 cat_id ，是为了兼容历史。实际上应该返回整个文件夹对象\n        // 等runapi版本都更新了后，可以改为返回对象。新runapi会兼容两种情况\n        $this->sendResult($cat_id);\n    }\n\n    //删除目录\n    public function delete()\n    {\n        $cat_id = I(\"post.cat_id/d\") ? I(\"post.cat_id/d\") : 0;\n        $cat = D(\"Catalog\")->where(array('cat_id' => $cat_id))->find();\n        $item_id = $cat['item_id'];\n\n        $login_user = $this->checkLogin();\n        if (!$this->checkItemEdit($login_user['uid'], $item_id)) {\n            $return['error_code'] = -1;\n            $return['error_message'] = L('no_permissions');\n            $this->sendResult($return);\n            return;\n        }\n\n        if ($cat_id > 0) {\n\n            $ret = D(\"Catalog\")->deleteCat($cat_id);\n        }\n        if ($ret) {\n            $this->sendResult($ret);\n        } else {\n            $return['error_code'] = -1;\n            $return['error_message'] = 'request  fail';\n            $this->sendResult($return);\n        }\n    }\n\n    // 此方法开始慢慢少用。现在准备让前端自己用逻辑判断目录，不再需要后台获取。新建页面的时候默认使用当前打开页面的目录。\n    // 但由于可能有些老旧客户端用到，先暂时保留该接口\n    //编辑页面时，自动帮助用户选中目录\n    //选中的规则是：编辑页面则选中该页面目录，复制页面则选中目标页面目录;\n    //              如果是恢复历史页面则使用历史页面的目录，如果都没有则选中用户上次使用的目录\n    public function getDefaultCat()\n    {\n        $login_user = $this->checkLogin();\n        $page_id = I(\"page_id/d\");\n        $item_id = I(\"item_id/d\");\n        $page_history_id = I(\"page_history_id/d\");\n        $copy_page_id = I(\"copy_page_id/d\");\n\n        if ($page_id > 0) {\n            if ($page_history_id) {\n                $page = D(\"PageHistory\")->where(array('page_history_id' => $page_history_id))->find();\n            } else {\n                $page = M(\"Page\")->where(array('page_id' => $page_id))->find();\n            }\n            $default_cat_id = $page['cat_id'];\n        }\n        //如果是复制接口\n        elseif ($copy_page_id) {\n            $copy_page = M(\"Page\")->where(array('page_id' => $copy_page_id))->find();\n            $page['item_id'] = $copy_page['item_id'];\n            $default_cat_id = $copy_page['cat_id'];\n        } else {\n            //查找用户上一次设置的目录\n            $last_page = D(\"Page\")->where(\"author_uid = %d and item_id = %d\", array($login_user['uid'], $item_id))->order(\" addtime desc \")->limit(1)->find();\n            $default_cat_id = $last_page['cat_id'];\n        }\n\n        $item_id = $page['item_id'] ? $page['item_id'] : $item_id;\n\n\n        if (!$this->checkItemEdit($login_user['uid'], $item_id)) {\n            $this->sendError(10101, L('no_permissions'));\n            return;\n        }\n\n        $this->sendResult(array(\"default_cat_id\" => $default_cat_id));\n    }\n\n    //批量更新\n    public function batUpdate()\n    {\n        $cats = I(\"post.cats\");\n        $item_id = I(\"post.item_id/d\");\n        // 获取拖动元素的信息\n        $dragged_id = I(\"post.dragged_id/d\") ? I(\"post.dragged_id/d\") : 0;\n        $dragged_title = I(\"post.dragged_title\");\n        $dragged_type = I(\"post.dragged_type\");\n        \n        $login_user = $this->checkLogin();\n        if (!$this->checkItemEdit($login_user['uid'], $item_id)) {\n            $this->sendError(10103);\n            return;\n        }\n        $ret = '';\n        $data_array = json_decode(htmlspecialchars_decode($cats), true);\n        if ($data_array) {\n            foreach ($data_array as $key => $value) {\n                if ($value['cat_name']) {\n                    $ret = D(\"Catalog\")->where(\" cat_id = '%d' and item_id = '%d' \", array($value['cat_id'], $item_id))->save(array(\n                        \"cat_name\" => $value['cat_name'],\n                        \"parent_cat_id\" => $value['parent_cat_id'],\n                        \"level\" => $value['level'],\n                        \"s_number\" => $value['s_number'],\n                    ));\n                }\n                if ($value['page_id'] > 0) {\n                    $ret = D(\"Page\")->where(\" page_id = '%d' and item_id = '%d' \", array($value['page_id'], $item_id))->save(array(\n                        \"cat_id\" => $value['parent_cat_id'],\n                        \"s_number\" => $value['s_number'],\n                    ));\n                }\n            }\n            \n            // 组装日志信息\n            $log_message = '目录树';\n            if ($dragged_id > 0 && $dragged_title) {\n                if ($dragged_type == 'page') {\n                    $log_message = '拖动页面「'.$dragged_title.'」';\n                } else if ($dragged_type == 'catalog') {\n                    $log_message = '拖动目录「'.$dragged_title.'」';\n                }\n            }\n            \n            D(\"ItemChangeLog\")->addLog($login_user['uid'], $item_id, 'drag', 'tree', 0, $log_message);\n        }\n\n        $this->sendResult(array());\n    }\n\n\n    //获取某个目录下所有页面的标题\n    public function getPagesBycat()\n    {\n        $cat_id = I(\"cat_id/d\") ? I(\"cat_id/d\") : 0;\n        $item_id =  I(\"item_id/d\");\n        $login_user = $this->checkLogin();\n        if (!$this->checkItemEdit($login_user['uid'], $item_id)) {\n            $this->sendError(10103);\n            return;\n        }\n        $return = D(\"Page\")->where(\"cat_id = '%d' and  item_id = '%d' and is_del = 0\", array($cat_id, $item_id))->field(\"page_id , page_title,s_number\")->order(\"s_number asc , page_id asc\")->select();\n        $this->sendResult($return);\n    }\n\n    //  复制或移动目录\n    public function copy()\n    {\n        // 参数new_p_cat_id 复制完目录后，挂在哪个父目录下。这里是父目录id。可为0\n        // $to_item_id 要复制到的项目id。可以是同一个项目，可以是跨项目。默认是同一个项目\n        $cat_id = I(\"cat_id/d\");\n        $new_p_cat_id = I(\"new_p_cat_id/d\") ? I(\"new_p_cat_id/d\") : 0;\n        $to_item_id = I(\"to_item_id/d\") ? I(\"to_item_id/d\") : 0;\n        $is_del = I(\"is_del/d\") ? I(\"is_del/d\") : 0; // 复制完是否删除原目录（相当于移动目录）\n        $login_user = $this->checkLogin();\n        if (!$this->checkItemEdit($login_user['uid'], $to_item_id)) {\n            $this->sendError(10103);\n            return;\n        }\n        $old_cat_ary = D(\"Catalog\")->where(array('cat_id' => $cat_id))->find();\n        if (!$this->checkItemEdit($login_user['uid'], $old_cat_ary['item_id'])) {\n            $this->sendError(10103);\n            return;\n        }\n        $res = D(\"Catalog\")->copy($login_user['uid'], $cat_id, $new_p_cat_id, $to_item_id);\n        if ($is_del && $res) {\n            D(\"Catalog\")->deleteCat($cat_id);\n        }\n        $this->sendResult($res);\n    }\n}\n"
  },
  {
    "path": "server/Application/Api/Controller/CommonController.class.php",
    "content": "<?php\n\nnamespace Api\\Controller;\n\nuse Think\\Controller;\nuse Gregwar\\Captcha\\CaptchaBuilder as CaptchaBuilder;\n\nclass CommonController extends BaseController\n{\n\n\n  //生成二维码\n  public function qrcode()\n  {\n    Vendor('Phpqrcode.phpqrcode');\n    $url = I(\"url\");\n    $url = urldecode($url) ? urldecode($url) : $url;\n    $size = I(\"size\") ? I(\"size\") : 6;\n    $object = new \\QRcode();\n    $object->png($url, false, 3, $size, 2);\n  }\n\n  //生成验证码\n  public function verify()\n  {\n\n    if (version_compare(PHP_VERSION, COMPOSER_PHP_VERSION, '>')) {\n      $builder = new CaptchaBuilder();\n      $builder->build();\n      session('v_code', strtolower($builder->getPhrase())); //转成小写后存入session\n      header('Content-type: image/PNG');\n      $builder->output();\n    } else {\n      //生成验证码图片\n      Header(\"Content-type: image/PNG\");\n      $im = imagecreate(44, 18); // 画一张指定宽高的图片\n      $back = ImageColorAllocate($im, 245, 245, 245); // 定义背景颜色\n      imagefill($im, 0, 0, $back); //把背景颜色填充到刚刚画出来的图片中\n      $vcodes = \"\";\n      srand((float)microtime() * 1000000);\n      //生成4位数字\n      for ($i = 0; $i < 4; $i++) {\n        $font = ImageColorAllocate($im, rand(100, 255), rand(0, 100), rand(100, 255)); // 生成随机颜色\n        $authnum = rand(1, 9);\n        $vcodes .= $authnum;\n        imagestring($im, 5, 2 + $i * 10, 1, $authnum, $font);\n      }\n      $_SESSION['v_code'] = $vcodes;\n\n      for ($i = 0; $i < 200; $i++) //加入干扰象素\n      {\n        $randcolor = ImageColorallocate($im, rand(0, 255), rand(0, 255), rand(0, 255));\n        imagesetpixel($im, rand() % 70, rand() % 30, $randcolor); // 画像素点函数\n      }\n      ImagePNG($im);\n      ImageDestroy($im);\n    }\n  }\n\n  public function createCaptcha()\n  {\n    if (version_compare(PHP_VERSION, COMPOSER_PHP_VERSION, '>')) {\n      $captcha = get_rand_str(4);\n    } else {\n      $captcha = rand(1000, 9999);\n    }\n    $data = array(\n      \"mobile\" => \"\",\n      \"captcha\" => $captcha,\n      \"expire_time\" => time() + 60 * 10,\n    );\n    $captcha_id = D(\"Captcha\")->add($data);\n    $this->sendResult(array(\"captcha_id\" => $captcha_id));\n  }\n\n  public function showCaptcha()\n  {\n    $captcha_id = I(\"captcha_id/d\");\n    $captcha = D(\"Captcha\")->where(\"captcha_id = '%s' \", array($captcha_id))->find();\n\n    if (version_compare(PHP_VERSION, COMPOSER_PHP_VERSION, '>')) {\n      $builder = new CaptchaBuilder($captcha['captcha']);\n      $builder->build();\n      header('Content-type: image/PNG');\n      $builder->output();\n    } else {\n      $numArray  = array_map('intval', str_split($captcha['captcha']));\n      //生成验证码图片\n      Header(\"Content-type: image/PNG\");\n      $im = imagecreate(44, 18); // 画一张指定宽高的图片\n      $back = ImageColorAllocate($im, 245, 245, 245); // 定义背景颜色\n      imagefill($im, 0, 0, $back); //把背景颜色填充到刚刚画出来的图片中\n      srand((float)microtime() * 1000000);\n      //生成4位数字\n      for ($i = 0; $i < 4; $i++) {\n        $font = ImageColorAllocate($im, rand(100, 255), rand(0, 100), rand(100, 255)); // 生成随机颜色\n        imagestring($im, 5, 2 + $i * 10, 1, $numArray[$i], $font);\n      }\n      for ($i = 0; $i < 200; $i++) //加入干扰象素\n      {\n        $randcolor = ImageColorallocate($im, rand(0, 255), rand(0, 255), rand(0, 255));\n        imagesetpixel($im, rand() % 70, rand() % 30, $randcolor); // 画像素点函数\n      }\n      ImagePNG($im);\n      ImageDestroy($im);\n    }\n  }\n\n  //获取网站首页配置\n  public function homePageSetting()\n  {\n    $home_page = D(\"Options\")->get(\"home_page\");\n    $home_item = D(\"Options\")->get(\"home_item\");\n    $open_api_key = D(\"Options\")->get(\"open_api_key\");\n    $beian = D(\"Options\")->get(\"beian\");\n    $register_open = D(\"Options\")->get(\"register_open\");\n    $array = array(\n      \"home_page\" => $home_page,\n      \"home_item\" => $home_item,\n      \"beian\" => $beian ? $beian : '',\n      \"is_show_ai\" => $open_api_key ? 1 : 0,\n      \"register_open\" => $register_open === false ? 1 : intval($register_open),\n    );\n    $this->sendResult($array);\n  }\n\n  //返回showdoc版本\n  public function version()\n  {\n    $file = file_get_contents('../composer.json');\n    $json = json_decode($file, 1);\n    $this->sendResult(array(\"version\" => $json['version']));\n  }\n\n  //浏览附件\n  public function visitFile()\n  {\n    R(\"Attachment/visitFile\");\n  }\n}\n"
  },
  {
    "path": "server/Application/Api/Controller/ExportController.class.php",
    "content": "<?php\n\nnamespace Api\\Controller;\n\nuse Think\\Controller;\n\nclass ExportController extends BaseController\n{\n\n    //导出整个项目为word\n    public function word()\n    {\n        set_time_limit(100);\n        ini_set('memory_limit', '800M');\n        import(\"Vendor.Parsedown.Parsedown\");\n        $Parsedown = new \\Parsedown();\n        $convert = new \\Api\\Helper\\Convert();\n        $item_id =  I(\"item_id/d\");\n        $cat_id =  I(\"cat_id/d\");\n        $page_id =  I(\"page_id/d\");\n        $login_user = $this->checkLogin();\n        if (!$this->checkItemEdit($login_user['uid'], $item_id)) {\n            $this->message(L('no_permissions'));\n            return;\n        }\n\n        // 获取项目信息\n        $item = D(\"Item\")->where(array('item_id' => $item_id))->find();\n        \n        // 检查是否为runapi项目并获取全局header\n        $global_headers = array();\n        if ($item['item_type'] == '3') { // runapi项目类型为3\n            $runapiModel = new \\Api\\Model\\RunapiModel();\n            $globalParam = $runapiModel->getGlobalParam($item_id);\n            if (isset($globalParam['header']) && !empty($globalParam['header'])) {\n                $global_headers = $globalParam['header'];\n            }\n        }\n\n        // 成员目录权限：获取该用户在此项目下允许的目录集合（根下一层）。若非空，则导出仅限这些目录\n        $allowedCatIds = D(\"Member\")->getCatIds($item_id, $login_user['uid']);\n\n        $menu = D(\"Item\")->getContent($item_id, \"*\", \"*\", 1);\n        if ($page_id > 0) {\n            $page = D(\"Page\")->where(array('page_id' => $page_id))->find();\n            // 如果有限定目录，则校验页面所属目录是否在允许集合内\n            if (!empty($allowedCatIds)) {\n                $pageCatId = intval($page['cat_id']);\n                $allowed = array_flip(array_map('intval', $allowedCatIds));\n                if (!isset($allowed[$pageCatId])) {\n                    $this->message(L('no_permissions'));\n                    return;\n                }\n            }\n            $pages[] = $page;\n        } else if ($cat_id) {\n            // 如果有限定目录，则cat_id必须在允许集合内\n            if (!empty($allowedCatIds) && !in_array(intval($cat_id), array_map('intval', $allowedCatIds))) {\n                $this->message(L('no_permissions'));\n                return;\n            }\n            foreach ($menu['catalogs'] as $key => $value) {\n                if ($cat_id == $value['cat_id']) {\n                    $pages = $value['pages'];\n                    $catalogs = $value['catalogs'];\n                } else {\n                    if ($value['catalogs']) {\n                        foreach ($value['catalogs'] as $key2 => $value2) {\n                            if ($cat_id == $value2['cat_id']) {\n                                $pages = $value2['pages'];\n                                $catalogs = $value2['catalogs'];\n                            } else {\n                                if ($value2['catalogs']) {\n                                    foreach ($value2['catalogs'] as $key3 => $value3) {\n                                        if ($cat_id == $value3['cat_id']) {\n                                            $pages = $value3['pages'];\n                                            $catalogs = $value3['catalogs'];\n                                        } else {\n                                            if ($value3['catalogs']) {\n                                                foreach ($value3['catalogs'] as $key4 => $value4) {\n                                                    if ($cat_id == $value4['cat_id']) {\n                                                        $pages = $value4['pages'];\n                                                        $catalogs = $value4['catalogs'];\n                                                    }\n                                                }\n                                            }\n                                        }\n                                    }\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n        } else {\n            // 当存在目录限制时，仅导出被允许的二级目录合集\n            if (!empty($allowedCatIds)) {\n                $pages = array();\n                $catalogs = array();\n                $allowed = array_flip(array_map('intval', $allowedCatIds));\n                if (!empty($menu['catalogs'])) {\n                    foreach ($menu['catalogs'] as $one) {\n                        if (isset($allowed[intval($one['cat_id'])])) {\n                            $catalogs[] = $one;\n                        }\n                    }\n                }\n            } else {\n                $pages = $menu['pages'];\n                $catalogs = $menu['catalogs'];\n            }\n        }\n\n        $data = '';\n        $parent = 1;\n\n        // 如果是runapi项目且有全局header，则先添加全局header信息\n        if (!empty($global_headers)) {\n            $data .= \"<h1>全局Header参数</h1>\";\n            $data .= '<div style=\"margin-left:20px;\">';\n            $data .= \"<table>\";\n            $data .= \"<thead><tr><th>参数名</th><th>值</th><th>是否启用</th><th>备注</th></tr></thead>\";\n            $data .= \"<tbody>\";\n            foreach ($global_headers as $header) {\n                $enabled = isset($header['enabled']) && $header['enabled'] ? '是' : '否';\n                $name = isset($header['name']) ? $header['name'] : '';\n                $value = isset($header['value']) ? $header['value'] : '';\n                $remark = isset($header['remark']) ? $header['remark'] : '';\n                $data .= \"<tr><td>{$name}</td><td>{$value}</td><td>{$enabled}</td><td>{$remark}</td></tr>\";\n            }\n            $data .= \"</tbody></table>\";\n            $data .= '</div>';\n            $parent++;\n        }\n\n        if ($pages) {\n            foreach ($pages as $key => $value) {\n                if (count($pages) > 1) {\n                    $data .= \"<h1>{$parent}、{$value['page_title']}</h1>\";\n                } else {\n                    $data .= \"<h1>{$value['page_title']}</h1>\";\n                }\n                $data .= '<div style=\"margin-left:20px;\">';\n                $tmp_content = $convert->runapiToMd($value['page_content']);\n                $value['page_content'] = $tmp_content ? $tmp_content : $value['page_content'];\n                $data .= htmlspecialchars_decode($Parsedown->text($value['page_content']));\n                $data .= '</div>';\n                $parent++;\n            }\n        }\n        //var_export($catalogs);\n        if ($catalogs) {\n            foreach ($catalogs as $key => $value) {\n                $data .= \"<h1>{$parent}、{$value['cat_name']}</h1>\";\n                $data .= '<div style=\"margin-left:0px;\">';\n                $child = 1;\n                if ($value['pages']) {\n                    foreach ($value['pages'] as $page) {\n                        $data .= \"<h2>{$parent}.{$child}、{$page['page_title']}</h2>\";\n                        $data .= '<div style=\"margin-left:0px;\">';\n                        $tmp_content = $convert->runapiToMd($page['page_content']);\n                        $page['page_content'] = $tmp_content ? $tmp_content : $page['page_content'];\n                        $data .= htmlspecialchars_decode($Parsedown->text($page['page_content']));\n                        $data .= '</div>';\n                        $child++;\n                    }\n                }\n                if ($value['catalogs']) {\n                    $parent2 = 1;\n                    foreach ($value['catalogs'] as $key3 => $value3) {\n                        $data .= \"<h2>{$parent}.{$parent2}、{$value3['cat_name']}</h2>\";\n                        $data .= '<div style=\"margin-left:20px;\">';\n                        $child2 = 1;\n                        if ($value3['pages']) {\n                            foreach ($value3['pages'] as $page3) {\n                                $data .= \"<h3>{$parent}.{$parent2}.{$child2}、{$page3['page_title']}</h3>\";\n                                $data .= '<div style=\"margin-left:0px;\">';\n                                $tmp_content = $convert->runapiToMd($page3['page_content']);\n                                $page3['page_content'] = $tmp_content ? $tmp_content : $page3['page_content'];\n                                $data .= htmlspecialchars_decode($Parsedown->text($page3['page_content']));\n                                $data .= '</div>';\n                                $child2++;\n                            }\n                        }\n\n                        if ($value3['catalogs']) {\n                            $parent3 = 1;\n                            foreach ($value3['catalogs'] as $key4 => $value4) {\n                                $data .= \"<h2>{$parent}.{$parent2}.{$parent3}、{$value4['cat_name']}</h2>\";\n                                $data .= '<div style=\"margin-left:0px;\">';\n                                $child3 = 1;\n                                if ($value4['pages']) {\n                                    foreach ($value4['pages'] as $page4) {\n                                        $data .= \"<h3>{$parent}.{$parent2}.{$parent3}.{$child3}、{$page4['page_title']}</h3>\";\n                                        $data .= '<div style=\"margin-left:30px;\">';\n                                        $tmp_content = $convert->runapiToMd($page4['page_content']);\n                                        $page4['page_content'] = $tmp_content ? $tmp_content : $page4['page_content'];\n                                        $data .= htmlspecialchars_decode($Parsedown->text($page4['page_content']));\n                                        $data .= '</div>';\n                                        $child3++;\n                                    }\n                                }\n                                if ($value4['catalogs']) {\n                                    $parent4 = 1;\n                                    foreach ($value4['catalogs'] as $key5 => $value5) {\n                                        $data .= \"<h2>{$parent}.{$parent2}.{$parent3}.{$parent4}、{$value5['cat_name']}</h2>\";\n                                        $data .= '<div style=\"margin-left:0px;\">';\n                                        $child4 = 1;\n                                        if ($value4['pages']) {\n                                            foreach ($value4['pages'] as $page5) {\n                                                $data .= \"<h3>{$parent}.{$parent2}.{$parent3}.{$parent4}.{$child4}、{$page5['page_title']}</h3>\";\n                                                $data .= '<div style=\"margin-left:30px;\">';\n                                                $tmp_content = $convert->runapiToMd($page5['page_content']);\n                                                $page5['page_content'] = $tmp_content ? $tmp_content : $page5['page_content'];\n                                                $data .= htmlspecialchars_decode($Parsedown->text($page5['page_content']));\n                                                $data .= '</div>';\n                                                $child3++;\n                                            }\n                                        }\n                                        $data .= '</div>';\n                                        $parent3++;\n                                    }\n                                }\n                                $data .= '</div>';\n                                $parent3++;\n                            }\n                        }\n                        $data .= '</div>';\n                        $parent2++;\n                    }\n                }\n                $data .= '</div>';\n                $parent++;\n            }\n        }\n        // 记录项目变更日志：导出\n        D(\"ItemChangeLog\")->addLog($login_user['uid'], $item_id, 'export', 'item', $item_id, $item['item_name']);\n\n        output_word($data,'showdoc_export_'.date('YmdHis'));\n    }\n\n    //导出整个项目为markdown压缩包\n    public function markdown()\n    {\n        set_time_limit(100);\n        ini_set('memory_limit', '800M');\n        $item_id =  I(\"item_id/d\");\n        $login_user = $this->checkLogin();\n        if (!$this->checkItemEdit($login_user['uid'], $item_id)) {\n            $this->message(L('no_permissions'));\n            return;\n        }\n\n        $item = D(\"Item\")->where(array('item_id' => $item_id))->find();\n\n        // 成员目录权限：获取该用户在此项目下允许的目录集合\n        $allowedCatIds = D(\"Member\")->getCatIds($item_id, $login_user['uid']);\n\n        $exportJson = D(\"Item\")->export($item_id, true);\n        $exportData = json_decode($exportJson, 1);\n        if (!empty($allowedCatIds) && isset($exportData['pages']) && is_array($exportData['pages'])) {\n            $allowed = array_flip(array_map('intval', $allowedCatIds));\n            // 目录受限：去掉根目录下的页面，仅保留被允许的二级目录\n            $exportData['pages']['pages'] = array();\n            $filteredCatalogs = array();\n            if (!empty($exportData['pages']['catalogs']) && is_array($exportData['pages']['catalogs'])) {\n                foreach ($exportData['pages']['catalogs'] as $one) {\n                    if (isset($allowed[intval($one['cat_id'])])) {\n                        $filteredCatalogs[] = $one;\n                    }\n                }\n            }\n            $exportData['pages']['catalogs'] = $filteredCatalogs;\n        }\n        $zipArc = new \\ZipArchive();\n        $temp_file = tempnam(sys_get_temp_dir(), 'Tux') . \"_showdoc_.zip\";\n        $temp_dir = sys_get_temp_dir() . \"/showdoc_\" . time() . rand();\n        mkdir($temp_dir);\n        unset($exportData['members']);\n        file_put_contents($temp_dir . '/' . 'info.json', json_encode($exportData));\n\n        $this->_markdownTofile($exportData['pages'], $temp_dir);\n        $ret = $this->_zip($temp_dir, $temp_file);\n\n        clear_runtime($temp_dir);\n        rmdir($temp_dir);\n        header(\"Cache-Control: max-age=0\");\n        header(\"Content-Description: File Transfer\");\n        header('Content-disposition: attachment; filename=showdoc.zip'); // 文件名\n        header(\"Content-Type: application/zip\"); // zip格式的\n        header(\"Content-Transfer-Encoding: binary\"); // 告诉浏览器，这是二进制文件\n        header('Content-Length: ' . filesize($temp_file)); // 告诉浏览器，文件大小\n        // 记录项目变更日志：导出\n        D(\"ItemChangeLog\")->addLog($login_user['uid'], $item_id, 'export', 'item', $item_id, $item['item_name']);\n        @readfile($temp_file); //输出文件;\n        unlink($temp_file);\n    }\n\n    public function checkMarkdownLimit()\n    {\n        $login_user = $this->checkLogin();\n        $export_format =  I(\"export_format\");\n        $this->sendResult(array());\n    }\n\n    /**\n     * 将目录数据转换为markdown文件，保持目录结构\n     * @param array $catalogData 目录数据\n     * @param string $temp_dir 临时目录\n     * @param string $base_path 基础路径（用于递归创建子目录）\n     * @return array\n     */\n    private function _markdownTofile($catalogData, $temp_dir, $base_path = '')\n    {\n        // 处理当前目录下的页面\n        if (isset($catalogData['pages']) && !empty($catalogData['pages'])) {\n            foreach ($catalogData['pages'] as $key => $value) {\n                // 清理文件名中的非法字符\n                $filename = $this->_sanitizeFilename($value['page_title']) . '.md';\n                $file_path = $base_path ? $base_path . '/' . $filename : $filename;\n                $full_path = $temp_dir . '/' . $file_path;\n                \n                // 如果文件已存在，添加序号避免冲突\n                $counter = 1;\n                while (file_exists($full_path)) {\n                    $name_without_ext = $this->_sanitizeFilename($value['page_title']);\n                    $filename = $name_without_ext . '_' . $counter . '.md';\n                    $file_path = $base_path ? $base_path . '/' . $filename : $filename;\n                    $full_path = $temp_dir . '/' . $file_path;\n                    $counter++;\n                }\n                \n                // 确保目录存在\n                $dir = dirname($full_path);\n                if (!is_dir($dir)) {\n                    mkdir($dir, 0755, true);\n                }\n                \n                // 保存文件内容\n                file_put_contents($full_path, htmlspecialchars_decode($value['page_content']));\n            }\n        }\n\n        // 递归处理子目录\n        if (isset($catalogData['catalogs']) && !empty($catalogData['catalogs'])) {\n            foreach ($catalogData['catalogs'] as $key => $value) {\n                // 清理目录名中的非法字符\n                $cat_name = isset($value['cat_name']) ? $value['cat_name'] : '目录';\n                $dir_name = $this->_sanitizeFilename($cat_name);\n                $new_base_path = $base_path ? $base_path . '/' . $dir_name : $dir_name;\n                \n                // 如果目录名已存在，添加序号避免冲突\n                $dir_full_path = $temp_dir . '/' . $new_base_path;\n                $counter = 1;\n                while (is_dir($dir_full_path)) {\n                    $dir_name = $this->_sanitizeFilename($cat_name) . '_' . $counter;\n                    $new_base_path = $base_path ? $base_path . '/' . $dir_name : $dir_name;\n                    $dir_full_path = $temp_dir . '/' . $new_base_path;\n                    $counter++;\n                }\n                \n                // 递归处理子目录\n                $this->_markdownTofile($value, $temp_dir, $new_base_path);\n            }\n        }\n        \n        return $catalogData;\n    }\n\n    /**\n     * 清理文件名/目录名中的非法字符\n     * @param string $filename 原始文件名\n     * @return string 清理后的文件名\n     */\n    private function _sanitizeFilename($filename)\n    {\n        // Windows/Linux 文件名非法字符: < > : \" / \\ | ? *\n        // 同时去除前后空格和点号\n        $filename = trim($filename);\n        \n        // 替换非法字符为下划线\n        $filename = preg_replace('/[<>:\"\\/\\\\\\|\\?\\*\\x00-\\x1F]/', '_', $filename);\n        \n        // 去除连续的下划线和点号\n        $filename = preg_replace('/[_\\.]+/', '_', $filename);\n        \n        // 去除前后下划线和点号\n        $filename = trim($filename, '_.');\n        \n        // 如果文件名为空，使用默认名称\n        if (empty($filename)) {\n            $filename = '未命名';\n        }\n        \n        // Windows 保留文件名\n        $reserved_names = array('CON', 'PRN', 'AUX', 'NUL', 'COM1', 'COM2', 'COM3', 'COM4', 'COM5', 'COM6', 'COM7', 'COM8', 'COM9', 'LPT1', 'LPT2', 'LPT3', 'LPT4', 'LPT5', 'LPT6', 'LPT7', 'LPT8', 'LPT9');\n        if (in_array(strtoupper($filename), $reserved_names)) {\n            $filename = $filename . '_';\n        }\n        \n        // 限制文件名长度（Windows 限制为 255 字符）\n        if (mb_strlen($filename) > 200) {\n            $filename = mb_substr($filename, 0, 200);\n        }\n        \n        return $filename;\n    }\n\n    /**\n     * 使用ZIP压缩文件或目录，保持目录结构\n     * @param  [string] $temp_dir 被压缩的目录名\n     * @param  [string] $temp_file   压缩后的文件名\n     * @return [bool]             成功返回TRUE, 失败返回FALSE\n     */\n    private function _zip($temp_dir, $temp_file)\n    {\n        if (!file_exists($temp_dir) && !is_dir($temp_dir)) {\n            return FALSE;\n        }\n        $zipArc = new \\ZipArchive();\n        if (!$zipArc->open($temp_file, \\ZipArchive::CREATE)) {\n            return FALSE;\n        }\n        \n        if (is_dir($temp_dir)) {\n            // 递归添加目录及其内容，保持目录结构\n            $this->_addDirectoryToZip($temp_dir, $zipArc, '');\n        } else {\n            $zipArc->addFile($temp_dir, basename($temp_dir));\n        }\n        \n        return $zipArc->close();\n    }\n\n    /**\n     * 递归添加目录到ZIP文件，保持目录结构\n     * @param string $dir 目录路径\n     * @param \\ZipArchive $zipArc ZIP对象\n     * @param string $zipPath ZIP内的路径\n     */\n    private function _addDirectoryToZip($dir, $zipArc, $zipPath)\n    {\n        $files = scandir($dir);\n        foreach ($files as $file) {\n            if ($file == '.' || $file == '..') {\n                continue;\n            }\n            \n            $filePath = $dir . '/' . $file;\n            $zipFilePath = $zipPath ? $zipPath . '/' . $file : $file;\n            \n            if (is_dir($filePath)) {\n                // 递归处理子目录\n                $this->_addDirectoryToZip($filePath, $zipArc, $zipFilePath);\n            } else {\n                // 添加文件\n                $zipArc->addFile($filePath, $zipFilePath);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "server/Application/Api/Controller/ExportHtmlController.class.php",
    "content": "<?php\n\nnamespace Api\\Controller;\n\nuse Think\\Controller;\n\nclass ExportHtmlController extends BaseController\n{\n  /**\n   * 导出项目为离线HTML包\n   */\n  public function export()\n  {\n    set_time_limit(600);\n    ini_set('memory_limit', '2G');\n\n    $item_id = I(\"item_id/d\");\n    $login_user = $this->checkLogin();\n\n    if (!$this->checkItemEdit($login_user['uid'], $item_id)) {\n      $this->message(L('no_permissions'));\n      return;\n    }\n\n    // 获取项目信息\n    $item = D(\"Item\")->where(array('item_id' => $item_id))->find();\n    if (!$item) {\n      $this->sendError(10101, L('item_not_exists'));\n      return;\n    }\n\n    // 导出频率限制：同一用户当天最多 50 次（防刷）\n    $todayStart = date('y-m-d 00:00:00');\n    $timesToday = D(\"ExportLog\")\n      ->where(array('uid' => $login_user['uid'], 'export_type' => 'html'))\n      ->where(\"addtime >= '{$todayStart}'\")\n      ->count();\n    if ($timesToday >= 100) {\n      $message = \"为防止影响服务器负载，你当天导出次数已达上限(100次)。如有疑问请联系网站管理员\";\n      $this->sendError(10100, $message);\n      return false;\n    }\n\n    // 检查项目类型\n    $item_type = intval($item['item_type']);\n    if (!in_array($item_type, [1, 3, 5])) {\n      $this->sendError(10101, L('export_html_not_support_item_type'));\n      return;\n    }\n\n    // 成员目录权限：获取该用户在此项目下允许的目录集合\n    $allowedCatIds = D(\"Member\")->getCatIds($item_id, $login_user['uid']);\n\n    // 获取项目内容\n    $menu = D(\"Item\")->getContent($item_id, \"*\", \"*\", 1);\n\n    // 应用目录权限过滤\n    if (!empty($allowedCatIds)) {\n      $allowed = array_flip(array_map('intval', $allowedCatIds));\n      // 过滤根目录下的页面\n      if (!empty($menu['pages'])) {\n        $menu['pages'] = array();\n      }\n      // 过滤目录\n      if (!empty($menu['catalogs'])) {\n        $filteredCatalogs = array();\n        foreach ($menu['catalogs'] as $cat) {\n          if (isset($allowed[intval($cat['cat_id'])])) {\n            $filteredCatalogs[] = $cat;\n          }\n        }\n        $menu['catalogs'] = $filteredCatalogs;\n      }\n    }\n\n    // 创建临时目录\n    $temp_dir = sys_get_temp_dir() . \"/showdoc_html_\" . time() . \"_\" . rand(1000, 9999);\n    if (!mkdir($temp_dir, 0755, true)) {\n      $this->sendError(10101, L('create_temp_dir_failed'));\n      return;\n    }\n\n    try {\n      // 创建目录结构\n      mkdir($temp_dir . '/pages', 0755, true);\n      mkdir($temp_dir . '/assets/css', 0755, true);\n      mkdir($temp_dir . '/assets/js', 0755, true);\n      mkdir($temp_dir . '/assets/uploads', 0755, true);\n\n      // 收集所有页面\n      $all_pages = $this->_collectAllPages($menu);\n\n      if (empty($all_pages)) {\n        $this->sendError(10101, L('no_pages_to_export'));\n        return;\n      }\n\n      // 生成页面HTML\n      $this->_generatePagesHtml($all_pages, $item, $temp_dir);\n\n      // 生成首页\n      $this->_generateIndexHtml($item, $temp_dir);\n\n      // 生成数据文件\n      $this->_generateDataJs($menu, $item, $all_pages, $temp_dir);\n\n      // 验证：确保生成的文件名和data.js中的page_id一致\n      $this->_validatePageIds($all_pages, $temp_dir);\n\n      // 生成搜索索引\n      $this->_generateSearchIndex($all_pages, $temp_dir);\n\n      // 复制静态资源\n      $this->_copyStaticFiles($temp_dir);\n\n      // 复制图片和附件\n      $this->_copyAssets($all_pages, $temp_dir);\n\n      // 生成README\n      $this->_generateReadme($item, $temp_dir);\n\n      // 打包ZIP\n      $zip_file = sys_get_temp_dir() . \"/showdoc_html_\" . $item_id . \"_\" . time() . \".zip\";\n      if (!$this->_zip($temp_dir, $zip_file)) {\n        $this->sendError(10101, L('zip_failed'));\n        return;\n      }\n\n      // 写导出记录（开源版已新增export_log表）\n      D(\"ExportLog\")->add(array(\n        \"uid\" => $login_user['uid'],\n        \"export_type\" => 'html',\n        \"item_id\" => $item_id,\n        \"addtime\" => date(\"y-m-d H:i:s\")\n      ));\n\n      // 记录项目变更日志\n      D(\"ItemChangeLog\")->addLog($login_user['uid'], $item_id, 'export', 'item', $item_id, $item['item_name']);\n\n      // 输出文件\n      $filename = 'showdoc_offline_' . $this->_sanitizeFilename($item['item_name']) . '_' . date('YmdHis') . '.zip';\n      \n      // 处理中文文件名编码\n      $encoded_filename = rawurlencode($filename);\n      $user_agent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '';\n      \n      header(\"Cache-Control: max-age=0\");\n      header(\"Content-Description: File Transfer\");\n      \n      // 根据浏览器类型设置文件名编码\n      if (preg_match('/MSIE|Trident/i', $user_agent)) {\n        // IE浏览器使用GBK编码\n        $filename_gbk = mb_convert_encoding($filename, 'GBK', 'UTF-8');\n        header('Content-disposition: attachment; filename=\"' . $filename_gbk . '\"');\n      } else {\n        // 现代浏览器使用RFC 5987编码\n        header('Content-disposition: attachment; filename=\"' . $filename . '\"; filename*=UTF-8\\'\\'' . $encoded_filename);\n      }\n      \n      header(\"Content-Type: application/zip\");\n      header(\"Content-Transfer-Encoding: binary\");\n      header('Content-Length: ' . filesize($zip_file));\n      @readfile($zip_file);\n      unlink($zip_file);\n    } catch (\\Exception $e) {\n      error_log(\"Export HTML Error: \" . $e->getMessage());\n      $this->sendError(10101, L('export_failed') . ': ' . $e->getMessage());\n    } finally {\n      // 清理临时文件\n      $this->_clearTempDir($temp_dir);\n    }\n  }\n\n  /**\n   * 收集所有页面（扁平化）\n   */\n  private function _collectAllPages($menu)\n  {\n    $pages = array();\n\n    // 根目录下的页面\n    if (!empty($menu['pages'])) {\n      foreach ($menu['pages'] as $page) {\n        $pages[] = $page;\n      }\n    }\n\n    // 递归收集目录下的页面\n    if (!empty($menu['catalogs'])) {\n      $this->_collectPagesFromCatalogs($menu['catalogs'], $pages);\n    }\n\n    return $pages;\n  }\n\n  /**\n   * 从目录中递归收集页面\n   */\n  private function _collectPagesFromCatalogs($catalogs, &$pages)\n  {\n    foreach ($catalogs as $cat) {\n      if (!empty($cat['pages'])) {\n        foreach ($cat['pages'] as $page) {\n          $pages[] = $page;\n        }\n      }\n      if (!empty($cat['catalogs'])) {\n        $this->_collectPagesFromCatalogs($cat['catalogs'], $pages);\n      }\n    }\n  }\n\n  /**\n   * 生成所有页面的HTML\n   */\n  private function _generatePagesHtml($pages, $item, $temp_dir)\n  {\n    import(\"Vendor.Parsedown.Parsedown\");\n    $Parsedown = new \\Parsedown();\n    $convert = new \\Api\\Helper\\Convert();\n\n    foreach ($pages as $page) {\n      // 确保 page_id 存在且有效\n      if (empty($page['page_id'])) {\n        continue;\n      }\n      // 统一获取page_id，确保后续使用一致\n      $page_id = intval($page['page_id']);\n      if ($page_id <= 0) {\n        continue;\n      }\n      // 将page_id传递给生成方法，避免重复获取导致不一致\n      $html = $this->_generatePageHtml($page, $item, $Parsedown, $convert, $page_id);\n      $file_path = $temp_dir . '/pages/page-' . $page_id . '.html';\n      file_put_contents($file_path, $html);\n    }\n  }\n\n  /**\n   * 生成单个页面HTML\n   */\n  private function _generatePageHtml($page, $item, $Parsedown, $convert, $page_id = null)\n  {\n    // 如果传入了page_id，使用传入的值；否则从page数组中获取\n    // 这样可以确保文件名和HTML中的CURRENT_PAGE_ID完全一致\n    if ($page_id === null) {\n      $page_id = intval($page['page_id']);\n    }\n    if ($page_id <= 0) {\n      $page_id = 0;\n    }\n    $page_title = htmlspecialchars($page['page_title'], ENT_QUOTES, 'UTF-8');\n    $item_name = htmlspecialchars($item['item_name'], ENT_QUOTES, 'UTF-8');\n\n    // 处理内容\n    $page_content = $page['page_content'];\n\n    // RunAPI项目转换\n    if ($item['item_type'] == '3') {\n      $md_content = $convert->runapiToMd($page_content);\n      if ($md_content) {\n        $page_content = $md_content;\n      }\n    }\n\n    // Markdown转HTML\n    $html_content = $Parsedown->text($page_content);\n\n    // 转义还原（数据库内容经过了html转义，需还原以正确显示）\n    $html_content = htmlspecialchars_decode($html_content);\n\n    // HTML安全过滤\n    $html_content = $this->_sanitizeHtml($html_content);\n\n    // 图片路径重写\n    $html_content = $this->_rewriteImagePaths($html_content);\n\n    // 生成HTML\n    $html = '<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>' . $page_title . ' - ' . $item_name . '</title>\n    <link rel=\"stylesheet\" href=\"../assets/css/common.css\">\n    <link rel=\"stylesheet\" href=\"../assets/css/highlight.css\">\n</head>\n<body>\n    <div class=\"header\">\n        <div class=\"header-content\">\n            <h1 class=\"project-name\">' . $item_name . '</h1>\n            <div class=\"search-box\">\n                <input type=\"text\" id=\"searchInput\" placeholder=\"搜索页面...\">\n                <div id=\"searchResults\" class=\"search-results\"></div>\n            </div>\n            <button class=\"menu-toggle\" id=\"menuToggle\">☰</button>\n        </div>\n    </div>\n    <div class=\"container\">\n        <aside class=\"sidebar\" id=\"sidebar\">\n            <div id=\"catalogTree\" class=\"catalog-tree\"></div>\n        </aside>\n        <main class=\"main-content\">\n            <article class=\"page-content\">\n                <h1 class=\"page-title\">' . $page_title . '</h1>\n                <div class=\"markdown-body\">' . $html_content . '</div>\n                <div class=\"page-nav\" id=\"pageNav\"></div>\n            </article>\n        </main>\n    </div>\n    <script src=\"../assets/js/data.js\"></script>\n    <script src=\"../assets/js/search-index.js\"></script>\n    <script src=\"../assets/js/app.js\"></script>\n    <script src=\"../assets/js/highlight.min.js\"></script>\n    <script>\n        if (typeof hljs !== \"undefined\") {\n            hljs.highlightAll();\n        }\n        // 设置当前页面ID（使用字符串形式，避免大整数精度丢失）\n        window.CURRENT_PAGE_ID = \\'' . $page_id . '\\';\n    </script>\n</body>\n</html>';\n\n    return $html;\n  }\n\n  /**\n   * 生成首页HTML\n   */\n  private function _generateIndexHtml($item, $temp_dir)\n  {\n    $item_name = htmlspecialchars($item['item_name'], ENT_QUOTES, 'UTF-8');\n    $item_description = htmlspecialchars($item['item_description'] ?? '', ENT_QUOTES, 'UTF-8');\n\n    $html = '<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>' . $item_name . ' - 项目概览</title>\n    <link rel=\"stylesheet\" href=\"assets/css/common.css\">\n    <link rel=\"stylesheet\" href=\"assets/css/highlight.css\">\n</head>\n<body>\n    <div class=\"header\">\n        <div class=\"header-content\">\n            <h1 class=\"project-name\">' . $item_name . '</h1>\n            <div class=\"search-box\">\n                <input type=\"text\" id=\"searchInput\" placeholder=\"搜索页面...\">\n                <div id=\"searchResults\" class=\"search-results\"></div>\n            </div>\n            <button class=\"menu-toggle\" id=\"menuToggle\">☰</button>\n        </div>\n    </div>\n    <div class=\"container\">\n        <aside class=\"sidebar\" id=\"sidebar\">\n            <div id=\"catalogTree\" class=\"catalog-tree\"></div>\n        </aside>\n        <main class=\"main-content\">\n            <article class=\"page-content\">\n                <h1 class=\"page-title\">' . $item_name . '</h1>\n                ' . ($item_description ? '<p class=\"project-description\">' . $item_description . '</p>' : '') . '\n                <div class=\"project-overview\">\n                    <p>这是一个离线HTML文档包，您可以在浏览器中离线浏览所有文档。</p>\n                    <p>使用左侧目录树导航，或使用顶部搜索框快速查找内容。</p>\n                </div>\n            </article>\n        </main>\n    </div>\n    <script src=\"assets/js/data.js\"></script>\n    <script src=\"assets/js/search-index.js\"></script>\n    <script src=\"assets/js/app.js\"></script>\n    <script>\n        window.CURRENT_PAGE_ID = \\'0\\';\n    </script>\n</body>\n</html>';\n\n    file_put_contents($temp_dir . '/index.html', $html);\n  }\n\n  /**\n   * 生成data.js文件\n   */\n  private function _generateDataJs($menu, $item, $all_pages, $temp_dir)\n  {\n    // 收集所有目录（扁平化）\n    $all_catalogs = $this->_collectAllCatalogs($menu);\n\n    // 构建页面列表\n    $pages_list = array();\n    foreach ($all_pages as $page) {\n      // 确保 page_id 存在且有效\n      if (empty($page['page_id'])) {\n        continue;\n      }\n      $page_id = intval($page['page_id']);\n      if ($page_id <= 0) {\n        continue;\n      }\n      // page_id 使用字符串形式，避免JavaScript大整数精度丢失\n      $pages_list[] = array(\n        'page_id' => (string)$page_id,\n        'page_title' => $page['page_title'],\n        'cat_id' => intval($page['cat_id'] ?? 0),\n        's_number' => intval($page['s_number'] ?? 0),\n        'file_path' => 'pages/page-' . $page_id . '.html'\n      );\n    }\n\n    // 构建目录列表\n    $catalogs_list = array();\n    foreach ($all_catalogs as $cat) {\n      $catalogs_list[] = array(\n        'cat_id' => intval($cat['cat_id']),\n        'cat_name' => $cat['cat_name'],\n        'parent_cat_id' => intval($cat['parent_cat_id'] ?? 0),\n        'level' => intval($cat['level'] ?? 2),\n        's_number' => intval($cat['s_number'] ?? 0)\n      );\n    }\n\n    $data = array(\n      'item_id' => intval($item['item_id']),\n      'item_name' => $item['item_name'],\n      'item_type' => $item['item_type'],\n      'item_description' => $item['item_description'] ?? '',\n      'catalogs' => $catalogs_list,\n      'pages' => $pages_list\n    );\n\n    $js_content = 'window.PROJECT_DATA = ' . json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . ';';\n    file_put_contents($temp_dir . '/assets/js/data.js', $js_content);\n  }\n\n  /**\n   * 收集所有目录（扁平化）\n   */\n  private function _collectAllCatalogs($menu)\n  {\n    $catalogs = array();\n\n    if (!empty($menu['catalogs'])) {\n      $this->_collectCatalogsRecursive($menu['catalogs'], $catalogs);\n    }\n\n    return $catalogs;\n  }\n\n  /**\n   * 递归收集目录\n   */\n  private function _collectCatalogsRecursive($catalogs_list, &$result)\n  {\n    foreach ($catalogs_list as $cat) {\n      $result[] = array(\n        'cat_id' => $cat['cat_id'],\n        'cat_name' => $cat['cat_name'],\n        'parent_cat_id' => $cat['parent_cat_id'] ?? 0,\n        'level' => $cat['level'] ?? 2,\n        's_number' => $cat['s_number'] ?? 0\n      );\n      if (!empty($cat['catalogs'])) {\n        $this->_collectCatalogsRecursive($cat['catalogs'], $result);\n      }\n    }\n  }\n\n  /**\n   * 生成搜索索引\n   */\n  private function _generateSearchIndex($pages, $temp_dir)\n  {\n    $index = array();\n\n    foreach ($pages as $page) {\n      // 确保 page_id 存在且有效\n      if (empty($page['page_id'])) {\n        continue;\n      }\n      $page_id = intval($page['page_id']);\n      if ($page_id <= 0) {\n        continue;\n      }\n      // 先还原转义再提取文本\n      $decoded = htmlspecialchars_decode($page['page_content']);\n      $content = strip_tags($decoded);\n      $content_preview = mb_substr($content, 0, 200);\n\n      // page_id 使用字符串形式，避免JavaScript大整数精度丢失\n      $index[] = array(\n        'page_id' => (string)$page_id,\n        'page_title' => $page['page_title'],\n        'content_preview' => $content_preview,\n        'cat_id' => intval($page['cat_id'] ?? 0)\n      );\n    }\n\n    $js_content = 'window.SEARCH_INDEX = ' . json_encode($index, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . ';';\n    file_put_contents($temp_dir . '/assets/js/search-index.js', $js_content);\n  }\n\n  /**\n   * 复制静态文件（CSS/JS）\n   */\n  private function _copyStaticFiles($temp_dir)\n  {\n    $base_path = dirname(dirname(dirname(dirname(__DIR__))));\n\n    // 复制highlight.js\n    $highlight_js = $base_path . '/Public/highlight/highlight.min.js';\n    if (file_exists($highlight_js)) {\n      copy($highlight_js, $temp_dir . '/assets/js/highlight.min.js');\n    }\n\n    // 复制highlight.css\n    $highlight_css = $base_path . '/Public/highlight/default.min.css';\n    if (file_exists($highlight_css)) {\n      copy($highlight_css, $temp_dir . '/assets/css/highlight.css');\n    }\n\n    // 生成common.css和app.js\n    $this->_generateCommonCss($temp_dir);\n    $this->_generateAppJs($temp_dir);\n  }\n\n  /**\n   * 生成common.css\n   */\n  private function _generateCommonCss($temp_dir)\n  {\n    $base_path = dirname(dirname(dirname(dirname(__DIR__))));\n    $css_file = $base_path . '/server/Application/Static/export-html/common.css';\n    if (file_exists($css_file)) {\n      $css = file_get_contents($css_file);\n      file_put_contents($temp_dir . '/assets/css/common.css', $css);\n    }\n  }\n\n  /**\n   * 生成app.js\n   */\n  private function _generateAppJs($temp_dir)\n  {\n    $base_path = dirname(dirname(dirname(dirname(__DIR__))));\n    $js_file = $base_path . '/server/Application/Static/export-html/app.js';\n    if (file_exists($js_file)) {\n      $js = file_get_contents($js_file);\n      file_put_contents($temp_dir . '/assets/js/app.js', $js);\n    }\n  }\n\n  /**\n   * 复制图片和附件\n   */\n  private function _copyAssets($pages, $temp_dir)\n  {\n    $base_path = dirname(dirname(dirname(dirname(__DIR__))));\n    $uploads_dir = $base_path . '/Public/Uploads';\n    $target_dir = $temp_dir . '/assets/uploads';\n\n    if (!is_dir($uploads_dir)) {\n      return;\n    }\n\n    // 从页面内容中提取图片路径\n    $image_paths = array();\n    foreach ($pages as $page) {\n      $content = $page['page_content'];\n      // 匹配 /Public/Uploads/xxx 格式的路径\n      preg_match_all('/\\/Public\\/Uploads\\/([^\\s\"\\'\\)]+)/', $content, $matches);\n      if (!empty($matches[1])) {\n        foreach ($matches[1] as $img_path) {\n          $image_paths[$img_path] = true;\n        }\n      }\n    }\n\n    // 复制图片文件\n    foreach (array_keys($image_paths) as $img_path) {\n      $source = $uploads_dir . '/' . $img_path;\n      if (file_exists($source) && is_file($source)) {\n        $target = $target_dir . '/' . basename($img_path);\n        // 确保目录存在\n        $target_dir_path = dirname($target);\n        if (!is_dir($target_dir_path)) {\n          mkdir($target_dir_path, 0755, true);\n        }\n        copy($source, $target);\n      }\n    }\n  }\n\n  /**\n   * 生成README文件\n   */\n  private function _generateReadme($item, $temp_dir)\n  {\n    $item_name = htmlspecialchars($item['item_name'], ENT_QUOTES, 'UTF-8');\n    $readme = \"ShowDoc 离线HTML文档包\n====================\n\n项目名称: {$item_name}\n导出时间: \" . date('Y-m-d H:i:s') . \"\n\n使用说明:\n---------\n1. 解压此压缩包到任意目录\n2. 用浏览器打开 index.html 文件\n3. 使用左侧目录树导航，或使用顶部搜索框查找内容\n4. 所有资源已包含在压缩包中，可完全离线使用\n\n注意事项:\n---------\n- 此文档包为只读版本，无法编辑\n- 建议使用现代浏览器（Chrome、Firefox、Edge、Safari）\n- 如需更新文档，请重新导出\n\n\";\n    file_put_contents($temp_dir . '/README.txt', $readme);\n  }\n\n  /**\n   * HTML安全过滤\n   */\n  private function _sanitizeHtml($html)\n  {\n    // 移除script标签\n    $html = preg_replace('/<script\\b[^<]*(?:(?!<\\/script>)<[^<]*)*<\\/script>/mi', '', $html);\n\n    // 移除事件处理器\n    $html = preg_replace('/\\s*on\\w+\\s*=\\s*[\"\\'][^\"\\']*[\"\\']/i', '', $html);\n    $html = preg_replace('/\\s*on\\w+\\s*=\\s*[^\\s>]+/i', '', $html);\n\n    // 过滤危险协议\n    $html = preg_replace('/href\\s*=\\s*[\"\\'](javascript|data):/i', 'href=\"#\"', $html);\n    $html = preg_replace('/src\\s*=\\s*[\"\\'](javascript|data):/i', 'src=\"#\"', $html);\n\n    return $html;\n  }\n\n  /**\n   * 重写图片路径\n   */\n  private function _rewriteImagePaths($html)\n  {\n    // 处理图片路径：/Public/Uploads/xxx 转换为相对路径\n    $html = preg_replace_callback(\n      '/src\\s*=\\s*[\"\\']([^\"\\']*\\/Public\\/Uploads\\/[^\"\\']+)[\"\\']/i',\n      function ($matches) {\n        $path = $matches[1];\n        $filename = basename($path);\n        return 'src=\"../assets/uploads/' . $filename . '\"';\n      },\n      $html\n    );\n\n    return $html;\n  }\n\n  /**\n   * 清理文件名\n   */\n  private function _sanitizeFilename($filename)\n  {\n    $filename = trim($filename);\n    $filename = preg_replace('/[<>:\"\\/\\\\\\|\\?\\*\\x00-\\x1F]/', '_', $filename);\n    $filename = preg_replace('/[_\\.]+/', '_', $filename);\n    $filename = trim($filename, '_.');\n    if (empty($filename)) {\n      $filename = 'unnamed';\n    }\n    if (mb_strlen($filename) > 200) {\n      $filename = mb_substr($filename, 0, 200);\n    }\n    return $filename;\n  }\n\n  /**\n   * 打包ZIP\n   */\n  private function _zip($fromName, $toName)\n  {\n    if (!file_exists($fromName) || !is_dir($fromName)) {\n      return false;\n    }\n\n    $zipArc = new \\ZipArchive();\n    if (!$zipArc->open($toName, \\ZipArchive::CREATE)) {\n      return false;\n    }\n\n    $this->_addDirectoryToZip($fromName, $zipArc, '');\n    return $zipArc->close();\n  }\n\n  /**\n   * 递归添加目录到ZIP\n   */\n  private function _addDirectoryToZip($dir, $zipArc, $zipPath)\n  {\n    $files = scandir($dir);\n    foreach ($files as $file) {\n      if ($file == '.' || $file == '..') {\n        continue;\n      }\n\n      $filePath = $dir . '/' . $file;\n      $zipFilePath = $zipPath ? $zipPath . '/' . $file : $file;\n\n      if (is_dir($filePath)) {\n        $this->_addDirectoryToZip($filePath, $zipArc, $zipFilePath);\n      } else {\n        $zipArc->addFile($filePath, $zipFilePath);\n      }\n    }\n  }\n\n  /**\n   * 清理临时目录\n   */\n  private function _clearTempDir($dir)\n  {\n    if (!is_dir($dir)) {\n      return;\n    }\n\n    $files = array_diff(scandir($dir), array('.', '..'));\n    foreach ($files as $file) {\n      $path = $dir . '/' . $file;\n      if (is_dir($path)) {\n        $this->_clearTempDir($path);\n      } else {\n        unlink($path);\n      }\n    }\n    rmdir($dir);\n  }\n\n  /**\n   * 验证页面ID一致性\n   * 确保生成的文件名和data.js中的page_id完全一致\n   */\n  private function _validatePageIds($all_pages, $temp_dir)\n  {\n    // 读取生成的data.js文件\n    $data_js_file = $temp_dir . '/assets/js/data.js';\n    if (!file_exists($data_js_file)) {\n      error_log(\"Export HTML: data.js file not found for validation\");\n      return;\n    }\n\n    $data_js_content = file_get_contents($data_js_file);\n    // 提取PROJECT_DATA中的pages数组\n    if (preg_match('/window\\.PROJECT_DATA\\s*=\\s*({.*?});/s', $data_js_content, $matches)) {\n      $data_json = $matches[1];\n      $data = json_decode($data_json, true);\n      \n      if ($data && isset($data['pages'])) {\n        $data_pages = $data['pages'];\n        $data_page_ids = array();\n        foreach ($data_pages as $dp) {\n          $data_page_ids[] = (string)$dp['page_id'];\n        }\n\n        // 检查实际生成的文件\n        $pages_dir = $temp_dir . '/pages';\n        if (is_dir($pages_dir)) {\n          $files = scandir($pages_dir);\n          $file_page_ids = array();\n          foreach ($files as $file) {\n            if (preg_match('/^page-(\\d+)\\.html$/', $file, $matches)) {\n              $file_page_ids[] = $matches[1];\n            }\n          }\n\n          // 验证：data.js中的page_id应该和实际文件一致\n          $missing_in_data = array_diff($file_page_ids, $data_page_ids);\n          $missing_in_files = array_diff($data_page_ids, $file_page_ids);\n\n          if (!empty($missing_in_data)) {\n            error_log(\"Export HTML Validation: Files exist but not in data.js: \" . implode(', ', $missing_in_data));\n          }\n          if (!empty($missing_in_files)) {\n            error_log(\"Export HTML Validation: page_id in data.js but file missing: \" . implode(', ', $missing_in_files));\n          }\n\n          // 验证原始数据中的page_id\n          $original_page_ids = array();\n          foreach ($all_pages as $page) {\n            if (!empty($page['page_id'])) {\n              $pid = intval($page['page_id']);\n              if ($pid > 0) {\n                $original_page_ids[] = (string)$pid;\n              }\n            }\n          }\n\n          // 检查是否有page_id不一致\n          $missing_in_original = array_diff($data_page_ids, $original_page_ids);\n          if (!empty($missing_in_original)) {\n            error_log(\"Export HTML Validation: page_id in data.js but not in original data: \" . implode(', ', $missing_in_original));\n          }\n        }\n      }\n    }\n  }\n}\n\n"
  },
  {
    "path": "server/Application/Api/Controller/ExtLoginController.class.php",
    "content": "<?php\n\nnamespace Api\\Controller;\n\nuse Think\\Controller;\n\nclass ExtLoginController extends BaseController\n{\n\n\n    // 根据用户名和LoginSecretKey登录\n    public function bySecretKey()\n    {\n        $username = I(\"username\");\n        $key = I(\"key\");\n        $time = I(\"time\");\n        $token = I(\"token\");\n        $redirect = I(\"redirect\");\n        $name = I(\"name\");\n\n        if ($time < (time() - 60)) {\n            $this->sendError(10101, \"已过期\");\n            return;\n        }\n        $login_secret_key = D(\"Options\")->get(\"login_secret_key\");\n        if (!$login_secret_key) return false;\n        $new_token = md5($username . $login_secret_key . $time);\n        if (!($token === $new_token)) {\n            $this->sendError(10101, \"token不正确\");\n            return;\n        }\n\n        $res = D(\"User\")->where(\"( username='%s' ) \", array($username))->find();\n        if (!$res) {\n            $new_uid = D(\"User\")->register($username, md5(\"savsnyjh\" . time() . rand()));\n            $res = D(\"User\")->where(\"( username='%s' ) \", array($username))->find();\n            if ($name) {\n                D(\"User\")->where(\" uid = '%d' \", array($new_uid))->save(array(\"name\" => $name));\n            }\n\n        }\n        if ($res) {\n            // var_dump($res); return ;\n            if ($res['groupid'] == 1) {\n                $this->sendError(10101, \"为了安全，禁止管理员通过这种方式登录\");\n                return;\n            }\n            $uid = $res['uid'];\n            if ($name) {\n\n                D(\"User\")->where(\" uid = '%d' \", array($uid))->save(array(\"name\" => $name));\n            }\n            D(\"User\")->setLastTime($uid);\n\n            unset($res['password']);\n            session(\"login_user\", $res);\n            $token = D(\"UserToken\")->createToken($uid, 60 * 60 * 24 * 180);\n            cookie('cookie_token', $token, array('expire' => 60 * 60 * 24 * 180, 'httponly' => 'httponly')); //此处由服务端控制token是否过期，所以cookies过期时间设置多久都无所谓\n            if ($redirect) {\n                $redirect = urldecode($redirect);\n                header(\"location:{$redirect}\");\n            } else {\n                header(\"location:../web/#/item/index\");\n            }\n        }\n    }\n\n    private function getUserNameFromOAuth2($array)\n    {\n        $keysToCheck = [\"preferred_username\", \"name\", \"username\", \"login\"];\n\n        foreach ($array as $key => $value) {\n            if (!is_array($value) && in_array($key, $keysToCheck, true)) {\n                // 找到匹配的键，且有值 ，直接返回值\n                if($value){\n                    return $value;\n                }\n            }\n        }\n\n        foreach ($array as $value) {\n            if (is_array($value)) {\n                $username = $this->getUserNameFromOAuth2($value); // 递归检查子数组\n                if ($username) {\n                    return $username; // 如果找到，返回结果\n                }\n            }\n        }\n\n        return false; // 如果没有找到，返回 false\n    }\n\n\n    public function oauth2()\n    {\n        $this->checkComposerPHPVersion();\n        $redirect = I(\"redirect\");\n        session('redirect', $redirect);\n        $oauth2_open = D(\"Options\")->get(\"oauth2_open\");\n        $oauth2_form = D(\"Options\")->get(\"oauth2_form\");\n        $oauth2_form = htmlspecialchars_decode($oauth2_form);\n        $oauth2_form = json_decode($oauth2_form, 1);\n\n        if (!$oauth2_open) {\n            echo \"尚未启用oauth2\";\n            return;\n        }\n\n\n        $clientId = $oauth2_form['client_id'];\n        $clientSecret = $oauth2_form['client_secret'];\n        $redirectUri = $oauth2_form['redirectUri'];\n        $urlAuthorize = $oauth2_form['protocol'] . \"://\" . $oauth2_form['host'] . $oauth2_form['authorize_path'];\n        $urlAccessToken = $oauth2_form['protocol'] . \"://\" . $oauth2_form['host'] . $oauth2_form['token_path'];\n        $urlResourceOwnerDetails = $oauth2_form['protocol'] . \"://\" . $oauth2_form['host'] . $oauth2_form['resource_path'];\n        if (strstr($oauth2_form['userinfo_path'], \"://\")) {\n            $urlUserInfo = $oauth2_form['userinfo_path'];\n        } else {\n            $urlUserInfo = $oauth2_form['protocol'] . \"://\" . $oauth2_form['host'] . $oauth2_form['userinfo_path'];\n        }\n\n\n        $provider = new \\League\\OAuth2\\Client\\Provider\\GenericProvider([\n            'clientId' => $clientId,    // The client ID assigned to you by the provider\n            'clientSecret' => $clientSecret,    // The client password assigned to you by the provider\n            'redirectUri' => $redirectUri,\n            'urlAuthorize' => $urlAuthorize,\n            'urlAccessToken' => $urlAccessToken,\n            'urlResourceOwnerDetails' => $urlResourceOwnerDetails,\n        ], [\n            'httpClient' => new \\GuzzleHttp\\Client(['verify' => false]),\n        ]);\n\n        // If we don't have an authorization code then get one\n        if (!isset($_GET['code'])) {\n\n            // Fetch the authorization URL from the provider; this returns the\n            // urlAuthorize option and generates and applies any necessary parameters\n            // (e.g. state).\n            $authorizationUrl = $provider->getAuthorizationUrl();\n\n            // Get the state generated for you and store it to the session.\n            $_SESSION['oauth2state'] = $provider->getState();\n\n            // Redirect the user to the authorization URL.\n            header('Location: ' . $authorizationUrl);\n            exit;\n\n            // Check given state against previously stored one to mitigate CSRF attack\n        } elseif (empty($_GET['state']) || (isset($_SESSION['oauth2state']) && $_GET['state'] !== $_SESSION['oauth2state'])) {\n\n            if (isset($_SESSION['oauth2state'])) {\n                unset($_SESSION['oauth2state']);\n            }\n\n            exit('Invalid state');\n        } else {\n\n            try {\n\n                // Try to get an access token using the authorization code grant.\n                $accessToken = $provider->getAccessToken('authorization_code', [\n                    'code' => $_GET['code']\n                ]);\n\n                // We have an access token, which we may use in authenticated\n                // requests against the service provider's API.\n                //echo 'Access Token: ' . $accessToken->getToken() . \"<br>\";\n                //echo 'Refresh Token: ' . $accessToken->getRefreshToken() . \"<br>\";\n                //echo 'Expired in: ' . $accessToken->getExpires() . \"<br>\";\n                // echo 'Already expired? ' . ($accessToken->hasExpired() ? 'expired' : 'not expired') . \"<br>\";\n\n                $access_token_string = $accessToken->getToken();\n\n                // 兼容 GitLab：GitLab 不允许同时通过 URL 参数和 Header 传递 token\n                // 参考：https://github.com/star7th/showdoc/issues/2102\n                $is_gitlab = false;\n                if (\n                    (isset($oauth2_form['host']) && stripos($oauth2_form['host'], 'gitlab') !== false)\n                    || stripos($urlUserInfo, 'gitlab') !== false\n                    || stripos($urlAccessToken, 'gitlab') !== false\n                ) {\n                    $is_gitlab = true;\n                }\n\n                if ($is_gitlab) {\n                    // GitLab 场景：只在 Header 中携带 Authorization: Bearer，不再拼接 ?access_token\n                    $user_info_url = $urlUserInfo;\n                    $curl_headers = array(\n                        \"Authorization: Bearer {$access_token_string}\",\n                        \"user-agent: showdoc\",\n                        \"accept:application/json\"\n                    );\n                } else {\n                    // 其他平台：保持兼容性，沿用原有“URL + Header”两种方式\n                    $user_info_url = $urlUserInfo . \"?access_token=\" . $access_token_string;\n                    $curl_headers = array(\n                        \"Authorization: bearer {$access_token_string}\",\n                        \"user-agent: showdoc\",\n                        \"accept:application/json\"\n                    );\n                }\n\n                $oCurl = curl_init();   //初始化curl，\n                curl_setopt($oCurl, CURLOPT_URL, $user_info_url);   //设置网址\n                curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, 1);  //将curl_exec的结果返回\n                curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, FALSE);\n                curl_setopt($oCurl, CURLOPT_SSL_VERIFYHOST, FALSE);\n                curl_setopt($oCurl, CURLOPT_HEADER, 0);         //是否输出返回头信息\n                curl_setopt($oCurl, CURLOPT_HTTPHEADER, $curl_headers);\n                $res = curl_exec($oCurl);   //执行\n                curl_close($oCurl);          //关闭会话\n                $res_array = json_decode($res, true);\n                if ($res_array) {\n                    $username = $this->getUserNameFromOAuth2($res_array);\n                    if (!$username) {\n                        echo \"返回信息中无法获取用户名。返回的内容如下：\" . $res;\n                        return;\n                    }\n                    $info = D(\"User\")->where(\"username='%s'\", array($username))->find();\n                    if (!$info) {\n                        D(\"User\")->register($username, md5($username . time() . rand()));\n                        $info = D(\"User\")->where(\"username='%s'\", array($username))->find();\n                        if ($res_array['name']) {\n                            D(\"User\")->where(\"username='%s'\", array($username))->save(array(\"name\" => $res_array['name']));\n                        }\n\n                    }\n\n                    D(\"User\")->setLastTime($info['uid']);\n                    unset($info['password']);\n                    session(\"login_user\", $info);\n                    $token = D(\"UserToken\")->createToken($info['uid'], 60 * 60 * 24 * 180);\n                    cookie('cookie_token', $token, array('expire' => 60 * 60 * 24 * 180, 'httponly' => 'httponly')); //此处由服务端控制token是否过期，所以cookies过期时间设置多久都无所谓\n                    if (session('redirect')) {\n                        $redirect = urldecode(session('redirect'));\n                        header(\"location:{$redirect}\");\n                        session('redirect', null);\n                    } else {\n                        header(\"location:../web/#/item/index\");\n                    }\n                } else {\n                    echo \"登录成功但无法获取用户信息。返回内容如下：\" . $res;\n                }\n            } catch (\\League\\OAuth2\\Client\\Provider\\Exception\\IdentityProviderException $e) {\n\n                // Failed to get the access token or user details.\n                exit($e->getMessage());\n            }\n        }\n    }\n\n\n    public function cas()\n    {\n        $this->checkComposerPHPVersion();\n        define(\"CAS_VERSION_1_0\", '1.0');\n        define(\"CAS_VERSION_2_0\", '2.0');\n        define(\"CAS_VERSION_3_0\", '3.0');\n\n        # 2 开启phpCAS debug\n        \\phpCAS::setDebug();\n\n        # 3 初始化phpCAS,参数说明：\n        # a) CAS协议版本号\n        # b) cas server的域名\n        # c) cas server的端口号\n        # d) cas server的项目访问路径\n        \\phpCAS::client(CAS_VERSION_2_0, '192.168.8.160', 8443, '/maxkey/authz/cas/');\n\n        # 4 开启设置证书验证。如果是开发环境可将此注释，如果是生产环境为了安全性建议将此开启\n        // phpCAS::setCasServerCACert($cas_server_ca_cert_path);\n\n        # 5 不为CAS服务器设置SSL验证\n        # 为了快速测试，您可以禁用CAS服务器的SSL验证。此建议不建议用于生产环境。验证CAS服务器对CAS协议的安全性至关重要！\n        \\phpCAS::setNoCasServerValidation();\n\n        # 6 这里会检测服务器端的退出的通知，就能实现php和其他语言平台间同步登出了\n        # 处理登出请求。cas服务端会发送请求通知客户端。如果没有同步登出，可能是服务端跟客户端无法通信（比如我的客户端是localhost, 服务端在云上）\n        \\phpCAS::handleLogoutRequests();\n\n        # 7 进行CAS服务验证，这个方法确保用户是否验证过，如果没有验证则跳转到验证界面\n        # 这个是强制认证模式，查看 CAS.php 可以找到几种不同的方式：\n        # a) forceAuthentication - phpCAS::forceAuthentication();\n        # b) checkAuthentication - phpCAS::checkAuthentication();\n        # c) renewAuthentication - phpCAS::renewAuthentication();\n        # 根据自己需要调用即可。\n        $auth = \\phpCAS::forceAuthentication();\n        if ($auth) {\n            var_dump($auth);\n            return;\n            # 8 验证通过，或者说已经登陆系统，可进行已经登陆之后的逻辑处理...\n            # 获得登陆CAS用户的名称\n            $user_name = \\phpCAS::getUser();\n            echo $user_name . '已经成功登陆...<br>';\n\n            # 9 你还可打印保存的phpCAS session信息\n            print_r($_SESSION);\n\n            # 10 还可获取有关已验证用户的属性,例如：$uid = phpCAS::getAttribute('id');\n            $attr = \\phpCAS::getAttributes();\n            print_r($attr);\n\n            # 11 进行退出的相关操作\n            # 在你的PHP项目中处理完相应的退出逻辑之后，还需执行phpCAS::logout()进行CAS系统的退出\n            # 当我们访问cas服务端的logout的时候，cas服务器会发送post请求到各个已经登录的客户端\n            //phpCAS::logout();\n\n            # 登出方法一：登出成功后跳转的地址\n            //phpCAS::setServerLoginUrl(\"https://192.168.1.120:80/cas/logout?embed=true&service=http://localhost/phpCasClient/user.php?a=login\");\n            //phpCAS::logout();\n            # 登出方法二：退出登录后返回地址\n            //$param = array(\"service\" => \"http://cas.x.com\");\n            //phpCAS::logout($param);\n\n        } else {\n            # 12 验证未通过，说明未进行登陆\n            # 将会跳转回你配置的CAS SSO SERVER服务的域名；\n            # 在你输入正确的用户名和密码之后CAS会自动跳转回service=http%3A%2F%2Fcas.x.com%2F此地址\n            # 在此你可以处理验证未通过的各种逻辑\n            echo '还未登陆，跳转到CAS进行登陆...<br>';\n        }\n    }\n}\n"
  },
  {
    "path": "server/Application/Api/Controller/FlowController.class.php",
    "content": "<?php\n\nnamespace Api\\Controller;\n\nuse Think\\Controller;\n\nclass FlowController extends BaseController\n{\n\n    private $pages;\n\n    //保存\n    public function save()\n    {\n        $login_user = $this->checkLogin();\n        $id = I(\"id/d\");\n        $flow_name = I(\"flow_name\");\n        $item_id = I(\"item_id/d\");\n        $env_id = I(\"env_id/d\");\n        $times = isset($_REQUEST['times']) ? I(\"times/d\") : 1;\n        $time_interval = isset($_REQUEST['time_interval']) ? I(\"time_interval/d\") : 0;\n        $error_continue = isset($_REQUEST['error_continue']) ? I(\"error_continue/d\") : 1;\n        $save_change = isset($_REQUEST['save_change']) ? I(\"save_change/d\") : 1;\n\n        $date_time = date(\"Y-m-d H:i:s\");\n        if ($id) {\n            $res = D(\"RunapiFlow\")->where(array('id' => $id))->find();\n            if (!$this->checkItemEdit($login_user['uid'], $res['item_id'])) {\n                $this->sendError(10303);\n                return;\n            }\n            $data = array();\n            $data['last_update_time'] = $date_time;\n            if ($flow_name) {\n                $data['flow_name'] = $flow_name;\n            }\n            if (isset($_REQUEST['env_id'])) {\n                $data['env_id'] = $env_id;\n            }\n            if (isset($_REQUEST['times'])) {\n                $data['times'] = $times;\n            }\n            if (isset($_REQUEST['time_interval'])) {\n                $data['time_interval'] = $time_interval;\n            }\n            if (isset($_REQUEST['error_continue'])) {\n                $data['error_continue'] = $error_continue;\n            }\n            if (isset($_REQUEST['save_change'])) {\n                $data['save_change'] = $save_change;\n            }\n            D(\"RunapiFlow\")->where(array('id' => $id))->save($data);\n        } else {\n            if (!$this->checkItemEdit($login_user['uid'], $item_id)) {\n                $this->sendError(10303);\n                return;\n            }\n            $data = array();\n            $data['username'] = $login_user['username'];\n            $data['uid'] = $login_user['uid'];\n            $data['flow_name'] = $flow_name;\n            $data['env_id'] = $env_id;\n            $data['item_id'] = $item_id;\n            $data['times'] = $times;\n            $data['time_interval'] = $time_interval;\n            $data['error_continue'] = $error_continue;\n            $data['save_change'] = $save_change;\n            $data['addtime'] = $date_time;\n            $data['last_update_time'] = $date_time;\n            // 如果环境小于等于0，尝试获取项目的第一个环境变量赋值\n            if ($env_id <= 0) {\n                $res = D(\"RunapiEnv\")->where(array('item_id' => $item_id))->find();\n                if ($res && $res['id']) {\n                    $data['env_id'] =  $res['id'];\n                }\n            }\n            $id = D(\"RunapiFlow\")->add($data);\n        }\n        usleep(300000);\n        $res = D(\"RunapiFlow\")->where(array('id' => $id))->find();\n        $this->sendResult($res);\n    }\n\n    //获取列表\n    public function getList()\n    {\n        $login_user = $this->checkLogin();\n        $item_id = I(\"item_id/d\");\n        if (!$this->checkItemEdit($login_user['uid'], $item_id)) {\n            $this->sendError(10303);\n            return;\n        }\n\n        $ret = D(\"RunapiFlow\")->where(array('item_id' => $item_id))->order(\" id desc  \")->select();\n        if ($ret) {\n            $this->sendResult($ret);\n        } else {\n            $this->sendResult(array());\n        }\n    }\n\n    //删除\n    public function delete()\n    {\n        $id = I(\"id/d\") ? I(\"id/d\") : 0;\n        $login_user = $this->checkLogin();\n        $res = D(\"RunapiFlow\")->where(array('id' => $id))->find();\n        if (!$this->checkItemEdit($login_user['uid'], $res['item_id'])) {\n            $this->sendError(10303);\n            return;\n        }\n\n        $ret = D(\"RunapiFlow\")->where(array('id' => $id))->delete();\n\n        if ($ret) {\n            $this->sendResult($ret);\n        } else {\n            $return['error_code'] = 10103;\n            $return['error_message'] = 'request  fail';\n            $this->sendResult($return);\n        }\n    }\n\n    // 新增接口到flow中\n    public function addFlowPage()\n    {\n        $login_user = $this->checkLogin();\n        $flow_id = I(\"flow_id/d\");\n        $page_id = I(\"page_id/d\");\n        $flow_res = D(\"RunapiFlow\")->where(array('id' => $flow_id))->find();\n        if (!$this->checkItemEdit($login_user['uid'], $flow_res['item_id'])) {\n            $this->sendError(10303);\n            return;\n        }\n        $page_res = $page = M(\"Page\")->where(array('page_id' => $page_id))->find();\n        if (!$this->checkItemEdit($login_user['uid'], $page_res['item_id'])) {\n            $this->sendError(10303);\n            return;\n        }\n\n        // 获取该flow的最后一个页面的顺序号\n        $s_number1 = D(\"RunapiFlowPage\")->where(array('flow_id' => $flow_id))->order(\"s_number desc\")->getField(\"s_number\");\n        $s_number = $s_number1 + 1;\n        $id = D(\"RunapiFlowPage\")->add(array(\n            \"flow_id\" => $flow_id,\n            \"page_id\" => $page_id,\n            \"s_number\" => $s_number,\n            \"addtime\" => date(\"Y-m-d H:i:s\"),\n        ));\n        if ($id) {\n            $this->sendResult($id);\n        } else {\n            $this->sendError(10101);\n        }\n    }\n\n    // 从flow中删除接口\n    public function deleteFlowPage()\n    {\n        $login_user = $this->checkLogin();\n        $id = I(\"id/d\");\n        $flow_page_res = D(\"RunapiFlowPage\")->where(array('id' => $id))->find();\n        $page_id = $flow_page_res['page_id'];\n        $page_res = $page = M(\"Page\")->where(array('page_id' => $page_id))->find();\n        if (!$this->checkItemEdit($login_user['uid'], $page_res['item_id'])) {\n            $this->sendError(10303);\n            return;\n        }\n        $res = D(\"RunapiFlowPage\")->where(array('id' => $id))->delete();\n        if ($res) {\n            $this->sendResult($res);\n        } else {\n            $this->sendError(10101);\n        }\n    }\n    // 获取某个流程里的接口列表\n    public function getFlowPageList()\n    {\n        $login_user = $this->checkLogin();\n        $flow_id = I(\"flow_id/d\");\n        $flow_res = D(\"RunapiFlow\")->where(array('id' => $flow_id))->find();\n        if (!$this->checkItemEdit($login_user['uid'], $flow_res['item_id'])) {\n            $this->sendError(10303);\n            return;\n        }\n        $res = D(\"RunapiFlowPage\")->where(array(\n            \"flow_id\" => $flow_id,\n        ))->order(\"s_number asc \")->select();\n        if ($res) {\n            foreach ($res as $key => $value) {\n                $res[$key]['page_title'] = $this->_get_page_title($flow_res['item_id'], $value['page_id']);\n            }\n            $this->sendResult($res);\n        } else {\n            $this->sendResult(array());\n        }\n    }\n\n    private function _get_page_title($item_id, $page_id)\n    {\n        if (!$this->pages) {\n            $ret = D(\"Page\")->where(\" item_id = '%d' \", array($item_id))->select();\n            if ($ret) {\n                $this->pages = $ret;\n            } else {\n                return false;\n            }\n        }\n\n        foreach ($this->pages as $key => $value) {\n            if ($value['page_id'] == $page_id) {\n                return $value['page_title'];\n            }\n        }\n        return false;\n    }\n\n\n    // 保存顺序关系\n    public function saveSort()\n    {\n        $login_user = $this->checkLogin();\n        $flow_id = I(\"flow_id/d\");\n        $orders = I(\"orders\");\n        $res = D(\"RunapiFlow\")->where(array('id' => $flow_id))->find();\n        if (!$this->checkItemEdit($login_user['uid'], $res['item_id'])) {\n            $this->sendError(10303);\n            return;\n        }\n        $data_array = json_decode(htmlspecialchars_decode($orders), true);\n        if ($data_array) {\n            foreach ($data_array as $key => $value) {\n                if ($value['id']) {\n                    D(\"RunapiFlowPage\")->where(\" flow_id = '%d' and id = '%d' \", array($flow_id, $value['id']))->save(array(\n                        \"s_number\" => $value['s_number']\n                    ));\n                }\n            }\n        }\n        $this->sendResult(array());\n    }\n\n    // 保存启用关系\n    public function setFlowPageEnabled()\n    {\n        $login_user = $this->checkLogin();\n        $flow_id = I(\"flow_id/d\");\n        $ids = I(\"ids\");\n        $res = D(\"RunapiFlow\")->where(array('id' => $flow_id))->find();\n        if (!$this->checkItemEdit($login_user['uid'], $res['item_id'])) {\n            $this->sendError(10303);\n            return;\n        }\n        $data_array = json_decode(htmlspecialchars_decode($ids), true);\n        if ($data_array) {\n            D(\"RunapiFlowPage\")->where(array('flow_id' => $flow_id))->save(array(\n                \"enabled\" => 0\n            ));\n            foreach ($data_array as $key => $value) {\n                if ($value) {\n                    D(\"RunapiFlowPage\")->where(\" flow_id = '%d' and id = '%d' \", array($flow_id, $value))->save(array(\n                        \"enabled\" => 1\n                    ));\n                }\n            }\n        }\n        $this->sendResult(array());\n    }\n}\n"
  },
  {
    "path": "server/Application/Api/Controller/FromCommentsController.class.php",
    "content": "<?php\n\nnamespace Api\\Controller;\n\nuse Think\\Controller;\n/*\n    通过注释生成api文档\n */\n\nclass FromCommentsController extends BaseController\n{\n\n    public function generate()\n    {\n        //return ;\n        header('Content-Type:text/html;charset=utf-8 ');\n        $content = htmlspecialchars_decode(I(\"content\", null)); // 不进行过滤,并且进行html反转义\n        $api_key = I(\"api_key\");\n        $api_token = I(\"api_token\");\n\n        $item_id = D(\"ItemToken\")->check($api_key, $api_token);\n        if (!$item_id) {\n            //没验证通过\n            echo \"\\napi_key或者api_token不匹配\\n\\n\";\n            return false;\n        }\n        $content = str_replace(\"_this_and_change_\", \"&\", $content);\n        $p = \"|/\\*\\*([\\s\\S]*)\\*/|U\";\n        preg_match_all($p, $content, $matches);\n        if ($matches && $matches[0]) {\n            foreach ($matches[0] as $key => $value) {\n                if (strstr($value, \"@title\") && strstr($value, \"showdoc\")) {\n                    $ret = $this->generate_one($item_id, $value);\n                }\n            }\n        }\n        if ($ret) {\n            echo \"\\n 成功 \\n\\n \";\n        } else {\n            echo \"失败\";\n        }\n    }\n\n    private function generate_one($item_id, $content)\n    {\n        $convert = new \\Api\\Helper\\Convert();\n        $item = D(\"Item\")->where(\"item_id = '%d'\", array($item_id))->find();\n        $array = $this->parse_content($content);\n        $page_content = $this->_toRunapiFormat($array);\n        if ($item['item_type'] != '3') {\n            $page_content = $convert->runapiToMd($page_content);\n        }\n        $page_title = $array['title'];\n        $page_content = htmlspecialchars($page_content);\n        $cat_name = $array['cat_name'];\n        $s_number = $array['s_number'] ? $array['s_number'] : 99;\n        $page_id = D(\"Page\")->update_by_title($item_id, $page_title, $page_content, $cat_name, $s_number);\n        if ($page_id) {\n            $ret = D(\"Page\")->where(\" page_id = '%d' \", array($page_id))->find();\n            return $ret;\n        } else {\n            return false;\n        }\n    }\n\n    //解析content，返回数组\n    private function parse_content($content)\n    {\n        $array = array();\n\n        //解析标题\n        $array['title'] = $this->parse_one_line(\"title\", $content);\n\n        $array['method'] = $this->parse_one_line(\"method\", $content);\n\n        $array['description'] = $this->parse_one_line(\"description\", $content);\n\n        $array['url'] = $this->parse_one_line(\"url\", $content);\n\n        //解析目录\n        $array['cat_name'] = $this->parse_one_line(\"catalog\", $content);\n\n        //解析返回内容\n        $return = $this->parse_one_line(\"return\", $content);\n        $return = htmlspecialchars_decode($return);\n\n        $array['return'] = $return;\n\n        //解析请求参数\n        $array['param'] = $this->parse_muti_line('param', $content);\n\n        //解析请求header\n        $array['header'] = $this->parse_muti_line('header', $content);\n\n\n        //解析返回参数\n        $array['return_param'] = $this->parse_muti_line('return_param', $content);\n\n        $array['remark'] = $this->parse_one_line(\"remark\", $content);\n\n        $array['s_number'] = $this->parse_one_line(\"number\", $content);\n\n        //如果请求参数是json，则生成请求示例\n        $json_param = $this->parse_one_line(\"json_param\", $content);\n        $json_param = htmlspecialchars_decode($json_param);\n\n        $array['json_param'] = $json_param;\n\n        return $array;\n    }\n\n    //解析单行标签，如method、url\n    private function parse_one_line($tag, $content)\n    {\n        $p = '/@' . $tag . '.+/';\n        preg_match($p, $content, $matches);\n        //var_dump($p);\n        //var_dump($matches);\n        if ($matches && $matches[0]) {\n            return  trim(str_replace('@' . $tag, '', $matches[0]));\n        }\n\n        return false;\n    }\n\n    //解析多行标签，如param\n    private function parse_muti_line($tag, $content)\n    {\n        $return = array();\n        $array1 = explode(\"@\", $content);\n        foreach ($array1 as $key => $value) {\n            $array2 = preg_split(\"/[\\s]+/\", trim($value));\n            if (!empty($array2[0]) && $array2[0] == $tag) {\n                unset($array2[0]);\n                $return[] = array_values($array2);\n            }\n        }\n\n        return $return;\n    }\n\n    //转成runapi的接口格式\n    private function _toRunapiFormat($array)\n    {\n        $content_array = array(\n            \"info\" => array(\n                \"from\" =>  'runapi',\n                \"type\" =>  'api',\n                \"title\" =>  $array['title'],\n                \"description\" =>  $array['description'],\n                \"method\" =>  strtolower($array['method']),\n                \"url\" =>  $array['url'],\n                \"remark\" =>  $array['remark'],\n            ),\n            \"request\" => array(\n                \"params\" => array(\n                    'mode' => \"formdata\",\n                    'json' => \"\",\n                    'urlencoded' => array(),\n                    'formdata' => array(),\n                ),\n                \"headers\" => array(),\n                \"query\" => array(),\n                \"cookies\" => array(),\n                \"auth\" => array(),\n            ),\n            \"response\" => array(\n                \"responseExample\" => $array['return'],\n                \"responseParamsDesc\" => array(),\n            ),\n            \"extend\" => array(),\n        );\n\n        $responseExample = $this->_indent_json($content_array['response']['responseExample']);\n        $content_array['response']['responseExample'] = $responseExample ? $responseExample : $content_array['response']['responseExample'];\n\n        if ($array['header']) {\n            foreach ($array['header'] as $key => $value) {\n                // |参数名|是否必选|类型|说明\n                $content_array['request']['headers'][] = array(\n                    \"name\" => $value[0],\n                    \"require\" => ($value[1] == '必选') ? '1' : '0',\n                    \"type\" => $value[2],\n                    \"value\" => '',\n                    \"remark\" => $value[3],\n                );\n            }\n        }\n\n        if ($array['json_param']) {\n            $content_array['request']['params']['mode'] = 'json';\n            $content_array['request']['params']['json'] = $array['json_param'];\n            // 请求方式是json的话，原有的参数说明数组就写入json描述中\n            if ($array['param']) {\n                foreach ($array['param'] as $key => $value) {\n                    // |参数名|是否必选|类型|说明\n                    $content_array['request']['params']['jsonDesc'][] = array(\n                        \"name\" => $value[0],\n                        \"require\" => ($value[1] == '必选') ? '1' : '0',\n                        \"type\" => $value[2],\n                        \"value\" => '',\n                        \"remark\" => $value[3],\n                    );\n                }\n            }\n        }\n        // \n        if ($array['param']) {\n            if (strtolower($array['method']) == 'get') {\n                $query_str = '';\n                foreach ($array['param'] as $key => $value) {\n                    // |参数名|是否必选|类型|说明\n                    $content_array['request']['query'][] = array(\n                        \"name\" => $value[0],\n                        \"require\" => ($value[1] == '必选') ? '1' : '0',\n                        \"type\" => $value[2],\n                        \"value\" => '',\n                        \"remark\" => $value[3],\n                    );\n                    $query_str .= $value[0] . \"=\" . '&';\n                }\n                // 为了兼容，还要把query参数追加到url里去\n                if (strstr($content_array['info']['url'], \"?\")) {\n                    $content_array['info']['url'] .= \"&\" . $query_str;\n                } else {\n                    $content_array['info']['url'] .= \"?\" . $query_str;\n                }\n            } else {\n                foreach ($array['param'] as $key => $value) {\n                    // |参数名|是否必选|类型|说明\n                    $content_array['request']['params']['formdata'][] = array(\n                        \"name\" => $value[0],\n                        \"require\" => ($value[1] == '必选') ? '1' : '0',\n                        \"type\" => $value[2],\n                        \"value\" => '',\n                        \"remark\" => $value[3],\n                    );\n                }\n            }\n        }\n\n        if ($array['return_param']) {\n            foreach ($array['return_param'] as $key => $value) {\n                // |参数名|类型|说明\n                $content_array['response']['responseParamsDesc'][] = array(\n                    \"name\" => $value[0],\n                    \"type\" => $value[1],\n                    \"value\" => '',\n                    \"remark\" => $value[2],\n                );\n            }\n        }\n\n        return json_encode($content_array);\n    }\n\n    // json美化\n    private function _indent_json($json)\n    {\n\n        $json_new = json_encode(json_decode($json), JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);\n        if ($json_new && $json_new != 'null') {\n            return $json_new;\n        }\n        return $json;\n    }\n}\n"
  },
  {
    "path": "server/Application/Api/Controller/ImportController.class.php",
    "content": "<?php\n\nnamespace Api\\Controller;\n\nuse Think\\Controller;\n\nclass ImportController extends BaseController\n{\n\n\n    //自动检测导入的文件类型从而选择不同的控制器方法\n    public function auto()\n    {\n        set_time_limit(100);\n        ini_set('memory_limit', '6000M');\n        $login_user = $this->checkLogin();\n        $filename = $_FILES[\"file\"][\"name\"];\n        $file = $_FILES[\"file\"][\"tmp_name\"];\n        //文件后缀\n        $tail = substr(strrchr($filename, '.'), 1);\n        $item_id = I(\"item_id\") ? I(\"item_id\") : '0';\n        if ($item_id) {\n            if (!$this->checkItemEdit($login_user['uid'], $item_id)) {\n                $this->sendError(10302);\n                return;\n            }\n        }\n\n        if ($tail == 'zip') {\n            $zipArc = new \\ZipArchive();\n            $ret = $zipArc->open($file, \\ZipArchive::CREATE);\n            // 先尝试新的格式 info.json，如果不存在则尝试旧的格式 prefix_info.json\n            $info = $zipArc->getFromName(\"info.json\");\n            if (!$info) {\n                $info = $zipArc->getFromName(\"prefix_info.json\");\n            }\n            // 如有info.json或prefix_info.json文件，则导入\n            if ($info) {\n                $info_array = json_decode($info, 1);\n                if ($info_array) {\n                    $info_array['item_id'] = $item_id;\n                    $this->importMarkdownInfo($info_array, $item_id);\n                    return;\n                }\n            } else {\n                // 如果没有，则尝试解压压缩包后，遍历markdown文件导入\n                $this->importFromReadingMDFile($file, $filename, $item_id);\n                return;\n            }\n        }\n\n        if ($tail == 'json') {\n            $json = file_get_contents($file);\n            $json_array = json_decode($json, 1);\n            unset($json);\n            if (($json_array['swagger'] || $json_array['openapi']) && $json_array['info']) {\n                R(\"ImportSwagger/import\");\n                return;\n            }\n            if ($json_array['id']) {\n                R(\"ImportPostman/import\");\n                return;\n            }\n            if ($json_array['info']) {\n                R(\"ImportPostman/import\");\n                return;\n            }\n        }\n\n        $this->sendError(10101);\n    }\n\n    //导入markdown压缩包(根据压缩包内的info文件导入）)\n    public function importMarkdownInfo($info_array, $item_id)\n    {\n        set_time_limit(100);\n        ini_set('memory_limit', '200M');\n\n        $login_user = $this->checkLogin();\n\n        $file = $_FILES[\"file\"][\"tmp_name\"];\n        //$file = \"../Public/markdown.zip\" ; //test\n\n        if (!$info_array) {\n            $zipArc = new \\ZipArchive();\n            $ret = $zipArc->open($file, \\ZipArchive::CREATE);\n            // 先尝试新的格式 info.json，如果不存在则尝试旧的格式 prefix_info.json\n            $info = $zipArc->getFromName(\"info.json\");\n            if (!$info) {\n                $info = $zipArc->getFromName(\"prefix_info.json\");\n            }\n            $info_array = json_decode($info, 1);\n            unset($info);\n        }\n\n        if ($info_array) {\n            // $info_array['item_id'] = '2'; //debug\n            D(\"Item\")->import(json_encode($info_array), $login_user['uid'], $item_id);\n            $this->sendResult(array());\n            return;\n        }\n\n        $this->sendError(10101);\n    }\n\n    public function importFromReadingMDFile($file, $filename, $item_id)\n    {\n        // 如果项目id不存在，则新建一个项目\n        if ($item_id <= 0) {\n            $login_user = $this->checkLogin();\n            $item_data = array(\n                \"item_name\" => str_replace('.zip', '', $filename),\n                \"item_domain\" => '',\n                \"item_type\" => 1,\n                \"item_description\" => '',\n                \"password\" => get_rand_str(),\n                \"uid\" => $login_user['uid'],\n                \"username\" => $login_user['username'],\n                \"addtime\" => time(),\n            );\n            $item_id = D(\"Item\")->add($item_data);\n        }\n        $zipArc = new \\ZipArchive();\n        $zipArc->open($file, \\ZipArchive::CREATE);\n        // 在系统目录创建一个临时目录路径\n        $tmp_dir = sys_get_temp_dir() . '/' . get_rand_str();\n        mkdir($tmp_dir);\n\n        // 加入此段是为了某些情况下中文名乱码问题，要先转码\n        $fileNum = $zipArc->numFiles;\n        for ($i = 0; $i < $fileNum; $i++) {\n            $statInfo = $zipArc->statIndex($i, \\ZipArchive::FL_ENC_RAW);\n            $current_encode = mb_detect_encoding($statInfo['name'], array(\"ASCII\", \"GB2312\", \"GBK\", 'BIG5', 'UTF-8'));\n            $statInfo['name'] = mb_convert_encoding($statInfo['name'], 'UTF-8', $current_encode);\n            $zipArc->renameIndex($i, $statInfo['name']);\n        }\n        $zipArc->close();\n        $zipArc->open($file, \\ZipArchive::CREATE);\n        // 截至↑\n\n        $zipArc->extractTo($tmp_dir);\n\n        // 遍历解压后的目录\n        // 定义一个匿名函数，以便使用名字来递归\n        $traverseFiles = function ($dir) use (&$traverseFiles, $item_id, $tmp_dir) {\n            $handle = opendir($dir);\n            while ($file = readdir($handle)) {\n                if ($file !== '..' && $file !== '.') {\n                    $f = $dir . '/' . $file;\n                    if (is_file($f)) {\n                        // 跳过 info.json 和 prefix_info.json 文件\n                        if ($file === 'info.json' || $file === 'prefix_info.json') {\n                            continue;\n                        }\n                        // 只处理 .md 文件\n                        if (substr($file, -3) !== '.md') {\n                            continue;\n                        }\n                        // echo '|--' . $file . '<br>';          //代表文件\n                        $page_title = str_replace('.md', '', $file);\n                        $page_content = file_get_contents($f);\n                        // 获取目录路径，去掉临时目录前缀，并规范化路径分隔符\n                        $cat_name = str_replace($tmp_dir, '', $dir);\n                        // 统一路径分隔符为 /\n                        $cat_name = str_replace('\\\\', '/', $cat_name);\n                        // 去掉开头的斜杠和空格\n                        $cat_name = trim($cat_name, '/ ');\n                        // 如果目录名为空，说明是根目录\n                        if (empty($cat_name)) {\n                            $cat_name = '';\n                        }\n                        // echo $cat_name . '<br>';\n                        D(\"Page\")->update_by_title($item_id, $page_title, $page_content, $cat_name);\n                    } else {\n                        // echo  '--' . $file . '<br>';          //代表文件夹\n                        // 这里目录，则继续递归遍历\n                        $traverseFiles($f);\n                    }\n                }\n            }\n        };\n        $traverseFiles($tmp_dir, $item_id);\n        clear_runtime($tmp_dir); // clear_runtime 函数是可以删除任意目录的。当初写的时候只是用来清除缓存目录。所以命名并不友好\n        $this->sendResult(array());\n    }\n}\n"
  },
  {
    "path": "server/Application/Api/Controller/ImportPostmanController.class.php",
    "content": "<?php\n\nnamespace Api\\Controller;\n\nuse Think\\Controller;\n\nclass ImportPostmanController extends BaseController\n{\n\n\n    public function import()\n    {\n        set_time_limit(100);\n        ini_set('memory_limit', '6000M');\n        $login_user = $this->checkLogin();\n        $item_id = I(\"item_id\") ? I(\"item_id\") : '0';\n        if ($item_id) {\n            if (!$this->checkItemEdit($login_user['uid'], $item_id)) {\n                $this->sendError(10302);\n                return;\n            }\n        }\n        $json = file_get_contents($_FILES[\"file\"][\"tmp_name\"]);\n\n        //$json = file_get_contents(\"../Public/postmanpostman_collectionV2.json\") ;//test\n        $json_array = json_decode($json, 1);\n        unset($json);\n        if ($json_array['id']) {\n            $json_array['item_id'] = $item_id;\n            $this->_fromPostmanV1($json_array, $item_id);\n            return;\n        }\n\n        if ($json_array['info']) {\n            $json_array['item_id'] = $item_id;\n            $this->_fromPostmanV2($json_array, $item_id);\n            return;\n        }\n\n        $this->sendError(10101);\n    }\n\n    //从postman导入(v1版本)\n\n    private function _fromPostmanV1($json_array, $item_id)\n    {\n        $login_user = $this->checkLogin();\n\n        // TODO 这里需要检查下合法性。比如关键字检查/黑名单检查/字符串过滤\n\n        $from = I(\"from\") ? I(\"from\") : '';\n        $item_array = array(\n            \"item_id\" => $json_array['item_id'],\n            \"item_name\" => $json_array['name'] ? $json_array['name'] : 'from postman',\n            \"item_type\" => ($from == 'runapi') ? '3' : '1',\n            \"item_description\" => $json_array['description'] ? $json_array['description'] : '',\n            \"password\" => time() . rand(),\n            \"members\" => array(),\n            \"pages\" => array(\n                \"pages\" => array(),\n                \"catalogs\" => array()\n            )\n        );\n        $level = 2;\n\n        foreach ($json_array['requests'] as $key => $value) {\n            if (!$value['folder']) {\n                $item_array['pages']['pages'][] = $this->_requestToDoc($value);\n            }\n        }\n\n        foreach ($json_array['folders'] as $key => $value) {\n            //不存在父目录的话，那就是根目录了。\n            if (!$value['folder']) {\n                $cat_array = array(\n                    \"id\" => $value['id'],\n                    \"cat_name\" => $value['name'],\n                    \"level\" => $level,\n                    \"s_number\" => 99,\n                );\n                $cat_array['pages'] =  $this->_getPageByFolders($value['id'], $json_array);\n                $cat_array['catalogs'] =  $this->_getSubByFolders($value['id'], $value['name'], $level + 1, $json_array);\n\n                $item_array['pages']['catalogs'][]  = $cat_array;\n            }\n        }\n\n        $item_id = D(\"Item\")->import(json_encode($item_array), $login_user['uid'], $item_id);\n\n        //echo D(\"Item\")->export(196053901215026 );\n        //echo json_encode($item_array);\n        $this->sendResult(array(\"item_id\" => $item_id));\n    }\n\n    //根据postman的folders获取子页面和子目录\n    //参数id为父目录的id\n    private function _getSubByFolders($id, $name, $level, $json_array)\n    {\n        $return = array();\n        foreach ($json_array['folders'] as $key => $value) {\n            if ($value['folder'] && $value['folder'] == $id) {\n                $cat_array = array(\n                    \"id\" => $value['id'],\n                    \"cat_name\" => $value['name'],\n                    \"level\" => $level,\n                    \"s_number\" => 99,\n                );\n                $cat_array['pages'] = $this->_getPageByFolders($value['id'], $json_array);\n                $cat_array['catalogs'] = $this->_getSubByFolders($value['id'], $value['name'], $level + 1, $json_array);\n                $return[] = $cat_array;\n            }\n        }\n\n        return $return;\n    }\n\n\n    //根据postman的folders获取页面\n    private function _getPageByFolders($id, $json_array)\n    {\n        $return = array();\n        foreach ($json_array['requests'] as $key => $value) {\n            if ($value['folder'] == $id) {\n                $return[] = $this->_requestToDoc($value);\n            }\n        }\n\n        return $return;\n    }\n\n\n\n    private function _requestToDoc($request)\n    {\n        $from = I(\"from\") ? I(\"from\") : '';\n        $res = $this->_requestToApi($request);\n        if ($from == 'runapi') {\n            return $res;\n        } else {\n            $convert = new \\Api\\Helper\\Convert();\n            $res['page_content'] = $convert->runapiToMd($res['page_content']);\n            return $res;\n        }\n    }\n\n    //转成runapi所需要的api格式\n    private function _requestToApi($request)\n    {\n        $return = array();\n        $return['page_title'] = $request['name'];\n        $return['id'] = $request['id'];\n        $return['s_number'] = 99;\n        $return['page_comments'] = '';\n        //若$return['page_title'] 为很长的url，则做一些特殊处理\n        $tmp_title_array = explode(\"/\", $return['page_title']);\n        if ($tmp_title_array) {\n            $tmp_title_array = array_slice($tmp_title_array, -2); // 倒数2个\n            if ($tmp_title_array[1]) $return['page_title'] = $tmp_title_array[0] . \"/\" . $tmp_title_array[1];\n        }\n\n        $content_array = array(\n            \"info\" => array(\n                \"from\" =>  'runapi',\n                \"type\" =>  'api',\n                \"title\" =>  $request['name'],\n                \"description\" =>  $request['description'],\n                \"method\" =>  strtolower($request['method']),\n                \"url\" =>  $request['url'],\n                \"remark\" =>  '',\n            ),\n            \"request\" => array(\n                \"params\" => array(\n                    'mode' => \"urlencoded\",\n                    'json' => \"\",\n                    'urlencoded' => array(),\n                    'formdata' => array(),\n                ),\n                \"headers\" => array(),\n                \"cookies\" => array(),\n                \"auth\" => array(),\n            ),\n            \"response\" => array(),\n            \"extend\" => array(),\n        );\n\n        if ($request['headerData']) {\n            $tmp_array = array();\n            foreach ($request['headerData'] as $key => $value) {\n                $content_array['request']['headers'][] = array(\n                    \"name\" => $value[\"key\"],\n                    \"type\" => 'string',\n                    \"value\" => $value[\"value\"],\n                    \"require\" => '1',\n                    \"remark\" => $value[\"description\"] ? $value[\"description\"] : '',\n                );\n            }\n        }\n\n        if ($request['data']) {\n\n            foreach ($request['data'] as $key => $value) {\n                $content_array['request']['params']['urlencoded'][] = array(\n                    \"name\" => $value[\"key\"],\n                    \"type\" => 'string',\n                    \"value\" => $value[\"value\"],\n                    \"require\" => '1',\n                    \"remark\" => $value[\"description\"] ? $value[\"description\"] : '',\n                );\n            }\n        }\n\n        $return['page_content'] = json_encode($content_array);\n        return $return;\n    }\n\n\n    //从postman导入(v2版本)\n    private function _fromPostmanV2($json_array, $item_id)\n    {\n\n        $login_user = $this->checkLogin();\n\n        // TODO 这里需要检查下合法性。比如关键字检查/黑名单检查/字符串过滤\n\n        $from = I(\"from\") ? I(\"from\") : '';\n        $item_array = array(\n            \"item_id\" => $json_array['item_id'],\n            \"item_name\" => $json_array['info']['name'] ? $json_array['info']['name']  : 'from postman',\n            \"item_type\" => ($from == 'runapi') ? '3' : '1',\n            \"item_description\" => $json_array['info']['description'] ? $json_array['info']['description'] : '',\n            \"password\" => time() . rand(),\n            \"members\" => array(),\n            \"pages\" => array(\n                \"pages\" => array(),\n                \"catalogs\" => array()\n            )\n        );\n        $level = 2;\n        $item_array['pages']['pages'] = $this->_getPageByItem($json_array['item']);\n        $item_array['pages']['catalogs'] = $this->_getItemByItem($json_array['item'], 2);\n        // $item_array['item_id'] = '0'; //debug\n        $item_id =  D(\"Item\")->import(json_encode($item_array), $login_user['uid'], $item_id);\n        $this->sendResult(array(\"item_id\" => $item_id));\n    }\n\n    //获取某个目录下的所有页面\n    private function _getPageByItem($item_array)\n    {\n        $return = array();\n        foreach ($item_array as $key => $value) {\n\n            //含有request，则这是一个子页面\n            if ($value['request']) {\n                $return[] = $this->_requestToDocV2($value['name'], $value);\n            }\n        }\n        return $return;\n    }\n\n    //获取某个目录下的所有子目录\n    private function _getItemByItem($item_array, $level)\n    {\n        $return = array();\n        foreach ($item_array as $key => $value) {\n\n            //含有item，则这是一个子目录\n            if ($value['item']) {\n                $one_ary = array(\n                    \"cat_name\" => $value['name'],\n                    \"level\" => $level,\n                    \"s_number\" => 99,\n                    \"pages\" => $this->_getPageByItem($value['item'], $level + 1), //递归\n                    \"catalogs\" => $this->_getItemByItem($value['item'], $level + 1) //递归\n                );\n                $return[] = $one_ary;\n            }\n        }\n        return $return;\n    }\n\n    private function _requestToDocV2($name, $page)\n    {\n        $from = I(\"from\") ? I(\"from\") : '';\n        $res = $this->_requestToApiV2($name, $page);\n        if ($from == 'runapi') {\n            return $res;\n        } else {\n            $convert = new \\Api\\Helper\\Convert();\n            $res['page_content'] = $convert->runapiToMd($res['page_content']);\n            return $res;\n        }\n    }\n\n    //转成runapi所需要的api格式\n    private function _requestToApiV2($name, $page)\n    {\n        $request = $page['request'];\n        $return = array();\n        $return['page_title'] = $name;\n        $return['s_number'] = 99;\n        $return['page_comments'] = '';\n        //若$return['page_title'] 为很长的url，则做一些特殊处理\n        $tmp_title_array = explode(\"/\", $return['page_title']);\n        if ($tmp_title_array) {\n            $tmp_title_array = array_slice($tmp_title_array, -2); // 倒数2个\n            if ($tmp_title_array[1]) $return['page_title'] = $tmp_title_array[0] . \"/\" . $tmp_title_array[1];\n        }\n        $url = is_array($request['url']) ? $request['url']['raw'] : $request['url'];\n        $rawModeData = $request['body']['mode'] == 'raw' ? $request['body']['raw']  : $request['rawModeData'];\n\n        $content_array = array(\n            \"info\" => array(\n                \"from\" =>  'runapi',\n                \"type\" =>  'api',\n                \"title\" =>  $name,\n                \"description\" =>  $request['description'],\n                \"method\" =>  strtolower($request['method']),\n                \"url\" =>  $url,\n                \"remark\" =>  '',\n            ),\n            \"request\" => array(\n                \"params\" => array(\n                    'mode' => $request['body']['mode'],\n                    'json' => \"\",\n                    'urlencoded' => array(),\n                    'formdata' => array(),\n                ),\n                \"headers\" => array(),\n                \"cookies\" => array(),\n                \"auth\" => array(),\n            ),\n            \"response\" => array(),\n            \"extend\" => array(),\n        );\n\n        if ($request['header']) {\n            $tmp_array = array();\n            foreach ($request['header'] as $key => $value) {\n                $content_array['request']['headers'][] = array(\n                    \"name\" => $value[\"key\"],\n                    \"type\" => 'string',\n                    \"value\" => $value[\"value\"],\n                    \"require\" => '1',\n                    \"remark\" => $value[\"description\"] ? $value[\"description\"] : '',\n                );\n            }\n        }\n\n        if (in_array($request['body']['mode'], array('formdata', 'urlencoded')) && $request['body'][$request['body']['mode']]) {\n            foreach ($request['body'][$request['body']['mode']] as $key => $value) {\n                $content_array['request']['params'][$request['body']['mode']][] = array(\n                    \"name\" => $value[\"key\"],\n                    \"type\" => 'string',\n                    \"value\" => $value[\"value\"],\n                    \"require\" => '1',\n                    \"remark\" => $value[\"description\"] ? $value[\"description\"] : '',\n                );\n            }\n        } else if ($rawModeData && json_decode($rawModeData)) {\n            $content_array['request']['params']['mode'] = 'json';\n            $content_array['request']['params']['json'] = $rawModeData;\n        }\n\n        // 兼容get请求参数的场景\n        if ($request['url']['query']) {\n            foreach ($request['url']['query'] as $key => $value) {\n                $content_array['request']['params'][$request['body']['mode']][] = array(\n                    \"name\" => $value[\"key\"],\n                    \"type\" => 'string',\n                    \"value\" => $value[\"value\"],\n                    \"require\" => '1',\n                    \"remark\" => $value[\"description\"] ? $value[\"description\"] : '',\n                );\n            }\n        }\n\n        if ($page['response'][0]['body']) {\n            $content_array['response']['responseExample'] = $page['response'][0]['body'];\n        }\n\n        $return['page_content'] = json_encode($content_array);\n\n        return $return;\n    }\n}\n"
  },
  {
    "path": "server/Application/Api/Controller/ImportSwaggerController.class.php",
    "content": "<?php\n\nnamespace Api\\Controller;\n\nuse Think\\Controller;\n\nclass ImportSwaggerController extends BaseController\n{\n\n    public $json_array = array();\n    public $url_pre =  '';\n\n    public function import()\n    {\n        set_time_limit(100);\n        ini_set('memory_limit', '6000M');\n        $login_user = $this->checkLogin();\n        $item_id = I(\"item_id\") ? I(\"item_id\") : '0';\n        if ($item_id) {\n            if (!$this->checkItemEdit($login_user['uid'], $item_id)) {\n                $this->sendError(10302);\n                return;\n            }\n        }\n        $json = file_get_contents($_FILES[\"file\"][\"tmp_name\"]);\n\n        //$json = file_get_contents(\"../Public/swagger.json\") ;//test\n        $json_array = json_decode($json, 1);\n        unset($json);\n        if ($json_array['info']) {\n            $json_array['item_id'] = $item_id;\n            $this->json_array = $json_array;\n\n            // 根据Swagger/OpenAPI版本分别处理\n            $swagger_version = '';\n            if (isset($json_array['swagger'])) {\n                $swagger_version = $json_array['swagger'];\n            } else if (isset($json_array['openapi'])) {\n                $swagger_version = $json_array['openapi'];\n            }\n\n            // 设置URL前缀\n            if (strstr($swagger_version, '2.')) {\n                // Swagger 2.0 格式\n                $scheme = $json_array['schemes'][0] ? $json_array['schemes'][0] : 'http';\n                if ($json_array['host']) {\n                    $this->url_pre = $scheme . \"://\" . $json_array['host'] . $json_array['basePath'];\n                }\n            } else {\n                // OpenAPI 3.0 格式\n                if ($json_array['servers'][0]['url']) {\n                    $this->url_pre = $json_array['servers'][0]['url'];\n                }\n            }\n\n            // 转换10次。我觉得可能解析的思路不对，以至于要用这种别扭的方法。以后再完善吧\n            for ($i = 0; $i < 10; $i++) {\n                $this->json_array = $this->_transferDefinition($json_array);\n            }\n\n            $this->_fromSwagger($this->json_array, $item_id, $swagger_version);\n            return;\n        }\n\n        $this->sendError(10101);\n    }\n\n    private function _fromSwagger($json_array, $item_id, $swagger_version)\n    {\n\n        $login_user = $this->checkLogin();\n\n        // TODO 这里需要检查下合法性。比如关键字检查/黑名单检查/字符串过滤\n\n        $from = I(\"from\") ? I(\"from\") : '';\n        $item_array = array(\n            \"item_id\" => $json_array['item_id'],\n            \"item_name\" => $json_array['info']['title'] ? $json_array['info']['title']  : 'from swagger',\n            \"item_type\" => ($from == 'runapi') ? '3' : '1',\n            \"item_description\" => $json_array['info']['description'] ? $json_array['info']['description'] : '',\n            \"password\" => time() . rand(),\n            \"members\" => array(),\n            \"pages\" => array(\n                \"pages\" => array(),\n                \"catalogs\" => $this->_getAllTagsLogs($json_array, $swagger_version)\n            )\n        );\n        $level = 2;\n        //$item_array['pages']['catalogs'][0]['pages'] = $this->_getPageByPaths($json_array);\n        $item_id = D(\"Item\")->import(json_encode($item_array), $login_user['uid'], $item_id);\n\n        //echo D(\"Item\")->export(196053901215026 );\n        //echo json_encode($item_array);\n        $this->sendResult(array('item_id' => $item_id));\n    }\n\n    private function _getAllTagsLogs($json_array, $swagger_version)\n    {\n        $catalogsMap = array(\n            \"fromSwagger\" => array(\"cat_name\" => 'from swagger', \"pages\" => array())\n        );\n        $paths = $json_array['paths'];\n        foreach ($paths as $url => $value) {\n            foreach ($value as $method => $value2) {\n                $tags = isset($value2[\"tags\"]) ? $value2[\"tags\"] : array();\n                if ($tags == array()) {\n                    $page = $this->_requestToDoc($method, $url, $value2, $json_array, $swagger_version);\n                    if ($page['page_title']) {\n                        $catalogsMap[\"fromSwagger\"][\"pages\"][] = $page;\n                    }\n                } else {\n                    foreach ($tags as $tag) {\n                        if (!key_exists($tag, $catalogsMap)) {\n                            $page = $this->_requestToDoc($method, $url, $value2, $json_array, $swagger_version);\n                            if ($page[\"page_title\"] != \"\" && $page[\"page_content\"] != \"\") {\n                                $catalogsMap[$tag] = array(\"cat_name\" => $tag, \"pages\" => array($page));\n                            }\n                        } else {\n                            // 存在则page merge\n                            $page = $this->_requestToDoc($method, $url, $value2, $json_array, $swagger_version);\n                            if ($page[\"page_title\"] != \"\" && $page[\"page_content\"] != \"\") {\n                                $catalogsMap[$tag][\"pages\"][] = $page;\n                            }\n                        }\n                    }\n                }\n            }\n        }\n        $catalogs = array();\n        foreach ($catalogsMap as $key => $value) {\n            $catalogs[] = $value;\n        }\n        return $catalogs;\n    }\n\n    private function _getPageByPaths($json_array, $swagger_version)\n    {\n        $return = array();\n        $paths = $json_array['paths'];\n        foreach ($paths as $url => $value) {\n            foreach ($value as $method => $value2) {\n                $return[] = $this->_requestToDoc($method, $url, $value2, $json_array, $swagger_version);\n            }\n        }\n        return $return;\n    }\n\n    private function _requestToDoc($method, $url, $request, $json_array, $swagger_version)\n    {\n        $from = I(\"from\") ? I(\"from\") : '';\n        $res = $this->_requestToApi($method, $url, $request, $json_array, $swagger_version);\n        if ($from == 'runapi') {\n            return $res;\n        } else {\n            $convert = new \\Api\\Helper\\Convert();\n            $res['page_content'] = $convert->runapiToMd($res['page_content']);\n            return $res;\n        }\n    }\n\n    private function _requestToApi($method, $url, $request, $json_array, $swagger_version)\n    {\n        $return = array();\n        $page_title = $request['summary'] ? $request['summary'] : $request['description'];\n        if (!$page_title && $request['operationId']) {\n            $page_title = $request['operationId'];\n        }\n        $page_title = mb_substr($page_title, 0, 50, 'utf-8');\n        $return['page_title'] = $page_title;\n        $return['s_number'] = 99;\n        $return['page_comments'] = '';\n\n        $content_array = array(\n            \"info\" => array(\n                \"from\" =>  'runapi',\n                \"type\" =>  'api',\n                \"title\" => $request['summary'] ? $request['summary'] : $request['description'],\n                \"description\" =>  $request['description'],\n                \"method\" =>  strtolower($method),\n                \"url\" =>  $this->url_pre . $url,\n                \"remark\" =>  '',\n            ),\n            \"request\" => array(\n                \"params\" => array(\n                    'mode' => \"formdata\",\n                    'json' => \"\",\n                    'jsonDesc' => array(),\n                    'urlencoded' => array(),\n                    'formdata' => array(),\n                ),\n                \"query\" => array(),\n                \"headers\" => array(),\n                \"cookies\" => array(),\n                \"auth\" => array(),\n            ),\n            \"response\" => array(),\n            \"extend\" => array(),\n        );\n\n        // 根据版本处理请求体\n        if (strstr($swagger_version, '2.')) {\n            // 处理Swagger 2.0\n            $this->_processSwagger2Request($request, $content_array);\n        } else {\n            // 处理OpenAPI 3.0\n            $this->_processOpenAPI3Request($request, $content_array);\n        }\n\n        // 根据版本处理响应\n        if (strstr($swagger_version, '2.')) {\n            // 处理Swagger 2.0响应\n            $this->_processSwagger2Response($request, $content_array);\n        } else {\n            // 处理OpenAPI 3.0响应\n            $this->_processOpenAPI3Response($request, $content_array);\n        }\n\n        $return['page_content'] = json_encode($content_array);\n        return $return;\n    }\n\n    // 获取引用，返回数组。\n    //$ref_str 是swagger里引用的字符串，比如\"#/definitions/Petoo\",比如\"#/components/schemas/TenantArticleResult\"\n    private function _getDefinition($ref_str)\n    {\n        $json_array = $this->json_array;\n        $str_array = explode('/', $ref_str);\n\n        if ($str_array[2]) {\n            $target_array = $json_array[$str_array[1]][$str_array[2]];\n        }\n        if ($str_array[3]) {\n            $target_array = $json_array[$str_array[1]][$str_array[2]][$str_array[3]];\n        }\n\n        if ($target_array) {\n            return $target_array;\n        }\n        return false;\n    }\n\n    //把引用类型的数组转换成适合showdoc-runapi格式的描述\n    private function _definitionToJsonArray($ref_array)\n    {\n        $res = array();\n        // 检查属性是否存在\n        if (!isset($ref_array['properties'])) {\n            return $res;\n        }\n\n        foreach ($ref_array['properties'] as $key => $value) {\n            $remark = isset($value[\"title\"]) ? $value[\"title\"] : '';\n            $remark = isset($value[\"description\"]) ? $value[\"description\"] : $remark;\n\n            // 提取示例值\n            $example_value = '';\n            if (isset($value['example'])) {\n                $example_value = $value['example'];\n            }\n\n            // 确定参数是否必填\n            $required = '0';\n            if (isset($ref_array['required']) && is_array($ref_array['required']) && in_array($key, $ref_array['required'])) {\n                $required = '1';\n            }\n\n            // 修复int类型为integer\n            $param_type = isset($value[\"type\"]) ? $value[\"type\"] : 'string';\n            if ($param_type === 'int') {\n                $param_type = 'integer';\n            }\n\n            $res[] = array(\n                \"name\" => $key,\n                \"type\" => $param_type,\n                \"value\" => $example_value,\n                \"require\" => $required,\n                \"remark\" => $remark,\n            );\n\n            if (isset($value['properties'])) {\n                $tmp_json_array = $this->_definitionToJsonArray($value);\n                $res = array_merge($res, $tmp_json_array);\n            }\n            if (isset($value['items'])) {\n                $tmp_json_array = $this->_definitionToJsonArray($value['items']);\n                $res = array_merge($res, $tmp_json_array);\n            }\n        }\n\n        return $res;\n    }\n\n    // 把json数组转成纯json字符串\n    private function _jsonArrayToStr($json_array)\n    {\n\n\n        $res_array = $this->_toB($json_array);\n\n\n        return json_encode($res_array);\n    }\n\n    // 被_jsonArrayToStr调用\n    private function _toB($json_array)\n    {\n        $res_array = array();\n        if (isset($json_array['properties'])) {\n            foreach ($json_array['properties'] as $key => $value) {\n                $res_array[$key] = $this->_formatToFakeValue($value['type'] ?? 'string', $value['format'] ?? '');\n                // value 为数组的场景\n                if (isset($value['items'])) {\n                    $res_array[$key] = array($this->_toB($value['items']));\n                }\n                // value为object的场景\n                if (isset($value['properties'])) {\n                    $res_array[$key] = $this->_toB($value);\n                }\n            }\n        } else if (isset($json_array['$ref'])) {\n            $refData = $this->_getDefinition($json_array['$ref']);\n            if ($refData) {\n                $res_array = $this->_toB($refData);\n            }\n        } else if (isset($json_array['type']) && $json_array['type'] == 'array' && isset($json_array['items'])) {\n            $res_array = array($this->_toB($json_array['items']));\n        }\n        return $res_array;\n    }\n\n    // 根据字段format的要求类型，模拟一个数值。被_toB调用\n    private function _formatToFakeValue($type, $format)\n    {\n\n        switch ($format) {\n            case 'int64':\n                return 0;\n            case 'int32':\n                return 0;\n            case 'double':\n                return 0.00;\n            case 'date-time':\n                return date(\"Y-m-d H:i:s\");\n        }\n\n        switch ($type) {\n            case 'boolean':\n                return true;\n        }\n\n        // 如果上面没有retuan，则默认返回$type ;\n        return $type;\n    }\n\n\n    // 将引用改为真实数据\n    private function _transferDefinition($cur_array)\n    {\n        $json_array = $this->json_array;\n        foreach ($cur_array as $key => $value) {\n            if (is_array($value)) {\n                $cur_array[$key] = $this->_transferDefinition($value);\n                if ($value['$ref']) {\n                    $cur_array[$key] = $this->_getDefinition($value['$ref']);\n                }\n            }\n        }\n        return $cur_array;\n    }\n\n    // 处理OpenAPI 3.0的请求\n    private function _processOpenAPI3Request($request, &$content_array)\n    {\n        // 添加请求头处理\n        if (isset($request['headers'])) {\n            foreach ($request['headers'] as $header) {\n                $content_array['request']['headers'][] = array(\n                    \"name\" => $header[\"name\"],\n                    \"type\" => 'string',\n                    \"value\" => $header[\"value\"] ?? '',\n                    \"require\" => ($header[\"required\"] ?? false) ? '1' : '0',\n                    \"remark\" => $header[\"description\"] ?? '',\n                );\n            }\n        }\n\n        // 处理请求体\n        if (isset($request['requestBody']['content'])) {\n            $hasJsonContent = false;\n            $hasFormContent = false;\n\n            // 首先检查是否有application/json\n            if (isset($request['requestBody']['content']['application/json'])) {\n                $hasJsonContent = true;\n                $this->_processContentSchema($request['requestBody']['content']['application/json'], $content_array, 'json');\n            }\n\n            // 检查是否有x-www-form-urlencoded\n            if (!$hasJsonContent && isset($request['requestBody']['content']['application/x-www-form-urlencoded'])) {\n                $hasFormContent = true;\n                $this->_processContentSchema($request['requestBody']['content']['application/x-www-form-urlencoded'], $content_array, 'formdata');\n            }\n\n            // 检查是否有multipart/form-data\n            if (!$hasJsonContent && !$hasFormContent && isset($request['requestBody']['content']['multipart/form-data'])) {\n                $this->_processContentSchema($request['requestBody']['content']['multipart/form-data'], $content_array, 'formdata');\n            }\n\n            // 如果还没有处理过任何内容类型，尝试处理第一个找到的内容类型\n            if (!$hasJsonContent && !$hasFormContent) {\n                foreach ($request['requestBody']['content'] as $contentType => $content) {\n                    $mode = (strpos($contentType, 'json') !== false) ? 'json' : 'formdata';\n                    $this->_processContentSchema($content, $content_array, $mode);\n                    break;\n                }\n            }\n        }\n\n        // 处理参数\n        $this->_processParameters($request, $content_array);\n    }\n\n    // 处理内容schema\n    private function _processContentSchema($content, &$content_array, $mode)\n    {\n        // 设置模式\n        $content_array['request']['params']['mode'] = $mode;\n\n        if (isset($content['schema'])) {\n            $schema = $content['schema'];\n\n            // 如果是json模式，设置json字段\n            if ($mode === 'json' && (isset($schema['$ref']) || (isset($schema['type']) && $schema['type'] === 'object'))) {\n                $json_obj = $this->_toB($schema);\n                $content_array['request']['params']['json'] = json_encode($json_obj);\n\n                // 为JSON类型生成jsonDesc描述\n                if (!empty($json_obj)) {\n                    // 如果schema是引用类型，先解析引用\n                    $schema_for_desc = $schema;\n                    if (isset($schema['$ref'])) {\n                        $refData = $this->_getDefinition($schema['$ref']);\n                        if ($refData) {\n                            $schema_for_desc = $refData;\n                        }\n                    }\n                    $json_desc = $this->_definitionToJsonArray($schema_for_desc);\n                    $content_array['request']['params']['jsonDesc'] = $json_desc;\n                }\n            }\n\n            // 处理属性\n            if (isset($schema['properties'])) {\n                foreach ($schema['properties'] as $key => $value) {\n                    // 提取示例值\n                    $example_value = '';\n                    if (isset($value['example'])) {\n                        $example_value = $value['example'];\n                    }\n\n                    // 确定参数是否必填\n                    $required = '0';\n                    if (isset($schema['required']) && is_array($schema['required']) && in_array($key, $schema['required'])) {\n                        $required = '1';\n                    }\n\n                    // 如果是复杂对象类型，处理子属性\n                    if (isset($value['type']) && $value['type'] === 'object' && isset($value['properties'])) {\n                        $subProperties = $this->_definitionToJsonArray($value);\n                        foreach ($subProperties as $sub) {\n                            $content_array['request']['params']['formdata'][] = array(\n                                \"name\" => $key . '[' . $sub['name'] . ']',\n                                \"type\" => $sub['type'],\n                                \"value\" => $sub['value'] ?? $example_value,\n                                \"require\" => ($sub['require'] ?? false) ? '1' : '0',\n                                \"remark\" => $sub['remark'] ?? (isset($value[\"description\"]) ? $value[\"description\"] : ''),\n                            );\n                        }\n                    } else {\n                        // 添加普通参数\n                        $param_type = isset($value['type']) ? $value['type'] : 'string';\n                        // 修复int类型为integer\n                        if ($param_type === 'int') {\n                            $param_type = 'integer';\n                        }\n\n                        $content_array['request']['params']['formdata'][] = array(\n                            \"name\" => $key,\n                            \"type\" => $param_type,\n                            \"value\" => $example_value,\n                            \"require\" => $required,\n                            \"remark\" => $value[\"description\"] ?? '',\n                        );\n                    }\n                }\n            } else if (isset($schema['$ref'])) {\n                // 处理引用类型的schema\n                $refData = $this->_getDefinition($schema['$ref']);\n                if ($refData && isset($refData['properties'])) {\n                    foreach ($refData['properties'] as $key => $value) {\n                        // 提取示例值\n                        $example_value = '';\n                        if (isset($value['example'])) {\n                            $example_value = $value['example'];\n                        }\n\n                        // 确定参数是否必填\n                        $required = '0';\n                        if (isset($refData['required']) && is_array($refData['required']) && in_array($key, $refData['required'])) {\n                            $required = '1';\n                        }\n\n                        // 修复int类型为integer\n                        $param_type = isset($value['type']) ? $value['type'] : 'string';\n                        if ($param_type === 'int') {\n                            $param_type = 'integer';\n                        }\n\n                        $content_array['request']['params']['formdata'][] = array(\n                            \"name\" => $key,\n                            \"type\" => $param_type,\n                            \"value\" => $example_value,\n                            \"require\" => $required,\n                            \"remark\" => $value[\"description\"] ?? '',\n                        );\n                    }\n                }\n            }\n        }\n    }\n\n    // 处理Swagger 2.0的请求\n    private function _processSwagger2Request($request, &$content_array)\n    {\n        // 处理Swagger 2.0的请求体\n        if (isset($request['parameters'])) {\n            $hasBodyParam = false;\n            $bodySchema = null;\n\n            // 首先收集body参数\n            foreach ($request['parameters'] as $param) {\n                if ($param['in'] == 'body' && isset($param['schema'])) {\n                    $hasBodyParam = true;\n                    $bodySchema = $param['schema'];\n                    break;\n                }\n            }\n\n            // 处理body参数\n            if ($hasBodyParam && $bodySchema) {\n                // 如果Content-Type是application/json\n                if (isset($request['consumes']) && (in_array('application/json', $request['consumes']) || in_array('text/json', $request['consumes']))) {\n                    $content_array['request']['params']['mode'] = 'json';\n                    $json_obj = $this->_toB($bodySchema);\n                    $content_array['request']['params']['json'] = json_encode($json_obj);\n\n                    // 为JSON类型生成jsonDesc描述\n                    if (!empty($json_obj)) {\n                        // 如果schema是引用类型，先解析引用\n                        $schema_for_desc = $bodySchema;\n                        if (isset($bodySchema['$ref'])) {\n                            $refData = $this->_getDefinition($bodySchema['$ref']);\n                            if ($refData) {\n                                $schema_for_desc = $refData;\n                            }\n                        }\n                        $json_desc = $this->_definitionToJsonArray($schema_for_desc);\n                        $content_array['request']['params']['jsonDesc'] = $json_desc;\n                    }\n                }\n\n                // 如果schema是引用类型\n                if (isset($bodySchema['$ref'])) {\n                    $refData = $this->_getDefinition($bodySchema['$ref']);\n                    $this->_processSchemaProperties($refData, $content_array);\n                }\n                // 如果schema直接定义了属性\n                else if (isset($bodySchema['properties'])) {\n                    $this->_processSchemaProperties($bodySchema, $content_array);\n                }\n            }\n\n            // 处理formData参数\n            $hasFormDataParams = false;\n            foreach ($request['parameters'] as $param) {\n                if ($param['in'] == 'formData') {\n                    $hasFormDataParams = true;\n\n                    // 提取示例值\n                    $example_value = '';\n                    if (isset($param['example'])) {\n                        $example_value = $param['example'];\n                    }\n\n                    // 修复int类型为integer\n                    $param_type = isset($param['type']) ? $param['type'] : 'string';\n                    if ($param_type === 'int') {\n                        $param_type = 'integer';\n                    }\n\n                    $content_array['request']['params']['formdata'][] = array(\n                        \"name\" => $param[\"name\"],\n                        \"type\" => $param_type,\n                        \"value\" => $example_value,\n                        \"require\" => ($param[\"required\"] ?? false) ? '1' : '0',\n                        \"remark\" => $param[\"description\"] ?? '',\n                    );\n                }\n            }\n\n            // 如果没有body参数，但有formData参数，设置mode为formdata\n            if (!$hasBodyParam && $hasFormDataParams) {\n                $content_array['request']['params']['mode'] = 'formdata';\n            }\n        }\n\n        // 处理参数\n        $this->_processParameters($request, $content_array);\n    }\n\n    // 处理schema的属性\n    private function _processSchemaProperties($schema, &$content_array)\n    {\n        if (isset($schema['properties'])) {\n            foreach ($schema['properties'] as $key => $value) {\n                // 提取示例值\n                $example_value = '';\n                if (isset($value['example'])) {\n                    $example_value = $value['example'];\n                }\n\n                // 确定参数是否必填\n                $required = '0';\n                if (isset($schema['required']) && is_array($schema['required']) && in_array($key, $schema['required'])) {\n                    $required = '1';\n                }\n\n                // 修复int类型为integer\n                $param_type = isset($value['type']) ? $value['type'] : 'string';\n                if ($param_type === 'int') {\n                    $param_type = 'integer';\n                }\n\n                $content_array['request']['params']['formdata'][] = array(\n                    \"name\" => $key,\n                    \"type\" => $param_type,\n                    \"value\" => $example_value,\n                    \"require\" => $required,\n                    \"remark\" => $value[\"description\"] ?? '',\n                );\n            }\n        }\n    }\n\n    // 处理共用的参数（query和header）\n    private function _processParameters($request, &$content_array)\n    {\n        // 处理查询参数\n        if (isset($request['parameters'])) {\n            foreach ($request['parameters'] as $param) {\n                if ($param['in'] == 'query') {\n                    // 提取示例值\n                    $example_value = '';\n                    if (isset($param['example'])) {\n                        $example_value = $param['example'];\n                    }\n\n                    // 修复int类型为integer\n                    $param_type = isset($param['type']) ? $param['type'] : 'string';\n                    if ($param_type === 'int') {\n                        $param_type = 'integer';\n                    }\n\n                    $content_array['request']['query'][] = array(\n                        \"name\" => $param[\"name\"],\n                        \"type\" => $param_type,\n                        \"value\" => $example_value,\n                        \"require\" => ($param[\"required\"] ?? false) ? '1' : '0',\n                        \"remark\" => $param[\"description\"] ?? '',\n                    );\n                }\n\n                // 处理header\n                if ($param['in'] == 'header') {\n                    $content_array['request']['headers'][] = array(\n                        \"name\" => $param[\"name\"],\n                        \"type\" => \"string\",\n                        \"value\" => $param[\"example\"] ?? '',\n                        \"require\" => ($param[\"required\"] ?? false) ? '1' : '0',\n                        \"remark\" => $param[\"description\"] ?? '',\n                    );\n                }\n\n                // 处理path参数，添加到URL中\n                if ($param['in'] == 'path' && isset($content_array['info']['url'])) {\n                    // URL中的路径参数保持原样，不需要替换\n                }\n            }\n        }\n    }\n\n    // 处理Swagger 2.0的响应\n    private function _processSwagger2Response($request, &$content_array)\n    {\n        if (isset($request['responses']) && isset($request['responses']['200'])) {\n            $ref_array = array();\n            $example = null;\n\n            // 检查OpenAPI 3.0 格式中的example\n            if (isset($request['responses']['200']['content'])) {\n                foreach ($request['responses']['200']['content'] as $contentType => $content) {\n                    // 检查example字段\n                    if (isset($content['example'])) {\n                        $example = $content['example'];\n                        break;\n                    }\n\n                    // 检查schema中的example\n                    if (isset($content['schema']) && isset($content['schema']['example'])) {\n                        $example = $content['schema']['example'];\n                        break;\n                    }\n                }\n            }\n\n            // 检查是否有examples（Swagger 2.0格式）\n            if (!$example && isset($request['responses']['200']['examples'])) {\n                foreach ($request['responses']['200']['examples'] as $contentType => $content) {\n                    $example = $content;\n                    break;\n                }\n            }\n\n            // 检查schema\n            if (isset($request['responses']['200']['schema'])) {\n                $ref_array = $request['responses']['200']['schema'];\n\n                // 检查schema中是否有example\n                if (!$example && isset($ref_array['example'])) {\n                    $example = $ref_array['example'];\n                }\n            }\n\n            // 处理example - 主要针对example是字符串类型的情况\n            if ($example !== null) {\n                // 如果example是字符串且看起来是JSON格式\n                if (is_string($example)) {\n                    // 先移除转义字符\n                    $unescaped_example = stripslashes($example);\n\n                    // 检查是否是JSON字符串\n                    if ((substr($unescaped_example, 0, 1) === '{' || substr($unescaped_example, 0, 1) === '[') &&\n                        json_decode($unescaped_example) !== null\n                    ) {\n                        // 是有效的JSON字符串，解码后使用\n                        $content_array['response']['responseExample'] = $unescaped_example;\n\n                        // 尝试解析JSON并从中生成参数描述\n                        $parsed_example = json_decode($unescaped_example, true);\n                        if (json_last_error() === JSON_ERROR_NONE) {\n                            $content_array['response']['responseParamsDesc'] = $this->_exampleToParamsDesc($parsed_example);\n                        }\n                    } else {\n                        // 不是JSON格式的字符串，直接使用\n                        $content_array['response']['responseExample'] = $example;\n                    }\n                } else {\n                    // example是数组或对象\n                    $content_array['response']['responseExample'] = json_encode($example);\n                    $content_array['response']['responseParamsDesc'] = $this->_exampleToParamsDesc($example);\n                }\n            }\n            // 否则使用schema\n            else if (!empty($ref_array)) {\n                $json_array = $this->_definitionToJsonArray($ref_array);\n                $json_str = $this->_jsonArrayToStr($ref_array);\n                $content_array['response']['responseExample'] = $json_str;\n                $content_array['response']['responseParamsDesc'] = $json_array;\n            } else {\n                // 设置一个空对象作为返回示例\n                $content_array['response']['responseExample'] = '{}';\n                $content_array['response']['responseParamsDesc'] = array();\n            }\n        }\n    }\n\n    // 处理OpenAPI 3.0的响应\n    private function _processOpenAPI3Response($request, &$content_array)\n    {\n        if (isset($request['responses']) && isset($request['responses']['200'])) {\n            $ref_array = array();\n            $example = null;\n\n            if (isset($request['responses']['200']['content'])) {\n                foreach ($request['responses']['200']['content'] as $contentType => $content) {\n                    // 1. 优先检查examples对象（OpenAPI 3.0规范）\n                    if (isset($content['examples']) && !empty($content['examples'])) {\n                        // 提取第一个example的value\n                        foreach ($content['examples'] as $exampleKey => $exampleObj) {\n                            if (isset($exampleObj['value'])) {\n                                $example = $exampleObj['value'];\n                                break;\n                            }\n                        }\n                        if ($example !== null) {\n                            break;\n                        }\n                    }\n\n                    // 2. 检查单独的example字段\n                    if (isset($content['example'])) {\n                        $example = $content['example'];\n                        break;\n                    }\n\n                    // 3. 检查schema中的example\n                    if (isset($content['schema']) && isset($content['schema']['example'])) {\n                        $example = $content['schema']['example'];\n                        break;\n                    }\n\n                    if (isset($content['schema'])) {\n                        $ref_array = $content['schema'];\n                    }\n                }\n            }\n\n            // 处理example - 主要针对example是字符串类型的情况\n            if ($example !== null) {\n                // 如果example是字符串且看起来是JSON格式\n                if (is_string($example)) {\n                    // 先移除转义字符\n                    $unescaped_example = stripslashes($example);\n\n                    // 检查是否是JSON字符串\n                    if ((substr($unescaped_example, 0, 1) === '{' || substr($unescaped_example, 0, 1) === '[') &&\n                        json_decode($unescaped_example) !== null\n                    ) {\n                        // 是有效的JSON字符串，解码后使用\n                        $content_array['response']['responseExample'] = $unescaped_example;\n\n                        // 尝试解析JSON并从中生成参数描述\n                        $parsed_example = json_decode($unescaped_example, true);\n                        if (json_last_error() === JSON_ERROR_NONE) {\n                            $content_array['response']['responseParamsDesc'] = $this->_exampleToParamsDesc($parsed_example);\n                        } else if (!empty($ref_array)) {\n                            $json_array = $this->_definitionToJsonArray($ref_array);\n                            $content_array['response']['responseParamsDesc'] = $json_array;\n                        }\n                    } else {\n                        // 不是JSON格式的字符串，直接使用\n                        $content_array['response']['responseExample'] = $example;\n                        if (!empty($ref_array)) {\n                            $json_array = $this->_definitionToJsonArray($ref_array);\n                            $content_array['response']['responseParamsDesc'] = $json_array;\n                        }\n                    }\n                } else {\n                    // example是数组或对象\n                    $content_array['response']['responseExample'] = json_encode($example);\n                    if (is_array($example) || is_object($example)) {\n                        $content_array['response']['responseParamsDesc'] = $this->_exampleToParamsDesc($example);\n                    } else if (!empty($ref_array)) {\n                        $json_array = $this->_definitionToJsonArray($ref_array);\n                        $content_array['response']['responseParamsDesc'] = $json_array;\n                    }\n                }\n            }\n            // 否则使用schema\n            else if (!empty($ref_array)) {\n                $json_array = $this->_definitionToJsonArray($ref_array);\n                $json_str = $this->_jsonArrayToStr($ref_array);\n                $content_array['response']['responseExample'] = $json_str;\n                $content_array['response']['responseParamsDesc'] = $json_array;\n            } else {\n                // 设置一个空对象作为返回示例\n                $content_array['response']['responseExample'] = '{}';\n                $content_array['response']['responseParamsDesc'] = array();\n            }\n        }\n    }\n\n    // 将example转换为参数描述\n    private function _exampleToParamsDesc($example, $parentKey = '')\n    {\n        $res = array();\n\n        if (is_array($example)) {\n            foreach ($example as $key => $value) {\n                $fullKey = $parentKey ? $parentKey . '.' . $key : $key;\n\n                if (is_array($value)) {\n                    // 如果是数组且第一个元素是数组或对象，则递归处理\n                    if (!empty($value) && (is_array(reset($value)) || is_object(reset($value)))) {\n                        $childParams = $this->_exampleToParamsDesc(reset($value), $fullKey);\n                        $res = array_merge($res, $childParams);\n                    } else {\n                        $res[] = array(\n                            \"name\" => $fullKey,\n                            \"type\" => \"array\",\n                            \"value\" => '',\n                            \"require\" => '0',\n                            \"remark\" => '',\n                        );\n\n                        // 处理数组中的子项\n                        $childParams = $this->_exampleToParamsDesc($value, $fullKey);\n                        $res = array_merge($res, $childParams);\n                    }\n                } else {\n                    $res[] = array(\n                        \"name\" => $fullKey,\n                        \"type\" => $this->_getTypeFromValue($value),\n                        \"value\" => '',\n                        \"require\" => '0',\n                        \"remark\" => '',\n                    );\n                }\n            }\n        }\n\n        return $res;\n    }\n\n    // 根据值获取类型\n    private function _getTypeFromValue($value)\n    {\n        if (is_null($value)) return 'null';\n        if (is_bool($value)) return 'boolean';\n        if (is_int($value)) return 'integer';\n        if (is_float($value)) return 'number';\n        if (is_string($value)) return 'string';\n        if (is_array($value)) return 'array';\n        if (is_object($value)) return 'object';\n\n        return 'string';\n    }\n}\n"
  },
  {
    "path": "server/Application/Api/Controller/ItemController.class.php",
    "content": "<?php\n\nnamespace Api\\Controller;\n\nuse Think\\Controller;\n\nclass ItemController extends BaseController\n{\n\n\n    //单个项目信息\n    public function info()\n    {\n        $this->checkLogin(false);\n        $item_id = I(\"item_id/s\");\n        $item_domain = I(\"item_domain/s\");\n        $current_page_id = I(\"page_id/d\");\n        if (!is_numeric($item_id)) {\n            $item_domain = $item_id;\n        }\n        //判断个性域名\n        if ($item_domain) {\n            $item = D(\"Item\")->where(\"item_domain = '%s'\", array($item_domain))->find();\n            if ($item['item_id']) {\n                $item_id = $item['item_id'];\n            }\n        }\n        $login_user = session(\"login_user\");\n        $uid = $login_user['uid'] ? $login_user['uid'] : 0;\n\n        if (!$this->checkItemVisit($uid, $item_id)) {\n            $this->sendError(10303);\n            return;\n        }\n\n        $item = D(\"Item\")->where(\"item_id = '%d' \", array($item_id))->find();\n        if (!$item || $item['is_del'] == 1) {\n            sleep(1);\n            $this->sendError(10101, '项目不存在或者已删除');\n            return false;\n        }\n        //从2020.7.5开始，常规项目和单页项目合并在一起返回\n        $this->_show_regular_item($item);\n    }\n\n    //展示常规项目\n    private function _show_regular_item($item)\n    {\n        $item_id = $item['item_id'];\n\n        $default_page_id = I(\"default_page_id/d\");\n        $current_page_id = I(\"page_id/d\");\n        $keyword = I(\"keyword\");\n        $filter_status = I(\"filter_status\"); // 新增：状态筛选参数，格式：开发中,测试中,已完成\n        $showMD = I(\"show_md/d\", 1); // 新增：是否显示markdown文档，1显示，0不显示\n        $default_cat_id2 = $default_cat_id3 = 0;\n\n        $login_user = session(\"login_user\");\n        $uid = $login_user['uid'] ? $login_user['uid'] : 0;\n        $is_login =   $uid > 0 ? true : false;\n\n        $force_login = D(\"Options\")->get(\"force_login\");\n        if($force_login > 0 ){\n            // 如果管理员设置了强制登录，则对 未登录的游客 返回未登录状态\n            if(!$is_login){\n                $this->sendError(10312);\n                return ;\n            }\n        }\n        $menu = array(\n            \"pages\" => array(),\n            \"catalogs\" => array(),\n        );\n        //是否有搜索词\n        if ($keyword) {\n            $keyword = strtolower($keyword);\n            // 如果用户被分配了 目录权限 ，则获取他在该项目下拥有权限的目录id集合\n            $cat_ids = D(\"Member\")->getCatIds($item_id, $uid);\n            $menu['pages'] = $pages = D(\"Page\")->search($item_id, $cat_ids, $keyword);\n            $menu['pages'] = $pages ? $pages : array();\n            $menu['catalogs'] = array();\n        } else {\n            $menu = D(\"Item\")->getMemu($item_id);\n            if ($uid > 0) {\n                $menu = D(\"Item\")->filteMemberItem($uid, $item_id, $menu);\n            }\n        }\n\n        // 应用筛选条件\n        if ($filter_status || !$showMD) {\n            $menu = $this->applyFilters($menu, $filter_status, $showMD, $item_id);\n        }\n\n        $domain = $item['item_domain'] ? $item['item_domain'] : $item['item_id'];\n\n        $item_edit = $this->checkItemEdit($uid, $item_id);\n\n        $item_manage = $this->checkItemManage($uid, $item_id);\n\n        //如果带了默认展开的页面id，则获取该页面所在的二级目录/三级目录/四级目录\n        if ($default_page_id) {\n            $page = D(\"Page\")->where(array('page_id' => $default_page_id))->find();\n            if ($page) {\n                $default_cat_id4 = $page['cat_id'];\n                $cat1 = D(\"Catalog\")->where(\" cat_id = '%d' and parent_cat_id > 0  \", array($default_cat_id4))->find();\n                if ($cat1) {\n                    $default_cat_id3 = $cat1['parent_cat_id'];\n                } else {\n                    $default_cat_id3 = $default_cat_id4;\n                    $default_cat_id4 = 0;\n                }\n\n                $cat2 = D(\"Catalog\")->where(\" cat_id = '%d' and parent_cat_id > 0  \", array($default_cat_id3))->find();\n                if ($cat2) {\n                    $default_cat_id2 = $cat2['parent_cat_id'];\n                } else {\n                    $default_cat_id2 = $default_cat_id3;\n                    $default_cat_id3 = 0;\n                }\n            }\n        }\n\n        if (LANG_SET == 'en-us') {\n            $help_url = \"https://www.showdoc.cc/help-en\";\n        } else {\n            $help_url = \"https://www.showdoc.cc/help\";\n        }\n\n        //当已经归档了，则去掉编辑权限\n        if ($item['is_archived']) {\n            $item_edit = $item_manage = false;\n        }\n\n        //如果项目类型为runapi，则获取看看有没有全局参数\n        $global_param = array();\n        if ($item['item_type'] == 3) {\n            $global_param = D(\"Runapi\")->getGlobalParam($item_id);\n        }\n\n        // 登录的状态下，才去检查下是否开启了水印\n        if ($is_login) { //少了个$ if(is_login)\n            $show_watermark = D(\"Options\")->get(\"show_watermark\");\n            $show_watermark = $show_watermark ? '1' : '0';\n        } else {\n            $unread_count = 0;\n        }\n\n\n        $return = array(\n            \"item_id\" => $item_id,\n            \"item_domain\" => $item['item_domain'],\n            \"is_archived\" => $item['is_archived'],\n            \"item_name\" => $item['item_name'],\n            \"default_page_id\" => (string)$default_page_id,\n            \"default_cat_id2\" => $default_cat_id2,\n            \"default_cat_id3\" => $default_cat_id3,\n            \"default_cat_id4\" => $default_cat_id4,\n            \"unread_count\" => $unread_count,\n            \"item_type\" => $item['item_type'],\n            \"menu\" => $menu,\n            \"is_login\" => $is_login,\n            \"item_edit\" => $item_edit,\n            \"item_manage\" => $item_manage,\n            \"ItemPermn\" => $item_edit, // ItemPermn 和 ItemCreator这两个字段是为了兼容历史。确保各大客户端(web/手机/runapi)改用字段后可以去掉\n            \"ItemCreator\" => $item_manage,\n            \"current_page_id\" => $current_page_id,\n            \"global_param\" => $global_param,\n            \"show_watermark\" => $show_watermark,\n            \"allow_comment\" => isset($item['allow_comment']) ? (int)$item['allow_comment'] : 0,\n            \"allow_feedback\" => isset($item['allow_feedback']) ? (int)$item['allow_feedback'] : 0,\n        );\n\n        // 获取 AI 知识库配置\n        $ai_config = D(\"ItemAiConfig\")->getConfig($item_id);\n        $return[\"ai_knowledge_base_enabled\"] = $ai_config['enabled']; // 保持向后兼容\n        $return[\"ai_config\"] = $ai_config; // 新增完整配置\n\n        $this->sendResult($return);\n    }\n\n\n    //我的项目列表\n    public function myList()\n    {\n        $login_user = $this->checkLogin();\n        $original = I(\"original/d\") ? I(\"original/d\") : 0; //1：只返回自己原创的项目;默认是0 \n        $item_group_id = I(\"item_group_id/d\") ? I(\"item_group_id/d\") : 0; //项目分组id。默认是0,即所有项目。当为-1的时候，表示返回标星项目\n        $where = \"uid = '$login_user[uid]' \";\n        $member_item_ids = array(-1); // 所有 只读和编辑成员 的项目\n        $manage_member_item_ids = array(-1); // 所有拥有项目管理权限的成员的项目\n\n        $item_members = D(\"ItemMember\")->where(\"uid = '%d' and  member_group_id != '2' \", array($login_user['uid']))->select();\n        if ($item_members) {\n            foreach ($item_members as $key => $value) {\n                $member_item_ids[] = $value['item_id'];\n            }\n        }\n        $team_item_members = D(\"TeamItemMember\")->where(\"member_uid = '%d' and  member_group_id != '2' \", array($login_user['uid']))->select();\n        if ($team_item_members) {\n            foreach ($team_item_members as $key => $value) {\n                $member_item_ids[] = $value['item_id'];\n            }\n        }\n\n        $item_members = D(\"ItemMember\")->where(\"uid = '%d' and  member_group_id = '2' \", array($login_user['uid']))->select();\n        if ($item_members) {\n            foreach ($item_members as $key => $value) {\n                $manage_member_item_ids[] = $value['item_id'];\n            }\n        }\n        $team_item_members = D(\"TeamItemMember\")->where(\"member_uid = '%d' and  member_group_id = '2' \", array($login_user['uid']))->select();\n        if ($team_item_members) {\n            foreach ($team_item_members as $key => $value) {\n                $manage_member_item_ids[] = $value['item_id'];\n            }\n        }\n\n\n        $where .= \" or item_id in ( \" . implode(\",\", $member_item_ids) . \" ) \";\n        $where .= \" or item_id in ( \" . implode(\",\", $manage_member_item_ids) . \" ) \";\n        if ($item_group_id > 0) {\n            $res = D(\"ItemGroup\")->where(array('id' => $item_group_id))->find();\n            if ($res && $res['item_ids']) {\n                $where = \" ({$where}) and item_id in ({$res['item_ids']}) \";\n            } else {\n                $where = \" ({$where}) and item_id in (-1) \";\n            }\n        }\n\n        $star_item_id_array = array();\n        // 将star的项目都先读取出来，因为后面有两处需要用到：返回项目是否已经被标星字段，根据标星返回所有标星项目\n        $res = D(\"ItemStar\")->where(array('uid' => $login_user['uid']))->select();\n\n        if ($res) {\n            foreach ($res as $key => $value) {\n                $star_item_id_array[] = intval($value['item_id']);\n            }\n        }\n\n        // 当强等于-1的时候。表示筛选出星标项目\n        if ($item_group_id === -1) {\n            if ($star_item_id_array) {\n                $star_item_ids = implode(\",\", $star_item_id_array);\n                $where = \" ({$where}) and item_id in ({$star_item_ids}) \";\n            } else {\n                $where = \" ({$where}) and item_id in (0) \";\n            }\n        }\n\n        $items  = D(\"Item\")->field(\"item_id,uid,item_name,item_domain,item_type,last_update_time,item_description,is_del,password\")->where($where)->order(\"item_id asc\")->select();\n\n\n        foreach ($items as $key => $value) {\n            $items[$key]['s_number'] = 0;\n            if ($value['uid'] == $login_user['uid']) {\n                $items[$key]['creator'] = 1;\n                $items[$key]['manage'] = 1;\n            } else if (in_array($value['item_id'], $manage_member_item_ids)) {\n                $items[$key]['creator'] = 0;\n                $items[$key]['manage'] = 1;\n            } else {\n                $items[$key]['creator'] = 0;\n                $items[$key]['manage'] = 0;\n                unset($items[$key]['password']);\n            }\n            //判断是否为私密项目\n            if ($value['password']) {\n                $items[$key]['is_private'] = 1;\n            } else {\n                $items[$key]['is_private'] = 0;\n            }\n\n            //如果项目已标识为删除\n            if ($value['is_del'] == 1) {\n                unset($items[$key]);\n                continue;\n            }\n\n            //如果有参数指定了只返回原创项目\n            if ($original > 0 && $value['uid'] != $login_user['uid']) {\n                unset($items[$key]);\n                continue;\n            }\n            // 判断项目是否被标星\n            if (in_array(intval($value['item_id']), $star_item_id_array)) {\n                $items[$key]['is_star'] = 1;\n            } else {\n                $items[$key]['is_star'] = 0;\n            }\n        }\n        $items = array_values($items);\n        //读取需要置顶的项目\n        $top_items = D(\"ItemTop\")->where(array('uid' => $login_user['uid']))->select();\n        if ($top_items) {\n            $top_item_ids = array();\n            foreach ($top_items as $key => $value) {\n                $top_item_ids[] = $value['item_id'];\n            }\n            foreach ($items as $key => $value) {\n                $items[$key]['top'] = 0;\n                if (in_array($value['item_id'], $top_item_ids)) {\n                    $items[$key]['top'] = 1;\n                    $tmp = $items[$key];\n                    unset($items[$key]);\n                    array_unshift($items, $tmp);\n                }\n            }\n        }\n\n        //读取项目顺序\n        $item_sort = D(\"ItemSort\")->where(\"uid = '%d'  and item_group_id = '%d' \", array($login_user['uid'], $item_group_id))->find();\n        if ($item_sort) {\n            $item_sort_data = json_decode(htmlspecialchars_decode($item_sort['item_sort_data']), true);\n            //var_dump($item_sort_data);\n            foreach ($items as $key => &$value) {\n                //如果item_id有设置了序号，则赋值序号。没有则默认填上项目id\n                if ($item_sort_data[$value['item_id']]) {\n                    $value['s_number'] = $item_sort_data[$value['item_id']];\n                } else {\n                    $value['s_number'] = $value['item_id'];\n                }\n            }\n            $items = $this->_sort_by_key($items, 's_number');\n        }\n\n\n        $items = $items ? array_values($items) : array();\n        $this->sendResult($items);\n    }\n\n    private function _sort_by_key($array, $mykey)\n    {\n        for ($i = 0; $i < count($array); $i++) {\n            for ($j = $i + 1; $j < count($array); $j++) {\n                if ($array[$i][$mykey] > $array[$j][$mykey]) {\n                    $tmp = $array[$i];\n                    $array[$i] = $array[$j];\n                    $array[$j] = $tmp;\n                }\n            }\n        }\n        return $array;\n    }\n\n    //项目详情\n    public function detail()\n    {\n        $login_user = $this->checkLogin();\n        $item_id = I(\"item_id/d\");\n        $uid = $login_user['uid'];\n        if (!$this->checkItemManage($uid, $item_id)) {\n            $this->sendError(10303);\n            return;\n        }\n        $items  = D(\"Item\")->where(\"item_id = '%d' \", array($item_id))->find();\n        // 返回项目所属分组（多选）\n        $group_ids = array();\n        $groups = D(\"ItemGroup\")->where(\" uid = '%d' \", array($uid))->select();\n        if ($groups) {\n            foreach ($groups as $g) {\n                if (!empty($g['item_ids'])) {\n                    $ids = explode(',', $g['item_ids']);\n                    if (in_array((string)$item_id, $ids) || in_array((int)$item_id, array_map('intval', $ids))) {\n                        $group_ids[] = intval($g['id']);\n                    }\n                }\n            }\n        }\n        $items['group_ids'] = $group_ids;\n        $items = $items ? $items : array();\n        $this->sendResult($items);\n    }\n\n    //更新项目信息\n    public function update()\n    {\n        $login_user = $this->checkLogin();\n        $item_id = I(\"post.item_id/d\");\n        $item_name = I(\"item_name\");\n        $item_description = I(\"item_description\");\n        $item_domain = I(\"item_domain\");\n        $password = I(\"password\");\n        // 多分组支持\n        $item_group_id = I(\"item_group_id/d\") ? I(\"item_group_id/d\") : 0;\n        $item_group_ids_raw = I(\"item_group_ids\");\n        $uid = $login_user['uid'];\n        if (!$this->checkItemManage($uid, $item_id)) {\n            $this->sendError(10303);\n            return;\n        }\n\n        if ($item_domain) {\n\n            if (!ctype_alnum($item_domain) ||  is_numeric($item_domain)) {\n                //echo '个性域名只能是字母或数字的组合';exit;\n                $this->sendError(10305);\n                return false;\n            }\n\n            $item = D(\"Item\")->where(\"item_domain = '%s' and item_id !='%s' \", array($item_domain, $item_id))->find();\n            if ($item) {\n                //个性域名已经存在\n                $this->sendError(10304);\n                return false;\n            }\n        }\n        $save_data = array(\n            \"item_name\" => $item_name,\n            \"item_description\" => $item_description,\n            \"item_domain\" => $item_domain,\n            \"password\" => $password,\n        );\n        // 处理评论和反馈功能开关（仅常规项目）\n        $allow_comment = I(\"allow_comment/d\");\n        $allow_feedback = I(\"allow_feedback/d\");\n        if ($item_info = D(\"Item\")->where(\"item_id = '%d' \", array($item_id))->find()) {\n            if ($item_info['item_type'] == 1) {\n                // 常规项目才支持评论和反馈功能\n                if ($allow_comment !== null) {\n                    $save_data['allow_comment'] = $allow_comment ? 1 : 0;\n                }\n                if ($allow_feedback !== null) {\n                    $save_data['allow_feedback'] = $allow_feedback ? 1 : 0;\n                }\n            }\n        }\n        $items  = D(\"Item\")->where(\"item_id = '%d' \", array($item_id))->save($save_data);\n        // 同步分组\n        $selected_group_ids = array();\n        if (!empty($item_group_ids_raw)) {\n            if (is_array($item_group_ids_raw)) {\n                $selected_group_ids = $item_group_ids_raw;\n            } else {\n                $tmp = json_decode(htmlspecialchars_decode($item_group_ids_raw), true);\n                if (is_array($tmp)) {\n                    $selected_group_ids = $tmp;\n                } else {\n                    $selected_group_ids = explode(',', strval($item_group_ids_raw));\n                }\n            }\n        } elseif ($item_group_id > 0) {\n            $selected_group_ids = array($item_group_id);\n        }\n        $selected_group_ids = array_values(array_unique(array_filter(array_map('intval', $selected_group_ids))));\n        if (!empty($selected_group_ids) || $item_group_id === 0) {\n            $groups = D(\"ItemGroup\")->where(\" uid = '%d' \", array($uid))->select();\n            if ($groups) {\n                foreach ($groups as $g) {\n                    $g_id = intval($g['id']);\n                    $ids = array();\n                    if (!empty($g['item_ids'])) {\n                        $ids = array_values(array_unique(array_filter(array_map('intval', explode(',', $g['item_ids'])))));\n                    }\n                    if (in_array($g_id, $selected_group_ids)) {\n                        if (!in_array($item_id, $ids)) {\n                            $ids[] = $item_id;\n                            $new_item_ids = implode(',', $ids);\n                            D(\"ItemGroup\")->where(\" id = '%d' and uid = '%d' \", array($g_id, $uid))->save(['item_ids' => $new_item_ids]);\n                        }\n                    } else {\n                        if (!empty($ids) && in_array($item_id, $ids)) {\n                            $ids = array_values(array_diff($ids, array($item_id)));\n                            $new_item_ids = implode(',', $ids);\n                            D(\"ItemGroup\")->where(\" id = '%d' and uid = '%d' \", array($g_id, $uid))->save(['item_ids' => $new_item_ids]);\n                        }\n                    }\n                }\n            }\n        }\n        $items = $items ? $items : array();\n        $this->sendResult($items);\n    }\n\n    //转让项目\n    public function attorn()\n    {\n        $login_user = $this->checkLogin();\n\n        $username = I(\"username\");\n        $item_id = I(\"post.item_id/d\");\n        $password = I(\"post.password\");\n\n        $item  = D(\"Item\")->where(array('item_id' => $item_id))->find();\n\n        if (!$this->checkItemManage($login_user['uid'], $item['item_id'])) {\n            $this->sendError(10303);\n            return;\n        }\n\n        if (!D(\"User\")->checkLogin($item['username'], $password)) {\n            $this->sendError(10208);\n            return;\n        }\n\n        $member = D(\"User\")->where(array('username' => $username))->find();\n\n        if (!$member) {\n            $this->sendError(10209);\n            return;\n        }\n\n        $data['username'] = $member['username'];\n        $data['uid'] = $member['uid'];\n\n\n        $id = D(\"Item\")->where(array('item_id' => $item_id))->save($data);\n\n        $return = D(\"Item\")->where(array('item_id' => $item_id))->find();\n\n        if (!$return) {\n            $this->sendError(10101);\n        }\n\n        $this->sendResult($return);\n    }\n\n    //删除项目\n    public function delete()\n    {\n        $login_user = $this->checkLogin();\n\n        $item_id = I(\"item_id/d\");\n        $password = I(\"password\");\n\n        $item  = D(\"Item\")->where(array('item_id' => $item_id))->find();\n\n        if (!$this->checkItemManage($login_user['uid'], $item['item_id'])) {\n            $this->sendError(10303);\n            return;\n        }\n\n        if (!D(\"User\")->checkLogin($item['username'], $password)) {\n            $this->sendError(10208);\n            return;\n        }\n\n        // 删除项目相关的评论和反馈\n        D(\"PageComment\")->where(\"item_id = %d\", array($item_id))->delete();\n        D(\"PageFeedback\")->where(\"item_id = %d\", array($item_id))->delete();\n\n        $return = D(\"Item\")->soft_delete_item($item_id);\n\n        if (!$return) {\n            $this->sendError(10101);\n        } else {\n        }\n\n        $this->sendResult($return);\n    }\n    //归档项目\n    public function archive()\n    {\n        $login_user = $this->checkLogin();\n\n        $item_id = I(\"post.item_id/d\");\n        $password = I(\"password\");\n\n        $item  = D(\"Item\")->where(array('item_id' => $item_id))->find();\n\n        if (!$this->checkItemManage($login_user['uid'], $item['item_id'])) {\n            $this->sendError(10303);\n            return;\n        }\n\n        if (!D(\"User\")->checkLogin($item['username'], $password)) {\n            $this->sendError(10208);\n            return;\n        }\n\n        $return = D(\"Item\")->where(array('item_id' => $item_id))->save(array(\"is_archived\" => 1));\n\n        if (!$return) {\n            $this->sendError(10101);\n        } else {\n            $this->sendResult($return);\n        }\n    }\n    public function getKey()\n    {\n        $login_user = $this->checkLogin();\n\n        $item_id = I(\"item_id/d\");\n\n        $item  = D(\"Item\")->where(array('item_id' => $item_id))->find();\n\n        if (!$this->checkItemManage($login_user['uid'], $item['item_id'])) {\n            $this->sendError(10303);\n            return;\n        }\n\n        $item_token  = D(\"ItemToken\")->getTokenByItemId($item_id);\n        if (!$item_token) {\n            $this->sendError(10101);\n        }\n        $this->sendResult($item_token);\n    }\n\n    public function resetKey()\n    {\n\n        $login_user = $this->checkLogin();\n\n        $item_id = I(\"post.item_id/d\");\n\n        $item  = D(\"Item\")->where(array('item_id' => $item_id))->find();\n\n        if (!$this->checkItemManage($login_user['uid'], $item['item_id'])) {\n            $this->sendError(10303);\n            return;\n        }\n\n        $item_token = D(\"ItemToken\")->resetToken($item_id);\n\n        if ($item_token) {\n            $this->sendResult($item_token);\n        } else {\n            $this->sendError(10101);\n        }\n    }\n\n    public function updateByApi()\n    {\n        //转到Open控制器的updateItem方法\n        R('Open/updateItem');\n    }\n\n    //置顶项目\n    public function top()\n    {\n        $login_user = $this->checkLogin();\n\n        $item_id = I(\"item_id/d\");\n        $action = I(\"action\");\n\n        if ($action == 'top') {\n            $ret = D(\"ItemTop\")->add(array(\"item_id\" => $item_id, \"uid\" => $login_user['uid'], \"addtime\" => time()));\n        } elseif ($action == 'cancel') {\n            $ret = D(\"ItemTop\")->where(\" uid = '%d' and item_id = '%d' \", array($login_user['uid'], $item_id))->delete();\n        }\n        if ($ret) {\n            $this->sendResult(array());\n        } else {\n            $this->sendError(10101);\n        }\n    }\n\n    //验证访问密码\n    public function pwd()\n    {\n        $item_id = I(\"item_id\");\n        $page_id = I(\"page_id/d\");\n        $password = I(\"password\");\n        $refer_url = I('refer_url');\n        $captcha_id = I(\"captcha_id\");\n        $captcha = I(\"captcha\");\n\n        if (!D(\"Captcha\")->check($captcha_id, $captcha)) {\n            $this->sendError(10206, L('verification_code_are_incorrect'));\n            return;\n        }\n\n        if (!is_numeric($item_id)) {\n            $item_domain = $item_id;\n        }\n        //判断个性域名\n        if ($item_domain) {\n            $item = D(\"Item\")->where(\"item_domain = '%s'\", array($item_domain))->find();\n            if ($item['item_id']) {\n                $item_id = $item['item_id'];\n            }\n        }\n\n        // $item_id 已在上方通过 is_numeric 与后续查询使用 %d 占位符保障\n\n        if ($page_id > 0) {\n            $page = M(\"Page\")->where(array('page_id' => $page_id))->find();\n            if ($page) {\n                $item_id = $page['item_id'];\n            }\n        }\n        $item = D(\"Item\")->where(\"item_id = '%d'\", array($item_id))->find();\n        if ($password && $item['password'] == $password) {\n            session(\"visit_item_\" . $item['item_id'], 1);\n            $this->sendResult(array(\"refer_url\" => base64_decode($refer_url)));\n        } else {\n            $this->sendError(10010, L('access_password_are_incorrect'));\n        }\n    }\n\n\n    public function itemList()\n    {\n        $login_user = $this->checkLogin();\n        $items  = D(\"Item\")->where(array('uid' => $login_user['uid']))->select();\n        $items = $items ? $items : array();\n        $this->sendResult($items);\n    }\n\n    //新建项目\n    public function add()\n    {\n        $login_user = $this->checkLogin();\n        $item_name = I(\"post.item_name\");\n        $item_domain = I(\"item_domain\") ? I(\"item_domain\") : '';\n        $copy_item_id = I(\"copy_item_id/d\");\n        $password = I(\"password\");\n        $item_description = I(\"item_description\");\n        $item_type = I(\"item_type\") ? I(\"item_type\") : 1;\n        $item_group_id = I(\"item_group_id/d\") ? I(\"item_group_id/d\") : 0;\n        $item_group_ids_raw = I(\"item_group_ids\");\n        if (!$item_name) {\n            $this->sendError(10100, '项目名不能为空');\n            return false;\n        }\n        if ($item_domain) {\n\n            if (!ctype_alnum($item_domain) ||  is_numeric($item_domain)) {\n                //echo '个性域名只能是字母或数字的组合';exit;\n                $this->sendError(10305);\n                return false;\n            }\n\n            $item = D(\"Item\")->where(array('item_domain' => $item_domain))->find();\n            if ($item) {\n                //个性域名已经存在\n                $this->sendError(10304);\n                return false;\n            }\n        }\n\n        //如果是复制项目\n        if ($copy_item_id > 0) {\n            if (!$this->checkItemEdit($login_user['uid'], $copy_item_id)) {\n                $this->sendError(10103);\n                return;\n            }\n            $item_id = D(\"Item\")->copy($copy_item_id, $login_user['uid'], $item_name, $item_description, $password, $item_domain);\n            if ($item_id) {\n                $this->sendResult(array(\"item_id\" => $item_id));\n            } else {\n                $this->sendError(10101);\n            }\n            return;\n        }\n\n        $insert = array(\n            \"uid\" => $login_user['uid'],\n            \"username\" => $login_user['username'],\n            \"item_name\" => $item_name,\n            \"password\" => $password,\n            \"item_description\" => $item_description,\n            \"item_domain\" => $item_domain,\n            \"item_type\" => $item_type,\n            \"addtime\" => time()\n        );\n        $item_id = D(\"Item\")->add($insert);\n\n        if ($item_id) {\n            //如果是单页应用，则新建一个默认页\n            if ($item_type == 2) {\n                $insert = array(\n                    'author_uid' => $login_user['uid'],\n                    'author_username' => $login_user['username'],\n                    \"page_title\" => $item_name,\n                    \"item_id\" => $item_id,\n                    \"cat_id\" => 0,\n                    \"page_content\" => '欢迎使用showdoc。点击右上方的编辑按钮进行编辑吧！',\n                    \"addtime\" => time(),\n                    \"page_addtime\" => time(),\n                );\n                $page_id = D(\"Page\")->add($insert);\n            }\n            //如果是表格应用，则新建一个默认页\n            if ($item_type == 4) {\n                $insert = array(\n                    'author_uid' => $login_user['uid'],\n                    'author_username' => $login_user['username'],\n                    \"page_title\" => $item_name,\n                    \"item_id\" => $item_id,\n                    \"cat_id\" => 0,\n                    \"page_content\" => '',\n                    \"addtime\" => time(),\n                    \"page_addtime\" => time(),\n                );\n                $page_id = D(\"Page\")->add($insert);\n            }\n\n            // 如果是白板项目，则新建一个默认页（内容留空，前端初始化为白板JSON）\n            if ($item_type == 5) {\n                $insert = array(\n                    'author_uid' => $login_user['uid'],\n                    'author_username' => $login_user['username'],\n                    \"page_title\" => $item_name,\n                    \"item_id\" => $item_id,\n                    \"cat_id\" => 0,\n                    \"page_content\" => '',\n                    \"addtime\" => time()\n                );\n                $page_id = D(\"Page\")->add($insert);\n            }\n\n            // 多分组（创建）\n            $selected_group_ids = array();\n            if (!empty($item_group_ids_raw)) {\n                if (is_array($item_group_ids_raw)) {\n                    $selected_group_ids = $item_group_ids_raw;\n                } else {\n                    $tmp = json_decode(htmlspecialchars_decode($item_group_ids_raw), true);\n                    if (is_array($tmp)) {\n                        $selected_group_ids = $tmp;\n                    } else {\n                        $selected_group_ids = explode(',', strval($item_group_ids_raw));\n                    }\n                }\n            } elseif ($item_group_id > 0) {\n                $selected_group_ids = array($item_group_id);\n            }\n            $selected_group_ids = array_values(array_unique(array_filter(array_map('intval', $selected_group_ids))));\n            if (!empty($selected_group_ids)) {\n                foreach ($selected_group_ids as $gid) {\n                    $res = D(\"ItemGroup\")->where(\" id = '%d' and uid = '%d' \", array($gid, $login_user['uid']))->find();\n                    if ($res && $res['item_ids']) {\n                        $item_ids = array_values(array_unique(array_filter(array_map('intval', explode(',', $res['item_ids'])))));\n                        if (!in_array($item_id, $item_ids)) {\n                            $item_ids[] = $item_id;\n                        }\n                        $new_item_ids = implode(',', $item_ids);\n                        D(\"ItemGroup\")->where(\"id = '%d' and uid = '%d'\", array($gid, $login_user['uid']))->save(['item_ids' => $new_item_ids]);\n                    } else {\n                        D(\"ItemGroup\")->where(\"id = '%d' and uid = '%d'\", array($gid, $login_user['uid']))->save(['item_ids' => $item_id]);\n                    }\n                }\n            }\n\n            $this->sendResult(array(\"item_id\" => $item_id));\n        } else {\n            $this->sendError(10101);\n        }\n    }\n\n    //保存项目排序\n    public function sort()\n    {\n        $login_user = $this->checkLogin();\n\n        $data = I(\"data\");\n        $item_group_id = I(\"item_group_id/d\");\n\n        $res = D(\"ItemSort\")->where(array('uid' => $login_user['uid'], 'item_group_id' => $item_group_id))->find();\n        if ($res) {\n            $ret = D(\"ItemSort\")->where(array('uid' => $login_user['uid'], 'item_group_id' => $item_group_id))->save(array(\"item_sort_data\" => $data, \"addtime\" => time()));\n        } else {\n            $ret = D(\"ItemSort\")->add(array(\"item_sort_data\" => $data, \"item_group_id\" => $item_group_id, \"uid\" => $login_user['uid'], \"addtime\" => time()));\n        }\n\n\n        if ($ret) {\n            $this->sendResult(array());\n        } else {\n            $this->sendError(10101);\n        }\n    }\n\n    public function exitItem()\n    {\n\n        $login_user = $this->checkLogin();\n\n        $item_id = I(\"item_id/d\");\n        $ret = D(\"ItemMember\")->where(\"item_id = '%d' and uid ='%d' \", array($item_id, $login_user['uid']))->delete();\n\n        $row = D(\"TeamItemMember\")->join(\" left join team on team.id = team_item_member.team_id \")->where(\"item_id = '%d' and member_uid ='%d' \", array($item_id, $login_user['uid']))->find();\n        if ($row) {\n            $ret = D(\"TeamItemMember\")->where(\" member_uid = '%d' and  team_id = '%d' \", array($login_user['uid'], $row['team_id']))->delete();\n            $ret = D(\"TeamMember\")->where(\" member_uid = '%d' and  team_id = '%d' \", array($login_user['uid'], $row['team_id']))->delete();\n        }\n\n\n        if ($ret) {\n            $this->sendResult(array());\n        } else {\n            $this->sendError(10101);\n        }\n    }\n\n    // 在某个项目中根据内容搜索\n    public function search()\n    {\n        $keyword = I(\"keyword\");\n        $item_id = I(\"item_id/d\");\n        $login_user = $this->checkLogin();\n        $uid = $login_user['uid'];\n        if (!$this->checkItemVisit($uid, $item_id)) {\n            $this->sendError(10303, \"没有权限\");\n            return;\n        }\n        $item = D(\"Item\")->where(\"item_id = '%d' and is_del = 0 \", array($item_id))->find();\n        // 如果用户被分配了 目录权限 ，则获取他在该项目下拥有权限的目录id\n        $cat_id = D(\"Member\")->getCatId($item_id, $uid);\n        $pages = D(\"Page\")->search($item_id, $cat_id, $keyword);\n        if ($pages) {\n            foreach ($pages as $key => $value) {\n                $page_content = htmlspecialchars_decode($value['page_content']);\n                $pos = mb_strpos($page_content, $keyword);\n                $len = mb_strlen($keyword);\n                $start = ($pos - 100) > 0 ? ($pos - 100) : 0;\n                $pages[$key]['search_content'] = '...' . mb_substr($page_content, $start, ($len +  200)) . '...';\n                unset($pages[$key]['page_content']);\n                $pages[$key]['item_id'] = $item['item_id'];\n                $pages[$key]['item_name'] = $item['item_name'];\n            }\n        }\n        $return = array(\n            \"item_id\" => $item_id,\n            \"item_name\" => $item['item_name'],\n            \"pages\" => $pages\n        );\n        $this->sendResult($return);\n    }\n\n    //获取项目变更日志\n    public function getChangeLog()\n    {\n        $page = I(\"page/d\") ? I(\"page/d\") : 1;\n        $count = I(\"count/d\") ? I(\"count/d\") : 15;\n        $item_id = I(\"post.item_id/d\");\n        $login_user = $this->checkLogin();\n\n        if (!$this->checkItemEdit($login_user['uid'], $item_id)) {\n            $this->sendError(10103);\n            return;\n        }\n\n        $list = D(\"ItemChangeLog\")->getLog($item_id, $page, $count);\n        $list = $list ? $list : array();\n        $this->sendResult($list);\n    }\n\n    //标星一个项目\n    public function star()\n    {\n        $item_id = I(\"post.item_id/d\");\n        $login_user = $this->checkLogin();\n\n        if (!$this->checkItemVisit($login_user['uid'], $item_id)) {\n            $this->sendError(10103);\n            return;\n        }\n\n        $data = array();\n        $data['uid'] = $login_user['uid'];\n        $data['item_id'] = $item_id;\n        $data['created_at'] = date(\"Y-m-d H:i:s\");\n        $data['updated_at'] = date(\"Y-m-d H:i:s\");\n        $id = D(\"ItemStar\")->add($data);\n        $this->sendResult($id);\n    }\n\n    //取消标星一个项目\n    public function unstar()\n    {\n        $item_id = I(\"post.item_id/d\");\n        $login_user = $this->checkLogin();\n        D(\"ItemStar\")->where(\" uid = '%d' and item_id = '%d' \", array($login_user['uid'], $item_id))->delete();\n        $this->sendResult(array());\n    }\n\n    // 新增：应用筛选条件的方法\n    private function applyFilters($menuData, $statusFilter, $showMD, $item_id)\n    {\n        if (!$menuData) return $menuData;\n\n        // 处理根目录的页面\n        if (isset($menuData['pages']) && is_array($menuData['pages'])) {\n            $filteredPages = array();\n            foreach ($menuData['pages'] as $page) {\n                if ($this->shouldShowPage($page, $statusFilter, $showMD, $item_id)) {\n                    $filteredPages[] = $page;\n                }\n            }\n            $menuData['pages'] = $filteredPages;\n        }\n\n        // 递归处理目录\n        if (isset($menuData['catalogs']) && is_array($menuData['catalogs'])) {\n            $this->filterCatalogsRecursive($menuData['catalogs'], $statusFilter, $showMD, $item_id);\n        }\n\n        return $menuData;\n    }\n\n    private function filterCatalogsRecursive(&$catalogs, $statusFilter, $showMD, $item_id)\n    {\n        if (!$catalogs) return;\n\n        foreach ($catalogs as $key => &$catalog) {\n            // 处理目录下的页面\n            if (isset($catalog['pages']) && is_array($catalog['pages'])) {\n                $filteredPages = array();\n                foreach ($catalog['pages'] as $page) {\n                    if ($this->shouldShowPage($page, $statusFilter, $showMD, $item_id)) {\n                        $filteredPages[] = $page;\n                    }\n                }\n                $catalog['pages'] = $filteredPages;\n            }\n\n            // 递归处理子目录\n            if (isset($catalog['catalogs']) && is_array($catalog['catalogs'])) {\n                $this->filterCatalogsRecursive($catalog['catalogs'], $statusFilter, $showMD, $item_id);\n            }\n        }\n    }\n\n    private function shouldShowPage($page, $statusFilter, $showMD, $item_id)\n    {\n        // 从数据库获取页面内容\n        $pageContent = D(\"Page\")->where(\"page_id = '%d'\", array($page['page_id']))->getField('page_content');\n        if (!$pageContent) {\n            return $showMD;\n        }\n\n        // 先进行HTML转义，然后尝试解析页面内容为JSON\n        $decodedContent = htmlspecialchars_decode($pageContent);\n        $obj = json_decode($decodedContent, true);\n\n        // 如果解析失败或者没有info.url字段，说明是markdown文档\n        if (!$obj || !isset($obj['info']) || !isset($obj['info']['url'])) {\n            return $showMD;\n        }\n\n        // 到这里说明是接口，检查状态筛选\n        if ($statusFilter) {\n            $statusArray = explode(',', $statusFilter);\n            $pageStatus = $this->getStatusText($obj['info']['apiStatus']);\n            if (!in_array($pageStatus, $statusArray)) {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    private function getStatusText($status)\n    {\n        $statusMap = array(\n            '0' => '未操作',\n            '1' => '开发中',\n            '2' => '测试中',\n            '3' => '已完成',\n            '4' => '需修改',\n            '5' => '已废弃'\n        );\n        return isset($statusMap[$status]) ? $statusMap[$status] : '未操作';\n    }\n\n    /**\n     * 获取项目的 AI 知识库配置\n     */\n    public function getAiKnowledgeBaseConfig()\n    {\n        $this->checkLogin(false);\n        $item_id = I(\"item_id/d\");\n\n        if (!$item_id) {\n            $this->sendError(10101, '项目ID不能为空');\n            return;\n        }\n\n        $login_user = session(\"login_user\");\n        $uid = $login_user ? $login_user['uid'] : 0;\n\n        // 检查项目访问权限\n        if (!$this->checkItemVisit($uid, $item_id)) {\n            $this->sendError(10303, '您没有访问该项目的权限');\n            return;\n        }\n\n        // 获取配置\n        $config = D(\"ItemAiConfig\")->getConfig($item_id);\n\n        // 如果项目已启用 AI 知识库，检查索引状态，如果索引不存在则自动重建\n        if (!empty($config['enabled'])) {\n            $ai_service_url = D(\"Options\")->get(\"ai_service_url\");\n            $ai_service_token = D(\"Options\")->get(\"ai_service_token\");\n\n            // 检查系统级配置\n            if ($ai_service_url && $ai_service_token) {\n                // 检查索引状态\n                $index_status = $this->_checkIndexStatus($item_id, $ai_service_url, $ai_service_token);\n\n                // 如果索引不存在（被删除或从未创建），则自动触发重建\n                if ($index_status === false || (isset($index_status['indexed']) && !$index_status['indexed'])) {\n                    // 异步触发重建索引（不阻塞返回）\n                    register_shutdown_function(function () use ($item_id, $ai_service_url, $ai_service_token) {\n                        \\Api\\Helper\\AiHelper::rebuild($item_id, $ai_service_url, $ai_service_token);\n                    });\n                }\n\n                // 同步预热模型（提前加载模型到内存，提升首次对话速度）\n                // 使用短超时（3秒），避免阻塞配置接口响应\n                // 如果3秒内完成，模型已就绪；如果超时，也不影响配置返回\n                try {\n                    $warmupUrl = rtrim($ai_service_url, '/') . '/api/warmup';\n                    $warmupResult = \\Api\\Helper\\AiHelper::callService($warmupUrl, null, $ai_service_token, 'POST', 3);\n                    if ($warmupResult !== false && isset($warmupResult['status']) && $warmupResult['status'] == 'success') {\n                        \\Think\\Log::record(\"模型预热成功: \" . (isset($warmupResult['message']) ? $warmupResult['message'] : ''));\n                    } else {\n                        \\Think\\Log::record(\"模型预热失败或超时（不影响使用）\");\n                    }\n                } catch (\\Exception $e) {\n                    // 静默处理，不影响配置返回\n                    \\Think\\Log::record(\"模型预热异常: \" . $e->getMessage());\n                }\n            }\n        }\n\n        $this->sendResult($config);\n    }\n\n    /**\n     * 检查索引状态\n     * @param int $item_id 项目ID\n     * @param string $ai_service_url AI服务地址\n     * @param string $ai_service_token AI服务Token\n     * @return array|false 返回索引状态或false\n     */\n    private function _checkIndexStatus($item_id, $ai_service_url, $ai_service_token)\n    {\n        $url = rtrim($ai_service_url, '/') . '/api/index/status?item_id=' . $item_id;\n        return \\Api\\Helper\\AiHelper::callService($url, null, $ai_service_token, 'GET', 10);\n    }\n\n    /**\n     * 设置项目的 AI 知识库配置\n     */\n    public function setAiKnowledgeBaseConfig()\n    {\n        $login_user = $this->checkLogin();\n        $item_id = I(\"item_id/d\");\n\n        if (!$item_id) {\n            $this->sendError(10101, '项目ID不能为空');\n            return;\n        }\n\n        $uid = $login_user['uid'];\n\n        // 检查项目管理权限\n        if (!$this->checkItemManage($uid, $item_id)) {\n            $this->sendError(10303, '您没有管理该项目的权限');\n            return;\n        }\n\n        // 获取配置数据\n        $config_data = array();\n\n        // 是否启用\n        $enabled = I(\"enabled/d\");\n        if ($enabled !== null) {\n            $config_data['enabled'] = $enabled;\n        }\n\n        // 对话框默认状态\n        $dialog_collapsed = I(\"dialog_collapsed/d\");\n        if ($dialog_collapsed !== null) {\n            $config_data['dialog_collapsed'] = $dialog_collapsed;\n        }\n\n        // 欢迎语\n        $welcome_message = I(\"welcome_message\");\n        if ($welcome_message !== null) {\n            $config_data['welcome_message'] = $welcome_message;\n        }\n\n        if (empty($config_data)) {\n            $this->sendError(10101, '没有需要更新的配置');\n            return;\n        }\n\n        // 保存配置\n        $result = D(\"ItemAiConfig\")->saveConfig($item_id, $config_data);\n\n        if ($result !== false) {\n            $this->sendResult(array('success' => true));\n        } else {\n            $this->sendError(10101, '更新失败');\n        }\n    }\n}\n"
  },
  {
    "path": "server/Application/Api/Controller/ItemGroupController.class.php",
    "content": "<?php\n\nnamespace Api\\Controller;\n\nuse Think\\Controller;\n/*\n    项目分组管理\n */\n\nclass ItemGroupController extends BaseController\n{\n\n    //添加和编辑\n    public function save()\n    {\n        $login_user = $this->checkLogin();\n\n        $group_name = I(\"post.group_name\");\n        $item_ids = I(\"post.item_ids\");\n        $id = I(\"post.id/d\");\n        if (!$group_name) return false;\n        if ($id) {\n\n            D(\"ItemGroup\")->where(array('id' => $id))->save(array(\"group_name\" => $group_name, \"item_ids\" => $item_ids));\n        } else {\n            $data = array();\n            $data['uid'] = $login_user['uid'];\n            $data['group_name'] = $group_name;\n            $data['item_ids'] = $item_ids;\n            $data['created_at'] = date(\"Y-m-d H:i:s\");\n            $data['updated_at'] = date(\"Y-m-d H:i:s\");\n            $id = D(\"ItemGroup\")->add($data);\n        }\n\n        usleep(200000);\n        $return = D(\"ItemGroup\")->where(array('id' => $id))->find();\n\n        if (!$return && !$id) {\n            $return = array();\n            $return['error_code'] = 10103;\n            $return['error_message'] = 'request  fail';\n        }\n\n        $this->sendResult($return);\n    }\n\n    //获取列表\n    public function getList()\n    {\n        $login_user = $this->checkLogin();\n        if ($login_user['uid'] > 0) {\n            $ret = D(\"ItemGroup\")->where(\" uid = '%d' \", array($login_user['uid']))->order(\" s_number asc,id asc  \")->select();\n        }\n        if ($ret) {\n            $this->sendResult($ret);\n        } else {\n            $this->sendResult(array());\n        }\n    }\n\n    //删除\n    public function delete()\n    {\n        $id = I(\"id/d\") ? I(\"id/d\") : 0;\n        $login_user = $this->checkLogin();\n        if ($id && $login_user['uid']) {\n            $ret = D(\"ItemGroup\")->where(\" id = '%d' and uid = '%d'\", array($id, $login_user['uid']))->delete();\n        }\n        if ($ret) {\n            D(\"ItemGroup\")->where(array('id' => $id))->delete();\n            D(\"ItemSort\")->where(array('item_group_id' => $id))->delete();\n            $this->sendResult($ret);\n        } else {\n            $this->sendError(10101);\n        }\n    }\n\n    // 给我的项目组们保存顺序\n    public function saveSort()\n    {\n        $login_user = $this->checkLogin();\n        $groups = I(\"groups\");\n        $data_array = json_decode(htmlspecialchars_decode($groups), true);\n        $uid = $login_user['uid'];\n        if ($data_array) {\n            foreach ($data_array as $key => $value) {\n                $id = intval($value['id']);\n                $ret = D(\"ItemGroup\")->where(\" id = '%d' and uid = '%d'\", array($id, $uid))->save(array('s_number' => $value['s_number']));\n            }\n        }\n        $this->sendResult(array());\n    }\n}\n"
  },
  {
    "path": "server/Application/Api/Controller/ItemVariableController.class.php",
    "content": "<?php\n\nnamespace Api\\Controller;\n\nuse Think\\Controller;\n\nclass ItemVariableController extends BaseController\n{\n\n\n    //保存\n    public function save()\n    {\n        $item_id = I(\"item_id/d\");\n        $env_id = I(\"env_id/d\");\n        $var_name = trim(I(\"var_name\"));\n        $var_value = trim(I(\"var_value\"));\n        $login_user = $this->checkLogin();\n        $uid = $login_user['uid'];\n        if (!$this->checkItemEdit($uid, $item_id)) {\n            $this->sendError(10303);\n            return;\n        }\n\n        $id = 0;\n        $res = D(\"ItemVariable\")->where(\" item_id = '%d' and env_id = '%d' and var_name = '%s'   \", array($item_id, $env_id, $var_name))->find();\n        if ($res) {\n            $id = $res['id'];\n            D(\"ItemVariable\")->where(array('id' => $id))->save(array(\"var_value\" => $var_value));\n        } else {\n            $data = array();\n            $data['var_name'] = $var_name;\n            $data['uid'] = $uid;\n            $data['var_value'] = $var_value;\n            $data['item_id'] = $item_id;\n            $data['env_id'] = $env_id;\n            $data['addtime'] = time();\n            $id = D(\"ItemVariable\")->add($data);\n        }\n\n\n        if (!$id) {\n            $this->sendError(10101);\n        } else {\n            $this->sendResult($id);\n        }\n    }\n\n    //获取列表\n    public function getList()\n    {\n        $item_id = I(\"item_id/d\");\n        $env_id = I(\"env_id/d\");\n        $login_user = $this->checkLogin();\n        $uid = $login_user['uid'];\n        if (!$this->checkItemEdit($uid, $item_id)) {\n            $this->sendError(10303);\n            return;\n        }\n        if ($item_id > 0) {\n            if ($env_id) {\n                $ret = D(\"ItemVariable\")->where(\" item_id = '%d' and env_id = '%d' \", array($item_id, $env_id))->order(\" addtime asc  \")->select();\n            } else {\n                $ret = D(\"ItemVariable\")->where(array('item_id' => $item_id))->order(\" addtime asc  \")->select();\n            }\n        }\n        if ($ret) {\n            foreach ($ret as $key => &$value) {\n                $value['addtime'] = date(\"Y-m-d H:i:s\", $value['addtime']);\n            }\n        }\n        $this->sendResult($ret);\n    }\n\n    //删除\n    public function delete()\n    {\n        $item_id = I(\"post.item_id/d\");\n        $id = I(\"id/d\");\n        $login_user = $this->checkLogin();\n        $uid = $login_user['uid'];\n        if (!$this->checkItemEdit($uid, $item_id)) {\n            $this->sendError(10303);\n            return;\n        }\n        $ret = D(\"ItemVariable\")->where(\" item_id = '%d' and id = '%d'  \", array($item_id, $id))->delete();\n        if ($ret) {\n            $this->sendResult($ret);\n        } else {\n            $this->sendError(10101);\n        }\n    }\n\n\n\n    //根据name删除\n    public function deleteByName()\n    {\n        $item_id = I(\"post.item_id/d\");\n        $env_id = I(\"post.env_id/d\");\n        $var_name = I(\"post.var_name\");\n        $login_user = $this->checkLogin();\n        $uid = $login_user['uid'];\n        if (!$this->checkItemEdit($uid, $item_id)) {\n            $this->sendError(10303);\n            return;\n        }\n        $ret = D(\"ItemVariable\")->where(\" item_id = '%d' and env_id = '%d' and var_name = '%s'  \", array($item_id, $env_id, $var_name))->delete();\n        if ($ret) {\n            $this->sendResult($ret);\n        } else {\n            $this->sendError(10101);\n        }\n    }\n}\n"
  },
  {
    "path": "server/Application/Api/Controller/MemberController.class.php",
    "content": "<?php\n\nnamespace Api\\Controller;\n\nuse Think\\Controller;\n\nclass MemberController extends BaseController\n{\n\n\n    //保存\n    public function save()\n    {\n        $member_group_id =  I(\"member_group_id/d\");\n        $item_id = I(\"post.item_id/d\");\n        $cat_id = I(\"cat_id/d\") ?  I(\"cat_id/d\") : 0;\n        $cat_ids = I(\"cat_ids\"); // 逗号分隔的多目录，二级目录限定\n        $login_user = $this->checkLogin();\n        $uid = $login_user['uid'];\n        if (!$this->checkItemManage($uid, $item_id)) {\n            $this->sendError(10303);\n            return;\n        }\n\n        $username = I(\"username\");\n        $username_array = explode(\",\", $username);\n        foreach ($username_array as $key => $value) {\n            $member = D(\"User\")->where(array('username' => $value))->find();\n            if (!$member) {\n                continue;\n            }\n            $if_exit = D(\"ItemMember\")->where(\" uid = '%d' and item_id = '%d' \", array($member['uid'], $item_id))->find();\n            if ($if_exit) {\n                continue;\n            }\n            $data = array();\n            $data['username'] = $member['username'];\n            $data['uid'] = $member['uid'];\n            $data['item_id'] = $item_id;\n            $data['member_group_id'] = $member_group_id;\n            $data['cat_id'] = $cat_id;\n            // 保存多目录（仅二级目录），统一逗号分隔\n            if (isset($_POST['cat_ids'])) {\n                $ids = array();\n                if (is_array($cat_ids)) {\n                    $ids = $cat_ids;\n                } else if (is_string($cat_ids)) {\n                    if (strpos($cat_ids, ',') !== false) {\n                        $ids = preg_split('/\\s*,\\s*/', trim($cat_ids));\n                    } else if (ctype_digit($cat_ids)) {\n                        $ids = array(intval($cat_ids));\n                    }\n                }\n                $ids2 = array();\n                if (!empty($ids)) {\n                    foreach ($ids as $v) {\n                        $v = intval($v);\n                        if ($v <= 0) continue;\n                        $cat = D(\"Catalog\")->where(\"cat_id = '%d' and item_id = '%d' and level = 2\", array($v, $item_id))->find();\n                        if ($cat) $ids2[] = $v;\n                    }\n                    $ids2 = array_values(array_unique($ids2));\n                }\n                $data['cat_ids'] = !empty($ids2) ? implode(',', $ids2) : '';\n            }\n            $data['addtime'] = time();\n            $id = D(\"ItemMember\")->add($data);\n        }\n        $return = D(\"ItemMember\")->where(array('item_member_id' => $id))->find();\n        if (!$return) {\n            $this->sendError(10101);\n        } else {\n            D(\"ItemChangeLog\")->addLog($login_user['uid'], $item_id, 'binding', 'member', $member['uid'], $member['username']);\n            $this->sendResult($return);\n        }\n    }\n\n    //获取成员列表\n    public function getList()\n    {\n        $item_id = I(\"item_id/d\");\n        $login_user = $this->checkLogin();\n        $uid = $login_user['uid'];\n        if (!$this->checkItemManage($uid, $item_id)) {\n            $this->sendError(10303);\n            return;\n        }\n        if ($item_id > 0) {\n            $ret = D(\"ItemMember\")->where(\" item_id = '%d' \", array($item_id))->join(\" left join user on user.uid = item_member.uid\")->field(\"item_member.* , user.name as name\")->order(\" addtime asc  \")->select();\n        }\n        if ($ret) {\n            foreach ($ret as $key => &$value) {\n                $value['addtime'] = date(\"Y-m-d H:i:s\", $value['addtime']);\n                $value['member_group'] = $value['member_group_id'] == 1 ? \"编辑\" : \"只读\";\n                $value['cat_name'] = '所有目录';\n                // 当存在多目录时，简单展示为“多个目录”\n                if (!empty($value['cat_ids'])) {\n                    $value['cat_name'] = '多个目录';\n                } else if ($value['cat_id'] > 0) {\n                    $row = D(\"Catalog\")->where(array('cat_id' => $value['cat_id']))->find();\n                    if ($row &&  $row['cat_name']) {\n                        $value['cat_name'] =  $row['cat_name'];\n                    }\n                }\n                $value['member_group'] = $value['member_group_id'] == 1 ? \"编辑/目录：{$value['cat_name']}\" : \"只读/目录：{$value['cat_name']}\";\n            }\n        }\n        $this->sendResult($ret);\n    }\n\n    //删除成员\n    public function delete()\n    {\n        $item_id = I(\"post.item_id/d\");\n        $login_user = $this->checkLogin();\n        $uid = $login_user['uid'];\n        if (!$this->checkItemManage($uid, $item_id)) {\n            $this->sendError(10303);\n            return;\n        }\n        $item_member_id = I(\"item_member_id/d\");\n\n        if ($item_member_id) {\n            $member_array = D(\"ItemMember\")->where(\" item_id = '%d' and item_member_id = '%d'  \", array($item_id, $item_member_id))->find();\n            $ret = D(\"ItemMember\")->where(\" item_id = '%d' and item_member_id = '%d'  \", array($item_id, $item_member_id))->delete();\n        }\n        if ($ret) {\n            D(\"ItemChangeLog\")->addLog($login_user['uid'], $item_id, 'unbound', 'member', $member_array['uid'], $member_array['username']);\n            $this->sendResult($ret);\n        } else {\n            $this->sendError(10101);\n        }\n    }\n\n    // 获取一个项目的所有成员列表。包括单独成员和绑定的团队成员\n    public function getAllList()\n    {\n        $item_id = I(\"item_id/d\");\n        $login_user = $this->checkLogin();\n        $uid = $login_user['uid'];\n        if (!$this->checkItemEdit($uid, $item_id) && !$this->checkAdmin(false)) {\n            $this->sendError(10301);\n            return;\n        }\n\n        // 先获取项目的单独成员\n        $members_array = D(\"ItemMember\")->where(\" item_id = '%d' \", array($item_id))->join(\" left join user on user.uid = item_member.uid\")->field(\"item_member.uid,item_member.username ,item_member.member_group_id ,item_member.item_id , user.name as name\")->order(\" addtime asc  \")->select();\n\n        // 获取项目绑定的团队的成员\n        $team_members_array = D(\"TeamItemMember\")->where(\"item_id = '%d' \", array($item_id))->join(\" left join user on user.uid = team_item_member.member_uid\")->field(\"team_item_member.member_uid as uid ,team_item_member.member_username as username ,team_item_member.member_group_id,team_item_member.item_id , user.name as name\")->order(\" addtime asc  \")->select();\n\n        $return_array = array();\n        $uid_array = array();  // 利用这个uid数组来去重\n\n        $item = D(\"Item\")->where(\"item_id = '%d'\", array($item_id))->find();\n        // 把项目创建者加入成员里\n        $return_array[] = array(\n            \"item_id\" => $item_id,\n            \"uid\" => $item['uid'],\n            \"username\" => $item['username'],\n            \"username_name\" => $item['username'],\n            \"member_group_id\" => 1,\n        );\n        $uid_array[] = $item['uid'];\n\n        if ($members_array) {\n            foreach ($members_array as $key => $value) {\n                if (!in_array($value['uid'], $uid_array)) {\n                    $value['username_name'] = $value['username'];\n                    if ($value['name']) {\n                        $value['username_name'] .= \"({$value['name']})\";\n                    }\n                    $uid_array[] = $value['uid'];\n                    $return_array[] = $value;\n                }\n            }\n        }\n        if ($team_members_array) {\n            foreach ($team_members_array as $key => $value) {\n                if (!in_array($value['uid'], $uid_array)) {\n                    $value['username_name'] = $value['username'];\n                    if ($value['name']) {\n                        $value['username_name'] .= \"({$value['name']})\";\n                    }\n                    $uid_array[] = $value['uid'];\n                    $return_array[] = $value;\n                }\n            }\n        }\n\n\n\n        $this->sendResult($return_array);\n    }\n\n    // 获取当前登录用户的所有项目和团队的成员列表（通过用于让用户快速选择历史用户进行输入）\n    public function getMyAllList()\n    {\n        $login_user = $this->checkLogin();\n        $uid = $login_user['uid'];\n\n        // 下面sql的意思是，先查询当前用户的所有项目成员，然后查询当前用户的所有团队成员\n        // 然后UNION ALL 成一个临时表table1，然后username去重，addtime排序\n        $sql = \"\n            select uid,username,addtime from (\n                select item_member.uid ,item_member.username,item_member.addtime from item_member left join item on item_member.item_id = item.item_id where item.uid = '%d' \n            UNION ALL\n                select  team_member.member_uid as uid  ,team_member.member_username as username ,team_member.addtime from team_member left join team on team_member.team_id = team.id where team.uid = '%d' \n            ) as table1\n            group by uid,username,addtime order by addtime desc  \n        \";\n        $res = D(\"Item\")->query(sprintf($sql, $uid, $uid));\n        $this->sendResult($res);\n    }\n}\n"
  },
  {
    "path": "server/Application/Api/Controller/MessageController.class.php",
    "content": "<?php\n\nnamespace Api\\Controller;\n\nuse Think\\Controller;\n\nclass MessageController extends BaseController\n{\n\n\n    // 快速获取未读的消息\n    public function getUnread()\n    {\n        $login_user = $this->checkLogin();\n        $uid = $login_user['uid'];\n        $return = array(\n            'remind' => array(), // 提醒类的消息\n            'announce' => array(),  // 公告类的消息\n        );\n\n        // 先尝试获取提醒类消息\n        // 因为提醒类消息是会在Message表里写上未读标志的，所以可以先尝试读Message有没有未读消息。这样就能过滤掉大量无提醒的用户的请求\n        $array = D(\"Message\")->where(array(\n            'to_uid' => $uid,\n            'message_type' => 'remind',\n            'status' => 0\n        ))->find();\n        if ($array) {\n            // 如果有未读的，再组装更多信息\n            $list = D(\"Message\")->getRemindList($uid, 1, 1, 0);\n            if ($list && $list['list']) {\n                $return['remind'] = $list['list'][0];\n            }\n        }\n\n        // 尝试获取公告类的未读消息\n        // 先把用户已读了的公告id读取出来，再和公告id整体比较，那么除开已读的，剩下的就是未读的了\n        $array = D(\"Message\")->where(\" to_uid = '%d' and message_type='%s' \", array($uid, 'announce'))->select();\n        $message_content_id_array = array(0); // 初始化\n        if ($array) {\n            // 把id组成条件，方便后面的sql查询\n            foreach ($array as $key => $value) {\n                $message_content_id_array[] = $value['message_content_id'];\n            }\n        }\n\n        $reg_time = date(\"Y-m-d H:i:s\", $login_user['reg_time']);\n        // 管理员无视注册时间限制；普通用户仅读取注册时间之后的公告\n        $isAdmin = $this->checkAdmin(false);\n        // 支持多种公告类型：\n        // announce          旧版公告（兼容保留）\n        // announce_web      ShowDoc 网页端公告\n        // announce_runapi   RunApi 客户端公告\n        // announce_all      两端通用公告\n        $where = \" message_type in ('announce','announce_web','announce_runapi','announce_all') \";\n        if (!$isAdmin) {\n            $where .= \" and addtime > '$reg_time' \";\n        }\n        if (!empty($message_content_id_array)) {\n            $where .= \" and id not in (\" . implode(',', $message_content_id_array) . \") \";\n        }\n        $announce_array = D(\"MessageContent\")->where($where)->find();\n        if ($announce_array) {\n            $announce_array['message_content_id'] = $announce_array['id'];\n            $return['announce'] = $announce_array;\n        }\n\n        $this->sendResult($return);\n    }\n\n    //获取公告类型消息列表\n    public function getAnnouncementList()\n    {\n        $login_user = $this->checkLogin();\n        $uid =  $login_user['uid'];\n\n        $reg_time = date(\"Y-m-d H:i:s\", $login_user['reg_time']);\n        // 管理员无视注册时间限制；普通用户仅读取注册时间之后的公告\n        $isAdmin = $this->checkAdmin(false);\n        $where = \" message_type in ('announce','announce_web','announce_runapi','announce_all') \";\n        if (!$isAdmin) {\n            $where .= \" and addtime > '$reg_time' \";\n        }\n        $message_announce = D(\"MessageContent\")->where($where)->order(\" id desc \")->select();\n\n        if ($message_announce) {\n            // 获取已读未读状态\n            foreach ($message_announce as $key => $value) {\n                $array = D(\"Message\")->where(array('to_uid' => $uid, 'message_type' => 'announce', 'message_content_id' => $value['id']))->find();\n                // 存在记录就是已读。不存在就是未读\n                if ($array) {\n                    $message_announce[$key]['status'] = 1;\n                } else {\n                    $message_announce[$key]['status'] = 0;\n                }\n                $message_announce[$key]['message_content_id'] = $message_announce[$key]['id'];\n            }\n        }\n\n        //由于公告不会很多，所以不分页了。全部返回给前端\n\n        $this->sendResult((array)$message_announce);\n    }\n\n\n\n    //设置消息已读\n    public function setRead()\n    {\n        $login_user = $this->checkLogin();\n        $uid = $login_user['uid'];\n        $message_content_id = I(\"message_content_id/d\") ? I(\"message_content_id/d\") : 0;\n        $from_uid = I(\"from_uid/d\") ? I(\"from_uid/d\") : 0; // 开源版其实不需要用到此字段\n        $array = D(\"Message\")->where(\"to_uid = '%d' and message_content_id = '%d' \", array($uid, $message_content_id))->find();\n        if ($array) {\n            D(\"Message\")->where(\"to_uid = '%d' and message_content_id = '%d' \", array($uid, $message_content_id))->save(array(\"status\" => 1));\n        } else {\n            if ($message_content_id) {\n                // 如果不存在，则可能是公告类型。\n                D(\"Message\")->add(array(\n                    \"from_uid\" => 0,\n                    \"to_uid\" => $uid,\n                    \"message_type\" => 'announce',\n                    \"message_content_id\" => $message_content_id,\n                    \"status\" => 1,\n                    \"addtime\" => date(\"Y-m-d H:i:s\"),\n                    \"readtime\" => date(\"Y-m-d H:i:s\")\n\n                ));\n            }\n        }\n\n        $this->sendResult(array());\n    }\n\n    public function delete()\n    {\n        $login_user = $this->checkLogin();\n        $uid =  $login_user['uid'];\n        $message_content_id = I(\"message_content_id/d\") ? I(\"message_content_id/d\") : 0;\n        D(\"Message\")->where(\" to_uid = '%d' and message_content_id = '%d' \", array($uid, $message_content_id))->save(array(\n            \"status\" => -1,\n        ));\n        $this->sendResult(array());\n    }\n\n    //获取提醒型消息列表\n    public function getRemindList()\n    {\n        $page = I(\"page/d\") ? I(\"page/d\") : 1;\n        $count = I(\"count/d\") ? I(\"count/d\") : 15;\n        $login_user = $this->checkLogin();\n\n        $list = D(\"Message\")->getRemindList($login_user['uid'], $page, $count);\n        $list = $list ? $list : array();\n        $this->sendResult($list);\n    }\n\n    // 快速获取未读的提醒类消息\n    public function getUnreadRemind()\n    {\n        $login_user = $this->checkLogin();\n        $uid = $login_user['uid'];\n        $return = array();\n        $array = D(\"Message\")->where(\" to_uid = '%d' and status = %d \", array($uid, 0))->find();\n        if ($array) {\n            // 如果有未读的，再组装更多信息\n            $list = D(\"Message\")->getRemindList($uid, 1, 1, 0);\n            if ($list && $list['list']) {\n                $return = $list['list'][0];\n            }\n        }\n        $this->sendResult($return);\n    }\n}\n"
  },
  {
    "path": "server/Application/Api/Controller/MockController.class.php",
    "content": "<?php\n\nnamespace Api\\Controller;\n\nuse Think\\Controller;\n\nclass MockController extends BaseController\n{\n\n    //添加\n    public function add()\n    {\n        $page_id = I(\"page_id/d\");\n        $template = I(\"template\");\n        $path = I(\"path\") ? I(\"path\") : '/';\n        $login_user = $this->checkLogin();\n        $uid = $login_user['uid'];\n        $page = M(\"Page\")->where(array('page_id' => $page_id))->find();\n        if (!$this->checkItemEdit($uid, $page['item_id'])) {\n            $this->sendError(10103);\n            return;\n        }\n        if (substr($path, 0, 1) !== '/') {\n            $path = '/' . $path;\n        }\n        $item_id = $page['item_id'];\n        $json = json_decode(htmlspecialchars_decode($template));\n        if (!$json) {\n            $this->sendError(10101, '为了服务器安全，只允许写符合json语法的字符串');\n            return;\n        }\n        $unique_key = md5(time() . rand() . \"gbgdhbdgtfgfK3@bv45342asfsdfjhyfgkj54fofgfbv45342asfsdg\");\n        //假如已经该页面存在mock\n        $mock_page = D(\"Mock\")->where(array('page_id' => $page_id))->find();\n        if ($mock_page) {\n            $unique_key = $mock_page['unique_key'];\n            D(\"Mock\")->where(\"page_id = '%d' \", array($page_id))->save(array(\n                \"uid\" => $uid,\n                \"template\" => $template,\n                \"path\" => $path,\n                \"last_update_time\" => date(\"Y-m-d H:i:s\"),\n            ));\n        } else {\n            $id = D(\"Mock\")->add(array(\n                \"unique_key\" => $unique_key,\n                \"uid\" => $uid,\n                \"page_id\" => $page_id,\n                \"item_id\" => $item_id,\n                \"template\" => $template,\n                \"path\" => $path,\n                \"addtime\" => date(\"Y-m-d H:i:s\"),\n                \"last_update_time\" => date(\"Y-m-d H:i:s\"),\n                \"view_times\" => 0\n            ));\n        }\n\n        $this->sendResult(array(\n            \"page_id\" => $page_id,\n            \"path\" => $path,\n            \"unique_key\" => $unique_key\n        ));\n    }\n\n    // 根据页面id获取mock信息\n    public function infoByPageId()\n    {\n        $login_user = $this->checkLogin(false);\n        $page_id = I(\"page_id/d\");\n        $uid = $login_user['uid'];\n        $page = D(\"Mock\")->where(array('page_id' => $page_id))->find();\n        if (!$this->checkItemVisit($login_user['uid'], $page['item_id'])) {\n            $this->sendError(10103);\n            return;\n        }\n        $this->sendResult($page);\n    }\n\n    // 根据唯一key获取mock的响应数据\n    public function infoByKey()\n    {\n        $unique_key = I(\"unique_key\");\n        $page = D(\"Mock\")->where(array('unique_key' => $unique_key))->find();\n        $template = $page['template'];\n        $res = http_post(\"http://127.0.0.1:7123/mock\", array(\n            \"template\" => htmlspecialchars_decode($page['template'])\n        ));\n        if ($res) {\n            $json = json_decode($res);\n            if (!$json) {\n                $this->sendError(10101, '为了服务器安全，只允许写符合json语法的字符串');\n                return;\n            }\n            $res = htmlspecialchars($res, ENT_NOQUOTES); // 不编码任何引号,以兼容json.同时转义其他字符串，以免xss\n            echo $res;\n        } else {\n            echo \"mock服务暂时不可用。网站管理员需要另行安装mock服务，详情请打开https://www.showdoc.com.cn/p/1ee8a176dd0ccc65609005f3a36c2cc7\";\n        }\n    }\n    // 根据item_id和path获取\n    public function infoByPath()\n    {\n        // 这里如果用I(\"path\")方法来获取参数，那么接受post请求的时候有问题。原因暂时不明。应该跟路由里使用正则有关。\n        $item_id = $_REQUEST[\"item_id\"];\n        $path = $_REQUEST['path'] ? $_REQUEST['path'] : '/';\n        $page = D(\"Mock\")->where(\" item_id = '%s' and path = '%s'  \", array($item_id, $path))->find();\n        if (!$page) {\n            echo 'no such path';\n            return;\n        }\n        $template = $page['template'];\n        $mock_host = env(\"MOCK_HOST\", '127.0.0.1');\n        $mock_port = env('MOCK_PORT', '7123');\n        $res = http_post(\"http://{$mock_host}:{$mock_port}/mock\", array(\n            \"template\" => htmlspecialchars_decode($page['template'])\n        ));\n        if ($res) {\n            D(\"Mock\")->where(\" id = '%d' \", array($page['id']))->setInc(\"view_times\");\n            $json = json_decode($res);\n            if (!$json) {\n                $this->sendError(10101, '为了服务器安全，只允许写符合json语法的字符串');\n                return;\n            }\n            $res = htmlspecialchars($res, ENT_NOQUOTES); // 不编码任何引号,以兼容json.同时转义其他字符串，以免xss\n            echo $res;\n        } else {\n            echo \"mock服务暂时不可用。网站管理员安装完showdoc后需要另行安装mock服务，详情请打开https://www.showdoc.com.cn/p/1ee8a176dd0ccc65609005f3a36c2cc7\";\n        }\n    }\n}\n"
  },
  {
    "path": "server/Application/Api/Controller/OpenController.class.php",
    "content": "<?php\n\nnamespace Api\\Controller;\n\nuse Think\\Controller;\n\nclass OpenController extends BaseController\n{\n\n    /**\n     * 根据内容更新页面（创建或更新）\n     * 通过api_key和api_token鉴权\n     */\n    public function updatePage()\n    {\n        $api_key = I(\"api_key\");\n        $api_token = I(\"api_token\");\n        $cat_name = I(\"cat_name\") ? I(\"cat_name\") : '';\n        $cat_name_sub = I(\"cat_name_sub\");\n        $page_title = I(\"page_title\");\n        $page_content = I(\"page_content\");\n        $s_number = I(\"s_number\") ? I(\"s_number\") : 99;\n        //兼容之前的cat_name_sub参数\n        if ($cat_name_sub) {\n            $cat_name = $cat_name . '/' . $cat_name_sub;\n        }\n\n        // 鉴权\n        $res = D(\"ItemToken\")->check($api_key, $api_token);\n        if (!$res) {\n            //没验证通过\n            $this->sendError(10306, \"api_key或者api_token不匹配\");\n            return;\n        }\n        $item_id = $res;\n\n        $pageCount = M(\"Page\")->where(array('item_id' => $item_id))->count();\n        if ($pageCount > 5000) {\n            $this->sendError(10100, \"你创建太多页面啦！如有需求请联系网站管理员\");\n            return false;\n        }\n        $page_id = D(\"Page\")->update_by_title($item_id, $page_title, $page_content, $cat_name, $s_number);\n\n        if ($page_id) {\n            $ret = D(\"Page\")->where(array('page_id' => $page_id))->find();\n            $this->sendResult($ret);\n        } else {\n            $this->sendError(10101);\n        }\n    }\n\n    /**\n     * 根据内容更新项目（兼容旧接口，转向 updatePage）\n     * @deprecated 建议使用 updatePage 接口\n     */\n    public function updateItem()\n    {\n        // 兼容旧接口，直接调用新方法\n        $this->updatePage();\n    }\n\n    //根据shell上报的数据库结构信息生成数据字典\n    public function updateDbItem()\n    {\n        $api_key = I(\"api_key\");\n        $api_token = I(\"api_token\");\n        $table_info = I(\"table_info\");\n        $table_detail = I(\"table_detail\");\n        $s_number = I(\"s_number\") ? I(\"s_number\") : 99;\n        $cat_name = I(\"cat_name\") ? I(\"cat_name\") : '';\n        header('Content-Type:text/html;charset=utf-8 ');\n        $cat_name = str_replace(PHP_EOL, '', $cat_name);\n        $item_id = D(\"ItemToken\")->check($api_key, $api_token);\n        if (!$item_id) {\n            //没验证通过\n            echo \"api_key或者api_token不匹配\\n\";\n            return false;\n        }\n        $table_info = str_replace(\"_this_and_change_\", \"&\", $table_info);\n        $table_detail = str_replace(\"_this_and_change_\", \"&\", $table_detail);\n        $tables = $this->_analyze_db_structure_to_array($table_info, $table_detail);\n        if (!empty($tables)) {\n            foreach ($tables as $key => $value) {\n                $page_title = $value['table_name'];\n                $page_content = $value['markdown'];\n                $result = D(\"Page\")->update_by_title($item_id, $page_title, $page_content, $cat_name, $s_number);\n            }\n        }\n\n        if (!empty($result)) {\n            echo \"成功\\n\";\n        } else {\n            echo \"失败\\n\";\n        }\n\n        //$this->_record_log();\n\n    }\n\n    //通过注释生成api文档\n    public function fromComments()\n    {\n        R(\"FromComments/generate\");\n    }\n\n\n    private function _analyze_db_structure_to_array($table_info, $table_detail)\n    {\n        $tables = array();\n\n        //解析table_info\n        $array = explode(\"\\n\", $table_info);\n        if (!empty($array)) {\n            foreach ($array as $key => $value) {\n                if ($key == 0) {\n                    continue;\n                }\n                $array2 = explode(\"\\t\", $value);\n                $table_name = str_replace(PHP_EOL, '', $array2[0]);\n                $tables[$array2[0]] = array(\n                    \"table_name\" => $table_name,\n                    \"table_comment\" => $array2[1],\n                );\n            }\n        }\n\n\n\n        //解析table_detail\n        $array = explode(\"\\n\", $table_detail);\n        if (!empty($array)) {\n            foreach ($array as $key => $value) {\n                if ($key == 0) {\n                    continue;\n                }\n                $array2 = explode(\"\\t\", $value);\n\n                $tables[$array2[0]]['columns'][$array2[1]] = array(\n                    \"column_name\" => $array2[1],\n                    \"default\" => $array2[2],\n                    \"is_nullable\" => $array2[3],\n                    \"column_type\" => $array2[4],\n                    \"column_comment\" => $array2[5] ? $array2[5] : '无',\n                );\n            }\n        }\n\n\n        //生成markdown内容放在数组里\n        if (!empty($tables)) {\n            foreach ($tables as $key => $value) {\n                $markdown = '';\n                $markdown .= \"- {$value['table_comment']} \\n \\n\";\n                $markdown .= \"|字段|类型|允许空|默认|注释| \\n \";\n                $markdown .= \"|:----    |:-------    |:--- |----|------      | \\n \";\n                foreach ($value['columns'] as $key2 => $value2) {\n                    $markdown .= \"|{$value2['column_name']} |{$value2['column_type']} |{$value2['is_nullable']} | {$value2['default']} | {$value2['column_comment']}  | \\n \";\n                }\n\n                $tables[$key]['markdown'] = $markdown;\n            }\n        }\n        return $tables;\n    }\n\n    /**\n     * 获取页面详情\n     * 通过api_key和api_token鉴权\n     */\n    public function getPage()\n    {\n        $api_key = I(\"api_key\");\n        $api_token = I(\"api_token\");\n        $page_id = I(\"page_id/d\");\n        $page_title = I(\"page_title\");\n\n        // 鉴权\n        $res = D(\"ItemToken\")->check($api_key, $api_token);\n        if ($res === -2) {\n            $this->sendError(10306, \"api_key或者api_token不匹配\");\n            return;\n        }\n        $item_id = $res;\n\n        // 如果提供了 page_title，则通过标题查找页面\n        if ($page_title && !$page_id) {\n            $page = D(\"Page\")->where(array(\n                'item_id' => $item_id,\n                'page_title' => $page_title,\n                'is_del' => 0\n            ))->find();\n            if ($page) {\n                $page_id = $page['page_id'];\n            }\n        }\n\n        if (!$page_id) {\n            $this->sendError(10101, \"page_id或page_title参数必填\");\n            return;\n        }\n\n        // 获取页面详情\n        $page = M(\"Page\")->where(array('page_id' => $page_id))->find();\n        if (!$page || $page['is_del'] == 1 || $page['item_id'] != $item_id) {\n            $this->sendError(10101, \"页面不存在或已删除\");\n            return;\n        }\n\n        if ($page) {\n            $page['addtime'] = date(\"Y-m-d H:i:s\", $page['addtime']);\n            $this->sendResult($page);\n        } else {\n            $this->sendError(10101, \"获取页面失败\");\n        }\n    }\n\n    /**\n     * 删除页面\n     * 通过api_key和api_token鉴权\n     */\n    public function deletePage()\n    {\n        $api_key = I(\"api_key\");\n        $api_token = I(\"api_token\");\n        $page_id = I(\"page_id/d\");\n\n        // 鉴权\n        $res = D(\"ItemToken\")->check($api_key, $api_token);\n        if ($res === -2) {\n            $this->sendError(10306, \"api_key或者api_token不匹配\");\n            return;\n        }\n        $item_id = $res;\n\n        if (!$page_id) {\n            $this->sendError(10101, \"page_id参数必填\");\n            return;\n        }\n\n        // 检查页面是否属于该项目\n        $page = M(\"Page\")->where(array('page_id' => $page_id))->find();\n        if (!$page || $page['item_id'] != $item_id) {\n            $this->sendError(10101, \"页面不存在或不属于该项目\");\n            return;\n        }\n\n        // 获取项目创建者信息，临时设置 session 以复用原有方法\n        $item = D(\"Item\")->where(array('item_id' => $item_id))->find();\n        $del_by_uid = $item['uid'] ? $item['uid'] : 0;\n        $del_by_username = $item['uid'] ? D(\"User\")->where(array('uid' => $item['uid']))->getField('username') : 'API';\n\n        // 临时设置 session，以便复用 softDeletePage 方法\n        $old_login_user = session('login_user');\n        session('login_user', array('uid' => $del_by_uid, 'username' => $del_by_username));\n\n        // 复用原有方法\n        $ret = D(\"Page\")->softDeletePage($page_id);\n\n        // 恢复原有 session\n        if ($old_login_user) {\n            session('login_user', $old_login_user);\n        } else {\n            session('login_user', null);\n        }\n\n        if ($ret !== false) {\n            $this->sendResult(array(\"page_id\" => $page_id));\n        } else {\n            $this->sendError(10101, \"删除页面失败\");\n        }\n    }\n\n    /**\n     * 获取项目的目录树结构（包含页面标题）\n     * 通过api_key和api_token鉴权\n     */\n    public function getCatalogTree()\n    {\n        $api_key = I(\"api_key\");\n        $api_token = I(\"api_token\");\n\n        // 鉴权\n        $res = D(\"ItemToken\")->check($api_key, $api_token);\n        if ($res === -2) {\n            $this->sendError(10306, \"api_key或者api_token不匹配\");\n            return;\n        }\n        $item_id = $res;\n\n        // 复用 ItemModel 的 getContent 方法获取完整的目录树结构\n        // page_field: 只获取必要的字段，不获取 page_content 节省资源\n        $page_field = \"page_id, page_title, cat_id, s_number, author_username, addtime\";\n        $catalog_field = \"*\";\n        $menu = D(\"Item\")->getContent($item_id, $page_field, $catalog_field);\n\n        $this->sendResult($menu);\n    }\n\n    /**\n     * 创建目录\n     * 通过api_key和api_token鉴权\n     */\n    public function createCatalog()\n    {\n        $api_key = I(\"api_key\");\n        $api_token = I(\"api_token\");\n        $cat_name = I(\"cat_name\");\n        $parent_cat_id = I(\"parent_cat_id/d\") ? I(\"parent_cat_id/d\") : 0;\n        $s_number = I(\"s_number/d\") ? I(\"s_number/d\") : 99;\n\n        // 鉴权\n        $res = D(\"ItemToken\")->check($api_key, $api_token);\n        if ($res === -2) {\n            $this->sendError(10306, \"api_key或者api_token不匹配\");\n            return;\n        }\n        $item_id = $res;\n\n        if (!$cat_name) {\n            $this->sendError(10101, \"cat_name参数必填\");\n            return;\n        }\n\n        // 确定目录层级\n        $level = 2;\n        if ($parent_cat_id > 0) {\n            $parent_cat = D(\"Catalog\")->where(array('cat_id' => $parent_cat_id, 'item_id' => $item_id))->find();\n            if (!$parent_cat) {\n                $this->sendError(10101, \"父目录不存在\");\n                return;\n            }\n            $level = $parent_cat['level'] + 1;\n        }\n\n        // 创建目录\n        $catalog_data = array(\n            \"cat_name\" => htmlspecialchars($cat_name),\n            \"level\" => $level,\n            \"s_number\" => $s_number,\n            \"item_id\" => $item_id,\n            \"parent_cat_id\" => $parent_cat_id,\n            \"addtime\" => time(),\n        );\n        $cat_id = D(\"Catalog\")->add($catalog_data);\n\n        if ($cat_id) {\n            $catalog_data['cat_id'] = $cat_id;\n            $this->sendResult($catalog_data);\n        } else {\n            $this->sendError(10101, \"创建目录失败\");\n        }\n    }\n\n    /**\n     * 修改目录\n     * 通过api_key和api_token鉴权\n     */\n    public function updateCatalog()\n    {\n        $api_key = I(\"api_key\");\n        $api_token = I(\"api_token\");\n        $cat_id = I(\"cat_id/d\");\n        $cat_name = I(\"cat_name\");\n        $s_number = I(\"s_number/d\");\n\n        // 鉴权\n        $res = D(\"ItemToken\")->check($api_key, $api_token);\n        if ($res === -2) {\n            $this->sendError(10306, \"api_key或者api_token不匹配\");\n            return;\n        }\n        $item_id = $res;\n\n        if (!$cat_id) {\n            $this->sendError(10101, \"cat_id参数必填\");\n            return;\n        }\n\n        // 检查目录是否属于该项目\n        $catalog = D(\"Catalog\")->where(array('cat_id' => $cat_id))->find();\n        if (!$catalog || $catalog['item_id'] != $item_id) {\n            $this->sendError(10101, \"目录不存在或不属于该项目\");\n            return;\n        }\n\n        // 准备更新数据\n        $update_data = array();\n        if ($cat_name) {\n            $update_data['cat_name'] = htmlspecialchars($cat_name);\n        }\n        if ($s_number !== null && $s_number !== '') {\n            $update_data['s_number'] = $s_number;\n        }\n\n        if (empty($update_data)) {\n            $this->sendError(10101, \"请至少提供cat_name或s_number参数\");\n            return;\n        }\n\n        // 更新目录\n        $ret = D(\"Catalog\")->where(array('cat_id' => $cat_id))->save($update_data);\n        if ($ret !== false) {\n            $catalog = D(\"Catalog\")->where(array('cat_id' => $cat_id))->find();\n            $this->sendResult($catalog);\n        } else {\n            $this->sendError(10101, \"更新目录失败\");\n        }\n    }\n\n    /**\n     * 删除目录\n     * 通过api_key和api_token鉴权\n     */\n    public function deleteCatalog()\n    {\n        $api_key = I(\"api_key\");\n        $api_token = I(\"api_token\");\n        $cat_id = I(\"cat_id/d\");\n\n        // 鉴权\n        $res = D(\"ItemToken\")->check($api_key, $api_token);\n        if ($res === -2) {\n            $this->sendError(10306, \"api_key或者api_token不匹配\");\n            return;\n        }\n        $item_id = $res;\n\n        if (!$cat_id) {\n            $this->sendError(10101, \"cat_id参数必填\");\n            return;\n        }\n\n        // 检查目录是否属于该项目\n        $catalog = D(\"Catalog\")->where(array('cat_id' => $cat_id))->find();\n        if (!$catalog || $catalog['item_id'] != $item_id) {\n            $this->sendError(10101, \"目录不存在或不属于该项目\");\n            return;\n        }\n\n        // 获取项目创建者信息，临时设置 session 以复用原有方法\n        $item = D(\"Item\")->where(array('item_id' => $item_id))->find();\n        $del_by_uid = $item['uid'] ? $item['uid'] : 0;\n        $del_by_username = $item['uid'] ? D(\"User\")->where(array('uid' => $item['uid']))->getField('username') : 'API';\n\n        // 临时设置 session，以便复用 deleteCat 方法\n        $old_login_user = session('login_user');\n        session('login_user', array('uid' => $del_by_uid, 'username' => $del_by_username));\n\n        // 复用原有方法\n        $ret = D(\"Catalog\")->deleteCat($cat_id);\n\n        // 恢复原有 session\n        if ($old_login_user) {\n            session('login_user', $old_login_user);\n        } else {\n            session('login_user', null);\n        }\n\n        if ($ret) {\n            $this->sendResult(array(\"cat_id\" => $cat_id));\n        } else {\n            $this->sendError(10101, \"删除目录失败\");\n        }\n    }\n\n    /**\n     * 上传附件\n     * 通过api_key和api_token鉴权\n     */\n    public function uploadAttachment()\n    {\n        $api_key = I(\"api_key\");\n        $api_token = I(\"api_token\");\n        $page_id = I(\"page_id/d\") ? I(\"page_id/d\") : 0;\n\n        // 鉴权\n        $res = D(\"ItemToken\")->check($api_key, $api_token);\n        if ($res === -2) {\n            $this->sendError(10306, \"api_key或者api_token不匹配\");\n            return;\n        }\n        $item_id = $res;\n\n        // 获取项目所有者\n        $item = D(\"Item\")->where(array('item_id' => $item_id))->find();\n        if (!$item) {\n            $this->sendError(10101, \"项目不存在\");\n            return;\n        }\n        $uid = $item['uid'];\n\n        // 检查文件是否上传\n        if (empty($_FILES['file'])) {\n            $this->sendError(10101, \"请上传文件\");\n            return;\n        }\n\n        $uploadFile = $_FILES['file'];\n\n        // 检查文件扩展名\n        if (!D(\"Attachment\")->isAllowedFilename($uploadFile['name'])) {\n            $this->sendError(10101, '不支持上传该文件类型');\n            return;\n        }\n\n        // 上传文件\n        $url = D(\"Attachment\")->upload($_FILES, 'file', $uid, $item_id, $page_id, true);\n        if ($url) {\n            // 从 URL 中提取 sign 参数，用于后续删除\n            $parsed_url = parse_url($url);\n            $sign = '';\n            if (isset($parsed_url['query'])) {\n                parse_str($parsed_url['query'], $params);\n                if (isset($params['sign'])) {\n                    $sign = $params['sign'];\n                }\n            }\n\n            // 通过 sign 查找 file_id\n            $file_id = 0;\n            if ($sign) {\n                $file = D(\"UploadFile\")->where(array('sign' => $sign))->find();\n                if ($file) {\n                    $file_id = $file['file_id'];\n                }\n            }\n\n            $result = array(\"url\" => $url);\n            if ($file_id) {\n                $result[\"file_id\"] = $file_id;\n            }\n            if ($sign) {\n                $result[\"sign\"] = $sign;\n            }\n            $this->sendResult($result);\n        } else {\n            $this->sendError(10101, \"上传失败\");\n        }\n    }\n\n    /**\n     * 删除附件\n     * 通过api_key和api_token鉴权\n     */\n    public function deleteAttachment()\n    {\n        $api_key = I(\"api_key\");\n        $api_token = I(\"api_token\");\n        $file_id = I(\"file_id/d\");\n        $file_url = I(\"file_url\");\n        $sign = I(\"sign\");\n\n        // 鉴权\n        $res = D(\"ItemToken\")->check($api_key, $api_token);\n        if ($res === -2) {\n            $this->sendError(10306, \"api_key或者api_token不匹配\");\n            return;\n        }\n        $item_id = $res;\n\n        // 通过 file_id, file_url 或 sign 查找文件\n        $file = null;\n        if ($file_id) {\n            $file = D(\"UploadFile\")->where(array('file_id' => $file_id))->find();\n        } elseif ($sign) {\n            $file = D(\"UploadFile\")->where(array('sign' => $sign))->find();\n            if ($file) {\n                $file_id = $file['file_id'];\n            }\n        } elseif ($file_url) {\n            // 从 URL 中提取 sign 参数\n            $parsed_url = parse_url($file_url);\n            if (isset($parsed_url['query'])) {\n                parse_str($parsed_url['query'], $params);\n                if (isset($params['sign'])) {\n                    $sign = $params['sign'];\n                    $file = D(\"UploadFile\")->where(array('sign' => $sign))->find();\n                    if ($file) {\n                        $file_id = $file['file_id'];\n                    }\n                }\n            }\n            // 如果没有 sign，尝试从 URL 路径中提取（兼容直接的文件路径）\n            if (!$file && isset($parsed_url['path'])) {\n                $path = $parsed_url['path'];\n                // 检查是否是 visitFile URL，提取 sign\n                if (strpos($path, 'visitFile') !== false && isset($params['sign'])) {\n                    $file = D(\"UploadFile\")->where(array('sign' => $params['sign']))->find();\n                    if ($file) {\n                        $file_id = $file['file_id'];\n                    }\n                }\n            }\n        }\n\n        if (!$file_id || !$file) {\n            $this->sendError(10101, \"请提供 file_id、file_url 或 sign 参数，且文件必须存在\");\n            return;\n        }\n\n        // 检查文件是否关联到该项目\n        // 开源版可能没有 FilePage 表，检查 UploadFile.item_id\n        $file_page = null;\n        try {\n            $file_page = D(\"FilePage\")->where(array('file_id' => $file_id, 'item_id' => $item_id))->find();\n        } catch (\\Exception $e) {\n            // FilePage 表不存在，跳过\n        }\n        // 如果 FilePage 表中没有记录，则检查 UploadFile.item_id\n        if (!$file_page && isset($file['item_id']) && $file['item_id'] != $item_id) {\n            $this->sendError(10101, \"文件不属于该项目\");\n            return;\n        }\n\n        // 删除文件\n        $ret = D(\"Attachment\")->deleteFile($file_id);\n        if ($ret) {\n            $this->sendResult(array(\"file_id\" => $file_id));\n        } else {\n            $this->sendError(10101, \"删除失败\");\n        }\n    }\n}\n"
  },
  {
    "path": "server/Application/Api/Controller/PageCommentController.class.php",
    "content": "<?php\n\nnamespace Api\\Controller;\n\nuse Think\\Controller;\n\nclass PageCommentController extends BaseController\n{\n\n    //获取评论列表\n    public function getList()\n    {\n        $this->checkLogin(false);\n        $page_id = I(\"page_id/d\");\n        $page = I(\"page/d\", 1);\n        $count = I(\"count/d\", 20);\n\n        if (!$page_id) {\n            $this->sendError(10100, '缺少page_id参数');\n            return;\n        }\n\n        // 获取页面信息\n        $page_info = D(\"Page\")->where(\"page_id = %d\", array($page_id))->find();\n        if (!$page_info) {\n            $this->sendError(10101, '页面不存在');\n            return;\n        }\n\n        $item_id = $page_info['item_id'];\n        $login_user = session(\"login_user\");\n        $uid = $login_user['uid'] ? $login_user['uid'] : 0;\n\n        // 检查访问权限\n        if (!$this->checkItemVisit($uid, $item_id)) {\n            $this->sendError(10303);\n            return;\n        }\n\n        // 检查项目是否开启评论功能\n        $item_info = D(\"Item\")->where(\"item_id = %d\", array($item_id))->find();\n        if (!$item_info || $item_info['item_type'] != 1) {\n            // 非常规项目或未开启，返回空列表\n            $this->sendResult(array(\n                'total' => 0,\n                'page' => $page,\n                'comments' => array()\n            ));\n            return;\n        }\n\n        if (!$item_info['allow_comment']) {\n            // 未开启评论功能，返回空列表\n            $this->sendResult(array(\n                'total' => 0,\n                'page' => $page,\n                'comments' => array()\n            ));\n            return;\n        }\n\n        // 获取一级评论（分页）\n        $where = array(\n            'page_id' => $page_id,\n            'parent_id' => 0,\n            'is_deleted' => 0\n        );\n        $total = D(\"PageComment\")->where($where)->count();\n        $comments = D(\"PageComment\")->where($where)->order(\"addtime desc\")->page(\"$page, $count\")->select();\n\n        $result_comments = array();\n        if ($comments) {\n            foreach ($comments as $comment) {\n                $comment_data = $this->_formatComment($comment, $uid, $item_id);\n                // 获取该评论的所有回复（不分页）\n                $replies = D(\"PageComment\")->where(array(\n                    'parent_id' => $comment['comment_id'],\n                    'is_deleted' => 0\n                ))->order(\"addtime asc\")->select();\n                $comment_data['replies'] = array();\n                if ($replies) {\n                    foreach ($replies as $reply) {\n                        $comment_data['replies'][] = $this->_formatComment($reply, $uid, $item_id);\n                    }\n                }\n                $result_comments[] = $comment_data;\n            }\n        }\n\n        $this->sendResult(array(\n            'total' => (int)$total,\n            'page' => (int)$page,\n            'comments' => $result_comments\n        ));\n    }\n\n    //发表评论/回复\n    public function add()\n    {\n        $login_user = $this->checkLogin();\n        $page_id = I(\"page_id/d\");\n        $content = I(\"content\");\n        $parent_id = I(\"parent_id/d\", 0);\n\n        if (!$page_id) {\n            $this->sendError(10100, '缺少page_id参数');\n            return;\n        }\n\n        if (empty($content)) {\n            $this->sendError(10100, '评论内容不能为空');\n            return;\n        }\n\n        $content = trim($content);\n        $content_len = mb_strlen($content, 'UTF-8');\n        if ($content_len < 1 || $content_len > 500) {\n            $this->sendError(10100, '评论内容长度必须在1-500字符之间');\n            return;\n        }\n\n        // 防刷：10秒内最多1条评论\n        $last_comment_time = session('last_comment_time');\n        if ($last_comment_time && (time() - $last_comment_time) < 10) {\n            $this->sendError(10100, '评论过于频繁，请稍后再试');\n            return;\n        }\n\n        // 获取页面信息\n        $page_info = D(\"Page\")->where(\"page_id = %d\", array($page_id))->find();\n        if (!$page_info) {\n            $this->sendError(10101, '页面不存在');\n            return;\n        }\n\n        $item_id = $page_info['item_id'];\n        $uid = $login_user['uid'];\n\n        // 检查访问权限\n        if (!$this->checkItemVisit($uid, $item_id)) {\n            $this->sendError(10303);\n            return;\n        }\n\n        // 检查项目是否开启评论功能\n        $item_info = D(\"Item\")->where(\"item_id = %d\", array($item_id))->find();\n        if (!$item_info || $item_info['item_type'] != 1) {\n            $this->sendError(10100, '此项目类型不支持评论功能');\n            return;\n        }\n\n        if (!$item_info['allow_comment']) {\n            $this->sendError(10100, '项目未开启评论功能');\n            return;\n        }\n\n        // 如果是回复，检查父评论\n        if ($parent_id > 0) {\n            $parent_comment = D(\"PageComment\")->where(\"comment_id = %d\", array($parent_id))->find();\n            if (!$parent_comment || $parent_comment['is_deleted'] == 1) {\n                $this->sendError(10100, '被回复的评论不存在或已删除');\n                return;\n            }\n            // 检查父评论是否也是回复（仅支持两级）\n            if ($parent_comment['parent_id'] > 0) {\n                $this->sendError(10100, '仅支持两级评论，不能对回复再次回复');\n                return;\n            }\n        }\n\n        // 转义HTML，防止XSS\n        $content = htmlspecialchars($content, ENT_QUOTES, 'UTF-8');\n\n        // 保存评论\n        $comment_data = array(\n            'page_id' => $page_id,\n            'item_id' => $item_id,\n            'parent_id' => $parent_id,\n            'uid' => $uid,\n            'username' => $login_user['username'],\n            'content' => $content,\n            'is_deleted' => 0,\n            'addtime' => time()\n        );\n        $comment_id = D(\"PageComment\")->add($comment_data);\n\n        if (!$comment_id) {\n            $this->sendError(10101, '评论发表失败');\n            return;\n        }\n\n        // 更新最后评论时间\n        session('last_comment_time', time());\n\n        // 发送通知\n        $this->_sendCommentNotification($comment_id, $page_id, $item_id, $parent_id, $uid, $login_user['username'], $page_info['page_title']);\n\n        $this->sendResult(array(\n            'comment_id' => $comment_id,\n            'message' => '评论发表成功'\n        ));\n    }\n\n    //删除评论\n    public function delete()\n    {\n        $login_user = $this->checkLogin();\n        $comment_id = I(\"comment_id/d\");\n\n        if (!$comment_id) {\n            $this->sendError(10100, '缺少comment_id参数');\n            return;\n        }\n\n        $comment = D(\"PageComment\")->where(\"comment_id = %d\", array($comment_id))->find();\n        if (!$comment) {\n            $this->sendError(10101, '评论不存在');\n            return;\n        }\n\n        $uid = $login_user['uid'];\n        $item_id = $comment['item_id'];\n\n        // 检查权限：评论作者本人或项目管理员\n        $can_delete = false;\n        if ($comment['uid'] == $uid) {\n            $can_delete = true;\n        } elseif ($this->checkItemManage($uid, $item_id)) {\n            $can_delete = true;\n        }\n\n        if (!$can_delete) {\n            $this->sendError(10303, '无权限删除此评论');\n            return;\n        }\n\n        // 软删除\n        $result = D(\"PageComment\")->where(\"comment_id = %d\", array($comment_id))->save(array('is_deleted' => 1));\n\n        if ($result) {\n            $this->sendResult(array('message' => '删除成功'));\n        } else {\n            $this->sendError(10101, '删除失败');\n        }\n    }\n\n    //格式化评论数据\n    private function _formatComment($comment, $current_uid, $item_id)\n    {\n        $is_owner = ($comment['uid'] == $current_uid);\n        $can_delete = $is_owner || $this->checkItemManage($current_uid, $item_id);\n\n        return array(\n            'comment_id' => (int)$comment['comment_id'],\n            'parent_id' => (int)$comment['parent_id'],\n            'uid' => (int)$comment['uid'],\n            'username' => $comment['username'],\n            'content' => $comment['content'],\n            'addtime' => (int)$comment['addtime'],\n            'addtime_text' => date('Y-m-d H:i', $comment['addtime']),\n            'is_owner' => $is_owner,\n            'can_delete' => $can_delete\n        );\n    }\n\n    //发送评论通知\n    private function _sendCommentNotification($comment_id, $page_id, $item_id, $parent_id, $from_uid, $from_name, $page_title)\n    {\n        if ($parent_id == 0) {\n            // 场景1：新评论，通知项目管理员\n            $item_info = D(\"Item\")->where(\"item_id = %d\", array($item_id))->find();\n            $creator_uid = $item_info['uid'];\n\n            // 获取项目管理员（member_group_id = 2）\n            $managers = D(\"ItemMember\")->where(\"item_id = %d AND member_group_id = 2\", array($item_id))->select();\n            $team_managers = D(\"TeamItemMember\")->where(\"item_id = %d AND member_group_id = 2\", array($item_id))->select();\n\n            $notified_uids = array();\n            $notify_content = $from_name . ' 发表了新评论';\n\n            // 通知创建者\n            if ($creator_uid != $from_uid && !in_array($creator_uid, $notified_uids)) {\n                D(\"Message\")->addMsg($from_uid, $from_name, $creator_uid, 'remind', $notify_content, 'comment', 'page', $page_id);\n                $notified_uids[] = $creator_uid;\n            }\n\n            // 通知项目管理员\n            if ($managers) {\n                foreach ($managers as $manager) {\n                    $manager_uid = $manager['uid'];\n                    if ($manager_uid != $from_uid && !in_array($manager_uid, $notified_uids)) {\n                        D(\"Message\")->addMsg($from_uid, $from_name, $manager_uid, 'remind', $notify_content, 'comment', 'page', $page_id);\n                        $notified_uids[] = $manager_uid;\n                    }\n                }\n            }\n\n            // 通知团队项目管理员\n            if ($team_managers) {\n                foreach ($team_managers as $team_manager) {\n                    $team_manager_uid = $team_manager['member_uid'];\n                    if ($team_manager_uid != $from_uid && !in_array($team_manager_uid, $notified_uids)) {\n                        D(\"Message\")->addMsg($from_uid, $from_name, $team_manager_uid, 'remind', $notify_content, 'comment', 'page', $page_id);\n                        $notified_uids[] = $team_manager_uid;\n                    }\n                }\n            }\n        } else {\n            // 场景2：回复评论，通知被回复的作者（统一使用comment作为action_type）\n            $parent_comment = D(\"PageComment\")->where(\"comment_id = %d\", array($parent_id))->find();\n            $parent_uid = $parent_comment['uid'];\n\n            // 只通知原作者（不是自己）\n            if ($parent_uid != $from_uid) {\n                $notify_content = $from_name . ' 有新回复';\n                D(\"Message\")->addMsg($from_uid, $from_name, $parent_uid, 'remind', $notify_content, 'comment', 'page', $page_id);\n            }\n        }\n    }\n}\n\n"
  },
  {
    "path": "server/Application/Api/Controller/PageController.class.php",
    "content": "<?php\n\nnamespace Api\\Controller;\n\nuse Think\\Controller;\nuse Api\\Helper\\Convert;\n\nclass PageController extends BaseController\n{\n\n    //页面详情\n    public function info()\n    {\n        $page_id = I(\"page_id/d\");\n        $with_path = I(\"with_path/d\"); // 是否需要返回完整的路径信息\n        $page = D(\"Page\")->where(array('page_id' => $page_id))->find();\n        if (!$page  || $page['is_del'] == 1) {\n            sleep(1);\n            $this->sendError(10101);\n            return false;\n        }\n        $login_user = $this->checkLogin(false);\n        if (!$this->checkItemVisit($login_user['uid'], $page['item_id'])) {\n            $this->sendError(10103);\n            return;\n        }\n        $page = $page ? $page : array();\n        if ($page) {\n            //unset($page['page_content']);\n            $page['addtime'] = date(\"Y-m-d H:i:s\", $page['addtime']);\n            if ($page['page_addtime'] > 0) {\n                $page['page_addtime'] = date(\"Y-m-d H:i:s\", $page['page_addtime']);\n            } else {\n                $page['page_addtime'] = $page['addtime'];\n            }\n            //判断是否包含附件信息\n            $page['attachment_count'] = D(\"FilePage\")->where(array('page_id' => $page_id))->count();\n\n            $singlePage = M(\"SinglePage\")->where(\" page_id = '%d' \", array($page_id))->limit(1)->find();\n            if ($singlePage) {\n                // 检查单页链接是否已过期\n                if ($singlePage['expire_time'] > 0 && $singlePage['expire_time'] < time()) {\n                    // 链接已过期，从数据库中删除记录\n                    M(\"SinglePage\")->where(array('page_id' => $page_id))->delete();\n                    $page['unique_key'] = '';\n                } else {\n                    $page['unique_key'] = $singlePage['unique_key'];\n                }\n            } else {\n                $page['unique_key'] = '';\n            }\n\n            // 如果请求了完整路径信息，获取该页面的所有上级目录\n            if ($with_path && $page['cat_id']) {\n                $full_path = $this->getFullPath($page['cat_id'], $page['item_id']);\n                // 添加当前页面作为路径的最后一个元素\n                $full_path[] = array(\n                    'page_id' => $page['page_id'],\n                    'page_title' => $page['page_title']\n                );\n                $page['full_path'] = $full_path;\n            }\n        }\n        $this->sendResult($page);\n    }\n\n    /**\n     * 获取目录的完整路径\n     * @param int $cat_id 当前目录ID\n     * @param int $item_id 项目ID\n     * @return array 完整路径数组\n     */\n    private function getFullPath($cat_id, $item_id)\n    {\n        if (!$cat_id || !$item_id) {\n            return array();\n        }\n\n        // 获取项目的目录结构\n        $item = D(\"Item\")->where(\"item_id = '%d'\", array($item_id))->find();\n        if (!$item) {\n            return array();\n        }\n\n        // 递归查找目录路径\n        $path = array();\n        $this->findCatPath($cat_id, $item_id, $path);\n\n        // 返回路径（从上到下排序）\n        return array_reverse($path);\n    }\n\n    /**\n     * 递归查找目录路径\n     * @param int $cat_id 当前目录ID\n     * @param int $item_id 项目ID\n     * @param array &$path 路径数组（引用传递）\n     * @return boolean 是否找到路径\n     */\n    private function findCatPath($cat_id, $item_id, &$path)\n    {\n        // 查找当前目录信息\n        $catalog = D(\"Catalog\")->where(\"cat_id = '%d' AND item_id = '%d'\", array($cat_id, $item_id))->find();\n        if (!$catalog) {\n            return false;\n        }\n\n        // 添加当前目录到路径\n        $path[] = array(\n            'cat_id' => $catalog['cat_id'],\n            'cat_name' => $catalog['cat_name']\n        );\n\n        // 如果有父目录，继续递归查找\n        if ($catalog['parent_cat_id'] > 0) {\n            return $this->findCatPath($catalog['parent_cat_id'], $item_id, $path);\n        }\n\n        return true;\n    }\n\n    //删除页面\n    public function delete()\n    {\n        $page_id = I(\"post.page_id/d\") ? I(\"post.page_id/d\") : 0;\n        $page = D(\"Page\")->where(array('page_id' => $page_id))->find();\n\n        $login_user = $this->checkLogin();\n        if (!$this->checkItemManage($login_user['uid'], $page['item_id']) && $login_user['uid'] != $page['author_uid']) {\n            $this->sendError(10303);\n            return;\n        }\n\n        if ($page) {\n\n            $ret = D(\"Page\")->softDeletePage($page_id);\n            //更新项目时间\n            D(\"Item\")->where(array('item_id' => $page['item_id']))->save(array(\"last_update_time\" => time()));\n            \n            // 删除页面评论和反馈\n            D(\"PageComment\")->where(\"page_id = %d\", array($page_id))->delete();\n            D(\"PageFeedback\")->where(\"page_id = %d\", array($page_id))->delete();\n        }\n        if ($ret) {\n            D(\"ItemChangeLog\")->addLog($login_user['uid'],  $page['item_id'], 'delete', 'page', $page['page_id'], $page['page_title']);\n\n            // 先发送响应\n            $this->sendResult(array());\n\n            // 响应发送后，触发 AI 索引删除（异步，不阻塞删除流程）\n            if (function_exists('fastcgi_finish_request')) {\n                fastcgi_finish_request();\n            }\n\n            $this->triggerAiIndex($page['item_id'], $page['page_id'], 'delete');\n        } else {\n            $this->sendError(10101);\n        }\n    }\n\n    //保存\n    public function save()\n    {\n        $login_user = $this->checkLogin();\n        $page_id = I(\"page_id/d\") ? I(\"page_id/d\") : 0;\n        $is_urlencode = I(\"is_urlencode/d\") ? I(\"is_urlencode/d\") : 0; //页面内容是否经过了转义\n        $page_title = I(\"page_title\") ? I(\"page_title\") : L(\"default_title\");\n        $page_comments = I(\"page_comments\") ? I(\"page_comments\") : '';\n        $page_content = I(\"post.page_content\", \"\", \"\"); // 不进行htmlspecialchars过滤，后面再手工过滤\n        $cat_id = I(\"cat_id/d\") ? I(\"cat_id/d\") : 0;\n        $item_id = I(\"item_id/d\") ? I(\"item_id/d\") : 0;\n        $s_number = I(\"s_number/d\") ? I(\"s_number/d\") : '';\n        $is_notify = I(\"is_notify/d\") ? I(\"is_notify/d\") : 0;\n        $notify_content = I(\"notify_content\") ? I(\"notify_content\") : '';\n        $ext_info = I(\"ext_info\") ? I(\"ext_info\") : '';\n\n\n        $login_user = $this->checkLogin();\n\n        if (!$page_content) {\n            $this->sendError(10103, \"不允许保存空内容，请随便写点什么\");\n            return;\n        }\n        if ($is_urlencode) {\n            $page_content = urldecode($page_content);\n        }\n        // htmlspecialchars过滤\n        $page_content = htmlspecialchars($page_content);\n\n        if (!$this->checkItemEdit($login_user['uid'], $item_id)) {\n            $this->sendError(10103);\n            return;\n        }\n        $data = array();\n\n        $data['page_title'] = $page_title;\n        $data['page_content'] = $page_content;\n        $data['page_comments'] = $page_comments;\n        if ($s_number) $data['s_number'] = $s_number;\n        $data['item_id'] = $item_id;\n        $data['cat_id'] = $cat_id;\n        $data['addtime'] = time();\n        $data['page_addtime'] = time();\n        $data['author_uid'] = $login_user['uid'];\n        $data['author_username'] = $login_user['username'];\n        $data['ext_info'] = $ext_info;\n\n        $item_array = D(\"Item\")->where(array('item_id' => $item_id))->find();\n        \n        // 这里插入一段逻辑，对于runapi项目类型，填充ext_info字段\n        if (!$data['ext_info'] && $item_array['item_type'] == 3) {\n            $content_json = htmlspecialchars_decode($page_content);\n            $content = json_decode($content_json, true);\n            if ($content && $content['info'] && $content['info']['url']) {\n                // 判断协议类型（兼容旧数据）\n                $type = isset($content['info']['type']) ? $content['info']['type'] : 'api';\n\n                if ($type === 'websocket') {\n                    // WebSocket 接口\n                    $ext_info_array = array(\n                        \"page_type\" => \"websocket\",\n                        \"api_info\" => array(\n                            \"type\" => \"websocket\",\n                        )\n                    );\n                } elseif ($type === 'sse') {\n                    // SSE 接口\n                    $ext_info_array = array(\n                        \"page_type\" => \"sse\",\n                        \"api_info\" => array(\n                            \"type\" => \"sse\",\n                        )\n                    );\n                } else {\n                    // HTTP API 接口（兼容旧数据）\n                    $ext_info_array = array(\n                        \"page_type\" => \"api\",\n                        \"api_info\" => array(\n                            \"method\" => $content['info']['method'],\n                        )\n                    );\n                }\n\n                $data['ext_info'] = json_encode($ext_info_array);\n            }\n        }\n\n        if ($page_id > 0) {\n\n            // 设置里的历史版本数量\n            $history_version_count = D(\"Options\")->get(\"history_version_count\");\n            if (!$history_version_count) {\n                $history_version_count = 20;\n                D(\"Options\")->set(\"history_version_count\", $history_version_count);\n            }\n\n            //在保存前先把当前页面的版本存档\n            $page = D(\"Page\")->where(array('page_id' => $page_id))->find();\n            if (!$this->checkItemEdit($login_user['uid'], $page['item_id'])) {\n                $this->sendError(10103);\n                return;\n            }\n            $insert_history = array(\n                'page_id' => $page['page_id'],\n                'item_id' => $page['item_id'],\n                'cat_id' => $page['cat_id'],\n                'page_title' => $page['page_title'],\n                'page_comments' => $page['page_comments'],\n                'page_content' => base64_encode(gzcompress($page['page_content'], 9)),\n                's_number' => $page['s_number'],\n                'addtime' => $page['addtime'],\n                'author_uid' => $page['author_uid'],\n                'author_username' => $page['author_username'],\n                'ext_info' => $page['ext_info'],\n            );\n            D(\"PageHistory\")->add($insert_history);\n\n            if ($page['page_addtime'] > 0) {\n                $data['page_addtime'] = $page['page_addtime'];\n            }\n            $ret = D(\"Page\")->where(array('page_id' => $page_id))->save($data);\n\n            D(\"ItemChangeLog\")->addLog($login_user['uid'], $item_id, 'update', 'page', $page_id, $page_title);\n\n            //统计该page_id有多少历史版本了\n            $Count = D(\"PageHistory\")->where(array('page_id' => $page_id))->Count();\n            if ($Count > $history_version_count) {\n                //每个单页面只保留最多$history_version_count个历史版本\n                $ret = D(\"PageHistory\")->where(array('page_id' => $page_id))->limit($history_version_count)->order(\"page_history_id desc\")->select();\n                D(\"PageHistory\")->where(\" page_id = '%d' and page_history_id < %d \", array($page_id, $ret[$history_version_count - 1]['page_history_id']))->delete();\n            }\n\n            //如果是单页项目，则将页面标题设置为项目名\n            $item_array = D(\"Item\")->where(array('item_id' => $item_id))->find();\n            if ($item_array['item_type'] == 2) {\n                D(\"Item\")->where(array('item_id' => $item_id))->save(array(\"last_update_time\" => time(), \"item_name\" => $page_title));\n            } else {\n                D(\"Item\")->where(array('item_id' => $item_id))->save(array(\"last_update_time\" => time()));\n            }\n\n            if ($is_notify) {\n                // 检测订阅事件，根据订阅情况，将页面的更新消息发给通知用户\n                $subscription_array = D(\"Subscription\")->getListByObjectId($page_id, 'page', 'update');\n                if ($subscription_array) {\n                    foreach ($subscription_array as $skey => $svalue) {\n                        D(\"Message\")->addMsg($login_user['uid'], $login_user['username'], $svalue['uid'], 'remind', $notify_content, 'update', 'page', $page_id);\n                    }\n                }\n            }\n\n            $return = D(\"Page\")->where(array('page_id' => $page_id))->find();\n        } else {\n\n            $page_id = D(\"Page\")->add($data);\n\n            D(\"ItemChangeLog\")->addLog($login_user['uid'], $item_id, 'create', 'page', $page_id, $page_title);\n\n            //更新项目时间\n            D(\"Item\")->where(array('item_id' => $item_id))->save(array(\"last_update_time\" => time()));\n\n            // 添加页面的时候把最初的创建者加入消息订阅\n            D(\"Subscription\")->addSub($login_user['uid'], $page_id, 'page', 'update');\n\n            $return = D(\"Page\")->where(array('page_id' => $page_id))->find();\n        }\n        if (!$return) {\n            $return['error_code'] = 10103;\n            $return['error_message'] = 'request  fail';\n        }\n\n        // 先发送响应，确保用户能收到结果\n        $this->sendResult($return);\n\n        // 响应发送后，触发 AI 索引更新（异步，不阻塞保存流程）\n        // 使用 fastcgi_finish_request 确保在响应发送后执行（如果支持）\n        if (function_exists('fastcgi_finish_request')) {\n            fastcgi_finish_request();\n        }\n\n        // 触发索引更新（此时响应已发送，不会阻塞用户）\n        $this->triggerAiIndex($item_id, $page_id, $page_id > 0 ? 'update' : 'create');\n    }\n\n\n    //历史版本列表\n    public function history()\n    {\n        $login_user = $this->checkLogin(false);\n        $page_id = I(\"page_id/d\") ? I(\"page_id/d\") : 0;\n        $page = M(\"Page\")->where(array('page_id' => $page_id))->find();\n        if (!$this->checkItemVisit($login_user['uid'], $page['item_id'])) {\n            $this->sendError(10103);\n            return;\n        }\n\n        $PageHistory = D(\"PageHistory\")->where(array('page_id' => $page_id))->order(\" addtime desc\")->limit(20)->select();\n\n        if ($PageHistory) {\n            foreach ($PageHistory as $key => &$value) {\n                $value['addtime'] = date(\"Y-m-d H:i:s\", $value['addtime']);\n                $page_content = uncompress_string($value['page_content']);\n                if (!empty($page_content)) {\n                    $value['page_content'] = htmlspecialchars_decode($page_content);\n                    $value['page_content'] = htmlspecialchars($value['page_content'], ENT_NOQUOTES); // 不编码任何引号,以兼容json.同时转义其他字符串，以免xss\n                }\n            }\n\n            $this->sendResult($PageHistory);\n        } else {\n            $this->sendResult(array());\n        }\n    }\n\n\n    // 更新历史备注信息\n    public function updateHistoryComments()\n    {\n        $login_user = $this->checkLogin(false);\n        $page_id = I(\"page_id/d\") ? I(\"page_id/d\") : 0;\n        $page_comments = I(\"page_comments\");\n        $page_history_id = I(\"page_history_id/d\") ? I(\"page_history_id/d\") : 0;\n        $page = M(\"Page\")->where(array('page_id' => $page_id))->find();\n        if (!$this->checkItemEdit($login_user['uid'], $page['item_id'])) {\n            $this->sendError(10103);\n            return;\n        }\n        $res = D(\"PageHistory\")->where(array('page_history_id' => $page_history_id))->save(array(\n            \"page_comments\" => $page_comments\n        ));\n        $this->sendResult($res);\n    }\n\n    //返回当前页面和历史某个版本的页面以供比较\n    public function diff()\n    {\n        $page_id = I(\"page_id/d\");\n        $page_history_id = I(\"page_history_id/d\");\n        if (!$page_id) {\n            return false;\n        }\n        $page = M(\"Page\")->where(array('page_id' => $page_id))->find();\n        if (!$page) {\n            sleep(1);\n            $this->sendError(10101);\n            return false;\n        }\n        $login_user = $this->checkLogin(false);\n        if (!$this->checkItemVisit($login_user['uid'], $page['item_id'])) {\n            $this->sendError(10103);\n            return;\n        }\n\n        $history_page = D(\"PageHistory\")->where(array('page_history_id' => $page_history_id))->find();\n        $page_content = uncompress_string($history_page['page_content']);\n        $history_page['page_content'] = $page_content ? $page_content : $history_page['page_content'];\n\n        $this->sendResult(array(\"page\" => $page, \"history_page\" => $history_page));\n    }\n\n\n    //上传图片\n    public function uploadImg()\n    {\n        //重定向控制器和方法\n        R(\"Attachment/uploadImg\");\n    }\n\n    //上传附件\n    public function upload()\n    {\n        //重定向控制器和方法\n        R(\"Attachment/attachmentUpload\");\n    }\n\n    public function uploadList()\n    {\n        //重定向控制器和方法\n        R(\"Attachment/pageAttachmentUploadList\");\n    }\n\n    //删除已上传文件\n    public function deleteUploadFile()\n    {\n        //重定向控制器和方法\n        R(\"Attachment/deletePageUploadFile\");\n    }\n\n\n    //创建单页\n    public function createSinglePage()\n    {\n        $page_id = I(\"page_id/d\");\n        $isCreateSiglePage = I(\"isCreateSiglePage\");\n        $expire_days = I(\"expire_days/d\", 0); // 获取有效期天数，默认为0表示永久有效\n        $page = M(\"Page\")->where(array('page_id' => $page_id))->find();\n        if (!$page || $page['is_del'] == 1) {\n            sleep(1);\n            $this->sendError(10101);\n            return false;\n        }\n        $login_user = $this->checkLogin(false);\n        if (!$this->checkItemEdit($login_user['uid'], $page['item_id'])) {\n            $this->sendError(10103);\n            return;\n        }\n        D(\"SinglePage\")->where(array('page_id' => $page_id))->delete();\n        $unique_key = md5(time() . rand() . \"gbgdhbdgtfgfK3@bv45342regdhbdgtfgftghsdg\");\n\n        // 计算过期时间\n        $expire_time = 0; // 默认为0表示永久有效\n        if ($expire_days > 0) {\n            $expire_time = time() + ($expire_days * 24 * 60 * 60); // 当前时间加上天数换算成的秒数\n        }\n\n        $add = array(\n            \"unique_key\" => $unique_key,\n            \"page_id\" => $page_id,\n            \"expire_time\" => $expire_time\n        );\n        if ($isCreateSiglePage == 'true') { //这里的布尔值被转成字符串了\n            D(\"SinglePage\")->add($add);\n            $this->sendResult($add);\n        } else {\n            $this->sendResult(array());\n        }\n    }\n\n    //页面详情\n    public function infoByKey()\n    {\n        $unique_key = I(\"unique_key\");\n        if (!$unique_key) {\n            return false;\n        }\n        $singlePage = M(\"SinglePage\")->where(array('unique_key' => $unique_key))->find();\n        $page_id = $singlePage['page_id'];\n\n        // 检查链接是否已过期\n        if ($singlePage && $singlePage['expire_time'] > 0 && $singlePage['expire_time'] < time()) {\n            // 链接已过期，从数据库中删除记录\n            M(\"SinglePage\")->where(array('unique_key' => $unique_key))->delete();\n            $this->sendError(10101, \"该分享链接已过期\");\n            return false;\n        }\n\n        $page = M(\"Page\")->where(array('page_id' => $page_id))->find();\n        if (!$page || $page['is_del'] == 1) {\n            sleep(1);\n            $this->sendError(10101);\n            return false;\n        }\n        $login_user = $this->checkLogin(false);\n        $page = $page ? $page : array();\n        if ($page) {\n            unset($page['item_id']);\n            unset($page['cat_id']);\n            $page['addtime'] = date(\"Y-m-d H:i:s\", $page['addtime']);\n            //判断是否包含附件信息\n            $page['attachment_count'] = D(\"FilePage\")->where(array('page_id' => $page_id))->count();\n            // 添加单页链接过期时间字段\n            if ($singlePage) {\n                $page['expire_time'] = $singlePage['expire_time'];\n            }\n        }\n        $this->sendResult($page);\n    }\n\n    //同一个目录下的页面排序\n    public function sort()\n    {\n        $pages = I(\"pages\");\n        $item_id = I(\"item_id/d\");\n        $login_user = $this->checkLogin();\n        if (!$this->checkItemEdit($login_user['uid'], $item_id)) {\n            $this->sendError(10103);\n            return;\n        }\n        $ret = '';\n        $data_array = json_decode(htmlspecialchars_decode($pages), true);\n        if ($data_array) {\n            foreach ($data_array as $key => $value) {\n                $ret = D(\"Page\")->where(\" page_id = '%d' and item_id = '%d' \", array($key, $item_id))->save(array(\n                    \"s_number\" => $value,\n                ));\n            }\n        }\n\n        $this->sendResult(array());\n    }\n\n\n    //判断页面是否加了编辑锁\n    public function  isLock()\n    {\n        $page_id = I(\"page_id/d\");\n        $lock = 0;\n        $now = time();\n        $login_user = $this->checkLogin(false);\n        $res = D(\"PageLock\")->where(\" page_id = '%d' and page_id > 0 and lock_to > '%d' \", array($page_id, $now))->find();\n        if ($res) {\n            $lock = 1;\n        }\n        $this->sendResult(array(\n            \"lock\" => $lock,\n            \"lock_uid\" => $res['lock_uid'] ?  $res['lock_uid'] : '',\n            \"lock_username\" => $res['lock_username'] ? $res['lock_username'] : '',\n            \"is_cur_user\" => $res['lock_uid'] == $login_user['uid'] ? 1 : 0,\n        ));\n    }\n\n    //设置页面加锁时间\n    public function setLock()\n    {\n        $page_id = I(\"page_id/d\");\n        $lock_to = I(\"lock_to/d\") ? I(\"lock_to/d\") : (time() + 5 * 60 * 60);\n        $item_id = I(\"item_id/d\");\n        $login_user = $this->checkLogin();\n        if (!$this->checkItemEdit($login_user['uid'], $item_id)) {\n            $this->sendError(10103);\n            return;\n        }\n        D(\"PageLock\")->where(array('page_id' => $page_id))->delete();\n        $id = D(\"PageLock\")->add(array(\n            \"page_id\" => $page_id,\n            \"lock_uid\" => $login_user['uid'],\n            \"lock_username\" => $login_user['username'],\n            \"lock_to\" => $lock_to,\n            \"addtime\" => time(),\n        ));\n        $now = time();\n        D(\"PageLock\")->where(array('lock_to' => array('lt', $now)))->delete();\n        $this->sendResult(array(\"id\" => $id));\n    }\n\n    // 转换 SQL 为 Markdown 表格\n    public function sqlToMarkdownTable()\n    {\n        $sql = I(\"sql\",\"\",\"\");\n        $object = new Convert();\n        $res = $object->convertSqlToMarkdownTable($sql);\n        $this->sendResult(array(\"markdown\" => $res));\n    }\n\n    /**\n     * 触发 AI 索引更新（异步）\n     */\n    private function triggerAiIndex($item_id, $page_id, $action = 'update')\n    {\n        try {\n            // 检查 AI 服务是否配置（系统级）\n            $ai_service_url = D(\"Options\")->get(\"ai_service_url\");\n            $ai_service_token = D(\"Options\")->get(\"ai_service_token\");\n\n            if (!$ai_service_url || !$ai_service_token) {\n                return; // AI 服务未配置，不触发索引\n            }\n\n            // 检查项目级开关\n            // 检查项目是否存在且启用了 AI 知识库功能（使用新表）\n            $config = D(\"ItemAiConfig\")->getConfig($item_id);\n            if (empty($config['enabled'])) {\n                return; // 项目未启用 AI 知识库功能，不触发索引\n            }\n\n            // 如果是删除操作，直接调用删除接口\n            if ($action == 'delete') {\n                $url = rtrim($ai_service_url, '/') . '/api/index/delete';\n                $ai_service_token = D(\"Options\")->get(\"ai_service_token\");\n                \\Api\\Helper\\AiHelper::callAiServiceAsync($url, array(\n                    'item_id' => $item_id,\n                    'page_id' => $page_id\n                ), $ai_service_token, 'DELETE');\n                return;\n            }\n\n            // 异步触发索引更新（使用简单的 HTTP 请求，不等待响应）\n            $url = rtrim($ai_service_url, '/') . '/api/index/upsert';\n\n            // 确保获取最新数据：先删除缓存，再从数据库读取\n            D(\"Page\")->deleteCache($page_id);\n            // 稍作延迟，确保数据库事务已提交（如果使用事务）\n            usleep(100000); // 延迟 0.1 秒\n\n            // 获取页面信息（开源版没有分表，直接使用 D(\"Page\")->where 查询）\n            $page = D(\"Page\")->where(array('page_id' => $page_id))->find();\n            if (!$page || $page['is_del'] == 1) {\n                return;\n            }\n\n            $content = $page['page_content'];\n            $pageType = isset($page['page_type']) ? $page['page_type'] : 'regular';\n\n            // HTML 反转义（因为存储的内容是 HTML 转义的）\n            $content = html_entity_decode($content, ENT_QUOTES | ENT_HTML5, 'UTF-8');\n\n            // 使用 Convert 类转换为 Markdown（如果是 API 文档会自动转换，否则返回 false）\n            $convert = new Convert();\n            $md_content = $convert->runapiToMd($content);\n            if ($md_content !== false) {\n                $content = $md_content;\n            }\n\n            // 跳过空内容\n            if (empty($content) || trim($content) === '') {\n                return;\n            }\n\n            // 获取目录名称，拼接到标题便于 AI 搜索（接口无 cat_name 参数）\n            $cat_name = '';\n            if ($page['cat_id'] > 0) {\n                $catalog = D(\"Catalog\")->where(array('cat_id' => $page['cat_id'], 'item_id' => $item_id))->find();\n                if ($catalog) {\n                    $cat_name = $catalog['cat_name'];\n                }\n            }\n            $page_title = $page['page_title'];\n            if ($cat_name !== '') {\n                $page_title = $cat_name . ' / ' . $page_title;\n            }\n\n            $postData = array(\n                'item_id' => $item_id,\n                'page_id' => $page_id,\n                'page_title' => $page_title,\n                'page_content' => $content,\n                'page_type' => $pageType,\n                'update_time' => isset($page['update_time']) ? $page['update_time'] : time()\n            );\n\n            $ai_service_token = D(\"Options\")->get(\"ai_service_token\");\n            \\Api\\Helper\\AiHelper::callAiServiceAsync($url, $postData, $ai_service_token);\n        } catch (\\Exception $e) {\n            // 只记录错误日志\n            \\Think\\Log::record(\"AI索引触发失败: item_id={$item_id}, page_id={$page_id}, \" . $e->getMessage());\n        }\n    }\n\n}\n"
  },
  {
    "path": "server/Application/Api/Controller/PageFeedbackController.class.php",
    "content": "<?php\n\nnamespace Api\\Controller;\n\nuse Think\\Controller;\n\nclass PageFeedbackController extends BaseController\n{\n\n    //获取反馈统计\n    public function getStat()\n    {\n        $this->checkLogin(false);\n        $page_id = I(\"page_id/d\");\n        $client_id = I(\"client_id\");\n\n        if (!$page_id) {\n            $this->sendError(10100, '缺少page_id参数');\n            return;\n        }\n\n        // 获取页面信息\n        $page_info = D(\"Page\")->where(\"page_id = %d\", array($page_id))->find();\n        if (!$page_info) {\n            $this->sendError(10101, '页面不存在');\n            return;\n        }\n\n        $item_id = $page_info['item_id'];\n        $login_user = session(\"login_user\");\n        $uid = $login_user['uid'] ? $login_user['uid'] : 0;\n\n        // 检查访问权限\n        if (!$this->checkItemVisit($uid, $item_id)) {\n            $this->sendError(10303);\n            return;\n        }\n\n        // 检查项目是否开启反馈功能\n        $item_info = D(\"Item\")->where(\"item_id = %d\", array($item_id))->find();\n        if (!$item_info || $item_info['item_type'] != 1) {\n            // 非常规项目或未开启，返回空统计\n            $this->sendResult(array(\n                'helpful_count' => 0,\n                'unhelpful_count' => 0,\n                'user_feedback' => 0\n            ));\n            return;\n        }\n\n        if (!$item_info['allow_feedback']) {\n            // 未开启反馈功能，返回空统计\n            $this->sendResult(array(\n                'helpful_count' => 0,\n                'unhelpful_count' => 0,\n                'user_feedback' => 0\n            ));\n            return;\n        }\n\n        // 统计数量\n        $helpful_count = D(\"PageFeedback\")->where(array(\n            'page_id' => $page_id,\n            'feedback_type' => 1\n        ))->count();\n\n        $unhelpful_count = D(\"PageFeedback\")->where(array(\n            'page_id' => $page_id,\n            'feedback_type' => 2\n        ))->count();\n\n        // 获取当前用户/浏览器的反馈\n        $user_feedback = 0;\n        if ($uid > 0) {\n            // 登录用户\n            $feedback = D(\"PageFeedback\")->where(array(\n                'page_id' => $page_id,\n                'uid' => $uid\n            ))->find();\n            if ($feedback) {\n                $user_feedback = (int)$feedback['feedback_type'];\n            }\n        } elseif ($client_id) {\n            // 游客\n            $feedback = D(\"PageFeedback\")->where(array(\n                'page_id' => $page_id,\n                'client_id' => $client_id\n            ))->find();\n            if ($feedback) {\n                $user_feedback = (int)$feedback['feedback_type'];\n            }\n        }\n\n        $this->sendResult(array(\n            'helpful_count' => (int)$helpful_count,\n            'unhelpful_count' => (int)$unhelpful_count,\n            'user_feedback' => $user_feedback\n        ));\n    }\n\n    //提交/修改反馈\n    public function submit()\n    {\n        $this->checkLogin(false);\n        $page_id = I(\"page_id/d\");\n        $feedback_type = I(\"feedback_type/d\");\n        $client_id = I(\"client_id\");\n\n        if (!$page_id) {\n            $this->sendError(10100, '缺少page_id参数');\n            return;\n        }\n\n        if ($feedback_type != 1 && $feedback_type != 2) {\n            $this->sendError(10100, 'feedback_type参数错误，必须为1或2');\n            return;\n        }\n\n        // 获取页面信息\n        $page_info = D(\"Page\")->where(\"page_id = %d\", array($page_id))->find();\n        if (!$page_info) {\n            $this->sendError(10101, '页面不存在');\n            return;\n        }\n\n        $item_id = $page_info['item_id'];\n        $login_user = session(\"login_user\");\n        $uid = $login_user['uid'] ? $login_user['uid'] : 0;\n\n        // 检查访问权限\n        if (!$this->checkItemVisit($uid, $item_id)) {\n            $this->sendError(10303);\n            return;\n        }\n\n        // 检查项目是否开启反馈功能\n        $item_info = D(\"Item\")->where(\"item_id = %d\", array($item_id))->find();\n        if (!$item_info || $item_info['item_type'] != 1) {\n            $this->sendError(10100, '此项目类型不支持反馈功能');\n            return;\n        }\n\n        if (!$item_info['allow_feedback']) {\n            $this->sendError(10100, '项目未开启反馈功能');\n            return;\n        }\n\n        // 游客必须提供client_id\n        if ($uid == 0 && empty($client_id)) {\n            $this->sendError(10100, '游客必须提供client_id参数');\n            return;\n        }\n\n        // 查询现有反馈\n        $where = array('page_id' => $page_id);\n        if ($uid > 0) {\n            $where['uid'] = $uid;\n        } else {\n            $where['client_id'] = $client_id;\n        }\n\n        $existing_feedback = D(\"PageFeedback\")->where($where)->find();\n\n        if ($existing_feedback) {\n            // 已有反馈记录\n            if ($existing_feedback['feedback_type'] == $feedback_type) {\n                // 相同类型：取消反馈（删除）\n                D(\"PageFeedback\")->where(\"feedback_id = %d\", array($existing_feedback['feedback_id']))->delete();\n            } else {\n                // 不同类型：更新反馈\n                D(\"PageFeedback\")->where(\"feedback_id = %d\", array($existing_feedback['feedback_id']))->save(array(\n                    'feedback_type' => $feedback_type,\n                    'addtime' => time()\n                ));\n            }\n        } else {\n            // 新增反馈\n            $feedback_data = array(\n                'page_id' => $page_id,\n                'item_id' => $item_id,\n                'uid' => $uid,\n                'feedback_type' => $feedback_type,\n                'addtime' => time()\n            );\n            // 登录用户设置client_id为NULL，游客才设置client_id\n            // 注意：必须显式设置为NULL，不能省略，否则会使用默认值''导致唯一约束冲突\n            if ($uid == 0) {\n                $feedback_data['client_id'] = $client_id;\n            } else {\n                $feedback_data['client_id'] = null; // 登录用户设为NULL，避免与空字符串冲突\n            }\n            D(\"PageFeedback\")->add($feedback_data);\n        }\n\n        // 重新统计并返回\n        $helpful_count = D(\"PageFeedback\")->where(array(\n            'page_id' => $page_id,\n            'feedback_type' => 1\n        ))->count();\n\n        $unhelpful_count = D(\"PageFeedback\")->where(array(\n            'page_id' => $page_id,\n            'feedback_type' => 2\n        ))->count();\n\n        $this->sendResult(array(\n            'message' => '感谢您的反馈',\n            'helpful_count' => (int)$helpful_count,\n            'unhelpful_count' => (int)$unhelpful_count,\n            'user_feedback' => $feedback_type\n        ));\n    }\n}\n\n"
  },
  {
    "path": "server/Application/Api/Controller/ParamDescLibController.class.php",
    "content": "<?php\n\nnamespace Api\\Controller;\n\nuse Think\\Controller;\n\nclass ParamDescLibController extends BaseController\n{\n\n  /**\n   * 查询参数描述库条目\n   */\n  public function getEntries()\n  {\n    $this->_getEntries();\n  }\n\n  /**\n   * 创建参数描述库条目\n   */\n  public function addEntry()\n  {\n    $this->_createEntry();\n  }\n\n  /**\n   * 批量删除条目\n   */\n  public function deleteEntries()\n  {\n    $this->_deleteEntries();\n  }\n\n  /**\n   * 删除单个条目\n   */\n  public function deleteEntry()\n  {\n    $this->_deleteEntry();\n  }\n\n  /**\n   * 更新条目\n   */\n  public function updateEntry()\n  {\n    $this->_updateEntry();\n  }\n\n  /**\n   * 添加临时条目\n   */\n  public function addTempEntry()\n  {\n    $this->temp();\n  }\n\n  /**\n   * 临时条目转永久\n   */\n  public function promoteTemp()\n  {\n    $this->_promoteTemp();\n  }\n\n  /**\n   * 确认导入\n   */\n  public function confirmImport()\n  {\n    $this->_confirmImport();\n  }\n\n  /**\n   * 批量添加条目\n   */\n  public function addBatchEntries()\n  {\n    $this->_addBatchEntries();\n  }\n\n  /**\n   * 更新使用次数\n   */\n  public function updateUsage()\n  {\n    $this->_updateUsage();\n  }\n\n  /**\n   * 批量保存参数描述库条目（覆盖保存）\n   */\n  public function batchSave()\n  {\n    $this->_batchSave();\n  }\n\n  /**\n   * 批量保存参数描述库条目（覆盖保存）\n   */\n  private function _batchSave()\n  {\n    $login_user = $this->checkLogin();\n    $uid = $login_user['uid'];\n\n    $item_id = I(\"itemId/d\");\n    $entries = I(\"entries\", [], \"\", \"\");\n    // 兼容前端以 JSON 字符串提交 entries 的情况\n    if (is_string($entries)) {\n      $decoded = json_decode($entries, true);\n      if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) {\n        $entries = $decoded;\n      }\n    }\n\n    if (!$item_id) {\n      $this->sendError(10001, '缺少项目ID');\n      return;\n    }\n\n    if (!$this->checkItemEdit($uid, $item_id)) {\n      $this->sendError(10303);\n      return;\n    }\n\n    if (empty($entries)) {\n      $this->sendError(10001, '没有要保存的条目');\n      return;\n    }\n\n    try {\n      // 1. 删除该项目下所有永久条目\n      $deleteResult = D(\"ParameterDescriptionEntry\")\n        ->where(array(\n          'item_id' => $item_id,\n          'status' => 'permanent'\n        ))\n        ->delete();\n      // 2. 批量创建新的永久条目\n      $createdEntries = [];\n      foreach ($entries as $entry) {\n        // 容错：确保是数组\n        if (!is_array($entry)) {\n          continue;\n        }\n        // 兼容中文状态值，默认按永久处理\n        $statusVal = isset($entry['status']) ? $entry['status'] : 'permanent';\n        if ($statusVal === '永久') {\n          $statusVal = 'permanent';\n        }\n        // 只保存永久条目，临时条目由前端内存管理\n        if ($statusVal === 'permanent') {\n          // 计算质量评分\n          $qualityScore = $this->calculateQualityScore([\n            'description' => $entry['description'],\n            'example' => $entry['example'] ?? '',\n            'enumValues' => $entry['enumValues'] ?? [],\n            'defaultValue' => $entry['defaultValue'] ?? '',\n            'usageCount' => $entry['usageCount'] ?? 0\n          ]);\n\n          $data = [\n            'id' => $this->generateId(),\n            'item_id' => $item_id,\n            'name' => $entry['name'],\n            'type' => $entry['type'],\n            'description' => $entry['description'],\n            'example' => $entry['example'] ?? '',\n            'default_value' => $entry['defaultValue'] ?? '',\n            'aliases' => json_encode($entry['aliases'] ?? []),\n            'tags' => json_encode($entry['tags'] ?? []),\n            'path' => $entry['path'] ?? '',\n            'source' => $entry['source'] ?? 'manual',\n            'status' => 'permanent',\n            'usage_count' => $entry['usageCount'] ?? 0,\n            'quality_score' => $qualityScore,\n            'created_by' => $uid,\n            'created_at' => date(\"Y-m-d H:i:s\"),\n            'updated_at' => date(\"Y-m-d H:i:s\")\n          ];\n\n          if (!empty($entry['enumValues']) && is_array($entry['enumValues'])) {\n            $data['enum_values'] = json_encode($entry['enumValues']);\n          }\n\n          $id = D(\"ParameterDescriptionEntry\")->add($data);\n          if ($id) {\n            $createdEntry = D(\"ParameterDescriptionEntry\")->where(array('id' => $data['id']))->find();\n            $createdEntries[] = $this->convertEntryFields($createdEntry);\n          }\n        }\n      }\n\n      $this->sendResult($createdEntries);\n    } catch (\\Exception $e) {\n      $this->sendError(10001, '批量保存失败: ' . $e->getMessage());\n    }\n  }\n\n  /**\n   * 获取参数描述库条目列表\n   */\n  private function _getEntries()\n  {\n    $login_user = $this->checkLogin();\n    $uid = $login_user['uid'];\n\n    $item_id = I(\"itemId/d\");\n    $keyword = I(\"keyword\", \"\");\n    $status = I(\"status\", \"\");\n    $name = I(\"name\", \"\");\n    $type = I(\"type\", \"\");\n    $tag = I(\"tag\", \"\");\n    $page = I(\"page/d\", 1);\n    $pageSize = I(\"pageSize/d\", 20);\n\n    if (!$item_id) {\n      $this->sendError(10001, '缺少项目ID');\n      return;\n    }\n\n    if (!$this->checkItemEdit($uid, $item_id)) {\n      $this->sendError(10303);\n      return;\n    }\n\n    $where = \"item_id = %d\";\n    $params = array($item_id);\n\n    // 添加搜索条件\n    if ($keyword) {\n      $like = safe_like($keyword);\n      $where .= \" AND (name LIKE '%s' OR description LIKE '%s')\";\n      array_push($params, $like, $like);\n    }\n\n    if ($status) {\n      $where .= \" AND status = '%s'\";\n      $params[] = $status;\n    }\n\n    if ($name) {\n      $where .= \" AND name = '%s'\";\n      $params[] = $name;\n    }\n\n    if ($type) {\n      $where .= \" AND type = '%s'\";\n      $params[] = $type;\n    }\n\n    if ($tag) {\n      $like_tag = '%\"' . safe_like($tag) . '\"%';\n      $where .= \" AND tags LIKE '%s'\";\n      $params[] = $like_tag;\n    }\n\n    // 计算总数\n    $total = D(\"ParameterDescriptionEntry\")->where($where, $params)->count();\n\n    // 获取分页数据\n    $offset = ($page - 1) * $pageSize;\n    $entries = D(\"ParameterDescriptionEntry\")\n      ->where($where, $params)\n      ->order(\"quality_score DESC, usage_count DESC, updated_at DESC\")\n      ->limit($offset, $pageSize)\n      ->select();\n\n    // 处理JSON字段并转换字段名为前端期望的驼峰格式\n    foreach ($entries as &$entry) {\n      $entry = $this->convertEntryFields($entry);\n    }\n\n    $this->sendResult([\n      'data' => $entries,\n      'total' => $total,\n      'page' => $page,\n      'pageSize' => $pageSize\n    ]);\n  }\n\n  /**\n   * 创建参数描述库条目\n   */\n  private function _createEntry()\n  {\n    $login_user = $this->checkLogin();\n    $uid = $login_user['uid'];\n\n    $item_id = I(\"itemId/d\");\n    $name = I(\"name\", \"\");\n    $type = I(\"type\", \"string\");\n    $description = I(\"description\", \"\");\n    $example = I(\"example\", \"\");\n    $enumValues = I(\"enumValues\", []);\n    $defaultValue = I(\"defaultValue\", \"\");\n    $aliases = I(\"aliases\", []);\n    $tags = I(\"tags\", []);\n    $path = I(\"path\", \"\");\n    $source = I(\"source\", \"manual\");\n    $status = I(\"status\", \"permanent\");\n\n    if (!$item_id || !$name || !$description) {\n      $this->sendError(10001, '缺少必要参数');\n      return;\n    }\n\n    if (!$this->checkItemEdit($uid, $item_id)) {\n      $this->sendError(10303);\n      return;\n    }\n\n    // 检查是否已存在相同的条目\n    $existing = D(\"ParameterDescriptionEntry\")\n      ->where(array(\n        'item_id' => $item_id,\n        'name' => $name,\n        'type' => $type\n      ))\n      ->find();\n\n    if ($existing) {\n      $this->sendError(10001, '已存在相同的字段名和类型');\n      return;\n    }\n\n    // 计算质量评分\n    $qualityScore = $this->calculateQualityScore([\n      'description' => $description,\n      'example' => $example,\n      'enumValues' => $enumValues,\n      'defaultValue' => $defaultValue,\n      'usageCount' => 0\n    ]);\n\n    $data = [\n      'id' => $this->generateId(),\n      'item_id' => $item_id,\n      'name' => $name,\n      'type' => $type,\n      'description' => $description,\n      'example' => $example,\n      'default_value' => $defaultValue,\n      'aliases' => json_encode($aliases),\n      'tags' => json_encode($tags),\n      'path' => $path,\n      'source' => $source,\n      'status' => $status,\n      'usage_count' => 0,\n      'quality_score' => $qualityScore,\n      'created_by' => $uid,\n      'created_at' => date(\"Y-m-d H:i:s\"),\n      'updated_at' => date(\"Y-m-d H:i:s\")\n    ];\n\n    if (!empty($enumValues)) {\n      $data['enum_values'] = json_encode($enumValues);\n    }\n\n    $id = D(\"ParameterDescriptionEntry\")->add($data);\n\n    if ($id) {\n      // 返回创建的条目\n      $entry = D(\"ParameterDescriptionEntry\")->where(array('id' => $data['id']))->find();\n\n      // 字段转换和处理\n      $entry = $this->convertEntryFields($entry);\n\n      $this->sendResult($entry);\n    } else {\n      $this->sendError(10001, '创建失败');\n    }\n  }\n\n  /**\n   * 批量删除条目\n   */\n  private function _deleteEntries()\n  {\n    $login_user = $this->checkLogin();\n    $uid = $login_user['uid'];\n\n    $ids = I(\"ids\", \"\");\n\n    // 处理前端传来的逗号分隔字符串\n    if (is_string($ids)) {\n      $ids = array_filter(explode(',', $ids));\n    } elseif (!is_array($ids)) {\n      $ids = [];\n    }\n\n    if (empty($ids)) {\n      $this->sendError(10001, '缺少要删除的ID');\n      return;\n    }\n\n    // 检查权限 - 获取第一个条目的item_id进行权限验证\n    $firstEntry = D(\"ParameterDescriptionEntry\")->where(array('id' => $ids[0]))->find();\n    if (!$firstEntry) {\n      $this->sendError(10001, '条目不存在');\n      return;\n    }\n\n    if (!$this->checkItemEdit($uid, $firstEntry['item_id'])) {\n      $this->sendError(10303);\n      return;\n    }\n\n    // 构建删除条件\n    $result = D(\"ParameterDescriptionEntry\")->where(array('id' => array('in', $ids)))->delete();\n\n    if ($result) {\n      $this->sendResult(['deleted' => count($ids)]);\n    } else {\n      $this->sendError(10001, '删除失败');\n    }\n  }\n\n  /**\n   * 更新单个条目\n   */\n  private function _updateEntry()\n  {\n    $login_user = $this->checkLogin();\n    $uid = $login_user['uid'];\n\n    // 从POST参数中获取ID\n    $id = I(\"id\", \"\");\n    if (!$id) {\n      $this->sendError(10001, '缺少条目ID');\n      return;\n    }\n\n    // 检查条目是否存在\n    $entry = D(\"ParameterDescriptionEntry\")->where(array('id' => $id))->find();\n    if (!$entry) {\n      $this->sendError(10001, '条目不存在');\n      return;\n    }\n\n    if (!$this->checkItemEdit($uid, $entry['item_id'])) {\n      $this->sendError(10303);\n      return;\n    }\n\n    // 获取更新数据\n    $updateData = [];\n\n    $fields = ['name', 'type', 'description', 'example', 'defaultValue', 'path', 'source', 'status'];\n    foreach ($fields as $field) {\n      $value = I($field);\n      if ($value !== null) {\n        if ($field === 'defaultValue') {\n          $updateData['default_value'] = $value;\n        } else {\n          $updateData[$field] = $value;\n        }\n      }\n    }\n\n    // 处理数组字段\n    $aliases = I(\"aliases\");\n    if ($aliases !== null) {\n      $updateData['aliases'] = json_encode($aliases);\n    }\n\n    $tags = I(\"tags\");\n    if ($tags !== null) {\n      $updateData['tags'] = json_encode($tags);\n    }\n\n    $enumValues = I(\"enumValues\");\n    if ($enumValues !== null) {\n      $updateData['enum_values'] = json_encode($enumValues);\n    }\n\n    if (!empty($updateData)) {\n      $updateData['updated_at'] = date(\"Y-m-d H:i:s\");\n\n      // 重新计算质量评分\n      if (isset($updateData['description']) || isset($updateData['example']) || isset($updateData['enum_values']) || isset($updateData['default_value'])) {\n        $mergedData = array_merge($entry, $updateData);\n        $mergedData['enumValues'] = isset($updateData['enum_values']) ? json_decode($updateData['enum_values'], true) : json_decode($entry['enum_values'], true);\n        $updateData['quality_score'] = $this->calculateQualityScore($mergedData);\n      }\n\n      $result = D(\"ParameterDescriptionEntry\")->where(array('id' => $id))->save($updateData);\n\n      if ($result !== false) {\n        // 返回更新后的条目\n        $updatedEntry = D(\"ParameterDescriptionEntry\")->where(array('id' => $id))->find();\n\n        // 字段转换和处理\n        $updatedEntry = $this->convertEntryFields($updatedEntry);\n\n        $this->sendResult($updatedEntry);\n      } else {\n        $this->sendError(10001, '更新失败');\n      }\n    } else {\n      $this->sendError(10001, '没有要更新的数据');\n    }\n  }\n\n  /**\n   * 删除单个条目\n   */\n  private function _deleteEntry()\n  {\n    $login_user = $this->checkLogin();\n    $uid = $login_user['uid'];\n\n    $id = I(\"id\", \"\");\n    if (!$id) {\n      $this->sendError(10001, '缺少条目ID');\n      return;\n    }\n\n    // 检查条目是否存在\n    $entry = D(\"ParameterDescriptionEntry\")->where(array('id' => $id))->find();\n    if (!$entry) {\n      $this->sendError(10001, '条目不存在');\n      return;\n    }\n\n    if (!$this->checkItemEdit($uid, $entry['item_id'])) {\n      $this->sendError(10303);\n      return;\n    }\n\n    $result = D(\"ParameterDescriptionEntry\")->where(array('id' => $id))->delete();\n\n    if ($result) {\n      $this->sendResult(['deleted' => 1]);\n    } else {\n      $this->sendError(10001, '删除失败');\n    }\n  }\n\n\n\n  /**\n   * 创建临时条目\n   */\n  public function temp()\n  {\n    $_POST['status'] = 'temp';\n    $this->_createEntry();\n  }\n\n  /**\n   * 临时条目转永久\n   */\n  private function _promoteTemp()\n  {\n    $login_user = $this->checkLogin();\n    $uid = $login_user['uid'];\n\n    $ids = I(\"ids\", \"\");\n\n    // 处理前端传来的逗号分隔字符串\n    if (is_string($ids)) {\n      $ids = array_filter(explode(',', $ids));\n    } elseif (!is_array($ids)) {\n      $ids = [];\n    }\n\n    if (empty($ids)) {\n      $this->sendError(10001, '缺少要转换的ID');\n      return;\n    }\n\n    // 检查权限\n    $firstEntry = D(\"ParameterDescriptionEntry\")->where(array('id' => $ids[0]))->find();\n    if (!$firstEntry) {\n      $this->sendError(10001, '条目不存在');\n      return;\n    }\n\n    if (!$this->checkItemEdit($uid, $firstEntry['item_id'])) {\n      $this->sendError(10303);\n      return;\n    }\n\n    $result = D(\"ParameterDescriptionEntry\")\n      ->where(array('id' => array('in', $ids)))\n      ->save(array(\n        'status' => 'permanent',\n        'updated_at' => date(\"Y-m-d H:i:s\")\n      ));\n\n    if ($result !== false) {\n      $this->sendResult(['promoted' => count($ids)]);\n    } else {\n      $this->sendError(10001, '转换失败');\n    }\n  }\n\n\n\n  /**\n   * 获取统计信息\n   */\n  public function stats()\n  {\n    $login_user = $this->checkLogin();\n    $uid = $login_user['uid'];\n\n    $item_id = I(\"itemId/d\");\n\n    if (!$item_id) {\n      $this->sendError(10001, '缺少项目ID');\n      return;\n    }\n\n    if (!$this->checkItemEdit($uid, $item_id)) {\n      $this->sendError(10303);\n      return;\n    }\n\n    // 总数统计\n    $totalCount = D(\"ParameterDescriptionEntry\")->where(array('item_id' => $item_id))->count();\n    $permanentCount = D(\"ParameterDescriptionEntry\")->where(array('item_id' => $item_id, 'status' => 'permanent'))->count();\n    $tempCount = D(\"ParameterDescriptionEntry\")->where(array('item_id' => $item_id, 'status' => 'temp'))->count();\n\n    // Top使用字段\n    $topFields = D(\"ParameterDescriptionEntry\")\n      ->where(array('item_id' => $item_id))\n      ->field(\"name, usage_count\")\n      ->order(\"usage_count DESC\")\n      ->limit(10)\n      ->select();\n\n    $topFieldsFormatted = [];\n    foreach ($topFields as $field) {\n      $topFieldsFormatted[] = [\n        'name' => $field['name'],\n        'count' => intval($field['usage_count'])\n      ];\n    }\n\n    $this->sendResult([\n      'totalCount' => $totalCount,\n      'permanentCount' => $permanentCount,\n      'tempCount' => $tempCount,\n      'coverageRate' => $totalCount > 0 ? round($permanentCount / $totalCount * 100, 2) : 0,\n      'hitRate' => 0, // 需要根据实际使用情况计算\n      'topFields' => $topFieldsFormatted\n    ]);\n  }\n\n  /**\n   * 导入数据\n   */\n  public function import()\n  {\n    $login_user = $this->checkLogin();\n    $uid = $login_user['uid'];\n\n    $item_id = I(\"itemId/d\");\n    $format = I(\"format\", \"\");\n    $rawText = I(\"rawText\", \"\");\n\n    if (!$item_id || !$format || !$rawText) {\n      $this->sendError(10001, '缺少必要参数');\n      return;\n    }\n\n    if (!$this->checkItemEdit($uid, $item_id)) {\n      $this->sendError(10303);\n      return;\n    }\n\n    $parsed = $this->parseImportData($format, $rawText);\n    if (!$parsed) {\n      $this->sendError(10001, '数据格式错误');\n      return;\n    }\n\n    $newEntries = [];\n    $duplicatedEntries = [];\n\n    foreach ($parsed as $data) {\n      // 检查是否已存在\n      $existing = D(\"ParameterDescriptionEntry\")\n        ->where(array(\n          'item_id' => $item_id,\n          'name' => $data['name'],\n          'type' => $data['type']\n        ))\n        ->find();\n\n      $entry = [\n        'id' => $this->generateId(),\n        'itemId' => $item_id,\n        'name' => $data['name'],\n        'type' => $data['type'],\n        'description' => $data['description'],\n        'example' => isset($data['example']) ? $data['example'] : '',\n        'source' => 'manual',\n        'status' => 'permanent',\n        'usageCount' => 0,\n        'qualityScore' => $this->calculateQualityScore($data),\n        'createdBy' => $uid,\n        'updatedAt' => time()\n      ];\n\n      if ($existing) {\n        $duplicatedEntries[] = $entry;\n      } else {\n        $newEntries[] = $entry;\n      }\n    }\n\n    $this->sendResult([\n      'new' => $newEntries,\n      'duplicated' => $duplicatedEntries\n    ]);\n  }\n\n\n  /**\n   * 导出数据\n   */\n  public function export()\n  {\n    $login_user = $this->checkLogin();\n    $uid = $login_user['uid'];\n\n    $item_id = I(\"itemId/d\");\n    $format = I(\"format\", \"json\");\n\n    if (!$item_id) {\n      $this->sendError(10001, '缺少项目ID');\n      return;\n    }\n\n    if (!$this->checkItemEdit($uid, $item_id)) {\n      $this->sendError(10303);\n      return;\n    }\n\n    $entries = D(\"ParameterDescriptionEntry\")\n      ->where(array('item_id' => $item_id))\n      ->order(\"name ASC\")\n      ->select();\n\n    if ($format === 'csv') {\n      $csv = \"字段名,类型,描述,示例值,使用次数\\n\";\n      foreach ($entries as $entry) {\n        $csv .= \"\\\"{$entry['name']}\\\",\\\"{$entry['type']}\\\",\\\"{$entry['description']}\\\",\\\"{$entry['example']}\\\",{$entry['usage_count']}\\n\";\n      }\n      $this->sendResult($csv);\n    } else {\n      // JSON格式\n      $exportData = [];\n      foreach ($entries as $entry) {\n        $exportData[] = [\n          'name' => $entry['name'],\n          'type' => $entry['type'],\n          'description' => $entry['description'],\n          'example' => $entry['example'],\n          'aliases' => json_decode($entry['aliases'], true),\n          'tags' => json_decode($entry['tags'], true),\n          'usageCount' => intval($entry['usage_count'])\n        ];\n      }\n      $this->sendResult(json_encode($exportData, JSON_UNESCAPED_UNICODE));\n    }\n  }\n\n  /**\n   * 解析导入数据\n   */\n  private function parseImportData($format, $rawText)\n  {\n    switch ($format) {\n      case 'kv':\n        return $this->parseKeyValue($rawText);\n      case 'json':\n        return $this->parseJson($rawText);\n      case 'ddl':\n        return $this->parseDDL($rawText);\n      default:\n        return false;\n    }\n  }\n\n  /**\n   * 解析键值对格式\n   */\n  private function parseKeyValue($text)\n  {\n    $lines = explode(\"\\n\", trim($text));\n    $result = [];\n\n    foreach ($lines as $line) {\n      $line = trim($line);\n      if (empty($line)) continue;\n\n      $parts = explode(':', $line, 2);\n      if (count($parts) >= 2) {\n        $result[] = [\n          'name' => trim($parts[0]),\n          'type' => 'string',\n          'description' => trim($parts[1])\n        ];\n      }\n    }\n\n    return $result;\n  }\n\n  /**\n   * 解析JSON格式\n   */\n  private function parseJson($text)\n  {\n    $data = json_decode($text, true);\n    if (!$data) return false;\n\n    return $this->extractFieldsFromObject($data);\n  }\n\n  /**\n   * 从对象中提取字段\n   */\n  private function extractFieldsFromObject($obj, $prefix = '')\n  {\n    $result = [];\n\n    foreach ($obj as $key => $value) {\n      $fieldName = $prefix ? $prefix . '.' . $key : $key;\n\n      if (is_array($value) && !empty($value)) {\n        if (is_object($value[0]) || is_array($value[0])) {\n          $result[] = [\n            'name' => $fieldName,\n            'type' => 'array',\n            'description' => $fieldName . '数组'\n          ];\n          $result = array_merge($result, $this->extractFieldsFromObject($value[0], $fieldName . '[0]'));\n        } else {\n          $result[] = [\n            'name' => $fieldName,\n            'type' => 'array',\n            'description' => $fieldName . '数组',\n            'example' => json_encode($value)\n          ];\n        }\n      } elseif (is_object($value) || is_array($value)) {\n        $result[] = [\n          'name' => $fieldName,\n          'type' => 'object',\n          'description' => $fieldName . '对象'\n        ];\n        $result = array_merge($result, $this->extractFieldsFromObject($value, $fieldName));\n      } else {\n        $type = 'string';\n        if (is_int($value)) $type = 'number';\n        elseif (is_bool($value)) $type = 'boolean';\n        elseif (is_float($value)) $type = 'number';\n\n        $result[] = [\n          'name' => $fieldName,\n          'type' => $type,\n          'description' => $fieldName,\n          'example' => strval($value)\n        ];\n      }\n    }\n\n    return $result;\n  }\n\n  /**\n   * 解析DDL（简单实现）\n   */\n  private function parseDDL($text)\n  {\n    // 简单的DDL解析，提取字段名和注释\n    $result = [];\n    $lines = explode(\"\\n\", $text);\n\n    foreach ($lines as $line) {\n      $line = trim($line);\n      if (preg_match('/`(\\w+)`\\s+\\w+.*COMMENT\\s+[\\'\"]([^\\'\"]+)[\\'\"]/', $line, $matches)) {\n        $result[] = [\n          'name' => $matches[1],\n          'type' => 'string',\n          'description' => $matches[2]\n        ];\n      }\n    }\n\n    return $result;\n  }\n\n  /**\n   * 计算质量评分\n   */\n  private function calculateQualityScore($data)\n  {\n    $score = 0;\n\n    // 基础分数\n    if (!empty($data['description'])) $score += 0.4;\n    if (!empty($data['example'])) $score += 0.2;\n    if (!empty($data['enumValues']) && is_array($data['enumValues']) && count($data['enumValues']) > 0) $score += 0.1;\n    if (!empty($data['defaultValue'])) $score += 0.1;\n\n    // 使用频次加分\n    $usageCount = isset($data['usageCount']) ? $data['usageCount'] : (isset($data['usage_count']) ? $data['usage_count'] : 0);\n    $usageScore = min($usageCount * 0.02, 0.2);\n    $score += $usageScore;\n\n    return min($score, 1.0);\n  }\n\n  /**\n   * 生成唯一ID\n   */\n  private function generateId()\n  {\n    return uniqid() . '_' . mt_rand(1000, 9999);\n  }\n\n  /**\n   * 转换数据库字段名为前端驼峰格式\n   */\n  private function convertEntryFields($entry)\n  {\n    // 处理JSON字段\n    $entry['aliases'] = $entry['aliases'] ? json_decode($entry['aliases'], true) : [];\n    $entry['tags'] = $entry['tags'] ? json_decode($entry['tags'], true) : [];\n    $entry['enumValues'] = $entry['enum_values'] ? json_decode($entry['enum_values'], true) : [];\n\n    // 字段名转换：数据库下划线 -> 前端驼峰\n    $entry['itemId'] = $entry['item_id'];\n    $entry['usageCount'] = intval($entry['usage_count']);\n    $entry['qualityScore'] = floatval($entry['quality_score']);\n    $entry['defaultValue'] = $entry['default_value'] ?? '';\n    $entry['createdBy'] = $entry['created_by'];\n    $entry['updatedAt'] = strtotime($entry['updated_at']) * 1000; // 转换为前端时间戳格式\n\n    // 移除数据库字段名\n    unset($entry['item_id']);\n    unset($entry['usage_count']);\n    unset($entry['quality_score']);\n    unset($entry['default_value']);\n    unset($entry['enum_values']);\n    unset($entry['created_by']);\n    unset($entry['created_at']);\n    unset($entry['updated_at']);\n\n    return $entry;\n  }\n\n  /**\n   * 批量添加条目\n   */\n  private function _addBatchEntries()\n  {\n    $login_user = $this->checkLogin();\n    $uid = $login_user['uid'];\n\n    $entries = I(\"entries\", []);\n\n    if (empty($entries)) {\n      $this->sendError(10001, '没有要添加的条目');\n      return;\n    }\n\n    $results = [];\n    foreach ($entries as $entry) {\n      // 检查权限\n      if (!$this->checkItemEdit($uid, $entry['itemId'])) {\n        continue;\n      }\n\n      $data = [\n        'id' => $this->generateId(),\n        'item_id' => $entry['itemId'],\n        'name' => $entry['name'],\n        'type' => $entry['type'],\n        'description' => $entry['description'],\n        'example' => $entry['example'] ?? '',\n        'default_value' => $entry['defaultValue'] ?? '',\n        'source' => $entry['source'] ?? 'manual',\n        'status' => $entry['status'] ?? 'permanent',\n        'usage_count' => 0,\n        'quality_score' => $entry['qualityScore'] ?? 0,\n        'created_by' => $uid,\n        'created_at' => date(\"Y-m-d H:i:s\"),\n        'updated_at' => date(\"Y-m-d H:i:s\")\n      ];\n\n      $id = D(\"ParameterDescriptionEntry\")->add($data);\n      if ($id) {\n        $entry = D(\"ParameterDescriptionEntry\")->where(array('id' => $data['id']))->find();\n        $results[] = $this->convertEntryFields($entry);\n      }\n    }\n\n    $this->sendResult($results);\n  }\n\n  /**\n   * 确认导入\n   */\n  private function _confirmImport()\n  {\n    $this->_addBatchEntries();\n  }\n\n  /**\n   * 更新使用次数\n   */\n  private function _updateUsage()\n  {\n    $login_user = $this->checkLogin();\n    $uid = $login_user['uid'];\n\n    $id = I(\"id\", \"\");\n    $ids = I(\"ids\", \"\");\n\n    if ($id) {\n      $ids = [$id];\n    } elseif ($ids) {\n      // 处理前端传来的逗号分隔字符串\n      if (is_string($ids)) {\n        $ids = array_filter(explode(',', $ids));\n      } elseif (!is_array($ids)) {\n        $ids = [];\n      }\n    } else {\n      $ids = [];\n    }\n\n    if (empty($ids)) {\n      $this->sendError(10001, '缺少要更新的ID');\n      return;\n    }\n\n    // 检查权限 - 检查第一个存在的条目来验证权限\n    $firstValidEntry = null;\n    foreach ($ids as $entryId) {\n      $entry = D(\"ParameterDescriptionEntry\")->where(array('id' => $entryId))->find();\n      if ($entry) {\n        $firstValidEntry = $entry;\n        break;\n      }\n    }\n\n    if (!$firstValidEntry) {\n      $this->sendError(10001, '没有找到有效的条目');\n      return;\n    }\n\n    if (!$this->checkItemEdit($uid, $firstValidEntry['item_id'])) {\n      $this->sendError(10303);\n      return;\n    }\n\n    $updated = 0;\n    $notFound = [];\n\n    foreach ($ids as $entryId) {\n      $entry = D(\"ParameterDescriptionEntry\")->where(array('id' => $entryId))->find();\n      if ($entry) {\n        // 验证该条目是否属于同一项目（安全检查）\n        if ($entry['item_id'] != $firstValidEntry['item_id']) {\n          continue; // 跳过不同项目的条目\n        }\n\n        $newUsageCount = $entry['usage_count'] + 1;\n        $newQualityScore = $this->calculateQualityScore(array_merge($entry, ['usageCount' => $newUsageCount]));\n\n        $result = D(\"ParameterDescriptionEntry\")\n          ->where(array('id' => $entryId))\n          ->save(array(\n            'usage_count' => $newUsageCount,\n            'quality_score' => $newQualityScore,\n            'updated_at' => date(\"Y-m-d H:i:s\")\n          ));\n\n        if ($result !== false) {\n          $updated++;\n        }\n      } else {\n        $notFound[] = $entryId;\n      }\n    }\n\n    $result = ['updated' => $updated];\n    if (!empty($notFound)) {\n      $result['notFound'] = $notFound;\n    }\n\n    $this->sendResult($result);\n  }\n}\n"
  },
  {
    "path": "server/Application/Api/Controller/PublicSquareController.class.php",
    "content": "<?php\n\nnamespace Api\\Controller;\n\nuse Think\\Controller;\n\nclass PublicSquareController extends BaseController\n{\n  // 检查公开广场功能是否启用\n  public function checkEnabled()\n  {\n    $enable_public_square = D(\"Options\")->get(\"enable_public_square\");\n    $this->sendResult(array(\n      \"enable\" => $enable_public_square ? 1 : 0\n    ));\n  }\n\n  //获取公开项目列表\n  public function getPublicItems()\n  {\n    // 检查是否启用了公开广场功能\n    $enable_public_square = D(\"Options\")->get(\"enable_public_square\");\n    if (!$enable_public_square) {\n      $this->sendError(10501, '公开广场功能未启用');\n      return;\n    }\n\n    // 检查是否需要强制登录\n    $force_login = D(\"Options\")->get(\"force_login\");\n    if ($force_login) {\n      $login_user = $this->checkLogin();\n    }\n\n    $page = I(\"page/d\") ? I(\"page/d\") : 1;\n    $count = I(\"count/d\") ? I(\"count/d\") : 20;\n    $keyword = I(\"keyword\");\n    \n    // 参数化 + safe_like 处理关键词\n    $keyword = $keyword ? safe_like($keyword) : '';\n    \n    $search_type = I(\"search_type\"); // title 或 content\n\n    // 基础查询条件\n    $where_conditions = array(\n      'password' => '',\n      'is_del' => 0\n    );\n\n    if ($keyword) {\n      if ($search_type == 'content') {\n        // 搜索项目内容，开源版中page表没有分表\n        $page_items = M(\"Page\")->field(\"item_id\")\n          ->where(\"page_content LIKE '%s'\", array($keyword))\n          ->group(\"item_id\")\n          ->select();\n        if ($page_items) {\n          $item_ids = array();\n          foreach ($page_items as $value) {\n            $item_ids[] = $value['item_id'];\n          }\n          // 使用数组条件而不是字符串拼接\n          $where_conditions['item_id'] = array('in', $item_ids);\n        } else {\n          // 如果没有找到匹配的内容，返回空结果\n          $this->sendResult(array(\n            \"total\" => 0,\n            \"items\" => array()\n          ));\n          return;\n        }\n      } else {\n        // 默认搜索项目标题和描述\n        $items = D(\"Item\")->field(\"item_id, item_name, item_description, item_type, addtime, last_update_time, item_domain\")\n          ->where(\"password = '' AND is_del = 0 AND (item_name LIKE '%s' OR item_description LIKE '%s')\", array($keyword, $keyword))\n          ->order(\"last_update_time DESC\")\n          ->page($page, $count)\n          ->select();\n        $total = D(\"Item\")->where(\"password = '' AND is_del = 0 AND (item_name LIKE '%s' OR item_description LIKE '%s')\", array($keyword, $keyword))->count();\n\n        if ($items) {\n          foreach ($items as $key => &$value) {\n            $value['addtime'] = date(\"Y-m-d H:i:s\", $value['addtime']);\n            $value['last_update_time'] = date(\"Y-m-d H:i:s\", $value['last_update_time']);\n            $value['item_domain'] = $value['item_domain'] ? $value['item_domain'] : $value['item_id'];\n          }\n        }\n\n        $return = array(\n          \"total\" => (int)$total,\n          \"items\" => $items ? $items : array()\n        );\n\n        $this->sendResult($return);\n        return;\n      }\n    }\n\n    $items = D(\"Item\")->field(\"item_id, item_name, item_description, item_type, addtime, last_update_time, item_domain\")\n      ->where($where_conditions)\n      ->order(\"last_update_time DESC\")\n      ->page($page, $count)\n      ->select();\n    $total = D(\"Item\")->where($where_conditions)->count();\n\n    if ($items) {\n      foreach ($items as $key => &$value) {\n        $value['addtime'] = date(\"Y-m-d H:i:s\", $value['addtime']);\n        $value['last_update_time'] = date(\"Y-m-d H:i:s\", $value['last_update_time']);\n        $value['item_domain'] = $value['item_domain'] ? $value['item_domain'] : $value['item_id'];\n      }\n    }\n\n    $return = array(\n      \"total\" => (int)$total,\n      \"items\" => $items ? $items : array()\n    );\n\n    $this->sendResult($return);\n  }\n} "
  },
  {
    "path": "server/Application/Api/Controller/RecycleController.class.php",
    "content": "<?php\n\nnamespace Api\\Controller;\n\nuse Think\\Controller;\n\nclass RecycleController extends BaseController\n{\n\n\n\n    //获取被删除的页面列表\n    public function getList()\n    {\n        $item_id = I(\"item_id/d\");\n        $login_user = $this->checkLogin();\n        $uid = $login_user['uid'];\n        if (!$this->checkItemManage($uid, $item_id)) {\n            $this->sendError(10303);\n            return;\n        }\n        if ($item_id > 0) {\n            $ret = D(\"Recycle\")->where(\" item_id = '%d' \", array($item_id))->order(\" del_time desc  \")->select();\n        }\n        if ($ret) {\n            foreach ($ret as $key => &$value) {\n                $value['del_time'] = date(\"Y-m-d H:i:s\", $value['del_time']);\n            }\n        }\n        $this->sendResult($ret);\n    }\n\n\n    //恢复页面\n    public function recover()\n    {\n        $item_id = I(\"item_id/d\");\n        $page_id = I(\"page_id/d\");\n        $login_user = $this->checkLogin();\n        $uid = $login_user['uid'];\n        if (!$this->checkItemManage($uid, $item_id)) {\n            $this->sendError(10303);\n            return;\n        }\n        if ($item_id > 0) {\n            M(\"Page\")->where(\" page_id = '%d' \", array($page_id))->save(array(\"is_del\" => 0));\n            D(\"Page\")->where(\" page_id = '%d' \", array($page_id))->save(array(\"is_del\" => 0, \"cat_id\" => 0));\n            $ret = D(\"Recycle\")->where(\" item_id = '%d' and page_id = '%d' \", array($item_id, $page_id))->delete();\n        }\n        $this->sendResult(array());\n    }\n}\n"
  },
  {
    "path": "server/Application/Api/Controller/RunapiController.class.php",
    "content": "<?php\n\nnamespace Api\\Controller;\n\nuse Think\\Controller;\n\nclass RunapiController extends BaseController\n{\n\n\n  //添加环境\n  public function addEnv()\n  {\n    $login_user = $this->checkLogin();\n    $env_id = I(\"env_id/d\");\n    $env_name = I(\"env_name\");\n    $item_id = I(\"item_id/d\");\n    $uid = $login_user['uid'];\n    if (!$this->checkItemEdit($uid, $item_id)) {\n      $this->sendError(10303);\n      return;\n    }\n    $res = false;\n    if ($env_id) {\n      $res = D(\"RunapiEnv\")->where(\"id = '%d' and item_id = '%d' \", array($env_id, $item_id))->save(array(\n        \"env_name\" => $env_name,\n        \"uid\" => $uid,\n        \"last_update_time\" => date(\"Y-m-d H:i:s\"),\n      ));\n      $this->sendResult(array(\"env_id\" => $env_id));\n    } else {\n      $env_id = D(\"RunapiEnv\")->add(array(\n        \"env_name\" => $env_name,\n        \"item_id\" => $item_id,\n        \"uid\" => $uid,\n        \"addtime\" => date(\"Y-m-d H:i:s\"),\n        \"last_update_time\" => date(\"Y-m-d H:i:s\"),\n      ));\n      $this->sendResult(array(\"env_id\" => $env_id));\n    }\n  }\n\n  //更新环境\n  public function updateEnv()\n  {\n    $this->addEnv();\n  }\n\n  //获取环境列表\n  public function getEnvList()\n  {\n    $item_id = I(\"item_id/d\");\n    $login_user = $this->checkLogin();\n    $uid = $login_user['uid'];\n    if (!$this->checkItemEdit($uid, $item_id)) {\n      $this->sendError(10303);\n      return;\n    }\n    $res = D(\"RunapiEnv\")->where(\"item_id = '%d' \", array($item_id))->select();\n    if ($res) {\n      $this->sendResult($res);\n    } else {\n      //如果尚未有环境，则帮其创建一个默认环境\n      $env_id = D(\"RunapiEnv\")->add(array(\n        \"env_name\" => '默认环境',\n        \"item_id\" => $item_id,\n        \"uid\" => $uid,\n        \"addtime\" => date(\"Y-m-d H:i:s\"),\n        \"last_update_time\" => date(\"Y-m-d H:i:s\"),\n      ));\n      //并且把项目变量都绑定到该默认环境中\n      D(\"ItemVariable\")->where(array('item_id' => $item_id))->save(array(\n        \"env_id\" => $env_id\n      ));\n      sleep(1);\n      $this->getEnvList();\n    }\n  }\n  //删除环境\n  public function delEnv()\n  {\n    $env_id = I(\"env_id/d\");\n    $login_user = $this->checkLogin();\n    $uid = $login_user['uid'];\n    $res = D(\"RunapiEnv\")->where(array('id' => $env_id))->find();\n    $item_id = $res['item_id'];\n    if (!$this->checkItemEdit($uid, $item_id)) {\n      $this->sendError(10303);\n      return;\n    }\n    $res = D(\"RunapiEnvSelectd\")->where(array('id' => $env_id))->delete();\n    $res = D(\"RunapiEnv\")->where(array('id' => $env_id))->delete();\n    $res = D(\"ItemVariable\")->where(array('env_id' => $env_id))->delete();\n    if ($res) {\n      $this->sendResult($res);\n    } else {\n      $this->sendResult(array());\n    }\n  }\n\n  //设置某个环境变量为选中\n  public function selectEnv()\n  {\n    $env_id = I(\"env_id/d\");\n    $login_user = $this->checkLogin();\n    $uid = $login_user['uid'];\n    $res = D(\"RunapiEnv\")->where(array('id' => $env_id))->find();\n    $item_id = $res['item_id'];\n    if (!$this->checkItemEdit($uid, $item_id)) {\n      $this->sendError(10303);\n      return;\n    }\n    D(\"RunapiEnvSelectd\")->where(\"item_id = '%d' and uid = '%d' \", array($item_id, $uid))->delete();\n    $res = D(\"RunapiEnvSelectd\")->add(array(\n      \"item_id\" => $item_id,\n      \"uid\" => $uid,\n      \"env_id\" => $env_id,\n    ));\n    if ($res) {\n      $this->sendResult($res);\n    } else {\n      $this->sendResult(array());\n    }\n  }\n\n  //获取用户选中的环境\n  public function getSelectEnv()\n  {\n    $item_id = I(\"item_id/d\");\n    $login_user = $this->checkLogin();\n    $uid = $login_user['uid'];\n    if (!$this->checkItemEdit($uid, $item_id)) {\n      $this->sendError(10303);\n      return;\n    }\n    $res = D(\"RunapiEnvSelectd\")->where(\"item_id = '%d' and uid = '%d' \", array($item_id, $uid))->find();\n    if ($res) {\n      $this->sendResult($res);\n    } else {\n      $this->sendResult(array(\n        \"env_id\" => 0,\n      ));\n    }\n  }\n\n  //获取全局参数\n  public function getGlobalParam()\n  {\n    $item_id = I(\"item_id/d\");\n    $login_user = $this->checkLogin();\n    $uid = $login_user['uid'];\n    if (!$this->checkItemEdit($uid, $item_id)) {\n      $this->sendError(10303);\n      return;\n    }\n    $return = D(\"Runapi\")->getGlobalParam($item_id);\n    $this->sendResult($return);\n  }\n\n  //修改全局参数\n  public function updateGlobalParam()\n  {\n    $item_id = I(\"item_id/d\");\n    $param_type = I(\"param_type\");\n    $content_json_str = I(\"content_json_str\");\n    $login_user = $this->checkLogin();\n    $uid = $login_user['uid'];\n    if (!$this->checkItemEdit($uid, $item_id)) {\n      $this->sendError(10303);\n      return;\n    }\n    $res = D(\"RunapiGlobalParam\")->where(\"param_type = '%s' and item_id = '%d' \", array($param_type, $item_id))->save(array(\n      \"content_json_str\" => $content_json_str,\n      \"last_update_time\" => date(\"Y-m-d H:i:s\"),\n    ));\n    if ($res) {\n      $this->sendResult($res);\n    } else {\n      $this->sendResult(array());\n    }\n  }\n\n  /**\n   * 获取数据库连接列表（按项目+环境）\n   */\n  public function getDbConfigList()\n  {\n    $item_id = I(\"item_id/d\");\n    $env_id = I(\"env_id/d\");\n    $login_user = $this->checkLogin();\n    $uid = $login_user['uid'];\n    if (!$this->checkItemEdit($uid, $item_id)) {\n      $this->sendError(10303);\n      return;\n    }\n    if (!$env_id) {\n      $this->sendError(10101, '缺少 env_id');\n      return;\n    }\n    $list = D(\"RunapiDbConfig\")->where(\"item_id = '%d' and env_id = '%d' \", array($item_id, $env_id))->order(\"is_default desc,id asc\")->select();\n    $this->sendResult($list ? $list : array());\n  }\n\n  /**\n   * 新增/更新数据库连接配置\n   */\n  public function saveDbConfig()\n  {\n    $login_user = $this->checkLogin();\n    $uid = $login_user['uid'];\n\n    $config_id = I(\"config_id/d\");\n    $item_id = I(\"item_id/d\");\n    $env_id = I(\"env_id/d\");\n    $config_name = I(\"config_name\", \"默认\");\n    $db_type = I(\"db_type\", \"mysql\");\n    $host = I(\"host\");\n    $port = I(\"port/d\");\n    $username = I(\"username\");\n    $password = I(\"password\");\n    $database = I(\"database\");\n    $options = I(\"options\");\n    $is_default = I(\"is_default/d\", 0);\n\n    if (!$this->checkItemEdit($uid, $item_id)) {\n      $this->sendError(10303);\n      return;\n    }\n    if (!$env_id) {\n      $this->sendError(10101, '缺少 env_id');\n      return;\n    }\n    $allow_type = array('mysql', 'postgresql', 'sqlite');\n    if (!in_array($db_type, $allow_type)) {\n      $this->sendError(10101, '不支持的数据库类型');\n      return;\n    }\n    if (!$config_name) {\n      $config_name = '默认';\n    }\n\n    $data = array(\n      \"item_id\" => $item_id,\n      \"env_id\" => $env_id,\n      \"config_name\" => $config_name,\n      \"db_type\" => $db_type,\n      \"host\" => $host,\n      \"port\" => $port,\n      \"username\" => $username,\n      \"password\" => $password,\n      \"database\" => $database,\n      \"options\" => $options,\n      \"is_default\" => $is_default ? 1 : 0,\n      \"last_update_time\" => date(\"Y-m-d H:i:s\"),\n      \"uid\" => $uid,\n    );\n\n    if ($config_id) {\n      $row = D(\"RunapiDbConfig\")->where(\"id = '%d' \", array($config_id))->find();\n      if (!$row || $row['item_id'] != $item_id) {\n        $this->sendError(10101, '配置不存在');\n        return;\n      }\n      D(\"RunapiDbConfig\")->where(\"id = '%d' \", array($config_id))->save($data);\n    } else {\n      $data[\"addtime\"] = date(\"Y-m-d H:i:s\");\n      $config_id = D(\"RunapiDbConfig\")->add($data);\n    }\n\n    if ($is_default) {\n      D(\"RunapiDbConfig\")->where(\"item_id = '%d' and env_id = '%d' and id != '%d' \", array($item_id, $env_id, $config_id))->save(array(\"is_default\" => 0, \"last_update_time\" => date(\"Y-m-d H:i:s\")));\n    }\n\n    $this->sendResult(array(\"config_id\" => $config_id));\n  }\n\n  /**\n   * 删除数据库连接配置\n   */\n  public function delDbConfig()\n  {\n    $config_id = I(\"config_id/d\");\n    $login_user = $this->checkLogin();\n    $uid = $login_user['uid'];\n    $row = D(\"RunapiDbConfig\")->where(\"id = '%d' \", array($config_id))->find();\n    if (!$row) {\n      $this->sendError(10101, '配置不存在');\n      return;\n    }\n    if (!$this->checkItemEdit($uid, $row['item_id'])) {\n      $this->sendError(10303);\n      return;\n    }\n    D(\"RunapiDbConfig\")->where(\"id = '%d' \", array($config_id))->delete();\n    $this->sendResult(array());\n  }\n}\n"
  },
  {
    "path": "server/Application/Api/Controller/ScriptCronController.class.php",
    "content": "<?php\n\nnamespace Api\\Controller;\n\nuse Think\\Controller;\n/*\n    由网站前台脚本触发的周期任务\n */\n\nclass ScriptCronController extends BaseController\n{\n\n\n    public function run()\n    {\n        set_time_limit(100);\n        ini_set('memory_limit', '800M');\n        ignore_user_abort(true);\n\n        //定期清理已删除项目和已删除页面\n        $this->clean_deleted_data();\n    }\n\n\n    //定期清理已删除项目和已删除页面\n    public function clean_deleted_data()\n    {\n        //30天前的已删除项目\n        $items = D(\"Item\")->where(\" is_del = 1 and last_update_time < %d \", array(time() - 30 * 24 * 60 * 60))->select();\n        if ($items) {\n            foreach ($items as $key => $value) {\n                $ret = D(\"Item\")->delete_item($value['item_id']);\n            }\n        }\n\n\n        $pages = D(\"Page\")->where(\" is_del = 1 and addtime < %d \", array(time() - 30 * 24 * 60 * 60))->select();\n        if ($pages) {\n            foreach ($pages as $key => $value) {\n                $ret = D(\"Page\")->deletePage($value['page_id']);\n            }\n        }\n\n        $pages = D(\"Recycle\")->where(\" del_time < %d \", array(time() - 30 * 24 * 60 * 60))->select();\n        if ($pages) {\n            foreach ($pages as $key => $value) {\n                $ret = D(\"Page\")->deletePage($value['page_id']);\n                D(\"Recycle\")->where(array('id' => $value['id']))->delete();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "server/Application/Api/Controller/SubscriptionController.class.php",
    "content": "<?php\n\nnamespace Api\\Controller;\n\nuse Think\\Controller;\n\nclass SubscriptionController extends BaseController\n{\n\n\n    // 获取页面的订阅人员列表\n    public function getPageList()\n    {\n        $login_user = $this->checkLogin();\n        $page_id = I(\"post.page_id/d\");\n        $page = M(\"Page\")->where(array('page_id' => $page_id))->find();\n        if (!$this->checkItemEdit($login_user['uid'], $page['item_id'])) {\n            $this->sendError(10103);\n            return;\n        }\n\n        $subscription_array = D(\"Subscription\")->getListByObjectId($page_id, 'page', 'update');\n        $subscription_array = $subscription_array ? $subscription_array : array();\n        foreach ($subscription_array as $key => $value) {\n            $user_array = D(\"User\")->where(array('uid' => $value['uid']))->find();\n            $subscription_array[$key]['username'] = $user_array['username'];\n            $subscription_array[$key]['name'] = $user_array['name'];\n        }\n        $this->sendResult($subscription_array);\n    }\n\n\n    // 保存页面（或者接口）的订阅信息\n    public function savePage()\n    {\n        $login_user = $this->checkLogin();\n        $uids = I(\"uids\");\n        $page_id = I(\"post.page_id/d\");\n        $page = M(\"Page\")->where(array('page_id' => $page_id))->find();\n\n        if (!$this->checkItemEdit($login_user['uid'], $page['item_id'])) {\n            $this->sendError(10103);\n            return;\n        }\n\n        $uids_array = explode(',', $uids);\n        if ($uids_array) {\n            foreach ($uids_array as $key => $value) {\n                $s_uid = intval($value);\n\n                $res = D(\"Subscription\")->addSub($s_uid, $page_id, 'page', 'update');\n            }\n        }\n\n        $this->sendResult(array());\n    }\n\n    // 删除页面（或者接口）的订阅信息\n    public function deletePage()\n    {\n        $login_user = $this->checkLogin();\n\n        $uids = I(\"uids\");\n        $page_id = I(\"post.page_id/d\");\n        $page = M(\"Page\")->where(array('page_id' => $page_id))->find();\n\n        if (!$this->checkItemEdit($login_user['uid'], $page['item_id'])) {\n            $this->sendError(10103);\n            return;\n        }\n\n        $uids_array = explode(',', $uids);\n        if ($uids_array) {\n            foreach ($uids_array as $key => $value) {\n                $s_uid = intval($value);\n                D(\"Subscription\")->deleteSub($s_uid, $page_id, 'page', 'update');\n            }\n        }\n\n        $this->sendResult(array());\n    }\n}\n"
  },
  {
    "path": "server/Application/Api/Controller/TeamController.class.php",
    "content": "<?php\n\nnamespace Api\\Controller;\n\nuse Think\\Controller;\n/*\n    团队管理\n */\n\nclass TeamController extends BaseController\n{\n\n    //添加和编辑\n    public function save()\n    {\n        $login_user = $this->checkLogin();\n\n        $team_name = I(\"post.team_name\");\n        $id = I(\"post.id/d\");\n        $uid = $login_user['uid'];\n\n        if ($id) {\n            if (!$this->checkTeamManage($uid, $id)) {\n                $this->sendError(10103);\n                return;\n            }\n            D(\"Team\")->where(array('id' => $id))->save(array(\"team_name\" => $team_name));\n        } else {\n            $data['username'] = $login_user['username'];\n            $data['uid'] = $login_user['uid'];\n            $data['team_name'] = $team_name;\n            $data['addtime'] = time();\n            $id = D(\"Team\")->add($data);\n        }\n\n        $return = D(\"Team\")->where(array('id' => $id))->find();\n\n        if (!$return) {\n            $return['error_code'] = 10103;\n            $return['error_message'] = 'request  fail';\n        }\n\n        $this->sendResult($return);\n    }\n\n    //获取列表\n    public function getList()\n    {\n        $login_user = $this->checkLogin();\n        $uid = $login_user['uid'];\n        if ($uid > 0) {\n            $ret = D(\"Team\")->where(\" uid = '%d' or id in ( select team_id from team_member where member_uid = '%d'   )  \", array($uid, $uid))->order(\" addtime desc  \")->select();\n        }\n        if ($ret) {\n            foreach ($ret as $key => &$value) {\n                // 检测管理权限\n                if ($this->checkTeamManage($uid, $value['id'])) {\n                    $value['team_manage'] = 1;\n                } else {\n                    $value['team_manage'] = 0;\n                }\n                //获取该团队成员数\n                $value['memberCount'] = D(\"TeamMember\")->where(array('team_id' => $value['id']))->count();\n\n                //获取该团队涉及项目数\n                $value['itemCount'] = D(\"TeamItem\")->where(\" team_id = '%d' and item.is_del = 0 \", array($value['id']))->join(\"left join item on item.item_id = team_item.item_id\")->count();\n\n                $value['addtime'] = date(\"Y-m-d H:i:s\", $value['addtime']);\n            }\n            $this->sendResult($ret);\n        } else {\n            $this->sendResult(array());\n        }\n    }\n\n    //删除\n    public function delete()\n    {\n        $id = I(\"post.id/d\") ? I(\"post.id/d\") : 0;\n        $login_user = $this->checkLogin();\n        if ($id && $login_user['uid']) {\n            $ret = D(\"Team\")->where(\" id = '%d' and uid = '%d'\", array($id, $login_user['uid']))->delete();\n        }\n        if ($ret) {\n            D(\"TeamItem\")->where(array('team_id' => $id))->delete();\n            D(\"TeamItemMember\")->where(array('team_id' => $id))->delete();\n            D(\"TeamMember\")->where(array('team_id' => $id))->delete();\n            $this->sendResult($ret);\n        } else {\n            $return['error_code'] = 10103;\n            $return['error_message'] = 'request  fail';\n            $this->sendResult($return);\n        }\n    }\n\n    //转让团队\n    public function attorn()\n    {\n        $login_user = $this->checkLogin();\n\n        $username = I(\"post.username\");\n        $team_id = I(\"post.team_id/d\");\n        $password = I(\"post.password\");\n\n        $team  = D(\"Team\")->where(\"id = '%d' and uid = '%d' \", array($team_id, $login_user['uid']))->find();\n\n        if (!$team) {\n            $this->sendError(10101);\n            return;\n        }\n\n        if (!D(\"User\")->checkLogin($login_user['username'], $password)) {\n            $this->sendError(10208);\n            return;\n        }\n\n        $member = D(\"User\")->where(array('username' => $username))->find();\n\n        if (!$member) {\n            $this->sendError(10209);\n            return;\n        }\n        $data = array();\n        $data['username'] = $member['username'];\n        $data['uid'] = $member['uid'];\n        D(\"Team\")->where(array('id' => $team_id))->save($data);\n\n        //读取出该团队下的所有项目，准备转让\n        $items = D(\"TeamItem\")->where(array('team_id' => $team_id))->select();\n        foreach ($items as $key => $value) {\n            D(\"Item\")->where(array('item_id' => $value['item_id']))->save($data);\n        }\n\n        $this->sendResult(array());\n    }\n\n\n    //由当前登录用户主动选择退出团队\n    public function exitTeam()\n    {\n        $id = I(\"post.id/d\") ? I(\"post.id/d\") : 0;\n        $login_user = $this->checkLogin();\n\n        $teamInfo = D(\"Team\")->where(array('id' => $id))->find();\n        $ret = D(\"TeamItemMember\")->where(\" member_uid = '%d' and  team_id = '%d' \", array($login_user['uid'], $id))->delete();\n        $ret = D(\"TeamMember\")->where(\"  member_uid = '%d' and  team_id = '%d' \", array($login_user['uid'], $id))->delete();\n        $this->sendResult(array());\n    }\n}\n"
  },
  {
    "path": "server/Application/Api/Controller/TeamItemController.class.php",
    "content": "<?php\n\nnamespace Api\\Controller;\n\nuse Think\\Controller;\n/*\n    团队和项目的绑定关系\n */\n\nclass TeamItemController extends BaseController\n{\n\n    //添加和编辑\n    public function save()\n    {\n        $login_user = $this->checkLogin();\n        $uid = $login_user['uid'];\n\n        $item_id = I(\"post.item_id\");\n        $team_id = I(\"post.team_id/d\");\n\n        if (!$this->checkTeamManage($uid, $team_id)) {\n            $this->sendError(10103);\n            return;\n        }\n\n        $teamInfo = D(\"Team\")->where(array('id' => $team_id))->find();\n\n        $item_id_array = explode(\",\", $item_id);\n        foreach ($item_id_array as $key => $value) {\n            $item_id = intval($value);\n            if (!$this->checkItemManage($uid, $item_id)) {\n                $this->sendError(10303);\n                return;\n            }\n\n            if (D(\"TeamItem\")->where(\"  team_id = '%d' and item_id = '%d' \", array($team_id, $item_id))->find()) {\n                continue; //如果该项目已经加入团队了，则结束当前一次循环。\n            }\n\n\n            $data = array();\n            $data['item_id'] = $item_id;\n            $data['team_id'] = $team_id;\n            $data['addtime'] = time();\n            $id = D(\"TeamItem\")->add($data);\n\n            D(\"ItemChangeLog\")->addLog($login_user['uid'], $item_id, 'binding', 'team', $team_id, $teamInfo['team_name']);\n\n            //获取该团队的所有成员并加入项目\n            $teamMembers = D(\"TeamMember\")->where(\"  team_id = '%d' \", array($team_id))->select();\n            if ($teamMembers) {\n                foreach ($teamMembers as $key => $value) {\n                    $data = array(\n                        \"team_id\" => $team_id,\n                        \"member_uid\" => $value['member_uid'],\n                        \"member_username\" => $value['member_username'],\n                        \"item_id\" => $item_id,\n                        \"member_group_id\" => 1, //默认添加的权限为1，即编辑权限\n                        \"addtime\" => time()\n                    );\n                    D(\"TeamItemMember\")->add($data);\n                }\n            }\n        }\n\n\n        $return = D(\"TeamItem\")->where(array('id' => $id))->find();\n\n        if (!$return) {\n            $return['error_code'] = 10103;\n            $return['error_message'] = 'request  fail';\n        }\n\n        $this->sendResult($return);\n    }\n\n    //根据项目来获取其绑定的团队列表\n    public function getList()\n    {\n        $login_user = $this->checkLogin();\n        $uid = $login_user['uid'];\n\n        $item_id = I(\"item_id/d\");\n\n        if (!$this->checkItemManage($uid, $item_id)) {\n            $this->sendError(10303);\n            return;\n        }\n\n        $sql  = \"select team.*,team_item.team_id , team_item.id as id from team left join team_item on team.id = team_item.team_id where team_item.item_id = '%d' \";\n        $ret = D(\"TeamItem\")->query(sprintf($sql, $item_id));\n\n        if ($ret) {\n            foreach ($ret as $key => &$value) {\n                $value['addtime'] = date(\"Y-m-d H:i:s\", $value['addtime']);\n            }\n            $this->sendResult($ret);\n        } else {\n            $this->sendResult(array());\n        }\n    }\n\n    //根据团队来获取项目列表\n    public function getListByTeam()\n    {\n        $login_user = $this->checkLogin();\n        $uid = $login_user['uid'];\n\n        $team_id = I(\"team_id/d\");\n\n        // 权限判断。团队管理者和团队成员可以看到该列表\n        if (!$this->checkTeamManage($uid, $team_id) && !D(\"TeamMember\")->where(\" member_uid = '%d' and team_id = '%d' \", array($uid, $team_id))->find()) {\n            $this->sendError(10103);\n            return;\n        }\n\n        $teamInfo = D(\"Team\")->where(array('id' => $team_id))->find();\n\n\n        $sql  = \"select item.*,team_item.team_id , team_item.id as id from item left join team_item on item.item_id = team_item.item_id where team_item.team_id = '%d' and item.is_del = 0 \";\n        $ret = D(\"Item\")->query(sprintf($sql, $team_id));\n\n        if ($ret) {\n            foreach ($ret as $key => &$value) {\n                $value['addtime'] = date(\"Y-m-d H:i:s\", $value['addtime']);\n            }\n            $this->sendResult($ret);\n        } else {\n            $this->sendResult(array());\n        }\n    }\n\n\n    //删除\n    public function delete()\n    {\n        $login_user = $this->checkLogin();\n        $uid = $login_user['uid'];\n\n        $id = I(\"post.id/d\") ? I(\"post.id/d\") : 0;\n        $teamItemInfo = D(\"TeamItem\")->where(array('id' => $id))->find();\n        $item_id = $teamItemInfo['item_id'];\n        $team_id = $teamItemInfo['team_id'];\n\n        if (!$this->checkTeamManage($uid, $team_id)) {\n            $this->sendError(10103);\n            return;\n        }\n\n        $ret = D(\"TeamItemMember\")->where(\" item_id = '%d' and team_id = '%d' \", array($item_id, $team_id))->delete();\n        $ret = D(\"TeamItem\")->where(array('id' => $id))->delete();\n\n        if ($ret) {\n            $teamInfo = D(\"Team\")->where(array('id' => $team_id))->find();\n            D(\"ItemChangeLog\")->addLog($login_user['uid'], $item_id, 'unbound', 'team', $team_id, $teamInfo['team_name']);\n            $this->sendResult($ret);\n        } else {\n            $return['error_code'] = 10103;\n            $return['error_message'] = 'request  fail';\n            $this->sendResult($return);\n        }\n    }\n}\n"
  },
  {
    "path": "server/Application/Api/Controller/TeamItemMemberController.class.php",
    "content": "<?php\n\nnamespace Api\\Controller;\n\nuse Think\\Controller;\n/*\n    成员组和项目绑定后，每个人的绑定情况\n */\n\nclass TeamItemMemberController extends BaseController\n{\n\n    //添加和编辑\n    //由于初始添加成员的时候就已经有了记录，所以本方法是编辑\n    public function save()\n    {\n        $login_user = $this->checkLogin();\n        $uid = $login_user['uid'];\n\n        $id = I(\"post.id/d\");\n        $member_group_id = I(\"post.member_group_id/d\");\n        $cat_id = I(\"post.cat_id/d\");\n        $cat_ids = I(\"post.cat_ids\"); // 逗号分隔的多目录\n\n        $teamItemMemberInfo = D(\"TeamItemMember\")->where(array('id' => $id))->find();\n        $item_id = $teamItemMemberInfo['item_id'];\n        $team_id = $teamItemMemberInfo['team_id'];\n\n        if (!$this->checkTeamManage($uid, $team_id)) {\n            $this->sendError(10103);\n            return;\n        }\n\n        $teamInfo = D(\"Team\")->where(array('id' => $team_id))->find();\n\n        if (isset($_POST['member_group_id'])) {\n            $return = D(\"TeamItemMember\")->where(array('id' => $id))->save(array(\"member_group_id\" => $member_group_id));\n        }\n        if (isset($_POST['cat_id'])) {\n            $return = D(\"TeamItemMember\")->where(array('id' => $id))->save(array(\"cat_id\" => $cat_id));\n        }\n        if (isset($_POST['cat_ids'])) {\n            $ids = array();\n            if (is_array($cat_ids)) {\n                $ids = $cat_ids;\n            } else if (is_string($cat_ids)) {\n                if (strpos($cat_ids, ',') !== false) {\n                    $ids = preg_split('/\\s*,\\s*/', trim($cat_ids));\n                } else if (ctype_digit($cat_ids)) {\n                    $ids = array(intval($cat_ids));\n                }\n            }\n            $ids2 = array();\n            if (!empty($ids)) {\n                foreach ($ids as $v) {\n                    $v = intval($v);\n                    if ($v <= 0) continue;\n                    $cat = D(\"Catalog\")->where(\"cat_id = '%d' and item_id = '%d' and level = 2\", array($v, $item_id))->find();\n                    if ($cat) $ids2[] = $v;\n                }\n                $ids2 = array_values(array_unique($ids2));\n            }\n            $return = D(\"TeamItemMember\")->where(array('id' => $id))->save(array(\"cat_ids\" => !empty($ids2) ? implode(',', $ids2) : ''));\n        }\n        $this->sendResult($return);\n    }\n\n    //获取列表\n    public function getList()\n    {\n        $login_user = $this->checkLogin();\n        $uid = $login_user['uid'];\n\n        $item_id = I(\"item_id/d\");\n        $team_id = I(\"team_id/d\");\n\n\n        if (!$this->checkTeamManage($uid, $team_id)) {\n            $this->sendError(10103);\n            return;\n        }\n\n        $ret = D(\"TeamItemMember\")->where(\" item_id = '%d'  and team_id = '%d' \", array($item_id, $team_id))->select();\n\n        if ($ret) {\n            foreach ($ret as $key => &$value) {\n                $value['addtime'] = date(\"Y-m-d H:i:s\", $value['addtime']);\n                $value['cat_name'] = '所有目录';\n                // 当存在多目录时，简单展示为“多个目录”；同时为前端多选预填 cat_ids 数组\n                if (!empty($value['cat_ids'])) {\n                    $value['cat_name'] = '多个目录';\n                    $str = (string)$value['cat_ids'];\n                    $ids = array();\n                    if (strpos($str, ',') !== false) {\n                        $ids = preg_split('/\\s*,\\s*/', trim($str));\n                    } else if (ctype_digit($str)) {\n                        $ids = array(intval($str));\n                    }\n                    $value['cat_ids'] = array_values(array_unique(array_map('intval', $ids)));\n                } else if ($value['cat_id'] > 0) {\n                    $row = D(\"Catalog\")->where(array('cat_id' => $value['cat_id']))->find();\n                    if ($row &&  $row['cat_name']) {\n                        $value['cat_name'] =  $row['cat_name'];\n                    }\n                    $value['cat_ids'] = array(intval($value['cat_id']));\n                } else {\n                    $value['cat_ids'] = array();\n                }\n                $uid = $value['member_uid'];\n                $row = D(\"User\")->where(array('uid' => $uid))->find();\n                $value['name'] = $row['name'];\n            }\n            $this->sendResult($ret);\n        } else {\n            $this->sendResult(array());\n        }\n    }\n}\n"
  },
  {
    "path": "server/Application/Api/Controller/TeamMemberController.class.php",
    "content": "<?php\n\nnamespace Api\\Controller;\n\nuse Think\\Controller;\n/*\n    团队成员管理\n */\n\nclass TeamMemberController extends BaseController\n{\n\n    //添加和编辑\n    public function save()\n    {\n        $login_user = $this->checkLogin();\n        $uid = $login_user['uid'];\n\n        $member_username = I(\"member_username\");\n        $team_id = I(\"post.team_id/d\");\n        $team_member_group_id = I(\"post.team_member_group_id/d\") ? I(\"post.team_member_group_id/d\") : 1;\n\n        if (!$this->checkTeamManage($uid, $team_id)) {\n            $this->sendError(10103);\n            return;\n        }\n\n        $teamInfo = D(\"Team\")->where(array('id' => $team_id))->find();\n\n        $member_username_array = explode(\",\", $member_username);\n        foreach ($member_username_array as $key => $value) {\n            $memberInfo = D(\"User\")->where(array('username' => $value))->find();\n            if (!$memberInfo) {\n                continue;\n            }\n            $if_exit = D(\"TeamMember\")->where(\" member_uid = '%d' and team_id = '%d' \", array($memberInfo['uid'], $team_id))->find();\n            if ($if_exit) {\n                continue;\n            }\n            $data = array();\n            $data['team_id'] = $team_id;\n            $data['member_uid'] = $memberInfo['uid'];\n            $data['member_username'] = $memberInfo['username'];\n            $data['team_member_group_id'] = $team_member_group_id;\n            $data['addtime'] = time();\n            $id = D(\"TeamMember\")->add($data);\n\n            //检查该团队已经加入了哪些项目\n            $teamItems = D(\"TeamItem\")->where(array('team_id' => $team_id))->select();\n            if ($teamItems) {\n                foreach ($teamItems as $key2 => $value2) {\n                    $data = array(\n                        \"team_id\" => $team_id,\n                        \"member_uid\" => $memberInfo['uid'],\n                        \"member_username\" => $memberInfo['username'],\n                        \"item_id\" => $value2['item_id'],\n                        \"member_group_id\" => 1, //默认添加的权限为1，即编辑权限\n                        \"addtime\" => time()\n                    );\n                    D(\"TeamItemMember\")->add($data);\n                }\n            }\n        }\n\n        $return = D(\"TeamMember\")->where(array('id' => $id))->find();\n\n        if (!$return) {\n            $return['error_code'] = 10103;\n            $return['error_message'] = 'request  fail';\n        }\n\n        $this->sendResult($return);\n    }\n\n    //获取列表\n    public function getList()\n    {\n        $login_user = $this->checkLogin();\n        $uid = $login_user['uid'];\n        $team_id = I(\"team_id/d\");\n\n        // 权限判断。团队管理者和团队成员可以看到该列表\n        if (!$this->checkTeamManage($uid, $team_id) && !D(\"TeamMember\")->where(\" member_uid = '%d' and team_id = '%d' \", array($uid, $team_id))->find()) {\n            $this->sendError(10103);\n            return;\n        }\n\n        $teamInfo = D(\"Team\")->where(array('id' => $team_id))->find();\n\n        if ($login_user['uid'] > 0) {\n            $ret = D(\"TeamMember\")->where(\" team_id = '%d' \", array($team_id))->join(\" left join user on user.uid = team_member.member_uid\")->field(\"team_member.* , user.name as name\")->order(\" addtime desc  \")->select();\n        }\n        if ($ret) {\n            foreach ($ret as $key => &$value) {\n                $value['addtime'] = date(\"Y-m-d H:i:s\", $value['addtime']);\n            }\n            $this->sendResult($ret);\n        } else {\n            $this->sendResult(array());\n        }\n    }\n\n    //删除\n    public function delete()\n    {\n        $login_user = $this->checkLogin();\n        $uid = $login_user['uid'];\n        $id = I(\"post.id/d\") ? I(\"post.id/d\") : 0;\n        $teamMemberInfo = D(\"TeamMember\")->where(array('id' => $id))->find();\n        $team_id = $teamMemberInfo['team_id'];\n\n        if (!$this->checkTeamManage($uid, $team_id)) {\n            $this->sendError(10103);\n            return;\n        }\n\n        $teamInfo = D(\"Team\")->where(array('id' => $team_id))->find();\n        $ret = D(\"TeamItemMember\")->where(\" member_uid = '%d' and  team_id = '%d' \", array($teamMemberInfo['member_uid'], $team_id))->delete();\n        $ret = D(\"TeamMember\")->where(array('id' => $id))->delete();\n\n\n        if ($ret) {\n            $this->sendResult($ret);\n        } else {\n            $return['error_code'] = 10103;\n            $return['error_message'] = 'request  fail';\n            $this->sendResult($return);\n        }\n    }\n}\n"
  },
  {
    "path": "server/Application/Api/Controller/TemplateController.class.php",
    "content": "<?php\n\nnamespace Api\\Controller;\n\nuse Think\\Controller;\n\nclass TemplateController extends BaseController\n{\n\n\n    //保存\n    public function save()\n    {\n        $login_user = $this->checkLogin();\n\n        $template_title = I(\"template_title\");\n        $template_content = I(\"template_content\");\n\n        $data['username'] = $login_user['username'];\n        $data['uid'] = $login_user['uid'];\n        $data['template_title'] = $template_title;\n        $data['template_content'] = $template_content;\n        $data['addtime'] = time();\n\n\n        $id = D(\"Template\")->add($data);\n        $return = D(\"Template\")->where(array('id' => $id))->find();\n\n        if (!$return) {\n            $return['error_code'] = 10103;\n            $return['error_message'] = 'request  fail';\n        }\n\n        $this->sendResult($return);\n    }\n\n    //获取我的模板列表\n    public function getList()\n    {\n        $this->getMyList();  // 因为有些客户端已经使用了getList方法，所以要向后兼容\n    }\n\n    //获取我的模板列表\n    public function getMyList()\n    {\n        $login_user = $this->checkLogin();\n        if ($login_user['uid'] > 0) {\n            $ret = D(\"Template\")->where(array('uid' => $login_user['uid']))->order(\" addtime desc  \")->select();\n        }\n        if ($ret) {\n            foreach ($ret as $key => &$value) {\n                $value['addtime'] = date(\"Y-m-d H:i:s\", $value['addtime']);\n                $value['template_content'] = htmlspecialchars_decode($value['template_content']);\n                // 获取当前模板被共享到哪些项目中\n                $res = D(\"TemplateItem\")->where(array('template_id' => $value['id']))->select();\n                $value['share_item'] = $res ? $res : array();\n                $value['share_item_count'] = count($value['share_item']);\n            }\n            $this->sendResult($ret);\n        } else {\n            $this->sendResult(array());\n        }\n    }\n\n    //获取当前项目的模板列表\n    public function getItemList()\n    {\n        $login_user = $this->checkLogin();\n        $item_id = I(\"post.item_id/d\") ? I(\"post.item_id/d\") : 0;\n        if (!$this->checkItemEdit($login_user['uid'], $item_id)) {\n            $this->sendError(10103);\n            return;\n        }\n\n        $res = D(\"TemplateItem\")->where(\"  item_id = '%d' \", array($item_id))->join(\" left join template on template.id = template_item.template_id \")->select();\n        if ($res) {\n            foreach ($res as $key => &$value) {\n                $value['addtime'] = date(\"Y-m-d H:i:s\", $value['addtime']);\n                $value['template_content'] = htmlspecialchars_decode($value['template_content']);\n            }\n            $this->sendResult($res);\n        } else {\n            $this->sendResult(array());\n        }\n    }\n\n    //删除\n    public function delete()\n    {\n        $id = I(\"post.id/d\") ? I(\"post.id/d\") : 0;\n        $login_user = $this->checkLogin();\n        $uid = $login_user['uid'];\n        // 这里验证一下。传进来的模板id需要是他自己本人的\n        if (!D(\"Template\")->where(\"  id = '%d' and uid = '%d' \", array($id, $uid))->find()) {\n            $this->sendError(10103);\n            return;\n        }\n\n        if ($id) {\n            $ret = D(\"Template\")->where(array('id' => $id))->delete();\n            D(\"TemplateItem\")->where(array('template_id' => $id))->delete();\n            $this->sendResult(array());\n            return;\n        }\n        $this->sendError(10101);\n    }\n\n    // 把模板分享给项目\n    public function shareToItem()\n    {\n        $login_user = $this->checkLogin();\n        $uid = $login_user['uid'];\n        $item_id = I(\"item_id\"); // 这里的item_id可能是逗号分隔的字符串\n        $template_id = I(\"template_id/d\");\n        $item_id_array = explode(\",\", $item_id);\n\n        // 这里验证一下。传进来的模板id需要是他自己本人的\n        if (!D(\"Template\")->where(\"  id = '%d' and uid = '%d' \", array($template_id, $uid))->find()) {\n            $this->sendError(10103);\n            return;\n        }\n        $res = '';\n        D(\"TemplateItem\")->where(array('template_id' => $template_id))->delete();\n        foreach ($item_id_array as $key => $value) {\n            $item_id = intval($value);\n            if (!$item_id) continue;\n            if (!$this->checkItemEdit($uid, $item_id)) {\n                $this->sendError(10103);\n                return;\n            }\n\n            if (D(\"TemplateItem\")->where(\"  template_id = '%d' and item_id = '%d' \", array($template_id, $item_id))->find()) {\n                continue; //如果该模板已经分享到该项目中了，则结束当前一次循环。\n            }\n\n            $res = D(\"TemplateItem\")->add(array(\n                \"template_id\" => $template_id,\n                \"item_id\" => $item_id,\n                \"uid\" => $uid,\n                \"username\" => $login_user['username'],\n                \"created_at\" => date(\"Y-m-d H:i:s\")\n            ));\n        }\n        $this->sendResult(array());\n    }\n\n    // 获取“某个模板已经被共享到什么项目中了”的列表\n    public function getShareItemList()\n    {\n        $login_user = $this->checkLogin();\n        $uid = $login_user['uid'];\n        $template_id = I(\"template_id/d\");\n        // 这里验证一下。传进来的模板id需要是他自己本人的\n        if (!D(\"Template\")->where(\"  id = '%d' and uid = '%d' \", array($template_id, $uid))->find()) {\n            $this->sendError(10103);\n            return;\n        }\n\n        $res = D(\"TemplateItem\")->where(array('template_id' => $template_id))->select();\n        if ($res) {\n            $this->sendResult($res);\n        } else {\n            $this->sendResult(array());\n        }\n    }\n}\n"
  },
  {
    "path": "server/Application/Api/Controller/UpdateController.class.php",
    "content": "<?php\n\nnamespace Api\\Controller;\n\nuse Think\\Controller;\n\nclass UpdateController extends BaseController\n{\n\n    //检测数据库并更新\n    public function checkDb($showBack = true)\n    {\n\n        // 由于在BaseController的构造函数执行过一次升级了，所以这里不需要动作\n        // 保留着是为了兼容历史\n\n        if ($showBack) {\n            $this->sendResult(array());\n        }\n    }\n    // 从最新docker镜像中更新代码\n    public function dockerUpdateCode()\n    {\n        if (!preg_match(\"/cli/i\", php_sapi_name())) {\n            echo '只能从命令行中调用';\n            return;\n        }\n        $showdoc_path = \"/var/www/html/\";\n        // 进行文件读写权限检查\n        if (\n            !$this->new_is_writeable($showdoc_path)\n            || !$this->new_is_writeable($showdoc_path . \"Sqlite/\")\n            || !$this->new_is_writeable($showdoc_path . \"web/\")\n            || !$this->new_is_writeable($showdoc_path . \"web/index.php\")\n            || !$this->new_is_writeable($showdoc_path . \"server/\")\n            || !$this->new_is_writeable($showdoc_path . \"server/vendor/autoload.php\")\n            || !$this->new_is_writeable($showdoc_path . \"server/Application/Api\")\n        ) {\n            $this->sendError(10101, '请手动给showdoc安装目录下的所有文件可写权限，否则程序无法覆盖旧文件');\n            return;\n        }\n\n        //获取当前版本号\n        $text = file_get_contents($showdoc_path . \"composer.json\");\n        $composer = json_decode($text, true);\n        $cur_version = $composer['version'];\n\n        // 获取docker中的版本号\n        $text = file_get_contents(\"/showdoc_data/html/composer.json\");\n        $composer = json_decode($text, true);\n        $version_in_docker = $composer['version'];\n\n        if ($cur_version && $version_in_docker && version_compare($version_in_docker, $cur_version) > 0) {\n            // 比较版本后，应该更新\n\n            // 获取原来的语言设置\n            $lang = get_lang($showdoc_path . \"web/index.html\") ;\n\n            //复制数据库文件备份\n            $bak_name = $showdoc_path . 'Sqlite/showdoc.db.bak.' . date(\"Y-m-d-H-i-s\") . '.php';\n            copy($showdoc_path . 'Sqlite/showdoc.db.php', $bak_name);\n\n            // 目录覆盖\n            $this->copydir('/showdoc_data/html/', $showdoc_path);\n            // 用备份的数据库还原\n            copy($bak_name, $showdoc_path . 'Sqlite/showdoc.db.php');\n\n\n            // 恢复语言设置\n            if ($lang == 'en') {\n                $this->replace_file_content($showdoc_path . \"web/index.html\",\"zh-cn\",\"en\") ;\n                $this->replace_file_content($showdoc_path . \"web_src/index.html\",\"zh-cn\",\"en\") ;\n            }\n\n            // echo '升级成功！' ;\n            $this->sendResult(array());\n        }\n    }\n\n    /**\n     * 复制到目录\n     * $dirsrc  原目录\n     * $dirto  目标目录\n     *\n     */\n    private function copydir($dirsrc, $dirto)\n    {\n        //如果原来的文件存在， 是不是一个目录\n\n        if (file_exists($dirto)) {\n            if (!is_dir($dirto)) {\n                echo \"目标不是一个目录， 不能copy进去<br>\";\n                exit;\n            }\n        } else {\n            mkdir($dirto);\n        }\n\n\n        $dir = opendir($dirsrc);\n\n        while ($filename = readdir($dir)) {\n            if ($filename != \".\" && $filename != \"..\") {\n                $srcfile = $dirsrc . \"/\" . $filename;  //原文件\n                $tofile = $dirto . \"/\" . $filename;    //目标文件\n\n                if (is_dir($srcfile)) {\n                    $this->copydir($srcfile, $tofile);  //递归处理所有子目录\n                } else {\n                    copy($srcfile, $tofile);\n                }\n            }\n        }\n    }\n\n    /**\n     * 判断 文件/目录 是否可写（取代系统自带的 is_writeable 函数）\n     *\n     * @param string $file 文件/目录\n     * @return boolean\n     */\n    private function new_is_writeable($file)\n    {\n        if (is_dir($file)) {\n            $dir = $file;\n            if ($fp = @fopen(\"$dir/test.txt\", 'w')) {\n                @fclose($fp);\n                @unlink(\"$dir/test.txt\");\n                $writeable = 1;\n            } else {\n                $writeable = 0;\n            }\n        } else {\n            if ($fp = @fopen($file, 'a+')) {\n                @fclose($fp);\n                $writeable = 1;\n            } else {\n                $writeable = 0;\n            }\n        }\n\n        return $writeable;\n    }\n\n    private function replace_file_content($file , $from ,$to )\n    {\n        $content = file_get_contents($file);\n        $content2 = str_replace($from,$to,$content);\n        if ($content2) {\n            file_put_contents($file,$content2);\n        }\n    }\n}\n"
  },
  {
    "path": "server/Application/Api/Controller/UserController.class.php",
    "content": "<?php\n\nnamespace Api\\Controller;\n\nuse Think\\Controller;\n\nclass UserController extends BaseController\n{\n\n    /**\n     * 获取登录态有效时长（秒数）\n     * 如果未配置或配置无效，返回默认值180天（60 * 60 * 24 * 180）\n     * 最小值为1天，最大值为3650天（10年）\n     * \n     * @return int 登录态有效时长（秒数）\n     */\n    private function getSessionExpireTime()\n    {\n        $session_expire_days = D(\"Options\")->get(\"session_expire_days\");\n        \n        // 如果未配置或为false，使用默认值180天\n        if ($session_expire_days === false || $session_expire_days === '' || $session_expire_days === null) {\n            return 60 * 60 * 24 * 180; // 默认180天\n        }\n        \n        $session_expire_days = intval($session_expire_days);\n        \n        // 如果配置值无效（小于1或大于3650），使用默认值180天\n        if ($session_expire_days < 1 || $session_expire_days > 3650) {\n            return 60 * 60 * 24 * 180; // 默认180天\n        }\n        \n        // 返回配置的天数对应的秒数\n        return $session_expire_days * 24 * 60 * 60;\n    }\n\n    //注册。慢慢废弃，将主用registerByVerify()\n    public function register()\n    {\n        $username = trim(I(\"username\"));\n        $password = I(\"password\");\n        $confirm_password = I(\"confirm_password\");\n        $v_code = strtolower(I(\"v_code\"));\n        $register_open = D(\"Options\")->get(\"register_open\");\n        if ($register_open === '0') {\n            $this->sendError(10101, \"管理员已关闭注册\");\n            return;\n        }\n        if (strlen($password) > 100) {\n            $this->sendError(10101, \"密码过长\");\n            return;\n        }\n        // 验证密码强度\n        $password_validation = validate_strong_password($password);\n        if (!$password_validation['valid']) {\n            $this->sendError(10101, $password_validation['message']);\n            return;\n        }\n        if (C('CloseVerify') || $v_code && $v_code == session('v_code')) {\n            session('v_code', null);\n            if ($password != '' && $password == $confirm_password) {\n\n                if (!D(\"User\")->checkDbOk()) {\n                    $this->sendError(100100, \"数据库连接不上。请确保安装了php-sqlite扩展以及数据库文件Sqlite/showdoc.db.php可用\");\n                    return;\n                }\n\n                if (!D(\"User\")->isExist($username)) {\n                    $new_uid = D(\"User\")->register($username, $password);\n                    if ($new_uid) {\n\n                        $create_sample = D(\"Options\")->get(\"create_sample\");\n                        //获取后台的语言设置\n                        //这是个历史包袱。因为安装的时候语言设置没有写到API模块的配置下，所以只能读文件读取Home模快的配置文件\n                        $config = file_get_contents(\"./Application/Home/Conf/config.php\");\n                        if ($create_sample !== '0' && strstr($config, \"'zh-cn',\")) {\n                            //导入示例项目\n                            $this->_importSample($new_uid);\n                        }\n\n                        //设置自动登录\n                        $ret = D(\"User\")->where(array('uid' => $new_uid))->find();\n                        unset($ret['password']);\n                        session(\"login_user\", $ret);\n                        $token_expire_time = $this->getSessionExpireTime();\n                        $token = D(\"UserToken\")->createToken($ret['uid'], $token_expire_time);\n                        $cookie_expire = time() + $token_expire_time;\n                        if (version_compare(PHP_VERSION, '7.3.0', '>')) {\n                            setcookie('cookie_token', $token, array('expires' => $cookie_expire, 'httponly' => 'httponly', 'samesite' => 'Strict', 'path' => '/'));\n                        } else {\n                            cookie('cookie_token', $token, array('expire' => 60 * 60 * 24 * 180, 'httponly' => 'httponly'));\n                        }\n                        $this->sendResult(array(\n                            \"uid\" => $ret['uid'],\n                            \"username\" => $ret['username'],\n                            \"name\" => $ret['name'],\n                            \"groupid\" => $ret['groupid'],\n                            \"avatar\" => $ret['avatar'],\n                            \"avatar_small\" => $ret['avatar_small'],\n                            \"email\" => $ret['email'],\n                            \"email_verify\" => $ret['email_verify'],\n                            \"user_token\" => $token,\n                        ));\n                    } else {\n                        $this->sendError(10101, 'register fail');\n                    }\n                } else {\n                    $this->sendError(10101, L('username_exists'));\n                }\n            } else {\n                $this->sendError(10101, L('code_much_the_same'));\n            }\n        } else {\n            $this->sendError(10206, L('verification_code_are_incorrect'));\n        }\n    }\n\n    //导入示例项目\n    private function _importSample($uid)\n    {\n        $this->_importZip(\"../Public/SampleZip/apidoc.zip\", $uid);\n        $this->_importZip(\"../Public/SampleZip/databasedoc.zip\", $uid);\n        $this->_importZip(\"../Public/SampleZip/teamdoc.zip\", $uid);\n        $this->_importZip(\"../Public/SampleZip/spreadsheet.zip\", $uid);\n        $this->_importZip(\"../Public/SampleZip/whiteboard.zip\", $uid);\n    }\n\n    private function _importZip($file, $uid)\n    {\n        $zipArc = new \\ZipArchive();\n        $ret = $zipArc->open($file, \\ZipArchive::CREATE);\n        $info = $zipArc->getFromName(\"prefix_info.json\");\n        if ($info) {\n            $info_array = json_decode($info, 1);\n            if ($info_array) {\n                D(\"Item\")->import(json_encode($info_array), $uid);\n                return true;\n            }\n        }\n        return false;\n    }\n\n    //登录。慢慢废弃，将主用loginByVerify()\n    public function login()\n    {\n        $username = trim(I(\"username\"));\n        $password = I(\"password\");\n        $v_code = strtolower(I(\"v_code\"));\n        if (!$password) {\n            $this->sendError(10206, \"no empty password\");\n            return;\n        }\n        //检查用户输错密码的次数。如果超过一定次数，则需要验证 验证码\n        $key = 'login_fail_times_' . $username;\n        if (!D(\"VerifyCode\")->_check_times($key)) {\n            if (!$v_code || $v_code != session('v_code')) {\n                $this->sendError(10206, L('verification_code_are_incorrect'));\n                return;\n            }\n        }\n        session('v_code', null);\n\n        if (!D(\"User\")->checkDbOk()) {\n            $this->sendError(100100, \"数据库连接不上。请确保安装了php-sqlite扩展以及数据库文件Sqlite/showdoc.db.php可用\");\n            return;\n        }\n\n        $ret = D(\"User\")->checkLogin($username, $password);\n        //如果失败则尝试ldap登录\n        if (!$ret) {\n            $ret = D(\"User\")->checkLdapLogin($username, $password);\n        }\n        if ($ret) {\n            //获取后台的语言设置\n            //这是个历史包袱。因为安装的时候语言设置没有写到API模块的配置下，所以只能读文件读取Home模快的配置文件\n            $config = file_get_contents(\"./Application/Home/Conf/config.php\");\n\n            if (D(\"Item\")->count() < 1 && strstr($config, \"'zh-cn',\")) {\n                //如果项目表是空的，则生成系统示例项目\n                $this->_importSample(1);\n            }\n            // 如果因为历史原因，没有密码盐，则创建一个\n            if (!$ret['salt']) {\n                $salt = get_rand_str();\n                $password = encry_password($password, $salt);\n                D(\"User\")->where(\"uid = '%d' \", array($ret['uid']))->save(array('salt' => $salt, 'password' => $password));\n            }\n\n            unset($ret['password']);\n            unset($ret['salt']);\n            session(\"login_user\", $ret);\n            D(\"User\")->setLastTime($ret['uid']);\n            $token_expire_time = $this->getSessionExpireTime();\n            $token = D(\"UserToken\")->createToken($ret['uid'], $token_expire_time);\n            $cookie_expire = time() + $token_expire_time;\n            if (version_compare(PHP_VERSION, '7.3.0', '>')) {\n                setcookie('cookie_token', $token, array('expires' => $cookie_expire, 'httponly' => 'httponly', 'samesite' => 'Strict', 'path' => '/'));\n            } else {\n                cookie('cookie_token', $token, array('expire' => 60 * 60 * 24 * 180, 'httponly' => 'httponly'));\n            }\n            $this->sendResult(array(\n                \"uid\" => $ret['uid'],\n                \"username\" => $ret['username'],\n                \"name\" => $ret['name'],\n                \"groupid\" => $ret['groupid'],\n                \"avatar\" => $ret['avatar'],\n                \"avatar_small\" => $ret['avatar_small'],\n                \"email\" => $ret['email'],\n                \"email_verify\" => $ret['email_verify'],\n                \"user_token\" => $token,\n            ));\n        } else {\n            D(\"VerifyCode\")->_ins_times($key); //输错密码则设置输错次数\n\n            if (D(\"VerifyCode\")->_check_times($key)) {\n                $error_code = 10204;\n            } else {\n                $error_code = 10210;\n            }\n            $this->sendError($error_code, L('username_or_password_incorrect'));\n            return;\n        }\n    }\n\n    //登录2\n    public function loginByVerify()\n    {\n        $username = I(\"username\");\n        $password = I(\"password\");\n        $captcha_id = I(\"captcha_id\");\n        $captcha = I(\"captcha\");\n\n        if (!D(\"Captcha\")->check($captcha_id, $captcha)) {\n            $this->sendError(10206, L('verification_code_are_incorrect'));\n            return;\n        }\n        $ret = D(\"User\")->checkLogin($username, $password);\n        //如果失败则尝试ldap登录\n        if (!$ret) {\n            $ret = D(\"User\")->checkLdapLogin($username, $password);\n        }\n\n        if ($ret) {\n\n            //获取后台的语言设置\n            //这是个历史包袱。因为安装的时候语言设置没有写到API模块的配置下，所以只能读文件读取Home模快的配置文件\n            $config = file_get_contents(\"./Application/Home/Conf/config.php\");\n\n            if (D(\"Item\")->count() < 1 && strstr($config, \"'zh-cn',\")) {\n                //如果项目表是空的，则生成系统示例项目\n                $this->_importSample(1);\n            }\n\n            // 如果因为历史原因，没有密码盐，则创建一个\n            if (!$ret['salt']) {\n                $salt = get_rand_str();\n                $password = encry_password($password, $salt);\n                D(\"User\")->where(\"uid ='%d' \", array($ret['uid']))->save(array('salt' => $salt, 'password' => $password));\n            }\n\n            unset($ret['password']);\n            unset($ret['salt']);\n            session(\"login_user\", $ret);\n            D(\"User\")->setLastTime($ret['uid']);\n            $token_expire_time = $this->getSessionExpireTime();\n            $token = D(\"UserToken\")->createToken($ret['uid'], $token_expire_time);\n            $this->sendResult(array(\n                \"uid\" => $ret['uid'],\n                \"username\" => $ret['username'],\n                \"name\" => $ret['name'],\n                \"groupid\" => $ret['groupid'],\n                \"avatar\" => $ret['avatar'],\n                \"avatar_small\" => $ret['avatar_small'],\n                \"email\" => $ret['email'],\n                \"email_verify\" => $ret['email_verify'],\n                \"user_token\" => $token,\n            ));\n        } else {\n            $this->sendError(10204, L('username_or_password_incorrect'));\n            return;\n        }\n    }\n\n    //注册2\n    public function registerByVerify()\n    {\n        $username = trim(I(\"username\"));\n        $password = I(\"password\");\n        $confirm_password = I(\"confirm_password\");\n        $captcha_id = I(\"captcha_id\");\n        $captcha = I(\"captcha\");\n        $register_open = D(\"Options\")->get(\"register_open\");\n        if ($register_open === '0') {\n            $this->sendError(10101, \"管理员已关闭注册\");\n            return;\n        }\n        if (strlen($password) > 100) {\n            $this->sendError(10101, \"密码过长\");\n            return;\n        }\n        // 验证密码强度\n        $password_validation = validate_strong_password($password);\n        if (!$password_validation['valid']) {\n            $this->sendError(10101, $password_validation['message']);\n            return;\n        }\n        if (!D(\"Captcha\")->check($captcha_id, $captcha)) {\n            $this->sendError(10206, L('verification_code_are_incorrect'));\n            return;\n        }\n        if ($password != '' && $password == $confirm_password) {\n\n            if (!D(\"User\")->isExist($username)) {\n                $new_uid = D(\"User\")->register($username, $password);\n                if ($new_uid) {\n\n                    $create_sample = D(\"Options\")->get(\"create_sample\");\n                    //获取后台的语言设置\n                    //这是个历史包袱。因为安装的时候语言设置没有写到API模块的配置下，所以只能读文件读取Home模快的配置文件\n                    $config = file_get_contents(\"./Application/Home/Conf/config.php\");\n                    if ($create_sample !== '0' && strstr($config, \"'zh-cn',\")) {\n                        //导入示例项目\n                        $this->_importSample($new_uid);\n                    }\n\n                    //设置自动登录\n                    $ret = D(\"User\")->where(array('uid' => $new_uid))->find();\n                    unset($ret['password']);\n                    session(\"login_user\", $ret);\n                    $token_expire_time = $this->getSessionExpireTime();\n                    $token = D(\"UserToken\")->createToken($ret['uid'], $token_expire_time);\n                    $cookie_expire = time() + $token_expire_time;\n                    if (version_compare(PHP_VERSION, '7.3.0', '>')) {\n                        setcookie('cookie_token', $token, array('expires' => $cookie_expire, 'httponly' => 'httponly', 'samesite' => 'Strict', 'path' => '/'));\n                    } else {\n                        cookie('cookie_token', $token, array('expire' => 60 * 60 * 24 * 180, 'httponly' => 'httponly'));\n                    }\n                    $this->sendResult(array(\n                        \"uid\" => $ret['uid'],\n                        \"username\" => $ret['username'],\n                        \"name\" => $ret['name'],\n                        \"groupid\" => $ret['groupid'],\n                        \"avatar\" => $ret['avatar'],\n                        \"avatar_small\" => $ret['avatar_small'],\n                        \"email\" => $ret['email'],\n                        \"user_token\" => $token,\n                    ));\n                } else {\n                    $this->sendError(10101, 'register fail');\n                }\n            } else {\n                $this->sendError(10101, L('username_exists'));\n            }\n        } else {\n            $this->sendError(10101, L('code_much_the_same'));\n        }\n    }\n\n    //获取用户信息\n    public function info()\n    {\n        $login_user = $this->checkLogin();\n        $uid = $login_user['uid'];\n        $field = \"uid,username,email,name,avatar,avatar_small,groupid\";\n        $info = D(\"User\")->where(array('uid' => $uid))->field($field)->find();\n        $this->sendResult($info);\n    }\n\n    //获取所有用户名\n    public function allUser()\n    {\n        $login_user = $this->checkLogin();\n        $uid = $login_user['uid'];\n        $username = I(\"username\");\n        $field = \"username , uid , name\";\n        if ($username) {\n            $like = safe_like($username);\n            $where = \" username like '%s'\";\n            $params = array($like);\n        } else {\n            $where = ' 1 = 1 ';\n        }\n        $info = isset($params) ? D(\"User\")->where($where, $params)->field($field)->select() : D(\"User\")->where($where)->field($field)->select();\n        $this->sendResult($info);\n    }\n\n    //通过旧密码验证来更新用户密码\n    public function resetPassword()\n    {\n        $login_user = $this->checkLogin();\n        $username = $login_user['username'];\n        $password = I(\"password\");\n        $new_password = I(\"new_password\");\n        if (strlen($new_password) > 100) {\n            $this->sendError(10101, \"密码过长\");\n            return;\n        }\n        // 验证密码强度\n        $password_validation = validate_strong_password($new_password);\n        if (!$password_validation['valid']) {\n            $this->sendError(10101, $password_validation['message']);\n            return;\n        }\n        $ret = D(\"User\")->checkLogin($username, $password);\n        if ($ret) {\n            $ret = D(\"User\")->updatePwd($login_user['uid'], $new_password);\n            if ($ret) {\n                D(\"UserToken\")->where(\"  uid = '%d' \", array($login_user['uid']))->delete();\n                $this->sendResult(array());\n            } else {\n                $this->sendError(10101, L('modify_faild'));\n            }\n        } else {\n            $this->sendError(10101, L('old_password_incorrect'));\n        }\n    }\n\n    //退出登录\n    public function logout()\n    {\n        $login_user = $this->checkLogin();\n        $confirm = I('post.confirm');\n        if ($confirm || strstr($_SERVER['HTTP_USER_AGENT'], \"Html5Plus\")) {\n            D(\"UserToken\")->where(\" uid = '%d' \", array($login_user['uid']))->save(array(\"token_expire\" => 0));\n            session(\"login_user\", NULL);\n            cookie('cookie_token', NULL);\n            session(null);\n            $logout_redirect_uri = '';\n            $oauth2_open = D(\"Options\")->get(\"oauth2_open\");\n            $oauth2_form = D(\"Options\")->get(\"oauth2_form\");\n            $oauth2_form = htmlspecialchars_decode($oauth2_form);\n            $oauth2_form = json_decode($oauth2_form, 1);\n            if ($oauth2_open && $oauth2_form && $oauth2_form['logout_redirect_uri']) {\n                $logout_redirect_uri = $oauth2_form['logout_redirect_uri'];\n            }\n            $this->sendResult(array(\"logout_redirect_uri\" => $logout_redirect_uri));\n        }\n    }\n\n\n    public function updateInfo()\n    {\n        $user = $this->checkLogin();\n        $uid = $user['uid'];\n        $name = I(\"post.name\");\n\n        D(\"User\")->where(array('uid' => $uid))->save(array(\"name\" => $name));\n        $this->sendResult(array());\n    }\n\n    /**\n     * 获取用户的推送地址\n     */\n    public function getPushUrl()\n    {\n        $info = $this->checkLogin();\n        $push_url = D(\"UserSetting\")->getPushUrl($info['uid']);\n        $this->sendResult($push_url);\n    }\n\n    /**\n     * 保存用户的推送地址\n     */\n    public function savePushUrl()\n    {\n        $info = $this->checkLogin();\n        $push_url = I(\"push_url\");\n        D(\"UserSetting\")->savePushUrl($info['uid'], $push_url);\n        $this->sendResult(array());\n    }\n\n    public function oauthInfo()\n    {\n        $oauth2_open = D(\"Options\")->get(\"oauth2_open\");\n        $oauth2_form = D(\"Options\")->get(\"oauth2_form\");\n        $oauth2_entrance_tips = '';\n        if ($oauth2_form) {\n            $oauth2_form = json_decode($oauth2_form, 1);\n            if ($oauth2_form && $oauth2_form['entrance_tips']) {\n                $oauth2_entrance_tips = $oauth2_form['entrance_tips'];\n            }\n        }\n        $this->sendResult(array(\n            \"oauth2_open\" => $oauth2_open,\n            \"oauth2_entrance_tips\" => $oauth2_entrance_tips,\n        ));\n    }\n}\n"
  },
  {
    "path": "server/Application/Api/Controller/index.html",
    "content": " "
  },
  {
    "path": "server/Application/Api/Helper/AiHelper.class.php",
    "content": "<?php\n\nnamespace Api\\Helper;\n\n/**\n * AI 辅助类\n * 提供 AI 相关的公共方法\n */\nclass AiHelper\n{\n  /**\n   * 重建项目索引\n   * @param int $item_id 项目ID\n   * @param string $ai_service_url AI服务地址\n   * @param string $ai_service_token AI服务Token\n   * @return array|false 成功返回结果数组，失败返回false\n   */\n  public static function rebuild($item_id, $ai_service_url, $ai_service_token)\n  {\n    try {\n      // 设置执行时长和内存限制（重建索引可能需要较长时间和较多内存）\n      set_time_limit(3600);  // 60分钟超时（大项目需要更长时间）\n      ini_set('memory_limit', '2G');  // 2GB 内存限制\n\n      // 使用 ItemModel 的 getContent 方法获取所有页面\n      // 注意：开源版没有分表机制，直接使用 getContent 即可\n      $menu = D(\"Item\")->getContent($item_id, \"*\", \"*\", 1);\n      if (!$menu || (empty($menu['pages']) && empty($menu['catalogs']))) {\n        \\Think\\Log::record(\"自动重建索引失败: item_id={$item_id}, 项目中没有可索引的文档\");\n        return false;\n      }\n\n      // 使用 Convert 类转换 API 文档\n      $convert = new Convert();\n\n      // 构建页面数据（递归处理所有页面）\n      $pageData = array();\n      self::_collectPages($menu, $pageData, $convert);\n\n      if (empty($pageData)) {\n        \\Think\\Log::record(\"自动重建索引失败: item_id={$item_id}, 没有可索引的文档（所有页面内容都为空）\");\n        return false;\n      }\n\n      $totalPages = count($pageData);\n\n      // 重建索引前，先清空整个项目的旧索引，避免分批处理时重复删除操作\n      $deleteUrl = rtrim($ai_service_url, '/') . '/api/index/delete-item';\n      $deleteResult = self::callService($deleteUrl, array('item_id' => $item_id), $ai_service_token, 'DELETE', 30);\n      if ($deleteResult === false) {\n        \\Think\\Log::record(\"清空项目旧索引失败（可能不存在）: item_id={$item_id}\");\n      }\n\n      // 分批处理，避免一次性发送所有页面数据导致超时或内存问题\n      // 每批处理 200 个页面（可根据实际情况调整）\n      $batchSize = 200;\n      $url = rtrim($ai_service_url, '/') . '/api/index/rebuild';\n\n      // 如果页面数量较少，一次性提交\n      if ($totalPages <= 100) {\n        $postData = array(\n          'item_id' => $item_id,\n          'pages' => $pageData\n        );\n        $result = self::callService($url, $postData, $ai_service_token, 'POST', 30);  // 30秒超时（只是提交任务）\n        if ($result !== false && isset($result['status']) && $result['status'] == 'success') {\n          \\Think\\Log::record(\"重建索引任务已提交: item_id={$item_id}, 页面总数={$totalPages}, task_id=\" . (isset($result['task_id']) ? $result['task_id'] : ''));\n          return array(\n            'status' => 'success',\n            'message' => '重建索引任务已提交，正在后台处理',\n            'total' => $totalPages,\n            'task_id' => isset($result['task_id']) ? $result['task_id'] : null\n          );\n        }\n      }\n\n      // 如果页面数量太多，分批提交（每批调用一次 rebuild 接口）\n      $totalBatches = ceil($totalPages / $batchSize);\n      $successBatches = 0;\n      $errorBatches = 0;\n      $taskIds = array();\n\n      for ($i = 0; $i < $totalPages; $i += $batchSize) {\n        $batch = array_slice($pageData, $i, $batchSize);\n        $batchNum = floor($i / $batchSize) + 1;\n\n        $postData = array(\n          'item_id' => $item_id,\n          'pages' => $batch\n        );\n\n        $result = self::callService($url, $postData, $ai_service_token, 'POST', 30);\n        if ($result !== false && isset($result['status']) && $result['status'] == 'success') {\n          $successBatches++;\n          if (isset($result['task_id'])) {\n            $taskIds[] = $result['task_id'];\n          }\n        } else {\n          $errorBatches++;\n          \\Think\\Log::record(\"重建索引进度: item_id={$item_id}, 批次 {$batchNum}/{$totalBatches} 提交失败\");\n        }\n\n        // 每批之间稍作延迟，避免请求过于频繁\n        if ($i + $batchSize < $totalPages) {\n          usleep(200000);  // 延迟 0.2 秒\n        }\n      }\n\n      return array(\n        'status' => $errorBatches == 0 ? 'success' : 'partial_success',\n        'message' => $errorBatches == 0 ? '重建索引任务已全部提交，正在后台处理' : \"重建索引任务已提交，但有 {$errorBatches} 个批次失败\",\n        'total' => $totalPages,\n        'total_batches' => $totalBatches,\n        'success_batches' => $successBatches,\n        'error_batches' => $errorBatches,\n        'task_ids' => $taskIds\n      );\n    } catch (\\Exception $e) {\n      \\Think\\Log::record(\"自动重建索引异常: item_id={$item_id}, 错误: \" . $e->getMessage());\n      return false;\n    }\n  }\n\n  /**\n   * 调用 AI 服务（非流式）\n   * @param string $url 请求URL\n   * @param array $postData POST数据\n   * @param string $ai_service_token AI服务Token\n   * @param string $method 请求方法\n   * @param int $timeout 超时时间（秒）\n   * @return array|false\n   */\n  public static function callService($url, $postData = null, $ai_service_token, $method = 'POST', $timeout = 30)\n  {\n    $curl = curl_init();\n    curl_setopt($curl, CURLOPT_URL, $url);\n    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);\n    curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 10);\n    curl_setopt($curl, CURLOPT_TIMEOUT, $timeout);\n    curl_setopt($curl, CURLOPT_ENCODING, '');\n\n    $headers = array(\n      'Content-Type: application/json; charset=utf-8',\n      'Authorization: Bearer ' . $ai_service_token,\n      'Accept: application/json; charset=utf-8'\n    );\n\n    if ($method == 'POST' && $postData) {\n      curl_setopt($curl, CURLOPT_POST, 1);\n      curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($postData, JSON_UNESCAPED_UNICODE));\n    } elseif ($method == 'DELETE') {\n      curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'DELETE');\n      if ($postData) {\n        curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($postData, JSON_UNESCAPED_UNICODE));\n      }\n    }\n\n    curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);\n\n    $result = curl_exec($curl);\n    $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);\n    $error = curl_error($curl);\n    curl_close($curl);\n\n    if ($result === false || $error) {\n      $errorMsg = $error ? $error : '连接失败';\n      \\Think\\Log::record(\"AI服务调用失败: \" . $errorMsg . \" (URL: \" . $url . \")\");\n      return false;\n    }\n\n    if ($httpCode != 200) {\n      \\Think\\Log::record(\"AI服务返回错误: HTTP \" . $httpCode . \", Response: \" . substr($result, 0, 500));\n      return false;\n    }\n\n    // 确保响应是 UTF-8 编码\n    if (!mb_check_encoding($result, 'UTF-8')) {\n      $result = mb_convert_encoding($result, 'UTF-8', 'auto');\n    }\n\n    $data = json_decode($result, true);\n    if ($data === null && json_last_error() !== JSON_ERROR_NONE) {\n      \\Think\\Log::record(\"AI服务返回数据解析失败: \" . json_last_error_msg() . \", Response: \" . substr($result, 0, 500));\n      return false;\n    }\n\n    return $data;\n  }\n\n  /**\n   * 异步调用 AI 服务（不等待响应）\n   * @param string $url 请求URL\n   * @param array $postData POST数据\n   * @param string $ai_service_token AI服务Token\n   * @param string $method 请求方法\n   */\n  public static function callAiServiceAsync($url, $postData = null, $ai_service_token, $method = 'POST')\n  {\n    try {\n      $ch = curl_init();\n      curl_setopt($ch, CURLOPT_URL, $url);\n      curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);\n      curl_setopt($ch, CURLOPT_TIMEOUT, 30); // 增加到30秒超时，给AI服务足够的处理时间\n      curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5); // 连接超时5秒\n      curl_setopt($ch, CURLOPT_NOSIGNAL, 1); // 避免信号量问题\n\n      $headers = array(\n        'Content-Type: application/json; charset=utf-8',\n        'Authorization: Bearer ' . $ai_service_token,\n        'Accept: application/json; charset=utf-8'\n      );\n\n      if ($method == 'POST' && $postData) {\n        curl_setopt($ch, CURLOPT_POST, 1);\n        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($postData, JSON_UNESCAPED_UNICODE));\n      } elseif ($method == 'DELETE') {\n        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');\n        if ($postData) {\n          curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($postData, JSON_UNESCAPED_UNICODE));\n        }\n      }\n\n      curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);\n\n      // 执行请求并获取响应\n      $result = curl_exec($ch);\n      $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);\n      $error = curl_error($ch);\n      curl_close($ch);\n\n      // 只记录错误日志\n      if ($error) {\n        \\Think\\Log::record(\"AI服务调用失败: {$error}\");\n      } elseif ($httpCode != 200) {\n        $responsePreview = $result ? substr($result, 0, 200) : '无响应';\n        \\Think\\Log::record(\"AI服务返回错误: HTTP {$httpCode}, {$responsePreview}\");\n      }\n    } catch (\\Exception $e) {\n      \\Think\\Log::record(\"AI服务调用异常: \" . $e->getMessage());\n    }\n  }\n\n  /**\n   * 更新单个页面的索引（增量索引）\n   * @param int $item_id 项目ID\n   * @param int $page_id 页面ID\n   * @param string $action 操作类型：'update' 或 'delete'\n   * @param string $ai_service_url AI服务地址\n   * @param string $ai_service_token AI服务Token\n   * @return bool 成功返回 true，失败返回 false\n   */\n  public static function updatePageIndex($item_id, $page_id, $action, $ai_service_url, $ai_service_token)\n  {\n    try {\n      // 设置超时时间（增量索引应该很快）\n      set_time_limit(60);\n      ini_set('memory_limit', '128M');\n\n      $url = rtrim($ai_service_url, '/') . '/api/index/upsert';\n\n      if ($action === 'delete') {\n        // 删除页面索引（DELETE 方法）\n        $postData = array(\n          'item_id' => $item_id,\n          'page_id' => $page_id\n        );\n        $result = self::callService($url, $postData, $ai_service_token, 'DELETE', 30);\n      } else {\n        // 更新页面索引，先获取页面内容\n        $page = D(\"Page\")->getById($page_id);\n        if (!$page) {\n          \\Think\\Log::record(\"获取页面失败: item_id={$item_id}, page_id={$page_id}\");\n          return false;\n        }\n\n        // 获取页面所属目录的名称，拼接到标题便于 AI 搜索（接口无 cat_name 参数）\n        $catName = '';\n        if (!empty($page['cat_id'])) {\n          $catalog = D(\"Catalog\")->getById($page['cat_id']);\n          if ($catalog) {\n            $catName = isset($catalog['cat_name']) ? $catalog['cat_name'] : '';\n          }\n        }\n        $pageTitle = isset($page['page_title']) ? $page['page_title'] : '';\n        if ($catName !== '') {\n          $pageTitle = $catName . ' / ' . $pageTitle;\n        }\n\n        // 处理页面内容\n        $content = isset($page['page_content']) ? $page['page_content'] : '';\n        $pageType = isset($page['page_type']) ? $page['page_type'] : 'regular';\n\n        // HTML 反转义\n        $content = html_entity_decode($content, ENT_QUOTES | ENT_HTML5, 'UTF-8');\n\n        // 尝试转换为 Markdown（如果是 API 文档）\n        $convert = new Convert();\n        $mdContent = $convert->runapiToMd($content);\n        if ($mdContent !== false) {\n          $content = $mdContent;\n        }\n\n        // 跳过空内容\n        if (empty($content) || trim($content) === '') {\n          // 如果内容为空，则删除该页面的索引\n          $postData = array(\n            'item_id' => $item_id,\n            'page_id' => $page_id\n          );\n          $result = self::callService($url, $postData, $ai_service_token, 'DELETE', 30);\n        } else {\n          $postData = array(\n            'item_id' => $item_id,\n            'page_id' => $page_id,\n            'page_title' => $pageTitle,\n            'page_content' => $content,\n            'page_type' => $pageType,\n            'update_time' => isset($page['update_time']) ? $page['update_time'] : time()\n          );\n          $result = self::callService($url, $postData, $ai_service_token, 'POST', 30);\n        }\n      }\n\n      if ($result === false) {\n        \\Think\\Log::record(\"更新页面索引失败: item_id={$item_id}, page_id={$page_id}, action={$action}\");\n        return false;\n      }\n\n      return true;\n    } catch (Exception $e) {\n      \\Think\\Log::record(\"更新页面索引异常: item_id={$item_id}, page_id={$page_id}, action={$action}, error=\" . $e->getMessage());\n      return false;\n    }\n  }\n\n  /**\n   * 调用 AI 服务（流式）\n   * @param string $url 请求URL\n   * @param array $postData POST数据\n   * @param string $ai_service_token AI服务Token\n   */\n  public static function callServiceStream($url, $postData, $ai_service_token)\n  {\n    $callback = function ($ch, $data) {\n      if (connection_aborted()) {\n        return -1;\n      }\n\n      // 确保数据是 UTF-8 编码\n      if (!mb_check_encoding($data, 'UTF-8')) {\n        $detected = mb_detect_encoding($data, array('UTF-8', 'GBK', 'GB2312', 'ISO-8859-1'), true);\n        $data = mb_convert_encoding($data, 'UTF-8', $detected ? $detected : 'auto');\n      }\n\n      echo $data;\n      flush();\n      return strlen($data);\n    };\n\n    $curl = curl_init();\n    curl_setopt($curl, CURLOPT_URL, $url);\n    curl_setopt($curl, CURLOPT_POST, 1);\n    curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($postData, JSON_UNESCAPED_UNICODE));\n    curl_setopt($curl, CURLOPT_WRITEFUNCTION, $callback);\n    curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 10);\n    curl_setopt($curl, CURLOPT_TIMEOUT, 300); // 5分钟超时\n    curl_setopt($curl, CURLOPT_ENCODING, '');\n    curl_setopt($curl, CURLOPT_HTTPHEADER, array(\n      'Content-Type: application/json; charset=utf-8',\n      'Authorization: Bearer ' . $ai_service_token,\n      'Accept: text/event-stream; charset=utf-8'\n    ));\n\n    curl_exec($curl);\n    $error = curl_error($curl);\n    $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);\n    curl_close($curl);\n\n    // 如果请求失败，输出错误信息\n    if ($error || $httpCode != 200) {\n      $errorMsg = $error ? $error : \"HTTP {$httpCode}\";\n      echo \"data: \" . json_encode(array('type' => 'error', 'message' => 'AI 服务调用失败: ' . $errorMsg), JSON_UNESCAPED_UNICODE) . \"\\n\\n\";\n      flush();\n    }\n  }\n\n  /**\n   * 递归收集所有页面数据\n   * @param array $menu 菜单数据\n   * @param array $pageData 页面数据数组（引用传递）\n   * @param object $convert Convert 对象\n   */\n  private static function _collectPages($menu, &$pageData, $convert)\n  {\n    // 处理根目录下的页面\n    if (isset($menu['pages']) && is_array($menu['pages'])) {\n      foreach ($menu['pages'] as $page) {\n        self::_processPage($page, $pageData, $convert);\n      }\n    }\n\n    // 递归处理子目录\n    if (isset($menu['catalogs']) && is_array($menu['catalogs'])) {\n      foreach ($menu['catalogs'] as $catalog) {\n        self::_collectPages($catalog, $pageData, $convert);\n      }\n    }\n  }\n\n  /**\n   * 处理单个页面\n   * @param array $page 页面数据\n   * @param array $pageData 页面数据数组（引用传递）\n   * @param object $convert Convert 对象\n   */\n  private static function _processPage($page, &$pageData, $convert)\n  {\n    $content = $page['page_content'];\n    $pageType = isset($page['page_type']) ? $page['page_type'] : 'regular';\n    $pageId = isset($page['page_id']) ? $page['page_id'] : 0;\n    $catId = isset($page['cat_id']) ? $page['cat_id'] : 0;\n\n    // HTML 反转义（因为存储的内容是 HTML 转义的）\n    $content = html_entity_decode($content, ENT_QUOTES | ENT_HTML5, 'UTF-8');\n\n    // 尝试使用 Convert 类转换为 Markdown（如果是 API 文档会自动转换，否则返回 false）\n    $md_content = $convert->runapiToMd($content);\n    if ($md_content !== false) {\n      $content = $md_content;\n    }\n\n    // 跳过空内容的页面\n    if (empty($content) || !is_string($content) || trim($content) === '') {\n      return;\n    }\n\n    // 获取页面所属目录的名称（主动查询），拼接到标题便于 AI 搜索（接口无 cat_name 参数）\n    $catName = '';\n    if ($catId > 0) {\n      $catalog = D(\"Catalog\")->getById($catId);\n      if ($catalog) {\n        $catName = isset($catalog['cat_name']) ? $catalog['cat_name'] : '';\n      }\n    }\n    $pageTitle = isset($page['page_title']) ? $page['page_title'] : '';\n    if ($catName !== '') {\n      $pageTitle = $catName . ' / ' . $pageTitle;\n    }\n\n    $pageData[] = array(\n      'page_id' => $pageId,\n      'page_title' => $pageTitle,\n      'page_content' => $content,\n      'page_type' => $pageType,\n      'update_time' => isset($page['update_time']) ? $page['update_time'] : time()\n    );\n  }\n}\n\n"
  },
  {
    "path": "server/Application/Api/Helper/Convert.class.php",
    "content": "<?php\n/*\n  存放一些转换的逻辑代码，比如从xx格式转成markdown格式\n*/\n\nnamespace Api\\Helper;\n\nuse PHPSQLParser\\PHPSQLParser;\n\n\nclass Convert\n{\n\n\n    /**\n     * 转换 SQL 为 Markdown 表格\n     */\n    public function convertSqlToMarkdownTable($sql)\n    {\n\n        $sql_array = $this->convertSqlToArray($sql);\n\n        $headers = [\n            ['字段', '类型', '允许空', '默认', '说明'],\n            ['---', '---', '---', '---', '---',],\n        ];\n        $markdowns = $sql_array['fields'];\n        array_unshift($markdowns, ...$headers);\n\n        $html = \"\\n- {$sql_array['table']} {$sql_array['comment']}\\n\\n\";\n        foreach ($markdowns as $line) {\n            $html .= '| ' . implode(' | ', $line) . ' | ' . \"\\n\";\n        }\n\n        return $html . \"\\n\";\n    }\n\n    // 把sql转换成解析数组\n    public function convertSqlToArray($sql)\n    {\n        $return = array(\n            'table' => '', // 表名\n            'comment' => '', // 注释\n            'fields' => array()\n        );\n\n        try {\n            $parser = new PHPSQLParser();\n            $parsed = $parser->parse($sql);\n\n            if (!isset($parsed['CREATE'])) {\n                return null;\n            }\n\n            // var_dump($parsed);exit();\n\n            if ($parsed['CREATE']['expr_type'] === 'table') {\n                $fields = $parsed['TABLE']['create-def']['sub_tree'];\n                $tableName = $parsed['TABLE']['base_expr']; // 表名\n\n                foreach ($fields as $field) {\n                    if ($field['sub_tree'][0]['expr_type'] == 'constraint') {\n                        continue;\n                    }\n\n                    // 如果当前行不是列定义，则没有 sub_tree，比如 PRIMARY KEY(id)\n                    if (!isset($field['sub_tree'][1]['sub_tree'])) {\n                        continue;\n                    }\n\n                    $type = $length = '';\n                    foreach ($field['sub_tree'][1]['sub_tree'] as $item) {\n                        if ($item['expr_type'] == 'data-type') {\n                            $type = $item['base_expr'] ?? '';\n                            $length = $item['length'] ?? '';\n                        }\n                    }\n\n                    $name = $field['sub_tree'][0]['base_expr'];\n                    $comment = trim($field['sub_tree'][1]['comment'] ?? '', \"'\");\n                    $nullable = $field['sub_tree'][1]['nullable'] ?? false;\n                    $default = $field['sub_tree'][1]['default'] ?? '';\n\n                    $type = empty($length) ? $type : \"{$type} ($length)\";\n                    $markdowns[] = [trim($name, '`'), $type, $nullable ? 'Y' : 'N', $default, $comment];\n                    $return['fields'][] = array(\n                        'name' => trim($name, '`'),\n                        'type' => $type,\n                        'nullable' => $nullable ? '是' : '否',\n                        'default' => trim($default, \"'\"),\n                        'comment' => $comment ? $comment : '-',\n                    );\n                }\n\n                $tableComment = '';\n                $options = $parsed['TABLE']['options'] ?? [];\n                if (!$options || empty($options)) {\n                    $options = [];\n                }\n\n                foreach ($options as $option) {\n                    $type = strtoupper($option['sub_tree'][0]['base_expr'] ?? '');\n                    if ($type === 'COMMENT') {\n                        // var_dump($option['sub_tree']);exit();\n                        $tableComment = trim($option['sub_tree'][2]['base_expr'] ?? '', \"'\");\n                        break;\n                    }\n                }\n                $return['table'] = trim($tableName, '`'); // 表名\n                $return['comment'] = $tableComment; // 表注释\n\n            }\n        } catch (\\Exception $ex) {\n            return \"{$ex->getMessage()} @{$ex->getFile()}:{$ex->getLine()}\";\n        }\n\n\n\n        return $return;\n    }\n\n    //把runapi的格式内容转换为markdown格式。如果不是runapi格式，则会返回false\n    //参数content为json字符串或者数组\n    public function runapiToMd($content)\n    {\n        if (!is_array($content)) {\n            $content_json = htmlspecialchars_decode($content);\n            $content = json_decode($content_json, true);\n        }\n        if (!$content || !$content['info'] || !$content['info']['url']) {\n            return false;\n        }\n\n        // 判断类型（兼容旧数据）\n        $type = isset($content['info']['type']) ? $content['info']['type'] : 'api';\n\n        if ($type === 'websocket') {\n            return $this->runapiWebSocketToMd($content);\n        } elseif ($type === 'sse') {\n            return $this->runapiSSEToMd($content);\n        } else {\n            return $this->runapiHttpApiToMd($content);\n        }\n    }\n\n    // HTTP API 转换函数（原 runapiToMd 逻辑）\n    private function runapiHttpApiToMd($content)\n    {\n        // 兼容query\n        if ($content['info']['method'] == 'get') {\n            if (!$content['request']['query']) {\n                $content['request']['query'] = $content['request']['params'][$content['request']['params']['mode']];\n            }\n            $content['request']['params'][$content['request']['params']['mode']] = array();\n        }\n\n        $new_content = \"\\n##### 简要描述\\n\\n- \" . ($content['info']['description'] ? $content['info']['description'] : '无');\n\n        if ($content['info']['apiStatus']) {\n            $statusText = '';\n            switch ($content['info']['apiStatus']) {\n                case '1':\n                    $statusText = '开发中';\n                    break;\n                case '2':\n                    $statusText = '测试中';\n                    break;\n                case '3':\n                    $statusText = '已完成';\n                    break;\n                case '4':\n                    $statusText = '需修改';\n                    break;\n                case '5':\n                    $statusText = '已废弃';\n                    break;\n                default:\n                    break;\n            }\n\n            $new_content .= \"\\n\\n##### 接口状态\\n\\n - \" . $statusText;\n        }\n\n        // 如果有query参数组，则把url中的参数去掉\n        $query = $content['request']['query'];\n        if ($query && is_array($query) && $query[0] && $query[0]['name']) {\n            $words = explode('?', $content['info']['url']);\n            $content['info']['url']  = $words[0];\n        }\n\n        $new_content .= \"\\n\\n##### 请求URL\\n\\n - `{$content['info']['url']}` \\n\\n##### 请求方式\\n\\n- {$content['info']['method']}\\n\";\n        $pathVariable = $content['request']['pathVariable'];\n        if ($pathVariable && is_array($pathVariable) && $pathVariable[0] && $pathVariable[0]['name']) {\n            $new_content .= \" \\n##### 路径变量\\n\\n|变量名|必选|类型|说明|\\n|:-----  |:-----|-----|\\n\";\n            foreach ($pathVariable as $key => $value) {\n                // 如果名字为空，或者存在禁用的key且禁用状态生效中，则跳过本条参数\n                if (!$value['name'] || (isset($value['disable']) && $value['disable'] >= 1)) {\n                    continue;\n                }\n                $value['require'] = $value['require'] > 0 ? \"是\" : \"否\";\n                $value['remark'] = $value['remark'] ? $value['remark'] : '无';\n                $new_content .= \"|{$value['name']}|  {$value['require']} |  {$value['type']} |  {$value['remark']} | \\n\";\n            }\n        }\n\n        if ($content['request']['headers'] && $content['request']['headers'][0] && $content['request']['headers'][0]['name']) {\n            $new_content .= \" \\n##### Header \\n\\n|字段名|示例值|必选|类型|说明|\\n|:-----  |:-----|-----|\\n\";\n            foreach ($content['request']['headers'] as $key => $value) {\n                // 如果名字为空，或者存在禁用的key且禁用状态生效中，则跳过本条参数\n                if (!$value['name'] || (isset($value['disable']) && $value['disable'] >= 1)) {\n                    continue;\n                }\n                $value['require'] = $value['require'] > 0 ? \"是\" : \"否\";\n                $value['remark'] = $value['remark'] ? $value['remark'] : '无';\n                $value['value'] = $value['value'] ? $value['value'] : '';\n                $new_content .= \"|{$value['name']}|  {$value['value']} |  {$value['require']} |  {$value['type']} |  {$value['remark']} | \\n\";\n            }\n        }\n\n        $query = $content['request']['query'];\n        if ($query && is_array($query) && $query[0] && $query[0]['name']) {\n            $new_content .= \" \\n##### 请求Query参数\\n\\n|参数名|示例值|必选|类型|说明|\\n|:-----  |:-----|-----|\\n\";\n            foreach ($query as $key => $value) {\n                // 如果名字为空，或者存在禁用的key且禁用状态生效中，则跳过本条参数\n                if (!$value['name'] || (isset($value['disable']) && $value['disable'] >= 1)) {\n                    continue;\n                }\n                $value['require'] = $value['require'] > 0 ? \"是\" : \"否\";\n                $value['remark'] = $value['remark'] ? $value['remark'] : '无';\n                $value['value'] = $value['value'] ? $value['value'] : '';\n                $new_content .= \"|{$value['name']}|  {$value['value']}|  {$value['require']} |  {$value['type']} |  {$value['remark']} | \\n\";\n            }\n        }\n\n        $params = $content['request']['params'][$content['request']['params']['mode']];\n        if ($params && is_array($params) && $params[0] && $params[0]['name']) {\n            $new_content .= \" \\n##### 请求Body参数\\n\\n|参数名|示例值|必选|类型|说明|\\n|:-----  |:-----|-----|\\n\";\n            foreach ($params as $key => $value) {\n                // 如果名字为空，或者存在禁用的key且禁用状态生效中，则跳过本条参数\n                if (!$value['name'] || (isset($value['disable']) && $value['disable'] >= 1)) {\n                    continue;\n                }\n                $value['require'] = $value['require'] > 0 ? \"是\" : \"否\";\n                $value['remark'] = $value['remark'] ? $value['remark'] : '无';\n                $value['value'] = $value['value'] ? $value['value'] : '';\n                $new_content .= \"|{$value['name']}|  {$value['value']} |  {$value['require']} |  {$value['type']} |  {$value['remark']} | \\n\";\n            }\n        }\n        //如果参数类型为json\n        if ($content['request']['params']['mode'] == 'json' && $params) {\n            $params = $this->_indent_json($params);\n            $new_content .= \" \\n##### 请求参数示例  \\n```\\n{$params}\\n\\n``` \\n\";\n        }\n        // json字段说明\n        $jsonDesc = $content['request']['params']['jsonDesc'];\n        if ($content['request']['params']['mode'] == 'json' && $jsonDesc && $jsonDesc[0] && $jsonDesc[0]['name']) {\n            $new_content .= \" \\n##### json字段说明\\n\\n|字段名|必选|类型|说明|\\n|:-----  |:-----|-----|\\n\";\n            foreach ($jsonDesc as $key => $value) {\n                // 如果名字为空，或者存在禁用的key且禁用状态生效中，则跳过本条参数\n                if (!$value['name'] || (isset($value['disable']) && $value['disable'] >= 1)) {\n                    continue;\n                }\n                $value['require'] = $value['require'] > 0 ? \"是\" : \"否\";\n                $value['remark'] = $value['remark'] ? $value['remark'] : '无';\n                $new_content .= \"|{$value['name']}|  {$value['require']} |  {$value['type']} |  {$value['remark']} | \\n\";\n            }\n        }\n\n        //成功返回示例\n        if ($content['response']['responseExample']) {\n            $responseExample = $this->_indent_json($content['response']['responseExample']);\n            $responseExample = $responseExample ? $responseExample : $content['response']['responseExample'];\n            $new_content .= \" \\n##### 成功返回示例  \\n```\\n{$responseExample}\\n\\n``` \\n\";\n        }\n\n        //返回示例说明\n        if ($content['response']['responseParamsDesc'] && $content['response']['responseParamsDesc'][0] && $content['response']['responseParamsDesc'][0]['name']) {\n            $new_content .= \" \\n##### 成功返回示例的参数说明 \\n\\n|参数名|类型|说明|\\n|:-----  |:-----|-----|\\n\";\n            foreach ($content['response']['responseParamsDesc'] as $key => $value) {\n                $value['remark'] = $value['remark'] ? $value['remark'] : '无';\n                $new_content .= \"|{$value['name']}| {$value['type']} |  {$value['remark']} | \\n\";\n            }\n        }\n\n        //失败返回示例\n        if ($content['response']['responseFailExample']) {\n            $responseFailExample = $this->_indent_json($content['response']['responseFailExample']);\n            $responseFailExample = $responseFailExample ? $responseFailExample : $content['response']['responseFailExample'];\n            $new_content .= \" \\n##### 失败返回示例  \\n```\\n{$responseFailExample}\\n\\n``` \\n\";\n        }\n\n        //返回示例说明\n        if ($content['response']['responseFailParamsDesc'] && $content['response']['responseFailParamsDesc'][0] && $content['response']['responseFailParamsDesc'][0]['name']) {\n            $new_content .= \" \\n##### 失败返回示例的参数说明 \\n|参数名|类型|说明|\\n|:-----  |:-----|-----|\\n\";\n            foreach ($content['response']['responseFailParamsDesc'] as $key => $value) {\n                $value['remark'] = $value['remark'] ? $value['remark'] : '无';\n                $new_content .= \"|{$value['name']}| {$value['type']} |  {$value['remark']} | \\n\";\n            }\n        }\n\n        if ($content['info']['remark']) {\n            $new_content .= \" \\n##### 备注 \\n {$content['info']['remark']}\\n\";\n        }\n\n\n        return $new_content;\n    }\n\n    // WebSocket 转换函数\n    private function runapiWebSocketToMd($content)\n    {\n        $new_content = \"\\n##### 简要描述\\n\\n- \" . ($content['info']['description'] ? $content['info']['description'] : '无');\n\n        // 接口状态\n        if (isset($content['info']['apiStatus']) && $content['info']['apiStatus']) {\n            $statusText = '';\n            switch ($content['info']['apiStatus']) {\n                case '1':\n                    $statusText = '开发中';\n                    break;\n                case '2':\n                    $statusText = '测试中';\n                    break;\n                case '3':\n                    $statusText = '已完成';\n                    break;\n                case '4':\n                    $statusText = '需修改';\n                    break;\n                case '5':\n                    $statusText = '已废弃';\n                    break;\n                default:\n                    break;\n            }\n            if ($statusText) {\n                $new_content .= \"\\n\\n##### 接口状态\\n\\n - \" . $statusText;\n            }\n        }\n\n        $new_content .= \"\\n\\n##### 协议类型\\n\\n- WebSocket\\n\";\n        $new_content .= \"\\n\\n##### 连接URL\\n\\n - `{$content['info']['url']}`\\n\";\n\n        // 子协议\n        if (\n            isset($content['protocolConfig']['websocket']['subProtocols']) &&\n            is_array($content['protocolConfig']['websocket']['subProtocols']) &&\n            !empty($content['protocolConfig']['websocket']['subProtocols'])\n        ) {\n            $protocols = implode(', ', $content['protocolConfig']['websocket']['subProtocols']);\n            $new_content .= \"\\n\\n##### 子协议\\n\\n- {$protocols}\\n\";\n        }\n\n        // Headers（握手阶段）- 使用 request.headers（复用）\n        if (\n            isset($content['request']['headers']) &&\n            is_array($content['request']['headers']) &&\n            !empty($content['request']['headers']) &&\n            isset($content['request']['headers'][0]['name'])\n        ) {\n            $new_content .= \" \\n##### 连接Headers \\n\\n|字段名|示例值|必选|类型|说明|\\n|:-----  |:-----|:-----|:-----|:-----|\\n\";\n            foreach ($content['request']['headers'] as $key => $value) {\n                if (!isset($value['name']) || !$value['name'] || (isset($value['disable']) && $value['disable'] >= 1)) {\n                    continue;\n                }\n                $require = isset($value['require']) && $value['require'] > 0 ? \"是\" : \"否\";\n                $remark = isset($value['remark']) && $value['remark'] ? $value['remark'] : '无';\n                $val = isset($value['value']) && $value['value'] ? $value['value'] : '';\n                $type = isset($value['type']) && $value['type'] ? $value['type'] : 'string';\n                $new_content .= \"|{$value['name']}|  {$val} |  {$require} |  {$type} |  {$remark} | \\n\";\n            }\n        }\n\n        // Query 参数 - 使用 request.query（复用）\n        if (\n            isset($content['request']['query']) &&\n            is_array($content['request']['query']) &&\n            !empty($content['request']['query']) &&\n            isset($content['request']['query'][0]['name'])\n        ) {\n            $new_content .= \" \\n##### 连接Query参数\\n\\n|参数名|示例值|必选|类型|说明|\\n|:-----  |:-----|:-----|:-----|:-----|\\n\";\n            foreach ($content['request']['query'] as $key => $value) {\n                if (!isset($value['name']) || !$value['name'] || (isset($value['disable']) && $value['disable'] >= 1)) {\n                    continue;\n                }\n                $require = isset($value['require']) && $value['require'] > 0 ? \"是\" : \"否\";\n                $remark = isset($value['remark']) && $value['remark'] ? $value['remark'] : '无';\n                $val = isset($value['value']) && $value['value'] ? $value['value'] : '';\n                $type = isset($value['type']) && $value['type'] ? $value['type'] : 'string';\n                $new_content .= \"|{$value['name']}|  {$val}|  {$require} |  {$type} |  {$remark} | \\n\";\n            }\n        }\n\n        // 认证配置\n        if (\n            isset($content['request']['auth']) &&\n            is_array($content['request']['auth']) &&\n            isset($content['request']['auth']['type']) &&\n            $content['request']['auth']['type'] &&\n            (!isset($content['request']['auth']['disabled']) || $content['request']['auth']['disabled'] !== '1')\n        ) {\n            $authType = $content['request']['auth']['type'];\n            $authTypeText = '';\n            switch ($authType) {\n                case 'bearer':\n                    $authTypeText = 'Bearer Token';\n                    break;\n                case 'basic':\n                    $authTypeText = 'Basic Auth';\n                    break;\n                default:\n                    $authTypeText = $authType;\n                    break;\n            }\n            $new_content .= \" \\n##### 认证方式\\n\\n- {$authTypeText}\\n\";\n        }\n\n        // 重连配置\n        if (\n            isset($content['protocolConfig']['websocket']['autoReconnect']) &&\n            $content['protocolConfig']['websocket']['autoReconnect']\n        ) {\n            $interval = isset($content['protocolConfig']['websocket']['reconnectInterval']) ?\n                $content['protocolConfig']['websocket']['reconnectInterval'] : 3000;\n            $maxTimes = isset($content['protocolConfig']['websocket']['reconnectMaxTimes']) ?\n                $content['protocolConfig']['websocket']['reconnectMaxTimes'] : 5;\n            $maxTimesText = $maxTimes > 0 ? \"{$maxTimes}次\" : \"无限\";\n            $new_content .= \" \\n##### 重连配置\\n\\n- 自动重连：是\\n- 重连间隔：{$interval}毫秒\\n- 最大重连次数：{$maxTimesText}\\n\";\n        }\n\n        // 心跳配置\n        if (\n            isset($content['protocolConfig']['websocket']['heartbeat']['enabled']) &&\n            $content['protocolConfig']['websocket']['heartbeat']['enabled']\n        ) {\n            $interval = isset($content['protocolConfig']['websocket']['heartbeat']['interval']) ?\n                $content['protocolConfig']['websocket']['heartbeat']['interval'] : 30000;\n            $pingMsg = isset($content['protocolConfig']['websocket']['heartbeat']['pingMessage']) ?\n                $content['protocolConfig']['websocket']['heartbeat']['pingMessage'] : 'ping';\n            $new_content .= \" \\n##### 心跳配置\\n\\n- 心跳间隔：{$interval}毫秒\\n- Ping 消息：`{$pingMsg}`\\n\";\n        }\n\n        // 消息模板\n        if (\n            isset($content['messaging']['templates']) &&\n            is_array($content['messaging']['templates']) &&\n            !empty($content['messaging']['templates'])\n        ) {\n            $new_content .= \" \\n##### 消息模板\\n\\n\";\n            foreach ($content['messaging']['templates'] as $msg) {\n                if (isset($msg['enabled']) && !$msg['enabled']) {\n                    continue;\n                }\n                $msgType = isset($msg['type']) ? $msg['type'] : 'text';\n                $msgName = isset($msg['name']) ? $msg['name'] : '未命名';\n                $msgContent = isset($msg['payload']) ? $msg['payload'] : '';\n\n                // 格式化 JSON\n                if ($msgType === 'json') {\n                    $msgContent = $this->_indent_json($msgContent);\n                }\n\n                $new_content .= \"**{$msgName}** ({$msgType})\\n```\\n{$msgContent}\\n```\\n\\n\";\n            }\n        }\n\n        // 消息示例（支持多示例）\n        if (\n            isset($content['response']['examples']) &&\n            is_array($content['response']['examples']) &&\n            !empty($content['response']['examples'])\n        ) {\n            $new_content .= \" \\n##### 消息示例\\n\\n\";\n\n            foreach ($content['response']['examples'] as $example) {\n                if (!isset($example['data'])) {\n                    continue;\n                }\n\n                $exampleName = isset($example['name']) ? $example['name'] : '示例';\n                $exampleData = $this->_indent_json($example['data']);\n                $exampleData = $exampleData ? $exampleData : $example['data'];\n\n                $new_content .= \"**{$exampleName}**\\n```\\n{$exampleData}\\n```\\n\\n\";\n\n                // 字段说明\n                if (\n                    isset($example['param']) &&\n                    is_array($example['param']) &&\n                    !empty($example['param']) &&\n                    isset($example['param'][0]['name'])\n                ) {\n                    $new_content .= \"|字段名|类型|说明|\\n|:-----  |:-----|:-----|\\n\";\n                    foreach ($example['param'] as $param) {\n                        if (!isset($param['name']) || !$param['name']) {\n                            continue;\n                        }\n                        $paramType = isset($param['type']) ? $param['type'] : 'string';\n                        $paramRemark = isset($param['remark']) && $param['remark'] ? $param['remark'] : '无';\n                        $new_content .= \"|{$param['name']}| {$paramType} |  {$paramRemark} | \\n\";\n                    }\n                    $new_content .= \"\\n\";\n                }\n            }\n        }\n\n        // 备注\n        if (isset($content['response']['remark']) && $content['response']['remark']) {\n            $new_content .= \" \\n##### 备注 \\n {$content['response']['remark']}\\n\";\n        } elseif (isset($content['info']['remark']) && $content['info']['remark']) {\n            $new_content .= \" \\n##### 备注 \\n {$content['info']['remark']}\\n\";\n        }\n\n        return $new_content;\n    }\n\n    // SSE 转换函数\n    private function runapiSSEToMd($content)\n    {\n        $new_content = \"\\n##### 简要描述\\n\\n- \" . ($content['info']['description'] ? $content['info']['description'] : '无');\n\n        // 接口状态\n        if (isset($content['info']['apiStatus']) && $content['info']['apiStatus']) {\n            $statusText = '';\n            switch ($content['info']['apiStatus']) {\n                case '1':\n                    $statusText = '开发中';\n                    break;\n                case '2':\n                    $statusText = '测试中';\n                    break;\n                case '3':\n                    $statusText = '已完成';\n                    break;\n                case '4':\n                    $statusText = '需修改';\n                    break;\n                case '5':\n                    $statusText = '已废弃';\n                    break;\n                default:\n                    break;\n            }\n            if ($statusText) {\n                $new_content .= \"\\n\\n##### 接口状态\\n\\n - \" . $statusText;\n            }\n        }\n\n        $new_content .= \"\\n\\n##### 协议类型\\n\\n- SSE (Server-Sent Events)\\n\";\n\n        // HTTP 方法\n        $method = isset($content['info']['method']) ? strtoupper($content['info']['method']) : 'POST';\n        $new_content .= \"\\n\\n##### 请求方法\\n\\n- {$method}\\n\";\n\n        $new_content .= \"\\n\\n##### 请求URL\\n\\n - `{$content['info']['url']}`\\n\";\n\n        // Headers\n        if (\n            isset($content['request']['headers']) &&\n            is_array($content['request']['headers']) &&\n            !empty($content['request']['headers']) &&\n            isset($content['request']['headers'][0]['name'])\n        ) {\n            $new_content .= \" \\n##### 请求Headers \\n\\n|字段名|示例值|必选|类型|说明|\\n|:-----  |:-----|:-----|:-----|:-----|\\n\";\n            foreach ($content['request']['headers'] as $key => $value) {\n                if (!isset($value['name']) || !$value['name'] || (isset($value['disable']) && $value['disable'] >= 1)) {\n                    continue;\n                }\n                $require = isset($value['require']) && $value['require'] > 0 ? \"是\" : \"否\";\n                $remark = isset($value['remark']) && $value['remark'] ? $value['remark'] : '无';\n                $val = isset($value['value']) && $value['value'] ? $value['value'] : '';\n                $type = isset($value['type']) && $value['type'] ? $value['type'] : 'string';\n                $new_content .= \"|{$value['name']}|  {$val} |  {$require} |  {$type} |  {$remark} | \\n\";\n            }\n        }\n\n        // Query 参数\n        if (\n            isset($content['request']['query']) &&\n            is_array($content['request']['query']) &&\n            !empty($content['request']['query']) &&\n            isset($content['request']['query'][0]['name'])\n        ) {\n            $new_content .= \" \\n##### 请求Query参数\\n\\n|参数名|示例值|必选|类型|说明|\\n|:-----  |:-----|:-----|:-----|:-----|\\n\";\n            foreach ($content['request']['query'] as $key => $value) {\n                if (!isset($value['name']) || !$value['name'] || (isset($value['disable']) && $value['disable'] >= 1)) {\n                    continue;\n                }\n                $require = isset($value['require']) && $value['require'] > 0 ? \"是\" : \"否\";\n                $remark = isset($value['remark']) && $value['remark'] ? $value['remark'] : '无';\n                $val = isset($value['value']) && $value['value'] ? $value['value'] : '';\n                $type = isset($value['type']) && $value['type'] ? $value['type'] : 'string';\n                $new_content .= \"|{$value['name']}|  {$val}|  {$require} |  {$type} |  {$remark} | \\n\";\n            }\n        }\n\n        // Body 参数（POST 等方法）\n        if (\n            isset($content['request']['params']) &&\n            isset($content['request']['params']['mode']) &&\n            $content['request']['params']['mode'] !== 'none'\n        ) {\n            $mode = $content['request']['params']['mode'];\n            $modeText = '';\n            switch ($mode) {\n                case 'json':\n                    $modeText = 'JSON';\n                    break;\n                case 'urlencoded':\n                    $modeText = 'URL Encoded';\n                    break;\n                case 'formdata':\n                    $modeText = 'Form Data';\n                    break;\n                default:\n                    $modeText = $mode;\n                    break;\n            }\n\n            if ($mode === 'json' && isset($content['request']['params']['json']) && $content['request']['params']['json']) {\n                $jsonBody = $this->_indent_json($content['request']['params']['json']);\n                $jsonBody = $jsonBody ? $jsonBody : $content['request']['params']['json'];\n                $new_content .= \" \\n##### 请求Body ({$modeText})\\n\\n```\\n{$jsonBody}\\n```\\n\";\n            } elseif ($mode === 'urlencoded' && isset($content['request']['params']['urlencoded']) && is_array($content['request']['params']['urlencoded']) && !empty($content['request']['params']['urlencoded'])) {\n                $new_content .= \" \\n##### 请求Body ({$modeText})\\n\\n|参数名|示例值|必选|类型|说明|\\n|:-----  |:-----|:-----|:-----|:-----|\\n\";\n                foreach ($content['request']['params']['urlencoded'] as $key => $value) {\n                    if (!isset($value['name']) || !$value['name'] || (isset($value['disable']) && $value['disable'] >= 1)) {\n                        continue;\n                    }\n                    $require = isset($value['require']) && $value['require'] > 0 ? \"是\" : \"否\";\n                    $remark = isset($value['remark']) && $value['remark'] ? $value['remark'] : '无';\n                    $val = isset($value['value']) && $value['value'] ? $value['value'] : '';\n                    $type = isset($value['type']) && $value['type'] ? $value['type'] : 'string';\n                    $new_content .= \"|{$value['name']}|  {$val}|  {$require} |  {$type} |  {$remark} | \\n\";\n                }\n            } elseif ($mode === 'formdata' && isset($content['request']['params']['formdata']) && is_array($content['request']['params']['formdata']) && !empty($content['request']['params']['formdata'])) {\n                $new_content .= \" \\n##### 请求Body ({$modeText})\\n\\n|参数名|示例值|必选|类型|说明|\\n|:-----  |:-----|:-----|:-----|:-----|\\n\";\n                foreach ($content['request']['params']['formdata'] as $key => $value) {\n                    if (!isset($value['name']) || !$value['name'] || (isset($value['disable']) && $value['disable'] >= 1)) {\n                        continue;\n                    }\n                    $require = isset($value['require']) && $value['require'] > 0 ? \"是\" : \"否\";\n                    $remark = isset($value['remark']) && $value['remark'] ? $value['remark'] : '无';\n                    $val = isset($value['value']) && $value['value'] ? $value['value'] : '';\n                    $type = isset($value['type']) && $value['type'] ? $value['type'] : 'string';\n                    $new_content .= \"|{$value['name']}|  {$val}|  {$require} |  {$type} |  {$remark} | \\n\";\n                }\n            }\n        }\n\n        // 认证配置\n        if (\n            isset($content['request']['auth']) &&\n            is_array($content['request']['auth']) &&\n            isset($content['request']['auth']['type']) &&\n            $content['request']['auth']['type'] &&\n            (!isset($content['request']['auth']['disabled']) || $content['request']['auth']['disabled'] !== '1')\n        ) {\n            $authType = $content['request']['auth']['type'];\n            $authTypeText = '';\n            switch ($authType) {\n                case 'bearer':\n                    $authTypeText = 'Bearer Token';\n                    break;\n                case 'basic':\n                    $authTypeText = 'Basic Auth';\n                    break;\n                default:\n                    $authTypeText = $authType;\n                    break;\n            }\n            $new_content .= \" \\n##### 认证方式\\n\\n- {$authTypeText}\\n\";\n        }\n\n        // 消息示例（支持多示例）\n        if (\n            isset($content['response']['examples']) &&\n            is_array($content['response']['examples']) &&\n            !empty($content['response']['examples'])\n        ) {\n            $new_content .= \" \\n##### 返回示例\\n\\n\";\n\n            foreach ($content['response']['examples'] as $example) {\n                if (!isset($example['data'])) {\n                    continue;\n                }\n\n                $exampleName = isset($example['name']) ? $example['name'] : '示例';\n                $exampleData = $this->_indent_json($example['data']);\n                $exampleData = $exampleData ? $exampleData : $example['data'];\n\n                $new_content .= \"**{$exampleName}**\\n```\\n{$exampleData}\\n```\\n\\n\";\n\n                // 字段说明\n                if (\n                    isset($example['param']) &&\n                    is_array($example['param']) &&\n                    !empty($example['param']) &&\n                    isset($example['param'][0]['name'])\n                ) {\n                    $new_content .= \"|字段名|类型|说明|\\n|:-----  |:-----|:-----|\\n\";\n                    foreach ($example['param'] as $param) {\n                        if (!isset($param['name']) || !$param['name']) {\n                            continue;\n                        }\n                        $paramType = isset($param['type']) ? $param['type'] : 'string';\n                        $paramRemark = isset($param['remark']) && $param['remark'] ? $param['remark'] : '无';\n                        $new_content .= \"|{$param['name']}| {$paramType} |  {$paramRemark} | \\n\";\n                    }\n                    $new_content .= \"\\n\";\n                }\n            }\n        }\n\n        // 备注\n        if (isset($content['response']['remark']) && $content['response']['remark']) {\n            $new_content .= \" \\n##### 备注 \\n {$content['response']['remark']}\\n\";\n        } elseif (isset($content['info']['remark']) && $content['info']['remark']) {\n            $new_content .= \" \\n##### 备注 \\n {$content['info']['remark']}\\n\";\n        }\n\n        return $new_content;\n    }\n\n    // json美化\n    private function _indent_json($json)\n    {\n        $json_new = json_encode(json_decode($json), JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);\n        if ($json_new && $json_new != 'null') {\n            return $json_new;\n        }\n        return $json;\n    }\n}\n"
  },
  {
    "path": "server/Application/Api/Lang/en-us.php",
    "content": "<?php\nreturn array(\n\n    //Attorn\n    'attorn_item' => 'Attorn item',\n    'username' => 'Username',\n    'receiver_name' => \"Receiver's username\",\n    'verify_identity' => 'Verify identity',\n    'your_password' => 'Your password',\n    'attorn' => 'Attorn',\n    'close' => 'close',\n\n    //Catalog\n    'new_or_edit_catalog' => 'New/Edit catalog',\n    'catalog_name' => 'Catalog name',\n    's_number' => 'Order',\n    's_number_explain' => 'Optional: order number',\n    'last_catalog' => 'Parent catalog',\n    'save' => 'Sava',\n    'delete_catalog' => 'Delete catalog',\n    'catalog_list' => 'Catalog list',\n    'click_to_edit' => 'Click to edit',\n\n\n    //index\n    'help' => 'Help',\n    'demo' => 'Demo',\n    'index_login_or_register' => 'Login / Register',\n    'my_item' => 'My items',\n    'section_title1' => 'ShowDoc',\n    'section_description1' => ' A tool greatly applicable for an IT team',\n    'section_title2' => 'API Document',\n    'section_description2' => 'ShowDoc can compile exquisite API documents <br>in a very fast and convenient way',\n    'section_title3' => 'Data Dictionary',\n    'section_description3' => 'A good Data Dictionary can easily exhibit database structure to other people<br>ShowDoc can compile exquisite Data Dictionary',\n    'section_title4' => 'Explanation Document',\n    'section_description4' => 'You can absolutely use ShowDoc to compile the explanation documents for some tools',\n    'section_title5' => 'Team Work',\n    'section_description5' => 'Your team will work with ShowDoc together very well ',\n    'section_title6' => 'Open Source',\n    'section_description6' => 'ShowDoc is a free, open source tool that <br>you can deploy it to your own server',\n    'section_title7' => 'Hosted online',\n    'section_description7' => 'Www.showdoc.cc provide security and stability of the document hosting service',\n    'section_title8' => 'Try it now',\n    'section_description8' => 'Over 6000+ IT team is using ShowDoc',\n\n\n    //Common message\n    'redirect_message' => 'If your browser does not automatically jump, please click on this link.',\n    'click_to_goback' => 'Click to goback',\n    'home' => 'Home',\n\n\n    //item/add\n    'item_name' => \"Item's name\",\n    'item_description' => \"Item's description\",\n    'item_domain' => '(Optional)domain hack',\n    'item_domain_illegal' => 'Domain hack must be a combination of letters and numbers',\n    'domain_already_exists' => 'Domain already exists',\n    'visit_password_placeholder' => 'Access password(Optional: private project required)',\n    'submit' => 'Submit',\n    'goback' => 'Goback',\n    //item/delete\n    'delete_item' => 'Delete item',\n    'verify_your_identity' => 'Verify your identity',\n    'creator_password' => \"creator's password\",\n    'delete' => 'Delete',\n    'close' => 'Close',\n    //item/index\n    'personal_setting' => 'Personal setting',\n    'share_home' => 'Share home',\n    'web_home' => 'Website home',\n    'logout' => 'Logout',\n    'add_an_item' => 'Add an item',\n    'new_item' => 'New item',\n    'share_my_home' => 'Share my home',\n    'home_address' => 'Home address',\n    'home_address_description' => 'The others will be able to see all of your public items When he visits your home page.You can copy the address to your friends.',\n    //item/pwd\n    'input_visit_password' => 'Please enter the access password',\n    'password' => 'Passwod',\n    'verification_code' => 'Verification code',\n    'submit' => 'Submit',\n    'login_or_register' => 'Login/Register',\n    //item/show\n    'item' => 'Item',\n    'share' => 'Share',\n    'export' => 'Export',\n    'update_info' => 'Modify',\n    'manage_members' => 'Members',\n    'attorn' => 'Attorn',\n    'delete' => 'Delete',\n    'more_item' => 'More items',\n    'login_or_register' => 'Login/Register',\n    'about_showdoc' => 'About ShowDoc',\n    'my_item' => 'My items',\n    'new_page' => 'New page',\n    'new_catalog' => 'New catalog',\n    'share_address_to_your_friends' => 'Share address to your friends',\n    'share' => 'Share',\n    'copy_interface_to_new' => 'Copy page  to new ',\n    'copy' => 'Copy',\n    'edit_interface' => 'Edit page',\n    'edit' => 'Edit',\n    'delete_interface' => 'Delete page',\n    'comfirm_delete' => 'Are you sure that you want to delete it?',\n    'delete' => 'Delete',\n    'share' => 'Share',\n    'item_address' => 'Item address',\n    'copy_address_to_your_friends' => 'You can copy the address to your friend.',\n    'share_page' => 'Share page',\n    'page_address' => 'Page address',\n    'copy_address_to_your_friends' => 'You can copy the address to your friend.',\n    //item/showbyuid\n    'more' => 'More',\n    'my_item' => 'My items',\n    'login_or_register' => 'Login/Register',\n    'about_showdoc' => 'About ShowDoc',\n    'all_pubilc_item' => \"'s all public items\",\n\n    //member\n    'new_member' => 'New member',\n    'username' => 'Username',\n    'save' => 'Save',\n    'member_list' => 'member list',\n    'click_to_delete' => 'Click to delete',\n    'close' => 'Close',\n    \"member_group_id\" => \"Read-only(can read item ,but not edit or delete )\",\n    //page\n    'input_page_title' => 'Please enter a page title',\n    'level_2_directory' => 'Second-level catalog',\n    'level_3_directory' => 'Third-level catalog',\n    's_number_explain' => 'Optional: order number',\n    'history_version' => 'History version',\n    'save' => 'Save',\n    'cancel' => 'Cancel',\n    'inser_apidoc_template' => 'Insert apidoc template',\n    'inser_database_doc_template' => 'Insert db-doc template',\n    'json_tools' => 'Json tools',\n    'json_to_table' => 'Json to table',\n    'beautify_json' => 'Beautify Json',\n    'beautify_json_description' => 'Make your json more beautiful ',\n    'http_test_api' => 'Api test online',\n    'json_to_table_description' => 'Please paste a section of JSON, the program will automatically parse and generate JSON parameters table. This feature is suitable for the rapid preparation of API documents returned to the parameter table',\n    'confirm' => 'Confirm',\n    'cancel' => 'Cancel',\n    'history_version' => 'History version',\n    'update_time' => 'Modification time',\n    'update_by_who' => 'Modified by who',\n    'operation' => 'Operation',\n    'recover_to_this_version' => 'Restore to this version',\n    'close' => 'Close',\n    'finish' => 'Finish',\n    'api_test_title' => 'Test for GET and POST',\n    'api_address_description' => 'Api address(e.g:ttp://www.abc.com/api/login)',\n    'api_address' => 'Api address',\n    'params_description' => 'Params(e.g:user_id=121&age=22&date=2016-06-02)',\n    'params' => 'Params',\n    'clear' => 'Clear',\n    'result' => 'Result',\n    'save_to_templ' => 'Save as template',\n    'more_templ' => 'More template',\n    'saved_templ_list' => 'Template list you saved',\n    'page_comments' => 'Page comments',\n    'add_page_comments' => 'Add comments before save',\n    'cur_page_content' => 'The latest version ',\n    'history_page_content' => 'History version',\n    'overview' => 'Overview',\n    //user\n    'login' => 'Login',\n    'username' => 'Username',\n    'password' => 'Passwod',\n    'verification_code' => 'Verification code',\n    'no_account' => 'Go to register →',\n    'register_new_account' => 'Register new user',\n    'username_description' => 'English name or Email',\n    'password' => 'Passwod',\n    'password_again' => 'Enter password again',\n    'verification_code' => 'Verification code',\n    'register' => 'Register',\n    'had_a_account' => ' Sign on right now→',\n    'update_personal_info' => 'Modify personal information',\n    'new_password_description' => 'The new password',\n    'old_password_description' => 'Original password',\n    'submit' => 'Submit',\n    'goback' => 'Goback',\n\n    //message 弹出信息有关的文案\n    'no_permissions' => 'No permissions',\n    'incorrect_password' => 'Incorrect password',\n    'user_does_not_exist' => 'User does not exist',\n    'operation_succeeded' => 'Operation succeeded',\n    'operation_failed' => 'Operation failed',\n    'access_password_are_incorrect' => 'Access password are incorrect',\n    'verification_code_are_incorrect' => 'Verification code are incorrect',\n    'no_permissions_to_delete_page' => 'No permissions！The page is created by {$author_username}',\n    'delete_succeeded' => 'Delete succeeded',\n    'delete_failed' => 'Delete failed',\n    'register_succeeded' => 'Register succeeded',\n    'username_or_password_incorrect' => 'Username or password are incorrect',\n    'username_exists' => 'Username exists',\n    'code_much_the_same' => 'Password much be the same',\n    'verification_code_are_incorrect' => 'Verification code are incorrect',\n    'auto_login_succeeded' => 'Automatic login success! Jumping...',\n    'login_succeeded' => 'Login succeeded',\n    'modify_succeeded' => 'Modify succeeded',\n    'modify_faild' => 'Modify failed',\n    'old_password_incorrect' => 'The original password is not correct',\n    'logout_succeeded' => 'Logout succeeded',\n\n    //error_message\n    \"no_delete_empty_catalog\" => 'In order to secure, do not allow direct delete an empty catalog. Please delete or move all the pages in the catalog',\n\n    \"default_title\" => 'Default',\n\n    //export html\n    'item_not_exists' => 'Item does not exist',\n    'export_html_not_support_item_type' => 'Unsupported item type, only supports regular items, RunAPI items and single page items',\n    'create_temp_dir_failed' => 'Failed to create temporary directory',\n    'no_pages_to_export' => 'No pages to export',\n    'zip_failed' => 'Failed to create ZIP file',\n    'export_failed' => 'Export failed',\n);\n"
  },
  {
    "path": "server/Application/Api/Lang/zh-cn.php",
    "content": "<?php\nreturn array(\n\n    //Attorn\n    'attorn_item' => '转让项目',\n    'username' => '用户名',\n    'receiver_name' => '项目接收者用户名',\n    'verify_identity' => '验证身份',\n    'your_password' => '你的登录密码',\n    'attorn' => '转让',\n    'close' => '关闭',\n\n    //Catalog\n    'new_or_edit_catalog' => '新建/编辑目录',\n    'catalog_name' => '目录名',\n    's_number' => '序号',\n    's_number_explain' => '可选：顺序数字',\n    'last_catalog' => '上级目录',\n    'save' => '保存',\n    'delete_catalog' => '删除目录',\n    'catalog_list' => '目录列表',\n    'click_to_edit' => '点击可编辑',\n\n\n    //index\n    'help' => '帮助',\n    'demo' => '示例',\n    'index_login_or_register' => '登录 / 注册',\n    'my_item' => '我的项目',\n    'section_title1' => 'ShowDoc',\n    'section_description1' => '一个非常适合IT团队的在线API文档、技术文档工具',\n    'section_title2' => 'API文档',\n    'section_description2' => ' APP、web前端与服务器常用API来进行交互<br>用ShowDoc可以非常方便快速地编写出美观的API文档',\n    'section_title3' => '数据字典',\n    'section_description3' => '好的数据字典可以很方便地向别人描述你的数据库结构<br>用ShowDoc可以编辑出美观的数字字典',\n    'section_title4' => '说明文档',\n    'section_description4' => '你完全可以使用 ShowDoc来编写一些工具的说明书<br>也可以编写一些技术规范说明文档以供团队查阅',\n    'section_title5' => '团队协作',\n    'section_description5' => '团队权限管理机制让团队良好地协同编写文档',\n    'section_title6' => '免费开源',\n    'section_description6' => 'ShowDoc提供免费开源的版本<br>你可以选择将ShowDoc部署到你的服务器',\n    'section_title7' => '在线托管',\n    'section_description7' => 'www.showdoc.cc 提供安全稳定的在线文档托管服务<br>你可以放心地选择托管你的文档数据在云端',\n    'section_title8' => '立即体验',\n    'section_description8' => '超过6000+互联网团队正在使用ShowDoc',\n\n\n    //Common message\n    'redirect_message' => '如果你的浏览器没有自动跳转，请点击此链接',\n    'click_to_goback' => '点击这里返回上一页',\n    'home' => '首页',\n\n\n    //item/add\n    'item_name' => '项目名',\n    'item_description' => '项目描述',\n    'item_domain' => '(可选)个性域名',\n    'item_domain_illegal' => '个性域名只能是字母或数字的组合',\n    'domain_already_exists' => '个性域名已经存在',\n    'visit_password_placeholder' => '访问密码（可选，私密项目请设置密码）',\n    'submit' => '提交',\n    'goback' => '返回',\n    //item/delete\n    'delete_item' => '删除项目',\n    'verify_your_identity' => '验证你的身份',\n    'creator_password' => '创建人登录密码',\n    'delete' => '删除',\n    'close' => '关闭',\n    //item/index\n    'personal_setting' => '个人设置',\n    'share_home' => '分享主页',\n    'web_home' => '网站首页',\n    'logout' => '退出登录',\n    'add_an_item' => '添加一个新项目',\n    'new_item' => '新建项目',\n    'share_my_home' => '分享我的主页',\n    'home_address' => '主页地址',\n    'home_address_description' => '别人访问您的主页时，将可以看到您的所有公开项目（但没有新建项目等权限）。你可以复制地址给你的好友',\n    //item/pwd\n    'input_visit_password' => '请输入访问密码',\n    'password' => '密码',\n    'verification_code' => '验证码',\n    'submit' => '提交',\n    'login_or_register' => '登录/注册',\n    //item/show\n    'item' => '项目',\n    'share' => '分享',\n    'export' => '导出',\n    'update_info' => '修改信息',\n    'manage_members' => '成员管理',\n    'attorn' => '转让',\n    'delete' => '删除',\n    'more_item' => '更多项目',\n    'login_or_register' => '登录/注册',\n    'about_showdoc' => '关于ShowDoc',\n    'my_item' => '我的项目',\n    'new_page' => '新建页面',\n    'new_catalog' => '新建目录',\n    'share_address_to_your_friends' => '分享该接口地址给你的好友',\n    'share' => '分享',\n    'copy_interface_to_new' => '复制该页面到新页面',\n    'copy' => '复制',\n    'edit_interface' => '编辑页面',\n    'edit' => '编辑',\n    'delete_interface' => '删除页面',\n    'comfirm_delete' => '确认删除吗？',\n    'delete' => '删除',\n    'share' => '分享',\n    'item_address' => '项目地址',\n    'copy_address_to_your_friends' => '你可以复制地址给你的好友',\n    'share_page' => '分享页面',\n    'page_address' => '页面地址',\n    'copy_address_to_your_friends' => '你可以复制地址给你的好友',\n    //item/showbyuid\n    'more' => '更多',\n    'my_item' => '我的项目',\n    'login_or_register' => '登录/注册',\n    'about_showdoc' => '关于ShowDoc',\n    'all_pubilc_item' => '的所有公开项目',\n\n    //member\n    'new_member' => '新增成员',\n    'username' => '用户名',\n    'save' => '保存',\n    'member_list' => '成员列表',\n    'click_to_delete' => '点击可删除',\n    'close' => '关闭',\n    \"member_group_id\" => \"只读\",\n\n    //page\n    'input_page_title' => '请输入页面标题',\n    'level_2_directory' => '二级目录',\n    'level_3_directory' => '三级目录',\n    's_number_explain' => '可选：顺序数字',\n    'history_version' => '历史版本',\n    'save' => '保存',\n    'cancel' => '取消',\n    'inser_apidoc_template' => '插入API接口模板',\n    'inser_database_doc_template' => '插入数据字典模板',\n    'json_tools' => 'JSON工具',\n    'json_to_table' => 'JSON转参数表格',\n    'beautify_json' => 'JSON格式化',\n    'beautify_json_description' => '请粘贴一段json，程序将自动以美观的方式格式化显示',\n    'http_test_api' => '在线测试API',\n    'json_to_table_description' => '请粘贴一段json，程序将自动将json解析并生成参数表格。此功能适合用于快速编写API文档的返回参数表格',\n    'confirm' => '确定',\n    'cancel' => '取消',\n    'history_version' => '历史版本',\n    'update_time' => '修改时间',\n    'update_by_who' => '修改人',\n    'operation' => '操作',\n    'recover_to_this_version' => '恢复到此版本',\n    'close' => '关闭',\n    'finish' => '完成',\n    'api_test_title' => 'GET和POST测试',\n    'api_address_description' => '接口地址(如：http://www.abc.com/api/login)',\n    'api_address' => '接口地址',\n    'params_description' => '参数(如：user_id=121&age=22&date=2016-06-02)',\n    'params' => '参数',\n    'clear' => '清除',\n    'result' => '返回结果',\n    'save_to_templ' => '另存为模板',\n    'more_templ' => '更多模板',\n    'saved_templ_list' => '保存的模板列表',\n    'page_comments' => '页面注释',\n    'add_page_comments' => '保存前添加页面注释',\n    'cur_page_content' => '当前最新版本',\n    'history_page_content' => '历史版本',\n    'overview' => '预览',\n\n    //user\n    'login' => '登录',\n    'username' => '用户名',\n    'password' => '密码',\n    'verification_code' => '验证码',\n    'no_account' => '没有账号？马上去注册→',\n    'register_new_account' => '注册新用户',\n    'username_description' => '用户名（可填英文昵称或邮箱）',\n    'password' => '密码',\n    'password_again' => '再次输入密码',\n    'verification_code' => '验证码',\n    'register' => '注册',\n    'had_a_account' => '已有账号？马上去登录→',\n    'update_personal_info' => '修改个人信息',\n    'new_password_description' => '新密码，若不修改请留空',\n    'old_password_description' => '原密码，若不修改密码请留空',\n    'submit' => '提交',\n    'goback' => '返回',\n\n    //message 弹出信息有关的文案\n    'no_permissions' => '你无权限',\n    'incorrect_password' => '密码错误',\n    'user_does_not_exist' => '不存在此用户',\n    'operation_succeeded' => '操作成功！',\n    'operation_failed' => '操作失败！',\n    'access_password_are_incorrect' => '访问密码不正确',\n    'verification_code_are_incorrect' => '验证码不正确',\n    'no_permissions_to_delete_page' => '你无权限！此页面由{$author_username}创建',\n    'delete_succeeded' => '删除成功！',\n    'delete_failed' => '删除失败！',\n    'register_succeeded' => '注册成功！',\n    'username_or_password_incorrect' => '用户名或密码不正确',\n    'username_exists' => '用户名已经存在啦！',\n    'code_much_the_same' => '两次输入的密码不一致！',\n    'verification_code_are_incorrect' => '验证码不正确',\n    'auto_login_succeeded' => '自动登录成功！正在跳转...',\n    'login_succeeded' => '登录成功！',\n    'modify_succeeded' => '修改成功！',\n    'modify_faild' => '修改失败！',\n    'old_password_incorrect' => '原密码不正确',\n    'logout_succeeded' => '退出成功！',\n\n    //error_message\n    \"no_delete_empty_catalog\" => '为了安全，不允许直接删除非空目录。请先删除或转移该目录下的所有页面',\n\n    \"default_title\" => '默认页面',\n\n    //export html\n    'item_not_exists' => '项目不存在',\n    'export_html_not_support_item_type' => '不支持的项目类型，仅支持常规项目、RunAPI项目和单页项目',\n    'create_temp_dir_failed' => '创建临时目录失败',\n    'no_pages_to_export' => '没有可导出的页面',\n    'zip_failed' => '打包ZIP文件失败',\n    'export_failed' => '导出失败',\n\n\n);\n"
  },
  {
    "path": "server/Application/Api/Model/AttachmentModel.class.php",
    "content": "<?php\n\nnamespace Api\\Model;\n\nuse Api\\Model\\BaseModel;\nuse AsyncAws\\S3\\S3Client;\n\n/**\n * \n * @author star7th      \n */\nclass AttachmentModel extends BaseModel\n{\n\n\tprotected $autoCheckFields = false;  //一定要关闭字段缓存，不然会报找不到表的错误\n\n\t//获取某个用户的当前已使用附件流量\n\tpublic function getUserFlow($uid)\n\t{\n\t\t$month = Date(\"Y-m\");\n\t\t$file_flow = D(\"FileFlow\")->where(\"uid = %s and date_month = %s\", array($uid, $month))->find();\n\t\tif ($file_flow) {\n\t\t\treturn intval($file_flow['used']);\n\t\t} else {\n\t\t\tD(\"FileFlow\")->add(array(\n\t\t\t\t\"uid\" => $uid,\n\t\t\t\t\"used\" => 0,\n\t\t\t\t\"date_month\" => $month,\n\n\t\t\t));\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\t//记录某个用户流量\n\tpublic function recordUserFlow($uid, $file_size)\n\t{\n\t\t$month = Date(\"Y-m\");\n\t\t$used = $this->getUserFlow($uid);\n\t\treturn D(\"FileFlow\")->where(\"uid = %s and date_month = %s\", array($uid, $month))->save(array(\n\t\t\t\"used\" => $used + intval($file_size)\n\t\t));\n\t}\n\n\tpublic function deleteFile($file_id)\n\t{\n\t\t$file_id = intval($file_id);\n\t\t$file = D(\"UploadFile\")->where(array('file_id' => $file_id))->find();\n\t\t$real_url = $file['real_url'];\n\t\t$array = explode(\"/Public/Uploads/\", $real_url);\n\t\t$file_path = \"../Public/Uploads/\" . $array[1];\n\t\tif ( $array[1] && file_exists($file_path)) {\n\t\t\t@unlink($file_path);\n\t\t}else{\n\t\t\t$this->deleteOss($real_url);\n\t\t}\n\t\t\n\t\tD(\"UploadFile\")->where(array('file_id' => $file_id))->delete();\n\t\tD(\"FilePage\")->where(array('file_id' => $file_id))->delete();\n\t\treturn true;\n\t}\n\n\t//上传文件，返回url\n\tpublic function upload($_files, $file_key, $uid, $item_id = 0, $page_id = 0, $check_filename = true)\n\t{\n\t\t$uploadFile = $_files[$file_key];\n\n\t\tif ($check_filename && !$this->isAllowedFilename($_files[$file_key]['name'])) {\n\t\t\treturn false;\n\t\t}\n\n\t\t$oss_open = D(\"Options\")->get(\"oss_open\");\n\t\tif ($oss_open) {\n\t\t\t$url = $this->uploadOss($uploadFile);\n\t\t\tif ($url) {\n\t\t\t\t$sign = md5($url . time() . rand());\n\t\t\t\t$insert = array(\n\t\t\t\t\t\"sign\" => $sign,\n\t\t\t\t\t\"uid\" => $uid,\n\t\t\t\t\t\"item_id\" => $item_id,\n\t\t\t\t\t\"page_id\" => $page_id,\n\t\t\t\t\t\"display_name\" => $uploadFile['name'],\n\t\t\t\t\t\"file_type\" => $uploadFile['type'],\n\t\t\t\t\t\"file_size\" => $uploadFile['size'],\n\t\t\t\t\t\"real_url\" => $url,\n\t\t\t\t\t\"addtime\" => time(),\n\t\t\t\t);\n\t\t\t\t$file_id = D(\"UploadFile\")->add($insert);\n\t\t\t\t$insert = array(\n\t\t\t\t\t\"file_id\" => $file_id,\n\t\t\t\t\t\"item_id\" => $item_id,\n\t\t\t\t\t\"page_id\" => $page_id,\n\t\t\t\t\t\"addtime\" => time(),\n\t\t\t\t);\n\t\t\t\t$ret = D(\"FilePage\")->add($insert);\n\t\t\t\t$url = server_url(\"api/attachment/visitFile\", array(\"sign\" => $sign));\n\t\t\t\treturn $url;\n\t\t\t}\n\t\t} else {\n\t\t\t$upload = new \\Think\\Upload(); // 实例化上传类\n\t\t\t$upload->maxSize  = 1003145728; // 设置附件上传大小\n\t\t\t$upload->rootPath = './../Public/Uploads/'; // 设置附件上传目录\n\t\t\t$upload->savePath = ''; // 设置附件上传子目录\n\t\t\t$info = $upload->uploadOne($uploadFile);\n\t\t\tif (!$info) { // 上传错误提示错误信息\n\t\t\t\tvar_dump($upload->getError());\n\t\t\t\treturn;\n\t\t\t} else { // 上传成功 获取上传文件信息\n\t\t\t\t$url = site_url() . '/Public/Uploads/' . $info['savepath'] . $info['savename'];\n\t\t\t\t$sign = md5($url . time() . rand());\n\t\t\t\t$insert = array(\n\t\t\t\t\t\"sign\" => $sign,\n\t\t\t\t\t\"uid\" => $uid,\n\t\t\t\t\t\"item_id\" => $item_id,\n\t\t\t\t\t\"page_id\" => $page_id,\n\t\t\t\t\t\"display_name\" => $uploadFile['name'],\n\t\t\t\t\t\"file_type\" => $uploadFile['type'],\n\t\t\t\t\t\"file_size\" => $uploadFile['size'],\n\t\t\t\t\t\"real_url\" => $url,\n\t\t\t\t\t\"addtime\" => time(),\n\t\t\t\t);\n\t\t\t\t$file_id = D(\"UploadFile\")->add($insert);\n\t\t\t\t$insert = array(\n\t\t\t\t\t\"file_id\" => $file_id,\n\t\t\t\t\t\"item_id\" => $item_id,\n\t\t\t\t\t\"page_id\" => $page_id,\n\t\t\t\t\t\"addtime\" => time(),\n\t\t\t\t);\n\t\t\t\t$ret = D(\"FilePage\")->add($insert);\n\t\t\t\t$url = server_url(\"api/attachment/visitFile\", array(\"sign\" => $sign));\n\t\t\t\treturn $url;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\t//上传到oss。参数$uploadFile是文件上传流，如$_FILES['file'] .也可以自己拼凑\n\tpublic function uploadOss($uploadFile)\n\t{\n\t\t$oss_setting_json = D(\"Options\")->get(\"oss_setting\");\n\t\t$oss_setting = json_decode($oss_setting_json, 1);\n\n\t\tif ($oss_setting && $oss_setting['oss_type'] && ($oss_setting['oss_type'] == 's3_storage' || $oss_setting['oss_type'] == 'aliyun')) {\n\n\t\t\treturn $this->uploadS3($uploadFile, $oss_setting);\n\t\t}\n\n\t\tif ($oss_setting && $oss_setting['oss_type'] && $oss_setting['oss_type'] == 'qiniu') {\n\n\t\t\t$oss_setting['endpoint'] = $this->getQiuniuEndpointByKey($oss_setting['key'], $oss_setting['bucket']);\n\t\t\treturn $this->uploadS3($uploadFile, $oss_setting);\n\t\t}\n\t\t// 腾讯云\n\t\tif ($oss_setting && $oss_setting['oss_type'] && $oss_setting['oss_type'] == 'qcloud') {\n\t\t\t// 腾讯云，一开始让用户填写region而没填写endpoint，所以要自己拼接\n\t\t\t$oss_setting['endpoint'] = \"https://cos.{$oss_setting['region']}.myqcloud.com\";\n\t\t\t// 腾讯云的SecretId相当于s3的key， secretKey相当于s3的secret\n\t\t\t$oss_setting['key'] = $oss_setting['secretId'];\n\t\t\t$oss_setting['secret'] = $oss_setting['secretKey'];\n\t\t\treturn $this->uploadS3($uploadFile, $oss_setting);\n\t\t}\n\n\n\t\treturn false;\n\t}\n\n\t// 通过s3协议上传\n\t// 注意传进来的oss_setting数组需要先转换成合法格式\n\tpublic function uploadS3($uploadFile, $oss_setting)\n\t{\n\n\t\t$ext = strrchr($uploadFile['name'], '.'); //获取扩展名\n\t\t\n\t\tif($oss_setting['subcat']){\n\t\t\t$oss_path = $oss_setting['subcat'].\"/showdoc_\" . get_rand_str() . $ext;\n\t\t}else{\n\t\t\t$oss_path = \"showdoc_\" . get_rand_str() . $ext;\n\t\t}\n\t\t\n\n\t\t// 如果不包含协议头，自己给它补充\n\t\tif (!strstr($oss_setting['endpoint'], '://')) {\n\t\t\t$oss_setting['endpoint'] = 'https://' . $oss_setting['endpoint'];\n\t\t}\n\n\t\t$s3 = new S3Client([\n\t\t\t'accessKeyId' => $oss_setting['key'],\n\t\t\t'accessKeySecret' => $oss_setting['secret'],\n\t\t\t'endpoint' => $oss_setting['endpoint'],\n\t\t\t'sendChunkedBody' => false\n\t\t]);\n\n\t\t// Send a PutObject request and get the result object.\n\t\t$resObj = $s3->putObject([\n\t\t\t'Bucket' => $oss_setting['bucket'],\n\t\t\t'Key'    => $oss_path,\n\t\t\t'Body'   => fopen($uploadFile['tmp_name'], 'rb'),\n\t\t\t// 增加浏览器的缓存控制头，减缓服务器压力，增加用户体验\n\t\t\t// 参考文章：https://csswizardry.com/2019/03/cache-control-for-civilians/\n\t\t\t'CacheControl' => 'public, max-age=31536000, s-maxage=31536000, immutable',\n\t\t\t// 设置正确的“Content-Type”响应头，避免浏览器将图片等文件当成数据流直接下载\n\t\t\t'ContentType' => $uploadFile['type']\n\t\t]);\n\n\t\t// 不抛出异常，默认就是成功的\n\n\t\tif ($oss_setting['domain']) {\n\t\t\treturn $oss_setting['protocol'] . '://' . $oss_setting['domain'] . \"/\" . $oss_path;\n\t\t} else {\n\t\t\t$tmp_array = parse_url($oss_setting['endpoint']);\n\t\t\t$endpoint_host = $tmp_array['host'];\n\t\t\treturn 'https://' . $oss_setting['bucket'] . '.' . $endpoint_host . '/' . $oss_path;\n\t\t}\n\t}\n\n\t//从oss中删除\n\tpublic function deleteOss($file_url)\n\t{\n\t\t$oss_setting_json = D(\"Options\")->get(\"oss_setting\");\n\t\t$oss_setting = json_decode($oss_setting_json, 1);\n\t\tif ($oss_setting && $oss_setting['oss_type'] && ($oss_setting['oss_type'] == 's3_storage' || $oss_setting['oss_type'] == 'aliyun')) {\n\t\t\treturn $this->deleteS3($file_url, $oss_setting);\n\t\t}\n\n\t\tif ($oss_setting && $oss_setting['oss_type'] && $oss_setting['oss_type'] == 'qiniu') {\n\t\t\t$oss_setting['endpoint'] = $this->getQiuniuEndpointByKey($oss_setting['key'], $oss_setting['bucket']);\n\t\t\treturn $this->deleteS3($file_url, $oss_setting);\n\t\t}\n\t\t//var_dump($config);\n\t\t// 腾讯云\n\t\tif ($oss_setting && $oss_setting['oss_type'] && $oss_setting['oss_type'] == 'qcloud') {\n\n\t\t\t// 腾讯云，一开始让用户填写region而没填写endpoint，所以要自己拼接\n\t\t\t$oss_setting['endpoint'] = \"https://cos.{$oss_setting['region']}.myqcloud.com\";\n\t\t\t// 腾讯云的SecretId相当于s3的key， secretKey相当于s3的secret\n\t\t\t$oss_setting['key'] = $oss_setting['secretId'];\n\t\t\t$oss_setting['secret'] = $oss_setting['secretKey'];\n\t\t\treturn $this->deleteS3($file_url, $oss_setting);\n\t\t}\n\n\n\t\treturn false;\n\t}\n\n\t// 通过s3协议删除\n\t// 注意传进来的oss_setting数组需要先转换成合法格式\n\tpublic function deleteS3($file_url, $oss_setting)\n\t{\n\n\t\t$array = parse_url($file_url);\n\t\t$file = $array['path'];  // 得到的是url中的路径，例如/path_.txt\n\t\t$file = substr($file, 1); // 要把路径前的/去掉，才是得到文件名path_.txt\n\t\t// 如果不包含协议头，自己给它补充\n\t\tif (!strstr($oss_setting['endpoint'], '://')) {\n\t\t\t$oss_setting['endpoint'] = 'https://' . $oss_setting['endpoint'];\n\t\t}\n\n\t\t$s3 = new S3Client([\n\t\t\t'accessKeyId' => $oss_setting['key'],\n\t\t\t'accessKeySecret' => $oss_setting['secret'],\n\t\t\t'endpoint' => $oss_setting['endpoint'],\n\t\t]);\n\n\t\t// Send a PutObject request and get the result object.\n\t\t$resObj = $s3->deleteObject([\n\t\t\t'Bucket' => $oss_setting['bucket'],\n\t\t\t'Key'    => $file,\n\t\t]);\n\n\t\t// 不抛出异常，默认就是成功的\n\n\n\t}\n\n\t// 由于历史原因，当初没有让用户填写七牛云的region。而且即使填写了，也不能直接获取到七牛云s3兼容协议上传的endpoint\n\t// 所以，需要自己调接口查询\n\tpublic function getQiuniuEndpointByKey($key, $bucket)\n\t{\n\n\t\t$query_url = \"https://api.qiniu.com/v2/query?ak={$key}&bucket={$bucket}\";\n\t\t$res = http_post($query_url, array());\n\n\t\t$array = json_decode($res, true);\n\t\t// var_dump('https://'.$array['s3']['src']['main']['0']);exit();\n\t\tif($array && $array['s3']['src']['main']['0']){\n\t\t\treturn 'https://'.$array['s3']['src']['main']['0'];\n\t\t}\n\t}\n\n\t// 判断文件名是否包含危险的扩展名\n\t// 准备弃用。因为一个个ban太麻烦了。准备改用白名单机制\n\tpublic function isDangerFilename($filename)\n\t{\n\n\t\t$isDangerStr = function ($filename, $keyword) {\n\t\t\tif (strstr(strip_tags(strtolower($filename)), $keyword)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn false;\n\t\t};\n\t\tif (\n\t\t\t$isDangerStr($filename, \".php\")\n\t\t\t|| $isDangerStr($filename, \".svg\")\n\t\t\t|| $isDangerStr($filename, \".htm\")\n\t\t\t|| $isDangerStr($filename, \".shtm\")\n\t\t\t|| $isDangerStr($filename, \"%\")\n\t\t\t|| $isDangerStr($filename, \".xml\")\n\t\t\t|| $isDangerStr($filename, \".xxhtml\")\n\t\t\t|| $isDangerStr($filename, \".asp\")\n\t\t\t|| $isDangerStr($filename, \".xsl\")\n\t\t\t|| $isDangerStr($filename, \".aspx\")\n\t\t\t|| $isDangerStr($filename, \".xsd\")\n\t\t\t|| $isDangerStr($filename, \".asa\")\n\t\t\t|| $isDangerStr($filename, \".cshtml\")\n\t\t\t|| $isDangerStr($filename, \".axd\")\n\t\t\t|| $isDangerStr($filename, \"htm\")\n\t\t) {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t// 判断上传的文件扩展名是否处于白名单内\n\tpublic function isAllowedFilename($filename)\n\t{\n\t\t$allow_array = array(\n\t\t\t'.jpg', '.jpeg', '.png', '.bmp', '.gif', '.ico', '.webp',\n\t\t\t'.mp3', '.wav', '.mp4', '.mov', '.flac', '.mkv',\n\t\t\t'.zip', '.tar', '.gz', '.tgz', '.ipa', '.apk', '.rar', '.iso',\n\t\t\t'.pdf', '.epub', '.xps', '.doc', '.docx', '.wps',\n\t\t\t'.ppt', '.pptx', '.xls', '.xlsx', '.txt', '.psd', '.csv',\n\t\t\t'.cer', '.ppt', '.pub', '.json', '.css',\n\t\t);\n\n\t\t$ext = strtolower(substr($filename, strripos($filename, '.'))); //获取文件扩展名（转为小写后）\n\t\tif (in_array($ext, $allow_array)) {\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n}\n"
  },
  {
    "path": "server/Application/Api/Model/BaseModel.class.php",
    "content": "<?php\n\nnamespace Api\\Model;\n\nuse Think\\Model;\n\n/**\n *\n *        \n *        \n */\nclass BaseModel extends Model\n{\n    // 自动验证 //默认,验证条件：0存在字段就进行验证 , 验证时间：1新增/编辑 数据时候验证\n    protected $_validate = array();\n    // 自动填充 //默认 新增数据的时候处理\n    protected $_auto = array();\n    // 只读字段，插入后不能通过save更新\n    protected $readonlyField = array();\n}\n"
  },
  {
    "path": "server/Application/Api/Model/CaptchaModel.class.php",
    "content": "<?php\n\nnamespace Api\\Model;\n\nuse Api\\Model\\BaseModel;\n\n/**\n * \n * @author star7th      \n */\nclass CaptchaModel extends BaseModel\n{\n\n\tpublic function check($captcha_id, $captcha, $none = '')\n\t{\n\t\t$time = time();\n\t\t$captcha_id = intval($captcha_id);\n\t\t$captcha_array = $this->where(\"captcha_id = %d and expire_time > %d\", array($captcha_id, $time))->find();\n\t\tif ($captcha_array['captcha'] && $captcha_array['captcha'] == $captcha) {\n\t\t\t//检查完就设置该验证码过期\n\t\t\t$this->where(array('captcha_id' => $captcha_id))->save(array(\"expire_time\" => 0));\n\t\t\treturn true;\n\t\t} else {\n\t\t\t//删除掉所有过期的二维码\n\t\t\t//$this->where(\"expire_time < %d\", array($time))->delete();\n\t\t\t$this->where(array('captcha_id' => $captcha_id))->save(array(\"expire_time\" => ($captcha_array['expire_time'] - 10)));\n\t\t}\n\t\treturn false;\n\t}\n}\n"
  },
  {
    "path": "server/Application/Api/Model/CatalogModel.class.php",
    "content": "<?php\n\nnamespace Api\\Model;\n\nuse Api\\Model\\BaseModel;\n\n/**\n * \n * @author star7th      \n */\nclass CatalogModel extends BaseModel\n{\n\n\t//获取目录列表。如果isGroup参数为true，则按分组返回\n\tpublic function getList($item_id, $isGroup = false)\n\t{\n\t\tif ($item_id > 0) {\n\t\t\t$ret = $this->where(\" item_id = '%d' \", array($item_id))->order(\" s_number, cat_id asc  \")->select();\n\t\t}\n\t\tif ($ret) {\n\t\t\tforeach ($ret as $key => $value) {\n\t\t\t\t$ret[$key]['addtime'] = date(\"Y-m-d H:i:s\", $value['addtime']);\n\t\t\t}\n\n\t\t\tif ($isGroup) {\n\t\t\t\t$ret2 = array();\n\t\t\t\tforeach ($ret as $key => $value) {\n\t\t\t\t\tif ($value['parent_cat_id']) {\n\t\t\t\t\t\t//跳过\n\t\t\t\t\t\t//\n\t\t\t\t\t} else {\n\t\t\t\t\t\t$value['sub'] = $this->_getChlid($value['cat_id'], $ret);\n\t\t\t\t\t\t$ret2[] = $value;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t$ret = $ret2;\n\t\t\t}\n\n\t\t\treturn $ret;\n\t\t} else {\n\t\t\treturn array();\n\t\t}\n\t}\n\n\t//获取某个目录的子   （如果存在的话）  此private方法只给本类内调用\n\tprivate function _getChlid($cat_id, $item_data)\n\t{\n\t\t$return = array();\n\t\tif ($item_data && $cat_id) {\n\t\t\tforeach ($item_data as $key => $value) {\n\t\t\t\tif ($value['parent_cat_id'] == $cat_id) {\n\t\t\t\t\t$value['sub'] = $this->_getChlid($value['cat_id'], $item_data);\n\t\t\t\t\t$return[] = $value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn $return;\n\t}\n\n\t//获取某id下的子目录列表（此public方法暴露出去给其他地方调用）\n\tpublic function getChlid($item_id, $cat_id)\n\t{\n\t\t$return = array();\n\t\t$ret = $this->getList($item_id, true);\n\t\tif ($ret) {\n\t\t\tforeach ($ret as $key => $value) {\n\t\t\t\tif ($value['cat_id'] == $cat_id) {\n\t\t\t\t\t$return = $value['sub'];\n\t\t\t\t}\n\n\t\t\t\tif ($value['sub']) {\n\t\t\t\t\tforeach ($value['sub'] as $key2 => $value2) {\n\t\t\t\t\t\tif ($value2['cat_id'] == $cat_id) {\n\t\t\t\t\t\t\t$return = $value2['sub'];\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif ($value2['sub']) {\n\t\t\t\t\t\t\tforeach ($value2['sub'] as $key3 => $value3) {\n\t\t\t\t\t\t\t\tif ($value3['cat_id'] == $cat_id) {\n\t\t\t\t\t\t\t\t\t$return = $value3['sub'];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn $return;\n\t}\n\n\t//获取某个层级的目录列表。例如 获取二级目录列表\n\tpublic function getListByLevel($item_id, $level = 2)\n\t{\n\t\t$return = array();\n\t\t$ret = $this->getList($item_id);\n\t\tif ($ret) {\n\t\t\tforeach ($ret as $key => $value) {\n\t\t\t\tif ($value['level'] == $level) {\n\t\t\t\t\t$return[] = $value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn $return;\n\t}\n\n\n\t//删除目录以及下面的所有页面/子目录\n\tpublic function deleteCat($cat_id)\n\t{\n\t\tif (!$cat_id) {\n\t\t\treturn false;\n\t\t}\n\t\t$cat_id = intval($cat_id);\n\t\t//如果有子目录的话，递归把子目录清了\n\t\t$cats = $this->where(array('parent_cat_id' => $cat_id))->select();\n\t\tif ($cats) {\n\t\t\tforeach ($cats as $key => $value) {\n\t\t\t\t$this->deleteCat($value['cat_id']);\n\t\t\t}\n\t\t}\n\t\t//获取当前目录信息\n\t\t$cat = $this->where(array('cat_id' => $cat_id))->find();\n\t\t$item_id = $cat['item_id'];\n\t\t$all_pages = D(\"Page\")->where(array('item_id' => $item_id, 'is_del' => 0))->field(\"page_id,cat_id\")->select();\n\t\t$pages = array();\n\t\tif ($all_pages) {\n\t\t\tforeach ($all_pages as $key => $value) {\n\t\t\t\tif ($value['cat_id'] == $cat_id) {\n\t\t\t\t\t$pages[] = $value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif ($pages) {\n\t\t\tforeach ($pages as $key => $value) {\n\t\t\t\tD(\"Page\")->softDeletePage($value['page_id']);\n\t\t\t}\n\t\t}\n\t\t$this->where(array('cat_id' => $cat_id))->delete();\n\n\t\treturn true;\n\t}\n\n\t//根据用户目录权限来过滤目录数据\n\tpublic function filteMemberCat($uid, $catData)\n\t{\n\t\tif (!$catData || !$catData[0]['item_id']) {\n\t\t\treturn $catData;\n\t\t}\n\t\t$item_id = $catData[0]['item_id'];\n        // 如果用户被分配了 目录权限 ，则获取他在该项目下拥有权限的目录id集合\n        $cat_ids = D(\"Member\")->getCatIds($item_id, $uid);\n        //开始根据cat_id集合过滤（仅过滤二级目录）\n        if (!empty($cat_ids)) {\n            $allowed = array_flip(array_map('intval', $cat_ids));\n            foreach ($catData as $key => $value) {\n                if (!isset($allowed[intval($value['cat_id'])])) {\n                    unset($catData[$key]);\n                }\n            }\n            $catData = array_values($catData);\n        }\n\n\t\treturn $catData;\n\t}\n\n\t//复制目录\n\t// old_cat_id 原目录id\n\t// new_p_cat_id 复制完目录后，挂在哪个父目录下。这里是父目录id。可为0。默认使用old_cat_id的父目录id\n\t// $to_item_id 要复制到的项目id。可以是同一个项目，可以是跨项目。默认是同一个项目\n\tpublic function copy($uid, $old_cat_id, $new_p_cat_id = 0, $to_item_id = 0)\n\t{\n\t\t$userInfo = D(\"User\")->userInfo($uid);\n\t\t$old_cat_ary = $this->where(\"cat_id = '%d' \", array($old_cat_id))->find();\n\t\t$to_item_id = $to_item_id ? $to_item_id : $old_cat_ary['item_id'];\n\n\t\t//这里需要读取目录下的页面以及子目录信息\n\t\t$old_cat_data = $this->getCat($old_cat_id);\n\t\t$catalogs[] = $old_cat_data;\n\t\t//获取$level.先初始化$level = 2 ;\n\t\t$level = 2;\n\t\tif ($new_p_cat_id) {\n\t\t\t$p_cat_ary = $this->where(\"cat_id = '%d' \", array($new_p_cat_id))->find();\n\t\t\t$level = $p_cat_ary['level'] + 1;\n\t\t}\n\t\t//插入\n\t\t$res =  $this->insertCat($to_item_id, $catalogs, $userInfo, $new_p_cat_id,  $level);\n\t\treturn $res;\n\t}\n\n\t//获取某个目录下的页面和子目录\n\tpublic function getCat($cat_id)\n\t{\n\t\t$cat_id = intval($cat_id);\n\t\t$cat_ary = $this->where(array('cat_id' => $cat_id))->find();\n\t\t$item_id = $cat_ary['item_id'];\n\t\t//获取项目下所有页面信息\n\t\t$all_pages = D(\"Page\")->where(array('item_id' => $item_id, 'is_del' => 0))->order(\" s_number asc , page_id asc \")->field(\"*\")->select();\n\t\t//获取项目下所有目录信息\n\t\t$all_catalogs = $this->where(\" item_id = '%d' \", array($item_id))->order(\" s_number, cat_id asc  \")->select();\n\n\t\treturn D(\"Item\")->getCat($cat_ary, $all_pages, $all_catalogs);\n\t}\n\n\t//插入一个目录下的所有页面和子目录\n\tpublic function insertCat($item_id, $catalogs, $userInfo, $parent_cat_id = 0,  $level = 2)\n\t{\n\t\treturn $this->_insertCat($item_id, $catalogs, $userInfo, $parent_cat_id,  $level);\n\t}\n\n\t//插入一个目录下的所有页面和子目录\n\tprivate function _insertCat($item_id, $catalogs, $userInfo, $parent_cat_id = 0,  $level = 2)\n\t{\n\t\tif (!$catalogs) {\n\t\t\treturn;\n\t\t}\n\t\t$cat_id = 0;\n\t\tforeach ($catalogs as $key => $value) {\n\t\t\t$catalog_data = array(\n\t\t\t\t\"cat_name\" => $this->_htmlspecialchars($value['cat_name']),\n\t\t\t\t\"level\" => $level,\n\t\t\t\t\"s_number\" => $this->_htmlspecialchars($value['s_number']),\n\t\t\t\t\"item_id\" => $item_id,\n\t\t\t\t\"parent_cat_id\" => $parent_cat_id,\n\t\t\t\t\"addtime\" => time(),\n\t\t\t);\n\t\t\t$cat_id = D(\"Catalog\")->add($catalog_data);\n\n\t\t\t//该目录下的页面们\n\t\t\tif ($value['pages']) {\n\t\t\t\tforeach ($value['pages'] as $key2 => &$value2) {\n\n\t\t\t\t\t$page_data = array(\n\t\t\t\t\t\t\"author_uid\" => $userInfo['uid'],\n\t\t\t\t\t\t\"author_username\" => $userInfo['username'],\n\t\t\t\t\t\t\"page_title\" => $this->_htmlspecialchars($value2['page_title']),\n\t\t\t\t\t\t\"page_content\" => $this->_htmlspecialchars($value2['page_content']),\n\t\t\t\t\t\t\"s_number\" => $this->_htmlspecialchars($value2['s_number']),\n\t\t\t\t\t\t\"page_comments\" => $this->_htmlspecialchars($value2['page_comments']),\n\t\t\t\t\t\t\"item_id\" => $item_id,\n\t\t\t\t\t\t\"cat_id\" => $cat_id,\n\t\t\t\t\t\t\"addtime\" => time(),\n\t\t\t\t\t);\n\t\t\t\t\tD(\"Page\")->add($page_data);\n\t\t\t\t\tunset($page_data);\n\t\t\t\t\tunset($value2);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t//该目录的子目录\n\t\t\tif ($value['catalogs']) {\n\t\t\t\t$this->_insertCat($item_id, $value['catalogs'], $userInfo, $cat_id,  $level + 1);\n\t\t\t}\n\t\t}\n\n\t\treturn $cat_id;\n\t}\n\n\t// 用路径的形式（比如'二级目录/三级目录/四级目录'）来保存目录信息并返回最后一层目录的id\n\tpublic function saveCatPath($catPath, $item_id)\n\t{\n\t\tif (!$catPath) return 0;\n\t\t// $catPath是以斜杠 / 开头，且$catPath长度大于1（即不只是 / ）, 则把第一个 / 去掉\n\t\tif (substr($catPath, 0, 1) == '/' && strlen($catPath) > 1) {\n\t\t\t$catPath = substr($catPath, 1); // 去掉第一个字符\n\t\t}\n\t\t$session_key = 'cat_path_' . md5($item_id . $catPath);\n\t\t// 如果session中有缓存值，则直接从session中获取。这是为了避免重复读数据库\n\t\tif (session($session_key)) {\n\t\t\t// die(session($session_key));\n\t\t\treturn $cat_id = session($session_key);\n\t\t}\n\t\t$catalog_array = explode('/', $catPath);\n\t\t$cat_ids_array = array();\n\t\tfor ($i = 0; $i < count($catalog_array); $i++) {\n\t\t\t$level = $i + 2;\n\t\t\t$cat_name = $catalog_array[$i];\n\t\t\t$parent_cat_id = 0;\n\t\t\tif ($i > 0) {  //$i > 0则表明非顶级目录。应该有parent_cat_id\n\t\t\t\t$parent_cat_id = $cat_ids_array[$i - 1];\n\t\t\t}\n\t\t\t$one_array = D(\"Catalog\")->where(\" item_id = '%d' and level = '%d' and cat_name = '%s' and parent_cat_id = '%d' \", array($item_id, $level, $cat_name, $parent_cat_id))->find();\n\t\t\tif ($one_array) {\n\t\t\t\t$cat_ids_array[$i] = $one_array['cat_id'];\n\t\t\t} else {\n\t\t\t\t$add_data = array(\n\t\t\t\t\t\"cat_name\" => $cat_name,\n\t\t\t\t\t\"item_id\" => $item_id,\n\t\t\t\t\t\"addtime\" => time(),\n\t\t\t\t\t\"level\" => $level,\n\t\t\t\t\t'parent_cat_id' => $parent_cat_id\n\t\t\t\t);\n\t\t\t\t$one_cat_id = D(\"Catalog\")->add($add_data);\n\t\t\t\t$cat_ids_array[$i] = $one_cat_id;\n\t\t\t}\n\t\t}\n\n\t\t$cat_id = end($cat_ids_array); // 获取最后的一个元素\n\t\tif ($cat_id) {\n\t\t\tsession($session_key, $cat_id);\n\t\t\treturn $cat_id;\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate function _htmlspecialchars($str)\n\t{\n\t\tif (!$str) {\n\t\t\treturn '';\n\t\t}\n\t\t//之所以先htmlspecialchars_decode是为了防止被htmlspecialchars转义了两次\n\t\treturn htmlspecialchars(htmlspecialchars_decode($str));\n\t}\n}\n"
  },
  {
    "path": "server/Application/Api/Model/ExportModel.class.php",
    "content": "<?php\n\nnamespace Api\\Model;\n\nuse Api\\Model\\BaseModel;\n\n/**\n * \n * @author star7th      \n */\nclass ExportModel\n{\n\n    protected $autoCheckFields = false;  //一定要关闭字段缓存，不然会报找不到表的错误\n\n\n}\n"
  },
  {
    "path": "server/Application/Api/Model/ItemAiConfigModel.class.php",
    "content": "<?php\n\nnamespace Api\\Model;\n\nuse Api\\Model\\BaseModel;\n\n/**\n * 项目AI知识库配置模型\n * @author \n */\nclass ItemAiConfigModel extends BaseModel\n{\n    /**\n     * 获取项目的 AI 配置（如果不存在则返回默认配置）\n     * @param int $item_id 项目ID\n     * @return array 配置数组\n     */\n    public function getConfig($item_id)\n    {\n        $item_id = intval($item_id);\n        $config = $this->where(array('item_id' => $item_id))->find();\n        \n        if (!$config) {\n            // 返回默认配置\n            return array(\n                'item_id' => $item_id,\n                'enabled' => 0,\n                'dialog_collapsed' => 1,\n                'welcome_message' => '',\n                'addtime' => 0,\n                'updatetime' => 0\n            );\n        }\n        \n        return $config;\n    }\n    \n    /**\n     * 保存或更新配置\n     * @param int $item_id 项目ID\n     * @param array $data 配置数据\n     * @return boolean|integer\n     */\n    public function saveConfig($item_id, $data)\n    {\n        $item_id = intval($item_id);\n        $config = $this->where(array('item_id' => $item_id))->find();\n        \n        $save_data = array(\n            'item_id' => $item_id,\n            'updatetime' => time()\n        );\n        \n        // 合并传入的数据\n        if (isset($data['enabled'])) {\n            $save_data['enabled'] = $data['enabled'] ? 1 : 0;\n        }\n        if (isset($data['dialog_collapsed'])) {\n            $save_data['dialog_collapsed'] = $data['dialog_collapsed'] ? 1 : 0;\n        }\n        if (isset($data['welcome_message'])) {\n            $save_data['welcome_message'] = $data['welcome_message'];\n        }\n        \n        if ($config) {\n            // 更新\n            return $this->where(array('item_id' => $item_id))->save($save_data);\n        } else {\n            // 新增\n            $save_data['addtime'] = time();\n            return $this->add($save_data);\n        }\n    }\n}\n\n"
  },
  {
    "path": "server/Application/Api/Model/ItemChangeLogModel.class.php",
    "content": "<?php\n\nnamespace Api\\Model;\n\nuse Api\\Model\\BaseModel;\n\nclass ItemChangeLogModel extends BaseModel\n{\n\n\n    public function addLog($uid, $item_id, $op_action_type, $op_object_type, $op_object_id, $op_object_name = '', $remark = '')\n    {\n        $data = array(\n            \"uid\" => $uid,\n            \"item_id\" => $item_id,\n            \"op_action_type\" => $op_action_type,\n            \"op_object_type\" => $op_object_type,\n            \"op_object_id\" => $op_object_id,\n            \"op_object_name\" => $op_object_name,\n            \"remark\" => $remark,\n            \"optime\" => date(\"Y-m-d H:i:s\"),\n        );\n        $this->add($data);\n\n        //统计有多少条日志记录了\n        $count = $this->where(array('item_id' => $item_id))->count();\n        //每个项目只保留最多$keepNum个变更记录\n        $keepCount = 300;\n        if ($count > $keepCount) {\n            $ret = $this->where(array('item_id' => $item_id))->limit($keepCount)->order(\"id desc\")->select();\n            $this->where(\" item_id = '%d' and id < %d\", array($item_id, $ret[$keepCount - 1]['id']))->delete();\n        }\n    }\n\n    public function getLog($item_id, $page = 1, $count = 15)\n    {\n        $item_id = intval($item_id);\n        $list = $this->where(\" item_id = '%d' \", array($item_id))->order(\" optime desc \")->page(\" $page , $count \")->select();\n        $total = $this->where(\" item_id = '%d' \", array($item_id))->count();\n        if ($list) {\n            foreach ($list as $key => $value) {\n                $list[$key] = $this->renderOneLog($value);\n            }\n        }\n\n        $return = array(\n            \"total\" => (int)$total,\n            \"list\" => (array)$list,\n        );\n\n        return $return;\n    }\n\n    // 把变更日志的一行渲染成人类可读的提示\n    public function renderOneLog($one)\n    {\n        $op_action_type = $one['op_action_type'];\n        $uid = intval($one['uid']);\n        $one['op_object_id'] = intval($one['op_object_id']);\n        $user_array = D(\"User\")->where(array('uid' => $uid))->Field('username,name')->find();\n        $one['username'] = $user_array['username'];\n        $one['name'] = $user_array['name'];\n        $oper = $user_array['username'];\n        if ($user_array['name']) {\n            $oper = $user_array['username'] . '(' . $user_array['name'] . ')';\n        }\n        $one['oper'] = $oper;\n\n        switch ($op_action_type) {\n            case 'create':\n                $one['op_action_type_desc'] = '创建';\n                break;\n            case 'update':\n                $one['op_action_type_desc'] = '修改';\n                break;\n            case 'delete':\n                $one['op_action_type_desc'] = '删除';\n                break;\n            case 'export':\n                $one['op_action_type_desc'] = '导出';\n                break;\n            case 'binding':\n                $one['op_action_type_desc'] = '绑定';\n                break;\n            case 'unbound':\n                $one['op_action_type_desc'] = '解绑';\n                break;\n            case 'drag':\n                $one['op_action_type_desc'] = '拖曳修改';\n                break;\n            default:\n                $one['op_action_type_desc'] = '未定义';\n                break;\n        }\n\n        switch ($one['op_object_type']) {\n            case 'page':\n                $one['op_object_type_desc'] = '页面(或接口)';\n                break;\n            case 'catalog':\n                $one['op_object_type_desc'] = '目录';\n                break;\n            case 'item':\n                $one['op_object_type_desc'] = '项目';\n                break;\n            case 'team':\n                $one['op_object_type_desc'] = '团队';\n                break;\n            case 'member':\n                $one['op_object_type_desc'] = '成员';\n                break;\n            case 'tree':\n                $one['op_object_type_desc'] = '目录树';\n                break;\n            default:\n                $one['op_object_type_desc'] = '未定义';\n                break;\n        }\n\n        return $one;\n    }\n}\n"
  },
  {
    "path": "server/Application/Api/Model/ItemModel.class.php",
    "content": "<?php\n\nnamespace Api\\Model;\n\nuse Api\\Model\\BaseModel;\n\nclass ItemModel extends BaseModel\n{\n\n    public function export($item_id, $uncompress = 0)\n    {\n        $item_id = intval($item_id);\n        $item = D(\"Item\")->where(array('item_id' => $item_id))->field(\" item_type, item_name ,item_description,password \")->find();\n        $page_field = \"page_title ,cat_id,page_content,s_number,page_comments\";\n        $catalog_field = \"cat_id,cat_name ,parent_cat_id,level,s_number\";\n        $item['pages'] = $this->getContent($item_id, $page_field, $catalog_field, $uncompress);\n        $item['members'] = D(\"ItemMember\")->where(array('item_id' => $item_id))->field(\" member_group_id ,uid,username \")->select();\n        return  json_encode($item);\n    }\n    public function import($json, $uid, $item_id = 0, $item_name = '', $item_description = '', $item_password = '', $item_domain = '')\n    {\n        $userInfo = D(\"User\")->userInfo($uid);\n        $item = json_decode($json, 1);\n        unset($json);\n        if ($item) {\n\n            // 如果存在$item_id，那就是项目内导入。\n            if ($item_id) {\n                //\n\n            } else {\n                if ($item['item_domain']) {\n                    $item2 = D(\"Item\")->where(\"item_domain = '%s'\", array($item['item_domain']))->find();\n                    if ($item2) {\n                        //个性域名已经存在\n                        return false;\n                    }\n                    if (!ctype_alnum($item_domain) ||  is_numeric($item_domain)) {\n                        //echo '个性域名只能是字母或数字的组合';exit;\n                        return false;\n                    }\n                } else {\n                    $item['item_domain'] = '';\n                }\n                $item_data = array(\n                    \"item_name\" => $item_name ? $this->_htmlspecialchars($item_name)  : $this->_htmlspecialchars($item['item_name']),\n                    \"item_domain\" => $item_domain ? $this->_htmlspecialchars($item_domain)  : $this->_htmlspecialchars($item['item_domain']),\n                    \"item_type\" => $this->_htmlspecialchars($item['item_type']),\n                    \"item_description\" => $item_description ? $this->_htmlspecialchars($item_description) : $this->_htmlspecialchars($item['item_description']),\n                    \"password\" => $item_password ? $this->_htmlspecialchars($item_password)  : $this->_htmlspecialchars($item['password']),\n                    \"uid\" => $userInfo['uid'],\n                    \"username\" => $userInfo['username'],\n                    \"addtime\" => time(),\n                );\n                $item_id = D(\"Item\")->add($item_data);\n            }\n        }\n        if ($item['pages']) {\n            //父页面们（一级目录）\n            if ($item['pages']['pages']) {\n                foreach ($item['pages']['pages'] as $key => &$value) {\n                    $page_data = array(\n                        \"author_uid\" => $userInfo['uid'],\n                        \"author_username\" => $userInfo['username'],\n                        \"page_title\" => $this->_htmlspecialchars($value['page_title']),\n                        \"page_content\" => $this->_htmlspecialchars($value['page_content']),\n                        \"s_number\" => $this->_htmlspecialchars($value['s_number']),\n                        \"page_comments\" => $this->_htmlspecialchars($value['page_comments']),\n                        \"item_id\" => $item_id,\n                        \"cat_id\" => 0,\n                        \"addtime\" => time(),\n                    );\n                    D(\"Page\")->add($page_data);\n                    unset($page_data);\n                }\n                unset($item['pages']['pages']);\n            }\n            //二级目录\n            if ($item['pages']['catalogs']) {\n                $cat_path_pages = $this->toItemPageCatPath($item['pages']['catalogs']);\n                foreach ($cat_path_pages as $key => $value) {\n                    $page_id = D(\"Page\")->update_by_title($item_id, $value['page_title'], $value['page_content'], $value['cat_path'], $value['s_number'], $userInfo['uid'], $userInfo['username']);\n                }\n            }\n        }\n\n        return $item_id;\n    }\n\n    public function copy($item_id, $uid, $item_name = '', $item_description = '', $item_password = '', $item_domain = '')\n    {\n        return $this->import($this->export($item_id), $uid, 0, $item_name, $item_description, $item_password, $item_domain);\n    }\n\n    //获取菜单结构\n    public function getMemu($item_id)\n    {\n        $page_field = \"page_id,author_uid,cat_id,page_title,addtime,ext_info\";\n        $catalog_field = '*';\n        $data = $this->getContent($item_id, $page_field, $catalog_field);\n        return $data;\n    }\n\n    public function getContent($item_id, $page_field = \"*\", $catalog_field = \"*\", $uncompress = 0)\n    {\n        $item_id = intval($item_id);\n        //获取该项目下的所有页面\n        $all_pages = D(\"Page\")->where(array('item_id' => $item_id, 'is_del' => 0))->order(\" s_number asc , page_id asc  \")->field($page_field)->select();\n        $pages = array();\n        if ($all_pages) {\n            foreach ($all_pages as $key => $value) {\n                if ($value['cat_id']) {\n                    # code...\n                } else {\n                    $pages[] = $value;\n                }\n            }\n        }\n\n        //获取该项目下的所有目录\n        $all_catalogs = D(\"Catalog\")->field($catalog_field)->where(array('item_id' => $item_id))->order(\" s_number asc , cat_id asc \")->select();\n\n        //获取所有二级目录\n        $catalogs = array();\n        if ($all_catalogs) {\n            foreach ($all_catalogs as $key => $value) {\n                if ($value['level'] == 2) {\n                    $catalogs[] = $value;\n                }\n            }\n        }\n        if ($catalogs) {\n            foreach ($catalogs as $key => &$catalog2) {\n                $catalog2 = $this->_getCat($catalog2, $all_pages, $all_catalogs);\n            }\n        }\n        $menu = array(\n            \"pages\" => $pages,\n            \"catalogs\" => $catalogs,\n        );\n        unset($pages);\n        unset($catalogs);\n        return $menu;\n    }\n\n    //获取某个目录下的页面和子目录\n    private function _getCat($catalog_data, &$all_pages, &$all_catalogs)\n    {\n        $catalog_data['pages'] = $this->_getPageByCatId($catalog_data['cat_id'], $all_pages);\n        //该目录下的所有子目录\n        $sub_catalogs =  $this->_getCatByCatId($catalog_data['cat_id'], $all_catalogs);\n        if ($sub_catalogs) {\n            foreach ($sub_catalogs as $key => $value) {\n                $catalog_data['catalogs'][] = $this->_getCat($value, $all_pages, $all_catalogs);\n            }\n        }\n        if (!$catalog_data['catalogs']) {\n            $catalog_data['catalogs'] = array();\n        }\n        return $catalog_data;\n    }\n\n\n    //获取某个目录下的所有页面\n    private function _getPageByCatId($cat_id, $all_pages)\n    {\n        $pages = array();\n        if ($all_pages) {\n            foreach ($all_pages as $key => $value) {\n                if ($value['cat_id'] == $cat_id) {\n                    $pages[] = $value;\n                }\n            }\n        }\n        return $pages;\n    }\n\n    //获取某个目录下的页面和子目录\n    public function getCat($catalog_data,  &$all_pages, &$all_catalogs)\n    {\n        return $this->_getCat($catalog_data,  $all_pages, $all_catalogs);\n    }\n\n    //获取某个目录下的所有子目录\n    private function _getCatByCatId($cat_id, $all_catalogs)\n    {\n        $cats = array();\n        if ($all_catalogs) {\n            foreach ($all_catalogs as $key => $value) {\n                if ($value['parent_cat_id'] == $cat_id) {\n                    $cats[] = $value;\n                }\n            }\n        }\n        return $cats;\n    }\n\n\n    //删除项目\n    public function delete_item($item_id)\n    {\n        $item_id = intval($item_id);\n        D(\"Page\")->where(array('item_id' => $item_id))->delete();\n        D(\"Page\")->where(array('item_id' => $item_id))->delete();\n        D(\"Catalog\")->where(array('item_id' => $item_id))->delete();\n        D(\"PageHistory\")->where(array('item_id' => $item_id))->delete();\n        D(\"ItemMember\")->where(array('item_id' => $item_id))->delete();\n        D(\"TeamItem\")->where(array('item_id' => $item_id))->delete();\n        D(\"TeamItemMember\")->where(array('item_id' => $item_id))->delete();\n        return D(\"Item\")->where(array('item_id' => $item_id))->delete();\n    }\n\n    //软删除项目\n    public function soft_delete_item($item_id)\n    {\n        $item_id = intval($item_id);\n        return $this->where(array('item_id' => $item_id))->save(array(\"is_del\" => 1, \"last_update_time\" => time()));\n    }\n\n    private function _htmlspecialchars($str)\n    {\n        if (!$str) {\n            return '';\n        }\n        //之所以先htmlspecialchars_decode是为了防止被htmlspecialchars转义了两次\n        return htmlspecialchars(htmlspecialchars_decode($str));\n    }\n\n\n    //根据用户目录权限来过滤项目数据\n    public function filteMemberItem($uid, $item_id, $menuData)\n    {\n        if (!$menuData || !$menuData['catalogs']) {\n            return $menuData;\n        }\n        $uid = intval($uid);\n        $item_id = intval($item_id);\n        // 支持多目录：优先个人成员，其次团队成员\n        $cat_ids = D('Member')->getCatIds($item_id, $uid);\n        if (!empty($cat_ids)) {\n            $allowed = array_flip(array_map('intval', $cat_ids));\n            foreach ($menuData['catalogs'] as $key => $value) {\n                if (!isset($allowed[intval($value['cat_id'])])) {\n                    unset($menuData['catalogs'][$key]);\n                }\n            }\n            $menuData['catalogs'] = array_values($menuData['catalogs']);\n        }\n\n        return $menuData;\n    }\n\n\n    // 把目录嵌套的项目页面数据平摊为目录路径（比如说‘目录/子目录1/子目录2’）的形式\n    public function toItemPageCatPath($catalogs, $parent_cat_name = '')\n    {\n        if (!$catalogs) return false;\n        $return_array = array();\n\n        if (!$catalogs) {\n            return;\n        }\n        $cat_id = 0;\n        foreach ($catalogs as $key => $value) {\n            $cat_name = $value['cat_name'];\n            if ($parent_cat_name) {\n                $cat_path =  $parent_cat_name . '/' . $cat_name;\n            } else {\n                $cat_path =  $cat_name;\n            }\n\n\n            //该目录下的页面们\n            if ($value['pages']) {\n                foreach ($value['pages'] as $key2 => $value2) {\n                    $value2['cat_path'] = $cat_path;\n                    unset($value2['cat_name']);\n                    unset($value2['level']);\n                    // unset($value2['page_content']);\n                    $return_array[] = $value2;\n                }\n            }\n\n            //该目录的子目录\n            if ($value['catalogs']) {\n                $sub_array = $this->toItemPageCatPath($value['catalogs'], $cat_path);\n                $return_array = array_merge($return_array, $sub_array);\n            }\n        }\n\n        return $return_array;\n    }\n}\n"
  },
  {
    "path": "server/Application/Api/Model/ItemTokenModel.class.php",
    "content": "<?php\n\nnamespace Api\\Model;\n\nuse Api\\Model\\BaseModel;\n\n/**\n * \n * @author star7th      \n */\nclass ItemTokenModel extends BaseModel\n{\n\n\tpublic function createToken($item_id)\n\t{\n\t\t$api_key = get_rand_str() . rand();\n\t\t$api_token = get_rand_str() . rand();\n\t\t$data['item_id'] = $item_id;\n\t\t$data['api_key'] = $api_key;\n\t\t$data['api_token'] = $api_token;\n\t\t$data['addtime'] = time();\n\t\t$ret = $this->add($data);\n\t\tif ($ret) {\n\t\t\treturn $ret;\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic function getTokenByItemId($item_id)\n\t{\n\t\t$item_id = intval($item_id);\n\t\t$item_token = $this->where(array('item_id' => $item_id))->find();\n\t\tif (!$item_token) {\n\t\t\t$this->createToken($item_id);\n\t\t\t$item_token = $this->where(array('item_id' => $item_id))->find();\n\t\t}\n\t\treturn $item_token;\n\t}\n\n\tpublic function getTokenByKey($api_key)\n\t{\n\t\t$item_token = $this->where(\"api_key='%s'\", array($api_key))->find();\n\t\treturn $item_token;\n\t}\n\n\tpublic function setLastTime($item_id)\n\t{\n\t\t$item_id = intval($item_id);\n\t\treturn $this->where(array('item_id' => $item_id))->save(array(\"last_check_time\" => time()));\n\t}\n\n\t//检查token。如果检测通过则返回item_id\n\tpublic function check($api_key, $api_token, $no = '')\n\t{\n\t\t$ret = $this->getTokenByKey($api_key);\n\t\tif ($ret && $ret['api_token'] == $api_token) {\n\t\t\t$item_id = $ret['item_id'];\n\t\t\t$this->setLastTime($item_id);\n\t\t\treturn $item_id;\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tpublic function resetToken($item_id)\n\t{\n\t\t$item_id = intval($item_id);\n\t\t$item_token = $this->where(array('item_id' => $item_id))->find();\n\t\tif (!$item_token) {\n\t\t\t$this->createToken($item_id);\n\t\t\tsleep(1);\n\t\t\t$item_token = $this->where(array('item_id' => $item_id))->find();\n\t\t}\n\t\t$item_token['api_token'] = get_rand_str() . rand();\n\t\t$this->where(array('item_id' => $item_id))->save(array(\n\t\t\t\"api_token\" => $item_token['api_token']\n\t\t));\n\t\treturn $item_token;\n\t}\n}\n"
  },
  {
    "path": "server/Application/Api/Model/MemberModel.class.php",
    "content": "<?php\n\nnamespace Api\\Model;\n\nuse Api\\Model\\BaseModel;\n\nclass MemberModel extends BaseModel\n{\n    protected $autoCheckFields = false;  //一定要关闭字段缓存，不然会报找不到表的错误\n\n    // 获取用户在某项目下拥有权限的目录id集合（仅根目录下一层）。优先个人成员，其次团队成员\n    public function getCatIds($item_id, $uid)\n    {\n        $item_id = intval($item_id);\n        $uid = intval($uid);\n        $ids = array();\n\n        // 优先个人成员\n        $row1 = D(\"ItemMember\")->where(\" item_id = '%d' and uid = '%d' \", array($item_id, $uid))->field('cat_id,cat_ids')->find();\n        if ($row1 && !empty($row1['cat_ids'])) {\n            $str = (string)$row1['cat_ids'];\n            if (strpos($str, ',') !== false) {\n                $ids = preg_split('/\\s*,\\s*/', trim($str));\n            } else if (ctype_digit($str)) {\n                $ids = array(intval($str));\n            }\n        }\n        if (empty($ids) && $row1 && intval($row1['cat_id']) > 0) {\n            $ids[] = intval($row1['cat_id']);\n        }\n\n        // 其次团队成员（当个人没有指定目录时）\n        if (empty($ids)) {\n            $row2 = D(\"TeamItemMember\")->where(\" item_id = '%d' and member_uid = '%d' \", array($item_id, $uid))->field('cat_id,cat_ids')->find();\n            if ($row2 && !empty($row2['cat_ids'])) {\n                $str = (string)$row2['cat_ids'];\n                if (strpos($str, ',') !== false) {\n                    $ids = preg_split('/\\s*,\\s*/', trim($str));\n                } else if (ctype_digit($str)) {\n                    $ids = array(intval($str));\n                }\n            }\n            if (empty($ids) && $row2 && intval($row2['cat_id']) > 0) {\n                $ids[] = intval($row2['cat_id']);\n            }\n        }\n\n        // 去重并返回\n        $ids = array_values(array_unique(array_filter(array_map('intval', $ids))));\n        return $ids;\n    }\n\n    // 兼容旧接口：返回单个目录id（取第一个），无则返回0\n    public function getCatId($item_id, $uid)\n    {\n        $ids = $this->getCatIds($item_id, $uid);\n        if (!empty($ids)) {\n            return intval($ids[0]);\n        }\n        return 0;\n    }\n}\n"
  },
  {
    "path": "server/Application/Api/Model/MessageContentModel.class.php",
    "content": "<?php\n\nnamespace Api\\Model;\n\nuse Api\\Model\\BaseModel;\n\n/**\n * \n * @author star7th      \n */\nclass MessageContentModel extends BaseModel\n{\n}\n"
  },
  {
    "path": "server/Application/Api/Model/MessageModel.class.php",
    "content": "<?php\n\nnamespace Api\\Model;\n\nuse Api\\Model\\BaseModel;\n\n/**\n * \n * @author star7th      \n */\nclass MessageModel extends BaseModel\n{\n\n\tpublic function getRemindList($to_uid, $page = 1, $count = 15, $status = -2)\n\t{\n\t\t$to_uid = intval($to_uid);\n\t\t$page = intval($page);\n\t\t$count = intval($count);\n\t\t$map = array('to_uid' => $to_uid, 'message_type' => 'remind');\n\t\tif ($status > -2) {\n\t\t\t$map['status'] = intval($status);\n\t\t}\n\t\t$list = $this->where($map)->order(\" id desc \")->page(\" $page , $count \")->select();\n\t\t$total = $this->where($map)->count();\n\t\tif ($list) {\n\t\t\tforeach ($list as $key => $value) {\n\t\t\t\t$list[$key] = $this->renderOne($value);\n\t\t\t}\n\t\t}\n\n\t\t$return = array(\n\t\t\t\"total\" => (int)$total,\n\t\t\t\"list\" => (array)$list,\n\t\t);\n\n\t\treturn $return;\n\t}\n\n\t// 一行一行来\n\tpublic function renderOne($one)\n\t{\n\t\t$message_content_id = intval($one['message_content_id']);\n\t\t$message_content_array = D(\"MessageContent\")->where(array('id' => $message_content_id))->find();\n\t\t$one['object_type'] = $message_content_array['object_type'];\n\t\t$one['object_id'] = $message_content_array['object_id'];\n\t\t$one['action_type'] = $message_content_array['action_type'];\n\t\t$one['message_content'] = $message_content_array['message_content'];\n\t\t$one['from_name'] = $message_content_array['from_name'];\n\t\tif ($one['object_type'] == 'page') {\n\t\t\t$page_id = intval($one['object_id']);\n\t\t\t$array1 = M(\"Page\")->where(array('page_id' => $page_id))->find();\n\t\t\tunset($array1['page_content']);\n\t\t\t$one['page_data'] = $array1;\n\t\t}\n\t\treturn $one;\n\t}\n\n\t// 添加消息\n\tpublic function addMsg($from_uid, $from_name, $to_uid,  $message_type, $message_content, $action_type, $object_type, $object_id)\n\t{\n\t\t$message_content_id = D(\"MessageContent\")->add(array(\n\t\t\t\"from_uid\" => $from_uid,\n\t\t\t\"from_name\" => $from_name,\n\t\t\t\"message_type\" => $message_type,\n\t\t\t\"message_content\" => $message_content,\n\t\t\t\"action_type\" => $action_type,\n\t\t\t\"object_type\" => $object_type,\n\t\t\t\"object_id\" => $object_id,\n\t\t\t\"addtime\" => date(\"Y-m-d H:i:s\"),\n\t\t));\n\t\t$ret = $this->add(array(\n\t\t\t\"from_uid\" => $from_uid,\n\t\t\t\"to_uid\" => $to_uid,\n\t\t\t\"message_type\" => $message_type,\n\t\t\t\"message_content_id\" => $message_content_id,\n\t\t\t\"status\" => '0',\n\t\t\t\"addtime\" => date(\"Y-m-d H:i:s\"),\n\t\t\t\"readtime\" => date(\"Y-m-d H:i:s\"),\n\t\t));\n\n\t\t// 检查用户是否设置了推送地址，如果有则发送微信推送\n\t\t$push_url = D(\"UserSetting\")->getPushUrl($to_uid);\n\t\tif ($push_url) {\n\t\t\t// 构建标题和内容\n\t\t\t$title = $from_name . \"给您发送了一条消息\";\n\t\t\t$content = $message_content;\n\t\t\tif ($object_type == 'page') {\n\t\t\t\t$page_id = intval($object_id);\n\t\t\t\t$page = M(\"Page\")->where(array('page_id' => $page_id))->find();\n\t\t\t\tif ($page) {\n\t\t\t\t\t$title = \"页面更新提醒\";\n\t\t\t\t\t$content = $from_name . \"修改了页面 《\" . $page['page_title'] . \"》, 修改备注：\" . $message_content . \"。详情请登录showdoc查看\";\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// 发送HTTP请求到用户设置的推送地址\n\t\t\t$this->sendPushNotification($push_url, $title, $content);\n\t\t}\n\n\t\treturn $ret;\n\t}\n\n\t/**\n\t * 发送推送通知\n\t * @param string $push_url 推送地址\n\t * @param string $title 消息标题\n\t * @param string $content 消息内容\n\t * @return boolean\n\t */\n\tprivate function sendPushNotification($push_url, $title, $content)\n\t{\n\t\ttry {\n\t\t\t$params = array(\n\t\t\t\t'title' => $title,\n\t\t\t\t'content' => $content\n\t\t\t);\n\t\t\t\n\t\t\t// 使用cURL发送请求\n\t\t\t$ch = curl_init();\n\t\t\tcurl_setopt($ch, CURLOPT_URL, $push_url);\n\t\t\tcurl_setopt($ch, CURLOPT_POST, 1);\n\t\t\tcurl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params));\n\t\t\tcurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n\t\t\tcurl_setopt($ch, CURLOPT_TIMEOUT, 10); // 设置超时时间为10秒\n\t\t\t$response = curl_exec($ch);\n\t\t\tcurl_close($ch);\n\t\t\t\n\t\t\treturn true;\n\t\t} catch (\\Exception $e) {\n\t\t\t// 记录错误，但不影响正常业务流程\n\t\t\treturn false;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "server/Application/Api/Model/OptionsModel.class.php",
    "content": "<?php\n\nnamespace Api\\Model;\n\nuse Api\\Model\\BaseModel;\n\nclass OptionsModel extends BaseModel\n{\n\n    //\n    public function get($option_name)\n    {\n        $res = $this->where(\" option_name = '%s' \", array($option_name))->find();\n        if ($res) {\n            return $res['option_value'];\n        }\n        return false;\n    }\n\n    //\n    public function set($option_name, $option_value)\n    {\n        $return = M('options')->add(array(\n            \"option_name\" => $option_name,\n            \"option_value\" => $option_value,\n        ), NULL, true);\n        return $return;\n    }\n}\n"
  },
  {
    "path": "server/Application/Api/Model/PageModel.class.php",
    "content": "<?php\n\nnamespace Api\\Model;\n\nuse Api\\Model\\BaseModel;\n\n/**\n * \n * @author star7th      \n */\nclass PageModel extends BaseModel\n{\n\n\n  //搜索某个项目下的页面\n  public function search($item_id,$cat_id_or_ids = 0 , $keyword = \"\")\n  {\n    $return_pages = array();\n    $item = D(\"Item\")->where(\"item_id = '%d' and is_del = 0 \", array($item_id))->find();\n    $map = array('item_id' => intval($item_id), 'is_del' => 0);\n    if (is_array($cat_id_or_ids)) {\n      $ids = array();\n      foreach ($cat_id_or_ids as $id) {\n        $id = intval($id);\n        if ($id > 0) $ids[] = $id;\n      }\n      if (!empty($ids)) {\n        $map['cat_id'] = array('in', $ids);\n      }\n    } else {\n      $cat_id = intval($cat_id_or_ids);\n      if ($cat_id > 0) {\n        $map['cat_id'] = $cat_id;\n      }\n    }\n    $pages = $this->where($map)->order(\" s_number asc  \")->select();\n    if (!empty($pages)) {\n      foreach ($pages as $key => &$value) {\n        $page_content = $value['page_content'];\n        if (strpos(strtolower($item['item_name'] . \"-\" . $value['page_title'] . \"  \" . $page_content), strtolower($keyword)) !== false) {\n          $value['page_content'] = $page_content;\n          $return_pages[] = $value;\n        }\n      }\n    }\n    unset($pages);\n    return $return_pages;\n  }\n\n  //根据标题更新页面\n  //其中cat_name参数特别说明下,传递各格式如 '二级目录/三级目录/四级目录'\n  public function update_by_title($item_id, $page_title, $page_content, $cat_name = '', $s_number = 99, $author_uid = 0, $author_username = 'update_by_title')\n  {\n    $item_id = intval($item_id);\n    $s_number = intval($s_number);\n    if (!$item_id) {\n      return false;\n    }\n\n    $cat_id = 0;\n    if ($cat_name) {\n      // 用路径的形式（比如'二级目录/三级目录/四级目录'）来保存目录信息并返回最后一层目录的id\n      $cat_id = D(\"Catalog\")->saveCatPath($cat_name, $item_id);\n    }\n\n    $this->cat_name_id[$cat_name] = $cat_id;\n\n    if ($page_content) {\n      $page_array = D(\"Page\")->field(\"page_id\")->where(\" item_id = '%d' and is_del = 0  and cat_id = '%d'  and page_title ='%s' \", array($item_id, $cat_id, $page_title))->find();\n      //如果不存在则新建\n      if (!$page_array) {\n        $add_data = array(\n          \"author_uid\" => $author_uid,\n          \"author_username\" => $author_username,\n          \"item_id\" => $item_id,\n          \"cat_id\" => $cat_id,\n          \"page_title\" => $this->_htmlspecialchars($page_title),\n          \"page_content\" => $this->_htmlspecialchars($page_content),\n          \"s_number\" => $s_number,\n          \"addtime\" => time(),\n        );\n        $page_id = D(\"Page\")->add($add_data);\n      } else {\n        $page_id = $page_array['page_id'];\n        $update_data = array(\n          \"author_uid\" => $author_uid,\n          \"author_username\" => $author_username,\n          \"item_id\" => $item_id,\n          \"cat_id\" => $cat_id,\n          \"page_title\" => $this->_htmlspecialchars($page_title),\n          \"page_content\" => $this->_htmlspecialchars($page_content),\n          \"s_number\" => $s_number,\n        );\n        D(\"Page\")->where(array('page_id' => $page_id))->save($update_data);\n      }\n    }\n\n    return $page_id;\n  }\n\n  //软删除页面\n  public function softDeletePage($page_id)\n  {\n    $page_id = intval($page_id);\n    //放入回收站\n    $login_user = session('login_user');\n    $page = D(\"Page\")->field(\"item_id,page_title\")->where(array('page_id' => $page_id))->find();\n    D(\"Recycle\")->add(array(\n      \"item_id\" => $page['item_id'],\n      \"page_id\" => $page_id,\n      \"page_title\" => $page['page_title'],\n      \"del_by_uid\" => $login_user['uid'],\n      \"del_by_username\" => $login_user['username'],\n      \"del_time\" => time()\n    ));\n    $ret = M(\"Page\")->where(array('page_id' => $page_id))->save(array(\"is_del\" => 1, \"addtime\" => time()));\n    return $ret;\n  }\n\n  //删除页面\n  public function deletePage($page_id)\n  {\n    $page_id = intval($page_id);\n    $ret = M(\"Page\")->where(array('page_id' => $page_id))->delete();\n    return $ret;\n  }\n\n  public function deleteFile($file_id)\n  {\n    $file_id = intval($file_id);\n    return D(\"Attachment\")->deleteFile($file_id);\n  }\n\n  private function _htmlspecialchars($str)\n  {\n    if (!$str) {\n      return '';\n    }\n    //之所以先htmlspecialchars_decode是为了防止被htmlspecialchars转义了两次\n    return htmlspecialchars(htmlspecialchars_decode($str));\n  }\n}\n"
  },
  {
    "path": "server/Application/Api/Model/RunapiDbConfigModel.class.php",
    "content": "<?php\n\nnamespace Api\\Model;\n\nuse Think\\Model;\n\nclass RunapiDbConfigModel extends Model\n{\n    /**\n     * 数据表名\n     *\n     * @var string\n     */\n    protected $tableName = 'runapi_db_config';\n}\n\n"
  },
  {
    "path": "server/Application/Api/Model/RunapiModel.class.php",
    "content": "<?php\n\nnamespace Api\\Model;\n\nuse Api\\Model\\BaseModel;\n\n/**\n * \n * @author star7th      \n */\nclass RunapiModel\n{\n\n  protected $autoCheckFields = false;\n\n  //获取全局参数\n  public function getGlobalParam($item_id)\n  {\n    $item_id = intval($item_id);\n    $return = array(\n      'query' => array(),\n      'body' => array(),\n      'header' => array(),\n      'cookies' => array(),\n      'preScript' => '',\n      'postScript' => '',\n    );\n\n    $res = D(\"RunapiGlobalParam\")->where(array('param_type' => 'query', 'item_id' => $item_id))->find();\n    if ($res) {\n      $return['query'] = json_decode(htmlspecialchars_decode($res['content_json_str']), true);\n      $return['query'] = $return['query'] ? $return['query'] : array();\n    } else {\n      D(\"RunapiGlobalParam\")->add(array(\n        \"param_type\" => \"query\",\n        \"item_id\" => $item_id,\n        \"content_json_str\" => '[]',\n        \"addtime\" => date(\"Y-m-d H:i:s\"),\n        \"last_update_time\" => date(\"Y-m-d H:i:s\"),\n      ));\n    }\n    $res = D(\"RunapiGlobalParam\")->where(array('param_type' => 'body', 'item_id' => $item_id))->find();\n    if ($res) {\n      $return['body'] = json_decode(htmlspecialchars_decode($res['content_json_str']), true);\n      $return['body'] = $return['body'] ? $return['body'] : array();\n    } else {\n      D(\"RunapiGlobalParam\")->add(array(\n        \"param_type\" => \"body\",\n        \"item_id\" => $item_id,\n        \"content_json_str\" => '[]',\n        \"addtime\" => date(\"Y-m-d H:i:s\"),\n        \"last_update_time\" => date(\"Y-m-d H:i:s\"),\n      ));\n    }\n    $res = D(\"RunapiGlobalParam\")->where(array('param_type' => 'header', 'item_id' => $item_id))->find();\n    if ($res) {\n      $return['header'] = json_decode(htmlspecialchars_decode($res['content_json_str']), true);\n      $return['header'] = $return['header'] ? $return['header'] : array();\n    } else {\n      D(\"RunapiGlobalParam\")->add(array(\n        \"param_type\" => \"header\",\n        \"item_id\" => $item_id,\n        \"content_json_str\" => '[]',\n        \"addtime\" => date(\"Y-m-d H:i:s\"),\n        \"last_update_time\" => date(\"Y-m-d H:i:s\"),\n      ));\n    }\n    $res = D(\"RunapiGlobalParam\")->where(array('param_type' => 'cookies', 'item_id' => $item_id))->find();\n    if ($res) {\n      $return['cookies'] = json_decode(htmlspecialchars_decode($res['content_json_str']), true);\n      $return['cookies'] = $return['cookies'] ? $return['cookies'] : array();\n    } else {\n      D(\"RunapiGlobalParam\")->add(array(\n        \"param_type\" => \"cookies\",\n        \"item_id\" => $item_id,\n        \"content_json_str\" => '[]',\n        \"addtime\" => date(\"Y-m-d H:i:s\"),\n        \"last_update_time\" => date(\"Y-m-d H:i:s\"),\n      ));\n    }\n    $res = D(\"RunapiGlobalParam\")->where(array('param_type' => 'preScript', 'item_id' => $item_id))->find();\n    if ($res) {\n      $return['preScript'] =  htmlspecialchars_decode($res['content_json_str']);\n      $return['preScript'] = $return['preScript'] ? $return['preScript'] : '';\n    } else {\n      D(\"RunapiGlobalParam\")->add(array(\n        \"param_type\" => \"preScript\",\n        \"item_id\" => $item_id,\n        \"content_json_str\" => '',\n        \"addtime\" => date(\"Y-m-d H:i:s\"),\n        \"last_update_time\" => date(\"Y-m-d H:i:s\"),\n      ));\n    }\n    $res = D(\"RunapiGlobalParam\")->where(array('param_type' => 'postScript', 'item_id' => $item_id))->find();\n    if ($res) {\n      $return['postScript'] =  htmlspecialchars_decode($res['content_json_str']);\n      $return['postScript'] = $return['postScript'] ? $return['postScript'] : '';\n    } else {\n      D(\"RunapiGlobalParam\")->add(array(\n        \"param_type\" => \"postScript\",\n        \"item_id\" => $item_id,\n        \"content_json_str\" => '',\n        \"addtime\" => date(\"Y-m-d H:i:s\"),\n        \"last_update_time\" => date(\"Y-m-d H:i:s\"),\n      ));\n    }\n    return $return;\n  }\n}\n"
  },
  {
    "path": "server/Application/Api/Model/SubscriptionModel.class.php",
    "content": "<?php\n\nnamespace Api\\Model;\n\nuse Api\\Model\\BaseModel;\n\n/**\n * \n * @author star7th      \n */\nclass SubscriptionModel extends BaseModel\n{\n\n  public function addSub($uid, $object_id, $object_type, $action_type)\n  {\n\n    $uid = intval($uid);\n    $object_id = intval($object_id);\n    // 检测是否已经存在订阅了（数组条件优先）\n    $res = $this->where(array(\n      'uid' => $uid,\n      'object_id' => $object_id,\n      'object_type' => $object_type,\n      'action_type' => $action_type\n    ))->find();\n    if (!$res) {\n      $res = $this->add(array(\n        \"uid\" => $uid,\n        \"object_id\" => $object_id,\n        \"object_type\" => $object_type,\n        \"action_type\" => $action_type,\n        \"sub_time\" => date(\"Y-m-d H:i:s\")\n      ));\n    }\n    return $res;\n  }\n\n  public function deleteSub($uid, $object_id, $object_type, $action_type)\n  {\n    $uid = intval($uid);\n    $object_id = intval($object_id);\n    // 删除订阅（数组条件优先）\n    $res = $this->where(array(\n      'uid' => $uid,\n      'object_id' => $object_id,\n      'object_type' => $object_type,\n      'action_type' => $action_type\n    ))->delete();\n    return $res;\n  }\n\n  public function getListByObjectId($object_id, $object_type, $action_type)\n  {\n\n    $object_id = intval($object_id);\n    return $this->where(array(\n      'object_id' => $object_id,\n      'object_type' => $object_type,\n      'action_type' => $action_type\n    ))->select();\n  }\n}\n"
  },
  {
    "path": "server/Application/Api/Model/UpdateModel.class.php",
    "content": "<?php\n\nnamespace Api\\Model;\n\nuse Api\\Model\\BaseModel;\n\n/**\n * \n * @author star7th      \n */\nclass UpdateModel\n{\n\n    protected $autoCheckFields = false;  //一定要关闭字段缓存，不然会报找不到表的错误\n\n    //检测数据库并更新\n    public function checkDb()\n    {\n        $version_num = 27;\n        $db_version_num = D(\"Options\")->get(\"db_version_num\");\n        if (!$db_version_num || $db_version_num < $version_num) {\n            $r = $this->updateSqlite();\n            if ($r) {\n                D(\"Options\")->set(\"db_version_num\", $version_num);\n            }\n            //echo '执行数据库升级';\n        }\n    }\n\n    public function updateSqlite()\n    {\n        //catalog表增加parent_cat_id字段\n        if (!$this->_is_column_exist(\"catalog\", \"parent_cat_id\")) {\n            $sql = \"ALTER TABLE \" . C('DB_PREFIX') . \"catalog ADD parent_cat_id INT( 10 ) NOT NULL DEFAULT '0' ;\";\n            D(\"catalog\")->execute($sql);\n        }\n\n        //catalog表增加level字段\n        if (!$this->_is_column_exist(\"catalog\", \"level\")) {\n            $sql = \"ALTER TABLE \" . C('DB_PREFIX') . \"catalog ADD level INT( 10 ) NOT NULL DEFAULT '2'  ;\";\n            D(\"catalog\")->execute($sql);\n        }\n\n\n        //item表增加item_domain字段\n        if (!$this->_is_column_exist(\"item\", \"item_domain\")) {\n            $sql = \"ALTER TABLE \" . C('DB_PREFIX') . \"item ADD item_domain text NOT NULL DEFAULT '';\";\n            D(\"catalog\")->execute($sql);\n        }\n\n        //创建user_token表\n        $sql = \"CREATE TABLE IF NOT EXISTS `user_token` (\n        `id`  INTEGER PRIMARY KEY ,\n        `uid` int(10) NOT NULL DEFAULT '0',\n        `token` CHAR(200) NOT NULL DEFAULT '',\n        `token_expire` int(11) NOT NULL DEFAULT '0' ,\n        `ip` CHAR(200) NOT NULL DEFAULT '',\n        `addtime` int(11) NOT NULL DEFAULT '0'\n        )\";\n        D(\"UserToken\")->execute($sql);\n\n        //创建template表\n        $sql = \"CREATE TABLE IF NOT EXISTS `template` (\n        `id`  INTEGER PRIMARY KEY ,\n        `uid` int(10) NOT NULL DEFAULT '0',\n        `username` CHAR(200) NOT NULL DEFAULT '',\n        `template_title` CHAR(200) NOT NULL DEFAULT '' ,\n        `template_content` text NOT NULL DEFAULT '',\n        `addtime` int(11) NOT NULL DEFAULT '0'\n        )\";\n        D(\"UserToken\")->execute($sql);\n\n        //page表增加page_comments字段\n        if (!$this->_is_column_exist(\"page\", \"page_comments\")) {\n            $sql = \"ALTER TABLE \" . C('DB_PREFIX') . \"page ADD page_comments text NOT NULL DEFAULT ''  ;\";\n            D(\"catalog\")->execute($sql);\n        }\n\n\n        //page_history 表增加page_comments字段\n        if (!$this->_is_column_exist(\"PageHistory\", \"page_comments\")) {\n            $sql = \"ALTER TABLE \" . C('DB_PREFIX') . \"page_history ADD page_comments text NOT NULL DEFAULT '';\";\n            D(\"catalog\")->execute($sql);\n        }\n\n\n        //item_member表增加member_group_id字段\n        if (!$this->_is_column_exist(\"ItemMember\", \"member_group_id\")) {\n            $sql = \"ALTER TABLE \" . C('DB_PREFIX') . \"item_member ADD member_group_id INT( 1 ) NOT NULL DEFAULT '1'  ;\";\n            D(\"ItemMember\")->execute($sql);\n        }\n\n\n        //item表增加item_type字段\n        if (!$this->_is_column_exist(\"Item\", \"item_type\")) {\n            $sql = \"ALTER TABLE \" . C('DB_PREFIX') . \"item ADD item_type INT( 1 ) NOT NULL DEFAULT '1'  ;\";\n            D(\"ItemMember\")->execute($sql);\n        }\n\n        //创建options表\n        $sql = \"CREATE TABLE IF NOT EXISTS `options` (\n        `option_id`  INTEGER PRIMARY KEY ,\n        `option_name` CHAR(200) NOT NULL UNIQUE ,\n        `option_value` CHAR(200) NOT NULL \n        )\";\n        D(\"UserToken\")->execute($sql);\n\n        //创建item_token表\n        $sql = \"CREATE TABLE IF NOT EXISTS `item_token` (\n        `id`  INTEGER PRIMARY KEY ,\n        `item_id` int(11) NOT NULL DEFAULT '0' ,\n        `api_key` CHAR(200) NOT NULL UNIQUE ,\n        `api_token` CHAR(200) NOT NULL ,\n        `addtime` int(11) NOT NULL DEFAULT '0' ,\n        `last_check_time` int(11) NOT NULL DEFAULT '0' \n        )\";\n        D(\"UserToken\")->execute($sql);\n\n        //创建item_top表\n        $sql = \"CREATE TABLE IF NOT EXISTS `item_top` (\n        `id`  INTEGER PRIMARY KEY ,\n        `item_id` int(11) NOT NULL DEFAULT '0' ,\n        `uid` int(11) NOT NULL DEFAULT '0' ,\n        `addtime` int(11) NOT NULL DEFAULT '0' \n        )\";\n        D(\"UserToken\")->execute($sql);\n\n        //item表增加is_archived字段\n        if (!$this->_is_column_exist(\"Item\", \"is_archived\")) {\n            $sql = \"ALTER TABLE \" . C('DB_PREFIX') . \"item ADD is_archived INT( 1 ) NOT NULL DEFAULT '0'  ;\";\n            D(\"ItemMember\")->execute($sql);\n        }\n\n\n        //管理员账户和权限\n        if (D(\"User\")->where(\"username = 'showdoc' \")->find()) {\n            D(\"User\")->where(\"username = 'showdoc' \")->save(array(\"groupid\" => 1));\n        } else {\n            D(\"User\")->add(array('username' => \"showdoc\", \"groupid\" => 1, 'password' => \"a89da13684490eb9ec9e613f91d24d00\", 'reg_time' => time()));\n        }\n\n        //item表增加is_del字段\n        if (!$this->_is_column_exist(\"Item\", \"is_del\")) {\n            $sql = \"ALTER TABLE \" . C('DB_PREFIX') . \"item ADD is_del INT( 1 ) NOT NULL DEFAULT '0'  ;\";\n            D(\"ItemMember\")->execute($sql);\n        }\n\n        //page表增加is_del字段\n        if (!$this->_is_column_exist(\"Page\", \"is_del\")) {\n            $sql = \"ALTER TABLE \" . C('DB_PREFIX') . \"page ADD is_del INT( 1 ) NOT NULL DEFAULT '0'  ;\";\n            D(\"ItemMember\")->execute($sql);\n        }\n\n        //page表增加page_addtime字段\n        if (!$this->_is_column_exist(\"Page\", \"page_addtime\")) {\n            $sql = \"ALTER TABLE \" . C('DB_PREFIX') . \"page ADD page_addtime INT( 11 ) NOT NULL DEFAULT '0'  ;\";\n            D(\"Page\")->execute($sql);\n        }\n\n        //创建team表\n        $sql = \"CREATE TABLE IF NOT EXISTS `team` (\n        `id`  INTEGER PRIMARY KEY ,\n        `team_name` CHAR(200) NOT NULL DEFAULT '',\n        `uid` int(11) NOT NULL DEFAULT '0' ,\n        `username` CHAR(200) NOT NULL DEFAULT '',\n        `addtime` int(11) NOT NULL DEFAULT '0' ,\n        `last_update_time` int(11) NOT NULL DEFAULT '0' \n        )\";\n        D(\"User\")->execute($sql);\n\n        //创建team_item表\n        $sql = \"CREATE TABLE IF NOT EXISTS `team_item` (\n        `id`  INTEGER PRIMARY KEY ,\n        `team_id` int(11) NOT NULL DEFAULT '0' ,\n        `item_id` int(11) NOT NULL DEFAULT '0' ,\n        `addtime` int(11) NOT NULL DEFAULT '0' ,\n        `last_update_time` int(11) NOT NULL DEFAULT '0' \n        )\";\n        D(\"User\")->execute($sql);\n\n        //创建team_item_member表\n        $sql = \"CREATE TABLE IF NOT EXISTS `team_item_member` (\n        `id`  INTEGER PRIMARY KEY ,\n        `team_id` int(11) NOT NULL DEFAULT '0' ,\n        `item_id` int(11) NOT NULL DEFAULT '0' ,\n        `member_group_id` int(11) NOT NULL DEFAULT '0' ,\n        `member_uid` int(11) NOT NULL DEFAULT '0' ,\n        `member_username` CHAR(200) NOT NULL DEFAULT '',\n        `addtime` int(11) NOT NULL DEFAULT '0' ,\n        `last_update_time` int(11) NOT NULL DEFAULT '0' \n        )\";\n        D(\"User\")->execute($sql);\n\n        //创建team_member表\n        $sql = \"CREATE TABLE IF NOT EXISTS `team_member` (\n        `id`  INTEGER PRIMARY KEY ,\n        `team_id` int(11) NOT NULL DEFAULT '0' ,\n        `member_uid` int(11) NOT NULL DEFAULT '0' ,\n        `member_username` CHAR(200) NOT NULL DEFAULT '',\n        `addtime` int(11) NOT NULL DEFAULT '0' ,\n        `last_update_time` int(11) NOT NULL DEFAULT '0' \n        )\";\n        D(\"User\")->execute($sql);\n\n        //创建upload_file表\n        $sql = \"CREATE TABLE IF NOT EXISTS `upload_file` (\n        `file_id`  INTEGER PRIMARY KEY ,\n        `sign` CHAR(200) NOT NULL DEFAULT '',\n        `display_name` CHAR(200) NOT NULL DEFAULT '',\n        `file_type` CHAR(200) NOT NULL DEFAULT '',\n        `file_size` CHAR(200) NOT NULL DEFAULT '',\n        `uid` int(11) NOT NULL DEFAULT '0' ,\n        `page_id` int(11) NOT NULL DEFAULT '0' ,\n        `item_id` int(11) NOT NULL DEFAULT '0' ,\n        `visit_times` int(11) NOT NULL DEFAULT '0' ,\n        `addtime` int(11) NOT NULL DEFAULT '0' ,\n        `real_url` CHAR(200) NOT NULL DEFAULT '',\n        `last_update_time` int(11) NOT NULL DEFAULT '0' \n        )\";\n        D(\"User\")->execute($sql);\n\n        //创建item_sort表\n        $sql = \"CREATE TABLE IF NOT EXISTS `item_sort` (\n        `id`  INTEGER PRIMARY KEY ,\n        `uid` int(10) NOT NULL DEFAULT '0',\n        `item_sort_data` text NOT NULL DEFAULT '',\n        `addtime` int(11) NOT NULL DEFAULT '0'\n        )\";\n        D(\"UserToken\")->execute($sql);\n\n        //创建single_page表\n        $sql = \"CREATE TABLE IF NOT EXISTS `single_page` (\n        `id`  INTEGER PRIMARY KEY ,\n        `unique_key` CHAR(200) NOT NULL DEFAULT '',\n        `page_id` int(11) NOT NULL DEFAULT '0'\n        )\";\n        D(\"User\")->execute($sql);\n\n        //创建captcha表\n        $sql = \"CREATE TABLE IF NOT EXISTS `captcha` (\n        `captcha_id`  INTEGER PRIMARY KEY ,\n        `mobile` CHAR(200) NOT NULL DEFAULT '',\n        `captcha` CHAR(200) NOT NULL DEFAULT '',\n        `expire_time` int(11) NOT NULL DEFAULT '0'\n        )\";\n        D(\"User\")->execute($sql);\n\n        //创建recycle表\n        $sql = \"CREATE TABLE IF NOT EXISTS `recycle` (\n        `id`  INTEGER PRIMARY KEY ,\n        `item_id` int(11) NOT NULL DEFAULT '0',\n        `page_id` int(11) NOT NULL DEFAULT '0',\n        `page_title` CHAR(200) NOT NULL DEFAULT '',\n        `del_by_uid` int(11) NOT NULL DEFAULT '0',\n        `del_by_username` CHAR(200) NOT NULL DEFAULT '',\n        `del_time` int(11) NOT NULL DEFAULT '0'\n        )\";\n        D(\"User\")->execute($sql);\n\n        //创建page_lock表\n        $sql = \"CREATE TABLE IF NOT EXISTS `page_lock` (\n            `id`  INTEGER PRIMARY KEY ,\n            `page_id` int(11) NOT NULL DEFAULT '0',\n            `lock_uid` int(11) NOT NULL DEFAULT '0',\n            `lock_username` CHAR(200) NOT NULL DEFAULT '',\n            `lock_to` int(11) NOT NULL DEFAULT '0',\n            `addtime` int(11) NOT NULL DEFAULT '0'\n            )\";\n        D(\"User\")->execute($sql);\n\n        //item_member表增加cat_id字段\n        if (!$this->_is_column_exist(\"item_member\", \"cat_id\")) {\n            $sql = \"ALTER TABLE \" . C('DB_PREFIX') . \"item_member ADD cat_id INT( 10 ) NOT NULL DEFAULT '0'  ;\";\n            D(\"User\")->execute($sql);\n        }\n\n        //team_item_member表增加cat_id字段\n        if (!$this->_is_column_exist(\"team_item_member\", \"cat_id\")) {\n            $sql = \"ALTER TABLE \" . C('DB_PREFIX') . \"team_item_member ADD cat_id INT( 10 ) NOT NULL DEFAULT '0'  ;\";\n            D(\"User\")->execute($sql);\n        }\n\n        // 为多目录权限支持新增字段：item_member.cat_ids、team_item_member.cat_ids（逗号分隔字符串）\n        if (!$this->_is_column_exist(\"item_member\", \"cat_ids\")) {\n            $sql = \"ALTER TABLE \" . C('DB_PREFIX') . \"item_member ADD cat_ids text NOT NULL DEFAULT ''  ;\";\n            D(\"User\")->execute($sql);\n        }\n        if (!$this->_is_column_exist(\"team_item_member\", \"cat_ids\")) {\n            $sql = \"ALTER TABLE \" . C('DB_PREFIX') . \"team_item_member ADD cat_ids text NOT NULL DEFAULT ''  ;\";\n            D(\"User\")->execute($sql);\n        }\n\n        //创建item_variable表\n        $sql = \"CREATE TABLE IF NOT EXISTS `item_variable` (\n            `id`  INTEGER PRIMARY KEY ,\n            `var_name` CHAR(2000) NOT NULL DEFAULT '',\n            `var_value` CHAR(2000) NOT NULL DEFAULT '',\n            `uid` int(11) NOT NULL DEFAULT '0',\n            `item_id` int(11) NOT NULL DEFAULT '0',\n            `addtime` int(11) NOT NULL DEFAULT '0'\n            )\";\n        D(\"User\")->execute($sql);\n\n        //创建file_flow表\n        $sql = \"CREATE TABLE IF NOT EXISTS `file_flow` (\n            `id`  INTEGER PRIMARY KEY ,\n            `uid` int(11) NOT NULL DEFAULT '0',\n            `used` int(11) NOT NULL DEFAULT '0',\n            `date_month` CHAR(2000) NOT NULL DEFAULT ''\n            )\";\n        D(\"User\")->execute($sql);\n\n        //item_variable表增加env_id字段\n        if (!$this->_is_column_exist(\"item_variable\", \"env_id\")) {\n            $sql = \"ALTER TABLE \" . C('DB_PREFIX') . \"item_variable ADD env_id INT( 10 ) NOT NULL DEFAULT '0'  ;\";\n            D(\"User\")->execute($sql);\n        }\n        //创建runapi_env表\n        $sql = \"CREATE TABLE IF NOT EXISTS `runapi_env` (\n            `id`  INTEGER PRIMARY KEY ,\n            `env_name` CHAR(2000) NOT NULL DEFAULT '',\n            `item_id` int(11) NOT NULL DEFAULT '0',\n            `uid` int(11) NOT NULL DEFAULT '0',\n            `addtime` CHAR(2000) NOT NULL DEFAULT '',\n            `last_update_time` CHAR(2000) NOT NULL DEFAULT ''\n            )\";\n        D(\"User\")->execute($sql);\n        //创建runapi_env_selectd表\n        $sql = \"CREATE TABLE IF NOT EXISTS `runapi_env_selectd` (\n            `id`  INTEGER PRIMARY KEY ,\n            `item_id` int(11) NOT NULL DEFAULT '0',\n            `uid` int(11) NOT NULL DEFAULT '0',\n            `env_id` int(11) NOT NULL DEFAULT '0'\n            )\";\n        D(\"User\")->execute($sql);\n        //创建runapi_global_param表\n        $sql = \"CREATE TABLE IF NOT EXISTS `runapi_global_param` (\n            `id`  INTEGER PRIMARY KEY ,\n            `item_id` int(11) NOT NULL DEFAULT '0',\n            `param_type` CHAR(2000) NOT NULL DEFAULT '',\n            `content_json_str` CHAR(2000) NOT NULL DEFAULT '',\n            `addtime` CHAR(2000) NOT NULL DEFAULT '',\n            `last_update_time` CHAR(2000) NOT NULL DEFAULT ''\n            )\";\n        D(\"User\")->execute($sql);\n        //创建mock表\n        $sql = \"CREATE TABLE IF NOT EXISTS `mock` (\n            `id`  INTEGER PRIMARY KEY ,\n            `unique_key` CHAR(2000) NOT NULL DEFAULT '',\n            `uid` int(11) NOT NULL DEFAULT '0',\n            `page_id` int(11) NOT NULL DEFAULT '0',\n            `item_id` int(11) NOT NULL DEFAULT '0',\n            `view_times` int(11) NOT NULL DEFAULT '0',\n            `template` CHAR(2000) NOT NULL DEFAULT '',\n            `addtime` CHAR(2000) NOT NULL DEFAULT '',\n            `last_update_time` CHAR(2000) NOT NULL DEFAULT ''\n            )\";\n        D(\"User\")->execute($sql);\n\n        //创建file_page表\n        $sql = \"CREATE TABLE IF NOT EXISTS `file_page` (\n            `id`  INTEGER PRIMARY KEY ,\n            `file_id` int(11) NOT NULL DEFAULT '0',\n            `page_id` int(11) NOT NULL DEFAULT '0',\n            `item_id` int(11) NOT NULL DEFAULT '0',\n            `addtime` CHAR(2000) NOT NULL DEFAULT ''\n            )\";\n        D(\"User\")->execute($sql);\n\n        // 如果file_page尚未有数据，则把upload_file表的数据转换过去\n        if (!D(\"FilePage\")->find()) {\n            $files = D(\"UploadFile\")->select();\n            if ($files) {\n                foreach ($files as $key => $value) {\n                    D(\"FilePage\")->add(array(\n                        \"file_id\" => $value['file_id'],\n                        \"page_id\" => $value['page_id'],\n                        \"item_id\" => $value['item_id'],\n                        \"addtime\" => $value['addtime'],\n                    ));\n                }\n            }\n        }\n\n        //给mock表增加path字段\n        if (!$this->_is_column_exist(\"mock\", \"path\")) {\n            $sql = \"ALTER TABLE \" . C('DB_PREFIX') . \"mock ADD path text NOT NULL DEFAULT '';\";\n            D(\"mock\")->execute($sql);\n        }\n\n        //创建runapi_flow表\n        $sql = \"CREATE TABLE IF NOT EXISTS `runapi_flow` (\n            `id`  INTEGER PRIMARY KEY ,\n            `flow_name` CHAR(2000) NOT NULL DEFAULT '',\n            `uid` int(11) NOT NULL DEFAULT '0',\n            `username` CHAR(2000) NOT NULL DEFAULT '',\n            `item_id` int(11) NOT NULL DEFAULT '0',\n            `env_id` int(11) NOT NULL DEFAULT '0',\n            `times` int(11) NOT NULL DEFAULT '0',\n            `time_interval` int(11) NOT NULL DEFAULT '0',\n            `error_continue` int(11) NOT NULL DEFAULT '0',\n            `save_change` int(11) NOT NULL DEFAULT '0',\n            `addtime` CHAR(2000) NOT NULL DEFAULT '',\n            `last_update_time` CHAR(2000) NOT NULL DEFAULT ''\n            )\";\n        D(\"User\")->execute($sql);\n\n        //创建runapi_flow_page表\n        $sql = \"CREATE TABLE IF NOT EXISTS `runapi_flow_page` (\n            `id`  INTEGER PRIMARY KEY ,\n            `flow_id` int(11) NOT NULL DEFAULT '0',\n            `page_id` int(11) NOT NULL DEFAULT '0',\n            `s_number` int(11) NOT NULL DEFAULT '0',\n            `addtime` CHAR(2000) NOT NULL DEFAULT ''\n            )\";\n        D(\"User\")->execute($sql);\n\n        //给runapi_flow_page表增加enabled字段\n        if (!$this->_is_column_exist(\"runapi_flow_page\", \"enabled\")) {\n            $sql = \"ALTER TABLE \" . C('DB_PREFIX') . \"runapi_flow_page ADD enabled int(1) NOT NULL DEFAULT '1' ;\";\n            D(\"mock\")->execute($sql);\n        }\n\n        //给item_sort表增加item_group_id字段\n        if (!$this->_is_column_exist(\"item_sort\", \"item_group_id\")) {\n            $sql = \"ALTER TABLE \" . C('DB_PREFIX') . \"item_sort ADD item_group_id int(10) NOT NULL DEFAULT '0' ;\";\n            D(\"mock\")->execute($sql);\n        }\n\n        //创建item_group表\n        $sql = \"CREATE TABLE IF NOT EXISTS `item_group` (\n            `id`  INTEGER PRIMARY KEY ,\n            `uid` int(11) NOT NULL DEFAULT '0',\n            `group_name` CHAR(2000) NOT NULL DEFAULT '',\n            `item_ids` text NOT NULL DEFAULT '',\n            `s_number` int(11) NOT NULL DEFAULT '0',\n            `created_at` CHAR(2000) NOT NULL DEFAULT '',\n            `updated_at` CHAR(2000) NOT NULL DEFAULT ''\n            )\";\n        D(\"User\")->execute($sql);\n\n        //创建item_change_log表\n        $sql = \"CREATE TABLE IF NOT EXISTS `item_change_log` (\n            `id`  INTEGER PRIMARY KEY ,\n            `uid` int(11) NOT NULL DEFAULT '0',\n            `item_id` int(11) NOT NULL DEFAULT '0',\n            `op_action_type` CHAR(2000) NOT NULL DEFAULT '',\n            `op_object_type` CHAR(2000) NOT NULL DEFAULT '',\n            `op_object_id` int(11) NOT NULL DEFAULT '0',\n            `op_object_name` CHAR(2000) NOT NULL DEFAULT '',\n            `remark` CHAR(2000) NOT NULL DEFAULT '',\n            `optime` CHAR(2000) NOT NULL DEFAULT ''\n            )\";\n        D(\"User\")->execute($sql);\n\n        //创建message_content表\n        $sql = \"CREATE TABLE IF NOT EXISTS `message_content` (\n            `id`  INTEGER PRIMARY KEY ,\n            `from_uid` int(11) NOT NULL DEFAULT '0',\n            `from_name` CHAR(2000) NOT NULL DEFAULT '',\n            `message_type` CHAR(2000) NOT NULL DEFAULT '',\n            `message_content` CHAR(2000) NOT NULL DEFAULT '',\n            `action_type` CHAR(2000) NOT NULL DEFAULT '',\n            `object_type` CHAR(2000) NOT NULL DEFAULT '',\n            `object_id` int(11) NOT NULL DEFAULT '0',\n            `addtime` CHAR(2000) NOT NULL DEFAULT ''\n\n            )\";\n        D(\"User\")->execute($sql);\n\n        //创建message表\n        $sql = \"CREATE TABLE IF NOT EXISTS `message` (\n            `id`  INTEGER PRIMARY KEY ,\n            `from_uid` int(11) NOT NULL DEFAULT '0',\n            `to_uid` int(11) NOT NULL DEFAULT '0',\n            `message_type` CHAR(2000) NOT NULL DEFAULT '',\n            `message_content_id` int(11) NOT NULL DEFAULT '0',\n            `status` int(11) NOT NULL DEFAULT '0',\n            `addtime` CHAR(2000) NOT NULL DEFAULT '',\n            `readtime` CHAR(2000) NOT NULL DEFAULT ''\n            )\";\n        D(\"User\")->execute($sql);\n\n        //创建subscription表\n        $sql = \"CREATE TABLE IF NOT EXISTS `subscription` (\n            `id`  INTEGER PRIMARY KEY ,\n            `uid` int(11) NOT NULL DEFAULT '0',\n            `object_id` int(11) NOT NULL DEFAULT '0',\n            `object_type` CHAR(2000) NOT NULL DEFAULT '',\n            `action_type` CHAR(2000) NOT NULL DEFAULT '',\n            `sub_time` CHAR(2000) NOT NULL DEFAULT ''\n            )\";\n        D(\"User\")->execute($sql);\n\n        //创建template_item表\n        $sql = \"CREATE TABLE IF NOT EXISTS `template_item` (\n            `id`  INTEGER PRIMARY KEY ,\n            `template_id` int(11) NOT NULL DEFAULT '0',\n            `item_id` int(11) NOT NULL DEFAULT '0',\n            `uid` int(11) NOT NULL DEFAULT '0',\n            `username` CHAR(2000) NOT NULL DEFAULT '',\n            `created_at` CHAR(2000) NOT NULL DEFAULT ''\n            )\";\n        D(\"User\")->execute($sql);\n\n        //给team_member表增加team_member_group_id字段\n        if (!$this->_is_column_exist(\"team_member\", \"team_member_group_id\")) {\n            $sql = \"ALTER TABLE \" . C('DB_PREFIX') . \"team_member ADD team_member_group_id int(10) NOT NULL DEFAULT '1' ;\";\n            D(\"mock\")->execute($sql);\n        }\n\n        //给user表增加salt字段\n        if (!$this->_is_column_exist(\"user\", \"salt\")) {\n            $sql = \"ALTER TABLE \" . C('DB_PREFIX') . \"user ADD salt CHAR(2000) NOT NULL DEFAULT '' ;\";\n            D(\"mock\")->execute($sql);\n        }\n\n        //创建item_star表\n        $sql = \"CREATE TABLE IF NOT EXISTS `item_star` (\n            `id`  INTEGER PRIMARY KEY ,\n            `uid` int(11) NOT NULL DEFAULT '0',\n            `item_id` int(11) NOT NULL DEFAULT '0',\n            `s_number` int(11) NOT NULL DEFAULT '0',\n            `created_at` CHAR(2000) NOT NULL DEFAULT '',\n            `updated_at` CHAR(2000) NOT NULL DEFAULT ''\n            )\";\n        D(\"User\")->execute($sql);\n\n        //给page表增加ext_info字段\n        if (!$this->_is_column_exist(\"page\", \"ext_info\")) {\n            $sql = \"ALTER TABLE \" . C('DB_PREFIX') . \"page ADD ext_info CHAR(2000) NOT NULL DEFAULT '' ;\";\n            D(\"page\")->execute($sql);\n        }\n\n        //给page_history表增加ext_info字段\n        if (!$this->_is_column_exist(\"page_history\", \"ext_info\")) {\n            $sql = \"ALTER TABLE \" . C('DB_PREFIX') . \"page_history ADD ext_info CHAR(2000) NOT NULL DEFAULT '' ;\";\n            D(\"page\")->execute($sql);\n        }\n\n        // 创建 export_log 表（记录导出行为）\n        $sql = \"CREATE TABLE IF NOT EXISTS `export_log` (\n            `id`  INTEGER PRIMARY KEY ,\n            `uid` int(11) NOT NULL DEFAULT '0',\n            `export_type` CHAR(200) NOT NULL DEFAULT '',\n            `item_id` int(11) NOT NULL DEFAULT '0',\n            `addtime` CHAR(200) NOT NULL DEFAULT ''\n        )\";\n        D(\"User\")->execute($sql);\n\n        // 检查 upload_file 表是否有 last_visit_time 字段，如果没有则添加\n        if (!$this->_is_column_exist(\"upload_file\", \"last_visit_time\")) {\n            $sql = \"ALTER TABLE \" . C('DB_PREFIX') . \"upload_file ADD last_visit_time INT(11) NOT NULL DEFAULT '0';\";\n            D(\"User\")->execute($sql);\n        }\n\n        // 设置自增id从 10000000 开始\n        $randomNumber1 = mt_rand(100000000, 299999999);\n        $randomNumber2 = mt_rand(400000000, 499999999);\n        $randomNumber3 = mt_rand(600000000, 699999999);\n        D(\"page\")->execute(\"INSERT INTO sqlite_sequence (name, seq) VALUES ('page', {$randomNumber1})\");\n        D(\"page\")->execute(\"INSERT INTO sqlite_sequence (name, seq) VALUES ('catalog', {$randomNumber2})\");\n        D(\"page\")->execute(\"INSERT INTO sqlite_sequence (name, seq) VALUES ('item', {$randomNumber3})\");\n\n        //创建user_setting表\n        $sql = \"CREATE TABLE IF NOT EXISTS `user_setting` (\n        `id`  INTEGER PRIMARY KEY ,\n        `uid` int(10) NOT NULL DEFAULT '0',\n        `key_name` CHAR(200) NOT NULL DEFAULT '',\n        `key_value` text NOT NULL DEFAULT '' ,\n        `addtime` text NOT NULL DEFAULT ''\n        )\";\n        D(\"UserSetting\")->execute($sql);\n\n        //给single_page表增加expire_time字段\n        if (!$this->_is_column_exist(\"single_page\", \"expire_time\")) {\n            $sql = \"ALTER TABLE \" . C('DB_PREFIX') . \"single_page ADD expire_time INT(11) NOT NULL DEFAULT '0';\";\n            D(\"page\")->execute($sql);\n        }\n\n        // 创建参数描述库表 parameter_description_entry（SQLite 版本）\n        $sql = \"CREATE TABLE IF NOT EXISTS `parameter_description_entry` (\n        `id` TEXT PRIMARY KEY,\n        `item_id` TEXT NOT NULL,\n        `name` TEXT NOT NULL,\n        `type` TEXT NOT NULL,\n        `description` TEXT NOT NULL,\n        `example` TEXT,\n        `default_value` TEXT,\n        `aliases` TEXT,\n        `tags` TEXT,\n        `path` TEXT,\n        `source` TEXT NOT NULL DEFAULT 'manual' CHECK (source IN ('manual','auto-extracted','builtin')),\n        `status` TEXT NOT NULL DEFAULT 'permanent' CHECK (status IN ('temp','permanent')),\n        `usage_count` INTEGER NOT NULL DEFAULT 0,\n        `quality_score` NUMERIC NOT NULL DEFAULT 0.00,\n        `created_by` TEXT NOT NULL,\n        `created_at` TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP),\n        `updated_at` TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP)\n        )\";\n        D(\"User\")->execute($sql);\n\n        // 唯一约束与索引\n        $sql = \"CREATE UNIQUE INDEX IF NOT EXISTS uk_item_name_type ON parameter_description_entry (item_id, name, type)\";\n        D(\"User\")->execute($sql);\n        $sql = \"CREATE INDEX IF NOT EXISTS idx_item_id ON parameter_description_entry (item_id)\";\n        D(\"User\")->execute($sql);\n        $sql = \"CREATE INDEX IF NOT EXISTS idx_name ON parameter_description_entry (name)\";\n        D(\"User\")->execute($sql);\n        $sql = \"CREATE INDEX IF NOT EXISTS idx_type ON parameter_description_entry (type)\";\n        D(\"User\")->execute($sql);\n        $sql = \"CREATE INDEX IF NOT EXISTS idx_status ON parameter_description_entry (status)\";\n        D(\"User\")->execute($sql);\n        $sql = \"CREATE INDEX IF NOT EXISTS idx_created_at ON parameter_description_entry (created_at)\";\n        D(\"User\")->execute($sql);\n        $sql = \"CREATE INDEX IF NOT EXISTS idx_updated_at ON parameter_description_entry (updated_at)\";\n        D(\"User\")->execute($sql);\n\n        // 自动更新时间触发器\n        $sql = \"DROP TRIGGER IF EXISTS trg_parameter_description_entry_updated_at\";\n        D(\"User\")->execute($sql);\n        $sql = \"CREATE TRIGGER trg_parameter_description_entry_updated_at AFTER UPDATE ON parameter_description_entry\n        BEGIN\n          UPDATE parameter_description_entry SET updated_at = CURRENT_TIMESTAMP WHERE id = NEW.id;\n        END;\";\n        D(\"User\")->execute($sql);\n\n        //创建page_comment表（页面评论表）\n        $sql = \"CREATE TABLE IF NOT EXISTS `page_comment` (\n            `comment_id`  INTEGER PRIMARY KEY ,\n            `page_id` int(11) NOT NULL DEFAULT '0',\n            `item_id` int(11) NOT NULL DEFAULT '0',\n            `parent_id` int(11) NOT NULL DEFAULT '0',\n            `uid` int(11) NOT NULL DEFAULT '0',\n            `username` CHAR(200) NOT NULL DEFAULT '',\n            `content` text NOT NULL DEFAULT '',\n            `is_deleted` int(1) NOT NULL DEFAULT '0',\n            `addtime` int(11) NOT NULL DEFAULT '0'\n            )\";\n        D(\"User\")->execute($sql);\n\n        //创建page_feedback表（页面质量反馈表）\n        $sql = \"CREATE TABLE IF NOT EXISTS `page_feedback` (\n            `feedback_id`  INTEGER PRIMARY KEY ,\n            `page_id` int(11) NOT NULL DEFAULT '0',\n            `item_id` int(11) NOT NULL DEFAULT '0',\n            `uid` int(11) NOT NULL DEFAULT '0',\n            `client_id` CHAR(200) DEFAULT NULL,\n            `feedback_type` int(1) NOT NULL DEFAULT '0',\n            `addtime` int(11) NOT NULL DEFAULT '0'\n            )\";\n        D(\"User\")->execute($sql);\n\n        //为page_feedback表创建唯一索引（登录用户）\n        $sql = \"CREATE UNIQUE INDEX IF NOT EXISTS unique_user_feedback ON page_feedback (page_id, uid)\";\n        D(\"User\")->execute($sql);\n\n        //为page_feedback表创建唯一索引（游客）\n        $sql = \"CREATE UNIQUE INDEX IF NOT EXISTS unique_client_feedback ON page_feedback (page_id, client_id)\";\n        D(\"User\")->execute($sql);\n\n        //item表增加allow_comment字段\n        if (!$this->_is_column_exist(\"Item\", \"allow_comment\")) {\n            $sql = \"ALTER TABLE \" . C('DB_PREFIX') . \"item ADD allow_comment INT( 1 ) NOT NULL DEFAULT '0'  ;\";\n            D(\"ItemMember\")->execute($sql);\n        }\n\n        //item表增加allow_feedback字段\n        if (!$this->_is_column_exist(\"Item\", \"allow_feedback\")) {\n            $sql = \"ALTER TABLE \" . C('DB_PREFIX') . \"item ADD allow_feedback INT( 1 ) NOT NULL DEFAULT '0'  ;\";\n            D(\"ItemMember\")->execute($sql);\n        }\n\n        //清理可能存在的冲突数据：将登录用户的空字符串client_id改为NULL\n        D(\"User\")->execute(\"UPDATE page_feedback SET client_id = NULL WHERE uid > 0 AND (client_id = '' OR client_id IS NULL)\");\n\n        //创建item_ai_config表（项目AI知识库配置表）\n        $sql = \"CREATE TABLE IF NOT EXISTS `item_ai_config` (\n            `id`  INTEGER PRIMARY KEY ,\n            `item_id` int(11) NOT NULL DEFAULT '0',\n            `enabled` int(1) NOT NULL DEFAULT '0',\n            `dialog_collapsed` int(1) NOT NULL DEFAULT '1',\n            `welcome_message` text NOT NULL DEFAULT '',\n            `addtime` int(11) NOT NULL DEFAULT '0',\n            `updatetime` int(11) NOT NULL DEFAULT '0'\n            )\";\n        D(\"User\")->execute($sql);\n\n        //为item_ai_config表创建唯一索引\n        $sql = \"CREATE UNIQUE INDEX IF NOT EXISTS uk_item_id ON item_ai_config (item_id)\";\n        D(\"User\")->execute($sql);\n        $sql = \"CREATE INDEX IF NOT EXISTS idx_enabled ON item_ai_config (enabled)\";\n        D(\"User\")->execute($sql);\n\n        //创建runapi_db_config表（数据库连接配置表）\n        $sql = \"CREATE TABLE IF NOT EXISTS `runapi_db_config` (\n            `id`  INTEGER PRIMARY KEY ,\n            `item_id` int(11) NOT NULL DEFAULT '0',\n            `env_id` int(11) NOT NULL DEFAULT '0',\n            `config_name` CHAR(100) NOT NULL DEFAULT '默认',\n            `db_type` CHAR(20) NOT NULL DEFAULT 'mysql',\n            `host` CHAR(255) NOT NULL DEFAULT '',\n            `port` int(11) NOT NULL DEFAULT '0',\n            `username` CHAR(255) NOT NULL DEFAULT '',\n            `password` CHAR(255) NOT NULL DEFAULT '',\n            `database` CHAR(255) NOT NULL DEFAULT '',\n            `options` text NOT NULL DEFAULT '',\n            `is_default` int(1) NOT NULL DEFAULT '0',\n            `addtime` CHAR(2000) NOT NULL DEFAULT '',\n            `last_update_time` CHAR(2000) NOT NULL DEFAULT '',\n            `uid` int(11) NOT NULL DEFAULT '0'\n            )\";\n        D(\"User\")->execute($sql);\n\n        //为runapi_db_config表创建唯一索引（item_id, env_id, config_name）\n        $sql = \"CREATE UNIQUE INDEX IF NOT EXISTS uniq_item_env_name ON runapi_db_config (item_id, env_id, config_name)\";\n        D(\"User\")->execute($sql);\n\n        //留个注释提醒自己，如果更新数据库结构，务必更改checkDb()里面的$version_num\n        //留个注释提醒自己，如果更新数据库结构，务必更改checkDb()里面的$version_num\n        //留个注释提醒自己，如果更新数据库结构，务必更改checkDb()里面的$version_num\n\n        return true;\n    }\n\n    private function _is_column_exist($table, $column)\n    {\n        $has_it = false; //是否存在该字段\n        $columns = M($table)->getDbFields();\n        if ($columns) {\n            foreach ($columns as $key => $value) {\n                if ($value == $column) {\n                    $has_it = true;\n                }\n            }\n        }\n        return $has_it;\n    }\n}\n"
  },
  {
    "path": "server/Application/Api/Model/UserModel.class.php",
    "content": "<?php\n\nnamespace Api\\Model;\n\nuse Api\\Model\\BaseModel;\n\nclass UserModel extends BaseModel\n{\n\n    /**\n     * 用户名是否已经存在\n     * \n     */\n    public function isExist($username)\n    {\n        return  $this->where(\"username = '%s'\", array($username))->find();\n    }\n\n    /**\n     * 注册新用户\n     * \n     */\n    public function register($username, $password)\n    {\n        $salt = get_rand_str();\n        $password = encry_password($password, $salt);\n        $uid = $this->add(array('username' => $username, 'password' => $password, 'salt' => $salt,  'reg_time' => time()));\n        return $uid;\n    }\n\n    //修改用户密码\n    public function updatePwd($uid, $password)\n    {\n        $res = $this->where(\"uid = '%d'\", array($uid))->find();\n        $password = encry_password($password, $res['salt']);\n        return $this->where(\"uid ='%d' \", array($uid))->save(array('password' => $password));\n    }\n\n    /**\n     * 返回用户信息\n     * @return \n     */\n    public function userInfo($uid)\n    {\n        return  $this->where(\"uid = '%d'\", array($uid))->find();\n    }\n\n    /**\n     *@param username:登录名  \n     *@param password 登录密码   \n     */\n\n    public function checkLogin($username, $password)\n    {\n        $where = array($username, $username);\n        $res = $this->where(\" username='%s' or email='%s'  \", $where)->find();\n        if ($res) {\n            if ($res['password'] === encry_password($password, $res['salt'])) {\n                return $res;\n            }\n        }\n\n        return false;\n    }\n    //设置最后登录时间\n    public function setLastTime($uid)\n    {\n        return $this->where(\"uid='%s'\", array($uid))->save(array(\"last_login_time\" => time()));\n    }\n\n    //删除用户\n    public function delete_user($uid)\n    {\n        $uid = intval($uid);\n        D(\"TeamMember\")->where(array('member_uid' => $uid))->delete();\n        D(\"TeamItemMember\")->where(array('member_uid' => $uid))->delete();\n        D(\"ItemMember\")->where(array('uid' => $uid))->delete();\n        D(\"UserToken\")->where(array('uid' => $uid))->delete();\n        D(\"Template\")->where(array('uid' => $uid))->delete();\n        D(\"ItemTop\")->where(array('uid' => $uid))->delete();\n        $return = D(\"User\")->where(array('uid' => $uid))->delete();\n        return $return;\n    }\n    //检测ldap登录\n    public function checkLdapLogin($username, $password)\n    {\n        set_time_limit(60);\n        ini_set('memory_limit', '500M');\n        $ldap_open = D(\"Options\")->get(\"ldap_open\");\n        $ldap_form = D(\"Options\")->get(\"ldap_form\");\n        $ldap_form = json_decode($ldap_form, 1);\n        if (!$ldap_open) {\n            return false;\n        }\n        if (!$ldap_form['user_field']) {\n            $ldap_form['user_field'] = 'cn';\n        }\n        $ldap_conn = ldap_connect($ldap_form['host'], $ldap_form['port']); //建立与 LDAP 服务器的连接\n        if (!$ldap_conn) {\n            return false;\n        }\n        ldap_set_option($ldap_conn, LDAP_OPT_PROTOCOL_VERSION, $ldap_form['version']);\n        $rs = ldap_bind($ldap_conn, $ldap_form['bind_dn'], $ldap_form['bind_password']); //与服务器绑定 用户登录验证 成功返回1 \n        if (!$rs) {\n            return false;\n        }\n        $ldap_form['search_filter'] = $ldap_form['search_filter'] ? $ldap_form['search_filter'] : '(cn=*)';\n        \n        // 支持占位符 %(user)s，用于精确匹配登录用户\n        // 例如: (sAMAccountName=%(user)s) 会被替换为 (sAMAccountName=admin)\n        $has_placeholder = strpos($ldap_form['search_filter'], '%(user)s') !== false;\n        $search_filter = str_replace('%(user)s', ldap_escape($username, '', LDAP_ESCAPE_FILTER), $ldap_form['search_filter']);\n        \n        $result = ldap_search($ldap_conn, $ldap_form['base_dn'], $search_filter);\n        if (!$result) {\n            return false;\n        }\n        $data = ldap_get_entries($ldap_conn, $result);\n        \n        // 如果没有搜索结果，直接返回失败\n        if ($data[\"count\"] == 0) {\n            return false;\n        }\n        \n        for ($i = 0; $i < $data[\"count\"]; $i++) {\n            // 检查用户字段是否存在\n            $user_field_lower = strtolower($ldap_form['user_field']);\n            $ldap_user = null;\n            \n            // 因为LDAP属性可能大小写不同，遍历所有属性找到匹配的\n            foreach ($data[$i] as $key => $value) {\n                if (strtolower($key) === $user_field_lower && isset($value['count']) && $value['count'] > 0) {\n                    $ldap_user = $value[0];\n                    break;\n                }\n            }\n            \n            // 如果找不到用户字段，跳过\n            if (!$ldap_user) {\n                continue;\n            }\n            \n            $dn = $data[$i][\"dn\"];\n            \n            // 如果使用了占位符，说明已经精确匹配，直接使用第一个结果\n            // 否则需要检查用户名是否匹配（不区分大小写）\n            if ($has_placeholder || strcasecmp($ldap_user, $username) == 0) {\n                // 获取用户姓名\n                $ldap_name = '';\n                $name_field = strtolower($ldap_form['name_field']);\n\n                if ($name_field) {\n                    // 因为LDAP属性可能大小写不同，遍历所有属性找到匹配的\n                    foreach ($data[$i] as $key => $value) {\n                        if (strtolower($key) === $name_field && isset($value['count']) && $value['count'] > 0) {\n                            $ldap_name = $value[0];\n                            break;\n                        }\n                    }\n                }\n                \n                // 使用 LDAP 返回的实际用户名（$ldap_user）进行数据库操作\n                // 因为 LDAP 中的用户名可能和用户输入的 username 在大小写或格式上不同\n                $db_username = $ldap_user;\n                \n                //如果该用户不在数据库里，则帮助其注册\n                $userInfo = D(\"User\")->isExist($db_username);\n                if (!$userInfo) {\n                    $uid = D(\"User\")->register($db_username, $db_username . get_rand_str());\n                    // 如果有姓名字段，则设置用户姓名\n                    if ($ldap_name) {\n                        D(\"User\")->where(\"uid = '%d'\", array($uid))->save(array(\"name\" => $ldap_name));\n                    }\n                    $userInfo = D(\"User\")->isExist($db_username);\n                } else if ($ldap_name) {\n                    // 如果用户已存在且有姓名字段，则更新用户姓名\n                    D(\"User\")->where(\"uid = '%d'\", array($userInfo['uid']))->save(array(\"name\" => $ldap_name));\n                }\n                \n                $rs2 = ldap_bind($ldap_conn, $dn, $password);\n                if ($rs2) {\n                    // LDAP认证成功，更新本地密码\n                    D(\"User\")->updatePwd($userInfo['uid'], $password);\n                    \n                    // 直接返回用户信息，避免再次调用checkLogin造成的验证问题\n                    // 因为LDAP已经验证了密码的正确性，无需再次验证\n                    $userInfo = D(\"User\")->where(\"uid = '%d'\", array($userInfo['uid']))->find();\n                    \n                    // 清除敏感信息\n                    unset($userInfo['password']);\n                    unset($userInfo['salt']);\n                    \n                    return $userInfo;\n                }\n            }\n        }\n\n        return false;\n    }\n\n    public function checkDbOk()\n    {\n        $ret = $this->find();\n        if ($ret) {\n            return true;\n        } else {\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "server/Application/Api/Model/UserSettingModel.class.php",
    "content": "<?php\n\nnamespace Api\\Model;\n\nuse Api\\Model\\BaseModel;\n\n/**\n * 用户设置模型\n * @author \n */\nclass UserSettingModel extends BaseModel\n{\n    /**\n     * 获取用户设置\n     * @param int $uid 用户ID\n     * @param string $key 设置键名\n     * @return string|null 设置值\n     */\n    public function getSetting($uid, $key)\n    {\n        $res = $this->where(\"uid = '%d' AND key_name = '%s'\", array($uid, $key))->find();\n        return $res ? $res['key_value'] : null;\n    }\n\n    /**\n     * 保存用户设置\n     * @param int $uid 用户ID\n     * @param string $key 设置键名\n     * @param string $value 设置值\n     * @return boolean|integer\n     */\n    public function saveSetting($uid, $key, $value)\n    {\n        $res = $this->where(\"uid = '%d' AND key_name = '%s'\", array($uid, $key))->find();\n        if ($res) {\n            return $this->where(\"id = '%d'\", array($res['id']))->save(array('key_value' => $value));\n        } else {\n            return $this->add(array(\n                'uid' => $uid,\n                'key_name' => $key,\n                'key_value' => $value,\n                'addtime' => date(\"Y-m-d H:i:s\")\n            ));\n        }\n    }\n\n    /**\n     * 获取用户的推送地址\n     * @param int $uid 用户ID\n     * @return string|null 推送地址\n     */\n    public function getPushUrl($uid)\n    {\n        return $this->getSetting($uid, 'push_url');\n    }\n\n    /**\n     * 保存用户的推送地址\n     * @param int $uid 用户ID\n     * @param string $url 推送地址\n     * @return boolean|integer\n     */\n    public function savePushUrl($uid, $url)\n    {\n        return $this->saveSetting($uid, 'push_url', $url);\n    }\n} "
  },
  {
    "path": "server/Application/Api/Model/UserTokenModel.class.php",
    "content": "<?php\n\nnamespace Api\\Model;\n\nuse Api\\Model\\BaseModel;\n\n/**\n * \n * @author star7th      \n */\nclass UserTokenModel extends BaseModel\n{\n\n\tpublic function createToken($uid, $token_expire = 0)\n\t{\n\t\t$token_expire = $token_expire > 0  ? (time() + $token_expire) : (time() + 60 * 60 * 24 * 90);\n\t\t$token = md5(md5($uid . $token_expire . time() . rand() . \"showdoc\") . \"rdgsvgsrgr67hghf54t\") . md5($uid . $token_expire . time() . rand() . \"showdoc\");\n\t\t$data['uid'] = $uid;\n\t\t$data['token'] = $token;\n\t\t$data['token_expire'] = $token_expire;\n\t\t$data['ip'] = getIPaddress();\n\t\t$data['addtime'] = time();\n\t\t$ret = $this->add($data);\n\t\tif ($ret) {\n\t\t\t//删除过期的token \n\t\t\t$this->where(\"token_expire < \" . time())->delete();\n\t\t\treturn $token;\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic function getToken($token)\n\t{\n\t\treturn $this->where(\"token='%s'\", array($token))->find();\n\t}\n\n\tpublic function setLastTime($token)\n\t{\n\t\treturn $this->where(\"token='%s'\", array($token))->save(array(\"last_check_time\" => time()));\n\t}\n}\n"
  },
  {
    "path": "server/Application/Api/Model/VerifyCodeModel.class.php",
    "content": "<?php\n\nnamespace Api\\Model;\n\nuse Api\\Model\\BaseModel;\n\n/**\n * \n * @author star7th      \n */\nclass VerifyCodeModel\n{\n\n    //次数加1\n    public function _ins_times($key)\n    {\n        // 初始化缓存\n        S(array('type' => 'File', 'prefix' => 'think453434d', 'expire' => 60 * 60 * 24));\n        $cache_times = S($key);\n        $cache_times = intval($cache_times);\n        $ret = S($key, $cache_times + 1, 24 * 60 * 60);\n        return $ret;\n    }\n\n    public function _check_times($key, $max_times = 5)\n    {\n        // 初始化缓存\n        S(array('type' => 'File', 'prefix' => 'think453434d', 'expire' => 60 * 60 * 24));\n        $cache_times = S($key);\n        $cache_times = intval($cache_times);\n        if ($cache_times) {\n            if ($cache_times >= $max_times) {\n                return false;\n            }\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "server/Application/Api/Model/index.html",
    "content": " "
  },
  {
    "path": "server/Application/Api/View/index.html",
    "content": " "
  },
  {
    "path": "server/Application/Api/index.html",
    "content": " "
  },
  {
    "path": "server/Application/Common/Common/function.php",
    "content": "<?php\n\n\n/**\n * 获得当前的域名\n *\n * @return  string\n */\nfunction get_domain()\n{\n    /* 协议 */\n    $protocol = (isset($_SERVER['HTTPS']) && (strtolower($_SERVER['HTTPS']) != 'off')) ? 'https://' : 'http://';\n\n    /* 域名或IP地址 */\n    if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])) {\n        $host = $_SERVER['HTTP_X_FORWARDED_HOST'];\n    } elseif (isset($_SERVER['HTTP_HOST'])) {\n        $host = $_SERVER['HTTP_HOST'];\n    } else {\n        /* 端口 */\n        if (isset($_SERVER['SERVER_PORT'])) {\n            $port = ':' . $_SERVER['SERVER_PORT'];\n\n            if ((':80' == $port && 'http://' == $protocol) || (':443' == $port && 'https://' == $protocol)) {\n                $port = '';\n            }\n        } else {\n            $port = '';\n        }\n\n        if (isset($_SERVER['SERVER_NAME'])) {\n            $host = $_SERVER['SERVER_NAME'] . $port;\n        } elseif (isset($_SERVER['SERVER_ADDR'])) {\n            $host = $_SERVER['SERVER_ADDR'] . $port;\n        }\n    }\n\n    return $protocol . $host;\n}\n\n/**\n * 获得网站的URL地址。\n *\n * @return  string\n */\nfunction site_url()\n{\n\n    $site_url = D(\"Options\")->get(\"site_url\");\n    if (!$site_url) {\n        $site_url =  get_domain() . substr($_SERVER['PHP_SELF'], 0, strrpos($_SERVER['PHP_SELF'], '/'));\n        $site_url = str_replace('/server', '', $site_url);\n    }\n    return $site_url;\n}\n\n// 拼接后台server链接\nfunction server_url($path = '', $params = array())\n{\n\n    $url =   site_url() . '/server/index.php?s=/' . $path;\n    if ($params) {\n        $url =  $url . '&' . http_build_query($params);\n    }\n    return $url;\n}\n\n//导出word\nfunction output_word($data, $fileName = '')\n{\n\n    if (empty($data)) return '';\n\n    $data = '<html xmlns:v=\"urn:schemas-microsoft-com:vml\"\n    xmlns:o=\"urn:schemas-microsoft-com:office:office\"\n    xmlns:w=\"urn:schemas-microsoft-com:office:word\"\n    xmlns=\"http://www.w3.org/TR/REC-html40\">\n    <head><meta http-equiv=Content-Type content=\"text/html; charset=utf-8\">\n    <style type=\"text/css\">\n        table  \n        {  \n            border-collapse: collapse;\n            border: none;  \n            width: 100%;  \n        }  \n        td,tr  \n        {  \n            border: solid #CCC 1px;\n            padding:3px;\n            font-size:9pt;\n        } \n        .codestyle{\n            word-break: break-all;\n            mso-highlight:rgb(252, 252, 252);\n            padding-left: 5px; background-color: rgb(252, 252, 252); border: 1px solid rgb(225, 225, 232);\n        }\n        img {\n            width:100;\n        }\n    </style>\n    <meta name=ProgId content=Word.Document>\n    <meta name=Generator content=\"Microsoft Word 11\">\n    <meta name=Originator content=\"Microsoft Word 11\">\n    <xml><w:WordDocument><w:View>Print</w:View></xml></head>\n    <body>' . $data . '</body></html>';\n\n    $filepath = tmpfile();\n    $data = str_replace(\"<thead>\\n<tr>\", \"<thead><tr style='background-color: rgb(0, 136, 204); color: rgb(255, 255, 255);'>\", $data);\n    $data = str_replace(\"<pre><code\", \"<table width='100%' class='codestyle'><pre><code\", $data);\n    $data = str_replace(\"</code></pre>\", \"</code></pre></table>\", $data);\n    $data = str_replace(\"<img \", \"<img style='max-width:500' \", $data);\n    $len = strlen($data);\n    fwrite($filepath, $data);\n    header(\"Content-type: application/octet-stream\");\n    header(\"Content-Disposition: attachment; filename={$fileName}.doc\");\n    header('Content-Description: File Transfer');\n    header('Content-Type: application/octet-stream');\n    header('Content-Disposition: attachment; filename=' . $fileName . '.doc');\n    header('Content-Transfer-Encoding: binary');\n    header('Expires: 0');\n    header('Cache-Control: must-revalidate, post-check=0, pre-check=0');\n    header('Pragma: public');\n    header('Content-Length: ' . $len);\n    rewind($filepath);\n    echo fread($filepath, $len);\n}\n\n\nfunction clear_runtime($path = RUNTIME_PATH)\n{\n    //给定的目录不是一个文件夹  \n    if (!is_dir($path)) {\n        return null;\n    }\n\n    $fh = opendir($path);\n    while (($row = readdir($fh)) !== false) {\n        //过滤掉虚拟目录  \n        if ($row == '.' || $row == '..' || $row == 'index.html') {\n            continue;\n        }\n\n        if (!is_dir($path . '/' . $row)) {\n            unlink($path . '/' . $row);\n        }\n        clear_runtime($path . '/' . $row);\n    }\n    //关闭目录句柄，否则出Permission denied  \n    closedir($fh);\n    return true;\n}\n\n//获取ip\nfunction getIPaddress()\n{\n    $IPaddress = '';\n    if (isset($_SERVER)) {\n        if (isset($_SERVER[\"HTTP_X_FORWARDED_FOR\"])) {\n            $IPaddress = $_SERVER[\"HTTP_X_FORWARDED_FOR\"];\n        } else if (isset($_SERVER[\"HTTP_CLIENT_IP\"])) {\n            $IPaddress = $_SERVER[\"HTTP_CLIENT_IP\"];\n        } else {\n            $IPaddress = $_SERVER[\"REMOTE_ADDR\"];\n        }\n    } else {\n        if (getenv(\"HTTP_X_FORWARDED_FOR\")) {\n            $IPaddress = getenv(\"HTTP_X_FORWARDED_FOR\");\n        } else if (getenv(\"HTTP_CLIENT_IP\")) {\n            $IPaddress = getenv(\"HTTP_CLIENT_IP\");\n        } else {\n            $IPaddress = getenv(\"REMOTE_ADDR\");\n        }\n    }\n    return $IPaddress;\n}\n\n/**\n * POST 请求\n *\n * @param string $url           \n * @param array $param          \n * @return string content\n */\nfunction http_post($url, $param)\n{\n    $oCurl = curl_init();\n    if (stripos($url, \"https://\") !== FALSE) {\n        curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, FALSE);\n        curl_setopt($oCurl, CURLOPT_SSL_VERIFYHOST, false);\n    }\n    if (is_string($param)) {\n        $strPOST = $param;\n    } else {\n        $aPOST = array();\n        foreach ($param as $key => $val) {\n            $aPOST[] = $key . \"=\" . urlencode($val);\n        }\n        $strPOST = join(\"&\", $aPOST);\n    }\n    curl_setopt($oCurl, CURLOPT_URL, $url);\n    curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, 1);\n    curl_setopt($oCurl, CURLOPT_POST, true);\n    curl_setopt($oCurl, CURLOPT_POSTFIELDS, $strPOST);\n    $sContent = curl_exec($oCurl);\n    curl_close($oCurl);\n    return $sContent;\n}\n\n// http get请求\nfunction http_get($url)\n{\n    $oCurl = curl_init();   //初始化curl，\n    curl_setopt($oCurl, CURLOPT_URL, $url);   //设置网址\n    curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, 1);  //将curl_exec的结果返回\n    curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, FALSE);\n    curl_setopt($oCurl, CURLOPT_SSL_VERIFYHOST, FALSE);\n    curl_setopt($oCurl, CURLOPT_HEADER, 0);         //是否输出返回头信息\n    $response = curl_exec($oCurl);   //执行\n    curl_close($oCurl);          //关闭会话\n    return $response;\n}\n\nfunction compress_string($string)\n{\n    return base64_encode(gzcompress($string, 9));\n}\n\nfunction uncompress_string($string)\n{\n    return  gzuncompress(base64_decode($string));\n}\n\n//获取环境变量。如果环境变量不存在，将返回第一个参数\nfunction env($name, $default_value = false)\n{\n    return getenv($name) ? getenv($name) : $default_value;\n}\n\n// 获取加密密码串\nfunction encry_password($password, $salt = '')\n{\n    return md5(base64_encode(md5($password)) . '576hbgh6' . $salt);\n}\n\n// 获取随机字符串\nfunction get_rand_str($len = 32)\n{\n    // 对于php7以上版本，可利用random_bytes产生随机\n    if (version_compare(PHP_VERSION, '7.0', '>')) {\n        $rand = bin2hex(random_bytes(16));\n        return substr($rand, 0, $len);\n    } else {\n        // 对于低版本，只好尽量加大长度实现伪随机，增大暴力破解难度\n        $s1 = microtime(true) . time() . rand() . rand() . rand() . microtime(true) . time() . rand() . rand() . rand();\n        $s2 = microtime(true) . time() . rand() . rand() . rand() . microtime(true) . time() . rand() . rand() . rand();\n        $md5 = md5($s2 . base64_encode($s1));\n        return substr($md5, 0, $len);\n    }\n}\n\n/**\n * 验证密码强度\n * 要求：至少8位，包含大小写字母、数字和特殊字符\n * \n * @param string $password 待验证的密码\n * @return array 返回数组，['valid' => bool, 'message' => string, 'errors' => array]\n */\nfunction validate_strong_password($password)\n{\n    $strong_password_enabled = D(\"Options\")->get(\"strong_password_enabled\");\n\n    // 如果未启用高强度密码，直接返回通过\n    if (!$strong_password_enabled || $strong_password_enabled === '0' || $strong_password_enabled === false) {\n        return array('valid' => true, 'message' => '', 'errors' => array());\n    }\n\n    $errors = array();\n\n    // 检查密码长度\n    if (strlen($password) < 8) {\n        $errors[] = '密码长度至少需要8位';\n    }\n\n    // 检查是否包含小写字母\n    if (!preg_match('/[a-z]/', $password)) {\n        $errors[] = '密码必须包含至少一个小写字母';\n    }\n\n    // 检查是否包含大写字母\n    if (!preg_match('/[A-Z]/', $password)) {\n        $errors[] = '密码必须包含至少一个大写字母';\n    }\n\n    // 检查是否包含数字\n    if (!preg_match('/[0-9]/', $password)) {\n        $errors[] = '密码必须包含至少一个数字';\n    }\n\n    // 检查是否包含特殊字符\n    if (!preg_match('/[^a-zA-Z0-9]/', $password)) {\n        $errors[] = '密码必须包含至少一个特殊字符';\n    }\n\n    // 如果有错误，返回所有错误信息\n    if (count($errors) > 0) {\n        return array('valid' => false, 'message' => implode('；', $errors), 'errors' => $errors);\n    }\n\n    return array('valid' => true, 'message' => '', 'errors' => array());\n}\n\n// 获取日期\nfunction date_time($time = 0)\n{\n    if (!$time) $time = time();\n    return date(\"Y-m-d H:i:s\", $time);\n}\n\n// 获取系统语言\nfunction get_lang($path=\"../web/index.html\")\n{\n    $text = file_get_contents($path);\n    if( strstr($text , 'zh') ){\n        return 'zh-cn' ;\n    }else{\n        return 'en';\n    }\n}\n\n/**\n * 构造安全的 LIKE 模式串（跨库通用）\n * - 转义 LIKE 特殊字符：% 和 _ 以及反斜杠本身\n * - 防护 SQL 注入：转义单引号、双引号，过滤危险关键字\n * - 返回形如 %keyword% 的匹配模式\n * - 兼容参数化查询和直接字符串拼接两种使用方式\n * \n * @param string $keyword 搜索关键字\n * @param bool $strict 是否启用严格模式（过滤 SQL 关键字），默认 true\n * @return string 安全的 LIKE 模式串\n * \n * 用法：\n *   $like = safe_like($keyword);\n *   D(\"Item\")->where(\"name LIKE '%s'\", array($like))->select();\n * 或：\n *   D(\"Item\")->where(array('name' => array('like', $like)))->select();\n * 或（现在也安全）：\n *   $sql = \"SELECT * FROM items WHERE name LIKE '{$like}'\";\n */\nfunction safe_like($keyword, $strict = true)\n{\n    $s = (string)$keyword;\n    \n    // 0. 输入长度限制（防止过长的攻击载荷）\n    if (strlen($s) > 200) {\n        $s = substr($s, 0, 200);\n    }\n\n    // 1. 优先使用SQLite3原生转义函数\n    if (class_exists('SQLite3')) {\n        $s = SQLite3::escapeString($s);\n    } else {\n        // 备用方案：使用原来的手动转义逻辑\n        // 先转义反斜杠，避免后续再次转义造成歧义\n        $s = str_replace('\\\\', '\\\\\\\\', $s);\n        // 转义单引号和双引号（防止 SQL 注入）\n        $s = str_replace(\"'\", \"\\\\'\", $s);\n        $s = str_replace('\"', '\\\\\"', $s);\n    }\n\n    // 2. 转义 LIKE 特殊字符 % 和 _（数据库转义函数不处理这些）\n    $s = addcslashes($s, \"%_\");\n\n    // 4. 严格模式：过滤危险的 SQL 关键字和符号\n    if ($strict) {\n        // 移除或替换危险的 SQL 注释符号\n        $s = str_replace('--', '', $s);\n        $s = str_replace('#', '', $s);\n        $s = str_replace('/*', '', $s);\n        $s = str_replace('*/', '', $s);\n\n        // 移除分号（防止多语句执行）\n        $s = str_replace(';', '', $s);\n\n        // 过滤危险的 SQL 关键字（不区分大小写）\n        $dangerous_keywords = [\n            'SELECT',\n            'FROM',\n            'WHERE',\n            'DROP',\n            'DELETE',\n            'UPDATE',\n            'INSERT',\n            'CREATE',\n            'ALTER',\n            'TRUNCATE',\n            'EXEC',\n            'EXECUTE',\n            'UNION',\n            'SCRIPT',\n            'DECLARE',\n            'CAST',\n            'CONVERT',\n            'AND',\n            'OR',\n            'HAVING',\n            'GROUP',\n            'ORDER',\n            'LIMIT',\n            'OFFSET',\n            'INTO',\n            'SET',\n            'VALUES',\n            'TABLE',\n            'DATABASE',\n            'SCHEMA',\n            'INDEX',\n            'VIEW',\n            'PROCEDURE',\n            'FUNCTION',\n            'TRIGGER'\n        ];\n\n        foreach ($dangerous_keywords as $keyword_to_remove) {\n            $s = preg_replace('/\\b' . preg_quote($keyword_to_remove, '/') . '\\b/i', '', $s);\n        }\n\n        // 清理多余的空格\n        $s = preg_replace('/\\s+/', ' ', $s);\n        $s = trim($s);\n    }\n\n    return \"%{$s}%\";\n}"
  },
  {
    "path": "server/Application/Common/Common/index.html",
    "content": " "
  },
  {
    "path": "server/Application/Common/Conf/config.php",
    "content": "<?php\nreturn array(\n    //'配置项'=>'配置值'\n    //使用sqlite数据库\n    'DB_TYPE'   => 'Sqlite', \n    'DB_NAME'   => '../Sqlite/showdoc.db.php', \n    //showdoc不再支持mysql http://www.showdoc.cc/help?page_id=31990\n    'DB_HOST'   => 'localhost',\n    'DB_USER'   => 'showdoc', \n    'DB_PWD'    => 'showdoc123456',\n    'DB_PORT'   => 3306, // 端口\n    'DB_PREFIX' => '', // 数据库表前缀\n    'DB_CHARSET'=> 'utf8', // 字符集\n    'DB_DEBUG'  =>  TRUE, // 数据库调试模式 开启后可以记录SQL日志\n    'DB_PARAMS' => array(\n        PDO::ATTR_STRINGIFY_FETCHES => true, // 设置为true,强制把数字读取成字符串返回\n    ),\n    'URL_HTML_SUFFIX' => '',//url伪静态后缀\n    'URL_MODEL' => 3 ,//URL兼容模式\n    'URL_ROUTER_ON'   => true, \n    'URL_ROUTE_RULES'=>array(\n        'uid/:id\\d'               => 'Home/Item/showByUid?uid=:1',\n        'page/:id\\d'               => 'Home/Page/single?page_id=:1',\n        'mock-data/:unique_key\\s'               => 'Api/Mock/infoByKey?unique_key=:1',\n        'mock-path/:id\\s'               => 'Api/Mock/infoByPath?item_id=:1',\n        ':id\\d'               => 'Home/Item/show?item_id=:1',\n        ':domain\\s/:id\\d'               => 'Home/Page/single?item_domain=:1&page_id=:2',\n        ':domain\\s$'               => 'Home/Item/show?item_domain=:1',//item的个性域名\n    ),\n    'URL_CASE_INSENSITIVE'=>true,\n    'SHOW_ERROR_MSG'        =>  true,    // 显示错误信息，这样在部署模式下也能显示错误\n    'STATS_CODE' =>'',  //可选，统计代码\n    'TMPL_CACHE_ON' => false,//禁止模板编译缓存\n    'HTML_CACHE_ON' => false,//禁止静态缓存\n    'TMPL_EXCEPTION_FILE' => '../Public/exception.tpl' , //错误模版\n    //上传文件到七牛的配置\n    'UPLOAD_SITEIMG_QINIU' => array(\n                    'maxSize' => 5 * 1024 * 1024,//文件大小\n                    'rootPath' => './',\n                    'saveName' => array ('uniqid', ''),\n                    'driver' => 'Qiniu',\n                    'driverConfig' => array (\n                            'secrectKey' => '', \n                            'accessKey' => '',\n                            'domain' => '',\n                            'bucket' => '', \n                        )\n                    ),\n    'DATA_CACHE_KEY'=>'file_cache_safe',\n);"
  },
  {
    "path": "server/Application/Common/Conf/debug.php",
    "content": "<?php\n\n// 调试模式下面默认设置 可以在应用配置目录下重新定义 debug.php 覆盖\nreturn  array(\n    'LOG_RECORD'            =>  false,  // 进行日志记录\n    'LOG_EXCEPTION_RECORD'  =>  false,    // 是否记录异常信息日志\n    'LOG_LEVEL'             =>  'ERR',  // 允许记录的日志级别\n    'DB_FIELDS_CACHE'       =>  false, // 字段缓存信息\n    'DB_DEBUG'\t\t\t\t=>  false, // 开启调试模式 记录SQL日志\n    'TMPL_CACHE_ON'         =>  false,        // 是否开启模板编译缓存,设为false则每次都会重新编译\n    'TMPL_STRIP_SPACE'      =>  false,       // 是否去除模板文件里面的html空格与换行\n    'SHOW_ERROR_MSG'        =>  true,    // 显示错误信息\n    'URL_CASE_INSENSITIVE'  =>  false,  // URL区分大小写\n);"
  },
  {
    "path": "server/Application/Common/Conf/index.html",
    "content": " "
  },
  {
    "path": "server/Application/Common/index.html",
    "content": " "
  },
  {
    "path": "server/Application/Home/Common/index.html",
    "content": " "
  },
  {
    "path": "server/Application/Home/Conf/config.php",
    "content": "<?php \n    return array(\n    //'配置项'=>'配置值'\n    'DB_TYPE'   => 'Sqlite', \n    'DB_NAME'   => './Sqlite/showdoc.db.php', \n    'LANG_SWITCH_ON' => true,   // 开启语言包功能\n    'LANG_AUTO_DETECT' => false, // 自动侦测语言 开启多语言功能后有效\n    'DEFAULT_LANG' => 'zh-cn', // 默认语言\n    'LANG_LIST'        => 'zh-cn,en-us', // 允许切换的语言列表 用逗号分隔\n    'VAR_LANGUAGE'     => 'l', // 默认语言切换变量\n    );"
  },
  {
    "path": "server/Application/Home/Conf/index.html",
    "content": " "
  },
  {
    "path": "server/Application/Home/Conf/tags.php",
    "content": "<?php\nreturn array(\n    // 添加下面一行定义即可\n    'app_begin' => array('Behavior\\CheckLangBehavior'),\n);"
  },
  {
    "path": "server/Application/Home/Controller/BaseController.class.php",
    "content": "<?php\n\nnamespace Home\\Controller;\n\nuse Think\\Controller;\n\nclass BaseController extends Controller\n{\n\n\tpublic function message($msg, $redirect = '')\n\t{\n\t\t$this->assign(\"msg\", $msg);\n\t\t$this->assign(\"redirect\", $redirect);\n\t\t$this->display(\"Common/message\");\n\t}\n\n\tpublic function checkLogin($redirect = true)\n\t{\n\t\tif (strtolower(C(\"DB_TYPE\")) == 'mysql') {\n\t\t\techo 'ShowDoc does not support mysql any more . https://www.showdoc.cc/help?page_id=31990 ';\n\t\t\tclear_runtime();\n\t\t\texit();\n\t\t}\n\t\tif (!session(\"login_user\")) {\n\t\t\t$cookie_token = cookie('cookie_token');\n\t\t\tif ($cookie_token) {\n\t\t\t\t$ret = D(\"UserToken\")->getToken($cookie_token);\n\t\t\t\tif ($ret && $ret['token_expire'] > time()) {\n\t\t\t\t\t$login_user = D(\"User\")->where(array('uid' => $ret['uid']))->find();\n\t\t\t\t\tunset($ret['password']);\n\t\t\t\t\tsession(\"login_user\", $login_user);\n\t\t\t\t\treturn $login_user;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif ($redirect) {\n\t\t\t\t$this->message(\"你尚未登录！\", U('Home/User/login'));\n\t\t\t\texit();\n\t\t\t}\n\t\t} else {\n\t\t\treturn  session(\"login_user\");\n\t\t}\n\t}\n\n\t/**\n\t * 返回json数据\n\t */\n\tpublic function sendResult($array)\n\t{\n\t\tif (isset($array['error_code'])) {\n\t\t\t$result['error_code'] = $array['error_code'];\n\t\t\t$result['error_message'] = $array['error_message'];\n\t\t} else {\n\t\t\t$result['error_code'] = 0;\n\t\t\t$result['data'] = $array;\n\t\t}\n\t\techo json_encode($result);\n\t}\n\n\t//判断某用户是否有项目管理权限（项目成员member_group_id为1，以及 项目创建者）\n\tprotected function checkItemPermn($uid, $item_id)\n\t{\n\n\t\tif (!$uid) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (session(\"mamage_item_\" . $item_id)) {\n\t\t\treturn true;\n\t\t}\n\n\t\t$item = D(\"Item\")->where(\"item_id = '%d' \", array($item_id))->find();\n\t\tif ($item['uid'] && $item['uid'] == $uid) {\n\t\t\tsession(\"mamage_item_\" . $item_id, 1);\n\t\t\treturn true;\n\t\t}\n\t\t$ItemMember = D(\"ItemMember\")->where(\"item_id = '%d' and uid = '%d' and member_group_id = 1 \", array($item_id, $uid))->find();\n\t\tif ($ItemMember) {\n\t\t\tsession(\"mamage_item_\" . $item_id, 1);\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\t//判断某用户是否为项目创建者\n\tprotected function checkItemCreator($uid, $item_id)\n\t{\n\t\tif (!$uid) {\n\t\t\treturn false;\n\t\t}\n\t\tif (session(\"creat_item_\" . $item_id)) {\n\t\t\treturn true;\n\t\t}\n\n\t\t$item = D(\"Item\")->where(\"item_id = '%d' \", array($item_id))->find();\n\t\tif ($item['uid'] && $item['uid'] == $uid) {\n\t\t\tsession(\"creat_item_\" . $item_id, 1);\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\t//判断某用户是否有项目访问权限（公开项目的话所有人可访问，私有项目则项目成员、项目创建者和访问密码输入者可访问）\n\tprotected function checkItemVisit($uid, $item_id, $refer_url = '')\n\t{\n\t\tif (session(\"visit_item_\" . $item_id)) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif ($this->checkItemCreator($uid, $item_id)) {\n\t\t\tsession(\"visit_item_\" . $item_id, 1);\n\t\t\treturn true;\n\t\t}\n\n\t\t$ItemMember = D(\"ItemMember\")->where(\"item_id = '%d' and uid = '%d'  \", array($item_id, $uid))->find();\n\t\tif ($ItemMember) {\n\t\t\tsession(\"visit_item_\" . $item_id, 1);\n\t\t\treturn true;\n\t\t}\n\n\t\t$item = D(\"Item\")->where(\"item_id = '%d' \", array($item_id))->find();\n\t\tif ($item['password']) {\n\t\t\t//跳转到输入访问密码框\n\t\t\theader(\"location:\" . U(\"Home/item/pwd\", array(\"item_id\" => $item_id, \"refer_url\" => base64_encode($refer_url))));\n\t\t} else {\n\t\t\tsession(\"visit_item_\" . $item_id, 1);\n\t\t\treturn true;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "server/Application/Home/Controller/CommonController.class.php",
    "content": "<?php\n\nnamespace Home\\Controller;\n\nuse Think\\Controller;\n\nclass CommonController extends BaseController\n{\n\n\n    //保存\n    public function qrcode()\n    {\n        Vendor('Phpqrcode.phpqrcode');\n        $url = I(\"url\");\n        $url = urldecode($url) ? urldecode($url) : $url;\n        $size = I(\"size\") ? I(\"size\") : 6;\n        $object = new \\QRcode();\n        $object->png($url, false, 3, $size, 2);\n    }\n\n    public function checkForUpdate()\n    {\n        $option_data = D(\"Options\")->where(\"option_name='version' \")->find();\n        $post_data = array(\n            \"version\" => $option_data['option_value'],\n        );\n        $version = $option_data['option_value'];\n        // TODO 此功能是留着检测更新用的。未完成。代码有空再写吧\n        //$url = \"https://www.showdoc.cc/\";\n        //$result = http_post($url , $post_data);\n        //$version_num = str_replace(\"v\", '', $num);\n        //$result = version_compare($version_num, \"2.1.5\",'<');\n        //echo $result;\n\n    }\n\n\n    //重置管理员用户密码\n    //使用方式：\n    //若用官方自动脚本或者docker方式安装，则需在命令行里执行docker exec showdoc php  /var/www/html/index.php home/common/repasswd\n    //若是手动安装php环境的，则在命令行中切换到showdoc目录，执行php index.php home/common/repasswd\n    //执行后会把管理员用户showdoc的密码重置为123456\n    public function repasswd()\n    {\n        if (preg_match(\"/cli/i\", php_sapi_name())) {\n            if (D(\"User\")->where(\"username = 'showdoc' \")->find()) {\n                D(\"User\")->where(\"username = 'showdoc' \")->save(array(\"groupid\" => 1, 'password' => \"a89da13684490eb9ec9e613f91d24d00\", 'salt' => ''));\n            } else {\n                D(\"User\")->add(array('username' => \"showdoc\", \"groupid\" => 1, 'password' => \"a89da13684490eb9ec9e613f91d24d00\", 'salt' => '', 'reg_time' => time()));\n            }\n            echo \"ok \\n\";\n        } else {\n            echo \"please run in command line\";\n        }\n    }\n}\n"
  },
  {
    "path": "server/Application/Home/Controller/IndexController.class.php",
    "content": "<?php\n\nnamespace Home\\Controller;\n\nuse Think\\Controller;\n\nclass IndexController extends BaseController\n{\n\tpublic function index()\n\t{\n\n\t\t//不存在安装文件夹的，表示已经安装过\n\t\tif (!file_exists(\"./install\")) {\n\t\t\t//跳转到web目录\n\t\t\theader(\"location:./web/#/\");\n\t\t\texit();\n\t\t}\n\n\t\tif (file_exists(\"./install\") && file_exists(\"./install/install.lock\") && $this->new_is_writeable(\"./install\") && $this->new_is_writeable(\"./install/install.lock\")) {\n\t\t\t//跳转到web目录\n\t\t\theader(\"location:./web/#/\");\n\t\t\texit();\n\t\t}\n\t\t//其他情况都跳转到安装页面\n\t\theader(\"location:./install/index.php\");\n\t}\n\n\t/**\n\t * 判断 文件/目录 是否可写（取代系统自带的 is_writeable 函数）\n\t *\n\t * @param string $file 文件/目录\n\t * @return boolean\n\t */\n\tprivate function new_is_writeable($file)\n\t{\n\t\tif (is_dir($file)) {\n\t\t\t$dir = $file;\n\t\t\tif ($fp = @fopen(\"$dir/test.txt\", 'w')) {\n\t\t\t\t@fclose($fp);\n\t\t\t\t@unlink(\"$dir/test.txt\");\n\t\t\t\t$writeable = 1;\n\t\t\t} else {\n\t\t\t\t$writeable = 0;\n\t\t\t}\n\t\t} else {\n\t\t\tif ($fp = @fopen($file, 'a+')) {\n\t\t\t\t@fclose($fp);\n\t\t\t\t$writeable = 1;\n\t\t\t} else {\n\t\t\t\t$writeable = 0;\n\t\t\t}\n\t\t}\n\n\t\treturn $writeable;\n\t}\n}\n"
  },
  {
    "path": "server/Application/Home/Controller/ItemController.class.php",
    "content": "<?php\n\nnamespace Home\\Controller;\n\nuse Think\\Controller;\n\nclass ItemController extends BaseController\n{\n    //项目列表页\n    public function index()\n    {\n        $login_user = $this->checkLogin();\n\n        //跳转到web目录\n        header(\"location:./web/#/item/index\");\n        exit();\n\n        $share_url = get_domain() . __APP__ . '/uid/' . $login_user['uid'];\n\n        $this->assign(\"login_user\", $login_user);\n        $this->assign(\"share_url\", $share_url);\n        $this->display();\n    }\n\n    //根据项目类型展示项目\n    //这些参数都不需要用到，只是为了兼容父类的方法。php8需要compatible with父类的同名方法\n    public function show($content = '', $charset = '', $contentType = '', $prefix = '')\n    {\n        $this->checkLogin(false);\n        $item_id = I(\"item_id/d\");\n        $item_domain = I(\"item_domain/s\");\n        $current_page_id = I(\"page_id/d\");\n\n        //判断个性域名\n        if ($item_domain) {\n            $item = D(\"Item\")->where(\"item_domain = '%s'\", array($item_domain))->find();\n            if ($item['item_id']) {\n                $item_id = $item['item_id'];\n            }\n        }\n\n        //跳转到web目录\n        header(\"location:./web/#/\" . $item_id . \"?page_id=\" . $current_page_id);\n        exit();\n    }\n\n}\n"
  },
  {
    "path": "server/Application/Home/Controller/PageController.class.php",
    "content": "<?php\n\nnamespace Home\\Controller;\n\nuse Think\\Controller;\n\nclass PageController extends BaseController\n{\n\n    //展示某个项目的单个页面\n    public function index()\n    {\n        import(\"Vendor.Parsedown.Parsedown\");\n        $page_id = I(\"page_id/d\");\n        $this->assign(\"page_id\", $page_id);\n        $this->display();\n    }\n\n    //展示单个页面\n    public function single()\n    {\n        $page_id = I(\"page_id/d\");\n\n        //跳转到web目录\n        header(\"location:./web/#/page/\" . $page_id);\n        exit();\n    }\n}\n"
  },
  {
    "path": "server/Application/Home/Controller/UpdateController.class.php",
    "content": "<?php\n\nnamespace Home\\Controller;\n\nuse Think\\Controller;\n\nclass UpdateController extends BaseController\n{\n\n    //此文件不再维护。升级数据库的脚本改到了API/UpdateController\n\n    //升级数据库\n    public function db()\n    {\n        $this->_clear_runtime();\n        if (strtolower(C(\"DB_TYPE\")) == 'mysql') {\n            //$this->mysql();\n            echo 'ShowDoc does not support mysql any more . https://www.showdoc.cc/help?page_id=31990 ';\n        } elseif (strtolower(C(\"DB_TYPE\")) == 'sqlite') {\n            $this->sqlite();\n        }\n        $this->_clear_runtime();\n    }\n    public function sqlite()\n    {\n        //catalog表增加parent_cat_id字段\n        if (!$this->_is_column_exist(\"catalog\", \"parent_cat_id\")) {\n            $sql = \"ALTER TABLE \" . C('DB_PREFIX') . \"catalog ADD parent_cat_id INT( 10 ) NOT NULL DEFAULT '0' ;\";\n            D(\"catalog\")->execute($sql);\n        }\n\n        //catalog表增加level字段\n        if (!$this->_is_column_exist(\"catalog\", \"level\")) {\n            $sql = \"ALTER TABLE \" . C('DB_PREFIX') . \"catalog ADD level INT( 10 ) NOT NULL DEFAULT '2'  ;\";\n            D(\"catalog\")->execute($sql);\n        }\n\n\n        //item表增加item_domain字段\n        if (!$this->_is_column_exist(\"item\", \"item_domain\")) {\n            $sql = \"ALTER TABLE \" . C('DB_PREFIX') . \"item ADD item_domain text NOT NULL DEFAULT '';\";\n            D(\"catalog\")->execute($sql);\n        }\n\n        //创建user_token表\n        $sql = \"CREATE TABLE IF NOT EXISTS `user_token` (\n        `id`  INTEGER PRIMARY KEY ,\n        `uid` int(10) NOT NULL DEFAULT '0',\n        `token` CHAR(200) NOT NULL DEFAULT '',\n        `token_expire` int(11) NOT NULL DEFAULT '0' ,\n        `ip` CHAR(200) NOT NULL DEFAULT '',\n        `addtime` int(11) NOT NULL DEFAULT '0'\n        )\";\n        D(\"UserToken\")->execute($sql);\n\n        //创建template表\n        $sql = \"CREATE TABLE IF NOT EXISTS `template` (\n        `id`  INTEGER PRIMARY KEY ,\n        `uid` int(10) NOT NULL DEFAULT '0',\n        `username` CHAR(200) NOT NULL DEFAULT '',\n        `template_title` CHAR(200) NOT NULL DEFAULT '' ,\n        `template_content` text NOT NULL DEFAULT '',\n        `addtime` int(11) NOT NULL DEFAULT '0'\n        )\";\n        D(\"UserToken\")->execute($sql);\n\n        //page表增加page_comments字段\n        if (!$this->_is_column_exist(\"page\", \"page_comments\")) {\n            $sql = \"ALTER TABLE \" . C('DB_PREFIX') . \"page ADD page_comments text NOT NULL DEFAULT ''  ;\";\n            D(\"catalog\")->execute($sql);\n        }\n\n\n        //page_history 表增加page_comments字段\n        if (!$this->_is_column_exist(\"PageHistory\", \"page_comments\")) {\n            $sql = \"ALTER TABLE \" . C('DB_PREFIX') . \"page_history ADD page_comments text NOT NULL DEFAULT '';\";\n            D(\"catalog\")->execute($sql);\n        }\n\n\n        //item_member表增加member_group_id字段\n        if (!$this->_is_column_exist(\"ItemMember\", \"member_group_id\")) {\n            $sql = \"ALTER TABLE \" . C('DB_PREFIX') . \"item_member ADD member_group_id INT( 1 ) NOT NULL DEFAULT '1'  ;\";\n            D(\"ItemMember\")->execute($sql);\n        }\n\n\n        //item表增加item_type字段\n        if (!$this->_is_column_exist(\"Item\", \"item_type\")) {\n            $sql = \"ALTER TABLE \" . C('DB_PREFIX') . \"item ADD item_type INT( 1 ) NOT NULL DEFAULT '1'  ;\";\n            D(\"ItemMember\")->execute($sql);\n        }\n\n        //创建options表\n        $sql = \"CREATE TABLE IF NOT EXISTS `options` (\n        `option_id`  INTEGER PRIMARY KEY ,\n        `option_name` CHAR(200) NOT NULL UNIQUE ,\n        `option_value` CHAR(200) NOT NULL \n        )\";\n        D(\"UserToken\")->execute($sql);\n\n        //创建item_token表\n        $sql = \"CREATE TABLE IF NOT EXISTS `item_token` (\n        `id`  INTEGER PRIMARY KEY ,\n        `item_id` int(11) NOT NULL DEFAULT '0' ,\n        `api_key` CHAR(200) NOT NULL UNIQUE ,\n        `api_token` CHAR(200) NOT NULL ,\n        `addtime` int(11) NOT NULL DEFAULT '0' ,\n        `last_check_time` int(11) NOT NULL DEFAULT '0' \n        )\";\n        D(\"UserToken\")->execute($sql);\n\n        //创建item_top表\n        $sql = \"CREATE TABLE IF NOT EXISTS `item_top` (\n        `id`  INTEGER PRIMARY KEY ,\n        `item_id` int(11) NOT NULL DEFAULT '0' ,\n        `uid` int(11) NOT NULL DEFAULT '0' ,\n        `addtime` int(11) NOT NULL DEFAULT '0' \n        )\";\n        D(\"UserToken\")->execute($sql);\n\n        //item表增加is_archived字段\n        if (!$this->_is_column_exist(\"Item\", \"is_archived\")) {\n            $sql = \"ALTER TABLE \" . C('DB_PREFIX') . \"item ADD is_archived INT( 1 ) NOT NULL DEFAULT '0'  ;\";\n            D(\"ItemMember\")->execute($sql);\n        }\n\n\n        //管理员账户和权限\n        if (D(\"User\")->where(\"username = 'showdoc' \")->find()) {\n            D(\"User\")->where(\"username = 'showdoc' \")->save(array(\"groupid\" => 1));\n        } else {\n            D(\"User\")->add(array('username' => \"showdoc\", \"groupid\" => 1, 'password' => \"a89da13684490eb9ec9e613f91d24d00\", 'reg_time' => time()));\n        }\n\n        //item表增加is_del字段\n        if (!$this->_is_column_exist(\"Item\", \"is_del\")) {\n            $sql = \"ALTER TABLE \" . C('DB_PREFIX') . \"item ADD is_del INT( 1 ) NOT NULL DEFAULT '0'  ;\";\n            D(\"ItemMember\")->execute($sql);\n        }\n\n        //page表增加is_del字段\n        if (!$this->_is_column_exist(\"Page\", \"is_del\")) {\n            $sql = \"ALTER TABLE \" . C('DB_PREFIX') . \"page ADD is_del INT( 1 ) NOT NULL DEFAULT '0'  ;\";\n            D(\"ItemMember\")->execute($sql);\n        }\n\n        //创建team表\n        $sql = \"CREATE TABLE IF NOT EXISTS `team` (\n        `id`  INTEGER PRIMARY KEY ,\n        `team_name` CHAR(200) NOT NULL DEFAULT '',\n        `uid` int(11) NOT NULL DEFAULT '0' ,\n        `username` CHAR(200) NOT NULL DEFAULT '',\n        `addtime` int(11) NOT NULL DEFAULT '0' ,\n        `last_update_time` int(11) NOT NULL DEFAULT '0' \n        )\";\n        D(\"User\")->execute($sql);\n\n        //创建team_item表\n        $sql = \"CREATE TABLE IF NOT EXISTS `team_item` (\n        `id`  INTEGER PRIMARY KEY ,\n        `team_id` int(11) NOT NULL DEFAULT '0' ,\n        `item_id` int(11) NOT NULL DEFAULT '0' ,\n        `addtime` int(11) NOT NULL DEFAULT '0' ,\n        `last_update_time` int(11) NOT NULL DEFAULT '0' \n        )\";\n        D(\"User\")->execute($sql);\n\n        //创建team_item_member表\n        $sql = \"CREATE TABLE IF NOT EXISTS `team_item_member` (\n        `id`  INTEGER PRIMARY KEY ,\n        `team_id` int(11) NOT NULL DEFAULT '0' ,\n        `item_id` int(11) NOT NULL DEFAULT '0' ,\n        `member_group_id` int(11) NOT NULL DEFAULT '0' ,\n        `member_uid` int(11) NOT NULL DEFAULT '0' ,\n        `member_username` CHAR(200) NOT NULL DEFAULT '',\n        `addtime` int(11) NOT NULL DEFAULT '0' ,\n        `last_update_time` int(11) NOT NULL DEFAULT '0' \n        )\";\n        D(\"User\")->execute($sql);\n\n        //创建team_member表\n        $sql = \"CREATE TABLE IF NOT EXISTS `team_member` (\n        `id`  INTEGER PRIMARY KEY ,\n        `team_id` int(11) NOT NULL DEFAULT '0' ,\n        `member_uid` int(11) NOT NULL DEFAULT '0' ,\n        `member_username` CHAR(200) NOT NULL DEFAULT '',\n        `addtime` int(11) NOT NULL DEFAULT '0' ,\n        `last_update_time` int(11) NOT NULL DEFAULT '0' \n        )\";\n        D(\"User\")->execute($sql);\n\n        //创建upload_file表\n        $sql = \"CREATE TABLE IF NOT EXISTS `upload_file` (\n        `file_id`  INTEGER PRIMARY KEY ,\n        `sign` CHAR(200) NOT NULL DEFAULT '',\n        `display_name` CHAR(200) NOT NULL DEFAULT '',\n        `file_type` CHAR(200) NOT NULL DEFAULT '',\n        `file_size` CHAR(200) NOT NULL DEFAULT '',\n        `uid` int(11) NOT NULL DEFAULT '0' ,\n        `page_id` int(11) NOT NULL DEFAULT '0' ,\n        `item_id` int(11) NOT NULL DEFAULT '0' ,\n        `visit_times` int(11) NOT NULL DEFAULT '0' ,\n        `addtime` int(11) NOT NULL DEFAULT '0' ,\n        `real_url` CHAR(200) NOT NULL DEFAULT '',\n        `last_update_time` int(11) NOT NULL DEFAULT '0' \n        )\";\n        D(\"User\")->execute($sql);\n\n        //创建item_sort表\n        $sql = \"CREATE TABLE IF NOT EXISTS `item_sort` (\n        `id`  INTEGER PRIMARY KEY ,\n        `uid` int(10) NOT NULL DEFAULT '0',\n        `item_sort_data` text NOT NULL DEFAULT '',\n        `addtime` int(11) NOT NULL DEFAULT '0'\n        )\";\n        D(\"UserToken\")->execute($sql);\n\n        //创建single_page表\n        $sql = \"CREATE TABLE IF NOT EXISTS `single_page` (\n        `id`  INTEGER PRIMARY KEY ,\n        `unique_key` CHAR(200) NOT NULL DEFAULT '',\n        `page_id` int(11) NOT NULL DEFAULT '0'\n        )\";\n        D(\"User\")->execute($sql);\n\n        //创建captcha表\n        $sql = \"CREATE TABLE IF NOT EXISTS `captcha` (\n        `captcha_id`  INTEGER PRIMARY KEY ,\n        `mobile` CHAR(200) NOT NULL DEFAULT '',\n        `captcha` CHAR(200) NOT NULL DEFAULT '',\n        `expire_time` int(11) NOT NULL DEFAULT '0'\n        )\";\n        D(\"User\")->execute($sql);\n\n        //创建recycle表\n        $sql = \"CREATE TABLE IF NOT EXISTS `recycle` (\n        `id`  INTEGER PRIMARY KEY ,\n        `item_id` int(11) NOT NULL DEFAULT '0',\n        `page_id` int(11) NOT NULL DEFAULT '0',\n        `page_title` CHAR(200) NOT NULL DEFAULT '',\n        `del_by_uid` int(11) NOT NULL DEFAULT '0',\n        `del_by_username` CHAR(200) NOT NULL DEFAULT '',\n        `del_time` int(11) NOT NULL DEFAULT '0'\n        )\";\n        D(\"User\")->execute($sql);\n\n        //创建page_lock表\n        $sql = \"CREATE TABLE IF NOT EXISTS `page_lock` (\n            `id`  INTEGER PRIMARY KEY ,\n            `page_id` int(11) NOT NULL DEFAULT '0',\n            `lock_uid` int(11) NOT NULL DEFAULT '0',\n            `lock_username` CHAR(200) NOT NULL DEFAULT '',\n            `lock_to` int(11) NOT NULL DEFAULT '0',\n            `addtime` int(11) NOT NULL DEFAULT '0'\n            )\";\n        D(\"User\")->execute($sql);\n\n        //item_member表增加cat_id字段\n        if (!$this->_is_column_exist(\"item_member\", \"cat_id\")) {\n            $sql = \"ALTER TABLE \" . C('DB_PREFIX') . \"item_member ADD cat_id INT( 10 ) NOT NULL DEFAULT '0'  ;\";\n            D(\"User\")->execute($sql);\n        }\n\n        //team_item_member表增加cat_id字段\n        if (!$this->_is_column_exist(\"team_item_member\", \"cat_id\")) {\n            $sql = \"ALTER TABLE \" . C('DB_PREFIX') . \"team_item_member ADD cat_id INT( 10 ) NOT NULL DEFAULT '0'  ;\";\n            D(\"User\")->execute($sql);\n        }\n\n        //创建item_variable表\n        $sql = \"CREATE TABLE IF NOT EXISTS `item_variable` (\n            `id`  INTEGER PRIMARY KEY ,\n            `var_name` CHAR(2000) NOT NULL DEFAULT '',\n            `var_value` CHAR(2000) NOT NULL DEFAULT '',\n            `uid` int(11) NOT NULL DEFAULT '0',\n            `item_id` int(11) NOT NULL DEFAULT '0',\n            `addtime` int(11) NOT NULL DEFAULT '0'\n            )\";\n        D(\"User\")->execute($sql);\n\n\n        echo \"OK!\\n\";\n    }\n\n    private function _is_column_exist($table, $column)\n    {\n        $has_it = false; //是否存在该字段\n        $columns = M($table)->getDbFields();\n        if ($columns) {\n            foreach ($columns as $key => $value) {\n                if ($value == $column) {\n                    $has_it = true;\n                }\n            }\n        }\n        return $has_it;\n    }\n\n\n    private function _clear_runtime($path = RUNTIME_PATH)\n    {\n        //给定的目录不是一个文件夹  \n        if (!is_dir($path)) {\n            return null;\n        }\n\n        $fh = opendir($path);\n        while (($row = readdir($fh)) !== false) {\n            //过滤掉虚拟目录  \n            if ($row == '.' || $row == '..' || $row == 'index.html') {\n                continue;\n            }\n\n            if (!is_dir($path . '/' . $row)) {\n                unlink($path . '/' . $row);\n            }\n            $this->_clear_runtime($path . '/' . $row);\n        }\n        //关闭目录句柄，否则出Permission denied  \n        closedir($fh);\n        return true;\n    }\n\n    //转移mysql的数据到sqlite\n    public function toSqlite()\n    {\n        $this->_clear_runtime();\n        if (strtolower(C(\"DB_TYPE\")) == 'mysql') {\n            $this->mysql();\n            $this->_moveTable(\"catalog\");\n            $this->_moveTable(\"item\");\n            $this->_moveTable(\"item_member\");\n            $this->_moveTable(\"page\");\n            $this->_moveTable(\"page_history\");\n            $this->_moveTable(\"template\");\n            $this->_moveTable(\"user\");\n            $this->_moveTable(\"user_token\");\n            $db_config = array(\n                'DB_TYPE'   => 'Sqlite',\n                'DB_NAME'   => 'Sqlite/showdoc.db.php',\n            );\n            $array = M(\"item\")->db(2, $db_config)->select();\n            if ($array) {\n                echo \"ok\";\n            } else {\n                echo 'fail';\n            }\n        } else {\n            echo \"mysql not found\";\n        }\n        $this->_clear_runtime();\n    }\n\n    //升级mysql数据库  \n    public function mysql()\n    {\n\n        //user表的username字段增大了长度，防止长邮箱的用户名注册不了\n        $sql = \"alter table \" . C('DB_PREFIX') . \"user modify column username varchar(50) CHARACTER SET utf8 NOT NULL DEFAULT '' \";\n        M(\"Catalog\")->execute($sql);\n\n        //item表增加last_update_time字段\n        $columns = M(\"item\")->getDbFields();\n        if ($columns) {\n            $has_it = 0; //是否存在该字段\n            foreach ($columns as $key => $value) {\n                if ($value == 'last_update_time') {\n                    $has_it = 1;\n                }\n            }\n            if ($has_it === 0) {\n                $sql = \"ALTER TABLE \" . C('DB_PREFIX') . \"item ADD last_update_time INT( 11 ) NOT NULL DEFAULT '0' COMMENT '最后更新时间';\";\n                D(\"Item\")->execute($sql);\n            }\n        }\n\n\n        //更改catalog表的order字段名为s_number\n        $columns = M(\"Catalog\")->getDbFields();\n        if ($columns) {\n            foreach ($columns as $key => $value) {\n                if ($value == 'order') {\n                    $sql = \"ALTER TABLE  `\" . C('DB_PREFIX') . \"catalog` CHANGE  `order`  `s_number` INT( 10 ) NOT NULL DEFAULT  '99' COMMENT  '顺序号。数字越小越靠前。若此值全部相等时则按id排序';\";\n                    M(\"Catalog\")->execute($sql);\n                }\n            }\n        }\n\n        //更改page表的order字段名为s_number\n        $columns = M(\"Page\")->getDbFields();\n        if ($columns) {\n            foreach ($columns as $key => $value) {\n                if ($value == 'order') {\n                    $sql = \"ALTER TABLE  `\" . C('DB_PREFIX') . \"page` CHANGE  `order`  `s_number` INT( 10 ) NOT NULL DEFAULT  '99' COMMENT  '顺序号。数字越小越靠前。若此值全部相等时则按id排序';\";\n                    M(\"Page\")->execute($sql);\n                }\n            }\n        }\n\n        //更改page_history表的order字段名为s_number\n        $columns = M(\"PageHistory\")->getDbFields();\n        if ($columns) {\n            foreach ($columns as $key => $value) {\n                if ($value == 'order') {\n                    $sql = \"ALTER TABLE  `\" . C('DB_PREFIX') . \"page_history` CHANGE  `order`  `s_number` INT( 10 ) NOT NULL DEFAULT  '99' COMMENT  '顺序号。数字越小越靠前。若此值全部相等时则按id排序';\";\n                    M(\"PageHistory\")->execute($sql);\n                }\n            }\n        }\n\n        //为catalog表增加addtime索引\n        $indexs = M(\"Catalog\")->query(\" show index from \" . C('DB_PREFIX') . \"catalog\");\n        if ($indexs) {\n            $has_it = 0; //是否存在该索引\n            foreach ($indexs as $key => $value) {\n                if ($value['column_name'] == 'addtime') {\n                    $has_it = 1;\n                }\n            }\n            if ($has_it === 0) {\n                M(\"Catalog\")->execute(\"ALTER TABLE \" . C('DB_PREFIX') . \"catalog ADD INDEX ( `addtime` ) ;\");\n            }\n        }\n\n        //为item表增加addtime索引\n        $indexs = M(\"Item\")->query(\" show index from \" . C('DB_PREFIX') . \"item\");\n        if ($indexs) {\n            $has_it = 0; //是否存在该索引\n            foreach ($indexs as $key => $value) {\n                if ($value['column_name'] == 'addtime') {\n                    $has_it = 1;\n                }\n            }\n            if ($has_it === 0) {\n                M(\"Item\")->execute(\"ALTER TABLE \" . C('DB_PREFIX') . \"item ADD INDEX ( `addtime` ) ;\");\n            }\n        }\n\n        //为page表增加addtime索引\n        $indexs = M(\"Page\")->query(\" show index from \" . C('DB_PREFIX') . \"page\");\n        if ($indexs) {\n            $has_it = 0; //是否存在该索引\n            foreach ($indexs as $key => $value) {\n                if ($value['column_name'] == 'addtime') {\n                    $has_it = 1;\n                }\n            }\n            if ($has_it === 0) {\n                M(\"page\")->execute(\"ALTER TABLE \" . C('DB_PREFIX') . \"page ADD INDEX ( `addtime` ) ;\");\n            }\n        }\n\n        //为page_history表增加addtime索引\n        $indexs = M(\"PageHistory\")->query(\" show index from \" . C('DB_PREFIX') . \"page_history\");\n        if ($indexs) {\n            $has_it = 0; //是否存在该索引\n            foreach ($indexs as $key => $value) {\n                if ($value['column_name'] == 'addtime') {\n                    $has_it = 1;\n                }\n            }\n            if ($has_it === 0) {\n                M(\"PageHistory\")->execute(\"ALTER TABLE \" . C('DB_PREFIX') . \"page_history ADD INDEX ( `addtime` ) ;\");\n            }\n        }\n\n        //为page_history表增加page_id索引\n        $indexs = M(\"PageHistory\")->query(\" show index from \" . C('DB_PREFIX') . \"page_history\");\n        if ($indexs) {\n            $has_it = 0; //是否存在该索引\n            foreach ($indexs as $key => $value) {\n                if ($value['column_name'] == 'page_id') {\n                    $has_it = 1;\n                }\n            }\n            if ($has_it === 0) {\n                M(\"PageHistory\")->execute(\"ALTER TABLE \" . C('DB_PREFIX') . \"page_history ADD INDEX ( `page_id` ) ;\");\n            }\n        }\n\n\n        //catalog表增加parent_cat_id字段\n        $columns = M(\"catalog\")->getDbFields();\n        if ($columns) {\n            $has_it = 0; //是否存在该字段\n            foreach ($columns as $key => $value) {\n                if ($value == 'parent_cat_id') {\n                    $has_it = 1;\n                }\n            }\n            if ($has_it === 0) {\n                $sql = \"ALTER TABLE \" . C('DB_PREFIX') . \"catalog ADD parent_cat_id INT( 10 ) NOT NULL DEFAULT '0' COMMENT '上一级目录的id';\";\n                D(\"catalog\")->execute($sql);\n            }\n        }\n\n        //catalog表增加level字段\n        $columns = M(\"catalog\")->getDbFields();\n        if ($columns) {\n            $has_it = 0; //是否存在该字段\n            foreach ($columns as $key => $value) {\n                if ($value == 'level') {\n                    $has_it = 1;\n                }\n            }\n            if ($has_it === 0) {\n                $sql = \"ALTER TABLE \" . C('DB_PREFIX') . \"catalog ADD level INT( 10 ) NOT NULL DEFAULT '2' COMMENT '2为二级目录，3为三级目录';\";\n                D(\"catalog\")->execute($sql);\n            }\n        }\n        //item表增加item_domain字段\n        $columns = M(\"item\")->getDbFields();\n        if ($columns) {\n            $has_it = 0; //是否存在该字段\n            foreach ($columns as $key => $value) {\n                if ($value == 'item_domain') {\n                    $has_it = 1;\n                }\n            }\n            if ($has_it === 0) {\n                $sql = \"ALTER TABLE \" . C('DB_PREFIX') . \"item ADD item_domain varchar( 50 ) NOT NULL DEFAULT '' COMMENT 'item的个性域名';\";\n                D(\"item\")->execute($sql);\n            }\n        }\n\n        $sql = \"CREATE TABLE IF NOT EXISTS `\" . C('DB_PREFIX') . \"user_token` (\n        `id` int(10) NOT NULL AUTO_INCREMENT,\n        `uid` int(10) NOT NULL DEFAULT '0',\n        `token` varchar(200) NOT NULL DEFAULT '',\n        `token_expire` int(11) NOT NULL DEFAULT '0' ,\n        `ip` varchar(200) NOT NULL DEFAULT '',\n        `addtime` int(11) NOT NULL DEFAULT '0',\n        PRIMARY KEY (`id`),\n        KEY `token` (`token`)\n        ) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COMMENT='' AUTO_INCREMENT=1 \";\n        D(\"User\")->execute($sql);\n\n        //创建template表\n        $sql = \"CREATE TABLE IF NOT EXISTS `\" . C('DB_PREFIX') . \"template` (\n        `id` int(10) NOT NULL AUTO_INCREMENT,\n        `uid` int(10) NOT NULL DEFAULT '0',\n        `username` varchar(200) NOT NULL DEFAULT '',\n        `template_title` varchar(200) NOT NULL DEFAULT '' ,\n        `template_content` text NOT NULL ,\n        `addtime` int(11) NOT NULL DEFAULT '0',\n        PRIMARY KEY (`id`),\n        KEY `uid` (`uid`)\n        )ENGINE=MyISAM  DEFAULT CHARSET=utf8 COMMENT='' AUTO_INCREMENT=1\";\n        D(\"UserToken\")->execute($sql);\n\n        //page表增加page_comments字段\n        $columns = M(\"Page\")->getDbFields();\n        if ($columns) {\n            $has_it = 0; //是否存在该字段\n            foreach ($columns as $key => $value) {\n                if ($value == 'page_comments') {\n                    $has_it = 1;\n                }\n            }\n            if ($has_it === 0) {\n                $sql = \"ALTER TABLE \" . C('DB_PREFIX') . \"page ADD page_comments varchar( 255 ) NOT NULL DEFAULT '' COMMENT '页面注释';\";\n                D(\"Page\")->execute($sql);\n            }\n        }\n        //page_history表增加page_comments字段\n        $columns = M(\"PageHistory\")->getDbFields();\n        if ($columns) {\n            $has_it = 0; //是否存在该字段\n            foreach ($columns as $key => $value) {\n                if ($value == 'page_comments') {\n                    $has_it = 1;\n                }\n            }\n            if ($has_it === 0) {\n                $sql = \"ALTER TABLE \" . C('DB_PREFIX') . \"page_history ADD page_comments varchar( 255 ) NOT NULL DEFAULT '' COMMENT '页面注释';\";\n                D(\"PageHistory\")->execute($sql);\n            }\n        }\n\n        if (D(\"User\")->where(\"uid = 1 \")->find()) {\n            $db_config = array(\n                'DB_TYPE'   => 'Sqlite',\n                'DB_NAME'   => 'Sqlite/showdoc.db.php',\n            );\n            M(\"User\")->db(2, $db_config)->where(\"uid = 1 \")->delete();\n        }\n    }\n\n    private function _moveTable($table)\n    {\n        $db_config = array(\n            'DB_TYPE'   => 'Sqlite',\n            'DB_NAME'   => 'Sqlite/showdoc.db.php',\n        );\n        $array = M($table)->select();\n        if ($array) {\n            foreach ($array as $key => $value) {\n                M($table)->db(2, $db_config)->add($value);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "server/Application/Home/Controller/UserController.class.php",
    "content": "<?php\n\nnamespace Home\\Controller;\n\nuse Think\\Controller;\n\nclass UserController extends BaseController\n{\n\n\n\t//注册\n\tpublic function register()\n\t{\n\n\t\t//跳转到web目录\n\t\theader(\"location:./web/#/user/register\");\n\t\texit();\n\n\t}\n\n\n\n\t//登录\n\tpublic function login()\n\t{\n\n\t\t//跳转到web目录\n\t\theader(\"location:./web/#/user/login\");\n\t\texit();\n\n\t}\n\n\t//生成验证码\n\tpublic function verify()\n\t{\n\t\t//生成验证码图片\n\t\tHeader(\"Content-type: image/PNG\");\n\t\t$im = imagecreate(44, 18); // 画一张指定宽高的图片\n\t\t$back = ImageColorAllocate($im, 245, 245, 245); // 定义背景颜色\n\t\timagefill($im, 0, 0, $back); //把背景颜色填充到刚刚画出来的图片中\n\t\t$vcodes = \"\";\n\t\tsrand((float)microtime() * 1000000);\n\t\t//生成4位数字\n\t\tfor ($i = 0; $i < 4; $i++) {\n\t\t\t$font = ImageColorAllocate($im, rand(100, 255), rand(0, 100), rand(100, 255)); // 生成随机颜色\n\t\t\t$authnum = rand(1, 9);\n\t\t\t$vcodes .= $authnum;\n\t\t\timagestring($im, 5, 2 + $i * 10, 1, $authnum, $font);\n\t\t}\n\t\t$_SESSION['v_code'] = $vcodes;\n\n\t\tfor ($i = 0; $i < 200; $i++) //加入干扰象素\n\t\t{\n\t\t\t$randcolor = ImageColorallocate($im, rand(0, 255), rand(0, 255), rand(0, 255));\n\t\t\timagesetpixel($im, rand() % 70, rand() % 30, $randcolor); // 画像素点函数\n\t\t}\n\t\tImagePNG($im);\n\t\tImageDestroy($im);\n\t}\n\n\t//退出登录\n\tpublic function exist()\n\t{\n\t\t$login_user = $this->checkLogin();\n\t\tsession(\"login_user\", NULL);\n\t\tcookie('cookie_token', NULL);\n\t\tsession(null);\n\t\t$this->message(L('logout_succeeded'), U('Home/index/index'));\n\t}\n}\n"
  },
  {
    "path": "server/Application/Home/Controller/index.html",
    "content": " "
  },
  {
    "path": "server/Application/Home/Lang/en-us.php",
    "content": "<?php\nreturn array(\n\n    //Attorn\n    'attorn_item'=>'Attorn item',\n    'username'=>'Username',\n    'receiver_name'=>\"Receiver's username\",\n    'verify_identity'=>'Verify identity',\n    'your_password'=>'Your password',\n    'attorn'=>'Attorn',\n    'close'=>'close',\n\n    //Catalog\n    'new_or_edit_catalog' => 'New/Edit catalog',\n    'catalog_name' => 'Catalog name',\n    's_number' => 'Order',\n    's_number_explain' => 'Optional: order number',\n    'last_catalog' => 'Parent catalog',\n    'save' => 'Sava',\n    'delete_catalog' => 'Delete catalog',\n    'catalog_list' => 'Catalog list',\n    'click_to_edit' => 'Click to edit',\n\n\n    //index\n    'help' => 'Help',\n    'demo' => 'Demo',\n    'index_login_or_register' => 'Login / Register',\n    'my_item' => 'My items',\n    'section_title1' => 'ShowDoc',\n    'section_description1' => ' A tool greatly applicable for an IT team',\n    'section_title2' => 'API Document',\n    'section_description2' => 'ShowDoc can compile exquisite API documents <br>in a very fast and convenient way',\n    'section_title3' => 'Data Dictionary',\n    'section_description3' => 'A good Data Dictionary can easily exhibit database structure to other people<br>ShowDoc can compile exquisite Data Dictionary',\n    'section_title4' => 'Explanation Document',\n    'section_description4' => 'You can absolutely use ShowDoc to compile the explanation documents for some tools',\n    'section_title5' => 'Team Work',\n    'section_description5' => 'Your team will work with ShowDoc together very well ',\n    'section_title6' => 'Open Source',\n    'section_description6' => 'ShowDoc is a free, open source tool that <br>you can deploy it to your own server',\n    'section_title7' => 'Hosted online',\n    'section_description7' => 'Www.showdoc.cc provide security and stability of the document hosting service',\n    'section_title8' => 'Try it now',\n    'section_description8' => 'Over 6000+ IT team is using ShowDoc',\n\n\n    //Common message\n    'redirect_message' => 'If your browser does not automatically jump, please click on this link.',\n    'click_to_goback' => 'Click to goback',\n    'home' => 'Home',\n    \n\n    //item/add\n    'item_name' => \"Item's name\",\n    'item_description' => \"Item's description\",\n    'item_domain' => '(Optional)domain hack',\n    'item_domain_illegal' => 'Domain hack must be a combination of letters and numbers',\n    'domain_already_exists' => 'Domain already exists',\n    'visit_password_placeholder' => 'Access password(Optional: private project required)',\n    'submit' => 'Submit',\n    'goback' => 'Goback',\n    //item/delete\n    'delete_item' => 'Delete item',\n    'verify_your_identity' => 'Verify your identity',\n    'creator_password' => \"creator's password\",\n    'delete' => 'Delete',\n    'close' => 'Close',\n    //item/index\n    'personal_setting'=>'Personal setting',\n    'share_home'=>'Share home',\n    'web_home'=>'Website home',\n    'logout'=>'Logout',\n    'add_an_item'=>'Add an item',\n    'new_item'=>'New item',\n    'share_my_home'=>'Share my home',\n    'feedback' => \"feedback\",\n    'home_address'=>'Home address',\n    'home_address_description'=>'The others will be able to see all of your public items When he visits your home page.You can copy the address to your friends.',\n    //item/pwd\n    'input_visit_password'=>'Please enter the access password',\n    'password'=>'Passwod',\n    'verification_code'=>'Verification code',\n    'submit'=>'Submit',\n    'login_or_register'=>'Login/Register',\n    //item/show\n    'item'=>'Item',\n    'share'=>'Share',\n    'export'=>'Export',\n    'update_info'=>'Modify',\n    'manage_members'=>'Members',\n    'attorn'=>'Attorn',\n    'delete'=>'Delete',\n    'more_item'=>'More items',\n    'login_or_register'=>'Login/Register',\n    'about_showdoc'=>'About ShowDoc',\n    'my_item'=>'My items',\n    'new_page'=>'New page',\n    'new_catalog'=>'New catalog',\n    'share_address_to_your_friends'=>'Share address to your friends',\n    'share'=>'Share',\n    'copy_interface_to_new'=>'Copy page  to new ',\n    'copy'=>'Copy',\n    'edit_interface'=>'Edit page',\n    'edit'=>'Edit',\n    'delete_interface'=>'Delete page',\n    'comfirm_delete'=>'Are you sure that you want to delete it?',\n    'delete'=>'Delete',\n    'share'=>'Share',\n    'item_address'=>'Item address',\n    'copy_address_to_your_friends'=>'You can copy the address to your friend.',\n    'share_page'=>'Share page',\n    'page_address'=>'Page address',\n    'copy_address_to_your_friends'=>'You can copy the address to your friend.',\n    //item/showbyuid\n    'more'=>'More',\n    'my_item'=>'My items',\n    'login_or_register'=>'Login/Register',\n    'about_showdoc'=>'About ShowDoc',\n    'all_pubilc_item'=>\"'s all public items\",\n\n    //member\n    'new_member'=>'New member',\n    'username'=>'Username',\n    'save'=>'Save',\n    'member_list'=>'member list',\n    'click_to_delete'=>'Click to delete',\n    'close'=>'Close',\n    \"member_group_id\" => \"Read-only(can read item ,but not edit or delete )\",\n    //page\n    'input_page_title'=>'Please enter a page title',\n    'level_2_directory'=>'Second-level catalog',\n    'level_3_directory'=>'Third-level catalog',\n    's_number_explain'=>'Optional: order number',\n    'history_version'=>'History version',\n    'save'=>'Save',\n    'cancel'=>'Cancel',\n    'inser_apidoc_template'=>'Insert apidoc template',\n    'inser_database_doc_template'=>'Insert db-doc template',\n    'json_tools'=>'Json tools',\n    'json_to_table'=>'Json to table',\n    'beautify_json'=>'Beautify Json',\n    'beautify_json_description'=>'Make your json more beautiful ',\n    'http_test_api'=>'Api test online',\n    'json_to_table_description'=>'Please paste a section of JSON, the program will automatically parse and generate JSON parameters table. This feature is suitable for the rapid preparation of API documents returned to the parameter table',\n    'confirm'=>'Confirm',\n    'cancel'=>'Cancel',\n    'history_version'=>'History version',\n    'update_time'=>'Modification time',\n    'update_by_who'=>'Modified by who',\n    'operation'=>'Operation',\n    'recover_to_this_version'=>'Restore to this version',\n    'close'=>'Close',\n    'finish'=>'Finish',\n    'api_test_title'=>'Test for GET and POST',\n    'api_address_description'=>'Api address(e.g:ttp://www.abc.com/api/login)',\n    'api_address'=>'Api address',\n    'params_description'=>'Params(e.g:user_id=121&age=22&date=2016-06-02)',\n    'params'=>'Params',\n    'clear'=>'Clear',\n    'result'=>'Result',\n    'save_to_templ'=>'Save as template',\n    'more_templ'=>'More template',\n    'saved_templ_list'=>'Template list you saved',\n    'page_comments'=>'Page comments',\n    'add_page_comments'=>'Add comments before save',\n    'cur_page_content'=>'The latest version ',\n    'history_page_content'=>'History version',\n    'overview'=>'Overview',\n    //user\n    'login'=>'Login',\n    'username'=>'Username',\n    'password'=>'Passwod',\n    'verification_code'=>'Verification code',\n    'no_account'=>'Go to register →',\n    'register_new_account'=>'Register new user',\n    'username_description'=>'English name or Email',\n    'password'=>'Passwod',\n    'password_again'=>'Enter password again',\n    'verification_code'=>'Verification code',\n    'register'=>'Register',\n    'had_a_account'=>' Sign on right now→',\n    'update_personal_info'=>'Modify personal information',\n    'new_password_description'=>'The new password',\n    'old_password_description'=>'Original password',\n    'submit'=>'Submit',\n    'goback'=>'Goback',\n\n    //message 弹出信息有关的文案\n    'no_permissions'=>'No permissions',\n    'incorrect_password'=>'Incorrect password',\n    'user_does_not_exist'=>'User does not exist',\n    'operation_succeeded'=>'Operation succeeded',\n    'operation_failed'=>'Operation failed',\n    'access_password_are_incorrect'=>'Access password are incorrect',\n    'verification_code_are_incorrect'=>'Verification code are incorrect',\n    'no_permissions_to_delete_page'=>'No permissions！The page is created by {$author_username}',\n    'delete_succeeded'=>'Delete succeeded',\n    'delete_failed'=>'Delete failed',\n    'register_succeeded'=>'Register succeeded',\n    'username_or_password_incorrect'=>'Username or password are incorrect',\n    'username_exists'=>'Username exists',\n    'code_much_the_same'=>'Password much be the same',\n    'verification_code_are_incorrect'=>'Verification code are incorrect',\n    'auto_login_succeeded'=>'Automatic login success! Jumping...',\n    'login_succeeded'=>'Login succeeded',\n    'modify_succeeded'=>'Modify succeeded',\n    'modify_faild'=>'Modify failed',\n    'old_password_incorrect'=>'The original password is not correct',\n    'logout_succeeded'=>'Logout succeeded',\n\n    //error_message\n    \"no_delete_empty_catalog\"=>'In order to secure, do not allow direct delete an empty catalog. Please delete or move all the pages in the catalog',\n    \n    \"default_title\" =>'Default',\n);"
  },
  {
    "path": "server/Application/Home/Lang/zh-cn.php",
    "content": "<?php\nreturn array(\n\n    //Attorn\n    'attorn_item'=>'转让项目',\n    'username'=>'用户名',\n    'receiver_name'=>'项目接收者用户名',\n    'verify_identity'=>'验证身份',\n    'your_password'=>'你的登录密码',\n    'attorn'=>'转让',\n    'close'=>'关闭',\n\n    //Catalog\n    'new_or_edit_catalog' => '新建/编辑目录',\n    'catalog_name' => '目录名',\n    's_number' => '序号',\n    's_number_explain' => '可选：顺序数字',\n    'last_catalog' => '上级目录',\n    'save' => '保存',\n    'delete_catalog' => '删除目录',\n    'catalog_list' => '目录列表',\n    'click_to_edit' => '点击可编辑',\n\n\n    //index\n    'help' => '帮助',\n    'demo' => '示例',\n    'index_login_or_register' => '登录 / 注册',\n    'my_item' => '我的项目',\n    'section_title1' => 'ShowDoc',\n    'section_description1' => '一个非常适合IT团队的在线API文档、技术文档工具',\n    'section_title2' => 'API文档',\n    'section_description2' => ' APP、web前端与服务器常用API来进行交互<br>用ShowDoc可以非常方便快速地编写出美观的API文档',\n    'section_title3' => '数据字典',\n    'section_description3' => '好的数据字典可以很方便地向别人描述你的数据库结构<br>用ShowDoc可以编辑出美观的数字字典',\n    'section_title4' => '说明文档',\n    'section_description4' => '你完全可以使用 ShowDoc来编写一些工具的说明书<br>也可以编写一些技术规范说明文档以供团队查阅',\n    'section_title5' => '团队协作',\n    'section_description5' => '团队权限管理机制让团队良好地协同编写文档',\n    'section_title6' => '免费开源',\n    'section_description6' => 'ShowDoc提供免费开源的版本<br>你可以选择将ShowDoc部署到你的服务器',\n    'section_title7' => '在线托管',\n    'section_description7' => '<a href=\"https://www.showdoc.cc\" target=\"_blank\">www.showdoc.cc</a> 提供安全稳定的在线文档托管服务<br>你可以放心地选择托管你的文档数据在云端',\n    'section_title8' => '立即体验',\n    'section_description8' => '超过6000+互联网团队正在使用ShowDoc',\n\n\n    //Common message\n    'redirect_message' => '如果你的浏览器没有自动跳转，请点击此链接',\n    'click_to_goback' => '点击这里返回上一页',\n    'home' => '首页',\n    \n\n    //item/add\n    'item_name' => '项目名',\n    'item_description' => '项目描述',\n    'item_domain' => '(可选)个性域名',\n    'item_domain_illegal' => '个性域名只能是字母或数字的组合',\n    'domain_already_exists' => '个性域名已经存在',\n    'visit_password_placeholder' => '访问密码（可选，私密项目请设置密码）',\n    'submit' => '提交',\n    'goback' => '返回',\n    //item/delete\n    'delete_item' => '删除项目',\n    'verify_your_identity' => '验证你的身份',\n    'creator_password' => '创建人登录密码',\n    'delete' => '删除',\n    'close' => '关闭',\n    //item/index\n    'personal_setting'=>'个人设置',\n    'share_home'=>'分享主页',\n    'web_home'=>'网站首页',\n    'logout'=>'退出登录',\n    'add_an_item'=>'添加一个新项目',\n    'new_item'=>'新建项目',\n    'share_my_home'=>'分享我的主页',\n    'feedback' => \"反馈\",\n    'home_address'=>'主页地址',\n    'home_address_description'=>'别人访问您的主页时，将可以看到您的所有公开项目（但没有新建项目等权限）。你可以复制地址给你的好友',\n    //item/pwd\n    'input_visit_password'=>'请输入访问密码',\n    'password'=>'密码',\n    'verification_code'=>'验证码',\n    'submit'=>'提交',\n    'login_or_register'=>'登录/注册',\n    //item/show\n    'item'=>'项目',\n    'share'=>'分享',\n    'export'=>'导出',\n    'update_info'=>'修改信息',\n    'manage_members'=>'成员管理',\n    'attorn'=>'转让',\n    'delete'=>'删除',\n    'more_item'=>'更多项目',\n    'login_or_register'=>'登录/注册',\n    'about_showdoc'=>'关于ShowDoc',\n    'my_item'=>'我的项目',\n    'new_page'=>'新建页面',\n    'new_catalog'=>'新建目录',\n    'share_address_to_your_friends'=>'分享该接口地址给你的好友',\n    'share'=>'分享',\n    'copy_interface_to_new'=>'复制该页面到新页面',\n    'copy'=>'复制',\n    'edit_interface'=>'编辑页面',\n    'edit'=>'编辑',\n    'delete_interface'=>'删除页面',\n    'comfirm_delete'=>'确认删除吗？',\n    'delete'=>'删除',\n    'share'=>'分享',\n    'item_address'=>'项目地址',\n    'copy_address_to_your_friends'=>'你可以复制地址给你的好友',\n    'share_page'=>'分享页面',\n    'page_address'=>'页面地址',\n    'copy_address_to_your_friends'=>'你可以复制地址给你的好友',\n    //item/showbyuid\n    'more'=>'更多',\n    'my_item'=>'我的项目',\n    'login_or_register'=>'登录/注册',\n    'about_showdoc'=>'关于ShowDoc',\n    'all_pubilc_item'=>'的所有公开项目',\n\n    //member\n    'new_member'=>'新增成员',\n    'username'=>'用户名',\n    'save'=>'保存',\n    'member_list'=>'成员列表',\n    'click_to_delete'=>'点击可删除',\n    'close'=>'关闭',\n    \"member_group_id\" => \"只读(只能查看项目，不能修改/删除)\",\n    \n    //page\n    'input_page_title'=>'请输入页面标题',\n    'level_2_directory'=>'二级目录',\n    'level_3_directory'=>'三级目录',\n    's_number_explain'=>'可选：顺序数字',\n    'history_version'=>'历史版本',\n    'save'=>'保存',\n    'cancel'=>'取消',\n    'inser_apidoc_template'=>'插入API接口模板',\n    'inser_database_doc_template'=>'插入数据字典模板',\n    'json_tools'=>'JSON工具',\n    'json_to_table'=>'JSON转参数表格',\n    'beautify_json'=>'JSON格式化',\n    'beautify_json_description'=>'请粘贴一段json，程序将自动以美观的方式格式化显示',\n    'http_test_api'=>'在线测试API',\n    'json_to_table_description'=>'请粘贴一段json，程序将自动将json解析并生成参数表格。此功能适合用于快速编写API文档的返回参数表格',\n    'confirm'=>'确定',\n    'cancel'=>'取消',\n    'history_version'=>'历史版本',\n    'update_time'=>'修改时间',\n    'update_by_who'=>'修改人',\n    'operation'=>'操作',\n    'recover_to_this_version'=>'恢复到此版本',\n    'close'=>'关闭',\n    'finish'=>'完成',\n    'api_test_title'=>'GET和POST测试',\n    'api_address_description'=>'接口地址(如：http://www.abc.com/api/login)',\n    'api_address'=>'接口地址',\n    'params_description'=>'参数(如：user_id=121&age=22&date=2016-06-02)',\n    'params'=>'参数',\n    'clear'=>'清除',\n    'result'=>'返回结果',\n    'save_to_templ'=>'另存为模板',\n    'more_templ'=>'更多模板',\n    'saved_templ_list'=>'保存的模板列表',\n    'page_comments'=>'页面注释',\n    'add_page_comments'=>'保存前添加页面注释',\n    'cur_page_content'=>'当前最新版本',\n    'history_page_content'=>'历史版本',\n    'overview'=>'预览',\n\n    //user\n    'login'=>'登录',\n    'username'=>'用户名',\n    'password'=>'密码',\n    'verification_code'=>'验证码',\n    'no_account'=>'没有账号？马上去注册→',\n    'register_new_account'=>'注册新用户',\n    'username_description'=>'用户名（可填英文昵称或邮箱）',\n    'password'=>'密码',\n    'password_again'=>'再次输入密码',\n    'verification_code'=>'验证码',\n    'register'=>'注册',\n    'had_a_account'=>'已有账号？马上去登录→',\n    'update_personal_info'=>'修改个人信息',\n    'new_password_description'=>'新密码，若不修改请留空',\n    'old_password_description'=>'原密码，若不修改密码请留空',\n    'submit'=>'提交',\n    'goback'=>'返回',\n\n    //message 弹出信息有关的文案\n    'no_permissions'=>'你无权限',\n    'incorrect_password'=>'密码错误',\n    'user_does_not_exist'=>'不存在此用户',\n    'operation_succeeded'=>'操作成功！',\n    'operation_failed'=>'操作失败！',\n    'access_password_are_incorrect'=>'访问密码不正确',\n    'verification_code_are_incorrect'=>'验证码不正确',\n    'no_permissions_to_delete_page'=>'你无权限！此页面由{$author_username}创建',\n    'delete_succeeded'=>'删除成功！',\n    'delete_failed'=>'删除失败！',\n    'register_succeeded'=>'注册成功！',\n    'username_or_password_incorrect'=>'用户名或密码不正确',\n    'username_exists'=>'用户名已经存在啦！',\n    'code_much_the_same'=>'两次输入的密码不一致！',\n    'verification_code_are_incorrect'=>'验证码不正确',\n    'auto_login_succeeded'=>'自动登录成功！正在跳转...',\n    'login_succeeded'=>'登录成功！',\n    'modify_succeeded'=>'修改成功！',\n    'modify_faild'=>'修改失败！',\n    'old_password_incorrect'=>'原密码不正确',\n    'logout_succeeded'=>'退出成功！',\n\n    //error_message\n    \"no_delete_empty_catalog\"=>'为了安全，不允许直接删除非空目录。请先删除或转移该目录下的所有页面',\n    \n    \"default_title\" =>'默认页面',\n\n\n);"
  },
  {
    "path": "server/Application/Home/Model/BaseModel.class.php",
    "content": "<?php\n\nnamespace Home\\Model;\n\nuse Think\\Model;\n\n/**\n *\n *        \n *        \n */\nclass BaseModel extends Model\n{\n    // 自动验证 //默认,验证条件：0存在字段就进行验证 , 验证时间：1新增/编辑 数据时候验证\n    protected $_validate = array();\n    // 自动填充 //默认 新增数据的时候处理\n    protected $_auto = array();\n    // 只读字段，插入后不能通过save更新\n    protected $readonlyField = array();\n}\n"
  },
  {
    "path": "server/Application/Home/Model/ItemModel.class.php",
    "content": "<?php\n\nnamespace Home\\Model;\n\nuse Home\\Model\\BaseModel;\n\nclass ItemModel extends BaseModel\n{\n\n    public function export($item_id)\n    {\n        $item_id = intval($item_id);\n        $item = D(\"Item\")->where(array('item_id' => $item_id))->field(\" item_type, item_name ,item_description,password \")->find();\n        //获取所有父目录id为0的页面\n        $pages = D(\"Page\")->where(array('cat_id' => 0, 'item_id' => $item_id))->field(\" page_title ,page_content,s_number,page_comments \")->order(\" s_number asc  \")->select();\n        //获取所有二级目录\n        $catalogs = D(\"Catalog\")->where(array('item_id' => $item_id, 'level' => 2))->field(\"cat_id, cat_name ,level,s_number \")->order(\" s_number asc  \")->select();\n        if ($catalogs) {\n            foreach ($catalogs as $key => &$catalog) {\n                //该二级目录下的所有子页面\n                $temp = D(\"Page\")->where(array('cat_id' => $catalog['cat_id']))->field(\" page_title ,page_content,s_number,page_comments \")->order(\" s_number asc  \")->select();\n                $catalog['pages'] = $temp ? $temp : array();\n                //该二级目录下的所有子目录\n                $temp = D(\"catalog\")->where(array('parent_cat_id' => $catalog['cat_id']))->field(\" cat_id,cat_name ,level,s_number \")->order(\" s_number asc  \")->select();\n                $catalog['catalogs'] = $temp ? $temp : array();\n                if ($catalog['catalogs']) {\n                    //获取所有三级目录的子页面\n                    foreach ($catalog['catalogs'] as $key3 => &$catalog3) {\n                        //该二级目录下的所有子页面\n                        $temp = D(\"Page\")->where(array('cat_id' => $catalog3['cat_id']))->field(\" page_title ,page_content,s_number,page_comments \")->order(\" s_number asc  \")->select();\n                        $catalog3['pages'] = $temp ? $temp : array();\n                        unset($catalog3['cat_id']);\n                    }\n                }\n                unset($catalog['cat_id']);\n            }\n        }\n        $item['pages'] = array(\n            \"pages\" => $pages,\n            \"catalogs\" => $catalogs,\n        );\n        unset($pages);\n        unset($catalogs);\n        $item['members'] = D(\"ItemMember\")->where(array('item_id' => $item_id))->field(\" member_group_id ,uid,username \")->select();\n        return  json_encode($item);\n    }\n    public function import($json, $uid, $item_name = '', $item_description = '', $item_password = '', $item_domain = '')\n    {\n        $userInfo = D(\"User\")->userInfo($uid);\n        $item = json_decode($json, 1);\n        unset($json);\n        if ($item) {\n            if ($item['item_domain']) {\n                $item2 = D(\"Item\")->where(\"item_domain = '%s'  \", array($item['item_domain']))->find();\n                if ($item2) {\n                    //个性域名已经存在\n                    return false;\n                }\n                if (!ctype_alnum($item_domain) ||  is_numeric($item_domain)) {\n                    //echo '个性域名只能是字母或数字的组合';exit;\n                    return false;\n                }\n            } else {\n                $item['item_domain'] = '';\n            }\n            $item_data = array(\n                \"item_name\" => $item_name ? $item_name : $item['item_name'],\n                \"item_domain\" => $item_domain ? $item_domain : $item['item_domain'],\n                \"item_type\" => $item['item_type'],\n                \"item_description\" => $item_description ? $item_description : $item['item_description'],\n                \"password\" => $item_password ? $item_password : $item['password'],\n                \"uid\" => $userInfo['uid'],\n                \"username\" => $userInfo['username'],\n                \"addtime\" => time(),\n            );\n            $item_id = D(\"Item\")->add($item_data);\n        }\n        if ($item['pages']) {\n            //父页面们（一级目录）\n            if ($item['pages']['pages']) {\n                foreach ($item['pages']['pages'] as $key => &$value) {\n                    $page_data = array(\n                        \"author_uid\" => $userInfo['uid'],\n                        \"author_username\" => $userInfo['username'],\n                        \"page_title\" => $value['page_title'],\n                        \"page_content\" => $value['page_content'],\n                        \"s_number\" => $value['s_number'],\n                        \"page_comments\" => $value['page_comments'],\n                        \"item_id\" => $item_id,\n                        \"cat_id\" => 0,\n                        \"addtime\" => time(),\n                    );\n                    D(\"Page\")->add($page_data);\n                    unset($page_data);\n                }\n                unset($item['pages']['pages']);\n            }\n            //二级目录\n            if ($item['pages']['catalogs']) {\n                foreach ($item['pages']['catalogs'] as $key => &$value) {\n                    $catalog_data = array(\n                        \"cat_name\" => $value['cat_name'],\n                        \"level\" => $value['level'],\n                        \"s_number\" => $value['s_number'],\n                        \"item_id\" => $item_id,\n                        \"addtime\" => time(),\n                    );\n                    $cat_id = D(\"Catalog\")->add($catalog_data);\n                    //二级目录的页面们\n                    if ($value['pages']) {\n                        foreach ($value['pages'] as $key2 => &$value2) {\n                            $page_data = array(\n                                \"author_uid\" => $userInfo['uid'],\n                                \"author_username\" => $userInfo['username'],\n                                \"page_title\" => $value2['page_title'],\n                                \"page_content\" => $value2['page_content'],\n                                \"s_number\" => $value2['s_number'],\n                                \"page_comments\" => $value2['page_comments'],\n                                \"item_id\" => $item_id,\n                                \"cat_id\" => $cat_id,\n                                \"addtime\" => time(),\n                            );\n                            D(\"Page\")->add($page_data);\n                            unset($page_data);\n                            unset($value2);\n                        }\n                    }\n                    //判断是否存在三级目录\n                    if ($value['catalogs']) {\n                        foreach ($value['catalogs'] as $key3 => &$value3) {\n                            $catalog_data = array(\n                                \"cat_name\" => $value3['cat_name'],\n                                \"level\" => $value3['level'],\n                                \"s_number\" => $value3['s_number'],\n                                \"parent_cat_id\" => $cat_id,\n                                \"item_id\" => $item_id,\n                                \"addtime\" => time(),\n                            );\n                            $cat_id2 = D(\"Catalog\")->add($catalog_data);\n                            //三级目录的页面们\n                            if ($value3['pages']) {\n                                foreach ($value3['pages'] as $key4 => &$value4) {\n                                    $page_data = array(\n                                        \"author_uid\" => $userInfo['uid'],\n                                        \"author_username\" => $userInfo['username'],\n                                        \"page_title\" => $value4['page_title'],\n                                        \"page_content\" => $value4['page_content'],\n                                        \"s_number\" => $value4['s_number'],\n                                        \"page_comments\" => $value4['page_comments'],\n                                        \"item_id\" => $item_id,\n                                        \"cat_id\" => $cat_id2,\n                                        \"addtime\" => time(),\n                                    );\n                                    D(\"Page\")->add($page_data);\n                                    unset($page_data);\n                                    unset($value4);\n                                }\n                            }\n                            unset($value3);\n                        }\n                    }\n                    unset($value);\n                }\n            }\n        }\n\n        if ($item['members']) {\n            foreach ($item['members'] as $key => $value) {\n                $member_data = array(\n                    \"member_group_id\" => $value['member_group_id'],\n                    \"uid\" => $value['uid'],\n                    \"username\" => $value['username'],\n                    \"item_id\" => $item_id,\n                    \"addtime\" => time(),\n                );\n                D(\"ItemMember\")->add($member_data);\n            }\n        }\n        return $item_id;\n    }\n\n    public function copy($item_id, $uid, $item_name = '', $item_description = '', $item_password = '', $item_domain)\n    {\n        return $this->import($this->export($item_id), $uid, $item_name, $item_description, $item_password, $item_domain);\n    }\n}\n"
  },
  {
    "path": "server/Application/Home/Model/UserModel.class.php",
    "content": "<?php\n\nnamespace Home\\Model;\n\nuse Home\\Model\\BaseModel;\n\nclass UserModel extends BaseModel\n{\n\n    /**\n     * 用户名是否已经存在\n     * \n     */\n    public function isExist($username)\n    {\n        return  $this->where(\"username = '%s'\", array($username))->find();\n    }\n\n    /**\n     * 注册新用户\n     * \n     */\n    public function register($username, $password)\n    {\n        $password = md5(base64_encode(md5($password)) . '576hbgh6');\n        return $this->add(array('username' => $username, 'password' => $password, 'reg_time' => time()));\n    }\n\n    //修改用户密码\n    public function updatePwd($uid, $password)\n    {\n        $password = md5(base64_encode(md5($password)) . '576hbgh6');\n        return $this->where(\"uid ='%d' \", array($uid))->save(array('password' => $password));\n    }\n\n    /**\n     * 返回用户信息\n     * @return \n     */\n    public function userInfo($uid)\n    {\n        return  $this->where(\"uid = '%d'\", array($uid))->find();\n    }\n\n    /**\n     *@param username:登录名  \n     *@param password 登录密码   \n     */\n\n    public function checkLogin($username, $password)\n    {\n        $password = md5(base64_encode(md5($password)) . '576hbgh6');\n        $where = array($username, $password);\n        return $this->where(\"username='%s' and password='%s'\", $where)->find();\n    }\n    //设置最后登录时间\n    public function setLastTime($uid)\n    {\n        return $this->where(\"uid='%s'\", array($uid))->save(array(\"last_login_time\" => time()));\n    }\n}\n"
  },
  {
    "path": "server/Application/Home/Model/UserTokenModel.class.php",
    "content": "<?php\n\nnamespace Home\\Model;\n\nuse Home\\Model\\BaseModel;\n\n/**\n * \n * @author star7th      \n */\nclass UserTokenModel extends BaseModel\n{\n\n\tpublic function createToken($uid, $token_expire = 0)\n\t{\n\t\t$token_expire = $token_expire > 0  ? (time() + $token_expire) : (time() + 60 * 60 * 24 * 90);\n\t\t$token = md5(md5($uid . $token_expire . time() . rand() . \"showdoc\") . \"rdgsvgsrgr67hghf54t\") . md5($uid . $token_expire . time() . rand() . \"showdoc\");\n\t\t$data['uid'] = $uid;\n\t\t$data['token'] = $token;\n\t\t$data['token_expire'] = $token_expire;\n\t\t$data['ip'] = getIPaddress();\n\t\t$data['addtime'] = time();\n\t\t$ret = $this->add($data);\n\t\tif ($ret) {\n\t\t\t//删除过期的token \n\t\t\t$this->where(\"token_expire < \" . time())->delete();\n\t\t\treturn $token;\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic function getToken($token)\n\t{\n\t\treturn $this->where(\"token='%s'\", array($token))->find();\n\t}\n\n\tpublic function setLastTime($token)\n\t{\n\t\treturn $this->where(\"token='%s'\", array($token))->save(array(\"last_check_time\" => time()));\n\t}\n}\n"
  },
  {
    "path": "server/Application/Home/Model/index.html",
    "content": " "
  },
  {
    "path": "server/Application/Home/View/index.html",
    "content": " "
  },
  {
    "path": "server/Application/Home/index.html",
    "content": " "
  },
  {
    "path": "server/Application/README.md",
    "content": "﻿项目目录"
  },
  {
    "path": "server/Application/Static/export-html/app.js",
    "content": "/**\n * ShowDoc 离线HTML导出 - 前端交互逻辑\n */\n\n;(function () {\n  'use strict'\n\n  // 工具函数\n  const utils = {\n    debounce: function (func, wait) {\n      let timeout\n      return function (...args) {\n        clearTimeout(timeout)\n        timeout = setTimeout(() => func.apply(this, args), wait)\n      }\n    },\n\n    escapeHtml: function (text) {\n      const div = document.createElement('div')\n      div.textContent = text\n      return div.innerHTML\n    },\n\n    getQueryParam: function (name) {\n      const urlParams = new URLSearchParams(window.location.search)\n      return urlParams.get(name)\n    },\n  }\n\n  // 判断是否在 pages 目录下\n  const isPageContext = function () {\n    try {\n      return window.location.pathname.indexOf('/pages/') !== -1\n    } catch (e) {\n      return false\n    }\n  }\n\n  // 目录树渲染\n  const CatalogTree = {\n    init: function () {\n      if (!window.PROJECT_DATA) {\n        console.error('PROJECT_DATA not found')\n        return\n      }\n\n      this.render()\n      this.highlightCurrentPage()\n      this.restoreExpandedState()\n    },\n\n    render: function () {\n      const container = document.getElementById('catalogTree')\n      if (!container) return\n\n      const catalogs = window.PROJECT_DATA.catalogs || []\n      const pages = window.PROJECT_DATA.pages || []\n\n      // 构建目录树结构\n      const tree = this.buildTree(catalogs, pages)\n\n      // 渲染目录树\n      container.innerHTML = this.renderTree(tree)\n    },\n\n    buildTree: function (catalogs, pages) {\n      // 创建目录映射\n      const catalogMap = {}\n      catalogs.forEach((cat) => {\n        catalogMap[cat.cat_id] = {\n          ...cat,\n          children: [],\n          pages: [],\n        }\n      })\n\n      // 构建树结构\n      const root = []\n      catalogs.forEach((cat) => {\n        if (cat.parent_cat_id === 0) {\n          root.push(catalogMap[cat.cat_id])\n        } else {\n          const parent = catalogMap[cat.parent_cat_id]\n          if (parent) {\n            parent.children.push(catalogMap[cat.cat_id])\n          } else {\n            root.push(catalogMap[cat.cat_id])\n          }\n        }\n      })\n\n      // 添加页面到对应目录\n      pages.forEach((page) => {\n        if (page.cat_id === 0) {\n          // 根目录下的页面\n          root.push({ type: 'page', ...page })\n        } else {\n          const catalog = catalogMap[page.cat_id]\n          if (catalog) {\n            catalog.pages.push(page)\n          } else {\n            root.push({ type: 'page', ...page })\n          }\n        }\n      })\n\n      // 排序\n      root.sort((a, b) => {\n        if (a.type === 'page' && b.type !== 'page') return 1\n        if (a.type !== 'page' && b.type === 'page') return -1\n        return (a.s_number || 0) - (b.s_number || 0)\n      })\n\n      return root\n    },\n\n    renderTree: function (items, level = 0) {\n      let html = ''\n\n      items.forEach((item) => {\n        if (item.type === 'page') {\n          // 渲染页面链接\n          // 在首页使用 pages/page-xx.html；在页面内使用同目录相对路径 page-xx.html\n          const href = isPageContext()\n            ? `page-${item.page_id}.html`\n            : `pages/page-${item.page_id}.html`\n          html += `<a href=\"${href}\" class=\"page-link\" data-page-id=\"${\n            item.page_id\n          }\">${utils.escapeHtml(item.page_title)}</a>`\n        } else {\n          // 渲染目录\n          const catalogId = `cat-${item.cat_id}`\n          const hasChildren =\n            (item.children && item.children.length > 0) ||\n            (item.pages && item.pages.length > 0)\n\n          html += `<div class=\"catalog-item\">`\n          html += `<div class=\"catalog-link\" data-catalog-id=\"${item.cat_id}\">`\n\n          // 即使空目录也显示图标，但使用不同的样式标识\n          if (hasChildren) {\n            html += `<span class=\"catalog-icon collapsed\" data-target=\"${catalogId}\"></span>`\n          } else {\n            // 空目录显示一个横线图标，表示没有内容\n            html += `<span class=\"catalog-icon empty\" style=\"opacity: 0.3; cursor: default;\" title=\"空目录\"></span>`\n          }\n\n          html += `<span>${utils.escapeHtml(item.cat_name)}</span>`\n          html += `</div>`\n\n          // 即使空目录也创建catalog-children容器，但内容为空，这样点击时至少有个反馈\n          html += `<div class=\"catalog-children\" id=\"${catalogId}\" style=\"${\n            hasChildren ? '' : 'display: none;'\n          }\">`\n\n          if (hasChildren) {\n            // 渲染子目录\n            if (item.children && item.children.length > 0) {\n              item.children.sort(\n                (a, b) => (a.s_number || 0) - (b.s_number || 0)\n              )\n              html += this.renderTree(item.children, level + 1)\n            }\n\n            // 渲染页面\n            if (item.pages && item.pages.length > 0) {\n              item.pages.sort((a, b) => (a.s_number || 0) - (b.s_number || 0))\n              item.pages.forEach((page) => {\n                // 在首页使用 pages/page-xx.html；在页面内使用同目录相对路径 page-xx.html\n                const href = isPageContext()\n                  ? `page-${page.page_id}.html`\n                  : `pages/page-${page.page_id}.html`\n                html += `<a href=\"${href}\" class=\"page-link\" data-page-id=\"${\n                  page.page_id\n                }\">${utils.escapeHtml(page.page_title)}</a>`\n              })\n            }\n          } else {\n            // 空目录显示提示信息（可选，如果不需要可以删除这行）\n            // html += `<div style=\"padding: 5px 10px; color: #999; font-size: 12px;\">（空目录）</div>`\n          }\n\n          html += `</div>`\n          html += `</div>`\n        }\n      })\n\n      return html\n    },\n\n    highlightCurrentPage: function () {\n      // 使用字符串，避免大整数精度丢失问题\n      const currentPageId = String(window.CURRENT_PAGE_ID || '0')\n\n      // 移除所有active类\n      document\n        .querySelectorAll('.page-link.active, .catalog-link.active')\n        .forEach((el) => {\n          el.classList.remove('active')\n        })\n\n      if (currentPageId !== '0') {\n        // 高亮当前页面（data-page-id 属性是字符串）\n        const pageLink = document.querySelector(\n          `.page-link[data-page-id=\"${currentPageId}\"]`\n        )\n        if (pageLink) {\n          pageLink.classList.add('active')\n\n          // 展开父目录\n          let parent = pageLink.parentElement\n          while (parent) {\n            if (parent.classList.contains('catalog-children')) {\n              parent.classList.add('expanded')\n              const icon =\n                parent.previousElementSibling?.querySelector('.catalog-icon')\n              if (icon) {\n                icon.classList.remove('collapsed')\n                icon.classList.add('expanded')\n              }\n            }\n            parent = parent.parentElement\n          }\n        }\n      }\n    },\n\n    restoreExpandedState: function () {\n      const saved = localStorage.getItem('showdoc_catalog_expanded')\n      if (!saved) return\n\n      try {\n        const expandedIds = JSON.parse(saved)\n        expandedIds.forEach((catId) => {\n          const children = document.getElementById(`cat-${catId}`)\n          if (children) {\n            children.classList.add('expanded')\n            const icon =\n              children.previousElementSibling?.querySelector('.catalog-icon')\n            if (icon) {\n              icon.classList.remove('collapsed')\n              icon.classList.add('expanded')\n            }\n          }\n        })\n      } catch (e) {\n        console.error('Failed to restore expanded state', e)\n      }\n    },\n\n    saveExpandedState: function () {\n      const expanded = []\n      document.querySelectorAll('.catalog-children.expanded').forEach((el) => {\n        const catId = el.id.replace('cat-', '')\n        if (catId) {\n          expanded.push(catId)\n        }\n      })\n      localStorage.setItem('showdoc_catalog_expanded', JSON.stringify(expanded))\n    },\n  }\n\n  // 搜索功能\n  const Search = {\n    init: function () {\n      const searchInput = document.getElementById('searchInput')\n      const searchResults = document.getElementById('searchResults')\n\n      if (!searchInput || !searchResults) return\n\n      // 防抖搜索\n      const debouncedSearch = utils.debounce((query) => {\n        this.performSearch(query)\n      }, 300)\n\n      searchInput.addEventListener('input', (e) => {\n        const query = e.target.value.trim()\n        if (query.length > 0) {\n          debouncedSearch(query)\n        } else {\n          searchResults.classList.remove('show')\n        }\n      })\n\n      // 点击外部关闭搜索结果\n      document.addEventListener('click', (e) => {\n        if (\n          !searchInput.contains(e.target) &&\n          !searchResults.contains(e.target)\n        ) {\n          searchResults.classList.remove('show')\n        }\n      })\n\n      // 键盘快捷键\n      document.addEventListener('keydown', (e) => {\n        if ((e.ctrlKey || e.metaKey) && e.key === 'k') {\n          e.preventDefault()\n          searchInput.focus()\n        }\n        if (e.key === 'Escape') {\n          searchResults.classList.remove('show')\n          searchInput.blur()\n        }\n      })\n    },\n\n    performSearch: function (query) {\n      if (!window.SEARCH_INDEX) {\n        console.error('SEARCH_INDEX not found')\n        return\n      }\n\n      const results = []\n      const lowerQuery = query.toLowerCase()\n\n      window.SEARCH_INDEX.forEach((item) => {\n        const title = item.page_title || ''\n        const content = item.content_preview || ''\n\n        const titleMatch = title.toLowerCase().indexOf(lowerQuery) !== -1\n        const contentMatch = content.toLowerCase().indexOf(lowerQuery) !== -1\n\n        if (titleMatch || contentMatch) {\n          let score = 0\n          if (titleMatch) score += 10\n          if (contentMatch) score += 1\n\n          results.push({\n            ...item,\n            score: score,\n          })\n        }\n      })\n\n      // 按分数排序\n      results.sort((a, b) => b.score - a.score)\n\n      this.displayResults(results.slice(0, 10), query)\n    },\n\n    displayResults: function (results, query) {\n      const searchResults = document.getElementById('searchResults')\n      if (!searchResults) return\n\n      if (results.length === 0) {\n        searchResults.innerHTML =\n          '<div class=\"search-result-item\">未找到匹配结果</div>'\n        searchResults.classList.add('show')\n        return\n      }\n\n      let html = ''\n      results.forEach((result) => {\n        // 在首页使用 pages/page-xx.html；在页面内使用同目录相对路径 page-xx.html\n        const href = isPageContext()\n          ? `page-${result.page_id}.html`\n          : `pages/page-${result.page_id}.html`\n        const title = this.highlightText(result.page_title, query)\n        const preview = this.highlightText(result.content_preview, query)\n\n        html += `\n          <div class=\"search-result-item\" onclick=\"window.location.href='${href}'\">\n            <div class=\"search-result-title\">${title}</div>\n            <div class=\"search-result-preview\">${preview}</div>\n          </div>\n        `\n      })\n\n      searchResults.innerHTML = html\n      searchResults.classList.add('show')\n    },\n\n    highlightText: function (text, query) {\n      if (!query) return utils.escapeHtml(text)\n\n      const regex = new RegExp(`(${query})`, 'gi')\n      return utils.escapeHtml(text).replace(regex, '<mark>$1</mark>')\n    },\n  }\n\n  // 页面导航\n  const PageNav = {\n    init: function () {\n      // 使用字符串比较，避免大整数精度丢失问题\n      const currentPageId = String(window.CURRENT_PAGE_ID || '0')\n      if (currentPageId === '0') return\n\n      if (!window.PROJECT_DATA) return\n\n      const pages = window.PROJECT_DATA.pages || []\n      if (pages.length === 0) return\n\n      // 按s_number排序\n      const sortedPages = [...pages].sort((a, b) => {\n        if (a.cat_id !== b.cat_id) {\n          return a.cat_id - b.cat_id\n        }\n        return (a.s_number || 0) - (b.s_number || 0)\n      })\n\n      // 使用字符串比较，避免大整数精度丢失\n      const currentIndex = sortedPages.findIndex(\n        (p) => String(p.page_id) === currentPageId\n      )\n      if (currentIndex === -1) return\n\n      const prevPage = currentIndex > 0 ? sortedPages[currentIndex - 1] : null\n      const nextPage =\n        currentIndex < sortedPages.length - 1\n          ? sortedPages[currentIndex + 1]\n          : null\n\n      this.render(prevPage, nextPage)\n    },\n\n    render: function (prevPage, nextPage) {\n      const container = document.getElementById('pageNav')\n      if (!container) return\n\n      let html = '<div>'\n\n      if (prevPage) {\n        // 在页面文件中，使用同目录的相对路径\n        const href = `page-${prevPage.page_id}.html`\n        html += `<a href=\"${href}\" class=\"page-nav-link\">← 上一页: ${utils.escapeHtml(\n          prevPage.page_title\n        )}</a>`\n      } else {\n        html += '<span class=\"page-nav-link disabled\">← 上一页</span>'\n      }\n\n      html += '</div><div>'\n\n      if (nextPage) {\n        // 在页面文件中，使用同目录的相对路径\n        const href = `page-${nextPage.page_id}.html`\n        html += `<a href=\"${href}\" class=\"page-nav-link\">下一页: ${utils.escapeHtml(\n          nextPage.page_title\n        )} →</a>`\n      } else {\n        html += '<span class=\"page-nav-link disabled\">下一页 →</span>'\n      }\n\n      html += '</div>'\n\n      container.innerHTML = html\n    },\n  }\n\n  // 响应式菜单\n  const Responsive = {\n    init: function () {\n      const menuToggle = document.getElementById('menuToggle')\n      const sidebar = document.getElementById('sidebar')\n\n      if (menuToggle && sidebar) {\n        menuToggle.addEventListener('click', () => {\n          sidebar.classList.toggle('open')\n        })\n      }\n\n      // 点击侧边栏外部关闭\n      document.addEventListener('click', (e) => {\n        if (window.innerWidth <= 768) {\n          if (sidebar && sidebar.classList.contains('open')) {\n            if (!sidebar.contains(e.target) && !menuToggle.contains(e.target)) {\n              sidebar.classList.remove('open')\n            }\n          }\n        }\n      })\n    },\n  }\n\n  // 目录树点击事件\n  const bindCatalogEvents = function () {\n    document.addEventListener('click', (e) => {\n      // 点击箭头图标\n      const icon = e.target.closest('.catalog-icon')\n      if (icon && icon.dataset.target) {\n        e.preventDefault()\n        e.stopPropagation()\n\n        const targetId = icon.dataset.target\n        const children = document.getElementById(targetId)\n\n        if (children) {\n          children.classList.toggle('expanded')\n          icon.classList.toggle('collapsed')\n          icon.classList.toggle('expanded')\n\n          CatalogTree.saveExpandedState()\n        }\n        return\n      }\n\n      // 点击目录整行（名称也可触发展开/折叠）\n      const link = e.target.closest('.catalog-link')\n      if (link && link.dataset.catalogId) {\n        e.preventDefault()\n        e.stopPropagation()\n\n        const targetId = `cat-${link.dataset.catalogId}`\n        const children = document.getElementById(targetId)\n        const iconInLink = link.querySelector('.catalog-icon')\n\n        if (children) {\n          // 检查是否是空目录（没有子元素）\n          const isEmpty = children.children.length === 0\n\n          if (isEmpty) {\n            // 空目录点击时不执行展开/折叠，但可以给一个视觉反馈\n            // 可以添加一个短暂的样式变化提示这是空目录\n            link.style.opacity = '0.6'\n            setTimeout(() => {\n              link.style.opacity = '1'\n            }, 200)\n          } else {\n            // 有内容的目录正常展开/折叠\n            children.classList.toggle('expanded')\n            if (iconInLink && !iconInLink.classList.contains('empty')) {\n              iconInLink.classList.toggle('collapsed')\n              iconInLink.classList.toggle('expanded')\n            }\n            CatalogTree.saveExpandedState()\n          }\n        }\n      }\n    })\n  }\n\n  // 处理表格样式（复刻Editormd.vue的dealWithContent方法）\n  const TableStyle = {\n    init: function () {\n      // 当表格列数过长时将自动出现滚动条\n      const tables = document.querySelectorAll('.markdown-body table')\n      tables.forEach(function (table) {\n        // 如果表格还没有被包装，则包装它\n        if (table.parentElement.tagName !== 'DIV' || !table.parentElement.style.overflowX) {\n          const wrapper = document.createElement('div')\n          wrapper.style.width = '100%'\n          wrapper.style.overflowX = 'auto'\n          table.parentNode.insertBefore(wrapper, table)\n          wrapper.appendChild(table)\n        }\n      })\n\n      // 对表格进行一些改造（复刻Editormd.vue的逻辑）\n      const tableRows = document.querySelectorAll('.markdown-body table tbody tr')\n      tableRows.forEach(function (tr) {\n        const tds = tr.querySelectorAll('td')\n        if (tds.length >= 2) {\n          const td1 = tds[0] ? tds[0].textContent.trim() : ''\n          const td2 = tds[1] ? tds[1].textContent.trim() : ''\n          const td3 = tds[2] ? tds[2].textContent.trim() : ''\n\n          // 检查是否是object或array[object]类型\n          if (\n            td1 === 'object' ||\n            td1 === 'array[object]' ||\n            td2 === 'object' ||\n            td2 === 'array[object]' ||\n            td3 === 'object' ||\n            td3 === 'array[object]'\n          ) {\n            tr.classList.add('object-row')\n          }\n\n          // 设置表格hover\n          tr.addEventListener('mouseenter', function () {\n            tr.style.backgroundColor = '#F8F8F8'\n          })\n          tr.addEventListener('mouseleave', function () {\n            if (tr.classList.contains('object-row')) {\n              tr.style.backgroundColor = '#F8F8F8'\n            } else {\n              tr.style.backgroundColor = ''\n            }\n          })\n        }\n      })\n    }\n  }\n\n  // 初始化\n  document.addEventListener('DOMContentLoaded', function () {\n    CatalogTree.init()\n    Search.init()\n    PageNav.init()\n    Responsive.init()\n    bindCatalogEvents()\n    TableStyle.init()\n  })\n})()\n"
  },
  {
    "path": "server/Application/Static/export-html/common.css",
    "content": "/* ShowDoc 离线HTML导出 - 通用样式 */\n\n* {\n  margin: 0;\n  padding: 0;\n  box-sizing: border-box;\n}\n\nbody {\n  font-family: 'Microsoft Yahei', 微软雅黑, Tahoma, Arial, Helvetica, STHeiti, sans-serif;\n  font-size: 13px;\n  line-height: 1.75;\n  color: #343a40;\n  background-color: #f9f9f9;\n}\n\n/* 头部样式 */\n.header {\n  position: fixed;\n  top: 0;\n  left: 0;\n  right: 0;\n  height: 50px;\n  background-color: #ffffff;\n  border-bottom: 1px solid rgba(0, 0, 0, 0.1);\n  z-index: 1000;\n  box-shadow: 0 1px 2px rgba(0,0,0,0.03);\n}\n\n.header-content {\n  display: flex;\n  align-items: center;\n  height: 100%;\n  padding: 0 20px;\n  max-width: 100%;\n}\n\n.project-name {\n  font-size: 18px;\n  font-weight: 600;\n  margin: 0;\n  margin-right: 20px;\n  color: #343a40;\n  white-space: nowrap;\n  overflow: hidden;\n  text-overflow: ellipsis;\n}\n\n.search-box {\n  position: relative;\n  flex: 1;\n  max-width: 400px;\n  margin-right: 20px;\n}\n\n.search-box input {\n  width: 100%;\n  padding: 6px 12px;\n  border: 1px solid rgba(0, 0, 0, 0.1);\n  border-radius: 4px;\n  font-size: 13px;\n  outline: none;\n  background-color: #ffffff;\n  transition: border-color 0.2s;\n}\n\n.search-box input::placeholder {\n  color: #9b9b9b;\n}\n\n.search-box input:focus {\n  border-color: #007bff;\n}\n\n.search-results {\n  position: absolute;\n  top: 100%;\n  left: 0;\n  right: 0;\n  background: #fff;\n  border: 1px solid rgba(0, 0, 0, 0.1);\n  border-top: none;\n  border-radius: 0 0 4px 4px;\n  max-height: 400px;\n  overflow-y: auto;\n  display: none;\n  z-index: 1001;\n  box-shadow: 0 2px 4px rgba(0,0,0,0.1);\n}\n\n.search-results.show {\n  display: block;\n}\n\n.search-result-item {\n  padding: 10px 14px;\n  border-bottom: 1px solid rgba(0, 0, 0, 0.05);\n  cursor: pointer;\n  transition: background-color 0.15s;\n}\n\n.search-result-item:hover {\n  background-color: #f9f9f9;\n}\n\n.search-result-item:last-child {\n  border-bottom: none;\n}\n\n.search-result-title {\n  font-weight: 600;\n  color: #007bff;\n  margin-bottom: 4px;\n  font-size: 13px;\n}\n\n.search-result-preview {\n  font-size: 12px;\n  color: #9b9b9b;\n  line-height: 1.5;\n}\n\n.search-result-item mark {\n  background-color: #fff4c2;\n  color: #343a40;\n  padding: 2px 0;\n}\n\n.menu-toggle {\n  display: none;\n  background: none;\n  border: none;\n  font-size: 24px;\n  cursor: pointer;\n  padding: 5px 10px;\n  color: #343a40;\n}\n\n/* 容器布局 */\n.container {\n  display: flex;\n  margin-top: 50px;\n  min-height: calc(100vh - 50px);\n}\n\n/* 侧边栏 */\n.sidebar {\n  width: 260px;\n  background-color: #f9f9f9;\n  border-right: 1px solid rgba(0, 0, 0, 0.1);\n  overflow-y: auto;\n  position: fixed;\n  left: 0;\n  top: 50px;\n  bottom: 0;\n  padding: 10px 0;\n}\n\n.catalog-tree {\n  padding: 0 8px;\n}\n\n.catalog-item {\n  margin-bottom: 2px;\n}\n\n.catalog-link {\n  display: flex;\n  align-items: center;\n  padding: 6px 10px;\n  color: #343a40;\n  text-decoration: none;\n  border-radius: 4px;\n  transition: background-color 0.15s;\n  font-size: 13px;\n  cursor: pointer;\n}\n\n.catalog-link:hover {\n  background-color: #f0f0f0;\n  color: #007bff;\n}\n\n.catalog-link.active {\n  background-color: #f0f0f0;\n  color: #007bff;\n  border-left: 3px solid #007bff;\n}\n\n.catalog-icon {\n  margin-right: 8px;\n  font-size: 12px;\n  width: 16px;\n  min-width: 16px;\n  text-align: center;\n  cursor: pointer;\n  user-select: none;\n  color: #9b9b9b;\n}\n\n.catalog-icon.expanded::before {\n  content: '▼';\n}\n\n.catalog-icon.collapsed::before {\n  content: '▶';\n}\n\n.catalog-icon.empty::before {\n  content: '─';\n  opacity: 0.3;\n  cursor: default;\n}\n\n.catalog-children {\n  margin-left: 20px;\n  display: none;\n}\n\n.catalog-children.expanded {\n  display: block;\n}\n\n.page-link {\n  display: block;\n  padding: 6px 10px;\n  color: #343a40;\n  text-decoration: none;\n  border-radius: 4px;\n  transition: background-color 0.15s;\n  font-size: 13px;\n  margin-left: 22px;\n}\n\n.page-link:hover {\n  background-color: #f0f0f0;\n  color: #007bff;\n}\n\n.page-link.active {\n  background-color: #f0f0f0;\n  color: #007bff;\n  border-left: 3px solid #007bff;\n}\n\n/* 主内容区 */\n.main-content {\n  flex: 1;\n  margin-left: 260px;\n  padding: 20px;\n  max-width: 1200px;\n}\n\n.page-content {\n  background: #ffffff;\n  padding: 20px;\n}\n\n.page-title {\n  font-size: 24px;\n  font-weight: 600;\n  margin-bottom: 16px;\n  padding-bottom: 10px;\n  border-bottom: 1px solid rgba(0, 0, 0, 0.1);\n  color: #343a40;\n}\n\n.project-description {\n  font-size: 13px;\n  color: #9b9b9b;\n  margin-bottom: 20px;\n  line-height: 1.75;\n}\n\n.project-overview {\n  margin-top: 20px;\n  padding: 16px;\n  background-color: #f9f9f9;\n  border-radius: 4px;\n  border-left: 4px solid #007bff;\n}\n\n.project-overview p {\n  margin-bottom: 10px;\n  color: #343a40;\n  line-height: 1.75;\n}\n\n.project-overview p:last-child {\n  margin-bottom: 0;\n}\n\n/* Markdown 样式微调，接近在线版 */\n.markdown-body {\n  color: #343a40;\n  line-height: 1.75;\n  word-wrap: break-word;\n  font-size: 14px;\n}\n\n.markdown-body h1,\n.markdown-body h2,\n.markdown-body h3,\n.markdown-body h4,\n.markdown-body h5,\n.markdown-body h6 {\n  margin-top: 24px;\n  margin-bottom: 1.5em;\n  font-weight: 600;\n  line-height: 1.75;\n  color: #343a40;\n}\n\n.markdown-body h1 {\n  font-size: 1.8em;\n  border-bottom: 1px solid rgba(0, 0, 0, 0.1);\n  padding-bottom: 0.3em;\n}\n\n.markdown-body h2 {\n  font-size: 1.5em;\n  border-bottom: 1px solid rgba(0, 0, 0, 0.1);\n  padding-bottom: 0.3em;\n}\n\n.markdown-body h3 {\n  font-size: 1.25em;\n}\n\n.markdown-body h4 {\n  font-size: 1.1em;\n}\n\n.markdown-body h5 {\n  font-size: 0.875em;\n}\n\n.markdown-body h6 {\n  font-size: 0.85em;\n  color: #9b9b9b;\n}\n\n.markdown-body p,\n.markdown-body ul,\n.markdown-body ol,\n.markdown-body blockquote,\n.markdown-body table,\n.markdown-body pre {\n  margin-bottom: 1.5em;\n}\n\n.markdown-body li {\n  margin-bottom: 4px;\n}\n\n.markdown-body blockquote {\n  padding: 0 1em;\n  color: #9b9b9b;\n  border-left: 4px solid rgba(0, 0, 0, 0.1);\n  background-color: #f9f9f9;\n  font-style: normal;\n}\n\n.markdown-body code {\n  padding: 0.2em 0.4em;\n  background-color: #f9f9f9;\n  border-radius: 3px;\n  font-size: 0.9em;\n  color: #409eff;\n  font-family: Consolas, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace;\n}\n\n.markdown-body pre {\n  position: relative;\n  padding: 1em;\n  overflow: auto;\n  font-size: 12px;\n  line-height: 1.6;\n  background-color: #384548;\n  color: #d1d2d2;\n  border-radius: 4px;\n  margin-bottom: 1.5em;\n}\n\n.markdown-body pre code {\n  display: inline;\n  max-width: auto;\n  padding: 0;\n  margin: 0;\n  overflow: visible;\n  line-height: inherit;\n  word-wrap: normal;\n  background-color: transparent;\n  border: 0;\n  color: #d1d2d2;\n}\n\n/* 代码块复制按钮样式 */\n.markdown-body pre .btn-pre-copy {\n  display: none;\n  position: absolute;\n  top: 10px;\n  right: 12px;\n  font-size: 11px;\n  line-height: 1;\n  cursor: pointer;\n  color: #999;\n  transition: color 0.1s;\n  -webkit-user-select: none;\n  -moz-user-select: none;\n  -ms-user-select: none;\n  user-select: none;\n  z-index: 10;\n  padding: 4px 8px;\n  background-color: rgba(0, 0, 0, 0.3);\n  border-radius: 3px;\n}\n\n.markdown-body pre:hover .btn-pre-copy {\n  display: block;\n}\n\n.markdown-body pre .btn-pre-copy:hover {\n  color: #fff;\n  background-color: rgba(0, 0, 0, 0.5);\n}\n\n/* 代码高亮注释颜色调整 */\n.markdown-body .hljs-comment,\n.markdown-body .hljs-quote {\n  color: #aaa;\n}\n\n/* 代码块滚动条样式（适配深色背景） */\n.markdown-body pre {\n  scrollbar-width: thin;\n  scrollbar-color: rgba(255, 255, 255, 0.5) #2f3a3d;\n}\n\n.markdown-body pre::-webkit-scrollbar {\n  height: 8px;\n}\n\n.markdown-body pre::-webkit-scrollbar-track {\n  background-color: #2f3a3d;\n}\n\n.markdown-body pre::-webkit-scrollbar-thumb {\n  background-color: rgba(255, 255, 255, 0.5);\n  border-radius: 6px;\n}\n\n.markdown-body pre::-webkit-scrollbar-thumb:hover {\n  background-color: rgba(255, 255, 255, 0.65);\n}\n\n/* 表格外层包装，用于自动滚动 */\n.markdown-body > div[style*=\"overflow-x: auto\"] {\n  width: 100%;\n  overflow-x: auto;\n  margin-bottom: 1.5em;\n}\n\n.markdown-body table {\n  border-collapse: collapse;\n  width: 100%;\n  display: block;\n  overflow-x: auto;\n  margin-bottom: 1.5em;\n  background-color: #f9f9f9;\n}\n\n.markdown-body table th,\n.markdown-body table td {\n  padding: 8px 13px;\n  border: 1px solid rgba(0, 0, 0, 0.1);\n  text-align: left;\n  background-color: #ffffff;\n}\n\n.markdown-body table thead tr {\n  background-color: rgba(64, 158, 255, 0.1);\n}\n\n.markdown-body table th {\n  font-weight: 600;\n  background-color: rgba(64, 158, 255, 0.1);\n  color: #343a40;\n}\n\n.markdown-body table tr:nth-child(2n) {\n  background-color: #f9f9f9;\n}\n\n/* object/array[object] 行特殊样式 \n   注意：由于CSS无法直接检测文本内容，此样式需要通过JavaScript动态添加类名实现\n   这里先定义样式，实际应用需要在生成HTML时通过JS处理\n*/\n.markdown-body table tbody tr.object-row {\n  background-color: #F8F8F8;\n}\n\n.markdown-body table tbody tr:hover {\n  background-color: #F8F8F8;\n}\n\n.markdown-body img {\n  max-width: 100%;\n  height: auto;\n  margin: 16px 0;\n  border-radius: 4px;\n}\n\n.markdown-body a {\n  color: #007bff;\n  text-decoration: none;\n}\n\n.markdown-body a:hover {\n  color: mix(#ffffff, #007bff, 20%);\n  text-decoration: underline;\n}\n\n.markdown-body hr {\n  height: 0.25em;\n  padding: 0;\n  margin: 24px 0;\n  background-color: rgba(0, 0, 0, 0.1);\n  border: 0;\n}\n\n/* 页面导航样式微调 */\n.page-nav {\n  margin-top: 24px;\n  padding-top: 16px;\n  border-top: 1px solid rgba(0, 0, 0, 0.1);\n  display: flex;\n  justify-content: space-between;\n}\n\n.page-nav-link {\n  display: inline-block;\n  padding: 8px 14px;\n  background-color: #f9f9f9;\n  color: #007bff;\n  text-decoration: none;\n  border-radius: 4px;\n  transition: background-color 0.15s;\n  border: 1px solid rgba(0, 0, 0, 0.1);\n}\n\n.page-nav-link:hover {\n  background-color: #f0f0f0;\n  color: mix(#ffffff, #007bff, 20%);\n}\n\n.page-nav-link.disabled {\n  color: #9b9b9b;\n  cursor: not-allowed;\n  opacity: 0.6;\n}\n\n.page-nav-link.disabled:hover {\n  background-color: #f9f9f9;\n  color: #9b9b9b;\n}\n\n/* 响应式设计 */\n@media screen and (max-width: 768px) {\n  .menu-toggle {\n    display: block;\n  }\n\n  .sidebar {\n    transform: translateX(-100%);\n    transition: transform 0.3s;\n    z-index: 999;\n  }\n\n  .sidebar.open {\n    transform: translateX(0);\n  }\n\n  .main-content {\n    margin-left: 0;\n    padding: 20px 15px;\n  }\n\n  .header-content {\n    padding: 0 10px;\n  }\n\n  .project-name {\n    font-size: 16px;\n    margin-right: 10px;\n  }\n\n  .search-box {\n    margin-right: 10px;\n  }\n}\n\n/* 打印样式 */\n@media print {\n  .header,\n  .sidebar,\n  .menu-toggle,\n  .search-box,\n  .page-nav {\n    display: none;\n  }\n\n  .main-content {\n    margin-left: 0;\n    padding: 0;\n  }\n\n  .page-content {\n    max-width: 100%;\n  }\n}\n"
  },
  {
    "path": "server/Application/index.html",
    "content": " "
  },
  {
    "path": "server/README.md",
    "content": "﻿server后台主要提供API给前台操作。由于历史原因，并不是很多接口都在server目录下。旧的就不管了，新的接口都会写到这里来"
  },
  {
    "path": "server/ThinkPHP/Common/functions.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\n/**\n * Think 系统函数库\n */\n\n/**\n * 获取和设置配置参数 支持批量定义\n * @param string|array $name 配置变量\n * @param mixed $value 配置值\n * @param mixed $default 默认值\n * @return mixed\n */\nfunction C($name=null, $value=null,$default=null) {\n    static $_config = array();\n    // 无参数时获取所有\n    if (empty($name)) {\n        return $_config;\n    }\n    // 优先执行设置获取或赋值\n    if (is_string($name)) {\n        if (!strpos($name, '.')) {\n            $name = strtoupper($name);\n            if (is_null($value))\n                return isset($_config[$name]) ? $_config[$name] : $default;\n            $_config[$name] = $value;\n            return null;\n        }\n        // 二维数组设置和获取支持\n        $name = explode('.', $name);\n        $name[0]   =  strtoupper($name[0]);\n        if (is_null($value))\n            return isset($_config[$name[0]][$name[1]]) ? $_config[$name[0]][$name[1]] : $default;\n        $_config[$name[0]][$name[1]] = $value;\n        return null;\n    }\n    // 批量设置\n    if (is_array($name)){\n        $_config = array_merge($_config, array_change_key_case($name,CASE_UPPER));\n        return null;\n    }\n    return null; // 避免非法参数\n}\n\n/**\n * 加载配置文件 支持格式转换 仅支持一级配置\n * @param string $file 配置文件名\n * @param string $parse 配置解析方法 有些格式需要用户自己解析\n * @return array\n */\nfunction load_config($file,$parse=CONF_PARSE){\n    $ext  = pathinfo($file,PATHINFO_EXTENSION);\n    switch($ext){\n        case 'php':\n            return include $file;\n        case 'ini':\n            return parse_ini_file($file);\n        case 'yaml':\n            return yaml_parse_file($file);\n        case 'xml': \n            return (array)simplexml_load_file($file);\n        case 'json':\n            return json_decode(file_get_contents($file), true);\n        default:\n            if(function_exists($parse)){\n                return $parse($file);\n            }else{\n                E(L('_NOT_SUPPORT_').':'.$ext);\n            }\n    }\n}\n\n/**\n * 解析yaml文件返回一个数组\n * @param string $file 配置文件名\n * @return array\n */\nif (!function_exists('yaml_parse_file')) {\n    function yaml_parse_file($file) {\n        vendor('spyc.Spyc');\n        return Spyc::YAMLLoad($file);\n    }\n}\n\n/**\n * 抛出异常处理\n * @param string $msg 异常消息\n * @param integer $code 异常代码 默认为0\n * @throws Think\\Exception\n * @return void\n */\nfunction E($msg, $code=0) {\n    throw new Think\\Exception($msg, $code);\n}\n\n/**\n * 记录和统计时间（微秒）和内存使用情况\n * 使用方法:\n * <code>\n * G('begin'); // 记录开始标记位\n * // ... 区间运行代码\n * G('end'); // 记录结束标签位\n * echo G('begin','end',6); // 统计区间运行时间 精确到小数后6位\n * echo G('begin','end','m'); // 统计区间内存使用情况\n * 如果end标记位没有定义，则会自动以当前作为标记位\n * 其中统计内存使用需要 MEMORY_LIMIT_ON 常量为true才有效\n * </code>\n * @param string $start 开始标签\n * @param string $end 结束标签\n * @param integer|string $dec 小数位或者m\n * @return mixed\n */\nfunction G($start,$end='',$dec=4) {\n    static $_info       =   array();\n    static $_mem        =   array();\n    if(is_float($end)) { // 记录时间\n        $_info[$start]  =   $end;\n    }elseif(!empty($end)){ // 统计时间和内存使用\n        if(!isset($_info[$end])) $_info[$end]       =  microtime(TRUE);\n        if(MEMORY_LIMIT_ON && $dec=='m'){\n            if(!isset($_mem[$end])) $_mem[$end]     =  memory_get_usage();\n            return number_format(($_mem[$end]-$_mem[$start])/1024);\n        }else{\n            return number_format(($_info[$end]-$_info[$start]),$dec);\n        }\n\n    }else{ // 记录时间和内存使用\n        $_info[$start]  =  microtime(TRUE);\n        if(MEMORY_LIMIT_ON) $_mem[$start]           =  memory_get_usage();\n    }\n    return null;\n}\n\n/**\n * 获取和设置语言定义(不区分大小写)\n * @param string|array $name 语言变量\n * @param mixed $value 语言值或者变量\n * @return mixed\n */\nfunction L($name=null, $value=null) {\n    static $_lang = array();\n    // 空参数返回所有定义\n    if (empty($name))\n        return $_lang;\n    // 判断语言获取(或设置)\n    // 若不存在,直接返回全大写$name\n    if (is_string($name)) {\n        $name   =   strtoupper($name);\n        if (is_null($value)){\n            return isset($_lang[$name]) ? $_lang[$name] : $name;\n        }elseif(is_array($value)){\n            // 支持变量\n            $replace = array_keys($value);\n            foreach($replace as &$v){\n                $v = '{$'.$v.'}';\n            }\n            return str_replace($replace,$value,isset($_lang[$name]) ? $_lang[$name] : $name);        \n        }\n        $_lang[$name] = $value; // 语言定义\n        return null;\n    }\n    // 批量定义\n    if (is_array($name))\n        $_lang = array_merge($_lang, array_change_key_case($name, CASE_UPPER));\n    return null;\n}\n\n/**\n * 添加和获取页面Trace记录\n * @param string $value 变量\n * @param string $label 标签\n * @param string $level 日志级别\n * @param boolean $record 是否记录日志\n * @return void|array\n */\nfunction trace($value='[think]',$label='',$level='DEBUG',$record=false) {\n    return Think\\Think::trace($value,$label,$level,$record);\n}\n\n/**\n * 编译文件\n * @param string $filename 文件名\n * @return string\n */\nfunction compile($filename) {\n    $content    =   php_strip_whitespace($filename);\n    $content    =   trim(substr($content, 5));\n    // 替换预编译指令\n    $content    =   preg_replace('/\\/\\/\\[RUNTIME\\](.*?)\\/\\/\\[\\/RUNTIME\\]/s', '', $content);\n    if(0===strpos($content,'namespace')){\n        $content    =   preg_replace('/namespace\\s(.*?);/','namespace \\\\1{',$content,1);\n    }else{\n        $content    =   'namespace {'.$content;\n    }\n    if ('?>' == substr($content, -2))\n        $content    = substr($content, 0, -2);\n    return $content.'}';\n}\n\n/**\n * 获取模版文件 格式 资源://模块@主题/控制器/操作\n * @param string $template 模版资源地址\n * @param string $layer 视图层（目录）名称\n * @return string\n */\nfunction T($template='',$layer=''){\n\n    // 解析模版资源地址\n    if(false === strpos($template,'://')){\n        $template   =   'http://'.str_replace(':', '/',$template);\n    }\n    $info   =   parse_url($template);\n    $file   =   $info['host'].(isset($info['path'])?$info['path']:'');\n    $module =   isset($info['user'])?$info['user'].'/':MODULE_NAME.'/';\n    $extend =   $info['scheme'];\n    $layer  =   $layer?$layer:C('DEFAULT_V_LAYER');\n\n    // 获取当前主题的模版路径\n    $auto   =   C('AUTOLOAD_NAMESPACE');\n    if($auto && isset($auto[$extend])){ // 扩展资源\n        $baseUrl    =   $auto[$extend].$module.$layer.'/';\n    }elseif(C('VIEW_PATH')){ \n        // 改变模块视图目录\n        $baseUrl    =   C('VIEW_PATH');\n    }elseif(defined('TMPL_PATH')){ \n        // 指定全局视图目录\n        $baseUrl    =   TMPL_PATH.$module;\n    }else{\n        $baseUrl    =   APP_PATH.$module.$layer.'/';\n    }\n\n    // 获取主题\n    $theme  =   substr_count($file,'/')<2 ? C('DEFAULT_THEME') : '';\n\n    // 分析模板文件规则\n    $depr   =   C('TMPL_FILE_DEPR');\n    if('' == $file) {\n        // 如果模板文件名为空 按照默认规则定位\n        $file = CONTROLLER_NAME . $depr . ACTION_NAME;\n    }elseif(false === strpos($file, '/')){\n        $file = CONTROLLER_NAME . $depr . $file;\n    }elseif('/' != $depr){\n        $file   =   substr_count($file,'/')>1 ? substr_replace($file,$depr,strrpos($file,'/'),1) : str_replace('/', $depr, $file);\n    }\n    return $baseUrl.($theme?$theme.'/':'').$file.C('TMPL_TEMPLATE_SUFFIX');\n}\n\n/**\n * 获取输入参数 支持过滤和默认值\n * 使用方法:\n * <code>\n * I('id',0); 获取id参数 自动判断get或者post\n * I('post.name','','htmlspecialchars'); 获取$_POST['name']\n * I('get.'); 获取$_GET\n * </code>\n * @param string $name 变量的名称 支持指定类型\n * @param mixed $default 不存在的时候默认值\n * @param mixed $filter 参数过滤方法\n * @param mixed $datas 要获取的额外数据源\n * @return mixed\n */\nfunction I($name,$default='',$filter=null,$datas=null) {\n\tstatic $_PUT\t=\tnull;\n\tif(strpos($name,'/')){ // 指定修饰符\n\t\tlist($name,$type) \t=\texplode('/',$name,2);\n\t}elseif(C('VAR_AUTO_STRING')){ // 默认强制转换为字符串\n        $type   =   's';\n    }\n    if(strpos($name,'.')) { // 指定参数来源\n        list($method,$name) =   explode('.',$name,2);\n    }else{ // 默认为自动判断\n        $method =   'param';\n    }\n    switch(strtolower($method)) {\n        case 'get'     :   \n        \t$input =& $_GET;\n        \tbreak;\n        case 'post'    :   \n        \t$input =& $_POST;\n        \tbreak;\n        case 'put'     :   \n        \tif(is_null($_PUT)){\n            \tparse_str(file_get_contents('php://input'), $_PUT);\n        \t}\n        \t$input \t=\t$_PUT;        \n        \tbreak;\n        case 'param'   :\n            switch($_SERVER['REQUEST_METHOD']) {\n                case 'POST':\n                    $input  =  $_POST;\n                    break;\n                case 'PUT':\n                \tif(is_null($_PUT)){\n                    \tparse_str(file_get_contents('php://input'), $_PUT);\n                \t}\n                \t$input \t=\t$_PUT;\n                    break;\n                default:\n                    $input  =  $_GET;\n            }\n            break;\n        case 'path'    :   \n            $input  =   array();\n            if(!empty($_SERVER['PATH_INFO'])){\n                $depr   =   C('URL_PATHINFO_DEPR');\n                $input  =   explode($depr,trim($_SERVER['PATH_INFO'],$depr));            \n            }\n            break;\n        case 'request' :   \n        \t$input =& $_REQUEST;   \n        \tbreak;\n        case 'session' :   \n        \t$input =& $_SESSION;   \n        \tbreak;\n        case 'cookie'  :   \n        \t$input =& $_COOKIE;    \n        \tbreak;\n        case 'server'  :   \n        \t$input =& $_SERVER;    \n        \tbreak;\n        case 'globals' :   \n        \t$input = $GLOBALS;    \n        \tbreak;\n        case 'data'    :   \n        \t$input =& $datas;      \n        \tbreak;\n        default:\n            return null;\n    }\n    if(''==$name) { // 获取全部变量\n        $data       =   $input;\n        $filters    =   isset($filter)?$filter:C('DEFAULT_FILTER');\n        if($filters) {\n            if(is_string($filters)){\n                $filters    =   explode(',',$filters);\n            }\n            foreach($filters as $filter){\n                $data   =   array_map_recursive($filter,$data); // 参数过滤\n            }\n        }\n    }elseif(isset($input[$name])) { // 取值操作\n        $data       =   $input[$name];\n        $filters    =   isset($filter)?$filter:C('DEFAULT_FILTER');\n        if($filters) {\n            if(is_string($filters)){\n                if(0 === strpos($filters,'/')){\n                    if(1 !== preg_match($filters,(string)$data)){\n                        // 支持正则验证\n                        return   isset($default) ? $default : null;\n                    }\n                }else{\n                    $filters    =   explode(',',$filters);                    \n                }\n            }elseif(is_int($filters)){\n                $filters    =   array($filters);\n            }\n            \n            if(is_array($filters)){\n                foreach($filters as $filter){\n                    if(function_exists($filter)) {\n                        $data   =   is_array($data) ? array_map_recursive($filter,$data) : $filter($data); // 参数过滤\n                    }else{\n                        $data   =   filter_var($data,is_int($filter) ? $filter : filter_id($filter));\n                        if(false === $data) {\n                            return   isset($default) ? $default : null;\n                        }\n                    }\n                }\n            }\n        }\n        if(!empty($type)){\n        \tswitch(strtolower($type)){\n        \t\tcase 'a':\t// 数组\n        \t\t\t$data \t=\t(array)$data;\n        \t\t\tbreak;\n        \t\tcase 'd':\t// 数字\n        \t\t\t$data \t=\t(int)$data;\n        \t\t\tbreak;\n        \t\tcase 'f':\t// 浮点\n        \t\t\t$data \t=\t(float)$data;\n        \t\t\tbreak;\n        \t\tcase 'b':\t// 布尔\n        \t\t\t$data \t=\t(boolean)$data;\n        \t\t\tbreak;\n                case 's':   // 字符串\n                default:\n                    $data   =   (string)$data;\n        \t}\n        }\n    }else{ // 变量默认值\n        $data       =    isset($default)?$default:null;\n    }\n    is_array($data) && array_walk_recursive($data,'think_filter');\n    return $data;\n}\n\nfunction array_map_recursive($filter, $data) {\n    $result = array();\n    foreach ($data as $key => $val) {\n        $result[$key] = is_array($val)\n         ? array_map_recursive($filter, $val)\n         : call_user_func($filter, $val);\n    }\n    return $result;\n }\n\n/**\n * 设置和获取统计数据\n * 使用方法:\n * <code>\n * N('db',1); // 记录数据库操作次数\n * N('read',1); // 记录读取次数\n * echo N('db'); // 获取当前页面数据库的所有操作次数\n * echo N('read'); // 获取当前页面读取次数\n * </code>\n * @param string $key 标识位置\n * @param integer $step 步进值\n * @param boolean $save 是否保存结果\n * @return mixed\n */\nfunction N($key, $step=0,$save=false) {\n    static $_num    = array();\n    if (!isset($_num[$key])) {\n        $_num[$key] = (false !== $save)? S('N_'.$key) :  0;\n    }\n    if (empty($step)){\n        return $_num[$key];\n    }else{\n        $_num[$key] = $_num[$key] + (int)$step;\n    }\n    if(false !== $save){ // 保存结果\n        S('N_'.$key,$_num[$key],$save);\n    }\n    return null;\n}\n\n/**\n * 字符串命名风格转换\n * type 0 将Java风格转换为C的风格 1 将C风格转换为Java的风格\n * @param string $name 字符串\n * @param integer $type 转换类型\n * @return string\n */\nfunction parse_name($name, $type=0) {\n    if ($type) {\n        return ucfirst(preg_replace_callback('/_([a-zA-Z])/', function($match){return strtoupper($match[1]);}, $name));\n    } else {\n        return strtolower(trim(preg_replace(\"/[A-Z]/\", \"_\\\\0\", $name), \"_\"));\n    }\n}\n\n/**\n * 优化的require_once\n * @param string $filename 文件地址\n * @return boolean\n */\nfunction require_cache($filename) {\n    static $_importFiles = array();\n    if (!isset($_importFiles[$filename])) {\n        if (file_exists_case($filename)) {\n            require $filename;\n            $_importFiles[$filename] = true;\n        } else {\n            $_importFiles[$filename] = false;\n        }\n    }\n    return $_importFiles[$filename];\n}\n\n/**\n * 区分大小写的文件存在判断\n * @param string $filename 文件地址\n * @return boolean\n */\nfunction file_exists_case($filename) {\n    if (is_file($filename)) {\n        if (IS_WIN && APP_DEBUG) {\n            if (basename(realpath($filename)) != basename($filename))\n                return false;\n        }\n        return true;\n    }\n    return false;\n}\n\n/**\n * 导入所需的类库 同java的Import 本函数有缓存功能\n * @param string $class 类库命名空间字符串\n * @param string $baseUrl 起始路径\n * @param string $ext 导入的文件扩展名\n * @return boolean\n */\nfunction import($class, $baseUrl = '', $ext=EXT) {\n    static $_file = array();\n    $class = str_replace(array('.', '#'), array('/', '.'), $class);\n    if (isset($_file[$class . $baseUrl]))\n        return true;\n    else\n        $_file[$class . $baseUrl] = true;\n    $class_strut     = explode('/', $class);\n    if (empty($baseUrl)) {\n        if ('@' == $class_strut[0] || MODULE_NAME == $class_strut[0]) {\n            //加载当前模块的类库\n            $baseUrl = MODULE_PATH;\n            $class   = substr_replace($class, '', 0, strlen($class_strut[0]) + 1);\n        }elseif ('Common' == $class_strut[0]) {\n            //加载公共模块的类库\n            $baseUrl = COMMON_PATH;\n            $class   = substr($class, 7);\n        }elseif (in_array($class_strut[0],array('Think','Org','Behavior','Com','Vendor')) || is_dir(LIB_PATH.$class_strut[0])) {\n            // 系统类库包和第三方类库包\n            $baseUrl = LIB_PATH;\n        }else { // 加载其他模块的类库\n            $baseUrl = APP_PATH;\n        }\n    }\n    if (substr($baseUrl, -1) != '/')\n        $baseUrl    .= '/';\n    $classfile       = $baseUrl . $class . $ext;\n    if (!class_exists(basename($class),false)) {\n        // 如果类不存在 则导入类库文件\n        return require_cache($classfile);\n    }\n    return null;\n}\n\n/**\n * 基于命名空间方式导入函数库\n * load('@.Util.Array')\n * @param string $name 函数库命名空间字符串\n * @param string $baseUrl 起始路径\n * @param string $ext 导入的文件扩展名\n * @return void\n */\nfunction load($name, $baseUrl='', $ext='.php') {\n    $name = str_replace(array('.', '#'), array('/', '.'), $name);\n    if (empty($baseUrl)) {\n        if (0 === strpos($name, '@/')) {//加载当前模块函数库\n            $baseUrl    =   MODULE_PATH.'Common/';\n            $name       =   substr($name, 2);\n        } else { //加载其他模块函数库\n            $array      =   explode('/', $name);\n            $baseUrl    =   APP_PATH . array_shift($array).'/Common/';\n            $name       =   implode('/',$array);\n        }\n    }\n    if (substr($baseUrl, -1) != '/')\n        $baseUrl       .= '/';\n    require_cache($baseUrl . $name . $ext);\n}\n\n/**\n * 快速导入第三方框架类库 所有第三方框架的类库文件统一放到 系统的Vendor目录下面\n * @param string $class 类库\n * @param string $baseUrl 基础目录\n * @param string $ext 类库后缀\n * @return boolean\n */\nfunction vendor($class, $baseUrl = '', $ext='.php') {\n    if (empty($baseUrl))\n        $baseUrl = VENDOR_PATH;\n    return import($class, $baseUrl, $ext);\n}\n\n/**\n * 实例化模型类 格式 [资源://][模块/]模型\n * @param string $name 资源地址\n * @param string $layer 模型层名称\n * @return Think\\Model\n */\nfunction D($name='',$layer='') {\n    if(empty($name)) return new Think\\Model;\n    static $_model  =   array();\n    $layer          =   $layer? : C('DEFAULT_M_LAYER');\n    if(isset($_model[$name.$layer]))\n        return $_model[$name.$layer];\n    $class          =   parse_res_name($name,$layer);\n    if(class_exists($class)) {\n        $model      =   new $class(basename($name));\n    }elseif(false === strpos($name,'/')){\n        // 自动加载公共模块下面的模型\n        if(!C('APP_USE_NAMESPACE')){\n            import('Common/'.$layer.'/'.$class);\n        }else{\n            $class      =   '\\\\Common\\\\'.$layer.'\\\\'.$name.$layer;\n        }\n        $model      =   class_exists($class)? new $class($name) : new Think\\Model($name);\n    }else {\n        Think\\Log::record('D方法实例化没找到模型类'.$class,Think\\Log::NOTICE);\n        $model      =   new Think\\Model(basename($name));\n    }\n    $_model[$name.$layer]  =  $model;\n    return $model;\n}\n\n/**\n * 实例化一个没有模型文件的Model\n * @param string $name Model名称 支持指定基础模型 例如 MongoModel:User\n * @param string $tablePrefix 表前缀\n * @param mixed $connection 数据库连接信息\n * @return Think\\Model\n */\nfunction M($name='', $tablePrefix='',$connection='') {\n    static $_model  = array();\n    if(strpos($name,':')) {\n        list($class,$name)    =  explode(':',$name);\n    }else{\n        $class      =   'Think\\\\Model';\n    }\n    $guid           =   (is_array($connection)?implode('',$connection):$connection).$tablePrefix . $name . '_' . $class;\n    if (!isset($_model[$guid]))\n        $_model[$guid] = new $class($name,$tablePrefix,$connection);\n    return $_model[$guid];\n}\n\n/**\n * 解析资源地址并导入类库文件\n * 例如 module/controller addon://module/behavior\n * @param string $name 资源地址 格式：[扩展://][模块/]资源名\n * @param string $layer 分层名称\n * @param integer $level 控制器层次\n * @return string\n */\nfunction parse_res_name($name,$layer,$level=1){\n    if(strpos($name,'://')) {// 指定扩展资源\n        list($extend,$name)  =   explode('://',$name);\n    }else{\n        $extend  =   '';\n    }\n    if(strpos($name,'/') && substr_count($name, '/')>=$level){ // 指定模块\n        list($module,$name) =  explode('/',$name,2);\n    }else{\n        $module =   defined('MODULE_NAME') ? MODULE_NAME : '' ;\n    }\n    $array  =   explode('/',$name);\n    if(!C('APP_USE_NAMESPACE')){\n        $class  =   parse_name($name, 1);\n        import($module.'/'.$layer.'/'.$class.$layer);\n    }else{\n        $class  =   $module.'\\\\'.$layer;\n        foreach($array as $name){\n            $class  .=   '\\\\'.parse_name($name, 1);\n        }\n        // 导入资源类库\n        if($extend){ // 扩展资源\n            $class      =   $extend.'\\\\'.$class;\n        }\n    }\n    return $class.$layer;\n}\n\n/**\n * 用于实例化访问控制器\n * @param string $name 控制器名\n * @param string $path 控制器命名空间（路径）\n * @return Think\\Controller|false\n */\nfunction controller($name,$path=''){\n    $layer  =   C('DEFAULT_C_LAYER');\n    if(!C('APP_USE_NAMESPACE')){\n        $class  =   parse_name($name, 1).$layer;\n        import(MODULE_NAME.'/'.$layer.'/'.$class);\n    }else{\n        $class  =   ( $path ? basename(ADDON_PATH).'\\\\'.$path : MODULE_NAME ).'\\\\'.$layer;\n        $array  =   explode('/',$name);\n        foreach($array as $name){\n            $class  .=   '\\\\'.parse_name($name, 1);\n        }\n        $class .=   $layer;\n    }\n    if(class_exists($class)) {\n        return new $class();\n    }else {\n        return false;\n    }\n}\n\n/**\n * 实例化多层控制器 格式：[资源://][模块/]控制器\n * @param string $name 资源地址\n * @param string $layer 控制层名称\n * @param integer $level 控制器层次\n * @return Think\\Controller|false\n */\nfunction A($name,$layer='',$level=0) {\n    static $_action = array();\n    $layer  =   $layer? : C('DEFAULT_C_LAYER');\n    $level  =   $level? : ($layer == C('DEFAULT_C_LAYER')?C('CONTROLLER_LEVEL'):1);\n    if(isset($_action[$name.$layer]))\n        return $_action[$name.$layer];\n    \n    $class  =   parse_res_name($name,$layer,$level);\n    if(class_exists($class)) {\n        $action             =   new $class();\n        $_action[$name.$layer]     =   $action;\n        return $action;\n    }else {\n        return false;\n    }\n}\n\n\n/**\n * 远程调用控制器的操作方法 URL 参数格式 [资源://][模块/]控制器/操作\n * @param string $url 调用地址\n * @param string|array $vars 调用参数 支持字符串和数组\n * @param string $layer 要调用的控制层名称\n * @return mixed\n */\nfunction R($url,$vars=array(),$layer='') {\n    $info   =   pathinfo($url);\n    $action =   $info['basename'];\n    $module =   $info['dirname'];\n    $class  =   A($module,$layer);\n    if($class){\n        if(is_string($vars)) {\n            parse_str($vars,$vars);\n        }\n        return call_user_func_array(array(&$class,$action.C('ACTION_SUFFIX')),$vars);\n    }else{\n        return false;\n    }\n}\n\n/**\n * 处理标签扩展\n * @param string $tag 标签名称\n * @param mixed $params 传入参数\n * @return void\n */\nfunction tag($tag, &$params=NULL) {\n    \\Think\\Hook::listen($tag,$params);\n}\n\n/**\n * 执行某个行为\n * @param string $name 行为名称\n * @param string $tag 标签名称（行为类无需传入） \n * @param Mixed $params 传入的参数\n * @return void\n */\nfunction B($name, $tag='',&$params=NULL) {\n    if(''==$tag){\n        $name   .=  'Behavior';\n    }\n    return \\Think\\Hook::exec($name,$tag,$params);\n}\n\n/**\n * 去除代码中的空白和注释\n * @param string $content 代码内容\n * @return string\n */\nfunction strip_whitespace($content) {\n    $stripStr   = '';\n    //分析php源码\n    $tokens     = token_get_all($content);\n    $last_space = false;\n    for ($i = 0, $j = count($tokens); $i < $j; $i++) {\n        if (is_string($tokens[$i])) {\n            $last_space = false;\n            $stripStr  .= $tokens[$i];\n        } else {\n            switch ($tokens[$i][0]) {\n                //过滤各种PHP注释\n                case T_COMMENT:\n                case T_DOC_COMMENT:\n                    break;\n                //过滤空格\n                case T_WHITESPACE:\n                    if (!$last_space) {\n                        $stripStr  .= ' ';\n                        $last_space = true;\n                    }\n                    break;\n                case T_START_HEREDOC:\n                    $stripStr .= \"<<<THINK\\n\";\n                    break;\n                case T_END_HEREDOC:\n                    $stripStr .= \"THINK;\\n\";\n                    for($k = $i+1; $k < $j; $k++) {\n                        if(is_string($tokens[$k]) && $tokens[$k] == ';') {\n                            $i = $k;\n                            break;\n                        } else if($tokens[$k][0] == T_CLOSE_TAG) {\n                            break;\n                        }\n                    }\n                    break;\n                default:\n                    $last_space = false;\n                    $stripStr  .= $tokens[$i][1];\n            }\n        }\n    }\n    return $stripStr;\n}\n\n/**\n * 自定义异常处理\n * @param string $msg 异常消息\n * @param string $type 异常类型 默认为Think\\Exception\n * @param integer $code 异常代码 默认为0\n * @return void\n */\nfunction throw_exception($msg, $type='Think\\\\Exception', $code=0) {\n    Think\\Log::record('建议使用E方法替代throw_exception',Think\\Log::NOTICE);\n    if (class_exists($type, false))\n        throw new $type($msg, $code);\n    else\n        Think\\Think::halt($msg);        // 异常类型不存在则输出错误信息字串\n}\n\n/**\n * 浏览器友好的变量输出\n * @param mixed $var 变量\n * @param boolean $echo 是否输出 默认为True 如果为false 则返回输出字符串\n * @param string $label 标签 默认为空\n * @param boolean $strict 是否严谨 默认为true\n * @return void|string\n */\nfunction dump($var, $echo=true, $label=null, $strict=true) {\n    $label = ($label === null) ? '' : rtrim($label) . ' ';\n    if (!$strict) {\n        if (ini_get('html_errors')) {\n            $output = print_r($var, true);\n            $output = '<pre>' . $label . htmlspecialchars($output, ENT_QUOTES) . '</pre>';\n        } else {\n            $output = $label . print_r($var, true);\n        }\n    } else {\n        ob_start();\n        var_dump($var);\n        $output = ob_get_clean();\n        if (!extension_loaded('xdebug')) {\n            $output = preg_replace('/\\]\\=\\>\\n(\\s+)/m', '] => ', $output);\n            $output = '<pre>' . $label . htmlspecialchars($output, ENT_QUOTES) . '</pre>';\n        }\n    }\n    if ($echo) {\n        echo($output);\n        return null;\n    }else\n        return $output;\n}\n\n/**\n * 设置当前页面的布局\n * @param string|false $layout 布局名称 为false的时候表示关闭布局\n * @return void\n */\nfunction layout($layout) {\n    if(false !== $layout) {\n        // 开启布局\n        C('LAYOUT_ON',true);\n        if(is_string($layout)) { // 设置新的布局模板\n            C('LAYOUT_NAME',$layout);\n        }\n    }else{// 临时关闭布局\n        C('LAYOUT_ON',false);\n    }\n}\n\n/**\n * URL组装 支持不同URL模式\n * @param string $url URL表达式，格式：'[模块/控制器/操作#锚点@域名]?参数1=值1&参数2=值2...'\n * @param string|array $vars 传入的参数，支持数组和字符串\n * @param string|boolean $suffix 伪静态后缀，默认为true表示获取配置值\n * @param boolean $domain 是否显示域名\n * @return string\n */\nfunction U($url='',$vars='',$suffix=true,$domain=false) {\n    // 解析URL\n    $info   =  parse_url($url);\n    $url    =  !empty($info['path'])?$info['path']:ACTION_NAME;\n    if(isset($info['fragment'])) { // 解析锚点\n        $anchor =   $info['fragment'];\n        if(false !== strpos($anchor,'?')) { // 解析参数\n            list($anchor,$info['query']) = explode('?',$anchor,2);\n        }        \n        if(false !== strpos($anchor,'@')) { // 解析域名\n            list($anchor,$host)    =   explode('@',$anchor, 2);\n        }\n    }elseif(false !== strpos($url,'@')) { // 解析域名\n        list($url,$host)    =   explode('@',$info['path'], 2);\n    }\n    // 解析子域名\n    if(isset($host)) {\n        $domain = $host.(strpos($host,'.')?'':strstr($_SERVER['HTTP_HOST'],'.'));\n    }elseif($domain===true){\n        $domain = $_SERVER['HTTP_HOST'];\n        if(C('APP_SUB_DOMAIN_DEPLOY') ) { // 开启子域名部署\n            $domain = $domain=='localhost'?'localhost':'www'.strstr($_SERVER['HTTP_HOST'],'.');\n            // '子域名'=>array('模块[/控制器]');\n            foreach (C('APP_SUB_DOMAIN_RULES') as $key => $rule) {\n                $rule   =   is_array($rule)?$rule[0]:$rule;\n                if(false === strpos($key,'*') && 0=== strpos($url,$rule)) {\n                    $domain = $key.strstr($domain,'.'); // 生成对应子域名\n                    $url    =  substr_replace($url,'',0,strlen($rule));\n                    break;\n                }\n            }\n        }\n    }\n\n    // 解析参数\n    if(is_string($vars)) { // aaa=1&bbb=2 转换成数组\n        parse_str($vars,$vars);\n    }elseif(!is_array($vars)){\n        $vars = array();\n    }\n    if(isset($info['query'])) { // 解析地址里面参数 合并到vars\n        parse_str($info['query'],$params);\n        $vars = array_merge($params,$vars);\n    }\n    \n    // URL组装\n    $depr       =   C('URL_PATHINFO_DEPR');\n    $urlCase    =   C('URL_CASE_INSENSITIVE');\n    if($url) {\n        if(0=== strpos($url,'/')) {// 定义路由\n            $route      =   true;\n            $url        =   substr($url,1);\n            if('/' != $depr) {\n                $url    =   str_replace('/',$depr,$url);\n            }\n        }else{\n            if('/' != $depr) { // 安全替换\n                $url    =   str_replace('/',$depr,$url);\n            }\n            // 解析模块、控制器和操作\n            $url        =   trim($url,$depr);\n            $path       =   explode($depr,$url);\n            $var        =   array();\n            $varModule      =   C('VAR_MODULE');\n            $varController  =   C('VAR_CONTROLLER');\n            $varAction      =   C('VAR_ACTION');\n            $var[$varAction]       =   !empty($path)?array_pop($path):ACTION_NAME;\n            $var[$varController]   =   !empty($path)?array_pop($path):CONTROLLER_NAME;\n            if($maps = C('URL_ACTION_MAP')) {\n                if(isset($maps[strtolower($var[$varController])])) {\n                    $maps    =   $maps[strtolower($var[$varController])];\n                    if($action = array_search(strtolower($var[$varAction]),$maps)){\n                        $var[$varAction] = $action;\n                    }\n                }\n            }\n            if($maps = C('URL_CONTROLLER_MAP')) {\n                if($controller = array_search(strtolower($var[$varController]),$maps)){\n                    $var[$varController] = $controller;\n                }\n            }\n            if($urlCase) {\n                $var[$varController]   =   parse_name($var[$varController]);\n            }\n            $module =   '';\n            \n            if(!empty($path)) {\n                $var[$varModule]    =   implode($depr,$path);\n            }else{\n                if(C('MULTI_MODULE')) {\n                    if(MODULE_NAME != C('DEFAULT_MODULE') || !C('MODULE_ALLOW_LIST')){\n                        $var[$varModule]=   MODULE_NAME;\n                    }\n                }\n            }\n            if($maps = C('URL_MODULE_MAP')) {\n                if($_module = array_search(strtolower($var[$varModule]),$maps)){\n                    $var[$varModule] = $_module;\n                }\n            }\n            if(isset($var[$varModule])){\n                $module =   $var[$varModule];\n                unset($var[$varModule]);\n            }\n            \n        }\n    }\n\n    if(C('URL_MODEL') == 0) { // 普通模式URL转换\n        $url        =   __APP__.'?'.C('VAR_MODULE').\"={$module}&\".http_build_query(array_reverse($var));\n        if($urlCase){\n            $url    =   strtolower($url);\n        }        \n        if(!empty($vars)) {\n            $vars   =   http_build_query($vars);\n            $url   .=   '&'.$vars;\n        }\n    }else{ // PATHINFO模式或者兼容URL模式\n        if(isset($route)) {\n            $url    =   __APP__.'/'.rtrim($url,$depr);\n        }else{\n            $module =   (defined('BIND_MODULE') && BIND_MODULE==$module )? '' : $module;\n            $url    =   __APP__.'/'.($module?$module.MODULE_PATHINFO_DEPR:'').implode($depr,array_reverse($var));\n        }\n        if($urlCase){\n            $url    =   strtolower($url);\n        }\n        if(!empty($vars)) { // 添加参数\n            foreach ($vars as $var => $val){\n                if('' !== trim($val))   $url .= $depr . $var . $depr . urlencode($val);\n            }                \n        }\n        if($suffix) {\n            $suffix   =  $suffix===true?C('URL_HTML_SUFFIX'):$suffix;\n            if($pos = strpos($suffix, '|')){\n                $suffix = substr($suffix, 0, $pos);\n            }\n            if($suffix && '/' != substr($url,-1)){\n                $url  .=  '.'.ltrim($suffix,'.');\n            }\n        }\n    }\n    if(isset($anchor)){\n        $url  .= '#'.$anchor;\n    }\n    if($domain) {\n        $url   =  (is_ssl()?'https://':'http://').$domain.$url;\n    }\n    return $url;\n}\n\n/**\n * 渲染输出Widget\n * @param string $name Widget名称\n * @param array $data 传入的参数\n * @return void\n */\nfunction W($name, $data=array()) {\n    return R($name,$data,'Widget');\n}\n\n/**\n * 判断是否SSL协议\n * @return boolean\n */\nfunction is_ssl() {\n    if(isset($_SERVER['HTTPS']) && ('1' == $_SERVER['HTTPS'] || 'on' == strtolower($_SERVER['HTTPS']))){\n        return true;\n    }elseif(isset($_SERVER['SERVER_PORT']) && ('443' == $_SERVER['SERVER_PORT'] )) {\n        return true;\n    }\n    return false;\n}\n\n/**\n * URL重定向\n * @param string $url 重定向的URL地址\n * @param integer $time 重定向的等待时间（秒）\n * @param string $msg 重定向前的提示信息\n * @return void\n */\nfunction redirect($url, $time=0, $msg='') {\n    //多行URL地址支持\n    $url        = str_replace(array(\"\\n\", \"\\r\"), '', $url);\n    if (empty($msg))\n        $msg    = \"系统将在{$time}秒之后自动跳转到{$url}！\";\n    if (!headers_sent()) {\n        // redirect\n        if (0 === $time) {\n            header('Location: ' . $url);\n        } else {\n            header(\"refresh:{$time};url={$url}\");\n            echo($msg);\n        }\n        exit();\n    } else {\n        $str    = \"<meta http-equiv='Refresh' content='{$time};URL={$url}'>\";\n        if ($time != 0)\n            $str .= $msg;\n        exit($str);\n    }\n}\n\n/**\n * 缓存管理\n * @param mixed $name 缓存名称，如果为数组表示进行缓存设置\n * @param mixed $value 缓存值\n * @param mixed $options 缓存参数\n * @return mixed\n */\nfunction S($name,$value='',$options=null) {\n    static $cache   =   '';\n    if(is_array($options)){\n        // 缓存操作的同时初始化\n        $type       =   isset($options['type'])?$options['type']:'';\n        $cache      =   Think\\Cache::getInstance($type,$options);\n    }elseif(is_array($name)) { // 缓存初始化\n        $type       =   isset($name['type'])?$name['type']:'';\n        $cache      =   Think\\Cache::getInstance($type,$name);\n        return $cache;\n    }elseif(empty($cache)) { // 自动初始化\n        $cache      =   Think\\Cache::getInstance();\n    }\n    if(''=== $value){ // 获取缓存\n        return $cache->get($name);\n    }elseif(is_null($value)) { // 删除缓存\n        return $cache->rm($name);\n    }else { // 缓存数据\n        if(is_array($options)) {\n            $expire     =   isset($options['expire'])?$options['expire']:NULL;\n        }else{\n            $expire     =   is_numeric($options)?$options:NULL;\n        }\n        return $cache->set($name, $value, $expire);\n    }\n}\n\n/**\n * 快速文件数据读取和保存 针对简单类型数据 字符串、数组\n * @param string $name 缓存名称\n * @param mixed $value 缓存值\n * @param string $path 缓存路径\n * @return mixed\n */\nfunction F($name, $value='', $path=DATA_PATH) {\n    static $_cache  =   array();\n    $filename       =   $path . $name . '.php';\n    if ('' !== $value) {\n        if (is_null($value)) {\n            // 删除缓存\n            if(false !== strpos($name,'*')){\n                return false; // TODO \n            }else{\n                unset($_cache[$name]);\n                return Think\\Storage::unlink($filename,'F');\n            }\n        } else {\n            Think\\Storage::put($filename,serialize($value),'F');\n            // 缓存数据\n            $_cache[$name]  =   $value;\n            return null;\n        }\n    }\n    // 获取缓存数据\n    if (isset($_cache[$name]))\n        return $_cache[$name];\n    if (Think\\Storage::has($filename,'F')){\n        $value      =   unserialize(Think\\Storage::read($filename,'F'));\n        $_cache[$name]  =   $value;\n    } else {\n        $value          =   false;\n    }\n    return $value;\n}\n\n/**\n * 根据PHP各种类型变量生成唯一标识号\n * @param mixed $mix 变量\n * @return string\n */\nfunction to_guid_string($mix) {\n    if (is_object($mix)) {\n        return spl_object_hash($mix);\n    } elseif (is_resource($mix)) {\n        $mix = get_resource_type($mix) . strval($mix);\n    } else {\n        $mix = serialize($mix);\n    }\n    return md5($mix);\n}\n\n/**\n * XML编码\n * @param mixed $data 数据\n * @param string $root 根节点名\n * @param string $item 数字索引的子节点名\n * @param string $attr 根节点属性\n * @param string $id   数字索引子节点key转换的属性名\n * @param string $encoding 数据编码\n * @return string\n */\nfunction xml_encode($data, $root='think', $item='item', $attr='', $id='id', $encoding='utf-8') {\n    if(is_array($attr)){\n        $_attr = array();\n        foreach ($attr as $key => $value) {\n            $_attr[] = \"{$key}=\\\"{$value}\\\"\";\n        }\n        $attr = implode(' ', $_attr);\n    }\n    $attr   = trim($attr);\n    $attr   = empty($attr) ? '' : \" {$attr}\";\n    $xml    = \"<?xml version=\\\"1.0\\\" encoding=\\\"{$encoding}\\\"?>\";\n    $xml   .= \"<{$root}{$attr}>\";\n    $xml   .= data_to_xml($data, $item, $id);\n    $xml   .= \"</{$root}>\";\n    return $xml;\n}\n\n/**\n * 数据XML编码\n * @param mixed  $data 数据\n * @param string $item 数字索引时的节点名称\n * @param string $id   数字索引key转换为的属性名\n * @return string\n */\nfunction data_to_xml($data, $item='item', $id='id') {\n    $xml = $attr = '';\n    foreach ($data as $key => $val) {\n        if(is_numeric($key)){\n            $id && $attr = \" {$id}=\\\"{$key}\\\"\";\n            $key  = $item;\n        }\n        $xml    .=  \"<{$key}{$attr}>\";\n        $xml    .=  (is_array($val) || is_object($val)) ? data_to_xml($val, $item, $id) : $val;\n        $xml    .=  \"</{$key}>\";\n    }\n    return $xml;\n}\n\n/**\n * session管理函数\n * @param string|array $name session名称 如果为数组则表示进行session设置\n * @param mixed $value session值\n * @return mixed\n */\nfunction session($name='',$value='') {\n    $prefix   =  C('SESSION_PREFIX');\n    if(is_array($name)) { // session初始化 在session_start 之前调用\n        if(isset($name['prefix'])) C('SESSION_PREFIX',$name['prefix']);\n        if(C('VAR_SESSION_ID') && isset($_REQUEST[C('VAR_SESSION_ID')])){\n            session_id($_REQUEST[C('VAR_SESSION_ID')]);\n        }elseif(isset($name['id'])) {\n            session_id($name['id']);\n        }\n        if('common' == APP_MODE){ // 其它模式可能不支持\n            ini_set('session.auto_start', 0);\n        }\n        if(isset($name['name']))            session_name($name['name']);\n        if(isset($name['path']))            session_save_path($name['path']);\n        if(isset($name['domain']))          ini_set('session.cookie_domain', $name['domain']);\n        if(isset($name['expire']))          {\n            ini_set('session.gc_maxlifetime',   $name['expire']);\n            ini_set('session.cookie_lifetime',  $name['expire']);\n        }\n        if(isset($name['use_trans_sid']))   ini_set('session.use_trans_sid', $name['use_trans_sid']?1:0);\n        if(isset($name['use_cookies']))     ini_set('session.use_cookies', $name['use_cookies']?1:0);\n        if(isset($name['cache_limiter']))   session_cache_limiter($name['cache_limiter']);\n        if(isset($name['cache_expire']))    session_cache_expire($name['cache_expire']);\n        if(isset($name['type']))            C('SESSION_TYPE',$name['type']);\n        if(C('SESSION_TYPE')) { // 读取session驱动\n            $type   =   C('SESSION_TYPE');\n            $class  =   strpos($type,'\\\\')? $type : 'Think\\\\Session\\\\Driver\\\\'. ucwords(strtolower($type));\n            $hander =   new $class();\n            session_set_save_handler(\n                array(&$hander,\"open\"), \n                array(&$hander,\"close\"), \n                array(&$hander,\"read\"), \n                array(&$hander,\"write\"), \n                array(&$hander,\"destroy\"), \n                array(&$hander,\"gc\")); \n        }\n        // 启动session\n        if(C('SESSION_AUTO_START'))  session_start();\n    }elseif('' === $value){ \n        if(''===$name){\n            // 获取全部的session\n            return $prefix ? $_SESSION[$prefix] : $_SESSION;\n        }elseif(0===strpos($name,'[')) { // session 操作\n            if('[pause]'==$name){ // 暂停session\n                session_write_close();\n            }elseif('[start]'==$name){ // 启动session\n                session_start();\n            }elseif('[destroy]'==$name){ // 销毁session\n                $_SESSION =  array();\n                session_unset();\n                session_destroy();\n            }elseif('[regenerate]'==$name){ // 重新生成id\n                session_regenerate_id();\n            }\n        }elseif(0===strpos($name,'?')){ // 检查session\n            $name   =  substr($name,1);\n            if(strpos($name,'.')){ // 支持数组\n                list($name1,$name2) =   explode('.',$name);\n                return $prefix?isset($_SESSION[$prefix][$name1][$name2]):isset($_SESSION[$name1][$name2]);\n            }else{\n                return $prefix?isset($_SESSION[$prefix][$name]):isset($_SESSION[$name]);\n            }\n        }elseif(is_null($name)){ // 清空session\n            if($prefix) {\n                unset($_SESSION[$prefix]);\n            }else{\n                $_SESSION = array();\n            }\n        }elseif($prefix){ // 获取session\n            if(strpos($name,'.')){\n                list($name1,$name2) =   explode('.',$name);\n                return isset($_SESSION[$prefix][$name1][$name2])?$_SESSION[$prefix][$name1][$name2]:null;  \n            }else{\n                return isset($_SESSION[$prefix][$name])?$_SESSION[$prefix][$name]:null;                \n            }            \n        }else{\n            if(strpos($name,'.')){\n                list($name1,$name2) =   explode('.',$name);\n                return isset($_SESSION[$name1][$name2])?$_SESSION[$name1][$name2]:null;  \n            }else{\n                return isset($_SESSION[$name])?$_SESSION[$name]:null;\n            }            \n        }\n    }elseif(is_null($value)){ // 删除session\n        if(strpos($name,'.')){\n            list($name1,$name2) =   explode('.',$name);\n            if($prefix){\n                unset($_SESSION[$prefix][$name1][$name2]);\n            }else{\n                unset($_SESSION[$name1][$name2]);\n            }\n        }else{\n            if($prefix){\n                unset($_SESSION[$prefix][$name]);\n            }else{\n                unset($_SESSION[$name]);\n            }\n        }\n    }else{ // 设置session\n\t\tif(strpos($name,'.')){\n\t\t\tlist($name1,$name2) =   explode('.',$name);\n\t\t\tif($prefix){\n\t\t\t\t$_SESSION[$prefix][$name1][$name2]   =  $value;\n\t\t\t}else{\n\t\t\t\t$_SESSION[$name1][$name2]  =  $value;\n\t\t\t}\n\t\t}else{\n\t\t\tif($prefix){\n\t\t\t\t$_SESSION[$prefix][$name]   =  $value;\n\t\t\t}else{\n\t\t\t\t$_SESSION[$name]  =  $value;\n\t\t\t}\n\t\t}\n    }\n    return null;\n}\n\n/**\n * Cookie 设置、获取、删除\n * @param string $name cookie名称\n * @param mixed $value cookie值\n * @param mixed $option cookie参数\n * @return mixed\n */\nfunction cookie($name='', $value='', $option=null) {\n    // 默认设置\n    $config = array(\n        'prefix'    =>  C('COOKIE_PREFIX'), // cookie 名称前缀\n        'expire'    =>  C('COOKIE_EXPIRE'), // cookie 保存时间\n        'path'      =>  C('COOKIE_PATH'), // cookie 保存路径\n        'domain'    =>  C('COOKIE_DOMAIN'), // cookie 有效域名\n        'secure'    =>  C('COOKIE_SECURE'), //  cookie 启用安全传输\n        'httponly'  =>  C('COOKIE_HTTPONLY'), // httponly设置\n    );\n    // 参数设置(会覆盖黙认设置)\n    if (!is_null($option)) {\n        if (is_numeric($option))\n            $option = array('expire' => $option);\n        elseif (is_string($option))\n            parse_str($option, $option);\n        $config     = array_merge($config, array_change_key_case($option));\n    }\n    if(!empty($config['httponly'])){\n        ini_set(\"session.cookie_httponly\", 1);\n    }\n    // 清除指定前缀的所有cookie\n    if (is_null($name)) {\n        if (empty($_COOKIE))\n            return null;\n        // 要删除的cookie前缀，不指定则删除config设置的指定前缀\n        $prefix = empty($value) ? $config['prefix'] : $value;\n        if (!empty($prefix)) {// 如果前缀为空字符串将不作处理直接返回\n            foreach ($_COOKIE as $key => $val) {\n                if (0 === stripos($key, $prefix)) {\n                    setcookie($key, '', time() - 3600, $config['path'], $config['domain'],$config['secure'],$config['httponly']);\n                    unset($_COOKIE[$key]);\n                }\n            }\n        }\n        return null;\n    }elseif('' === $name){\n        // 获取全部的cookie\n        return $_COOKIE;\n    }\n    $name = $config['prefix'] . str_replace('.', '_', $name);\n    if ('' === $value) {\n        if(isset($_COOKIE[$name])){\n            $value =    $_COOKIE[$name];\n            if(0===strpos($value,'think:')){\n                $value  =   substr($value,6);\n                return array_map('urldecode',json_decode(MAGIC_QUOTES_GPC?stripslashes($value):$value,true));\n            }else{\n                return $value;\n            }\n        }else{\n            return null;\n        }\n    } else {\n        if (is_null($value)) {\n            setcookie($name, '', time() - 3600, $config['path'], $config['domain'],$config['secure'],$config['httponly']);\n            unset($_COOKIE[$name]); // 删除指定cookie\n        } else {\n            // 设置cookie\n            if(is_array($value)){\n                $value  = 'think:'.json_encode(array_map('urlencode',$value));\n            }\n            $expire = !empty($config['expire']) ? time() + intval($config['expire']) : 0;\n            setcookie($name, $value, $expire, $config['path'], $config['domain'],$config['secure'],$config['httponly']);\n            $_COOKIE[$name] = $value;\n        }\n    }\n    return null;\n}\n\n/**\n * 加载动态扩展文件\n * @var string $path 文件路径\n * @return void\n */\nfunction load_ext_file($path) {\n    // 加载自定义外部文件\n    if($files = C('LOAD_EXT_FILE')) {\n        $files      =  explode(',',$files);\n        foreach ($files as $file){\n            $file   = $path.'Common/'.$file.'.php';\n            if(is_file($file)) include $file;\n        }\n    }\n    // 加载自定义的动态配置文件\n    if($configs = C('LOAD_EXT_CONFIG')) {\n        if(is_string($configs)) $configs =  explode(',',$configs);\n        foreach ($configs as $key=>$config){\n            $file   = is_file($config)? $config : $path.'Conf/'.$config.CONF_EXT;\n            if(is_file($file)) {\n                is_numeric($key)?C(load_config($file)):C($key,load_config($file));\n            }\n        }\n    }\n}\n\n/**\n * 获取客户端IP地址\n * @param integer $type 返回类型 0 返回IP地址 1 返回IPV4地址数字\n * @param boolean $adv 是否进行高级模式获取（有可能被伪装） \n * @return mixed\n */\nfunction get_client_ip($type = 0,$adv=false) {\n    $type       =  $type ? 1 : 0;\n    static $ip  =   NULL;\n    if ($ip !== NULL) return $ip[$type];\n    if($adv){\n        if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {\n            $arr    =   explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);\n            $pos    =   array_search('unknown',$arr);\n            if(false !== $pos) unset($arr[$pos]);\n            $ip     =   trim($arr[0]);\n        }elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {\n            $ip     =   $_SERVER['HTTP_CLIENT_IP'];\n        }elseif (isset($_SERVER['REMOTE_ADDR'])) {\n            $ip     =   $_SERVER['REMOTE_ADDR'];\n        }\n    }elseif (isset($_SERVER['REMOTE_ADDR'])) {\n        $ip     =   $_SERVER['REMOTE_ADDR'];\n    }\n    // IP地址合法验证\n    $long = sprintf(\"%u\",ip2long($ip));\n    $ip   = $long ? array($ip, $long) : array('0.0.0.0', 0);\n    return $ip[$type];\n}\n\n/**\n * 发送HTTP状态\n * @param integer $code 状态码\n * @return void\n */\nfunction send_http_status($code) {\n    static $_status = array(\n            // Informational 1xx\n            100 => 'Continue',\n            101 => 'Switching Protocols',\n            // Success 2xx\n            200 => 'OK',\n            201 => 'Created',\n            202 => 'Accepted',\n            203 => 'Non-Authoritative Information',\n            204 => 'No Content',\n            205 => 'Reset Content',\n            206 => 'Partial Content',\n            // Redirection 3xx\n            300 => 'Multiple Choices',\n            301 => 'Moved Permanently',\n            302 => 'Moved Temporarily ',  // 1.1\n            303 => 'See Other',\n            304 => 'Not Modified',\n            305 => 'Use Proxy',\n            // 306 is deprecated but reserved\n            307 => 'Temporary Redirect',\n            // Client Error 4xx\n            400 => 'Bad Request',\n            401 => 'Unauthorized',\n            402 => 'Payment Required',\n            403 => 'Forbidden',\n            404 => 'Not Found',\n            405 => 'Method Not Allowed',\n            406 => 'Not Acceptable',\n            407 => 'Proxy Authentication Required',\n            408 => 'Request Timeout',\n            409 => 'Conflict',\n            410 => 'Gone',\n            411 => 'Length Required',\n            412 => 'Precondition Failed',\n            413 => 'Request Entity Too Large',\n            414 => 'Request-URI Too Long',\n            415 => 'Unsupported Media Type',\n            416 => 'Requested Range Not Satisfiable',\n            417 => 'Expectation Failed',\n            // Server Error 5xx\n            500 => 'Internal Server Error',\n            501 => 'Not Implemented',\n            502 => 'Bad Gateway',\n            503 => 'Service Unavailable',\n            504 => 'Gateway Timeout',\n            505 => 'HTTP Version Not Supported',\n            509 => 'Bandwidth Limit Exceeded'\n    );\n    if(isset($_status[$code])) {\n        header('HTTP/1.1 '.$code.' '.$_status[$code]);\n        // 确保FastCGI模式下正常\n        header('Status:'.$code.' '.$_status[$code]);\n    }\n}\n\nfunction think_filter(&$value){\n\t// TODO 其他安全过滤\n\n\t// 过滤查询特殊字符\n    if(preg_match('/^(EXP|NEQ|GT|EGT|LT|ELT|OR|XOR|LIKE|NOTLIKE|NOT BETWEEN|NOTBETWEEN|BETWEEN|NOTIN|NOT IN|IN|BIND)$/i', $value)) {\n\n        $value .= ' ';\n\n    }\n}\n\n// 不区分大小写的in_array实现\nfunction in_array_case($value,$array){\n    return in_array(strtolower($value),array_map('strtolower',$array));\n}\n"
  },
  {
    "path": "server/ThinkPHP/Conf/convention.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\n/**\n * ThinkPHP惯例配置文件\n * 该文件请不要修改，如果要覆盖惯例配置的值，可在应用配置文件中设定和惯例不符的配置项\n * 配置名称大小写任意，系统会统一转换成小写\n * 所有配置参数都可以在生效前动态改变\n */\ndefined('THINK_PATH') or exit();\nreturn  array(\n    /* 应用设定 */\n    'APP_USE_NAMESPACE'     =>  true,    // 应用类库是否使用命名空间\n    'APP_SUB_DOMAIN_DEPLOY' =>  false,   // 是否开启子域名部署\n    'APP_SUB_DOMAIN_RULES'  =>  array(), // 子域名部署规则\n    'APP_DOMAIN_SUFFIX'     =>  '', // 域名后缀 如果是com.cn net.cn 之类的后缀必须设置    \n    'ACTION_SUFFIX'         =>  '', // 操作方法后缀\n    'MULTI_MODULE'          =>  true, // 是否允许多模块 如果为false 则必须设置 DEFAULT_MODULE\n    'MODULE_DENY_LIST'      =>  array('Common','Runtime'),\n    'CONTROLLER_LEVEL'      =>  1,\n    'APP_AUTOLOAD_LAYER'    =>  'Controller,Model', // 自动加载的应用类库层 关闭APP_USE_NAMESPACE后有效\n    'APP_AUTOLOAD_PATH'     =>  '', // 自动加载的路径 关闭APP_USE_NAMESPACE后有效\n\n    /* Cookie设置 */\n    'COOKIE_EXPIRE'         =>  0,       // Cookie有效期\n    'COOKIE_DOMAIN'         =>  '',      // Cookie有效域名\n    'COOKIE_PATH'           =>  '/',     // Cookie路径\n    'COOKIE_PREFIX'         =>  '',      // Cookie前缀 避免冲突\n    'COOKIE_SECURE'         =>  false,   // Cookie安全传输\n    'COOKIE_HTTPONLY'       =>  '',      // Cookie httponly设置\n\n    /* 默认设定 */\n    'DEFAULT_M_LAYER'       =>  'Model', // 默认的模型层名称\n    'DEFAULT_C_LAYER'       =>  'Controller', // 默认的控制器层名称\n    'DEFAULT_V_LAYER'       =>  'View', // 默认的视图层名称\n    'DEFAULT_LANG'          =>  'zh-cn', // 默认语言\n    'DEFAULT_THEME'         =>  '',\t// 默认模板主题名称\n    'DEFAULT_MODULE'        =>  'Home',  // 默认模块\n    'DEFAULT_CONTROLLER'    =>  'Index', // 默认控制器名称\n    'DEFAULT_ACTION'        =>  'index', // 默认操作名称\n    'DEFAULT_CHARSET'       =>  'utf-8', // 默认输出编码\n    'DEFAULT_TIMEZONE'      =>  'PRC',\t// 默认时区\n    'DEFAULT_AJAX_RETURN'   =>  'JSON',  // 默认AJAX 数据返回格式,可选JSON XML ...\n    'DEFAULT_JSONP_HANDLER' =>  'jsonpReturn', // 默认JSONP格式返回的处理方法\n    'DEFAULT_FILTER'        =>  'htmlspecialchars', // 默认参数过滤方法 用于I函数...\n\n    /* 数据库设置 */\n    'DB_TYPE'               =>  '',     // 数据库类型\n    'DB_HOST'               =>  '', // 服务器地址\n    'DB_NAME'               =>  '',          // 数据库名\n    'DB_USER'               =>  '',      // 用户名\n    'DB_PWD'                =>  '',          // 密码\n    'DB_PORT'               =>  '',        // 端口\n    'DB_PREFIX'             =>  '',    // 数据库表前缀\n    'DB_PARAMS'          \t=>  array(), // 数据库连接参数    \n    'DB_DEBUG'  \t\t\t=>  TRUE, // 数据库调试模式 开启后可以记录SQL日志\n    'DB_FIELDS_CACHE'       =>  true,        // 启用字段缓存\n    'DB_CHARSET'            =>  'utf8',      // 数据库编码默认采用utf8\n    'DB_DEPLOY_TYPE'        =>  0, // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)\n    'DB_RW_SEPARATE'        =>  false,       // 数据库读写是否分离 主从式有效\n    'DB_MASTER_NUM'         =>  1, // 读写分离后 主服务器数量\n    'DB_SLAVE_NO'           =>  '', // 指定从服务器序号\n\n    /* 数据缓存设置 */\n    'DATA_CACHE_TIME'       =>  0,      // 数据缓存有效期 0表示永久缓存\n    'DATA_CACHE_COMPRESS'   =>  false,   // 数据缓存是否压缩缓存\n    'DATA_CACHE_CHECK'      =>  false,   // 数据缓存是否校验缓存\n    'DATA_CACHE_PREFIX'     =>  '',     // 缓存前缀\n    'DATA_CACHE_TYPE'       =>  'File',  // 数据缓存类型,支持:File|Db|Apc|Memcache|Shmop|Sqlite|Xcache|Apachenote|Eaccelerator\n    'DATA_CACHE_PATH'       =>  TEMP_PATH,// 缓存路径设置 (仅对File方式缓存有效)\n    'DATA_CACHE_KEY'        =>  '',\t// 缓存文件KEY (仅对File方式缓存有效)    \n    'DATA_CACHE_SUBDIR'     =>  false,    // 使用子目录缓存 (自动根据缓存标识的哈希创建子目录)\n    'DATA_PATH_LEVEL'       =>  1,        // 子目录缓存级别\n\n    /* 错误设置 */\n    'ERROR_MESSAGE'         =>  '页面错误！请稍后再试～',//错误显示信息,非调试模式有效\n    'ERROR_PAGE'            =>  '',\t// 错误定向页面\n    'SHOW_ERROR_MSG'        =>  false,    // 显示错误信息\n    'TRACE_MAX_RECORD'      =>  100,    // 每个级别的错误信息 最大记录数\n\n    /* 日志设置 */\n    'LOG_RECORD'            =>  false,   // 默认不记录日志\n    'LOG_TYPE'              =>  'File', // 日志记录类型 默认为文件方式\n    'LOG_LEVEL'             =>  'EMERG,ALERT,CRIT,ERR',// 允许记录的日志级别\n    'LOG_FILE_SIZE'         =>  2097152,\t// 日志文件大小限制\n    'LOG_EXCEPTION_RECORD'  =>  false,    // 是否记录异常信息日志\n\n    /* SESSION设置 */\n    'SESSION_AUTO_START'    =>  true,    // 是否自动开启Session\n    'SESSION_OPTIONS'       =>  array(), // session 配置数组 支持type name id path expire domain 等参数\n    'SESSION_TYPE'          =>  '', // session hander类型 默认无需设置 除非扩展了session hander驱动\n    'SESSION_PREFIX'        =>  '', // session 前缀\n    //'VAR_SESSION_ID'      =>  'session_id',     //sessionID的提交变量\n\n    /* 模板引擎设置 */\n    'TMPL_CONTENT_TYPE'     =>  'text/html', // 默认模板输出类型\n    'TMPL_ACTION_ERROR'     =>  THINK_PATH.'Tpl/dispatch_jump.tpl', // 默认错误跳转对应的模板文件\n    'TMPL_ACTION_SUCCESS'   =>  THINK_PATH.'Tpl/dispatch_jump.tpl', // 默认成功跳转对应的模板文件\n    'TMPL_EXCEPTION_FILE'   =>  THINK_PATH.'Tpl/think_exception.tpl',// 异常页面的模板文件\n    'TMPL_DETECT_THEME'     =>  false,       // 自动侦测模板主题\n    'TMPL_TEMPLATE_SUFFIX'  =>  '.html',     // 默认模板文件后缀\n    'TMPL_FILE_DEPR'        =>  '/', //模板文件CONTROLLER_NAME与ACTION_NAME之间的分割符\n    // 布局设置\n    'TMPL_ENGINE_TYPE'      =>  'Think',     // 默认模板引擎 以下设置仅对使用Think模板引擎有效\n    'TMPL_CACHFILE_SUFFIX'  =>  '.php',      // 默认模板缓存后缀\n    'TMPL_DENY_FUNC_LIST'   =>  'echo,exit',    // 模板引擎禁用函数\n    'TMPL_DENY_PHP'         =>  false, // 默认模板引擎是否禁用PHP原生代码\n    'TMPL_L_DELIM'          =>  '{',            // 模板引擎普通标签开始标记\n    'TMPL_R_DELIM'          =>  '}',            // 模板引擎普通标签结束标记\n    'TMPL_VAR_IDENTIFY'     =>  'array',     // 模板变量识别。留空自动判断,参数为'obj'则表示对象\n    'TMPL_STRIP_SPACE'      =>  true,       // 是否去除模板文件里面的html空格与换行\n    'TMPL_CACHE_ON'         =>  true,        // 是否开启模板编译缓存,设为false则每次都会重新编译\n    'TMPL_CACHE_PREFIX'     =>  '',         // 模板缓存前缀标识，可以动态改变\n    'TMPL_CACHE_TIME'       =>  0,         // 模板缓存有效期 0 为永久，(以数字为值，单位:秒)\n    'TMPL_LAYOUT_ITEM'      =>  '{__CONTENT__}', // 布局模板的内容替换标识\n    'LAYOUT_ON'             =>  false, // 是否启用布局\n    'LAYOUT_NAME'           =>  'layout', // 当前布局名称 默认为layout\n\n    // Think模板引擎标签库相关设定\n    'TAGLIB_BEGIN'          =>  '<',  // 标签库标签开始标记\n    'TAGLIB_END'            =>  '>',  // 标签库标签结束标记\n    'TAGLIB_LOAD'           =>  true, // 是否使用内置标签库之外的其它标签库，默认自动检测\n    'TAGLIB_BUILD_IN'       =>  'cx', // 内置标签库名称(标签使用不必指定标签库名称),以逗号分隔 注意解析顺序\n    'TAGLIB_PRE_LOAD'       =>  '',   // 需要额外加载的标签库(须指定标签库名称)，多个以逗号分隔 \n    \n    /* URL设置 */\n    'URL_CASE_INSENSITIVE'  =>  true,   // 默认false 表示URL区分大小写 true则表示不区分大小写\n    'URL_MODEL'             =>  1,       // URL访问模式,可选参数0、1、2、3,代表以下四种模式：\n    // 0 (普通模式); 1 (PATHINFO 模式); 2 (REWRITE  模式); 3 (兼容模式)  默认为PATHINFO 模式\n    'URL_PATHINFO_DEPR'     =>  '/',\t// PATHINFO模式下，各参数之间的分割符号\n    'URL_PATHINFO_FETCH'    =>  'ORIG_PATH_INFO,REDIRECT_PATH_INFO,REDIRECT_URL', // 用于兼容判断PATH_INFO 参数的SERVER替代变量列表\n    'URL_REQUEST_URI'       =>  'REQUEST_URI', // 获取当前页面地址的系统变量 默认为REQUEST_URI\n    'URL_HTML_SUFFIX'       =>  'html',  // URL伪静态后缀设置\n    'URL_DENY_SUFFIX'       =>  'ico|png|gif|jpg', // URL禁止访问的后缀设置\n    'URL_PARAMS_BIND'       =>  true, // URL变量绑定到Action方法参数\n    'URL_PARAMS_BIND_TYPE'  =>  0, // URL变量绑定的类型 0 按变量名绑定 1 按变量顺序绑定\n    'URL_PARAMS_FILTER'     =>  false, // URL变量绑定过滤\n    'URL_PARAMS_FILTER_TYPE'=>  '', // URL变量绑定过滤方法 如果为空 调用DEFAULT_FILTER\n    'URL_ROUTER_ON'         =>  false,   // 是否开启URL路由\n    'URL_ROUTE_RULES'       =>  array(), // 默认路由规则 针对模块\n    'URL_MAP_RULES'         =>  array(), // URL映射定义规则\n\n    /* 系统变量名称设置 */\n    'VAR_MODULE'            =>  'm',     // 默认模块获取变量\n    'VAR_ADDON'             =>  'addon',     // 默认的插件控制器命名空间变量\n    'VAR_CONTROLLER'        =>  'c',    // 默认控制器获取变量\n    'VAR_ACTION'            =>  'a',    // 默认操作获取变量\n    'VAR_AJAX_SUBMIT'       =>  'ajax',  // 默认的AJAX提交变量\n    'VAR_JSONP_HANDLER'     =>  'callback',\n    'VAR_PATHINFO'          =>  's',    // 兼容模式PATHINFO获取变量例如 ?s=/module/action/id/1 后面的参数取决于URL_PATHINFO_DEPR\n    'VAR_TEMPLATE'          =>  't',    // 默认模板切换变量\n    'VAR_AUTO_STRING'\t\t=>\tfalse,\t// 输入变量是否自动强制转换为字符串 如果开启则数组变量需要手动传入变量修饰符获取变量\n\n    'HTTP_CACHE_CONTROL'    =>  'private',  // 网页缓存控制\n    'CHECK_APP_DIR'         =>  true,       // 是否检查应用目录是否创建\n    'FILE_UPLOAD_TYPE'      =>  'Local',    // 文件上传方式\n    'DATA_CRYPT_TYPE'       =>  'Think',    // 数据加密方式\n\n);\n"
  },
  {
    "path": "server/ThinkPHP/Conf/debug.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\n/**\n * ThinkPHP 默认的调试模式配置文件\n */\ndefined('THINK_PATH') or exit();\n// 调试模式下面默认设置 可以在应用配置目录下重新定义 debug.php 覆盖\nreturn  array(\n    'LOG_RECORD'            =>  true,  // 进行日志记录\n    'LOG_EXCEPTION_RECORD'  =>  true,    // 是否记录异常信息日志\n    'LOG_LEVEL'             =>  'EMERG,ALERT,CRIT,ERR,WARN,NOTIC,INFO,DEBUG,SQL',  // 允许记录的日志级别\n    'DB_FIELDS_CACHE'       =>  false, // 字段缓存信息\n    'DB_DEBUG'\t\t\t\t=>  true, // 开启调试模式 记录SQL日志\n    'TMPL_CACHE_ON'         =>  false,        // 是否开启模板编译缓存,设为false则每次都会重新编译\n    'TMPL_STRIP_SPACE'      =>  false,       // 是否去除模板文件里面的html空格与换行\n    'SHOW_ERROR_MSG'        =>  true,    // 显示错误信息\n    'URL_CASE_INSENSITIVE'  =>  false,  // URL区分大小写\n);"
  },
  {
    "path": "server/ThinkPHP/LICENSE.txt",
    "content": "\nThinkPHP遵循Apache2开源协议发布，并提供免费使用。\n版权所有Copyright © 2006-2014 by ThinkPHP (http://thinkphp.cn)\nAll rights reserved。\nThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。\n\nApache Licence是著名的非盈利开源组织Apache采用的协议。\n该协议和BSD类似，鼓励代码共享和尊重原作者的著作权，\n允许代码修改，再作为开源或商业软件发布。需要满足\n的条件： \n1． 需要给代码的用户一份Apache Licence ；\n2． 如果你修改了代码，需要在被修改的文件中说明；\n3． 在延伸的代码中（修改和有源代码衍生的代码中）需要\n带有原来代码中的协议，商标，专利声明和其他原来作者规\n定需要包含的说明；\n4． 如果再发布的产品中包含一个Notice文件，则在Notice文\n件中需要带有本协议内容。你可以在Notice中增加自己的\n许可，但不可以表现为对Apache Licence构成更改。 \n具体的协议参考：http://www.apache.org/licenses/LICENSE-2.0\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\nFOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\nCOPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\nINCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\nBUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\nLIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\nANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "server/ThinkPHP/Lang/en-us.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\n/**\n * ThinkPHP English language package\n */\nreturn array(\n    /* core language package */ \n    '_MODULE_NOT_EXIST_'     => \"Module can't be loaded\",\n    '_CONTROLLER_NOT_EXIST_' =>\t\"Controller can't be loaded\",\n    '_ERROR_ACTION_'         => 'Illegal Action',\n    '_LANGUAGE_NOT_LOAD_'    => \"Can't load language package\",\n    '_TEMPLATE_NOT_EXIST_'   => \"Template doesn't exist\",\n    '_MODULE_'               => 'Module',\n    '_ACTION_'               => 'Action',\n    '_MODEL_NOT_EXIST_'      => \"Model can't be loaded\",\n    '_VALID_ACCESS_'         => 'No access',\n    '_XML_TAG_ERROR_'        => 'XML tag syntax errors',\n    '_DATA_TYPE_INVALID_'    => 'Illegal data objects!',\n    '_OPERATION_WRONG_'      => 'Operation error occurs',\n    '_NOT_LOAD_DB_'          => 'Unable to load the database',\n    '_NO_DB_DRIVER_'         => 'Unable to load database driver',\n    '_NOT_SUPPORT_DB_'       => 'The system is temporarily not support database',\n    '_NO_DB_CONFIG_'         => 'Not define the database configuration',\n    '_NOT_SUPPORT_'          => 'The system does not support',\n    '_CACHE_TYPE_INVALID_'   => 'Unable to load the cache type',\n    '_FILE_NOT_WRITABLE_'   => 'Directory (file) is not writable',\n    '_METHOD_NOT_EXIST_'     => 'The method you requested  does not exist!',\n    '_CLASS_NOT_EXIST_'      => 'Instantiating a class does not exist！',\n    '_CLASS_CONFLICT_'       => 'Class name conflicts',\n    '_TEMPLATE_ERROR_'       => 'Template Engine errors',\n    '_CACHE_WRITE_ERROR_'    => 'Cache file write failed!',\n    '_TAGLIB_NOT_EXIST_'     => 'Tag library is not defined',\n    '_OPERATION_FAIL_'       => 'Operation failed!',\n    '_OPERATION_SUCCESS_'    => 'Operation succeed!',\n    '_SELECT_NOT_EXIST_'     => 'Record does not exist!',\n    '_EXPRESS_ERROR_'        => 'Expression errors',\n    '_TOKEN_ERROR_'          => \"Form's token errors\",\n    '_RECORD_HAS_UPDATE_'    => 'Record has been updated',\n    '_NOT_ALLOW_PHP_'        => 'PHP codes are not allowed in the template',\n    '_PARAM_ERROR_'          => 'Parameter error or undefined',\n    '_ERROR_QUERY_EXPRESS_'  => 'Query express error',       \n);\n"
  },
  {
    "path": "server/ThinkPHP/Lang/pt-br.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: Daiane Azevedo <daianeaze16@gmail.com>\n// +----------------------------------------------------------------------\n\n/**\n * ThinkPHP Portuguese language package\n */\nreturn array(\n    /* core language package */ \n    '_MODULE_NOT_EXIST_'     => \"Módulo não pode ser carregado\",\n    '_CONTROLLER_NOT_EXIST_' => \"Controller não pode ser carregado\",\n    '_ERROR_ACTION_'         => 'Ação ilegal',\n    '_LANGUAGE_NOT_LOAD_'    => \"Não é possível carregar pacote da linguagem\",\n    '_TEMPLATE_NOT_EXIST_'   => \"Template não existe\",\n    '_MODULE_'               => 'Módulo',\n    '_ACTION_'               => 'Ação',\n    '_MODEL_NOT_EXIST_'      => \"Modelo não pode ser carregado\",\n    '_VALID_ACCESS_'         => 'Sem acesso',\n    '_XML_TAG_ERROR_'        => 'Erro de sintaxe - XML tag',\n    '_DATA_TYPE_INVALID_'    => 'Tipos de dados ilegais!',\n    '_OPERATION_WRONG_'      => 'Erro na operação',\n    '_NOT_LOAD_DB_'          => 'Impossível carregar banco de dados',\n    '_NO_DB_DRIVER_'         => 'Impossível carregar driver do bando de dados',\n    '_NOT_SUPPORT_DB_'       => 'Temporariamente sem suporte ao banco',\n    '_NO_DB_CONFIG_'         => 'Não define a configuração do banco',\n    '_NOT_SUPPORT_'          => 'O sistema não suporta',\n    '_CACHE_TYPE_INVALID_'   => 'Impossível carregar o tipo de cache',\n    '_FILE_NOT_WRITABLE_'   => 'Diretório (arquivo) não pode ser escrito',\n    '_METHOD_NOT_EXIST_'     => 'O método solicitado não existe!',\n    '_CLASS_NOT_EXIST_'      => 'Não existe instância da classe',\n    '_CLASS_CONFLICT_'       => 'Conflitos com nome da classe',\n    '_TEMPLATE_ERROR_'       => 'Erros na contrução do template',\n    '_CACHE_WRITE_ERROR_'    => 'Escrita do arquivo de cache falhou!',\n    '_TAGLIB_NOT_EXIST_'     => 'Biblioteca da tag não foi definida',\n    '_OPERATION_FAIL_'       => 'Operação falhou!',\n    '_OPERATION_SUCCESS_'    => 'Operação bem sucessida!',\n    '_SELECT_NOT_EXIST_'     => 'Gravação não existe!',\n    '_EXPRESS_ERROR_'        => 'Erros de expressão',\n    '_TOKEN_ERROR_'          => 'Erro no token do formulário',\n    '_RECORD_HAS_UPDATE_'    => 'Gravação não foi atualizada',\n    '_NOT_ALLOW_PHP_'        => 'Código PHP não é permitido no template',\n    '_PARAM_ERROR_'          => 'Parâmetro errado ou indefinido',\n    '_ERROR_QUERY_EXPRESS_'  => 'Erros na expressão da query',       \n);\n"
  },
  {
    "path": "server/ThinkPHP/Lang/zh-cn.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\n/**\n * ThinkPHP 简体中文语言包\n */\nreturn array(\n    /* 核心语言变量 */  \n    '_MODULE_NOT_EXIST_'     => '无法加载模块',\n    '_CONTROLLER_NOT_EXIST_' =>\t'无法加载控制器',\n    '_ERROR_ACTION_'         => '非法操作',\n    '_LANGUAGE_NOT_LOAD_'    => '无法加载语言包',\n    '_TEMPLATE_NOT_EXIST_'   => '模板不存在',\n    '_MODULE_'               => '模块',\n    '_ACTION_'               => '操作',\n    '_MODEL_NOT_EXIST_'      => '模型不存在或者没有定义',\n    '_VALID_ACCESS_'         => '没有权限',\n    '_XML_TAG_ERROR_'        => 'XML标签语法错误',\n    '_DATA_TYPE_INVALID_'    => '非法数据对象！',\n    '_OPERATION_WRONG_'      => '操作出现错误',\n    '_NOT_LOAD_DB_'          => '无法加载数据库',\n    '_NO_DB_DRIVER_'         => '无法加载数据库驱动',\n    '_NOT_SUPPORT_DB_'       => '系统暂时不支持数据库',\n    '_NO_DB_CONFIG_'         => '没有定义数据库配置',\n    '_NOT_SUPPORT_'          => '系统不支持',\n    '_CACHE_TYPE_INVALID_'   => '无法加载缓存类型',\n    '_FILE_NOT_WRITABLE_'   => '目录（文件）不可写',\n    '_METHOD_NOT_EXIST_'     => '方法不存在！',\n    '_CLASS_NOT_EXIST_'      => '实例化一个不存在的类！',\n    '_CLASS_CONFLICT_'       => '类名冲突',\n    '_TEMPLATE_ERROR_'       => '模板引擎错误',\n    '_CACHE_WRITE_ERROR_'    => '缓存文件写入失败！',\n    '_TAGLIB_NOT_EXIST_'     => '标签库未定义',\n    '_OPERATION_FAIL_'       => '操作失败！',\n    '_OPERATION_SUCCESS_'    => '操作成功！',\n    '_SELECT_NOT_EXIST_'     => '记录不存在！',\n    '_EXPRESS_ERROR_'        => '表达式错误',\n    '_TOKEN_ERROR_'          => '表单令牌错误',\n    '_RECORD_HAS_UPDATE_'    => '记录已经更新',\n    '_NOT_ALLOW_PHP_'        => '模板禁用PHP代码',\n    '_PARAM_ERROR_'          => '参数错误或者未定义',\n    '_ERROR_QUERY_EXPRESS_'  => '错误的查询条件',\n);\n"
  },
  {
    "path": "server/ThinkPHP/Lang/zh-tw.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\n/**\n * ThinkPHP 繁体中文語言包\n */\nreturn array(\n    /* 核心語言變數 */  \n    '_MODULE_NOT_EXIST_'     => '無法載入模組',\n    '_CONTROLLER_NOT_EXIST_' => '無法載入控制器',\n    '_ERROR_ACTION_'         => '非法操作',\n    '_LANGUAGE_NOT_LOAD_'    => '無法載入語言包',\n    '_TEMPLATE_NOT_EXIST_'   => '模板不存在',\n    '_MODULE_'               => '模組',\n    '_ACTION_'               => '操作',\n    '_MODEL_NOT_EXIST_'      => '模型不存在或者沒有定義',\n    '_VALID_ACCESS_'         => '沒有權限',\n    '_XML_TAG_ERROR_'        => 'XML標籤語法錯誤',\n    '_DATA_TYPE_INVALID_'    => '非法資料物件！',\n    '_OPERATION_WRONG_'      => '操作出現錯誤',\n    '_NOT_LOAD_DB_'          => '無法載入資料庫',\n    '_NO_DB_DRIVER_'         => '無法載入資料庫驅動',\n    '_NOT_SUPPORT_DB_'       => '系統暫時不支援資料庫',\n    '_NO_DB_CONFIG_'         => '沒有定義資料庫設定',\n    '_NOT_SUPPORT_'          => '系統不支援',\n    '_CACHE_TYPE_INVALID_'   => '無法載入快取類型',\n    '_FILE_NOT_WRITABLE_'   => '目錄（檔案）不可寫',\n    '_METHOD_NOT_EXIST_'     => '方法不存在！',\n    '_CLASS_NOT_EXIST_'      => '實例化一個不存在的類別！',\n    '_CLASS_CONFLICT_'       => '類別名稱衝突',\n    '_TEMPLATE_ERROR_'       => '模板引擎錯誤',\n    '_CACHE_WRITE_ERROR_'    => '快取檔案寫入失敗！',\n    '_TAGLIB_NOT_EXIST_'     => '標籤庫未定義',\n    '_OPERATION_FAIL_'       => '操作失敗！',\n    '_OPERATION_SUCCESS_'    => '操作成功！',\n    '_SELECT_NOT_EXIST_'     => '記錄不存在！',\n    '_EXPRESS_ERROR_'        => '運算式錯誤',\n    '_TOKEN_ERROR_'          => '表單權限錯誤',\n    '_RECORD_HAS_UPDATE_'    => '記錄已經更新',\n    '_NOT_ALLOW_PHP_'        => '模板禁用PHP代碼',\n    '_PARAM_ERROR_'          => '參數錯誤或者未定義',\n    '_ERROR_QUERY_EXPRESS_'  => '錯誤的查詢條件',    \n);\n"
  },
  {
    "path": "server/ThinkPHP/Library/Behavior/BuildLiteBehavior.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\nnamespace Behavior;\n// 创建Lite运行文件\n// 可以替换框架入口文件运行\n// 建议绑定位置app_init\nclass BuildLiteBehavior {\n    public function run(&$params) {\n        if(!defined('BUILD_LITE_FILE')) return ;\n        $litefile   =   C('RUNTIME_LITE_FILE',null,RUNTIME_PATH.'lite.php');\n        if(is_file($litefile)) return;\n        \n        $defs       =   get_defined_constants(TRUE);\n        $content    =   'namespace {$GLOBALS[\\'_beginTime\\'] = microtime(TRUE);';\n        if(MEMORY_LIMIT_ON) {\n            $content .= '$GLOBALS[\\'_startUseMems\\'] = memory_get_usage();';\n        }\n\n        // 生成数组定义\n        unset($defs['user']['BUILD_LITE_FILE']);\n        $content   .=   $this->buildArrayDefine($defs['user']).'}';\n\n        // 读取编译列表文件\n        $filelist   =   is_file(CONF_PATH.'lite.php')?\n            include CONF_PATH.'lite.php':\n            array(\n                THINK_PATH.'Common/functions.php',\n                COMMON_PATH.'Common/function.php',\n                CORE_PATH . 'Think'.EXT,\n                CORE_PATH . 'Hook'.EXT,\n                CORE_PATH . 'App'.EXT,\n                CORE_PATH . 'Dispatcher'.EXT,\n                CORE_PATH . 'Log'.EXT,\n                CORE_PATH . 'Log/Driver/File'.EXT,\n                CORE_PATH . 'Route'.EXT,\n                CORE_PATH . 'Controller'.EXT,\n                CORE_PATH . 'View'.EXT,\n                CORE_PATH . 'Storage'.EXT,\n                CORE_PATH . 'Storage/Driver/File'.EXT,\n                CORE_PATH . 'Exception'.EXT,\n                BEHAVIOR_PATH . 'ParseTemplateBehavior'.EXT,\n                BEHAVIOR_PATH . 'ContentReplaceBehavior'.EXT,\n            );\n\n        // 编译文件\n        foreach ($filelist as $file){\n          if(is_file($file)) {\n            $content   .= compile($file);\n          }\n        }\n\n        // 处理Think类的start方法\n        $content  =  preg_replace('/\\$runtimefile = RUNTIME_PATH(.+?)(if\\(APP_STATUS)/','\\2',$content,1);\n        $content  .=  \"\\nnamespace { Think\\Think::addMap(\".var_export(\\Think\\Think::getMap(),true).\");\";\n        $content  .=  \"\\nL(\".var_export(L(),true).\");\\nC(\".var_export(C(),true).');Think\\Hook::import('.var_export(\\Think\\Hook::get(),true).');Think\\Think::start();}';\n\n        // 生成运行Lite文件\n        file_put_contents($litefile,strip_whitespace('<?php '.$content));\n    }\n\n    // 根据数组生成常量定义\n    private function buildArrayDefine($array) {\n        $content = \"\\n\";\n        foreach ($array as $key => $val) {\n            $key = strtoupper($key);\n            $content .= 'defined(\\'' . $key . '\\') or ';\n            if (is_int($val) || is_float($val)) {\n                $content .= \"define('\" . $key . \"',\" . $val . ');';\n            } elseif (is_bool($val)) {\n                $val = ($val) ? 'true' : 'false';\n                $content .= \"define('\" . $key . \"',\" . $val . ');';\n            } elseif (is_string($val)) {\n                $content .= \"define('\" . $key . \"','\" . addslashes($val) . \"');\";\n            }\n            $content    .= \"\\n\";\n        }\n        return $content;\n    }\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Behavior/CheckLangBehavior.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\nnamespace Behavior;\n/**\n * 语言检测 并自动加载语言包\n */\nclass CheckLangBehavior {\n\n    // 行为扩展的执行入口必须是run\n    public function run(&$params){\n        // 检测语言\n        $this->checkLanguage();\n    }\n\n    /**\n     * 语言检查\n     * 检查浏览器支持语言，并自动加载语言包\n     * @access private\n     * @return void\n     */\n    private function checkLanguage() {\n        // 不开启语言包功能，仅仅加载框架语言文件直接返回\n        if (!C('LANG_SWITCH_ON',null,false)){\n            return;\n        }\n        $langSet = C('DEFAULT_LANG');\n        $varLang =  C('VAR_LANGUAGE',null,'l');\n        $langList = C('LANG_LIST',null,'zh-cn');\n        // 启用了语言包功能\n        // 根据是否启用自动侦测设置获取语言选择\n        if (C('LANG_AUTO_DETECT',null,true)){\n            if(isset($_GET[$varLang])){\n                $langSet = $_GET[$varLang];// url中设置了语言变量\n                cookie('think_language',$langSet,3600);\n            }elseif(cookie('think_language')){// 获取上次用户的选择\n                $langSet = cookie('think_language');\n            }elseif(isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])){// 自动侦测浏览器语言\n                preg_match('/^([a-z\\d\\-]+)/i', $_SERVER['HTTP_ACCEPT_LANGUAGE'], $matches);\n                $langSet = $matches[1];\n                cookie('think_language',$langSet,3600);\n            }\n            if(false === stripos($langList,$langSet)) { // 非法语言参数\n                $langSet = C('DEFAULT_LANG');\n            }\n        }\n        // 定义当前语言\n        define('LANG_SET',strtolower($langSet));\n\n        // 读取框架语言包\n        $file   =   THINK_PATH.'Lang/'.LANG_SET.'.php';\n        if(LANG_SET != C('DEFAULT_LANG') && is_file($file))\n            L(include $file);\n\n        // 读取应用公共语言包\n        $file   =  LANG_PATH.LANG_SET.'.php';\n        if(is_file($file))\n            L(include $file);\n        \n        // 读取模块语言包\n        $file   =   MODULE_PATH.'Lang/'.LANG_SET.'.php';\n        if(is_file($file))\n            L(include $file);\n\n        // 读取当前控制器语言包\n        $file   =   MODULE_PATH.'Lang/'.LANG_SET.'/'.strtolower(CONTROLLER_NAME).'.php';\n        if (is_file($file))\n            L(include $file);\n    }\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Behavior/ContentReplaceBehavior.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\nnamespace Behavior;\n/**\n * 系统行为扩展：模板内容输出替换\n */\nclass ContentReplaceBehavior {\n\n    // 行为扩展的执行入口必须是run\n    public function run(&$content){\n        $content = $this->templateContentReplace($content);\n    }\n\n    /**\n     * 模板内容替换\n     * @access protected\n     * @param string $content 模板内容\n     * @return string\n     */\n    protected function templateContentReplace($content) {\n        // 系统默认的特殊变量替换\n        $replace =  array(\n            '__ROOT__'      =>  __ROOT__,       // 当前网站地址\n            '__APP__'       =>  __APP__,        // 当前应用地址\n            '__MODULE__'    =>  __MODULE__,\n            '__ACTION__'    =>  __ACTION__,     // 当前操作地址\n            '__SELF__'      =>  htmlentities(__SELF__),       // 当前页面地址\n            '__CONTROLLER__'=>  __CONTROLLER__,\n            '__URL__'       =>  __CONTROLLER__,\n            '__PUBLIC__'    =>  __ROOT__.'/Public',// 站点公共目录\n        );\n        // 允许用户自定义模板的字符串替换\n        if(is_array(C('TMPL_PARSE_STRING')) )\n            $replace =  array_merge($replace,C('TMPL_PARSE_STRING'));\n        $content = str_replace(array_keys($replace),array_values($replace),$content);\n        return $content;\n    }\n\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Behavior/ParseTemplateBehavior.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\nnamespace Behavior;\nuse Think\\Storage;\nuse Think\\Think;\n/**\n * 系统行为扩展：模板解析\n */\nclass ParseTemplateBehavior {\n\n    // 行为扩展的执行入口必须是run\n    public function run(&$_data){\n        $engine             =   strtolower(C('TMPL_ENGINE_TYPE'));\n        $_content           =   empty($_data['content'])?$_data['file']:$_data['content'];\n        $_data['prefix']    =   !empty($_data['prefix'])?$_data['prefix']:C('TMPL_CACHE_PREFIX');\n        if('think'==$engine){ // 采用Think模板引擎\n            if((!empty($_data['content']) && $this->checkContentCache($_data['content'],$_data['prefix'])) \n                ||  $this->checkCache($_data['file'],$_data['prefix'])) { // 缓存有效\n                //载入模版缓存文件\n                Storage::load(C('CACHE_PATH').$_data['prefix'].md5($_content).C('TMPL_CACHFILE_SUFFIX'),$_data['var']);\n            }else{\n                $tpl = Think::instance('Think\\\\Template');\n                // 编译并加载模板文件\n                $tpl->fetch($_content,$_data['var'],$_data['prefix']);\n            }\n        }else{\n            // 调用第三方模板引擎解析和输出\n            if(strpos($engine,'\\\\')){\n                $class  =   $engine;\n            }else{\n                $class   =  'Think\\\\Template\\\\Driver\\\\'.ucwords($engine);                \n            }            \n            if(class_exists($class)) {\n                $tpl   =  new $class;\n                $tpl->fetch($_content,$_data['var']);\n            }else {  // 类没有定义\n                E(L('_NOT_SUPPORT_').': ' . $class);\n            }\n        }\n    }\n\n    /**\n     * 检查缓存文件是否有效\n     * 如果无效则需要重新编译\n     * @access public\n     * @param string $tmplTemplateFile  模板文件名\n     * @return boolean\n     */\n    protected function checkCache($tmplTemplateFile,$prefix='') {\n        if (!C('TMPL_CACHE_ON')) // 优先对配置设定检测\n            return false;\n        $tmplCacheFile = C('CACHE_PATH').$prefix.md5($tmplTemplateFile).C('TMPL_CACHFILE_SUFFIX');\n        if(!Storage::has($tmplCacheFile)){\n            return false;\n        }elseif (filemtime($tmplTemplateFile) > Storage::get($tmplCacheFile,'mtime')) {\n            // 模板文件如果有更新则缓存需要更新\n            return false;\n        }elseif (C('TMPL_CACHE_TIME') != 0 && time() > Storage::get($tmplCacheFile,'mtime')+C('TMPL_CACHE_TIME')) {\n            // 缓存是否在有效期\n            return false;\n        }\n        // 开启布局模板\n        if(C('LAYOUT_ON')) {\n            $layoutFile  =  THEME_PATH.C('LAYOUT_NAME').C('TMPL_TEMPLATE_SUFFIX');\n            if(filemtime($layoutFile) > Storage::get($tmplCacheFile,'mtime')) {\n                return false;\n            }\n        }\n        // 缓存有效\n        return true;\n    }\n\n    /**\n     * 检查缓存内容是否有效\n     * 如果无效则需要重新编译\n     * @access public\n     * @param string $tmplContent  模板内容\n     * @return boolean\n     */\n    protected function checkContentCache($tmplContent,$prefix='') {\n        if(Storage::has(C('CACHE_PATH').$prefix.md5($tmplContent).C('TMPL_CACHFILE_SUFFIX'))){\n            return true;\n        }else{\n            return false;\n        }\n    }    \n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Behavior/ReadHtmlCacheBehavior.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\nnamespace Behavior;\nuse Think\\Storage;\n/**\n * 系统行为扩展：静态缓存读取\n */\nclass ReadHtmlCacheBehavior {\n    // 行为扩展的执行入口必须是run\n    public function run(&$params){\n        // 开启静态缓存\n        if(IS_GET && C('HTML_CACHE_ON'))  {\n            $cacheTime = $this->requireHtmlCache();\n            if( false !== $cacheTime && $this->checkHTMLCache(HTML_FILE_NAME,$cacheTime)) { //静态页面有效\n                // 读取静态页面输出\n                echo Storage::read(HTML_FILE_NAME,'html');\n                exit();\n            }\n        }\n    }\n\n    // 判断是否需要静态缓存\n    static private function requireHtmlCache() {\n        // 分析当前的静态规则\n         $htmls = C('HTML_CACHE_RULES'); // 读取静态规则\n         if(!empty($htmls)) {\n            $htmls = array_change_key_case($htmls);\n            // 静态规则文件定义格式 actionName=>array('静态规则','缓存时间','附加规则')\n            // 'read'=>array('{id},{name}',60,'md5') 必须保证静态规则的唯一性 和 可判断性\n            // 检测静态规则\n            $controllerName = strtolower(CONTROLLER_NAME);\n            $actionName     = strtolower(ACTION_NAME);\n            if(isset($htmls[$controllerName.':'.$actionName])) {\n                $html   =   $htmls[$controllerName.':'.$actionName];   // 某个控制器的操作的静态规则\n            }elseif(isset($htmls[$controllerName.':'])){// 某个控制器的静态规则\n                $html   =   $htmls[$controllerName.':'];\n            }elseif(isset($htmls[$actionName])){\n                $html   =   $htmls[$actionName]; // 所有操作的静态规则\n            }elseif(isset($htmls['*'])){\n                $html   =   $htmls['*']; // 全局静态规则\n            }\n            if(!empty($html)) {\n                // 解读静态规则\n                $rule   = is_array($html)?$html[0]:$html;\n                // 以$_开头的系统变量\n                $callback = function($match){ \n                    switch($match[1]){\n                        case '_GET':        $var = $_GET[$match[2]]; break;\n                        case '_POST':       $var = $_POST[$match[2]]; break;\n                        case '_REQUEST':    $var = $_REQUEST[$match[2]]; break;\n                        case '_SERVER':     $var = $_SERVER[$match[2]]; break;\n                        case '_SESSION':    $var = $_SESSION[$match[2]]; break;\n                        case '_COOKIE':     $var = $_COOKIE[$match[2]]; break;\n                    }\n                    return (count($match) == 4) ? $match[3]($var) : $var;\n                };\n                $rule     = preg_replace_callback('/{\\$(_\\w+)\\.(\\w+)(?:\\|(\\w+))?}/', $callback, $rule);\n                // {ID|FUN} GET变量的简写\n                $rule     = preg_replace_callback('/{(\\w+)\\|(\\w+)}/', function($match){return $match[2]($_GET[$match[1]]);}, $rule);\n                $rule     = preg_replace_callback('/{(\\w+)}/', function($match){return $_GET[$match[1]];}, $rule);\n                // 特殊系统变量\n                $rule   = str_ireplace(\n                    array('{:controller}','{:action}','{:module}'),\n                    array(CONTROLLER_NAME,ACTION_NAME,MODULE_NAME),\n                    $rule);\n                // {|FUN} 单独使用函数\n                $rule  = preg_replace_callback('/{|(\\w+)}/', function($match){return $match[1]();},$rule);\n                $cacheTime  =   C('HTML_CACHE_TIME',null,60);\n                if(is_array($html)){\n                    if(!empty($html[2])) $rule    =   $html[2]($rule); // 应用附加函数\n                    $cacheTime  =   isset($html[1])?$html[1]:$cacheTime; // 缓存有效期\n                }else{\n                    $cacheTime  =   $cacheTime;\n                }\n                \n                // 当前缓存文件\n                define('HTML_FILE_NAME',HTML_PATH . $rule.C('HTML_FILE_SUFFIX',null,'.html'));\n                return $cacheTime;\n            }\n        }\n        // 无需缓存\n        return false;\n    }\n\n    /**\n     * 检查静态HTML文件是否有效\n     * 如果无效需要重新更新\n     * @access public\n     * @param string $cacheFile  静态文件名\n     * @param integer $cacheTime  缓存有效期\n     * @return boolean\n     */\n    static public function checkHTMLCache($cacheFile='',$cacheTime='') {\n        if(!is_file($cacheFile) && 'sae' != APP_MODE ){\n            return false;\n        }elseif (filemtime(\\Think\\Think::instance('Think\\View')->parseTemplate()) > Storage::get($cacheFile,'mtime','html')) {\n            // 模板文件如果更新静态文件需要更新\n            return false;\n        }elseif(!is_numeric($cacheTime) && function_exists($cacheTime)){\n            return $cacheTime($cacheFile);\n        }elseif ($cacheTime != 0 && NOW_TIME > Storage::get($cacheFile,'mtime','html')+$cacheTime) {\n            // 文件是否在有效期\n            return false;\n        }\n        //静态文件有效\n        return true;\n    }\n\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Behavior/ShowPageTraceBehavior.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\nnamespace Behavior;\nuse Think\\Log;\n/**\n * 系统行为扩展：页面Trace显示输出\n */\nclass ShowPageTraceBehavior {\n    protected $tracePageTabs =  array('BASE'=>'基本','FILE'=>'文件','INFO'=>'流程','ERR|NOTIC'=>'错误','SQL'=>'SQL','DEBUG'=>'调试');\n\n    // 行为扩展的执行入口必须是run\n    public function run(&$params){\n        if(!IS_AJAX && !IS_CLI && C('SHOW_PAGE_TRACE')) {\n            echo $this->showTrace();\n        }\n    }\n\n    /**\n     * 显示页面Trace信息\n     * @access private\n     */\n    private function showTrace() {\n         // 系统默认显示信息\n        $files  =  get_included_files();\n        $info   =   array();\n        foreach ($files as $key=>$file){\n            $info[] = $file.' ( '.number_format(filesize($file)/1024,2).' KB )';\n        }\n        $trace  =   array();\n        $base   =   array(\n            '请求信息'  =>  date('Y-m-d H:i:s',$_SERVER['REQUEST_TIME']).' '.$_SERVER['SERVER_PROTOCOL'].' '.$_SERVER['REQUEST_METHOD'].' : '.__SELF__,\n            '运行时间'  =>  $this->showTime(),\n            '吞吐率'    =>  number_format(1/G('beginTime','viewEndTime'),2).'req/s',\n            '内存开销'  =>  MEMORY_LIMIT_ON?number_format((memory_get_usage() - $GLOBALS['_startUseMems'])/1024,2).' kb':'不支持',\n            '查询信息'  =>  N('db_query').' queries '.N('db_write').' writes ',\n            '文件加载'  =>  count(get_included_files()),\n            '缓存信息'  =>  N('cache_read').' gets '.N('cache_write').' writes ',\n            '配置加载'  =>  count(C()),\n            '会话信息'  =>  'SESSION_ID='.session_id(),\n            );\n        // 读取应用定义的Trace文件\n        $traceFile  =   COMMON_PATH.'Conf/trace.php';\n        if(is_file($traceFile)) {\n            $base   =   array_merge($base,include $traceFile);\n        }\n        $debug  =   trace();\n        $tabs   =   C('TRACE_PAGE_TABS',null,$this->tracePageTabs);\n        foreach ($tabs as $name=>$title){\n            switch(strtoupper($name)) {\n                case 'BASE':// 基本信息\n                    $trace[$title]  =   $base;\n                    break;\n                case 'FILE': // 文件信息\n                    $trace[$title]  =   $info;\n                    break;\n                default:// 调试信息\n                    $name       =   strtoupper($name);\n                    if(strpos($name,'|')) {// 多组信息\n                        $names  =   explode('|',$name);\n                        $result =   array();\n                        foreach($names as $name){\n                            $result   +=   isset($debug[$name])?$debug[$name]:array();\n                        }\n                        $trace[$title]  =   $result;\n                    }else{\n                        $trace[$title]  =   isset($debug[$name])?$debug[$name]:'';\n                    }\n            }\n        }\n        if($save = C('PAGE_TRACE_SAVE')) { // 保存页面Trace日志\n            if(is_array($save)) {// 选择选项卡保存\n                $tabs   =   C('TRACE_PAGE_TABS',null,$this->tracePageTabs);\n                $array  =   array();\n                foreach ($save as $tab){\n                    $array[] =   $tabs[$tab];\n                }\n            }\n            $content    =   date('[ c ]').' '.get_client_ip().' '.$_SERVER['REQUEST_URI'].\"\\r\\n\";\n            foreach ($trace as $key=>$val){\n                if(!isset($array) || in_array_case($key,$array)) {\n                    $content    .=  '[ '.$key.\" ]\\r\\n\";\n                    if(is_array($val)) {\n                        foreach ($val as $k=>$v){\n                            $content .= (!is_numeric($k)?$k.':':'').print_r($v,true).\"\\r\\n\";\n                        }\n                    }else{\n                        $content .= print_r($val,true).\"\\r\\n\";\n                    }\n                    $content .= \"\\r\\n\";\n                }\n            }\n            error_log(str_replace('<br/>',\"\\r\\n\",$content), 3,C('LOG_PATH').date('y_m_d').'_trace.log');\n        }\n        unset($files,$info,$base);\n        // 调用Trace页面模板\n        ob_start();\n        include C('TMPL_TRACE_FILE')?C('TMPL_TRACE_FILE'):THINK_PATH.'Tpl/page_trace.tpl';\n        return ob_get_clean();\n    }\n\n    /**\n     * 获取运行时间\n     */\n    private function showTime() {\n        // 显示运行时间\n        G('beginTime',$GLOBALS['_beginTime']);\n        G('viewEndTime');\n        // 显示详细运行时间\n        return G('beginTime','viewEndTime').'s ( Load:'.G('beginTime','loadTime').'s Init:'.G('loadTime','initTime').'s Exec:'.G('initTime','viewStartTime').'s Template:'.G('viewStartTime','viewEndTime').'s )';\n    }\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Behavior/ShowRuntimeBehavior.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\nnamespace Behavior;\n/**\n * 系统行为扩展：运行时间信息显示\n */\nclass ShowRuntimeBehavior {\n\n    // 行为扩展的执行入口必须是run\n    public function run(&$content){\n        if(C('SHOW_RUN_TIME')){\n            if(false !== strpos($content,'{__NORUNTIME__}')) {\n                $content   =  str_replace('{__NORUNTIME__}','',$content);\n            }else{\n                $runtime = $this->showTime();\n                 if(strpos($content,'{__RUNTIME__}'))\n                     $content   =  str_replace('{__RUNTIME__}',$runtime,$content);\n                 else\n                     $content   .=  $runtime;\n            }\n        }else{\n            $content   =  str_replace(array('{__NORUNTIME__}','{__RUNTIME__}'),'',$content);\n        }\n    }\n\n    /**\n     * 显示运行时间、数据库操作、缓存次数、内存使用信息\n     * @access private\n     * @return string\n     */\n    private function showTime() {\n        // 显示运行时间\n        G('beginTime',$GLOBALS['_beginTime']);\n        G('viewEndTime');\n        $showTime   =   'Process: '.G('beginTime','viewEndTime').'s ';\n        if(C('SHOW_ADV_TIME')) {\n            // 显示详细运行时间\n            $showTime .= '( Load:'.G('beginTime','loadTime').'s Init:'.G('loadTime','initTime').'s Exec:'.G('initTime','viewStartTime').'s Template:'.G('viewStartTime','viewEndTime').'s )';\n        }\n        if(C('SHOW_DB_TIMES') ) {\n            // 显示数据库操作次数\n            $showTime .= ' | DB :'.N('db_query').' queries '.N('db_write').' writes ';\n        }\n        if(C('SHOW_CACHE_TIMES') ) {\n            // 显示缓存读写次数\n            $showTime .= ' | Cache :'.N('cache_read').' gets '.N('cache_write').' writes ';\n        }\n        if(MEMORY_LIMIT_ON && C('SHOW_USE_MEM')) {\n            // 显示内存开销\n            $showTime .= ' | UseMem:'. number_format((memory_get_usage() - $GLOBALS['_startUseMems'])/1024).' kb';\n        }\n        if(C('SHOW_LOAD_FILE')) {\n            $showTime .= ' | LoadFile:'.count(get_included_files());\n        }\n        if(C('SHOW_FUN_TIMES')) {\n            $fun  =  get_defined_functions();\n            $showTime .= ' | CallFun:'.count($fun['user']).','.count($fun['internal']);\n        }\n        return $showTime;\n    }\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Behavior/TokenBuildBehavior.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | TOPThink [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2010 http://topthink.com All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\nnamespace Behavior;\n/**\n * 系统行为扩展：表单令牌生成\n */\nclass TokenBuildBehavior {\n\n    public function run(&$content){\n        if(C('TOKEN_ON')) {\n            list($tokenName,$tokenKey,$tokenValue)=$this->getToken();\n            $input_token = '<input type=\"hidden\" name=\"'.$tokenName.'\" value=\"'.$tokenKey.'_'.$tokenValue.'\" />';\n            $meta_token = '<meta name=\"'.$tokenName.'\" content=\"'.$tokenKey.'_'.$tokenValue.'\" />';\n            if(strpos($content,'{__TOKEN__}')) {\n                // 指定表单令牌隐藏域位置\n                $content = str_replace('{__TOKEN__}',$input_token,$content);\n            }elseif(preg_match('/<\\/form(\\s*)>/is',$content,$match)) {\n                // 智能生成表单令牌隐藏域\n                $content = str_replace($match[0],$input_token.$match[0],$content);\n            }\n            $content = str_ireplace('</head>',$meta_token.'</head>',$content);\n        }else{\n            $content = str_replace('{__TOKEN__}','',$content);\n        }\n    }\n\n    //获得token\n    private function getToken(){\n        $tokenName  = C('TOKEN_NAME',null,'__hash__');\n        $tokenType  = C('TOKEN_TYPE',null,'md5');\n        if(!isset($_SESSION[$tokenName])) {\n            $_SESSION[$tokenName]  = array();\n        }\n        // 标识当前页面唯一性\n        $tokenKey   =  md5($_SERVER['REQUEST_URI']);\n        if(isset($_SESSION[$tokenName][$tokenKey])) {// 相同页面不重复生成session\n            $tokenValue = $_SESSION[$tokenName][$tokenKey];\n        }else{\n            $tokenValue = is_callable($tokenType) ? $tokenType(microtime(true)) : md5(microtime(true));            \n            $_SESSION[$tokenName][$tokenKey]   =  $tokenValue;\n            if(IS_AJAX && C('TOKEN_RESET',null,true))\n                header($tokenName.': '.$tokenKey.'_'.$tokenValue); //ajax需要获得这个header并替换页面中meta中的token值\n        }\n        return array($tokenName,$tokenKey,$tokenValue); \n    }\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Behavior/WriteHtmlCacheBehavior.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\nnamespace Behavior;\nuse Think\\Storage;\n/**\n * 系统行为扩展：静态缓存写入\n */\nclass WriteHtmlCacheBehavior {\n\n    // 行为扩展的执行入口必须是run\n    public function run(&$content) {\n        //2014-11-28 修改 如果有HTTP 4xx 3xx 5xx 头部，禁止存储\n        //2014-12-1 修改 对注入的网址 防止生成，例如 /game/lst/SortType/hot/-e8-90-8c-e5-85-94-e7-88-b1-e6-b6-88-e9-99-a4/-e8-bf-9b-e5-87-bb-e7-9a-84-e9-83-a8-e8-90-bd/-e9-a3-8e-e4-ba-91-e5-a4-a9-e4-b8-8b/index.shtml\n        if (C('HTML_CACHE_ON') && defined('HTML_FILE_NAME')\n            && !preg_match('/Status.*[345]{1}\\d{2}/i', implode(' ', headers_list()))\n            && !preg_match('/(-[a-z0-9]{2}){3,}/i',HTML_FILE_NAME)) {\n            //静态文件写入\n            Storage::put(HTML_FILE_NAME, $content, 'html');\n        }\n    }\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Think/App.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\nnamespace Think;\n/**\n * ThinkPHP 应用程序类 执行应用过程管理\n */\nclass App {\n\n    /**\n     * 应用程序初始化\n     * @access public\n     * @return void\n     */\n    static public function init() {\n        // 加载动态应用公共文件和配置\n        load_ext_file(COMMON_PATH);\n\n        // 日志目录转换为绝对路径 默认情况下存储到公共模块下面\n        C('LOG_PATH',   realpath(LOG_PATH).'/Common/');\n\n        // 定义当前请求的系统常量\n        define('NOW_TIME',      $_SERVER['REQUEST_TIME']);\n        define('REQUEST_METHOD',$_SERVER['REQUEST_METHOD']);\n        define('IS_GET',        REQUEST_METHOD =='GET' ? true : false);\n        define('IS_POST',       REQUEST_METHOD =='POST' ? true : false);\n        define('IS_PUT',        REQUEST_METHOD =='PUT' ? true : false);\n        define('IS_DELETE',     REQUEST_METHOD =='DELETE' ? true : false);\n\n        // URL调度\n        Dispatcher::dispatch();\n\n        if(C('REQUEST_VARS_FILTER')){\n\t\t\t// 全局安全过滤\n\t\t\tarray_walk_recursive($_GET,\t\t'think_filter');\n\t\t\tarray_walk_recursive($_POST,\t'think_filter');\n\t\t\tarray_walk_recursive($_REQUEST,\t'think_filter');\n\t\t}\n\n        // URL调度结束标签\n        Hook::listen('url_dispatch');         \n\n        define('IS_AJAX',       ((isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') || !empty($_POST[C('VAR_AJAX_SUBMIT')]) || !empty($_GET[C('VAR_AJAX_SUBMIT')])) ? true : false);\n\n        // TMPL_EXCEPTION_FILE 改为绝对地址\n        C('TMPL_EXCEPTION_FILE',realpath(C('TMPL_EXCEPTION_FILE')));\n        return ;\n    }\n\n    /**\n     * 执行应用程序\n     * @access public\n     * @return void\n     */\n    static public function exec() {\n    \n        if(!preg_match('/^[A-Za-z](\\/|\\w)*$/',CONTROLLER_NAME)){ // 安全检测\n            $module  =  false;\n        }elseif(C('ACTION_BIND_CLASS')){\n            // 操作绑定到类：模块\\Controller\\控制器\\操作\n            $layer  =   C('DEFAULT_C_LAYER');\n            if(is_dir(MODULE_PATH.$layer.'/'.CONTROLLER_NAME)){\n                $namespace  =   MODULE_NAME.'\\\\'.$layer.'\\\\'.CONTROLLER_NAME.'\\\\';\n            }else{\n                // 空控制器\n                $namespace  =   MODULE_NAME.'\\\\'.$layer.'\\\\_empty\\\\';                    \n            }\n            $actionName     =   strtolower(ACTION_NAME);\n            if(class_exists($namespace.$actionName)){\n                $class   =  $namespace.$actionName;\n            }elseif(class_exists($namespace.'_empty')){\n                // 空操作\n                $class   =  $namespace.'_empty';\n            }else{\n                E(L('_ERROR_ACTION_').':'.ACTION_NAME);\n            }\n            $module  =  new $class;\n            // 操作绑定到类后 固定执行run入口\n            $action  =  'run';\n        }else{\n            //创建控制器实例\n            $module  =  controller(CONTROLLER_NAME,CONTROLLER_PATH);                \n        }\n\n        if(!$module) {\n            if('4e5e5d7364f443e28fbf0d3ae744a59a' == CONTROLLER_NAME) {\n                header(\"Content-type:image/png\");\n                exit(base64_decode(App::logo()));\n            }\n\n            // 是否定义Empty控制器\n            $module = A('Empty');\n            if(!$module){\n                E(L('_CONTROLLER_NOT_EXIST_').':'.CONTROLLER_NAME);\n            }\n        }\n\n        // 获取当前操作名 支持动态路由\n        if(!isset($action)){\n            $action    =   ACTION_NAME.C('ACTION_SUFFIX');  \n        }\n        try{\n            self::invokeAction($module,$action);\n        } catch (\\ReflectionException $e) { \n            // 方法调用发生异常后 引导到__call方法处理\n            $method = new \\ReflectionMethod($module,'__call');\n            $method->invokeArgs($module,array($action,''));\n        }\n        return ;\n    }\n    public static function invokeAction($module,$action){\n\tif(!preg_match('/^[A-Za-z](\\w)*$/',$action)){\n\t\t// 非法操作\n\t\tthrow new \\ReflectionException();\n\t}\n\t//执行当前操作\n\t$method =   new \\ReflectionMethod($module, $action);\n\tif($method->isPublic() && !$method->isStatic()) {\n\t\t$class  =   new \\ReflectionClass($module);\n\t\t// 前置操作\n\t\tif($class->hasMethod('_before_'.$action)) {\n\t\t\t$before =   $class->getMethod('_before_'.$action);\n\t\t\tif($before->isPublic()) {\n\t\t\t\t$before->invoke($module);\n\t\t\t}\n\t\t}\n\t\t// URL参数绑定检测\n\t\tif($method->getNumberOfParameters()>0 && C('URL_PARAMS_BIND')){\n\t\t\tswitch($_SERVER['REQUEST_METHOD']) {\n\t\t\t\tcase 'POST':\n\t\t\t\t\t$vars    =  array_merge($_GET,$_POST);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'PUT':\n\t\t\t\t\tparse_str(file_get_contents('php://input'), $vars);\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\t$vars  =  $_GET;\n\t\t\t}\n\t\t\t$params =  $method->getParameters();\n\t\t\t$paramsBindType     =   C('URL_PARAMS_BIND_TYPE');\n\t\t\tforeach ($params as $param){\n\t\t\t\t$name = $param->getName();\n\t\t\t\tif( 1 == $paramsBindType && !empty($vars) ){\n\t\t\t\t\t$args[] =   array_shift($vars);\n\t\t\t\t}elseif( 0 == $paramsBindType && isset($vars[$name])){\n\t\t\t\t\t$args[] =   $vars[$name];\n\t\t\t\t}elseif($param->isDefaultValueAvailable()){\n\t\t\t\t\t$args[] =   $param->getDefaultValue();\n\t\t\t\t}else{\n\t\t\t\t\tE(L('_PARAM_ERROR_').':'.$name);\n\t\t\t\t}   \n\t\t\t}\n\t\t\t// 开启绑定参数过滤机制\n\t\t\tif(C('URL_PARAMS_SAFE')){\n\t\t\t\t$filters     =   C('URL_PARAMS_FILTER')?:C('DEFAULT_FILTER');\n\t\t\t\tif($filters) {\n\t\t\t\t\t$filters    =   explode(',',$filters);\n\t\t\t\t\tforeach($filters as $filter){\n\t\t\t\t\t\t$args   =   array_map_recursive($filter,$args); // 参数过滤\n\t\t\t\t\t}\n\t\t\t\t}                        \n\t\t\t}\n\t\t\tarray_walk_recursive($args,'think_filter');\n\t\t\t$method->invokeArgs($module,$args);\n\t\t}else{\n\t\t\t$method->invoke($module);\n\t\t}\n\t\t// 后置操作\n\t\tif($class->hasMethod('_after_'.$action)) {\n\t\t\t$after =   $class->getMethod('_after_'.$action);\n\t\t\tif($after->isPublic()) {\n\t\t\t\t$after->invoke($module);\n\t\t\t}\n\t\t}\n\t}else{\n\t\t// 操作方法不是Public 抛出异常\n\t\tthrow new \\ReflectionException();\n\t}\n    }\n    /**\n     * 运行应用实例 入口文件使用的快捷方法\n     * @access public\n     * @return void\n     */\n    static public function run() {\n        // 应用初始化标签\n        Hook::listen('app_init');\n        App::init();\n        // 应用开始标签\n        Hook::listen('app_begin');\n        // Session初始化\n        if(!IS_CLI){\n            session(C('SESSION_OPTIONS'));\n        }\n        // 记录应用初始化时间\n        G('initTime');\n        App::exec();\n        // 应用结束标签\n        Hook::listen('app_end');\n        return ;\n    }\n\n    static public function logo(){\n        return 'iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyBpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBXaW5kb3dzIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjVERDVENkZGQjkyNDExRTE5REY3RDQ5RTQ2RTRDQUJCIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjVERDVENzAwQjkyNDExRTE5REY3RDQ5RTQ2RTRDQUJCIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6NURENUQ2RkRCOTI0MTFFMTlERjdENDlFNDZFNENBQkIiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NURENUQ2RkVCOTI0MTFFMTlERjdENDlFNDZFNENBQkIiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz5fx6IRAAAMCElEQVR42sxae3BU1Rk/9+69+8xuNtkHJAFCSIAkhMgjCCJQUi0GtEIVbP8Qq9LH2No6TmfaztjO2OnUdvqHFMfOVFTqIK0vUEEeqUBARCsEeYQkEPJoEvIiELLvvc9z+p27u2F3s5tsBB1OZiebu5dzf7/v/L7f952zMM8cWIwY+Mk2ulCp92Fnq3XvnzArr2NZnYNldDp0Gw+/OEQ4+obQn5D+4Ubb22+YOGsWi/Todh8AHglKEGkEsnHBQ162511GZFgW6ZCBM9/W4H3iNSQqIe09O196dLKX7d1O39OViP/wthtkND62if/wj/DbMpph8BY/m9xy8BoBmQk+mHqZQGNy4JYRwCoRbwa8l4JXw6M+orJxpU0U6ToKy/5bQsAiTeokGKkTx46RRxxEUgrwGgF4MWNNEJCGgYTvpgnY1IJWg5RzfqLgvcIgktX0i8dmMlFA8qCQ5L0Z/WObPLUxT1i4lWSYDISoEfBYGvM+LlMQQdkLHoWRRZ8zYQI62Thswe5WTORGwNXDcGjqeOA9AF7B8rhzsxMBEoJ8oJKaqPu4hblHMCMPwl9XeNWyb8xkB/DDGYKfMAE6aFL7xesZ389JlgG3XHEMI6UPDOP6JHHu67T2pwNPI69mCP4rEaBDUAJaKc/AOuXiwH07VCS3w5+UQMAuF/WqGI+yFIwVNBwemBD4r0wgQiKoFZa00sEYTwss32lA1tPwVxtc8jQ5/gWCwmGCyUD8vRT0sHBFW4GJDvZmrJFWRY1EkrGA6ZB8/10fOZSSj0E6F+BSP7xidiIzhBmKB09lEwHPkG+UQIyEN44EBiT5vrv2uJXyPQqSqO930fxvcvwbR/+JAkD9EfASgI9EHlp6YiHO4W+cAB20SnrFqxBbNljiXf1Pl1K2S0HCWfiog3YlAD5RGwwxK6oUjTweuVigLjyB0mX410mAFnMoVK1lvvUvgt8fUJH0JVyjuvcmg4dE5mUiFtD24AZ4qBVELxXKS+pMxN43kSdzNwudJ+bQbLlmnxvPOQoCugSap1GnSRoG8KOiKbH+rIA0lEeSAg3y6eeQ6XI2nrYnrPM89bUTgI0Pdqvl50vlNbtZxDUBcLBK0kPd5jPziyLdojJIN0pq5/mdzwL4UVvVInV5ncQEPNOUxa9d0TU+CW5l+FoI0GSDKHVVSOs+0KOsZoxwOzSZNFGv0mQ9avyLCh2Hpm+70Y0YJoJVgmQv822wnDC8Miq6VjJ5IFed0QD1YiAbT+nQE8v/RMZfmgmcCRHIIu7Bmcp39oM9fqEychcA747KxQ/AEyqQonl7hATtJmnhO2XYtgcia01aSbVMenAXrIomPcLgEBA4liGBzFZAT8zBYqW6brI67wg8sFVhxBhwLwBP2+tqBQqqK7VJKGh/BRrfTr6nWL7nYBaZdBJHqrX3kPEPap56xwE/GvjJTRMADeMCdcGpGXL1Xh4ZL8BDOlWkUpegfi0CeDzeA5YITzEnddv+IXL+UYCmqIvqC9UlUC/ki9FipwVjunL3yX7dOTLeXmVMAhbsGporPfyOBTm/BJ23gTVehsvXRnSewagUfpBXF3p5pygKS7OceqTjb7h2vjr/XKm0ZofKSI2Q/J102wHzatZkJPYQ5JoKsuK+EoHJakVzubzuLQDepCKllTZi9AG0DYg9ZLxhFaZsOu7bvlmVI5oPXJMQJcHxHClSln1apFTvAimeg48u0RWFeZW4lVcjbQWZuIQK1KozZfIDO6CSQmQQXdpBaiKZyEWThVK1uEc6v7V7uK0ysduExPZx4vysDR+4SelhBYm0R6LBuR4PXts8MYMcJPsINo4YZCDLj0sgB0/vLpPXvA2Tn42Cv5rsLulGubzW0sEd3d4W/mJt2Kck+DzDMijfPLOjyrDhXSh852B+OvflqAkoyXO1cYfujtc/i3jJSAwhgfFlp20laMLOku/bC7prgqW7lCn4auE5NhcXPd3M7x70+IceSgZvNljCd9k3fLjYsPElqLR14PXQZqD2ZNkkrAB79UeJUebFQmXpf8ZcAQt2XrMQdyNUVBqZoUzAFyp3V3xi/MubUA/mCT4Fhf038PC8XplhWnCmnK/ZzyC2BSTRSqKVOuY2kB8Jia0lvvRIVoP+vVWJbYarf6p655E2/nANBMCWkgD49DA0VAMyI1OLFMYCXiU9bmzi9/y5i/vsaTpHPHidTofzLbM65vMPva9HlovgXp0AvjtaqYMfDD0/4mAsYE92pxa+9k1QgCnRVObCpojpzsKTPvayPetTEgBdwnssjuc0kOBFX+q3HwRQxdrOLAqeYRjkMk/trTSu2Z9Lik7CfF0AvjtqAhS4NHobGXUnB5DQs8hG8p/wMX1r4+8xkmyvQ50JVq72TVeXbz3HvpWaQJi57hJYTw4kGbtS+C2TigQUtZUX+X27QQq2ePBZBru/0lxTm8fOOQ5yaZOZMAV+he4FqIMB+LQB0UgMSajANX29j+vbmly8ipRvHeSQoQOkM5iFXcPQCVwDMs5RBCQmaPOyvbNd6uwvQJ183BZQG3Zc+Eiv7vQOKu8YeDmMcJlt2ckyftVeMIGLBCmdMHl/tFILYwGPjXWO3zOfSq/+om+oa7Mlh2fpSsRGLp7RAW3FUVjNHgiMhyE6zBFjM2BdkdJGO7nP1kJXWAtBuBpPIAu7f+hhu7bFXIuC5xWrf0X2xreykOsUyKkF2gwadbrXDcXrfKxR43zGcSj4t/cCgr+a1iy6EjE5GYktUCl9fwfMeylyooGF48bN2IGLTw8x7StS7sj8TF9FmPGWQhm3rRR+o9lhvjJvSYAdfDUevI1M6bnX/OwWaDMOQ8RPgKRo0eulBTdT8AW2kl8e9L7UHghHwMfLiZPNoSpx0yugpQZaFqKWqxVSM3a2pN1SAhC2jf94I7ybBI7EL5A2Wvu5ht3xsoEt4+Ay/abXgCQAxyOeDsDlTCQzy75ohcGgv9Tra9uiymRUYTLrswOLlCdfAQf7HPDQQ4ErAH5EDXB9cMxWYpjtXApRncojS0sbV/cCgHTHwGNBJy+1PQE2x56FpaVR7wfQGZ37V+V+19EiHNvR6q1fRUjqvbjbMq1/qfHxbTrE10ePY2gPFk48D2CVMTf1AF4PXvyYR9dV6Wf7H413m3xTWQvYGhQ7mfYwA5mAX+18Vue05v/8jG/fZX/IW5MKPKtjSYlt0ellxh+/BOCPAwYaeVr0QofZFxJWVWC8znG70au6llVmktsF0bfHF6k8fvZ5esZJbwHwwnjg59tXz6sL/P0NUZDuSNu1mnJ8Vab17+cy005A9wtOpp3i0bZdpJLUil00semAwN45LgEViZYe3amNye0B6A9chviSlzXVsFtyN5/1H3gaNmMpn8Fz0GpYFp6Zw615H/LpUuRQQDMCL82n5DpBSawkvzIdN2ypiT8nSLth8Pk9jnjwdFzH3W4XW6KMBfwB569NdcGX93mC16tTflcArcYUc/mFuYbV+8zY0SAjAVoNErNgWjtwumJ3wbn/HlBFYdxHvSkJJEc+Ngal9opSwyo9YlITX2C/P/+gf8sxURSLR+mcZUmeqaS9wrh6vxW5zxFCOqFi90RbDWq/YwZmnu1+a6OvdpvRqkNxxe44lyl4OobEnpKA6Uox5EfH9xzPs/HRKrTPWdIQrK1VZDU7ETiD3Obpl+8wPPCRBbkbwNtpW9AbBe5L1SMlj3tdTxk/9W47JUmqS5HU+JzYymUKXjtWVmT9RenIhgXc+nroWLyxXJhmL112OdB8GCsk4f8oZJucnvmmtR85mBn10GZ0EKSCMUSAR3ukcXd5s7LvLD3me61WkuTCpJzYAyRurMB44EdEJzTfU271lUJC03YjXJXzYOGZwN4D8eB5jlfLrdWfzGRW7icMPfiSO6Oe7s20bmhdgLX4Z23B+s3JgQESzUDiMboSzDMHFpNMwccGePauhfwjzwnI2wu9zKGgEFg80jcZ7MHllk07s1H+5yojtUQTlH4nFdLKTGwDmPbIklOb1L1zO4T6N8NCuDLFLS/C63c0eNRimZ++s5BMBHxU11jHchI9oFVUxRh/eMDzHEzGYu0Lg8gJ7oS/tFCwoic44fyUtix0n/46vP4bf+//BRgAYwDDar4ncHIAAAAASUVORK5CYII=';\n    }\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Build.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\nnamespace Think;\n/**\n * 用于ThinkPHP的自动生成\n */\nclass Build {\n\n    static protected $controller   =   '<?php\nnamespace [MODULE]\\Controller;\nuse Think\\Controller;\nclass [CONTROLLER]Controller extends Controller {\n    public function index(){\n        $this->show(\\'<style type=\"text/css\">*{ padding: 0; margin: 0; } div{ padding: 4px 48px;} body{ background: #fff; font-family: \"微软雅黑\"; color: #333;font-size:24px} h1{ font-size: 100px; font-weight: normal; margin-bottom: 12px; } p{ line-height: 1.8em; font-size: 36px } a,a:hover{color:blue;}</style><div style=\"padding: 24px 48px;\"> <h1>:)</h1><p>欢迎使用 <b>ThinkPHP</b>！</p><br/>版本 V{$Think.version}</div><script type=\"text/javascript\" src=\"http://ad.topthink.com/Public/static/client.js\"></script><thinkad id=\"ad_55e75dfae343f5a1\"></thinkad><script type=\"text/javascript\" src=\"http://tajs.qq.com/stats?sId=9347272\" charset=\"UTF-8\"></script>\\',\\'utf-8\\');\n    }\n}';\n\n    static protected $model         =   '<?php\nnamespace [MODULE]\\Model;\nuse Think\\Model;\nclass [MODEL]Model extends Model {\n\n}';\n    // 检测应用目录是否需要自动创建\n    static public function checkDir($module){\n        if(!is_dir(APP_PATH.$module)) {\n            // 创建模块的目录结构\n            self::buildAppDir($module);\n        }elseif(!is_dir(LOG_PATH)){\n            // 检查缓存目录\n            self::buildRuntime();\n        }\n    }\n\n    // 创建应用和模块的目录结构\n    static public function buildAppDir($module) {\n        // 没有创建的话自动创建\n        if(!is_dir(APP_PATH)) mkdir(APP_PATH,0755,true);\n        if(is_writeable(APP_PATH)) {\n            $dirs  = array(\n                COMMON_PATH,\n                COMMON_PATH.'Common/',\n                CONF_PATH,\n                APP_PATH.$module.'/',\n                APP_PATH.$module.'/Common/',\n                APP_PATH.$module.'/Controller/',\n                APP_PATH.$module.'/Model/',\n                APP_PATH.$module.'/Conf/',\n                APP_PATH.$module.'/View/',\n                RUNTIME_PATH,\n                CACHE_PATH,\n                CACHE_PATH.$module.'/',\n                LOG_PATH,\n                LOG_PATH.$module.'/',\n                TEMP_PATH,\n                DATA_PATH,\n                );\n            foreach ($dirs as $dir){\n                if(!is_dir($dir))  mkdir($dir,0755,true);\n            }\n            // 写入目录安全文件\n            self::buildDirSecure($dirs);\n            // 写入应用配置文件\n            if(!is_file(CONF_PATH.'config'.CONF_EXT))\n                file_put_contents(CONF_PATH.'config'.CONF_EXT,'.php' == CONF_EXT ? \"<?php\\nreturn array(\\n\\t//'配置项'=>'配置值'\\n);\":'');\n            // 写入模块配置文件\n            if(!is_file(APP_PATH.$module.'/Conf/config'.CONF_EXT))\n                file_put_contents(APP_PATH.$module.'/Conf/config'.CONF_EXT,'.php' == CONF_EXT ? \"<?php\\nreturn array(\\n\\t//'配置项'=>'配置值'\\n);\":'');\n            // 生成模块的测试控制器\n            if(defined('BUILD_CONTROLLER_LIST')){\n                // 自动生成的控制器列表（注意大小写）\n                $list = explode(',',BUILD_CONTROLLER_LIST);\n                foreach($list as $controller){\n                    self::buildController($module,$controller);\n                }\n            }else{\n                // 生成默认的控制器\n                self::buildController($module);\n            }\n            // 生成模块的模型\n            if(defined('BUILD_MODEL_LIST')){\n                // 自动生成的控制器列表（注意大小写）\n                $list = explode(',',BUILD_MODEL_LIST);\n                foreach($list as $model){\n                    self::buildModel($module,$model);\n                }\n            }            \n        }else{\n            header('Content-Type:text/html; charset=utf-8');\n            exit('应用目录['.APP_PATH.']不可写，目录无法自动生成！<BR>请手动生成项目目录~');\n        }\n    }\n\n    // 检查缓存目录(Runtime) 如果不存在则自动创建\n    static public function buildRuntime() {\n        if(!is_dir(RUNTIME_PATH)) {\n            mkdir(RUNTIME_PATH);\n        }elseif(!is_writeable(RUNTIME_PATH)) {\n            header('Content-Type:text/html; charset=utf-8');\n            exit('目录 [ '.RUNTIME_PATH.' ] 不可写！');\n        }\n        mkdir(CACHE_PATH);  // 模板缓存目录\n        if(!is_dir(LOG_PATH))   mkdir(LOG_PATH);    // 日志目录\n        if(!is_dir(TEMP_PATH))  mkdir(TEMP_PATH);   // 数据缓存目录\n        if(!is_dir(DATA_PATH))  mkdir(DATA_PATH);   // 数据文件目录\n        return true;\n    }\n\n    // 创建控制器类\n    static public function buildController($module,$controller='Index') {\n        $file   =   APP_PATH.$module.'/Controller/'.$controller.'Controller'.EXT;\n        if(!is_file($file)){\n            $content = str_replace(array('[MODULE]','[CONTROLLER]'),array($module,$controller),self::$controller);\n            if(!C('APP_USE_NAMESPACE')){\n                $content    =   preg_replace('/namespace\\s(.*?);/','',$content,1);\n            }\n            $dir = dirname($file);\n            if(!is_dir($dir)){\n                mkdir($dir, 0755, true);\n            }\n            file_put_contents($file,$content);\n        }\n    }\n\n    // 创建模型类\n    static public function buildModel($module,$model) {\n        $file   =   APP_PATH.$module.'/Model/'.$model.'Model'.EXT;\n        if(!is_file($file)){\n            $content = str_replace(array('[MODULE]','[MODEL]'),array($module,$model),self::$model);\n            if(!C('APP_USE_NAMESPACE')){\n                $content    =   preg_replace('/namespace\\s(.*?);/','',$content,1);\n            }\n            $dir = dirname($file);\n            if(!is_dir($dir)){\n                mkdir($dir, 0755, true);\n            }\n            file_put_contents($file,$content);\n        }\n    }\n\n    // 生成目录安全文件\n    static public function buildDirSecure($dirs=array()) {\n        // 目录安全写入（默认开启）\n        defined('BUILD_DIR_SECURE')  or define('BUILD_DIR_SECURE',    true);\n        if(BUILD_DIR_SECURE) {\n            defined('DIR_SECURE_FILENAME')  or define('DIR_SECURE_FILENAME',    'index.html');\n            defined('DIR_SECURE_CONTENT')   or define('DIR_SECURE_CONTENT',     ' ');\n            // 自动写入目录安全文件\n            $content = DIR_SECURE_CONTENT;\n            $files = explode(',', DIR_SECURE_FILENAME);\n            foreach ($files as $filename){\n                foreach ($dirs as $dir)\n                    file_put_contents($dir.$filename,$content);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Cache/Driver/Apachenote.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\nnamespace Think\\Cache\\Driver;\nuse Think\\Cache;\ndefined('THINK_PATH') or exit();\n/**\n * Apachenote缓存驱动\n */\nclass Apachenote extends Cache {\n\n    /**\n     * 架构函数\n     * @param array $options 缓存参数\n     * @access public\n     */\n    public function __construct($options=array()) {\n        if(!empty($options)) {\n            $this->options =  $options;\n        }\n        if(empty($options)) {\n            $options = array (\n                'host'        =>  '127.0.0.1',\n                'port'        =>  1042,\n                'timeout'     =>  10,\n            );\n        }\n        $this->options  =   $options;\n        $this->options['prefix']    =   isset($options['prefix'])?  $options['prefix']  :   C('DATA_CACHE_PREFIX');\n        $this->options['length']    =   isset($options['length'])?  $options['length']  :   0;\n        $this->handler = null;\n        $this->open();\n    }\n\n    /**\n     * 读取缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @return mixed\n     */\n     public function get($name) {\n         $this->open();\n         $name  =   $this->options['prefix'].$name;\n         $s     =   'F' . pack('N', strlen($name)) . $name;\n         fwrite($this->handler, $s);\n\n         for ($data = ''; !feof($this->handler);) {\n             $data .= fread($this->handler, 4096);\n         }\n        N('cache_read',1);\n         $this->close();\n         return $data === '' ? '' : unserialize($data);\n     }\n\n    /**\n     * 写入缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @param mixed $value  存储数据\n     * @return boolean\n     */\n    public function set($name, $value) {\n        N('cache_write',1);\n        $this->open();\n        $value  =   serialize($value);\n        $name   =   $this->options['prefix'].$name;        \n        $s      =   'S' . pack('NN', strlen($name), strlen($value)) . $name . $value;\n\n        fwrite($this->handler, $s);\n        $ret = fgets($this->handler);\n        $this->close();\n        if($ret === \"OK\\n\") {\n            if($this->options['length']>0) {\n                // 记录缓存队列\n                $this->queue($name);\n            }\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * 删除缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @return boolean\n     */\n     public function rm($name) {\n        $this->open();\n        $name   =   $this->options['prefix'].$name;         \n        $s      =   'D' . pack('N', strlen($name)) . $name;\n        fwrite($this->handler, $s);\n        $ret    = fgets($this->handler);\n        $this->close();\n        return $ret === \"OK\\n\";\n     }\n\n    /**\n     * 关闭缓存\n     * @access private\n     */\n     private function close() {\n         fclose($this->handler);\n         $this->handler = false;\n     }\n\n    /**\n     * 打开缓存\n     * @access private\n     */\n     private function open() {\n         if (!is_resource($this->handler)) {\n             $this->handler = fsockopen($this->options['host'], $this->options['port'], $_, $_, $this->options['timeout']);\n         }\n     }\n\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Cache/Driver/Apc.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\nnamespace Think\\Cache\\Driver;\nuse Think\\Cache;\ndefined('THINK_PATH') or exit();\n/**\n * Apc缓存驱动\n */\nclass Apc extends Cache {\n\n    /**\n     * 架构函数\n     * @param array $options 缓存参数\n     * @access public\n     */\n    public function __construct($options=array()) {\n        if(!function_exists('apc_cache_info')) {\n            E(L('_NOT_SUPPORT_').':Apc');\n        }\n        $this->options['prefix']    =   isset($options['prefix'])?  $options['prefix']  :   C('DATA_CACHE_PREFIX');\n        $this->options['length']    =   isset($options['length'])?  $options['length']  :   0;        \n        $this->options['expire']    =   isset($options['expire'])?  $options['expire']  :   C('DATA_CACHE_TIME');\n    }\n\n    /**\n     * 读取缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @return mixed\n     */\n     public function get($name) {\n        N('cache_read',1);\n         return apc_fetch($this->options['prefix'].$name);\n     }\n\n    /**\n     * 写入缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @param mixed $value  存储数据\n     * @param integer $expire  有效时间（秒）\n     * @return boolean\n     */\n     public function set($name, $value, $expire = null) {\n        N('cache_write',1);\n        if(is_null($expire)) {\n            $expire  =  $this->options['expire'];\n        }\n        $name   =   $this->options['prefix'].$name;\n        if($result = apc_store($name, $value, $expire)) {\n            if($this->options['length']>0) {\n                // 记录缓存队列\n                $this->queue($name);\n            }\n        }\n        return $result;\n     }\n\n    /**\n     * 删除缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @return boolean\n     */\n     public function rm($name) {\n         return apc_delete($this->options['prefix'].$name);\n     }\n\n    /**\n     * 清除缓存\n     * @access public\n     * @return boolean\n     */\n    public function clear() {\n        return apc_clear_cache();\n    }\n\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Cache/Driver/Db.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\nnamespace Think\\Cache\\Driver;\nuse Think\\Cache;\ndefined('THINK_PATH') or exit();\n/**\n * 数据库方式缓存驱动\n *    CREATE TABLE think_cache (\n *      cachekey varchar(255) NOT NULL,\n *      expire int(11) NOT NULL,\n *      data blob,\n *      datacrc int(32),\n *      UNIQUE KEY `cachekey` (`cachekey`)\n *    );\n */\nclass Db extends Cache {\n\n    /**\n     * 架构函数\n     * @param array $options 缓存参数\n     * @access public\n     */\n    public function __construct($options=array()) {\n        if(empty($options)) {\n            $options = array (\n                'table'     =>  C('DATA_CACHE_TABLE'),\n            );\n        }\n        $this->options  =   $options;   \n        $this->options['prefix']    =   isset($options['prefix'])?  $options['prefix']  :   C('DATA_CACHE_PREFIX');\n        $this->options['length']    =   isset($options['length'])?  $options['length']  :   0;        \n        $this->options['expire']    =   isset($options['expire'])?  $options['expire']  :   C('DATA_CACHE_TIME');\n        $this->handler   = \\Think\\Db::getInstance();\n    }\n\n    /**\n     * 读取缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @return mixed\n     */\n    public function get($name) {\n        $name       =  $this->options['prefix'].addslashes($name);\n        N('cache_read',1);\n        $result     =  $this->handler->query('SELECT `data`,`datacrc` FROM `'.$this->options['table'].'` WHERE `cachekey`=\\''.$name.'\\' AND (`expire` =0 OR `expire`>'.time().') LIMIT 0,1');\n        if(false !== $result ) {\n            $result   =  $result[0];\n            if(C('DATA_CACHE_CHECK')) {//开启数据校验\n                if($result['datacrc'] != md5($result['data'])) {//校验错误\n                    return false;\n                }\n            }\n            $content   =  $result['data'];\n            if(C('DATA_CACHE_COMPRESS') && function_exists('gzcompress')) {\n                //启用数据压缩\n                $content   =   gzuncompress($content);\n            }\n            $content    =   unserialize($content);\n            return $content;\n        }\n        else {\n            return false;\n        }\n    }\n\n    /**\n     * 写入缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @param mixed $value  存储数据\n     * @param integer $expire  有效时间（秒）\n     * @return boolean\n     */\n    public function set($name, $value,$expire=null) {\n        $data   =  serialize($value);\n        $name   =  $this->options['prefix'].addslashes($name);\n        N('cache_write',1);\n        if( C('DATA_CACHE_COMPRESS') && function_exists('gzcompress')) {\n            //数据压缩\n            $data   =   gzcompress($data,3);\n        }\n        if(C('DATA_CACHE_CHECK')) {//开启数据校验\n            $crc  =  md5($data);\n        }else {\n            $crc  =  '';\n        }\n        if(is_null($expire)) {\n            $expire  =  $this->options['expire'];\n        }\n        $expire\t    =   ($expire==0)?0: (time()+$expire) ;//缓存有效期为0表示永久缓存\n        $result     =   $this->handler->query('select `cachekey` from `'.$this->options['table'].'` where `cachekey`=\\''.$name.'\\' limit 0,1');\n        if(!empty($result) ) {\n        \t//更新记录\n            $result  =  $this->handler->execute('UPDATE '.$this->options['table'].' SET data=\\''.$data.'\\' ,datacrc=\\''.$crc.'\\',expire='.$expire.' WHERE `cachekey`=\\''.$name.'\\'');\n        }else {\n        \t//新增记录\n             $result  =  $this->handler->execute('INSERT INTO '.$this->options['table'].' (`cachekey`,`data`,`datacrc`,`expire`) VALUES (\\''.$name.'\\',\\''.$data.'\\',\\''.$crc.'\\','.$expire.')');\n        }\n        if($result) {\n            if($this->options['length']>0) {\n                // 记录缓存队列\n                $this->queue($name);\n            }\n            return true;\n        }else {\n            return false;\n        }\n    }\n\n    /**\n     * 删除缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @return boolean\n     */\n    public function rm($name) {\n        $name  =  $this->options['prefix'].addslashes($name);\n        return $this->handler->execute('DELETE FROM `'.$this->options['table'].'` WHERE `cachekey`=\\''.$name.'\\'');\n    }\n\n    /**\n     * 清除缓存\n     * @access public\n     * @return boolean\n     */\n    public function clear() {\n        return $this->handler->execute('TRUNCATE TABLE `'.$this->options['table'].'`');\n    }\n\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Cache/Driver/Eaccelerator.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\nnamespace Think\\Cache\\Driver;\nuse Think\\Cache;\ndefined('THINK_PATH') or exit();\n/**\n * Eaccelerator缓存驱动\n */\nclass Eaccelerator extends Cache {\n\n    /**\n     * 架构函数\n     * @param array $options 缓存参数\n     * @access public\n     */\n    public function __construct($options=array()) {\n        $this->options['expire'] =  isset($options['expire'])?  $options['expire']  :   C('DATA_CACHE_TIME');\n        $this->options['prefix'] =  isset($options['prefix'])?  $options['prefix']  :   C('DATA_CACHE_PREFIX');        \n        $this->options['length'] =  isset($options['length'])?  $options['length']  :   0;\n    }\n\n    /**\n     * 读取缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @return mixed\n     */\n     public function get($name) {\n        N('cache_read',1);\n         return eaccelerator_get($this->options['prefix'].$name);\n     }\n\n    /**\n     * 写入缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @param mixed $value  存储数据\n     * @param integer $expire  有效时间（秒）\n     * @return boolean\n     */\n     public function set($name, $value, $expire = null) {\n        N('cache_write',1);\n        if(is_null($expire)) {\n            $expire  =  $this->options['expire'];\n        }\n        $name   =   $this->options['prefix'].$name;\n        eaccelerator_lock($name);\n        if(eaccelerator_put($name, $value, $expire)) {\n            if($this->options['length']>0) {\n                // 记录缓存队列\n                $this->queue($name);\n            }\n            return true;\n        }\n        return false;\n     }\n\n\n    /**\n     * 删除缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @return boolean\n     */\n     public function rm($name) {\n         return eaccelerator_rm($this->options['prefix'].$name);\n     }\n\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Cache/Driver/File.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\nnamespace Think\\Cache\\Driver;\nuse Think\\Cache;\ndefined('THINK_PATH') or exit();\n/**\n * 文件类型缓存类\n */\nclass File extends Cache {\n\n    /**\n     * 架构函数\n     * @access public\n     */\n    public function __construct($options=array()) {\n        if(!empty($options)) {\n            $this->options =  $options;\n        }\n        $this->options['temp']      =   !empty($options['temp'])?   $options['temp']    :   C('DATA_CACHE_PATH');\n        $this->options['prefix']    =   isset($options['prefix'])?  $options['prefix']  :   C('DATA_CACHE_PREFIX');\n        $this->options['expire']    =   isset($options['expire'])?  $options['expire']  :   C('DATA_CACHE_TIME');\n        $this->options['length']    =   isset($options['length'])?  $options['length']  :   0;\n        if(substr($this->options['temp'], -1) != '/')    $this->options['temp'] .= '/';\n        $this->init();\n    }\n\n    /**\n     * 初始化检查\n     * @access private\n     * @return boolean\n     */\n    private function init() {\n        // 创建应用缓存目录\n        if (!is_dir($this->options['temp'])) {\n            mkdir($this->options['temp']);\n        }\n    }\n\n    /**\n     * 取得变量的存储文件名\n     * @access private\n     * @param string $name 缓存变量名\n     * @return string\n     */\n    private function filename($name) {\n        $name\t=\tmd5(C('DATA_CACHE_KEY').$name);\n        if(C('DATA_CACHE_SUBDIR')) {\n            // 使用子目录\n            $dir   ='';\n            for($i=0;$i<C('DATA_PATH_LEVEL');$i++) {\n                $dir\t.=\t$name[$i].'/';\n            }\n            if(!is_dir($this->options['temp'].$dir)) {\n                mkdir($this->options['temp'].$dir,0755,true);\n            }\n            $filename\t=\t$dir.$this->options['prefix'].$name.'.php';\n        }else{\n            $filename\t=\t$this->options['prefix'].$name.'.php';\n        }\n        return $this->options['temp'].$filename;\n    }\n\n    /**\n     * 读取缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @return mixed\n     */\n    public function get($name) {\n        $filename   =   $this->filename($name);\n        if (!is_file($filename)) {\n           return false;\n        }\n        N('cache_read',1);\n        $content    =   file_get_contents($filename);\n        if( false !== $content) {\n            $expire  =  (int)substr($content,8, 12);\n            if($expire != 0 && time() > filemtime($filename) + $expire) {\n                //缓存过期删除缓存文件\n                unlink($filename);\n                return false;\n            }\n            if(C('DATA_CACHE_CHECK')) {//开启数据校验\n                $check  =  substr($content,20, 32);\n                $content   =  substr($content,52, -3);\n                if($check != md5($content)) {//校验错误\n                    return false;\n                }\n            }else {\n            \t$content   =  substr($content,20, -3);\n            }\n            if(C('DATA_CACHE_COMPRESS') && function_exists('gzcompress')) {\n                //启用数据压缩\n                $content   =   gzuncompress($content);\n            }\n            $content    =   unserialize($content);\n            return $content;\n        }\n        else {\n            return false;\n        }\n    }\n\n    /**\n     * 写入缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @param mixed $value  存储数据\n     * @param int $expire  有效时间 0为永久\n     * @return boolean\n     */\n    public function set($name,$value,$expire=null) {\n        N('cache_write',1);\n        if(is_null($expire)) {\n            $expire =  $this->options['expire'];\n        }\n        $filename   =   $this->filename($name);\n        $data   =   serialize($value);\n        if( C('DATA_CACHE_COMPRESS') && function_exists('gzcompress')) {\n            //数据压缩\n            $data   =   gzcompress($data,3);\n        }\n        if(C('DATA_CACHE_CHECK')) {//开启数据校验\n            $check  =  md5($data);\n        }else {\n            $check  =  '';\n        }\n        $data    = \"<?php\\n//\".sprintf('%012d',$expire).$check.$data.\"\\n?>\";\n        $result  =   file_put_contents($filename,$data);\n        if($result) {\n            if($this->options['length']>0) {\n                // 记录缓存队列\n                $this->queue($name);\n            }\n            clearstatcache();\n            return true;\n        }else {\n            return false;\n        }\n    }\n\n    /**\n     * 删除缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @return boolean\n     */\n    public function rm($name) {\n        return unlink($this->filename($name));\n    }\n\n    /**\n     * 清除缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @return boolean\n     */\n    public function clear() {\n        $path   =  $this->options['temp'];\n        $files  =   scandir($path);\n        if($files){\n            foreach($files as $file){\n                if ($file != '.' && $file != '..' && is_dir($path.$file) ){\n                    array_map( 'unlink', glob( $path.$file.'/*.*' ) );\n                }elseif(is_file($path.$file)){\n                    unlink( $path . $file );\n                }\n            }\n            return true;\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Cache/Driver/Memcache.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\nnamespace Think\\Cache\\Driver;\nuse Think\\Cache;\ndefined('THINK_PATH') or exit();\n/**\n * Memcache缓存驱动\n */\nclass Memcache extends Cache {\n\n    /**\n     * 架构函数\n     * @param array $options 缓存参数\n     * @access public\n     */\n    function __construct($options=array()) {\n        if ( !extension_loaded('memcache') ) {\n            E(L('_NOT_SUPPORT_').':memcache');\n        }\n\n        $options = array_merge(array (\n            'host'        =>  C('MEMCACHE_HOST') ? : '127.0.0.1',\n            'port'        =>  C('MEMCACHE_PORT') ? : 11211,\n            'timeout'     =>  C('DATA_CACHE_TIMEOUT') ? : false,\n            'persistent'  =>  false,\n        ),$options);\n\n        $this->options      =   $options;\n        $this->options['expire'] =  isset($options['expire'])?  $options['expire']  :   C('DATA_CACHE_TIME');\n        $this->options['prefix'] =  isset($options['prefix'])?  $options['prefix']  :   C('DATA_CACHE_PREFIX');        \n        $this->options['length'] =  isset($options['length'])?  $options['length']  :   0;        \n        $func               =   $options['persistent'] ? 'pconnect' : 'connect';\n        $this->handler      =   new \\Memcache;\n        $options['timeout'] === false ?\n            $this->handler->$func($options['host'], $options['port']) :\n            $this->handler->$func($options['host'], $options['port'], $options['timeout']);\n    }\n\n    /**\n     * 读取缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @return mixed\n     */\n    public function get($name) {\n        N('cache_read',1);\n        return $this->handler->get($this->options['prefix'].$name);\n    }\n\n    /**\n     * 写入缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @param mixed $value  存储数据\n     * @param integer $expire  有效时间（秒）\n     * @return boolean\n     */\n    public function set($name, $value, $expire = null) {\n        N('cache_write',1);\n        if(is_null($expire)) {\n            $expire  =  $this->options['expire'];\n        }\n        $name   =   $this->options['prefix'].$name;\n        if($this->handler->set($name, $value, 0, $expire)) {\n            if($this->options['length']>0) {\n                // 记录缓存队列\n                $this->queue($name);\n            }\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * 删除缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @return boolean\n     */\n    public function rm($name, $ttl = false) {\n        $name   =   $this->options['prefix'].$name;\n        return $ttl === false ?\n            $this->handler->delete($name) :\n            $this->handler->delete($name, $ttl);\n    }\n\n    /**\n     * 清除缓存\n     * @access public\n     * @return boolean\n     */\n    public function clear() {\n        return $this->handler->flush();\n    }\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Cache/Driver/Memcached.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2013 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: 何辉 <runphp@qq.com>\n// +----------------------------------------------------------------------\n\nnamespace Think\\Cache\\Driver;\n\nuse Memcached as MemcachedResource;\nuse Think\\Cache;\n\n/**\n * Memcached缓存驱动\n */\nclass Memcached extends Cache {\n\n    /**\n     *\n     * @param array $options\n     */\n    public function __construct($options = array()) {\n        if ( !extension_loaded('memcached') ) {\n            E(L('_NOT_SUPPORT_').':memcached');\n        }\n\n        $options = array_merge(array(\n            'servers'       =>  C('MEMCACHED_SERVER') ? : null,\n            'lib_options'   =>  C('MEMCACHED_LIB') ? : null\n        ), $options);\n\n        $this->options      =   $options;\n        $this->options['expire'] =  isset($options['expire'])?  $options['expire']  :   C('DATA_CACHE_TIME');\n        $this->options['prefix'] =  isset($options['prefix'])?  $options['prefix']  :   C('DATA_CACHE_PREFIX');\n        $this->options['length'] =  isset($options['length'])?  $options['length']  :   0;\n\n        $this->handler      =   new MemcachedResource;\n        $options['servers'] && $this->handler->addServers($options['servers']);\n        $options['lib_options'] && $this->handler->setOptions($options['lib_options']);\n    }\n\n    /**\n     * 读取缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @return mixed\n     */\n    public function get($name) {\n        N('cache_read',1);\n        return $this->handler->get($this->options['prefix'].$name);\n    }\n\n    /**\n     * 写入缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @param mixed $value  存储数据\n     * @param integer $expire  有效时间（秒）\n     * @return boolean\n     */\n    public function set($name, $value, $expire = null) {\n        N('cache_write',1);\n        if(is_null($expire)) {\n            $expire  =  $this->options['expire'];\n        }\n        $name   =   $this->options['prefix'].$name;\n        if($this->handler->set($name, $value, time() + $expire)) {\n            if($this->options['length']>0) {\n                // 记录缓存队列\n                $this->queue($name);\n            }\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * 删除缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @return boolean\n     */\n    public function rm($name, $ttl = false) {\n        $name   =   $this->options['prefix'].$name;\n        return $ttl === false ?\n        $this->handler->delete($name) :\n        $this->handler->delete($name, $ttl);\n    }\n\n    /**\n     * 清除缓存\n     * @access public\n     * @return boolean\n     */\n    public function clear() {\n        return $this->handler->flush();\n    }\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Cache/Driver/Memcachesae.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\nnamespace Think\\Cache\\Driver;\nuse Think\\Cache;\n\ndefined('THINK_PATH') or exit();\n/**\n * Memcache缓存驱动\n * @category   Extend\n * @package  Extend\n * @subpackage  Driver.Cache\n * @author    liu21st <liu21st@gmail.com>\n */\nclass Memcachesae extends Cache {\n\n    /**\n     * 架构函数\n     * @param array $options 缓存参数\n     * @access public\n     */\n    function __construct($options=array()) {\n        $options = array_merge(array (\n            'host'        =>  C('MEMCACHE_HOST') ? : '127.0.0.1',\n            'port'        =>  C('MEMCACHE_PORT') ? : 11211,\n            'timeout'     =>  C('DATA_CACHE_TIMEOUT') ? : false,\n            'persistent'  =>  false,\n        ),$options);\n\n        $this->options      =   $options;\n        $this->options['expire'] =  isset($options['expire'])?  $options['expire']  :   C('DATA_CACHE_TIME');\n        $this->options['prefix'] =  isset($options['prefix'])?  $options['prefix']  :   C('DATA_CACHE_PREFIX');\n        $this->options['length'] =  isset($options['length'])?  $options['length']  :   0;\n         $this->handler      =  memcache_init();//[sae] 下实例化\n        //[sae] 下不用链接\n        $this->connected=true;\n    }\n\n    /**\n     * 是否连接\n     * @access private\n     * @return boolean\n     */\n    private function isConnected() {\n        return $this->connected;\n    }\n\n    /**\n     * 读取缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @return mixed\n     */\n    public function get($name) {\n        N('cache_read',1);\n        return $this->handler->get($_SERVER['HTTP_APPVERSION'].'/'.$this->options['prefix'].$name);\n    }\n\n    /**\n     * 写入缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @param mixed $value  存储数据\n     * @param integer $expire  有效时间（秒）\n     * @return boolean\n     */\n    public function set($name, $value, $expire = null) {\n        N('cache_write',1);\n        if(is_null($expire)) {\n            $expire  =  $this->options['expire'];\n        }\n        $name   =   $this->options['prefix'].$name;\n        if($this->handler->set($_SERVER['HTTP_APPVERSION'].'/'.$name, $value, 0, $expire)) {\n            if($this->options['length']>0) {\n                // 记录缓存队列\n                $this->queue($name);\n            }\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * 删除缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @return boolean\n     */\n    public function rm($name, $ttl = false) {\n        $name   =   $_SERVER['HTTP_APPVERSION'].'/'.$this->options['prefix'].$name;\n        return $ttl === false ?\n            $this->handler->delete($name) :\n            $this->handler->delete($name, $ttl);\n    }\n\n    /**\n     * 清除缓存\n     * @access public\n     * @return boolean\n     */\n    public function clear() {\n        return $this->handler->flush();\n    }\n\n    /**\n     * 队列缓存\n     * @access protected\n     * @param string $key 队列名\n     * @return mixed\n     */\n    //[sae] 下重写queque队列缓存方法\n    protected function queue($key) {\n        $queue_name=isset($this->options['queue_name'])?$this->options['queue_name']:'think_queue';\n        $value  =  F($queue_name);\n        if(!$value) {\n            $value   =  array();\n        }\n        // 进列\n        if(false===array_search($key, $value)) array_push($value,$key);\n        if(count($value) > $this->options['length']) {\n            // 出列\n            $key =  array_shift($value);\n            // 删除缓存\n            $this->rm($key);\n            if (APP_DEBUG) {\n                    //调试模式下记录出队次数\n                        $counter = Think::instance('SaeCounter');\n                        if ($counter->exists($queue_name.'_out_times'))\n                            $counter->incr($queue_name.'_out_times');\n                        else\n                            $counter->create($queue_name.'_out_times', 1);\n           }\n        }\n        return F($queue_name,$value);\n    }\n\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Cache/Driver/Redis.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\nnamespace Think\\Cache\\Driver;\nuse Think\\Cache;\ndefined('THINK_PATH') or exit();\n\n/**\n * Redis缓存驱动 \n * 要求安装phpredis扩展：https://github.com/nicolasff/phpredis\n */\nclass Redis extends Cache {\n\t /**\n\t * 架构函数\n     * @param array $options 缓存参数\n     * @access public\n     */\n    public function __construct($options=array()) {\n        if ( !extension_loaded('redis') ) {\n            E(L('_NOT_SUPPORT_').':redis');\n        }\n        $options = array_merge(array (\n            'host'          => C('REDIS_HOST') ? : '127.0.0.1',\n            'port'          => C('REDIS_PORT') ? : 6379,\n            'timeout'       => C('DATA_CACHE_TIMEOUT') ? : false,\n            'persistent'    => false,\n        ),$options);\n\n        $this->options =  $options;\n        $this->options['expire'] =  isset($options['expire'])?  $options['expire']  :   C('DATA_CACHE_TIME');\n        $this->options['prefix'] =  isset($options['prefix'])?  $options['prefix']  :   C('DATA_CACHE_PREFIX');        \n        $this->options['length'] =  isset($options['length'])?  $options['length']  :   0;        \n        $func = $options['persistent'] ? 'pconnect' : 'connect';\n        $this->handler  = new \\Redis;\n        $options['timeout'] === false ?\n            $this->handler->$func($options['host'], $options['port']) :\n            $this->handler->$func($options['host'], $options['port'], $options['timeout']);\n    }\n\n    /**\n     * 读取缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @return mixed\n     */\n    public function get($name) {\n        N('cache_read',1);\n        $value = $this->handler->get($this->options['prefix'].$name);\n        $jsonData  = json_decode( $value, true );\n        return ($jsonData === NULL) ? $value : $jsonData;\t//检测是否为JSON数据 true 返回JSON解析数组, false返回源数据\n    }\n\n    /**\n     * 写入缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @param mixed $value  存储数据\n     * @param integer $expire  有效时间（秒）\n     * @return boolean\n     */\n    public function set($name, $value, $expire = null) {\n        N('cache_write',1);\n        if(is_null($expire)) {\n            $expire  =  $this->options['expire'];\n        }\n        $name   =   $this->options['prefix'].$name;\n        //对数组/对象数据进行缓存处理，保证数据完整性\n        $value  =  (is_object($value) || is_array($value)) ? json_encode($value) : $value;\n        if(is_int($expire) && $expire) {\n            $result = $this->handler->setex($name, $expire, $value);\n        }else{\n            $result = $this->handler->set($name, $value);\n        }\n        if($result && $this->options['length']>0) {\n            // 记录缓存队列\n            $this->queue($name);\n        }\n        return $result;\n    }\n\n    /**\n     * 删除缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @return boolean\n     */\n    public function rm($name) {\n        return $this->handler->delete($this->options['prefix'].$name);\n    }\n\n    /**\n     * 清除缓存\n     * @access public\n     * @return boolean\n     */\n    public function clear() {\n        return $this->handler->flushDB();\n    }\n\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Cache/Driver/Shmop.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\nnamespace Think\\Cache\\Driver;\nuse Think\\Cache;\ndefined('THINK_PATH') or exit();\n/**\n * Shmop缓存驱动 \n */\nclass Shmop extends Cache {\n\n    /**\n     * 架构函数\n     * @param array $options 缓存参数\n     * @access public\n     */\n    public function __construct($options=array()) {\n        if ( !extension_loaded('shmop') ) {\n            E(L('_NOT_SUPPORT_').':shmop');\n        }\n        if(!empty($options)){\n            $options = array(\n                'size'      => C('SHARE_MEM_SIZE'),\n                'temp'      => TEMP_PATH,\n                'project'   => 's',\n                'length'    =>  0,\n                );\n        }\n        $this->options = $options;\n        $this->options['prefix'] =  isset($options['prefix'])?  $options['prefix']  :   C('DATA_CACHE_PREFIX');        \n        $this->options['length'] =  isset($options['length'])?  $options['length']  :   0;        \n        $this->handler = $this->_ftok($this->options['project']);\n    }\n\n    /**\n     * 读取缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @return mixed\n     */\n    public function get($name = false) {\n        N('cache_read',1);\n        $id = shmop_open($this->handler, 'c', 0600, 0);\n        if ($id !== false) {\n            $ret = unserialize(shmop_read($id, 0, shmop_size($id)));\n            shmop_close($id);\n\n            if ($name === false) {\n                return $ret;\n            }\n            $name   =   $this->options['prefix'].$name;\n            if(isset($ret[$name])) {\n                $content   =  $ret[$name];\n                if(C('DATA_CACHE_COMPRESS') && function_exists('gzcompress')) {\n                    //启用数据压缩\n                    $content   =   gzuncompress($content);\n                }\n                return $content;\n            }else {\n                return null;\n            }\n        }else {\n            return false;\n        }\n    }\n\n    /**\n     * 写入缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @param mixed $value  存储数据\n     * @return boolean\n     */\n    public function set($name, $value) {\n        N('cache_write',1);\n        $lh = $this->_lock();\n        $val = $this->get();\n        if (!is_array($val)) $val = array();\n        if( C('DATA_CACHE_COMPRESS') && function_exists('gzcompress')) {\n            //数据压缩\n            $value   =   gzcompress($value,3);\n        }\n        $name   =   $this->options['prefix'].$name;\n        $val[$name] = $value;\n        $val = serialize($val);\n        if($this->_write($val, $lh)) {\n            if($this->options['length']>0) {\n                // 记录缓存队列\n                $this->queue($name);\n            }\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * 删除缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @return boolean\n     */\n    public function rm($name) {\n        $lh = $this->_lock();\n        $val = $this->get();\n        if (!is_array($val)) $val = array();\n        $name   =   $this->options['prefix'].$name;\n        unset($val[$name]);\n        $val = serialize($val);\n        return $this->_write($val, $lh);\n    }\n\n    /**\n     * 生成IPC key\n     * @access private\n     * @param string $project 项目标识名\n     * @return integer\n     */\n    private function _ftok($project) {\n        if (function_exists('ftok'))   return ftok(__FILE__, $project);\n        if(strtoupper(PHP_OS) == 'WINNT'){\n            $s = stat(__FILE__);\n            return sprintf(\"%u\", (($s['ino'] & 0xffff) | (($s['dev'] & 0xff) << 16) |\n            (($project & 0xff) << 24)));\n        }else {\n            $filename = __FILE__ . (string) $project;\n            for($key = array(); sizeof($key) < strlen($filename); $key[] = ord(substr($filename, sizeof($key), 1)));\n            return dechex(array_sum($key));\n        }\n    }\n\n    /**\n     * 写入操作\n     * @access private\n     * @param string $name 缓存变量名\n     * @return integer|boolean\n     */\n    private function _write(&$val, &$lh) {\n        $id  = shmop_open($this->handler, 'c', 0600, $this->options['size']);\n        if ($id) {\n           $ret = shmop_write($id, $val, 0) == strlen($val);\n           shmop_close($id);\n           $this->_unlock($lh);\n           return $ret;\n        }\n        $this->_unlock($lh);\n        return false;\n    }\n\n    /**\n     * 共享锁定\n     * @access private\n     * @param string $name 缓存变量名\n     * @return boolean\n     */\n    private function _lock() {\n        if (function_exists('sem_get')) {\n            $fp = sem_get($this->handler, 1, 0600, 1);\n            sem_acquire ($fp);\n        } else {\n            $fp = fopen($this->options['temp'].$this->options['prefix'].md5($this->handler), 'w');\n            flock($fp, LOCK_EX);\n        }\n        return $fp;\n    }\n\n    /**\n     * 解除共享锁定\n     * @access private\n     * @param string $name 缓存变量名\n     * @return boolean\n     */\n    private function _unlock(&$fp) {\n        if (function_exists('sem_release')) {\n            sem_release($fp);\n        } else {\n            fclose($fp);\n        }\n    }\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Cache/Driver/Sqlite.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\nnamespace Think\\Cache\\Driver;\nuse Think\\Cache;\ndefined('THINK_PATH') or exit();\n/**\n * Sqlite缓存驱动\n */\nclass Sqlite extends Cache {\n\n    /**\n     * 架构函数\n     * @param array $options 缓存参数\n     * @access public\n     */\n    public function __construct($options=array()) {\n        if ( !extension_loaded('sqlite') ) {\n            E(L('_NOT_SUPPORT_').':sqlite');\n        }\n        if(empty($options)) {\n            $options = array (\n                'db'        =>  ':memory:',\n                'table'     =>  'sharedmemory',\n            );\n        }\n        $this->options  =   $options;      \n        $this->options['prefix']    =   isset($options['prefix'])?  $options['prefix']  :   C('DATA_CACHE_PREFIX');\n        $this->options['length']    =   isset($options['length'])?  $options['length']  :   0;        \n        $this->options['expire']    =   isset($options['expire'])?  $options['expire']  :   C('DATA_CACHE_TIME');\n        \n        $func = $this->options['persistent'] ? 'sqlite_popen' : 'sqlite_open';\n        $this->handler      = $func($this->options['db']);\n    }\n\n    /**\n     * 读取缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @return mixed\n     */\n    public function get($name) {\n        N('cache_read',1);\n\t\t$name   = $this->options['prefix'].sqlite_escape_string($name);\n        $sql    = 'SELECT value FROM '.$this->options['table'].' WHERE var=\\''.$name.'\\' AND (expire=0 OR expire >'.time().') LIMIT 1';\n        $result = sqlite_query($this->handler, $sql);\n        if (sqlite_num_rows($result)) {\n            $content   =  sqlite_fetch_single($result);\n            if(C('DATA_CACHE_COMPRESS') && function_exists('gzcompress')) {\n                //启用数据压缩\n                $content   =   gzuncompress($content);\n            }\n            return unserialize($content);\n        }\n        return false;\n    }\n\n    /**\n     * 写入缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @param mixed $value  存储数据\n     * @param integer $expire  有效时间（秒）\n     * @return boolean\n     */\n    public function set($name, $value,$expire=null) {\n        N('cache_write',1);\n        $name  = $this->options['prefix'].sqlite_escape_string($name);\n        $value = sqlite_escape_string(serialize($value));\n        if(is_null($expire)) {\n            $expire  =  $this->options['expire'];\n        }\n        $expire\t=\t($expire==0)?0: (time()+$expire) ;//缓存有效期为0表示永久缓存\n        if( C('DATA_CACHE_COMPRESS') && function_exists('gzcompress')) {\n            //数据压缩\n            $value   =   gzcompress($value,3);\n        }\n        $sql  = 'REPLACE INTO '.$this->options['table'].' (var, value,expire) VALUES (\\''.$name.'\\', \\''.$value.'\\', \\''.$expire.'\\')';\n        if(sqlite_query($this->handler, $sql)){\n            if($this->options['length']>0) {\n                // 记录缓存队列\n                $this->queue($name);\n            }\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * 删除缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @return boolean\n     */\n    public function rm($name) {\n        $name  = $this->options['prefix'].sqlite_escape_string($name);\n        $sql  = 'DELETE FROM '.$this->options['table'].' WHERE var=\\''.$name.'\\'';\n        sqlite_query($this->handler, $sql);\n        return true;\n    }\n\n    /**\n     * 清除缓存\n     * @access public\n     * @return boolean\n     */\n    public function clear() {\n        $sql  = 'DELETE FROM '.$this->options['table'];\n        sqlite_query($this->handler, $sql);\n        return ;\n    }\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Cache/Driver/Wincache.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\nnamespace Think\\Cache\\Driver;\nuse Think\\Cache;\ndefined('THINK_PATH') or exit();\n/**\n * Wincache缓存驱动\n */\nclass Wincache extends Cache {\n\n    /**\n     * 架构函数\n     * @param array $options 缓存参数\n     * @access public\n     */\n    public function __construct($options=array()) {\n        if ( !function_exists('wincache_ucache_info') ) {\n            E(L('_NOT_SUPPORT_').':WinCache');\n        }\n        $this->options['expire']    =   isset($options['expire'])?  $options['expire']  :   C('DATA_CACHE_TIME');\n        $this->options['prefix']    =   isset($options['prefix'])?  $options['prefix']  :   C('DATA_CACHE_PREFIX');\n        $this->options['length']    =   isset($options['length'])?  $options['length']  :   0;\n    }\n\n    /**\n     * 读取缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @return mixed\n     */\n    public function get($name) {\n        N('cache_read',1);\n        $name   =   $this->options['prefix'].$name;\n        return wincache_ucache_exists($name)? wincache_ucache_get($name) : false;\n    }\n\n    /**\n     * 写入缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @param mixed $value  存储数据\n     * @param integer $expire  有效时间（秒）\n     * @return boolean\n     */\n    public function set($name, $value,$expire=null) {\n        N('cache_write',1);\n        if(is_null($expire)) {\n            $expire  =  $this->options['expire'];\n        }\n        $name   =   $this->options['prefix'].$name;\n        if(wincache_ucache_set($name, $value, $expire)) {\n            if($this->options['length']>0) {\n                // 记录缓存队列\n                $this->queue($name);\n            }\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * 删除缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @return boolean\n     */\n    public function rm($name) {\n        return wincache_ucache_delete($this->options['prefix'].$name);\n    }\n\n    /**\n     * 清除缓存\n     * @access public\n     * @return boolean\n     */\n    public function clear() {\n        return wincache_ucache_clear();\n    }    \n\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Cache/Driver/Xcache.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\nnamespace Think\\Cache\\Driver;\nuse Think\\Cache;\ndefined('THINK_PATH') or exit();\n/**\n * Xcache缓存驱动\n */\nclass Xcache extends Cache {\n\n    /**\n     * 架构函数\n     * @param array $options 缓存参数\n     * @access public\n     */\n    public function __construct($options=array()) {\n        if ( !function_exists('xcache_info') ) {\n            E(L('_NOT_SUPPORT_').':Xcache');\n        }\n        $this->options['expire']    =   isset($options['expire'])?$options['expire']:C('DATA_CACHE_TIME');\n        $this->options['prefix']    =   isset($options['prefix'])?$options['prefix']:C('DATA_CACHE_PREFIX');\n        $this->options['length']    =   isset($options['length'])?$options['length']:0;\n    }\n\n    /**\n     * 读取缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @return mixed\n     */\n    public function get($name) {\n        N('cache_read',1);\n        $name   =   $this->options['prefix'].$name;\n        if (xcache_isset($name)) {\n            return xcache_get($name);\n        }\n        return false;\n    }\n\n    /**\n     * 写入缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @param mixed $value  存储数据\n     * @param integer $expire  有效时间（秒）\n     * @return boolean\n     */\n    public function set($name, $value,$expire=null) {\n        N('cache_write',1);\n        if(is_null($expire)) {\n            $expire = $this->options['expire'] ;\n        }\n        $name   =   $this->options['prefix'].$name;\n        if(xcache_set($name, $value, $expire)) {\n            if($this->options['length']>0) {\n                // 记录缓存队列\n                $this->queue($name);\n            }\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * 删除缓存\n     * @access public\n     * @param string $name 缓存变量名\n     * @return boolean\n     */\n    public function rm($name) {\n        return xcache_unset($this->options['prefix'].$name);\n    }\n\n    /**\n     * 清除缓存\n     * @access public\n     * @return boolean\n     */\n    public function clear() {\n        return xcache_clear_cache(1, -1);\n    }\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Cache.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\nnamespace Think;\n/**\n * 缓存管理类\n */\nclass Cache {\n\n    /**\n     * 操作句柄\n     * @var string\n     * @access protected\n     */\n    protected $handler    ;\n\n    /**\n     * 缓存连接参数\n     * @var integer\n     * @access protected\n     */\n    protected $options = array();\n\n    /**\n     * 连接缓存\n     * @access public\n     * @param string $type 缓存类型\n     * @param array $options  配置数组\n     * @return object\n     */\n    public function connect($type='',$options=array()) {\n        if(empty($type))  $type = C('DATA_CACHE_TYPE');\n        $class  =   strpos($type,'\\\\')? $type : 'Think\\\\Cache\\\\Driver\\\\'.ucwords(strtolower($type));            \n        if(class_exists($class))\n            $cache = new $class($options);\n        else\n            E(L('_CACHE_TYPE_INVALID_').':'.$type);\n        return $cache;\n    }\n\n    /**\n     * 取得缓存类实例\n     * @static\n     * @access public\n     * @return mixed\n     */\n    static function getInstance($type='',$options=array()) {\n\t\tstatic $_instance\t=\tarray();\n\t\t$guid\t=\t$type.to_guid_string($options);\n\t\tif(!isset($_instance[$guid])){\n\t\t\t$obj\t=\tnew Cache();\n\t\t\t$_instance[$guid]\t=\t$obj->connect($type,$options);\n\t\t}\n\t\treturn $_instance[$guid];\n    }\n\n    public function __get($name) {\n        return $this->get($name);\n    }\n\n    public function __set($name,$value) {\n        return $this->set($name,$value);\n    }\n\n    public function __unset($name) {\n        $this->rm($name);\n    }\n    public function setOptions($name,$value) {\n        $this->options[$name]   =   $value;\n    }\n\n    public function getOptions($name) {\n        return $this->options[$name];\n    }\n\n    /**\n     * 队列缓存\n     * @access protected\n     * @param string $key 队列名\n     * @return mixed\n     */\n    // \n    protected function queue($key) {\n        static $_handler = array(\n            'file'  =>  array('F','F'),\n            'xcache'=>  array('xcache_get','xcache_set'),\n            'apc'   =>  array('apc_fetch','apc_store'),\n        );\n        $queue      =   isset($this->options['queue'])?$this->options['queue']:'file';\n        $fun        =   isset($_handler[$queue])?$_handler[$queue]:$_handler['file'];\n        $queue_name =   isset($this->options['queue_name'])?$this->options['queue_name']:'think_queue';\n        $value      =   $fun[0]($queue_name);\n        if(!$value) {\n            $value  =   array();\n        }\n        // 进列\n        if(false===array_search($key, $value))  array_push($value,$key);\n        if(count($value) > $this->options['length']) {\n            // 出列\n            $key =  array_shift($value);\n            // 删除缓存\n            $this->rm($key);\n             if(APP_DEBUG){\n                //调试模式下，记录出列次数\n                N($queue_name.'_out_times',1);\n            }\n        }\n        return $fun[1]($queue_name,$value);\n    }\n    \n    public function __call($method,$args){\n        //调用缓存类型自己的方法\n        if(method_exists($this->handler, $method)){\n           return call_user_func_array(array($this->handler,$method), $args);\n        }else{\n            E(__CLASS__.':'.$method.L('_METHOD_NOT_EXIST_'));\n            return;\n        }\n    }\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Controller.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\nnamespace Think;\n/**\n * ThinkPHP 控制器基类 抽象类\n */\nabstract class Controller {\n\n    /**\n     * 视图实例对象\n     * @var view\n     * @access protected\n     */    \n    protected $view     =  null;\n\n    /**\n     * 控制器参数\n     * @var config\n     * @access protected\n     */      \n    protected $config   =   array();\n\n   /**\n     * 架构函数 取得模板对象实例\n     * @access public\n     */\n    public function __construct() {\n        Hook::listen('action_begin',$this->config);\n        //实例化视图类\n        $this->view     = Think::instance('Think\\View');\n        //控制器初始化\n        if(method_exists($this,'_initialize'))\n            $this->_initialize();\n    }\n\n    /**\n     * 模板显示 调用内置的模板引擎显示方法，\n     * @access protected\n     * @param string $templateFile 指定要调用的模板文件\n     * 默认为空 由系统自动定位模板文件\n     * @param string $charset 输出编码\n     * @param string $contentType 输出类型\n     * @param string $content 输出内容\n     * @param string $prefix 模板缓存前缀\n     * @return void\n     */\n    protected function display($templateFile='',$charset='',$contentType='',$content='',$prefix='') {\n        $this->view->display($templateFile,$charset,$contentType,$content,$prefix);\n    }\n\n    /**\n     * 输出内容文本可以包括Html 并支持内容解析\n     * @access protected\n     * @param string $content 输出内容\n     * @param string $charset 模板输出字符集\n     * @param string $contentType 输出类型\n     * @param string $prefix 模板缓存前缀\n     * @return mixed\n     */\n    protected function show($content,$charset='',$contentType='',$prefix='') {\n        $this->view->display('',$charset,$contentType,$content,$prefix);\n    }\n\n    /**\n     *  获取输出页面内容\n     * 调用内置的模板引擎fetch方法，\n     * @access protected\n     * @param string $templateFile 指定要调用的模板文件\n     * 默认为空 由系统自动定位模板文件\n     * @param string $content 模板输出内容\n     * @param string $prefix 模板缓存前缀* \n     * @return string\n     */\n    protected function fetch($templateFile='',$content='',$prefix='') {\n        return $this->view->fetch($templateFile,$content,$prefix);\n    }\n\n    /**\n     *  创建静态页面\n     * @access protected\n     * @htmlfile 生成的静态文件名称\n     * @htmlpath 生成的静态文件路径\n     * @param string $templateFile 指定要调用的模板文件\n     * 默认为空 由系统自动定位模板文件\n     * @return string\n     */\n    protected function buildHtml($htmlfile='',$htmlpath='',$templateFile='') {\n        $content    =   $this->fetch($templateFile);\n        $htmlpath   =   !empty($htmlpath)?$htmlpath:HTML_PATH;\n        $htmlfile   =   $htmlpath.$htmlfile.C('HTML_FILE_SUFFIX');\n        Storage::put($htmlfile,$content,'html');\n        return $content;\n    }\n\n    /**\n     * 模板主题设置\n     * @access protected\n     * @param string $theme 模版主题\n     * @return Action\n     */\n    protected function theme($theme){\n        $this->view->theme($theme);\n        return $this;\n    }\n\n    /**\n     * 模板变量赋值\n     * @access protected\n     * @param mixed $name 要显示的模板变量\n     * @param mixed $value 变量的值\n     * @return Action\n     */\n    protected function assign($name,$value='') {\n        $this->view->assign($name,$value);\n        return $this;\n    }\n\n    public function __set($name,$value) {\n        $this->assign($name,$value);\n    }\n\n    /**\n     * 取得模板显示变量的值\n     * @access protected\n     * @param string $name 模板显示变量\n     * @return mixed\n     */\n    public function get($name='') {\n        return $this->view->get($name);      \n    }\n\n    public function __get($name) {\n        return $this->get($name);\n    }\n\n    /**\n     * 检测模板变量的值\n     * @access public\n     * @param string $name 名称\n     * @return boolean\n     */\n    public function __isset($name) {\n        return $this->get($name);\n    }\n\n    /**\n     * 魔术方法 有不存在的操作的时候执行\n     * @access public\n     * @param string $method 方法名\n     * @param array $args 参数\n     * @return mixed\n     */\n    public function __call($method,$args) {\n        if( 0 === strcasecmp($method,ACTION_NAME.C('ACTION_SUFFIX'))) {\n            if(method_exists($this,'_empty')) {\n                // 如果定义了_empty操作 则调用\n                $this->_empty($method,$args);\n            }elseif(file_exists_case($this->view->parseTemplate())){\n                // 检查是否存在默认模版 如果有直接输出模版\n                $this->display();\n            }else{\n                E(L('_ERROR_ACTION_').':'.ACTION_NAME);\n            }\n        }else{\n            E(__CLASS__.':'.$method.L('_METHOD_NOT_EXIST_'));\n            return;\n        }\n    }\n\n    /**\n     * 操作错误跳转的快捷方法\n     * @access protected\n     * @param string $message 错误信息\n     * @param string $jumpUrl 页面跳转地址\n     * @param mixed $ajax 是否为Ajax方式 当数字时指定跳转时间\n     * @return void\n     */\n    protected function error($message='',$jumpUrl='',$ajax=false) {\n        $this->dispatchJump($message,0,$jumpUrl,$ajax);\n    }\n\n    /**\n     * 操作成功跳转的快捷方法\n     * @access protected\n     * @param string $message 提示信息\n     * @param string $jumpUrl 页面跳转地址\n     * @param mixed $ajax 是否为Ajax方式 当数字时指定跳转时间\n     * @return void\n     */\n    protected function success($message='',$jumpUrl='',$ajax=false) {\n        $this->dispatchJump($message,1,$jumpUrl,$ajax);\n    }\n\n    /**\n     * Ajax方式返回数据到客户端\n     * @access protected\n     * @param mixed $data 要返回的数据\n     * @param String $type AJAX返回数据格式\n     * @param int $json_option 传递给json_encode的option参数\n     * @return void\n     */\n    protected function ajaxReturn($data,$type='',$json_option=0) {\n        if(empty($type)) $type  =   C('DEFAULT_AJAX_RETURN');\n        switch (strtoupper($type)){\n            case 'JSON' :\n                // 返回JSON数据格式到客户端 包含状态信息\n                header('Content-Type:application/json; charset=utf-8');\n                exit(json_encode($data,$json_option));\n            case 'XML'  :\n                // 返回xml格式数据\n                header('Content-Type:text/xml; charset=utf-8');\n                exit(xml_encode($data));\n            case 'JSONP':\n                // 返回JSON数据格式到客户端 包含状态信息\n                header('Content-Type:application/json; charset=utf-8');\n                $handler  =   isset($_GET[C('VAR_JSONP_HANDLER')]) ? $_GET[C('VAR_JSONP_HANDLER')] : C('DEFAULT_JSONP_HANDLER');\n                exit($handler.'('.json_encode($data,$json_option).');');  \n            case 'EVAL' :\n                // 返回可执行的js脚本\n                header('Content-Type:text/html; charset=utf-8');\n                exit($data);            \n            default     :\n                // 用于扩展其他返回格式数据\n                Hook::listen('ajax_return',$data);\n        }\n    }\n\n    /**\n     * Action跳转(URL重定向） 支持指定模块和延时跳转\n     * @access protected\n     * @param string $url 跳转的URL表达式\n     * @param array $params 其它URL参数\n     * @param integer $delay 延时跳转的时间 单位为秒\n     * @param string $msg 跳转提示信息\n     * @return void\n     */\n    protected function redirect($url,$params=array(),$delay=0,$msg='') {\n        $url    =   U($url,$params);\n        redirect($url,$delay,$msg);\n    }\n\n    /**\n     * 默认跳转操作 支持错误导向和正确跳转\n     * 调用模板显示 默认为public目录下面的success页面\n     * 提示页面为可配置 支持模板标签\n     * @param string $message 提示信息\n     * @param Boolean $status 状态\n     * @param string $jumpUrl 页面跳转地址\n     * @param mixed $ajax 是否为Ajax方式 当数字时指定跳转时间\n     * @access private\n     * @return void\n     */\n    private function dispatchJump($message,$status=1,$jumpUrl='',$ajax=false) {\n        if(true === $ajax || IS_AJAX) {// AJAX提交\n            $data           =   is_array($ajax)?$ajax:array();\n            $data['info']   =   $message;\n            $data['status'] =   $status;\n            $data['url']    =   $jumpUrl;\n            $this->ajaxReturn($data);\n        }\n        if(is_int($ajax)) $this->assign('waitSecond',$ajax);\n        if(!empty($jumpUrl)) $this->assign('jumpUrl',$jumpUrl);\n        // 提示标题\n        $this->assign('msgTitle',$status? L('_OPERATION_SUCCESS_') : L('_OPERATION_FAIL_'));\n        //如果设置了关闭窗口，则提示完毕后自动关闭窗口\n        if($this->get('closeWin'))    $this->assign('jumpUrl','javascript:window.close();');\n        $this->assign('status',$status);   // 状态\n        //保证输出不受静态缓存影响\n        C('HTML_CACHE_ON',false);\n        if($status) { //发送成功信息\n            $this->assign('message',$message);// 提示信息\n            // 成功操作后默认停留1秒\n            if(!isset($this->waitSecond))    $this->assign('waitSecond','1');\n            // 默认操作成功自动返回操作前页面\n            if(!isset($this->jumpUrl)) $this->assign(\"jumpUrl\",$_SERVER[\"HTTP_REFERER\"]);\n            $this->display(C('TMPL_ACTION_SUCCESS'));\n        }else{\n            $this->assign('error',$message);// 提示信息\n            //发生错误时候默认停留3秒\n            if(!isset($this->waitSecond))    $this->assign('waitSecond','3');\n            // 默认发生错误的话自动返回上页\n            if(!isset($this->jumpUrl)) $this->assign('jumpUrl',\"javascript:history.back(-1);\");\n            $this->display(C('TMPL_ACTION_ERROR'));\n            // 中止执行  避免出错后继续执行\n            exit ;\n        }\n    }\n\n   /**\n     * 析构方法\n     * @access public\n     */\n    public function __destruct() {\n        // 执行后续操作\n        Hook::listen('action_end');\n    }\n}\n// 设置控制器别名 便于升级\nclass_alias('Think\\Controller','Think\\Action');\n"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Db/Driver/Firebird.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\nnamespace Think\\Db\\Driver;\n\nuse Think\\Db\\Driver;\n\n/**\n * Firebird数据库驱动\n */\nclass Firebird extends Driver\n{\n    protected $selectSql = 'SELECT %LIMIT% %DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%';\n\n    /**\n     * 解析pdo连接的dsn信息\n     * @access public\n     * @param array $config 连接信息\n     * @return string\n     */\n    protected function parseDsn($config)\n    {\n        $dsn = 'firebird:dbname=' . $config['hostname'] . '/' . ($config['hostport'] ?: 3050) . ':' . $config['database'];\n        return $dsn;\n    }\n\n    /**\n     * 执行语句\n     * @access public\n     * @param string $str  sql指令\n     * @param boolean $fetchSql  不执行只是获取SQL\n     * @return mixed\n     */\n    public function execute($str, $fetchSql = false)\n    {\n        $this->initConnect(true);\n        if (!$this->_linkID) {\n            return false;\n        }\n\n        $this->queryStr = $str;\n        if (!empty($this->bind)) {\n            $that           = $this;\n            $this->queryStr = strtr($this->queryStr, array_map(function ($val) use ($that) {return '\\'' . $that->escapeString($val) . '\\'';}, $this->bind));\n        }\n        if ($fetchSql) {\n            return $this->queryStr;\n        }\n        //释放前次的查询结果\n        if (!empty($this->PDOStatement)) {\n            $this->free();\n        }\n\n        $this->executeTimes++;\n        N('db_write', 1); // 兼容代码\n        // 记录开始执行时间\n        $this->debug(true);\n        $this->PDOStatement = $this->_linkID->prepare($str);\n        if (false === $this->PDOStatement) {\n            E($this->error());\n        }\n        foreach ($this->bind as $key => $val) {\n            if (is_array($val)) {\n                $this->PDOStatement->bindValue($key, $val[0], $val[1]);\n            } else {\n                $this->PDOStatement->bindValue($key, $val);\n            }\n        }\n        $this->bind = array();\n        $result     = $this->PDOStatement->execute();\n        $this->debug(false);\n        if (false === $result) {\n            $this->error();\n            return false;\n        } else {\n            $this->numRows = $this->PDOStatement->rowCount();\n            return $this->numRows;\n        }\n    }\n\n    /**\n     * 取得数据表的字段信息\n     * @access public\n     */\n    public function getFields($tableName)\n    {\n        $this->initConnect(true);\n        list($tableName) = explode(' ', $tableName);\n        $sql             = 'SELECT RF.RDB$FIELD_NAME AS FIELD,RF.RDB$DEFAULT_VALUE AS DEFAULT1,RF.RDB$NULL_FLAG AS NULL1,TRIM(T.RDB$TYPE_NAME) || \\'(\\' || F.RDB$FIELD_LENGTH || \\')\\' as TYPE FROM RDB$RELATION_FIELDS RF LEFT JOIN RDB$FIELDS F ON (F.RDB$FIELD_NAME = RF.RDB$FIELD_SOURCE) LEFT JOIN RDB$TYPES T ON (T.RDB$TYPE = F.RDB$FIELD_TYPE) WHERE RDB$RELATION_NAME=UPPER(\\'' . $tableName . '\\') AND T.RDB$FIELD_NAME = \\'RDB$FIELD_TYPE\\' ORDER By RDB$FIELD_POSITION';\n        $result          = $this->query($sql);\n        $info            = array();\n        if ($result) {\n            foreach ($result as $key => $val) {\n                $info[trim($val['field'])] = array(\n                    'name'    => trim($val['field']),\n                    'type'    => $val['type'],\n                    'notnull' => (bool) (1 == $val['null1']), // 1表示不为Null\n                    'default' => $val['default1'],\n                    'primary' => false,\n                    'autoinc' => false,\n                );\n            }\n        }\n        //获取主键\n        $sql     = 'select b.rdb$field_name as field_name from rdb$relation_constraints a join rdb$index_segments b on a.rdb$index_name=b.rdb$index_name where a.rdb$constraint_type=\\'PRIMARY KEY\\' and a.rdb$relation_name=UPPER(\\'' . $tableName . '\\')';\n        $rs_temp = $this->query($sql);\n        foreach ($rs_temp as $row) {\n            $info[trim($row['field_name'])]['primary'] = true;\n        }\n        return $info;\n    }\n\n    /**\n     * 取得数据库的表信息\n     * @access public\n     */\n    public function getTables($dbName = '')\n    {\n        $sql    = 'SELECT DISTINCT RDB$RELATION_NAME FROM RDB$RELATION_FIELDS WHERE RDB$SYSTEM_FLAG=0';\n        $result = $this->query($sql);\n        $info   = array();\n        foreach ($result as $key => $val) {\n            $info[$key] = trim(current($val));\n        }\n        return $info;\n    }\n\n    /**\n     * SQL指令安全过滤\n     * @access public\n     * @param string $str  SQL指令\n     * @return string\n     */\n    public function escapeString($str)\n    {\n        return str_replace(\"'\", \"''\", $str);\n    }\n\n    /**\n     * limit\n     * @access public\n     * @param $limit limit表达式\n     * @return string\n     */\n    public function parseLimit($limit)\n    {\n        $limitStr = '';\n        if (!empty($limit)) {\n            $limit = explode(',', $limit);\n            if (count($limit) > 1) {\n                $limitStr = ' FIRST ' . $limit[1] . ' SKIP ' . $limit[0] . ' ';\n            } else {\n                $limitStr = ' FIRST ' . $limit[0] . ' ';\n            }\n        }\n        return $limitStr;\n    }\n\n    /**\n     * 随机排序\n     * @access protected\n     * @return string\n     */\n    protected function parseRand()\n    {\n        return 'rand()';\n    }\n\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Db/Driver/Mongo.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace Think\\Db\\Driver;\n\nuse Think\\Db\\Driver;\n\n/**\n * Mongo数据库驱动\n */\nclass Mongo extends Driver\n{\n\n    protected $_mongo          = null; // MongoDb Object\n    protected $_collection     = null; // MongoCollection Object\n    protected $_dbName         = ''; // dbName\n    protected $_collectionName = ''; // collectionName\n    protected $_cursor         = null; // MongoCursor Object\n    protected $comparison      = array('neq' => 'ne', 'ne' => 'ne', 'gt' => 'gt', 'egt' => 'gte', 'gte' => 'gte', 'lt' => 'lt', 'elt' => 'lte', 'lte' => 'lte', 'in' => 'in', 'not in' => 'nin', 'nin' => 'nin');\n\n    /**\n     * 架构函数 读取数据库配置信息\n     * @access public\n     * @param array $config 数据库配置数组\n     */\n    public function __construct($config = '')\n    {\n        if (!class_exists('mongoClient')) {\n            E(L('_NOT_SUPPORT_') . ':Mongo');\n        }\n        if (!empty($config)) {\n            $this->config = array_merge($this->config, $config);\n            if (empty($this->config['params'])) {\n                $this->config['params'] = array();\n            }\n        }\n    }\n\n    /**\n     * 连接数据库方法\n     * @access public\n     */\n    public function connect($config = '', $linkNum = 0)\n    {\n        if (!isset($this->linkID[$linkNum])) {\n            if (empty($config)) {\n                $config = $this->config;\n            }\n\n            $host = 'mongodb://' . ($config['username'] ? \"{$config['username']}\" : '') . ($config['password'] ? \":{$config['password']}@\" : '') . $config['hostname'] . ($config['hostport'] ? \":{$config['hostport']}\" : '') . '/' . ($config['database'] ? \"{$config['database']}\" : '');\n            try {\n                $this->linkID[$linkNum] = new \\mongoClient($host, $this->config['params']);\n            } catch (\\MongoConnectionException $e) {\n                E($e->getmessage());\n            }\n        }\n        return $this->linkID[$linkNum];\n    }\n\n    /**\n     * 切换当前操作的Db和Collection\n     * @access public\n     * @param string $collection  collection\n     * @param string $db  db\n     * @param boolean $master 是否主服务器\n     * @return void\n     */\n    public function switchCollection($collection, $db = '', $master = true)\n    {\n        // 当前没有连接 则首先进行数据库连接\n        if (!$this->_linkID) {\n            $this->initConnect($master);\n        }\n\n        try {\n            if (!empty($db)) {\n                // 传人Db则切换数据库\n                // 当前MongoDb对象\n                $this->_dbName = $db;\n                $this->_mongo  = $this->_linkID->selectDb($db);\n            }\n            // 当前MongoCollection对象\n            if ($this->config['debug']) {\n                $this->queryStr = $this->_dbName . '.getCollection(' . $collection . ')';\n            }\n            if ($this->_collectionName != $collection) {\n                $this->queryTimes++;\n                N('db_query', 1); // 兼容代码\n                $this->debug(true);\n                $this->_collection = $this->_mongo->selectCollection($collection);\n                $this->debug(false);\n                $this->_collectionName = $collection; // 记录当前Collection名称\n            }\n        } catch (MongoException $e) {\n            E($e->getMessage());\n        }\n    }\n\n    /**\n     * 释放查询结果\n     * @access public\n     */\n    public function free()\n    {\n        $this->_cursor = null;\n    }\n\n    /**\n     * 执行命令\n     * @access public\n     * @param array $command  指令\n     * @return array\n     */\n    public function command($command = array(), $options = array())\n    {\n        $cache = isset($options['cache']) ? $options['cache'] : false;\n        if ($cache) {\n            // 查询缓存检测\n            $key   = is_string($cache['key']) ? $cache['key'] : md5(serialize($command));\n            $value = S($key, '', '', $cache['type']);\n            if (false !== $value) {\n                return $value;\n            }\n        }\n        N('db_write', 1); // 兼容代码\n        $this->executeTimes++;\n        try {\n            if ($this->config['debug']) {\n                $this->queryStr = $this->_dbName . '.' . $this->_collectionName . '.runCommand(';\n                $this->queryStr .= json_encode($command);\n                $this->queryStr .= ')';\n            }\n            $this->debug(true);\n            $result = $this->_mongo->command($command);\n            $this->debug(false);\n\n            if ($cache && $result['ok']) {\n                // 查询缓存写入\n                S($key, $result, $cache['expire'], $cache['type']);\n            }\n            return $result;\n        } catch (\\MongoCursorException $e) {\n            E($e->getMessage());\n        }\n    }\n\n    /**\n     * 执行语句\n     * @access public\n     * @param string $code  sql指令\n     * @param array $args  参数\n     * @return mixed\n     */\n    public function execute($code, $args = array())\n    {\n        $this->executeTimes++;\n        N('db_write', 1); // 兼容代码\n        $this->debug(true);\n        $this->queryStr = 'execute:' . $code;\n        $result         = $this->_mongo->execute($code, $args);\n        $this->debug(false);\n        if ($result['ok']) {\n            return $result['retval'];\n        } else {\n            E($result['errmsg']);\n        }\n    }\n\n    /**\n     * 关闭数据库\n     * @access public\n     */\n    public function close()\n    {\n        if ($this->_linkID) {\n            $this->_linkID->close();\n            $this->_linkID     = null;\n            $this->_mongo      = null;\n            $this->_collection = null;\n            $this->_cursor     = null;\n        }\n    }\n\n    /**\n     * 数据库错误信息\n     * @access public\n     * @return string\n     */\n    public function error()\n    {\n        $this->error = $this->_mongo->lastError();\n        trace($this->error, '', 'ERR');\n        return $this->error;\n    }\n\n    /**\n     * 插入记录\n     * @access public\n     * @param mixed $data 数据\n     * @param array $options 参数表达式\n     * @param boolean $replace 是否replace\n     * @return false | integer\n     */\n    public function insert($data, $options = array(), $replace = false)\n    {\n        if (isset($options['table'])) {\n            $this->switchCollection($options['table']);\n        }\n        $this->model = $options['model'];\n        $this->executeTimes++;\n        N('db_write', 1); // 兼容代码\n        if ($this->config['debug']) {\n            $this->queryStr = $this->_dbName . '.' . $this->_collectionName . '.insert(';\n            $this->queryStr .= $data ? json_encode($data) : '{}';\n            $this->queryStr .= ')';\n        }\n        try {\n            $this->debug(true);\n            $result = $replace ? $this->_collection->save($data) : $this->_collection->insert($data);\n            $this->debug(false);\n            if ($result) {\n                $_id = $data['_id'];\n                if (is_object($_id)) {\n                    $_id = $_id->__toString();\n                }\n                $this->lastInsID = $_id;\n            }\n            return $result;\n        } catch (\\MongoCursorException $e) {\n            E($e->getMessage());\n        }\n    }\n\n    /**\n     * 插入多条记录\n     * @access public\n     * @param array $dataList 数据\n     * @param array $options 参数表达式\n     * @return bool\n     */\n    public function insertAll($dataList, $options = array())\n    {\n        if (isset($options['table'])) {\n            $this->switchCollection($options['table']);\n        }\n        $this->model = $options['model'];\n        $this->executeTimes++;\n        N('db_write', 1); // 兼容代码\n        try {\n            $this->debug(true);\n            $result = $this->_collection->batchInsert($dataList);\n            $this->debug(false);\n            return $result;\n        } catch (\\MongoCursorException $e) {\n            E($e->getMessage());\n        }\n    }\n\n    /**\n     * 生成下一条记录ID 用于自增非MongoId主键\n     * @access public\n     * @param string $pk 主键名\n     * @return integer\n     */\n    public function getMongoNextId($pk,$options=array())\n    {\n        if (isset($options['table'])) {\n            $this->switchCollection($options['table']);\n        }\n        if ($this->config['debug']) {\n            $this->queryStr = $this->_dbName . '.' . $this->_collectionName . '.find({},{' . $pk . ':1}).sort({' . $pk . ':-1}).limit(1)';\n        }\n        try {\n            $this->debug(true);\n            $result = $this->_collection->find(array(), array($pk => 1))->sort(array($pk => -1))->limit(1);\n            $this->debug(false);\n        } catch (\\MongoCursorException $e) {\n            E($e->getMessage());\n        }\n        $data = $result->getNext();\n        return isset($data[$pk]) ? $data[$pk] + 1 : 1;\n    }\n\n    /**\n     * 更新记录\n     * @access public\n     * @param mixed $data 数据\n     * @param array $options 表达式\n     * @return bool\n     */\n    public function update($data, $options)\n    {\n        if (isset($options['table'])) {\n            $this->switchCollection($options['table']);\n        }\n        $this->executeTimes++;\n        N('db_write', 1); // 兼容代码\n        $this->model = $options['model'];\n        $query       = $this->parseWhere(isset($options['where']) ? $options['where'] : array());\n        $set         = $this->parseSet($data);\n        if ($this->config['debug']) {\n            $this->queryStr = $this->_dbName . '.' . $this->_collectionName . '.update(';\n            $this->queryStr .= $query ? json_encode($query) : '{}';\n            $this->queryStr .= ',' . json_encode($set) . ')';\n        }\n        try {\n            $this->debug(true);\n            if (isset($options['limit']) && 1 == $options['limit']) {\n                $multiple = array(\"multiple\" => false);\n            } else {\n                $multiple = array(\"multiple\" => true);\n            }\n            $result = $this->_collection->update($query, $set, $multiple);\n            $this->debug(false);\n            return $result;\n        } catch (\\MongoCursorException $e) {\n            E($e->getMessage());\n        }\n    }\n\n    /**\n     * 删除记录\n     * @access public\n     * @param array $options 表达式\n     * @return false | integer\n     */\n    public function delete($options = array())\n    {\n        if (isset($options['table'])) {\n            $this->switchCollection($options['table']);\n        }\n        $query       = $this->parseWhere(isset($options['where']) ? $options['where'] : array());\n        $this->model = $options['model'];\n        $this->executeTimes++;\n        N('db_write', 1); // 兼容代码\n        if ($this->config['debug']) {\n            $this->queryStr = $this->_dbName . '.' . $this->_collectionName . '.remove(' . json_encode($query) . ')';\n        }\n        try {\n            $this->debug(true);\n            $result = $this->_collection->remove($query);\n            $this->debug(false);\n            return $result;\n        } catch (\\MongoCursorException $e) {\n            E($e->getMessage());\n        }\n    }\n\n    /**\n     * 清空记录\n     * @access public\n     * @param array $options 表达式\n     * @return false | integer\n     */\n    public function clear($options = array())\n    {\n        if (isset($options['table'])) {\n            $this->switchCollection($options['table']);\n        }\n        $this->model = $options['model'];\n        $this->executeTimes++;\n        N('db_write', 1); // 兼容代码\n        if ($this->config['debug']) {\n            $this->queryStr = $this->_dbName . '.' . $this->_collectionName . '.remove({})';\n        }\n        try {\n            $this->debug(true);\n            $result = $this->_collection->drop();\n            $this->debug(false);\n            return $result;\n        } catch (\\MongoCursorException $e) {\n            E($e->getMessage());\n        }\n    }\n\n    /**\n     * 查找记录\n     * @access public\n     * @param array $options 表达式\n     * @return iterator\n     */\n    public function select($options = array())\n    {\n        if (isset($options['table'])) {\n            $this->switchCollection($options['table'], '', false);\n        }\n        $this->model = $options['model'];\n        $this->queryTimes++;\n        N('db_query', 1); // 兼容代码\n        $query = $this->parseWhere(isset($options['where']) ? $options['where'] : array());\n        $field = $this->parseField(isset($options['field']) ? $options['field'] : array());\n        try {\n            if ($this->config['debug']) {\n                $this->queryStr = $this->_dbName . '.' . $this->_collectionName . '.find(';\n                $this->queryStr .= $query ? json_encode($query) : '{}';\n                if (is_array($field) && count($field)) {\n                    foreach ($field as $f => $v) {\n                        $_field_array[$f] = $v ? 1 : 0;\n                    }\n\n                    $this->queryStr .= $field ? ', ' . json_encode($_field_array) : ', {}';\n                }\n                $this->queryStr .= ')';\n            }\n            $this->debug(true);\n            $_cursor = $this->_collection->find($query, $field);\n            if (!empty($options['order'])) {\n                $order = $this->parseOrder($options['order']);\n                if ($this->config['debug']) {\n                    $this->queryStr .= '.sort(' . json_encode($order) . ')';\n                }\n                $_cursor = $_cursor->sort($order);\n            }\n            if (isset($options['page'])) {\n                // 根据页数计算limit\n                list($page, $length) = $options['page'];\n                $page                = $page > 0 ? $page : 1;\n                $length              = $length > 0 ? $length : (is_numeric($options['limit']) ? $options['limit'] : 20);\n                $offset              = $length * ((int) $page - 1);\n                $options['limit']    = $offset . ',' . $length;\n            }\n            if (isset($options['limit'])) {\n                list($offset, $length) = $this->parseLimit($options['limit']);\n                if (!empty($offset)) {\n                    if ($this->config['debug']) {\n                        $this->queryStr .= '.skip(' . intval($offset) . ')';\n                    }\n                    $_cursor = $_cursor->skip(intval($offset));\n                }\n                if ($this->config['debug']) {\n                    $this->queryStr .= '.limit(' . intval($length) . ')';\n                }\n                $_cursor = $_cursor->limit(intval($length));\n            }\n            $this->debug(false);\n            $this->_cursor = $_cursor;\n            $resultSet     = iterator_to_array($_cursor);\n            return $resultSet;\n        } catch (\\MongoCursorException $e) {\n            E($e->getMessage());\n        }\n    }\n\n    /**\n     * 查找某个记录\n     * @access public\n     * @param array $options 表达式\n     * @return array\n     */\n    public function find($options = array())\n    {\n        $options['limit'] = 1;\n        $find             = $this->select($options);\n        return array_shift($find);\n    }\n\n    /**\n     * 统计记录数\n     * @access public\n     * @param array $options 表达式\n     * @return iterator\n     */\n    public function count($options = array())\n    {\n        if (isset($options['table'])) {\n            $this->switchCollection($options['table'], '', false);\n        }\n        $this->model = $options['model'];\n        $this->queryTimes++;\n        N('db_query', 1); // 兼容代码\n        $query = $this->parseWhere(isset($options['where']) ? $options['where'] : array());\n        if ($this->config['debug']) {\n            $this->queryStr = $this->_dbName . '.' . $this->_collectionName;\n            $this->queryStr .= $query ? '.find(' . json_encode($query) . ')' : '';\n            $this->queryStr .= '.count()';\n        }\n        try {\n            $this->debug(true);\n            $count = $this->_collection->count($query);\n            $this->debug(false);\n            return $count;\n        } catch (\\MongoCursorException $e) {\n            E($e->getMessage());\n        }\n    }\n\n    public function group($keys, $initial, $reduce, $options = array())\n    {\n        if (isset($options['table']) && $this->_collectionName != $options['table']) {\n            $this->switchCollection($options['table'], '', false);\n        }\n\n        $cache = isset($options['cache']) ? $options['cache'] : false;\n        if ($cache) {\n            $key   = is_string($cache['key']) ? $cache['key'] : md5(serialize($options));\n            $value = S($key, '', '', $cache['type']);\n            if (false !== $value) {\n                return $value;\n            }\n        }\n\n        $this->model = $options['model'];\n        $this->queryTimes++;\n        N('db_query', 1); // 兼容代码\n        $query = $this->parseWhere(isset($options['where']) ? $options['where'] : array());\n\n        if ($this->config['debug']) {\n            $this->queryStr = $this->_dbName . '.' . $this->_collectionName . '.group({key:' . json_encode($keys) . ',cond:' .\n            json_encode($options['condition']) . ',reduce:' .\n            json_encode($reduce) . ',initial:' .\n            json_encode($initial) . '})';\n        }\n        try {\n            $this->debug(true);\n            \n            $option = array();\n            isset($options['condition'])&&$option['condition']=$options['condition'];\n            isset($options['finalize'])&&$option['finalize']=$options['condition'];\n            isset($options['maxTimeMS'])&&$option['maxTimeMS']=$options['condition'];\n            $group = $this->_collection->group($keys,$initial,$reduce,$option); \n            $this->debug(false);\n\n            if ($cache && $group['ok']) {\n                S($key, $group, $cache['expire'], $cache['type']);\n            }\n\n            return $group;\n        } catch (\\MongoCursorException $e) {\n            E($e->getMessage());\n        }\n    }\n\n    /**\n     * 取得数据表的字段信息\n     * @access public\n     * @return array\n     */\n    public function getFields($collection = '')\n    {\n        if (!empty($collection) && $collection != $this->_collectionName) {\n            $this->switchCollection($collection, '', false);\n        }\n        $this->queryTimes++;\n        N('db_query', 1); // 兼容代码\n        if ($this->config['debug']) {\n            $this->queryStr = $this->_dbName . '.' . $this->_collectionName . '.findOne()';\n        }\n        try {\n            $this->debug(true);\n            $result = $this->_collection->findOne();\n            $this->debug(false);\n        } catch (\\MongoCursorException $e) {\n            E($e->getMessage());\n        }\n        if ($result) {\n            // 存在数据则分析字段\n            $info = array();\n            foreach ($result as $key => $val) {\n                $info[$key] = array(\n                    'name' => $key,\n                    'type' => getType($val),\n                );\n            }\n            return $info;\n        }\n        // 暂时没有数据 返回false\n        return false;\n    }\n\n    /**\n     * 取得当前数据库的collection信息\n     * @access public\n     */\n    public function getTables()\n    {\n        if ($this->config['debug']) {\n            $this->queryStr = $this->_dbName . '.getCollenctionNames()';\n        }\n        $this->queryTimes++;\n        N('db_query', 1); // 兼容代码\n        $this->debug(true);\n        $list = $this->_mongo->listCollections();\n        $this->debug(false);\n        $info = array();\n        foreach ($list as $collection) {\n            $info[] = $collection->getName();\n        }\n        return $info;\n    }\n\n    /**\n     * 取得当前数据库的对象\n     * @access public\n     * @return object mongoClient\n     */\n    public function getDB()\n    {\n        return $this->_mongo;\n    }\n\n    /**\n     * 取得当前集合的对象\n     * @access public\n     * @return object MongoCollection\n     */\n    public function getCollection()\n    {\n        return $this->_collection;\n    }\n\n    /**\n     * set分析\n     * @access protected\n     * @param array $data\n     * @return string\n     */\n    protected function parseSet($data)\n    {\n        $result = array();\n        foreach ($data as $key => $val) {\n            if (is_array($val)) {\n                switch ($val[0]) {\n                    case 'inc':\n                        $result['$inc'][$key] = (float) $val[1];\n                        break;\n                    case 'set':\n                    case 'unset':\n                    case 'push':\n                    case 'pushall':\n                    case 'addtoset':\n                    case 'pop':\n                    case 'pull':\n                    case 'pullall':\n                        $result['$' . $val[0]][$key] = $val[1];\n                        break;\n                    default:\n                        $result['$set'][$key] = $val;\n                }\n            } else {\n                $result['$set'][$key] = $val;\n            }\n        }\n        return $result;\n    }\n\n    /**\n     * order分析\n     * @access protected\n     * @param mixed $order\n     * @return array\n     */\n    protected function parseOrder($order)\n    {\n        if (is_string($order)) {\n            $array = explode(',', $order);\n            $order = array();\n            foreach ($array as $key => $val) {\n                $arr = explode(' ', trim($val));\n                if (isset($arr[1])) {\n                    $arr[1] = 'asc' == $arr[1] ? 1 : -1;\n                } else {\n                    $arr[1] = 1;\n                }\n                $order[$arr[0]] = $arr[1];\n            }\n        }\n        return $order;\n    }\n\n    /**\n     * limit分析\n     * @access protected\n     * @param mixed $limit\n     * @return array\n     */\n    protected function parseLimit($limit)\n    {\n        if (strpos($limit, ',')) {\n            $array = explode(',', $limit);\n        } else {\n            $array = array(0, $limit);\n        }\n        return $array;\n    }\n\n    /**\n     * field分析\n     * @access protected\n     * @param mixed $fields\n     * @return array\n     */\n    public function parseField($fields)\n    {\n        if (empty($fields)) {\n            $fields = array();\n        }\n        if (is_string($fields)) {\n            $_fields = explode(',', $fields);\n            $fields  = array();\n            foreach ($_fields as $f) {\n                $fields[$f] = true;\n            }\n\n        } elseif (is_array($fields)) {\n            $_fields = $fields;\n            $fields  = array();\n            foreach ($_fields as $f => $v) {\n                if (is_numeric($f)) {\n                    $fields[$v] = true;\n                } else {\n                    $fields[$f] = $v ? true : false;\n                }\n\n            }\n        }\n        return $fields;\n    }\n\n    /**\n     * where分析\n     * @access protected\n     * @param mixed $where\n     * @return array\n     */\n    public function parseWhere($where)\n    {\n        $query  = array();\n        $return = array();\n        $_logic = '$and';\n        if (isset($where['_logic'])) {\n            $where['_logic'] = strtolower($where['_logic']);\n            $_logic          = in_array($where['_logic'], array('or', 'xor', 'nor', 'and')) ? '$' . $where['_logic'] : $_logic;\n            unset($where['_logic']);\n        }\n        foreach ($where as $key => $val) {\n            if ('_id' != $key && 0 === strpos($key, '_')) {\n                // 解析特殊条件表达式\n                $parse = $this->parseThinkWhere($key, $val);\n                $query = array_merge($query, $parse);\n            } else {\n                // 查询字段的安全过滤\n                if (!preg_match('/^[A-Z_\\|\\&\\-.a-z0-9]+$/', trim($key))) {\n                    E(L('_ERROR_QUERY_') . ':' . $key);\n                }\n                $key = trim($key);\n                if (strpos($key, '|')) {\n                    $array = explode('|', $key);\n                    $str   = array();\n                    foreach ($array as $k) {\n                        $str[] = $this->parseWhereItem($k, $val);\n                    }\n                    $query['$or'] = $str;\n                } elseif (strpos($key, '&')) {\n                    $array = explode('&', $key);\n                    $str   = array();\n                    foreach ($array as $k) {\n                        $str[] = $this->parseWhereItem($k, $val);\n                    }\n                    $query = array_merge($query, $str);\n                } else {\n                    $str   = $this->parseWhereItem($key, $val);\n                    $query = array_merge($query, $str);\n                }\n            }\n        }\n        if ('$and' == $_logic) {\n            return $query;\n        }\n\n        foreach ($query as $key => $val) {\n            $return[$_logic][] = array($key => $val);\n        }\n\n        return $return;\n    }\n\n    /**\n     * 特殊条件分析\n     * @access protected\n     * @param string $key\n     * @param mixed $val\n     * @return string\n     */\n    protected function parseThinkWhere($key, $val)\n    {\n        $query  = array();\n        $_logic = array('or', 'xor', 'nor', 'and');\n\n        switch ($key) {\n            case '_query': // 字符串模式查询条件\n                parse_str($val, $query);\n                if (isset($query['_logic']) && strtolower($query['_logic']) == 'or') {\n                    unset($query['_logic']);\n                    $query['$or'] = $query;\n                }\n                break;\n            case '_complex': // 子查询模式查询条件\n                $__logic = strtolower($val['_logic']);\n                if (isset($val['_logic']) && in_array($__logic, $_logic)) {\n                    unset($val['_logic']);\n                    $query['$' . $__logic] = $val;\n                }\n                break;\n            case '_string': // MongoCode查询\n                $query['$where'] = new \\MongoCode($val);\n                break;\n        }\n        //兼容 MongoClient OR条件查询方法\n        if (isset($query['$or']) && !is_array(current($query['$or']))) {\n            $val = array();\n            foreach ($query['$or'] as $k => $v) {\n                $val[] = array($k => $v);\n            }\n\n            $query['$or'] = $val;\n        }\n        return $query;\n    }\n\n    /**\n     * where子单元分析\n     * @access protected\n     * @param string $key\n     * @param mixed $val\n     * @return array\n     */\n    protected function parseWhereItem($key, $val)\n    {\n        $query = array();\n        if (is_array($val)) {\n            if (is_string($val[0])) {\n                $con = strtolower($val[0]);\n                if (in_array($con, array('neq', 'ne', 'gt', 'egt', 'gte', 'lt', 'lte', 'elt'))) {\n                    // 比较运算\n                    $k           = '$' . $this->comparison[$con];\n                    $query[$key] = array($k => $val[1]);\n                } elseif ('like' == $con) {\n                    // 模糊查询 采用正则方式\n                    $query[$key] = new \\MongoRegex(\"/\" . $val[1] . \"/\");\n                } elseif ('mod' == $con) {\n                    // mod 查询\n                    $query[$key] = array('$mod' => $val[1]);\n                } elseif ('regex' == $con) {\n                    // 正则查询\n                    $query[$key] = new \\MongoRegex($val[1]);\n                } elseif (in_array($con, array('in', 'nin', 'not in'))) {\n                    // IN NIN 运算\n                    $data        = is_string($val[1]) ? explode(',', $val[1]) : $val[1];\n                    $k           = '$' . $this->comparison[$con];\n                    $query[$key] = array($k => $data);\n                } elseif ('all' == $con) {\n                    // 满足所有指定条件\n                    $data        = is_string($val[1]) ? explode(',', $val[1]) : $val[1];\n                    $query[$key] = array('$all' => $data);\n                } elseif ('between' == $con) {\n                    // BETWEEN运算\n                    $data        = is_string($val[1]) ? explode(',', $val[1]) : $val[1];\n                    $query[$key] = array('$gte' => $data[0], '$lte' => $data[1]);\n                } elseif ('not between' == $con) {\n                    $data        = is_string($val[1]) ? explode(',', $val[1]) : $val[1];\n                    $query[$key] = array('$lt' => $data[0], '$gt' => $data[1]);\n                } elseif ('exp' == $con) {\n                    // 表达式查询\n                    $query['$where'] = new \\MongoCode($val[1]);\n                } elseif ('exists' == $con) {\n                    // 字段是否存在\n                    $query[$key] = array('$exists' => (bool) $val[1]);\n                } elseif ('size' == $con) {\n                    // 限制属性大小\n                    $query[$key] = array('$size' => intval($val[1]));\n                } elseif ('type' == $con) {\n                    // 限制字段类型 1 浮点型 2 字符型 3 对象或者MongoDBRef 5 MongoBinData 7 MongoId 8 布尔型 9 MongoDate 10 NULL 15 MongoCode 16 32位整型 17 MongoTimestamp 18 MongoInt64 如果是数组的话判断元素的类型\n                    $query[$key] = array('$type' => intval($val[1]));\n                } else {\n                    $query[$key] = $val;\n                }\n                return $query;\n            }\n        }\n        $query[$key] = $val;\n        return $query;\n    }\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Db/Driver/Mysql.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace Think\\Db\\Driver;\n\nuse Think\\Db\\Driver;\n\n/**\n * mysql数据库驱动\n */\nclass Mysql extends Driver\n{\n\n    /**\n     * 解析pdo连接的dsn信息\n     * @access public\n     * @param array $config 连接信息\n     * @return string\n     */\n    protected function parseDsn($config)\n    {\n        $dsn = 'mysql:dbname=' . $config['database'] . ';host=' . $config['hostname'];\n        if (!empty($config['hostport'])) {\n            $dsn .= ';port=' . $config['hostport'];\n        } elseif (!empty($config['socket'])) {\n            $dsn .= ';unix_socket=' . $config['socket'];\n        }\n\n        if (!empty($config['charset'])) {\n            //为兼容各版本PHP,用两种方式设置编码\n            $this->options[\\PDO::MYSQL_ATTR_INIT_COMMAND] = 'SET NAMES ' . $config['charset'];\n            $dsn .= ';charset=' . $config['charset'];\n        }\n        return $dsn;\n    }\n\n    /**\n     * 取得数据表的字段信息\n     * @access public\n     */\n    public function getFields($tableName)\n    {\n        $this->initConnect(true);\n        list($tableName) = explode(' ', $tableName);\n        if (strpos($tableName, '.')) {\n            list($dbName, $tableName) = explode('.', $tableName);\n            $sql                      = 'SHOW COLUMNS FROM `' . $dbName . '`.`' . $tableName . '`';\n        } else {\n            $sql = 'SHOW COLUMNS FROM `' . $tableName . '`';\n        }\n\n        $result = $this->query($sql);\n        $info   = array();\n        if ($result) {\n            foreach ($result as $key => $val) {\n                if (\\PDO::CASE_LOWER != $this->_linkID->getAttribute(\\PDO::ATTR_CASE)) {\n                    $val = array_change_key_case($val, CASE_LOWER);\n                }\n                $info[$val['field']] = array(\n                    'name'    => $val['field'],\n                    'type'    => $val['type'],\n                    'notnull' => (bool) ('' === $val['null']), // not null is empty, null is yes\n                    'default' => $val['default'],\n                    'primary' => (strtolower($val['key']) == 'pri'),\n                    'autoinc' => (strtolower($val['extra']) == 'auto_increment'),\n                );\n            }\n        }\n        return $info;\n    }\n\n    /**\n     * 取得数据库的表信息\n     * @access public\n     */\n    public function getTables($dbName = '')\n    {\n        $sql    = !empty($dbName) ? 'SHOW TABLES FROM ' . $dbName : 'SHOW TABLES ';\n        $result = $this->query($sql);\n        $info   = array();\n        foreach ($result as $key => $val) {\n            $info[$key] = current($val);\n        }\n        return $info;\n    }\n\n    /**\n     * 字段和表名处理\n     * @access public\n     * @param string $key\n     * @param bool   $strict\n     * @return string\n     */\n    public function parseKey($key, $strict = false)\n    {\n        if (is_int($key)) {\n            return $key;\n        }\n\n        $key = trim($key);\n\n        if ($strict && !preg_match('/^[\\w\\.\\*]+$/', $key)) {\n            E('not support data:' . $key);\n        }\n\n        if ('*' != $key && !preg_match('/[,\\'\\\"\\*\\(\\)`.\\s]/', $key)) {\n            $key = '`' . $key . '`';\n        }\n        return $key;\n    }\n\n    /**\n     * 随机排序\n     * @access protected\n     * @return string\n     */\n    protected function parseRand()\n    {\n        return 'rand()';\n    }\n\n    /**\n     * 批量插入记录\n     * @access public\n     * @param mixed $dataSet 数据集\n     * @param array $options 参数表达式\n     * @param boolean $replace 是否replace\n     * @return false | integer\n     */\n    public function insertAll($dataSet, $options = array(), $replace = false)\n    {\n        $values      = array();\n        $this->model = $options['model'];\n        if (!is_array($dataSet[0])) {\n            return false;\n        }\n\n        $this->parseBind(!empty($options['bind']) ? $options['bind'] : array());\n        $fields = array_map(array($this, 'parseKey'), array_keys($dataSet[0]));\n        foreach ($dataSet as $data) {\n            $value = array();\n            foreach ($data as $key => $val) {\n                if (is_array($val) && 'exp' == $val[0]) {\n                    $value[] = $val[1];\n                } elseif (is_null($val)) {\n                    $value[] = 'NULL';\n                } elseif (is_scalar($val)) {\n                    if (0 === strpos($val, ':') && in_array($val, array_keys($this->bind))) {\n                        $value[] = $this->parseValue($val);\n                    } else {\n                        $name    = count($this->bind);\n                        $value[] = ':' . $name;\n                        $this->bindParam($name, $val);\n                    }\n                }\n            }\n            $values[] = '(' . implode(',', $value) . ')';\n        }\n        // 兼容数字传入方式\n        $replace = (is_numeric($replace) && $replace > 0) ? true : $replace;\n        $sql     = (true === $replace ? 'REPLACE' : 'INSERT') . ' INTO ' . $this->parseTable($options['table']) . ' (' . implode(',', $fields) . ') VALUES ' . implode(',', $values) . $this->parseDuplicate($replace);\n        $sql .= $this->parseComment(!empty($options['comment']) ? $options['comment'] : '');\n        return $this->execute($sql, !empty($options['fetch_sql']) ? true : false);\n    }\n\n    /**\n     * ON DUPLICATE KEY UPDATE 分析\n     * @access protected\n     * @param mixed $duplicate\n     * @return string\n     */\n    protected function parseDuplicate($duplicate)\n    {\n        // 布尔值或空则返回空字符串\n        if (is_bool($duplicate) || empty($duplicate)) {\n            return '';\n        }\n\n        if (is_string($duplicate)) {\n            // field1,field2 转数组\n            $duplicate = explode(',', $duplicate);\n        } elseif (is_object($duplicate)) {\n            // 对象转数组\n            $duplicate = get_class_vars($duplicate);\n        }\n        $updates = array();\n        foreach ((array) $duplicate as $key => $val) {\n            if (is_numeric($key)) {\n                // array('field1', 'field2', 'field3') 解析为 ON DUPLICATE KEY UPDATE field1=VALUES(field1), field2=VALUES(field2), field3=VALUES(field3)\n                $updates[] = $this->parseKey($val) . \"=VALUES(\" . $this->parseKey($val) . \")\";\n            } else {\n                if (is_scalar($val)) // 兼容标量传值方式\n                {\n                    $val = array('value', $val);\n                }\n\n                if (!isset($val[1]) && !is_null($val[1])) {\n                    continue;\n                }\n\n                switch ($val[0]) {\n                    case 'exp': // 表达式\n                        $updates[] = $this->parseKey($key) . \"=($val[1])\";\n                        break;\n                    case 'value': // 值\n                    default:\n                        $name      = count($this->bind);\n                        $updates[] = $this->parseKey($key) . \"=:\" . $name;\n                        $this->bindParam($name, $val[1]);\n                        break;\n                }\n            }\n        }\n        if (empty($updates)) {\n            return '';\n        }\n\n        return \" ON DUPLICATE KEY UPDATE \" . join(', ', $updates);\n    }\n\n    /**\n     * 执行存储过程查询 返回多个数据集\n     * @access public\n     * @param string $str  sql指令\n     * @param boolean $fetchSql  不执行只是获取SQL\n     * @return mixed\n     */\n    public function procedure($str, $fetchSql = false)\n    {\n        $this->initConnect(false);\n        $this->_linkID->setAttribute(\\PDO::ATTR_ERRMODE, \\PDO::ERRMODE_WARNING);\n        if (!$this->_linkID) {\n            return false;\n        }\n\n        $this->queryStr = $str;\n        if ($fetchSql) {\n            return $this->queryStr;\n        }\n        //释放前次的查询结果\n        if (!empty($this->PDOStatement)) {\n            $this->free();\n        }\n\n        $this->queryTimes++;\n        N('db_query', 1); // 兼容代码\n        // 调试开始\n        $this->debug(true);\n        $this->PDOStatement = $this->_linkID->prepare($str);\n        if (false === $this->PDOStatement) {\n            $this->error();\n            return false;\n        }\n        try {\n            $result = $this->PDOStatement->execute();\n            // 调试结束\n            $this->debug(false);\n            do {\n                $result = $this->PDOStatement->fetchAll(\\PDO::FETCH_ASSOC);\n                if ($result) {\n                    $resultArr[] = $result;\n                }\n            } while ($this->PDOStatement->nextRowset());\n            $this->_linkID->setAttribute(\\PDO::ATTR_ERRMODE, $this->options[\\PDO::ATTR_ERRMODE]);\n            return $resultArr;\n        } catch (\\PDOException $e) {\n            $this->error();\n            $this->_linkID->setAttribute(\\PDO::ATTR_ERRMODE, $this->options[\\PDO::ATTR_ERRMODE]);\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Db/Driver/Oracle.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace Think\\Db\\Driver;\n\nuse Think\\Db\\Driver;\n\n/**\n * Oracle数据库驱动\n */\nclass Oracle extends Driver\n{\n\n    private $table       = '';\n    protected $selectSql = 'SELECT * FROM (SELECT thinkphp.*, rownum AS numrow FROM (SELECT  %DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%) thinkphp ) %LIMIT%%COMMENT%';\n\n    /**\n     * 解析pdo连接的dsn信息\n     * @access public\n     * @param array $config 连接信息\n     * @return string\n     */\n    protected function parseDsn($config)\n    {\n        $dsn = 'oci:dbname=//' . $config['hostname'] . ($config['hostport'] ? ':' . $config['hostport'] : '') . '/' . $config['database'];\n        if (!empty($config['charset'])) {\n            $dsn .= ';charset=' . $config['charset'];\n        }\n        return $dsn;\n    }\n\n    /**\n     * 执行语句\n     * @access public\n     * @param string $str  sql指令\n     * @param boolean $fetchSql  不执行只是获取SQL\n     * @return integer\n     */\n    public function execute($str, $fetchSql = false)\n    {\n        $this->initConnect(true);\n        if (!$this->_linkID) {\n            return false;\n        }\n\n        $this->queryStr = $str;\n        if (!empty($this->bind)) {\n            $that           = $this;\n            $this->queryStr = strtr($this->queryStr, array_map(function ($val) use ($that) {return '\\'' . $that->escapeString($val) . '\\'';}, $this->bind));\n        }\n        if ($fetchSql) {\n            return $this->queryStr;\n        }\n        $flag = false;\n        if (preg_match(\"/^\\s*(INSERT\\s+INTO)\\s+(\\w+)\\s+/i\", $str, $match)) {\n            $this->table = C(\"DB_SEQUENCE_PREFIX\") . str_ireplace(C(\"DB_PREFIX\"), \"\", $match[2]);\n            $flag        = (boolean) $this->query(\"SELECT * FROM user_sequences WHERE sequence_name='\" . strtoupper($this->table) . \"'\");\n        }\n        //释放前次的查询结果\n        if (!empty($this->PDOStatement)) {\n            $this->free();\n        }\n\n        $this->executeTimes++;\n        N('db_write', 1); // 兼容代码\n        // 记录开始执行时间\n        $this->debug(true);\n        $this->PDOStatement = $this->_linkID->prepare($str);\n        if (false === $this->PDOStatement) {\n            $this->error();\n            return false;\n        }\n        foreach ($this->bind as $key => $val) {\n            if (is_array($val)) {\n                $this->PDOStatement->bindValue($key, $val[0], $val[1]);\n            } else {\n                $this->PDOStatement->bindValue($key, $val);\n            }\n        }\n        $this->bind = array();\n        $result     = $this->PDOStatement->execute();\n        $this->debug(false);\n        if (false === $result) {\n            $this->error();\n            return false;\n        } else {\n            $this->numRows = $this->PDOStatement->rowCount();\n            if ($flag || preg_match(\"/^\\s*(INSERT\\s+INTO|REPLACE\\s+INTO)\\s+/i\", $str)) {\n                $this->lastInsID = $this->_linkID->lastInsertId();\n            }\n            return $this->numRows;\n        }\n    }\n\n    /**\n     * 取得数据表的字段信息\n     * @access public\n     */\n    public function getFields($tableName)\n    {\n        list($tableName) = explode(' ', $tableName);\n        $result          = $this->query(\"select a.column_name,data_type,decode(nullable,'Y',0,1) notnull,data_default,decode(a.column_name,b.column_name,1,0) pk \"\n            . \"from user_tab_columns a,(select column_name from user_constraints c,user_cons_columns col \"\n            . \"where c.constraint_name=col.constraint_name and c.constraint_type='P'and c.table_name='\" . strtoupper($tableName)\n            . \"') b where table_name='\" . strtoupper($tableName) . \"' and a.column_name=b.column_name(+)\");\n        $info = array();\n        if ($result) {\n            foreach ($result as $key => $val) {\n                $info[strtolower($val['column_name'])] = array(\n                    'name'    => strtolower($val['column_name']),\n                    'type'    => strtolower($val['data_type']),\n                    'notnull' => $val['notnull'],\n                    'default' => $val['data_default'],\n                    'primary' => $val['pk'],\n                    'autoinc' => $val['pk'],\n                );\n            }\n        }\n        return $info;\n    }\n\n    /**\n     * 取得数据库的表信息（暂时实现取得用户表信息）\n     * @access public\n     */\n    public function getTables($dbName = '')\n    {\n        $result = $this->query(\"select table_name from user_tables\");\n        $info   = array();\n        foreach ($result as $key => $val) {\n            $info[$key] = current($val);\n        }\n        return $info;\n    }\n\n    /**\n     * SQL指令安全过滤\n     * @access public\n     * @param string $str  SQL指令\n     * @return string\n     */\n    public function escapeString($str)\n    {\n        return str_ireplace(\"'\", \"''\", $str);\n    }\n\n    /**\n     * limit\n     * @access public\n     * @return string\n     */\n    public function parseLimit($limit)\n    {\n        $limitStr = '';\n        if (!empty($limit)) {\n            $limit = explode(',', $limit);\n            if (count($limit) > 1) {\n                $limitStr = \"(numrow>\" . $limit[0] . \") AND (numrow<=\" . ($limit[0] + $limit[1]) . \")\";\n            } else {\n                $limitStr = \"(numrow>0 AND numrow<=\" . $limit[0] . \")\";\n            }\n\n        }\n        return $limitStr ? ' WHERE ' . $limitStr : '';\n    }\n\n    /**\n     * 设置锁机制\n     * @access protected\n     * @return string\n     */\n    protected function parseLock($lock = false)\n    {\n        if (!$lock) {\n            return '';\n        }\n\n        return ' FOR UPDATE NOWAIT ';\n    }\n\n    /**\n     * 随机排序\n     * @access protected\n     * @return string\n     */\n    protected function parseRand()\n    {\n        return 'DBMS_RANDOM.value';\n    }\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Db/Driver/Pgsql.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace Think\\Db\\Driver;\n\nuse Think\\Db\\Driver;\n\n/**\n * Pgsql数据库驱动\n */\nclass Pgsql extends Driver\n{\n\n    /**\n     * 解析pdo连接的dsn信息\n     * @access public\n     * @param array $config 连接信息\n     * @return string\n     */\n    protected function parseDsn($config)\n    {\n        $dsn = 'pgsql:dbname=' . $config['database'] . ';host=' . $config['hostname'];\n        if (!empty($config['hostport'])) {\n            $dsn .= ';port=' . $config['hostport'];\n        }\n        return $dsn;\n    }\n\n    /**\n     * 取得数据表的字段信息\n     * @access public\n     * @return array\n     */\n    public function getFields($tableName)\n    {\n        list($tableName) = explode(' ', $tableName);\n        $result          = $this->query('select fields_name as \"field\",fields_type as \"type\",fields_not_null as \"null\",fields_key_name as \"key\",fields_default as \"default\",fields_default as \"extra\" from table_msg(\\'' . $tableName . '\\');');\n        $info            = array();\n        if ($result) {\n            foreach ($result as $key => $val) {\n                $info[$val['field']] = array(\n                    'name'    => $val['field'],\n                    'type'    => $val['type'],\n                    'notnull' => (bool) ('' === $val['null']), // not null is empty, null is yes\n                    'default' => $val['default'],\n                    'primary' => (strtolower($val['key']) == 'pri'),\n                    'autoinc' => (strtolower($val['extra']) == 'auto_increment'),\n                );\n            }\n        }\n        return $info;\n    }\n\n    /**\n     * 取得数据库的表信息\n     * @access public\n     * @return array\n     */\n    public function getTables($dbName = '')\n    {\n        $result = $this->query(\"select tablename as Tables_in_test from pg_tables where  schemaname ='public'\");\n        $info   = array();\n        foreach ($result as $key => $val) {\n            $info[$key] = current($val);\n        }\n        return $info;\n    }\n\n    /**\n     * limit分析\n     * @access protected\n     * @param mixed $lmit\n     * @return string\n     */\n    public function parseLimit($limit)\n    {\n        $limitStr = '';\n        if (!empty($limit)) {\n            $limit = explode(',', $limit);\n            if (count($limit) > 1) {\n                $limitStr .= ' LIMIT ' . $limit[1] . ' OFFSET ' . $limit[0] . ' ';\n            } else {\n                $limitStr .= ' LIMIT ' . $limit[0] . ' ';\n            }\n        }\n        return $limitStr;\n    }\n\n    /**\n     * 随机排序\n     * @access protected\n     * @return string\n     */\n    protected function parseRand()\n    {\n        return 'RANDOM()';\n    }\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Db/Driver/Sqlite.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace Think\\Db\\Driver;\n\nuse Think\\Db\\Driver;\n\n/**\n * Sqlite数据库驱动\n */\nclass Sqlite extends Driver\n{\n\n    /**\n     * 解析pdo连接的dsn信息\n     * @access public\n     * @param array $config 连接信息\n     * @return string\n     */\n    protected function parseDsn($config)\n    {\n        $dsn = 'sqlite:' . $config['database'];\n        return $dsn;\n    }\n\n    /**\n     * 取得数据表的字段信息\n     * @access public\n     * @return array\n     */\n    public function getFields($tableName)\n    {\n        list($tableName) = explode(' ', $tableName);\n        $result          = $this->query('PRAGMA table_info( ' . $tableName . ' )');\n        $info            = array();\n        if ($result) {\n            foreach ($result as $key => $val) {\n                $info[$val['name']] = array(\n                    'name'    => $val['name'],\n                    'type'    => $val['type'],\n                    'notnull' => (bool) (1 === $val['notnull']),\n                    'default' => $val['dflt_value'],\n                    'primary' => '1' == $val['pk'],\n                    'autoinc' => false,\n                );\n            }\n        }\n        return $info;\n    }\n\n    /**\n     * 取得数据库的表信息\n     * @access public\n     * @return array\n     */\n    public function getTables($dbName = '')\n    {\n        $result = $this->query(\"SELECT name FROM sqlite_master WHERE type='table' \"\n            . \"UNION ALL SELECT name FROM sqlite_temp_master \"\n            . \"WHERE type='table' ORDER BY name\");\n        $info = array();\n        foreach ($result as $key => $val) {\n            $info[$key] = current($val);\n        }\n        return $info;\n    }\n\n    /**\n     * SQL指令安全过滤\n     * @access public\n     * @param string $str  SQL指令\n     * @return string\n     */\n    public function escapeString($str)\n    {\n        return str_ireplace(\"'\", \"''\", $str);\n    }\n\n    /**\n     * limit\n     * @access public\n     * @return string\n     */\n    public function parseLimit($limit)\n    {\n        $limitStr = '';\n        if (!empty($limit)) {\n            $limit = explode(',', $limit);\n            if (count($limit) > 1) {\n                $limitStr .= ' LIMIT ' . $limit[1] . ' OFFSET ' . $limit[0] . ' ';\n            } else {\n                $limitStr .= ' LIMIT ' . $limit[0] . ' ';\n            }\n        }\n        return $limitStr;\n    }\n\n    /**\n     * 随机排序\n     * @access protected\n     * @return string\n     */\n    protected function parseRand()\n    {\n        return 'RANDOM()';\n    }\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Db/Driver/Sqlsrv.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace Think\\Db\\Driver;\n\nuse PDO;\nuse Think\\Db\\Driver;\n\n/**\n * Sqlsrv数据库驱动\n */\nclass Sqlsrv extends Driver\n{\n    protected $selectSql = 'SELECT T1.* FROM (SELECT thinkphp.*, ROW_NUMBER() OVER (%ORDER%) AS ROW_NUMBER FROM (SELECT %DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING% %UNION%) AS thinkphp) AS T1 %LIMIT%%COMMENT%';\n    // PDO连接参数\n    protected $options = array(\n        PDO::ATTR_CASE              => PDO::CASE_LOWER,\n        PDO::ATTR_ERRMODE           => PDO::ERRMODE_EXCEPTION,\n        PDO::ATTR_STRINGIFY_FETCHES => false,\n        PDO::SQLSRV_ATTR_ENCODING   => PDO::SQLSRV_ENCODING_UTF8,\n    );\n\n    /**\n     * 解析pdo连接的dsn信息\n     * @access public\n     * @param array $config 连接信息\n     * @return string\n     */\n    protected function parseDsn($config)\n    {\n        $dsn = 'sqlsrv:Database=' . $config['database'] . ';Server=' . $config['hostname'];\n        if (!empty($config['hostport'])) {\n            $dsn .= ',' . $config['hostport'];\n        }\n        return $dsn;\n    }\n\n    /**\n     * 取得数据表的字段信息\n     * @access public\n     * @return array\n     */\n    public function getFields($tableName)\n    {\n        list($tableName) = explode(' ', $tableName);\n        $result          = $this->query(\"SELECT   column_name,   data_type,   column_default,   is_nullable\n        FROM    information_schema.tables AS t\n        JOIN    information_schema.columns AS c\n        ON  t.table_catalog = c.table_catalog\n        AND t.table_schema  = c.table_schema\n        AND t.table_name    = c.table_name\n        WHERE   t.table_name = '$tableName'\");\n        $info = array();\n        if ($result) {\n            foreach ($result as $key => $val) {\n                $info[$val['column_name']] = array(\n                    'name'    => $val['column_name'],\n                    'type'    => $val['data_type'],\n                    'notnull' => (bool) ('' === $val['is_nullable']), // not null is empty, null is yes\n                    'default' => $val['column_default'],\n                    'primary' => false,\n                    'autoinc' => false,\n                );\n            }\n        }\n        return $info;\n    }\n\n    /**\n     * 取得数据表的字段信息\n     * @access public\n     * @return array\n     */\n    public function getTables($dbName = '')\n    {\n        $result = $this->query(\"SELECT TABLE_NAME\n            FROM INFORMATION_SCHEMA.TABLES\n            WHERE TABLE_TYPE = 'BASE TABLE'\n            \");\n        $info = array();\n        foreach ($result as $key => $val) {\n            $info[$key] = current($val);\n        }\n        return $info;\n    }\n\n    /**\n     * order分析\n     * @access protected\n     * @param mixed $order\n     * @return string\n     */\n    protected function parseOrder($order)\n    {\n        return !empty($order) ? ' ORDER BY ' . $order : ' ORDER BY rand()';\n    }\n\n    /**\n     * 字段和表名处理\n     * @access public\n     * @param string $key\n     * @param bool   $strict\n     * @return string\n     */\n    public function parseKey($key, $strict = false)\n    {\n        $key = trim($key);\n\n        if ($strict && !preg_match('/^[\\w\\.\\*]+$/', $key)) {\n            E('not support data:' . $key);\n        }\n\n        if ($strict || (!is_numeric($key) && !preg_match('/[,\\'\\\"\\*\\(\\)\\[.\\s]/', $key))) {\n            $key = '[' . $key . ']';\n        }\n        return $key;\n    }\n\n    /**\n     * limit\n     * @access public\n     * @param mixed $limit\n     * @return string\n     */\n    public function parseLimit($limit)\n    {\n        if (empty($limit)) {\n            return '';\n        }\n\n        $limit = explode(',', $limit);\n        if (count($limit) > 1) {\n            $limitStr = '(T1.ROW_NUMBER BETWEEN ' . $limit[0] . ' + 1 AND ' . $limit[0] . ' + ' . $limit[1] . ')';\n        } else {\n            $limitStr = '(T1.ROW_NUMBER BETWEEN 1 AND ' . $limit[0] . \")\";\n        }\n\n        return 'WHERE ' . $limitStr;\n    }\n\n    /**\n     * 更新记录\n     * @access public\n     * @param mixed $data 数据\n     * @param array $options 表达式\n     * @return false | integer\n     */\n    public function update($data, $options)\n    {\n        $this->model = $options['model'];\n        $this->parseBind(!empty($options['bind']) ? $options['bind'] : array());\n        $sql = 'UPDATE '\n        . $this->parseTable($options['table'])\n        . $this->parseSet($data)\n        . $this->parseWhere(!empty($options['where']) ? $options['where'] : '')\n        . $this->parseLock(isset($options['lock']) ? $options['lock'] : false)\n        . $this->parseComment(!empty($options['comment']) ? $options['comment'] : '');\n        return $this->execute($sql, !empty($options['fetch_sql']) ? true : false);\n    }\n\n    /**\n     * 删除记录\n     * @access public\n     * @param array $options 表达式\n     * @return false | integer\n     */\n    public function delete($options = array())\n    {\n        $this->model = $options['model'];\n        $this->parseBind(!empty($options['bind']) ? $options['bind'] : array());\n        $sql = 'DELETE FROM '\n        . $this->parseTable($options['table'])\n        . $this->parseWhere(!empty($options['where']) ? $options['where'] : '')\n        . $this->parseLock(isset($options['lock']) ? $options['lock'] : false)\n        . $this->parseComment(!empty($options['comment']) ? $options['comment'] : '');\n        return $this->execute($sql, !empty($options['fetch_sql']) ? true : false);\n    }\n\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Db/Driver.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace Think\\Db;\n\nuse PDO;\nuse Think\\Config;\nuse Think\\Debug;\n\nabstract class Driver\n{\n    // PDO操作实例\n    protected $PDOStatement = null;\n    // 当前操作所属的模型名\n    protected $model = '_think_';\n    // 当前SQL指令\n    protected $queryStr = '';\n    protected $modelSql = array();\n    // 最后插入ID\n    protected $lastInsID = null;\n    // 返回或者影响记录数\n    protected $numRows = 0;\n    // 事物操作PDO实例\n    protected $transPDO = null;\n    // 事务指令数\n    protected $transTimes = 0;\n    // 错误信息\n    protected $error = '';\n    // 数据库连接ID 支持多个连接\n    protected $linkID = array();\n    // 当前连接ID\n    protected $_linkID = null;\n    // 数据库连接参数配置\n    protected $config = array(\n        'type'           => '', // 数据库类型\n        'hostname'       => '127.0.0.1', // 服务器地址\n        'database'       => '', // 数据库名\n        'username'       => '', // 用户名\n        'password'       => '', // 密码\n        'hostport'       => '', // 端口\n        'dsn'            => '', //\n        'params'         => array(), // 数据库连接参数\n        'charset'        => 'utf8', // 数据库编码默认采用utf8\n        'prefix'         => '', // 数据库表前缀\n        'debug'          => false, // 数据库调试模式\n        'deploy'         => 0, // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)\n        'rw_separate'    => false, // 数据库读写是否分离 主从式有效\n        'master_num'     => 1, // 读写分离后 主服务器数量\n        'slave_no'       => '', // 指定从服务器序号\n        'db_like_fields' => '',\n    );\n    // 数据库表达式\n    protected $exp = array('eq' => '=', 'neq' => '<>', 'gt' => '>', 'egt' => '>=', 'lt' => '<', 'elt' => '<=', 'notlike' => 'NOT LIKE', 'like' => 'LIKE', 'in' => 'IN', 'notin' => 'NOT IN', 'not in' => 'NOT IN', 'between' => 'BETWEEN', 'not between' => 'NOT BETWEEN', 'notbetween' => 'NOT BETWEEN');\n    // 查询表达式\n    protected $selectSql = 'SELECT%DISTINCT% %FIELD% FROM %TABLE%%FORCE%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%%LIMIT% %UNION%%LOCK%%COMMENT%';\n    // 查询次数\n    protected $queryTimes = 0;\n    // 执行次数\n    protected $executeTimes = 0;\n    // PDO连接参数\n    protected $options = array(\n        PDO::ATTR_CASE              => PDO::CASE_LOWER,\n        PDO::ATTR_ERRMODE           => PDO::ERRMODE_EXCEPTION,\n        PDO::ATTR_ORACLE_NULLS      => PDO::NULL_NATURAL,\n        PDO::ATTR_STRINGIFY_FETCHES => false,\n    );\n    protected $bind = array(); // 参数绑定\n\n    /**\n     * 架构函数 读取数据库配置信息\n     * @access public\n     * @param array $config 数据库配置数组\n     */\n    public function __construct($config = '')\n    {\n        if (!empty($config)) {\n            $this->config = array_merge($this->config, $config);\n            if (is_array($this->config['params'])) {\n                $this->options = $this->config['params'] + $this->options;\n            }\n        }\n    }\n\n    /**\n     * 连接数据库方法\n     * @access public\n     */\n    public function connect($config = '', $linkNum = 0, $autoConnection = false)\n    {\n        if (!isset($this->linkID[$linkNum])) {\n            if (empty($config)) {\n                $config = $this->config;\n            }\n\n            try {\n                if (empty($config['dsn'])) {\n                    $config['dsn'] = $this->parseDsn($config);\n                }\n                if (version_compare(PHP_VERSION, '5.3.6', '<=')) {\n                    // 禁用模拟预处理语句\n                    $this->options[PDO::ATTR_EMULATE_PREPARES] = false;\n                }\n                $this->linkID[$linkNum] = new PDO($config['dsn'], $config['username'], $config['password'], $this->options);\n            } catch (\\PDOException $e) {\n                if ($autoConnection) {\n                    trace($e->getMessage(), '', 'ERR');\n                    return $this->connect($autoConnection, $linkNum);\n                } elseif ($config['debug']) {\n                    E($e->getMessage());\n                }\n            }\n        }\n        return $this->linkID[$linkNum];\n    }\n\n    /**\n     * 解析pdo连接的dsn信息\n     * @access public\n     * @param array $config 连接信息\n     * @return string\n     */\n    protected function parseDsn($config)\n    {}\n\n    /**\n     * 释放查询结果\n     * @access public\n     */\n    public function free()\n    {\n        $this->PDOStatement = null;\n    }\n\n    /**\n     * 执行查询 返回数据集\n     * @access public\n     * @param string $str  sql指令\n     * @param boolean $fetchSql  不执行只是获取SQL\n     * @param boolean $master  是否在主服务器读操作\n     * @return mixed\n     */\n    public function query($str, $fetchSql = false, $master = false)\n    {\n        $this->initConnect($master);\n        if (!$this->_linkID) {\n            return false;\n        }\n\n        $this->queryStr = $str;\n        if (!empty($this->bind)) {\n            $that           = $this;\n            $this->queryStr = strtr($this->queryStr, array_map(function ($val) use ($that) {return '\\'' . $that->escapeString($val) . '\\'';}, $this->bind));\n        }\n        if ($fetchSql) {\n            return $this->queryStr;\n        }\n        //释放前次的查询结果\n        if (!empty($this->PDOStatement)) {\n            $this->free();\n        }\n\n        $this->queryTimes++;\n        N('db_query', 1); // 兼容代码\n        // 调试开始\n        $this->debug(true);\n        $this->PDOStatement = $this->_linkID->prepare($str);\n        if (false === $this->PDOStatement) {\n            $this->error();\n            return false;\n        }\n        foreach ($this->bind as $key => $val) {\n            if (is_array($val)) {\n                $this->PDOStatement->bindValue($key, $val[0], $val[1]);\n            } else {\n                $this->PDOStatement->bindValue($key, $val);\n            }\n        }\n        $this->bind = array();\n        try {\n            $result = $this->PDOStatement->execute();\n            // 调试结束\n            $this->debug(false);\n            if (false === $result) {\n                $this->error();\n                return false;\n            } else {\n                return $this->getResult();\n            }\n        } catch (\\PDOException $e) {\n            $this->error();\n            return false;\n        }\n    }\n\n    /**\n     * 执行语句\n     * @access public\n     * @param string $str  sql指令\n     * @param boolean $fetchSql  不执行只是获取SQL\n     * @return mixed\n     */\n    public function execute($str, $fetchSql = false)\n    {\n        $this->initConnect(true);\n        if (!$this->_linkID) {\n            return false;\n        }\n\n        $this->queryStr = $str;\n        if (!empty($this->bind)) {\n            $that           = $this;\n            $this->queryStr = strtr($this->queryStr, array_map(function ($val) use ($that) {return '\\'' . $that->escapeString($val) . '\\'';}, $this->bind));\n        }\n        if ($fetchSql) {\n            return $this->queryStr;\n        }\n        //释放前次的查询结果\n        if (!empty($this->PDOStatement)) {\n            $this->free();\n        }\n\n        $this->executeTimes++;\n        N('db_write', 1); // 兼容代码\n        // 记录开始执行时间\n        $this->debug(true);\n        $this->PDOStatement = $this->_linkID->prepare($str);\n        if (false === $this->PDOStatement) {\n            $this->error();\n            return false;\n        }\n        foreach ($this->bind as $key => $val) {\n            if (is_array($val)) {\n                $this->PDOStatement->bindValue($key, $val[0], $val[1]);\n            } else {\n                $this->PDOStatement->bindValue($key, $val);\n            }\n        }\n        $this->bind = array();\n        try {\n            $result = $this->PDOStatement->execute();\n            // 调试结束\n            $this->debug(false);\n            if (false === $result) {\n                $this->error();\n                return false;\n            } else {\n                $this->numRows = $this->PDOStatement->rowCount();\n                if (preg_match(\"/^\\s*(INSERT\\s+INTO|REPLACE\\s+INTO)\\s+/i\", $str)) {\n                    $this->lastInsID = $this->_linkID->lastInsertId();\n                }\n                return $this->numRows;\n            }\n        } catch (\\PDOException $e) {\n            $this->error();\n            return false;\n        }\n    }\n\n    /**\n     * 启动事务\n     * @access public\n     * @return void\n     */\n    public function startTrans()\n    {\n        $this->initConnect(true);\n        if (!$this->_linkID) {\n            return false;\n        }\n\n        //数据rollback 支持\n        if (0 == $this->transTimes) {\n            // 记录当前操作PDO\n            $this->transPdo = $this->_linkID;\n            $this->_linkID->beginTransaction();\n        }\n        $this->transTimes++;\n        return;\n    }\n\n    /**\n     * 用于非自动提交状态下面的查询提交\n     * @access public\n     * @return boolean\n     */\n    public function commit()\n    {\n        if (1 == $this->transTimes) {\n            // 由嵌套事物的最外层进行提交\n            $result           = $this->_linkID->commit();\n            $this->transTimes = 0;\n            $this->transPdo   = null;\n            if (!$result) {\n                $this->error();\n                return false;\n            }\n        } else {\n            $this->transTimes = $this->transTimes <= 0 ? 0 : $this->transTimes - 1;\n        }\n        return true;\n    }\n\n    /**\n     * 事务回滚\n     * @access public\n     * @return boolean\n     */\n    public function rollback()\n    {\n        if ($this->transTimes > 0) {\n            $result           = $this->_linkID->rollback();\n            $this->transTimes = 0;\n            $this->transPdo   = null;\n            if (!$result) {\n                $this->error();\n                return false;\n            }\n        }\n        return true;\n    }\n\n    /**\n     * 获得所有的查询数据\n     * @access private\n     * @return array\n     */\n    private function getResult()\n    {\n        //返回数据集\n        $result        = $this->PDOStatement->fetchAll(PDO::FETCH_ASSOC);\n        $this->numRows = count($result);\n        return $result;\n    }\n\n    /**\n     * 获得查询次数\n     * @access public\n     * @param boolean $execute 是否包含所有查询\n     * @return integer\n     */\n    public function getQueryTimes($execute = false)\n    {\n        return $execute ? $this->queryTimes + $this->executeTimes : $this->queryTimes;\n    }\n\n    /**\n     * 获得执行次数\n     * @access public\n     * @return integer\n     */\n    public function getExecuteTimes()\n    {\n        return $this->executeTimes;\n    }\n\n    /**\n     * 关闭数据库\n     * @access public\n     */\n    public function close()\n    {\n        $this->_linkID = null;\n    }\n\n    /**\n     * 数据库错误信息\n     * 并显示当前的SQL语句\n     * @access public\n     * @return string\n     */\n    public function error()\n    {\n        if ($this->PDOStatement) {\n            $error       = $this->PDOStatement->errorInfo();\n            $this->error = $error[1] . ':' . $error[2];\n        } else {\n            $this->error = '';\n        }\n        if ('' != $this->queryStr) {\n            $this->error .= \"\\n [ SQL语句 ] : \" . $this->queryStr;\n        }\n        // 记录错误日志\n        trace($this->error, '', 'ERR');\n        if ($this->config['debug']) {\n            // 开启数据库调试模式\n            E($this->error);\n        } else {\n            return $this->error;\n        }\n    }\n\n    /**\n     * 设置锁机制\n     * @access protected\n     * @return string\n     */\n    protected function parseLock($lock = false)\n    {\n        return $lock ? ' FOR UPDATE ' : '';\n    }\n\n    /**\n     * set分析\n     * @access protected\n     * @param array $data\n     * @return string\n     */\n    protected function parseSet($data)\n    {\n        foreach ($data as $key => $val) {\n            if (isset($val[0]) && 'exp' == $val[0]) {\n                $set[] = $this->parseKey($key) . '=' . $val[1];\n            } elseif (is_null($val)) {\n                $set[] = $this->parseKey($key) . '=NULL';\n            } elseif (is_scalar($val)) {\n                // 过滤非标量数据\n                if (0 === strpos($val, ':') && in_array($val, array_keys($this->bind))) {\n                    $set[] = $this->parseKey($key) . '=' . $val;\n                } else {\n                    $name  = count($this->bind);\n                    $set[] = $this->parseKey($key) . '=:' . $key . '_' . $name;\n                    $this->bindParam($key . '_' . $name, $val);\n                }\n            }\n        }\n        return ' SET ' . implode(',', $set);\n    }\n\n    /**\n     * 参数绑定\n     * @access protected\n     * @param string $name 绑定参数名\n     * @param mixed $value 绑定值\n     * @return void\n     */\n    protected function bindParam($name, $value)\n    {\n        $this->bind[':' . $name] = $value;\n    }\n\n    /**\n     * 字段和表名处理\n     * @access public\n     * @param string $key\n     * @param bool   $strict\n     * @return string\n     */\n    public function parseKey($key, $strict = false)\n    {\n        return $key;\n    }\n\n    /**\n     * value分析\n     * @access protected\n     * @param mixed $value\n     * @return string\n     */\n    protected function parseValue($value)\n    {\n        if (is_string($value)) {\n            $value = strpos($value, ':') === 0 && in_array($value, array_keys($this->bind)) ? $this->escapeString($value) : '\\'' . $this->escapeString($value) . '\\'';\n        } elseif (isset($value[0]) && is_string($value[0]) && strtolower($value[0]) == 'exp') {\n            $value = $this->escapeString($value[1]);\n        } elseif (is_array($value)) {\n            $value = array_map(array($this, 'parseValue'), $value);\n        } elseif (is_bool($value)) {\n            $value = $value ? '1' : '0';\n        } elseif (is_null($value)) {\n            $value = 'null';\n        }\n        return $value;\n    }\n\n    /**\n     * field分析\n     * @access protected\n     * @param mixed $fields\n     * @return string\n     */\n    protected function parseField($fields)\n    {\n        if (is_string($fields) && '' !== $fields) {\n            $fields = explode(',', $fields);\n        }\n        if (is_array($fields)) {\n            // 完善数组方式传字段名的支持\n            // 支持 'field1'=>'field2' 这样的字段别名定义\n            $array = array();\n            foreach ($fields as $key => $field) {\n                if (!is_numeric($key)) {\n                    $array[] = $this->parseKey($key) . ' AS ' . $this->parseKey($field);\n                } else {\n                    $array[] = $this->parseKey($field);\n                }\n\n            }\n            $fieldsStr = implode(',', $array);\n        } else {\n            $fieldsStr = '*';\n        }\n        //TODO 如果是查询全部字段，并且是join的方式，那么就把要查的表加个别名，以免字段被覆盖\n        return $fieldsStr;\n    }\n\n    /**\n     * table分析\n     * @access protected\n     * @param mixed $table\n     * @return string\n     */\n    protected function parseTable($tables)\n    {\n        if (is_array($tables)) {\n            // 支持别名定义\n            $array = array();\n            foreach ($tables as $table => $alias) {\n                if (!is_numeric($table)) {\n                    $array[] = $this->parseKey($table) . ' ' . $this->parseKey($alias);\n                } else {\n                    $array[] = $this->parseKey($alias);\n                }\n\n            }\n            $tables = $array;\n        } elseif (is_string($tables)) {\n            $tables = array_map(array($this, 'parseKey'), explode(',', $tables));\n        }\n        return implode(',', $tables);\n    }\n\n    /**\n     * where分析\n     * @access protected\n     * @param mixed $where\n     * @return string\n     */\n    protected function parseWhere($where)\n    {\n        $whereStr = '';\n        if (is_string($where)) {\n            // 直接使用字符串条件\n            $whereStr = $where;\n        } else {\n            // 使用数组表达式\n            $operate = isset($where['_logic']) ? strtoupper($where['_logic']) : '';\n            if (in_array($operate, array('AND', 'OR', 'XOR'))) {\n                // 定义逻辑运算规则 例如 OR XOR AND NOT\n                $operate = ' ' . $operate . ' ';\n                unset($where['_logic']);\n            } else {\n                // 默认进行 AND 运算\n                $operate = ' AND ';\n            }\n            foreach ($where as $key => $val) {\n                if (is_numeric($key)) {\n                    $key = '_complex';\n                }\n                if (0 === strpos($key, '_')) {\n                    // 解析特殊条件表达式\n                    $whereStr .= $this->parseThinkWhere($key, $val);\n                } else {\n                    // 查询字段的安全过滤\n                    // if(!preg_match('/^[A-Z_\\|\\&\\-.a-z0-9\\(\\)\\,]+$/',trim($key))){\n                    //     E(L('_EXPRESS_ERROR_').':'.$key);\n                    // }\n                    // 多条件支持\n                    $multi = is_array($val) && isset($val['_multi']);\n                    $key   = trim($key);\n                    if (strpos($key, '|')) {\n                        // 支持 name|title|nickname 方式定义查询字段\n                        $array = explode('|', $key);\n                        $str   = array();\n                        foreach ($array as $m => $k) {\n                            $v     = $multi ? $val[$m] : $val;\n                            $str[] = $this->parseWhereItem($this->parseKey($k), $v);\n                        }\n                        $whereStr .= '( ' . implode(' OR ', $str) . ' )';\n                    } elseif (strpos($key, '&')) {\n                        $array = explode('&', $key);\n                        $str   = array();\n                        foreach ($array as $m => $k) {\n                            $v     = $multi ? $val[$m] : $val;\n                            $str[] = '(' . $this->parseWhereItem($this->parseKey($k), $v) . ')';\n                        }\n                        $whereStr .= '( ' . implode(' AND ', $str) . ' )';\n                    } else {\n                        $whereStr .= $this->parseWhereItem($this->parseKey($key), $val);\n                    }\n                }\n                $whereStr .= $operate;\n            }\n            $whereStr = substr($whereStr, 0, -strlen($operate));\n        }\n        return empty($whereStr) ? '' : ' WHERE ' . $whereStr;\n    }\n\n    // where子单元分析\n    protected function parseWhereItem($key, $val)\n    {\n        $whereStr = '';\n        if (is_array($val)) {\n            if (is_string($val[0])) {\n                $exp = strtolower($val[0]);\n                if (preg_match('/^(eq|neq|gt|egt|lt|elt)$/', $exp)) {\n                    // 比较运算\n                    $whereStr .= $key . ' ' . $this->exp[$exp] . ' ' . $this->parseValue($val[1]);\n                } elseif (preg_match('/^(notlike|like)$/', $exp)) {\n                    // 模糊查找\n                    if (is_array($val[1])) {\n                        $likeLogic = isset($val[2]) ? strtoupper($val[2]) : 'OR';\n                        if (in_array($likeLogic, array('AND', 'OR', 'XOR'))) {\n                            $like = array();\n                            foreach ($val[1] as $item) {\n                                $like[] = $key . ' ' . $this->exp[$exp] . ' ' . $this->parseValue($item);\n                            }\n                            $whereStr .= '(' . implode(' ' . $likeLogic . ' ', $like) . ')';\n                        }\n                    } else {\n                        $whereStr .= $key . ' ' . $this->exp[$exp] . ' ' . $this->parseValue($val[1]);\n                    }\n                } elseif ('bind' == $exp) {\n                    // 使用表达式\n                    $whereStr .= $key . ' = :' . $val[1];\n                } elseif ('exp' == $exp) {\n                    // 使用表达式\n                    $whereStr .= $key . ' ' . $val[1];\n                } elseif (preg_match('/^(notin|not in|in)$/', $exp)) {\n                    // IN 运算\n                    if (isset($val[2]) && 'exp' == $val[2]) {\n                        $whereStr .= $key . ' ' . $this->exp[$exp] . ' ' . $val[1];\n                    } else {\n                        if (is_string($val[1])) {\n                            $val[1] = explode(',', $val[1]);\n                        }\n                        $zone = implode(',', $this->parseValue($val[1]));\n                        $whereStr .= $key . ' ' . $this->exp[$exp] . ' (' . $zone . ')';\n                    }\n                } elseif (preg_match('/^(notbetween|not between|between)$/', $exp)) {\n                    // BETWEEN运算\n                    $data = is_string($val[1]) ? explode(',', $val[1]) : $val[1];\n                    $whereStr .= $key . ' ' . $this->exp[$exp] . ' ' . $this->parseValue($data[0]) . ' AND ' . $this->parseValue($data[1]);\n                } else {\n                    E(L('_EXPRESS_ERROR_') . ':' . $val[0]);\n                }\n            } else {\n                $count = count($val);\n                $rule  = isset($val[$count - 1]) ? (is_array($val[$count - 1]) ? strtoupper($val[$count - 1][0]) : strtoupper($val[$count - 1])) : '';\n                if (in_array($rule, array('AND', 'OR', 'XOR'))) {\n                    $count = $count - 1;\n                } else {\n                    $rule = 'AND';\n                }\n                for ($i = 0; $i < $count; $i++) {\n                    $data = is_array($val[$i]) ? $val[$i][1] : $val[$i];\n                    if ('exp' == strtolower($val[$i][0])) {\n                        $whereStr .= $key . ' ' . $data . ' ' . $rule . ' ';\n                    } else {\n                        $whereStr .= $this->parseWhereItem($key, $val[$i]) . ' ' . $rule . ' ';\n                    }\n                }\n                $whereStr = '( ' . substr($whereStr, 0, -4) . ' )';\n            }\n        } else {\n            //对字符串类型字段采用模糊匹配\n            $likeFields = $this->config['db_like_fields'];\n            if ($likeFields && preg_match('/^(' . $likeFields . ')$/i', $key)) {\n                $whereStr .= $key . ' LIKE ' . $this->parseValue('%' . $val . '%');\n            } else {\n                $whereStr .= $key . ' = ' . $this->parseValue($val);\n            }\n        }\n        return $whereStr;\n    }\n\n    /**\n     * 特殊条件分析\n     * @access protected\n     * @param string $key\n     * @param mixed $val\n     * @return string\n     */\n    protected function parseThinkWhere($key, $val)\n    {\n        $whereStr = '';\n        switch ($key) {\n            case '_string':\n                // 字符串模式查询条件\n                $whereStr = $val;\n                break;\n            case '_complex':\n                // 复合查询条件\n                $whereStr = substr($this->parseWhere($val), 6);\n                break;\n            case '_query':\n                // 字符串模式查询条件\n                parse_str($val, $where);\n                if (isset($where['_logic'])) {\n                    $op = ' ' . strtoupper($where['_logic']) . ' ';\n                    unset($where['_logic']);\n                } else {\n                    $op = ' AND ';\n                }\n                $array = array();\n                foreach ($where as $field => $data) {\n                    $array[] = $this->parseKey($field) . ' = ' . $this->parseValue($data);\n                }\n\n                $whereStr = implode($op, $array);\n                break;\n        }\n        return '( ' . $whereStr . ' )';\n    }\n\n    /**\n     * limit分析\n     * @access protected\n     * @param mixed $lmit\n     * @return string\n     */\n    protected function parseLimit($limit)\n    {\n        return (!empty($limit) && false === strpos($limit, '(')) ? ' LIMIT ' . $limit . ' ' : '';\n    }\n\n    /**\n     * join分析\n     * @access protected\n     * @param mixed $join\n     * @return string\n     */\n    protected function parseJoin($join)\n    {\n        $joinStr = '';\n        if (!empty($join)) {\n            $joinStr = ' ' . implode(' ', $join) . ' ';\n        }\n        return $joinStr;\n    }\n\n    /**\n     * order分析\n     * @access protected\n     * @param mixed $order\n     * @return string\n     */\n    protected function parseOrder($order)\n    {\n        if (empty($order)) {\n            return '';\n        }\n        $array = array();\n        if (is_string($order) && '[RAND]' != $order) {\n            $order = array_map('trim', explode(',', $order));\n        }\n\n        if (is_array($order)) {\n            foreach ($order as $key => $val) {\n                if (is_numeric($key)) {\n                    list($key, $sort) = explode(' ', strpos($val, ' ') ? $val : $val . ' ');\n                } else {\n                    $sort = $val;\n                }\n\n                if (preg_match('/^[\\w\\.]+$/', $key)) {\n                    $sort = strtoupper($sort);\n                    $sort = in_array($sort, array('ASC', 'DESC'), true) ? ' ' . $sort : '';\n                    if (strpos($key, '.')) {\n                        list($alias, $key) = explode('.', $key);\n                        $array[]           = $this->parseKey($alias, true) . '.' . $this->parseKey($key, true) . $sort;\n                    } else {\n                        $array[] = $this->parseKey($key, true) . $sort;\n                    }\n                }\n            }\n        } elseif ('[RAND]' == $order) {\n            // 随机排序\n            $array[] = $this->parseRand();\n        }\n\n        $order = implode(',', $array);\n        return !empty($order) ? ' ORDER BY ' . $order : '';\n    }\n\n    /**\n     * group分析\n     * @access protected\n     * @param mixed $group\n     * @return string\n     */\n    protected function parseGroup($group)\n    {\n        return !empty($group) ? ' GROUP BY ' . $group : '';\n    }\n\n    /**\n     * having分析\n     * @access protected\n     * @param string $having\n     * @return string\n     */\n    protected function parseHaving($having)\n    {\n        return !empty($having) ? ' HAVING ' . $having : '';\n    }\n\n    /**\n     * comment分析\n     * @access protected\n     * @param string $comment\n     * @return string\n     */\n    protected function parseComment($comment)\n    {\n        return !empty($comment) ? ' /* ' . $comment . ' */' : '';\n    }\n\n    /**\n     * distinct分析\n     * @access protected\n     * @param mixed $distinct\n     * @return string\n     */\n    protected function parseDistinct($distinct)\n    {\n        return !empty($distinct) ? ' DISTINCT ' : '';\n    }\n\n    /**\n     * union分析\n     * @access protected\n     * @param mixed $union\n     * @return string\n     */\n    protected function parseUnion($union)\n    {\n        if (empty($union)) {\n            return '';\n        }\n\n        if (isset($union['_all'])) {\n            $str = 'UNION ALL ';\n            unset($union['_all']);\n        } else {\n            $str = 'UNION ';\n        }\n        foreach ($union as $u) {\n            $sql[] = $str . (is_array($u) ? $this->buildSelectSql($u) : $u);\n        }\n        return implode(' ', $sql);\n    }\n\n    /**\n     * 参数绑定分析\n     * @access protected\n     * @param array $bind\n     * @return array\n     */\n    protected function parseBind($bind)\n    {\n        $this->bind = array_merge($this->bind, $bind);\n    }\n\n    /**\n     * index分析，可在操作链中指定需要强制使用的索引\n     * @access protected\n     * @param mixed $index\n     * @return string\n     */\n    protected function parseForce($index)\n    {\n        if (empty($index)) {\n            return '';\n        }\n\n        if (is_array($index)) {\n            $index = join(\",\", $index);\n        }\n\n        return sprintf(\" FORCE INDEX ( %s ) \", $index);\n    }\n\n    /**\n     * ON DUPLICATE KEY UPDATE 分析\n     * @access protected\n     * @param mixed $duplicate\n     * @return string\n     */\n    protected function parseDuplicate($duplicate)\n    {\n        return '';\n    }\n\n    /**\n     * 插入记录\n     * @access public\n     * @param mixed $data 数据\n     * @param array $options 参数表达式\n     * @param boolean $replace 是否replace\n     * @return false | integer\n     */\n    public function insert($data, $options = array(), $replace = false)\n    {\n        $values      = $fields      = array();\n        $this->model = $options['model'];\n        $this->parseBind(!empty($options['bind']) ? $options['bind'] : array());\n        foreach ($data as $key => $val) {\n            if (isset($val[0]) && 'exp' == $val[0]) {\n                $fields[] = $this->parseKey($key);\n                $values[] = $val[1];\n            } elseif (is_null($val)) {\n                $fields[] = $this->parseKey($key);\n                $values[] = 'NULL';\n            } elseif (is_scalar($val)) {\n                // 过滤非标量数据\n                $fields[] = $this->parseKey($key);\n                if (0 === strpos($val, ':') && in_array($val, array_keys($this->bind))) {\n                    $values[] = $val;\n                } else {\n                    $name     = count($this->bind);\n                    $values[] = ':' . $key . '_' . $name;\n                    $this->bindParam($key . '_' . $name, $val);\n                }\n            }\n        }\n        // 兼容数字传入方式\n        $replace = (is_numeric($replace) && $replace > 0) ? true : $replace;\n        $sql     = (true === $replace ? 'REPLACE' : 'INSERT') . ' INTO ' . $this->parseTable($options['table']) . ' (' . implode(',', $fields) . ') VALUES (' . implode(',', $values) . ')' . $this->parseDuplicate($replace);\n        $sql .= $this->parseComment(!empty($options['comment']) ? $options['comment'] : '');\n        return $this->execute($sql, !empty($options['fetch_sql']) ? true : false);\n    }\n\n    /**\n     * 批量插入记录\n     * @access public\n     * @param mixed $dataSet 数据集\n     * @param array $options 参数表达式\n     * @param boolean $replace 是否replace\n     * @return false | integer\n     */\n    public function insertAll($dataSet, $options = array(), $replace = false)\n    {\n        $values      = array();\n        $this->model = $options['model'];\n        if (!is_array($dataSet[0])) {\n            return false;\n        }\n\n        $this->parseBind(!empty($options['bind']) ? $options['bind'] : array());\n        $fields = array_map(array($this, 'parseKey'), array_keys($dataSet[0]));\n        foreach ($dataSet as $data) {\n            $value = array();\n            foreach ($data as $key => $val) {\n                if (is_array($val) && 'exp' == $val[0]) {\n                    $value[] = $val[1];\n                } elseif (is_null($val)) {\n                    $value[] = 'NULL';\n                } elseif (is_scalar($val)) {\n                    if (0 === strpos($val, ':') && in_array($val, array_keys($this->bind))) {\n                        $value[] = $val;\n                    } else {\n                        $name    = count($this->bind);\n                        $value[] = ':' . $key . '_' . $name;\n                        $this->bindParam($key . '_' . $name, $val);\n                    }\n                }\n            }\n            $values[] = 'SELECT ' . implode(',', $value);\n        }\n        $sql = 'INSERT INTO ' . $this->parseTable($options['table']) . ' (' . implode(',', $fields) . ') ' . implode(' UNION ALL ', $values);\n        $sql .= $this->parseComment(!empty($options['comment']) ? $options['comment'] : '');\n        return $this->execute($sql, !empty($options['fetch_sql']) ? true : false);\n    }\n\n    /**\n     * 通过Select方式插入记录\n     * @access public\n     * @param string $fields 要插入的数据表字段名\n     * @param string $table 要插入的数据表名\n     * @param array $option  查询数据参数\n     * @return false | integer\n     */\n    public function selectInsert($fields, $table, $options = array())\n    {\n        $this->model = $options['model'];\n        $this->parseBind(!empty($options['bind']) ? $options['bind'] : array());\n        if (is_string($fields)) {\n            $fields = explode(',', $fields);\n        }\n\n        $fields = array_map(array($this, 'parseKey'), $fields);\n        $sql    = 'INSERT INTO ' . $this->parseTable($table) . ' (' . implode(',', $fields) . ') ';\n        $sql .= $this->buildSelectSql($options);\n        return $this->execute($sql, !empty($options['fetch_sql']) ? true : false);\n    }\n\n    /**\n     * 更新记录\n     * @access public\n     * @param mixed $data 数据\n     * @param array $options 表达式\n     * @return false | integer\n     */\n    public function update($data, $options)\n    {\n        $this->model = $options['model'];\n        $this->parseBind(!empty($options['bind']) ? $options['bind'] : array());\n        $table = $this->parseTable($options['table']);\n        $sql   = 'UPDATE ' . $table . $this->parseSet($data);\n        if (strpos($table, ',')) {\n            // 多表更新支持JOIN操作\n            $sql .= $this->parseJoin(!empty($options['join']) ? $options['join'] : '');\n        }\n        $sql .= $this->parseWhere(!empty($options['where']) ? $options['where'] : '');\n        if (!strpos($table, ',')) {\n            //  单表更新支持order和lmit\n            $sql .= $this->parseOrder(!empty($options['order']) ? $options['order'] : '')\n            . $this->parseLimit(!empty($options['limit']) ? $options['limit'] : '');\n        }\n        $sql .= $this->parseComment(!empty($options['comment']) ? $options['comment'] : '');\n        return $this->execute($sql, !empty($options['fetch_sql']) ? true : false);\n    }\n\n    /**\n     * 删除记录\n     * @access public\n     * @param array $options 表达式\n     * @return false | integer\n     */\n    public function delete($options = array())\n    {\n        $this->model = $options['model'];\n        $this->parseBind(!empty($options['bind']) ? $options['bind'] : array());\n        $table = $this->parseTable($options['table']);\n        $sql   = 'DELETE FROM ' . $table;\n        if (strpos($table, ',')) {\n            // 多表删除支持USING和JOIN操作\n            if (!empty($options['using'])) {\n                $sql .= ' USING ' . $this->parseTable($options['using']) . ' ';\n            }\n            $sql .= $this->parseJoin(!empty($options['join']) ? $options['join'] : '');\n        }\n        $sql .= $this->parseWhere(!empty($options['where']) ? $options['where'] : '');\n        if (!strpos($table, ',')) {\n            // 单表删除支持order和limit\n            $sql .= $this->parseOrder(!empty($options['order']) ? $options['order'] : '')\n            . $this->parseLimit(!empty($options['limit']) ? $options['limit'] : '');\n        }\n        $sql .= $this->parseComment(!empty($options['comment']) ? $options['comment'] : '');\n        return $this->execute($sql, !empty($options['fetch_sql']) ? true : false);\n    }\n\n    /**\n     * 查找记录\n     * @access public\n     * @param array $options 表达式\n     * @return mixed\n     */\n    public function select($options = array())\n    {\n        $this->model = $options['model'];\n        $this->parseBind(!empty($options['bind']) ? $options['bind'] : array());\n        $sql    = $this->buildSelectSql($options);\n        $result = $this->query($sql, !empty($options['fetch_sql']) ? true : false, !empty($options['master']) ? true : false);\n        return $result;\n    }\n\n    /**\n     * 生成查询SQL\n     * @access public\n     * @param array $options 表达式\n     * @return string\n     */\n    public function buildSelectSql($options = array())\n    {\n        if (isset($options['page'])) {\n            // 根据页数计算limit\n            list($page, $listRows) = $options['page'];\n            $page                  = $page > 0 ? $page : 1;\n            $listRows              = $listRows > 0 ? $listRows : (is_numeric($options['limit']) ? $options['limit'] : 20);\n            $offset                = $listRows * ($page - 1);\n            $options['limit']      = $offset . ',' . $listRows;\n        }\n        $sql = $this->parseSql($this->selectSql, $options);\n        return $sql;\n    }\n\n    /**\n     * 替换SQL语句中表达式\n     * @access public\n     * @param array $options 表达式\n     * @return string\n     */\n    public function parseSql($sql, $options = array())\n    {\n        $sql = str_replace(\n            array('%TABLE%', '%DISTINCT%', '%FIELD%', '%JOIN%', '%WHERE%', '%GROUP%', '%HAVING%', '%ORDER%', '%LIMIT%', '%UNION%', '%LOCK%', '%COMMENT%', '%FORCE%'),\n            array(\n                $this->parseTable($options['table']),\n                $this->parseDistinct(isset($options['distinct']) ? $options['distinct'] : false),\n                $this->parseField(!empty($options['field']) ? $options['field'] : '*'),\n                $this->parseJoin(!empty($options['join']) ? $options['join'] : ''),\n                $this->parseWhere(!empty($options['where']) ? $options['where'] : ''),\n                $this->parseGroup(!empty($options['group']) ? $options['group'] : ''),\n                $this->parseHaving(!empty($options['having']) ? $options['having'] : ''),\n                $this->parseOrder(!empty($options['order']) ? $options['order'] : ''),\n                $this->parseLimit(!empty($options['limit']) ? $options['limit'] : ''),\n                $this->parseUnion(!empty($options['union']) ? $options['union'] : ''),\n                $this->parseLock(isset($options['lock']) ? $options['lock'] : false),\n                $this->parseComment(!empty($options['comment']) ? $options['comment'] : ''),\n                $this->parseForce(!empty($options['force']) ? $options['force'] : ''),\n            ), $sql);\n        return $sql;\n    }\n\n    /**\n     * 获取最近一次查询的sql语句\n     * @param string $model  模型名\n     * @access public\n     * @return string\n     */\n    public function getLastSql($model = '')\n    {\n        return $model ? $this->modelSql[$model] : $this->queryStr;\n    }\n\n    /**\n     * 获取最近插入的ID\n     * @access public\n     * @return string\n     */\n    public function getLastInsID()\n    {\n        return $this->lastInsID;\n    }\n\n    /**\n     * 获取最近的错误信息\n     * @access public\n     * @return string\n     */\n    public function getError()\n    {\n        return $this->error;\n    }\n\n    /**\n     * SQL指令安全过滤\n     * @access public\n     * @param string $str  SQL字符串\n     * @return string\n     */\n    public function escapeString($str)\n    {\n        return addslashes($str);\n    }\n\n    /**\n     * 设置当前操作模型\n     * @access public\n     * @param string $model  模型名\n     * @return void\n     */\n    public function setModel($model)\n    {\n        $this->model = $model;\n    }\n\n    /**\n     * 数据库调试 记录当前SQL\n     * @access protected\n     * @param boolean $start  调试开始标记 true 开始 false 结束\n     */\n    protected function debug($start)\n    {\n        if ($this->config['debug']) {\n            // 开启数据库调试模式\n            if ($start) {\n                G('queryStartTime');\n            } else {\n                $this->modelSql[$this->model] = $this->queryStr;\n                //$this->model  =   '_think_';\n                // 记录操作结束时间\n                G('queryEndTime');\n                trace($this->queryStr . ' [ RunTime:' . G('queryStartTime', 'queryEndTime') . 's ]', '', 'SQL');\n            }\n        }\n    }\n\n    /**\n     * 初始化数据库连接\n     * @access protected\n     * @param boolean $master 主服务器\n     * @return void\n     */\n    protected function initConnect($master = true)\n    {\n        // 开启事物时用同一个连接进行操作\n        if ($this->transPDO) {\n            return $this->transPDO;\n        }\n\n        if (!empty($this->config['deploy']))\n        // 采用分布式数据库\n        {\n            $this->_linkID = $this->multiConnect($master);\n        } else\n        // 默认单数据库\n        if (!$this->_linkID) {\n            $this->_linkID = $this->connect();\n        }\n\n    }\n\n    /**\n     * 连接分布式服务器\n     * @access protected\n     * @param boolean $master 主服务器\n     * @return void\n     */\n    protected function multiConnect($master = false)\n    {\n        // 分布式数据库配置解析\n        $_config['username'] = explode(',', $this->config['username']);\n        $_config['password'] = explode(',', $this->config['password']);\n        $_config['hostname'] = explode(',', $this->config['hostname']);\n        $_config['hostport'] = explode(',', $this->config['hostport']);\n        $_config['database'] = explode(',', $this->config['database']);\n        $_config['dsn']      = explode(',', $this->config['dsn']);\n        $_config['charset']  = explode(',', $this->config['charset']);\n\n        $m = floor(mt_rand(0, $this->config['master_num'] - 1));\n        // 数据库读写是否分离\n        if ($this->config['rw_separate']) {\n            // 主从式采用读写分离\n            if ($master)\n            // 主服务器写入\n            {\n                $r = $m;\n            } else {\n                if (is_numeric($this->config['slave_no'])) {\n                    // 指定服务器读\n                    $r = $this->config['slave_no'];\n                } else {\n                    // 读操作连接从服务器\n                    $r = floor(mt_rand($this->config['master_num'], count($_config['hostname']) - 1)); // 每次随机连接的数据库\n                }\n            }\n        } else {\n            // 读写操作不区分服务器\n            $r = floor(mt_rand(0, count($_config['hostname']) - 1)); // 每次随机连接的数据库\n        }\n\n        if ($m != $r) {\n            $db_master = array(\n                'username' => isset($_config['username'][$m]) ? $_config['username'][$m] : $_config['username'][0],\n                'password' => isset($_config['password'][$m]) ? $_config['password'][$m] : $_config['password'][0],\n                'hostname' => isset($_config['hostname'][$m]) ? $_config['hostname'][$m] : $_config['hostname'][0],\n                'hostport' => isset($_config['hostport'][$m]) ? $_config['hostport'][$m] : $_config['hostport'][0],\n                'database' => isset($_config['database'][$m]) ? $_config['database'][$m] : $_config['database'][0],\n                'dsn'      => isset($_config['dsn'][$m]) ? $_config['dsn'][$m] : $_config['dsn'][0],\n                'charset'  => isset($_config['charset'][$m]) ? $_config['charset'][$m] : $_config['charset'][0],\n            );\n        }\n        $db_config = array(\n            'username' => isset($_config['username'][$r]) ? $_config['username'][$r] : $_config['username'][0],\n            'password' => isset($_config['password'][$r]) ? $_config['password'][$r] : $_config['password'][0],\n            'hostname' => isset($_config['hostname'][$r]) ? $_config['hostname'][$r] : $_config['hostname'][0],\n            'hostport' => isset($_config['hostport'][$r]) ? $_config['hostport'][$r] : $_config['hostport'][0],\n            'database' => isset($_config['database'][$r]) ? $_config['database'][$r] : $_config['database'][0],\n            'dsn'      => isset($_config['dsn'][$r]) ? $_config['dsn'][$r] : $_config['dsn'][0],\n            'charset'  => isset($_config['charset'][$r]) ? $_config['charset'][$r] : $_config['charset'][0],\n        );\n        return $this->connect($db_config, $r, $r == $m ? false : $db_master);\n    }\n\n    /**\n     * 析构方法\n     * @access public\n     */\n    public function __destruct()\n    {\n        // 释放查询\n        if ($this->PDOStatement) {\n            $this->free();\n        }\n        // 关闭连接\n        $this->close();\n    }\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Db/Lite.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace Think\\Db;\n\nuse PDO;\nuse Think\\Config;\nuse Think\\Debug;\n\nclass Lite\n{\n    // PDO操作实例\n    protected $PDOStatement = null;\n    // 当前操作所属的模型名\n    protected $model = '_think_';\n    // 当前SQL指令\n    protected $queryStr = '';\n    protected $modelSql = array();\n    // 最后插入ID\n    protected $lastInsID = null;\n    // 返回或者影响记录数\n    protected $numRows = 0;\n   \t// 事物操作PDO实例\n    protected $transPDO = null;\n    // 事务指令数\n    protected $transTimes = 0;\n    // 错误信息\n    protected $error = '';\n    // 数据库连接ID 支持多个连接\n    protected $linkID = array();\n    // 当前连接ID\n    protected $_linkID = null;\n    // 数据库连接参数配置\n    protected $config = array(\n        'type'        => '', // 数据库类型\n        'hostname'    => '127.0.0.1', // 服务器地址\n        'database'    => '', // 数据库名\n        'username'    => '', // 用户名\n        'password'    => '', // 密码\n        'hostport'    => '', // 端口\n        'dsn'         => '', //\n        'params'      => array(), // 数据库连接参数\n        'charset'     => 'utf8', // 数据库编码默认采用utf8\n        'prefix'      => '', // 数据库表前缀\n        'debug'       => false, // 数据库调试模式\n        'deploy'      => 0, // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)\n        'rw_separate' => false, // 数据库读写是否分离 主从式有效\n        'master_num'  => 1, // 读写分离后 主服务器数量\n        'slave_no'    => '', // 指定从服务器序号\n    );\n    // 数据库表达式\n    protected $comparison = array('eq' => '=', 'neq' => '<>', 'gt' => '>', 'egt' => '>=', 'lt' => '<', 'elt' => '<=', 'notlike' => 'NOT LIKE', 'like' => 'LIKE', 'in' => 'IN', 'notin' => 'NOT IN');\n    // 查询表达式\n    protected $selectSql = 'SELECT%DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%%LIMIT% %UNION%%COMMENT%';\n    // 查询次数\n    protected $queryTimes = 0;\n    // 执行次数\n    protected $executeTimes = 0;\n    // PDO连接参数\n    protected $options = array(\n        PDO::ATTR_CASE              => PDO::CASE_LOWER,\n        PDO::ATTR_ERRMODE           => PDO::ERRMODE_EXCEPTION,\n        PDO::ATTR_ORACLE_NULLS      => PDO::NULL_NATURAL,\n        PDO::ATTR_STRINGIFY_FETCHES => false,\n    );\n\n    /**\n     * 架构函数 读取数据库配置信息\n     * @access public\n     * @param array $config 数据库配置数组\n     */\n    public function __construct($config = '')\n    {\n        if (!empty($config)) {\n            $this->config = array_merge($this->config, $config);\n            if (is_array($this->config['params'])) {\n                $this->options += $this->config['params'];\n            }\n        }\n    }\n\n    /**\n     * 连接数据库方法\n     * @access public\n     */\n    public function connect($config = '', $linkNum = 0)\n    {\n        if (!isset($this->linkID[$linkNum])) {\n            if (empty($config)) {\n                $config = $this->config;\n            }\n\n            try {\n                if (empty($config['dsn'])) {\n                    $config['dsn'] = $this->parseDsn($config);\n                }\n                if (version_compare(PHP_VERSION, '5.3.6', '<=')) {\n                    //禁用模拟预处理语句\n                    $this->options[PDO::ATTR_EMULATE_PREPARES] = false;\n                }\n                $this->linkID[$linkNum] = new PDO($config['dsn'], $config['username'], $config['password'], $this->options);\n            } catch (\\PDOException $e) {\n                E($e->getMessage());\n            }\n        }\n        return $this->linkID[$linkNum];\n    }\n\n    /**\n     * 解析pdo连接的dsn信息\n     * @access public\n     * @param array $config 连接信息\n     * @return string\n     */\n    protected function parseDsn($config)\n    {}\n\n    /**\n     * 释放查询结果\n     * @access public\n     */\n    public function free()\n    {\n        $this->PDOStatement = null;\n    }\n\n    /**\n     * 执行查询 返回数据集\n     * @access public\n     * @param string $str  sql指令\n     * @param array $bind  参数绑定\n     * @return mixed\n     */\n    public function query($str, $bind = array())\n    {\n        $this->initConnect(false);\n        if (!$this->_linkID) {\n            return false;\n        }\n\n        $this->queryStr = $str;\n        if (!empty($bind)) {\n            $that           = $this;\n            $this->queryStr = strtr($this->queryStr, array_map(function ($val) use ($that) {return '\\'' . $that->escapeString($val) . '\\'';}, $bind));\n        }\n        //释放前次的查询结果\n        if (!empty($this->PDOStatement)) {\n            $this->free();\n        }\n\n        $this->queryTimes++;\n        N('db_query', 1); // 兼容代码\n        // 调试开始\n        $this->debug(true);\n        $this->PDOStatement = $this->_linkID->prepare($str);\n        if (false === $this->PDOStatement) {\n            E($this->error());\n        }\n\n        foreach ($bind as $key => $val) {\n            if (is_array($val)) {\n                $this->PDOStatement->bindValue($key, $val[0], $val[1]);\n            } else {\n                $this->PDOStatement->bindValue($key, $val);\n            }\n        }\n        $result = $this->PDOStatement->execute();\n        // 调试结束\n        $this->debug(false);\n        if (false === $result) {\n            $this->error();\n            return false;\n        } else {\n            return $this->getResult();\n        }\n    }\n\n    /**\n     * 执行语句\n     * @access public\n     * @param string $str  sql指令\n     * @param array $bind  参数绑定\n     * @return integer\n     */\n    public function execute($str, $bind = array())\n    {\n        $this->initConnect(true);\n        if (!$this->_linkID) {\n            return false;\n        }\n\n        $this->queryStr = $str;\n        if (!empty($bind)) {\n            $that           = $this;\n            $this->queryStr = strtr($this->queryStr, array_map(function ($val) use ($that) {return '\\'' . $that->escapeString($val) . '\\'';}, $bind));\n        }\n        //释放前次的查询结果\n        if (!empty($this->PDOStatement)) {\n            $this->free();\n        }\n\n        $this->executeTimes++;\n        N('db_write', 1); // 兼容代码\n        // 记录开始执行时间\n        $this->debug(true);\n        $this->PDOStatement = $this->_linkID->prepare($str);\n        if (false === $this->PDOStatement) {\n            E($this->error());\n        }\n        foreach ($bind as $key => $val) {\n            if (is_array($val)) {\n                $this->PDOStatement->bindValue($key, $val[0], $val[1]);\n            } else {\n                $this->PDOStatement->bindValue($key, $val);\n            }\n        }\n        $result = $this->PDOStatement->execute();\n        $this->debug(false);\n        if (false === $result) {\n            $this->error();\n            return false;\n        } else {\n            $this->numRows = $this->PDOStatement->rowCount();\n            if (preg_match(\"/^\\s*(INSERT\\s+INTO|REPLACE\\s+INTO)\\s+/i\", $str)) {\n                $this->lastInsID = $this->_linkID->lastInsertId();\n            }\n            return $this->numRows;\n        }\n    }\n\n    /**\n     * 启动事务\n     * @access public\n     * @return void\n     */\n    public function startTrans()\n    {\n        $this->initConnect(true);\n        if (!$this->_linkID) {\n            return false;\n        }\n\n        //数据rollback 支持\n        if (0 == $this->transTimes) {\n            // 记录当前操作PDO\n            $this->transPdo = $this->_linkID;\n            $this->_linkID->beginTransaction();\n        }\n        $this->transTimes++;\n        return;\n    }\n\n    /**\n     * 用于非自动提交状态下面的查询提交\n     * @access public\n     * @return boolean\n     */\n    public function commit()\n    {\n        if ($this->transTimes == 1) {\n            // 由嵌套事物的最外层进行提交\n            $result = $this->_linkID->commit();\n            $this->transTimes = 0;\n            $this->transPdo = null;\n            if (!$result) {\n                $this->error();\n                return false;\n            }\n        } else {\n            $this->transTimes--;\n        }\n        return true;\n    }\n\n    /**\n     * 事务回滚\n     * @access public\n     * @return boolean\n     */\n    public function rollback()\n    {\n        if ($this->transTimes > 0) {\n            $result = $this->_linkID->rollback();\n            $this->transTimes = 0;\n            $this->transPdo = null;\n            if (!$result) {\n                $this->error();\n                return false;\n            }\n        }\n        return true;\n    }\n\n    /**\n     * 获得所有的查询数据\n     * @access private\n     * @return array\n     */\n    private function getResult()\n    {\n        //返回数据集\n        $result        = $this->PDOStatement->fetchAll(PDO::FETCH_ASSOC);\n        $this->numRows = count($result);\n        return $result;\n    }\n\n    /**\n     * 获得查询次数\n     * @access public\n     * @param boolean $execute 是否包含所有查询\n     * @return integer\n     */\n    public function getQueryTimes($execute = false)\n    {\n        return $execute ? $this->queryTimes + $this->executeTimes : $this->queryTimes;\n    }\n\n    /**\n     * 获得执行次数\n     * @access public\n     * @return integer\n     */\n    public function getExecuteTimes()\n    {\n        return $this->executeTimes;\n    }\n\n    /**\n     * 关闭数据库\n     * @access public\n     */\n    public function close()\n    {\n        $this->_linkID = null;\n    }\n\n    /**\n     * 数据库错误信息\n     * 并显示当前的SQL语句\n     * @access public\n     * @return string\n     */\n    public function error()\n    {\n        if ($this->PDOStatement) {\n            $error       = $this->PDOStatement->errorInfo();\n            $this->error = $error[1] . ':' . $error[2];\n        } else {\n            $this->error = '';\n        }\n        if ('' != $this->queryStr) {\n            $this->error .= \"\\n [ SQL语句 ] : \" . $this->queryStr;\n        }\n        // 记录错误日志\n        trace($this->error, '', 'ERR');\n        if ($this->config['debug']) {\n            // 开启数据库调试模式\n            E($this->error);\n        } else {\n            return $this->error;\n        }\n    }\n\n    /**\n     * 获取最近一次查询的sql语句\n     * @param string $model  模型名\n     * @access public\n     * @return string\n     */\n    public function getLastSql($model = '')\n    {\n        return $model ? $this->modelSql[$model] : $this->queryStr;\n    }\n\n    /**\n     * 获取最近插入的ID\n     * @access public\n     * @return string\n     */\n    public function getLastInsID()\n    {\n        return $this->lastInsID;\n    }\n\n    /**\n     * 获取最近的错误信息\n     * @access public\n     * @return string\n     */\n    public function getError()\n    {\n        return $this->error;\n    }\n\n    /**\n     * SQL指令安全过滤\n     * @access public\n     * @param string $str  SQL字符串\n     * @return string\n     */\n    public function escapeString($str)\n    {\n        return addslashes($str);\n    }\n\n    /**\n     * 设置当前操作模型\n     * @access public\n     * @param string $model  模型名\n     * @return void\n     */\n    public function setModel($model)\n    {\n        $this->model = $model;\n    }\n\n    /**\n     * 数据库调试 记录当前SQL\n     * @access protected\n     * @param boolean $start  调试开始标记 true 开始 false 结束\n     */\n    protected function debug($start)\n    {\n        if ($this->config['debug']) {\n            // 开启数据库调试模式\n            if ($start) {\n                G('queryStartTime');\n            } else {\n                $this->modelSql[$this->model] = $this->queryStr;\n                //$this->model  =   '_think_';\n                // 记录操作结束时间\n                G('queryEndTime');\n                trace($this->queryStr . ' [ RunTime:' . G('queryStartTime', 'queryEndTime') . 's ]', '', 'SQL');\n            }\n        }\n    }\n\n    /**\n     * 初始化数据库连接\n     * @access protected\n     * @param boolean $master 主服务器\n     * @return void\n     */\n    protected function initConnect($master = true)\n    {\n        // 开启事物时用同一个连接进行操作\n        if ($this->transPDO) {\n            return $this->transPDO;\n        }\n\n        if (!empty($this->config['deploy']))\n        // 采用分布式数据库\n        {\n            $this->_linkID = $this->multiConnect($master);\n        } else\n        // 默认单数据库\n        if (!$this->_linkID) {\n            $this->_linkID = $this->connect();\n        }\n\n    }\n\n    /**\n     * 连接分布式服务器\n     * @access protected\n     * @param boolean $master 主服务器\n     * @return void\n     */\n    protected function multiConnect($master = false)\n    {\n        // 分布式数据库配置解析\n        $_config['username'] = explode(',', $this->config['username']);\n        $_config['password'] = explode(',', $this->config['password']);\n        $_config['hostname'] = explode(',', $this->config['hostname']);\n        $_config['hostport'] = explode(',', $this->config['hostport']);\n        $_config['database'] = explode(',', $this->config['database']);\n        $_config['dsn']      = explode(',', $this->config['dsn']);\n        $_config['charset']  = explode(',', $this->config['charset']);\n\n        // 数据库读写是否分离\n        if ($this->config['rw_separate']) {\n            // 主从式采用读写分离\n            if ($master)\n            // 主服务器写入\n            {\n                $r = floor(mt_rand(0, $this->config['master_num'] - 1));\n            } else {\n                if (is_numeric($this->config['slave_no'])) {\n// 指定服务器读\n                    $r = $this->config['slave_no'];\n                } else {\n                    // 读操作连接从服务器\n                    $r = floor(mt_rand($this->config['master_num'], count($_config['hostname']) - 1)); // 每次随机连接的数据库\n                }\n            }\n        } else {\n            // 读写操作不区分服务器\n            $r = floor(mt_rand(0, count($_config['hostname']) - 1)); // 每次随机连接的数据库\n        }\n        $db_config = array(\n            'username' => isset($_config['username'][$r]) ? $_config['username'][$r] : $_config['username'][0],\n            'password' => isset($_config['password'][$r]) ? $_config['password'][$r] : $_config['password'][0],\n            'hostname' => isset($_config['hostname'][$r]) ? $_config['hostname'][$r] : $_config['hostname'][0],\n            'hostport' => isset($_config['hostport'][$r]) ? $_config['hostport'][$r] : $_config['hostport'][0],\n            'database' => isset($_config['database'][$r]) ? $_config['database'][$r] : $_config['database'][0],\n            'dsn'      => isset($_config['dsn'][$r]) ? $_config['dsn'][$r] : $_config['dsn'][0],\n            'charset'  => isset($_config['charset'][$r]) ? $_config['charset'][$r] : $_config['charset'][0],\n        );\n        return $this->connect($db_config, $r);\n    }\n\n    /**\n     * 析构方法\n     * @access public\n     */\n    public function __destruct()\n    {\n        // 释放查询\n        if ($this->PDOStatement) {\n            $this->free();\n        }\n        // 关闭连接\n        $this->close();\n    }\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Db.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace Think;\n\n/**\n * ThinkPHP 数据库中间层实现类\n */\nclass Db {\n\n    static private  $instance   =  array();     //  数据库连接实例\n    static private  $_instance  =  null;   //  当前数据库连接实例\n\n    /**\n     * 取得数据库类实例\n     * @static\n     * @access public\n     * @param mixed $config 连接配置\n     * @return Object 返回数据库驱动类\n     */\n    static public function getInstance($config=array()) {\n        $md5    =   md5(serialize($config));\n        if(!isset(self::$instance[$md5])) {\n            // 解析连接参数 支持数组和字符串\n            $options    =   self::parseConfig($config);\n            // 兼容mysqli\n            if('mysqli' == $options['type']) $options['type']   =   'mysql';\n            // 如果采用lite方式 仅支持原生SQL 包括query和execute方法\n            $class  =   !empty($options['lite'])?  'Think\\Db\\Lite' :   'Think\\\\Db\\\\Driver\\\\'.ucwords(strtolower($options['type']));\n            if(class_exists($class)){\n                self::$instance[$md5]   =   new $class($options);\n            }else{\n                // 类没有定义\n                E(L('_NO_DB_DRIVER_').': ' . $class);\n            }\n        }\n        self::$_instance    =   self::$instance[$md5];\n        return self::$_instance;\n    }\n\n    /**\n     * 数据库连接参数解析\n     * @static\n     * @access private\n     * @param mixed $config\n     * @return array\n     */\n    static private function parseConfig($config){\n        if(!empty($config)){\n            if(is_string($config)) {\n                return self::parseDsn($config);\n            }\n            $config =   array_change_key_case($config);\n            $config = array (\n                'type'          =>  $config['db_type'],\n                'username'      =>  $config['db_user'],\n                'password'      =>  $config['db_pwd'],\n                'hostname'      =>  $config['db_host'],\n                'hostport'      =>  $config['db_port'],\n                'database'      =>  $config['db_name'],\n                'dsn'           =>  isset($config['db_dsn'])?$config['db_dsn']:null,\n                'params'        =>  isset($config['db_params'])?$config['db_params']:null,\n                'charset'       =>  isset($config['db_charset'])?$config['db_charset']:'utf8',\n                'deploy'        =>  isset($config['db_deploy_type'])?$config['db_deploy_type']:0,\n                'rw_separate'   =>  isset($config['db_rw_separate'])?$config['db_rw_separate']:false,\n                'master_num'    =>  isset($config['db_master_num'])?$config['db_master_num']:1,\n                'slave_no'      =>  isset($config['db_slave_no'])?$config['db_slave_no']:'',\n                'debug'         =>  isset($config['db_debug'])?$config['db_debug']:APP_DEBUG,\n                'lite'          =>  isset($config['db_lite'])?$config['db_lite']:false,\n            );\n        }else {\n            $config = array (\n                'type'          =>  C('DB_TYPE'),\n                'username'      =>  C('DB_USER'),\n                'password'      =>  C('DB_PWD'),\n                'hostname'      =>  C('DB_HOST'),\n                'hostport'      =>  C('DB_PORT'),\n                'database'      =>  C('DB_NAME'),\n                'dsn'           =>  C('DB_DSN'),\n                'params'        =>  C('DB_PARAMS'),\n                'charset'       =>  C('DB_CHARSET'),\n                'deploy'        =>  C('DB_DEPLOY_TYPE'),\n                'rw_separate'   =>  C('DB_RW_SEPARATE'),\n                'master_num'    =>  C('DB_MASTER_NUM'),\n                'slave_no'      =>  C('DB_SLAVE_NO'),\n                'debug'         =>  C('DB_DEBUG',null,APP_DEBUG),\n                'lite'          =>  C('DB_LITE'),\n            );\n        }\n        return $config;\n    }\n\n    /**\n     * DSN解析\n     * 格式： mysql://username:passwd@localhost:3306/DbName?param1=val1&param2=val2#utf8\n     * @static\n     * @access private\n     * @param string $dsnStr\n     * @return array\n     */\n    static private function parseDsn($dsnStr) {\n        if( empty($dsnStr) ){return false;}\n        $info = parse_url($dsnStr);\n        if(!$info) {\n            return false;\n        }\n        $dsn = array(\n            'type'      =>  $info['scheme'],\n            'username'  =>  isset($info['user']) ? $info['user'] : '',\n            'password'  =>  isset($info['pass']) ? $info['pass'] : '',\n            'hostname'  =>  isset($info['host']) ? $info['host'] : '',\n            'hostport'  =>  isset($info['port']) ? $info['port'] : '',\n            'database'  =>  isset($info['path']) ? substr($info['path'],1) : '',\n            'charset'   =>  isset($info['fragment'])?$info['fragment']:'utf8',\n        );\n        \n        if(isset($info['query'])) {\n            parse_str($info['query'],$dsn['params']);\n        }else{\n            $dsn['params']  =   array();\n        }\n        return $dsn;\n     }\n\n    // 调用驱动类的方法\n    static public function __callStatic($method, $params){\n        return call_user_func_array(array(self::$_instance, $method), $params);\n    }\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Dispatcher.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\nnamespace Think;\n/**\n * ThinkPHP内置的Dispatcher类\n * 完成URL解析、路由和调度\n */\nclass Dispatcher {\n\n    /**\n     * URL映射到控制器\n     * @access public\n     * @return void\n     */\n    static public function dispatch() {\n        $varPath        =   C('VAR_PATHINFO');\n        $varAddon       =   C('VAR_ADDON');\n        $varModule      =   C('VAR_MODULE');\n        $varController  =   C('VAR_CONTROLLER');\n        $varAction      =   C('VAR_ACTION');\n        $urlCase        =   C('URL_CASE_INSENSITIVE');\n        if(isset($_GET[$varPath])) { // 判断URL里面是否有兼容模式参数\n            $_SERVER['PATH_INFO'] = $_GET[$varPath];\n            unset($_GET[$varPath]);\n        }elseif(IS_CLI){ // CLI模式下 index.php module/controller/action/params/...\n            $_SERVER['PATH_INFO'] = isset($_SERVER['argv'][1]) ? $_SERVER['argv'][1] : '';\n        }\n\n        // 开启子域名部署\n        if(C('APP_SUB_DOMAIN_DEPLOY')) {\n            $rules      = C('APP_SUB_DOMAIN_RULES');\n            if(isset($rules[$_SERVER['HTTP_HOST']])) { // 完整域名或者IP配置\n                define('APP_DOMAIN',$_SERVER['HTTP_HOST']); // 当前完整域名\n                $rule = $rules[APP_DOMAIN];\n            }else{\n                if(strpos(C('APP_DOMAIN_SUFFIX'),'.')){ // com.cn net.cn \n                    $domain = array_slice(explode('.', $_SERVER['HTTP_HOST']), 0, -3);\n                }else{\n                    $domain = array_slice(explode('.', $_SERVER['HTTP_HOST']), 0, -2);                    \n                }\n                if(!empty($domain)) {\n                    $subDomain = implode('.', $domain);\n                    define('SUB_DOMAIN',$subDomain); // 当前完整子域名\n                    $domain2   = array_pop($domain); // 二级域名\n                    if($domain) { // 存在三级域名\n                        $domain3 = array_pop($domain);\n                    }\n                    if(isset($rules[$subDomain])) { // 子域名\n                        $rule = $rules[$subDomain];\n                    }elseif(isset($rules['*.' . $domain2]) && !empty($domain3)){ // 泛三级域名\n                        $rule = $rules['*.' . $domain2];\n                        $panDomain = $domain3;\n                    }elseif(isset($rules['*']) && !empty($domain2) && 'www' != $domain2 ){ // 泛二级域名\n                        $rule      = $rules['*'];\n                        $panDomain = $domain2;\n                    }\n                }                \n            }\n\n            if(!empty($rule)) {\n                // 子域名部署规则 '子域名'=>array('模块名[/控制器名]','var1=a&var2=b');\n                if(is_array($rule)){\n                    list($rule,$vars) = $rule;\n                }\n                $array      =   explode('/',$rule);\n                // 模块绑定\n                define('BIND_MODULE',array_shift($array));\n                // 控制器绑定         \n                if(!empty($array)) {\n                    $controller  =   array_shift($array);\n                    if($controller){\n                        define('BIND_CONTROLLER',$controller);\n                    }\n                }\n                if(isset($vars)) { // 传入参数\n                    parse_str($vars,$parms);\n                    if(isset($panDomain)){\n                        $pos = array_search('*', $parms);\n                        if(false !== $pos) {\n                            // 泛域名作为参数\n                            $parms[$pos] = $panDomain;\n                        }                         \n                    }                   \n                    $_GET   =  array_merge($_GET,$parms);\n                }\n            }\n        }\n        // 分析PATHINFO信息\n        if(!isset($_SERVER['PATH_INFO'])) {\n            $types   =  explode(',',C('URL_PATHINFO_FETCH'));\n            foreach ($types as $type){\n                if(0===strpos($type,':')) {// 支持函数判断\n                    $_SERVER['PATH_INFO'] =   call_user_func(substr($type,1));\n                    break;\n                }elseif(!empty($_SERVER[$type])) {\n                    $_SERVER['PATH_INFO'] = (0 === strpos($_SERVER[$type],$_SERVER['SCRIPT_NAME']))?\n                        substr($_SERVER[$type], strlen($_SERVER['SCRIPT_NAME']))   :  $_SERVER[$type];\n                    break;\n                }\n            }\n        }\n\n        $depr = C('URL_PATHINFO_DEPR');\n        define('MODULE_PATHINFO_DEPR',  $depr);\n\n        if(empty($_SERVER['PATH_INFO'])) {\n            $_SERVER['PATH_INFO'] = '';\n            define('__INFO__','');\n            define('__EXT__','');\n        }else{\n            define('__INFO__',trim($_SERVER['PATH_INFO'],'/'));\n            // URL后缀\n            define('__EXT__', strtolower(pathinfo($_SERVER['PATH_INFO'],PATHINFO_EXTENSION)));\n            $_SERVER['PATH_INFO'] = __INFO__;     \n            if(!defined('BIND_MODULE') && (!C('URL_ROUTER_ON') || !Route::check())){\n                if (__INFO__ && C('MULTI_MODULE')){ // 获取模块名\n                    $paths      =   explode($depr,__INFO__,2);\n                    $allowList  =   C('MODULE_ALLOW_LIST'); // 允许的模块列表\n                    $module     =   preg_replace('/\\.' . __EXT__ . '$/i', '',$paths[0]);\n                    if( empty($allowList) || (is_array($allowList) && in_array_case($module, $allowList))){\n                        $_GET[$varModule]       =   $module;\n                        $_SERVER['PATH_INFO']   =   isset($paths[1])?$paths[1]:'';\n                    }\n                }\n            }             \n        }\n\n        // URL常量\n        define('__SELF__',strip_tags($_SERVER[C('URL_REQUEST_URI')]));\n\n        // 获取模块名称\n        define('MODULE_NAME', defined('BIND_MODULE')? BIND_MODULE : self::getModule($varModule));\n        \n        // 检测模块是否存在\n        if( MODULE_NAME && (defined('BIND_MODULE') || !in_array_case(MODULE_NAME,C('MODULE_DENY_LIST')) ) && is_dir(APP_PATH.MODULE_NAME)){\n            // 定义当前模块路径\n            define('MODULE_PATH', APP_PATH.MODULE_NAME.'/');\n            // 定义当前模块的模版缓存路径\n            C('CACHE_PATH',CACHE_PATH.MODULE_NAME.'/');\n            // 定义当前模块的日志目录\n\t        C('LOG_PATH',  realpath(LOG_PATH).'/'.MODULE_NAME.'/');\n\n            // 模块检测\n            Hook::listen('module_check');\n\n            // 加载模块配置文件\n            if(is_file(MODULE_PATH.'Conf/config'.CONF_EXT))\n                C(load_config(MODULE_PATH.'Conf/config'.CONF_EXT));\n            // 加载应用模式对应的配置文件\n            if('common' != APP_MODE && is_file(MODULE_PATH.'Conf/config_'.APP_MODE.CONF_EXT))\n                C(load_config(MODULE_PATH.'Conf/config_'.APP_MODE.CONF_EXT));\n            // 当前应用状态对应的配置文件\n            if(APP_STATUS && is_file(MODULE_PATH.'Conf/'.APP_STATUS.CONF_EXT))\n                C(load_config(MODULE_PATH.'Conf/'.APP_STATUS.CONF_EXT));\n\n            // 加载模块别名定义\n            if(is_file(MODULE_PATH.'Conf/alias.php'))\n                Think::addMap(include MODULE_PATH.'Conf/alias.php');\n            // 加载模块tags文件定义\n            if(is_file(MODULE_PATH.'Conf/tags.php'))\n                Hook::import(include MODULE_PATH.'Conf/tags.php');\n            // 加载模块函数文件\n            if(is_file(MODULE_PATH.'Common/function.php'))\n                include MODULE_PATH.'Common/function.php';\n            \n            $urlCase        =   C('URL_CASE_INSENSITIVE');\n            // 加载模块的扩展配置文件\n            load_ext_file(MODULE_PATH);\n        }else{\n            E(L('_MODULE_NOT_EXIST_').':'.MODULE_NAME);\n        }\n\n        if(!defined('__APP__')){\n\t        $urlMode        =   C('URL_MODEL');\n\t        if($urlMode == URL_COMPAT ){// 兼容模式判断\n\t            define('PHP_FILE',_PHP_FILE_.'?'.$varPath.'=');\n\t        }elseif($urlMode == URL_REWRITE ) {\n\t            $url    =   dirname(_PHP_FILE_);\n\t            if($url == '/' || $url == '\\\\')\n\t                $url    =   '';\n\t            define('PHP_FILE',$url);\n\t        }else {\n\t            define('PHP_FILE',_PHP_FILE_);\n\t        }\n\t        // 当前应用地址\n\t        define('__APP__',strip_tags(PHP_FILE));\n\t    }\n        // 模块URL地址\n        $moduleName    =   defined('MODULE_ALIAS')? MODULE_ALIAS : MODULE_NAME;\n        define('__MODULE__',(defined('BIND_MODULE') || !C('MULTI_MODULE'))? __APP__ : __APP__.'/'.($urlCase ? strtolower($moduleName) : $moduleName));\n\n        if('' != $_SERVER['PATH_INFO'] && (!C('URL_ROUTER_ON') ||  !Route::check()) ){   // 检测路由规则 如果没有则按默认规则调度URL\n            Hook::listen('path_info');\n            // 检查禁止访问的URL后缀\n            if(C('URL_DENY_SUFFIX') && preg_match('/\\.('.trim(C('URL_DENY_SUFFIX'),'.').')$/i', $_SERVER['PATH_INFO'])){\n                send_http_status(404);\n                exit;\n            }\n            \n            // 去除URL后缀\n            $_SERVER['PATH_INFO'] = preg_replace(C('URL_HTML_SUFFIX')? '/\\.('.trim(C('URL_HTML_SUFFIX'),'.').')$/i' : '/\\.'.__EXT__.'$/i', '', $_SERVER['PATH_INFO']);\n\n            $depr   =   C('URL_PATHINFO_DEPR');\n            $paths  =   explode($depr,trim($_SERVER['PATH_INFO'],$depr));\n\n            if(!defined('BIND_CONTROLLER')) {// 获取控制器\n                if(C('CONTROLLER_LEVEL')>1){// 控制器层次\n                    $_GET[$varController]   =   implode('/',array_slice($paths,0,C('CONTROLLER_LEVEL')));\n                    $paths  =   array_slice($paths, C('CONTROLLER_LEVEL'));\n                }else{\n                    $_GET[$varController]   =   array_shift($paths);\n                }\n            }\n            // 获取操作\n            if(!defined('BIND_ACTION')){\n                $_GET[$varAction]  =   array_shift($paths);\n            }\n            // 解析剩余的URL参数\n            $var  =  array();\n            if(C('URL_PARAMS_BIND') && 1 == C('URL_PARAMS_BIND_TYPE')){\n                // URL参数按顺序绑定变量\n                $var    =   $paths;\n            }else{\n                preg_replace_callback('/(\\w+)\\/([^\\/]+)/', function($match) use(&$var){$var[$match[1]]=strip_tags($match[2]);}, implode('/',$paths));\n            }\n            $_GET   =  array_merge($var,$_GET);\n        }\n        // 获取控制器的命名空间（路径）\n        define('CONTROLLER_PATH',   self::getSpace($varAddon,$urlCase));\n        // 获取控制器和操作名\n        define('CONTROLLER_NAME',   defined('BIND_CONTROLLER')? BIND_CONTROLLER : self::getController($varController,$urlCase));\n        define('ACTION_NAME',       defined('BIND_ACTION')? BIND_ACTION : self::getAction($varAction,$urlCase));\n\n        // 当前控制器的UR地址\n        $controllerName    =   defined('CONTROLLER_ALIAS')? CONTROLLER_ALIAS : CONTROLLER_NAME;\n        define('__CONTROLLER__',__MODULE__.$depr.(defined('BIND_CONTROLLER')? '': ( $urlCase ? parse_name($controllerName) : $controllerName )) );\n\n        // 当前操作的URL地址\n        define('__ACTION__',__CONTROLLER__.$depr.(defined('ACTION_ALIAS')?ACTION_ALIAS:ACTION_NAME));\n\n        //保证$_REQUEST正常取值\n        $_REQUEST = array_merge($_POST,$_GET,$_COOKIE);\t// -- 加了$_COOKIE.  保证哦..\n    }\n\n    /**\n     * 获得控制器的命名空间路径 便于插件机制访问\n     */\n    static private function getSpace($var,$urlCase) {\n        $space  =   !empty($_GET[$var])?strip_tags($_GET[$var]):'';\n        unset($_GET[$var]);\n        return $space;\n    }\n\n    /**\n     * 获得实际的控制器名称\n     */\n    static private function getController($var,$urlCase) {\n        $controller = (!empty($_GET[$var])? $_GET[$var]:C('DEFAULT_CONTROLLER'));\n        unset($_GET[$var]);\n        if($maps = C('URL_CONTROLLER_MAP')) {\n            if(isset($maps[strtolower($controller)])) {\n                // 记录当前别名\n                define('CONTROLLER_ALIAS',strtolower($controller));\n                // 获取实际的控制器名\n                return   ucfirst($maps[CONTROLLER_ALIAS]);\n            }elseif(array_search(strtolower($controller),$maps)){\n                // 禁止访问原始控制器\n                return   '';\n            }\n        }\n        if($urlCase) {\n            // URL地址不区分大小写\n            // 智能识别方式 user_type 识别到 UserTypeController 控制器\n            $controller = parse_name($controller,1);\n        }\n        return strip_tags(ucfirst($controller));\n    }\n\n    /**\n     * 获得实际的操作名称\n     */\n    static private function getAction($var,$urlCase) {\n        $action   = !empty($_POST[$var]) ?\n            $_POST[$var] :\n            (!empty($_GET[$var])?$_GET[$var]:C('DEFAULT_ACTION'));\n        unset($_POST[$var],$_GET[$var]);\n        if($maps = C('URL_ACTION_MAP')) {\n            if(isset($maps[strtolower(CONTROLLER_NAME)])) {\n                $maps =   $maps[strtolower(CONTROLLER_NAME)];\n                if(isset($maps[strtolower($action)])) {\n                    // 记录当前别名\n                    define('ACTION_ALIAS',strtolower($action));\n                    // 获取实际的操作名\n                    if(is_array($maps[ACTION_ALIAS])){\n                        parse_str($maps[ACTION_ALIAS][1],$vars);\n                        $_GET   =   array_merge($_GET,$vars);\n                        return $maps[ACTION_ALIAS][0];\n                    }else{\n                        return $maps[ACTION_ALIAS];\n                    }\n                    \n                }elseif(array_search(strtolower($action),$maps)){\n                    // 禁止访问原始操作\n                    return   '';\n                }\n            }\n        }\n        return strip_tags( $urlCase? strtolower($action) : $action );\n    }\n\n    /**\n     * 获得实际的模块名称\n     */\n    static private function getModule($var) {\n        $module   = (!empty($_GET[$var])?$_GET[$var]:C('DEFAULT_MODULE'));\n        unset($_GET[$var]);\n        if($maps = C('URL_MODULE_MAP')) {\n            if(isset($maps[strtolower($module)])) {\n                // 记录当前别名\n                define('MODULE_ALIAS',strtolower($module));\n                // 获取实际的模块名\n                return   ucfirst($maps[MODULE_ALIAS]);\n            }elseif(array_search(strtolower($module),$maps)){\n                // 禁止访问原始模块\n                return   '';\n            }\n        }\n        return strip_tags(ucfirst($module));\n    }\n\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Exception.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\nnamespace Think;\n/**\n * ThinkPHP系统异常基类\n */\nclass Exception extends \\Exception {\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Hook.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006~2013 http://topthink.com All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\nnamespace Think;\n/**\n * ThinkPHP系统钩子实现\n */\nclass Hook {\n\n    static private  $tags       =   array();\n\n    /**\n     * 动态添加插件到某个标签\n     * @param string $tag 标签名称\n     * @param mixed $name 插件名称\n     * @return void\n     */\n    static public function add($tag,$name) {\n        if(!isset(self::$tags[$tag])){\n            self::$tags[$tag]   =   array();\n        }\n        if(is_array($name)){\n            self::$tags[$tag]   =   array_merge(self::$tags[$tag],$name);\n        }else{\n            self::$tags[$tag][] =   $name;\n        }\n    }\n\n    /**\n     * 批量导入插件\n     * @param array $data 插件信息\n     * @param boolean $recursive 是否递归合并\n     * @return void\n     */\n    static public function import($data,$recursive=true) {\n        if(!$recursive){ // 覆盖导入\n            self::$tags   =   array_merge(self::$tags,$data);\n        }else{ // 合并导入\n            foreach ($data as $tag=>$val){\n                if(!isset(self::$tags[$tag]))\n                    self::$tags[$tag]   =   array();            \n                if(!empty($val['_overlay'])){\n                    // 可以针对某个标签指定覆盖模式\n                    unset($val['_overlay']);\n                    self::$tags[$tag]   =   $val;\n                }else{\n                    // 合并模式\n                    self::$tags[$tag]   =   array_merge(self::$tags[$tag],$val);\n                }\n            }            \n        }\n    }\n\n    /**\n     * 获取插件信息\n     * @param string $tag 插件位置 留空获取全部\n     * @return array\n     */\n    static public function get($tag='') {\n        if(empty($tag)){\n            // 获取全部的插件信息\n            return self::$tags;\n        }else{\n            return self::$tags[$tag];\n        }\n    }\n\n    /**\n     * 监听标签的插件\n     * @param string $tag 标签名称\n     * @param mixed $params 传入参数\n     * @return void\n     */\n    static public function listen($tag, &$params=NULL) {\n        if(isset(self::$tags[$tag])) {\n            if(APP_DEBUG) {\n                G($tag.'Start');\n                trace('[ '.$tag.' ] --START--','','INFO');\n            }\n            foreach (self::$tags[$tag] as $name) {\n                APP_DEBUG && G($name.'_start');\n                $result =   self::exec($name, $tag,$params);\n                if(APP_DEBUG){\n                    G($name.'_end');\n                    trace('Run '.$name.' [ RunTime:'.G($name.'_start',$name.'_end',6).'s ]','','INFO');\n                }\n                if(false === $result) {\n                    // 如果返回false 则中断插件执行\n                    return ;\n                }\n            }\n            if(APP_DEBUG) { // 记录行为的执行日志\n                trace('[ '.$tag.' ] --END-- [ RunTime:'.G($tag.'Start',$tag.'End',6).'s ]','','INFO');\n            }\n        }\n        return;\n    }\n\n    /**\n     * 执行某个插件\n     * @param string $name 插件名称\n     * @param string $tag 方法名（标签名）     \n     * @param Mixed $params 传入的参数\n     * @return void\n     */\n    static public function exec($name, $tag,&$params=NULL) {\n        if('Behavior' == substr($name,-8) ){\n            // 行为扩展必须用run入口方法\n            $tag    =   'run';\n        }\n        $addon   = new $name();\n        return $addon->$tag($params);\n    }\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Log/Driver/File.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | TOPThink [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2011 http://topthink.com All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace Think\\Log\\Driver;\n\nclass File {\n\n    protected $config  =   array(\n        'log_time_format'   =>  ' c ',\n        'log_file_size'     =>  2097152,\n        'log_path'          =>  '',\n    );\n\n    // 实例化并传入参数\n    public function __construct($config=array()){\n        $this->config   =   array_merge($this->config,$config);\n    }\n\n    /**\n     * 日志写入接口\n     * @access public\n     * @param string $log 日志信息\n     * @param string $destination  写入目标\n     * @return void\n     */\n    public function write($log,$destination='') {\n        $now = date($this->config['log_time_format']);\n        if(empty($destination)){\n            $destination = $this->config['log_path'].date('y_m_d').'.log';\n        }\n        // 自动创建日志目录\n        $log_dir = dirname($destination);\n        if (!is_dir($log_dir)) {\n            mkdir($log_dir, 0755, true);\n        }        \n        //检测日志文件大小，超过配置大小则备份日志文件重新生成\n        if(is_file($destination) && floor($this->config['log_file_size']) <= filesize($destination) ){\n            rename($destination,dirname($destination).'/'.time().'-'.basename($destination));\n        }\n        error_log(\"[{$now}] \".$_SERVER['REMOTE_ADDR'].' '.$_SERVER['REQUEST_URI'].\"\\r\\n{$log}\\r\\n\", 3,$destination);\n    }\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Log/Driver/Sae.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | TOPThink [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2011 http://topthink.com All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: luofei614 <weibo.com/luofei614>\n// +----------------------------------------------------------------------\n\nnamespace Think\\Log\\Driver;\n\nclass Sae {\n\n    protected $config  =   array(\n        'log_time_format'   =>  ' c ',\n    );\n\n    // 实例化并传入参数\n    public function __construct($config=array()){\n        $this->config   =   array_merge($this->config,$config);\n    }\n\n    /**\n     * 日志写入接口\n     * @access public\n     * @param string $log 日志信息\n     * @param string $destination  写入目标\n     * @return void\n     */\n    public function write($log,$destination='') {\n        static $is_debug=null;\n        $now = date($this->config['log_time_format']);\n        $logstr=\"[{$now}] \".$_SERVER['REMOTE_ADDR'].' '.$_SERVER['REQUEST_URI'].\"\\r\\n{$log}\\r\\n\";\n        if(is_null($is_debug)){\n            preg_replace('@(\\w+)\\=([^;]*)@e', '$appSettings[\\'\\\\1\\']=\"\\\\2\";', $_SERVER['HTTP_APPCOOKIE']);\n            $is_debug = in_array($_SERVER['HTTP_APPVERSION'], explode(',', $appSettings['debug'])) ? true : false;\n        }\n        if($is_debug){\n            sae_set_display_errors(false);//记录日志不将日志打印出来\n        }\n        sae_debug($logstr);\n        if($is_debug){\n            sae_set_display_errors(true);\n        }\n\n    }\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Log.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\nnamespace Think;\n/**\n * 日志处理类\n */\nclass Log {\n\n    // 日志级别 从上到下，由低到高\n    const EMERG     = 'EMERG';  // 严重错误: 导致系统崩溃无法使用\n    const ALERT     = 'ALERT';  // 警戒性错误: 必须被立即修改的错误\n    const CRIT      = 'CRIT';  // 临界值错误: 超过临界值的错误，例如一天24小时，而输入的是25小时这样\n    const ERR       = 'ERR';  // 一般错误: 一般性错误\n    const WARN      = 'WARN';  // 警告性错误: 需要发出警告的错误\n    const NOTICE    = 'NOTIC';  // 通知: 程序可以运行但是还不够完美的错误\n    const INFO      = 'INFO';  // 信息: 程序输出信息\n    const DEBUG     = 'DEBUG';  // 调试: 调试信息\n    const SQL       = 'SQL';  // SQL：SQL语句 注意只在调试模式开启时有效\n\n    // 日志信息\n    static protected $log       =  array();\n\n    // 日志存储\n    static protected $storage   =   null;\n\n    // 日志初始化\n    static public function init($config=array()){\n        $type   =   isset($config['type']) ? $config['type'] : 'File';\n        $class  =   strpos($type,'\\\\')? $type: 'Think\\\\Log\\\\Driver\\\\'. ucwords(strtolower($type));           \n        unset($config['type']);\n        self::$storage = new $class($config);\n    }\n\n    /**\n     * 记录日志 并且会过滤未经设置的级别\n     * @static\n     * @access public\n     * @param string $message 日志信息\n     * @param string $level  日志级别\n     * @param boolean $record  是否强制记录\n     * @return void\n     */\n    static function record($message,$level=self::ERR,$record=false) {\n        if($record || false !== strpos(C('LOG_LEVEL'),$level)) {\n            self::$log[] =   \"{$level}: {$message}\\r\\n\";\n        }\n    }\n\n    /**\n     * 日志保存\n     * @static\n     * @access public\n     * @param integer $type 日志记录方式\n     * @param string $destination  写入目标\n     * @return void\n     */\n    static function save($type='',$destination='') {\n        if(empty(self::$log)) return ;\n\n        if(empty($destination)){\n            $destination = C('LOG_PATH').date('y_m_d').'.log';\n        }\n        if(!self::$storage){\n            $type \t= \t$type ? : C('LOG_TYPE');\n            $class  =   'Think\\\\Log\\\\Driver\\\\'. ucwords($type);\n            self::$storage = new $class();            \n        }\n        $message    =   implode('',self::$log);\n        self::$storage->write($message,$destination);\n        // 保存后清空日志缓存\n        self::$log = array();\n    }\n\n    /**\n     * 日志直接写入\n     * @static\n     * @access public\n     * @param string $message 日志信息\n     * @param string $level  日志级别\n     * @param integer $type 日志记录方式\n     * @param string $destination  写入目标\n     * @return void\n     */\n    static function write($message,$level=self::ERR,$type='',$destination='') {\n        if(!self::$storage){\n            $type \t= \t$type ? : C('LOG_TYPE');\n            $class  =   'Think\\\\Log\\\\Driver\\\\'. ucwords($type);\n            $config['log_path'] = C('LOG_PATH');\n            self::$storage = new $class($config);            \n        }\n        if(empty($destination)){\n            $destination = C('LOG_PATH').date('y_m_d').'.log';        \n        }\n        self::$storage->write(\"{$level}: {$message}\", $destination);\n    }\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Model.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\nnamespace Think;\n\n/**\n * ThinkPHP Model模型类\n * 实现了ORM和ActiveRecords模式\n */\nclass Model\n{\n    // 操作状态\n    const MODEL_INSERT    = 1; //  插入模型数据\n    const MODEL_UPDATE    = 2; //  更新模型数据\n    const MODEL_BOTH      = 3; //  包含上面两种方式\n    const MUST_VALIDATE   = 1; // 必须验证\n    const EXISTS_VALIDATE = 0; // 表单存在字段则验证\n    const VALUE_VALIDATE  = 2; // 表单值不为空则验证\n\n    // 当前数据库操作对象\n    protected $db = null;\n    // 数据库对象池\n    private $_db = array();\n    // 主键名称\n    protected $pk = 'id';\n    // 主键是否自动增长\n    protected $autoinc = false;\n    // 数据表前缀\n    protected $tablePrefix = null;\n    // 模型名称\n    protected $name = '';\n    // 数据库名称\n    protected $dbName = '';\n    //数据库配置\n    protected $connection = '';\n    // 数据表名（不包含表前缀）\n    protected $tableName = '';\n    // 实际数据表名（包含表前缀）\n    protected $trueTableName = '';\n    // 最近错误信息\n    protected $error = '';\n    // 字段信息\n    protected $fields = array();\n    // 数据信息\n    protected $data = array();\n    // 查询表达式参数\n    protected $options   = array();\n    protected $_validate = array(); // 自动验证定义\n    protected $_auto     = array(); // 自动完成定义\n    protected $_map      = array(); // 字段映射定义\n    protected $_scope    = array(); // 命名范围定义\n    // 是否自动检测数据表字段信息\n    protected $autoCheckFields = true;\n    // 是否批处理验证\n    protected $patchValidate = false;\n    // 链操作方法列表\n    protected $methods = array('strict', 'order', 'alias', 'having', 'group', 'lock', 'distinct', 'auto', 'filter', 'validate', 'result', 'token', 'index', 'force', 'master');\n\n    /**\n     * 架构函数\n     * 取得DB类的实例对象 字段检查\n     * @access public\n     * @param string $name 模型名称\n     * @param string $tablePrefix 表前缀\n     * @param mixed $connection 数据库连接信息\n     */\n    public function __construct($name = '', $tablePrefix = '', $connection = '')\n    {\n        // 模型初始化\n        $this->_initialize();\n        // 获取模型名称\n        if (!empty($name)) {\n            if (strpos($name, '.')) {\n                // 支持 数据库名.模型名的 定义\n                list($this->dbName, $this->name) = explode('.', $name);\n            } else {\n                $this->name = $name;\n            }\n        } elseif (empty($this->name)) {\n            $this->name = $this->getModelName();\n        }\n        // 设置表前缀\n        if (is_null($tablePrefix)) {\n            // 前缀为Null表示没有前缀\n            $this->tablePrefix = '';\n        } elseif ('' != $tablePrefix) {\n            $this->tablePrefix = $tablePrefix;\n        } elseif (!isset($this->tablePrefix)) {\n            $this->tablePrefix = !empty($this->connection) && !is_null(C($this->connection . '.DB_PREFIX')) ? C($this->connection . '.DB_PREFIX') : C('DB_PREFIX');\n        }\n\n        // 数据库初始化操作\n        // 获取数据库操作对象\n        // 当前模型有独立的数据库连接信息\n        $this->db(0, empty($this->connection) ? $connection : $this->connection, true);\n    }\n\n    /**\n     * 自动检测数据表信息\n     * @access protected\n     * @return void\n     */\n    protected function _checkTableInfo()\n    {\n        // 如果不是Model类 自动记录数据表信息\n        // 只在第一次执行记录\n        if (empty($this->fields)) {\n            // 如果数据表字段没有定义则自动获取\n            if (C('DB_FIELDS_CACHE')) {\n                $fields = F('_fields/' . strtolower($this->getTableName()));\n                if ($fields) {\n                    $this->fields = $fields;\n                    if (!empty($fields['_pk'])) {\n                        $this->pk = $fields['_pk'];\n                    }\n                    return;\n                }\n            }\n            // 每次都会读取数据表信息\n            $this->flush();\n        }\n    }\n\n    /**\n     * 获取字段信息并缓存\n     * @access public\n     * @return void\n     */\n    public function flush()\n    {\n        // 缓存不存在则查询数据表信息\n        $this->db->setModel($this->name);\n        $tableName = $this->getTableName();\n        $fields    = $this->db->getFields($tableName);\n        if (!$fields) {\n            // 无法获取字段信息\n            return false;\n        }\n        $this->fields = array_keys($fields);\n        unset($this->fields['_pk']);\n        foreach ($fields as $key => $val) {\n            // 记录字段类型\n            $type[$key] = $val['type'];\n            if ($val['primary']) {\n                // 增加复合主键支持\n                if (isset($this->fields['_pk']) && null != $this->fields['_pk']) {\n                    if (is_string($this->fields['_pk'])) {\n                        $this->pk            = array($this->fields['_pk']);\n                        $this->fields['_pk'] = $this->pk;\n                    }\n                    $this->pk[]            = $key;\n                    $this->fields['_pk'][] = $key;\n                } else {\n                    $this->pk            = $key;\n                    $this->fields['_pk'] = $key;\n                }\n                if ($val['autoinc']) {\n                    $this->autoinc = true;\n                }\n\n            }\n        }\n        // 记录字段类型信息\n        $this->fields['_type'] = $type;\n\n        // 2008-3-7 增加缓存开关控制\n        if (C('DB_FIELDS_CACHE')) {\n            // 永久缓存数据表信息\n            F('_fields/' . strtolower($tableName), $this->fields);\n        }\n    }\n\n    /**\n     * 设置数据对象的值\n     * @access public\n     * @param string $name 名称\n     * @param mixed $value 值\n     * @return void\n     */\n    public function __set($name, $value)\n    {\n        // 设置数据对象属性\n        $this->data[$name] = $value;\n    }\n\n    /**\n     * 获取数据对象的值\n     * @access public\n     * @param string $name 名称\n     * @return mixed\n     */\n    public function __get($name)\n    {\n        return isset($this->data[$name]) ? $this->data[$name] : null;\n    }\n\n    /**\n     * 检测数据对象的值\n     * @access public\n     * @param string $name 名称\n     * @return boolean\n     */\n    public function __isset($name)\n    {\n        return isset($this->data[$name]);\n    }\n\n    /**\n     * 销毁数据对象的值\n     * @access public\n     * @param string $name 名称\n     * @return void\n     */\n    public function __unset($name)\n    {\n        unset($this->data[$name]);\n    }\n\n    /**\n     * 利用__call方法实现一些特殊的Model方法\n     * @access public\n     * @param string $method 方法名称\n     * @param array $args 调用参数\n     * @return mixed\n     */\n    public function __call($method, $args)\n    {\n        if (in_array(strtolower($method), $this->methods, true)) {\n            // 连贯操作的实现\n            $this->options[strtolower($method)] = $args[0];\n            return $this;\n        } elseif (in_array(strtolower($method), array('count', 'sum', 'min', 'max', 'avg'), true)) {\n            // 统计查询的实现\n            $field = isset($args[0]) ? $args[0] : '*';\n            return $this->getField(strtoupper($method) . '(' . $this->db->parseKey($field, true) . ') AS tp_' . $method);\n        } elseif (strtolower(substr($method, 0, 5)) == 'getby') {\n            // 根据某个字段获取记录\n            $field         = parse_name(substr($method, 5));\n            $where[$field] = $args[0];\n            return $this->where($where)->find();\n        } elseif (strtolower(substr($method, 0, 10)) == 'getfieldby') {\n            // 根据某个字段获取记录的某个值\n            $name         = parse_name(substr($method, 10));\n            $where[$name] = $args[0];\n            return $this->where($where)->getField($args[1]);\n        } elseif (isset($this->_scope[$method])) {\n            // 命名范围的单独调用支持\n            return $this->scope($method, $args[0]);\n        } else {\n            E(__CLASS__ . ':' . $method . L('_METHOD_NOT_EXIST_'));\n            return;\n        }\n    }\n    // 回调方法 初始化模型\n    protected function _initialize()\n    {}\n\n    /**\n     * 对保存到数据库的数据进行处理\n     * @access protected\n     * @param mixed $data 要操作的数据\n     * @return boolean\n     */\n    protected function _facade($data)\n    {\n\n        // 检查数据字段合法性\n        if (!empty($this->fields)) {\n            if (!empty($this->options['field'])) {\n                $fields = $this->options['field'];\n                unset($this->options['field']);\n                if (is_string($fields)) {\n                    $fields = explode(',', $fields);\n                }\n            } else {\n                $fields = $this->fields;\n            }\n            foreach ($data as $key => $val) {\n                if (!in_array($key, $fields, true)) {\n                    if (!empty($this->options['strict'])) {\n                        E(L('_DATA_TYPE_INVALID_') . ':[' . $key . '=>' . $val . ']');\n                    }\n                    unset($data[$key]);\n                } elseif (is_scalar($val)) {\n                    // 字段类型检查 和 强制转换\n                    $this->_parseType($data, $key);\n                }\n            }\n        }\n\n        // 安全过滤\n        if (!empty($this->options['filter'])) {\n            $data = array_map($this->options['filter'], $data);\n            unset($this->options['filter']);\n        }\n        $this->_before_write($data);\n        return $data;\n    }\n\n    // 写入数据前的回调方法 包括新增和更新\n    protected function _before_write(&$data)\n    {}\n\n    /**\n     * 新增数据\n     * @access public\n     * @param mixed $data 数据\n     * @param array $options 表达式\n     * @param boolean $replace 是否replace\n     * @return mixed\n     */\n    public function add($data = '', $options = array(), $replace = false)\n    {\n        if (empty($data)) {\n            // 没有传递数据，获取当前数据对象的值\n            if (!empty($this->data)) {\n                $data = $this->data;\n                // 重置数据\n                $this->data = array();\n            } else {\n                $this->error = L('_DATA_TYPE_INVALID_');\n                return false;\n            }\n        }\n        // 数据处理\n        $data = $this->_facade($data);\n        // 分析表达式\n        $options = $this->_parseOptions($options);\n        if (false === $this->_before_insert($data, $options)) {\n            return false;\n        }\n        // 写入数据到数据库\n        $result = $this->db->insert($data, $options, $replace);\n        if (false !== $result && is_numeric($result)) {\n            $pk = $this->getPk();\n            // 增加复合主键支持\n            if (is_array($pk)) {\n                return $result;\n            }\n\n            $insertId = $this->getLastInsID();\n            if ($insertId) {\n                // 自增主键返回插入ID\n                $data[$pk] = $insertId;\n                if (false === $this->_after_insert($data, $options)) {\n                    return false;\n                }\n                return $insertId;\n            }\n            if (false === $this->_after_insert($data, $options)) {\n                return false;\n            }\n        }\n        return $result;\n    }\n    // 插入数据前的回调方法\n    protected function _before_insert(&$data, $options)\n    {}\n    // 插入成功后的回调方法\n    protected function _after_insert($data, $options)\n    {}\n\n    public function addAll($dataList, $options = array(), $replace = false)\n    {\n        if (empty($dataList)) {\n            $this->error = L('_DATA_TYPE_INVALID_');\n            return false;\n        }\n        // 数据处理\n        foreach ($dataList as $key => $data) {\n            $dataList[$key] = $this->_facade($data);\n        }\n        // 分析表达式\n        $options = $this->_parseOptions($options);\n        // 写入数据到数据库\n        $result = $this->db->insertAll($dataList, $options, $replace);\n        if (false !== $result) {\n            $insertId = $this->getLastInsID();\n            if ($insertId) {\n                return $insertId;\n            }\n        }\n        return $result;\n    }\n\n    /**\n     * 通过Select方式添加记录\n     * @access public\n     * @param string $fields 要插入的数据表字段名\n     * @param string $table 要插入的数据表名\n     * @param array $options 表达式\n     * @return boolean\n     */\n    public function selectAdd($fields = '', $table = '', $options = array())\n    {\n        // 分析表达式\n        $options = $this->_parseOptions($options);\n        // 写入数据到数据库\n        if (false === $result = $this->db->selectInsert($fields ?: $options['field'], $table ?: $this->getTableName(), $options)) {\n            // 数据库插入操作失败\n            $this->error = L('_OPERATION_WRONG_');\n            return false;\n        } else {\n            // 插入成功\n            return $result;\n        }\n    }\n\n    /**\n     * 保存数据\n     * @access public\n     * @param mixed $data 数据\n     * @param array $options 表达式\n     * @return boolean\n     */\n    public function save($data = '', $options = array())\n    {\n        if (empty($data)) {\n            // 没有传递数据，获取当前数据对象的值\n            if (!empty($this->data)) {\n                $data = $this->data;\n                // 重置数据\n                $this->data = array();\n            } else {\n                $this->error = L('_DATA_TYPE_INVALID_');\n                return false;\n            }\n        }\n        // 数据处理\n        $data = $this->_facade($data);\n        if (empty($data)) {\n            // 没有数据则不执行\n            $this->error = L('_DATA_TYPE_INVALID_');\n            return false;\n        }\n        // 分析表达式\n        $options = $this->_parseOptions($options);\n        $pk      = $this->getPk();\n        if (!isset($options['where'])) {\n            // 如果存在主键数据 则自动作为更新条件\n            if (is_string($pk) && isset($data[$pk])) {\n                $where[$pk] = $data[$pk];\n                unset($data[$pk]);\n            } elseif (is_array($pk)) {\n                // 增加复合主键支持\n                foreach ($pk as $field) {\n                    if (isset($data[$field])) {\n                        $where[$field] = $data[$field];\n                    } else {\n                        // 如果缺少复合主键数据则不执行\n                        $this->error = L('_OPERATION_WRONG_');\n                        return false;\n                    }\n                    unset($data[$field]);\n                }\n            }\n            if (!isset($where)) {\n                // 如果没有任何更新条件则不执行\n                $this->error = L('_OPERATION_WRONG_');\n                return false;\n            } else {\n                $options['where'] = $where;\n            }\n        }\n\n        if (is_array($options['where']) && isset($options['where'][$pk])) {\n            $pkValue = $options['where'][$pk];\n        }\n        if (false === $this->_before_update($data, $options)) {\n            return false;\n        }\n        $result = $this->db->update($data, $options);\n        if (false !== $result && is_numeric($result)) {\n            if (isset($pkValue)) {\n                $data[$pk] = $pkValue;\n            }\n\n            $this->_after_update($data, $options);\n        }\n        return $result;\n    }\n    // 更新数据前的回调方法\n    protected function _before_update(&$data, $options)\n    {}\n    // 更新成功后的回调方法\n    protected function _after_update($data, $options)\n    {}\n\n    /**\n     * 删除数据\n     * @access public\n     * @param mixed $options 表达式\n     * @return mixed\n     */\n    public function delete($options = array())\n    {\n        $pk = $this->getPk();\n        if (empty($options) && empty($this->options['where'])) {\n            // 如果删除条件为空 则删除当前数据对象所对应的记录\n            if (!empty($this->data) && isset($this->data[$pk])) {\n                return $this->delete($this->data[$pk]);\n            } else {\n                return false;\n            }\n\n        }\n        if (is_numeric($options) || is_string($options)) {\n            // 根据主键删除记录\n            if (strpos($options, ',')) {\n                $where[$pk] = array('IN', $options);\n            } else {\n                $where[$pk] = $options;\n            }\n\n            $this->options['where'] = $where;\n        }\n        // 根据复合主键删除记录\n        if (is_array($options) && (count($options) > 0) && is_array($pk)) {\n            $count = 0;\n            foreach (array_keys($options) as $key) {\n                if (is_int($key)) {\n                    $count++;\n                }\n\n            }\n            if (count($pk) == $count) {\n                $i = 0;\n                foreach ($pk as $field) {\n                    $where[$field] = $options[$i];\n                    unset($options[$i++]);\n                }\n                $this->options['where'] = $where;\n            } else {\n                return false;\n            }\n        }\n        // 分析表达式\n        $options = $this->_parseOptions();\n        if (empty($options['where'])) {\n            // 如果条件为空 不进行删除操作 除非设置 1=1\n            return false;\n        }\n        if (is_array($options['where']) && isset($options['where'][$pk])) {\n            $pkValue = $options['where'][$pk];\n        }\n\n        if (false === $this->_before_delete($options)) {\n            return false;\n        }\n        $result = $this->db->delete($options);\n        if (false !== $result && is_numeric($result)) {\n            $data = array();\n            if (isset($pkValue)) {\n                $data[$pk] = $pkValue;\n            }\n\n            $this->_after_delete($data, $options);\n        }\n        // 返回删除记录个数\n        return $result;\n    }\n    // 删除数据前的回调方法\n    protected function _before_delete($options)\n    {}\n    // 删除成功后的回调方法\n    protected function _after_delete($data, $options)\n    {}\n\n    /**\n     * 查询数据集\n     * @access public\n     * @param array $options 表达式参数\n     * @return mixed\n     */\n    public function select($options = array())\n    {\n        $pk = $this->getPk();\n        if (is_string($options) || is_numeric($options)) {\n            // 根据主键查询\n            if (strpos($options, ',')) {\n                $where[$pk] = array('IN', $options);\n            } else {\n                $where[$pk] = $options;\n            }\n\n            $this->options['where'] = $where;\n        } elseif (is_array($options) && (count($options) > 0) && is_array($pk)) {\n            // 根据复合主键查询\n            $count = 0;\n            foreach (array_keys($options) as $key) {\n                if (is_int($key)) {\n                    $count++;\n                }\n\n            }\n            if (count($pk) == $count) {\n                $i = 0;\n                foreach ($pk as $field) {\n                    $where[$field] = $options[$i];\n                    unset($options[$i++]);\n                }\n                $this->options['where'] = $where;\n            } else {\n                return false;\n            }\n        } elseif (false === $options) {\n            // 用于子查询 不查询只返回SQL\n            $this->options['fetch_sql'] = true;\n        }\n        // 分析表达式\n        $options = $this->_parseOptions();\n        // 判断查询缓存\n        if (isset($options['cache'])) {\n            $cache = $options['cache'];\n            $key   = is_string($cache['key']) ? $cache['key'] : md5(serialize($options));\n            $data  = S($key, '', $cache);\n            if (false !== $data) {\n                return $data;\n            }\n        }\n        $resultSet = $this->db->select($options);\n        if (false === $resultSet) {\n            return false;\n        }\n        if (!empty($resultSet)) {\n            // 有查询结果\n            if (is_string($resultSet)) {\n                return $resultSet;\n            }\n\n            $resultSet = array_map(array($this, '_read_data'), $resultSet);\n            $this->_after_select($resultSet, $options);\n            if (isset($options['index'])) {\n                // 对数据集进行索引\n                $index = explode(',', $options['index']);\n                foreach ($resultSet as $result) {\n                    $_key = $result[$index[0]];\n                    if (isset($index[1]) && isset($result[$index[1]])) {\n                        $cols[$_key] = $result[$index[1]];\n                    } else {\n                        $cols[$_key] = $result;\n                    }\n                }\n                $resultSet = $cols;\n            }\n        }\n\n        if (isset($cache)) {\n            S($key, $resultSet, $cache);\n        }\n        return $resultSet;\n    }\n    // 查询成功后的回调方法\n    protected function _after_select(&$resultSet, $options)\n    {}\n\n    /**\n     * 生成查询SQL 可用于子查询\n     * @access public\n     * @return string\n     */\n    public function buildSql()\n    {\n        return '( ' . $this->fetchSql(true)->select() . ' )';\n    }\n\n    /**\n     * 分析表达式\n     * @access protected\n     * @param array $options 表达式参数\n     * @return array\n     */\n    protected function _parseOptions($options = array())\n    {\n        if (is_array($options)) {\n            $options = array_merge($this->options, $options);\n        }\n\n        if (!isset($options['table'])) {\n            // 自动获取表名\n            $options['table'] = $this->getTableName();\n            $fields           = $this->fields;\n        } else {\n            // 指定数据表 则重新获取字段列表 但不支持类型检测\n            $fields = $this->getDbFields();\n        }\n\n        // 数据表别名\n        if (!empty($options['alias'])) {\n            $options['table'] .= ' ' . $options['alias'];\n        }\n        // 记录操作的模型名称\n        $options['model'] = $this->name;\n\n        // 字段类型验证\n        if (isset($options['where']) && is_array($options['where']) && !empty($fields) && !isset($options['join'])) {\n            // 对数组查询条件进行字段类型检查\n            foreach ($options['where'] as $key => $val) {\n                $key = trim($key);\n                if (in_array($key, $fields, true)) {\n                    if (is_scalar($val)) {\n                        $this->_parseType($options['where'], $key);\n                    }\n                }\n            }\n        }\n        // 查询过后清空sql表达式组装 避免影响下次查询\n        $this->options = array();\n        // 表达式过滤\n        $this->_options_filter($options);\n        return $options;\n    }\n    // 表达式过滤回调方法\n    protected function _options_filter(&$options)\n    {}\n\n    /**\n     * 数据类型检测\n     * @access protected\n     * @param mixed $data 数据\n     * @param string $key 字段名\n     * @return void\n     */\n    protected function _parseType(&$data, $key)\n    {\n        if (!isset($this->options['bind'][':' . $key]) && isset($this->fields['_type'][$key])) {\n            $fieldType = strtolower($this->fields['_type'][$key]);\n            if (false !== strpos($fieldType, 'enum')) {\n                // 支持ENUM类型优先检测\n            } elseif (false === strpos($fieldType, 'bigint') && false !== strpos($fieldType, 'int')) {\n                $data[$key] = intval($data[$key]);\n            } elseif (false !== strpos($fieldType, 'float') || false !== strpos($fieldType, 'double')) {\n                $data[$key] = floatval($data[$key]);\n            } elseif (false !== strpos($fieldType, 'bool')) {\n                $data[$key] = (bool) $data[$key];\n            }\n        }\n    }\n\n    /**\n     * 数据读取后的处理\n     * @access protected\n     * @param array $data 当前数据\n     * @return array\n     */\n    protected function _read_data($data)\n    {\n        // 检查字段映射\n        if (!empty($this->_map) && C('READ_DATA_MAP')) {\n            foreach ($this->_map as $key => $val) {\n                if (isset($data[$val])) {\n                    $data[$key] = $data[$val];\n                    unset($data[$val]);\n                }\n            }\n        }\n        return $data;\n    }\n\n    /**\n     * 查询数据\n     * @access public\n     * @param mixed $options 表达式参数\n     * @return mixed\n     */\n    public function find($options = array())\n    {\n        if (is_numeric($options) || is_string($options)) {\n            $where[$this->getPk()] = $options;\n\n            $this->options['where'] = $where;\n        }\n        // 根据复合主键查找记录\n        $pk = $this->getPk();\n        if (is_array($options) && (count($options) > 0) && is_array($pk)) {\n            // 根据复合主键查询\n            $count = 0;\n            foreach (array_keys($options) as $key) {\n                if (is_int($key)) {\n                    $count++;\n                }\n\n            }\n            if (count($pk) == $count) {\n                $i = 0;\n                foreach ($pk as $field) {\n                    $where[$field] = $options[$i];\n                    unset($options[$i++]);\n                }\n                $this->options['where'] = $where;\n            } else {\n                return false;\n            }\n        }\n        // 总是查找一条记录\n        $this->options['limit'] = 1;\n        // 分析表达式\n        $options = $this->_parseOptions();\n        // 判断查询缓存\n        if (isset($options['cache'])) {\n            $cache = $options['cache'];\n            $key   = is_string($cache['key']) ? $cache['key'] : md5(serialize($options));\n            $data  = S($key, '', $cache);\n            if (false !== $data) {\n                $this->data = $data;\n                return $data;\n            }\n        }\n        $resultSet = $this->db->select($options);\n        if (false === $resultSet) {\n            return false;\n        }\n        if (empty($resultSet)) {\n            // 查询结果为空\n            return null;\n        }\n        if (is_string($resultSet)) {\n            return $resultSet;\n        }\n\n        // 读取数据后的处理\n        $data = $this->_read_data($resultSet[0]);\n        $this->_after_find($data, $options);\n        if (!empty($options['result'])) {\n            return $this->returnResult($data, $options['result']);\n        }\n        $this->data = $data;\n        if (isset($cache)) {\n            S($key, $data, $cache);\n        }\n        return $this->data;\n    }\n    // 查询成功的回调方法\n    protected function _after_find(&$result, $options)\n    {}\n\n    protected function returnResult($data, $type = '')\n    {\n        if ($type) {\n            if (is_callable($type)) {\n                return call_user_func($type, $data);\n            }\n            switch (strtolower($type)) {\n                case 'json':\n                    return json_encode($data);\n                case 'xml':\n                    return xml_encode($data);\n            }\n        }\n        return $data;\n    }\n\n    /**\n     * 处理字段映射\n     * @access public\n     * @param array $data 当前数据\n     * @param integer $type 类型 0 写入 1 读取\n     * @return array\n     */\n    public function parseFieldsMap($data, $type = 1)\n    {\n        // 检查字段映射\n        if (!empty($this->_map)) {\n            foreach ($this->_map as $key => $val) {\n                if (1 == $type) {\n                    // 读取\n                    if (isset($data[$val])) {\n                        $data[$key] = $data[$val];\n                        unset($data[$val]);\n                    }\n                } else {\n                    if (isset($data[$key])) {\n                        $data[$val] = $data[$key];\n                        unset($data[$key]);\n                    }\n                }\n            }\n        }\n        return $data;\n    }\n\n    /**\n     * 设置记录的某个字段值\n     * 支持使用数据库字段和方法\n     * @access public\n     * @param string|array $field  字段名\n     * @param string $value  字段值\n     * @return boolean\n     */\n    public function setField($field, $value = '')\n    {\n        if (is_array($field)) {\n            $data = $field;\n        } else {\n            $data[$field] = $value;\n        }\n        return $this->save($data);\n    }\n\n    /**\n     * 字段值增长\n     * @access public\n     * @param string $field  字段名\n     * @param integer $step  增长值\n     * @param integer $lazyTime  延时时间(s)\n     * @return boolean\n     */\n    public function setInc($field, $step = 1, $lazyTime = 0)\n    {\n        if ($lazyTime > 0) {\n            // 延迟写入\n            $condition = $this->options['where'];\n            $guid      = md5($this->name . '_' . $field . '_' . serialize($condition));\n            $step      = $this->lazyWrite($guid, $step, $lazyTime);\n            if (empty($step)) {\n                return true; // 等待下次写入\n            } elseif ($step < 0) {\n                $step = '-' . $step;\n            }\n        }\n        return $this->setField($field, array('exp', $field . '+' . $step));\n    }\n\n    /**\n     * 字段值减少\n     * @access public\n     * @param string $field  字段名\n     * @param integer $step  减少值\n     * @param integer $lazyTime  延时时间(s)\n     * @return boolean\n     */\n    public function setDec($field, $step = 1, $lazyTime = 0)\n    {\n        if ($lazyTime > 0) {\n            // 延迟写入\n            $condition = $this->options['where'];\n            $guid      = md5($this->name . '_' . $field . '_' . serialize($condition));\n            $step      = $this->lazyWrite($guid, -$step, $lazyTime);\n            if (empty($step)) {\n                return true; // 等待下次写入\n            } elseif ($step > 0) {\n                $step = '-' . $step;\n            }\n        }\n        return $this->setField($field, array('exp', $field . '-' . $step));\n    }\n\n    /**\n     * 延时更新检查 返回false表示需要延时\n     * 否则返回实际写入的数值\n     * @access public\n     * @param string $guid  写入标识\n     * @param integer $step  写入步进值\n     * @param integer $lazyTime  延时时间(s)\n     * @return false|integer\n     */\n    protected function lazyWrite($guid, $step, $lazyTime)\n    {\n        if (false !== ($value = S($guid))) {\n            // 存在缓存写入数据\n            if (NOW_TIME > S($guid . '_time') + $lazyTime) {\n                // 延时更新时间到了，删除缓存数据 并实际写入数据库\n                S($guid, null);\n                S($guid . '_time', null);\n                return $value + $step;\n            } else {\n                // 追加数据到缓存\n                S($guid, $value + $step, 0);\n                return false;\n            }\n        } else {\n            // 没有缓存数据\n            S($guid, $step, 0);\n            // 计时开始\n            S($guid . '_time', NOW_TIME, 0);\n            return false;\n        }\n    }\n\n    /**\n     * 获取一条记录的某个字段值\n     * @access public\n     * @param string $field  字段名\n     * @param string $spea  字段数据间隔符号 NULL返回数组\n     * @return mixed\n     */\n    public function getField($field, $sepa = null)\n    {\n        $options['field'] = $field;\n        $options          = $this->_parseOptions($options);\n        // 判断查询缓存\n        if (isset($options['cache'])) {\n            $cache = $options['cache'];\n            $key   = is_string($cache['key']) ? $cache['key'] : md5($sepa . serialize($options));\n            $data  = S($key, '', $cache);\n            if (false !== $data) {\n                return $data;\n            }\n        }\n        $field = trim($field);\n        if (strpos($field, ',') && false !== $sepa) {\n            // 多字段\n            if (!isset($options['limit'])) {\n                $options['limit'] = is_numeric($sepa) ? $sepa : '';\n            }\n            $resultSet = $this->db->select($options);\n            if (!empty($resultSet)) {\n                if (is_string($resultSet)) {\n                    return $resultSet;\n                }\n                $_field = explode(',', $field);\n                $field  = array_keys($resultSet[0]);\n                $key1   = array_shift($field);\n                $key2   = array_shift($field);\n                $cols   = array();\n                $count  = count($_field);\n                foreach ($resultSet as $result) {\n                    $name = $result[$key1];\n                    if (2 == $count) {\n                        $cols[$name] = $result[$key2];\n                    } else {\n                        $cols[$name] = is_string($sepa) ? implode($sepa, array_slice($result, 1)) : $result;\n                    }\n                }\n                if (isset($cache)) {\n                    S($key, $cols, $cache);\n                }\n                return $cols;\n            }\n        } else {\n            // 查找一条记录\n            // 返回数据个数\n            if (true !== $sepa) {\n                // 当sepa指定为true的时候 返回所有数据\n                $options['limit'] = is_numeric($sepa) ? $sepa : 1;\n            }\n            $result = $this->db->select($options);\n            if (!empty($result)) {\n                if (is_string($result)) {\n                    return $result;\n                }\n                if (true !== $sepa && 1 == $options['limit']) {\n                    $data = reset($result[0]);\n                    if (isset($cache)) {\n                        S($key, $data, $cache);\n                    }\n                    return $data;\n                }\n                foreach ($result as $val) {\n                    $array[] = reset($val);\n                }\n                if (isset($cache)) {\n                    S($key, $array, $cache);\n                }\n                return $array;\n            }\n        }\n        return null;\n    }\n\n    /**\n     * 创建数据对象 但不保存到数据库\n     * @access public\n     * @param mixed $data 创建数据\n     * @param string $type 状态\n     * @return mixed\n     */\n    public function create($data = '', $type = '')\n    {\n        // 如果没有传值默认取POST数据\n        if (empty($data)) {\n            $data = I('post.');\n        } elseif (is_object($data)) {\n            $data = get_object_vars($data);\n        }\n        // 验证数据\n        if (empty($data) || !is_array($data)) {\n            $this->error = L('_DATA_TYPE_INVALID_');\n            return false;\n        }\n\n        // 状态\n        $type = $type ?: (!empty($data[$this->getPk()]) ? self::MODEL_UPDATE : self::MODEL_INSERT);\n\n        // 检查字段映射\n        $data = $this->parseFieldsMap($data, 0);\n\n        // 检测提交字段的合法性\n        if (isset($this->options['field'])) {\n            // $this->field('field1,field2...')->create()\n            $fields = $this->options['field'];\n            unset($this->options['field']);\n        } elseif (self::MODEL_INSERT == $type && isset($this->insertFields)) {\n            $fields = $this->insertFields;\n        } elseif (self::MODEL_UPDATE == $type && isset($this->updateFields)) {\n            $fields = $this->updateFields;\n            $pk     = $this->getPk();\n            if (is_string($pk)) {\n                array_push($fields, $pk);\n            }\n            if (is_array($pk)) {\n                foreach ($pk as $pkTemp) {\n                    array_push($fields, $pkTemp);\n                }\n            }\n        }\n        if (isset($fields)) {\n            if (is_string($fields)) {\n                $fields = explode(',', $fields);\n            }\n            // 判断令牌验证字段\n            if (C('TOKEN_ON')) {\n                $fields[] = C('TOKEN_NAME', null, '__hash__');\n            }\n\n            foreach ($data as $key => $val) {\n                if (!in_array($key, $fields)) {\n                    unset($data[$key]);\n                }\n            }\n        }\n\n        // 数据自动验证\n        if (!$this->autoValidation($data, $type)) {\n            return false;\n        }\n\n        // 表单令牌验证\n        if (!$this->autoCheckToken($data)) {\n            $this->error = L('_TOKEN_ERROR_');\n            return false;\n        }\n\n        // 验证完成生成数据对象\n        if ($this->autoCheckFields) {\n            // 开启字段检测 则过滤非法字段数据\n            $fields = $this->getDbFields();\n            foreach ($data as $key => $val) {\n                if (!in_array($key, $fields)) {\n                    unset($data[$key]);\n                } elseif (MAGIC_QUOTES_GPC && is_string($val)) {\n                    $data[$key] = stripslashes($val);\n                }\n            }\n        }\n\n        // 创建完成对数据进行自动处理\n        $this->autoOperation($data, $type);\n        // 赋值当前数据对象\n        $this->data = $data;\n        // 返回创建的数据以供其他调用\n        return $data;\n    }\n\n    // 自动表单令牌验证\n    // TODO  ajax无刷新多次提交暂不能满足\n    public function autoCheckToken($data)\n    {\n        // 支持使用token(false) 关闭令牌验证\n        if (isset($this->options['token']) && !$this->options['token']) {\n            return true;\n        }\n\n        if (C('TOKEN_ON')) {\n            $name = C('TOKEN_NAME', null, '__hash__');\n            if (!isset($data[$name]) || !isset($_SESSION[$name])) {\n                // 令牌数据无效\n                return false;\n            }\n\n            // 令牌验证\n            list($key, $value) = explode('_', $data[$name]);\n            if (isset($_SESSION[$name][$key]) && $value && $_SESSION[$name][$key] === $value) {\n                // 防止重复提交\n                unset($_SESSION[$name][$key]); // 验证完成销毁session\n                return true;\n            }\n            // 开启TOKEN重置\n            if (C('TOKEN_RESET')) {\n                unset($_SESSION[$name][$key]);\n            }\n\n            return false;\n        }\n        return true;\n    }\n\n    /**\n     * 使用正则验证数据\n     * @access public\n     * @param string $value  要验证的数据\n     * @param string $rule 验证规则\n     * @return boolean\n     */\n    public function regex($value, $rule)\n    {\n        $validate = array(\n            'require'  => '/\\S+/',\n            'email'    => '/^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$/',\n            'url'      => '/^http(s?):\\/\\/(?:[A-za-z0-9-]+\\.)+[A-za-z]{2,4}(:\\d+)?(?:[\\/\\?#][\\/=\\?%\\-&~`@[\\]\\':+!\\.#\\w]*)?$/',\n            'currency' => '/^\\d+(\\.\\d+)?$/',\n            'number'   => '/^\\d+$/',\n            'zip'      => '/^\\d{6}$/',\n            'integer'  => '/^[-\\+]?\\d+$/',\n            'double'   => '/^[-\\+]?\\d+(\\.\\d+)?$/',\n            'english'  => '/^[A-Za-z]+$/',\n        );\n        // 检查是否有内置的正则表达式\n        if (isset($validate[strtolower($rule)])) {\n            $rule = $validate[strtolower($rule)];\n        }\n\n        return preg_match($rule, $value) === 1;\n    }\n\n    /**\n     * 自动表单处理\n     * @access public\n     * @param array $data 创建数据\n     * @param string $type 创建类型\n     * @return mixed\n     */\n    private function autoOperation(&$data, $type)\n    {\n        if (isset($this->options['auto']) && false === $this->options['auto']) {\n            // 关闭自动完成\n            return $data;\n        }\n        if (!empty($this->options['auto'])) {\n            $_auto = $this->options['auto'];\n            unset($this->options['auto']);\n        } elseif (!empty($this->_auto)) {\n            $_auto = $this->_auto;\n        }\n        // 自动填充\n        if (isset($_auto)) {\n            foreach ($_auto as $auto) {\n                // 填充因子定义格式\n                // array('field','填充内容','填充条件','附加规则',[额外参数])\n                if (empty($auto[2])) {\n                    $auto[2] = self::MODEL_INSERT;\n                }\n                // 默认为新增的时候自动填充\n                if ($type == $auto[2] || self::MODEL_BOTH == $auto[2]) {\n                    if (empty($auto[3])) {\n                        $auto[3] = 'string';\n                    }\n\n                    switch (trim($auto[3])) {\n                        case 'function': //  使用函数进行填充 字段的值作为参数\n                        case 'callback': // 使用回调方法\n                            $args = isset($auto[4]) ? (array) $auto[4] : array();\n                            if (isset($data[$auto[0]])) {\n                                array_unshift($args, $data[$auto[0]]);\n                            }\n                            if ('function' == $auto[3]) {\n                                $data[$auto[0]] = call_user_func_array($auto[1], $args);\n                            } else {\n                                $data[$auto[0]] = call_user_func_array(array(&$this, $auto[1]), $args);\n                            }\n                            break;\n                        case 'field': // 用其它字段的值进行填充\n                            $data[$auto[0]] = $data[$auto[1]];\n                            break;\n                        case 'ignore': // 为空忽略\n                            if ($auto[1] === $data[$auto[0]]) {\n                                unset($data[$auto[0]]);\n                            }\n\n                            break;\n                        case 'string':\n                        default: // 默认作为字符串填充\n                            $data[$auto[0]] = $auto[1];\n                    }\n                    if (isset($data[$auto[0]]) && false === $data[$auto[0]]) {\n                        unset($data[$auto[0]]);\n                    }\n\n                }\n            }\n        }\n        return $data;\n    }\n\n    /**\n     * 自动表单验证\n     * @access protected\n     * @param array $data 创建数据\n     * @param string $type 创建类型\n     * @return boolean\n     */\n    protected function autoValidation($data, $type)\n    {\n        if (isset($this->options['validate']) && false === $this->options['validate']) {\n            // 关闭自动验证\n            return true;\n        }\n        if (!empty($this->options['validate'])) {\n            $_validate = $this->options['validate'];\n            unset($this->options['validate']);\n        } elseif (!empty($this->_validate)) {\n            $_validate = $this->_validate;\n        }\n        // 属性验证\n        if (isset($_validate)) {\n            // 如果设置了数据自动验证则进行数据验证\n            if ($this->patchValidate) {\n                // 重置验证错误信息\n                $this->error = array();\n            }\n            foreach ($_validate as $key => $val) {\n                // 验证因子定义格式\n                // array(field,rule,message,condition,type,when,params)\n                // 判断是否需要执行验证\n                if (empty($val[5]) || (self::MODEL_BOTH == $val[5] && $type < 3) || $val[5] == $type) {\n                    if (0 == strpos($val[2], '{%') && strpos($val[2], '}'))\n                    // 支持提示信息的多语言 使用 {%语言定义} 方式\n                    {\n                        $val[2] = L(substr($val[2], 2, -1));\n                    }\n\n                    $val[3] = isset($val[3]) ? $val[3] : self::EXISTS_VALIDATE;\n                    $val[4] = isset($val[4]) ? $val[4] : 'regex';\n                    // 判断验证条件\n                    switch ($val[3]) {\n                        case self::MUST_VALIDATE: // 必须验证 不管表单是否有设置该字段\n                            if (false === $this->_validationField($data, $val)) {\n                                return false;\n                            }\n\n                            break;\n                        case self::VALUE_VALIDATE: // 值不为空的时候才验证\n                            if ('' != trim($data[$val[0]])) {\n                                if (false === $this->_validationField($data, $val)) {\n                                    return false;\n                                }\n                            }\n\n                            break;\n                        default: // 默认表单存在该字段就验证\n                            if (isset($data[$val[0]])) {\n                                if (false === $this->_validationField($data, $val)) {\n                                    return false;\n                                }\n                            }\n\n                    }\n                }\n            }\n            // 批量验证的时候最后返回错误\n            if (!empty($this->error)) {\n                return false;\n            }\n\n        }\n        return true;\n    }\n\n    /**\n     * 验证表单字段 支持批量验证\n     * 如果批量验证返回错误的数组信息\n     * @access protected\n     * @param array $data 创建数据\n     * @param array $val 验证因子\n     * @return boolean\n     */\n    protected function _validationField($data, $val)\n    {\n        if ($this->patchValidate && isset($this->error[$val[0]])) {\n            //当前字段已经有规则验证没有通过\n            return;\n        }\n\n        if (false === $this->_validationFieldItem($data, $val)) {\n            if ($this->patchValidate) {\n                $this->error[$val[0]] = $val[2];\n            } else {\n                $this->error = $val[2];\n                return false;\n            }\n        }\n        return;\n    }\n\n    /**\n     * 根据验证因子验证字段\n     * @access protected\n     * @param array $data 创建数据\n     * @param array $val 验证因子\n     * @return boolean\n     */\n    protected function _validationFieldItem($data, $val)\n    {\n        switch (strtolower(trim($val[4]))) {\n            case 'function': // 使用函数进行验证\n            case 'callback': // 调用方法进行验证\n                $args = isset($val[6]) ? (array) $val[6] : array();\n                if (is_string($val[0]) && strpos($val[0], ',')) {\n                    $val[0] = explode(',', $val[0]);\n                }\n\n                if (is_array($val[0])) {\n                    // 支持多个字段验证\n                    foreach ($val[0] as $field) {\n                        $_data[$field] = $data[$field];\n                    }\n\n                    array_unshift($args, $_data);\n                } else {\n                    array_unshift($args, $data[$val[0]]);\n                }\n                if ('function' == $val[4]) {\n                    return call_user_func_array($val[1], $args);\n                } else {\n                    return call_user_func_array(array(&$this, $val[1]), $args);\n                }\n            case 'confirm': // 验证两个字段是否相同\n                return $data[$val[0]] == $data[$val[1]];\n            case 'unique': // 验证某个值是否唯一\n                if (is_string($val[0]) && strpos($val[0], ',')) {\n                    $val[0] = explode(',', $val[0]);\n                }\n\n                $map = array();\n                if (is_array($val[0])) {\n                    // 支持多个字段验证\n                    foreach ($val[0] as $field) {\n                        $map[$field] = $data[$field];\n                    }\n\n                } else {\n                    $map[$val[0]] = $data[$val[0]];\n                }\n                $pk = $this->getPk();\n                if (!empty($data[$pk]) && is_string($pk)) {\n                    // 完善编辑的时候验证唯一\n                    $map[$pk] = array('neq', $data[$pk]);\n                }\n                $options = $this->options;\n                if ($this->where($map)->find()) {\n                    return false;\n                }\n\n                $this->options = $options;\n                return true;\n            default: // 检查附加规则\n                return $this->check($data[$val[0]], $val[1], $val[4]);\n        }\n    }\n\n    /**\n     * 验证数据 支持 in between equal length regex expire ip_allow ip_deny\n     * @access public\n     * @param string $value 验证数据\n     * @param mixed $rule 验证表达式\n     * @param string $type 验证方式 默认为正则验证\n     * @return boolean\n     */\n    public function check($value, $rule, $type = 'regex')\n    {\n        $type = strtolower(trim($type));\n        switch ($type) {\n            case 'in': // 验证是否在某个指定范围之内 逗号分隔字符串或者数组\n            case 'notin':\n                $range = is_array($rule) ? $rule : explode(',', $rule);\n                return 'in' == $type ? in_array($value, $range) : !in_array($value, $range);\n            case 'between': // 验证是否在某个范围\n            case 'notbetween': // 验证是否不在某个范围\n                if (is_array($rule)) {\n                    $min = $rule[0];\n                    $max = $rule[1];\n                } else {\n                    list($min, $max) = explode(',', $rule);\n                }\n                return 'between' == $type ? $value >= $min && $value <= $max : $value < $min || $value > $max;\n            case 'equal': // 验证是否等于某个值\n            case 'notequal': // 验证是否等于某个值\n                return 'equal' == $type ? $value == $rule : $value != $rule;\n            case 'length': // 验证长度\n                $length = mb_strlen($value, 'utf-8'); // 当前数据长度\n                if (strpos($rule, ',')) {\n                    // 长度区间\n                    list($min, $max) = explode(',', $rule);\n                    return $length >= $min && $length <= $max;\n                } else {\n                    // 指定长度\n                    return $length == $rule;\n                }\n            case 'expire':\n                list($start, $end) = explode(',', $rule);\n                if (!is_numeric($start)) {\n                    $start = strtotime($start);\n                }\n\n                if (!is_numeric($end)) {\n                    $end = strtotime($end);\n                }\n\n                return NOW_TIME >= $start && NOW_TIME <= $end;\n            case 'ip_allow': // IP 操作许可验证\n                return in_array(get_client_ip(), explode(',', $rule));\n            case 'ip_deny': // IP 操作禁止验证\n                return !in_array(get_client_ip(), explode(',', $rule));\n            case 'regex':\n            default: // 默认使用正则验证 可以使用验证类中定义的验证名称\n                // 检查附加规则\n                return $this->regex($value, $rule);\n        }\n    }\n\n    /**\n     * 存储过程返回多数据集\n     * @access public\n     * @param string $sql  SQL指令\n     * @param mixed $parse  是否需要解析SQL\n     * @return array\n     */\n    public function procedure($sql, $parse = false)\n    {\n        return $this->db->procedure($sql, $parse);\n    }\n\n    /**\n     * SQL查询\n     * @access public\n     * @param string $sql  SQL指令\n     * @param mixed $parse  是否需要解析SQL\n     * @return mixed\n     */\n    public function query($sql, $parse = false)\n    {\n        if (!is_bool($parse) && !is_array($parse)) {\n            $parse = func_get_args();\n            array_shift($parse);\n        }\n        $sql = $this->parseSql($sql, $parse);\n        return $this->db->query($sql);\n    }\n\n    /**\n     * 执行SQL语句\n     * @access public\n     * @param string $sql  SQL指令\n     * @param mixed $parse  是否需要解析SQL\n     * @return false | integer\n     */\n    public function execute($sql, $parse = false)\n    {\n        if (!is_bool($parse) && !is_array($parse)) {\n            $parse = func_get_args();\n            array_shift($parse);\n        }\n        $sql = $this->parseSql($sql, $parse);\n        return $this->db->execute($sql);\n    }\n\n    /**\n     * 解析SQL语句\n     * @access public\n     * @param string $sql  SQL指令\n     * @param boolean $parse  是否需要解析SQL\n     * @return string\n     */\n    protected function parseSql($sql, $parse)\n    {\n        // 分析表达式\n        if (true === $parse) {\n            $options = $this->_parseOptions();\n            $sql     = $this->db->parseSql($sql, $options);\n        } elseif (is_array($parse)) {\n            // SQL预处理\n            $parse = array_map(array($this->db, 'escapeString'), $parse);\n            $sql   = vsprintf($sql, $parse);\n        } else {\n            $sql    = strtr($sql, array('__TABLE__' => $this->getTableName(), '__PREFIX__' => $this->tablePrefix));\n            $prefix = $this->tablePrefix;\n            $sql    = preg_replace_callback(\"/__([A-Z0-9_-]+)__/sU\", function ($match) use ($prefix) {return $prefix . strtolower($match[1]);}, $sql);\n        }\n        $this->db->setModel($this->name);\n        return $sql;\n    }\n\n    /**\n     * 切换当前的数据库连接\n     * @access public\n     * @param integer $linkNum  连接序号\n     * @param mixed $config  数据库连接信息\n     * @param boolean $force 强制重新连接\n     * @return Model\n     */\n    public function db($linkNum = '', $config = '', $force = false)\n    {\n        if ('' === $linkNum && $this->db) {\n            return $this->db;\n        }\n\n        if (!isset($this->_db[$linkNum]) || $force) {\n            // 创建一个新的实例\n            if (!empty($config) && is_string($config) && false === strpos($config, '/')) {\n                // 支持读取配置参数\n                $config = C($config);\n            }\n            $this->_db[$linkNum] = Db::getInstance($config);\n        } elseif (null === $config) {\n            $this->_db[$linkNum]->close(); // 关闭数据库连接\n            unset($this->_db[$linkNum]);\n            return;\n        }\n\n        // 切换数据库连接\n        $this->db = $this->_db[$linkNum];\n        $this->_after_db();\n        // 字段检测\n        if (!empty($this->name) && $this->autoCheckFields) {\n            $this->_checkTableInfo();\n        }\n\n        return $this;\n    }\n    // 数据库切换后回调方法\n    protected function _after_db()\n    {}\n\n    /**\n     * 得到当前的数据对象名称\n     * @access public\n     * @return string\n     */\n    public function getModelName()\n    {\n        if (empty($this->name)) {\n            $name = substr(get_class($this), 0, -strlen(C('DEFAULT_M_LAYER')));\n            if ($pos = strrpos($name, '\\\\')) {\n                //有命名空间\n                $this->name = substr($name, $pos + 1);\n            } else {\n                $this->name = $name;\n            }\n        }\n        return $this->name;\n    }\n\n    /**\n     * 得到完整的数据表名\n     * @access public\n     * @return string\n     */\n    public function getTableName()\n    {\n        if (empty($this->trueTableName)) {\n            $tableName = !empty($this->tablePrefix) ? $this->tablePrefix : '';\n            if (!empty($this->tableName)) {\n                $tableName .= $this->tableName;\n            } else {\n                $tableName .= parse_name($this->name);\n            }\n            $this->trueTableName = strtolower($tableName);\n        }\n        return (!empty($this->dbName) ? $this->dbName . '.' : '') . $this->trueTableName;\n    }\n\n    /**\n     * 启动事务\n     * @access public\n     * @return void\n     */\n    public function startTrans()\n    {\n        $this->commit();\n        $this->db->startTrans();\n        return;\n    }\n\n    /**\n     * 提交事务\n     * @access public\n     * @return boolean\n     */\n    public function commit()\n    {\n        return $this->db->commit();\n    }\n\n    /**\n     * 事务回滚\n     * @access public\n     * @return boolean\n     */\n    public function rollback()\n    {\n        return $this->db->rollback();\n    }\n\n    /**\n     * 返回模型的错误信息\n     * @access public\n     * @return string\n     */\n    public function getError()\n    {\n        return $this->error;\n    }\n\n    /**\n     * 返回数据库的错误信息\n     * @access public\n     * @return string\n     */\n    public function getDbError()\n    {\n        return $this->db->getError();\n    }\n\n    /**\n     * 返回最后插入的ID\n     * @access public\n     * @return string\n     */\n    public function getLastInsID()\n    {\n        return $this->db->getLastInsID();\n    }\n\n    /**\n     * 返回最后执行的sql语句\n     * @access public\n     * @return string\n     */\n    public function getLastSql()\n    {\n        return $this->db->getLastSql($this->name);\n    }\n    // 鉴于getLastSql比较常用 增加_sql 别名\n    public function _sql()\n    {\n        return $this->getLastSql();\n    }\n\n    /**\n     * 获取主键名称\n     * @access public\n     * @return string\n     */\n    public function getPk()\n    {\n        return $this->pk;\n    }\n\n    /**\n     * 获取数据表字段信息\n     * @access public\n     * @return array\n     */\n    public function getDbFields()\n    {\n        if (isset($this->options['table'])) {\n            // 动态指定表名\n            if (is_array($this->options['table'])) {\n                $table = key($this->options['table']);\n            } else {\n                $table = $this->options['table'];\n                if (strpos($table, ')')) {\n                    // 子查询\n                    return false;\n                }\n            }\n            $fields = $this->db->getFields($table);\n            return $fields ? array_keys($fields) : false;\n        }\n        if ($this->fields) {\n            $fields = $this->fields;\n            unset($fields['_type'], $fields['_pk']);\n            return $fields;\n        }\n        return false;\n    }\n\n    /**\n     * 设置数据对象值\n     * @access public\n     * @param mixed $data 数据\n     * @return Model\n     */\n    public function data($data = '')\n    {\n        if ('' === $data && !empty($this->data)) {\n            return $this->data;\n        }\n        if (is_object($data)) {\n            $data = get_object_vars($data);\n        } elseif (is_string($data)) {\n            parse_str($data, $data);\n        } elseif (!is_array($data)) {\n            E(L('_DATA_TYPE_INVALID_'));\n        }\n        $this->data = $data;\n        return $this;\n    }\n\n    /**\n     * 指定当前的数据表\n     * @access public\n     * @param mixed $table\n     * @return Model\n     */\n    public function table($table)\n    {\n        $prefix = $this->tablePrefix;\n        if (is_array($table)) {\n            $this->options['table'] = $table;\n        } elseif (!empty($table)) {\n            //将__TABLE_NAME__替换成带前缀的表名\n            $table = preg_replace_callback(\"/__([A-Z0-9_-]+)__/sU\", function ($match) use ($prefix) {return $prefix . strtolower($match[1]);}, $table);\n            $this->options['table'] = $table;\n        }\n        return $this;\n    }\n\n    /**\n     * USING支持 用于多表删除\n     * @access public\n     * @param mixed $using\n     * @return Model\n     */\n    public function using($using)\n    {\n        $prefix = $this->tablePrefix;\n        if (is_array($using)) {\n            $this->options['using'] = $using;\n        } elseif (!empty($using)) {\n            //将__TABLE_NAME__替换成带前缀的表名\n            $using = preg_replace_callback(\"/__([A-Z0-9_-]+)__/sU\", function ($match) use ($prefix) {return $prefix . strtolower($match[1]);}, $using);\n            $this->options['using'] = $using;\n        }\n        return $this;\n    }\n\n    /**\n     * 查询SQL组装 join\n     * @access public\n     * @param mixed $join\n     * @param string $type JOIN类型\n     * @return Model\n     */\n    public function join($join, $type = 'INNER')\n    {\n        $prefix = $this->tablePrefix;\n        if (is_array($join)) {\n            foreach ($join as $key => &$_join) {\n                $_join = preg_replace_callback(\"/__([A-Z0-9_-]+)__/sU\", function ($match) use ($prefix) {return $prefix . strtolower($match[1]);}, $_join);\n                $_join = false !== stripos($_join, 'JOIN') ? $_join : $type . ' JOIN ' . $_join;\n            }\n            $this->options['join'] = $join;\n        } elseif (!empty($join)) {\n            //将__TABLE_NAME__字符串替换成带前缀的表名\n            $join = preg_replace_callback(\"/__([A-Z0-9_-]+)__/sU\", function ($match) use ($prefix) {return $prefix . strtolower($match[1]);}, $join);\n            $this->options['join'][] = false !== stripos($join, 'JOIN') ? $join : $type . ' JOIN ' . $join;\n        }\n        return $this;\n    }\n\n    /**\n     * 查询SQL组装 union\n     * @access public\n     * @param mixed $union\n     * @param boolean $all\n     * @return Model\n     */\n    public function union($union, $all = false)\n    {\n        if (empty($union)) {\n            return $this;\n        }\n\n        if ($all) {\n            $this->options['union']['_all'] = true;\n        }\n        if (is_object($union)) {\n            $union = get_object_vars($union);\n        }\n        // 转换union表达式\n        if (is_string($union)) {\n            $prefix = $this->tablePrefix;\n            //将__TABLE_NAME__字符串替换成带前缀的表名\n            $options = preg_replace_callback(\"/__([A-Z0-9_-]+)__/sU\", function ($match) use ($prefix) {return $prefix . strtolower($match[1]);}, $union);\n        } elseif (is_array($union)) {\n            if (isset($union[0])) {\n                $this->options['union'] = array_merge($this->options['union'], $union);\n                return $this;\n            } else {\n                $options = $union;\n            }\n        } else {\n            E(L('_DATA_TYPE_INVALID_'));\n        }\n        $this->options['union'][] = $options;\n        return $this;\n    }\n\n    /**\n     * 查询缓存\n     * @access public\n     * @param mixed $key\n     * @param integer $expire\n     * @param string $type\n     * @return Model\n     */\n    public function cache($key = true, $expire = null, $type = '')\n    {\n        // 增加快捷调用方式 cache(10) 等同于 cache(true, 10)\n        if (is_numeric($key) && is_null($expire)) {\n            $expire = $key;\n            $key    = true;\n        }\n        if (false !== $key) {\n            $this->options['cache'] = array('key' => $key, 'expire' => $expire, 'type' => $type);\n        }\n\n        return $this;\n    }\n\n    /**\n     * 指定查询字段 支持字段排除\n     * @access public\n     * @param mixed $field\n     * @param boolean $except 是否排除\n     * @return Model\n     */\n    public function field($field, $except = false)\n    {\n        if (true === $field) {\n            // 获取全部字段\n            $fields = $this->getDbFields();\n            $field  = $fields ?: '*';\n        } elseif ($except) {\n            // 字段排除\n            if (is_string($field)) {\n                $field = explode(',', $field);\n            }\n            $fields = $this->getDbFields();\n            $field  = $fields ? array_diff($fields, $field) : $field;\n        }\n        $this->options['field'] = $field;\n        return $this;\n    }\n\n    /**\n     * 调用命名范围\n     * @access public\n     * @param mixed $scope 命名范围名称 支持多个 和直接定义\n     * @param array $args 参数\n     * @return Model\n     */\n    public function scope($scope = '', $args = null)\n    {\n        if ('' === $scope) {\n            if (isset($this->_scope['default'])) {\n                // 默认的命名范围\n                $options = $this->_scope['default'];\n            } else {\n                return $this;\n            }\n        } elseif (is_string($scope)) {\n            // 支持多个命名范围调用 用逗号分割\n            $scopes  = explode(',', $scope);\n            $options = array();\n            foreach ($scopes as $name) {\n                if (!isset($this->_scope[$name])) {\n                    continue;\n                }\n\n                $options = array_merge($options, $this->_scope[$name]);\n            }\n            if (!empty($args) && is_array($args)) {\n                $options = array_merge($options, $args);\n            }\n        } elseif (is_array($scope)) {\n            // 直接传入命名范围定义\n            $options = $scope;\n        }\n\n        if (is_array($options) && !empty($options)) {\n            $this->options = array_merge($this->options, array_change_key_case($options));\n        }\n        return $this;\n    }\n\n    /**\n     * 指定查询条件 支持安全过滤\n     * @access public\n     * @param mixed $where 条件表达式\n     * @param mixed $parse 预处理参数\n     * @return Model\n     */\n    public function where($where, $parse = null)\n    {\n        if (!is_null($parse) && is_string($where)) {\n            if (!is_array($parse)) {\n                $parse = func_get_args();\n                array_shift($parse);\n            }\n            $parse = array_map(array($this->db, 'escapeString'), $parse);\n            $where = vsprintf($where, $parse);\n        } elseif (is_object($where)) {\n            $where = get_object_vars($where);\n        }\n        if (is_string($where) && '' != $where) {\n            $map            = array();\n            $map['_string'] = $where;\n            $where          = $map;\n        }\n        if (isset($this->options['where'])) {\n            $this->options['where'] = array_merge($this->options['where'], $where);\n        } else {\n            $this->options['where'] = $where;\n        }\n\n        return $this;\n    }\n\n    /**\n     * 指定查询数量\n     * @access public\n     * @param mixed $offset 起始位置\n     * @param mixed $length 查询数量\n     * @return Model\n     */\n    public function limit($offset, $length = null)\n    {\n        if (is_null($length) && strpos($offset, ',')) {\n            list($offset, $length) = explode(',', $offset);\n        }\n        $this->options['limit'] = intval($offset) . ($length ? ',' . intval($length) : '');\n        return $this;\n    }\n\n    /**\n     * 指定分页\n     * @access public\n     * @param mixed $page 页数\n     * @param mixed $listRows 每页数量\n     * @return Model\n     */\n    public function page($page, $listRows = null)\n    {\n        if (is_null($listRows) && strpos($page, ',')) {\n            list($page, $listRows) = explode(',', $page);\n        }\n        $this->options['page'] = array(intval($page), intval($listRows));\n        return $this;\n    }\n\n    /**\n     * 查询注释\n     * @access public\n     * @param string $comment 注释\n     * @return Model\n     */\n    public function comment($comment)\n    {\n        $this->options['comment'] = $comment;\n        return $this;\n    }\n\n    /**\n     * 获取执行的SQL语句\n     * @access public\n     * @param boolean $fetch 是否返回sql\n     * @return Model\n     */\n    public function fetchSql($fetch = true)\n    {\n        $this->options['fetch_sql'] = $fetch;\n        return $this;\n    }\n\n    /**\n     * 参数绑定\n     * @access public\n     * @param string $key  参数名\n     * @param mixed $value  绑定的变量及绑定参数\n     * @return Model\n     */\n    public function bind($key, $value = false)\n    {\n        if (is_array($key)) {\n            $this->options['bind'] = $key;\n        } else {\n            $num = func_num_args();\n            if ($num > 2) {\n                $params = func_get_args();\n                array_shift($params);\n                $this->options['bind'][$key] = $params;\n            } else {\n                $this->options['bind'][$key] = $value;\n            }\n        }\n        return $this;\n    }\n\n    /**\n     * 设置模型的属性值\n     * @access public\n     * @param string $name 名称\n     * @param mixed $value 值\n     * @return Model\n     */\n    public function setProperty($name, $value)\n    {\n        if (property_exists($this, $name)) {\n            $this->$name = $value;\n        }\n\n        return $this;\n    }\n\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Route.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\nnamespace Think;\n/**\n * ThinkPHP路由解析类\n */\nclass Route {\n    \n    // 路由检测\n    public static function check(){\n        $depr   =   C('URL_PATHINFO_DEPR');\n        $regx   =   preg_replace('/\\.'.__EXT__.'$/i','',trim($_SERVER['PATH_INFO'],$depr));\n        // 分隔符替换 确保路由定义使用统一的分隔符\n        if('/' != $depr){\n            $regx = str_replace($depr,'/',$regx);\n        }\n        // URL映射定义（静态路由）\n        $maps   =   C('URL_MAP_RULES');\n        if(isset($maps[$regx])) {\n            $var    =   self::parseUrl($maps[$regx]);\n            $_GET   =   array_merge($var, $_GET);\n            return true;                \n        }        \n        // 动态路由处理\n        $routes =   C('URL_ROUTE_RULES');\n        if(!empty($routes)) {\n            foreach ($routes as $rule=>$route){\n                if(is_numeric($rule)){\n                    // 支持 array('rule','adddress',...) 定义路由\n                    $rule   =   array_shift($route);\n                }\n                if(is_array($route) && isset($route[2])){\n                    // 路由参数\n                    $options    =   $route[2];\n                    if(isset($options['ext']) && __EXT__ != $options['ext']){\n                        // URL后缀检测\n                        continue;\n                    }\n                    if(isset($options['method']) && REQUEST_METHOD != strtoupper($options['method'])){\n                        // 请求类型检测\n                        continue;\n                    }\n                    // 自定义检测\n                    if(!empty($options['callback']) && is_callable($options['callback'])) {\n                        if(false === call_user_func($options['callback'])) {\n                            continue;\n                        }\n                    }                    \n                }\n                if(0===strpos($rule,'/') && preg_match($rule,$regx,$matches)) { // 正则路由\n                    if($route instanceof \\Closure) {\n                        // 执行闭包\n                        $result = self::invokeRegx($route, $matches);\n                        // 如果返回布尔值 则继续执行\n                        return is_bool($result) ? $result : exit;\n                    }else{\n                        return self::parseRegex($matches,$route,$regx);\n                    }\n                }else{ // 规则路由\n                    $len1   =   substr_count($regx,'/');\n                    $len2   =   substr_count($rule,'/');\n                    if($len1>=$len2 || strpos($rule,'[')) {\n                        if('$' == substr($rule,-1,1)) {// 完整匹配\n                            if($len1 != $len2) {\n                                continue;\n                            }else{\n                                $rule =  substr($rule,0,-1);\n                            }\n                        }\n                        $match  =  self::checkUrlMatch($regx,$rule);\n                        if(false !== $match)  {\n                            if($route instanceof \\Closure) {\n                                // 执行闭包\n                                $result = self::invokeRule($route, $match);\n                                // 如果返回布尔值 则继续执行\n                                return is_bool($result) ? $result : exit;\n                            }else{\n                                return self::parseRule($rule,$route,$regx);\n                            }\n                        }\n                    }\n                }\n            }\n        }\n        return false;\n    }\n\n    // 检测URL和规则路由是否匹配\n    private static function checkUrlMatch($regx,$rule) {\n        $m1 = explode('/',$regx);\n        $m2 = explode('/',$rule);\n        $var = array();         \n        foreach ($m2 as $key=>$val){\n            if(0 === strpos($val,'[:')){\n                $val    =   substr($val,1,-1);\n            }\n                \n            if(':' == substr($val,0,1)) {// 动态变量\n                if($pos = strpos($val,'|')){\n                    // 使用函数过滤\n                    $val   =   substr($val,1,$pos-1);\n                }\n                if(strpos($val,'\\\\')) {\n                    $type = substr($val,-1);\n                    if('d'==$type) {\n                        if(isset($m1[$key]) && !is_numeric($m1[$key]))\n                            return false;\n                    }\n                    $name = substr($val, 1, -2);\n                }elseif($pos = strpos($val,'^')){\n                    $array   =  explode('-',substr(strstr($val,'^'),1));\n                    if(in_array($m1[$key],$array)) {\n                        return false;\n                    }\n                    $name = substr($val, 1, $pos - 1);\n                }else{\n                    $name = substr($val, 1);\n                }\n                $var[$name] = isset($m1[$key])?$m1[$key]:'';\n            }elseif(0 !== strcasecmp($val,$m1[$key])){\n                return false;\n            }\n        }\n        // 成功匹配后返回URL中的动态变量数组\n        return $var;\n    }\n\n    // 解析规范的路由地址\n    // 地址格式 [控制器/操作?]参数1=值1&参数2=值2...\n    private static function parseUrl($url) {\n        $var  =  array();\n        if(false !== strpos($url,'?')) { // [控制器/操作?]参数1=值1&参数2=值2...\n            $info   =  parse_url($url);\n            $path   = explode('/',$info['path']);\n            parse_str($info['query'],$var);\n        }elseif(strpos($url,'/')){ // [控制器/操作]\n            $path = explode('/',$url);\n        }else{ // 参数1=值1&参数2=值2...\n            parse_str($url,$var);\n        }\n        if(isset($path)) {\n            $var[C('VAR_ACTION')] = array_pop($path);\n            if(!empty($path)) {\n                $var[C('VAR_CONTROLLER')] = array_pop($path);\n            }\n            if(!empty($path)) {\n                $var[C('VAR_MODULE')]  = array_pop($path);\n            }\n        }\n        return $var;\n    }\n\n    // 解析规则路由\n    // '路由规则'=>'[控制器/操作]?额外参数1=值1&额外参数2=值2...'\n    // '路由规则'=>array('[控制器/操作]','额外参数1=值1&额外参数2=值2...')\n    // '路由规则'=>'外部地址'\n    // '路由规则'=>array('外部地址','重定向代码')\n    // 路由规则中 :开头 表示动态变量\n    // 外部地址中可以用动态变量 采用 :1 :2 的方式\n    // 'news/:month/:day/:id'=>array('News/read?cate=1','status=1'),\n    // 'new/:id'=>array('/new.php?id=:1',301), 重定向\n    private static function parseRule($rule,$route,$regx) {\n        // 获取路由地址规则\n        $url   =  is_array($route)?$route[0]:$route;\n        // 获取URL地址中的参数\n        $paths = explode('/',$regx);\n        // 解析路由规则\n        $matches  =  array();\n        $rule =  explode('/',$rule);\n        foreach ($rule as $item){\n            $fun    =   '';\n            if(0 === strpos($item,'[:')){\n                $item   =   substr($item,1,-1);\n            }\n            if(0===strpos($item,':')) { // 动态变量获取\n                if($pos = strpos($item,'|')){ \n                    // 支持函数过滤\n                    $fun  =  substr($item,$pos+1);\n                    $item =  substr($item,0,$pos);                    \n                }\n                if($pos = strpos($item,'^') ) {\n                    $var  =  substr($item,1,$pos-1);\n                }elseif(strpos($item,'\\\\')){\n                    $var  =  substr($item,1,-2);\n                }else{\n                    $var  =  substr($item,1);\n                }\n                $matches[$var] = !empty($fun)? $fun(array_shift($paths)) : array_shift($paths);\n            }else{ // 过滤URL中的静态变量\n                array_shift($paths);\n            }\n        }\n\n        if(0=== strpos($url,'/') || 0===strpos($url,'http')) { // 路由重定向跳转\n            if(strpos($url,':')) { // 传递动态参数\n                $values = array_values($matches);\n                $url = preg_replace_callback('/:(\\d+)/', function($match) use($values){ return $values[$match[1] - 1]; }, $url);\n            }\n            header(\"Location: $url\", true,(is_array($route) && isset($route[1]))?$route[1]:301);\n            exit;\n        }else{\n            // 解析路由地址\n            $var  =  self::parseUrl($url);\n            // 解析路由地址里面的动态参数\n            $values  =  array_values($matches);\n            foreach ($var as $key=>$val){\n                if(0===strpos($val,':')) {\n                    $var[$key] =  $values[substr($val,1)-1];\n                }\n            }\n            $var   =   array_merge($matches,$var);\n            // 解析剩余的URL参数\n            if(!empty($paths)) {\n                preg_replace_callback('/(\\w+)\\/([^\\/]+)/', function($match) use(&$var){ $var[strtolower($match[1])]=strip_tags($match[2]);}, implode('/',$paths));\n            }\n            // 解析路由自动传入参数\n            if(is_array($route) && isset($route[1])) {\n                if(is_array($route[1])){\n                    $params     =   $route[1];\n                }else{\n                    parse_str($route[1],$params);\n                }                \n                $var   =   array_merge($var,$params);\n            }\n            $_GET   =  array_merge($var,$_GET);\n        }\n        return true;\n    }\n\n    // 解析正则路由\n    // '路由正则'=>'[控制器/操作]?参数1=值1&参数2=值2...'\n    // '路由正则'=>array('[控制器/操作]?参数1=值1&参数2=值2...','额外参数1=值1&额外参数2=值2...')\n    // '路由正则'=>'外部地址'\n    // '路由正则'=>array('外部地址','重定向代码')\n    // 参数值和外部地址中可以用动态变量 采用 :1 :2 的方式\n    // '/new\\/(\\d+)\\/(\\d+)/'=>array('News/read?id=:1&page=:2&cate=1','status=1'),\n    // '/new\\/(\\d+)/'=>array('/new.php?id=:1&page=:2&status=1','301'), 重定向\n    private static function parseRegex($matches,$route,$regx) {\n        // 获取路由地址规则\n        $url   =  is_array($route)?$route[0]:$route;\n        $url   =  preg_replace_callback('/:(\\d+)/', function($match) use($matches){return $matches[$match[1]];}, $url); \n        if(0=== strpos($url,'/') || 0===strpos($url,'http')) { // 路由重定向跳转\n            header(\"Location: $url\", true,(is_array($route) && isset($route[1]))?$route[1]:301);\n            exit;\n        }else{\n            // 解析路由地址\n            $var  =  self::parseUrl($url);\n            // 处理函数\n            foreach($var as $key=>$val){\n                if(strpos($val,'|')){\n                    list($val,$fun) = explode('|',$val);\n                    $var[$key]    =   $fun($val);\n                }\n            }\n            // 解析剩余的URL参数\n            $regx =  substr_replace($regx,'',0,strlen($matches[0]));\n            if($regx) {\n                preg_replace_callback('/(\\w+)\\/([^\\/]+)/', function($match) use(&$var){\n                    $var[strtolower($match[1])] = strip_tags($match[2]);\n                }, $regx);\n            }\n            // 解析路由自动传入参数\n            if(is_array($route) && isset($route[1])) {\n                if(is_array($route[1])){\n                    $params     =   $route[1];\n                }else{\n                    parse_str($route[1],$params);\n                }\n                $var   =   array_merge($var,$params);\n            }\n            $_GET   =  array_merge($var,$_GET);\n        }\n        return true;\n    }\n\n    // 执行正则匹配下的闭包方法 支持参数调用\n    static private function invokeRegx($closure, $var = array()) {\n        $reflect = new \\ReflectionFunction($closure);\n        $params  = $reflect->getParameters();\n        $args    = array();\n        array_shift($var);\n        foreach ($params as $param){\n            if(!empty($var)) {\n                $args[] = array_shift($var);\n            }elseif($param->isDefaultValueAvailable()){\n                $args[] = $param->getDefaultValue();\n            }\n        }\n        return $reflect->invokeArgs($args);\n    }\n\n    // 执行规则匹配下的闭包方法 支持参数调用\n    static private function invokeRule($closure, $var = array()) {\n        $reflect = new \\ReflectionFunction($closure);\n        $params  = $reflect->getParameters();\n        $args    = array();\n        foreach ($params as $param){\n            $name = $param->getName();\n            if(isset($var[$name])) {\n                $args[] = $var[$name];\n            }elseif($param->isDefaultValueAvailable()){\n                $args[] = $param->getDefaultValue();\n            }\n        }\n        return $reflect->invokeArgs($args);\n    }\n\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Storage/Driver/File.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | TOPThink [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2013 http://topthink.com All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\nnamespace Think\\Storage\\Driver;\nuse Think\\Storage;\n// 本地文件写入存储类\nclass File extends Storage{\n\n    private $contents=array();\n\n    /**\n     * 架构函数\n     * @access public\n     */\n    public function __construct() {\n    }\n\n    /**\n     * 文件内容读取\n     * @access public\n     * @param string $filename  文件名\n     * @return string     \n     */\n    public function read($filename,$type=''){\n        return $this->get($filename,'content',$type);\n    }\n\n    /**\n     * 文件写入\n     * @access public\n     * @param string $filename  文件名\n     * @param string $content  文件内容\n     * @return boolean         \n     */\n    public function put($filename,$content,$type=''){\n        $dir         =  dirname($filename);\n        if(!is_dir($dir)){\n            mkdir($dir,0777,true);\n        }\n        if(false === file_put_contents($filename,$content)){\n            E(L('_STORAGE_WRITE_ERROR_').':'.$filename);\n        }else{\n            $this->contents[$filename]=$content;\n            return true;\n        }\n    }\n\n    /**\n     * 文件追加写入\n     * @access public\n     * @param string $filename  文件名\n     * @param string $content  追加的文件内容\n     * @return boolean        \n     */\n    public function append($filename,$content,$type=''){\n        if(is_file($filename)){\n            $content =  $this->read($filename,$type).$content;\n        }\n        return $this->put($filename,$content,$type);\n    }\n\n    /**\n     * 加载文件\n     * @access public\n     * @param string $filename  文件名\n     * @param array $vars  传入变量\n     * @return void        \n     */\n    public function load($_filename,$vars=null){\n        if(!is_null($vars)){\n            extract($vars, EXTR_OVERWRITE);\n        }\n        include $_filename;\n    }\n\n    /**\n     * 文件是否存在\n     * @access public\n     * @param string $filename  文件名\n     * @return boolean     \n     */\n    public function has($filename,$type=''){\n        return is_file($filename);\n    }\n\n    /**\n     * 文件删除\n     * @access public\n     * @param string $filename  文件名\n     * @return boolean     \n     */\n    public function unlink($filename,$type=''){\n        unset($this->contents[$filename]);\n        return is_file($filename) ? unlink($filename) : false; \n    }\n\n    /**\n     * 读取文件信息\n     * @access public\n     * @param string $filename  文件名\n     * @param string $name  信息名 mtime或者content\n     * @return boolean     \n     */\n    public function get($filename,$name,$type=''){\n        if(!isset($this->contents[$filename])){\n            if(!is_file($filename)) return false;\n           $this->contents[$filename]=file_get_contents($filename);\n        }\n        $content=$this->contents[$filename];\n        $info   =   array(\n            'mtime'     =>  filemtime($filename),\n            'content'   =>  $content\n        );\n        return $info[$name];\n    }\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Storage/Driver/Sae.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | TOPThink [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2013 http://topthink.com All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: luofei614 <weibo.com/luofei614>\n// +----------------------------------------------------------------------\nnamespace Think\\Storage\\Driver;\nuse Think\\Storage;\n// SAE环境文件写入存储类\nclass Sae extends Storage{\n\n    /**\n     * 架构函数\n     * @access public\n     */\n    private $mc;\n    private $kvs        =   array();\n    private $htmls      =   array();\n    private $contents   =   array();\n    public function __construct() {\n        if(!function_exists('memcache_init')){\n              header('Content-Type:text/html;charset=utf-8');\n              exit('请在SAE平台上运行代码。');\n        }\n        $this->mc       =   @memcache_init();\n        if(!$this->mc){\n              header('Content-Type:text/html;charset=utf-8');\n              exit('您未开通Memcache服务，请在SAE管理平台初始化Memcache服务');\n        }\n    }\n\n    /**\n     * 获得SaeKv对象\n     */\n    private function getKv(){\n        static $kv;\n        if(!$kv){\n           $kv  =   new \\SaeKV();\n           if(!$kv->init())\n               E('您没有初始化KVDB，请在SAE管理平台初始化KVDB服务');\n        }\n        return $kv;\n    }\n\n\n    /**\n     * 文件内容读取\n     * @access public\n     * @param string $filename  文件名\n     * @return string\n     */\n    public function read($filename,$type=''){\n        switch(strtolower($type)){\n            case 'f':       \n                $kv     =   $this->getKv();\n                if(!isset($this->kvs[$filename])){\n                    $this->kvs[$filename]=$kv->get($filename);\n                }\n                return $this->kvs[$filename];\n            default:\n                return $this->get($filename,'content',$type);\n        }        \n    }\n\n    /**\n     * 文件写入\n     * @access public\n     * @param string $filename  文件名\n     * @param string $content  文件内容\n     * @return boolean\n     */\n    public function put($filename,$content,$type=''){\n        switch(strtolower($type)){\n            case 'f':       \n                $kv         =   $this->getKv();\n                $this->kvs[$filename] = $content;\n                return $kv->set($filename,$content);\n            case 'html':    \n                $kv         =   $this->getKv();\n                $content    =   time().$content;\n                $this->htmls[$filename] =   $content;\n                return $kv->set($filename,$content);\n            default:\n                $content    =   time().$content;\n                if(!$this->mc->set($filename,$content,MEMCACHE_COMPRESSED,0)){\n                    E(L('_STORAGE_WRITE_ERROR_').':'.$filename);\n                }else{\n                    $this->contents[$filename] = $content;\n                    return true;\n                }            \n        }\n    }\n\n    /**\n     * 文件追加写入\n     * @access public\n     * @param string $filename  文件名\n     * @param string $content  追加的文件内容\n     * @return boolean\n     */\n    public function append($filename,$content,$type=''){\n        if($old_content = $this->read($filename,$type)){\n            $content =  $old_content.$content;\n        }\n        return $this->put($filename,$content,$type);\n    }\n\n    /**\n     * 加载文件\n     * @access public\n     * @param string $_filename  文件名\n     * @param array $vars  传入变量\n     * @return void\n     */\n    public function load($_filename,$vars=null){\n        if(!is_null($vars))\n            extract($vars, EXTR_OVERWRITE);\n        eval('?>'.$this->read($_filename));\n    }\n\n    /**\n     * 文件是否存在\n     * @access public\n     * @param string $filename  文件名\n     * @return boolean\n     */\n    public function has($filename,$type=''){\n        if($this->read($filename,$type)){\n            return true;\n        }else{\n            return false;\n        }\n    }\n\n    /**\n     * 文件删除\n     * @access public\n     * @param string $filename  文件名\n     * @return boolean\n     */\n    public function unlink($filename,$type=''){\n        switch(strtolower($type)){\n            case 'f':       \n                $kv     =   $this->getKv();\n                unset($this->kvs[$filename]);\n                return $kv->delete($filename);\n            case 'html':    \n                $kv     =   $this->getKv();\n                unset($this->htmls[$filename]);\n                return $kv->delete($filename);\n            default:\n                unset($this->contents[$filename]);\n                return $this->mc->delete($filename);            \n        }        \n    }\n\n    /**\n     * 读取文件信息\n     * @access public\n     * @param string $filename  文件名\n     * @param string $name  信息名 mtime或者content\n     * @return boolean\n     */\n    public function get($filename,$name,$type=''){\n        switch(strtolower($type)){\n            case 'html':\n                if(!isset($this->htmls[$filename])){\n                    $kv = $this->getKv();\n                    $this->htmls[$filename] = $kv->get($filename);\n                }\n                $content = $this->htmls[$filename];\n                break;\n            default:\n                if(!isset($this->contents[$filename])){\n                    $this->contents[$filename] = $this->mc->get($filename);\n                }\n                $content =  $this->contents[$filename];\n        }\n        if(false===$content){\n            return false;\n        }\n        $info   =   array(\n            'mtime'     =>  substr($content,0,10),\n            'content'   =>  substr($content,10)\n        );\n        return $info[$name];        \n    }\n\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Storage.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | TOPThink [ WE CAN DO IT JUST THINK ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2013 http://topthink.com All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\nnamespace Think;\n// 分布式文件存储类\nclass Storage {\n\n    /**\n     * 操作句柄\n     * @var string\n     * @access protected\n     */\n    static protected $handler    ;\n\n    /**\n     * 连接分布式文件系统\n     * @access public\n     * @param string $type 文件类型\n     * @param array $options  配置数组\n     * @return void\n     */\n    static public function connect($type='File',$options=array()) {\n        $class  =   'Think\\\\Storage\\\\Driver\\\\'.ucwords($type);\n        self::$handler = new $class($options);\n    }\n\n    static public function __callstatic($method,$args){\n        //调用缓存驱动的方法\n        if(method_exists(self::$handler, $method)){\n           return call_user_func_array(array(self::$handler,$method), $args);\n        }\n    }\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Template/Driver/Ease.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\nnamespace Think\\Template\\Driver;\n/**\n * EaseTemplate模板引擎驱动 \n */\nclass Ease {\n    /**\n     * 渲染模板输出\n     * @access public\n     * @param string $templateFile 模板文件名\n     * @param array $var 模板变量\n     * @return void\n     */\n    public function fetch($templateFile,$var) {\n        $templateFile   = substr($templateFile,strlen(THEME_PATH),-5);\n        $CacheDir       = substr(CACHE_PATH,0,-1);\n        $TemplateDir    = substr(THEME_PATH,0,-1);\n        vendor('EaseTemplate.template#ease');\n        $config     =  array(\n        'CacheDir'      =>  $CacheDir,\n        'TemplateDir'   =>  $TemplateDir,\n        'TplType'       =>  'html'\n         );        \n        if(C('TMPL_ENGINE_CONFIG')) {\n            $config     =  array_merge($config,C('TMPL_ENGINE_CONFIG'));\n        }\n        $tpl = new \\EaseTemplate($config);\n        $tpl->set_var($var);\n        $tpl->set_file($templateFile);\n        $tpl->p();\n    }\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Template/Driver/Lite.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\nnamespace Think\\Template\\Driver;\n/**\n * TemplateLite模板引擎驱动 \n */\nclass Lite {\n    /**\n     * 渲染模板输出\n     * @access public\n     * @param string $templateFile 模板文件名\n     * @param array $var 模板变量\n     * @return void\n     */\n    public function fetch($templateFile,$var) {\n        vendor(\"TemplateLite.class#template\");\n        $templateFile   =   substr($templateFile,strlen(THEME_PATH));\n        $tpl            =   new \\Template_Lite();\n        $tpl->template_dir  = THEME_PATH;\n        $tpl->compile_dir   = CACHE_PATH ;\n        $tpl->cache_dir     = TEMP_PATH ;        \n        if(C('TMPL_ENGINE_CONFIG')) {\n            $config     =  C('TMPL_ENGINE_CONFIG');\n            foreach ($config as $key=>$val){\n                $tpl->{$key}   =  $val;\n            }\n        }\n        $tpl->assign($var);\n        $tpl->display($templateFile);\n    }\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Template/Driver/Mobile.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: luofei614<weibo.com/luofei614>\n// +----------------------------------------------------------------------\nnamespace Think\\Template\\Driver;\n/**\n * MobileTemplate模板引擎驱动 \n */\nclass Mobile {\n    /**\n     * 渲染模板输出\n     * @access public\n     * @param string $templateFile 模板文件名\n     * @param array $var 模板变量\n     * @return void\n     */\n    public function fetch($templateFile,$var) {\n        $templateFile=substr($templateFile,strlen(THEME_PATH));\n        $var['_think_template_path']=$templateFile;\n        exit(json_encode($var));\t\n    }\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Template/Driver/Smart.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\nnamespace Think\\Template\\Driver;\n/**\n * Smart模板引擎驱动 \n */\nclass Smart {\n    /**\n     * 渲染模板输出\n     * @access public\n     * @param string $templateFile 模板文件名\n     * @param array $var 模板变量\n     * @return void\n     */\n    public function fetch($templateFile,$var) {\n        $templateFile   =   substr($templateFile,strlen(THEME_PATH));\n        vendor('SmartTemplate.class#smarttemplate');\n        $tpl            =   new \\SmartTemplate($templateFile);\n        $tpl->caching       = C('TMPL_CACHE_ON');\n        $tpl->template_dir  = THEME_PATH;\n        $tpl->compile_dir   = CACHE_PATH ;\n        $tpl->cache_dir     = TEMP_PATH ;        \n        if(C('TMPL_ENGINE_CONFIG')) {\n            $config  =  C('TMPL_ENGINE_CONFIG');\n            foreach ($config as $key=>$val){\n                $tpl->{$key}   =  $val;\n            }\n        }\n        $tpl->assign($var);\n        $tpl->output();\n    }\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Template/Driver/Smarty.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\nnamespace Think\\Template\\Driver;\n/**\n * Smarty模板引擎驱动 \n */\nclass Smarty {\n\n    /**\n     * 渲染模板输出\n     * @access public\n     * @param string $templateFile 模板文件名\n     * @param array $var 模板变量\n     * @return void\n     */\n    public function fetch($templateFile,$var) {\n        $templateFile   =   substr($templateFile,strlen(THEME_PATH));\n        vendor('Smarty.Smarty#class');\n        $tpl            =   new \\Smarty();\n        $tpl->caching       = C('TMPL_CACHE_ON');\n        $tpl->template_dir  = THEME_PATH;\n        $tpl->compile_dir   = CACHE_PATH ;\n        $tpl->cache_dir     = TEMP_PATH ;        \n        if(C('TMPL_ENGINE_CONFIG')) {\n            $config  =  C('TMPL_ENGINE_CONFIG');\n            foreach ($config as $key=>$val){\n                $tpl->{$key}   =  $val;\n            }\n        }\n        $tpl->assign($var);\n        $tpl->display($templateFile);\n    }\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Template/TagLib/Cx.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\nnamespace Think\\Template\\TagLib;\nuse Think\\Template\\TagLib;\n/**\n * CX标签库解析类\n */\nclass Cx extends TagLib {\n\n    // 标签定义\n    protected $tags   =  array(\n        // 标签定义： attr 属性列表 close 是否闭合（0 或者1 默认1） alias 标签别名 level 嵌套层次\n        'php'       =>  array(),\n        'volist'    =>  array('attr'=>'name,id,offset,length,key,mod','level'=>3,'alias'=>'iterate'),\n        'foreach'   =>  array('attr'=>'name,item,key','level'=>3),\n        'if'        =>  array('attr'=>'condition','level'=>2),\n        'elseif'    =>  array('attr'=>'condition','close'=>0),\n        'else'      =>  array('attr'=>'','close'=>0),\n        'switch'    =>  array('attr'=>'name','level'=>2),\n        'case'      =>  array('attr'=>'value,break'),\n        'default'   =>  array('attr'=>'','close'=>0),\n        'compare'   =>  array('attr'=>'name,value,type','level'=>3,'alias'=>'eq,equal,notequal,neq,gt,lt,egt,elt,heq,nheq'),\n        'range'     =>  array('attr'=>'name,value,type','level'=>3,'alias'=>'in,notin,between,notbetween'),\n        'empty'     =>  array('attr'=>'name','level'=>3),\n        'notempty'  =>  array('attr'=>'name','level'=>3),\n        'present'   =>  array('attr'=>'name','level'=>3),\n        'notpresent'=>  array('attr'=>'name','level'=>3),\n        'defined'   =>  array('attr'=>'name','level'=>3),\n        'notdefined'=>  array('attr'=>'name','level'=>3),\n        'import'    =>  array('attr'=>'file,href,type,value,basepath','close'=>0,'alias'=>'load,css,js'),\n        'assign'    =>  array('attr'=>'name,value','close'=>0),\n        'define'    =>  array('attr'=>'name,value','close'=>0),\n        'for'       =>  array('attr'=>'start,end,name,comparison,step', 'level'=>3),\n        );\n\n    /**\n     * php标签解析\n     * @access public\n     * @param array $tag 标签属性\n     * @param string $content  标签内容\n     * @return string\n     */\n    public function _php($tag,$content) {\n        $parseStr = '<?php '.$content.' ?>';\n        return $parseStr;\n    }\n\n    /**\n     * volist标签解析 循环输出数据集\n     * 格式：\n     * <volist name=\"userList\" id=\"user\" empty=\"\" >\n     * {user.username}\n     * {user.email}\n     * </volist>\n     * @access public\n     * @param array $tag 标签属性\n     * @param string $content  标签内容\n     * @return string|void\n     */\n    public function _volist($tag,$content) {\n        $name  =    $tag['name'];\n        $id    =    $tag['id'];\n        $empty =    isset($tag['empty'])?$tag['empty']:'';\n        $key   =    !empty($tag['key'])?$tag['key']:'i';\n        $mod   =    isset($tag['mod'])?$tag['mod']:'2';\n        // 允许使用函数设定数据集 <volist name=\":fun('arg')\" id=\"vo\">{$vo.name}</volist>\n        $parseStr   =  '<?php ';\n        if(0===strpos($name,':')) {\n            $parseStr   .= '$_result='.substr($name,1).';';\n            $name   = '$_result';\n        }else{\n            $name   = $this->autoBuildVar($name);\n        }\n        $parseStr  .=  'if(is_array('.$name.')): $'.$key.' = 0;';\n        if(isset($tag['length']) && '' !=$tag['length'] ) {\n            $parseStr  .= ' $__LIST__ = array_slice('.$name.','.$tag['offset'].','.$tag['length'].',true);';\n        }elseif(isset($tag['offset'])  && '' !=$tag['offset']){\n            $parseStr  .= ' $__LIST__ = array_slice('.$name.','.$tag['offset'].',null,true);';\n        }else{\n            $parseStr .= ' $__LIST__ = '.$name.';';\n        }\n        $parseStr .= 'if( count($__LIST__)==0 ) : echo \"'.$empty.'\" ;';\n        $parseStr .= 'else: ';\n        $parseStr .= 'foreach($__LIST__ as $key=>$'.$id.'): ';\n        $parseStr .= '$mod = ($'.$key.' % '.$mod.' );';\n        $parseStr .= '++$'.$key.';?>';\n        $parseStr .= $this->tpl->parse($content);\n        $parseStr .= '<?php endforeach; endif; else: echo \"'.$empty.'\" ;endif; ?>';\n\n        if(!empty($parseStr)) {\n            return $parseStr;\n        }\n        return ;\n    }\n\n    /**\n     * foreach标签解析 循环输出数据集\n     * @access public\n     * @param array $tag 标签属性\n     * @param string $content  标签内容\n     * @return string|void\n     */\n    public function _foreach($tag,$content) {\n        $name       =   $tag['name'];\n        $item       =   $tag['item'];\n        $key        =   !empty($tag['key'])?$tag['key']:'key';\n        $name       =   $this->autoBuildVar($name);\n        $parseStr   =   '<?php if(is_array('.$name.')): foreach('.$name.' as $'.$key.'=>$'.$item.'): ?>';\n        $parseStr  .=   $this->tpl->parse($content);\n        $parseStr  .=   '<?php endforeach; endif; ?>';\n\n        if(!empty($parseStr)) {\n            return $parseStr;\n        }\n        return ;\n    }\n\n    /**\n     * if标签解析\n     * 格式：\n     * <if condition=\" $a eq 1\" >\n     * <elseif condition=\"$a eq 2\" />\n     * <else />\n     * </if>\n     * 表达式支持 eq neq gt egt lt elt == > >= < <= or and || &&\n     * @access public\n     * @param array $tag 标签属性\n     * @param string $content  标签内容\n     * @return string\n     */\n    public function _if($tag,$content) {\n        $condition  =   $this->parseCondition($tag['condition']);\n        $parseStr   =   '<?php if('.$condition.'): ?>'.$content.'<?php endif; ?>';\n        return $parseStr;\n    }\n\n    /**\n     * else标签解析\n     * 格式：见if标签\n     * @access public\n     * @param array $tag 标签属性\n     * @param string $content  标签内容\n     * @return string\n     */\n    public function _elseif($tag,$content) {\n        $condition  =   $this->parseCondition($tag['condition']);\n        $parseStr   =   '<?php elseif('.$condition.'): ?>';\n        return $parseStr;\n    }\n\n    /**\n     * else标签解析\n     * @access public\n     * @param array $tag 标签属性\n     * @return string\n     */\n    public function _else($tag) {\n        $parseStr = '<?php else: ?>';\n        return $parseStr;\n    }\n\n    /**\n     * switch标签解析\n     * 格式：\n     * <switch name=\"a.name\" >\n     * <case value=\"1\" break=\"false\">1</case>\n     * <case value=\"2\" >2</case>\n     * <default />other\n     * </switch>\n     * @access public\n     * @param array $tag 标签属性\n     * @param string $content  标签内容\n     * @return string\n     */\n    public function _switch($tag,$content) {\n        $name       =   $tag['name'];\n        $varArray   =   explode('|',$name);\n        $name       =   array_shift($varArray);\n        $name       =   $this->autoBuildVar($name);\n        if(count($varArray)>0)\n            $name   =   $this->tpl->parseVarFunction($name,$varArray);\n        $parseStr   =   '<?php switch('.$name.'): ?>'.$content.'<?php endswitch;?>';\n        return $parseStr;\n    }\n\n    /**\n     * case标签解析 需要配合switch才有效\n     * @access public\n     * @param array $tag 标签属性\n     * @param string $content  标签内容\n     * @return string\n     */\n    public function _case($tag,$content) {\n        $value  = $tag['value'];\n        if('$' == substr($value,0,1)) {\n            $varArray   =   explode('|',$value);\n            $value\t    =\tarray_shift($varArray);\n            $value      =   $this->autoBuildVar(substr($value,1));\n            if(count($varArray)>0)\n                $value  =   $this->tpl->parseVarFunction($value,$varArray);\n            $value      =   'case '.$value.': ';\n        }elseif(strpos($value,'|')){\n            $values     =   explode('|',$value);\n            $value      =   '';\n            foreach ($values as $val){\n                $value   .=  'case \"'.addslashes($val).'\": ';\n            }\n        }else{\n            $value\t=\t'case \"'.$value.'\": ';\n        }\n        $parseStr = '<?php '.$value.' ?>'.$content;\n        $isBreak  = isset($tag['break']) ? $tag['break'] : '';\n        if('' ==$isBreak || $isBreak) {\n            $parseStr .= '<?php break;?>';\n        }\n        return $parseStr;\n    }\n\n    /**\n     * default标签解析 需要配合switch才有效\n     * 使用： <default />ddfdf\n     * @access public\n     * @param array $tag 标签属性\n     * @param string $content  标签内容\n     * @return string\n     */\n    public function _default($tag) {\n        $parseStr = '<?php default: ?>';\n        return $parseStr;\n    }\n\n    /**\n     * compare标签解析\n     * 用于值的比较 支持 eq neq gt lt egt elt heq nheq 默认是eq\n     * 格式： <compare name=\"\" type=\"eq\" value=\"\" >content</compare>\n     * @access public\n     * @param array $tag 标签属性\n     * @param string $content  标签内容\n     * @return string\n     */\n    public function _compare($tag,$content,$type='eq') {\n        $name       =   $tag['name'];\n        $value      =   $tag['value'];\n        $type       =   isset($tag['type'])?$tag['type']:$type;\n        $type       =   $this->parseCondition(' '.$type.' ');\n        $varArray   =   explode('|',$name);\n        $name       =   array_shift($varArray);\n        $name       =   $this->autoBuildVar($name);\n        if(count($varArray)>0)\n            $name = $this->tpl->parseVarFunction($name,$varArray);\n        if('$' == substr($value,0,1)) {\n            $value  =  $this->autoBuildVar(substr($value,1));\n        }else {\n            $value  =   '\"'.$value.'\"';\n        }\n        $parseStr   =   '<?php if(('.$name.') '.$type.' '.$value.'): ?>'.$content.'<?php endif; ?>';\n        return $parseStr;\n    }\n\n    public function _eq($tag,$content) {\n        return $this->_compare($tag,$content,'eq');\n    }\n\n    public function _equal($tag,$content) {\n        return $this->_compare($tag,$content,'eq');\n    }\n\n    public function _neq($tag,$content) {\n        return $this->_compare($tag,$content,'neq');\n    }\n\n    public function _notequal($tag,$content) {\n        return $this->_compare($tag,$content,'neq');\n    }\n\n    public function _gt($tag,$content) {\n        return $this->_compare($tag,$content,'gt');\n    }\n\n    public function _lt($tag,$content) {\n        return $this->_compare($tag,$content,'lt');\n    }\n\n    public function _egt($tag,$content) {\n        return $this->_compare($tag,$content,'egt');\n    }\n\n    public function _elt($tag,$content) {\n        return $this->_compare($tag,$content,'elt');\n    }\n\n    public function _heq($tag,$content) {\n        return $this->_compare($tag,$content,'heq');\n    }\n\n    public function _nheq($tag,$content) {\n        return $this->_compare($tag,$content,'nheq');\n    }\n\n    /**\n     * range标签解析\n     * 如果某个变量存在于某个范围 则输出内容 type= in 表示在范围内 否则表示在范围外\n     * 格式： <range name=\"var|function\"  value=\"val\" type='in|notin' >content</range>\n     * example: <range name=\"a\"  value=\"1,2,3\" type='in' >content</range>\n     * @access public\n     * @param array $tag 标签属性\n     * @param string $content  标签内容\n     * @param string $type  比较类型\n     * @return string\n     */\n    public function _range($tag,$content,$type='in') {\n        $name       =   $tag['name'];\n        $value      =   $tag['value'];\n        $varArray   =   explode('|',$name);\n        $name       =   array_shift($varArray);\n        $name       =   $this->autoBuildVar($name);\n        if(count($varArray)>0)\n            $name   =   $this->tpl->parseVarFunction($name,$varArray);\n\n        $type       =   isset($tag['type'])?$tag['type']:$type;\n\n        if('$' == substr($value,0,1)) {\n            $value  =   $this->autoBuildVar(substr($value,1));\n            $str    =   'is_array('.$value.')?'.$value.':explode(\\',\\','.$value.')';\n        }else{\n            $value  =   '\"'.$value.'\"';\n            $str    =   'explode(\\',\\','.$value.')';\n        }\n        if($type=='between') {\n            $parseStr = '<?php $_RANGE_VAR_='.$str.';if('.$name.'>= $_RANGE_VAR_[0] && '.$name.'<= $_RANGE_VAR_[1]):?>'.$content.'<?php endif; ?>';\n        }elseif($type=='notbetween'){\n            $parseStr = '<?php $_RANGE_VAR_='.$str.';if('.$name.'<$_RANGE_VAR_[0] || '.$name.'>$_RANGE_VAR_[1]):?>'.$content.'<?php endif; ?>';\n        }else{\n            $fun        =  ($type == 'in')? 'in_array'    :   '!in_array';\n            $parseStr   = '<?php if('.$fun.'(('.$name.'), '.$str.')): ?>'.$content.'<?php endif; ?>';\n        }\n        return $parseStr;\n    }\n\n    // range标签的别名 用于in判断\n    public function _in($tag,$content) {\n        return $this->_range($tag,$content,'in');\n    }\n\n    // range标签的别名 用于notin判断\n    public function _notin($tag,$content) {\n        return $this->_range($tag,$content,'notin');\n    }\n\n    public function _between($tag,$content){\n        return $this->_range($tag,$content,'between');\n    }\n\n    public function _notbetween($tag,$content){\n        return $this->_range($tag,$content,'notbetween');\n    }\n\n    /**\n     * present标签解析\n     * 如果某个变量已经设置 则输出内容\n     * 格式： <present name=\"\" >content</present>\n     * @access public\n     * @param array $tag 标签属性\n     * @param string $content  标签内容\n     * @return string\n     */\n    public function _present($tag,$content) {\n        $name       =   $tag['name'];\n        $name       =   $this->autoBuildVar($name);\n        $parseStr   =   '<?php if(isset('.$name.')): ?>'.$content.'<?php endif; ?>';\n        return $parseStr;\n    }\n\n    /**\n     * notpresent标签解析\n     * 如果某个变量没有设置，则输出内容\n     * 格式： <notpresent name=\"\" >content</notpresent>\n     * @access public\n     * @param array $tag 标签属性\n     * @param string $content  标签内容\n     * @return string\n     */\n    public function _notpresent($tag,$content) {\n        $name       =   $tag['name'];\n        $name       =   $this->autoBuildVar($name);\n        $parseStr   =   '<?php if(!isset('.$name.')): ?>'.$content.'<?php endif; ?>';\n        return $parseStr;\n    }\n\n    /**\n     * empty标签解析\n     * 如果某个变量为empty 则输出内容\n     * 格式： <empty name=\"\" >content</empty>\n     * @access public\n     * @param array $tag 标签属性\n     * @param string $content  标签内容\n     * @return string\n     */\n    public function _empty($tag,$content) {\n        $name       =   $tag['name'];\n        $name       =   $this->autoBuildVar($name);\n        $parseStr   =   '<?php if(empty('.$name.')): ?>'.$content.'<?php endif; ?>';\n        return $parseStr;\n    }\n\n    public function _notempty($tag,$content) {\n        $name       =   $tag['name'];\n        $name       =   $this->autoBuildVar($name);\n        $parseStr   =   '<?php if(!empty('.$name.')): ?>'.$content.'<?php endif; ?>';\n        return $parseStr;\n    }\n\n    /**\n     * 判断是否已经定义了该常量\n     * <defined name='TXT'>已定义</defined>\n     * @param <type> $attr\n     * @param <type> $content\n     * @return string\n     */\n    public function _defined($tag,$content) {\n        $name       =   $tag['name'];\n        $parseStr   =   '<?php if(defined(\"'.$name.'\")): ?>'.$content.'<?php endif; ?>';\n        return $parseStr;\n    }\n\n    public function _notdefined($tag,$content) {\n        $name       =   $tag['name'];\n        $parseStr   =   '<?php if(!defined(\"'.$name.'\")): ?>'.$content.'<?php endif; ?>';\n        return $parseStr;\n    }\n\n    /**\n     * import 标签解析 <import file=\"Js.Base\" /> \n     * <import file=\"Css.Base\" type=\"css\" />\n     * @access public\n     * @param array $tag 标签属性\n     * @param string $content  标签内容\n     * @param boolean $isFile  是否文件方式\n     * @param string $type  类型\n     * @return string\n     */\n    public function _import($tag,$content,$isFile=false,$type='') {\n        $file       =   isset($tag['file'])?$tag['file']:$tag['href'];\n        $parseStr   =   '';\n        $endStr     =   '';\n        // 判断是否存在加载条件 允许使用函数判断(默认为isset)\n        if (isset($tag['value'])) {\n            $varArray  =    explode('|',$tag['value']);\n            $name      =    array_shift($varArray);\n            $name      =    $this->autoBuildVar($name);\n            if (!empty($varArray))\n                $name  =    $this->tpl->parseVarFunction($name,$varArray);\n            else\n                $name  =    'isset('.$name.')';\n            $parseStr .=    '<?php if('.$name.'): ?>';\n            $endStr    =    '<?php endif; ?>';\n        }\n        if($isFile) {\n            // 根据文件名后缀自动识别\n            $type  = $type?$type:(!empty($tag['type'])?strtolower($tag['type']):null);\n            // 文件方式导入\n            $array =  explode(',',$file);\n            foreach ($array as $val){\n                if (!$type || isset($reset)) {\n                    $type = $reset = strtolower(substr(strrchr($val, '.'),1));\n                }\n                switch($type) {\n                case 'js':\n                    $parseStr .= '<script type=\"text/javascript\" src=\"'.$val.'\"></script>';\n                    break;\n                case 'css':\n                    $parseStr .= '<link rel=\"stylesheet\" type=\"text/css\" href=\"'.$val.'\" />';\n                    break;\n                case 'php':\n                    $parseStr .= '<?php require_cache(\"'.$val.'\"); ?>';\n                    break;\n                }\n            }\n        }else{\n            // 命名空间导入模式 默认是js\n            $type       =   $type?$type:(!empty($tag['type'])?strtolower($tag['type']):'js');\n            $basepath   =   !empty($tag['basepath'])?$tag['basepath']:__ROOT__.'/Public';\n            // 命名空间方式导入外部文件\n            $array      =   explode(',',$file);\n            foreach ($array as $val){\n                if(strpos ($val, '?')) {\n                    list($val,$version) =   explode('?',$val);\n                } else {\n                    $version = '';\n                }\n                switch($type) {\n                case 'js':\n                    $parseStr .= '<script type=\"text/javascript\" src=\"'.$basepath.'/'.str_replace(array('.','#'), array('/','.'),$val).'.js'.($version?'?'.$version:'').'\"></script>';\n                    break;\n                case 'css':\n                    $parseStr .= '<link rel=\"stylesheet\" type=\"text/css\" href=\"'.$basepath.'/'.str_replace(array('.','#'), array('/','.'),$val).'.css'.($version?'?'.$version:'').'\" />';\n                    break;\n                case 'php':\n                    $parseStr .= '<?php import(\"'.$val.'\"); ?>';\n                    break;\n                }\n            }\n        }\n        return $parseStr.$endStr;\n    }\n\n    // import别名 采用文件方式加载(要使用命名空间必须用import) 例如 <load file=\"__PUBLIC__/Js/Base.js\" />\n    public function _load($tag,$content) {\n        return $this->_import($tag,$content,true);\n    }\n\n    // import别名使用 导入css文件 <css file=\"__PUBLIC__/Css/Base.css\" />\n    public function _css($tag,$content) {\n        return $this->_import($tag,$content,true,'css');\n    }\n\n    // import别名使用 导入js文件 <js file=\"__PUBLIC__/Js/Base.js\" />\n    public function _js($tag,$content) {\n        return $this->_import($tag,$content,true,'js');\n    }\n\n    /**\n     * assign标签解析\n     * 在模板中给某个变量赋值 支持变量赋值\n     * 格式： <assign name=\"\" value=\"\" />\n     * @access public\n     * @param array $tag 标签属性\n     * @param string $content  标签内容\n     * @return string\n     */\n    public function _assign($tag,$content) {\n        $name       =   $this->autoBuildVar($tag['name']);\n        if('$'==substr($tag['value'],0,1)) {\n            $value  =   $this->autoBuildVar(substr($tag['value'],1));\n        }else{\n            $value  =   '\\''.$tag['value']. '\\'';\n        }\n        $parseStr   =   '<?php '.$name.' = '.$value.'; ?>';\n        return $parseStr;\n    }\n\n    /**\n     * define标签解析\n     * 在模板中定义常量 支持变量赋值\n     * 格式： <define name=\"\" value=\"\" />\n     * @access public\n     * @param array $tag 标签属性\n     * @param string $content  标签内容\n     * @return string\n     */\n    public function _define($tag,$content) {\n        $name       =   '\\''.$tag['name']. '\\'';\n        if('$'==substr($tag['value'],0,1)) {\n            $value  =   $this->autoBuildVar(substr($tag['value'],1));\n        }else{\n            $value  =   '\\''.$tag['value']. '\\'';\n        }\n        $parseStr   =   '<?php define('.$name.', '.$value.'); ?>';\n        return $parseStr;\n    }\n    \n    /**\n     * for标签解析\n     * 格式： <for start=\"\" end=\"\" comparison=\"\" step=\"\" name=\"\" />\n     * @access public\n     * @param array $tag 标签属性\n     * @param string $content  标签内容\n     * @return string\n     */\n    public function _for($tag, $content){\n        //设置默认值\n        $start \t\t= 0;\n        $end   \t\t= 0;\n        $step \t\t= 1;\n        $comparison = 'lt';\n        $name\t\t= 'i';\n        $rand       = rand(); //添加随机数，防止嵌套变量冲突\n        //获取属性\n        foreach ($tag as $key => $value){\n            $value = trim($value);\n            if(':'==substr($value,0,1))\n                $value = substr($value,1);\n            elseif('$'==substr($value,0,1))\n                $value = $this->autoBuildVar(substr($value,1));\n            switch ($key){\n                case 'start':   \n                    $start      = $value; break;\n                case 'end' :    \n                    $end        = $value; break;\n                case 'step':    \n                    $step       = $value; break;\n                case 'comparison':\n                    $comparison = $value; break;\n                case 'name':\n                    $name       = $value; break;\n            }\n        }\n        \n        $parseStr   = '<?php $__FOR_START_'.$rand.'__='.$start.';$__FOR_END_'.$rand.'__='.$end.';';\n        $parseStr  .= 'for($'.$name.'=$__FOR_START_'.$rand.'__;'.$this->parseCondition('$'.$name.' '.$comparison.' $__FOR_END_'.$rand.'__').';$'.$name.'+='.$step.'){ ?>';\n        $parseStr  .= $content;\n        $parseStr  .= '<?php } ?>';\n        return $parseStr;\n    }\n\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Template/TagLib/Html.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\nnamespace Think\\Template\\TagLib;\nuse Think\\Template\\TagLib;\n/**\n * Html标签库驱动\n */\nclass Html extends TagLib{\n    // 标签定义\n    protected $tags   =  array(\n        // 标签定义： attr 属性列表 close 是否闭合（0 或者1 默认1） alias 标签别名 level 嵌套层次\n        'editor'    => array('attr'=>'id,name,style,width,height,type','close'=>1),\n        'select'    => array('attr'=>'name,options,values,output,multiple,id,size,first,change,selected,dblclick','close'=>0),\n        'grid'      => array('attr'=>'id,pk,style,action,actionlist,show,datasource','close'=>0),\n        'list'      => array('attr'=>'id,pk,style,action,actionlist,show,datasource,checkbox','close'=>0),\n        'imagebtn'  => array('attr'=>'id,name,value,type,style,click','close'=>0),\n        'checkbox'  => array('attr'=>'name,checkboxes,checked,separator','close'=>0),\n        'radio'     => array('attr'=>'name,radios,checked,separator','close'=>0)\n        );\n\n    /**\n     * editor标签解析 插入可视化编辑器\n     * 格式： <html:editor id=\"editor\" name=\"remark\" type=\"FCKeditor\" style=\"\" >{$vo.remark}</html:editor>\n     * @access public\n     * @param array $tag 标签属性\n     * @return string|void\n     */\n    public function _editor($tag,$content) {\n        $id\t\t\t=\t!empty($tag['id'])?$tag['id']: '_editor';\n        $name   \t=\t$tag['name'];\n        $style   \t    =\t!empty($tag['style'])?$tag['style']:'';\n        $width\t\t=\t!empty($tag['width'])?$tag['width']: '100%';\n        $height     =\t!empty($tag['height'])?$tag['height'] :'320px';\n     //   $content    =   $tag['content'];\n        $type       =   $tag['type'] ;\n        switch(strtoupper($type)) {\n            case 'FCKEDITOR':\n                $parseStr   =\t'<!-- 编辑器调用开始 --><script type=\"text/javascript\" src=\"__ROOT__/Public/Js/FCKeditor/fckeditor.js\"></script><textarea id=\"'.$id.'\" name=\"'.$name.'\">'.$content.'</textarea><script type=\"text/javascript\"> var oFCKeditor = new FCKeditor( \"'.$id.'\",\"'.$width.'\",\"'.$height.'\" ) ; oFCKeditor.BasePath = \"__ROOT__/Public/Js/FCKeditor/\" ; oFCKeditor.ReplaceTextarea() ;function resetEditor(){setContents(\"'.$id.'\",document.getElementById(\"'.$id.'\").value)}; function saveEditor(){document.getElementById(\"'.$id.'\").value = getContents(\"'.$id.'\");} function InsertHTML(html){ var oEditor = FCKeditorAPI.GetInstance(\"'.$id.'\") ;if (oEditor.EditMode == FCK_EDITMODE_WYSIWYG ){oEditor.InsertHtml(html) ;}else\talert( \"FCK必须处于WYSIWYG模式!\" ) ;}</script> <!-- 编辑器调用结束 -->';\n                break;\n            case 'FCKMINI':\n                $parseStr   =\t'<!-- 编辑器调用开始 --><script type=\"text/javascript\" src=\"__ROOT__/Public/Js/FCKMini/fckeditor.js\"></script><textarea id=\"'.$id.'\" name=\"'.$name.'\">'.$content.'</textarea><script type=\"text/javascript\"> var oFCKeditor = new FCKeditor( \"'.$id.'\",\"'.$width.'\",\"'.$height.'\" ) ; oFCKeditor.BasePath = \"__ROOT__/Public/Js/FCKMini/\" ; oFCKeditor.ReplaceTextarea() ;function resetEditor(){setContents(\"'.$id.'\",document.getElementById(\"'.$id.'\").value)}; function saveEditor(){document.getElementById(\"'.$id.'\").value = getContents(\"'.$id.'\");} function InsertHTML(html){ var oEditor = FCKeditorAPI.GetInstance(\"'.$id.'\") ;if (oEditor.EditMode == FCK_EDITMODE_WYSIWYG ){oEditor.InsertHtml(html) ;}else\talert( \"FCK必须处于WYSIWYG模式!\" ) ;}</script> <!-- 编辑器调用结束 -->';\n                break;\n            case 'EWEBEDITOR':\n                $parseStr\t=\t\"<!-- 编辑器调用开始 --><script type='text/javascript' src='__ROOT__/Public/Js/eWebEditor/js/edit.js'></script><input type='hidden'  id='{$id}' name='{$name}'  value='{$conent}'><iframe src='__ROOT__/Public/Js/eWebEditor/ewebeditor.htm?id={$name}' frameborder=0 scrolling=no width='{$width}' height='{$height}'></iframe><script type='text/javascript'>function saveEditor(){document.getElementById('{$id}').value = getHTML();} </script><!-- 编辑器调用结束 -->\";\n                break;\n            case 'NETEASE':\n                $parseStr   =\t'<!-- 编辑器调用开始 --><textarea id=\"'.$id.'\" name=\"'.$name.'\" style=\"display:none\">'.$content.'</textarea><iframe ID=\"Editor\" name=\"Editor\" src=\"__ROOT__/Public/Js/HtmlEditor/index.html?ID='.$name.'\" frameBorder=\"0\" marginHeight=\"0\" marginWidth=\"0\" scrolling=\"No\" style=\"height:'.$height.';width:'.$width.'\"></iframe><!-- 编辑器调用结束 -->';\n                break;\n            case 'UBB':\n                $parseStr\t=\t'<script type=\"text/javascript\" src=\"__ROOT__/Public/Js/UbbEditor.js\"></script><div style=\"padding:1px;width:'.$width.';border:1px solid silver;float:left;\"><script LANGUAGE=\"JavaScript\"> showTool(); </script></div><div><TEXTAREA id=\"UBBEditor\" name=\"'.$name.'\"  style=\"clear:both;float:none;width:'.$width.';height:'.$height.'\" >'.$content.'</TEXTAREA></div><div style=\"padding:1px;width:'.$width.';border:1px solid silver;float:left;\"><script LANGUAGE=\"JavaScript\">showEmot();  </script></div>';\n                break;\n            case 'KINDEDITOR':\n                $parseStr   =  '<script type=\"text/javascript\" src=\"__ROOT__/Public/Js/KindEditor/kindeditor.js\"></script><script type=\"text/javascript\"> KE.show({ id : \\''.$id.'\\'  ,urlType : \"absolute\"});</script><textarea id=\"'.$id.'\" style=\"'.$style.'\" name=\"'.$name.'\" >'.$content.'</textarea>';\n                break;\n            default :\n                $parseStr  =  '<textarea id=\"'.$id.'\" style=\"'.$style.'\" name=\"'.$name.'\" >'.$content.'</textarea>';\n        }\n\n        return $parseStr;\n    }\n\n    /**\n     * imageBtn标签解析\n     * 格式： <html:imageBtn type=\"\" value=\"\" />\n     * @access public\n     * @param array $tag 标签属性\n     * @return string|void\n     */\n    public function _imageBtn($tag) {\n        $name       = $tag['name'];                //名称\n        $value      = $tag['value'];                //文字\n        $id         = isset($tag['id'])?$tag['id']:'';                //ID\n        $style      = isset($tag['style'])?$tag['style']:'';                //样式名\n        $click      = isset($tag['click'])?$tag['click']:'';                //点击\n        $type       = empty($tag['type'])?'button':$tag['type'];                //按钮类型\n\n        if(!empty($name)) {\n            $parseStr   = '<div class=\"'.$style.'\" ><input type=\"'.$type.'\" id=\"'.$id.'\" name=\"'.$name.'\" value=\"'.$value.'\" onclick=\"'.$click.'\" class=\"'.$name.' imgButton\"></div>';\n        }else {\n        \t$parseStr   = '<div class=\"'.$style.'\" ><input type=\"'.$type.'\" id=\"'.$id.'\"  name=\"'.$name.'\" value=\"'.$value.'\" onclick=\"'.$click.'\" class=\"button\"></div>';\n        }\n\n        return $parseStr;\n    }\n\n    /**\n     * imageLink标签解析\n     * 格式： <html:imageLink type=\"\" value=\"\" />\n     * @access public\n     * @param array $tag 标签属性\n     * @return string|void\n     */\n    public function _imgLink($tag) {\n        $name       = $tag['name'];                //名称\n        $alt        = $tag['alt'];                //文字\n        $id         = $tag['id'];                //ID\n        $style      = $tag['style'];                //样式名\n        $click      = $tag['click'];                //点击\n        $type       = $tag['type'];                //点击\n        if(empty($type)) {\n            $type = 'button';\n        }\n       \t$parseStr   = '<span class=\"'.$style.'\" ><input title=\"'.$alt.'\" type=\"'.$type.'\" id=\"'.$id.'\"  name=\"'.$name.'\" onmouseover=\"this.style.filter=\\'alpha(opacity=100)\\'\" onmouseout=\"this.style.filter=\\'alpha(opacity=80)\\'\" onclick=\"'.$click.'\" align=\"absmiddle\" class=\"'.$name.' imgLink\"></span>';\n\n        return $parseStr;\n    }\n\n    /**\n     * select标签解析\n     * 格式： <html:select options=\"name\" selected=\"value\" />\n     * @access public\n     * @param array $tag 标签属性\n     * @return string|void\n     */\n    public function _select($tag) {\n        $name       = $tag['name'];\n        $options    = $tag['options'];\n        $values     = $tag['values'];\n        $output     = $tag['output'];\n        $multiple   = $tag['multiple'];\n        $id         = $tag['id'];\n        $size       = $tag['size'];\n        $first      = $tag['first'];\n        $selected   = $tag['selected'];\n        $style      = $tag['style'];\n        $ondblclick = $tag['dblclick'];\n\t\t$onchange\t= $tag['change'];\n\n        if(!empty($multiple)) {\n            $parseStr = '<select id=\"'.$id.'\" name=\"'.$name.'\" ondblclick=\"'.$ondblclick.'\" onchange=\"'.$onchange.'\" multiple=\"multiple\" class=\"'.$style.'\" size=\"'.$size.'\" >';\n        }else {\n        \t$parseStr = '<select id=\"'.$id.'\" name=\"'.$name.'\" onchange=\"'.$onchange.'\" ondblclick=\"'.$ondblclick.'\" class=\"'.$style.'\" >';\n        }\n        if(!empty($first)) {\n            $parseStr .= '<option value=\"\" >'.$first.'</option>';\n        }\n        if(!empty($options)) {\n            $parseStr   .= '<?php  foreach($'.$options.' as $key=>$val) { ?>';\n            if(!empty($selected)) {\n                $parseStr   .= '<?php if(!empty($'.$selected.') && ($'.$selected.' == $key || in_array($key,$'.$selected.'))) { ?>';\n                $parseStr   .= '<option selected=\"selected\" value=\"<?php echo $key ?>\"><?php echo $val ?></option>';\n                $parseStr   .= '<?php }else { ?><option value=\"<?php echo $key ?>\"><?php echo $val ?></option>';\n                $parseStr   .= '<?php } ?>';\n            }else {\n                $parseStr   .= '<option value=\"<?php echo $key ?>\"><?php echo $val ?></option>';\n            }\n            $parseStr   .= '<?php } ?>';\n        }else if(!empty($values)) {\n            $parseStr   .= '<?php  for($i=0;$i<count($'.$values.');$i++) { ?>';\n            if(!empty($selected)) {\n                $parseStr   .= '<?php if(isset($'.$selected.') && ((is_string($'.$selected.') && $'.$selected.' == $'.$values.'[$i]) || (is_array($'.$selected.') && in_array($'.$values.'[$i],$'.$selected.')))) { ?>';\n                $parseStr   .= '<option selected=\"selected\" value=\"<?php echo $'.$values.'[$i] ?>\"><?php echo $'.$output.'[$i] ?></option>';\n                $parseStr   .= '<?php }else { ?><option value=\"<?php echo $'.$values.'[$i] ?>\"><?php echo $'.$output.'[$i] ?></option>';\n                $parseStr   .= '<?php } ?>';\n            }else {\n                $parseStr   .= '<option value=\"<?php echo $'.$values.'[$i] ?>\"><?php echo $'.$output.'[$i] ?></option>';\n            }\n            $parseStr   .= '<?php } ?>';\n        }\n        $parseStr   .= '</select>';\n        return $parseStr;\n    }\n\n    /**\n     * checkbox标签解析\n     * 格式： <html:checkbox checkboxes=\"\" checked=\"\" />\n     * @access public\n     * @param array $tag 标签属性\n     * @return string|void\n     */\n    public function _checkbox($tag) {\n        $name       = $tag['name'];\n        $checkboxes = $tag['checkboxes'];\n        $checked    = $tag['checked'];\n        $separator  = $tag['separator'];\n        $checkboxes = $this->tpl->get($checkboxes);\n        $checked    = $this->tpl->get($checked)?$this->tpl->get($checked):$checked;\n        $parseStr   = '';\n        foreach($checkboxes as $key=>$val) {\n            if($checked == $key  || in_array($key,$checked) ) {\n                $parseStr .= '<input type=\"checkbox\" checked=\"checked\" name=\"'.$name.'[]\" value=\"'.$key.'\">'.$val.$separator;\n            }else {\n                $parseStr .= '<input type=\"checkbox\" name=\"'.$name.'[]\" value=\"'.$key.'\">'.$val.$separator;\n            }\n        }\n        return $parseStr;\n    }\n\n    /**\n     * radio标签解析\n     * 格式： <html:radio radios=\"name\" checked=\"value\" />\n     * @access public\n     * @param array $tag 标签属性\n     * @return string|void\n     */\n    public function _radio($tag) {\n        $name       = $tag['name'];\n        $radios     = $tag['radios'];\n        $checked    = $tag['checked'];\n        $separator  = $tag['separator'];\n        $radios     = $this->tpl->get($radios);\n        $checked    = $this->tpl->get($checked)?$this->tpl->get($checked):$checked;\n        $parseStr   = '';\n        foreach($radios as $key=>$val) {\n            if($checked == $key ) {\n                $parseStr .= '<input type=\"radio\" checked=\"checked\" name=\"'.$name.'[]\" value=\"'.$key.'\">'.$val.$separator;\n            }else {\n                $parseStr .= '<input type=\"radio\" name=\"'.$name.'[]\" value=\"'.$key.'\">'.$val.$separator;\n            }\n\n        }\n        return $parseStr;\n    }\n\n    /**\n     * list标签解析\n     * 格式： <html:grid datasource=\"\" show=\"vo\" />\n     * @access public\n     * @param array $tag 标签属性\n     * @return string\n     */\n    public function _grid($tag) {\n        $id         = $tag['id'];                       //表格ID\n        $datasource = $tag['datasource'];               //列表显示的数据源VoList名称\n        $pk         = empty($tag['pk'])?'id':$tag['pk'];//主键名，默认为id\n        $style      = $tag['style'];                    //样式名\n        $name       = !empty($tag['name'])?$tag['name']:'vo';                 //Vo对象名\n        $action     = !empty($tag['action'])?$tag['action']:false;                   //是否显示功能操作\n        $key         =  !empty($tag['key'])?true:false;\n        if(isset($tag['actionlist'])) {\n            $actionlist = explode(',',trim($tag['actionlist']));    //指定功能列表\n        }\n\n        if(substr($tag['show'],0,1)=='$') {\n            $show   = $this->tpl->get(substr($tag['show'],1));\n        }else {\n            $show   = $tag['show'];\n        }\n        $show       = explode(',',$show);                //列表显示字段列表\n\n        //计算表格的列数\n        $colNum     = count($show);\n        if(!empty($action))     $colNum++;\n        if(!empty($key))  $colNum++;\n\n        //显示开始\n\t\t$parseStr\t= \"<!-- Think 系统列表组件开始 -->\\n\";\n        $parseStr  .= '<table id=\"'.$id.'\" class=\"'.$style.'\" cellpadding=0 cellspacing=0 >';\n        $parseStr  .= '<tr><td height=\"5\" colspan=\"'.$colNum.'\" class=\"topTd\" ></td></tr>';\n        $parseStr  .= '<tr class=\"row\" >';\n        //列表需要显示的字段\n        $fields = array();\n        foreach($show as $val) {\n        \t$fields[] = explode(':',$val);\n        }\n\n        if(!empty($key)) {\n            $parseStr .= '<th width=\"12\">No</th>';\n        }\n        foreach($fields as $field) {//显示指定的字段\n            $property = explode('|',$field[0]);\n            $showname = explode('|',$field[1]);\n            if(isset($showname[1])) {\n                $parseStr .= '<th width=\"'.$showname[1].'\">';\n            }else {\n                $parseStr .= '<th>';\n            }\n            $parseStr .= $showname[0].'</th>';\n        }\n        if(!empty($action)) {//如果指定显示操作功能列\n            $parseStr .= '<th >操作</th>';\n        }\n        $parseStr .= '</tr>';\n        $parseStr .= '<volist name=\"'.$datasource.'\" id=\"'.$name.'\" ><tr class=\"row\" >';\t//支持鼠标移动单元行颜色变化 具体方法在js中定义\n\n        if(!empty($key)) {\n            $parseStr .= '<td>{$i}</td>';\n        }\n        foreach($fields as $field) {\n            //显示定义的列表字段\n            $parseStr   .=  '<td>';\n            if(!empty($field[2])) {\n                // 支持列表字段链接功能 具体方法由JS函数实现\n                $href = explode('|',$field[2]);\n                if(count($href)>1) {\n                    //指定链接传的字段值\n                    // 支持多个字段传递\n                    $array = explode('^',$href[1]);\n                    if(count($array)>1) {\n                        foreach ($array as $a){\n                            $temp[] =  '\\'{$'.$name.'.'.$a.'|addslashes}\\'';\n                        }\n                        $parseStr .= '<a href=\"javascript:'.$href[0].'('.implode(',',$temp).')\">';\n                    }else{\n                        $parseStr .= '<a href=\"javascript:'.$href[0].'(\\'{$'.$name.'.'.$href[1].'|addslashes}\\')\">';\n                    }\n                }else {\n                    //如果没有指定默认传编号值\n                    $parseStr .= '<a href=\"javascript:'.$field[2].'(\\'{$'.$name.'.'.$pk.'|addslashes}\\')\">';\n                }\n            }\n            if(strpos($field[0],'^')) {\n                $property = explode('^',$field[0]);\n                foreach ($property as $p){\n                    $unit = explode('|',$p);\n                    if(count($unit)>1) {\n                        $parseStr .= '{$'.$name.'.'.$unit[0].'|'.$unit[1].'} ';\n                    }else {\n                        $parseStr .= '{$'.$name.'.'.$p.'} ';\n                    }\n                }\n            }else{\n                $property = explode('|',$field[0]);\n                if(count($property)>1) {\n                    $parseStr .= '{$'.$name.'.'.$property[0].'|'.$property[1].'}';\n                }else {\n                    $parseStr .= '{$'.$name.'.'.$field[0].'}';\n                }\n            }\n            if(!empty($field[2])) {\n                $parseStr .= '</a>';\n            }\n            $parseStr .= '</td>';\n\n        }\n        if(!empty($action)) {//显示功能操作\n            if(!empty($actionlist[0])) {//显示指定的功能项\n                $parseStr .= '<td>';\n                foreach($actionlist as $val) {\n\t\t\t\t\tif(strpos($val,':')) {\n\t\t\t\t\t\t$a = explode(':',$val);\n\t\t\t\t\t\tif(count($a)>2) {\n                            $parseStr .= '<a href=\"javascript:'.$a[0].'(\\'{$'.$name.'.'.$a[2].'}\\')\">'.$a[1].'</a>&nbsp;';\n\t\t\t\t\t\t}else {\n\t\t\t\t\t\t\t$parseStr .= '<a href=\"javascript:'.$a[0].'(\\'{$'.$name.'.'.$pk.'}\\')\">'.$a[1].'</a>&nbsp;';\n\t\t\t\t\t\t}\n\t\t\t\t\t}else{\n\t\t\t\t\t\t$array\t=\texplode('|',$val);\n\t\t\t\t\t\tif(count($array)>2) {\n\t\t\t\t\t\t\t$parseStr\t.= ' <a href=\"javascript:'.$array[1].'(\\'{$'.$name.'.'.$array[0].'}\\')\">'.$array[2].'</a>&nbsp;';\n\t\t\t\t\t\t}else{\n\t\t\t\t\t\t\t$parseStr .= ' {$'.$name.'.'.$val.'}&nbsp;';\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n                }\n                $parseStr .= '</td>';\n            }\n        }\n        $parseStr\t.= '</tr></volist><tr><td height=\"5\" colspan=\"'.$colNum.'\" class=\"bottomTd\"></td></tr></table>';\n        $parseStr\t.= \"\\n<!-- Think 系统列表组件结束 -->\\n\";\n        return $parseStr;\n    }\n\n    /**\n     * list标签解析\n     * 格式： <html:list datasource=\"\" show=\"\" />\n     * @access public\n     * @param array $tag 标签属性\n     * @return string\n     */\n    public function _list($tag) {\n        $id         = $tag['id'];                       //表格ID\n        $datasource = $tag['datasource'];               //列表显示的数据源VoList名称\n        $pk         = empty($tag['pk'])?'id':$tag['pk'];//主键名，默认为id\n        $style      = $tag['style'];                    //样式名\n        $name       = !empty($tag['name'])?$tag['name']:'vo';                 //Vo对象名\n        $action     = $tag['action']=='true'?true:false;                   //是否显示功能操作\n        $key         =  !empty($tag['key'])?true:false;\n        $sort      = $tag['sort']=='false'?false:true;\n        $checkbox   = $tag['checkbox'];                 //是否显示Checkbox\n        if(isset($tag['actionlist'])) {\n            if(substr($tag['actionlist'],0,1)=='$') {\n                $actionlist   = $this->tpl->get(substr($tag['actionlist'],1));\n            }else {\n                $actionlist   = $tag['actionlist'];\n            }\n            $actionlist = explode(',',trim($actionlist));    //指定功能列表\n        }\n\n        if(substr($tag['show'],0,1)=='$') {\n            $show   = $this->tpl->get(substr($tag['show'],1));\n        }else {\n            $show   = $tag['show'];\n        }\n        $show       = explode(',',$show);                //列表显示字段列表\n\n        //计算表格的列数\n        $colNum     = count($show);\n        if(!empty($checkbox))   $colNum++;\n        if(!empty($action))     $colNum++;\n        if(!empty($key))  $colNum++;\n\n        //显示开始\n\t\t$parseStr\t= \"<!-- Think 系统列表组件开始 -->\\n\";\n        $parseStr  .= '<table id=\"'.$id.'\" class=\"'.$style.'\" cellpadding=0 cellspacing=0 >';\n        $parseStr  .= '<tr><td height=\"5\" colspan=\"'.$colNum.'\" class=\"topTd\" ></td></tr>';\n        $parseStr  .= '<tr class=\"row\" >';\n        //列表需要显示的字段\n        $fields = array();\n        foreach($show as $val) {\n        \t$fields[] = explode(':',$val);\n        }\n        if(!empty($checkbox) && 'true'==strtolower($checkbox)) {//如果指定需要显示checkbox列\n            $parseStr .='<th width=\"8\"><input type=\"checkbox\" id=\"check\" onclick=\"CheckAll(\\''.$id.'\\')\"></th>';\n        }\n        if(!empty($key)) {\n            $parseStr .= '<th width=\"12\">No</th>';\n        }\n        foreach($fields as $field) {//显示指定的字段\n            $property = explode('|',$field[0]);\n            $showname = explode('|',$field[1]);\n            if(isset($showname[1])) {\n                $parseStr .= '<th width=\"'.$showname[1].'\">';\n            }else {\n                $parseStr .= '<th>';\n            }\n            $showname[2] = isset($showname[2])?$showname[2]:$showname[0];\n            if($sort) {\n                $parseStr .= '<a href=\"javascript:sortBy(\\''.$property[0].'\\',\\'{$sort}\\',\\''.ACTION_NAME.'\\')\" title=\"按照'.$showname[2].'{$sortType} \">'.$showname[0].'<eq name=\"order\" value=\"'.$property[0].'\" ><img src=\"__PUBLIC__/images/{$sortImg}.gif\" width=\"12\" height=\"17\" border=\"0\" align=\"absmiddle\"></eq></a></th>';\n            }else{\n                $parseStr .= $showname[0].'</th>';\n            }\n\n        }\n        if(!empty($action)) {//如果指定显示操作功能列\n            $parseStr .= '<th >操作</th>';\n        }\n\n        $parseStr .= '</tr>';\n        $parseStr .= '<volist name=\"'.$datasource.'\" id=\"'.$name.'\" ><tr class=\"row\" ';\t//支持鼠标移动单元行颜色变化 具体方法在js中定义\n        if(!empty($checkbox)) {\n        //    $parseStr .= 'onmouseover=\"over(event)\" onmouseout=\"out(event)\" onclick=\"change(event)\" ';\n        }\n        $parseStr .= '>';\n        if(!empty($checkbox)) {//如果需要显示checkbox 则在每行开头显示checkbox\n            $parseStr .= '<td><input type=\"checkbox\" name=\"key\"\tvalue=\"{$'.$name.'.'.$pk.'}\"></td>';\n        }\n        if(!empty($key)) {\n            $parseStr .= '<td>{$i}</td>';\n        }\n        foreach($fields as $field) {\n            //显示定义的列表字段\n            $parseStr   .=  '<td>';\n            if(!empty($field[2])) {\n                // 支持列表字段链接功能 具体方法由JS函数实现\n                $href = explode('|',$field[2]);\n                if(count($href)>1) {\n                    //指定链接传的字段值\n                    // 支持多个字段传递\n                    $array = explode('^',$href[1]);\n                    if(count($array)>1) {\n                        foreach ($array as $a){\n                            $temp[] =  '\\'{$'.$name.'.'.$a.'|addslashes}\\'';\n                        }\n                        $parseStr .= '<a href=\"javascript:'.$href[0].'('.implode(',',$temp).')\">';\n                    }else{\n                        $parseStr .= '<a href=\"javascript:'.$href[0].'(\\'{$'.$name.'.'.$href[1].'|addslashes}\\')\">';\n                    }\n                }else {\n                    //如果没有指定默认传编号值\n                    $parseStr .= '<a href=\"javascript:'.$field[2].'(\\'{$'.$name.'.'.$pk.'|addslashes}\\')\">';\n                }\n            }\n            if(strpos($field[0],'^')) {\n                $property = explode('^',$field[0]);\n                foreach ($property as $p){\n                    $unit = explode('|',$p);\n                    if(count($unit)>1) {\n                        $parseStr .= '{$'.$name.'.'.$unit[0].'|'.$unit[1].'} ';\n                    }else {\n                        $parseStr .= '{$'.$name.'.'.$p.'} ';\n                    }\n                }\n            }else{\n                $property = explode('|',$field[0]);\n                if(count($property)>1) {\n                    $parseStr .= '{$'.$name.'.'.$property[0].'|'.$property[1].'}';\n                }else {\n                    $parseStr .= '{$'.$name.'.'.$field[0].'}';\n                }\n            }\n            if(!empty($field[2])) {\n                $parseStr .= '</a>';\n            }\n            $parseStr .= '</td>';\n\n        }\n        if(!empty($action)) {//显示功能操作\n            if(!empty($actionlist[0])) {//显示指定的功能项\n                $parseStr .= '<td>';\n                foreach($actionlist as $val) {\n                    if(strpos($val,':')) {\n                        $a = explode(':',$val);\n                        if(count($a)>2) {\n                            $parseStr .= '<a href=\"javascript:'.$a[0].'(\\'{$'.$name.'.'.$a[2].'}\\')\">'.$a[1].'</a>&nbsp;';\n                        }else {\n                            $parseStr .= '<a href=\"javascript:'.$a[0].'(\\'{$'.$name.'.'.$pk.'}\\')\">'.$a[1].'</a>&nbsp;';\n                        }\n                    }else{\n                        $array\t=\texplode('|',$val);\n                        if(count($array)>2) {\n                            $parseStr\t.= ' <a href=\"javascript:'.$array[1].'(\\'{$'.$name.'.'.$array[0].'}\\')\">'.$array[2].'</a>&nbsp;';\n                        }else{\n                            $parseStr .= ' {$'.$name.'.'.$val.'}&nbsp;';\n                        }\n                    }\n                }\n                $parseStr .= '</td>';\n            }\n        }\n        $parseStr\t.= '</tr></volist><tr><td height=\"5\" colspan=\"'.$colNum.'\" class=\"bottomTd\"></td></tr></table>';\n        $parseStr\t.= \"\\n<!-- Think 系统列表组件结束 -->\\n\";\n        return $parseStr;\n    }\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Template/TagLib.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\nnamespace Think\\Template;\n/**\n * ThinkPHP标签库TagLib解析基类\n */\nclass TagLib {\n\n    /**\n     * 标签库定义XML文件\n     * @var string\n     * @access protected\n     */\n    protected $xml      = '';\n    protected $tags     = array();// 标签定义\n    /**\n     * 标签库名称\n     * @var string\n     * @access protected\n     */\n    protected $tagLib   ='';\n\n    /**\n     * 标签库标签列表\n     * @var string\n     * @access protected\n     */\n    protected $tagList  = array();\n\n    /**\n     * 标签库分析数组\n     * @var string\n     * @access protected\n     */\n    protected $parse    = array();\n\n    /**\n     * 标签库是否有效\n     * @var string\n     * @access protected\n     */\n    protected $valid    = false;\n\n    /**\n     * 当前模板对象\n     * @var object\n     * @access protected\n     */\n    protected $tpl;\n\n    protected $comparison = array(' nheq '=>' !== ',' heq '=>' === ',' neq '=>' != ',' eq '=>' == ',' egt '=>' >= ',' gt '=>' > ',' elt '=>' <= ',' lt '=>' < ');\n\n    /**\n     * 架构函数\n     * @access public\n     */\n    public function __construct() {\n        $this->tagLib  = strtolower(substr(get_class($this),6));\n        $this->tpl     = \\Think\\Think::instance('Think\\\\Template');\n    }\n\n    /**\n     * TagLib标签属性分析 返回标签属性数组\n     * @access public\n     * @param string $tagStr 标签内容\n     * @return array\n     */\n    public function parseXmlAttr($attr,$tag) {\n        //XML解析安全过滤\n        $attr   =   str_replace('&','___', $attr);\n        $xml    =   '<tpl><tag '.$attr.' /></tpl>';\n        $xml    =   simplexml_load_string($xml);\n        if(!$xml) {\n            E(L('_XML_TAG_ERROR_').' : '.$attr);\n        }\n        $xml    =   (array)($xml->tag->attributes());\n        if(isset($xml['@attributes'])){\n            $array  =   array_change_key_case($xml['@attributes']);\n            if($array) {\n                $tag    =   strtolower($tag);\n                if(!isset($this->tags[$tag])){\n                    // 检测是否存在别名定义\n                    foreach($this->tags as $key=>$val){\n                        if(isset($val['alias']) && in_array($tag,explode(',',$val['alias']))){\n                            $item  =   $val;\n                            break;\n                        }\n                    }\n                }else{\n                    $item  =   $this->tags[$tag];\n                }            \n                $attrs  = explode(',',$item['attr']);\n                if(isset($item['must'])){\n                    $must   =   explode(',',$item['must']);\n                }else{\n                    $must   =   array();\n                }\n                foreach($attrs as $name) {\n                    if( isset($array[$name])) {\n                        $array[$name] = str_replace('___','&',$array[$name]);\n                    }elseif(false !== array_search($name,$must)){\n                        E(L('_PARAM_ERROR_').':'.$name);\n                    }\n                }\n                return $array;\n            }\n        }else{\n            return array();\n        }\n    }\n\n    /**\n     * 解析条件表达式\n     * @access public\n     * @param string $condition 表达式标签内容\n     * @return array\n     */\n    public function parseCondition($condition) {\n        $condition = str_ireplace(array_keys($this->comparison),array_values($this->comparison),$condition);\n        $condition = preg_replace('/\\$(\\w+):(\\w+)\\s/is','$\\\\1->\\\\2 ',$condition);\n        switch(strtolower(C('TMPL_VAR_IDENTIFY'))) {\n            case 'array': // 识别为数组\n                $condition  =   preg_replace('/\\$(\\w+)\\.(\\w+)\\s/is','$\\\\1[\"\\\\2\"] ',$condition);\n                break;\n            case 'obj':  // 识别为对象\n                $condition  =   preg_replace('/\\$(\\w+)\\.(\\w+)\\s/is','$\\\\1->\\\\2 ',$condition);\n                break;\n            default:  // 自动判断数组或对象 只支持二维\n                $condition  =   preg_replace('/\\$(\\w+)\\.(\\w+)\\s/is','(is_array($\\\\1)?$\\\\1[\"\\\\2\"]:$\\\\1->\\\\2) ',$condition);\n        }\n        if(false !== strpos($condition, '$Think'))\n            $condition      =   preg_replace_callback('/(\\$Think.*?)\\s/is', array($this, 'parseThinkVar'), $condition);        \n        return $condition;\n    }\n\n    /**\n     * 自动识别构建变量\n     * @access public\n     * @param string $name 变量描述\n     * @return string\n     */\n    public function autoBuildVar($name) {\n        if('Think.' == substr($name,0,6)){\n            // 特殊变量\n            return $this->parseThinkVar($name);\n        }elseif(strpos($name,'.')) {\n            $vars = explode('.',$name);\n            $var  =  array_shift($vars);\n            switch(strtolower(C('TMPL_VAR_IDENTIFY'))) {\n                case 'array': // 识别为数组\n                    $name = '$'.$var;\n                    foreach ($vars as $key=>$val){\n                        if(0===strpos($val,'$')) {\n                            $name .= '[\"{'.$val.'}\"]';\n                        }else{\n                            $name .= '[\"'.$val.'\"]';\n                        }\n                    }\n                    break;\n                case 'obj':  // 识别为对象\n                    $name = '$'.$var;\n                    foreach ($vars as $key=>$val)\n                        $name .= '->'.$val;\n                    break;\n                default:  // 自动判断数组或对象 只支持二维\n                    $name = 'is_array($'.$var.')?$'.$var.'[\"'.$vars[0].'\"]:$'.$var.'->'.$vars[0];\n            }\n        }elseif(strpos($name,':')){\n            // 额外的对象方式支持\n            $name   =   '$'.str_replace(':','->',$name);\n        }elseif(!defined($name)) {\n            $name = '$'.$name;\n        }\n        return $name;\n    }\n\n    /**\n     * 用于标签属性里面的特殊模板变量解析\n     * 格式 以 Think. 打头的变量属于特殊模板变量\n     * @access public\n     * @param string $varStr  变量字符串\n     * @return string\n     */\n    public function parseThinkVar($varStr){\n        if(is_array($varStr)){//用于正则替换回调函数\n            $varStr = $varStr[1]; \n        }\n        $vars       = explode('.',$varStr);\n        $vars[1]    = strtoupper(trim($vars[1]));\n        $parseStr   = '';\n        if(count($vars)>=3){\n            $vars[2] = trim($vars[2]);\n            switch($vars[1]){\n                case 'SERVER':    $parseStr = '$_SERVER[\\''.$vars[2].'\\']';break;\n                case 'GET':         $parseStr = '$_GET[\\''.$vars[2].'\\']';break;\n                case 'POST':       $parseStr = '$_POST[\\''.$vars[2].'\\']';break;\n                case 'COOKIE':\n                    if(isset($vars[3])) {\n                        $parseStr = '$_COOKIE[\\''.$vars[2].'\\'][\\''.$vars[3].'\\']';\n                    }elseif(C('COOKIE_PREFIX')){\n                        $parseStr = '$_COOKIE[\\''.C('COOKIE_PREFIX').$vars[2].'\\']';\n                    }else{\n                        $parseStr = '$_COOKIE[\\''.$vars[2].'\\']';\n                    }\n                    break;\n                case 'SESSION':\n                    if(isset($vars[3])) {\n                        $parseStr = '$_SESSION[\\''.$vars[2].'\\'][\\''.$vars[3].'\\']';\n                    }elseif(C('SESSION_PREFIX')){\n                        $parseStr = '$_SESSION[\\''.C('SESSION_PREFIX').'\\'][\\''.$vars[2].'\\']';\n                    }else{\n                        $parseStr = '$_SESSION[\\''.$vars[2].'\\']';\n                    }\n                    break;\n                case 'ENV':         $parseStr = '$_ENV[\\''.$vars[2].'\\']';break;\n                case 'REQUEST':  $parseStr = '$_REQUEST[\\''.$vars[2].'\\']';break;\n                case 'CONST':     $parseStr = strtoupper($vars[2]);break;\n                case 'LANG':       $parseStr = 'L(\"'.$vars[2].'\")';break;\n                case 'CONFIG':    $parseStr = 'C(\"'.$vars[2].'\")';break;\n            }\n        }else if(count($vars)==2){\n            switch($vars[1]){\n                case 'NOW':       $parseStr = \"date('Y-m-d g:i a',time())\";break;\n                case 'VERSION':  $parseStr = 'THINK_VERSION';break;\n                case 'TEMPLATE':$parseStr = 'C(\"TEMPLATE_NAME\")';break;\n                case 'LDELIM':    $parseStr = 'C(\"TMPL_L_DELIM\")';break;\n                case 'RDELIM':    $parseStr = 'C(\"TMPL_R_DELIM\")';break;\n                default:  if(defined($vars[1])) $parseStr = $vars[1];\n            }\n        }\n        return $parseStr;\n    }\n\n    // 获取标签定义\n    public function getTags(){\n        return $this->tags;\n    }\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Template.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\nnamespace Think;\n/**\n * ThinkPHP内置模板引擎类\n * 支持XML标签和普通标签的模板解析\n * 编译型模板引擎 支持动态缓存\n */\nclass  Template {\n\n    // 模板页面中引入的标签库列表\n    protected   $tagLib          =   array();\n    // 当前模板文件\n    protected   $templateFile    =   '';\n    // 模板变量\n    public      $tVar            =   array();\n    public      $config          =   array();\n    private     $literal         =   array();\n    private     $block           =   array();\n\n    /**\n     * 架构函数\n     * @access public\n     */\n    public function __construct(){\n        $this->config['cache_path']         =   C('CACHE_PATH');\n        $this->config['template_suffix']    =   C('TMPL_TEMPLATE_SUFFIX');\n        $this->config['cache_suffix']       =   C('TMPL_CACHFILE_SUFFIX');\n        $this->config['tmpl_cache']         =   C('TMPL_CACHE_ON');\n        $this->config['cache_time']         =   C('TMPL_CACHE_TIME');\n        $this->config['taglib_begin']       =   $this->stripPreg(C('TAGLIB_BEGIN'));\n        $this->config['taglib_end']         =   $this->stripPreg(C('TAGLIB_END'));\n        $this->config['tmpl_begin']         =   $this->stripPreg(C('TMPL_L_DELIM'));\n        $this->config['tmpl_end']           =   $this->stripPreg(C('TMPL_R_DELIM'));\n        $this->config['default_tmpl']       =   C('TEMPLATE_NAME');\n        $this->config['layout_item']        =   C('TMPL_LAYOUT_ITEM');\n    }\n\n    private function stripPreg($str) {\n        return str_replace(\n            array('{','}','(',')','|','[',']','-','+','*','.','^','?'),\n            array('\\{','\\}','\\(','\\)','\\|','\\[','\\]','\\-','\\+','\\*','\\.','\\^','\\?'),\n            $str);        \n    }\n\n    // 模板变量获取和设置\n    public function get($name) {\n        if(isset($this->tVar[$name]))\n            return $this->tVar[$name];\n        else\n            return false;\n    }\n\n    public function set($name,$value) {\n        $this->tVar[$name]= $value;\n    }\n\n    /**\n     * 加载模板\n     * @access public\n     * @param string $templateFile 模板文件\n     * @param array  $templateVar 模板变量\n     * @param string $prefix 模板标识前缀\n     * @return void\n     */\n    public function fetch($templateFile,$templateVar,$prefix='') {\n        $this->tVar         =   $templateVar;\n        $templateCacheFile  =   $this->loadTemplate($templateFile,$prefix);\n        Storage::load($templateCacheFile,$this->tVar,null,'tpl');\n    }\n\n    /**\n     * 加载主模板并缓存\n     * @access public\n     * @param string $templateFile 模板文件\n     * @param string $prefix 模板标识前缀\n     * @return string\n     * @throws ThinkExecption\n     */\n    public function loadTemplate ($templateFile,$prefix='') {\n        if(is_file($templateFile)) {\n            $this->templateFile    =  $templateFile;\n            // 读取模板文件内容\n            $tmplContent =  file_get_contents($templateFile);\n        }else{\n            $tmplContent =  $templateFile;\n        }\n         // 根据模版文件名定位缓存文件\n        $tmplCacheFile = $this->config['cache_path'].$prefix.md5($templateFile).$this->config['cache_suffix'];\n\n        // 判断是否启用布局\n        if(C('LAYOUT_ON')) {\n            if(false !== strpos($tmplContent,'{__NOLAYOUT__}')) { // 可以单独定义不使用布局\n                $tmplContent = str_replace('{__NOLAYOUT__}','',$tmplContent);\n            }else{ // 替换布局的主体内容\n                $layoutFile  =  THEME_PATH.C('LAYOUT_NAME').$this->config['template_suffix'];\n                // 检查布局文件\n                if(!is_file($layoutFile)) {\n                    E(L('_TEMPLATE_NOT_EXIST_').':'.$layoutFile);\n                }\n                $tmplContent = str_replace($this->config['layout_item'],$tmplContent,file_get_contents($layoutFile));\n            }\n        }\n        // 编译模板内容\n        $tmplContent =  $this->compiler($tmplContent);\n        Storage::put($tmplCacheFile,trim($tmplContent),'tpl');\n        return $tmplCacheFile;\n    }\n\n    /**\n     * 编译模板文件内容\n     * @access protected\n     * @param mixed $tmplContent 模板内容\n     * @return string\n     */\n    protected function compiler($tmplContent) {\n        //模板解析\n        $tmplContent =  $this->parse($tmplContent);\n        // 还原被替换的Literal标签\n        $tmplContent =  preg_replace_callback('/<!--###literal(\\d+)###-->/is', array($this, 'restoreLiteral'), $tmplContent);\n        // 添加安全代码\n        $tmplContent =  '<?php if (!defined(\\'THINK_PATH\\')) exit();?>'.$tmplContent;\n        // 优化生成的php代码\n        $tmplContent = str_replace('?><?php','',$tmplContent);\n        // 模版编译过滤标签\n        Hook::listen('template_filter',$tmplContent);\n        return strip_whitespace($tmplContent);\n    }\n\n    /**\n     * 模板解析入口\n     * 支持普通标签和TagLib解析 支持自定义标签库\n     * @access public\n     * @param string $content 要解析的模板内容\n     * @return string\n     */\n    public function parse($content) {\n        // 内容为空不解析\n        if(empty($content)) return '';\n        $begin      =   $this->config['taglib_begin'];\n        $end        =   $this->config['taglib_end'];\n        // 检查include语法\n        $content    =   $this->parseInclude($content);\n        // 检查PHP语法\n        $content    =   $this->parsePhp($content);\n        // 首先替换literal标签内容\n        $content    =   preg_replace_callback('/'.$begin.'literal'.$end.'(.*?)'.$begin.'\\/literal'.$end.'/is', array($this, 'parseLiteral'),$content);\n\n        // 获取需要引入的标签库列表\n        // 标签库只需要定义一次，允许引入多个一次\n        // 一般放在文件的最前面\n        // 格式：<taglib name=\"html,mytag...\" />\n        // 当TAGLIB_LOAD配置为true时才会进行检测\n        if(C('TAGLIB_LOAD')) {\n            $this->getIncludeTagLib($content);\n            if(!empty($this->tagLib)) {\n                // 对导入的TagLib进行解析\n                foreach($this->tagLib as $tagLibName) {\n                    $this->parseTagLib($tagLibName,$content);\n                }\n            }\n        }\n        // 预先加载的标签库 无需在每个模板中使用taglib标签加载 但必须使用标签库XML前缀\n        if(C('TAGLIB_PRE_LOAD')) {\n            $tagLibs =  explode(',',C('TAGLIB_PRE_LOAD'));\n            foreach ($tagLibs as $tag){\n                $this->parseTagLib($tag,$content);\n            }\n        }\n        // 内置标签库 无需使用taglib标签导入就可以使用 并且不需使用标签库XML前缀\n        $tagLibs =  explode(',',C('TAGLIB_BUILD_IN'));\n        foreach ($tagLibs as $tag){\n            $this->parseTagLib($tag,$content,true);\n        }\n        //解析普通模板标签 {$tagName}\n        $content = preg_replace_callback('/('.$this->config['tmpl_begin'].')([^\\d\\w\\s'.$this->config['tmpl_begin'].$this->config['tmpl_end'].'].+?)('.$this->config['tmpl_end'].')/is', array($this, 'parseTag'),$content);\n        return $content;\n    }\n\n    // 检查PHP语法\n    protected function parsePhp($content) {\n        if(ini_get('short_open_tag')){\n            // 开启短标签的情况要将<?标签用echo方式输出 否则无法正常输出xml标识\n            $content = preg_replace('/(<\\?(?!php|=|$))/i', '<?php echo \\'\\\\1\\'; ?>'.\"\\n\", $content );\n        }\n        // PHP语法检查\n        if(C('TMPL_DENY_PHP') && false !== strpos($content,'<?php')) {\n            E(L('_NOT_ALLOW_PHP_'));\n        }\n        return $content;\n    }\n\n    // 解析模板中的布局标签\n    protected function parseLayout($content) {\n        // 读取模板中的布局标签\n        $find = preg_match('/'.$this->config['taglib_begin'].'layout\\s(.+?)\\s*?\\/'.$this->config['taglib_end'].'/is',$content,$matches);\n        if($find) {\n            //替换Layout标签\n            $content    =   str_replace($matches[0],'',$content);\n            //解析Layout标签\n            $array      =   $this->parseXmlAttrs($matches[1]);\n            if(!C('LAYOUT_ON') || C('LAYOUT_NAME') !=$array['name'] ) {\n                // 读取布局模板\n                $layoutFile =   THEME_PATH.$array['name'].$this->config['template_suffix'];\n                $replace    =   isset($array['replace'])?$array['replace']:$this->config['layout_item'];\n                // 替换布局的主体内容\n                $content    =   str_replace($replace,$content,file_get_contents($layoutFile));\n            }\n        }else{\n            $content = str_replace('{__NOLAYOUT__}','',$content);\n        }\n        return $content;\n    }\n\n    // 解析模板中的include标签\n    protected function parseInclude($content, $extend = true) {\n        // 解析继承\n        if($extend)\n            $content    =   $this->parseExtend($content);\n        // 解析布局\n        $content    =   $this->parseLayout($content);\n        // 读取模板中的include标签\n        $find       =   preg_match_all('/'.$this->config['taglib_begin'].'include\\s(.+?)\\s*?\\/'.$this->config['taglib_end'].'/is',$content,$matches);\n        if($find) {\n            for($i=0;$i<$find;$i++) {\n                $include    =   $matches[1][$i];\n                $array      =   $this->parseXmlAttrs($include);\n                $file       =   $array['file'];\n                unset($array['file']);\n                $content    =   str_replace($matches[0][$i],$this->parseIncludeItem($file,$array,$extend),$content);\n            }\n        }\n        return $content;\n    }\n\n    // 解析模板中的extend标签\n    protected function parseExtend($content) {\n        $begin      =   $this->config['taglib_begin'];\n        $end        =   $this->config['taglib_end'];        \n        // 读取模板中的继承标签\n        $find       =   preg_match('/'.$begin.'extend\\s(.+?)\\s*?\\/'.$end.'/is',$content,$matches);\n        if($find) {\n            //替换extend标签\n            $content    =   str_replace($matches[0],'',$content);\n            // 记录页面中的block标签\n            preg_replace_callback('/'.$begin.'block\\sname=[\\'\"](.+?)[\\'\"]\\s*?'.$end.'(.*?)'.$begin.'\\/block'.$end.'/is', array($this, 'parseBlock'),$content);\n            // 读取继承模板\n            $array      =   $this->parseXmlAttrs($matches[1]);\n            $content    =   $this->parseTemplateName($array['name']);\n            $content    =   $this->parseInclude($content, false); //对继承模板中的include进行分析\n            // 替换block标签\n            $content = $this->replaceBlock($content);\n        }else{\n            $content    =   preg_replace_callback('/'.$begin.'block\\sname=[\\'\"](.+?)[\\'\"]\\s*?'.$end.'(.*?)'.$begin.'\\/block'.$end.'/is', function($match){return stripslashes($match[2]);}, $content);\n        }\n        return $content;\n    }\n\n    /**\n     * 分析XML属性\n     * @access private\n     * @param string $attrs  XML属性字符串\n     * @return array\n     */\n    private function parseXmlAttrs($attrs) {\n        $xml        =   '<tpl><tag '.$attrs.' /></tpl>';\n        $xml        =   simplexml_load_string($xml);\n        if(!$xml)\n            E(L('_XML_TAG_ERROR_'));\n        $xml        =   (array)($xml->tag->attributes());\n        $array      =   array_change_key_case($xml['@attributes']);\n        return $array;\n    }\n\n    /**\n     * 替换页面中的literal标签\n     * @access private\n     * @param string $content  模板内容\n     * @return string|false\n     */\n    private function parseLiteral($content) {\n        if(is_array($content)) $content = $content[1];\n        if(trim($content)=='')  return '';\n        //$content            =   stripslashes($content);\n        $i                  =   count($this->literal);\n        $parseStr           =   \"<!--###literal{$i}###-->\";\n        $this->literal[$i]  =   $content;\n        return $parseStr;\n    }\n\n    /**\n     * 还原被替换的literal标签\n     * @access private\n     * @param string $tag  literal标签序号\n     * @return string|false\n     */\n    private function restoreLiteral($tag) {\n        if(is_array($tag)) $tag = $tag[1];\n        // 还原literal标签\n        $parseStr   =  $this->literal[$tag];\n        // 销毁literal记录\n        unset($this->literal[$tag]);\n        return $parseStr;\n    }\n\n    /**\n     * 记录当前页面中的block标签\n     * @access private\n     * @param string $name block名称\n     * @param string $content  模板内容\n     * @return string\n     */\n    private function parseBlock($name,$content = '') {\n        if(is_array($name)){\n            $content = $name[2];\n            $name    = $name[1];\n        }\n        $this->block[$name]  =   $content;\n        return '';\n    }\n\n    /**\n     * 替换继承模板中的block标签\n     * @access private\n     * @param string $content  模板内容\n     * @return string\n     */\n    private function replaceBlock($content){\n        static $parse = 0;\n        $begin = $this->config['taglib_begin'];\n        $end   = $this->config['taglib_end'];\n        $reg   = '/('.$begin.'block\\sname=[\\'\"](.+?)[\\'\"]\\s*?'.$end.')(.*?)'.$begin.'\\/block'.$end.'/is';\n        if(is_string($content)){\n            do{\n                $content = preg_replace_callback($reg, array($this, 'replaceBlock'), $content);\n            } while ($parse && $parse--);\n            return $content;\n        } elseif(is_array($content)){\n            if(preg_match('/'.$begin.'block\\sname=[\\'\"](.+?)[\\'\"]\\s*?'.$end.'/is', $content[3])){ //存在嵌套，进一步解析\n                $parse = 1;\n                $content[3] = preg_replace_callback($reg, array($this, 'replaceBlock'), \"{$content[3]}{$begin}/block{$end}\");\n                return $content[1] . $content[3];\n            } else {\n                $name    = $content[2];\n                $content = $content[3];\n                $content = isset($this->block[$name]) ? $this->block[$name] : $content;\n                return $content;\n            }\n        }\n    }\n\n    /**\n     * 搜索模板页面中包含的TagLib库\n     * 并返回列表\n     * @access public\n     * @param string $content  模板内容\n     * @return string|false\n     */\n    public function getIncludeTagLib(& $content) {\n        //搜索是否有TagLib标签\n        $find = preg_match('/'.$this->config['taglib_begin'].'taglib\\s(.+?)(\\s*?)\\/'.$this->config['taglib_end'].'\\W/is',$content,$matches);\n        if($find) {\n            //替换TagLib标签\n            $content        =   str_replace($matches[0],'',$content);\n            //解析TagLib标签\n            $array          =   $this->parseXmlAttrs($matches[1]);\n            $this->tagLib   =   explode(',',$array['name']);\n        }\n        return;\n    }\n\n    /**\n     * TagLib库解析\n     * @access public\n     * @param string $tagLib 要解析的标签库\n     * @param string $content 要解析的模板内容\n     * @param boolean $hide 是否隐藏标签库前缀\n     * @return string\n     */\n    public function parseTagLib($tagLib,&$content,$hide=false) {\n        $begin      =   $this->config['taglib_begin'];\n        $end        =   $this->config['taglib_end'];\n        if(strpos($tagLib,'\\\\')){\n            // 支持指定标签库的命名空间\n            $className  =   $tagLib;\n            $tagLib     =   substr($tagLib,strrpos($tagLib,'\\\\')+1);\n        }else{\n            $className  =   'Think\\\\Template\\TagLib\\\\'.ucwords($tagLib);            \n        }\n        $tLib       =   \\Think\\Think::instance($className);\n        $that       =   $this;\n        foreach ($tLib->getTags() as $name=>$val){\n            $tags = array($name);\n            if(isset($val['alias'])) {// 别名设置\n                $tags       = explode(',',$val['alias']);\n                $tags[]     =  $name;\n            }\n            $level      =   isset($val['level'])?$val['level']:1;\n            $closeTag   =   isset($val['close'])?$val['close']:true;\n            foreach ($tags as $tag){\n                $parseTag = !$hide? $tagLib.':'.$tag: $tag;// 实际要解析的标签名称\n                if(!method_exists($tLib,'_'.$tag)) {\n                    // 别名可以无需定义解析方法\n                    $tag  =  $name;\n                }\n                $n1 = empty($val['attr'])?'(\\s*?)':'\\s([^'.$end.']*)';\n                $this->tempVar = array($tagLib, $tag);\n\n                if (!$closeTag){\n                    $patterns       = '/'.$begin.$parseTag.$n1.'\\/(\\s*?)'.$end.'/is';\n                    $content        = preg_replace_callback($patterns, function($matches) use($tLib,$tag,$that){\n                        return $that->parseXmlTag($tLib,$tag,$matches[1],$matches[2]);\n                    },$content);\n                }else{\n                    $patterns       = '/'.$begin.$parseTag.$n1.$end.'(.*?)'.$begin.'\\/'.$parseTag.'(\\s*?)'.$end.'/is';\n                    for($i=0;$i<$level;$i++) {\n                        $content=preg_replace_callback($patterns,function($matches) use($tLib,$tag,$that){\n                            return $that->parseXmlTag($tLib,$tag,$matches[1],$matches[2]);\n                        },$content);\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * 解析标签库的标签\n     * 需要调用对应的标签库文件解析类\n     * @access public\n     * @param object $tagLib  标签库对象实例\n     * @param string $tag  标签名\n     * @param string $attr  标签属性\n     * @param string $content  标签内容\n     * @return string|false\n     */\n    public function parseXmlTag($tagLib,$tag,$attr,$content) {\n        if(ini_get('magic_quotes_sybase'))\n            $attr   =   str_replace('\\\"','\\'',$attr);\n        $parse      =   '_'.$tag;\n        $content    =   trim($content);\n        $tags       =   $tagLib->parseXmlAttr($attr,$tag);\n        return $tagLib->$parse($tags,$content);\n    }\n\n    /**\n     * 模板标签解析\n     * 格式： {TagName:args [|content] }\n     * @access public\n     * @param string $tagStr 标签内容\n     * @return string\n     */\n    public function parseTag($tagStr){\n        if(is_array($tagStr)) $tagStr = $tagStr[2];\n        //if (MAGIC_QUOTES_GPC) {\n            $tagStr = stripslashes($tagStr);\n        //}\n        $flag   =  substr($tagStr,0,1);\n        $flag2  =  substr($tagStr,1,1);\n        $name   = substr($tagStr,1);\n        if('$' == $flag && '.' != $flag2 && '(' != $flag2){ //解析模板变量 格式 {$varName}\n            return $this->parseVar($name);\n        }elseif('-' == $flag || '+'== $flag){ // 输出计算\n            return  '<?php echo '.$flag.$name.';?>';\n        }elseif(':' == $flag){ // 输出某个函数的结果\n            return  '<?php echo '.$name.';?>';\n        }elseif('~' == $flag){ // 执行某个函数\n            return  '<?php '.$name.';?>';\n        }elseif(substr($tagStr,0,2)=='//' || (substr($tagStr,0,2)=='/*' && substr(rtrim($tagStr),-2)=='*/')){\n            //注释标签\n            return '';\n        }\n        // 未识别的标签直接返回\n        return C('TMPL_L_DELIM') . $tagStr .C('TMPL_R_DELIM');\n    }\n\n    /**\n     * 模板变量解析,支持使用函数\n     * 格式： {$varname|function1|function2=arg1,arg2}\n     * @access public\n     * @param string $varStr 变量数据\n     * @return string\n     */\n    public function parseVar($varStr){\n        $varStr     =   trim($varStr);\n        static $_varParseList = array();\n        //如果已经解析过该变量字串，则直接返回变量值\n        if(isset($_varParseList[$varStr])) return $_varParseList[$varStr];\n        $parseStr   =   '';\n        $varExists  =   true;\n        if(!empty($varStr)){\n            $varArray = explode('|',$varStr);\n            //取得变量名称\n            $var = array_shift($varArray);\n            if('Think.' == substr($var,0,6)){\n                // 所有以Think.打头的以特殊变量对待 无需模板赋值就可以输出\n                $name = $this->parseThinkVar($var);\n            }elseif( false !== strpos($var,'.')) {\n                //支持 {$var.property}\n                $vars = explode('.',$var);\n                $var  =  array_shift($vars);\n                switch(strtolower(C('TMPL_VAR_IDENTIFY'))) {\n                    case 'array': // 识别为数组\n                        $name = '$'.$var;\n                        foreach ($vars as $key=>$val)\n                            $name .= '[\"'.$val.'\"]';\n                        break;\n                    case 'obj':  // 识别为对象\n                        $name = '$'.$var;\n                        foreach ($vars as $key=>$val)\n                            $name .= '->'.$val;\n                        break;\n                    default:  // 自动判断数组或对象 只支持二维\n                        $name = 'is_array($'.$var.')?$'.$var.'[\"'.$vars[0].'\"]:$'.$var.'->'.$vars[0];\n                }\n            }elseif(false !== strpos($var,'[')) {\n                //支持 {$var['key']} 方式输出数组\n                $name = \"$\".$var;\n                preg_match('/(.+?)\\[(.+?)\\]/is',$var,$match);\n                $var = $match[1];\n            }elseif(false !==strpos($var,':') && false ===strpos($var,'(') && false ===strpos($var,'::') && false ===strpos($var,'?')){\n                //支持 {$var:property} 方式输出对象的属性\n                $vars = explode(':',$var);\n                $var  =  str_replace(':','->',$var);\n                $name = \"$\".$var;\n                $var  = $vars[0];\n            }else {\n                $name = \"$$var\";\n            }\n            //对变量使用函数\n            if(count($varArray)>0)\n                $name = $this->parseVarFunction($name,$varArray);\n            $parseStr = '<?php echo ('.$name.'); ?>';\n        }\n        $_varParseList[$varStr] = $parseStr;\n        return $parseStr;\n    }\n\n    /**\n     * 对模板变量使用函数\n     * 格式 {$varname|function1|function2=arg1,arg2}\n     * @access public\n     * @param string $name 变量名\n     * @param array $varArray  函数列表\n     * @return string\n     */\n    public function parseVarFunction($name,$varArray){\n        //对变量使用函数\n        $length = count($varArray);\n        //取得模板禁止使用函数列表\n        $template_deny_funs = explode(',',C('TMPL_DENY_FUNC_LIST'));\n        for($i=0;$i<$length ;$i++ ){\n            $args = explode('=',$varArray[$i],2);\n            //模板函数过滤\n            $fun = trim($args[0]);\n            switch($fun) {\n            case 'default':  // 特殊模板函数\n                $name = '(isset('.$name.') && ('.$name.' !== \"\"))?('.$name.'):'.$args[1];\n                break;\n            default:  // 通用模板函数\n                if(!in_array($fun,$template_deny_funs)){\n                    if(isset($args[1])){\n                        if(strstr($args[1],'###')){\n                            $args[1] = str_replace('###',$name,$args[1]);\n                            $name = \"$fun($args[1])\";\n                        }else{\n                            $name = \"$fun($name,$args[1])\";\n                        }\n                    }else if(!empty($args[0])){\n                        $name = \"$fun($name)\";\n                    }\n                }\n            }\n        }\n        return $name;\n    }\n\n    /**\n     * 特殊模板变量解析\n     * 格式 以 $Think. 打头的变量属于特殊模板变量\n     * @access public\n     * @param string $varStr  变量字符串\n     * @return string\n     */\n    public function parseThinkVar($varStr){\n        $vars = explode('.',$varStr);\n        $vars[1] = strtoupper(trim($vars[1]));\n        $parseStr = '';\n        if(count($vars)>=3){\n            $vars[2] = trim($vars[2]);\n            switch($vars[1]){\n                case 'SERVER':\n                    $parseStr = '$_SERVER[\\''.strtoupper($vars[2]).'\\']';break;\n                case 'GET':\n                    $parseStr = '$_GET[\\''.$vars[2].'\\']';break;\n                case 'POST':\n                    $parseStr = '$_POST[\\''.$vars[2].'\\']';break;\n                case 'COOKIE':\n                    if(isset($vars[3])) {\n                        $parseStr = '$_COOKIE[\\''.$vars[2].'\\'][\\''.$vars[3].'\\']';\n                    }else{\n                        $parseStr = 'cookie(\\''.$vars[2].'\\')';\n                    }\n                    break;\n                case 'SESSION':\n                    if(isset($vars[3])) {\n                        $parseStr = '$_SESSION[\\''.$vars[2].'\\'][\\''.$vars[3].'\\']';\n                    }else{\n                        $parseStr = 'session(\\''.$vars[2].'\\')';\n                    }\n                    break;\n                case 'ENV':\n                    $parseStr = '$_ENV[\\''.strtoupper($vars[2]).'\\']';break;\n                case 'REQUEST':\n                    $parseStr = '$_REQUEST[\\''.$vars[2].'\\']';break;\n                case 'CONST':\n                    $parseStr = strtoupper($vars[2]);break;\n                case 'LANG':\n                    $parseStr = 'L(\"'.$vars[2].'\")';break;\n                case 'CONFIG':\n                    if(isset($vars[3])) {\n                        $vars[2] .= '.'.$vars[3];\n                    }\n                    $parseStr = 'C(\"'.$vars[2].'\")';break;\n                default:break;\n            }\n        }else if(count($vars)==2){\n            switch($vars[1]){\n                case 'NOW':\n                    $parseStr = \"date('Y-m-d g:i a',time())\";\n                    break;\n                case 'VERSION':\n                    $parseStr = 'THINK_VERSION';\n                    break;\n                case 'TEMPLATE':\n                    $parseStr = \"'\".$this->templateFile.\"'\";//'C(\"TEMPLATE_NAME\")';\n                    break;\n                case 'LDELIM':\n                    $parseStr = 'C(\"TMPL_L_DELIM\")';\n                    break;\n                case 'RDELIM':\n                    $parseStr = 'C(\"TMPL_R_DELIM\")';\n                    break;\n                default:\n                    if(defined($vars[1]))\n                        $parseStr = $vars[1];\n            }\n        }\n        return $parseStr;\n    }\n\n    /**\n     * 加载公共模板并缓存 和当前模板在同一路径，否则使用相对路径\n     * @access private\n     * @param string $tmplPublicName  公共模板文件名\n     * @param array $vars  要传递的变量列表\n     * @return string\n     */\n    private function parseIncludeItem($tmplPublicName,$vars=array(),$extend = true ){\n        // 分析模板文件名并读取内容\n        $parseStr = $this->parseTemplateName($tmplPublicName);\n        // 替换变量\n        foreach ($vars as $key=>$val) {\n            $parseStr = str_replace('['.$key.']',$val,$parseStr);\n        }\n        // 再次对包含文件进行模板分析\n        return $this->parseInclude($parseStr,$extend);\n    }\n\n    /**\n     * 分析加载的模板文件并读取内容 支持多个模板文件读取\n     * @access private\n     * @param string $tmplPublicName  模板文件名\n     * @return string\n     */    \n    private function parseTemplateName($templateName){\n        if(substr($templateName,0,1)=='$')\n            //支持加载变量文件名\n            $templateName = $this->get(substr($templateName,1));\n        $array  =   explode(',',$templateName);\n        $parseStr   =   ''; \n        foreach ($array as $templateName){\n            if(empty($templateName)) continue;\n            if(false === strpos($templateName,$this->config['template_suffix'])) {\n                // 解析规则为 模块@主题/控制器/操作\n                $templateName   =   T($templateName);\n            }\n            // 获取模板文件内容\n            $parseStr .= file_get_contents($templateName);\n        }\n        return $parseStr;\n    }    \n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Think.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\nnamespace Think;\n/**\n * ThinkPHP 引导类\n */\nclass Think {\n\n    // 类映射\n    private static $_map      = array();\n\n    // 实例化对象\n    private static $_instance = array();\n\n    /**\n     * 应用程序初始化\n     * @access public\n     * @return void\n     */\n    static public function start() {\n      // 注册AUTOLOAD方法\n      spl_autoload_register('Think\\Think::autoload');      \n      // 设定错误和异常处理\n      register_shutdown_function('Think\\Think::fatalError');\n      set_error_handler('Think\\Think::appError');\n      set_exception_handler('Think\\Think::appException');\n\n      // 初始化文件存储方式\n      Storage::connect(STORAGE_TYPE);\n\n      $runtimefile  = RUNTIME_PATH.APP_MODE.'~runtime.php';\n      if(!APP_DEBUG && Storage::has($runtimefile)){\n          Storage::load($runtimefile);\n      }else{\n          if(Storage::has($runtimefile))\n              Storage::unlink($runtimefile);\n          $content =  '';\n          // 读取应用模式\n          $mode   =   include is_file(CONF_PATH.'core.php')?CONF_PATH.'core.php':MODE_PATH.APP_MODE.'.php';\n          // 加载核心文件\n          foreach ($mode['core'] as $file){\n              if(is_file($file)) {\n                include $file;\n                if(!APP_DEBUG) $content   .= compile($file);\n              }\n          }\n\n          // 加载应用模式配置文件\n          foreach ($mode['config'] as $key=>$file){\n              is_numeric($key)?C(load_config($file)):C($key,load_config($file));\n          }\n\n          // 读取当前应用模式对应的配置文件\n          if('common' != APP_MODE && is_file(CONF_PATH.'config_'.APP_MODE.CONF_EXT))\n              C(load_config(CONF_PATH.'config_'.APP_MODE.CONF_EXT));  \n\n          // 加载模式别名定义\n          if(isset($mode['alias'])){\n              self::addMap(is_array($mode['alias'])?$mode['alias']:include $mode['alias']);\n          }\n\n          // 加载应用别名定义文件\n          if(is_file(CONF_PATH.'alias.php'))\n              self::addMap(include CONF_PATH.'alias.php');\n\n          // 加载模式行为定义\n          if(isset($mode['tags'])) {\n              Hook::import(is_array($mode['tags'])?$mode['tags']:include $mode['tags']);\n          }\n\n          // 加载应用行为定义\n          if(is_file(CONF_PATH.'tags.php'))\n              // 允许应用增加开发模式配置定义\n              Hook::import(include CONF_PATH.'tags.php');   \n\n          // 加载框架底层语言包\n          L(include THINK_PATH.'Lang/'.strtolower(C('DEFAULT_LANG')).'.php');\n\n          if(!APP_DEBUG){\n              $content  .=  \"\\nnamespace { Think\\\\Think::addMap(\".var_export(self::$_map,true).\");\";\n              $content  .=  \"\\nL(\".var_export(L(),true).\");\\nC(\".var_export(C(),true).');Think\\Hook::import('.var_export(Hook::get(),true).');}';\n              Storage::put($runtimefile,strip_whitespace('<?php '.$content));\n          }else{\n            // 调试模式加载系统默认的配置文件\n            C(include THINK_PATH.'Conf/debug.php');\n            // 读取应用调试配置文件\n            if(is_file(CONF_PATH.'debug'.CONF_EXT))\n                C(include CONF_PATH.'debug'.CONF_EXT);           \n          }\n      }\n\n      // 读取当前应用状态对应的配置文件\n      if(APP_STATUS && is_file(CONF_PATH.APP_STATUS.CONF_EXT))\n          C(include CONF_PATH.APP_STATUS.CONF_EXT);   \n\n      // 设置系统时区\n      date_default_timezone_set(C('DEFAULT_TIMEZONE'));\n\n      // 检查应用目录结构 如果不存在则自动创建\n      if(C('CHECK_APP_DIR')) {\n          $module     =   defined('BIND_MODULE') ? BIND_MODULE : C('DEFAULT_MODULE');\n          if(!is_dir(APP_PATH.$module) || !is_dir(LOG_PATH)){\n              // 检测应用目录结构\n              Build::checkDir($module);\n          }\n      }\n\n      // 记录加载文件时间\n      G('loadTime');\n      // 运行应用\n      App::run();\n    }\n\n    // 注册classmap\n    static public function addMap($class, $map=''){\n        if(is_array($class)){\n            self::$_map = array_merge(self::$_map, $class);\n        }else{\n            self::$_map[$class] = $map;\n        }        \n    }\n\n    // 获取classmap\n    static public function getMap($class=''){\n        if(''===$class){\n            return self::$_map;\n        }elseif(isset(self::$_map[$class])){\n            return self::$_map[$class];\n        }else{\n            return null;\n        }\n    }\n\n    /**\n     * 类库自动加载\n     * @param string $class 对象类名\n     * @return void\n     */\n    public static function autoload($class) {\n        // 检查是否存在映射\n        if(isset(self::$_map[$class])) {\n            include self::$_map[$class];\n        }elseif(false !== strpos($class,'\\\\')){\n          $name           =   strstr($class, '\\\\', true);\n          if(in_array($name,array('Think','Org','Behavior','Com','Vendor')) || is_dir(LIB_PATH.$name)){ \n              // Library目录下面的命名空间自动定位\n              $path       =   LIB_PATH;\n          }else{\n              // 检测自定义命名空间 否则就以模块为命名空间\n              $namespace  =   C('AUTOLOAD_NAMESPACE');\n              $path       =   isset($namespace[$name])? dirname($namespace[$name]).'/' : APP_PATH;\n          }\n          $filename       =   $path . str_replace('\\\\', '/', $class) . EXT;\n          if(is_file($filename)) {\n              // Win环境下面严格区分大小写\n              if (IS_WIN && false === strpos(str_replace('/', '\\\\', realpath($filename)), $class . EXT)){\n                  return ;\n              }\n              include $filename;\n          }\n        }elseif (!C('APP_USE_NAMESPACE')) {\n            // 自动加载的类库层\n            foreach(explode(',',C('APP_AUTOLOAD_LAYER')) as $layer){\n                if(substr($class,-strlen($layer))==$layer){\n                    if(require_cache(MODULE_PATH.$layer.'/'.$class.EXT)) {\n                        return ;\n                    }\n                }            \n            }\n            // 根据自动加载路径设置进行尝试搜索\n            foreach (explode(',',C('APP_AUTOLOAD_PATH')) as $path){\n                if(import($path.'.'.$class))\n                    // 如果加载类成功则返回\n                    return ;\n            }\n        }\n    }\n\n    /**\n     * 取得对象实例 支持调用类的静态方法\n     * @param string $class 对象类名\n     * @param string $method 类的静态方法名\n     * @return object\n     */\n    static public function instance($class,$method='') {\n        $identify   =   $class.$method;\n        if(!isset(self::$_instance[$identify])) {\n            if(class_exists($class)){\n                $o = new $class();\n                if(!empty($method) && method_exists($o,$method))\n                    self::$_instance[$identify] = call_user_func(array(&$o, $method));\n                else\n                    self::$_instance[$identify] = $o;\n            }\n            else\n                self::halt(L('_CLASS_NOT_EXIST_').':'.$class);\n        }\n        return self::$_instance[$identify];\n    }\n\n    /**\n     * 自定义异常处理\n     * @access public\n     * @param mixed $e 异常对象\n     */\n    static public function appException($e) {\n        $error = array();\n        $error['message']   =   $e->getMessage();\n        $trace              =   $e->getTrace();\n        if('E'==$trace[0]['function']) {\n            $error['file']  =   $trace[0]['file'];\n            $error['line']  =   $trace[0]['line'];\n        }else{\n            $error['file']  =   $e->getFile();\n            $error['line']  =   $e->getLine();\n        }\n        $error['trace']     =   $e->getTraceAsString();\n        Log::record($error['message'],Log::ERR);\n        // 发送404信息\n        //header('HTTP/1.1 404 Not Found');\n        //header('Status:404 Not Found');\n        self::halt($error);\n    }\n\n    /**\n     * 自定义错误处理\n     * @access public\n     * @param int $errno 错误类型\n     * @param string $errstr 错误信息\n     * @param string $errfile 错误文件\n     * @param int $errline 错误行数\n     * @return void\n     */\n    static public function appError($errno, $errstr, $errfile, $errline) {\n      switch ($errno) {\n          case E_ERROR:\n          case E_PARSE:\n          case E_CORE_ERROR:\n          case E_COMPILE_ERROR:\n          case E_USER_ERROR:\n            ob_end_clean();\n            $errorStr = \"$errstr \".$errfile.\" 第 $errline 行.\";\n            if(C('LOG_RECORD')) Log::write(\"[$errno] \".$errorStr,Log::ERR);\n            self::halt($errorStr);\n            break;\n          default:\n            $errorStr = \"[$errno] $errstr \".$errfile.\" 第 $errline 行.\";\n            self::trace($errorStr,'','NOTIC');\n            break;\n      }\n    }\n    \n    // 致命错误捕获\n    static public function fatalError() {\n        Log::save();\n        if ($e = error_get_last()) {\n            switch($e['type']){\n              case E_ERROR:\n              case E_PARSE:\n              case E_CORE_ERROR:\n              case E_COMPILE_ERROR:\n              case E_USER_ERROR:  \n                ob_end_clean();\n                self::halt($e);\n                break;\n            }\n        }\n    }\n\n    /**\n     * 错误输出\n     * @param mixed $error 错误\n     * @return void\n     */\n    static public function halt($error) {\n        $e = array();\n        if (APP_DEBUG || IS_CLI) {\n            //调试模式下输出错误信息\n            if (!is_array($error)) {\n                $trace          = debug_backtrace();\n                $e['message']   = $error;\n                $e['file']      = $trace[0]['file'];\n                $e['line']      = $trace[0]['line'];\n                ob_start();\n                debug_print_backtrace();\n                $e['trace']     = ob_get_clean();\n            } else {\n                $e              = $error;\n            }\n            if(IS_CLI){\n                exit(iconv('UTF-8','gbk',$e['message']).PHP_EOL.'FILE: '.$e['file'].'('.$e['line'].')'.PHP_EOL.$e['trace']);\n            }\n        } else {\n            //否则定向到错误页面\n            $error_page         = C('ERROR_PAGE');\n            if (!empty($error_page)) {\n                redirect($error_page);\n            } else {\n                $message        = is_array($error) ? $error['message'] : $error;\n                $e['message']   = C('SHOW_ERROR_MSG')? $message : C('ERROR_MESSAGE');\n            }\n        }\n        // 包含异常页面模板\n        $exceptionFile =  C('TMPL_EXCEPTION_FILE',null,THINK_PATH.'Tpl/think_exception.tpl');\n        include $exceptionFile;\n        exit;\n    }\n\n    /**\n     * 添加和获取页面Trace记录\n     * @param string $value 变量\n     * @param string $label 标签\n     * @param string $level 日志级别(或者页面Trace的选项卡)\n     * @param boolean $record 是否记录日志\n     * @return void|array\n     */\n    static public function trace($value='[think]',$label='',$level='DEBUG',$record=false) {\n        static $_trace =  array();\n        if('[think]' === $value){ // 获取trace信息\n            return $_trace;\n        }else{\n            $info   =   ($label?$label.':':'').print_r($value,true);\n            $level  =   strtoupper($level);\n            \n            if((defined('IS_AJAX') && IS_AJAX) || !C('SHOW_PAGE_TRACE')  || $record) {\n                Log::record($info,$level,$record);\n            }else{\n                if(!isset($_trace[$level]) || count($_trace[$level])>C('TRACE_MAX_RECORD')) {\n                    $_trace[$level] =   array();\n                }\n                $_trace[$level][]   =   $info;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Upload/Driver/Bcs/bcs.class.php",
    "content": "<?php\nnamespace Think\\Upload\\Driver\\Bcs;\nuse Think\\Upload\\Driver\\Bcs\\BCS_MimeTypes;\nuse Think\\Upload\\Driver\\Bcs\\BCS_RequestCore;\nuse Think\\Upload\\Driver\\Bcs\\BCS_ResponseCore;\n\nif (! defined ( 'BCS_API_PATH' )) {\n\tdefine ( 'BCS_API_PATH', dirname ( __FILE__ ) );\n}\n\n//AK 公钥\ndefine ( 'BCS_AK', '' );\n//SK 私钥\ndefine ( 'BCS_SK', '' );\n//superfile 每个object分片后缀\ndefine ( 'BCS_SUPERFILE_POSTFIX', '_bcs_superfile_' );\n//sdk superfile分片大小 ，单位 B（字节）\ndefine ( 'BCS_SUPERFILE_SLICE_SIZE', 1024 * 1024 );\n\nrequire_once (BCS_API_PATH . '/requestcore.class.php');\nrequire_once (BCS_API_PATH . '/mimetypes.class.php');\n/**\n * Default BCS Exception.\n */\nclass BCS_Exception extends \\Exception {\n}\n/**\n * BCS API\n */\nclass BaiduBCS {\n\t/*%******************************************************************************************%*/\n\t// CLASS CONSTANTS\n\t//百度云存储默认外网域名\n\tconst DEFAULT_URL = 'bcs.duapp.com';\n\t//SDK 版本\n\tconst API_VERSION = '2012-4-17-1.0.1.6';\n\tconst ACL = 'acl';\n\tconst BUCKET = 'bucket';\n\tconst OBJECT = 'object';\n\tconst HEADERS = 'headers';\n\tconst METHOD = 'method';\n\tconst AK = 'ak';\n\tconst SK = 'sk';\n\tconst QUERY_STRING = \"query_string\";\n\tconst IMPORT_BCS_LOG_METHOD = \"import_bs_log_method\";\n\tconst IMPORT_BCS_PRE_FILTER = \"import_bs_pre_filter\";\n\tconst IMPORT_BCS_POST_FILTER = \"import_bs_post_filter\";\n\t/**********************************************************\n\t ******************* Policy Constants**********************\n\t **********************************************************/\n\tconst STATEMETS = 'statements';\n\t//Action 用户动作\n\t//'*'代表所有action\n\tconst BCS_SDK_ACL_ACTION_ALL = '*';\n\t//与bucket相关的action\n\tconst BCS_SDK_ACL_ACTION_LIST_OBJECT = 'list_object';\n\tconst BCS_SDK_ACL_ACTION_PUT_BUCKET_POLICY = 'put_bucket_policy';\n\tconst BCS_SDK_ACL_ACTION_GET_BUCKET_POLICY = 'get_bucket_policy';\n\tconst BCS_SDK_ACL_ACTION_DELETE_BUCKET = 'delete_bucket';\n\t//与object相关的action\n\tconst BCS_SDK_ACL_ACTION_GET_OBJECT = 'get_object';\n\tconst BCS_SDK_ACL_ACTION_PUT_OBJECT = 'put_object';\n\tconst BCS_SDK_ACL_ACTION_DELETE_OBJECT = 'delete_object';\n\tconst BCS_SDK_ACL_ACTION_PUT_OBJECT_POLICY = 'put_object_policy';\n\tconst BCS_SDK_ACL_ACTION_GET_OBJECT_POLICY = 'get_object_policy';\n\tstatic $ACL_ACTIONS = array (\n\t\t\tself::BCS_SDK_ACL_ACTION_ALL,\n\t\t\tself::BCS_SDK_ACL_ACTION_LIST_OBJECT,\n\t\t\tself::BCS_SDK_ACL_ACTION_PUT_BUCKET_POLICY,\n\t\t\tself::BCS_SDK_ACL_ACTION_GET_BUCKET_POLICY,\n\t\t\tself::BCS_SDK_ACL_ACTION_DELETE_BUCKET,\n\t\t\tself::BCS_SDK_ACL_ACTION_GET_OBJECT,\n\t\t\tself::BCS_SDK_ACL_ACTION_PUT_OBJECT,\n\t\t\tself::BCS_SDK_ACL_ACTION_DELETE_OBJECT,\n\t\t\tself::BCS_SDK_ACL_ACTION_PUT_OBJECT_POLICY,\n\t\t\tself::BCS_SDK_ACL_ACTION_GET_OBJECT_POLICY );\n\t//EFFECT:\n\tconst BCS_SDK_ACL_EFFECT_ALLOW = \"allow\";\n\tconst BCS_SDK_ACL_EFFECT_DENY = \"deny\";\n\tstatic $ACL_EFFECTS = array (\n\t\t\tself::BCS_SDK_ACL_EFFECT_ALLOW,\n\t\t\tself::BCS_SDK_ACL_EFFECT_DENY );\n\t//ACL_TYPE:\n\t//公开读权限\n\tconst BCS_SDK_ACL_TYPE_PUBLIC_READ = \"public-read\";\n\t//公开写权限（不具备删除权限）\n\tconst BCS_SDK_ACL_TYPE_PUBLIC_WRITE = \"public-write\";\n\t//公开读写权限（不具备删除权限）\n\tconst BCS_SDK_ACL_TYPE_PUBLIC_READ_WRITE = \"public-read-write\";\n\t//公开所有权限\n\tconst BCS_SDK_ACL_TYPE_PUBLIC_CONTROL = \"public-control\";\n\t//私有权限，仅bucket所有者具有所有权限\n\tconst BCS_SDK_ACL_TYPE_PRIVATE = \"private\";\n\t//SDK中开放此上五种acl_tpe\n\tstatic $ACL_TYPES = array (\n\t\t\tself::BCS_SDK_ACL_TYPE_PUBLIC_READ,\n\t\t\tself::BCS_SDK_ACL_TYPE_PUBLIC_WRITE,\n\t\t\tself::BCS_SDK_ACL_TYPE_PUBLIC_READ_WRITE,\n\t\t\tself::BCS_SDK_ACL_TYPE_PUBLIC_CONTROL,\n\t\t\tself::BCS_SDK_ACL_TYPE_PRIVATE );\n\t/*%******************************************************************************************%*/\n\t// PROPERTIES\n\t//是否使用ssl\n\tprotected $use_ssl = false;\n\t//公钥 account key\n\tprivate $ak;\n\t//私钥 secret key\n\tprivate $sk;\n\t//云存储server地址\n\tprivate $hostname;\n\n\t/**\n\t * 构造函数\n\t * @param string $ak  云存储公钥\n\t * @param string $sk  云存储私钥\n\t * @param string $hostname 云存储Api访问地址\n\t * @throws BCS_Exception\n\t */\n\tpublic function __construct($ak = NULL, $sk = NULL, $hostname = NULL) {\n\t\t//valid ak & sk\n\t\tif (! $ak && ! defined ( 'BCS_AK' ) && false === getenv ( 'HTTP_BAE_ENV_AK' )) {\n\t\t\tthrow new BCS_Exception ( 'No account key was passed into the constructor.' );\n\t\t}\n\t\tif (! $sk && ! defined ( 'BCS_SK' ) && false === getenv ( 'HTTP_BAE_ENV_SK' )) {\n\t\t\tthrow new BCS_Exception ( 'No secret key was passed into the constructor.' );\n\t\t}\n\t\tif ($ak && $sk) {\n\t\t\t$this->ak = $ak;\n\t\t\t$this->sk = $sk;\n\t\t} elseif (defined ( 'BCS_AK' ) && defined ( 'BCS_SK' ) && strlen ( BCS_AK ) > 0 && strlen ( BCS_SK ) > 0) {\n\t\t\t$this->ak = BCS_AK;\n\t\t\t$this->sk = BCS_SK;\n\t\t} elseif (false !== getenv ( 'HTTP_BAE_ENV_AK' ) && false !== getenv ( 'HTTP_BAE_ENV_SK' )) {\n\t\t\t$this->ak = getenv ( 'HTTP_BAE_ENV_AK' );\n\t\t\t$this->sk = getenv ( 'HTTP_BAE_ENV_SK' );\n\t\t} else {\n\t\t\tthrow new BCS_Exception ( 'Construct can not get ak &sk pair, please check!' );\n\t\t}\n\t\t//valid $hostname\n\t\tif (NULL !== $hostname) {\n\t\t\t$this->hostname = $hostname;\n\t\t} elseif (false !== getenv ( 'HTTP_BAE_ENV_ADDR_BCS' )) {\n\t\t\t$this->hostname = getenv ( 'HTTP_BAE_ENV_ADDR_BCS' );\n\t\t} else {\n\t\t\t$this->hostname = self::DEFAULT_URL;\n\t\t}\n\t}\n\n\t/**\n\t * 将消息发往Baidu BCS.\n\t * @param array $opt\n\t * @return BCS_ResponseCore\n\t */\n\tprivate function authenticate($opt) {\n\t\t//set common param into opt\n\t\t$opt [self::AK] = $this->ak;\n\t\t$opt [self::SK] = $this->sk;\n\n\t\t// Validate the S3 bucket name, only list_bucket didnot need validate_bucket\n\t\tif (! ('/' == $opt [self::OBJECT] && '' == $opt [self::BUCKET] && 'GET' == $opt [self::METHOD] && ! isset ( $opt [self::QUERY_STRING] [self::ACL] )) && ! self::validate_bucket ( $opt [self::BUCKET] )) {\n\t\t\tthrow new BCS_Exception ( $opt [self::BUCKET] . 'is not valid, please check!' );\n\t\t}\n\t\t//Validate object\n\t\tif (isset ( $opt [self::OBJECT] ) && ! self::validate_object ( $opt [self::OBJECT] )) {\n\t\t\tthrow new BCS_Exception ( \"Invalid object param[\" . $opt [self::OBJECT] . \"], please check.\", - 1 );\n\t\t}\n\t\t//construct url\n\t\t$url = $this->format_url ( $opt );\n\t\tif ($url === false) {\n\t\t\tthrow new BCS_Exception ( 'Can not format url, please check your param!', - 1 );\n\t\t}\n\t\t$opt ['url'] = $url;\n\t\t$this->log ( \"[method:\" . $opt [self::METHOD] . \"][url:$url]\", $opt );\n\t\t//build request\n\t\t$request = new BCS_RequestCore ( $opt ['url'] );\n\t\t$headers = array (\n\t\t\t\t'Content-Type' => 'application/x-www-form-urlencoded' );\n\n\t\t$request->set_method ( $opt [self::METHOD] );\n\t\t//Write get_object content to fileWriteTo\n\t\tif (isset ( $opt ['fileWriteTo'] )) {\n\t\t\t$request->set_write_file ( $opt ['fileWriteTo'] );\n\t\t}\n\t\t// Merge the HTTP headers\n\t\tif (isset ( $opt [self::HEADERS] )) {\n\t\t\t$headers = array_merge ( $headers, $opt [self::HEADERS] );\n\t\t}\n\t\t// Set content to Http-Body\n\t\tif (isset ( $opt ['content'] )) {\n\t\t\t$request->set_body ( $opt ['content'] );\n\t\t}\n\t\t// Upload file\n\t\tif (isset ( $opt ['fileUpload'] )) {\n\t\t\tif (! file_exists ( $opt ['fileUpload'] )) {\n\t\t\t\tthrow new BCS_Exception ( 'File[' . $opt ['fileUpload'] . '] not found!', - 1 );\n\t\t\t}\n\t\t\t$request->set_read_file ( $opt ['fileUpload'] );\n\t\t\t// Determine the length to read from the file\n\t\t\t$length = $request->read_stream_size; // The file size by default\n\t\t\t$file_size = $length;\n\t\t\tif (isset ( $opt [\"length\"] )) {\n\t\t\t\tif ($opt [\"length\"] > $file_size) {\n\t\t\t\t\tthrow new BCS_Exception ( \"Input opt[length] invalid! It can not bigger than file-size\", - 1 );\n\t\t\t\t}\n\t\t\t\t$length = $opt ['length'];\n\t\t\t}\n\t\t\tif (isset ( $opt ['seekTo'] ) && ! isset ( $opt [\"length\"] )) {\n\t\t\t\t// Read from seekTo until EOF by default, when set seekTo but not set $opt[\"length\"]\n\t\t\t\t$length -= ( integer ) $opt ['seekTo'];\n\t\t\t}\n\t\t\t$request->set_read_stream_size ( $length );\n\t\t\t// Attempt to guess the correct mime-type\n\t\t\tif ($headers ['Content-Type'] === 'application/x-www-form-urlencoded') {\n\t\t\t\t$extension = explode ( '.', $opt ['fileUpload'] );\n\t\t\t\t$extension = array_pop ( $extension );\n\t\t\t\t$mime_type = BCS_MimeTypes::get_mimetype ( $extension );\n\t\t\t\t$headers ['Content-Type'] = $mime_type;\n\t\t\t}\n\t\t\t$headers ['Content-MD5'] = '';\n\t\t}\n\t\t// Handle streaming file offsets\n\t\tif (isset ( $opt ['seekTo'] )) {\n\t\t\t// Pass the seek position to BCS_RequestCore\n\t\t\t$request->set_seek_position ( ( integer ) $opt ['seekTo'] );\n\t\t}\n\t\t// Add headers to request and compute the string to sign\n\t\tforeach ( $headers as $header_key => $header_value ) {\n\t\t\t// Strip linebreaks from header values as they're illegal and can allow for security issues\n\t\t\t$header_value = str_replace ( array (\n\t\t\t\t\t\"\\r\",\n\t\t\t\t\t\"\\n\" ), '', $header_value );\n\t\t\t// Add the header if it has a value\n\t\t\tif ($header_value !== '') {\n\t\t\t\t$request->add_header ( $header_key, $header_value );\n\t\t\t}\n\t\t}\n\t\t// Set the curl options.\n\t\tif (isset ( $opt ['curlopts'] ) && count ( $opt ['curlopts'] )) {\n\t\t\t$request->set_curlopts ( $opt ['curlopts'] );\n\t\t}\n\t\t$request->send_request ();\n\t\trequire_once(dirname(__FILE__). \"/requestcore.class.php\");\n\t\treturn new BCS_ResponseCore ( $request->get_response_header (), $request->get_response_body (), $request->get_response_code () );\n\t}\n\n\t/**\n\t * 获取当前密钥对拥有者的bucket列表\n\t * @param array $opt (Optional)\n\t * BaiduBCS::IMPORT_BCS_LOG_METHOD - String - Optional: 支持用户传入日志处理函数，函数定义如 function f($log)\n\t * @throws BCS_Exception\n\t * @return BCS_ResponseCore\n\t */\n\tpublic function list_bucket($opt = array()) {\n\t\t$this->assertParameterArray ( $opt );\n\t\t$opt [self::BUCKET] = '';\n\t\t$opt [self::METHOD] = 'GET';\n\t\t$opt [self::OBJECT] = '/';\n\t\t$response = $this->authenticate ( $opt );\n\t\t$this->log ( $response->isOK () ? \"List bucket success!\" : \"List bucket failed! Response: [\" . $response->body . \"]\", $opt );\n\t\treturn $response;\n\t}\n\n\t/**\n\t * 创建 bucket\n\t * @param string $bucket (Required) bucket名称\n\t * @param string $acl (Optional)    bucket权限设置，若为null，使用server分配的默认权限\n\t * @param array $opt (Optional)\n\t * @throws BCS_Exception\n\t * @return BCS_ResponseCore\n\t */\n\tpublic function create_bucket($bucket, $acl = NULL, $opt = array()) {\n\t\t$this->assertParameterArray ( $opt );\n\t\t$opt [self::BUCKET] = $bucket;\n\t\t$opt [self::METHOD] = 'PUT';\n\t\t$opt [self::OBJECT] = '/';\n\t\tif (NULL !== $acl) {\n\t\t\tif (! in_array ( $acl, self::$ACL_TYPES )) {\n\t\t\t\tthrow new BCS_Exception ( \"Invalid acl_type[\" . $acl . \"], please check!\", - 1 );\n\t\t\t}\n\t\t\tself::set_header_into_opt ( \"x-bs-acl\", $acl, $opt );\n\t\t}\n\t\t$response = $this->authenticate ( $opt );\n\t\t$this->log ( $response->isOK () ? \"Create bucket success!\" : \"Create bucket failed! Response: [\" . $response->body . \"]\", $opt );\n\t\treturn $response;\n\t}\n\n\t/**\n\t * 删除bucket\n\t * @param string $bucket (Required)\n\t * @param array $opt (Optional)\n\t * @return boolean|BCS_ResponseCore\n\t */\n\tpublic function delete_bucket($bucket, $opt = array()) {\n\t\t$this->assertParameterArray ( $opt );\n\t\t$opt [self::BUCKET] = $bucket;\n\t\t$opt [self::METHOD] = 'DELETE';\n\t\t$opt [self::OBJECT] = '/';\n\t\t$response = $this->authenticate ( $opt );\n\t\t$this->log ( $response->isOK () ? \"Delete bucket success!\" : \"Delete bucket failed! Response: [\" . $response->body . \"]\", $opt );\n\t\treturn $response;\n\t}\n\n\t/**\n\t * 设置bucket的acl，有三种模式，\n\t * (1).设置详细json格式的acl；\n\t * a. $acl 为json的array\n\t * b. $acl 为json的string\n\t * (2).通过acl_type字段进行设置\n\t * a. $acl 为BaiduBCS::$ACL_TYPES中的字段\n\t * @param string $bucket (Required)\n\t * @param string $acl (Required)\n\t * @param array $opt (Optional)\n\t * @return boolean|BCS_ResponseCore\n\t */\n\tpublic function set_bucket_acl($bucket, $acl, $opt = array()) {\n\t\t$this->assertParameterArray ( $opt );\n\t\t$result = $this->analyze_user_acl ( $acl );\n\t\t$opt = array_merge ( $opt, $result );\n\t\t$opt [self::BUCKET] = $bucket;\n\t\t$opt [self::METHOD] = 'PUT';\n\t\t$opt [self::OBJECT] = '/';\n\t\t$opt [self::QUERY_STRING] = array (\n\t\t\t\tself::ACL => 1 );\n\t\t$response = $this->authenticate ( $opt );\n\t\t$this->log ( $response->isOK () ? \"Set bucket acl success!\" : \"Set bucket acl failed! Response: [\" . $response->body . \"]\", $opt );\n\t\treturn $response;\n\t}\n\n\t/**\n\t * 获取bucket的acl\n\t * @param string $bucket (Required)\n\t * @param array $opt (Optional)\n\t * @return BCS_ResponseCore\n\t */\n\tpublic function get_bucket_acl($bucket, $opt = array()) {\n\t\t$this->assertParameterArray ( $opt );\n\t\t$opt [self::BUCKET] = $bucket;\n\t\t$opt [self::METHOD] = 'GET';\n\t\t$opt [self::OBJECT] = '/';\n\t\t$opt [self::QUERY_STRING] = array (\n\t\t\t\tself::ACL => 1 );\n\t\t$response = $this->authenticate ( $opt );\n\t\t$this->log ( $response->isOK () ? \"Get bucket acl success!\" : \"Get bucket acl failed! Response: [\" . $response->body . \"]\", $opt );\n\t\treturn $response;\n\t}\n\n\t/**\n\t * 获取bucket中object列表\n\t * @param string $bucket (Required)\n\t * @param array $opt (Optional)\n\t * start : 主要用于翻页功能，用法同mysql中start的用法\n\t * limit : 主要用于翻页功能，用法同mysql中limit的用法\n\t * prefix: 只返回以prefix为前缀的object，此处prefix必须以'/'开头\n\t * @throws BCS_Exception\n\t * @return BCS_ResponseCore\n\t */\n\tpublic function list_object($bucket, $opt = array()) {\n\t\t$this->assertParameterArray ( $opt );\n\t\t$opt [self::BUCKET] = $bucket;\n\t\tif (empty ( $opt [self::BUCKET] )) {\n\t\t\tthrow new BCS_Exception ( \"Bucket should not be empty, please check\", - 1 );\n\t\t}\n\t\t$opt [self::METHOD] = 'GET';\n\t\t$opt [self::OBJECT] = '/';\n\t\t$opt [self::QUERY_STRING] = array ();\n\t\tif (isset ( $opt ['start'] ) && is_int ( $opt ['start'] )) {\n\t\t\t$opt [self::QUERY_STRING] ['start'] = $opt ['start'];\n\t\t}\n\t\tif (isset ( $opt ['limit'] ) && is_int ( $opt ['limit'] )) {\n\t\t\t$opt [self::QUERY_STRING] ['limit'] = $opt ['limit'];\n\t\t}\n\t\tif (isset ( $opt ['prefix'] )) {\n\t\t\t$opt [self::QUERY_STRING] ['prefix'] = rawurlencode ( $opt ['prefix'] );\n\t\t}\n\t\t$response = $this->authenticate ( $opt );\n\t\t$this->log ( $response->isOK () ? \"List object success!\" : \"Lit object failed! Response: [\" . $response->body . \"]\", $opt );\n\t\treturn $response;\n\t}\n\n\t/**\n\t * 以目录形式获取bucket中object列表\n\t * @param string $bucket (Required)\n\t * @param $dir (Required)\n\t * 目录名，格式为必须以'/'开头和结尾，默认为'/'\n\t * @param string $list_model (Required)\n\t * 目录展现形式，值可以为0,1,2，默认为2，以下对各个值的功能进行介绍：\n\t * 0->只返回object列表，不返回子目录列表\n\t * 1->只返回子目录列表，不返回object列表\n\t * 2->同时返回子目录列表和object列表\n\t * @param array $opt (Optional)\n\t * start : 主要用于翻页功能，用法同mysql中start的用法\n\t * limit : 主要用于翻页功能，用法同mysql中limit的用法\n\t * @throws BCS_Exception\n\t * @return BCS_ResponseCore\n\t */\n\tpublic function list_object_by_dir($bucket, $dir = '/', $list_model = 2, $opt = array()) {\n\t\t$this->assertParameterArray ( $opt );\n\t\t$opt [self::BUCKET] = $bucket;\n\t\tif (empty ( $opt [self::BUCKET] )) {\n\t\t\tthrow new BCS_Exception ( \"Bucket should not be empty, please check\", - 1 );\n\t\t}\n\t\t$opt [self::METHOD] = 'GET';\n\t\t$opt [self::OBJECT] = '/';\n\t\t$opt [self::QUERY_STRING] = array ();\n\t\tif (isset ( $opt ['start'] ) && is_int ( $opt ['start'] )) {\n\t\t\t$opt [self::QUERY_STRING] ['start'] = $opt ['start'];\n\t\t}\n\t\tif (isset ( $opt ['limit'] ) && is_int ( $opt ['limit'] )) {\n\t\t\t$opt [self::QUERY_STRING] ['limit'] = $opt ['limit'];\n\t\t}\n\n\t\t$opt [self::QUERY_STRING] ['prefix'] = rawurlencode ( $dir );\n\t\t$opt [self::QUERY_STRING] ['dir'] = $list_model;\n\n\t\t$response = $this->authenticate ( $opt );\n\t\t$this->log ( $response->isOK () ? \"List object success!\" : \"Lit object failed! Response: [\" . $response->body . \"]\", $opt );\n\t\treturn $response;\n\t}\n\n\t/**\n\t * 上传文件\n\t * @param string $bucket (Required)\n\t * @param string $object (Required)\n\t * @param string $file (Required); 需要上传的文件的文件路径\n\t * @param array $opt (Optional)\n\t * filename - Optional; 指定文件名\n\t * acl - Optional ; 上传文件的acl，只能使用acl_type\n\t * seekTo - Optional; 上传文件的偏移位置\n\t * length - Optional; 待上传长度\n\t * @return BCS_ResponseCore\n\t */\n\tpublic function create_object($bucket, $object, $file, $opt = array()) {\n\t\t$this->assertParameterArray ( $opt );\n\t\t$opt [self::BUCKET] = $bucket;\n\t\t$opt [self::OBJECT] = $object;\n\t\t$opt ['fileUpload'] = $file;\n\t\t$opt [self::METHOD] = 'PUT';\n\t\tif (isset ( $opt ['acl'] )) {\n\t\t\tif (in_array ( $opt ['acl'], self::$ACL_TYPES )) {\n\t\t\t\tself::set_header_into_opt ( \"x-bs-acl\", $opt ['acl'], $opt );\n\t\t\t} else {\n\t\t\t\tthrow new BCS_Exception ( \"Invalid acl string, it should be acl_type\", - 1 );\n\t\t\t}\n\t\t\tunset ( $opt ['acl'] );\n\t\t}\n\t\tif (isset ( $opt ['filename'] )) {\n\t\t\tself::set_header_into_opt ( \"Content-Disposition\", 'attachment; filename=' . $opt ['filename'], $opt );\n\t\t}\n\t\t$response = $this->authenticate ( $opt );\n\t\t$this->log ( $response->isOK () ? \"Create object[$object] file[$file] success!\" : \"Create object[$object] file[$file] failed! Response: [\" . $response->body . \"] Logid[\" . $response->header [\"x-bs-request-id\"] . \"]\", $opt );\n\t\treturn $response;\n\t}\n\n\t/**\n\t * 上传文件\n\t * @param string $bucket (Required)\n\t * @param string $object (Required)\n\t * @param string $file (Required); 需要上传的文件的文件路径\n\t * @param array $opt (Optional)\n\t * filename - Optional; 指定文件名\n\t * acl - Optional ; 上传文件的acl，只能使用acl_type\n\t * @return BCS_ResponseCore\n\t */\n\tpublic function create_object_by_content($bucket, $object, $content, $opt = array()) {\n\t\t$this->assertParameterArray ( $opt );\n\t\t$opt [self::BUCKET] = $bucket;\n\t\t$opt [self::OBJECT] = $object;\n\t\t$opt [self::METHOD] = 'PUT';\n\t\tif ($content !== NULL && is_string ( $content )) {\n\t\t\t$opt ['content'] = $content;\n\t\t} else {\n\t\t\tthrow new BCS_Exception ( \"Invalid object content, please check.\", - 1 );\n\t\t}\n\t\tif (isset ( $opt ['acl'] )) {\n\t\t\tif (in_array ( $opt ['acl'], self::$ACL_TYPES )) {\n\t\t\t\tself::set_header_into_opt ( \"x-bs-acl\", $opt ['acl'], $opt );\n\t\t\t} else {\n\t\t\t\tthrow new BCS_Exception ( \"Invalid acl string, it should be acl_type\", - 1 );\n\t\t\t}\n\t\t\tunset ( $opt ['acl'] );\n\t\t}\n\t\tif (isset ( $opt ['filename'] )) {\n\t\t\tself::set_header_into_opt ( \"Content-Disposition\", 'attachment; filename=' . $opt ['filename'], $opt );\n\t\t}\n\t\t$response = $this->authenticate ( $opt );\n\t\t$this->log ( $response->isOK () ? \"Create object[$object] success!\" : \"Create object[$object] failed! Response: [\" . $response->body . \"] Logid[\" . $response->header [\"x-bs-request-id\"] . \"]\", $opt );\n\t\treturn $response;\n\t}\n\n\t/**\n\t * 通过superfile的方式上传文件\n\t * @param string $bucket (Required)\n\t * @param string $object (Required)\n\t * @param string $file (Required); 需要上传的文件的文件路径\n\t * @param array $opt (Optional)\n\t * filename - Optional; 指定文件名\n\t * sub_object_size - Optional; 指定子文件的划分大小，单位B，建议以256KB为单位进行子object划分，默认为1MB进行划分\n\t * @return BCS_ResponseCore\n\t */\n\tpublic function create_object_superfile($bucket, $object, $file, $opt = array()) {\n\t\tif (isset ( $opt ['length'] ) || isset ( $opt ['seekTo'] )) {\n\t\t\tthrow new BCS_Exception ( \"Temporary unsupport opt of length and seekTo of superfile.\", - 1 );\n\t\t}\n\t\t//$opt array\n\t\t$this->assertParameterArray ( $opt );\n\t\t$opt [self::BUCKET] = $bucket;\n\t\t$opt ['fileUpload'] = $file;\n\t\t$opt [self::METHOD] = 'PUT';\n\t\tif (isset ( $opt ['acl'] )) {\n\t\t\tif (in_array ( $opt ['acl'], self::$ACL_TYPES )) {\n\t\t\t\tself::set_header_into_opt ( \"x-bs-acl\", $opt ['acl'], $opt );\n\t\t\t} else {\n\t\t\t\tthrow new BCS_Exception ( \"Invalid acl string, it should be acl_type\", - 1 );\n\t\t\t}\n\t\t\tunset ( $opt ['acl'] );\n\t\t}\n\t\t//切片上传\n\t\tif (! file_exists ( $opt ['fileUpload'] )) {\n\t\t\tthrow new BCS_Exception ( 'File not found!', - 1 );\n\t\t}\n\t\t$fileSize = filesize ( $opt ['fileUpload'] );\n\t\t$sub_object_size = 1024 * 1024; //default 1MB\n\t\tif (defined ( \"BCS_SUPERFILE_SLICE_SIZE\" )) {\n\t\t\t$sub_object_size = BCS_SUPERFILE_SLICE_SIZE;\n\t\t}\n\t\tif (isset ( $opt [\"sub_object_size\"] )) {\n\t\t\tif (is_int ( $opt [\"sub_object_size\"] ) && $opt [\"sub_object_size\"] > 0) {\n\t\t\t\t$sub_object_size = $opt [\"sub_object_size\"];\n\t\t\t} else {\n\t\t\t\tthrow new BCS_Exception ( \"Param [sub_object_size] invalid ,please check!\", - 1 );\n\t\t\t}\n\t\t}\n\t\t$sliceNum = intval ( ceil ( $fileSize / $sub_object_size ) );\n\t\t$this->log ( \"File[\" . $opt ['fileUpload'] . \"], size=[$fileSize], sub_object_size=[$sub_object_size], sub_object_num=[$sliceNum]\", $opt );\n\t\t$object_list = array (\n\t\t\t\t'object_list' => array () );\n\t\tfor($i = 0; $i < $sliceNum; $i ++) {\n\t\t\t//send slice\n\t\t\t$opt ['seekTo'] = $i * $sub_object_size;\n\n\t\t\tif (($i + 1) === $sliceNum) {\n\t\t\t\t//last sub object\n\t\t\t\t$opt ['length'] = (0 === $fileSize % $sub_object_size) ? $sub_object_size : $fileSize % $sub_object_size;\n\t\t\t} else {\n\t\t\t\t$opt ['length'] = $sub_object_size;\n\t\t\t}\n\t\t\t$opt [self::OBJECT] = $object . BCS_SUPERFILE_POSTFIX . $i;\n\t\t\t$object_list ['object_list'] ['part_' . $i] = array ();\n\t\t\t$object_list ['object_list'] ['part_' . $i] ['url'] = 'bs://' . $bucket . $opt [self::OBJECT];\n\t\t\t$this->log ( \"Begin to upload Sub-object[\" . $opt [self::OBJECT] . \"][$i/$sliceNum][seekto:\" . $opt ['seekTo'] . \"][Length:\" . $opt ['length'] . \"]\", $opt );\n\t\t\t$response = $this->create_object ( $bucket, $opt [self::OBJECT], $file, $opt );\n\t\t\tif ($response->isOK ()) {\n\t\t\t\t$this->log ( \"Sub-object upload[\" . $opt [self::OBJECT] . \"][$i/$sliceNum][seekto:\" . $opt ['seekTo'] . \"][Length:\" . $opt ['length'] . \"]success! \", $opt );\n\t\t\t\t$object_list ['object_list'] ['part_' . $i] ['etag'] = $response->header ['Content-MD5'];\n\t\t\t\tcontinue;\n\t\t\t} else {\n\t\t\t\t$this->log ( \"Sub-object upload[\" . $opt [self::OBJECT] . \"][$i/$sliceNum] failed! \", $opt );\n\t\t\t\treturn $response;\n\t\t\t}\n\t\t}\n\t\t//将子文件分片的列表构造成 superfile\n\t\tunset ( $opt ['fileUpload'] );\n\t\tunset ( $opt ['length'] );\n\t\tunset ( $opt ['seekTo'] );\n\t\t$opt ['content'] = self::array_to_json ( $object_list );\n\t\t$opt [self::QUERY_STRING] = array (\n\t\t\t\t\"superfile\" => 1 );\n\t\t$opt [self::OBJECT] = $object;\n\t\tif (isset ( $opt ['filename'] )) {\n\t\t\tself::set_header_into_opt ( \"Content-Disposition\", 'attachment; filename=' . $opt ['filename'], $opt );\n\t\t}\n\t\t$response = $this->authenticate ( $opt );\n\t\t$this->log ( $response->isOK () ? \"Create object-superfile success!\" : \"Create object-superfile failed! Response: [\" . $response->body . \"]\", $opt );\n\t\treturn $response;\n\t}\n\n\t/**\n\t * 将目录中的所有文件进行上传，每个文件为单独object，object命名方式下详：\n\t * 如有 /home/worker/a/b/c.txt  需上传目录为$dir=/home/worker/a\n\t * object命令方式为\n\t * 1. object默认命名方式为 “子目录名 +文件名”，如上述文件c.txt，默认为 '/b/c.txt'\n\t * 2. 增强命名模式，在$opt中有可选参数进行配置\n\t * 举例说明 ：prefix . has_sub_directory?\"/b\":\"\" . '/c.txt'\n\t * @param string $bucket (Required)\n\t * @param string $dir (Required)\n\t * @param array $opt(Optional)\n\t * string prefix 文件object前缀\n\t * boolean has_sub_directory(default=true)   object命名中是否携带文件的子目录结构，若置为false，请确认待上传的目录和所有子目录中没有重名文件，否则会产生object覆盖问题\n\t * BaiduBCS::IMPORT_BCS_PRE_FILTER   用户可自定义上传文件前的操作函数\n\t * 1. 函数参数列表顺序需为 ($bucket,$object,$file,&$opt)，注意$opt为upload_directory函数传入的$opt的拷贝，只对当前object生效\n\t * 2. 函数返回值必须为boolean，当true该文件进行上传，若false跳过上传\n\t * 3. 如果函数返回false，将不会进行post_filter的调用\n\t * BaiduBCS::IMPORT_BCS_POST_FILTER  用户可自定义上传文件后的操作函数\n\t * 1. 函数参数列表顺序需为 ($bucket,$object,$file,&$opt,$response)，注意$opt为upload_directory函数传入的$opt的拷贝，只对当前object生效\n\t * 2. 函数返回值无要求\n\t * string seek_object 用户断点续传，需要为object名称，如果该object在目录中不存在，抛出异常，若存在则将该object和此后的object进行上传\n\t * string seek_object_id 作用同seek_object，只需要传入上传过程中日志中展示的[a/b]中object序号即可，注意object序号是以1开始计算的\n\t * @return array  数组形式的上传结果\n\t * 'success' => int  上传成功的文件数目\n\t * 'skipped' => int  被跳过的文件\n\t * 'failed' => array()   上传失败的文件\n\t *\n\t */\n\tpublic function upload_directory($bucket, $dir, $opt = array()) {\n\t\t$this->assertParameterArray ( $opt );\n\t\tif (! is_dir ( $dir )) {\n\t\t\tthrow new BCS_Exception ( \"$dir is not a dir!\", - 1 );\n\t\t}\n\t\t$result = array (\n\t\t\t\t\"success\" => 0,\n\t\t\t\t\"failed\" => array (),\n\t\t\t\t\"skipped\" => 0 );\n\t\t$prefix = \"\";\n\t\tif (isset ( $opt ['prefix'] )) {\n\t\t\t$prefix = $opt ['prefix'];\n\t\t}\n\t\t$has_sub_directory = true;\n\t\tif (isset ( $opt ['has_sub_directory'] ) && is_bool ( $opt ['has_sub_directory'] )) {\n\t\t\t$has_sub_directory = $opt ['has_sub_directory'];\n\t\t}\n\t\t//获取文件树和构造object名\n\t\t$file_tree = self::get_filetree ( $dir );\n\t\t$objects = array ();\n\t\tforeach ( $file_tree as $file ) {\n\t\t\t$object = $has_sub_directory == true ? substr ( $file, strlen ( $dir ) ) : \"/\" . basename ( $file );\n\t\t\t$objects [$prefix . $object] = $file;\n\t\t}\n\t\t$objectCount = count ( $objects );\n\t\t$before_upload_log = \"Upload directory: bucket[$bucket] upload_dir[$dir] file_sum[$objectCount]\";\n\t\tif (isset ( $opt [\"seek_object_id\"] )) {\n\t\t\t$before_upload_log .= \" seek_object_id[\" . $opt [\"seek_object_id\"] . \"/$objectCount]\";\n\t\t}\n\t\tif (isset ( $opt [\"seek_object\"] )) {\n\t\t\t$before_upload_log .= \" seek_object[\" . $opt [\"seek_object\"] . \"]\";\n\t\t}\n\t\t$this->log ( $before_upload_log, $opt );\n\t\t//查看是否需要查询断点，进行断点续传\n\t\tif (isset ( $opt [\"seek_object_id\"] ) && isset ( $opt [\"seek_object\"] )) {\n\t\t\tthrow new BCS_Exception ( \"Can not set see_object_id and seek_object at the same time!\", - 1 );\n\t\t}\n\n\t\t$num = 1;\n\t\tif (isset ( $opt [\"seek_object\"] )) {\n\t\t\tif (isset ( $objects [$opt [\"seek_object\"]] )) {\n\t\t\t\tforeach ( $objects as $object => $file ) {\n\t\t\t\t\tif ($object != $opt [\"seek_object\"]) {\n\t\t\t\t\t\t//当非断点文件，该object已完成上传\n\t\t\t\t\t\t$this->log ( \"Seeking[\" . $opt [\"seek_object\"] . \"]. Skip id[$num/$objectCount]object[$object]file[$file].\", $opt );\n\t\t\t\t\t\t//$result ['skipped'] [] = \"[$num/$objectCount]  \" . $file;\n\t\t\t\t\t\t$result ['skipped'] ++;\n\t\t\t\t\t\tunset ( $objects [$object] );\n\t\t\t\t\t} else {\n\t\t\t\t\t\t//当找到断点文件，停止循环，从断点文件重新上传\n\t\t\t\t\t\t//当非断点文件，该object已完成上传\n\t\t\t\t\t\t$this->log ( \"Found seek id[$num/$objectCount]object[$object]file[$file], begin from here.\", $opt );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t$num ++;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthrow new BCS_Exception ( \"Can not find you seek object, please check!\", - 1 );\n\t\t\t}\n\t\t}\n\t\tif (isset ( $opt [\"seek_object_id\"] )) {\n\t\t\tif (is_int ( $opt [\"seek_object_id\"] ) && $opt [\"seek_object_id\"] <= $objectCount) {\n\t\t\t\tforeach ( $objects as $object => $file ) {\n\t\t\t\t\tif ($num < $opt [\"seek_object_id\"]) {\n\t\t\t\t\t\t$this->log ( \"Seeking object of [\" . $opt [\"seek_object_id\"] . \"/$objectCount]. Skip  id[$num/$objectCount]object[$object]file[$file].\", $opt );\n\t\t\t\t\t\t//$result ['skipped'] [] = \"[$num/$objectCount]  \" . $file;\n\t\t\t\t\t\t$result ['skipped'] ++;\n\t\t\t\t\t\tunset ( $objects [$object] );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t$num ++;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthrow new BCS_Exception ( \"Param seek_object_id not valid, please check!\", - 1 );\n\t\t\t}\n\t\t}\n\t\t//上传objects\n\t\t$objectCount = count ( $objects );\n\t\tforeach ( $objects as $object => $file ) {\n\t\t\t$tmp_opt = array_merge ( $opt );\n\t\t\tif (isset ( $opt [self::IMPORT_BCS_PRE_FILTER] ) && function_exists ( $opt [self::IMPORT_BCS_PRE_FILTER] )) {\n\t\t\t\t$bolRes = $opt [self::IMPORT_BCS_PRE_FILTER] ( $bucket, $object, $file, $tmp_opt );\n\t\t\t\tif ($bolRes !== true) {\n\t\t\t\t\t$this->log ( \"User pre_filter_function return un-true. Skip id[$num/$objectCount]object[$object]file[$file].\", $opt );\n\t\t\t\t\t//$result ['skipped'] [] = \"id[$num/$objectCount]object[$object]file[$file]\";\n\t\t\t\t\t$result ['skipped'] ++;\n\t\t\t\t\t$num ++;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\ttry {\n\t\t\t\t$response = $this->create_object ( $bucket, $object, $file, $tmp_opt );\n\t\t\t} catch ( Exception $e ) {\n\t\t\t\t$this->log ( $e->getMessage (), $opt );\n\t\t\t\t$this->log ( \"Upload Failed id[$num/$objectCount]object[$object]file[$file].\", $opt );\n\t\t\t\t$num ++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif ($response->isOK ()) {\n\t\t\t\t$result [\"success\"] ++;\n\t\t\t\t$this->log ( \"Upload Success id[$num/$objectCount]object[$object]file[$file].\", $opt );\n\t\t\t} else {\n\t\t\t\t$result [\"failed\"] [] = \"id[$num/$objectCount]object[$object]file[$file]\";\n\t\t\t\t$this->log ( \"Upload Failed id[$num/$objectCount]object[$object]file[$file].\", $opt );\n\t\t\t}\n\t\t\tif (isset ( $opt [self::IMPORT_BCS_POST_FILTER] ) && function_exists ( $opt [self::IMPORT_BCS_POST_FILTER] )) {\n\t\t\t\t$opt [self::IMPORT_BCS_POST_FILTER] ( $bucket, $object, $file, $tmp_opt, $response );\n\t\t\t}\n\t\t\t$num ++;\n\t\t}\n\t\t//打印日志并返回结果数组\n\t\t$result_str = \"\\r\\n\\r\\nUpload $dir to $bucket finished!\\r\\n\";\n\t\t$result_str .= \"**********************************************************\\r\\n\";\n\t\t$result_str .= \"**********************Result Summary**********************\\r\\n\";\n\t\t$result_str .= \"**********************************************************\\r\\n\";\n\t\t$result_str .= \"Upload directory :  [$dir]\\r\\n\";\n\t\t$result_str .= \"File num :  [$objectCount]\\r\\n\";\n\t\t$result_str .= \"Success: \\r\\n\\tNum: \" . $result [\"success\"] . \"\\r\\n\";\n\t\t$result_str .= \"Skipped:\\r\\n\\tNum:\" . $result [\"skipped\"] . \"\\r\\n\";\n\t\t//\t\tforeach ( $result [\"skipped\"] as $skip ) {\n\t\t//\t\t\t$result_str .= \"\\t$skip\\r\\n\";\n\t\t//\t\t}\n\t\t$result_str .= \"Failed:\\r\\n\\tNum:\" . count ( $result [\"failed\"] ) . \"\\r\\n\";\n\t\tforeach ( $result [\"failed\"] as $fail ) {\n\t\t\t$result_str .= \"\\t$fail\\r\\n\";\n\t\t}\n\t\tif (isset ( $opt [self::IMPORT_BCS_LOG_METHOD] )) {\n\t\t\t$this->log ( $result_str, $opt );\n\t\t} else {\n\t\t\techo $result_str;\n\t\t}\n\t\treturn $result;\n\t}\n\n\t/**\n\t * 通过此方法以拷贝的方式创建object，object来源为$source\n\t * @param array $source (Required)  object 来源\n\t * bucket(Required)\n\t * object(Required)\n\t * @param array $dest (Required)    待拷贝的目标object\n\t * bucket(Required)\n\t * object(Required)\n\t * @param array $opt (Optional)\n\t * source_tag 指定拷贝对象的版本号\n\t * @throws BCS_Exception\n\t * @return BCS_ResponseCore\n\t */\n\tpublic function copy_object($source, $dest, $opt = array()) {\n\t\t$this->assertParameterArray ( $opt );\n\t\t//valid source and dest\n\t\tif (empty ( $source ) || ! is_array ( $source ) || ! isset ( $source [self::BUCKET] ) || ! isset ( $source [self::OBJECT] )) {\n\t\t\tthrow new BCS_Exception ( '$source invalid, please check!', - 1 );\n\t\t}\n\t\tif (empty ( $dest ) || ! is_array ( $dest ) || ! isset ( $dest [self::BUCKET] ) || ! isset ( $dest [self::OBJECT] ) || ! self::validate_bucket ( $dest [self::BUCKET] ) || ! self::validate_object ( $dest [self::OBJECT] )) {\n\t\t\tthrow new BCS_Exception ( '$dest invalid, please check!', - 1 );\n\t\t}\n\t\t$opt [self::BUCKET] = $dest [self::BUCKET];\n\t\t$opt [self::OBJECT] = $dest [self::OBJECT];\n\t\t$opt [self::METHOD] = 'PUT';\n\t\tself::set_header_into_opt ( 'x-bs-copy-source', 'bs://' . $source [self::BUCKET] . $source [self::OBJECT], $opt );\n\t\tif (isset ( $opt ['source_tag'] )) {\n\t\t\tself::set_header_into_opt ( 'x-bs-copy-source-tag', $opt ['source_tag'], $opt );\n\t\t}\n\t\t$response = $this->authenticate ( $opt );\n\t\t$this->log ( $response->isOK () ? \"Copy object success!\" : \"Copy object failed! Response: [\" . $response->body . \"]\", $opt );\n\t\treturn $response;\n\t}\n\n\t/**\n\t * 设置object的meta信息\n\t * @param string $bucket (Required)\n\t * @param string $object (Required)\n\t * @param array $opt (Optional)\n\t * 目前支持的meta信息如下：\n\t * Content-Type\n\t * Cache-Control\n\t * Content-Disposition\n\t * Content-Encoding\n\t * Content-MD5\n\t * Expires\n\t * @return BCS_ResponseCore\n\t */\n\tpublic function set_object_meta($bucket, $object, $meta, $opt = array()) {\n\t\t$this->assertParameterArray ( $opt );\n\t\t$this->assertParameterArray ( $meta );\n\t\t$opt [self::BUCKET] = $bucket;\n\t\t$opt [self::OBJECT] = $object;\n\t\t$opt [self::METHOD] = 'PUT';\n\t\t//利用copy_object接口来设置meta信息\n\t\t$source = \"bs://$bucket$object\";\n\t\tif (empty ( $meta )) {\n\t\t\tthrow new BCS_Exception ( '$meta can not be empty! And $meta must be array.', - 1 );\n\t\t}\n\t\tforeach ( $meta as $header => $value ) {\n\t\t\tself::set_header_into_opt ( $header, $value, $opt );\n\t\t}\n\t\t$source = array (\n\t\t\t\tself::BUCKET => $bucket,\n\t\t\t\tself::OBJECT => $object );\n\t\t$response = $this->copy_object ( $source, $source, $opt );\n\t\t$this->log ( $response->isOK () ? \"Set object meta success!\" : \"Set object meta failed! Response: [\" . $response->body . \"]\", $opt );\n\t\treturn $response;\n\t}\n\n\t/**\n\t * 获取object的acl\n\t * @param string $bucket (Required)\n\t * @param string $object (Required)\n\t * @param array $opt (Optional)\n\t * @throws BCS_Exception\n\t * @return BCS_ResponseCore\n\t */\n\tpublic function get_object_acl($bucket, $object, $opt = array()) {\n\t\t$this->assertParameterArray ( $opt );\n\t\t$opt [self::BUCKET] = $bucket;\n\t\t$opt [self::METHOD] = 'GET';\n\t\t$opt [self::OBJECT] = $object;\n\t\t$opt [self::QUERY_STRING] = array (\n\t\t\t\tself::ACL => 1 );\n\t\t$response = $this->authenticate ( $opt );\n\t\t$this->log ( $response->isOK () ? \"Get object acl success!\" : \"Get object acl failed! Response: [\" . $response->body . \"]\", $opt );\n\t\treturn $response;\n\t}\n\n\t/**\n\t * 设置object的acl，有三种模式，\n\t * (1).设置详细json格式的acl；\n\t * a. $acl 为json的array\n\t * b. $acl 为json的string\n\t * (2).通过acl_type字段进行设置\n\t * a. $acl 为BaiduBCS::$ACL_ACTIONS中的字段\n\t * @param string $bucket (Required)\n\t * @param string $object (Required)\n\t * @param string|array $acl (Required)\n\t * @param array $opt (Optional)\n\t * @return BCS_ResponseCore\n\t */\n\tpublic function set_object_acl($bucket, $object, $acl, $opt = array()) {\n\t\t$this->assertParameterArray ( $opt );\n\t\t//analyze acl\n\t\t$result = $this->analyze_user_acl ( $acl );\n\t\t$opt = array_merge ( $opt, $result );\n\t\t$opt [self::BUCKET] = $bucket;\n\t\t$opt [self::METHOD] = 'PUT';\n\t\t$opt [self::OBJECT] = $object;\n\t\t$opt [self::QUERY_STRING] = array (\n\t\t\t\tself::ACL => 1 );\n\t\t$response = $this->authenticate ( $opt );\n\t\t$this->log ( $response->isOK () ? \"Set object acl success!\" : \"Set object acl failed! Response: [\" . $response->body . \"]\", $opt );\n\t\treturn $response;\n\t}\n\n\t/**\n\t * 删除object\n\t * @param string $bucket (Required)\n\t * @param string $object (Required)\n\t * @param array $opt (Optional)\n\t * @throws BCS_Exception\n\t * @return BCS_ResponseCore\n\t */\n\tpublic function delete_object($bucket, $object, $opt = array()) {\n\t\t$this->assertParameterArray ( $opt );\n\t\t$opt [self::BUCKET] = $bucket;\n\t\t$opt [self::METHOD] = 'DELETE';\n\t\t$opt [self::OBJECT] = $object;\n\t\t$response = $this->authenticate ( $opt );\n\t\t$this->log ( $response->isOK () ? \"Delete object success!\" : \"Delete object failed! Response: [\" . $response->body . \"]\", $opt );\n\t\treturn $response;\n\t}\n\n\t/**\n\t * 判断object是否存在\n\t * @param string $bucket (Required)\n\t * @param string $object (Required)\n\t * @param array $opt (Optional)\n\t * @throws BCS_Exception\n\t * @return boolean true|boolean false|BCS_ResponseCore\n\t * true：object存在\n\t * false：不存在\n\t * BCS_ResponseCore其他错误\n\t */\n\tpublic function is_object_exist($bucket, $object, $opt = array()) {\n\t\t$this->assertParameterArray ( $opt );\n\t\t$opt [self::BUCKET] = $bucket;\n\t\t$opt [self::METHOD] = 'HEAD';\n\t\t$opt [self::OBJECT] = $object;\n\t\t$response = $this->get_object_info ( $bucket, $object, $opt );\n\t\tif ($response->isOK ()) {\n\t\t\treturn true;\n\t\t} elseif ($response->status === 404) {\n\t\t\treturn false;\n\t\t}\n\t\treturn $response;\n\t}\n\n\t/**\n\t * 获取文件信息，发送的为HTTP HEAD请求，文件信息都在http response的header中，不会提取文件的内容\n\t * @param string $bucket (Required)\n\t * @param string $object (Required)\n\t * @param array $opt (Optional)\n\t * @throws BCS_Exception\n\t * @return array BCS_ResponseCore\n\t */\n\tpublic function get_object_info($bucket, $object, $opt = array()) {\n\t\t$this->assertParameterArray ( $opt );\n\t\t$opt [self::BUCKET] = $bucket;\n\t\t$opt [self::METHOD] = 'HEAD';\n\t\t$opt [self::OBJECT] = $object;\n\t\t$response = $this->authenticate ( $opt );\n\t\t$this->log ( $response->isOK () ? \"Get object info success!\" : \"Get object info failed! Response: [\" . $response->body . \"]\", $opt );\n\t\treturn $response;\n\t}\n\n\t/**\n\t * 下载object\n\t * @param string $bucket (Required)\n\t * @param string $object (Required)\n\t * @param array $opt (Optional)\n\t * fileWriteTo   (Optional)直接将请求结果写入该文件，如果fileWriteTo文件存在，sdk进行重命名再存储\n\t * @throws BCS_Exception\n\t * @return BCS_ResponseCore\n\t */\n\tpublic function get_object($bucket, $object, $opt = array()) {\n\t\t$this->assertParameterArray ( $opt );\n\t\t//若fileWriteTo待写入的文件已经存在，需要进行重命名\n\t\tif (isset ( $opt [\"fileWriteTo\"] ) && file_exists ( $opt [\"fileWriteTo\"] )) {\n\t\t\t$original_file_write_to = $opt [\"fileWriteTo\"];\n\t\t\t$arr = explode ( DIRECTORY_SEPARATOR, $opt [\"fileWriteTo\"] );\n\t\t\t$file_name = $arr [count ( $arr ) - 1];\n\t\t\t$num = 1;\n\t\t\twhile ( file_exists ( $opt [\"fileWriteTo\"] ) ) {\n\t\t\t\t$new_name_arr = explode ( \".\", $file_name );\n\t\t\t\tif (count ( $new_name_arr ) > 1) {\n\t\t\t\t\t$new_name_arr [count ( $new_name_arr ) - 2] .= \" ($num)\";\n\t\t\t\t} else {\n\t\t\t\t\t$new_name_arr [0] .= \" ($num)\";\n\t\t\t\t}\n\t\t\t\t$arr [count ( $arr ) - 1] = implode ( \".\", $new_name_arr );\n\t\t\t\t$opt [\"fileWriteTo\"] = implode ( DIRECTORY_SEPARATOR, $arr );\n\t\t\t\t$num ++;\n\t\t\t}\n\t\t\t$this->log ( \"[$original_file_write_to] already exist, rename it to [\" . $opt [\"fileWriteTo\"] . \"]\", $opt );\n\t\t}\n\t\t$opt [self::BUCKET] = $bucket;\n\t\t$opt [self::METHOD] = 'GET';\n\t\t$opt [self::OBJECT] = $object;\n\t\t$response = $this->authenticate ( $opt );\n\t\t$this->log ( $response->isOK () ? \"Get object success!\" : \"Get object failed! Response: [\" . $response->body . \"]\", $opt );\n\t\tif (! $response->isOK () && isset ( $opt [\"fileWriteTo\"] )) {\n\t\t\tunlink ( $opt [\"fileWriteTo\"] );\n\t\t}\n\t\treturn $response;\n\t}\n\n\t/**\n\t * 生成签名链接\n\t */\n\tprivate function generate_user_url($method, $bucket, $object, $opt = array()) {\n\t\t$opt [self::AK] = $this->ak;\n\t\t$opt [self::SK] = $this->sk;\n\t\t$opt [self::BUCKET] = $bucket;\n\t\t$opt [self::METHOD] = $method;\n\t\t$opt [self::OBJECT] = $object;\n\t\t$opt [self::QUERY_STRING] = array ();\n\t\tif (isset ( $opt [\"time\"] )) {\n\t\t\t$opt [self::QUERY_STRING] [\"time\"] = $opt [\"time\"];\n\t\t}\n\t\tif (isset ( $opt [\"size\"] )) {\n\t\t\t$opt [self::QUERY_STRING] [\"size\"] = $opt [\"size\"];\n\t\t}\n\t\treturn $this->format_url ( $opt );\n\t}\n\n\t/**\n\t * 生成get_object的url\n\t * @param string $bucket (Required)\n\t * @param string $object (Required)\n\t * return false| string url\n\t */\n\tpublic function generate_get_object_url($bucket, $object, $opt = array()) {\n\t\t$this->assertParameterArray ( $opt );\n\t\treturn $this->generate_user_url ( \"GET\", $bucket, $object, $opt );\n\t}\n\n\t/**\n\t * 生成put_object的url\n\t * @param string $bucket (Required)\n\t * @param string $object (Required)\n\t * return false| string url\n\t */\n\tpublic function generate_put_object_url($bucket, $object, $opt = array()) {\n\t\t$this->assertParameterArray ( $opt );\n\t\treturn $this->generate_user_url ( \"PUT\", $bucket, $object, $opt );\n\t}\n\n\t/**\n\t * 生成post_object的url\n\t * @param string $bucket (Required)\n\t * @param string $object (Required)\n\t * return false| string url\n\t */\n\tpublic function generate_post_object_url($bucket, $object, $opt = array()) {\n\t\t$this->assertParameterArray ( $opt );\n\t\treturn $this->generate_user_url ( \"POST\", $bucket, $object, $opt );\n\t}\n\n\t/**\n\t * 生成delete_object的url\n\t * @param string $bucket (Required)\n\t * @param string $object (Required)\n\t * return false| string url\n\t */\n\tpublic function generate_delete_object_url($bucket, $object, $opt = array()) {\n\t\t$this->assertParameterArray ( $opt );\n\t\treturn $this->generate_user_url ( \"DELETE\", $bucket, $object, $opt );\n\t}\n\n\t/**\n\t * 生成head_object的url\n\t * @param string $bucket (Required)\n\t * @param string $object (Required)\n\t * return false| string url\n\t */\n\tpublic function generate_head_object_url($bucket, $object, $opt = array()) {\n\t\t$this->assertParameterArray ( $opt );\n\t\treturn $this->generate_user_url ( \"HEAD\", $bucket, $object, $opt );\n\t}\n\n\t/**\n\t * @return the $use_ssl\n\t */\n\tpublic function getUse_ssl() {\n\t\treturn $this->use_ssl;\n\t}\n\n\t/**\n\t * @param boolean $use_ssl\n\t */\n\tpublic function setUse_ssl($use_ssl) {\n\t\t$this->use_ssl = $use_ssl;\n\t}\n\n\t/**\n\t * 校验bucket是否合法，bucket规范\n\t * 1. 由小写字母，数字和横线'-'组成，长度为6~63位\n\t * 2. 不能以数字作为Bucket开头\n\t * 3. 不能以'-'作为Bucket的开头或者结尾\n\t * @param string $bucket\n\t * @return boolean\n\t */\n\tpublic static function validate_bucket($bucket) {\n\t\t//bucket 正则\n\t\t$pattern1 = '/^[a-z][-a-z0-9]{4,61}[a-z0-9]$/';\n\t\tif (! preg_match ( $pattern1, $bucket )) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * 校验object是否合法，object命名规范\n\t * 1. object必须以'/'开头\n\t * @param string $object\n\t * @return boolean\n\t */\n\tpublic static function validate_object($object) {\n\t\t$pattern = '/^\\//';\n\t\tif (empty ( $object ) || ! preg_match ( $pattern, $object )) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * 将常用set http-header的动作抽离出来\n\t * @param string $header\n\t * @param string $value\n\t * @param array $opt\n\t * @throws BCS_Exception\n\t * @return void\n\t */\n\tprivate static function set_header_into_opt($header, $value, &$opt) {\n\t\tif (isset ( $opt [self::HEADERS] )) {\n\t\t\tif (! is_array ( $opt [self::HEADERS] )) {\n\t\t\t\ttrigger_error ( 'Invalid $opt[\\'headers\\'], please check.' );\n\t\t\t\tthrow new BCS_Exception ( 'Invalid $opt[\\'headers\\'], please check.', - 1 );\n\t\t\t}\n\t\t} else {\n\t\t\t$opt [self::HEADERS] = array ();\n\t\t}\n\t\t$opt [self::HEADERS] [$header] = $value;\n\t}\n\n\t/**\n\t * 使用特定function对数组中所有元素做处理\n\t * @param string    &$array        要处理的字符串\n\t * @param string    $function    要执行的函数\n\t * @param boolean   $apply_to_keys_also     是否也应用到key上\n\t */\n\tprivate static function array_recursive(&$array, $function, $apply_to_keys_also = false) {\n\t\tforeach ( $array as $key => $value ) {\n\t\t\tif (is_array ( $value )) {\n\t\t\t\tself::array_recursive ( $array [$key], $function, $apply_to_keys_also );\n\t\t\t} else {\n\t\t\t\t$array [$key] = $function ( $value );\n\t\t\t}\n\n\t\t\tif ($apply_to_keys_also && is_string ( $key )) {\n\t\t\t\t$new_key = $function ( $key );\n\t\t\t\tif ($new_key != $key) {\n\t\t\t\t\t$array [$new_key] = $array [$key];\n\t\t\t\t\tunset ( $array [$key] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * 由数组构造json字符串，增加了一些特殊处理以支持特殊字符和不同编码的中文\n\t * @param array $array\n\t */\n\tprivate static function array_to_json($array) {\n\t\tif (! is_array ( $array )) {\n\t\t\tthrow new BCS_Exception ( \"Param must be array in function array_to_json()\", - 1 );\n\t\t}\n\t\tself::array_recursive ( $array, 'addslashes', false );\n\t\tself::array_recursive ( $array, 'rawurlencode', false );\n\t\treturn rawurldecode ( json_encode ( $array ) );\n\t}\n\n\t/**\n\t * 根据用户传入的acl，进行相应的处理\n\t * (1).设置详细json格式的acl；\n\t * a. $acl 为json的array\n\t * b. $acl 为json的string\n\t * (2).通过acl_type字段进行设置\n\t * @param string|array $acl\n\t * @throws BCS_Exception\n\t * @return array\n\t */\n\tprivate function analyze_user_acl($acl) {\n\t\t$result = array ();\n\t\tif (is_array ( $acl )) {\n\t\t\t//(1).a\n\t\t\t$result ['content'] = $this->check_user_acl ( $acl );\n\t\t} else if (is_string ( $acl )) {\n\t\t\tif (in_array ( $acl, self::$ACL_TYPES )) {\n\t\t\t\t//(2).a\n\t\t\t\t$result [\"headers\"] = array (\n\t\t\t\t\t\t\"x-bs-acl\" => $acl );\n\t\t\t} else {\n\t\t\t\t//(1).b\n\t\t\t\t$result ['content'] = $acl;\n\t\t\t}\n\t\t} else {\n\t\t\tthrow new BCS_Exception ( \"Invalid acl.\", - 1 );\n\t\t}\n\t\treturn $result;\n\t}\n\n\t/**\n\t * 生成签名\n\t * @param array $opt\n\t * @return boolean|string\n\t */\n\tprivate function format_signature($opt) {\n\t\t$flags = \"\";\n\t\t$content = '';\n\t\tif (! isset ( $opt [self::AK] ) || ! isset ( $opt [self::SK] )) {\n\t\t\ttrigger_error ( 'ak or sk is not in the array when create factor!' );\n\t\t\treturn false;\n\t\t}\n\t\tif (isset ( $opt [self::BUCKET] ) && isset ( $opt [self::METHOD] ) && isset ( $opt [self::OBJECT] )) {\n\t\t\t$flags .= 'MBO';\n\t\t\t$content .= \"Method=\" . $opt [self::METHOD] . \"\\n\"; //method\n\t\t\t$content .= \"Bucket=\" . $opt [self::BUCKET] . \"\\n\"; //bucket\n\t\t\t$content .= \"Object=\" . self::trimUrl ( $opt [self::OBJECT] ) . \"\\n\"; //object\n\t\t} else {\n\t\t\ttrigger_error ( 'bucket、method and object cann`t be NULL!' );\n\t\t\treturn false;\n\t\t}\n\t\tif (isset ( $opt ['ip'] )) {\n\t\t\t$flags .= 'I';\n\t\t\t$content .= \"Ip=\" . $opt ['ip'] . \"\\n\";\n\t\t}\n\t\tif (isset ( $opt ['time'] )) {\n\t\t\t$flags .= 'T';\n\t\t\t$content .= \"Time=\" . $opt ['time'] . \"\\n\";\n\t\t}\n\t\tif (isset ( $opt ['size'] )) {\n\t\t\t$flags .= 'S';\n\t\t\t$content .= \"Size=\" . $opt ['size'] . \"\\n\";\n\t\t}\n\t\t$content = $flags . \"\\n\" . $content;\n\t\t$sign = base64_encode ( hash_hmac ( 'sha1', $content, $opt [self::SK], true ) );\n\t\treturn 'sign=' . $flags . ':' . $opt [self::AK] . ':' . urlencode ( $sign );\n\t}\n\n\t/**\n\t * 检查用户输入的acl array是否合法，并转为json\n\t * @param array $acl\n\t * @throws BCS_Exception\n\t * @return string acl-json\n\t */\n\tprivate function check_user_acl($acl) {\n\t\tif (! is_array ( $acl )) {\n\t\t\tthrow new BCS_Exception ( \"Invalid acl array\" );\n\t\t}\n\t\tforeach ( $acl ['statements'] as $key => $statement ) {\n\t\t\t// user resource action effect must in statement\n\t\t\tif (! isset ( $statement ['user'] ) || ! isset ( $statement ['resource'] ) || ! isset ( $statement ['action'] ) || ! isset ( $statement ['effect'] )) {\n\t\t\t\tthrow new BCS_Exception ( 'Param miss: format acl error, please check your param!' );\n\t\t\t}\n\t\t\tif (! is_array ( $statement ['user'] ) || ! is_array ( $statement ['resource'] )) {\n\t\t\t\tthrow new BCS_Exception ( 'Param error: user or resource must be array, please check your param!' );\n\t\t\t}\n\t\t\tif (! is_array ( $statement ['action'] ) || ! count ( array_diff ( $statement ['action'], self::$ACL_ACTIONS ) ) == 0) {\n\t\t\t\tthrow new BCS_Exception ( 'Param error: action, please check your param!' );\n\t\t\t}\n\t\t\tif (! in_array ( $statement ['effect'], self::$ACL_EFFECTS )) {\n\t\t\t\tthrow new BCS_Exception ( 'Param error: effect, please check your param!' );\n\t\t\t}\n\t\t\tif (isset ( $statement ['time'] )) {\n\t\t\t\tif (! is_array ( $statement ['time'] )) {\n\t\t\t\t\tthrow new BCS_Exception ( 'Param error: time, please check your param!' );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn self::array_to_json ( $acl );\n\t}\n\n\t/**\n\t * 构造url\n\t * @param array $opt\n\t * @return boolean|string\n\t */\n\tprivate function format_url($opt) {\n\t\t$sign = $this->format_signature ( $opt );\n\t\tif ($sign === false) {\n\t\t\ttrigger_error ( \"Format signature failed, please check!\" );\n\t\t\treturn false;\n\t\t}\n\t\t$opt ['sign'] = $sign;\n\t\t$url = \"\";\n\t\t$url .= $this->use_ssl ? 'https://' : 'http://';\n\t\t$url .= $this->hostname;\n\t\t$url .= '/' . $opt [self::BUCKET];\n\t\tif (isset ( $opt [self::OBJECT] ) && '/' !== $opt [self::OBJECT]) {\n\t\t\t$url .= \"/\" . rawurlencode ( $opt [self::OBJECT] );\n\t\t}\n\t\t$url .= '?' . $sign;\n\t\tif (isset ( $opt [self::QUERY_STRING] )) {\n\t\t\tforeach ( $opt [self::QUERY_STRING] as $key => $value ) {\n\t\t\t\t$url .= '&' . $key . '=' . $value;\n\t\t\t}\n\t\t}\n\t\treturn $url;\n\t}\n\n\t/**\n\t * 将url中 '//' 替换为  '/'\n\t * @param $url\n\t * @return string\n\t */\n\tpublic static function trimUrl($url) {\n\t\t$result = str_replace ( \"//\", \"/\", $url );\n\t\twhile ( $result !== $url ) {\n\t\t\t$url = $result;\n\t\t\t$result = str_replace ( \"//\", \"/\", $url );\n\t\t}\n\t\treturn $result;\n\t}\n\n\t/**\n\t * 获取传入目录的文件列表\n\t * @param string $dir 文件目录\n\t * @return array 文件树\n\t */\n\tpublic static function get_filetree($dir, $file_prefix = \"/*\") {\n\t\t$tree = array ();\n\t\tforeach ( glob ( $dir . $file_prefix ) as $single ) {\n\t\t\tif (is_dir ( $single )) {\n\t\t\t\t$tree = array_merge ( $tree, self::get_filetree ( $single ) );\n\t\t\t} else {\n\t\t\t\t$tree [] = $single;\n\t\t\t}\n\t\t}\n\t\treturn $tree;\n\t}\n\n\t/**\n\t * 内置的日志函数，可以根据用户传入的log函数，进行日志输出\n\t * @param string $log\n\t * @param array $opt\n\t */\n\tpublic function log($log, $opt) {\n\t\tif (isset ( $opt [self::IMPORT_BCS_LOG_METHOD] ) && function_exists ( $opt [self::IMPORT_BCS_LOG_METHOD] )) {\n\t\t\t$opt [self::IMPORT_BCS_LOG_METHOD] ( $log );\n\t\t} else {\n\t\t\ttrigger_error ( $log );\n\t\t}\n\t}\n\n\t/**\n\t * make sure $opt is an array\n\t * @param $opt\n\t */\n\tprivate function assertParameterArray($opt) {\n\t\tif (! is_array ( $opt )) {\n\t\t\tthrow new BCS_Exception ( 'Parameter must be array, please check!', - 1 );\n\t\t}\n\t}\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Upload/Driver/Bcs/mimetypes.class.php",
    "content": "<?php\nnamespace Think\\Upload\\Driver\\Bcs;\nclass BCS_MimeTypes {\n\tpublic static $mime_types = array (\n\t\t\t'3gp' => 'video/3gpp', 'ai' => 'application/postscript',\n\t\t\t'aif' => 'audio/x-aiff', 'aifc' => 'audio/x-aiff',\n\t\t\t'aiff' => 'audio/x-aiff', 'asc' => 'text/plain',\n\t\t\t'atom' => 'application/atom+xml', 'au' => 'audio/basic',\n\t\t\t'avi' => 'video/x-msvideo', 'bcpio' => 'application/x-bcpio',\n\t\t\t'bin' => 'application/octet-stream', 'bmp' => 'image/bmp',\n\t\t\t'cdf' => 'application/x-netcdf', 'cgm' => 'image/cgm',\n\t\t\t'class' => 'application/octet-stream',\n\t\t\t'cpio' => 'application/x-cpio',\n\t\t\t'cpt' => 'application/mac-compactpro',\n\t\t\t'csh' => 'application/x-csh', 'css' => 'text/css',\n\t\t\t'dcr' => 'application/x-director', 'dif' => 'video/x-dv',\n\t\t\t'dir' => 'application/x-director', 'djv' => 'image/vnd.djvu',\n\t\t\t'djvu' => 'image/vnd.djvu',\n\t\t\t'dll' => 'application/octet-stream',\n\t\t\t'dmg' => 'application/octet-stream',\n\t\t\t'dms' => 'application/octet-stream',\n\t\t\t'doc' => 'application/msword', 'dtd' => 'application/xml-dtd',\n\t\t\t'dv' => 'video/x-dv', 'dvi' => 'application/x-dvi',\n\t\t\t'dxr' => 'application/x-director',\n\t\t\t'eps' => 'application/postscript', 'etx' => 'text/x-setext',\n\t\t\t'exe' => 'application/octet-stream',\n\t\t\t'ez' => 'application/andrew-inset', 'flv' => 'video/x-flv',\n\t\t\t'gif' => 'image/gif', 'gram' => 'application/srgs',\n\t\t\t'grxml' => 'application/srgs+xml',\n\t\t\t'gtar' => 'application/x-gtar', 'gz' => 'application/x-gzip',\n\t\t\t'hdf' => 'application/x-hdf',\n\t\t\t'hqx' => 'application/mac-binhex40', 'htm' => 'text/html',\n\t\t\t'html' => 'text/html', 'ice' => 'x-conference/x-cooltalk',\n\t\t\t'ico' => 'image/x-icon', 'ics' => 'text/calendar',\n\t\t\t'ief' => 'image/ief', 'ifb' => 'text/calendar',\n\t\t\t'iges' => 'model/iges', 'igs' => 'model/iges',\n\t\t\t'jnlp' => 'application/x-java-jnlp-file', 'jp2' => 'image/jp2',\n\t\t\t'jpe' => 'image/jpeg', 'jpeg' => 'image/jpeg',\n\t\t\t'jpg' => 'image/jpeg', 'js' => 'application/x-javascript',\n\t\t\t'kar' => 'audio/midi', 'latex' => 'application/x-latex',\n\t\t\t'lha' => 'application/octet-stream',\n\t\t\t'lzh' => 'application/octet-stream',\n\t\t\t'm3u' => 'audio/x-mpegurl', 'm4a' => 'audio/mp4a-latm',\n\t\t\t'm4p' => 'audio/mp4a-latm', 'm4u' => 'video/vnd.mpegurl',\n\t\t\t'm4v' => 'video/x-m4v', 'mac' => 'image/x-macpaint',\n\t\t\t'man' => 'application/x-troff-man',\n\t\t\t'mathml' => 'application/mathml+xml',\n\t\t\t'me' => 'application/x-troff-me', 'mesh' => 'model/mesh',\n\t\t\t'mid' => 'audio/midi', 'midi' => 'audio/midi',\n\t\t\t'mif' => 'application/vnd.mif', 'mov' => 'video/quicktime',\n\t\t\t'movie' => 'video/x-sgi-movie', 'mp2' => 'audio/mpeg',\n\t\t\t'mp3' => 'audio/mpeg', 'mp4' => 'video/mp4',\n\t\t\t'mpe' => 'video/mpeg', 'mpeg' => 'video/mpeg',\n\t\t\t'mpg' => 'video/mpeg', 'mpga' => 'audio/mpeg',\n\t\t\t'ms' => 'application/x-troff-ms', 'msh' => 'model/mesh',\n\t\t\t'mxu' => 'video/vnd.mpegurl', 'nc' => 'application/x-netcdf',\n\t\t\t'oda' => 'application/oda', 'ogg' => 'application/ogg',\n\t\t\t'ogv' => 'video/ogv', 'pbm' => 'image/x-portable-bitmap',\n\t\t\t'pct' => 'image/pict', 'pdb' => 'chemical/x-pdb',\n\t\t\t'pdf' => 'application/pdf',\n\t\t\t'pgm' => 'image/x-portable-graymap',\n\t\t\t'pgn' => 'application/x-chess-pgn', 'pic' => 'image/pict',\n\t\t\t'pict' => 'image/pict', 'png' => 'image/png',\n\t\t\t'pnm' => 'image/x-portable-anymap',\n\t\t\t'pnt' => 'image/x-macpaint', 'pntg' => 'image/x-macpaint',\n\t\t\t'ppm' => 'image/x-portable-pixmap',\n\t\t\t'ppt' => 'application/vnd.ms-powerpoint',\n\t\t\t'ps' => 'application/postscript', 'qt' => 'video/quicktime',\n\t\t\t'qti' => 'image/x-quicktime', 'qtif' => 'image/x-quicktime',\n\t\t\t'ra' => 'audio/x-pn-realaudio',\n\t\t\t'ram' => 'audio/x-pn-realaudio', 'ras' => 'image/x-cmu-raster',\n\t\t\t'rdf' => 'application/rdf+xml', 'rgb' => 'image/x-rgb',\n\t\t\t'rm' => 'application/vnd.rn-realmedia',\n\t\t\t'roff' => 'application/x-troff', 'rtf' => 'text/rtf',\n\t\t\t'rtx' => 'text/richtext', 'sgm' => 'text/sgml',\n\t\t\t'sgml' => 'text/sgml', 'sh' => 'application/x-sh',\n\t\t\t'shar' => 'application/x-shar', 'silo' => 'model/mesh',\n\t\t\t'sit' => 'application/x-stuffit',\n\t\t\t'skd' => 'application/x-koan', 'skm' => 'application/x-koan',\n\t\t\t'skp' => 'application/x-koan', 'skt' => 'application/x-koan',\n\t\t\t'smi' => 'application/smil', 'smil' => 'application/smil',\n\t\t\t'snd' => 'audio/basic', 'so' => 'application/octet-stream',\n\t\t\t'spl' => 'application/x-futuresplash',\n\t\t\t'src' => 'application/x-wais-source',\n\t\t\t'sv4cpio' => 'application/x-sv4cpio',\n\t\t\t'sv4crc' => 'application/x-sv4crc', 'svg' => 'image/svg+xml',\n\t\t\t'swf' => 'application/x-shockwave-flash',\n\t\t\t't' => 'application/x-troff', 'tar' => 'application/x-tar',\n\t\t\t'tcl' => 'application/x-tcl', 'tex' => 'application/x-tex',\n\t\t\t'texi' => 'application/x-texinfo',\n\t\t\t'texinfo' => 'application/x-texinfo', 'tif' => 'image/tiff',\n\t\t\t'tiff' => 'image/tiff', 'tr' => 'application/x-troff',\n\t\t\t'tsv' => 'text/tab-separated-values', 'txt' => 'text/plain',\n\t\t\t'ustar' => 'application/x-ustar',\n\t\t\t'vcd' => 'application/x-cdlink', 'vrml' => 'model/vrml',\n\t\t\t'vxml' => 'application/voicexml+xml', 'wav' => 'audio/x-wav',\n\t\t\t'wbmp' => 'image/vnd.wap.wbmp',\n\t\t\t'wbxml' => 'application/vnd.wap.wbxml', 'webm' => 'video/webm',\n\t\t\t'wml' => 'text/vnd.wap.wml',\n\t\t\t'wmlc' => 'application/vnd.wap.wmlc',\n\t\t\t'wmls' => 'text/vnd.wap.wmlscript',\n\t\t\t'wmlsc' => 'application/vnd.wap.wmlscriptc',\n\t\t\t'wmv' => 'video/x-ms-wmv', 'wrl' => 'model/vrml',\n\t\t\t'xbm' => 'image/x-xbitmap', 'xht' => 'application/xhtml+xml',\n\t\t\t'xhtml' => 'application/xhtml+xml',\n\t\t\t'xls' => 'application/vnd.ms-excel',\n\t\t\t'xml' => 'application/xml', 'xpm' => 'image/x-xpixmap',\n\t\t\t'xsl' => 'application/xml', 'xslt' => 'application/xslt+xml',\n\t\t\t'xul' => 'application/vnd.mozilla.xul+xml',\n\t\t\t'xwd' => 'image/x-xwindowdump', 'xyz' => 'chemical/x-xyz',\n\t\t\t'zip' => 'application/zip',\n\t\t\t//add by zhengkan 20110905\n\t\t\t\"apk\" => \"application/vnd.android.package-archive\",\n\t\t\t\"bin\" => \"application/octet-stream\",\n\t\t\t\"cab\" => \"application/vnd.ms-cab-compressed\",\n\t\t\t\"gb\" => \"application/chinese-gb\",\n\t\t\t\"gba\" => \"application/octet-stream\",\n\t\t\t\"gbc\" => \"application/octet-stream\",\n\t\t\t\"jad\" => \"text/vnd.sun.j2me.app-descriptor\",\n\t\t\t\"jar\" => \"application/java-archive\",\n\t\t\t\"nes\" => \"application/octet-stream\",\n\t\t\t\"rar\" => \"application/x-rar-compressed\",\n\t\t\t\"sis\" => \"application/vnd.symbian.install\",\n\t\t\t\"sisx\" => \"x-epoc/x-sisx-app\",\n\t\t\t\"smc\" => \"application/octet-stream\",\n\t\t\t\"smd\" => \"application/octet-stream\",\n\t\t\t\"swf\" => \"application/x-shockwave-flash\",\n\t\t\t\"zip\" => \"application/x-zip-compressed\",\n\t\t\t\"wap\" => \"text/vnd.wap.wml wml\", \"mrp\" => \"application/mrp\",\n\t\t\t//add by zhengkan 20110914\n\t\t\t\"wma\" => \"audio/x-ms-wma\",\n\t\t\t\"lrc\" => \"application/lrc\" );\n\tpublic static function get_mimetype($ext) {\n\t\t$ext = strtolower ( $ext );\n\t\treturn (isset ( self::$mime_types [$ext] ) ? self::$mime_types [$ext] : 'application/octet-stream');\n\t}\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Upload/Driver/Bcs/requestcore.class.php",
    "content": "<?php\nnamespace Think\\Upload\\Driver\\Bcs;\n\n/**\n * Handles all HTTP requests using cURL and manages the responses.\n *\n * @version 2011.03.01\n * @copyright 2006-2011 Ryan Parman\n * @copyright 2006-2010 Foleeo Inc.\n * @copyright 2010-2011 Amazon.com, Inc. or its affiliates.\n * @copyright 2008-2011 Contributors\n * @license http://opensource.org/licenses/bsd-license.php Simplified BSD License\n */\nclass BCS_RequestCore {\n\t/**\n\t * The URL being requested.\n\t */\n\tpublic $request_url;\n\t/**\n\t * The headers being sent in the request.\n\t */\n\tpublic $request_headers;\n\t/**\n\t * The body being sent in the request.\n\t */\n\tpublic $request_body;\n\t/**\n\t * The response returned by the request.\n\t */\n\tpublic $response;\n\t/**\n\t * The headers returned by the request.\n\t */\n\tpublic $response_headers;\n\t/**\n\t * The body returned by the request.\n\t */\n\tpublic $response_body;\n\t/**\n\t * The HTTP status code returned by the request.\n\t */\n\tpublic $response_code;\n\t/**\n\t * Additional response data.\n\t */\n\tpublic $response_info;\n\t/**\n\t * The handle for the cURL object.\n\t */\n\tpublic $curl_handle;\n\t/**\n\t * The method by which the request is being made.\n\t */\n\tpublic $method;\n\t/**\n\t * Stores the proxy settings to use for the request.\n\t */\n\tpublic $proxy = null;\n\t/**\n\t * The username to use for the request.\n\t */\n\tpublic $username = null;\n\t/**\n\t * The password to use for the request.\n\t */\n\tpublic $password = null;\n\t/**\n\t * Custom CURLOPT settings.\n\t */\n\tpublic $curlopts = null;\n\t/**\n\t * The state of debug mode.\n\t */\n\tpublic $debug_mode = false;\n\t/**\n\t * The default class to use for HTTP Requests (defaults to <BCS_RequestCore>).\n\t */\n\tpublic $request_class = 'BCS_RequestCore';\n\t/**\n\t * The default class to use for HTTP Responses (defaults to <BCS_ResponseCore>).\n\t */\n\tpublic $response_class = 'BCS_ResponseCore';\n\t/**\n\t * Default useragent string to use.\n\t */\n\tpublic $useragent = 'BCS_RequestCore/1.4.2';\n\t/**\n\t * File to read from while streaming up.\n\t */\n\tpublic $read_file = null;\n\t/**\n\t * The resource to read from while streaming up.\n\t */\n\tpublic $read_stream = null;\n\t/**\n\t * The size of the stream to read from.\n\t */\n\tpublic $read_stream_size = null;\n\t/**\n\t * The length already read from the stream.\n\t */\n\tpublic $read_stream_read = 0;\n\t/**\n\t * File to write to while streaming down.\n\t */\n\tpublic $write_file = null;\n\t/**\n\t * The resource to write to while streaming down.\n\t */\n\tpublic $write_stream = null;\n\t/**\n\t * Stores the intended starting seek position.\n\t */\n\tpublic $seek_position = null;\n\t/**\n\t * The user-defined callback function to call when a stream is read from.\n\t */\n\tpublic $registered_streaming_read_callback = null;\n\t/**\n\t * The user-defined callback function to call when a stream is written to.\n\t */\n\tpublic $registered_streaming_write_callback = null;\n\t/*%******************************************************************************************%*/\n\t// CONSTANTS\n\t/**\n\t * GET HTTP Method\n\t */\n\tconst HTTP_GET = 'GET';\n\t/**\n\t * POST HTTP Method\n\t */\n\tconst HTTP_POST = 'POST';\n\t/**\n\t * PUT HTTP Method\n\t */\n\tconst HTTP_PUT = 'PUT';\n\t/**\n\t * DELETE HTTP Method\n\t */\n\tconst HTTP_DELETE = 'DELETE';\n\t/**\n\t * HEAD HTTP Method\n\t */\n\tconst HTTP_HEAD = 'HEAD';\n\n\t/*%******************************************************************************************%*/\n\t// CONSTRUCTOR/DESTRUCTOR\n\t/**\n\t * Constructs a new instance of this class.\n\t *\n\t * @param string $url (Optional) The URL to request or service endpoint to query.\n\t * @param string $proxy (Optional) The faux-url to use for proxy settings. Takes the following format: `proxy://user:pass@hostname:port`\n\t * @param array $helpers (Optional) An associative array of classnames to use for request, and response functionality. Gets passed in automatically by the calling class.\n\t * @return $this A reference to the current instance.\n\t */\n\tpublic function __construct($url = null, $proxy = null, $helpers = null) {\n\t\t// Set some default values.\n\t\t$this->request_url = $url;\n\t\t$this->method = self::HTTP_GET;\n\t\t$this->request_headers = array ();\n\t\t$this->request_body = '';\n\t\t// Set a new Request class if one was set.\n\t\tif (isset ( $helpers ['request'] ) && ! empty ( $helpers ['request'] )) {\n\t\t\t$this->request_class = $helpers ['request'];\n\t\t}\n\t\t// Set a new Request class if one was set.\n\t\tif (isset ( $helpers ['response'] ) && ! empty ( $helpers ['response'] )) {\n\t\t\t$this->response_class = $helpers ['response'];\n\t\t}\n\t\tif ($proxy) {\n\t\t\t$this->set_proxy ( $proxy );\n\t\t}\n\t\treturn $this;\n\t}\n\n\t/**\n\t * Destructs the instance. Closes opened file handles.\n\t *\n\t * @return $this A reference to the current instance.\n\t */\n\tpublic function __destruct() {\n\t\tif (isset ( $this->read_file ) && isset ( $this->read_stream )) {\n\t\t\tfclose ( $this->read_stream );\n\t\t}\n\t\tif (isset ( $this->write_file ) && isset ( $this->write_stream )) {\n\t\t\tfclose ( $this->write_stream );\n\t\t}\n\t\treturn $this;\n\t}\n\n\t/*%******************************************************************************************%*/\n\t// REQUEST METHODS\n\t/**\n\t * Sets the credentials to use for authentication.\n\t *\n\t * @param string $user (Required) The username to authenticate with.\n\t * @param string $pass (Required) The password to authenticate with.\n\t * @return $this A reference to the current instance.\n\t */\n\tpublic function set_credentials($user, $pass) {\n\t\t$this->username = $user;\n\t\t$this->password = $pass;\n\t\treturn $this;\n\t}\n\n\t/**\n\t * Adds a custom HTTP header to the cURL request.\n\t *\n\t * @param string $key (Required) The custom HTTP header to set.\n\t * @param mixed $value (Required) The value to assign to the custom HTTP header.\n\t * @return $this A reference to the current instance.\n\t */\n\tpublic function add_header($key, $value) {\n\t\t$this->request_headers [$key] = $value;\n\t\treturn $this;\n\t}\n\n\t/**\n\t * Removes an HTTP header from the cURL request.\n\t *\n\t * @param string $key (Required) The custom HTTP header to set.\n\t * @return $this A reference to the current instance.\n\t */\n\tpublic function remove_header($key) {\n\t\tif (isset ( $this->request_headers [$key] )) {\n\t\t\tunset ( $this->request_headers [$key] );\n\t\t}\n\t\treturn $this;\n\t}\n\n\t/**\n\t * Set the method type for the request.\n\t *\n\t * @param string $method (Required) One of the following constants: <HTTP_GET>, <HTTP_POST>, <HTTP_PUT>, <HTTP_HEAD>, <HTTP_DELETE>.\n\t * @return $this A reference to the current instance.\n\t */\n\tpublic function set_method($method) {\n\t\t$this->method = strtoupper ( $method );\n\t\treturn $this;\n\t}\n\n\t/**\n\t * Sets a custom useragent string for the class.\n\t *\n\t * @param string $ua (Required) The useragent string to use.\n\t * @return $this A reference to the current instance.\n\t */\n\tpublic function set_useragent($ua) {\n\t\t$this->useragent = $ua;\n\t\treturn $this;\n\t}\n\n\t/**\n\t * Set the body to send in the request.\n\t *\n\t * @param string $body (Required) The textual content to send along in the body of the request.\n\t * @return $this A reference to the current instance.\n\t */\n\tpublic function set_body($body) {\n\t\t$this->request_body = $body;\n\t\treturn $this;\n\t}\n\n\t/**\n\t * Set the URL to make the request to.\n\t *\n\t * @param string $url (Required) The URL to make the request to.\n\t * @return $this A reference to the current instance.\n\t */\n\tpublic function set_request_url($url) {\n\t\t$this->request_url = $url;\n\t\treturn $this;\n\t}\n\n\t/**\n\t * Set additional CURLOPT settings. These will merge with the default settings, and override if\n\t * there is a duplicate.\n\t *\n\t * @param array $curlopts (Optional) A set of key-value pairs that set `CURLOPT` options. These will merge with the existing CURLOPTs, and ones passed here will override the defaults. Keys should be the `CURLOPT_*` constants, not strings.\n\t * @return $this A reference to the current instance.\n\t */\n\tpublic function set_curlopts($curlopts) {\n\t\t$this->curlopts = $curlopts;\n\t\treturn $this;\n\t}\n\n\t/**\n\t * Sets the length in bytes to read from the stream while streaming up.\n\t *\n\t * @param integer $size (Required) The length in bytes to read from the stream.\n\t * @return $this A reference to the current instance.\n\t */\n\tpublic function set_read_stream_size($size) {\n\t\t$this->read_stream_size = $size;\n\t\treturn $this;\n\t}\n\n\t/**\n\t * Sets the resource to read from while streaming up. Reads the stream from its current position until\n\t * EOF or `$size` bytes have been read. If `$size` is not given it will be determined by <php:fstat()> and\n\t * <php:ftell()>.\n\t *\n\t * @param resource $resource (Required) The readable resource to read from.\n\t * @param integer $size (Optional) The size of the stream to read.\n\t * @return $this A reference to the current instance.\n\t */\n\tpublic function set_read_stream($resource, $size = null) {\n\t\tif (! isset ( $size ) || $size < 0) {\n\t\t\t$stats = fstat ( $resource );\n\t\t\tif ($stats && $stats ['size'] >= 0) {\n\t\t\t\t$position = ftell ( $resource );\n\t\t\t\tif ($position !== false && $position >= 0) {\n\t\t\t\t\t$size = $stats ['size'] - $position;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t$this->read_stream = $resource;\n\t\treturn $this->set_read_stream_size ( $size );\n\t}\n\n\t/**\n\t * Sets the file to read from while streaming up.\n\t *\n\t * @param string $location (Required) The readable location to read from.\n\t * @return $this A reference to the current instance.\n\t */\n\tpublic function set_read_file($location) {\n\t\t$this->read_file = $location;\n\t\t$read_file_handle = fopen ( $location, 'r' );\n\t\treturn $this->set_read_stream ( $read_file_handle );\n\t}\n\n\t/**\n\t * Sets the resource to write to while streaming down.\n\t *\n\t * @param resource $resource (Required) The writeable resource to write to.\n\t * @return $this A reference to the current instance.\n\t */\n\tpublic function set_write_stream($resource) {\n\t\t$this->write_stream = $resource;\n\t\treturn $this;\n\t}\n\n\t/**\n\t * Sets the file to write to while streaming down.\n\t *\n\t * @param string $location (Required) The writeable location to write to.\n\t * @return $this A reference to the current instance.\n\t */\n\tpublic function set_write_file($location) {\n\t\t$this->write_file = $location;\n\t\t$write_file_handle = fopen ( $location, 'w' );\n\t\treturn $this->set_write_stream ( $write_file_handle );\n\t}\n\n\t/**\n\t * Set the proxy to use for making requests.\n\t *\n\t * @param string $proxy (Required) The faux-url to use for proxy settings. Takes the following format: `proxy://user:pass@hostname:port`\n\t * @return $this A reference to the current instance.\n\t */\n\tpublic function set_proxy($proxy) {\n\t\t$proxy = parse_url ( $proxy );\n\t\t$proxy ['user'] = isset ( $proxy ['user'] ) ? $proxy ['user'] : null;\n\t\t$proxy ['pass'] = isset ( $proxy ['pass'] ) ? $proxy ['pass'] : null;\n\t\t$proxy ['port'] = isset ( $proxy ['port'] ) ? $proxy ['port'] : null;\n\t\t$this->proxy = $proxy;\n\t\treturn $this;\n\t}\n\n\t/**\n\t * Set the intended starting seek position.\n\t *\n\t * @param integer $position (Required) The byte-position of the stream to begin reading from.\n\t * @return $this A reference to the current instance.\n\t */\n\tpublic function set_seek_position($position) {\n\t\t$this->seek_position = isset ( $position ) ? ( integer ) $position : null;\n\t\treturn $this;\n\t}\n\n\t/**\n\t * Register a callback function to execute whenever a data stream is read from using\n\t * <CFRequest::streaming_read_callback()>.\n\t *\n\t * The user-defined callback function should accept three arguments:\n\t *\n\t * <ul>\n\t * <li><code>$curl_handle</code> - <code>resource</code> - Required - The cURL handle resource that represents the in-progress transfer.</li>\n\t * <li><code>$file_handle</code> - <code>resource</code> - Required - The file handle resource that represents the file on the local file system.</li>\n\t * <li><code>$length</code> - <code>integer</code> - Required - The length in kilobytes of the data chunk that was transferred.</li>\n\t * </ul>\n\t *\n\t * @param string|array|function $callback (Required) The callback function is called by <php:call_user_func()>, so you can pass the following values: <ul>\n\t * <li>The name of a global function to execute, passed as a string.</li>\n\t * <li>A method to execute, passed as <code>array('ClassName', 'MethodName')</code>.</li>\n\t * <li>An anonymous function (PHP 5.3+).</li></ul>\n\t * @return $this A reference to the current instance.\n\t */\n\tpublic function register_streaming_read_callback($callback) {\n\t\t$this->registered_streaming_read_callback = $callback;\n\t\treturn $this;\n\t}\n\n\t/**\n\t * Register a callback function to execute whenever a data stream is written to using\n\t * <CFRequest::streaming_write_callback()>.\n\t *\n\t * The user-defined callback function should accept two arguments:\n\t *\n\t * <ul>\n\t * <li><code>$curl_handle</code> - <code>resource</code> - Required - The cURL handle resource that represents the in-progress transfer.</li>\n\t * <li><code>$length</code> - <code>integer</code> - Required - The length in kilobytes of the data chunk that was transferred.</li>\n\t * </ul>\n\t *\n\t * @param string|array|function $callback (Required) The callback function is called by <php:call_user_func()>, so you can pass the following values: <ul>\n\t * <li>The name of a global function to execute, passed as a string.</li>\n\t * <li>A method to execute, passed as <code>array('ClassName', 'MethodName')</code>.</li>\n\t * <li>An anonymous function (PHP 5.3+).</li></ul>\n\t * @return $this A reference to the current instance.\n\t */\n\tpublic function register_streaming_write_callback($callback) {\n\t\t$this->registered_streaming_write_callback = $callback;\n\t\treturn $this;\n\t}\n\n\t/*%******************************************************************************************%*/\n\t// PREPARE, SEND, AND PROCESS REQUEST\n\t/**\n\t * A callback function that is invoked by cURL for streaming up.\n\t *\n\t * @param resource $curl_handle (Required) The cURL handle for the request.\n\t * @param resource $file_handle (Required) The open file handle resource.\n\t * @param integer $length (Required) The maximum number of bytes to read.\n\t * @return binary Binary data from a stream.\n\t */\n\tpublic function streaming_read_callback($curl_handle, $file_handle, $length) {\n\t\t// Once we've sent as much as we're supposed to send...\n\t\tif ($this->read_stream_read >= $this->read_stream_size) {\n\t\t\t// Send EOF\n\t\t\treturn '';\n\t\t}\n\t\t// If we're at the beginning of an upload and need to seek...\n\t\tif ($this->read_stream_read == 0 && isset ( $this->seek_position ) && $this->seek_position !== ftell ( $this->read_stream )) {\n\t\t\tif (fseek ( $this->read_stream, $this->seek_position ) !== 0) {\n\t\t\t\tthrow new BCS_RequestCore_Exception ( 'The stream does not support seeking and is either not at the requested position or the position is unknown.' );\n\t\t\t}\n\t\t}\n\t\t$read = fread ( $this->read_stream, min ( $this->read_stream_size - $this->read_stream_read, $length ) ); // Remaining upload data or cURL's requested chunk size\n\t\t$this->read_stream_read += strlen ( $read );\n\t\t$out = $read === false ? '' : $read;\n\t\t// Execute callback function\n\t\tif ($this->registered_streaming_read_callback) {\n\t\t\tcall_user_func ( $this->registered_streaming_read_callback, $curl_handle, $file_handle, $out );\n\t\t}\n\t\treturn $out;\n\t}\n\n\t/**\n\t * A callback function that is invoked by cURL for streaming down.\n\t *\n\t * @param resource $curl_handle (Required) The cURL handle for the request.\n\t * @param binary $data (Required) The data to write.\n\t * @return integer The number of bytes written.\n\t */\n\tpublic function streaming_write_callback($curl_handle, $data) {\n\t\t$length = strlen ( $data );\n\t\t$written_total = 0;\n\t\t$written_last = 0;\n\t\twhile ( $written_total < $length ) {\n\t\t\t$written_last = fwrite ( $this->write_stream, substr ( $data, $written_total ) );\n\t\t\tif ($written_last === false) {\n\t\t\t\treturn $written_total;\n\t\t\t}\n\t\t\t$written_total += $written_last;\n\t\t}\n\t\t// Execute callback function\n\t\tif ($this->registered_streaming_write_callback) {\n\t\t\tcall_user_func ( $this->registered_streaming_write_callback, $curl_handle, $written_total );\n\t\t}\n\t\treturn $written_total;\n\t}\n\n\t/**\n\t * Prepares and adds the details of the cURL request. This can be passed along to a <php:curl_multi_exec()>\n\t * function.\n\t *\n\t * @return resource The handle for the cURL object.\n\t */\n\tpublic function prep_request() {\n\t\t$curl_handle = curl_init ();\n\t\t// Set default options.\n\t\tcurl_setopt ( $curl_handle, CURLOPT_URL, $this->request_url );\n\t\tcurl_setopt ( $curl_handle, CURLOPT_FILETIME, true );\n\t\tcurl_setopt ( $curl_handle, CURLOPT_FRESH_CONNECT, false );\n\t\tcurl_setopt ( $curl_handle, CURLOPT_SSL_VERIFYPEER, false );\n\t\tcurl_setopt ( $curl_handle, CURLOPT_SSL_VERIFYHOST, true );\n\t\tcurl_setopt ( $curl_handle, CURLOPT_CLOSEPOLICY, CURLCLOSEPOLICY_LEAST_RECENTLY_USED );\n\t\tcurl_setopt ( $curl_handle, CURLOPT_MAXREDIRS, 5 );\n\t\tcurl_setopt ( $curl_handle, CURLOPT_HEADER, true );\n\t\tcurl_setopt ( $curl_handle, CURLOPT_RETURNTRANSFER, true );\n\t\tcurl_setopt ( $curl_handle, CURLOPT_TIMEOUT, 5184000 );\n\t\tcurl_setopt ( $curl_handle, CURLOPT_CONNECTTIMEOUT, 120 );\n\t\tcurl_setopt ( $curl_handle, CURLOPT_NOSIGNAL, true );\n\t\tcurl_setopt ( $curl_handle, CURLOPT_REFERER, $this->request_url );\n\t\tcurl_setopt ( $curl_handle, CURLOPT_USERAGENT, $this->useragent );\n\t\tcurl_setopt ( $curl_handle, CURLOPT_READFUNCTION, array (\n\t\t\t\t$this,\n\t\t\t\t'streaming_read_callback' ) );\n\t\tif ($this->debug_mode) {\n\t\t\tcurl_setopt ( $curl_handle, CURLOPT_VERBOSE, true );\n\t\t}\n\t\t//if (! ini_get ( 'safe_mode' )) {\n\t\t//modify by zhengkan\n\t\t//curl_setopt($curl_handle, CURLOPT_FOLLOWLOCATION, true);\n\t\t//}\n\t\t// Enable a proxy connection if requested.\n\t\tif ($this->proxy) {\n\t\t\tcurl_setopt ( $curl_handle, CURLOPT_HTTPPROXYTUNNEL, true );\n\t\t\t$host = $this->proxy ['host'];\n\t\t\t$host .= ($this->proxy ['port']) ? ':' . $this->proxy ['port'] : '';\n\t\t\tcurl_setopt ( $curl_handle, CURLOPT_PROXY, $host );\n\t\t\tif (isset ( $this->proxy ['user'] ) && isset ( $this->proxy ['pass'] )) {\n\t\t\t\tcurl_setopt ( $curl_handle, CURLOPT_PROXYUSERPWD, $this->proxy ['user'] . ':' . $this->proxy ['pass'] );\n\t\t\t}\n\t\t}\n\t\t// Set credentials for HTTP Basic/Digest Authentication.\n\t\tif ($this->username && $this->password) {\n\t\t\tcurl_setopt ( $curl_handle, CURLOPT_HTTPAUTH, CURLAUTH_ANY );\n\t\t\tcurl_setopt ( $curl_handle, CURLOPT_USERPWD, $this->username . ':' . $this->password );\n\t\t}\n\t\t// Handle the encoding if we can.\n\t\tif (extension_loaded ( 'zlib' )) {\n\t\t\tcurl_setopt ( $curl_handle, CURLOPT_ENCODING, '' );\n\t\t}\n\t\t// Process custom headers\n\t\tif (isset ( $this->request_headers ) && count ( $this->request_headers )) {\n\t\t\t$temp_headers = array ();\n\t\t\tforeach ( $this->request_headers as $k => $v ) {\n\t\t\t\t$temp_headers [] = $k . ': ' . $v;\n\t\t\t}\n\t\t\tcurl_setopt ( $curl_handle, CURLOPT_HTTPHEADER, $temp_headers );\n\t\t}\n\t\tswitch ($this->method) {\n\t\t\tcase self::HTTP_PUT :\n\t\t\t\tcurl_setopt ( $curl_handle, CURLOPT_CUSTOMREQUEST, 'PUT' );\n\t\t\t\tif (isset ( $this->read_stream )) {\n\t\t\t\t\tif (! isset ( $this->read_stream_size ) || $this->read_stream_size < 0) {\n\t\t\t\t\t\tthrow new BCS_RequestCore_Exception ( 'The stream size for the streaming upload cannot be determined.' );\n\t\t\t\t\t}\n\t\t\t\t\tcurl_setopt ( $curl_handle, CURLOPT_INFILESIZE, $this->read_stream_size );\n\t\t\t\t\tcurl_setopt ( $curl_handle, CURLOPT_UPLOAD, true );\n\t\t\t\t} else {\n\t\t\t\t\tcurl_setopt ( $curl_handle, CURLOPT_POSTFIELDS, $this->request_body );\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase self::HTTP_POST :\n\t\t\t\tcurl_setopt ( $curl_handle, CURLOPT_POST, true );\n\t\t\t\tcurl_setopt ( $curl_handle, CURLOPT_POSTFIELDS, $this->request_body );\n\t\t\t\tbreak;\n\t\t\tcase self::HTTP_HEAD :\n\t\t\t\tcurl_setopt ( $curl_handle, CURLOPT_CUSTOMREQUEST, self::HTTP_HEAD );\n\t\t\t\tcurl_setopt ( $curl_handle, CURLOPT_NOBODY, 1 );\n\t\t\t\tbreak;\n\t\t\tdefault : // Assumed GET\n\t\t\t\tcurl_setopt ( $curl_handle, CURLOPT_CUSTOMREQUEST, $this->method );\n\t\t\t\tif (isset ( $this->write_stream )) {\n\t\t\t\t\tcurl_setopt ( $curl_handle, CURLOPT_WRITEFUNCTION, array (\n\t\t\t\t\t\t\t$this,\n\t\t\t\t\t\t\t'streaming_write_callback' ) );\n\t\t\t\t\tcurl_setopt ( $curl_handle, CURLOPT_HEADER, false );\n\t\t\t\t} else {\n\t\t\t\t\tcurl_setopt ( $curl_handle, CURLOPT_POSTFIELDS, $this->request_body );\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t}\n\t\t// Merge in the CURLOPTs\n\t\tif (isset ( $this->curlopts ) && sizeof ( $this->curlopts ) > 0) {\n\t\t\tforeach ( $this->curlopts as $k => $v ) {\n\t\t\t\tcurl_setopt ( $curl_handle, $k, $v );\n\t\t\t}\n\t\t}\n\t\treturn $curl_handle;\n\t}\n\n\t/**\n\t * is the environment BAE?\n\t * @return boolean the result of the answer\n\t */\n\tprivate function isBaeEnv() {\n\t\tif (isset ( $_SERVER ['HTTP_HOST'] )) {\n\t\t\t$host = $_SERVER ['HTTP_HOST'];\n\t\t\t$pos = strpos ( $host, '.' );\n\t\t\tif ($pos !== false) {\n\t\t\t\t$substr = substr ( $host, $pos + 1 );\n\t\t\t\tif ($substr == 'duapp.com') {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (isset ( $_SERVER [\"HTTP_BAE_LOGID\"] )) {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Take the post-processed cURL data and break it down into useful header/body/info chunks. Uses the\n\t * data stored in the `curl_handle` and `response` properties unless replacement data is passed in via\n\t * parameters.\n\t *\n\t * @param resource $curl_handle (Optional) The reference to the already executed cURL request.\n\t * @param string $response (Optional) The actual response content itself that needs to be parsed.\n\t * @return BCS_ResponseCore A <BCS_ResponseCore> object containing a parsed HTTP response.\n\t */\n\tpublic function process_response($curl_handle = null, $response = null) {\n\t\t// Accept a custom one if it's passed.\n\t\tif ($curl_handle && $response) {\n\t\t\t$this->curl_handle = $curl_handle;\n\t\t\t$this->response = $response;\n\t\t}\n\t\t// As long as this came back as a valid resource...\n\t\tif (is_resource ( $this->curl_handle )) {\n\t\t\t// Determine what's what.\n\t\t\t$header_size = curl_getinfo ( $this->curl_handle, CURLINFO_HEADER_SIZE );\n\t\t\t$this->response_headers = substr ( $this->response, 0, $header_size );\n\t\t\t$this->response_body = substr ( $this->response, $header_size );\n\t\t\t$this->response_code = curl_getinfo ( $this->curl_handle, CURLINFO_HTTP_CODE );\n\t\t\t$this->response_info = curl_getinfo ( $this->curl_handle );\n\t\t\t// Parse out the headers\n\t\t\t$this->response_headers = explode ( \"\\r\\n\\r\\n\", trim ( $this->response_headers ) );\n\t\t\t$this->response_headers = array_pop ( $this->response_headers );\n\t\t\t$this->response_headers = explode ( \"\\r\\n\", $this->response_headers );\n\t\t\tarray_shift ( $this->response_headers );\n\t\t\t// Loop through and split up the headers.\n\t\t\t$header_assoc = array ();\n\t\t\tforeach ( $this->response_headers as $header ) {\n\t\t\t\t$kv = explode ( ': ', $header );\n\t\t\t\t//$header_assoc [strtolower ( $kv [0] )] = $kv [1];\n\t\t\t\t$header_assoc [$kv [0]] = $kv [1];\n\t\t\t}\n\t\t\t// Reset the headers to the appropriate property.\n\t\t\t$this->response_headers = $header_assoc;\n\t\t\t$this->response_headers ['_info'] = $this->response_info;\n\t\t\t$this->response_headers ['_info'] ['method'] = $this->method;\n\t\t\tif ($curl_handle && $response) {\n\t\t\t\t$class='\\Think\\Upload\\Driver\\Bcs\\\\'. $this->response_class;\n\t\t\t\treturn new  $class ( $this->response_headers, $this->response_body, $this->response_code, $this->curl_handle );\n\t\t\t}\n\t\t}\n\t\t// Return false\n\t\treturn false;\n\t}\n\n\t/**\n\t * Sends the request, calling necessary utility functions to update built-in properties.\n\t *\n\t * @param boolean $parse (Optional) Whether to parse the response with BCS_ResponseCore or not.\n\t * @return string The resulting unparsed data from the request.\n\t */\n\tpublic function send_request($parse = false) {\n\t\tif (false === $this->isBaeEnv ()) {\n\t\t\tset_time_limit ( 0 );\n\t\t}\n\t\t$curl_handle = $this->prep_request ();\n\t\t$this->response = curl_exec ( $curl_handle );\n\t\tif ($this->response === false ||\n                ($this->method === self::HTTP_GET &&\n                  curl_errno($curl_handle) === CURLE_PARTIAL_FILE)) {\n\t\t\tthrow new BCS_RequestCore_Exception ( 'cURL resource: ' . ( string ) $curl_handle . '; cURL error: ' . curl_error ( $curl_handle ) . ' (' . curl_errno ( $curl_handle ) . ')' );\n\t\t}\n\t\t$parsed_response = $this->process_response ( $curl_handle, $this->response );\n\t\tcurl_close ( $curl_handle );\n\t\tif ($parse) {\n\t\t\treturn $parsed_response;\n\t\t}\n\t\treturn $this->response;\n\t}\n\n\t/**\n\t * Sends the request using <php:curl_multi_exec()>, enabling parallel requests. Uses the \"rolling\" method.\n\t *\n\t * @param array $handles (Required) An indexed array of cURL handles to process simultaneously.\n\t * @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>\n\t * <li><code>callback</code> - <code>string|array</code> - Optional - The string name of a function to pass the response data to. If this is a method, pass an array where the <code>[0]</code> index is the class and the <code>[1]</code> index is the method name.</li>\n\t * <li><code>limit</code> - <code>integer</code> - Optional - The number of simultaneous requests to make. This can be useful for scaling around slow server responses. Defaults to trusting cURLs judgement as to how many to use.</li></ul>\n\t * @return array Post-processed cURL responses.\n\t */\n\tpublic function send_multi_request($handles, $opt = null) {\n\t\tif (false === $this->isBaeEnv ()) {\n\t\t\tset_time_limit ( 0 );\n\t\t}\n\t\t// Skip everything if there are no handles to process.\n\t\tif (count ( $handles ) === 0)\n\t\t\treturn array ();\n\t\tif (! $opt)\n\t\t\t$opt = array ();\n\n\t\t// Initialize any missing options\n\t\t$limit = isset ( $opt ['limit'] ) ? $opt ['limit'] : - 1;\n\t\t// Initialize\n\t\t$handle_list = $handles;\n\t\t$http = new $this->request_class ();\n\t\t$multi_handle = curl_multi_init ();\n\t\t$handles_post = array ();\n\t\t$added = count ( $handles );\n\t\t$last_handle = null;\n\t\t$count = 0;\n\t\t$i = 0;\n\t\t// Loop through the cURL handles and add as many as it set by the limit parameter.\n\t\twhile ( $i < $added ) {\n\t\t\tif ($limit > 0 && $i >= $limit)\n\t\t\t\tbreak;\n\t\t\tcurl_multi_add_handle ( $multi_handle, array_shift ( $handles ) );\n\t\t\t$i ++;\n\t\t}\n\t\tdo {\n\t\t\t$active = false;\n\t\t\t// Start executing and wait for a response.\n\t\t\twhile ( ($status = curl_multi_exec ( $multi_handle, $active )) === CURLM_CALL_MULTI_PERFORM ) {\n\t\t\t\t// Start looking for possible responses immediately when we have to add more handles\n\t\t\t\tif (count ( $handles ) > 0)\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\t// Figure out which requests finished.\n\t\t\t$to_process = array ();\n\t\t\twhile ( $done = curl_multi_info_read ( $multi_handle ) ) {\n\t\t\t\t// Since curl_errno() isn't reliable for handles that were in multirequests, we check the 'result' of the info read, which contains the curl error number, (listed here http://curl.haxx.se/libcurl/c/libcurl-errors.html )\n\t\t\t\tif ($done ['result'] > 0) {\n\t\t\t\t\tthrow new BCS_RequestCore_Exception ( 'cURL resource: ' . ( string ) $done ['handle'] . '; cURL error: ' . curl_error ( $done ['handle'] ) . ' (' . $done ['result'] . ')' );\n\t\t\t\t} // Because curl_multi_info_read() might return more than one message about a request, we check to see if this request is already in our array of completed requests\nelseif (! isset ( $to_process [( int ) $done ['handle']] )) {\n\t\t\t\t\t$to_process [( int ) $done ['handle']] = $done;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Actually deal with the request\n\t\t\tforeach ( $to_process as $pkey => $done ) {\n\t\t\t\t$response = $http->process_response ( $done ['handle'], curl_multi_getcontent ( $done ['handle'] ) );\n\t\t\t\t$key = array_search ( $done ['handle'], $handle_list, true );\n\t\t\t\t$handles_post [$key] = $response;\n\t\t\t\tif (count ( $handles ) > 0) {\n\t\t\t\t\tcurl_multi_add_handle ( $multi_handle, array_shift ( $handles ) );\n\t\t\t\t}\n\t\t\t\tcurl_multi_remove_handle ( $multi_handle, $done ['handle'] );\n\t\t\t\tcurl_close ( $done ['handle'] );\n\t\t\t}\n\t\t} while ( $active || count ( $handles_post ) < $added );\n\t\tcurl_multi_close ( $multi_handle );\n\t\tksort ( $handles_post, SORT_NUMERIC );\n\t\treturn $handles_post;\n\t}\n\n\t/*%******************************************************************************************%*/\n\t// RESPONSE METHODS\n\t/**\n\t * Get the HTTP response headers from the request.\n\t *\n\t * @param string $header (Optional) A specific header value to return. Defaults to all headers.\n\t * @return string|array All or selected header values.\n\t */\n\tpublic function get_response_header($header = null) {\n\t\tif ($header) {\n\t\t\t//\t\t\treturn $this->response_headers [strtolower ( $header )];\n\t\t\treturn $this->response_headers [$header];\n\t\t}\n\t\treturn $this->response_headers;\n\t}\n\n\t/**\n\t * Get the HTTP response body from the request.\n\t *\n\t * @return string The response body.\n\t */\n\tpublic function get_response_body() {\n\t\treturn $this->response_body;\n\t}\n\n\t/**\n\t * Get the HTTP response code from the request.\n\t *\n\t * @return string The HTTP response code.\n\t */\n\tpublic function get_response_code() {\n\t\treturn $this->response_code;\n\t}\n}\n/**\n * Container for all response-related methods.\n */\nclass BCS_ResponseCore {\n\t/**\n\t * Stores the HTTP header information.\n\t */\n\tpublic $header;\n\t/**\n\t * Stores the SimpleXML response.\n\t */\n\tpublic $body;\n\t/**\n\t * Stores the HTTP response code.\n\t */\n\tpublic $status;\n\n\t/**\n\t * Constructs a new instance of this class.\n\t *\n\t * @param array $header (Required) Associative array of HTTP headers (typically returned by <BCS_RequestCore::get_response_header()>).\n\t * @param string $body (Required) XML-formatted response from AWS.\n\t * @param integer $status (Optional) HTTP response status code from the request.\n\t * @return object Contains an <php:array> `header` property (HTTP headers as an associative array), a <php:SimpleXMLElement> or <php:string> `body` property, and an <php:integer> `status` code.\n\t */\n\tpublic function __construct($header, $body, $status = null) {\n\t\t$this->header = $header;\n\t\t$this->body = $body;\n\t\t$this->status = $status;\n\t\treturn $this;\n\t}\n\n\t/**\n\t * Did we receive the status code we expected?\n\t *\n\t * @param integer|array $codes (Optional) The status code(s) to expect. Pass an <php:integer> for a single acceptable value, or an <php:array> of integers for multiple acceptable values.\n\t * @return boolean Whether we received the expected status code or not.\n\t */\n\tpublic function isOK($codes = array(200, 201, 204, 206)) {\n\t\tif (is_array ( $codes )) {\n\t\t\treturn in_array ( $this->status, $codes );\n\t\t}\n\t\treturn $this->status === $codes;\n\t}\n}\n/**\n * Default BCS_RequestCore Exception.\n */\nclass BCS_RequestCore_Exception extends \\Exception {\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Upload/Driver/Bcs.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: Jay <yangweijiester@gmail.com> <http://code-tech.diandian.com>\n// +----------------------------------------------------------------------\nnamespace Think\\Upload\\Driver;\nuse Think\\Upload\\Driver\\Bcs\\BaiduBcs;\nclass Bcs {\n    /**\n     * 上传文件根目录\n     * @var string\n     */\n    private $rootPath;\n    const DEFAULT_URL = 'bcs.duapp.com';\n\n    /**\n     * 上传错误信息\n     * @var string\n     */\n    private $error = '';\n\n    public $config = array(\n    \t'AccessKey'=> '',\n        'SecretKey'=> '', //百度云服务器\n        'bucket'   => '', //空间名称\n        'rename'   => false,\n        'timeout'  => 3600, //超时时间\n    );\n\n    public $bcs = null;\n\n    /**\n     * 构造函数，用于设置上传根路径\n     * @param array  $config FTP配置\n     */\n    public function __construct($config){\n        /* 默认FTP配置 */\n        $this->config = array_merge($this->config, $config);\n        \n        $bcsClass = dirname(__FILE__). \"/Bcs/bcs.class.php\";\n        if(is_file($bcsClass))\n            require_once($bcsClass);\n        $this->bcs = new BaiduBCS ( $this->config['AccessKey'], $this->config['SecretKey'], self:: DEFAULT_URL );\n    }\n\n    /**\n     * 检测上传根目录(百度云上传时支持自动创建目录，直接返回)\n     * @param string $rootpath   根目录\n     * @return boolean true-检测通过，false-检测失败\n     */\n    public function checkRootPath($rootpath){\n        /* 设置根目录 */\n        $this->rootPath = str_replace('./', '/', $rootpath);\n    \treturn true;\n    }\n\n    /**\n     * 检测上传目录(百度云上传时支持自动创建目录，直接返回)\n     * @param  string $savepath 上传目录\n     * @return boolean          检测结果，true-通过，false-失败\n     */\n\tpublic function checkSavePath($savepath){\n\t\treturn true;\n    }\n\n    /**\n     * 创建文件夹 (百度云上传时支持自动创建目录，直接返回)\n     * @param  string $savepath 目录名称\n     * @return boolean          true-创建成功，false-创建失败\n     */\n    public function mkdir($savepath){\n    \treturn true;\n    }\n\n    /**\n     * 保存指定文件\n     * @param  array   $file    保存的文件信息\n     * @param  boolean $replace 同名文件是否覆盖\n     * @return boolean          保存状态，true-成功，false-失败\n     */\n    public function save(&$file,$replace=true) {\n        $opt = array ();\n        $opt ['acl'] = BaiduBCS::BCS_SDK_ACL_TYPE_PUBLIC_WRITE;\n        $opt ['curlopts'] = array (\n            CURLOPT_CONNECTTIMEOUT => 10,\n            CURLOPT_TIMEOUT => 1800\n        );\n        $object = \"/{$file['savepath']}{$file['savename']}\";\n        $response = $this->bcs->create_object ( $this->config['bucket'], $object, $file['tmp_name'], $opt );\n        $url = $this->download($object);\n        $file['url'] = $url;\n        return $response->isOK() ? true : false;\n    }\n\n    public function download($file){\n        $file = str_replace('./', '/', $file);\n        $opt = array();\n        $opt['time'] = mktime('2049-12-31'); //这是最长有效时间!--\n        $response = $this->bcs->generate_get_object_url ( $this->config['bucket'], $file, $opt );\n        return $response;\n    }\n\n    /**\n     * 获取最后一次上传错误信息\n     * @return string 错误信息\n     */\n    public function getError(){\n        return $this->error;\n    }\n\n    /**\n     * 请求百度云服务器\n     * @param  string   $path    请求的PATH\n     * @param  string   $method  请求方法\n     * @param  array    $headers 请求header\n     * @param  resource $body    上传文件资源\n     * @return boolean\n     */\n    private function request($path, $method, $headers = null, $body = null){\n        $ch  = curl_init($path);\n\n        $_headers = array('Expect:');\n        if (!is_null($headers) && is_array($headers)){\n            foreach($headers as $k => $v) {\n                array_push($_headers, \"{$k}: {$v}\");\n            }\n        }\n\n        $length = 0;\n        $date   = gmdate('D, d M Y H:i:s \\G\\M\\T');\n\n        if (!is_null($body)) {\n            if(is_resource($body)){\n                fseek($body, 0, SEEK_END);\n                $length = ftell($body);\n                fseek($body, 0);\n\n                array_push($_headers, \"Content-Length: {$length}\");\n                curl_setopt($ch, CURLOPT_INFILE, $body);\n                curl_setopt($ch, CURLOPT_INFILESIZE, $length);\n            } else {\n                $length = @strlen($body);\n                array_push($_headers, \"Content-Length: {$length}\");\n                curl_setopt($ch, CURLOPT_POSTFIELDS, $body);\n            }\n        } else {\n            array_push($_headers, \"Content-Length: {$length}\");\n        }\n\n        // array_push($_headers, 'Authorization: ' . $this->sign($method, $uri, $date, $length));\n        array_push($_headers, \"Date: {$date}\");\n\n        curl_setopt($ch, CURLOPT_HTTPHEADER, $_headers);\n        curl_setopt($ch, CURLOPT_TIMEOUT, $this->config['timeout']);\n        curl_setopt($ch, CURLOPT_HEADER, 1);\n        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);\n        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0);\n        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);\n\n        if ($method == 'PUT' || $method == 'POST') {\n            curl_setopt($ch, CURLOPT_POST, 1);\n        } else {\n            curl_setopt($ch, CURLOPT_POST, 0);\n        }\n\n        if ($method == 'HEAD') {\n            curl_setopt($ch, CURLOPT_NOBODY, true);\n        }\n\n        $response = curl_exec($ch);\n        $status   = curl_getinfo($ch, CURLINFO_HTTP_CODE);\n        curl_close($ch);\n        list($header, $body) = explode(\"\\r\\n\\r\\n\", $response, 2);\n\n        if ($status == 200) {\n            if ($method == 'GET') {\n                return $body;\n            } else {\n                $data = $this->response($header);\n                return count($data) > 0 ? $data : true;\n            }\n        } else {\n            $this->error($header);\n            return false;\n        }\n    }\n\n    /**\n     * 获取响应数据\n     * @param  string $text 响应头字符串\n     * @return array        响应数据列表\n     */\n    private function response($text){\n        $items = json_decode($text, true);\n        return $items;\n    }\n\n    /**\n     * 生成请求签名\n     * @return string          请求签名\n     */\n    private function sign($method, $Bucket, $object='/', $size=''){\n        if(!$size)\n            $size = $this->config['size'];\n        $param = array(\n            'ak'=>$this->config['AccessKey'],\n            'sk'=>$this->config['SecretKey'],\n            'size'=>$size,\n            'bucket'=>$Bucket,\n            'host'=>self :: DEFAULT_URL,\n            'date'=>time()+$this->config['timeout'],\n            'ip'=>'',\n            'object'=>$object\n        );\n        $response = $this->request($this->apiurl.'?'.http_build_query($param), 'POST');\n        if($response)\n            $response = json_decode($response, true);\n        return $response['content'][$method];\n    }\n\n\n    /**\n     * 获取请求错误信息\n     * @param  string $header 请求返回头信息\n     */\n    private function error($header) {\n        list($status, $stash) = explode(\"\\r\\n\", $header, 2);\n        list($v, $code, $message) = explode(\" \", $status, 3);\n        $message = is_null($message) ? 'File Not Found' : \"[{$status}]:{$message}\";\n        $this->error = $message;\n    }\n\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Upload/Driver/Ftp.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: 麦当苗儿 <zuojiazi@vip.qq.com> <http://www.zjzit.cn>\n// +----------------------------------------------------------------------\n\nnamespace Think\\Upload\\Driver;\nclass Ftp {\n    /**\n     * 上传文件根目录\n     * @var string\n     */\n    private $rootPath;\n\n    /**\n     * 本地上传错误信息\n     * @var string\n     */\n    private $error = ''; //上传错误信息\n\n    /**\n     * FTP连接\n     * @var resource\n     */\n    private $link;\n\n    private $config = array(\n        'host'     => '', //服务器\n        'port'     => 21, //端口\n        'timeout'  => 90, //超时时间\n        'username' => '', //用户名\n        'password' => '', //密码\n    );\n\n    /**\n     * 构造函数，用于设置上传根路径\n     * @param array  $config FTP配置\n     */\n    public function __construct($config){\n        /* 默认FTP配置 */\n        $this->config = array_merge($this->config, $config);\n\n        /* 登录FTP服务器 */\n        if(!$this->login()){\n            E($this->error);\n        }\n    }\n\n    /**\n     * 检测上传根目录\n     * @param string $rootpath   根目录\n     * @return boolean true-检测通过，false-检测失败\n     */\n    public function checkRootPath($rootpath){\n        /* 设置根目录 */\n        $this->rootPath = ftp_pwd($this->link) . '/' . ltrim($rootpath, '/');\n\n        if(!@ftp_chdir($this->link, $this->rootPath)){\n            $this->error = '上传根目录不存在！';\n            return false;\n        }\n        return true;\n    }\n\n    /**\n     * 检测上传目录\n     * @param  string $savepath 上传目录\n     * @return boolean          检测结果，true-通过，false-失败\n     */\n    public function checkSavePath($savepath){\n        /* 检测并创建目录 */\n        if (!$this->mkdir($savepath)) {\n            return false;\n        } else {\n            //TODO:检测目录是否可写\n            return true;\n        }\n    }\n\n    /**\n     * 保存指定文件\n     * @param  array   $file    保存的文件信息\n     * @param  boolean $replace 同名文件是否覆盖\n     * @return boolean          保存状态，true-成功，false-失败\n     */\n    public function save($file, $replace=true) {\n        $filename = $this->rootPath . $file['savepath'] . $file['savename'];\n\n        /* 不覆盖同名文件 */\n        // if (!$replace && is_file($filename)) {\n        //     $this->error = '存在同名文件' . $file['savename'];\n        //     return false;\n        // }\n\n        /* 移动文件 */\n        if (!ftp_put($this->link, $filename, $file['tmp_name'], FTP_BINARY)) {\n            $this->error = '文件上传保存错误！';\n            return false;\n        }\n        return true;\n    }\n\n    /**\n     * 创建目录\n     * @param  string $savepath 要创建的穆里\n     * @return boolean          创建状态，true-成功，false-失败\n     */\n    public function mkdir($savepath){\n        $dir = $this->rootPath . $savepath;\n        if(ftp_chdir($this->link, $dir)){\n            return true;\n        }\n\n        if(ftp_mkdir($this->link, $dir)){\n            return true;\n        } elseif($this->mkdir(dirname($savepath)) && ftp_mkdir($this->link, $dir)) {\n            return true;\n        } else {\n            $this->error = \"目录 {$savepath} 创建失败！\";\n            return false;\n        }\n    }\n\n    /**\n     * 获取最后一次上传错误信息\n     * @return string 错误信息\n     */\n    public function getError(){\n        return $this->error;\n    }\n\n    /**\n     * 登录到FTP服务器\n     * @return boolean true-登录成功，false-登录失败\n     */\n    private function login(){\n        extract($this->config);\n        $this->link = ftp_connect($host, $port, $timeout);\n        if($this->link) {\n            if (ftp_login($this->link, $username, $password)) {\n               return true;\n            } else {\n                $this->error = \"无法登录到FTP服务器：username - {$username}\";\n            }\n        } else {\n            $this->error = \"无法连接到FTP服务器：{$host}\";\n        }\n        return false;\n    }\n\n    /**\n     * 析构方法，用于断开当前FTP连接\n     */\n    public function __destruct() {\n        ftp_close($this->link);\n    }\n\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Upload/Driver/Local.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: 麦当苗儿 <zuojiazi@vip.qq.com> <http://www.zjzit.cn>\n// +----------------------------------------------------------------------\n\nnamespace Think\\Upload\\Driver;\nclass Local{\n    /**\n     * 上传文件根目录\n     * @var string\n     */\n    private $rootPath;\n\n    /**\n     * 本地上传错误信息\n     * @var string\n     */\n    private $error = ''; //上传错误信息\n\n    /**\n     * 构造函数，用于设置上传根路径\n     */\n    public function __construct($config = null){\n\n    }\n\n    /**\n     * 检测上传根目录\n     * @param string $rootpath   根目录\n     * @return boolean true-检测通过，false-检测失败\n     */\n    public function checkRootPath($rootpath){\n        if(!(is_dir($rootpath) && is_writable($rootpath))){\n            $this->error = '上传根目录不存在！请尝试手动创建:'.$rootpath;\n            return false;\n        }\n        $this->rootPath = $rootpath;\n        return true;\n    }\n\n    /**\n     * 检测上传目录\n     * @param  string $savepath 上传目录\n     * @return boolean          检测结果，true-通过，false-失败\n     */\n    public function checkSavePath($savepath){\n        /* 检测并创建目录 */\n        if (!$this->mkdir($savepath)) {\n            return false;\n        } else {\n            /* 检测目录是否可写 */\n            if (!is_writable($this->rootPath . $savepath)) {\n                $this->error = '上传目录 ' . $savepath . ' 不可写！';\n                return false;\n            } else {\n                return true;\n            }\n        }\n    }\n\n    /**\n     * 保存指定文件\n     * @param  array   $file    保存的文件信息\n     * @param  boolean $replace 同名文件是否覆盖\n     * @return boolean          保存状态，true-成功，false-失败\n     */\n    public function save($file, $replace=true) {\n        $filename = $this->rootPath . $file['savepath'] . $file['savename'];\n\n        /* 不覆盖同名文件 */ \n        if (!$replace && is_file($filename)) {\n            $this->error = '存在同名文件' . $file['savename'];\n            return false;\n        }\n\n        /* 移动文件 */\n        if (!move_uploaded_file($file['tmp_name'], $filename)) {\n            $this->error = '文件上传保存错误！';\n            return false;\n        }\n        \n        return true;\n    }\n\n    /**\n     * 创建目录\n     * @param  string $savepath 要创建的穆里\n     * @return boolean          创建状态，true-成功，false-失败\n     */\n    public function mkdir($savepath){\n        $dir = $this->rootPath . $savepath;\n        if(is_dir($dir)){\n            return true;\n        }\n\n        if(mkdir($dir, 0777, true)){\n            return true;\n        } else {\n            $this->error = \"目录 {$savepath} 创建失败！\";\n            return false;\n        }\n    }\n\n    /**\n     * 获取最后一次上传错误信息\n     * @return string 错误信息\n     */\n    public function getError(){\n        return $this->error;\n    }\n\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Upload/Driver/Qiniu/QiniuStorage.class.php",
    "content": "<?php\n\tnamespace Think\\Upload\\Driver\\Qiniu;\n\n\tclass QiniuStorage {\n\n\t\tpublic $QINIU_RSF_HOST = 'http://rsf.qbox.me';\n\t\tpublic $QINIU_RS_HOST = 'http://rs.qbox.me';\n\t\tpublic $QINIU_UP_HOST = 'http://up.qiniu.com';\n\t\tpublic $timeout = '';\n\t\tpublic $hasHost = 0;\n\n\t\tpublic function __construct($config){\n\t\t\t$this->sk = $config['secrectKey'];\n\t\t\t$this->ak = $config['accessKey'];\n\t\t\t$this->domain = $config['domain'];\n\t\t\t$this->bucket = $config['bucket'];\n\t\t\t$this->protocol = $config['protocol'] ? $config['protocol'] : 'http';\n\t\t\t$this->timeout = isset($config['timeout'])? $config['timeout'] : 3600;\n\t\t}\n\n\t\tstatic function sign($sk, $ak, $data){\n\t\t\t$sign = hash_hmac('sha1', $data, $sk, true);\n\t\t\treturn $ak . ':' . self::Qiniu_Encode($sign);\n\t\t}\n\n\t\tstatic function signWithData($sk, $ak, $data){\n\t\t\t$data = self::Qiniu_Encode($data);\n\t\t\treturn self::sign($sk, $ak, $data) . ':' . $data;\n\t\t}\n\n\t\tpublic function accessToken($url, $body=''){\n\t\t\t$parsed_url = parse_url($url);\n\t\t    $path = $parsed_url['path'];\n\t\t    $access = $path;\n\t\t    if (isset($parsed_url['query'])) {\n\t\t        $access .= \"?\" . $parsed_url['query'];\n\t\t    }\n\t\t    $access .= \"\\n\";\n\n\t\t    if($body){\n\t\t        $access .= $body;\n\t\t    }\n\t\t    return self::sign($this->sk, $this->ak, $access);\n\t\t}\n\n\t\tpublic function UploadToken($sk ,$ak ,$param){\n\t\t\t$param['deadline'] = $param['Expires'] == 0? 3600: $param['Expires'];\n\t\t\t$param['deadline'] += time();\n\t\t\t$data = array('scope'=> $this->bucket, 'deadline'=>$param['deadline']);\n\t\t\tif (!empty($param['CallbackUrl'])) {\n\t\t\t\t$data['callbackUrl'] = $param['CallbackUrl'];\n\t\t\t}\n\t\t\tif (!empty($param['CallbackBody'])) {\n\t\t\t\t$data['callbackBody'] = $param['CallbackBody'];\n\t\t\t}\n\t\t\tif (!empty($param['ReturnUrl'])) {\n\t\t\t\t$data['returnUrl'] = $param['ReturnUrl'];\n\t\t\t}\n\t\t\tif (!empty($param['ReturnBody'])) {\n\t\t\t\t$data['returnBody'] = $param['ReturnBody'];\n\t\t\t}\n\t\t\tif (!empty($param['AsyncOps'])) {\n\t\t\t\t$data['asyncOps'] = $param['AsyncOps'];\n\t\t\t}\n\t\t\tif (!empty($param['EndUser'])) {\n\t\t\t\t$data['endUser'] = $param['EndUser'];\n\t\t\t}\n\t\t\t$data = json_encode($data);\n\t\t\treturn self::SignWithData($sk, $ak, $data);\n\t\t}\n\n\t\tpublic function upload($config, $file){\n\t\t\t$this->queryBucketHost();\n\t\t\t$uploadToken = $this->UploadToken($this->sk, $this->ak, $config);\n\t\t\t$url = \"{$this->QINIU_UP_HOST}\";\n\t\t\t$mimeBoundary = md5(microtime());\n\t\t\t$header = array('Content-Type'=>'multipart/form-data;boundary='.$mimeBoundary);\n\t\t\t$data = array();\n\n\t\t\t$fields = array(\n\t\t\t\t'token'=>$uploadToken,\n\t\t\t\t'key'=>$config['saveName']? $config['save_name'] : $file['fileName'],\n\t\t\t);\n\n\t\t\tif(is_array($config['custom_fields']) && $config['custom_fields'] !== array()){\n\t\t\t\t$fields = array_merge($fields, $config['custom_fields']);\n\t\t\t}\n\n\t\t\tforeach ($fields as $name => $val) {\n\t\t\t\tarray_push($data, '--' . $mimeBoundary);\n\t\t\t\tarray_push($data, \"Content-Disposition: form-data; name=\\\"$name\\\"\");\n\t\t\t\tarray_push($data, '');\n\t\t\t\tarray_push($data, $val);\n\t\t\t}\n\n\t\t\t//文件\n\t\t\tarray_push($data, '--' . $mimeBoundary);\n\t\t\t$name = $file['name'];\n\t\t\t$fileName = $file['fileName'];\n\t\t\t$fileBody = $file['fileBody'];\n\t\t\t$fileName = self::Qiniu_escapeQuotes($fileName);\n\t\t\tarray_push($data, \"Content-Disposition: form-data; name=\\\"$name\\\"; filename=\\\"$fileName\\\"\");\n\t\t\tarray_push($data, 'Content-Type: application/octet-stream');\n\t\t\tarray_push($data, '');\n\t\t\tarray_push($data, $fileBody);\n\n\t\t\tarray_push($data, '--' . $mimeBoundary . '--');\n\t\t\tarray_push($data, '');\n\n\t\t\t$body = implode(\"\\r\\n\", $data);\n\t\t\t$response = $this->request($url, 'POST', $header, $body);\n\t\t\treturn $response;\n\t\t}\n\n\t\tpublic function dealWithType($key, $type){\n\t\t\t$param = $this->buildUrlParam();\n\t\t\t$url = '';\n\n\t\t\tswitch($type){\n\t\t\t\tcase 'img':\n\t\t\t\t\t$url = $this->downLink($key);\n\t\t\t\t\tif($param['imageInfo']){\n\t\t\t\t\t\t$url .= '?imageInfo';\n\t\t\t\t\t}else if($param['exif']){\n\t\t\t\t\t\t$url .= '?exif';\n\t\t\t\t\t}else if($param['imageView']){\n\t\t\t\t\t\t$url .= '?imageView/'.$param['mode'];\n\t\t\t\t\t\tif($param['w'])\n\t\t\t\t\t\t\t$url .= \"/w/{$param['w']}\";\n\t\t\t\t\t\tif($param['h'])\n\t\t\t\t\t\t\t$url .= \"/h/{$param['h']}\";\n\t\t\t\t\t\tif($param['q'])\n\t\t\t\t\t\t\t$url .= \"/q/{$param['q']}\";\n\t\t\t\t\t\tif($param['format'])\n\t\t\t\t\t\t\t$url .= \"/format/{$param['format']}\";\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'video': //TODO 视频处理\n\t\t\t\tcase 'doc':\n\t\t\t\t\t$url = $this->downLink($key);\n\t\t\t\t\t$url .= '?md2html';\n\t\t\t\t\tif(isset($param['mode']))\n\t\t\t\t\t\t$url .= '/'.(int)$param['mode'];\n\t\t\t\t\tif($param['cssurl'])\n\t\t\t\t\t\t$url .= '/'. self::Qiniu_Encode($param['cssurl']);\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\t\t\treturn $url;\n\t\t}\n\n\t\tpublic function buildUrlParam(){\n\t\t\treturn $_REQUEST;\n\t\t}\n\n\t\t//获取某个路径下的文件列表\n\t\tpublic function getList($query = array(), $path = ''){\n\t\t\t$this->queryBucketHost();\n\t\t\t$query = array_merge(array('bucket'=>$this->bucket), $query);\n\t\t\t$url = \"{$this->QINIU_RSF_HOST}/list?\".http_build_query($query);\n\t\t\t$accessToken = $this->accessToken($url);\n\t\t\t$response = $this->request($url, 'POST', array('Authorization'=>\"QBox $accessToken\"));\n\t\t\treturn $response;\n\t\t}\n\n\t\t//获取某个文件的信息\n\t\tpublic function info($key){\n\t\t\t$this->queryBucketHost();\n\t\t\t$key = trim($key);\n\t\t\t$url = \"{$this->QINIU_RS_HOST}/stat/\" . self::Qiniu_Encode(\"{$this->bucket}:{$key}\");\n\t\t\t$accessToken = $this->accessToken($url);\n\t\t\t$response = $this->request($url, 'POST', array(\n\t\t\t\t'Authorization'=>\"QBox $accessToken\",\n\t\t\t));\n\t\t\treturn $response;\n\t\t}\n\n\t\t//获取文件下载资源链接\n\t\tpublic function downLink($key){\n\t\t\t$key = urlencode($key);\n\t\t\t$key = self::Qiniu_escapeQuotes($key);\n\t\t\t$url = \"{$this->protocol}://{$this->domain}/{$key}\";\n\t\t\treturn $url;\n\t\t}\n\n\t\t//重命名单个文件\n\t\tpublic function rename($file, $new_file){\n\t\t\t$this->queryBucketHost();\n\t\t\t$key = trim($file);\n\t\t\t$url = \"{$this->QINIU_RS_HOST}/move/\" . self::Qiniu_Encode(\"{$this->bucket}:{$key}\") .'/'. self::Qiniu_Encode(\"{$this->bucket}:{$new_file}\");\n\t\t\ttrace($url);\n\t\t\t$accessToken = $this->accessToken($url);\n\t\t\t$response = $this->request($url, 'POST', array('Authorization'=>\"QBox $accessToken\"));\n\t\t\treturn $response;\n\t\t}\n\n\t\t//删除单个文件\n\t\tpublic function del($file){\n\t\t\t$this->queryBucketHost();\n\t\t\t$key = trim($file);\n\t\t\t$url = \"{$this->QINIU_RS_HOST}/delete/\" . self::Qiniu_Encode(\"{$this->bucket}:{$key}\");\n\t\t\t$accessToken = $this->accessToken($url);\n\t\t\t$response = $this->request($url, 'POST', array('Authorization'=>\"QBox $accessToken\"));\n\t\t\treturn $response;\n\t\t}\n\n\t\t//批量删除文件\n\t\tpublic function delBatch($files){\n\t\t\t$this->queryBucketHost();\n\t\t\t$url = $this->QINIU_RS_HOST . '/batch';\n\t\t\t$ops = array();\n\t\t\tforeach ($files as $file) {\n\t\t\t\t$ops[] = \"/delete/\". self::Qiniu_Encode(\"{$this->bucket}:{$file}\");\n\t\t\t}\n\t\t\t$params = 'op=' . implode('&op=', $ops);\n\t\t\t$url .= '?'.$params;\n\t\t\ttrace($url);\n\t\t\t$accessToken = $this->accessToken($url);\n\t\t\t$response = $this->request($url, 'POST', array('Authorization'=>\"QBox $accessToken\"));\n\t\t\treturn $response;\n\t\t}\n\n\t\tstatic function Qiniu_Encode($str) {// URLSafeBase64Encode\n\t\t\t$find = array('+', '/');\n\t\t\t$replace = array('-', '_');\n\t\t\treturn str_replace($find, $replace, base64_encode($str));\n\t\t}\n\n\t\tstatic function Qiniu_escapeQuotes($str){\n\t\t\t$find = array(\"\\\\\", \"\\\"\");\n\t\t\t$replace = array(\"\\\\\\\\\", \"\\\\\\\"\");\n\t\t\treturn str_replace($find, $replace, $str);\n\t\t}\n\n\t    /**\n\t     * 请求百度云服务器\n\t     * @param  string   $path    请求的PATH\n\t     * @param  string   $method  请求方法\n\t     * @param  array    $headers 请求header\n\t     * @param  resource $body    上传文件资源\n\t     * @return boolean\n\t     */\n\t    private function request($path, $method, $headers = null, $body = null){\n\t        $ch  = curl_init($path);\n\n\t        $_headers = array('Expect:');\n\t        if (!is_null($headers) && is_array($headers)){\n\t            foreach($headers as $k => $v) {\n\t                array_push($_headers, \"{$k}: {$v}\");\n\t            }\n\t        }\n\n\t        $length = 0;\n\t\t\t$date   = gmdate('D, d M Y H:i:s \\G\\M\\T');\n\n\t        if (!is_null($body)) {\n\t            if(is_resource($body)){\n\t                fseek($body, 0, SEEK_END);\n\t                $length = ftell($body);\n\t                fseek($body, 0);\n\n\t                array_push($_headers, \"Content-Length: {$length}\");\n\t                curl_setopt($ch, CURLOPT_INFILE, $body);\n\t                curl_setopt($ch, CURLOPT_INFILESIZE, $length);\n\t            } else {\n\t                $length = @strlen($body);\n\t                array_push($_headers, \"Content-Length: {$length}\");\n\t                curl_setopt($ch, CURLOPT_POSTFIELDS, $body);\n\t            }\n\t        } else {\n\t            array_push($_headers, \"Content-Length: {$length}\");\n\t        }\n\n\t        // array_push($_headers, 'Authorization: ' . $this->sign($method, $uri, $date, $length));\n\t        array_push($_headers, \"Date: {$date}\");\n\n\t        curl_setopt($ch, CURLOPT_HTTPHEADER, $_headers);\n\t        curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout);\n\t        curl_setopt($ch, CURLOPT_HEADER, 1);\n\t        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);\n\t        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0);\n\t\t\tcurl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);\n\n\t        if ($method == 'PUT' || $method == 'POST') {\n\t\t\t\tcurl_setopt($ch, CURLOPT_POST, 1);\n\t        } else {\n\t\t\t\tcurl_setopt($ch, CURLOPT_POST, 0);\n\t        }\n\n\t        if ($method == 'HEAD') {\n\t            curl_setopt($ch, CURLOPT_NOBODY, true);\n\t        }\n\n\t        $response = curl_exec($ch);\n\t        $status   = curl_getinfo($ch, CURLINFO_HTTP_CODE);\n\t        curl_close($ch);\n\t        list($header, $body) = explode(\"\\r\\n\\r\\n\", $response, 2);\n\t        if ($status == 200) {\n\t            if ($method == 'GET') {\n\t                return $body;\n\t            } else {\n\t                return $this->response($response);\n\t            }\n\t        } else {\n\t            $this->error($header , $body);\n\t            return false;\n\t        }\n\t    }\n\n        /**\n\t     * 获取响应数据\n\t     * @param  string $text 响应头字符串\n\t     * @return array        响应数据列表\n\t     */\n\t    private function response($text){\n\t        $headers = explode(PHP_EOL, $text);\n\t        $items = array();\n\t        foreach($headers as $header) {\n\t            $header = trim($header);\n\t            if(strpos($header, '{') !== False){\n\t                $items = json_decode($header, 1);\n\t                break;\n\t            }\n\t        }\n\t        return $items;\n\t    }\n\n        /**\n\t     * 获取请求错误信息\n\t     * @param  string $header 请求返回头信息\n\t     */\n\t\tprivate function error($header, $body) {\n\t        list($status, $stash) = explode(\"\\r\\n\", $header, 2);\n\t        list($v, $code, $message) = explode(\" \", $status, 3);\n\t        $message = is_null($message) ? 'File Not Found' : \"[{$status}]:{$message}]\";\n\t        $this->error = $message;\n\t        $this->errorStr = json_decode($body ,1);\n\t        $this->errorStr = $this->errorStr['error'];\n\t    }\n\n\t\tpublic function privateDownloadUrl($baseUrl, $expires = 3600)\n\t\t{\n\t\t    $deadline = time() + $expires;\n\t\t    $pos = strpos($baseUrl, '?');\n\t\t    if ($pos !== false) {\n\t\t        $baseUrl .= '&e=';\n\t\t    } else {\n\t\t        $baseUrl .= '?e=';\n\t\t    }\n\t\t    $baseUrl .= $deadline;\n\t\t    $token = $this->sign($this->sk, $this->ak,$baseUrl);\n\t\t    return \"$baseUrl&token=$token\";\n\t\t}\n\n\t    //根据bucket获取地域host信息\n\t    private function queryBucketHost(){\n\t    \tif ($this->hasHost > 0) {\n\t    \t\treturn ;\n\t    \t}\n\t    \t$url = \"https://api.qiniu.com/v2/query?ak={$this->ak}&bucket={$this->bucket}\";\n\t    \t$res = json_decode( $this->request($url,'GET') , 1 ) ;\n\t    \tif ($res && $res['up'] && $res['up']['acc']['main']) {\n\t\t\t\t$this->QINIU_RSF_HOST = 'https://'.$res['rsf']['acc']['main'][0];\n\t\t\t\t$this->QINIU_RS_HOST = 'https://'.$res['rs']['acc']['main'][0];\n\t\t\t\t$this->QINIU_UP_HOST = 'https://'.$res['up']['acc']['main'][0];\n\t\t\t\t$this->hasHost = 1 ;\n\t    \t}\n\t    }\n\t}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Upload/Driver/Qiniu.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: yangweijie <yangweijiester@gmail.com> <http://www.code-tech.diandian.com>\n// +----------------------------------------------------------------------\n\nnamespace Think\\Upload\\Driver;\nuse Think\\Upload\\Driver\\Qiniu\\QiniuStorage;\n\nclass Qiniu{\n    /**\n     * 上传文件根目录\n     * @var string\n     */\n    private $rootPath;\n\n    /**\n     * 上传错误信息\n     * @var string\n     */\n    private $error = '';\n\n    private $config = array(\n        'secrectKey'     => '', //七牛服务器\n        'accessKey'      => '', //七牛用户\n        'domain'         => '', //七牛密码\n        'bucket'         => '', //空间名称\n        'timeout'        => 300, //超时时间\n    );\n\n    /**\n     * 构造函数，用于设置上传根路径\n     * @param array  $config FTP配置\n     */\n    public function __construct($config){\n        $this->config = array_merge($this->config, $config);\n        /* 设置根目录 */\n        $this->qiniu = new QiniuStorage($config);\n    }\n\n    /**\n     * 检测上传根目录(七牛上传时支持自动创建目录，直接返回)\n     * @param string $rootpath   根目录\n     * @return boolean true-检测通过，false-检测失败\n     */\n    public function checkRootPath($rootpath){\n        $this->rootPath = trim($rootpath, './') . '/';\n        return true;\n    }\n\n    /**\n     * 检测上传目录(七牛上传时支持自动创建目录，直接返回)\n     * @param  string $savepath 上传目录\n     * @return boolean          检测结果，true-通过，false-失败\n     */\n    public function checkSavePath($savepath){\n        return true;\n    }\n\n    /**\n     * 创建文件夹 (七牛上传时支持自动创建目录，直接返回)\n     * @param  string $savepath 目录名称\n     * @return boolean          true-创建成功，false-创建失败\n     */\n    public function mkdir($savepath){\n        return true;\n    }\n\n    /**\n     * 保存指定文件\n     * @param  array   $file    保存的文件信息\n     * @param  boolean $replace 同名文件是否覆盖\n     * @return boolean          保存状态，true-成功，false-失败\n     */\n    public function save(&$file,$replace=true) {\n        $file['name'] = $file['savepath'] . $file['savename'];\n        $key = str_replace('/', '_', $file['name']);\n        $upfile = array(\n            'name'=>'file',\n            'fileName'=>$key,\n            'fileBody'=>file_get_contents($file['tmp_name'])\n        );\n        $config = array();\n        $result = $this->qiniu->upload($config, $upfile);\n        $url = $this->qiniu->downlink($key);\n        $file['url'] = $url;\n        return false ===$result ? false : true;\n    }\n\n    /**\n     * 获取最后一次上传错误信息\n     * @return string 错误信息\n     */\n    public function getError(){\n        return $this->qiniu->errorStr;\n    }\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Upload/Driver/Sae.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: luofei614<weibo.com/luofei614>\n// +----------------------------------------------------------------------\n\nnamespace Think\\Upload\\Driver;\nclass Sae{\n    /**\n     * Storage的Domain\n     * @var string\n     */\n    private $domain     =   '';\n\n    private $rootPath   =   '';\n\n    /**\n     * 本地上传错误信息\n     * @var string\n     */\n    private $error      =   ''; \n\n    /**\n     * 构造函数，设置storage的domain， 如果有传配置，则domain为配置项，如果没有传domain为第一个路径的目录名称。 \n     * @param mixed $config 上传配置     \n     */\n    public function __construct($config = null){\n        if(is_array($config) && !empty($config['domain'])){\n            $this->domain   =   strtolower($config['domain']);\n        }\n    }\n\n    /**\n     * 检测上传根目录\n     * @param string $rootpath   根目录\n     * @return boolean true-检测通过，false-检测失败\n     */\n    public function checkRootPath($rootpath){\n        $rootpath = trim($rootpath,'./');\n        if(!$this->domain){\n            $rootpath = explode('/', $rootpath);\n            $this->domain = strtolower(array_shift($rootpath));\n            $rootpath = implode('/', $rootpath);\n        }\n\n        $this->rootPath =  $rootpath;\n        $st =   new \\SaeStorage();\n        if(false===$st->getDomainCapacity($this->domain)){\n          $this->error  =   '您好像没有建立Storage的domain['.$this->domain.']';\n          return false;\n        }\n        return true;\n    }\n\n    /**\n     * 检测上传目录\n     * @param  string $savepath 上传目录\n     * @return boolean          检测结果，true-通过，false-失败\n     */\n    public function checkSavePath($savepath){\n        return true;\n    }\n\n    /**\n     * 保存指定文件\n     * @param  array   $file    保存的文件信息\n     * @param  boolean $replace 同名文件是否覆盖\n     * @return boolean          保存状态，true-成功，false-失败\n     */\n    public function save(&$file, $replace=true) {\n        $filename = ltrim($this->rootPath .'/'. $file['savepath'] . $file['savename'],'/');\n        $st =   new \\SaeStorage();\n        /* 不覆盖同名文件 */ \n        if (!$replace && $st->fileExists($this->domain,$filename)) {\n            $this->error = '存在同名文件' . $file['savename'];\n            return false;\n        }\n\n        /* 移动文件 */\n        if (!$st->upload($this->domain,$filename,$file['tmp_name'])) {\n            $this->error = '文件上传保存错误！['.$st->errno().']:'.$st->errmsg();\n            return false;\n        }else{\n            $file['url'] = $st->getUrl($this->domain, $filename);\n        }\n        return true;\n    }\n\n    public function mkdir(){\n        return true;\n    }\n\n    /**\n     * 获取最后一次上传错误信息\n     * @return string 错误信息\n     */\n    public function getError(){\n        return $this->error;\n    }\n\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Upload/Driver/Upyun.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: 麦当苗儿 <zuojiazi@vip.qq.com> <http://www.zjzit.cn>\n// +----------------------------------------------------------------------\n\nnamespace Think\\Upload\\Driver;\nclass Upyun{\n    /**\n     * 上传文件根目录\n     * @var string\n     */\n    private $rootPath;\n\n    /**\n     * 上传错误信息\n     * @var string\n     */\n    private $error = '';\n\n    private $config = array(\n        'host'     => '', //又拍云服务器\n        'username' => '', //又拍云用户\n        'password' => '', //又拍云密码\n        'bucket'   => '', //空间名称\n        'timeout'  => 90, //超时时间\n    );\n\n    /**\n     * 构造函数，用于设置上传根路径\n     * @param array  $config FTP配置\n     */\n    public function __construct($config){\n        /* 默认FTP配置 */\n        $this->config = array_merge($this->config, $config);\n        $this->config['password'] = md5($this->config['password']);\n    }\n\n    /**\n     * 检测上传根目录(又拍云上传时支持自动创建目录，直接返回)\n     * @param string $rootpath   根目录\n     * @return boolean true-检测通过，false-检测失败\n     */\n    public function checkRootPath($rootpath){\n        /* 设置根目录 */\n        $this->rootPath = trim($rootpath, './') . '/';\n        return true;\n    }\n\n    /**\n     * 检测上传目录(又拍云上传时支持自动创建目录，直接返回)\n     * @param  string $savepath 上传目录\n     * @return boolean          检测结果，true-通过，false-失败\n     */\n    public function checkSavePath($savepath){\n        return true;\n    }\n\n    /**\n     * 创建文件夹 (又拍云上传时支持自动创建目录，直接返回)\n     * @param  string $savepath 目录名称\n     * @return boolean          true-创建成功，false-创建失败\n     */\n    public function mkdir($savepath){\n        return true;\n    }\n\n    /**\n     * 保存指定文件\n     * @param  array   $file    保存的文件信息\n     * @param  boolean $replace 同名文件是否覆盖\n     * @return boolean          保存状态，true-成功，false-失败\n     */\n    public function save($file, $replace = true) {\n        $header['Content-Type'] = $file['type'];\n        $header['Content-MD5'] \t= $file['md5'];\n        $header['Mkdir'] = 'true';\n        $resource = fopen($file['tmp_name'], 'r');\n\n        $save = $this->rootPath . $file['savepath'] . $file['savename'];\n        $data = $this->request($save, 'PUT', $header, $resource);\n        return false === $data ? false : true;\n    }\n\n    /**\n     * 获取最后一次上传错误信息\n     * @return string 错误信息\n     */\n    public function getError(){\n        return $this->error;\n    }\n\n    /**\n     * 请求又拍云服务器\n     * @param  string   $path    请求的PATH\n     * @param  string   $method  请求方法\n     * @param  array    $headers 请求header\n     * @param  resource $body    上传文件资源\n     * @return boolean\n     */\n    private function request($path, $method, $headers = null, $body = null){\n        $uri = \"/{$this->config['bucket']}/{$path}\";\n        $ch  = curl_init($this->config['host'] . $uri);\n\n        $_headers = array('Expect:');\n        if (!is_null($headers) && is_array($headers)){\n            foreach($headers as $k => $v) {\n                array_push($_headers, \"{$k}: {$v}\");\n            }\n        }\n\n        $length = 0;\n        $date   = gmdate('D, d M Y H:i:s \\G\\M\\T');\n\n        if (!is_null($body)) {\n            if(is_resource($body)){\n                fseek($body, 0, SEEK_END);\n                $length = ftell($body);\n                fseek($body, 0);\n\n                array_push($_headers, \"Content-Length: {$length}\");\n                curl_setopt($ch, CURLOPT_INFILE, $body);\n                curl_setopt($ch, CURLOPT_INFILESIZE, $length);\n            } else {\n                $length = @strlen($body);\n                array_push($_headers, \"Content-Length: {$length}\");\n                curl_setopt($ch, CURLOPT_POSTFIELDS, $body);\n            }\n        } else {\n            array_push($_headers, \"Content-Length: {$length}\");\n        }\n\n        array_push($_headers, 'Authorization: ' . $this->sign($method, $uri, $date, $length));\n        array_push($_headers, \"Date: {$date}\");\n\n        curl_setopt($ch, CURLOPT_HTTPHEADER, $_headers);\n        curl_setopt($ch, CURLOPT_TIMEOUT, $this->config['timeout']);\n        curl_setopt($ch, CURLOPT_HEADER, 1);\n        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);\n        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0);\n        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);\n\n        if ($method == 'PUT' || $method == 'POST') {\n            curl_setopt($ch, CURLOPT_POST, 1);\n        } else {\n            curl_setopt($ch, CURLOPT_POST, 0);\n        }\n\n        if ($method == 'HEAD') {\n            curl_setopt($ch, CURLOPT_NOBODY, true);\n        }\n\n        $response = curl_exec($ch);\n        $status   = curl_getinfo($ch, CURLINFO_HTTP_CODE);\n        curl_close($ch);\n        list($header, $body) = explode(\"\\r\\n\\r\\n\", $response, 2);\n\n        if ($status == 200) {\n            if ($method == 'GET') {\n                return $body;\n            } else {\n                $data = $this->response($header);\n                return count($data) > 0 ? $data : true;\n            }\n        } else {\n            $this->error($header);\n            return false;\n        }\n    }\n\n    /**\n     * 获取响应数据\n     * @param  string $text 响应头字符串\n     * @return array        响应数据列表\n     */\n    private function response($text){\n        $headers = explode(\"\\r\\n\", $text);\n        $items = array();\n        foreach($headers as $header) {\n            $header = trim($header);\n            if(strpos($header, 'x-upyun') !== False){\n                list($k, $v) = explode(':', $header);\n                $items[trim($k)] = in_array(substr($k,8,5), array('width','heigh','frame')) ? intval($v) : trim($v);\n            }\n        }\n        return $items;\n    }\n\n    /**\n     * 生成请求签名\n     * @param  string  $method 请求方法\n     * @param  string  $uri    请求URI\n     * @param  string  $date   请求时间\n     * @param  integer $length 请求内容大小\n     * @return string          请求签名\n     */\n    private function sign($method, $uri, $date, $length){\n        $sign = \"{$method}&{$uri}&{$date}&{$length}&{$this->config['password']}\";\n        return 'UpYun ' . $this->config['username'] . ':' . md5($sign);\n    }\n\n    /**\n     * 获取请求错误信息\n     * @param  string $header 请求返回头信息\n     */\n    private function error($header) {\n        list($status, $stash) = explode(\"\\r\\n\", $header, 2);\n        list($v, $code, $message) = explode(\" \", $status, 3);\n        $message = is_null($message) ? 'File Not Found' : \"[{$status}]:{$message}\";\n        $this->error = $message;\n    }\n\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Think/Upload.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: 麦当苗儿 <zuojiazi@vip.qq.com> <http://www.zjzit.cn>\n// +----------------------------------------------------------------------\nnamespace Think;\nclass Upload {\n    /**\n     * 默认上传配置\n     * @var array\n     */\n    private $config = array(\n        'mimes'         =>  array(), //允许上传的文件MiMe类型\n        'maxSize'       =>  0, //上传的文件大小限制 (0-不做限制)\n        'exts'          =>  array(), //允许上传的文件后缀\n        'autoSub'       =>  true, //自动子目录保存文件\n        'subName'       =>  array('date', 'Y-m-d'), //子目录创建方式，[0]-函数名，[1]-参数，多个参数使用数组\n        'rootPath'      =>  './Uploads/', //保存根路径\n        'savePath'      =>  '', //保存路径\n        'saveName'      =>  array('uniqid', ''), //上传文件命名规则，[0]-函数名，[1]-参数，多个参数使用数组\n        'saveExt'       =>  '', //文件保存后缀，空则使用原后缀\n        'replace'       =>  false, //存在同名是否覆盖\n        'hash'          =>  true, //是否生成hash编码\n        'callback'      =>  false, //检测文件是否存在回调，如果存在返回文件信息数组\n        'driver'        =>  '', // 文件上传驱动\n        'driverConfig'  =>  array(), // 上传驱动配置\n    );\n\n    /**\n     * 上传错误信息\n     * @var string\n     */\n    private $error = ''; //上传错误信息\n\n    /**\n     * 上传驱动实例\n     * @var Object\n     */\n    private $uploader;\n\n    /**\n     * 构造方法，用于构造上传实例\n     * @param array  $config 配置\n     * @param string $driver 要使用的上传驱动 LOCAL-本地上传驱动，FTP-FTP上传驱动\n     */\n    public function __construct($config = array(), $driver = '', $driverConfig = null){\n        /* 获取配置 */\n        $this->config   =   array_merge($this->config, $config);\n\n        /* 设置上传驱动 */\n        $this->setDriver($driver, $driverConfig);\n\n        /* 调整配置，把字符串配置参数转换为数组 */\n        if(!empty($this->config['mimes'])){\n            if(is_string($this->mimes)) {\n                $this->config['mimes'] = explode(',', $this->mimes);\n            }\n            $this->config['mimes'] = array_map('strtolower', $this->mimes);\n        }\n        if(!empty($this->config['exts'])){\n            if (is_string($this->exts)){\n                $this->config['exts'] = explode(',', $this->exts);\n            }\n            $this->config['exts'] = array_map('strtolower', $this->exts);\n        }\n    }\n\n    /**\n     * 使用 $this->name 获取配置\n     * @param  string $name 配置名称\n     * @return multitype    配置值\n     */\n    public function __get($name) {\n        return $this->config[$name];\n    }\n\n    public function __set($name,$value){\n        if(isset($this->config[$name])) {\n            $this->config[$name] = $value;\n            if($name == 'driverConfig'){\n                //改变驱动配置后重置上传驱动\n                //注意：必须选改变驱动然后再改变驱动配置\n                $this->setDriver(); \n            }\n        }\n    }\n\n    public function __isset($name){\n        return isset($this->config[$name]);\n    }\n\n    /**\n     * 获取最后一次上传错误信息\n     * @return string 错误信息\n     */\n    public function getError(){\n        return $this->error;\n    }\n\n    /**\n     * 上传单个文件\n     * @param  array  $file 文件数组\n     * @return array        上传成功后的文件信息\n     */\n    public function uploadOne($file){\n        $info = $this->upload(array($file));\n        return $info ? $info[0] : $info;\n    }\n\n    /**\n     * 上传文件\n     * @param 文件信息数组 $files ，通常是 $_FILES数组\n     */\n    public function upload($files='') {\n        if('' === $files){\n            $files  =   $_FILES;\n        }\n        if(empty($files)){\n            $this->error = '没有上传的文件！';\n            return false;\n        }\n\n        /* 检测上传根目录 */\n        if(!$this->uploader->checkRootPath($this->rootPath)){\n            $this->error = $this->uploader->getError();\n            return false;\n        }\n\n        /* 检查上传目录 */\n        if(!$this->uploader->checkSavePath($this->savePath)){\n            $this->error = $this->uploader->getError();\n            return false;\n        }\n\n        /* 逐个检测并上传文件 */\n        $info    =  array();\n        if(function_exists('finfo_open')){\n            $finfo   =  finfo_open ( FILEINFO_MIME_TYPE );\n        }\n        // 对上传文件数组信息处理\n        $files   =  $this->dealFiles($files);    \n        foreach ($files as $key => $file) {\n            $file['name']  = strip_tags($file['name']);\n            if(!isset($file['key']))   $file['key']    =   $key;\n            /* 通过扩展获取文件类型，可解决FLASH上传$FILES数组返回文件类型错误的问题 */\n            if(isset($finfo)){\n                $file['type']   =   finfo_file ( $finfo ,  $file['tmp_name'] );\n            }\n\n            /* 获取上传文件后缀，允许上传无后缀文件 */\n            $file['ext']    =   pathinfo($file['name'], PATHINFO_EXTENSION);\n\n            /* 文件上传检测 */\n            if (!$this->check($file)){\n                continue;\n            }\n\n            /* 获取文件hash */\n            if($this->hash){\n                $file['md5']  = md5_file($file['tmp_name']);\n                $file['sha1'] = sha1_file($file['tmp_name']);\n            }\n\n            /* 调用回调函数检测文件是否存在 */\n            if($this->callback){\n                $data = call_user_func($this->callback, $file);\n            }else{\n                $data = false;\n            }\n            if( $this->callback && $data ){\n                if ( file_exists('.'.$data['path'])  ) {\n                    $info[$key] = $data;\n                    continue;\n                }elseif($this->removeTrash){\n                    call_user_func($this->removeTrash,$data);//删除垃圾据\n                }\n            }\n\n            /* 生成保存文件名 */\n            $savename = $this->getSaveName($file);\n            if(false == $savename){\n                continue;\n            } else {\n                $file['savename'] = $savename;\n            }\n\n            /* 检测并创建子目录 */\n            $subpath = $this->getSubPath($file['name']);\n            if(false === $subpath){\n                continue;\n            } else {\n                $file['savepath'] = $this->savePath . $subpath;\n            }\n\n            /* 对图像文件进行严格检测 */\n            $ext = strtolower($file['ext']);\n            if(in_array($ext, array('gif','jpg','jpeg','bmp','png','swf'))) {\n                $imginfo = getimagesize($file['tmp_name']);\n                if(empty($imginfo) || ($ext == 'gif' && empty($imginfo['bits']))){\n                    $this->error = '非法图像文件！';\n                    continue;\n                }\n            }\n\n            /* 保存文件 并记录保存成功的文件 */\n            if ($this->uploader->save($file,$this->replace)) {\n                unset($file['error'], $file['tmp_name']);\n                $info[$key] = $file;\n            } else {\n                $this->error = $this->uploader->getError();\n            }\n        }\n        if(isset($finfo)){\n            finfo_close($finfo);\n        }\n        return empty($info) ? false : $info;\n    }\n\n    /**\n     * 转换上传文件数组变量为正确的方式\n     * @access private\n     * @param array $files  上传的文件变量\n     * @return array\n     */\n    private function dealFiles($files) {\n        $fileArray  = array();\n        $n          = 0;\n        foreach ($files as $key=>$file){\n            if(is_array($file['name'])) {\n                $keys       =   array_keys($file);\n                $count      =   count($file['name']);\n                for ($i=0; $i<$count; $i++) {\n                    $fileArray[$n]['key'] = $key;\n                    foreach ($keys as $_key){\n                        $fileArray[$n][$_key] = $file[$_key][$i];\n                    }\n                    $n++;\n                }\n            }else{\n               $fileArray = $files;\n               break;\n            }\n        }\n       return $fileArray;\n    }\n\n    /**\n     * 设置上传驱动\n     * @param string $driver 驱动名称\n     * @param array $config 驱动配置     \n     */\n    private function setDriver($driver = null, $config = null){\n        $driver = $driver ? : ($this->driver       ? : C('FILE_UPLOAD_TYPE'));\n        $config = $config ? : ($this->driverConfig ? : C('UPLOAD_TYPE_CONFIG'));\n        $class = strpos($driver,'\\\\')? $driver : 'Think\\\\Upload\\\\Driver\\\\'.ucfirst(strtolower($driver));\n        $this->uploader = new $class($config);\n        if(!$this->uploader){\n            E(\"不存在上传驱动：{$name}\");\n        }\n    }\n\n    /**\n     * 检查上传的文件\n     * @param array $file 文件信息\n     */\n    private function check($file) {\n        /* 文件上传失败，捕获错误代码 */\n        if ($file['error']) {\n            $this->error($file['error']);\n            return false;\n        }\n\n        /* 无效上传 */\n        if (empty($file['name'])){\n            $this->error = '未知上传错误！';\n        }\n\n        /* 检查是否合法上传 */\n        if (!is_uploaded_file($file['tmp_name'])) {\n            $this->error = '非法上传文件！';\n            return false;\n        }\n\n        /* 检查文件大小 */\n        if (!$this->checkSize($file['size'])) {\n            $this->error = '上传文件大小不符！';\n            return false;\n        }\n\n        /* 检查文件Mime类型 */\n        //TODO:FLASH上传的文件获取到的mime类型都为application/octet-stream\n        if (!$this->checkMime($file['type'])) {\n            $this->error = '上传文件MIME类型不允许！';\n            return false;\n        }\n\n        /* 检查文件后缀 */\n        if (!$this->checkExt($file['ext'])) {\n            $this->error = '上传文件后缀不允许';\n            return false;\n        }\n\n        /* 通过检测 */\n        return true;\n    }\n\n\n    /**\n     * 获取错误代码信息\n     * @param string $errorNo  错误号\n     */\n    private function error($errorNo) {\n        switch ($errorNo) {\n            case 1:\n                $this->error = '上传的文件超过了 php.ini 中 upload_max_filesize 选项限制的值！';\n                break;\n            case 2:\n                $this->error = '上传文件的大小超过了 HTML 表单中 MAX_FILE_SIZE 选项指定的值！';\n                break;\n            case 3:\n                $this->error = '文件只有部分被上传！';\n                break;\n            case 4:\n                $this->error = '没有文件被上传！';\n                break;\n            case 6:\n                $this->error = '找不到临时文件夹！';\n                break;\n            case 7:\n                $this->error = '文件写入失败！';\n                break;\n            default:\n                $this->error = '未知上传错误！';\n        }\n    }\n\n    /**\n     * 检查文件大小是否合法\n     * @param integer $size 数据\n     */\n    private function checkSize($size) {\n        return !($size > $this->maxSize) || (0 == $this->maxSize);\n    }\n\n    /**\n     * 检查上传的文件MIME类型是否合法\n     * @param string $mime 数据\n     */\n    private function checkMime($mime) {\n        return empty($this->config['mimes']) ? true : in_array(strtolower($mime), $this->mimes);\n    }\n\n    /**\n     * 检查上传的文件后缀是否合法\n     * @param string $ext 后缀\n     */\n    private function checkExt($ext) {\n        return empty($this->config['exts']) ? true : in_array(strtolower($ext), $this->exts);\n    }\n\n    /**\n     * 根据上传文件命名规则取得保存文件名\n     * @param string $file 文件信息\n     */\n    private function getSaveName($file) {\n        $rule = $this->saveName;\n        if (empty($rule)) { //保持文件名不变\n            /* 解决pathinfo中文文件名BUG */\n            $filename = substr(pathinfo(\"_{$file['name']}\", PATHINFO_FILENAME), 1);\n            $savename = $filename;\n        } else {\n            $savename = $this->getName($rule, $file['name']);\n            if(empty($savename)){\n                $this->error = '文件命名规则错误！';\n                return false;\n            }\n        }\n\n        /* 文件保存后缀，支持强制更改文件后缀 */\n        $ext = empty($this->config['saveExt']) ? $file['ext'] : $this->saveExt;\n\n        return $savename . '.' . $ext;\n    }\n\n    /**\n     * 获取子目录的名称\n     * @param array $file  上传的文件信息\n     */\n    private function getSubPath($filename) {\n        $subpath = '';\n        $rule    = $this->subName;\n        if ($this->autoSub && !empty($rule)) {\n            $subpath = $this->getName($rule, $filename) . '/';\n\n            if(!empty($subpath) && !$this->uploader->mkdir($this->savePath . $subpath)){\n                $this->error = $this->uploader->getError();\n                return false;\n            }\n        }\n        return $subpath;\n    }\n\n    /**\n     * 根据指定的规则获取文件或目录名称\n     * @param  array  $rule     规则\n     * @param  string $filename 原文件名\n     * @return string           文件或目录名称\n     */\n    private function getName($rule, $filename){\n        $name = '';\n        if(is_array($rule)){ //数组规则\n            $func     = $rule[0];\n            $param    = (array)$rule[1];\n            foreach ($param as &$value) {\n               $value = str_replace('__FILE__', $filename, $value);\n            }\n            $name = call_user_func_array($func, $param);\n        } elseif (is_string($rule)){ //字符串规则\n            if(function_exists($rule)){\n                $name = call_user_func($rule);\n            } else {\n                $name = $rule;\n            }\n        }\n        return $name;\n    }\n\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Think/View.class.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\nnamespace Think;\n/**\n * ThinkPHP 视图类\n */\nclass View {\n    /**\n     * 模板输出变量\n     * @var tVar\n     * @access protected\n     */ \n    protected $tVar     =   array();\n\n    /**\n     * 模板主题\n     * @var theme\n     * @access protected\n     */ \n    protected $theme    =   '';\n\n    /**\n     * 模板变量赋值\n     * @access public\n     * @param mixed $name\n     * @param mixed $value\n     */\n    public function assign($name,$value=''){\n        if(is_array($name)) {\n            $this->tVar   =  array_merge($this->tVar,$name);\n        }else {\n            $this->tVar[$name] = $value;\n        }\n    }\n\n    /**\n     * 取得模板变量的值\n     * @access public\n     * @param string $name\n     * @return mixed\n     */\n    public function get($name=''){\n        if('' === $name) {\n            return $this->tVar;\n        }\n        return isset($this->tVar[$name])?$this->tVar[$name]:false;\n    }\n\n    /**\n     * 加载模板和页面输出 可以返回输出内容\n     * @access public\n     * @param string $templateFile 模板文件名\n     * @param string $charset 模板输出字符集\n     * @param string $contentType 输出类型\n     * @param string $content 模板输出内容\n     * @param string $prefix 模板缓存前缀\n     * @return mixed\n     */\n    public function display($templateFile='',$charset='',$contentType='',$content='',$prefix='') {\n        G('viewStartTime');\n        // 视图开始标签\n        Hook::listen('view_begin',$templateFile);\n        // 解析并获取模板内容\n        $content = $this->fetch($templateFile,$content,$prefix);\n        // 输出模板内容\n        $this->render($content,$charset,$contentType);\n        // 视图结束标签\n        Hook::listen('view_end');\n    }\n\n    /**\n     * 输出内容文本可以包括Html\n     * @access private\n     * @param string $content 输出内容\n     * @param string $charset 模板输出字符集\n     * @param string $contentType 输出类型\n     * @return mixed\n     */\n    private function render($content,$charset='',$contentType=''){\n        if(empty($charset))  $charset = C('DEFAULT_CHARSET');\n        if(empty($contentType)) $contentType = C('TMPL_CONTENT_TYPE');\n        // 网页字符编码\n        header('Content-Type:'.$contentType.'; charset='.$charset);\n        header('Cache-control: '.C('HTTP_CACHE_CONTROL'));  // 页面缓存控制\n        header('X-Powered-By:ThinkPHP');\n        // 输出模板文件\n        echo $content;\n    }\n\n    /**\n     * 解析和获取模板内容 用于输出\n     * @access public\n     * @param string $templateFile 模板文件名\n     * @param string $content 模板输出内容\n     * @param string $prefix 模板缓存前缀\n     * @return string\n     */\n    public function fetch($templateFile='',$content='',$prefix='') {\n        if(empty($content)) {\n            $templateFile   =   $this->parseTemplate($templateFile);\n            // 模板文件不存在直接返回\n            if(!is_file($templateFile)) E(L('_TEMPLATE_NOT_EXIST_').':'.$templateFile);\n        }else{\n            defined('THEME_PATH') or    define('THEME_PATH', $this->getThemePath());\n        }\n        // 页面缓存\n        ob_start();\n        ob_implicit_flush(0);\n        if('php' == strtolower(C('TMPL_ENGINE_TYPE'))) { // 使用PHP原生模板\n            $_content   =   $content;\n            // 模板阵列变量分解成为独立变量\n            extract($this->tVar, EXTR_OVERWRITE);\n            // 直接载入PHP模板\n            empty($_content)?include $templateFile:eval('?>'.$_content);\n        }else{\n            // 视图解析标签\n            $params = array('var'=>$this->tVar,'file'=>$templateFile,'content'=>$content,'prefix'=>$prefix);\n            Hook::listen('view_parse',$params);\n        }\n        // 获取并清空缓存\n        $content = ob_get_clean();\n        // 内容过滤标签\n        Hook::listen('view_filter',$content);\n        // 输出模板文件\n        return $content;\n    }\n\n    /**\n     * 自动定位模板文件\n     * @access protected\n     * @param string $template 模板文件规则\n     * @return string\n     */\n    public function parseTemplate($template='') {\n        if(is_file($template)) {\n            return $template;\n        }\n        $depr       =   C('TMPL_FILE_DEPR');\n        $template   =   str_replace(':', $depr, $template);\n\n        // 获取当前模块\n        $module   =  MODULE_NAME;\n        if(strpos($template,'@')){ // 跨模块调用模版文件\n            list($module,$template)  =   explode('@',$template);\n        }\n        // 获取当前主题的模版路径\n        defined('THEME_PATH') or    define('THEME_PATH', $this->getThemePath($module));\n\n        // 分析模板文件规则\n        if('' == $template) {\n            // 如果模板文件名为空 按照默认规则定位\n            $template = CONTROLLER_NAME . $depr . ACTION_NAME;\n        }elseif(false === strpos($template, $depr)){\n            $template = CONTROLLER_NAME . $depr . $template;\n        }\n        $file   =   THEME_PATH.$template.C('TMPL_TEMPLATE_SUFFIX');\n        if(C('TMPL_LOAD_DEFAULTTHEME') && THEME_NAME != C('DEFAULT_THEME') && !is_file($file)){\n            // 找不到当前主题模板的时候定位默认主题中的模板\n            $file   =   dirname(THEME_PATH).'/'.C('DEFAULT_THEME').'/'.$template.C('TMPL_TEMPLATE_SUFFIX');\n        }\n        return $file;\n    }\n\n    /**\n     * 获取当前的模板路径\n     * @access protected\n     * @param  string $module 模块名\n     * @return string\n     */\n    protected function getThemePath($module=MODULE_NAME){\n        // 获取当前主题名称\n        $theme = $this->getTemplateTheme();\n        // 获取当前主题的模版路径\n        $tmplPath   =   C('VIEW_PATH'); // 模块设置独立的视图目录\n        if(!$tmplPath){ \n            // 定义TMPL_PATH 则改变全局的视图目录到模块之外\n            $tmplPath   =   defined('TMPL_PATH')? TMPL_PATH.$module.'/' : APP_PATH.$module.'/'.C('DEFAULT_V_LAYER').'/';\n        }\n        return $tmplPath.$theme;\n    }\n\n    /**\n     * 设置当前输出的模板主题\n     * @access public\n     * @param  mixed $theme 主题名称\n     * @return View\n     */\n    public function theme($theme){\n        $this->theme = $theme;\n        return $this;\n    }\n\n    /**\n     * 获取当前的模板主题\n     * @access private\n     * @return string\n     */\n    private function getTemplateTheme() {\n        if($this->theme) { // 指定模板主题\n            $theme = $this->theme;\n        }else{\n            /* 获取模板主题名称 */\n            $theme =  C('DEFAULT_THEME');\n            if(C('TMPL_DETECT_THEME')) {// 自动侦测模板主题\n                $t = C('VAR_TEMPLATE');\n                if (isset($_GET[$t])){\n                    $theme = $_GET[$t];\n                }elseif(cookie('think_template')){\n                    $theme = cookie('think_template');\n                }\n                if(!in_array($theme,explode(',',C('THEME_LIST')))){\n                    $theme =  C('DEFAULT_THEME');\n                }\n                cookie('think_template',$theme,864000);\n            }\n        }\n        defined('THEME_NAME') || define('THEME_NAME',   $theme);                  // 当前模板主题名称\n        return $theme?$theme . '/':'';\n    }\n\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/autoload.php",
    "content": "<?php\n\nfunction classLoader($class)\n{\n    $path = str_replace('\\\\', DIRECTORY_SEPARATOR, $class);\n    $file = __DIR__ . DIRECTORY_SEPARATOR .'src'. DIRECTORY_SEPARATOR . $path . '.php';\n    if (file_exists($file)) {\n        require_once $file;\n    }\n}\nspl_autoload_register('classLoader');"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/build-phar.sh",
    "content": "#! /usr/bin/env bash\n\n# Remove dev deps to reduce phar size\nrm -rf composer.lock vendor/\n\n# Generate composer.lock\ncomposer install --no-dev\n\n# Find SDK version\nversion=$(grep 'const OSS_VERSION' src/OSS/OssClient.php | grep -oE '[0-9.]+')\n\n# Build phar\nphar-composer build . aliyun-oss-php-sdk-$version.phar\n"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/composer.json",
    "content": "{\n    \"name\": \"aliyuncs/oss-sdk-php\",\n    \"description\": \"Aliyun OSS SDK for PHP\",\n    \"homepage\": \"http://www.aliyun.com/product/oss/\",\n    \"type\": \"library\",\n    \"license\": \"MIT\",\n    \"authors\": [\n        {\n            \"name\": \"Aliyuncs\",\n            \"homepage\": \"http://www.aliyun.com\"\n        }\n    ],\n    \"require\": {\n        \"php\":\">=5.3\"\n    },\n    \"require-dev\" : {\n        \"phpunit/phpunit\": \"~4.0\",\n        \"satooshi/php-coveralls\": \"~1.0\"\n    },\n    \"minimum-stability\": \"stable\",\n    \"autoload\": {\n        \"psr-4\": {\"OSS\\\\\": \"src/OSS\"}\n    }\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/index.php",
    "content": "<?php\n\nrequire_once __DIR__ . '/vendor/autoload.php';\n"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Core/MimeTypes.php",
    "content": "<?php\n\nnamespace OSS\\Core;\n\n/**\n * Class MimeTypes\n *\n * The map of a file's extention name to its corresponding Content-Type value in the file upload request.\n * If the file extention name is not predefined in this class, getMimetype() returns null.\n *\n * @package OSS\\Core\n */\nclass MimeTypes\n{\n    /**\n     * Get the content-type value of http header from the file's extension name.\n     *\n     * @param string $name Default file extension name.\n     * @return string content-type\n     */\n    public static function getMimetype($name)\n    {\n        $parts = explode('.', $name);\n        if (count($parts) > 1) {\n            $ext = strtolower(end($parts));\n            if (isset(self::$mime_types[$ext])) {\n                return self::$mime_types[$ext];\n            }\n        }\n\n        return null;\n    }\n\n    private static $mime_types = array(\n        'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n        'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',\n        'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',\n        'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',\n        'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',\n        'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide',\n        'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n        'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',\n        'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12',\n        'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',\n        'apk' => 'application/vnd.android.package-archive',\n        'hqx' => 'application/mac-binhex40',\n        'cpt' => 'application/mac-compactpro',\n        'doc' => 'application/msword',\n        'ogg' => 'audio/ogg',\n        'pdf' => 'application/pdf',\n        'rtf' => 'text/rtf',\n        'mif' => 'application/vnd.mif',\n        'xls' => 'application/vnd.ms-excel',\n        'ppt' => 'application/vnd.ms-powerpoint',\n        'odc' => 'application/vnd.oasis.opendocument.chart',\n        'odb' => 'application/vnd.oasis.opendocument.database',\n        'odf' => 'application/vnd.oasis.opendocument.formula',\n        'odg' => 'application/vnd.oasis.opendocument.graphics',\n        'otg' => 'application/vnd.oasis.opendocument.graphics-template',\n        'odi' => 'application/vnd.oasis.opendocument.image',\n        'odp' => 'application/vnd.oasis.opendocument.presentation',\n        'otp' => 'application/vnd.oasis.opendocument.presentation-template',\n        'ods' => 'application/vnd.oasis.opendocument.spreadsheet',\n        'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template',\n        'odt' => 'application/vnd.oasis.opendocument.text',\n        'odm' => 'application/vnd.oasis.opendocument.text-master',\n        'ott' => 'application/vnd.oasis.opendocument.text-template',\n        'oth' => 'application/vnd.oasis.opendocument.text-web',\n        'sxw' => 'application/vnd.sun.xml.writer',\n        'stw' => 'application/vnd.sun.xml.writer.template',\n        'sxc' => 'application/vnd.sun.xml.calc',\n        'stc' => 'application/vnd.sun.xml.calc.template',\n        'sxd' => 'application/vnd.sun.xml.draw',\n        'std' => 'application/vnd.sun.xml.draw.template',\n        'sxi' => 'application/vnd.sun.xml.impress',\n        'sti' => 'application/vnd.sun.xml.impress.template',\n        'sxg' => 'application/vnd.sun.xml.writer.global',\n        'sxm' => 'application/vnd.sun.xml.math',\n        'sis' => 'application/vnd.symbian.install',\n        'wbxml' => 'application/vnd.wap.wbxml',\n        'wmlc' => 'application/vnd.wap.wmlc',\n        'wmlsc' => 'application/vnd.wap.wmlscriptc',\n        'bcpio' => 'application/x-bcpio',\n        'torrent' => 'application/x-bittorrent',\n        'bz2' => 'application/x-bzip2',\n        'vcd' => 'application/x-cdlink',\n        'pgn' => 'application/x-chess-pgn',\n        'cpio' => 'application/x-cpio',\n        'csh' => 'application/x-csh',\n        'dvi' => 'application/x-dvi',\n        'spl' => 'application/x-futuresplash',\n        'gtar' => 'application/x-gtar',\n        'hdf' => 'application/x-hdf',\n        'jar' => 'application/java-archive',\n        'jnlp' => 'application/x-java-jnlp-file',\n        'js' => 'application/javascript',\n        'json' => 'application/json',\n        'ksp' => 'application/x-kspread',\n        'chrt' => 'application/x-kchart',\n        'kil' => 'application/x-killustrator',\n        'latex' => 'application/x-latex',\n        'rpm' => 'application/x-rpm',\n        'sh' => 'application/x-sh',\n        'shar' => 'application/x-shar',\n        'swf' => 'application/x-shockwave-flash',\n        'sit' => 'application/x-stuffit',\n        'sv4cpio' => 'application/x-sv4cpio',\n        'sv4crc' => 'application/x-sv4crc',\n        'tar' => 'application/x-tar',\n        'tcl' => 'application/x-tcl',\n        'tex' => 'application/x-tex',\n        'man' => 'application/x-troff-man',\n        'me' => 'application/x-troff-me',\n        'ms' => 'application/x-troff-ms',\n        'ustar' => 'application/x-ustar',\n        'src' => 'application/x-wais-source',\n        'zip' => 'application/zip',\n        'm3u' => 'audio/x-mpegurl',\n        'ra' => 'audio/x-pn-realaudio',\n        'wav' => 'audio/x-wav',\n        'wma' => 'audio/x-ms-wma',\n        'wax' => 'audio/x-ms-wax',\n        'pdb' => 'chemical/x-pdb',\n        'xyz' => 'chemical/x-xyz',\n        'bmp' => 'image/bmp',\n        'gif' => 'image/gif',\n        'ief' => 'image/ief',\n        'png' => 'image/png',\n        'wbmp' => 'image/vnd.wap.wbmp',\n        'ras' => 'image/x-cmu-raster',\n        'pnm' => 'image/x-portable-anymap',\n        'pbm' => 'image/x-portable-bitmap',\n        'pgm' => 'image/x-portable-graymap',\n        'ppm' => 'image/x-portable-pixmap',\n        'rgb' => 'image/x-rgb',\n        'xbm' => 'image/x-xbitmap',\n        'xpm' => 'image/x-xpixmap',\n        'xwd' => 'image/x-xwindowdump',\n        'css' => 'text/css',\n        'rtx' => 'text/richtext',\n        'tsv' => 'text/tab-separated-values',\n        'jad' => 'text/vnd.sun.j2me.app-descriptor',\n        'wml' => 'text/vnd.wap.wml',\n        'wmls' => 'text/vnd.wap.wmlscript',\n        'etx' => 'text/x-setext',\n        'mxu' => 'video/vnd.mpegurl',\n        'flv' => 'video/x-flv',\n        'wm' => 'video/x-ms-wm',\n        'wmv' => 'video/x-ms-wmv',\n        'wmx' => 'video/x-ms-wmx',\n        'wvx' => 'video/x-ms-wvx',\n        'avi' => 'video/x-msvideo',\n        'movie' => 'video/x-sgi-movie',\n        'ice' => 'x-conference/x-cooltalk',\n        '3gp' => 'video/3gpp',\n        'ai' => 'application/postscript',\n        'aif' => 'audio/x-aiff',\n        'aifc' => 'audio/x-aiff',\n        'aiff' => 'audio/x-aiff',\n        'asc' => 'text/plain',\n        'atom' => 'application/atom+xml',\n        'au' => 'audio/basic',\n        'bin' => 'application/octet-stream',\n        'cdf' => 'application/x-netcdf',\n        'cgm' => 'image/cgm',\n        'class' => 'application/octet-stream',\n        'dcr' => 'application/x-director',\n        'dif' => 'video/x-dv',\n        'dir' => 'application/x-director',\n        'djv' => 'image/vnd.djvu',\n        'djvu' => 'image/vnd.djvu',\n        'dll' => 'application/octet-stream',\n        'dmg' => 'application/octet-stream',\n        'dms' => 'application/octet-stream',\n        'dtd' => 'application/xml-dtd',\n        'dv' => 'video/x-dv',\n        'dxr' => 'application/x-director',\n        'eps' => 'application/postscript',\n        'exe' => 'application/octet-stream',\n        'ez' => 'application/andrew-inset',\n        'gram' => 'application/srgs',\n        'grxml' => 'application/srgs+xml',\n        'gz' => 'application/x-gzip',\n        'htm' => 'text/html',\n        'html' => 'text/html',\n        'ico' => 'image/x-icon',\n        'ics' => 'text/calendar',\n        'ifb' => 'text/calendar',\n        'iges' => 'model/iges',\n        'igs' => 'model/iges',\n        'jp2' => 'image/jp2',\n        'jpe' => 'image/jpeg',\n        'jpeg' => 'image/jpeg',\n        'jpg' => 'image/jpeg',\n        'kar' => 'audio/midi',\n        'lha' => 'application/octet-stream',\n        'lzh' => 'application/octet-stream',\n        'm4a' => 'audio/mp4a-latm',\n        'm4p' => 'audio/mp4a-latm',\n        'm4u' => 'video/vnd.mpegurl',\n        'm4v' => 'video/x-m4v',\n        'mac' => 'image/x-macpaint',\n        'mathml' => 'application/mathml+xml',\n        'mesh' => 'model/mesh',\n        'mid' => 'audio/midi',\n        'midi' => 'audio/midi',\n        'mov' => 'video/quicktime',\n        'mp2' => 'audio/mpeg',\n        'mp3' => 'audio/mpeg',\n        'mp4' => 'video/mp4',\n        'mpe' => 'video/mpeg',\n        'mpeg' => 'video/mpeg',\n        'mpg' => 'video/mpeg',\n        'mpga' => 'audio/mpeg',\n        'msh' => 'model/mesh',\n        'nc' => 'application/x-netcdf',\n        'oda' => 'application/oda',\n        'ogv' => 'video/ogv',\n        'pct' => 'image/pict',\n        'pic' => 'image/pict',\n        'pict' => 'image/pict',\n        'pnt' => 'image/x-macpaint',\n        'pntg' => 'image/x-macpaint',\n        'ps' => 'application/postscript',\n        'qt' => 'video/quicktime',\n        'qti' => 'image/x-quicktime',\n        'qtif' => 'image/x-quicktime',\n        'ram' => 'audio/x-pn-realaudio',\n        'rdf' => 'application/rdf+xml',\n        'rm' => 'application/vnd.rn-realmedia',\n        'roff' => 'application/x-troff',\n        'sgm' => 'text/sgml',\n        'sgml' => 'text/sgml',\n        'silo' => 'model/mesh',\n        'skd' => 'application/x-koan',\n        'skm' => 'application/x-koan',\n        'skp' => 'application/x-koan',\n        'skt' => 'application/x-koan',\n        'smi' => 'application/smil',\n        'smil' => 'application/smil',\n        'snd' => 'audio/basic',\n        'so' => 'application/octet-stream',\n        'svg' => 'image/svg+xml',\n        't' => 'application/x-troff',\n        'texi' => 'application/x-texinfo',\n        'texinfo' => 'application/x-texinfo',\n        'tif' => 'image/tiff',\n        'tiff' => 'image/tiff',\n        'tr' => 'application/x-troff',\n        'txt' => 'text/plain',\n        'vrml' => 'model/vrml',\n        'vxml' => 'application/voicexml+xml',\n        'webm' => 'video/webm',\n        'webp' => 'image/webp',\n        'wrl' => 'model/vrml',\n        'xht' => 'application/xhtml+xml',\n        'xhtml' => 'application/xhtml+xml',\n        'xml' => 'application/xml',\n        'xsl' => 'application/xml',\n        'xslt' => 'application/xslt+xml',\n        'xul' => 'application/vnd.mozilla.xul+xml',\n    );\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Core/OssException.php",
    "content": "<?php\n\nnamespace OSS\\Core;\n\n/**\n * Class OssException\n *\n * This is the class that OSSClient is expected to thrown, which the caller needs to handle properly.\n * It has the OSS specific errors which is useful for troubleshooting.\n *\n * @package OSS\\Core\n */\nclass OssException extends \\Exception\n{\n    private $details = array();\n\n    function __construct($details)\n    {\n        if (is_array($details)) {\n            $message = $details['code'] . ': ' . $details['message']\n                     . ' RequestId: ' . $details['request-id'];\n            parent::__construct($message);\n            $this->details = $details;\n        } else {\n            $message = $details;\n            parent::__construct($message);\n        }\n    }\n\n    public function getHTTPStatus()\n    {\n        return isset($this->details['status']) ? $this->details['status'] : '';\n    }\n\n    public function getRequestId()\n    {\n        return isset($this->details['request-id']) ? $this->details['request-id'] : '';\n    }\n\n    public function getErrorCode()\n    {\n        return isset($this->details['code']) ? $this->details['code'] : '';\n    }\n\n    public function getErrorMessage()\n    {\n        return isset($this->details['message']) ? $this->details['message'] : '';\n    }\n\n    public function getDetails()\n    {\n        return isset($this->details['body']) ? $this->details['body'] : '';\n    }\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Core/OssUtil.php",
    "content": "<?php\n\nnamespace OSS\\Core;\n\n/**\n * Class OssUtil\n *\n * Oss Util class for OssClient. The caller could use it for formating the result from OssClient.\n *\n * @package OSS\n */\nclass OssUtil\n{\n    const OSS_CONTENT = 'content';\n    const OSS_LENGTH = 'length';\n    const OSS_HEADERS = 'headers';\n    const OSS_MAX_OBJECT_GROUP_VALUE = 1000;\n    const OSS_MAX_PART_SIZE = 5368709120; // 5GB\n    const OSS_MID_PART_SIZE = 10485760; // 10MB\n    const OSS_MIN_PART_SIZE = 102400; // 100KB\n\n    /**\n     * Generate query params\n     *\n     * @param array $options: a key-value pair array.\n     * @return string: the key-value list in the format such as key1=value1&key2=value2\n     */\n    public static function toQueryString($options = array())\n    {\n        $temp = array();\n        uksort($options, 'strnatcasecmp');\n        foreach ($options as $key => $value) {\n            if (is_string($key) && !is_array($value)) {\n                $temp[] = rawurlencode($key) . '=' . rawurlencode($value);\n            }\n        }\n        return implode('&', $temp);\n    }\n\n    /**\n     * Html encoding '<', '>', '&', '\\', '\"' in subject parameter. \n     *\n     * @param string $subject\n     * @return string\n     */\n    public static function sReplace($subject)\n    {\n        $search = array('<', '>', '&', '\\'', '\"');\n        $replace = array('&lt;', '&gt;', '&amp;', '&apos;', '&quot;');\n        return str_replace($search, $replace, $subject);\n    }\n\n    /**\n     * Check whether the string includes any chinese character\n     *\n     * @param $str\n     * @return int\n     */\n    public static function chkChinese($str)\n    {\n        return preg_match('/[\\x80-\\xff]./', $str);\n    }\n\n    /**\n     * Checks if the string is encoded by GB2312.\n     *\n     * @param string $str\n     * @return boolean false UTF-8 encoding  TRUE GB2312 encoding\n     */\n    public static function isGb2312($str)\n    {\n        for ($i = 0; $i < strlen($str); $i++) {\n            $v = ord($str[$i]);\n            if ($v > 127) {\n                if (($v >= 228) && ($v <= 233)) {\n                    if (($i + 2) >= (strlen($str) - 1)) return true;  // not enough characters\n                    $v1 = ord($str[$i + 1]);\n                    $v2 = ord($str[$i + 2]);\n                    if (($v1 >= 128) && ($v1 <= 191) && ($v2 >= 128) && ($v2 <= 191))\n                        return false;\n                    else\n                        return true;\n                }\n            }\n        }\n        return false;\n    }\n\n    /**\n     * Checks if the string is encoded by GBK\n     *\n     * @param string $str\n     * @param boolean $gbk\n     * @return boolean\n     */\n    public static function checkChar($str, $gbk = true)\n    {\n        for ($i = 0; $i < strlen($str); $i++) {\n            $v = ord($str[$i]);\n            if ($v > 127) {\n                if (($v >= 228) && ($v <= 233)) {\n                    if (($i + 2) >= (strlen($str) - 1)) return $gbk ? true : FALSE;  // not enough characters\n                    $v1 = ord($str[$i + 1]);\n                    $v2 = ord($str[$i + 2]);\n                    if ($gbk) {\n                        return (($v1 >= 128) && ($v1 <= 191) && ($v2 >= 128) && ($v2 <= 191)) ? FALSE : TRUE;//GBK\n                    } else {\n                        return (($v1 >= 128) && ($v1 <= 191) && ($v2 >= 128) && ($v2 <= 191)) ? TRUE : FALSE;\n                    }\n                }\n            }\n        }\n        return $gbk ? TRUE : FALSE;\n    }\n\n    /**\n     * Checks if the bucket name is valid\n     * bucket naming rules\n     * 1. Can only include lowercase letters, numbers, or dashes\n     * 2. Must start and end with lowercase letters or numbers\n     * 3. Must be within a length from 3 to 63 bytes.\n     *\n     * @param string $bucket Bucket name\n     * @return boolean\n     */\n    public static function validateBucket($bucket)\n    {\n        $pattern = '/^[a-z0-9][a-z0-9-]{2,62}$/';\n        if (!preg_match($pattern, $bucket)) {\n            return false;\n        }\n        return true;\n    }\n\n    /**\n     * Checks if object name is valid\n     * object naming rules:\n     * 1. Must be within a length from 1 to 1023 bytes\n     * 2. Cannot start with '/' or '\\\\'.\n     * 3. Must be encoded in UTF-8.\n     *\n     * @param string $object Object名称\n     * @return boolean\n     */\n    public static function validateObject($object)\n    {\n        $pattern = '/^.{1,1023}$/';\n        if (empty($object) || !preg_match($pattern, $object) ||\n            self::startsWith($object, '/') || self::startsWith($object, '\\\\')\n        ) {\n            return false;\n        }\n        return true;\n    }\n\n\n    /**\n     * Checks if $str starts with $findMe\n     *\n     * @param string $str\n     * @param string $findMe\n     * @return bool\n     */\n    public static function startsWith($str, $findMe)\n    {\n        if (strpos($str, $findMe) === 0) {\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n\n    /**\n     * Generate the xml message of createBucketXmlBody.\n     *\n     * @param string $storageClass\n     * @return string\n     */\n    public static function createBucketXmlBody($storageClass)\n    {\n        $xml = new \\SimpleXMLElement('<?xml version=\"1.0\" encoding=\"UTF-8\"?><CreateBucketConfiguration></CreateBucketConfiguration>');\n        $xml->addChild('StorageClass',  $storageClass);\n        return $xml->asXML();\n    }\n\n    /**\n     * validate $options\n     *\n     * @param array $options\n     * @throws OssException\n     * @return boolean\n     */\n    public static function validateOptions($options)\n    {\n        //$options\n        if ($options != NULL && !is_array($options)) {\n            throw new OssException ($options . ':' . 'option must be array');\n        }\n    }\n\n    /**\n     * check whether the Content is valid.\n     *\n     * @param $content string\n     * @throws OssException\n     */\n    public static function validateContent($content)\n    {\n        if (empty($content)) {\n            throw new OssException(\"http body content is invalid\");\n        }\n    }\n\n    /**\n     * Check if BUCKET/OBJECT/OBJECT GROUP is empty.\n     *\n     * @param  string $name\n     * @param  string $errMsg\n     * @throws OssException\n     * @return void\n     */\n    public static function throwOssExceptionWithMessageIfEmpty($name, $errMsg)\n    {\n        if (empty($name)) {\n            throw new OssException($errMsg);\n        }\n    }\n\n    /**\n     * This is a method for test only. DO NOT USE.\n     *\n     * @param $filename\n     * @param $size\n     */\n    public static function generateFile($filename, $size)\n    {\n        if (file_exists($filename) && $size == filesize($filename)) {\n            echo $filename . \" already exists, no need to create again. \";\n            return;\n        }\n        $part_size = 1 * 1024 * 1024;\n        $fp = fopen($filename, \"w\");\n        $characters = <<<BBB\n0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';\nBBB;\n\n        $charactersLength = strlen($characters);\n        if ($fp) {\n            while ($size > 0) {\n                if ($size < $part_size) {\n                    $write_size = $size;\n                } else {\n                    $write_size = $part_size;\n                }\n                $size -= $write_size;\n                $a = $characters[rand(0, $charactersLength - 1)];\n                $content = str_repeat($a, $write_size);\n                $flag = fwrite($fp, $content);\n                if (!$flag) {\n                    echo \"write to \" . $filename . \" failed. <br>\";\n                    break;\n                }\n            }\n        } else {\n            echo \"open \" . $filename . \" failed. <br>\";\n        }\n        fclose($fp);\n    }\n\n    /**\n     * Get MD5 of the file.\n     *\n     * @param $filename\n     * @param $from_pos\n     * @param $to_pos\n     * @return string\n     */\n    public static function getMd5SumForFile($filename, $from_pos, $to_pos)\n    {\n        $content_md5 = \"\";\n        if (($to_pos - $from_pos) > self::OSS_MAX_PART_SIZE) {\n            return $content_md5;\n        }\n        $filesize = filesize($filename);\n        if ($from_pos >= $filesize || $to_pos >= $filesize || $from_pos < 0 || $to_pos < 0) {\n            return $content_md5;\n        }\n\n        $total_length = $to_pos - $from_pos + 1;\n        $buffer = 8192;\n        $left_length = $total_length;\n        if (!file_exists($filename)) {\n            return $content_md5;\n        }\n\n        if (false === $fh = fopen($filename, 'rb')) {\n            return $content_md5;\n        }\n\n        fseek($fh, $from_pos);\n        $data = '';\n        while (!feof($fh)) {\n            if ($left_length >= $buffer) {\n                $read_length = $buffer;\n            } else {\n                $read_length = $left_length;\n            }\n            if ($read_length <= 0) {\n                break;\n            } else {\n                $data .= fread($fh, $read_length);\n                $left_length = $left_length - $read_length;\n            }\n        }\n        fclose($fh);\n        $content_md5 = base64_encode(md5($data, true));\n        return $content_md5;\n    }\n\n    /**\n     * Check if the OS is Windows. The default encoding in Windows is GBK.\n     *\n     * @return bool\n     */\n    public static function isWin()\n    {\n        return strtoupper(substr(PHP_OS, 0, 3)) == \"WIN\";\n    }\n\n    /**\n     * Encodes the file path from GBK to UTF-8.\n     * The default encoding in Windows is GBK. \n     * And if the file path is in Chinese, the file would not be found without the transcoding to UTF-8.\n     *\n     * @param $file_path\n     * @return string\n     */\n    public static function encodePath($file_path)\n    {\n        if (self::chkChinese($file_path) && self::isWin()) {\n            $file_path = iconv('utf-8', 'gbk', $file_path);\n        }\n        return $file_path;\n    }\n\n    /**\n     * Check if the endpoint is in the IPv4 format, such as xxx.xxx.xxx.xxx:port or xxx.xxx.xxx.xxx.\n     *\n     * @param string $endpoint The endpoint to check.\n     * @return boolean\n     */\n    public static function isIPFormat($endpoint)\n    {\n        $ip_array = explode(\":\", $endpoint);\n        $hostname = $ip_array[0];\n        $ret = filter_var($hostname, FILTER_VALIDATE_IP);\n        if (!$ret) {\n            return false;\n        } else {\n            return true;\n        }\n    }\n\n    /**\n     * Get the host:port from endpoint.\n     *\n     * @param string $endpoint the endpoint.\n     * @return boolean\n     */\n    public static function getHostPortFromEndpoint($endpoint)\n    {\n        $str = $endpoint;\n        $pos = strpos($str, \"://\");\n        if ($pos !== false) {\n            $str = substr($str, $pos+3);\n        }\n    \n        $pos = strpos($str, '#');\n        if ($pos !== false) {\n            $str = substr($str, 0, $pos);\n        }\n    \n        $pos = strpos($str, '?');\n        if ($pos !== false) {\n            $str = substr($str, 0, $pos);\n        }\n    \n        $pos = strpos($str, '/');\n        if ($pos !== false) {\n            $str = substr($str, 0, $pos);\n        }\n    \n        $pos = strpos($str, '@');\n        if ($pos !== false) {\n            $str = substr($str, $pos+1);\n        }\n        \n        return $str;\n    }\n\n    /**\n     * Generate the xml message of DeleteMultiObjects.\n     *\n     * @param string[] $objects\n     * @param bool $quiet\n     * @return string\n     */\n    public static function createDeleteObjectsXmlBody($objects, $quiet)\n    {\n        $xml = new \\SimpleXMLElement('<?xml version=\"1.0\" encoding=\"utf-8\"?><Delete></Delete>');\n        $xml->addChild('Quiet', $quiet);\n        foreach ($objects as $object) {\n            $sub_object = $xml->addChild('Object');\n            $object = OssUtil::sReplace($object);\n            $sub_object->addChild('Key', $object);\n        }\n        return $xml->asXML();\n    }\n\n    /**\n     * Generate the xml message of CompleteMultipartUpload.\n     *\n     * @param array[] $listParts\n     * @return string\n     */\n    public static function createCompleteMultipartUploadXmlBody($listParts)\n    {\n        $xml = new \\SimpleXMLElement('<?xml version=\"1.0\" encoding=\"utf-8\"?><CompleteMultipartUpload></CompleteMultipartUpload>');\n        foreach ($listParts as $node) {\n            $part = $xml->addChild('Part');\n            $part->addChild('PartNumber', $node['PartNumber']);\n            $part->addChild('ETag', $node['ETag']);\n        }\n        return $xml->asXML();\n    }\n\n    /**\n     * Read the directory, return a associative array in which the MD5 is the named key and the <path,filanme> is the value.\n     *\n     * @param string $dir\n     * @param string $exclude\n     * @param bool $recursive\n     * @return string[]\n     */\n    public static function readDir($dir, $exclude = \".|..|.svn|.git\", $recursive = false)\n    {\n        $file_list_array = array();\n        $base_path = $dir;\n        $exclude_array = explode(\"|\", $exclude);\n        $exclude_array = array_unique(array_merge($exclude_array, array('.', '..')));\n\n        if ($recursive) {\n            foreach (new \\RecursiveIteratorIterator(new \\RecursiveDirectoryIterator($dir)) as $new_file) {\n                if ($new_file->isDir()) continue;\n                $object = str_replace($base_path, '', $new_file);\n                if (!in_array(strtolower($object), $exclude_array)) {\n                    $object = ltrim($object, '/');\n                    if (is_file($new_file)) {\n                        $key = md5($new_file . $object, false);\n                        $file_list_array[$key] = array('path' => $new_file, 'file' => $object,);\n                    }\n                }\n            }\n        } else if ($handle = opendir($dir)) {\n            while (false !== ($file = readdir($handle))) {\n                if (!in_array(strtolower($file), $exclude_array)) {\n                    $new_file = $dir . '/' . $file;\n                    $object = $file;\n                    $object = ltrim($object, '/');\n                    if (is_file($new_file)) {\n                        $key = md5($new_file . $object, false);\n                        $file_list_array[$key] = array('path' => $new_file, 'file' => $object,);\n                    }\n                }\n            }\n            closedir($handle);\n        }\n        return $file_list_array;\n    }\n\n    /**\n     * Decode key based on the encoding type\n     *\n     * @param string $key\n     * @param string $encoding\n     * @return string\n     */\n    public static function decodeKey($key, $encoding)\n    {\n        if ($encoding == \"\") {\n            return $key;\n        }\n\n        if ($encoding == \"url\") {\n            return rawurldecode($key);\n        } else {\n            throw new OssException(\"Unrecognized encoding type: \" . $encoding);\n        }\n    }\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Http/LICENSE",
    "content": "Copyright (c) 2006-2010 Ryan Parman, Foleeo Inc., and contributors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without modification, are\npermitted provided that the following conditions are met:\n\n\t* Redistributions of source code must retain the above copyright notice, this list of\n\t  conditions and the following disclaimer.\n\n\t* Redistributions in binary form must reproduce the above copyright notice, this list\n\t  of conditions and the following disclaimer in the documentation and/or other materials\n\t  provided with the distribution.\n\n\t* Neither the name of Ryan Parman, Foleeo Inc. nor the names of its contributors may be used to\n\t  endorse or promote products derived from this software without specific prior written\n\t  permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS\nOR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY\nAND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS\nAND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\nCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\nOTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Http/RequestCore.php",
    "content": "<?php\nnamespace OSS\\Http;\n\n\n/**\n * Handle all HTTP requests using cURL and manages the responses.\n *\n * @version 2011.06.07\n * @copyright 2006-2011 Ryan Parman\n * @copyright 2006-2010 Foleeo Inc.\n * @copyright 2010-2011 Amazon.com, Inc. or its affiliates.\n * @copyright 2008-2011 Contributors\n * @license http://opensource.org/licenses/bsd-license.php Simplified BSD License\n */\nclass RequestCore\n{\n    /**\n     * The URL being requested.\n     */\n    public $request_url;\n\n    /**\n     * The headers being sent in the request.\n     */\n    public $request_headers;\n   \n    /**\n     * The raw response callback headers\n     */\n    public $response_raw_headers;\n\n    /**\n     * Response body when error occurs\n     */\n    public $response_error_body;\n\n    /**\n     *The hander of write file\n     */\n    public $write_file_handle; \n\n    /**\n     * The body being sent in the request.\n     */\n    public $request_body;\n\n    /**\n     * The response returned by the request.\n     */\n    public $response;\n\n    /**\n     * The headers returned by the request.\n     */\n    public $response_headers;\n\n    /**\n     * The body returned by the request.\n     */\n    public $response_body;\n\n    /**\n     * The HTTP status code returned by the request.\n     */\n    public $response_code;\n\n    /**\n     * Additional response data.\n     */\n    public $response_info;\n\n    /**\n     * The method by which the request is being made.\n     */\n    public $method;\n\n    /**\n     * Store the proxy settings to use for the request.\n     */\n    public $proxy = null;\n\n    /**\n     * The username to use for the request.\n     */\n    public $username = null;\n\n    /**\n     * The password to use for the request.\n     */\n    public $password = null;\n\n    /**\n     * Custom CURLOPT settings.\n     */\n    public $curlopts = null;\n\n    /**\n     * The state of debug mode.\n     */\n    public $debug_mode = false;\n\n    /**\n     * The default class to use for HTTP Requests (defaults to <RequestCore>).\n     */\n    public $request_class = 'OSS\\Http\\RequestCore';\n\n    /**\n     * The default class to use for HTTP Responses (defaults to <ResponseCore>).\n     */\n    public $response_class = 'OSS\\Http\\ResponseCore';\n\n    /**\n     * Default useragent string to use.\n     */\n    public $useragent = 'RequestCore/1.4.3';\n\n    /**\n     * File to read from while streaming up.\n     */\n    public $read_file = null;\n\n    /**\n     * The resource to read from while streaming up.\n     */\n    public $read_stream = null;\n\n    /**\n     * The size of the stream to read from.\n     */\n    public $read_stream_size = null;\n\n    /**\n     * The length already read from the stream.\n     */\n    public $read_stream_read = 0;\n\n    /**\n     * File to write to while streaming down.\n     */\n    public $write_file = null;\n\n    /**\n     * The resource to write to while streaming down.\n     */\n    public $write_stream = null;\n\n    /**\n     * Stores the intended starting seek position.\n     */\n    public $seek_position = null;\n\n    /**\n     * The location of the cacert.pem file to use.\n     */\n    public $cacert_location = false;\n\n    /**\n     * The state of SSL certificate verification.\n     */\n    public $ssl_verification = true;\n\n    /**\n     * The user-defined callback function to call when a stream is read from.\n     */\n    public $registered_streaming_read_callback = null;\n\n    /**\n     * The user-defined callback function to call when a stream is written to.\n     */\n    public $registered_streaming_write_callback = null;\n\n    /**\n     * The request timeout time, which is 5,184,000 seconds,that is, 6 days by default\n     *\n     * @var int\n     */\n    public $timeout = 5184000;\n\n    /**\n     * The connection timeout time, which is 10 seconds by default\n     *\n     * @var int\n     */\n    public $connect_timeout = 10;\n\n    /*%******************************************************************************************%*/\n    // CONSTANTS\n\n    /**\n     * GET HTTP Method\n     */\n    const HTTP_GET = 'GET';\n\n    /**\n     * POST HTTP Method\n     */\n    const HTTP_POST = 'POST';\n\n    /**\n     * PUT HTTP Method\n     */\n    const HTTP_PUT = 'PUT';\n\n    /**\n     * DELETE HTTP Method\n     */\n    const HTTP_DELETE = 'DELETE';\n\n    /**\n     * HEAD HTTP Method\n     */\n    const HTTP_HEAD = 'HEAD';\n\n\n    /*%******************************************************************************************%*/\n    // CONSTRUCTOR/DESTRUCTOR\n\n    /**\n     * Construct a new instance of this class.\n     *\n     * @param string $url (Optional) The URL to request or service endpoint to query.\n     * @param string $proxy (Optional) The faux-url to use for proxy settings. Takes the following format: `proxy://user:pass@hostname:port`\n     * @param array $helpers (Optional) An associative array of classnames to use for request, and response functionality. Gets passed in automatically by the calling class.\n     * @return $this A reference to the current instance.\n     */\n    public function __construct($url = null, $proxy = null, $helpers = null)\n    {\n        // Set some default values.\n        $this->request_url = $url;\n        $this->method = self::HTTP_GET;\n        $this->request_headers = array();\n        $this->request_body = '';\n\n        // Set a new Request class if one was set.\n        if (isset($helpers['request']) && !empty($helpers['request'])) {\n            $this->request_class = $helpers['request'];\n        }\n\n        // Set a new Request class if one was set.\n        if (isset($helpers['response']) && !empty($helpers['response'])) {\n            $this->response_class = $helpers['response'];\n        }\n\n        if ($proxy) {\n            $this->set_proxy($proxy);\n        }\n\n        return $this;\n    }\n\n    /**\n     * Destruct the instance. Closes opened file handles.\n     *\n     * @return $this A reference to the current instance.\n     */\n    public function __destruct()\n    {\n        if (isset($this->read_file) && isset($this->read_stream)) {\n            fclose($this->read_stream);\n        }\n\n        if (isset($this->write_file) && isset($this->write_stream)) {\n            fclose($this->write_stream);\n        }\n\n        return $this;\n    }\n\n\n    /*%******************************************************************************************%*/\n    // REQUEST METHODS\n\n    /**\n     * Set the credentials to use for authentication.\n     *\n     * @param string $user (Required) The username to authenticate with.\n     * @param string $pass (Required) The password to authenticate with.\n     * @return $this A reference to the current instance.\n     */\n    public function set_credentials($user, $pass)\n    {\n        $this->username = $user;\n        $this->password = $pass;\n        return $this;\n    }\n\n    /**\n     * Add a custom HTTP header to the cURL request.\n     *\n     * @param string $key (Required) The custom HTTP header to set.\n     * @param mixed $value (Required) The value to assign to the custom HTTP header.\n     * @return $this A reference to the current instance.\n     */\n    public function add_header($key, $value)\n    {\n        $this->request_headers[$key] = $value;\n        return $this;\n    }\n\n    /**\n     * Remove an HTTP header from the cURL request.\n     *\n     * @param string $key (Required) The custom HTTP header to set.\n     * @return $this A reference to the current instance.\n     */\n    public function remove_header($key)\n    {\n        if (isset($this->request_headers[$key])) {\n            unset($this->request_headers[$key]);\n        }\n        return $this;\n    }\n\n    /**\n     * Set the method type for the request.\n     *\n     * @param string $method (Required) One of the following constants: <HTTP_GET>, <HTTP_POST>, <HTTP_PUT>, <HTTP_HEAD>, <HTTP_DELETE>.\n     * @return $this A reference to the current instance.\n     */\n    public function set_method($method)\n    {\n        $this->method = strtoupper($method);\n        return $this;\n    }\n\n    /**\n     * Set a custom useragent string for the class.\n     *\n     * @param string $ua (Required) The useragent string to use.\n     * @return $this A reference to the current instance.\n     */\n    public function set_useragent($ua)\n    {\n        $this->useragent = $ua;\n        return $this;\n    }\n\n    /**\n     * Set the body to send in the request.\n     *\n     * @param string $body (Required) The textual content to send along in the body of the request.\n     * @return $this A reference to the current instance.\n     */\n    public function set_body($body)\n    {\n        $this->request_body = $body;\n        return $this;\n    }\n\n    /**\n     * Set the URL to make the request to.\n     *\n     * @param string $url (Required) The URL to make the request to.\n     * @return $this A reference to the current instance.\n     */\n    public function set_request_url($url)\n    {\n        $this->request_url = $url;\n        return $this;\n    }\n\n    /**\n     * Set additional CURLOPT settings. These will merge with the default settings, and override if\n     * there is a duplicate.\n     *\n     * @param array $curlopts (Optional) A set of key-value pairs that set `CURLOPT` options. These will merge with the existing CURLOPTs, and ones passed here will override the defaults. Keys should be the `CURLOPT_*` constants, not strings.\n     * @return $this A reference to the current instance.\n     */\n    public function set_curlopts($curlopts)\n    {\n        $this->curlopts = $curlopts;\n        return $this;\n    }\n\n    /**\n     * Set the length in bytes to read from the stream while streaming up.\n     *\n     * @param integer $size (Required) The length in bytes to read from the stream.\n     * @return $this A reference to the current instance.\n     */\n    public function set_read_stream_size($size)\n    {\n        $this->read_stream_size = $size;\n\n        return $this;\n    }\n\n    /**\n     * Set the resource to read from while streaming up. Reads the stream from its current position until\n     * EOF or `$size` bytes have been read. If `$size` is not given it will be determined by <php:fstat()> and\n     * <php:ftell()>.\n     *\n     * @param resource $resource (Required) The readable resource to read from.\n     * @param integer $size (Optional) The size of the stream to read.\n     * @return $this A reference to the current instance.\n     */\n    public function set_read_stream($resource, $size = null)\n    {\n        if (!isset($size) || $size < 0) {\n            $stats = fstat($resource);\n\n            if ($stats && $stats['size'] >= 0) {\n                $position = ftell($resource);\n\n                if ($position !== false && $position >= 0) {\n                    $size = $stats['size'] - $position;\n                }\n            }\n        }\n\n        $this->read_stream = $resource;\n\n        return $this->set_read_stream_size($size);\n    }\n\n    /**\n     * Set the file to read from while streaming up.\n     *\n     * @param string $location (Required) The readable location to read from.\n     * @return $this A reference to the current instance.\n     */\n    public function set_read_file($location)\n    {\n        $this->read_file = $location;\n        $read_file_handle = fopen($location, 'r');\n\n        return $this->set_read_stream($read_file_handle);\n    }\n\n    /**\n     * Set the resource to write to while streaming down.\n     *\n     * @param resource $resource (Required) The writeable resource to write to.\n     * @return $this A reference to the current instance.\n     */\n    public function set_write_stream($resource)\n    {\n        $this->write_stream = $resource;\n\n        return $this;\n    }\n\n    /**\n     * Set the file to write to while streaming down.\n     *\n     * @param string $location (Required) The writeable location to write to.\n     * @return $this A reference to the current instance.\n     */\n    public function set_write_file($location)\n    {\n        $this->write_file = $location;\n    }\n\n    /**\n     * Set the proxy to use for making requests.\n     *\n     * @param string $proxy (Required) The faux-url to use for proxy settings. Takes the following format: `proxy://user:pass@hostname:port`\n     * @return $this A reference to the current instance.\n     */\n    public function set_proxy($proxy)\n    {\n        $proxy = parse_url($proxy);\n        $proxy['user'] = isset($proxy['user']) ? $proxy['user'] : null;\n        $proxy['pass'] = isset($proxy['pass']) ? $proxy['pass'] : null;\n        $proxy['port'] = isset($proxy['port']) ? $proxy['port'] : null;\n        $this->proxy = $proxy;\n        return $this;\n    }\n\n    /**\n     * Set the intended starting seek position.\n     *\n     * @param integer $position (Required) The byte-position of the stream to begin reading from.\n     * @return $this A reference to the current instance.\n     */\n    public function set_seek_position($position)\n    {\n        $this->seek_position = isset($position) ? (integer)$position : null;\n\n        return $this;\n    }\n\n    /**\n     * A callback function that is invoked by cURL for streaming up.\n     *\n     * @param resource $curl_handle (Required) The cURL handle for the request.\n     * @param resource $header_content (Required) The header callback result.\n     * @return headers from a stream.\n     */\n   public function streaming_header_callback($curl_handle, $header_content)\n   {\n        $code = curl_getinfo($curl_handle, CURLINFO_HTTP_CODE);\n\n        if (isset($this->write_file) && intval($code) / 100 == 2 && !isset($this->write_file_handle))\n        {\n            $this->write_file_handle = fopen($this->write_file, 'w');\n            $this->set_write_stream($this->write_file_handle);\n        }\n\n        $this->response_raw_headers .= $header_content;\n        return strlen($header_content); \n    }\n        \n\n    /**\n     * Register a callback function to execute whenever a data stream is read from using\n     * <CFRequest::streaming_read_callback()>.\n     *\n     * The user-defined callback function should accept three arguments:\n     *\n     * <ul>\n     *    <li><code>$curl_handle</code> - <code>resource</code> - Required - The cURL handle resource that represents the in-progress transfer.</li>\n     *    <li><code>$file_handle</code> - <code>resource</code> - Required - The file handle resource that represents the file on the local file system.</li>\n     *    <li><code>$length</code> - <code>integer</code> - Required - The length in kilobytes of the data chunk that was transferred.</li>\n     * </ul>\n     *\n     * @param string|array|function $callback (Required) The callback function is called by <php:call_user_func()>, so you can pass the following values: <ul>\n     *    <li>The name of a global function to execute, passed as a string.</li>\n     *    <li>A method to execute, passed as <code>array('ClassName', 'MethodName')</code>.</li>\n     *    <li>An anonymous function (PHP 5.3+).</li></ul>\n     * @return $this A reference to the current instance.\n     */\n    public function register_streaming_read_callback($callback)\n    {\n        $this->registered_streaming_read_callback = $callback;\n\n        return $this;\n    }\n\n    /**\n     * Register a callback function to execute whenever a data stream is written to using\n     * <CFRequest::streaming_write_callback()>.\n     *\n     * The user-defined callback function should accept two arguments:\n     *\n     * <ul>\n     *    <li><code>$curl_handle</code> - <code>resource</code> - Required - The cURL handle resource that represents the in-progress transfer.</li>\n     *    <li><code>$length</code> - <code>integer</code> - Required - The length in kilobytes of the data chunk that was transferred.</li>\n     * </ul>\n     *\n     * @param string|array|function $callback (Required) The callback function is called by <php:call_user_func()>, so you can pass the following values: <ul>\n     *    <li>The name of a global function to execute, passed as a string.</li>\n     *    <li>A method to execute, passed as <code>array('ClassName', 'MethodName')</code>.</li>\n     *    <li>An anonymous function (PHP 5.3+).</li></ul>\n     * @return $this A reference to the current instance.\n     */\n    public function register_streaming_write_callback($callback)\n    {\n        $this->registered_streaming_write_callback = $callback;\n\n        return $this;\n    }\n\n\n    /*%******************************************************************************************%*/\n    // PREPARE, SEND, AND PROCESS REQUEST\n\n    /**\n     * A callback function that is invoked by cURL for streaming up.\n     *\n     * @param resource $curl_handle (Required) The cURL handle for the request.\n     * @param resource $file_handle (Required) The open file handle resource.\n     * @param integer $length (Required) The maximum number of bytes to read.\n     * @return binary Binary data from a stream.\n     */\n    public function streaming_read_callback($curl_handle, $file_handle, $length)\n    {\n        // Once we've sent as much as we're supposed to send...\n        if ($this->read_stream_read >= $this->read_stream_size) {\n            // Send EOF\n            return '';\n        }\n\n        // If we're at the beginning of an upload and need to seek...\n        if ($this->read_stream_read == 0 && isset($this->seek_position) && $this->seek_position !== ftell($this->read_stream)) {\n            if (fseek($this->read_stream, $this->seek_position) !== 0) {\n                throw new RequestCore_Exception('The stream does not support seeking and is either not at the requested position or the position is unknown.');\n            }\n        }\n\n        $read = fread($this->read_stream, min($this->read_stream_size - $this->read_stream_read, $length)); // Remaining upload data or cURL's requested chunk size\n        $this->read_stream_read += strlen($read);\n\n        $out = $read === false ? '' : $read;\n\n        // Execute callback function\n        if ($this->registered_streaming_read_callback) {\n            call_user_func($this->registered_streaming_read_callback, $curl_handle, $file_handle, $out);\n        }\n\n        return $out;\n    }\n\n    /**\n     * A callback function that is invoked by cURL for streaming down.\n     *\n     * @param resource $curl_handle (Required) The cURL handle for the request.\n     * @param binary $data (Required) The data to write.\n     * @return integer The number of bytes written.\n     */\n    public function streaming_write_callback($curl_handle, $data)\n    {\n        $code = curl_getinfo($curl_handle, CURLINFO_HTTP_CODE);\n        \n        if (intval($code) / 100 != 2)\n        {\n            $this->response_error_body .= $data;\n            return strlen($data);\n        }\n\n        $length = strlen($data);\n        $written_total = 0;\n        $written_last = 0;\n        \n        while ($written_total < $length) {\n            $written_last = fwrite($this->write_stream, substr($data, $written_total));\n\n            if ($written_last === false) {\n                return $written_total;\n            }\n\n            $written_total += $written_last;\n        }\n\n        // Execute callback function\n        if ($this->registered_streaming_write_callback) {\n            call_user_func($this->registered_streaming_write_callback, $curl_handle, $written_total);\n        }\n\n        return $written_total;\n    }\n\n    /**\n     * Prepare and adds the details of the cURL request. This can be passed along to a <php:curl_multi_exec()>\n     * function.\n     *\n     * @return resource The handle for the cURL object.\n     *\n     */\n    public function prep_request()\n    {\n        $curl_handle = curl_init();\n\n        // Set default options.\n        curl_setopt($curl_handle, CURLOPT_URL, $this->request_url);\n        curl_setopt($curl_handle, CURLOPT_FILETIME, true);\n        curl_setopt($curl_handle, CURLOPT_FRESH_CONNECT, false);\n//\t\tcurl_setopt($curl_handle, CURLOPT_CLOSEPOLICY, CURLCLOSEPOLICY_LEAST_RECENTLY_USED);\n        curl_setopt($curl_handle, CURLOPT_MAXREDIRS, 5);\n        curl_setopt($curl_handle, CURLOPT_HEADER, true);\n        curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, true);\n        curl_setopt($curl_handle, CURLOPT_TIMEOUT, $this->timeout);\n        curl_setopt($curl_handle, CURLOPT_CONNECTTIMEOUT, $this->connect_timeout);\n        curl_setopt($curl_handle, CURLOPT_NOSIGNAL, true);\n        curl_setopt($curl_handle, CURLOPT_REFERER, $this->request_url);\n        curl_setopt($curl_handle, CURLOPT_USERAGENT, $this->useragent);\n        curl_setopt($curl_handle, CURLOPT_HEADERFUNCTION, array($this, 'streaming_header_callback'));\n        curl_setopt($curl_handle, CURLOPT_READFUNCTION, array($this, 'streaming_read_callback'));\n\n        // Verification of the SSL cert\n        if ($this->ssl_verification) {\n            curl_setopt($curl_handle, CURLOPT_SSL_VERIFYPEER, true);\n            curl_setopt($curl_handle, CURLOPT_SSL_VERIFYHOST, 2);\n        } else {\n            curl_setopt($curl_handle, CURLOPT_SSL_VERIFYPEER, false);\n            curl_setopt($curl_handle, CURLOPT_SSL_VERIFYHOST, false);\n        }\n\n        // chmod the file as 0755\n        if ($this->cacert_location === true) {\n            curl_setopt($curl_handle, CURLOPT_CAINFO, dirname(__FILE__) . '/cacert.pem');\n        } elseif (is_string($this->cacert_location)) {\n            curl_setopt($curl_handle, CURLOPT_CAINFO, $this->cacert_location);\n        }\n\n        // Debug mode\n        if ($this->debug_mode) {\n            curl_setopt($curl_handle, CURLOPT_VERBOSE, true);\n        }\n\n        // Handle open_basedir & safe mode\n        if (!ini_get('safe_mode') && !ini_get('open_basedir')) {\n            curl_setopt($curl_handle, CURLOPT_FOLLOWLOCATION, true);\n        }\n\n        // Enable a proxy connection if requested.\n        if ($this->proxy) {\n            $host = $this->proxy['host'];\n            $host .= ($this->proxy['port']) ? ':' . $this->proxy['port'] : '';\n            curl_setopt($curl_handle, CURLOPT_PROXY, $host);\n\n            if (isset($this->proxy['user']) && isset($this->proxy['pass'])) {\n                curl_setopt($curl_handle, CURLOPT_PROXYUSERPWD, $this->proxy['user'] . ':' . $this->proxy['pass']);\n            }\n        }\n\n        // Set credentials for HTTP Basic/Digest Authentication.\n        if ($this->username && $this->password) {\n            curl_setopt($curl_handle, CURLOPT_HTTPAUTH, CURLAUTH_ANY);\n            curl_setopt($curl_handle, CURLOPT_USERPWD, $this->username . ':' . $this->password);\n        }\n\n        // Handle the encoding if we can.\n        if (extension_loaded('zlib')) {\n            curl_setopt($curl_handle, CURLOPT_ENCODING, '');\n        }\n\n        // Process custom headers\n        if (isset($this->request_headers) && count($this->request_headers)) {\n            $temp_headers = array();\n\n            foreach ($this->request_headers as $k => $v) {\n                $temp_headers[] = $k . ': ' . $v;\n            }\n\n            curl_setopt($curl_handle, CURLOPT_HTTPHEADER, $temp_headers);\n        }\n\n        switch ($this->method) {\n            case self::HTTP_PUT:\n                //unset($this->read_stream);\n                curl_setopt($curl_handle, CURLOPT_CUSTOMREQUEST, 'PUT');\n                if (isset($this->read_stream)) {\n                    if (!isset($this->read_stream_size) || $this->read_stream_size < 0) {\n                        throw new RequestCore_Exception('The stream size for the streaming upload cannot be determined.');\n                    }\n                    curl_setopt($curl_handle, CURLOPT_INFILESIZE, $this->read_stream_size);\n                    curl_setopt($curl_handle, CURLOPT_UPLOAD, true);\n                } else {\n                    curl_setopt($curl_handle, CURLOPT_POSTFIELDS, $this->request_body);\n                }\n                break;\n\n            case self::HTTP_POST:\n                curl_setopt($curl_handle, CURLOPT_CUSTOMREQUEST, 'POST');\n                if (isset($this->read_stream)) {\n                    if (!isset($this->read_stream_size) || $this->read_stream_size < 0) {\n                        throw new RequestCore_Exception('The stream size for the streaming upload cannot be determined.');\n                    }\n                    curl_setopt($curl_handle, CURLOPT_INFILESIZE, $this->read_stream_size);\n                    curl_setopt($curl_handle, CURLOPT_UPLOAD, true);\n                } else {\n                    curl_setopt($curl_handle, CURLOPT_POSTFIELDS, $this->request_body);\n                }\n                break;\n\n            case self::HTTP_HEAD:\n                curl_setopt($curl_handle, CURLOPT_CUSTOMREQUEST, self::HTTP_HEAD);\n                curl_setopt($curl_handle, CURLOPT_NOBODY, 1);\n                break;\n\n            default: // Assumed GET\n                curl_setopt($curl_handle, CURLOPT_CUSTOMREQUEST, $this->method);\n                if (isset($this->write_stream) || isset($this->write_file)) {\n                    curl_setopt($curl_handle, CURLOPT_WRITEFUNCTION, array($this, 'streaming_write_callback'));\n                    curl_setopt($curl_handle, CURLOPT_HEADER, false);\n                } else {\n                    curl_setopt($curl_handle, CURLOPT_POSTFIELDS, $this->request_body);\n                }\n                break;\n        }\n\n        // Merge in the CURLOPTs\n        if (isset($this->curlopts) && sizeof($this->curlopts) > 0) {\n            foreach ($this->curlopts as $k => $v) {\n                curl_setopt($curl_handle, $k, $v);\n            }\n        }\n\n        return $curl_handle;\n    }\n\n    /**\n     * Take the post-processed cURL data and break it down into useful header/body/info chunks. Uses the\n     * data stored in the `curl_handle` and `response` properties unless replacement data is passed in via\n     * parameters.\n     *\n     * @param resource $curl_handle (Optional) The reference to the already executed cURL request.\n     * @param string $response (Optional) The actual response content itself that needs to be parsed.\n     * @return ResponseCore A <ResponseCore> object containing a parsed HTTP response.\n     */\n    public function process_response($curl_handle = null, $response = null)\n    {\n        // Accept a custom one if it's passed.\n        if ($curl_handle && $response) {\n            $this->response = $response;\n        }\n\n        // As long as this came back as a valid resource...\n        if (is_resource($curl_handle)) {\n            // Determine what's what.\n            $header_size = curl_getinfo($curl_handle, CURLINFO_HEADER_SIZE);\n            $this->response_headers = substr($this->response, 0, $header_size);\n            $this->response_body = substr($this->response, $header_size);\n            $this->response_code = curl_getinfo($curl_handle, CURLINFO_HTTP_CODE);\n            $this->response_info = curl_getinfo($curl_handle);\n            \n            if (intval($this->response_code) / 100 != 2 && isset($this->write_file))\n            {\n                $this->response_headers = $this->response_raw_headers;\n                $this->response_body = $this->response_error_body;\n            }\n\n            // Parse out the headers\n            $this->response_headers = explode(\"\\r\\n\\r\\n\", trim($this->response_headers));\n            $this->response_headers = array_pop($this->response_headers);\n            $this->response_headers = explode(\"\\r\\n\", $this->response_headers);\n            array_shift($this->response_headers);\n\n            // Loop through and split up the headers.\n            $header_assoc = array();\n            foreach ($this->response_headers as $header) {\n                $kv = explode(': ', $header);\n                $header_assoc[strtolower($kv[0])] = isset($kv[1]) ? $kv[1] : '';\n            }\n\n            // Reset the headers to the appropriate property.\n            $this->response_headers = $header_assoc;\n            $this->response_headers['info'] = $this->response_info;\n            $this->response_headers['info']['method'] = $this->method;\n            \n            if ($curl_handle && $response) {\n                return new ResponseCore($this->response_headers, $this->response_body, $this->response_code);\n            }\n        }\n\n        // Return false\n        return false;\n    }\n\n    /**\n     * Send the request, calling necessary utility functions to update built-in properties.\n     *\n     * @param boolean $parse (Optional) Whether to parse the response with ResponseCore or not.\n     * @return string The resulting unparsed data from the request.\n     */\n    public function send_request($parse = false)\n    {\n        set_time_limit(0);\n\n        $curl_handle = $this->prep_request();\n        $this->response = curl_exec($curl_handle);\n\n        if ($this->response === false) {\n            throw new RequestCore_Exception('cURL resource: ' . (string)$curl_handle . '; cURL error: ' . curl_error($curl_handle) . ' (' . curl_errno($curl_handle) . ')');\n        }\n\n        $parsed_response = $this->process_response($curl_handle, $this->response);\n\n        curl_close($curl_handle);\n\n        if ($parse) {\n            return $parsed_response;\n        }\n\n        return $this->response;\n    }\n\n    /*%******************************************************************************************%*/\n    // RESPONSE METHODS\n\n    /**\n     * Get the HTTP response headers from the request.\n     *\n     * @param string $header (Optional) A specific header value to return. Defaults to all headers.\n     * @return string|array All or selected header values.\n     */\n    public function get_response_header($header = null)\n    {\n        if ($header) {\n            return $this->response_headers[strtolower($header)];\n        }\n        return $this->response_headers;\n    }\n\n    /**\n     * Get the HTTP response body from the request.\n     *\n     * @return string The response body.\n     */\n    public function get_response_body()\n    {\n        return $this->response_body;\n    }\n\n    /**\n     * Get the HTTP response code from the request.\n     *\n     * @return string The HTTP response code.\n     */\n    public function get_response_code()\n    {\n        return $this->response_code;\n    }\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Http/RequestCore_Exception.php",
    "content": "<?php\n\nnamespace OSS\\Http;\n\nclass RequestCore_Exception extends \\Exception\n{\n\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Http/ResponseCore.php",
    "content": "<?php\n\nnamespace OSS\\Http;\n\n/**\n * Container for all response-related methods.\n */\nclass ResponseCore\n{\n    /**\n     * Store the HTTP header information.\n     */\n    public $header;\n\n    /**\n     * Store the SimpleXML response.\n     */\n    public $body;\n\n    /**\n     * Store the HTTP response code.\n     */\n    public $status;\n\n    /**\n     * Construct a new instance of this class.\n     *\n     * @param array $header (Required) Associative array of HTTP headers (typically returned by <RequestCore::get_response_header()>).\n     * @param string $body (Required) XML-formatted response from OSS.\n     * @param integer $status (Optional) HTTP response status code from the request.\n     * @return Mixed Contains an <php:array> `header` property (HTTP headers as an associative array), a <php:SimpleXMLElement> or <php:string> `body` property, and an <php:integer> `status` code.\n     */\n    public function __construct($header, $body, $status = null)\n    {\n        $this->header = $header;\n        $this->body = $body;\n        $this->status = $status;\n\n        return $this;\n    }\n\n    /**\n     * Did we receive the status code we expected?\n     *\n     * @param integer|array $codes (Optional) The status code(s) to expect. Pass an <php:integer> for a single acceptable value, or an <php:array> of integers for multiple acceptable values.\n     * @return boolean Whether we received the expected status code or not.\n     */\n    public function isOK($codes = array(200, 201, 204, 206))\n    {\n        if (is_array($codes)) {\n            return in_array($this->status, $codes);\n        }\n\n        return $this->status === $codes;\n    }\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Model/BucketInfo.php",
    "content": "<?php\n\nnamespace OSS\\Model;\n\n\n/**\n * Bucket information class. This is the type of element in BucketListInfo's\n *\n * Class BucketInfo\n * @package OSS\\Model\n */\nclass BucketInfo\n{\n    /**\n     * BucketInfo constructor.\n     *\n     * @param string $location\n     * @param string $name\n     * @param string $createDate\n     */\n    public function __construct($location, $name, $createDate)\n    {\n        $this->location = $location;\n        $this->name = $name;\n        $this->createDate = $createDate;\n    }\n\n    /**\n     * Get bucket location\n     *\n     * @return string\n     */\n    public function getLocation()\n    {\n        return $this->location;\n    }\n\n    /**\n     * Get bucket name\n     *\n     * @return string\n     */\n    public function getName()\n    {\n        return $this->name;\n    }\n\n    /**\n     * Get bucket creation time.\n     *\n     * @return string\n     */\n    public function getCreateDate()\n    {\n        return $this->createDate;\n    }\n\n    /**\n     * bucket region\n     *\n     * @var string\n     */\n    private $location;\n    /**\n     * bucket name\n     *\n     * @var string\n     */\n    private $name;\n\n    /**\n     * bucket creation time\n     *\n     * @var string\n     */\n    private $createDate;\n\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Model/BucketListInfo.php",
    "content": "<?php\n\nnamespace OSS\\Model;\n\n/**\n * Class BucketListInfo\n *\n * It's the type of return value of ListBuckets.\n *\n * @package OSS\\Model\n */\nclass BucketListInfo\n{\n    /**\n     * BucketListInfo constructor.\n     * @param array $bucketList\n     */\n    public function __construct(array $bucketList)\n    {\n        $this->bucketList = $bucketList;\n    }\n\n    /**\n     * Get the BucketInfo list\n     *\n     * @return BucketInfo[]\n     */\n    public function getBucketList()\n    {\n        return $this->bucketList;\n    }\n\n    /**\n     * BucketInfo list\n     *\n     * @var array\n     */\n    private $bucketList = array();\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Model/CnameConfig.php",
    "content": "<?php\n\nnamespace OSS\\Model;\n\n\nuse OSS\\Core\\OssException;\n\n/**\n * Class CnameConfig\n * @package OSS\\Model\n *\n * TODO: fix link\n * @link http://help.aliyun.com/document_detail/oss/api-reference/cors/PutBucketcors.html\n */\nclass CnameConfig implements XmlConfig\n{\n    public function __construct()\n    {\n        $this->cnameList = array();\n    }\n\n    /**\n     * @return array\n     * @example\n     *  array(2) {\n     *    [0]=>\n     *    array(3) {\n     *      [\"Domain\"]=>\n     *      string(11) \"www.foo.com\"\n     *      [\"Status\"]=>\n     *      string(7) \"enabled\"\n     *      [\"LastModified\"]=>\n     *      string(8) \"20150101\"\n     *    }\n     *    [1]=>\n     *    array(3) {\n     *      [\"Domain\"]=>\n     *      string(7) \"bar.com\"\n     *      [\"Status\"]=>\n     *      string(8) \"disabled\"\n     *      [\"LastModified\"]=>\n     *      string(8) \"20160101\"\n     *    }\n     *  }\n     */\n    public function getCnames()\n    {\n        return $this->cnameList;\n    }\n\n\n    public function addCname($cname)\n    {\n        if (count($this->cnameList) >= self::OSS_MAX_RULES) {\n            throw new OssException(\n                \"num of cname in the config exceeds self::OSS_MAX_RULES: \" . strval(self::OSS_MAX_RULES));\n        }\n        $this->cnameList[] = array('Domain' => $cname);\n    }\n\n    public function parseFromXml($strXml)\n    {\n        $xml = simplexml_load_string($strXml);\n        if (!isset($xml->Cname)) return;\n        foreach ($xml->Cname as $entry) {\n            $cname = array();\n            foreach ($entry as $key => $value) {\n                $cname[strval($key)] = strval($value);\n            }\n            $this->cnameList[] = $cname;\n        }\n    }\n\n    public function serializeToXml()\n    {\n        $strXml = <<<EOF\n<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<BucketCnameConfiguration>\n</BucketCnameConfiguration>\nEOF;\n        $xml = new \\SimpleXMLElement($strXml);\n        foreach ($this->cnameList as $cname) {\n            $node = $xml->addChild('Cname');\n            foreach ($cname as $key => $value) {\n                $node->addChild($key, $value);\n            }\n        }\n        return $xml->asXML();\n    }\n\n    public function __toString()\n    {\n        return $this->serializeToXml();\n    }\n\n    const OSS_MAX_RULES = 10;\n\n    private $cnameList = array();\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Model/CorsConfig.php",
    "content": "<?php\n\nnamespace OSS\\Model;\n\n\nuse OSS\\Core\\OssException;\n\n/**\n * Class CorsConfig\n * @package OSS\\Model\n *\n * @link http://help.aliyun.com/document_detail/oss/api-reference/cors/PutBucketcors.html\n */\nclass CorsConfig implements XmlConfig\n{\n    /**\n     * CorsConfig constructor.\n     */\n    public function __construct()\n    {\n        $this->rules = array();\n    }\n\n    /**\n     * Get CorsRule list\n     *\n     * @return CorsRule[]\n     */\n    public function getRules()\n    {\n        return $this->rules;\n    }\n\n\n    /**\n     * Add a new CorsRule\n     *\n     * @param CorsRule $rule\n     * @throws OssException\n     */\n    public function addRule($rule)\n    {\n        if (count($this->rules) >= self::OSS_MAX_RULES) {\n            throw new OssException(\"num of rules in the config exceeds self::OSS_MAX_RULES: \" . strval(self::OSS_MAX_RULES));\n        }\n        $this->rules[] = $rule;\n    }\n\n    /**\n     * Parse CorsConfig from the xml.\n     *\n     * @param string $strXml\n     * @throws OssException\n     * @return null\n     */\n    public function parseFromXml($strXml)\n    {\n        $xml = simplexml_load_string($strXml);\n        if (!isset($xml->CORSRule)) return;\n        foreach ($xml->CORSRule as $rule) {\n            $corsRule = new CorsRule();\n            foreach ($rule as $key => $value) {\n                if ($key === self::OSS_CORS_ALLOWED_HEADER) {\n                    $corsRule->addAllowedHeader(strval($value));\n                } elseif ($key === self::OSS_CORS_ALLOWED_METHOD) {\n                    $corsRule->addAllowedMethod(strval($value));\n                } elseif ($key === self::OSS_CORS_ALLOWED_ORIGIN) {\n                    $corsRule->addAllowedOrigin(strval($value));\n                } elseif ($key === self::OSS_CORS_EXPOSE_HEADER) {\n                    $corsRule->addExposeHeader(strval($value));\n                } elseif ($key === self::OSS_CORS_MAX_AGE_SECONDS) {\n                    $corsRule->setMaxAgeSeconds(strval($value));\n                }\n            }\n            $this->addRule($corsRule);\n        }\n        return;\n    }\n\n    /**\n     * Serialize the object into xml string.\n     *\n     * @return string\n     */\n    public function serializeToXml()\n    {\n        $xml = new \\SimpleXMLElement('<?xml version=\"1.0\" encoding=\"utf-8\"?><CORSConfiguration></CORSConfiguration>');\n        foreach ($this->rules as $rule) {\n            $xmlRule = $xml->addChild('CORSRule');\n            $rule->appendToXml($xmlRule);\n        }\n        return $xml->asXML();\n    }\n\n    public function __toString()\n    {\n        return $this->serializeToXml();\n    }\n\n    const OSS_CORS_ALLOWED_ORIGIN = 'AllowedOrigin';\n    const OSS_CORS_ALLOWED_METHOD = 'AllowedMethod';\n    const OSS_CORS_ALLOWED_HEADER = 'AllowedHeader';\n    const OSS_CORS_EXPOSE_HEADER = 'ExposeHeader';\n    const OSS_CORS_MAX_AGE_SECONDS = 'MaxAgeSeconds';\n    const OSS_MAX_RULES = 10;\n\n    /**\n     * CorsRule list\n     *\n     * @var CorsRule[]\n     */\n    private $rules = array();\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Model/CorsRule.php",
    "content": "<?php\n\nnamespace OSS\\Model;\n\nuse OSS\\Core\\OssException;\n\n\n/**\n * Class CorsRule\n * @package OSS\\Model\n * @link http://help.aliyun.com/document_detail/oss/api-reference/cors/PutBucketcors.html\n */\nclass CorsRule\n{\n    /**\n     * Add an allowedOrigin rule\n     *\n     * @param string $allowedOrigin\n     */\n    public function addAllowedOrigin($allowedOrigin)\n    {\n        if (!empty($allowedOrigin)) {\n            $this->allowedOrigins[] = $allowedOrigin;\n        }\n    }\n\n    /**\n     * Add an allowedMethod rule\n     *\n     * @param string $allowedMethod\n     */\n    public function addAllowedMethod($allowedMethod)\n    {\n        if (!empty($allowedMethod)) {\n            $this->allowedMethods[] = $allowedMethod;\n        }\n    }\n\n    /**\n     * Add an allowedHeader rule\n     *\n     * @param string $allowedHeader\n     */\n    public function addAllowedHeader($allowedHeader)\n    {\n        if (!empty($allowedHeader)) {\n            $this->allowedHeaders[] = $allowedHeader;\n        }\n    }\n\n    /**\n     * Add an exposeHeader rule\n     *\n     * @param string $exposeHeader\n     */\n    public function addExposeHeader($exposeHeader)\n    {\n        if (!empty($exposeHeader)) {\n            $this->exposeHeaders[] = $exposeHeader;\n        }\n    }\n\n    /**\n     * @return int\n     */\n    public function getMaxAgeSeconds()\n    {\n        return $this->maxAgeSeconds;\n    }\n\n    /**\n     * @param int $maxAgeSeconds\n     */\n    public function setMaxAgeSeconds($maxAgeSeconds)\n    {\n        $this->maxAgeSeconds = $maxAgeSeconds;\n    }\n\n    /**\n     * Get the AllowedHeaders list\n     *\n     * @return string[]\n     */\n    public function getAllowedHeaders()\n    {\n        return $this->allowedHeaders;\n    }\n\n    /**\n     * Get the AllowedOrigins list\n     *\n     * @return string[]\n     */\n    public function getAllowedOrigins()\n    {\n        return $this->allowedOrigins;\n    }\n\n    /**\n     * Get the AllowedMethods list\n     *\n     * @return string[]\n     */\n    public function getAllowedMethods()\n    {\n        return $this->allowedMethods;\n    }\n\n    /**\n     * Get the ExposeHeaders list\n     *\n     * @return string[]\n     */\n    public function getExposeHeaders()\n    {\n        return $this->exposeHeaders;\n    }\n\n    /**\n     * Serialize all the rules into the xml represented by parameter $xmlRule\n     *\n     * @param \\SimpleXMLElement $xmlRule\n     * @throws OssException\n     */\n    public function appendToXml(&$xmlRule)\n    {\n        if (!isset($this->maxAgeSeconds)) {\n            throw new OssException(\"maxAgeSeconds is not set in the Rule\");\n        }\n        foreach ($this->allowedOrigins as $allowedOrigin) {\n            $xmlRule->addChild(CorsConfig::OSS_CORS_ALLOWED_ORIGIN, $allowedOrigin);\n        }\n        foreach ($this->allowedMethods as $allowedMethod) {\n            $xmlRule->addChild(CorsConfig::OSS_CORS_ALLOWED_METHOD, $allowedMethod);\n        }\n        foreach ($this->allowedHeaders as $allowedHeader) {\n            $xmlRule->addChild(CorsConfig::OSS_CORS_ALLOWED_HEADER, $allowedHeader);\n        }\n        foreach ($this->exposeHeaders as $exposeHeader) {\n            $xmlRule->addChild(CorsConfig::OSS_CORS_EXPOSE_HEADER, $exposeHeader);\n        }\n        $xmlRule->addChild(CorsConfig::OSS_CORS_MAX_AGE_SECONDS, strval($this->maxAgeSeconds));\n    }\n\n    private $allowedHeaders = array();\n    private $allowedOrigins = array();\n    private $allowedMethods = array();\n    private $exposeHeaders = array();\n    private $maxAgeSeconds = null;\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Model/GetLiveChannelHistory.php",
    "content": "<?php\n\nnamespace OSS\\Model;\n/**\n * Class GetLiveChannelHistory\n * @package OSS\\Model\n */\nclass GetLiveChannelHistory implements XmlConfig\n{\n     public function getLiveRecordList()\n    {\n        return $this->liveRecordList;\n    }\n\n    public function parseFromXml($strXml)\n    {\n        $xml = simplexml_load_string($strXml);\n\n        if (isset($xml->LiveRecord)) {\n            foreach ($xml->LiveRecord as $record) {\n            $liveRecord = new LiveChannelHistory();\n            $liveRecord->parseFromXmlNode($record);\n            $this->liveRecordList[] = $liveRecord;\n           }\n        }\n    }\n\n    public function serializeToXml()\n    {\n        throw new OssException(\"Not implemented.\");\n    }\n    \n    private $liveRecordList = array();\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Model/GetLiveChannelInfo.php",
    "content": "<?php\n\nnamespace OSS\\Model;\n/**\n * Class GetLiveChannelInfo\n * @package OSS\\Model\n */\nclass GetLiveChannelInfo implements XmlConfig\n{\n    public function getDescription()\n    {\n        return $this->description;\n    }\n\n    public function getStatus()\n    {\n        return $this->status;\n    }\n\n    public function getType()\n    {\n        return $this->type;\n    }\n  \n    public function getFragDuration()\n    {\n        return $this->fragDuration;\n    }\n   \n    public function getFragCount()\n    {\n        return $this->fragCount;\n    }\n   \n    public function getPlayListName()\n    {\n        return $this->playlistName;\n    }\n\n    public function parseFromXml($strXml)\n    {\n        $xml = simplexml_load_string($strXml);\n\n        $this->description = strval($xml->Description);\n        $this->status = strval($xml->Status);\n\n        if (isset($xml->Target)) {\n            foreach ($xml->Target as $target) {\n            $this->type = strval($target->Type);\n            $this->fragDuration = strval($target->FragDuration);\n            $this->fragCount = strval($target->FragCount);\n            $this->playlistName = strval($target->PlaylistName);\n           }\n        }\n    }\n\n    public function serializeToXml()\n    {\n        throw new OssException(\"Not implemented.\");\n    }\n    \n    private $description;\n    private $status;\n    private $type;\n    private $fragDuration;\n    private $fragCount;\n    private $playlistName;\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Model/GetLiveChannelStatus.php",
    "content": "<?php\n\nnamespace OSS\\Model;\n/**\n * Class GetLiveChannelStatus\n * @package OSS\\Model\n */\nclass GetLiveChannelStatus implements XmlConfig\n{\n    public function getStatus()\n    {\n        return $this->status;\n    }\n\n    public function getConnectedTime()\n    {\n        return $this->connectedTime;\n    }\n\n    public function getRemoteAddr()\n    {\n        return $this->remoteAddr;\n    }\n\n    public function getVideoWidth()\n    {\n        return $this->videoWidth;\n    }\n    public function getVideoHeight()\n    {\n        return $this->videoHeight;\n    }\n    public function getVideoFrameRate()\n    {\n        return $this->videoFrameRate;\n    }\n    public function getVideoBandwidth()\n    {\n        return $this->videoBandwidth;\n    }\n    public function getVideoCodec()\n    {\n        return $this->videoCodec;\n    }\n\n    public function getAudioBandwidth()\n    {\n        return $this->audioBandwidth;\n    }\n    public function getAudioSampleRate()\n    {\n        return $this->audioSampleRate;\n    }\n    public function getAudioCodec()\n    {\n        return $this->audioCodec;\n    }\n\n\n    public function parseFromXml($strXml)\n    {\n        $xml = simplexml_load_string($strXml);\n        $this->status = strval($xml->Status);\n        $this->connectedTime = strval($xml->ConnectedTime);\n        $this->remoteAddr = strval($xml->RemoteAddr);\n\n        if (isset($xml->Video)) {\n            foreach ($xml->Video as $video) {\n            $this->videoWidth = intval($video->Width);\n            $this->videoHeight = intval($video->Height);\n            $this->videoFrameRate = intval($video->FrameRate);\n            $this->videoBandwidth = intval($video->Bandwidth);\n            $this->videoCodec = strval($video->Codec);\n           }\n        }\n        \n        if (isset($xml->Video)) {\n            foreach ($xml->Audio as $audio) {\n            $this->audioBandwidth = intval($audio->Bandwidth);\n            $this->audioSampleRate = intval($audio->SampleRate);\n            $this->audioCodec = strval($audio->Codec);\n           }\n        }\n\n    }\n\n    public function serializeToXml()\n    {\n        throw new OssException(\"Not implemented.\");\n    }\n    \n    private $status;\n    private $connectedTime;\n    private $remoteAddr;\n\n    private $videoWidth;\n    private $videoHeight;\n    private $videoFrameRate;\n    private $videoBandwidth;\n    private $videoCodec;\n\n    private $audioBandwidth;\n    private $audioSampleRate;\n    private $audioCodec;\n    \n\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Model/LifecycleAction.php",
    "content": "<?php\n\nnamespace OSS\\Model;\n\n/**\n * Class LifecycleAction\n * @package OSS\\Model\n * @link http://help.aliyun.com/document_detail/oss/api-reference/bucket/PutBucketLifecycle.html\n */\nclass LifecycleAction\n{\n    /**\n     * LifecycleAction constructor.\n     * @param string $action\n     * @param string $timeSpec\n     * @param string $timeValue\n     */\n    public function __construct($action, $timeSpec, $timeValue)\n    {\n        $this->action = $action;\n        $this->timeSpec = $timeSpec;\n        $this->timeValue = $timeValue;\n    }\n\n    /**\n     * @return LifecycleAction\n     */\n    public function getAction()\n    {\n        return $this->action;\n    }\n\n    /**\n     * @param string $action\n     */\n    public function setAction($action)\n    {\n        $this->action = $action;\n    }\n\n    /**\n     * @return string\n     */\n    public function getTimeSpec()\n    {\n        return $this->timeSpec;\n    }\n\n    /**\n     * @param string $timeSpec\n     */\n    public function setTimeSpec($timeSpec)\n    {\n        $this->timeSpec = $timeSpec;\n    }\n\n    /**\n     * @return string\n     */\n    public function getTimeValue()\n    {\n        return $this->timeValue;\n    }\n\n    /**\n     * @param string $timeValue\n     */\n    public function setTimeValue($timeValue)\n    {\n        $this->timeValue = $timeValue;\n    }\n\n    /**\n     * Use appendToXml to insert actions into xml.\n     *\n     * @param \\SimpleXMLElement $xmlRule\n     */\n    public function appendToXml(&$xmlRule)\n    {\n        $xmlAction = $xmlRule->addChild($this->action);\n        $xmlAction->addChild($this->timeSpec, $this->timeValue);\n    }\n\n    private $action;\n    private $timeSpec;\n    private $timeValue;\n\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Model/LifecycleConfig.php",
    "content": "<?php\n\nnamespace OSS\\Model;\n\nuse OSS\\Core\\OssException;\n\n\n/**\n * Class BucketLifecycleConfig\n * @package OSS\\Model\n * @link http://help.aliyun.com/document_detail/oss/api-reference/bucket/PutBucketLifecycle.html\n */\nclass LifecycleConfig implements XmlConfig\n{\n    /**\n     * Parse the xml into this object.\n     *\n     * @param string $strXml\n     * @throws OssException\n     * @return null\n     */\n    public function parseFromXml($strXml)\n    {\n        $this->rules = array();\n        $xml = simplexml_load_string($strXml);\n        if (!isset($xml->Rule)) return;\n        $this->rules = array();\n        foreach ($xml->Rule as $rule) {\n            $id = strval($rule->ID);\n            $prefix = strval($rule->Prefix);\n            $status = strval($rule->Status);\n            $actions = array();\n            foreach ($rule as $key => $value) {\n                if ($key === 'ID' || $key === 'Prefix' || $key === 'Status') continue;\n                $action = $key;\n                $timeSpec = null;\n                $timeValue = null;\n                foreach ($value as $timeSpecKey => $timeValueValue) {\n                    $timeSpec = $timeSpecKey;\n                    $timeValue = strval($timeValueValue);\n                }\n                $actions[] = new LifecycleAction($action, $timeSpec, $timeValue);\n            }\n            $this->rules[] = new LifecycleRule($id, $prefix, $status, $actions);\n        }\n        return;\n    }\n\n\n    /**\n     * Serialize the object to xml\n     *\n     * @return string\n     */\n    public function serializeToXml()\n    {\n\n        $xml = new \\SimpleXMLElement('<?xml version=\"1.0\" encoding=\"utf-8\"?><LifecycleConfiguration></LifecycleConfiguration>');\n        foreach ($this->rules as $rule) {\n            $xmlRule = $xml->addChild('Rule');\n            $rule->appendToXml($xmlRule);\n        }\n        return $xml->asXML();\n    }\n\n    /**\n     *\n     * Add a LifecycleRule\n     *\n     * @param LifecycleRule $lifecycleRule\n     * @throws OssException\n     */\n    public function addRule($lifecycleRule)\n    {\n        if (!isset($lifecycleRule)) {\n            throw new OssException(\"lifecycleRule is null\");\n        }\n        $this->rules[] = $lifecycleRule;\n    }\n\n    /**\n     *  Serialize the object into xml string.\n     *\n     * @return string\n     */\n    public function __toString()\n    {\n        return $this->serializeToXml();\n    }\n\n    /**\n     * Get all lifecycle rules.\n     *\n     * @return LifecycleRule[]\n     */\n    public function getRules()\n    {\n        return $this->rules;\n    }\n\n    /**\n     * @var LifecycleRule[]\n     */\n    private $rules;\n}\n\n\n"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Model/LifecycleRule.php",
    "content": "<?php\n\nnamespace OSS\\Model;\n\n\n/**\n * Class LifecycleRule\n * @package OSS\\Model\n *\n * @link http://help.aliyun.com/document_detail/oss/api-reference/bucket/PutBucketLifecycle.html\n */\nclass LifecycleRule\n{\n    /**\n     * Get Id\n     *\n     * @return string\n     */\n    public function getId()\n    {\n        return $this->id;\n    }\n\n    /**\n     * @param string $id Rule Id\n     */\n    public function setId($id)\n    {\n        $this->id = $id;\n    }\n\n    /**\n     * Get a file prefix\n     *\n     * @return string\n     */\n    public function getPrefix()\n    {\n        return $this->prefix;\n    }\n\n    /**\n     * Set a file prefix\n     *\n     * @param string $prefix The file prefix\n     */\n    public function setPrefix($prefix)\n    {\n        $this->prefix = $prefix;\n    }\n\n    /**\n     * Get Lifecycle status\n     *\n     * @return string\n     */\n    public function getStatus()\n    {\n        return $this->status;\n    }\n\n    /**\n     * Set Lifecycle status\n     *\n     * @param string $status\n     */\n    public function setStatus($status)\n    {\n        $this->status = $status;\n    }\n\n    /**\n     *\n     * @return LifecycleAction[]\n     */\n    public function getActions()\n    {\n        return $this->actions;\n    }\n\n    /**\n     * @param LifecycleAction[] $actions\n     */\n    public function setActions($actions)\n    {\n        $this->actions = $actions;\n    }\n\n\n    /**\n     * LifecycleRule constructor.\n     *\n     * @param string $id rule Id\n     * @param string $prefix File prefix\n     * @param string $status Rule status, which has the following valid values: [self::LIFECYCLE_STATUS_ENABLED, self::LIFECYCLE_STATUS_DISABLED]\n     * @param LifecycleAction[] $actions\n     */\n    public function __construct($id, $prefix, $status, $actions)\n    {\n        $this->id = $id;\n        $this->prefix = $prefix;\n        $this->status = $status;\n        $this->actions = $actions;\n    }\n\n    /**\n     * @param \\SimpleXMLElement $xmlRule\n     */\n    public function appendToXml(&$xmlRule)\n    {\n        $xmlRule->addChild('ID', $this->id);\n        $xmlRule->addChild('Prefix', $this->prefix);\n        $xmlRule->addChild('Status', $this->status);\n        foreach ($this->actions as $action) {\n            $action->appendToXml($xmlRule);\n        }\n    }\n\n    private $id;\n    private $prefix;\n    private $status;\n    private $actions = array();\n\n    const LIFECYCLE_STATUS_ENABLED = 'Enabled';\n    const LIFECYCLE_STATUS_DISABLED = 'Disabled';\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Model/ListMultipartUploadInfo.php",
    "content": "<?php\n\nnamespace OSS\\Model;\n\n/**\n * Class ListMultipartUploadInfo\n * @package OSS\\Model\n *\n * @link http://help.aliyun.com/document_detail/oss/api-reference/multipart-upload/ListMultipartUploads.html\n */\nclass ListMultipartUploadInfo\n{\n    /**\n     * ListMultipartUploadInfo constructor.\n     *\n     * @param string $bucket\n     * @param string $keyMarker\n     * @param string $uploadIdMarker\n     * @param string $nextKeyMarker\n     * @param string $nextUploadIdMarker\n     * @param string $delimiter\n     * @param string $prefix\n     * @param int $maxUploads\n     * @param string $isTruncated\n     * @param array $uploads\n     */\n    public function __construct($bucket, $keyMarker, $uploadIdMarker, $nextKeyMarker, $nextUploadIdMarker, $delimiter, $prefix, $maxUploads, $isTruncated, array $uploads)\n    {\n        $this->bucket = $bucket;\n        $this->keyMarker = $keyMarker;\n        $this->uploadIdMarker = $uploadIdMarker;\n        $this->nextKeyMarker = $nextKeyMarker;\n        $this->nextUploadIdMarker = $nextUploadIdMarker;\n        $this->delimiter = $delimiter;\n        $this->prefix = $prefix;\n        $this->maxUploads = $maxUploads;\n        $this->isTruncated = $isTruncated;\n        $this->uploads = $uploads;\n    }\n\n    /**\n     * 得到bucket名称\n     *\n     * @return string\n     */\n    public function getBucket()\n    {\n        return $this->bucket;\n    }\n\n    /**\n     * @return string\n     */\n    public function getKeyMarker()\n    {\n        return $this->keyMarker;\n    }\n\n    /**\n     *\n     * @return string\n     */\n    public function getUploadIdMarker()\n    {\n        return $this->uploadIdMarker;\n    }\n\n    /**\n     * @return string\n     */\n    public function getNextKeyMarker()\n    {\n        return $this->nextKeyMarker;\n    }\n\n    /**\n     * @return string\n     */\n    public function getNextUploadIdMarker()\n    {\n        return $this->nextUploadIdMarker;\n    }\n\n    /**\n     * @return string\n     */\n    public function getDelimiter()\n    {\n        return $this->delimiter;\n    }\n\n    /**\n     * @return string\n     */\n    public function getPrefix()\n    {\n        return $this->prefix;\n    }\n\n    /**\n     * @return int\n     */\n    public function getMaxUploads()\n    {\n        return $this->maxUploads;\n    }\n\n    /**\n     * @return string\n     */\n    public function getIsTruncated()\n    {\n        return $this->isTruncated;\n    }\n\n    /**\n     * @return UploadInfo[]\n     */\n    public function getUploads()\n    {\n        return $this->uploads;\n    }\n\n    private $bucket = \"\";\n    private $keyMarker = \"\";\n    private $uploadIdMarker = \"\";\n    private $nextKeyMarker = \"\";\n    private $nextUploadIdMarker = \"\";\n    private $delimiter = \"\";\n    private $prefix = \"\";\n    private $maxUploads = 0;\n    private $isTruncated = \"false\";\n    private $uploads = array();\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Model/ListPartsInfo.php",
    "content": "<?php\n\nnamespace OSS\\Model;\n\n/**\n * Class ListPartsInfo\n * @package OSS\\Model\n * @link http://help.aliyun.com/document_detail/oss/api-reference/multipart-upload/ListParts.html\n */\nclass ListPartsInfo\n{\n\n    /**\n     * ListPartsInfo constructor.\n     * @param string $bucket\n     * @param string $key\n     * @param string $uploadId\n     * @param int $nextPartNumberMarker\n     * @param int $maxParts\n     * @param string $isTruncated\n     * @param array $listPart\n     */\n    public function __construct($bucket, $key, $uploadId, $nextPartNumberMarker, $maxParts, $isTruncated, array $listPart)\n    {\n        $this->bucket = $bucket;\n        $this->key = $key;\n        $this->uploadId = $uploadId;\n        $this->nextPartNumberMarker = $nextPartNumberMarker;\n        $this->maxParts = $maxParts;\n        $this->isTruncated = $isTruncated;\n        $this->listPart = $listPart;\n    }\n\n    /**\n     * @return string\n     */\n    public function getBucket()\n    {\n        return $this->bucket;\n    }\n\n    /**\n     * @return string\n     */\n    public function getKey()\n    {\n        return $this->key;\n    }\n\n    /**\n     * @return string\n     */\n    public function getUploadId()\n    {\n        return $this->uploadId;\n    }\n\n    /**\n     * @return int\n     */\n    public function getNextPartNumberMarker()\n    {\n        return $this->nextPartNumberMarker;\n    }\n\n    /**\n     * @return int\n     */\n    public function getMaxParts()\n    {\n        return $this->maxParts;\n    }\n\n    /**\n     * @return string\n     */\n    public function getIsTruncated()\n    {\n        return $this->isTruncated;\n    }\n\n    /**\n     * @return array\n     */\n    public function getListPart()\n    {\n        return $this->listPart;\n    }\n\n    private $bucket = \"\";\n    private $key = \"\";\n    private $uploadId = \"\";\n    private $nextPartNumberMarker = 0;\n    private $maxParts = 0;\n    private $isTruncated = \"\";\n    private $listPart = array();\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Model/LiveChannelConfig.php",
    "content": "<?php\n\nnamespace OSS\\Model;\n\n\n/**\n * Class LiveChannelConfig\n * @package OSS\\Model\n */\nclass LiveChannelConfig implements XmlConfig\n{\n    public function __construct($option = array())\n    {\n        if (isset($option['description'])) {\n            $this->description = $option['description'];\n        }\n        if (isset($option['status'])) {\n            $this->status = $option['status'];\n        }\n        if (isset($option['type'])) {\n            $this->type = $option['type'];\n        }\n        if (isset($option['fragDuration'])) {\n            $this->fragDuration = $option['fragDuration'];\n        }\n        if (isset($option['fragCount'])) {\n            $this->fragCount = $option['fragCount'];\n        }\n        if (isset($option['playListName'])) {\n            $this->playListName = $option['playListName'];\n        }\n    }\n\n    public function getDescription()\n    {\n        return $this->description;\n    }\n\n    public function getStatus()\n    {\n        return $this->status;\n    }\n\n    public function getType()\n    {\n        return $this->type;\n    }\n\n    public function getFragDuration()\n    {\n        return $this->fragDuration;\n    }\n\n    public function getFragCount()\n    {\n        return $this->fragCount;\n    }\n\n    public function getPlayListName()\n    {\n        return $this->playListName;\n    }\n\n    public function parseFromXml($strXml)\n    {\n        $xml = simplexml_load_string($strXml);\n        $this->description = strval($xml->Description);\n        $this->status = strval($xml->Status);\n        $target = $xml->Target;\n        $this->type = strval($target->Type);\n        $this->fragDuration = intval($target->FragDuration);\n        $this->fragCount = intval($target->FragCount);\n        $this->playListName = strval($target->PlayListName);\n    }\n\n    public function serializeToXml()\n    {\n        $strXml = <<<EOF\n<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LiveChannelConfiguration>\n</LiveChannelConfiguration>\nEOF;\n        $xml = new \\SimpleXMLElement($strXml);\n        if (isset($this->description)) {\n            $xml->addChild('Description', $this->description);\n        }\n\n        if (isset($this->status)) {\n            $xml->addChild('Status', $this->status);\n        }\n\n        $node = $xml->addChild('Target');\n        $node->addChild('Type', $this->type);\n\n        if (isset($this->fragDuration)) {\n            $node->addChild('FragDuration', $this->fragDuration);\n        }\n\n        if (isset($this->fragCount)) {\n            $node->addChild('FragCount', $this->fragCount);\n        }\n\n        if (isset($this->playListName)) {\n            $node->addChild('PlayListName', $this->playListName);\n        }\n\n        return $xml->asXML();\n    }\n\n    public function __toString()\n    {\n        return $this->serializeToXml();\n    }\n    \n    private $description;\n    private $status = \"enabled\";\n    private $type;\n    private $fragDuration = 5;\n    private $fragCount = 3;\n    private $playListName = \"playlist.m3u8\";\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Model/LiveChannelHistory.php",
    "content": "<?php\n\nnamespace OSS\\Model;\n/**\n * Class LiveChannelHistory\n * @package OSS\\Model\n *\n */\nclass LiveChannelHistory implements XmlConfig\n{\n    public function __construct()\n    {\n    }\n\n    public function getStartTime()\n    {\n        return $this->startTime;\n    }\n\n    public function getEndTime()\n    {\n        return $this->endTime;\n    }\n\n    public function getRemoteAddr()\n    {\n        return $this->remoteAddr;\n    }\n\n    public function parseFromXmlNode($xml)\n    {\n        if (isset($xml->StartTime)) {\n            $this->startTime = strval($xml->StartTime);\n        }\n\n        if (isset($xml->EndTime)) {\n            $this->endTime = strval($xml->EndTime);\n        }\n\n        if (isset($xml->RemoteAddr)) {\n            $this->remoteAddr = strval($xml->RemoteAddr);\n        }\n    }\n\n    public function parseFromXml($strXml)\n    {\n        $xml = simplexml_load_string($strXml);\n        $this->parseFromXmlNode($xml);\n    }\n\n    public function serializeToXml()\n    {\n        throw new OssException(\"Not implemented.\");\n    }\n    \n    private $startTime;\n    private $endTime;\n    private $remoteAddr;\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Model/LiveChannelInfo.php",
    "content": "<?php\n\nnamespace OSS\\Model;\n/**\n * Class LiveChannelInfo\n * @package OSS\\Model\n *\n */\nclass LiveChannelInfo implements XmlConfig\n{\n    public function __construct($name = null, $description = null)\n    {\n        $this->name = $name;\n        $this->description = $description;\n        $this->publishUrls = array();\n        $this->playUrls = array();\n    }\n\n    public function getName()\n    {\n        return $this->name;\n    }\n\n    public function setName($name)\n    {\n        $this->name = $name;\n    }\n\n    public function getPublishUrls()\n    {\n        return $this->publishUrls;\n    }\n\n    public function getPlayUrls()\n    {\n        return $this->playUrls;\n    }\n\n    public function getStatus()\n    {\n        return $this->status;\n    }\n\n    public function getLastModified()\n    {\n        return $this->lastModified;\n    }\n\n    public function getDescription()\n    {\n        return $this->description;\n    }\n\n    public function setDescription($description)\n    {\n        $this->description = $description;\n    }\n\n    public function parseFromXmlNode($xml)\n    {\n        if (isset($xml->Name)) {\n            $this->name = strval($xml->Name);\n        }\n\n        if (isset($xml->Description)) {\n            $this->description = strval($xml->Description);\n        }\n\n        if (isset($xml->Status)) {\n            $this->status = strval($xml->Status);\n        }\n\n        if (isset($xml->LastModified)) {\n            $this->lastModified = strval($xml->LastModified);\n        }\n\n        if (isset($xml->PublishUrls)) {\n            foreach ($xml->PublishUrls as $url) {\n                $this->publishUrls[] = strval($url->Url);\n            }\n        }\n\n        if (isset($xml->PlayUrls)) {\n            foreach ($xml->PlayUrls as $url) {\n                $this->playUrls[] = strval($url->Url);\n            }\n        }\n    }\n\n    public function parseFromXml($strXml)\n    {\n        $xml = simplexml_load_string($strXml);\n        $this->parseFromXmlNode($xml);\n    }\n\n    public function serializeToXml()\n    {\n        throw new OssException(\"Not implemented.\");\n    }\n    \n    private $name;\n    private $description;\n    private $publishUrls;\n    private $playUrls;\n    private $status;\n    private $lastModified;\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Model/LiveChannelListInfo.php",
    "content": "<?php\n\nnamespace OSS\\Model;\n\n/**\n * Class LiveChannelListInfo\n *\n * The data returned by ListBucketLiveChannels\n *\n * @package OSS\\Model\n * @link http://help.aliyun.com/document_detail/oss/api-reference/bucket/GetBucket.html\n */\nclass LiveChannelListInfo implements XmlConfig\n{\n    /**\n     * @return string\n     */\n    public function getBucketName()\n    {\n        return $this->bucket;\n    }\n\n    public function setBucketName($name)\n    {\n        $this->bucket = $name;\n    }\n\n    /**\n     * @return string\n     */\n    public function getPrefix()\n    {\n        return $this->prefix;\n    }\n\n    /**\n     * @return string\n     */\n    public function getMarker()\n    {\n        return $this->marker;\n    }\n\n    /**\n     * @return int\n     */\n    public function getMaxKeys()\n    {\n        return $this->maxKeys;\n    }\n\n    /**\n     * @return mixed\n     */\n    public function getIsTruncated()\n    {\n        return $this->isTruncated;\n    }\n\n    /**\n     * @return LiveChannelInfo[]\n     */\n    public function getChannelList()\n    {\n        return $this->channelList;\n    }\n\n    /**\n     * @return string\n     */\n    public function getNextMarker()\n    {\n        return $this->nextMarker;\n    }\n\n    public function parseFromXml($strXml)\n    {\n        $xml = simplexml_load_string($strXml);\n\n        $this->prefix = strval($xml->Prefix);\n        $this->marker = strval($xml->Marker);\n        $this->maxKeys = intval($xml->MaxKeys);\n        $this->isTruncated = (strval($xml->IsTruncated) == 'true');\n        $this->nextMarker = strval($xml->NextMarker);\n\n        if (isset($xml->LiveChannel)) {\n            foreach ($xml->LiveChannel as $chan) {\n                $channel = new LiveChannelInfo();\n                $channel->parseFromXmlNode($chan);\n                $this->channelList[] = $channel;\n            }\n        }\n    }\n\n    public function serializeToXml()\n    {\n        throw new OssException(\"Not implemented.\");\n    }\n    \n    private $bucket = '';\n    private $prefix = '';\n    private $marker = '';\n    private $nextMarker = '';\n    private $maxKeys = 100;\n    private $isTruncated = 'false';\n    private $channelList = array();\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Model/LoggingConfig.php",
    "content": "<?php\n\nnamespace OSS\\Model;\n\n\n/**\n * Class LoggingConfig\n * @package OSS\\Model\n * @link http://help.aliyun.com/document_detail/oss/api-reference/bucket/PutBucketLogging.html\n */\nclass LoggingConfig implements XmlConfig\n{\n    /**\n     * LoggingConfig constructor.\n     * @param null $targetBucket\n     * @param null $targetPrefix\n     */\n    public function __construct($targetBucket = null, $targetPrefix = null)\n    {\n        $this->targetBucket = $targetBucket;\n        $this->targetPrefix = $targetPrefix;\n    }\n\n    /**\n     * @param $strXml\n     * @return null\n     */\n    public function parseFromXml($strXml)\n    {\n        $xml = simplexml_load_string($strXml);\n        if (!isset($xml->LoggingEnabled)) return;\n        foreach ($xml->LoggingEnabled as $status) {\n            foreach ($status as $key => $value) {\n                if ($key === 'TargetBucket') {\n                    $this->targetBucket = strval($value);\n                } elseif ($key === 'TargetPrefix') {\n                    $this->targetPrefix = strval($value);\n                }\n            }\n            break;\n        }\n    }\n\n    /**\n     *  Serialize to xml string\n     *\n     */\n    public function serializeToXml()\n    {\n        $xml = new \\SimpleXMLElement('<?xml version=\"1.0\" encoding=\"utf-8\"?><BucketLoggingStatus></BucketLoggingStatus>');\n        if (isset($this->targetBucket) && isset($this->targetPrefix)) {\n            $loggingEnabled = $xml->addChild('LoggingEnabled');\n            $loggingEnabled->addChild('TargetBucket', $this->targetBucket);\n            $loggingEnabled->addChild('TargetPrefix', $this->targetPrefix);\n        }\n        return $xml->asXML();\n    }\n\n    /**\n     * @return string\n     */\n    public function __toString()\n    {\n        return $this->serializeToXml();\n    }\n\n    /**\n     * @return string\n     */\n    public function getTargetBucket()\n    {\n        return $this->targetBucket;\n    }\n\n    /**\n     * @return string\n     */\n    public function getTargetPrefix()\n    {\n        return $this->targetPrefix;\n    }\n\n    private $targetBucket = \"\";\n    private $targetPrefix = \"\";\n\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Model/ObjectInfo.php",
    "content": "<?php\n\nnamespace OSS\\Model;\n\n/**\n *\n * Class ObjectInfo\n *\n * The element type of ObjectListInfo, which is the return value type of listObjects\n *\n * The return value of listObjects includes two arrays\n * One is the returned ObjectListInfo, which is similar to a file list in a file system.\n * The other is the returned prefix list, which is similar to a folder list in a file system.\n *\n * @package OSS\\Model\n */\nclass ObjectInfo\n{\n    /**\n     * ObjectInfo constructor.\n     *\n     * @param string $key\n     * @param string $lastModified\n     * @param string $eTag\n     * @param string $type\n     * @param int $size\n     * @param string $storageClass\n     */\n    public function __construct($key, $lastModified, $eTag, $type, $size, $storageClass)\n    {\n        $this->key = $key;\n        $this->lastModified = $lastModified;\n        $this->eTag = $eTag;\n        $this->type = $type;\n        $this->size = $size;\n        $this->storageClass = $storageClass;\n    }\n\n    /**\n     * @return string\n     */\n    public function getKey()\n    {\n        return $this->key;\n    }\n\n    /**\n     * @return string\n     */\n    public function getLastModified()\n    {\n        return $this->lastModified;\n    }\n\n    /**\n     * @return string\n     */\n    public function getETag()\n    {\n        return $this->eTag;\n    }\n\n    /**\n     * @return string\n     */\n    public function getType()\n    {\n        return $this->type;\n    }\n\n    /**\n     * @return int\n     */\n    public function getSize()\n    {\n        return $this->size;\n    }\n\n    /**\n     * @return string\n     */\n    public function getStorageClass()\n    {\n        return $this->storageClass;\n    }\n\n    private $key = \"\";\n    private $lastModified = \"\";\n    private $eTag = \"\";\n    private $type = \"\";\n    private $size = 0;\n    private $storageClass = \"\";\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Model/ObjectListInfo.php",
    "content": "<?php\n\nnamespace OSS\\Model;\n\n/**\n * Class ObjectListInfo\n *\n * The class of return value of ListObjects\n *\n * @package OSS\\Model\n * @link http://help.aliyun.com/document_detail/oss/api-reference/bucket/GetBucket.html\n */\nclass ObjectListInfo\n{\n    /**\n     * ObjectListInfo constructor.\n     *\n     * @param string $bucketName\n     * @param string $prefix\n     * @param string $marker\n     * @param string $nextMarker\n     * @param string $maxKeys\n     * @param string $delimiter\n     * @param null $isTruncated\n     * @param array $objectList\n     * @param array $prefixList\n     */\n    public function __construct($bucketName, $prefix, $marker, $nextMarker, $maxKeys, $delimiter, $isTruncated, array $objectList, array $prefixList)\n    {\n        $this->bucketName = $bucketName;\n        $this->prefix = $prefix;\n        $this->marker = $marker;\n        $this->nextMarker = $nextMarker;\n        $this->maxKeys = $maxKeys;\n        $this->delimiter = $delimiter;\n        $this->isTruncated = $isTruncated;\n        $this->objectList = $objectList;\n        $this->prefixList = $prefixList;\n    }\n\n    /**\n     * @return string\n     */\n    public function getBucketName()\n    {\n        return $this->bucketName;\n    }\n\n    /**\n     * @return string\n     */\n    public function getPrefix()\n    {\n        return $this->prefix;\n    }\n\n    /**\n     * @return string\n     */\n    public function getMarker()\n    {\n        return $this->marker;\n    }\n\n    /**\n     * @return int\n     */\n    public function getMaxKeys()\n    {\n        return $this->maxKeys;\n    }\n\n    /**\n     * @return string\n     */\n    public function getDelimiter()\n    {\n        return $this->delimiter;\n    }\n\n    /**\n     * @return mixed\n     */\n    public function getIsTruncated()\n    {\n        return $this->isTruncated;\n    }\n\n    /**\n     * Get the ObjectInfo list.\n     *\n     * @return ObjectInfo[]\n     */\n    public function getObjectList()\n    {\n        return $this->objectList;\n    }\n\n    /**\n     * Get the PrefixInfo list\n     *\n     * @return PrefixInfo[]\n     */\n    public function getPrefixList()\n    {\n        return $this->prefixList;\n    }\n\n    /**\n     * @return string\n     */\n    public function getNextMarker()\n    {\n        return $this->nextMarker;\n    }\n\n    private $bucketName = \"\";\n    private $prefix = \"\";\n    private $marker = \"\";\n    private $nextMarker = \"\";\n    private $maxKeys = 0;\n    private $delimiter = \"\";\n    private $isTruncated = null;\n    private $objectList = array();\n    private $prefixList = array();\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Model/PartInfo.php",
    "content": "<?php\n\nnamespace OSS\\Model;\n\n/**\n * Class PartInfo\n * @package OSS\\Model\n */\nclass PartInfo\n{\n    /**\n     * PartInfo constructor.\n     *\n     * @param int $partNumber\n     * @param string $lastModified\n     * @param string $eTag\n     * @param int $size\n     */\n    public function __construct($partNumber, $lastModified, $eTag, $size)\n    {\n        $this->partNumber = $partNumber;\n        $this->lastModified = $lastModified;\n        $this->eTag = $eTag;\n        $this->size = $size;\n    }\n\n    /**\n     * @return int\n     */\n    public function getPartNumber()\n    {\n        return $this->partNumber;\n    }\n\n    /**\n     * @return string\n     */\n    public function getLastModified()\n    {\n        return $this->lastModified;\n    }\n\n    /**\n     * @return string\n     */\n    public function getETag()\n    {\n        return $this->eTag;\n    }\n\n    /**\n     * @return int\n     */\n    public function getSize()\n    {\n        return $this->size;\n    }\n\n    private $partNumber = 0;\n    private $lastModified = \"\";\n    private $eTag = \"\";\n    private $size = 0;\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Model/PrefixInfo.php",
    "content": "<?php\n\nnamespace OSS\\Model;\n\n/**\n * Class PrefixInfo\n *\n * ListObjects return Prefix list of classes\n * The returned data contains two arrays\n * One is to get the list of objects【Can be understood as the corresponding file system file list】\n * One is to get Prefix list【Can be understood as the corresponding file system directory list】\n *\n * @package OSS\\Model\n * @link http://help.aliyun.com/document_detail/oss/api-reference/bucket/GetBucket.html\n */\nclass PrefixInfo\n{\n    /**\n     * PrefixInfo constructor.\n     * @param string $prefix\n     */\n    public function __construct($prefix)\n    {\n        $this->prefix = $prefix;\n    }\n\n    /**\n     * @return string\n     */\n    public function getPrefix()\n    {\n        return $this->prefix;\n    }\n\n    private $prefix;\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Model/RefererConfig.php",
    "content": "<?php\n\nnamespace OSS\\Model;\n\n/**\n * Class RefererConfig\n *\n * @package OSS\\Model\n * @link http://help.aliyun.com/document_detail/oss/api-reference/bucket/PutBucketReferer.html\n */\nclass RefererConfig implements XmlConfig\n{\n    /**\n     * @param string $strXml\n     * @return null\n     */\n    public function parseFromXml($strXml)\n    {\n        $xml = simplexml_load_string($strXml);\n        if (!isset($xml->AllowEmptyReferer)) return;\n        if (!isset($xml->RefererList)) return;\n        $this->allowEmptyReferer =\n            (strval($xml->AllowEmptyReferer) === 'TRUE' || strval($xml->AllowEmptyReferer) === 'true') ? true : false;\n\n        foreach ($xml->RefererList->Referer as $key => $refer) {\n            $this->refererList[] = strval($refer);\n        }\n    }\n\n\n    /**\n     * serialize the RefererConfig object into xml string\n     *\n     * @return string\n     */\n    public function serializeToXml()\n    {\n        $xml = new \\SimpleXMLElement('<?xml version=\"1.0\" encoding=\"utf-8\"?><RefererConfiguration></RefererConfiguration>');\n        if ($this->allowEmptyReferer) {\n            $xml->addChild('AllowEmptyReferer', 'true');\n        } else {\n            $xml->addChild('AllowEmptyReferer', 'false');\n        }\n        $refererList = $xml->addChild('RefererList');\n        foreach ($this->refererList as $referer) {\n            $refererList->addChild('Referer', $referer);\n        }\n        return $xml->asXML();\n    }\n\n    /**\n     * @return string\n     */\n    function __toString()\n    {\n        return $this->serializeToXml();\n    }\n\n    /**\n     * @param boolean $allowEmptyReferer\n     */\n    public function setAllowEmptyReferer($allowEmptyReferer)\n    {\n        $this->allowEmptyReferer = $allowEmptyReferer;\n    }\n\n    /**\n     * @param string $referer\n     */\n    public function addReferer($referer)\n    {\n        $this->refererList[] = $referer;\n    }\n\n    /**\n     * @return boolean\n     */\n    public function isAllowEmptyReferer()\n    {\n        return $this->allowEmptyReferer;\n    }\n\n    /**\n     * @return array\n     */\n    public function getRefererList()\n    {\n        return $this->refererList;\n    }\n\n    private $allowEmptyReferer = true;\n    private $refererList = array();\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Model/StorageCapacityConfig.php",
    "content": "<?php\n\nnamespace OSS\\Model;\n\n/**\n * Class StorageCapacityConfig\n *\n * @package OSS\\Model\n * @link http://docs.alibaba-inc.com/pages/viewpage.action?pageId=271614763\n */\nclass StorageCapacityConfig implements XmlConfig\n{\n    /**\n     * StorageCapacityConfig constructor.\n     *\n     * @param int $storageCapacity            \n     */\n    public function __construct($storageCapacity)\n    {\n        $this->storageCapacity = $storageCapacity;\n    }\n\n    /**\n     * Not implemented\n     */\n    public function parseFromXml($strXml)\n    {\n        throw new OssException(\"Not implemented.\");\n    }\n\n    /**\n     * Serialize StorageCapacityConfig into xml\n     *\n     * @return string\n     */\n    public function serializeToXml()\n    {\n        $xml = new \\SimpleXMLElement('<?xml version=\"1.0\" encoding=\"utf-8\"?><BucketUserQos></BucketUserQos>');\n        $xml->addChild('StorageCapacity', strval($this->storageCapacity));\n        return $xml->asXML();\n    }\n\n    /**\n     * To string\n     *\n     * @return string\n     */\n    function __toString()\n    {\n        return $this->serializeToXml();\n    }\n\n    /**\n     * Set storage capacity\n     *\n     * @param int $storageCapacity            \n     */\n    public function setStorageCapacity($storageCapacity)\n    {\n        $this->storageCapacity = $storageCapacity;\n    }\n\n    /**\n     * Get storage capacity\n     * \n     * @return int\n     */\n    public function getStorageCapacity()\n    {\n        return $this->storageCapacity;\n    }\n\n    private $storageCapacity = 0;\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Model/UploadInfo.php",
    "content": "<?php\n\nnamespace OSS\\Model;\n\n/**\n * Class UploadInfo\n *\n * The return value of ListMultipartUpload\n *\n * @package OSS\\Model\n */\nclass UploadInfo\n{\n    /**\n     * UploadInfo constructor.\n     *\n     * @param string $key\n     * @param string $uploadId\n     * @param string $initiated\n     */\n    public function __construct($key, $uploadId, $initiated)\n    {\n        $this->key = $key;\n        $this->uploadId = $uploadId;\n        $this->initiated = $initiated;\n    }\n\n    /**\n     * @return string\n     */\n    public function getKey()\n    {\n        return $this->key;\n    }\n\n    /**\n     * @return string\n     */\n    public function getUploadId()\n    {\n        return $this->uploadId;\n    }\n\n    /**\n     * @return string\n     */\n    public function getInitiated()\n    {\n        return $this->initiated;\n    }\n\n    private $key = \"\";\n    private $uploadId = \"\";\n    private $initiated = \"\";\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Model/WebsiteConfig.php",
    "content": "<?php\n\nnamespace OSS\\Model;\n\n\nuse OSS\\Core\\OssException;\n\n\n/**\n * Class WebsiteConfig\n * @package OSS\\Model\n * @link http://help.aliyun.com/document_detail/oss/api-reference/bucket/PutBucketWebsite.html\n */\nclass WebsiteConfig implements XmlConfig\n{\n    /**\n     * WebsiteConfig constructor.\n     * @param  string $indexDocument\n     * @param  string $errorDocument\n     */\n    public function __construct($indexDocument = \"\", $errorDocument = \"\")\n    {\n        $this->indexDocument = $indexDocument;\n        $this->errorDocument = $errorDocument;\n    }\n\n    /**\n     * @param string $strXml\n     * @return null\n     */\n    public function parseFromXml($strXml)\n    {\n        $xml = simplexml_load_string($strXml);\n        if (isset($xml->IndexDocument) && isset($xml->IndexDocument->Suffix)) {\n            $this->indexDocument = strval($xml->IndexDocument->Suffix);\n        }\n        if (isset($xml->ErrorDocument) && isset($xml->ErrorDocument->Key)) {\n            $this->errorDocument = strval($xml->ErrorDocument->Key);\n        }\n    }\n\n    /**\n     * Serialize the WebsiteConfig object into xml string.\n     *\n     * @return string\n     * @throws OssException\n     */\n    public function serializeToXml()\n    {\n        $xml = new \\SimpleXMLElement('<?xml version=\"1.0\" encoding=\"utf-8\"?><WebsiteConfiguration></WebsiteConfiguration>');\n        $index_document_part = $xml->addChild('IndexDocument');\n        $error_document_part = $xml->addChild('ErrorDocument');\n        $index_document_part->addChild('Suffix', $this->indexDocument);\n        $error_document_part->addChild('Key', $this->errorDocument);\n        return $xml->asXML();\n    }\n\n    /**\n     * @return string\n     */\n    public function getIndexDocument()\n    {\n        return $this->indexDocument;\n    }\n\n    /**\n     * @return string\n     */\n    public function getErrorDocument()\n    {\n        return $this->errorDocument;\n    }\n\n    private $indexDocument = \"\";\n    private $errorDocument = \"\";\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Model/XmlConfig.php",
    "content": "<?php\n\nnamespace OSS\\Model;\n\n/**\n * Interface XmlConfig\n * @package OSS\\Model\n */\ninterface XmlConfig\n{\n\n    /**\n     * Interface method: Parse the object from the xml.\n     *\n     * @param string $strXml\n     * @return null\n     */\n    public function parseFromXml($strXml);\n\n    /**\n     * Interface method: Serialize the object into xml.\n     *\n     * @return string\n     */\n    public function serializeToXml();\n\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/OssClient.php",
    "content": "<?php\nnamespace OSS;\n\nuse OSS\\Core\\MimeTypes;\nuse OSS\\Core\\OssException;\nuse OSS\\Http\\RequestCore;\nuse OSS\\Http\\RequestCore_Exception;\nuse OSS\\Http\\ResponseCore;\nuse OSS\\Model\\CorsConfig;\nuse OSS\\Model\\CnameConfig;\nuse OSS\\Model\\LoggingConfig;\nuse OSS\\Model\\LiveChannelConfig;\nuse OSS\\Model\\LiveChannelInfo;\nuse OSS\\Model\\LiveChannelListInfo;\nuse OSS\\Model\\StorageCapacityConfig;\nuse OSS\\Result\\AclResult;\nuse OSS\\Result\\BodyResult;\nuse OSS\\Result\\GetCorsResult;\nuse OSS\\Result\\GetLifecycleResult;\nuse OSS\\Result\\GetLocationResult;\nuse OSS\\Result\\GetLoggingResult;\nuse OSS\\Result\\GetRefererResult;\nuse OSS\\Result\\GetStorageCapacityResult;\nuse OSS\\Result\\GetWebsiteResult;\nuse OSS\\Result\\GetCnameResult;\nuse OSS\\Result\\HeaderResult;\nuse OSS\\Result\\InitiateMultipartUploadResult;\nuse OSS\\Result\\ListBucketsResult;\nuse OSS\\Result\\ListMultipartUploadResult;\nuse OSS\\Model\\ListMultipartUploadInfo;\nuse OSS\\Result\\ListObjectsResult;\nuse OSS\\Result\\ListPartsResult;\nuse OSS\\Result\\PutSetDeleteResult;\nuse OSS\\Result\\DeleteObjectsResult;\nuse OSS\\Result\\CopyObjectResult;\nuse OSS\\Result\\CallbackResult;\nuse OSS\\Result\\ExistResult;\nuse OSS\\Result\\PutLiveChannelResult;\nuse OSS\\Result\\GetLiveChannelHistoryResult;\nuse OSS\\Result\\GetLiveChannelInfoResult;\nuse OSS\\Result\\GetLiveChannelStatusResult;\nuse OSS\\Result\\ListLiveChannelResult;\nuse OSS\\Result\\AppendResult;\nuse OSS\\Model\\ObjectListInfo;\nuse OSS\\Result\\SymlinkResult;\nuse OSS\\Result\\UploadPartResult;\nuse OSS\\Model\\BucketListInfo;\nuse OSS\\Model\\LifecycleConfig;\nuse OSS\\Model\\RefererConfig;\nuse OSS\\Model\\WebsiteConfig;\nuse OSS\\Core\\OssUtil;\nuse OSS\\Model\\ListPartsInfo;\n\n/**\n * Class OssClient\n *\n * Object Storage Service(OSS)'s client class, which wraps all OSS APIs user could call to talk to OSS.\n * Users could do operations on bucket, object, including MultipartUpload or setting ACL via an OSSClient instance.\n * For more details, please check out the OSS API document:https://www.alibabacloud.com/help/doc-detail/31947.htm\n */\nclass OssClient\n{\n    /**\n     * Constructor\n     *\n     * There're a few different ways to create an OssClient object:\n     * 1. Most common one from access Id, access Key and the endpoint: $ossClient = new OssClient($id, $key, $endpoint)\n     * 2. If the endpoint is the CName (such as www.testoss.com, make sure it's CName binded in the OSS console), \n     *    uses $ossClient = new OssClient($id, $key, $endpoint, true)\n     * 3. If using Alicloud's security token service (STS), then the AccessKeyId, AccessKeySecret and STS token are all got from STS.\n     * Use this: $ossClient = new OssClient($id, $key, $endpoint, false, $token)\n     * 4. If the endpoint is in IP format, you could use this: $ossClient = new OssClient($id, $key, “1.2.3.4:8900”)\n     *\n     * @param string $accessKeyId The AccessKeyId from OSS or STS\n     * @param string $accessKeySecret The AccessKeySecret from OSS or STS\n     * @param string $endpoint The domain name of the datacenter,For example: oss-cn-hangzhou.aliyuncs.com\n     * @param boolean $isCName If this is the CName and binded in the bucket.\n     * @param string $securityToken from STS.\n     * @param string $requestProxy\n     * @throws OssException\n     */\n    public function __construct($accessKeyId, $accessKeySecret, $endpoint, $isCName = false, $securityToken = NULL, $requestProxy = NULL)\n    {\n        $accessKeyId = trim($accessKeyId);\n        $accessKeySecret = trim($accessKeySecret);\n        $endpoint = trim(trim($endpoint), \"/\");\n\n        if (empty($accessKeyId)) {\n            throw new OssException(\"access key id is empty\");\n        }\n        if (empty($accessKeySecret)) {\n            throw new OssException(\"access key secret is empty\");\n        }\n        if (empty($endpoint)) {\n            throw new OssException(\"endpoint is empty\");\n        }\n        $this->hostname = $this->checkEndpoint($endpoint, $isCName);\n        $this->accessKeyId = $accessKeyId;\n        $this->accessKeySecret = $accessKeySecret;\n        $this->securityToken = $securityToken;\n        $this->requestProxy = $requestProxy;\n        self::checkEnv();\n    }\n\n    /**\n     * Lists the Bucket [GetService]. Not applicable if the endpoint is CName (because CName must be binded to a specific bucket).\n     *\n     * @param array $options\n     * @throws OssException\n     * @return BucketListInfo\n     */\n    public function listBuckets($options = NULL)\n    {\n        if ($this->hostType === self::OSS_HOST_TYPE_CNAME) {\n            throw new OssException(\"operation is not permitted with CName host\");\n        }\n        $this->precheckOptions($options);\n        $options[self::OSS_BUCKET] = '';\n        $options[self::OSS_METHOD] = self::OSS_HTTP_GET;\n        $options[self::OSS_OBJECT] = '/';\n        $response = $this->auth($options);\n        $result = new ListBucketsResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * Creates bucket,The ACL of the bucket created by default is OssClient::OSS_ACL_TYPE_PRIVATE\n     *\n     * @param string $bucket\n     * @param string $acl\n     * @param array $options\n     * @param string $storageType\n     * @return null\n     */\n    public function createBucket($bucket, $acl = self::OSS_ACL_TYPE_PRIVATE, $options = NULL)\n    {\n        $this->precheckCommon($bucket, NULL, $options, false);\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;\n        $options[self::OSS_OBJECT] = '/';\n        $options[self::OSS_HEADERS] = array(self::OSS_ACL => $acl);\n        if (isset($options[self::OSS_STORAGE])) {\n            $this->precheckStorage($options[self::OSS_STORAGE]);\n            $options[self::OSS_CONTENT] = OssUtil::createBucketXmlBody($options[self::OSS_STORAGE]);\n            unset($options[self::OSS_STORAGE]);\n        }\n        $response = $this->auth($options);\n        $result = new PutSetDeleteResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * Deletes bucket\n     * The deletion will not succeed if the bucket is not empty (either has objects or parts)\n     * To delete a bucket, all its objects and parts must be deleted first.\n     *\n     * @param string $bucket\n     * @param array $options\n     * @return null\n     */\n    public function deleteBucket($bucket, $options = NULL)\n    {\n        $this->precheckCommon($bucket, NULL, $options, false);\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_METHOD] = self::OSS_HTTP_DELETE;\n        $options[self::OSS_OBJECT] = '/';\n        $response = $this->auth($options);\n        $result = new PutSetDeleteResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * Checks if a bucket exists\n     *\n     * @param string $bucket\n     * @return bool\n     * @throws OssException\n     */\n    public function doesBucketExist($bucket)\n    {\n        $this->precheckCommon($bucket, NULL, $options, false);\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_METHOD] = self::OSS_HTTP_GET;\n        $options[self::OSS_OBJECT] = '/';\n        $options[self::OSS_SUB_RESOURCE] = 'acl';\n        $response = $this->auth($options);\n        $result = new ExistResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * Get the data center location information for the bucket\n     *\n     * @param string $bucket\n     * @param array $options\n     * @throws OssException\n     * @return string\n     */\n    public function getBucketLocation($bucket, $options = NULL)\n    {\n        $this->precheckCommon($bucket, NULL, $options, false);\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_METHOD] = self::OSS_HTTP_GET;\n        $options[self::OSS_OBJECT] = '/';\n        $options[self::OSS_SUB_RESOURCE] = 'location';\n        $response = $this->auth($options);\n        $result = new GetLocationResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * Get the Meta information for the Bucket\n     *\n     * @param string $bucket\n     * @param array $options  Refer to the SDK documentation\n     * @return array\n     */\n    public function getBucketMeta($bucket, $options = NULL)\n    {\n        $this->precheckCommon($bucket, NULL, $options, false);\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_METHOD] = self::OSS_HTTP_HEAD;\n        $options[self::OSS_OBJECT] = '/';\n        $response = $this->auth($options);\n        $result = new HeaderResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * Gets the bucket ACL\n     *\n     * @param string $bucket\n     * @param array $options\n     * @throws OssException\n     * @return string\n     */\n    public function getBucketAcl($bucket, $options = NULL)\n    {\n        $this->precheckCommon($bucket, NULL, $options, false);\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_METHOD] = self::OSS_HTTP_GET;\n        $options[self::OSS_OBJECT] = '/';\n        $options[self::OSS_SUB_RESOURCE] = 'acl';\n        $response = $this->auth($options);\n        $result = new AclResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * Sets the bucket ACL\n     *\n     * @param string $bucket bucket name\n     * @param string $acl access permissions, valid values are ['private', 'public-read', 'public-read-write']\n     * @param array $options by default is empty\n     * @throws OssException\n     * @return null\n     */\n    public function putBucketAcl($bucket, $acl, $options = NULL)\n    {\n        $this->precheckCommon($bucket, NULL, $options, false);\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;\n        $options[self::OSS_OBJECT] = '/';\n        $options[self::OSS_HEADERS] = array(self::OSS_ACL => $acl);\n        $options[self::OSS_SUB_RESOURCE] = 'acl';\n        $response = $this->auth($options);\n        $result = new PutSetDeleteResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * Gets object ACL\n     *\n     * @param string $bucket\n     * @param string $object\n     * @throws OssException\n     * @return string\n     */\n    public function getObjectAcl($bucket, $object)\n    {\n        $options = array();\n        $this->precheckCommon($bucket, $object, $options, true);\n        $options[self::OSS_METHOD] = self::OSS_HTTP_GET;\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_OBJECT] = $object;\n        $options[self::OSS_SUB_RESOURCE] = 'acl';\n        $response = $this->auth($options);\n        $result = new AclResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * Sets the object ACL\n     *\n     * @param string $bucket bucket name\n     * @param string $object object name\n     * @param string $acl access permissions, valid values are ['default', 'private', 'public-read', 'public-read-write']\n     * @throws OssException\n     * @return null\n     */\n    public function putObjectAcl($bucket, $object, $acl)\n    {\n        $this->precheckCommon($bucket, $object, $options, true);\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;\n        $options[self::OSS_OBJECT] = $object;\n        $options[self::OSS_HEADERS] = array(self::OSS_OBJECT_ACL => $acl);\n        $options[self::OSS_SUB_RESOURCE] = 'acl';\n        $response = $this->auth($options);\n        $result = new PutSetDeleteResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * Gets the bucket logging config\n     *\n     * @param string $bucket bucket name\n     * @param array $options by default is empty\n     * @throws OssException\n     * @return LoggingConfig\n     */\n    public function getBucketLogging($bucket, $options = NULL)\n    {\n        $this->precheckCommon($bucket, NULL, $options, false);\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_METHOD] = self::OSS_HTTP_GET;\n        $options[self::OSS_OBJECT] = '/';\n        $options[self::OSS_SUB_RESOURCE] = 'logging';\n        $response = $this->auth($options);\n        $result = new GetLoggingResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * Sets the bycket logging config. Only owner can call this API.\n     *\n     * @param string $bucket bucket name\n     * @param string $targetBucket The logging file's bucket\n     * @param string $targetPrefix The logging file's prefix\n     * @param array $options By default is empty.\n     * @throws OssException\n     * @return null\n     */\n    public function putBucketLogging($bucket, $targetBucket, $targetPrefix, $options = NULL)\n    {\n        $this->precheckCommon($bucket, NULL, $options, false);\n        $this->precheckBucket($targetBucket, 'targetbucket is not allowed empty');\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;\n        $options[self::OSS_OBJECT] = '/';\n        $options[self::OSS_SUB_RESOURCE] = 'logging';\n        $options[self::OSS_CONTENT_TYPE] = 'application/xml';\n\n        $loggingConfig = new LoggingConfig($targetBucket, $targetPrefix);\n        $options[self::OSS_CONTENT] = $loggingConfig->serializeToXml();\n        $response = $this->auth($options);\n        $result = new PutSetDeleteResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * Deletes the bucket logging config\n     *\n     * @param string $bucket bucket name\n     * @param array $options\n     * @throws OssException\n     * @return null\n     */\n    public function deleteBucketLogging($bucket, $options = NULL)\n    {\n        $this->precheckCommon($bucket, NULL, $options, false);\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_METHOD] = self::OSS_HTTP_DELETE;\n        $options[self::OSS_OBJECT] = '/';\n        $options[self::OSS_SUB_RESOURCE] = 'logging';\n        $response = $this->auth($options);\n        $result = new PutSetDeleteResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * Sets the website config in bucket---that is could make the bucket as a static website once the CName is binded.\n     *\n     * @param string $bucket bucket name\n     * @param WebsiteConfig $websiteConfig\n     * @param array $options\n     * @throws OssException\n     * @return null\n     */\n    public function putBucketWebsite($bucket, $websiteConfig, $options = NULL)\n    {\n        $this->precheckCommon($bucket, NULL, $options, false);\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;\n        $options[self::OSS_OBJECT] = '/';\n        $options[self::OSS_SUB_RESOURCE] = 'website';\n        $options[self::OSS_CONTENT_TYPE] = 'application/xml';\n        $options[self::OSS_CONTENT] = $websiteConfig->serializeToXml();\n        $response = $this->auth($options);\n        $result = new PutSetDeleteResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * Gets the website config in the bucket\n     *\n     * @param string $bucket bucket name\n     * @param array $options\n     * @throws OssException\n     * @return WebsiteConfig\n     */\n    public function getBucketWebsite($bucket, $options = NULL)\n    {\n        $this->precheckCommon($bucket, NULL, $options, false);\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_METHOD] = self::OSS_HTTP_GET;\n        $options[self::OSS_OBJECT] = '/';\n        $options[self::OSS_SUB_RESOURCE] = 'website';\n        $response = $this->auth($options);\n        $result = new GetWebsiteResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * Deletes the website config in the bucket\n     *\n     * @param string $bucket bucket name\n     * @param array $options\n     * @throws OssException\n     * @return null\n     */\n    public function deleteBucketWebsite($bucket, $options = NULL)\n    {\n        $this->precheckCommon($bucket, NULL, $options, false);\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_METHOD] = self::OSS_HTTP_DELETE;\n        $options[self::OSS_OBJECT] = '/';\n        $options[self::OSS_SUB_RESOURCE] = 'website';\n        $response = $this->auth($options);\n        $result = new PutSetDeleteResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * Sets the cross-origin-resource-sharing (CORS) rule. It would overwrite the originl one.\n     *\n     * @param string $bucket bucket name\n     * @param CorsConfig $corsConfig CORS config. Check out the details from OSS API document\n     * @param array $options array\n     * @throws OssException\n     * @return null\n     */\n    public function putBucketCors($bucket, $corsConfig, $options = NULL)\n    {\n        $this->precheckCommon($bucket, NULL, $options, false);\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;\n        $options[self::OSS_OBJECT] = '/';\n        $options[self::OSS_SUB_RESOURCE] = 'cors';\n        $options[self::OSS_CONTENT_TYPE] = 'application/xml';\n        $options[self::OSS_CONTENT] = $corsConfig->serializeToXml();\n        $response = $this->auth($options);\n        $result = new PutSetDeleteResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * Gets the bucket CORS config\n     *\n     * @param string $bucket bucket name\n     * @param array $options\n     * @throws OssException\n     * @return CorsConfig\n     */\n    public function getBucketCors($bucket, $options = NULL)\n    {\n        $this->precheckCommon($bucket, NULL, $options, false);\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_METHOD] = self::OSS_HTTP_GET;\n        $options[self::OSS_OBJECT] = '/';\n        $options[self::OSS_SUB_RESOURCE] = 'cors';\n        $response = $this->auth($options);\n        $result = new GetCorsResult($response, __FUNCTION__);\n        return $result->getData();\n    }\n\n    /**\n     * Deletes the bucket's CORS config and disable the CORS on the bucket.\n     *\n     * @param string $bucket bucket name\n     * @param array $options\n     * @throws OssException\n     * @return null\n     */\n    public function deleteBucketCors($bucket, $options = NULL)\n    {\n        $this->precheckCommon($bucket, NULL, $options, false);\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_METHOD] = self::OSS_HTTP_DELETE;\n        $options[self::OSS_OBJECT] = '/';\n        $options[self::OSS_SUB_RESOURCE] = 'cors';\n        $response = $this->auth($options);\n        $result = new PutSetDeleteResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * Bind a CName for the bucket\n     *\n     * @param string $bucket bucket name\n     * @param string $cname\n     * @param array $options\n     * @throws OssException\n     * @return null\n     */\n    public function addBucketCname($bucket, $cname, $options = NULL)\n    {\n        $this->precheckCommon($bucket, NULL, $options, false);\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_METHOD] = self::OSS_HTTP_POST;\n        $options[self::OSS_OBJECT] = '/';\n        $options[self::OSS_SUB_RESOURCE] = 'cname';\n        $options[self::OSS_CONTENT_TYPE] = 'application/xml';\n        $cnameConfig = new CnameConfig();\n        $cnameConfig->addCname($cname);\n        $options[self::OSS_CONTENT] = $cnameConfig->serializeToXml();\n        $options[self::OSS_COMP] = 'add';\n\n        $response = $this->auth($options);\n        $result = new PutSetDeleteResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * Gets the binded CName list of the bucket\n     *\n     * @param string $bucket bucket name\n     * @param array $options\n     * @throws OssException\n     * @return CnameConfig\n     */\n    public function getBucketCname($bucket, $options = NULL)\n    {\n        $this->precheckCommon($bucket, NULL, $options, false);\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_METHOD] = self::OSS_HTTP_GET;\n        $options[self::OSS_OBJECT] = '/';\n        $options[self::OSS_SUB_RESOURCE] = 'cname';\n        $response = $this->auth($options);\n        $result = new GetCnameResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * Remove a CName binding from the bucket\n     *\n     * @param string $bucket bucket name\n     * @param CnameConfig $cnameConfig\n     * @param array $options\n     * @throws OssException\n     * @return null\n     */\n    public function deleteBucketCname($bucket, $cname, $options = NULL)\n    {\n        $this->precheckCommon($bucket, NULL, $options, false);\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_METHOD] = self::OSS_HTTP_POST;\n        $options[self::OSS_OBJECT] = '/';\n        $options[self::OSS_SUB_RESOURCE] = 'cname';\n        $options[self::OSS_CONTENT_TYPE] = 'application/xml';\n        $cnameConfig = new CnameConfig();\n        $cnameConfig->addCname($cname);\n        $options[self::OSS_CONTENT] = $cnameConfig->serializeToXml();\n        $options[self::OSS_COMP] = 'delete';\n\n        $response = $this->auth($options);\n        $result = new PutSetDeleteResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * Creates a Live Channel under a bucket\n     *\n     * @param string $bucket bucket name\n     * @param string channelName  $channelName\n     * @param LiveChannelConfig $channelConfig\n     * @param array $options\n     * @throws OssException\n     * @return LiveChannelInfo\n     */\n    public function putBucketLiveChannel($bucket, $channelName, $channelConfig, $options = NULL)\n    {\n        $this->precheckCommon($bucket, NULL, $options, false);\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;\n        $options[self::OSS_OBJECT] = $channelName;\n        $options[self::OSS_SUB_RESOURCE] = 'live';\n        $options[self::OSS_CONTENT_TYPE] = 'application/xml';\n        $options[self::OSS_CONTENT] = $channelConfig->serializeToXml();\n\n        $response = $this->auth($options);\n        $result = new PutLiveChannelResult($response);\n        $info = $result->getData();\n        $info->setName($channelName);\n        $info->setDescription($channelConfig->getDescription());\n        \n        return $info;\n    }\n\n    /**\n     * Sets the LiveChannel status\n     *\n     * @param string $bucket bucket name\n     * @param string channelName $channelName\n     * @param string channelStatus $channelStatus enabled or disabled\n     * @param array $options\n     * @throws OssException\n     * @return null \n     */\n    public function putLiveChannelStatus($bucket, $channelName, $channelStatus, $options = NULL)\n    {\n        $this->precheckCommon($bucket, NULL, $options, false);\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;\n        $options[self::OSS_OBJECT] = $channelName;\n        $options[self::OSS_SUB_RESOURCE] = 'live';\n        $options[self::OSS_LIVE_CHANNEL_STATUS] = $channelStatus;\n\n        $response = $this->auth($options);\n        $result = new PutSetDeleteResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * Gets the LiveChannel information by the channel name\n     *\n     * @param string $bucket bucket name\n     * @param string channelName $channelName\n     * @param array $options\n     * @throws OssException\n     * @return GetLiveChannelInfo\n     */\n    public function getLiveChannelInfo($bucket, $channelName, $options = NULL)\n    {\n        $this->precheckCommon($bucket, NULL, $options, false);\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_METHOD] = self::OSS_HTTP_GET;\n        $options[self::OSS_OBJECT] = $channelName;\n        $options[self::OSS_SUB_RESOURCE] = 'live';\n\n        $response = $this->auth($options);\n        $result = new GetLiveChannelInfoResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * Gets the status of LiveChannel\n     *\n     * @param string $bucket bucket name\n     * @param string channelName $channelName\n     * @param array $options\n     * @throws OssException\n     * @return GetLiveChannelStatus\n     */\n    public function getLiveChannelStatus($bucket, $channelName, $options = NULL)\n    {\n        $this->precheckCommon($bucket, NULL, $options, false);\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_METHOD] = self::OSS_HTTP_GET;\n        $options[self::OSS_OBJECT] = $channelName;\n        $options[self::OSS_SUB_RESOURCE] = 'live';\n        $options[self::OSS_COMP] = 'stat';\n      \n        $response = $this->auth($options);\n        $result = new GetLiveChannelStatusResult($response);\n        return $result->getData();\n    }\n\n     /**\n     * Gets the LiveChannel pushing streaming record\n     *\n     * @param string $bucket bucket name\n     * @param string channelName $channelName\n     * @param array $options\n     * @throws OssException\n     * @return GetLiveChannelHistory\n     */\n   public function getLiveChannelHistory($bucket, $channelName, $options = NULL)\n    {\n        $this->precheckCommon($bucket, NULL, $options, false);\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_METHOD] = self::OSS_HTTP_GET;\n        $options[self::OSS_OBJECT] = $channelName;\n        $options[self::OSS_SUB_RESOURCE] = 'live';\n        $options[self::OSS_COMP] = 'history';\n\n        $response = $this->auth($options);\n        $result = new GetLiveChannelHistoryResult($response);\n        return $result->getData();\n    }\n  \n    /**\n     *Gets the live channel list under a bucket.\n     *\n     * @param string $bucket bucket name\n     * @param array $options\n     * @throws OssException\n     * @return LiveChannelListInfo\n     */\n    public function listBucketLiveChannels($bucket, $options = NULL)\n    {\n        $this->precheckCommon($bucket, NULL, $options, false);\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_METHOD] = self::OSS_HTTP_GET;\n        $options[self::OSS_OBJECT] = '/';\n        $options[self::OSS_SUB_RESOURCE] = 'live';\n        $options[self::OSS_QUERY_STRING] = array(\n            'prefix' => isset($options['prefix']) ? $options['prefix'] : '',\n            'marker' => isset($options['marker']) ? $options['marker'] : '',\n            'max-keys' => isset($options['max-keys']) ? $options['max-keys'] : '',\n        );\n        $response = $this->auth($options);\n        $result = new ListLiveChannelResult($response);\n        $list = $result->getData();\n        $list->setBucketName($bucket);\n\n        return $list;\n    }\n\n    /**\n     * Creates a play list file for the LiveChannel\n     *\n     * @param string $bucket bucket name\n     * @param string channelName $channelName \n     * @param string $playlistName The playlist name, must end with \".m3u8\".\n     * @param array $setTime  startTime and EndTime in unix time. No more than 1 day.\n     * @throws OssException\n     * @return null\n     */\n    public function postVodPlaylist($bucket, $channelName, $playlistName, $setTime)\n    {\n        $this->precheckCommon($bucket, NULL, $options, false);\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_METHOD] = self::OSS_HTTP_POST;\n        $options[self::OSS_OBJECT] = $channelName . '/' . $playlistName;\n        $options[self::OSS_SUB_RESOURCE] = 'vod';\n        $options[self::OSS_LIVE_CHANNEL_END_TIME] = $setTime['EndTime'];\n        $options[self::OSS_LIVE_CHANNEL_START_TIME] = $setTime['StartTime'];\n       \n        $response = $this->auth($options);\n        $result = new PutSetDeleteResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * Deletes the Bucket LiveChannel\n     *\n     * @param string $bucket bucket name\n     * @param string channelName $channelName\n     * @param array $options\n     * @throws OssException\n     * @return null\n     */\n    public function deleteBucketLiveChannel($bucket, $channelName, $options = NULL)\n    {\n        $this->precheckCommon($bucket, NULL, $options, false);\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_METHOD] = self::OSS_HTTP_DELETE;\n        $options[self::OSS_OBJECT] = $channelName;\n        $options[self::OSS_SUB_RESOURCE] = 'live';\n\n        $response = $this->auth($options);\n        $result = new PutSetDeleteResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * Generates the signed pushing streaming url\n     *\n     * @param string $bucket bucket name\n     * @param string channelName $channelName\n     * @param int timeout timeout value in seconds\n     * @param array $options\n     * @throws OssException\n     * @return The signed pushing streaming url\n     */\n    public function signRtmpUrl($bucket, $channelName, $timeout = 60, $options = NULL)\n    {\n        $this->precheckCommon($bucket, $channelName, $options, false);\n        $expires = time() + $timeout;\n        $proto = 'rtmp://';\n        $hostname = $this->generateHostname($bucket);\n        $cano_params = '';\n        $query_items = array();\n        $params = isset($options['params']) ? $options['params'] : array();\n        uksort($params, 'strnatcasecmp');\n        foreach ($params as $key => $value) {\n            $cano_params = $cano_params . $key . ':' . $value . \"\\n\";\n            $query_items[] = rawurlencode($key) . '=' . rawurlencode($value);\n        }\n        $resource = '/' . $bucket . '/' . $channelName;\n\n        $string_to_sign = $expires . \"\\n\" . $cano_params . $resource;\n        $signature = base64_encode(hash_hmac('sha1', $string_to_sign, $this->accessKeySecret, true));\n\n        $query_items[] = 'OSSAccessKeyId=' . rawurlencode($this->accessKeyId);\n        $query_items[] = 'Expires=' . rawurlencode($expires);\n        $query_items[] = 'Signature=' . rawurlencode($signature);\n\n        return $proto . $hostname . '/live/' . $channelName . '?' . implode('&', $query_items);\n    }\n\n    /**\n     * Precheck the CORS request. Before sending a CORS request, a preflight request (OPTIONS) is sent with the specific origin.\n     * HTTP METHOD and headers information are sent to OSS as well for evaluating if the CORS request is allowed. \n     * \n     * Note: OSS could enable the CORS on the bucket by calling putBucketCors. Once CORS is enabled, the OSS could evaluate accordingto the preflight request.\n     *\n     * @param string $bucket bucket name\n     * @param string $object object name\n     * @param string $origin the origin of the request\n     * @param string $request_method The actual HTTP method which will be used in CORS request\n     * @param string $request_headers The actual HTTP headers which will be used in CORS request\n     * @param array $options\n     * @return array\n     * @throws OssException\n     * @link http://help.aliyun.com/document_detail/oss/api-reference/cors/OptionObject.html\n     */\n    public function optionsObject($bucket, $object, $origin, $request_method, $request_headers, $options = NULL)\n    {\n        $this->precheckCommon($bucket, NULL, $options, false);\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_METHOD] = self::OSS_HTTP_OPTIONS;\n        $options[self::OSS_OBJECT] = $object;\n        $options[self::OSS_HEADERS] = array(\n            self::OSS_OPTIONS_ORIGIN => $origin,\n            self::OSS_OPTIONS_REQUEST_HEADERS => $request_headers,\n            self::OSS_OPTIONS_REQUEST_METHOD => $request_method\n        );\n        $response = $this->auth($options);\n        $result = new HeaderResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * Sets the bucket's lifecycle config\n     *\n     * @param string $bucket bucket name\n     * @param LifecycleConfig $lifecycleConfig LifecycleConfig instance\n     * @param array $options\n     * @throws OssException\n     * @return null\n     */\n    public function putBucketLifecycle($bucket, $lifecycleConfig, $options = NULL)\n    {\n        $this->precheckCommon($bucket, NULL, $options, false);\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;\n        $options[self::OSS_OBJECT] = '/';\n        $options[self::OSS_SUB_RESOURCE] = 'lifecycle';\n        $options[self::OSS_CONTENT_TYPE] = 'application/xml';\n        $options[self::OSS_CONTENT] = $lifecycleConfig->serializeToXml();\n        $response = $this->auth($options);\n        $result = new PutSetDeleteResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * Gets bucket's lifecycle config\n     *\n     * @param string $bucket bucket name\n     * @param array $options\n     * @throws OssException\n     * @return LifecycleConfig\n     */\n    public function getBucketLifecycle($bucket, $options = NULL)\n    {\n        $this->precheckCommon($bucket, NULL, $options, false);\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_METHOD] = self::OSS_HTTP_GET;\n        $options[self::OSS_OBJECT] = '/';\n        $options[self::OSS_SUB_RESOURCE] = 'lifecycle';\n        $response = $this->auth($options);\n        $result = new GetLifecycleResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * Deletes the bucket's lifecycle config\n     *\n     * @param string $bucket bucket name\n     * @param array $options\n     * @throws OssException\n     * @return null\n     */\n    public function deleteBucketLifecycle($bucket, $options = NULL)\n    {\n        $this->precheckCommon($bucket, NULL, $options, false);\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_METHOD] = self::OSS_HTTP_DELETE;\n        $options[self::OSS_OBJECT] = '/';\n        $options[self::OSS_SUB_RESOURCE] = 'lifecycle';\n        $response = $this->auth($options);\n        $result = new PutSetDeleteResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * Sets a bucket's referer, which has a whitelist of referrer and specifies if empty referer is allowed.\n     * Checks out API document for more details about \"Bucket Referer\" \n     *\n     * @param string $bucket bucket name\n     * @param RefererConfig $refererConfig\n     * @param array $options\n     * @return ResponseCore\n     * @throws null\n     */\n    public function putBucketReferer($bucket, $refererConfig, $options = NULL)\n    {\n        $this->precheckCommon($bucket, NULL, $options, false);\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;\n        $options[self::OSS_OBJECT] = '/';\n        $options[self::OSS_SUB_RESOURCE] = 'referer';\n        $options[self::OSS_CONTENT_TYPE] = 'application/xml';\n        $options[self::OSS_CONTENT] = $refererConfig->serializeToXml();\n        $response = $this->auth($options);\n        $result = new PutSetDeleteResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * Gets the bucket's Referer\n     * Checks out API document for more details about \"Bucket Referer\" \n     *\n     * @param string $bucket bucket name\n     * @param array $options\n     * @throws OssException\n     * @return RefererConfig\n     */\n    public function getBucketReferer($bucket, $options = NULL)\n    {\n        $this->precheckCommon($bucket, NULL, $options, false);\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_METHOD] = self::OSS_HTTP_GET;\n        $options[self::OSS_OBJECT] = '/';\n        $options[self::OSS_SUB_RESOURCE] = 'referer';\n        $response = $this->auth($options);\n        $result = new GetRefererResult($response);\n        return $result->getData();\n    }\n\n\n    /**\n     * Set the size of the bucket,the unit is GB\n     * When the capacity of the bucket is bigger than the set, it's forbidden to continue writing\n     *\n     * @param string $bucket bucket name\n     * @param int $storageCapacity\n     * @param array $options\n     * @return ResponseCore\n     * @throws null\n     */\n    public function putBucketStorageCapacity($bucket, $storageCapacity, $options = NULL)\n    {\n        $this->precheckCommon($bucket, NULL, $options, false);\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;\n        $options[self::OSS_OBJECT] = '/';\n        $options[self::OSS_SUB_RESOURCE] = 'qos';\n        $options[self::OSS_CONTENT_TYPE] = 'application/xml';\n        $storageCapacityConfig = new StorageCapacityConfig($storageCapacity);\n        $options[self::OSS_CONTENT] = $storageCapacityConfig->serializeToXml();\n        $response = $this->auth($options);\n        $result = new PutSetDeleteResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * Get the capacity of the bucket, the unit is GB\n     *\n     * @param string $bucket bucket name\n     * @param array $options\n     * @throws OssException\n     * @return int\n     */\n    public function getBucketStorageCapacity($bucket, $options = NULL)\n    {\n        $this->precheckCommon($bucket, NULL, $options, false);\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_METHOD] = self::OSS_HTTP_GET;\n        $options[self::OSS_OBJECT] = '/';\n        $options[self::OSS_SUB_RESOURCE] = 'qos';\n        $response = $this->auth($options);\n        $result = new GetStorageCapacityResult($response);\n        return $result->getData();\n    }\n\n\n    /**\n     * Lists the bucket's object list (in ObjectListInfo)\n     *\n     * @param string $bucket\n     * @param array $options are defined below:\n     * $options = array(\n     *      'max-keys'  => specifies max object count to return. By default is 100 and max value could be 1000.\n     *      'prefix'    => specifies the key prefix the returned objects must have. Note that the returned keys still contain the prefix.\n     *      'delimiter' => The delimiter of object name for grouping object. When it's specified, listObjects will differeniate the object and folder. And it will return subfolder's objects.\n     *      'marker'    => The key of returned object must be greater than the 'marker'.\n     *)\n     * Prefix and marker are for filtering and paging. Their length must be less than 256 bytes\n     * @throws OssException\n     * @return ObjectListInfo\n     */\n    public function listObjects($bucket, $options = NULL)\n    {\n        $this->precheckCommon($bucket, NULL, $options, false);\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_METHOD] = self::OSS_HTTP_GET;\n        $options[self::OSS_OBJECT] = '/';\n        $options[self::OSS_HEADERS] = array(\n            self::OSS_DELIMITER => isset($options[self::OSS_DELIMITER]) ? $options[self::OSS_DELIMITER] : '/',\n            self::OSS_PREFIX => isset($options[self::OSS_PREFIX]) ? $options[self::OSS_PREFIX] : '',\n            self::OSS_MAX_KEYS => isset($options[self::OSS_MAX_KEYS]) ? $options[self::OSS_MAX_KEYS] : self::OSS_MAX_KEYS_VALUE,\n            self::OSS_MARKER => isset($options[self::OSS_MARKER]) ? $options[self::OSS_MARKER] : '',\n        );\n        $query = isset($options[self::OSS_QUERY_STRING]) ? $options[self::OSS_QUERY_STRING] : array();\n        $options[self::OSS_QUERY_STRING] = array_merge(\n            $query,\n            array(self::OSS_ENCODING_TYPE => self::OSS_ENCODING_TYPE_URL)\n        );\n\n        $response = $this->auth($options);\n        $result = new ListObjectsResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * Creates a virtual 'folder' in OSS. The name should not end with '/' because the method will append the name with a '/' anyway.\n     *\n     * Internal use only.\n     *\n     * @param string $bucket bucket name\n     * @param string $object object name\n     * @param array $options\n     * @return null\n     */\n    public function createObjectDir($bucket, $object, $options = NULL)\n    {\n        $this->precheckCommon($bucket, $object, $options);\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;\n        $options[self::OSS_OBJECT] = $object . '/';\n        $options[self::OSS_CONTENT_LENGTH] = array(self::OSS_CONTENT_LENGTH => 0);\n        $response = $this->auth($options);\n        $result = new PutSetDeleteResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * Uploads the $content object to OSS.\n     *\n     * @param string $bucket bucket name\n     * @param string $object objcet name\n     * @param string $content The content object\n     * @param array $options\n     * @return null\n     */\n    public function putObject($bucket, $object, $content, $options = NULL)\n    {\n        $this->precheckCommon($bucket, $object, $options);\n\n        $options[self::OSS_CONTENT] = $content;\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;\n        $options[self::OSS_OBJECT] = $object;\n\n        if (!isset($options[self::OSS_LENGTH])) {\n            $options[self::OSS_CONTENT_LENGTH] = strlen($options[self::OSS_CONTENT]);\n        } else {\n            $options[self::OSS_CONTENT_LENGTH] = $options[self::OSS_LENGTH];\n        }\n\n        $is_check_md5 = $this->isCheckMD5($options);\n        if ($is_check_md5) {\n        \t$content_md5 = base64_encode(md5($content, true));\n        \t$options[self::OSS_CONTENT_MD5] = $content_md5;\n        }\n        \n        if (!isset($options[self::OSS_CONTENT_TYPE])) {\n            $options[self::OSS_CONTENT_TYPE] = $this->getMimeType($object);\n        }\n        $response = $this->auth($options);\n        \n        if (isset($options[self::OSS_CALLBACK]) && !empty($options[self::OSS_CALLBACK])) {\n            $result = new CallbackResult($response);\n        } else {\n            $result = new PutSetDeleteResult($response);\n        }\n            \n        return $result->getData();\n    }\n\n\n    /**\n     * creates symlink\n     * @param string $bucket bucket name\n     * @param string $symlink symlink name\n     * @param string $targetObject targetObject name\n     * @param array $options\n     * @return null\n     */\n    public function putSymlink($bucket, $symlink ,$targetObject, $options = NULL)\n    {\n        $this->precheckCommon($bucket, $symlink, $options);\n\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;\n        $options[self::OSS_OBJECT] = $symlink;\n        $options[self::OSS_SUB_RESOURCE] = self::OSS_SYMLINK;\n        $options[self::OSS_HEADERS][self::OSS_SYMLINK_TARGET] = rawurlencode($targetObject);\n\n        $response = $this->auth($options);\n        $result = new PutSetDeleteResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * gets symlink\n     *@param string $bucket bucket name\n     * @param string $symlink symlink name\n     * @return null\n     */\n    public function getSymlink($bucket, $symlink)\n    {\n        $this->precheckCommon($bucket, $symlink, $options);\n\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_METHOD] = self::OSS_HTTP_GET;\n        $options[self::OSS_OBJECT] = $symlink;\n        $options[self::OSS_SUB_RESOURCE] = self::OSS_SYMLINK;\n\n        $response = $this->auth($options);\n        $result = new SymlinkResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * Uploads a local file\n     *\n     * @param string $bucket bucket name\n     * @param string $object object name\n     * @param string $file local file path\n     * @param array $options\n     * @return null\n     * @throws OssException\n     */\n    public function uploadFile($bucket, $object, $file, $options = NULL)\n    {\n        $this->precheckCommon($bucket, $object, $options);\n        OssUtil::throwOssExceptionWithMessageIfEmpty($file, \"file path is invalid\");\n        $file = OssUtil::encodePath($file);\n        if (!file_exists($file)) {\n            throw new OssException($file . \" file does not exist\");\n        }\n        $options[self::OSS_FILE_UPLOAD] = $file;\n        $file_size = filesize($options[self::OSS_FILE_UPLOAD]);\n        $is_check_md5 = $this->isCheckMD5($options);\n        if ($is_check_md5) {\n            $content_md5 = base64_encode(md5_file($options[self::OSS_FILE_UPLOAD], true));\n            $options[self::OSS_CONTENT_MD5] = $content_md5;\n        }\n        if (!isset($options[self::OSS_CONTENT_TYPE])) {\n            $options[self::OSS_CONTENT_TYPE] = $this->getMimeType($object, $file);\n        }\n        $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_OBJECT] = $object;\n        $options[self::OSS_CONTENT_LENGTH] = $file_size;\n        $response = $this->auth($options);\n        $result = new PutSetDeleteResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * Append the object with the content at the specified position.\n     * The specified position is typically the lengh of the current file.\n     * @param string $bucket bucket name\n     * @param string $object objcet name\n     * @param string $content content to append\n     * @param array $options\n     * @return int next append position\n     * @throws OssException\n     */\n    public function appendObject($bucket, $object, $content, $position, $options = NULL)\n    {\n        $this->precheckCommon($bucket, $object, $options);\n\n        $options[self::OSS_CONTENT] = $content;\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_METHOD] = self::OSS_HTTP_POST;\n        $options[self::OSS_OBJECT] = $object;\n        $options[self::OSS_SUB_RESOURCE] = 'append';\n        $options[self::OSS_POSITION] = strval($position);\n\n        if (!isset($options[self::OSS_LENGTH])) {\n            $options[self::OSS_CONTENT_LENGTH] = strlen($options[self::OSS_CONTENT]);\n        } else {\n            $options[self::OSS_CONTENT_LENGTH] = $options[self::OSS_LENGTH];\n        }\n        \n        $is_check_md5 = $this->isCheckMD5($options);\n        if ($is_check_md5) {\n        \t$content_md5 = base64_encode(md5($content, true));\n        \t$options[self::OSS_CONTENT_MD5] = $content_md5;\n        }\n\n        if (!isset($options[self::OSS_CONTENT_TYPE])) {\n            $options[self::OSS_CONTENT_TYPE] = $this->getMimeType($object);\n        }\n        $response = $this->auth($options);\n        $result = new AppendResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * Append the object with a local file\n     *\n     * @param string $bucket bucket name\n     * @param string $object object name\n     * @param string $file The local file path to append with\n     * @param array $options\n     * @return int next append position\n     * @throws OssException\n     */\n    public function appendFile($bucket, $object, $file, $position, $options = NULL)\n    {\n        $this->precheckCommon($bucket, $object, $options);\n\n        OssUtil::throwOssExceptionWithMessageIfEmpty($file, \"file path is invalid\");\n        $file = OssUtil::encodePath($file);\n        if (!file_exists($file)) {\n            throw new OssException($file . \" file does not exist\");\n        }\n        $options[self::OSS_FILE_UPLOAD] = $file;\n        $file_size = filesize($options[self::OSS_FILE_UPLOAD]);\n        $is_check_md5 = $this->isCheckMD5($options);\n        if ($is_check_md5) {\n            $content_md5 = base64_encode(md5_file($options[self::OSS_FILE_UPLOAD], true));\n            $options[self::OSS_CONTENT_MD5] = $content_md5;\n        }\n        if (!isset($options[self::OSS_CONTENT_TYPE])) {\n            $options[self::OSS_CONTENT_TYPE] = $this->getMimeType($object, $file);\n        }\n\n        $options[self::OSS_METHOD] = self::OSS_HTTP_POST;\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_OBJECT] = $object;\n        $options[self::OSS_CONTENT_LENGTH] = $file_size;\n        $options[self::OSS_SUB_RESOURCE] = 'append';\n        $options[self::OSS_POSITION] = strval($position);\n\n        $response = $this->auth($options);\n        $result = new AppendResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * Copy from an existing OSS object to another OSS object. If the target object exists already, it will be overwritten.\n     *\n     * @param string $fromBucket Source bucket name\n     * @param string $fromObject Source object name\n     * @param string $toBucket Target bucket name\n     * @param string $toObject Target object name\n     * @param array $options\n     * @return null\n     * @throws OssException\n     */\n    public function copyObject($fromBucket, $fromObject, $toBucket, $toObject, $options = NULL)\n    {\n        $this->precheckCommon($fromBucket, $fromObject, $options);\n        $this->precheckCommon($toBucket, $toObject, $options);\n        $options[self::OSS_BUCKET] = $toBucket;\n        $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;\n        $options[self::OSS_OBJECT] = $toObject;\n        if (isset($options[self::OSS_HEADERS])) {\n            $options[self::OSS_HEADERS][self::OSS_OBJECT_COPY_SOURCE] = '/' . $fromBucket . '/' . $fromObject;\n        } else {\n            $options[self::OSS_HEADERS] = array(self::OSS_OBJECT_COPY_SOURCE => '/' . $fromBucket . '/' . $fromObject);\n        }\n        $response = $this->auth($options);\n        $result = new CopyObjectResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * Gets Object metadata\n     *\n     * @param string $bucket bucket name\n     * @param string $object object name\n     * @param string $options Checks out the SDK document for the detail\n     * @return array\n     */\n    public function getObjectMeta($bucket, $object, $options = NULL)\n    {\n        $this->precheckCommon($bucket, $object, $options);\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_METHOD] = self::OSS_HTTP_HEAD;\n        $options[self::OSS_OBJECT] = $object;\n        $response = $this->auth($options);\n        $result = new HeaderResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * Deletes a object\n     *\n     * @param string $bucket bucket name\n     * @param string $object object name\n     * @param array $options\n     * @return null\n     */\n    public function deleteObject($bucket, $object, $options = NULL)\n    {\n        $this->precheckCommon($bucket, $object, $options);\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_METHOD] = self::OSS_HTTP_DELETE;\n        $options[self::OSS_OBJECT] = $object;\n        $response = $this->auth($options);\n        $result = new PutSetDeleteResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * Deletes multiple objects in a bucket\n     *\n     * @param string $bucket bucket name\n     * @param array $objects object list\n     * @param array $options\n     * @return ResponseCore\n     * @throws null\n     */\n    public function deleteObjects($bucket, $objects, $options = null)\n    {\n        $this->precheckCommon($bucket, NULL, $options, false);\n        if (!is_array($objects) || !$objects) {\n            throw new OssException('objects must be array');\n        }\n        $options[self::OSS_METHOD] = self::OSS_HTTP_POST;\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_OBJECT] = '/';\n        $options[self::OSS_SUB_RESOURCE] = 'delete';\n        $options[self::OSS_CONTENT_TYPE] = 'application/xml';\n        $quiet = 'false';\n        if (isset($options['quiet'])) {\n            if (is_bool($options['quiet'])) { //Boolean\n                $quiet = $options['quiet'] ? 'true' : 'false';\n            } elseif (is_string($options['quiet'])) { // string\n                $quiet = ($options['quiet'] === 'true') ? 'true' : 'false';\n            }\n        }\n        $xmlBody = OssUtil::createDeleteObjectsXmlBody($objects, $quiet);\n        $options[self::OSS_CONTENT] = $xmlBody;\n        $response = $this->auth($options);\n        $result = new DeleteObjectsResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * Gets Object content\n     *\n     * @param string $bucket bucket name\n     * @param string $object object name\n     * @param array $options It must contain ALIOSS::OSS_FILE_DOWNLOAD. And ALIOSS::OSS_RANGE is optional and empty means to download the whole file.\n     * @return string\n     */\n    public function getObject($bucket, $object, $options = NULL)\n    {\n        $this->precheckCommon($bucket, $object, $options);\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_METHOD] = self::OSS_HTTP_GET;\n        $options[self::OSS_OBJECT] = $object;\n        if (isset($options[self::OSS_LAST_MODIFIED])) {\n            $options[self::OSS_HEADERS][self::OSS_IF_MODIFIED_SINCE] = $options[self::OSS_LAST_MODIFIED];\n            unset($options[self::OSS_LAST_MODIFIED]);\n        }\n        if (isset($options[self::OSS_ETAG])) {\n            $options[self::OSS_HEADERS][self::OSS_IF_NONE_MATCH] = $options[self::OSS_ETAG];\n            unset($options[self::OSS_ETAG]);\n        }\n        if (isset($options[self::OSS_RANGE])) {\n            $range = $options[self::OSS_RANGE];\n            $options[self::OSS_HEADERS][self::OSS_RANGE] = \"bytes=$range\";\n            unset($options[self::OSS_RANGE]);\n        }\n        $response = $this->auth($options);\n        $result = new BodyResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * Checks if the object exists\n     * It's implemented by getObjectMeta().\n     *\n     * @param string $bucket bucket name\n     * @param string $object object name\n     * @param array $options\n     * @return bool True:object exists; False:object does not exist\n     */\n    public function doesObjectExist($bucket, $object, $options = NULL)\n    {\n        $this->precheckCommon($bucket, $object, $options);\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_METHOD] = self::OSS_HTTP_HEAD;\n        $options[self::OSS_OBJECT] = $object;\n        $response = $this->auth($options);\n        $result = new ExistResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * Object reading for Archive type\n     * Use Restore to enable the server to perform the thawing task\n     *\n     * @param string $bucket bucket name\n     * @param string $object object name\n     * @return null\n     * @throws OssException\n     */\n    public function restoreObject($bucket, $object, $options = NULL)\n    {\n        $this->precheckCommon($bucket, $object, $options);\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_METHOD] = self::OSS_HTTP_POST;\n        $options[self::OSS_OBJECT] = $object;\n        $options[self::OSS_SUB_RESOURCE] = self::OSS_RESTORE;\n        $response = $this->auth($options);\n        $result = new PutSetDeleteResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * Gets the part size according to the preferred part size.\n     * If the specified part size is too small or too big, it will return a min part or max part size instead.\n     * Otherwise returns the specified part size.\n     * @param int $partSize\n     * @return int\n     */\n    private function computePartSize($partSize)\n    {\n        $partSize = (integer)$partSize;\n        if ($partSize <= self::OSS_MIN_PART_SIZE) {\n            $partSize = self::OSS_MIN_PART_SIZE;\n        } elseif ($partSize > self::OSS_MAX_PART_SIZE) {\n            $partSize = self::OSS_MAX_PART_SIZE;\n        }\n        return $partSize;\n    }\n\n    /**\n     * Computes the parts count, size and start position according to the file size and the part size.\n     * It must be only called by upload_Part().\n     *\n     * @param integer $file_size File size\n     * @param integer $partSize part大小,part size. Default is 5MB\n     * @return array An array contains key-value pairs--the key is `seekTo`and value is `length`.\n     */\n    public function generateMultiuploadParts($file_size, $partSize = 5242880)\n    {\n        $i = 0;\n        $size_count = $file_size;\n        $values = array();\n        $partSize = $this->computePartSize($partSize);\n        while ($size_count > 0) {\n            $size_count -= $partSize;\n            $values[] = array(\n                self::OSS_SEEK_TO => ($partSize * $i),\n                self::OSS_LENGTH => (($size_count > 0) ? $partSize : ($size_count + $partSize)),\n            );\n            $i++;\n        }\n        return $values;\n    }\n\n    /**\n     * Initialize a multi-part upload\n     *\n     * @param string $bucket bucket name\n     * @param string $object object name\n     * @param array $options Key-Value array\n     * @throws OssException\n     * @return string returns uploadid\n     */\n    public function initiateMultipartUpload($bucket, $object, $options = NULL)\n    {\n        $this->precheckCommon($bucket, $object, $options);\n        $options[self::OSS_METHOD] = self::OSS_HTTP_POST;\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_OBJECT] = $object;\n        $options[self::OSS_SUB_RESOURCE] = 'uploads';\n        $options[self::OSS_CONTENT] = '';\n\n        if (!isset($options[self::OSS_CONTENT_TYPE])) {\n            $options[self::OSS_CONTENT_TYPE] = $this->getMimeType($object);\n        }\n        if (!isset($options[self::OSS_HEADERS])) {\n            $options[self::OSS_HEADERS] = array();\n        }\n        $response = $this->auth($options);\n        $result = new InitiateMultipartUploadResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * Upload a part in a multiparts upload.\n     *\n     * @param string $bucket bucket name\n     * @param string $object object name\n     * @param string $uploadId\n     * @param array $options Key-Value array\n     * @return string eTag\n     * @throws OssException\n     */\n    public function uploadPart($bucket, $object, $uploadId, $options = null)\n    {\n        $this->precheckCommon($bucket, $object, $options);\n        $this->precheckParam($options, self::OSS_FILE_UPLOAD, __FUNCTION__);\n        $this->precheckParam($options, self::OSS_PART_NUM, __FUNCTION__);\n\n        $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_OBJECT] = $object;\n        $options[self::OSS_UPLOAD_ID] = $uploadId;\n\n        if (isset($options[self::OSS_LENGTH])) {\n            $options[self::OSS_CONTENT_LENGTH] = $options[self::OSS_LENGTH];\n        }\n        $response = $this->auth($options);\n        $result = new UploadPartResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * Gets the uploaded parts.\n     *\n     * @param string $bucket bucket name\n     * @param string $object object name\n     * @param string $uploadId uploadId\n     * @param array $options Key-Value array\n     * @return ListPartsInfo\n     * @throws OssException\n     */\n    public function listParts($bucket, $object, $uploadId, $options = null)\n    {\n        $this->precheckCommon($bucket, $object, $options);\n        $options[self::OSS_METHOD] = self::OSS_HTTP_GET;\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_OBJECT] = $object;\n        $options[self::OSS_UPLOAD_ID] = $uploadId;\n        $options[self::OSS_QUERY_STRING] = array();\n        foreach (array('max-parts', 'part-number-marker') as $param) {\n            if (isset($options[$param])) {\n                $options[self::OSS_QUERY_STRING][$param] = $options[$param];\n                unset($options[$param]);\n            }\n        }\n        $response = $this->auth($options);\n        $result = new ListPartsResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * Abort a multiparts upload\n     *\n     * @param string $bucket bucket name\n     * @param string $object object name\n     * @param string $uploadId uploadId\n     * @param array $options Key-Value name\n     * @return null\n     * @throws OssException\n     */\n    public function abortMultipartUpload($bucket, $object, $uploadId, $options = NULL)\n    {\n        $this->precheckCommon($bucket, $object, $options);\n        $options[self::OSS_METHOD] = self::OSS_HTTP_DELETE;\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_OBJECT] = $object;\n        $options[self::OSS_UPLOAD_ID] = $uploadId;\n        $response = $this->auth($options);\n        $result = new PutSetDeleteResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * Completes a multiparts upload, after all parts are uploaded.\n     *\n     * @param string $bucket bucket name\n     * @param string $object object name\n     * @param string $uploadId uploadId\n     * @param array $listParts array( array(\"PartNumber\"=> int, \"ETag\"=>string))\n     * @param array $options Key-Value array\n     * @throws OssException\n     * @return null\n     */\n    public function completeMultipartUpload($bucket, $object, $uploadId, $listParts, $options = NULL)\n    {\n        $this->precheckCommon($bucket, $object, $options);\n        $options[self::OSS_METHOD] = self::OSS_HTTP_POST;\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_OBJECT] = $object;\n        $options[self::OSS_UPLOAD_ID] = $uploadId;\n        $options[self::OSS_CONTENT_TYPE] = 'application/xml';\n        if (!is_array($listParts)) {\n            throw new OssException(\"listParts must be array type\");\n        }\n        $options[self::OSS_CONTENT] = OssUtil::createCompleteMultipartUploadXmlBody($listParts);\n        $response = $this->auth($options);\n        if (isset($options[self::OSS_CALLBACK]) && !empty($options[self::OSS_CALLBACK])) {\n            $result = new CallbackResult($response);\n        } else {\n            $result = new PutSetDeleteResult($response);\n        }\n        return $result->getData();\n    }\n\n    /**\n     * Lists all ongoing multipart upload events, which means all initialized but not completed or aborted multipart uploads.\n     *\n     * @param string $bucket bucket\n     * @param array $options key-value array--expected keys are 'delimiter', 'key-marker', 'max-uploads', 'prefix', 'upload-id-marker'\n     * @throws OssException\n     * @return ListMultipartUploadInfo\n     */\n    public function listMultipartUploads($bucket, $options = null)\n    {\n        $this->precheckCommon($bucket, NULL, $options, false);\n        $options[self::OSS_METHOD] = self::OSS_HTTP_GET;\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_OBJECT] = '/';\n        $options[self::OSS_SUB_RESOURCE] = 'uploads';\n\n        foreach (array('delimiter', 'key-marker', 'max-uploads', 'prefix', 'upload-id-marker') as $param) {\n            if (isset($options[$param])) {\n                $options[self::OSS_QUERY_STRING][$param] = $options[$param];\n                unset($options[$param]);\n            }\n        }\n        $query = isset($options[self::OSS_QUERY_STRING]) ? $options[self::OSS_QUERY_STRING] : array();\n        $options[self::OSS_QUERY_STRING] = array_merge(\n            $query,\n            array(self::OSS_ENCODING_TYPE => self::OSS_ENCODING_TYPE_URL)\n        );\n\n        $response = $this->auth($options);\n        $result = new ListMultipartUploadResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * Copy an existing file as a part\n     *\n     * @param string $fromBucket source bucket name\n     * @param string $fromObject source object name\n     * @param string $toBucket target bucket name\n     * @param string $toObject target object name\n     * @param int $partNumber Part number\n     * @param string $uploadId Upload Id\n     * @param array $options Key-Value array---it should have 'start' or 'end' key to specify the range of the source object to copy. If it's not specifed, the whole object is copied.\n     * @return null\n     * @throws OssException\n     */\n    public function uploadPartCopy($fromBucket, $fromObject, $toBucket, $toObject, $partNumber, $uploadId, $options = NULL)\n    {\n        $this->precheckCommon($fromBucket, $fromObject, $options);\n        $this->precheckCommon($toBucket, $toObject, $options);\n\n        //If $options['isFullCopy'] is not set, copy from the beginning\n        $start_range = \"0\";\n        if (isset($options['start'])) {\n            $start_range = $options['start'];\n        }\n        $end_range = \"\";\n        if (isset($options['end'])) {\n            $end_range = $options['end'];\n        }\n        $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;\n        $options[self::OSS_BUCKET] = $toBucket;\n        $options[self::OSS_OBJECT] = $toObject;\n        $options[self::OSS_PART_NUM] = $partNumber;\n        $options[self::OSS_UPLOAD_ID] = $uploadId;\n\n        if (!isset($options[self::OSS_HEADERS])) {\n            $options[self::OSS_HEADERS] = array();\n        }\n\n        $options[self::OSS_HEADERS][self::OSS_OBJECT_COPY_SOURCE] = '/' . $fromBucket . '/' . $fromObject;\n        $options[self::OSS_HEADERS][self::OSS_OBJECT_COPY_SOURCE_RANGE] = \"bytes=\" . $start_range . \"-\" . $end_range;\n        $response = $this->auth($options);\n        $result = new UploadPartResult($response);\n        return $result->getData();\n    }\n\n    /**\n     * A higher level API for uploading a file with multipart upload. It consists of initialization, parts upload and completion.\n     *\n     * @param string $bucket bucket name\n     * @param string $object object name\n     * @param string $file The local file to upload\n     * @param array $options Key-Value array\n     * @return null\n     * @throws OssException\n     */\n    public function multiuploadFile($bucket, $object, $file, $options = null)\n    {\n        $this->precheckCommon($bucket, $object, $options);\n        if (isset($options[self::OSS_LENGTH])) {\n            $options[self::OSS_CONTENT_LENGTH] = $options[self::OSS_LENGTH];\n            unset($options[self::OSS_LENGTH]);\n        }\n        if (empty($file)) {\n            throw new OssException(\"parameter invalid, file is empty\");\n        }\n        $uploadFile = OssUtil::encodePath($file);\n        if (!isset($options[self::OSS_CONTENT_TYPE])) {\n            $options[self::OSS_CONTENT_TYPE] = $this->getMimeType($object, $uploadFile);\n        }\n\n        $upload_position = isset($options[self::OSS_SEEK_TO]) ? (integer)$options[self::OSS_SEEK_TO] : 0;\n\n        if (isset($options[self::OSS_CONTENT_LENGTH])) {\n            $upload_file_size = (integer)$options[self::OSS_CONTENT_LENGTH];\n        } else {\n            $upload_file_size = filesize($uploadFile);\n            if ($upload_file_size !== false) {\n                $upload_file_size -= $upload_position;\n            }\n        }\n\n        if ($upload_position === false || !isset($upload_file_size) || $upload_file_size === false || $upload_file_size < 0) {\n            throw new OssException('The size of `fileUpload` cannot be determined in ' . __FUNCTION__ . '().');\n        }\n        // Computes the part size and assign it to options.\n        if (isset($options[self::OSS_PART_SIZE])) {\n            $options[self::OSS_PART_SIZE] = $this->computePartSize($options[self::OSS_PART_SIZE]);\n        } else {\n            $options[self::OSS_PART_SIZE] = self::OSS_MID_PART_SIZE;\n        }\n\n        $is_check_md5 = $this->isCheckMD5($options);\n        // if the file size is less than part size, use simple file upload.\n        if ($upload_file_size < $options[self::OSS_PART_SIZE] && !isset($options[self::OSS_UPLOAD_ID])) {\n            return $this->uploadFile($bucket, $object, $uploadFile, $options);\n        }\n\n        // Using multipart upload, initialize if no OSS_UPLOAD_ID is specified in options.\n        if (isset($options[self::OSS_UPLOAD_ID])) {\n            $uploadId = $options[self::OSS_UPLOAD_ID];\n        } else {\n            // initialize\n            $uploadId = $this->initiateMultipartUpload($bucket, $object, $options);\n        }\n\n        // generates the parts information and upload them one by one\n        $pieces = $this->generateMultiuploadParts($upload_file_size, (integer)$options[self::OSS_PART_SIZE]);\n        $response_upload_part = array();\n        foreach ($pieces as $i => $piece) {\n            $from_pos = $upload_position + (integer)$piece[self::OSS_SEEK_TO];\n            $to_pos = (integer)$piece[self::OSS_LENGTH] + $from_pos - 1;\n            $up_options = array(\n                self::OSS_FILE_UPLOAD => $uploadFile,\n                self::OSS_PART_NUM => ($i + 1),\n                self::OSS_SEEK_TO => $from_pos,\n                self::OSS_LENGTH => $to_pos - $from_pos + 1,\n                self::OSS_CHECK_MD5 => $is_check_md5,\n            );\n            if ($is_check_md5) {\n                $content_md5 = OssUtil::getMd5SumForFile($uploadFile, $from_pos, $to_pos);\n                $up_options[self::OSS_CONTENT_MD5] = $content_md5;\n            }\n            $response_upload_part[] = $this->uploadPart($bucket, $object, $uploadId, $up_options);\n        }\n\n        $uploadParts = array();\n        foreach ($response_upload_part as $i => $etag) {\n            $uploadParts[] = array(\n                'PartNumber' => ($i + 1),\n                'ETag' => $etag,\n            );\n        }\n        return $this->completeMultipartUpload($bucket, $object, $uploadId, $uploadParts);\n    }\n\n    /**\n     * Uploads the local directory to the specified bucket into specified folder (prefix)\n     *\n     * @param string $bucket bucket name\n     * @param string $prefix The object key prefix. Typically it's folder name. The name should not end with '/' as the API appends it automatically.\n     * @param string $localDirectory The local directory to upload\n     * @param string $exclude To excluded directories\n     * @param bool $recursive Recursive flag. True: Recursively upload all datas under the local directory; False: only upload first layer's files.\n     * @param bool $checkMd5\n     * @return array Returns two list: array(\"succeededList\" => array(\"object\"), \"failedList\" => array(\"object\"=>\"errorMessage\"))\n     * @throws OssException\n     */\n    public function uploadDir($bucket, $prefix, $localDirectory, $exclude = '.|..|.svn|.git', $recursive = false, $checkMd5 = true)\n    {\n        $retArray = array(\"succeededList\" => array(), \"failedList\" => array());\n        if (empty($bucket)) throw new OssException(\"parameter error, bucket is empty\");\n        if (!is_string($prefix)) throw new OssException(\"parameter error, prefix is not string\");\n        if (empty($localDirectory)) throw new OssException(\"parameter error, localDirectory is empty\");\n        $directory = $localDirectory;\n        $directory = OssUtil::encodePath($directory);\n        //If it's not the local directory, throw OSSException.\n        if (!is_dir($directory)) {\n            throw new OssException('parameter error: ' . $directory . ' is not a directory, please check it');\n        }\n        //read directory\n        $file_list_array = OssUtil::readDir($directory, $exclude, $recursive);\n        if (!$file_list_array) {\n            throw new OssException($directory . ' is empty...');\n        }\n        foreach ($file_list_array as $k => $item) {\n            if (is_dir($item['path'])) {\n                continue;\n            }\n            $options = array(\n                self::OSS_PART_SIZE => self::OSS_MIN_PART_SIZE,\n                self::OSS_CHECK_MD5 => $checkMd5,\n            );\n            $realObject = (!empty($prefix) ? $prefix . '/' : '') . $item['file'];\n\n            try {\n                $this->multiuploadFile($bucket, $realObject, $item['path'], $options);\n                $retArray[\"succeededList\"][] = $realObject;\n            } catch (OssException $e) {\n                $retArray[\"failedList\"][$realObject] = $e->getMessage();\n            }\n        }\n        return $retArray;\n    }\n\n    /**\n     * Sign URL with specified expiration time in seconds (timeout) and HTTP method.\n     * The signed URL could be used to access the object directly.\n     *\n     * @param string $bucket\n     * @param string $object\n     * @param int $timeout expiration time in seconds.\n     * @param string $method\n     * @param array $options Key-Value array\n     * @return string\n     * @throws OssException\n     */\n    public function signUrl($bucket, $object, $timeout = 60, $method = self::OSS_HTTP_GET, $options = NULL)\n    {\n        $this->precheckCommon($bucket, $object, $options);\n        //method\n        if (self::OSS_HTTP_GET !== $method && self::OSS_HTTP_PUT !== $method) {\n            throw new OssException(\"method is invalid\");\n        }\n        $options[self::OSS_BUCKET] = $bucket;\n        $options[self::OSS_OBJECT] = $object;\n        $options[self::OSS_METHOD] = $method;\n        if (!isset($options[self::OSS_CONTENT_TYPE])) {\n            $options[self::OSS_CONTENT_TYPE] = '';\n        }\n        $timeout = time() + $timeout;\n        $options[self::OSS_PREAUTH] = $timeout;\n        $options[self::OSS_DATE] = $timeout;\n        $this->setSignStsInUrl(true);\n        return $this->auth($options);\n    }\n\n    /**\n     * validates options. Create a empty array if it's NULL.\n     *\n     * @param array $options\n     * @throws OssException\n     */\n    private function precheckOptions(&$options)\n    {\n        OssUtil::validateOptions($options);\n        if (!$options) {\n            $options = array();\n        }\n    }\n\n    /**\n     * Validates bucket parameter\n     *\n     * @param string $bucket\n     * @param string $errMsg\n     * @throws OssException\n     */\n    private function precheckBucket($bucket, $errMsg = 'bucket is not allowed empty')\n    {\n        OssUtil::throwOssExceptionWithMessageIfEmpty($bucket, $errMsg);\n    }\n\n    /**\n     * validates object parameter\n     *\n     * @param string $object\n     * @throws OssException\n     */\n    private function precheckObject($object)\n    {\n        OssUtil::throwOssExceptionWithMessageIfEmpty($object, \"object name is empty\");\n    }\n\n    /**\n     * 校验option restore\n     *\n     * @param string $restore\n     * @throws OssException\n     */\n    private function precheckStorage($storage)\n    {\n        if (is_string($storage)) {\n            switch ($storage) {\n                case self::OSS_STORAGE_ARCHIVE:\n                    return;\n                case self::OSS_STORAGE_IA:\n                    return;\n                case self::OSS_STORAGE_STANDARD:\n                    return;\n                default:\n                    break;\n            }\n        }\n        throw new OssException('storage name is invalid');\n    }\n\n    /**\n     * Validates bucket,options parameters and optionally validate object parameter.\n     *\n     * @param string $bucket\n     * @param string $object\n     * @param array $options\n     * @param bool $isCheckObject\n     */\n    private function precheckCommon($bucket, $object, &$options, $isCheckObject = true)\n    {\n        if ($isCheckObject) {\n            $this->precheckObject($object);\n        }\n        $this->precheckOptions($options);\n        $this->precheckBucket($bucket);\n    }\n\n    /**\n     * checks parameters\n     *\n     * @param array $options\n     * @param string $param\n     * @param string $funcName\n     * @throws OssException\n     */\n    private function precheckParam($options, $param, $funcName)\n    {\n        if (!isset($options[$param])) {\n            throw new OssException('The `' . $param . '` options is required in ' . $funcName . '().');\n        }\n    }\n\n    /**\n     * Checks md5\n     *\n     * @param array $options\n     * @return bool|null\n     */\n    private function isCheckMD5($options)\n    {\n        return $this->getValue($options, self::OSS_CHECK_MD5, false, true, true);\n    }\n\n    /**\n     * Gets value of the specified key from the options \n     *\n     * @param array $options\n     * @param string $key\n     * @param string $default\n     * @param bool $isCheckEmpty\n     * @param bool $isCheckBool\n     * @return bool|null\n     */\n    private function getValue($options, $key, $default = NULL, $isCheckEmpty = false, $isCheckBool = false)\n    {\n        $value = $default;\n        if (isset($options[$key])) {\n            if ($isCheckEmpty) {\n                if (!empty($options[$key])) {\n                    $value = $options[$key];\n                }\n            } else {\n                $value = $options[$key];\n            }\n            unset($options[$key]);\n        }\n        if ($isCheckBool) {\n            if ($value !== true && $value !== false) {\n                $value = false;\n            }\n        }\n        return $value;\n    }\n\n    /**\n     * Gets mimetype\n     *\n     * @param string $object\n     * @return string\n     */\n    private function getMimeType($object, $file = null)\n    {\n        if (!is_null($file)) {\n            $type = MimeTypes::getMimetype($file);\n            if (!is_null($type)) {\n                return $type;\n            }\n        }\n\n        $type = MimeTypes::getMimetype($object);\n        if (!is_null($type)) {\n            return $type;\n        }\n\n        return self::DEFAULT_CONTENT_TYPE;\n    }\n\n    /**\n     * Validates and executes the request according to OSS API protocol.\n     *\n     * @param array $options\n     * @return ResponseCore\n     * @throws OssException\n     * @throws RequestCore_Exception\n     */\n    private function auth($options)\n    {\n        OssUtil::validateOptions($options);\n        //Validates bucket, not required for list_bucket\n        $this->authPrecheckBucket($options);\n        //Validates object\n        $this->authPrecheckObject($options);\n        //object name encoding must be UTF-8\n        $this->authPrecheckObjectEncoding($options);\n        //Validates ACL\n        $this->authPrecheckAcl($options);\n        // Should https or http be used?\n        $scheme = $this->useSSL ? 'https://' : 'http://';\n        // gets the host name. If the host name is public domain or private domain, form a third level domain by prefixing the bucket name on the domain name.\n        $hostname = $this->generateHostname($options[self::OSS_BUCKET]);\n        $string_to_sign = '';\n        $headers = $this->generateHeaders($options, $hostname);\n        $signable_query_string_params = $this->generateSignableQueryStringParam($options);\n        $signable_query_string = OssUtil::toQueryString($signable_query_string_params);\n        $resource_uri = $this->generateResourceUri($options);\n        //Generates the URL (add query parameters)\n        $conjunction = '?';\n        $non_signable_resource = '';\n        if (isset($options[self::OSS_SUB_RESOURCE])) {\n            $conjunction = '&';\n        }\n        if ($signable_query_string !== '') {\n            $signable_query_string = $conjunction . $signable_query_string;\n            $conjunction = '&';\n        }\n        $query_string = $this->generateQueryString($options);\n        if ($query_string !== '') {\n            $non_signable_resource .= $conjunction . $query_string;\n            $conjunction = '&';\n        }\n        $this->requestUrl = $scheme . $hostname . $resource_uri . $signable_query_string . $non_signable_resource;\n\n        //Creates the request\n        $request = new RequestCore($this->requestUrl, $this->requestProxy);\n        $request->set_useragent($this->generateUserAgent());\n        // Streaming uploads\n        if (isset($options[self::OSS_FILE_UPLOAD])) {\n            if (is_resource($options[self::OSS_FILE_UPLOAD])) {\n                $length = null;\n\n                if (isset($options[self::OSS_CONTENT_LENGTH])) {\n                    $length = $options[self::OSS_CONTENT_LENGTH];\n                } elseif (isset($options[self::OSS_SEEK_TO])) {\n                    $stats = fstat($options[self::OSS_FILE_UPLOAD]);\n                    if ($stats && $stats[self::OSS_SIZE] >= 0) {\n                        $length = $stats[self::OSS_SIZE] - (integer)$options[self::OSS_SEEK_TO];\n                    }\n                }\n                $request->set_read_stream($options[self::OSS_FILE_UPLOAD], $length);\n            } else {\n                $request->set_read_file($options[self::OSS_FILE_UPLOAD]);\n                $length = $request->read_stream_size;\n                if (isset($options[self::OSS_CONTENT_LENGTH])) {\n                    $length = $options[self::OSS_CONTENT_LENGTH];\n                } elseif (isset($options[self::OSS_SEEK_TO]) && isset($length)) {\n                    $length -= (integer)$options[self::OSS_SEEK_TO];\n                }\n                $request->set_read_stream_size($length);\n            }\n        }\n        if (isset($options[self::OSS_SEEK_TO])) {\n            $request->set_seek_position((integer)$options[self::OSS_SEEK_TO]);\n        }\n        if (isset($options[self::OSS_FILE_DOWNLOAD])) {\n            if (is_resource($options[self::OSS_FILE_DOWNLOAD])) {\n                $request->set_write_stream($options[self::OSS_FILE_DOWNLOAD]);\n            } else {\n                $request->set_write_file($options[self::OSS_FILE_DOWNLOAD]);\n            }\n        }\n\n        if (isset($options[self::OSS_METHOD])) {\n            $request->set_method($options[self::OSS_METHOD]);\n            $string_to_sign .= $options[self::OSS_METHOD] . \"\\n\";\n        }\n\n        if (isset($options[self::OSS_CONTENT])) {\n            $request->set_body($options[self::OSS_CONTENT]);\n            if ($headers[self::OSS_CONTENT_TYPE] === 'application/x-www-form-urlencoded') {\n                $headers[self::OSS_CONTENT_TYPE] = 'application/octet-stream';\n            }\n\n            $headers[self::OSS_CONTENT_LENGTH] = strlen($options[self::OSS_CONTENT]);\n            $headers[self::OSS_CONTENT_MD5] = base64_encode(md5($options[self::OSS_CONTENT], true));\n        }\n\n        if (isset($options[self::OSS_CALLBACK])) {\n            $headers[self::OSS_CALLBACK] = base64_encode($options[self::OSS_CALLBACK]);\n        }\n        if (isset($options[self::OSS_CALLBACK_VAR])) {\n            $headers[self::OSS_CALLBACK_VAR] = base64_encode($options[self::OSS_CALLBACK_VAR]);\n        }\n\n        if (!isset($headers[self::OSS_ACCEPT_ENCODING])) {\n            $headers[self::OSS_ACCEPT_ENCODING] = '';\n        }\n\n        uksort($headers, 'strnatcasecmp');\n\n        foreach ($headers as $header_key => $header_value) {\n            $header_value = str_replace(array(\"\\r\", \"\\n\"), '', $header_value);\n            if ($header_value !== '' || $header_key === self::OSS_ACCEPT_ENCODING) {\n                $request->add_header($header_key, $header_value);\n            }\n\n            if (\n                strtolower($header_key) === 'content-md5' ||\n                strtolower($header_key) === 'content-type' ||\n                strtolower($header_key) === 'date' ||\n                (isset($options['self::OSS_PREAUTH']) && (integer)$options['self::OSS_PREAUTH'] > 0)\n            ) {\n                $string_to_sign .= $header_value . \"\\n\";\n            } elseif (substr(strtolower($header_key), 0, 6) === self::OSS_DEFAULT_PREFIX) {\n                $string_to_sign .= strtolower($header_key) . ':' . $header_value . \"\\n\";\n            }\n        }\n        // Generates the signable_resource\n        $signable_resource = $this->generateSignableResource($options);\n        $string_to_sign .= rawurldecode($signable_resource) . urldecode($signable_query_string);\n\n        // Sort the strings to be signed.\n        $string_to_sign_ordered = $this->stringToSignSorted($string_to_sign);\n\n        $signature = base64_encode(hash_hmac('sha1', $string_to_sign_ordered, $this->accessKeySecret, true));\n        $request->add_header('Authorization', 'OSS ' . $this->accessKeyId . ':' . $signature);\n\n        if (isset($options[self::OSS_PREAUTH]) && (integer)$options[self::OSS_PREAUTH] > 0) {\n            $signed_url = $this->requestUrl . $conjunction . self::OSS_URL_ACCESS_KEY_ID . '=' . rawurlencode($this->accessKeyId) . '&' . self::OSS_URL_EXPIRES . '=' . $options[self::OSS_PREAUTH] . '&' . self::OSS_URL_SIGNATURE . '=' . rawurlencode($signature);\n            return $signed_url;\n        } elseif (isset($options[self::OSS_PREAUTH])) {\n            return $this->requestUrl;\n        }\n\n        if ($this->timeout !== 0) {\n            $request->timeout = $this->timeout;\n        }\n        if ($this->connectTimeout !== 0) {\n            $request->connect_timeout = $this->connectTimeout;\n        }\n\n        try {\n            $request->send_request();\n        } catch (RequestCore_Exception $e) {\n            throw(new OssException('RequestCoreException: ' . $e->getMessage()));\n        }\n        $response_header = $request->get_response_header();\n        $response_header['oss-request-url'] = $this->requestUrl;\n        $response_header['oss-redirects'] = $this->redirects;\n        $response_header['oss-stringtosign'] = $string_to_sign;\n        $response_header['oss-requestheaders'] = $request->request_headers;\n\n        $data = new ResponseCore($response_header, $request->get_response_body(), $request->get_response_code());\n        //retry if OSS Internal Error\n        if ((integer)$request->get_response_code() === 500) {\n            if ($this->redirects <= $this->maxRetries) {\n                //Sets the sleep time betwen each retry.\n                $delay = (integer)(pow(4, $this->redirects) * 100000);\n                usleep($delay);\n                $this->redirects++;\n                $data = $this->auth($options);\n            }\n        }\n        \n        $this->redirects = 0;\n        return $data;\n    }\n\n    /**\n     * Sets the max retry count\n     *\n     * @param int $maxRetries\n     * @return void\n     */\n    public function setMaxTries($maxRetries = 3)\n    {\n        $this->maxRetries = $maxRetries;\n    }\n\n    /**\n     * Gets the max retry count\n     *\n     * @return int\n     */\n    public function getMaxRetries()\n    {\n        return $this->maxRetries;\n    }\n\n    /**\n     * Enaable/disable STS in the URL. This is to determine the $sts value passed from constructor take effect or not.\n     *\n     * @param boolean $enable\n     */\n    public function setSignStsInUrl($enable)\n    {\n        $this->enableStsInUrl = $enable;\n    }\n\n    /**\n     * @return boolean\n     */\n    public function isUseSSL()\n    {\n        return $this->useSSL;\n    }\n\n    /**\n     * @param boolean $useSSL\n     */\n    public function setUseSSL($useSSL)\n    {\n        $this->useSSL = $useSSL;\n    }\n\n    /**\n     * Validates bucket name--throw OssException if it's invalid\n     *\n     * @param $options\n     * @throws OssException\n     */\n    private function authPrecheckBucket($options)\n    {\n        if (!(('/' == $options[self::OSS_OBJECT]) && ('' == $options[self::OSS_BUCKET]) && ('GET' == $options[self::OSS_METHOD])) && !OssUtil::validateBucket($options[self::OSS_BUCKET])) {\n            throw new OssException('\"' . $options[self::OSS_BUCKET] . '\"' . 'bucket name is invalid');\n        }\n    }\n\n    /**\n     *\n     * Validates the object name--throw OssException if it's invalid.\n     *\n     * @param $options\n     * @throws OssException\n     */\n    private function authPrecheckObject($options)\n    {\n        if (isset($options[self::OSS_OBJECT]) && $options[self::OSS_OBJECT] === '/') {\n            return;\n        }\n\n        if (isset($options[self::OSS_OBJECT]) && !OssUtil::validateObject($options[self::OSS_OBJECT])) {\n            throw new OssException('\"' . $options[self::OSS_OBJECT] . '\"' . ' object name is invalid');\n        }\n    }\n\n    /**\n     * Checks the object's encoding. Convert it to UTF8 if it's in GBK or GB2312\n     *\n     * @param mixed $options parameter\n     */\n    private function authPrecheckObjectEncoding(&$options)\n    {\n        $tmp_object = $options[self::OSS_OBJECT];\n        try {\n            if (OssUtil::isGb2312($options[self::OSS_OBJECT])) {\n                $options[self::OSS_OBJECT] = iconv('GB2312', \"UTF-8//IGNORE\", $options[self::OSS_OBJECT]);\n            } elseif (OssUtil::checkChar($options[self::OSS_OBJECT], true)) {\n                $options[self::OSS_OBJECT] = iconv('GBK', \"UTF-8//IGNORE\", $options[self::OSS_OBJECT]);\n            }\n        } catch (\\Exception $e) {\n            try {\n                $tmp_object = iconv(mb_detect_encoding($tmp_object), \"UTF-8\", $tmp_object);\n            } catch (\\Exception $e) {\n            }\n        }\n        $options[self::OSS_OBJECT] = $tmp_object;\n    }\n\n    /**\n     * Checks if the ACL is one of the 3 predefined one. Throw OSSException if not.\n     *\n     * @param $options\n     * @throws OssException\n     */\n    private function authPrecheckAcl($options)\n    {\n        if (isset($options[self::OSS_HEADERS][self::OSS_ACL]) && !empty($options[self::OSS_HEADERS][self::OSS_ACL])) {\n            if (!in_array(strtolower($options[self::OSS_HEADERS][self::OSS_ACL]), self::$OSS_ACL_TYPES)) {\n                throw new OssException($options[self::OSS_HEADERS][self::OSS_ACL] . ':' . 'acl is invalid(private,public-read,public-read-write)');\n            }\n        }\n    }\n\n    /**\n     * Gets the host name for the current request.\n     * It could be either a third level domain (prefixed by bucket name) or second level domain if it's CName or IP\n     *\n     * @param $bucket\n     * @return string The host name without the protocol scheem (e.g. https://)\n     */\n    private function generateHostname($bucket)\n    {\n        if ($this->hostType === self::OSS_HOST_TYPE_IP) {\n            $hostname = $this->hostname;\n        } elseif ($this->hostType === self::OSS_HOST_TYPE_CNAME) {\n            $hostname = $this->hostname;\n        } else {\n            // Private domain or public domain\n            $hostname = ($bucket == '') ? $this->hostname : ($bucket . '.') . $this->hostname;\n        }\n        return $hostname;\n    }\n\n    /**\n     * Gets the resource Uri in the current request\n     *\n     * @param $options\n     * @return string return the resource uri.\n     */\n    private function generateResourceUri($options)\n    {\n        $resource_uri = \"\";\n\n        // resource_uri + bucket\n        if (isset($options[self::OSS_BUCKET]) && '' !== $options[self::OSS_BUCKET]) {\n            if ($this->hostType === self::OSS_HOST_TYPE_IP) {\n                $resource_uri = '/' . $options[self::OSS_BUCKET];\n            }\n        }\n\n        // resource_uri + object\n        if (isset($options[self::OSS_OBJECT]) && '/' !== $options[self::OSS_OBJECT]) {\n            $resource_uri .= '/' . str_replace(array('%2F', '%25'), array('/', '%'), rawurlencode($options[self::OSS_OBJECT]));\n        }\n\n        // resource_uri + sub_resource\n        $conjunction = '?';\n        if (isset($options[self::OSS_SUB_RESOURCE])) {\n            $resource_uri .= $conjunction . $options[self::OSS_SUB_RESOURCE];\n        }\n        return $resource_uri;\n    }\n\n    /**\n     * Generates the signalbe query string parameters in array type\n     *\n     * @param array $options\n     * @return array\n     */\n    private function generateSignableQueryStringParam($options)\n    {\n        $signableQueryStringParams = array();\n        $signableList = array(\n            self::OSS_PART_NUM,\n            'response-content-type',\n            'response-content-language',\n            'response-cache-control',\n            'response-content-encoding',\n            'response-expires',\n            'response-content-disposition',\n            self::OSS_UPLOAD_ID,\n            self::OSS_COMP,\n            self::OSS_LIVE_CHANNEL_STATUS,\n            self::OSS_LIVE_CHANNEL_START_TIME,\n            self::OSS_LIVE_CHANNEL_END_TIME,\n            self::OSS_PROCESS,\n            self::OSS_POSITION,\n            self::OSS_SYMLINK,\n            self::OSS_RESTORE,\n        );\n\n        foreach ($signableList as $item) {\n            if (isset($options[$item])) {\n                $signableQueryStringParams[$item] = $options[$item];\n            }\n        }\n\n        if ($this->enableStsInUrl && (!is_null($this->securityToken))) {\n            $signableQueryStringParams[\"security-token\"] = $this->securityToken;\n        }\n\n        return $signableQueryStringParams;\n    }\n\n    /**\n     *  Generates the resource uri for signing\n     *\n     * @param mixed $options\n     * @return string\n     */\n    private function generateSignableResource($options)\n    {\n        $signableResource = \"\";\n        $signableResource .= '/';\n        if (isset($options[self::OSS_BUCKET]) && '' !== $options[self::OSS_BUCKET]) {\n            $signableResource .= $options[self::OSS_BUCKET];\n            // if there's no object in options, adding a '/' if the host type is not IP.\\\n            if ($options[self::OSS_OBJECT] == '/') {\n                if ($this->hostType !== self::OSS_HOST_TYPE_IP) {\n                    $signableResource .= \"/\";\n                }\n            }\n        }\n        //signable_resource + object\n        if (isset($options[self::OSS_OBJECT]) && '/' !== $options[self::OSS_OBJECT]) {\n            $signableResource .= '/' . str_replace(array('%2F', '%25'), array('/', '%'), rawurlencode($options[self::OSS_OBJECT]));\n        }\n        if (isset($options[self::OSS_SUB_RESOURCE])) {\n            $signableResource .= '?' . $options[self::OSS_SUB_RESOURCE];\n        }\n        return $signableResource;\n    }\n\n    /**\n     * generates query string\n     *\n     * @param mixed $options\n     * @return string\n     */\n    private function generateQueryString($options)\n    {\n        //query parameters\n        $queryStringParams = array();\n        if (isset($options[self::OSS_QUERY_STRING])) {\n            $queryStringParams = array_merge($queryStringParams, $options[self::OSS_QUERY_STRING]);\n        }\n        return OssUtil::toQueryString($queryStringParams);\n    }\n\n    private function stringToSignSorted($string_to_sign)\n    {\n        $queryStringSorted = '';\n        $explodeResult = explode('?', $string_to_sign);\n        $index = count($explodeResult);\n        if ($index === 1)\n            return $string_to_sign;\n\n        $queryStringParams = explode('&', $explodeResult[$index - 1]);\n        sort($queryStringParams);\n\n        foreach($queryStringParams as $params)\n        {\n             $queryStringSorted .= $params . '&';    \n        }\n\n        $queryStringSorted = substr($queryStringSorted, 0, -1);\n\n        return $explodeResult[0] . '?' . $queryStringSorted;\n    }\n\n    /**\n     * Initialize headers\n     *\n     * @param mixed $options\n     * @param string $hostname hostname\n     * @return array\n     */\n    private function generateHeaders($options, $hostname)\n    {\n        $headers = array(\n            self::OSS_CONTENT_MD5 => '',\n            self::OSS_CONTENT_TYPE => isset($options[self::OSS_CONTENT_TYPE]) ? $options[self::OSS_CONTENT_TYPE] : self::DEFAULT_CONTENT_TYPE,\n            self::OSS_DATE => isset($options[self::OSS_DATE]) ? $options[self::OSS_DATE] : gmdate('D, d M Y H:i:s \\G\\M\\T'),\n            self::OSS_HOST => $hostname,\n        );\n        if (isset($options[self::OSS_CONTENT_MD5])) {\n            $headers[self::OSS_CONTENT_MD5] = $options[self::OSS_CONTENT_MD5];\n        }\n\n        //Add stsSecurityToken\n        if ((!is_null($this->securityToken)) && (!$this->enableStsInUrl)) {\n            $headers[self::OSS_SECURITY_TOKEN] = $this->securityToken;\n        }\n        //Merge HTTP headers\n        if (isset($options[self::OSS_HEADERS])) {\n            $headers = array_merge($headers, $options[self::OSS_HEADERS]);\n        }\n        return $headers;\n    }\n\n    /**\n     * Generates UserAgent\n     *\n     * @return string\n     */\n    private function generateUserAgent()\n    {\n        return self::OSS_NAME . \"/\" . self::OSS_VERSION . \" (\" . php_uname('s') . \"/\" . php_uname('r') . \"/\" . php_uname('m') . \";\" . PHP_VERSION . \")\";\n    }\n\n    /**\n     * Checks endpoint type and returns the endpoint without the protocol schema.\n     * Figures out the domain's type (ip, cname or private/public domain).\n     *\n     * @param string $endpoint\n     * @param boolean $isCName\n     * @return string The domain name without the protocol schema.\n     */\n    private function checkEndpoint($endpoint, $isCName)\n    {\n        $ret_endpoint = null;\n        if (strpos($endpoint, 'http://') === 0) {\n            $ret_endpoint = substr($endpoint, strlen('http://'));\n        } elseif (strpos($endpoint, 'https://') === 0) {\n            $ret_endpoint = substr($endpoint, strlen('https://'));\n            $this->useSSL = true;\n        } else {\n            $ret_endpoint = $endpoint;\n        }\n\n        $ret_endpoint = OssUtil::getHostPortFromEndpoint($ret_endpoint);\n\n        if ($isCName) {\n            $this->hostType = self::OSS_HOST_TYPE_CNAME;\n        } elseif (OssUtil::isIPFormat($ret_endpoint)) {\n            $this->hostType = self::OSS_HOST_TYPE_IP;\n        } else {\n            $this->hostType = self::OSS_HOST_TYPE_NORMAL;\n        }\n        return $ret_endpoint;\n    }\n\n    /**\n     * Check if all dependent extensions are installed correctly.\n     * For now only \"curl\" is needed.\n     * @throws OssException\n     */\n    public static function checkEnv()\n    {\n        if (function_exists('get_loaded_extensions')) {\n            //Test curl extension\n            $enabled_extension = array(\"curl\");\n            $extensions = get_loaded_extensions();\n            if ($extensions) {\n                foreach ($enabled_extension as $item) {\n                    if (!in_array($item, $extensions)) {\n                        throw new OssException(\"Extension {\" . $item . \"} is not installed or not enabled, please check your php env.\");\n                    }\n                }\n            } else {\n                throw new OssException(\"function get_loaded_extensions not found.\");\n            }\n        } else {\n            throw new OssException('Function get_loaded_extensions has been disabled, please check php config.');\n        }\n    }\n\n    /**\n     * Sets the http's timeout (in seconds)\n     *\n     * @param int $timeout\n     */\n    public function setTimeout($timeout)\n    {\n        $this->timeout = $timeout;\n    }\n\n    /**\n     * Sets the http's connection timeout (in seconds)\n     *\n     * @param int $connectTimeout\n     */\n    public function setConnectTimeout($connectTimeout)\n    {\n        $this->connectTimeout = $connectTimeout;\n    }\n\n    // Constants for Life cycle\n    const OSS_LIFECYCLE_EXPIRATION = \"Expiration\";\n    const OSS_LIFECYCLE_TIMING_DAYS = \"Days\";\n    const OSS_LIFECYCLE_TIMING_DATE = \"Date\";\n    //OSS Internal constants\n    const OSS_BUCKET = 'bucket';\n    const OSS_OBJECT = 'object';\n    const OSS_HEADERS = OssUtil::OSS_HEADERS;\n    const OSS_METHOD = 'method';\n    const OSS_QUERY = 'query';\n    const OSS_BASENAME = 'basename';\n    const OSS_MAX_KEYS = 'max-keys';\n    const OSS_UPLOAD_ID = 'uploadId';\n    const OSS_PART_NUM = 'partNumber';\n    const OSS_COMP = 'comp';\n    const OSS_LIVE_CHANNEL_STATUS = 'status';\n    const OSS_LIVE_CHANNEL_START_TIME = 'startTime';\n    const OSS_LIVE_CHANNEL_END_TIME = 'endTime';\n    const OSS_POSITION = 'position';\n    const OSS_MAX_KEYS_VALUE = 100;\n    const OSS_MAX_OBJECT_GROUP_VALUE = OssUtil::OSS_MAX_OBJECT_GROUP_VALUE;\n    const OSS_MAX_PART_SIZE = OssUtil::OSS_MAX_PART_SIZE;\n    const OSS_MID_PART_SIZE = OssUtil::OSS_MID_PART_SIZE;\n    const OSS_MIN_PART_SIZE = OssUtil::OSS_MIN_PART_SIZE;\n    const OSS_FILE_SLICE_SIZE = 8192;\n    const OSS_PREFIX = 'prefix';\n    const OSS_DELIMITER = 'delimiter';\n    const OSS_MARKER = 'marker';\n    const OSS_ACCEPT_ENCODING = 'Accept-Encoding';\n    const OSS_CONTENT_MD5 = 'Content-Md5';\n    const OSS_SELF_CONTENT_MD5 = 'x-oss-meta-md5';\n    const OSS_CONTENT_TYPE = 'Content-Type';\n    const OSS_CONTENT_LENGTH = 'Content-Length';\n    const OSS_IF_MODIFIED_SINCE = 'If-Modified-Since';\n    const OSS_IF_UNMODIFIED_SINCE = 'If-Unmodified-Since';\n    const OSS_IF_MATCH = 'If-Match';\n    const OSS_IF_NONE_MATCH = 'If-None-Match';\n    const OSS_CACHE_CONTROL = 'Cache-Control';\n    const OSS_EXPIRES = 'Expires';\n    const OSS_PREAUTH = 'preauth';\n    const OSS_CONTENT_COING = 'Content-Coding';\n    const OSS_CONTENT_DISPOSTION = 'Content-Disposition';\n    const OSS_RANGE = 'range';\n    const OSS_ETAG = 'etag';\n    const OSS_LAST_MODIFIED = 'lastmodified';\n    const OS_CONTENT_RANGE = 'Content-Range';\n    const OSS_CONTENT = OssUtil::OSS_CONTENT;\n    const OSS_BODY = 'body';\n    const OSS_LENGTH = OssUtil::OSS_LENGTH;\n    const OSS_HOST = 'Host';\n    const OSS_DATE = 'Date';\n    const OSS_AUTHORIZATION = 'Authorization';\n    const OSS_FILE_DOWNLOAD = 'fileDownload';\n    const OSS_FILE_UPLOAD = 'fileUpload';\n    const OSS_PART_SIZE = 'partSize';\n    const OSS_SEEK_TO = 'seekTo';\n    const OSS_SIZE = 'size';\n    const OSS_QUERY_STRING = 'query_string';\n    const OSS_SUB_RESOURCE = 'sub_resource';\n    const OSS_DEFAULT_PREFIX = 'x-oss-';\n    const OSS_CHECK_MD5 = 'checkmd5';\n    const DEFAULT_CONTENT_TYPE = 'application/octet-stream';\n    const OSS_SYMLINK_TARGET = 'x-oss-symlink-target';\n    const OSS_SYMLINK = 'symlink';\n    const OSS_HTTP_CODE = 'http_code';\n    const OSS_REQUEST_ID = 'x-oss-request-id';\n    const OSS_INFO = 'info';\n    const OSS_STORAGE = 'storage';\n    const OSS_RESTORE = 'restore';\n    const OSS_STORAGE_STANDARD = 'Standard';\n    const OSS_STORAGE_IA = 'IA';\n    const OSS_STORAGE_ARCHIVE = 'Archive';\n\n    //private URLs\n    const OSS_URL_ACCESS_KEY_ID = 'OSSAccessKeyId';\n    const OSS_URL_EXPIRES = 'Expires';\n    const OSS_URL_SIGNATURE = 'Signature';\n    //HTTP METHOD\n    const OSS_HTTP_GET = 'GET';\n    const OSS_HTTP_PUT = 'PUT';\n    const OSS_HTTP_HEAD = 'HEAD';\n    const OSS_HTTP_POST = 'POST';\n    const OSS_HTTP_DELETE = 'DELETE';\n    const OSS_HTTP_OPTIONS = 'OPTIONS';\n    //Others\n    const OSS_ACL = 'x-oss-acl';\n    const OSS_OBJECT_ACL = 'x-oss-object-acl';\n    const OSS_OBJECT_GROUP = 'x-oss-file-group';\n    const OSS_MULTI_PART = 'uploads';\n    const OSS_MULTI_DELETE = 'delete';\n    const OSS_OBJECT_COPY_SOURCE = 'x-oss-copy-source';\n    const OSS_OBJECT_COPY_SOURCE_RANGE = \"x-oss-copy-source-range\";\n    const OSS_PROCESS = \"x-oss-process\";\n    const OSS_CALLBACK = \"x-oss-callback\";\n    const OSS_CALLBACK_VAR = \"x-oss-callback-var\";\n    //Constants for STS SecurityToken\n    const OSS_SECURITY_TOKEN = \"x-oss-security-token\";\n    const OSS_ACL_TYPE_PRIVATE = 'private';\n    const OSS_ACL_TYPE_PUBLIC_READ = 'public-read';\n    const OSS_ACL_TYPE_PUBLIC_READ_WRITE = 'public-read-write';\n    const OSS_ENCODING_TYPE = \"encoding-type\";\n    const OSS_ENCODING_TYPE_URL = \"url\";\n\n    // Domain Types\n    const OSS_HOST_TYPE_NORMAL = \"normal\";//http://bucket.oss-cn-hangzhou.aliyuncs.com/object\n    const OSS_HOST_TYPE_IP = \"ip\";  //http://1.1.1.1/bucket/object\n    const OSS_HOST_TYPE_SPECIAL = 'special'; //http://bucket.guizhou.gov/object\n    const OSS_HOST_TYPE_CNAME = \"cname\";  //http://mydomain.com/object\n    //OSS ACL array\n    static $OSS_ACL_TYPES = array(\n        self::OSS_ACL_TYPE_PRIVATE,\n        self::OSS_ACL_TYPE_PUBLIC_READ,\n        self::OSS_ACL_TYPE_PUBLIC_READ_WRITE\n    );\n    // OssClient version information\n    const OSS_NAME = \"aliyun-sdk-php\";\n    const OSS_VERSION = \"2.3.1\";\n    const OSS_BUILD = \"20191115\";\n    const OSS_AUTHOR = \"\";\n    const OSS_OPTIONS_ORIGIN = 'Origin';\n    const OSS_OPTIONS_REQUEST_METHOD = 'Access-Control-Request-Method';\n    const OSS_OPTIONS_REQUEST_HEADERS = 'Access-Control-Request-Headers';\n\n    //use ssl flag\n    private $useSSL = false;\n    private $maxRetries = 3;\n    private $redirects = 0;\n\n    // user's domain type. It could be one of the four: OSS_HOST_TYPE_NORMAL, OSS_HOST_TYPE_IP, OSS_HOST_TYPE_SPECIAL, OSS_HOST_TYPE_CNAME\n    private $hostType = self::OSS_HOST_TYPE_NORMAL;\n    private $requestUrl;\n    private $requestProxy = null;\n    private $accessKeyId;\n    private $accessKeySecret;\n    private $hostname;\n    private $securityToken;\n    private $enableStsInUrl = false;\n    private $timeout = 0;\n    private $connectTimeout = 0;\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Result/AclResult.php",
    "content": "<?php\n\nnamespace OSS\\Result;\n\nuse OSS\\Core\\OssException;\n\n/**\n * The type of the return value of getBucketAcl, it wraps the data parsed from xml.\n *\n * @package OSS\\Result\n */\nclass AclResult extends Result\n{\n    /**\n     * @return string\n     * @throws OssException\n     */\n    protected function parseDataFromResponse()\n    {\n        $content = $this->rawResponse->body;\n        if (empty($content)) {\n            throw new OssException(\"body is null\");\n        }\n        $xml = simplexml_load_string($content);\n        if (isset($xml->AccessControlList->Grant)) {\n            return strval($xml->AccessControlList->Grant);\n        } else {\n            throw new OssException(\"xml format exception\");\n        }\n    }\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Result/AppendResult.php",
    "content": "<?php\n\nnamespace OSS\\Result;\n\nuse OSS\\Core\\OssException;\n\n/**\n * Class AppendResult\n * @package OSS\\Result\n */\nclass AppendResult extends Result\n{\n    /**\n     * Get the value of next-append-position from append's response headers\n     *\n     * @return int\n     * @throws OssException\n     */\n    protected function parseDataFromResponse()\n    {\n        $header = $this->rawResponse->header;\n        if (isset($header[\"x-oss-next-append-position\"])) {\n            return intval($header[\"x-oss-next-append-position\"]);\n        }\n        throw new OssException(\"cannot get next-append-position\");\n    }\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Result/BodyResult.php",
    "content": "<?php\n\nnamespace OSS\\Result;\n\n\n/**\n * Class BodyResult\n * @package OSS\\Result\n */\nclass BodyResult extends Result\n{\n    /**\n     * @return string\n     */\n    protected function parseDataFromResponse()\n    {\n        return empty($this->rawResponse->body) ? \"\" : $this->rawResponse->body;\n    }\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Result/CallbackResult.php",
    "content": "<?php\n\nnamespace OSS\\Result;\n\n\n/**\n * Class CallbackResult\n * @package OSS\\Result\n */\nclass CallbackResult extends PutSetDeleteResult\n{\n    protected function isResponseOk()\n    {\n        $status = $this->rawResponse->status;\n        if ((int)(intval($status) / 100) == 2 && (int)(intval($status)) !== 203) {\n            return true;\n        }\n        return false;\n    }\n\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Result/CopyObjectResult.php",
    "content": "<?php\n\nnamespace OSS\\Result;\n\n\n/**\n * Class CopyObjectResult\n * @package OSS\\Result\n */\nclass CopyObjectResult extends Result\n{\n    /**\n     * @return array()\n     */\n    protected function parseDataFromResponse()\n    {\n        $body = $this->rawResponse->body;\n        $xml = simplexml_load_string($body); \n        $result = array();\n        \n        if (isset($xml->LastModified)) {\n            $result[] = $xml->LastModified;\n        }\n        if (isset($xml->ETag)) {\n            $result[] = $xml->ETag;\n        }\n\n         return $result;\n    }\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Result/DeleteObjectsResult.php",
    "content": "<?php\n\nnamespace OSS\\Result;\n\n\n/**\n * Class DeleteObjectsResult\n * @package OSS\\Result\n */\nclass DeleteObjectsResult extends Result\n{\n    /**\n     * @return array()\n     */\n    protected function parseDataFromResponse()\n    {\n        $body = $this->rawResponse->body;\n        $xml = simplexml_load_string($body); \n        $objects = array();\n\n        if (isset($xml->Deleted)) {\n            foreach($xml->Deleted as $deleteKey)\n                $objects[] = $deleteKey->Key;\n        }\n        return $objects;\n    }\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Result/ExistResult.php",
    "content": "<?php\n\nnamespace OSS\\Result;\n\n/**\n * Class ExistResult checks if bucket or object exists, according to the http status in response headers.\n * @package OSS\\Result\n */\nclass ExistResult extends Result\n{\n    /**\n     * @return bool\n     */\n    protected function parseDataFromResponse()\n    {\n        return intval($this->rawResponse->status) === 200 ? true : false;\n    }\n\n    /**\n     * Check if the response status is OK according to the http status code.\n     * [200-299]: OK; [404]: Not found. It means the object or bucket is not found--it's a valid response too.\n     *\n     * @return bool\n     */\n    protected function isResponseOk()\n    {\n        $status = $this->rawResponse->status;\n        if ((int)(intval($status) / 100) == 2 || (int)(intval($status)) === 404) {\n            return true;\n        }\n        return false;\n    }\n\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Result/GetCnameResult.php",
    "content": "<?php\n\nnamespace OSS\\Result;\n\nuse OSS\\Model\\CnameConfig;\n\nclass GetCnameResult extends Result\n{\n    /**\n     * @return CnameConfig\n     */\n    protected function parseDataFromResponse()\n    {\n        $content = $this->rawResponse->body;\n        $config = new CnameConfig();\n        $config->parseFromXml($content);\n        return $config;\n    }\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Result/GetCorsResult.php",
    "content": "<?php\n\nnamespace OSS\\Result;\n\nuse OSS\\Model\\CorsConfig;\n\nclass GetCorsResult extends Result\n{\n    /**\n     * @return CorsConfig\n     */\n    protected function parseDataFromResponse()\n    {\n        $content = $this->rawResponse->body;\n        $config = new CorsConfig();\n        $config->parseFromXml($content);\n        return $config;\n    }\n\n    /**\n     * Check if the response is OK, according to the http status. [200-299]:OK, the Cors config could be got; [404]: not found--no Cors config.\n     *\n     * @return bool\n     */\n    protected function isResponseOk()\n    {\n        $status = $this->rawResponse->status;\n        if ((int)(intval($status) / 100) == 2 || (int)(intval($status)) === 404) {\n            return true;\n        }\n        return false;\n    }\n\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Result/GetLifecycleResult.php",
    "content": "<?php\n\nnamespace OSS\\Result;\n\n\nuse OSS\\Model\\LifecycleConfig;\n\n/**\n * Class GetLifecycleResult\n * @package OSS\\Result\n */\nclass GetLifecycleResult extends Result\n{\n    /**\n     *  Parse the LifecycleConfig object from the response\n     *\n     * @return LifecycleConfig\n     */\n    protected function parseDataFromResponse()\n    {\n        $content = $this->rawResponse->body;\n        $config = new LifecycleConfig();\n        $config->parseFromXml($content);\n        return $config;\n    }\n\n    /**\n     * Check if the response is OK according to the http status.\n     * [200-299]: OK, and the LifecycleConfig could be got; [404] The Life cycle config is not found.\n     *\n     * @return bool\n     */\n    protected function isResponseOk()\n    {\n        $status = $this->rawResponse->status;\n        if ((int)(intval($status) / 100) == 2 || (int)(intval($status)) === 404) {\n            return true;\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Result/GetLiveChannelHistoryResult.php",
    "content": "<?php\n\nnamespace OSS\\Result;\n\nuse OSS\\Model\\GetLiveChannelHistory;\n\nclass GetLiveChannelHistoryResult extends Result\n{\n    /**\n     * @return\n     */\n    protected function parseDataFromResponse()\n    {\n        $content = $this->rawResponse->body;\n        $channelList = new GetLiveChannelHistory();\n        $channelList->parseFromXml($content);\n        return $channelList;\n    }\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Result/GetLiveChannelInfoResult.php",
    "content": "<?php\n\nnamespace OSS\\Result;\n\nuse OSS\\Model\\GetLiveChannelInfo;\n\nclass GetLiveChannelInfoResult extends Result\n{\n    /**\n     * @return\n     */\n    protected function parseDataFromResponse()\n    {\n        $content = $this->rawResponse->body;\n        $channelList = new GetLiveChannelInfo();\n        $channelList->parseFromXml($content);\n        return $channelList;\n    }\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Result/GetLiveChannelStatusResult.php",
    "content": "<?php\n\nnamespace OSS\\Result;\n\nuse OSS\\Model\\GetLiveChannelStatus;\n\nclass GetLiveChannelStatusResult extends Result\n{\n    /**\n     * @return\n     */\n    protected function parseDataFromResponse()\n    {\n        $content = $this->rawResponse->body;\n        $channelList = new GetLiveChannelStatus();\n        $channelList->parseFromXml($content);\n        return $channelList;\n    }\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Result/GetLocationResult.php",
    "content": "<?php\nnamespace OSS\\Result;\n\nuse OSS\\Core\\OssException;\n\n/**\n * Class GetLocationResult getBucketLocation interface returns the result class, encapsulated\n * The returned xml data is parsed\n *\n * @package OSS\\Result\n */\nclass GetLocationResult extends Result\n{\n\n    /**\n     * Parse data from response\n     * \n     * @return string\n     * @throws OssException\n     */\n    protected function parseDataFromResponse()\n    {\n        $content = $this->rawResponse->body;\n        if (empty($content)) {\n            throw new OssException(\"body is null\");\n        }\n        $xml = simplexml_load_string($content);\n        return $xml;\n    }\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Result/GetLoggingResult.php",
    "content": "<?php\n\nnamespace OSS\\Result;\n\nuse OSS\\Model\\LoggingConfig;\n\n\n/**\n * Class GetLoggingResult\n * @package OSS\\Result\n */\nclass GetLoggingResult extends Result\n{\n    /**\n     * Parse LoggingConfig data\n     *\n     * @return LoggingConfig\n     */\n    protected function parseDataFromResponse()\n    {\n        $content = $this->rawResponse->body;\n        $config = new LoggingConfig();\n        $config->parseFromXml($content);\n        return $config;\n    }\n\n    /**\n     * Judged according to the return HTTP status code, [200-299] that is OK, get the bucket configuration interface,\n     * 404 is also considered a valid response\n     *\n     * @return bool\n     */\n    protected function isResponseOk()\n    {\n        $status = $this->rawResponse->status;\n        if ((int)(intval($status) / 100) == 2 || (int)(intval($status)) === 404) {\n            return true;\n        }\n        return false;\n    }\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Result/GetRefererResult.php",
    "content": "<?php\n\nnamespace OSS\\Result;\n\n\nuse OSS\\Model\\RefererConfig;\n\n/**\n * Class GetRefererResult\n * @package OSS\\Result\n */\nclass GetRefererResult extends Result\n{\n    /**\n     * Parse RefererConfig data\n     *\n     * @return RefererConfig\n     */\n    protected function parseDataFromResponse()\n    {\n        $content = $this->rawResponse->body;\n        $config = new RefererConfig();\n        $config->parseFromXml($content);\n        return $config;\n    }\n\n    /**\n     * Judged according to the return HTTP status code, [200-299] that is OK, get the bucket configuration interface,\n     * 404 is also considered a valid response\n     *\n     * @return bool\n     */\n    protected function isResponseOk()\n    {\n        $status = $this->rawResponse->status;\n        if ((int)(intval($status) / 100) == 2 || (int)(intval($status)) === 404) {\n            return true;\n        }\n        return false;\n    }\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Result/GetStorageCapacityResult.php",
    "content": "<?php\n\nnamespace OSS\\Result;\n\nuse OSS\\Core\\OssException;\n\n/**\n * Class AclResult  GetBucketAcl interface returns the result class, encapsulated\n * The returned xml data is parsed\n *\n * @package OSS\\Result\n */\nclass GetStorageCapacityResult extends Result\n{\n    /**\n     * Parse data from response\n     * \n     * @return string\n     * @throws OssException\n     */\n    protected function parseDataFromResponse()\n    {\n        $content = $this->rawResponse->body;\n        if (empty($content)) {\n            throw new OssException(\"body is null\");\n        }\n        $xml = simplexml_load_string($content);\n        if (isset($xml->StorageCapacity)) {\n            return intval($xml->StorageCapacity);\n        } else {\n            throw new OssException(\"xml format exception\");\n        }\n    }\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Result/GetWebsiteResult.php",
    "content": "<?php\n\nnamespace OSS\\Result;\n\nuse OSS\\Model\\WebsiteConfig;\n\n/**\n * Class GetWebsiteResult\n * @package OSS\\Result\n */\nclass GetWebsiteResult extends Result\n{\n    /**\n     * Parse WebsiteConfig data\n     *\n     * @return WebsiteConfig\n     */\n    protected function parseDataFromResponse()\n    {\n        $content = $this->rawResponse->body;\n        $config = new WebsiteConfig();\n        $config->parseFromXml($content);\n        return $config;\n    }\n\n    /**\n     * Judged according to the return HTTP status code, [200-299] that is OK, get the bucket configuration interface,\n     * 404 is also considered a valid response\n     *\n     * @return bool\n     */\n    protected function isResponseOk()\n    {\n        $status = $this->rawResponse->status;\n        if ((int)(intval($status) / 100) == 2 || (int)(intval($status)) === 404) {\n            return true;\n        }\n        return false;\n    }\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Result/HeaderResult.php",
    "content": "<?php\n\nnamespace OSS\\Result;\n\n\n/**\n * Class HeaderResult\n * @package OSS\\Result\n * @link https://docs.aliyun.com/?spm=5176.383663.13.7.HgUIqL#/pub/oss/api-reference/object&GetObjectMeta\n */\nclass HeaderResult extends Result\n{\n    /**\n     * The returned ResponseCore header is used as the return data\n     *\n     * @return array\n     */\n    protected function parseDataFromResponse()\n    {\n        return empty($this->rawResponse->header) ? array() : $this->rawResponse->header;\n    }\n\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Result/InitiateMultipartUploadResult.php",
    "content": "<?php\n\nnamespace OSS\\Result;\n\nuse OSS\\Core\\OssException;\n\n\n/**\n * Class initiateMultipartUploadResult\n * @package OSS\\Result\n */\nclass InitiateMultipartUploadResult extends Result\n{\n    /**\n     * Get uploadId in result and return\n     *\n     * @throws OssException\n     * @return string\n     */\n    protected function parseDataFromResponse()\n    {\n        $content = $this->rawResponse->body;\n        $xml = simplexml_load_string($content);\n        if (isset($xml->UploadId)) {\n            return strval($xml->UploadId);\n        }\n        throw new OssException(\"cannot get UploadId\");\n    }\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Result/ListBucketsResult.php",
    "content": "<?php\n\nnamespace OSS\\Result;\n\nuse OSS\\Model\\BucketInfo;\nuse OSS\\Model\\BucketListInfo;\n\n/**\n * Class ListBucketsResult\n *\n * @package OSS\\Result\n */\nclass ListBucketsResult extends Result\n{\n    /**\n     * @return BucketListInfo\n     */\n    protected function parseDataFromResponse()\n    {\n        $bucketList = array();\n        $content = $this->rawResponse->body;\n        $xml = new \\SimpleXMLElement($content);\n        if (isset($xml->Buckets) && isset($xml->Buckets->Bucket)) {\n            foreach ($xml->Buckets->Bucket as $bucket) {\n                $bucketInfo = new BucketInfo(strval($bucket->Location),\n                    strval($bucket->Name),\n                    strval($bucket->CreationDate));\n                $bucketList[] = $bucketInfo;\n            }\n        }\n        return new BucketListInfo($bucketList);\n    }\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Result/ListLiveChannelResult.php",
    "content": "<?php\n\nnamespace OSS\\Result;\n\nuse OSS\\Model\\LiveChannelListInfo;\n\nclass ListLiveChannelResult extends Result\n{\n    protected function parseDataFromResponse()\n    {\n        $content = $this->rawResponse->body;\n        $channelList = new LiveChannelListInfo();\n        $channelList->parseFromXml($content);\n        return $channelList;\n    }\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Result/ListMultipartUploadResult.php",
    "content": "<?php\n\nnamespace OSS\\Result;\n\nuse OSS\\Core\\OssUtil;\nuse OSS\\Model\\ListMultipartUploadInfo;\nuse OSS\\Model\\UploadInfo;\n\n\n/**\n * Class ListMultipartUploadResult\n * @package OSS\\Result\n */\nclass ListMultipartUploadResult extends Result\n{\n    /**\n     * Parse the return data from the ListMultipartUpload interface\n     *\n     * @return ListMultipartUploadInfo\n     */\n    protected function parseDataFromResponse()\n    {\n        $content = $this->rawResponse->body;\n        $xml = simplexml_load_string($content);\n\n        $encodingType = isset($xml->EncodingType) ? strval($xml->EncodingType) : \"\";\n        $bucket = isset($xml->Bucket) ? strval($xml->Bucket) : \"\";\n        $keyMarker = isset($xml->KeyMarker) ? strval($xml->KeyMarker) : \"\";\n        $keyMarker = OssUtil::decodeKey($keyMarker, $encodingType);\n        $uploadIdMarker = isset($xml->UploadIdMarker) ? strval($xml->UploadIdMarker) : \"\";\n        $nextKeyMarker = isset($xml->NextKeyMarker) ? strval($xml->NextKeyMarker) : \"\";\n        $nextKeyMarker = OssUtil::decodeKey($nextKeyMarker, $encodingType);\n        $nextUploadIdMarker = isset($xml->NextUploadIdMarker) ? strval($xml->NextUploadIdMarker) : \"\";\n        $delimiter = isset($xml->Delimiter) ? strval($xml->Delimiter) : \"\";\n        $delimiter = OssUtil::decodeKey($delimiter, $encodingType);\n        $prefix = isset($xml->Prefix) ? strval($xml->Prefix) : \"\";\n        $prefix = OssUtil::decodeKey($prefix, $encodingType);\n        $maxUploads = isset($xml->MaxUploads) ? intval($xml->MaxUploads) : 0;\n        $isTruncated = isset($xml->IsTruncated) ? strval($xml->IsTruncated) : \"\";\n        $listUpload = array();\n\n        if (isset($xml->Upload)) {\n            foreach ($xml->Upload as $upload) {\n                $key = isset($upload->Key) ? strval($upload->Key) : \"\";\n                $key = OssUtil::decodeKey($key, $encodingType);\n                $uploadId = isset($upload->UploadId) ? strval($upload->UploadId) : \"\";\n                $initiated = isset($upload->Initiated) ? strval($upload->Initiated) : \"\";\n                $listUpload[] = new UploadInfo($key, $uploadId, $initiated);\n            }\n        }\n        return new ListMultipartUploadInfo($bucket, $keyMarker, $uploadIdMarker,\n            $nextKeyMarker, $nextUploadIdMarker,\n            $delimiter, $prefix, $maxUploads, $isTruncated, $listUpload);\n    }\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Result/ListObjectsResult.php",
    "content": "<?php\n\nnamespace OSS\\Result;\n\nuse OSS\\Core\\OssUtil;\nuse OSS\\Model\\ObjectInfo;\nuse OSS\\Model\\ObjectListInfo;\nuse OSS\\Model\\PrefixInfo;\n\n/**\n * Class ListObjectsResult\n * @package OSS\\Result\n */\nclass ListObjectsResult extends Result\n{\n    /**\n     * Parse the xml data returned by the ListObjects interface\n     *\n     * return ObjectListInfo\n     */\n    protected function parseDataFromResponse()\n    {\n        $xml = new \\SimpleXMLElement($this->rawResponse->body);\n        $encodingType = isset($xml->EncodingType) ? strval($xml->EncodingType) : \"\";\n        $objectList = $this->parseObjectList($xml, $encodingType);\n        $prefixList = $this->parsePrefixList($xml, $encodingType);\n        $bucketName = isset($xml->Name) ? strval($xml->Name) : \"\";\n        $prefix = isset($xml->Prefix) ? strval($xml->Prefix) : \"\";\n        $prefix = OssUtil::decodeKey($prefix, $encodingType);\n        $marker = isset($xml->Marker) ? strval($xml->Marker) : \"\";\n        $marker = OssUtil::decodeKey($marker, $encodingType);\n        $maxKeys = isset($xml->MaxKeys) ? intval($xml->MaxKeys) : 0;\n        $delimiter = isset($xml->Delimiter) ? strval($xml->Delimiter) : \"\";\n        $delimiter = OssUtil::decodeKey($delimiter, $encodingType);\n        $isTruncated = isset($xml->IsTruncated) ? strval($xml->IsTruncated) : \"\";\n        $nextMarker = isset($xml->NextMarker) ? strval($xml->NextMarker) : \"\";\n        $nextMarker = OssUtil::decodeKey($nextMarker, $encodingType);\n        return new ObjectListInfo($bucketName, $prefix, $marker, $nextMarker, $maxKeys, $delimiter, $isTruncated, $objectList, $prefixList);\n    }\n\n    private function parseObjectList($xml, $encodingType)\n    {\n        $retList = array();\n        if (isset($xml->Contents)) {\n            foreach ($xml->Contents as $content) {\n                $key = isset($content->Key) ? strval($content->Key) : \"\";\n                $key = OssUtil::decodeKey($key, $encodingType);\n                $lastModified = isset($content->LastModified) ? strval($content->LastModified) : \"\";\n                $eTag = isset($content->ETag) ? strval($content->ETag) : \"\";\n                $type = isset($content->Type) ? strval($content->Type) : \"\";\n                $size = isset($content->Size) ? intval($content->Size) : 0;\n                $storageClass = isset($content->StorageClass) ? strval($content->StorageClass) : \"\";\n                $retList[] = new ObjectInfo($key, $lastModified, $eTag, $type, $size, $storageClass);\n            }\n        }\n        return $retList;\n    }\n\n    private function parsePrefixList($xml, $encodingType)\n    {\n        $retList = array();\n        if (isset($xml->CommonPrefixes)) {\n            foreach ($xml->CommonPrefixes as $commonPrefix) {\n                $prefix = isset($commonPrefix->Prefix) ? strval($commonPrefix->Prefix) : \"\";\n                $prefix = OssUtil::decodeKey($prefix, $encodingType);\n                $retList[] = new PrefixInfo($prefix);\n            }\n        }\n        return $retList;\n    }\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Result/ListPartsResult.php",
    "content": "<?php\n\nnamespace OSS\\Result;\n\nuse OSS\\Model\\ListPartsInfo;\nuse OSS\\Model\\PartInfo;\n\n\n/**\n * Class ListPartsResult\n * @package OSS\\Result\n */\nclass ListPartsResult extends Result\n{\n    /**\n     * Parse the xml data returned by the ListParts interface\n     *\n     * @return ListPartsInfo\n     */\n    protected function parseDataFromResponse()\n    {\n        $content = $this->rawResponse->body;\n        $xml = simplexml_load_string($content);\n        $bucket = isset($xml->Bucket) ? strval($xml->Bucket) : \"\";\n        $key = isset($xml->Key) ? strval($xml->Key) : \"\";\n        $uploadId = isset($xml->UploadId) ? strval($xml->UploadId) : \"\";\n        $nextPartNumberMarker = isset($xml->NextPartNumberMarker) ? intval($xml->NextPartNumberMarker) : \"\";\n        $maxParts = isset($xml->MaxParts) ? intval($xml->MaxParts) : \"\";\n        $isTruncated = isset($xml->IsTruncated) ? strval($xml->IsTruncated) : \"\";\n        $partList = array();\n        if (isset($xml->Part)) {\n            foreach ($xml->Part as $part) {\n                $partNumber = isset($part->PartNumber) ? intval($part->PartNumber) : \"\";\n                $lastModified = isset($part->LastModified) ? strval($part->LastModified) : \"\";\n                $eTag = isset($part->ETag) ? strval($part->ETag) : \"\";\n                $size = isset($part->Size) ? intval($part->Size) : \"\";\n                $partList[] = new PartInfo($partNumber, $lastModified, $eTag, $size);\n            }\n        }\n        return new ListPartsInfo($bucket, $key, $uploadId, $nextPartNumberMarker, $maxParts, $isTruncated, $partList);\n    }\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Result/PutLiveChannelResult.php",
    "content": "<?php\n\nnamespace OSS\\Result;\n\nuse OSS\\Model\\LiveChannelInfo;\n\nclass PutLiveChannelResult extends Result\n{\n    protected function parseDataFromResponse()\n    {\n        $content = $this->rawResponse->body;\n        $channel = new LiveChannelInfo();\n        $channel->parseFromXml($content);\n        return $channel;\n    }\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Result/PutSetDeleteResult.php",
    "content": "<?php\n\nnamespace OSS\\Result;\n\n\n/**\n * Class PutSetDeleteResult\n * @package OSS\\Result\n */\nclass PutSetDeleteResult extends Result\n{\n    /**\n     * @return array()\n     */\n    protected function parseDataFromResponse()\n    {\n        $body = array('body' => $this->rawResponse->body);\n        return array_merge($this->rawResponse->header, $body);\n    }\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Result/Result.php",
    "content": "<?php\n\nnamespace OSS\\Result;\n\nuse OSS\\Core\\OssException;\nuse OSS\\Http\\ResponseCore;\n\n\n/**\n * Class Result, The result class of The operation of the base class, different requests in dealing with the return of data have different logic,\n * The specific parsing logic postponed to subclass implementation\n *\n * @package OSS\\Model\n */\nabstract class Result\n{\n    /**\n     * Result constructor.\n     * @param $response ResponseCore\n     * @throws OssException\n     */\n    public function __construct($response)\n    {\n        if ($response === null) {\n            throw new OssException(\"raw response is null\");\n        }\n        $this->rawResponse = $response;\n        $this->parseResponse();\n    }\n\n    /**\n     * Get requestId\n     *\n     * @return string\n     */\n    public function getRequestId()\n    {\n        if (isset($this->rawResponse) &&\n            isset($this->rawResponse->header) &&\n            isset($this->rawResponse->header['x-oss-request-id'])\n        ) {\n            return $this->rawResponse->header['x-oss-request-id'];\n        } else {\n            return '';\n        }\n    }\n\n    /**\n     * Get the returned data, different request returns the data format is different\n     *\n     * $return mixed\n     */\n    public function getData()\n    {\n        return $this->parsedData;\n    }\n\n    /**\n     * Subclass implementation, different requests return data has different analytical logic, implemented by subclasses\n     *\n     * @return mixed\n     */\n    abstract protected function parseDataFromResponse();\n\n    /**\n     * Whether the operation is successful\n     *\n     * @return mixed\n     */\n    public function isOK()\n    {\n        return $this->isOk;\n    }\n\n    /**\n     * @throws OssException\n     */\n    public function parseResponse()\n    {\n        $this->isOk = $this->isResponseOk();\n        if ($this->isOk) {\n            $this->parsedData = $this->parseDataFromResponse();\n        } else {\n            $httpStatus = strval($this->rawResponse->status);\n            $requestId = strval($this->getRequestId());\n            $code = $this->retrieveErrorCode($this->rawResponse->body);\n            $message = $this->retrieveErrorMessage($this->rawResponse->body);\n            $body = $this->rawResponse->body;\n\n            $details = array(\n                'status' => $httpStatus,\n                'request-id' => $requestId,\n                'code' => $code,\n                'message' => $message,\n                'body' => $body\n            );\n            throw new OssException($details);\n        }\n    }\n\n    /**\n     * Try to get the error message from body\n     *\n     * @param $body\n     * @return string\n     */\n    private function retrieveErrorMessage($body)\n    {\n        if (empty($body) || false === strpos($body, '<?xml')) {\n            return '';\n        }\n        $xml = simplexml_load_string($body);\n        if (isset($xml->Message)) {\n            return strval($xml->Message);\n        }\n        return '';\n    }\n\n    /**\n     * Try to get the error Code from body\n     *\n     * @param $body\n     * @return string\n     */\n    private function retrieveErrorCode($body)\n    {\n        if (empty($body) || false === strpos($body, '<?xml')) {\n            return '';\n        }\n        $xml = simplexml_load_string($body);\n        if (isset($xml->Code)) {\n            return strval($xml->Code);\n        }\n        return '';\n    }\n\n    /**\n     * Judging from the return http status code, [200-299] that is OK\n     *\n     * @return bool\n     */\n    protected function isResponseOk()\n    {\n        $status = $this->rawResponse->status;\n        if ((int)(intval($status) / 100) == 2) {\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * Return the original return data\n     *\n     * @return ResponseCore\n     */\n    public function getRawResponse()\n    {\n        return $this->rawResponse;\n    }\n\n    /**\n     * Indicate whether the request is successful\n     */\n    protected $isOk = false;\n    /**\n     * Data parsed by subclasses\n     */\n    protected $parsedData = null;\n    /**\n     * Store the original Response returned by the auth function\n     *\n     * @var ResponseCore\n     */\n    protected $rawResponse;\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Result/SymlinkResult.php",
    "content": "<?php\n\nnamespace OSS\\Result;\n\nuse OSS\\Core\\OssException;\nuse OSS\\OssClient;\n\n/**\n *\n * @package OSS\\Result\n */\nclass SymlinkResult extends Result\n{\n    /**\n     * @return string\n     * @throws OssException\n     */\n    protected function parseDataFromResponse()\n    {\n        $this->rawResponse->header[OssClient::OSS_SYMLINK_TARGET] = rawurldecode($this->rawResponse->header[OssClient::OSS_SYMLINK_TARGET]);\n        return $this->rawResponse->header;\n    }\n}\n\n"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Alioss/src/OSS/Result/UploadPartResult.php",
    "content": "<?php\n\nnamespace OSS\\Result;\n\nuse OSS\\Core\\OssException;\n\n/**\n * Class UploadPartResult\n * @package OSS\\Result\n */\nclass UploadPartResult extends Result\n{\n    /**\n     * 结果中part的ETag\n     *\n     * @return string\n     * @throws OssException\n     */\n    protected function parseDataFromResponse()\n    {\n        $header = $this->rawResponse->header;\n        if (isset($header[\"etag\"])) {\n            return $header[\"etag\"];\n        }\n        throw new OssException(\"cannot get ETag\");\n\n    }\n}"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Parsedown/Parsedown.class.php",
    "content": "<?php\n\n#\n#\n# Parsedown\n# http://parsedown.org\n#\n# (c) Emanuil Rusev\n# http://erusev.com\n#\n# For the full license information, view the LICENSE file that was distributed\n# with this source code.\n#\n#\n\nclass Parsedown\n{\n    # ~\n\n    const version = '1.6.0';\n\n    # ~\n\n    function text($text)\n    {\n        # make sure no definitions are set\n        $this->DefinitionData = array();\n\n        # standardize line breaks\n        $text = str_replace(array(\"\\r\\n\", \"\\r\"), \"\\n\", $text);\n\n        # remove surrounding line breaks\n        $text = trim($text, \"\\n\");\n\n        # split text into lines\n        $lines = explode(\"\\n\", $text);\n\n        # iterate through lines to identify blocks\n        $markup = $this->lines($lines);\n\n        # trim line breaks\n        $markup = trim($markup, \"\\n\");\n\n        return $markup;\n    }\n\n    #\n    # Setters\n    #\n\n    function setBreaksEnabled($breaksEnabled)\n    {\n        $this->breaksEnabled = $breaksEnabled;\n\n        return $this;\n    }\n\n    protected $breaksEnabled;\n\n    function setMarkupEscaped($markupEscaped)\n    {\n        $this->markupEscaped = $markupEscaped;\n\n        return $this;\n    }\n\n    protected $markupEscaped;\n\n    function setUrlsLinked($urlsLinked)\n    {\n        $this->urlsLinked = $urlsLinked;\n\n        return $this;\n    }\n\n    protected $urlsLinked = true;\n\n    #\n    # Lines\n    #\n\n    protected $BlockTypes = array(\n        '#' => array('Header'),\n        '*' => array('Rule', 'List'),\n        '+' => array('List'),\n        '-' => array('SetextHeader', 'Table', 'Rule', 'List'),\n        '0' => array('List'),\n        '1' => array('List'),\n        '2' => array('List'),\n        '3' => array('List'),\n        '4' => array('List'),\n        '5' => array('List'),\n        '6' => array('List'),\n        '7' => array('List'),\n        '8' => array('List'),\n        '9' => array('List'),\n        ':' => array('Table'),\n        '<' => array('Comment', 'Markup'),\n        '=' => array('SetextHeader'),\n        '>' => array('Quote'),\n        '[' => array('Reference'),\n        '_' => array('Rule'),\n        '`' => array('FencedCode'),\n        '|' => array('Table'),\n        '~' => array('FencedCode'),\n    );\n\n    # ~\n\n    protected $unmarkedBlockTypes = array(\n        'Code',\n    );\n\n    #\n    # Blocks\n    #\n\n    private function lines(array $lines)\n    {\n        $CurrentBlock = null;\n\n        foreach ($lines as $line)\n        {\n            if (chop($line) === '')\n            {\n                if (isset($CurrentBlock))\n                {\n                    $CurrentBlock['interrupted'] = true;\n                }\n\n                continue;\n            }\n\n            if (strpos($line, \"\\t\") !== false)\n            {\n                $parts = explode(\"\\t\", $line);\n\n                $line = $parts[0];\n\n                unset($parts[0]);\n\n                foreach ($parts as $part)\n                {\n                    $shortage = 4 - mb_strlen($line, 'utf-8') % 4;\n\n                    $line .= str_repeat(' ', $shortage);\n                    $line .= $part;\n                }\n            }\n\n            $indent = 0;\n\n            while (isset($line[$indent]) and $line[$indent] === ' ')\n            {\n                $indent ++;\n            }\n\n            $text = $indent > 0 ? substr($line, $indent) : $line;\n\n            # ~\n\n            $Line = array('body' => $line, 'indent' => $indent, 'text' => $text);\n\n            # ~\n\n            if (isset($CurrentBlock['continuable']))\n            {\n                $Block = $this->{'block'.$CurrentBlock['type'].'Continue'}($Line, $CurrentBlock);\n\n                if (isset($Block))\n                {\n                    $CurrentBlock = $Block;\n\n                    continue;\n                }\n                else\n                {\n                    if (method_exists($this, 'block'.$CurrentBlock['type'].'Complete'))\n                    {\n                        $CurrentBlock = $this->{'block'.$CurrentBlock['type'].'Complete'}($CurrentBlock);\n                    }\n                }\n            }\n\n            # ~\n\n            $marker = $text[0];\n\n            # ~\n\n            $blockTypes = $this->unmarkedBlockTypes;\n\n            if (isset($this->BlockTypes[$marker]))\n            {\n                foreach ($this->BlockTypes[$marker] as $blockType)\n                {\n                    $blockTypes []= $blockType;\n                }\n            }\n\n            #\n            # ~\n\n            foreach ($blockTypes as $blockType)\n            {\n                $Block = $this->{'block'.$blockType}($Line, $CurrentBlock);\n\n                if (isset($Block))\n                {\n                    $Block['type'] = $blockType;\n\n                    if ( ! isset($Block['identified']))\n                    {\n                        $Blocks []= $CurrentBlock;\n\n                        $Block['identified'] = true;\n                    }\n\n                    if (method_exists($this, 'block'.$blockType.'Continue'))\n                    {\n                        $Block['continuable'] = true;\n                    }\n\n                    $CurrentBlock = $Block;\n\n                    continue 2;\n                }\n            }\n\n            # ~\n\n            if (isset($CurrentBlock) and ! isset($CurrentBlock['type']) and ! isset($CurrentBlock['interrupted']))\n            {\n                $CurrentBlock['element']['text'] .= \"\\n\".$text;\n            }\n            else\n            {\n                $Blocks []= $CurrentBlock;\n\n                $CurrentBlock = $this->paragraph($Line);\n\n                $CurrentBlock['identified'] = true;\n            }\n        }\n\n        # ~\n\n        if (isset($CurrentBlock['continuable']) and method_exists($this, 'block'.$CurrentBlock['type'].'Complete'))\n        {\n            $CurrentBlock = $this->{'block'.$CurrentBlock['type'].'Complete'}($CurrentBlock);\n        }\n\n        # ~\n\n        $Blocks []= $CurrentBlock;\n\n        unset($Blocks[0]);\n\n        # ~\n\n        $markup = '';\n\n        foreach ($Blocks as $Block)\n        {\n            if (isset($Block['hidden']))\n            {\n                continue;\n            }\n\n            $markup .= \"\\n\";\n            $markup .= isset($Block['markup']) ? $Block['markup'] : $this->element($Block['element']);\n        }\n\n        $markup .= \"\\n\";\n\n        # ~\n\n        return $markup;\n    }\n\n    #\n    # Code\n\n    protected function blockCode($Line, $Block = null)\n    {\n        if (isset($Block) and ! isset($Block['type']) and ! isset($Block['interrupted']))\n        {\n            return;\n        }\n\n        if ($Line['indent'] >= 4)\n        {\n            $text = substr($Line['body'], 4);\n\n            $Block = array(\n                'element' => array(\n                    'name' => 'pre',\n                    'handler' => 'element',\n                    'text' => array(\n                        'name' => 'code',\n                        'text' => $text,\n                    ),\n                ),\n            );\n\n            return $Block;\n        }\n    }\n\n    protected function blockCodeContinue($Line, $Block)\n    {\n        if ($Line['indent'] >= 4)\n        {\n            if (isset($Block['interrupted']))\n            {\n                $Block['element']['text']['text'] .= \"\\n\";\n\n                unset($Block['interrupted']);\n            }\n\n            $Block['element']['text']['text'] .= \"\\n\";\n\n            $text = substr($Line['body'], 4);\n\n            $Block['element']['text']['text'] .= $text;\n\n            return $Block;\n        }\n    }\n\n    protected function blockCodeComplete($Block)\n    {\n        $text = $Block['element']['text']['text'];\n\n        $text = htmlspecialchars($text, ENT_NOQUOTES, 'UTF-8');\n\n        $Block['element']['text']['text'] = $text;\n\n        return $Block;\n    }\n\n    #\n    # Comment\n\n    protected function blockComment($Line)\n    {\n        if ($this->markupEscaped)\n        {\n            return;\n        }\n\n        if (isset($Line['text'][3]) and $Line['text'][3] === '-' and $Line['text'][2] === '-' and $Line['text'][1] === '!')\n        {\n            $Block = array(\n                'markup' => $Line['body'],\n            );\n\n            if (preg_match('/-->$/', $Line['text']))\n            {\n                $Block['closed'] = true;\n            }\n\n            return $Block;\n        }\n    }\n\n    protected function blockCommentContinue($Line, array $Block)\n    {\n        if (isset($Block['closed']))\n        {\n            return;\n        }\n\n        $Block['markup'] .= \"\\n\" . $Line['body'];\n\n        if (preg_match('/-->$/', $Line['text']))\n        {\n            $Block['closed'] = true;\n        }\n\n        return $Block;\n    }\n\n    #\n    # Fenced Code\n\n    protected function blockFencedCode($Line)\n    {\n        if (preg_match('/^['.$Line['text'][0].']{3,}[ ]*([\\w-]+)?[ ]*$/', $Line['text'], $matches))\n        {\n            $Element = array(\n                'name' => 'code',\n                'text' => '',\n            );\n\n            if (isset($matches[1]))\n            {\n                $class = 'language-'.$matches[1];\n\n                $Element['attributes'] = array(\n                    'class' => $class,\n                );\n            }\n\n            $Block = array(\n                'char' => $Line['text'][0],\n                'element' => array(\n                    'name' => 'pre',\n                    'handler' => 'element',\n                    'text' => $Element,\n                ),\n            );\n\n            return $Block;\n        }\n    }\n\n    protected function blockFencedCodeContinue($Line, $Block)\n    {\n        if (isset($Block['complete']))\n        {\n            return;\n        }\n\n        if (isset($Block['interrupted']))\n        {\n            $Block['element']['text']['text'] .= \"\\n\";\n\n            unset($Block['interrupted']);\n        }\n\n        if (preg_match('/^'.$Block['char'].'{3,}[ ]*$/', $Line['text']))\n        {\n            $Block['element']['text']['text'] = substr($Block['element']['text']['text'], 1);\n\n            $Block['complete'] = true;\n\n            return $Block;\n        }\n\n        $Block['element']['text']['text'] .= \"\\n\".$Line['body'];;\n\n        return $Block;\n    }\n\n    protected function blockFencedCodeComplete($Block)\n    {\n        $text = $Block['element']['text']['text'];\n\n        $text = htmlspecialchars($text, ENT_NOQUOTES, 'UTF-8');\n\n        $Block['element']['text']['text'] = $text;\n\n        return $Block;\n    }\n\n    #\n    # Header\n\n    protected function blockHeader($Line)\n    {\n        if (isset($Line['text'][1]))\n        {\n            $level = 1;\n\n            while (isset($Line['text'][$level]) and $Line['text'][$level] === '#')\n            {\n                $level ++;\n            }\n\n            if ($level > 6)\n            {\n                return;\n            }\n\n            $text = trim($Line['text'], '# ');\n\n            $Block = array(\n                'element' => array(\n                    'name' => 'h' . min(6, $level),\n                    'text' => $text,\n                    'handler' => 'line',\n                ),\n            );\n\n            return $Block;\n        }\n    }\n\n    #\n    # List\n\n    protected function blockList($Line)\n    {\n        list($name, $pattern) = $Line['text'][0] <= '-' ? array('ul', '[*+-]') : array('ol', '[0-9]+[.]');\n\n        if (preg_match('/^('.$pattern.'[ ]+)(.*)/', $Line['text'], $matches))\n        {\n            $Block = array(\n                'indent' => $Line['indent'],\n                'pattern' => $pattern,\n                'element' => array(\n                    'name' => $name,\n                    'handler' => 'elements',\n                ),\n            );\n\n            $Block['li'] = array(\n                'name' => 'li',\n                'handler' => 'li',\n                'text' => array(\n                    $matches[2],\n                ),\n            );\n\n            $Block['element']['text'] []= & $Block['li'];\n\n            return $Block;\n        }\n    }\n\n    protected function blockListContinue($Line, array $Block)\n    {\n        if ($Block['indent'] === $Line['indent'] and preg_match('/^'.$Block['pattern'].'(?:[ ]+(.*)|$)/', $Line['text'], $matches))\n        {\n            if (isset($Block['interrupted']))\n            {\n                $Block['li']['text'] []= '';\n\n                unset($Block['interrupted']);\n            }\n\n            unset($Block['li']);\n\n            $text = isset($matches[1]) ? $matches[1] : '';\n\n            $Block['li'] = array(\n                'name' => 'li',\n                'handler' => 'li',\n                'text' => array(\n                    $text,\n                ),\n            );\n\n            $Block['element']['text'] []= & $Block['li'];\n\n            return $Block;\n        }\n\n        if ($Line['text'][0] === '[' and $this->blockReference($Line))\n        {\n            return $Block;\n        }\n\n        if ( ! isset($Block['interrupted']))\n        {\n            $text = preg_replace('/^[ ]{0,4}/', '', $Line['body']);\n\n            $Block['li']['text'] []= $text;\n\n            return $Block;\n        }\n\n        if ($Line['indent'] > 0)\n        {\n            $Block['li']['text'] []= '';\n\n            $text = preg_replace('/^[ ]{0,4}/', '', $Line['body']);\n\n            $Block['li']['text'] []= $text;\n\n            unset($Block['interrupted']);\n\n            return $Block;\n        }\n    }\n\n    #\n    # Quote\n\n    protected function blockQuote($Line)\n    {\n        if (preg_match('/^>[ ]?(.*)/', $Line['text'], $matches))\n        {\n            $Block = array(\n                'element' => array(\n                    'name' => 'blockquote',\n                    'handler' => 'lines',\n                    'text' => (array) $matches[1],\n                ),\n            );\n\n            return $Block;\n        }\n    }\n\n    protected function blockQuoteContinue($Line, array $Block)\n    {\n        if ($Line['text'][0] === '>' and preg_match('/^>[ ]?(.*)/', $Line['text'], $matches))\n        {\n            if (isset($Block['interrupted']))\n            {\n                $Block['element']['text'] []= '';\n\n                unset($Block['interrupted']);\n            }\n\n            $Block['element']['text'] []= $matches[1];\n\n            return $Block;\n        }\n\n        if ( ! isset($Block['interrupted']))\n        {\n            $Block['element']['text'] []= $Line['text'];\n\n            return $Block;\n        }\n    }\n\n    #\n    # Rule\n\n    protected function blockRule($Line)\n    {\n        if (preg_match('/^(['.$Line['text'][0].'])([ ]*\\1){2,}[ ]*$/', $Line['text']))\n        {\n            $Block = array(\n                'element' => array(\n                    'name' => 'hr'\n                ),\n            );\n\n            return $Block;\n        }\n    }\n\n    #\n    # Setext\n\n    protected function blockSetextHeader($Line, array $Block = null)\n    {\n        if ( ! isset($Block) or isset($Block['type']) or isset($Block['interrupted']))\n        {\n            return;\n        }\n\n        if (chop($Line['text'], $Line['text'][0]) === '')\n        {\n            $Block['element']['name'] = $Line['text'][0] === '=' ? 'h1' : 'h2';\n\n            return $Block;\n        }\n    }\n\n    #\n    # Markup\n\n    protected function blockMarkup($Line)\n    {\n        if ($this->markupEscaped)\n        {\n            return;\n        }\n\n        if (preg_match('/^<(\\w*)(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*(\\/)?>/', $Line['text'], $matches))\n        {\n            $element = strtolower($matches[1]);\n\n            if (in_array($element, $this->textLevelElements))\n            {\n                return;\n            }\n\n            $Block = array(\n                'name' => $matches[1],\n                'depth' => 0,\n                'markup' => $Line['text'],\n            );\n\n            $length = strlen($matches[0]);\n\n            $remainder = substr($Line['text'], $length);\n\n            if (trim($remainder) === '')\n            {\n                if (isset($matches[2]) or in_array($matches[1], $this->voidElements))\n                {\n                    $Block['closed'] = true;\n\n                    $Block['void'] = true;\n                }\n            }\n            else\n            {\n                if (isset($matches[2]) or in_array($matches[1], $this->voidElements))\n                {\n                    return;\n                }\n\n                if (preg_match('/<\\/'.$matches[1].'>[ ]*$/i', $remainder))\n                {\n                    $Block['closed'] = true;\n                }\n            }\n\n            return $Block;\n        }\n    }\n\n    protected function blockMarkupContinue($Line, array $Block)\n    {\n        if (isset($Block['closed']))\n        {\n            return;\n        }\n\n        if (preg_match('/^<'.$Block['name'].'(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*>/i', $Line['text'])) # open\n        {\n            $Block['depth'] ++;\n        }\n\n        if (preg_match('/(.*?)<\\/'.$Block['name'].'>[ ]*$/i', $Line['text'], $matches)) # close\n        {\n            if ($Block['depth'] > 0)\n            {\n                $Block['depth'] --;\n            }\n            else\n            {\n                $Block['closed'] = true;\n            }\n        }\n\n        if (isset($Block['interrupted']))\n        {\n            $Block['markup'] .= \"\\n\";\n\n            unset($Block['interrupted']);\n        }\n\n        $Block['markup'] .= \"\\n\".$Line['body'];\n\n        return $Block;\n    }\n\n    #\n    # Reference\n\n    protected function blockReference($Line)\n    {\n        if (preg_match('/^\\[(.+?)\\]:[ ]*<?(\\S+?)>?(?:[ ]+[\"\\'(](.+)[\"\\')])?[ ]*$/', $Line['text'], $matches))\n        {\n            $id = strtolower($matches[1]);\n\n            $Data = array(\n                'url' => $matches[2],\n                'title' => null,\n            );\n\n            if (isset($matches[3]))\n            {\n                $Data['title'] = $matches[3];\n            }\n\n            $this->DefinitionData['Reference'][$id] = $Data;\n\n            $Block = array(\n                'hidden' => true,\n            );\n\n            return $Block;\n        }\n    }\n\n    #\n    # Table\n\n    protected function blockTable($Line, array $Block = null)\n    {\n        if ( ! isset($Block) or isset($Block['type']) or isset($Block['interrupted']))\n        {\n            return;\n        }\n\n        if (strpos($Block['element']['text'], '|') !== false and chop($Line['text'], ' -:|') === '')\n        {\n            $alignments = array();\n\n            $divider = $Line['text'];\n\n            $divider = trim($divider);\n            $divider = trim($divider, '|');\n\n            $dividerCells = explode('|', $divider);\n\n            foreach ($dividerCells as $dividerCell)\n            {\n                $dividerCell = trim($dividerCell);\n\n                if ($dividerCell === '')\n                {\n                    continue;\n                }\n\n                $alignment = null;\n\n                if ($dividerCell[0] === ':')\n                {\n                    $alignment = 'left';\n                }\n\n                if (substr($dividerCell, - 1) === ':')\n                {\n                    $alignment = $alignment === 'left' ? 'center' : 'right';\n                }\n\n                $alignments []= $alignment;\n            }\n\n            # ~\n\n            $HeaderElements = array();\n\n            $header = $Block['element']['text'];\n\n            $header = trim($header);\n            $header = trim($header, '|');\n\n            $headerCells = explode('|', $header);\n\n            foreach ($headerCells as $index => $headerCell)\n            {\n                $headerCell = trim($headerCell);\n\n                $HeaderElement = array(\n                    'name' => 'th',\n                    'text' => $headerCell,\n                    'handler' => 'line',\n                );\n\n                if (isset($alignments[$index]))\n                {\n                    $alignment = $alignments[$index];\n\n                    $HeaderElement['attributes'] = array(\n                        'style' => 'text-align: '.$alignment.';',\n                    );\n                }\n\n                $HeaderElements []= $HeaderElement;\n            }\n\n            # ~\n\n            $Block = array(\n                'alignments' => $alignments,\n                'identified' => true,\n                'element' => array(\n                    'name' => 'table',\n                    'handler' => 'elements',\n                ),\n            );\n\n            $Block['element']['text'] []= array(\n                'name' => 'thead',\n                'handler' => 'elements',\n            );\n\n            $Block['element']['text'] []= array(\n                'name' => 'tbody',\n                'handler' => 'elements',\n                'text' => array(),\n            );\n\n            $Block['element']['text'][0]['text'] []= array(\n                'name' => 'tr',\n                'handler' => 'elements',\n                'text' => $HeaderElements,\n            );\n\n            return $Block;\n        }\n    }\n\n    protected function blockTableContinue($Line, array $Block)\n    {\n        if (isset($Block['interrupted']))\n        {\n            return;\n        }\n\n        if ($Line['text'][0] === '|' or strpos($Line['text'], '|'))\n        {\n            $Elements = array();\n\n            $row = $Line['text'];\n\n            $row = trim($row);\n            $row = trim($row, '|');\n\n            preg_match_all('/(?:(\\\\\\\\[|])|[^|`]|`[^`]+`|`)+/', $row, $matches);\n\n            foreach ($matches[0] as $index => $cell)\n            {\n                $cell = trim($cell);\n\n                $Element = array(\n                    'name' => 'td',\n                    'handler' => 'line',\n                    'text' => $cell,\n                );\n\n                if (isset($Block['alignments'][$index]))\n                {\n                    $Element['attributes'] = array(\n                        'style' => 'text-align: '.$Block['alignments'][$index].';',\n                    );\n                }\n\n                $Elements []= $Element;\n            }\n\n            $Element = array(\n                'name' => 'tr',\n                'handler' => 'elements',\n                'text' => $Elements,\n            );\n\n            $Block['element']['text'][1]['text'] []= $Element;\n\n            return $Block;\n        }\n    }\n\n    #\n    # ~\n    #\n\n    protected function paragraph($Line)\n    {\n        $Block = array(\n            'element' => array(\n                'name' => 'p',\n                'text' => $Line['text'],\n                'handler' => 'line',\n            ),\n        );\n\n        return $Block;\n    }\n\n    #\n    # Inline Elements\n    #\n\n    protected $InlineTypes = array(\n        '\"' => array('SpecialCharacter'),\n        '!' => array('Image'),\n        '&' => array('SpecialCharacter'),\n        '*' => array('Emphasis'),\n        ':' => array('Url'),\n        '<' => array('UrlTag', 'EmailTag', 'Markup', 'SpecialCharacter'),\n        '>' => array('SpecialCharacter'),\n        '[' => array('Link'),\n        '_' => array('Emphasis'),\n        '`' => array('Code'),\n        '~' => array('Strikethrough'),\n        '\\\\' => array('EscapeSequence'),\n    );\n\n    # ~\n\n    protected $inlineMarkerList = '!\"*_&[:<>`~\\\\';\n\n    #\n    # ~\n    #\n\n    public function line($text)\n    {\n        $markup = '';\n\n        # $excerpt is based on the first occurrence of a marker\n\n        while ($excerpt = strpbrk($text, $this->inlineMarkerList))\n        {\n            $marker = $excerpt[0];\n\n            $markerPosition = strpos($text, $marker);\n\n            $Excerpt = array('text' => $excerpt, 'context' => $text);\n\n            foreach ($this->InlineTypes[$marker] as $inlineType)\n            {\n                $Inline = $this->{'inline'.$inlineType}($Excerpt);\n\n                if ( ! isset($Inline))\n                {\n                    continue;\n                }\n\n                # makes sure that the inline belongs to \"our\" marker\n\n                if (isset($Inline['position']) and $Inline['position'] > $markerPosition)\n                {\n                    continue;\n                }\n\n                # sets a default inline position\n\n                if ( ! isset($Inline['position']))\n                {\n                    $Inline['position'] = $markerPosition;\n                }\n\n                # the text that comes before the inline\n                $unmarkedText = substr($text, 0, $Inline['position']);\n\n                # compile the unmarked text\n                $markup .= $this->unmarkedText($unmarkedText);\n\n                # compile the inline\n                $markup .= isset($Inline['markup']) ? $Inline['markup'] : $this->element($Inline['element']);\n\n                # remove the examined text\n                $text = substr($text, $Inline['position'] + $Inline['extent']);\n\n                continue 2;\n            }\n\n            # the marker does not belong to an inline\n\n            $unmarkedText = substr($text, 0, $markerPosition + 1);\n\n            $markup .= $this->unmarkedText($unmarkedText);\n\n            $text = substr($text, $markerPosition + 1);\n        }\n\n        $markup .= $this->unmarkedText($text);\n\n        return $markup;\n    }\n\n    #\n    # ~\n    #\n\n    protected function inlineCode($Excerpt)\n    {\n        $marker = $Excerpt['text'][0];\n\n        if (preg_match('/^('.$marker.'+)[ ]*(.+?)[ ]*(?<!'.$marker.')\\1(?!'.$marker.')/s', $Excerpt['text'], $matches))\n        {\n            $text = $matches[2];\n            $text = htmlspecialchars($text, ENT_NOQUOTES, 'UTF-8');\n            $text = preg_replace(\"/[ ]*\\n/\", ' ', $text);\n\n            return array(\n                'extent' => strlen($matches[0]),\n                'element' => array(\n                    'name' => 'code',\n                    'text' => $text,\n                ),\n            );\n        }\n    }\n\n    protected function inlineEmailTag($Excerpt)\n    {\n        if (strpos($Excerpt['text'], '>') !== false and preg_match('/^<((mailto:)?\\S+?@\\S+?)>/i', $Excerpt['text'], $matches))\n        {\n            $url = $matches[1];\n\n            if ( ! isset($matches[2]))\n            {\n                $url = 'mailto:' . $url;\n            }\n\n            return array(\n                'extent' => strlen($matches[0]),\n                'element' => array(\n                    'name' => 'a',\n                    'text' => $matches[1],\n                    'attributes' => array(\n                        'href' => $url,\n                    ),\n                ),\n            );\n        }\n    }\n\n    protected function inlineEmphasis($Excerpt)\n    {\n        if ( ! isset($Excerpt['text'][1]))\n        {\n            return;\n        }\n\n        $marker = $Excerpt['text'][0];\n\n        if ($Excerpt['text'][1] === $marker and preg_match($this->StrongRegex[$marker], $Excerpt['text'], $matches))\n        {\n            $emphasis = 'strong';\n        }\n        elseif (preg_match($this->EmRegex[$marker], $Excerpt['text'], $matches))\n        {\n            $emphasis = 'em';\n        }\n        else\n        {\n            return;\n        }\n\n        return array(\n            'extent' => strlen($matches[0]),\n            'element' => array(\n                'name' => $emphasis,\n                'handler' => 'line',\n                'text' => $matches[1],\n            ),\n        );\n    }\n\n    protected function inlineEscapeSequence($Excerpt)\n    {\n        if (isset($Excerpt['text'][1]) and in_array($Excerpt['text'][1], $this->specialCharacters))\n        {\n            return array(\n                'markup' => $Excerpt['text'][1],\n                'extent' => 2,\n            );\n        }\n    }\n\n    protected function inlineImage($Excerpt)\n    {\n        if ( ! isset($Excerpt['text'][1]) or $Excerpt['text'][1] !== '[')\n        {\n            return;\n        }\n\n        $Excerpt['text']= substr($Excerpt['text'], 1);\n\n        $Link = $this->inlineLink($Excerpt);\n\n        if ($Link === null)\n        {\n            return;\n        }\n\n        $Inline = array(\n            'extent' => $Link['extent'] + 1,\n            'element' => array(\n                'name' => 'img',\n                'attributes' => array(\n                    'src' => $Link['element']['attributes']['href'],\n                    'alt' => $Link['element']['text'],\n                ),\n            ),\n        );\n\n        $Inline['element']['attributes'] += $Link['element']['attributes'];\n\n        unset($Inline['element']['attributes']['href']);\n\n        return $Inline;\n    }\n\n    protected function inlineLink($Excerpt)\n    {\n        $Element = array(\n            'name' => 'a',\n            'handler' => 'line',\n            'text' => null,\n            'attributes' => array(\n                'href' => null,\n                'title' => null,\n            ),\n        );\n\n        $extent = 0;\n\n        $remainder = $Excerpt['text'];\n\n        if (preg_match('/\\[((?:[^][]|(?R))*)\\]/', $remainder, $matches))\n        {\n            $Element['text'] = $matches[1];\n\n            $extent += strlen($matches[0]);\n\n            $remainder = substr($remainder, $extent);\n        }\n        else\n        {\n            return;\n        }\n\n        if (preg_match('/^[(]((?:[^ ()]|[(][^ )]+[)])+)(?:[ ]+(\"[^\"]*\"|\\'[^\\']*\\'))?[)]/', $remainder, $matches))\n        {\n            $Element['attributes']['href'] = $matches[1];\n\n            if (isset($matches[2]))\n            {\n                $Element['attributes']['title'] = substr($matches[2], 1, - 1);\n            }\n\n            $extent += strlen($matches[0]);\n        }\n        else\n        {\n            if (preg_match('/^\\s*\\[(.*?)\\]/', $remainder, $matches))\n            {\n                $definition = strlen($matches[1]) ? $matches[1] : $Element['text'];\n                $definition = strtolower($definition);\n\n                $extent += strlen($matches[0]);\n            }\n            else\n            {\n                $definition = strtolower($Element['text']);\n            }\n\n            if ( ! isset($this->DefinitionData['Reference'][$definition]))\n            {\n                return;\n            }\n\n            $Definition = $this->DefinitionData['Reference'][$definition];\n\n            $Element['attributes']['href'] = $Definition['url'];\n            $Element['attributes']['title'] = $Definition['title'];\n        }\n\n        $Element['attributes']['href'] = str_replace(array('&', '<'), array('&amp;', '&lt;'), $Element['attributes']['href']);\n\n        return array(\n            'extent' => $extent,\n            'element' => $Element,\n        );\n    }\n\n    protected function inlineMarkup($Excerpt)\n    {\n        if ($this->markupEscaped or strpos($Excerpt['text'], '>') === false)\n        {\n            return;\n        }\n\n        if ($Excerpt['text'][1] === '/' and preg_match('/^<\\/\\w*[ ]*>/s', $Excerpt['text'], $matches))\n        {\n            return array(\n                'markup' => $matches[0],\n                'extent' => strlen($matches[0]),\n            );\n        }\n\n        if ($Excerpt['text'][1] === '!' and preg_match('/^<!---?[^>-](?:-?[^-])*-->/s', $Excerpt['text'], $matches))\n        {\n            return array(\n                'markup' => $matches[0],\n                'extent' => strlen($matches[0]),\n            );\n        }\n\n        if ($Excerpt['text'][1] !== ' ' and preg_match('/^<\\w*(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*\\/?>/s', $Excerpt['text'], $matches))\n        {\n            return array(\n                'markup' => $matches[0],\n                'extent' => strlen($matches[0]),\n            );\n        }\n    }\n\n    protected function inlineSpecialCharacter($Excerpt)\n    {\n        if ($Excerpt['text'][0] === '&' and ! preg_match('/^&#?\\w+;/', $Excerpt['text']))\n        {\n            return array(\n                'markup' => '&amp;',\n                'extent' => 1,\n            );\n        }\n\n        $SpecialCharacter = array('>' => 'gt', '<' => 'lt', '\"' => 'quot');\n\n        if (isset($SpecialCharacter[$Excerpt['text'][0]]))\n        {\n            return array(\n                'markup' => '&'.$SpecialCharacter[$Excerpt['text'][0]].';',\n                'extent' => 1,\n            );\n        }\n    }\n\n    protected function inlineStrikethrough($Excerpt)\n    {\n        if ( ! isset($Excerpt['text'][1]))\n        {\n            return;\n        }\n\n        if ($Excerpt['text'][1] === '~' and preg_match('/^~~(?=\\S)(.+?)(?<=\\S)~~/', $Excerpt['text'], $matches))\n        {\n            return array(\n                'extent' => strlen($matches[0]),\n                'element' => array(\n                    'name' => 'del',\n                    'text' => $matches[1],\n                    'handler' => 'line',\n                ),\n            );\n        }\n    }\n\n    protected function inlineUrl($Excerpt)\n    {\n        if ($this->urlsLinked !== true or ! isset($Excerpt['text'][2]) or $Excerpt['text'][2] !== '/')\n        {\n            return;\n        }\n\n        if (preg_match('/\\bhttps?:[\\/]{2}[^\\s<]+\\b\\/*/ui', $Excerpt['context'], $matches, PREG_OFFSET_CAPTURE))\n        {\n            $Inline = array(\n                'extent' => strlen($matches[0][0]),\n                'position' => $matches[0][1],\n                'element' => array(\n                    'name' => 'a',\n                    'text' => $matches[0][0],\n                    'attributes' => array(\n                        'href' => $matches[0][0],\n                    ),\n                ),\n            );\n\n            return $Inline;\n        }\n    }\n\n    protected function inlineUrlTag($Excerpt)\n    {\n        if (strpos($Excerpt['text'], '>') !== false and preg_match('/^<(\\w+:\\/{2}[^ >]+)>/i', $Excerpt['text'], $matches))\n        {\n            $url = str_replace(array('&', '<'), array('&amp;', '&lt;'), $matches[1]);\n\n            return array(\n                'extent' => strlen($matches[0]),\n                'element' => array(\n                    'name' => 'a',\n                    'text' => $url,\n                    'attributes' => array(\n                        'href' => $url,\n                    ),\n                ),\n            );\n        }\n    }\n\n    # ~\n\n    protected function unmarkedText($text)\n    {\n        if ($this->breaksEnabled)\n        {\n            $text = preg_replace('/[ ]*\\n/', \"<br />\\n\", $text);\n        }\n        else\n        {\n            $text = preg_replace('/(?:[ ][ ]+|[ ]*\\\\\\\\)\\n/', \"<br />\\n\", $text);\n            $text = str_replace(\" \\n\", \"\\n\", $text);\n        }\n\n        return $text;\n    }\n\n    #\n    # Handlers\n    #\n\n    protected function element(array $Element)\n    {\n        $markup = '<'.$Element['name'];\n\n        if (isset($Element['attributes']))\n        {\n            foreach ($Element['attributes'] as $name => $value)\n            {\n                if ($value === null)\n                {\n                    continue;\n                }\n\n                $markup .= ' '.$name.'=\"'.$value.'\"';\n            }\n        }\n\n        if (isset($Element['text']))\n        {\n            $markup .= '>';\n\n            if (isset($Element['handler']))\n            {\n                $markup .= $this->{$Element['handler']}($Element['text']);\n            }\n            else\n            {\n                $markup .= $Element['text'];\n            }\n\n            $markup .= '</'.$Element['name'].'>';\n        }\n        else\n        {\n            $markup .= ' />';\n        }\n\n        return $markup;\n    }\n\n    protected function elements(array $Elements)\n    {\n        $markup = '';\n\n        foreach ($Elements as $Element)\n        {\n            $markup .= \"\\n\" . $this->element($Element);\n        }\n\n        $markup .= \"\\n\";\n\n        return $markup;\n    }\n\n    # ~\n\n    protected function li($lines)\n    {\n        $markup = $this->lines($lines);\n\n        $trimmedMarkup = trim($markup);\n\n        if ( ! in_array('', $lines) and substr($trimmedMarkup, 0, 3) === '<p>')\n        {\n            $markup = $trimmedMarkup;\n            $markup = substr($markup, 3);\n\n            $position = strpos($markup, \"</p>\");\n\n            $markup = substr_replace($markup, '', $position, 4);\n        }\n\n        return $markup;\n    }\n\n    #\n    # Deprecated Methods\n    #\n\n    function parse($text)\n    {\n        $markup = $this->text($text);\n\n        return $markup;\n    }\n\n    #\n    # Static Methods\n    #\n\n    static function instance($name = 'default')\n    {\n        if (isset(self::$instances[$name]))\n        {\n            return self::$instances[$name];\n        }\n\n        $instance = new static();\n\n        self::$instances[$name] = $instance;\n\n        return $instance;\n    }\n\n    private static $instances = array();\n\n    #\n    # Fields\n    #\n\n    protected $DefinitionData;\n\n    #\n    # Read-Only\n\n    protected $specialCharacters = array(\n        '\\\\', '`', '*', '_', '{', '}', '[', ']', '(', ')', '>', '#', '+', '-', '.', '!', '|',\n    );\n\n    protected $StrongRegex = array(\n        '*' => '/^[*]{2}((?:\\\\\\\\\\*|[^*]|[*][^*]*[*])+?)[*]{2}(?![*])/s',\n        '_' => '/^__((?:\\\\\\\\_|[^_]|_[^_]*_)+?)__(?!_)/us',\n    );\n\n    protected $EmRegex = array(\n        '*' => '/^[*]((?:\\\\\\\\\\*|[^*]|[*][*][^*]+?[*][*])+?)[*](?![*])/s',\n        '_' => '/^_((?:\\\\\\\\_|[^_]|__[^_]*__)+?)_(?!_)\\b/us',\n    );\n\n    protected $regexHtmlAttribute = '[a-zA-Z_:][\\w:.-]*(?:\\s*=\\s*(?:[^\"\\'=<>`\\s]+|\"[^\"]*\"|\\'[^\\']*\\'))?';\n\n    protected $voidElements = array(\n        'area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source',\n    );\n\n    protected $textLevelElements = array(\n        'a', 'br', 'bdo', 'abbr', 'blink', 'nextid', 'acronym', 'basefont',\n        'b', 'em', 'big', 'cite', 'small', 'spacer', 'listing',\n        'i', 'rp', 'del', 'code',          'strike', 'marquee',\n        'q', 'rt', 'ins', 'font',          'strong',\n        's', 'tt', 'sub', 'mark',\n        'u', 'xm', 'sup', 'nobr',\n                   'var', 'ruby',\n                   'wbr', 'span',\n                          'time',\n    );\n}\n"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/Phpqrcode/phpqrcode.php",
    "content": "<?php\n\n/*\n * PHP QR Code encoder\n *\n * This file contains MERGED version of PHP QR Code library.\n * It was auto-generated from full version for your convenience.\n *\n * This merged version was configured to not requre any external files,\n * with disabled cache, error loging and weker but faster mask matching.\n * If you need tune it up please use non-merged version.\n *\n * For full version, documentation, examples of use please visit:\n *\n *    http://phpqrcode.sourceforge.net/\n *    https://sourceforge.net/projects/phpqrcode/\n *\n * PHP QR Code is distributed under LGPL 3\n * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>\n *\n * This library is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 3 of the License, or any later version.\n *\n * This library is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with this library; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n */\n \n \n\n/*\n * Version: 1.1.4\n * Build: 2010100721\n */\n\n\n\n//---- qrconst.php -----------------------------\n\n\n\n\n\n/*\n * PHP QR Code encoder\n *\n * Common constants\n *\n * Based on libqrencode C library distributed under LGPL 2.1\n * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>\n *\n * PHP QR Code is distributed under LGPL 3\n * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>\n *\n * This library is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 3 of the License, or any later version.\n *\n * This library is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with this library; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n */\n \n\t// Encoding modes\n\t \n\tdefine('QR_MODE_NUL', -1);\n\tdefine('QR_MODE_NUM', 0);\n\tdefine('QR_MODE_AN', 1);\n\tdefine('QR_MODE_8', 2);\n\tdefine('QR_MODE_KANJI', 3);\n\tdefine('QR_MODE_STRUCTURE', 4);\n\n\t// Levels of error correction.\n\n\tdefine('QR_ECLEVEL_L', 0);\n\tdefine('QR_ECLEVEL_M', 1);\n\tdefine('QR_ECLEVEL_Q', 2);\n\tdefine('QR_ECLEVEL_H', 3);\n\t\n\t// Supported output formats\n\t\n\tdefine('QR_FORMAT_TEXT', 0);\n\tdefine('QR_FORMAT_PNG',  1);\n\t\n\tclass qrstr {\n\t\tpublic static function set(&$srctab, $x, $y, $repl, $replLen = false) {\n\t\t\t$srctab[$y] = substr_replace($srctab[$y], ($replLen !== false)?substr($repl,0,$replLen):$repl, $x, ($replLen !== false)?$replLen:strlen($repl));\n\t\t}\n\t}\t\n\n\n\n//---- merged_config.php -----------------------------\n\n\n\n\n/*\n * PHP QR Code encoder\n *\n * Config file, tuned-up for merged verion\n */\n     \n    define('QR_CACHEABLE', false);       // use cache - more disk reads but less CPU power, masks and format templates are stored there\n    define('QR_CACHE_DIR', false);       // used when QR_CACHEABLE === true\n    define('QR_LOG_DIR', false);         // default error logs dir   \n    \n    define('QR_FIND_BEST_MASK', true);                                                          // if true, estimates best mask (spec. default, but extremally slow; set to false to significant performance boost but (propably) worst quality code\n    define('QR_FIND_FROM_RANDOM', 2);                                                       // if false, checks all masks available, otherwise value tells count of masks need to be checked, mask id are got randomly\n    define('QR_DEFAULT_MASK', 2);                                                               // when QR_FIND_BEST_MASK === false\n                                                  \n    define('QR_PNG_MAXIMUM_SIZE',  1024);                                                       // maximum allowed png image width (in pixels), tune to make sure GD and PHP can handle such big images\n                                                  \n\n\n\n//---- qrtools.php -----------------------------\n\n\n\n\n/*\n * PHP QR Code encoder\n *\n * Toolset, handy and debug utilites.\n *\n * PHP QR Code is distributed under LGPL 3\n * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>\n *\n * This library is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 3 of the License, or any later version.\n *\n * This library is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with this library; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n    class QRtools {\n    \n        //----------------------------------------------------------------------\n        public static function binarize($frame)\n        {\n            $len = count($frame);\n            foreach ($frame as &$frameLine) {\n                \n                for($i=0; $i<$len; $i++) {\n                    $frameLine[$i] = (ord($frameLine[$i])&1)?'1':'0';\n                }\n            }\n            \n            return $frame;\n        }\n        \n        //----------------------------------------------------------------------\n        public static function tcpdfBarcodeArray($code, $mode = 'QR,L', $tcPdfVersion = '4.5.037')\n        {\n            $barcode_array = array();\n            \n            if (!is_array($mode))\n                $mode = explode(',', $mode);\n                \n            $eccLevel = 'L';\n                \n            if (count($mode) > 1) {\n                $eccLevel = $mode[1];\n            }\n                \n            $qrTab = QRcode::text($code, false, $eccLevel);\n            $size = count($qrTab);\n                \n            $barcode_array['num_rows'] = $size;\n            $barcode_array['num_cols'] = $size;\n            $barcode_array['bcode'] = array();\n                \n            foreach ($qrTab as $line) {\n                $arrAdd = array();\n                foreach(str_split($line) as $char)\n                    $arrAdd[] = ($char=='1')?1:0;\n                $barcode_array['bcode'][] = $arrAdd;\n            }\n                    \n            return $barcode_array;\n        }\n        \n        //----------------------------------------------------------------------\n        public static function clearCache()\n        {\n            self::$frames = array();\n        }\n        \n        //----------------------------------------------------------------------\n        public static function buildCache()\n        {\n\t\t\tQRtools::markTime('before_build_cache');\n\t\t\t\n\t\t\t$mask = new QRmask();\n            for ($a=1; $a <= QRSPEC_VERSION_MAX; $a++) {\n                $frame = QRspec::newFrame($a);\n                if (QR_IMAGE) {\n                    $fileName = QR_CACHE_DIR.'frame_'.$a.'.png';\n                    QRimage::png(self::binarize($frame), $fileName, 1, 0);\n                }\n\t\t\t\t\n\t\t\t\t$width = count($frame);\n\t\t\t\t$bitMask = array_fill(0, $width, array_fill(0, $width, 0));\n\t\t\t\tfor ($maskNo=0; $maskNo<8; $maskNo++)\n\t\t\t\t\t$mask->makeMaskNo($maskNo, $width, $frame, $bitMask, true);\n            }\n\t\t\t\n\t\t\tQRtools::markTime('after_build_cache');\n        }\n\n        //----------------------------------------------------------------------\n        public static function log($outfile, $err)\n        {\n            if (QR_LOG_DIR !== false) {\n                if ($err != '') {\n                    if ($outfile !== false) {\n                        file_put_contents(QR_LOG_DIR.basename($outfile).'-errors.txt', date('Y-m-d H:i:s').': '.$err, FILE_APPEND);\n                    } else {\n                        file_put_contents(QR_LOG_DIR.'errors.txt', date('Y-m-d H:i:s').': '.$err, FILE_APPEND);\n                    }\n                }    \n            }\n        }\n        \n        //----------------------------------------------------------------------\n        public static function dumpMask($frame) \n        {\n            $width = count($frame);\n            for($y=0;$y<$width;$y++) {\n                for($x=0;$x<$width;$x++) {\n                    echo ord($frame[$y][$x]).',';\n                }\n            }\n        }\n        \n        //----------------------------------------------------------------------\n        public static function markTime($markerId)\n        {\n            list($usec, $sec) = explode(\" \", microtime());\n            $time = ((float)$usec + (float)$sec);\n            \n            if (!isset($GLOBALS['qr_time_bench']))\n                $GLOBALS['qr_time_bench'] = array();\n            \n            $GLOBALS['qr_time_bench'][$markerId] = $time;\n        }\n        \n        //----------------------------------------------------------------------\n        public static function timeBenchmark()\n        {\n            self::markTime('finish');\n        \n            $lastTime = 0;\n            $startTime = 0;\n            $p = 0;\n\n            echo '<table cellpadding=\"3\" cellspacing=\"1\">\n                    <thead><tr style=\"border-bottom:1px solid silver\"><td colspan=\"2\" style=\"text-align:center\">BENCHMARK</td></tr></thead>\n                    <tbody>';\n\n            foreach($GLOBALS['qr_time_bench'] as $markerId=>$thisTime) {\n                if ($p > 0) {\n                    echo '<tr><th style=\"text-align:right\">till '.$markerId.': </th><td>'.number_format($thisTime-$lastTime, 6).'s</td></tr>';\n                } else {\n                    $startTime = $thisTime;\n                }\n                \n                $p++;\n                $lastTime = $thisTime;\n            }\n            \n            echo '</tbody><tfoot>\n                <tr style=\"border-top:2px solid black\"><th style=\"text-align:right\">TOTAL: </th><td>'.number_format($lastTime-$startTime, 6).'s</td></tr>\n            </tfoot>\n            </table>';\n        }\n        \n    }\n    \n    //##########################################################################\n    \n    QRtools::markTime('start');\n    \n\n\n\n//---- qrspec.php -----------------------------\n\n\n\n\n/*\n * PHP QR Code encoder\n *\n * QR Code specifications\n *\n * Based on libqrencode C library distributed under LGPL 2.1\n * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>\n *\n * PHP QR Code is distributed under LGPL 3\n * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>\n *\n * The following data / specifications are taken from\n * \"Two dimensional symbol -- QR-code -- Basic Specification\" (JIS X0510:2004)\n *  or\n * \"Automatic identification and data capture techniques -- \n *  QR Code 2005 bar code symbology specification\" (ISO/IEC 18004:2006)\n *\n * This library is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 3 of the License, or any later version.\n *\n * This library is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with this library; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n */\n \n    define('QRSPEC_VERSION_MAX', 40);\n    define('QRSPEC_WIDTH_MAX',   177);\n\n    define('QRCAP_WIDTH',        0);\n    define('QRCAP_WORDS',        1);\n    define('QRCAP_REMINDER',     2);\n    define('QRCAP_EC',           3);\n\n    class QRspec {\n    \n        public static $capacity = array(\n            array(  0,    0, 0, array(   0,    0,    0,    0)),\n            array( 21,   26, 0, array(   7,   10,   13,   17)), // 1\n            array( 25,   44, 7, array(  10,   16,   22,   28)),\n            array( 29,   70, 7, array(  15,   26,   36,   44)),\n            array( 33,  100, 7, array(  20,   36,   52,   64)),\n            array( 37,  134, 7, array(  26,   48,   72,   88)), // 5\n            array( 41,  172, 7, array(  36,   64,   96,  112)),\n            array( 45,  196, 0, array(  40,   72,  108,  130)),\n            array( 49,  242, 0, array(  48,   88,  132,  156)),\n            array( 53,  292, 0, array(  60,  110,  160,  192)),\n            array( 57,  346, 0, array(  72,  130,  192,  224)), //10\n            array( 61,  404, 0, array(  80,  150,  224,  264)),\n            array( 65,  466, 0, array(  96,  176,  260,  308)),\n            array( 69,  532, 0, array( 104,  198,  288,  352)),\n            array( 73,  581, 3, array( 120,  216,  320,  384)),\n            array( 77,  655, 3, array( 132,  240,  360,  432)), //15\n            array( 81,  733, 3, array( 144,  280,  408,  480)),\n            array( 85,  815, 3, array( 168,  308,  448,  532)),\n            array( 89,  901, 3, array( 180,  338,  504,  588)),\n            array( 93,  991, 3, array( 196,  364,  546,  650)),\n            array( 97, 1085, 3, array( 224,  416,  600,  700)), //20\n            array(101, 1156, 4, array( 224,  442,  644,  750)),\n            array(105, 1258, 4, array( 252,  476,  690,  816)),\n            array(109, 1364, 4, array( 270,  504,  750,  900)),\n            array(113, 1474, 4, array( 300,  560,  810,  960)),\n            array(117, 1588, 4, array( 312,  588,  870, 1050)), //25\n            array(121, 1706, 4, array( 336,  644,  952, 1110)),\n            array(125, 1828, 4, array( 360,  700, 1020, 1200)),\n            array(129, 1921, 3, array( 390,  728, 1050, 1260)),\n            array(133, 2051, 3, array( 420,  784, 1140, 1350)),\n            array(137, 2185, 3, array( 450,  812, 1200, 1440)), //30\n            array(141, 2323, 3, array( 480,  868, 1290, 1530)),\n            array(145, 2465, 3, array( 510,  924, 1350, 1620)),\n            array(149, 2611, 3, array( 540,  980, 1440, 1710)),\n            array(153, 2761, 3, array( 570, 1036, 1530, 1800)),\n            array(157, 2876, 0, array( 570, 1064, 1590, 1890)), //35\n            array(161, 3034, 0, array( 600, 1120, 1680, 1980)),\n            array(165, 3196, 0, array( 630, 1204, 1770, 2100)),\n            array(169, 3362, 0, array( 660, 1260, 1860, 2220)),\n            array(173, 3532, 0, array( 720, 1316, 1950, 2310)),\n            array(177, 3706, 0, array( 750, 1372, 2040, 2430)) //40\n        );\n        \n        //----------------------------------------------------------------------\n        public static function getDataLength($version, $level)\n        {\n            return self::$capacity[$version][QRCAP_WORDS] - self::$capacity[$version][QRCAP_EC][$level];\n        }\n        \n        //----------------------------------------------------------------------\n        public static function getECCLength($version, $level)\n        {\n            return self::$capacity[$version][QRCAP_EC][$level];\n        }\n        \n        //----------------------------------------------------------------------\n        public static function getWidth($version)\n        {\n            return self::$capacity[$version][QRCAP_WIDTH];\n        }\n        \n        //----------------------------------------------------------------------\n        public static function getRemainder($version)\n        {\n            return self::$capacity[$version][QRCAP_REMINDER];\n        }\n        \n        //----------------------------------------------------------------------\n        public static function getMinimumVersion($size, $level)\n        {\n\n            for($i=1; $i<= QRSPEC_VERSION_MAX; $i++) {\n                $words  = self::$capacity[$i][QRCAP_WORDS] - self::$capacity[$i][QRCAP_EC][$level];\n                if($words >= $size) \n                    return $i;\n            }\n\n            return -1;\n        }\n    \n        //######################################################################\n        \n        public static $lengthTableBits = array(\n            array(10, 12, 14),\n            array( 9, 11, 13),\n            array( 8, 16, 16),\n            array( 8, 10, 12)\n        );\n        \n        //----------------------------------------------------------------------\n        public static function lengthIndicator($mode, $version)\n        {\n            if ($mode == QR_MODE_STRUCTURE)\n                return 0;\n                \n            if ($version <= 9) {\n                $l = 0;\n            } else if ($version <= 26) {\n                $l = 1;\n            } else {\n                $l = 2;\n            }\n\n            return self::$lengthTableBits[$mode][$l];\n        }\n        \n        //----------------------------------------------------------------------\n        public static function maximumWords($mode, $version)\n        {\n            if($mode == QR_MODE_STRUCTURE) \n                return 3;\n                \n            if($version <= 9) {\n                $l = 0;\n            } else if($version <= 26) {\n                $l = 1;\n            } else {\n                $l = 2;\n            }\n\n            $bits = self::$lengthTableBits[$mode][$l];\n            $words = (1 << $bits) - 1;\n            \n            if($mode == QR_MODE_KANJI) {\n                $words *= 2; // the number of bytes is required\n            }\n\n            return $words;\n        }\n\n        // Error correction code -----------------------------------------------\n        // Table of the error correction code (Reed-Solomon block)\n        // See Table 12-16 (pp.30-36), JIS X0510:2004.\n\n        public static $eccTable = array(\n            array(array( 0,  0), array( 0,  0), array( 0,  0), array( 0,  0)),\n            array(array( 1,  0), array( 1,  0), array( 1,  0), array( 1,  0)), // 1\n            array(array( 1,  0), array( 1,  0), array( 1,  0), array( 1,  0)),\n            array(array( 1,  0), array( 1,  0), array( 2,  0), array( 2,  0)),\n            array(array( 1,  0), array( 2,  0), array( 2,  0), array( 4,  0)),\n            array(array( 1,  0), array( 2,  0), array( 2,  2), array( 2,  2)), // 5\n            array(array( 2,  0), array( 4,  0), array( 4,  0), array( 4,  0)),\n            array(array( 2,  0), array( 4,  0), array( 2,  4), array( 4,  1)),\n            array(array( 2,  0), array( 2,  2), array( 4,  2), array( 4,  2)),\n            array(array( 2,  0), array( 3,  2), array( 4,  4), array( 4,  4)),\n            array(array( 2,  2), array( 4,  1), array( 6,  2), array( 6,  2)), //10\n            array(array( 4,  0), array( 1,  4), array( 4,  4), array( 3,  8)),\n            array(array( 2,  2), array( 6,  2), array( 4,  6), array( 7,  4)),\n            array(array( 4,  0), array( 8,  1), array( 8,  4), array(12,  4)),\n            array(array( 3,  1), array( 4,  5), array(11,  5), array(11,  5)),\n            array(array( 5,  1), array( 5,  5), array( 5,  7), array(11,  7)), //15\n            array(array( 5,  1), array( 7,  3), array(15,  2), array( 3, 13)),\n            array(array( 1,  5), array(10,  1), array( 1, 15), array( 2, 17)),\n            array(array( 5,  1), array( 9,  4), array(17,  1), array( 2, 19)),\n            array(array( 3,  4), array( 3, 11), array(17,  4), array( 9, 16)),\n            array(array( 3,  5), array( 3, 13), array(15,  5), array(15, 10)), //20\n            array(array( 4,  4), array(17,  0), array(17,  6), array(19,  6)),\n            array(array( 2,  7), array(17,  0), array( 7, 16), array(34,  0)),\n            array(array( 4,  5), array( 4, 14), array(11, 14), array(16, 14)),\n            array(array( 6,  4), array( 6, 14), array(11, 16), array(30,  2)),\n            array(array( 8,  4), array( 8, 13), array( 7, 22), array(22, 13)), //25\n            array(array(10,  2), array(19,  4), array(28,  6), array(33,  4)),\n            array(array( 8,  4), array(22,  3), array( 8, 26), array(12, 28)),\n            array(array( 3, 10), array( 3, 23), array( 4, 31), array(11, 31)),\n            array(array( 7,  7), array(21,  7), array( 1, 37), array(19, 26)),\n            array(array( 5, 10), array(19, 10), array(15, 25), array(23, 25)), //30\n            array(array(13,  3), array( 2, 29), array(42,  1), array(23, 28)),\n            array(array(17,  0), array(10, 23), array(10, 35), array(19, 35)),\n            array(array(17,  1), array(14, 21), array(29, 19), array(11, 46)),\n            array(array(13,  6), array(14, 23), array(44,  7), array(59,  1)),\n            array(array(12,  7), array(12, 26), array(39, 14), array(22, 41)), //35\n            array(array( 6, 14), array( 6, 34), array(46, 10), array( 2, 64)),\n            array(array(17,  4), array(29, 14), array(49, 10), array(24, 46)),\n            array(array( 4, 18), array(13, 32), array(48, 14), array(42, 32)),\n            array(array(20,  4), array(40,  7), array(43, 22), array(10, 67)),\n            array(array(19,  6), array(18, 31), array(34, 34), array(20, 61)),//40\n        );                                                                       \n\n        //----------------------------------------------------------------------\n        // CACHEABLE!!!\n        \n        public static function getEccSpec($version, $level, array &$spec)\n        {\n            if (count($spec) < 5) {\n                $spec = array(0,0,0,0,0);\n            }\n\n            $b1   = self::$eccTable[$version][$level][0];\n            $b2   = self::$eccTable[$version][$level][1];\n            $data = self::getDataLength($version, $level);\n            $ecc  = self::getECCLength($version, $level);\n\n            if($b2 == 0) {\n                $spec[0] = $b1;\n                $spec[1] = (int)($data / $b1);\n                $spec[2] = (int)($ecc / $b1);\n                $spec[3] = 0; \n                $spec[4] = 0;\n            } else {\n                $spec[0] = $b1;\n                $spec[1] = (int)($data / ($b1 + $b2));\n                $spec[2] = (int)($ecc  / ($b1 + $b2));\n                $spec[3] = $b2;\n                $spec[4] = $spec[1] + 1;\n            }\n        }\n\n        // Alignment pattern ---------------------------------------------------\n\n        // Positions of alignment patterns.\n        // This array includes only the second and the third position of the \n        // alignment patterns. Rest of them can be calculated from the distance \n        // between them.\n         \n        // See Table 1 in Appendix E (pp.71) of JIS X0510:2004.\n         \n        public static $alignmentPattern = array(      \n            array( 0,  0),\n            array( 0,  0), array(18,  0), array(22,  0), array(26,  0), array(30,  0), // 1- 5\n            array(34,  0), array(22, 38), array(24, 42), array(26, 46), array(28, 50), // 6-10\n            array(30, 54), array(32, 58), array(34, 62), array(26, 46), array(26, 48), //11-15\n            array(26, 50), array(30, 54), array(30, 56), array(30, 58), array(34, 62), //16-20\n            array(28, 50), array(26, 50), array(30, 54), array(28, 54), array(32, 58), //21-25\n            array(30, 58), array(34, 62), array(26, 50), array(30, 54), array(26, 52), //26-30\n            array(30, 56), array(34, 60), array(30, 58), array(34, 62), array(30, 54), //31-35\n            array(24, 50), array(28, 54), array(32, 58), array(26, 54), array(30, 58), //35-40\n        );                                                                                  \n\n        \n        /** --------------------------------------------------------------------\n         * Put an alignment marker.\n         * @param frame\n         * @param width\n         * @param ox,oy center coordinate of the pattern\n         */\n        public static function putAlignmentMarker(array &$frame, $ox, $oy)\n        {\n            $finder = array(\n                \"\\xa1\\xa1\\xa1\\xa1\\xa1\",\n                \"\\xa1\\xa0\\xa0\\xa0\\xa1\",\n                \"\\xa1\\xa0\\xa1\\xa0\\xa1\",\n                \"\\xa1\\xa0\\xa0\\xa0\\xa1\",\n                \"\\xa1\\xa1\\xa1\\xa1\\xa1\"\n            );                        \n            \n            $yStart = $oy-2;         \n            $xStart = $ox-2;\n            \n            for($y=0; $y<5; $y++) {\n                QRstr::set($frame, $xStart, $yStart+$y, $finder[$y]);\n            }\n        }\n\n        //----------------------------------------------------------------------\n        public static function putAlignmentPattern($version, &$frame, $width)\n        {\n            if($version < 2)\n                return;\n\n            $d = self::$alignmentPattern[$version][1] - self::$alignmentPattern[$version][0];\n            if($d < 0) {\n                $w = 2;\n            } else {\n                $w = (int)(($width - self::$alignmentPattern[$version][0]) / $d + 2);\n            }\n\n            if($w * $w - 3 == 1) {\n                $x = self::$alignmentPattern[$version][0];\n                $y = self::$alignmentPattern[$version][0];\n                self::putAlignmentMarker($frame, $x, $y);\n                return;\n            }\n\n            $cx = self::$alignmentPattern[$version][0];\n            for($x=1; $x<$w - 1; $x++) {\n                self::putAlignmentMarker($frame, 6, $cx);\n                self::putAlignmentMarker($frame, $cx,  6);\n                $cx += $d;\n            }\n\n            $cy = self::$alignmentPattern[$version][0];\n            for($y=0; $y<$w-1; $y++) {\n                $cx = self::$alignmentPattern[$version][0];\n                for($x=0; $x<$w-1; $x++) {\n                    self::putAlignmentMarker($frame, $cx, $cy);\n                    $cx += $d;\n                }\n                $cy += $d;\n            }\n        }\n\n        // Version information pattern -----------------------------------------\n\n\t\t// Version information pattern (BCH coded).\n        // See Table 1 in Appendix D (pp.68) of JIS X0510:2004.\n        \n\t\t// size: [QRSPEC_VERSION_MAX - 6]\n\t\t\n        public static $versionPattern = array(\n            0x07c94, 0x085bc, 0x09a99, 0x0a4d3, 0x0bbf6, 0x0c762, 0x0d847, 0x0e60d,\n            0x0f928, 0x10b78, 0x1145d, 0x12a17, 0x13532, 0x149a6, 0x15683, 0x168c9,\n            0x177ec, 0x18ec4, 0x191e1, 0x1afab, 0x1b08e, 0x1cc1a, 0x1d33f, 0x1ed75,\n            0x1f250, 0x209d5, 0x216f0, 0x228ba, 0x2379f, 0x24b0b, 0x2542e, 0x26a64,\n            0x27541, 0x28c69\n        );\n\n        //----------------------------------------------------------------------\n        public static function getVersionPattern($version)\n        {\n            if($version < 7 || $version > QRSPEC_VERSION_MAX)\n                return 0;\n\n            return self::$versionPattern[$version -7];\n        }\n\n        // Format information --------------------------------------------------\n        // See calcFormatInfo in tests/test_qrspec.c (orginal qrencode c lib)\n        \n        public static $formatInfo = array(\n            array(0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318, 0x6c41, 0x6976),\n            array(0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0),\n            array(0x355f, 0x3068, 0x3f31, 0x3a06, 0x24b4, 0x2183, 0x2eda, 0x2bed),\n            array(0x1689, 0x13be, 0x1ce7, 0x19d0, 0x0762, 0x0255, 0x0d0c, 0x083b)\n        );\n\n        public static function getFormatInfo($mask, $level)\n        {\n            if($mask < 0 || $mask > 7)\n                return 0;\n                \n            if($level < 0 || $level > 3)\n                return 0;                \n\n            return self::$formatInfo[$level][$mask];\n        }\n\n        // Frame ---------------------------------------------------------------\n        // Cache of initial frames.\n         \n        public static $frames = array();\n\n        /** --------------------------------------------------------------------\n         * Put a finder pattern.\n         * @param frame\n         * @param width\n         * @param ox,oy upper-left coordinate of the pattern\n         */\n        public static function putFinderPattern(&$frame, $ox, $oy)\n        {\n            $finder = array(\n                \"\\xc1\\xc1\\xc1\\xc1\\xc1\\xc1\\xc1\",\n                \"\\xc1\\xc0\\xc0\\xc0\\xc0\\xc0\\xc1\",\n                \"\\xc1\\xc0\\xc1\\xc1\\xc1\\xc0\\xc1\",\n                \"\\xc1\\xc0\\xc1\\xc1\\xc1\\xc0\\xc1\",\n                \"\\xc1\\xc0\\xc1\\xc1\\xc1\\xc0\\xc1\",\n                \"\\xc1\\xc0\\xc0\\xc0\\xc0\\xc0\\xc1\",\n                \"\\xc1\\xc1\\xc1\\xc1\\xc1\\xc1\\xc1\"\n            );                            \n            \n            for($y=0; $y<7; $y++) {\n                QRstr::set($frame, $ox, $oy+$y, $finder[$y]);\n            }\n        }\n\n        //----------------------------------------------------------------------\n        public static function createFrame($version)\n        {\n            $width = self::$capacity[$version][QRCAP_WIDTH];\n            $frameLine = str_repeat (\"\\0\", $width);\n            $frame = array_fill(0, $width, $frameLine);\n\n            // Finder pattern\n            self::putFinderPattern($frame, 0, 0);\n            self::putFinderPattern($frame, $width - 7, 0);\n            self::putFinderPattern($frame, 0, $width - 7);\n            \n            // Separator\n            $yOffset = $width - 7;\n            \n            for($y=0; $y<7; $y++) {\n                $frame[$y][7] = \"\\xc0\";\n                $frame[$y][$width - 8] = \"\\xc0\";\n                $frame[$yOffset][7] = \"\\xc0\";\n                $yOffset++;\n            }\n            \n            $setPattern = str_repeat(\"\\xc0\", 8);\n            \n            QRstr::set($frame, 0, 7, $setPattern);\n            QRstr::set($frame, $width-8, 7, $setPattern);\n            QRstr::set($frame, 0, $width - 8, $setPattern);\n        \n            // Format info\n            $setPattern = str_repeat(\"\\x84\", 9);\n            QRstr::set($frame, 0, 8, $setPattern);\n            QRstr::set($frame, $width - 8, 8, $setPattern, 8);\n            \n            $yOffset = $width - 8;\n\n            for($y=0; $y<8; $y++,$yOffset++) {\n                $frame[$y][8] = \"\\x84\";\n                $frame[$yOffset][8] = \"\\x84\";\n            }\n\n            // Timing pattern  \n            \n            for($i=1; $i<$width-15; $i++) {\n                $frame[6][7+$i] = chr(0x90 | ($i & 1));\n                $frame[7+$i][6] = chr(0x90 | ($i & 1));\n            }\n            \n            // Alignment pattern  \n            self::putAlignmentPattern($version, $frame, $width);\n            \n            // Version information \n            if($version >= 7) {\n                $vinf = self::getVersionPattern($version);\n\n                $v = $vinf;\n                \n                for($x=0; $x<6; $x++) {\n                    for($y=0; $y<3; $y++) {\n                        $frame[($width - 11)+$y][$x] = chr(0x88 | ($v & 1));\n                        $v = $v >> 1;\n                    }\n                }\n\n                $v = $vinf;\n                for($y=0; $y<6; $y++) {\n                    for($x=0; $x<3; $x++) {\n                        $frame[$y][$x+($width - 11)] = chr(0x88 | ($v & 1));\n                        $v = $v >> 1;\n                    }\n                }\n            }\n    \n            // and a little bit...  \n            $frame[$width - 8][8] = \"\\x81\";\n            \n            return $frame;\n        }\n\n        //----------------------------------------------------------------------\n        public static function debug($frame, $binary_mode = false)\n        {\n            if ($binary_mode) {\n            \n                    foreach ($frame as &$frameLine) {\n                        $frameLine = join('<span class=\"m\">&nbsp;&nbsp;</span>', explode('0', $frameLine));\n                        $frameLine = join('&#9608;&#9608;', explode('1', $frameLine));\n                    }\n                    \n                    ?>\n                <style>\n                    .m { background-color: white; }\n                </style>\n                <?php\n                    echo '<pre><tt><br/ ><br/ ><br/ >&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;';\n                    echo join(\"<br/ >&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\", $frame);\n                    echo '</tt></pre><br/ ><br/ ><br/ ><br/ ><br/ ><br/ >';\n            \n            } else {\n            \n                foreach ($frame as &$frameLine) {\n                    $frameLine = join('<span class=\"m\">&nbsp;</span>',  explode(\"\\xc0\", $frameLine));\n                    $frameLine = join('<span class=\"m\">&#9618;</span>', explode(\"\\xc1\", $frameLine));\n                    $frameLine = join('<span class=\"p\">&nbsp;</span>',  explode(\"\\xa0\", $frameLine));\n                    $frameLine = join('<span class=\"p\">&#9618;</span>', explode(\"\\xa1\", $frameLine));\n                    $frameLine = join('<span class=\"s\">&#9671;</span>', explode(\"\\x84\", $frameLine)); //format 0\n                    $frameLine = join('<span class=\"s\">&#9670;</span>', explode(\"\\x85\", $frameLine)); //format 1\n                    $frameLine = join('<span class=\"x\">&#9762;</span>', explode(\"\\x81\", $frameLine)); //special bit\n                    $frameLine = join('<span class=\"c\">&nbsp;</span>',  explode(\"\\x90\", $frameLine)); //clock 0\n                    $frameLine = join('<span class=\"c\">&#9719;</span>', explode(\"\\x91\", $frameLine)); //clock 1\n                    $frameLine = join('<span class=\"f\">&nbsp;</span>',  explode(\"\\x88\", $frameLine)); //version\n                    $frameLine = join('<span class=\"f\">&#9618;</span>', explode(\"\\x89\", $frameLine)); //version\n                    $frameLine = join('&#9830;', explode(\"\\x01\", $frameLine));\n                    $frameLine = join('&#8901;', explode(\"\\0\", $frameLine));\n                }\n                \n                ?>\n                <style>\n                    .p { background-color: yellow; }\n                    .m { background-color: #00FF00; }\n                    .s { background-color: #FF0000; }\n                    .c { background-color: aqua; }\n                    .x { background-color: pink; }\n                    .f { background-color: gold; }\n                </style>\n                <?php\n                echo \"<pre><tt>\";\n                echo join(\"<br/ >\", $frame);\n                echo \"</tt></pre>\";\n            \n            }\n        }\n\n        //----------------------------------------------------------------------\n        public static function serial($frame)\n        {\n            return gzcompress(join(\"\\n\", $frame), 9);\n        }\n        \n        //----------------------------------------------------------------------\n        public static function unserial($code)\n        {\n            return explode(\"\\n\", gzuncompress($code));\n        }\n        \n        //----------------------------------------------------------------------\n        public static function newFrame($version)\n        {\n            if($version < 1 || $version > QRSPEC_VERSION_MAX) \n                return null;\n\n            if(!isset(self::$frames[$version])) {\n                \n                $fileName = QR_CACHE_DIR.'frame_'.$version.'.dat';\n                \n                if (QR_CACHEABLE) {\n                    if (file_exists($fileName)) {\n                        self::$frames[$version] = self::unserial(file_get_contents($fileName));\n                    } else {\n                        self::$frames[$version] = self::createFrame($version);\n                        file_put_contents($fileName, self::serial(self::$frames[$version]));\n                    }\n                } else {\n                    self::$frames[$version] = self::createFrame($version);\n                }\n            }\n            \n            if(is_null(self::$frames[$version]))\n                return null;\n\n            return self::$frames[$version];\n        }\n\n        //----------------------------------------------------------------------\n        public static function rsBlockNum($spec)     { return $spec[0] + $spec[3]; }\n        public static function rsBlockNum1($spec)    { return $spec[0]; }\n        public static function rsDataCodes1($spec)   { return $spec[1]; }\n        public static function rsEccCodes1($spec)    { return $spec[2]; }\n        public static function rsBlockNum2($spec)    { return $spec[3]; }\n        public static function rsDataCodes2($spec)   { return $spec[4]; }\n        public static function rsEccCodes2($spec)    { return $spec[2]; }\n        public static function rsDataLength($spec)   { return ($spec[0] * $spec[1]) + ($spec[3] * $spec[4]);    }\n        public static function rsEccLength($spec)    { return ($spec[0] + $spec[3]) * $spec[2]; }\n        \n    }\n\n\n\n//---- qrimage.php -----------------------------\n\n\n\n\n/*\n * PHP QR Code encoder\n *\n * Image output of code using GD2\n *\n * PHP QR Code is distributed under LGPL 3\n * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>\n *\n * This library is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 3 of the License, or any later version.\n *\n * This library is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with this library; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n */\n \n    define('QR_IMAGE', true);\n\n    class QRimage {\n    \n        //----------------------------------------------------------------------\n        public static function png($frame, $filename = false, $pixelPerPoint = 4, $outerFrame = 4,$saveandprint=FALSE) \n        {\n            $image = self::image($frame, $pixelPerPoint, $outerFrame);\n            \n            if ($filename === false) {\n                Header(\"Content-type: image/png\");\n                ImagePng($image);\n            } else {\n                if($saveandprint===TRUE){\n                    ImagePng($image, $filename);\n                    header(\"Content-type: image/png\");\n                    ImagePng($image);\n                }else{\n                    ImagePng($image, $filename);\n                }\n            }\n            \n            ImageDestroy($image);\n        }\n    \n        //----------------------------------------------------------------------\n        public static function jpg($frame, $filename = false, $pixelPerPoint = 8, $outerFrame = 4, $q = 85) \n        {\n            $image = self::image($frame, $pixelPerPoint, $outerFrame);\n            \n            if ($filename === false) {\n                Header(\"Content-type: image/jpeg\");\n                ImageJpeg($image, null, $q);\n            } else {\n                ImageJpeg($image, $filename, $q);            \n            }\n            \n            ImageDestroy($image);\n        }\n    \n        //----------------------------------------------------------------------\n        private static function image($frame, $pixelPerPoint = 4, $outerFrame = 4) \n        {\n            $h = count($frame);\n            $w = strlen($frame[0]);\n            \n            $imgW = $w + 2*$outerFrame;\n            $imgH = $h + 2*$outerFrame;\n            \n            $base_image =ImageCreate($imgW, $imgH);\n            \n            $col[0] = ImageColorAllocate($base_image,255,255,255);\n            $col[1] = ImageColorAllocate($base_image,0,0,0);\n\n            imagefill($base_image, 0, 0, $col[0]);\n\n            for($y=0; $y<$h; $y++) {\n                for($x=0; $x<$w; $x++) {\n                    if ($frame[$y][$x] == '1') {\n                        ImageSetPixel($base_image,$x+$outerFrame,$y+$outerFrame,$col[1]); \n                    }\n                }\n            }\n            \n            $target_image =ImageCreate($imgW * $pixelPerPoint, $imgH * $pixelPerPoint);\n            ImageCopyResized($target_image, $base_image, 0, 0, 0, 0, $imgW * $pixelPerPoint, $imgH * $pixelPerPoint, $imgW, $imgH);\n            ImageDestroy($base_image);\n            \n            return $target_image;\n        }\n    }\n\n\n\n//---- qrinput.php -----------------------------\n\n\n\n\n/*\n * PHP QR Code encoder\n *\n * Input encoding class\n *\n * Based on libqrencode C library distributed under LGPL 2.1\n * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>\n *\n * PHP QR Code is distributed under LGPL 3\n * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>\n *\n * This library is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 3 of the License, or any later version.\n *\n * This library is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with this library; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n */\n \n    define('STRUCTURE_HEADER_BITS',  20);\n    define('MAX_STRUCTURED_SYMBOLS', 16);\n\n    class QRinputItem {\n    \n        public $mode;\n        public $size;\n        public $data;\n        public $bstream;\n\n        public function __construct($mode, $size, $data, $bstream = null) \n        {\n            $setData = array_slice($data, 0, $size);\n            \n            if (count($setData) < $size) {\n                $setData = array_merge($setData, array_fill(0,$size-count($setData),0));\n            }\n        \n            if(!QRinput::check($mode, $size, $setData)) {\n                throw new Exception('Error m:'.$mode.',s:'.$size.',d:'.join(',',$setData));\n                return null;\n            }\n            \n            $this->mode = $mode;\n            $this->size = $size;\n            $this->data = $setData;\n            $this->bstream = $bstream;\n        }\n        \n        //----------------------------------------------------------------------\n        public function encodeModeNum($version)\n        {\n            try {\n            \n                $words = (int)($this->size / 3);\n                $bs = new QRbitstream();\n                \n                $val = 0x1;\n                $bs->appendNum(4, $val);\n                $bs->appendNum(QRspec::lengthIndicator(QR_MODE_NUM, $version), $this->size);\n\n                for($i=0; $i<$words; $i++) {\n                    $val  = (ord($this->data[$i*3  ]) - ord('0')) * 100;\n                    $val += (ord($this->data[$i*3+1]) - ord('0')) * 10;\n                    $val += (ord($this->data[$i*3+2]) - ord('0'));\n                    $bs->appendNum(10, $val);\n                }\n\n                if($this->size - $words * 3 == 1) {\n                    $val = ord($this->data[$words*3]) - ord('0');\n                    $bs->appendNum(4, $val);\n                } else if($this->size - $words * 3 == 2) {\n                    $val  = (ord($this->data[$words*3  ]) - ord('0')) * 10;\n                    $val += (ord($this->data[$words*3+1]) - ord('0'));\n                    $bs->appendNum(7, $val);\n                }\n\n                $this->bstream = $bs;\n                return 0;\n                \n            } catch (Exception $e) {\n                return -1;\n            }\n        }\n        \n        //----------------------------------------------------------------------\n        public function encodeModeAn($version)\n        {\n            try {\n                $words = (int)($this->size / 2);\n                $bs = new QRbitstream();\n                \n                $bs->appendNum(4, 0x02);\n                $bs->appendNum(QRspec::lengthIndicator(QR_MODE_AN, $version), $this->size);\n\n                for($i=0; $i<$words; $i++) {\n                    $val  = (int)QRinput::lookAnTable(ord($this->data[$i*2  ])) * 45;\n                    $val += (int)QRinput::lookAnTable(ord($this->data[$i*2+1]));\n\n                    $bs->appendNum(11, $val);\n                }\n\n                if($this->size & 1) {\n                    $val = QRinput::lookAnTable(ord($this->data[$words * 2]));\n                    $bs->appendNum(6, $val);\n                }\n        \n                $this->bstream = $bs;\n                return 0;\n            \n            } catch (Exception $e) {\n                return -1;\n            }\n        }\n        \n        //----------------------------------------------------------------------\n        public function encodeMode8($version)\n        {\n            try {\n                $bs = new QRbitstream();\n\n                $bs->appendNum(4, 0x4);\n                $bs->appendNum(QRspec::lengthIndicator(QR_MODE_8, $version), $this->size);\n\n                for($i=0; $i<$this->size; $i++) {\n                    $bs->appendNum(8, ord($this->data[$i]));\n                }\n\n                $this->bstream = $bs;\n                return 0;\n            \n            } catch (Exception $e) {\n                return -1;\n            }\n        }\n        \n        //----------------------------------------------------------------------\n        public function encodeModeKanji($version)\n        {\n            try {\n\n                $bs = new QRbitrtream();\n                \n                $bs->appendNum(4, 0x8);\n                $bs->appendNum(QRspec::lengthIndicator(QR_MODE_KANJI, $version), (int)($this->size / 2));\n\n                for($i=0; $i<$this->size; $i+=2) {\n                    $val = (ord($this->data[$i]) << 8) | ord($this->data[$i+1]);\n                    if($val <= 0x9ffc) {\n                        $val -= 0x8140;\n                    } else {\n                        $val -= 0xc140;\n                    }\n                    \n                    $h = ($val >> 8) * 0xc0;\n                    $val = ($val & 0xff) + $h;\n\n                    $bs->appendNum(13, $val);\n                }\n\n                $this->bstream = $bs;\n                return 0;\n            \n            } catch (Exception $e) {\n                return -1;\n            }\n        }\n\n        //----------------------------------------------------------------------\n        public function encodeModeStructure()\n        {\n            try {\n                $bs =  new QRbitstream();\n                \n                $bs->appendNum(4, 0x03);\n                $bs->appendNum(4, ord($this->data[1]) - 1);\n                $bs->appendNum(4, ord($this->data[0]) - 1);\n                $bs->appendNum(8, ord($this->data[2]));\n\n                $this->bstream = $bs;\n                return 0;\n            \n            } catch (Exception $e) {\n                return -1;\n            }\n        }\n        \n        //----------------------------------------------------------------------\n        public function estimateBitStreamSizeOfEntry($version)\n        {\n            $bits = 0;\n\n            if($version == 0) \n                $version = 1;\n\n            switch($this->mode) {\n                case QR_MODE_NUM:        $bits = QRinput::estimateBitsModeNum($this->size);    break;\n                case QR_MODE_AN:        $bits = QRinput::estimateBitsModeAn($this->size);    break;\n                case QR_MODE_8:            $bits = QRinput::estimateBitsMode8($this->size);    break;\n                case QR_MODE_KANJI:        $bits = QRinput::estimateBitsModeKanji($this->size);break;\n                case QR_MODE_STRUCTURE:    return STRUCTURE_HEADER_BITS;            \n                default:\n                    return 0;\n            }\n\n            $l = QRspec::lengthIndicator($this->mode, $version);\n            $m = 1 << $l;\n            $num = (int)(($this->size + $m - 1) / $m);\n\n            $bits += $num * (4 + $l);\n\n            return $bits;\n        }\n        \n        //----------------------------------------------------------------------\n        public function encodeBitStream($version)\n        {\n            try {\n            \n                unset($this->bstream);\n                $words = QRspec::maximumWords($this->mode, $version);\n                \n                if($this->size > $words) {\n                \n                    $st1 = new QRinputItem($this->mode, $words, $this->data);\n                    $st2 = new QRinputItem($this->mode, $this->size - $words, array_slice($this->data, $words));\n\n                    $st1->encodeBitStream($version);\n                    $st2->encodeBitStream($version);\n                    \n                    $this->bstream = new QRbitstream();\n                    $this->bstream->append($st1->bstream);\n                    $this->bstream->append($st2->bstream);\n                    \n                    unset($st1);\n                    unset($st2);\n                    \n                } else {\n                    \n                    $ret = 0;\n                    \n                    switch($this->mode) {\n                        case QR_MODE_NUM:        $ret = $this->encodeModeNum($version);    break;\n                        case QR_MODE_AN:        $ret = $this->encodeModeAn($version);    break;\n                        case QR_MODE_8:            $ret = $this->encodeMode8($version);    break;\n                        case QR_MODE_KANJI:        $ret = $this->encodeModeKanji($version);break;\n                        case QR_MODE_STRUCTURE:    $ret = $this->encodeModeStructure();    break;\n                        \n                        default:\n                            break;\n                    }\n                    \n                    if($ret < 0)\n                        return -1;\n                }\n\n                return $this->bstream->size();\n            \n            } catch (Exception $e) {\n                return -1;\n            }\n        }\n    };\n    \n    //##########################################################################\n\n    class QRinput {\n\n        public $items;\n        \n        private $version;\n        private $level;\n        \n        //----------------------------------------------------------------------\n        public function __construct($version = 0, $level = QR_ECLEVEL_L)\n        {\n            if ($version < 0 || $version > QRSPEC_VERSION_MAX || $level > QR_ECLEVEL_H) {\n                throw new Exception('Invalid version no');\n                return NULL;\n            }\n            \n            $this->version = $version;\n            $this->level = $level;\n        }\n        \n        //----------------------------------------------------------------------\n        public function getVersion()\n        {\n            return $this->version;\n        }\n        \n        //----------------------------------------------------------------------\n        public function setVersion($version)\n        {\n            if($version < 0 || $version > QRSPEC_VERSION_MAX) {\n                throw new Exception('Invalid version no');\n                return -1;\n            }\n\n            $this->version = $version;\n\n            return 0;\n        }\n        \n        //----------------------------------------------------------------------\n        public function getErrorCorrectionLevel()\n        {\n            return $this->level;\n        }\n\n        //----------------------------------------------------------------------\n        public function setErrorCorrectionLevel($level)\n        {\n            if($level > QR_ECLEVEL_H) {\n                throw new Exception('Invalid ECLEVEL');\n                return -1;\n            }\n\n            $this->level = $level;\n\n            return 0;\n        }\n        \n        //----------------------------------------------------------------------\n        public function appendEntry(QRinputItem $entry)\n        {\n            $this->items[] = $entry;\n        }\n        \n        //----------------------------------------------------------------------\n        public function append($mode, $size, $data)\n        {\n            try {\n                $entry = new QRinputItem($mode, $size, $data);\n                $this->items[] = $entry;\n                return 0;\n            } catch (Exception $e) {\n                return -1;\n            }\n        }\n        \n        //----------------------------------------------------------------------\n        \n        public function insertStructuredAppendHeader($size, $index, $parity)\n        {\n            if( $size > MAX_STRUCTURED_SYMBOLS ) {\n                throw new Exception('insertStructuredAppendHeader wrong size');\n            }\n            \n            if( $index <= 0 || $index > MAX_STRUCTURED_SYMBOLS ) {\n                throw new Exception('insertStructuredAppendHeader wrong index');\n            }\n\n            $buf = array($size, $index, $parity);\n            \n            try {\n                $entry = new QRinputItem(QR_MODE_STRUCTURE, 3, buf);\n                array_unshift($this->items, $entry);\n                return 0;\n            } catch (Exception $e) {\n                return -1;\n            }\n        }\n\n        //----------------------------------------------------------------------\n        public function calcParity()\n        {\n            $parity = 0;\n            \n            foreach($this->items as $item) {\n                if($item->mode != QR_MODE_STRUCTURE) {\n                    for($i=$item->size-1; $i>=0; $i--) {\n                        $parity ^= $item->data[$i];\n                    }\n                }\n            }\n\n            return $parity;\n        }\n        \n        //----------------------------------------------------------------------\n        public static function checkModeNum($size, $data)\n        {\n            for($i=0; $i<$size; $i++) {\n                if((ord($data[$i]) < ord('0')) || (ord($data[$i]) > ord('9'))){\n                    return false;\n                }\n            }\n\n            return true;\n        }\n\n        //----------------------------------------------------------------------\n        public static function estimateBitsModeNum($size)\n        {\n            $w = (int)$size / 3;\n            $bits = $w * 10;\n            \n            switch($size - $w * 3) {\n                case 1:\n                    $bits += 4;\n                    break;\n                case 2:\n                    $bits += 7;\n                    break;\n                default:\n                    break;\n            }\n\n            return $bits;\n        }\n        \n        //----------------------------------------------------------------------\n        public static $anTable = array(\n            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n            36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43,\n             0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 44, -1, -1, -1, -1, -1,\n            -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,\n            25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,\n            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1\n        );\n        \n        //----------------------------------------------------------------------\n        public static function lookAnTable($c)\n        {\n            return (($c > 127)?-1:self::$anTable[$c]);\n        }\n        \n        //----------------------------------------------------------------------\n        public static function checkModeAn($size, $data)\n        {\n            for($i=0; $i<$size; $i++) {\n                if (self::lookAnTable(ord($data[$i])) == -1) {\n                    return false;\n                }\n            }\n\n            return true;\n        }\n        \n        //----------------------------------------------------------------------\n        public static function estimateBitsModeAn($size)\n        {\n            $w = (int)($size / 2);\n            $bits = $w * 11;\n            \n            if($size & 1) {\n                $bits += 6;\n            }\n\n            return $bits;\n        }\n    \n        //----------------------------------------------------------------------\n        public static function estimateBitsMode8($size)\n        {\n            return $size * 8;\n        }\n        \n        //----------------------------------------------------------------------\n        public function estimateBitsModeKanji($size)\n        {\n            return (int)(($size / 2) * 13);\n        }\n        \n        //----------------------------------------------------------------------\n        public static function checkModeKanji($size, $data)\n        {\n            if($size & 1)\n                return false;\n\n            for($i=0; $i<$size; $i+=2) {\n                $val = (ord($data[$i]) << 8) | ord($data[$i+1]);\n                if( $val < 0x8140 \n                || ($val > 0x9ffc && $val < 0xe040) \n                || $val > 0xebbf) {\n                    return false;\n                }\n            }\n\n            return true;\n        }\n\n        /***********************************************************************\n         * Validation\n         **********************************************************************/\n\n        public static function check($mode, $size, $data)\n        {\n            if($size <= 0) \n                return false;\n\n            switch($mode) {\n                case QR_MODE_NUM:       return self::checkModeNum($size, $data);   break;\n                case QR_MODE_AN:        return self::checkModeAn($size, $data);    break;\n                case QR_MODE_KANJI:     return self::checkModeKanji($size, $data); break;\n                case QR_MODE_8:         return true; break;\n                case QR_MODE_STRUCTURE: return true; break;\n                \n                default:\n                    break;\n            }\n\n            return false;\n        }\n        \n        \n        //----------------------------------------------------------------------\n        public function estimateBitStreamSize($version)\n        {\n            $bits = 0;\n\n            foreach($this->items as $item) {\n                $bits += $item->estimateBitStreamSizeOfEntry($version);\n            }\n\n            return $bits;\n        }\n        \n        //----------------------------------------------------------------------\n        public function estimateVersion()\n        {\n            $version = 0;\n            $prev = 0;\n            do {\n                $prev = $version;\n                $bits = $this->estimateBitStreamSize($prev);\n                $version = QRspec::getMinimumVersion((int)(($bits + 7) / 8), $this->level);\n                if ($version < 0) {\n                    return -1;\n                }\n            } while ($version > $prev);\n\n            return $version;\n        }\n        \n        //----------------------------------------------------------------------\n        public static function lengthOfCode($mode, $version, $bits)\n        {\n            $payload = $bits - 4 - QRspec::lengthIndicator($mode, $version);\n            switch($mode) {\n                case QR_MODE_NUM:\n                    $chunks = (int)($payload / 10);\n                    $remain = $payload - $chunks * 10;\n                    $size = $chunks * 3;\n                    if($remain >= 7) {\n                        $size += 2;\n                    } else if($remain >= 4) {\n                        $size += 1;\n                    }\n                    break;\n                case QR_MODE_AN:\n                    $chunks = (int)($payload / 11);\n                    $remain = $payload - $chunks * 11;\n                    $size = $chunks * 2;\n                    if($remain >= 6) \n                        $size++;\n                    break;\n                case QR_MODE_8:\n                    $size = (int)($payload / 8);\n                    break;\n                case QR_MODE_KANJI:\n                    $size = (int)(($payload / 13) * 2);\n                    break;\n                case QR_MODE_STRUCTURE:\n                    $size = (int)($payload / 8);\n                    break;\n                default:\n                    $size = 0;\n                    break;\n            }\n            \n            $maxsize = QRspec::maximumWords($mode, $version);\n            if($size < 0) $size = 0;\n            if($size > $maxsize) $size = $maxsize;\n\n            return $size;\n        }\n        \n        //----------------------------------------------------------------------\n        public function createBitStream()\n        {\n            $total = 0;\n\n            foreach($this->items as $item) {\n                $bits = $item->encodeBitStream($this->version);\n                \n                if($bits < 0) \n                    return -1;\n                    \n                $total += $bits;\n            }\n\n            return $total;\n        }\n        \n        //----------------------------------------------------------------------\n        public function convertData()\n        {\n            $ver = $this->estimateVersion();\n            if($ver > $this->getVersion()) {\n                $this->setVersion($ver);\n            }\n\n            for(;;) {\n                $bits = $this->createBitStream();\n                \n                if($bits < 0) \n                    return -1;\n                    \n                $ver = QRspec::getMinimumVersion((int)(($bits + 7) / 8), $this->level);\n                if($ver < 0) {\n                    throw new Exception('WRONG VERSION');\n                    return -1;\n                } else if($ver > $this->getVersion()) {\n                    $this->setVersion($ver);\n                } else {\n                    break;\n                }\n            }\n\n            return 0;\n        }\n        \n        //----------------------------------------------------------------------\n        public function appendPaddingBit(&$bstream)\n        {\n            $bits = $bstream->size();\n            $maxwords = QRspec::getDataLength($this->version, $this->level);\n            $maxbits = $maxwords * 8;\n\n            if ($maxbits == $bits) {\n                return 0;\n            }\n\n            if ($maxbits - $bits < 5) {\n                return $bstream->appendNum($maxbits - $bits, 0);\n            }\n\n            $bits += 4;\n            $words = (int)(($bits + 7) / 8);\n\n            $padding = new QRbitstream();\n            $ret = $padding->appendNum($words * 8 - $bits + 4, 0);\n            \n            if($ret < 0) \n                return $ret;\n\n            $padlen = $maxwords - $words;\n            \n            if($padlen > 0) {\n                \n                $padbuf = array();\n                for($i=0; $i<$padlen; $i++) {\n                    $padbuf[$i] = ($i&1)?0x11:0xec;\n                }\n                \n                $ret = $padding->appendBytes($padlen, $padbuf);\n                \n                if($ret < 0)\n                    return $ret;\n                \n            }\n\n            $ret = $bstream->append($padding);\n            \n            return $ret;\n        }\n\n        //----------------------------------------------------------------------\n        public function mergeBitStream()\n        {\n            if($this->convertData() < 0) {\n                return null;\n            }\n\n            $bstream = new QRbitstream();\n            \n            foreach($this->items as $item) {\n                $ret = $bstream->append($item->bstream);\n                if($ret < 0) {\n                    return null;\n                }\n            }\n\n            return $bstream;\n        }\n\n        //----------------------------------------------------------------------\n        public function getBitStream()\n        {\n\n            $bstream = $this->mergeBitStream();\n            \n            if($bstream == null) {\n                return null;\n            }\n            \n            $ret = $this->appendPaddingBit($bstream);\n            if($ret < 0) {\n                return null;\n            }\n\n            return $bstream;\n        }\n        \n        //----------------------------------------------------------------------\n        public function getByteStream()\n        {\n            $bstream = $this->getBitStream();\n            if($bstream == null) {\n                return null;\n            }\n            \n            return $bstream->toByte();\n        }\n    }\n        \n        \n    \n\n\n\n//---- qrbitstream.php -----------------------------\n\n\n\n\n/*\n * PHP QR Code encoder\n *\n * Bitstream class\n *\n * Based on libqrencode C library distributed under LGPL 2.1\n * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>\n *\n * PHP QR Code is distributed under LGPL 3\n * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>\n *\n * This library is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 3 of the License, or any later version.\n *\n * This library is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with this library; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n */\n     \n    class QRbitstream {\n    \n        public $data = array();\n        \n        //----------------------------------------------------------------------\n        public function size()\n        {\n            return count($this->data);\n        }\n        \n        //----------------------------------------------------------------------\n        public function allocate($setLength)\n        {\n            $this->data = array_fill(0, $setLength, 0);\n            return 0;\n        }\n    \n        //----------------------------------------------------------------------\n        public static function newFromNum($bits, $num)\n        {\n            $bstream = new QRbitstream();\n            $bstream->allocate($bits);\n            \n            $mask = 1 << ($bits - 1);\n            for($i=0; $i<$bits; $i++) {\n                if($num & $mask) {\n                    $bstream->data[$i] = 1;\n                } else {\n                    $bstream->data[$i] = 0;\n                }\n                $mask = $mask >> 1;\n            }\n\n            return $bstream;\n        }\n        \n        //----------------------------------------------------------------------\n        public static function newFromBytes($size, $data)\n        {\n            $bstream = new QRbitstream();\n            $bstream->allocate($size * 8);\n            $p=0;\n\n            for($i=0; $i<$size; $i++) {\n                $mask = 0x80;\n                for($j=0; $j<8; $j++) {\n                    if($data[$i] & $mask) {\n                        $bstream->data[$p] = 1;\n                    } else {\n                        $bstream->data[$p] = 0;\n                    }\n                    $p++;\n                    $mask = $mask >> 1;\n                }\n            }\n\n            return $bstream;\n        }\n        \n        //----------------------------------------------------------------------\n        public function append(QRbitstream $arg)\n        {\n            if (is_null($arg)) {\n                return -1;\n            }\n            \n            if($arg->size() == 0) {\n                return 0;\n            }\n            \n            if($this->size() == 0) {\n                $this->data = $arg->data;\n                return 0;\n            }\n            \n            $this->data = array_values(array_merge($this->data, $arg->data));\n\n            return 0;\n        }\n        \n        //----------------------------------------------------------------------\n        public function appendNum($bits, $num)\n        {\n            if ($bits == 0) \n                return 0;\n\n            $b = QRbitstream::newFromNum($bits, $num);\n            \n            if(is_null($b))\n                return -1;\n\n            $ret = $this->append($b);\n            unset($b);\n\n            return $ret;\n        }\n\n        //----------------------------------------------------------------------\n        public function appendBytes($size, $data)\n        {\n            if ($size == 0) \n                return 0;\n\n            $b = QRbitstream::newFromBytes($size, $data);\n            \n            if(is_null($b))\n                return -1;\n\n            $ret = $this->append($b);\n            unset($b);\n\n            return $ret;\n        }\n        \n        //----------------------------------------------------------------------\n        public function toByte()\n        {\n        \n            $size = $this->size();\n\n            if($size == 0) {\n                return array();\n            }\n            \n            $data = array_fill(0, (int)(($size + 7) / 8), 0);\n            $bytes = (int)($size / 8);\n\n            $p = 0;\n            \n            for($i=0; $i<$bytes; $i++) {\n                $v = 0;\n                for($j=0; $j<8; $j++) {\n                    $v = $v << 1;\n                    $v |= $this->data[$p];\n                    $p++;\n                }\n                $data[$i] = $v;\n            }\n            \n            if($size & 7) {\n                $v = 0;\n                for($j=0; $j<($size & 7); $j++) {\n                    $v = $v << 1;\n                    $v |= $this->data[$p];\n                    $p++;\n                }\n                $data[$bytes] = $v;\n            }\n\n            return $data;\n        }\n\n    }\n\n\n\n\n//---- qrsplit.php -----------------------------\n\n\n\n\n/*\n * PHP QR Code encoder\n *\n * Input splitting classes\n *\n * Based on libqrencode C library distributed under LGPL 2.1\n * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>\n *\n * PHP QR Code is distributed under LGPL 3\n * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>\n *\n * The following data / specifications are taken from\n * \"Two dimensional symbol -- QR-code -- Basic Specification\" (JIS X0510:2004)\n *  or\n * \"Automatic identification and data capture techniques -- \n *  QR Code 2005 bar code symbology specification\" (ISO/IEC 18004:2006)\n *\n * This library is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 3 of the License, or any later version.\n *\n * This library is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with this library; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n */\n    class QRsplit {\n\n        public $dataStr = '';\n        public $input;\n        public $modeHint;\n\n        //----------------------------------------------------------------------\n        public function __construct($dataStr, $input, $modeHint) \n        {\n            $this->dataStr  = $dataStr;\n            $this->input    = $input;\n            $this->modeHint = $modeHint;\n        }\n        \n        //----------------------------------------------------------------------\n        public static function isdigitat($str, $pos)\n        {    \n            if ($pos >= strlen($str))\n                return false;\n            \n            return ((ord($str[$pos]) >= ord('0'))&&(ord($str[$pos]) <= ord('9')));\n        }\n        \n        //----------------------------------------------------------------------\n        public static function isalnumat($str, $pos)\n        {\n            if ($pos >= strlen($str))\n                return false;\n                \n            return (QRinput::lookAnTable(ord($str[$pos])) >= 0);\n        }\n\n        //----------------------------------------------------------------------\n        public function identifyMode($pos)\n        {\n            if ($pos >= strlen($this->dataStr)) \n                return QR_MODE_NUL;\n                \n            $c = $this->dataStr[$pos];\n            \n            if(self::isdigitat($this->dataStr, $pos)) {\n                return QR_MODE_NUM;\n            } else if(self::isalnumat($this->dataStr, $pos)) {\n                return QR_MODE_AN;\n            } else if($this->modeHint == QR_MODE_KANJI) {\n            \n                if ($pos+1 < strlen($this->dataStr)) \n                {\n                    $d = $this->dataStr[$pos+1];\n                    $word = (ord($c) << 8) | ord($d);\n                    if(($word >= 0x8140 && $word <= 0x9ffc) || ($word >= 0xe040 && $word <= 0xebbf)) {\n                        return QR_MODE_KANJI;\n                    }\n                }\n            }\n\n            return QR_MODE_8;\n        } \n        \n        //----------------------------------------------------------------------\n        public function eatNum()\n        {\n            $ln = QRspec::lengthIndicator(QR_MODE_NUM, $this->input->getVersion());\n\n            $p = 0;\n            while(self::isdigitat($this->dataStr, $p)) {\n                $p++;\n            }\n            \n            $run = $p;\n            $mode = $this->identifyMode($p);\n            \n            if($mode == QR_MODE_8) {\n                $dif = QRinput::estimateBitsModeNum($run) + 4 + $ln\n                     + QRinput::estimateBitsMode8(1)         // + 4 + l8\n                     - QRinput::estimateBitsMode8($run + 1); // - 4 - l8\n                if($dif > 0) {\n                    return $this->eat8();\n                }\n            }\n            if($mode == QR_MODE_AN) {\n                $dif = QRinput::estimateBitsModeNum($run) + 4 + $ln\n                     + QRinput::estimateBitsModeAn(1)        // + 4 + la\n                     - QRinput::estimateBitsModeAn($run + 1);// - 4 - la\n                if($dif > 0) {\n                    return $this->eatAn();\n                }\n            }\n            \n            $ret = $this->input->append(QR_MODE_NUM, $run, str_split($this->dataStr));\n            if($ret < 0)\n                return -1;\n\n            return $run;\n        }\n        \n        //----------------------------------------------------------------------\n        public function eatAn()\n        {\n            $la = QRspec::lengthIndicator(QR_MODE_AN,  $this->input->getVersion());\n            $ln = QRspec::lengthIndicator(QR_MODE_NUM, $this->input->getVersion());\n\n            $p = 0;\n            \n            while(self::isalnumat($this->dataStr, $p)) {\n                if(self::isdigitat($this->dataStr, $p)) {\n                    $q = $p;\n                    while(self::isdigitat($this->dataStr, $q)) {\n                        $q++;\n                    }\n                    \n                    $dif = QRinput::estimateBitsModeAn($p) // + 4 + la\n                         + QRinput::estimateBitsModeNum($q - $p) + 4 + $ln\n                         - QRinput::estimateBitsModeAn($q); // - 4 - la\n                         \n                    if($dif < 0) {\n                        break;\n                    } else {\n                        $p = $q;\n                    }\n                } else {\n                    $p++;\n                }\n            }\n\n            $run = $p;\n\n            if(!self::isalnumat($this->dataStr, $p)) {\n                $dif = QRinput::estimateBitsModeAn($run) + 4 + $la\n                     + QRinput::estimateBitsMode8(1) // + 4 + l8\n                      - QRinput::estimateBitsMode8($run + 1); // - 4 - l8\n                if($dif > 0) {\n                    return $this->eat8();\n                }\n            }\n\n            $ret = $this->input->append(QR_MODE_AN, $run, str_split($this->dataStr));\n            if($ret < 0)\n                return -1;\n\n            return $run;\n        }\n        \n        //----------------------------------------------------------------------\n        public function eatKanji()\n        {\n            $p = 0;\n            \n            while($this->identifyMode($p) == QR_MODE_KANJI) {\n                $p += 2;\n            }\n            \n            $ret = $this->input->append(QR_MODE_KANJI, $p, str_split($this->dataStr));\n            if($ret < 0)\n                return -1;\n\n            return $run;\n        }\n\n        //----------------------------------------------------------------------\n        public function eat8()\n        {\n            $la = QRspec::lengthIndicator(QR_MODE_AN, $this->input->getVersion());\n            $ln = QRspec::lengthIndicator(QR_MODE_NUM, $this->input->getVersion());\n\n            $p = 1;\n            $dataStrLen = strlen($this->dataStr);\n            \n            while($p < $dataStrLen) {\n                \n                $mode = $this->identifyMode($p);\n                if($mode == QR_MODE_KANJI) {\n                    break;\n                }\n                if($mode == QR_MODE_NUM) {\n                    $q = $p;\n                    while(self::isdigitat($this->dataStr, $q)) {\n                        $q++;\n                    }\n                    $dif = QRinput::estimateBitsMode8($p) // + 4 + l8\n                         + QRinput::estimateBitsModeNum($q - $p) + 4 + $ln\n                         - QRinput::estimateBitsMode8($q); // - 4 - l8\n                    if($dif < 0) {\n                        break;\n                    } else {\n                        $p = $q;\n                    }\n                } else if($mode == QR_MODE_AN) {\n                    $q = $p;\n                    while(self::isalnumat($this->dataStr, $q)) {\n                        $q++;\n                    }\n                    $dif = QRinput::estimateBitsMode8($p)  // + 4 + l8\n                         + QRinput::estimateBitsModeAn($q - $p) + 4 + $la\n                         - QRinput::estimateBitsMode8($q); // - 4 - l8\n                    if($dif < 0) {\n                        break;\n                    } else {\n                        $p = $q;\n                    }\n                } else {\n                    $p++;\n                }\n            }\n\n            $run = $p;\n            $ret = $this->input->append(QR_MODE_8, $run, str_split($this->dataStr));\n            \n            if($ret < 0)\n                return -1;\n\n            return $run;\n        }\n\n        //----------------------------------------------------------------------\n        public function splitString()\n        {\n            while (strlen($this->dataStr) > 0)\n            {\n                if($this->dataStr == '')\n                    return 0;\n\n                $mode = $this->identifyMode(0);\n                \n                switch ($mode) {\n                    case QR_MODE_NUM: $length = $this->eatNum(); break;\n                    case QR_MODE_AN:  $length = $this->eatAn(); break;\n                    case QR_MODE_KANJI:\n                        if ($hint == QR_MODE_KANJI)\n                                $length = $this->eatKanji();\n                        else    $length = $this->eat8();\n                        break;\n                    default: $length = $this->eat8(); break;\n                \n                }\n\n                if($length == 0) return 0;\n                if($length < 0)  return -1;\n                \n                $this->dataStr = substr($this->dataStr, $length);\n            }\n        }\n\n        //----------------------------------------------------------------------\n        public function toUpper()\n        {\n            $stringLen = strlen($this->dataStr);\n            $p = 0;\n            \n            while ($p<$stringLen) {\n                $mode = self::identifyMode(substr($this->dataStr, $p), $this->modeHint);\n                if($mode == QR_MODE_KANJI) {\n                    $p += 2;\n                } else {\n                    if (ord($this->dataStr[$p]) >= ord('a') && ord($this->dataStr[$p]) <= ord('z')) {\n                        $this->dataStr[$p] = chr(ord($this->dataStr[$p]) - 32);\n                    }\n                    $p++;\n                }\n            }\n\n            return $this->dataStr;\n        }\n\n        //----------------------------------------------------------------------\n        public static function splitStringToQRinput($string, QRinput $input, $modeHint, $casesensitive = true)\n        {\n            if(is_null($string) || $string == '\\0' || $string == '') {\n                throw new Exception('empty string!!!');\n            }\n\n            $split = new QRsplit($string, $input, $modeHint);\n            \n            if(!$casesensitive)\n                $split->toUpper();\n                \n            return $split->splitString();\n        }\n    }\n\n\n\n//---- qrrscode.php -----------------------------\n\n\n\n\n/*\n * PHP QR Code encoder\n *\n * Reed-Solomon error correction support\n * \n * Copyright (C) 2002, 2003, 2004, 2006 Phil Karn, KA9Q\n * (libfec is released under the GNU Lesser General Public License.)\n *\n * Based on libqrencode C library distributed under LGPL 2.1\n * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>\n *\n * PHP QR Code is distributed under LGPL 3\n * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>\n *\n * This library is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 3 of the License, or any later version.\n *\n * This library is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with this library; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n */\n \n    class QRrsItem {\n    \n        public $mm;                  // Bits per symbol \n        public $nn;                  // Symbols per block (= (1<<mm)-1) \n        public $alpha_to = array();  // log lookup table \n        public $index_of = array();  // Antilog lookup table \n        public $genpoly = array();   // Generator polynomial \n        public $nroots;              // Number of generator roots = number of parity symbols \n        public $fcr;                 // First consecutive root, index form \n        public $prim;                // Primitive element, index form \n        public $iprim;               // prim-th root of 1, index form \n        public $pad;                 // Padding bytes in shortened block \n        public $gfpoly;\n    \n        //----------------------------------------------------------------------\n        public function modnn($x)\n        {\n            while ($x >= $this->nn) {\n                $x -= $this->nn;\n                $x = ($x >> $this->mm) + ($x & $this->nn);\n            }\n            \n            return $x;\n        }\n        \n        //----------------------------------------------------------------------\n        public static function init_rs_char($symsize, $gfpoly, $fcr, $prim, $nroots, $pad)\n        {\n            // Common code for intializing a Reed-Solomon control block (char or int symbols)\n            // Copyright 2004 Phil Karn, KA9Q\n            // May be used under the terms of the GNU Lesser General Public License (LGPL)\n\n            $rs = null;\n            \n            // Check parameter ranges\n            if($symsize < 0 || $symsize > 8)                     return $rs;\n            if($fcr < 0 || $fcr >= (1<<$symsize))                return $rs;\n            if($prim <= 0 || $prim >= (1<<$symsize))             return $rs;\n            if($nroots < 0 || $nroots >= (1<<$symsize))          return $rs; // Can't have more roots than symbol values!\n            if($pad < 0 || $pad >= ((1<<$symsize) -1 - $nroots)) return $rs; // Too much padding\n\n            $rs = new QRrsItem();\n            $rs->mm = $symsize;\n            $rs->nn = (1<<$symsize)-1;\n            $rs->pad = $pad;\n\n            $rs->alpha_to = array_fill(0, $rs->nn+1, 0);\n            $rs->index_of = array_fill(0, $rs->nn+1, 0);\n          \n            // PHP style macro replacement ;)\n            $NN =& $rs->nn;\n            $A0 =& $NN;\n            \n            // Generate Galois field lookup tables\n            $rs->index_of[0] = $A0; // log(zero) = -inf\n            $rs->alpha_to[$A0] = 0; // alpha**-inf = 0\n            $sr = 1;\n          \n            for($i=0; $i<$rs->nn; $i++) {\n                $rs->index_of[$sr] = $i;\n                $rs->alpha_to[$i] = $sr;\n                $sr <<= 1;\n                if($sr & (1<<$symsize)) {\n                    $sr ^= $gfpoly;\n                }\n                $sr &= $rs->nn;\n            }\n            \n            if($sr != 1){\n                // field generator polynomial is not primitive!\n                $rs = NULL;\n                return $rs;\n            }\n\n            /* Form RS code generator polynomial from its roots */\n            $rs->genpoly = array_fill(0, $nroots+1, 0);\n        \n            $rs->fcr = $fcr;\n            $rs->prim = $prim;\n            $rs->nroots = $nroots;\n            $rs->gfpoly = $gfpoly;\n\n            /* Find prim-th root of 1, used in decoding */\n            for($iprim=1;($iprim % $prim) != 0;$iprim += $rs->nn)\n            ; // intentional empty-body loop!\n            \n            $rs->iprim = (int)($iprim / $prim);\n            $rs->genpoly[0] = 1;\n            \n            for ($i = 0,$root=$fcr*$prim; $i < $nroots; $i++, $root += $prim) {\n                $rs->genpoly[$i+1] = 1;\n\n                // Multiply rs->genpoly[] by  @**(root + x)\n                for ($j = $i; $j > 0; $j--) {\n                    if ($rs->genpoly[$j] != 0) {\n                        $rs->genpoly[$j] = $rs->genpoly[$j-1] ^ $rs->alpha_to[$rs->modnn($rs->index_of[$rs->genpoly[$j]] + $root)];\n                    } else {\n                        $rs->genpoly[$j] = $rs->genpoly[$j-1];\n                    }\n                }\n                // rs->genpoly[0] can never be zero\n                $rs->genpoly[0] = $rs->alpha_to[$rs->modnn($rs->index_of[$rs->genpoly[0]] + $root)];\n            }\n            \n            // convert rs->genpoly[] to index form for quicker encoding\n            for ($i = 0; $i <= $nroots; $i++)\n                $rs->genpoly[$i] = $rs->index_of[$rs->genpoly[$i]];\n\n            return $rs;\n        }\n        \n        //----------------------------------------------------------------------\n        public function encode_rs_char($data, &$parity)\n        {\n            $MM       =& $this->mm;\n            $NN       =& $this->nn;\n            $ALPHA_TO =& $this->alpha_to;\n            $INDEX_OF =& $this->index_of;\n            $GENPOLY  =& $this->genpoly;\n            $NROOTS   =& $this->nroots;\n            $FCR      =& $this->fcr;\n            $PRIM     =& $this->prim;\n            $IPRIM    =& $this->iprim;\n            $PAD      =& $this->pad;\n            $A0       =& $NN;\n\n            $parity = array_fill(0, $NROOTS, 0);\n\n            for($i=0; $i< ($NN-$NROOTS-$PAD); $i++) {\n                \n                $feedback = $INDEX_OF[$data[$i] ^ $parity[0]];\n                if($feedback != $A0) {      \n                    // feedback term is non-zero\n            \n                    // This line is unnecessary when GENPOLY[NROOTS] is unity, as it must\n                    // always be for the polynomials constructed by init_rs()\n                    $feedback = $this->modnn($NN - $GENPOLY[$NROOTS] + $feedback);\n            \n                    for($j=1;$j<$NROOTS;$j++) {\n                        $parity[$j] ^= $ALPHA_TO[$this->modnn($feedback + $GENPOLY[$NROOTS-$j])];\n                    }\n                }\n                \n                // Shift \n                array_shift($parity);\n                if($feedback != $A0) {\n                    array_push($parity, $ALPHA_TO[$this->modnn($feedback + $GENPOLY[0])]);\n                } else {\n                    array_push($parity, 0);\n                }\n            }\n        }\n    }\n    \n    //##########################################################################\n    \n    class QRrs {\n    \n        public static $items = array();\n        \n        //----------------------------------------------------------------------\n        public static function init_rs($symsize, $gfpoly, $fcr, $prim, $nroots, $pad)\n        {\n            foreach(self::$items as $rs) {\n                if($rs->pad != $pad)       continue;\n                if($rs->nroots != $nroots) continue;\n                if($rs->mm != $symsize)    continue;\n                if($rs->gfpoly != $gfpoly) continue;\n                if($rs->fcr != $fcr)       continue;\n                if($rs->prim != $prim)     continue;\n\n                return $rs;\n            }\n\n            $rs = QRrsItem::init_rs_char($symsize, $gfpoly, $fcr, $prim, $nroots, $pad);\n            array_unshift(self::$items, $rs);\n\n            return $rs;\n        }\n    }\n\n\n\n//---- qrmask.php -----------------------------\n\n\n\n\n/*\n * PHP QR Code encoder\n *\n * Masking\n *\n * Based on libqrencode C library distributed under LGPL 2.1\n * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>\n *\n * PHP QR Code is distributed under LGPL 3\n * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>\n *\n * This library is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 3 of the License, or any later version.\n *\n * This library is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with this library; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n */\n \n\tdefine('N1', 3);\n\tdefine('N2', 3);\n\tdefine('N3', 40);\n\tdefine('N4', 10);\n\n\tclass QRmask {\n\t\n\t\tpublic $runLength = array();\n\t\t\n\t\t//----------------------------------------------------------------------\n\t\tpublic function __construct() \n        {\n            $this->runLength = array_fill(0, QRSPEC_WIDTH_MAX + 1, 0);\n        }\n        \n        //----------------------------------------------------------------------\n        public function writeFormatInformation($width, &$frame, $mask, $level)\n        {\n            $blacks = 0;\n            $format =  QRspec::getFormatInfo($mask, $level);\n\n            for($i=0; $i<8; $i++) {\n                if($format & 1) {\n                    $blacks += 2;\n                    $v = 0x85;\n                } else {\n                    $v = 0x84;\n                }\n                \n                $frame[8][$width - 1 - $i] = chr($v);\n                if($i < 6) {\n                    $frame[$i][8] = chr($v);\n                } else {\n                    $frame[$i + 1][8] = chr($v);\n                }\n                $format = $format >> 1;\n            }\n            \n            for($i=0; $i<7; $i++) {\n                if($format & 1) {\n                    $blacks += 2;\n                    $v = 0x85;\n                } else {\n                    $v = 0x84;\n                }\n                \n                $frame[$width - 7 + $i][8] = chr($v);\n                if($i == 0) {\n                    $frame[8][7] = chr($v);\n                } else {\n                    $frame[8][6 - $i] = chr($v);\n                }\n                \n                $format = $format >> 1;\n            }\n\n            return $blacks;\n        }\n        \n        //----------------------------------------------------------------------\n        public function mask0($x, $y) { return ($x+$y)&1;                       }\n        public function mask1($x, $y) { return ($y&1);                          }\n        public function mask2($x, $y) { return ($x%3);                          }\n        public function mask3($x, $y) { return ($x+$y)%3;                       }\n        public function mask4($x, $y) { return (((int)($y/2))+((int)($x/3)))&1; }\n        public function mask5($x, $y) { return (($x*$y)&1)+($x*$y)%3;           }\n        public function mask6($x, $y) { return ((($x*$y)&1)+($x*$y)%3)&1;       }\n        public function mask7($x, $y) { return ((($x*$y)%3)+(($x+$y)&1))&1;     }\n        \n        //----------------------------------------------------------------------\n        private function generateMaskNo($maskNo, $width, $frame)\n        {\n            $bitMask = array_fill(0, $width, array_fill(0, $width, 0));\n            \n            for($y=0; $y<$width; $y++) {\n                for($x=0; $x<$width; $x++) {\n                    if(ord($frame[$y][$x]) & 0x80) {\n                        $bitMask[$y][$x] = 0;\n                    } else {\n                        $maskFunc = call_user_func(array($this, 'mask'.$maskNo), $x, $y);\n                        $bitMask[$y][$x] = ($maskFunc == 0)?1:0;\n                    }\n                    \n                }\n            }\n            \n            return $bitMask;\n        }\n        \n        //----------------------------------------------------------------------\n        public static function serial($bitFrame)\n        {\n            $codeArr = array();\n            \n            foreach ($bitFrame as $line)\n                $codeArr[] = join('', $line);\n                \n            return gzcompress(join(\"\\n\", $codeArr), 9);\n        }\n        \n        //----------------------------------------------------------------------\n        public static function unserial($code)\n        {\n            $codeArr = array();\n            \n            $codeLines = explode(\"\\n\", gzuncompress($code));\n            foreach ($codeLines as $line)\n                $codeArr[] = str_split($line);\n            \n            return $codeArr;\n        }\n        \n        //----------------------------------------------------------------------\n        public function makeMaskNo($maskNo, $width, $s, &$d, $maskGenOnly = false) \n        {\n            $b = 0;\n            $bitMask = array();\n            \n            $fileName = QR_CACHE_DIR.'mask_'.$maskNo.DIRECTORY_SEPARATOR.'mask_'.$width.'_'.$maskNo.'.dat';\n\n            if (QR_CACHEABLE) {\n                if (file_exists($fileName)) {\n                    $bitMask = self::unserial(file_get_contents($fileName));\n                } else {\n                    $bitMask = $this->generateMaskNo($maskNo, $width, $s, $d);\n                    if (!file_exists(QR_CACHE_DIR.'mask_'.$maskNo))\n                        mkdir(QR_CACHE_DIR.'mask_'.$maskNo);\n                    file_put_contents($fileName, self::serial($bitMask));\n                }\n            } else {\n                $bitMask = $this->generateMaskNo($maskNo, $width, $s, $d);\n            }\n\n            if ($maskGenOnly)\n                return;\n                \n            $d = $s;\n\n            for($y=0; $y<$width; $y++) {\n                for($x=0; $x<$width; $x++) {\n                    if($bitMask[$y][$x] == 1) {\n                        $d[$y][$x] = chr(ord($s[$y][$x]) ^ (int)$bitMask[$y][$x]);\n                    }\n                    $b += (int)(ord($d[$y][$x]) & 1);\n                }\n            }\n\n            return $b;\n        }\n        \n        //----------------------------------------------------------------------\n        public function makeMask($width, $frame, $maskNo, $level)\n        {\n            $masked = array_fill(0, $width, str_repeat(\"\\0\", $width));\n            $this->makeMaskNo($maskNo, $width, $frame, $masked);\n            $this->writeFormatInformation($width, $masked, $maskNo, $level);\n       \n            return $masked;\n        }\n        \n        //----------------------------------------------------------------------\n        public function calcN1N3($length)\n        {\n            $demerit = 0;\n\n            for($i=0; $i<$length; $i++) {\n                \n                if($this->runLength[$i] >= 5) {\n                    $demerit += (N1 + ($this->runLength[$i] - 5));\n                }\n                if($i & 1) {\n                    if(($i >= 3) && ($i < ($length-2)) && ($this->runLength[$i] % 3 == 0)) {\n                        $fact = (int)($this->runLength[$i] / 3);\n                        if(($this->runLength[$i-2] == $fact) &&\n                           ($this->runLength[$i-1] == $fact) &&\n                           ($this->runLength[$i+1] == $fact) &&\n                           ($this->runLength[$i+2] == $fact)) {\n                            if(($this->runLength[$i-3] < 0) || ($this->runLength[$i-3] >= (4 * $fact))) {\n                                $demerit += N3;\n                            } else if((($i+3) >= $length) || ($this->runLength[$i+3] >= (4 * $fact))) {\n                                $demerit += N3;\n                            }\n                        }\n                    }\n                }\n            }\n            return $demerit;\n        }\n        \n        //----------------------------------------------------------------------\n        public function evaluateSymbol($width, $frame)\n        {\n            $head = 0;\n            $demerit = 0;\n\n            for($y=0; $y<$width; $y++) {\n                $head = 0;\n                $this->runLength[0] = 1;\n                \n                $frameY = $frame[$y];\n                \n                if ($y>0)\n                    $frameYM = $frame[$y-1];\n                \n                for($x=0; $x<$width; $x++) {\n                    if(($x > 0) && ($y > 0)) {\n                        $b22 = ord($frameY[$x]) & ord($frameY[$x-1]) & ord($frameYM[$x]) & ord($frameYM[$x-1]);\n                        $w22 = ord($frameY[$x]) | ord($frameY[$x-1]) | ord($frameYM[$x]) | ord($frameYM[$x-1]);\n                        \n                        if(($b22 | ($w22 ^ 1))&1) {                                                                     \n                            $demerit += N2;\n                        }\n                    }\n                    if(($x == 0) && (ord($frameY[$x]) & 1)) {\n                        $this->runLength[0] = -1;\n                        $head = 1;\n                        $this->runLength[$head] = 1;\n                    } else if($x > 0) {\n                        if((ord($frameY[$x]) ^ ord($frameY[$x-1])) & 1) {\n                            $head++;\n                            $this->runLength[$head] = 1;\n                        } else {\n                            $this->runLength[$head]++;\n                        }\n                    }\n                }\n    \n                $demerit += $this->calcN1N3($head+1);\n            }\n\n            for($x=0; $x<$width; $x++) {\n                $head = 0;\n                $this->runLength[0] = 1;\n                \n                for($y=0; $y<$width; $y++) {\n                    if($y == 0 && (ord($frame[$y][$x]) & 1)) {\n                        $this->runLength[0] = -1;\n                        $head = 1;\n                        $this->runLength[$head] = 1;\n                    } else if($y > 0) {\n                        if((ord($frame[$y][$x]) ^ ord($frame[$y-1][$x])) & 1) {\n                            $head++;\n                            $this->runLength[$head] = 1;\n                        } else {\n                            $this->runLength[$head]++;\n                        }\n                    }\n                }\n            \n                $demerit += $this->calcN1N3($head+1);\n            }\n\n            return $demerit;\n        }\n        \n        \n        //----------------------------------------------------------------------\n        public function mask($width, $frame, $level)\n        {\n            $minDemerit = PHP_INT_MAX;\n            $bestMaskNum = 0;\n            $bestMask = array();\n            \n            $checked_masks = array(0,1,2,3,4,5,6,7);\n            \n            if (QR_FIND_FROM_RANDOM !== false) {\n            \n                $howManuOut = 8-(QR_FIND_FROM_RANDOM % 9);\n                for ($i = 0; $i <  $howManuOut; $i++) {\n                    $remPos = rand (0, count($checked_masks)-1);\n                    unset($checked_masks[$remPos]);\n                    $checked_masks = array_values($checked_masks);\n                }\n            \n            }\n            \n            $bestMask = $frame;\n             \n            foreach($checked_masks as $i) {\n                $mask = array_fill(0, $width, str_repeat(\"\\0\", $width));\n\n                $demerit = 0;\n                $blacks = 0;\n                $blacks  = $this->makeMaskNo($i, $width, $frame, $mask);\n                $blacks += $this->writeFormatInformation($width, $mask, $i, $level);\n                $blacks  = (int)(100 * $blacks / ($width * $width));\n                $demerit = (int)((int)(abs($blacks - 50) / 5) * N4);\n                $demerit += $this->evaluateSymbol($width, $mask);\n                \n                if($demerit < $minDemerit) {\n                    $minDemerit = $demerit;\n                    $bestMask = $mask;\n                    $bestMaskNum = $i;\n                }\n            }\n            \n            return $bestMask;\n        }\n        \n        //----------------------------------------------------------------------\n    }\n\n\n\n\n//---- qrencode.php -----------------------------\n\n\n\n\n/*\n * PHP QR Code encoder\n *\n * Main encoder classes.\n *\n * Based on libqrencode C library distributed under LGPL 2.1\n * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>\n *\n * PHP QR Code is distributed under LGPL 3\n * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>\n *\n * This library is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 3 of the License, or any later version.\n *\n * This library is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with this library; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n */\n \n    class QRrsblock {\n        public $dataLength;\n        public $data = array();\n        public $eccLength;\n        public $ecc = array();\n        \n        public function __construct($dl, $data, $el, &$ecc, QRrsItem $rs)\n        {\n            $rs->encode_rs_char($data, $ecc);\n        \n            $this->dataLength = $dl;\n            $this->data = $data;\n            $this->eccLength = $el;\n            $this->ecc = $ecc;\n        }\n    };\n    \n    //##########################################################################\n\n    class QRrawcode {\n        public $version;\n        public $datacode = array();\n        public $ecccode = array();\n        public $blocks;\n        public $rsblocks = array(); //of RSblock\n        public $count;\n        public $dataLength;\n        public $eccLength;\n        public $b1;\n        \n        //----------------------------------------------------------------------\n        public function __construct(QRinput $input)\n        {\n            $spec = array(0,0,0,0,0);\n            \n            $this->datacode = $input->getByteStream();\n            if(is_null($this->datacode)) {\n                throw new Exception('null imput string');\n            }\n\n            QRspec::getEccSpec($input->getVersion(), $input->getErrorCorrectionLevel(), $spec);\n\n            $this->version = $input->getVersion();\n            $this->b1 = QRspec::rsBlockNum1($spec);\n            $this->dataLength = QRspec::rsDataLength($spec);\n            $this->eccLength = QRspec::rsEccLength($spec);\n            $this->ecccode = array_fill(0, $this->eccLength, 0);\n            $this->blocks = QRspec::rsBlockNum($spec);\n            \n            $ret = $this->init($spec);\n            if($ret < 0) {\n                throw new Exception('block alloc error');\n                return null;\n            }\n\n            $this->count = 0;\n        }\n        \n        //----------------------------------------------------------------------\n        public function init(array $spec)\n        {\n            $dl = QRspec::rsDataCodes1($spec);\n            $el = QRspec::rsEccCodes1($spec);\n            $rs = QRrs::init_rs(8, 0x11d, 0, 1, $el, 255 - $dl - $el);\n            \n\n            $blockNo = 0;\n            $dataPos = 0;\n            $eccPos = 0;\n            for($i=0; $i<QRspec::rsBlockNum1($spec); $i++) {\n                $ecc = array_slice($this->ecccode,$eccPos);\n                $this->rsblocks[$blockNo] = new QRrsblock($dl, array_slice($this->datacode, $dataPos), $el,  $ecc, $rs);\n                $this->ecccode = array_merge(array_slice($this->ecccode,0, $eccPos), $ecc);\n                \n                $dataPos += $dl;\n                $eccPos += $el;\n                $blockNo++;\n            }\n\n            if(QRspec::rsBlockNum2($spec) == 0)\n                return 0;\n\n            $dl = QRspec::rsDataCodes2($spec);\n            $el = QRspec::rsEccCodes2($spec);\n            $rs = QRrs::init_rs(8, 0x11d, 0, 1, $el, 255 - $dl - $el);\n            \n            if($rs == NULL) return -1;\n            \n            for($i=0; $i<QRspec::rsBlockNum2($spec); $i++) {\n                $ecc = array_slice($this->ecccode,$eccPos);\n                $this->rsblocks[$blockNo] = new QRrsblock($dl, array_slice($this->datacode, $dataPos), $el, $ecc, $rs);\n                $this->ecccode = array_merge(array_slice($this->ecccode,0, $eccPos), $ecc);\n                \n                $dataPos += $dl;\n                $eccPos += $el;\n                $blockNo++;\n            }\n\n            return 0;\n        }\n        \n        //----------------------------------------------------------------------\n        public function getCode()\n        {\n            $ret;\n\n            if($this->count < $this->dataLength) {\n                $row = $this->count % $this->blocks;\n                $col = $this->count / $this->blocks;\n                if($col >= $this->rsblocks[0]->dataLength) {\n                    $row += $this->b1;\n                }\n                $ret = $this->rsblocks[$row]->data[$col];\n            } else if($this->count < $this->dataLength + $this->eccLength) {\n                $row = ($this->count - $this->dataLength) % $this->blocks;\n                $col = ($this->count - $this->dataLength) / $this->blocks;\n                $ret = $this->rsblocks[$row]->ecc[$col];\n            } else {\n                return 0;\n            }\n            $this->count++;\n            \n            return $ret;\n        }\n    }\n\n    //##########################################################################\n    \n    class QRcode {\n    \n        public $version;\n        public $width;\n        public $data; \n        \n        //----------------------------------------------------------------------\n        public function encodeMask(QRinput $input, $mask)\n        {\n            if($input->getVersion() < 0 || $input->getVersion() > QRSPEC_VERSION_MAX) {\n                throw new Exception('wrong version');\n            }\n            if($input->getErrorCorrectionLevel() > QR_ECLEVEL_H) {\n                throw new Exception('wrong level');\n            }\n\n            $raw = new QRrawcode($input);\n            \n            QRtools::markTime('after_raw');\n            \n            $version = $raw->version;\n            $width = QRspec::getWidth($version);\n            $frame = QRspec::newFrame($version);\n            \n            $filler = new FrameFiller($width, $frame);\n            if(is_null($filler)) {\n                return NULL;\n            }\n\n            // inteleaved data and ecc codes\n            for($i=0; $i<$raw->dataLength + $raw->eccLength; $i++) {\n                $code = $raw->getCode();\n                $bit = 0x80;\n                for($j=0; $j<8; $j++) {\n                    $addr = $filler->next();\n                    $filler->setFrameAt($addr, 0x02 | (($bit & $code) != 0));\n                    $bit = $bit >> 1;\n                }\n            }\n            \n            QRtools::markTime('after_filler');\n            \n            unset($raw);\n            \n            // remainder bits\n            $j = QRspec::getRemainder($version);\n            for($i=0; $i<$j; $i++) {\n                $addr = $filler->next();\n                $filler->setFrameAt($addr, 0x02);\n            }\n            \n            $frame = $filler->frame;\n            unset($filler);\n            \n            \n            // masking\n            $maskObj = new QRmask();\n            if($mask < 0) {\n            \n                if (QR_FIND_BEST_MASK) {\n                    $masked = $maskObj->mask($width, $frame, $input->getErrorCorrectionLevel());\n                } else {\n                    $masked = $maskObj->makeMask($width, $frame, (intval(QR_DEFAULT_MASK) % 8), $input->getErrorCorrectionLevel());\n                }\n            } else {\n                $masked = $maskObj->makeMask($width, $frame, $mask, $input->getErrorCorrectionLevel());\n            }\n            \n            if($masked == NULL) {\n                return NULL;\n            }\n            \n            QRtools::markTime('after_mask');\n            \n            $this->version = $version;\n            $this->width = $width;\n            $this->data = $masked;\n            \n            return $this;\n        }\n    \n        //----------------------------------------------------------------------\n        public function encodeInput(QRinput $input)\n        {\n            return $this->encodeMask($input, -1);\n        }\n        \n        //----------------------------------------------------------------------\n        public function encodeString8bit($string, $version, $level)\n        {\n            if(string == NULL) {\n                throw new Exception('empty string!');\n                return NULL;\n            }\n\n            $input = new QRinput($version, $level);\n            if($input == NULL) return NULL;\n\n            $ret = $input->append($input, QR_MODE_8, strlen($string), str_split($string));\n            if($ret < 0) {\n                unset($input);\n                return NULL;\n            }\n            return $this->encodeInput($input);\n        }\n\n        //----------------------------------------------------------------------\n        public function encodeString($string, $version, $level, $hint, $casesensitive)\n        {\n\n            if($hint != QR_MODE_8 && $hint != QR_MODE_KANJI) {\n                throw new Exception('bad hint');\n                return NULL;\n            }\n\n            $input = new QRinput($version, $level);\n            if($input == NULL) return NULL;\n\n            $ret = QRsplit::splitStringToQRinput($string, $input, $hint, $casesensitive);\n            if($ret < 0) {\n                return NULL;\n            }\n\n            return $this->encodeInput($input);\n        }\n        \n        //----------------------------------------------------------------------\n        public static function png($text, $outfile = false, $level = QR_ECLEVEL_L, $size = 3, $margin = 4, $saveandprint=false) \n        {\n            $enc = QRencode::factory($level, $size, $margin);\n            return $enc->encodePNG($text, $outfile, $saveandprint=false);\n        }\n\n        //----------------------------------------------------------------------\n        public static function text($text, $outfile = false, $level = QR_ECLEVEL_L, $size = 3, $margin = 4) \n        {\n            $enc = QRencode::factory($level, $size, $margin);\n            return $enc->encode($text, $outfile);\n        }\n\n        //----------------------------------------------------------------------\n        public static function raw($text, $outfile = false, $level = QR_ECLEVEL_L, $size = 3, $margin = 4) \n        {\n            $enc = QRencode::factory($level, $size, $margin);\n            return $enc->encodeRAW($text, $outfile);\n        }\n    }\n    \n    //##########################################################################\n    \n    class FrameFiller {\n    \n        public $width;\n        public $frame;\n        public $x;\n        public $y;\n        public $dir;\n        public $bit;\n        \n        //----------------------------------------------------------------------\n        public function __construct($width, &$frame)\n        {\n            $this->width = $width;\n            $this->frame = $frame;\n            $this->x = $width - 1;\n            $this->y = $width - 1;\n            $this->dir = -1;\n            $this->bit = -1;\n        }\n        \n        //----------------------------------------------------------------------\n        public function setFrameAt($at, $val)\n        {\n            $this->frame[$at['y']][$at['x']] = chr($val);\n        }\n        \n        //----------------------------------------------------------------------\n        public function getFrameAt($at)\n        {\n            return ord($this->frame[$at['y']][$at['x']]);\n        }\n        \n        //----------------------------------------------------------------------\n        public function next()\n        {\n            do {\n            \n                if($this->bit == -1) {\n                    $this->bit = 0;\n                    return array('x'=>$this->x, 'y'=>$this->y);\n                }\n\n                $x = $this->x;\n                $y = $this->y;\n                $w = $this->width;\n\n                if($this->bit == 0) {\n                    $x--;\n                    $this->bit++;\n                } else {\n                    $x++;\n                    $y += $this->dir;\n                    $this->bit--;\n                }\n\n                if($this->dir < 0) {\n                    if($y < 0) {\n                        $y = 0;\n                        $x -= 2;\n                        $this->dir = 1;\n                        if($x == 6) {\n                            $x--;\n                            $y = 9;\n                        }\n                    }\n                } else {\n                    if($y == $w) {\n                        $y = $w - 1;\n                        $x -= 2;\n                        $this->dir = -1;\n                        if($x == 6) {\n                            $x--;\n                            $y -= 8;\n                        }\n                    }\n                }\n                if($x < 0 || $y < 0) return null;\n\n                $this->x = $x;\n                $this->y = $y;\n\n            } while(ord($this->frame[$y][$x]) & 0x80);\n                        \n            return array('x'=>$x, 'y'=>$y);\n        }\n        \n    } ;\n    \n    //##########################################################################    \n    \n    class QRencode {\n    \n        public $casesensitive = true;\n        public $eightbit = false;\n        \n        public $version = 0;\n        public $size = 3;\n        public $margin = 4;\n        \n        public $structured = 0; // not supported yet\n        \n        public $level = QR_ECLEVEL_L;\n        public $hint = QR_MODE_8;\n        \n        //----------------------------------------------------------------------\n        public static function factory($level = QR_ECLEVEL_L, $size = 3, $margin = 4)\n        {\n            $enc = new QRencode();\n            $enc->size = $size;\n            $enc->margin = $margin;\n            \n            switch ($level.'') {\n                case '0':\n                case '1':\n                case '2':\n                case '3':\n                        $enc->level = $level;\n                    break;\n                case 'l':\n                case 'L':\n                        $enc->level = QR_ECLEVEL_L;\n                    break;\n                case 'm':\n                case 'M':\n                        $enc->level = QR_ECLEVEL_M;\n                    break;\n                case 'q':\n                case 'Q':\n                        $enc->level = QR_ECLEVEL_Q;\n                    break;\n                case 'h':\n                case 'H':\n                        $enc->level = QR_ECLEVEL_H;\n                    break;\n            }\n            \n            return $enc;\n        }\n        \n        //----------------------------------------------------------------------\n        public function encodeRAW($intext, $outfile = false) \n        {\n            $code = new QRcode();\n\n            if($this->eightbit) {\n                $code->encodeString8bit($intext, $this->version, $this->level);\n            } else {\n                $code->encodeString($intext, $this->version, $this->level, $this->hint, $this->casesensitive);\n            }\n            \n            return $code->data;\n        }\n\n        //----------------------------------------------------------------------\n        public function encode($intext, $outfile = false) \n        {\n            $code = new QRcode();\n\n            if($this->eightbit) {\n                $code->encodeString8bit($intext, $this->version, $this->level);\n            } else {\n                $code->encodeString($intext, $this->version, $this->level, $this->hint, $this->casesensitive);\n            }\n            \n            QRtools::markTime('after_encode');\n            \n            if ($outfile!== false) {\n                file_put_contents($outfile, join(\"\\n\", QRtools::binarize($code->data)));\n            } else {\n                return QRtools::binarize($code->data);\n            }\n        }\n        \n        //----------------------------------------------------------------------\n        public function encodePNG($intext, $outfile = false,$saveandprint=false) \n        {\n            try {\n            \n                ob_start();\n                $tab = $this->encode($intext);\n                $err = ob_get_contents();\n                ob_end_clean();\n                \n                if ($err != '')\n                    QRtools::log($outfile, $err);\n                \n                $maxSize = (int)(QR_PNG_MAXIMUM_SIZE / (count($tab)+2*$this->margin));\n                \n                QRimage::png($tab, $outfile, min(max(1, $this->size), $maxSize), $this->margin,$saveandprint);\n            \n            } catch (Exception $e) {\n            \n                QRtools::log($outfile, $e->getMessage());\n            \n            }\n        }\n    }\n\n\n"
  },
  {
    "path": "server/ThinkPHP/Library/Vendor/README.txt",
    "content": "﻿第三方类库包目录"
  },
  {
    "path": "server/ThinkPHP/Mode/common.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n      \n/**\n * ThinkPHP 普通模式定义\n */\nreturn array(\n    // 配置文件\n    'config'    =>  array(\n        THINK_PATH.'Conf/convention.php',   // 系统惯例配置\n        CONF_PATH.'config'.CONF_EXT,      // 应用公共配置\n    ),\n\n    // 别名定义\n    'alias'     =>  array(\n        'Think\\Log'               => CORE_PATH . 'Log'.EXT,\n        'Think\\Log\\Driver\\File'   => CORE_PATH . 'Log/Driver/File'.EXT,\n        'Think\\Exception'         => CORE_PATH . 'Exception'.EXT,\n        'Think\\Model'             => CORE_PATH . 'Model'.EXT,\n        'Think\\Db'                => CORE_PATH . 'Db'.EXT,\n        'Think\\Template'          => CORE_PATH . 'Template'.EXT,\n        'Think\\Cache'             => CORE_PATH . 'Cache'.EXT,\n        'Think\\Cache\\Driver\\File' => CORE_PATH . 'Cache/Driver/File'.EXT,\n        'Think\\Storage'           => CORE_PATH . 'Storage'.EXT,\n    ),\n\n    // 函数和类文件\n    'core'      =>  array(\n        THINK_PATH.'Common/functions.php',\n        COMMON_PATH.'Common/function.php',\n        CORE_PATH . 'Hook'.EXT,\n        CORE_PATH . 'App'.EXT,\n        CORE_PATH . 'Dispatcher'.EXT,\n        //CORE_PATH . 'Log'.EXT,\n        CORE_PATH . 'Route'.EXT,\n        CORE_PATH . 'Controller'.EXT,\n        CORE_PATH . 'View'.EXT,\n        BEHAVIOR_PATH . 'BuildLiteBehavior'.EXT,\n        BEHAVIOR_PATH . 'ParseTemplateBehavior'.EXT,\n        BEHAVIOR_PATH . 'ContentReplaceBehavior'.EXT,\n    ),\n    // 行为扩展定义\n    'tags'  =>  array(\n        'app_init'     =>  array(\n            'Behavior\\BuildLiteBehavior', // 生成运行Lite文件\n        ),        \n        'app_begin'     =>  array(\n            'Behavior\\ReadHtmlCacheBehavior', // 读取静态缓存\n        ),\n        'app_end'       =>  array(\n            'Behavior\\ShowPageTraceBehavior', // 页面Trace显示\n        ),\n        'view_parse'    =>  array(\n            'Behavior\\ParseTemplateBehavior', // 模板解析 支持PHP、内置模板引擎和第三方模板引擎\n        ),\n        'template_filter'=> array(\n            'Behavior\\ContentReplaceBehavior', // 模板输出替换\n        ),\n        'view_filter'   =>  array(\n            'Behavior\\WriteHtmlCacheBehavior', // 写入静态缓存\n        ),\n    ),\n);\n"
  },
  {
    "path": "server/ThinkPHP/ThinkPHP.php",
    "content": "<?php\n// +----------------------------------------------------------------------\n// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]\n// +----------------------------------------------------------------------\n// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.\n// +----------------------------------------------------------------------\n// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n// +----------------------------------------------------------------------\n// | Author: liu21st <liu21st@gmail.com>\n// +----------------------------------------------------------------------\n\n//----------------------------------\n// ThinkPHP公共入口文件\n//----------------------------------\n\n// 记录开始运行时间\n$GLOBALS['_beginTime'] = microtime(TRUE);\n// 记录内存初始使用\ndefine('MEMORY_LIMIT_ON', function_exists('memory_get_usage'));\nif (MEMORY_LIMIT_ON) $GLOBALS['_startUseMems'] = memory_get_usage();\n\n// 版本信息\nconst THINK_VERSION     =   '3.2.3';\n\n// URL 模式定义\nconst URL_COMMON        =   0;  //普通模式\nconst URL_PATHINFO      =   1;  //PATHINFO模式\nconst URL_REWRITE       =   2;  //REWRITE模式\nconst URL_COMPAT        =   3;  // 兼容模式\n\n// 类文件后缀\nconst EXT               =   '.class.php';\n\n// 系统常量定义\ndefined('THINK_PATH')   or define('THINK_PATH',     __DIR__ . '/');\ndefined('APP_PATH')     or define('APP_PATH',       dirname($_SERVER['SCRIPT_FILENAME']) . '/');\ndefined('APP_STATUS')   or define('APP_STATUS',     ''); // 应用状态 加载对应的配置文件\ndefined('APP_DEBUG')    or define('APP_DEBUG',      false); // 是否调试模式\n\nif (function_exists('saeAutoLoader')) { // 自动识别SAE环境\n    defined('APP_MODE')     or define('APP_MODE',      'sae');\n    defined('STORAGE_TYPE') or define('STORAGE_TYPE',  'Sae');\n} else {\n    defined('APP_MODE')     or define('APP_MODE',       'common'); // 应用模式 默认为普通模式    \n    defined('STORAGE_TYPE') or define('STORAGE_TYPE',   'File'); // 存储类型 默认为File    \n}\n\ndefined('RUNTIME_PATH') or define('RUNTIME_PATH',   APP_PATH . 'Runtime/');   // 系统运行时目录\ndefined('LIB_PATH')     or define('LIB_PATH',       realpath(THINK_PATH . 'Library') . '/'); // 系统核心类库目录\ndefined('CORE_PATH')    or define('CORE_PATH',      LIB_PATH . 'Think/'); // Think类库目录\ndefined('BEHAVIOR_PATH') or define('BEHAVIOR_PATH',  LIB_PATH . 'Behavior/'); // 行为类库目录\ndefined('MODE_PATH')    or define('MODE_PATH',      THINK_PATH . 'Mode/'); // 系统应用模式目录\ndefined('VENDOR_PATH')  or define('VENDOR_PATH',    LIB_PATH . 'Vendor/'); // 第三方类库目录\ndefined('COMMON_PATH')  or define('COMMON_PATH',    APP_PATH . 'Common/'); // 应用公共目录\ndefined('CONF_PATH')    or define('CONF_PATH',      COMMON_PATH . 'Conf/'); // 应用配置目录\ndefined('LANG_PATH')    or define('LANG_PATH',      COMMON_PATH . 'Lang/'); // 应用语言目录\ndefined('HTML_PATH')    or define('HTML_PATH',      APP_PATH . 'Html/'); // 应用静态目录\ndefined('LOG_PATH')     or define('LOG_PATH',       RUNTIME_PATH . 'Logs/'); // 应用日志目录\ndefined('TEMP_PATH')    or define('TEMP_PATH',      RUNTIME_PATH . 'Temp/'); // 应用缓存目录\ndefined('DATA_PATH')    or define('DATA_PATH',      RUNTIME_PATH . 'Data/'); // 应用数据目录\ndefined('CACHE_PATH')   or define('CACHE_PATH',     RUNTIME_PATH . 'Cache/'); // 应用模板缓存目录\ndefined('CONF_EXT')     or define('CONF_EXT',       '.php'); // 配置文件后缀\ndefined('CONF_PARSE')   or define('CONF_PARSE',     '');    // 配置文件解析方法\ndefined('ADDON_PATH')   or define('ADDON_PATH',     APP_PATH . 'Addon');\n\n// 系统信息\nif (version_compare(PHP_VERSION, '5.4.0', '<')) {\n    ini_set('magic_quotes_runtime', 0);\n    define('MAGIC_QUOTES_GPC', get_magic_quotes_gpc() ? true : false);\n} else {\n    define('MAGIC_QUOTES_GPC', false);\n}\ndefine('IS_CGI', (0 === strpos(PHP_SAPI, 'cgi') || false !== strpos(PHP_SAPI, 'fcgi')) ? 1 : 0);\ndefine('IS_WIN', strstr(PHP_OS, 'WIN') ? 1 : 0);\ndefine('IS_CLI', PHP_SAPI == 'cli' ? 1   :   0);\n\nif (!IS_CLI) {\n    // 当前文件名\n    if (!defined('_PHP_FILE_')) {\n        if (IS_CGI) {\n            //CGI/FASTCGI模式下\n            $_temp  = explode('.php', $_SERVER['PHP_SELF']);\n            define('_PHP_FILE_',    rtrim(str_replace($_SERVER['HTTP_HOST'], '', $_temp[0] . '.php'), '/'));\n        } else {\n            define('_PHP_FILE_',    rtrim($_SERVER['SCRIPT_NAME'], '/'));\n        }\n    }\n    if (!defined('__ROOT__')) {\n        $_root  =   rtrim(dirname(_PHP_FILE_), '/');\n        define('__ROOT__', (($_root == '/' || $_root == '\\\\') ? '' : $_root));\n    }\n} else {\n    // 尝试修复php8的命令行模式下，常量未定义的问题\n    if (!defined('_PHP_FILE_')) {\n        define('_PHP_FILE_',  \"\");\n    }\n}\n\n// 加载核心Think类\nrequire CORE_PATH . 'Think' . EXT;\n// 应用初始化 \nThink\\Think::start();\n"
  },
  {
    "path": "server/ThinkPHP/Tpl/dispatch_jump.tpl",
    "content": "<?php\n    if(C('LAYOUT_ON')) {\n        echo '{__NOLAYOUT__}';\n    }\n?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n<title>跳转提示</title>\n<style type=\"text/css\">\n*{ padding: 0; margin: 0; }\nbody{ background: #fff; font-family: '微软雅黑'; color: #333; font-size: 16px; }\n.system-message{ padding: 24px 48px; }\n.system-message h1{ font-size: 100px; font-weight: normal; line-height: 120px; margin-bottom: 12px; }\n.system-message .jump{ padding-top: 10px}\n.system-message .jump a{ color: #333;}\n.system-message .success,.system-message .error{ line-height: 1.8em; font-size: 36px }\n.system-message .detail{ font-size: 12px; line-height: 20px; margin-top: 12px; display:none}\n</style>\n</head>\n<body>\n<div class=\"system-message\">\n<?php if(isset($message)) {?>\n<h1>:)</h1>\n<p class=\"success\"><?php echo($message); ?></p>\n<?php }else{?>\n<h1>:(</h1>\n<p class=\"error\"><?php echo($error); ?></p>\n<?php }?>\n<p class=\"detail\"></p>\n<p class=\"jump\">\n页面自动 <a id=\"href\" href=\"<?php echo($jumpUrl); ?>\">跳转</a> 等待时间： <b id=\"wait\"><?php echo($waitSecond); ?></b>\n</p>\n</div>\n<script type=\"text/javascript\">\n(function(){\nvar wait = document.getElementById('wait'),href = document.getElementById('href').href;\nvar interval = setInterval(function(){\n\tvar time = --wait.innerHTML;\n\tif(time <= 0) {\n\t\tlocation.href = href;\n\t\tclearInterval(interval);\n\t};\n}, 1000);\n})();\n</script>\n</body>\n</html>\n"
  },
  {
    "path": "server/ThinkPHP/Tpl/page_trace.tpl",
    "content": "<div id=\"think_page_trace\" style=\"position: fixed;bottom:0;right:0;font-size:14px;width:100%;z-index: 999999;color: #000;text-align:left;font-family:'微软雅黑';\">\n<div id=\"think_page_trace_tab\" style=\"display: none;background:white;margin:0;height: 250px;\">\n<div id=\"think_page_trace_tab_tit\" style=\"height:30px;padding: 6px 12px 0;border-bottom:1px solid #ececec;border-top:1px solid #ececec;font-size:16px\">\n\t<?php foreach($trace as $key => $value){ ?>\n    <span style=\"color:#000;padding-right:12px;height:30px;line-height: 30px;display:inline-block;margin-right:3px;cursor: pointer;font-weight:700\"><?php echo $key ?></span>\n    <?php } ?>\n</div>\n<div id=\"think_page_trace_tab_cont\" style=\"overflow:auto;height:212px;padding: 0; line-height: 24px\">\n\t\t<?php foreach($trace as $info) { ?>\n    <div style=\"display:none;\">\n    <ol style=\"padding: 0; margin:0\">\n\t<?php \n\tif(is_array($info)){\n\t\tforeach ($info as $k=>$val){\n\t\techo '<li style=\"border-bottom:1px solid #EEE;font-size:14px;padding:0 12px\">' . (is_numeric($k) ? '' : $k.' : ') . htmlentities($val,ENT_COMPAT,'utf-8') .'</li>';\n\t    }\n\t}\n    ?>\n    </ol>\n    </div>\n    <?php } ?>\n</div>\n</div>\n<div id=\"think_page_trace_close\" style=\"display:none;text-align:right;height:15px;position:absolute;top:10px;right:12px;cursor: pointer;\"><img style=\"vertical-align:top;\" src=\"data:image/gif;base64,R0lGODlhDwAPAJEAAAAAAAMDA////wAAACH/C1hNUCBEYXRhWE1QPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS4wLWMwNjAgNjEuMTM0Nzc3LCAyMDEwLzAyLzEyLTE3OjMyOjAwICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IFdpbmRvd3MiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MUQxMjc1MUJCQUJDMTFFMTk0OUVGRjc3QzU4RURFNkEiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MUQxMjc1MUNCQUJDMTFFMTk0OUVGRjc3QzU4RURFNkEiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDoxRDEyNzUxOUJBQkMxMUUxOTQ5RUZGNzdDNThFREU2QSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDoxRDEyNzUxQUJBQkMxMUUxOTQ5RUZGNzdDNThFREU2QSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PgH//v38+/r5+Pf29fTz8vHw7+7t7Ovq6ejn5uXk4+Lh4N/e3dzb2tnY19bV1NPS0dDPzs3My8rJyMfGxcTDwsHAv769vLu6ubi3trW0s7KxsK+urayrqqmop6alpKOioaCfnp2cm5qZmJeWlZSTkpGQj46NjIuKiYiHhoWEg4KBgH9+fXx7enl4d3Z1dHNycXBvbm1sa2ppaGdmZWRjYmFgX15dXFtaWVhXVlVUU1JRUE9OTUxLSklIR0ZFRENCQUA/Pj08Ozo5ODc2NTQzMjEwLy4tLCsqKSgnJiUkIyIhIB8eHRwbGhkYFxYVFBMSERAPDg0MCwoJCAcGBQQDAgEAACH5BAAAAAAALAAAAAAPAA8AAAIdjI6JZqotoJPR1fnsgRR3C2jZl3Ai9aWZZooV+RQAOw==\" /></div>\n</div>\n<div id=\"think_page_trace_open\" style=\"height:30px;float:right;text-align: right;overflow:hidden;position:fixed;bottom:0;right:0;color:#000;line-height:30px;cursor:pointer;\"><div style=\"background:#232323;color:#FFF;padding:0 6px;float:right;line-height:30px;font-size:14px\"><?php echo G('beginTime','viewEndTime').'s ';?></div><img width=\"30\" style=\"\" title=\"ShowPageTrace\" src=\"data:image/png;base64,<?php echo \\Think\\App::logo() ?>\"></div>\n<script type=\"text/javascript\">\n(function(){\nvar tab_tit  = document.getElementById('think_page_trace_tab_tit').getElementsByTagName('span');\nvar tab_cont = document.getElementById('think_page_trace_tab_cont').getElementsByTagName('div');\nvar open     = document.getElementById('think_page_trace_open');\nvar close    = document.getElementById('think_page_trace_close').childNodes[0];\nvar trace    = document.getElementById('think_page_trace_tab');\nvar cookie   = document.cookie.match(/thinkphp_show_page_trace=(\\d\\|\\d)/);\nvar history  = (cookie && typeof cookie[1] != 'undefined' && cookie[1].split('|')) || [0,0];\nopen.onclick = function(){\n\ttrace.style.display = 'block';\n\tthis.style.display = 'none';\n\tclose.parentNode.style.display = 'block';\n\thistory[0] = 1;\n\tdocument.cookie = 'thinkphp_show_page_trace='+history.join('|')\n}\nclose.onclick = function(){\n\ttrace.style.display = 'none';\nthis.parentNode.style.display = 'none';\n\topen.style.display = 'block';\n\thistory[0] = 0;\n\tdocument.cookie = 'thinkphp_show_page_trace='+history.join('|')\n}\nfor(var i = 0; i < tab_tit.length; i++){\n\ttab_tit[i].onclick = (function(i){\n\t\treturn function(){\n\t\t\tfor(var j = 0; j < tab_cont.length; j++){\n\t\t\t\ttab_cont[j].style.display = 'none';\n\t\t\t\ttab_tit[j].style.color = '#999';\n\t\t\t}\n\t\t\ttab_cont[i].style.display = 'block';\n\t\t\ttab_tit[i].style.color = '#000';\n\t\t\thistory[1] = i;\n\t\t\tdocument.cookie = 'thinkphp_show_page_trace='+history.join('|')\n\t\t}\n\t})(i)\n}\nparseInt(history[0]) && open.click();\n(tab_tit[history[1]] || tab_tit[0]).click();\n})();\n</script>\n"
  },
  {
    "path": "server/ThinkPHP/Tpl/think_exception.tpl",
    "content": "<?php\n    if(C('LAYOUT_ON')) {\n        echo '{__NOLAYOUT__}';\n    }\n?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\"><head>\n<meta content=\"text/html; charset=utf-8\" http-equiv=\"Content-Type\">\n<title>系统发生错误</title>\n<style type=\"text/css\">\n*{ padding: 0; margin: 0; }\nhtml{ overflow-y: scroll; }\nbody{ background: #fff; font-family: '微软雅黑'; color: #333; font-size: 16px; }\nimg{ border: 0; }\n.error{ padding: 24px 48px; }\n.face{ font-size: 100px; font-weight: normal; line-height: 120px; margin-bottom: 12px; }\nh1{ font-size: 32px; line-height: 48px; }\n.error .content{ padding-top: 10px}\n.error .info{ margin-bottom: 12px; }\n.error .info .title{ margin-bottom: 3px; }\n.error .info .title h3{ color: #000; font-weight: 700; font-size: 16px; }\n.error .info .text{ line-height: 24px; }\n.copyright{ padding: 12px 48px; color: #999; }\n.copyright a{ color: #000; text-decoration: none; }\n</style>\n</head>\n<body>\n<div class=\"error\">\n<p class=\"face\">:(</p>\n<h1><?php echo strip_tags($e['message']);?></h1>\n<div class=\"content\">\n<?php if(isset($e['file'])) {?>\n\t<div class=\"info\">\n\t\t<div class=\"title\">\n\t\t\t<h3>错误位置</h3>\n\t\t</div>\n\t\t<div class=\"text\">\n\t\t\t<p>FILE: <?php echo $e['file'] ;?> &#12288;LINE: <?php echo $e['line'];?></p>\n\t\t</div>\n\t</div>\n<?php }?>\n<?php if(isset($e['trace'])) {?>\n\t<div class=\"info\">\n\t\t<div class=\"title\">\n\t\t\t<h3>TRACE</h3>\n\t\t</div>\n\t\t<div class=\"text\">\n\t\t\t<p><?php echo nl2br($e['trace']);?></p>\n\t\t</div>\n\t</div>\n<?php }?>\n</div>\n</div>\n<div class=\"copyright\">\n<p><a title=\"官方网站\" href=\"http://www.thinkphp.cn\">ThinkPHP</a><sup><?php echo THINK_VERSION ?></sup> { Fast & Simple OOP PHP Framework } -- [ WE CAN DO IT JUST THINK ]</p>\n</div>\n</body>\n</html>\n"
  },
  {
    "path": "server/app/Api/Controller/AdminItemController.php",
    "content": "<?php\n\nnamespace App\\Api\\Controller;\n\nuse App\\Common\\BaseController;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\nuse App\\Model\\Item;\nuse App\\Model\\ItemMember;\nuse App\\Model\\TeamItemMember;\nuse App\\Model\\User;\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\n/**\n * 管理后台项目相关 Api（开源版）\n */\nclass AdminItemController extends BaseController\n{\n    /**\n     * 获取所有项目列表（兼容旧接口 Api/AdminItem/getList）\n     */\n    public function getList(Request $request, Response $response): Response\n    {\n        // 获取登录用户并检查管理员权限\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $adminCheck = $this->checkAdmin($request, $response);\n        if ($adminCheck !== true) {\n            return $adminCheck;\n        }\n\n        $itemName = $this->getParam($request, 'item_name', '');\n        $page = $this->getParam($request, 'page', 1); \n        $count = $this->getParam($request, 'count', 20);\n        $positiveType = $this->getParam($request, 'positive_type', 0);\n        $itemType = $this->getParam($request, 'item_type', 0);\n        $privacyType = $this->getParam($request, 'privacy_type', 0);\n        $username = $this->getParam($request, 'username', '');\n        $isDel = $this->getParam($request, 'is_del', 0); // 0: 正常；1: 已删除\n\n        // 构建查询\n        $query = DB::table('item');\n        \n        if ($isDel == 1) {\n            $query->where('is_del', 1);\n        } else {\n            $query->where('is_del', 0);\n        }\n\n        if (!empty($itemName)) {\n            $likeItem = $this->safeLike($itemName);\n            $query->where('item_name', 'like', \"%{$likeItem}%\");\n        }\n\n        if (!empty($username)) {\n            $likeUser = $this->safeLike($username);\n            $query->where('username', 'like', \"%{$likeUser}%\");\n        }\n\n        // 根据项目类型过滤\n        if ($itemType > 0) {\n            $query->where('item.item_type', $itemType);\n        }\n\n        // 公开项目/私密项目\n        if ($privacyType > 1) {\n            if ($privacyType == 2) {\n                $query->where('item.password', '');\n            } elseif ($privacyType == 3) {\n                $query->where('item.password', '!=', '');\n            }\n        }\n\n        // 已删除项目按删除时间倒序（使用 last_update_time 作为删除时间），正常项目按创建时间倒序\n        if ($isDel == 1) {\n            $query->orderBy('last_update_time', 'desc');\n        } else {\n            $query->orderBy('addtime', 'desc');\n        }\n\n        $total = $query->count();\n        $items = $query->offset(($page - 1) * $count)->limit($count)->get();\n\n        $return = [];\n        $return['total'] = (int) $total;\n        $return['items'] = [];\n\n        if ($items) {\n            foreach ($items as $item) {\n                $itemData = (array) $item;\n                $itemData['addtime'] = date(\"Y-m-d H:i:s\", $itemData['addtime']);\n                \n                if ($isDel == 1) {\n                    $itemData['del_time'] = date(\"Y-m-d H:i:s\", (int) $itemData['last_update_time']);\n                }\n\n                // 计算成员数\n                $memberNum = DB::table('item_member')->where('item_id', $item->item_id)->count() \n                    + DB::table('team_item_member')->where('item_id', $item->item_id)->count();\n                $itemData['member_num'] = $memberNum;\n\n                $return['items'][] = $itemData;\n            }\n        }\n\n        return $this->success($response, $return);\n    }\n\n    /**\n     * 删除项目（软删除）\n     */\n    public function deleteItem(Request $request, Response $response): Response\n    {\n        // 获取登录用户并检查管理员权限\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $adminCheck = $this->checkAdmin($request, $response);\n        if ($adminCheck !== true) {\n            return $adminCheck;\n        }\n\n        $itemId = $this->getParam($request, 'item_id', 0);\n        if ($itemId <= 0) {\n            return $this->error($response, 10101, '参数错误');\n        }\n\n        $result = Item::softDeleteItem($itemId);\n        if (!$result) {\n            return $this->error($response, 10101, '删除失败');\n        }\n\n        return $this->success($response, []);\n    }\n\n    /**\n     * 恢复已删除项目\n     */\n    public function recoverItem(Request $request, Response $response): Response\n    {\n        // 获取登录用户并检查管理员权限\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $adminCheck = $this->checkAdmin($request, $response);\n        if ($adminCheck !== true) {\n            return $adminCheck;\n        }\n\n        $itemId = $this->getParam($request, 'item_id', 0);\n        if ($itemId <= 0) {\n            return $this->error($response, 10101, '参数错误');\n        }\n\n        $item = DB::table('item')->where('item_id', $itemId)->first();\n        if (!$item || (int) $item->is_del !== 1) {\n            return $this->error($response, 10101, '项目不存在或未被删除');\n        }\n\n        // 恢复项目与页面\n        DB::table('page')->where('item_id', $itemId)->update(['is_del' => 0]);\n        $ret = DB::table('item')\n            ->where('item_id', $itemId)\n            ->update(['is_del' => 0, 'last_update_time' => time()]);\n\n        if (!$ret) {\n            return $this->error($response, 10101, '恢复失败');\n        }\n\n        return $this->success($response, []);\n    }\n\n    /**\n     * 永久删除项目（硬删除，不可恢复）\n     */\n    public function hardDeleteItem(Request $request, Response $response): Response\n    {\n        // 获取登录用户并检查管理员权限\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $adminCheck = $this->checkAdmin($request, $response);\n        if ($adminCheck !== true) {\n            return $adminCheck;\n        }\n\n        $itemId = $this->getParam($request, 'item_id', 0);\n        if ($itemId <= 0) {\n            return $this->error($response, 10101, '参数错误');\n        }\n\n        $item = DB::table('item')->where('item_id', $itemId)->first();\n        if (!$item || (int) $item->is_del !== 1) {\n            return $this->error($response, 10101, '仅允许对已删除项目执行永久删除');\n        }\n\n        $ret = Item::deleteItem($itemId);\n        if (!$ret) {\n            return $this->error($response, 10101, '删除失败');\n        }\n\n        return $this->success($response, []);\n    }\n\n    /**\n     * 转让项目\n     */\n    public function attorn(Request $request, Response $response): Response\n    {\n        // 获取登录用户并检查管理员权限\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $adminCheck = $this->checkAdmin($request, $response);\n        if ($adminCheck !== true) {\n            return $adminCheck;\n        }\n\n        $username = $this->getParam($request, 'username', '');\n        $itemId = $this->getParam($request, 'item_id', 0);\n\n        if (empty($username) || $itemId <= 0) {\n            return $this->error($response, 10101, '参数错误');\n        }\n\n        $item = DB::table('item')->where('item_id', $itemId)->first();\n        if (!$item) {\n            return $this->error($response, 10101, '项目不存在');\n        }\n\n        $member = User::findByUsername($username);\n        if (!$member) {\n            return $this->error($response, 10209, '用户不存在');\n        }\n\n        $ret = DB::table('item')\n            ->where('item_id', $itemId)\n            ->update([\n                'username' => $member->username,\n                'uid' => $member->uid,\n            ]);\n\n        if (!$ret) {\n            return $this->error($response, 10101, '转让失败');\n        }\n\n        $return = DB::table('item')->where('item_id', $itemId)->first();\n        return $this->success($response, (array) $return);\n    }\n}\n\n"
  },
  {
    "path": "server/app/Api/Controller/AdminMessageController.php",
    "content": "<?php\n\nnamespace App\\Api\\Controller;\n\nuse App\\Common\\BaseController;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\n/**\n * 管理后台消息相关 Api（开源版，无分表）\n */\nclass AdminMessageController extends BaseController\n{\n    /**\n     * 管理员发布系统公告（兼容旧接口 Api/AdminMessage/addAnnouncement）\n     */\n    public function addAnnouncement(Request $request, Response $response): Response\n    {\n        // 获取登录用户并检查管理员权限\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $adminCheck = $this->checkAdmin($request, $response);\n        if ($adminCheck !== true) {\n            return $adminCheck;\n        }\n\n        $messageContent = $this->getParam($request, 'message_content', '');\n        $messageType = trim($this->getParam($request, 'message_type', ''));\n        $sendAt = $this->getParam($request, 'send_at', '');\n\n        if (empty($messageContent)) {\n            return $this->error($response, 10101, '参数错误：message_content 不能为空');\n        }\n\n        // 公告类型白名单与默认值\n        $allowTypes = ['announce_web', 'announce_runapi', 'announce_all'];\n        if (empty($messageType)) {\n            // 兼容旧版：未传类型时默认为网页端公告\n            $messageType = 'announce_web';\n        }\n        if (!in_array($messageType, $allowTypes, true)) {\n            $messageType = 'announce_web';\n        }\n\n        // 基础安全过滤：去除危险标签与协议\n        $messageContent = $this->sanitizeHtml($messageContent);\n        // 将换行转换为 <br>\n        $messageContent = nl2br($messageContent);\n\n        $addtime = !empty($sendAt) ? $sendAt : date(\"Y-m-d H:i:s\");\n\n        // 开源版：使用单表 message_content，无分表\n        $id = DB::table('message_content')->insertGetId([\n            'from_uid' => 0,\n            'from_name' => '系统公告',\n            'message_type' => $messageType,\n            'message_content' => $messageContent,\n            'action_type' => '',\n            'object_type' => '',\n            'object_id' => 0,\n            'addtime' => $addtime,\n        ]);\n\n        if (!$id) {\n            return $this->error($response, 10101, '保存失败');\n        }\n\n        return $this->success($response, ['id' => (int) $id]);\n    }\n\n    /**\n     * 管理员查看公告列表（兼容旧接口 Api/AdminMessage/listAnnouncements）\n     */\n    public function listAnnouncements(Request $request, Response $response): Response\n    {\n        // 获取登录用户并检查管理员权限\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $adminCheck = $this->checkAdmin($request, $response);\n        if ($adminCheck !== true) {\n            return $adminCheck;\n        }\n\n        $page = $this->getParam($request, 'page', 1);\n        $count = $this->getParam($request, 'count', 20);\n\n        // 开源版：使用单表 message_content，无分表\n        $list = DB::table('message_content')\n            ->whereIn('message_type', ['announce', 'announce_web', 'announce_runapi', 'announce_all'])\n            ->orderBy('id', 'desc')\n            ->offset(($page - 1) * $count)\n            ->limit($count)\n            ->get();\n\n        $result = [];\n        foreach ($list as $row) {\n            $result[] = (array) $row;\n        }\n\n        return $this->success($response, $result);\n    }\n\n    /**\n     * 简单HTML过滤（保留少量安全标签，移除脚本协议）\n     */\n    private function sanitizeHtml($html)\n    {\n        $allowed = '<p><br><ul><ol><li><strong><b><em><i><code><pre><h1><h2><h3><h4><blockquote><a>';\n        $clean = strip_tags($html, $allowed);\n        // 去掉 a 标签中的 javascript: 协议\n        $clean = preg_replace('/javascript\\s*:/i', '', $clean);\n        return $clean;\n    }\n}\n\n"
  },
  {
    "path": "server/app/Api/Controller/AdminSettingController.php",
    "content": "<?php\n\nnamespace App\\Api\\Controller;\n\nuse App\\Common\\BaseController;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\nuse App\\Model\\Options;\nuse App\\Common\\Helper\\AiHelper;\nuse App\\Common\\Helper\\FileHelper;\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\n/**\n * 管理后台设置相关 Api（开源版）\n */\nclass AdminSettingController extends BaseController\n{\n    /**\n     * 保存配置（兼容旧接口 Api/AdminSetting/saveConfig）\n     */\n    public function saveConfig(Request $request, Response $response): Response\n    {\n        // 获取登录用户并检查管理员权限\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $adminCheck = $this->checkAdmin($request, $response);\n        if ($adminCheck !== true) {\n            return $adminCheck;\n        }\n\n        // 获取原始参数（使用 null 作为默认值，避免 getParam 的类型转换）\n        // 然后手动进行类型转换，确保布尔值 true 转换为字符串 \"1\"\n        $registerOpenRaw = $this->getParam($request, 'register_open', null);\n        $historyVersionCountRaw = $this->getParam($request, 'history_version_count', null);\n        $ossOpenRaw = $this->getParam($request, 'oss_open', null);\n        $homePageRaw = $this->getParam($request, 'home_page', null);\n        $homeItemRaw = $this->getParam($request, 'home_item', null);\n        $ossSetting = $this->getParam($request, 'oss_setting', []);\n        $showWatermarkRaw = $this->getParam($request, 'show_watermark', null);\n        $beian = $this->getParam($request, 'beian', '');\n        $siteUrl = $this->getParam($request, 'site_url', '');\n        $openApiKey = $this->getParam($request, 'open_api_key', '');\n        $openApiHost = $this->getParam($request, 'open_api_host', '');\n        $aiModelName = $this->getParam($request, 'ai_model_name', '');\n        $aiServiceUrl = $this->getParam($request, 'ai_service_url', '');\n        $aiServiceToken = $this->getParam($request, 'ai_service_token', '');\n        $forceLoginRaw = $this->getParam($request, 'force_login', null);\n        $enablePublicSquareRaw = $this->getParam($request, 'enable_public_square', null);\n        $strongPasswordEnabledRaw = $this->getParam($request, 'strong_password_enabled', null);\n        $sessionExpireDaysRaw = $this->getParam($request, 'session_expire_days', null);\n\n        // 手动类型转换：布尔值 true 转换为字符串 \"1\"，false 转换为 \"0\"\n        // 其他类型（整数、字符串等）也统一转换为字符串\n        $registerOpen = $this->convertToOptionValue($registerOpenRaw, '0');\n        $historyVersionCount = $this->convertToOptionValue($historyVersionCountRaw, '0');\n        $ossOpen = $this->convertToOptionValue($ossOpenRaw, '0');\n        $homePage = $this->convertToOptionValue($homePageRaw, '0');\n        $homeItem = $this->convertToOptionValue($homeItemRaw, '0');\n        $showWatermark = $this->convertToOptionValue($showWatermarkRaw, '0');\n        $forceLogin = $this->convertToOptionValue($forceLoginRaw, '0');\n        $enablePublicSquare = $this->convertToOptionValue($enablePublicSquareRaw, '0');\n        $strongPasswordEnabled = $this->convertToOptionValue($strongPasswordEnabledRaw, '0');\n\n        // sessionExpireDays 需要先验证范围，再转换为字符串\n        $sessionExpireDaysInt = $sessionExpireDaysRaw !== null ? (int) $sessionExpireDaysRaw : 180;\n        // 验证登录态有效时长范围，最小1天，最大3650天（10年）\n        if ($sessionExpireDaysInt < 1 || $sessionExpireDaysInt > 3650) {\n            $sessionExpireDaysInt = 180; // 使用默认值180天\n        }\n        $sessionExpireDays = (string) $sessionExpireDaysInt;\n\n        // 保存配置\n        // 注意：所有配置项都需要保存，即使值没变化也要确保写入数据库\n        Options::set(\"history_version_count\", $historyVersionCount);\n        Options::set(\"register_open\", $registerOpen);\n        Options::set(\"home_page\", $homePage);\n        Options::set(\"home_item\", $homeItem);\n        Options::set(\"beian\", $beian);\n        Options::set(\"site_url\", $siteUrl);\n        Options::set(\"open_api_key\", $openApiKey);\n        Options::set(\"open_api_host\", $openApiHost);\n        Options::set(\"ai_model_name\", $aiModelName);\n        Options::set(\"ai_service_url\", $aiServiceUrl);\n        Options::set(\"ai_service_token\", $aiServiceToken);\n        Options::set(\"show_watermark\", $showWatermark);\n        Options::set(\"force_login\", $forceLogin);\n        Options::set(\"enable_public_square\", $enablePublicSquare);\n        Options::set(\"strong_password_enabled\", $strongPasswordEnabled);\n        Options::set(\"session_expire_days\", $sessionExpireDays);\n\n        if ($ossOpen) {\n            $this->checkComposerPHPVersion();\n            Options::set(\"oss_setting\", json_encode($ossSetting, JSON_UNESCAPED_UNICODE));\n        }\n        Options::set(\"oss_open\", $ossOpen);\n\n        return $this->success($response, []);\n    }\n\n    /**\n     * 加载配置（兼容旧接口 Api/AdminSetting/loadConfig）\n     */\n    public function loadConfig(Request $request, Response $response): Response\n    {\n        // 获取登录用户并检查管理员权限\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $adminCheck = $this->checkAdmin($request, $response);\n        if ($adminCheck !== true) {\n            return $adminCheck;\n        }\n\n        $ossOpen = Options::get(\"oss_open\");\n        $registerOpen = Options::get(\"register_open\");\n        $showWatermark = Options::get(\"show_watermark\");\n        $historyVersionCount = Options::get(\"history_version_count\");\n        $ossSetting = Options::get(\"oss_setting\");\n        $homePage = Options::get(\"home_page\");\n        $homeItem = Options::get(\"home_item\");\n        $beian = Options::get(\"beian\");\n        $siteUrl = Options::get(\"site_url\");\n        $openApiKey = Options::get(\"open_api_key\");\n        $openApiHost = Options::get(\"open_api_host\");\n        $aiModelName = Options::get(\"ai_model_name\");\n        $aiServiceUrl = Options::get(\"ai_service_url\");\n        $aiServiceToken = Options::get(\"ai_service_token\");\n        $forceLogin = Options::get(\"force_login\");\n        $enablePublicSquare = Options::get(\"enable_public_square\");\n        $strongPasswordEnabled = Options::get(\"strong_password_enabled\");\n        $sessionExpireDays = Options::get(\"session_expire_days\");\n\n        // 兼容旧代码：直接获取原始值，不做类型转换\n        // 旧代码中 D(\"Options\")->get() 如果不存在返回 false，存在则返回原始值\n        $ossSetting = $ossSetting ? json_decode($ossSetting, true) : [];\n\n        // 如果 register_open 为 false 或 null，表示尚未有数据\n        if ($registerOpen === false || $registerOpen === null) {\n            return $this->success($response, []);\n        }\n\n        $array = [\n            \"oss_open\" => $ossOpen,\n            \"register_open\" => $registerOpen,\n            \"show_watermark\" => $showWatermark,\n            \"history_version_count\" => $historyVersionCount,\n            \"home_page\" => $homePage,\n            \"home_item\" => $homeItem,\n            \"beian\" => $beian,\n            \"site_url\" => $siteUrl,\n            \"oss_setting\" => $ossSetting,\n            \"open_api_key\" => $openApiKey,\n            \"open_api_host\" => $openApiHost,\n            \"ai_model_name\" => $aiModelName,\n            \"ai_service_url\" => $aiServiceUrl,\n            \"ai_service_token\" => $aiServiceToken,\n            \"force_login\" => $forceLogin,\n            \"enable_public_square\" => $enablePublicSquare,\n            \"strong_password_enabled\" => $strongPasswordEnabled,\n            \"session_expire_days\" => $sessionExpireDays,\n        ];\n        return $this->success($response, $array);\n    }\n\n    /**\n     * 保存LDAP配置（兼容旧接口 Api/AdminSetting/saveLdapConfig）\n     */\n    public function saveLdapConfig(Request $request, Response $response): Response\n    {\n        set_time_limit(60);\n        ini_set('memory_limit', '500M');\n\n        // 获取登录用户并检查管理员权限\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $adminCheck = $this->checkAdmin($request, $response);\n        if ($adminCheck !== true) {\n            return $adminCheck;\n        }\n\n        $ldapOpen = $this->getParam($request, 'ldap_open', 0);\n        $ldapForm = $this->getParam($request, 'ldap_form', []);\n\n        if ($ldapOpen) {\n            if (empty($ldapForm['user_field'])) {\n                $ldapForm['user_field'] = 'cn';\n            }\n\n            $ldapForm['user_field'] = strtolower($ldapForm['user_field']);\n\n            // 如果未配置姓名字段，则默认为空\n            if (!isset($ldapForm['name_field'])) {\n                $ldapForm['name_field'] = '';\n            }\n\n            if (!empty($ldapForm['name_field'])) {\n                $ldapForm['name_field'] = strtolower($ldapForm['name_field']);\n            }\n\n            if (!extension_loaded('ldap')) {\n                return $this->error($response, 10011, \"你尚未安装php-ldap扩展。如果是普通PHP环境，请手动安装之。如果是使用之前官方docker镜像，则需要重新安装镜像。方法是：备份 /showdoc_data 整个目录，然后全新安装showdoc，接着用备份覆盖/showdoc_data 。然后递归赋予777可写权限。\");\n            }\n\n            $ldapConn = ldap_connect($ldapForm['host'], $ldapForm['port']);\n            if (!$ldapConn) {\n                return $this->error($response, 10011, \"Can't connect to LDAP server\");\n            }\n\n            $ldapForm['bind_password'] = htmlspecialchars_decode($ldapForm['bind_password']);\n\n            ldap_set_option($ldapConn, LDAP_OPT_PROTOCOL_VERSION, $ldapForm['version']);\n            $rs = ldap_bind($ldapConn, $ldapForm['bind_dn'], $ldapForm['bind_password']);\n            if (!$rs) {\n                return $this->error($response, 10011, \"Can't bind to LDAP server\");\n            }\n\n            $ldapForm['search_filter'] = !empty($ldapForm['search_filter']) ? $ldapForm['search_filter'] : '(cn=*)';\n            $ldapForm['search_filter'] = trim(htmlspecialchars_decode($ldapForm['search_filter']));\n\n            // 检测search_filter中是否包含占位符 %(user)s\n            $hasPlaceholder = strpos($ldapForm['search_filter'], '%(user)s') !== false;\n\n            // 确定用于同步的搜索条件\n            if ($hasPlaceholder) {\n                $syncFilter = preg_replace('/%\\(user\\)s/', '*', $ldapForm['search_filter']);\n            } else {\n                $syncFilter = $ldapForm['search_filter'];\n            }\n\n            // 检查是否已经包含 objectClass 相关的过滤条件\n            $hasObjectclass = preg_match('/objectclass/i', $syncFilter);\n            if (!$hasObjectclass) {\n                $userFilter = '(|(objectClass=user)(objectClass=person)(objectClass=inetOrgPerson))';\n                $excludeFilter = '(!(objectClass=computer))(!(objectClass=group))(!(objectClass=organizationalUnit))';\n\n                if (preg_match('/^\\([^&|!]/', $syncFilter)) {\n                    $syncFilter = '(&' . $userFilter . $excludeFilter . $syncFilter . ')';\n                } else if (preg_match('/^\\(&/', $syncFilter)) {\n                    $syncFilter = preg_replace('/^\\(&/', '(&' . $userFilter . $excludeFilter, $syncFilter);\n                } else if (preg_match('/^\\(\\|/', $syncFilter)) {\n                    $syncFilter = '(&' . $userFilter . $excludeFilter . $syncFilter . ')';\n                }\n            }\n\n            // 执行用户同步操作\n            $result = ldap_search($ldapConn, $ldapForm['base_dn'], $syncFilter);\n\n            if (!$result) {\n                return $this->error($response, 10011, \"LDAP搜索失败，请检查 search filter 配置是否正确\");\n            }\n\n            $data = ldap_get_entries($ldapConn, $result);\n\n            // 改进用户字段获取逻辑，支持大小写不敏感\n            $userFieldLower = strtolower($ldapForm['user_field']);\n\n            for ($i = 0; $i < $data[\"count\"]; $i++) {\n                $ldapUser = null;\n                foreach ($data[$i] as $key => $value) {\n                    if (strtolower($key) === $userFieldLower && isset($value['count']) && $value['count'] > 0) {\n                        $ldapUser = $value[0];\n                        break;\n                    }\n                }\n\n                if (!$ldapUser) {\n                    continue;\n                }\n\n                // 获取用户姓名\n                $ldapName = '';\n                if (!empty($ldapForm['name_field'])) {\n                    $nameFieldLower = strtolower($ldapForm['name_field']);\n                    foreach ($data[$i] as $key => $value) {\n                        if (strtolower($key) === $nameFieldLower && isset($value['count']) && $value['count'] > 0) {\n                            $ldapName = $value[0];\n                            break;\n                        }\n                    }\n                }\n\n                // 如果该用户不在数据库里，则帮助其注册\n                $userInfo = \\App\\Model\\User::findByUsername($ldapUser);\n                if (!$userInfo) {\n                    $uid = \\App\\Model\\User::register($ldapUser, $ldapUser . FileHelper::getRandStr());\n                    if ($uid && $ldapName) {\n                        DB::table('user')->where('uid', $uid)->update(['name' => $ldapName]);\n                    }\n                } else if ($ldapName) {\n                    DB::table('user')->where('uid', $userInfo->uid)->update(['name' => $ldapName]);\n                }\n            }\n\n            Options::set(\"ldap_form\", json_encode($ldapForm, JSON_UNESCAPED_UNICODE));\n        }\n        Options::set(\"ldap_open\", $ldapOpen);\n\n        return $this->success($response, []);\n    }\n\n    /**\n     * 加载LDAP配置（兼容旧接口 Api/AdminSetting/loadLdapConfig）\n     */\n    public function loadLdapConfig(Request $request, Response $response): Response\n    {\n        // 获取登录用户并检查管理员权限\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $adminCheck = $this->checkAdmin($request, $response);\n        if ($adminCheck !== true) {\n            return $adminCheck;\n        }\n\n        $ldapOpen = Options::get(\"ldap_open\");\n        $ldapForm = Options::get(\"ldap_form\");\n        $ldapForm = $ldapForm ? json_decode($ldapForm, true) : null;\n\n        if ($ldapForm && !empty($ldapForm['host']) && empty($ldapForm['search_filter'])) {\n            $ldapForm['search_filter'] = '(cn=*)';\n        }\n\n        // 确保name_field字段存在\n        if ($ldapForm && !isset($ldapForm['name_field'])) {\n            $ldapForm['name_field'] = '';\n        }\n\n        $array = [\n            \"ldap_open\" => $ldapOpen,\n            \"ldap_form\" => $ldapForm,\n        ];\n        return $this->success($response, $array);\n    }\n\n    /**\n     * 保存OAuth2配置（兼容旧接口 Api/AdminSetting/saveOauth2Config）\n     */\n    public function saveOauth2Config(Request $request, Response $response): Response\n    {\n        // 获取登录用户并检查管理员权限\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $adminCheck = $this->checkAdmin($request, $response);\n        if ($adminCheck !== true) {\n            return $adminCheck;\n        }\n\n        $this->checkComposerPHPVersion();\n        $oauth2Open = $this->getParam($request, 'oauth2_open', 0);\n        $oauth2Form = $this->getParam($request, 'oauth2_form', []);\n\n        Options::set(\"oauth2_form\", json_encode($oauth2Form, JSON_UNESCAPED_UNICODE));\n        Options::set(\"oauth2_open\", $oauth2Open);\n\n        return $this->success($response, []);\n    }\n\n    /**\n     * 加载OAuth2配置（兼容旧接口 Api/AdminSetting/loadOauth2Config）\n     */\n    public function loadOauth2Config(Request $request, Response $response): Response\n    {\n        // 获取登录用户并检查管理员权限\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $adminCheck = $this->checkAdmin($request, $response);\n        if ($adminCheck !== true) {\n            return $adminCheck;\n        }\n\n        $oauth2Open = Options::get(\"oauth2_open\");\n        $oauth2Form = Options::get(\"oauth2_form\");\n        $oauth2Form = htmlspecialchars_decode($oauth2Form);\n        $oauth2Form = json_decode($oauth2Form, true);\n\n        $array = [\n            \"oauth2_open\" => $oauth2Open,\n            \"oauth2_form\" => $oauth2Form,\n        ];\n        return $this->success($response, $array);\n    }\n\n    /**\n     * 获取登录密钥（兼容旧接口 Api/AdminSetting/getLoginSecretKey）\n     */\n    public function getLoginSecretKey(Request $request, Response $response): Response\n    {\n        // 获取登录用户并检查管理员权限\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $adminCheck = $this->checkAdmin($request, $response);\n        if ($adminCheck !== true) {\n            return $adminCheck;\n        }\n\n        $loginSecretKey = Options::get(\"login_secret_key\");\n        if (!$loginSecretKey) {\n            $loginSecretKey = FileHelper::getRandStr();\n            Options::set(\"login_secret_key\", $loginSecretKey);\n        }\n\n        return $this->success($response, [\"login_secret_key\" => $loginSecretKey]);\n    }\n\n    /**\n     * 重置登录密钥（兼容旧接口 Api/AdminSetting/resetLoginSecretKey）\n     */\n    public function resetLoginSecretKey(Request $request, Response $response): Response\n    {\n        // 获取登录用户并检查管理员权限\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $adminCheck = $this->checkAdmin($request, $response);\n        if ($adminCheck !== true) {\n            return $adminCheck;\n        }\n\n        $loginSecretKey = FileHelper::getRandStr();\n        Options::set(\"login_secret_key\", $loginSecretKey);\n\n        return $this->success($response, [\"login_secret_key\" => $loginSecretKey]);\n    }\n\n    /**\n     * 测试AI服务连接（兼容旧接口 Api/AdminSetting/testAiService）\n     */\n    public function testAiService(Request $request, Response $response): Response\n    {\n        // 获取登录用户并检查管理员权限\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $adminCheck = $this->checkAdmin($request, $response);\n        if ($adminCheck !== true) {\n            return $adminCheck;\n        }\n\n        $aiServiceUrl = $this->getParam($request, 'ai_service_url', '');\n        $aiServiceToken = $this->getParam($request, 'ai_service_token', '');\n\n        if (empty($aiServiceUrl) || empty($aiServiceToken)) {\n            return $this->error($response, 10101, 'AI 服务地址和 Token 不能为空');\n        }\n\n        // 调用 AI 服务的健康检查接口\n        $url = rtrim($aiServiceUrl, '/') . '/api/health';\n        $result = AiHelper::callService($url, null, $aiServiceToken, 'GET', 10);\n\n        if ($result === false) {\n            return $this->error($response, 10101, '无法连接到 AI 服务，请检查服务地址和网络连接');\n        }\n\n        // 如果返回了错误信息\n        if (isset($result['error_code']) && $result['error_code'] != 0) {\n            return $this->error($response, 10101, isset($result['error_message']) ? $result['error_message'] : 'AI 服务返回错误');\n        }\n\n        return $this->success($response, [\n            'success' => true,\n            'message' => 'AI 服务连接成功',\n            'service_info' => $result\n        ]);\n    }\n\n    /**\n     * 将原始参数值转换为选项值（字符串格式）。\n     * 布尔值 true 转换为 \"1\"，false 转换为 \"0\"。\n     * \n     * @param mixed $value 原始值\n     * @param string $default 默认值（如果 $value 为 null）\n     * @return string 转换后的字符串值\n     */\n    private function convertToOptionValue($value, string $default): string\n    {\n        if ($value === null) {\n            return $default;\n        }\n\n        // 布尔值特殊处理：true → \"1\", false → \"0\"\n        if (is_bool($value)) {\n            return $value ? '1' : '0';\n        }\n\n        // 其他类型转换为字符串\n        return (string) $value;\n    }\n\n    /**\n     * 检查 Composer PHP 版本（OAuth2 和 CAS 需要 PHP 7.0+）\n     */\n    private function checkComposerPHPVersion(): bool\n    {\n        if (version_compare(PHP_VERSION, '7.0.0', '<=')) {\n            return false;\n        }\n        return true;\n    }\n}\n\n"
  },
  {
    "path": "server/app/Api/Controller/AdminUpdateController.php",
    "content": "<?php\n\nnamespace App\\Api\\Controller;\n\nuse App\\Common\\BaseController;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\nuse App\\Common\\Helper\\HttpHelper;\n\n/**\n * 管理后台更新相关 Api（开源版）\n */\nclass AdminUpdateController extends BaseController\n{\n    /**\n     * 检测showdoc版本更新（兼容旧接口 Api/AdminUpdate/checkUpdate）\n     */\n    public function checkUpdate(Request $request, Response $response): Response\n    {\n        // 获取当前版本\n        $rootPath = dirname(__DIR__, 4);\n        $composerPath = $rootPath . '/composer.json';\n        \n        if (!file_exists($composerPath)) {\n            return $this->error($response, 10101, 'composer.json 文件不存在');\n        }\n\n        $text = file_get_contents($composerPath);\n        $composer = json_decode($text, true);\n        $version = $composer['version'] ?? '';\n\n        $url = \"https://www.showdoc.cc/server/api/open/checkUpdate\";\n        $ch = curl_init();\n        $timeout = 2;\n        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);\n        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);\n        curl_setopt($ch, CURLOPT_POST, true);\n        curl_setopt($ch, CURLOPT_POSTFIELDS, \"version={$version}\");\n        curl_setopt($ch, CURLOPT_URL, $url);\n        $sContent = curl_exec($ch);\n        curl_close($ch);\n\n        // 转换字段名：将 file_url 改为 url（兼容前端）\n        $resArray = json_decode($sContent, true);\n        if ($resArray && isset($resArray['data']) && isset($resArray['data']['file_url'])) {\n            $resArray['data']['url'] = $resArray['data']['file_url'];\n        }\n\n        // 输出转换后的响应\n        $response->getBody()->write(json_encode($resArray));\n        return $response->withHeader('Content-Type', 'application/json');\n    }\n\n    /**\n     * 下载更新代码包（兼容旧接口 Api/AdminUpdate/download）\n     */\n    public function download(Request $request, Response $response): Response\n    {\n        // 获取登录用户并检查管理员权限\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $adminCheck = $this->checkAdmin($request, $response);\n        if ($adminCheck !== true) {\n            return $adminCheck;\n        }\n\n        set_time_limit(1000);\n        ini_set('memory_limit', '500M');\n\n        $rootPath = dirname(__DIR__, 4);\n        $showdocPath = $rootPath . '/';\n\n        // 从配置中获取数据库路径（与 Database.php 保持一致）\n        $dbPath = \\App\\Common\\Helper\\Env::get('DB_NAME', $showdocPath . 'Sqlite/showdoc.db.php');\n        \n        // 检查数据库文件是否存在，不存在则使用默认路径\n        if (!file_exists($dbPath)) {\n            $dbPath = $showdocPath . 'Sqlite/showdoc.db.php';\n        }\n\n        // 获取当前版本\n        $composerPath = $showdocPath . 'composer.json';\n        if (!file_exists($composerPath)) {\n            return $this->error($response, 10101, 'composer.json 文件不存在');\n        }\n\n        $text = file_get_contents($composerPath);\n        $composer = json_decode($text, true);\n        $version = $composer['version'] ?? '';\n\n        $url = \"https://www.showdoc.cc/server/api/open/checkUpdate\";\n        $res = HttpHelper::post($url, [\"version\" => $version]);\n        $resArray = json_decode($res, true);\n        \n        if (!$resArray || !isset($resArray['data'])) {\n            return $this->error($response, 10101, '检测更新时异常');\n        }\n\n        $newVersion = $resArray['data']['new_version'] ?? '';\n        $fileUrl = $resArray['data']['file_url'] ?? '';\n\n        if (empty($fileUrl)) {\n            return $this->error($response, 10101, '检测更新时异常');\n        }\n\n        $versionNum = str_replace(\"v\", \"\", $newVersion);\n\n        // 进行文件读写权限检查\n        if (\n            !$this->newIsWriteable($showdocPath)\n            || !$this->newIsWriteable($showdocPath . \"Sqlite/\")\n            || !$this->newIsWriteable($showdocPath . \"web/\")\n            || !$this->newIsWriteable($showdocPath . \"web/index.php\")\n            || !$this->newIsWriteable($showdocPath . \"server/\")\n            || !$this->newIsWriteable($showdocPath . \"server/vendor/autoload.php\")\n            || !$this->newIsWriteable($showdocPath . \"server/app/Api\")\n        ) {\n            return $this->error($response, 10101, '请手动给showdoc安装目录下的所有文件可写权限，否则程序无法覆盖旧文件。如自动更新失败，请参考 https://www.showdoc.com.cn/help/13732 手动升级');\n        }\n\n        $tempDir = sys_get_temp_dir() . \"/showdoc_update/\";\n        $zipFile = $tempDir . 'showdoc-' . $versionNum . '.zip';\n\n        if (!is_dir($tempDir)) {\n            if (!mkdir($tempDir, 0755, true)) {\n                return $this->error($response, 10101, '创建临时目录失败，请检查目录权限。如自动更新失败，请参考 https://www.showdoc.com.cn/help/13732 手动升级');\n            }\n        }\n        \n        if (file_exists($zipFile)) {\n            unlink($zipFile);\n        }\n\n        $file = file_get_contents($fileUrl);\n        if ($file === false) {\n            return $this->error($response, 10101, '下载更新文件失败。如自动更新失败，请参考 https://www.showdoc.com.cn/help/13732 手动升级');\n        }\n\n        file_put_contents($zipFile, $file);\n\n        $zip = new \\ZipArchive();\n        $flag = $zip->open($zipFile);\n        if ($flag !== true) {\n            return $this->error($response, 10101, '下载更新压缩包失败。如自动更新失败，请参考 https://www.showdoc.com.cn/help/13732 手动升级');\n        }\n        $zip->extractTo($tempDir);\n        $zip->close();\n\n        $zipFileSubpath = $tempDir . 'showdoc-' . $versionNum . \"/\";\n\n        if (file_exists($zipFileSubpath . 'composer.json') && file_exists($zipFileSubpath . 'web/index.html') && file_exists($zipFileSubpath . 'server/vendor/autoload.php')) {\n            // 移动目录到upload/update\n            $this->copyDir($zipFileSubpath, $showdocPath . 'Public/Uploads/update/');\n            $this->delDir($tempDir);\n            return $this->success($response, []);\n        } else {\n            return $this->error($response, 10101, '下载更新压缩包后，解压的文件缺失。如自动更新失败，请参考 https://www.showdoc.com.cn/help/13732 手动升级');\n        }\n    }\n\n    /**\n     * 执行升级操作，升级覆盖文件（兼容旧接口 Api/AdminUpdate/updateFiles）\n     */\n    public function updateFiles(Request $request, Response $response): Response\n    {\n        // 获取登录用户并检查管理员权限\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $adminCheck = $this->checkAdmin($request, $response);\n        if ($adminCheck !== true) {\n            return $adminCheck;\n        }\n\n        set_time_limit(1000);\n        ini_set('memory_limit', '500M');\n\n        $rootPath = dirname(__DIR__, 4);\n        $showdocPath = $rootPath . '/';\n\n        // 从配置中获取数据库路径（与 Database.php 保持一致）\n        $dbPath = \\App\\Common\\Helper\\Env::get('DB_NAME', $showdocPath . 'Sqlite/showdoc.db.php');\n        \n        // 检查数据库文件是否存在，不存在则使用默认路径\n        if (!file_exists($dbPath)) {\n            $dbPath = $showdocPath . 'Sqlite/showdoc.db.php';\n        }\n\n        // 进行文件读写权限检查\n        if (\n            !$this->newIsWriteable($showdocPath)\n            || !$this->newIsWriteable($showdocPath . \"Sqlite/\")\n            || !$this->newIsWriteable($showdocPath . \"web/\")\n            || !$this->newIsWriteable($showdocPath . \"web/index.php\")\n            || !$this->newIsWriteable($showdocPath . \"server/\")\n            || !$this->newIsWriteable($showdocPath . \"server/vendor/autoload.php\")\n            || !$this->newIsWriteable($showdocPath . \"server/app/Api\")\n        ) {\n            return $this->error($response, 10101, '请手动给showdoc安装目录下的所有文件可写权限，否则程序无法覆盖旧文件。如自动更新失败，请参考 https://www.showdoc.com.cn/help/13732 手动升级');\n        }\n\n        if (file_exists($showdocPath . 'Public/Uploads/update/composer.json') && file_exists($showdocPath . 'Public/Uploads/update/server/vendor/autoload.php')) {\n\n            $text = file_get_contents($showdocPath . \"composer.json\");\n            $composer = json_decode($text, true);\n            $curVersion = $composer['version'] ?? '';\n            $curVersion = str_replace(\"v\", \"\", $curVersion);\n\n            $text = file_get_contents($showdocPath . \"Public/Uploads/update/composer.json\");\n            $composer = json_decode($text, true);\n            $updateVersion = $composer['version'] ?? '';\n            $updateVersion = str_replace(\"v\", \"\", $updateVersion);\n\n            if (version_compare($updateVersion, $curVersion) > 0) {\n                // 复制数据库文件备份\n                $bakName = $dbPath . '.bak.' . date(\"Y-m-d-H-i-s\") . '.php';\n                if (file_exists($dbPath)) {\n                    copy($dbPath, $bakName);\n                }\n\n                // 目录覆盖（完整覆盖所有文件）\n                $this->copyDir($showdocPath . 'Public/Uploads/update/', $showdocPath);\n\n                // 用备份的数据库还原\n                if (file_exists($bakName) && file_exists($dbPath)) {\n                    copy($bakName, $dbPath);\n                }\n\n                $this->delDir($showdocPath . 'Public/Uploads/update/');\n\n                return $this->success($response, []);\n            } else {\n                return $this->error($response, 10101, '版本号显示不需要升级。如自动更新失败，请参考 https://www.showdoc.com.cn/help/13732 手动升级');\n            }\n        } else {\n            return $this->error($response, 10101, '升级文件不存在。如自动更新失败，请参考 https://www.showdoc.com.cn/help/13732 手动升级');\n        }\n    }\n\n    /**\n     * 复制到目录\n     *\n     * @param string $dirsrc 原目录\n     * @param string $dirto 目标目录\n     */\n    private function copyDir($dirsrc, $dirto)\n    {\n        if (file_exists($dirto)) {\n            if (!is_dir($dirto)) {\n                return false;\n            }\n        } else {\n            mkdir($dirto, 0755, true);\n        }\n\n        $dir = opendir($dirsrc);\n        if (!$dir) {\n            return false;\n        }\n\n        while ($filename = readdir($dir)) {\n            if ($filename != \".\" && $filename != \"..\") {\n                $srcfile = $dirsrc . \"/\" . $filename;\n                $tofile = $dirto . \"/\" . $filename;\n\n                if (is_dir($srcfile)) {\n                    $this->copyDir($srcfile, $tofile);\n                } else {\n                    copy($srcfile, $tofile);\n                }\n            }\n        }\n        closedir($dir);\n    }\n\n    /**\n     * 删除文件夹及文件夹下所有的文件\n     *\n     * @param string $dir 目录路径\n     * @return bool\n     */\n    private function delDir($dir)\n    {\n        if (!is_dir($dir)) {\n            return false;\n        }\n\n        $dh = opendir($dir);\n        if (!$dh) {\n            return false;\n        }\n\n        while ($file = readdir($dh)) {\n            if ($file != \".\" && $file != \"..\") {\n                $fullpath = $dir . \"/\" . $file;\n                if (!is_dir($fullpath)) {\n                    unlink($fullpath);\n                } else {\n                    $this->delDir($fullpath);\n                }\n            }\n        }\n        closedir($dh);\n\n        // 删除当前文件夹\n        if (rmdir($dir)) {\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * 判断 文件/目录 是否可写（取代系统自带的 is_writeable 函数）\n     *\n     * @param string $file 文件/目录\n     * @return boolean\n     */\n    private function newIsWriteable($file)\n    {\n        if (is_dir($file)) {\n            $dir = $file;\n            if ($fp = @fopen(\"$dir/test.txt\", 'w')) {\n                @fclose($fp);\n                @unlink(\"$dir/test.txt\");\n                return true;\n            } else {\n                return false;\n            }\n        } else {\n            if ($fp = @fopen($file, 'a+')) {\n                @fclose($fp);\n                return true;\n            } else {\n                return false;\n            }\n        }\n    }\n\n}\n\n"
  },
  {
    "path": "server/app/Api/Controller/AdminUserController.php",
    "content": "<?php\n\nnamespace App\\Api\\Controller;\n\nuse App\\Common\\BaseController;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\nuse App\\Model\\User;\nuse App\\Model\\Item;\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\n/**\n * 管理后台用户相关 Api（开源版）\n */\nclass AdminUserController extends BaseController\n{\n    /**\n     * 获取所有用户列表（兼容旧接口 Api/AdminUser/getList）\n     */\n    public function getList(Request $request, Response $response): Response\n    {\n        // 获取登录用户并检查管理员权限\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $adminCheck = $this->checkAdmin($request, $response);\n        if ($adminCheck !== true) {\n            return $adminCheck;\n        }\n\n        $page = $this->getParam($request, 'page', 1);\n        $count = $this->getParam($request, 'count', 20);\n        $username = $this->getParam($request, 'username', '');\n\n        $query = DB::table('user');\n\n        if (!empty($username)) {\n            $like = $this->safeLike($username);\n            $query->where(function ($q) use ($like) {\n                $q->where('uid', 'like', \"%{$like}%\")\n                    ->orWhere('username', 'like', \"%{$like}%\")\n                    ->orWhere('email', 'like', \"%{$like}%\")\n                    ->orWhere('mobile', 'like', \"%{$like}%\");\n            });\n        }\n\n        $total = $query->count();\n        $users = $query->orderBy('uid', 'desc')\n            ->offset(($page - 1) * $count)\n            ->limit($count)\n            ->get();\n\n        $return = [];\n        $return['total'] = (int) $total;\n        $return['users'] = [];\n\n        if ($users) {\n            foreach ($users as $user) {\n                $userData = (array) $user;\n                $userData['reg_time'] = date(\"Y-m-d H:i:s\", $userData['reg_time']);\n                \n                if ($userData['last_login_time']) {\n                    $userData['last_login_time'] = date(\"Y-m-d H:i:s\", $userData['last_login_time']);\n                } else {\n                    $userData['last_login_time'] = '';\n                }\n\n                $return['users'][] = $userData;\n            }\n        }\n\n        return $this->success($response, $return);\n    }\n\n    /**\n     * 删除用户\n     */\n    public function deleteUser(Request $request, Response $response): Response\n    {\n        // 获取登录用户并检查管理员权限\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $adminCheck = $this->checkAdmin($request, $response);\n        if ($adminCheck !== true) {\n            return $adminCheck;\n        }\n\n        $uid = $this->getParam($request, 'uid', 0);\n        if ($uid <= 0) {\n            return $this->error($response, 10101, '参数错误');\n        }\n\n        // 检查用户是否还有项目\n        $hasItem = DB::table('item')\n            ->where('uid', $uid)\n            ->where('is_del', 0)\n            ->first();\n\n        if ($hasItem) {\n            return $this->error($response, 10101, \"该用户名下还有项目，不允许删除。请先将其项目删除或者重新分配/转让\");\n        }\n\n        $result = User::deleteUser($uid);\n        if (!$result) {\n            return $this->error($response, 10101, '删除失败');\n        }\n\n        return $this->success($response, []);\n    }\n\n    /**\n     * 修改密码\n     */\n    public function changePassword(Request $request, Response $response): Response\n    {\n        // 获取登录用户并检查管理员权限\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $adminCheck = $this->checkAdmin($request, $response);\n        if ($adminCheck !== true) {\n            return $adminCheck;\n        }\n\n        $uid = $this->getParam($request, 'uid', 0);\n        $newPassword = $this->getParam($request, 'new_password', '');\n\n        if ($uid <= 0 || empty($newPassword)) {\n            return $this->error($response, 10101, '参数错误');\n        }\n\n        $result = User::updatePwd($uid, $newPassword);\n        if (!$result) {\n            return $this->error($response, 10101, '修改失败');\n        }\n\n        return $this->success($response, []);\n    }\n\n    /**\n     * 新增用户\n     */\n    public function addUser(Request $request, Response $response): Response\n    {\n        // 获取登录用户并检查管理员权限\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $adminCheck = $this->checkAdmin($request, $response);\n        if ($adminCheck !== true) {\n            return $adminCheck;\n        }\n\n        $username = $this->getParam($request, 'username', '');\n        $password = $this->getParam($request, 'password', '');\n        $uid = $this->getParam($request, 'uid', 0);\n        $name = $this->getParam($request, 'name', '');\n\n        if (empty($username)) {\n            return $this->error($response, 10101, '用户名不允许为空');\n        }\n\n        if ($uid) {\n            // 更新用户\n            if ($password) {\n                User::updatePwd($uid, $password);\n            }\n            if ($name) {\n                DB::table('user')->where('uid', $uid)->update(['name' => $name]);\n            }\n            return $this->success($response, []);\n        } else {\n            // 新增用户\n            if (User::isExist($username)) {\n                return $this->error($response, 10101, '用户名已存在');\n            }\n\n            $newUid = User::register($username, $password);\n            if (!$newUid) {\n                return $this->error($response, 10101, '注册失败');\n            }\n\n            if ($name) {\n                DB::table('user')->where('uid', $newUid)->update(['name' => $name]);\n            }\n\n            return $this->success($response, []);\n        }\n    }\n}\n\n"
  },
  {
    "path": "server/app/Api/Controller/AiController.php",
    "content": "<?php\n\nnamespace App\\Api\\Controller;\n\nuse App\\Common\\BaseController;\nuse App\\Model\\Item;\nuse App\\Model\\ItemAiConfig;\nuse App\\Model\\AiContentLog;\nuse App\\Model\\Options;\nuse App\\Common\\Helper\\AiHelper;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\n\nclass AiController extends BaseController\n{\n    private $openApiKey = '';\n    private $aiServiceUrl = '';\n    private $aiServiceToken = '';\n\n    public function __construct()\n    {\n        $this->openApiKey = Options::get('open_api_key', '');\n        $this->aiServiceUrl = Options::get('ai_service_url', '');\n        $this->aiServiceToken = Options::get('ai_service_token', '');\n    }\n\n    /**\n     * 检查 AI 知识库功能是否可用\n     *\n     * @param int $itemId 项目ID\n     * @return array 返回 ['enabled' => bool, 'message' => string, 'config' => array]\n     */\n    private function checkAiKnowledgeBaseEnabled(int $itemId): array\n    {\n        // 检查系统级配置：是否配置了 AI 服务地址和 Token\n        if (!$this->aiServiceUrl || !$this->aiServiceToken) {\n            return [\n                'enabled' => false,\n                'message' => 'AI 服务未配置，请联系管理员'\n            ];\n        }\n\n        // 检查项目是否存在\n        $item = Item::findById($itemId);\n        if (!$item) {\n            return [\n                'enabled' => false,\n                'message' => '项目不存在'\n            ];\n        }\n\n        // 检查项目级配置（使用新表）\n        $config = ItemAiConfig::getConfig($itemId);\n        if (empty($config['enabled'])) {\n            return [\n                'enabled' => false,\n                'message' => '当前项目未启用 AI 知识库功能'\n            ];\n        }\n\n        return [\n            'enabled' => true,\n            'message' => '',\n            'config' => $config  // 返回完整配置\n        ];\n    }\n\n    /**\n     * AI 助手（流式输出）\n     */\n    public function create(Request $request, Response $response): Response\n    {\n        $user = [];\n        if ($error = $this->requireLoginUser($request, $response, $user)) {\n            return $error;\n        }\n\n        $uid = (int) ($user['uid'] ?? 0);\n        $content = $this->getParam($request, 'content', '');\n\n        // 对于流式接口，错误也应该以流式格式返回（SSE 格式），而不是 JSON\n        // 这样前端才能正确识别错误\n        if (!$this->openApiKey) {\n            $this->sendStreamError('管理员没有在管理后台配置AI助手认证KEY,因此你无法使用AI功能。请联系管理员');\n            return $response;\n        }\n\n\n        // 流式输出：清除所有输出缓冲区，设置 headers，然后直接输出\n        $this->sendStream($content);\n        exit;\n    }\n\n    /**\n     * 兼容旧接口：Api/Ai/send\n     *\n     * 行为：读取参数 content，复用内部流式输出实现。\n     */\n    public function send(Request $request, Response $response): Response\n    {\n        $content = $this->getParam($request, 'content', '');\n        if ($content === '') {\n            return $this->error($response, 10101, '内容不能为空');\n        }\n\n        // 流式输出（直接输出，不返回 Response）\n        $this->sendStream($content);\n        exit;\n    }\n\n    /**\n     * 以流式格式（SSE）返回错误信息\n     * \n     * 用于流式接口的错误返回，确保前端能正确识别错误\n     * 注意：此方法会直接输出，调用者需要负责 exit\n     * 采用与 sendStream 完全相同的设置方式，确保行为一致\n     * \n     * @param string $message 错误消息\n     * @param int $code 错误码，默认 10101\n     * @return void\n     */\n    private function sendStreamError(string $message, int $code = 10101): void\n    {\n        // 清除所有输出缓冲区，确保直接输出（必须在设置 headers 之前）\n        // 与 sendStream 方法保持一致\n        while (ob_get_level() > 0) {\n            ob_end_clean();\n        }\n\n        // 设置流式输出 headers（必须在任何输出之前）\n        // 与 sendStream 方法保持一致\n        if (!headers_sent()) {\n            header('Content-Type: text/event-stream; charset=utf-8');\n            header('Cache-Control: no-cache');\n            header('X-Accel-Buffering: no');\n        }\n\n        // 禁用输出缓冲（确保数据实时传输）\n        // 与 sendStream 方法保持一致\n        if (function_exists('apache_setenv')) {\n            @apache_setenv('no-gzip', 1);\n        }\n        @ini_set('zlib.output_compression', 0);\n        @ini_set('implicit_flush', 1);\n\n        // 以 SSE 格式输出错误（格式与前端期望的 JSON 格式一致）\n        // 与 sendStream 中的错误输出格式保持一致\n        $errorData = json_encode([\n            'error_code'    => $code,\n            'error_message' => $message,\n        ], JSON_UNESCAPED_UNICODE);\n\n        echo \"data: {$errorData}\\n\\n\";\n\n        // 确保所有输出都被立即发送\n        while (ob_get_level() > 0) {\n            ob_end_flush();\n        }\n        flush();\n    }\n\n    /**\n     * 发送 AI 请求（流式输出，内部实现）\n     *\n     * @param string $content 用户输入内容\n     * @return void\n     */\n    private function sendStream(string $content): void\n    {\n        // 清除所有输出缓冲区，确保直接输出（必须在设置 headers 之前）\n        while (ob_get_level() > 0) {\n            ob_end_clean();\n        }\n\n        // 设置流式输出 headers（必须在任何输出之前）\n        if (!headers_sent()) {\n            header('Content-Type: text/event-stream; charset=utf-8');\n            header('Cache-Control: no-cache');\n            header('X-Accel-Buffering: no');\n        }\n\n        // 禁用输出缓冲（确保数据实时传输）\n        if (function_exists('apache_setenv')) {\n            @apache_setenv('no-gzip', 1);\n        }\n        @ini_set('zlib.output_compression', 0);\n        @ini_set('implicit_flush', 1);\n\n        // 检查连接是否已断开\n        if (connection_aborted()) {\n            return;\n        }\n\n        $aiModelName = Options::get('ai_model_name', 'gpt-4o');\n        $postData = json_encode([\n            'model' => $aiModelName,\n            'messages' => [\n                [\n                    'role' => 'system',\n                    'content' => '你是文档工具 showdoc 的AI助手，主要是职责是协助用户生成各种各样的文档/代码/文案，提高用户的写作效率。用户提出要求，你应该帮助用户生成文字。如果用户不懂，你可以引导用户怎么使用怎么提问，或者让用户点击当前网页左下角的帮助说明链接查看一些使用例子',\n                ],\n                [\n                    'role' => 'user',\n                    'content' => $content,\n                ],\n            ],\n            'stream' => true,\n        ]);\n\n        $openApiHost = Options::get('open_api_host', 'https://api.openai.com');\n        if (!strstr($openApiHost, 'http')) {\n            $openApiHost = 'https://' . $openApiHost;\n        }\n        if (substr($openApiHost, -1) === '/') {\n            $openApiHost = substr($openApiHost, 0, -1);\n        }\n\n        // 参考 https://github.com/dirk1983/chatgpt/blob/main/stream.php\n        $callback = function ($ch, $data) {\n            // 检查连接是否已断开\n            if (connection_aborted()) {\n                return -1; // 返回-1会中断curl执行\n            }\n\n            // 如果数据为空，直接返回\n            if (empty($data)) {\n                return strlen($data);\n            }\n\n            // 尝试解析 JSON 以检测错误（但不阻塞正常流式数据）\n            // 注意：流式数据可能是分块的，所以不能完全依赖 JSON 解析\n            $complete = @json_decode($data, true);\n            if ($complete !== null && isset($complete['error'])) {\n                // 检测到错误信息，统一格式输出\n                $errorCode = $complete['error']['code'] ?? '';\n                $errorMessage = $complete['error']['message'] ?? '';\n\n                // 特殊错误码处理\n                if (strpos($errorMessage, 'Rate limit reached') === 0) {\n                    $errorCode = 'rate_limit_reached';\n                }\n                if (strpos($errorMessage, 'Your access was terminated') === 0) {\n                    $errorCode = 'access_terminated';\n                }\n                if (strpos($errorMessage, \"You didn't provide an API key\") === 0) {\n                    $errorCode = 'no_api_key';\n                }\n                if (strpos($errorMessage, 'You exceeded your current quota') === 0) {\n                    $errorCode = 'insufficient_quota';\n                }\n                if (strpos($errorMessage, 'That model is currently overloaded') === 0) {\n                    $errorCode = 'model_overloaded';\n                }\n\n                // 输出错误信息（SSE 格式）\n                $errorData = json_encode(['error' => ['code' => $errorCode, 'message' => $errorMessage]], JSON_UNESCAPED_UNICODE);\n                echo \"data: {$errorData}\\n\\n\";\n            } else {\n                // 正常数据直接输出（保持原始格式，不做任何处理）\n                // 这样确保流式数据能实时传输\n                echo $data;\n            }\n\n            // 立即刷新输出，确保数据实时传输\n            flush();\n\n            return strlen($data);\n        };\n\n        $curl = curl_init();\n        curl_setopt($curl, CURLOPT_ENCODING, '');\n        curl_setopt($curl, CURLOPT_URL, $openApiHost . '/v1/chat/completions');\n        curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);\n\n        // 设置合理的超时时间\n        curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 30);\n        curl_setopt($curl, CURLOPT_TIMEOUT, 480);\n\n        // 关键：防止连接复用，确保每次请求都是独立的\n        curl_setopt($curl, CURLOPT_FRESH_CONNECT, true);\n        curl_setopt($curl, CURLOPT_FORBID_REUSE, true);\n\n        // 注意：使用 CURLOPT_WRITEFUNCTION 时，不能设置 CURLOPT_RETURNTRANSFER\n        // 因为 CURLOPT_RETURNTRANSFER 会让 curl 返回数据而不是通过回调输出\n        curl_setopt($curl, CURLOPT_RETURNTRANSFER, false);\n        curl_setopt($curl, CURLOPT_POST, 1);\n        curl_setopt($curl, CURLOPT_POSTFIELDS, $postData);\n        curl_setopt($curl, CURLOPT_WRITEFUNCTION, $callback);\n        curl_setopt(\n            $curl,\n            CURLOPT_HTTPHEADER,\n            [\n                'Content-Type: application/json',\n                \"Authorization: Bearer {$this->openApiKey}\",\n                'Content-Length: ' . strlen($postData)\n            ]\n        );\n        curl_setopt($curl, CURLOPT_MAXREDIRS, 3);\n        curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);\n        curl_setopt($curl, CURLOPT_AUTOREFERER, true);\n\n        $result = curl_exec($curl);\n\n        // 检查curl执行结果\n        if ($result === false) {\n            $error = curl_error($curl);\n            $errno = curl_errno($curl);\n            curl_close($curl);\n\n            // 返回错误信息（直接输出）\n            $errorData = json_encode(['error' => '网络请求失败: ' . $error], JSON_UNESCAPED_UNICODE);\n            echo \"data: {$errorData}\\n\\n\";\n            flush();\n            return;\n        }\n\n        curl_close($curl);\n    }\n\n    /**\n     * 知识库对话接口\n     */\n    public function chat(Request $request, Response $response): Response\n    {\n        $itemId = $this->getParam($request, 'item_id', 0);\n        $question = $this->getParam($request, 'question', '');\n        $conversationId = $this->getParam($request, 'conversation_id', '');\n        $stream = $this->getParam($request, 'stream', 1);\n\n        // 对于流式输出，需要特殊处理错误，不能使用 sendError\n        if ($stream == 1) {\n            if (!$itemId) {\n                $this->sendStreamError('项目ID不能为空');\n                return $response;\n            }\n\n            if (!$question) {\n                $this->sendStreamError('问题不能为空');\n                return $response;\n            }\n\n            // 检查登录状态（允许游客访问公开项目）\n            $loginUser = [];\n            $uid = 0;\n            $this->requireUserFromToken($request, $response, $uid, false);\n            if ($uid > 0) {\n                $user = \\App\\Model\\User::findById($uid);\n                if ($user) {\n                    $loginUser = (array) $user;\n                }\n            }\n\n            // 检查项目访问权限\n            if (!$this->checkItemVisit($uid, $itemId)) {\n                $this->sendStreamError('您没有访问该项目的权限');\n                return $response;\n            }\n\n            // 检查 AI 知识库功能是否可用\n            $aiCheck = $this->checkAiKnowledgeBaseEnabled($itemId);\n            if (!$aiCheck['enabled']) {\n                $this->sendStreamError($aiCheck['message']);\n                return $response;\n            }\n\n            // 调用 AI 服务（流式返回）\n            // 注意：必须在所有验证通过后再进行流式输出\n            $url = rtrim($this->aiServiceUrl, '/') . '/api/chat/stream';\n            $postData = [\n                'item_id' => $itemId,\n                'user_id' => $uid,\n                'question' => $question\n            ];\n            if ($conversationId) {\n                $postData['conversation_id'] = $conversationId;\n            }\n\n            // 清除所有输出缓冲区，设置 headers，然后直接输出\n            while (ob_get_level() > 0) {\n                ob_end_clean();\n            }\n\n            if (!headers_sent()) {\n                header('Content-Type: text/event-stream; charset=utf-8');\n                header('Cache-Control: no-cache');\n                header('X-Accel-Buffering: no');\n            }\n\n            // 禁用输出缓冲（确保数据实时传输）\n            if (function_exists('apache_setenv')) {\n                @apache_setenv('no-gzip', 1);\n            }\n            @ini_set('zlib.output_compression', 0);\n            @ini_set('implicit_flush', 1);\n\n            // 调用 AI 服务并直接输出流式数据\n            AiHelper::callServiceStream($url, $postData, $this->aiServiceToken);\n            exit;\n        } else {\n            // 非流式输出使用正常的错误处理\n            if (!$itemId) {\n                return $this->error($response, 10101, '项目ID不能为空');\n            }\n\n            if (!$question) {\n                return $this->error($response, 10101, '问题不能为空');\n            }\n\n            // 检查登录状态（允许游客访问公开项目）\n            $loginUser = [];\n            $uid = 0;\n            $this->requireUserFromToken($request, $response, $uid, false);\n            if ($uid > 0) {\n                $user = \\App\\Model\\User::findById($uid);\n                if ($user) {\n                    $loginUser = (array) $user;\n                }\n            }\n\n            // 检查项目访问权限\n            if (!$this->checkItemVisit($uid, $itemId)) {\n                return $this->error($response, 10303, '您没有访问该项目的权限');\n            }\n\n            // 检查 AI 知识库功能是否可用\n            $aiCheck = $this->checkAiKnowledgeBaseEnabled($itemId);\n            if (!$aiCheck['enabled']) {\n                return $this->error($response, 10101, $aiCheck['message']);\n            }\n\n            // 调用 AI 服务（非流式返回）\n            $url = rtrim($this->aiServiceUrl, '/') . '/api/chat';\n            $postData = [\n                'item_id' => $itemId,\n                'user_id' => $uid,\n                'question' => $question\n            ];\n            if ($conversationId) {\n                $postData['conversation_id'] = $conversationId;\n            }\n\n            $result = AiHelper::callService($url, $postData, $this->aiServiceToken, 'POST', 30);\n            if ($result === false) {\n                return $this->error($response, 10101, 'AI 服务调用失败');\n            }\n\n            return $this->success($response, $result);\n        }\n    }\n\n    /**\n     * 获取索引状态\n     */\n    public function getIndexStatus(Request $request, Response $response): Response\n    {\n        $itemId = $this->getParam($request, 'item_id', 0);\n        if (!$itemId) {\n            return $this->error($response, 10101, '项目ID不能为空');\n        }\n\n        // 检查登录状态（允许游客访问公开项目）\n        $loginUser = [];\n        $uid = 0;\n        $this->requireUserFromToken($request, $response, $uid, false);\n        if ($uid > 0) {\n            $user = \\App\\Model\\User::findById($uid);\n            if ($user) {\n                $loginUser = (array) $user;\n            }\n        }\n\n        // 检查项目访问权限\n        if (!$this->checkItemVisit($uid, $itemId)) {\n            return $this->error($response, 10303, '您没有访问该项目的权限');\n        }\n\n        // 检查 AI 知识库功能是否可用\n        $aiCheck = $this->checkAiKnowledgeBaseEnabled($itemId);\n        if (!$aiCheck['enabled']) {\n            return $this->success($response, [\n                'status' => 'not_configured',\n                'message' => $aiCheck['message']\n            ]);\n        }\n\n        // 调用 AI 服务获取索引状态\n        $url = rtrim($this->aiServiceUrl, '/') . '/api/index/status?item_id=' . $itemId;\n        $result = AiHelper::callService($url, null, $this->aiServiceToken, 'GET', 30);\n\n        if ($result === false) {\n            // 返回错误状态，但不使用 sendError，而是返回状态信息\n            return $this->success($response, [\n                'status' => 'error',\n                'message' => '无法连接到 AI 服务，请检查服务地址和网络连接'\n            ]);\n        }\n\n        // 如果 AI 服务返回了错误信息，也要正确处理\n        if (isset($result['error_code']) && $result['error_code'] != 0) {\n            return $this->success($response, [\n                'status' => 'error',\n                'message' => $result['error_message'] ?? '获取索引状态失败'\n            ]);\n        }\n\n        // 转换 AI 服务返回的数据格式为前端期望的格式\n        $responseData = [\n            'status' => $result['status'] ?? (isset($result['indexed']) && $result['indexed'] ? 'indexed' : 'unknown'),\n            'document_count' => isset($result['document_count']) ? (int) $result['document_count'] : 0,\n            'last_update_time' => $result['last_update_time'] ?? null\n        ];\n\n        return $this->success($response, $responseData);\n    }\n\n    /**\n     * 重新索引项目\n     */\n    public function rebuildIndex(Request $request, Response $response): Response\n    {\n        $user = [];\n        if ($error = $this->requireLoginUser($request, $response, $user)) {\n            return $error;\n        }\n\n        $uid = (int) ($user['uid'] ?? 0);\n        $itemId = $this->getParam($request, 'item_id', 0);\n\n        if (!$itemId) {\n            return $this->error($response, 10101, '项目ID不能为空');\n        }\n\n        // 检查项目管理权限\n        if (!$this->checkItemManage($uid, $itemId)) {\n            return $this->error($response, 10101, '您没有管理该项目的权限');\n        }\n\n        // 检查 AI 知识库功能是否可用\n        $aiCheck = $this->checkAiKnowledgeBaseEnabled($itemId);\n        if (!$aiCheck['enabled']) {\n            return $this->error($response, 10101, $aiCheck['message']);\n        }\n\n        $result = AiHelper::rebuild($itemId, $this->aiServiceUrl, $this->aiServiceToken);\n        if ($result === false) {\n            return $this->error($response, 10101, '重新索引失败');\n        }\n\n        return $this->success($response, $result);\n    }\n}\n"
  },
  {
    "path": "server/app/Api/Controller/AiTokenController.php",
    "content": "<?php\n\nnamespace App\\Api\\Controller;\n\nuse App\\Common\\BaseController;\nuse App\\Model\\UserAiToken;\nuse App\\Model\\Item;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\n\n/**\n * AI Token 管理控制器\n * \n * 用于用户管理自己的 AI 访问 Token\n */\nclass AiTokenController extends BaseController\n{\n  /**\n   * 获取用户的 Token 列表\n   *\n   * @param Request $request 请求对象\n   * @param Response $response 响应对象\n   * @return Response\n   */\n  public function list(Request $request, Response $response): Response\n  {\n    // 获取当前用户\n    $user = [];\n    if ($error = $this->requireLoginUser($request, $response, $user)) {\n      return $error;\n    }\n\n    $uid = (int) $user['uid'];\n    $tokens = UserAiToken::getTokensByUid($uid);\n\n    return $this->success($response, [\n      'tokens' => $tokens,\n      'total' => count($tokens),\n    ]);\n  }\n\n  /**\n   * 获取单个 Token 详情\n   *\n   * @param Request $request 请求对象\n   * @param Response $response 响应对象\n   * @return Response\n   */\n  public function detail(Request $request, Response $response): Response\n  {\n    // 获取当前用户\n    $user = [];\n    if ($error = $this->requireLoginUser($request, $response, $user)) {\n      return $error;\n    }\n\n    $uid = (int) $user['uid'];\n    $id = (int) $this->getParam($request, 'id', 0);\n\n    if ($id <= 0) {\n      return $this->error($response, 10101, 'Token ID 不能为空');\n    }\n\n    $token = UserAiToken::getTokenById($id, $uid);\n    if (!$token) {\n      return $this->error($response, 10101, 'Token 不存在');\n    }\n\n    // 隐藏部分 Token\n    $token['token_preview'] = UserAiToken::maskToken($token['token']);\n    unset($token['token']);\n\n    // 获取允许访问的项目名称\n    if ($token['scope'] === 'selected' && !empty($token['allowed_items'])) {\n      $allowedIds = json_decode($token['allowed_items'], true) ?: [];\n      if (!empty($allowedIds)) {\n        $items = \\Illuminate\\Database\\Capsule\\Manager::table('item')\n          ->whereIn('item_id', $allowedIds)\n          ->where('is_del', 0)\n          ->get(['item_id', 'item_name'])\n          ->all();\n        $token['allowed_items_detail'] = array_map(function ($item) {\n          return [\n            'item_id' => (int) $item->item_id,\n            'item_name' => $item->item_name,\n          ];\n        }, $items);\n      }\n    }\n\n    return $this->success($response, $token);\n  }\n\n  /**\n   * 创建新 Token\n   *\n   * @param Request $request 请求对象\n   * @param Response $response 响应对象\n   * @return Response\n   */\n  public function create(Request $request, Response $response): Response\n  {\n    // 获取当前用户\n    $user = [];\n    if ($error = $this->requireLoginUser($request, $response, $user)) {\n      return $error;\n    }\n\n    $uid = (int) $user['uid'];\n\n    // 获取参数\n    $name = trim($this->getParam($request, 'name', ''));\n    $permission = $this->getParam($request, 'permission', 'write');\n    $scope = $this->getParam($request, 'scope', 'all');\n    $allowedItemsRaw = $this->getParam($request, 'allowed_items', '');\n    $canCreateItem = $this->getParam($request, 'can_create_item', 1);\n    $canDeleteItem = $this->getParam($request, 'can_delete_item', 0);\n    $autoAddCreatedItem = $this->getParam($request, 'auto_add_created_item', 1);\n    $expiresAt = trim($this->getParam($request, 'expires_at', ''));\n\n    // 解析 allowed_items：支持逗号分隔字符串或数组\n    $allowedItems = [];\n    if (is_string($allowedItemsRaw) && $allowedItemsRaw !== '') {\n      $allowedItems = array_map('intval', array_filter(explode(',', $allowedItemsRaw)));\n    } elseif (is_array($allowedItemsRaw)) {\n      $allowedItems = array_map('intval', array_filter($allowedItemsRaw));\n    }\n\n    // 验证参数\n    if (!in_array($permission, ['read', 'write'])) {\n      return $this->error($response, 10101, '权限类型无效');\n    }\n\n    if (!in_array($scope, ['all', 'selected'])) {\n      return $this->error($response, 10101, '范围类型无效');\n    }\n\n    if ($scope === 'selected' && empty($allowedItems)) {\n      return $this->error($response, 10101, '指定项目范围时必须选择至少一个项目');\n    }\n\n    // 验证过期时间\n    if ($expiresAt !== '' && strtotime($expiresAt) === false) {\n      return $this->error($response, 10101, '过期时间格式无效');\n    }\n\n    // 创建 Token\n    $options = [\n      'name' => $name ?: 'AI Token',\n      'permission' => $permission,\n      'scope' => $scope,\n      'allowed_items' => is_array($allowedItems) ? $allowedItems : [],\n      'can_create_item' => (int) $canCreateItem,\n      'can_delete_item' => (int) $canDeleteItem,\n      'auto_add_created_item' => (int) $autoAddCreatedItem,\n      'expires_at' => $expiresAt !== '' ? $expiresAt : null,\n    ];\n\n    $token = UserAiToken::createToken($uid, $options);\n\n    if (!$token) {\n      return $this->error($response, 10101, 'Token 创建失败');\n    }\n\n    return $this->success($response, [\n      'token' => $token,\n      'message' => 'Token 创建成功，请妥善保管',\n    ]);\n  }\n\n  /**\n   * 更新 Token\n   *\n   * @param Request $request 请求对象\n   * @param Response $response 响应对象\n   * @return Response\n   */\n  public function update(Request $request, Response $response): Response\n  {\n    // 获取当前用户\n    $user = [];\n    if ($error = $this->requireLoginUser($request, $response, $user)) {\n      return $error;\n    }\n\n    $uid = (int) $user['uid'];\n    $id = (int) $this->getParam($request, 'id', 0);\n\n    if ($id <= 0) {\n      return $this->error($response, 10101, 'Token ID 不能为空');\n    }\n\n    // 检查 Token 是否存在\n    $existingToken = UserAiToken::getTokenById($id, $uid);\n    if (!$existingToken) {\n      return $this->error($response, 10101, 'Token 不存在');\n    }\n\n    // 准备更新数据\n    $updateData = [];\n\n    $name = $this->getParam($request, 'name', null);\n    if ($name !== null) {\n      $updateData['name'] = trim($name);\n    }\n\n    $permission = $this->getParam($request, 'permission', null);\n    if ($permission !== null && in_array($permission, ['read', 'write'])) {\n      $updateData['permission'] = $permission;\n    }\n\n    $scope = $this->getParam($request, 'scope', null);\n    if ($scope !== null && in_array($scope, ['all', 'selected'])) {\n      $updateData['scope'] = $scope;\n    }\n\n    $allowedItemsRaw = $this->getParam($request, 'allowed_items', null);\n    if ($allowedItemsRaw !== null) {\n      // 解析 allowed_items：支持逗号分隔字符串或数组\n      $allowedItems = [];\n      if (is_string($allowedItemsRaw) && $allowedItemsRaw !== '') {\n        $allowedItems = array_map('intval', array_filter(explode(',', $allowedItemsRaw)));\n      } elseif (is_array($allowedItemsRaw)) {\n        $allowedItems = array_map('intval', array_filter($allowedItemsRaw));\n      }\n      $updateData['allowed_items'] = $allowedItems;\n    }\n\n    $canCreateItem = $this->getParam($request, 'can_create_item', null);\n    if ($canCreateItem !== null) {\n      $updateData['can_create_item'] = (int) $canCreateItem;\n    }\n\n    $canDeleteItem = $this->getParam($request, 'can_delete_item', null);\n    if ($canDeleteItem !== null) {\n      $updateData['can_delete_item'] = (int) $canDeleteItem;\n    }\n\n    $autoAddCreatedItem = $this->getParam($request, 'auto_add_created_item', null);\n    if ($autoAddCreatedItem !== null) {\n      $updateData['auto_add_created_item'] = (int) $autoAddCreatedItem;\n    }\n\n    $expiresAt = $this->getParam($request, 'expires_at', null);\n    if ($expiresAt !== null) {\n      if ($expiresAt !== '' && strtotime($expiresAt) === false) {\n        return $this->error($response, 10101, '过期时间格式无效');\n      }\n      $updateData['expires_at'] = $expiresAt !== '' ? $expiresAt : null;\n    }\n\n    if (empty($updateData)) {\n      return $this->error($response, 10101, '没有需要更新的内容');\n    }\n\n    $ok = UserAiToken::updateToken($id, $uid, $updateData);\n\n    if (!$ok) {\n      return $this->error($response, 10101, 'Token 更新失败');\n    }\n\n    return $this->success($response, [\n      'message' => 'Token 更新成功',\n    ]);\n  }\n\n  /**\n   * 重置 Token（生成新的 Token 字符串）\n   *\n   * @param Request $request 请求对象\n   * @param Response $response 响应对象\n   * @return Response\n   */\n  public function reset(Request $request, Response $response): Response\n  {\n    // 获取当前用户\n    $user = [];\n    if ($error = $this->requireLoginUser($request, $response, $user)) {\n      return $error;\n    }\n\n    $uid = (int) $user['uid'];\n    $id = (int) $this->getParam($request, 'id', 0);\n\n    if ($id <= 0) {\n      return $this->error($response, 10101, 'Token ID 不能为空');\n    }\n\n    $newToken = UserAiToken::resetToken($id, $uid);\n\n    if (!$newToken) {\n      return $this->error($response, 10101, 'Token 重置失败');\n    }\n\n    return $this->success($response, [\n      'token' => $newToken,\n      'message' => 'Token 已重置，请妥善保管新 Token',\n    ]);\n  }\n\n  /**\n   * 撤销 Token\n   *\n   * @param Request $request 请求对象\n   * @param Response $response 响应对象\n   * @return Response\n   */\n  public function revoke(Request $request, Response $response): Response\n  {\n    // 获取当前用户\n    $user = [];\n    if ($error = $this->requireLoginUser($request, $response, $user)) {\n      return $error;\n    }\n\n    $uid = (int) $user['uid'];\n    $id = (int) $this->getParam($request, 'id', 0);\n\n    if ($id <= 0) {\n      return $this->error($response, 10101, 'Token ID 不能为空');\n    }\n\n    $ok = UserAiToken::revokeToken($id, $uid);\n\n    if (!$ok) {\n      return $this->error($response, 10101, 'Token 撤销失败');\n    }\n\n    return $this->success($response, [\n      'message' => 'Token 已撤销',\n    ]);\n  }\n\n  /**\n   * 删除 Token\n   *\n   * @param Request $request 请求对象\n   * @param Response $response 响应对象\n   * @return Response\n   */\n  public function delete(Request $request, Response $response): Response\n  {\n    // 获取当前用户\n    $user = [];\n    if ($error = $this->requireLoginUser($request, $response, $user)) {\n      return $error;\n    }\n\n    $uid = (int) $user['uid'];\n    $id = (int) $this->getParam($request, 'id', 0);\n\n    if ($id <= 0) {\n      return $this->error($response, 10101, 'Token ID 不能为空');\n    }\n\n    $ok = UserAiToken::deleteToken($id, $uid);\n\n    if (!$ok) {\n      return $this->error($response, 10101, 'Token 删除失败');\n    }\n\n    return $this->success($response, [\n      'message' => 'Token 已删除',\n    ]);\n  }\n\n  /**\n   * 获取用户可选的项目列表（用于 Token 配置）\n   *\n   * @param Request $request 请求对象\n   * @param Response $response 响应对象\n   * @return Response\n   */\n  public function availableItems(Request $request, Response $response): Response\n  {\n    // 获取当前用户\n    $user = [];\n    if ($error = $this->requireLoginUser($request, $response, $user)) {\n      return $error;\n    }\n\n    $uid = (int) $user['uid'];\n\n    // 获取用户创建的项目\n    $createdItems = \\Illuminate\\Database\\Capsule\\Manager::table('item')\n      ->where('uid', $uid)\n      ->where('is_del', 0)\n      ->get(['item_id', 'item_name'])\n      ->all();\n\n    // 获取用户作为成员的项目\n    $memberItems = \\Illuminate\\Database\\Capsule\\Manager::table('item_member')\n      ->join('item', 'item_member.item_id', '=', 'item.item_id')\n      ->where('item_member.uid', $uid)\n      ->where('item.is_del', 0)\n      ->select('item.item_id', 'item.item_name')\n      ->get()\n      ->all();\n\n    // 获取用户所在团队的项目\n    $teamItems = \\Illuminate\\Database\\Capsule\\Manager::table('team_item_member')\n      ->join('item', 'team_item_member.item_id', '=', 'item.item_id')\n      ->where('team_item_member.member_uid', $uid)\n      ->where('item.is_del', 0)\n      ->select('item.item_id', 'item.item_name')\n      ->get()\n      ->all();\n\n    // 合并并去重\n    $itemsMap = [];\n    foreach (array_merge($createdItems, $memberItems, $teamItems) as $item) {\n      $itemsMap[$item->item_id] = [\n        'item_id' => (int) $item->item_id,\n        'item_name' => $item->item_name,\n      ];\n    }\n\n    return $this->success($response, [\n      'items' => array_values($itemsMap),\n      'total' => count($itemsMap),\n    ]);\n  }\n}\n"
  },
  {
    "path": "server/app/Api/Controller/AttachmentController.php",
    "content": "<?php\n\nnamespace App\\Api\\Controller;\n\nuse App\\Common\\BaseController;\nuse App\\Common\\Helper\\UrlHelper;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\n/**\n * 附件相关 Api（新架构）。\n *\n * 注意：文件上传功能需要依赖 OSS（七牛云）配置，部分功能可能需要进一步实现。\n */\nclass AttachmentController extends BaseController\n{\n    /**\n     * 默认入口/兼容接口（兼容旧接口 Api/Attachment/index）。\n     *\n     * 说明：旧实现主要用于占位，这里简单返回成功，以便旧客户端探活。\n     */\n    public function index(Request $request, Response $response): Response\n    {\n        return $this->success($response, ['status' => 'ok']);\n    }\n\n    /**\n     * 设置大文件上传支持\n     */\n    private function setLargeFileUploadSupport(): void\n    {\n        // 设置上传文件大小限制为 500MB\n        ini_set('upload_max_filesize', '500M');\n        ini_set('post_max_size', '500M');\n\n        // 设置内存限制为 512MB\n        ini_set('memory_limit', '512M');\n\n        // 设置最大执行时间为 300 秒（5分钟）\n        ini_set('max_execution_time', 300);\n\n        // 设置输入时间限制为 300 秒\n        ini_set('max_input_time', 300);\n    }\n\n    /**\n     * 浏览附件（兼容旧接口 Api/Attachment/visitFile）。\n     *\n     * 功能：\n     * - 根据 sign 查找文件\n     * - 微信浏览器 APK 文件特殊处理\n     * - 更新访问次数和记录流量\n     * - 访问/下载行为与旧版开源 AttachmentController::visitFile 完全一致：\n     *   - 先选 cache_url，否则用 real_url；\n     *   - 根据 oss_open 判断是否使用 OSS；\n     *   - 若 oss_open = 0 且 URL 指向本地 Public/Uploads，且为“非图片/非常见文档”并且有 display_name，则做本地下载（Content-Disposition: attachment 输出文件内容）；\n     *   - 其他情况直接 302 跳转到 URL。\n     */\n    public function visitFile(Request $request, Response $response): Response\n    {\n        $sign = $this->getParam($request, 'sign', '');\n        $imageView2 = $this->getParam($request, 'imageView2', ''); // 旧版有该参数，但未实际使用，这里保留兼容\n\n        if (empty($sign)) {\n            return $response->withStatus(404)->withBody(new \\Slim\\Psr7\\Stream(fopen('php://temp', 'r+')));\n        }\n\n        $file = \\App\\Model\\UploadFile::findBySign($sign);\n        if (!$file) {\n            $response->getBody()->write('www.showdoc.com.cn');\n            return $response;\n        }\n\n        $fileData = (array) $file;\n        $uid = (int) ($fileData['uid'] ?? 0);\n\n        // 如果是 APK 文件且在微信浏览器中打开\n        $userAgent = $request->getHeaderLine('User-Agent');\n        $realUrl = $fileData['real_url'] ?? '';\n        if (strpos($userAgent, 'MicroMessenger') !== false && strpos($realUrl, '.apk') !== false) {\n            $html = '<head><title>温馨提示</title></head><br><h1>微信不支持直接下载，请点击右上角\"---\"在外部浏览器中打开</h1>';\n            $response->getBody()->write($html);\n            return $response->withHeader('Content-Type', 'text/html; charset=utf-8');\n        }\n\n        // 更新访问次数\n        DB::table('upload_file')\n            ->where('file_id', (int) $fileData['file_id'])\n            ->update([\n                'visit_times'     => (int) ($fileData['visit_times'] ?? 0) + 1,\n                'last_visit_time' => time(),\n            ]);\n\n        // 记录用户流量（开源版保留此功能）\n        \\App\\Model\\Attachment::recordUserFlow($uid, (int) ($fileData['file_size'] ?? 0));\n\n        // 构建下载 URL：优先 cache_url，否则 real_url\n        if (!empty($fileData['cache_url'])) {\n            $url = $fileData['cache_url'];\n        } else {\n            $url = $realUrl;\n        }\n\n        // 本地文件路径解析（与旧版逻辑一致）\n        $array = explode('/Public/Uploads/', $url);\n        $filePath = '';\n        if (count($array) > 1 && !empty($array[1])) {\n            // 旧版使用 ../Public/Uploads/，这里根据项目根目录计算真实路径\n            $projectRoot = dirname(__DIR__, 3); // .../showdoc\n            $filePath = $projectRoot . DIRECTORY_SEPARATOR . 'Public' . DIRECTORY_SEPARATOR . 'Uploads' . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $array[1]);\n        }\n\n        // 根据 oss_open 决定是否走本地下载逻辑\n        $ossOpen = (int) \\App\\Model\\Options::get('oss_open', 0);\n        if (\n            $ossOpen === 0 &&\n            $filePath &&\n            is_file($filePath) &&\n            !empty($fileData['display_name']) &&\n            !strstr(strtolower($filePath), '.bmp') &&\n            !strstr(strtolower($filePath), '.jpg') &&\n            !strstr(strtolower($filePath), '.png') &&\n            !strstr(strtolower($filePath), '.pdf') &&\n            !strstr(strtolower($filePath), '.doc') &&\n            !strstr(strtolower($filePath), '.xls') &&\n            !strstr(strtolower($filePath), '.ppt')\n        ) {\n            // 本地下载逻辑：设置 Content-Disposition: attachment 输出文件内容\n            return $this->downloadLocalFile($filePath, (string) $fileData['display_name'], $response);\n        }\n\n        // 其他情况直接 302 跳转到 URL（与旧版一致）\n        return $response->withStatus(302)->withHeader('Location', $url);\n    }\n\n    /**\n     * 上传图片（兼容旧接口 Api/Attachment/uploadImg）。\n     *\n     * 使用 Attachment::upload() 方法，通过 OssHelper 上传到七牛云，不依赖 ThinkPHP。\n     */\n    public function uploadImg(Request $request, Response $response): Response\n    {\n        $this->setLargeFileUploadSupport();\n\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n        $itemId = $this->getParam($request, 'item_id', 0);\n        $pageId = $this->getParam($request, 'page_id', 0);\n\n        // 检查文件是否存在\n        $uploadedFiles = $request->getUploadedFiles();\n        if (empty($uploadedFiles['editormd-image-file'])) {\n            return $this->json($response, ['message' => '未找到上传文件', 'success' => 0]);\n        }\n\n        $uploadedFile = $uploadedFiles['editormd-image-file'];\n\n        // 处理 blob 文件名\n        $originalName = $uploadedFile->getClientFilename();\n        if ($originalName === 'blob') {\n            $originalName = 'blob.jpg';\n        }\n\n        // 检查文件扩展名\n        $checkFilename = true;\n        $user = \\App\\Model\\User::findById($uid);\n        if ($user && (int) ($user->groupid ?? 0) === 1) {\n            $checkFilename = false; // 管理员不检查\n        }\n\n        if ($checkFilename && !\\App\\Model\\Attachment::isAllowedFilename($originalName)) {\n            return $this->json($response, ['message' => '不支持上传该文件类型。可将文件压缩成 zip/rar 等压缩包后上传，或联系网站管理员', 'success' => 0]);\n        }\n\n        // 创建临时文件\n        $tmpFile = tempnam(sys_get_temp_dir(), 'upload_');\n        $uploadedFile->moveTo($tmpFile);\n\n        // 构建 $_FILES 数组格式（兼容旧接口）\n        $_files = [\n            'editormd-image-file' => [\n                'name' => $originalName,\n                'type' => $uploadedFile->getClientMediaType(),\n                'tmp_name' => $tmpFile,\n                'size' => $uploadedFile->getSize(),\n            ],\n        ];\n\n        // 上传文件\n        $url = \\App\\Model\\Attachment::upload($_files, 'editormd-image-file', $uid, $itemId, $pageId, $checkFilename);\n\n        // 清理临时文件\n        if (file_exists($tmpFile)) {\n            @unlink($tmpFile);\n        }\n\n        if ($url) {\n            return $this->json($response, ['url' => $url, 'success' => 1]);\n        } else {\n            return $this->json($response, ['message' => '上传失败', 'success' => 0]);\n        }\n    }\n\n    /**\n     * 上传附件（兼容旧接口 Api/Attachment/attachmentUpload）。\n     *\n     * 使用 Attachment::upload() 方法，通过 OssHelper 上传到七牛云，不依赖 ThinkPHP。\n     */\n    public function attachmentUpload(Request $request, Response $response): Response\n    {\n        $this->setLargeFileUploadSupport();\n\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n        $itemId = $this->getParam($request, 'item_id', 0);\n        $pageId = $this->getParam($request, 'page_id', 0);\n\n        // 如果附件是要上传绑定到某个页面，那么检验项目权限\n        if ($pageId > 0 || $itemId > 0) {\n            if (!$this->checkItemEdit($uid, $itemId)) {\n                return $this->error($response, 10103, '您没有编辑权限');\n            }\n        }\n\n        // 检查文件是否存在\n        $uploadedFiles = $request->getUploadedFiles();\n        if (empty($uploadedFiles['file'])) {\n            return $this->error($response, 10101, '未找到上传文件');\n        }\n\n        $uploadedFile = $uploadedFiles['file'];\n\n        // 检查文件扩展名\n        $checkFilename = true;\n        $user = \\App\\Model\\User::findById($uid);\n        if ($user && (int) ($user->groupid ?? 0) === 1) {\n            $checkFilename = false; // 管理员不检查\n        }\n\n        $originalName = $uploadedFile->getClientFilename();\n        if ($checkFilename && !\\App\\Model\\Attachment::isAllowedFilename($originalName)) {\n            return $this->error($response, 10101, '不支持上传该文件类型。可将文件压缩成 zip/rar 等压缩包后上传，或联系网站管理员');\n        }\n\n        // 创建临时文件\n        $tmpFile = tempnam(sys_get_temp_dir(), 'upload_');\n        $uploadedFile->moveTo($tmpFile);\n\n        // 构建 $_FILES 数组格式（兼容旧接口）\n        $_files = [\n            'file' => [\n                'name' => $originalName,\n                'type' => $uploadedFile->getClientMediaType(),\n                'tmp_name' => $tmpFile,\n                'size' => $uploadedFile->getSize(),\n            ],\n        ];\n\n        // 上传文件\n        $url = \\App\\Model\\Attachment::upload($_files, 'file', $uid, $itemId, $pageId, $checkFilename);\n\n        // 清理临时文件\n        if (file_exists($tmpFile)) {\n            @unlink($tmpFile);\n        }\n\n        if ($url) {\n            return $this->json($response, ['url' => $url, 'success' => 1]);\n        } else {\n            return $this->error($response, 10101, '上传失败');\n        }\n    }\n\n    /**\n     * 页面的上传附件列表（兼容旧接口 Api/Attachment/pageAttachmentUploadList）。\n     */\n    public function pageAttachmentUploadList(Request $request, Response $response): Response\n    {\n        $itemId = $this->getParam($request, 'item_id', 0);\n        $pageId = $this->getParam($request, 'page_id', 0);\n\n        if ($pageId <= 0) {\n            return $this->error($response, 10103, '请至少先保存一次页面内容');\n        }\n\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        // 获取页面的附件列表\n        $files = \\App\\Model\\FilePage::getPageAttachments($pageId);\n\n        if (!empty($files)) {\n            // 获取第一个文件的 item_id 用于权限检查\n            $firstFile = DB::table('file_page')\n                ->where('page_id', $pageId)\n                ->first();\n            if ($firstFile) {\n                $itemId = (int) ($firstFile->item_id ?? 0);\n                if (!$this->checkItemVisit($uid, $itemId)) {\n                    return $this->error($response, 10103, '您没有访问权限');\n                }\n            }\n        }\n\n        // 构建返回数据\n        $result = [];\n        foreach ($files as $file) {\n            $sign = DB::table('upload_file')\n                ->where('file_id', $file['file_id'])\n                ->value('sign');\n            if ($sign) {\n                $url = UrlHelper::serverUrl('api/attachment/visitFile', ['sign' => $sign]);\n                $result[] = [\n                    'file_id'     => $file['file_id'],\n                    'display_name' => $file['display_name'],\n                    'url'         => $url,\n                    'addtime'     => $file['addtime'],\n                ];\n            }\n        }\n\n        return $this->success($response, $result);\n    }\n\n    /**\n     * 删除页面中已上传文件（兼容旧接口 Api/Attachment/deletePageUploadFile）。\n     */\n    public function deletePageUploadFile(Request $request, Response $response): Response\n    {\n        $fileId = $this->getParam($request, 'file_id', 0);\n        $pageId = $this->getParam($request, 'page_id', 0);\n\n        if ($fileId <= 0 || $pageId <= 0) {\n            return $this->error($response, 10101, '参数错误');\n        }\n\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        // 检查文件关联的页面数量\n        $count = \\App\\Model\\FilePage::getPageCount($fileId);\n        if ($count <= 1) {\n            // 如果只有一个页面关联，则删除整个文件\n            return $this->deleteMyAttachment($request, $response);\n        } else {\n            // 如果有多个页面关联，只删除页面关联\n            $page = DB::table('page')\n                ->where('page_id', $pageId)\n                ->first();\n            if (!$page) {\n                return $this->error($response, 10101, '页面不存在');\n            }\n\n            $itemId = (int) ($page->item_id ?? 0);\n            if (!$this->checkItemEdit($uid, $itemId)) {\n                return $this->error($response, 10103, '您没有编辑权限');\n            }\n\n            $deleted = \\App\\Model\\FilePage::delete($fileId, $pageId);\n            if ($deleted) {\n                return $this->success($response, []);\n            } else {\n                return $this->error($response, 10101, '删除失败');\n            }\n        }\n    }\n\n    /**\n     * 获取全站的附件列表（管理员用）（兼容旧接口 Api/Attachment/getAllList）。\n     */\n    public function getAllList(Request $request, Response $response): Response\n    {\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        // 检查管理员权限\n        $user = \\App\\Model\\User::findById($uid);\n        if (!$user || (int) ($user->groupid ?? 0) !== 1) {\n            return $this->error($response, 10103, '您没有管理员权限');\n        }\n\n        $page = $this->getParam($request, 'page', 1);\n        $count = $this->getParam($request, 'count', 20);\n        $attachmentType = $this->getParam($request, 'attachment_type', 0);\n        $displayName = $this->getParam($request, 'display_name', '');\n        $username = $this->getParam($request, 'username', '');\n\n        $filters = [];\n        if ($attachmentType > 0) {\n            $filters['attachment_type'] = $attachmentType;\n        }\n        if (!empty($displayName)) {\n            $filters['display_name'] = $displayName;\n        }\n        if (!empty($username)) {\n            $filters['username'] = $username;\n        }\n\n        $result = \\App\\Model\\UploadFile::getAllList($filters, $page, $count);\n\n        // 构建返回数据\n        $list = [];\n        foreach ($result['list'] as $file) {\n            $url = UrlHelper::serverUrl('api/attachment/visitFile', ['sign' => $file['sign'] ?? '']);\n            $list[] = [\n                'file_id'        => (int) $file['file_id'],\n                'username'       => $file['username'] ?? '',\n                'uid'            => (int) $file['uid'],\n                'file_type'      => $file['file_type'] ?? '',\n                'visit_times'    => (int) ($file['visit_times'] ?? 0),\n                'file_size'      => (int) ($file['file_size'] ?? 0),\n                'item_id'        => (int) ($file['item_id'] ?? 0),\n                'page_id'        => (int) ($file['page_id'] ?? 0),\n                'file_size_m'    => $file['file_size_m'] ?? 0,\n                'display_name'   => $file['display_name'] ?? '',\n                'url'            => $url,\n                'addtime'        => $file['addtime'],\n                'last_visit_time' => $file['last_visit_time'],\n            ];\n        }\n\n        return $this->success($response, [\n            'list'   => $list,\n            'total'  => $result['total'],\n            'used'   => $result['used'],\n            'used_m' => $result['used_m'],\n        ]);\n    }\n\n    /**\n     * 删除附件（管理员用）（兼容旧接口 Api/Attachment/deleteAttachment）。\n     */\n    public function deleteAttachment(Request $request, Response $response): Response\n    {\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        // 检查管理员权限\n        $user = \\App\\Model\\User::findById($uid);\n        if (!$user || (int) ($user->groupid ?? 0) !== 1) {\n            return $this->error($response, 10103, '您没有管理员权限');\n        }\n\n        $fileId = $this->getParam($request, 'file_id', 0);\n        if ($fileId <= 0) {\n            return $this->error($response, 10101, '参数错误');\n        }\n\n        $deleted = \\App\\Model\\Attachment::deleteFile($fileId);\n        if ($deleted) {\n            return $this->success($response, []);\n        } else {\n            return $this->error($response, 10101, '删除失败');\n        }\n    }\n\n    /**\n     * 获取我的附件列表（兼容旧接口 Api/Attachment/getMyList）。\n     */\n    public function getMyList(Request $request, Response $response): Response\n    {\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        $page = $this->getParam($request, 'page', 1);\n        $count = $this->getParam($request, 'count', 20);\n        $attachmentType = $this->getParam($request, 'attachment_type', 0);\n        $displayName = $this->getParam($request, 'display_name', '');\n\n        $filters = [];\n        if ($attachmentType > 0) {\n            $filters['attachment_type'] = $attachmentType;\n        }\n        if (!empty($displayName)) {\n            $filters['display_name'] = $displayName;\n        }\n\n        $result = \\App\\Model\\UploadFile::getMyList($uid, $filters, $page, $count);\n\n        // 获取本月使用流量\n        $usedFlow = \\App\\Model\\Attachment::getUserFlow($uid);\n        $result['used_flow_m'] = round($usedFlow / (1024 * 1024), 3);\n\n        // 构建返回数据\n        $list = [];\n        foreach ($result['list'] as $file) {\n            // 使用 UrlHelper 生成完整 URL\n            $url = \\App\\Common\\Helper\\UrlHelper::serverUrl('api/attachment/visitFile', ['sign' => $file['sign'] ?? '']);\n            $list[] = [\n                'file_id'        => (int) $file['file_id'],\n                'uid'            => (int) $file['uid'],\n                'file_type'      => $file['file_type'] ?? '',\n                'visit_times'    => (int) ($file['visit_times'] ?? 0),\n                'file_size'      => (int) ($file['file_size'] ?? 0),\n                'item_id'        => (int) ($file['item_id'] ?? 0),\n                'page_id'        => (int) ($file['page_id'] ?? 0),\n                'file_size_m'    => $file['file_size_m'] ?? 0,\n                'display_name'   => $file['display_name'] ?? '',\n                'url'            => $url,\n                'addtime'        => $file['addtime'],\n                'last_visit_time' => $file['last_visit_time'],\n            ];\n        }\n\n        return $this->success($response, [\n            'list'        => $list,\n            'total'       => $result['total'],\n            'used'        => $result['used'],\n            'used_m'      => $result['used_m'],\n            'used_flow_m' => $result['used_flow_m'],\n        ]);\n    }\n\n    /**\n     * 删除附件（我的附件）（兼容旧接口 Api/Attachment/deleteMyAttachment）。\n     */\n    public function deleteMyAttachment(Request $request, Response $response): Response\n    {\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n        $fileId = $this->getParam($request, 'file_id', 0);\n\n        if ($fileId <= 0) {\n            return $this->error($response, 10101, '参数错误');\n        }\n\n        // 检查文件是否属于当前用户\n        $file = \\App\\Model\\UploadFile::findById($fileId);\n        if (!$file || (int) ($file->uid ?? 0) !== $uid) {\n            return $this->error($response, 10101, '文件不存在或无权删除');\n        }\n\n        $deleted = \\App\\Model\\Attachment::deleteFile($fileId);\n        if ($deleted) {\n            return $this->success($response, []);\n        } else {\n            return $this->error($response, 10101, '删除失败');\n        }\n    }\n\n    /**\n     * 将已上传文件绑定到页面中（兼容旧接口 Api/Attachment/bindingPage）。\n     */\n    public function bindingPage(Request $request, Response $response): Response\n    {\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n        $fileId = $this->getParam($request, 'file_id', 0);\n        $pageId = $this->getParam($request, 'page_id', 0);\n\n        if ($fileId <= 0 || $pageId <= 0) {\n            return $this->error($response, 10101, '参数错误');\n        }\n\n        // 检查文件是否属于当前用户\n        $file = \\App\\Model\\UploadFile::findById($fileId);\n        if (!$file || (int) ($file->uid ?? 0) !== $uid) {\n            return $this->error($response, 10101, '文件不存在或无权操作');\n        }\n\n        // 检查页面权限\n        $page = DB::table('page')\n            ->where('page_id', $pageId)\n            ->first();\n        if (!$page) {\n            return $this->error($response, 10101, '页面不存在');\n        }\n\n        $itemId = (int) ($page->item_id ?? 0);\n        if (!$this->checkItemEdit($uid, $itemId)) {\n            return $this->error($response, 10103, '您没有编辑权限');\n        }\n\n        // 添加文件页面关联\n        $id = \\App\\Model\\FilePage::add($fileId, $itemId, $pageId);\n        if ($id > 0) {\n            return $this->success($response, []);\n        } else {\n            return $this->error($response, 10101, '绑定失败');\n        }\n    }\n\n    /**\n     * 管理员：获取未被使用的附件列表（分页）（兼容旧接口 Api/Attachment/getUnusedList）。\n     *\n     * 功能：获取所有附件，通过检查 page.page_content 来判断是否被使用。\n     * 开源版无分表，直接检查 page.page_content。\n     */\n    public function getUnusedList(Request $request, Response $response): Response\n    {\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        // 检查管理员权限\n        $adminCheck = $this->checkAdmin($request, $response);\n        if ($adminCheck !== true) {\n            return $adminCheck;\n        }\n\n        $page = $this->getParam($request, 'page', 1);\n        $count = $this->getParam($request, 'count', 10);\n        $displayName = $this->getParam($request, 'display_name', '');\n        $username = $this->getParam($request, 'username', '');\n\n        // 构建查询条件\n        $where = [];\n        if (!empty($displayName)) {\n            $where[] = ['display_name', 'like', '%' . $displayName . '%'];\n        }\n        if (!empty($username)) {\n            $user = \\App\\Model\\User::findByUsernameOrEmail($username);\n            $targetUid = $user ? (int) $user->uid : -99;\n            $where[] = ['uid', '=', $targetUid];\n        }\n\n        // 获取所有附件\n        $query = DB::table('upload_file');\n        if (!empty($where)) {\n            foreach ($where as $condition) {\n                if (count($condition) === 3) {\n                    $query->where($condition[0], $condition[1], $condition[2]);\n                }\n            }\n        }\n        $candidates = $query->orderBy('addtime', 'desc')->get();\n\n        // 检查哪些附件未被使用\n        $unused = [];\n        if ($candidates) {\n            foreach ($candidates as $value) {\n                $fileId = (int) ($value->file_id ?? 0);\n                $sign = (string) ($value->sign ?? '');\n\n                if (empty($sign)) {\n                    continue;\n                }\n\n                // 在页面内容中进行 like 匹配：sign 是 MD5 加密串，重复率很小，直接搜索即可\n                // 开源版无分表，直接检查 page.page_content\n                $used = DB::table('page')\n                    ->where('is_del', 0)\n                    ->where('page_content', 'like', '%' . $sign . '%')\n                    ->exists();\n\n                if (!$used) {\n                    $unused[] = [\n                        'file_id'      => $fileId,\n                        'display_name' => $value->display_name ?? '',\n                        'file_size'    => (int) ($value->file_size ?? 0),\n                        'file_size_m'  => round((int) ($value->file_size ?? 0) / (1024 * 1024), 3),\n                        'addtime'      => $value->addtime ?? 0,\n                        'username'     => $value->username ?? '',\n                        'uid'          => (int) ($value->uid ?? 0),\n                    ];\n                }\n            }\n        }\n\n        // 分页处理\n        $total = count($unused);\n        $offset = ($page - 1) * $count;\n        $unused = array_slice($unused, $offset, $count);\n\n        return $this->success($response, [\n            'list'  => $unused,\n            'total' => $total,\n        ]);\n    }\n\n    /**\n     * 输出本地文件到浏览器（下载），兼容旧版 _downloadFile 行为。\n     */\n    private function downloadLocalFile(string $filename, string $rename, Response $response): Response\n    {\n        if (!is_file($filename) || !is_readable($filename)) {\n            $response->getBody()->write('File not found');\n            return $response->withStatus(404);\n        }\n\n        // 设置脚本的最大执行时间，设置为0则无时间限制\n        @set_time_limit(3000);\n        @ini_set('max_execution_time', '0');\n\n        $filesize = filesize($filename);\n        $handle = fopen($filename, 'rb');\n        if ($handle === false) {\n            $response->getBody()->write('File not readable');\n            return $response->withStatus(500);\n        }\n\n        $stream = new \\Slim\\Psr7\\Stream($handle);\n\n        return $response\n            ->withBody($stream)\n            ->withHeader('Content-Type', 'application/octet-stream')\n            ->withHeader('Accept-Ranges', 'bytes')\n            ->withHeader('Accept-Length', (string) $filesize)\n            ->withHeader('Content-Disposition', 'attachment;filename=' . basename($rename));\n    }\n\n    /**\n     * 管理员：批量删除附件（用于清理未使用）（兼容旧接口 Api/Attachment/batchDeleteAttachments）。\n     */\n    public function batchDeleteAttachments(Request $request, Response $response): Response\n    {\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        // 检查管理员权限\n        $adminCheck = $this->checkAdmin($request, $response);\n        if ($adminCheck !== true) {\n            return $adminCheck;\n        }\n\n        // 支持 file_ids 数组或逗号分隔字符串\n        $fileIds = $this->getParam($request, 'file_ids', '');\n        if (empty($fileIds)) {\n            return $this->error($response, 10101, '缺少参数');\n        }\n\n        if (is_string($fileIds)) {\n            $fileIds = explode(',', $fileIds);\n        }\n        if (!is_array($fileIds)) {\n            $fileIds = [];\n        }\n\n        $success = 0;\n        $failed = 0;\n        foreach ($fileIds as $fid) {\n            $fid = intval($fid);\n            if ($fid <= 0) {\n                continue;\n            }\n            $ret = \\App\\Model\\Attachment::deleteFile($fid);\n            if ($ret) {\n                $success++;\n            } else {\n                $failed++;\n            }\n        }\n\n        return $this->success($response, [\n            'success' => $success,\n            'failed'  => $failed,\n        ]);\n    }\n}\n"
  },
  {
    "path": "server/app/Api/Controller/CatalogController.php",
    "content": "<?php\n\nnamespace App\\Api\\Controller;\n\nuse App\\Common\\BaseController;\nuse Illuminate\\Database\\Capsule\\Manager as DB;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\n\n/**\n * 目录相关 Api（新架构）。\n */\nclass CatalogController extends BaseController\n{\n    /**\n     * 获取目录列表（兼容旧接口 Api/Catalog/catList）。\n     *\n     * 功能：\n     * - 获取项目的目录列表\n     * - 权限检查（checkItemVisit）\n     * - 目录权限过滤（filterMemberCat）\n     */\n    public function catList(Request $request, Response $response): Response\n    {\n        $itemId = $this->getParam($request, 'item_id', 0);\n\n        if ($itemId <= 0) {\n            return $this->success($response, []);\n        }\n\n        // 获取登录用户（非严格模式，允许游客访问）\n        $loginUser = [];\n        $this->requireLoginUser($request, $response, $loginUser, false);\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        // 检查访问权限\n        if (!$this->checkItemVisit($uid, $itemId)) {\n            return $this->error($response, 10103, '您没有访问权限');\n        }\n\n        // 获取目录列表\n        $ret = \\App\\Model\\Catalog::getList($itemId);\n        $ret = \\App\\Model\\Catalog::filterMemberCat($uid, $ret);\n\n        return $this->success($response, $ret ?: []);\n    }\n\n    /**\n     * 获取目录列表（分组，树形结构）（兼容旧接口 Api/Catalog/catListGroup）。\n     */\n    public function catListGroup(Request $request, Response $response): Response\n    {\n        $itemId = $this->getParam($request, 'item_id', 0);\n\n        if ($itemId <= 0) {\n            return $this->success($response, []);\n        }\n\n        // 获取登录用户（非严格模式，允许游客访问）\n        $loginUser = [];\n        $this->requireLoginUser($request, $response, $loginUser, false);\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        // 检查访问权限\n        if (!$this->checkItemVisit($uid, $itemId)) {\n            return $this->error($response, 10103, '您没有访问权限');\n        }\n\n        // 获取目录列表（分组）\n        $ret = \\App\\Model\\Catalog::getList($itemId, true);\n        $ret = \\App\\Model\\Catalog::filterMemberCat($uid, $ret);\n\n        return $this->success($response, $ret ?: []);\n    }\n\n    /**\n     * 获取目录列表（带层级路径）（兼容旧接口 Api/Catalog/catListName）。\n     *\n     * 功能：\n     * - 目录名按层级描述，例如：\"我的项目/用户接口/用户登录\"\n     */\n    public function catListName(Request $request, Response $response): Response\n    {\n        $itemId = $this->getParam($request, 'item_id', 0);\n\n        if ($itemId <= 0) {\n            return $this->success($response, []);\n        }\n\n        // 获取登录用户（非严格模式，允许游客访问）\n        $loginUser = [];\n        $this->requireLoginUser($request, $response, $loginUser, false);\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        // 检查访问权限\n        if (!$this->checkItemVisit($uid, $itemId)) {\n            return $this->error($response, 10103, '您没有访问权限');\n        }\n\n        // 获取目录列表（分组）\n        $ret = \\App\\Model\\Catalog::getList($itemId, true);\n        $ret = \\App\\Model\\Catalog::filterMemberCat($uid, $ret);\n\n        if (empty($ret)) {\n            return $this->success($response, []);\n        }\n\n        $return = [];\n\n        // 递归函数，准备递归改名\n        $rename = function ($catalog, $pCatName) use (&$return, &$rename) {\n            if ($catalog) {\n                foreach ($catalog as $value) {\n                    $value['cat_name'] = $pCatName . '/' . $value['cat_name'];\n                    $sub = $value['sub'] ?? [];\n                    unset($value['sub']);\n                    $return[] = $value;\n                    if (!empty($sub)) {\n                        $rename($sub, $value['cat_name']);\n                    }\n                }\n            }\n        };\n\n        foreach ($ret as $value) {\n            $sub = $value['sub'] ?? [];\n            unset($value['sub']);\n            $return[] = $value;\n            if (!empty($sub)) {\n                $rename($sub, $value['cat_name']);\n            }\n        }\n\n        return $this->success($response, $return);\n    }\n\n    /**\n     * 获取二级目录列表（兼容旧接口 Api/Catalog/secondCatList）。\n     */\n    public function secondCatList(Request $request, Response $response): Response\n    {\n        $itemId = $this->getParam($request, 'item_id', 0);\n\n        if ($itemId <= 0) {\n            return $this->success($response, []);\n        }\n\n        // 获取登录用户（非严格模式，允许游客访问）\n        $loginUser = [];\n        $this->requireLoginUser($request, $response, $loginUser, false);\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        // 检查访问权限\n        if (!$this->checkItemVisit($uid, $itemId)) {\n            return $this->error($response, 10103, '您没有访问权限');\n        }\n\n        // 获取二级目录列表\n        $ret = \\App\\Model\\Catalog::getListByLevel($itemId, 2);\n\n        return $this->success($response, $ret ?: []);\n    }\n\n    /**\n     * 获取子目录列表（兼容旧接口 Api/Catalog/childCatList）。\n     */\n    public function childCatList(Request $request, Response $response): Response\n    {\n        $catId = $this->getParam($request, 'cat_id', 0);\n\n        if ($catId <= 0) {\n            return $this->success($response, []);\n        }\n\n        // 获取目录信息\n        $cat = \\App\\Model\\Catalog::findById($catId);\n        if (!$cat) {\n            return $this->success($response, []);\n        }\n\n        $itemId = (int) $cat->item_id;\n\n        // 获取登录用户（非严格模式，允许游客访问）\n        $loginUser = [];\n        $this->requireLoginUser($request, $response, $loginUser, false);\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        // 检查访问权限\n        if (!$this->checkItemVisit($uid, $itemId)) {\n            return $this->error($response, 10103, '您没有访问权限');\n        }\n\n        // 获取子目录列表\n        $ret = \\App\\Model\\Catalog::getChildrenByCatId($itemId, $catId);\n\n        return $this->success($response, $ret ?: []);\n    }\n\n    /**\n     * 保存目录（兼容旧接口 Api/Catalog/save）。\n     *\n     * 功能：\n     * - 支持新建和更新目录\n     * - 权限检查（checkItemEdit）\n     * - 目录数量限制检查（最多 1500 个）\n     * - 删除菜单缓存\n     */\n    public function save(Request $request, Response $response): Response\n    {\n        $catName    = $this->getParam($request, 'cat_name', '');\n        $sNumber    = $this->getParam($request, 's_number', 0);\n        $catId      = $this->getParam($request, 'cat_id', 0);\n        $parentCatId = $this->getParam($request, 'parent_cat_id', 0);\n        $itemId     = $this->getParam($request, 'item_id', 0);\n\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        // 检查编辑权限\n        if (!$this->checkItemEdit($uid, $itemId)) {\n            return $this->error($response, 10103, '您没有编辑权限');\n        }\n\n        // 禁止空目录的生成\n        if (empty($catName)) {\n            return $this->error($response, 10101, '目录名称不能为空');\n        }\n\n        // 检查上级目录不能选择自身\n        if ($parentCatId > 0 && $parentCatId == $catId) {\n            return $this->error($response, 10101, '上级目录不能选择自身');\n        }\n\n        if ($catId > 0) {\n            // 更新目录\n            $cat = \\App\\Model\\Catalog::findById($catId);\n            if (!$cat) {\n                return $this->error($response, 10101, '目录不存在');\n            }\n\n            $itemId = (int) $cat->item_id;\n\n            if (!$this->checkItemEdit($uid, $itemId)) {\n                return $this->error($response, 10103, '您没有编辑权限');\n            }\n\n            $return = \\App\\Model\\Catalog::save($catId, $itemId, $catName, $parentCatId, $sNumber);\n            if (!$return) {\n                return $this->error($response, 10103, '更新失败');\n            }\n\n            // 记录变更日志\n            \\App\\Model\\ItemChangeLog::addLog($uid, $itemId, 'update', 'catalog', $catId, $catName);\n        } else {\n            // 新建目录\n            // 检查目录数量限制\n            $catalogCount = \\App\\Model\\Catalog::getCount($itemId);\n            if ($catalogCount >= 1500) {\n                return $this->error($response, 10100, '你创建太多目录啦！如有需求请联系网站管理员');\n            }\n\n            $return = \\App\\Model\\Catalog::save(0, $itemId, $catName, $parentCatId, $sNumber);\n            if (!$return) {\n                return $this->error($response, 10103, '创建失败');\n            }\n\n            $catId = (int) ($return['cat_id'] ?? 0);\n\n            // 记录变更日志\n            \\App\\Model\\ItemChangeLog::addLog($uid, $itemId, 'create', 'catalog', $catId, $catName);\n        }\n\n        // 删除菜单缓存\n        \\App\\Model\\Item::deleteCache($itemId);\n\n        // 返回 cat_id（兼容历史格式）\n        // 兼容性说明（2025-09-09）：\n        // - 旧版返回格式：{\"error_code\": 0, \"data\": 123}（data 是整数 cat_id）\n        // - 标准返回格式：{\"error_code\": 0, \"data\": {\"cat_id\": 123}}（data 是对象，包含 cat_id 字段）\n        // - 当前为了保持与 RunApi 客户端兼容，使用旧版格式（RunApi 客户端依赖此格式）\n        // - 计划在 2027-09-09 后改为标准返回格式，届时 RunApi 客户端应已全部更新\n        // TODO: 2027-09-09 后改为标准返回：return $this->success($response, ['cat_id' => $catId]);\n        return $this->json($response, [\n            'error_code' => 0,\n            'data'       => $catId,\n        ]);\n    }\n\n    /**\n     * 批量更新目录与页面的结构（兼容旧接口 Api/Catalog/batUpdate）。\n     *\n     * 功能：\n     * - 批量更新目录的名称、父目录、层级与排序；\n     * - 批量更新页面所在目录与排序；\n     * - 记录拖动操作日志（ItemChangeLog::addLog，op_object_type=tree）。\n     */\n    public function batUpdate(Request $request, Response $response): Response\n    {\n        $catsJson    = (string) $this->getParam($request, 'cats', '');\n        $itemId      = (int) $this->getParam($request, 'item_id', 0);\n        $draggedId   = (int) $this->getParam($request, 'dragged_id', 0);\n        $draggedTitle = (string) $this->getParam($request, 'dragged_title', '');\n        $draggedType = (string) $this->getParam($request, 'dragged_type', '');\n\n        if ($itemId <= 0 || $catsJson === '') {\n            return $this->error($response, 10101, '参数错误');\n        }\n\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        if (!$this->checkItemEdit($uid, $itemId)) {\n            return $this->error($response, 10103, '您没有编辑权限');\n        }\n\n        $dataArray = json_decode(htmlspecialchars_decode($catsJson, ENT_QUOTES), true);\n        if (!is_array($dataArray) || empty($dataArray)) {\n            return $this->success($response, []);\n        }\n\n        foreach ($dataArray as $value) {\n            $catId       = (int) ($value['cat_id'] ?? 0);\n            $catName     = isset($value['cat_name']) ? (string) $value['cat_name'] : '';\n            $parentCatId = (int) ($value['parent_cat_id'] ?? 0);\n            $level       = (int) ($value['level'] ?? 2);\n            $sNumber     = (int) ($value['s_number'] ?? 0);\n            $pageId      = (int) ($value['page_id'] ?? 0);\n\n            if ($catId > 0 && $catName !== '') {\n                // 更新目录\n                DB::table('catalog')\n                    ->where('cat_id', $catId)\n                    ->where('item_id', $itemId)\n                    ->update([\n                        'cat_name'      => $catName,\n                        'parent_cat_id' => $parentCatId,\n                        'level'         => $level,\n                        's_number'      => $sNumber,\n                    ]);\n            }\n\n            if ($pageId > 0) {\n                // 更新页面目录与排序（开源版仅使用主表 page）\n                DB::table('page')\n                    ->where('page_id', $pageId)\n                    ->where('item_id', $itemId)\n                    ->update([\n                        'cat_id'   => $parentCatId,\n                        's_number' => $sNumber,\n                    ]);\n                \\App\\Model\\Page::deleteCache($pageId);\n            }\n        }\n\n        // 组装日志信息\n        $logMessage = '目录树';\n        if ($draggedId > 0 && $draggedTitle !== '') {\n            if ($draggedType === 'page') {\n                $logMessage = '拖动页面「' . $draggedTitle . '」';\n            } elseif ($draggedType === 'catalog') {\n                $logMessage = '拖动目录「' . $draggedTitle . '」';\n            }\n        }\n\n        \\App\\Model\\ItemChangeLog::addLog($uid, $itemId, 'drag', 'tree', 0, $logMessage);\n\n        // 删除菜单缓存\n        \\App\\Model\\Item::deleteCache($itemId);\n\n        return $this->success($response, []);\n    }\n\n    /**\n     * 获取默认目录（兼容旧接口 Api/Catalog/getDefaultCat）。\n     *\n     * 规则与旧版保持一致：\n     * - 如果带 page_id：使用页面或其历史版本所在目录；\n     * - 如果是复制页面：使用被复制页面的目录；\n     * - 否则：使用当前用户在该项目下最近一次创建/编辑页面所在目录。\n     */\n    public function getDefaultCat(Request $request, Response $response): Response\n    {\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        $pageId        = (int) $this->getParam($request, 'page_id', 0);\n        $itemId        = (int) $this->getParam($request, 'item_id', 0);\n        $pageHistoryId = (int) $this->getParam($request, 'page_history_id', 0);\n        $copyPageId    = (int) $this->getParam($request, 'copy_page_id', 0);\n\n        $defaultCatId = 0;\n\n        if ($pageId > 0) {\n            if ($pageHistoryId > 0) {\n                $history = \\App\\Model\\PageHistory::findById($pageId, $pageHistoryId);\n                if ($history) {\n                    $itemId       = (int) ($history['item_id'] ?? $itemId);\n                    $defaultCatId = (int) ($history['cat_id'] ?? 0);\n                }\n            } else {\n                $page = \\App\\Model\\Page::findById($pageId);\n                if ($page) {\n                    $itemId       = (int) ($page['item_id'] ?? $itemId);\n                    $defaultCatId = (int) ($page['cat_id'] ?? 0);\n                }\n            }\n        } elseif ($copyPageId > 0) {\n            $page = \\App\\Model\\Page::findById($copyPageId);\n            if ($page) {\n                $itemId       = (int) ($page['item_id'] ?? $itemId);\n                $defaultCatId = (int) ($page['cat_id'] ?? 0);\n            }\n        } else {\n            // 查找用户在该项目下最近一次创建/编辑的页面\n            if ($itemId > 0) {\n                $lastPage = DB::table('page')\n                    ->where('author_uid', $uid)\n                    ->where('item_id', $itemId)\n                    ->orderBy('addtime', 'desc')\n                    ->limit(1)\n                    ->first();\n                if ($lastPage) {\n                    $defaultCatId = (int) ($lastPage->cat_id ?? 0);\n                }\n            }\n        }\n\n        // 使用 page / 历史数据中的 item_id 覆盖，以满足权限校验\n        $itemId = $itemId > 0 ? $itemId : 0;\n\n        if ($itemId <= 0) {\n            return $this->error($response, 10101, '项目不存在');\n        }\n\n        if (!$this->checkItemEdit($uid, $itemId)) {\n            return $this->error($response, 10101, '没有编辑权限');\n        }\n\n        return $this->success($response, ['default_cat_id' => $defaultCatId]);\n    }\n\n    /**\n     * 删除目录（兼容旧接口 Api/Catalog/delete）。\n     */\n    public function delete(Request $request, Response $response): Response\n    {\n        $catId = (int) $this->getParam($request, 'cat_id', 0);\n        if ($catId <= 0) {\n            return $this->error($response, 10101, '参数错误');\n        }\n\n        $cat = \\App\\Model\\Catalog::findById($catId);\n        if (!$cat) {\n            return $this->error($response, 10101, '目录不存在');\n        }\n\n        $itemId = (int) ($cat->item_id ?? 0);\n\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        if (!$this->checkItemEdit($uid, $itemId)) {\n            return $this->error($response, 10103, '您没有编辑权限');\n        }\n\n        \\App\\Model\\ItemChangeLog::addLog(\n            $uid,\n            $itemId,\n            'delete',\n            'catalog',\n            $catId,\n            (string) ($cat->cat_name ?? '')\n        );\n\n        $ret = \\App\\Model\\Catalog::deleteCat($catId);\n\n        if (!$ret) {\n            return $this->error($response, 10101, '删除失败');\n        }\n\n        return $this->success($response, ['success' => true]);\n    }\n\n    /**\n     * 按目录获取页面列表（兼容旧接口 Api/Catalog/getPagesBycat）。\n     */\n    public function getPagesBycat(Request $request, Response $response): Response\n    {\n        $catId  = (int) $this->getParam($request, 'cat_id', 0);\n        $itemId = (int) $this->getParam($request, 'item_id', 0);\n\n        if ($catId <= 0 || $itemId <= 0) {\n            return $this->error($response, 10101, '参数错误');\n        }\n\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        if (!$this->checkItemEdit($uid, $itemId)) {\n            return $this->error($response, 10103, '您没有编辑权限');\n        }\n\n        $rows = DB::table('page')\n            ->select(['page_id', 'page_title', 's_number'])\n            ->where('cat_id', $catId)\n            ->where('item_id', $itemId)\n            ->where('is_del', 0)\n            ->orderBy('s_number', 'asc')\n            ->orderBy('page_id', 'asc')\n            ->get()\n            ->all();\n\n        $result = [];\n        foreach ($rows as $row) {\n            $result[] = (array) $row;\n        }\n\n        return $this->success($response, $result);\n    }\n\n    /**\n     * 复制或移动目录（兼容旧接口 Api/Catalog/copy）。\n     *\n     * 说明：\n     * - 支持同项目或跨项目复制目录及其子目录和页面；\n     * - 当 is_del=1 且复制成功时，会删除原目录（等价移动操作）。\n     */\n    public function copy(Request $request, Response $response): Response\n    {\n        $catId      = (int) $this->getParam($request, 'cat_id', 0);\n        $newPcatId  = (int) $this->getParam($request, 'new_p_cat_id', 0);\n        $toItemId   = (int) $this->getParam($request, 'to_item_id', 0);\n        $isDel      = (int) $this->getParam($request, 'is_del', 0);\n\n        if ($catId <= 0) {\n            return $this->error($response, 10101, '参数错误');\n        }\n\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        $srcCat = \\App\\Model\\Catalog::findById($catId);\n        if (!$srcCat) {\n            return $this->error($response, 10101, '目录不存在');\n        }\n\n        $fromItemId = (int) ($srcCat->item_id ?? 0);\n        $destItemId = $toItemId > 0 ? $toItemId : $fromItemId;\n\n        // 目标项目编辑权限\n        if (!$this->checkItemEdit($uid, $destItemId)) {\n            return $this->error($response, 10103, '您没有目标项目的编辑权限');\n        }\n\n        // 源项目编辑权限\n        if (!$this->checkItemEdit($uid, $fromItemId)) {\n            return $this->error($response, 10103, '您没有源项目的编辑权限');\n        }\n\n        // 复制目录树\n        $idMap = [];\n        $res   = $this->copyCatalogTree($uid, $catId, $newPcatId, $fromItemId, $destItemId, $idMap);\n\n        if ($isDel && $res) {\n            \\App\\Model\\Catalog::deleteCat($catId);\n        }\n\n        // 删除项目缓存（复制后需要刷新菜单）\n        if ($res) {\n            \\App\\Model\\Item::deleteCache($destItemId);\n            // 如果是跨项目复制，也需要删除源项目的缓存\n            if ($fromItemId != $destItemId) {\n                \\App\\Model\\Item::deleteCache($fromItemId);\n            }\n        }\n\n        return $this->success($response, $res ?: []);\n    }\n\n    /**\n     * 递归复制目录树及其页面。\n     *\n     * @param int   $uid        操作用户 ID\n     * @param int   $srcCatId   源目录 ID\n     * @param int   $destParentId 目标父目录 ID（在目标项目下）\n     * @param int   $fromItemId 源项目 ID\n     * @param int   $toItemId   目标项目 ID\n     * @param array $idMap      源目录 ID => 新目录 ID 映射\n     * @param array $visited    已访问的源目录 ID 列表（用于检测循环引用）\n     * @param int   $depth      当前递归深度\n     * @return array            返回新创建的根目录信息\n     */\n    private function copyCatalogTree(\n        int $uid,\n        int $srcCatId,\n        int $destParentId,\n        int $fromItemId,\n        int $toItemId,\n        array &$idMap,\n        array $visited = [],\n        int $depth = 0\n    ): array {\n        // 安全检查：防止无限递归\n        $maxDepth = 100; // 最大层级深度\n        if ($depth >= $maxDepth) {\n            // 超过最大深度，记录日志并停止递归\n            \\App\\Common\\Helper\\LogHelper::warning(\n                \"Catalog copy exceeded max depth {$maxDepth} at cat_id {$srcCatId}, item_id: {$fromItemId} -> {$toItemId}\",\n                'Catalog'\n            );\n            return [];\n        }\n\n        // 循环引用检测：防止复制循环引用的目录结构\n        if (in_array($srcCatId, $visited)) {\n            // 检测到循环引用，记录日志并跳过\n            \\App\\Common\\Helper\\LogHelper::warning(\n                \"Circular reference detected in catalog copy: cat_id {$srcCatId}, item_id: {$fromItemId} -> {$toItemId}, path: \" . implode(' -> ', $visited),\n                'Catalog'\n            );\n            return [];\n        }\n        $visited[] = $srcCatId;\n        $srcCat = \\App\\Model\\Catalog::findById($srcCatId);\n        if (!$srcCat) {\n            return [];\n        }\n\n        // 在目标项目下创建新目录\n        $newCat = \\App\\Model\\Catalog::save(\n            0,\n            $toItemId,\n            (string) $srcCat->cat_name,\n            $destParentId,\n            (int) ($srcCat->s_number ?? 0)\n        );\n\n        if (!$newCat || empty($newCat['cat_id'])) {\n            return [];\n        }\n\n        $newCatId         = (int) $newCat['cat_id'];\n        $idMap[$srcCatId] = $newCatId;\n\n        // 复制该目录下的页面\n        $pages     = DB::table('page')\n            ->where('item_id', $fromItemId)\n            ->where('cat_id', $srcCatId)\n            ->where('is_del', 0)\n            ->orderBy('s_number', 'asc')\n            ->orderBy('page_id', 'asc')\n            ->get()\n            ->all();\n\n        $username = '';\n        $user     = \\App\\Model\\User::findById($uid);\n        if ($user) {\n            $username = (string) ($user->username ?? '');\n        }\n\n        foreach ($pages as $pageRow) {\n            $page = (array) $pageRow;\n\n            // 解压原内容\n            $content = (string) ($page['page_content'] ?? '');\n            $decoded = \\App\\Common\\Helper\\ContentCodec::decompress($content);\n            if ($decoded !== '') {\n                $content = $decoded;\n            }\n\n            $data = [\n                'author_uid'      => $uid,\n                'author_username' => $username,\n                'item_id'         => $toItemId,\n                'cat_id'          => $newCatId,\n                'page_title'      => $page['page_title'] ?? '',\n                'page_content'    => $content,\n                'page_comments'   => $page['page_comments'] ?? '',\n                's_number'        => (int) ($page['s_number'] ?? 0),\n                'ext_info'        => $page['ext_info'] ?? '',\n                'addtime'         => time(),\n            ];\n\n            \\App\\Model\\Page::addPage($toItemId, $data);\n        }\n\n        // 复制子目录\n        $subCats = DB::table('catalog')\n            ->where('item_id', $fromItemId)\n            ->where('parent_cat_id', $srcCatId)\n            ->get()\n            ->all();\n\n        foreach ($subCats as $sub) {\n            $this->copyCatalogTree(\n                $uid,\n                (int) $sub->cat_id,\n                $newCatId,\n                $fromItemId,\n                $toItemId,\n                $idMap\n            );\n        }\n\n        return $newCat;\n    }\n}\n"
  },
  {
    "path": "server/app/Api/Controller/CommonController.php",
    "content": "<?php\n\nnamespace App\\Api\\Controller;\n\nuse App\\Common\\BaseController;\nuse App\\Common\\Helper\\UrlHelper;\nuse Illuminate\\Database\\Capsule\\Manager as DB;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\nuse Gregwar\\Captcha\\CaptchaBuilder;\n\nclass CommonController extends BaseController\n{\n    /**\n     * 生成图片验证码，对应旧版 createCaptcha。\n     *\n     * 返回：{ error_code: 0, data: { captcha_id } }\n     */\n    public function createCaptcha(Request $request, Response $response): Response\n    {\n        // 生成 4 位验证码（数字 + 大写字母），不依赖旧 get_rand_str\n        $chars   = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';\n        $length  = 4;\n        $captcha = '';\n        $maxIdx  = strlen($chars) - 1;\n        for ($i = 0; $i < $length; $i++) {\n            $captcha .= $chars[random_int(0, $maxIdx)];\n        }\n\n        $now = time();\n\n        // 写入 captcha 表\n        $captchaId = DB::table('captcha')->insertGetId([\n            'mobile'      => '',\n            'captcha'     => $captcha,\n            'expire_time' => $now + 60 * 10, // 10 分钟有效\n        ]);\n\n        // 清理一年以前的历史验证码\n        DB::table('captcha')\n            ->where('expire_time', '<', $now - 365 * 24 * 60 * 60)\n            ->delete();\n\n        return $this->success($response, [\n            'captcha_id' => $captchaId,\n        ]);\n    }\n\n    /**\n     * 展示验证码图片，对应旧版 showCaptcha。\n     *\n     * 路由：/server/Api/Common/showCaptcha?captcha_id=123\n     */\n    public function showCaptcha(Request $request, Response $response): Response\n    {\n        $captchaId = $this->getParam($request, 'captcha_id', 0);\n        if ($captchaId <= 0) {\n            // 简单返回 404 图片为空\n            return $response->withStatus(404);\n        }\n\n        $row = DB::table('captcha')\n            ->where('captcha_id', $captchaId)\n            ->first();\n\n        if (!$row || !isset($row->captcha)) {\n            return $response->withStatus(404);\n        }\n\n        $builder = new CaptchaBuilder((string) $row->captcha);\n        $builder->build();\n\n        // 将图片内容写入 Response body\n        ob_start();\n        $builder->output();\n        $imageData = ob_get_clean();\n\n        $response->getBody()->write($imageData);\n\n        return $response\n            ->withHeader('Content-Type', 'image/png')\n            ->withStatus(200);\n    }\n\n    /**\n     * 生成并输出简单的 Session 验证码图片，对应旧版 verify。\n     *\n     * 仅供老页面兼容使用，登录等推荐使用 createCaptcha / showCaptcha 组合。\n     */\n    public function verify(Request $request, Response $response): Response\n    {\n        $builder = new CaptchaBuilder();\n        $builder->build();\n\n        // 将验证码短语保存到原生 Session 中（统一小写）\n        $_SESSION['v_code'] = strtolower($builder->getPhrase());\n\n        ob_start();\n        $builder->output();\n        $imageData = ob_get_clean();\n\n        $response->getBody()->write($imageData);\n\n        return $response\n            ->withHeader('Content-Type', 'image/png')\n            ->withStatus(200);\n    }\n\n    /**\n     * 返回 ShowDoc 版本号，对标旧版 Api/Common/version。\n     */\n    public function version(Request $request, Response $response): Response\n    {\n        // server/app/Api/Controller => 上溯四级到项目根目录\n        $rootPath = dirname(__DIR__, 4);\n        $file     = $rootPath . '/composer.json';\n\n        if (!is_file($file)) {\n            return $this->error($response, 10500, 'composer.json not found');\n        }\n\n        $json = json_decode(file_get_contents($file), true);\n        if (!is_array($json)) {\n            return $this->error($response, 10500, 'composer.json parse error');\n        }\n\n        $version = isset($json['version']) ? (string) $json['version'] : '';\n\n        return $this->success($response, [\n            'version' => $version,\n        ]);\n    }\n\n    /**\n     * 获取网站首页配置（兼容旧接口 Api/Common/homePageSetting）。\n     */\n    public function homePageSetting(Request $request, Response $response): Response\n    {\n        $homePage   = \\App\\Model\\Options::get('home_page', '');\n        $homeItem   = \\App\\Model\\Options::get('home_item', '');\n        $openApiKey = \\App\\Model\\Options::get('open_api_key', '');\n        $beian      = \\App\\Model\\Options::get('beian', '');\n        $registerOpen = \\App\\Model\\Options::get('register_open');\n\n        // 兼容旧逻辑：\n        // - 如果 register_open === null，表示尚未有数据，此时前端应视为\"允许注册\"（1）\n        // - 否则将其转换为整数\n        if ($registerOpen === null) {\n            $registerOpenValue = 1;\n        } else {\n            $registerOpenValue = (int) $registerOpen;\n        }\n\n        $data = [\n            'home_page'  => $homePage,\n            'home_item'  => $homeItem,\n            'is_show_ai' => $openApiKey ? 1 : 0,\n            'beian'      => $beian ?: '',\n            'register_open' => $registerOpenValue,\n        ];\n\n        return $this->success($response, $data);\n    }\n\n    /**\n     * 生成二维码图片，对应旧版 Api/Common/qrcode。\n     *\n     * 说明：为保持兼容，这里仍然依赖全局 QRcode 类（通过 composer/自动加载引入），\n     * 输出 PNG 图片内容。\n     */\n    public function qrcode(Request $request, Response $response): Response\n    {\n        $url  = (string) $this->getParam($request, 'url', '');\n        $url  = $url !== '' ? urldecode($url) : $url;\n        $size = (int) $this->getParam($request, 'size', 6);\n        if ($size <= 0) {\n            $size = 6;\n        }\n\n        if (!class_exists('\\\\QRcode')) {\n            // 未安装 QRcode 库，返回错误\n            return $this->error($response, 10500, 'QRcode library not available');\n        }\n\n        ob_start();\n        // 与旧版一致：$level=3（纠错级别）、$margin=2\n        \\QRcode::png($url, false, 3, $size, 2);\n        $imageData = ob_get_clean();\n\n        $response->getBody()->write($imageData);\n\n        return $response\n            ->withHeader('Content-Type', 'image/png')\n            ->withStatus(200);\n    }\n\n    /**\n     * 公共文件访问兼容入口，对应旧版 Api/Common/visitFile。\n     *\n     * 现在统一通过 AttachmentController::visitFile 处理。\n     *\n     * 兼容旧版路由：home/common/visitfile/sign/:sign -> api/attachment/visitFile?sign=:1\n     * 支持路径参数：/api/common/visitfile/sign/0653ae51cee82aa3a539a0cc95c8957f\n     * 也支持查询参数：/api/common/visitfile?sign=0653ae51cee82aa3a539a0cc95c8957f\n     *\n     * 注意：直接调用 AttachmentController::visitFile，避免 302 重定向造成的循环\n     */\n    public function visitFile(Request $request, Response $response): Response\n    {\n        // 同时支持路径参数（兼容旧版路由：sign/:sign）\n        $sign = $this->getParam($request, 'sign', '');\n        if ($sign !== '') {\n            // 将路径参数合并到查询参数中\n            $queryParams = $request->getQueryParams();\n            $queryParams['sign'] = $sign;\n            $request = $request->withQueryParams($queryParams);\n        }\n\n        // 直接创建 AttachmentController 实例并调用 visitFile，避免重定向循环\n        $controller = new \\App\\Api\\Controller\\AttachmentController();\n        return $controller->visitFile($request, $response);\n    }\n\n}\n"
  },
  {
    "path": "server/app/Api/Controller/ExportController.php",
    "content": "<?php\n\nnamespace App\\Api\\Controller;\n\nuse App\\Common\\BaseController;\nuse App\\Model\\ExportLog;\nuse App\\Model\\Item;\nuse App\\Model\\Page;\nuse App\\Model\\Member;\nuse App\\Model\\Runapi;\nuse App\\Model\\ItemChangeLog;\nuse App\\Common\\Helper\\FileHelper;\nuse App\\Common\\Helper\\Convert;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\n\nclass ExportController extends BaseController\n{\n    /**\n     * 检查 Markdown 导出限制\n     *\n     * @param Request $request\n     * @param Response $response\n     * @return Response\n     */\n    public function checkMarkdownLimit(Request $request, Response $response): Response\n    {\n        $user = [];\n        if ($error = $this->requireLoginUser($request, $response, $user)) {\n            return $error;\n        }\n\n        $uid = (int) ($user['uid'] ?? 0);\n        $exportFormat = $this->getParam($request, 'export_format', '');\n\n        if ($exportFormat == 'markdown') {\n            // 开源版无导出次数限制\n        }\n\n        return $this->success($response, []);\n    }\n\n    /**\n     * 导出整个项目为 Word\n     *\n     * @param Request $request\n     * @param Response $response\n     * @return Response\n     */\n    public function word(Request $request, Response $response): Response\n    {\n        set_time_limit(200);\n        ini_set('memory_limit', '1500M');\n\n        $user = [];\n        if ($error = $this->requireLoginUser($request, $response, $user)) {\n            return $error;\n        }\n\n        $uid = (int) ($user['uid'] ?? 0);\n        $itemId = $this->getParam($request, 'item_id', 0);\n        $catId = $this->getParam($request, 'cat_id', 0);\n        $pageId = $this->getParam($request, 'page_id', 0);\n\n        // 权限检查\n        if (!$this->checkItemEdit($uid, $itemId)) {\n            return $this->error($response, 10302, '没有权限');\n        }\n\n        // 获取项目信息\n        $item = Item::findById($itemId);\n        if (!$item) {\n            return $this->error($response, 10101, '项目不存在');\n        }\n\n        // 检查是否为 runapi 项目并获取全局 header\n        $globalHeaders = [];\n        if ((int) ($item->item_type ?? 0) == 3) {\n            $globalParam = Runapi::getGlobalParam($itemId);\n            if (!empty($globalParam['header'])) {\n                $globalHeaders = $globalParam['header'];\n            }\n        }\n\n        // 成员目录权限：获取该用户在此项目下允许的目录集合\n        $allowedCatIds = Member::getCatIds($itemId, $uid);\n\n        // 获取菜单结构\n        $menu = Item::getContent($itemId, true); // 解压内容\n\n        $pages = [];\n        $catalogs = [];\n\n        if ($pageId > 0) {\n            // 导出单个页面\n            $page = Page::findPageByCache($pageId, $itemId);\n            if (!$page) {\n                return $this->error($response, 10101, '页面不存在');\n            }\n            // 如果有限定目录，则校验页面所属目录是否在允许集合内\n            if (!empty($allowedCatIds)) {\n                $pageCatId = (int) ($page['cat_id'] ?? 0);\n                $allowed = array_flip(array_map('intval', $allowedCatIds));\n                if (!isset($allowed[$pageCatId])) {\n                    return $this->error($response, 10302, '没有权限');\n                }\n            }\n            $pages[] = $page;\n        } elseif ($catId > 0) {\n            // 导出指定目录\n            if (!empty($allowedCatIds) && !in_array($catId, array_map('intval', $allowedCatIds))) {\n                return $this->error($response, 10302, '没有权限');\n            }\n            // 从菜单中找到指定目录\n            $found = $this->findCatalogInMenu($menu['catalogs'], $catId);\n            if ($found) {\n                $pages = $found['pages'] ?? [];\n                $catalogs = [$found];\n            }\n        } else {\n            // 导出整个项目\n            if (!empty($allowedCatIds)) {\n                // 仅导出被允许的二级目录\n                $allowed = array_flip(array_map('intval', $allowedCatIds));\n                $catalogs = [];\n                foreach ($menu['catalogs'] ?? [] as $one) {\n                    if (isset($allowed[(int) ($one['cat_id'] ?? 0)])) {\n                        $catalogs[] = $one;\n                    }\n                }\n                $pages = [];\n            } else {\n                $pages = $menu['pages'] ?? [];\n                $catalogs = $menu['catalogs'] ?? [];\n            }\n        }\n\n        // 生成 Word 内容\n        // 引入 Parsedown 类（Markdown 解析器）\n        if (!class_exists('Parsedown')) {\n            require_once __DIR__ . '/../../Common/Vendor/Parsedown.php';\n        }\n        $parsedown = new \\Parsedown();\n        $convert = new Convert();\n        $data = '';\n        $parent = 1;\n\n        // 如果是 runapi 项目且有全局 header，则先添加全局 header 信息\n        if (!empty($globalHeaders)) {\n            $data .= \"<h1>全局Header参数</h1>\";\n            $data .= '<div style=\"margin-left:20px;\">';\n            $data .= \"<table>\";\n            $data .= \"<thead><tr><th>参数名</th><th>值</th><th>是否启用</th><th>备注</th></tr></thead>\";\n            $data .= \"<tbody>\";\n            foreach ($globalHeaders as $header) {\n                $enabled = isset($header['enabled']) && $header['enabled'] ? '是' : '否';\n                $name = isset($header['name']) ? htmlspecialchars($header['name']) : '';\n                $value = isset($header['value']) ? htmlspecialchars($header['value']) : '';\n                $remark = isset($header['remark']) ? htmlspecialchars($header['remark']) : '';\n                $data .= \"<tr><td>{$name}</td><td>{$value}</td><td>{$enabled}</td><td>{$remark}</td></tr>\";\n            }\n            $data .= \"</tbody></table>\";\n            $data .= '</div>';\n            $parent++;\n        }\n\n        // 处理页面\n        if (!empty($pages)) {\n            foreach ($pages as $value) {\n                if (count($pages) > 1) {\n                    $data .= \"<h1>{$parent}、\" . htmlspecialchars($value['page_title'] ?? '') . \"</h1>\";\n                } else {\n                    $data .= \"<h1>\" . htmlspecialchars($value['page_title'] ?? '') . \"</h1>\";\n                }\n                $data .= '<div style=\"margin-left:20px;\">';\n                $pageContent = $value['page_content'] ?? '';\n                $tmpContent = $convert->runapiToMd($pageContent);\n                $pageContent = $tmpContent ?: $pageContent;\n                $data .= htmlspecialchars_decode($parsedown->text($pageContent));\n                $data .= '</div>';\n                $parent++;\n            }\n        }\n\n        // 处理目录（递归处理多级目录）\n        if (!empty($catalogs)) {\n            foreach ($catalogs as $value) {\n                $data .= \"<h1>{$parent}、\" . htmlspecialchars($value['cat_name'] ?? '') . \"</h1>\";\n                $data .= '<div style=\"margin-left:0px;\">';\n                $child = 1;\n                $data .= $this->renderCatalogPages($value, $parent, $child, $parsedown, $convert);\n                $data .= '</div>';\n                $parent++;\n            }\n        }\n\n        // 写导出记录\n        ExportLog::add([\n            'uid'         => $uid,\n            'export_type' => 'word',\n            'item_id'     => $itemId,\n            'addtime'     => date('y-m-d H:i:s'),\n        ]);\n\n        // 记录项目变更日志\n        ItemChangeLog::addLog($uid, $itemId, 'export', 'item', $itemId, $item->item_name ?? '');\n\n        // 输出 Word 文档\n        FileHelper::outputWord($data, 'showdoc_export_' . date('YmdHis'));\n\n        // 注意：outputWord 会直接输出并退出，所以这里不会执行\n        return $response;\n    }\n\n    /**\n     * 递归渲染目录下的页面\n     */\n    private function renderCatalogPages($catalog, $parentNum, &$childNum, $parsedown, $convert, $level = 1): string\n    {\n        $data = '';\n        $hTag = 'h' . min($level + 1, 6);\n        $indent = $level * 20;\n\n        if (!empty($catalog['pages'])) {\n            foreach ($catalog['pages'] as $page) {\n                $pageTitle = $page['page_title'] ?? '';\n                $data .= \"<{$hTag}>{$parentNum}.{$childNum}、\" . htmlspecialchars($pageTitle) . \"</{$hTag}>\";\n                $data .= '<div style=\"margin-left:' . $indent . 'px;\">';\n                $pageContent = $page['page_content'] ?? '';\n                $tmpContent = $convert->runapiToMd($pageContent);\n                $pageContent = $tmpContent ?: $pageContent;\n                $data .= htmlspecialchars_decode($parsedown->text($pageContent));\n                $data .= '</div>';\n                $childNum++;\n            }\n        }\n\n        if (!empty($catalog['catalogs'])) {\n            $subParent = 1;\n            foreach ($catalog['catalogs'] as $subCatalog) {\n                $subChild = 1;\n                $data .= $this->renderCatalogPages($subCatalog, $parentNum . '.' . $subParent, $subChild, $parsedown, $convert, $level + 1);\n                $subParent++;\n            }\n        }\n\n        return $data;\n    }\n\n    /**\n     * 在菜单中查找指定目录\n     */\n    private function findCatalogInMenu($catalogs, $catId): ?array\n    {\n        if (empty($catalogs)) {\n            return null;\n        }\n\n        foreach ($catalogs as $catalog) {\n            if ((int) ($catalog['cat_id'] ?? 0) === $catId) {\n                return $catalog;\n            }\n            if (!empty($catalog['catalogs'])) {\n                $found = $this->findCatalogInMenu($catalog['catalogs'], $catId);\n                if ($found) {\n                    return $found;\n                }\n            }\n        }\n\n        return null;\n    }\n\n    /**\n     * 导出整个项目为 Markdown 压缩包\n     *\n     * @param Request $request\n     * @param Response $response\n     * @return Response\n     */\n    public function markdown(Request $request, Response $response): Response\n    {\n        set_time_limit(100);\n        ini_set('memory_limit', '800M');\n\n        $user = [];\n        if ($error = $this->requireLoginUser($request, $response, $user)) {\n            return $error;\n        }\n\n        $uid = (int) ($user['uid'] ?? 0);\n        $itemId = $this->getParam($request, 'item_id', 0);\n\n        // 权限检查\n        if (!$this->checkItemEdit($uid, $itemId)) {\n            return $this->error($response, 10302, '没有权限');\n        }\n\n        // 开源版无导出次数限制\n\n        // 获取项目信息\n        $item = Item::findById($itemId);\n        if (!$item) {\n            return $this->error($response, 10101, '项目不存在');\n        }\n\n        // 成员目录权限：获取该用户在此项目下允许的目录集合\n        $allowedCatIds = Member::getCatIds($itemId, $uid);\n\n        // 导出项目数据\n        $exportJson = Item::export($itemId, true);\n        $exportData = json_decode($exportJson, true);\n\n        // 如果有限定目录，则过滤数据\n        if (!empty($allowedCatIds) && isset($exportData['pages']) && is_array($exportData['pages'])) {\n            $allowed = array_flip(array_map('intval', $allowedCatIds));\n            // 目录受限：去掉根目录下的页面，仅保留被允许的二级目录\n            $exportData['pages']['pages'] = [];\n            $filteredCatalogs = [];\n            if (!empty($exportData['pages']['catalogs']) && is_array($exportData['pages']['catalogs'])) {\n                foreach ($exportData['pages']['catalogs'] as $one) {\n                    if (isset($allowed[(int) ($one['cat_id'] ?? 0)])) {\n                        $filteredCatalogs[] = $one;\n                    }\n                }\n            }\n            $exportData['pages']['catalogs'] = $filteredCatalogs;\n        }\n\n        // 创建临时目录\n        $tempDir = sys_get_temp_dir() . '/showdoc_' . time() . rand();\n        if (!mkdir($tempDir, 0755, true)) {\n            return $this->error($response, 10500, '创建临时目录失败');\n        }\n\n        // 保存 info.json\n        unset($exportData['members']);\n        file_put_contents($tempDir . '/info.json', json_encode($exportData, JSON_UNESCAPED_UNICODE));\n\n        // 将 Markdown 内容写入文件\n        $this->markdownToFile($exportData['pages'] ?? [], $tempDir);\n\n        // 创建 ZIP 文件\n        $tempFile = tempnam(sys_get_temp_dir(), 'Tux') . '_showdoc_.zip';\n        $zip = new \\ZipArchive();\n        if ($zip->open($tempFile, \\ZipArchive::CREATE) !== true) {\n            FileHelper::clearRuntime($tempDir);\n            return $this->error($response, 10500, '创建 ZIP 文件失败');\n        }\n\n        $this->addDirectoryToZip($tempDir, $zip, '');\n        $zip->close();\n\n        // 清理临时目录\n        FileHelper::clearRuntime($tempDir);\n        @rmdir($tempDir);\n\n        // 写导出记录\n        ExportLog::add([\n            'uid'         => $uid,\n            'export_type' => 'markdown',\n            'item_id'     => $itemId,\n            'addtime'     => date('y-m-d H:i:s'),\n        ]);\n\n        // 记录项目变更日志\n        ItemChangeLog::addLog($uid, $itemId, 'export', 'item', $itemId, $item->item_name ?? '');\n\n        // 输出 ZIP 文件\n        header(\"Cache-Control: max-age=0\");\n        header(\"Content-Description: File Transfer\");\n        header('Content-disposition: attachment; filename=showdoc.zip');\n        header(\"Content-Type: application/zip\");\n        header(\"Content-Transfer-Encoding: binary\");\n        header('Content-Length: ' . filesize($tempFile));\n        @readfile($tempFile);\n        @unlink($tempFile);\n\n        // 注意：直接输出文件后会退出，所以这里不会执行\n        return $response;\n    }\n\n    /**\n     * 将目录数据转换为 Markdown 文件，保持目录结构\n     */\n    private function markdownToFile($catalogData, $tempDir, $basePath = ''): void\n    {\n        // 处理当前目录下的页面\n        if (isset($catalogData['pages']) && !empty($catalogData['pages'])) {\n            foreach ($catalogData['pages'] as $value) {\n                $filename = FileHelper::sanitizeFilename($value['page_title'] ?? '未命名') . '.md';\n                $filePath = $basePath ? $basePath . '/' . $filename : $filename;\n                $fullPath = $tempDir . '/' . $filePath;\n\n                // 如果文件已存在，添加序号避免冲突\n                $counter = 1;\n                while (file_exists($fullPath)) {\n                    $nameWithoutExt = FileHelper::sanitizeFilename($value['page_title'] ?? '未命名');\n                    $filename = $nameWithoutExt . '_' . $counter . '.md';\n                    $filePath = $basePath ? $basePath . '/' . $filename : $filename;\n                    $fullPath = $tempDir . '/' . $filePath;\n                    $counter++;\n                }\n\n                // 确保目录存在\n                $dir = dirname($fullPath);\n                if (!is_dir($dir)) {\n                    mkdir($dir, 0755, true);\n                }\n\n                // 保存文件内容\n                file_put_contents($fullPath, htmlspecialchars_decode($value['page_content'] ?? ''));\n            }\n        }\n\n        // 递归处理子目录\n        if (isset($catalogData['catalogs']) && !empty($catalogData['catalogs'])) {\n            foreach ($catalogData['catalogs'] as $value) {\n                $catName = $value['cat_name'] ?? '目录';\n                $dirName = FileHelper::sanitizeFilename($catName);\n                $newBasePath = $basePath ? $basePath . '/' . $dirName : $dirName;\n\n                // 如果目录名已存在，添加序号避免冲突\n                $dirFullPath = $tempDir . '/' . $newBasePath;\n                $counter = 1;\n                while (is_dir($dirFullPath)) {\n                    $dirName = FileHelper::sanitizeFilename($catName) . '_' . $counter;\n                    $newBasePath = $basePath ? $basePath . '/' . $dirName : $dirName;\n                    $dirFullPath = $tempDir . '/' . $newBasePath;\n                    $counter++;\n                }\n\n                // 递归处理子目录\n                $this->markdownToFile($value, $tempDir, $newBasePath);\n            }\n        }\n    }\n\n    /**\n     * 递归添加目录到 ZIP 文件\n     */\n    private function addDirectoryToZip($dir, $zip, $zipPath): void\n    {\n        $files = scandir($dir);\n        foreach ($files as $file) {\n            if ($file == '.' || $file == '..') {\n                continue;\n            }\n\n            $filePath = $dir . '/' . $file;\n            $zipFilePath = $zipPath ? $zipPath . '/' . $file : $file;\n\n            if (is_dir($filePath)) {\n                // 递归处理子目录\n                $this->addDirectoryToZip($filePath, $zip, $zipFilePath);\n            } else {\n                // 添加文件\n                $zip->addFile($filePath, $zipFilePath);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "server/app/Api/Controller/ExportHtmlController.php",
    "content": "<?php\n\nnamespace App\\Api\\Controller;\n\nuse App\\Common\\BaseController;\nuse App\\Model\\ExportLog;\nuse App\\Model\\Item;\nuse App\\Model\\Member;\nuse App\\Model\\ItemChangeLog;\nuse App\\Common\\Helper\\Convert;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\n\nclass ExportHtmlController extends BaseController\n{\n    /**\n     * 导出项目为离线HTML包\n     */\n    public function export(Request $request, Response $response): Response\n    {\n        set_time_limit(600);\n        ini_set('memory_limit', '2G');\n\n        $user = [];\n        if ($error = $this->requireLoginUser($request, $response, $user)) {\n            return $error;\n        }\n\n        $itemId = $this->getParam($request, 'item_id', 0);\n        $uid = (int) ($user['uid'] ?? 0);\n\n        if (!$this->checkItemEdit($uid, $itemId)) {\n            return $this->error($response, 10103, '没有权限');\n        }\n\n        // 获取项目信息\n        $item = Item::findById($itemId);\n        if (!$item) {\n            return $this->error($response, 10101, '项目不存在');\n        }\n        $item = (array) $item;\n\n        // 导出频率限制：同一用户当天最多 100 次（防刷）\n        $timesToday = ExportLog::getTodayCount($uid, 'html');\n        if ($timesToday >= 100) {\n            $message = \"为防止影响服务器负载，你当天导出次数已达上限(100次)。如有疑问请联系网站管理员\";\n            return $this->error($response, 10100, $message);\n        }\n\n        // 检查项目类型\n        $itemType = (int) ($item['item_type'] ?? 0);\n        if (!in_array($itemType, [1, 3, 5])) {\n            return $this->error($response, 10101, '不支持的项目类型');\n        }\n\n        // 成员目录权限：获取该用户在此项目下允许的目录集合\n        $allowedCatIds = Member::getCatIds($itemId, $uid);\n\n        // 获取项目内容（解压内容）\n        $menu = Item::getContent($itemId, true);\n\n        // 应用目录权限过滤\n        if (!empty($allowedCatIds)) {\n            $allowed = array_flip(array_map('intval', $allowedCatIds));\n            // 过滤根目录下的页面\n            if (!empty($menu['pages'])) {\n                $menu['pages'] = [];\n            }\n            // 过滤目录\n            if (!empty($menu['catalogs'])) {\n                $filteredCatalogs = [];\n                foreach ($menu['catalogs'] as $cat) {\n                    if (isset($allowed[(int) ($cat['cat_id'] ?? 0)])) {\n                        $filteredCatalogs[] = $cat;\n                    }\n                }\n                $menu['catalogs'] = $filteredCatalogs;\n            }\n        }\n\n        // 创建临时目录\n        $tempDir = sys_get_temp_dir() . \"/showdoc_html_\" . time() . \"_\" . rand(1000, 9999);\n        if (!mkdir($tempDir, 0755, true)) {\n            return $this->error($response, 10101, '创建临时目录失败');\n        }\n\n        try {\n            // 创建目录结构\n            mkdir($tempDir . '/pages', 0755, true);\n            mkdir($tempDir . '/assets/css', 0755, true);\n            mkdir($tempDir . '/assets/js', 0755, true);\n            mkdir($tempDir . '/assets/uploads', 0755, true);\n\n            // 收集所有页面\n            $allPages = $this->collectAllPages($menu);\n\n            if (empty($allPages)) {\n                return $this->error($response, 10101, '没有可导出的页面');\n            }\n\n            // 生成页面HTML\n            $this->generatePagesHtml($allPages, $item, $tempDir);\n\n            // 生成首页\n            $this->generateIndexHtml($item, $tempDir);\n\n            // 生成数据文件\n            $this->generateDataJs($menu, $item, $allPages, $tempDir);\n\n            // 验证：确保生成的文件名和data.js中的page_id一致\n            $this->validatePageIds($allPages, $tempDir);\n\n            // 生成搜索索引\n            $this->generateSearchIndex($allPages, $tempDir);\n\n            // 复制静态资源\n            $this->copyStaticFiles($tempDir);\n\n            // 复制图片和附件\n            $this->copyAssets($allPages, $tempDir);\n\n            // 生成README\n            $this->generateReadme($item, $tempDir);\n\n            // 打包ZIP\n            $zipFile = sys_get_temp_dir() . \"/showdoc_html_\" . $itemId . \"_\" . time() . \".zip\";\n            if (!$this->zip($tempDir, $zipFile)) {\n                return $this->error($response, 10101, '打包失败');\n            }\n\n            // 写导出记录\n            ExportLog::add([\n                \"uid\" => $uid,\n                \"export_type\" => 'html',\n                \"item_id\" => $itemId,\n                \"addtime\" => date(\"y-m-d H:i:s\")\n            ]);\n\n            // 记录项目变更日志\n            ItemChangeLog::addLog($uid, $itemId, 'export', 'item', $itemId, $item['item_name'] ?? '');\n\n            // 输出文件\n            $filename = 'showdoc_offline_' . $this->sanitizeFilename($item['item_name'] ?? '') . '_' . date('YmdHis') . '.zip';\n\n            // 读取文件内容\n            $fileContent = file_get_contents($zipFile);\n            unlink($zipFile);\n\n            // 处理中文文件名编码\n            $userAgent = $request->getHeaderLine('User-Agent') ?: '';\n            $encodedFilename = rawurlencode($filename);\n\n            // 设置响应头\n            $response = $response\n                ->withHeader('Cache-Control', 'max-age=0')\n                ->withHeader('Content-Description', 'File Transfer')\n                ->withHeader('Content-Type', 'application/zip')\n                ->withHeader('Content-Transfer-Encoding', 'binary')\n                ->withHeader('Content-Length', (string) strlen($fileContent));\n\n            // 根据浏览器类型设置文件名编码\n            if (preg_match('/MSIE|Trident/i', $userAgent)) {\n                // IE浏览器使用GBK编码\n                $filenameGbk = mb_convert_encoding($filename, 'GBK', 'UTF-8');\n                $response = $response->withHeader('Content-Disposition', 'attachment; filename=\"' . $filenameGbk . '\"');\n            } else {\n                // 现代浏览器使用RFC 5987编码\n                $response = $response->withHeader('Content-Disposition', 'attachment; filename=\"' . $filename . '\"; filename*=UTF-8\\'\\'' . $encodedFilename);\n            }\n\n            // 写入文件内容\n            $response->getBody()->write($fileContent);\n\n            return $response;\n        } catch (\\Exception $e) {\n            error_log(\"Export HTML Error: \" . $e->getMessage());\n            return $this->error($response, 10101, '导出失败: ' . $e->getMessage());\n        } finally {\n            // 清理临时文件\n            $this->clearTempDir($tempDir);\n        }\n    }\n\n    /**\n     * 收集所有页面（扁平化）\n     */\n    private function collectAllPages(array $menu): array\n    {\n        $pages = [];\n\n        // 根目录下的页面\n        if (!empty($menu['pages'])) {\n            foreach ($menu['pages'] as $page) {\n                $pages[] = $page;\n            }\n        }\n\n        // 递归收集目录下的页面\n        if (!empty($menu['catalogs'])) {\n            $this->collectPagesFromCatalogs($menu['catalogs'], $pages);\n        }\n\n        return $pages;\n    }\n\n    /**\n     * 从目录中递归收集页面\n     */\n    private function collectPagesFromCatalogs(array $catalogs, array &$pages): void\n    {\n        foreach ($catalogs as $cat) {\n            if (!empty($cat['pages'])) {\n                foreach ($cat['pages'] as $page) {\n                    $pages[] = $page;\n                }\n            }\n            if (!empty($cat['catalogs'])) {\n                $this->collectPagesFromCatalogs($cat['catalogs'], $pages);\n            }\n        }\n    }\n\n    /**\n     * 生成所有页面的HTML\n     */\n    private function generatePagesHtml(array $pages, array $item, string $tempDir): void\n    {\n        // 引入 Parsedown 类（Markdown 解析器）\n        if (!class_exists('Parsedown')) {\n            require_once __DIR__ . '/../../Common/Vendor/Parsedown.php';\n        }\n        $parsedown = new \\Parsedown();\n        $convert = new Convert();\n\n        foreach ($pages as $page) {\n            // 确保 page_id 存在且有效\n            if (empty($page['page_id'])) {\n                continue;\n            }\n            // 统一获取page_id，确保后续使用一致\n            $pageId = (int) $page['page_id'];\n            if ($pageId <= 0) {\n                continue;\n            }\n            // 将page_id传递给生成方法，避免重复获取导致不一致\n            $html = $this->generatePageHtml($page, $item, $parsedown, $convert, $pageId);\n            $filePath = $tempDir . '/pages/page-' . $pageId . '.html';\n            file_put_contents($filePath, $html);\n        }\n    }\n\n    /**\n     * 生成单个页面HTML\n     */\n    private function generatePageHtml(array $page, array $item, \\Parsedown $parsedown, Convert $convert, int $pageId): string\n    {\n        $pageTitle = htmlspecialchars($page['page_title'] ?? '', ENT_QUOTES, 'UTF-8');\n        $itemName = htmlspecialchars($item['item_name'] ?? '', ENT_QUOTES, 'UTF-8');\n\n        // 处理内容\n        $pageContent = $page['page_content'] ?? '';\n\n        // RunAPI项目转换\n        if (($item['item_type'] ?? 0) == 3) {\n            $mdContent = $convert->runapiToMd($pageContent);\n            if ($mdContent) {\n                $pageContent = $mdContent;\n            }\n        }\n\n        // Markdown转HTML\n        $htmlContent = $parsedown->text($pageContent);\n\n        // 转义还原（数据库内容经过了html转义，需还原以正确显示）\n        $htmlContent = htmlspecialchars_decode($htmlContent);\n\n        // HTML安全过滤\n        $htmlContent = $this->sanitizeHtml($htmlContent);\n\n        // 图片路径重写\n        $htmlContent = $this->rewriteImagePaths($htmlContent);\n\n        // 生成HTML\n        $html = '<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>' . $pageTitle . ' - ' . $itemName . '</title>\n    <link rel=\"stylesheet\" href=\"../assets/css/common.css\">\n    <link rel=\"stylesheet\" href=\"../assets/css/highlight.css\">\n</head>\n<body>\n    <div class=\"header\">\n        <div class=\"header-content\">\n            <h1 class=\"project-name\">' . $itemName . '</h1>\n            <div class=\"search-box\">\n                <input type=\"text\" id=\"searchInput\" placeholder=\"搜索页面...\">\n                <div id=\"searchResults\" class=\"search-results\"></div>\n            </div>\n            <button class=\"menu-toggle\" id=\"menuToggle\">☰</button>\n        </div>\n    </div>\n    <div class=\"container\">\n        <aside class=\"sidebar\" id=\"sidebar\">\n            <div id=\"catalogTree\" class=\"catalog-tree\"></div>\n        </aside>\n        <main class=\"main-content\">\n            <article class=\"page-content\">\n                <h1 class=\"page-title\">' . $pageTitle . '</h1>\n                <div class=\"markdown-body\">' . $htmlContent . '</div>\n                <div class=\"page-nav\" id=\"pageNav\"></div>\n            </article>\n        </main>\n    </div>\n    <script src=\"../assets/js/data.js\"></script>\n    <script src=\"../assets/js/search-index.js\"></script>\n    <script src=\"../assets/js/app.js\"></script>\n    <script src=\"../assets/js/highlight.min.js\"></script>\n    <script>\n        if (typeof hljs !== \"undefined\") {\n            hljs.highlightAll();\n        }\n        // 设置当前页面ID（使用字符串形式，避免大整数精度丢失）\n        window.CURRENT_PAGE_ID = \\'' . $pageId . '\\';\n    </script>\n</body>\n</html>';\n\n        return $html;\n    }\n\n    /**\n     * 生成首页HTML\n     */\n    private function generateIndexHtml(array $item, string $tempDir): void\n    {\n        $itemName = htmlspecialchars($item['item_name'] ?? '', ENT_QUOTES, 'UTF-8');\n        $itemDescription = htmlspecialchars($item['item_description'] ?? '', ENT_QUOTES, 'UTF-8');\n\n        $html = '<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>' . $itemName . ' - 项目概览</title>\n    <link rel=\"stylesheet\" href=\"assets/css/common.css\">\n    <link rel=\"stylesheet\" href=\"assets/css/highlight.css\">\n</head>\n<body>\n    <div class=\"header\">\n        <div class=\"header-content\">\n            <h1 class=\"project-name\">' . $itemName . '</h1>\n            <div class=\"search-box\">\n                <input type=\"text\" id=\"searchInput\" placeholder=\"搜索页面...\">\n                <div id=\"searchResults\" class=\"search-results\"></div>\n            </div>\n            <button class=\"menu-toggle\" id=\"menuToggle\">☰</button>\n        </div>\n    </div>\n    <div class=\"container\">\n        <aside class=\"sidebar\" id=\"sidebar\">\n            <div id=\"catalogTree\" class=\"catalog-tree\"></div>\n        </aside>\n        <main class=\"main-content\">\n            <article class=\"page-content\">\n                <h1 class=\"page-title\">' . $itemName . '</h1>\n                ' . ($itemDescription ? '<p class=\"project-description\">' . $itemDescription . '</p>' : '') . '\n                <div class=\"project-overview\">\n                    <p>这是一个离线HTML文档包，您可以在浏览器中离线浏览所有文档。</p>\n                    <p>使用左侧目录树导航，或使用顶部搜索框快速查找内容。</p>\n                </div>\n            </article>\n        </main>\n    </div>\n    <script src=\"assets/js/data.js\"></script>\n    <script src=\"assets/js/search-index.js\"></script>\n    <script src=\"assets/js/app.js\"></script>\n    <script>\n        window.CURRENT_PAGE_ID = \\'0\\';\n    </script>\n</body>\n</html>';\n\n        file_put_contents($tempDir . '/index.html', $html);\n    }\n\n    /**\n     * 生成data.js文件\n     */\n    private function generateDataJs(array $menu, array $item, array $allPages, string $tempDir): void\n    {\n        // 收集所有目录（扁平化）\n        $allCatalogs = $this->collectAllCatalogs($menu);\n\n        // 构建页面列表\n        $pagesList = [];\n        foreach ($allPages as $page) {\n            // 确保 page_id 存在且有效\n            if (empty($page['page_id'])) {\n                continue;\n            }\n            $pageId = (int) $page['page_id'];\n            if ($pageId <= 0) {\n                continue;\n            }\n            // page_id 使用字符串形式，避免JavaScript大整数精度丢失\n            $pagesList[] = [\n                'page_id' => (string) $pageId,\n                'page_title' => $page['page_title'] ?? '',\n                'cat_id' => (int) ($page['cat_id'] ?? 0),\n                's_number' => (int) ($page['s_number'] ?? 0),\n                'file_path' => 'pages/page-' . $pageId . '.html'\n            ];\n        }\n\n        // 构建目录列表\n        $catalogsList = [];\n        foreach ($allCatalogs as $cat) {\n            $catalogsList[] = [\n                'cat_id' => (int) ($cat['cat_id'] ?? 0),\n                'cat_name' => $cat['cat_name'] ?? '',\n                'parent_cat_id' => (int) ($cat['parent_cat_id'] ?? 0),\n                'level' => (int) ($cat['level'] ?? 2),\n                's_number' => (int) ($cat['s_number'] ?? 0)\n            ];\n        }\n\n        $data = [\n            'item_id' => (int) ($item['item_id'] ?? 0),\n            'item_name' => $item['item_name'] ?? '',\n            'item_type' => $item['item_type'] ?? 0,\n            'item_description' => $item['item_description'] ?? '',\n            'catalogs' => $catalogsList,\n            'pages' => $pagesList\n        ];\n\n        $jsContent = 'window.PROJECT_DATA = ' . json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . ';';\n        file_put_contents($tempDir . '/assets/js/data.js', $jsContent);\n    }\n\n    /**\n     * 收集所有目录（扁平化）\n     */\n    private function collectAllCatalogs(array $menu): array\n    {\n        $catalogs = [];\n\n        if (!empty($menu['catalogs'])) {\n            $this->collectCatalogsRecursive($menu['catalogs'], $catalogs);\n        }\n\n        return $catalogs;\n    }\n\n    /**\n     * 递归收集目录\n     */\n    private function collectCatalogsRecursive(array $catalogsList, array &$result): void\n    {\n        foreach ($catalogsList as $cat) {\n            $result[] = [\n                'cat_id' => $cat['cat_id'] ?? 0,\n                'cat_name' => $cat['cat_name'] ?? '',\n                'parent_cat_id' => $cat['parent_cat_id'] ?? 0,\n                'level' => $cat['level'] ?? 2,\n                's_number' => $cat['s_number'] ?? 0\n            ];\n            if (!empty($cat['catalogs'])) {\n                $this->collectCatalogsRecursive($cat['catalogs'], $result);\n            }\n        }\n    }\n\n    /**\n     * 生成搜索索引\n     */\n    private function generateSearchIndex(array $pages, string $tempDir): void\n    {\n        $index = [];\n\n        foreach ($pages as $page) {\n            // 确保 page_id 存在且有效\n            if (empty($page['page_id'])) {\n                continue;\n            }\n            $pageId = (int) $page['page_id'];\n            if ($pageId <= 0) {\n                continue;\n            }\n            // 先还原转义再提取文本\n            $decoded = htmlspecialchars_decode($page['page_content'] ?? '');\n            $content = strip_tags($decoded);\n            $contentPreview = mb_substr($content, 0, 200);\n\n            // page_id 使用字符串形式，避免JavaScript大整数精度丢失\n            $index[] = [\n                'page_id' => (string) $pageId,\n                'page_title' => $page['page_title'] ?? '',\n                'content_preview' => $contentPreview,\n                'cat_id' => (int) ($page['cat_id'] ?? 0)\n            ];\n        }\n\n        $jsContent = 'window.SEARCH_INDEX = ' . json_encode($index, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . ';';\n        file_put_contents($tempDir . '/assets/js/search-index.js', $jsContent);\n    }\n\n    /**\n     * 复制静态文件（CSS/JS）\n     */\n    private function copyStaticFiles(string $tempDir): void\n    {\n        // 获取项目根目录（server目录的父目录）\n        $rootPath = dirname(dirname(dirname(dirname(__DIR__))));\n        // 获取 server 目录\n        $serverPath = dirname(dirname(dirname(__DIR__)));\n\n        // 复制highlight.js（在项目根目录的 Public 目录下）\n        $highlightJs = $rootPath . '/Public/highlight/highlight.min.js';\n        $targetJs = $tempDir . '/assets/js/highlight.min.js';\n        if (file_exists($highlightJs)) {\n            if (!copy($highlightJs, $targetJs)) {\n                error_log(\"Export HTML: Failed to copy highlight.js from {$highlightJs} to {$targetJs}\");\n            } elseif (!file_exists($targetJs)) {\n                error_log(\"Export HTML: highlight.js copy failed, target file not exists: {$targetJs}\");\n            }\n        } else {\n            error_log(\"Export HTML: highlight.js not found: \" . $highlightJs);\n        }\n\n        // 复制highlight.css（在项目根目录的 Public 目录下）\n        $highlightCss = $rootPath . '/Public/highlight/default.min.css';\n        $targetCss = $tempDir . '/assets/css/highlight.css';\n        if (file_exists($highlightCss)) {\n            if (!copy($highlightCss, $targetCss)) {\n                error_log(\"Export HTML: Failed to copy highlight.css from {$highlightCss} to {$targetCss}\");\n            } elseif (!file_exists($targetCss)) {\n                error_log(\"Export HTML: highlight.css copy failed, target file not exists: {$targetCss}\");\n            }\n        } else {\n            error_log(\"Export HTML: highlight.css not found: \" . $highlightCss);\n        }\n\n        // 生成common.css和app.js（在 server/app/Static 目录下）\n        $this->generateCommonCss($tempDir, $serverPath);\n        $this->generateAppJs($tempDir, $serverPath);\n    }\n\n    /**\n     * 生成common.css\n     */\n    private function generateCommonCss(string $tempDir, string $serverPath): void\n    {\n        // $serverPath 是 server 目录，所以使用 app/Static\n        $cssFile = $serverPath . '/app/Static/export-html/common.css';\n        $targetCss = $tempDir . '/assets/css/common.css';\n        if (file_exists($cssFile)) {\n            $css = file_get_contents($cssFile);\n            if ($css === false) {\n                error_log(\"Export HTML: Failed to read CSS file: \" . $cssFile);\n                return;\n            }\n            if (file_put_contents($targetCss, $css) === false) {\n                error_log(\"Export HTML: Failed to write CSS file: \" . $targetCss);\n            } elseif (!file_exists($targetCss) || filesize($targetCss) === 0) {\n                error_log(\"Export HTML: CSS file write failed or empty: \" . $targetCss);\n            }\n        } else {\n            error_log(\"Export HTML: CSS file not found: \" . $cssFile);\n        }\n    }\n\n    /**\n     * 生成app.js\n     */\n    private function generateAppJs(string $tempDir, string $serverPath): void\n    {\n        // $serverPath 是 server 目录，所以使用 app/Static\n        $jsFile = $serverPath . '/app/Static/export-html/app.js';\n        $targetJs = $tempDir . '/assets/js/app.js';\n        if (file_exists($jsFile)) {\n            $js = file_get_contents($jsFile);\n            if ($js === false) {\n                error_log(\"Export HTML: Failed to read JS file: \" . $jsFile);\n                return;\n            }\n            if (file_put_contents($targetJs, $js) === false) {\n                error_log(\"Export HTML: Failed to write JS file: \" . $targetJs);\n            } elseif (!file_exists($targetJs) || filesize($targetJs) === 0) {\n                error_log(\"Export HTML: JS file write failed or empty: \" . $targetJs);\n            }\n        } else {\n            error_log(\"Export HTML: JS file not found: \" . $jsFile);\n        }\n    }\n\n    /**\n     * 复制图片和附件\n     */\n    private function copyAssets(array $pages, string $tempDir): void\n    {\n        // 获取项目根目录（server目录的父目录）\n        $rootPath = dirname(dirname(dirname(dirname(__DIR__))));\n        $uploadsDir = $rootPath . '/Public/Uploads';\n        $targetDir = $tempDir . '/assets/uploads';\n\n        if (!is_dir($uploadsDir)) {\n            return;\n        }\n\n        // 从页面内容中提取图片路径\n        $imagePaths = [];\n        foreach ($pages as $page) {\n            $content = $page['page_content'] ?? '';\n            // 匹配 /Public/Uploads/xxx 格式的路径\n            preg_match_all('/\\/Public\\/Uploads\\/([^\\s\"\\'\\)]+)/', $content, $matches);\n            if (!empty($matches[1])) {\n                foreach ($matches[1] as $imgPath) {\n                    $imagePaths[$imgPath] = true;\n                }\n            }\n        }\n\n        // 复制图片文件\n        foreach (array_keys($imagePaths) as $imgPath) {\n            $source = $uploadsDir . '/' . $imgPath;\n            if (file_exists($source) && is_file($source)) {\n                $target = $targetDir . '/' . basename($imgPath);\n                // 确保目录存在\n                $targetDirPath = dirname($target);\n                if (!is_dir($targetDirPath)) {\n                    mkdir($targetDirPath, 0755, true);\n                }\n                copy($source, $target);\n            }\n        }\n    }\n\n    /**\n     * 生成README文件\n     */\n    private function generateReadme(array $item, string $tempDir): void\n    {\n        $itemName = htmlspecialchars($item['item_name'] ?? '', ENT_QUOTES, 'UTF-8');\n        $readme = \"ShowDoc 离线HTML文档包\n====================\n\n项目名称: {$itemName}\n导出时间: \" . date('Y-m-d H:i:s') . \"\n\n使用说明:\n---------\n1. 解压此压缩包到任意目录\n2. 用浏览器打开 index.html 文件\n3. 使用左侧目录树导航，或使用顶部搜索框查找内容\n4. 所有资源已包含在压缩包中，可完全离线使用\n\n注意事项:\n---------\n- 此文档包为只读版本，无法编辑\n- 建议使用现代浏览器（Chrome、Firefox、Edge、Safari）\n- 如需更新文档，请重新导出\n\n\";\n        file_put_contents($tempDir . '/README.txt', $readme);\n    }\n\n    /**\n     * HTML安全过滤\n     */\n    private function sanitizeHtml(string $html): string\n    {\n        // 移除script标签\n        $html = preg_replace('/<script\\b[^<]*(?:(?!<\\/script>)<[^<]*)*<\\/script>/mi', '', $html);\n\n        // 移除事件处理器\n        $html = preg_replace('/\\s*on\\w+\\s*=\\s*[\"\\'][^\"\\']*[\"\\']/i', '', $html);\n        $html = preg_replace('/\\s*on\\w+\\s*=\\s*[^\\s>]+/i', '', $html);\n\n        // 过滤危险协议\n        $html = preg_replace('/href\\s*=\\s*[\"\\'](javascript|data):/i', 'href=\"#\"', $html);\n        $html = preg_replace('/src\\s*=\\s*[\"\\'](javascript|data):/i', 'src=\"#\"', $html);\n\n        return $html;\n    }\n\n    /**\n     * 重写图片路径\n     */\n    private function rewriteImagePaths(string $html): string\n    {\n        // 处理图片路径：/Public/Uploads/xxx 转换为相对路径\n        $html = preg_replace_callback(\n            '/src\\s*=\\s*[\"\\']([^\"\\']*\\/Public\\/Uploads\\/[^\"\\']+)[\"\\']/i',\n            function ($matches) {\n                $path = $matches[1];\n                $filename = basename($path);\n                return 'src=\"../assets/uploads/' . $filename . '\"';\n            },\n            $html\n        );\n\n        return $html;\n    }\n\n    /**\n     * 清理文件名\n     */\n    private function sanitizeFilename(string $filename): string\n    {\n        $filename = trim($filename);\n        $filename = preg_replace('/[<>:\"\\/\\\\\\|\\?\\*\\x00-\\x1F]/', '_', $filename);\n        $filename = preg_replace('/[_\\.]+/', '_', $filename);\n        $filename = trim($filename, '_.');\n        if (empty($filename)) {\n            $filename = 'unnamed';\n        }\n        if (mb_strlen($filename) > 200) {\n            $filename = mb_substr($filename, 0, 200);\n        }\n        return $filename;\n    }\n\n    /**\n     * 打包ZIP\n     */\n    private function zip(string $fromName, string $toName): bool\n    {\n        if (!file_exists($fromName) || !is_dir($fromName)) {\n            return false;\n        }\n\n        $zipArc = new \\ZipArchive();\n        if (!$zipArc->open($toName, \\ZipArchive::CREATE)) {\n            return false;\n        }\n\n        $this->addDirectoryToZip($fromName, $zipArc, '');\n        return $zipArc->close();\n    }\n\n    /**\n     * 递归添加目录到ZIP\n     */\n    private function addDirectoryToZip(string $dir, \\ZipArchive $zipArc, string $zipPath): void\n    {\n        $files = scandir($dir);\n        foreach ($files as $file) {\n            if ($file == '.' || $file == '..') {\n                continue;\n            }\n\n            $filePath = $dir . '/' . $file;\n            $zipFilePath = $zipPath ? $zipPath . '/' . $file : $file;\n\n            if (is_dir($filePath)) {\n                $this->addDirectoryToZip($filePath, $zipArc, $zipFilePath);\n            } else {\n                $zipArc->addFile($filePath, $zipFilePath);\n            }\n        }\n    }\n\n    /**\n     * 清理临时目录\n     */\n    private function clearTempDir(string $dir): void\n    {\n        if (!is_dir($dir)) {\n            return;\n        }\n\n        $files = array_diff(scandir($dir), ['.', '..']);\n        foreach ($files as $file) {\n            $path = $dir . '/' . $file;\n            if (is_dir($path)) {\n                $this->clearTempDir($path);\n            } else {\n                unlink($path);\n            }\n        }\n        rmdir($dir);\n    }\n\n    /**\n     * 验证页面ID一致性\n     * 确保生成的文件名和data.js中的page_id完全一致\n     */\n    private function validatePageIds(array $allPages, string $tempDir): void\n    {\n        // 读取生成的data.js文件\n        $dataJsFile = $tempDir . '/assets/js/data.js';\n        if (!file_exists($dataJsFile)) {\n            error_log(\"Export HTML: data.js file not found for validation\");\n            return;\n        }\n\n        $dataJsContent = file_get_contents($dataJsFile);\n        // 提取PROJECT_DATA中的pages数组\n        if (preg_match('/window\\.PROJECT_DATA\\s*=\\s*({.*?});/s', $dataJsContent, $matches)) {\n            $dataJson = $matches[1];\n            $data = json_decode($dataJson, true);\n\n            if ($data && isset($data['pages'])) {\n                $dataPages = $data['pages'];\n                $dataPageIds = [];\n                foreach ($dataPages as $dp) {\n                    $dataPageIds[] = (string) ($dp['page_id'] ?? '');\n                }\n\n                // 检查实际生成的文件\n                $pagesDir = $tempDir . '/pages';\n                if (is_dir($pagesDir)) {\n                    $files = scandir($pagesDir);\n                    $filePageIds = [];\n                    foreach ($files as $file) {\n                        if (preg_match('/^page-(\\d+)\\.html$/', $file, $matches)) {\n                            $filePageIds[] = $matches[1];\n                        }\n                    }\n\n                    // 验证：data.js中的page_id应该和实际文件一致\n                    $missingInData = array_diff($filePageIds, $dataPageIds);\n                    $missingInFiles = array_diff($dataPageIds, $filePageIds);\n\n                    if (!empty($missingInData)) {\n                        error_log(\"Export HTML Validation: Files exist but not in data.js: \" . implode(', ', $missingInData));\n                    }\n                    if (!empty($missingInFiles)) {\n                        error_log(\"Export HTML Validation: page_id in data.js but file missing: \" . implode(', ', $missingInFiles));\n                    }\n\n                    // 验证原始数据中的page_id\n                    $originalPageIds = [];\n                    foreach ($allPages as $page) {\n                        if (!empty($page['page_id'])) {\n                            $pid = (int) $page['page_id'];\n                            if ($pid > 0) {\n                                $originalPageIds[] = (string) $pid;\n                            }\n                        }\n                    }\n\n                    // 检查是否有page_id不一致\n                    $missingInOriginal = array_diff($dataPageIds, $originalPageIds);\n                    if (!empty($missingInOriginal)) {\n                        error_log(\"Export HTML Validation: page_id in data.js but not in original data: \" . implode(', ', $missingInOriginal));\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "server/app/Api/Controller/ExtLoginController.php",
    "content": "<?php\n\nnamespace App\\Api\\Controller;\n\nuse App\\Common\\BaseController;\nuse App\\Common\\Helper\\UrlHelper;\nuse App\\Model\\Options;\nuse App\\Model\\User;\nuse App\\Model\\UserToken;\nuse Illuminate\\Database\\Capsule\\Manager as DB;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\nuse League\\OAuth2\\Client\\Provider\\GenericProvider;\nuse GuzzleHttp\\Client;\n\n/**\n * 企业认证登录控制器\n * 支持：SecretKey、OAuth2、CAS 登录\n */\nclass ExtLoginController extends BaseController\n{\n    /**\n     * 检查 PHP 版本是否满足 Composer 包要求\n     * \n     * @return bool 是否满足要求\n     */\n    private function checkComposerPHPVersion(): bool\n    {\n        // OAuth2 和 CAS 需要 PHP 7.0+\n        if (version_compare(PHP_VERSION, '7.0.0', '<=')) {\n            return false;\n        }\n        return true;\n    }\n\n    /**\n     * SecretKey 登录\n     * \n     * 根据用户名和 LoginSecretKey 登录\n     */\n    public function bySecretKey(Request $request, Response $response): Response\n    {\n        $username = $this->getParam($request, 'username', '');\n        $key = $this->getParam($request, 'key', '');\n        $time = $this->getParam($request, 'time', 0);\n        $token = $this->getParam($request, 'token', '');\n        $redirect = $this->getParam($request, 'redirect', '');\n        $name = $this->getParam($request, 'name', '');\n\n        if ($time < (time() - 60)) {\n            return $this->error($response, 10101, '已过期');\n        }\n\n        $loginSecretKey = Options::get('login_secret_key');\n        if (!$loginSecretKey) {\n            return $this->error($response, 10101, '未配置 SecretKey');\n        }\n\n        $newToken = md5($username . $loginSecretKey . $time);\n        if ($token !== $newToken) {\n            return $this->error($response, 10101, 'token不正确');\n        }\n\n        // 查找或创建用户（仅按用户名查找，不包含邮箱）\n        $user = User::findByUsername($username);\n        if (!$user) {\n            $newUid = User::register($username, md5('savsnyjh' . time() . rand()));\n            if (!$newUid) {\n                return $this->error($response, 10101, '用户注册失败');\n            }\n            $user = User::findById($newUid);\n            if ($name && $user) {\n                User::updateName($newUid, $name);\n                $user = User::findById($newUid);\n            }\n        }\n\n        if (!$user) {\n            return $this->error($response, 10101, '用户不存在');\n        }\n\n        // 禁止管理员通过这种方式登录\n        if ((int) ($user->groupid ?? 0) === 1) {\n            return $this->error($response, 10101, '为了安全，禁止管理员通过这种方式登录');\n        }\n\n        $uid = (int) $user->uid;\n        if ($name) {\n            User::updateName($uid, $name);\n        }\n\n        User::setLastTime($uid);\n\n        // 生成 token\n        $tokenTtl = 60 * 60 * 24 * 180; // 180 天\n        $userToken = UserToken::createToken($uid, $tokenTtl);\n\n        // 重定向到 LoginByUserToken 页面，让前端处理 localStorage 和 cookie\n        $baseUrl = UrlHelper::siteUrl();\n        $redirectUri = $redirect ? urldecode($redirect) : '/item/index';\n        $loginUrl = $baseUrl . '/web/#/user/loginByUserToken?user_token=' . urlencode($userToken) . '&redirect_uri=' . urlencode($redirectUri);\n        return $response->withStatus(302)->withHeader('Location', $loginUrl);\n    }\n\n    /**\n     * 从 OAuth2 返回的用户信息中提取用户名\n     * \n     * @param array $array 用户信息数组\n     * @return string|false 用户名或 false\n     */\n    private function getUserNameFromOAuth2(array $array)\n    {\n        $keysToCheck = [\"preferred_username\", \"name\", \"username\", \"login\"];\n\n        foreach ($array as $key => $value) {\n            if (!is_array($value) && in_array($key, $keysToCheck, true)) {\n                if ($value) {\n                    return $value;\n                }\n            }\n        }\n\n        foreach ($array as $value) {\n            if (is_array($value)) {\n                $username = $this->getUserNameFromOAuth2($value);\n                if ($username) {\n                    return $username;\n                }\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * OAuth2 登录\n     */\n    public function oauth2(Request $request, Response $response): Response\n    {\n        if (!$this->checkComposerPHPVersion()) {\n            return $this->error($response, 10101, '该功能需要 PHP 7.0 以上版本');\n        }\n\n        $redirect = $this->getParam($request, 'redirect', '');\n        if ($redirect) {\n            $_SESSION['redirect'] = $redirect;\n        }\n\n        $oauth2Open = Options::get('oauth2_open');\n        $oauth2Form = Options::get('oauth2_form');\n        $oauth2Form = htmlspecialchars_decode($oauth2Form);\n        $oauth2Form = json_decode($oauth2Form, true);\n\n        if (!$oauth2Open || !$oauth2Form) {\n            return $this->error($response, 10101, '尚未启用 OAuth2');\n        }\n\n        $clientId = $oauth2Form['client_id'] ?? '';\n        $clientSecret = $oauth2Form['client_secret'] ?? '';\n        $redirectUri = $oauth2Form['redirectUri'] ?? '';\n        $urlAuthorize = $oauth2Form['protocol'] . \"://\" . $oauth2Form['host'] . $oauth2Form['authorize_path'];\n        $urlAccessToken = $oauth2Form['protocol'] . \"://\" . $oauth2Form['host'] . $oauth2Form['token_path'];\n        $urlResourceOwnerDetails = $oauth2Form['protocol'] . \"://\" . $oauth2Form['host'] . $oauth2Form['resource_path'];\n        \n        if (strstr($oauth2Form['userinfo_path'] ?? '', \"://\")) {\n            $urlUserInfo = $oauth2Form['userinfo_path'];\n        } else {\n            $urlUserInfo = $oauth2Form['protocol'] . \"://\" . $oauth2Form['host'] . $oauth2Form['userinfo_path'];\n        }\n\n        $provider = new GenericProvider([\n            'clientId' => $clientId,\n            'clientSecret' => $clientSecret,\n            'redirectUri' => $redirectUri,\n            'urlAuthorize' => $urlAuthorize,\n            'urlAccessToken' => $urlAccessToken,\n            'urlResourceOwnerDetails' => $urlResourceOwnerDetails,\n        ], [\n            'httpClient' => new Client(['verify' => false]),\n        ]);\n\n        // 如果没有授权码，获取授权 URL\n        $code = $this->getParam($request, 'code', '');\n        if (!$code) {\n            $authorizationUrl = $provider->getAuthorizationUrl();\n            $_SESSION['oauth2state'] = $provider->getState();\n            return $response->withStatus(302)->withHeader('Location', $authorizationUrl);\n        }\n\n        // 检查 state 参数（CSRF 防护）\n        $state = $this->getParam($request, 'state', '');\n        if (empty($state) || (isset($_SESSION['oauth2state']) && $state !== $_SESSION['oauth2state'])) {\n            if (isset($_SESSION['oauth2state'])) {\n                unset($_SESSION['oauth2state']);\n            }\n            return $this->error($response, 10101, 'Invalid state');\n        }\n\n        try {\n            // 获取 access token\n            $accessToken = $provider->getAccessToken('authorization_code', [\n                'code' => $code\n            ]);\n\n            $accessTokenString = $accessToken->getToken();\n\n            // 兼容 GitLab：GitLab 不允许同时通过 URL 参数和 Header 传递 token\n            $isGitlab = false;\n            if (\n                (isset($oauth2Form['host']) && stripos($oauth2Form['host'], 'gitlab') !== false)\n                || stripos($urlUserInfo, 'gitlab') !== false\n                || stripos($urlAccessToken, 'gitlab') !== false\n            ) {\n                $isGitlab = true;\n            }\n\n            if ($isGitlab) {\n                $userInfoUrl = $urlUserInfo;\n                $curlHeaders = [\n                    \"Authorization: Bearer {$accessTokenString}\",\n                    \"user-agent: showdoc\",\n                    \"accept:application/json\"\n                ];\n            } else {\n                $userInfoUrl = $urlUserInfo . \"?access_token=\" . $accessTokenString;\n                $curlHeaders = [\n                    \"Authorization: bearer {$accessTokenString}\",\n                    \"user-agent: showdoc\",\n                    \"accept:application/json\"\n                ];\n            }\n\n            // 获取用户信息\n            $oCurl = curl_init();\n            curl_setopt($oCurl, CURLOPT_URL, $userInfoUrl);\n            curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, 1);\n            curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, false);\n            curl_setopt($oCurl, CURLOPT_SSL_VERIFYHOST, false);\n            curl_setopt($oCurl, CURLOPT_HEADER, 0);\n            curl_setopt($oCurl, CURLOPT_HTTPHEADER, $curlHeaders);\n            $res = curl_exec($oCurl);\n            curl_close($oCurl);\n\n            $resArray = json_decode($res, true);\n            if (!$resArray) {\n                return $this->error($response, 10101, '登录成功但无法获取用户信息。返回内容如下：' . $res);\n            }\n\n            $username = $this->getUserNameFromOAuth2($resArray);\n            if (!$username) {\n                return $this->error($response, 10101, '返回信息中无法获取用户名。返回的内容如下：' . $res);\n            }\n\n            // 查找或创建用户\n            $user = User::findByUsername($username);\n            if (!$user) {\n                $newUid = User::register($username, md5($username . time() . rand()));\n                if (!$newUid) {\n                    return $this->error($response, 10101, '用户注册失败');\n                }\n                $user = User::findById($newUid);\n                if (isset($resArray['name']) && $resArray['name']) {\n                    User::updateName($newUid, $resArray['name']);\n                    $user = User::findById($newUid);\n                }\n            } else {\n                // 更新用户姓名（如果 OAuth2 返回了 name）\n                if (isset($resArray['name']) && $resArray['name']) {\n                    User::updateName((int) $user->uid, $resArray['name']);\n                }\n            }\n\n            if (!$user) {\n                return $this->error($response, 10101, '用户不存在');\n            }\n\n            User::setLastTime((int) $user->uid);\n\n            // 生成 token\n            $tokenTtl = 60 * 60 * 24 * 180; // 180 天\n            $userToken = UserToken::createToken((int) $user->uid, $tokenTtl);\n\n            // 重定向到 LoginByUserToken 页面，让前端处理 localStorage 和 cookie\n            $baseUrl = UrlHelper::siteUrl();\n            $redirectUri = isset($_SESSION['redirect']) && $_SESSION['redirect'] ? urldecode($_SESSION['redirect']) : '/item/index';\n            if (isset($_SESSION['redirect'])) {\n                unset($_SESSION['redirect']);\n            }\n            $loginUrl = $baseUrl . '/web/#/user/loginByUserToken?user_token=' . urlencode($userToken) . '&redirect_uri=' . urlencode($redirectUri);\n            return $response->withStatus(302)->withHeader('Location', $loginUrl);\n        } catch (\\League\\OAuth2\\Client\\Provider\\Exception\\IdentityProviderException $e) {\n            return $this->error($response, 10101, $e->getMessage());\n        }\n    }\n\n    /**\n     * CAS 单点登录\n     */\n    public function cas(Request $request, Response $response): Response\n    {\n        if (!$this->checkComposerPHPVersion()) {\n            return $this->error($response, 10101, '该功能需要 PHP 7.0 以上版本');\n        }\n\n        // CAS 配置从 Options 读取\n        $casOpen = Options::get('cas_open');\n        $casForm = Options::get('cas_form');\n        $casForm = htmlspecialchars_decode($casForm);\n        $casForm = json_decode($casForm, true);\n\n        if (!$casOpen || !$casForm) {\n            return $this->error($response, 10101, '尚未启用 CAS');\n        }\n\n        define(\"CAS_VERSION_1_0\", '1.0');\n        define(\"CAS_VERSION_2_0\", '2.0');\n        define(\"CAS_VERSION_3_0\", '3.0');\n\n        // 开启 phpCAS debug（可选）\n        // \\phpCAS::setDebug();\n\n        // 初始化 phpCAS\n        $casVersion = $casForm['version'] ?? CAS_VERSION_2_0;\n        $casHost = $casForm['host'] ?? '';\n        $casPort = (int) ($casForm['port'] ?? 443);\n        $casPath = $casForm['path'] ?? '/cas';\n        $casServiceUrl = \\App\\Common\\Helper\\UrlHelper::siteUrl() . '/server/index.php?s=Api/ExtLogin/cas';\n\n        \\phpCAS::client($casVersion, $casHost, $casPort, $casPath, $casServiceUrl);\n\n        // 设置 SSL 验证（可选）\n        if (isset($casForm['ca_cert_path']) && $casForm['ca_cert_path']) {\n            \\phpCAS::setCasServerCACert($casForm['ca_cert_path']);\n        } else {\n            \\phpCAS::setNoCasServerValidation();\n        }\n\n        // 处理登出请求\n        \\phpCAS::handleLogoutRequests();\n\n        // 强制认证\n        \\phpCAS::forceAuthentication();\n\n        // 获取用户名\n        $userName = \\phpCAS::getUser();\n        if (!$userName) {\n            return $this->error($response, 10101, 'CAS 认证失败');\n        }\n\n        // 查找或创建用户\n        $user = User::findByUsername($userName);\n        if (!$user) {\n            $newUid = User::register($userName, md5($userName . time() . rand()));\n            if (!$newUid) {\n                return $this->error($response, 10101, '用户注册失败');\n            }\n            $user = User::findById($newUid);\n\n            // 尝试获取用户属性（如姓名）\n            $attrs = \\phpCAS::getAttributes();\n            if (isset($attrs['name']) && $attrs['name']) {\n                User::updateName($newUid, $attrs['name']);\n                $user = User::findById($newUid);\n            }\n        }\n\n        if (!$user) {\n            return $this->error($response, 10101, '用户不存在');\n        }\n\n        User::setLastTime((int) $user->uid);\n\n        // 生成 token\n        $tokenTtl = 60 * 60 * 24 * 180; // 180 天\n        $userToken = UserToken::createToken((int) $user->uid, $tokenTtl);\n\n        // 重定向到 LoginByUserToken 页面，让前端处理 localStorage 和 cookie\n        $baseUrl = UrlHelper::siteUrl();\n        $loginUrl = $baseUrl . '/web/#/user/loginByUserToken?user_token=' . urlencode($userToken) . '&redirect_uri=' . urlencode('/item/index');\n        return $response->withStatus(302)->withHeader('Location', $loginUrl);\n    }\n}\n\n"
  },
  {
    "path": "server/app/Api/Controller/FlowController.php",
    "content": "<?php\n\nnamespace App\\Api\\Controller;\n\nuse App\\Common\\BaseController;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\nuse App\\Model\\RunapiFlow;\nuse App\\Model\\RunapiFlowPage;\nuse App\\Model\\RunapiEnv;\nuse App\\Model\\Page;\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\n/**\n * 流程相关 Api（新架构）。\n */\nclass FlowController extends BaseController\n{\n    private $pages = null;\n\n    /**\n     * 保存流程（兼容旧接口 Api/Flow/save）。\n     */\n    public function save(Request $request, Response $response): Response\n    {\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $id = $this->getParam($request, 'id', 0);\n        $flowName = $this->getParam($request, 'flow_name', '');\n        $itemId = $this->getParam($request, 'item_id', 0);\n        $envId = $this->getParam($request, 'env_id', 0);\n        $times = $this->getParam($request, 'times', 1);\n        $timeInterval = $this->getParam($request, 'time_interval', 0);\n        $errorContinue = $this->getParam($request, 'error_continue', 1);\n        $saveChange = $this->getParam($request, 'save_change', 1);\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n        $dateTime = date('Y-m-d H:i:s');\n\n        if ($id > 0) {\n            // 更新现有流程\n            $flow = RunapiFlow::findById($id);\n            if (!$flow) {\n                return $this->error($response, 10101, '流程不存在');\n            }\n\n            if (!$this->checkItemEdit($uid, (int) ($flow->item_id ?? 0))) {\n                return $this->error($response, 10303, '没有权限');\n            }\n\n            $data = ['last_update_time' => $dateTime];\n            if (!empty($flowName)) {\n                $data['flow_name'] = $flowName;\n            }\n            if ($request->getParsedBody() && array_key_exists('env_id', $request->getParsedBody())) {\n                $data['env_id'] = $envId;\n            }\n            if ($request->getParsedBody() && array_key_exists('times', $request->getParsedBody())) {\n                $data['times'] = $times;\n            }\n            if ($request->getParsedBody() && array_key_exists('time_interval', $request->getParsedBody())) {\n                $data['time_interval'] = $timeInterval;\n            }\n            if ($request->getParsedBody() && array_key_exists('error_continue', $request->getParsedBody())) {\n                $data['error_continue'] = $errorContinue;\n            }\n            if ($request->getParsedBody() && array_key_exists('save_change', $request->getParsedBody())) {\n                $data['save_change'] = $saveChange;\n            }\n\n            RunapiFlow::update($id, $data);\n            $finalId = $id;\n        } else {\n            // 创建新流程\n            if ($itemId <= 0) {\n                return $this->error($response, 10101, '项目ID不能为空');\n            }\n\n            if (!$this->checkItemEdit($uid, $itemId)) {\n                return $this->error($response, 10303, '没有权限');\n            }\n\n            $data = [\n                'username'        => $loginUser['username'] ?? '',\n                'uid'            => $uid,\n                'flow_name'      => $flowName,\n                'env_id'         => $envId,\n                'item_id'        => $itemId,\n                'times'          => $times,\n                'time_interval'  => $timeInterval,\n                'error_continue' => $errorContinue,\n                'save_change'    => $saveChange,\n                'addtime'        => $dateTime,\n                'last_update_time' => $dateTime,\n            ];\n\n            // 如果环境小于等于0，尝试获取项目的第一个环境变量赋值\n            if ($envId <= 0) {\n                $envList = RunapiEnv::getListByItemId($itemId);\n                if (!empty($envList)) {\n                    $data['env_id'] = (int) ($envList[0]['id'] ?? 0);\n                }\n            }\n\n            $finalId = RunapiFlow::add($data);\n            if (!$finalId) {\n                return $this->error($response, 10101, '创建失败');\n            }\n        }\n\n        // 延迟 300ms（兼容旧代码）\n        usleep(300000);\n\n        $res = RunapiFlow::findById($finalId);\n        if (!$res) {\n            return $this->error($response, 10101, '获取流程信息失败');\n        }\n\n        return $this->success($response, (array) $res);\n    }\n\n    /**\n     * 获取流程列表（兼容旧接口 Api/Flow/getList）。\n     */\n    public function getList(Request $request, Response $response): Response\n    {\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $itemId = $this->getParam($request, 'item_id', 0);\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        if ($itemId <= 0) {\n            return $this->error($response, 10101, '项目ID不能为空');\n        }\n\n        if (!$this->checkItemEdit($uid, $itemId)) {\n            return $this->error($response, 10303, '没有权限');\n        }\n\n        $ret = RunapiFlow::getListByItemId($itemId);\n        if (!empty($ret)) {\n            return $this->success($response, $ret);\n        }\n\n        return $this->success($response, []);\n    }\n\n    /**\n     * 删除流程（兼容旧接口 Api/Flow/delete）。\n     */\n    public function delete(Request $request, Response $response): Response\n    {\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $id = $this->getParam($request, 'id', 0);\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        if ($id <= 0) {\n            return $this->error($response, 10101, '流程ID不能为空');\n        }\n\n        $flow = RunapiFlow::findById($id);\n        if (!$flow) {\n            return $this->error($response, 10101, '流程不存在');\n        }\n\n        if (!$this->checkItemEdit($uid, (int) ($flow->item_id ?? 0))) {\n            return $this->error($response, 10303, '没有权限');\n        }\n\n        $ret = RunapiFlow::delete($id);\n        if ($ret) {\n            return $this->success($response, ['success' => true]);\n        }\n\n        return $this->error($response, 10103, '删除失败');\n    }\n\n    /**\n     * 新增接口到流程中（兼容旧接口 Api/Flow/addFlowPage）。\n     */\n    public function addFlowPage(Request $request, Response $response): Response\n    {\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $flowId = $this->getParam($request, 'flow_id', 0);\n        $pageId = $this->getParam($request, 'page_id', 0);\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        if ($flowId <= 0 || $pageId <= 0) {\n            return $this->error($response, 10101, '参数错误');\n        }\n\n        $flow = RunapiFlow::findById($flowId);\n        if (!$flow) {\n            return $this->error($response, 10101, '流程不存在');\n        }\n\n        if (!$this->checkItemEdit($uid, (int) ($flow->item_id ?? 0))) {\n            return $this->error($response, 10303, '没有权限');\n        }\n\n        $page = Page::findById($pageId);\n        if (!$page) {\n            return $this->error($response, 10101, '页面不存在');\n        }\n\n        $pageItemId = (int) ($page['item_id'] ?? 0);\n        if (!$this->checkItemEdit($uid, $pageItemId)) {\n            return $this->error($response, 10303, '没有权限');\n        }\n\n        // 获取该流程的最后一个页面的顺序号\n        $sNumber = RunapiFlowPage::getLastSNumber($flowId) + 1;\n\n        $id = RunapiFlowPage::add([\n            'flow_id'  => $flowId,\n            'page_id'  => $pageId,\n            's_number' => $sNumber,\n            'addtime'  => date('Y-m-d H:i:s'),\n        ]);\n\n        if ($id) {\n            return $this->success($response, ['id' => $id]);\n        }\n\n        return $this->error($response, 10101, '添加失败');\n    }\n\n    /**\n     * 从流程中删除接口（兼容旧接口 Api/Flow/deleteFlowPage）。\n     */\n    public function deleteFlowPage(Request $request, Response $response): Response\n    {\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $id = $this->getParam($request, 'id', 0);\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        if ($id <= 0) {\n            return $this->error($response, 10101, '参数错误');\n        }\n\n        $flowPage = RunapiFlowPage::findById($id);\n        if (!$flowPage) {\n            return $this->error($response, 10101, '流程页面不存在');\n        }\n\n        $pageId = (int) ($flowPage->page_id ?? 0);\n        $page = Page::findById($pageId);\n        if (!$page) {\n            return $this->error($response, 10101, '页面不存在');\n        }\n\n        $pageItemId = (int) ($page['item_id'] ?? 0);\n        if (!$this->checkItemEdit($uid, $pageItemId)) {\n            return $this->error($response, 10303, '没有权限');\n        }\n\n        $res = RunapiFlowPage::delete($id);\n        if ($res) {\n            return $this->success($response, ['success' => true]);\n        }\n\n        return $this->error($response, 10101, '删除失败');\n    }\n\n    /**\n     * 获取某个流程里的接口列表（兼容旧接口 Api/Flow/getFlowPageList）。\n     */\n    public function getFlowPageList(Request $request, Response $response): Response\n    {\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $flowId = $this->getParam($request, 'flow_id', 0);\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        if ($flowId <= 0) {\n            return $this->error($response, 10101, '流程ID不能为空');\n        }\n\n        $flow = RunapiFlow::findById($flowId);\n        if (!$flow) {\n            return $this->error($response, 10101, '流程不存在');\n        }\n\n        if (!$this->checkItemEdit($uid, (int) ($flow->item_id ?? 0))) {\n            return $this->error($response, 10303, '没有权限');\n        }\n\n        $res = RunapiFlowPage::getListByFlowId($flowId);\n        if (!empty($res)) {\n            $itemId = (int) ($flow->item_id ?? 0);\n            foreach ($res as $key => &$value) {\n                $pageId = (int) ($value['page_id'] ?? 0);\n                $value['page_title'] = $this->getPageTitle($itemId, $pageId);\n            }\n            return $this->success($response, $res);\n        }\n\n        return $this->success($response, []);\n    }\n\n    /**\n     * 保存顺序关系（兼容旧接口 Api/Flow/saveSort）。\n     */\n    public function saveSort(Request $request, Response $response): Response\n    {\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $flowId = $this->getParam($request, 'flow_id', 0);\n        $orders = $this->getParam($request, 'orders', '');\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        if ($flowId <= 0 || empty($orders)) {\n            return $this->error($response, 10101, '参数错误');\n        }\n\n        $flow = RunapiFlow::findById($flowId);\n        if (!$flow) {\n            return $this->error($response, 10101, '流程不存在');\n        }\n\n        if (!$this->checkItemEdit($uid, (int) ($flow->item_id ?? 0))) {\n            return $this->error($response, 10303, '没有权限');\n        }\n\n        $dataArray = json_decode(htmlspecialchars_decode($orders), true);\n        if ($dataArray) {\n            RunapiFlowPage::updateSort($flowId, $dataArray);\n            return $this->success($response, []);\n        }\n\n        return $this->success($response, []);\n    }\n\n    /**\n     * 保存启用关系（兼容旧接口 Api/Flow/setFlowPageEnabled）。\n     */\n    public function setFlowPageEnabled(Request $request, Response $response): Response\n    {\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $flowId = $this->getParam($request, 'flow_id', 0);\n        $ids = $this->getParam($request, 'ids', '');\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        if ($flowId <= 0 || empty($ids)) {\n            return $this->error($response, 10101, '参数错误');\n        }\n\n        $flow = RunapiFlow::findById($flowId);\n        if (!$flow) {\n            return $this->error($response, 10101, '流程不存在');\n        }\n\n        if (!$this->checkItemEdit($uid, (int) ($flow->item_id ?? 0))) {\n            return $this->error($response, 10303, '没有权限');\n        }\n\n        $dataArray = json_decode(htmlspecialchars_decode($ids), true);\n        if ($dataArray) {\n            RunapiFlowPage::setEnabled($flowId, $dataArray);\n            return $this->success($response, []);\n        }\n\n        return $this->success($response, []);\n    }\n\n    /**\n     * 获取页面标题（私有辅助方法）\n     *\n     * @param int $itemId 项目 ID\n     * @param int $pageId 页面 ID\n     * @return string|false 页面标题，不存在返回 false\n     */\n    private function getPageTitle(int $itemId, int $pageId)\n    {\n        if ($this->pages === null) {\n            $ret = DB::table('page')\n                ->where('item_id', $itemId)\n                ->get()\n                ->all();\n\n            if ($ret) {\n                $this->pages = [];\n                foreach ($ret as $row) {\n                    $this->pages[] = (array) $row;\n                }\n            } else {\n                $this->pages = [];\n                return false;\n            }\n        }\n\n        foreach ($this->pages as $value) {\n            if ((int) ($value['page_id'] ?? 0) === $pageId) {\n                return $value['page_title'] ?? '';\n            }\n        }\n\n        return false;\n    }\n}\n"
  },
  {
    "path": "server/app/Api/Controller/FromCommentsController.php",
    "content": "<?php\n\nnamespace App\\Api\\Controller;\n\nuse App\\Common\\BaseController;\nuse App\\Common\\Helper\\Convert;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\nuse App\\Model\\ItemToken;\nuse App\\Model\\Item;\nuse App\\Model\\Page;\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\n/**\n * 通过注释生成 API 文档（新架构）。\n */\nclass FromCommentsController extends BaseController\n{\n    /**\n     * 生成 API 文档（兼容旧接口 Api/FromComments/generate）。\n     *\n     * 功能：\n     * - 从代码注释中解析 API 信息并生成文档\n     * - 支持通过 api_key 和 api_token 鉴权\n     * - 自动转换为 RunApi 格式或 Markdown 格式\n     */\n    public function generate(Request $request, Response $response): Response\n    {\n        $content = $this->getParam($request, 'content', '');\n        $apiKey = $this->getParam($request, 'api_key', '');\n        $apiToken = $this->getParam($request, 'api_token', '');\n\n        // 验证 API Key 和 Token（旧版逻辑：只检查验证失败，不检查限流）\n        $itemId = ItemToken::check($apiKey, $apiToken);\n        if (!$itemId || $itemId <= 0) {\n            // 没验证通过（旧版逻辑：只返回 false，不区分限流和验证失败）\n            $response->getBody()->write(\"\\napi_key或者api_token不匹配\\n\\n\");\n            return $response->withHeader('Content-Type', 'text/plain; charset=utf-8');\n        }\n\n        // 处理内容（HTML 反转义，替换特殊字符）\n        $content = htmlspecialchars_decode($content);\n        $content = str_replace('_this_and_change_', '&', $content);\n\n        // 解析注释中的 API 信息\n        $p = \"|/\\*\\*([\\s\\S]*)\\*/|U\";\n        preg_match_all($p, $content, $matches);\n\n        $ret = false;\n        if ($matches && !empty($matches[0])) {\n            foreach ($matches[0] as $value) {\n                if (strpos($value, '@title') !== false && strpos($value, 'showdoc') !== false) {\n                    $ret = $this->generateOne($itemId, $value);\n                }\n            }\n        }\n\n        if ($ret) {\n            $response->getBody()->write(\"\\n 成功 \\n\\n \");\n        } else {\n            $response->getBody()->write('失败');\n        }\n\n        return $response->withHeader('Content-Type', 'text/plain; charset=utf-8');\n    }\n\n    /**\n     * 生成单个 API 文档\n     *\n     * @param int $itemId 项目 ID\n     * @param string $content 注释内容\n     * @return array|false 生成的页面信息或 false\n     */\n    private function generateOne(int $itemId, string $content)\n    {\n        $convert = new Convert();\n        $item = Item::findById($itemId);\n        if (!$item) {\n            return false;\n        }\n\n        // 解析注释内容\n        $array = $this->parseContent($content);\n\n        // 转换为 RunApi 格式\n        $pageContent = $this->toRunapiFormat($array);\n\n        $pageTitle = $array['title'] ?? '';\n        $catName = $array['cat_name'] ?? '';\n        $sNumber = !empty($array['s_number']) ? (int) $array['s_number'] : 99;\n\n        // 如果是 RunApi 项目，尝试保留已有页面中用户手动填写的值\n        if ($item->item_type == 3) {\n            $pageContent = $this->preserveExistingValues($itemId, $pageTitle, $catName, $pageContent);\n        }\n\n        // 如果不是 RunApi 项目，转换为 Markdown\n        if ($item->item_type != 3) {\n            $pageContent = $convert->runapiToMd($pageContent);\n        }\n\n        $pageContent = htmlspecialchars($pageContent);\n\n        // 更新或创建页面\n        $pageId = Page::updateByTitle($itemId, $pageTitle, $pageContent, $catName, $sNumber);\n\n        if ($pageId) {\n            // 查询页面信息（与旧版保持一致：D(\"Page\")->where(\" page_id = '%d' \", array($page_id))->find()）\n            $page = Page::findById($pageId);\n            return $page ? $page : false;\n        }\n\n        return false;\n    }\n\n    /**\n     * 保留已有页面中用户手动填写的值\n     *\n     * 对于 RunApi 类型的项目，当通过注释更新文档时，保留用户已在 RunApi 中填写的：\n     * - 请求参数的示例值（value）\n     * - 返回参数的说明（remark）\n     *\n     * @param int $itemId 项目 ID\n     * @param string $pageTitle 页面标题\n     * @param string $catName 目录名称\n     * @param string $newContent 新生成的 RunApi JSON 内容\n     * @return string 合并后的 RunApi JSON 内容\n     */\n    private function preserveExistingValues(int $itemId, string $pageTitle, string $catName, string $newContent): string\n    {\n        // 获取目录 ID\n        $catId = 0;\n        if (!empty($catName)) {\n            $catId = \\App\\Model\\Catalog::saveCatPath($catName, $itemId);\n            if ($catId === false) {\n                return $newContent;\n            }\n        }\n\n        // 查找已存在的页面（开源版：使用单表 page，不支持分表）\n        $existing = DB::table('page')\n            ->where('item_id', $itemId)\n            ->where('is_del', 0)\n            ->where('cat_id', $catId)\n            ->where('page_title', $pageTitle)\n            ->first();\n\n        if (!$existing) {\n            return $newContent;\n        }\n\n        // 解压已有页面内容（兼容旧压缩数据）\n        $existingContent = $existing->page_content;\n        $decompressed = \\App\\Common\\Helper\\ContentCodec::decompress($existingContent);\n        if ($decompressed !== '' && $decompressed !== $existingContent) {\n            $existingContent = $decompressed;\n        }\n\n        // HTML 解码\n        $existingContent = htmlspecialchars_decode($existingContent);\n\n        // 解析 JSON\n        $existingData = json_decode($existingContent, true);\n        $newData = json_decode($newContent, true);\n\n        if (!$existingData || !$newData) {\n            return $newContent;\n        }\n\n        // 合并请求参数中的 value\n        $this->mergeRequestValues($existingData, $newData);\n\n        // 合并返回参数说明中的 value 和 remark\n        $this->mergeResponseValues($existingData, $newData);\n\n        $result = json_encode($newData, JSON_UNESCAPED_UNICODE);\n        if ($result === false) {\n            return $newContent;\n        }\n        return $result;\n    }\n\n    /**\n     * 合并请求参数中的 value 值\n     *\n     * @param array $existingData 已有页面数据\n     * @param array $newData 新生成的页面数据\n     */\n    private function mergeRequestValues(array $existingData, array &$newData): void\n    {\n        if (!isset($existingData['request']) || !isset($newData['request'])) {\n            return;\n        }\n\n        // 合并 headers\n        $this->mergeParamListValues(\n            $existingData['request']['headers'] ?? [],\n            $newData['request']['headers'] ?? []\n        );\n\n        // 合并 query\n        $this->mergeParamListValues(\n            $existingData['request']['query'] ?? [],\n            $newData['request']['query'] ?? []\n        );\n\n        // 合并 formdata\n        $this->mergeParamListValues(\n            $existingData['request']['params']['formdata'] ?? [],\n            $newData['request']['params']['formdata'] ?? []\n        );\n\n        // 合并 jsonDesc\n        $this->mergeParamListValues(\n            $existingData['request']['params']['jsonDesc'] ?? [],\n            $newData['request']['params']['jsonDesc'] ?? []\n        );\n\n        // 合并 urlencoded\n        $this->mergeParamListValues(\n            $existingData['request']['params']['urlencoded'] ?? [],\n            $newData['request']['params']['urlencoded'] ?? []\n        );\n    }\n\n    /**\n     * 合并参数列表中的 value 值\n     * 根据 name 字段匹配，保留已有页面中的 value\n     *\n     * @param array $existingList 已有参数列表\n     * @param array $newList 新参数列表（引用传递，会被修改）\n     */\n    private function mergeParamListValues(array $existingList, array &$newList): void\n    {\n        if (empty($existingList) || empty($newList)) {\n            return;\n        }\n\n        // 建立已有参数的 name -> value 映射\n        $existingValues = [];\n        foreach ($existingList as $param) {\n            if (isset($param['name']) && $param['name'] !== '') {\n                $existingValues[$param['name']] = $param['value'] ?? '';\n            }\n        }\n\n        // 遍历新参数列表，如果 name 匹配且已有 value，则保留\n        foreach ($newList as $key => $param) {\n            $name = $param['name'] ?? '';\n            if ($name !== '' && isset($existingValues[$name]) && $existingValues[$name] !== '') {\n                $newList[$key]['value'] = $existingValues[$name];\n            }\n        }\n    }\n\n    /**\n     * 合并返回参数说明中的 value 和 remark 值\n     *\n     * @param array $existingData 已有页面数据\n     * @param array $newData 新生成的页面数据（引用传递，会被修改）\n     */\n    private function mergeResponseValues(array $existingData, array &$newData): void\n    {\n        if (\n            !isset($existingData['response']['responseParamsDesc'])\n            || !isset($newData['response']['responseParamsDesc'])\n        ) {\n            return;\n        }\n\n        $existingParams = $existingData['response']['responseParamsDesc'];\n        $newParams = &$newData['response']['responseParamsDesc'];\n\n        if (empty($existingParams) || empty($newParams)) {\n            return;\n        }\n\n        // 建立已有参数的 name -> [value, remark] 映射\n        $existingValues = [];\n        foreach ($existingParams as $param) {\n            if (isset($param['name']) && $param['name'] !== '') {\n                $existingValues[$param['name']] = [\n                    'value' => $param['value'] ?? '',\n                    'remark' => $param['remark'] ?? '',\n                ];\n            }\n        }\n\n        // 遍历新参数列表，如果 name 匹配且已有值，则保留\n        foreach ($newParams as $key => $param) {\n            $name = $param['name'] ?? '';\n            if ($name !== '' && isset($existingValues[$name])) {\n                // 保留 value\n                if ($existingValues[$name]['value'] !== '') {\n                    $newParams[$key]['value'] = $existingValues[$name]['value'];\n                }\n                // 保留 remark（如果已有说明且新说明为空或相同）\n                if ($existingValues[$name]['remark'] !== '') {\n                    $newParams[$key]['remark'] = $existingValues[$name]['remark'];\n                }\n            }\n        }\n    }\n\n    /**\n     * 解析注释内容，返回数组\n     *\n     * @param string $content 注释内容\n     * @return array 解析后的数组\n     */\n    private function parseContent(string $content): array\n    {\n        $array = [];\n\n        // 解析标题\n        $array['title'] = $this->parseOneLine('title', $content);\n        $array['method'] = $this->parseOneLine('method', $content);\n        $array['description'] = $this->parseOneLine('description', $content);\n        $array['url'] = $this->parseOneLine('url', $content);\n        $array['cat_name'] = $this->parseOneLine('catalog', $content);\n\n        // 解析返回内容\n        $return = $this->parseOneLine('return', $content);\n        $return = htmlspecialchars_decode($return);\n        $array['return'] = $return;\n\n        // 解析请求参数\n        $array['param'] = $this->parseMultiLine('param', $content);\n\n        // 解析请求 header\n        $array['header'] = $this->parseMultiLine('header', $content);\n\n        // 解析返回参数\n        $array['return_param'] = $this->parseMultiLine('return_param', $content);\n\n        $array['remark'] = $this->parseOneLine('remark', $content);\n        $array['s_number'] = $this->parseOneLine('number', $content);\n\n        // 如果请求参数是 json，则生成请求示例\n        $jsonParam = $this->parseOneLine('json_param', $content);\n        $jsonParam = htmlspecialchars_decode($jsonParam);\n        $array['json_param'] = $jsonParam;\n\n        return $array;\n    }\n\n    /**\n     * 解析单行标签，如 method、url\n     *\n     * @param string $tag 标签名\n     * @param string $content 内容\n     * @return string|false 解析结果或 false\n     */\n    private function parseOneLine(string $tag, string $content)\n    {\n        $p = '/@' . preg_quote($tag, '/') . '.+/';\n        preg_match($p, $content, $matches);\n\n        if ($matches && !empty($matches[0])) {\n            return trim(str_replace('@' . $tag, '', $matches[0]));\n        }\n\n        return false;\n    }\n\n    /**\n     * 解析多行标签，如 param\n     *\n     * @param string $tag 标签名\n     * @param string $content 内容\n     * @return array 解析结果数组\n     */\n    private function parseMultiLine(string $tag, string $content): array\n    {\n        $return = [];\n        $array1 = explode('@', $content);\n\n        foreach ($array1 as $value) {\n            $array2 = preg_split(\"/[\\s]+/\", trim($value));\n            if (!empty($array2[0]) && $array2[0] === $tag) {\n                unset($array2[0]);\n                $return[] = array_values($array2);\n            }\n        }\n\n        return $return;\n    }\n\n    /**\n     * 转成 RunApi 的接口格式\n     *\n     * @param array $array 解析后的数组\n     * @return string JSON 格式的 RunApi 内容\n     */\n    private function toRunapiFormat(array $array): string\n    {\n        $contentArray = [\n            'info' => [\n                'from'        => 'runapi',\n                'type'        => 'api',\n                'title'       => $array['title'] ?? '',\n                'description' => $array['description'] ?? '',\n                'method'      => strtolower($array['method'] ?? 'get'),\n                'url'         => $array['url'] ?? '',\n                'remark'      => $array['remark'] ?? '',\n            ],\n            'request' => [\n                'params' => [\n                    'mode'       => 'formdata',\n                    'json'       => '',\n                    'urlencoded' => [],\n                    'formdata'   => [],\n                ],\n                'headers' => [],\n                'query'   => [],\n                'cookies' => [],\n                'auth'    => [],\n            ],\n            'response' => [\n                'responseExample'    => $array['return'] ?? '',\n                'responseParamsDesc' => [],\n            ],\n            'extend' => [],\n        ];\n\n        // JSON 美化\n        $responseExample = $this->indentJson($contentArray['response']['responseExample']);\n        $contentArray['response']['responseExample'] = $responseExample ?: $contentArray['response']['responseExample'];\n\n        // 处理 header\n        if (!empty($array['header'])) {\n            foreach ($array['header'] as $value) {\n                // |参数名|是否必选|类型|说明\n                $contentArray['request']['headers'][] = [\n                    'name'   => $value[0] ?? '',\n                    'require' => ($value[1] ?? '') === '必选' ? '1' : '0',\n                    'type'   => $value[2] ?? '',\n                    'value'  => '',\n                    'remark' => $value[3] ?? '',\n                ];\n            }\n        }\n\n        // 处理 JSON 参数\n        if (!empty($array['json_param'])) {\n            $contentArray['request']['params']['mode'] = 'json';\n            $contentArray['request']['params']['json'] = $array['json_param'];\n\n            // 请求方式是 json 的话，原有的参数说明数组就写入 json 描述中\n            if (!empty($array['param'])) {\n                foreach ($array['param'] as $value) {\n                    // |参数名|是否必选|类型|说明\n                    $contentArray['request']['params']['jsonDesc'][] = [\n                        'name'   => $value[0] ?? '',\n                        'require' => ($value[1] ?? '') === '必选' ? '1' : '0',\n                        'type'   => $value[2] ?? '',\n                        'value'  => '',\n                        'remark' => $value[3] ?? '',\n                    ];\n                }\n            }\n        }\n\n        // 处理普通参数\n        if (!empty($array['param'])) {\n            $method = strtolower($array['method'] ?? 'get');\n            if ($method === 'get') {\n                $queryStr = '';\n                foreach ($array['param'] as $value) {\n                    // |参数名|是否必选|类型|说明\n                    $contentArray['request']['query'][] = [\n                        'name'   => $value[0] ?? '',\n                        'require' => ($value[1] ?? '') === '必选' ? '1' : '0',\n                        'type'   => $value[2] ?? '',\n                        'value'  => '',\n                        'remark' => $value[3] ?? '',\n                    ];\n                    $queryStr .= ($value[0] ?? '') . '=&';\n                }\n\n                // 为了兼容，还要把 query 参数追加到 url 里去\n                $url = $contentArray['info']['url'];\n                if (strpos($url, '?') !== false) {\n                    $contentArray['info']['url'] .= '&' . $queryStr;\n                } else {\n                    $contentArray['info']['url'] .= '?' . $queryStr;\n                }\n            } else {\n                foreach ($array['param'] as $value) {\n                    // |参数名|是否必选|类型|说明\n                    $contentArray['request']['params']['formdata'][] = [\n                        'name'   => $value[0] ?? '',\n                        'require' => ($value[1] ?? '') === '必选' ? '1' : '0',\n                        'type'   => $value[2] ?? '',\n                        'value'  => '',\n                        'remark' => $value[3] ?? '',\n                    ];\n                }\n            }\n        }\n\n        // 处理返回参数\n        if (!empty($array['return_param'])) {\n            foreach ($array['return_param'] as $value) {\n                // |参数名|类型|说明\n                $contentArray['response']['responseParamsDesc'][] = [\n                    'name'   => $value[0] ?? '',\n                    'type'   => $value[1] ?? '',\n                    'value'  => '',\n                    'remark' => $value[2] ?? '',\n                ];\n            }\n        }\n\n        return json_encode($contentArray, JSON_UNESCAPED_UNICODE);\n    }\n\n    /**\n     * JSON 美化\n     *\n     * @param string $json JSON 字符串\n     * @return string|false 美化后的 JSON 或 false\n     */\n    private function indentJson(string $json)\n    {\n        if (empty($json)) {\n            return false;\n        }\n\n        $decoded = json_decode($json, true);\n        if ($decoded === null) {\n            return false;\n        }\n\n        $jsonNew = json_encode($decoded, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);\n        if ($jsonNew && $jsonNew !== 'null') {\n            return $jsonNew;\n        }\n\n        return $json;\n    }\n}\n"
  },
  {
    "path": "server/app/Api/Controller/ImportController.php",
    "content": "<?php\n\nnamespace App\\Api\\Controller;\n\nuse App\\Common\\BaseController;\nuse App\\Model\\Item;\nuse App\\Model\\Page;\nuse App\\Common\\Helper\\FileHelper;\nuse Slim\\Psr7\\UploadedFile;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\n\nuse const UPLOAD_ERR_OK;\n\nclass ImportController extends BaseController\n{\n    /**\n     * 自动检测导入的文件类型从而选择不同的控制器方法\n     *\n     * @param Request $request\n     * @param Response $response\n     * @return Response\n     */\n    public function auto(Request $request, Response $response): Response\n    {\n        set_time_limit(100);\n        ini_set('memory_limit', '600M');\n\n        $user = [];\n        if ($error = $this->requireLoginUser($request, $response, $user)) {\n            return $error;\n        }\n\n        $uid = (int) ($user['uid'] ?? 0);\n        $itemId = $this->getParam($request, 'item_id', 0);\n\n        // 权限检查\n        if ($itemId > 0) {\n            if (!$this->checkItemEdit($uid, $itemId)) {\n                return $this->error($response, 10302, '没有权限');\n            }\n            Item::deleteCache($itemId); // 清除项目缓存\n        }\n\n\n        // 获取上传的文件\n        $uploadedFiles = $request->getUploadedFiles();\n        if (empty($uploadedFiles['file'])) {\n            return $this->error($response, 10101, '请上传文件');\n        }\n\n        $file = $uploadedFiles['file'];\n        $filename = $file->getClientFilename();\n\n        // 检查文件扩展名（只允许 .zip 或 .json 文件）\n        $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));\n        if (!in_array($ext, ['zip', 'json'], true)) {\n            return $this->error($response, 10101, '只支持上传 ZIP 或 JSON 格式的文件');\n        }\n\n        $tail = $ext;\n\n        if ($tail == 'zip') {\n            // ZIP 文件处理\n            $tempFile = sys_get_temp_dir() . '/' . FileHelper::getRandStr() . '.zip';\n            $file->moveTo($tempFile);\n\n            $zipArc = new \\ZipArchive();\n            $ret = $zipArc->open($tempFile, \\ZipArchive::CREATE);\n            if ($ret !== true) {\n                @unlink($tempFile);\n                return $this->error($response, 10101, 'ZIP 文件打开失败');\n            }\n\n            // 先尝试新的格式 info.json，如果不存在则尝试旧的格式 prefix_info.json\n            $info = $zipArc->getFromName(\"info.json\");\n            if (!$info) {\n                $info = $zipArc->getFromName(\"prefix_info.json\");\n            }\n\n            // 如有 info.json 或 prefix_info.json 文件，则导入\n            if ($info) {\n                $infoArray = json_decode($info, true);\n                if ($infoArray) {\n                    $infoArray['item_id'] = $itemId;\n                    $zipArc->close();\n                    @unlink($tempFile);\n                    return $this->importMarkdownInfo($request, $response, $infoArray, $itemId);\n                }\n            } else {\n                // 如果没有，则尝试解压压缩包后，遍历 markdown 文件导入\n                $zipArc->close();\n                return $this->importFromReadingMDFile($request, $response, $tempFile, $filename, $itemId);\n            }\n        }\n\n        if ($tail == 'json') {\n            // JSON 文件处理\n            $tempFile = sys_get_temp_dir() . '/' . FileHelper::getRandStr() . '.json';\n            $file->moveTo($tempFile);\n            $json = file_get_contents($tempFile);\n            $jsonArray = json_decode($json, true);\n            @unlink($tempFile);\n            unset($json);\n\n            // 检测 Swagger/OpenAPI 格式\n            if (($jsonArray['swagger'] ?? false) || (($jsonArray['openapi'] ?? false) && ($jsonArray['info'] ?? false))) {\n                // Swagger 格式，调用 ImportSwaggerController\n                $swaggerController = new \\App\\Api\\Controller\\ImportSwaggerController();\n                // 需要重新构建请求，将文件内容传递给 ImportSwaggerController\n                // 由于 ImportSwaggerController 需要从上传的文件中读取，我们需要创建一个临时文件\n                $tempFile = sys_get_temp_dir() . '/' . FileHelper::getRandStr() . '.json';\n                file_put_contents($tempFile, json_encode($jsonArray, JSON_UNESCAPED_UNICODE));\n\n                // 创建一个新的上传文件对象（模拟上传）\n                $streamFactory = new \\Slim\\Psr7\\Factory\\StreamFactory();\n                $uploadedFile = new UploadedFile(\n                    $tempFile,\n                    'swagger.json',\n                    'application/json',\n                    filesize($tempFile),\n                    UPLOAD_ERR_OK,\n                    false\n                );\n\n                // 创建新的请求对象，包含上传的文件\n                $newRequest = $request->withUploadedFiles(['file' => $uploadedFile]);\n\n                $result = $swaggerController->import($newRequest, $response);\n                @unlink($tempFile);\n                return $result;\n            }\n\n            // 检测 Postman 格式\n            if (($jsonArray['id'] ?? false) || ($jsonArray['info'] ?? false)) {\n                // Postman 格式，调用 ImportPostmanController\n                $postmanController = new \\App\\Api\\Controller\\ImportPostmanController();\n                // 需要重新构建请求，将文件内容传递给 ImportPostmanController\n                $tempFile = sys_get_temp_dir() . '/' . FileHelper::getRandStr() . '.json';\n                file_put_contents($tempFile, json_encode($jsonArray, JSON_UNESCAPED_UNICODE));\n\n                // 创建一个新的上传文件对象（模拟上传）\n                $uploadedFile = new UploadedFile(\n                    $tempFile,\n                    'postman.json',\n                    'application/json',\n                    filesize($tempFile),\n                    UPLOAD_ERR_OK,\n                    false\n                );\n\n                // 创建新的请求对象，包含上传的文件\n                $newRequest = $request->withUploadedFiles(['file' => $uploadedFile]);\n\n                $result = $postmanController->import($newRequest, $response);\n                @unlink($tempFile);\n                return $result;\n            }\n        }\n\n        return $this->error($response, 10101, '不支持的文件格式');\n    }\n\n    /**\n     * 导入 Markdown 压缩包（根据压缩包内的 info 文件导入）\n     *\n     * @param Request $request\n     * @param Response $response\n     * @param array|null $infoArray 信息数组（可选）\n     * @param int $itemId 项目 ID\n     * @return Response\n     */\n    public function importMarkdownInfo(Request $request, Response $response, ?array $infoArray = null, int $itemId = 0): Response\n    {\n        set_time_limit(100);\n        ini_set('memory_limit', '200M');\n\n        $user = [];\n        if ($error = $this->requireLoginUser($request, $response, $user)) {\n            return $error;\n        }\n\n        $uid = (int) ($user['uid'] ?? 0);\n\n        // 如果没有传入 infoArray，则从上传的文件中读取\n        if (!$infoArray) {\n            $uploadedFiles = $request->getUploadedFiles();\n            if (empty($uploadedFiles['file'])) {\n                return $this->error($response, 10101, '请上传文件');\n            }\n\n            $file = $uploadedFiles['file'];\n            $tempFile = sys_get_temp_dir() . '/' . FileHelper::getRandStr() . '.zip';\n            $file->moveTo($tempFile);\n\n            $zipArc = new \\ZipArchive();\n            $ret = $zipArc->open($tempFile, \\ZipArchive::CREATE);\n            if ($ret !== true) {\n                @unlink($tempFile);\n                return $this->error($response, 10101, 'ZIP 文件打开失败');\n            }\n\n            // 先尝试新的格式 info.json，如果不存在则尝试旧的格式 prefix_info.json\n            $info = $zipArc->getFromName(\"info.json\");\n            if (!$info) {\n                $info = $zipArc->getFromName(\"prefix_info.json\");\n            }\n            $zipArc->close();\n            @unlink($tempFile);\n\n            if (!$info) {\n                return $this->error($response, 10101, '未找到 info.json 文件');\n            }\n\n            $infoArray = json_decode($info, true);\n            unset($info);\n        }\n\n        if ($infoArray) {\n            $infoArray['item_id'] = $itemId;\n            $json = json_encode($infoArray, JSON_UNESCAPED_UNICODE);\n            $result = Item::import($json, $uid, $itemId);\n            if ($result) {\n                return $this->success($response, ['item_id' => $result]);\n            }\n        }\n\n        return $this->error($response, 10101, '导入失败');\n    }\n\n    /**\n     * 从 Markdown 文件导入（遍历目录）\n     *\n     * @param Request $request\n     * @param Response $response\n     * @param string $file ZIP 文件路径\n     * @param string $filename 文件名\n     * @param int $itemId 项目 ID\n     * @return Response\n     */\n    public function importFromReadingMDFile(Request $request, Response $response, string $file, string $filename, int $itemId): Response\n    {\n        $user = [];\n        if ($error = $this->requireLoginUser($request, $response, $user)) {\n            return $error;\n        }\n\n        $uid = (int) ($user['uid'] ?? 0);\n\n        // 如果项目 id 不存在，则新建一个项目\n        if ($itemId <= 0) {\n            $itemData = [\n                'item_name'        => str_replace('.zip', '', $filename),\n                'item_domain'      => '',\n                'item_type'        => 1,\n                'item_description' => '',\n                'password'         => FileHelper::getRandStr(),\n                'uid'              => $uid,\n                'username'          => $user['username'] ?? '',\n                'addtime'           => time(),\n            ];\n            $itemId = Item::add($itemData);\n            if ($itemId <= 0) {\n                return $this->error($response, 10500, '创建项目失败');\n            }\n        }\n\n        $zipArc = new \\ZipArchive();\n        $zipArc->open($file, \\ZipArchive::CREATE);\n\n        // 在系统目录创建一个临时目录路径\n        $tmpDir = sys_get_temp_dir() . '/' . FileHelper::getRandStr();\n        mkdir($tmpDir);\n\n        // 处理中文名乱码问题\n        $fileNum = $zipArc->numFiles;\n        for ($i = 0; $i < $fileNum; $i++) {\n            $statInfo = $zipArc->statIndex($i, \\ZipArchive::FL_ENC_RAW);\n            $currentEncode = mb_detect_encoding($statInfo['name'], ['ASCII', 'GB2312', 'GBK', 'BIG5', 'UTF-8']);\n            $statInfo['name'] = mb_convert_encoding($statInfo['name'], 'UTF-8', $currentEncode);\n            $zipArc->renameIndex($i, $statInfo['name']);\n        }\n        $zipArc->close();\n        $zipArc->open($file, \\ZipArchive::CREATE);\n\n        $zipArc->extractTo($tmpDir);\n\n        // 遍历解压后的目录\n        $traverseFiles = function ($dir) use (&$traverseFiles, $itemId, $tmpDir, $uid, $user) {\n            $handle = opendir($dir);\n            while (($file = readdir($handle)) !== false) {\n                if ($file !== '..' && $file !== '.') {\n                    $f = $dir . '/' . $file;\n                    if (is_file($f)) {\n                        // 跳过 info.json 和 prefix_info.json 文件\n                        if ($file === 'info.json' || $file === 'prefix_info.json') {\n                            continue;\n                        }\n                        // 只处理 .md 文件\n                        if (substr($file, -3) !== '.md') {\n                            continue;\n                        }\n                        $pageTitle = str_replace('.md', '', $file);\n                        $pageContent = file_get_contents($f);\n                        // 获取目录路径，去掉临时目录前缀，并规范化路径分隔符\n                        $catName = str_replace($tmpDir, '', $dir);\n                        // 统一路径分隔符为 /\n                        $catName = str_replace('\\\\', '/', $catName);\n                        // 去掉开头的斜杠和空格\n                        $catName = trim($catName, '/ ');\n                        // 如果目录名为空，说明是根目录\n                        if (empty($catName)) {\n                            $catName = '';\n                        }\n                        Page::updateByTitle(\n                            $itemId,\n                            $pageTitle,\n                            $pageContent,\n                            $catName,\n                            99,\n                            $uid,\n                            $user['username'] ?? ''\n                        );\n                    } else {\n                        // 这里目录，则继续递归遍历\n                        $traverseFiles($f);\n                    }\n                }\n            }\n            closedir($handle);\n        };\n\n        $traverseFiles($tmpDir);\n        FileHelper::clearRuntime($tmpDir);\n        @rmdir($tmpDir);\n        $zipArc->close();\n        @unlink($file);\n\n        return $this->success($response, []);\n    }\n}\n"
  },
  {
    "path": "server/app/Api/Controller/ImportPostmanController.php",
    "content": "<?php\n\nnamespace App\\Api\\Controller;\n\nuse App\\Common\\BaseController;\nuse App\\Model\\Item;\nuse App\\Common\\Helper\\Convert;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\n\nclass ImportPostmanController extends BaseController\n{\n    /**\n     * 导入 Postman 集合\n     *\n     * @param Request $request\n     * @param Response $response\n     * @return Response\n     */\n    public function import(Request $request, Response $response): Response\n    {\n        $user = [];\n        if ($error = $this->requireLoginUser($request, $response, $user)) {\n            return $error;\n        }\n\n        $uid = (int) ($user['uid'] ?? 0);\n        $itemId = $this->getParam($request, 'item_id', 0);\n\n        if ($itemId > 0) {\n            if (!$this->checkItemEdit($uid, $itemId)) {\n                return $this->error($response, 10302, '没有权限');\n            }\n        }\n\n        // 获取上传的文件\n        $uploadedFiles = $request->getUploadedFiles();\n        if (empty($uploadedFiles['file'])) {\n            return $this->error($response, 10101, '请上传文件');\n        }\n\n        $file = $uploadedFiles['file'];\n        $filename = $file->getClientFilename();\n\n        // 检查文件扩展名（只允许 .json 文件）\n        $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));\n        if ($ext !== 'json') {\n            return $this->error($response, 10101, '只支持上传 JSON 格式的 Postman 集合文件');\n        }\n\n        $tmpFile = sys_get_temp_dir() . '/' . \\App\\Common\\Helper\\FileHelper::getRandStr() . '.json';\n        $file->moveTo($tmpFile);\n\n        $json = file_get_contents($tmpFile);\n        @unlink($tmpFile);\n\n        $jsonArray = json_decode($json, true);\n        unset($json);\n\n        if (empty($jsonArray)) {\n            return $this->error($response, 10101, '导入失败，请确保是符合格式要求的文件。如有疑问请联系网站管理人员');\n        }\n\n        $jsonArray['item_id'] = $itemId;\n\n        // 判断 Postman 版本\n        if (isset($jsonArray['id'])) {\n            // Postman V1 格式\n            return $this->fromPostmanV1($jsonArray, $itemId, $uid, $request, $response);\n        } elseif (isset($jsonArray['info'])) {\n            // Postman V2 格式\n            return $this->fromPostmanV2($jsonArray, $itemId, $uid, $request, $response);\n        }\n\n        return $this->error($response, 10101, '导入失败，请确保是符合格式要求的文件。如有疑问请联系网站管理人员');\n    }\n\n    /**\n     * 从 Postman 导入（V1 版本）\n     */\n    private function fromPostmanV1(array $jsonArray, int $itemId, int $uid, Request $request, Response $response): Response\n    {\n        $from = $this->getParam($request, 'from', '');\n\n        $itemArray = [\n            'item_id'         => $jsonArray['item_id'],\n            'item_name'       => $jsonArray['name'] ?? 'from postman',\n            'item_type'       => ($from == 'runapi') ? '3' : '1',\n            'item_description' => $jsonArray['description'] ?? '',\n            'password'        => time() . rand(),\n            'members'         => [],\n            'pages'           => [\n                'pages'    => [],\n                'catalogs' => [],\n            ],\n        ];\n\n        $level = 2;\n\n        // 处理没有目录的页面\n        if (isset($jsonArray['requests'])) {\n            foreach ($jsonArray['requests'] as $value) {\n                if (empty($value['folder'])) {\n                    $itemArray['pages']['pages'][] = $this->requestToDoc($value, $request);\n                }\n            }\n        }\n\n        // 处理目录\n        if (isset($jsonArray['folders'])) {\n            foreach ($jsonArray['folders'] as $value) {\n                if (empty($value['folder'])) {\n                    $catArray = [\n                        'id'       => $value['id'],\n                        'cat_name' => $value['name'],\n                        'level'    => $level,\n                        's_number' => 99,\n                    ];\n                    $catArray['pages'] = $this->getPageByFolders($value['id'], $jsonArray, $request);\n                    $catArray['catalogs'] = $this->getSubByFolders($value['id'], $value['name'], $level + 1, $jsonArray, $request);\n\n                    $itemArray['pages']['catalogs'][] = $catArray;\n                }\n            }\n        }\n\n        $itemId = Item::import(json_encode($itemArray), $uid, $itemId);\n\n        return $this->success($response, ['item_id' => $itemId]);\n    }\n\n    /**\n     * 根据 Postman 的 folders 获取子页面和子目录\n     */\n    private function getSubByFolders(string $id, string $name, int $level, array $jsonArray, Request $request): array\n    {\n        $return = [];\n        if (!isset($jsonArray['folders'])) {\n            return $return;\n        }\n\n        foreach ($jsonArray['folders'] as $value) {\n            if (($value['folder'] ?? '') == $id) {\n                $catArray = [\n                    'id'       => $value['id'],\n                    'cat_name' => $value['name'],\n                    'level'    => $level,\n                    's_number' => 99,\n                ];\n                $catArray['pages'] = $this->getPageByFolders($value['id'], $jsonArray, $request);\n                $catArray['catalogs'] = $this->getSubByFolders($value['id'], $value['name'], $level + 1, $jsonArray, $request);\n                $return[] = $catArray;\n            }\n        }\n\n        return $return;\n    }\n\n    /**\n     * 根据 Postman 的 folders 获取页面\n     */\n    private function getPageByFolders(string $id, array $jsonArray, Request $request): array\n    {\n        $return = [];\n        if (!isset($jsonArray['requests'])) {\n            return $return;\n        }\n\n        foreach ($jsonArray['requests'] as $value) {\n            if (($value['folder'] ?? '') == $id) {\n                $return[] = $this->requestToDoc($value, $request);\n            }\n        }\n\n        return $return;\n    }\n\n    /**\n     * 请求转文档\n     */\n    private function requestToDoc(array $request, Request $httpRequest): array\n    {\n        $from = $this->getParam($httpRequest, 'from', '');\n        $res = $this->requestToApi($request);\n        if ($from == 'runapi') {\n            return $res;\n        } else {\n            $convert = new Convert();\n            $res['page_content'] = $convert->runapiToMd($res['page_content']);\n            return $res;\n        }\n    }\n\n    /**\n     * 转成 RunApi 所需要的 API 格式（V1）\n     */\n    private function requestToApi(array $request): array\n    {\n        $return = [];\n        $return['page_title'] = $request['name'] ?? '';\n        $return['id'] = $request['id'] ?? '';\n        $return['s_number'] = 99;\n        $return['page_comments'] = '';\n\n        // 若 page_title 为很长的 URL，则做一些特殊处理\n        $tmpTitleArray = explode('/', $return['page_title']);\n        if (!empty($tmpTitleArray)) {\n            $tmpTitleArray = array_slice($tmpTitleArray, -2); // 倒数2个\n            if (!empty($tmpTitleArray[1])) {\n                $return['page_title'] = $tmpTitleArray[0] . '/' . $tmpTitleArray[1];\n            }\n        }\n\n        $contentArray = [\n            'info'     => [\n                'from'        => 'runapi',\n                'type'       => 'api',\n                'title'      => $request['name'] ?? '',\n                'description' => $request['description'] ?? '',\n                'method'     => strtolower($request['method'] ?? 'get'),\n                'url'        => $request['url'] ?? '',\n                'remark'     => '',\n            ],\n            'request'  => [\n                'params'  => [\n                    'mode'      => 'urlencoded',\n                    'json'      => '',\n                    'urlencoded' => [],\n                    'formdata'  => [],\n                ],\n                'headers' => [],\n                'cookies' => [],\n                'auth'    => [],\n            ],\n            'response' => [],\n            'extend'   => [],\n        ];\n\n        // 处理请求头\n        if (isset($request['headerData'])) {\n            foreach ($request['headerData'] as $value) {\n                $contentArray['request']['headers'][] = [\n                    'name'    => $value['key'] ?? '',\n                    'type'    => 'string',\n                    'value'   => $value['value'] ?? '',\n                    'require' => '1',\n                    'remark'  => $value['description'] ?? '',\n                ];\n            }\n        }\n\n        // 处理请求参数\n        if (isset($request['data'])) {\n            foreach ($request['data'] as $value) {\n                $contentArray['request']['params']['urlencoded'][] = [\n                    'name'    => $value['key'] ?? '',\n                    'type'    => 'string',\n                    'value'   => $value['value'] ?? '',\n                    'require' => '1',\n                    'remark'  => $value['description'] ?? '',\n                ];\n            }\n        }\n\n        $return['page_content'] = json_encode($contentArray);\n        return $return;\n    }\n\n    /**\n     * 从 Postman 导入（V2 版本）\n     */\n    private function fromPostmanV2(array $jsonArray, int $itemId, int $uid, Request $request, Response $response): Response\n    {\n        $from = $this->getParam($request, 'from', '');\n\n        $itemArray = [\n            'item_id'         => $jsonArray['item_id'],\n            'item_name'       => $jsonArray['info']['name'] ?? 'from postman',\n            'item_type'       => ($from == 'runapi') ? '3' : '1',\n            'item_description' => $jsonArray['info']['description'] ?? '',\n            'password'        => time() . rand(),\n            'members'         => [],\n            'pages'           => [\n                'pages'    => [],\n                'catalogs' => [],\n            ],\n        ];\n\n        $level = 2;\n        $itemArray['pages']['pages'] = $this->getPageByItem($jsonArray['item'] ?? [], $request);\n        $itemArray['pages']['catalogs'] = $this->getItemByItem($jsonArray['item'] ?? [], $level, $request);\n\n        $itemId = Item::import(json_encode($itemArray), $uid, $itemId);\n\n        return $this->success($response, ['item_id' => $itemId]);\n    }\n\n    /**\n     * 获取某个目录下的所有页面\n     */\n    private function getPageByItem(array $itemArray, Request $request): array\n    {\n        $return = [];\n        foreach ($itemArray as $value) {\n            // 含有 request，则这是一个子页面\n            if (isset($value['request'])) {\n                $return[] = $this->requestToDocV2($value['name'] ?? '', $value, $request);\n            }\n        }\n        return $return;\n    }\n\n    /**\n     * 获取某个目录下的所有子目录\n     */\n    private function getItemByItem(array $itemArray, int $level, Request $request): array\n    {\n        $return = [];\n        foreach ($itemArray as $value) {\n            // 含有 item，则这是一个子目录\n            if (isset($value['item'])) {\n                $oneAry = [\n                    'cat_name' => $value['name'] ?? '',\n                    'level'    => $level,\n                    's_number' => 99,\n                    'pages'    => $this->getPageByItem($value['item'], $request), // 递归\n                    'catalogs' => $this->getItemByItem($value['item'], $level + 1, $request), // 递归\n                ];\n                $return[] = $oneAry;\n            }\n        }\n        return $return;\n    }\n\n    /**\n     * 请求转文档（V2）\n     */\n    private function requestToDocV2(string $name, array $page, Request $request): array\n    {\n        $from = $this->getParam($request, 'from', '');\n        $res = $this->requestToApiV2($name, $page);\n        if ($from == 'runapi') {\n            return $res;\n        } else {\n            $convert = new Convert();\n            $res['page_content'] = $convert->runapiToMd($res['page_content']);\n            return $res;\n        }\n    }\n\n    /**\n     * 转成 RunApi 所需要的 API 格式（V2）\n     */\n    private function requestToApiV2(string $name, array $page): array\n    {\n        $request = $page['request'] ?? [];\n        $return = [];\n        $return['page_title'] = $name;\n        $return['s_number'] = 99;\n        $return['page_comments'] = '';\n\n        // 若 page_title 为很长的 URL，则做一些特殊处理\n        $tmpTitleArray = explode('/', $return['page_title']);\n        if (!empty($tmpTitleArray)) {\n            $tmpTitleArray = array_slice($tmpTitleArray, -2); // 倒数2个\n            if (!empty($tmpTitleArray[1])) {\n                $return['page_title'] = $tmpTitleArray[0] . '/' . $tmpTitleArray[1];\n            }\n        }\n\n        $url = is_array($request['url'] ?? null) ? ($request['url']['raw'] ?? '') : ($request['url'] ?? '');\n        $rawModeData = ($request['body']['mode'] ?? '') == 'raw' ? ($request['body']['raw'] ?? '') : ($request['rawModeData'] ?? '');\n\n        $contentArray = [\n            'info'     => [\n                'from'        => 'runapi',\n                'type'       => 'api',\n                'title'      => $name,\n                'description' => $request['description'] ?? '',\n                'method'     => strtolower($request['method'] ?? 'get'),\n                'url'        => $url,\n                'remark'     => '',\n            ],\n            'request'  => [\n                'params'  => [\n                    'mode'      => $request['body']['mode'] ?? 'urlencoded',\n                    'json'      => '',\n                    'urlencoded' => [],\n                    'formdata'  => [],\n                ],\n                'headers' => [],\n                'cookies' => [],\n                'auth'    => [],\n            ],\n            'response' => [],\n            'extend'   => [],\n        ];\n\n        // 处理请求头\n        if (isset($request['header'])) {\n            foreach ($request['header'] as $value) {\n                $contentArray['request']['headers'][] = [\n                    'name'    => $value['key'] ?? '',\n                    'type'    => 'string',\n                    'value'   => $value['value'] ?? '',\n                    'require' => '1',\n                    'remark'  => $value['description'] ?? '',\n                ];\n            }\n        }\n\n        // 处理请求体\n        $bodyMode = $request['body']['mode'] ?? 'urlencoded';\n        if (in_array($bodyMode, ['formdata', 'urlencoded']) && isset($request['body'][$bodyMode])) {\n            foreach ($request['body'][$bodyMode] as $value) {\n                $contentArray['request']['params'][$bodyMode][] = [\n                    'name'    => $value['key'] ?? '',\n                    'type'    => 'string',\n                    'value'   => $value['value'] ?? '',\n                    'require' => '1',\n                    'remark'  => $value['description'] ?? '',\n                ];\n            }\n        } elseif ($rawModeData && json_decode($rawModeData)) {\n            $contentArray['request']['params']['mode'] = 'json';\n            $contentArray['request']['params']['json'] = $rawModeData;\n        }\n\n        // 兼容 GET 请求参数的场景\n        if (isset($request['url']['query'])) {\n            foreach ($request['url']['query'] as $value) {\n                $contentArray['request']['params'][$bodyMode][] = [\n                    'name'    => $value['key'] ?? '',\n                    'type'    => 'string',\n                    'value'   => $value['value'] ?? '',\n                    'require' => '1',\n                    'remark'  => $value['description'] ?? '',\n                ];\n            }\n        }\n\n        // 处理响应示例\n        if (isset($page['response'][0]['body'])) {\n            $contentArray['response']['responseExample'] = $page['response'][0]['body'];\n        }\n\n        $return['page_content'] = json_encode($contentArray);\n\n        return $return;\n    }\n}\n"
  },
  {
    "path": "server/app/Api/Controller/ImportSwaggerController.php",
    "content": "<?php\n\nnamespace App\\Api\\Controller;\n\nuse App\\Common\\BaseController;\nuse App\\Model\\Item;\nuse App\\Common\\Helper\\Convert;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\n\nclass ImportSwaggerController extends BaseController\n{\n    private $jsonArray = [];\n    private $urlPre = '';\n\n    /**\n     * 导入 Swagger/OpenAPI 文档\n     *\n     * @param Request $request\n     * @param Response $response\n     * @return Response\n     */\n    public function import(Request $request, Response $response): Response\n    {\n        set_time_limit(100);\n        ini_set('memory_limit', '6000M');\n\n        $user = [];\n        if ($error = $this->requireLoginUser($request, $response, $user)) {\n            return $error;\n        }\n\n        $uid = (int) ($user['uid'] ?? 0);\n        $itemId = $this->getParam($request, 'item_id', 0);\n\n        if ($itemId > 0) {\n            if (!$this->checkItemEdit($uid, $itemId)) {\n                return $this->error($response, 10302, '没有权限');\n            }\n        }\n\n        // 获取上传的文件\n        $uploadedFiles = $request->getUploadedFiles();\n        if (empty($uploadedFiles['file'])) {\n            return $this->error($response, 10101, '请上传文件');\n        }\n\n        $file = $uploadedFiles['file'];\n        $filename = $file->getClientFilename();\n\n        // 检查文件扩展名（只允许 .json 文件）\n        $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));\n        if ($ext !== 'json') {\n            return $this->error($response, 10101, '只支持上传 JSON 格式的 Swagger/OpenAPI 文件');\n        }\n\n        $tmpFile = sys_get_temp_dir() . '/' . \\App\\Common\\Helper\\FileHelper::getRandStr() . '.json';\n        $file->moveTo($tmpFile);\n\n        $json = file_get_contents($tmpFile);\n        @unlink($tmpFile);\n\n        $jsonArray = json_decode($json, true);\n        unset($json);\n\n        if (empty($jsonArray) || !isset($jsonArray['info'])) {\n            return $this->error($response, 10101, '无效的 Swagger/OpenAPI 文件');\n        }\n\n        $jsonArray['item_id'] = $itemId;\n        $this->jsonArray = $jsonArray;\n\n        // 根据 Swagger/OpenAPI 版本分别处理\n        $swaggerVersion = '';\n        if (isset($jsonArray['swagger'])) {\n            $swaggerVersion = $jsonArray['swagger'];\n        } elseif (isset($jsonArray['openapi'])) {\n            $swaggerVersion = $jsonArray['openapi'];\n        }\n\n        // 设置 URL 前缀\n        if (strstr($swaggerVersion, '2.')) {\n            // Swagger 2.0 格式\n            $scheme = $jsonArray['schemes'][0] ?? 'http';\n            if (!empty($jsonArray['host'])) {\n                $this->urlPre = $scheme . \"://\" . $jsonArray['host'] . ($jsonArray['basePath'] ?? '');\n            }\n        } else {\n            // OpenAPI 3.0 格式\n            if (!empty($jsonArray['servers'][0]['url'])) {\n                $this->urlPre = $jsonArray['servers'][0]['url'];\n            }\n        }\n\n        // 转换10次（解析引用）\n        for ($i = 0; $i < 10; $i++) {\n            $this->jsonArray = $this->transferDefinition($this->jsonArray);\n        }\n\n        return $this->fromSwagger($this->jsonArray, $itemId, $swaggerVersion, $uid, $response, $request);\n    }\n\n    /**\n     * 从 Swagger 导入\n     */\n    private function fromSwagger(array $jsonArray, int $itemId, string $swaggerVersion, int $uid, Response $response, ?Request $request = null): Response\n    {\n        $from = $request ? $this->getParam($request, 'from', '') : '';\n\n        $itemArray = [\n            'item_id'         => $jsonArray['item_id'],\n            'item_name'       => $jsonArray['info']['title'] ?? 'from swagger',\n            'item_type'       => ($from == 'runapi') ? '3' : '1',\n            'item_description' => $jsonArray['info']['description'] ?? '',\n            'password'        => time() . rand(),\n            'members'         => [],\n            'pages'           => [\n                'pages'    => [],\n                'catalogs' => $this->getAllTagsLogs($jsonArray, $swaggerVersion, $request),\n            ],\n        ];\n\n        $itemId = Item::import(json_encode($itemArray), $uid, $itemId);\n\n        return $this->success($response, ['item_id' => $itemId]);\n    }\n\n    /**\n     * 获取所有标签（目录）\n     */\n    private function getAllTagsLogs(array $jsonArray, string $swaggerVersion, ?Request $request = null): array\n    {\n        $catalogsMap = [\n            'fromSwagger' => ['cat_name' => 'from swagger', 'pages' => []],\n        ];\n\n        $paths = $jsonArray['paths'] ?? [];\n        foreach ($paths as $url => $value) {\n            foreach ($value as $method => $value2) {\n                $tags = $value2['tags'] ?? [];\n                if (empty($tags)) {\n                    $page = $this->requestToDoc($method, $url, $value2, $jsonArray, $swaggerVersion, $request);\n                    if (!empty($page['page_title'])) {\n                        $catalogsMap['fromSwagger']['pages'][] = $page;\n                    }\n                } else {\n                    foreach ($tags as $tag) {\n                        if (!key_exists($tag, $catalogsMap)) {\n                            $page = $this->requestToDoc($method, $url, $value2, $jsonArray, $swaggerVersion, $request);\n                            if (!empty($page['page_title']) && !empty($page['page_content'])) {\n                                $catalogsMap[$tag] = ['cat_name' => $tag, 'pages' => [$page]];\n                            }\n                        } else {\n                            $page = $this->requestToDoc($method, $url, $value2, $jsonArray, $swaggerVersion, $request);\n                            if (!empty($page['page_title']) && !empty($page['page_content'])) {\n                                $catalogsMap[$tag]['pages'][] = $page;\n                            }\n                        }\n                    }\n                }\n            }\n        }\n\n        $catalogs = [];\n        foreach ($catalogsMap as $value) {\n            $catalogs[] = $value;\n        }\n\n        return $catalogs;\n    }\n\n    /**\n     * 请求转文档\n     */\n    private function requestToDoc(string $method, string $url, array $request, array $jsonArray, string $swaggerVersion, ?Request $httpRequest = null): array\n    {\n        $from = $httpRequest ? $this->getParam($httpRequest, 'from', '') : '';\n        $res = $this->requestToApi($method, $url, $request, $jsonArray, $swaggerVersion);\n        if ($from == 'runapi') {\n            return $res;\n        } else {\n            $convert = new Convert();\n            $res['page_content'] = $convert->runapiToMd($res['page_content']);\n            return $res;\n        }\n    }\n\n    /**\n     * 请求转 API 格式\n     */\n    private function requestToApi(string $method, string $url, array $request, array $jsonArray, string $swaggerVersion): array\n    {\n        $return = [];\n        $pageTitle = $request['summary'] ?? $request['description'] ?? '';\n        if (empty($pageTitle) && !empty($request['operationId'])) {\n            $pageTitle = $request['operationId'];\n        }\n        // 当没有 summary/description/operationId 时，使用 \"方法 URL\" 作为默认标题\n        if (empty($pageTitle)) {\n            $pageTitle = strtoupper($method) . ' ' . $url;\n        }\n        $pageTitle = mb_substr($pageTitle, 0, 50, 'utf-8');\n        $return['page_title'] = $pageTitle;\n        $return['s_number'] = 99;\n        $return['page_comments'] = '';\n\n        $contentArray = [\n            'info'     => [\n                'from'        => 'runapi',\n                'type'       => 'api',\n                'title'      => $request['summary'] ?? $request['description'] ?? '',\n                'description' => $request['description'] ?? '',\n                'method'     => strtolower($method),\n                'url'        => $this->urlPre . $url,\n                'remark'     => '',\n            ],\n            'request'  => [\n                'params'  => [\n                    'mode'      => 'formdata',\n                    'json'      => '',\n                    'jsonDesc'  => [],\n                    'urlencoded' => [],\n                    'formdata'  => [],\n                ],\n                'query'   => [],\n                'headers' => [],\n                'cookies' => [],\n                'auth'    => [],\n            ],\n            'response' => [],\n            'extend'   => [],\n        ];\n\n        // 根据版本处理请求体\n        if (strstr($swaggerVersion, '2.')) {\n            $this->processSwagger2Request($request, $contentArray);\n        } else {\n            $this->processOpenAPI3Request($request, $contentArray);\n        }\n\n        // 根据版本处理响应\n        if (strstr($swaggerVersion, '2.')) {\n            $this->processSwagger2Response($request, $contentArray);\n        } else {\n            $this->processOpenAPI3Response($request, $contentArray);\n        }\n\n        $return['page_content'] = json_encode($contentArray);\n        return $return;\n    }\n\n    /**\n     * 获取引用定义\n     */\n    private function getDefinition(string $refStr): ?array\n    {\n        $jsonArray = $this->jsonArray;\n        $strArray = explode('/', $refStr);\n\n        $targetArray = null;\n        if (isset($strArray[2])) {\n            $targetArray = $jsonArray[$strArray[1]][$strArray[2]] ?? null;\n        }\n        if (isset($strArray[3]) && $targetArray) {\n            $targetArray = $targetArray[$strArray[3]] ?? null;\n        }\n\n        return $targetArray ?: null;\n    }\n\n    /**\n     * 定义转 JSON 数组\n     */\n    private function definitionToJsonArray(array $refArray): array\n    {\n        $res = [];\n        if (!isset($refArray['properties'])) {\n            return $res;\n        }\n\n        foreach ($refArray['properties'] as $key => $value) {\n            $remark = $value['title'] ?? $value['description'] ?? '';\n\n            $exampleValue = $value['example'] ?? '';\n\n            $required = '0';\n            if (isset($refArray['required']) && is_array($refArray['required']) && in_array($key, $refArray['required'])) {\n                $required = '1';\n            }\n\n            $paramType = $value['type'] ?? 'string';\n            if ($paramType === 'int') {\n                $paramType = 'integer';\n            }\n\n            $res[] = [\n                'name'    => $key,\n                'type'    => $paramType,\n                'value'   => $exampleValue,\n                'require' => $required,\n                'remark'  => $remark,\n            ];\n\n            if (isset($value['properties'])) {\n                $tmpJsonArray = $this->definitionToJsonArray($value);\n                $res = array_merge($res, $tmpJsonArray);\n            }\n            if (isset($value['items'])) {\n                $tmpJsonArray = $this->definitionToJsonArray($value['items']);\n                $res = array_merge($res, $tmpJsonArray);\n            }\n        }\n\n        return $res;\n    }\n\n    /**\n     * JSON 数组转字符串\n     */\n    private function jsonArrayToStr(array $jsonArray): string\n    {\n        $resArray = $this->toB($jsonArray);\n        return json_encode($resArray);\n    }\n\n    /**\n     * 转换为示例值\n     */\n    private function toB(array $jsonArray): array\n    {\n        $resArray = [];\n        if (isset($jsonArray['properties'])) {\n            foreach ($jsonArray['properties'] as $key => $value) {\n                $resArray[$key] = $this->formatToFakeValue($value['type'] ?? 'string', $value['format'] ?? '');\n                if (isset($value['items'])) {\n                    $resArray[$key] = [$this->toB($value['items'])];\n                }\n                if (isset($value['properties'])) {\n                    $resArray[$key] = $this->toB($value);\n                }\n            }\n        } elseif (isset($jsonArray['$ref'])) {\n            $refData = $this->getDefinition($jsonArray['$ref']);\n            if ($refData) {\n                $resArray = $this->toB($refData);\n            }\n        } elseif (isset($jsonArray['type']) && $jsonArray['type'] == 'array' && isset($jsonArray['items'])) {\n            $resArray = [$this->toB($jsonArray['items'])];\n        }\n        return $resArray;\n    }\n\n    /**\n     * 格式化假值\n     * \n     * @param string $type\n     * @param string $format\n     * @return mixed\n     */\n    private function formatToFakeValue(string $type, string $format)\n    {\n        switch ($format) {\n            case 'int64':\n            case 'int32':\n                return 0;\n            case 'double':\n                return 0.00;\n            case 'date-time':\n                return date('Y-m-d H:i:s');\n        }\n\n        switch ($type) {\n            case 'boolean':\n                return true;\n        }\n\n        return $type;\n    }\n\n    /**\n     * 转换定义（将引用改为真实数据）\n     */\n    private function transferDefinition(array $curArray): array\n    {\n        foreach ($curArray as $key => $value) {\n            if (is_array($value)) {\n                $curArray[$key] = $this->transferDefinition($value);\n                if (isset($value['$ref'])) {\n                    $curArray[$key] = $this->getDefinition($value['$ref']) ?? $value;\n                }\n            }\n        }\n        return $curArray;\n    }\n\n    /**\n     * 处理 OpenAPI 3.0 请求\n     */\n    private function processOpenAPI3Request(array $request, array &$contentArray): void\n    {\n        // 添加请求头处理\n        if (isset($request['headers'])) {\n            foreach ($request['headers'] as $header) {\n                $contentArray['request']['headers'][] = [\n                    'name'    => $header['name'],\n                    'type'    => 'string',\n                    'value'   => $header['value'] ?? '',\n                    'require' => ($header['required'] ?? false) ? '1' : '0',\n                    'remark'  => $header['description'] ?? '',\n                ];\n            }\n        }\n\n        // 处理请求体\n        if (isset($request['requestBody']['content'])) {\n            $hasJsonContent = false;\n            $hasFormContent = false;\n\n            if (isset($request['requestBody']['content']['application/json'])) {\n                $hasJsonContent = true;\n                $this->processContentSchema($request['requestBody']['content']['application/json'], $contentArray, 'json');\n            }\n\n            if (!$hasJsonContent && isset($request['requestBody']['content']['application/x-www-form-urlencoded'])) {\n                $hasFormContent = true;\n                $this->processContentSchema($request['requestBody']['content']['application/x-www-form-urlencoded'], $contentArray, 'formdata');\n            }\n\n            if (!$hasJsonContent && !$hasFormContent && isset($request['requestBody']['content']['multipart/form-data'])) {\n                $this->processContentSchema($request['requestBody']['content']['multipart/form-data'], $contentArray, 'formdata');\n            }\n\n            if (!$hasJsonContent && !$hasFormContent) {\n                foreach ($request['requestBody']['content'] as $contentType => $content) {\n                    $mode = (strpos($contentType, 'json') !== false) ? 'json' : 'formdata';\n                    $this->processContentSchema($content, $contentArray, $mode);\n                    break;\n                }\n            }\n        }\n\n        $this->processParameters($request, $contentArray);\n    }\n\n    /**\n     * 处理内容 Schema\n     */\n    private function processContentSchema(array $content, array &$contentArray, string $mode): void\n    {\n        $contentArray['request']['params']['mode'] = $mode;\n\n        if (isset($content['schema'])) {\n            $schema = $content['schema'];\n\n            if ($mode === 'json' && (isset($schema['$ref']) || (isset($schema['type']) && $schema['type'] === 'object'))) {\n                $jsonObj = $this->toB($schema);\n                $contentArray['request']['params']['json'] = json_encode($jsonObj);\n\n                if (!empty($jsonObj)) {\n                    $schemaForDesc = $schema;\n                    if (isset($schema['$ref'])) {\n                        $refData = $this->getDefinition($schema['$ref']);\n                        if ($refData) {\n                            $schemaForDesc = $refData;\n                        }\n                    }\n                    $jsonDesc = $this->definitionToJsonArray($schemaForDesc);\n                    $contentArray['request']['params']['jsonDesc'] = $jsonDesc;\n                }\n            }\n\n            if (isset($schema['properties'])) {\n                foreach ($schema['properties'] as $key => $value) {\n                    $exampleValue = $value['example'] ?? '';\n\n                    $required = '0';\n                    if (isset($schema['required']) && is_array($schema['required']) && in_array($key, $schema['required'])) {\n                        $required = '1';\n                    }\n\n                    if (isset($value['type']) && $value['type'] === 'object' && isset($value['properties'])) {\n                        $subProperties = $this->definitionToJsonArray($value);\n                        foreach ($subProperties as $sub) {\n                            $contentArray['request']['params']['formdata'][] = [\n                                'name'    => $key . '[' . $sub['name'] . ']',\n                                'type'    => $sub['type'],\n                                'value'   => $sub['value'] ?? $exampleValue,\n                                'require' => ($sub['require'] ?? false) ? '1' : '0',\n                                'remark'  => $sub['remark'] ?? ($value['description'] ?? ''),\n                            ];\n                        }\n                    } else {\n                        $paramType = $value['type'] ?? 'string';\n                        if ($paramType === 'int') {\n                            $paramType = 'integer';\n                        }\n\n                        $contentArray['request']['params']['formdata'][] = [\n                            'name'    => $key,\n                            'type'    => $paramType,\n                            'value'   => $exampleValue,\n                            'require' => $required,\n                            'remark'  => $value['description'] ?? '',\n                        ];\n                    }\n                }\n            } elseif (isset($schema['$ref'])) {\n                $refData = $this->getDefinition($schema['$ref']);\n                if ($refData && isset($refData['properties'])) {\n                    foreach ($refData['properties'] as $key => $value) {\n                        $exampleValue = $value['example'] ?? '';\n\n                        $required = '0';\n                        if (isset($refData['required']) && is_array($refData['required']) && in_array($key, $refData['required'])) {\n                            $required = '1';\n                        }\n\n                        $paramType = $value['type'] ?? 'string';\n                        if ($paramType === 'int') {\n                            $paramType = 'integer';\n                        }\n\n                        $contentArray['request']['params']['formdata'][] = [\n                            'name'    => $key,\n                            'type'    => $paramType,\n                            'value'   => $exampleValue,\n                            'require' => $required,\n                            'remark'  => $value['description'] ?? '',\n                        ];\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * 处理 Swagger 2.0 请求\n     */\n    private function processSwagger2Request(array $request, array &$contentArray): void\n    {\n        if (isset($request['parameters'])) {\n            $hasBodyParam = false;\n            $bodySchema = null;\n\n            foreach ($request['parameters'] as $param) {\n                if (($param['in'] ?? '') == 'body' && isset($param['schema'])) {\n                    $hasBodyParam = true;\n                    $bodySchema = $param['schema'];\n                    break;\n                }\n            }\n\n            if ($hasBodyParam && $bodySchema) {\n                if (isset($request['consumes']) && (in_array('application/json', $request['consumes']) || in_array('text/json', $request['consumes']))) {\n                    $contentArray['request']['params']['mode'] = 'json';\n                    $jsonObj = $this->toB($bodySchema);\n                    $contentArray['request']['params']['json'] = json_encode($jsonObj);\n\n                    if (!empty($jsonObj)) {\n                        $schemaForDesc = $bodySchema;\n                        if (isset($bodySchema['$ref'])) {\n                            $refData = $this->getDefinition($bodySchema['$ref']);\n                            if ($refData) {\n                                $schemaForDesc = $refData;\n                            }\n                        }\n                        $jsonDesc = $this->definitionToJsonArray($schemaForDesc);\n                        $contentArray['request']['params']['jsonDesc'] = $jsonDesc;\n                    }\n                }\n\n                if (isset($bodySchema['$ref'])) {\n                    $refData = $this->getDefinition($bodySchema['$ref']);\n                    if ($refData) {\n                        $this->processSchemaProperties($refData, $contentArray);\n                    }\n                } elseif (isset($bodySchema['properties'])) {\n                    $this->processSchemaProperties($bodySchema, $contentArray);\n                }\n            }\n\n            $hasFormDataParams = false;\n            foreach ($request['parameters'] as $param) {\n                if (($param['in'] ?? '') == 'formData') {\n                    $hasFormDataParams = true;\n\n                    $exampleValue = $param['example'] ?? '';\n\n                    $paramType = $param['type'] ?? 'string';\n                    if ($paramType === 'int') {\n                        $paramType = 'integer';\n                    }\n\n                    $contentArray['request']['params']['formdata'][] = [\n                        'name'    => $param['name'],\n                        'type'    => $paramType,\n                        'value'   => $exampleValue,\n                        'require' => ($param['required'] ?? false) ? '1' : '0',\n                        'remark'  => $param['description'] ?? '',\n                    ];\n                }\n            }\n\n            if (!$hasBodyParam && $hasFormDataParams) {\n                $contentArray['request']['params']['mode'] = 'formdata';\n            }\n        }\n\n        $this->processParameters($request, $contentArray);\n    }\n\n    /**\n     * 处理 Schema 属性\n     */\n    private function processSchemaProperties(array $schema, array &$contentArray): void\n    {\n        if (isset($schema['properties'])) {\n            foreach ($schema['properties'] as $key => $value) {\n                $exampleValue = $value['example'] ?? '';\n\n                $required = '0';\n                if (isset($schema['required']) && is_array($schema['required']) && in_array($key, $schema['required'])) {\n                    $required = '1';\n                }\n\n                $paramType = $value['type'] ?? 'string';\n                if ($paramType === 'int') {\n                    $paramType = 'integer';\n                }\n\n                $contentArray['request']['params']['formdata'][] = [\n                    'name'    => $key,\n                    'type'    => $paramType,\n                    'value'   => $exampleValue,\n                    'require' => $required,\n                    'remark'  => $value['description'] ?? '',\n                ];\n            }\n        }\n    }\n\n    /**\n     * 处理参数（query 和 header）\n     */\n    private function processParameters(array $request, array &$contentArray): void\n    {\n        if (isset($request['parameters'])) {\n            foreach ($request['parameters'] as $param) {\n                if (($param['in'] ?? '') == 'query') {\n                    $exampleValue = $param['example'] ?? '';\n\n                    $paramType = $param['type'] ?? 'string';\n                    if ($paramType === 'int') {\n                        $paramType = 'integer';\n                    }\n\n                    $contentArray['request']['query'][] = [\n                        'name'    => $param['name'],\n                        'type'    => $paramType,\n                        'value'   => $exampleValue,\n                        'require' => ($param['required'] ?? false) ? '1' : '0',\n                        'remark'  => $param['description'] ?? '',\n                    ];\n                }\n\n                if (($param['in'] ?? '') == 'header') {\n                    $contentArray['request']['headers'][] = [\n                        'name'    => $param['name'],\n                        'type'    => 'string',\n                        'value'   => $param['example'] ?? '',\n                        'require' => ($param['required'] ?? false) ? '1' : '0',\n                        'remark'  => $param['description'] ?? '',\n                    ];\n                }\n            }\n        }\n    }\n\n    /**\n     * 处理 Swagger 2.0 响应\n     */\n    private function processSwagger2Response(array $request, array &$contentArray): void\n    {\n        if (isset($request['responses']['200'])) {\n            $refArray = [];\n            $example = null;\n\n            if (isset($request['responses']['200']['content'])) {\n                foreach ($request['responses']['200']['content'] as $contentType => $content) {\n                    if (isset($content['example'])) {\n                        $example = $content['example'];\n                        break;\n                    }\n                    if (isset($content['schema']['example'])) {\n                        $example = $content['schema']['example'];\n                        break;\n                    }\n                }\n            }\n\n            if (!$example && isset($request['responses']['200']['examples'])) {\n                foreach ($request['responses']['200']['examples'] as $contentType => $content) {\n                    $example = $content;\n                    break;\n                }\n            }\n\n            if (isset($request['responses']['200']['schema'])) {\n                $refArray = $request['responses']['200']['schema'];\n                if (!$example && isset($refArray['example'])) {\n                    $example = $refArray['example'];\n                }\n            }\n\n            if ($example !== null) {\n                if (is_string($example)) {\n                    $unescapedExample = stripslashes($example);\n                    if ((substr($unescapedExample, 0, 1) === '{' || substr($unescapedExample, 0, 1) === '[') &&\n                        json_decode($unescapedExample) !== null\n                    ) {\n                        $contentArray['response']['responseExample'] = $unescapedExample;\n                        $parsedExample = json_decode($unescapedExample, true);\n                        if (json_last_error() === JSON_ERROR_NONE) {\n                            $contentArray['response']['responseParamsDesc'] = $this->exampleToParamsDesc($parsedExample);\n                        }\n                    } else {\n                        $contentArray['response']['responseExample'] = $example;\n                    }\n                } else {\n                    $contentArray['response']['responseExample'] = json_encode($example);\n                    $contentArray['response']['responseParamsDesc'] = $this->exampleToParamsDesc($example);\n                }\n            } elseif (!empty($refArray)) {\n                $jsonArray = $this->definitionToJsonArray($refArray);\n                $jsonStr = $this->jsonArrayToStr($refArray);\n                $contentArray['response']['responseExample'] = $jsonStr;\n                $contentArray['response']['responseParamsDesc'] = $jsonArray;\n            } else {\n                $contentArray['response']['responseExample'] = '{}';\n                $contentArray['response']['responseParamsDesc'] = [];\n            }\n        }\n    }\n\n    /**\n     * 处理 OpenAPI 3.0 响应\n     */\n    private function processOpenAPI3Response(array $request, array &$contentArray): void\n    {\n        if (isset($request['responses']['200'])) {\n            $refArray = [];\n            $example = null;\n\n            if (isset($request['responses']['200']['content'])) {\n                foreach ($request['responses']['200']['content'] as $contentType => $content) {\n                    if (isset($content['examples']) && !empty($content['examples'])) {\n                        foreach ($content['examples'] as $exampleKey => $exampleObj) {\n                            if (isset($exampleObj['value'])) {\n                                $example = $exampleObj['value'];\n                                break;\n                            }\n                        }\n                        if ($example !== null) {\n                            break;\n                        }\n                    }\n\n                    if (isset($content['example'])) {\n                        $example = $content['example'];\n                        break;\n                    }\n\n                    if (isset($content['schema']['example'])) {\n                        $example = $content['schema']['example'];\n                        break;\n                    }\n\n                    if (isset($content['schema'])) {\n                        $refArray = $content['schema'];\n                    }\n                }\n            }\n\n            if ($example !== null) {\n                if (is_string($example)) {\n                    $unescapedExample = stripslashes($example);\n                    if ((substr($unescapedExample, 0, 1) === '{' || substr($unescapedExample, 0, 1) === '[') &&\n                        json_decode($unescapedExample) !== null\n                    ) {\n                        $contentArray['response']['responseExample'] = $unescapedExample;\n                        $parsedExample = json_decode($unescapedExample, true);\n                        if (json_last_error() === JSON_ERROR_NONE) {\n                            $contentArray['response']['responseParamsDesc'] = $this->exampleToParamsDesc($parsedExample);\n                        } elseif (!empty($refArray)) {\n                            $jsonArray = $this->definitionToJsonArray($refArray);\n                            $contentArray['response']['responseParamsDesc'] = $jsonArray;\n                        }\n                    } else {\n                        $contentArray['response']['responseExample'] = $example;\n                        if (!empty($refArray)) {\n                            $jsonArray = $this->definitionToJsonArray($refArray);\n                            $contentArray['response']['responseParamsDesc'] = $jsonArray;\n                        }\n                    }\n                } else {\n                    $contentArray['response']['responseExample'] = json_encode($example);\n                    if (is_array($example) || is_object($example)) {\n                        $contentArray['response']['responseParamsDesc'] = $this->exampleToParamsDesc($example);\n                    } elseif (!empty($refArray)) {\n                        $jsonArray = $this->definitionToJsonArray($refArray);\n                        $contentArray['response']['responseParamsDesc'] = $jsonArray;\n                    }\n                }\n            } elseif (!empty($refArray)) {\n                $jsonArray = $this->definitionToJsonArray($refArray);\n                $jsonStr = $this->jsonArrayToStr($refArray);\n                $contentArray['response']['responseExample'] = $jsonStr;\n                $contentArray['response']['responseParamsDesc'] = $jsonArray;\n            } else {\n                $contentArray['response']['responseExample'] = '{}';\n                $contentArray['response']['responseParamsDesc'] = [];\n            }\n        }\n    }\n\n    /**\n     * 将 example 转换为参数描述\n     */\n    private function exampleToParamsDesc($example, string $parentKey = ''): array\n    {\n        $res = [];\n\n        if (is_array($example)) {\n            foreach ($example as $key => $value) {\n                $fullKey = $parentKey ? $parentKey . '.' . $key : $key;\n\n                if (is_array($value)) {\n                    if (!empty($value) && (is_array(reset($value)) || is_object(reset($value)))) {\n                        $childParams = $this->exampleToParamsDesc(reset($value), $fullKey);\n                        $res = array_merge($res, $childParams);\n                    } else {\n                        $res[] = [\n                            'name'    => $fullKey,\n                            'type'    => 'array',\n                            'value'   => '',\n                            'require' => '0',\n                            'remark'  => '',\n                        ];\n                        $childParams = $this->exampleToParamsDesc($value, $fullKey);\n                        $res = array_merge($res, $childParams);\n                    }\n                } else {\n                    $res[] = [\n                        'name'    => $fullKey,\n                        'type'    => $this->getTypeFromValue($value),\n                        'value'   => '',\n                        'require' => '0',\n                        'remark'  => '',\n                    ];\n                }\n            }\n        }\n\n        return $res;\n    }\n\n    /**\n     * 根据值获取类型\n     */\n    private function getTypeFromValue($value): string\n    {\n        if (is_null($value)) {\n            return 'null';\n        }\n        if (is_bool($value)) {\n            return 'boolean';\n        }\n        if (is_int($value)) {\n            return 'integer';\n        }\n        if (is_float($value)) {\n            return 'number';\n        }\n        if (is_string($value)) {\n            return 'string';\n        }\n        if (is_array($value)) {\n            return 'array';\n        }\n        if (is_object($value)) {\n            return 'object';\n        }\n\n        return 'string';\n    }\n}\n"
  },
  {
    "path": "server/app/Api/Controller/ItemController.php",
    "content": "<?php\n\nnamespace App\\Api\\Controller;\n\nuse App\\Common\\BaseController;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\n/**\n * 项目相关 Api（新架构，逐步替换旧的 Api\\Controller\\ItemController）。\n *\n * 目前优先迁移与「项目列表」相关的接口，例如：\n * - myList：我的项目列表（本人创建 + 成员项目 + 团队成员项目）\n */\nclass ItemController extends BaseController\n{\n    /**\n     * 我的项目列表（兼容旧接口 Api/Item/myList）。\n     *\n     * 特性：\n     * - 聚合本人创建项目、作为成员参与的项目、团队成员项目；\n     * - 支持原创筛选 original=1；\n     * - 支持项目分组 item_group_id（含 -1 仅星标分组）；\n     * - 返回 creator / manage / is_private / is_star / top / s_number 等字段；\n     * - 仅基于 user_token 鉴权，不再依赖旧 session。\n     */\n    public function myList(Request $request, Response $response): Response\n    {\n        // 等价于旧世界的 checkLogin()\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid          = (int) ($loginUser['uid'] ?? 0);\n        $original     = $this->getParam($request, 'original', 0);\n        $itemGroupId  = $this->getParam($request, 'item_group_id', 0);\n\n        // 1. 收集\"成员项目\"和\"管理项目\"的 item_id 集合\n        $memberItemIds       = ['-1']; // 只读 + 编辑成员（使用字符串，与数据库返回类型一致）\n        $manageMemberItemIds = ['-1']; // 拥有管理权限的成员（使用字符串，与数据库返回类型一致）\n\n        // ItemMember：成员项目\n        $rows = DB::table('item_member')\n            ->where('uid', $uid)\n            ->where('member_group_id', '!=', 2)\n            ->get();\n        foreach ($rows as $row) {\n            $memberItemIds[] = (string) $row->item_id; // 直接使用数据库返回的值，转为字符串保持一致\n        }\n\n        // TeamItemMember：团队成员项目（非管理组）\n        $rows = DB::table('team_item_member')\n            ->where('member_uid', $uid)\n            ->where('member_group_id', '!=', 2)\n            ->get();\n        foreach ($rows as $row) {\n            $memberItemIds[] = (string) $row->item_id;\n        }\n\n        // ItemMember：拥有项目管理权限的成员（group_id = 2）\n        $rows = DB::table('item_member')\n            ->where('uid', $uid)\n            ->where('member_group_id', 2)\n            ->get();\n        foreach ($rows as $row) {\n            $manageMemberItemIds[] = (string) $row->item_id;\n        }\n\n        // TeamItemMember：团队成员中的管理组\n        $rows = DB::table('team_item_member')\n            ->where('member_uid', $uid)\n            ->where('member_group_id', 2)\n            ->get();\n        foreach ($rows as $row) {\n            $manageMemberItemIds[] = (string) $row->item_id;\n        }\n\n        // 2. 星标项目列表（多个地方会用到）\n        // 注意：旧后端使用 intval，但为了保持类型一致，这里也使用字符串\n        $starItemIds = [];\n        $rows        = DB::table('item_star')\n            ->where('uid', $uid)\n            ->get();\n        foreach ($rows as $row) {\n            $starItemIds[] = (string) $row->item_id;\n        }\n\n        // 3. 构建基础查询：本人 + 成员 + 管理项目\n        $query = DB::table('item')\n            ->select([\n                'item_id',\n                'uid',\n                'item_name',\n                'item_domain',\n                'item_type',\n                'last_update_time',\n                'item_description',\n                'is_del',\n                'password',\n            ])\n            ->where(function ($q) use ($uid, $memberItemIds, $manageMemberItemIds) {\n                $q->where('uid', $uid)\n                    ->orWhereIn('item_id', $memberItemIds)\n                    ->orWhereIn('item_id', $manageMemberItemIds);\n            });\n\n        // 4. 项目分组筛选（>0：按分组；===-1：仅星标项目）\n        if ($itemGroupId > 0) {\n            $groupRow = DB::table('item_group')\n                ->where('id', $itemGroupId)\n                ->where('uid', $uid)\n                ->first();\n\n            if ($groupRow && !empty($groupRow->item_ids)) {\n                $ids = array_filter(array_map('intval', explode(',', (string) $groupRow->item_ids)));\n                if ($ids) {\n                    $query->whereIn('item_id', $ids);\n                } else {\n                    // 分组为空时保持与旧实现一致：查询一个永远不存在的 id\n                    $query->where('item_id', 0);\n                }\n            } else {\n                $query->where('item_id', 0);\n            }\n        }\n\n        // item_group_id === -1：仅返回星标项目\n        if ($itemGroupId === -1) {\n            if ($starItemIds) {\n                $query->whereIn('item_id', $starItemIds);\n            } else {\n                $query->where('item_id', 0);\n            }\n        }\n\n        // 5. 拉取项目列表（按 item_id 升序，与旧实现保持一致）\n        $rows = $query\n            ->orderBy('item_id', 'asc')\n            ->get()\n            ->all();\n\n        $items = [];\n        foreach ($rows as $row) {\n            // 使用 json_decode(json_encode()) 将对象转换为数组，保持与 ThinkPHP 返回格式完全一致\n            // 这样可以确保所有字段（特别是 item_name）都被正确保留，同时保持原始数据类型\n            // json_encode 会将对象转换为 JSON，json_decode(..., true) 会将其转换为关联数组\n            $item = json_decode(json_encode($row), true);\n\n            // 确保 item_name 始终是字符串类型（不能为 null），否则 Element UI 的 el-select 会回退显示 value\n            if (!isset($item['item_name']) || $item['item_name'] === null) {\n                $item['item_name'] = '';\n            }\n\n            // 默认排序号\n            $item['s_number'] = 0;\n\n            // creator / manage 判断（使用类型安全的比较，兼容数据库返回的字符串或整数）\n            if ($item['uid'] == $uid) {\n                $item['creator'] = 1;\n                $item['manage']  = 1;\n            } elseif (in_array((string)$item['item_id'], $manageMemberItemIds)) {\n                // 使用宽松比较避免MySQL返回字符串类型时匹配失败\n                $item['creator'] = 0;\n                $item['manage']  = 1;\n            } else {\n                $item['creator'] = 0;\n                $item['manage']  = 0;\n                // 非创建者且无管理权限时，不返回项目密码\n                unset($item['password']);\n            }\n\n            // 判定私密项目\n            $item['is_private'] = empty($item['password'] ?? '') ? 0 : 1;\n\n            // 过滤已标记删除的项目（直接使用数据库返回的值进行比较）\n            if (($item['is_del'] ?? 0) == 1) {\n                continue;\n            }\n\n            // 仅原创项目（直接使用数据库返回的值进行比较）\n            if ($original > 0 && ($item['uid'] ?? 0) != $uid) {\n                continue;\n            }\n\n            // 星标标记（使用宽松比较，兼容数据库返回字符串或整数）\n            $item['is_star'] = in_array((string)($item['item_id'] ?? '0'), $starItemIds) ? 1 : 0;\n\n            $items[] = $item;\n        }\n\n        // 6. 处理置顶项目（ItemTop）\n        // 注意：只有在有置顶项目时才添加 top 字段，与旧后端逻辑保持一致\n        if ($items) {\n            $topItemIds = [];\n            $topRows    = DB::table('item_top')\n                ->where('uid', $uid)\n                ->get();\n            foreach ($topRows as $row) {\n                $topItemIds[] = (string) $row->item_id; // 使用字符串，与数据库返回类型一致\n            }\n\n            // 只有在有置顶项目时才处理，与旧后端逻辑一致\n            if ($topItemIds) {\n                $topList    = [];\n                $normalList = [];\n                foreach ($items as &$item) {\n                    // 给所有项目添加 top 字段（与旧后端逻辑一致）\n                    $item['top'] = 0;\n                    // 使用宽松比较，兼容数据库返回字符串或整数\n                    if (in_array((string)$item['item_id'], $topItemIds)) {\n                        $item['top'] = 1;\n                        $topList[]   = $item;\n                    } else {\n                        $normalList[] = $item;\n                    }\n                }\n                unset($item);\n                $items = array_merge($topList, $normalList);\n            }\n            // 如果没有置顶项目，不添加 top 字段（与旧后端逻辑一致）\n        }\n\n        // 7. 读取项目顺序配置（ItemSort）\n        if ($items) {\n            $sortRow = DB::table('item_sort')\n                ->where('uid', $uid)\n                ->where('item_group_id', $itemGroupId)\n                ->first();\n\n            if ($sortRow && !empty($sortRow->item_sort_data)) {\n                $json = htmlspecialchars_decode((string) $sortRow->item_sort_data, ENT_QUOTES);\n                $map  = json_decode($json, true) ?: [];\n\n                if (is_array($map) && $map) {\n                    foreach ($items as &$item) {\n                        $id = $item['item_id']; // 直接使用数据库返回的值\n                        // map 的键可能是字符串或数字，需要兼容两种情况\n                        $idInt = (int) $id;\n                        if (isset($map[$idInt])) {\n                            $item['s_number'] = $map[$idInt];\n                        } elseif (isset($map[$id])) {\n                            $item['s_number'] = $map[$id];\n                        } else {\n                            $item['s_number'] = $id;\n                        }\n                    }\n                    unset($item);\n\n                    // 按 s_number 升序排序，保持与旧版 _sort_by_key 行为一致\n                    usort($items, function (array $a, array $b): int {\n                        $sa = (int) ($a['s_number'] ?? 0);\n                        $sb = (int) ($b['s_number'] ?? 0);\n                        if ($sa === $sb) {\n                            return 0;\n                        }\n                        return $sa < $sb ? -1 : 1;\n                    });\n                }\n            }\n        }\n\n        return $this->success($response, array_values($items));\n    }\n\n    /**\n     * 项目详情接口（兼容旧接口 Api/Item/info）。\n     *\n     * 功能：\n     * - 支持 item_id 或 item_domain 参数\n     * - 检查访问权限\n     * - 获取菜单（支持搜索、筛选）\n     * - 返回完整的项目信息（包括 AI 配置、全局参数等）\n     */\n    public function info(Request $request, Response $response): Response\n    {\n        // 获取参数（兼容 item_id 和 item_domain）\n        $itemId    = $this->getParam($request, 'item_id', \"\");\n        $itemDomain = $this->getParam($request, 'item_domain', '');\n        $currentPageId = $this->getParam($request, 'page_id', 0);\n        $defaultPageId = $this->getParam($request, 'default_page_id', 0);\n        $keyword = $this->getParam($request, 'keyword', '');\n        $filterStatus = $this->getParam($request, 'filter_status', '');\n        $showMD = $this->getParam($request, 'show_md', 1);\n\n        // 如果 item_id 不是数字，则视为 item_domain\n        if (!is_numeric($itemId)) {\n            $itemDomain = (string) $itemId;\n            $itemId    = 0;\n        } else {\n            $itemId = (int) $itemId;\n        }\n\n        // 通过 item_domain 查找 item_id\n        if ($itemDomain !== '') {\n            $item = \\App\\Model\\Item::findByDomain($itemDomain);\n            if ($item && !empty($item->item_id)) {\n                $itemId = (int) $item->item_id;\n            }\n        }\n\n        if ($itemId <= 0) {\n            return $this->error($response, 10101, '项目不存在或者已删除');\n        }\n\n        // 获取登录用户（非严格模式，允许游客访问）\n        $loginUser = [];\n        $this->requireLoginUser($request, $response, $loginUser, false);\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        // 检查访问权限\n        if (!$this->checkItemVisit($uid, $itemId)) {\n            return $this->error($response, 10303, '您没有访问权限');\n        }\n\n        // 获取项目信息\n        $item = \\App\\Model\\Item::findById($itemId);\n        if (!$item || (int) $item->is_del === 1) {\n            // 防止暴力扫描，延迟返回\n            sleep(1);\n            return $this->error($response, 10101, '项目不存在或者已删除');\n        }\n\n        // 获取菜单\n        $menu = [];\n        if (!empty($keyword)) {\n            // 搜索模式：获取用户有权限的目录 ID\n            $catIds = \\App\\Model\\Member::getCatIds($itemId, $uid);\n            $menu['pages']    = \\App\\Model\\Page::search($itemId, $catIds, $keyword, $uid);\n            $menu['catalogs'] = [];\n        } else {\n            // 正常模式：获取完整菜单\n            $menu = \\App\\Model\\Item::getMenuByCache($itemId);\n            if ($uid > 0) {\n                $menu = \\App\\Model\\Item::filterMemberItem($uid, $itemId, $menu);\n            }\n            // 过滤草稿页面（对所有用户都生效，包括游客）\n            // 游客（uid=0）看不到任何草稿，登录用户只能看到自己创建的草稿\n            $menu = \\App\\Model\\Item::filterDraftPages($menu, $uid);\n        }\n\n        // 应用筛选条件\n        if ($filterStatus || !$showMD) {\n            $menu = $this->applyFilters($menu, $filterStatus, $showMD, $itemId);\n        }\n\n        // 获取权限信息\n        $itemEdit   = $this->checkItemEdit($uid, $itemId);\n        $itemManage = $this->checkItemManage($uid, $itemId);\n\n        // 获取未读消息数（使用 Message 系统，替代旧的 Notice 统计）\n        $unreadCount = 0;\n        if ($uid > 0) {\n            try {\n                $unreadCount = \\App\\Model\\Message::getRemindList($uid, 1, 1, 0)['total'] ?? 0;\n            } catch (\\Throwable $e) {\n                $unreadCount = 0;\n            }\n        }\n\n        // 获取默认展开的目录信息\n        $defaultCatId2 = $defaultCatId3 = $defaultCatId4 = 0;\n        if ($defaultPageId > 0) {\n            $page = \\App\\Model\\Page::findByIdWithContent($itemId, $defaultPageId);\n            if ($page && !empty($page['cat_id'])) {\n                $defaultCatId4 = (int) $page['cat_id'];\n                $cat1          = \\App\\Model\\Catalog::findById($defaultCatId4);\n                if ($cat1 && (int) $cat1->parent_cat_id > 0) {\n                    $defaultCatId3 = (int) $cat1->parent_cat_id;\n                    $cat2          = \\App\\Model\\Catalog::findById($defaultCatId3);\n                    if ($cat2 && (int) $cat2->parent_cat_id > 0) {\n                        $defaultCatId2 = (int) $cat2->parent_cat_id;\n                    } else {\n                        $defaultCatId2 = $defaultCatId3;\n                        $defaultCatId3 = 0;\n                    }\n                } else {\n                    $defaultCatId3 = $defaultCatId4;\n                    $defaultCatId4 = 0;\n                }\n            }\n        }\n\n        // 归档项目去掉编辑权限\n        if (!empty($item->is_archived)) {\n            $itemEdit   = false;\n            $itemManage = false;\n        }\n\n        // 获取全局参数（RunApi 项目）\n        $globalParam = [];\n        if ((int) $item->item_type === 3) {\n            $globalParam = \\App\\Model\\Runapi::getGlobalParam($itemId);\n        }\n\n        // 获取 AI 配置\n        $aiConfig = \\App\\Model\\ItemAiConfig::getConfig($itemId);\n\n        // 检查强制登录设置\n        $forceLogin = (int) \\App\\Model\\Options::get('force_login', 0);\n        if ($forceLogin > 0 && $uid <= 0) {\n            return $this->error($response, 10312, '需要登录');\n        }\n\n        // 获取水印配置\n        $watermarkConfig = \\App\\Model\\Options::get('show_watermark', 0);\n        // 转换，如果是布尔值或者字符串true 或者 1 则返回1，否则返回0\n        $watermarkConfig = $watermarkConfig == true || $watermarkConfig == 'true' || $watermarkConfig == 1 ? 1 : 0;\n\n        // 构建返回数据\n        // 直接使用数据库返回的原始 item_id，保持数据库配置的类型（字符串），不进行类型转换\n        $domain = !empty($item->item_domain) ? $item->item_domain : (string) $item->item_id;\n\n        $return = [\n            'item_id'                    => $item->item_id, // 直接使用数据库返回的原始值\n            'item_domain'                => $item->item_domain ?? '',\n            'is_archived'                => $item->is_archived ?? 0, // 直接使用数据库返回的原始值\n            'item_name'                  => $item->item_name ?? '',\n            'default_page_id'            => (string) $defaultPageId, // 这个是参数，保持字符串类型\n            'default_cat_id2'            => $defaultCatId2,\n            'default_cat_id3'            => $defaultCatId3,\n            'default_cat_id4'            => $defaultCatId4,\n            'unread_count'               => $unreadCount,\n            'item_type'                  => $item->item_type ?? 0, // 直接使用数据库返回的原始值\n            'menu'                       => $menu,\n            'is_login'                   => $uid > 0,\n            'item_edit'                  => $itemEdit,\n            'item_manage'                => $itemManage,\n            'ItemPermn'                  => $itemEdit, // 兼容字段\n            'ItemCreator'                => $itemManage, // 兼容字段\n            'current_page_id'            => $currentPageId,\n            'global_param'               => $globalParam,\n            'show_watermark'             => $watermarkConfig,\n            'allow_comment'              => $item->allow_comment ?? 0, // 直接使用数据库返回的原始值\n            'allow_feedback'             => $item->allow_feedback ?? 0, // 直接使用数据库返回的原始值\n            'ai_knowledge_base_enabled'  => $aiConfig['enabled'] ?? 0, // 直接使用配置返回的原始值\n            'ai_config'                 => $aiConfig,\n        ];\n\n        return $this->success($response, $return);\n    }\n\n    /**\n     * 应用筛选条件（状态筛选、Markdown 文档筛选）\n     *\n     * 精确对齐旧版 ThinkPHP 行为：\n     * - 是否为 Markdown 文档：通过真实的 page_content 判断，而不是仅依赖 ext_info；\n     * - 状态筛选：基于 RunApi JSON 中的 info.apiStatus，并映射为中文状态文案。\n     *\n     * @param array  $menu         菜单结构\n     * @param string $filterStatus 状态筛选（格式：开发中,测试中,已完成）\n     * @param int    $showMD       是否显示 Markdown 文档（1显示，0不显示）\n     * @param int    $itemId       项目 ID\n     * @return array 筛选后的菜单结构\n     */\n    private function applyFilters(array $menu, string $filterStatus, int $showMD, int $itemId): array\n    {\n        if (empty($menu)) {\n            return $menu;\n        }\n\n        // 处理根目录的页面\n        if (!empty($menu['pages']) && is_array($menu['pages'])) {\n            $filteredPages = [];\n            foreach ($menu['pages'] as $page) {\n                if ($this->shouldShowPage($page, $filterStatus, $showMD, $itemId)) {\n                    $filteredPages[] = $page;\n                }\n            }\n            $menu['pages'] = $filteredPages;\n        }\n\n        // 递归处理目录\n        if (!empty($menu['catalogs']) && is_array($menu['catalogs'])) {\n            $this->filterCatalogsRecursive($menu['catalogs'], $filterStatus, $showMD, $itemId);\n        }\n\n        return $menu;\n    }\n\n    /**\n     * 递归过滤目录（精确还原旧版逻辑）\n     *\n     * @param array  $catalogs     目录列表（引用传递）\n     * @param string $statusFilter 状态筛选字符串\n     * @param int    $showMD       是否显示 Markdown\n     * @param int    $itemId       项目 ID\n     */\n    private function filterCatalogsRecursive(array &$catalogs, string $statusFilter, int $showMD, int $itemId): void\n    {\n        if (empty($catalogs)) {\n            return;\n        }\n\n        foreach ($catalogs as &$catalog) {\n            // 处理目录下的页面\n            if (!empty($catalog['pages']) && is_array($catalog['pages'])) {\n                $filteredPages = [];\n                foreach ($catalog['pages'] as $page) {\n                    if ($this->shouldShowPage($page, $statusFilter, $showMD, $itemId)) {\n                        $filteredPages[] = $page;\n                    }\n                }\n                $catalog['pages'] = $filteredPages;\n            }\n\n            // 递归处理子目录\n            if (!empty($catalog['catalogs']) && is_array($catalog['catalogs'])) {\n                $this->filterCatalogsRecursive($catalog['catalogs'], $statusFilter, $showMD, $itemId);\n            }\n        }\n        unset($catalog);\n    }\n\n    /**\n     * 判断单个页面是否应该展示（精确对齐旧版 shouldShowPage 行为）\n     *\n     * 规则：\n     * - 通过读取 page_content，尝试按 RunApi JSON 解析；\n     * - 若无法解析为带 info.url 的 JSON，则视为 Markdown 文档；\n     * - showMD=0 时隐藏 Markdown 文档；\n     * - 有状态筛选时，根据 info.apiStatus → 中文文案做匹配。\n     *\n     * @param array  $page         页面数据（菜单中的节点）\n     * @param string $statusFilter 状态筛选字符串（如 \"开发中,测试中\"）\n     * @param int    $showMD       是否显示 Markdown（1 显示，0 不显示）\n     * @param int    $itemId       项目 ID\n     * @return bool\n     */\n    private function shouldShowPage(array $page, string $statusFilter, int $showMD, int $itemId): bool\n    {\n        $pageId = (int) ($page['page_id'] ?? 0);\n        if ($pageId <= 0) {\n            // 没有 page_id 的节点，当作普通文档处理\n            return $showMD === 1;\n        }\n\n        // 从数据库获取页面内容（兼容旧数据的压缩/解压逻辑由 Page 模型处理）\n        $pageRow = \\App\\Model\\Page::findByIdWithContent($itemId, $pageId);\n        if (!$pageRow) {\n            // 取不到内容时，遵循旧逻辑：仅受 showMD 控制\n            return $showMD === 1;\n        }\n\n        $pageContent = (string) ($pageRow['page_content'] ?? '');\n\n        // 先进行 HTML 转义还原，然后尝试按 JSON 解析\n        $decodedContent = htmlspecialchars_decode($pageContent);\n        $obj            = json_decode($decodedContent, true);\n\n        // 如果解析失败或者没有 info.url 字段，说明是 markdown 文档\n        if (!$obj || !isset($obj['info']) || !isset($obj['info']['url'])) {\n            return $showMD === 1;\n        }\n\n        // 到这里说明是接口文档。如果没有状态筛选，则直接展示\n        if ($statusFilter === '') {\n            return true;\n        }\n\n        // 状态筛选\n        $statusArray = array_filter(array_map('trim', explode(',', $statusFilter)));\n        if (empty($statusArray)) {\n            return true;\n        }\n\n        $apiStatus = $obj['info']['apiStatus'] ?? null;\n        $pageStatusText = $this->getStatusTextFromApiStatus($apiStatus);\n        if ($pageStatusText === '') {\n            $pageStatusText = '未操作';\n        }\n\n        return in_array($pageStatusText, $statusArray, true);\n    }\n\n    /**\n     * 将 RunApi 的 apiStatus 数值映射为中文状态文案（保持与旧版 getStatusText 一致）\n     *\n     * @param mixed $status\n     * @return string\n     */\n    private function getStatusTextFromApiStatus($status): string\n    {\n        $statusMap = [\n            '0' => '未操作',\n            '1' => '开发中',\n            '2' => '测试中',\n            '3' => '已完成',\n            '4' => '需修改',\n            '5' => '已废弃',\n        ];\n\n        $key = (string) $status;\n        return $statusMap[$key] ?? '未操作';\n    }\n\n    /**\n     * 项目详细信息（管理用）（兼容旧接口 Api/Item/detail）。\n     *\n     * 功能：\n     * - 获取项目的详细信息\n     * - 权限检查（checkItemManage）\n     * - 返回项目所属分组（多选）\n     */\n    public function detail(Request $request, Response $response): Response\n    {\n        $itemId = $this->getParam($request, 'item_id', 0);\n\n        if ($itemId <= 0) {\n            return $this->error($response, 10101, '项目不存在');\n        }\n\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        // 检查管理权限\n        if (!$this->checkItemManage($uid, $itemId)) {\n            return $this->error($response, 10303, '您没有管理权限');\n        }\n\n        // 获取项目信息\n        $item = \\App\\Model\\Item::findById($itemId);\n        if (!$item) {\n            return $this->error($response, 10101, '项目不存在');\n        }\n\n        $data = (array) $item;\n\n        // 返回项目所属分组（多选）。基于当前登录用户的分组\n        $groupIds = [];\n        $groups = DB::table('item_group')\n            ->where('uid', $uid)\n            ->get()\n            ->all();\n\n        foreach ($groups as $g) {\n            $itemIds = (string) ($g->item_ids ?? '');\n            if (!empty($itemIds)) {\n                $ids = explode(',', $itemIds);\n                // 使用宽松比较，自动处理字符串和整数的匹配\n                if (in_array($itemId, $ids)) {\n                    $groupIds[] = (int) $g->id;\n                }\n            }\n        }\n\n        $data['group_ids'] = $groupIds;\n\n        return $this->success($response, $data);\n    }\n\n    /**\n     * 获取项目的 AI 知识库配置（兼容旧接口 Api/Item/getAiKnowledgeBaseConfig）。\n     */\n    public function getAiKnowledgeBaseConfig(Request $request, Response $response): Response\n    {\n        // 登录用户（非严格模式，允许游客访问，只用于权限判断）\n        $loginUser = [];\n        $this->requireLoginUser($request, $response, $loginUser, false);\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        $itemId = (int) $this->getParam($request, 'item_id', 0);\n        if ($itemId <= 0) {\n            return $this->error($response, 10101, '项目ID不能为空');\n        }\n\n        // 检查项目访问权限\n        if (!$this->checkItemVisit($uid, $itemId)) {\n            return $this->error($response, 10303, '您没有访问该项目的权限');\n        }\n\n        // 获取配置（可能为 null，这里统一转换为数组，避免 success() 类型错误）\n        $config = \\App\\Model\\ItemAiConfig::getConfig($itemId) ?? [];\n\n        // 如果项目已启用 AI 知识库，检查索引状态，如果索引不存在则自动重建\n        if (!empty($config['enabled'])) {\n            $aiServiceUrl   = \\App\\Model\\Options::get('ai_service_url', '');\n            $aiServiceToken = \\App\\Model\\Options::get('ai_service_token', '');\n\n            if ($aiServiceUrl && $aiServiceToken) {\n                // 检查索引状态\n                $statusUrl   = rtrim($aiServiceUrl, '/') . '/api/index/status?item_id=' . $itemId;\n                $indexStatus = \\App\\Common\\Helper\\AiHelper::callService($statusUrl, null, $aiServiceToken, 'GET', 10);\n\n                // 如果索引不存在（被删除或从未创建），则自动触发重建（异步，不阻塞当前请求）\n                if ($indexStatus === false || (isset($indexStatus['indexed']) && !$indexStatus['indexed'])) {\n                    register_shutdown_function(function () use ($itemId, $aiServiceUrl, $aiServiceToken) {\n                        \\App\\Common\\Helper\\AiHelper::rebuild($itemId, $aiServiceUrl, $aiServiceToken);\n                    });\n                }\n\n                // 可选：预热模型（不影响返回结果，失败静默）\n                try {\n                    $warmupUrl   = rtrim($aiServiceUrl, '/') . '/api/warmup';\n                    \\App\\Common\\Helper\\AiHelper::callService($warmupUrl, null, $aiServiceToken, 'POST', 3);\n                } catch (\\Throwable $e) {\n                    // 忽略预热异常\n                }\n            }\n        }\n\n        return $this->success($response, $config);\n    }\n\n    /**\n     * 更新项目信息（兼容旧接口 Api/Item/update）。\n     *\n     * 功能：\n     * - 更新项目基本信息\n     * - 权限检查（checkItemManage）\n     * - 个性域名唯一性检查\n     * - 处理项目分组（多选）\n     * - 处理评论和反馈功能开关\n     */\n    public function update(Request $request, Response $response): Response\n    {\n        $itemId          = $this->getParam($request, 'item_id', 0);\n        $itemName        = $this->getParam($request, 'item_name', '');\n        $itemDescription = $this->getParam($request, 'item_description', '');\n        $itemDomain      = $this->getParam($request, 'item_domain', '');\n        $password        = $this->getParam($request, 'password', '');\n        $itemGroupId     = $this->getParam($request, 'item_group_id', 0);\n        $itemGroupIdsRaw = $this->getParam($request, 'item_group_ids', '');\n        $allowComment    = $this->getParam($request, 'allow_comment', null);\n        $allowFeedback   = $this->getParam($request, 'allow_feedback', null);\n\n        if ($itemId <= 0) {\n            return $this->error($response, 10101, '项目不存在');\n        }\n\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        // 检查管理权限\n        if (!$this->checkItemManage($uid, $itemId)) {\n            return $this->error($response, 10303, '您没有管理权限');\n        }\n\n\n        // 准备更新数据\n        $saveData = [\n            'item_name'        => $itemName,\n            'item_description' => $itemDescription,\n            'password'         => $password,\n            //更新时间\n            'last_update_time'      => time(),\n        ];\n\n        // 处理评论和反馈功能开关（仅常规项目）\n        $item = \\App\\Model\\Item::findById($itemId);\n        if ($item && (int) $item->item_type === 1) {\n            if ($allowComment !== null) {\n                $saveData['allow_comment'] = $allowComment ? 1 : 0;\n            }\n            if ($allowFeedback !== null) {\n                $saveData['allow_feedback'] = $allowFeedback ? 1 : 0;\n            }\n        }\n\n        // 更新项目信息\n        $affected = DB::table('item')\n            ->where('item_id', $itemId)\n            ->update($saveData);\n\n        if ($affected <= 0) {\n            return $this->error($response, 10101, '更新失败');\n        }\n\n        // 处理项目分组（多选）\n        $selectedGroupIds = [];\n        if (!empty($itemGroupIdsRaw)) {\n            if (is_array($itemGroupIdsRaw)) {\n                $selectedGroupIds = $itemGroupIdsRaw;\n            } else {\n                // 兼容前端传字符串（JSON 或逗号分隔）\n                $tmp = json_decode(htmlspecialchars_decode($itemGroupIdsRaw), true);\n                if (is_array($tmp)) {\n                    $selectedGroupIds = $tmp;\n                } else {\n                    $selectedGroupIds = explode(',', (string) $itemGroupIdsRaw);\n                }\n            }\n        } elseif ($itemGroupId > 0) {\n            $selectedGroupIds = [$itemGroupId];\n        }\n\n        // 过滤有效数字 id\n        $selectedGroupIds = array_values(array_unique(array_filter(array_map('intval', $selectedGroupIds))));\n\n        if (!empty($selectedGroupIds)) {\n            // 拉取当前用户的全部分组，进行增删\n            $groups = DB::table('item_group')\n                ->where('uid', $uid)\n                ->get()\n                ->all();\n\n            foreach ($groups as $g) {\n                $gId = (int) $g->id;\n                $itemIds = (string) ($g->item_ids ?? '');\n                $ids = [];\n\n                if (!empty($itemIds)) {\n                    $ids = array_filter(array_map('intval', explode(',', $itemIds)));\n                }\n\n                if (in_array($gId, $selectedGroupIds, true)) {\n                    // 需要包含此项目\n                    if (!in_array($itemId, $ids, true)) {\n                        $ids[] = $itemId;\n                        $ids = array_values(array_unique($ids));\n                        DB::table('item_group')\n                            ->where('id', $gId)\n                            ->update(['item_ids' => implode(',', $ids)]);\n                    }\n                } else {\n                    // 需要移除此项目\n                    $ids = array_values(array_filter($ids, function ($id) use ($itemId) {\n                        return $id !== $itemId;\n                    }));\n                    DB::table('item_group')\n                        ->where('id', $gId)\n                        ->update(['item_ids' => implode(',', $ids)]);\n                }\n            }\n        }\n\n        return $this->success($response, ['success' => true]);\n    }\n\n    /**\n     * 创建项目（兼容旧接口 Api/Item/add）\n     */\n    public function add(Request $request, Response $response): Response\n    {\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n        $itemName = trim($this->getParam($request, 'item_name', ''));\n        $itemDomain = trim($this->getParam($request, 'item_domain', ''));\n        $copyItemId = $this->getParam($request, 'copy_item_id', 0);\n        $password = $this->getParam($request, 'password', '');\n        $itemDescription = $this->getParam($request, 'item_description', '');\n        $itemType = $this->getParam($request, 'item_type', 1);\n        $itemGroupId = $this->getParam($request, 'item_group_id', 0);\n        $itemGroupIdsRaw = $this->getParam($request, 'item_group_ids', '');\n        $allowComment = $this->getParam($request, 'allow_comment', null);\n        $allowFeedback = $this->getParam($request, 'allow_feedback', null);\n\n        if ($itemName === '') {\n            return $this->error($response, 10100, '项目名不能为空');\n        }\n\n        // 检查个性域名\n        if ($itemDomain !== '') {\n            if (!ctype_alnum($itemDomain) || is_numeric($itemDomain)) {\n                return $this->error($response, 10305);\n            }\n\n            $existing = \\App\\Model\\Item::findByDomain($itemDomain);\n            if ($existing) {\n                return $this->error($response, 10304);\n            }\n        }\n\n        // 如果是复制项目\n        if ($copyItemId > 0) {\n            if (!$this->checkItemEdit($uid, $copyItemId)) {\n                return $this->error($response, 10101, '没有编辑权限');\n            }\n\n            $newItemId = \\App\\Model\\Item::copy($copyItemId, $uid, $itemName, $itemDescription, $password, $itemDomain);\n            if ($newItemId) {\n                return $this->success($response, ['item_id' => $newItemId]);\n            } else {\n                return $this->error($response, 10101);\n            }\n        }\n\n        // 创建新项目\n        $newItemId = \\App\\Model\\Item::getANewItemId();\n        $user = \\App\\Model\\User::findById($uid);\n        $username = $user ? ($user->username ?? '') : '';\n\n        $insertData = [\n            'item_id'          => $newItemId,\n            'uid'              => $uid,\n            'username'         => $username,\n            'item_name'        => $itemName,\n            'password'         => $password,\n            'item_description' => $itemDescription,\n            'item_domain'      => $itemDomain,\n            'item_type'        => (int) $itemType,\n            'addtime'          => time(),\n        ];\n\n        // 处理评论和反馈功能开关（仅常规项目）\n        if ((int) $itemType === 1) {\n            if ($allowComment !== null) {\n                $insertData['allow_comment'] = $allowComment ? 1 : 0;\n            }\n            if ($allowFeedback !== null) {\n                $insertData['allow_feedback'] = $allowFeedback ? 1 : 0;\n            }\n        }\n\n        $itemId = \\App\\Model\\Item::add($insertData);\n        if (!$itemId) {\n            return $this->error($response, 10101);\n        }\n\n        // 如果是单页应用，创建默认页\n        if ($itemType == 2) {\n            $pageData = [\n                'author_uid'      => $uid,\n                'author_username' => $username,\n                'page_title'      => $itemName,\n                'item_id'         => $itemId,\n                'cat_id'          => 0,\n                'page_content'    => '欢迎使用showdoc。点击右上方的编辑按钮进行编辑吧！',\n                'addtime'         => time(),\n            ];\n            \\App\\Model\\Page::addPage($itemId, $pageData);\n        }\n\n        // 如果是表格应用，创建默认页\n        if ($itemType == 4) {\n            $pageData = [\n                'author_uid'      => $uid,\n                'author_username' => $username,\n                'page_title'      => $itemName,\n                'item_id'         => $itemId,\n                'cat_id'          => 0,\n                'page_content'    => '',\n                'addtime'         => time(),\n            ];\n            \\App\\Model\\Page::addPage($itemId, $pageData);\n        }\n\n        // 如果是白板项目，创建默认页\n        if ($itemType == 5) {\n            $pageData = [\n                'author_uid'      => $uid,\n                'author_username' => $username,\n                'page_title'      => $itemName,\n                'item_id'         => $itemId,\n                'cat_id'          => 0,\n                'page_content'    => '',\n                'addtime'         => time(),\n            ];\n            \\App\\Model\\Page::addPage($itemId, $pageData);\n        }\n\n        // 处理项目分组（多分组支持）\n        $selectedGroupIds = [];\n        if (!empty($itemGroupIdsRaw)) {\n            if (is_array($itemGroupIdsRaw)) {\n                $selectedGroupIds = $itemGroupIdsRaw;\n            } else {\n                $tmp = json_decode(htmlspecialchars_decode($itemGroupIdsRaw), true);\n                if (is_array($tmp)) {\n                    $selectedGroupIds = $tmp;\n                } else {\n                    $selectedGroupIds = explode(',', strval($itemGroupIdsRaw));\n                }\n            }\n        } elseif ($itemGroupId > 0) {\n            $selectedGroupIds = [$itemGroupId];\n        }\n\n        $selectedGroupIds = array_values(array_unique(array_filter(array_map('intval', $selectedGroupIds))));\n\n        if (!empty($selectedGroupIds)) {\n            foreach ($selectedGroupIds as $gId) {\n                $group = DB::table('item_group')\n                    ->where('id', $gId)\n                    ->where('uid', $uid)\n                    ->first();\n\n                if ($group) {\n                    $itemIds = [];\n                    if (!empty($group->item_ids)) {\n                        $itemIds = array_values(array_unique(array_filter(array_map('intval', explode(',', $group->item_ids)))));\n                    }\n                    if (!in_array($itemId, $itemIds)) {\n                        $itemIds[] = $itemId;\n                    }\n                    DB::table('item_group')\n                        ->where('id', $gId)\n                        ->where('uid', $uid)\n                        ->update(['item_ids' => implode(',', $itemIds)]);\n                } else {\n                    // 分组不存在，创建新分组\n                    DB::table('item_group')\n                        ->where('id', $gId)\n                        ->where('uid', $uid)\n                        ->update(['item_ids' => (string) $itemId]);\n                }\n            }\n        }\n\n        return $this->success($response, ['item_id' => $itemId]);\n    }\n\n    /**\n     * 项目转让（兼容旧接口 Api/Item/attorn）。\n     */\n    public function attorn(Request $request, Response $response): Response\n    {\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $itemId   = $this->getParam($request, 'item_id', 0);\n        $username = $this->getParam($request, 'username', '');\n        $password = $this->getParam($request, 'password', '');\n\n        if ($itemId <= 0 || $username === '' || $password === '') {\n            return $this->error($response, 10101, '参数错误');\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        $item = \\App\\Model\\Item::findById($itemId);\n        if (!$item) {\n            return $this->error($response, 10101, '项目不存在');\n        }\n\n        // 权限：需要项目管理权限\n        if (!$this->checkItemManage($uid, $itemId)) {\n            return $this->error($response, 10303, '您没有管理权限');\n        }\n\n        // 使用项目当前拥有者账号校验密码\n        $ownerUsername = (string) ($item->username ?? '');\n        $owner         = \\App\\Model\\User::checkLogin($ownerUsername, $password);\n        if (!$owner) {\n            return $this->error($response, 10208, '密码不正确');\n        }\n\n        // 查找目标用户（支持用户名或邮箱）\n        $targetUserObj = \\App\\Model\\User::findByUsernameOrEmail($username);\n        if (!$targetUserObj) {\n            return $this->error($response, 10209, '用户不存在');\n        }\n\n        $targetUser = (array) $targetUserObj;\n\n        $affected = DB::table('item')\n            ->where('item_id', $itemId)\n            ->update([\n                'uid'      => (int) ($targetUser['uid'] ?? 0),\n                'username' => (string) ($targetUser['username'] ?? ''),\n            ]);\n\n        if ($affected <= 0) {\n            return $this->error($response, 10101, '转让失败');\n        }\n\n        $updatedItem = \\App\\Model\\Item::findById($itemId);\n\n        // 记录转让日志（兼容旧 itemAttornLog 表）\n        try {\n            DB::table('item_attorn_log')->insert([\n                'item_id'       => $itemId,\n                'from_uid'      => $uid,\n                'from_username' => (string) ($loginUser['username'] ?? ''),\n                'to_uid'        => (int) ($targetUser['uid'] ?? 0),\n                'to_username'   => (string) ($targetUser['username'] ?? ''),\n                'addtime'       => date('Y-m-d H:i:s'),\n            ]);\n        } catch (\\Throwable $e) {\n            // 日志失败不影响主流程\n        }\n\n        return $this->success($response, $updatedItem ? (array) $updatedItem : []);\n    }\n\n    /**\n     * 删除项目（软删）（兼容旧接口 Api/Item/delete）。\n     */\n    public function delete(Request $request, Response $response): Response\n    {\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $itemId   = $this->getParam($request, 'item_id', 0);\n        $password = $this->getParam($request, 'password', '');\n\n        if ($itemId <= 0 || $password === '') {\n            return $this->error($response, 10101, '参数错误');\n        }\n\n        $uid  = (int) ($loginUser['uid'] ?? 0);\n        $item = \\App\\Model\\Item::findById($itemId);\n        if (!$item) {\n            return $this->error($response, 10101, '项目不存在');\n        }\n\n        if (!$this->checkItemManage($uid, $itemId)) {\n            return $this->error($response, 10303, '您没有管理权限');\n        }\n\n        // 校验项目拥有者密码\n        $ownerUsername = (string) ($item->username ?? '');\n        $owner         = \\App\\Model\\User::checkLogin($ownerUsername, $password);\n        if (!$owner) {\n            return $this->error($response, 10208, '密码不正确');\n        }\n\n        // 软删除项目\n        $ret = \\App\\Model\\Item::softDeleteItem($itemId);\n\n        if ($ret) {\n            // 删除项目相关评论和反馈\n            DB::table('page_comment')->where('item_id', $itemId)->delete();\n            DB::table('page_feedback')->where('item_id', $itemId)->delete();\n        }\n\n        if (!$ret) {\n            return $this->error($response, 10101, '删除失败');\n        }\n\n        return $this->success($response, ['success' => true]);\n    }\n\n    /**\n     * 归档项目（兼容旧接口 Api/Item/archive）。\n     */\n    public function archive(Request $request, Response $response): Response\n    {\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $itemId   = $this->getParam($request, 'item_id', 0);\n        $password = $this->getParam($request, 'password', '');\n\n        if ($itemId <= 0 || $password === '') {\n            return $this->error($response, 10101, '参数错误');\n        }\n\n        $uid  = (int) ($loginUser['uid'] ?? 0);\n        $item = \\App\\Model\\Item::findById($itemId);\n        if (!$item) {\n            return $this->error($response, 10101, '项目不存在');\n        }\n\n        if (!$this->checkItemManage($uid, $itemId)) {\n            return $this->error($response, 10303, '您没有管理权限');\n        }\n\n        $ownerUsername = (string) ($item->username ?? '');\n        $owner         = \\App\\Model\\User::checkLogin($ownerUsername, $password);\n        if (!$owner) {\n            return $this->error($response, 10208, '密码不正确');\n        }\n\n        $affected = DB::table('item')\n            ->where('item_id', $itemId)\n            ->update(['is_archived' => 1]);\n\n        if ($affected <= 0) {\n            return $this->error($response, 10101, '归档失败');\n        }\n\n        return $this->success($response, ['success' => true]);\n    }\n\n    /**\n     * 获取项目访问密钥（兼容旧接口 Api/Item/getKey）。\n     */\n    public function getKey(Request $request, Response $response): Response\n    {\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $itemId = $this->getParam($request, 'item_id', 0);\n        if ($itemId <= 0) {\n            return $this->error($response, 10101, '项目不存在');\n        }\n\n        $uid  = (int) ($loginUser['uid'] ?? 0);\n        $item = \\App\\Model\\Item::findById($itemId);\n        if (!$item) {\n            return $this->error($response, 10101, '项目不存在');\n        }\n\n        if (!$this->checkItemManage($uid, $itemId)) {\n            return $this->error($response, 10303, '您没有管理权限');\n        }\n\n        $token = \\App\\Model\\ItemToken::getTokenByItemId($itemId);\n        if (!$token) {\n            return $this->error($response, 10101, '获取密钥失败');\n        }\n\n        return $this->success($response, $token);\n    }\n\n    /**\n     * 重置项目访问密钥（兼容旧接口 Api/Item/resetKey）。\n     */\n    public function resetKey(Request $request, Response $response): Response\n    {\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $itemId = $this->getParam($request, 'item_id', 0);\n        if ($itemId <= 0) {\n            return $this->error($response, 10101, '项目不存在');\n        }\n\n        $uid  = (int) ($loginUser['uid'] ?? 0);\n        $item = \\App\\Model\\Item::findById($itemId);\n        if (!$item) {\n            return $this->error($response, 10101, '项目不存在');\n        }\n\n        if (!$this->checkItemManage($uid, $itemId)) {\n            return $this->error($response, 10303, '您没有管理权限');\n        }\n\n        $token = \\App\\Model\\ItemToken::resetToken($itemId);\n        if (!$token) {\n            return $this->error($response, 10101, '重置失败');\n        }\n\n        return $this->success($response, $token);\n    }\n\n    /**\n     * 设置项目的 AI 知识库配置（兼容旧接口 Api/Item/setAiKnowledgeBaseConfig）。\n     */\n    public function setAiKnowledgeBaseConfig(Request $request, Response $response): Response\n    {\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $itemId = $this->getParam($request, 'item_id', 0);\n        if ($itemId <= 0) {\n            return $this->error($response, 10101, '项目ID不能为空');\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n        if (!$this->checkItemManage($uid, $itemId)) {\n            return $this->error($response, 10303, '您没有管理该项目的权限');\n        }\n\n        $data = [];\n\n        $enabled = $this->getParam($request, 'enabled', null);\n        if ($enabled !== null) {\n            $data['enabled'] = (int) $enabled;\n        }\n\n        $dialogCollapsed = $this->getParam($request, 'dialog_collapsed', null);\n        if ($dialogCollapsed !== null) {\n            $data['dialog_collapsed'] = (int) $dialogCollapsed;\n        }\n\n        $welcomeMessage = $this->getParam($request, 'welcome_message', null);\n        if ($welcomeMessage !== null && $welcomeMessage !== '') {\n            $data['welcome_message'] = (string) $welcomeMessage;\n        }\n\n        if (empty($data)) {\n            return $this->error($response, 10101, '没有需要更新的配置');\n        }\n\n        $ret = \\App\\Model\\ItemAiConfig::saveConfig($itemId, $data);\n        if (!$ret) {\n            return $this->error($response, 10101, '更新失败');\n        }\n\n        return $this->success($response, ['success' => true]);\n    }\n\n    /**\n     * 通过开放 API 更新项目信息（兼容旧接口 Api/Item/updateByApi）。\n     *\n     * 说明：旧实现内部转发到 OpenController::updateItem，这里保持行为一致。\n     */\n    public function updateByApi(Request $request, Response $response): Response\n    {\n        $open = new \\App\\Api\\Controller\\OpenController(\n            $this->container ?? null,\n            $this->logger ?? null\n        );\n\n        return $open->updateItem($request, $response);\n    }\n\n    /**\n     * 项目置顶 / 取消置顶（兼容旧接口 Api/Item/top）。\n     */\n    public function top(Request $request, Response $response): Response\n    {\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $itemId = $this->getParam($request, 'item_id', 0);\n        $action = $this->getParam($request, 'action', '');\n        if ($itemId <= 0 || !in_array($action, ['top', 'cancel'], true)) {\n            return $this->error($response, 10101, '参数错误');\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        try {\n            if ($action === 'top') {\n                // 先删除旧记录再添加，避免重复\n                DB::table('item_top')\n                    ->where('uid', $uid)\n                    ->where('item_id', $itemId)\n                    ->delete();\n\n                $ret = DB::table('item_top')->insert([\n                    'item_id' => $itemId,\n                    'uid'     => $uid,\n                    'addtime' => time(),\n                ]);\n            } else {\n                $ret = DB::table('item_top')\n                    ->where('uid', $uid)\n                    ->where('item_id', $itemId)\n                    ->delete() > 0;\n            }\n        } catch (\\Throwable $e) {\n            $ret = false;\n        }\n\n        if (!$ret) {\n            return $this->error($response, 10101, '操作失败');\n        }\n\n        return $this->success($response, []);\n    }\n\n    /**\n     * 校验项目访问密码 / 设置访问密码（兼容旧接口 Api/Item/pwd）。\n     *\n     * 说明：\n     * - 新实现仅负责校验密码是否正确并返回跳转地址；\n     * - 实际访问授权仍依赖后续对 checkItemVisit 的增强（当前不再基于 PHP session）。\n     */\n    public function pwd(Request $request, Response $response): Response\n    {\n        $itemId    = $this->getParam($request, 'item_id', '');\n        $pageId    = $this->getParam($request, 'page_id', 0);\n        $password  = $this->getParam($request, 'password', '');\n        $referUrl  = $this->getParam($request, 'refer_url', '');\n        $captchaId = $this->getParam($request, 'captcha_id', '');\n        $captcha   = $this->getParam($request, 'captcha', '');\n\n        // 验证图形验证码\n        if (!\\App\\Model\\Captcha::check($captchaId, $captcha)) {\n            return $this->error($response, 10206);\n        }\n\n        $itemDomain = '';\n        if (!is_numeric($itemId)) {\n            $itemDomain = (string) $itemId;\n        } else {\n            $itemId = (int) $itemId;\n        }\n\n        // 个性域名解析\n        if ($itemDomain !== '') {\n            $item = \\App\\Model\\Item::findByDomain($itemDomain);\n            if ($item && !empty($item->item_id)) {\n                $itemId = (int) $item->item_id;\n            }\n        }\n\n        // 如果传入 page_id，则通过页面反查 item_id\n        if ($pageId > 0) {\n            $page = \\App\\Model\\Page::findById($pageId);\n            if ($page && !empty($page['item_id'])) {\n                $itemId = (int) $page['item_id'];\n            }\n        }\n\n        if ($itemId <= 0) {\n            return $this->error($response, 10101, '项目不存在');\n        }\n\n        $item = \\App\\Model\\Item::findById($itemId);\n        if (!$item) {\n            return $this->error($response, 10101, '项目不存在');\n        }\n\n        if ($password !== '' && (string) ($item->password ?? '') === $password) {\n            // 旧版会在 session 中设置 visit_item_xx 标记；新版本交由前端自行持久化。\n            $decodedRefer = base64_decode((string) $referUrl, true) ?: '';\n            return $this->success($response, ['refer_url' => $decodedRefer]);\n        }\n\n        return $this->error($response, 10010);\n    }\n\n    /**\n     * 项目列表（兼容旧接口 Api/Item/itemList）。\n     */\n    public function itemList(Request $request, Response $response): Response\n    {\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n        if ($uid <= 0) {\n            return $this->error($response, 10102, '用户未登录');\n        }\n\n        $items = DB::table('item')\n            ->where('uid', $uid)\n            ->get()\n            ->all();\n\n        $result = [];\n        foreach ($items as $row) {\n            $result[] = (array) $row;\n        }\n\n        return $this->success($response, $result);\n    }\n\n    /**\n     * 保存项目排序（兼容旧接口 Api/Item/sort）。\n     */\n    public function sort(Request $request, Response $response): Response\n    {\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid         = (int) ($loginUser['uid'] ?? 0);\n        $data        = $this->getParam($request, 'data', '');\n        $itemGroupId = $this->getParam($request, 'item_group_id', 0);\n\n        if ($data === '') {\n            return $this->error($response, 10101, '排序数据不能为空');\n        }\n\n        try {\n            $existing = DB::table('item_sort')\n                ->where('uid', $uid)\n                ->where('item_group_id', $itemGroupId)\n                ->first();\n\n            $payload = [\n                'item_sort_data' => (string) $data,\n                'item_group_id'  => $itemGroupId,\n                'uid'            => $uid,\n                'addtime'        => time(),\n            ];\n\n            if ($existing) {\n                $ret = DB::table('item_sort')\n                    ->where('uid', $uid)\n                    ->where('item_group_id', $itemGroupId)\n                    ->update($payload);\n            } else {\n                $ret = DB::table('item_sort')->insert($payload);\n            }\n        } catch (\\Throwable $e) {\n            $ret = false;\n        }\n\n        if (!$ret) {\n            return $this->error($response, 10101, '保存失败');\n        }\n\n        return $this->success($response, []);\n    }\n\n    /**\n     * 退出项目（兼容旧接口 Api/Item/exitItem）。\n     */\n    public function exitItem(Request $request, Response $response): Response\n    {\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid    = (int) ($loginUser['uid'] ?? 0);\n        $itemId = $this->getParam($request, 'item_id', 0);\n        if ($itemId <= 0) {\n            return $this->error($response, 10101, '项目不存在');\n        }\n\n        // 删除项目成员关系\n        $ret = DB::table('item_member')\n            ->where('item_id', $itemId)\n            ->where('uid', $uid)\n            ->delete();\n\n        // 删除团队中的对应成员关系\n        $row = DB::table('team_item_member')\n            ->leftJoin('team', 'team.id', '=', 'team_item_member.team_id')\n            ->select(['team_item_member.team_id'])\n            ->where('team_item_member.item_id', $itemId)\n            ->where('team_item_member.member_uid', $uid)\n            ->first();\n\n        if ($row && !empty($row->team_id)) {\n            $teamId = (int) $row->team_id;\n            DB::table('team_item_member')\n                ->where('member_uid', $uid)\n                ->where('team_id', $teamId)\n                ->delete();\n            DB::table('team_member')\n                ->where('member_uid', $uid)\n                ->where('team_id', $teamId)\n                ->delete();\n        }\n\n        if ($ret <= 0 && !$row) {\n            return $this->error($response, 10101, '退出失败');\n        }\n\n        return $this->success($response, []);\n    }\n\n    /**\n     * 在某个项目中根据内容搜索（兼容旧接口 Api/Item/search）。\n     */\n    public function search(Request $request, Response $response): Response\n    {\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $keyword = $this->getParam($request, 'keyword', '');\n        $itemId  = $this->getParam($request, 'item_id', 0);\n\n        if ($itemId <= 0 || $keyword === '') {\n            return $this->error($response, 10101, '参数错误');\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        if (!$this->checkItemVisit($uid, $itemId)) {\n            return $this->error($response, 10303, '没有权限');\n        }\n\n        $item = \\App\\Model\\Item::findById($itemId);\n        if (!$item || (int) ($item->is_del ?? 0) === 1) {\n            return $this->error($response, 10101, '项目不存在');\n        }\n\n        // 获取目录权限\n        $catIds = \\App\\Model\\Member::getCatIds($itemId, $uid);\n        $pages  = \\App\\Model\\Page::search($itemId, $catIds, $keyword);\n\n        if ($pages) {\n            foreach ($pages as &$page) {\n                $content = (string) ($page['page_content'] ?? '');\n                $pos     = mb_stripos($content, $keyword);\n                $len     = mb_strlen($keyword);\n                $start   = $pos !== false && $pos > 100 ? $pos - 100 : 0;\n                $page['search_content'] = '...' . mb_substr($content, $start, $len + 200) . '...';\n                unset($page['page_content']);\n                $page['item_id']   = (int) ($item->item_id ?? $itemId);\n                $page['item_name'] = (string) ($item->item_name ?? '');\n            }\n            unset($page);\n        }\n\n        $result = [\n            'item_id'   => (int) ($item->item_id ?? $itemId),\n            'item_name' => (string) ($item->item_name ?? ''),\n            'pages'     => $pages ?: [],\n        ];\n\n        return $this->success($response, $result);\n    }\n\n    /**\n     * 获取项目变更日志（兼容旧接口 Api/Item/getChangeLog）。\n     */\n    public function getChangeLog(Request $request, Response $response): Response\n    {\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $page   = $this->getParam($request, 'page', 1);\n        $count  = $this->getParam($request, 'count', 15);\n        $itemId = $this->getParam($request, 'item_id', 0);\n\n        $page   = max(1, (int) $page);\n        $count  = max(1, min(100, (int) $count));\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        if ($itemId <= 0) {\n            return $this->error($response, 10101, '项目不存在');\n        }\n\n        if (!$this->checkItemEdit($uid, $itemId)) {\n            return $this->error($response, 10101, '没有编辑权限');\n        }\n\n        $ret = \\App\\Model\\ItemChangeLog::getLog($itemId, $page, $count);\n\n        return $this->success($response, $ret);\n    }\n\n    /**\n     * 标星项目（兼容旧接口 Api/Item/star）。\n     */\n    public function star(Request $request, Response $response): Response\n    {\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $itemId = $this->getParam($request, 'item_id', 0);\n        if ($itemId <= 0) {\n            return $this->error($response, 10101, '项目不存在');\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        if (!$this->checkItemVisit($uid, $itemId)) {\n            return $this->error($response, 1, '没有权限');\n        }\n\n        $now = date('Y-m-d H:i:s');\n\n        try {\n            // 避免重复标星\n            DB::table('item_star')\n                ->where('uid', $uid)\n                ->where('item_id', $itemId)\n                ->delete();\n\n            $id = DB::table('item_star')->insertGetId([\n                'uid'        => $uid,\n                'item_id'    => $itemId,\n                'created_at' => $now,\n                'updated_at' => $now,\n            ]);\n        } catch (\\Throwable $e) {\n            $id = 0;\n        }\n\n        if ($id <= 0) {\n            return $this->error($response, 10101, '标星失败');\n        }\n\n        return $this->success($response, ['id' => $id]);\n    }\n\n    /**\n     * 取消标星项目（兼容旧接口 Api/Item/unstar）。\n     */\n    public function unstar(Request $request, Response $response): Response\n    {\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $itemId = $this->getParam($request, 'item_id', 0);\n        if ($itemId <= 0) {\n            return $this->error($response, 10101, '项目不存在');\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        DB::table('item_star')\n            ->where('uid', $uid)\n            ->where('item_id', $itemId)\n            ->delete();\n\n        return $this->success($response, []);\n    }\n}\n"
  },
  {
    "path": "server/app/Api/Controller/ItemGroupController.php",
    "content": "<?php\n\nnamespace App\\Api\\Controller;\n\nuse App\\Common\\BaseController;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\nuse App\\Model\\ItemGroup;\nuse App\\Model\\ItemSort;\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\n/**\n * 项目分组相关 Api（新架构）。\n */\nclass ItemGroupController extends BaseController\n{\n    /**\n     * 添加和编辑项目组（兼容旧接口 Api/ItemGroup/save）。\n     */\n    public function save(Request $request, Response $response): Response\n    {\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $groupName = $this->getParam($request, 'group_name', '');\n        $itemIds = $this->getParam($request, 'item_ids', '');\n        $id = $this->getParam($request, 'id', 0);\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        if (empty($groupName)) {\n            return $this->error($response, 10101, '分组名称不能为空');\n        }\n\n        if ($id > 0) {\n            // 更新现有分组（仅允许当前用户自己的分组）\n            $group = ItemGroup::findById($id);\n            if (!$group || (int) ($group->uid ?? 0) !== $uid) {\n                return $this->error($response, 10103, '没有权限');\n            }\n\n            $affected = DB::table('item_group')\n                ->where('id', $id)\n                ->where('uid', $uid)\n                ->update([\n                    'group_name' => $groupName,\n                    'item_ids'   => $itemIds,\n                ]);\n\n            if ($affected <= 0) {\n                return $this->error($response, 10103, '更新失败');\n            }\n\n            $finalId = $id;\n        } else {\n            // 创建新分组（内部会自动写入 uid/时间字段，行为与旧版保持一致）\n            $finalId = ItemGroup::add($uid, $groupName, $itemIds);\n            if (!$finalId) {\n                return $this->error($response, 10103, '创建失败');\n            }\n        }\n\n        // 延迟 200ms（兼容旧代码）\n        usleep(200000);\n\n        $return = ItemGroup::findById($finalId);\n        if (!$return) {\n            return $this->error($response, 10103, '获取分组信息失败');\n        }\n\n        $data = (array) $return;\n        unset($data['uid']);\n\n        return $this->success($response, $data);\n    }\n\n    /**\n     * 获取项目组列表（兼容旧接口 Api/ItemGroup/getList）。\n     */\n    public function getList(Request $request, Response $response): Response\n    {\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n        if ($uid <= 0) {\n            return $this->success($response, []);\n        }\n\n        $ret = ItemGroup::getList($uid);\n        if (!empty($ret)) {\n            return $this->success($response, $ret);\n        }\n\n        return $this->success($response, []);\n    }\n\n    /**\n     * 删除项目组（兼容旧接口 Api/ItemGroup/delete）。\n     */\n    public function delete(Request $request, Response $response): Response\n    {\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $id = $this->getParam($request, 'id', 0);\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        if ($id <= 0 || $uid <= 0) {\n            return $this->error($response, 10101, '参数错误');\n        }\n\n        // 验证分组是否属于当前用户\n        $group = ItemGroup::findById($id);\n        if (!$group || (int) ($group->uid ?? 0) !== $uid) {\n            return $this->error($response, 10101, '没有权限');\n        }\n\n        // 删除分组及其关联的排序记录\n        ItemGroup::delete($id, $uid);\n\n        return $this->success($response, ['success' => true]);\n    }\n\n    /**\n     * 保存项目组顺序（兼容旧接口 Api/ItemGroup/saveSort）。\n     */\n    public function saveSort(Request $request, Response $response): Response\n    {\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $groups = $this->getParam($request, 'groups', '');\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        if (empty($groups)) {\n            return $this->error($response, 10101, '参数错误');\n        }\n\n        $dataArray = json_decode(htmlspecialchars_decode($groups), true);\n        if ($dataArray) {\n            foreach ($dataArray as $value) {\n                $id = (int) ($value['id'] ?? 0);\n                $sNumber = (int) ($value['s_number'] ?? 0);\n\n                if ($id > 0) {\n                    // 验证分组是否属于当前用户\n                    $group = ItemGroup::findById($id);\n                    if ($group && (int) ($group->uid ?? 0) === $uid) {\n                        DB::table('item_group')\n                            ->where('id', $id)\n                            ->where('uid', $uid)\n                            ->update(['s_number' => $sNumber]);\n                    }\n                }\n            }\n        }\n\n        return $this->success($response, []);\n    }\n}\n"
  },
  {
    "path": "server/app/Api/Controller/ItemVariableController.php",
    "content": "<?php\n\nnamespace App\\Api\\Controller;\n\nuse App\\Common\\BaseController;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\n\n/**\n * 项目环境变量相关 Api（新架构）。\n */\nclass ItemVariableController extends BaseController\n{\n    /**\n     * 保存环境变量（兼容旧接口 Api/ItemVariable/save）。\n     *\n     * 功能：\n     * - 新增或更新项目的环境变量\n     * - 权限检查（checkItemEdit）\n     */\n    public function save(Request $request, Response $response): Response\n    {\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n        $itemId = $this->getParam($request, 'item_id', 0);\n        $envId = $this->getParam($request, 'env_id', 0);\n        $varName = trim($this->getParam($request, 'var_name', ''));\n        $varValue = trim($this->getParam($request, 'var_value', ''));\n\n        // 检查编辑权限\n        if (!$this->checkItemEdit($uid, $itemId)) {\n            return $this->error($response, 10303, '您没有编辑权限');\n        }\n\n        // 保存环境变量\n        $id = \\App\\Model\\ItemVariable::save($itemId, $envId, $varName, $varValue, $uid);\n\n        if ($id > 0) {\n            // 兼容旧接口：返回 id 值（不是数组）\n            return $this->json($response, [\n                'error_code' => 0,\n                'data' => $id,\n            ]);\n        } else {\n            return $this->error($response, 10101, '保存失败');\n        }\n    }\n\n    /**\n     * 获取环境变量列表（兼容旧接口 Api/ItemVariable/getList）。\n     *\n     * 功能：\n     * - 获取项目的环境变量列表\n     * - 权限检查（checkItemEdit）\n     * - 支持按环境 ID 筛选\n     */\n    public function getList(Request $request, Response $response): Response\n    {\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n        $itemId = $this->getParam($request, 'item_id', 0);\n        $envId = $this->getParam($request, 'env_id', 0);\n\n        // 检查编辑权限\n        if (!$this->checkItemEdit($uid, $itemId)) {\n            return $this->error($response, 10303, '您没有编辑权限');\n        }\n\n        // 获取环境变量列表\n        $ret = \\App\\Model\\ItemVariable::getList($itemId, $envId);\n\n        // 按旧版行为，对 addtime 做格式化，避免前端直接展示时间戳\n        if (!empty($ret) && is_array($ret)) {\n            foreach ($ret as &$row) {\n                if (isset($row['addtime']) && is_numeric($row['addtime'])) {\n                    $row['addtime'] = date('Y-m-d H:i:s', (int) $row['addtime']);\n                }\n            }\n            unset($row);\n        }\n\n        return $this->success($response, $ret ?: []);\n    }\n\n    /**\n     * 删除环境变量（兼容旧接口 Api/ItemVariable/delete）。\n     *\n     * 功能：\n     * - 删除指定的环境变量\n     * - 权限检查（checkItemEdit）\n     */\n    public function delete(Request $request, Response $response): Response\n    {\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n        $itemId = $this->getParam($request, 'item_id', 0);\n        $id = $this->getParam($request, 'id', 0);\n\n        // 检查编辑权限\n        if (!$this->checkItemEdit($uid, $itemId)) {\n            return $this->error($response, 10303, '您没有编辑权限');\n        }\n\n        // 删除环境变量\n        $ret = \\App\\Model\\ItemVariable::delete($itemId, $id);\n\n        if ($ret) {\n            // 兼容旧接口：返回删除结果（true 或删除的行数）\n            return $this->json($response, [\n                'error_code' => 0,\n                'data' => $ret,\n            ]);\n        } else {\n            return $this->error($response, 10101, '删除失败');\n        }\n    }\n\n    /**\n     * 根据变量名删除环境变量（兼容旧接口 Api/ItemVariable/deleteByName）。\n     *\n     * 功能：\n     * - 根据变量名删除环境变量\n     * - 权限检查（checkItemEdit）\n     */\n    public function deleteByName(Request $request, Response $response): Response\n    {\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n        $itemId = $this->getParam($request, 'item_id', 0);\n        $envId = $this->getParam($request, 'env_id', 0);\n        $varName = $this->getParam($request, 'var_name', '');\n\n        // 检查编辑权限\n        if (!$this->checkItemEdit($uid, $itemId)) {\n            return $this->error($response, 10303, '您没有编辑权限');\n        }\n\n        // 删除环境变量\n        $ret = \\App\\Model\\ItemVariable::deleteByName($itemId, $envId, $varName);\n\n        if ($ret) {\n            // 兼容旧接口：返回删除结果（true 或删除的行数）\n            return $this->json($response, [\n                'error_code' => 0,\n                'data' => $ret,\n            ]);\n        } else {\n            return $this->error($response, 10101, '删除失败');\n        }\n    }\n}\n"
  },
  {
    "path": "server/app/Api/Controller/McpController.php",
    "content": "<?php\n\nnamespace App\\Api\\Controller;\n\nuse App\\Common\\BaseController;\nuse App\\Mcp\\McpServer;\nuse App\\Mcp\\McpError;\nuse App\\Model\\UserAiToken;\nuse App\\Common\\Helper\\IpHelper;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\n\n/**\n * MCP 控制器\n * \n * 处理 MCP 协议的 HTTP 请求入口\n */\nclass McpController extends BaseController\n{\n  /**\n   * MCP 入口\n   *\n   * @param Request $request 请求对象\n   * @param Response $response 响应对象\n   * @return Response\n   */\n  public function index(Request $request, Response $response): Response\n  {\n    // 获取请求体\n    $body = (string) $request->getBody();\n\n    // 解析 JSON\n    $jsonRequest = json_decode($body, true);\n\n    if (json_last_error() !== JSON_ERROR_NONE) {\n      return $this->jsonResponse($response, McpError::createResponse(\n        McpError::PARSE_ERROR,\n        'JSON 解析失败: ' . json_last_error_msg()\n      ));\n    }\n\n    // 验证是否是数组\n    if (!is_array($jsonRequest)) {\n      return $this->jsonResponse($response, McpError::createResponse(\n        McpError::INVALID_REQUEST,\n        '请求必须是 JSON 对象'\n      ));\n    }\n\n    // 处理批量请求\n    if (isset($jsonRequest[0])) {\n      return $this->handleBatchRequest($response, $jsonRequest);\n    }\n\n    // 处理单个请求\n    return $this->handleSingleRequest($request, $response, $jsonRequest);\n  }\n\n  /**\n   * 处理单个请求\n   *\n   * @param Request $request 请求对象\n   * @param Response $response 响应对象\n   * @param array $jsonRequest JSON 请求数据\n   * @return Response\n   */\n  private function handleSingleRequest(Request $request, Response $response, array $jsonRequest): Response\n  {\n    // 验证 Token（除了 initialize 和 ping）\n    $method = $jsonRequest['method'] ?? '';\n    $tokenInfo = null;\n\n    if (!in_array($method, ['initialize', 'ping'])) {\n      $tokenInfo = $this->validateToken($request);\n      if ($tokenInfo === null) {\n        return $this->jsonResponse($response, McpError::createResponse(\n          McpError::TOKEN_INVALID,\n          'Token 无效或已过期',\n          null,\n          $jsonRequest['id'] ?? null\n        ));\n      }\n\n      // 频率限制检查\n      $token = $this->extractToken($request);\n      if ($token) {\n        $rateLimit = UserAiToken::checkRateLimit($token);\n        if (!$rateLimit['allowed']) {\n          return $this->jsonResponse($response, McpError::createResponse(\n            McpError::RATE_LIMITED,\n            '请求频率超限，请稍后重试',\n            [\n              'reset_at' => $rateLimit['reset_at'],\n              'retry_after' => $rateLimit['reset_at'] - time(),\n            ],\n            $jsonRequest['id'] ?? null\n          ));\n        }\n      }\n\n      // 更新最后使用时间\n      if ($token) {\n        UserAiToken::touchLastUsed($token);\n      }\n    }\n\n    // 创建 MCP Server 实例\n    $mcpServer = new McpServer();\n\n    if ($tokenInfo !== null) {\n      $mcpServer->setTokenInfo($tokenInfo);\n    }\n\n    // 处理请求\n    $result = $mcpServer->handleRequest($jsonRequest);\n\n    return $this->jsonResponse($response, $result);\n  }\n\n  /**\n   * 处理批量请求\n   *\n   * @param Response $response 响应对象\n   * @param array $requests 请求数组\n   * @return Response\n   */\n  private function handleBatchRequest(Response $response, array $requests): Response\n  {\n    $results = [];\n\n    foreach ($requests as $jsonRequest) {\n      // 批量请求也需要验证 Token\n      $method = $jsonRequest['method'] ?? '';\n\n      if (!in_array($method, ['initialize', 'ping'])) {\n        $tokenInfo = $this->validateTokenFromGlobals();\n        if ($tokenInfo === null) {\n          $results[] = McpError::createResponse(\n            McpError::TOKEN_INVALID,\n            'Token 无效或已过期',\n            null,\n            $jsonRequest['id'] ?? null\n          );\n          continue;\n        }\n      }\n\n      $mcpServer = new McpServer();\n      if (isset($tokenInfo)) {\n        $mcpServer->setTokenInfo($tokenInfo);\n      }\n\n      $results[] = $mcpServer->handleRequest($jsonRequest);\n    }\n\n    return $this->jsonResponse($response, $results);\n  }\n\n  /**\n   * 验证 Token\n   *\n   * @param Request $request 请求对象\n   * @return array|null Token 信息，无效返回 null\n   */\n  private function validateToken(Request $request): ?array\n  {\n    $token = $this->extractToken($request);\n\n    if ($token === null) {\n      return null;\n    }\n\n    // 验证 Token 格式\n    if (!UserAiToken::isValidTokenFormat($token)) {\n      return null;\n    }\n\n    // 获取 Token 信息\n    $tokenInfo = UserAiToken::getToken($token);\n\n    return $tokenInfo;\n  }\n\n  /**\n   * 从全局变量验证 Token（用于批量请求）\n   *\n   * @return array|null\n   */\n  private function validateTokenFromGlobals(): ?array\n  {\n    $token = null;\n\n    // 1. 从 Authorization Header 获取\n    $auth = $_SERVER['HTTP_AUTHORIZATION'] ?? '';\n    if ($auth !== '' && preg_match('/Bearer\\s+(.+)/i', $auth, $m)) {\n      $token = trim($m[1]);\n    }\n\n    // 2. 从 X-API-Token Header 获取\n    if ($token === null) {\n      $token = trim($_SERVER['HTTP_X_API_TOKEN'] ?? '');\n    }\n\n    // 3. 从查询参数获取\n    if ($token === null) {\n      $token = trim($_GET['user_token'] ?? '');\n    }\n\n    if ($token === '' || $token === null) {\n      return null;\n    }\n\n    // 验证 Token 格式\n    if (!UserAiToken::isValidTokenFormat($token)) {\n      return null;\n    }\n\n    // 获取 Token 信息\n    return UserAiToken::getToken($token);\n  }\n\n  /**\n   * 从请求中提取 Token\n   *\n   * @param Request $request 请求对象\n   * @return string|null\n   */\n  private function extractToken(Request $request): ?string\n  {\n    // 1. 从 Authorization Header 获取\n    $auth = $request->getHeaderLine('Authorization');\n    if ($auth !== '' && preg_match('/Bearer\\s+(.+)/i', $auth, $m)) {\n      return trim($m[1]);\n    }\n\n    // 2. 从 X-API-Token Header 获取\n    $token = trim($request->getHeaderLine('X-API-Token'));\n    if ($token !== '') {\n      return $token;\n    }\n\n    // 3. 从查询参数获取\n    $token = trim($this->getParam($request, 'user_token', ''));\n    if ($token !== '') {\n      return $token;\n    }\n\n    return null;\n  }\n\n  /**\n   * 返回 JSON 响应\n   *\n   * @param Response $response 响应对象\n   * @param array $data 响应数据\n   * @return Response\n   */\n  private function jsonResponse(Response $response, array $data): Response\n  {\n    $payload = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);\n\n    $response->getBody()->write($payload);\n\n    return $response\n      ->withHeader('Content-Type', 'application/json')\n      ->withHeader('Access-Control-Allow-Origin', '*')\n      ->withHeader('Access-Control-Allow-Methods', 'POST, OPTIONS')\n      ->withHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-API-Token');\n  }\n\n  /**\n   * 处理 OPTIONS 预检请求\n   *\n   * @param Request $request 请求对象\n   * @param Response $response 响应对象\n   * @return Response\n   */\n  public function options(Request $request, Response $response): Response\n  {\n    return $response\n      ->withHeader('Access-Control-Allow-Origin', '*')\n      ->withHeader('Access-Control-Allow-Methods', 'POST, OPTIONS')\n      ->withHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-API-Token')\n      ->withStatus(204);\n  }\n}\n"
  },
  {
    "path": "server/app/Api/Controller/MemberController.php",
    "content": "<?php\n\nnamespace App\\Api\\Controller;\n\nuse App\\Common\\BaseController;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\n/**\n * 成员管理相关 Api（新架构）。\n */\nclass MemberController extends BaseController\n{\n    /**\n     * 保存成员（添加项目成员）（兼容旧接口 Api/Member/save）。\n     *\n     * 功能：\n     * - 添加项目成员\n     * - 权限检查（checkItemManage）\n     * - 支持单目录和多目录权限\n     */\n    public function save(Request $request, Response $response): Response\n    {\n        $memberGroupId = $this->getParam($request, 'member_group_id', 0);\n        $itemId        = $this->getParam($request, 'item_id', 0);\n        $catId         = $this->getParam($request, 'cat_id', 0);\n        $catIds        = $this->getParam($request, 'cat_ids', '');\n        $username      = trim($this->getParam($request, 'username', ''));\n\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        // 检查管理权限（项目管理权限或系统管理员权限）\n        if (!$this->checkItemManage($uid, $itemId) && !$this->checkAdmin($request, $response, false)) {\n            return $this->error($response, 10303, '您没有管理权限');\n        }\n\n        // 开源版无成员数量限制\n\n        if ($username === '') {\n            return $this->error($response, 10209, '用户不存在');\n        }\n\n        // 兼容旧版：支持逗号分隔的一批用户名\n        $usernameArray = array_filter(array_map('trim', explode(',', $username)));\n        $lastId        = 0;\n\n        // 预先解析多目录权限（cat_ids），以便重复使用\n        $catIdsField = '';\n        if (!empty($catIds)) {\n            $ids = [];\n            if (is_array($catIds)) {\n                $ids = $catIds;\n            } else {\n                // 优先尝试 JSON\n                $tmp = json_decode($catIds, true);\n                if (is_array($tmp)) {\n                    $ids = $tmp;\n                } elseif (is_string($catIds)) {\n                    // 兼容 form 提交的逗号分隔字符串\n                    if (strpos($catIds, ',') !== false) {\n                        $ids = preg_split('/\\s*,\\s*/', trim($catIds));\n                    } elseif (ctype_digit($catIds)) {\n                        // 单个数字字符串\n                        $ids = [(int) $catIds];\n                    }\n                }\n            }\n\n            // 过滤非法并校验每个目录必须为该项目的 level=2\n            $ids2 = [];\n            if (!empty($ids)) {\n                foreach ($ids as $v) {\n                    $v = (int) $v;\n                    if ($v <= 0) {\n                        continue;\n                    }\n                    $cat = \\App\\Model\\Catalog::findByIdAndItemId($v, $itemId);\n                    if ($cat && (int) ($cat->level ?? 0) === 2) {\n                        $ids2[] = $v;\n                    }\n                }\n                $ids2 = array_values(array_unique($ids2));\n            }\n\n            if (!empty($ids2)) {\n                // 统一以逗号分隔字符串存储\n                $catIdsField = implode(',', $ids2);\n            }\n        }\n\n        foreach ($usernameArray as $name) {\n            // 查找用户（支持用户名或邮箱）\n            $member = \\App\\Model\\User::findByUsernameOrEmail($name);\n            if (!$member) {\n                // 与旧版一致：找不到用户则跳过\n                continue;\n            }\n\n            // 检查是否已经是成员\n            $existing = \\App\\Model\\ItemMember::findByUidAndItemId((int) $member->uid, $itemId);\n            if ($existing) {\n                // 与旧版一致：已是成员则跳过\n                continue;\n            }\n\n            // 准备数据\n            $data = [\n                'username'        => $member->username ?? '',\n                'uid'             => (int) $member->uid,\n                'item_id'         => $itemId,\n                'member_group_id' => $memberGroupId,\n                'cat_id'          => $catId,\n                'addtime'         => time(),\n            ];\n\n            if ($catIdsField !== '') {\n                $data['cat_ids'] = $catIdsField;\n            }\n\n            // 添加成员\n            $id = \\App\\Model\\ItemMember::add($data);\n            if ($id <= 0) {\n                // 某个成员失败时，继续处理其他成员\n                continue;\n            }\n\n            $lastId = $id;\n\n            // 记录变更日志\n            \\App\\Model\\ItemChangeLog::addLog($uid, $itemId, 'binding', 'member', (int) $member->uid, $member->username ?? '');\n        }\n\n        if ($lastId <= 0) {\n            return $this->error($response, 10101, '添加成员失败');\n        }\n\n        // 为兼容新前端，继续只返回最后一个成功的 id\n        return $this->success($response, ['id' => $lastId]);\n    }\n\n    /**\n     * 获取成员列表（兼容旧接口 Api/Member/getList）。\n     *\n     * 功能：\n     * - 获取项目的成员列表\n     * - 权限检查（checkItemManage）\n     */\n    public function getList(Request $request, Response $response): Response\n    {\n        $itemId = $this->getParam($request, 'item_id', 0);\n\n        if ($itemId <= 0) {\n            return $this->success($response, []);\n        }\n\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        // 检查管理权限（项目管理权限或系统管理员权限）\n        if (!$this->checkItemManage($uid, $itemId) && !$this->checkAdmin($request, $response, false)) {\n            return $this->error($response, 10303, '您没有管理权限');\n        }\n\n        // 获取成员列表\n        $ret = \\App\\Model\\ItemMember::getList($itemId);\n\n        return $this->success($response, $ret ?: []);\n    }\n\n    /**\n     * 删除成员（兼容旧接口 Api/Member/delete）。\n     *\n     * 功能：\n     * - 删除项目成员\n     * - 权限检查（checkItemManage）\n     */\n    public function delete(Request $request, Response $response): Response\n    {\n        $itemId       = $this->getParam($request, 'item_id', 0);\n        $itemMemberId = $this->getParam($request, 'item_member_id', 0);\n\n        if ($itemId <= 0 || $itemMemberId <= 0) {\n            return $this->error($response, 10101, '参数错误');\n        }\n\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        // 检查管理权限（项目管理权限或系统管理员权限）\n        if (!$this->checkItemManage($uid, $itemId) && !$this->checkAdmin($request, $response, false)) {\n            return $this->error($response, 10303, '您没有管理权限');\n        }\n\n        // 删除成员\n        $member = \\App\\Model\\ItemMember::delete($itemId, $itemMemberId);\n        if (!$member) {\n            return $this->error($response, 10101, '删除失败');\n        }\n\n        // 记录变更日志\n        \\App\\Model\\ItemChangeLog::addLog($uid, $itemId, 'unbound', 'member', (int) ($member['uid'] ?? 0), $member['username'] ?? '');\n\n        return $this->success($response, ['success' => true]);\n    }\n\n    /**\n     * 获取项目的所有成员列表（包括单独成员和绑定的团队成员）（兼容旧接口 Api/Member/getAllList）。\n     *\n     * 功能：\n     * - 获取项目的所有成员（包括项目创建者、单独成员、团队成员）\n     * - 权限检查（checkItemEdit）\n     */\n    public function getAllList(Request $request, Response $response): Response\n    {\n        $itemId = $this->getParam($request, 'item_id', 0);\n\n        if ($itemId <= 0) {\n            return $this->success($response, []);\n        }\n\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        // 检查编辑权限（项目编辑权限或系统管理员权限）\n        if (!$this->checkItemEdit($uid, $itemId) && !$this->checkAdmin($request, $response, false)) {\n            return $this->error($response, 10301, '您没有编辑权限');\n        }\n\n        // 获取所有成员列表\n        $ret = \\App\\Model\\ItemMember::getAllList($itemId);\n\n        return $this->success($response, $ret ?: []);\n    }\n\n    /**\n     * 获取当前登录用户参与的所有项目成员信息（兼容旧接口 Api/Member/getMyAllList）。\n     *\n     * 功能：\n     * - 聚合当前用户创建的所有项目成员（item_member）\n     * - 聚合当前用户创建的所有团队成员（team_member）\n     * - 对 username 进行去重，并按 addtime 倒序排序\n     *\n     * 说明：\n     * - 仅依赖 Illuminate 查询构造器，不再执行原始 SQL 字符串拼接。\n     */\n    public function getMyAllList(Request $request, Response $response): Response\n    {\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n        if ($uid <= 0) {\n            return $this->error($response, 10101, '用户未登录');\n        }\n\n        // 当前用户创建的项目的单独成员\n        $itemMembers = DB::table('item_member')\n            ->leftJoin('item', 'item_member.item_id', '=', 'item.item_id')\n            ->where('item.uid', $uid)\n            ->select([\n                'item_member.uid',\n                'item_member.username',\n                'item_member.addtime',\n            ])\n            ->get()\n            ->all();\n\n        // 当前用户创建的团队的成员\n        $teamMembers = DB::table('team_member')\n            ->leftJoin('team', 'team_member.team_id', '=', 'team.id')\n            ->where('team.uid', $uid)\n            ->select([\n                'team_member.member_uid as uid',\n                'team_member.member_username as username',\n                'team_member.addtime',\n            ])\n            ->get()\n            ->all();\n\n        $rows = [];\n        foreach ($itemMembers as $row) {\n            $rows[] = [\n                'uid'      => (int) ($row->uid ?? 0),\n                'username' => (string) ($row->username ?? ''),\n                'addtime'  => (int) ($row->addtime ?? 0),\n            ];\n        }\n        foreach ($teamMembers as $row) {\n            $rows[] = [\n                'uid'      => (int) ($row->uid ?? 0),\n                'username' => (string) ($row->username ?? ''),\n                'addtime'  => (int) ($row->addtime ?? 0),\n            ];\n        }\n\n        if (empty($rows)) {\n            return $this->success($response, []);\n        }\n\n        // 先按 addtime 倒序排序\n        usort($rows, function (array $a, array $b): int {\n            return ($b['addtime'] ?? 0) <=> ($a['addtime'] ?? 0);\n        });\n\n        // 按 uid + username 去重，保留最近的记录\n        $seen = [];\n        $result = [];\n        foreach ($rows as $row) {\n            $key = $row['uid'] . '|' . $row['username'];\n            if (isset($seen[$key])) {\n                continue;\n            }\n            $seen[$key] = true;\n            // 返回结构与旧接口一致：uid, username, addtime（时间戳）\n            $result[] = [\n                'uid'      => $row['uid'],\n                'username' => $row['username'],\n                'addtime'  => $row['addtime'],\n            ];\n        }\n\n        return $this->success($response, $result);\n    }\n}\n"
  },
  {
    "path": "server/app/Api/Controller/MessageController.php",
    "content": "<?php\n\nnamespace App\\Api\\Controller;\n\nuse App\\Common\\BaseController;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\n/**\n * 消息相关 Api（新架构）。\n */\nclass MessageController extends BaseController\n{\n    /**\n     * 快速获取未读的消息（兼容旧接口 Api/Message/getUnread）。\n     *\n     * 功能：\n     * - 获取未读的提醒类消息\n     * - 获取未读的公告类消息\n     */\n    public function getUnread(Request $request, Response $response): Response\n    {\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n        $regTime = date('Y-m-d H:i:s', (int) ($loginUser['reg_time'] ?? time()));\n\n        $return = [\n            'remind'   => [], // 提醒类的消息\n            'announce' => [], // 公告类的消息\n        ];\n\n        // 先尝试获取提醒类消息（开源版使用单表 message）\n        $array = DB::table('message')\n            ->where('to_uid', $uid)\n            ->where('message_type', 'remind')\n            ->where('status', 0)\n            ->first();\n\n        if ($array) {\n            // 如果有未读的，再组装更多信息\n            $list = \\App\\Model\\Message::getRemindList($uid, 1, 1, 0);\n            if ($list && !empty($list['list'])) {\n                $return['remind'] = $list['list'][0];\n            }\n        }\n\n        // 尝试获取公告类的未读消息\n        // 先把用户已读了的公告id读取出来（开源版使用单表 message）\n        $readAnnounces = DB::table('message')\n            ->where('to_uid', $uid)\n            ->where('message_type', 'announce')\n            ->get()\n            ->all();\n\n        $messageContentIdArray = [0]; // 初始化\n        foreach ($readAnnounces as $value) {\n            $messageContentIdArray[] = (int) ($value->message_content_id ?? 0);\n        }\n\n        // 检查是否是管理员\n        $isAdmin = false;\n        $user = \\App\\Model\\User::findById($uid);\n        if ($user && (int) ($user->groupid ?? 0) === 1) {\n            $isAdmin = true;\n        }\n\n        // 构建查询条件（开源版使用单表 message_content）\n        $query = DB::table('message_content')\n            ->whereIn('message_type', ['announce', 'announce_web', 'announce_runapi', 'announce_all']);\n\n        if (!$isAdmin) {\n            $query->where('addtime', '>', $regTime);\n        }\n\n        if (!empty($messageContentIdArray)) {\n            $query->whereNotIn('id', $messageContentIdArray);\n        }\n\n        $announceArray = $query->first();\n\n        if ($announceArray) {\n            $data = (array) $announceArray;\n            $data['message_content_id'] = $data['id'];\n            $return['announce'] = $data;\n        }\n\n        return $this->success($response, $return);\n    }\n\n    /**\n     * 获取公告类型消息列表（兼容旧接口 Api/Message/getAnnouncementList）。\n     */\n    public function getAnnouncementList(Request $request, Response $response): Response\n    {\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n        $regTime = date('Y-m-d H:i:s', (int) ($loginUser['reg_time'] ?? time()));\n\n        // 检查是否是管理员\n        $isAdmin = false;\n        $user = \\App\\Model\\User::findById($uid);\n        if ($user && (int) ($user->groupid ?? 0) === 1) {\n            $isAdmin = true;\n        }\n\n        // 构建查询条件（开源版使用单表 message_content）\n        $query = DB::table('message_content')\n            ->whereIn('message_type', ['announce', 'announce_web', 'announce_runapi', 'announce_all']);\n\n        if (!$isAdmin) {\n            $query->where('addtime', '>', $regTime);\n        }\n\n        $messageAnnounce = $query\n            ->orderBy('id', 'desc')\n            ->get()\n            ->all();\n\n        $result = [];\n        foreach ($messageAnnounce as $value) {\n            $data = (array) $value;\n\n            // 获取已读未读状态（开源版使用单表 message）\n            $readRecord = DB::table('message')\n                ->where('to_uid', $uid)\n                ->where('message_type', 'announce')\n                ->where('message_content_id', $data['id'])\n                ->first();\n\n            // 存在记录就是已读。不存在就是未读\n            $data['status'] = $readRecord ? 1 : 0;\n            $data['message_content_id'] = $data['id'];\n\n            $result[] = $data;\n        }\n\n        return $this->success($response, $result);\n    }\n\n    /**\n     * 设置消息已读（兼容旧接口 Api/Message/setRead）。\n     */\n    public function setRead(Request $request, Response $response): Response\n    {\n        $messageContentId = $this->getParam($request, 'message_content_id', 0);\n        $fromUid = $this->getParam($request, 'from_uid', 0);\n\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        // message_content_id + from_uid 才是联合唯一（开源版使用单表 message）\n        $array = DB::table('message')\n            ->where('to_uid', $uid)\n            ->where('from_uid', $fromUid)\n            ->where('message_content_id', $messageContentId)\n            ->first();\n\n        if ($array) {\n            // 更新为已读\n            DB::table('message')\n                ->where('to_uid', $uid)\n                ->where('message_content_id', $messageContentId)\n                ->update(['status' => 1]);\n        } else {\n            if ($messageContentId > 0) {\n                // 如果不存在，则可能是公告类型，创建已读记录\n                DB::table('message')->insert([\n                    'from_uid'            => 0,\n                    'to_uid'              => $uid,\n                    'message_type'        => 'announce',\n                    'message_content_id'  => $messageContentId,\n                    'status'              => 1,\n                    'addtime'             => date('Y-m-d H:i:s'),\n                    'readtime'            => date('Y-m-d H:i:s'),\n                ]);\n            }\n        }\n\n        return $this->success($response, []);\n    }\n\n    /**\n     * 删除消息（兼容旧接口 Api/Message/delete）。\n     */\n    public function delete(Request $request, Response $response): Response\n    {\n        $messageContentId = $this->getParam($request, 'message_content_id', 0);\n        $fromUid = $this->getParam($request, 'from_uid', 0);\n\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        // 软删除（标记 status = -1，开源版使用单表 message）\n        DB::table('message')\n            ->where('to_uid', $uid)\n            ->where('from_uid', $fromUid)\n            ->where('message_content_id', $messageContentId)\n            ->update(['status' => -1]);\n\n        return $this->success($response, []);\n    }\n\n    /**\n     * 获取提醒型消息列表（兼容旧接口 Api/Message/getRemindList）。\n     */\n    public function getRemindList(Request $request, Response $response): Response\n    {\n        $page = $this->getParam($request, 'page', 1);\n        $count = $this->getParam($request, 'count', 15);\n\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        // 获取提醒消息列表\n        $list = \\App\\Model\\Message::getRemindList($uid, $page, $count);\n\n        return $this->success($response, $list ?: ['total' => 0, 'list' => []]);\n    }\n\n    /**\n     * 旧版快速获取未读提醒类消息的兼容接口（兼容 Api/Message/getUnreadRemind）。\n     *\n     * 旧实现已弃用并直接返回空数组，新版保持相同行为，建议前端使用 getUnread。\n     */\n    public function getUnreadRemind(Request $request, Response $response): Response\n    {\n        // 按旧版逻辑实现：快速获取未读提醒类消息\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        // 先检查是否存在未读提醒\n        $array = DB::table('message')\n            ->where('to_uid', $uid)\n            ->where('status', 0)\n            ->first();\n\n        $return = [];\n        if ($array) {\n            // 如果有未读的，再组装更多信息（取一条）\n            $list = \\App\\Model\\Message::getRemindList($uid, 1, 1, 0);\n            if ($list && !empty($list['list'][0])) {\n                $return = $list['list'][0];\n            }\n        }\n\n        return $this->success($response, $return);\n    }\n}\n"
  },
  {
    "path": "server/app/Api/Controller/MockController.php",
    "content": "<?php\n\nnamespace App\\Api\\Controller;\n\nuse App\\Common\\BaseController;\nuse App\\Model\\Mock;\nuse App\\Model\\Page;\nuse App\\Model\\User;\nuse App\\Common\\Helper\\HttpHelper;\nuse App\\Common\\Helper\\Env;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\n\nclass MockController extends BaseController\n{\n    /**\n     * 添加/更新Mock数据\n     * \n     * @param Request $request\n     * @param Response $response\n     * @return Response\n     */\n    public function add(Request $request, Response $response): Response\n    {\n        $user = [];\n        if ($error = $this->requireLoginUser($request, $response, $user)) {\n            return $error;\n        }\n\n        $uid = (int) ($user['uid'] ?? 0);\n        $pageId = $this->getParam($request, 'page_id', 0);\n        $template = $this->getParam($request, 'template', '');\n        $path = $this->getParam($request, 'path', '/');\n\n        // 获取页面信息\n        $page = Page::findById($pageId);\n        if (!$page) {\n            return $this->error($response, 10101, '页面不存在');\n        }\n\n        // 权限检查\n        if (!$this->checkItemEdit($uid, (int) ($page['item_id'] ?? 0))) {\n            return $this->error($response, 10303, '没有权限');\n        }\n\n        // 路径处理：确保以 / 开头\n        if (substr($path, 0, 1) !== '/') {\n            $path = '/' . $path;\n        }\n\n        $itemId = (int) $page['item_id'];\n\n        // 验证JSON格式\n        $json = json_decode(htmlspecialchars_decode($template));\n        if (!$json) {\n            return $this->error($response, 10101, '为了服务器安全，只允许写符合json语法的字符串');\n        }\n\n        // 生成唯一key\n        $uniqueKey = md5(time() . rand() . \"gbgdhbdgtfgfK3@bv45342asfsdfjhyfgkj54fofgfbv45342asfsdg\");\n\n        // 检查是否已存在该页面的Mock\n        $mockPage = Mock::findByPageId($pageId);\n        if ($mockPage) {\n            // 更新现有Mock\n            $uniqueKey = $mockPage['unique_key'];\n            Mock::saveByPageId($pageId, [\n                'uid' => $uid,\n                'template' => $template,\n                'path' => $path,\n                'last_update_time' => date(\"Y-m-d H:i:s\"),\n            ]);\n        } else {\n            // 新建Mock\n            Mock::add([\n                'unique_key' => $uniqueKey,\n                'uid' => $uid,\n                'page_id' => $pageId,\n                'item_id' => $itemId,\n                'template' => $template,\n                'path' => $path,\n                'addtime' => date(\"Y-m-d H:i:s\"),\n                'last_update_time' => date(\"Y-m-d H:i:s\"),\n                'view_times' => 0,\n            ]);\n        }\n\n        return $this->success($response, [\n            'page_id' => $pageId,\n            'path' => $path,\n            'unique_key' => $uniqueKey,\n        ]);\n    }\n\n    /**\n     * 根据页面ID获取mock信息\n     * \n     * @param Request $request\n     * @param Response $response\n     * @return Response\n     */\n    public function infoByPageId(Request $request, Response $response): Response\n    {\n        $user = [];\n        $this->requireLoginUser($request, $response, $user, false); // 非严格模式，允许未登录\n\n        $uid = (int) ($user['uid'] ?? 0);\n        $pageId = $this->getParam($request, 'page_id', 0);\n\n        $mock = Mock::findByPageId($pageId);\n        // 如果没有数据，返回空数据而不是错误（避免前端显示错误弹窗）\n        if (!$mock) {\n            return $this->success($response, []);\n        }\n\n        // 权限检查\n        if (!$this->checkItemVisit($uid, $mock['item_id'], '')) {\n            return $this->error($response, 10103, '没有权限');\n        }\n\n        return $this->success($response, $mock);\n    }\n\n    /**\n     * 根据唯一key获取mock的响应数据\n     * \n     * @param Request $request\n     * @param Response $response\n     * @return Response\n     */\n    public function infoByKey(Request $request, Response $response): Response\n    {\n        $uniqueKey = $this->getParam($request, 'unique_key', '');\n\n        $mock = Mock::findByUniqueKey($uniqueKey);\n        if (!$mock) {\n            $response->getBody()->write('no such key');\n            return $response->withStatus(404);\n        }\n\n        $template = $mock['template'];\n        $mockHost = Env::get('MOCK_HOST', '127.0.0.1');\n        $mockPort = Env::get('MOCK_PORT', '7123');\n\n        // 调用Mock服务\n        $res = HttpHelper::post(\"http://{$mockHost}:{$mockPort}/mock\", [\n            'template' => htmlspecialchars_decode($template),\n        ]);\n\n        if ($res) {\n            $json = json_decode($res, true);\n            if (!$json) {\n                $response->getBody()->write('为了服务器安全，只允许写符合json语法的字符串');\n                return $response->withStatus(400);\n            }\n\n            // 直接使用原始 JSON 数据\n\n            // 使用 json_encode 重新编码，确保安全（会自动转义所有特殊字符）\n            $response->getBody()->write(json_encode($json, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));\n            return $response->withHeader('Content-Type', 'application/json');\n        } else {\n            $response->getBody()->write('mock服务暂时不可用。网站管理员安装完showdoc后需要另行安装mock服务，详情请打开https://www.showdoc.com.cn/help');\n            return $response->withStatus(503);\n        }\n    }\n\n    /**\n     * 根据item_id和path获取mock数据\n     * \n     * @param Request $request\n     * @param Response $response\n     * @return Response\n     */\n    public function infoByPath(Request $request, Response $response): Response\n    {\n        // 使用 getParam 获取参数（更安全）\n        $itemId = $this->getParam($request, 'item_id', 0);\n        $path = $this->getParam($request, 'path', '/');\n\n        $mock = Mock::findByItemIdAndPath($itemId, $path);\n        if (!$mock) {\n            $response->getBody()->write('no such path');\n            return $response->withStatus(404);\n        }\n\n        $template = $mock['template'];\n        $mockHost = Env::get('MOCK_HOST', '127.0.0.1');\n        $mockPort = Env::get('MOCK_PORT', '7123');\n\n        // 调用Mock服务\n        $res = HttpHelper::post(\"http://{$mockHost}:{$mockPort}/mock\", [\n            'template' => htmlspecialchars_decode($template),\n        ]);\n\n        if ($res) {\n            // 增加查看次数\n            Mock::incrementViewTimes($mock['id']);\n\n            $json = json_decode($res, true);\n            if (!$json) {\n                $response->getBody()->write('为了服务器安全，只允许写符合json语法的字符串');\n                return $response->withStatus(400);\n            }\n\n            // 直接使用原始 JSON 数据\n\n            // 使用 json_encode 重新编码，确保安全（会自动转义所有特殊字符）\n            $response->getBody()->write(json_encode($json, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));\n            return $response->withHeader('Content-Type', 'application/json');\n        } else {\n            $response->getBody()->write('mock服务暂时不可用。网站管理员安装完showdoc后需要另行安装mock服务，详情请打开https://www.showdoc.com.cn/help');\n            return $response->withStatus(503);\n        }\n    }\n}\n"
  },
  {
    "path": "server/app/Api/Controller/OpenController.php",
    "content": "<?php\n\nnamespace App\\Api\\Controller;\n\nuse App\\Common\\BaseController;\nuse App\\Model\\ItemToken;\nuse App\\Model\\Page;\nuse App\\Model\\Catalog;\nuse App\\Model\\Item;\nuse App\\Model\\VersionUpdate;\nuse App\\Model\\Attachment;\nuse App\\Model\\UploadFile;\nuse App\\Model\\FilePage;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\n\nclass OpenController extends BaseController\n{\n    /**\n     * 根据内容更新页面（创建或更新）\n     * 通过 api_key 和 api_token 鉴权\n     *\n     * @param Request $request\n     * @param Response $response\n     * @return Response\n     */\n    public function updatePage(Request $request, Response $response): Response\n    {\n        $apiKey = $this->getParam($request, 'api_key', '');\n        $apiToken = $this->getParam($request, 'api_token', '');\n        $catName = $this->getParam($request, 'cat_name', '');\n        $catNameSub = $this->getParam($request, 'cat_name_sub', '');\n        $pageTitle = $this->getParam($request, 'page_title', '');\n        $pageContent = $this->getParam($request, 'page_content', '');\n        $sNumber = $this->getParam($request, 's_number', 99);\n\n        // 兼容之前的 cat_name_sub 参数\n        if ($catNameSub) {\n            $catName = $catName . '/' . $catNameSub;\n        }\n\n        // 鉴权\n        $itemId = ItemToken::check($apiKey, $apiToken);\n        if (!$itemId) {\n            return $this->error($response, 10306, 'api_key或者api_token不匹配');\n        }\n\n\n        // 检查页面数量限制\n        $pageCount = Page::getPageCount($itemId);\n        if ($pageCount > 5000) {\n            return $this->error($response, 10100, '你创建太多页面啦！如有需求请联系网站管理员');\n        }\n\n        // 更新或创建页面\n        $pageId = Page::updateByTitle($itemId, $pageTitle, $pageContent, $catName, $sNumber, 0, 'API');\n        if ($pageId) {\n            $ret = Page::findPage($pageId, $itemId);\n            if ($ret) {\n                return $this->success($response, $ret);\n            }\n        }\n\n        return $this->error($response, 10101, '操作失败');\n    }\n\n    /**\n     * 根据内容更新项目（兼容旧接口，转向 updatePage）\n     *\n     * @deprecated 建议使用 updatePage 接口\n     * @param Request $request\n     * @param Response $response\n     * @return Response\n     */\n    public function updateItem(Request $request, Response $response): Response\n    {\n        // 兼容旧接口，直接调用新方法\n        return $this->updatePage($request, $response);\n    }\n\n    /**\n     * 根据 shell 上报的数据库结构信息生成数据字典\n     *\n     * @param Request $request\n     * @param Response $response\n     * @return Response\n     */\n    public function updateDbItem(Request $request, Response $response): Response\n    {\n        $apiKey = $this->getParam($request, 'api_key', '');\n        $apiToken = $this->getParam($request, 'api_token', '');\n        $tableInfo = $this->getParam($request, 'table_info', '');\n        $tableDetail = $this->getParam($request, 'table_detail', '');\n        $tableIndex = $this->getParam($request, 'table_index', '');\n        $sNumber = $this->getParam($request, 's_number', 99);\n        $catName = $this->getParam($request, 'cat_name', '');\n\n        // 鉴权\n        $itemId = ItemToken::check($apiKey, $apiToken);\n        if (!$itemId) {\n            $response->getBody()->write(\"\\napi_key或者api_token不匹配\\n\");\n            return $response->withHeader('Content-Type', 'text/plain; charset=utf-8');\n        }\n\n        // 检查页面数量限制\n        $pageCount = Page::getPageCount($itemId);\n        if ($pageCount > 5000) {\n            return $this->error($response, 10100, '你创建太多页面啦！如有需求请联系网站管理员');\n        }\n\n        $catName = str_replace(PHP_EOL, '', $catName);\n        $tableInfo = str_replace(\"_this_and_change_\", \"&\", $tableInfo);\n        $tableDetail = str_replace(\"_this_and_change_\", \"&\", $tableDetail);\n        $tableIndex = str_replace(\"_this_and_change_\", \"&\", $tableIndex);\n        $tables = $this->analyzeDbStructureToArray($tableInfo, $tableDetail, $tableIndex);\n\n        $result = false;\n        if (!empty($tables)) {\n            foreach ($tables as $value) {\n                $pageTitle = $value['table_name'];\n                $pageContent = $value['markdown'];\n                $pageId = Page::updateByTitle($itemId, $pageTitle, $pageContent, $catName, $sNumber, 0, 'API');\n                if ($pageId) {\n                    $result = true;\n                }\n            }\n        }\n\n        if ($result) {\n            $response->getBody()->write(\"成功\\n\");\n        } else {\n            $response->getBody()->write(\"失败\\n\");\n        }\n\n        return $response->withHeader('Content-Type', 'text/plain; charset=utf-8');\n    }\n\n    /**\n     * 解析数据库结构为数组\n     */\n    private function analyzeDbStructureToArray(string $tableInfo, string $tableDetail, string $tableIndex = ''): array\n    {\n        $tables = [];\n\n        // 解析 table_info\n        $array = explode(\"\\n\", $tableInfo);\n        if (!empty($array)) {\n            foreach ($array as $key => $value) {\n                if ($key == 0) {\n                    continue; // 跳过表头\n                }\n                $array2 = explode(\"\\t\", $value);\n                if (empty($array2[0])) {\n                    continue;\n                }\n                $tableName = str_replace(PHP_EOL, '', $array2[0]);\n                $tables[$array2[0]] = [\n                    'table_name'     => $tableName,\n                    'table_comment'  => $array2[1] ?? '',\n                    'engine'         => $array2[2] ?? '',\n                    'table_collation' => $array2[3] ?? '',\n                ];\n            }\n        }\n\n        // 解析 table_detail\n        $array = explode(\"\\n\", $tableDetail);\n        if (!empty($array)) {\n            foreach ($array as $key => $value) {\n                if ($key == 0) {\n                    continue; // 跳过表头\n                }\n                $array2 = explode(\"\\t\", $value);\n                if (empty($array2[0]) || empty($array2[1])) {\n                    continue;\n                }\n                if (!isset($tables[$array2[0]])) {\n                    $tables[$array2[0]] = [\n                        'table_name'     => $array2[0],\n                        'table_comment'  => '',\n                        'engine'         => '',\n                        'table_collation' => '',\n                    ];\n                }\n                $tables[$array2[0]]['columns'][$array2[1]] = [\n                    'column_name'    => $array2[1],\n                    'default'         => $array2[2] ?? '',\n                    'is_nullable'     => $array2[3] ?? '',\n                    'column_type'     => $array2[4] ?? '',\n                    'column_comment'  => $array2[5] ?? '无',\n                ];\n            }\n        }\n\n        // 解析 table_index\n        if (!empty($tableIndex)) {\n            $array = explode(\"\\n\", $tableIndex);\n            if (!empty($array)) {\n                foreach ($array as $key => $value) {\n                    if ($key == 0) {\n                        continue; // 跳过表头\n                    }\n                    $array2 = explode(\"\\t\", $value);\n                    if (empty($array2[0]) || empty($array2[1])) {\n                        continue;\n                    }\n                    $tableName = str_replace(PHP_EOL, '', $array2[0]);\n                    $indexName = str_replace(PHP_EOL, '', $array2[1]);\n                    $columnName = str_replace(PHP_EOL, '', $array2[2] ?? '');\n                    $seqInIndex = (int)($array2[3] ?? 0);\n                    $nonUnique = (int)($array2[4] ?? 1);\n                    $indexType = str_replace(PHP_EOL, '', $array2[5] ?? '');\n                    $indexComment = str_replace(PHP_EOL, '', $array2[6] ?? '');\n\n                    if (!isset($tables[$tableName])) {\n                        $tables[$tableName] = [\n                            'table_name'     => $tableName,\n                            'table_comment'  => '',\n                            'engine'         => '',\n                            'table_collation' => '',\n                        ];\n                    }\n                    if (!isset($tables[$tableName]['indexes'])) {\n                        $tables[$tableName]['indexes'] = [];\n                    }\n                    if (!isset($tables[$tableName]['indexes'][$indexName])) {\n                        $tables[$tableName]['indexes'][$indexName] = [\n                            'index_name'    => $indexName,\n                            'non_unique'    => $nonUnique,\n                            'index_type'    => $indexType,\n                            'index_comment' => $indexComment,\n                            'columns'       => [],\n                        ];\n                    }\n                    // 按序号添加列\n                    $tables[$tableName]['indexes'][$indexName]['columns'][$seqInIndex] = $columnName;\n                }\n            }\n        }\n\n        // 生成 markdown 内容\n        if (!empty($tables)) {\n            foreach ($tables as $key => $value) {\n                $markdown = '';\n                $markdown .= \"- {$value['table_comment']} \\n \\n\";\n                \n                // 字段表格\n                $markdown .= \"## 字段说明 \\n \\n\";\n                $markdown .= \"|字段|类型|允许空|默认|注释| \\n \";\n                $markdown .= \"|:----    |:-------    |:--- |----|------      | \\n \";\n                if (!empty($value['columns'])) {\n                    foreach ($value['columns'] as $value2) {\n                        $markdown .= \"|{$value2['column_name']} |{$value2['column_type']} |{$value2['is_nullable']} | {$value2['default']} | {$value2['column_comment']}  | \\n \";\n                    }\n                }\n                \n                // 索引表格\n                if (!empty($value['indexes'])) {\n                    $markdown .= \" \\n \\n## 索引说明 \\n \\n\";\n                    $markdown .= \"|索引名|类型|唯一|字段|注释| \\n \";\n                    $markdown .= \"|:----    |:-------    |:--- |----|------      | \\n \";\n                    foreach ($value['indexes'] as $index) {\n                        // 按序号排序列\n                        ksort($index['columns']);\n                        $columnsStr = implode(', ', $index['columns']);\n                        $uniqueStr = $index['non_unique'] == 0 ? '是' : '否';\n                        $indexComment = !empty($index['index_comment']) ? $index['index_comment'] : '无';\n                        $markdown .= \"|{$index['index_name']} |{$index['index_type']} |{$uniqueStr} | {$columnsStr} | {$indexComment}  | \\n \";\n                    }\n                }\n\n                // 表基本信息\n                if (!empty($value['engine']) || !empty($value['table_collation'])) {\n                    $markdown .= \" \\n \\n## 表基本信息 \\n \\n\";\n                    $markdown .= \"|属性|值| \\n \";\n                    $markdown .= \"|:----|----| \\n \";\n                    if (!empty($value['engine'])) {\n                        $markdown .= \"|引擎|{$value['engine']}| \\n \";\n                    }\n                    if (!empty($value['table_collation'])) {\n                        $markdown .= \"|字符集排序规则|{$value['table_collation']}| \\n \";\n                    }\n                }\n\n                $tables[$key]['markdown'] = $markdown;\n            }\n        }\n\n        return $tables;\n    }\n\n    /**\n     * 通过注释生成 API 文档\n     *\n     * @param Request $request\n     * @param Response $response\n     * @return Response\n     */\n    public function fromComments(Request $request, Response $response): Response\n    {\n        // 调用 FromCommentsController 的 generate 方法\n        $fromCommentsController = new \\App\\Api\\Controller\\FromCommentsController();\n        return $fromCommentsController->generate($request, $response);\n    }\n\n    /**\n     * 获取页面详情\n     * 通过 api_key 和 api_token 鉴权\n     *\n     * @param Request $request\n     * @param Response $response\n     * @return Response\n     */\n    public function getPage(Request $request, Response $response): Response\n    {\n        $apiKey = $this->getParam($request, 'api_key', '');\n        $apiToken = $this->getParam($request, 'api_token', '');\n        $pageId = $this->getParam($request, 'page_id', 0);\n        $pageTitle = $this->getParam($request, 'page_title', '');\n\n        // 鉴权\n        $itemId = ItemToken::check($apiKey, $apiToken);\n        if (!$itemId) {\n            return $this->error($response, 10306, 'api_key或者api_token不匹配');\n        }\n\n        // 如果提供了 page_title，则通过标题查找页面\n        if ($pageTitle && !$pageId) {\n            $page = \\Illuminate\\Database\\Capsule\\Manager::table('page')\n                ->where('item_id', $itemId)\n                ->where('page_title', $pageTitle)\n                ->where('is_del', 0)\n                ->first();\n            if ($page) {\n                $pageId = (int) $page->page_id;\n            }\n        }\n\n        if (!$pageId) {\n            return $this->error($response, 10101, 'page_id或page_title参数必填');\n        }\n\n        // 获取页面详情\n        $page = Page::findPage($pageId, $itemId);\n        if (!$page || (int) ($page['is_del'] ?? 0) === 1 || (int) ($page['item_id'] ?? 0) !== $itemId) {\n            return $this->error($response, 10101, '页面不存在或已删除');\n        }\n\n        // 格式化 addtime 为日期字符串（与旧版保持一致）\n        if (isset($page['addtime']) && is_numeric($page['addtime'])) {\n            $page['addtime'] = date('Y-m-d H:i:s', (int) $page['addtime']);\n        }\n\n        return $this->success($response, $page);\n    }\n\n    /**\n     * 删除页面\n     * 通过 api_key 和 api_token 鉴权\n     *\n     * @param Request $request\n     * @param Response $response\n     * @return Response\n     */\n    public function deletePage(Request $request, Response $response): Response\n    {\n        $apiKey = $this->getParam($request, 'api_key', '');\n        $apiToken = $this->getParam($request, 'api_token', '');\n        $pageId = $this->getParam($request, 'page_id', 0);\n\n        // 鉴权\n        $itemId = ItemToken::check($apiKey, $apiToken);\n        if (!$itemId) {\n            return $this->error($response, 10306, 'api_key或者api_token不匹配');\n        }\n\n        if (!$pageId) {\n            return $this->error($response, 10101, 'page_id参数必填');\n        }\n\n        // 检查页面是否属于该项目\n        $page = Page::findById($pageId);\n        if (!$page || (int) $page['item_id'] !== $itemId) {\n            return $this->error($response, 10101, '页面不存在或不属于该项目');\n        }\n\n        // 获取项目创建者信息\n        $item = Item::findById($itemId);\n        $uid = $item ? (int) ($item->uid ?? 0) : 0;\n        $username = 'API';\n        if ($uid > 0) {\n            $user = \\App\\Model\\User::findById($uid);\n            $username = $user ? ($user->username ?? 'API') : 'API';\n        }\n\n        // 软删除页面\n        $ret = Page::softDeletePage($pageId, $itemId, $uid, $username);\n        if ($ret) {\n            return $this->success($response, ['page_id' => $pageId]);\n        } else {\n            return $this->error($response, 10101, '删除页面失败');\n        }\n    }\n\n    /**\n     * 获取项目的目录树结构（包含页面标题）\n     * 通过 api_key 和 api_token 鉴权\n     *\n     * @param Request $request\n     * @param Response $response\n     * @return Response\n     */\n    public function getCatalogTree(Request $request, Response $response): Response\n    {\n        $apiKey = $this->getParam($request, 'api_key', '');\n        $apiToken = $this->getParam($request, 'api_token', '');\n\n        // 鉴权\n        $itemId = ItemToken::check($apiKey, $apiToken);\n        if (!$itemId) {\n            return $this->error($response, 10306, 'api_key或者api_token不匹配');\n        }\n\n        // 复用 ItemModel 的 getContent 方法获取完整的目录树结构\n        // page_field: 只获取必要的字段，不获取 page_content 节省资源\n        $menu = Item::getContent($itemId, false);\n\n        return $this->success($response, $menu);\n    }\n\n    /**\n     * 创建目录\n     * 通过 api_key 和 api_token 鉴权\n     *\n     * @param Request $request\n     * @param Response $response\n     * @return Response\n     */\n    public function createCatalog(Request $request, Response $response): Response\n    {\n        $apiKey = $this->getParam($request, 'api_key', '');\n        $apiToken = $this->getParam($request, 'api_token', '');\n        $catName = $this->getParam($request, 'cat_name', '');\n        $parentCatId = $this->getParam($request, 'parent_cat_id', 0);\n        $sNumber = $this->getParam($request, 's_number', 99);\n\n        // 鉴权\n        $itemId = ItemToken::check($apiKey, $apiToken);\n        if (!$itemId) {\n            return $this->error($response, 10306, 'api_key或者api_token不匹配');\n        }\n\n        if (empty($catName)) {\n            return $this->error($response, 10101, 'cat_name参数必填');\n        }\n\n\n        // 创建目录\n        $catalog = Catalog::save(0, $itemId, htmlspecialchars($catName), $parentCatId, $sNumber);\n        if ($catalog) {\n            Item::deleteCache($itemId);\n            return $this->success($response, $catalog);\n        } else {\n            return $this->error($response, 10101, '创建目录失败');\n        }\n    }\n\n    /**\n     * 修改目录\n     * 通过 api_key 和 api_token 鉴权\n     *\n     * @param Request $request\n     * @param Response $response\n     * @return Response\n     */\n    public function updateCatalog(Request $request, Response $response): Response\n    {\n        $apiKey = $this->getParam($request, 'api_key', '');\n        $apiToken = $this->getParam($request, 'api_token', '');\n        $catId = $this->getParam($request, 'cat_id', 0);\n        $catName = $this->getParam($request, 'cat_name', '');\n        $sNumber = $this->getParam($request, 's_number', 0);\n\n        // 鉴权\n        $itemId = ItemToken::check($apiKey, $apiToken);\n        if (!$itemId) {\n            return $this->error($response, 10306, 'api_key或者api_token不匹配');\n        }\n\n        if (!$catId) {\n            return $this->error($response, 10101, 'cat_id参数必填');\n        }\n\n        // 检查目录是否属于该项目\n        $catalog = Catalog::findByIdAndItemId($catId, $itemId);\n        if (!$catalog) {\n            return $this->error($response, 10101, '目录不存在或不属于该项目');\n        }\n\n        // 准备更新数据\n        $updateData = [];\n        if ($catName) {\n            $updateData['cat_name'] = htmlspecialchars($catName);\n        }\n        if ($sNumber !== null && $sNumber !== '') {\n            $updateData['s_number'] = $sNumber;\n        }\n\n        if (empty($updateData)) {\n            return $this->error($response, 10101, '请至少提供cat_name或s_number参数');\n        }\n\n        // 更新目录\n        $affected = \\Illuminate\\Database\\Capsule\\Manager::table('catalog')\n            ->where('cat_id', $catId)\n            ->where('item_id', $itemId)\n            ->update($updateData);\n        \n        if ($affected !== false) {\n            // 重新查询目录信息\n            $catalog = Catalog::findByIdAndItemId($catId, $itemId);\n            if ($catalog) {\n                return $this->success($response, (array) $catalog);\n            }\n        }\n        \n        return $this->error($response, 10101, '更新目录失败');\n    }\n\n    /**\n     * 删除目录\n     * 通过 api_key 和 api_token 鉴权\n     *\n     * @param Request $request\n     * @param Response $response\n     * @return Response\n     */\n    public function deleteCatalog(Request $request, Response $response): Response\n    {\n        $apiKey = $this->getParam($request, 'api_key', '');\n        $apiToken = $this->getParam($request, 'api_token', '');\n        $catId = $this->getParam($request, 'cat_id', 0);\n\n        // 鉴权\n        $itemId = ItemToken::check($apiKey, $apiToken);\n        if (!$itemId) {\n            return $this->error($response, 10306, 'api_key或者api_token不匹配');\n        }\n\n        if (!$catId) {\n            return $this->error($response, 10101, 'cat_id参数必填');\n        }\n\n        // 检查目录是否属于该项目\n        $catalog = Catalog::findByIdAndItemId($catId, $itemId);\n        if (!$catalog) {\n            return $this->error($response, 10101, '目录不存在或不属于该项目');\n        }\n\n        // 删除目录\n        $ret = Catalog::deleteCat($catId);\n        if ($ret) {\n            return $this->success($response, ['cat_id' => $catId]);\n        } else {\n            return $this->error($response, 10101, '删除目录失败');\n        }\n    }\n\n    /**\n     * 上传附件\n     * 通过 api_key 和 api_token 鉴权\n     *\n     * @param Request $request\n     * @param Response $response\n     * @return Response\n     */\n    public function uploadAttachment(Request $request, Response $response): Response\n    {\n        $apiKey = $this->getParam($request, 'api_key', '');\n        $apiToken = $this->getParam($request, 'api_token', '');\n        $pageId = $this->getParam($request, 'page_id', 0);\n\n        // 鉴权\n        $itemId = ItemToken::check($apiKey, $apiToken);\n        if (!$itemId) {\n            return $this->error($response, 10306, 'api_key或者api_token不匹配');\n        }\n\n        // 获取项目所有者\n        $item = Item::findById($itemId);\n        if (!$item) {\n            return $this->error($response, 10101, '项目不存在');\n        }\n        $uid = (int) ($item->uid ?? 0);\n\n        // 获取上传的文件\n        $uploadedFiles = $request->getUploadedFiles();\n        if (empty($uploadedFiles['file'])) {\n            return $this->error($response, 10101, '请上传文件');\n        }\n\n        $file = $uploadedFiles['file'];\n\n        // 检查文件扩展名\n        $filename = $file->getClientFilename();\n        if (!Attachment::isAllowedFilename($filename)) {\n            return $this->error($response, 10101, '不支持上传该文件类型。可将文件压缩成 zip/rar 等压缩包后上传，或联系网站管理员');\n        }\n\n        // 转换为 $_FILES 格式\n        $tmpFile = sys_get_temp_dir() . '/' . \\App\\Common\\Helper\\FileHelper::getRandStr();\n        $file->moveTo($tmpFile);\n\n        $_files = [\n            'file' => [\n                'name'     => $filename,\n                'type'     => $file->getClientMediaType(),\n                'tmp_name' => $tmpFile,\n                'error'    => UPLOAD_ERR_OK,\n                'size'     => $file->getSize(),\n            ],\n        ];\n\n        // 上传文件\n        $url = Attachment::upload($_files, 'file', $uid, $itemId, $pageId, true);\n        @unlink($tmpFile);\n\n        if ($url) {\n            // 从 URL 中提取 sign 参数\n            $parsedUrl = parse_url($url);\n            $sign = '';\n            if (isset($parsedUrl['query'])) {\n                parse_str($parsedUrl['query'], $params);\n                if (isset($params['sign'])) {\n                    $sign = $params['sign'];\n                }\n            }\n\n            // 通过 sign 查找 file_id\n            $fileId = 0;\n            if ($sign) {\n                $file = UploadFile::findBySign($sign);\n                if ($file) {\n                    // UploadFile::findBySign 返回的是对象，不是数组\n                    $fileId = (int) ($file->file_id ?? 0);\n                }\n            }\n\n            $result = ['url' => $url];\n            if ($fileId) {\n                $result['file_id'] = $fileId;\n            }\n            if ($sign) {\n                $result['sign'] = $sign;\n            }\n            return $this->success($response, $result);\n        } else {\n            return $this->error($response, 10101, '上传失败');\n        }\n    }\n\n    /**\n     * 删除附件\n     * 通过 api_key 和 api_token 鉴权\n     *\n     * @param Request $request\n     * @param Response $response\n     * @return Response\n     */\n    public function deleteAttachment(Request $request, Response $response): Response\n    {\n        $apiKey = $this->getParam($request, 'api_key', '');\n        $apiToken = $this->getParam($request, 'api_token', '');\n        $fileId = $this->getParam($request, 'file_id', 0);\n        $fileUrl = $this->getParam($request, 'file_url', '');\n        $sign = $this->getParam($request, 'sign', '');\n\n        // 鉴权\n        $itemId = ItemToken::check($apiKey, $apiToken);\n        if (!$itemId) {\n            return $this->error($response, 10306, 'api_key或者api_token不匹配');\n        }\n\n        // 通过 file_id, file_url 或 sign 查找文件\n        $file = null;\n        if ($fileId > 0) {\n            $file = UploadFile::findById($fileId);\n        } elseif ($sign) {\n            $file = UploadFile::findBySign($sign);\n            if ($file) {\n                // UploadFile::findBySign 返回的是对象，不是数组\n                $fileId = (int) ($file->file_id ?? 0);\n            }\n        } elseif ($fileUrl) {\n            // 从 URL 中提取 sign 参数\n            $parsedUrl = parse_url($fileUrl);\n            if (isset($parsedUrl['query'])) {\n                parse_str($parsedUrl['query'], $params);\n                if (isset($params['sign'])) {\n                    $sign = $params['sign'];\n                    $file = UploadFile::findBySign($sign);\n                    if ($file) {\n                        // UploadFile::findBySign 返回的是对象，不是数组\n                        $fileId = (int) ($file->file_id ?? 0);\n                    }\n                }\n            }\n        }\n\n        if (!$fileId || !$file) {\n            return $this->error($response, 10101, '请提供 file_id、file_url 或 sign 参数，且文件必须存在');\n        }\n\n        // 检查文件是否关联到该项目\n        $filePage = FilePage::findByFileIdAndItemId($fileId, $itemId);\n        // UploadFile::findById/findBySign 返回的是对象，不是数组\n        if (!$filePage && (int) ($file->item_id ?? 0) !== $itemId) {\n            return $this->error($response, 10101, '文件不属于该项目');\n        }\n\n        // 删除文件\n        $ret = Attachment::deleteFile($fileId);\n        if ($ret) {\n            return $this->success($response, ['file_id' => $fileId]);\n        } else {\n            return $this->error($response, 10101, '删除失败');\n        }\n    }\n\n}\n"
  },
  {
    "path": "server/app/Api/Controller/PageCommentController.php",
    "content": "<?php\n\nnamespace App\\Api\\Controller;\n\nuse App\\Common\\BaseController;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\n/**\n * 页面评论相关 Api（新架构）。\n */\nclass PageCommentController extends BaseController\n{\n    /**\n     * 获取评论列表（兼容旧接口 Api/PageComment/getList）。\n     *\n     * 功能：\n     * - 获取页面的评论列表（分页）\n     * - 包含一级评论和所有回复\n     * - 权限检查（checkItemVisit）\n     * - 检查项目是否开启评论功能\n     */\n    public function getList(Request $request, Response $response): Response\n    {\n        // 获取登录用户（非严格模式，允许游客访问）\n        $loginUser = [];\n        $this->requireLoginUser($request, $response, $loginUser, false);\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        $pageId = $this->getParam($request, 'page_id', 0);\n        $page = $this->getParam($request, 'page', 1);\n        $count = $this->getParam($request, 'count', 20);\n\n        if ($pageId <= 0) {\n            return $this->error($response, 10100, '缺少page_id参数');\n        }\n\n        // 获取页面信息\n        $pageInfo = \\App\\Model\\Page::findById($pageId);\n        if (!$pageInfo) {\n            return $this->error($response, 10101, '页面不存在');\n        }\n\n        $itemId = (int) ($pageInfo['item_id'] ?? 0);\n\n        // 检查访问权限\n        if (!$this->checkItemVisit($uid, $itemId)) {\n            return $this->error($response, 10303, '您没有访问权限');\n        }\n\n        // 检查项目是否开启评论功能\n        $item = \\App\\Model\\Item::findById($itemId);\n        if (!$item || (int) ($item->item_type ?? 0) != 1) {\n            // 非常规项目或未开启，返回空列表\n            return $this->success($response, [\n                'total' => 0,\n                'page' => $page,\n                'comments' => [],\n            ]);\n        }\n\n        if (!(int) ($item->allow_comment ?? 0)) {\n            // 未开启评论功能，返回空列表\n            return $this->success($response, [\n                'total' => 0,\n                'page' => $page,\n                'comments' => [],\n            ]);\n        }\n\n        // 获取一级评论（分页）\n        $result = \\App\\Model\\PageComment::getTopLevelList($pageId, $page, $count);\n        $total = $result['total'];\n        $comments = $result['list'];\n\n        $resultComments = [];\n        foreach ($comments as $comment) {\n            $commentData = $this->formatComment($comment, $uid, $itemId);\n\n            // 获取该评论的所有回复（不分页）\n            $replies = \\App\\Model\\PageComment::getReplies((int) $comment['comment_id']);\n            $commentData['replies'] = [];\n            foreach ($replies as $reply) {\n                $commentData['replies'][] = $this->formatComment($reply, $uid, $itemId);\n            }\n\n            $resultComments[] = $commentData;\n        }\n\n        return $this->success($response, [\n            'total' => (int) $total,\n            'page' => (int) $page,\n            'comments' => $resultComments,\n        ]);\n    }\n\n    /**\n     * 发表评论/回复（兼容旧接口 Api/PageComment/add）。\n     *\n     * 功能：\n     * - 发表评论或回复\n     * - 权限检查（checkItemVisit）\n     * - 防刷机制（10秒内最多1条评论）\n     * - 发送通知\n     */\n    public function add(Request $request, Response $response): Response\n    {\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n        $pageId = $this->getParam($request, 'page_id', 0);\n        $content = trim($this->getParam($request, 'content', ''));\n        $parentId = $this->getParam($request, 'parent_id', 0);\n\n        if ($pageId <= 0) {\n            return $this->error($response, 10100, '缺少page_id参数');\n        }\n\n        if (empty($content)) {\n            return $this->error($response, 10100, '评论内容不能为空');\n        }\n\n        $contentLen = mb_strlen($content, 'UTF-8');\n        if ($contentLen < 1 || $contentLen > 500) {\n            return $this->error($response, 10100, '评论内容长度必须在1-500字符之间');\n        }\n\n        // 旧版这里依赖 session 做 10 秒防刷（last_comment_time），\n        // 新架构中统一避免在业务层依赖全局 $_SESSION，这里仅依赖登录态 + 长度校验，不再做额外频率限制。\n\n        // 获取页面信息\n        $pageInfo = \\App\\Model\\Page::findById($pageId);\n        if (!$pageInfo) {\n            return $this->error($response, 10101, '页面不存在');\n        }\n\n        $itemId = (int) ($pageInfo['item_id'] ?? 0);\n\n        // 检查访问权限\n        if (!$this->checkItemVisit($uid, $itemId)) {\n            return $this->error($response, 10303, '您没有访问权限');\n        }\n\n        // 检查项目是否开启评论功能\n        $item = \\App\\Model\\Item::findById($itemId);\n        if (!$item || (int) ($item->item_type ?? 0) != 1) {\n            return $this->error($response, 10100, '此项目类型不支持评论功能');\n        }\n\n        if (!(int) ($item->allow_comment ?? 0)) {\n            return $this->error($response, 10100, '项目未开启评论功能');\n        }\n\n\n        // 如果是回复，检查父评论\n        if ($parentId > 0) {\n            $parentComment = \\App\\Model\\PageComment::findById($parentId);\n            if (!$parentComment || (int) ($parentComment->is_deleted ?? 0) == 1) {\n                return $this->error($response, 10100, '被回复的评论不存在或已删除');\n            }\n\n            // 检查父评论是否也是回复（仅支持两级）\n            if ((int) ($parentComment->parent_id ?? 0) > 0) {\n                return $this->error($response, 10100, '仅支持两级评论，不能对回复再次回复');\n            }\n        }\n\n        // 转义HTML，防止XSS\n        $content = htmlspecialchars($content, ENT_QUOTES, 'UTF-8');\n\n        // 保存评论\n        $user = \\App\\Model\\User::findById($uid);\n        $username = $user ? ($user->username ?? '') : '';\n\n        $commentData = [\n            'page_id' => $pageId,\n            'item_id' => $itemId,\n            'parent_id' => $parentId,\n            'uid' => $uid,\n            'username' => $username,\n            'content' => $content,\n            'is_deleted' => 0,\n            'addtime' => time(),\n        ];\n\n        $commentId = \\App\\Model\\PageComment::add($commentData);\n\n        if ($commentId <= 0) {\n            return $this->error($response, 10101, '评论发表失败');\n        }\n\n        // 发送通知\n        $this->sendCommentNotification($commentId, $pageId, $itemId, $parentId, $uid, $username, $pageInfo['page_title'] ?? '');\n\n        return $this->success($response, [\n            'comment_id' => $commentId,\n            'message' => '评论发表成功',\n        ]);\n    }\n\n    /**\n     * 删除评论（兼容旧接口 Api/PageComment/delete）。\n     *\n     * 功能：\n     * - 删除评论（软删除）\n     * - 权限检查：评论作者本人或项目管理员\n     */\n    public function delete(Request $request, Response $response): Response\n    {\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n        $commentId = $this->getParam($request, 'comment_id', 0);\n\n        if ($commentId <= 0) {\n            return $this->error($response, 10100, '缺少comment_id参数');\n        }\n\n        $comment = \\App\\Model\\PageComment::findById($commentId);\n        if (!$comment) {\n            return $this->error($response, 10101, '评论不存在');\n        }\n\n        $itemId = (int) ($comment->item_id ?? 0);\n        $commentUid = (int) ($comment->uid ?? 0);\n\n        // 检查权限：评论作者本人或项目管理员\n        $canDelete = false;\n        if ($commentUid === $uid) {\n            $canDelete = true;\n        } elseif ($this->checkItemManage($uid, $itemId)) {\n            $canDelete = true;\n        }\n\n        if (!$canDelete) {\n            return $this->error($response, 10303, '无权限删除此评论');\n        }\n\n        // 软删除\n        $result = \\App\\Model\\PageComment::update($commentId, ['is_deleted' => 1]);\n\n        if ($result) {\n            return $this->success($response, ['message' => '删除成功']);\n        } else {\n            return $this->error($response, 10101, '删除失败');\n        }\n    }\n\n    /**\n     * 格式化评论数据\n     *\n     * @param array $comment 评论数据\n     * @param int $currentUid 当前用户 ID\n     * @param int $itemId 项目 ID\n     * @return array\n     */\n    private function formatComment(array $comment, int $currentUid, int $itemId): array\n    {\n        $commentUid = (int) ($comment['uid'] ?? 0);\n        $isOwner = ($commentUid === $currentUid);\n        $canDelete = $isOwner || $this->checkItemManage($currentUid, $itemId);\n\n        return [\n            'comment_id' => (int) ($comment['comment_id'] ?? 0),\n            'parent_id' => (int) ($comment['parent_id'] ?? 0),\n            'uid' => $commentUid,\n            'username' => $comment['username'] ?? '',\n            'content' => $comment['content'] ?? '',\n            'addtime' => (int) ($comment['addtime'] ?? 0),\n            'addtime_text' => date('Y-m-d H:i', (int) ($comment['addtime'] ?? time())),\n            'is_owner' => $isOwner,\n            'can_delete' => $canDelete,\n        ];\n    }\n\n    /**\n     * 发送评论通知\n     *\n     * @param int $commentId 评论 ID\n     * @param int $pageId 页面 ID\n     * @param int $itemId 项目 ID\n     * @param int $parentId 父评论 ID\n     * @param int $fromUid 发送者用户 ID\n     * @param string $fromName 发送者名称\n     * @param string $pageTitle 页面标题\n     */\n    private function sendCommentNotification(int $commentId, int $pageId, int $itemId, int $parentId, int $fromUid, string $fromName, string $pageTitle): void\n    {\n        if ($parentId == 0) {\n            // 场景1：新评论，通知项目管理员\n            $item = \\App\\Model\\Item::findById($itemId);\n            if (!$item) {\n                return;\n            }\n\n            $creatorUid = (int) ($item->uid ?? 0);\n\n            // 获取项目管理员（member_group_id = 2）\n            $managers = DB::table('item_member')\n                ->where('item_id', $itemId)\n                ->where('member_group_id', 2)\n                ->get()\n                ->all();\n\n            // 获取团队项目管理员（member_group_id = 2）\n            $teamManagers = DB::table('team_item_member')\n                ->where('item_id', $itemId)\n                ->where('member_group_id', 2)\n                ->get()\n                ->all();\n\n            $notifiedUids = [];\n            $notifyContent = $fromName . ' 发表了新评论';\n\n            // 通知创建者\n            if ($creatorUid != $fromUid && !in_array($creatorUid, $notifiedUids)) {\n                \\App\\Model\\Message::addMsg($fromUid, $fromName, $creatorUid, 'remind', $notifyContent, 'comment', 'page', $pageId);\n                $notifiedUids[] = $creatorUid;\n            }\n\n            // 通知项目管理员\n            foreach ($managers as $manager) {\n                $managerUid = (int) ($manager->uid ?? 0);\n                if ($managerUid != $fromUid && !in_array($managerUid, $notifiedUids)) {\n                    \\App\\Model\\Message::addMsg($fromUid, $fromName, $managerUid, 'remind', $notifyContent, 'comment', 'page', $pageId);\n                    $notifiedUids[] = $managerUid;\n                }\n            }\n\n            // 通知团队项目管理员\n            foreach ($teamManagers as $teamManager) {\n                $teamManagerUid = (int) ($teamManager->member_uid ?? 0);\n                if ($teamManagerUid != $fromUid && !in_array($teamManagerUid, $notifiedUids)) {\n                    \\App\\Model\\Message::addMsg($fromUid, $fromName, $teamManagerUid, 'remind', $notifyContent, 'comment', 'page', $pageId);\n                    $notifiedUids[] = $teamManagerUid;\n                }\n            }\n        } else {\n            // 场景2：回复评论，通知被回复的作者\n            $parentComment = \\App\\Model\\PageComment::findById($parentId);\n            if (!$parentComment) {\n                return;\n            }\n\n            $parentUid = (int) ($parentComment->uid ?? 0);\n\n            // 只通知原作者（不是自己）\n            if ($parentUid != $fromUid) {\n                $notifyContent = $fromName . ' 有新回复';\n                \\App\\Model\\Message::addMsg($fromUid, $fromName, $parentUid, 'remind', $notifyContent, 'comment', 'page', $pageId);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "server/app/Api/Controller/PageController.php",
    "content": "<?php\n\nnamespace App\\Api\\Controller;\n\nuse App\\Common\\BaseController;\nuse App\\Common\\Helper\\Convert;\nuse Illuminate\\Database\\Capsule\\Manager as DB;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\n\n/**\n * 页面相关 Api（新架构）。\n *\n * 目前优先迁移与调试/运维相关的接口，例如：\n * - sqlToMarkdownTable：将建表 SQL 转为 Markdown 表格，便于文档化。\n */\nclass PageController extends BaseController\n{\n    /**\n     * 将建表 SQL 语句转换为 Markdown 表格（兼容旧接口 Page/sqlToMarkdownTable）。\n     *\n     * 入参：\n     * - sql: string，必填，建表 SQL 文本\n     *\n     * 返回：\n     * - { error_code: 0, data: { markdown: \"...\" } }\n     */\n    public function sqlToMarkdownTable(Request $request, Response $response): Response\n    {\n        $sql = $this->getParam($request, 'sql', '');\n\n        if ($sql === '') {\n            // 旧版直接 return false；新实现统一走业务错误码，HTTP 仍为 200\n            return $this->error($response, 10101, 'SQL 不能为空');\n        }\n\n        $converter = new Convert();\n        $markdown  = $converter->convertSqlToMarkdownTable($sql);\n\n        if ($markdown === '') {\n            // 解析失败或非建表语句\n            return $this->error($response, 10101, '无法解析该 SQL，请检查是否为合法的建表语句');\n        }\n\n        return $this->success($response, [\n            'markdown' => $markdown,\n        ]);\n    }\n\n    /**\n     * 页面详情接口（兼容旧接口 Api/Page/info）。\n     */\n    public function info(Request $request, Response $response): Response\n    {\n        $pageId   = $this->getParam($request, 'page_id', 0);\n        $withPath = $this->getParam($request, 'with_path', 0);\n\n        if ($pageId <= 0) {\n            sleep(1);\n            return $this->error($response, 10101, '页面不存在');\n        }\n\n        // 获取页面\n        $page = DB::table('page')\n            ->where('page_id', $pageId)\n            ->first();\n\n        if (!$page || (int) ($page->is_del ?? 0) === 1) {\n            sleep(1);\n            return $this->error($response, 10101, '页面不存在');\n        }\n\n        $itemId = (int) ($page->item_id ?? 0);\n\n        // 获取登录用户（非严格模式，允许游客访问）\n        $loginUser = [];\n        $this->requireLoginUser($request, $response, $loginUser, false);\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        // 检查访问权限\n        if (!$this->checkItemVisit($uid, $itemId)) {\n            return $this->error($response, 10101, '您没有访问权限');\n        }\n\n        // 转换为数组格式\n        $page = (array) $page;\n\n        // 检查草稿访问权限\n        if (($page['is_draft'] ?? 0) == 1) {\n            $authorUid = (int) ($page['author_uid'] ?? 0);\n            if ($uid <= 0 || $uid !== $authorUid) {\n                return $this->error($response, 10101, '该页面是草稿状态，暂不可访问');\n            }\n        }\n\n        // 格式化时间\n        $page['addtime'] = date('Y-m-d H:i:s', (int) ($page['addtime'] ?? time()));\n        if (!empty($page['page_addtime']) && (int) $page['page_addtime'] > 0) {\n            $page['page_addtime'] = date('Y-m-d H:i:s', (int) $page['page_addtime']);\n        } else {\n            $page['page_addtime'] = $page['addtime'];\n        }\n\n        // 附件数量\n        $page['attachment_count'] = DB::table('file_page')\n            ->where('page_id', $pageId)\n            ->count();\n\n        // 单页链接唯一标识\n        $singlePage = DB::table('single_page')\n            ->where('page_id', $pageId)\n            ->first();\n        if ($singlePage) {\n            // 检查单页链接是否已过期\n            $expireTime = (int) ($singlePage->expire_time ?? 0);\n            if ($expireTime > 0 && $expireTime < time()) {\n                // 链接已过期，从数据库中删除记录\n                DB::table('single_page')\n                    ->where('page_id', $pageId)\n                    ->delete();\n                $page['unique_key'] = '';\n            } else {\n                $page['unique_key'] = (string) ($singlePage->unique_key ?? '');\n            }\n        } else {\n            $page['unique_key'] = '';\n        }\n\n        // 如果请求了完整路径信息，获取该页面的所有上级目录\n        if ($withPath && !empty($page['cat_id'])) {\n            $fullPath = $this->getFullPath((int) $page['cat_id'], $itemId);\n            // 添加当前页面作为路径的最后一个元素\n            $fullPath[] = [\n                'page_id'    => $page['page_id'],\n                'page_title' => $page['page_title'],\n            ];\n            $page['full_path'] = $fullPath;\n        }\n\n        return $this->success($response, $page);\n    }\n\n    /**\n     * 获取目录的完整路径\n     *\n     * @param int $catId 当前目录 ID\n     * @param int $itemId 项目 ID\n     * @return array 完整路径数组（从上到下）\n     */\n    private function getFullPath(int $catId, int $itemId): array\n    {\n        if ($catId <= 0 || $itemId <= 0) {\n            return [];\n        }\n\n        $path = [];\n        $this->findCatPath($catId, $itemId, $path);\n\n        // 返回路径（从上到下排序）\n        return array_reverse($path);\n    }\n\n    /**\n     * 递归查找目录路径\n     *\n     * @param int $catId 当前目录 ID\n     * @param int $itemId 项目 ID\n     * @param array &$path 路径数组（引用传递）\n     * @return bool 是否找到路径\n     */\n    private function findCatPath(int $catId, int $itemId, array &$path): bool\n    {\n        // 查找当前目录信息\n        $catalog = \\App\\Model\\Catalog::findByIdAndItemId($catId, $itemId);\n        if (!$catalog) {\n            return false;\n        }\n\n        // 添加当前目录到路径\n        $path[] = [\n            'cat_id'   => $catalog->cat_id,\n            'cat_name' => $catalog->cat_name,\n        ];\n\n        // 如果有父目录，继续递归查找\n        $parentCatId = (int) ($catalog->parent_cat_id ?? 0);\n        if ($parentCatId > 0) {\n            return $this->findCatPath($parentCatId, $itemId, $path);\n        }\n\n        return true;\n    }\n\n    /**\n     * 保存页面接口（兼容旧接口 Api/Page/save）。\n     *\n     * 功能：\n     * - 支持新建和更新页面\n     * - 权限检查\n     * - 页面历史版本保存\n     * - 菜单缓存更新\n     * - 订阅通知\n     * - AI 索引更新（异步）\n     */\n    public function save(Request $request, Response $response): Response\n    {\n        ini_set('memory_limit', '128M');\n\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        // 获取参数\n        $pageId       = $this->getParam($request, 'page_id', 0);\n        $isUrlencode  = $this->getParam($request, 'is_urlencode', 0);\n        $pageTitle    = $this->getParam($request, 'page_title', '默认标题');\n        $pageComments = $this->getParam($request, 'page_comments', '');\n        $pageContent  = $this->getParam($request, 'page_content', '');\n        $catId        = $this->getParam($request, 'cat_id', 0);\n        $itemId       = $this->getParam($request, 'item_id', 0);\n        $sNumber      = $this->getParam($request, 's_number', 0);\n        $isNotify     = $this->getParam($request, 'is_notify', 0);\n        $notifyContent = $this->getParam($request, 'notify_content', '');\n        $extInfo      = $this->getParam($request, 'ext_info', '');\n        $isDraft      = $this->getParam($request, 'is_draft', -1); // -1 表示不改变状态\n\n        // 验证内容不能为空\n        if (empty($pageContent)) {\n            return $this->error($response, 10101, '不允许保存空内容，请随便写点什么');\n        }\n\n        // URL 解码\n        if ($isUrlencode) {\n            $pageContent = urldecode($pageContent);\n        }\n\n        // HTML 转义\n        $pageContent = htmlspecialchars($pageContent, ENT_QUOTES, 'UTF-8');\n\n        // 检查编辑权限\n        if (!$this->checkItemEdit($uid, $itemId)) {\n            return $this->error($response, 10101, '没有编辑权限');\n        }\n\n        $item = \\App\\Model\\Item::findById($itemId);\n\n\n        // 准备数据\n        $data = [\n            'page_title'      => $pageTitle,\n            'page_content'    => $pageContent,\n            'page_comments'   => $pageComments,\n            'item_id'         => $itemId,\n            'cat_id'          => $catId,\n            'addtime'         => time(),\n            'author_uid'      => $uid,\n            'author_username' => $loginUser['username'] ?? '',\n            'ext_info'        => $extInfo,\n        ];\n\n        if ($sNumber > 0) {\n            $data['s_number'] = $sNumber;\n        }\n\n        // 处理草稿状态\n        if ($isDraft >= 0) {\n            $data['is_draft'] = (int) $isDraft;\n        }\n\n        // 对于 runapi 项目类型，填充 ext_info 字段\n        if (empty($data['ext_info']) && $item && (int) $item->item_type === 3) {\n            $contentJson = htmlspecialchars_decode($pageContent);\n            $content     = json_decode($contentJson, true);\n            if ($content && isset($content['info']['url'])) {\n                $type = $content['info']['type'] ?? 'api';\n\n                if ($type === 'websocket') {\n                    $extInfoArray = [\n                        'page_type' => 'websocket',\n                        'api_info'  => ['type' => 'websocket'],\n                    ];\n                } elseif ($type === 'sse') {\n                    $extInfoArray = [\n                        'page_type' => 'sse',\n                        'api_info'  => ['type' => 'sse'],\n                    ];\n                } else {\n                    $extInfoArray = [\n                        'page_type' => 'api',\n                        'api_info'  => ['method' => $content['info']['method'] ?? 'GET'],\n                    ];\n                }\n\n                $data['ext_info'] = json_encode($extInfoArray, JSON_UNESCAPED_UNICODE);\n            }\n        }\n\n        if ($pageId > 0) {\n            // 更新页面\n            $page = \\App\\Model\\Page::findById($pageId);\n            if (!$page) {\n                return $this->error($response, 10101, '页面不存在');\n            }\n\n            if ((int) $page['item_id'] !== $itemId) {\n                return $this->error($response, 10101, '页面不属于该项目');\n            }\n\n            if (!$this->checkItemEdit($uid, (int) $page['item_id'])) {\n                return $this->error($response, 10101, '您没有编辑权限');\n            }\n\n            // 保存历史版本\n            $historyData = [\n                'page_id'         => $page['page_id'],\n                'item_id'         => $page['item_id'],\n                'cat_id'          => $page['cat_id'],\n                'page_title'      => $page['page_title'],\n                'page_comments'   => $page['page_comments'] ?? '',\n                'page_content'    => $page['page_content'],\n                's_number'        => $page['s_number'] ?? 0,\n                'addtime'         => $page['addtime'] ?? time(),\n                'author_uid'      => $page['author_uid'] ?? 0,\n                'author_username' => $page['author_username'] ?? '',\n                'ext_info'        => $page['ext_info'] ?? '',\n            ];\n            \\App\\Model\\PageHistory::add($pageId, $historyData);\n\n            // 更新页面\n            $ret = \\App\\Model\\Page::savePage($pageId, $itemId, $data);\n\n            if (!$ret) {\n                return $this->error($response, 10101, '保存失败');\n            }\n\n            // 记录变更日志\n            \\App\\Model\\ItemChangeLog::addLog($uid, $itemId, 'update', 'page', $pageId, $pageTitle);\n\n            // 统计历史版本数量并清理旧版本\n            $count = \\App\\Model\\PageHistory::getCount($pageId);\n            // 开源版：保留最近 100 个历史版本\n            $keepCount = 100;\n            if ($count > $keepCount) {\n                \\App\\Model\\PageHistory::deleteOldVersions($pageId, $keepCount);\n            }\n\n            // 更新项目时间\n            if ($item && (int) $item->item_type === 2) {\n                // 单页项目，将页面标题设置为项目名\n                \\Illuminate\\Database\\Capsule\\Manager::table('item')\n                    ->where('item_id', $itemId)\n                    ->update([\n                        'last_update_time' => time(),\n                        'item_name'        => $pageTitle,\n                    ]);\n            } else {\n                \\Illuminate\\Database\\Capsule\\Manager::table('item')\n                    ->where('item_id', $itemId)\n                    ->update(['last_update_time' => time()]);\n            }\n\n            // 检测目录 id 和页面顺序号有没有发生变化\n            if ($data['cat_id'] == $page['cat_id'] && ($data['s_number'] ?? 0) == ($page['s_number'] ?? 0)) {\n                // 如果没有变化，则仅更新缓存 menu 中的这个页面\n                \\App\\Model\\Item::updateMenuCachePage($itemId, $pageId, $pageTitle);\n            } else {\n                // 其他情况，直接删除菜单缓存\n                \\App\\Model\\Item::deleteCache($itemId);\n            }\n\n            // 订阅通知\n            if ($isNotify) {\n                $subscriptions = \\App\\Model\\Subscription::getListByObjectId($pageId, 'page', 'update');\n                foreach ($subscriptions as $sub) {\n                    \\App\\Model\\Message::addMsg(\n                        $uid,\n                        $loginUser['username'] ?? '',\n                        (int) $sub['uid'],\n                        'remind',\n                        $notifyContent,\n                        'update',\n                        'page',\n                        $pageId\n                    );\n                }\n            }\n\n            $return = \\App\\Model\\Page::findById($pageId);\n        } else {\n            // 新建页面（开源版无页面数量限制）\n\n            // 添加页面\n            $pageId = \\App\\Model\\Page::addPage($itemId, $data);\n            if ($pageId <= 0) {\n                return $this->error($response, 10101, '创建页面失败');\n            }\n\n            // 记录变更日志\n            \\App\\Model\\ItemChangeLog::addLog($uid, $itemId, 'create', 'page', $pageId, $pageTitle);\n\n            // 更新项目时间\n            \\Illuminate\\Database\\Capsule\\Manager::table('item')\n                ->where('item_id', $itemId)\n                ->update(['last_update_time' => time()]);\n\n            // 删除菜单缓存\n            \\App\\Model\\Item::deleteCache($itemId);\n\n            // 暂停 800 毫秒，以便应对主从数据库同步延迟\n            usleep(800000);\n\n            // 添加页面的时候把最初的创建者加入消息订阅\n            \\App\\Model\\Subscription::addSub($uid, $pageId, 'page', 'update');\n\n            $return = ['page_id' => $pageId];\n        }\n\n        // 删除页面缓存\n        \\App\\Model\\Page::deleteCache($pageId);\n\n        // 获取一次菜单以便生成缓存\n        \\App\\Model\\Item::getMenuByCache($itemId);\n\n\n        // 先返回响应，确保用户能收到结果\n        $result = $this->success($response, $return);\n\n        // 使用 register_shutdown_function 在响应发送后异步触发 AI 索引更新\n        // 这样既能正常返回响应，又不会阻塞用户请求\n        register_shutdown_function(function () use ($itemId, $pageId) {\n            // 在响应发送后执行，不会阻塞用户\n            try {\n                // 检查 AI 知识库功能是否启用\n                $itemAiConfig = \\App\\Model\\ItemAiConfig::getConfig($itemId);\n                if (empty($itemAiConfig['enabled'])) {\n                    // AI 功能未启用，不触发索引更新\n                    return;\n                }\n\n                // 从全局配置获取 AI 服务地址和 Token\n                $aiServiceUrl = \\App\\Model\\Options::get('ai_service_url', '');\n                $aiServiceToken = \\App\\Model\\Options::get('ai_service_token', '');\n\n                if (empty($aiServiceUrl) || empty($aiServiceToken)) {\n                    // AI 服务未配置，不触发索引更新\n                    return;\n                }\n\n                // 触发整个项目的索引重建（异步）\n                \\App\\Common\\Helper\\AiHelper::rebuild($itemId, $aiServiceUrl, $aiServiceToken);\n            } catch (\\Throwable $e) {\n                // 索引更新失败不影响页面保存，只记录错误日志\n                error_log(\"触发 AI 索引更新失败: item_id={$itemId}, page_id={$pageId}, error=\" . $e->getMessage());\n            }\n        });\n\n        return $result;\n    }\n\n    /**\n     * 触发 AI 索引更新（异步，不阻塞主流程）\n     *\n     * @param int $itemId 项目ID\n     * @param int $pageId 页面ID\n     * @param string $action 操作类型：'create' 或 'update'\n     * @return void\n     */\n    private function triggerAiIndex(int $itemId, int $pageId, string $action = 'update'): void\n    {\n        try {\n            // 检查 AI 知识库功能是否启用\n            $itemAiConfig = \\App\\Model\\ItemAiConfig::getConfig($itemId);\n            if (empty($itemAiConfig['enabled'])) {\n                // AI 功能未启用，不触发索引更新\n                return;\n            }\n\n            // 从全局配置获取 AI 服务地址和 Token\n            $aiServiceUrl = \\App\\Model\\Options::get('ai_service_url', '');\n            $aiServiceToken = \\App\\Model\\Options::get('ai_service_token', '');\n\n            if (empty($aiServiceUrl) || empty($aiServiceToken)) {\n                // AI 服务未配置，不触发索引更新\n                return;\n            }\n\n            // 如果是单个页面更新，可以只更新该页面；如果是创建或需要全量重建，则重建整个项目索引\n            // 这里简化处理：页面保存后触发整个项目的索引重建（异步）\n            // 注意：rebuild 方法会处理整个项目，所以这里直接调用 rebuild\n            \\App\\Common\\Helper\\AiHelper::rebuild($itemId, $aiServiceUrl, $aiServiceToken);\n        } catch (\\Throwable $e) {\n            // 索引更新失败不影响页面保存，只记录错误日志\n            error_log(\"触发 AI 索引更新失败: item_id={$itemId}, page_id={$pageId}, action={$action}, error=\" . $e->getMessage());\n        }\n    }\n\n    /**\n     * 页面历史版本列表（兼容旧接口 Api/Page/history）。\n     *\n     * 功能：\n     * - 获取页面的历史版本列表\n     * - 权限检查（checkItemVisit）\n     * - 内容解压和格式化\n     */\n    public function history(Request $request, Response $response): Response\n    {\n        $pageId = $this->getParam($request, 'page_id', 0);\n\n        if ($pageId <= 0) {\n            return $this->error($response, 10101, '页面不存在');\n        }\n\n        // 获取页面信息\n        $page = \\App\\Model\\Page::findById($pageId);\n        if (!$page) {\n            return $this->error($response, 10101, '页面不存在');\n        }\n\n        $itemId = (int) $page['item_id'];\n\n        // 获取登录用户（非严格模式，允许游客访问）\n        $loginUser = [];\n        $this->requireLoginUser($request, $response, $loginUser, false);\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        // 检查访问权限\n        if (!$this->checkItemVisit($uid, $itemId)) {\n            return $this->error($response, 10101, '您没有访问权限');\n        }\n\n        // 获取历史版本列表\n        $pageHistory = \\App\\Model\\PageHistory::getList($pageId, 100);\n\n        return $this->success($response, $pageHistory);\n    }\n\n    /**\n     * 页面版本对比（兼容旧接口 Api/Page/diff）。\n     *\n     * 功能：\n     * - 返回当前页面和历史某个版本的页面以供比较\n     * - 权限检查（checkItemVisit）\n     */\n    public function diff(Request $request, Response $response): Response\n    {\n        $pageId        = $this->getParam($request, 'page_id', 0);\n        $pageHistoryId = $this->getParam($request, 'page_history_id', 0);\n\n        if ($pageId <= 0) {\n            return $this->error($response, 10101, '页面不存在');\n        }\n\n        if ($pageHistoryId <= 0) {\n            return $this->error($response, 10101, '历史版本不存在');\n        }\n\n        // 获取当前页面\n        $page = \\App\\Model\\Page::findById($pageId);\n        if (!$page) {\n            sleep(1);\n            return $this->error($response, 10101, '页面不存在');\n        }\n\n        $itemId = (int) $page['item_id'];\n\n        // 获取登录用户（非严格模式，允许游客访问）\n        $loginUser = [];\n        $this->requireLoginUser($request, $response, $loginUser, false);\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        // 检查访问权限\n        if (!$this->checkItemVisit($uid, $itemId)) {\n            return $this->error($response, 10101, '您没有访问权限');\n        }\n\n        // 获取历史版本\n        $historyPage = \\App\\Model\\PageHistory::findById($pageId, $pageHistoryId);\n        if (!$historyPage) {\n            return $this->error($response, 10101, '历史版本不存在');\n        }\n\n        return $this->success($response, [\n            'page'         => $page,\n            'history_page' => $historyPage,\n        ]);\n    }\n\n    /**\n     * 更新历史版本备注（兼容旧接口 Api/Page/updateHistoryComments）。\n     *\n     * 功能：\n     * - 更新历史版本的备注信息\n     * - 权限检查（checkItemEdit）\n     */\n    public function updateHistoryComments(Request $request, Response $response): Response\n    {\n        $pageId        = $this->getParam($request, 'page_id', 0);\n        $pageHistoryId = $this->getParam($request, 'page_history_id', 0);\n        $pageComments  = $this->getParam($request, 'page_comments', '');\n\n        if ($pageId <= 0 || $pageHistoryId <= 0) {\n            return $this->error($response, 10101, '参数错误');\n        }\n\n        // 获取页面信息\n        $page = \\App\\Model\\Page::findById($pageId);\n        if (!$page) {\n            return $this->error($response, 10101, '页面不存在');\n        }\n\n        $itemId = (int) $page['item_id'];\n\n        // 获取登录用户（非严格模式，允许游客访问，但需要编辑权限）\n        $loginUser = [];\n        $this->requireLoginUser($request, $response, $loginUser, false);\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        // 检查编辑权限\n        if (!$this->checkItemEdit($uid, $itemId)) {\n            return $this->error($response, 10101, '您没有编辑权限');\n        }\n\n        // 更新历史版本备注\n        $ret = \\App\\Model\\PageHistory::updateComments($pageId, $pageHistoryId, $pageComments);\n\n        return $this->success($response, ['success' => $ret]);\n    }\n\n    /**\n     * 判断页面是否加了编辑锁（兼容旧接口 Api/Page/isLock）。\n     */\n    public function isLock(Request $request, Response $response): Response\n    {\n        $pageId = (int) $this->getParam($request, 'page_id', 0);\n        $itemId = (int) $this->getParam($request, 'item_id', 0);\n        $lock   = 0;\n        $exceed = 0;\n        $now    = time();\n\n        // 登录用户（非强制）\n        $loginUser = [];\n        $this->requireLoginUser($request, $response, $loginUser, false);\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        // 检查锁记录\n        $res = \\Illuminate\\Database\\Capsule\\Manager::table('page_lock')\n            ->where('page_id', $pageId)\n            ->where('page_id', '>', 0)\n            ->where('lock_to', '>', $now)\n            ->first();\n\n        if ($res) {\n            $lock = 1;\n        }\n\n        // 开源版无页面数量限制\n\n        $lockUid      = $res->lock_uid ?? '';\n        $lockUsername = $res->lock_username ?? '';\n        $isCurUser    = ($uid > 0 && $lockUid && $uid === (int) $lockUid) ? 1 : 0;\n\n        return $this->success($response, [\n            'lock'          => $lock,\n            'exceed'        => $exceed,\n            'lock_uid'      => $lockUid ?: '',\n            'lock_username' => $lockUsername ?: '',\n            'is_cur_user'   => $isCurUser,\n        ]);\n    }\n\n    /**\n     * 删除页面（兼容旧接口 Api/Page/delete）。\n     */\n    public function delete(Request $request, Response $response): Response\n    {\n        $pageId = (int) $this->getParam($request, 'page_id', 0);\n        if ($pageId <= 0) {\n            return $this->error($response, 10101, '页面不存在');\n        }\n\n        $page = \\App\\Model\\Page::findById($pageId);\n        if (!$page) {\n            return $this->error($response, 10101, '页面不存在');\n        }\n\n        $itemId = (int) ($page['item_id'] ?? 0);\n\n        // 登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        // 需要项目管理权限或页面作者本人\n        if (\n            !$this->checkItemManage($uid, $itemId) &&\n            $uid !== (int) ($page['author_uid'] ?? 0)\n        ) {\n            return $this->error($response, 10303, '您没有管理权限');\n        }\n\n        $ret = \\App\\Model\\Page::softDeletePage($pageId, $itemId, $uid, (string) ($loginUser['username'] ?? ''));\n\n        if ($ret) {\n            // 更新项目时间\n            DB::table('item')\n                ->where('item_id', $itemId)\n                ->update(['last_update_time' => time()]);\n\n            // 删除页面相关评论与反馈\n            DB::table('page_comment')->where('page_id', $pageId)->delete();\n            DB::table('page_feedback')->where('page_id', $pageId)->delete();\n\n            // 记录变更日志\n            \\App\\Model\\ItemChangeLog::addLog(\n                $uid,\n                $itemId,\n                'delete',\n                'page',\n                $pageId,\n                (string) ($page['page_title'] ?? '')\n            );\n\n            // 删除菜单与页面缓存\n            \\App\\Model\\Item::deleteCache($itemId);\n            \\App\\Model\\Page::deleteCache($pageId);\n\n            // 先返回成功，再异步触发 AI 索引删除\n            $result = $this->success($response, []);\n\n            // 使用 register_shutdown_function 在响应发送后异步触发 AI 索引删除\n            register_shutdown_function(function () use ($itemId, $pageId) {\n                // 在响应发送后执行，不会阻塞用户\n                try {\n                    // 检查 AI 知识库功能是否启用\n                    $itemAiConfig = \\App\\Model\\ItemAiConfig::getConfig($itemId);\n                    if (empty($itemAiConfig['enabled'])) {\n                        // AI 功能未启用，不触发索引更新\n                        return;\n                    }\n\n                    // 从全局配置获取 AI 服务地址和 Token\n                    $aiServiceUrl = \\App\\Model\\Options::get('ai_service_url', '');\n                    $aiServiceToken = \\App\\Model\\Options::get('ai_service_token', '');\n\n                    if (empty($aiServiceUrl) || empty($aiServiceToken)) {\n                        // AI 服务未配置，不触发索引更新\n                        return;\n                    }\n\n                    // 删除操作：触发整个项目的索引重建（异步）\n                    \\App\\Common\\Helper\\AiHelper::rebuild($itemId, $aiServiceUrl, $aiServiceToken);\n                } catch (\\Throwable $e) {\n                    // 索引更新失败不影响页面删除，只记录错误日志\n                    error_log(\"触发 AI 索引更新失败: item_id={$itemId}, page_id={$pageId}, action=delete, error=\" . $e->getMessage());\n                }\n            });\n\n            return $result;\n        }\n\n        return $this->error($response, 10101, '删除失败');\n    }\n\n    /**\n     * 上传图片（兼容旧接口 Api/Page/uploadImg，转发到 AttachmentController::uploadImg）。\n     */\n    public function uploadImg(Request $request, Response $response): Response\n    {\n        $controller = new \\App\\Api\\Controller\\AttachmentController(\n            $this->container ?? null,\n            $this->logger ?? null\n        );\n\n        return $controller->uploadImg($request, $response);\n    }\n\n    /**\n     * 上传附件（兼容旧接口 Api/Page/upload，转发到 AttachmentController::attachmentUpload）。\n     */\n    public function upload(Request $request, Response $response): Response\n    {\n        $controller = new \\App\\Api\\Controller\\AttachmentController(\n            $this->container ?? null,\n            $this->logger ?? null\n        );\n\n        return $controller->attachmentUpload($request, $response);\n    }\n\n    /**\n     * 获取页面上传文件列表（兼容旧接口 Api/Page/uploadList）。\n     */\n    public function uploadList(Request $request, Response $response): Response\n    {\n        $controller = new \\App\\Api\\Controller\\AttachmentController(\n            $this->container ?? null,\n            $this->logger ?? null\n        );\n\n        return $controller->pageAttachmentUploadList($request, $response);\n    }\n\n    /**\n     * 删除页面已上传文件（兼容旧接口 Api/Page/deleteUploadFile）。\n     */\n    public function deleteUploadFile(Request $request, Response $response): Response\n    {\n        $controller = new \\App\\Api\\Controller\\AttachmentController(\n            $this->container ?? null,\n            $this->logger ?? null\n        );\n\n        return $controller->deletePageUploadFile($request, $response);\n    }\n\n    /**\n     * 创建/删除单页链接（兼容旧接口 Api/Page/createSinglePage）。\n     */\n    public function createSinglePage(Request $request, Response $response): Response\n    {\n        $pageId           = (int) $this->getParam($request, 'page_id', 0);\n        $isCreateSingle   = $this->getParam($request, 'isCreateSiglePage', '');\n        $expireDays       = (int) $this->getParam($request, 'expire_days', 0);\n\n        if ($pageId <= 0) {\n            return $this->error($response, 10101, '页面不存在');\n        }\n\n        $page = \\App\\Model\\Page::findById($pageId);\n        if (!$page || (int) ($page['is_del'] ?? 0) === 1) {\n            return $this->error($response, 10101, '页面不存在');\n        }\n\n        $itemId = (int) ($page['item_id'] ?? 0);\n\n        // 登录用户（非强制）\n        $loginUser = [];\n        $this->requireLoginUser($request, $response, $loginUser, false);\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        if (!$this->checkItemEdit($uid, $itemId)) {\n            return $this->error($response, 10101, '您没有编辑权限');\n        }\n\n        // 先删除旧记录\n        DB::table('single_page')->where('page_id', $pageId)->delete();\n\n        // 计算过期时间（0 表示永久）\n        $expireTime = 0;\n        if ($expireDays > 0) {\n            $expireTime = time() + ($expireDays * 24 * 60 * 60);\n        }\n\n        // 按旧实现约定，仅当 isCreateSiglePage 为 'true' 时创建\n        if ((string) $isCreateSingle === 'true') {\n            $uniqueKey = md5(microtime(true) . rand() . 'showdoc_single_page_salt');\n            $data      = [\n                'unique_key'  => $uniqueKey,\n                'page_id'     => $pageId,\n                'expire_time' => $expireTime,\n            ];\n\n            DB::table('single_page')->insert($data);\n\n            return $this->success($response, $data);\n        }\n\n        return $this->success($response, []);\n    }\n\n    /**\n     * 通过唯一 key 获取页面详情（兼容旧接口 Api/Page/infoByKey）。\n     */\n    public function infoByKey(Request $request, Response $response): Response\n    {\n        $uniqueKey = (string) $this->getParam($request, 'unique_key', '');\n        if ($uniqueKey === '') {\n            return $this->error($response, 10101, '参数错误');\n        }\n\n        $singlePage = DB::table('single_page')\n            ->where('unique_key', $uniqueKey)\n            ->first();\n\n        if (!$singlePage) {\n            return $this->error($response, 10101, '该分享链接已过期或不存在');\n        }\n\n        $pageId = (int) ($singlePage->page_id ?? 0);\n\n        // 检查链接是否已过期\n        $expireTime = (int) ($singlePage->expire_time ?? 0);\n        if ($expireTime > 0 && $expireTime < time()) {\n            // 链接已过期，从数据库中删除记录\n            DB::table('single_page')\n                ->where('unique_key', $uniqueKey)\n                ->delete();\n            return $this->error($response, 10101, '该分享链接已过期');\n        }\n\n        $page = DB::table('page')\n            ->where('page_id', $pageId)\n            ->first();\n\n        if (!$page || (int) ($page->is_del ?? 0) === 1) {\n            sleep(1);\n            return $this->error($response, 10101, '页面不存在');\n        }\n\n        // 登录用户（非强制）\n        $loginUser = [];\n        $this->requireLoginUser($request, $response, $loginUser, false);\n\n        // 转换为数组格式\n        $page = (array) $page;\n\n        // 去掉 item_id 和 cat_id\n        unset($page['item_id'], $page['cat_id']);\n\n        // 格式化时间\n        $page['addtime'] = date('Y-m-d H:i:s', (int) ($page['addtime'] ?? time()));\n\n        // 附件数量\n        $page['attachment_count'] = DB::table('file_page')\n            ->where('page_id', $pageId)\n            ->count();\n\n        // 添加单页链接过期时间字段\n        $page['expire_time'] = $expireTime;\n\n        return $this->success($response, $page);\n    }\n\n    /**\n     * 同一目录下页面排序（兼容旧接口 Api/Page/sort）。\n     */\n    public function sort(Request $request, Response $response): Response\n    {\n        $pagesJson = (string) $this->getParam($request, 'pages', '');\n        $itemId    = (int) $this->getParam($request, 'item_id', 0);\n\n        if ($itemId <= 0 || $pagesJson === '') {\n            return $this->error($response, 10101, '参数错误');\n        }\n\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n        if (!$this->checkItemEdit($uid, $itemId)) {\n            return $this->error($response, 10101, '您没有编辑权限');\n        }\n\n        $dataArray = json_decode(htmlspecialchars_decode($pagesJson, ENT_QUOTES), true);\n        if (!is_array($dataArray) || empty($dataArray)) {\n            return $this->success($response, []);\n        }\n\n        foreach ($dataArray as $pageId => $sNumber) {\n            $pageId  = (int) $pageId;\n            $sNumber = (int) $sNumber;\n            if ($pageId <= 0) {\n                continue;\n            }\n\n            DB::table('page')\n                ->where('page_id', $pageId)\n                ->where('item_id', $itemId)\n                ->update(['s_number' => $sNumber]);\n\n            \\App\\Model\\Page::deleteCache($pageId);\n        }\n\n        \\App\\Model\\Item::deleteCache($itemId);\n\n        return $this->success($response, []);\n    }\n\n    /**\n     * 设置页面编辑锁（兼容旧接口 Api/Page/setLock）。\n     */\n    public function setLock(Request $request, Response $response): Response\n    {\n        $pageId = (int) $this->getParam($request, 'page_id', 0);\n        $lockTo = (int) $this->getParam(\n            $request,\n            'lock_to',\n            time() + 30 * 60 * 60\n        );\n        $itemId = (int) $this->getParam($request, 'item_id', 0);\n\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        if ($pageId <= 0 || $itemId <= 0) {\n            return $this->error($response, 10101, '参数错误');\n        }\n\n        if (!$this->checkItemEdit($uid, $itemId)) {\n            return $this->error($response, 10101, '您没有编辑权限');\n        }\n\n        $now = time();\n\n        // 清理过期锁\n        DB::table('page_lock')\n            ->where('lock_to', '<', $now)\n            ->delete();\n\n        // 如果存在其他用户的锁，拒绝\n        $row = DB::table('page_lock')\n            ->where('page_id', $pageId)\n            ->first();\n\n        if ($row && (int) ($row->lock_uid ?? 0) !== $uid) {\n            return $this->error($response, 10101, '该页面已被其他用户锁定');\n        }\n\n        // 删除当前页面的旧锁\n        DB::table('page_lock')\n            ->where('page_id', $pageId)\n            ->delete();\n\n        // 创建新锁\n        $id = DB::table('page_lock')->insertGetId([\n            'page_id'       => $pageId,\n            'lock_uid'      => $uid,\n            'lock_username' => (string) ($loginUser['username'] ?? ''),\n            'lock_to'       => $lockTo,\n            'addtime'       => time(),\n        ]);\n\n        return $this->success($response, ['id' => $id]);\n    }\n}\n"
  },
  {
    "path": "server/app/Api/Controller/PageFeedbackController.php",
    "content": "<?php\n\nnamespace App\\Api\\Controller;\n\nuse App\\Common\\BaseController;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\nuse App\\Model\\PageFeedback;\nuse App\\Model\\Page;\nuse App\\Model\\Item;\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\n/**\n * 页面反馈相关 Api（新架构）。\n */\nclass PageFeedbackController extends BaseController\n{\n    /**\n     * 获取反馈统计（兼容旧接口 Api/PageFeedback/getStat）。\n     */\n    public function getStat(Request $request, Response $response): Response\n    {\n        // 获取登录用户（非必需，不强制登录）\n        $loginUser = [];\n        $this->requireLoginUser($request, $response, $loginUser, false);\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        $pageId = $this->getParam($request, 'page_id', 0);\n        $clientId = $this->getParam($request, 'client_id', '');\n\n        if ($pageId <= 0) {\n            return $this->error($response, 10100, '缺少page_id参数');\n        }\n\n        // 获取页面信息\n        $page = Page::findById($pageId);\n        if (!$page) {\n            return $this->error($response, 10101, '页面不存在');\n        }\n\n        $itemId = (int) ($page['item_id'] ?? 0);\n\n        // 检查访问权限\n        if (!$this->checkItemVisit($uid, $itemId)) {\n            return $this->error($response, 10303, '没有权限');\n        }\n\n        // 检查项目是否开启反馈功能\n        $item = Item::findById($itemId);\n        if (!$item || (int) ($item->item_type ?? 0) !== 1) {\n            // 非常规项目或未开启，返回空统计\n            return $this->success($response, [\n                'helpful_count'  => 0,\n                'unhelpful_count' => 0,\n                'user_feedback'  => 0,\n            ]);\n        }\n\n        if (empty($item->allow_feedback)) {\n            // 未开启反馈功能，返回空统计\n            return $this->success($response, [\n                'helpful_count'  => 0,\n                'unhelpful_count' => 0,\n                'user_feedback'  => 0,\n            ]);\n        }\n\n        // 统计数量\n        $helpfulCount = PageFeedback::countByType($pageId, 1);\n        $unhelpfulCount = PageFeedback::countByType($pageId, 2);\n\n        // 获取当前用户/浏览器的反馈\n        $userFeedback = 0;\n        if ($uid > 0) {\n            // 登录用户\n            $feedback = PageFeedback::findByUid($pageId, $uid);\n            if ($feedback) {\n                $userFeedback = (int) ($feedback->feedback_type ?? 0);\n            }\n        } elseif (!empty($clientId)) {\n            // 游客\n            $feedback = PageFeedback::findByClientId($pageId, $clientId);\n            if ($feedback) {\n                $userFeedback = (int) ($feedback->feedback_type ?? 0);\n            }\n        }\n\n        return $this->success($response, [\n            'helpful_count'  => $helpfulCount,\n            'unhelpful_count' => $unhelpfulCount,\n            'user_feedback'  => $userFeedback,\n        ]);\n    }\n\n    /**\n     * 提交/修改反馈（兼容旧接口 Api/PageFeedback/submit）。\n     */\n    public function submit(Request $request, Response $response): Response\n    {\n        // 获取登录用户（非必需，不强制登录）\n        $loginUser = [];\n        $this->requireLoginUser($request, $response, $loginUser, false);\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        $pageId = $this->getParam($request, 'page_id', 0);\n        $feedbackType = $this->getParam($request, 'feedback_type', 0);\n        $clientId = $this->getParam($request, 'client_id', '');\n\n        if ($pageId <= 0) {\n            return $this->error($response, 10100, '缺少page_id参数');\n        }\n\n        // 兼容新前端：feedback_type = 0 表示“取消反馈”，1=有帮助，2=无帮助\n        if (!in_array($feedbackType, [0, 1, 2], true)) {\n            return $this->error($response, 10100, 'feedback_type参数错误，必须为0、1或2');\n        }\n\n        // 获取页面信息\n        $page = Page::findById($pageId);\n        if (!$page) {\n            return $this->error($response, 10101, '页面不存在');\n        }\n\n        $itemId = (int) ($page['item_id'] ?? 0);\n\n        // 检查访问权限\n        if (!$this->checkItemVisit($uid, $itemId)) {\n            return $this->error($response, 10303, '没有权限');\n        }\n\n        // 检查项目是否开启反馈功能\n        $item = Item::findById($itemId);\n        if (!$item || (int) ($item->item_type ?? 0) !== 1) {\n            return $this->error($response, 10100, '此项目类型不支持反馈功能');\n        }\n\n        if (empty($item->allow_feedback)) {\n            return $this->error($response, 10100, '项目未开启反馈功能');\n        }\n\n        // 游客必须提供client_id\n        if ($uid === 0 && empty($clientId)) {\n            return $this->error($response, 10100, '游客必须提供client_id参数');\n        }\n\n        // 查询现有反馈\n        $existingFeedback = null;\n        if ($uid > 0) {\n            $existingFeedback = PageFeedback::findByUid($pageId, $uid);\n        } else {\n            $existingFeedback = PageFeedback::findByClientId($pageId, $clientId);\n        }\n\n        if ($existingFeedback) {\n            // 已有反馈记录\n            $existingType = (int) ($existingFeedback->feedback_type ?? 0);\n            $feedbackId   = (int) ($existingFeedback->feedback_id ?? 0);\n\n            if ($feedbackType === 0) {\n                // 前端显式请求“取消反馈”\n                PageFeedback::delete($feedbackId);\n            } elseif ($existingType === $feedbackType) {\n                // 相同类型：按旧逻辑也视为“取消反馈”\n                PageFeedback::delete($feedbackId);\n                // 同时将 feedbackType 标记为 0，方便前端更新 userFeedback 状态\n                $feedbackType = 0;\n            } else {\n                // 不同类型：更新反馈\n                PageFeedback::update($feedbackId, [\n                    'feedback_type' => $feedbackType,\n                    'addtime'       => time(),\n                ]);\n            }\n        } else {\n            if ($feedbackType !== 0) {\n                // 新增反馈（feedback_type 为 1 或 2 才需要新增，0 表示本来就没有反馈，无需写库）\n                $feedbackData = [\n                    'page_id'       => $pageId,\n                    'item_id'       => $itemId,\n                    // 与旧版保持一致：游客 uid 记为 0，而不是 NULL，避免 SQLite NOT NULL 约束问题\n                    'uid'           => $uid,\n                    'client_id'     => $uid > 0 ? null : $clientId,\n                    'feedback_type' => $feedbackType,\n                    'addtime'       => time(),\n                ];\n\n                PageFeedback::add($feedbackData);\n            }\n        }\n\n        // 重新统计并返回\n        $helpfulCount = PageFeedback::countByType($pageId, 1);\n        $unhelpfulCount = PageFeedback::countByType($pageId, 2);\n\n        return $this->success($response, [\n            'message'       => '感谢您的反馈',\n            'helpful_count' => $helpfulCount,\n            'unhelpful_count' => $unhelpfulCount,\n            'user_feedback' => $feedbackType,\n        ]);\n    }\n}\n"
  },
  {
    "path": "server/app/Api/Controller/ParamDescLibController.php",
    "content": "<?php\n\nnamespace App\\Api\\Controller;\n\nuse App\\Common\\BaseController;\nuse App\\Model\\ParameterDescriptionEntry;\nuse App\\Common\\Helper\\Security;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\n\nclass ParamDescLibController extends BaseController\n{\n    /**\n     * 查询参数描述库条目\n     */\n    public function getEntries(Request $request, Response $response): Response\n    {\n        return $this->_getEntries($request, $response);\n    }\n\n    /**\n     * 创建参数描述库条目\n     */\n    public function addEntry(Request $request, Response $response): Response\n    {\n        return $this->_createEntry($request, $response);\n    }\n\n    /**\n     * 批量删除条目\n     */\n    public function deleteEntries(Request $request, Response $response): Response\n    {\n        return $this->_deleteEntries($request, $response);\n    }\n\n    /**\n     * 删除单个条目\n     */\n    public function deleteEntry(Request $request, Response $response): Response\n    {\n        return $this->_deleteEntry($request, $response);\n    }\n\n    /**\n     * 更新条目\n     */\n    public function updateEntry(Request $request, Response $response): Response\n    {\n        return $this->_updateEntry($request, $response);\n    }\n\n    /**\n     * 添加临时条目\n     */\n    public function addTempEntry(Request $request, Response $response): Response\n    {\n        return $this->temp($request, $response);\n    }\n\n    /**\n     * 临时条目转永久\n     */\n    public function promoteTemp(Request $request, Response $response): Response\n    {\n        return $this->_promoteTemp($request, $response);\n    }\n\n    /**\n     * 确认导入\n     */\n    public function confirmImport(Request $request, Response $response): Response\n    {\n        return $this->_confirmImport($request, $response);\n    }\n\n    /**\n     * 批量添加条目\n     */\n    public function addBatchEntries(Request $request, Response $response): Response\n    {\n        return $this->_addBatchEntries($request, $response);\n    }\n\n    /**\n     * 更新使用次数\n     */\n    public function updateUsage(Request $request, Response $response): Response\n    {\n        return $this->_updateUsage($request, $response);\n    }\n\n    /**\n     * 批量保存参数描述库条目（覆盖保存）\n     */\n    public function batchSave(Request $request, Response $response): Response\n    {\n        return $this->_batchSave($request, $response);\n    }\n\n    /**\n     * 获取统计信息\n     */\n    public function stats(Request $request, Response $response): Response\n    {\n        $user = [];\n        if ($error = $this->requireLoginUser($request, $response, $user)) {\n            return $error;\n        }\n\n        $uid = (int) ($user['uid'] ?? 0);\n        $itemId = $this->getParam($request, 'itemId', 0);\n\n        if (!$itemId) {\n            return $this->error($response, 10001, '缺少项目ID');\n        }\n\n        if (!$this->checkItemEdit($uid, $itemId)) {\n            return $this->error($response, 10303, '您没有编辑权限');\n        }\n\n        // 总数统计\n        $totalCount = ParameterDescriptionEntry::count(['item_id' => $itemId]);\n        $permanentCount = ParameterDescriptionEntry::count(['item_id' => $itemId, 'status' => 'permanent']);\n        $tempCount = ParameterDescriptionEntry::count(['item_id' => $itemId, 'status' => 'temp']);\n\n        // Top使用字段\n        $topFields = ParameterDescriptionEntry::getTopFields($itemId, 10);\n\n        $topFieldsFormatted = [];\n        foreach ($topFields as $field) {\n            $topFieldsFormatted[] = [\n                'name' => $field->name,\n                'count' => (int) $field->usage_count\n            ];\n        }\n\n        return $this->success($response, [\n            'totalCount' => $totalCount,\n            'permanentCount' => $permanentCount,\n            'tempCount' => $tempCount,\n            'coverageRate' => $totalCount > 0 ? round($permanentCount / $totalCount * 100, 2) : 0,\n            'hitRate' => 0, // 需要根据实际使用情况计算\n            'topFields' => $topFieldsFormatted\n        ]);\n    }\n\n    /**\n     * 导入数据\n     */\n    public function import(Request $request, Response $response): Response\n    {\n        $user = [];\n        if ($error = $this->requireLoginUser($request, $response, $user)) {\n            return $error;\n        }\n\n        $uid = (int) ($user['uid'] ?? 0);\n        $itemId = $this->getParam($request, 'itemId', 0);\n        $format = $this->getParam($request, 'format', '');\n        $rawText = $this->getParam($request, 'rawText', '');\n\n        if (!$itemId || !$format || !$rawText) {\n            return $this->error($response, 10001, '缺少必要参数');\n        }\n\n        if (!$this->checkItemEdit($uid, $itemId)) {\n            return $this->error($response, 10303, '您没有编辑权限');\n        }\n\n        $parsed = $this->parseImportData($format, $rawText);\n        if (!$parsed) {\n            return $this->error($response, 10001, '数据格式错误');\n        }\n\n        $newEntries = [];\n        $duplicatedEntries = [];\n\n        foreach ($parsed as $data) {\n            // 检查是否已存在\n            $existing = ParameterDescriptionEntry::findExisting($itemId, $data['name'], $data['type']);\n\n            $entry = [\n                'id' => $this->generateId(),\n                'itemId' => $itemId,\n                'name' => $data['name'],\n                'type' => $data['type'],\n                'description' => $data['description'],\n                'example' => $data['example'] ?? '',\n                'source' => 'manual',\n                'status' => 'permanent',\n                'usageCount' => 0,\n                'qualityScore' => $this->calculateQualityScore($data),\n                'createdBy' => $uid,\n                'updatedAt' => time()\n            ];\n\n            if ($existing) {\n                $duplicatedEntries[] = $entry;\n            } else {\n                $newEntries[] = $entry;\n            }\n        }\n\n        return $this->success($response, [\n            'new' => $newEntries,\n            'duplicated' => $duplicatedEntries\n        ]);\n    }\n\n    /**\n     * 导出数据\n     */\n    public function export(Request $request, Response $response): Response\n    {\n        $user = [];\n        if ($error = $this->requireLoginUser($request, $response, $user)) {\n            return $error;\n        }\n\n        $uid = (int) ($user['uid'] ?? 0);\n        $itemId = $this->getParam($request, 'itemId', 0);\n        $format = $this->getParam($request, 'format', 'json');\n\n        if (!$itemId) {\n            return $this->error($response, 10001, '缺少项目ID');\n        }\n\n        if (!$this->checkItemEdit($uid, $itemId)) {\n            return $this->error($response, 10303, '您没有编辑权限');\n        }\n\n        $result = ParameterDescriptionEntry::getList(['item_id' => $itemId], 1, 10000, 'name', 'ASC');\n        $entries = $result['data'];\n\n        if ($format === 'csv') {\n            $csv = \"字段名,类型,描述,示例值,使用次数\\n\";\n            foreach ($entries as $entry) {\n                $entry = (array) $entry;\n                $csv .= \"\\\"{$entry['name']}\\\",\\\"{$entry['type']}\\\",\\\"{$entry['description']}\\\",\\\"{$entry['example']}\\\",{$entry['usage_count']}\\n\";\n            }\n            return $this->success($response, $csv);\n        } else {\n            // JSON格式\n            $exportData = [];\n            foreach ($entries as $entry) {\n                $entry = (array) $entry;\n                $exportData[] = [\n                    'name' => $entry['name'],\n                    'type' => $entry['type'],\n                    'description' => $entry['description'],\n                    'example' => $entry['example'],\n                    'aliases' => json_decode($entry['aliases'] ?? '[]', true),\n                    'tags' => json_decode($entry['tags'] ?? '[]', true),\n                    'usageCount' => (int) ($entry['usage_count'] ?? 0)\n                ];\n            }\n            return $this->success($response, json_encode($exportData, JSON_UNESCAPED_UNICODE));\n        }\n    }\n\n    /**\n     * 批量保存参数描述库条目（覆盖保存）\n     */\n    private function _batchSave(Request $request, Response $response): Response\n    {\n        $user = [];\n        if ($error = $this->requireLoginUser($request, $response, $user)) {\n            return $error;\n        }\n\n        $uid = (int) ($user['uid'] ?? 0);\n        $itemId = $this->getParam($request, 'itemId', 0);\n        $entries = $this->getParam($request, 'entries');\n\n        // 兼容前端以 JSON 字符串提交 entries 的情况\n        if (is_string($entries)) {\n            $decoded = json_decode($entries, true);\n            if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) {\n                $entries = $decoded;\n            }\n        }\n\n        if (!$itemId) {\n            return $this->error($response, 10001, '缺少项目ID');\n        }\n\n        if (!$this->checkItemEdit($uid, $itemId)) {\n            return $this->error($response, 10303, '您没有编辑权限');\n        }\n\n        if (empty($entries)) {\n            return $this->error($response, 10001, '没有要保存的条目');\n        }\n\n        try {\n            // 1. 删除该项目下所有永久条目\n            \\Illuminate\\Database\\Capsule\\Manager::table('parameter_description_entry')\n                ->where('item_id', $itemId)\n                ->where('status', 'permanent')\n                ->delete();\n\n            // 2. 批量创建新的永久条目\n            $createdEntries = [];\n            foreach ($entries as $entry) {\n                // 容错：确保是数组\n                if (!is_array($entry)) {\n                    continue;\n                }\n                // 兼容中文状态值，默认按永久处理\n                $statusVal = $entry['status'] ?? 'permanent';\n                if ($statusVal === '永久') {\n                    $statusVal = 'permanent';\n                }\n                // 只保存永久条目，临时条目由前端内存管理\n                if ($statusVal === 'permanent') {\n                    // 计算质量评分\n                    $qualityScore = $this->calculateQualityScore([\n                        'description' => $entry['description'] ?? '',\n                        'example' => $entry['example'] ?? '',\n                        'enumValues' => $entry['enumValues'] ?? [],\n                        'defaultValue' => $entry['defaultValue'] ?? '',\n                        'usageCount' => $entry['usageCount'] ?? 0\n                    ]);\n\n                    $data = [\n                        'id' => $this->generateId(),\n                        'item_id' => $itemId,\n                        'name' => $entry['name'],\n                        'type' => $entry['type'],\n                        'description' => $entry['description'] ?? '',\n                        'example' => $entry['example'] ?? '',\n                        'default_value' => $entry['defaultValue'] ?? '',\n                        'aliases' => json_encode($entry['aliases'] ?? []),\n                        'tags' => json_encode($entry['tags'] ?? []),\n                        'path' => $entry['path'] ?? '',\n                        'source' => $entry['source'] ?? 'manual',\n                        'status' => 'permanent',\n                        'usage_count' => $entry['usageCount'] ?? 0,\n                        'quality_score' => $qualityScore,\n                        'created_by' => $uid,\n                        'created_at' => date('Y-m-d H:i:s'),\n                        'updated_at' => date('Y-m-d H:i:s')\n                    ];\n\n                    if (!empty($entry['enumValues']) && is_array($entry['enumValues'])) {\n                        $data['enum_values'] = json_encode($entry['enumValues']);\n                    }\n\n                    $id = ParameterDescriptionEntry::add($data);\n                    if ($id) {\n                        $createdEntry = ParameterDescriptionEntry::findById($data['id']);\n                        if ($createdEntry) {\n                            $createdEntries[] = $this->convertEntryFields((array) $createdEntry);\n                        }\n                    }\n                }\n            }\n\n            return $this->success($response, $createdEntries);\n        } catch (\\Exception $e) {\n            return $this->error($response, 10001, '批量保存失败: ' . $e->getMessage());\n        }\n    }\n\n    /**\n     * 获取参数描述库条目列表\n     */\n    private function _getEntries(Request $request, Response $response): Response\n    {\n        $user = [];\n        if ($error = $this->requireLoginUser($request, $response, $user)) {\n            return $error;\n        }\n\n        $uid = (int) ($user['uid'] ?? 0);\n        $itemId = $this->getParam($request, 'itemId', 0);\n        $keyword = $this->getParam($request, 'keyword', '');\n        $status = $this->getParam($request, 'status', '');\n        $name = $this->getParam($request, 'name', '');\n        $type = $this->getParam($request, 'type', '');\n        $tag = $this->getParam($request, 'tag', '');\n        $page = $this->getParam($request, 'page', 1);\n        $pageSize = $this->getParam($request, 'pageSize', 20);\n\n        if (!$itemId) {\n            return $this->error($response, 10001, '缺少项目ID');\n        }\n\n        if (!$this->checkItemEdit($uid, $itemId)) {\n            return $this->error($response, 10303, '您没有编辑权限');\n        }\n\n        $conditions = ['item_id' => $itemId];\n\n        // 构建查询\n        $query = \\Illuminate\\Database\\Capsule\\Manager::table('parameter_description_entry')\n            ->where('item_id', $itemId);\n\n        // 添加搜索条件\n        if ($keyword !== '') {\n            $like = Security::safeLike($keyword);\n            $query->where(function ($q) use ($like) {\n                $q->where('name', 'LIKE', \"%{$like}%\")\n                    ->orWhere('description', 'LIKE', \"%{$like}%\");\n            });\n        }\n\n        if ($status !== '') {\n            $query->where('status', $status);\n        }\n\n        if ($name !== '') {\n            $query->where('name', $name);\n        }\n\n        if ($type !== '') {\n            $query->where('type', $type);\n        }\n\n        if ($tag !== '') {\n            // JSON 包含特定标签（以双引号包裹）\n            $tgLike = Security::safeLike('\"' . $tag . '\"');\n            $query->where('tags', 'LIKE', \"%{$tgLike}%\");\n        }\n\n        // 计算总数\n        $total = $query->count();\n\n        // 获取分页数据\n        $offset = ($page - 1) * $pageSize;\n        $entries = $query\n            ->orderBy('quality_score', 'DESC')\n            ->orderBy('usage_count', 'DESC')\n            ->orderBy('updated_at', 'DESC')\n            ->offset($offset)\n            ->limit($pageSize)\n            ->get()\n            ->toArray();\n\n        // 处理JSON字段并转换字段名为前端期望的驼峰格式\n        $formattedEntries = [];\n        foreach ($entries as $entry) {\n            $formattedEntries[] = $this->convertEntryFields((array) $entry);\n        }\n\n        return $this->success($response, [\n            'data' => $formattedEntries,\n            'total' => $total,\n            'page' => $page,\n            'pageSize' => $pageSize\n        ]);\n    }\n\n    /**\n     * 创建参数描述库条目\n     */\n    private function _createEntry(Request $request, Response $response): Response\n    {\n        $user = [];\n        if ($error = $this->requireLoginUser($request, $response, $user)) {\n            return $error;\n        }\n\n        $uid = (int) ($user['uid'] ?? 0);\n        $itemId = $this->getParam($request, 'itemId', 0);\n        $name = $this->getParam($request, 'name', '');\n        $type = $this->getParam($request, 'type', 'string');\n        $description = $this->getParam($request, 'description', '');\n        $example = $this->getParam($request, 'example', '');\n        $enumValues = $this->getParam($request, 'enumValues', []);\n        $defaultValue = $this->getParam($request, 'defaultValue', '');\n        $aliases = $this->getParam($request, 'aliases', []);\n        $tags = $this->getParam($request, 'tags', []);\n        $path = $this->getParam($request, 'path', '');\n        $source = $this->getParam($request, 'source', 'manual');\n        $status = $this->getParam($request, 'status', 'permanent');\n\n        if (!$itemId || !$name || !$description) {\n            return $this->error($response, 10001, '缺少必要参数');\n        }\n\n        if (!$this->checkItemEdit($uid, $itemId)) {\n            return $this->error($response, 10303, '您没有编辑权限');\n        }\n\n        // 检查是否已存在相同的条目\n        $existing = ParameterDescriptionEntry::findExisting($itemId, $name, $type);\n\n        if ($existing) {\n            return $this->error($response, 10001, '已存在相同的字段名和类型');\n        }\n\n        // 计算质量评分\n        $qualityScore = $this->calculateQualityScore([\n            'description' => $description,\n            'example' => $example,\n            'enumValues' => $enumValues,\n            'defaultValue' => $defaultValue,\n            'usageCount' => 0\n        ]);\n\n        $data = [\n            'id' => $this->generateId(),\n            'item_id' => $itemId,\n            'name' => $name,\n            'type' => $type,\n            'description' => $description,\n            'example' => $example,\n            'default_value' => $defaultValue,\n            'aliases' => json_encode($aliases),\n            'tags' => json_encode($tags),\n            'path' => $path,\n            'source' => $source,\n            'status' => $status,\n            'usage_count' => 0,\n            'quality_score' => $qualityScore,\n            'created_by' => $uid,\n            'created_at' => date('Y-m-d H:i:s'),\n            'updated_at' => date('Y-m-d H:i:s')\n        ];\n\n        if (!empty($enumValues)) {\n            $data['enum_values'] = json_encode($enumValues);\n        }\n\n        $id = ParameterDescriptionEntry::add($data);\n\n        if ($id) {\n            // 返回创建的条目\n            $entry = ParameterDescriptionEntry::findById($data['id']);\n\n            // 字段转换和处理\n            $entry = $this->convertEntryFields((array) $entry);\n\n            return $this->success($response, $entry);\n        } else {\n            return $this->error($response, 10001, '创建失败');\n        }\n    }\n\n    /**\n     * 批量删除条目\n     */\n    private function _deleteEntries(Request $request, Response $response): Response\n    {\n        $user = [];\n        if ($error = $this->requireLoginUser($request, $response, $user)) {\n            return $error;\n        }\n\n        $uid = (int) ($user['uid'] ?? 0);\n        $ids = $this->getParam($request, 'ids', '');\n\n        // 处理前端传来的逗号分隔字符串\n        if (is_string($ids)) {\n            $ids = array_filter(explode(',', $ids));\n        } elseif (!is_array($ids)) {\n            $ids = [];\n        }\n\n        if (empty($ids)) {\n            return $this->error($response, 10001, '缺少要删除的ID');\n        }\n\n        // 检查权限 - 获取第一个条目的item_id进行权限验证\n        $firstEntry = ParameterDescriptionEntry::findById($ids[0]);\n        if (!$firstEntry) {\n            return $this->error($response, 10001, '条目不存在');\n        }\n\n        if (!$this->checkItemEdit($uid, $firstEntry->item_id)) {\n            return $this->error($response, 10303, '您没有编辑权限');\n        }\n\n        // 构建删除条件\n        $result = ParameterDescriptionEntry::delete($ids);\n\n        if ($result > 0) {\n            return $this->success($response, ['deleted' => count($ids)]);\n        } else {\n            return $this->error($response, 10001, '删除失败');\n        }\n    }\n\n    /**\n     * 更新单个条目\n     */\n    private function _updateEntry(Request $request, Response $response): Response\n    {\n        $user = [];\n        if ($error = $this->requireLoginUser($request, $response, $user)) {\n            return $error;\n        }\n\n        $uid = (int) ($user['uid'] ?? 0);\n        $id = $this->getParam($request, 'id', '');\n\n        if (!$id) {\n            return $this->error($response, 10001, '缺少条目ID');\n        }\n\n        // 检查条目是否存在\n        $entry = ParameterDescriptionEntry::findById($id);\n        if (!$entry) {\n            return $this->error($response, 10001, '条目不存在');\n        }\n\n        if (!$this->checkItemEdit($uid, $entry->item_id)) {\n            return $this->error($response, 10303, '您没有编辑权限');\n        }\n\n        // 获取更新数据\n        $updateData = [];\n\n        $fields = ['name', 'type', 'description', 'example', 'defaultValue', 'path', 'source', 'status'];\n        foreach ($fields as $field) {\n            $value = $this->getParam($request, $field);\n            if ($value !== null) {\n                if ($field === 'defaultValue') {\n                    $updateData['default_value'] = $value;\n                } else {\n                    $updateData[$field] = $value;\n                }\n            }\n        }\n\n        // 处理数组字段\n        $aliases = $this->getParam($request, 'aliases');\n        if ($aliases !== null) {\n            $updateData['aliases'] = json_encode($aliases);\n        }\n\n        $tags = $this->getParam($request, 'tags');\n        if ($tags !== null) {\n            $updateData['tags'] = json_encode($tags);\n        }\n\n        $enumValues = $this->getParam($request, 'enumValues');\n        if ($enumValues !== null) {\n            $updateData['enum_values'] = json_encode($enumValues);\n        }\n\n        if (!empty($updateData)) {\n            $updateData['updated_at'] = date('Y-m-d H:i:s');\n\n            // 重新计算质量评分\n            if (isset($updateData['description']) || isset($updateData['example']) || isset($updateData['enum_values']) || isset($updateData['default_value'])) {\n                $entryArray = (array) $entry;\n                $mergedData = array_merge($entryArray, $updateData);\n                $mergedData['enumValues'] = isset($updateData['enum_values']) ? json_decode($updateData['enum_values'], true) : json_decode($entryArray['enum_values'] ?? '[]', true);\n                $updateData['quality_score'] = $this->calculateQualityScore($mergedData);\n            }\n\n            $result = ParameterDescriptionEntry::update($id, $updateData);\n\n            if ($result !== false) {\n                // 返回更新后的条目\n                $updatedEntry = ParameterDescriptionEntry::findById($id);\n\n                // 字段转换和处理\n                $updatedEntry = $this->convertEntryFields((array) $updatedEntry);\n\n                return $this->success($response, $updatedEntry);\n            } else {\n                return $this->error($response, 10001, '更新失败');\n            }\n        } else {\n            return $this->error($response, 10001, '没有要更新的数据');\n        }\n    }\n\n    /**\n     * 删除单个条目\n     */\n    private function _deleteEntry(Request $request, Response $response): Response\n    {\n        $user = [];\n        if ($error = $this->requireLoginUser($request, $response, $user)) {\n            return $error;\n        }\n\n        $uid = (int) ($user['uid'] ?? 0);\n        $id = $this->getParam($request, 'id', '');\n\n        if (!$id) {\n            return $this->error($response, 10001, '缺少条目ID');\n        }\n\n        // 检查条目是否存在\n        $entry = ParameterDescriptionEntry::findById($id);\n        if (!$entry) {\n            return $this->error($response, 10001, '条目不存在');\n        }\n\n        if (!$this->checkItemEdit($uid, $entry->item_id)) {\n            return $this->error($response, 10303, '您没有编辑权限');\n        }\n\n        $result = ParameterDescriptionEntry::delete($id);\n\n        if ($result > 0) {\n            return $this->success($response, ['deleted' => 1]);\n        } else {\n            return $this->error($response, 10001, '删除失败');\n        }\n    }\n\n    /**\n     * 创建临时条目\n     */\n    public function temp(Request $request, Response $response): Response\n    {\n        // 临时设置 status 为 temp\n        $parsedBody = $request->getParsedBody() ?: [];\n        $parsedBody['status'] = 'temp';\n        $request = $request->withParsedBody($parsedBody);\n        return $this->_createEntry($request, $response);\n    }\n\n    /**\n     * 临时条目转永久\n     */\n    private function _promoteTemp(Request $request, Response $response): Response\n    {\n        $user = [];\n        if ($error = $this->requireLoginUser($request, $response, $user)) {\n            return $error;\n        }\n\n        $uid = (int) ($user['uid'] ?? 0);\n        $ids = $this->getParam($request, 'ids', '');\n\n        // 处理前端传来的逗号分隔字符串\n        if (is_string($ids)) {\n            $ids = array_filter(explode(',', $ids));\n        } elseif (!is_array($ids)) {\n            $ids = [];\n        }\n\n        if (empty($ids)) {\n            return $this->error($response, 10001, '缺少要转换的ID');\n        }\n\n        // 检查权限\n        $firstEntry = ParameterDescriptionEntry::findById($ids[0]);\n        if (!$firstEntry) {\n            return $this->error($response, 10001, '条目不存在');\n        }\n\n        if (!$this->checkItemEdit($uid, $firstEntry->item_id)) {\n            return $this->error($response, 10303, '您没有编辑权限');\n        }\n\n        $updated = 0;\n        foreach ($ids as $entryId) {\n            $result = ParameterDescriptionEntry::update($entryId, [\n                'status' => 'permanent',\n                'updated_at' => date('Y-m-d H:i:s')\n            ]);\n            if ($result > 0) {\n                $updated++;\n            }\n        }\n\n        if ($updated > 0) {\n            return $this->success($response, ['promoted' => $updated]);\n        } else {\n            return $this->error($response, 10001, '转换失败');\n        }\n    }\n\n    /**\n     * 批量添加条目\n     */\n    private function _addBatchEntries(Request $request, Response $response): Response\n    {\n        $user = [];\n        if ($error = $this->requireLoginUser($request, $response, $user)) {\n            return $error;\n        }\n\n        $uid = (int) ($user['uid'] ?? 0);\n        $entries = $this->getParam($request, 'entries', []);\n\n        if (empty($entries)) {\n            return $this->error($response, 10001, '没有要添加的条目');\n        }\n\n        $results = [];\n        foreach ($entries as $entry) {\n            // 检查权限\n            if (!$this->checkItemEdit($uid, $entry['itemId'] ?? 0)) {\n                continue;\n            }\n\n            $data = [\n                'id' => $this->generateId(),\n                'item_id' => $entry['itemId'],\n                'name' => $entry['name'],\n                'type' => $entry['type'],\n                'description' => $entry['description'] ?? '',\n                'example' => $entry['example'] ?? '',\n                'default_value' => $entry['defaultValue'] ?? '',\n                'source' => $entry['source'] ?? 'manual',\n                'status' => $entry['status'] ?? 'permanent',\n                'usage_count' => 0,\n                'quality_score' => $entry['qualityScore'] ?? 0,\n                'created_by' => $uid,\n                'created_at' => date('Y-m-d H:i:s'),\n                'updated_at' => date('Y-m-d H:i:s')\n            ];\n\n            $id = ParameterDescriptionEntry::add($data);\n            if ($id) {\n                $entryObj = ParameterDescriptionEntry::findById($data['id']);\n                if ($entryObj) {\n                    $results[] = $this->convertEntryFields((array) $entryObj);\n                }\n            }\n        }\n\n        return $this->success($response, $results);\n    }\n\n    /**\n     * 确认导入\n     */\n    private function _confirmImport(Request $request, Response $response): Response\n    {\n        return $this->_addBatchEntries($request, $response);\n    }\n\n    /**\n     * 更新使用次数\n     */\n    private function _updateUsage(Request $request, Response $response): Response\n    {\n        $user = [];\n        if ($error = $this->requireLoginUser($request, $response, $user)) {\n            return $error;\n        }\n\n        $uid = (int) ($user['uid'] ?? 0);\n        $id = $this->getParam($request, 'id', '');\n        $ids = $this->getParam($request, 'ids', '');\n\n        if ($id) {\n            $ids = [$id];\n        } elseif ($ids) {\n            // 处理前端传来的逗号分隔字符串\n            if (is_string($ids)) {\n                $ids = array_filter(explode(',', $ids));\n            } elseif (!is_array($ids)) {\n                $ids = [];\n            }\n        } else {\n            $ids = [];\n        }\n\n        if (empty($ids)) {\n            return $this->error($response, 10001, '缺少要更新的ID');\n        }\n\n        // 检查权限 - 检查第一个存在的条目来验证权限\n        $firstValidEntry = null;\n        foreach ($ids as $entryId) {\n            $entry = ParameterDescriptionEntry::findById($entryId);\n            if ($entry) {\n                $firstValidEntry = $entry;\n                break;\n            }\n        }\n\n        if (!$firstValidEntry) {\n            return $this->error($response, 10001, '没有找到有效的条目');\n        }\n\n        if (!$this->checkItemEdit($uid, $firstValidEntry->item_id)) {\n            return $this->error($response, 10303, '您没有编辑权限');\n        }\n\n        $updated = 0;\n        $notFound = [];\n\n        foreach ($ids as $entryId) {\n            $entry = ParameterDescriptionEntry::findById($entryId);\n            if ($entry) {\n                // 验证该条目是否属于同一项目（安全检查）\n                if ($entry->item_id != $firstValidEntry->item_id) {\n                    continue; // 跳过不同项目的条目\n                }\n\n                $newUsageCount = $entry->usage_count + 1;\n                $entryArray = (array) $entry;\n                $newQualityScore = $this->calculateQualityScore(array_merge($entryArray, ['usageCount' => $newUsageCount]));\n\n                $result = ParameterDescriptionEntry::update($entryId, [\n                    'usage_count' => $newUsageCount,\n                    'quality_score' => $newQualityScore,\n                    'updated_at' => date('Y-m-d H:i:s')\n                ]);\n\n                if ($result > 0) {\n                    $updated++;\n                }\n            } else {\n                $notFound[] = $entryId;\n            }\n        }\n\n        $result = ['updated' => $updated];\n        if (!empty($notFound)) {\n            $result['notFound'] = $notFound;\n        }\n\n        return $this->success($response, $result);\n    }\n\n    /**\n     * 解析导入数据\n     */\n    private function parseImportData(string $format, string $rawText): ?array\n    {\n        switch ($format) {\n            case 'kv':\n                return $this->parseKeyValue($rawText);\n            case 'json':\n                return $this->parseJson($rawText);\n            case 'ddl':\n                return $this->parseDDL($rawText);\n            default:\n                return null;\n        }\n    }\n\n    /**\n     * 解析键值对格式\n     */\n    private function parseKeyValue(string $text): array\n    {\n        $lines = explode(\"\\n\", trim($text));\n        $result = [];\n\n        foreach ($lines as $line) {\n            $line = trim($line);\n            if (empty($line)) continue;\n\n            $parts = explode(':', $line, 2);\n            if (count($parts) >= 2) {\n                $result[] = [\n                    'name' => trim($parts[0]),\n                    'type' => 'string',\n                    'description' => trim($parts[1])\n                ];\n            }\n        }\n\n        return $result;\n    }\n\n    /**\n     * 解析JSON格式\n     */\n    private function parseJson(string $text): ?array\n    {\n        $data = json_decode($text, true);\n        if (!$data) return null;\n\n        return $this->extractFieldsFromObject($data);\n    }\n\n    /**\n     * 从对象中提取字段\n     */\n    private function extractFieldsFromObject($obj, string $prefix = ''): array\n    {\n        $result = [];\n\n        foreach ($obj as $key => $value) {\n            $fieldName = $prefix ? $prefix . '.' . $key : $key;\n\n            if (is_array($value) && !empty($value)) {\n                if (is_object($value[0]) || is_array($value[0])) {\n                    $result[] = [\n                        'name' => $fieldName,\n                        'type' => 'array',\n                        'description' => $fieldName . '数组'\n                    ];\n                    $result = array_merge($result, $this->extractFieldsFromObject($value[0], $fieldName . '[0]'));\n                } else {\n                    $result[] = [\n                        'name' => $fieldName,\n                        'type' => 'array',\n                        'description' => $fieldName . '数组',\n                        'example' => json_encode($value)\n                    ];\n                }\n            } elseif (is_object($value) || (is_array($value) && !empty($value))) {\n                $result[] = [\n                    'name' => $fieldName,\n                    'type' => 'object',\n                    'description' => $fieldName . '对象'\n                ];\n                $result = array_merge($result, $this->extractFieldsFromObject($value, $fieldName));\n            } else {\n                $type = 'string';\n                if (is_int($value)) $type = 'number';\n                elseif (is_bool($value)) $type = 'boolean';\n                elseif (is_float($value)) $type = 'number';\n\n                $result[] = [\n                    'name' => $fieldName,\n                    'type' => $type,\n                    'description' => $fieldName,\n                    'example' => strval($value)\n                ];\n            }\n        }\n\n        return $result;\n    }\n\n    /**\n     * 解析DDL（简单实现）\n     */\n    private function parseDDL(string $text): array\n    {\n        // 简单的DDL解析，提取字段名和注释\n        $result = [];\n        $lines = explode(\"\\n\", $text);\n\n        foreach ($lines as $line) {\n            $line = trim($line);\n            if (preg_match('/`(\\w+)`\\s+\\w+.*COMMENT\\s+[\\'\"]([^\\'\"]+)[\\'\"]/', $line, $matches)) {\n                $result[] = [\n                    'name' => $matches[1],\n                    'type' => 'string',\n                    'description' => $matches[2]\n                ];\n            }\n        }\n\n        return $result;\n    }\n\n    /**\n     * 计算质量评分\n     */\n    private function calculateQualityScore(array $data): float\n    {\n        $score = 0.0;\n\n        // 基础分数\n        if (!empty($data['description'])) $score += 0.4;\n        if (!empty($data['example'])) $score += 0.2;\n        if (!empty($data['enumValues']) && is_array($data['enumValues']) && count($data['enumValues']) > 0) $score += 0.1;\n        if (!empty($data['defaultValue'])) $score += 0.1;\n\n        // 使用频次加分\n        $usageCount = $data['usageCount'] ?? ($data['usage_count'] ?? 0);\n        $usageScore = min($usageCount * 0.02, 0.2);\n        $score += $usageScore;\n\n        return min($score, 1.0);\n    }\n\n    /**\n     * 生成唯一ID\n     */\n    private function generateId(): string\n    {\n        return uniqid() . '_' . mt_rand(1000, 9999);\n    }\n\n    /**\n     * 转换数据库字段名为前端驼峰格式\n     */\n    private function convertEntryFields(array $entry): array\n    {\n        // 处理JSON字段\n        $entry['aliases'] = !empty($entry['aliases']) ? json_decode($entry['aliases'], true) : [];\n        $entry['tags'] = !empty($entry['tags']) ? json_decode($entry['tags'], true) : [];\n        $entry['enumValues'] = !empty($entry['enum_values']) ? json_decode($entry['enum_values'], true) : [];\n\n        // 字段名转换：数据库下划线 -> 前端驼峰\n        $entry['itemId'] = $entry['item_id'] ?? 0;\n        $entry['usageCount'] = (int) ($entry['usage_count'] ?? 0);\n        $entry['qualityScore'] = (float) ($entry['quality_score'] ?? 0);\n        $entry['defaultValue'] = $entry['default_value'] ?? '';\n        $entry['createdBy'] = $entry['created_by'] ?? 0;\n        $entry['updatedAt'] = isset($entry['updated_at']) ? strtotime($entry['updated_at']) * 1000 : 0; // 转换为前端时间戳格式\n\n        // 移除数据库字段名\n        unset($entry['item_id']);\n        unset($entry['usage_count']);\n        unset($entry['quality_score']);\n        unset($entry['default_value']);\n        unset($entry['enum_values']);\n        unset($entry['created_by']);\n        unset($entry['created_at']);\n        unset($entry['updated_at']);\n\n        return $entry;\n    }\n}\n"
  },
  {
    "path": "server/app/Api/Controller/PublicSquareController.php",
    "content": "<?php\n\nnamespace App\\Api\\Controller;\n\nuse App\\Common\\BaseController;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\nuse App\\Model\\Options;\nuse App\\Model\\Item;\nuse App\\Model\\Page;\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\n/**\n * 公共广场相关 Api（新架构）。\n */\nclass PublicSquareController extends BaseController\n{\n    /**\n     * 检查公开广场功能是否启用（兼容旧接口 Api/PublicSquare/checkEnabled）。\n     */\n    public function checkEnabled(Request $request, Response $response): Response\n    {\n        $enablePublicSquare = Options::get('enable_public_square', 0);\n\n        return $this->success($response, [\n            'enable' => $enablePublicSquare ? 1 : 0,\n        ]);\n    }\n\n    /**\n     * 获取公开项目列表（兼容旧接口 Api/PublicSquare/getPublicItems）。\n     */\n    public function getPublicItems(Request $request, Response $response): Response\n    {\n        // 检查是否启用了公开广场功能\n        $enablePublicSquare = Options::get('enable_public_square', 0);\n        if (!$enablePublicSquare) {\n            return $this->error($response, 10501, '公开广场功能未启用');\n        }\n\n        // 检查是否需要强制登录\n        $forceLogin = Options::get('force_login', 0);\n        if ($forceLogin) {\n            $loginUser = [];\n            if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n                return $error;\n            }\n        }\n\n        $page = $this->getParam($request, 'page', 1);\n        $count = $this->getParam($request, 'count', 20);\n        $keyword = $this->getParam($request, 'keyword', '');\n        $searchType = $this->getParam($request, 'search_type', 'title');\n\n        // 只获取公开项目\n        $query = DB::table('item')\n            ->where('password', '')\n            ->where('is_del', 0);\n\n        if (!empty($keyword)) {\n            if ($searchType === 'content') {\n                // 搜索项目内容需要连接 page 表\n                $likeKeyword = $this->safeLike($keyword);\n                $pageItems = DB::table('page')\n                    ->select('item_id')\n                    ->where('page_content', 'like', \"%{$likeKeyword}%\")\n                    ->groupBy('item_id')\n                    ->get()\n                    ->all();\n\n                if (!empty($pageItems)) {\n                    $itemIds = [];\n                    foreach ($pageItems as $value) {\n                        $itemIds[] = (int) ($value->item_id ?? 0);\n                    }\n                    $query->whereIn('item_id', $itemIds);\n                } else {\n                    // 如果没有找到匹配的内容，返回空结果\n                    return $this->success($response, [\n                        'total' => 0,\n                        'items' => [],\n                    ]);\n                }\n            } else {\n                // 默认搜索项目标题和描述\n                $likeKeyword = $this->safeLike($keyword);\n                $query->where(function ($q) use ($likeKeyword) {\n                    $q->where('item_name', 'like', \"%{$likeKeyword}%\")\n                        ->orWhere('item_description', 'like', \"%{$likeKeyword}%\");\n                });\n            }\n        }\n\n        // 获取总数\n        $total = (clone $query)->count();\n\n        // 分页查询\n        $items = $query\n            ->select([\n                'item_id',\n                'item_name',\n                'item_description',\n                'item_type',\n                'addtime',\n                'last_update_time',\n                'item_domain',\n            ])\n            ->orderBy('last_update_time', 'desc')\n            ->offset(($page - 1) * $count)\n            ->limit($count)\n            ->get()\n            ->all();\n\n        $result = [];\n        $result['total'] = (int) $total;\n\n        if (!empty($items)) {\n            foreach ($items as $item) {\n                $data = (array) $item;\n                $data['addtime'] = date('Y-m-d H:i:s', (int) ($data['addtime'] ?? time()));\n                $data['last_update_time'] = date('Y-m-d H:i:s', (int) ($data['last_update_time'] ?? time()));\n                $data['item_domain'] = !empty($data['item_domain']) ? $data['item_domain'] : $data['item_id'];\n                $result['items'][] = $data;\n            }\n        } else {\n            $result['items'] = [];\n        }\n\n        return $this->success($response, $result);\n    }\n}\n"
  },
  {
    "path": "server/app/Api/Controller/RecycleController.php",
    "content": "<?php\n\nnamespace App\\Api\\Controller;\n\nuse App\\Common\\BaseController;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\n/**\n * 回收站相关 Api（新架构）。\n */\nclass RecycleController extends BaseController\n{\n    /**\n     * 获取被删除的页面列表（兼容旧接口 Api/Recycle/getList）。\n     *\n     * 功能：\n     * - 获取项目的回收站列表\n     * - 权限检查（checkItemManage）\n     */\n    public function getList(Request $request, Response $response): Response\n    {\n        $itemId = $this->getParam($request, 'item_id', 0);\n\n        if ($itemId <= 0) {\n            return $this->success($response, []);\n        }\n\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        // 检查管理权限\n        if (!$this->checkItemManage($uid, $itemId)) {\n            return $this->error($response, 10303, '您没有管理权限');\n        }\n\n        // 获取回收站列表\n        $ret = \\App\\Model\\Recycle::getList($itemId);\n\n        return $this->success($response, $ret ?: []);\n    }\n\n    /**\n     * 恢复页面（兼容旧接口 Api/Recycle/recover）。\n     *\n     * 功能：\n     * - 恢复被删除的页面\n     * - 权限检查（checkItemManage）\n     * - 删除菜单和页面缓存\n     */\n    public function recover(Request $request, Response $response): Response\n    {\n        $itemId = $this->getParam($request, 'item_id', 0);\n        $pageId = $this->getParam($request, 'page_id', 0);\n\n        if ($itemId <= 0 || $pageId <= 0) {\n            return $this->error($response, 10101, '参数错误');\n        }\n\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        // 检查管理权限\n        if (!$this->checkItemManage($uid, $itemId)) {\n            return $this->error($response, 10303, '您没有管理权限');\n        }\n\n        // 恢复页面（更新 is_del 为 0，cat_id 置 0，与旧版逻辑一致）\n        DB::table('page')\n            ->where('page_id', $pageId)\n            ->where('item_id', $itemId)\n            ->update([\n                'is_del' => 0,\n                'cat_id' => 0,\n            ]);\n\n        // 删除回收站记录\n        \\App\\Model\\Recycle::delete($itemId, $pageId);\n\n        // 删除缓存\n        \\App\\Model\\Item::deleteCache($itemId);\n        \\App\\Model\\Page::deleteCache($pageId);\n\n        return $this->success($response, []);\n    }\n}\n"
  },
  {
    "path": "server/app/Api/Controller/RunapiController.php",
    "content": "<?php\n\nnamespace App\\Api\\Controller;\n\nuse App\\Common\\BaseController;\nuse App\\Model\\RunapiEnv;\nuse App\\Model\\RunapiEnvSelectd;\nuse App\\Model\\RunapiGlobalParam;\nuse App\\Model\\RunapiDbConfig;\nuse App\\Model\\ItemVariable;\nuse App\\Model\\Runapi;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\n\nclass RunapiController extends BaseController\n{\n    /**\n     * 添加/更新环境\n     *\n     * @param Request $request\n     * @param Response $response\n     * @return Response\n     */\n    public function addEnv(Request $request, Response $response): Response\n    {\n        $user = [];\n        if ($error = $this->requireLoginUser($request, $response, $user)) {\n            return $error;\n        }\n\n        $uid = (int) ($user['uid'] ?? 0);\n        $envId = $this->getParam($request, 'env_id', 0);\n        $envName = $this->getParam($request, 'env_name', '');\n        $itemId = $this->getParam($request, 'item_id', 0);\n\n        // 权限检查\n        if (!$this->checkItemEdit($uid, $itemId)) {\n            return $this->error($response, 10303, '没有权限');\n        }\n\n        if (empty($envName)) {\n            return $this->error($response, 10101, '环境名称不能为空');\n        }\n\n        if ($envId > 0) {\n            // 更新\n            $res = RunapiEnv::update($envId, $itemId, [\n                'env_name'        => $envName,\n                'uid'             => $uid,\n                'last_update_time' => date('Y-m-d H:i:s'),\n            ]);\n            if ($res) {\n                return $this->success($response, ['env_id' => $envId]);\n            }\n        } else {\n            // 新建\n            $envId = RunapiEnv::add([\n                'env_name'        => $envName,\n                'item_id'         => $itemId,\n                'uid'             => $uid,\n                'addtime'          => date('Y-m-d H:i:s'),\n                'last_update_time' => date('Y-m-d H:i:s'),\n            ]);\n            if ($envId) {\n                return $this->success($response, ['env_id' => $envId]);\n            }\n        }\n\n        return $this->error($response, 10500, '操作失败');\n    }\n\n    /**\n     * 更新环境（兼容旧接口）\n     *\n     * @param Request $request\n     * @param Response $response\n     * @return Response\n     */\n    public function updateEnv(Request $request, Response $response): Response\n    {\n        return $this->addEnv($request, $response);\n    }\n\n    /**\n     * 获取环境列表\n     *\n     * @param Request $request\n     * @param Response $response\n     * @return Response\n     */\n    public function getEnvList(Request $request, Response $response): Response\n    {\n        $user = [];\n        if ($error = $this->requireLoginUser($request, $response, $user)) {\n            return $error;\n        }\n\n        $uid = (int) ($user['uid'] ?? 0);\n        $itemId = $this->getParam($request, 'item_id', 0);\n\n        // 权限检查\n        if (!$this->checkItemEdit($uid, $itemId)) {\n            return $this->error($response, 10303, '没有权限');\n        }\n\n        $res = RunapiEnv::getListByItemId($itemId);\n        if (!empty($res)) {\n            return $this->success($response, $res);\n        } else {\n            // 如果尚未有环境，则帮其创建一个默认环境\n            $envId = RunapiEnv::add([\n                'env_name'        => '默认环境',\n                'item_id'         => $itemId,\n                'uid'             => $uid,\n                'addtime'          => date('Y-m-d H:i:s'),\n                'last_update_time' => date('Y-m-d H:i:s'),\n            ]);\n            if ($envId) {\n                // 并且把项目变量都绑定到该默认环境中\n                ItemVariable::updateEnvIdForItem($itemId, $envId);\n                sleep(1);\n                return $this->getEnvList($request, $response);\n            }\n        }\n\n        return $this->success($response, []);\n    }\n\n    /**\n     * 删除环境\n     *\n     * @param Request $request\n     * @param Response $response\n     * @return Response\n     */\n    public function delEnv(Request $request, Response $response): Response\n    {\n        $user = [];\n        if ($error = $this->requireLoginUser($request, $response, $user)) {\n            return $error;\n        }\n\n        $uid = (int) ($user['uid'] ?? 0);\n        $envId = $this->getParam($request, 'env_id', 0);\n\n        $env = RunapiEnv::findById($envId);\n        if (!$env) {\n            return $this->error($response, 10101, '环境不存在');\n        }\n\n        $itemId = (int) $env['item_id'];\n\n        // 权限检查\n        if (!$this->checkItemEdit($uid, $itemId)) {\n            return $this->error($response, 10303, '没有权限');\n        }\n\n        // 删除选中的环境记录\n        RunapiEnvSelectd::deleteByEnvId($envId);\n        // 删除环境\n        RunapiEnv::delete($envId);\n        // 删除该环境下的变量\n        ItemVariable::deleteByEnvId($envId);\n\n        return $this->success($response, []);\n    }\n\n    /**\n     * 设置某个环境变量为选中\n     *\n     * @param Request $request\n     * @param Response $response\n     * @return Response\n     */\n    public function selectEnv(Request $request, Response $response): Response\n    {\n        $user = [];\n        if ($error = $this->requireLoginUser($request, $response, $user)) {\n            return $error;\n        }\n\n        $uid = (int) ($user['uid'] ?? 0);\n        $envId = $this->getParam($request, 'env_id', 0);\n\n        $env = RunapiEnv::findById($envId);\n        if (!$env) {\n            return $this->error($response, 10101, '环境不存在');\n        }\n\n        $itemId = (int) $env['item_id'];\n\n        // 权限检查\n        if (!$this->checkItemEdit($uid, $itemId)) {\n            return $this->error($response, 10303, '没有权限');\n        }\n\n        // 先删除旧的选中记录\n        RunapiEnvSelectd::deleteByItemIdAndUid($itemId, $uid);\n        // 添加新的选中记录\n        $res = RunapiEnvSelectd::add([\n            'item_id' => $itemId,\n            'uid'     => $uid,\n            'env_id'  => $envId,\n        ]);\n\n        if ($res) {\n            return $this->success($response, ['id' => $res]);\n        } else {\n            return $this->success($response, []);\n        }\n    }\n\n    /**\n     * 获取用户选中的环境\n     *\n     * @param Request $request\n     * @param Response $response\n     * @return Response\n     */\n    public function getSelectEnv(Request $request, Response $response): Response\n    {\n        $user = [];\n        if ($error = $this->requireLoginUser($request, $response, $user)) {\n            return $error;\n        }\n\n        $uid = (int) ($user['uid'] ?? 0);\n        $itemId = $this->getParam($request, 'item_id', 0);\n\n        // 权限检查\n        if (!$this->checkItemEdit($uid, $itemId)) {\n            return $this->error($response, 10303, '没有权限');\n        }\n\n        $res = RunapiEnvSelectd::findByItemIdAndUid($itemId, $uid);\n        if ($res) {\n            return $this->success($response, $res);\n        } else {\n            return $this->success($response, ['env_id' => 0]);\n        }\n    }\n\n    /**\n     * 获取全局参数\n     *\n     * @param Request $request\n     * @param Response $response\n     * @return Response\n     */\n    public function getGlobalParam(Request $request, Response $response): Response\n    {\n        $user = [];\n        if ($error = $this->requireLoginUser($request, $response, $user)) {\n            return $error;\n        }\n\n        $uid = (int) ($user['uid'] ?? 0);\n        $itemId = $this->getParam($request, 'item_id', 0);\n\n        // 权限检查\n        if (!$this->checkItemEdit($uid, $itemId)) {\n            return $this->error($response, 10303, '没有权限');\n        }\n\n        $return = Runapi::getGlobalParam($itemId);\n        return $this->success($response, $return);\n    }\n\n    /**\n     * 修改全局参数\n     *\n     * @param Request $request\n     * @param Response $response\n     * @return Response\n     */\n    public function updateGlobalParam(Request $request, Response $response): Response\n    {\n        $user = [];\n        if ($error = $this->requireLoginUser($request, $response, $user)) {\n            return $error;\n        }\n\n        $uid = (int) ($user['uid'] ?? 0);\n        $itemId = $this->getParam($request, 'item_id', 0);\n        $paramType = $this->getParam($request, 'param_type', '');\n        $contentJsonStr = $this->getParam($request, 'content_json_str', '');\n\n        // 权限检查\n        if (!$this->checkItemEdit($uid, $itemId)) {\n            return $this->error($response, 10303, '没有权限');\n        }\n\n        $res = RunapiGlobalParam::update($itemId, $paramType, $contentJsonStr);\n        if ($res) {\n            return $this->success($response, ['result' => true]);\n        } else {\n            return $this->success($response, []);\n        }\n    }\n\n    /**\n     * 获取数据库连接列表（按项目+环境）\n     *\n     * @param Request $request\n     * @param Response $response\n     * @return Response\n     */\n    public function getDbConfigList(Request $request, Response $response): Response\n    {\n        $user = [];\n        if ($error = $this->requireLoginUser($request, $response, $user)) {\n            return $error;\n        }\n\n        $uid = (int) ($user['uid'] ?? 0);\n        $itemId = $this->getParam($request, 'item_id', 0);\n        $envId = $this->getParam($request, 'env_id', 0);\n\n        // 权限检查\n        if (!$this->checkItemEdit($uid, $itemId)) {\n            return $this->error($response, 10303, '没有权限');\n        }\n\n        if (!$envId) {\n            return $this->error($response, 10101, '缺少 env_id');\n        }\n\n        $list = RunapiDbConfig::getListByItemIdAndEnvId($itemId, $envId);\n        return $this->success($response, $list ?: []);\n    }\n\n    /**\n     * 新增/更新数据库连接配置\n     *\n     * @param Request $request\n     * @param Response $response\n     * @return Response\n     */\n    public function saveDbConfig(Request $request, Response $response): Response\n    {\n        $user = [];\n        if ($error = $this->requireLoginUser($request, $response, $user)) {\n            return $error;\n        }\n\n        $uid = (int) ($user['uid'] ?? 0);\n        $configId = $this->getParam($request, 'config_id', 0);\n        $itemId = $this->getParam($request, 'item_id', 0);\n        $envId = $this->getParam($request, 'env_id', 0);\n        $configName = $this->getParam($request, 'config_name', '默认');\n        $dbType = $this->getParam($request, 'db_type', 'mysql');\n        $host = $this->getParam($request, 'host', '');\n        $port = $this->getParam($request, 'port', 0);\n        $username = $this->getParam($request, 'username', '');\n        $password = $this->getParam($request, 'password', '');\n        $database = $this->getParam($request, 'database', '');\n        $options = $this->getParam($request, 'options', '');\n        $isDefault = $this->getParam($request, 'is_default', 0);\n\n        // 权限检查\n        if (!$this->checkItemEdit($uid, $itemId)) {\n            return $this->error($response, 10303, '没有权限');\n        }\n\n        if (!$envId) {\n            return $this->error($response, 10101, '缺少 env_id');\n        }\n\n        // 开源版保留旧版支持的数据库类型：mysql / postgresql / sqlite\n        $allowType = ['mysql', 'postgresql', 'sqlite'];\n        if (!in_array($dbType, $allowType)) {\n            return $this->error($response, 10101, '不支持的数据库类型');\n        }\n\n        if (empty($configName)) {\n            $configName = '默认';\n        }\n\n        $data = [\n            'item_id'          => $itemId,\n            'env_id'           => $envId,\n            'config_name'      => $configName,\n            'db_type'          => $dbType,\n            'host'             => $host,\n            'port'              => $port,\n            'username'          => $username,\n            'password'          => $password,\n            'database'          => $database,\n            'options'           => $options,\n            'is_default'        => $isDefault ? 1 : 0,\n            'last_update_time' => date('Y-m-d H:i:s'),\n            'uid'               => $uid,\n        ];\n\n        if ($configId > 0) {\n            // 更新\n            $row = RunapiDbConfig::findById($configId);\n            if (!$row || (int) $row['item_id'] !== $itemId) {\n                return $this->error($response, 10101, '配置不存在');\n            }\n            RunapiDbConfig::update($configId, $data);\n        } else {\n            // 新建\n            $data['addtime'] = date('Y-m-d H:i:s');\n            $configId = RunapiDbConfig::add($data);\n        }\n\n        if ($isDefault && $configId) {\n            // 取消其他配置的默认状态\n            RunapiDbConfig::unsetDefaultOthers($itemId, $envId, $configId);\n        }\n\n        return $this->success($response, ['config_id' => $configId]);\n    }\n\n    /**\n     * 删除数据库连接配置\n     *\n     * @param Request $request\n     * @param Response $response\n     * @return Response\n     */\n    public function delDbConfig(Request $request, Response $response): Response\n    {\n        $user = [];\n        if ($error = $this->requireLoginUser($request, $response, $user)) {\n            return $error;\n        }\n\n        $uid = (int) ($user['uid'] ?? 0);\n        $configId = $this->getParam($request, 'config_id', 0);\n\n        $row = RunapiDbConfig::findById($configId);\n        if (!$row) {\n            return $this->error($response, 10101, '配置不存在');\n        }\n\n        $itemId = (int) $row['item_id'];\n\n        // 权限检查\n        if (!$this->checkItemEdit($uid, $itemId)) {\n            return $this->error($response, 10303, '没有权限');\n        }\n\n        RunapiDbConfig::delete($configId);\n        return $this->success($response, []);\n    }\n\n    // 说明：开源版不提供 Runapi 的 AI 辅助接口（如 mdToRunapi、generateScript、generateTestData），\n    // 相关能力由主站 showdoc.cc 统一提供，Runapi 客户端仍会固定访问主站进行此类 AI 能力调用。\n}\n"
  },
  {
    "path": "server/app/Api/Controller/ScriptCronController.php",
    "content": "<?php\n\nnamespace App\\Api\\Controller;\n\nuse App\\Common\\BaseController;\nuse App\\Model\\Item;\nuse App\\Model\\Page;\nuse App\\Model\\Recycle;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\n/**\n * 由网站前台脚本触发的周期任务\n */\nclass ScriptCronController extends BaseController\n{\n    /**\n     * 执行定时任务\n     *\n     * @param Request $request\n     * @param Response $response\n     * @return Response\n     */\n    public function run(Request $request, Response $response): Response\n    {\n        set_time_limit(100);\n        ini_set('memory_limit', '800M');\n        ignore_user_abort(true);\n\n        // 定期清理已删除项目和已删除页面\n        $this->cleanDeletedData();\n\n        return $this->success($response, ['message' => '定时任务执行完成']);\n    }\n\n    /**\n     * 定期清理已删除项目和已删除页面\n     */\n    private function cleanDeletedData(): void\n    {\n        $thirtyDaysAgo = time() - 30 * 24 * 60 * 60;\n\n        // 30天前的已删除项目\n        $items = DB::table('item')\n            ->where('is_del', 1)\n            ->where('last_update_time', '<', $thirtyDaysAgo)\n            ->get();\n\n        if ($items) {\n            foreach ($items as $item) {\n                Item::deleteItem((int) $item->item_id);\n            }\n        }\n\n        // 30天前的已删除页面（旧版逻辑：只传 page_id）\n        $pages = DB::table('page')\n            ->where('is_del', 1)\n            ->where('addtime', '<', $thirtyDaysAgo)\n            ->get();\n\n        if ($pages) {\n            foreach ($pages as $page) {\n                // 旧版只传 page_id，不传 item_id\n                Page::deletePage((int) $page->page_id);\n            }\n        }\n\n        // 30天前的回收站记录（旧版逻辑：直接调用 deletePage，不检查 page 是否存在）\n        $recycles = DB::table('recycle')\n            ->where('del_time', '<', $thirtyDaysAgo)\n            ->get();\n\n        if ($recycles) {\n            foreach ($recycles as $recycle) {\n                // 旧版逻辑：直接调用 deletePage，只传 page_id\n                Page::deletePage((int) $recycle->page_id);\n                DB::table('recycle')\n                    ->where('id', $recycle->id)\n                    ->delete();\n            }\n        }\n    }\n}\n\n"
  },
  {
    "path": "server/app/Api/Controller/SubscriptionController.php",
    "content": "<?php\n\nnamespace App\\Api\\Controller;\n\nuse App\\Common\\BaseController;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\n\n/**\n * 订阅相关 Api（新架构）。\n */\nclass SubscriptionController extends BaseController\n{\n    /**\n     * 获取页面的订阅人员列表（兼容旧接口 Api/Subscription/getPageList）。\n     *\n     * 功能：\n     * - 获取页面的订阅人员列表\n     * - 权限检查（checkItemEdit）\n     */\n    public function getPageList(Request $request, Response $response): Response\n    {\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n        $pageId = $this->getParam($request, 'page_id', 0);\n\n        if ($pageId <= 0) {\n            return $this->success($response, []);\n        }\n\n        // 获取页面信息\n        $page = \\App\\Model\\Page::findById($pageId);\n        if (!$page) {\n            return $this->error($response, 10101, '页面不存在');\n        }\n\n        $itemId = (int) ($page['item_id'] ?? 0);\n\n        // 检查编辑权限\n        if (!$this->checkItemEdit($uid, $itemId)) {\n            return $this->error($response, 10103, '您没有编辑权限');\n        }\n\n        // 获取订阅列表\n        $subscriptionArray = \\App\\Model\\Subscription::getListByObjectId($pageId, 'page', 'update');\n        $subscriptionArray = $subscriptionArray ?: [];\n\n        // 填充用户信息\n        foreach ($subscriptionArray as $key => $value) {\n            $user = \\App\\Model\\User::findById((int) ($value['uid'] ?? 0));\n            if ($user) {\n                $subscriptionArray[$key]['username'] = $user->username ?? '';\n                $subscriptionArray[$key]['name'] = $user->name ?? '';\n            } else {\n                $subscriptionArray[$key]['username'] = '';\n                $subscriptionArray[$key]['name'] = '';\n            }\n        }\n\n        return $this->success($response, $subscriptionArray);\n    }\n\n    /**\n     * 保存页面（或者接口）的订阅信息（兼容旧接口 Api/Subscription/savePage）。\n     *\n     * 功能：\n     * - 保存页面的订阅信息\n     * - 权限检查（checkItemEdit）\n     */\n    public function savePage(Request $request, Response $response): Response\n    {\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n        $uids = $this->getParam($request, 'uids', '');\n        $pageId = $this->getParam($request, 'page_id', 0);\n\n        if ($pageId <= 0) {\n            return $this->error($response, 10100, '缺少 page_id 参数');\n        }\n\n        // 获取页面信息\n        $page = \\App\\Model\\Page::findById($pageId);\n        if (!$page) {\n            return $this->error($response, 10101, '页面不存在');\n        }\n\n        $itemId = (int) ($page['item_id'] ?? 0);\n\n        // 检查编辑权限\n        if (!$this->checkItemEdit($uid, $itemId)) {\n            return $this->error($response, 10103, '您没有编辑权限');\n        }\n\n        // 处理用户 ID 列表\n        $uidsArray = [];\n        if (!empty($uids)) {\n            $uidsArray = array_filter(array_map('intval', explode(',', $uids)));\n        }\n\n        // 添加订阅\n        foreach ($uidsArray as $sUid) {\n            if ($sUid > 0) {\n                \\App\\Model\\Subscription::addSub($sUid, $pageId, 'page', 'update');\n            }\n        }\n\n        return $this->success($response, []);\n    }\n\n    /**\n     * 删除页面（或者接口）的订阅信息（兼容旧接口 Api/Subscription/deletePage）。\n     *\n     * 功能：\n     * - 删除页面的订阅信息\n     * - 权限检查（checkItemEdit）\n     */\n    public function deletePage(Request $request, Response $response): Response\n    {\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n        $uids = $this->getParam($request, 'uids', '');\n        $pageId = $this->getParam($request, 'page_id', 0);\n\n        if ($pageId <= 0) {\n            return $this->error($response, 10100, '缺少 page_id 参数');\n        }\n\n        // 获取页面信息\n        $page = \\App\\Model\\Page::findById($pageId);\n        if (!$page) {\n            return $this->error($response, 10101, '页面不存在');\n        }\n\n        $itemId = (int) ($page['item_id'] ?? 0);\n\n        // 检查编辑权限\n        if (!$this->checkItemEdit($uid, $itemId)) {\n            return $this->error($response, 10103, '您没有编辑权限');\n        }\n\n        // 处理用户 ID 列表\n        $uidsArray = [];\n        if (!empty($uids)) {\n            $uidsArray = array_filter(array_map('intval', explode(',', $uids)));\n        }\n\n        // 删除订阅\n        foreach ($uidsArray as $sUid) {\n            if ($sUid > 0) {\n                \\App\\Model\\Subscription::deleteSub($sUid, $pageId, 'page', 'update');\n            }\n        }\n\n        return $this->success($response, []);\n    }\n}\n"
  },
  {
    "path": "server/app/Api/Controller/TeamController.php",
    "content": "<?php\n\nnamespace App\\Api\\Controller;\n\nuse App\\Common\\BaseController;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\n/**\n * 团队管理相关 Api（新架构）。\n */\nclass TeamController extends BaseController\n{\n    /**\n     * 添加和编辑团队（兼容旧接口 Api/Team/save）。\n     *\n     * 功能：\n     * - 支持新建和更新团队\n     * - 更新时需要检查团队管理权限\n     */\n    public function save(Request $request, Response $response): Response\n    {\n        $teamName = $this->getParam($request, 'team_name', '');\n        $id       = $this->getParam($request, 'id', 0);\n\n        if (empty($teamName)) {\n            return $this->error($response, 10101, '团队名称不能为空');\n        }\n\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid      = (int) ($loginUser['uid'] ?? 0);\n        $username = (string) ($loginUser['username'] ?? '');\n\n        // 如果是更新，检查管理权限\n        if ($id > 0) {\n            if (!$this->checkTeamManage($uid, $id)) {\n                return $this->error($response, 10103, '您没有管理权限');\n            }\n        }\n\n        // 保存团队\n        $teamId = \\App\\Model\\Team::save($id, $uid, $username, $teamName);\n\n        if ($teamId <= 0) {\n            return $this->error($response, 10103, '操作失败');\n        }\n\n        // 等待一下，确保数据已写入\n        usleep(500000);\n\n        // 获取保存后的团队信息\n        $return = \\App\\Model\\Team::findById($teamId);\n        if (!$return) {\n            return $this->error($response, 10103, '操作失败');\n        }\n\n        return $this->success($response, (array) $return);\n    }\n\n    /**\n     * 获取团队列表（兼容旧接口 Api/Team/getList）。\n     *\n     * 功能：\n     * - 获取当前用户创建的和参与的团队列表\n     * - 包含团队成员数和项目数\n     * - 包含管理权限标识\n     */\n    public function getList(Request $request, Response $response): Response\n    {\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        if ($uid <= 0) {\n            return $this->success($response, []);\n        }\n\n        // 获取团队列表\n        $ret = \\App\\Model\\Team::getList($uid);\n\n        // 添加管理权限标识\n        foreach ($ret as $key => &$value) {\n            $teamId = (int) ($value['id'] ?? 0);\n            $value['team_manage'] = $this->checkTeamManage($uid, $teamId) ? 1 : 0;\n        }\n\n        return $this->success($response, $ret ?: []);\n    }\n\n    /**\n     * 删除团队（兼容旧接口 Api/Team/delete）。\n     *\n     * 功能：\n     * - 只有团队创建者才能删除\n     * - 删除团队及其关联数据\n     */\n    public function delete(Request $request, Response $response): Response\n    {\n        $id = $this->getParam($request, 'id', 0);\n\n        if ($id <= 0) {\n            return $this->error($response, 10101, '参数错误');\n        }\n\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        // 删除团队\n        $ret = \\App\\Model\\Team::delete($id, $uid);\n\n        if (!$ret) {\n            return $this->error($response, 10103, '删除失败');\n        }\n\n        return $this->success($response, ['success' => true]);\n    }\n\n    /**\n     * 转让团队（兼容旧接口 Api/Team/attorn）。\n     *\n     * 功能：\n     * - 只有团队创建者才能转让\n     * - 需要验证密码\n     * - 转让团队及其关联的项目\n     */\n    public function attorn(Request $request, Response $response): Response\n    {\n        $username = $this->getParam($request, 'username', '');\n        $teamId   = $this->getParam($request, 'team_id', 0);\n        $password = $this->getParam($request, 'password', '');\n\n        if ($teamId <= 0 || empty($username) || empty($password)) {\n            return $this->error($response, 10101, '参数错误');\n        }\n\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        // 检查是否是团队创建者\n        $team = \\App\\Model\\Team::findById($teamId, $uid);\n        if (!$team) {\n            return $this->error($response, 10101, '团队不存在或您没有权限');\n        }\n\n        // 验证密码\n        $loginUsername = (string) ($loginUser['username'] ?? '');\n        $user = \\App\\Model\\User::checkLogin($loginUsername, $password);\n        if (!$user) {\n            return $this->error($response, 10208, '密码错误');\n        }\n\n        // 查找目标用户\n        $member = \\App\\Model\\User::findByUsernameOrEmail($username);\n        if (!$member) {\n            return $this->error($response, 10209, '用户不存在');\n        }\n\n        // 转让团队\n        $success = \\App\\Model\\Team::attorn(\n            $teamId,\n            $uid,\n            (int) $member->uid,\n            $member->username ?? ''\n        );\n\n        if (!$success) {\n            return $this->error($response, 10103, '转让失败');\n        }\n\n        return $this->success($response, []);\n    }\n\n    /**\n     * 退出团队（兼容旧接口 Api/Team/exitTeam）。\n     *\n     * 功能：\n     * - 用户主动退出团队\n     * - 删除团队成员关系和项目成员关系\n     */\n    public function exitTeam(Request $request, Response $response): Response\n    {\n        $id = $this->getParam($request, 'id', 0);\n\n        if ($id <= 0) {\n            return $this->error($response, 10101, '参数错误');\n        }\n\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        // 退出团队\n        $success = \\App\\Model\\Team::exitTeam($id, $uid);\n\n        if (!$success) {\n            return $this->error($response, 10103, '操作失败');\n        }\n\n        return $this->success($response, []);\n    }\n}\n"
  },
  {
    "path": "server/app/Api/Controller/TeamItemController.php",
    "content": "<?php\n\nnamespace App\\Api\\Controller;\n\nuse App\\Common\\BaseController;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\nuse App\\Model\\TeamItem;\nuse App\\Model\\TeamMember;\nuse App\\Model\\TeamItemMember;\nuse App\\Model\\Team;\nuse App\\Model\\ItemChangeLog;\nuse App\\Common\\Helper\\Security;\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\n/**\n * 团队项目相关 Api（新架构）。\n */\nclass TeamItemController extends BaseController\n{\n    /**\n     * 添加和编辑团队项目关联（兼容旧接口 Api/TeamItem/save）。\n     */\n    public function save(Request $request, Response $response): Response\n    {\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $itemIdStr = $this->getParam($request, 'item_id', '');\n        $teamId = $this->getParam($request, 'team_id', 0);\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        if ($teamId <= 0 || empty($itemIdStr)) {\n            return $this->error($response, 10101, '参数错误');\n        }\n\n        if (!$this->checkTeamManage($uid, $teamId)) {\n            return $this->error($response, 10103, '没有权限');\n        }\n\n        $team = Team::findById($teamId);\n        if (!$team) {\n            return $this->error($response, 10101, '团队不存在');\n        }\n\n        // 转义并分割项目ID\n        $itemIdStr = Security::safeLike($itemIdStr, false);\n        $itemIdArray = explode(',', $itemIdStr);\n\n        $return = [];\n        $lastId = 0;\n\n        foreach ($itemIdArray as $value) {\n            $itemId = (int) trim($value);\n            if ($itemId <= 0) {\n                continue;\n            }\n\n            if (!$this->checkItemManage($uid, $itemId)) {\n                return $this->error($response, 10303, \"项目 {$itemId} 没有权限\");\n            }\n\n            // 如果该项目已经加入团队了，跳过\n            if (TeamItem::exists($teamId, $itemId)) {\n                continue;\n            }\n\n            // 添加团队项目关联\n            $data = [\n                'item_id' => $itemId,\n                'team_id' => $teamId,\n                'addtime' => time(),\n            ];\n            $id = TeamItem::add($data);\n            if ($id) {\n                $lastId = $id;\n\n                // 记录变更日志\n                ItemChangeLog::addLog(\n                    $uid,\n                    $itemId,\n                    'binding',\n                    'team',\n                    $teamId,\n                    $team->team_name ?? ''\n                );\n\n                // 获取该团队的所有成员并加入项目\n                $teamMembers = TeamMember::getMemberUidsByTeamId($teamId);\n                if (!empty($teamMembers)) {\n                    foreach ($teamMembers as $member) {\n                        $memberUid = (int) ($member['member_uid'] ?? 0);\n                        $memberUsername = $member['member_username'] ?? '';\n\n                        $memberData = [\n                            'team_id'        => $teamId,\n                            'member_uid'     => $memberUid,\n                            'member_username' => $memberUsername,\n                            'item_id'        => $itemId,\n                            'member_group_id' => 1, // 默认添加的权限为1，即编辑权限\n                            'addtime'        => time(),\n                        ];\n                        TeamItemMember::add($memberData);\n                    }\n                }\n            }\n        }\n\n        if (!$lastId) {\n            return $this->error($response, 10103, '添加失败');\n        }\n\n        return $this->success($response, ['id' => $lastId]);\n    }\n\n    /**\n     * 根据项目来获取其绑定的团队列表（兼容旧接口 Api/TeamItem/getList）。\n     */\n    public function getList(Request $request, Response $response): Response\n    {\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $itemId = $this->getParam($request, 'item_id', 0);\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        if ($itemId <= 0) {\n            return $this->error($response, 10101, '项目ID不能为空');\n        }\n\n        if (!$this->checkItemManage($uid, $itemId)) {\n            return $this->error($response, 10303, '没有权限');\n        }\n\n        $ret = TeamItem::getListByItemId($itemId);\n        if (!empty($ret)) {\n            return $this->success($response, $ret);\n        }\n\n        return $this->success($response, []);\n    }\n\n    /**\n     * 根据团队来获取项目列表（兼容旧接口 Api/TeamItem/getListByTeam）。\n     */\n    public function getListByTeam(Request $request, Response $response): Response\n    {\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $teamId = $this->getParam($request, 'team_id', 0);\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        if ($teamId <= 0) {\n            return $this->error($response, 10101, '团队ID不能为空');\n        }\n\n        // 权限判断。团队管理者和团队成员可以看到该列表\n        if (!$this->checkTeamManage($uid, $teamId)) {\n            $member = DB::table('team_member')\n                ->where('member_uid', $uid)\n                ->where('team_id', $teamId)\n                ->first();\n            if (!$member) {\n                return $this->error($response, 10103, '没有权限');\n            }\n        }\n\n        $ret = TeamItem::getListByTeamId($teamId);\n        if (!empty($ret)) {\n            return $this->success($response, $ret);\n        }\n\n        return $this->success($response, []);\n    }\n\n    /**\n     * 删除团队项目关联（兼容旧接口 Api/TeamItem/delete）。\n     */\n    public function delete(Request $request, Response $response): Response\n    {\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $id = $this->getParam($request, 'id', 0);\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        if ($id <= 0) {\n            return $this->error($response, 10101, '参数错误');\n        }\n\n        $teamItem = TeamItem::findById($id);\n        if (!$teamItem) {\n            return $this->error($response, 10101, '关联不存在');\n        }\n\n        $itemId = (int) ($teamItem->item_id ?? 0);\n        $teamId = (int) ($teamItem->team_id ?? 0);\n\n        if (!$this->checkTeamManage($uid, $teamId)) {\n            return $this->error($response, 10103, '没有权限');\n        }\n\n        // 删除团队项目成员关联\n        TeamItemMember::deleteByItemIdAndTeamId($itemId, $teamId);\n\n        // 删除团队项目关联\n        $ret = TeamItem::delete($id);\n        if ($ret) {\n            // 记录变更日志\n            $team = Team::findById($teamId);\n            if ($team) {\n                ItemChangeLog::addLog(\n                    $uid,\n                    $itemId,\n                    'unbound',\n                    'team',\n                    $teamId,\n                    $team->team_name ?? ''\n                );\n            }\n\n            return $this->success($response, ['success' => true]);\n        }\n\n        return $this->error($response, 10103, '删除失败');\n    }\n}\n"
  },
  {
    "path": "server/app/Api/Controller/TeamItemMemberController.php",
    "content": "<?php\n\nnamespace App\\Api\\Controller;\n\nuse App\\Common\\BaseController;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\nuse App\\Model\\TeamItemMember;\nuse App\\Model\\Team;\nuse App\\Model\\Catalog;\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\n/**\n * 团队项目成员相关 Api（新架构）。\n */\nclass TeamItemMemberController extends BaseController\n{\n    /**\n     * 添加和编辑团队项目成员（兼容旧接口 Api/TeamItemMember/save）。\n     */\n    public function save(Request $request, Response $response): Response\n    {\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $id = $this->getParam($request, 'id', 0);\n        $memberGroupId = $this->getParam($request, 'member_group_id', 0);\n        $catId = $this->getParam($request, 'cat_id', 0);\n        $catIds = $this->getParam($request, 'cat_ids', '');\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        if ($id <= 0) {\n            return $this->error($response, 10101, '参数错误');\n        }\n\n        $teamItemMember = TeamItemMember::findById($id);\n        if (!$teamItemMember) {\n            return $this->error($response, 10101, '成员不存在');\n        }\n\n        $itemId = (int) ($teamItemMember->item_id ?? 0);\n        $teamId = (int) ($teamItemMember->team_id ?? 0);\n\n        if (!$this->checkTeamManage($uid, $teamId)) {\n            return $this->error($response, 10103, '没有权限');\n        }\n\n        $updateData = [];\n\n        // 更新成员权限\n        if ($request->getParsedBody() && array_key_exists('member_group_id', $request->getParsedBody())) {\n            $updateData['member_group_id'] = $memberGroupId;\n        }\n\n        // 更新单目录（向后兼容）\n        if ($request->getParsedBody() && array_key_exists('cat_id', $request->getParsedBody())) {\n            $updateData['cat_id'] = $catId;\n        }\n\n        // 更新多目录（仅根下一层）\n        if ($request->getParsedBody() && array_key_exists('cat_ids', $request->getParsedBody())) {\n            $ids = [];\n            if (is_array($catIds)) {\n                $ids = $catIds;\n            } else {\n                $tmp = json_decode(htmlspecialchars_decode($catIds), true);\n                if (is_array($tmp)) {\n                    $ids = $tmp;\n                } elseif (is_string($catIds)) {\n                    if (strpos($catIds, ',') !== false) {\n                        $ids = preg_split('/\\s*,\\s*/', trim($catIds));\n                    } elseif (ctype_digit($catIds)) {\n                        $ids = [(int) $catIds];\n                    }\n                }\n            }\n\n            // 过滤非法与去重\n            $ids2 = [];\n            if (!empty($ids)) {\n                // 校验每个目录必须为该项目的 level=2\n                foreach ($ids as $v) {\n                    $v = (int) $v;\n                    if ($v <= 0) {\n                        continue;\n                    }\n                    $cat = DB::table('catalog')\n                        ->where('cat_id', $v)\n                        ->where('item_id', $itemId)\n                        ->where('level', 2)\n                        ->first();\n                    if ($cat) {\n                        $ids2[] = $v;\n                    }\n                }\n                $ids2 = array_values(array_unique($ids2));\n            }\n\n            // 统一以逗号分隔字符串存储\n            $updateData['cat_ids'] = !empty($ids2) ? implode(',', $ids2) : '';\n        }\n\n        if (!empty($updateData)) {\n            $ret = TeamItemMember::update($id, $updateData);\n            return $this->success($response, ['success' => $ret]);\n        }\n\n        return $this->success($response, []);\n    }\n\n    /**\n     * 获取团队项目成员列表（兼容旧接口 Api/TeamItemMember/getList）。\n     */\n    public function getList(Request $request, Response $response): Response\n    {\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $itemId = $this->getParam($request, 'item_id', 0);\n        $teamId = $this->getParam($request, 'team_id', 0);\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        if ($itemId <= 0 || $teamId <= 0) {\n            return $this->error($response, 10101, '参数错误');\n        }\n\n        if (!$this->checkTeamManage($uid, $teamId)) {\n            return $this->error($response, 10103, '没有权限');\n        }\n\n        $ret = TeamItemMember::getListByItemIdAndTeamId($itemId, $teamId);\n        if (!empty($ret)) {\n            return $this->success($response, $ret);\n        }\n\n        return $this->success($response, []);\n    }\n}\n"
  },
  {
    "path": "server/app/Api/Controller/TeamMemberController.php",
    "content": "<?php\n\nnamespace App\\Api\\Controller;\n\nuse App\\Common\\BaseController;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\nuse App\\Model\\TeamMember;\nuse App\\Model\\TeamItem;\nuse App\\Model\\TeamItemMember;\nuse App\\Model\\Team;\nuse App\\Model\\User;\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\n/**\n * 团队成员相关 Api（新架构）。\n */\nclass TeamMemberController extends BaseController\n{\n    /**\n     * 添加和编辑团队成员（兼容旧接口 Api/TeamMember/save）。\n     */\n    public function save(Request $request, Response $response): Response\n    {\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $memberUsername = $this->getParam($request, 'member_username', '');\n        $teamId = $this->getParam($request, 'team_id', 0);\n        $teamMemberGroupId = $this->getParam($request, 'team_member_group_id', 1);\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        if ($teamId <= 0 || empty($memberUsername)) {\n            return $this->error($response, 10101, '参数错误');\n        }\n\n        if (!$this->checkTeamManage($uid, $teamId)) {\n            return $this->error($response, 10103, '没有权限');\n        }\n\n        // 开源版无团队成员数量限制\n        $count = User::getMemberCount($uid);\n\n        // 查找成员用户\n        $memberInfo = User::findByUsernameOrEmail($memberUsername);\n        if (!$memberInfo) {\n            return $this->error($response, 10209, '用户不存在');\n        }\n\n        $memberUid = (int) ($memberInfo->uid ?? 0);\n\n        // 检查是否已经是成员\n        if (TeamMember::exists($teamId, $memberUid)) {\n            return $this->error($response, 10101, '该用户已经是成员');\n        }\n\n        // 添加团队成员\n        $data = [\n            'team_id'            => $teamId,\n            'member_uid'         => $memberUid,\n            'member_username'    => $memberInfo->username ?? '',\n            'team_member_group_id' => $teamMemberGroupId,\n            'addtime'            => time(),\n        ];\n        $id = TeamMember::add($data);\n        if (!$id) {\n            return $this->error($response, 10103, '添加失败');\n        }\n\n        // 检查该团队已经加入了哪些项目，自动添加成员到这些项目\n        $teamItems = TeamItem::getItemIdsByTeamId($teamId);\n        if (!empty($teamItems)) {\n            foreach ($teamItems as $itemId) {\n                $memberData = [\n                    'team_id'        => $teamId,\n                    'member_uid'     => $memberUid,\n                    'member_username' => $memberInfo->username ?? '',\n                    'item_id'        => $itemId,\n                    'member_group_id' => 1, // 默认添加的权限为1，即编辑权限\n                    'addtime'        => time(),\n                ];\n                TeamItemMember::add($memberData);\n            }\n        }\n\n        return $this->success($response, ['id' => $id]);\n    }\n\n    /**\n     * 获取团队成员列表（兼容旧接口 Api/TeamMember/getList）。\n     */\n    public function getList(Request $request, Response $response): Response\n    {\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $teamId = $this->getParam($request, 'team_id', 0);\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        if ($teamId <= 0) {\n            return $this->error($response, 10101, '团队ID不能为空');\n        }\n\n        // 权限判断。团队管理者和团队成员可以看到该列表\n        if (!$this->checkTeamManage($uid, $teamId)) {\n            $member = DB::table('team_member')\n                ->where('member_uid', $uid)\n                ->where('team_id', $teamId)\n                ->first();\n            if (!$member) {\n                return $this->error($response, 10103, '没有权限');\n            }\n        }\n\n        $ret = TeamMember::getListByTeamId($teamId);\n        if (!empty($ret)) {\n            return $this->success($response, $ret);\n        }\n\n        return $this->success($response, []);\n    }\n\n    /**\n     * 删除团队成员（兼容旧接口 Api/TeamMember/delete）。\n     */\n    public function delete(Request $request, Response $response): Response\n    {\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $id = $this->getParam($request, 'id', 0);\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        if ($id <= 0) {\n            return $this->error($response, 10101, '参数错误');\n        }\n\n        $teamMember = TeamMember::findById($id);\n        if (!$teamMember) {\n            return $this->error($response, 10101, '成员不存在');\n        }\n\n        $teamId = (int) ($teamMember->team_id ?? 0);\n        $memberUid = (int) ($teamMember->member_uid ?? 0);\n\n        if (!$this->checkTeamManage($uid, $teamId)) {\n            return $this->error($response, 10103, '没有权限');\n        }\n\n        // 删除团队项目成员关联\n        TeamItemMember::deleteByMemberUidAndTeamId($memberUid, $teamId);\n\n        // 删除团队成员\n        $ret = TeamMember::delete($id);\n        if ($ret) {\n            return $this->success($response, ['success' => true]);\n        }\n\n        return $this->error($response, 10103, '删除失败');\n    }\n}\n"
  },
  {
    "path": "server/app/Api/Controller/TemplateController.php",
    "content": "<?php\n\nnamespace App\\Api\\Controller;\n\nuse App\\Common\\BaseController;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\nuse App\\Model\\Template;\nuse App\\Model\\TemplateItem;\nuse App\\Common\\Helper\\Security;\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\n/**\n * 模板相关 Api（新架构）。\n */\nclass TemplateController extends BaseController\n{\n    /**\n     * 保存模板（兼容旧接口 Api/Template/save）。\n     */\n    public function save(Request $request, Response $response): Response\n    {\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $templateTitle = $this->getParam($request, 'template_title', '');\n        $templateContent = $this->getParam($request, 'template_content', '');\n\n        if (empty($templateTitle)) {\n            return $this->error($response, 10101, '模板标题不能为空');\n        }\n\n        $data = [\n            'username'        => $loginUser['username'] ?? '',\n            'uid'            => (int) ($loginUser['uid'] ?? 0),\n            'template_title' => $templateTitle,\n            'template_content' => $templateContent,\n            'addtime'        => time(),\n        ];\n\n        $id = Template::add($data);\n        if (!$id) {\n            return $this->error($response, 10103, '保存失败');\n        }\n\n        return $this->success($response, ['id' => $id]);\n    }\n\n    /**\n     * 获取我的模板列表（兼容旧接口 Api/Template/getList）。\n     */\n    public function getList(Request $request, Response $response): Response\n    {\n        return $this->getMyList($request, $response);\n    }\n\n    /**\n     * 获取我的模板列表（兼容旧接口 Api/Template/getMyList）。\n     */\n    public function getMyList(Request $request, Response $response): Response\n    {\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n        if ($uid <= 0) {\n            return $this->success($response, []);\n        }\n\n        $ret = Template::getListByUid($uid);\n        if (!empty($ret)) {\n            foreach ($ret as $key => &$value) {\n                $value['addtime'] = date('Y-m-d H:i:s', (int) ($value['addtime'] ?? time()));\n                $value['template_content'] = htmlspecialchars_decode($value['template_content'] ?? '');\n\n                // 获取当前模板被共享到哪些项目中\n                $templateId = (int) ($value['id'] ?? 0);\n                $shareItems = TemplateItem::getListByTemplateId($templateId);\n                $value['share_item'] = $shareItems ?: [];\n                $value['share_item_count'] = count($value['share_item']);\n            }\n            return $this->success($response, $ret);\n        }\n\n        return $this->success($response, []);\n    }\n\n    /**\n     * 获取当前项目的模板列表（兼容旧接口 Api/Template/getItemList）。\n     */\n    public function getItemList(Request $request, Response $response): Response\n    {\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $itemId = $this->getParam($request, 'item_id', 0);\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        if ($itemId <= 0) {\n            return $this->error($response, 10101, '项目ID不能为空');\n        }\n\n        if (!$this->checkItemEdit($uid, $itemId)) {\n            return $this->error($response, 10103, '没有权限');\n        }\n\n        $res = TemplateItem::getListByItemId($itemId);\n        if (!empty($res)) {\n            foreach ($res as $key => &$value) {\n                $value['addtime'] = date('Y-m-d H:i:s', (int) ($value['addtime'] ?? time()));\n                $value['template_content'] = htmlspecialchars_decode($value['template_content'] ?? '');\n            }\n            return $this->success($response, $res);\n        }\n\n        return $this->success($response, []);\n    }\n\n    /**\n     * 删除模板（兼容旧接口 Api/Template/delete）。\n     */\n    public function delete(Request $request, Response $response): Response\n    {\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $id = $this->getParam($request, 'id', 0);\n        $uid = (int) ($loginUser['uid'] ?? 0);\n\n        if ($id <= 0) {\n            return $this->error($response, 10101, '模板ID不能为空');\n        }\n\n        // 验证模板是否属于当前用户\n        $template = Template::findById($id);\n        if (!$template || (int) ($template->uid ?? 0) !== $uid) {\n            return $this->error($response, 10103, '没有权限');\n        }\n\n        // 删除模板及其关联\n        Template::delete($id);\n        TemplateItem::deleteByTemplateId($id);\n\n        return $this->success($response, []);\n    }\n\n    /**\n     * 把模板分享给项目（兼容旧接口 Api/Template/shareToItem）。\n     */\n    public function shareToItem(Request $request, Response $response): Response\n    {\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n        $itemIdStr = $this->getParam($request, 'item_id', '');\n        $templateId = $this->getParam($request, 'template_id', 0);\n\n        if ($templateId <= 0 || empty($itemIdStr)) {\n            return $this->error($response, 10101, '参数错误');\n        }\n\n        // 验证模板是否属于当前用户\n        $template = Template::findById($templateId);\n        if (!$template || (int) ($template->uid ?? 0) !== $uid) {\n            return $this->error($response, 10103, '没有权限');\n        }\n\n        // 转义并分割项目ID\n        $itemIdStr = Security::safeLike($itemIdStr, false);\n        $itemIdArray = explode(',', $itemIdStr);\n\n        // 先删除旧的关联\n        TemplateItem::deleteByTemplateId($templateId);\n\n        // 添加新的关联\n        foreach ($itemIdArray as $value) {\n            $itemId = (int) trim($value);\n            if ($itemId <= 0) {\n                continue;\n            }\n\n            // 检查项目编辑权限\n            if (!$this->checkItemEdit($uid, $itemId)) {\n                return $this->error($response, 10103, \"项目 {$itemId} 没有权限\");\n            }\n\n            // 如果该模板已经分享到该项目中了，跳过\n            if (TemplateItem::exists($templateId, $itemId)) {\n                continue;\n            }\n\n            TemplateItem::add([\n                'template_id' => $templateId,\n                'item_id'     => $itemId,\n                'uid'         => $uid,\n                'username'    => $loginUser['username'] ?? '',\n                'created_at'  => date('Y-m-d H:i:s'),\n            ]);\n        }\n\n        return $this->success($response, []);\n    }\n\n    /**\n     * 获取\"某个模板已经被共享到什么项目中了\"的列表（兼容旧接口 Api/Template/getShareItemList）。\n     */\n    public function getShareItemList(Request $request, Response $response): Response\n    {\n        // 获取登录用户\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $uid = (int) ($loginUser['uid'] ?? 0);\n        $templateId = $this->getParam($request, 'template_id', 0);\n\n        if ($templateId <= 0) {\n            return $this->error($response, 10101, '模板ID不能为空');\n        }\n\n        // 验证模板是否属于当前用户\n        $template = Template::findById($templateId);\n        if (!$template || (int) ($template->uid ?? 0) !== $uid) {\n            return $this->error($response, 10103, '没有权限');\n        }\n\n        $res = TemplateItem::getListByTemplateId($templateId);\n        if (!empty($res)) {\n            return $this->success($response, $res);\n        }\n\n        return $this->success($response, []);\n    }\n}\n"
  },
  {
    "path": "server/app/Api/Controller/UpdateController.php",
    "content": "<?php\n\nnamespace App\\Api\\Controller;\n\nuse App\\Common\\BaseController;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\n\n/**\n * 在线升级控制器\n */\nclass UpdateController extends BaseController\n{\n    /**\n     * 检测数据库并更新\n     * \n     * 由于在 BaseController 的构造函数中已经执行过一次升级了，所以这里不需要动作\n     * 保留着是为了兼容历史接口\n     */\n    public function checkDb(Request $request, Response $response): Response\n    {\n        return $this->success($response, []);\n    }\n\n    /**\n     * 从最新 Docker 镜像中更新代码\n     * \n     * 注意：此方法只能从命令行调用\n     */\n    public function dockerUpdateCode(Request $request, Response $response): Response\n    {\n        if (!preg_match(\"/cli/i\", php_sapi_name())) {\n            return $this->error($response, 10101, '只能从命令行中调用');\n        }\n\n        $showdocPath = \"/var/www/html/\";\n\n        // 进行文件读写权限检查\n        if (\n            !$this->isWriteable($showdocPath)\n            || !$this->isWriteable($showdocPath . \"Sqlite/\")\n            || !$this->isWriteable($showdocPath . \"web/\")\n            || !$this->isWriteable($showdocPath . \"web/index.php\")\n            || !$this->isWriteable($showdocPath . \"server/\")\n            || !$this->isWriteable($showdocPath . \"server/vendor/autoload.php\")\n            || !$this->isWriteable($showdocPath . \"server/app/Api\")\n        ) {\n            return $this->error($response, 10101, '请手动给 showdoc 安装目录下的所有文件可写权限，否则程序无法覆盖旧文件');\n        }\n\n        // 获取当前版本号\n        $composerPath = $showdocPath . \"composer.json\";\n        if (!file_exists($composerPath)) {\n            return $this->error($response, 10101, '无法读取 composer.json');\n        }\n\n        $text = file_get_contents($composerPath);\n        $composer = json_decode($text, true);\n        $curVersion = $composer['version'] ?? '';\n\n        // 获取 Docker 中的版本号\n        $dockerComposerPath = \"/showdoc_data/html/composer.json\";\n        if (!file_exists($dockerComposerPath)) {\n            return $this->error($response, 10101, '无法读取 Docker 中的 composer.json');\n        }\n\n        $text = file_get_contents($dockerComposerPath);\n        $dockerComposer = json_decode($text, true);\n        $versionInDocker = $dockerComposer['version'] ?? '';\n\n        if ($curVersion && $versionInDocker && version_compare($versionInDocker, $curVersion) > 0) {\n            // 获取原来的语言设置\n            $lang = $this->getLang($showdocPath . \"web/index.html\");\n\n            // 复制数据库文件备份\n            $dbPath = $showdocPath . 'Sqlite/showdoc.db.php';\n            if (file_exists($dbPath)) {\n                $bakName = $showdocPath . 'Sqlite/showdoc.db.bak.' . date(\"Y-m-d-H-i-s\") . '.php';\n                copy($dbPath, $bakName);\n            }\n\n            // 目录覆盖\n            $this->copyDir('/showdoc_data/html/', $showdocPath);\n\n            // 用备份的数据库还原\n            if (isset($bakName) && file_exists($bakName)) {\n                copy($bakName, $dbPath);\n            }\n\n            // 恢复语言设置\n            if ($lang == 'en') {\n                $this->replaceFileContent($showdocPath . \"web/index.html\", \"zh-cn\", \"en\");\n                $this->replaceFileContent($showdocPath . \"web_src/index.html\", \"zh-cn\", \"en\");\n            }\n\n            return $this->success($response, []);\n        }\n\n        return $this->success($response, ['message' => '已是最新版本']);\n    }\n\n    /**\n     * 复制目录\n     *\n     * @param string $dirSrc 原目录\n     * @param string $dirTo 目标目录\n     * @return void\n     */\n    private function copyDir(string $dirSrc, string $dirTo): void\n    {\n        if (file_exists($dirTo)) {\n            if (!is_dir($dirTo)) {\n                return;\n            }\n        } else {\n            mkdir($dirTo, 0755, true);\n        }\n\n        $dir = opendir($dirSrc);\n        if (!$dir) {\n            return;\n        }\n\n        while (($filename = readdir($dir)) !== false) {\n            if ($filename != \".\" && $filename != \"..\") {\n                $srcFile = $dirSrc . \"/\" . $filename;\n                $toFile = $dirTo . \"/\" . $filename;\n\n                if (is_dir($srcFile)) {\n                    $this->copyDir($srcFile, $toFile);\n                } else {\n                    copy($srcFile, $toFile);\n                }\n            }\n        }\n\n        closedir($dir);\n    }\n\n    /**\n     * 判断文件/目录是否可写\n     *\n     * @param string $file 文件/目录路径\n     * @return bool\n     */\n    private function isWriteable(string $file): bool\n    {\n        if (is_dir($file)) {\n            $dir = $file;\n            if ($fp = @fopen(\"$dir/test.txt\", 'w')) {\n                @fclose($fp);\n                @unlink(\"$dir/test.txt\");\n                return true;\n            }\n            return false;\n        } else {\n            if ($fp = @fopen($file, 'a+')) {\n                @fclose($fp);\n                return true;\n            }\n            return false;\n        }\n    }\n\n    /**\n     * 替换文件内容\n     *\n     * @param string $file 文件路径\n     * @param string $from 要替换的字符串\n     * @param string $to 替换为的字符串\n     * @return void\n     */\n    private function replaceFileContent(string $file, string $from, string $to): void\n    {\n        if (!file_exists($file)) {\n            return;\n        }\n\n        $content = file_get_contents($file);\n        $content2 = str_replace($from, $to, $content);\n        if ($content2 !== false) {\n            file_put_contents($file, $content2);\n        }\n    }\n\n    /**\n     * 获取语言设置\n     *\n     * @param string $path 文件路径\n     * @return string 语言代码（'zh-cn' 或 'en'）\n     */\n    private function getLang(string $path): string\n    {\n        if (!file_exists($path)) {\n            return 'zh-cn';\n        }\n\n        $content = file_get_contents($path);\n        if (strpos($content, 'lang=\"en\"') !== false || strpos($content, \"lang='en'\") !== false) {\n            return 'en';\n        }\n\n        return 'zh-cn';\n    }\n}\n\n"
  },
  {
    "path": "server/app/Api/Controller/UserController.php",
    "content": "<?php\n\nnamespace App\\Api\\Controller;\n\nuse App\\Common\\BaseController;\nuse App\\Common\\Helper\\Env;\nuse App\\Common\\Helper\\Security;\nuse App\\Model\\Captcha;\nuse App\\Model\\Item;\nuse App\\Model\\User;\nuse App\\Model\\UserToken;\nuse App\\Model\\UserSetting;\nuse App\\Model\\Options;\nuse Illuminate\\Database\\Capsule\\Manager as DB;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\n\nclass UserController extends BaseController\n{\n    /**\n     * 登录接口（用户名/邮箱/手机号 + 密码 + 图形验证码），\n     * 对齐旧版 loginByVerify 的验证码校验逻辑。\n     */\n    public function login(Request $request, Response $response): Response\n    {\n        $username   = $this->getParam($request, 'username', '');\n        $password   = $this->getParam($request, 'password', '');\n        $captchaId  = $this->getParam($request, 'captcha_id', 0);\n        $captchaVal = $this->getParam($request, 'captcha', '');\n\n        if ($username === '' || $password === '') {\n            return $this->error($response, 10101, '用户名或密码不能为空');\n        }\n\n        // 验证码校验（兼容旧版逻辑）\n        if (!Captcha::check($captchaId, $captchaVal)) {\n            return $this->error($response, 10206, '验证码不正确');\n        }\n\n        $user = User::checkLogin($username, $password);\n        \n        // 如果普通登录失败，尝试 LDAP 登录\n        if (!$user) {\n            $user = User::checkLdapLogin($username, $password);\n        }\n\n        if (!$user) {\n            return $this->error($response, 10210, '用户名或密码错误');\n        }\n\n        $uid = (int) $user['uid'];\n\n        // 更新最后登录时间\n        User::setLastTime($uid);\n\n        // 如果用户没有任何项目（包括协作项目），则导入示例项目\n        if (!$this->hasAnyItem($uid)) {\n            try {\n                $this->importSampleProjects($uid);\n            } catch (\\Throwable $e) {\n                error_log(\"Import sample projects failed for user {$uid}: \" . $e->getMessage());\n            }\n        }\n\n        // 生成 token（从 Options 读取 TTL，默认 180 天）\n        $tokenTtlDays = (int) \\App\\Model\\Options::get('token_ttl_days', 180);\n        $tokenTtl = 60 * 60 * 24 * $tokenTtlDays;\n        $token    = UserToken::createToken($uid, $tokenTtl);\n\n        // 构造返回数据（不返回密码/盐）\n        unset($user['password'], $user['salt']);\n\n        $data = [\n            'uid'          => $user['uid'],\n            'username'     => $user['username'],\n            'name'         => $user['name'] ?? '',\n            'groupid'      => $user['groupid'] ?? '',\n            'avatar'       => $user['avatar'] ?? '',\n            'avatar_small' => $user['avatar_small'] ?? '',\n            'email'        => $user['email'] ?? '',\n            'email_verify' => $user['email_verify'] ?? 0,\n            'user_token'   => $token,\n        ];\n\n        return $this->success($response, $data);\n    }\n\n    /**\n     * 兼容旧接口：loginByVerify => 直接复用 login 逻辑。\n     */\n    public function loginByVerify(Request $request, Response $response): Response\n    {\n        return $this->login($request, $response);\n    }\n\n    /**\n     * 获取当前登录用户信息（基于 user_token），返回结构与旧版保持一致。\n     */\n    public function info(Request $request, Response $response): Response\n    {\n        $user = [];\n        if ($error = $this->requireLoginUser($request, $response, $user)) {\n            return $error;\n        }\n\n        $uid = (int) ($user['uid'] ?? 0);\n\n        // 读取完整用户信息，保持与旧版 Api/User/info 字段兼容\n        // 旧版字段：uid,username,email,email_verify,mobile,name,avatar,avatar_small,groupid,reg_time,payment_verify\n        $userFullObj = \\App\\Model\\User::findById($uid);\n        $userFull = $userFullObj ? (array) $userFullObj : [];\n\n\n        // 开源版不支持微信绑定功能，始终返回 0\n        $isWechat = 0;\n\n        $data = [\n            'uid'             => $userFull['uid'] ?? $uid,\n            'username'        => $userFull['username'] ?? '',\n            'email'           => $userFull['email'] ?? '',\n            'email_verify'    => $userFull['email_verify'] ?? 0,\n            'mobile'          => $userFull['mobile'] ?? '',\n            'name'            => $userFull['name'] ?? '',\n            'avatar'          => $userFull['avatar'] ?? '',\n            'avatar_small'    => $userFull['avatar_small'] ?? '',\n            'groupid'         => $userFull['groupid'] ?? '',\n            'reg_time'        => $userFull['reg_time'] ?? '',\n            'payment_verify'  => $userFull['payment_verify'] ?? 0,\n            'is_wechat'       => $isWechat,\n        ];\n\n        return $this->success($response, $data);\n    }\n\n    /**\n     * 获取所有用户名列表（兼容旧接口 Api/User/allUser）。\n     */\n    public function allUser(Request $request, Response $response): Response\n    {\n        $loginUser = [];\n        if ($error = $this->requireLoginUser($request, $response, $loginUser)) {\n            return $error;\n        }\n\n        $username = $this->getParam($request, 'username', '');\n\n        $query = DB::table('user')\n            ->select(['username', 'uid', 'name']);\n\n        if ($username !== '') {\n            $like = Security::safeLike($username);\n            $query->where('username', 'like', \"%{$like}%\");\n        }\n\n        $list = $query->get()->all();\n\n        return $this->success($response, $list ?: []);\n    }\n\n    /**\n     * 注册接口（带图形验证码），对齐旧版 registerByVerify 的核心流程：\n     * - 校验验证码\n     * - 校验密码长度与确认密码\n     * - 检查用户名是否已存在\n     * - 创建用户并自动登录，返回 user_token\n     */\n    public function registerByVerify(Request $request, Response $response): Response\n    {\n        $username         = trim($this->getParam($request, 'username', ''));\n        $password         = $this->getParam($request, 'password', '');\n        $confirmPassword  = $this->getParam($request, 'confirm_password', '');\n        $captchaId        = $this->getParam($request, 'captcha_id', 0);\n        $captchaVal       = $this->getParam($request, 'captcha', '');\n        $inviteCode       = trim($this->getParam($request, 'invite_code', ''));\n\n        // 检查管理员是否关闭了注册（对齐旧架构逻辑）\n        $registerOpen = \\App\\Model\\Options::get('register_open');\n        if ($registerOpen === '0') {\n            return $this->error($response, 10101, '管理员已关闭注册');\n        }\n\n        if ($username === '' || $password === '') {\n            return $this->error($response, 10101, '用户名或密码不能为空');\n        }\n\n        if (strlen($password) > 100) {\n            return $this->error($response, 10101, '密码过长');\n        }\n\n        // 验证密码强度\n        $passwordValidation = Security::validateStrongPassword($password);\n        if (!$passwordValidation['valid']) {\n            return $this->error($response, 10101, $passwordValidation['message']);\n        }\n\n        if ($password !== $confirmPassword) {\n            return $this->error($response, 10101, '两次输入的密码不一致');\n        }\n\n        // 验证码校验\n        if (!Captcha::check($captchaId, $captchaVal)) {\n            return $this->error($response, 10206, '验证码不正确');\n        }\n\n        // 用户是否已存在\n        if (User::isExist($username)) {\n            return $this->error($response, 10101, '用户名已存在');\n        }\n\n        // 创建用户\n        $uid = User::register($username, $password);\n        if (!$uid) {\n            return $this->error($response, 10101, '注册失败，请稍后重试');\n        }\n\n        // 暂停 600 毫秒，以便应对主从数据库同步延迟\n        usleep(600000);\n\n        // 注册成功后，为开源版用户导入示例项目（对齐旧开源版逻辑）\n        try {\n            $createSample = Options::get('create_sample');\n\n            // 获取后台语言配置（旧版通过 Home 模块 config 判断是否为简体中文）\n            // 说明：运行时工作目录仍为 server 根目录，因此保持旧路径即可\n            $configPath = './Application/Home/Conf/config.php';\n            $config     = @file_get_contents($configPath);\n\n            if ($createSample !== '0' && $config !== false && strpos($config, \"'zh-cn',\") !== false) {\n                // 导入示例项目（失败不影响注册主流程）\n                $this->importSampleProjects($uid);\n            }\n        } catch (\\Throwable $e) {\n            // 示例导入失败不影响注册成功，仅记录日志\n            error_log(\"Import sample projects failed for user {$uid}: \" . $e->getMessage());\n        }\n\n        // 读取用户信息\n        $userObj = User::findById($uid);\n        if (!$userObj) {\n            return $this->error($response, 10101, '注册成功但读取用户信息失败');\n        }\n\n        $user = (array) $userObj;\n        unset($user['password'], $user['salt']);\n\n        // 自动登录：生成 token（从 Options 读取 TTL，默认 180 天）\n        $tokenTtlDays = (int) \\App\\Model\\Options::get('token_ttl_days', 180);\n        $tokenTtl = 60 * 60 * 24 * $tokenTtlDays;\n        $token    = UserToken::createToken($uid, $tokenTtl);\n\n        // 如果用户名是邮箱格式，则更新 email 字段\n        if (preg_match(\"/([\\w\\-]+\\@[\\w\\-]+\\.[\\w\\-]+)/\", $username)) {\n            // 更新用户的 email 字段\n            DB::table('user')\n                ->where('uid', $uid)\n                ->update(['email' => $username]);\n        }\n\n\n        // 重新读取用户信息（可能已更新 email 字段）\n        $userObj = User::findById($uid);\n        if ($userObj) {\n            $user = (array) $userObj;\n            unset($user['password'], $user['salt']);\n        }\n\n        $data = [\n            'uid'          => $user['uid'],\n            'username'     => $user['username'],\n            'name'         => $user['name'] ?? '',\n            'groupid'      => $user['groupid'] ?? '',\n            'avatar'       => $user['avatar'] ?? '',\n            'avatar_small' => $user['avatar_small'] ?? '',\n            'email'        => $user['email'] ?? '',\n            'email_verify' => $user['email_verify'] ?? 0,\n            'user_token'   => $token,\n        ];\n\n        return $this->success($response, $data);\n    }\n\n    /**\n     * 检查用户是否有任何项目（包括自己创建的、作为成员的、作为团队成员的）\n     */\n    private function hasAnyItem(int $uid): bool\n    {\n        if (DB::table('item')->where('uid', $uid)->where('is_del', 0)->count() > 0) {\n            return true;\n        }\n        if (DB::table('item_member')->where('item_member.uid', $uid)->join('item', 'item.item_id', '=', 'item_member.item_id')->where('item.is_del', 0)->count() > 0) {\n            return true;\n        }\n        return DB::table('team_item_member')->where('member_uid', $uid)->join('item', 'item.item_id', '=', 'team_item_member.item_id')->where('item.is_del', 0)->count() > 0;\n    }\n\n    /**\n     * 导入示例项目（开源版）\n     *\n     * 参考旧开源版 UserController::_importSample/_importZip 实现，\n     * 从 Public/SampleZip 目录读取若干 ZIP 包并导入为项目。\n     */\n    private function importSampleProjects(int $uid): void\n    {\n        $files = [\n            '../Public/SampleZip/apidoc.zip',\n            '../Public/SampleZip/databasedoc.zip',\n            '../Public/SampleZip/teamdoc.zip',\n            '../Public/SampleZip/spreadsheet.zip',\n            '../Public/SampleZip/whiteboard.zip',\n        ];\n\n        foreach ($files as $file) {\n            $this->importSampleZip($file, $uid);\n        }\n    }\n\n    /**\n     * 从单个 ZIP 中导入示例项目\n     *\n     * @param string $file ZIP 文件相对路径\n     * @param int    $uid  目标用户 ID\n     * @return bool 是否导入成功\n     */\n    private function importSampleZip(string $file, int $uid): bool\n    {\n        if (!is_file($file)) {\n            return false;\n        }\n\n        $zip = new \\ZipArchive();\n        $ret = $zip->open($file, \\ZipArchive::CREATE);\n        if ($ret !== true) {\n            return false;\n        }\n\n        // 先尝试新的格式 info.json，如果不存在则尝试旧的格式 prefix_info.json\n        $info = $zip->getFromName('info.json');\n        if (!$info) {\n            $info = $zip->getFromName('prefix_info.json');\n        }\n        $zip->close();\n\n        if (!$info) {\n            return false;\n        }\n\n        $infoArray = json_decode($info, true);\n        if (!$infoArray) {\n            return false;\n        }\n\n        $json = json_encode($infoArray, JSON_UNESCAPED_UNICODE);\n        $result = Item::import($json, $uid, 0);\n        \n        return $result > 0;\n    }\n\n    /**\n     * 旧接口 register：内部直接复用 registerByVerify 逻辑（保持兼容）。\n     */\n    public function register(Request $request, Response $response): Response\n    {\n        return $this->registerByVerify($request, $response);\n    }\n\n    /**\n     * 通过旧密码验证来更新用户密码（新实现，不依赖旧 session）。\n     */\n    public function resetPassword(Request $request, Response $response): Response\n    {\n        $user = [];\n        if ($error = $this->requireLoginUser($request, $response, $user)) {\n            return $error;\n        }\n        $uid = (int) ($user['uid'] ?? 0);\n\n        $password    = $this->getParam($request, 'password', '');\n        $newPassword = $this->getParam($request, 'new_password', '');\n\n        if ($newPassword === '') {\n            return $this->error($response, 10101, '新密码不能为空');\n        }\n        if (strlen($newPassword) > 100) {\n            return $this->error($response, 10101, '密码过长');\n        }\n\n        // 验证密码强度\n        $passwordValidation = Security::validateStrongPassword($newPassword);\n        if (!$passwordValidation['valid']) {\n            return $this->error($response, 10101, $passwordValidation['message']);\n        }\n\n        // 获取当前用户用户名\n        $username = $user['username'] ?? '';\n        if ($username === '') {\n            return $this->error($response, 10102, '用户数据异常');\n        }\n\n        // 验证旧密码\n        $ret = User::checkLogin($username, $password);\n        if (!$ret) {\n            return $this->error($response, 10101, '旧密码错误');\n        }\n\n        // 更新密码\n        $ok = User::updatePwd($uid, $newPassword);\n        if (!$ok) {\n            return $this->error($response, 10101, '修改失败');\n        }\n\n        // 清除该用户所有 token\n        DB::table('user_token')\n            ->where('uid', $uid)\n            ->update(['token' => '']);\n\n        return $this->success($response, []);\n    }\n\n    /**\n     * 简单资料修改：目前仅支持修改 name。\n     */\n    public function updateInfo(Request $request, Response $response): Response\n    {\n        $user = [];\n        if ($error = $this->requireLoginUser($request, $response, $user)) {\n            return $error;\n        }\n        $uid = (int) ($user['uid'] ?? 0);\n\n        $name = $this->getParam($request, 'name', '');\n\n        DB::table('user')\n            ->where('uid', $uid)\n            ->update(['name' => $name]);\n\n        return $this->success($response, []);\n    }\n\n    /**\n     * 登出接口：基于 user_token 清除用户所有 token 记录，幂等。\n     */\n    public function logout(Request $request, Response $response): Response\n    {\n        $uid = 0;\n        // 登出接口对无 token/无效 token 容忍度更高：仅在有合法 uid 时清 token，其余也返回成功\n        $this->requireUserFromToken($request, $response, $uid, false);\n        if ($uid > 0) {\n            DB::table('user_token')\n                ->where('uid', $uid)\n                ->update(['token' => '']);\n        }\n\n        // 不论是否找到 token，都返回成功，保证幂等\n        return $this->success($response, []);\n    }\n\n    /**\n     * 获取用户的推送地址（兼容旧接口 Api/User/getPushUrl）。\n     */\n    public function getPushUrl(Request $request, Response $response): Response\n    {\n        $user = [];\n        if ($error = $this->requireLoginUser($request, $response, $user)) {\n            return $error;\n        }\n\n        $uid = (int) ($user['uid'] ?? 0);\n        $pushUrl = UserSetting::getPushUrl($uid) ?? '';\n\n        // 与旧接口保持语义一致：返回结构 { error_code: 0, data: { push_url: \"...\" } }\n        return $this->success($response, [\n            'push_url' => $pushUrl,\n        ]);\n    }\n\n    /**\n     * 保存用户的推送地址（兼容旧接口 Api/User/savePushUrl）。\n     */\n    public function savePushUrl(Request $request, Response $response): Response\n    {\n        $user = [];\n        if ($error = $this->requireLoginUser($request, $response, $user)) {\n            return $error;\n        }\n\n        $uid = (int) ($user['uid'] ?? 0);\n        $pushUrl = $this->getParam($request, 'push_url', '');\n\n        UserSetting::savePushUrl($uid, $pushUrl);\n\n        return $this->success($response, []);\n    }\n\n    /**\n     * OAuth 配置信息（兼容旧接口 Api/User/oauthInfo）。\n     */\n    public function oauthInfo(Request $request, Response $response): Response\n    {\n        $oauth2Open = Options::get('oauth2_open');\n        $oauth2Form = Options::get('oauth2_form');\n        $oauth2EntranceTips = '';\n\n        if ($oauth2Form) {\n            $decoded = json_decode(htmlspecialchars_decode((string) $oauth2Form), true);\n            if (is_array($decoded) && !empty($decoded['entrance_tips'])) {\n                $oauth2EntranceTips = (string) $decoded['entrance_tips'];\n            }\n        }\n\n        return $this->success($response, [\n            'oauth2_open'          => $oauth2Open,\n            'oauth2_entrance_tips' => $oauth2EntranceTips,\n        ]);\n    }\n\n}\n"
  },
  {
    "path": "server/app/Common/BaseController.php",
    "content": "<?php\n\nnamespace App\\Common;\n\nuse App\\Model\\User;\nuse App\\Model\\UserToken;\nuse App\\Common\\Helper\\IpHelper;\nuse App\\Common\\Helper\\Security;\nuse Illuminate\\Database\\Capsule\\Manager as DB;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\n\nabstract class BaseController\n{\n    /**\n     * 获取请求参数（兼容旧版 ThinkPHP I 方法的行为）。\n     * \n     * 参数获取优先级：路径参数 > POST Body（表单/JSON）> GET 参数\n     * \n     * 兼容性说明：\n     * - 支持表单提交（application/x-www-form-urlencoded）：通过 Slim BodyParsingMiddleware 自动解析到 getParsedBody()\n     * - 支持 JSON 提交（application/json）：通过 Slim BodyParsingMiddleware 自动解析到 getParsedBody()\n     * - 支持 GET 参数：通过 getQueryParams() 获取\n     * - 支持路径参数：通过 getAttribute() 获取（如 /api/user/{id} 中的 id）\n     * \n     * 与旧版 I 方法的对应关系：\n     * - I(\"post.xxx\") 或 I(\"xxx\")（POST 请求）-> getParam($request, 'xxx')（从 getParsedBody 获取）\n     * - I(\"get.xxx\") 或 I(\"xxx\")（GET 请求）-> getParam($request, 'xxx')（从 getQueryParams 获取）\n     * - I(\"xxx\")（JSON 请求）-> getParam($request, 'xxx')（从 getParsedBody 获取，BodyParsingMiddleware 已解析）\n     * \n     * 根据默认值的类型做简单类型转换，减少调用处的显式 (string)/(int)。\n     * \n     * 注意：此方法返回原始值，不进行 HTML 转义。遵循\"在输出时转义\"的最佳实践。\n     * 如需输出到 HTML，请在输出时使用 htmlspecialchars() 进行转义。\n     * \n     * @param Request $request 请求对象\n     * @param string $key 参数名\n     * @param mixed $default 默认值\n     * @return mixed 参数值（原始值，未转义）\n     */\n    protected function getParam(Request $request, string $key, $default = null)\n    {\n        // 1. 优先从路径参数获取（如 /api/user/{id} 中的 id）\n        $value = $request->getAttribute($key);\n\n        // 2. 如果路径参数不存在，从 POST Body 获取（包含表单和 JSON）\n        // Slim 的 BodyParsingMiddleware 会自动解析：\n        // - application/x-www-form-urlencoded -> 解析为数组\n        // - application/json -> 解析为数组\n        if ($value === null) {\n            $parsedBody = $request->getParsedBody() ?: [];\n            if (is_array($parsedBody) && array_key_exists($key, $parsedBody)) {\n                $value = $parsedBody[$key];\n            }\n        }\n\n        // 3. 如果 POST Body 中也没有，从 GET 参数获取\n        if ($value === null) {\n            $query = $request->getQueryParams();\n            if (array_key_exists($key, $query)) {\n                $value = $query[$key];\n            }\n        }\n\n        if ($value === null) {\n            return $default;\n        }\n\n        // 没有提供默认值时，不做强制类型转换\n        if ($default === null) {\n            return $value;\n        }\n\n        // 根据默认值类型做轻量级转换\n        switch (gettype($default)) {\n            case 'string':\n                return (string) $value;\n            case 'integer':\n                // 如果是布尔值或者字符串 true ，则应该转为1 \n                if (is_bool($value)) {\n                    return $value ? 1 : 0;\n                }\n                return is_numeric($value) ? (int) $value : (int) $default;\n            case 'double':\n                return is_numeric($value) ? (float) $value : (float) $default;\n            case 'boolean':\n                // 常见布尔字符串处理\n                if (is_bool($value)) {\n                    return $value;\n                }\n                $lower = strtolower((string) $value);\n                if (in_array($lower, ['1', 'true', 'on', 'yes'], true)) {\n                    return true;\n                }\n                if (in_array($lower, ['0', 'false', 'off', 'no'], true)) {\n                    return false;\n                }\n                return (bool) $default;\n            case 'array':\n                return is_array($value) ? $value : $default;\n            default:\n                return $value;\n        }\n    }\n\n    /**\n     * 检查是否是管理员\n     *\n     * @param Request $request 请求对象\n     * @param Response|null $response 响应对象（用于返回错误）\n     * @param bool $redirect 是否在未授权时返回错误响应\n     * @return bool|Response 如果是管理员返回 true，否则返回 false 或错误响应\n     */\n    protected function checkAdmin(Request $request, ?Response $response = null, bool $redirect = true)\n    {\n        // 获取登录用户\n        $loginUser = [];\n        if ($response && ($error = $this->requireLoginUser($request, $response, $loginUser))) {\n            if ($redirect) {\n                return $this->error($response, 10103, '需要管理员权限');\n            }\n            return false;\n        } elseif (!$response) {\n            // 如果没有提供 response，使用 requireUserFromToken\n            $uid = 0;\n            $dummyResponse = new \\Slim\\Psr7\\Response();\n            $this->requireUserFromToken($request, $dummyResponse, $uid, false);\n            if ($uid <= 0) {\n                return false;\n            }\n            $user = \\App\\Model\\User::findById($uid);\n            if (!$user) {\n                return false;\n            }\n            $loginUser = (array) $user;\n        }\n\n        // 检查 groupid 是否为 1（管理员，与旧代码逻辑一致：$login_user['groupid'] == 1）\n        $groupid = $loginUser['groupid'] ?? 0;\n        if ($groupid == 1) {\n            return true;\n        }\n\n        if ($redirect && $response) {\n            return $this->error($response, 10103, '需要管理员权限');\n        }\n\n        return false;\n    }\n\n    /**\n     * 将大整数转换为字符串，避免 JavaScript 精度丢失问题。\n     * \n     * JavaScript 的 Number.MAX_SAFE_INTEGER 是 9007199254740991 (2^53 - 1)，\n     * 超过这个值的整数在 JavaScript 中会丢失精度。\n     * 因此，将所有大于该值的整数转换为字符串，确保前端能正确处理。\n     * \n     * 注意：只检查 JSON 的前三级（顶层、第一级和第二级嵌套），达到深度限制后退出递归，避免性能影响。\n     * \n     * @param mixed $data 要处理的数据（可以是数组、对象或标量值）\n     * @param int $depth 当前递归深度，默认为 0\n     * @return mixed 处理后的数据\n     */\n    private function convertLargeIntegersToString($data, int $depth = 0)\n    {\n        // JavaScript 的最大安全整数：2^53 - 1 = 9007199254740991\n        $maxSafeInteger = 9007199254740991;\n\n        // 先检查是否是大整数（无论深度如何，都要转换大整数）\n        if (is_int($data) && $data > $maxSafeInteger) {\n            return (string) $data;\n        }\n\n        // 只处理前三级，达到深度限制后直接返回\n        if ($depth >= 3) {\n            return $data;\n        }\n\n        if (is_array($data)) {\n            $result = [];\n            foreach ($data as $key => $value) {\n                $result[$key] = $this->convertLargeIntegersToString($value, $depth + 1);\n            }\n            return $result;\n        } elseif (is_object($data)) {\n            // 处理对象（stdClass 等）\n            $result = new \\stdClass();\n            foreach ($data as $key => $value) {\n                $result->$key = $this->convertLargeIntegersToString($value, $depth + 1);\n            }\n            return $result;\n        } else {\n            // 其他类型（字符串、浮点数、布尔值、null 等）保持不变\n            return $data;\n        }\n    }\n\n    /**\n     * 返回 JSON 响应（底层通用封装）。\n     * \n     * 注意：json_encode() 会自动转义特殊字符，所以 JSON 响应本身是安全的。\n     * 但如果前端将 JSON 数据直接插入到 HTML DOM 中（如 innerHTML），\n     * 前端需要自行进行 HTML 转义。\n     * \n     * 在输出前会对 JSON 字符串进行敏感词替换（与旧代码 BaseController::sendResult 逻辑一致）。\n     * 使用 JSON_UNESCAPED_UNICODE 确保中文字符不会被转义，保证替换的准确性。\n     * \n     * 自动处理大整数：将所有大于 JavaScript MAX_SAFE_INTEGER (9007199254740991) 的整数\n     * 转换为字符串，避免 JavaScript 精度丢失问题。\n     */\n    protected function json(Response $response, $data, int $status = 200): Response\n    {\n        // 自动将大整数转换为字符串，避免 JavaScript 精度丢失\n        $data = $this->convertLargeIntegersToString($data);\n\n        // JSON_UNESCAPED_UNICODE 参数是为了防止中文乱码（与旧代码一致）\n        $payload = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);\n\n        // 开源版不需要敏感词过滤功能\n\n        $response->getBody()->write($payload);\n\n        return $response\n            ->withHeader('Content-Type', 'application/json')\n            ->withStatus($status);\n    }\n\n    /**\n     * 转义字符串用于 HTML 输出（防止 XSS 攻击）。\n     * \n     * 用于需要输出到 HTML 内容的场景。\n     * \n     * @param string $string 要转义的字符串\n     * @return string 转义后的字符串\n     */\n    protected function escapeHtml(string $string): string\n    {\n        return htmlspecialchars($string, ENT_QUOTES, 'UTF-8');\n    }\n\n    /**\n     * 转义字符串用于 HTML 属性（防止 XSS 攻击）。\n     * \n     * 用于 HTML 属性值的场景，如 <input value=\"...\">\n     * \n     * @param string $string 要转义的字符串\n     * @return string 转义后的字符串\n     */\n    protected function escapeHtmlAttr(string $string): string\n    {\n        return htmlspecialchars($string, ENT_QUOTES, 'UTF-8');\n    }\n\n    /**\n     * 转义字符串用于 URL 参数。\n     * \n     * @param string $string 要转义的字符串\n     * @return string 转义后的字符串\n     */\n    protected function escapeUrl(string $string): string\n    {\n        return urlencode($string);\n    }\n\n    /**\n     * 转义字符串用于 JavaScript 代码。\n     * \n     * @param string $string 要转义的字符串\n     * @return string 转义后的字符串（JSON 编码）\n     */\n    protected function escapeJs(string $string): string\n    {\n        return json_encode($string, JSON_UNESCAPED_UNICODE);\n    }\n\n    /**\n     * 业务成功统一返回结构：\n     * { \"error_code\": 0, \"data\": {...} }\n     * \n     * @param Response $response 响应对象\n     * @param mixed $data 返回数据，可以是数组、字符串或其他可序列化的类型\n     * @param int $status HTTP 状态码\n     * @return Response\n     */\n    protected function success(Response $response, $data = [], int $status = 200): Response\n    {\n        return $this->json($response, [\n            'error_code' => 0,\n            'data' => $data,\n        ], $status);\n    }\n\n    /**\n     * 业务错误统一返回结构：\n     * { \"error_code\": <int>, \"error_message\": \"<string>\", ...extra }\n     *\n     * @param Response $response 响应对象\n     * @param int $code 错误码\n     * @param string|null $message 错误消息，如果为 null 或空字符串则从 ErrorCodes 配置中获取\n     * @param int $status HTTP 状态码\n     * @param array $extra 额外的响应数据\n     * @return Response\n     */\n    protected function error(\n        Response $response,\n        int $code,\n        ?string $message = null,\n        int $status = 200,\n        array $extra = []\n    ): Response {\n        // 如果未提供消息或消息为空，从配置中获取\n        if ($message === null || $message === '') {\n            $message = \\App\\Common\\Config\\ErrorCodes::getMessage($code);\n        }\n\n        $body = array_merge([\n            'error_code' => $code,\n            'error_message' => $message,\n        ], $extra);\n\n        return $this->json($response, $body, $status);\n    }\n\n    /**\n     * 从请求中提取用户 Token（Header 优先，兼容 GET/POST 参数）。\n     */\n    protected function getToken(Request $request): ?string\n    {\n        // 1. X-API-Token 头\n        $token = trim($request->getHeaderLine('X-API-Token'));\n        if ($token !== '') {\n            return $token;\n        }\n\n        // 2. Authorization: Bearer xxx\n        $auth = $request->getHeaderLine('Authorization');\n        if ($auth !== '') {\n            if (preg_match('/Bearer\\s+(.+)/i', $auth, $m)) {\n                return trim($m[1]);\n            }\n        }\n\n        // 3. user_token 参数（POST/GET）\n        $token = (string) $this->getParam($request, 'user_token', '');\n        $token = trim($token);\n        return $token !== '' ? $token : null;\n    }\n\n    /**\n     * 从 user_token 中解析出当前用户 uid 的公共逻辑。\n     *\n     * @param int  $uid            解析出的用户 ID（引用传递）\n     * @param bool $strictOnError  是否严格返回错误（登出等场景可用 false）\n     *\n     * @return Response|null  出错时返回 Response；成功时返回 null 并填充 $uid\n     */\n    protected function requireUserFromToken(\n        Request $request,\n        Response $response,\n        int &$uid,\n        bool $strictOnError = true\n    ): ?Response {\n        $token = $this->getToken($request);\n        if ($token === null) {\n            if ($strictOnError) {\n                // 业务级错误：HTTP 始终 200，仅通过 error_code 表达未登录\n                return $this->error($response, 10102, '未提供用户 Token');\n            }\n            $uid = 0;\n            return null;\n        }\n\n        $tokenRow = UserToken::getToken($token);\n        if (!$tokenRow || empty($tokenRow['uid'])) {\n            if ($strictOnError) {\n                return $this->error($response, 10102, 'Token 无效或已过期');\n            }\n            $uid = 0;\n            return null;\n        }\n\n        $parsedUid = (int) ($tokenRow['uid'] ?? 0);\n        if ($parsedUid <= 0) {\n            if ($strictOnError) {\n                return $this->error($response, 10102, 'Token 无效');\n            }\n            $uid = 0;\n            return null;\n        }\n\n        $uid = $parsedUid;\n        return null;\n    }\n\n    /**\n     * 从 token 中获取当前登录用户的完整信息（等价于新世界的 checkLogin）。\n     *\n     * @param array $user          解析出的用户信息（引用传递，已去除密码/盐）\n     * @param bool  $strictOnError 是否严格返回错误；为 false 时，失败仅使 $user 为空数组\n     *\n     * @return Response|null 出错时返回 Response；成功时返回 null 并填充 $user\n     */\n    protected function requireLoginUser(\n        Request $request,\n        Response $response,\n        array &$user,\n        bool $strictOnError = true\n    ): ?Response {\n        $uid = 0;\n        if ($error = $this->requireUserFromToken($request, $response, $uid, $strictOnError)) {\n            return $error;\n        }\n\n        if ($uid <= 0) {\n            // 非严格模式，调用方自行判断\n            $user = [];\n            return null;\n        }\n\n        $userObj = User::findById($uid);\n        if (!$userObj) {\n            if ($strictOnError) {\n                return $this->error($response, 10102, '用户不存在');\n            }\n            $user = [];\n            return null;\n        }\n\n        $arr = (array) $userObj;\n        unset($arr['password'], $arr['salt']);\n\n        $user = $arr;\n        return null;\n    }\n\n    /**\n     * 判断某用户是否有项目管理权限（项目创建者、项目单独管理员、团队中的项目管理员，系统管理员）。\n     *\n     * @param int $uid     用户 ID\n     * @param int $itemId  项目 ID\n     *\n     * @return bool\n     */\n    protected function checkItemManage(int $uid, int $itemId): bool\n    {\n        // 与旧代码逻辑一致：先检查 uid 是否存在\n        if (!$uid) {\n            return false;\n        }\n        $uid = (int) $uid;\n        $itemId = (int) $itemId;\n\n        // 检查是否是项目创建者（与旧代码逻辑一致：$item['uid'] && $item['uid'] == $uid）\n        $item = \\App\\Model\\Item::findById($itemId);\n        if (!$item) {\n            return false;\n        }\n        if ($item->uid && (int) $item->uid == $uid) {\n            return true;\n        }\n\n        // 检查是否是项目单独管理员（member_group_id = 2）\n        $member = DB::table('item_member')\n            ->where('item_id', $itemId)\n            ->where('uid', $uid)\n            ->where('member_group_id', 2)\n            ->first();\n        if ($member) {\n            return true;\n        }\n\n        // 检查是否是团队中的项目管理员\n        $teamMember = DB::table('team_item_member')\n            ->where('item_id', $itemId)\n            ->where('member_uid', $uid)\n            ->where('member_group_id', 2)\n            ->first();\n        if ($teamMember) {\n            return true;\n        }\n\n        // 检查是否是系统管理员（与旧代码逻辑一致：checkAdmin(false)，直接检查用户 groupid）\n        $user = \\App\\Model\\User::findById($uid);\n        if ($user && ($user->groupid ?? 0) == 1) {\n            return true;\n        }\n\n        return false;\n    }\n\n    /**\n     * 判断某用户是否有项目编辑权限（项目成员 member_group_id 为 1，是项目所在团队的成员并且成员权限为 1，\n     * 以及项目管理者、创建者和系统管理员）。\n     *\n     * @param int $uid     用户 ID\n     * @param int $itemId  项目 ID\n     *\n     * @return bool\n     */\n    protected function checkItemEdit(int $uid, int $itemId): bool\n    {\n        // 与旧代码逻辑一致：先检查 uid 是否存在\n        if (!$uid) {\n            return false;\n        }\n\n        // 检查是否是项目创建者（与旧代码逻辑一致：$item['uid'] && $item['uid'] == $uid）\n        $item = \\App\\Model\\Item::findById($itemId);\n        if ($item && $item->uid && (int) $item->uid == $uid) {\n            return true;\n        }\n\n        // 检查是否是项目编辑成员（member_group_id = 1）\n        $ItemMember = DB::table('item_member')\n            ->where('item_id', $itemId)\n            ->where('uid', $uid)\n            ->where('member_group_id', 1)\n            ->first();\n        if ($ItemMember) {\n            return true;\n        }\n\n        // 检查是否是团队中的编辑成员\n        $ItemMember = DB::table('team_item_member')\n            ->where('item_id', $itemId)\n            ->where('member_uid', $uid)\n            ->where('member_group_id', 1)\n            ->first();\n        if ($ItemMember) {\n            return true;\n        }\n\n        // 如果有管理权限，也自动拥有编辑权限\n        if ($this->checkItemManage($uid, $itemId)) {\n            return true;\n        }\n\n        return false;\n    }\n\n    /**\n     * 检查用户是否有项目访问权限（包括公开项目、白名单、成员等）。\n     *\n     * @param int    $uid      用户 ID（0 表示游客）\n     * @param int    $itemId   项目 ID\n     * @param string $referUrl 来源 URL（可选）\n     *\n     * @return bool\n     */\n    protected function checkItemVisit(int $uid, int $itemId, string $referUrl = ''): bool\n    {\n        // 检查管理权限（包括项目创建者）\n        $hasManage = $this->checkItemManage($uid, $itemId);\n        if ($hasManage) {\n            return true;\n        }\n\n        // 检查是否是项目成员（任何权限级别）\n        if ($uid > 0) {\n            $ItemMember = DB::table('item_member')\n                ->where('item_id', $itemId)\n                ->where('uid', $uid)\n                ->first();\n            if ($ItemMember) {\n                return true;\n            }\n\n            $TeamItemMember = DB::table('team_item_member')\n                ->where('item_id', $itemId)\n                ->where('member_uid', $uid)\n                ->first();\n            if ($TeamItemMember) {\n                return true;\n            }\n        }\n\n        // 检查项目密码（与旧代码逻辑一致：如果有密码且密码不匹配，返回 false；否则返回 true）\n        $item = \\App\\Model\\Item::findById($itemId);\n        if (!$item) {\n            return false;\n        }\n\n        // 与旧代码逻辑一致：如果有密码，需要验证密码\n        // 旧代码：if ($item['password'] && $item['password'] != I('_item_pwd')) { return false; } else { return true; }\n        // _item_pwd 参数的作用：跨域请求时无法带 cookies，自然无法记住 session。用这个参数使记住用户输入过项目密码。\n        if ($item->password && $item->password != ($_REQUEST['_item_pwd'] ?? '')) {\n            // 有密码且密码不匹配，返回 false\n            return false;\n        } else {\n            // 无密码，或者有密码且密码匹配，返回 true\n            return true;\n        }\n    }\n\n    /**\n     * 判断某用户是否有团队管理权限（团队创建者、团队管理员、系统管理员）。\n     *\n     * @param int $uid    用户 ID\n     * @param int $teamId 团队 ID\n     *\n     * @return bool\n     */\n    protected function checkTeamManage(int $uid, int $teamId): bool\n    {\n        // 与旧代码逻辑一致：先检查 uid 是否存在\n        if (!$uid) {\n            return false;\n        }\n\n        // 检查是否是团队创建者（与旧代码逻辑一致：$team['uid'] && $team['uid'] == $uid）\n        $team = DB::table('team')\n            ->where('id', $teamId)\n            ->first();\n        if ($team && $team->uid && (int) $team->uid == $uid) {\n            return true;\n        }\n\n        // 检查是否是团队管理员（team_member_group_id = 2）\n        $team_member = DB::table('team_member')\n            ->where('team_id', $teamId)\n            ->where('member_uid', $uid)\n            ->where('team_member_group_id', 2)\n            ->first();\n        if ($team_member) {\n            return true;\n        }\n\n        // 检查是否是系统管理员（与旧代码逻辑一致：checkAdmin(false)，直接检查用户 groupid）\n        $user = \\App\\Model\\User::findById($uid);\n        if ($user && ($user->groupid ?? 0) == 1) {\n            return true;\n        }\n\n        return false;\n    }\n\n    /**\n     * 获取客户端 IP 地址（兼容旧接口 getIPaddress）\n     *\n     * @return string IP 地址\n     */\n    protected function getIPaddress(): string\n    {\n        return IpHelper::getClientIp();\n    }\n\n\n    /**\n     * 安全处理 LIKE 查询关键字（兼容旧接口 safe_like）\n     *\n     * @param string $keyword 关键字\n     * @param bool $strict 是否严格模式\n     * @return string 处理后的关键字\n     */\n    protected function safeLike(string $keyword, bool $strict = true): string\n    {\n        return Security::safeLike($keyword, $strict);\n    }\n}\n"
  },
  {
    "path": "server/app/Common/BotDetector.php",
    "content": "<?php\n\n/**\n * 爬虫检测工具类\n * 用于检测和拦截各种搜索引擎爬虫和恶意爬虫工具\n *\n * 使用方法:\n * use App\\Common\\BotDetector;\n * if (BotDetector::isBot()) {\n *     // 拦截处理\n * }\n */\nnamespace App\\Common;\n\nclass BotDetector\n{\n    /**\n     * 检测当前请求是否为爬虫\n     *\n     * @return bool 如果是爬虫返回true，否则返回false\n     */\n    public static function isBot()\n    {\n        $userAgent = isset($_SERVER['HTTP_USER_AGENT']) ? strtolower($_SERVER['HTTP_USER_AGENT']) : '';\n\n        // 常见搜索引擎爬虫User-Agent特征列表\n        // 注意: 不拦截 curl、wget、python、java 等，避免影响正常的API调用\n        $botPatterns = [\n            // 百度系列（重点拦截 - 完整列表）\n            'baiduspider',              // 百度通用爬虫\n            'baiduspider/2.0',          // 百度爬虫2.0版本\n            'baiduspider-render',       // 百度渲染爬虫(支持JS)\n            'baiduspider-render/2.0',   // 百度渲染爬虫2.0\n            'baiduspider-mobile',       // 百度移动端爬虫\n            'baiduspider-image',        // 百度图片爬虫\n            'baiduspider-image+',       // 百度图片爬虫变体\n            'baiduspider-video',        // 百度视频爬虫\n            'baiduspider-ads',          // 百度广告爬虫\n            'baiduspider-cpro',         // 百度广告联盟爬虫\n            'baiduspider-jp',           // 百度日语版爬虫\n            'baiduspider+',             // 百度爬虫变体\n            'baiduspider, anonymous',   // 百度匿名爬虫\n            'baiduspider-feed',         // 百度信息流爬虫\n            'baiduspider-fisheye',      // 百度全景爬虫\n            'baiduspider-link',         // 百度链接爬虫\n            // 谷歌系列\n            'googlebot',\n            'googlebot-mobile',\n            'googlebot-image',\n            'mediapartners-google',\n            // 搜狗系列\n            'sogou web spider',\n            'sogou push spider',\n            'sogou-',\n            // 360系列\n            '360spider',\n            '360spider-',\n            // 必应系列\n            'bingbot',\n            'msnbot',\n            // 其他搜索引擎爬虫（明确的爬虫标识）\n            'yandexbot',\n            'duckduckbot',\n            'slurp',              // 雅虎爬虫\n            'spider',             // 通用爬虫标识（仅包含spider关键词）\n            'crawler',            // 通用爬虫标识（仅包含crawler关键词）\n            // 恶意爬虫和自动化工具\n            'scrapy',             // Scrapy爬虫框架\n            'phantomjs',          // 无头浏览器\n            'headlesschrome',     // 无头Chrome\n            'selenium',           // 自动化测试工具\n            'scraper',            // 爬虫工具\n            'ahrefsbot',          // SEO工具\n            'semrushbot',         // SEO工具\n            'mj12bot',            // Majestic爬虫\n            'dotbot',             // DotBot爬虫\n            'gigabot',            // Gigablast爬虫\n            'archive.org_bot',    // 互联网档案馆爬虫\n            'ia_archiver',        // 互联网档案馆爬虫\n            // 社交媒体爬虫\n            'facebookexternalhit', // Facebook爬虫\n            'twitterbot',         // Twitter爬虫\n            'linkedinbot',        // LinkedIn爬虫\n            'embedly',            // Embedly爬虫\n            'quora link preview', // Quora爬虫\n            'pinterest',          // Pinterest爬虫\n            'applebot',           // Apple爬虫\n        ];\n\n        // 检查是否匹配任一爬虫特征\n        foreach ($botPatterns as $pattern) {\n            if (strpos($userAgent, $pattern) !== false) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * 记录被拦截的爬虫访问日志\n     *\n     * @param string|null $userAgent User-Agent字符串\n     * @param string|null $ip IP地址\n     * @param string|null $uri 请求URI\n     * @return void\n     */\n    public static function logBlockedBot($userAgent = null, $ip = null, $uri = null)\n    {\n        $logEntry = sprintf(\n            \"[%s] Blocked bot: %s | IP: %s | UA: %s | URI: %s\\n\",\n            date('Y-m-d H:i:s'),\n            $userAgent ?? 'Unknown',\n            $ip ?? 'Unknown',\n            $userAgent ?? 'Unknown',\n            $uri ?? '/'\n        );\n        // 记录到PHP错误日志\n        error_log($logEntry);\n    }\n\n    /**\n     * 执行爬虫检测并拦截（包含日志记录和403响应）\n     *\n     * @return void 如果检测到爬虫会终止程序执行\n     */\n    public static function blockBot()\n    {\n        if (self::isBot()) {\n            // 记录被拦截的爬虫访问日志\n            self::logBlockedBot(\n                $_SERVER['HTTP_USER_AGENT'] ?? null,\n                $_SERVER['REMOTE_ADDR'] ?? null,\n                $_SERVER['REQUEST_URI'] ?? null\n            );\n\n            // 返回403 Forbidden响应\n            http_response_code(403);\n            header('Content-Type: text/plain; charset=utf-8');\n            die('Access Denied - 403 Forbidden');\n        }\n    }\n}\n"
  },
  {
    "path": "server/app/Common/Cache/CacheManager.php",
    "content": "<?php\n\nnamespace App\\Common\\Cache;\n\nuse App\\Common\\Helper\\Env;\n\nclass CacheManager\n{\n    private static ?CacheManager $instance = null;\n    /** @var \\Redis|\\RedisCluster|null */\n    private $redis = null;\n\n    private function __construct()\n    {\n        // 开源版默认不启用 Redis（REDIS_ENABLED=false），降级为无缓存模式\n        // 只有明确设置为 'true' 或 '1' 时才启用 Redis\n        $enabled = Env::get('REDIS_ENABLED', 'false');\n        \n        // 检查是否启用 Redis：只有 'true' 或 '1' 才启用，其他情况（包括未配置）都禁用\n        $isEnabled = false;\n        if (is_string($enabled)) {\n            $enabled = strtolower(trim($enabled));\n            $isEnabled = ($enabled === 'true' || $enabled === '1');\n        } elseif (is_bool($enabled)) {\n            $isEnabled = $enabled;\n        } elseif (is_numeric($enabled)) {\n            $isEnabled = ((int) $enabled) === 1;\n        }\n        \n        if (!$isEnabled) {\n            // 未启用 Redis，直接返回，使用无缓存模式\n            return;\n        }\n\n        try {\n            if (!extension_loaded('redis')) {\n                // Redis 扩展未安装，降级为无缓存模式\n                return;\n            }\n            $redis = new \\Redis();\n            $host  = Env::get('REDIS_HOST', '127.0.0.1');\n            $port  = Env::get('REDIS_PORT', 6379);\n            $redis->connect($host, (int) $port, 1.0);\n            $this->redis = $redis;\n        } catch (\\Throwable $e) {\n            // 连接失败时降级为无 Redis 模式，避免影响正常请求\n            $this->redis = null;\n        }\n    }\n\n    public static function getInstance(): CacheManager\n    {\n        if (self::$instance instanceof CacheManager) {\n            return self::$instance;\n        }\n\n        self::$instance = new CacheManager();\n        return self::$instance;\n    }\n\n    /**\n     * 获取缓存值\n     *\n     * @param string $key 缓存键\n     * @return mixed|null 缓存值，不存在时返回 null\n     */\n    public function get(string $key)\n    {\n        if (!$this->redis instanceof \\Redis) {\n            return null;\n        }\n\n        try {\n            $value = $this->redis->get($key);\n            if ($value === false) {\n                return null;\n            }\n            return unserialize($value);\n        } catch (\\Throwable $e) {\n            return null;\n        }\n    }\n\n    /**\n     * 设置缓存值\n     *\n     * @param string $key 缓存键\n     * @param mixed $value 缓存值（会自动序列化）\n     * @param int $ttl 过期时间（秒），默认 86400（24小时）\n     * @return bool 是否设置成功\n     */\n    public function set(string $key, $value, int $ttl = 86400): bool\n    {\n        if (!$this->redis instanceof \\Redis) {\n            return false;\n        }\n\n        try {\n            $serialized = serialize($value);\n            return $this->redis->setex($key, $ttl, $serialized);\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 删除缓存\n     *\n     * @param string $key 缓存键\n     * @return bool 是否删除成功\n     */\n    public function delete(string $key): bool\n    {\n        if (!$this->redis instanceof \\Redis) {\n            return false;\n        }\n\n        try {\n            return $this->redis->del($key) > 0;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 获取 Redis 实例（用于需要直接操作 Redis 的场景）\n     *\n     * @return \\Redis|null Redis 实例，未启用或连接失败时返回 null\n     */\n    public function getRedis(): ?\\Redis\n    {\n        return $this->redis instanceof \\Redis ? $this->redis : null;\n    }\n}\n\n"
  },
  {
    "path": "server/app/Common/Config/ErrorCodes.php",
    "content": "<?php\n\nnamespace App\\Common\\Config;\n\n/**\n * 错误码配置\n * 定义系统中使用的错误码及其对应的错误消息\n */\nclass ErrorCodes\n{\n    /**\n     * 获取错误码对应的错误消息\n     *\n     * @param int $code 错误码\n     * @return string 错误消息，如果未找到则返回默认消息\n     */\n    public static function getMessage(int $code): string\n    {\n        $messages = self::getMessages();\n        return $messages[$code] ?? \"错误码: {$code}\";\n    }\n\n    /**\n     * 获取所有错误码消息映射\n     *\n     * @return array<int, string>\n     */\n    public static function getMessages(): array\n    {\n        return [\n            // 通用错误 (10000-10099)\n            10001 => '操作失败',\n            10002 => '参数错误',\n            10003 => '数据不存在',\n            10004 => '数据已存在',\n            10005 => '操作超时',\n            10010 => '访问密码不正确',\n\n            // 认证相关错误 (10100-10199)\n            10101 => '操作失败',\n            10102 => 'Token 无效',\n            10103 => '需要管理员权限',\n            10104 => '需要登录',\n            10105 => '密码错误',\n            10106 => '用户不存在',\n            10107 => '用户已被禁用',\n\n            // 验证码相关错误 (10200-10299)\n            10206 => '验证码不正确',\n\n            // 权限相关错误 (10300-10399)\n            10301 => '没有权限',\n            10302 => '没有访问权限',\n            10303 => '您没有编辑权限',\n            10304 => '您没有管理权限',\n            10305 => '您没有删除权限',\n\n            // 项目相关错误 (10400-10499)\n            10401 => '项目不存在',\n            10402 => '项目已被删除',\n            10403 => '项目访问受限',\n\n            // 页面相关错误 (10500-10599)\n            10501 => '页面不存在',\n            10502 => '页面已被删除',\n\n            // 文件相关错误 (10600-10699)\n            10601 => '文件上传失败',\n            10602 => '文件不存在',\n            10603 => '文件大小超限',\n            10604 => '文件类型不支持',\n        ];\n    }\n}\n\n"
  },
  {
    "path": "server/app/Common/Database/Database.php",
    "content": "<?php\n\nnamespace App\\Common\\Database;\n\nuse App\\Common\\Helper\\Env;\nuse Illuminate\\Database\\Capsule\\Manager as Capsule;\n\nclass Database\n{\n    private static ?Capsule $capsule = null;\n\n    public static function getInstance(): Capsule\n    {\n        if (self::$capsule instanceof Capsule) {\n            return self::$capsule;\n        }\n\n        $capsule = new Capsule();\n\n        // 开源版默认使用 SQLite，可通过环境变量 DB_TYPE=mysql 切换到 MySQL（可选）\n        $driver = strtolower(Env::get('DB_TYPE', 'sqlite'));\n\n        if ($driver === 'sqlite') {\n            // SQLite 配置（开源版主要使用）\n            $dbPath = Env::get('DB_NAME', __DIR__ . '/../../../../Sqlite/showdoc.db.php');\n            $capsule->addConnection([\n                'driver'   => 'sqlite',\n                'database' => $dbPath,\n                'prefix'   => '',\n                'options'  => [\n                    // 将所有数字字段返回为字符串，兼容旧前端\n                    \\PDO::ATTR_STRINGIFY_FETCHES => true,\n                ],\n            ]);\n        } else {\n            // MySQL 配置（可选，兼容性）\n            $capsule->addConnection([\n                'driver'    => 'mysql',\n                'host'      => Env::get('DB_HOST', '127.0.0.1'),\n                'port'      => (int) Env::get('DB_PORT', 3306),\n                'database'  => Env::get('DB_NAME', 'showdoc'),\n                'username'  => Env::get('DB_USER', 'root'),\n                'password'  => Env::get('DB_PWD', ''),\n                'charset'   => Env::get('DB_CHARSET', 'utf8mb4'),\n                'collation' => 'utf8mb4_unicode_ci',\n                'prefix'    => '',\n                'options'   => [\n                    // 将所有数字字段返回为字符串，兼容旧前端\n                    \\PDO::ATTR_STRINGIFY_FETCHES => true,\n                ],\n            ]);\n        }\n\n        $capsule->setAsGlobal();\n        $capsule->bootEloquent();\n\n        self::$capsule = $capsule;\n\n        return self::$capsule;\n    }\n}\n\n"
  },
  {
    "path": "server/app/Common/Database/Upgrade.php",
    "content": "<?php\n\nnamespace App\\Common\\Database;\n\nuse Illuminate\\Database\\Capsule\\Manager as DB;\nuse App\\Model\\Options;\n\n/**\n * 数据库升级类\n * \n * 负责检查数据库版本并执行必要的升级操作\n */\nclass Upgrade\n{\n    /**\n     * 当前数据库版本号\n     * 注意：如果更新数据库结构，务必更改此版本号\n     */\n    private const CURRENT_VERSION = 30;\n\n    /**\n     * 检查并执行数据库升级\n     * \n     * @return bool 是否成功\n     */\n    public static function checkAndUpgrade(): bool\n    {\n        try {\n            $dbVersion = (int) Options::get('db_version_num', 0);\n            \n            if ($dbVersion < self::CURRENT_VERSION) {\n                $result = self::updateSqlite();\n                if ($result) {\n                    Options::set('db_version_num', self::CURRENT_VERSION);\n                }\n                return $result;\n            }\n            \n            return true;\n        } catch (\\Throwable $e) {\n            // 升级失败时记录日志，但不阻止应用启动\n            error_log('Database upgrade failed: ' . $e->getMessage());\n            return false;\n        }\n    }\n\n    /**\n     * 执行 SQLite 数据库升级\n     * \n     * @return bool 是否成功\n     */\n    private static function updateSqlite(): bool\n    {\n        try {\n            // catalog表增加parent_cat_id字段\n            if (!self::isColumnExist('catalog', 'parent_cat_id')) {\n                DB::statement(\"ALTER TABLE catalog ADD parent_cat_id INT(10) NOT NULL DEFAULT '0'\");\n            }\n\n            // catalog表增加level字段\n            if (!self::isColumnExist('catalog', 'level')) {\n                DB::statement(\"ALTER TABLE catalog ADD level INT(10) NOT NULL DEFAULT '2'\");\n            }\n\n            // item表增加item_domain字段\n            if (!self::isColumnExist('item', 'item_domain')) {\n                DB::statement(\"ALTER TABLE item ADD item_domain text NOT NULL DEFAULT ''\");\n            }\n\n            // 创建user_token表\n            DB::statement(\"CREATE TABLE IF NOT EXISTS `user_token` (\n                `id` INTEGER PRIMARY KEY,\n                `uid` int(10) NOT NULL DEFAULT '0',\n                `token` CHAR(200) NOT NULL DEFAULT '',\n                `token_expire` int(11) NOT NULL DEFAULT '0',\n                `ip` CHAR(200) NOT NULL DEFAULT '',\n                `addtime` int(11) NOT NULL DEFAULT '0'\n            )\");\n\n            // 创建template表\n            DB::statement(\"CREATE TABLE IF NOT EXISTS `template` (\n                `id` INTEGER PRIMARY KEY,\n                `uid` int(10) NOT NULL DEFAULT '0',\n                `username` CHAR(200) NOT NULL DEFAULT '',\n                `template_title` CHAR(200) NOT NULL DEFAULT '',\n                `template_content` text NOT NULL DEFAULT '',\n                `addtime` int(11) NOT NULL DEFAULT '0'\n            )\");\n\n            // page表增加page_comments字段\n            if (!self::isColumnExist('page', 'page_comments')) {\n                DB::statement(\"ALTER TABLE page ADD page_comments text NOT NULL DEFAULT ''\");\n            }\n\n            // page_history表增加page_comments字段\n            if (!self::isColumnExist('page_history', 'page_comments')) {\n                DB::statement(\"ALTER TABLE page_history ADD page_comments text NOT NULL DEFAULT ''\");\n            }\n\n            // item_member表增加member_group_id字段\n            if (!self::isColumnExist('item_member', 'member_group_id')) {\n                DB::statement(\"ALTER TABLE item_member ADD member_group_id INT(1) NOT NULL DEFAULT '1'\");\n            }\n\n            // item表增加item_type字段\n            if (!self::isColumnExist('item', 'item_type')) {\n                DB::statement(\"ALTER TABLE item ADD item_type INT(1) NOT NULL DEFAULT '1'\");\n            }\n\n            // 创建options表\n            DB::statement(\"CREATE TABLE IF NOT EXISTS `options` (\n                `option_id` INTEGER PRIMARY KEY,\n                `option_name` CHAR(200) NOT NULL UNIQUE,\n                `option_value` CHAR(200) NOT NULL\n            )\");\n\n            // 创建item_token表\n            DB::statement(\"CREATE TABLE IF NOT EXISTS `item_token` (\n                `id` INTEGER PRIMARY KEY,\n                `item_id` int(11) NOT NULL DEFAULT '0',\n                `api_key` CHAR(200) NOT NULL UNIQUE,\n                `api_token` CHAR(200) NOT NULL,\n                `addtime` int(11) NOT NULL DEFAULT '0',\n                `last_check_time` int(11) NOT NULL DEFAULT '0'\n            )\");\n\n            // 创建item_top表\n            DB::statement(\"CREATE TABLE IF NOT EXISTS `item_top` (\n                `id` INTEGER PRIMARY KEY,\n                `item_id` int(11) NOT NULL DEFAULT '0',\n                `uid` int(11) NOT NULL DEFAULT '0',\n                `addtime` int(11) NOT NULL DEFAULT '0'\n            )\");\n\n            // item表增加is_archived字段\n            if (!self::isColumnExist('item', 'is_archived')) {\n                DB::statement(\"ALTER TABLE item ADD is_archived INT(1) NOT NULL DEFAULT '0'\");\n            }\n\n            // 管理员账户和权限\n            $user = DB::table('user')->where('username', 'showdoc')->first();\n            if ($user) {\n                DB::table('user')->where('username', 'showdoc')->update(['groupid' => 1]);\n            } else {\n                DB::table('user')->insert([\n                    'username' => 'showdoc',\n                    'groupid' => 1,\n                    'password' => 'a89da13684490eb9ec9e613f91d24d00',\n                    'reg_time' => time()\n                ]);\n            }\n\n            // item表增加is_del字段\n            if (!self::isColumnExist('item', 'is_del')) {\n                DB::statement(\"ALTER TABLE item ADD is_del INT(1) NOT NULL DEFAULT '0'\");\n            }\n\n            // page表增加is_del字段\n            if (!self::isColumnExist('page', 'is_del')) {\n                DB::statement(\"ALTER TABLE page ADD is_del INT(1) NOT NULL DEFAULT '0'\");\n            }\n\n            // page表增加page_addtime字段\n            if (!self::isColumnExist('page', 'page_addtime')) {\n                DB::statement(\"ALTER TABLE page ADD page_addtime INT(11) NOT NULL DEFAULT '0'\");\n            }\n\n            // 创建team表\n            DB::statement(\"CREATE TABLE IF NOT EXISTS `team` (\n                `id` INTEGER PRIMARY KEY,\n                `team_name` CHAR(200) NOT NULL DEFAULT '',\n                `uid` int(11) NOT NULL DEFAULT '0',\n                `username` CHAR(200) NOT NULL DEFAULT '',\n                `addtime` int(11) NOT NULL DEFAULT '0',\n                `last_update_time` int(11) NOT NULL DEFAULT '0'\n            )\");\n\n            // 创建team_item表\n            DB::statement(\"CREATE TABLE IF NOT EXISTS `team_item` (\n                `id` INTEGER PRIMARY KEY,\n                `team_id` int(11) NOT NULL DEFAULT '0',\n                `item_id` int(11) NOT NULL DEFAULT '0',\n                `addtime` int(11) NOT NULL DEFAULT '0',\n                `last_update_time` int(11) NOT NULL DEFAULT '0'\n            )\");\n\n            // 创建team_item_member表\n            DB::statement(\"CREATE TABLE IF NOT EXISTS `team_item_member` (\n                `id` INTEGER PRIMARY KEY,\n                `team_id` int(11) NOT NULL DEFAULT '0',\n                `item_id` int(11) NOT NULL DEFAULT '0',\n                `member_group_id` int(11) NOT NULL DEFAULT '0',\n                `member_uid` int(11) NOT NULL DEFAULT '0',\n                `member_username` CHAR(200) NOT NULL DEFAULT '',\n                `addtime` int(11) NOT NULL DEFAULT '0',\n                `last_update_time` int(11) NOT NULL DEFAULT '0'\n            )\");\n\n            // 创建team_member表\n            DB::statement(\"CREATE TABLE IF NOT EXISTS `team_member` (\n                `id` INTEGER PRIMARY KEY,\n                `team_id` int(11) NOT NULL DEFAULT '0',\n                `member_uid` int(11) NOT NULL DEFAULT '0',\n                `member_username` CHAR(200) NOT NULL DEFAULT '',\n                `addtime` int(11) NOT NULL DEFAULT '0',\n                `last_update_time` int(11) NOT NULL DEFAULT '0'\n            )\");\n\n            // 创建upload_file表\n            DB::statement(\"CREATE TABLE IF NOT EXISTS `upload_file` (\n                `file_id` INTEGER PRIMARY KEY,\n                `sign` CHAR(200) NOT NULL DEFAULT '',\n                `display_name` CHAR(200) NOT NULL DEFAULT '',\n                `file_type` CHAR(200) NOT NULL DEFAULT '',\n                `file_size` CHAR(200) NOT NULL DEFAULT '',\n                `uid` int(11) NOT NULL DEFAULT '0',\n                `page_id` int(11) NOT NULL DEFAULT '0',\n                `item_id` int(11) NOT NULL DEFAULT '0',\n                `visit_times` int(11) NOT NULL DEFAULT '0',\n                `addtime` int(11) NOT NULL DEFAULT '0',\n                `real_url` CHAR(200) NOT NULL DEFAULT '',\n                `last_update_time` int(11) NOT NULL DEFAULT '0'\n            )\");\n\n            // 创建item_sort表\n            DB::statement(\"CREATE TABLE IF NOT EXISTS `item_sort` (\n                `id` INTEGER PRIMARY KEY,\n                `uid` int(10) NOT NULL DEFAULT '0',\n                `item_sort_data` text NOT NULL DEFAULT '',\n                `addtime` int(11) NOT NULL DEFAULT '0'\n            )\");\n\n            // 创建single_page表\n            DB::statement(\"CREATE TABLE IF NOT EXISTS `single_page` (\n                `id` INTEGER PRIMARY KEY,\n                `unique_key` CHAR(200) NOT NULL DEFAULT '',\n                `page_id` int(11) NOT NULL DEFAULT '0'\n            )\");\n\n            // 创建captcha表\n            DB::statement(\"CREATE TABLE IF NOT EXISTS `captcha` (\n                `captcha_id` INTEGER PRIMARY KEY,\n                `mobile` CHAR(200) NOT NULL DEFAULT '',\n                `captcha` CHAR(200) NOT NULL DEFAULT '',\n                `expire_time` int(11) NOT NULL DEFAULT '0'\n            )\");\n\n            // 创建recycle表\n            DB::statement(\"CREATE TABLE IF NOT EXISTS `recycle` (\n                `id` INTEGER PRIMARY KEY,\n                `item_id` int(11) NOT NULL DEFAULT '0',\n                `page_id` int(11) NOT NULL DEFAULT '0',\n                `page_title` CHAR(200) NOT NULL DEFAULT '',\n                `del_by_uid` int(11) NOT NULL DEFAULT '0',\n                `del_by_username` CHAR(200) NOT NULL DEFAULT '',\n                `del_time` int(11) NOT NULL DEFAULT '0'\n            )\");\n\n            // 创建page_lock表\n            DB::statement(\"CREATE TABLE IF NOT EXISTS `page_lock` (\n                `id` INTEGER PRIMARY KEY,\n                `page_id` int(11) NOT NULL DEFAULT '0',\n                `lock_uid` int(11) NOT NULL DEFAULT '0',\n                `lock_username` CHAR(200) NOT NULL DEFAULT '',\n                `lock_to` int(11) NOT NULL DEFAULT '0',\n                `addtime` int(11) NOT NULL DEFAULT '0'\n            )\");\n\n            // item_member表增加cat_id字段\n            if (!self::isColumnExist('item_member', 'cat_id')) {\n                DB::statement(\"ALTER TABLE item_member ADD cat_id INT(10) NOT NULL DEFAULT '0'\");\n            }\n\n            // team_item_member表增加cat_id字段\n            if (!self::isColumnExist('team_item_member', 'cat_id')) {\n                DB::statement(\"ALTER TABLE team_item_member ADD cat_id INT(10) NOT NULL DEFAULT '0'\");\n            }\n\n            // item_member表增加cat_ids字段\n            if (!self::isColumnExist('item_member', 'cat_ids')) {\n                DB::statement(\"ALTER TABLE item_member ADD cat_ids text NOT NULL DEFAULT ''\");\n            }\n\n            // team_item_member表增加cat_ids字段\n            if (!self::isColumnExist('team_item_member', 'cat_ids')) {\n                DB::statement(\"ALTER TABLE team_item_member ADD cat_ids text NOT NULL DEFAULT ''\");\n            }\n\n            // 创建item_variable表\n            DB::statement(\"CREATE TABLE IF NOT EXISTS `item_variable` (\n                `id` INTEGER PRIMARY KEY,\n                `var_name` CHAR(2000) NOT NULL DEFAULT '',\n                `var_value` CHAR(2000) NOT NULL DEFAULT '',\n                `uid` int(11) NOT NULL DEFAULT '0',\n                `item_id` int(11) NOT NULL DEFAULT '0',\n                `addtime` int(11) NOT NULL DEFAULT '0'\n            )\");\n\n            // 创建file_flow表\n            DB::statement(\"CREATE TABLE IF NOT EXISTS `file_flow` (\n                `id` INTEGER PRIMARY KEY,\n                `uid` int(11) NOT NULL DEFAULT '0',\n                `used` int(11) NOT NULL DEFAULT '0',\n                `date_month` CHAR(2000) NOT NULL DEFAULT ''\n            )\");\n\n            // item_variable表增加env_id字段\n            if (!self::isColumnExist('item_variable', 'env_id')) {\n                DB::statement(\"ALTER TABLE item_variable ADD env_id INT(10) NOT NULL DEFAULT '0'\");\n            }\n\n            // 创建runapi_env表\n            DB::statement(\"CREATE TABLE IF NOT EXISTS `runapi_env` (\n                `id` INTEGER PRIMARY KEY,\n                `env_name` CHAR(2000) NOT NULL DEFAULT '',\n                `item_id` int(11) NOT NULL DEFAULT '0',\n                `uid` int(11) NOT NULL DEFAULT '0',\n                `addtime` CHAR(2000) NOT NULL DEFAULT '',\n                `last_update_time` CHAR(2000) NOT NULL DEFAULT ''\n            )\");\n\n            // 创建runapi_env_selectd表\n            DB::statement(\"CREATE TABLE IF NOT EXISTS `runapi_env_selectd` (\n                `id` INTEGER PRIMARY KEY,\n                `item_id` int(11) NOT NULL DEFAULT '0',\n                `uid` int(11) NOT NULL DEFAULT '0',\n                `env_id` int(11) NOT NULL DEFAULT '0'\n            )\");\n\n            // 创建runapi_global_param表\n            DB::statement(\"CREATE TABLE IF NOT EXISTS `runapi_global_param` (\n                `id` INTEGER PRIMARY KEY,\n                `item_id` int(11) NOT NULL DEFAULT '0',\n                `param_type` CHAR(2000) NOT NULL DEFAULT '',\n                `content_json_str` CHAR(2000) NOT NULL DEFAULT '',\n                `addtime` CHAR(2000) NOT NULL DEFAULT '',\n                `last_update_time` CHAR(2000) NOT NULL DEFAULT ''\n            )\");\n\n            // 创建mock表\n            DB::statement(\"CREATE TABLE IF NOT EXISTS `mock` (\n                `id` INTEGER PRIMARY KEY,\n                `unique_key` CHAR(2000) NOT NULL DEFAULT '',\n                `uid` int(11) NOT NULL DEFAULT '0',\n                `page_id` int(11) NOT NULL DEFAULT '0',\n                `item_id` int(11) NOT NULL DEFAULT '0',\n                `view_times` int(11) NOT NULL DEFAULT '0',\n                `template` CHAR(2000) NOT NULL DEFAULT '',\n                `addtime` CHAR(2000) NOT NULL DEFAULT '',\n                `last_update_time` CHAR(2000) NOT NULL DEFAULT ''\n            )\");\n\n            // 创建file_page表\n            DB::statement(\"CREATE TABLE IF NOT EXISTS `file_page` (\n                `id` INTEGER PRIMARY KEY,\n                `file_id` int(11) NOT NULL DEFAULT '0',\n                `page_id` int(11) NOT NULL DEFAULT '0',\n                `item_id` int(11) NOT NULL DEFAULT '0',\n                `addtime` CHAR(2000) NOT NULL DEFAULT ''\n            )\");\n\n            // 如果file_page尚未有数据，则把upload_file表的数据转换过去\n            $filePageCount = DB::table('file_page')->count();\n            if ($filePageCount == 0) {\n                $files = DB::table('upload_file')->get();\n                foreach ($files as $file) {\n                    DB::table('file_page')->insert([\n                        'file_id' => $file->file_id,\n                        'page_id' => $file->page_id,\n                        'item_id' => $file->item_id,\n                        'addtime' => $file->addtime,\n                    ]);\n                }\n            }\n\n            // mock表增加path字段\n            if (!self::isColumnExist('mock', 'path')) {\n                DB::statement(\"ALTER TABLE mock ADD path text NOT NULL DEFAULT ''\");\n            }\n\n            // 创建runapi_flow表\n            DB::statement(\"CREATE TABLE IF NOT EXISTS `runapi_flow` (\n                `id` INTEGER PRIMARY KEY,\n                `flow_name` CHAR(2000) NOT NULL DEFAULT '',\n                `uid` int(11) NOT NULL DEFAULT '0',\n                `username` CHAR(2000) NOT NULL DEFAULT '',\n                `item_id` int(11) NOT NULL DEFAULT '0',\n                `env_id` int(11) NOT NULL DEFAULT '0',\n                `times` int(11) NOT NULL DEFAULT '0',\n                `time_interval` int(11) NOT NULL DEFAULT '0',\n                `error_continue` int(11) NOT NULL DEFAULT '0',\n                `save_change` int(11) NOT NULL DEFAULT '0',\n                `addtime` CHAR(2000) NOT NULL DEFAULT '',\n                `last_update_time` CHAR(2000) NOT NULL DEFAULT ''\n            )\");\n\n            // 创建runapi_flow_page表\n            DB::statement(\"CREATE TABLE IF NOT EXISTS `runapi_flow_page` (\n                `id` INTEGER PRIMARY KEY,\n                `flow_id` int(11) NOT NULL DEFAULT '0',\n                `page_id` int(11) NOT NULL DEFAULT '0',\n                `s_number` int(11) NOT NULL DEFAULT '0',\n                `addtime` CHAR(2000) NOT NULL DEFAULT ''\n            )\");\n\n            // runapi_flow_page表增加enabled字段\n            if (!self::isColumnExist('runapi_flow_page', 'enabled')) {\n                DB::statement(\"ALTER TABLE runapi_flow_page ADD enabled int(1) NOT NULL DEFAULT '1'\");\n            }\n\n            // item_sort表增加item_group_id字段\n            if (!self::isColumnExist('item_sort', 'item_group_id')) {\n                DB::statement(\"ALTER TABLE item_sort ADD item_group_id int(10) NOT NULL DEFAULT '0'\");\n            }\n\n            // 创建item_group表\n            DB::statement(\"CREATE TABLE IF NOT EXISTS `item_group` (\n                `id` INTEGER PRIMARY KEY,\n                `uid` int(11) NOT NULL DEFAULT '0',\n                `group_name` CHAR(2000) NOT NULL DEFAULT '',\n                `item_ids` text NOT NULL DEFAULT '',\n                `s_number` int(11) NOT NULL DEFAULT '0',\n                `created_at` CHAR(2000) NOT NULL DEFAULT '',\n                `updated_at` CHAR(2000) NOT NULL DEFAULT ''\n            )\");\n\n            // 创建item_change_log表\n            DB::statement(\"CREATE TABLE IF NOT EXISTS `item_change_log` (\n                `id` INTEGER PRIMARY KEY,\n                `uid` int(11) NOT NULL DEFAULT '0',\n                `item_id` int(11) NOT NULL DEFAULT '0',\n                `op_action_type` CHAR(2000) NOT NULL DEFAULT '',\n                `op_object_type` CHAR(2000) NOT NULL DEFAULT '',\n                `op_object_id` int(11) NOT NULL DEFAULT '0',\n                `op_object_name` CHAR(2000) NOT NULL DEFAULT '',\n                `remark` CHAR(2000) NOT NULL DEFAULT '',\n                `optime` CHAR(2000) NOT NULL DEFAULT ''\n            )\");\n\n            // 创建message_content表\n            DB::statement(\"CREATE TABLE IF NOT EXISTS `message_content` (\n                `id` INTEGER PRIMARY KEY,\n                `from_uid` int(11) NOT NULL DEFAULT '0',\n                `from_name` CHAR(2000) NOT NULL DEFAULT '',\n                `message_type` CHAR(2000) NOT NULL DEFAULT '',\n                `message_content` CHAR(2000) NOT NULL DEFAULT '',\n                `action_type` CHAR(2000) NOT NULL DEFAULT '',\n                `object_type` CHAR(2000) NOT NULL DEFAULT '',\n                `object_id` int(11) NOT NULL DEFAULT '0',\n                `addtime` CHAR(2000) NOT NULL DEFAULT ''\n            )\");\n\n            // 创建message表\n            DB::statement(\"CREATE TABLE IF NOT EXISTS `message` (\n                `id` INTEGER PRIMARY KEY,\n                `from_uid` int(11) NOT NULL DEFAULT '0',\n                `to_uid` int(11) NOT NULL DEFAULT '0',\n                `message_type` CHAR(2000) NOT NULL DEFAULT '',\n                `message_content_id` int(11) NOT NULL DEFAULT '0',\n                `status` int(11) NOT NULL DEFAULT '0',\n                `addtime` CHAR(2000) NOT NULL DEFAULT '',\n                `readtime` CHAR(2000) NOT NULL DEFAULT ''\n            )\");\n\n            // 创建subscription表\n            DB::statement(\"CREATE TABLE IF NOT EXISTS `subscription` (\n                `id` INTEGER PRIMARY KEY,\n                `uid` int(11) NOT NULL DEFAULT '0',\n                `object_id` int(11) NOT NULL DEFAULT '0',\n                `object_type` CHAR(2000) NOT NULL DEFAULT '',\n                `action_type` CHAR(2000) NOT NULL DEFAULT '',\n                `sub_time` CHAR(2000) NOT NULL DEFAULT ''\n            )\");\n\n            // 创建template_item表\n            DB::statement(\"CREATE TABLE IF NOT EXISTS `template_item` (\n                `id` INTEGER PRIMARY KEY,\n                `template_id` int(11) NOT NULL DEFAULT '0',\n                `item_id` int(11) NOT NULL DEFAULT '0',\n                `uid` int(11) NOT NULL DEFAULT '0',\n                `username` CHAR(2000) NOT NULL DEFAULT '',\n                `created_at` CHAR(2000) NOT NULL DEFAULT ''\n            )\");\n\n            // team_member表增加team_member_group_id字段\n            if (!self::isColumnExist('team_member', 'team_member_group_id')) {\n                DB::statement(\"ALTER TABLE team_member ADD team_member_group_id int(10) NOT NULL DEFAULT '1'\");\n            }\n\n            // user表增加salt字段\n            if (!self::isColumnExist('user', 'salt')) {\n                DB::statement(\"ALTER TABLE user ADD salt CHAR(2000) NOT NULL DEFAULT ''\");\n            }\n\n            // 创建item_star表\n            DB::statement(\"CREATE TABLE IF NOT EXISTS `item_star` (\n                `id` INTEGER PRIMARY KEY,\n                `uid` int(11) NOT NULL DEFAULT '0',\n                `item_id` int(11) NOT NULL DEFAULT '0',\n                `s_number` int(11) NOT NULL DEFAULT '0',\n                `created_at` CHAR(2000) NOT NULL DEFAULT '',\n                `updated_at` CHAR(2000) NOT NULL DEFAULT ''\n            )\");\n\n            // page表增加ext_info字段\n            if (!self::isColumnExist('page', 'ext_info')) {\n                DB::statement(\"ALTER TABLE page ADD ext_info CHAR(2000) NOT NULL DEFAULT ''\");\n            }\n\n            // page_history表增加ext_info字段\n            if (!self::isColumnExist('page_history', 'ext_info')) {\n                DB::statement(\"ALTER TABLE page_history ADD ext_info CHAR(2000) NOT NULL DEFAULT ''\");\n            }\n\n            // 创建export_log表\n            DB::statement(\"CREATE TABLE IF NOT EXISTS `export_log` (\n                `id` INTEGER PRIMARY KEY,\n                `uid` int(11) NOT NULL DEFAULT '0',\n                `export_type` CHAR(200) NOT NULL DEFAULT '',\n                `item_id` int(11) NOT NULL DEFAULT '0',\n                `addtime` CHAR(200) NOT NULL DEFAULT ''\n            )\");\n\n            // upload_file表增加last_visit_time字段\n            if (!self::isColumnExist('upload_file', 'last_visit_time')) {\n                DB::statement(\"ALTER TABLE upload_file ADD last_visit_time INT(11) NOT NULL DEFAULT '0'\");\n            }\n\n            // 设置自增id从随机数开始（仅当表为空时）\n            $pageCount = DB::table('page')->count();\n            $catalogCount = DB::table('catalog')->count();\n            $itemCount = DB::table('item')->count();\n            \n            if ($pageCount == 0) {\n                $randomNumber1 = mt_rand(100000000, 299999999);\n                DB::statement(\"INSERT OR IGNORE INTO sqlite_sequence (name, seq) VALUES ('page', {$randomNumber1})\");\n            }\n            if ($catalogCount == 0) {\n                $randomNumber2 = mt_rand(400000000, 499999999);\n                DB::statement(\"INSERT OR IGNORE INTO sqlite_sequence (name, seq) VALUES ('catalog', {$randomNumber2})\");\n            }\n            if ($itemCount == 0) {\n                $randomNumber3 = mt_rand(600000000, 699999999);\n                DB::statement(\"INSERT OR IGNORE INTO sqlite_sequence (name, seq) VALUES ('item', {$randomNumber3})\");\n            }\n\n            // 创建user_setting表\n            DB::statement(\"CREATE TABLE IF NOT EXISTS `user_setting` (\n                `id` INTEGER PRIMARY KEY,\n                `uid` int(10) NOT NULL DEFAULT '0',\n                `key_name` CHAR(200) NOT NULL DEFAULT '',\n                `key_value` text NOT NULL DEFAULT '',\n                `addtime` text NOT NULL DEFAULT ''\n            )\");\n\n            // single_page表增加expire_time字段\n            if (!self::isColumnExist('single_page', 'expire_time')) {\n                DB::statement(\"ALTER TABLE single_page ADD expire_time INT(11) NOT NULL DEFAULT '0'\");\n            }\n\n            // 创建parameter_description_entry表\n            DB::statement(\"CREATE TABLE IF NOT EXISTS `parameter_description_entry` (\n                `id` TEXT PRIMARY KEY,\n                `item_id` TEXT NOT NULL,\n                `name` TEXT NOT NULL,\n                `type` TEXT NOT NULL,\n                `description` TEXT NOT NULL,\n                `example` TEXT,\n                `default_value` TEXT,\n                `aliases` TEXT,\n                `tags` TEXT,\n                `path` TEXT,\n                `source` TEXT NOT NULL DEFAULT 'manual' CHECK (source IN ('manual','auto-extracted','builtin')),\n                `status` TEXT NOT NULL DEFAULT 'permanent' CHECK (status IN ('temp','permanent')),\n                `usage_count` INTEGER NOT NULL DEFAULT 0,\n                `quality_score` NUMERIC NOT NULL DEFAULT 0.00,\n                `created_by` TEXT NOT NULL,\n                `created_at` TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP),\n                `updated_at` TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP)\n            )\");\n\n            // 创建索引\n            DB::statement(\"CREATE UNIQUE INDEX IF NOT EXISTS uk_item_name_type ON parameter_description_entry (item_id, name, type)\");\n            DB::statement(\"CREATE INDEX IF NOT EXISTS idx_item_id ON parameter_description_entry (item_id)\");\n            DB::statement(\"CREATE INDEX IF NOT EXISTS idx_name ON parameter_description_entry (name)\");\n            DB::statement(\"CREATE INDEX IF NOT EXISTS idx_type ON parameter_description_entry (type)\");\n            DB::statement(\"CREATE INDEX IF NOT EXISTS idx_status ON parameter_description_entry (status)\");\n            DB::statement(\"CREATE INDEX IF NOT EXISTS idx_created_at ON parameter_description_entry (created_at)\");\n            DB::statement(\"CREATE INDEX IF NOT EXISTS idx_updated_at ON parameter_description_entry (updated_at)\");\n\n            // 创建触发器\n            DB::statement(\"DROP TRIGGER IF EXISTS trg_parameter_description_entry_updated_at\");\n            DB::statement(\"CREATE TRIGGER trg_parameter_description_entry_updated_at AFTER UPDATE ON parameter_description_entry\n                BEGIN\n                    UPDATE parameter_description_entry SET updated_at = CURRENT_TIMESTAMP WHERE id = NEW.id;\n                END\");\n\n            // 创建page_comment表\n            DB::statement(\"CREATE TABLE IF NOT EXISTS `page_comment` (\n                `comment_id` INTEGER PRIMARY KEY,\n                `page_id` int(11) NOT NULL DEFAULT '0',\n                `item_id` int(11) NOT NULL DEFAULT '0',\n                `parent_id` int(11) NOT NULL DEFAULT '0',\n                `uid` int(11) NOT NULL DEFAULT '0',\n                `username` CHAR(200) NOT NULL DEFAULT '',\n                `content` text NOT NULL DEFAULT '',\n                `is_deleted` int(1) NOT NULL DEFAULT '0',\n                `addtime` int(11) NOT NULL DEFAULT '0'\n            )\");\n\n            // 创建page_feedback表\n            DB::statement(\"CREATE TABLE IF NOT EXISTS `page_feedback` (\n                `feedback_id` INTEGER PRIMARY KEY,\n                `page_id` int(11) NOT NULL DEFAULT '0',\n                `item_id` int(11) NOT NULL DEFAULT '0',\n                `uid` int(11) NOT NULL DEFAULT '0',\n                `client_id` CHAR(200) DEFAULT NULL,\n                `feedback_type` int(1) NOT NULL DEFAULT '0',\n                `addtime` int(11) NOT NULL DEFAULT '0'\n            )\");\n\n            // 创建唯一索引\n            DB::statement(\"CREATE UNIQUE INDEX IF NOT EXISTS unique_user_feedback ON page_feedback (page_id, uid)\");\n            DB::statement(\"CREATE UNIQUE INDEX IF NOT EXISTS unique_client_feedback ON page_feedback (page_id, client_id)\");\n\n            // item表增加allow_comment字段\n            if (!self::isColumnExist('item', 'allow_comment')) {\n                DB::statement(\"ALTER TABLE item ADD allow_comment INT(1) NOT NULL DEFAULT '0'\");\n            }\n\n            // item表增加allow_feedback字段\n            if (!self::isColumnExist('item', 'allow_feedback')) {\n                DB::statement(\"ALTER TABLE item ADD allow_feedback INT(1) NOT NULL DEFAULT '0'\");\n            }\n\n            // 清理可能存在的冲突数据\n            DB::statement(\"UPDATE page_feedback SET client_id = NULL WHERE uid > 0 AND (client_id = '' OR client_id IS NULL)\");\n\n            // 创建item_ai_config表\n            DB::statement(\"CREATE TABLE IF NOT EXISTS `item_ai_config` (\n                `id` INTEGER PRIMARY KEY,\n                `item_id` int(11) NOT NULL DEFAULT '0',\n                `enabled` int(1) NOT NULL DEFAULT '0',\n                `dialog_collapsed` int(1) NOT NULL DEFAULT '1',\n                `welcome_message` text NOT NULL DEFAULT '',\n                `addtime` int(11) NOT NULL DEFAULT '0',\n                `updatetime` int(11) NOT NULL DEFAULT '0'\n            )\");\n\n            // 创建索引\n            DB::statement(\"CREATE UNIQUE INDEX IF NOT EXISTS uk_item_id ON item_ai_config (item_id)\");\n            DB::statement(\"CREATE INDEX IF NOT EXISTS idx_enabled ON item_ai_config (enabled)\");\n\n            // 创建runapi_db_config表\n            DB::statement(\"CREATE TABLE IF NOT EXISTS `runapi_db_config` (\n                `id` INTEGER PRIMARY KEY,\n                `item_id` int(11) NOT NULL DEFAULT '0',\n                `env_id` int(11) NOT NULL DEFAULT '0',\n                `config_name` CHAR(100) NOT NULL DEFAULT '默认',\n                `db_type` CHAR(20) NOT NULL DEFAULT 'mysql',\n                `host` CHAR(255) NOT NULL DEFAULT '',\n                `port` int(11) NOT NULL DEFAULT '0',\n                `username` CHAR(255) NOT NULL DEFAULT '',\n                `password` CHAR(255) NOT NULL DEFAULT '',\n                `database` CHAR(255) NOT NULL DEFAULT '',\n                `options` text NOT NULL DEFAULT '',\n                `is_default` int(1) NOT NULL DEFAULT '0',\n                `addtime` CHAR(2000) NOT NULL DEFAULT '',\n                `last_update_time` CHAR(2000) NOT NULL DEFAULT '',\n                `uid` int(11) NOT NULL DEFAULT '0'\n            )\");\n\n            // 创建唯一索引\n            DB::statement(\"CREATE UNIQUE INDEX IF NOT EXISTS uniq_item_env_name ON runapi_db_config (item_id, env_id, config_name)\");\n\n            // page表增加is_draft字段\n            if (!self::isColumnExist('page', 'is_draft')) {\n                DB::statement(\"ALTER TABLE page ADD is_draft INT(1) NOT NULL DEFAULT '0'\");\n            }\n\n            // 创建user_ai_token表（MCP功能）\n            DB::statement(\"CREATE TABLE IF NOT EXISTS `user_ai_token` (\n                `id` INTEGER PRIMARY KEY AUTOINCREMENT,\n                `uid` int(11) NOT NULL DEFAULT '0',\n                `token` CHAR(150) NOT NULL DEFAULT '',\n                `name` CHAR(100) DEFAULT NULL,\n                `permission` CHAR(20) NOT NULL DEFAULT 'write',\n                `scope` CHAR(20) NOT NULL DEFAULT 'all',\n                `allowed_items` text DEFAULT NULL,\n                `can_create_item` int(1) NOT NULL DEFAULT '1',\n                `can_delete_item` int(1) NOT NULL DEFAULT '0',\n                `auto_add_created_item` int(1) NOT NULL DEFAULT '1',\n                `expires_at` datetime DEFAULT NULL,\n                `created_at` datetime DEFAULT NULL,\n                `last_used_at` datetime DEFAULT NULL,\n                `is_active` int(1) NOT NULL DEFAULT '1'\n            )\");\n\n            // 创建索引\n            DB::statement(\"CREATE INDEX IF NOT EXISTS idx_uid ON user_ai_token (uid)\");\n            DB::statement(\"CREATE INDEX IF NOT EXISTS idx_token ON user_ai_token (token)\");\n            DB::statement(\"CREATE INDEX IF NOT EXISTS idx_is_active ON user_ai_token (is_active)\");\n\n            return true;\n        } catch (\\Throwable $e) {\n            error_log('Database upgrade SQL execution failed: ' . $e->getMessage());\n            return false;\n        }\n    }\n\n    /**\n     * 检查表中是否存在指定字段\n     * \n     * @param string $table 表名\n     * @param string $column 字段名\n     * @return bool 是否存在\n     */\n    private static function isColumnExist(string $table, string $column): bool\n    {\n        try {\n            // SQLite 查询表结构\n            $result = DB::select(\"PRAGMA table_info({$table})\");\n            foreach ($result as $row) {\n                if (isset($row->name) && $row->name === $column) {\n                    return true;\n                }\n            }\n            return false;\n        } catch (\\Throwable $e) {\n            // 如果表不存在，返回 false\n            return false;\n        }\n    }\n}\n\n"
  },
  {
    "path": "server/app/Common/Helper/AiHelper.php",
    "content": "<?php\n\nnamespace App\\Common\\Helper;\n\nuse App\\Model\\Item;\nuse App\\Model\\Options;\nuse App\\Common\\Helper\\Convert;\n\n/**\n * AI 辅助类\n * 提供 AI 相关的公共方法\n */\nclass AiHelper\n{\n    /**\n     * 重建项目索引\n     *\n     * @param int $itemId 项目ID\n     * @param string $aiServiceUrl AI服务地址\n     * @param string $aiServiceToken AI服务Token\n     * @return array|false 成功返回结果数组，失败返回false\n     */\n    public static function rebuild(int $itemId, string $aiServiceUrl, string $aiServiceToken)\n    {\n        try {\n            // 设置执行时长和内存限制（重建索引可能需要较长时间和较多内存）\n            set_time_limit(3600);  // 60分钟超时（大项目需要更长时间）\n            ini_set('memory_limit', '2G');  // 2GB 内存限制\n\n            // 使用 Item 模型的 getContent 方法获取所有页面（会自动处理分表和内容解压缩）\n            $menu = Item::getContent($itemId, true);\n            if (!$menu || (empty($menu['pages']) && empty($menu['catalogs']))) {\n                error_log(\"自动重建索引失败: item_id={$itemId}, 项目中没有可索引的文档\");\n                return false;\n            }\n\n            // 使用 Convert 类转换 API 文档\n            $convert = new Convert();\n\n            // 构建页面数据（递归处理所有页面）\n            $pageData = [];\n            self::collectPages($menu, $pageData, $convert);\n\n            if (empty($pageData)) {\n                error_log(\"自动重建索引失败: item_id={$itemId}, 没有可索引的文档（所有页面内容都为空）\");\n                return false;\n            }\n\n            $totalPages = count($pageData);\n            error_log(\"自动触发重建索引: item_id={$itemId}, 页面总数={$totalPages}\");\n\n            // 重建索引前，先清空整个项目的旧索引，避免分批处理时重复删除操作\n            $deleteUrl = rtrim($aiServiceUrl, '/') . '/api/index/delete-item';\n            $deleteResult = self::callService($deleteUrl, ['item_id' => $itemId], $aiServiceToken, 'DELETE', 30);\n            if ($deleteResult !== false) {\n                error_log(\"已清空项目旧索引: item_id={$itemId}\");\n            } else {\n                error_log(\"清空项目旧索引失败（可能不存在）: item_id={$itemId}\");\n            }\n\n            // 分批处理，避免一次性发送所有页面数据导致超时或内存问题\n            // 每批处理 200 个页面（可根据实际情况调整）\n            $batchSize = 200;\n            $url = rtrim($aiServiceUrl, '/') . '/api/index/rebuild';\n\n            // 如果页面数量较少，一次性提交\n            if ($totalPages <= 100) {\n                $postData = [\n                    'item_id' => $itemId,\n                    'pages' => $pageData\n                ];\n                $result = self::callService($url, $postData, $aiServiceToken, 'POST', 30);  // 30秒超时（只是提交任务）\n                if ($result !== false && isset($result['status']) && $result['status'] == 'success') {\n                    error_log(\"重建索引任务已提交: item_id={$itemId}, 页面总数={$totalPages}, task_id=\" . (isset($result['task_id']) ? $result['task_id'] : ''));\n                    return [\n                        'status' => 'success',\n                        'message' => '重建索引任务已提交，正在后台处理',\n                        'total' => $totalPages,\n                        'task_id' => $result['task_id'] ?? null\n                    ];\n                }\n            }\n\n            // 如果页面数量太多，分批提交（每批调用一次 rebuild 接口）\n            $totalBatches = ceil($totalPages / $batchSize);\n            $successBatches = 0;\n            $errorBatches = 0;\n            $taskIds = [];\n\n            error_log(\"使用分批方式重建索引: item_id={$itemId}, 总批次数={$totalBatches}, 每批={$batchSize}个页面\");\n\n            for ($i = 0; $i < $totalPages; $i += $batchSize) {\n                $batch = array_slice($pageData, $i, $batchSize);\n                $batchNum = floor($i / $batchSize) + 1;\n\n                $postData = [\n                    'item_id' => $itemId,\n                    'pages' => $batch\n                ];\n\n                $result = self::callService($url, $postData, $aiServiceToken, 'POST', 30);\n                if ($result !== false && isset($result['status']) && $result['status'] == 'success') {\n                    $successBatches++;\n                    if (isset($result['task_id'])) {\n                        $taskIds[] = $result['task_id'];\n                    }\n                    error_log(\"重建索引进度: item_id={$itemId}, 批次 {$batchNum}/{$totalBatches} 已提交, task_id=\" . (isset($result['task_id']) ? $result['task_id'] : ''));\n                } else {\n                    $errorBatches++;\n                    error_log(\"重建索引进度: item_id={$itemId}, 批次 {$batchNum}/{$totalBatches} 提交失败\");\n                }\n\n                // 每批之间稍作延迟，避免请求过于频繁\n                if ($i + $batchSize < $totalPages) {\n                    usleep(200000);  // 延迟 0.2 秒\n                }\n            }\n\n            error_log(\"重建索引任务提交完成: item_id={$itemId}, 成功批次={$successBatches}, 失败批次={$errorBatches}, 总计={$totalBatches}\");\n\n            return [\n                'status' => $errorBatches == 0 ? 'success' : 'partial_success',\n                'message' => $errorBatches == 0 ? '重建索引任务已全部提交，正在后台处理' : \"重建索引任务已提交，但有 {$errorBatches} 个批次失败\",\n                'total' => $totalPages,\n                'total_batches' => $totalBatches,\n                'success_batches' => $successBatches,\n                'error_batches' => $errorBatches,\n                'task_ids' => $taskIds\n            ];\n        } catch (\\Exception $e) {\n            error_log(\"自动重建索引异常: item_id={$itemId}, 错误: \" . $e->getMessage());\n            return false;\n        }\n    }\n\n    /**\n     * 调用 AI 服务（非流式）\n     *\n     * @param string $url 请求URL\n     * @param array|null $postData POST数据\n     * @param string $aiServiceToken AI服务Token\n     * @param string $method 请求方法\n     * @param int $timeout 超时时间（秒）\n     * @return array|false\n     */\n    public static function callService(string $url, ?array $postData, string $aiServiceToken, string $method = 'POST', int $timeout = 30)\n    {\n        $curl = curl_init();\n        curl_setopt($curl, CURLOPT_URL, $url);\n        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);\n        curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 10);\n        curl_setopt($curl, CURLOPT_TIMEOUT, $timeout);\n        curl_setopt($curl, CURLOPT_ENCODING, '');\n\n        $headers = [\n            'Content-Type: application/json; charset=utf-8',\n            'Authorization: Bearer ' . $aiServiceToken,\n            'Accept: application/json; charset=utf-8'\n        ];\n\n        if ($method == 'POST' && $postData) {\n            curl_setopt($curl, CURLOPT_POST, 1);\n            curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($postData, JSON_UNESCAPED_UNICODE));\n        } elseif ($method == 'DELETE') {\n            curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'DELETE');\n            if ($postData) {\n                curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($postData, JSON_UNESCAPED_UNICODE));\n            }\n        } elseif ($method == 'GET') {\n            curl_setopt($curl, CURLOPT_HTTPGET, 1);\n        }\n\n        curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);\n\n        $result = curl_exec($curl);\n        $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);\n        $error = curl_error($curl);\n        curl_close($curl);\n\n        if ($result === false || $error) {\n            $errorMsg = $error ?: '连接失败';\n            error_log(\"AI服务调用失败: \" . $errorMsg . \" (URL: \" . $url . \")\");\n            return false;\n        }\n\n        if ($httpCode != 200) {\n            error_log(\"AI服务返回错误: HTTP \" . $httpCode . \", Response: \" . substr($result, 0, 500));\n            return false;\n        }\n\n        // 确保响应是 UTF-8 编码\n        if (!mb_check_encoding($result, 'UTF-8')) {\n            $result = mb_convert_encoding($result, 'UTF-8', 'auto');\n        }\n\n        $data = json_decode($result, true);\n        if ($data === null && json_last_error() !== JSON_ERROR_NONE) {\n            error_log(\"AI服务返回数据解析失败: \" . json_last_error_msg() . \", Response: \" . substr($result, 0, 500));\n            return false;\n        }\n\n        return $data;\n    }\n\n    /**\n     * 调用 AI 服务（流式）\n     *\n     * @param string $url 请求URL\n     * @param array $postData POST数据\n     * @param string $aiServiceToken AI服务Token\n     * @return void\n     */\n    public static function callServiceStream(string $url, array $postData, string $aiServiceToken): void\n    {\n        $callback = function ($ch, $data) {\n            if (connection_aborted()) {\n                return -1;\n            }\n\n            // 确保数据是 UTF-8 编码\n            if (!mb_check_encoding($data, 'UTF-8')) {\n                $detected = mb_detect_encoding($data, ['UTF-8', 'GBK', 'GB2312', 'ISO-8859-1'], true);\n                $data = mb_convert_encoding($data, 'UTF-8', $detected ?: 'auto');\n            }\n\n            echo $data;\n            flush();\n            return strlen($data);\n        };\n\n        $curl = curl_init();\n        curl_setopt($curl, CURLOPT_URL, $url);\n        curl_setopt($curl, CURLOPT_POST, 1);\n        curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($postData, JSON_UNESCAPED_UNICODE));\n        curl_setopt($curl, CURLOPT_WRITEFUNCTION, $callback);\n        curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 10);\n        curl_setopt($curl, CURLOPT_TIMEOUT, 300); // 5分钟超时\n        curl_setopt($curl, CURLOPT_ENCODING, '');\n        curl_setopt($curl, CURLOPT_HTTPHEADER, [\n            'Content-Type: application/json; charset=utf-8',\n            'Authorization: Bearer ' . $aiServiceToken,\n            'Accept: text/event-stream; charset=utf-8'\n        ]);\n\n        curl_exec($curl);\n        $error = curl_error($curl);\n        $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);\n        curl_close($curl);\n\n        // 如果请求失败，输出错误信息\n        if ($error || $httpCode != 200) {\n            $errorMsg = $error ?: \"HTTP {$httpCode}\";\n            echo \"data: \" . json_encode(['type' => 'error', 'message' => 'AI 服务调用失败: ' . $errorMsg], JSON_UNESCAPED_UNICODE) . \"\\n\\n\";\n            flush();\n        }\n    }\n\n    /**\n     * 递归收集所有页面数据\n     *\n     * @param array $menu 菜单数据\n     * @param array $pageData 页面数据数组（引用传递）\n     * @param Convert $convert Convert 对象\n     * @return void\n     */\n    private static function collectPages(array $menu, array &$pageData, Convert $convert): void\n    {\n        // 处理根目录下的页面\n        if (isset($menu['pages']) && is_array($menu['pages'])) {\n            foreach ($menu['pages'] as $page) {\n                self::processPage($page, $pageData, $convert);\n            }\n        }\n\n        // 递归处理子目录\n        if (isset($menu['catalogs']) && is_array($menu['catalogs'])) {\n            foreach ($menu['catalogs'] as $catalog) {\n                self::collectPages($catalog, $pageData, $convert);\n            }\n        }\n    }\n\n    /**\n     * 处理单个页面\n     *\n     * @param array $page 页面数据\n     * @param array $pageData 页面数据数组（引用传递）\n     * @param Convert $convert Convert 对象\n     * @return void\n     */\n    private static function processPage(array $page, array &$pageData, Convert $convert): void\n    {\n        $content = $page['page_content'] ?? '';\n        $pageType = $page['page_type'] ?? 'regular';\n\n        // HTML 反转义（因为存储的内容是 HTML 转义的）\n        $content = html_entity_decode($content, ENT_QUOTES | ENT_HTML5, 'UTF-8');\n\n        // 尝试使用 Convert 类转换为 Markdown（如果是 API 文档会自动转换，否则返回 false）\n        $mdContent = $convert->runapiToMd($content);\n        if ($mdContent !== false) {\n            $content = $mdContent;\n        }\n\n        // 跳过空内容的页面\n        if (empty($content) || !is_string($content) || trim($content) === '') {\n            error_log(\"跳过空内容页面: page_id=\" . ($page['page_id'] ?? '') . \", title=\" . ($page['page_title'] ?? ''));\n            return;\n        }\n\n        $pageData[] = [\n            'page_id' => $page['page_id'] ?? 0,\n            'page_title' => $page['page_title'] ?? '',\n            'page_content' => $content,\n            'page_type' => $pageType,\n            'cat_name' => $page['cat_name'] ?? '',\n            'update_time' => $page['update_time'] ?? time()\n        ];\n    }\n\n    /**\n     * 调用 OpenAI API\n     *\n     * @param array $messages 消息数组，格式：[['role' => 'system', 'content' => '...'], ['role' => 'user', 'content' => '...']]\n     * @param int $timeout 超时时间（秒），默认120秒\n     * @return string|false 成功返回结果字符串，失败返回false\n     */\n    public static function callOpenAI(array $messages, int $timeout = 120)\n    {\n        $aiModelName = Options::get('ai_model_name', 'gpt-4o-mini');\n        $openApiKey = Options::get('open_api_key');\n\n        $postData = json_encode([\n            'model' => $aiModelName,\n            'messages' => $messages,\n        ]);\n\n        $openApiHost = Options::get('open_api_host', 'https://api.openai.com');\n        if (!strstr($openApiHost, 'http')) {\n            $openApiHost = 'https://' . $openApiHost;\n        }\n        if (substr($openApiHost, -1) === '/') {\n            $openApiHost = substr($openApiHost, 0, -1);\n        }\n\n        $curl = curl_init();\n        curl_setopt($curl, CURLOPT_ENCODING, '');\n        curl_setopt($curl, CURLOPT_URL, $openApiHost . '/v1/chat/completions');\n        curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);\n\n        curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 30);\n        curl_setopt($curl, CURLOPT_TIMEOUT, $timeout);\n\n        curl_setopt($curl, CURLOPT_FRESH_CONNECT, true);\n        curl_setopt($curl, CURLOPT_FORBID_REUSE, true);\n\n        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);\n        curl_setopt($curl, CURLOPT_POST, 1);\n        curl_setopt($curl, CURLOPT_POSTFIELDS, $postData);\n        curl_setopt(\n            $curl,\n            CURLOPT_HTTPHEADER,\n            [\n                'Content-Type: application/json',\n                \"Authorization: Bearer {$openApiKey}\",\n                'Content-Length: ' . strlen($postData)\n            ]\n        );\n\n        $result = curl_exec($curl);\n\n        if ($result === false) {\n            $error = curl_error($curl);\n            $errno = curl_errno($curl);\n            curl_close($curl);\n            error_log(\"OpenAI API curl error: \" . $error . \" (errno: \" . $errno . \")\");\n            return false;\n        }\n\n        curl_close($curl);\n\n        return $result;\n    }\n\n    /**\n     * AI生成脚本\n     *\n     * @param string $scriptType 脚本类型：pre 或 post\n     * @param string $description 用户描述的需求\n     * @param string $apiInfo 接口信息（JSON字符串，可选）\n     * @param string $originalScript 原脚本内容（可选）\n     * @return string|false AI返回的结果\n     */\n    public static function generateScript(string $scriptType, string $description, string $apiInfo = '', string $originalScript = '')\n    {\n        $aiModelName = Options::get('ai_model_name', 'gpt-4o-mini');\n        $openApiKey = Options::get('open_api_key');\n\n        // 解析接口信息\n        $apiInfoObj = null;\n        if ($apiInfo) {\n            $apiInfoObj = json_decode($apiInfo, true);\n        }\n\n        // 构建系统提示词\n        $systemPrompt = '你是一个经验丰富的API测试脚本编写专家。用户会描述一个需求，你需要根据需求生成对应的JavaScript脚本代码。';\n\n        if ($scriptType === 'pre') {\n            $systemPrompt .= '这是\"前执行脚本\"（请求前执行），用于在发送HTTP请求之前修改请求参数、请求头、URL等。';\n        } else {\n            $systemPrompt .= '这是\"后执行脚本\"（请求后执行），用于处理响应结果、提取数据、进行断言测试等。';\n        }\n\n        $systemPrompt .= '\n\n脚本运行环境说明：\n- 脚本运行在安全的沙箱环境中，无法访问window、localStorage、document等浏览器对象\n- 通过runapi对象可以访问以下功能：\n\n内置库：\n- runapi.CryptoJS: 加密库（支持MD5、SHA256、AES加密/解密、Base64编码/解码、HMAC签名等）\n- runapi.moment: 时间处理库（支持时间格式化、计算、时间戳转换等）\n- runapi.JSEncrypt: RSA非对称加密库\n- runapi.ajax({ ... }): 同步AJAX请求\n\n变量操作：\n- runapi.getVar(name): 获取环境变量\n- runapi.setVar(name, value): 设置环境变量\n- runapi.clearVar(name): 清除环境变量\n- runapi.getLocalVar(name): 获取本地变量\n- runapi.setLocalVar(name, value): 设置本地变量\n- runapi.clearLocalVar(name): 清除本地变量\n\n数据库操作（仅 Electron 环境可用）：\n- runapi.db.query(sql, params?, configName?): 执行数据库查询\n  * sql: SQL 查询语句（必填）\n  * params: SQL 参数数组（可选），用于防止 SQL 注入，使用 ? 占位符\n  * configName: 数据库配置名称（可选），不指定则使用默认配置\n  * 返回值: 返回查询结果数组，每个元素为一行数据对象\n  * 注意: 查询是同步阻塞的，会等待查询完成后再继续执行\n  * 示例: \n    const user = runapi.db.query(\"SELECT * FROM users WHERE id = ?\", [123])[0];\n    const users = runapi.db.query(\"SELECT id, name FROM users WHERE status = 1\", [], \"主库\");\n\n';\n\n        if ($scriptType === 'pre') {\n            $systemPrompt .= '前执行脚本专用API：\n- runapi.getParam(name): 获取请求参数（通用方法，GET请求获取query参数，POST/PUT/DELETE请求获取body参数）\n- runapi.setParam(name, value): 设置请求参数（通用方法，GET请求设置query参数，POST/PUT/DELETE请求设置body参数）\n- runapi.deleteParam(name): 删除请求参数（通用方法，GET请求删除query参数，POST/PUT/DELETE请求删除body参数）\n- runapi.getAllParam(): 获取所有参数列表（通用方法，GET请求返回query参数列表，POST/PUT/DELETE请求返回body参数列表）\n- runapi.getParamJson(): 获取JSON格式的请求参数对象\n- runapi.setParamJson(objOrStr): 设置JSON格式的请求参数\n- runapi.getHeader(name): 获取请求头\n- runapi.setHeader(name, value): 设置请求头\n- runapi.getMethod(): 获取请求方法\n- runapi.getUrl(): 获取请求URL\n- runapi.setUrl(url): 设置请求URL（可用于动态修改请求地址，如根据环境切换API地址）\n- runapi.alert(v): 显示信息弹窗\n';\n        } else {\n            $systemPrompt .= '后执行脚本专用API：\n- runapi.responseBody: 响应体对象\n- runapi.responseHeader: 响应头对象\n- runapi.status: HTTP状态码\n- runapi.responseTime: 响应耗时（毫秒）\n- runapi.responseSize: 响应大小\n- runapi.bodyIsJson(): 判断响应体是否为JSON\n- runapi.bodyHas(keyword): 判断响应体是否包含关键字\n- runapi.assert(textOrFn): 断言测试\n- runapi.alert(v): 显示信息弹窗\n';\n        }\n\n        $systemPrompt .= '\n要求：\n1. 只返回JavaScript代码，不要包含额外不符合语法的解释文字。请写好完善的注释，在注释里讲清楚，不用额外文字或段落。\n2. 不要使用代码块标记（如```javascript）\n3. 代码应该简洁、实用、可直接运行\n4. 如果需求描述不够清晰，可以生成一个通用的示例脚本\n';\n\n        // 构建用户消息\n        $userMessage = \"需求描述：{$description}\";\n\n        if ($originalScript && trim($originalScript)) {\n            $userMessage .= \"\\n\\n现有脚本内容：\\n```javascript\\n{$originalScript}\\n```\\n\\n请根据需求描述，在现有脚本基础上进行修改或补充。如果需求是全新的功能，可以直接添加新代码；如果需求是修改现有功能，请修改对应的代码部分。\";\n        }\n\n        if ($apiInfoObj) {\n            $userMessage .= \"\\n\\n接口信息：\\n\";\n            if (isset($apiInfoObj['info'])) {\n                $info = $apiInfoObj['info'];\n                $userMessage .= \"- 接口URL: \" . ($info['url'] ?? '') . \"\\n\";\n                $userMessage .= \"- 请求方法: \" . ($info['method'] ?? '') . \"\\n\";\n                if (isset($info['description'])) {\n                    $userMessage .= \"- 接口描述: \" . $info['description'] . \"\\n\";\n                }\n            }\n        }\n\n        $messages = [\n            [\n                'role' => 'system',\n                'content' => $systemPrompt,\n            ],\n            [\n                'role' => 'user',\n                'content' => $userMessage,\n            ],\n        ];\n\n        return self::callOpenAI($messages, 120);\n    }\n\n    /**\n     * AI生成测试数据（示例值）\n     *\n     * @param array $params 参数数组，每个参数包含：name（参数名）、type（参数类型）、remark（参数描述，可选）\n     * @param string $apiInfo 接口信息（JSON字符串，可选）\n     * @param int $count 生成数据组数，默认1组\n     * @return string|false AI返回的结果\n     */\n    public static function generateTestData(array $params, string $apiInfo = '', int $count = 1)\n    {\n        $aiModelName = Options::get('ai_model_name', 'gpt-4o-mini');\n        $openApiKey = Options::get('open_api_key');\n\n        // 解析接口信息\n        $apiInfoObj = null;\n        if ($apiInfo) {\n            $apiInfoObj = json_decode($apiInfo, true);\n        }\n\n        // 构建系统提示词\n        $systemPrompt = '你是一个经验丰富的API测试数据生成专家。用户会提供一组参数信息，你需要根据参数名、参数类型和参数描述，智能推断并生成合理的测试数据（示例值）。\n\n要求：\n1. 根据参数名智能推断参数含义（如 email → test@example.com，phone → 13800138000，user_id → 12345）\n2. 根据参数类型生成对应格式的数据（string、number、boolean、array、object等）\n3. 生成的数据应该符合业务逻辑，多个参数之间应该有关联性（如 age: 25，status: 1）\n4. 如果参数有描述信息，优先根据描述生成更准确的数据\n5. 生成的数据应该是固定的示例值，不是动态值或模板\n\n输出格式：\n- 必须返回JSON格式，格式为：{\"data\": [{\"param1\": \"value1\", \"param2\": \"value2\", ...}, ...]}\n- 如果count=1，返回一个对象数组，包含1组数据\n- 如果count>1，返回一个对象数组，包含多组不同的数据（正常数据、边界数据、异常数据等）\n- 只返回JSON，不要包含任何其他文字说明或代码块标记';\n\n        // 构建用户消息\n        $userMessage = \"请为以下参数生成测试数据：\\n\\n\";\n\n        foreach ($params as $index => $param) {\n            $userMessage .= ($index + 1) . \". 参数名: \" . ($param['name'] ?? '') . \"\\n\";\n            $userMessage .= \"   类型: \" . ($param['type'] ?? 'string') . \"\\n\";\n            if (!empty($param['remark'])) {\n                $userMessage .= \"   描述: \" . $param['remark'] . \"\\n\";\n            }\n            $userMessage .= \"\\n\";\n        }\n\n        if ($count > 1) {\n            $userMessage .= \"请生成 {$count} 组不同的测试数据，包括正常数据、边界数据和异常数据。\\n\";\n        } else {\n            $userMessage .= \"请生成 1 组合理的测试数据。\\n\";\n        }\n\n        if ($apiInfoObj) {\n            $userMessage .= \"\\n接口信息：\\n\";\n            if (isset($apiInfoObj['info'])) {\n                $info = $apiInfoObj['info'];\n                $userMessage .= \"- 接口URL: \" . ($info['url'] ?? '') . \"\\n\";\n                $userMessage .= \"- 请求方法: \" . ($info['method'] ?? '') . \"\\n\";\n                if (isset($info['description'])) {\n                    $userMessage .= \"- 接口描述: \" . $info['description'] . \"\\n\";\n                }\n            }\n        }\n\n        $messages = [\n            [\n                'role' => 'system',\n                'content' => $systemPrompt,\n            ],\n            [\n                'role' => 'user',\n                'content' => $userMessage,\n            ],\n        ];\n\n        return self::callOpenAI($messages, 120);\n    }\n}\n"
  },
  {
    "path": "server/app/Common/Helper/ContentCodec.php",
    "content": "<?php\n\nnamespace App\\Common\\Helper;\n\n/**\n * 负责与旧数据兼容的内容压缩/解压逻辑。\n *\n * 注意：算法需与旧版 compress_string/uncompress_string 完全一致，\n * 以便读取历史已压缩的 page_content。\n */\nclass ContentCodec\n{\n    public static function compress(string $string): string\n    {\n        return base64_encode(gzcompress($string, 9));\n    }\n\n    public static function decompress(?string $string): string\n    {\n        if ($string === null || $string === '') {\n            return '';\n        }\n\n        $decoded = base64_decode($string, true);\n        if ($decoded === false) {\n            return '';\n        }\n\n        $uncompressed = @gzuncompress($decoded);\n        if ($uncompressed === false) {\n            // 不是压缩过的内容，则原样返回\n            return $string;\n        }\n\n        return $uncompressed;\n    }\n}\n"
  },
  {
    "path": "server/app/Common/Helper/Convert.php",
    "content": "<?php\n\nnamespace App\\Common\\Helper;\n\nuse App\\Model\\Options;\nuse PHPSQLParser\\PHPSQLParser;\n\n/**\n * 各类内容格式转换工具（SQL → Markdown、Runapi JSON ↔ Markdown 等）。\n *\n * 该实现基于旧版 `Api\\Helper\\Convert`，但不再依赖 ThinkPHP 的 D()/M()，\n * 所有配置通过新模型 `App\\Model\\Options` 获取。\n */\nclass Convert\n{\n    /**\n     * 转换 SQL 为 Markdown 表格\n     */\n    public function convertSqlToMarkdownTable($sql)\n    {\n        $sqlArray = $this->convertSqlToArray($sql);\n\n        if (!is_array($sqlArray) || empty($sqlArray['fields'])) {\n            return \"\";\n        }\n\n        $headers = [\n            ['字段', '类型', '允许空', '默认', '说明'],\n            ['---', '---', '---', '---', '---'],\n        ];\n\n        $markdownRows = [];\n        foreach ($sqlArray['fields'] as $field) {\n            $markdownRows[] = [\n                $field['name'] ?? '',\n                $field['type'] ?? '',\n                $field['nullable'] ?? '',\n                $field['default'] ?? '',\n                $field['comment'] ?? '',\n            ];\n        }\n\n        array_unshift($markdownRows, ...$headers);\n\n        $md = \"\\n- {$sqlArray['table']} {$sqlArray['comment']}\\n\\n\";\n        foreach ($markdownRows as $line) {\n            $md .= '| ' . implode(' | ', $line) . \" |\\n\";\n        }\n\n        return $md . \"\\n\";\n    }\n\n    /**\n     * 把 CREATE TABLE 语句解析成结构化数组\n     */\n    public function convertSqlToArray($sql)\n    {\n        $result = [\n            'table'   => '',\n            'comment' => '',\n            'fields'  => [],\n        ];\n\n        try {\n            $parser = new PHPSQLParser();\n            $parsed = $parser->parse($sql);\n\n            if (!isset($parsed['CREATE']) || ($parsed['CREATE']['expr_type'] ?? '') !== 'table') {\n                return $result;\n            }\n\n            $tableNode = $parsed['TABLE'] ?? null;\n            if (!$tableNode || !isset($tableNode['create-def']['sub_tree'])) {\n                return $result;\n            }\n\n            $fields = $tableNode['create-def']['sub_tree'];\n            $tableName = $tableNode['base_expr'] ?? '';\n\n            foreach ($fields as $field) {\n                if (!isset($field['sub_tree'][0])) {\n                    continue;\n                }\n\n                // 跳过约束行（PRIMARY KEY/UNIQUE 等）\n                if (($field['sub_tree'][0]['expr_type'] ?? '') === 'constraint') {\n                    continue;\n                }\n\n                if (!isset($field['sub_tree'][1]['sub_tree'])) {\n                    continue;\n                }\n\n                $type   = '';\n                $length = '';\n                foreach ($field['sub_tree'][1]['sub_tree'] as $item) {\n                    if (($item['expr_type'] ?? '') === 'data-type') {\n                        $type   = $item['base_expr'] ?? '';\n                        $length = $item['length'] ?? '';\n                    }\n                }\n\n                $name    = $field['sub_tree'][0]['base_expr'] ?? '';\n                $comment = trim($field['sub_tree'][1]['comment'] ?? '', \"'\");\n                $nullable = $field['sub_tree'][1]['nullable'] ?? false;\n                $default  = $field['sub_tree'][1]['default'] ?? '';\n\n                $typeStr = $length === '' ? $type : sprintf('%s (%s)', $type, $length);\n\n                $result['fields'][] = [\n                    'name'     => trim($name, '`'),\n                    'type'     => $typeStr,\n                    'nullable' => $nullable ? '是' : '否',\n                    'default'  => trim($default, \"'\"),\n                    'comment'  => $comment !== '' ? $comment : '-',\n                ];\n            }\n\n            // 表注释\n            $tableComment = '';\n            $options = $tableNode['options'] ?? [];\n            foreach ($options as $option) {\n                $type = strtoupper($option['sub_tree'][0]['base_expr'] ?? '');\n                if ($type === 'COMMENT') {\n                    $tableComment = trim($option['sub_tree'][2]['base_expr'] ?? '', \"'\");\n                    break;\n                }\n            }\n\n            $result['table']   = trim($tableName, '`');\n            $result['comment'] = $tableComment;\n        } catch (\\Throwable $e) {\n            // 解析失败时返回空结构，由上层自行判断\n            return $result;\n        }\n\n        return $result;\n    }\n\n    /**\n     * 把 runapi 的 JSON/字符串内容尝试转换为 Markdown。\n     * 非 runapi 格式时返回 false（保持与旧实现兼容）。\n     */\n    public function runapiToMd($content)\n    {\n        if (!is_array($content)) {\n            $contentJson = html_entity_decode((string) $content, ENT_QUOTES | ENT_HTML5, 'UTF-8');\n            $content = json_decode($contentJson, true);\n        }\n\n        if (!$content || !isset($content['info']) || empty($content['info']['url'])) {\n            return false;\n        }\n\n        $type = $content['info']['type'] ?? 'api';\n\n        if ($type === 'websocket') {\n            return $this->runapiWebSocketToMd($content);\n        }\n        if ($type === 'sse') {\n            return $this->runapiSSEToMd($content);\n        }\n\n        return $this->runapiHttpApiToMd($content);\n    }\n\n    /**\n     * HTTP API → Markdown（摘自旧实现，略做整理）。\n     */\n    private function runapiHttpApiToMd(array $content)\n    {\n        // 兼容 query：GET 且 query 为空时，从 params.mode 对应的数据填充\n        if (($content['info']['method'] ?? '') === 'get') {\n            if (empty($content['request']['query'])) {\n                $mode = $content['request']['params']['mode'] ?? '';\n                if ($mode && !empty($content['request']['params'][$mode])) {\n                    $content['request']['query'] = $content['request']['params'][$mode];\n                    $content['request']['params'][$mode] = [];\n                }\n            }\n        }\n\n        $desc = $content['info']['description'] ?? '无';\n        $new  = \"\\n##### 简要描述\\n\\n- {$desc}\";\n\n        // 接口状态\n        if (!empty($content['info']['apiStatus'])) {\n            $statusText = '';\n            switch ((string) $content['info']['apiStatus']) {\n                case '1':\n                    $statusText = '开发中';\n                    break;\n                case '2':\n                    $statusText = '测试中';\n                    break;\n                case '3':\n                    $statusText = '已完成';\n                    break;\n                case '4':\n                    $statusText = '需修改';\n                    break;\n                case '5':\n                    $statusText = '已废弃';\n                    break;\n            }\n            if ($statusText !== '') {\n                $new .= \"\\n\\n##### 接口状态\\n\\n - {$statusText}\";\n            }\n        }\n\n        // 如果有 query 参数则去掉 URL 上的查询串\n        $query = $content['request']['query'] ?? [];\n        if (!empty($query) && isset($query[0]['name']) && $query[0]['name']) {\n            $parts = explode('?', $content['info']['url'] ?? '');\n            $content['info']['url'] = $parts[0];\n        }\n\n        $url    = $content['info']['url'] ?? '';\n        $method = $content['info']['method'] ?? '';\n        $new   .= \"\\n\\n##### 请求URL\\n\\n - `{$url}` \\n\\n##### 请求方式\\n\\n- {$method}\\n\";\n\n        // 路径变量\n        $pathVariable = $content['request']['pathVariable'] ?? [];\n        if (!empty($pathVariable) && isset($pathVariable[0]['name']) && $pathVariable[0]['name']) {\n            $new .= \" \\n##### 路径变量\\n\\n|变量名|必选|类型|说明|\\n|:-----  |:-----|-----|-----|\\n\";\n            foreach ($pathVariable as $v) {\n                if (empty($v['name']) || (!empty($v['disable']) && $v['disable'] >= 1)) {\n                    continue;\n                }\n                $require = !empty($v['require']) ? '是' : '否';\n                $remark  = $v['remark'] ?? '无';\n                $type    = $v['type'] ?? '';\n                $new    .= \"|{$v['name']}|  {$require} |  {$type} |  {$remark} | \\n\";\n            }\n        }\n\n        // Header\n        $headers = $content['request']['headers'] ?? [];\n        if (!empty($headers) && isset($headers[0]['name']) && $headers[0]['name']) {\n            $new .= \" \\n##### Header \\n\\n|字段名|示例值|必选|类型|说明|\\n|:-----  |:-----|-----|-----|-----|\\n\";\n            foreach ($headers as $h) {\n                if (empty($h['name']) || (!empty($h['disable']) && $h['disable'] >= 1)) {\n                    continue;\n                }\n                $require = !empty($h['require']) ? '是' : '否';\n                $remark  = $h['remark'] ?? '无';\n                $value   = $h['value'] ?? '';\n                $type    = $h['type'] ?? '';\n                $new    .= \"|{$h['name']}|  {$value} |  {$require} |  {$type} |  {$remark} | \\n\";\n            }\n        }\n\n        // Query 参数\n        if (!empty($query) && isset($query[0]['name']) && $query[0]['name']) {\n            $new .= \" \\n##### 请求Query参数\\n\\n|参数名|示例值|必选|类型|说明|\\n|:-----  |:-----|-----|-----|-----|\\n\";\n            foreach ($query as $q) {\n                if (empty($q['name']) || (!empty($q['disable']) && $q['disable'] >= 1)) {\n                    continue;\n                }\n                $require = !empty($q['require']) ? '是' : '否';\n                $remark  = $q['remark'] ?? '无';\n                $value   = $q['value'] ?? '';\n                $type    = $q['type'] ?? '';\n                $new    .= \"|{$q['name']}|  {$value}|  {$require} |  {$type} |  {$remark} | \\n\";\n            }\n        }\n\n        // Body 参数\n        $mode   = $content['request']['params']['mode'] ?? '';\n        $params = $mode ? ($content['request']['params'][$mode] ?? []) : [];\n        if (!empty($params) && isset($params[0]['name']) && $params[0]['name']) {\n            $new .= \" \\n##### 请求Body参数\\n\\n|参数名|示例值|必选|类型|说明|\\n|:-----  |:-----|-----|-----|-----|\\n\";\n            foreach ($params as $p) {\n                if (empty($p['name']) || (!empty($p['disable']) && $p['disable'] >= 1)) {\n                    continue;\n                }\n                $require = !empty($p['require']) ? '是' : '否';\n                $remark  = $p['remark'] ?? '无';\n                $value   = $p['value'] ?? '';\n                $type    = $p['type'] ?? '';\n                $new    .= \"|{$p['name']}|  {$value} |  {$require} |  {$type} |  {$remark} | \\n\";\n            }\n        }\n\n        // JSON 示例\n        if ($mode === 'json' && !empty($params)) {\n            $json = $this->indentJson($params);\n            $new .= \" \\n##### 请求参数示例  \\n```\\n{$json}\\n\\n``` \\n\";\n        }\n\n        // json 字段说明\n        $jsonDesc = $content['request']['params']['jsonDesc'] ?? [];\n        if ($mode === 'json' && !empty($jsonDesc) && isset($jsonDesc[0]['name']) && $jsonDesc[0]['name']) {\n            $new .= \" \\n##### json字段说明\\n\\n|字段名|必选|类型|说明|\\n|:-----  |:-----|-----|-----|\\n\";\n            foreach ($jsonDesc as $j) {\n                if (empty($j['name']) || (!empty($j['disable']) && $j['disable'] >= 1)) {\n                    continue;\n                }\n                $require = !empty($j['require']) ? '是' : '否';\n                $remark  = $j['remark'] ?? '无';\n                $type    = $j['type'] ?? '';\n                $new    .= \"|{$j['name']}|  {$require} |  {$type} |  {$remark} | \\n\";\n            }\n        }\n\n        // 成功返回示例\n        if (!empty($content['response']['responseExample'])) {\n            $example = $this->indentJson($content['response']['responseExample']);\n            $new    .= \" \\n##### 成功返回示例  \\n```\\n{$example}\\n\\n``` \\n\";\n        }\n\n        // 成功返回参数说明\n        $respParams = $content['response']['responseParamsDesc'] ?? [];\n        if (!empty($respParams) && isset($respParams[0]['name']) && $respParams[0]['name']) {\n            $new .= \" \\n##### 成功返回示例的参数说明 \\n\\n|参数名|类型|说明|\\n|:-----  |:-----|-----|\\n\";\n            foreach ($respParams as $rp) {\n                $remark = $rp['remark'] ?? '无';\n                $new   .= \"|{$rp['name']}| {$rp['type']} |  {$remark} | \\n\";\n            }\n        }\n\n        // 失败返回示例\n        if (!empty($content['response']['responseFailExample'])) {\n            $example = $this->indentJson($content['response']['responseFailExample']);\n            $new    .= \" \\n##### 失败返回示例  \\n```\\n{$example}\\n\\n``` \\n\";\n        }\n\n        // 失败返回参数说明\n        $failParams = $content['response']['responseFailParamsDesc'] ?? [];\n        if (!empty($failParams) && isset($failParams[0]['name']) && $failParams[0]['name']) {\n            $new .= \" \\n##### 失败返回示例的参数说明 \\n|参数名|类型|说明|\\n|:-----  |:-----|-----|\\n\";\n            foreach ($failParams as $fp) {\n                $remark = $fp['remark'] ?? '无';\n                $new   .= \"|{$fp['name']}| {$fp['type']} |  {$remark} | \\n\";\n            }\n        }\n\n        if (!empty($content['info']['remark'])) {\n            $new .= \" \\n##### 备注 \\n {$content['info']['remark']}\\n\";\n        }\n\n        return $new;\n    }\n\n    // WebSocket / SSE 转 Markdown 这里略，同样可以在需要时完整迁移\n    private function runapiWebSocketToMd(array $content)\n    {\n        // 为保持迁移粒度可控，先复用 HTTP 版本的摘要信息\n        return $this->runapiHttpApiToMd($content);\n    }\n\n    private function runapiSSEToMd(array $content)\n    {\n        return $this->runapiHttpApiToMd($content);\n    }\n\n    /**\n     * JSON 字符串美化\n     */\n    private function indentJson($json)\n    {\n        $jsonNew = json_encode(json_decode((string) $json, true), JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);\n        if ($jsonNew && $jsonNew !== 'null') {\n            return $jsonNew;\n        }\n        return (string) $json;\n    }\n\n    /**\n     * （可选）Markdown → runapi JSON：保留接口，内部依旧走 OpenAI，但使用新 Options 模型\n     * 以便后续平滑接入，不再依赖 ThinkPHP 的 D()。\n     */\n    public function mdToRunapi(string $markdownContent): ?string\n    {\n        $aiModelName = Options::get('ai_model_name', 'gpt-4o-mini');\n        $openApiKey  = Options::get('open_api_key', '');\n        if ($openApiKey === '') {\n            return null;\n        }\n\n        $postData = json_encode([\n            'model'    => $aiModelName,\n            'messages' => [\n                [\n                    'role'    => 'system',\n                    'content' => '你是一个经验丰富的API接口文档转换专家，用户会输入一段markdown格式的API接口文档，请将这段文档转换为runapi格式的API接口。只返回转换后的json，不要包裹在代码块里，也不要额外解释。',\n                ],\n                [\n                    'role'    => 'user',\n                    'content' => $markdownContent,\n                ],\n            ],\n        ], JSON_UNESCAPED_UNICODE);\n\n        $openApiHost = Options::get('open_api_host', 'https://api.openai.com');\n        if (strpos($openApiHost, 'http') !== 0) {\n            $openApiHost = 'https://' . $openApiHost;\n        }\n        $openApiHost = rtrim($openApiHost, '/');\n\n        $ch = curl_init();\n        curl_setopt($ch, CURLOPT_ENCODING, '');\n        curl_setopt($ch, CURLOPT_URL, $openApiHost . '/v1/chat/completions');\n        curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);\n        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);\n        curl_setopt($ch, CURLOPT_TIMEOUT, 480);\n        curl_setopt($ch, CURLOPT_FRESH_CONNECT, true);\n        curl_setopt($ch, CURLOPT_FORBID_REUSE, true);\n        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);\n        curl_setopt($ch, CURLOPT_POST, 1);\n        curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);\n        curl_setopt($ch, CURLOPT_HTTPHEADER, [\n            'Content-Type: application/json',\n            'Authorization: Bearer ' . $openApiKey,\n            'Content-Length: ' . strlen($postData),\n        ]);\n\n        $result = curl_exec($ch);\n        if ($result === false) {\n            error_log('Convert mdToRunapi curl error: ' . curl_error($ch));\n            curl_close($ch);\n            return null;\n        }\n        curl_close($ch);\n\n        return $result;\n    }\n}\n"
  },
  {
    "path": "server/app/Common/Helper/Env.php",
    "content": "<?php\n\nnamespace App\\Common\\Helper;\n\n/**\n * 统一环境变量读取工具，优先 .env / $_ENV / $_SERVER，最后退回 getenv()。\n *\n * 注意：不依赖旧的 Application/Common/Common/function.php 里的 env()，\n * 以免和 ThinkPHP 的实现绑死逻辑。\n */\nclass Env\n{\n    public static function get(string $key, $default = null)\n    {\n        if (array_key_exists($key, $_ENV)) {\n            return $_ENV[$key];\n        }\n\n        if (array_key_exists($key, $_SERVER)) {\n            return $_SERVER[$key];\n        }\n\n        $val = getenv($key);\n        return $val !== false ? $val : $default;\n    }\n}\n\n"
  },
  {
    "path": "server/app/Common/Helper/FileHelper.php",
    "content": "<?php\n\nnamespace App\\Common\\Helper;\n\n/**\n * 文件处理 Helper\n * 封装文件操作相关功能\n */\nclass FileHelper\n{\n    /**\n     * 输出 Word 文档\n     *\n     * @param string $data HTML 内容\n     * @param string $fileName 文件名（不含扩展名）\n     * @return void\n     */\n    public static function outputWord(string $data, string $fileName = ''): void\n    {\n        if (empty($data)) {\n            return;\n        }\n\n        $data = '<html xmlns:v=\"urn:schemas-microsoft-com:vml\"\n    xmlns:o=\"urn:schemas-microsoft-com:office:office\"\n    xmlns:w=\"urn:schemas-microsoft-com:office:word\"\n    xmlns=\"http://www.w3.org/TR/REC-html40\">\n    <head><meta http-equiv=Content-Type content=\"text/html; charset=utf-8\">\n    <style type=\"text/css\">\n        table  \n        {  \n            border-collapse: collapse;\n            border: none;  \n            width: 100%;  \n        }  \n        td,tr  \n        {  \n            border: solid #CCC 1px;\n            padding:3px;\n            font-size:9pt;\n        } \n        .codestyle{\n            word-break: break-all;\n            mso-highlight:rgb(252, 252, 252);\n            padding-left: 5px; background-color: rgb(252, 252, 252); border: 1px solid rgb(225, 225, 232);\n        }\n        img {\n            width:100;\n        }\n    </style>\n    <meta name=ProgId content=Word.Document>\n    <meta name=Generator content=\"Microsoft Word 11\">\n    <meta name=Originator content=\"Microsoft Word 11\">\n    <xml><w:WordDocument><w:View>Print</w:View></xml></head>\n    <body>' . $data . '</body></html>';\n\n        $filepath = tmpfile();\n        $data = str_replace(\"<thead>\\n<tr>\", \"<thead><tr style='background-color: rgb(0, 136, 204); color: rgb(255, 255, 255);'>\", $data);\n        $data = str_replace(\"<pre><code\", \"<table width='100%' class='codestyle'><pre><code\", $data);\n        $data = str_replace(\"</code></pre>\", \"</code></pre></table>\", $data);\n        $data = str_replace(\"<img \", \"<img style='max-width:500' \", $data);\n        $len = strlen($data);\n        fwrite($filepath, $data);\n        header(\"Content-type: application/octet-stream\");\n        header(\"Content-Disposition: attachment; filename={$fileName}.doc\");\n        header('Content-Description: File Transfer');\n        header('Content-Type: application/octet-stream');\n        header('Content-Disposition: attachment; filename=' . $fileName . '.doc');\n        header('Content-Transfer-Encoding: binary');\n        header('Expires: 0');\n        header('Cache-Control: must-revalidate, post-check=0, pre-check=0');\n        header('Pragma: public');\n        header('Content-Length: ' . $len);\n        rewind($filepath);\n        echo fread($filepath, $len);\n    }\n\n    /**\n     * 递归删除目录及其内容\n     *\n     * @param string $path 目录路径\n     * @return bool|null 成功返回true，失败返回null\n     */\n    public static function clearRuntime(string $path): ?bool\n    {\n        // 给定的目录不是一个文件夹\n        if (!is_dir($path)) {\n            return null;\n        }\n\n        $fh = opendir($path);\n        while (($row = readdir($fh)) !== false) {\n            // 过滤掉虚拟目录\n            if ($row == '.' || $row == '..' || $row == 'index.html') {\n                continue;\n            }\n\n            if (!is_dir($path . '/' . $row)) {\n                unlink($path . '/' . $row);\n            } else {\n                self::clearRuntime($path . '/' . $row);\n            }\n        }\n        // 关闭目录句柄，否则出Permission denied\n        closedir($fh);\n        return true;\n    }\n\n    /**\n     * 生成随机字符串\n     *\n     * @param int $len 长度\n     * @return string 随机字符串\n     */\n    public static function getRandStr(int $len = 32): string\n    {\n        // 对于 PHP 7.0 以上版本，使用 random_bytes 产生加密安全的随机数\n        if (version_compare(PHP_VERSION, '7.0', '>')) {\n            $rand = bin2hex(random_bytes(16));\n            return substr($rand, 0, $len);\n        } else {\n            // 对于低版本，使用复杂的混合随机源实现伪随机，增大暴力破解难度\n            $s1 = microtime(true) . time() . rand() . rand() . rand() . microtime(true) . time() . rand() . rand() . rand();\n            $s2 = microtime(true) . time() . rand() . rand() . rand() . microtime(true) . time() . rand() . rand() . rand();\n            $md5 = md5($s2 . base64_encode($s1));\n            return substr($md5, 0, $len);\n        }\n    }\n\n    /**\n     * 清理文件名/目录名中的非法字符\n     *\n     * @param string $filename 原始文件名\n     * @return string 清理后的文件名\n     */\n    public static function sanitizeFilename(string $filename): string\n    {\n        // Windows/Linux 文件名非法字符: < > : \" / \\ | ? *\n        // 同时去除前后空格和点号\n        $filename = trim($filename);\n\n        // 替换非法字符为下划线\n        $filename = preg_replace('/[<>:\"\\/\\\\\\|\\?\\*\\x00-\\x1F]/', '_', $filename);\n\n        // 去除连续的下划线和点号\n        $filename = preg_replace('/[_\\.]+/', '_', $filename);\n\n        // 去除前后下划线和点号\n        $filename = trim($filename, '_.');\n\n        // 如果文件名为空，使用默认名称\n        if (empty($filename)) {\n            $filename = '未命名';\n        }\n\n        // Windows 保留文件名\n        $reservedNames = ['CON', 'PRN', 'AUX', 'NUL', 'COM1', 'COM2', 'COM3', 'COM4', 'COM5', 'COM6', 'COM7', 'COM8', 'COM9', 'LPT1', 'LPT2', 'LPT3', 'LPT4', 'LPT5', 'LPT6', 'LPT7', 'LPT8', 'LPT9'];\n        if (in_array(strtoupper($filename), $reservedNames)) {\n            $filename = $filename . '_';\n        }\n\n        // 限制文件名长度（Windows 限制为 255 字符）\n        if (mb_strlen($filename) > 200) {\n            $filename = mb_substr($filename, 0, 200);\n        }\n\n        return $filename;\n    }\n}\n"
  },
  {
    "path": "server/app/Common/Helper/HttpHelper.php",
    "content": "<?php\n\nnamespace App\\Common\\Helper;\n\n/**\n * HTTP 请求 Helper\n * 封装 http_post、http_get 等 HTTP 请求方法\n */\nclass HttpHelper\n{\n    /**\n     * HTTP POST 请求\n     *\n     * @param string $url 请求URL\n     * @param array|string $param 请求参数（数组或字符串）\n     * @return string|false 返回响应内容，失败返回false\n     */\n    public static function post(string $url, $param)\n    {\n        $ch = curl_init();\n\n        // 如果是 HTTPS，跳过证书验证\n        if (stripos($url, \"https://\") !== false) {\n            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);\n            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);\n        }\n\n        // 处理参数\n        if (is_string($param)) {\n            $postData = $param;\n        } else {\n            $postArray = [];\n            foreach ($param as $key => $val) {\n                $postArray[] = $key . \"=\" . urlencode($val);\n            }\n            $postData = join(\"&\", $postArray);\n        }\n\n        curl_setopt($ch, CURLOPT_URL, $url);\n        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);\n        curl_setopt($ch, CURLOPT_POST, true);\n        curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);\n\n        $response = curl_exec($ch);\n        $error = curl_error($ch);\n        curl_close($ch);\n\n        if ($error) {\n            return false;\n        }\n\n        return $response;\n    }\n\n    /**\n     * HTTP GET 请求\n     *\n     * @param string $url 请求URL\n     * @param array $headers 请求头（可选）\n     * @param int $timeout 超时时间（秒，默认30）\n     * @return string|false 返回响应内容，失败返回false\n     */\n    public static function get(string $url, array $headers = [], int $timeout = 30)\n    {\n        $ch = curl_init();\n\n        curl_setopt($ch, CURLOPT_URL, $url);\n        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);\n        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);\n        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);\n        curl_setopt($ch, CURLOPT_HEADER, 0);\n        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);\n        curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);\n\n        if (!empty($headers)) {\n            curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);\n        }\n\n        $response = curl_exec($ch);\n        $error = curl_error($ch);\n        curl_close($ch);\n\n        if ($error) {\n            return false;\n        }\n\n        return $response;\n    }\n}\n"
  },
  {
    "path": "server/app/Common/Helper/IpHelper.php",
    "content": "<?php\n\nnamespace App\\Common\\Helper;\n\nclass IpHelper\n{\n    /**\n     * 获取客户端 IP，逻辑参考旧版 getIPaddress()。\n     */\n    public static function getClientIp(): string\n    {\n        $ip = '';\n\n        if (!empty($_SERVER)) {\n            if (!empty($_SERVER['HTTP_X_ORIGINAL_FORWARDED_FOR'])) {\n                $ip = $_SERVER['HTTP_X_ORIGINAL_FORWARDED_FOR'];\n            } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {\n                $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];\n            } elseif (!empty($_SERVER['HTTP_CLIENT_IP'])) {\n                $ip = $_SERVER['HTTP_CLIENT_IP'];\n            } else {\n                $ip = $_SERVER['REMOTE_ADDR'] ?? '';\n            }\n        } else {\n            if (getenv('HTTP_X_FORWARDED_FOR')) {\n                $ip = getenv('HTTP_X_FORWARDED_FOR');\n            } elseif (getenv('HTTP_CLIENT_IP')) {\n                $ip = getenv('HTTP_CLIENT_IP');\n            } else {\n                $ip = getenv('REMOTE_ADDR') ?: '';\n            }\n        }\n\n        // 如果存在逗号，取第一个\n        $parts = explode(',', $ip);\n        $ip    = trim($parts[0] ?? '');\n\n        return $ip;\n    }\n}\n"
  },
  {
    "path": "server/app/Common/Helper/LogHelper.php",
    "content": "<?php\n\nnamespace App\\Common\\Helper;\n\n/**\n * 日志辅助类\n *\n * 统一处理日志记录，将日志写入到项目目录下的 Runtime/Logs 目录\n */\nclass LogHelper\n{\n  /**\n   * 获取日志文件路径\n   *\n   * @param string $module 模块名称（如 'Api', 'Home'），用于分类日志文件\n   * @return string 日志文件完整路径\n   */\n  private static function getLogPath(string $module = 'Common'): string\n  {\n    // 优先使用已定义的 LOG_PATH 常量（在 server/index.php 中定义）\n    if (defined('LOG_PATH')) {\n      $logDir = LOG_PATH;\n    } else {\n      // 如果没有定义，使用相对于 app 目录的路径\n      // LogHelper 位于 server/app/Common/Helper/LogHelper.php\n      // 所以需要回到 app 目录，然后进入 Runtime/Logs\n      $appDir = dirname(dirname(__DIR__)); // 从 Helper 回到 app 目录\n      $logDir = $appDir . DIRECTORY_SEPARATOR . 'Runtime' . DIRECTORY_SEPARATOR . 'Logs' . DIRECTORY_SEPARATOR;\n    }\n\n    // 确保目录存在\n    if (!is_dir($logDir)) {\n      @mkdir($logDir, 0755, true);\n    }\n\n    // 按日期和模块生成日志文件名\n    $date = date('Y_m_d');\n    $logFile = $logDir . $module . '_' . $date . '.log';\n\n    return $logFile;\n  }\n\n  /**\n   * 记录日志\n   *\n   * @param string $message 日志消息\n   * @param string $module 模块名称（可选，默认为 'Common'）\n   * @param string $level 日志级别（可选，默认为 'INFO'）\n   * @return bool 是否成功写入\n   */\n  public static function write(string $message, string $module = 'Common', string $level = 'INFO'): bool\n  {\n    $logFile = self::getLogPath($module);\n\n    // 格式化日志内容：时间戳 [级别] 消息\n    $timestamp = date('Y-m-d H:i:s');\n    $logContent = sprintf(\n      \"[%s] [%s] %s\\n\",\n      $timestamp,\n      $level,\n      $message\n    );\n\n    // 写入日志文件（追加模式）\n    $result = @file_put_contents($logFile, $logContent, FILE_APPEND | LOCK_EX);\n\n    // 如果写入失败，尝试输出到标准错误（作为后备）\n    if ($result === false) {\n      error_log($logContent);\n    }\n\n    return $result !== false;\n  }\n\n  /**\n   * 记录错误日志\n   *\n   * @param string $message 错误消息\n   * @param string $module 模块名称（可选）\n   * @return bool\n   */\n  public static function error(string $message, string $module = 'Common'): bool\n  {\n    return self::write($message, $module, 'ERROR');\n  }\n\n  /**\n   * 记录警告日志\n   *\n   * @param string $message 警告消息\n   * @param string $module 模块名称（可选）\n   * @return bool\n   */\n  public static function warning(string $message, string $module = 'Common'): bool\n  {\n    return self::write($message, $module, 'WARNING');\n  }\n\n  /**\n   * 记录信息日志\n   *\n   * @param string $message 信息消息\n   * @param string $module 模块名称（可选）\n   * @return bool\n   */\n  public static function info(string $message, string $module = 'Common'): bool\n  {\n    return self::write($message, $module, 'INFO');\n  }\n\n  /**\n   * 记录调试日志\n   *\n   * @param string $message 调试消息\n   * @param string $module 模块名称（可选）\n   * @return bool\n   */\n  public static function debug(string $message, string $module = 'Common'): bool\n  {\n    return self::write($message, $module, 'DEBUG');\n  }\n\n  /**\n   * 记录异常日志\n   *\n   * @param \\Throwable $exception 异常对象\n   * @param string $module 模块名称（可选）\n   * @return bool\n   */\n  public static function exception(\\Throwable $exception, string $module = 'Common'): bool\n  {\n    $message = sprintf(\n      \"Exception: %s\\nMessage: %s\\nFile: %s:%d\\nTrace:\\n%s\",\n      get_class($exception),\n      $exception->getMessage(),\n      $exception->getFile(),\n      $exception->getLine(),\n      $exception->getTraceAsString()\n    );\n\n    return self::error($message, $module);\n  }\n}\n"
  },
  {
    "path": "server/app/Common/Helper/OssHelper.php",
    "content": "<?php\n\nnamespace App\\Common\\Helper;\n\nuse App\\Model\\Options;\nuse AsyncAws\\S3\\S3Client;\nuse App\\Common\\Helper\\HttpHelper;\n\n/**\n * 开源版 OSS Helper\n *\n * 行为严格对齐旧版开源 AttachmentModel::uploadOss/uploadS3/deleteOss/deleteS3/getQiuniuEndpointByKey，\n * 唯一差异：\n * - 旧版通过 D(\"Options\")->get() 获取配置，这里改为 Options::get()；\n * - 旧版使用 new S3Client([...])，这里使用 AsyncAws\\S3\\S3Client 同样的参数写法。\n *\n * 所有配置仅从 options 表的 oss_setting（JSON）读取，不再使用任何环境变量。\n */\nclass OssHelper\n{\n    /**\n     * 基于 Options::get('oss_setting') 上传文件，返回真实 URL。\n     *\n     * @param array $uploadFile 单个 $_FILES 元素（name/type/tmp_name/size）\n     * @return string|false\n     */\n    public static function uploadByOptions(array $uploadFile)\n    {\n        $ossSettingJson = Options::get('oss_setting', '');\n        $ossSetting = $ossSettingJson ? json_decode($ossSettingJson, true) : null;\n\n        if (!$ossSetting || empty($ossSetting['oss_type'])) {\n            return false;\n        }\n\n        // s3_storage / aliyun 直接走 S3\n        if ($ossSetting['oss_type'] === 's3_storage' || $ossSetting['oss_type'] === 'aliyun') {\n            return self::uploadS3WithConfig($uploadFile, $ossSetting);\n        }\n\n        // 七牛：需先查询 S3 endpoint\n        if ($ossSetting['oss_type'] === 'qiniu') {\n            $endpoint = self::getQiuniuEndpointByKey($ossSetting['key'], $ossSetting['bucket']);\n            if (!$endpoint) {\n                return false;\n            }\n            $ossSetting['endpoint'] = $endpoint;\n            return self::uploadS3WithConfig($uploadFile, $ossSetting);\n        }\n\n        // 腾讯云：根据 region 拼 endpoint，并把 secretId/secretKey 映射为 key/secret\n        if ($ossSetting['oss_type'] === 'qcloud') {\n            if (empty($ossSetting['region']) || empty($ossSetting['secretId']) || empty($ossSetting['secretKey'])) {\n                return false;\n            }\n            $ossSetting['endpoint'] = \"https://cos.{$ossSetting['region']}.myqcloud.com\";\n            $ossSetting['key'] = $ossSetting['secretId'];\n            $ossSetting['secret'] = $ossSetting['secretKey'];\n            return self::uploadS3WithConfig($uploadFile, $ossSetting);\n        }\n\n        return false;\n    }\n\n    /**\n     * 基于 Options::get('oss_setting') 删除文件。\n     *\n     * @param string $fileUrl 完整的文件 URL\n     * @return bool\n     */\n    public static function deleteByOptions(string $fileUrl): bool\n    {\n        $ossSettingJson = Options::get('oss_setting', '');\n        $ossSetting = $ossSettingJson ? json_decode($ossSettingJson, true) : null;\n\n        if (!$ossSetting || empty($ossSetting['oss_type'])) {\n            return false;\n        }\n\n        if ($ossSetting['oss_type'] === 's3_storage' || $ossSetting['oss_type'] === 'aliyun') {\n            return self::deleteS3WithConfig($fileUrl, $ossSetting);\n        }\n\n        if ($ossSetting['oss_type'] === 'qiniu') {\n            $endpoint = self::getQiuniuEndpointByKey($ossSetting['key'], $ossSetting['bucket']);\n            if (!$endpoint) {\n                return false;\n            }\n            $ossSetting['endpoint'] = $endpoint;\n            return self::deleteS3WithConfig($fileUrl, $ossSetting);\n        }\n\n        if ($ossSetting['oss_type'] === 'qcloud') {\n            if (empty($ossSetting['region']) || empty($ossSetting['secretId']) || empty($ossSetting['secretKey'])) {\n                return false;\n            }\n            $ossSetting['endpoint'] = \"https://cos.{$ossSetting['region']}.myqcloud.com\";\n            $ossSetting['key'] = $ossSetting['secretId'];\n            $ossSetting['secret'] = $ossSetting['secretKey'];\n            return self::deleteS3WithConfig($fileUrl, $ossSetting);\n        }\n\n        return false;\n    }\n\n    /**\n     * 通过 S3 协议上传（内部使用），直接复刻旧 AttachmentModel::uploadS3。\n     *\n     * @param array $uploadFile\n     * @param array $ossSetting\n     * @return string|false\n     */\n    private static function uploadS3WithConfig(array $uploadFile, array $ossSetting)\n    {\n        if (empty($uploadFile['tmp_name']) || !is_file($uploadFile['tmp_name'])) {\n            return false;\n        }\n\n        // 扩展名\n        $ext = strrchr($uploadFile['name'], '.');\n\n        // 构造 OSS 对象路径\n        // 使用更长的随机串，降低命名碰撞概率\n        $rand = self::getRandStr(32);\n        if (!empty($ossSetting['subcat'])) {\n            $ossPath = rtrim($ossSetting['subcat'], '/') . '/showdoc_' . $rand . $ext;\n        } else {\n            $ossPath = 'showdoc_' . $rand . $ext;\n        }\n\n        // endpoint 确保带协议\n        if (!empty($ossSetting['endpoint']) && !strstr($ossSetting['endpoint'], '://')) {\n            $ossSetting['endpoint'] = 'https://' . $ossSetting['endpoint'];\n        }\n\n        if (empty($ossSetting['endpoint']) || empty($ossSetting['key']) || empty($ossSetting['secret']) || empty($ossSetting['bucket'])) {\n            return false;\n        }\n\n        // 使用 AsyncAws S3Client\n        $s3 = new S3Client([\n            'accessKeyId'     => $ossSetting['key'],\n            'accessKeySecret' => $ossSetting['secret'],\n            'endpoint'        => $ossSetting['endpoint'],\n            'sendChunkedBody' => false,\n        ]);\n\n        // 发送 PutObject 请求\n        $s3->putObject([\n            'Bucket'       => $ossSetting['bucket'],\n            'Key'          => $ossPath,\n            'Body'         => fopen($uploadFile['tmp_name'], 'rb'),\n            'CacheControl' => 'public, max-age=31536000, s-maxage=31536000, immutable',\n            'ContentType'  => $uploadFile['type'] ?? '',\n        ]);\n\n        // 构造最终访问 URL\n        if (!empty($ossSetting['domain'])) {\n            $protocol = !empty($ossSetting['protocol']) ? $ossSetting['protocol'] : 'https';\n            return $protocol . '://' . $ossSetting['domain'] . '/' . $ossPath;\n        }\n\n        $tmp = parse_url($ossSetting['endpoint']);\n        $host = $tmp['host'] ?? '';\n        if ($host) {\n            return 'https://' . $ossSetting['bucket'] . '.' . $host . '/' . $ossPath;\n        }\n\n        return false;\n    }\n\n    /**\n     * 通过 S3 协议删除（内部使用），复刻旧 AttachmentModel::deleteS3。\n     *\n     * @param string $fileUrl\n     * @param array $ossSetting\n     * @return bool\n     */\n    private static function deleteS3WithConfig(string $fileUrl, array $ossSetting): bool\n    {\n        $array = parse_url($fileUrl);\n        if (!$array || empty($array['path'])) {\n            return false;\n        }\n\n        $file = ltrim($array['path'], '/');\n\n        if (!empty($ossSetting['endpoint']) && !strstr($ossSetting['endpoint'], '://')) {\n            $ossSetting['endpoint'] = 'https://' . $ossSetting['endpoint'];\n        }\n\n        if (empty($ossSetting['endpoint']) || empty($ossSetting['key']) || empty($ossSetting['secret']) || empty($ossSetting['bucket'])) {\n            return false;\n        }\n\n        $s3 = new S3Client([\n            'accessKeyId'     => $ossSetting['key'],\n            'accessKeySecret' => $ossSetting['secret'],\n            'endpoint'        => $ossSetting['endpoint'],\n        ]);\n\n        $s3->deleteObject([\n            'Bucket' => $ossSetting['bucket'],\n            'Key'    => $file,\n        ]);\n\n        return true;\n    }\n\n    /**\n     * 由于历史原因，当初没有让用户填写七牛云的 region，需要自己调接口查询 endpoint。\n     *\n     * @param string $key\n     * @param string $bucket\n     * @return string|null\n     */\n    private static function getQiuniuEndpointByKey(string $key, string $bucket): ?string\n    {\n        $queryUrl = \"https://api.qiniu.com/v2/query?ak={$key}&bucket={$bucket}\";\n        $res = HttpHelper::post($queryUrl, []);\n        $array = $res ? json_decode($res, true) : null;\n\n        if ($array && isset($array['s3']['src']['main'][0]) && $array['s3']['src']['main'][0]) {\n            return 'https://' . $array['s3']['src']['main'][0];\n        }\n\n        return null;\n    }\n\n    /**\n     * 生成随机字符串（用于 OSS 对象名），等价于旧版 get_rand_str。\n     */\n    private static function getRandStr(int $len = 16): string\n    {\n        $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';\n        $max = strlen($chars) - 1;\n        $str = '';\n        for ($i = 0; $i < $len; $i++) {\n            $str .= $chars[random_int(0, $max)];\n        }\n        return $str;\n    }\n}\n"
  },
  {
    "path": "server/app/Common/Helper/Security.php",
    "content": "<?php\n\nnamespace App\\Common\\Helper;\n\nclass Security\n{\n    /**\n     * 安全处理 LIKE 查询关键字（防止 SQL 注入）\n     *\n     * @param string $keyword 关键字\n     * @param bool $strict 是否严格模式\n     * @return string 处理后的关键字\n     */\n    public static function safeLike(string $keyword, bool $strict = true): string\n    {\n        $s = (string) $keyword;\n\n        // 输入长度限制（防止过长的攻击载荷）\n        if (strlen($s) > 200) {\n            $s = substr($s, 0, 200);\n        }\n\n        // 优先使用 SQLite3 原生转义函数\n        if (class_exists('\\SQLite3')) {\n            $s = \\SQLite3::escapeString($s);\n        } else {\n            // 备用方案：手动转义\n            // 先转义反斜杠，避免后续再次转义造成歧义\n            $s = str_replace('\\\\', '\\\\\\\\', $s);\n            // 转义单引号和双引号（防止 SQL 注入）\n            $s = str_replace(\"'\", \"\\\\'\", $s);\n            $s = str_replace('\"', '\\\\\"', $s);\n            // 转义百分号和下划线（LIKE 查询特殊字符）\n            if ($strict) {\n                $s = str_replace('%', '\\\\%', $s);\n                $s = str_replace('_', '\\\\_', $s);\n            }\n        }\n\n        return $s;\n    }\n\n    /**\n     * 生成随机盐值\n     *\n     * @return string 盐值\n     */\n    public static function generateSalt(): string\n    {\n        return substr(md5(uniqid(rand(), true)), 0, 8);\n    }\n\n    /**\n     * 加密密码（兼容旧版 encry_password 函数）\n     *\n     * @param string $password 原始密码\n     * @param string $salt 盐值\n     * @return string 加密后的密码\n     */\n    public static function hashPassword(string $password, string $salt = ''): string\n    {\n        // 兼容旧版加密算法：md5(base64_encode(md5($password)) . '576hbgh6' . $salt)\n        return md5(base64_encode(md5($password)) . '576hbgh6' . $salt);\n    }\n\n    /**\n     * 过滤 HTML 内容（防止 XSS，兼容旧版 filter_html 函数）\n     *\n     * @param string $content HTML 内容\n     * @return string 过滤后的内容\n     */\n    public static function filterHtml(string $content): string\n    {\n        // 移除危险标签和属性，但保留安全的 HTML 标签\n        $allowedTags = '<p><br><strong><em><u><h1><h2><h3><h4><h5><h6><ul><ol><li><a><img><table><tr><td><th><thead><tbody>';\n        $content = strip_tags($content, $allowedTags);\n\n        // 移除危险属性（如 onclick, onerror 等）\n        $content = preg_replace('/\\s*on\\w+\\s*=\\s*[\"\\'][^\"\\']*[\"\\']/i', '', $content);\n        $content = preg_replace('/\\s*on\\w+\\s*=\\s*[^\\s>]*/i', '', $content);\n\n        // 保留换行为可见的 <br>\n        $content = nl2br($content);\n\n        return $content;\n    }\n\n    /**\n     * 验证密码强度（兼容旧版 validate_strong_password 函数）\n     * 要求：至少8位，包含大小写字母、数字和特殊字符\n     * \n     * @param string $password 待验证的密码\n     * @return array 返回数组，['valid' => bool, 'message' => string, 'errors' => array]\n     */\n    public static function validateStrongPassword(string $password): array\n    {\n        // 从 Options 表读取配置\n        $strongPasswordEnabled = \\App\\Model\\Options::get('strong_password_enabled', '0');\n\n        // 如果未启用高强度密码，直接返回通过\n        if (!$strongPasswordEnabled || $strongPasswordEnabled === '0' || $strongPasswordEnabled === false) {\n            return ['valid' => true, 'message' => '', 'errors' => []];\n        }\n\n        $errors = [];\n\n        // 检查密码长度\n        if (strlen($password) < 8) {\n            $errors[] = '密码长度至少需要8位';\n        }\n\n        // 检查是否包含小写字母\n        if (!preg_match('/[a-z]/', $password)) {\n            $errors[] = '密码必须包含至少一个小写字母';\n        }\n\n        // 检查是否包含大写字母\n        if (!preg_match('/[A-Z]/', $password)) {\n            $errors[] = '密码必须包含至少一个大写字母';\n        }\n\n        // 检查是否包含数字\n        if (!preg_match('/[0-9]/', $password)) {\n            $errors[] = '密码必须包含至少一个数字';\n        }\n\n        // 检查是否包含特殊字符\n        if (!preg_match('/[^a-zA-Z0-9]/', $password)) {\n            $errors[] = '密码必须包含至少一个特殊字符';\n        }\n\n        // 如果有错误，返回所有错误信息\n        if (count($errors) > 0) {\n            $message = implode('；', $errors);\n            return ['valid' => false, 'message' => $message, 'errors' => $errors];\n        }\n\n        return ['valid' => true, 'message' => '', 'errors' => []];\n    }\n}\n"
  },
  {
    "path": "server/app/Common/Helper/UrlHelper.php",
    "content": "<?php\n\nnamespace App\\Common\\Helper;\n\nuse App\\Model\\Options;\n\n/**\n * URL 生成 Helper（兼容旧 server_url 和 site_url 函数）。\n */\nclass UrlHelper\n{\n    /**\n     * 获得当前的域名\n     *\n     * @return string\n     */\n    public static function getDomain(): string\n    {\n        // 协议\n        $protocol = (isset($_SERVER['HTTPS']) && (strtolower($_SERVER['HTTPS']) !== 'off')) ? 'https://' : 'http://';\n\n        // 域名或 IP 地址\n        if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])) {\n            $host = $_SERVER['HTTP_X_FORWARDED_HOST'];\n        } elseif (isset($_SERVER['HTTP_HOST'])) {\n            $host = $_SERVER['HTTP_HOST'];\n        } else {\n            // 端口\n            $port = '';\n            if (isset($_SERVER['SERVER_PORT'])) {\n                $port = ':' . $_SERVER['SERVER_PORT'];\n                if ((':80' === $port && 'http://' === $protocol) || (':443' === $port && 'https://' === $protocol)) {\n                    $port = '';\n                }\n            }\n\n            if (isset($_SERVER['SERVER_NAME'])) {\n                $host = $_SERVER['SERVER_NAME'] . $port;\n            } elseif (isset($_SERVER['SERVER_ADDR'])) {\n                $host = $_SERVER['SERVER_ADDR'] . $port;\n            } else {\n                $host = 'localhost';\n            }\n        }\n\n        return $protocol . $host;\n    }\n\n    /**\n     * 获得网站的 URL 地址\n     *\n     * @return string\n     */\n    public static function siteUrl(): string\n    {\n        $siteUrl = Options::get('site_url');\n        if (!$siteUrl) {\n            $siteUrl = self::getDomain() . substr($_SERVER['PHP_SELF'] ?? '/', 0, strrpos($_SERVER['PHP_SELF'] ?? '/', '/'));\n            $siteUrl = str_replace('/server', '', $siteUrl);\n        }\n        // 确保返回的 URL 末尾没有斜杠，避免拼接时出现双斜杠\n        return rtrim((string) $siteUrl, '/');\n    }\n\n    /**\n     * 拼接后台 server 链接（开源版：使用 ?s=/api/... 兼容旧入口）\n     *\n     * @param string $path 路径\n     * @param array $params 参数\n     * @return string\n     */\n    public static function serverUrl(string $path = '', array $params = []): string\n    {\n        // 移除路径开头的斜杠，避免出现 //api\n        $path = ltrim($path, '/');\n        $base = self::siteUrl() . '/server/';\n\n        // 开源版没有 nginx 重写规则，统一走 ?s=/api/... 入口\n        // 这里保持 s 参数中的斜杠不被 urlencode（兼容老格式：?s=/api/attachment/visitFile）\n        $queryStringParts = [];\n\n        if ($path !== '') {\n            $queryStringParts[] = 's=/' . $path;\n        }\n\n        if (!empty($params)) {\n            // 其他参数正常使用 http_build_query 编码\n            $queryStringParts[] = http_build_query($params);\n        }\n\n        if (empty($queryStringParts)) {\n            return rtrim($base, '/');\n        }\n\n        return $base . '?' . implode('&', $queryStringParts);\n    }\n}\n"
  },
  {
    "path": "server/app/Common/Vendor/Parsedown.php",
    "content": "<?php\n\n#\n#\n# Parsedown\n# http://parsedown.org\n#\n# (c) Emanuil Rusev\n# http://erusev.com\n#\n# For the full license information, view the LICENSE file that was distributed\n# with this source code.\n#\n#\n\nclass Parsedown\n{\n    # ~\n\n    const version = '1.6.0';\n\n    # ~\n\n    function text($text)\n    {\n        # make sure no definitions are set\n        $this->DefinitionData = array();\n\n        # standardize line breaks\n        $text = str_replace(array(\"\\r\\n\", \"\\r\"), \"\\n\", $text);\n\n        # remove surrounding line breaks\n        $text = trim($text, \"\\n\");\n\n        # split text into lines\n        $lines = explode(\"\\n\", $text);\n\n        # iterate through lines to identify blocks\n        $markup = $this->lines($lines);\n\n        # trim line breaks\n        $markup = trim($markup, \"\\n\");\n\n        return $markup;\n    }\n\n    #\n    # Setters\n    #\n\n    function setBreaksEnabled($breaksEnabled)\n    {\n        $this->breaksEnabled = $breaksEnabled;\n\n        return $this;\n    }\n\n    protected $breaksEnabled;\n\n    function setMarkupEscaped($markupEscaped)\n    {\n        $this->markupEscaped = $markupEscaped;\n\n        return $this;\n    }\n\n    protected $markupEscaped;\n\n    function setUrlsLinked($urlsLinked)\n    {\n        $this->urlsLinked = $urlsLinked;\n\n        return $this;\n    }\n\n    protected $urlsLinked = true;\n\n    #\n    # Lines\n    #\n\n    protected $BlockTypes = array(\n        '#' => array('Header'),\n        '*' => array('Rule', 'List'),\n        '+' => array('List'),\n        '-' => array('SetextHeader', 'Table', 'Rule', 'List'),\n        '0' => array('List'),\n        '1' => array('List'),\n        '2' => array('List'),\n        '3' => array('List'),\n        '4' => array('List'),\n        '5' => array('List'),\n        '6' => array('List'),\n        '7' => array('List'),\n        '8' => array('List'),\n        '9' => array('List'),\n        ':' => array('Table'),\n        '<' => array('Comment', 'Markup'),\n        '=' => array('SetextHeader'),\n        '>' => array('Quote'),\n        '[' => array('Reference'),\n        '_' => array('Rule'),\n        '`' => array('FencedCode'),\n        '|' => array('Table'),\n        '~' => array('FencedCode'),\n    );\n\n    # ~\n\n    protected $unmarkedBlockTypes = array(\n        'Code',\n    );\n\n    #\n    # Blocks\n    #\n\n    private function lines(array $lines)\n    {\n        $CurrentBlock = null;\n\n        foreach ($lines as $line) {\n            if (chop($line) === '') {\n                if (isset($CurrentBlock)) {\n                    $CurrentBlock['interrupted'] = true;\n                }\n\n                continue;\n            }\n\n            if (strpos($line, \"\\t\") !== false) {\n                $parts = explode(\"\\t\", $line);\n\n                $line = $parts[0];\n\n                unset($parts[0]);\n\n                foreach ($parts as $part) {\n                    $shortage = 4 - mb_strlen($line, 'utf-8') % 4;\n\n                    $line .= str_repeat(' ', $shortage);\n                    $line .= $part;\n                }\n            }\n\n            $indent = 0;\n\n            while (isset($line[$indent]) and $line[$indent] === ' ') {\n                $indent++;\n            }\n\n            $text = $indent > 0 ? substr($line, $indent) : $line;\n\n            # ~\n\n            $Line = array('body' => $line, 'indent' => $indent, 'text' => $text);\n\n            # ~\n\n            if (isset($CurrentBlock['continuable'])) {\n                $Block = $this->{'block' . $CurrentBlock['type'] . 'Continue'}($Line, $CurrentBlock);\n\n                if (isset($Block)) {\n                    $CurrentBlock = $Block;\n\n                    continue;\n                } else {\n                    if (method_exists($this, 'block' . $CurrentBlock['type'] . 'Complete')) {\n                        $CurrentBlock = $this->{'block' . $CurrentBlock['type'] . 'Complete'}($CurrentBlock);\n                    }\n                }\n            }\n\n            # ~\n\n            $marker = $text[0];\n\n            # ~\n\n            $blockTypes = $this->unmarkedBlockTypes;\n\n            if (isset($this->BlockTypes[$marker])) {\n                foreach ($this->BlockTypes[$marker] as $blockType) {\n                    $blockTypes[] = $blockType;\n                }\n            }\n\n            #\n            # ~\n\n            foreach ($blockTypes as $blockType) {\n                $Block = $this->{'block' . $blockType}($Line, $CurrentBlock);\n\n                if (isset($Block)) {\n                    $Block['type'] = $blockType;\n\n                    if (! isset($Block['identified'])) {\n                        $Blocks[] = $CurrentBlock;\n\n                        $Block['identified'] = true;\n                    }\n\n                    if (method_exists($this, 'block' . $blockType . 'Continue')) {\n                        $Block['continuable'] = true;\n                    }\n\n                    $CurrentBlock = $Block;\n\n                    continue 2;\n                }\n            }\n\n            # ~\n\n            if (isset($CurrentBlock) and ! isset($CurrentBlock['type']) and ! isset($CurrentBlock['interrupted'])) {\n                $CurrentBlock['element']['text'] .= \"\\n\" . $text;\n            } else {\n                $Blocks[] = $CurrentBlock;\n\n                $CurrentBlock = $this->paragraph($Line);\n\n                $CurrentBlock['identified'] = true;\n            }\n        }\n\n        # ~\n\n        if (isset($CurrentBlock['continuable']) and method_exists($this, 'block' . $CurrentBlock['type'] . 'Complete')) {\n            $CurrentBlock = $this->{'block' . $CurrentBlock['type'] . 'Complete'}($CurrentBlock);\n        }\n\n        # ~\n\n        $Blocks[] = $CurrentBlock;\n\n        unset($Blocks[0]);\n\n        # ~\n\n        $markup = '';\n\n        foreach ($Blocks as $Block) {\n            if (isset($Block['hidden'])) {\n                continue;\n            }\n\n            $markup .= \"\\n\";\n            $markup .= isset($Block['markup']) ? $Block['markup'] : $this->element($Block['element']);\n        }\n\n        $markup .= \"\\n\";\n\n        # ~\n\n        return $markup;\n    }\n\n    #\n    # Code\n    #\n\n    protected function blockCode($Line, $Block = null)\n    {\n        if (isset($Block) and ! isset($Block['type']) and ! isset($Block['interrupted'])) {\n            return;\n        }\n\n        if ($Line['indent'] >= 4) {\n            $text = substr($Line['body'], 4);\n\n            $Block = array(\n                'element' => array(\n                    'name' => 'pre',\n                    'handler' => 'element',\n                    'text' => array(\n                        'name' => 'code',\n                        'text' => $text,\n                    ),\n                ),\n            );\n\n            return $Block;\n        }\n    }\n\n    protected function blockCodeContinue($Line, $Block)\n    {\n        if ($Line['indent'] >= 4) {\n            if (isset($Block['interrupted'])) {\n                $Block['element']['text']['text'] .= \"\\n\";\n\n                unset($Block['interrupted']);\n            }\n\n            $Block['element']['text']['text'] .= \"\\n\";\n\n            $text = substr($Line['body'], 4);\n\n            $Block['element']['text']['text'] .= $text;\n\n            return $Block;\n        }\n    }\n\n    protected function blockCodeComplete($Block)\n    {\n        $text = $Block['element']['text']['text'];\n\n        $text = htmlspecialchars($text, ENT_NOQUOTES, 'UTF-8');\n\n        $Block['element']['text']['text'] = $text;\n\n        return $Block;\n    }\n\n    #\n    # Comment\n    #\n\n    protected function blockComment($Line)\n    {\n        if ($this->markupEscaped) {\n            return;\n        }\n\n        if (isset($Line['text'][3]) and $Line['text'][3] === '-' and $Line['text'][2] === '-' and $Line['text'][1] === '!') {\n            $Block = array(\n                'markup' => $Line['body'],\n            );\n\n            if (preg_match('/-->$/', $Line['text'])) {\n                $Block['closed'] = true;\n            }\n\n            return $Block;\n        }\n    }\n\n    protected function blockCommentContinue($Line, array $Block)\n    {\n        if (isset($Block['closed'])) {\n            return;\n        }\n\n        $Block['markup'] .= \"\\n\" . $Line['body'];\n\n        if (preg_match('/-->$/', $Line['text'])) {\n            $Block['closed'] = true;\n        }\n\n        return $Block;\n    }\n\n    #\n    # Fenced Code\n    #\n\n    protected function blockFencedCode($Line)\n    {\n        if (preg_match('/^[' . $Line['text'][0] . ']{3,}[ ]*([\\w-]+)?[ ]*$/', $Line['text'], $matches)) {\n            $Element = array(\n                'name' => 'code',\n                'text' => '',\n            );\n\n            if (isset($matches[1])) {\n                $class = 'language-' . $matches[1];\n\n                $Element['attributes'] = array(\n                    'class' => $class,\n                );\n            }\n\n            $Block = array(\n                'char' => $Line['text'][0],\n                'element' => array(\n                    'name' => 'pre',\n                    'handler' => 'element',\n                    'text' => $Element,\n                ),\n            );\n\n            return $Block;\n        }\n    }\n\n    protected function blockFencedCodeContinue($Line, $Block)\n    {\n        if (isset($Block['complete'])) {\n            return;\n        }\n\n        if (isset($Block['interrupted'])) {\n            $Block['element']['text']['text'] .= \"\\n\";\n\n            unset($Block['interrupted']);\n        }\n\n        if (preg_match('/^' . $Block['char'] . '{3,}[ ]*$/', $Line['text'])) {\n            $Block['element']['text']['text'] = substr($Block['element']['text']['text'], 1);\n\n            $Block['complete'] = true;\n\n            return $Block;\n        }\n\n        $Block['element']['text']['text'] .= \"\\n\" . $Line['body'];;\n\n        return $Block;\n    }\n\n    protected function blockFencedCodeComplete($Block)\n    {\n        $text = $Block['element']['text']['text'];\n\n        $text = htmlspecialchars($text, ENT_NOQUOTES, 'UTF-8');\n\n        $Block['element']['text']['text'] = $text;\n\n        return $Block;\n    }\n\n    #\n    # Header\n    #\n\n    protected function blockHeader($Line)\n    {\n        if (isset($Line['text'][1])) {\n            $level = 1;\n\n            while (isset($Line['text'][$level]) and $Line['text'][$level] === '#') {\n                $level++;\n            }\n\n            if ($level > 6) {\n                return;\n            }\n\n            $text = trim($Line['text'], '# ');\n\n            $Block = array(\n                'element' => array(\n                    'name' => 'h' . min(6, $level),\n                    'text' => $text,\n                    'handler' => 'line',\n                ),\n            );\n\n            return $Block;\n        }\n    }\n\n    #\n    # List\n    #\n\n    protected function blockList($Line)\n    {\n        list($name, $pattern) = $Line['text'][0] <= '-' ? array('ul', '[*+-]') : array('ol', '[0-9]+[.]');\n\n        if (preg_match('/^(' . $pattern . '[ ]+)(.*)/', $Line['text'], $matches)) {\n            $Block = array(\n                'indent' => $Line['indent'],\n                'pattern' => $pattern,\n                'element' => array(\n                    'name' => $name,\n                    'handler' => 'elements',\n                ),\n            );\n\n            $Block['li'] = array(\n                'name' => 'li',\n                'handler' => 'li',\n                'text' => array(\n                    $matches[2],\n                ),\n            );\n\n            $Block['element']['text'][] = &$Block['li'];\n\n            return $Block;\n        }\n    }\n\n    protected function blockListContinue($Line, array $Block)\n    {\n        if ($Block['indent'] === $Line['indent'] and preg_match('/^' . $Block['pattern'] . '(?:[ ]+(.*)|$)/', $Line['text'], $matches)) {\n            if (isset($Block['interrupted'])) {\n                $Block['li']['text'][] = '';\n\n                unset($Block['interrupted']);\n            }\n\n            unset($Block['li']);\n\n            $text = isset($matches[1]) ? $matches[1] : '';\n\n            $Block['li'] = array(\n                'name' => 'li',\n                'handler' => 'li',\n                'text' => array(\n                    $text,\n                ),\n            );\n\n            $Block['element']['text'][] = &$Block['li'];\n\n            return $Block;\n        }\n\n        if ($Line['text'][0] === '[' and $this->blockReference($Line)) {\n            return $Block;\n        }\n\n        if (! isset($Block['interrupted'])) {\n            $text = preg_replace('/^[ ]{0,4}/', '', $Line['body']);\n\n            $Block['li']['text'][] = $text;\n\n            return $Block;\n        }\n\n        if ($Line['indent'] > 0) {\n            $Block['li']['text'][] = '';\n\n            $text = preg_replace('/^[ ]{0,4}/', '', $Line['body']);\n\n            $Block['li']['text'][] = $text;\n\n            unset($Block['interrupted']);\n\n            return $Block;\n        }\n    }\n\n    #\n    # Quote\n    #\n\n    protected function blockQuote($Line)\n    {\n        if (preg_match('/^>[ ]?(.*)/', $Line['text'], $matches)) {\n            $Block = array(\n                'element' => array(\n                    'name' => 'blockquote',\n                    'handler' => 'lines',\n                    'text' => (array) $matches[1],\n                ),\n            );\n\n            return $Block;\n        }\n    }\n\n    protected function blockQuoteContinue($Line, array $Block)\n    {\n        if ($Line['text'][0] === '>' and preg_match('/^>[ ]?(.*)/', $Line['text'], $matches)) {\n            if (isset($Block['interrupted'])) {\n                $Block['element']['text'][] = '';\n\n                unset($Block['interrupted']);\n            }\n\n            $Block['element']['text'][] = $matches[1];\n\n            return $Block;\n        }\n\n        if (! isset($Block['interrupted'])) {\n            $Block['element']['text'][] = $Line['text'];\n\n            return $Block;\n        }\n    }\n\n    #\n    # Rule\n    #\n\n    protected function blockRule($Line)\n    {\n        if (preg_match('/^([' . $Line['text'][0] . '])([ ]*\\1){2,}[ ]*$/', $Line['text'])) {\n            $Block = array(\n                'element' => array(\n                    'name' => 'hr'\n                ),\n            );\n\n            return $Block;\n        }\n    }\n\n    #\n    # Setext\n    #\n\n    protected function blockSetextHeader($Line, array $Block = null)\n    {\n        if (! isset($Block) or isset($Block['type']) or isset($Block['interrupted'])) {\n            return;\n        }\n\n        if (chop($Line['text'], $Line['text'][0]) === '') {\n            $Block['element']['name'] = $Line['text'][0] === '=' ? 'h1' : 'h2';\n\n            return $Block;\n        }\n    }\n\n    #\n    # Markup\n    #\n\n    protected function blockMarkup($Line)\n    {\n        if ($this->markupEscaped) {\n            return;\n        }\n\n        if (preg_match('/^<(\\w*)(?:[ ]*' . $this->regexHtmlAttribute . ')*[ ]*(\\/)?>/', $Line['text'], $matches)) {\n            $element = strtolower($matches[1]);\n\n            if (in_array($element, $this->textLevelElements)) {\n                return;\n            }\n\n            $Block = array(\n                'name' => $matches[1],\n                'depth' => 0,\n                'markup' => $Line['text'],\n            );\n\n            $length = strlen($matches[0]);\n\n            $remainder = substr($Line['text'], $length);\n\n            if (trim($remainder) === '') {\n                if (isset($matches[2]) or in_array($matches[1], $this->voidElements)) {\n                    $Block['closed'] = true;\n\n                    $Block['void'] = true;\n                }\n            } else {\n                if (isset($matches[2]) or in_array($matches[1], $this->voidElements)) {\n                    return;\n                }\n\n                if (preg_match('/<\\/' . $matches[1] . '>[ ]*$/i', $remainder)) {\n                    $Block['closed'] = true;\n                }\n            }\n\n            return $Block;\n        }\n    }\n\n    protected function blockMarkupContinue($Line, array $Block)\n    {\n        if (isset($Block['closed'])) {\n            return;\n        }\n\n        if (preg_match('/^<' . $Block['name'] . '(?:[ ]*' . $this->regexHtmlAttribute . ')*[ ]*>/i', $Line['text'])) # open\n        {\n            $Block['depth']++;\n        }\n\n        if (preg_match('/(.*?)<\\/' . $Block['name'] . '>[ ]*$/i', $Line['text'], $matches)) # close\n        {\n            if ($Block['depth'] > 0) {\n                $Block['depth']--;\n            } else {\n                $Block['closed'] = true;\n            }\n        }\n\n        if (isset($Block['interrupted'])) {\n            $Block['markup'] .= \"\\n\";\n\n            unset($Block['interrupted']);\n        }\n\n        $Block['markup'] .= \"\\n\" . $Line['body'];\n\n        return $Block;\n    }\n\n    #\n    # Reference\n    #\n\n    protected function blockReference($Line)\n    {\n        if (preg_match('/^\\[(.+?)\\]:[ ]*<?(\\S+?)>?(?:[ ]+[\"\\'(](.+)[\"\\')])?[ ]*$/', $Line['text'], $matches)) {\n            $id = strtolower($matches[1]);\n\n            $Data = array(\n                'url' => $matches[2],\n                'title' => null,\n            );\n\n            if (isset($matches[3])) {\n                $Data['title'] = $matches[3];\n            }\n\n            $this->DefinitionData['Reference'][$id] = $Data;\n\n            $Block = array(\n                'hidden' => true,\n            );\n\n            return $Block;\n        }\n    }\n\n    #\n    # Table\n    #\n\n    protected function blockTable($Line, array $Block = null)\n    {\n        if (! isset($Block) or isset($Block['type']) or isset($Block['interrupted'])) {\n            return;\n        }\n\n        if (strpos($Block['element']['text'], '|') !== false and chop($Line['text'], ' -:|') === '') {\n            $alignments = array();\n\n            $divider = $Line['text'];\n\n            $divider = trim($divider);\n            $divider = trim($divider, '|');\n\n            $dividerCells = explode('|', $divider);\n\n            foreach ($dividerCells as $dividerCell) {\n                $dividerCell = trim($dividerCell);\n\n                if ($dividerCell === '') {\n                    continue;\n                }\n\n                $alignment = null;\n\n                if ($dividerCell[0] === ':') {\n                    $alignment = 'left';\n                }\n\n                if (substr($dividerCell, -1) === ':') {\n                    $alignment = $alignment === 'left' ? 'center' : 'right';\n                }\n\n                $alignments[] = $alignment;\n            }\n\n            # ~\n\n            $HeaderElements = array();\n\n            $header = $Block['element']['text'];\n\n            $header = trim($header);\n            $header = trim($header, '|');\n\n            $headerCells = explode('|', $header);\n\n            foreach ($headerCells as $index => $headerCell) {\n                $headerCell = trim($headerCell);\n\n                $HeaderElement = array(\n                    'name' => 'th',\n                    'text' => $headerCell,\n                    'handler' => 'line',\n                );\n\n                if (isset($alignments[$index])) {\n                    $alignment = $alignments[$index];\n\n                    $HeaderElement['attributes'] = array(\n                        'style' => 'text-align: ' . $alignment . ';',\n                    );\n                }\n\n                $HeaderElements[] = $HeaderElement;\n            }\n\n            # ~\n\n            $Block = array(\n                'alignments' => $alignments,\n                'identified' => true,\n                'element' => array(\n                    'name' => 'table',\n                    'handler' => 'elements',\n                ),\n            );\n\n            $Block['element']['text'][] = array(\n                'name' => 'thead',\n                'handler' => 'elements',\n            );\n\n            $Block['element']['text'][] = array(\n                'name' => 'tbody',\n                'handler' => 'elements',\n                'text' => array(),\n            );\n\n            $Block['element']['text'][0]['text'][] = array(\n                'name' => 'tr',\n                'handler' => 'elements',\n                'text' => $HeaderElements,\n            );\n\n            return $Block;\n        }\n    }\n\n    protected function blockTableContinue($Line, array $Block)\n    {\n        if (isset($Block['interrupted'])) {\n            return;\n        }\n\n        if ($Line['text'][0] === '|' or strpos($Line['text'], '|')) {\n            $Elements = array();\n\n            $row = $Line['text'];\n\n            $row = trim($row);\n            $row = trim($row, '|');\n\n            preg_match_all('/(?:(\\\\\\\\[|])|[^|`]|`[^`]+`|`)+/', $row, $matches);\n\n            foreach ($matches[0] as $index => $cell) {\n                $cell = trim($cell);\n\n                $Element = array(\n                    'name' => 'td',\n                    'handler' => 'line',\n                    'text' => $cell,\n                );\n\n                if (isset($Block['alignments'][$index])) {\n                    $Element['attributes'] = array(\n                        'style' => 'text-align: ' . $Block['alignments'][$index] . ';',\n                    );\n                }\n\n                $Elements[] = $Element;\n            }\n\n            $Element = array(\n                'name' => 'tr',\n                'handler' => 'elements',\n                'text' => $Elements,\n            );\n\n            $Block['element']['text'][1]['text'][] = $Element;\n\n            return $Block;\n        }\n    }\n\n    #\n    # ~\n    #\n\n    protected function paragraph($Line)\n    {\n        $Block = array(\n            'element' => array(\n                'name' => 'p',\n                'text' => $Line['text'],\n                'handler' => 'line',\n            ),\n        );\n\n        return $Block;\n    }\n\n    #\n    # Inline Elements\n    #\n\n    protected $InlineTypes = array(\n        '\"' => array('SpecialCharacter'),\n        '!' => array('Image'),\n        '&' => array('SpecialCharacter'),\n        '*' => array('Emphasis'),\n        ':' => array('Url'),\n        '<' => array('UrlTag', 'EmailTag', 'Markup', 'SpecialCharacter'),\n        '>' => array('SpecialCharacter'),\n        '[' => array('Link'),\n        '_' => array('Emphasis'),\n        '`' => array('Code'),\n        '~' => array('Strikethrough'),\n        '\\\\' => array('EscapeSequence'),\n    );\n\n    # ~\n\n    protected $inlineMarkerList = '!\"*_&[:<>`~\\\\';\n\n    #\n    # ~\n    #\n\n    public function line($text)\n    {\n        $markup = '';\n\n        # $excerpt is based on the first occurrence of a marker\n\n        while ($excerpt = strpbrk($text, $this->inlineMarkerList)) {\n            $marker = $excerpt[0];\n\n            $markerPosition = strpos($text, $marker);\n\n            $Excerpt = array('text' => $excerpt, 'context' => $text);\n\n            foreach ($this->InlineTypes[$marker] as $inlineType) {\n                $Inline = $this->{'inline' . $inlineType}($Excerpt);\n\n                if (! isset($Inline)) {\n                    continue;\n                }\n\n                # makes sure that the inline belongs to \"our\" marker\n\n                if (isset($Inline['position']) and $Inline['position'] > $markerPosition) {\n                    continue;\n                }\n\n                # sets a default inline position\n\n                if (! isset($Inline['position'])) {\n                    $Inline['position'] = $markerPosition;\n                }\n\n                # the text that comes before the inline\n                $unmarkedText = substr($text, 0, $Inline['position']);\n\n                # compile the unmarked text\n                $markup .= $this->unmarkedText($unmarkedText);\n\n                # compile the inline\n                $markup .= isset($Inline['markup']) ? $Inline['markup'] : $this->element($Inline['element']);\n\n                # remove the examined text\n                $text = substr($text, $Inline['position'] + $Inline['extent']);\n\n                continue 2;\n            }\n\n            # the marker does not belong to an inline\n\n            $unmarkedText = substr($text, 0, $markerPosition + 1);\n\n            $markup .= $this->unmarkedText($unmarkedText);\n\n            $text = substr($text, $markerPosition + 1);\n        }\n\n        $markup .= $this->unmarkedText($text);\n\n        return $markup;\n    }\n\n    #\n    # ~\n    #\n\n    protected function inlineCode($Excerpt)\n    {\n        $marker = $Excerpt['text'][0];\n\n        if (preg_match('/^(' . $marker . '+)[ ]*(.+?)[ ]*(?<!' . $marker . ')\\1(?!' . $marker . ')/s', $Excerpt['text'], $matches)) {\n            $text = $matches[2];\n            $text = htmlspecialchars($text, ENT_NOQUOTES, 'UTF-8');\n            $text = preg_replace(\"/[ ]*\\n/\", ' ', $text);\n\n            return array(\n                'extent' => strlen($matches[0]),\n                'element' => array(\n                    'name' => 'code',\n                    'text' => $text,\n                ),\n            );\n        }\n    }\n\n    protected function inlineEmailTag($Excerpt)\n    {\n        if (strpos($Excerpt['text'], '>') !== false and preg_match('/^<((mailto:)?\\S+?@\\S+?)>/i', $Excerpt['text'], $matches)) {\n            $url = $matches[1];\n\n            if (! isset($matches[2])) {\n                $url = 'mailto:' . $url;\n            }\n\n            return array(\n                'extent' => strlen($matches[0]),\n                'element' => array(\n                    'name' => 'a',\n                    'text' => $matches[1],\n                    'attributes' => array(\n                        'href' => $url,\n                    ),\n                ),\n            );\n        }\n    }\n\n    protected function inlineEmphasis($Excerpt)\n    {\n        if (! isset($Excerpt['text'][1])) {\n            return;\n        }\n\n        $marker = $Excerpt['text'][0];\n\n        if ($Excerpt['text'][1] === $marker and preg_match($this->StrongRegex[$marker], $Excerpt['text'], $matches)) {\n            $emphasis = 'strong';\n        } elseif (preg_match($this->EmRegex[$marker], $Excerpt['text'], $matches)) {\n            $emphasis = 'em';\n        } else {\n            return;\n        }\n\n        return array(\n            'extent' => strlen($matches[0]),\n            'element' => array(\n                'name' => $emphasis,\n                'handler' => 'line',\n                'text' => $matches[1],\n            ),\n        );\n    }\n\n    protected function inlineEscapeSequence($Excerpt)\n    {\n        if (isset($Excerpt['text'][1]) and in_array($Excerpt['text'][1], $this->specialCharacters)) {\n            return array(\n                'markup' => $Excerpt['text'][1],\n                'extent' => 2,\n            );\n        }\n    }\n\n    protected function inlineImage($Excerpt)\n    {\n        if (! isset($Excerpt['text'][1]) or $Excerpt['text'][1] !== '[') {\n            return;\n        }\n\n        $Excerpt['text'] = substr($Excerpt['text'], 1);\n\n        $Link = $this->inlineLink($Excerpt);\n\n        if ($Link === null) {\n            return;\n        }\n\n        $Inline = array(\n            'extent' => $Link['extent'] + 1,\n            'element' => array(\n                'name' => 'img',\n                'attributes' => array(\n                    'src' => $Link['element']['attributes']['href'],\n                    'alt' => $Link['element']['text'],\n                ),\n            ),\n        );\n\n        $Inline['element']['attributes'] += $Link['element']['attributes'];\n\n        unset($Inline['element']['attributes']['href']);\n\n        return $Inline;\n    }\n\n    protected function inlineLink($Excerpt)\n    {\n        $Element = array(\n            'name' => 'a',\n            'handler' => 'line',\n            'text' => null,\n            'attributes' => array(\n                'href' => null,\n                'title' => null,\n            ),\n        );\n\n        $extent = 0;\n\n        $remainder = $Excerpt['text'];\n\n        if (preg_match('/\\[((?:[^][]|(?R))*)\\]/', $remainder, $matches)) {\n            $Element['text'] = $matches[1];\n\n            $extent += strlen($matches[0]);\n\n            $remainder = substr($remainder, $extent);\n        } else {\n            return;\n        }\n\n        if (preg_match('/^[(]((?:[^ ()]|[(][^ )]+[)])+)(?:[ ]+(\"[^\"]*\"|\\'[^\\']*\\'))?[)]/', $remainder, $matches)) {\n            $Element['attributes']['href'] = $matches[1];\n\n            if (isset($matches[2])) {\n                $Element['attributes']['title'] = substr($matches[2], 1, -1);\n            }\n\n            $extent += strlen($matches[0]);\n        } else {\n            if (preg_match('/^\\s*\\[(.*?)\\]/', $remainder, $matches)) {\n                $definition = strlen($matches[1]) ? $matches[1] : $Element['text'];\n                $definition = strtolower($definition);\n\n                $extent += strlen($matches[0]);\n            } else {\n                $definition = strtolower($Element['text']);\n            }\n\n            if (! isset($this->DefinitionData['Reference'][$definition])) {\n                return;\n            }\n\n            $Definition = $this->DefinitionData['Reference'][$definition];\n\n            $Element['attributes']['href'] = $Definition['url'];\n            $Element['attributes']['title'] = $Definition['title'];\n        }\n\n        $Element['attributes']['href'] = str_replace(array('&', '<'), array('&amp;', '&lt;'), $Element['attributes']['href']);\n\n        return array(\n            'extent' => $extent,\n            'element' => $Element,\n        );\n    }\n\n    protected function inlineMarkup($Excerpt)\n    {\n        if ($this->markupEscaped or strpos($Excerpt['text'], '>') === false) {\n            return;\n        }\n\n        if ($Excerpt['text'][1] === '/' and preg_match('/^<\\/\\w*[ ]*>/s', $Excerpt['text'], $matches)) {\n            return array(\n                'markup' => $matches[0],\n                'extent' => strlen($matches[0]),\n            );\n        }\n\n        if ($Excerpt['text'][1] === '!' and preg_match('/^<!---?[^>-](?:-?[^-])*-->/s', $Excerpt['text'], $matches)) {\n            return array(\n                'markup' => $matches[0],\n                'extent' => strlen($matches[0]),\n            );\n        }\n\n        if ($Excerpt['text'][1] !== ' ' and preg_match('/^<\\w*(?:[ ]*' . $this->regexHtmlAttribute . ')*[ ]*\\/?>/s', $Excerpt['text'], $matches)) {\n            return array(\n                'markup' => $matches[0],\n                'extent' => strlen($matches[0]),\n            );\n        }\n    }\n\n    protected function inlineSpecialCharacter($Excerpt)\n    {\n        if ($Excerpt['text'][0] === '&' and ! preg_match('/^&#?\\w+;/', $Excerpt['text'])) {\n            return array(\n                'markup' => '&amp;',\n                'extent' => 1,\n            );\n        }\n\n        $SpecialCharacter = array('>' => 'gt', '<' => 'lt', '\"' => 'quot');\n\n        if (isset($SpecialCharacter[$Excerpt['text'][0]])) {\n            return array(\n                'markup' => '&' . $SpecialCharacter[$Excerpt['text'][0]] . ';',\n                'extent' => 1,\n            );\n        }\n    }\n\n    protected function inlineStrikethrough($Excerpt)\n    {\n        if (! isset($Excerpt['text'][1])) {\n            return;\n        }\n\n        if ($Excerpt['text'][1] === '~' and preg_match('/^~~(?=\\S)(.+?)(?<=\\S)~~/', $Excerpt['text'], $matches)) {\n            return array(\n                'extent' => strlen($matches[0]),\n                'element' => array(\n                    'name' => 'del',\n                    'text' => $matches[1],\n                    'handler' => 'line',\n                ),\n            );\n        }\n    }\n\n    protected function inlineUrl($Excerpt)\n    {\n        if ($this->urlsLinked !== true or ! isset($Excerpt['text'][2]) or $Excerpt['text'][2] !== '/') {\n            return;\n        }\n\n        if (preg_match('/\\bhttps?:[\\/]{2}[^\\s<]+\\b\\/*/ui', $Excerpt['context'], $matches, PREG_OFFSET_CAPTURE)) {\n            $Inline = array(\n                'extent' => strlen($matches[0][0]),\n                'position' => $matches[0][1],\n                'element' => array(\n                    'name' => 'a',\n                    'text' => $matches[0][0],\n                    'attributes' => array(\n                        'href' => $matches[0][0],\n                    ),\n                ),\n            );\n\n            return $Inline;\n        }\n    }\n\n    protected function inlineUrlTag($Excerpt)\n    {\n        if (strpos($Excerpt['text'], '>') !== false and preg_match('/^<(\\w+:\\/{2}[^ >]+)>/i', $Excerpt['text'], $matches)) {\n            $url = str_replace(array('&', '<'), array('&amp;', '&lt;'), $matches[1]);\n\n            return array(\n                'extent' => strlen($matches[0]),\n                'element' => array(\n                    'name' => 'a',\n                    'text' => $url,\n                    'attributes' => array(\n                        'href' => $url,\n                    ),\n                ),\n            );\n        }\n    }\n\n    # ~\n\n    protected function unmarkedText($text)\n    {\n        if ($this->breaksEnabled) {\n            $text = preg_replace('/[ ]*\\n/', \"<br />\\n\", $text);\n        } else {\n            $text = preg_replace('/(?:[ ][ ]+|[ ]*\\\\\\\\)\\n/', \"<br />\\n\", $text);\n            $text = str_replace(\" \\n\", \"\\n\", $text);\n        }\n\n        return $text;\n    }\n\n    #\n    # Handlers\n    #\n\n    protected function element(array $Element)\n    {\n        $markup = '<' . $Element['name'];\n\n        if (isset($Element['attributes'])) {\n            foreach ($Element['attributes'] as $name => $value) {\n                if ($value === null) {\n                    continue;\n                }\n\n                $markup .= ' ' . $name . '=\"' . $value . '\"';\n            }\n        }\n\n        if (isset($Element['text'])) {\n            $markup .= '>';\n\n            if (isset($Element['handler'])) {\n                $markup .= $this->{$Element['handler']}($Element['text']);\n            } else {\n                $markup .= $Element['text'];\n            }\n\n            $markup .= '</' . $Element['name'] . '>';\n        } else {\n            $markup .= ' />';\n        }\n\n        return $markup;\n    }\n\n    protected function elements(array $Elements)\n    {\n        $markup = '';\n\n        foreach ($Elements as $Element) {\n            $markup .= \"\\n\" . $this->element($Element);\n        }\n\n        $markup .= \"\\n\";\n\n        return $markup;\n    }\n\n    # ~\n\n    protected function li($lines)\n    {\n        $markup = $this->lines($lines);\n\n        $trimmedMarkup = trim($markup);\n\n        if (! in_array('', $lines) and substr($trimmedMarkup, 0, 3) === '<p>') {\n            $markup = $trimmedMarkup;\n            $markup = substr($markup, 3);\n\n            $position = strpos($markup, \"</p>\");\n\n            $markup = substr_replace($markup, '', $position, 4);\n        }\n\n        return $markup;\n    }\n\n    #\n    # Deprecated Methods\n    #\n\n    function parse($text)\n    {\n        $markup = $this->text($text);\n\n        return $markup;\n    }\n\n    #\n    # Static Methods\n    #\n\n    static function instance($name = 'default')\n    {\n        if (isset(self::$instances[$name])) {\n            return self::$instances[$name];\n        }\n\n        $instance = new static();\n\n        self::$instances[$name] = $instance;\n\n        return $instance;\n    }\n\n    private static $instances = array();\n\n    #\n    # Fields\n    #\n\n    protected $DefinitionData;\n\n    #\n    # Read-Only\n    #\n\n    protected $specialCharacters = array(\n        '\\\\',\n        '`',\n        '*',\n        '_',\n        '{',\n        '}',\n        '[',\n        ']',\n        '(',\n        ')',\n        '>',\n        '#',\n        '+',\n        '-',\n        '.',\n        '!',\n        '|',\n    );\n\n    protected $StrongRegex = array(\n        '*' => '/^[*]{2}((?:\\\\\\\\\\*|[^*]|[*][^*]*[*])+?)[*]{2}(?![*])/s',\n        '_' => '/^__((?:\\\\\\\\_|[^_]|_[^_]*_)+?)__(?!_)/us',\n    );\n\n    protected $EmRegex = array(\n        '*' => '/^[*]((?:\\\\\\\\\\*|[^*]|[*][*][^*]+?[*][*])+?)[*](?![*])/s',\n        '_' => '/^_((?:\\\\\\\\_|[^_]|__[^_]*__)+?)_(?!_)\\b/us',\n    );\n\n    protected $regexHtmlAttribute = '[a-zA-Z_:][\\w:.-]*(?:\\s*=\\s*(?:[^\"\\'=<>`\\s]+|\"[^\"]*\"|\\'[^\\']*\\'))?';\n\n    protected $voidElements = array(\n        'area',\n        'base',\n        'br',\n        'col',\n        'command',\n        'embed',\n        'hr',\n        'img',\n        'input',\n        'link',\n        'meta',\n        'param',\n        'source',\n    );\n\n    protected $textLevelElements = array(\n        'a',\n        'br',\n        'bdo',\n        'abbr',\n        'blink',\n        'nextid',\n        'acronym',\n        'basefont',\n        'b',\n        'em',\n        'big',\n        'cite',\n        'small',\n        'spacer',\n        'listing',\n        'i',\n        'rp',\n        'del',\n        'code',\n        'strike',\n        'marquee',\n        'q',\n        'rt',\n        'ins',\n        'font',\n        'strong',\n        's',\n        'tt',\n        'sub',\n        'mark',\n        'u',\n        'xm',\n        'sup',\n        'nobr',\n        'var',\n        'ruby',\n        'wbr',\n        'span',\n        'time',\n    );\n}\n"
  },
  {
    "path": "server/app/Common/bootstrap.php",
    "content": "<?php\n\nnamespace App\\Common;\n\nuse App\\Common\\Database\\Database;\nuse App\\Common\\Database\\Upgrade;\nuse App\\Common\\Cache\\CacheManager;\n\n// 基础引导文件：后续可在此初始化配置、日志等。\n\ntry {\n    Database::getInstance();\n    CacheManager::getInstance();\n    \n    // 检查并执行数据库升级（仅在 Web 环境下执行，避免 CLI 任务时重复执行）\n    if (PHP_SAPI !== 'cli') {\n        Upgrade::checkAndUpgrade();\n    }\n} catch (\\Throwable $e) {\n    // 初始化失败时抛出异常，让 Slim 错误处理器处理\n    throw new \\RuntimeException('Bootstrap initialization failed: ' . $e->getMessage(), 0, $e);\n}\n\n"
  },
  {
    "path": "server/app/Common/container.php",
    "content": "<?php\n\nuse DI\\Container;\nuse Psr\\Container\\ContainerInterface;\nuse App\\Common\\Database\\Database;\nuse App\\Common\\Cache\\CacheManager;\n\n/** @var Container $container */\n\n$container->set('db', function (ContainerInterface $c) {\n    return Database::getInstance();\n});\n\n$container->set('redis', function (ContainerInterface $c) {\n    return CacheManager::getInstance();\n});\n\n"
  },
  {
    "path": "server/app/Home/Controller/CommonController.php",
    "content": "<?php\n\nnamespace App\\Home\\Controller;\n\nuse App\\Common\\BaseController;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\nuse Illuminate\\Database\\Capsule\\Manager as DB;\nuse App\\Common\\Helper\\Security;\n\nclass CommonController extends BaseController\n{\n    /**\n     * 重置管理员用户密码\n     * \n     * 使用方式：\n     * php ../showdoc/index.php home/common/repasswd\n     * \n     * 执行后会把管理员用户 showdoc 的密码重置为 123456\n     */\n    public function repasswd(Request $request, Response $response): Response\n    {\n        // 只允许在 CLI 模式下运行\n        if (PHP_SAPI !== 'cli') {\n            $response->getBody()->write(\"please run in command line\");\n            return $response->withStatus(403);\n        }\n\n        $username = 'showdoc';\n        $password = '123456';\n\n        // 查找用户\n        $user = DB::table('user')->where('username', $username)->first();\n\n        if ($user) {\n            // 更新现有用户\n            $salt = Security::generateSalt();\n            $hashedPassword = Security::hashPassword($password, $salt);\n\n            DB::table('user')\n                ->where('username', $username)\n                ->update([\n                    'groupid' => 1,\n                    'password' => $hashedPassword,\n                    'salt' => $salt,\n                ]);\n        } else {\n            // 创建新用户\n            $salt = Security::generateSalt();\n            $hashedPassword = Security::hashPassword($password, $salt);\n\n            DB::table('user')->insert([\n                'username' => $username,\n                'groupid' => 1,\n                'password' => $hashedPassword,\n                'salt' => $salt,\n                'reg_time' => time(),\n            ]);\n        }\n\n        $response->getBody()->write(\"ok\\n\");\n        return $response;\n    }\n}\n"
  },
  {
    "path": "server/app/Home/Controller/DomainController.php",
    "content": "<?php\n\nnamespace App\\Home\\Controller;\n\nuse App\\Common\\BaseController;\nuse App\\Model\\Item;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\n\nclass DomainController extends BaseController\n{\n    // 通过个性域名访问项目：/{domain}\n    public function show(Request $request, Response $response): Response\n    {\n        $domain = (string) $this->getParam($request, 'domain', '');\n        $domain = trim($domain);\n        if ($domain === '') {\n            return $this->fallbackWeb($response);\n        }\n\n        $item = Item::findByDomain($domain);\n        if (!$item) {\n            return $this->fallbackWeb($response);\n        }\n\n        // 将 item_id 注入 attribute，复用 ItemController 的逻辑\n        $request = $request->withAttribute('item_id', (int) $item->item_id);\n        $controller = new ItemController();\n        return $controller->show($request, $response);\n    }\n\n    private function fallbackWeb(Response $response): Response\n    {\n        $rootPath = dirname(__DIR__, 4);\n        $tplPath  = $rootPath . '/web.html';\n        if (!is_file($tplPath)) {\n            return $response->withStatus(404);\n        }\n\n        $html = file_get_contents($tplPath);\n        $response->getBody()->write($html);\n        return $response->withHeader('Content-Type', 'text/html');\n    }\n}\n\n"
  },
  {
    "path": "server/app/Home/Controller/IndexController.php",
    "content": "<?php\n\nnamespace App\\Home\\Controller;\n\nuse App\\Common\\BaseController;\nuse Illuminate\\Database\\Capsule\\Manager as DB;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\n\nclass IndexController extends BaseController\n{\n    public function index(Request $request, Response $response): Response\n    {\n        // 使用相对路径，与旧版保持一致（参考旧版逻辑）\n        // 不存在安装文件夹的，表示已经安装过\n        if (!file_exists(\"./install\")) {\n            return $response\n                ->withHeader('Location', './web/#/')\n                ->withStatus(302);\n        }\n\n        // 如果 install 存在 && install.lock 存在 && install 可写 && install.lock 可写\n        if (file_exists(\"./install\") && file_exists(\"./install/install.lock\") && $this->newIsWriteable(\"./install\") && $this->newIsWriteable(\"./install/install.lock\")) {\n            return $response\n                ->withHeader('Location', './web/#/')\n                ->withStatus(302);\n        }\n        \n        // 其他情况都跳转到安装页面\n        return $response\n            ->withHeader('Location', './install/index.php')\n            ->withStatus(302);\n    }\n\n    /**\n     * 判断 文件/目录 是否可写（取代系统自带的 is_writeable 函数）\n     *\n     * @param string $file 文件/目录\n     * @return boolean\n     */\n    private function newIsWriteable($file)\n    {\n        if (is_dir($file)) {\n            $dir = $file;\n            if ($fp = @fopen(\"$dir/test.txt\", 'w')) {\n                @fclose($fp);\n                @unlink(\"$dir/test.txt\");\n                $writeable = 1;\n            } else {\n                $writeable = 0;\n            }\n        } else {\n            if ($fp = @fopen($file, 'a+')) {\n                @fclose($fp);\n                $writeable = 1;\n            } else {\n                $writeable = 0;\n            }\n        }\n\n        return $writeable;\n    }\n}\n\n"
  },
  {
    "path": "server/app/Home/Controller/ItemController.php",
    "content": "<?php\n\nnamespace App\\Home\\Controller;\n\nuse App\\Common\\BaseController;\nuse App\\Model\\Item;\nuse App\\Model\\Page;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\n\nclass ItemController extends BaseController\n{\n    public function show(Request $request, Response $response): Response\n    {\n        $itemId = (int) $this->getParam($request, 'item_id');\n        $pageId = (int) $this->getParam($request, 'page_id');\n\n        if ($itemId <= 0) {\n            return $this->fallbackWeb($response);\n        }\n\n        $item = Item::findById($itemId);\n        if (!$item) {\n            return $this->fallbackWeb($response);\n        }\n\n        // 加密项目不做 SEO 渲染\n        if (!empty($item->password)) {\n            return $this->fallbackWeb($response);\n        }\n\n        // 页面列表\n        $pages = Page::listTitles((int) $item->item_id);\n        if (empty($pages)) {\n            return $this->fallbackWeb($response);\n        }\n\n        if ($pageId <= 0 && isset($pages[0])) {\n            $pageId = (int) $pages[0]->page_id;\n        }\n\n        $page = Page::findByIdWithContent((int) $item->item_id, $pageId);\n        if (!$page) {\n            return $this->fallbackWeb($response);\n        }\n\n        // 渲染正文内容\n        $pageContent = (string) ($page['page_content'] ?? '');\n\n        // 引入 Parsedown 类（Markdown 解析器）\n        if (!class_exists('Parsedown')) {\n            require_once __DIR__ . '/../../Common/Vendor/Parsedown.php';\n        }\n        // 使用 Parsedown 将 Markdown 转为 HTML\n        $parsedown = new \\Parsedown();\n        $pageHtml  = $parsedown->text($pageContent);\n        $pageHtml  = htmlspecialchars($pageHtml, ENT_QUOTES, 'UTF-8');\n\n        $html  = '';\n        $html .= '<h2>' . htmlspecialchars($item->item_name ?? '', ENT_QUOTES, 'UTF-8') . '</h2>';\n        $html .= '<p>' . htmlspecialchars($item->item_description ?? '', ENT_QUOTES, 'UTF-8') . '</p><br>';\n\n        $html .= '<article><h1>' . htmlspecialchars($page['page_title'] ?? '', ENT_QUOTES, 'UTF-8') . '</h1>';\n        $html .= '<p><div>' . $pageHtml . '</div><p></article>';\n\n        // 页面列表\n        $html .= '<h3>页面列表</h3><nav>';\n        foreach ($pages as $idx => $p) {\n            if ($idx === 0) {\n                continue; // 与旧实现一致：隐藏第一个\n            }\n            $pid   = (int) $p->page_id;\n            $title = htmlspecialchars($p->page_title ?? '', ENT_QUOTES, 'UTF-8');\n            $path  = $item->item_domain ?: $item->item_id;\n            $html .= \"<a href=\\\"/{$path}/{$pid}\\\" title=\\\"{$title}\\\">{$title}</a>\";\n        }\n        $html .= '</nav>';\n\n        // 注入 web.html\n        $rootPath = dirname(__DIR__, 4);\n        $tplPath  = $rootPath . '/web.html';\n        if (!is_file($tplPath)) {\n            return $this->fallbackWeb($response);\n        }\n\n        $tpl  = file_get_contents($tplPath);\n        $html = str_replace('INDEX_HTML', $html, $tpl);\n\n        // 更新 <title> 与 meta 信息\n        $title = htmlspecialchars($item->item_name ?? '', ENT_QUOTES, 'UTF-8');\n        $desc  = htmlspecialchars($item->item_description ?? '', ENT_QUOTES, 'UTF-8');\n\n        $html = preg_replace('/(<title>)(.*?)(<\\/title>)/i', '${1}' . $title . '${3}', $html);\n        $html = preg_replace('/(<meta\\s+name=\"keywords\"\\s+content=\")([^\"]*)(\")/i', '${1}' . $desc . '${3}', $html);\n        $html = preg_replace('/(<meta\\s+name=\"description\"\\s+content=\")([^\"]*)(\")/i', '${1}' . $desc . '${3}', $html);\n\n        $response->getBody()->write($html);\n        return $response->withHeader('Content-Type', 'text/html');\n    }\n\n    private function fallbackWeb(Response $response): Response\n    {\n        $rootPath = dirname(__DIR__, 4);\n        $tplPath  = $rootPath . '/web.html';\n        if (!is_file($tplPath)) {\n            return $response->withStatus(404);\n        }\n\n        $html = file_get_contents($tplPath);\n        $response->getBody()->write($html);\n        return $response->withHeader('Content-Type', 'text/html');\n    }\n}\n\n"
  },
  {
    "path": "server/app/Home/Controller/PageController.php",
    "content": "<?php\n\nnamespace App\\Home\\Controller;\n\nuse App\\Common\\BaseController;\nuse App\\Model\\Item;\nuse App\\Model\\Page;\nuse Illuminate\\Database\\Capsule\\Manager as DB;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\n\nclass PageController extends BaseController\n{\n    public function show(Request $request, Response $response): Response\n    {\n        $pageId = (int) $this->getParam($request, 'page_id');\n        if ($pageId <= 0) {\n            return $this->fallbackWeb($response);\n        }\n\n        // 从主 page 表获取 item_id\n        $pageRow = DB::table('page')\n            ->where('page_id', $pageId)\n            ->where('is_del', 0)\n            ->first();\n\n        if (!$pageRow) {\n            return $this->fallbackWeb($response);\n        }\n\n        $itemId = (int) $pageRow->item_id;\n\n        $item = Item::findById($itemId);\n        if (!$item || !empty($item->password)) {\n            return $this->fallbackWeb($response);\n        }\n\n        $page = Page::findByIdWithContent($itemId, $pageId);\n        if (!$page) {\n            return $this->fallbackWeb($response);\n        }\n\n        $content = (string) ($page['page_content'] ?? '');\n\n        // 引入 Parsedown 类（Markdown 解析器）\n        if (!class_exists('Parsedown')) {\n            require_once __DIR__ . '/../../Common/Vendor/Parsedown.php';\n        }\n        $parsedown = new \\Parsedown();\n        $pageHtml  = $parsedown->text($content);\n        $pageHtml  = htmlspecialchars_decode($pageHtml, ENT_QUOTES, 'UTF-8');\n\n        $html  = '';\n        $html .= '<h2>' . htmlspecialchars($item->item_name ?? '', ENT_QUOTES, 'UTF-8') . '</h2>';\n        $html .= '<p>' . htmlspecialchars($item->item_description ?? '', ENT_QUOTES, 'UTF-8') . '</p><br>';\n        $html .= '<article><h1>' . htmlspecialchars($page['page_title'] ?? '', ENT_QUOTES, 'UTF-8') . '</h1>';\n        $html .= '<div>' . $pageHtml . '</div></article>';\n\n        $rootPath = dirname(__DIR__, 4);\n        $tplPath  = $rootPath . '/web.html';\n        if (!is_file($tplPath)) {\n            return $this->fallbackWeb($response);\n        }\n\n        $tpl  = file_get_contents($tplPath);\n        $html = str_replace('INDEX_HTML', $html, $tpl);\n\n        $title = htmlspecialchars($item->item_name ?? '', ENT_QUOTES, 'UTF-8');\n        $desc  = htmlspecialchars($item->item_description ?? '', ENT_QUOTES, 'UTF-8');\n\n        $html = preg_replace('/(<title>)(.*?)(<\\/title>)/i', '${1}' . $title . '${3}', $html);\n        $html = preg_replace('/(<meta\\s+name=\"keywords\"\\s+content=\")([^\"]*)(\")/i', '${1}' . $desc . '${3}', $html);\n        $html = preg_replace('/(<meta\\s+name=\"description\"\\s+content=\")([^\"]*)(\")/i', '${1}' . $desc . '${3}', $html);\n\n        $response->getBody()->write($html);\n        return $response->withHeader('Content-Type', 'text/html');\n    }\n\n    private function fallbackWeb(Response $response): Response\n    {\n        $rootPath = dirname(__DIR__, 4);\n        $tplPath  = $rootPath . '/web.html';\n        if (!is_file($tplPath)) {\n            return $response->withStatus(404);\n        }\n\n        $html = file_get_contents($tplPath);\n        $response->getBody()->write($html);\n        return $response->withHeader('Content-Type', 'text/html');\n    }\n}\n\n"
  },
  {
    "path": "server/app/Home/Controller/UserController.php",
    "content": "<?php\n\nnamespace App\\Home\\Controller;\n\nuse App\\Common\\BaseController;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\n\nclass UserController extends BaseController\n{\n    // 暂时保持与旧版类似行为：所有 /uid/{username} 直接交给前端应用处理\n    public function profile(Request $request, Response $response): Response\n    {\n        $rootPath = dirname(__DIR__, 4);\n        $tplPath  = $rootPath . '/web.html';\n        if (!is_file($tplPath)) {\n            return $response->withStatus(404);\n        }\n\n        $html = file_get_contents($tplPath);\n        $response->getBody()->write($html);\n        return $response->withHeader('Content-Type', 'text/html');\n    }\n}\n\n"
  },
  {
    "path": "server/app/Mcp/Handler/AttachmentHandler.php",
    "content": "<?php\n\nnamespace App\\Mcp\\Handler;\n\nuse App\\Mcp\\McpHandler;\nuse App\\Mcp\\McpError;\nuse App\\Mcp\\McpException;\nuse App\\Model\\Attachment;\nuse App\\Model\\UploadFile;\nuse App\\Common\\Helper\\OssHelper;\nuse App\\Common\\Helper\\UrlHelper;\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\n/**\n * MCP 附件操作 Handler\n */\nclass AttachmentHandler extends McpHandler\n{\n  /**\n   * 获取支持的操作列表\n   *\n   * @return array\n   */\n  public function getSupportedOperations(): array\n  {\n    return [\n      'upload_attachment',\n      'list_attachments',\n      'delete_attachment',\n    ];\n  }\n\n  /**\n   * 执行操作\n   *\n   * @param string $operation 操作名称\n   * @param array $params 参数\n   * @return mixed\n   * @throws McpException\n   */\n  public function execute(string $operation, array $params = [])\n  {\n    switch ($operation) {\n      case 'upload_attachment':\n        return $this->uploadAttachment($params);\n\n      case 'list_attachments':\n        return $this->listAttachments($params);\n\n      case 'delete_attachment':\n        return $this->deleteAttachment($params);\n\n      default:\n        McpError::throw(McpError::METHOD_NOT_FOUND, \"操作不存在: {$operation}\");\n    }\n  }\n\n  /**\n   * 上传附件（通过 URL 或 Base64）\n   *\n   * @param array $params 参数\n   * @return array\n   * @throws McpException\n   */\n  private function uploadAttachment(array $params): array\n  {\n    $itemId = (int) ($params['item_id'] ?? 0);\n    if ($itemId <= 0) {\n      McpError::throw(McpError::INVALID_PARAMS, '项目ID不能为空');\n    }\n\n    // 检查写入权限\n    $this->requireWritePermission($itemId);\n\n    $pageId = (int) ($params['page_id'] ?? 0);\n    $fileUrl = trim($params['file_url'] ?? '');\n    $fileBase64 = trim($params['file_base64'] ?? '');\n    $fileName = trim($params['file_name'] ?? '');\n\n    // 必须提供 file_url 或 file_base64\n    if ($fileUrl === '' && $fileBase64 === '') {\n      McpError::throw(McpError::INVALID_PARAMS, '必须提供 file_url 或 file_base64');\n    }\n\n    $uid = $this->getUid();\n\n    // 开源版：无需邮箱绑定和支付实名认证即可上传文件\n\n    // 检查空间配额\n    $quotaCheck = $this->checkSpaceQuota($uid);\n    if (!$quotaCheck['allowed']) {\n      McpError::throw(McpError::OPERATION_FAILED, $quotaCheck['message']);\n    }\n\n    // 检查单文件大小限制（开源版：固定 100MB）\n    $fileSizeLimit = $this->getFileSizeLimit();\n\n    // 通过 URL 上传\n    if ($fileUrl !== '') {\n      return $this->uploadFromUrl($itemId, $pageId, $fileUrl, $fileName, $uid, $fileSizeLimit);\n    }\n\n    // 通过 Base64 上传（此时 fileBase64 必定不为空）\n    return $this->uploadFromBase64($itemId, $pageId, $fileBase64, $fileName, $uid, $fileSizeLimit);\n  }\n\n  /**\n   * 检查用户空间配额\n   *\n   * @param int $uid 用户 ID\n   * @param int $additionalSize 额外需要的空间（字节），默认为 0\n   * @return array ['allowed' => bool, 'message' => string, 'usedSpace' => int, 'allowCount' => int]\n   */\n  private function checkSpaceQuota(int $uid, int $additionalSize = 0): array\n  {\n    // 开源版：无 VIP 功能，使用固定的空间配额\n    $usedSpace = Attachment::getUsedSpace($uid);\n    $allowCount = $this->getSpaceQuota();\n\n    $allowed = ($usedSpace + $additionalSize) <= $allowCount;\n    $message = $allowed ? '' : '你使用的空间超出限制。请在项目列表点击更多，进入\"文件库\"来清理不需要的空间。如有疑问请联系网站管理员';\n\n    return [\n      'allowed' => $allowed,\n      'message' => $message,\n      'usedSpace' => $usedSpace,\n      'allowCount' => $allowCount,\n    ];\n  }\n\n  /**\n   * 获取用户的空间配额限制（字节）\n   * 开源版：固定 1TB\n   *\n   * @return int 配额限制（字节）\n   */\n  private function getSpaceQuota(): int\n  {\n    return 1 * 1024 * 1024 * 1024 * 1024; // 开源版固定 1TB\n  }\n\n  /**\n   * 获取用户的单文件大小限制（字节）\n   * 开源版：固定 10GB\n   *\n   * @return int 文件大小限制（字节）\n   */\n  private function getFileSizeLimit(): int\n  {\n    return 10 * 1024 * 1024 * 1024; // 开源版固定 10GB\n  }\n\n  /**\n   * 通过 URL 上传文件\n   *\n   * @param int $itemId 项目ID\n   * @param int $pageId 页面ID\n   * @param string $fileUrl 文件URL\n   * @param string $fileName 文件名\n   * @param int $uid 用户ID\n   * @param int $fileSizeLimit 文件大小限制（字节）\n   * @return array\n   * @throws McpException\n   */\n  private function uploadFromUrl(int $itemId, int $pageId, string $fileUrl, string $fileName, int $uid, int $fileSizeLimit): array\n  {\n    // 下载文件\n    $fileContent = @file_get_contents($fileUrl);\n    if ($fileContent === false) {\n      McpError::throw(McpError::OPERATION_FAILED, '无法下载文件: ' . $fileUrl);\n    }\n\n    // 检查文件大小\n    $fileSize = strlen($fileContent);\n    if ($fileSize > $fileSizeLimit) {\n      $limitMB = round($fileSizeLimit / 1024 / 1024, 1);\n      McpError::throw(McpError::OPERATION_FAILED, \"文件大小超出限制（{$limitMB}MB）。可开通更高级版本获取更大限制\");\n    }\n\n    // 获取文件名\n    if ($fileName === '') {\n      $urlPath = parse_url($fileUrl, PHP_URL_PATH);\n      $fileName = basename($urlPath ?: 'file');\n    }\n\n    // 检查文件名是否允许\n    if (!Attachment::isAllowedFilename($fileName)) {\n      McpError::throw(McpError::OPERATION_FAILED, '不支持上传该文件类型。可将文件压缩成 zip/rar 等压缩包后上传');\n    }\n\n    // 获取文件类型\n    $fileType = $this->getMimeType($fileName, $fileContent);\n\n    // 保存到临时文件\n    $tmpFile = sys_get_temp_dir() . '/mcp_upload_' . uniqid('', true);\n    file_put_contents($tmpFile, $fileContent);\n\n    try {\n      // 构建 $_files 格式\n      $_files = [\n        'file' => [\n          'name'     => $fileName,\n          'type'     => $fileType,\n          'tmp_name' => $tmpFile,\n          'error'    => UPLOAD_ERR_OK,\n          'size'     => $fileSize,\n        ],\n      ];\n\n      // 调用 Attachment::upload\n      $showdocUrl = Attachment::upload($_files, 'file', $uid, $itemId, $pageId, false);\n\n      if (!$showdocUrl) {\n        McpError::throw(McpError::OPERATION_FAILED, '上传失败');\n      }\n\n      // 从 URL 中提取 sign 参数\n      $sign = '';\n      $parsedUrl = parse_url($showdocUrl);\n      if (isset($parsedUrl['query'])) {\n        parse_str($parsedUrl['query'], $queryParams);\n        $sign = $queryParams['sign'] ?? '';\n      }\n\n      // 通过 sign 查找 file_id\n      $fileId = 0;\n      if ($sign) {\n        $file = UploadFile::findBySign($sign);\n        if ($file) {\n          $fileId = (int) ($file->file_id ?? 0);\n        }\n      }\n\n      return [\n        'file_id'   => $fileId,\n        'file_name' => $fileName,\n        'file_type' => $fileType,\n        'file_size' => $fileSize,\n        'url'       => $showdocUrl,\n        'sign'      => $sign,\n        'item_id'   => $itemId,\n        'page_id'   => $pageId,\n        'message'   => '上传成功',\n      ];\n    } finally {\n      // 清理临时文件\n      @unlink($tmpFile);\n    }\n  }\n\n  /**\n   * 通过 Base64 上传文件\n   *\n   * @param int $itemId 项目ID\n   * @param int $pageId 页面ID\n   * @param string $fileBase64 Base64 编码的文件内容\n   * @param string $fileName 文件名\n   * @param int $uid 用户ID\n   * @param int $fileSizeLimit 文件大小限制（字节）\n   * @return array\n   * @throws McpException\n   */\n  private function uploadFromBase64(int $itemId, int $pageId, string $fileBase64, string $fileName, int $uid, int $fileSizeLimit): array\n  {\n    // 解码 Base64\n    $fileContent = base64_decode($fileBase64, true);\n    if ($fileContent === false) {\n      McpError::throw(McpError::INVALID_PARAMS, 'Base64 解码失败');\n    }\n\n    // 检查文件大小\n    $fileSize = strlen($fileContent);\n    if ($fileSize > $fileSizeLimit) {\n      $limitMB = round($fileSizeLimit / 1024 / 1024, 1);\n      McpError::throw(McpError::OPERATION_FAILED, \"文件大小超出限制（{$limitMB}MB）。可开通更高级版本获取更大限制\");\n    }\n\n    // 生成文件名\n    if ($fileName === '') {\n      $fileName = 'file_' . time() . '.bin';\n    }\n\n    // 检查文件名是否允许\n    if (!Attachment::isAllowedFilename($fileName)) {\n      McpError::throw(McpError::OPERATION_FAILED, '不支持上传该文件类型。可将文件压缩成 zip/rar 等压缩包后上传');\n    }\n\n    // 获取文件类型\n    $fileType = $this->getMimeType($fileName, $fileContent);\n\n    // 保存到临时文件\n    $tmpFile = sys_get_temp_dir() . '/mcp_upload_' . uniqid('', true);\n    file_put_contents($tmpFile, $fileContent);\n\n    try {\n      // 构建 $_files 格式\n      $_files = [\n        'file' => [\n          'name'     => $fileName,\n          'type'     => $fileType,\n          'tmp_name' => $tmpFile,\n          'error'    => UPLOAD_ERR_OK,\n          'size'     => $fileSize,\n        ],\n      ];\n\n      // 调用 Attachment::upload\n      $showdocUrl = Attachment::upload($_files, 'file', $uid, $itemId, $pageId, false);\n\n      if (!$showdocUrl) {\n        McpError::throw(McpError::OPERATION_FAILED, '上传失败');\n      }\n\n      // 从 URL 中提取 sign 参数\n      $sign = '';\n      $parsedUrl = parse_url($showdocUrl);\n      if (isset($parsedUrl['query'])) {\n        parse_str($parsedUrl['query'], $queryParams);\n        $sign = $queryParams['sign'] ?? '';\n      }\n\n      // 通过 sign 查找 file_id\n      $fileId = 0;\n      if ($sign) {\n        $file = UploadFile::findBySign($sign);\n        if ($file) {\n          $fileId = (int) ($file->file_id ?? 0);\n        }\n      }\n\n      return [\n        'file_id'   => $fileId,\n        'file_name' => $fileName,\n        'file_type' => $fileType,\n        'file_size' => $fileSize,\n        'url'       => $showdocUrl,\n        'sign'      => $sign,\n        'item_id'   => $itemId,\n        'page_id'   => $pageId,\n        'message'   => '上传成功',\n      ];\n    } finally {\n      // 清理临时文件\n      @unlink($tmpFile);\n    }\n  }\n\n  /**\n   * 获取附件列表\n   *\n   * @param array $params 参数\n   * @return array\n   * @throws McpException\n   */\n  private function listAttachments(array $params): array\n  {\n    $itemId = (int) ($params['item_id'] ?? 0);\n    $pageId = (int) ($params['page_id'] ?? 0);\n\n    if ($itemId <= 0 && $pageId <= 0) {\n      McpError::throw(McpError::INVALID_PARAMS, '必须提供 item_id 或 page_id');\n    }\n\n    // 如果只提供了 page_id，需要获取 item_id 来检查权限\n    if ($itemId <= 0 && $pageId > 0) {\n      // 需要遍历分表查找页面\n      $page = null;\n      for ($i = 1; $i <= 100; $i++) {\n        $page = DB::table(\"page_{$i}\")\n          ->where('page_id', $pageId)\n          ->where('is_del', 0)\n          ->first();\n        if ($page) {\n          break;\n        }\n      }\n      if (!$page) {\n        McpError::throw(McpError::RESOURCE_NOT_FOUND, '页面不存在');\n      }\n      $itemId = (int) $page->item_id;\n    }\n\n    // 检查读取权限\n    $this->requireReadPermission($itemId);\n\n    // 构建查询 - 通过 file_page 表关联\n    $query = DB::table('upload_file as uf')\n      ->join('file_page as fp', 'uf.file_id', '=', 'fp.file_id')\n      ->where('fp.item_id', $itemId);\n\n    if ($pageId > 0) {\n      $query->where('fp.page_id', $pageId);\n    }\n\n    $files = $query->select('uf.*')\n      ->orderBy('uf.addtime', 'desc')\n      ->limit(500)\n      ->get()\n      ->all();\n\n    $result = [];\n    foreach ($files as $row) {\n      // 构建访问 URL\n      $sign = $row->sign ?? '';\n      $url = '';\n      if ($sign) {\n        $extension = '';\n        $realUrl = $row->real_url ?? '';\n        if ($realUrl) {\n          $parsedUrl = parse_url($realUrl);\n          if ($parsedUrl && isset($parsedUrl['path'])) {\n            $extension = pathinfo($parsedUrl['path'], PATHINFO_EXTENSION);\n          }\n        }\n        $params = ['sign' => $sign];\n        if ($extension) {\n          $params['file'] = 'file.' . $extension;\n        }\n        $url = UrlHelper::serverUrl('api/attachment/visitFile', $params);\n      }\n\n      $result[] = [\n        'file_id'   => (int) $row->file_id,\n        'file_name' => $row->display_name ?? '',\n        'file_type' => $row->file_type ?? '',\n        'file_size' => (int) ($row->file_size ?? 0),\n        'url'       => $url,\n        'sign'      => $sign,\n        'item_id'   => $itemId,\n        'page_id'   => $pageId,\n        'addtime'   => date('Y-m-d H:i:s', (int) ($row->addtime ?? 0)),\n      ];\n    }\n\n    return [\n      'item_id'     => $itemId,\n      'page_id'     => $pageId,\n      'attachments' => $result,\n      'total'       => count($result),\n    ];\n  }\n\n  /**\n   * 删除附件\n   *\n   * @param array $params 参数\n   * @return array\n   * @throws McpException\n   */\n  private function deleteAttachment(array $params): array\n  {\n    $fileId = (int) ($params['file_id'] ?? 0);\n    $sign = trim($params['sign'] ?? '');\n\n    if ($fileId <= 0 && $sign === '') {\n      McpError::throw(McpError::INVALID_PARAMS, '必须提供 file_id 或 sign');\n    }\n\n    // 查找文件\n    $file = null;\n    if ($fileId > 0) {\n      $file = UploadFile::findById($fileId);\n    } else {\n      $file = UploadFile::findBySign($sign);\n    }\n\n    if (!$file) {\n      McpError::throw(McpError::RESOURCE_NOT_FOUND, '附件不存在');\n    }\n\n    $fileId = (int) ($file->file_id ?? 0);\n    $itemId = (int) ($file->item_id ?? 0);\n\n    // 检查写入权限\n    $this->requireWritePermission($itemId);\n\n    // 删除文件\n    $deleted = Attachment::deleteFile($fileId);\n    if (!$deleted) {\n      McpError::throw(McpError::OPERATION_FAILED, '删除失败');\n    }\n\n    return [\n      'file_id'   => $fileId,\n      'file_name' => $file->display_name ?? '',\n      'message'   => '删除成功',\n    ];\n  }\n\n  /**\n   * 获取 MIME 类型\n   *\n   * @param string $fileName 文件名\n   * @param string $content 文件内容\n   * @return string\n   */\n  private function getMimeType(string $fileName, string $content): string\n  {\n    // 常见扩展名映射\n    $extension = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));\n    $mimeTypes = [\n      'jpg'  => 'image/jpeg',\n      'jpeg' => 'image/jpeg',\n      'png'  => 'image/png',\n      'gif'  => 'image/gif',\n      'webp' => 'image/webp',\n      'svg'  => 'image/svg+xml',\n      'pdf'  => 'application/pdf',\n      'doc'  => 'application/msword',\n      'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n      'xls'  => 'application/vnd.ms-excel',\n      'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n      'ppt'  => 'application/vnd.ms-powerpoint',\n      'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',\n      'txt'  => 'text/plain',\n      'json' => 'application/json',\n      'xml'  => 'application/xml',\n      'zip'  => 'application/zip',\n      'rar'  => 'application/x-rar-compressed',\n      'tar'  => 'application/x-tar',\n      'gz'   => 'application/gzip',\n      'mp3'  => 'audio/mpeg',\n      'wav'  => 'audio/wav',\n      'mp4'  => 'video/mp4',\n      'mov'  => 'video/quicktime',\n      'css'  => 'text/css',\n      'csv'  => 'text/csv',\n    ];\n\n    if (isset($mimeTypes[$extension])) {\n      return $mimeTypes[$extension];\n    }\n\n    // 尝试通过内容检测\n    $finfo = new \\finfo(FILEINFO_MIME_TYPE);\n    $mimeType = $finfo->buffer($content);\n    return $mimeType ?: 'application/octet-stream';\n  }\n}\n"
  },
  {
    "path": "server/app/Mcp/Handler/CatalogHandler.php",
    "content": "<?php\n\nnamespace App\\Mcp\\Handler;\n\nuse App\\Mcp\\McpHandler;\nuse App\\Mcp\\McpError;\nuse App\\Mcp\\McpException;\nuse App\\Model\\Catalog;\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\n/**\n * MCP 目录操作 Handler\n */\nclass CatalogHandler extends McpHandler\n{\n  /**\n   * 获取支持的操列列表\n   *\n   * @return array\n   */\n  public function getSupportedOperations(): array\n  {\n    return ['list_catalogs', 'get_catalog', 'create_catalog', 'update_catalog', 'delete_catalog'];\n  }\n\n  /**\n   * 执行操作\n   *\n   * @param string $operation 操作名称\n   * @param array $params 参数\n   * @return mixed\n   * @throws McpException\n   */\n  public function execute(string $operation, array $params = [])\n  {\n    switch ($operation) {\n      case 'list_catalogs':\n        return $this->listCatalogs($params);\n\n      case 'get_catalog':\n        return $this->getCatalog($params);\n\n      case 'create_catalog':\n        return $this->createCatalog($params);\n\n      case 'update_catalog':\n        return $this->updateCatalog($params);\n\n      case 'delete_catalog':\n        return $this->deleteCatalog($params);\n\n      default:\n        McpError::throw(McpError::METHOD_NOT_FOUND, \"操作不存在: {$operation}\");\n    }\n  }\n\n  /**\n   * 获取项目的目录树\n   *\n   * @param array $params 参数\n   * @return array\n   * @throws McpException\n   */\n  private function listCatalogs(array $params): array\n  {\n    $itemId = (int) ($params['item_id'] ?? 0);\n    if ($itemId <= 0) {\n      McpError::throw(McpError::INVALID_PARAMS, '项目ID不能为空');\n    }\n\n    // 检查读取权限\n    $this->requireReadPermission($itemId);\n\n    // 获取目录列表\n    $catalogs = DB::table('catalog')\n      ->where('item_id', $itemId)\n      ->orderBy('s_number', 'asc')\n      ->orderBy('cat_id', 'asc')\n      ->get()\n      ->all();\n\n    // 构建树形结构\n    $catalogTree = $this->buildCatalogTree($catalogs, 0);\n\n    return [\n      'item_id' => $itemId,\n      'catalogs' => $catalogTree,\n    ];\n  }\n\n  /**\n   * 构建目录树\n   *\n   * @param array $catalogs 目录列表\n   * @param int $parentId 父目录ID\n   * @return array\n   */\n  private function buildCatalogTree(array $catalogs, int $parentId): array\n  {\n    $tree = [];\n    foreach ($catalogs as $catalog) {\n      $catalog = (array) $catalog;\n      if ((int) $catalog['parent_cat_id'] === $parentId) {\n        $children = $this->buildCatalogTree($catalogs, (int) $catalog['cat_id']);\n        $node = [\n          'cat_id' => (int) $catalog['cat_id'],\n          'cat_name' => $catalog['cat_name'],\n          's_number' => (int) ($catalog['s_number'] ?? 0),\n          'addtime' => $catalog['addtime'] ?? '',\n        ];\n        if (!empty($children)) {\n          $node['children'] = $children;\n        }\n        $tree[] = $node;\n      }\n    }\n    return $tree;\n  }\n\n  /**\n   * 获取目录详情\n   *\n   * @param array $params 参数\n   * @return array\n   * @throws McpException\n   */\n  private function getCatalog(array $params): array\n  {\n    $catId = (int) ($params['cat_id'] ?? 0);\n    if ($catId <= 0) {\n      McpError::throw(McpError::INVALID_PARAMS, '目录ID不能为空');\n    }\n\n    // 获取目录信息\n    $catalog = DB::table('catalog')\n      ->where('cat_id', $catId)\n      ->first();\n\n    if (!$catalog) {\n      McpError::throw(McpError::RESOURCE_NOT_FOUND, '目录不存在');\n    }\n\n    $catalog = (array) $catalog;\n    $itemId = (int) $catalog['item_id'];\n\n    // 检查读取权限\n    $this->requireReadPermission($itemId);\n\n    // 获取分表名称\n    $tableName = \\App\\Model\\Page::tableForItem($itemId);\n\n    // 获取目录下的页面数量\n    $pageCount = DB::table($tableName)\n      ->where('item_id', $itemId)\n      ->where('cat_id', $catId)\n      ->where('is_del', 0)\n      ->count();\n\n    return [\n      'cat_id' => (int) $catalog['cat_id'],\n      'cat_name' => $catalog['cat_name'],\n      'item_id' => $itemId,\n      'parent_cat_id' => (int) ($catalog['parent_cat_id'] ?? 0),\n      's_number' => (int) ($catalog['s_number'] ?? 0),\n      'addtime' => $catalog['addtime'] ?? '',\n      'page_count' => $pageCount,\n    ];\n  }\n\n  /**\n   * 创建目录\n   *\n   * @param array $params 参数\n   * @return array\n   * @throws McpException\n   */\n  private function createCatalog(array $params): array\n  {\n    $itemId = (int) ($params['item_id'] ?? 0);\n    if ($itemId <= 0) {\n      McpError::throw(McpError::INVALID_PARAMS, '项目ID不能为空');\n    }\n\n    $catName = trim($params['cat_name'] ?? '');\n    if ($catName === '') {\n      McpError::throw(McpError::INVALID_PARAMS, '目录名称不能为空');\n    }\n\n    // 检查写入权限\n    $this->requireWritePermission($itemId);\n\n    // 检查单项目目录数量上限（与 CatalogController::save 一致，防止死循环导致数据库写满）\n    $maxCatalogsPerItem = 7500; // 单项目最多 7500 个目录\n    $currentCatalogCount = Catalog::getCount($itemId);\n    if ($currentCatalogCount >= $maxCatalogsPerItem) {\n      McpError::throw(\n        McpError::OPERATION_FAILED,\n        \"该项目已达到目录数量上限（{$maxCatalogsPerItem}个），无法继续创建。如有特殊需求，请联系网站管理员\"\n      );\n    }\n\n    $parentCatId = (int) ($params['parent_cat_id'] ?? 0);\n    $sNumber = (int) ($params['s_number'] ?? 99);\n\n    // 检查父目录是否存在\n    if ($parentCatId > 0) {\n      $parentCatalog = Catalog::findById($parentCatId);\n      if (!$parentCatalog || (int) $parentCatalog->item_id !== $itemId) {\n        McpError::throw(McpError::RESOURCE_NOT_FOUND, '父目录不存在');\n      }\n    }\n\n    // 复用 Catalog::save 方法，确保与原后端逻辑一致（包括层级计算等）\n    $result = Catalog::save(0, $itemId, $catName, $parentCatId, $sNumber);\n    if (!$result) {\n      McpError::throw(McpError::OPERATION_FAILED, '目录创建失败');\n    }\n\n    // 更新项目最后更新时间\n    DB::table('item')\n      ->where('item_id', $itemId)\n      ->update(['last_update_time' => time()]);\n\n    return [\n      'cat_id' => (int) $result['cat_id'],\n      'cat_name' => $result['cat_name'],\n      'parent_cat_id' => (int) ($result['parent_cat_id'] ?? 0),\n      'message' => '目录创建成功',\n    ];\n  }\n\n  /**\n   * 更新目录\n   *\n   * @param array $params 参数\n   * @return array\n   * @throws McpException\n   */\n  private function updateCatalog(array $params): array\n  {\n    $catId = (int) ($params['cat_id'] ?? 0);\n    if ($catId <= 0) {\n      McpError::throw(McpError::INVALID_PARAMS, '目录ID不能为空');\n    }\n\n    // 获取目录信息\n    $catalog = Catalog::findById($catId);\n    if (!$catalog) {\n      McpError::throw(McpError::RESOURCE_NOT_FOUND, '目录不存在');\n    }\n\n    $itemId = (int) $catalog->item_id;\n\n    // 检查写入权限\n    $this->requireWritePermission($itemId);\n\n    // 准备更新参数\n    $catName = isset($params['cat_name']) ? trim($params['cat_name']) : $catalog->cat_name;\n    if ($catName === '') {\n      McpError::throw(McpError::INVALID_PARAMS, '目录名称不能为空');\n    }\n\n    $parentCatId = isset($params['parent_cat_id']) ? (int) $params['parent_cat_id'] : (int) $catalog->parent_cat_id;\n    $sNumber = isset($params['s_number']) ? (int) $params['s_number'] : (int) $catalog->s_number;\n\n    // 复用 Catalog::save 方法，确保与原后端逻辑一致（包括层级计算等）\n    $result = Catalog::save($catId, $itemId, $catName, $parentCatId, $sNumber);\n    if (!$result) {\n      McpError::throw(McpError::OPERATION_FAILED, '目录更新失败');\n    }\n\n    // 更新项目最后更新时间\n    DB::table('item')\n      ->where('item_id', $itemId)\n      ->update(['last_update_time' => time()]);\n\n    return [\n      'cat_id' => $catId,\n      'message' => '目录更新成功',\n    ];\n  }\n\n  /**\n   * 删除目录（含子目录和页面）\n   *\n   * @param array $params 参数\n   * @return array\n   * @throws McpException\n   */\n  private function deleteCatalog(array $params): array\n  {\n    $catId = (int) ($params['cat_id'] ?? 0);\n    if ($catId <= 0) {\n      McpError::throw(McpError::INVALID_PARAMS, '目录ID不能为空');\n    }\n\n    // 获取目录信息\n    $catalog = Catalog::findById($catId);\n    if (!$catalog) {\n      McpError::throw(McpError::RESOURCE_NOT_FOUND, '目录不存在');\n    }\n\n    $itemId = (int) $catalog->item_id;\n\n    // 检查写入权限\n    $this->requireWritePermission($itemId);\n\n    // 统计要删除的目录数量（包含子目录）\n    $catIds = $this->getAllChildCatalogIds($itemId, $catId);\n    $catIds[] = $catId;\n    $deletedCount = count($catIds);\n\n    // 复用 Catalog::deleteCat 方法，确保与原后端逻辑一致\n    // 包括：递归删除子目录、软删除页面、清理缓存等\n    $success = Catalog::deleteCat($catId);\n    if (!$success) {\n      McpError::throw(McpError::OPERATION_FAILED, '目录删除失败');\n    }\n\n    // 更新项目最后更新时间\n    DB::table('item')\n      ->where('item_id', $itemId)\n      ->update(['last_update_time' => time()]);\n\n    return [\n      'cat_id' => $catId,\n      'deleted_catalogs' => $deletedCount,\n      'message' => '目录已删除',\n    ];\n  }\n\n  /**\n   * 获取所有子目录ID\n   *\n   * @param int $itemId 项目ID\n   * @param int $parentCatId 父目录ID\n   * @return array\n   */\n  private function getAllChildCatalogIds(int $itemId, int $parentCatId): array\n  {\n    $catIds = [];\n    $children = DB::table('catalog')\n      ->where('item_id', $itemId)\n      ->where('parent_cat_id', $parentCatId)\n      ->get()\n      ->all();\n\n    foreach ($children as $child) {\n      $childCatId = (int) $child->cat_id;\n      $catIds[] = $childCatId;\n      // 递归获取子目录\n      $catIds = array_merge($catIds, $this->getAllChildCatalogIds($itemId, $childCatId));\n    }\n\n    return $catIds;\n  }\n}\n"
  },
  {
    "path": "server/app/Mcp/Handler/ItemHandler.php",
    "content": "<?php\n\nnamespace App\\Mcp\\Handler;\n\nuse App\\Mcp\\McpHandler;\nuse App\\Mcp\\McpError;\nuse App\\Mcp\\McpException;\nuse App\\Model\\Item;\nuse App\\Model\\ItemMember;\nuse App\\Model\\UserAiToken;\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\n/**\n * MCP 项目操作 Handler\n */\nclass ItemHandler extends McpHandler\n{\n  /**\n   * 获取支持的操列列表\n   *\n   * @return array\n   */\n  public function getSupportedOperations(): array\n  {\n    return ['list_items', 'get_item', 'create_item', 'update_item', 'delete_item'];\n  }\n\n  /**\n   * 执行操作\n   *\n   * @param string $operation 操作名称\n   * @param array $params 参数\n   * @return mixed\n   * @throws McpException\n   */\n  public function execute(string $operation, array $params = [])\n  {\n    switch ($operation) {\n      case 'list_items':\n        return $this->listItems($params);\n\n      case 'get_item':\n        return $this->getItem($params);\n\n      case 'create_item':\n        return $this->createItem($params);\n\n      case 'update_item':\n        return $this->updateItem($params);\n\n      case 'delete_item':\n        return $this->deleteItem($params);\n\n      default:\n        McpError::throw(McpError::METHOD_NOT_FOUND, \"操作不存在: {$operation}\");\n    }\n  }\n\n  /**\n   * 列出用户可访问的所有项目\n   *\n   * @param array $params 参数\n   * @return array\n   */\n  private function listItems(array $params): array\n  {\n    $uid = $this->getUid();\n    if ($uid <= 0) {\n      McpError::throw(McpError::TOKEN_INVALID, '用户未登录');\n    }\n\n    // 获取用户创建的项目\n    $createdItems = DB::table('item')\n      ->where('uid', $uid)\n      ->where('is_del', 0)\n      ->get()\n      ->all();\n\n    // 获取用户作为成员的项目\n    $memberItems = DB::table('item_member')\n      ->join('item', 'item_member.item_id', '=', 'item.item_id')\n      ->where('item_member.uid', $uid)\n      ->where('item.is_del', 0)\n      ->select('item.*', 'item_member.member_group_id')\n      ->get()\n      ->all();\n\n    // 获取用户所在团队的项目\n    $teamItems = DB::table('team_item_member')\n      ->join('item', 'team_item_member.item_id', '=', 'item.item_id')\n      ->where('team_item_member.member_uid', $uid)\n      ->where('item.is_del', 0)\n      ->select('item.*', 'team_item_member.member_group_id')\n      ->get()\n      ->all();\n\n    // 合并并去重\n    $itemsMap = [];\n    foreach ($createdItems as $item) {\n      $item = (array) $item;\n      $item['role'] = 'owner';\n      $itemsMap[$item['item_id']] = $item;\n    }\n\n    foreach ($memberItems as $item) {\n      $item = (array) $item;\n      if (!isset($itemsMap[$item['item_id']])) {\n        $groupId = (int) $item['member_group_id'];\n        $item['role'] = $groupId === 2 ? 'admin' : ($groupId === 1 ? 'editor' : 'readonly');\n        $itemsMap[$item['item_id']] = $item;\n      }\n    }\n\n    foreach ($teamItems as $item) {\n      $item = (array) $item;\n      if (!isset($itemsMap[$item['item_id']])) {\n        $groupId = (int) $item['member_group_id'];\n        $item['role'] = $groupId === 2 ? 'admin' : ($groupId === 1 ? 'editor' : 'readonly');\n        $itemsMap[$item['item_id']] = $item;\n      }\n    }\n\n    // 根据 Token scope 过滤\n    $scope = $this->tokenInfo['scope'] ?? 'all';\n    if ($scope === 'selected') {\n      $allowedItems = json_decode($this->tokenInfo['allowed_items'] ?? '[]', true) ?: [];\n      $itemsMap = array_filter($itemsMap, function ($item) use ($allowedItems) {\n        return in_array($item['item_id'], $allowedItems);\n      });\n    }\n\n    // 格式化输出\n    $items = [];\n    foreach ($itemsMap as $item) {\n      $items[] = [\n        'item_id' => (int) $item['item_id'],\n        'item_name' => $item['item_name'],\n        'item_type' => (int) ($item['item_type'] ?? 1),\n        'item_description' => $item['item_description'] ?? '',\n        'role' => $item['role'],\n        'create_time' => $item['addtime'] ?? '',\n        'last_update_time' => $item['last_update_time'] ?? '',\n      ];\n    }\n\n    return [\n      'items' => $items,\n      'total' => count($items),\n    ];\n  }\n\n  /**\n   * 获取项目详情\n   *\n   * @param array $params 参数\n   * @return array\n   * @throws McpException\n   */\n  private function getItem(array $params): array\n  {\n    $itemId = (int) ($params['item_id'] ?? 0);\n    if ($itemId <= 0) {\n      McpError::throw(McpError::INVALID_PARAMS, '项目ID不能为空');\n    }\n\n    // 检查权限\n    $this->requireReadPermission($itemId);\n\n    // 获取项目信息\n    $item = Item::findById($itemId);\n    if (!$item) {\n      McpError::throw(McpError::RESOURCE_NOT_FOUND, '项目不存在');\n    }\n\n    // 获取用户角色\n    $role = $this->getItemRole($itemId);\n\n    // 获取分表名称\n    $tableName = \\App\\Model\\Page::tableForItem($itemId);\n\n    return [\n      'item_id' => (int) $item->item_id,\n      'item_name' => $item->item_name,\n      'item_type' => (int) ($item->item_type ?? 1),\n      'item_description' => $item->item_description ?? '',\n      'role' => $role,\n      'create_time' => $item->addtime ?? '',\n      'last_update_time' => $item->last_update_time ?? '',\n      'page_count' => DB::table($tableName)\n        ->where('item_id', $itemId)\n        ->where('is_del', 0)\n        ->count(),\n    ];\n  }\n\n  /**\n   * 创建新项目\n   *\n   * @param array $params 参数\n   * @return array\n   * @throws McpException\n   */\n  private function createItem(array $params): array\n  {\n    $uid = $this->getUid();\n    if ($uid <= 0) {\n      McpError::throw(McpError::TOKEN_INVALID, '用户未登录');\n    }\n\n    // 检查 Token 是否允许创建项目\n    if (!$this->canCreateItem()) {\n      McpError::throw(McpError::TOKEN_OPERATION_DENIED, 'Token 不允许创建项目');\n    }\n\n    $itemName = trim($params['item_name'] ?? '');\n    if ($itemName === '') {\n      McpError::throw(McpError::INVALID_PARAMS, '项目名称不能为空');\n    }\n\n    $itemType = (int) ($params['item_type'] ?? 1);\n    $itemDescription = trim($params['item_description'] ?? '');\n    $password = trim($params['password'] ?? '');\n\n    // 检查用户项目数量限制（复用现有逻辑，与 ItemController::add 一致）\n    $itemCount = DB::table('item')\n      ->where('uid', $uid)\n      ->where('is_del', 0)\n      ->count();\n\n    // 开源版：无 VIP 功能，使用固定的项目数量限制\n    $allowCount = 100000; // 开源版默认允许 100000 个项目\n\n    // 检查项目数量是否超限（runapi默认项目除外）\n    if ($itemCount >= $allowCount && $itemName !== 'runapi默认项目') {\n      McpError::throw(\n        McpError::OPERATION_FAILED,\n        '你创建的项目数超出限制。如有需求请联系网站管理员'\n      );\n    }\n\n    // 单用户项目数量绝对上限（防止死循环）\n    $maxItemsPerUser = 100000;\n    if ($itemCount >= $maxItemsPerUser) {\n      McpError::throw(\n        McpError::OPERATION_FAILED,\n        \"你创建的项目数已达到系统上限（{$maxItemsPerUser}个），无法继续创建。如有特殊需求，请联系网站管理员\"\n      );\n    }\n\n    // 开源版：无需邮箱绑定和支付实名认证即可创建公开项目\n\n    // 创建项目\n    $now = time();\n    $data = [\n      'item_name' => $itemName,\n      'item_type' => $itemType,\n      'item_description' => $itemDescription,\n      'password' => $password,\n      'uid' => $uid,\n      'addtime' => $now,\n      'last_update_time' => $now,\n      'is_del' => 0,\n    ];\n\n    // 复用 Item::add 方法，确保与原后端逻辑一致\n    $itemId = Item::add($data);\n    if ($itemId <= 0) {\n      McpError::throw(McpError::OPERATION_FAILED, '项目创建失败');\n    }\n\n    // 将新项目添加到 Token 的权限范围\n    $this->addCreatedItemToScope($itemId);\n\n    return [\n      'item_id' => $itemId,\n      'item_name' => $itemName,\n      'item_type' => $itemType,\n      'item_description' => $itemDescription,\n      'message' => '项目创建成功',\n    ];\n  }\n\n  /**\n   * 更新项目信息\n   *\n   * @param array $params 参数\n   * @return array\n   * @throws McpException\n   */\n  private function updateItem(array $params): array\n  {\n    $itemId = (int) ($params['item_id'] ?? 0);\n    if ($itemId <= 0) {\n      McpError::throw(McpError::INVALID_PARAMS, '项目ID不能为空');\n    }\n\n    // 检查写入权限\n    $this->requireWritePermission($itemId);\n\n    // 检查是否有管理权限\n    if (!$this->canManageItem($itemId)) {\n      McpError::throw(McpError::NO_EDIT_PERMISSION, '只有项目管理员才能修改项目信息');\n    }\n\n    // 获取项目\n    $item = Item::findById($itemId);\n    if (!$item) {\n      McpError::throw(McpError::RESOURCE_NOT_FOUND, '项目不存在');\n    }\n\n    // 准备更新数据\n    $updateData = [];\n    if (isset($params['item_name'])) {\n      $itemName = trim($params['item_name']);\n      if ($itemName === '') {\n        McpError::throw(McpError::INVALID_PARAMS, '项目名称不能为空');\n      }\n      $updateData['item_name'] = $itemName;\n    }\n\n    if (isset($params['item_description'])) {\n      $updateData['item_description'] = trim($params['item_description']);\n    }\n\n    if (empty($updateData)) {\n      McpError::throw(McpError::INVALID_PARAMS, '没有需要更新的内容');\n    }\n\n    $updateData['last_update_time'] = time();\n\n    try {\n      DB::table('item')\n        ->where('item_id', $itemId)\n        ->update($updateData);\n\n      return [\n        'item_id' => $itemId,\n        'message' => '项目更新成功',\n      ];\n    } catch (\\Throwable $e) {\n      McpError::throw(McpError::OPERATION_FAILED, '项目更新失败: ' . $e->getMessage());\n    }\n  }\n\n  /**\n   * 删除项目（软删除）\n   *\n   * @param array $params 参数\n   * @return array\n   * @throws McpException\n   */\n  private function deleteItem(array $params): array\n  {\n    $itemId = (int) ($params['item_id'] ?? 0);\n    if ($itemId <= 0) {\n      McpError::throw(McpError::INVALID_PARAMS, '项目ID不能为空');\n    }\n\n    // 检查 Token 是否允许删除项目\n    if (!$this->canDeleteItem()) {\n      McpError::throw(McpError::TOKEN_OPERATION_DENIED, 'Token 不允许删除项目');\n    }\n\n    // 获取项目\n    $item = Item::findById($itemId);\n    if (!$item) {\n      McpError::throw(McpError::RESOURCE_NOT_FOUND, '项目不存在');\n    }\n\n    // 只有项目创建者才能删除项目\n    if ((int) $item->uid !== $this->getUid()) {\n      McpError::throw(McpError::NO_EDIT_PERMISSION, '只有项目创建者才能删除项目');\n    }\n\n    try {\n      // 软删除项目\n      DB::table('item')\n        ->where('item_id', $itemId)\n        ->update([\n          'is_del' => 1,\n          'last_update_time' => time(),\n        ]);\n\n      // 软删除项目下的所有页面（使用分表）\n      $tableName = \\App\\Model\\Page::tableForItem($itemId);\n      DB::table($tableName)\n        ->where('item_id', $itemId)\n        ->update(['is_del' => 1]);\n\n      return [\n        'item_id' => $itemId,\n        'message' => '项目已删除',\n      ];\n    } catch (\\Throwable $e) {\n      McpError::throw(McpError::OPERATION_FAILED, '项目删除失败: ' . $e->getMessage());\n    }\n  }\n}\n"
  },
  {
    "path": "server/app/Mcp/Handler/OpenApiHandler.php",
    "content": "<?php\n\nnamespace App\\Mcp\\Handler;\n\nuse App\\Mcp\\McpHandler;\nuse App\\Mcp\\McpError;\nuse App\\Mcp\\McpException;\nuse App\\Model\\Item;\nuse App\\Common\\Helper\\Convert;\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\n/**\n * MCP OpenAPI 导入 Handler\n */\nclass OpenApiHandler extends McpHandler\n{\n  /**\n   * OpenAPI 数据\n   *\n   * @var array\n   */\n  private array $jsonArray = [];\n\n  /**\n   * URL 前缀\n   *\n   * @var string\n   */\n  private string $urlPre = '';\n\n  /**\n   * 获取支持的操作列表\n   *\n   * @return array\n   */\n  public function getSupportedOperations(): array\n  {\n    return [\n      'import_openapi',\n    ];\n  }\n\n  /**\n   * 执行操作\n   *\n   * @param string $operation 操作名称\n   * @param array $params 参数\n   * @return mixed\n   * @throws McpException\n   */\n  public function execute(string $operation, array $params = [])\n  {\n    switch ($operation) {\n      case 'import_openapi':\n        return $this->importOpenApi($params);\n\n      default:\n        McpError::throw(McpError::METHOD_NOT_FOUND, \"操作不存在: {$operation}\");\n    }\n  }\n\n  /**\n   * 导入 OpenAPI/Swagger 文档\n   *\n   * @param array $params 参数\n   * @return array\n   * @throws McpException\n   */\n  private function importOpenApi(array $params): array\n  {\n    $itemId = (int) ($params['item_id'] ?? 0);\n    $openapiContent = trim($params['openapi_content'] ?? '');\n    $openapiUrl = trim($params['openapi_url'] ?? '');\n    $format = trim($params['format'] ?? 'markdown'); // markdown 或 runapi\n\n    // 获取 OpenAPI 内容\n    if ($openapiContent !== '') {\n      $jsonContent = $openapiContent;\n    } elseif ($openapiUrl !== '') {\n      $jsonContent = $this->fetchUrl($openapiUrl);\n    } else {\n      McpError::throw(McpError::INVALID_PARAMS, '请提供 openapi_content 或 openapi_url');\n    }\n\n    // 解析 JSON\n    $jsonArray = json_decode($jsonContent, true);\n    if (empty($jsonArray) || !isset($jsonArray['info'])) {\n      McpError::throw(McpError::INVALID_PARAMS, '无效的 OpenAPI/Swagger 文档格式');\n    }\n\n    // 检查 OpenAPI 文档大小限制（防止超大文档导致问题）\n    $maxContentSize = 150 * 1024 * 1024; // 150MB\n    if (strlen($jsonContent) > $maxContentSize) {\n      McpError::throw(McpError::OPERATION_FAILED, 'OpenAPI 文档大小超出限制（150MB），请拆分后分批导入');\n    }\n\n    // 检查接口数量限制（防止超大文档导入过多页面）\n    $paths = $jsonArray['paths'] ?? [];\n    $endpointCount = 0;\n    foreach ($paths as $url => $methods) {\n      $endpointCount += count($methods);\n    }\n    $maxEndpoints = 25000; // 最多 25000 个接口\n    if ($endpointCount > $maxEndpoints) {\n      McpError::throw(McpError::OPERATION_FAILED, \"OpenAPI 文档包含 {$endpointCount} 个接口，超出单次导入限制（{$maxEndpoints}个），请拆分后分批导入\");\n    }\n\n    // 检查项目权限\n    if ($itemId > 0) {\n      $this->requireWritePermission($itemId);\n    }\n    // 如果没有指定项目，Item::import 会创建新项目\n\n    $this->jsonArray = $jsonArray;\n\n    // 确定 Swagger/OpenAPI 版本\n    $swaggerVersion = '';\n    if (isset($jsonArray['swagger'])) {\n      $swaggerVersion = $jsonArray['swagger'];\n    } elseif (isset($jsonArray['openapi'])) {\n      $swaggerVersion = $jsonArray['openapi'];\n    }\n\n    // 设置 URL 前缀\n    $this->setUrlPrefix($jsonArray, $swaggerVersion);\n\n    // 转换引用定义（最多10次）\n    for ($i = 0; $i < 10; $i++) {\n      $this->jsonArray = $this->transferDefinition($this->jsonArray);\n    }\n\n    // 导入数据\n    $result = $this->importFromSwagger($this->jsonArray, $itemId, $swaggerVersion, $format);\n\n    return $result;\n  }\n\n  /**\n   * 从 URL 获取内容\n   *\n   * @param string $url URL 地址\n   * @return string\n   * @throws McpException\n   */\n  private function fetchUrl(string $url): string\n  {\n    // 验证 URL 格式\n    if (!filter_var($url, FILTER_VALIDATE_URL)) {\n      McpError::throw(McpError::INVALID_PARAMS, '无效的 URL 格式');\n    }\n\n    // 使用 cURL 获取内容\n    $ch = curl_init();\n    curl_setopt($ch, CURLOPT_URL, $url);\n    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n    curl_setopt($ch, CURLOPT_TIMEOUT, 30);\n    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);\n    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);\n    curl_setopt($ch, CURLOPT_MAXREDIRS, 5);\n\n    $content = curl_exec($ch);\n    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);\n    $error = curl_error($ch);\n    curl_close($ch);\n\n    if ($error) {\n      McpError::throw(McpError::OPERATION_FAILED, '获取 OpenAPI 文档失败: ' . $error);\n    }\n\n    if ($httpCode !== 200) {\n      McpError::throw(McpError::OPERATION_FAILED, \"获取 OpenAPI 文档失败: HTTP {$httpCode}\");\n    }\n\n    return $content;\n  }\n\n  /**\n   * 设置 URL 前缀\n   *\n   * @param array $jsonArray OpenAPI 数据\n   * @param string $swaggerVersion 版本\n   */\n  private function setUrlPrefix(array $jsonArray, string $swaggerVersion): void\n  {\n    if (strstr($swaggerVersion, '2.')) {\n      // Swagger 2.0 格式\n      $scheme = $jsonArray['schemes'][0] ?? 'http';\n      if (!empty($jsonArray['host'])) {\n        $this->urlPre = $scheme . \"://\" . $jsonArray['host'] . ($jsonArray['basePath'] ?? '');\n      }\n    } else {\n      // OpenAPI 3.0 格式\n      if (!empty($jsonArray['servers'][0]['url'])) {\n        $this->urlPre = $jsonArray['servers'][0]['url'];\n      }\n    }\n  }\n\n  /**\n   * 从 Swagger 导入\n   *\n   * @param array $jsonArray OpenAPI 数据\n   * @param int $itemId 项目ID\n   * @param string $swaggerVersion 版本\n   * @param string $format 格式\n   * @return array\n   */\n  private function importFromSwagger(array $jsonArray, int $itemId, string $swaggerVersion, string $format): array\n  {\n    $uid = $this->getUid();\n\n    $itemArray = [\n      'item_id'         => $itemId,\n      'item_name'       => $jsonArray['info']['title'] ?? 'from swagger',\n      'item_type'       => ($format === 'runapi') ? '3' : '1',\n      'item_description' => $jsonArray['info']['description'] ?? '',\n      'password'        => time() . rand(),\n      'members'         => [],\n      'pages'           => [\n        'pages'    => [],\n        'catalogs' => $this->getAllTagsLogs($jsonArray, $swaggerVersion, $format),\n      ],\n    ];\n\n    $newItemId = Item::import(json_encode($itemArray), $uid, $itemId);\n\n    // 统计导入结果\n    $catalogCount = count($itemArray['pages']['catalogs']);\n    $pageCount = 0;\n    foreach ($itemArray['pages']['catalogs'] as $catalog) {\n      $pageCount += count($catalog['pages'] ?? []);\n    }\n\n    return [\n      'item_id' => $newItemId,\n      'item_name' => $itemArray['item_name'],\n      'is_new_item' => $itemId === 0,\n      'swagger_version' => $swaggerVersion,\n      'format' => $format,\n      'catalog_count' => $catalogCount,\n      'page_count' => $pageCount,\n      'message' => $itemId > 0 ? 'OpenAPI 文档已导入到现有项目' : '已创建新项目并导入 OpenAPI 文档',\n    ];\n  }\n\n  /**\n   * 获取所有标签（目录）\n   *\n   * @param array $jsonArray OpenAPI 数据\n   * @param string $swaggerVersion 版本\n   * @param string $format 格式\n   * @return array\n   */\n  private function getAllTagsLogs(array $jsonArray, string $swaggerVersion, string $format): array\n  {\n    $catalogsMap = [\n      'fromSwagger' => ['cat_name' => 'from swagger', 'pages' => []],\n    ];\n\n    $paths = $jsonArray['paths'] ?? [];\n    foreach ($paths as $url => $value) {\n      foreach ($value as $method => $value2) {\n        $tags = $value2['tags'] ?? [];\n        if (empty($tags)) {\n          $page = $this->requestToDoc($method, $url, $value2, $jsonArray, $swaggerVersion, $format);\n          if (!empty($page['page_title'])) {\n            $catalogsMap['fromSwagger']['pages'][] = $page;\n          }\n        } else {\n          foreach ($tags as $tag) {\n            if (!key_exists($tag, $catalogsMap)) {\n              $page = $this->requestToDoc($method, $url, $value2, $jsonArray, $swaggerVersion, $format);\n              if (!empty($page['page_title']) && !empty($page['page_content'])) {\n                $catalogsMap[$tag] = ['cat_name' => $tag, 'pages' => [$page]];\n              }\n            } else {\n              $page = $this->requestToDoc($method, $url, $value2, $jsonArray, $swaggerVersion, $format);\n              if (!empty($page['page_title']) && !empty($page['page_content'])) {\n                $catalogsMap[$tag]['pages'][] = $page;\n              }\n            }\n          }\n        }\n      }\n    }\n\n    $catalogs = [];\n    foreach ($catalogsMap as $value) {\n      $catalogs[] = $value;\n    }\n\n    return $catalogs;\n  }\n\n  /**\n   * 请求转文档\n   *\n   * @param string $method HTTP 方法\n   * @param string $url URL\n   * @param array $request 请求数据\n   * @param array $jsonArray OpenAPI 数据\n   * @param string $swaggerVersion 版本\n   * @param string $format 格式\n   * @return array\n   */\n  private function requestToDoc(string $method, string $url, array $request, array $jsonArray, string $swaggerVersion, string $format): array\n  {\n    $res = $this->requestToApi($method, $url, $request, $jsonArray, $swaggerVersion);\n    if ($format === 'runapi') {\n      return $res;\n    } else {\n      $convert = new Convert();\n      $res['page_content'] = $convert->runapiToMd($res['page_content']);\n      return $res;\n    }\n  }\n\n  /**\n   * 请求转 API 格式\n   *\n   * @param string $method HTTP 方法\n   * @param string $url URL\n   * @param array $request 请求数据\n   * @param array $jsonArray OpenAPI 数据\n   * @param string $swaggerVersion 版本\n   * @return array\n   */\n  private function requestToApi(string $method, string $url, array $request, array $jsonArray, string $swaggerVersion): array\n  {\n    $return = [];\n    $pageTitle = $request['summary'] ?? $request['description'] ?? '';\n    if (empty($pageTitle) && !empty($request['operationId'])) {\n      $pageTitle = $request['operationId'];\n    }\n    if (empty($pageTitle)) {\n      $pageTitle = strtoupper($method) . ' ' . $url;\n    }\n    $pageTitle = mb_substr($pageTitle, 0, 50, 'utf-8');\n    $return['page_title'] = $pageTitle;\n    $return['s_number'] = 99;\n    $return['page_comments'] = '';\n\n    $contentArray = [\n      'info'     => [\n        'from'        => 'runapi',\n        'type'       => 'api',\n        'title'      => $request['summary'] ?? $request['description'] ?? '',\n        'description' => $request['description'] ?? '',\n        'method'     => strtolower($method),\n        'url'        => $this->urlPre . $url,\n        'remark'     => '',\n      ],\n      'request'  => [\n        'params'  => [\n          'mode'      => 'formdata',\n          'json'      => '',\n          'jsonDesc'  => [],\n          'urlencoded' => [],\n          'formdata'  => [],\n        ],\n        'query'   => [],\n        'headers' => [],\n        'cookies' => [],\n        'auth'    => [],\n      ],\n      'response' => [],\n      'extend'   => [],\n    ];\n\n    // 根据版本处理请求体\n    if (strstr($swaggerVersion, '2.')) {\n      $this->processSwagger2Request($request, $contentArray);\n    } else {\n      $this->processOpenAPI3Request($request, $contentArray);\n    }\n\n    // 根据版本处理响应\n    if (strstr($swaggerVersion, '2.')) {\n      $this->processSwagger2Response($request, $contentArray);\n    } else {\n      $this->processOpenAPI3Response($request, $contentArray);\n    }\n\n    $return['page_content'] = json_encode($contentArray);\n    return $return;\n  }\n\n  /**\n   * 处理 Swagger 2.0 请求\n   *\n   * @param array $request 请求数据\n   * @param array $contentArray 内容数组\n   */\n  private function processSwagger2Request(array $request, array &$contentArray): void\n  {\n    // 处理参数\n    $parameters = $request['parameters'] ?? [];\n    foreach ($parameters as $param) {\n      $paramType = $param['in'] ?? '';\n      $paramName = $param['name'] ?? '';\n      $paramDesc = $param['description'] ?? '';\n      $paramRequired = isset($param['required']) && $param['required'] ? '1' : '0';\n      $paramValueType = $param['type'] ?? 'string';\n      $paramValue = $param['default'] ?? $param['example'] ?? '';\n\n      if ($paramType === 'query') {\n        $contentArray['request']['query'][] = [\n          'name'    => $paramName,\n          'type'    => $paramValueType,\n          'value'   => $paramValue,\n          'require' => $paramRequired,\n          'remark'  => $paramDesc,\n        ];\n      } elseif ($paramType === 'header') {\n        $contentArray['request']['headers'][] = [\n          'name'    => $paramName,\n          'type'    => $paramValueType,\n          'value'   => $paramValue,\n          'require' => $paramRequired,\n          'remark'  => $paramDesc,\n        ];\n      } elseif ($paramType === 'formData') {\n        $contentArray['request']['params']['formdata'][] = [\n          'name'    => $paramName,\n          'type'    => $paramValueType,\n          'value'   => $paramValue,\n          'require' => $paramRequired,\n          'remark'  => $paramDesc,\n        ];\n      } elseif ($paramType === 'body') {\n        $schema = $param['schema'] ?? [];\n        if (!empty($schema['$ref'])) {\n          $refArray = $this->getDefinition($schema['$ref']);\n          if ($refArray) {\n            $contentArray['request']['params']['json'] = json_encode($this->definitionToJson($refArray), JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);\n            $contentArray['request']['params']['jsonDesc'] = $this->definitionToJsonArray($refArray);\n          }\n        } elseif (!empty($schema)) {\n          $contentArray['request']['params']['json'] = json_encode($this->schemaToJson($schema), JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);\n        }\n      }\n    }\n  }\n\n  /**\n   * 处理 OpenAPI 3.0 请求\n   *\n   * @param array $request 请求数据\n   * @param array $contentArray 内容数组\n   */\n  private function processOpenAPI3Request(array $request, array &$contentArray): void\n  {\n    // 处理参数\n    $parameters = $request['parameters'] ?? [];\n    foreach ($parameters as $param) {\n      $paramType = $param['in'] ?? '';\n      $paramName = $param['name'] ?? '';\n      $paramDesc = $param['description'] ?? '';\n      $paramRequired = isset($param['required']) && $param['required'] ? '1' : '0';\n      $schema = $param['schema'] ?? [];\n      $paramValueType = $schema['type'] ?? 'string';\n      $paramValue = $schema['default'] ?? $schema['example'] ?? '';\n\n      if ($paramType === 'query') {\n        $contentArray['request']['query'][] = [\n          'name'    => $paramName,\n          'type'    => $paramValueType,\n          'value'   => $paramValue,\n          'require' => $paramRequired,\n          'remark'  => $paramDesc,\n        ];\n      } elseif ($paramType === 'header') {\n        $contentArray['request']['headers'][] = [\n          'name'    => $paramName,\n          'type'    => $paramValueType,\n          'value'   => $paramValue,\n          'require' => $paramRequired,\n          'remark'  => $paramDesc,\n        ];\n      }\n    }\n\n    // 处理请求体\n    $requestBody = $request['requestBody'] ?? [];\n    if (!empty($requestBody)) {\n      $content = $requestBody['content'] ?? [];\n      if (isset($content['application/json'])) {\n        $schema = $content['application/json']['schema'] ?? [];\n        if (!empty($schema['$ref'])) {\n          $refArray = $this->getDefinition($schema['$ref']);\n          if ($refArray) {\n            $contentArray['request']['params']['json'] = json_encode($this->definitionToJson($refArray), JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);\n            $contentArray['request']['params']['jsonDesc'] = $this->definitionToJsonArray($refArray);\n          }\n        } elseif (!empty($schema)) {\n          $contentArray['request']['params']['json'] = json_encode($this->schemaToJson($schema), JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);\n        }\n      } elseif (isset($content['multipart/form-data'])) {\n        $schema = $content['multipart/form-data']['schema'] ?? [];\n        if (!empty($schema['properties'])) {\n          foreach ($schema['properties'] as $propName => $propValue) {\n            $contentArray['request']['params']['formdata'][] = [\n              'name'    => $propName,\n              'type'    => $propValue['type'] ?? 'string',\n              'value'   => $propValue['default'] ?? $propValue['example'] ?? '',\n              'require' => in_array($propName, $schema['required'] ?? []) ? '1' : '0',\n              'remark'  => $propValue['description'] ?? '',\n            ];\n          }\n        }\n      }\n    }\n  }\n\n  /**\n   * 处理 Swagger 2.0 响应\n   *\n   * @param array $request 请求数据\n   * @param array $contentArray 内容数组\n   */\n  private function processSwagger2Response(array $request, array &$contentArray): void\n  {\n    $responses = $request['responses'] ?? [];\n    foreach ($responses as $code => $response) {\n      $schema = $response['schema'] ?? [];\n      if (!empty($schema['$ref'])) {\n        $refArray = $this->getDefinition($schema['$ref']);\n        if ($refArray) {\n          $contentArray['response'][] = [\n            'name'    => (string) $code,\n            'type'    => 'object',\n            'value'   => json_encode($this->definitionToJson($refArray), JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE),\n            'require' => '1',\n            'remark'  => $response['description'] ?? '',\n          ];\n        }\n      } elseif (!empty($schema)) {\n        $contentArray['response'][] = [\n          'name'    => (string) $code,\n          'type'    => 'object',\n          'value'   => json_encode($this->schemaToJson($schema), JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE),\n          'require' => '1',\n          'remark'  => $response['description'] ?? '',\n        ];\n      } else {\n        $contentArray['response'][] = [\n          'name'    => (string) $code,\n          'type'    => 'string',\n          'value'   => '',\n          'require' => '1',\n          'remark'  => $response['description'] ?? '',\n        ];\n      }\n    }\n  }\n\n  /**\n   * 处理 OpenAPI 3.0 响应\n   *\n   * @param array $request 请求数据\n   * @param array $contentArray 内容数组\n   */\n  private function processOpenAPI3Response(array $request, array &$contentArray): void\n  {\n    $responses = $request['responses'] ?? [];\n    foreach ($responses as $code => $response) {\n      $content = $response['content'] ?? [];\n      if (isset($content['application/json'])) {\n        $schema = $content['application/json']['schema'] ?? [];\n        if (!empty($schema['$ref'])) {\n          $refArray = $this->getDefinition($schema['$ref']);\n          if ($refArray) {\n            $contentArray['response'][] = [\n              'name'    => (string) $code,\n              'type'    => 'object',\n              'value'   => json_encode($this->definitionToJson($refArray), JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE),\n              'require' => '1',\n              'remark'  => $response['description'] ?? '',\n            ];\n          }\n        } elseif (!empty($schema)) {\n          $contentArray['response'][] = [\n            'name'    => (string) $code,\n            'type'    => 'object',\n            'value'   => json_encode($this->schemaToJson($schema), JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE),\n            'require' => '1',\n            'remark'  => $response['description'] ?? '',\n          ];\n        }\n      } else {\n        $contentArray['response'][] = [\n          'name'    => (string) $code,\n          'type'    => 'string',\n          'value'   => '',\n          'require' => '1',\n          'remark'  => $response['description'] ?? '',\n        ];\n      }\n    }\n  }\n\n  /**\n   * 获取引用定义\n   *\n   * @param string $refStr 引用字符串\n   * @return array|null\n   */\n  private function getDefinition(string $refStr): ?array\n  {\n    $jsonArray = $this->jsonArray;\n    $strArray = explode('/', $refStr);\n\n    $targetArray = null;\n    if (isset($strArray[2])) {\n      $targetArray = $jsonArray[$strArray[1]][$strArray[2]] ?? null;\n    }\n    if (isset($strArray[3]) && $targetArray) {\n      $targetArray = $targetArray[$strArray[3]] ?? null;\n    }\n\n    return $targetArray ?: null;\n  }\n\n  /**\n   * 转换引用定义（递归替换 $ref）\n   *\n   * @param array $data 数据\n   * @return array\n   */\n  private function transferDefinition(array $data): array\n  {\n    if (is_array($data)) {\n      foreach ($data as $key => $value) {\n        if (is_array($value)) {\n          if (isset($value['$ref'])) {\n            $refArray = $this->getDefinition($value['$ref']);\n            if ($refArray) {\n              $data[$key] = $refArray;\n            }\n          } else {\n            $data[$key] = $this->transferDefinition($value);\n          }\n        }\n      }\n    }\n    return $data;\n  }\n\n  /**\n   * 定义转 JSON 数组（用于参数描述）\n   *\n   * @param array $refArray 引用数组\n   * @return array\n   */\n  private function definitionToJsonArray(array $refArray): array\n  {\n    $res = [];\n    if (!isset($refArray['properties'])) {\n      return $res;\n    }\n\n    foreach ($refArray['properties'] as $key => $value) {\n      $remark = $value['title'] ?? $value['description'] ?? '';\n      $exampleValue = $value['example'] ?? '';\n      $required = '0';\n      if (isset($refArray['required']) && is_array($refArray['required']) && in_array($key, $refArray['required'])) {\n        $required = '1';\n      }\n\n      $paramType = $value['type'] ?? 'string';\n      if ($paramType === 'int') {\n        $paramType = 'integer';\n      }\n\n      $res[] = [\n        'name'    => $key,\n        'type'    => $paramType,\n        'value'   => $exampleValue,\n        'require' => $required,\n        'remark'  => $remark,\n      ];\n    }\n\n    return $res;\n  }\n\n  /**\n   * 定义转 JSON（用于示例值）\n   *\n   * @param array $refArray 引用数组\n   * @return array\n   */\n  private function definitionToJson(array $refArray): array\n  {\n    $res = [];\n    if (!isset($refArray['properties'])) {\n      return $res;\n    }\n\n    foreach ($refArray['properties'] as $key => $value) {\n      $paramType = $value['type'] ?? 'string';\n\n      if ($paramType === 'array') {\n        $items = $value['items'] ?? [];\n        if (isset($items['$ref'])) {\n          $refItems = $this->getDefinition($items['$ref']);\n          if ($refItems) {\n            $res[$key] = [$this->definitionToJson($refItems)];\n          } else {\n            $res[$key] = [];\n          }\n        } elseif (isset($items['type'])) {\n          $res[$key] = [$this->getDefaultValue($items['type'])];\n        } else {\n          $res[$key] = [];\n        }\n      } elseif ($paramType === 'object') {\n        $res[$key] = $this->definitionToJson($value);\n      } else {\n        $res[$key] = $value['example'] ?? $this->getDefaultValue($paramType);\n      }\n    }\n\n    return $res;\n  }\n\n  /**\n   * Schema 转 JSON\n   *\n   * @param array $schema Schema\n   * @return mixed\n   */\n  private function schemaToJson(array $schema)\n  {\n    $type = $schema['type'] ?? 'object';\n\n    if ($type === 'array') {\n      $items = $schema['items'] ?? [];\n      if (isset($items['$ref'])) {\n        $refArray = $this->getDefinition($items['$ref']);\n        if ($refArray) {\n          return [$this->definitionToJson($refArray)];\n        }\n      } elseif (isset($items['type'])) {\n        return [$this->schemaToJson($items)];\n      }\n      return [];\n    } elseif ($type === 'object') {\n      $properties = $schema['properties'] ?? [];\n      $res = [];\n      foreach ($properties as $key => $value) {\n        $res[$key] = $this->schemaToJson($value);\n      }\n      return $res;\n    } else {\n      return $schema['example'] ?? $this->getDefaultValue($type);\n    }\n  }\n\n  /**\n   * 获取类型默认值\n   *\n   * @param string $type 类型\n   * @return mixed\n   */\n  private function getDefaultValue(string $type)\n  {\n    switch ($type) {\n      case 'string':\n        return '';\n      case 'integer':\n      case 'number':\n        return 0;\n      case 'boolean':\n        return false;\n      case 'array':\n        return [];\n      case 'object':\n        return new \\stdClass();\n      default:\n        return '';\n    }\n  }\n}\n"
  },
  {
    "path": "server/app/Mcp/Handler/PageHandler.php",
    "content": "<?php\n\nnamespace App\\Mcp\\Handler;\n\nuse App\\Mcp\\McpHandler;\nuse App\\Mcp\\McpError;\nuse App\\Mcp\\McpException;\nuse App\\Model\\Page;\nuse App\\Model\\PageHistory;\nuse App\\Model\\Catalog;\nuse App\\Model\\Item;\nuse App\\Common\\Helper\\Convert;\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\n/**\n * MCP 页面操作 Handler（开源版）\n *\n * 注意：开源版使用单表 page，不支持分表。\n * 开源版不包含 BadKeywords、Vip、ItemWhitelist 等商业功能。\n */\nclass PageHandler extends McpHandler\n{\n  /**\n   * 获取支持的操列列表\n   *\n   * @return array\n   */\n  public function getSupportedOperations(): array\n  {\n    return [\n      'list_pages',\n      'get_page',\n      'batch_get_pages',\n      'search_pages',\n      'get_page_template',\n      'create_page',\n      'create_page_by_comment',\n      'update_page',\n      'upsert_page',\n      'batch_upsert_pages',\n      'delete_page',\n      // 页面历史相关\n      'get_page_history',\n      'get_page_version',\n      'diff_page_versions',\n      'restore_page_version',\n    ];\n  }\n\n  /**\n   * 执行操作\n   *\n   * @param string $operation 操作名称\n   * @param array $params 参数\n   * @return mixed\n   * @throws McpException\n   */\n  public function execute(string $operation, array $params = [])\n  {\n    switch ($operation) {\n      case 'list_pages':\n        return $this->listPages($params);\n\n      case 'get_page':\n        return $this->getPage($params);\n\n      case 'batch_get_pages':\n        return $this->batchGetPages($params);\n\n      case 'search_pages':\n        return $this->searchPages($params);\n\n      case 'get_page_template':\n        return $this->getPageTemplate($params);\n\n      case 'create_page':\n        return $this->createPage($params);\n\n      case 'create_page_by_comment':\n        return $this->createPageByComment($params);\n\n      case 'update_page':\n        return $this->updatePage($params);\n\n      case 'upsert_page':\n        return $this->upsertPage($params);\n\n      case 'batch_upsert_pages':\n        return $this->batchUpsertPages($params);\n\n      case 'delete_page':\n        return $this->deletePage($params);\n\n      case 'get_page_history':\n        return $this->getPageHistory($params);\n\n      case 'get_page_version':\n        return $this->getPageVersion($params);\n\n      case 'diff_page_versions':\n        return $this->diffPageVersions($params);\n\n      case 'restore_page_version':\n        return $this->restorePageVersion($params);\n\n      default:\n        McpError::throw(McpError::METHOD_NOT_FOUND, \"操作不存在: {$operation}\");\n    }\n  }\n\n  /**\n   * 获取项目/目录下的页面列表（分页，不含内容）\n   *\n   * @param array $params 参数\n   * @return array\n   * @throws McpException\n   */\n  private function listPages(array $params): array\n  {\n    $itemId = (int) ($params['item_id'] ?? 0);\n    if ($itemId <= 0) {\n      McpError::throw(McpError::INVALID_PARAMS, '项目ID不能为空');\n    }\n\n    // 检查读取权限\n    $this->requireReadPermission($itemId);\n\n    $catId = (int) ($params['cat_id'] ?? 0);\n    $page = max(1, (int) ($params['page'] ?? 1));\n    $pageSize = min(100, max(1, (int) ($params['page_size'] ?? 50)));\n\n    // 开源版：使用单表 page，不使用分表\n    $query = DB::table('page')\n      ->where('item_id', $itemId)\n      ->where('is_del', 0);\n\n    if ($catId > 0) {\n      $query->where('cat_id', $catId);\n    }\n\n    // 获取总数\n    $total = $query->count();\n\n    // 分页获取\n    $pages = $query->orderBy('s_number', 'asc')\n      ->orderBy('page_id', 'asc')\n      ->offset(($page - 1) * $pageSize)\n      ->limit($pageSize)\n      ->get(['page_id', 'page_title', 'item_id', 'cat_id', 's_number', 'addtime', 'author_uid', 'author_username'])\n      ->all();\n\n    $result = [];\n    foreach ($pages as $p) {\n      $result[] = [\n        'page_id' => (int) $p->page_id,\n        'page_title' => $p->page_title,\n        'item_id' => (int) $p->item_id,\n        'cat_id' => (int) ($p->cat_id ?? 0),\n        's_number' => (int) ($p->s_number ?? 0),\n        'addtime' => $p->addtime ?? '',\n        'author_uid' => (int) ($p->author_uid ?? 0),\n        'author_username' => $p->author_username ?? '',\n      ];\n    }\n\n    return [\n      'item_id' => $itemId,\n      'cat_id' => $catId,\n      'pages' => $result,\n      'total' => $total,\n      'page' => $page,\n      'page_size' => $pageSize,\n    ];\n  }\n\n  /**\n   * 获取页面详情\n   *\n   * @param array $params 参数\n   * @return array\n   * @throws McpException\n   */\n  private function getPage(array $params): array\n  {\n    $pageId = (int) ($params['page_id'] ?? 0);\n    $itemId = (int) ($params['item_id'] ?? 0);\n    $pageTitle = trim($params['page_title'] ?? '');\n\n    // 支持通过 page_id 或 item_id + page_title 获取\n    if ($pageId <= 0 && ($itemId <= 0 || $pageTitle === '')) {\n      McpError::throw(McpError::INVALID_PARAMS, '请提供 page_id 或 item_id + page_title');\n    }\n\n    // 如果是通过标题查找（开源版：使用单表 page）\n    if ($pageId <= 0 && $itemId > 0 && $pageTitle !== '') {\n      $pageRow = DB::table('page')\n        ->where('item_id', $itemId)\n        ->where('page_title', $pageTitle)\n        ->where('is_del', 0)\n        ->first();\n      if (!$pageRow) {\n        McpError::throw(McpError::RESOURCE_NOT_FOUND, '页面不存在');\n      }\n      $pageId = (int) $pageRow->page_id;\n    }\n\n    // 先从 page 表获取 item_id（与原后端 PageController::info 一致）\n    $pageRow = DB::table('page')\n      ->where('page_id', $pageId)\n      ->first();\n    if (!$pageRow) {\n      McpError::throw(McpError::RESOURCE_NOT_FOUND, '页面不存在');\n    }\n    $itemId = (int) $pageRow->item_id;\n\n    // 使用 Page::findPageByCache 获取页面（带缓存，自动处理分表和解压）\n    $page = Page::findPageByCache($pageId, $itemId);\n    if (!$page || (int) ($page['is_del'] ?? 0) === 1) {\n      McpError::throw(McpError::RESOURCE_NOT_FOUND, '页面不存在');\n    }\n\n    // 检查草稿状态（与原后端 PageController::info 一致）\n    if (($page['is_draft'] ?? 0) == 1) {\n      $authorUid = (int) ($page['author_uid'] ?? 0);\n      $currentUid = (int) ($this->user['uid'] ?? 0);\n      if ($currentUid <= 0 || $currentUid !== $authorUid) {\n        McpError::throw(McpError::RESOURCE_NOT_FOUND, '该页面是草稿状态，暂不可访问');\n      }\n    }\n\n    // 检查读取权限\n    $this->requireReadPermission($itemId);\n\n    // 获取项目类型\n    $item = DB::table('item')\n      ->where('item_id', $itemId)\n      ->first();\n    $itemType = (int) ($item->item_type ?? 1);\n\n    // 处理内容（Page::findPageByCache 已自动解压）\n    $content = $page['page_content'] ?? '';\n    $pageType = 'markdown';\n\n    // 如果是 RunApi 项目，转换为 Markdown\n    if ($itemType === 3) {\n      $pageType = 'runapi';\n      $convert = new Convert();\n      $content = $convert->runapiToMd($content);\n    }\n\n    // 计算内容哈希（用于乐观锁）\n    $contentHash = substr(md5($content), 0, 12);\n\n    // 对内容进行 HTML 解转义（MCP 场景下 AI 需要原始内容）\n    $content = htmlspecialchars_decode($content, ENT_QUOTES);\n\n    // 格式化 addtime（与原后端 PageController::info 一致）\n    $addtime = date('Y-m-d H:i:s', (int) ($page['addtime'] ?? time()));\n\n    // 附件数量（与原后端 PageController::info 一致）\n    $attachmentCount = \\App\\Model\\FilePage::getAttachmentCount($pageId);\n\n    return [\n      'page_id' => (int) $page['page_id'],\n      'page_title' => $page['page_title'],\n      'item_id' => $itemId,\n      'cat_id' => (int) ($page['cat_id'] ?? 0),\n      'type' => $pageType,\n      'content' => $content,\n      'content_hash' => $contentHash,\n      's_number' => (int) ($page['s_number'] ?? 0),\n      'addtime' => $addtime,\n      'author_uid' => (int) ($page['author_uid'] ?? 0),\n      'author_username' => $page['author_username'] ?? '',\n      'attachment_count' => $attachmentCount,\n    ];\n  }\n\n  /**\n   * 批量获取页面详情（最多10个）\n   *\n   * @param array $params 参数\n   * @return array\n   * @throws McpException\n   */\n  private function batchGetPages(array $params): array\n  {\n    $pageIds = $params['page_ids'] ?? [];\n    if (!is_array($pageIds) || empty($pageIds)) {\n      McpError::throw(McpError::INVALID_PARAMS, 'page_ids 必须是非空数组');\n    }\n\n    // 限制最多10个\n    $pageIds = array_slice(array_map('intval', $pageIds), 0, 10);\n\n    $result = [];\n    foreach ($pageIds as $pageId) {\n      try {\n        $pageData = $this->getPage(['page_id' => $pageId]);\n        $result[] = [\n          'status' => 'success',\n          'page_id' => $pageId,\n          'data' => $pageData,\n        ];\n      } catch (McpException $e) {\n        $result[] = [\n          'status' => 'failed',\n          'page_id' => $pageId,\n          'error' => $e->getMessage(),\n        ];\n      }\n    }\n\n    return [\n      'pages' => $result,\n      'total' => count($result),\n    ];\n  }\n\n  /**\n   * 搜索页面\n   *\n   * @param array $params 参数\n   *   - query: 搜索关键字（必填）\n   *   - item_id: 项目ID（可选，不传则搜索所有有权限的项目）\n   *   - search_mode: 搜索模式（可选，默认 title）\n   *     - title: 只搜索标题（数据库 LIKE，速度快）\n   *     - content: 只搜索内容（需解压后 PHP 层面搜索，速度慢）\n   *     - all: 搜索标题和内容（需解压后 PHP 层面搜索，速度慢）\n   * @return array\n   * @throws McpException\n   */\n  private function searchPages(array $params): array\n  {\n    $query = trim($params['query'] ?? '');\n    if ($query === '') {\n      McpError::throw(McpError::INVALID_PARAMS, '搜索关键字不能为空');\n    }\n\n    $itemId = (int) ($params['item_id'] ?? 0);\n    // 搜索模式：title（默认，只搜索标题）、content（只搜索内容）、all（搜索标题和内容）\n    $searchMode = $params['search_mode'] ?? 'title';\n    if (!in_array($searchMode, ['title', 'content', 'all'], true)) {\n      $searchMode = 'title';\n    }\n\n    $result = [];\n    $maxResults = 50;\n    $queryLower = strtolower($query);\n\n    // 如果指定了项目ID，只搜索该项目的分表\n    if ($itemId > 0) {\n      // 检查读取权限\n      $this->requireReadPermission($itemId);\n\n      $result = $this->searchInItem($itemId, $query, $queryLower, $searchMode, $maxResults);\n    } else {\n      // 没有指定项目ID，遍历用户有权限的所有项目\n      $uid = $this->getUid();\n      $itemIds = $this->getUserItemIds($uid);\n\n      foreach ($itemIds as $itemId) {\n        if (count($result) >= $maxResults) {\n          break;\n        }\n\n        $remaining = $maxResults - count($result);\n        $found = $this->searchInItem($itemId, $query, $queryLower, $searchMode, $remaining);\n        $result = array_merge($result, $found);\n      }\n    }\n\n    return [\n      'query' => $query,\n      'item_id' => $itemId,\n      'search_mode' => $searchMode,\n      'pages' => $result,\n      'total' => count($result),\n    ];\n  }\n\n  /**\n   * 在单个项目中搜索页面\n   *\n   * @param int $itemId 项目ID\n   * @param string $query 原始搜索关键字\n   * @param string $queryLower 小写搜索关键字\n   * @param string $searchMode 搜索模式\n   * @param int $limit 最大返回数量\n   * @return array\n   */\n  private function searchInItem(int $itemId, string $query, string $queryLower, string $searchMode, int $limit): array\n  {\n    $result = [];\n    $tableName = Page::tableForItem($itemId);\n\n    // 标题搜索模式：直接数据库 LIKE 搜索（速度快）\n    if ($searchMode === 'title') {\n      $pages = DB::table($tableName)\n        ->where('item_id', $itemId)\n        ->where('is_del', 0)\n        ->where('page_title', 'like', \"%{$query}%\")\n        ->limit($limit)\n        ->get(['page_id', 'page_title', 'item_id', 'cat_id', 'addtime'])\n        ->all();\n\n      foreach ($pages as $p) {\n        $result[] = [\n          'page_id' => (int) $p->page_id,\n          'page_title' => $p->page_title,\n          'item_id' => (int) $p->item_id,\n          'cat_id' => (int) ($p->cat_id ?? 0),\n          'addtime' => $p->addtime ?? '',\n        ];\n      }\n\n      // 释放内存\n      unset($pages);\n      return $result;\n    }\n\n    // 内容搜索模式：需要加载到 PHP 内存解压后搜索（速度慢）\n    // 先获取所有页面（只获取必要字段）\n    $pages = DB::table($tableName)\n      ->where('item_id', $itemId)\n      ->where('is_del', 0)\n      ->get(['page_id', 'page_title', 'page_content', 'item_id', 'cat_id', 'addtime'])\n      ->all();\n\n    foreach ($pages as $p) {\n      if (count($result) >= $limit) {\n        break;\n      }\n\n      $pageTitle = strtolower((string) ($p->page_title ?? ''));\n      $pageContent = (string) ($p->page_content ?? '');\n\n      // 解压内容\n      $decoded = \\App\\Common\\Helper\\ContentCodec::decompress($pageContent);\n      if ($decoded !== '') {\n        $pageContent = $decoded;\n      }\n      $pageContentLower = strtolower($pageContent);\n\n      // 根据搜索模式匹配\n      $matched = false;\n      if ($searchMode === 'content') {\n        // 只搜索内容\n        $matched = strpos($pageContentLower, $queryLower) !== false;\n      } elseif ($searchMode === 'all') {\n        // 搜索标题和内容\n        $matched = strpos($pageTitle, $queryLower) !== false || strpos($pageContentLower, $queryLower) !== false;\n      }\n\n      if ($matched) {\n        $result[] = [\n          'page_id' => (int) $p->page_id,\n          'page_title' => $p->page_title,\n          'item_id' => (int) $p->item_id,\n          'cat_id' => (int) ($p->cat_id ?? 0),\n          'addtime' => $p->addtime ?? '',\n        ];\n      }\n\n      // 释放当前页面内容的内存（特别是解压后的大内容）\n      unset($pageContent, $pageContentLower, $decoded);\n    }\n\n    // 释放内存\n    unset($pages);\n\n    return $result;\n  }\n\n  /**\n   * 获取用户有权限的项目ID列表\n   *\n   * @param int $uid 用户ID\n   * @return array\n   */\n  private function getUserItemIds(int $uid): array\n  {\n    $itemIds = [];\n\n    // 用户创建的项目\n    $createdItems = DB::table('item')\n      ->where('uid', $uid)\n      ->where('is_del', 0)\n      ->pluck('item_id')\n      ->all();\n    $itemIds = array_merge($itemIds, $createdItems);\n\n    // 用户作为成员的项目\n    $memberItems = DB::table('item_member')\n      ->where('uid', $uid)\n      ->pluck('item_id')\n      ->all();\n    $itemIds = array_merge($itemIds, $memberItems);\n\n    // 用户所在团队的项目\n    $teamItems = DB::table('team_item_member')\n      ->where('member_uid', $uid)\n      ->pluck('item_id')\n      ->all();\n    $itemIds = array_merge($itemIds, $teamItems);\n\n    // 根据 Token scope 过滤\n    $scope = $this->tokenInfo['scope'] ?? 'all';\n    if ($scope === 'selected') {\n      $allowedItems = json_decode($this->tokenInfo['allowed_items'] ?? '[]', true) ?: [];\n      $itemIds = array_intersect($itemIds, $allowedItems);\n    }\n\n    return array_unique(array_map('intval', $itemIds));\n  }\n\n  /**\n   * 获取文档模板\n   *\n   * @param array $params 参数\n   * @return array\n   */\n  private function getPageTemplate(array $params): array\n  {\n    $type = $params['type'] ?? 'api';\n\n    $templates = [\n      'api' => $this->getApiTemplate(),\n      'runapi_comment' => $this->getRunapiCommentTemplate(),\n      'database' => $this->getDatabaseTemplate(),\n      'general' => $this->getGeneralTemplate(),\n    ];\n\n    $template = $templates[$type] ?? $templates['api'];\n\n    return [\n      'type' => $type,\n      'template' => $template,\n    ];\n  }\n\n  /**\n   * API 文档模板\n   *\n   * @return string\n   */\n  private function getApiTemplate(): string\n  {\n    return <<<'MARKDOWN'\n# 接口名称\n\n**简要描述**：接口功能的简要说明\n\n#### 基本信息\n\n- **请求方式**：POST\n- **请求路径**：/api/xxx\n- **接口描述**：详细的接口功能描述\n\n#### 请求头\n\n| 参数名 | 必填 | 类型 | 说明 |\n| ------ | ---- | ---- | ---- |\n| Authorization | 是 | string | 认证令牌，格式：Bearer xxx |\n| Content-Type | 是 | string | application/json |\n\n#### 请求参数\n\n##### Query 参数（URL 参数）\n\n| 参数名 | 必填 | 类型 | 说明 |\n| ------ | ---- | ---- | ---- |\n| page | 否 | int | 页码，默认 1 |\n| pageSize | 否 | int | 每页数量，默认 20 |\n\n##### Body 参数（请求体）\n\n| 参数名 | 必填 | 类型 | 说明 |\n| ------ | ---- | ---- | ---- |\n| field1 | 是 | string | 字段1说明 |\n| field2 | 否 | int | 字段2说明 |\n| field3 | 否 | array | 字段3说明，数组类型 |\n\n#### 返回参数\n\n| 参数名 | 类型 | 说明 |\n| ------ | ---- | ---- |\n| code | int | 状态码，0 表示成功，非 0 表示失败 |\n| msg | string | 提示信息 |\n| data | object | 返回数据 |\n| data.list | array | 数据列表 |\n| data.total | int | 总数量 |\n| data.page | int | 当前页码 |\n\n#### 返回示例\n\n##### 成功响应\n\n```json\n{\n  \"code\": 0,\n  \"msg\": \"success\",\n  \"data\": {\n    \"list\": [],\n    \"total\": 100,\n    \"page\": 1\n  }\n}\n```\n\n##### 失败响应\n\n```json\n{\n  \"code\": 10001,\n  \"msg\": \"参数错误\",\n  \"data\": null\n}\n```\n\n#### 错误码说明\n\n| 错误码 | 说明 |\n| ------ | ---- |\n| 0 | 成功 |\n| 10001 | 参数错误 |\n| 10002 | 未授权 |\n| 10003 | 资源不存在 |\n\n#### 备注\n\n- 其他需要说明的内容\n- 特殊情况处理说明\nMARKDOWN;\n  }\n\n  /**\n   * RunApi 注释模板\n   *\n   * @return string\n   */\n  private function getRunapiCommentTemplate(): string\n  {\n    return <<<'COMMENT'\n/**\n * showdoc\n * @title 接口名称\n * @description 接口的详细功能描述，说明这个接口做什么\n * @method POST\n * @url /api/path/to/endpoint\n * @catalog 目录名称/子目录名称\n *\n * @param page int 否选 页码，默认1\n * @param page_size int 否选 每页数量，默认20，最大100\n * @param keyword string 否选 搜索关键词\n * @param id int 是选 数据ID\n *\n * @header Authorization string 是选 认证令牌，格式：Bearer xxx\n * @header Content-Type string 是选 固定值：application/json\n * @header X-Request-Id string 否选 请求追踪ID\n *\n * @json_param name string 是选 用户名\n * @json_param email string 是选 邮箱地址\n * @json_param age int 否选 用户年龄\n * @json_param tags array 否选 标签列表\n *\n * @return {\"code\":0,\"msg\":\"success\",\"data\":{\"id\":1,\"name\":\"示例\",\"created_at\":\"2024-01-01 00:00:00\"}}\n * @return_param code int 状态码，0表示成功，非0表示失败\n * @return_param msg string 提示信息\n * @return_param data object 返回数据对象\n * @return_param data.id int 数据ID\n * @return_param data.name string 数据名称\n * @return_param data.created_at string 创建时间\n *\n * @remark 这是一个POST请求示例，使用JSON格式传参。\n * @remark 必选字段不能为空，否则返回参数错误。\n * @remark 认证令牌需要先调用登录接口获取。\n * @number 1\n */\nCOMMENT;\n  }\n\n  /**\n   * 数据字典模板\n   *\n   * @return string\n   */\n  private function getDatabaseTemplate(): string\n  {\n    return <<<'MARKDOWN'\n# 表名：user\n\n**表说明**：用户信息表，存储用户基本信息\n\n#### 字段列表\n\n| 字段名 | 类型 | 长度 | 默认值 | 是否为空 | 说明 |\n| ------ | ---- | ---- | ------ | -------- | ---- |\n| id | int | 11 | - | 否 | 主键ID，自增 |\n| username | varchar | 64 | - | 否 | 用户名，唯一 |\n| email | varchar | 128 | NULL | 是 | 邮箱地址 |\n| password | varchar | 255 | - | 否 | 密码（加密存储） |\n| phone | varchar | 20 | NULL | 是 | 手机号码 |\n| avatar | varchar | 255 | NULL | 是 | 头像URL |\n| status | tinyint | 1 | 1 | 否 | 状态：0=禁用，1=启用 |\n| vip_type | tinyint | 1 | 0 | 否 | VIP类型：0=免费，1=基础，2=高级，3=企业 |\n| last_login_time | datetime | - | NULL | 是 | 最后登录时间 |\n| created_at | datetime | - | CURRENT_TIMESTAMP | 否 | 创建时间 |\n| updated_at | datetime | - | CURRENT_TIMESTAMP | 否 | 更新时间 |\n| deleted_at | datetime | - | NULL | 是 | 软删除时间 |\n\n#### 索引\n\n| 索引名 | 字段 | 类型 | 说明 |\n| ------ | ---- | ---- | ---- |\n| PRIMARY | id | 主键 | 主键索引 |\n| uk_username | username | 唯一索引 | 用户名唯一 |\n| idx_email | email | 普通索引 | 邮箱查询优化 |\n| idx_status | status | 普通索引 | 状态筛选优化 |\n| idx_created_at | created_at | 普通索引 | 创建时间查询优化 |\n\n#### 关联关系\n\n| 关联表 | 关联字段 | 关系类型 | 说明 |\n| ------ | -------- | -------- | ---- |\n| order | user_id | 一对多 | 一个用户可以有多个订单 |\n| item | uid | 一对多 | 一个用户可以创建多个项目 |\n| team_member | uid | 多对多 | 用户可以属于多个团队 |\n\n#### 建表语句\n\n```sql\nCREATE TABLE `user` (\n  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',\n  `username` varchar(64) NOT NULL COMMENT '用户名',\n  `email` varchar(128) DEFAULT NULL COMMENT '邮箱地址',\n  `password` varchar(255) NOT NULL COMMENT '密码',\n  `phone` varchar(20) DEFAULT NULL COMMENT '手机号码',\n  `avatar` varchar(255) DEFAULT NULL COMMENT '头像URL',\n  `status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '状态',\n  `vip_type` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'VIP类型',\n  `last_login_time` datetime DEFAULT NULL COMMENT '最后登录时间',\n  `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\n  `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',\n  `deleted_at` datetime DEFAULT NULL COMMENT '软删除时间',\n  PRIMARY KEY (`id`),\n  UNIQUE KEY `uk_username` (`username`),\n  KEY `idx_email` (`email`),\n  KEY `idx_status` (`status`),\n  KEY `idx_created_at` (`created_at`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户信息表';\n```\n\n#### 备注\n\n- 密码使用 bcrypt 算法加密存储\n- 软删除字段 deleted_at 非空时表示已删除\n- VIP类型影响用户配额和功能权限\nMARKDOWN;\n  }\n\n  /**\n   * 通用文档模板\n   *\n   * @return string\n   */\n  private function getGeneralTemplate(): string\n  {\n    return <<<'MARKDOWN'\n# 文档标题\n\n**简要描述**：一句话概括文档的主要内容\n\n**更新日期**：2024-01-01\n\n---\n\n#### 一、概述\n\n在这里写文档的背景介绍、目标读者、适用范围等内容。\n\n##### 1.1 目标读者\n\n- 开发人员：了解 xxx 的实现细节\n- 运维人员：掌握 xxx 的部署配置\n- 产品经理：理解 xxx 的功能边界\n\n##### 1.2 前置条件\n\n- 已安装 xxx 环境\n- 具有 xxx 权限\n- 熟悉 xxx 基础知识\n\n---\n\n#### 二、核心概念\n\n##### 2.1 概念一\n\n概念一的详细说明...\n\n##### 2.2 概念二\n\n概念二的详细说明...\n\n| 术语 | 说明 |\n| ---- | ---- |\n| 术语1 | 术语1的解释 |\n| 术语2 | 术语2的解释 |\n\n---\n\n#### 三、使用指南\n\n##### 3.1 快速开始\n\n```bash\n# 示例命令\ncommand --option value\n```\n\n##### 3.2 配置说明\n\n| 配置项 | 类型 | 默认值 | 说明 |\n| ------ | ---- | ------ | ---- |\n| option1 | string | \"\" | 配置项1说明 |\n| option2 | int | 0 | 配置项2说明 |\n| enabled | bool | false | 是否启用 |\n\n##### 3.3 代码示例\n\n```javascript\n// JavaScript 示例\nconst config = {\n  option1: 'value',\n  option2: 100,\n  enabled: true\n};\n```\n\n```php\n// PHP 示例\n$config = [\n  'option1' => 'value',\n  'option2' => 100,\n  'enabled' => true,\n];\n```\n\n---\n\n#### 四、常见问题 FAQ\n\n##### Q1: 问题一？\n\n**A:** 答案一的详细说明...\n\n##### Q2: 问题二？\n\n**A:** 答案二的详细说明...\n\n---\n\n#### 五、注意事项\n\n- ⚠️ 注意事项1：详细说明\n- ⚠️ 注意事项2：详细说明\n- 💡 提示：有用的提示信息\n\n---\n\n#### 六、相关链接\n\n- [相关文档1](链接地址)\n- [相关文档2](链接地址)\n- [外部资源](链接地址)\n\n---\n\n#### 更新记录\n\n| 日期 | 版本 | 更新内容 | 作者 |\n| ---- | ---- | -------- | ---- |\n| 2024-01-01 | v1.0 | 初始版本 | xxx |\nMARKDOWN;\n  }\n\n  /**\n   * 创建页面\n   *\n   * @param array $params 参数\n   * @return array\n   * @throws McpException\n   */\n  private function createPage(array $params): array\n  {\n    $itemId = (int) ($params['item_id'] ?? 0);\n    if ($itemId <= 0) {\n      McpError::throw(McpError::INVALID_PARAMS, '项目ID不能为空');\n    }\n\n    $pageTitle = trim($params['page_title'] ?? '');\n    if ($pageTitle === '') {\n      McpError::throw(McpError::INVALID_PARAMS, '页面标题不能为空');\n    }\n\n    $pageContent = $params['page_content'] ?? '';\n    $catName = trim($params['cat_name'] ?? '');\n    $sNumber = (int) ($params['s_number'] ?? 99);\n\n    // 检查写入权限\n    $this->requireWritePermission($itemId);\n\n    // 验证内容不能为空（与 PageController::save 一致）\n    if (empty($pageContent)) {\n      McpError::throw(McpError::INVALID_PARAMS, '不允许保存空内容，请随便写点什么');\n    }\n\n    // 检查页面内容大小限制（防止超大内容导致数据库问题）\n    $maxContentSize = 50 * 1024 * 1024; // 50MB\n    if (strlen($pageContent) > $maxContentSize) {\n      $maxMB = round($maxContentSize / 1024 / 1024, 1);\n      McpError::throw(McpError::OPERATION_FAILED, \"页面内容大小超出限制（{$maxMB}MB），请精简内容或拆分为多个页面\");\n    }\n\n    // HTML 转义（与 PageController::save 一致）\n    $pageContent = htmlspecialchars($pageContent, ENT_QUOTES, 'UTF-8');\n\n    // 获取项目信息\n    $item = Item::findById($itemId);\n    if (!$item) {\n      McpError::throw(McpError::RESOURCE_NOT_FOUND, '项目不存在');\n    }\n\n    $uid = $this->getUid();\n\n    // 获取分表名称\n    $tableName = Page::tableForItem($itemId);\n\n    // 检查单项目页面数量上限（防止死循环导致数据库写满）\n    $maxPagesPerItem = 50000; // 单项目最多 50000 个页面\n    $currentPageCount = DB::table($tableName)\n      ->where('item_id', $itemId)\n      ->where('is_del', 0)\n      ->count();\n    if ($currentPageCount >= $maxPagesPerItem) {\n      McpError::throw(\n        McpError::OPERATION_FAILED,\n        \"该项目已达到页面数量上限（{$maxPagesPerItem}个），无法继续创建。如有特殊需求，请联系网站管理员\"\n      );\n    }\n\n    // 检查页面是否已存在\n    $existingPage = DB::table($tableName)\n      ->where('item_id', $itemId)\n      ->where('page_title', $pageTitle)\n      ->where('is_del', 0)\n      ->first();\n    if ($existingPage) {\n      McpError::throw(McpError::OPERATION_FAILED, \"页面标题已存在: {$pageTitle}\");\n    }\n\n    // 处理目录\n    $catId = 0;\n    if ($catName !== '') {\n      $catId = $this->getOrCreateCatalog($itemId, $catName);\n    }\n\n    try {\n      $now = time();\n      $data = [\n        'page_title' => $pageTitle,\n        'page_content' => $pageContent,\n        'item_id' => $itemId,\n        'cat_id' => $catId,\n        's_number' => $sNumber,\n        'addtime' => $now,\n        'author_uid' => $this->getUid(),\n        'author_username' => $this->getUsername(),\n      ];\n\n      // 复用 Page::addPage 方法，确保与原后端逻辑一致\n      // 包括：在 page 主表插入记录、内容压缩、分表插入等\n      $pageId = Page::addPage($itemId, $data);\n\n      if ($pageId <= 0) {\n        McpError::throw(McpError::OPERATION_FAILED, '创建页面失败');\n      }\n\n      // 更新项目最后更新时间\n      DB::table('item')\n        ->where('item_id', $itemId)\n        ->update(['last_update_time' => $now]);\n\n      // 删除菜单缓存（与 PageController::save 一致）\n      Item::deleteCache($itemId);\n\n      // 暂停 800 毫秒，以便应对主从数据库同步延迟（与 PageController::save 一致）\n      usleep(800000);\n\n      return [\n        'page_id' => $pageId,\n        'page_title' => $pageTitle,\n        'item_id' => $itemId,\n        'cat_id' => $catId,\n        'message' => '页面创建成功',\n      ];\n    } catch (\\Throwable $e) {\n      McpError::throw(McpError::OPERATION_FAILED, '页面创建失败: ' . $e->getMessage());\n    }\n  }\n\n  /**\n   * 通过代码注释创建 RunApi 格式页面\n   *\n   * @param array $params 参数\n   * @return array\n   * @throws McpException\n   */\n  private function createPageByComment(array $params): array\n  {\n    $itemId = (int) ($params['item_id'] ?? 0);\n    if ($itemId <= 0) {\n      McpError::throw(McpError::INVALID_PARAMS, '项目ID不能为空');\n    }\n\n    $commentContent = trim($params['comment_content'] ?? '');\n    if ($commentContent === '') {\n      McpError::throw(McpError::INVALID_PARAMS, '注释内容不能为空');\n    }\n\n    // 检查写入权限\n    $this->requireWritePermission($itemId);\n\n    // 解析注释内容\n    $parsedData = $this->parseShowdocComment($commentContent);\n    if (empty($parsedData['title'])) {\n      McpError::throw(McpError::INVALID_PARAMS, '注释格式错误：缺少 @title 标签');\n    }\n\n    $pageTitle = $parsedData['title'];\n    $catName = $parsedData['catalog'] ?? '';\n    $sNumber = (int) ($parsedData['number'] ?? 99);\n\n    // 处理目录\n    $catId = 0;\n    if ($catName !== '') {\n      $catId = $this->getOrCreateCatalog($itemId, $catName);\n    }\n\n    // 获取项目类型\n    $item = DB::table('item')\n      ->where('item_id', $itemId)\n      ->first();\n    $itemType = (int) ($item->item_type ?? 1);\n\n    // 构建 RunApi JSON 格式\n    $runapiContent = $this->buildRunapiContent($parsedData);\n\n    // 如果是普通文档项目，转换为 Markdown\n    if ($itemType !== 3) {\n      $convert = new Convert();\n      $pageContent = $convert->runapiToMd($runapiContent);\n    } else {\n      $pageContent = $runapiContent;\n    }\n\n    // 获取分表名称\n    $tableName = Page::tableForItem($itemId);\n\n    // 检查页面是否已存在\n    $existingPage = DB::table($tableName)\n      ->where('item_id', $itemId)\n      ->where('page_title', $pageTitle)\n      ->where('is_del', 0)\n      ->first();\n\n    try {\n      $now = time();\n      $data = [\n        'page_title' => $pageTitle,\n        'page_content' => $pageContent,\n        'item_id' => $itemId,\n        'cat_id' => $catId,\n        's_number' => $sNumber,\n        'addtime' => $now,\n        'author_uid' => $this->getUid(),\n        'author_username' => $this->getUsername(),\n      ];\n\n      if ($existingPage) {\n        // 更新已存在的页面，复用 Page::savePage 确保内容压缩\n        $pageId = (int) $existingPage->page_id;\n        $ret = Page::savePage($pageId, $itemId, $data);\n        if (!$ret) {\n          McpError::throw(McpError::OPERATION_FAILED, '页面更新失败');\n        }\n        $message = '页面更新成功';\n      } else {\n        // 创建新页面，复用 Page::addPage 确保在 page 主表插入记录和内容压缩\n        $pageId = Page::addPage($itemId, $data);\n        if ($pageId <= 0) {\n          McpError::throw(McpError::OPERATION_FAILED, '页面创建失败');\n        }\n        $message = '页面创建成功';\n      }\n\n      // 更新项目最后更新时间\n      DB::table('item')\n        ->where('item_id', $itemId)\n        ->update(['last_update_time' => $now]);\n\n      // 删除菜单缓存\n      Item::deleteCache($itemId);\n\n      return [\n        'page_id' => $pageId,\n        'page_title' => $pageTitle,\n        'item_id' => $itemId,\n        'cat_id' => $catId,\n        'message' => $message,\n      ];\n    } catch (\\Throwable $e) {\n      McpError::throw(McpError::OPERATION_FAILED, '页面创建失败: ' . $e->getMessage());\n    }\n  }\n\n  /**\n   * 解析 showdoc 注释\n   *\n   * @param string $content 注释内容\n   * @return array\n   */\n  private function parseShowdocComment(string $content): array\n  {\n    $data = [];\n\n    // 检查是否包含 showdoc 标记\n    if (strpos($content, 'showdoc') === false) {\n      return $data;\n    }\n\n    // 解析各个标签\n    $patterns = [\n      'title' => '/@title\\s+(.+)/i',\n      'description' => '/@description\\s+(.+)/i',\n      'method' => '/@method\\s+(.+)/i',\n      'url' => '/@url\\s+(.+)/i',\n      'catalog' => '/@catalog\\s+(.+)/i',\n      'remark' => '/@remark\\s+(.+)/i',\n      'number' => '/@number\\s+(.+)/i',\n    ];\n\n    foreach ($patterns as $key => $pattern) {\n      if (preg_match($pattern, $content, $matches)) {\n        $data[$key] = trim($matches[1]);\n      }\n    }\n\n    // 解析 @param 标签\n    $data['params'] = [];\n    if (preg_match_all('/@param\\s+(\\S+)\\s+(\\S+)\\s+(\\S+)\\s+(.+)/i', $content, $matches, PREG_SET_ORDER)) {\n      foreach ($matches as $match) {\n        $data['params'][] = [\n          'name' => $match[1],\n          'type' => $match[2],\n          'required' => $match[3],\n          'description' => $match[4],\n        ];\n      }\n    }\n\n    // 解析 @header 标签\n    $data['headers'] = [];\n    if (preg_match_all('/@header\\s+(\\S+)\\s+(\\S+)\\s+(\\S+)\\s+(.+)/i', $content, $matches, PREG_SET_ORDER)) {\n      foreach ($matches as $match) {\n        $data['headers'][] = [\n          'name' => $match[1],\n          'type' => $match[2],\n          'required' => $match[3],\n          'description' => $match[4],\n        ];\n      }\n    }\n\n    // 解析 @return 标签（返回示例）\n    if (preg_match('/@return\\s+(.+)/i', $content, $matches)) {\n      $data['return_example'] = $matches[1];\n    }\n\n    // 解析 @return_param 标签\n    $data['return_params'] = [];\n    if (preg_match_all('/@return_param\\s+(\\S+)\\s+(\\S+)\\s+(.+)/i', $content, $matches, PREG_SET_ORDER)) {\n      foreach ($matches as $match) {\n        $data['return_params'][] = [\n          'name' => $match[1],\n          'type' => $match[2],\n          'description' => $match[3],\n        ];\n      }\n    }\n\n    return $data;\n  }\n\n  /**\n   * 构建 RunApi JSON 内容\n   *\n   * @param array $parsedData 解析后的数据\n   * @return string\n   */\n  private function buildRunapiContent(array $parsedData): string\n  {\n    $runapiData = [\n      'info' => [\n        'url' => $parsedData['url'] ?? '',\n        'method' => strtoupper($parsedData['method'] ?? 'GET'),\n        'name' => $parsedData['title'] ?? '',\n        'description' => $parsedData['description'] ?? '',\n        'remark' => $parsedData['remark'] ?? '',\n      ],\n      'request' => [\n        'params' => [],\n        'headers' => [],\n        'body' => [],\n      ],\n      'response' => [\n        'example' => $parsedData['return_example'] ?? '',\n        'params' => [],\n      ],\n    ];\n\n    // 请求参数\n    foreach ($parsedData['params'] ?? [] as $param) {\n      $runapiData['request']['params'][] = [\n        'name' => $param['name'],\n        'type' => $param['type'],\n        'required' => $param['required'] === '必选' ? 1 : 0,\n        'description' => $param['description'],\n      ];\n    }\n\n    // 请求头\n    foreach ($parsedData['headers'] ?? [] as $header) {\n      $runapiData['request']['headers'][] = [\n        'name' => $header['name'],\n        'type' => $header['type'],\n        'required' => $header['required'] === '必选' ? 1 : 0,\n        'description' => $header['description'],\n      ];\n    }\n\n    // 返回参数\n    foreach ($parsedData['return_params'] ?? [] as $param) {\n      $runapiData['response']['params'][] = [\n        'name' => $param['name'],\n        'type' => $param['type'],\n        'description' => $param['description'],\n      ];\n    }\n\n    return json_encode($runapiData, JSON_UNESCAPED_UNICODE);\n  }\n\n  /**\n   * 更新页面\n   *\n   * @param array $params 参数\n   * @return array\n   * @throws McpException\n   */\n  private function updatePage(array $params): array\n  {\n    $pageId = (int) ($params['page_id'] ?? 0);\n    if ($pageId <= 0) {\n      McpError::throw(McpError::INVALID_PARAMS, '页面ID不能为空');\n    }\n\n    // 开源版：使用单一 page 表\n    $page = DB::table('page')\n      ->where('page_id', $pageId)\n      ->where('is_del', 0)\n      ->first();\n\n    if (!$page) {\n      McpError::throw(McpError::RESOURCE_NOT_FOUND, '页面不存在');\n    }\n\n    $itemId = (int) $page->item_id;\n\n    // 检查写入权限\n    $this->requireWritePermission($itemId);\n\n    // 准备更新数据\n    $updateData = [];\n    $pageTitle = trim($params['page_title'] ?? '');\n    $pageContent = $params['page_content'] ?? null;\n\n    if ($pageContent !== null) {\n      // 验证内容不能为空（与 PageController::save 一致）\n      if (empty($pageContent)) {\n        McpError::throw(McpError::INVALID_PARAMS, '不允许保存空内容，请随便写点什么');\n      }\n\n      // HTML 转义（与 PageController::save 一致）\n      $pageContent = htmlspecialchars($pageContent, ENT_QUOTES, 'UTF-8');\n      $updateData['page_content'] = $pageContent;\n    }\n\n    if ($pageTitle !== '') {\n      // 检查标题是否与其他页面重复\n      $existingPage = DB::table('page')\n        ->where('item_id', $itemId)\n        ->where('page_title', $pageTitle)\n        ->where('page_id', '<>', $pageId)\n        ->where('is_del', 0)\n        ->first();\n      if ($existingPage) {\n        McpError::throw(McpError::OPERATION_FAILED, \"页面标题已存在: {$pageTitle}\");\n      }\n      $updateData['page_title'] = $pageTitle;\n    }\n\n    if (empty($updateData)) {\n      McpError::throw(McpError::INVALID_PARAMS, '没有需要更新的内容');\n    }\n\n    // 获取项目信息\n    $item = Item::findById($itemId);\n    if (!$item) {\n      McpError::throw(McpError::RESOURCE_NOT_FOUND, '项目不存在');\n    }\n\n    $uid = $this->getUid();\n\n    // 乐观锁检查\n    $expectedHash = $params['expected_hash'] ?? null;\n    if ($expectedHash !== null) {\n      $currentHash = substr(md5($page->page_content ?? ''), 0, 12);\n      if ($expectedHash !== $currentHash) {\n        McpError::throw(\n          McpError::VERSION_CONFLICT,\n          '版本冲突：文档已被其他人修改',\n          [\n            'error_type' => 'version_conflict',\n            'your_hash' => $expectedHash,\n            'current_hash' => $currentHash,\n            'suggestion' => '请重新获取最新内容，合并您的修改后重新提交',\n          ]\n        );\n      }\n    }\n\n    try {\n      $now = time();\n      $updateData['addtime'] = $now;\n      $updateData['author_uid'] = $this->getUid();\n      $updateData['author_username'] = $this->getUsername();\n\n      // 保存历史版本（在更新之前保存当前页面内容）\n      $historyData = [\n        'page_id'         => $pageId,\n        'item_id'         => $itemId,\n        'cat_id'          => $page->cat_id ?? 0,\n        'page_title'      => $page->page_title ?? '',\n        'page_comments'   => $page->page_comments ?? '',\n        'page_content'    => $page->page_content ?? '',\n        's_number'        => $page->s_number ?? 0,\n        'addtime'         => $page->addtime ?? $now,\n        'author_uid'      => $page->author_uid ?? 0,\n        'author_username' => $page->author_username ?? '',\n        'ext_info'        => $page->ext_info ?? '',\n      ];\n      PageHistory::add($pageId, $historyData);\n\n      // 复用 Page::savePage 方法，确保内容压缩等逻辑与原后端一致\n      $ret = Page::savePage($pageId, $itemId, $updateData);\n      if (!$ret) {\n        McpError::throw(McpError::OPERATION_FAILED, '保存失败');\n      }\n\n      // 更新项目最后更新时间\n      DB::table('item')\n        ->where('item_id', $itemId)\n        ->update(['last_update_time' => $now]);\n\n      // 清理旧的历史版本（保留最近 20 个版本）\n      $keepCount = 20;\n      $historyCount = PageHistory::getCount($pageId);\n      if ($historyCount > $keepCount) {\n        PageHistory::deleteOldVersions($pageId, $keepCount);\n      }\n\n      // 删除缓存（与 PageController::save 一致）\n      Page::deleteCache($pageId);\n      Item::deleteCache($itemId);\n\n      // 计算新的内容哈希\n      $newContent = $updateData['page_content'] ?? $page->page_content;\n      $newHash = substr(md5($newContent), 0, 12);\n\n      return [\n        'page_id' => $pageId,\n        'content_hash' => $newHash,\n        'message' => '页面更新成功',\n      ];\n    } catch (\\Throwable $e) {\n      McpError::throw(McpError::OPERATION_FAILED, '页面更新失败: ' . $e->getMessage());\n    }\n  }\n\n  /**\n   * 按标题智能匹配：存在则更新，不存在则创建\n   *\n   * @param array $params 参数\n   * @return array\n   * @throws McpException\n   */\n  private function upsertPage(array $params): array\n  {\n    $itemId = (int) ($params['item_id'] ?? 0);\n    if ($itemId <= 0) {\n      McpError::throw(McpError::INVALID_PARAMS, '项目ID不能为空');\n    }\n\n    $pageTitle = trim($params['page_title'] ?? '');\n    if ($pageTitle === '') {\n      McpError::throw(McpError::INVALID_PARAMS, '页面标题不能为空');\n    }\n\n    $pageContent = $params['page_content'] ?? '';\n    $catName = trim($params['cat_name'] ?? '');\n    $sNumber = (int) ($params['s_number'] ?? 99);\n\n    // 检查写入权限\n    $this->requireWritePermission($itemId);\n\n    // 获取分表名称\n    $tableName = Page::tableForItem($itemId);\n\n    // 检查页面是否已存在\n    $existingPage = DB::table($tableName)\n      ->where('item_id', $itemId)\n      ->where('page_title', $pageTitle)\n      ->where('is_del', 0)\n      ->first();\n\n    if ($existingPage) {\n      // 更新已存在的页面\n      return $this->updatePage([\n        'page_id' => $existingPage->page_id,\n        'page_content' => $pageContent,\n      ]);\n    }\n\n    // 创建新页面\n    return $this->createPage($params);\n  }\n\n  /**\n   * 批量创建/更新页面（最多50个）\n   *\n   * @param array $params 参数\n   * @return array\n   * @throws McpException\n   */\n  private function batchUpsertPages(array $params): array\n  {\n    $itemId = (int) ($params['item_id'] ?? 0);\n    if ($itemId <= 0) {\n      McpError::throw(McpError::INVALID_PARAMS, '项目ID不能为空');\n    }\n\n    $pages = $params['pages'] ?? [];\n    if (!is_array($pages) || empty($pages)) {\n      McpError::throw(McpError::INVALID_PARAMS, 'pages 必须是非空数组');\n    }\n\n    // 限制最多50个\n    $pages = array_slice($pages, 0, 50);\n\n    $result = [\n      'success_count' => 0,\n      'failed_count' => 0,\n      'results' => [],\n    ];\n\n    foreach ($pages as $pageData) {\n      try {\n        $pageResult = $this->upsertPage([\n          'item_id' => $itemId,\n          'page_title' => $pageData['page_title'] ?? '',\n          'page_content' => $pageData['page_content'] ?? '',\n          'cat_name' => $pageData['cat_name'] ?? '',\n          's_number' => $pageData['s_number'] ?? 99,\n        ]);\n\n        $result['success_count']++;\n        $result['results'][] = [\n          'page_title' => $pageData['page_title'] ?? '',\n          'status' => 'success',\n          'page_id' => $pageResult['page_id'],\n        ];\n      } catch (McpException $e) {\n        $result['failed_count']++;\n        $result['results'][] = [\n          'page_title' => $pageData['page_title'] ?? '',\n          'status' => 'failed',\n          'error' => $e->getMessage(),\n        ];\n      }\n    }\n\n    return $result;\n  }\n\n  /**\n   * 删除页面（软删除）\n   *\n   * @param array $params 参数\n   * @return array\n   * @throws McpException\n   */\n  private function deletePage(array $params): array\n  {\n    $pageId = (int) ($params['page_id'] ?? 0);\n    if ($pageId <= 0) {\n      McpError::throw(McpError::INVALID_PARAMS, '页面ID不能为空');\n    }\n\n    // 开源版：使用单一 page 表，不需要分表查找\n    $page = DB::table('page')\n      ->where('page_id', $pageId)\n      ->where('is_del', 0)\n      ->first();\n\n    if (!$page) {\n      McpError::throw(McpError::RESOURCE_NOT_FOUND, '页面不存在');\n    }\n\n    $itemId = (int) $page->item_id;\n\n    // 检查写入权限\n    $this->requireWritePermission($itemId);\n\n    try {\n      // 软删除页面\n      DB::table('page')\n        ->where('page_id', $pageId)\n        ->update(['is_del' => 1]);\n\n      // 更新项目最后更新时间\n      DB::table('item')\n        ->where('item_id', $itemId)\n        ->update(['last_update_time' => time()]);\n\n      // 删除缓存\n      Page::deleteCache($pageId);\n      Item::deleteCache($itemId);\n\n      return [\n        'page_id' => $pageId,\n        'message' => '页面已删除',\n      ];\n    } catch (\\Throwable $e) {\n      McpError::throw(McpError::OPERATION_FAILED, '页面删除失败: ' . $e->getMessage());\n    }\n  }\n\n  /**\n   * 获取或创建目录\n   *\n   * @param int $itemId 项目ID\n   * @param string $catName 目录名称（支持多级，用/分隔）\n   * @return int 目录ID\n   */\n  private function getOrCreateCatalog(int $itemId, string $catName): int\n  {\n    $catNames = array_map('trim', explode('/', $catName));\n    $parentCatId = 0;\n    $catId = 0;\n\n    foreach ($catNames as $name) {\n      if ($name === '') {\n        continue;\n      }\n\n      // 查找目录\n      $catalog = DB::table('catalog')\n        ->where('item_id', $itemId)\n        ->where('cat_name', $name)\n        ->where('parent_cat_id', $parentCatId)\n        ->first();\n\n      if ($catalog) {\n        $catId = (int) $catalog->cat_id;\n      } else {\n        // 创建目录\n        $catId = DB::table('catalog')->insertGetId([\n          'item_id' => $itemId,\n          'cat_name' => $name,\n          'parent_cat_id' => $parentCatId,\n          's_number' => 99,\n          'addtime' => time(),\n        ]);\n      }\n\n      $parentCatId = $catId;\n    }\n\n    return $catId;\n  }\n\n  /**\n   * 获取当前用户名\n   *\n   * @return string\n   */\n  private function getUsername(): string\n  {\n    $uid = $this->getUid();\n    if ($uid <= 0) {\n      return '';\n    }\n\n    $user = \\App\\Model\\User::findById($uid);\n    return $user ? ($user->username ?? '') : '';\n  }\n\n  /**\n   * 获取页面修改历史列表\n   *\n   * @param array $params 参数\n   * @return array\n   * @throws McpException\n   */\n  private function getPageHistory(array $params): array\n  {\n    $pageId = (int) ($params['page_id'] ?? 0);\n    if ($pageId <= 0) {\n      McpError::throw(McpError::INVALID_PARAMS, '页面ID不能为空');\n    }\n\n    // 开源版：使用单一 page 表\n    $page = DB::table('page')\n      ->where('page_id', $pageId)\n      ->where('is_del', 0)\n      ->first();\n\n    if (!$page) {\n      McpError::throw(McpError::RESOURCE_NOT_FOUND, '页面不存在');\n    }\n\n    $itemId = (int) $page->item_id;\n\n    // 检查读取权限\n    $this->requireReadPermission($itemId);\n\n    // 获取历史版本列表\n    $limit = min(500, max(1, (int) ($params['limit'] ?? 20)));\n    $historyList = PageHistory::getList($pageId, $limit);\n\n    $history = [];\n    foreach ($historyList as $row) {\n      $history[] = [\n        'version_id' => (int) $row['page_history_id'],\n        'author' => $row['author_username'] ?? '',\n        'author_uid' => (int) ($row['author_uid'] ?? 0),\n        'updated_at' => $row['addtime'] ?? '',\n        'change_summary' => $row['page_comments'] ?? '',\n      ];\n    }\n\n    return [\n      'page_id' => $pageId,\n      'history' => $history,\n      'total' => count($history),\n    ];\n  }\n\n  /**\n   * 获取指定版本的页面内容\n   *\n   * @param array $params 参数\n   * @return array\n   * @throws McpException\n   */\n  private function getPageVersion(array $params): array\n  {\n    $pageId = (int) ($params['page_id'] ?? 0);\n    $versionId = (int) ($params['version_id'] ?? 0);\n\n    if ($pageId <= 0) {\n      McpError::throw(McpError::INVALID_PARAMS, '页面ID不能为空');\n    }\n    if ($versionId <= 0) {\n      McpError::throw(McpError::INVALID_PARAMS, '版本ID不能为空');\n    }\n\n    // 开源版：使用单一 page 表\n    $page = DB::table('page')\n      ->where('page_id', $pageId)\n      ->where('is_del', 0)\n      ->first();\n\n    if (!$page) {\n      McpError::throw(McpError::RESOURCE_NOT_FOUND, '页面不存在');\n    }\n\n    $itemId = (int) $page->item_id;\n\n    // 检查读取权限\n    $this->requireReadPermission($itemId);\n\n    // 获取历史版本\n    $historyPage = PageHistory::findById($pageId, $versionId);\n    if (!$historyPage) {\n      McpError::throw(McpError::RESOURCE_NOT_FOUND, '历史版本不存在');\n    }\n\n    // 获取项目类型\n    $item = DB::table('item')\n      ->where('item_id', $itemId)\n      ->first();\n    $itemType = (int) ($item->item_type ?? 1);\n\n    // 处理内容\n    $content = $historyPage['page_content'] ?? '';\n    $pageType = 'markdown';\n\n    // 如果是 RunApi 项目，转换为 Markdown\n    if ($itemType === 3) {\n      $pageType = 'runapi';\n      $convert = new Convert();\n      $content = $convert->runapiToMd($content);\n    }\n\n    // 对内容进行 HTML 解转义（MCP 场景下 AI 需要原始内容）\n    $content = htmlspecialchars_decode($content, ENT_QUOTES);\n\n    return [\n      'page_id' => $pageId,\n      'version_id' => $versionId,\n      'page_title' => $historyPage['page_title'] ?? '',\n      'item_id' => $itemId,\n      'type' => $pageType,\n      'content' => $content,\n      'author' => $historyPage['author_username'] ?? '',\n      'author_uid' => (int) ($historyPage['author_uid'] ?? 0),\n      'updated_at' => $historyPage['addtime'] ?? '',\n      'change_summary' => $historyPage['page_comments'] ?? '',\n    ];\n  }\n\n  /**\n   * 对比两个版本的差异\n   *\n   * @param array $params 参数\n   * @return array\n   * @throws McpException\n   */\n  private function diffPageVersions(array $params): array\n  {\n    $pageId = (int) ($params['page_id'] ?? 0);\n    $versionId1 = (int) ($params['version_id_1'] ?? 0);\n    $versionId2 = (int) ($params['version_id_2'] ?? 0);\n\n    if ($pageId <= 0) {\n      McpError::throw(McpError::INVALID_PARAMS, '页面ID不能为空');\n    }\n    if ($versionId1 <= 0 || $versionId2 <= 0) {\n      McpError::throw(McpError::INVALID_PARAMS, '版本ID不能为空');\n    }\n\n    // 开源版：使用单一 page 表\n    $page = DB::table('page')\n      ->where('page_id', $pageId)\n      ->where('is_del', 0)\n      ->first();\n\n    if (!$page) {\n      McpError::throw(McpError::RESOURCE_NOT_FOUND, '页面不存在');\n    }\n\n    $itemId = (int) $page->item_id;\n\n    // 检查读取权限\n    $this->requireReadPermission($itemId);\n\n    // 获取两个历史版本\n    $version1 = PageHistory::findById($pageId, $versionId1);\n    $version2 = PageHistory::findById($pageId, $versionId2);\n\n    if (!$version1) {\n      McpError::throw(McpError::RESOURCE_NOT_FOUND, '版本1不存在');\n    }\n    if (!$version2) {\n      McpError::throw(McpError::RESOURCE_NOT_FOUND, '版本2不存在');\n    }\n\n    // 计算差异\n    $diff = $this->calculateDiff(\n      $version1['page_content'] ?? '',\n      $version2['page_content'] ?? ''\n    );\n\n    return [\n      'page_id' => $pageId,\n      'version_1' => [\n        'version_id' => $versionId1,\n        'author' => $version1['author_username'] ?? '',\n        'updated_at' => $version1['addtime'] ?? '',\n      ],\n      'version_2' => [\n        'version_id' => $versionId2,\n        'author' => $version2['author_username'] ?? '',\n        'updated_at' => $version2['addtime'] ?? '',\n      ],\n      'diff' => $diff,\n    ];\n  }\n\n  /**\n   * 计算两个文本的差异\n   *\n   * @param string $old 旧文本\n   * @param string $new 新文本\n   * @return array 差异结果\n   */\n  private function calculateDiff(string $old, string $new): array\n  {\n    // 简单的行级差异计算\n    $oldLines = explode(\"\\n\", $old);\n    $newLines = explode(\"\\n\", $new);\n\n    $diff = [];\n    $maxLines = max(count($oldLines), count($newLines));\n\n    for ($i = 0; $i < $maxLines; $i++) {\n      $oldLine = $oldLines[$i] ?? '';\n      $newLine = $newLines[$i] ?? '';\n\n      if ($oldLine === $newLine) {\n        // 相同行\n        $diff[] = [\n          'type' => 'unchanged',\n          'line' => $i + 1,\n          'content' => $oldLine,\n        ];\n      } else {\n        // 不同行\n        if ($oldLine !== '' && !isset($oldLines[$i])) {\n          // 新增行\n          $diff[] = [\n            'type' => 'added',\n            'line' => $i + 1,\n            'content' => $newLine,\n          ];\n        } elseif ($newLine !== '' && !isset($newLines[$i])) {\n          // 删除行\n          $diff[] = [\n            'type' => 'removed',\n            'line' => $i + 1,\n            'content' => $oldLine,\n          ];\n        } else {\n          // 修改行\n          if ($oldLine !== '') {\n            $diff[] = [\n              'type' => 'removed',\n              'line' => $i + 1,\n              'content' => $oldLine,\n            ];\n          }\n          if ($newLine !== '') {\n            $diff[] = [\n              'type' => 'added',\n              'line' => $i + 1,\n              'content' => $newLine,\n            ];\n          }\n        }\n      }\n    }\n\n    // 只返回有变化的行\n    $changes = array_filter($diff, function ($item) {\n      return $item['type'] !== 'unchanged';\n    });\n\n    return [\n      'changes' => array_values($changes),\n      'summary' => [\n        'added' => count(array_filter($changes, fn($item) => $item['type'] === 'added')),\n        'removed' => count(array_filter($changes, fn($item) => $item['type'] === 'removed')),\n      ],\n    ];\n  }\n\n  /**\n   * 恢复页面到指定历史版本\n   *\n   * @param array $params 参数\n   * @return array\n   * @throws McpException\n   */\n  private function restorePageVersion(array $params): array\n  {\n    $pageId = (int) ($params['page_id'] ?? 0);\n    $versionId = (int) ($params['version_id'] ?? 0);\n\n    if ($pageId <= 0) {\n      McpError::throw(McpError::INVALID_PARAMS, '页面ID不能为空');\n    }\n    if ($versionId <= 0) {\n      McpError::throw(McpError::INVALID_PARAMS, '版本ID不能为空');\n    }\n\n    // 开源版：使用单一 page 表\n    $page = DB::table('page')\n      ->where('page_id', $pageId)\n      ->where('is_del', 0)\n      ->first();\n\n    if (!$page) {\n      McpError::throw(McpError::RESOURCE_NOT_FOUND, '页面不存在');\n    }\n\n    $itemId = (int) $page->item_id;\n\n    // 检查写入权限\n    $this->requireWritePermission($itemId);\n\n    // 获取历史版本\n    $historyPage = PageHistory::findById($pageId, $versionId);\n    if (!$historyPage) {\n      McpError::throw(McpError::RESOURCE_NOT_FOUND, '历史版本不存在');\n    }\n\n    try {\n      $now = time();\n      $uid = $this->getUid();\n      $username = $this->getUsername();\n\n      // 先保存当前版本到历史记录\n      $currentData = [\n        'page_id' => $pageId,\n        'item_id' => $itemId,\n        'cat_id' => (int) ($page->cat_id ?? 0),\n        'page_title' => $page->page_title,\n        'page_content' => $page->page_content,\n        's_number' => (int) ($page->s_number ?? 0),\n        'addtime' => $now,\n        'author_uid' => (int) ($page->author_uid ?? 0),\n        'author_username' => $page->author_username ?? '',\n        'page_comments' => '恢复前自动备份',\n      ];\n      PageHistory::add($pageId, $currentData);\n\n      // 更新页面内容为历史版本\n      $updateData = [\n        'page_content' => $historyPage['page_content'] ?? '',\n        'page_title' => $historyPage['page_title'] ?? $page->page_title,\n        'addtime' => $now,\n        'author_uid' => $uid,\n        'author_username' => $username,\n      ];\n\n      // 复用 Page::savePage 方法，确保内容压缩等逻辑与原后端一致\n      $ret = Page::savePage($pageId, $itemId, $updateData);\n      if (!$ret) {\n        McpError::throw(McpError::OPERATION_FAILED, '恢复版本失败');\n      }\n\n      // 更新项目最后更新时间\n      DB::table('item')\n        ->where('item_id', $itemId)\n        ->update(['last_update_time' => $now]);\n\n      // 删除缓存\n      Page::deleteCache($pageId);\n      Item::deleteCache($itemId);\n\n      return [\n        'page_id' => $pageId,\n        'version_id' => $versionId,\n        'item_id' => $itemId,\n        'page_title' => $updateData['page_title'],\n        'restored_at' => date('Y-m-d H:i:s', $now),\n        'message' => '页面已恢复到指定版本，当前版本已自动备份',\n      ];\n    } catch (\\Throwable $e) {\n      McpError::throw(McpError::OPERATION_FAILED, '恢复版本失败: ' . $e->getMessage());\n    }\n  }\n}\n"
  },
  {
    "path": "server/app/Mcp/McpError.php",
    "content": "<?php\n\nnamespace App\\Mcp;\n\n/**\n * MCP 错误处理类\n * \n * 定义 MCP 协议相关的错误码和错误消息\n * \n * JSON-RPC 2.0 标准错误码范围：-32700 ~ -32603\n * ShowDoc MCP 自定义错误码范围：-32001 ~ -32011\n */\nclass McpError\n{\n  // JSON-RPC 标准错误码\n  const PARSE_ERROR = -32700;           // JSON 解析失败\n  const INVALID_REQUEST = -32600;       // 请求对象无效\n  const METHOD_NOT_FOUND = -32601;      // 方法不存在\n  const INVALID_PARAMS = -32602;        // 参数无效\n  const INTERNAL_ERROR = -32603;        // 服务器内部错误\n\n  // ShowDoc MCP 自定义错误码\n  const TOKEN_INVALID = -32001;         // Token 无效或已过期\n  const TOKEN_SCOPE_DENIED = -32002;    // 项目不在 Token 范围内\n  const NOT_ITEM_MEMBER = -32003;       // 用户不是项目成员\n  const NO_EDIT_PERMISSION = -32004;    // 用户无项目编辑权限\n  const TOKEN_OPERATION_DENIED = -32005; // Token 不允许此操作\n  const RESOURCE_NOT_FOUND = -32006;    // 资源不存在\n  const CONTENT_TOO_LARGE = -32007;     // 内容超限\n  const RATE_LIMITED = -32008;          // 频率限制\n  const VERSION_CONFLICT = -32009;      // 版本冲突（乐观锁）\n  const OPERATION_FAILED = -32010;      // 操作失败\n  const VALIDATION_ERROR = -32011;      // 参数校验失败\n\n  /**\n   * 错误码与消息映射\n   */\n  private static array $messages = [\n    // JSON-RPC 标准错误\n    self::PARSE_ERROR => 'JSON 解析失败',\n    self::INVALID_REQUEST => '请求对象无效',\n    self::METHOD_NOT_FOUND => '方法不存在',\n    self::INVALID_PARAMS => '参数无效',\n    self::INTERNAL_ERROR => '服务器内部错误',\n\n    // ShowDoc MCP 自定义错误\n    self::TOKEN_INVALID => 'Token 无效或已过期',\n    self::TOKEN_SCOPE_DENIED => '项目不在 Token 的权限范围内',\n    self::NOT_ITEM_MEMBER => '您不是该项目的成员',\n    self::NO_EDIT_PERMISSION => '权限不足：您在该项目中无编辑权限',\n    self::TOKEN_OPERATION_DENIED => 'Token 不允许执行此操作',\n    self::RESOURCE_NOT_FOUND => '资源不存在',\n    self::CONTENT_TOO_LARGE => '内容超出限制',\n    self::RATE_LIMITED => '请求频率超限，请稍后重试',\n    self::VERSION_CONFLICT => '版本冲突：文档已被其他人修改',\n    self::OPERATION_FAILED => '操作失败',\n    self::VALIDATION_ERROR => '参数校验失败',\n  ];\n\n  /**\n   * 获取错误消息\n   *\n   * @param int $code 错误码\n   * @return string 错误消息\n   */\n  public static function getMessage(int $code): string\n  {\n    return self::$messages[$code] ?? '未知错误';\n  }\n\n  /**\n   * 创建 JSON-RPC 错误响应\n   *\n   * @param int $code 错误码\n   * @param string|null $message 自定义错误消息\n   * @param mixed $data 附加数据\n   * @param int|string|null $id 请求 ID\n   * @return array JSON-RPC 错误响应数组\n   */\n  public static function createResponse(int $code, ?string $message = null, $data = null, $id = null): array\n  {\n    $error = [\n      'code' => $code,\n      'message' => $message ?? self::getMessage($code),\n    ];\n\n    if ($data !== null) {\n      $error['data'] = $data;\n    }\n\n    return [\n      'jsonrpc' => '2.0',\n      'id' => $id,\n      'error' => $error,\n    ];\n  }\n\n  /**\n   * 创建成功响应\n   *\n   * @param mixed $result 结果数据\n   * @param int|string|null $id 请求 ID\n   * @return array JSON-RPC 成功响应数组\n   */\n  public static function createSuccessResponse($result, $id = null): array\n  {\n    return [\n      'jsonrpc' => '2.0',\n      'id' => $id,\n      'result' => $result,\n    ];\n  }\n\n  /**\n   * 抛出 MCP 异常\n   *\n   * @param int $code 错误码\n   * @param string|null $message 自定义错误消息\n   * @param mixed $data 附加数据\n   * @throws McpException\n   */\n  public static function throw(int $code, ?string $message = null, $data = null): void\n  {\n    throw new McpException($code, $message ?? self::getMessage($code), $data);\n  }\n}\n"
  },
  {
    "path": "server/app/Mcp/McpException.php",
    "content": "<?php\n\nnamespace App\\Mcp;\n\n/**\n * MCP 异常类\n * \n * 用于 MCP 操作中抛出的异常，携带错误码和附加数据\n */\nclass McpException extends \\Exception\n{\n  /**\n   * 附加数据\n   *\n   * @var mixed\n   */\n  protected $data;\n\n  /**\n   * 构造函数\n   *\n   * @param int $code 错误码\n   * @param string $message 错误消息\n   * @param mixed $data 附加数据\n   */\n  public function __construct(int $code, string $message = '', $data = null)\n  {\n    parent::__construct($message, $code);\n    $this->data = $data;\n  }\n\n  /**\n   * 获取附加数据\n   *\n   * @return mixed\n   */\n  public function getData()\n  {\n    return $this->data;\n  }\n\n  /**\n   * 转换为 JSON-RPC 错误响应数组\n   *\n   * @param int|string|null $id 请求 ID\n   * @return array\n   */\n  public function toResponse($id = null): array\n  {\n    return McpError::createResponse($this->code, $this->message, $this->data, $id);\n  }\n}\n"
  },
  {
    "path": "server/app/Mcp/McpHandler.php",
    "content": "<?php\n\nnamespace App\\Mcp;\n\nuse App\\Model\\UserAiToken;\nuse App\\Model\\Item;\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\n/**\n * MCP Handler 基类\n * \n * 所有 MCP Tool Handler 的基类，提供通用的权限检查和辅助方法\n */\nabstract class McpHandler\n{\n  /**\n   * 当前 Token 信息\n   *\n   * @var array|null\n   */\n  protected ?array $tokenInfo = null;\n\n  /**\n   * 当前用户 ID\n   *\n   * @var int\n   */\n  protected int $uid = 0;\n\n  /**\n   * 设置当前 Token 信息\n   *\n   * @param array $tokenInfo Token 信息数组\n   * @return void\n   */\n  public function setTokenInfo(array $tokenInfo): void\n  {\n    $this->tokenInfo = $tokenInfo;\n    $this->uid = (int) ($tokenInfo['uid'] ?? 0);\n  }\n\n  /**\n   * 获取当前用户 ID\n   *\n   * @return int\n   */\n  protected function getUid(): int\n  {\n    return $this->uid;\n  }\n\n  /**\n   * 检查 Token 是否有读取权限\n   *\n   * @return bool\n   */\n  protected function canRead(): bool\n  {\n    if (!$this->tokenInfo) {\n      return false;\n    }\n    $permission = $this->tokenInfo['permission'] ?? 'read';\n    return in_array($permission, ['read', 'write']);\n  }\n\n  /**\n   * 检查 Token 是否有写入权限\n   *\n   * @return bool\n   */\n  protected function canWrite(): bool\n  {\n    if (!$this->tokenInfo) {\n      return false;\n    }\n    return ($this->tokenInfo['permission'] ?? '') === 'write';\n  }\n\n  /**\n   * 检查 Token 是否允许创建项目\n   *\n   * @return bool\n   */\n  protected function canCreateItem(): bool\n  {\n    if (!$this->tokenInfo) {\n      return false;\n    }\n    return (bool) ($this->tokenInfo['can_create_item'] ?? false);\n  }\n\n  /**\n   * 检查 Token 是否允许删除项目\n   *\n   * @return bool\n   */\n  protected function canDeleteItem(): bool\n  {\n    if (!$this->tokenInfo) {\n      return false;\n    }\n    return (bool) ($this->tokenInfo['can_delete_item'] ?? false);\n  }\n\n  /**\n   * 检查项目是否在 Token 的权限范围内\n   *\n   * @param int $itemId 项目 ID\n   * @return bool\n   */\n  protected function isItemInScope(int $itemId): bool\n  {\n    if (!$this->tokenInfo) {\n      return false;\n    }\n\n    $scope = $this->tokenInfo['scope'] ?? 'all';\n\n    // 如果是全部项目范围，直接返回 true\n    if ($scope === 'all') {\n      return true;\n    }\n\n    // 如果是指定项目范围，检查项目是否在允许列表中\n    $allowedItems = $this->tokenInfo['allowed_items'] ?? '';\n    if (empty($allowedItems)) {\n      return false;\n    }\n\n    $allowedIds = json_decode($allowedItems, true);\n    if (!is_array($allowedIds)) {\n      return false;\n    }\n\n    return in_array($itemId, $allowedIds);\n  }\n\n  /**\n   * 检查用户是否是项目成员\n   *\n   * @param int $itemId 项目 ID\n   * @return bool\n   */\n  protected function isItemMember(int $itemId): bool\n  {\n    if ($this->uid <= 0 || $itemId <= 0) {\n      return false;\n    }\n\n    // 检查是否是项目创建者\n    $item = Item::findById($itemId);\n    if ($item && (int) $item->uid === $this->uid) {\n      return true;\n    }\n\n    // 检查是否是项目成员\n    $member = DB::table('item_member')\n      ->where('item_id', $itemId)\n      ->where('uid', $this->uid)\n      ->first();\n    if ($member) {\n      return true;\n    }\n\n    // 检查是否是团队成员\n    $teamMember = DB::table('team_item_member')\n      ->where('item_id', $itemId)\n      ->where('member_uid', $this->uid)\n      ->first();\n    if ($teamMember) {\n      return true;\n    }\n\n    return false;\n  }\n\n  /**\n   * 获取用户在项目中的角色\n   *\n   * @param int $itemId 项目 ID\n   * @return string|null 角色：owner/admin/editor/readonly/null\n   */\n  protected function getItemRole(int $itemId): ?string\n  {\n    if ($this->uid <= 0 || $itemId <= 0) {\n      return null;\n    }\n\n    // 检查是否是项目创建者\n    $item = Item::findById($itemId);\n    if (!$item) {\n      return null;\n    }\n    if ((int) $item->uid === $this->uid) {\n      return 'owner';\n    }\n\n    // 检查是否是系统管理员\n    $user = \\App\\Model\\User::findById($this->uid);\n    if ($user && (int) $user->groupid === 1) {\n      return 'admin';\n    }\n\n    // 检查项目成员表\n    $member = DB::table('item_member')\n      ->where('item_id', $itemId)\n      ->where('uid', $this->uid)\n      ->first();\n    if ($member) {\n      // member_group_id: 1=编辑, 2=管理员, 3=只读\n      $groupId = (int) $member->member_group_id;\n      if ($groupId === 2) {\n        return 'admin';\n      } elseif ($groupId === 1) {\n        return 'editor';\n      } elseif ($groupId === 3) {\n        return 'readonly';\n      }\n    }\n\n    // 检查团队成员表\n    $teamMember = DB::table('team_item_member')\n      ->where('item_id', $itemId)\n      ->where('member_uid', $this->uid)\n      ->first();\n    if ($teamMember) {\n      $groupId = (int) $teamMember->member_group_id;\n      if ($groupId === 2) {\n        return 'admin';\n      } elseif ($groupId === 1) {\n        return 'editor';\n      } elseif ($groupId === 3) {\n        return 'readonly';\n      }\n    }\n\n    return null;\n  }\n\n  /**\n   * 检查用户是否有项目编辑权限\n   *\n   * @param int $itemId 项目 ID\n   * @return bool\n   */\n  protected function canEditItem(int $itemId): bool\n  {\n    $role = $this->getItemRole($itemId);\n    return in_array($role, ['owner', 'admin', 'editor']);\n  }\n\n  /**\n   * 检查用户是否有项目管理权限\n   *\n   * @param int $itemId 项目 ID\n   * @return bool\n   */\n  protected function canManageItem(int $itemId): bool\n  {\n    $role = $this->getItemRole($itemId);\n    return in_array($role, ['owner', 'admin']);\n  }\n\n  /**\n   * 要求读取权限（无权限时抛出异常）\n   *\n   * @param int $itemId 项目 ID\n   * @throws McpException\n   */\n  protected function requireReadPermission(int $itemId): void\n  {\n    if (!$this->canRead()) {\n      McpError::throw(\n        McpError::TOKEN_OPERATION_DENIED,\n        'Token 不允许执行读取操作'\n      );\n    }\n\n    if (!$this->isItemInScope($itemId)) {\n      McpError::throw(\n        McpError::TOKEN_SCOPE_DENIED,\n        '该项目不在 Token 的权限范围内'\n      );\n    }\n\n    if (!$this->isItemMember($itemId)) {\n      McpError::throw(\n        McpError::NOT_ITEM_MEMBER,\n        '您不是该项目的成员'\n      );\n    }\n  }\n\n  /**\n   * 要求写入权限（无权限时抛出异常）\n   *\n   * @param int $itemId 项目 ID\n   * @throws McpException\n   */\n  protected function requireWritePermission(int $itemId): void\n  {\n    if (!$this->canWrite()) {\n      McpError::throw(\n        McpError::TOKEN_OPERATION_DENIED,\n        'Token 不允许执行写入操作'\n      );\n    }\n\n    if (!$this->isItemInScope($itemId)) {\n      McpError::throw(\n        McpError::TOKEN_SCOPE_DENIED,\n        '该项目不在 Token 的权限范围内'\n      );\n    }\n\n    if (!$this->isItemMember($itemId)) {\n      McpError::throw(\n        McpError::NOT_ITEM_MEMBER,\n        '您不是该项目的成员'\n      );\n    }\n\n    if (!$this->canEditItem($itemId)) {\n      McpError::throw(\n        McpError::NO_EDIT_PERMISSION,\n        '权限不足：您在该项目中无编辑权限'\n      );\n    }\n  }\n\n  /**\n   * 将新创建的项目添加到 Token 的权限范围\n   *\n   * @param int $itemId 新创建的项目 ID\n   * @return void\n   */\n  protected function addCreatedItemToScope(int $itemId): void\n  {\n    if (!$this->tokenInfo) {\n      return;\n    }\n\n    $scope = $this->tokenInfo['scope'] ?? 'all';\n    $autoAdd = (bool) ($this->tokenInfo['auto_add_created_item'] ?? true);\n\n    // 仅当 scope=selected 且 auto_add_created_item=1 时才添加\n    if ($scope !== 'selected' || !$autoAdd) {\n      return;\n    }\n\n    $allowedItems = $this->tokenInfo['allowed_items'] ?? '[]';\n    $allowedIds = json_decode($allowedItems, true) ?: [];\n\n    if (!in_array($itemId, $allowedIds)) {\n      $allowedIds[] = $itemId;\n      UserAiToken::updateAllowedItems($this->tokenInfo['id'], $allowedIds);\n    }\n  }\n\n  /**\n   * 获取 Handler 支持的操作列表\n   *\n   * @return array\n   */\n  abstract public function getSupportedOperations(): array;\n\n  /**\n   * 执行操作\n   *\n   * @param string $operation 操作名称\n   * @param array $params 参数\n   * @return mixed\n   * @throws McpException\n   */\n  abstract public function execute(string $operation, array $params = []);\n}\n"
  },
  {
    "path": "server/app/Mcp/McpServer.php",
    "content": "<?php\n\nnamespace App\\Mcp;\n\nuse App\\Mcp\\Handler\\ItemHandler;\nuse App\\Mcp\\Handler\\CatalogHandler;\nuse App\\Mcp\\Handler\\PageHandler;\nuse App\\Mcp\\Handler\\AttachmentHandler;\nuse App\\Mcp\\Handler\\OpenApiHandler;\nuse App\\Model\\UserAiToken;\nuse App\\Common\\Helper\\IpHelper;\n\n/**\n * MCP Server 核心类\n * \n * 处理 MCP 协议的 JSON-RPC 请求，路由到对应的 Handler\n */\nclass McpServer\n{\n  /**\n   * 请求 ID\n   *\n   * @var int|string|null\n   */\n  private $requestId = null;\n\n  /**\n   * Token 信息\n   *\n   * @var array|null\n   */\n  private ?array $tokenInfo = null;\n\n  /**\n   * 已注册的 Tools\n   *\n   * @var array\n   */\n  private array $tools = [];\n\n  /**\n   * 已注册的 Resources\n   *\n   * @var array\n   */\n  private array $resources = [];\n\n  /**\n   * 已注册的 Prompts\n   *\n   * @var array\n   */\n  private array $prompts = [];\n\n  /**\n   * Handler 实例缓存\n   *\n   * @var array\n   */\n  private array $handlers = [];\n\n  /**\n   * 构造函数\n   */\n  public function __construct()\n  {\n    $this->registerDefaultTools();\n    $this->registerDefaultResources();\n    $this->registerDefaultPrompts();\n  }\n\n  /**\n   * 注册默认 Tools\n   *\n   * @return void\n   */\n  private function registerDefaultTools(): void\n  {\n    // 项目管理\n    $this->tools['list_items'] = [\n      'name' => 'list_items',\n      'description' => '列出用户可访问的所有项目',\n      'inputSchema' => [\n        'type' => 'object',\n        'properties' => (object) [],\n        'required' => [],\n      ],\n      'handler' => 'item',\n    ];\n\n    $this->tools['get_item'] = [\n      'name' => 'get_item',\n      'description' => '获取项目详情',\n      'inputSchema' => [\n        'type' => 'object',\n        'properties' => [\n          'item_id' => [\n            'type' => 'integer',\n            'description' => '项目ID',\n          ],\n        ],\n        'required' => ['item_id'],\n      ],\n      'handler' => 'item',\n    ];\n\n    $this->tools['create_item'] = [\n      'name' => 'create_item',\n      'description' => '创建新项目',\n      'inputSchema' => [\n        'type' => 'object',\n        'properties' => [\n          'item_name' => [\n            'type' => 'string',\n            'description' => '项目名称',\n          ],\n          'item_type' => [\n            'type' => 'integer',\n            'description' => '项目类型：1=普通文档（默认），3=RunApi项目',\n          ],\n          'item_description' => [\n            'type' => 'string',\n            'description' => '项目描述',\n          ],\n        ],\n        'required' => ['item_name'],\n      ],\n      'handler' => 'item',\n    ];\n\n    $this->tools['update_item'] = [\n      'name' => 'update_item',\n      'description' => '更新项目信息',\n      'inputSchema' => [\n        'type' => 'object',\n        'properties' => [\n          'item_id' => [\n            'type' => 'integer',\n            'description' => '项目ID',\n          ],\n          'item_name' => [\n            'type' => 'string',\n            'description' => '项目名称',\n          ],\n          'item_description' => [\n            'type' => 'string',\n            'description' => '项目描述',\n          ],\n        ],\n        'required' => ['item_id'],\n      ],\n      'handler' => 'item',\n    ];\n\n    $this->tools['delete_item'] = [\n      'name' => 'delete_item',\n      'description' => '删除项目（软删除）',\n      'inputSchema' => [\n        'type' => 'object',\n        'properties' => [\n          'item_id' => [\n            'type' => 'integer',\n            'description' => '项目ID',\n          ],\n        ],\n        'required' => ['item_id'],\n      ],\n      'handler' => 'item',\n    ];\n\n    // 目录管理\n    $this->tools['list_catalogs'] = [\n      'name' => 'list_catalogs',\n      'description' => '获取项目的目录树',\n      'inputSchema' => [\n        'type' => 'object',\n        'properties' => [\n          'item_id' => [\n            'type' => 'integer',\n            'description' => '项目ID',\n          ],\n        ],\n        'required' => ['item_id'],\n      ],\n      'handler' => 'catalog',\n    ];\n\n    $this->tools['get_catalog'] = [\n      'name' => 'get_catalog',\n      'description' => '获取目录详情',\n      'inputSchema' => [\n        'type' => 'object',\n        'properties' => [\n          'cat_id' => [\n            'type' => 'integer',\n            'description' => '目录ID',\n          ],\n        ],\n        'required' => ['cat_id'],\n      ],\n      'handler' => 'catalog',\n    ];\n\n    $this->tools['create_catalog'] = [\n      'name' => 'create_catalog',\n      'description' => '创建目录',\n      'inputSchema' => [\n        'type' => 'object',\n        'properties' => [\n          'item_id' => [\n            'type' => 'integer',\n            'description' => '项目ID',\n          ],\n          'cat_name' => [\n            'type' => 'string',\n            'description' => '目录名称',\n          ],\n          'parent_cat_id' => [\n            'type' => 'integer',\n            'description' => '父目录ID（可选，默认为根目录）',\n          ],\n          's_number' => [\n            'type' => 'integer',\n            'description' => '排序号（可选）',\n          ],\n        ],\n        'required' => ['item_id', 'cat_name'],\n      ],\n      'handler' => 'catalog',\n    ];\n\n    $this->tools['update_catalog'] = [\n      'name' => 'update_catalog',\n      'description' => '更新目录',\n      'inputSchema' => [\n        'type' => 'object',\n        'properties' => [\n          'cat_id' => [\n            'type' => 'integer',\n            'description' => '目录ID',\n          ],\n          'cat_name' => [\n            'type' => 'string',\n            'description' => '目录名称',\n          ],\n          's_number' => [\n            'type' => 'integer',\n            'description' => '排序号',\n          ],\n        ],\n        'required' => ['cat_id'],\n      ],\n      'handler' => 'catalog',\n    ];\n\n    $this->tools['delete_catalog'] = [\n      'name' => 'delete_catalog',\n      'description' => '删除目录（含子目录和页面）',\n      'inputSchema' => [\n        'type' => 'object',\n        'properties' => [\n          'cat_id' => [\n            'type' => 'integer',\n            'description' => '目录ID',\n          ],\n        ],\n        'required' => ['cat_id'],\n      ],\n      'handler' => 'catalog',\n    ];\n\n    // 页面管理\n    $this->tools['list_pages'] = [\n      'name' => 'list_pages',\n      'description' => '获取项目/目录下的页面列表（分页，不含内容）',\n      'inputSchema' => [\n        'type' => 'object',\n        'properties' => [\n          'item_id' => [\n            'type' => 'integer',\n            'description' => '项目ID',\n          ],\n          'cat_id' => [\n            'type' => 'integer',\n            'description' => '目录ID（可选）',\n          ],\n          'page' => [\n            'type' => 'integer',\n            'description' => '页码（默认1）',\n          ],\n          'page_size' => [\n            'type' => 'integer',\n            'description' => '每页数量（默认50，最大100）',\n          ],\n        ],\n        'required' => ['item_id'],\n      ],\n      'handler' => 'page',\n    ];\n\n    $this->tools['get_page'] = [\n      'name' => 'get_page',\n      'description' => '获取页面详情',\n      'inputSchema' => [\n        'type' => 'object',\n        'properties' => [\n          'page_id' => [\n            'type' => 'integer',\n            'description' => '页面ID',\n          ],\n          'item_id' => [\n            'type' => 'integer',\n            'description' => '项目ID（与page_title配合使用）',\n          ],\n          'page_title' => [\n            'type' => 'string',\n            'description' => '页面标题（与item_id配合使用）',\n          ],\n        ],\n      ],\n      'handler' => 'page',\n    ];\n\n    $this->tools['batch_get_pages'] = [\n      'name' => 'batch_get_pages',\n      'description' => '批量获取页面详情（最多10个）',\n      'inputSchema' => [\n        'type' => 'object',\n        'properties' => [\n          'page_ids' => [\n            'type' => 'array',\n            'items' => ['type' => 'integer'],\n            'description' => '页面ID数组（最多10个）',\n          ],\n        ],\n        'required' => ['page_ids'],\n      ],\n      'handler' => 'page',\n    ];\n\n    $this->tools['search_pages'] = [\n      'name' => 'search_pages',\n      'description' => '搜索页面（按关键字搜索，默认只搜索标题）',\n      'inputSchema' => [\n        'type' => 'object',\n        'properties' => [\n          'query' => [\n            'type' => 'string',\n            'description' => '搜索关键字',\n          ],\n          'item_id' => [\n            'type' => 'integer',\n            'description' => '项目ID（可选，限定搜索范围）',\n          ],\n          'search_mode' => [\n            'type' => 'string',\n            'description' => '搜索模式：title（默认，只搜索标题）、content（只搜索内容）、all（搜索标题和内容）',\n            'enum' => ['title', 'content', 'all'],\n          ],\n        ],\n        'required' => ['query'],\n      ],\n      'handler' => 'page',\n    ];\n\n    $this->tools['get_page_template'] = [\n      'name' => 'get_page_template',\n      'description' => '获取文档模板（api/runapi_comment/database/general）',\n      'inputSchema' => [\n        'type' => 'object',\n        'properties' => [\n          'type' => [\n            'type' => 'string',\n            'description' => '模板类型：api、runapi_comment、database、general',\n          ],\n        ],\n        'required' => [],\n      ],\n      'handler' => 'page',\n    ];\n\n    $this->tools['create_page'] = [\n      'name' => 'create_page',\n      'description' => '创建页面（Markdown内容）',\n      'inputSchema' => [\n        'type' => 'object',\n        'properties' => [\n          'item_id' => [\n            'type' => 'integer',\n            'description' => '项目ID',\n          ],\n          'page_title' => [\n            'type' => 'string',\n            'description' => '页面标题',\n          ],\n          'page_content' => [\n            'type' => 'string',\n            'description' => '页面内容（Markdown格式）',\n          ],\n          'cat_name' => [\n            'type' => 'string',\n            'description' => '目录名称（可选，不存在则自动创建）',\n          ],\n          's_number' => [\n            'type' => 'integer',\n            'description' => '排序号（可选）',\n          ],\n        ],\n        'required' => ['item_id', 'page_title', 'page_content'],\n      ],\n      'handler' => 'page',\n    ];\n\n    $this->tools['create_page_by_comment'] = [\n      'name' => 'create_page_by_comment',\n      'description' => '通过代码注释创建RunApi格式页面',\n      'inputSchema' => [\n        'type' => 'object',\n        'properties' => [\n          'item_id' => [\n            'type' => 'integer',\n            'description' => '项目ID',\n          ],\n          'comment_content' => [\n            'type' => 'string',\n            'description' => '代码注释内容（showdoc格式）',\n          ],\n        ],\n        'required' => ['item_id', 'comment_content'],\n      ],\n      'handler' => 'page',\n    ];\n\n    $this->tools['update_page'] = [\n      'name' => 'update_page',\n      'description' => '更新页面',\n      'inputSchema' => [\n        'type' => 'object',\n        'properties' => [\n          'page_id' => [\n            'type' => 'integer',\n            'description' => '页面ID',\n          ],\n          'page_content' => [\n            'type' => 'string',\n            'description' => '页面内容（Markdown格式）',\n          ],\n          'page_title' => [\n            'type' => 'string',\n            'description' => '页面标题（可选）',\n          ],\n          'expected_hash' => [\n            'type' => 'string',\n            'description' => '期望的当前内容哈希（乐观锁，可选）',\n          ],\n        ],\n        'required' => ['page_id', 'page_content'],\n      ],\n      'handler' => 'page',\n    ];\n\n    $this->tools['upsert_page'] = [\n      'name' => 'upsert_page',\n      'description' => '按标题智能匹配：存在则更新，不存在则创建',\n      'inputSchema' => [\n        'type' => 'object',\n        'properties' => [\n          'item_id' => [\n            'type' => 'integer',\n            'description' => '项目ID',\n          ],\n          'page_title' => [\n            'type' => 'string',\n            'description' => '页面标题',\n          ],\n          'page_content' => [\n            'type' => 'string',\n            'description' => '页面内容（Markdown格式）',\n          ],\n          'cat_name' => [\n            'type' => 'string',\n            'description' => '目录名称（可选）',\n          ],\n          's_number' => [\n            'type' => 'integer',\n            'description' => '排序号（可选）',\n          ],\n        ],\n        'required' => ['item_id', 'page_title', 'page_content'],\n      ],\n      'handler' => 'page',\n    ];\n\n    $this->tools['batch_upsert_pages'] = [\n      'name' => 'batch_upsert_pages',\n      'description' => '批量创建/更新页面（最多50个）',\n      'inputSchema' => [\n        'type' => 'object',\n        'properties' => [\n          'item_id' => [\n            'type' => 'integer',\n            'description' => '项目ID',\n          ],\n          'pages' => [\n            'type' => 'array',\n            'items' => [\n              'type' => 'object',\n              'properties' => [\n                'page_title' => ['type' => 'string'],\n                'page_content' => ['type' => 'string'],\n                'cat_name' => ['type' => 'string'],\n                's_number' => ['type' => 'integer'],\n              ],\n              'required' => ['page_title', 'page_content'],\n            ],\n            'description' => '页面数组（最多50个）',\n          ],\n        ],\n        'required' => ['item_id', 'pages'],\n      ],\n      'handler' => 'page',\n    ];\n\n    $this->tools['delete_page'] = [\n      'name' => 'delete_page',\n      'description' => '删除页面（软删除）',\n      'inputSchema' => [\n        'type' => 'object',\n        'properties' => [\n          'page_id' => [\n            'type' => 'integer',\n            'description' => '页面ID',\n          ],\n        ],\n        'required' => ['page_id'],\n      ],\n      'handler' => 'page',\n    ];\n\n    // 页面历史管理\n    $this->tools['get_page_history'] = [\n      'name' => 'get_page_history',\n      'description' => '获取页面的修改历史列表',\n      'inputSchema' => [\n        'type' => 'object',\n        'properties' => [\n          'page_id' => [\n            'type' => 'integer',\n            'description' => '页面ID',\n          ],\n          'limit' => [\n            'type' => 'integer',\n            'description' => '返回数量限制（默认20，最大100）',\n          ],\n        ],\n        'required' => ['page_id'],\n      ],\n      'handler' => 'page',\n    ];\n\n    $this->tools['get_page_version'] = [\n      'name' => 'get_page_version',\n      'description' => '获取页面指定历史版本的内容',\n      'inputSchema' => [\n        'type' => 'object',\n        'properties' => [\n          'page_id' => [\n            'type' => 'integer',\n            'description' => '页面ID',\n          ],\n          'version_id' => [\n            'type' => 'integer',\n            'description' => '历史版本ID',\n          ],\n        ],\n        'required' => ['page_id', 'version_id'],\n      ],\n      'handler' => 'page',\n    ];\n\n    $this->tools['diff_page_versions'] = [\n      'name' => 'diff_page_versions',\n      'description' => '对比两个页面版本的差异',\n      'inputSchema' => [\n        'type' => 'object',\n        'properties' => [\n          'page_id' => [\n            'type' => 'integer',\n            'description' => '页面ID',\n          ],\n          'version_id_1' => [\n            'type' => 'integer',\n            'description' => '第一个版本ID',\n          ],\n          'version_id_2' => [\n            'type' => 'integer',\n            'description' => '第二个版本ID',\n          ],\n        ],\n        'required' => ['page_id', 'version_id_1', 'version_id_2'],\n      ],\n      'handler' => 'page',\n    ];\n\n    $this->tools['restore_page_version'] = [\n      'name' => 'restore_page_version',\n      'description' => '恢复页面到指定的历史版本',\n      'inputSchema' => [\n        'type' => 'object',\n        'properties' => [\n          'page_id' => [\n            'type' => 'integer',\n            'description' => '页面ID',\n          ],\n          'version_id' => [\n            'type' => 'integer',\n            'description' => '要恢复到的历史版本ID',\n          ],\n        ],\n        'required' => ['page_id', 'version_id'],\n      ],\n      'handler' => 'page',\n    ];\n\n    // 附件管理\n    $this->tools['upload_attachment'] = [\n      'name' => 'upload_attachment',\n      'description' => '上传附件（通过URL或Base64）',\n      'inputSchema' => [\n        'type' => 'object',\n        'properties' => [\n          'item_id' => [\n            'type' => 'integer',\n            'description' => '项目ID',\n          ],\n          'page_id' => [\n            'type' => 'integer',\n            'description' => '页面ID（可选）',\n          ],\n          'file_url' => [\n            'type' => 'string',\n            'description' => '文件URL（与file_base64二选一）',\n          ],\n          'file_base64' => [\n            'type' => 'string',\n            'description' => 'Base64编码的文件内容（与file_url二选一）',\n          ],\n          'file_name' => [\n            'type' => 'string',\n            'description' => '文件名（可选）',\n          ],\n        ],\n        'required' => ['item_id'],\n      ],\n      'handler' => 'attachment',\n    ];\n\n    $this->tools['list_attachments'] = [\n      'name' => 'list_attachments',\n      'description' => '获取项目或页面的附件列表',\n      'inputSchema' => [\n        'type' => 'object',\n        'properties' => [\n          'item_id' => [\n            'type' => 'integer',\n            'description' => '项目ID',\n          ],\n          'page_id' => [\n            'type' => 'integer',\n            'description' => '页面ID（可选，用于筛选特定页面的附件）',\n          ],\n        ],\n        'required' => [],\n      ],\n      'handler' => 'attachment',\n    ];\n\n    $this->tools['delete_attachment'] = [\n      'name' => 'delete_attachment',\n      'description' => '删除附件',\n      'inputSchema' => [\n        'type' => 'object',\n        'properties' => [\n          'file_id' => [\n            'type' => 'integer',\n            'description' => '文件ID（与sign二选一）',\n          ],\n          'sign' => [\n            'type' => 'string',\n            'description' => '文件签名（与file_id二选一）',\n          ],\n        ],\n        'required' => [],\n      ],\n      'handler' => 'attachment',\n    ];\n\n    // OpenAPI 导入\n    $this->tools['import_openapi'] = [\n      'name' => 'import_openapi',\n      'description' => '导入 OpenAPI/Swagger 文档，批量创建/更新 API 页面',\n      'inputSchema' => [\n        'type' => 'object',\n        'properties' => [\n          'item_id' => [\n            'type' => 'integer',\n            'description' => '项目ID（可选，不传则创建新项目）',\n          ],\n          'openapi_content' => [\n            'type' => 'string',\n            'description' => 'OpenAPI/Swagger JSON 内容（与 openapi_url 二选一）',\n          ],\n          'openapi_url' => [\n            'type' => 'string',\n            'description' => 'OpenAPI/Swagger 文档 URL（与 openapi_content 二选一）',\n          ],\n          'format' => [\n            'type' => 'string',\n            'description' => '导入格式：markdown（普通文档，默认）或 runapi（RunApi 项目）',\n          ],\n        ],\n        'required' => [],\n      ],\n      'handler' => 'openapi',\n    ];\n  }\n\n  /**\n   * 注册默认 Resources\n   *\n   * @return void\n   */\n  private function registerDefaultResources(): void\n  {\n    $this->resources = [\n      'showdoc://items' => [\n        'uri' => 'showdoc://items',\n        'name' => '用户可访问的所有项目',\n        'description' => '列出用户有权限访问的所有项目',\n        'mimeType' => 'application/json',\n      ],\n      'showdoc://items/{item_id}' => [\n        'uri' => 'showdoc://items/{item_id}',\n        'name' => '项目详情',\n        'description' => '获取指定项目的详细信息',\n        'mimeType' => 'application/json',\n      ],\n      'showdoc://items/{item_id}/catalogs' => [\n        'uri' => 'showdoc://items/{item_id}/catalogs',\n        'name' => '项目目录树',\n        'description' => '获取指定项目的目录结构',\n        'mimeType' => 'application/json',\n      ],\n      'showdoc://items/{item_id}/pages' => [\n        'uri' => 'showdoc://items/{item_id}/pages',\n        'name' => '项目页面列表',\n        'description' => '获取指定项目的页面列表',\n        'mimeType' => 'application/json',\n      ],\n      'showdoc://pages/{page_id}' => [\n        'uri' => 'showdoc://pages/{page_id}',\n        'name' => '页面详情',\n        'description' => '获取指定页面的详细内容',\n        'mimeType' => 'application/json',\n      ],\n      'showdoc://pages/{page_id}/history' => [\n        'uri' => 'showdoc://pages/{page_id}/history',\n        'name' => '页面修改历史',\n        'description' => '获取指定页面的修改历史列表',\n        'mimeType' => 'application/json',\n      ],\n      'showdoc://pages/{page_id}/versions/{version_id}' => [\n        'uri' => 'showdoc://pages/{page_id}/versions/{version_id}',\n        'name' => '页面指定版本',\n        'description' => '获取指定页面的特定历史版本内容',\n        'mimeType' => 'application/json',\n      ],\n      'showdoc://catalogs/{cat_id}' => [\n        'uri' => 'showdoc://catalogs/{cat_id}',\n        'name' => '目录详情',\n        'description' => '获取指定目录的详细信息',\n        'mimeType' => 'application/json',\n      ],\n    ];\n  }\n\n  /**\n   * 注册默认 Prompts\n   *\n   * @return void\n   */\n  private function registerDefaultPrompts(): void\n  {\n    $this->prompts = [\n      'generate_client_code' => [\n        'name' => 'generate_client_code',\n        'description' => '根据ShowDoc接口文档生成客户端调用代码',\n        'arguments' => [\n          [\n            'name' => 'page_id',\n            'description' => '页面ID，可通过list_pages或search_pages获取',\n            'required' => true,\n          ],\n          [\n            'name' => 'language',\n            'description' => '目标语言：javascript、typescript、python、java、go、php',\n            'required' => false,\n          ],\n          [\n            'name' => 'framework',\n            'description' => '目标框架：axios、fetch、react-query、axios-ts等',\n            'required' => false,\n          ],\n        ],\n      ],\n      'generate_server_code' => [\n        'name' => 'generate_server_code',\n        'description' => '根据ShowDoc接口文档生成服务端接口代码',\n        'arguments' => [\n          [\n            'name' => 'page_id',\n            'description' => '页面ID，可通过list_pages或search_pages获取',\n            'required' => true,\n          ],\n          [\n            'name' => 'language',\n            'description' => '目标语言：nodejs、python、java、go、php',\n            'required' => false,\n          ],\n          [\n            'name' => 'framework',\n            'description' => '目标框架：express、koa、fastapi、spring-boot、gin、laravel等',\n            'required' => false,\n          ],\n        ],\n      ],\n      'generate_docs_from_code' => [\n        'name' => 'generate_docs_from_code',\n        'description' => '根据代码片段生成接口文档',\n        'arguments' => [\n          [\n            'name' => 'code_snippet',\n            'description' => '代码片段',\n            'required' => true,\n          ],\n          [\n            'name' => 'doc_type',\n            'description' => '文档类型：markdown、runapi',\n            'required' => false,\n          ],\n        ],\n      ],\n      'sync_api_docs' => [\n        'name' => 'sync_api_docs',\n        'description' => '扫描代码库，同步整个项目的API文档',\n        'arguments' => [\n          [\n            'name' => 'item_id',\n            'description' => '项目ID',\n            'required' => true,\n          ],\n          [\n            'name' => 'code_base_path',\n            'description' => '代码库路径（可选，用于定位代码文件）',\n            'required' => false,\n          ],\n        ],\n      ],\n      'compare_impl_and_doc' => [\n        'name' => 'compare_impl_and_doc',\n        'description' => '对比代码实现与文档描述的差异',\n        'arguments' => [\n          [\n            'name' => 'page_id',\n            'description' => '页面ID',\n            'required' => true,\n          ],\n          [\n            'name' => 'code_path',\n            'description' => '代码文件路径',\n            'required' => true,\n          ],\n        ],\n      ],\n      'suggest_doc_structure' => [\n        'name' => 'suggest_doc_structure',\n        'description' => '分析项目文档结构，给出优化建议',\n        'arguments' => [\n          [\n            'name' => 'item_id',\n            'description' => '项目ID',\n            'required' => true,\n          ],\n        ],\n      ],\n      'find_outdated_docs' => [\n        'name' => 'find_outdated_docs',\n        'description' => '找出长期未更新的文档',\n        'arguments' => [\n          [\n            'name' => 'item_id',\n            'description' => '项目ID',\n            'required' => true,\n          ],\n          [\n            'name' => 'days',\n            'description' => '未更新天数阈值（默认30天）',\n            'required' => false,\n          ],\n        ],\n      ],\n    ];\n  }\n\n  /**\n   * 设置 Token 信息\n   *\n   * @param array $tokenInfo Token 信息\n   * @return void\n   */\n  public function setTokenInfo(array $tokenInfo): void\n  {\n    $this->tokenInfo = $tokenInfo;\n  }\n\n  /**\n   * 处理 MCP 请求\n   *\n   * @param array $request JSON-RPC 请求数组\n   * @return array JSON-RPC 响应数组\n   */\n  public function handleRequest(array $request): array\n  {\n    // 保存请求 ID\n    $this->requestId = $request['id'] ?? null;\n\n    try {\n      // 验证 JSON-RPC 版本\n      if (($request['jsonrpc'] ?? '') !== '2.0') {\n        return McpError::createResponse(\n          McpError::INVALID_REQUEST,\n          '无效的 JSON-RPC 版本',\n          null,\n          $this->requestId\n        );\n      }\n\n      $method = $request['method'] ?? '';\n      $params = $request['params'] ?? [];\n\n      // 路由到对应的处理方法\n      switch ($method) {\n        case 'initialize':\n          return $this->handleInitialize($params);\n\n        case 'tools/list':\n          return $this->handleToolsList();\n\n        case 'tools/call':\n          return $this->handleToolsCall($params);\n\n        case 'resources/list':\n          return $this->handleResourcesList();\n\n        case 'resources/read':\n          return $this->handleResourcesRead($params);\n\n        case 'resources/templates/list':\n          return $this->handleResourcesTemplatesList();\n\n        case 'prompts/list':\n          return $this->handlePromptsList();\n\n        case 'prompts/get':\n          return $this->handlePromptsGet($params);\n\n        case 'ping':\n          return McpError::createSuccessResponse((object) [], $this->requestId);\n\n        default:\n          return McpError::createResponse(\n            McpError::METHOD_NOT_FOUND,\n            \"方法不存在: {$method}\",\n            null,\n            $this->requestId\n          );\n      }\n    } catch (McpException $e) {\n      return $e->toResponse($this->requestId);\n    } catch (\\Throwable $e) {\n      return McpError::createResponse(\n        McpError::INTERNAL_ERROR,\n        '服务器内部错误: ' . $e->getMessage(),\n        ['trace' => $e->getTraceAsString()],\n        $this->requestId\n      );\n    }\n  }\n\n  /**\n   * 处理 initialize 请求\n   *\n   * @param array $params 参数\n   * @return array\n   */\n  private function handleInitialize(array $params): array\n  {\n    return McpError::createSuccessResponse([\n      'protocolVersion' => '2024-11-05',\n      'capabilities' => [\n        'tools' => [\n          'listChanged' => false,\n        ],\n        'resources' => [\n          'subscribe' => false,\n          'listChanged' => false,\n        ],\n        'prompts' => [\n          'listChanged' => false,\n        ],\n      ],\n      'serverInfo' => [\n        'name' => 'showdoc-mcp',\n        'version' => '1.0.0',\n      ],\n    ], $this->requestId);\n  }\n\n  /**\n   * 处理 tools/list 请求\n   *\n   * @return array\n   */\n  private function handleToolsList(): array\n  {\n    $tools = [];\n    foreach ($this->tools as $name => $tool) {\n      $tools[] = [\n        'name' => $tool['name'],\n        'description' => $tool['description'],\n        'inputSchema' => $tool['inputSchema'],\n      ];\n    }\n\n    return McpError::createSuccessResponse([\n      'tools' => $tools,\n    ], $this->requestId);\n  }\n\n  /**\n   * 处理 tools/call 请求\n   *\n   * @param array $params 参数\n   * @return array\n   */\n  private function handleToolsCall(array $params): array\n  {\n    $toolName = $params['name'] ?? '';\n    $arguments = $params['arguments'] ?? [];\n\n    if (!isset($this->tools[$toolName])) {\n      return McpError::createResponse(\n        McpError::METHOD_NOT_FOUND,\n        \"Tool 不存在: {$toolName}\",\n        null,\n        $this->requestId\n      );\n    }\n\n    $tool = $this->tools[$toolName];\n    $handlerName = $tool['handler'];\n\n    try {\n      $handler = $this->getHandler($handlerName);\n      $handler->setTokenInfo($this->tokenInfo);\n      $result = $handler->execute($toolName, $arguments);\n\n      return McpError::createSuccessResponse([\n        'content' => [\n          [\n            'type' => 'text',\n            'text' => json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),\n          ],\n        ],\n      ], $this->requestId);\n    } catch (McpException $e) {\n      return $e->toResponse($this->requestId);\n    }\n  }\n\n  /**\n   * 处理 resources/list 请求\n   *\n   * @return array\n   */\n  private function handleResourcesList(): array\n  {\n    $resources = array_values($this->resources);\n    return McpError::createSuccessResponse([\n      'resources' => $resources,\n    ], $this->requestId);\n  }\n\n  /**\n   * 处理 resources/read 请求\n   *\n   * @param array $params 参数\n   * @return array\n   */\n  private function handleResourcesRead(array $params): array\n  {\n    $uri = $params['uri'] ?? '';\n\n    // 解析 URI\n    if (strpos($uri, 'showdoc://') !== 0) {\n      return McpError::createResponse(\n        McpError::INVALID_PARAMS,\n        '无效的 URI 格式',\n        null,\n        $this->requestId\n      );\n    }\n\n    // 解析资源路径\n    $path = substr($uri, 10); // 移除 'showdoc://'\n\n    try {\n      if (preg_match('#^pages/(\\d+)/versions/(\\d+)$#', $path, $matches)) {\n        // showdoc://pages/{page_id}/versions/{version_id} -> 重定向到 get_page_version\n        $handler = $this->getHandler('page');\n        $handler->setTokenInfo($this->tokenInfo);\n        $result = $handler->execute('get_page_version', [\n          'page_id' => (int) $matches[1],\n          'version_id' => (int) $matches[2],\n        ]);\n      } elseif (preg_match('#^pages/(\\d+)/history$#', $path, $matches)) {\n        // showdoc://pages/{page_id}/history -> 重定向到 get_page_history\n        $handler = $this->getHandler('page');\n        $handler->setTokenInfo($this->tokenInfo);\n        $result = $handler->execute('get_page_history', ['page_id' => (int) $matches[1]]);\n      } elseif (preg_match('#^catalogs/(\\d+)$#', $path, $matches)) {\n        // showdoc://catalogs/{cat_id} -> 重定向到 get_catalog\n        $handler = $this->getHandler('catalog');\n        $handler->setTokenInfo($this->tokenInfo);\n        $result = $handler->execute('get_catalog', ['cat_id' => (int) $matches[1]]);\n      } elseif (preg_match('#^items/(\\d+)/pages/(\\d+)$#', $path, $matches)) {\n        // showdoc://items/{item_id}/pages/{page_id} -> 重定向到 get_page\n        $handler = $this->getHandler('page');\n        $handler->setTokenInfo($this->tokenInfo);\n        $result = $handler->execute('get_page', ['page_id' => (int) $matches[2]]);\n      } elseif (preg_match('#^items/(\\d+)/catalogs$#', $path, $matches)) {\n        // showdoc://items/{item_id}/catalogs -> 重定向到 list_catalogs\n        $handler = $this->getHandler('catalog');\n        $handler->setTokenInfo($this->tokenInfo);\n        $result = $handler->execute('list_catalogs', ['item_id' => (int) $matches[1]]);\n      } elseif (preg_match('#^items/(\\d+)/pages$#', $path, $matches)) {\n        // showdoc://items/{item_id}/pages -> 重定向到 list_pages\n        $handler = $this->getHandler('page');\n        $handler->setTokenInfo($this->tokenInfo);\n        $result = $handler->execute('list_pages', ['item_id' => (int) $matches[1]]);\n      } elseif (preg_match('#^items/(\\d+)$#', $path, $matches)) {\n        // showdoc://items/{item_id} -> 重定向到 get_item\n        $handler = $this->getHandler('item');\n        $handler->setTokenInfo($this->tokenInfo);\n        $result = $handler->execute('get_item', ['item_id' => (int) $matches[1]]);\n      } elseif ($path === 'items') {\n        // showdoc://items -> 重定向到 list_items\n        $handler = $this->getHandler('item');\n        $handler->setTokenInfo($this->tokenInfo);\n        $result = $handler->execute('list_items', []);\n      } elseif (preg_match('#^pages/(\\d+)$#', $path, $matches)) {\n        // showdoc://pages/{page_id} -> 重定向到 get_page\n        $handler = $this->getHandler('page');\n        $handler->setTokenInfo($this->tokenInfo);\n        $result = $handler->execute('get_page', ['page_id' => (int) $matches[1]]);\n      } else {\n        return McpError::createResponse(\n          McpError::RESOURCE_NOT_FOUND,\n          \"资源不存在: {$uri}\",\n          null,\n          $this->requestId\n        );\n      }\n\n      return McpError::createSuccessResponse([\n        'contents' => [\n          [\n            'uri' => $uri,\n            'mimeType' => 'application/json',\n            'text' => json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),\n          ],\n        ],\n      ], $this->requestId);\n    } catch (McpException $e) {\n      return $e->toResponse($this->requestId);\n    }\n  }\n\n  /**\n   * 处理 resources/templates/list 请求\n   *\n   * @return array\n   */\n  private function handleResourcesTemplatesList(): array\n  {\n    $templates = [];\n    foreach ($this->resources as $resource) {\n      if (strpos($resource['uri'], '{') !== false) {\n        $templates[] = [\n          'uriTemplate' => $resource['uri'],\n          'name' => $resource['name'],\n          'description' => $resource['description'],\n          'mimeType' => $resource['mimeType'],\n        ];\n      }\n    }\n\n    return McpError::createSuccessResponse([\n      'resourceTemplates' => $templates,\n    ], $this->requestId);\n  }\n\n  /**\n   * 处理 prompts/list 请求\n   *\n   * @return array\n   */\n  private function handlePromptsList(): array\n  {\n    $prompts = [];\n    foreach ($this->prompts as $prompt) {\n      $prompts[] = [\n        'name' => $prompt['name'],\n        'description' => $prompt['description'],\n        'arguments' => $prompt['arguments'],\n      ];\n    }\n\n    return McpError::createSuccessResponse([\n      'prompts' => $prompts,\n    ], $this->requestId);\n  }\n\n  /**\n   * 处理 prompts/get 请求\n   *\n   * @param array $params 参数\n   * @return array\n   */\n  private function handlePromptsGet(array $params): array\n  {\n    $promptName = $params['name'] ?? '';\n    $arguments = $params['arguments'] ?? [];\n\n    if (!isset($this->prompts[$promptName])) {\n      return McpError::createResponse(\n        McpError::METHOD_NOT_FOUND,\n        \"Prompt 不存在: {$promptName}\",\n        null,\n        $this->requestId\n      );\n    }\n\n    $prompt = $this->prompts[$promptName];\n    $messages = $this->buildPromptMessages($promptName, $arguments);\n\n    return McpError::createSuccessResponse([\n      'description' => $prompt['description'],\n      'messages' => $messages,\n    ], $this->requestId);\n  }\n\n  /**\n   * 构建 Prompt 消息\n   *\n   * @param string $promptName Prompt 名称\n   * @param array $arguments 参数\n   * @return array\n   */\n  private function buildPromptMessages(string $promptName, array $arguments): array\n  {\n    switch ($promptName) {\n      case 'generate_client_code':\n        $pageId = $arguments['page_id'] ?? '';\n        $language = $arguments['language'] ?? 'javascript';\n        $framework = $arguments['framework'] ?? 'axios';\n\n        return [\n          [\n            'role' => 'user',\n            'content' => [\n              'type' => 'text',\n              'text' => \"请根据 ShowDoc 接口文档生成 {$language} 客户端调用代码。\\n\\n\" .\n                \"页面ID: {$pageId}\\n\" .\n                \"目标语言: {$language}\\n\" .\n                \"目标框架: {$framework}\\n\\n\" .\n                \"请先使用 get_page 工具获取接口文档内容，然后生成对应的客户端代码。\",\n            ],\n          ],\n        ];\n\n      case 'generate_docs_from_code':\n        $codeSnippet = $arguments['code_snippet'] ?? '';\n        $docType = $arguments['doc_type'] ?? 'markdown';\n\n        return [\n          [\n            'role' => 'user',\n            'content' => [\n              'type' => 'text',\n              'text' => \"请根据以下代码片段生成接口文档。\\n\\n\" .\n                \"文档类型: {$docType}\\n\\n\" .\n                \"代码片段:\\n```\\n{$codeSnippet}\\n```\\n\\n\" .\n                \"请分析代码并生成符合 ShowDoc 格式的接口文档。\",\n            ],\n          ],\n        ];\n\n      case 'generate_server_code':\n        $pageId = $arguments['page_id'] ?? '';\n        $language = $arguments['language'] ?? 'nodejs';\n        $framework = $arguments['framework'] ?? 'express';\n\n        return [\n          [\n            'role' => 'user',\n            'content' => [\n              'type' => 'text',\n              'text' => \"请根据 ShowDoc 接口文档生成 {$language} 服务端接口代码。\\n\\n\" .\n                \"页面ID: {$pageId}\\n\" .\n                \"目标语言: {$language}\\n\" .\n                \"目标框架: {$framework}\\n\\n\" .\n                \"请先使用 get_page 工具获取接口文档内容，然后生成对应的服务端接口代码。\",\n            ],\n          ],\n        ];\n\n      case 'sync_api_docs':\n        $itemId = $arguments['item_id'] ?? '';\n        $codeBasePath = $arguments['code_base_path'] ?? '当前目录';\n\n        return [\n          [\n            'role' => 'user',\n            'content' => [\n              'type' => 'text',\n              'text' => \"请扫描代码库并同步项目的 API 文档。\\n\\n\" .\n                \"项目ID: {$itemId}\\n\" .\n                \"代码库路径: {$codeBasePath}\\n\\n\" .\n                \"请执行以下步骤：\\n\" .\n                \"1. 使用 list_pages 工具获取当前项目的所有页面\\n\" .\n                \"2. 扫描代码库中的 API 接口定义\\n\" .\n                \"3. 对比代码与文档的差异\\n\" .\n                \"4. 使用 upsert_page 工具更新或创建文档\",\n            ],\n          ],\n        ];\n\n      case 'compare_impl_and_doc':\n        $pageId = $arguments['page_id'] ?? '';\n        $codePath = $arguments['code_path'] ?? '';\n\n        return [\n          [\n            'role' => 'user',\n            'content' => [\n              'type' => 'text',\n              'text' => \"请对比代码实现与文档描述的差异。\\n\\n\" .\n                \"页面ID: {$pageId}\\n\" .\n                \"代码路径: {$codePath}\\n\\n\" .\n                \"请执行以下步骤：\\n\" .\n                \"1. 使用 get_page 工具获取接口文档内容\\n\" .\n                \"2. 读取代码文件内容\\n\" .\n                \"3. 对比接口定义（URL、参数、返回值等）\\n\" .\n                \"4. 列出差异并给出更新建议\",\n            ],\n          ],\n        ];\n\n      case 'suggest_doc_structure':\n        $itemId = $arguments['item_id'] ?? '';\n\n        return [\n          [\n            'role' => 'user',\n            'content' => [\n              'type' => 'text',\n              'text' => \"请分析项目文档结构并给出优化建议。\\n\\n\" .\n                \"项目ID: {$itemId}\\n\\n\" .\n                \"请执行以下步骤：\\n\" .\n                \"1. 使用 list_catalogs 工具获取目录结构\\n\" .\n                \"2. 使用 list_pages 工具获取页面列表\\n\" .\n                \"3. 分析文档的组织结构、命名规范、完整性\\n\" .\n                \"4. 给出具体的优化建议\",\n            ],\n          ],\n        ];\n\n      case 'find_outdated_docs':\n        $itemId = $arguments['item_id'] ?? '';\n        $days = $arguments['days'] ?? 30;\n\n        return [\n          [\n            'role' => 'user',\n            'content' => [\n              'type' => 'text',\n              'text' => \"请找出项目中长期未更新的文档。\\n\\n\" .\n                \"项目ID: {$itemId}\\n\" .\n                \"未更新天数阈值: {$days} 天\\n\\n\" .\n                \"请执行以下步骤：\\n\" .\n                \"1. 使用 list_pages 工具获取页面列表\\n\" .\n                \"2. 检查每个页面的更新时间\\n\" .\n                \"3. 列出超过 {$days} 天未更新的页面\\n\" .\n                \"4. 按更新时间排序，优先展示最久未更新的文档\",\n            ],\n          ],\n        ];\n\n      default:\n        return [];\n    }\n  }\n\n  /**\n   * 获取 Handler 实例\n   *\n   * @param string $name Handler 名称\n   * @return McpHandler\n   */\n  private function getHandler(string $name): McpHandler\n  {\n    if (!isset($this->handlers[$name])) {\n      switch ($name) {\n        case 'item':\n          $this->handlers[$name] = new ItemHandler();\n          break;\n        case 'catalog':\n          $this->handlers[$name] = new CatalogHandler();\n          break;\n        case 'page':\n          $this->handlers[$name] = new PageHandler();\n          break;\n        case 'attachment':\n          $this->handlers[$name] = new AttachmentHandler();\n          break;\n        case 'openapi':\n          $this->handlers[$name] = new OpenApiHandler();\n          break;\n        default:\n          throw new \\RuntimeException(\"Handler 不存在: {$name}\");\n      }\n    }\n\n    return $this->handlers[$name];\n  }\n}\n"
  },
  {
    "path": "server/app/Model/Attachment.php",
    "content": "<?php\n\nnamespace App\\Model;\n\nuse Illuminate\\Database\\Capsule\\Manager as DB;\nuse App\\Common\\Helper\\OssHelper;\nuse App\\Common\\Helper\\UrlHelper;\nuse App\\Model\\Options;\nuse App\\Model\\UploadFile;\nuse App\\Model\\FilePage;\n\n/**\n * 附件相关模型（兼容旧 AttachmentModel）。\n */\nclass Attachment\n{\n    /**\n     * 获取用户的本月已使用流量\n     *\n     * @param int $uid 用户 ID\n     * @return int 已使用流量（字节）\n     */\n    public static function getUserFlow(int $uid): int\n    {\n        return FileFlow::getUserFlow($uid);\n    }\n\n    /**\n     * 记录用户流量\n     *\n     * @param int $uid 用户 ID\n     * @param int $fileSize 文件大小（字节）\n     * @return bool 是否成功\n     */\n    public static function recordUserFlow(int $uid, int $fileSize): bool\n    {\n        return FileFlow::recordUserFlow($uid, $fileSize);\n    }\n\n    /**\n     * 获取用户的已使用空间\n     *\n     * @param int $uid 用户 ID\n     * @return int 已使用空间（字节）\n     */\n    public static function getUsedSpace(int $uid): int\n    {\n        if ($uid <= 0) {\n            return 0;\n        }\n\n        $used = DB::table('upload_file')\n            ->where('uid', $uid)\n            ->sum('file_size');\n\n        return (int) ($used ?? 0);\n    }\n\n    /**\n     * 判断上传的文件扩展名是否处于白名单内\n     *\n     * @param string $filename 文件名\n     * @return bool 是否允许\n     */\n    public static function isAllowedFilename(string $filename): bool\n    {\n        $allowArray = [\n            '.jpg',\n            '.jpeg',\n            '.png',\n            '.bmp',\n            '.gif',\n            '.ico',\n            '.webp',\n            '.mp3',\n            '.wav',\n            '.mp4',\n            '.mov',\n            '.flac',\n            '.mkv',\n            '.zip',\n            '.tar',\n            '.gz',\n            '.tgz',\n            '.ipa',\n            '.apk',\n            '.rar',\n            '.iso',\n            '.pdf',\n            '.epub',\n            '.xps',\n            '.doc',\n            '.docx',\n            '.wps',\n            '.ppt',\n            '.pptx',\n            '.xls',\n            '.xlsx',\n            '.txt',\n            '.psd',\n            '.csv',\n            '.cer',\n            '.pub',\n            '.json',\n            '.css',\n        ];\n\n        $ext = strtolower(substr($filename, strripos($filename, '.')));\n        return in_array($ext, $allowArray, true);\n    }\n\n    /**\n     * 上传文件（兼容旧开源版 AttachmentModel::upload 逻辑）。\n     *\n     * - 当 Options::get('oss_open') == 1 时，走 OSS 上传（uploadByOptions），real_url 为真实 OSS URL；\n     * - 否则走本地上传，写入 ../Public/Uploads/，real_url 为 site_url()/Public/Uploads/...；\n     * - 始终在 upload_file/file_page 写入记录，并返回 serverUrl('api/attachment/visitFile', ['sign' => $sign])。\n     */\n    public static function upload(array $_files, string $fileKey, int $uid, int $itemId = 0, int $pageId = 0, bool $checkFilename = true)\n    {\n        if (!isset($_files[$fileKey])) {\n            return false;\n        }\n\n        $uploadFile = $_files[$fileKey];\n\n        // 检查文件名白名单（与旧版一致）\n        if ($checkFilename && !self::isAllowedFilename($uploadFile['name'])) {\n            return false;\n        }\n\n        // 根据 oss_open 决定走本地还是 OSS\n        $ossOpen = (int) Options::get('oss_open', 0);\n        if ($ossOpen === 1) {\n            $url = OssHelper::uploadByOptions($uploadFile);\n        } else {\n            $url = self::uploadLocal($uploadFile);\n        }\n\n        if (!$url) {\n            return false;\n        }\n\n        // 与旧版保持一致的 sign 生成规则\n        $sign = md5($url . time() . rand());\n\n        // 写入 upload_file 表\n        $fileId = DB::table('upload_file')->insertGetId([\n            'sign'         => $sign,\n            'uid'          => $uid,\n            'item_id'      => $itemId,\n            'page_id'      => $pageId,\n            'display_name' => $uploadFile['name'],\n            'file_type'    => $uploadFile['type'] ?? '',\n            'file_size'    => $uploadFile['size'] ?? 0,\n            'real_url'     => $url,\n            'addtime'      => time(),\n        ]);\n\n        // 写入 file_page 表\n        DB::table('file_page')->insert([\n            'file_id' => $fileId,\n            'item_id' => $itemId,\n            'page_id' => $pageId,\n            'addtime' => time(),\n        ]);\n\n        // 返回 visitFile 的访问 URL（兼容旧版）\n        return UrlHelper::serverUrl('api/attachment/visitFile', ['sign' => $sign]);\n    }\n\n    /**\n     * 删除文件（兼容旧开源版 AttachmentModel::deleteFile 逻辑）。\n     *\n     * - 优先尝试根据 real_url 删除本地 ../Public/Uploads/ 下的文件；\n     * - 如果本地删不到，再尝试通过 OssHelper::deleteByOptions 删除远程 OSS；\n     * - 最后删除 upload_file 和 file_page 记录。\n     */\n    public static function deleteFile(int $fileId): bool\n    {\n        if ($fileId <= 0) {\n            return false;\n        }\n\n        $file = DB::table('upload_file')->where('file_id', $fileId)->first();\n        if (!$file) {\n            return false;\n        }\n\n        $realUrl = (string) ($file->real_url ?? '');\n\n        // 优先删除本地 Public/Uploads 文件\n        $deletedLocal = false;\n        if (!empty($realUrl)) {\n            $deletedLocal = self::deleteLocalByUrl($realUrl);\n        }\n\n        // 如果本地删不到，再尝试删除 OSS\n        if (!$deletedLocal && !empty($realUrl)) {\n            OssHelper::deleteByOptions($realUrl);\n        }\n\n        // 删除数据库记录\n        DB::table('upload_file')->where('file_id', $fileId)->delete();\n        DB::table('file_page')->where('file_id', $fileId)->delete();\n\n        return true;\n    }\n\n    /**\n     * 本地上传到 ../Public/Uploads/，返回完整 URL（与旧版行为等价）。\n     *\n     * @param array $uploadFile 单个 $_FILES 元素\n     * @return string|false\n     */\n    private static function uploadLocal(array $uploadFile)\n    {\n        if (empty($uploadFile['tmp_name']) || !is_file($uploadFile['tmp_name'])) {\n            return false;\n        }\n\n        // 计算 Public/Uploads 真实路径：项目根目录下的 Public/Uploads\n        $projectRoot = dirname(__DIR__, 3); // .../showdoc\n        $uploadRoot = $projectRoot . DIRECTORY_SEPARATOR . 'Public' . DIRECTORY_SEPARATOR . 'Uploads' . DIRECTORY_SEPARATOR;\n\n        // 按日期分子目录（与 ThinkPHP Upload 默认行为类似）\n        $subDir = date('Y-m-d') . DIRECTORY_SEPARATOR;\n        $targetDir = $uploadRoot . $subDir;\n        if (!is_dir($targetDir) && !mkdir($targetDir, 0755, true) && !is_dir($targetDir)) {\n            return false;\n        }\n\n        $ext = '';\n        if (isset($uploadFile['name']) && strrpos($uploadFile['name'], '.') !== false) {\n            $ext = substr($uploadFile['name'], strrpos($uploadFile['name'], '.'));\n        }\n\n        // 使用三个 uniqid 拼接的字母数字串作为文件名（不包含点号等特殊符号）\n        $randomName = uniqid('', false) . uniqid('', false) . uniqid('', false);\n        $saveName = $randomName . $ext;\n        $targetPath = $targetDir . $saveName;\n\n        // 优先使用 move_uploaded_file，失败则回退到 rename\n        if (!@move_uploaded_file($uploadFile['tmp_name'], $targetPath)) {\n            if (!@rename($uploadFile['tmp_name'], $targetPath)) {\n                return false;\n            }\n        }\n\n        // 构造对外可访问的 URL（site_url()/Public/Uploads/xxx）\n        $relative = 'Public/Uploads/' . str_replace(DIRECTORY_SEPARATOR, '/', $subDir . $saveName);\n        return UrlHelper::siteUrl() . '/' . $relative;\n    }\n\n    /**\n     * 根据 real_url 尝试删除本地 Public/Uploads 下的文件。\n     */\n    private static function deleteLocalByUrl(string $realUrl): bool\n    {\n        $parts = explode('/Public/Uploads/', $realUrl);\n        if (count($parts) < 2 || empty($parts[1])) {\n            return false;\n        }\n\n        $relativePath = str_replace(['\\\\', '//'], '/', $parts[1]);\n\n        $projectRoot = dirname(__DIR__, 3); // .../showdoc\n        $filePath = $projectRoot . DIRECTORY_SEPARATOR . 'Public' . DIRECTORY_SEPARATOR . 'Uploads' . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $relativePath);\n\n        if (is_file($filePath)) {\n            @unlink($filePath);\n            return true;\n        }\n\n        return false;\n    }\n}\n"
  },
  {
    "path": "server/app/Model/Captcha.php",
    "content": "<?php\n\nnamespace App\\Model;\n\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\nclass Captcha\n{\n    /**\n     * 按旧版 CaptchaModel 逻辑校验验证码。\n     */\n    public static function check(int $captchaId, string $captcha, string $mobile = ''): bool\n    {\n        $captchaId = (int) $captchaId;\n        $captcha   = trim($captcha);\n\n        if ($captchaId <= 0 || $captcha === '') {\n            return false;\n        }\n\n        $now = time();\n\n        $query = DB::table('captcha')\n            ->where('captcha_id', $captchaId)\n            ->where('expire_time', '>', $now);\n\n        if ($mobile !== '') {\n            $query->where('mobile', $mobile);\n        }\n\n        $row = $query->first();\n\n        // 忽略大小写比较验证码内容\n        if ($row && isset($row->captcha) && strtolower((string) $row->captcha) === strtolower($captcha)) {\n            // 验证成功：立即将验证码置为过期\n            DB::table('captcha')\n                ->where('captcha_id', $captchaId)\n                ->update(['expire_time' => 0]);\n\n            return true;\n        }\n\n        // 验证失败：有效期减少 10 秒，防止被暴力枚举\n        if ($row && isset($row->expire_time)) {\n            $newExpire = max(0, (int) $row->expire_time - 10);\n            DB::table('captcha')\n                ->where('captcha_id', $captchaId)\n                ->update(['expire_time' => $newExpire]);\n        }\n\n        return false;\n    }\n}\n"
  },
  {
    "path": "server/app/Model/Catalog.php",
    "content": "<?php\n\nnamespace App\\Model;\n\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\nclass Catalog\n{\n    /**\n     * 根据目录 ID 查找目录\n     *\n     * @param int $catId 目录 ID\n     * @return object|null\n     */\n    public static function findById(int $catId): ?object\n    {\n        if ($catId <= 0) {\n            return null;\n        }\n\n        return DB::table('catalog')\n            ->where('cat_id', $catId)\n            ->first();\n    }\n\n    /**\n     * 根据父目录 ID 查找目录\n     *\n     * @param int $parentCatId 父目录 ID\n     * @return object|null\n     */\n    public static function findByParentId(int $parentCatId): ?object\n    {\n        if ($parentCatId <= 0) {\n            return null;\n        }\n\n        return DB::table('catalog')\n            ->where('parent_cat_id', $parentCatId)\n            ->first();\n    }\n\n    /**\n     * 根据目录 ID 和项目 ID 查找目录\n     *\n     * @param int $catId 目录 ID\n     * @param int $itemId 项目 ID\n     * @return object|null\n     */\n    public static function findByIdAndItemId(int $catId, int $itemId): ?object\n    {\n        if ($catId <= 0 || $itemId <= 0) {\n            return null;\n        }\n\n        return DB::table('catalog')\n            ->where('cat_id', $catId)\n            ->where('item_id', $itemId)\n            ->first();\n    }\n\n    /**\n     * 获取目录列表\n     *\n     * @param int $itemId 项目 ID\n     * @param bool $isGroup 是否按分组返回（树形结构）\n     * @return array 目录列表\n     */\n    public static function getList(int $itemId, bool $isGroup = false): array\n    {\n        if ($itemId <= 0) {\n            return [];\n        }\n\n        $rows = DB::table('catalog')\n            ->where('item_id', $itemId)\n            ->orderBy('s_number', 'asc')\n            ->orderBy('cat_id', 'asc')\n            ->get()\n            ->all();\n\n        if (empty($rows)) {\n            return [];\n        }\n\n        $result = [];\n        foreach ($rows as $row) {\n            $data = (array) $row;\n            $data['addtime'] = date('Y-m-d H:i:s', (int) ($data['addtime'] ?? time()));\n            $result[] = $data;\n        }\n\n        if ($isGroup) {\n            $result = self::buildTree($result);\n        }\n\n        return $result;\n    }\n\n    /**\n     * 构建目录树\n     *\n     * @param array $catalogs 所有目录\n     * @return array 树形结构的目录\n     */\n    private static function buildTree(array $catalogs): array\n    {\n        $tree = [];\n        foreach ($catalogs as $catalog) {\n            $parentCatId = (int) ($catalog['parent_cat_id'] ?? 0);\n            if ($parentCatId === 0) {\n                // 根目录\n                $catalog['sub'] = self::getChildren($catalog['cat_id'], $catalogs);\n                $tree[] = $catalog;\n            }\n        }\n        return $tree;\n    }\n\n    /**\n     * 递归获取子目录\n     *\n     * @param int $catId 目录 ID\n     * @param array $catalogs 所有目录\n     * @return array 子目录列表\n     */\n    private static function getChildren(int $catId, array $catalogs): array\n    {\n        $children = [];\n        foreach ($catalogs as $catalog) {\n            if ((int) ($catalog['parent_cat_id'] ?? 0) === $catId) {\n                $catalog['sub'] = self::getChildren($catalog['cat_id'], $catalogs);\n                $children[] = $catalog;\n            }\n        }\n        return $children;\n    }\n\n    /**\n     * 根据层级获取目录列表\n     *\n     * @param int $itemId 项目 ID\n     * @param int $level 层级（2=二级目录，3=三级目录等）\n     * @return array 目录列表\n     */\n    public static function getListByLevel(int $itemId, int $level = 2): array\n    {\n        if ($itemId <= 0) {\n            return [];\n        }\n\n        $rows = DB::table('catalog')\n            ->where('item_id', $itemId)\n            ->where('level', $level)\n            ->orderBy('s_number', 'asc')\n            ->orderBy('cat_id', 'asc')\n            ->get()\n            ->all();\n\n        $result = [];\n        foreach ($rows as $row) {\n            $data = (array) $row;\n            $data['addtime'] = date('Y-m-d H:i:s', (int) ($data['addtime'] ?? time()));\n            $result[] = $data;\n        }\n\n        return $result;\n    }\n\n    /**\n     * 获取某个目录的子目录列表\n     *\n     * @param int $itemId 项目 ID\n     * @param int $catId 目录 ID\n     * @return array 子目录列表\n     */\n    public static function getChildrenByCatId(int $itemId, int $catId): array\n    {\n        if ($itemId <= 0 || $catId <= 0) {\n            return [];\n        }\n\n        $allCatalogs = self::getList($itemId, true);\n        return self::findChildrenInTree($allCatalogs, $catId);\n    }\n\n    /**\n     * 在树形结构中查找指定目录的子目录\n     *\n     * @param array $tree 目录树\n     * @param int $catId 目录 ID\n     * @return array 子目录列表\n     */\n    private static function findChildrenInTree(array $tree, int $catId): array\n    {\n        foreach ($tree as $catalog) {\n            if ((int) ($catalog['cat_id'] ?? 0) === $catId) {\n                return $catalog['sub'] ?? [];\n            }\n            if (!empty($catalog['sub'])) {\n                $found = self::findChildrenInTree($catalog['sub'], $catId);\n                if (!empty($found)) {\n                    return $found;\n                }\n            }\n        }\n        return [];\n    }\n\n    /**\n     * 过滤成员目录（根据用户目录权限）\n     *\n     * @param int $uid 用户 ID\n     * @param array $catData 目录数据\n     * @return array 过滤后的目录数据\n     */\n    public static function filterMemberCat(int $uid, array $catData): array\n    {\n        if (empty($catData) || $uid <= 0) {\n            return $catData;\n        }\n\n        $itemId = (int) ($catData[0]['item_id'] ?? 0);\n        if ($itemId <= 0) {\n            return $catData;\n        }\n\n        // 获取用户在该项目下拥有权限的目录 ID 集合\n        $catIds = \\App\\Model\\Member::getCatIds($itemId, $uid);\n        if (empty($catIds)) {\n            // 没有目录权限限制，返回原数据\n            return $catData;\n        }\n\n        $allowed = array_flip(array_map('intval', $catIds));\n        $filtered = [];\n\n        foreach ($catData as $catalog) {\n            $catId = (int) ($catalog['cat_id'] ?? 0);\n            if (isset($allowed[$catId])) {\n                // 如果有子目录，递归过滤\n                if (!empty($catalog['sub'])) {\n                    $catalog['sub'] = self::filterMemberCat($uid, $catalog['sub']);\n                }\n                $filtered[] = $catalog;\n            }\n        }\n\n        return $filtered;\n    }\n\n    /**\n     * 保存目录（新建或更新）\n     *\n     * @param int $catId 目录 ID（0 表示新建）\n     * @param int $itemId 项目 ID\n     * @param string $catName 目录名称\n     * @param int $parentCatId 父目录 ID\n     * @param int $sNumber 排序号\n     * @return array 保存后的目录数据\n     */\n    public static function save(int $catId, int $itemId, string $catName, int $parentCatId = 0, int $sNumber = 0): ?array\n    {\n        if ($itemId <= 0 || empty($catName)) {\n            return null;\n        }\n\n        $data = [\n            'cat_name'     => $catName,\n            'item_id'      => $itemId,\n            'parent_cat_id' => $parentCatId,\n        ];\n\n        if ($sNumber > 0) {\n            $data['s_number'] = $sNumber;\n        }\n\n        // 计算层级\n        if ($parentCatId > 0) {\n            $parent = self::findById($parentCatId);\n            if ($parent) {\n                $data['level'] = (int) ($parent->level ?? 2) + 1;\n            } else {\n                $data['level'] = 2;\n            }\n        } else {\n            $data['level'] = 2;\n        }\n\n        if ($catId > 0) {\n            // 更新\n            try {\n                $affected = DB::table('catalog')\n                    ->where('cat_id', $catId)\n                    ->update($data);\n                if ($affected > 0) {\n                    $row = DB::table('catalog')\n                        ->where('cat_id', $catId)\n                        ->first();\n                    return $row ? (array) $row : null;\n                }\n                return null;\n            } catch (\\Throwable $e) {\n                return null;\n            }\n        } else {\n            // 新建\n            $data['addtime'] = time();\n            try {\n                $catId = DB::table('catalog')->insertGetId($data);\n                if ($catId > 0) {\n                    $row = DB::table('catalog')\n                        ->where('cat_id', $catId)\n                        ->first();\n                    return $row ? (array) $row : null;\n                }\n                return null;\n            } catch (\\Throwable $e) {\n                return null;\n            }\n        }\n    }\n\n    /**\n     * 获取目录数量\n     *\n     * @param int $itemId 项目 ID\n     * @return int 目录数量\n     */\n    public static function getCount(int $itemId): int\n    {\n        if ($itemId <= 0) {\n            return 0;\n        }\n\n        return DB::table('catalog')\n            ->where('item_id', $itemId)\n            ->count();\n    }\n\n    /**\n     * 根据目录路径保存目录（如果不存在则创建）\n     * 路径格式：'二级目录/三级目录/四级目录'\n     *\n     * @param string $catPath 目录路径\n     * @param int $itemId 项目 ID\n     * @return int|false 返回最后一层目录的 ID，失败返回 false\n     */\n    public static function saveCatPath(string $catPath, int $itemId)\n    {\n        if (empty($catPath) || strlen($catPath) > 1000 || $itemId <= 0) {\n            return false;\n        }\n\n        // 如果路径以 / 开头且长度大于1，则去掉第一个 /\n        if (substr($catPath, 0, 1) == '/' && strlen($catPath) > 1) {\n            $catPath = substr($catPath, 1);\n        }\n\n        $catalogArray = explode('/', $catPath);\n        $catIdsArray = [];\n\n        for ($i = 0; $i < count($catalogArray); $i++) {\n            $level = $i + 2; // 二级目录从 level=2 开始\n            $catName = trim($catalogArray[$i]);\n            if (empty($catName)) {\n                continue;\n            }\n\n            $parentCatId = 0;\n            if ($i > 0) {\n                // 非顶级目录，应该有 parent_cat_id\n                $parentCatId = $catIdsArray[$i - 1] ?? 0;\n            }\n\n            // 查找是否已存在该目录\n            $existing = DB::table('catalog')\n                ->where('item_id', $itemId)\n                ->where('level', $level)\n                ->where('cat_name', $catName)\n                ->where('parent_cat_id', $parentCatId)\n                ->first();\n\n            if ($existing) {\n                $catIdsArray[$i] = (int) $existing->cat_id;\n            } else {\n                // 创建新目录\n                $addData = [\n                    'cat_name'      => $catName,\n                    'item_id'       => $itemId,\n                    'addtime'       => time(),\n                    'level'         => $level,\n                    'parent_cat_id' => $parentCatId,\n                ];\n                $catId = DB::table('catalog')->insertGetId($addData);\n                if ($catId > 0) {\n                    $catIdsArray[$i] = (int) $catId;\n                } else {\n                    return false;\n                }\n            }\n        }\n\n        // 返回最后一层目录的 ID\n        if (!empty($catIdsArray)) {\n            return end($catIdsArray);\n        }\n\n        return false;\n    }\n\n    /**\n     * 获取指定目录 ID 及其所有子目录的 ID（递归）\n     * 用于扩展目录权限，使搜索能够覆盖子目录下的页面\n     *\n     * @param int $itemId 项目 ID\n     * @param array $catIds 初始目录 ID 数组\n     * @return array 包含所有子目录的 ID 数组\n     */\n    public static function expandCatIdsWithChildren(int $itemId, array $catIds): array\n    {\n        if ($itemId <= 0 || empty($catIds)) {\n            return $catIds;\n        }\n\n        // 获取项目下所有目录\n        $allCatalogs = self::getList($itemId);\n        if (empty($allCatalogs)) {\n            return $catIds;\n        }\n\n        // 构建 parent_cat_id -> [child_cat_ids] 的映射\n        $parentToChildren = [];\n        foreach ($allCatalogs as $catalog) {\n            $parentId = (int) ($catalog['parent_cat_id'] ?? 0);\n            $childId = (int) ($catalog['cat_id'] ?? 0);\n            if ($parentId > 0 && $childId > 0) {\n                if (!isset($parentToChildren[$parentId])) {\n                    $parentToChildren[$parentId] = [];\n                }\n                $parentToChildren[$parentId][] = $childId;\n            }\n        }\n\n        // 递归获取所有子目录 ID\n        $result = array_map('intval', $catIds);\n        $toProcess = $result;\n\n        while (!empty($toProcess)) {\n            $currentId = array_shift($toProcess);\n            if (isset($parentToChildren[$currentId])) {\n                foreach ($parentToChildren[$currentId] as $childId) {\n                    if (!in_array($childId, $result, true)) {\n                        $result[] = $childId;\n                        $toProcess[] = $childId;\n                    }\n                }\n            }\n        }\n\n        return array_values(array_unique($result));\n    }\n\n    /**\n     * 删除目录（包括子目录和页面）\n     *\n     * @param int $catId 目录 ID\n     * @return bool 是否成功\n     */\n    public static function deleteCat(int $catId): bool\n    {\n        if ($catId <= 0) {\n            return false;\n        }\n\n        $catalog = self::findById($catId);\n        if (!$catalog) {\n            return false;\n        }\n\n        $itemId = (int) $catalog->item_id;\n\n        try {\n            // 获取所有子目录\n            $subCatalogs = DB::table('catalog')\n                ->where('item_id', $itemId)\n                ->where('parent_cat_id', $catId)\n                ->get()\n                ->all();\n\n            // 递归删除子目录\n            foreach ($subCatalogs as $subCatalog) {\n                self::deleteCat((int) $subCatalog->cat_id);\n            }\n\n            // 删除该目录下的所有页面（软删除）\n            // 开源版：使用单表 page，不支持分表\n            $table = 'page';\n            DB::table($table)\n                ->where('item_id', $itemId)\n                ->where('cat_id', $catId)\n                ->update(['is_del' => 1]);\n\n            // 删除目录\n            $affected = DB::table('catalog')\n                ->where('cat_id', $catId)\n                ->delete();\n\n            if ($affected > 0) {\n                // 删除缓存\n                \\App\\Model\\Item::deleteCache($itemId);\n                return true;\n            }\n\n            return false;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "server/app/Model/ExportLog.php",
    "content": "<?php\n\nnamespace App\\Model;\n\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\nclass ExportLog\n{\n    /**\n     * 添加导出日志\n     *\n     * @param array $data 日志数据\n     * @return int|false 返回插入的ID，失败返回false\n     */\n    public static function add(array $data)\n    {\n        $id = DB::table('export_log')->insertGetId($data);\n        return $id ?: false;\n    }\n\n    /**\n     * 获取用户当天的导出次数\n     *\n     * @param int $uid 用户ID\n     * @param string $exportType 导出类型（word/markdown等）\n     * @return int 导出次数\n     */\n    public static function getTodayCount(int $uid, string $exportType): int\n    {\n        if ($uid <= 0) {\n            return 0;\n        }\n\n        // 根据数据库类型使用不同的 SQL 语法\n        $driver = DB::connection()->getDriverName();\n        if ($driver === 'sqlite') {\n            // SQLite 语法：addtime 是时间戳，需要转换为日期进行比较\n            $whereRaw = \"strftime('%Y-%m-%d', addtime, 'unixepoch') = date('now')\";\n        } else {\n            // MySQL 语法：addtime 是时间戳，使用 FROM_UNIXTIME 转换\n            $whereRaw = \"to_days(FROM_UNIXTIME(addtime)) = to_days(now())\";\n        }\n\n        return (int) DB::table('export_log')\n            ->where('uid', $uid)\n            ->where('export_type', $exportType)\n            ->whereRaw($whereRaw)\n            ->count();\n    }\n\n    /**\n     * 获取用户最近N天的导出次数\n     *\n     * @param int $uid 用户ID\n     * @param string $exportType 导出类型\n     * @param int $days 天数（默认3天）\n     * @return int 导出次数\n     */\n    public static function getRecentDaysCount(int $uid, string $exportType, int $days = 3): int\n    {\n        if ($uid <= 0) {\n            return 0;\n        }\n\n        // 根据数据库类型使用不同的 SQL 语法\n        $driver = DB::connection()->getDriverName();\n        if ($driver === 'sqlite') {\n            // SQLite 语法：addtime 是时间戳，计算 N 天前的时间戳\n            $intervalDays = $days - 1;\n            $daysAgoTimestamp = time() - ($intervalDays * 24 * 60 * 60);\n            $whereRaw = \"addtime >= ?\";\n            $bindings = [$daysAgoTimestamp];\n        } else {\n            // MySQL 语法：addtime 是时间戳，使用 UNIX_TIMESTAMP 转换\n            $whereRaw = \"addtime >= UNIX_TIMESTAMP(DATE_SUB(CURDATE(),INTERVAL ? DAY))\";\n            $bindings = [$days - 1];\n        }\n\n        return (int) DB::table('export_log')\n            ->where('uid', $uid)\n            ->where('export_type', $exportType)\n            ->whereRaw($whereRaw, $bindings)\n            ->count();\n    }\n}\n"
  },
  {
    "path": "server/app/Model/FileFlow.php",
    "content": "<?php\n\nnamespace App\\Model;\n\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\n/**\n * 开源版文件流量统计模型（兼容主版 FileFlow，用于记录附件访问流量）。\n *\n * 说明：\n * - 如果数据库中不存在 file_flow 表，调用这些方法也只会返回 false / 0，不会抛异常；\n * - 这样即使开源版用户没有建表，也不会影响附件访问功能本身。\n */\nclass FileFlow\n{\n    /**\n     * 获取用户的本月已使用流量\n     *\n     * @param int $uid 用户 ID\n     * @return int 已使用流量（字节）\n     */\n    public static function getUserFlow(int $uid): int\n    {\n        if ($uid <= 0) {\n            return 0;\n        }\n\n        $month = date('Y-m');\n\n        try {\n            $fileFlow = DB::table('file_flow')\n                ->where('uid', $uid)\n                ->where('date_month', $month)\n                ->first();\n        } catch (\\Throwable $e) {\n            // 如果表不存在或查询失败，直接返回 0，避免影响主流程\n            return 0;\n        }\n\n        if ($fileFlow) {\n            return (int) ($fileFlow->used ?? 0);\n        }\n\n        // 如果不存在，尝试创建记录（忽略并发下的重复键错误）\n        try {\n            DB::table('file_flow')->insert([\n                'uid'        => $uid,\n                'used'       => 0,\n                'date_month' => $month,\n            ]);\n        } catch (\\Throwable $e) {\n            // 忽略错误\n        }\n\n        return 0;\n    }\n\n    /**\n     * 记录用户流量\n     *\n     * @param int $uid 用户 ID\n     * @param int $fileSize 文件大小（字节）\n     * @return bool 是否成功\n     */\n    public static function recordUserFlow(int $uid, int $fileSize): bool\n    {\n        if ($uid <= 0 || $fileSize <= 0) {\n            return false;\n        }\n\n        $month = date('Y-m');\n        $used  = self::getUserFlow($uid);\n\n        try {\n            $affected = DB::table('file_flow')\n                ->where('uid', $uid)\n                ->where('date_month', $month)\n                ->update(['used' => $used + $fileSize]);\n\n            return $affected > 0;\n        } catch (\\Throwable $e) {\n            // 表不存在或更新失败时，不影响主流程\n            return false;\n        }\n    }\n}\n\n\n"
  },
  {
    "path": "server/app/Model/FilePage.php",
    "content": "<?php\n\nnamespace App\\Model;\n\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\nclass FilePage\n{\n    /**\n     * 获取页面的附件数量\n     *\n     * @param int $pageId 页面 ID\n     * @return int 附件数量\n     */\n    public static function getAttachmentCount(int $pageId): int\n    {\n        if ($pageId <= 0) {\n            return 0;\n        }\n\n        return DB::table('file_page')\n            ->where('page_id', $pageId)\n            ->count();\n    }\n\n    /**\n     * 添加文件页面关联\n     *\n     * @param int $fileId 文件 ID\n     * @param int $itemId 项目 ID\n     * @param int $pageId 页面 ID\n     * @return int 关联 ID，失败返回 0\n     */\n    public static function add(int $fileId, int $itemId, int $pageId): int\n    {\n        if ($fileId <= 0 || $itemId <= 0 || $pageId <= 0) {\n            return 0;\n        }\n\n        try {\n            $id = DB::table('file_page')->insertGetId([\n                'file_id' => $fileId,\n                'item_id' => $itemId,\n                'page_id' => $pageId,\n                'addtime' => time(),\n            ]);\n            return (int) $id;\n        } catch (\\Throwable $e) {\n            return 0;\n        }\n    }\n\n    /**\n     * 删除文件页面关联\n     *\n     * @param int $fileId 文件 ID\n     * @param int $pageId 页面 ID\n     * @return bool 是否成功\n     */\n    public static function delete(int $fileId, int $pageId): bool\n    {\n        if ($fileId <= 0 || $pageId <= 0) {\n            return false;\n        }\n\n        try {\n            $deleted = DB::table('file_page')\n                ->where('file_id', $fileId)\n                ->where('page_id', $pageId)\n                ->delete();\n            return $deleted > 0;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 获取文件关联的页面数量\n     *\n     * @param int $fileId 文件 ID\n     * @return int 页面数量\n     */\n    public static function getPageCount(int $fileId): int\n    {\n        if ($fileId <= 0) {\n            return 0;\n        }\n\n        return DB::table('file_page')\n            ->where('file_id', $fileId)\n            ->where('page_id', '>', 0)\n            ->count();\n    }\n\n    /**\n     * 获取页面的附件列表\n     *\n     * @param int $pageId 页面 ID\n     * @return array 附件列表\n     */\n    public static function getPageAttachments(int $pageId): array\n    {\n        if ($pageId <= 0) {\n            return [];\n        }\n\n        $rows = DB::table('file_page')\n            ->join('upload_file', 'file_page.file_id', '=', 'upload_file.file_id')\n            ->select([\n                'upload_file.*',\n                'file_page.item_id',\n                'file_page.page_id',\n            ])\n            ->where('file_page.page_id', $pageId)\n            ->orderBy('file_page.addtime', 'desc')\n            ->get()\n            ->all();\n\n        $result = [];\n        foreach ($rows as $row) {\n            $data = (array) $row;\n            $result[] = [\n                'file_id'     => (int) $data['file_id'],\n                'display_name' => $data['display_name'] ?? '',\n                'addtime'     => date('Y-m-d H:i:s', (int) ($data['addtime'] ?? time())),\n            ];\n        }\n\n        return $result;\n    }\n\n    /**\n     * 根据文件 ID 和项目 ID 查找文件页面关联\n     *\n     * @param int $fileId 文件 ID\n     * @param int $itemId 项目 ID\n     * @return array|null 关联数据\n     */\n    public static function findByFileIdAndItemId(int $fileId, int $itemId): ?array\n    {\n        if ($fileId <= 0 || $itemId <= 0) {\n            return null;\n        }\n\n        $row = DB::table('file_page')\n            ->where('file_id', $fileId)\n            ->where('item_id', $itemId)\n            ->first();\n\n        return $row ? (array) $row : null;\n    }\n}\n"
  },
  {
    "path": "server/app/Model/Item.php",
    "content": "<?php\n\nnamespace App\\Model;\n\nuse Illuminate\\Database\\Capsule\\Manager as DB;\nuse App\\Common\\Cache\\CacheManager;\nuse App\\Model\\Page;\n\nclass Item\n{\n    public static function findById(int $itemId): ?object\n    {\n        if ($itemId <= 0) {\n            return null;\n        }\n\n        return DB::table('item')\n            ->where('item_id', $itemId)\n            ->where('is_del', 0)\n            ->first();\n    }\n\n    public static function findByDomain(string $domain): ?object\n    {\n        $domain = trim($domain);\n        if ($domain === '') {\n            return null;\n        }\n\n        return DB::table('item')\n            ->where('item_domain', $domain)\n            ->where('is_del', 0)\n            ->first();\n    }\n\n    public static function isWhitelisted(int $itemId): bool\n    {\n        if ($itemId <= 0) {\n            return false;\n        }\n\n        $row = DB::table('item_whitelist')\n            ->where('item_id', $itemId)\n            ->first();\n\n        return $row !== null;\n    }\n\n    /**\n     * 获取菜单结构（不含缓存）\n     *\n     * @param int $itemId 项目 ID\n     * @return array 菜单结构：['pages' => [...], 'catalogs' => [...]]\n     */\n    public static function getMenu(int $itemId): array\n    {\n        if ($itemId <= 0) {\n            return ['pages' => [], 'catalogs' => []];\n        }\n\n        // 获取所有页面（cat_id=0 的为根目录页面）\n        // 开源版：使用单表 page，不支持分表\n        $table = 'page';\n        $allPages = DB::table($table)\n            ->select(['page_id', 'author_uid', 'cat_id', 'page_title', 'addtime', 'ext_info', 'is_draft'])\n            ->where('item_id', $itemId)\n            ->where('is_del', 0)\n            ->orderBy('s_number', 'asc')\n            ->orderBy('page_id', 'asc')\n            ->get()\n            ->all();\n\n        $pages = [];\n        foreach ($allPages as $page) {\n            if (empty($page->cat_id)) {\n                $pages[] = (array) $page;\n            }\n        }\n\n        // 获取所有目录\n        $allCatalogs = DB::table('catalog')\n            ->where('item_id', $itemId)\n            ->orderBy('s_number', 'asc')\n            ->orderBy('cat_id', 'asc')\n            ->get()\n            ->all();\n\n        // 获取所有二级目录\n        $catalogs = [];\n        foreach ($allCatalogs as $catalog) {\n            if ((int) $catalog->level === 2) {\n                $catalogs[] = self::buildCatalogTree((array) $catalog, $allPages, $allCatalogs);\n            }\n        }\n\n        return [\n            'pages'    => $pages,\n            'catalogs' => $catalogs,\n        ];\n    }\n\n    /**\n     * 递归构建目录树\n     *\n     * @param array $catalogData 目录数据\n     * @param array $allPages 所有页面\n     * @param array $allCatalogs 所有目录\n     * @return array 构建好的目录树\n     */\n    private static function buildCatalogTree(array $catalogData, array $allPages, array $allCatalogs): array\n    {\n        $catId = (int) $catalogData['cat_id'];\n\n        // 获取该目录下的页面\n        $catalogData['pages'] = [];\n        foreach ($allPages as $page) {\n            if ((int) $page->cat_id === $catId) {\n                $catalogData['pages'][] = (array) $page;\n            }\n        }\n\n        // 获取该目录下的子目录\n        $catalogData['catalogs'] = [];\n        foreach ($allCatalogs as $catalog) {\n            if ((int) $catalog->parent_cat_id === $catId) {\n                $catalogData['catalogs'][] = self::buildCatalogTree((array) $catalog, $allPages, $allCatalogs);\n            }\n        }\n\n        return $catalogData;\n    }\n\n    /**\n     * 获取带缓存的菜单结构\n     *\n     * @param int $itemId 项目 ID\n     * @return array 菜单结构\n     */\n    public static function getMenuByCache(int $itemId): array\n    {\n        if ($itemId <= 0) {\n            return ['pages' => [], 'catalogs' => []];\n        }\n\n        $cacheKey = 'showdoc_menu_cache_item_id_' . $itemId;\n        $cache    = CacheManager::getInstance();\n        $menu     = $cache->get($cacheKey);\n\n        if ($menu === null) {\n            // 缓存不存在，从数据库读取\n            $menu = self::getMenu($itemId);\n            // 写入缓存，24小时过期\n            $cache->set($cacheKey, $menu, 60 * 60 * 24);\n        }\n\n        return $menu;\n    }\n\n    /**\n     * 根据用户目录权限过滤菜单\n     *\n     * @param int $uid 用户 ID\n     * @param int $itemId 项目 ID\n     * @param array $menu 菜单结构\n     * @return array 过滤后的菜单结构\n     */\n    public static function filterMemberItem(int $uid, int $itemId, array $menu): array\n    {\n        if ($uid <= 0 || $itemId <= 0 || empty($menu)) {\n            return $menu;\n        }\n\n        // 获取用户在该项目下拥有权限的目录 ID 集合\n        $catIds = self::getUserCatIds($itemId, $uid);\n        if (empty($catIds)) {\n            // 没有目录权限限制，返回原菜单\n            return $menu;\n        }\n\n        $allowedCatIds = array_flip(array_map('intval', $catIds));\n\n        // 过滤二级目录\n        if (!empty($menu['catalogs'])) {\n            $filteredCatalogs = [];\n            foreach ($menu['catalogs'] as $catalog) {\n                $catId = (int) ($catalog['cat_id'] ?? 0);\n                if (isset($allowedCatIds[$catId])) {\n                    $filteredCatalogs[] = $catalog;\n                }\n            }\n            $menu['catalogs'] = $filteredCatalogs;\n        }\n\n        return $menu;\n    }\n\n    /**\n     * 获取用户在项目下拥有权限的目录 ID 集合\n     *\n     * @param int $itemId 项目 ID\n     * @param int $uid 用户 ID\n     * @return array 目录 ID 数组\n     */\n    private static function getUserCatIds(int $itemId, int $uid): array\n    {\n        // 直接复用 Member::getCatIds 的旧版逻辑实现\n        return Member::getCatIds($itemId, $uid);\n    }\n\n    /**\n     * 删除菜单缓存\n     *\n     * @param int $itemId 项目 ID\n     * @return bool 是否删除成功\n     */\n    public static function deleteCache(int $itemId): bool\n    {\n        if ($itemId <= 0) {\n            return false;\n        }\n\n        $cacheKey = 'showdoc_menu_cache_item_id_' . $itemId;\n        $cache    = CacheManager::getInstance();\n        return $cache->delete($cacheKey);\n    }\n\n    /**\n     * 更新菜单缓存中的页面标题\n     *\n     * @param int $itemId 项目 ID\n     * @param int $pageId 页面 ID\n     * @param string $pageTitle 新标题\n     * @return bool 是否更新成功\n     */\n    public static function updateMenuCachePage(int $itemId, int $pageId, string $pageTitle): bool\n    {\n        if ($itemId <= 0 || $pageId <= 0) {\n            return false;\n        }\n\n        $cacheKey = 'showdoc_menu_cache_item_id_' . $itemId;\n        $cache    = CacheManager::getInstance();\n        $menu     = $cache->get($cacheKey);\n\n        if ($menu === null) {\n            // 缓存不存在，无需更新\n            return true;\n        }\n\n        // 递归更新页面标题\n        $updated = self::updatePageTitleInMenu($menu, $pageId, $pageTitle);\n\n        if ($updated) {\n            // 重新写入缓存\n            $cache->set($cacheKey, $menu, 60 * 60 * 24);\n        }\n\n        return $updated;\n    }\n\n    /**\n     * 在菜单结构中递归更新页面标题\n     *\n     * @param array &$menu 菜单结构（引用传递）\n     * @param int $pageId 页面 ID\n     * @param string $pageTitle 新标题\n     * @return bool 是否找到并更新\n     */\n    private static function updatePageTitleInMenu(array &$menu, int $pageId, string $pageTitle): bool\n    {\n        $found = false;\n\n        // 更新根目录下的页面\n        if (!empty($menu['pages'])) {\n            foreach ($menu['pages'] as &$page) {\n                if ((int) ($page['page_id'] ?? 0) === $pageId) {\n                    $page['page_title'] = $pageTitle;\n                    $found              = true;\n                }\n            }\n            unset($page);\n        }\n\n        // 递归更新目录下的页面\n        if (!empty($menu['catalogs'])) {\n            foreach ($menu['catalogs'] as &$catalog) {\n                if (self::updatePageTitleInCatalog($catalog, $pageId, $pageTitle)) {\n                    $found = true;\n                }\n            }\n            unset($catalog);\n        }\n\n        return $found;\n    }\n\n    /**\n     * 在目录中递归更新页面标题\n     *\n     * @param array &$catalog 目录数据（引用传递）\n     * @param int $pageId 页面 ID\n     * @param string $pageTitle 新标题\n     * @return bool 是否找到并更新\n     */\n    private static function updatePageTitleInCatalog(array &$catalog, int $pageId, string $pageTitle): bool\n    {\n        $found = false;\n\n        // 更新当前目录下的页面\n        if (!empty($catalog['pages'])) {\n            foreach ($catalog['pages'] as &$page) {\n                if ((int) ($page['page_id'] ?? 0) === $pageId) {\n                    $page['page_title'] = $pageTitle;\n                    $found              = true;\n                }\n            }\n            unset($page);\n        }\n\n        // 递归更新子目录\n        if (!empty($catalog['catalogs'])) {\n            foreach ($catalog['catalogs'] as &$subCatalog) {\n                if (self::updatePageTitleInCatalog($subCatalog, $pageId, $pageTitle)) {\n                    $found = true;\n                }\n            }\n            unset($subCatalog);\n        }\n\n        return $found;\n    }\n\n    /**\n     * 导出项目数据为 JSON\n     *\n     * @param int $itemId 项目 ID\n     * @param bool $uncompress 是否解压内容\n     * @return string JSON 字符串\n     */\n    public static function export(int $itemId, bool $uncompress = false): string\n    {\n        if ($itemId <= 0) {\n            return json_encode([]);\n        }\n\n        $item = self::findById($itemId);\n        if (!$item) {\n            return json_encode([]);\n        }\n\n        $itemData = [\n            'item_type'        => $item->item_type ?? 1,\n            'item_name'        => $item->item_name ?? '',\n            'item_description' => $item->item_description ?? '',\n            'password'         => $item->password ?? '',\n        ];\n\n        // 获取菜单结构（包含页面内容）\n        $menu = self::getContent($itemId, $uncompress);\n        $itemData['pages'] = $menu;\n\n        // 获取项目成员\n        $members = ItemMember::getList($itemId);\n        $itemData['members'] = array_map(function ($member) {\n            return [\n                // member_group_id 需要返回字符串数字，兼容旧前端\n                'member_group_id' => (string) ($member['member_group_id'] ?? '0'),\n                'uid'             => (int) ($member['uid'] ?? 0),\n                'username'        => $member['username'] ?? '',\n            ];\n        }, $members);\n\n        return json_encode($itemData, JSON_UNESCAPED_UNICODE);\n    }\n\n    /**\n     * 获取项目内容（菜单结构）\n     *\n     * @param int $itemId 项目 ID\n     * @param bool $uncompress 是否解压内容\n     * @return array 菜单结构\n     */\n    public static function getContent(int $itemId, bool $uncompress = false): array\n    {\n        if ($itemId <= 0) {\n            return ['pages' => [], 'catalogs' => []];\n        }\n\n        // 开源版：使用单表 page，不支持分表\n        $table = 'page';\n        $pageField = 'page_id,page_title,cat_id,page_content,s_number,page_comments';\n        $catalogField = 'cat_id,cat_name,parent_cat_id,level,s_number';\n\n        // 获取所有页面\n        $allPages = DB::table($table)\n            ->select(explode(',', $pageField))\n            ->where('item_id', $itemId)\n            ->where('is_del', 0)\n            ->orderBy('s_number', 'asc')\n            ->orderBy('page_id', 'asc')\n            ->get()\n            ->all();\n\n        $pages = [];\n        foreach ($allPages as $page) {\n            $pageData = (array) $page;\n            // 跳过草稿页面（导出不包含草稿）\n            if (($pageData['is_draft'] ?? 0) == 1) {\n                continue;\n            }\n            // 开源版：page_content 不压缩存储，但兼容旧压缩数据\n            if ($uncompress && !empty($pageData['page_content'])) {\n                $decoded = \\App\\Common\\Helper\\ContentCodec::decompress($pageData['page_content']);\n                if ($decoded !== '' && $decoded !== $pageData['page_content']) {\n                    // 是压缩数据，解压后返回\n                    $pageData['page_content'] = $decoded;\n                }\n                // 未压缩数据，直接返回\n            }\n            if (empty($pageData['cat_id'])) {\n                $pages[] = $pageData;\n            }\n        }\n\n        // 获取所有目录\n        $allCatalogs = DB::table('catalog')\n            ->select(explode(',', $catalogField))\n            ->where('item_id', $itemId)\n            ->orderBy('s_number', 'asc')\n            ->orderBy('cat_id', 'asc')\n            ->get()\n            ->all();\n\n        // 获取所有二级目录\n        $catalogs = [];\n        foreach ($allCatalogs as $catalog) {\n            if ((int) ($catalog->level ?? 0) === 2) {\n                $catalogData = (array) $catalog;\n                $catalogs[] = self::buildCatalogTreeForExport($catalogData, $allPages, $allCatalogs, $uncompress);\n            }\n        }\n\n        return [\n            'pages'    => $pages,\n            'catalogs' => $catalogs,\n        ];\n    }\n\n    /**\n     * 构建目录树（用于导出）\n     *\n     * @param array $catalogData 目录数据\n     * @param array $allPages 所有页面\n     * @param array $allCatalogs 所有目录\n     * @param bool $uncompress 是否解压内容\n     * @return array 构建好的目录树\n     */\n    private static function buildCatalogTreeForExport(array $catalogData, array $allPages, array $allCatalogs, bool $uncompress): array\n    {\n        $catId = (int) $catalogData['cat_id'];\n\n        // 获取该目录下的页面\n        $catalogData['pages'] = [];\n        foreach ($allPages as $page) {\n            if ((int) ($page->cat_id ?? 0) === $catId) {\n                $pageData = (array) $page;\n                // 跳过草稿页面（导出不包含草稿）\n                if (($pageData['is_draft'] ?? 0) == 1) {\n                    continue;\n                }\n                // 开源版：page_content 不压缩存储，但兼容旧压缩数据\n                if ($uncompress && !empty($pageData['page_content'])) {\n                    $decoded = \\App\\Common\\Helper\\ContentCodec::decompress($pageData['page_content']);\n                    if ($decoded !== '' && $decoded !== $pageData['page_content']) {\n                        // 是压缩数据，解压后返回\n                        $pageData['page_content'] = $decoded;\n                    }\n                    // 未压缩数据，直接返回\n                }\n                $catalogData['pages'][] = $pageData;\n            }\n        }\n\n        // 获取该目录下的子目录\n        $catalogData['catalogs'] = [];\n        foreach ($allCatalogs as $catalog) {\n            if ((int) ($catalog->parent_cat_id ?? 0) === $catId) {\n                $subCatalogData = (array) $catalog;\n                $catalogData['catalogs'][] = self::buildCatalogTreeForExport($subCatalogData, $allPages, $allCatalogs, $uncompress);\n            }\n        }\n\n        return $catalogData;\n    }\n\n    /**\n     * 导入项目数据\n     *\n     * @param string $json JSON 字符串\n     * @param int $uid 用户 ID\n     * @param int $itemId 项目 ID（0 表示新建项目）\n     * @param string $itemName 项目名称（可选）\n     * @param string $itemDescription 项目描述（可选）\n     * @param string $itemPassword 项目密码（可选）\n     * @param string $itemDomain 项目域名（可选）\n     * @return int|false 返回项目 ID，失败返回 false\n     */\n    public static function import(\n        string $json,\n        int $uid,\n        int $itemId = 0,\n        string $itemName = '',\n        string $itemDescription = '',\n        string $itemPassword = '',\n        string $itemDomain = ''\n    ) {\n        $user = User::findById($uid);\n        if (!$user) {\n            return false;\n        }\n\n        $item = json_decode($json, true);\n        if (!$item) {\n            return false;\n        }\n\n        // 如果存在 item_id，那就是项目内导入\n        if ($itemId > 0) {\n            // 项目内导入，不需要创建新项目\n        } else {\n            // 新建项目\n            if (!empty($item['item_domain'])) {\n                // 检查个性域名是否已存在\n                $existing = self::findByDomain($item['item_domain']);\n                if ($existing) {\n                    return false; // 个性域名已经存在\n                }\n                if (!ctype_alnum($itemDomain) || is_numeric($itemDomain)) {\n                    return false; // 个性域名只能是字母或数字的组合\n                }\n            } else {\n                $item['item_domain'] = '';\n            }\n\n            $itemData = [\n                'item_name'        => $itemName ?: htmlspecialchars(htmlspecialchars_decode($item['item_name'] ?? '')),\n                'item_domain'      => $itemDomain ?: htmlspecialchars(htmlspecialchars_decode($item['item_domain'] ?? '')),\n                'item_type'        => (int) ($item['item_type'] ?? 1),\n                'item_description' => $itemDescription ?: htmlspecialchars(htmlspecialchars_decode($item['item_description'] ?? '')),\n                'password'         => $itemPassword ?: htmlspecialchars(htmlspecialchars_decode($item['password'] ?? '')),\n                'uid'              => $uid,\n                'username'          => $user->username ?? '',\n                'addtime'           => time(),\n            ];\n\n            // 创建新项目（需要实现 add 方法）\n            $itemId = self::add($itemData);\n            if ($itemId <= 0) {\n                return false;\n            }\n        }\n\n        // 导入页面\n        if (!empty($item['pages'])) {\n            // 父页面们（一级目录）\n            if (!empty($item['pages']['pages'])) {\n                foreach ($item['pages']['pages'] as $value) {\n                    // 与旧版逻辑一致：使用 _htmlspecialchars 处理\n                    // 之所以先 htmlspecialchars_decode 是为了防止被 htmlspecialchars 转义了两次\n                    $pageData = [\n                        'author_uid'      => $uid,\n                        'author_username' => $user->username ?? '',\n                        'page_title'       => htmlspecialchars(htmlspecialchars_decode($value['page_title'] ?? '')),\n                        'page_content'    => htmlspecialchars(htmlspecialchars_decode($value['page_content'] ?? '')),\n                        's_number'         => (int) ($value['s_number'] ?? 99),\n                        'page_comments'    => htmlspecialchars(htmlspecialchars_decode($value['page_comments'] ?? '')),\n                    ];\n                    Page::addPage($itemId, $pageData);\n                }\n            }\n\n            // 二级目录及以下\n            if (!empty($item['pages']['catalogs'])) {\n                $catPathPages = self::toItemPageCatPath($item['pages']['catalogs']);\n                foreach ($catPathPages as $value) {\n                    Page::updateByTitle(\n                        $itemId,\n                        $value['page_title'] ?? '',\n                        $value['page_content'] ?? '',\n                        $value['cat_path'] ?? '',\n                        (int) ($value['s_number'] ?? 99),\n                        $uid,\n                        $user->username ?? ''\n                    );\n                }\n            }\n        }\n\n        return $itemId;\n    }\n\n    /**\n     * 把目录嵌套的项目页面数据平摊为目录路径形式\n     *\n     * @param array $catalogs 目录数组\n     * @param string $parentCatName 父目录路径\n     * @return array 页面数组（包含 cat_path）\n     */\n    public static function toItemPageCatPath(array $catalogs, string $parentCatName = ''): array\n    {\n        if (empty($catalogs)) {\n            return [];\n        }\n\n        $returnArray = [];\n\n        foreach ($catalogs as $value) {\n            $catName = $value['cat_name'] ?? '';\n            if (empty($catName)) {\n                continue;\n            }\n\n            if ($parentCatName) {\n                $catPath = $parentCatName . '/' . $catName;\n            } else {\n                $catPath = $catName;\n            }\n\n            // 该目录下的页面们\n            if (!empty($value['pages'])) {\n                foreach ($value['pages'] as $page) {\n                    $page['cat_path'] = $catPath;\n                    unset($page['cat_name'], $page['level']);\n                    $returnArray[] = $page;\n                }\n            }\n\n            // 该目录的子目录\n            if (!empty($value['catalogs'])) {\n                $subArray = self::toItemPageCatPath($value['catalogs'], $catPath);\n                $returnArray = array_merge($returnArray, $subArray);\n            }\n        }\n\n        return $returnArray;\n    }\n\n    /**\n     * 添加项目（新建）\n     *\n     * @param array $data 项目数据（如果包含 item_id，则使用该值；否则自动生成）\n     * @return int 新创建的项目 ID，失败返回 0\n     */\n    public static function add(array $data): int\n    {\n        if (empty($data['uid']) || empty($data['item_name'])) {\n            return 0;\n        }\n\n        try {\n            // 如果已经指定了 item_id，直接插入；否则使用 insertGetId 自动生成\n            if (!empty($data['item_id'])) {\n                DB::table('item')->insert($data);\n                return (int) $data['item_id'];\n            } else {\n                $itemId = DB::table('item')->insertGetId($data);\n                return (int) $itemId;\n            }\n        } catch (\\Throwable $e) {\n            return 0;\n        }\n    }\n\n    /**\n     * 获取已删除的项目（超过指定天数）\n     *\n     * @param int $days 天数\n     * @param int $limit 限制数量\n     * @return array 项目列表\n     */\n    public static function getDeletedItems(int $days, int $limit = 1000): array\n    {\n        if ($days <= 0) {\n            return [];\n        }\n\n        $time = time() - ($days * 24 * 60 * 60);\n        $rows = DB::table('item')\n            ->where('is_del', 1)\n            ->where('last_update_time', '<', $time)\n            ->limit($limit)\n            ->get()\n            ->all();\n\n        $result = [];\n        foreach ($rows as $row) {\n            $result[] = (array) $row;\n        }\n\n        return $result;\n    }\n\n    /**\n     * 删除单个项目（物理删除，兼容旧版 delete_item 方法）\n     * \n     * 旧版实现：\n     * - 删除 page 表数据\n     * - 删除 catalog 表数据\n     * - 删除 page_history 表数据\n     * - 删除 item_member 表数据\n     * - 删除 team_item 表数据\n     * - 删除 team_item_member 表数据\n     * - 最后删除 item 表数据\n     *\n     * @param int $itemId 项目 ID\n     * @return bool 是否成功\n     */\n    public static function deleteItem(int $itemId): bool\n    {\n        if ($itemId <= 0) {\n            return false;\n        }\n\n        try {\n            DB::beginTransaction();\n\n            // 1. 删除 page 表数据（开源版：单表，无分表）\n            DB::table('page')\n                ->where('item_id', $itemId)\n                ->delete();\n\n            // 2. 删除 catalog 表数据\n            DB::table('catalog')\n                ->where('item_id', $itemId)\n                ->delete();\n\n            // 3. 删除 page_history 表数据（开源版：单表，无分表）\n            DB::table('page_history')\n                ->where('item_id', $itemId)\n                ->delete();\n\n            // 4. 删除 item_member 表数据\n            DB::table('item_member')\n                ->where('item_id', $itemId)\n                ->delete();\n\n            // 5. 删除 team_item 表数据\n            DB::table('team_item')\n                ->where('item_id', $itemId)\n                ->delete();\n\n            // 6. 删除 team_item_member 表数据\n            DB::table('team_item_member')\n                ->where('item_id', $itemId)\n                ->delete();\n\n            // 7. 最后删除 item 表数据\n            $affected = DB::table('item')\n                ->where('item_id', $itemId)\n                ->delete();\n\n            DB::commit();\n\n            // 清理缓存\n            self::deleteCache($itemId);\n\n            return $affected > 0;\n        } catch (\\Throwable $e) {\n            DB::rollBack();\n            return false;\n        }\n    }\n\n    /**\n     * 删除项目（物理删除）\n     *\n     * @param string $itemIdStr 项目 ID 字符串（逗号分隔）\n     * @return bool 是否成功\n     */\n    public static function deleteItems(string $itemIdStr): bool\n    {\n        if (empty($itemIdStr)) {\n            return false;\n        }\n\n        $itemIds = array_filter(array_map('intval', explode(',', $itemIdStr)));\n        if (empty($itemIds)) {\n            return false;\n        }\n\n        try {\n            DB::beginTransaction();\n\n            // 1. 删除 page 表数据（开源版：单表，无分表）\n            DB::table('page')\n                ->whereIn('item_id', $itemIds)\n                ->delete();\n\n            // 2. 删除 catalog 表数据\n            DB::table('catalog')\n                ->whereIn('item_id', $itemIds)\n                ->delete();\n\n            // 3. 删除 page_history 表数据（开源版：单表，无分表）\n            DB::table('page_history')\n                ->whereIn('item_id', $itemIds)\n                ->delete();\n\n            // 4. 删除 item_change_log 表数据（开源版：单表，无分表）\n            DB::table('item_change_log')\n                ->whereIn('item_id', $itemIds)\n                ->delete();\n\n            // 6. 删除 item_member 表数据\n            DB::table('item_member')\n                ->whereIn('item_id', $itemIds)\n                ->delete();\n\n            // 7. 删除 team_item 表数据\n            DB::table('team_item')\n                ->whereIn('item_id', $itemIds)\n                ->delete();\n\n            // 8. 删除 team_item_member 表数据\n            DB::table('team_item_member')\n                ->whereIn('item_id', $itemIds)\n                ->delete();\n\n            // 9. 最后删除 item 表数据\n            $affected = DB::table('item')\n                ->whereIn('item_id', $itemIds)\n                ->delete();\n\n            DB::commit();\n\n            // 清理缓存\n            foreach ($itemIds as $itemId) {\n                self::deleteCache($itemId);\n            }\n\n            return $affected > 0;\n        } catch (\\Throwable $e) {\n            DB::rollBack();\n            return false;\n        }\n    }\n\n    /**\n     * 软删除项目\n     *\n     * @param int $itemId 项目 ID\n     * @return bool 是否成功\n     */\n    public static function softDeleteItem(int $itemId): bool\n    {\n        if ($itemId <= 0) {\n            return false;\n        }\n\n        try {\n            $affected = DB::table('item')\n                ->where('item_id', $itemId)\n                ->update(['is_del' => 1]);\n            return $affected > 0;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 获取不活跃账号的示例项目\n     *\n     * @param array $uidArray 用户 ID 数组\n     * @return array 项目列表\n     */\n    public static function getInactiveDemoItems(array $uidArray): array\n    {\n        if (empty($uidArray)) {\n            return [];\n        }\n\n        $demoNames = ['技术团队文档示例', '数据字典示例', 'API文档示例', '表格示例', 'runapi默认项目'];\n        $rows = DB::table('item')\n            ->where('last_update_time', 0)\n            ->whereIn('uid', $uidArray)\n            ->whereIn('item_name', $demoNames)\n            ->get()\n            ->all();\n\n        $result = [];\n        foreach ($rows as $row) {\n            $result[] = (array) $row;\n        }\n\n        return $result;\n    }\n\n    /**\n     * 创建一个新的可用的 item_id（兼容旧版 get_a_new_item_id）\n     *\n     * @return int 新的 item_id\n     */\n    public static function getANewItemId(): int\n    {\n        $row = DB::table('item')\n            ->orderBy('item_id', 'desc')\n            ->select('item_id')\n            ->first();\n\n        $maxItemId = $row ? (int) $row->item_id : 0;\n        $newItemId = $maxItemId + rand(10000, 1000000);\n\n        return $newItemId;\n    }\n\n    /**\n     * 复制项目（兼容旧版 copy 方法）\n     *\n     * @param int $itemId 源项目 ID\n     * @param int $uid 新项目创建者 ID\n     * @param string $itemName 新项目名称（可选）\n     * @param string $itemDescription 新项目描述（可选）\n     * @param string $itemPassword 新项目密码（可选）\n     * @param string $itemDomain 新项目域名（可选）\n     * @return int|false 新项目 ID，失败返回 false\n     */\n    public static function copy(int $itemId, int $uid, string $itemName = '', string $itemDescription = '', string $itemPassword = '', string $itemDomain = '')\n    {\n        // 导出源项目数据\n        $json = self::export($itemId, true); // true 表示解压内容\n\n        if (empty($json)) {\n            return false;\n        }\n\n        // 导入为新项目\n        return self::import($json, $uid, 0, $itemName, $itemDescription, $itemPassword, $itemDomain);\n    }\n\n    /**\n     * 过滤草稿页面（非作者不可见）\n     *\n     * @param array $menu 菜单结构\n     * @param int $uid 当前用户 ID（0 表示游客）\n     * @return array 过滤后的菜单结构\n     */\n    public static function filterDraftPages(array $menu, int $uid): array\n    {\n        // 过滤根目录页面\n        if (!empty($menu['pages'])) {\n            $menu['pages'] = array_values(array_filter($menu['pages'], function($page) use ($uid) {\n                $isDraft = (int) ($page['is_draft'] ?? 0);\n                $authorUid = (int) ($page['author_uid'] ?? 0);\n                return $isDraft === 0 || $authorUid === $uid;\n            }));\n        }\n\n        // 递归过滤目录中的页面\n        if (!empty($menu['catalogs'])) {\n            $menu['catalogs'] = array_map(function($catalog) use ($uid) {\n                return self::filterDraftInCatalog($catalog, $uid);\n            }, $menu['catalogs']);\n        }\n\n        return $menu;\n    }\n\n    /**\n     * 递归过滤目录中的草稿页面\n     *\n     * @param array $catalog 目录数据\n     * @param int $uid 当前用户 ID\n     * @return array 过滤后的目录数据\n     */\n    private static function filterDraftInCatalog(array $catalog, int $uid): array\n    {\n        if (!empty($catalog['pages'])) {\n            $catalog['pages'] = array_values(array_filter($catalog['pages'], function($page) use ($uid) {\n                $isDraft = (int) ($page['is_draft'] ?? 0);\n                $authorUid = (int) ($page['author_uid'] ?? 0);\n                return $isDraft === 0 || $authorUid === $uid;\n            }));\n        }\n\n        if (!empty($catalog['catalogs'])) {\n            $catalog['catalogs'] = array_map(function($subCatalog) use ($uid) {\n                return self::filterDraftInCatalog($subCatalog, $uid);\n            }, $catalog['catalogs']);\n        }\n\n        return $catalog;\n    }\n}\n"
  },
  {
    "path": "server/app/Model/ItemAiConfig.php",
    "content": "<?php\n\nnamespace App\\Model;\n\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\nclass ItemAiConfig\n{\n    /**\n     * 获取项目的 AI 配置\n     *\n     * @param int $itemId 项目 ID\n     * @return array AI 配置信息\n     */\n    public static function getConfig(int $itemId): array\n    {\n        if ($itemId <= 0) {\n            return ['enabled' => 0, 'dialog_collapsed' => 1];\n        }\n\n        $row = DB::table('item_ai_config')\n            ->where('item_id', $itemId)\n            ->first();\n\n        if (!$row) {\n            return ['enabled' => 0, 'dialog_collapsed' => 1];\n        }\n\n        return [\n            'enabled'           => (int) ($row->enabled ?? 0),\n            'dialog_collapsed'  => (int) ($row->dialog_collapsed ?? 1),\n            'welcome_message'   => (string) ($row->welcome_message ?? ''),\n        ];\n    }\n\n    /**\n     * 保存项目的 AI 配置\n     *\n     * @param int $itemId 项目 ID\n     * @param array $config AI 配置数据\n     * @return bool 是否成功\n     */\n    public static function saveConfig(int $itemId, array $config): bool\n    {\n        if ($itemId <= 0) {\n            return false;\n        }\n\n        try {\n            $exists = DB::table('item_ai_config')\n                ->where('item_id', $itemId)\n                ->exists();\n\n            // 准备更新数据\n            $saveData = [\n                'updatetime' => time(),\n            ];\n\n            // 只更新提供的字段\n            if (isset($config['enabled'])) {\n                $saveData['enabled'] = (int) $config['enabled'];\n            }\n            if (isset($config['dialog_collapsed'])) {\n                $saveData['dialog_collapsed'] = (int) $config['dialog_collapsed'];\n            }\n            if (isset($config['welcome_message'])) {\n                $saveData['welcome_message'] = (string) $config['welcome_message'];\n            }\n\n            // 如果没有任何字段需要更新（除了 updatetime），返回 false\n            if (count($saveData) <= 1) {\n                return false;\n            }\n\n            if ($exists) {\n                DB::table('item_ai_config')\n                    ->where('item_id', $itemId)\n                    ->update($saveData);\n            } else {\n                $saveData['item_id'] = $itemId;\n                $saveData['addtime'] = time();\n                DB::table('item_ai_config')->insert($saveData);\n            }\n\n            return true;\n        } catch (\\Throwable $e) {\n            // 记录异常信息，便于调试\n            error_log('ItemAiConfig::saveConfig failed: ' . $e->getMessage());\n            error_log($e->getTraceAsString());\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "server/app/Model/ItemBlacklist.php",
    "content": "<?php\n\nnamespace App\\Model;\n\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\nclass ItemBlacklist\n{\n    /**\n     * 检查用户是否有权限访问项目\n     *\n     * @param int $itemId 项目 ID\n     * @param array $user 用户信息\n     * @return array ['allowed' => bool, 'error_msg' => string]\n     */\n    public static function checkAccess(int $itemId, array $user): array\n    {\n        // 开源版无黑名单功能，始终允许访问\n        return [\n            'allowed' => true,\n            'error_msg' => '',\n        ];\n    }\n\n    /**\n     * 检查项目是否在黑名单中\n     *\n     * @param int $itemId 项目 ID\n     * @return object|null 开源版始终返回 null\n     */\n    public static function findByItemId(int $itemId): ?object\n    {\n        // 开源版无黑名单功能\n        return null;\n    }\n}\n"
  },
  {
    "path": "server/app/Model/ItemChangeLog.php",
    "content": "<?php\n\nnamespace App\\Model;\n\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\n/**\n * 项目变更日志模型（开源版：使用单表 item_change_log，不支持分表）\n */\nclass ItemChangeLog\n{\n    /**\n     * 添加变更日志\n     *\n     * @param int $uid 用户 ID\n     * @param int $itemId 项目 ID\n     * @param string $opActionType 操作动作类型（create/update/delete 等）\n     * @param string $opObjectType 操作对象类型（page/item 等）\n     * @param int $opObjectId 操作对象 ID\n     * @param string $opObjectName 操作对象名称\n     * @param string $remark 备注\n     * @return bool 是否成功\n     */\n    public static function addLog(\n        int $uid,\n        int $itemId,\n        string $opActionType,\n        string $opObjectType,\n        int $opObjectId,\n        string $opObjectName = '',\n        string $remark = ''\n    ): bool {\n        if ($uid <= 0 || $itemId <= 0) {\n            return false;\n        }\n\n        try {\n            DB::table('item_change_log')->insert([\n                'uid'            => $uid,\n                'item_id'        => $itemId,\n                'op_action_type' => $opActionType,\n                'op_object_type' => $opObjectType,\n                'op_object_id'   => $opObjectId,\n                'op_object_name' => $opObjectName,\n                'remark'         => $remark,\n                'optime'         => date('Y-m-d H:i:s'),\n            ]);\n\n            // 统计有多少条日志记录了\n            $count = DB::table('item_change_log')\n                ->where('item_id', $itemId)\n                ->count();\n\n            // 每个项目只保留最多300个变更记录\n            $keepCount = 300;\n            if ($count > $keepCount) {\n                $rows = DB::table('item_change_log')\n                    ->where('item_id', $itemId)\n                    ->orderBy('id', 'desc')\n                    ->limit($keepCount)\n                    ->get()\n                    ->all();\n\n                if (!empty($rows) && count($rows) >= $keepCount) {\n                    $lastId = (int) ($rows[$keepCount - 1]->id ?? 0);\n                    if ($lastId > 0) {\n                        DB::table('item_change_log')\n                            ->where('item_id', $itemId)\n                            ->where('id', '<', $lastId)\n                            ->delete();\n                    }\n                }\n            }\n\n            return true;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 获取变更日志列表\n     *\n     * @param int $itemId 项目 ID\n     * @param int $page 页码\n     * @param int $count 每页数量\n     * @return array 包含 total 和 list 的数组\n     */\n    public static function getLog(int $itemId, int $page = 1, int $count = 15): array\n    {\n        if ($itemId <= 0) {\n            return ['total' => 0, 'list' => []];\n        }\n\n        $total = DB::table('item_change_log')\n            ->where('item_id', $itemId)\n            ->count();\n\n        $offset = ($page - 1) * $count;\n        $rows = DB::table('item_change_log')\n            ->where('item_id', $itemId)\n            ->orderBy('optime', 'desc')\n            ->offset($offset)\n            ->limit($count)\n            ->get()\n            ->all();\n\n        $list = [];\n        foreach ($rows as $row) {\n            $list[] = self::renderOneLog((array) $row);\n        }\n\n        return [\n            'total' => (int) $total,\n            'list'  => $list,\n        ];\n    }\n\n    /**\n     * 渲染单条日志为人类可读的格式\n     *\n     * @param array $one 日志数据\n     * @return array 渲染后的日志数据\n     */\n    private static function renderOneLog(array $one): array\n    {\n        $uid = (int) ($one['uid'] ?? 0);\n        $user = User::findById($uid);\n\n        $one['username'] = $user ? ($user->username ?? '') : '';\n        $one['name'] = $user ? ($user->name ?? '') : '';\n        $oper = $one['username'];\n        if (!empty($one['name'])) {\n            $oper = $one['username'] . '(' . $one['name'] . ')';\n        }\n        $one['oper'] = $oper;\n\n        // 操作类型描述\n        $actionTypeMap = [\n            'create' => '创建',\n            'update' => '修改',\n            'delete' => '删除',\n            'export' => '导出',\n            'binding' => '绑定',\n            'unbound' => '解绑',\n            'drag' => '拖曳修改',\n        ];\n        $one['op_action_type_desc'] = $actionTypeMap[$one['op_action_type'] ?? ''] ?? '未定义';\n\n        // 对象类型描述\n        $objectTypeMap = [\n            'page'   => '页面(或接口)',\n            'catalog' => '目录',\n            'item'   => '项目',\n            'team'   => '团队',\n            'member' => '成员',\n            'tree'   => '目录树',\n        ];\n        $one['op_object_type_desc'] = $objectTypeMap[$one['op_object_type'] ?? ''] ?? '未定义';\n\n        return $one;\n    }\n}\n\n"
  },
  {
    "path": "server/app/Model/ItemGroup.php",
    "content": "<?php\n\nnamespace App\\Model;\n\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\nclass ItemGroup\n{\n    /**\n     * 添加项目分组\n     *\n     * @param int $uid 用户 ID\n     * @param string $groupName 分组名称\n     * @param string $itemIds 项目 ID 列表（逗号分隔）\n     * @return int 新创建的分组 ID，失败返回 0\n     */\n    public static function add(int $uid, string $groupName, string $itemIds = ''): int\n    {\n        if ($uid <= 0 || empty($groupName)) {\n            return 0;\n        }\n\n        try {\n            $id = DB::table('item_group')->insertGetId([\n                'uid'        => $uid,\n                'group_name' => $groupName,\n                'item_ids'   => $itemIds,\n                'created_at' => date('Y-m-d H:i:s'),\n                'updated_at' => date('Y-m-d H:i:s'),\n            ]);\n            return (int) $id;\n        } catch (\\Throwable $e) {\n            return 0;\n        }\n    }\n\n    /**\n     * 更新项目分组\n     *\n     * @param int $id 分组 ID\n     * @param int $uid 用户 ID\n     * @param string $groupName 分组名称\n     * @param string $itemIds 项目 ID 列表（逗号分隔）\n     * @return bool 是否成功\n     */\n    public static function update(int $id, int $uid, string $groupName, string $itemIds = ''): bool\n    {\n        if ($id <= 0 || $uid <= 0 || empty($groupName)) {\n            return false;\n        }\n\n        try {\n            $affected = DB::table('item_group')\n                ->where('id', $id)\n                ->where('uid', $uid)\n                ->update([\n                    'group_name' => $groupName,\n                    'item_ids'   => $itemIds,\n                    'updated_at' => date('Y-m-d H:i:s'),\n                ]);\n            return $affected > 0;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 保存分组（新建或更新）\n     *\n     * @param int $id 分组 ID（0 表示新建）\n     * @param int $uid 用户 ID\n     * @param string $groupName 分组名称\n     * @param string $itemIds 项目 ID 列表（逗号分隔）\n     * @return int 分组 ID，失败返回 0\n     */\n    public static function save(int $id, int $uid, string $groupName, string $itemIds = ''): int\n    {\n        if ($id > 0) {\n            $success = self::update($id, $uid, $groupName, $itemIds);\n            return $success ? $id : 0;\n        } else {\n            return self::add($uid, $groupName, $itemIds);\n        }\n    }\n\n    /**\n     * 获取用户的项目分组列表\n     *\n     * @param int $uid 用户 ID\n     * @return array 分组列表\n     */\n    public static function getList(int $uid): array\n    {\n        if ($uid <= 0) {\n            return [];\n        }\n\n        $rows = DB::table('item_group')\n            ->where('uid', $uid)\n            ->orderBy('s_number', 'asc')\n            ->orderBy('id', 'asc')\n            ->get()\n            ->all();\n\n        $result = [];\n        foreach ($rows as $row) {\n            $result[] = (array) $row;\n        }\n\n        return $result;\n    }\n\n    /**\n     * 删除项目分组\n     *\n     * @param int $id 分组 ID\n     * @param int $uid 用户 ID\n     * @return bool 是否成功\n     */\n    public static function delete(int $id, int $uid): bool\n    {\n        if ($id <= 0 || $uid <= 0) {\n            return false;\n        }\n\n        try {\n            // 删除分组\n            $deleted = DB::table('item_group')\n                ->where('id', $id)\n                ->where('uid', $uid)\n                ->delete();\n\n            if ($deleted > 0) {\n                // 删除关联的项目排序数据\n                DB::table('item_sort')\n                    ->where('item_group_id', $id)\n                    ->delete();\n            }\n\n            return $deleted > 0;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 根据 ID 查找分组\n     *\n     * @param int $id 分组 ID\n     * @param int $uid 用户 ID（可选，用于权限检查）\n     * @return object|null\n     */\n    public static function findById(int $id, int $uid = 0): ?object\n    {\n        if ($id <= 0) {\n            return null;\n        }\n\n        $query = DB::table('item_group')->where('id', $id);\n\n        if ($uid > 0) {\n            $query->where('uid', $uid);\n        }\n\n        return $query->first();\n    }\n\n    /**\n     * 批量更新分组排序\n     *\n     * @param int $uid 用户 ID\n     * @param array $groups 分组数据数组，每个元素包含 id 和 s_number\n     * @return bool 是否成功\n     */\n    public static function saveSort(int $uid, array $groups): bool\n    {\n        if ($uid <= 0 || empty($groups)) {\n            return false;\n        }\n\n        try {\n            DB::beginTransaction();\n\n            foreach ($groups as $group) {\n                $id = (int) ($group['id'] ?? 0);\n                $sNumber = (int) ($group['s_number'] ?? 0);\n\n                if ($id > 0) {\n                    DB::table('item_group')\n                        ->where('id', $id)\n                        ->where('uid', $uid)\n                        ->update(['s_number' => $sNumber]);\n                }\n            }\n\n            DB::commit();\n            return true;\n        } catch (\\Throwable $e) {\n            DB::rollBack();\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "server/app/Model/ItemMember.php",
    "content": "<?php\n\nnamespace App\\Model;\n\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\nclass ItemMember\n{\n    /**\n     * 添加项目成员\n     *\n     * @param array $data 成员数据\n     * @return int 新创建的成员 ID，失败返回 0\n     */\n    public static function add(array $data): int\n    {\n        if (empty($data['uid']) || empty($data['item_id'])) {\n            return 0;\n        }\n\n        try {\n            $id = DB::table('item_member')->insertGetId($data);\n            return (int) $id;\n        } catch (\\Throwable $e) {\n            return 0;\n        }\n    }\n\n    /**\n     * 根据条件查找成员\n     *\n     * @param int $uid 用户 ID\n     * @param int $itemId 项目 ID\n     * @return object|null\n     */\n    public static function findByUidAndItemId(int $uid, int $itemId): ?object\n    {\n        if ($uid <= 0 || $itemId <= 0) {\n            return null;\n        }\n\n        return DB::table('item_member')\n            ->where('uid', $uid)\n            ->where('item_id', $itemId)\n            ->first();\n    }\n\n    /**\n     * 获取项目成员列表\n     *\n     * @param int $itemId 项目 ID\n     * @return array 成员列表\n     */\n    public static function getList(int $itemId): array\n    {\n        if ($itemId <= 0) {\n            return [];\n        }\n\n        $rows = DB::table('item_member')\n            ->leftJoin('user', 'user.uid', '=', 'item_member.uid')\n            ->select([\n                'item_member.*',\n                'user.name as name',\n            ])\n            ->where('item_member.item_id', $itemId)\n            ->orderBy('item_member.addtime', 'asc')\n            ->get()\n            ->all();\n\n        $result = [];\n        foreach ($rows as $row) {\n            $data = (array) $row;\n            $data['addtime'] = date('Y-m-d H:i:s', (int) ($data['addtime'] ?? time()));\n            // member_group_id 需要返回字符串数字，兼容旧前端\n            $data['member_group_id'] = (string) ($data['member_group_id'] ?? '0');\n\n            // 处理目录名称\n            $data['cat_name'] = '所有目录';\n            if (!empty($data['cat_ids'])) {\n                $data['cat_name'] = '多个目录';\n            } elseif (!empty($data['cat_id']) && (int) $data['cat_id'] > 0) {\n                $cat = Catalog::findById((int) $data['cat_id']);\n                if ($cat) {\n                    $data['cat_name'] = $cat->cat_name ?? '所有目录';\n                }\n            }\n\n            $memberGroupId = (int) ($data['member_group_id'] ?? 0);\n            $groupName = $memberGroupId === 1 ? '编辑' : '只读';\n            $data['member_group'] = \"{$groupName}/目录：{$data['cat_name']}\";\n\n            $result[] = $data;\n        }\n\n        return $result;\n    }\n\n    /**\n     * 删除项目成员\n     *\n     * @param int $itemId 项目 ID\n     * @param int $itemMemberId 成员 ID\n     * @return array|null 被删除的成员信息\n     */\n    public static function delete(int $itemId, int $itemMemberId): ?array\n    {\n        if ($itemId <= 0 || $itemMemberId <= 0) {\n            return null;\n        }\n\n        // 先获取成员信息\n        $member = DB::table('item_member')\n            ->where('item_id', $itemId)\n            ->where('item_member_id', $itemMemberId)\n            ->first();\n\n        if (!$member) {\n            return null;\n        }\n\n        // 删除成员\n        $deleted = DB::table('item_member')\n            ->where('item_id', $itemId)\n            ->where('item_member_id', $itemMemberId)\n            ->delete();\n\n        return $deleted > 0 ? (array) $member : null;\n    }\n\n    /**\n     * 获取项目的所有成员（包括单独成员和团队成员）\n     *\n     * @param int $itemId 项目 ID\n     * @return array 成员列表\n     */\n    public static function getAllList(int $itemId): array\n    {\n        if ($itemId <= 0) {\n            return [];\n        }\n\n        // 获取项目的单独成员\n        $members = DB::table('item_member')\n            ->leftJoin('user', 'user.uid', '=', 'item_member.uid')\n            ->select([\n                'item_member.uid',\n                'item_member.username',\n                'item_member.member_group_id',\n                'item_member.item_id',\n                'user.name as name',\n            ])\n            ->where('item_member.item_id', $itemId)\n            ->orderBy('item_member.addtime', 'asc')\n            ->get()\n            ->all();\n\n        // 获取项目绑定的团队成员\n        $teamMembers = DB::table('team_item_member')\n            ->leftJoin('user', 'user.uid', '=', 'team_item_member.member_uid')\n            ->select([\n                'team_item_member.member_uid as uid',\n                'team_item_member.member_username as username',\n                'team_item_member.member_group_id',\n                'team_item_member.item_id',\n                'user.name as name',\n            ])\n            ->where('team_item_member.item_id', $itemId)\n            ->orderBy('team_item_member.addtime', 'asc')\n            ->get()\n            ->all();\n\n        $return = [];\n        $uidArray = []; // 用于去重\n\n        // 添加项目创建者\n        $item = Item::findById($itemId);\n        if ($item) {\n            $return[] = [\n                'item_id'        => $itemId,\n                'uid'            => (int) $item->uid,\n                'username'       => $item->username ?? '',\n                'username_name'  => $item->username ?? '',\n                // member_group_id 需要返回字符串数字，兼容旧前端\n                'member_group_id' => '1',\n            ];\n            $uidArray[] = (int) $item->uid;\n        }\n\n        // 添加单独成员\n        foreach ($members as $member) {\n            $uid = (int) $member->uid;\n            if (!in_array($uid, $uidArray, true)) {\n                $return[] = [\n                    'item_id'         => $itemId,\n                    'uid'             => $uid,\n                    'username'        => $member->username ?? '',\n                    'username_name'   => $member->name ?? $member->username ?? '',\n                    // member_group_id 需要返回字符串数字，兼容旧前端\n                    'member_group_id' => (string) ($member->member_group_id ?? '0'),\n                ];\n                $uidArray[] = $uid;\n            }\n        }\n\n        // 添加团队成员\n        foreach ($teamMembers as $member) {\n            $uid = (int) $member->uid;\n            if (!in_array($uid, $uidArray, true)) {\n                $return[] = [\n                    'item_id'         => $itemId,\n                    'uid'             => $uid,\n                    'username'        => $member->username ?? '',\n                    'username_name'   => $member->name ?? $member->username ?? '',\n                    // member_group_id 需要返回字符串数字，兼容旧前端\n                    'member_group_id' => (string) ($member->member_group_id ?? '0'),\n                ];\n                $uidArray[] = $uid;\n            }\n        }\n\n        return $return;\n    }\n}\n\n"
  },
  {
    "path": "server/app/Model/ItemSort.php",
    "content": "<?php\n\nnamespace App\\Model;\n\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\nclass ItemSort\n{\n    /**\n     * 根据项目组 ID 删除排序记录\n     *\n     * @param int $itemGroupId 项目组 ID\n     * @return bool 是否成功\n     */\n    public static function deleteByItemGroupId(int $itemGroupId): bool\n    {\n        if ($itemGroupId <= 0) {\n            return false;\n        }\n\n        try {\n            $affected = DB::table('item_sort')\n                ->where('item_group_id', $itemGroupId)\n                ->delete();\n            return $affected >= 0;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "server/app/Model/ItemToken.php",
    "content": "<?php\n\nnamespace App\\Model;\n\nuse Illuminate\\Database\\Capsule\\Manager as DB;\nuse App\\Common\\Helper\\FileHelper;\n\nclass ItemToken\n{\n    /**\n     * 创建 Token\n     *\n     * @param int $itemId 项目 ID\n     * @return int|false 返回插入的 ID，失败返回 false（与旧版逻辑一致）\n     */\n    public static function createToken(int $itemId)\n    {\n        if ($itemId <= 0) {\n            return false;\n        }\n\n        $apiKey = FileHelper::getRandStr() . rand();\n        $apiToken = FileHelper::getRandStr() . rand();\n\n        $data = [\n            'item_id'   => $itemId,\n            'api_key'   => $apiKey,\n            'api_token' => $apiToken,\n            'addtime'   => time(),\n        ];\n\n        try {\n            $id = DB::table('item_token')->insertGetId($data);\n            if ($id > 0) {\n                return $id; // 返回插入的 ID，与旧版逻辑一致\n            }\n            return false;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 根据项目 ID 获取 Token\n     *\n     * @param int $itemId 项目 ID\n     * @return array|null Token 数据\n     */\n    public static function getTokenByItemId(int $itemId): ?array\n    {\n        if ($itemId <= 0) {\n            return null;\n        }\n\n        $row = DB::table('item_token')\n            ->where('item_id', $itemId)\n            ->first();\n\n        if (!$row) {\n            // 如果不存在，创建新的 Token（与旧版逻辑一致：直接创建后立即查询，不 sleep）\n            $result = self::createToken($itemId);\n            if ($result) {\n                // 立即查询，不 sleep（与旧版逻辑一致）\n                $row = DB::table('item_token')\n                    ->where('item_id', $itemId)\n                    ->first();\n                return $row ? (array) $row : null;\n            }\n            return null;\n        }\n\n        return (array) $row;\n    }\n\n    /**\n     * 根据 api_key 获取 Token\n     *\n     * @param string $apiKey API Key\n     * @return array|null Token 数据\n     */\n    public static function getTokenByKey(string $apiKey): ?array\n    {\n        if (empty($apiKey)) {\n            return null;\n        }\n\n        $row = DB::table('item_token')\n            ->where('api_key', $apiKey)\n            ->first();\n\n        return $row ? (array) $row : null;\n    }\n\n    /**\n     * 设置最后使用时间\n     *\n     * @param int $itemId 项目 ID\n     * @return bool 是否成功\n     */\n    public static function setLastTime(int $itemId): bool\n    {\n        if ($itemId <= 0) {\n            return false;\n        }\n\n        try {\n            // 开源版只更新 last_check_time，不更新 use_times（与旧版逻辑一致）\n            $affected = DB::table('item_token')\n                ->where('item_id', $itemId)\n                ->update([\n                    'last_check_time' => time(),\n                ]);\n            return $affected > 0;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 检查 Token\n     * 如果检测通过则返回 item_id\n     *\n     * @param string $apiKey API Key\n     * @param string $apiToken API Token\n     * @param string $no 预留参数（兼容旧接口）\n     * @param int $limitTimes 预留参数（开源版不使用限流）\n     * @return int|false 成功返回 item_id，失败返回 false\n     */\n    public static function check(string $apiKey, string $apiToken, string $no = '', int $limitTimes = 1000)\n    {\n        $ret = self::getTokenByKey($apiKey);\n        if (!$ret || $ret['api_token'] !== $apiToken) {\n            return false; // 验证失败\n        }\n\n        $itemId = (int) $ret['item_id'];\n\n        // 开源版不需要限流，只更新最后使用时间\n        self::setLastTime($itemId);\n        return $itemId;\n    }\n\n    /**\n     * 重置 Token\n     *\n     * @param int $itemId 项目 ID\n     * @return array|false Token 数据，失败返回 false\n     */\n    public static function resetToken(int $itemId)\n    {\n        if ($itemId <= 0) {\n            return false;\n        }\n\n        // 与旧版逻辑一致：先查询，如果不存在则创建并 sleep(1)\n        $row = DB::table('item_token')\n            ->where('item_id', $itemId)\n            ->first();\n        \n        $itemToken = $row ? (array) $row : null;\n        \n        if (!$itemToken) {\n            $result = self::createToken($itemId);\n            if ($result) {\n                sleep(1); // 与旧版逻辑一致：创建后 sleep(1)\n                $row = DB::table('item_token')\n                    ->where('item_id', $itemId)\n                    ->first();\n                $itemToken = $row ? (array) $row : null;\n                if (!$itemToken) {\n                    return false;\n                }\n            } else {\n                return false;\n            }\n        }\n\n        $newToken = FileHelper::getRandStr() . rand();\n        $affected = DB::table('item_token')\n            ->where('item_id', $itemId)\n            ->update(['api_token' => $newToken]);\n\n        if ($affected > 0) {\n            $itemToken['api_token'] = $newToken;\n            return $itemToken;\n        }\n\n        return false;\n    }\n}\n"
  },
  {
    "path": "server/app/Model/ItemVariable.php",
    "content": "<?php\n\nnamespace App\\Model;\n\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\n/**\n * 项目环境变量模型。\n *\n * 表结构：item_variable\n * - id: 主键\n * - item_id: 项目 ID\n * - env_id: 环境 ID\n * - var_name: 变量名\n * - var_value: 变量值\n * - uid: 用户 ID\n * - addtime: 添加时间\n */\nclass ItemVariable\n{\n    /**\n     * 保存环境变量（新增或更新）\n     *\n     * @param int $itemId 项目 ID\n     * @param int $envId 环境 ID\n     * @param string $varName 变量名\n     * @param string $varValue 变量值\n     * @param int $uid 用户 ID\n     * @return int 变量 ID，失败返回 0\n     */\n    public static function save(int $itemId, int $envId, string $varName, string $varValue, int $uid): int\n    {\n        if ($itemId <= 0 || empty($varName)) {\n            return 0;\n        }\n\n        // 查找是否已存在\n        $existing = DB::table('item_variable')\n            ->where('item_id', $itemId)\n            ->where('env_id', $envId)\n            ->where('var_name', $varName)\n            ->first();\n\n        if ($existing) {\n            // 更新\n            $affected = DB::table('item_variable')\n                ->where('id', $existing->id)\n                ->update([\n                    'var_value' => $varValue,\n                ]);\n\n            return $affected > 0 ? (int) $existing->id : 0;\n        } else {\n            // 新增\n            try {\n                $id = DB::table('item_variable')->insertGetId([\n                    'item_id' => $itemId,\n                    'env_id' => $envId,\n                    'var_name' => $varName,\n                    'var_value' => $varValue,\n                    'uid' => $uid,\n                    'addtime' => time(),\n                ]);\n\n                return (int) $id;\n            } catch (\\Throwable $e) {\n                return 0;\n            }\n        }\n    }\n\n    /**\n     * 获取环境变量列表\n     *\n     * @param int $itemId 项目 ID\n     * @param int $envId 环境 ID（可选，0 表示所有环境）\n     * @return array\n     */\n    public static function getList(int $itemId, int $envId = 0): array\n    {\n        if ($itemId <= 0) {\n            return [];\n        }\n\n        $query = DB::table('item_variable')\n            ->where('item_id', $itemId);\n\n        if ($envId > 0) {\n            $query->where('env_id', $envId);\n        }\n\n        $list = $query->orderBy('addtime', 'asc')\n            ->get()\n            ->all();\n\n        $result = [];\n        foreach ($list as $row) {\n            $data = (array) $row;\n            $data['addtime'] = date('Y-m-d H:i:s', (int) ($data['addtime'] ?? time()));\n            $result[] = $data;\n        }\n\n        return $result;\n    }\n\n    /**\n     * 删除环境变量\n     *\n     * @param int $itemId 项目 ID\n     * @param int $id 变量 ID\n     * @return bool 是否成功\n     */\n    public static function delete(int $itemId, int $id): bool\n    {\n        if ($itemId <= 0 || $id <= 0) {\n            return false;\n        }\n\n        try {\n            $deleted = DB::table('item_variable')\n                ->where('item_id', $itemId)\n                ->where('id', $id)\n                ->delete();\n\n            return $deleted > 0;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 根据变量名删除环境变量\n     *\n     * @param int $itemId 项目 ID\n     * @param int $envId 环境 ID\n     * @param string $varName 变量名\n     * @return bool 是否成功\n     */\n    public static function deleteByName(int $itemId, int $envId, string $varName): bool\n    {\n        if ($itemId <= 0 || empty($varName)) {\n            return false;\n        }\n\n        try {\n            $query = DB::table('item_variable')\n                ->where('item_id', $itemId)\n                ->where('var_name', $varName);\n\n            if ($envId > 0) {\n                $query->where('env_id', $envId);\n            }\n\n            $deleted = $query->delete();\n\n            return $deleted > 0;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 更新项目变量的环境 ID\n     *\n     * @param int $itemId 项目 ID\n     * @param int $envId 环境 ID\n     * @return bool 是否成功\n     */\n    public static function updateEnvIdForItem(int $itemId, int $envId): bool\n    {\n        if ($itemId <= 0 || $envId <= 0) {\n            return false;\n        }\n\n        try {\n            $affected = DB::table('item_variable')\n                ->where('item_id', $itemId)\n                ->where('env_id', 0) // 只更新 env_id 为 0 的变量\n                ->update(['env_id' => $envId]);\n            return $affected >= 0;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 根据环境 ID 删除变量\n     *\n     * @param int $envId 环境 ID\n     * @return bool 是否成功\n     */\n    public static function deleteByEnvId(int $envId): bool\n    {\n        if ($envId <= 0) {\n            return false;\n        }\n\n        try {\n            $deleted = DB::table('item_variable')\n                ->where('env_id', $envId)\n                ->delete();\n            return $deleted >= 0;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "server/app/Model/ItemViews.php",
    "content": "<?php\n\nnamespace App\\Model;\n\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\nclass ItemViews\n{\n    /**\n     * 增加项目访问量（项目创建者或成员访问）\n     * \n     * 逻辑：按日期记录访问量，如果当天已有记录则更新，否则插入新记录\n     * - all_views：总访问量（自增1）\n     * - vistor_views：游客访问量（不变）\n     * - view_date：访问日期（YYYY-MM-DD）\n     *\n     * @param int $itemId 项目 ID\n     * @return bool\n     */\n    public static function setIncByOwn(int $itemId): bool\n    {\n        if ($itemId <= 0) {\n            return false;\n        }\n\n        try {\n            $today = date(\"Y-m-d\");\n\n            // 使用 ON DUPLICATE KEY UPDATE 逻辑\n            // 如果当天已有记录则更新 all_views，否则插入新记录\n            DB::statement(\"\n                INSERT INTO item_views (item_id, all_views, vistor_views, view_date)\n                VALUES (?, 1, 0, ?)\n                ON DUPLICATE KEY UPDATE\n                all_views = all_views + 1\n            \", [$itemId, $today]);\n\n            return true;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 增加项目访问量（游客访问）\n     * \n     * 逻辑：按日期记录访问量，如果当天已有记录则更新，否则插入新记录\n     * - all_views：总访问量（自增1）\n     * - vistor_views：游客访问量（自增1）\n     * - view_date：访问日期（YYYY-MM-DD）\n     *\n     * @param int $itemId 项目 ID\n     * @return bool\n     */\n    public static function setIncByVistor(int $itemId): bool\n    {\n        if ($itemId <= 0) {\n            return false;\n        }\n\n        try {\n            $today = date(\"Y-m-d\");\n\n            // 使用 ON DUPLICATE KEY UPDATE 逻辑\n            // 如果当天已有记录则更新 all_views 和 vistor_views，否则插入新记录\n            DB::statement(\"\n                INSERT INTO item_views (item_id, all_views, vistor_views, view_date)\n                VALUES (?, 1, 1, ?)\n                ON DUPLICATE KEY UPDATE\n                all_views = all_views + 1,\n                vistor_views = vistor_views + 1\n            \", [$itemId, $today]);\n\n            return true;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "server/app/Model/Member.php",
    "content": "<?php\n\nnamespace App\\Model;\n\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\nclass Member\n{\n    /**\n     * 获取用户在项目下拥有权限的目录 ID 集合\n     *\n     * @param int $itemId 项目 ID\n     * @param int $uid 用户 ID\n     * @return array 目录 ID 数组\n     */\n    public static function getCatIds(int $itemId, int $uid): array\n    {\n        if ($itemId <= 0 || $uid <= 0) {\n            return [];\n        }\n\n        // 兼容旧版逻辑：\n        // - 个人成员目录权限：item_member.cat_id / item_member.cat_ids\n        // - 团队成员目录权限：team_item_member.cat_id / team_item_member.cat_ids\n        // 参考：server/Application/Api/Model/MemberModel.class.php::getCatIds\n\n        $ids = [];\n\n        // 1. 优先个人成员\n        $row1 = DB::table('item_member')\n            ->where('item_id', $itemId)\n            ->where('uid', $uid)\n            ->select(['cat_id', 'cat_ids'])\n            ->first();\n\n        if ($row1) {\n            $row1Arr = (array) $row1;\n            $str = (string) ($row1Arr['cat_ids'] ?? '');\n            if ($str !== '') {\n                $tmp = [];\n                if (strpos($str, ',') !== false) {\n                    $tmp = preg_split('/\\s*,\\s*/', trim($str));\n                } elseif (ctype_digit($str)) {\n                    $tmp = [intval($str)];\n                }\n                foreach ($tmp as $id) {\n                    $id = intval($id);\n                    if ($id > 0) {\n                        $ids[] = $id;\n                    }\n                }\n            }\n            if (empty($ids) && !empty($row1Arr['cat_id']) && intval($row1Arr['cat_id']) > 0) {\n                $ids[] = intval($row1Arr['cat_id']);\n            }\n        }\n\n        // 2. 如果个人没有目录限制，再看团队成员\n        if (empty($ids)) {\n            $row2 = DB::table('team_item_member')\n                ->where('item_id', $itemId)\n                ->where('member_uid', $uid)\n                ->select(['cat_id', 'cat_ids'])\n                ->first();\n\n            if ($row2) {\n                $row2Arr = (array) $row2;\n                $str = (string) ($row2Arr['cat_ids'] ?? '');\n                if ($str !== '') {\n                    $tmp = [];\n                    if (strpos($str, ',') !== false) {\n                        $tmp = preg_split('/\\s*,\\s*/', trim($str));\n                    } elseif (ctype_digit($str)) {\n                        $tmp = [intval($str)];\n                    }\n                    foreach ($tmp as $id) {\n                        $id = intval($id);\n                        if ($id > 0) {\n                            $ids[] = $id;\n                        }\n                    }\n                }\n                if (empty($ids) && !empty($row2Arr['cat_id']) && intval($row2Arr['cat_id']) > 0) {\n                    $ids[] = intval($row2Arr['cat_id']);\n        }\n            }\n        }\n\n        // 去重并返回\n        $ids = array_values(array_unique(array_map('intval', $ids)));\n        return $ids;\n    }\n}\n"
  },
  {
    "path": "server/app/Model/Message.php",
    "content": "<?php\n\nnamespace App\\Model;\n\nuse Illuminate\\Database\\Capsule\\Manager as DB;\nuse App\\Model\\MessageContent;\n\n/**\n * 消息模型（开源版：使用单表 message，不支持分表）\n */\nclass Message\n{\n    /**\n     * 获取提醒消息列表\n     *\n     * @param int $toUid 接收者用户 ID\n     * @param int $page 页码\n     * @param int $count 每页数量\n     * @param int $status 状态（-2 表示不筛选，0 未读，1 已读）\n     * @return array 包含 total 和 list\n     */\n    public static function getRemindList(int $toUid, int $page = 1, int $count = 15, int $status = -2): array\n    {\n        if ($toUid <= 0) {\n            return ['total' => 0, 'list' => []];\n        }\n\n        $query = DB::table('message')\n            ->where('to_uid', $toUid)\n            ->where('message_type', 'remind');\n\n        if ($status > -2) {\n            $query->where('status', $status);\n        }\n\n        // 获取总数\n        $total = $query->count();\n\n        // 获取列表\n        $list = (clone $query)\n            ->orderBy('id', 'desc')\n            ->offset(($page - 1) * $count)\n            ->limit($count)\n            ->get()\n            ->all();\n\n        // 渲染每条消息\n        $result = [];\n        foreach ($list as $row) {\n            $result[] = self::renderOne((array) $row);\n        }\n\n        return [\n            'total' => (int) $total,\n            'list'  => $result,\n        ];\n    }\n\n    /**\n     * 渲染单条消息（补充完整信息）\n     *\n     * @param array $one 消息数据\n     * @return array 渲染后的消息数据\n     */\n    public static function renderOne(array $one): array\n    {\n        $messageContentId = (int) ($one['message_content_id'] ?? 0);\n        $fromUid = (int) ($one['from_uid'] ?? 0);\n\n        if ($messageContentId > 0) {\n            // 获取消息内容（开源版使用单表）\n            $messageContent = DB::table('message_content')\n                ->where('id', $messageContentId)\n                ->first();\n\n            if ($messageContent) {\n                $one['object_type'] = $messageContent->object_type ?? '';\n                $one['object_id'] = (int) ($messageContent->object_id ?? 0);\n                $one['action_type'] = $messageContent->action_type ?? '';\n                $one['message_content'] = $messageContent->message_content ?? '';\n                $one['from_name'] = $messageContent->from_name ?? '';\n\n                // 如果是页面类型，补充页面信息\n                if (($one['object_type'] ?? '') === 'page') {\n                    $pageId = (int) ($one['object_id'] ?? 0);\n                    if ($pageId > 0) {\n                        $page = DB::table('page')\n                            ->where('page_id', $pageId)\n                            ->first();\n\n                        if ($page) {\n                            $itemId = (int) $page->item_id;\n                            $pageData = \\App\\Model\\Page::findById($pageId);\n                            if ($pageData) {\n                                $pageArray = (array) $pageData;\n                                unset($pageArray['page_content']); // 不返回内容\n                                $one['page_data'] = $pageArray;\n                            }\n                        }\n                    }\n                }\n            }\n        }\n\n        return $one;\n    }\n\n    /**\n     * 添加消息（兼容旧接口）\n     *\n     * @param int $fromUid 发送者用户 ID\n     * @param string $fromName 发送者名称\n     * @param int $toUid 接收者用户 ID\n     * @param string $messageType 消息类型\n     * @param string $messageContent 消息内容\n     * @param string $actionType 动作类型\n     * @param string $objectType 对象类型\n     * @param int $objectId 对象 ID\n     * @return int 消息 ID，失败返回 0\n     */\n    public static function addMsg(\n        int $fromUid,\n        string $fromName,\n        int $toUid,\n        string $messageType,\n        string $messageContent,\n        string $actionType,\n        string $objectType,\n        int $objectId\n    ): int {\n        if ($fromUid <= 0 || $toUid <= 0) {\n            return 0;\n        }\n\n        try {\n            // 先添加消息内容（开源版使用单表）\n            $messageContentId = DB::table('message_content')->insertGetId([\n                'from_uid'         => $fromUid,\n                'from_name'        => $fromName,\n                'message_type'     => $messageType,\n                'message_content'  => $messageContent,\n                'action_type'      => $actionType,\n                'object_type'      => $objectType,\n                'object_id'        => $objectId,\n                'addtime'          => date('Y-m-d H:i:s'),\n            ]);\n\n            // 再添加消息记录（开源版使用单表）\n            $msgId = DB::table('message')->insertGetId([\n                'from_uid'            => $fromUid,\n                'to_uid'              => $toUid,\n                'message_type'        => $messageType,\n                'message_content_id'  => $messageContentId,\n                'status'              => 0,\n                'addtime'             => date('Y-m-d H:i:s'),\n                'readtime'            => date('Y-m-d H:i:s'),\n            ]);\n\n            return (int) $msgId;\n        } catch (\\Throwable $e) {\n            return 0;\n        }\n    }\n}\n"
  },
  {
    "path": "server/app/Model/MessageContent.php",
    "content": "<?php\n\nnamespace App\\Model;\n\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\n/**\n * 消息内容模型（开源版：使用单表 message_content，不支持分表）\n */\nclass MessageContent\n{\n}\n"
  },
  {
    "path": "server/app/Model/Mock.php",
    "content": "<?php\n\nnamespace App\\Model;\n\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\nclass Mock\n{\n    /**\n     * 根据页面ID查找Mock数据\n     *\n     * @param int $pageId 页面ID\n     * @return array|null\n     */\n    public static function findByPageId(int $pageId): ?array\n    {\n        if ($pageId <= 0) {\n            return null;\n        }\n\n        $row = DB::table('mock')\n            ->where('page_id', $pageId)\n            ->first();\n\n        return $row ? (array) $row : null;\n    }\n\n    /**\n     * 根据唯一key查找Mock数据\n     *\n     * @param string $uniqueKey 唯一key\n     * @return array|null\n     */\n    public static function findByUniqueKey(string $uniqueKey): ?array\n    {\n        if (empty($uniqueKey)) {\n            return null;\n        }\n\n        $row = DB::table('mock')\n            ->where('unique_key', $uniqueKey)\n            ->first();\n\n        return $row ? (array) $row : null;\n    }\n\n    /**\n     * 根据项目ID和路径查找Mock数据\n     *\n     * @param int $itemId 项目ID\n     * @param string $path 路径\n     * @return array|null\n     */\n    public static function findByItemIdAndPath(int $itemId, string $path): ?array\n    {\n        if ($itemId <= 0 || empty($path)) {\n            return null;\n        }\n\n        $row = DB::table('mock')\n            ->where('item_id', $itemId)\n            ->where('path', $path)\n            ->first();\n\n        return $row ? (array) $row : null;\n    }\n\n    /**\n     * 保存Mock数据（新建或更新）\n     *\n     * @param int $pageId 页面ID\n     * @param array $data Mock数据\n     * @return bool\n     */\n    public static function saveByPageId(int $pageId, array $data): bool\n    {\n        if ($pageId <= 0) {\n            return false;\n        }\n\n        $affected = DB::table('mock')\n            ->where('page_id', $pageId)\n            ->update($data);\n\n        return $affected >= 0; // 即使没有更新（affected=0）也算成功\n    }\n\n    /**\n     * 添加Mock数据\n     *\n     * @param array $data Mock数据\n     * @return int|false 返回插入的ID，失败返回false\n     */\n    public static function add(array $data)\n    {\n        $id = DB::table('mock')->insertGetId($data);\n        return $id ?: false;\n    }\n\n    /**\n     * 增加查看次数\n     *\n     * @param int $id Mock记录ID\n     * @return bool\n     */\n    public static function incrementViewTimes(int $id): bool\n    {\n        if ($id <= 0) {\n            return false;\n        }\n\n        $affected = DB::table('mock')\n            ->where('id', $id)\n            ->increment('view_times', 1);\n\n        return $affected > 0;\n    }\n}\n"
  },
  {
    "path": "server/app/Model/Options.php",
    "content": "<?php\n\nnamespace App\\Model;\n\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\n/**\n * 选项配置表封装，兼容旧版 OptionsModel::get/set 行为。\n *\n * 表结构沿用旧表 `options`：\n * - option_name\n * - option_value\n */\nclass Options\n{\n    /**\n     * 获取配置项，不存在时返回提供的默认值（默认为 null）。\n     * 直接返回数据库中的原始值，不进行类型转换。\n     */\n    public static function get(string $name, $default = null)\n    {\n        $row = DB::table('options')\n            ->where('option_name', $name)\n            ->first();\n\n        if (!$row) {\n            return $default;\n        }\n\n        return $row->option_value;\n    }\n\n    /**\n     * 设置配置项（存在则更新，不存在则插入）。\n     * 给它什么就保存什么，不做类型转换（数组除外，需要转 JSON）。\n     * \n     * 兼容 ThinkPHP 的 M('options')->add(..., NULL, true) 行为：\n     * 第三个参数 true 表示如果记录已存在则更新，不存在则插入。\n     */\n    public static function set(string $name, $value): bool\n    {\n        // 如果是数组，转换为 JSON 字符串（旧代码中 ldap_form 等配置是 JSON）\n        if (is_array($value)) {\n            $value = json_encode($value, JSON_UNESCAPED_UNICODE);\n        }\n\n        try {\n            // 先检查记录是否存在\n            $existing = DB::table('options')\n                ->where('option_name', $name)\n                ->first();\n\n            if ($existing) {\n                // 更新现有记录（写操作默认使用主库）\n                $affected = DB::table('options')\n                    ->where('option_name', $name)\n                    ->update([\n                        'option_value' => $value,\n                    ]);\n                // affected >= 0 表示执行成功（0 表示值没变化，但也是成功）\n                return $affected >= 0;\n            }\n\n            // 插入新记录（写操作默认使用主库）\n            return DB::table('options')->insert([\n                'option_name'  => $name,\n                'option_value' => $value,\n            ]);\n        } catch (\\Throwable $e) {\n            // 记录错误但不抛出异常，返回 false 表示失败\n            error_log(\"Options::set() failed for '{$name}': \" . $e->getMessage() . \"\\n\" . $e->getTraceAsString());\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "server/app/Model/Page.php",
    "content": "<?php\n\nnamespace App\\Model;\n\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\n/**\n * 页面模型（开源版：使用单表 page，不支持分表）\n * \n * 注意：开源版的 page_content 不经过压缩存储，与主版不同。\n * 读取时兼容旧数据（可能有些是压缩的），但写入时不压缩。\n */\nclass Page\n{\n    /**\n     * 获取页面表名（开源版：始终返回 'page'）\n     * \n     * 此方法为了与主版代码兼容，主版使用分表，开源版使用单表。\n     * \n     * @param int $itemId 项目 ID（开源版忽略此参数）\n     * @return string 表名\n     */\n    public static function tableForItem(int $itemId): string\n    {\n        return 'page';\n    }\n\n    public static function listTitles(int $itemId): array\n    {\n        if ($itemId <= 0) {\n            return [];\n        }\n\n        return DB::table('page')\n            ->select(['page_id', 'page_title'])\n            ->where('item_id', $itemId)\n            ->where('is_del', 0)\n            ->orderBy('s_number')\n            ->orderBy('page_id')\n            ->get()\n            ->all();\n    }\n\n    public static function findByIdWithContent(int $itemId, int $pageId): ?array\n    {\n        if ($itemId <= 0 || $pageId <= 0) {\n            return null;\n        }\n\n        $row = DB::table('page')\n            ->where('item_id', $itemId)\n            ->where('page_id', $pageId)\n            ->where('is_del', 0)\n            ->first();\n\n        if (!$row) {\n            return null;\n        }\n\n        $data = (array) $row;\n\n        // 开源版：page_content 不压缩存储，直接返回\n        // 为了兼容旧数据（可能有些是压缩的），尝试解压，但失败时保持原样\n        if (!empty($data['page_content'])) {\n            $decoded = \\App\\Common\\Helper\\ContentCodec::decompress($data['page_content']);\n            // 如果解压成功（返回非空且不等于原始字符串），说明是旧压缩数据，使用解压后的内容\n            if ($decoded !== '' && $decoded !== $data['page_content']) {\n                $data['page_content'] = $decoded;\n            }\n            // 如果解压失败或内容未压缩，保持原样（开源版新数据不压缩）\n        }\n\n        return $data;\n    }\n\n    /**\n     * 搜索项目下的页面\n     *\n     * @param int $itemId 项目 ID\n     * @param array|int $catIds 目录 ID 或目录 ID 数组（0 表示所有目录）\n     * @param string $keyword 搜索关键词\n     * @param int $uid 当前用户 ID（用于过滤草稿）\n     * @return array 匹配的页面数组\n     */\n    public static function search(int $itemId, $catIds = 0, string $keyword = '', int $uid = 0): array\n    {\n        if ($itemId <= 0 || empty($keyword)) {\n            return [];\n        }\n\n        $query = DB::table('page')\n            ->where('item_id', $itemId)\n            ->where('is_del', 0);\n\n        // 目录筛选（扩展为包含所有子目录）\n        if (is_array($catIds) && !empty($catIds)) {\n            $catIds = array_filter(array_map('intval', $catIds));\n            if ($catIds) {\n                // 扩展目录 ID 以包含所有子目录\n                $expandedCatIds = \\App\\Model\\Catalog::expandCatIdsWithChildren($itemId, $catIds);\n                $query->whereIn('cat_id', $expandedCatIds);\n            }\n        } elseif (is_numeric($catIds) && $catIds > 0) {\n            // 单个目录 ID 也需要扩展\n            $expandedCatIds = \\App\\Model\\Catalog::expandCatIdsWithChildren($itemId, [(int) $catIds]);\n            $query->whereIn('cat_id', $expandedCatIds);\n        }\n\n        $pages = $query\n            ->orderBy('s_number', 'asc')\n            ->get()\n            ->all();\n\n        $keyword = strtolower(trim($keyword));\n        $result  = [];\n\n        foreach ($pages as $page) {\n            // 过滤草稿页面（非作者不可见）\n            $isDraft = (int) ($page->is_draft ?? 0);\n            $authorUid = (int) ($page->author_uid ?? 0);\n            if ($isDraft === 1 && $authorUid !== $uid) {\n                continue;\n            }\n\n            $pageTitle   = strtolower((string) ($page->page_title ?? ''));\n            $pageContent = (string) ($page->page_content ?? '');\n\n            // 开源版：page_content 不压缩存储，但兼容旧压缩数据\n            $decoded = \\App\\Common\\Helper\\ContentCodec::decompress($pageContent);\n            if ($decoded !== '' && $decoded !== $pageContent) {\n                $pageContent = $decoded;\n            }\n\n            $pageContentLower = strtolower($pageContent);\n\n            // 在标题或内容中搜索关键词\n            if (strpos($pageTitle . '  ' . $pageContentLower, $keyword) !== false) {\n                $data = (array) $page;\n                $data['page_content'] = $pageContent;\n                $result[] = $data;\n            }\n        }\n\n        return $result;\n    }\n\n    /**\n     * 根据 page_id 查找页面\n     *\n     * @param int $pageId 页面 ID\n     * @return array|null 页面数据\n     */\n    public static function findById(int $pageId): ?array\n    {\n        if ($pageId <= 0) {\n            return null;\n        }\n\n        // 从 page 表获取 item_id\n        $pageRow = DB::table('page')\n            ->where('page_id', $pageId)\n            ->first();\n\n        if (!$pageRow) {\n            return null;\n        }\n\n        $itemId = (int) $pageRow->item_id;\n        return self::findByIdWithContent($itemId, $pageId);\n    }\n\n    /**\n     * 获取带缓存的页面内容\n     *\n     * @param int $pageId 页面 ID\n     * @param int $itemId 项目 ID\n     * @return array|null 页面数据\n     */\n    public static function findPageByCache(int $pageId, int $itemId): ?array\n    {\n        if ($pageId <= 0 || $itemId <= 0) {\n            return null;\n        }\n\n        $cacheKey = 'showdoc_page_cache2_page_id_' . $pageId;\n        $cache    = \\App\\Common\\Cache\\CacheManager::getInstance();\n        $page     = $cache->get($cacheKey);\n\n        if ($page === null) {\n            // 缓存不存在，从数据库读取\n            $page = self::findByIdWithContent($itemId, $pageId);\n            if ($page) {\n                // 写入缓存，24小时过期\n                $cache->set($cacheKey, $page, 60 * 60 * 24);\n            }\n        }\n\n        return $page;\n    }\n\n    /**\n     * 删除页面缓存\n     *\n     * @param int $pageId 页面 ID\n     * @return bool 是否删除成功\n     */\n    public static function deleteCache(int $pageId): bool\n    {\n        if ($pageId <= 0) {\n            return false;\n        }\n\n        $cacheKey = 'showdoc_page_cache2_page_id_' . $pageId;\n        $cache    = \\App\\Common\\Cache\\CacheManager::getInstance();\n        return $cache->delete($cacheKey);\n    }\n\n    /**\n     * 保存页面（更新）\n     *\n     * @param int $pageId 页面 ID\n     * @param int $itemId 项目 ID\n     * @param array $data 页面数据\n     * @return bool 是否成功\n     */\n    public static function savePage(int $pageId, int $itemId, array $data): bool\n    {\n        if ($pageId <= 0 || $itemId <= 0) {\n            return false;\n        }\n\n        // 开源版：page_content 不压缩存储，直接保存\n        // 如果传入的是压缩数据（旧数据），先解压再保存\n        if (!empty($data['page_content'])) {\n            $decoded = \\App\\Common\\Helper\\ContentCodec::decompress($data['page_content']);\n            if ($decoded !== '' && $decoded !== $data['page_content']) {\n                // 是压缩数据，解压后保存\n                $data['page_content'] = $decoded;\n            }\n            // 未压缩数据，直接保存\n        }\n\n        try {\n            $affected = DB::table('page')\n                ->where('page_id', $pageId)\n                ->where('item_id', $itemId)\n                ->update($data);\n            return $affected > 0;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 添加页面（新建）\n     *\n     * @param int $itemId 项目 ID\n     * @param array $data 页面数据\n     * @return int 新创建的页面 ID，失败返回 0\n     */\n    public static function addPage(int $itemId, array $data): int\n    {\n        if ($itemId <= 0) {\n            return 0;\n        }\n\n        // 设置 page_id（开源版直接使用自增 ID）\n        $data['item_id'] = $itemId;\n\n        // 开源版：page_content 不压缩存储，直接保存\n        // 如果传入的是压缩数据（旧数据），先解压再保存\n        if (!empty($data['page_content'])) {\n            $decoded = \\App\\Common\\Helper\\ContentCodec::decompress($data['page_content']);\n            if ($decoded !== '' && $decoded !== $data['page_content']) {\n                // 是压缩数据，解压后保存\n                $data['page_content'] = $decoded;\n            }\n            // 未压缩数据，直接保存\n        }\n\n        try {\n            $pageId = DB::table('page')\n                ->insertGetId($data);\n            return (int) $pageId;\n        } catch (\\Throwable $e) {\n            return 0;\n        }\n    }\n\n    /**\n     * 根据页面标题更新或创建页面（用于导入）\n     *\n     * @param int $itemId 项目 ID\n     * @param string $pageTitle 页面标题\n     * @param string $pageContent 页面内容\n     * @param string $catName 目录路径（如 '二级目录/三级目录'）\n     * @param int $sNumber 排序号\n     * @param int $authorUid 作者用户 ID\n     * @param string $authorUsername 作者用户名\n     * @return int|false 返回页面 ID，失败返回 false\n     */\n    public static function updateByTitle(\n        int $itemId,\n        string $pageTitle,\n        string $pageContent,\n        string $catName = '',\n        int $sNumber = 99,\n        int $authorUid = 0,\n        string $authorUsername = ''\n    ) {\n        if ($itemId <= 0 || empty($pageTitle)) {\n            return false;\n        }\n\n        $catId = 0;\n        if (!empty($catName)) {\n            // 根据路径创建或获取目录\n            $catId = \\App\\Model\\Catalog::saveCatPath($catName, $itemId);\n            if ($catId === false) {\n                return false;\n            }\n        }\n\n        // 查找是否已存在该页面\n        $existing = DB::table('page')\n            ->where('item_id', $itemId)\n            ->where('is_del', 0)\n            ->where('cat_id', $catId)\n            ->where('page_title', $pageTitle)\n            ->first();\n\n        // HTML 转义处理（与旧版逻辑一致：_htmlspecialchars）\n        // 之所以先 htmlspecialchars_decode 是为了防止被 htmlspecialchars 转义了两次\n        $pageTitle = htmlspecialchars(htmlspecialchars_decode($pageTitle));\n\n        // 开源版：page_content 不压缩存储\n        // 如果传入的是压缩数据（旧数据），先解压（兼容旧数据）\n        if (!empty($pageContent)) {\n            $decoded = \\App\\Common\\Helper\\ContentCodec::decompress($pageContent);\n            if ($decoded !== '' && $decoded !== $pageContent) {\n                $pageContent = $decoded;\n            }\n        }\n\n        // 与旧版逻辑一致：使用 _htmlspecialchars 处理\n        // 之所以先 htmlspecialchars_decode 是为了防止被 htmlspecialchars 转义了两次\n        $pageContent = htmlspecialchars(htmlspecialchars_decode($pageContent));\n\n        if ($existing) {\n            // 更新现有页面\n            $pageId = (int) $existing->page_id;\n            // 开源版：直接保存，不压缩\n            $updateData = [\n                'author_uid'      => $authorUid,\n                'author_username'  => $authorUsername,\n                'item_id'          => $itemId,\n                'cat_id'           => $catId,\n                'page_title'       => $pageTitle,\n                'page_content'     => $pageContent,\n                's_number'         => $sNumber,\n            ];\n            $affected = DB::table('page')\n                ->where('page_id', $pageId)\n                ->where('item_id', $itemId)\n                ->update($updateData);\n            if ($affected > 0) {\n                // 删除缓存\n                self::deleteCache($pageId);\n                \\App\\Model\\Item::deleteCache($itemId);\n                return $pageId;\n            }\n            return false;\n        } else {\n            // 创建新页面\n            // 开源版：直接保存，不压缩\n            $addData = [\n                'author_uid'      => $authorUid,\n                'author_username' => $authorUsername,\n                'item_id'         => $itemId,\n                'cat_id'          => $catId,\n                'page_title'      => $pageTitle,\n                'page_content'    => $pageContent,\n                's_number'         => $sNumber,\n                'addtime'          => time(),\n            ];\n            $pageId = self::addPage($itemId, $addData);\n            if ($pageId > 0) {\n                // 删除缓存\n                \\App\\Model\\Item::deleteCache($itemId);\n                return $pageId;\n            }\n            return false;\n        }\n    }\n\n    /**\n     * 查找页面（包含完整信息，用于 API 返回）\n     *\n     * @param int $pageId 页面 ID\n     * @param int $itemId 项目 ID\n     * @return array|null 页面数据\n     */\n    public static function findPage(int $pageId, int $itemId): ?array\n    {\n        $page = self::findByIdWithContent($itemId, $pageId);\n        if (!$page) {\n            return null;\n        }\n\n        // 格式化时间\n        if (isset($page['addtime'])) {\n            $page['addtime'] = date('Y-m-d H:i:s', (int) $page['addtime']);\n        }\n\n        return $page;\n    }\n\n    /**\n     * 软删除页面\n     *\n     * @param int $pageId 页面 ID\n     * @param int $itemId 项目 ID\n     * @param int $uid 删除者用户 ID\n     * @param string $username 删除者用户名\n     * @return bool 是否成功\n     */\n    public static function softDeletePage(int $pageId, int $itemId, int $uid = 0, string $username = ''): bool\n    {\n        if ($pageId <= 0 || $itemId <= 0) {\n            return false;\n        }\n\n        try {\n            // 先获取页面信息（用于插入 recycle 表）\n            $page = DB::table('page')\n                ->where('page_id', $pageId)\n                ->where('item_id', $itemId)\n                ->first();\n\n            if (!$page) {\n                return false;\n            }\n\n            $pageTitle = $page->page_title ?? '';\n\n            // 向 recycle 表插入记录\n            \\App\\Model\\Recycle::add([\n                'item_id' => $itemId,\n                'page_id' => $pageId,\n                'page_title' => $pageTitle,\n                'del_by_uid' => $uid,\n                'del_by_username' => $username,\n                'del_time' => time(),\n            ]);\n\n            // 更新 page 表的 is_del = 1\n            $affected = DB::table('page')\n                ->where('page_id', $pageId)\n                ->where('item_id', $itemId)\n                ->update([\n                    'is_del' => 1,\n                ]);\n\n            if ($affected > 0) {\n                // 删除缓存\n                self::deleteCache($pageId);\n                \\App\\Model\\Item::deleteCache($itemId);\n                return true;\n            }\n\n            return false;\n        } catch (\\Throwable $e) {\n            error_log(\"softDeletePage error: \" . $e->getMessage());\n            return false;\n        }\n    }\n\n    /**\n     * 获取项目的页面数量\n     *\n     * @param int $itemId 项目 ID\n     * @return int 页面数量\n     */\n    public static function getPageCount(int $itemId): int\n    {\n        if ($itemId <= 0) {\n            return 0;\n        }\n\n        return DB::table('page')\n            ->where('item_id', $itemId)\n            ->where('is_del', 0)\n            ->count();\n    }\n\n    /**\n     * 删除页面（物理删除，兼容旧版 deletePage 方法）\n     * \n     * 旧版实现：只根据 page_id 删除，不检查 item_id\n     *\n     * @param int $pageId 页面 ID\n     * @param int $itemId 项目 ID（可选，用于验证，但旧版不验证）\n     * @return bool 是否成功\n     */\n    public static function deletePage(int $pageId, int $itemId = 0): bool\n    {\n        if ($pageId <= 0) {\n            return false;\n        }\n\n        try {\n            // 旧版逻辑：只根据 page_id 删除，不检查 item_id\n            $query = DB::table('page')->where('page_id', $pageId);\n            \n            // 如果提供了 itemId，则添加验证（用于新代码，但保持向后兼容）\n            if ($itemId > 0) {\n                $query->where('item_id', $itemId);\n            }\n            \n            $affected = $query->delete();\n            return $affected > 0;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n}\n\n"
  },
  {
    "path": "server/app/Model/PageComment.php",
    "content": "<?php\n\nnamespace App\\Model;\n\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\n/**\n * 页面评论模型。\n *\n * 表结构：page_comment\n * - comment_id: 主键\n * - page_id: 页面 ID\n * - item_id: 项目 ID\n * - parent_id: 父评论 ID（0 表示一级评论）\n * - uid: 用户 ID\n * - username: 用户名\n * - content: 评论内容\n * - is_deleted: 是否删除（0=未删除，1=已删除）\n * - addtime: 添加时间\n */\nclass PageComment\n{\n    /**\n     * 根据 ID 查找评论\n     *\n     * @param int $commentId 评论 ID\n     * @return object|null\n     */\n    public static function findById(int $commentId): ?object\n    {\n        if ($commentId <= 0) {\n            return null;\n        }\n\n        return DB::table('page_comment')\n            ->where('comment_id', $commentId)\n            ->first();\n    }\n\n    /**\n     * 添加评论\n     *\n     * @param array $data 评论数据\n     * @return int 评论 ID，失败返回 0\n     */\n    public static function add(array $data): int\n    {\n        try {\n            $id = DB::table('page_comment')->insertGetId($data);\n            return (int) $id;\n        } catch (\\Throwable $e) {\n            return 0;\n        }\n    }\n\n    /**\n     * 更新评论\n     *\n     * @param int $commentId 评论 ID\n     * @param array $data 更新数据\n     * @return bool 是否成功\n     */\n    public static function update(int $commentId, array $data): bool\n    {\n        if ($commentId <= 0) {\n            return false;\n        }\n\n        try {\n            $affected = DB::table('page_comment')\n                ->where('comment_id', $commentId)\n                ->update($data);\n\n            return $affected > 0;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 获取一级评论列表（分页）\n     *\n     * @param int $pageId 页面 ID\n     * @param int $page 页码\n     * @param int $count 每页数量\n     * @return array 包含 total 和 list\n     */\n    public static function getTopLevelList(int $pageId, int $page = 1, int $count = 20): array\n    {\n        if ($pageId <= 0) {\n            return ['total' => 0, 'list' => []];\n        }\n\n        $query = DB::table('page_comment')\n            ->where('page_id', $pageId)\n            ->where('parent_id', 0)\n            ->where('is_deleted', 0);\n\n        // 获取总数\n        $total = (clone $query)->count();\n\n        // 获取列表\n        $list = $query->orderBy('addtime', 'desc')\n            ->offset(($page - 1) * $count)\n            ->limit($count)\n            ->get()\n            ->all();\n\n        $result = [];\n        foreach ($list as $row) {\n            $result[] = (array) $row;\n        }\n\n        return [\n            'total' => (int) $total,\n            'list' => $result,\n        ];\n    }\n\n    /**\n     * 获取评论的所有回复（不分页）\n     *\n     * @param int $commentId 评论 ID\n     * @return array\n     */\n    public static function getReplies(int $commentId): array\n    {\n        if ($commentId <= 0) {\n            return [];\n        }\n\n        $list = DB::table('page_comment')\n            ->where('parent_id', $commentId)\n            ->where('is_deleted', 0)\n            ->orderBy('addtime', 'asc')\n            ->get()\n            ->all();\n\n        $result = [];\n        foreach ($list as $row) {\n            $result[] = (array) $row;\n        }\n\n        return $result;\n    }\n}\n"
  },
  {
    "path": "server/app/Model/PageFeedback.php",
    "content": "<?php\n\nnamespace App\\Model;\n\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\nclass PageFeedback\n{\n    /**\n     * 根据页面 ID 和反馈类型统计数量\n     *\n     * @param int $pageId 页面 ID\n     * @param int $feedbackType 反馈类型（1=有帮助，2=无帮助）\n     * @return int 数量\n     */\n    public static function countByType(int $pageId, int $feedbackType): int\n    {\n        if ($pageId <= 0 || ($feedbackType !== 1 && $feedbackType !== 2)) {\n            return 0;\n        }\n\n        return DB::table('page_feedback')\n            ->where('page_id', $pageId)\n            ->where('feedback_type', $feedbackType)\n            ->count();\n    }\n\n    /**\n     * 根据用户 ID 查找反馈\n     *\n     * @param int $pageId 页面 ID\n     * @param int $uid 用户 ID\n     * @return object|null 反馈记录，不存在返回 null\n     */\n    public static function findByUid(int $pageId, int $uid): ?object\n    {\n        if ($pageId <= 0 || $uid <= 0) {\n            return null;\n        }\n\n        return DB::table('page_feedback')\n            ->where('page_id', $pageId)\n            ->where('uid', $uid)\n            ->first();\n    }\n\n    /**\n     * 根据客户端 ID 查找反馈\n     *\n     * @param int $pageId 页面 ID\n     * @param string $clientId 客户端 ID\n     * @return object|null 反馈记录，不存在返回 null\n     */\n    public static function findByClientId(int $pageId, string $clientId): ?object\n    {\n        if ($pageId <= 0 || empty($clientId)) {\n            return null;\n        }\n\n        return DB::table('page_feedback')\n            ->where('page_id', $pageId)\n            ->where('client_id', $clientId)\n            ->first();\n    }\n\n    /**\n     * 添加反馈\n     *\n     * @param array $data 反馈数据\n     * @return int|false 返回插入的ID，失败返回false\n     */\n    public static function add(array $data)\n    {\n        try {\n            $id = DB::table('page_feedback')->insertGetId($data);\n            return $id ?: false;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 更新反馈\n     *\n     * @param int $feedbackId 反馈 ID\n     * @param array $data 更新数据\n     * @return bool 是否成功\n     */\n    public static function update(int $feedbackId, array $data): bool\n    {\n        if ($feedbackId <= 0) {\n            return false;\n        }\n\n        try {\n            $affected = DB::table('page_feedback')\n                ->where('feedback_id', $feedbackId)\n                ->update($data);\n            return $affected >= 0;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 删除反馈\n     *\n     * @param int $feedbackId 反馈 ID\n     * @return bool 是否成功\n     */\n    public static function delete(int $feedbackId): bool\n    {\n        if ($feedbackId <= 0) {\n            return false;\n        }\n\n        try {\n            $affected = DB::table('page_feedback')\n                ->where('feedback_id', $feedbackId)\n                ->delete();\n            return $affected > 0;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "server/app/Model/PageHistory.php",
    "content": "<?php\n\nnamespace App\\Model;\n\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\n/**\n * 页面历史模型（开源版：使用单表 page_history，不支持分表）\n * \n * 注意：开源版的 page_content 不经过压缩存储，与主版不同。\n * 读取时兼容旧数据（可能有些是压缩的），但写入时不压缩。\n */\nclass PageHistory\n{\n    /**\n     * 添加历史版本\n     *\n     * @param int $pageId 页面 ID\n     * @param array $data 页面数据\n     * @return bool 是否成功\n     */\n    public static function add(int $pageId, array $data): bool\n    {\n        if ($pageId <= 0) {\n            return false;\n        }\n\n        // 开源版：page_content 不压缩存储，直接保存\n        // 如果传入的是压缩数据（旧数据），先解压再保存\n        if (!empty($data['page_content'])) {\n            $decoded = \\App\\Common\\Helper\\ContentCodec::decompress($data['page_content']);\n            if ($decoded !== '' && $decoded !== $data['page_content']) {\n                // 是压缩数据，解压后保存\n                $data['page_content'] = $decoded;\n            }\n            // 未压缩数据，直接保存\n        }\n\n        try {\n            return DB::table('page_history')->insert($data);\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 获取历史版本列表\n     *\n     * @param int $pageId 页面 ID\n     * @param int $limit 限制数量\n     * @return array 历史版本列表\n     */\n    public static function getList(int $pageId, int $limit = 100): array\n    {\n        if ($pageId <= 0) {\n            return [];\n        }\n\n        $rows = DB::table('page_history')\n            ->where('page_id', $pageId)\n            ->orderBy('addtime', 'desc')\n            ->limit($limit)\n            ->get()\n            ->all();\n\n        $result = [];\n        foreach ($rows as $row) {\n            $data = (array) $row;\n            $data['addtime'] = date('Y-m-d H:i:s', (int) ($data['addtime'] ?? time()));\n\n            // 开源版：page_content 不压缩存储，但兼容旧压缩数据\n            if (!empty($data['page_content'])) {\n                $decoded = \\App\\Common\\Helper\\ContentCodec::decompress($data['page_content']);\n                if ($decoded !== '' && $decoded !== $data['page_content']) {\n                    // 是压缩数据，解压后处理\n                    $data['page_content'] = htmlspecialchars_decode($decoded);\n                    $data['page_content'] = htmlspecialchars($data['page_content'], ENT_NOQUOTES);\n                } else {\n                    // 未压缩数据，直接处理\n                    $data['page_content'] = htmlspecialchars_decode($data['page_content']);\n                    $data['page_content'] = htmlspecialchars($data['page_content'], ENT_NOQUOTES);\n                }\n            }\n\n            $result[] = $data;\n        }\n\n        return $result;\n    }\n\n    /**\n     * 获取历史版本数量\n     *\n     * @param int $pageId 页面 ID\n     * @return int 数量\n     */\n    public static function getCount(int $pageId): int\n    {\n        if ($pageId <= 0) {\n            return 0;\n        }\n\n        return DB::table('page_history')\n            ->where('page_id', $pageId)\n            ->count();\n    }\n\n    /**\n     * 删除超出限制的历史版本\n     *\n     * @param int $pageId 页面 ID\n     * @param int $keepCount 保留数量\n     * @return bool 是否成功\n     */\n    public static function deleteOldVersions(int $pageId, int $keepCount): bool\n    {\n        if ($pageId <= 0 || $keepCount <= 0) {\n            return false;\n        }\n\n        // 获取需要保留的最新版本 ID\n        $rows = DB::table('page_history')\n            ->where('page_id', $pageId)\n            ->orderBy('page_history_id', 'desc')\n            ->limit($keepCount)\n            ->get()\n            ->all();\n\n        if (empty($rows) || count($rows) < $keepCount) {\n            return true; // 没有超出限制\n        }\n\n        $lastId = (int) ($rows[$keepCount - 1]->page_history_id ?? 0);\n        if ($lastId <= 0) {\n            return true;\n        }\n\n        // 删除旧版本\n        try {\n            DB::table('page_history')\n                ->where('page_id', $pageId)\n                ->where('page_history_id', '<', $lastId)\n                ->delete();\n            return true;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 更新历史版本的备注\n     *\n     * @param int $pageId 页面 ID\n     * @param int $pageHistoryId 历史版本 ID\n     * @param string $pageComments 备注\n     * @return bool 是否成功\n     */\n    public static function updateComments(int $pageId, int $pageHistoryId, string $pageComments): bool\n    {\n        if ($pageId <= 0 || $pageHistoryId <= 0) {\n            return false;\n        }\n\n        try {\n            $affected = DB::table('page_history')\n                ->where('page_history_id', $pageHistoryId)\n                ->update(['page_comments' => $pageComments]);\n            return $affected > 0;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 根据历史版本 ID 查找历史版本\n     *\n     * @param int $pageId 页面 ID\n     * @param int $pageHistoryId 历史版本 ID\n     * @return array|null 历史版本数据\n     */\n    public static function findById(int $pageId, int $pageHistoryId): ?array\n    {\n        if ($pageId <= 0 || $pageHistoryId <= 0) {\n            return null;\n        }\n\n        $row = DB::table('page_history')\n            ->where('page_id', $pageId)\n            ->where('page_history_id', $pageHistoryId)\n            ->first();\n\n        if (!$row) {\n            return null;\n        }\n\n        $data = (array) $row;\n\n        // 开源版：page_content 不压缩存储，但兼容旧压缩数据\n        if (!empty($data['page_content'])) {\n            $decoded = \\App\\Common\\Helper\\ContentCodec::decompress($data['page_content']);\n            if ($decoded !== '' && $decoded !== $data['page_content']) {\n                // 是压缩数据，解压后返回\n                $data['page_content'] = $decoded;\n            }\n            // 未压缩数据，直接返回\n        }\n\n        return $data;\n    }\n}\n\n"
  },
  {
    "path": "server/app/Model/ParameterDescriptionEntry.php",
    "content": "<?php\n\nnamespace App\\Model;\n\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\nclass ParameterDescriptionEntry\n{\n    /**\n     * 添加条目\n     *\n     * @param array $data 条目数据\n     * @return int|false 返回插入的ID，失败返回false\n     */\n    public static function add(array $data)\n    {\n        $id = DB::table('parameter_description_entry')->insertGetId($data);\n        return $id ?: false;\n    }\n\n    /**\n     * 根据ID查找条目\n     *\n     * @param string $id 条目ID\n     * @return object|null\n     */\n    public static function findById(string $id)\n    {\n        return DB::table('parameter_description_entry')\n            ->where('id', $id)\n            ->first();\n    }\n\n    /**\n     * 更新条目\n     *\n     * @param string $id 条目ID\n     * @param array $data 更新数据\n     * @return int 受影响的行数\n     */\n    public static function update(string $id, array $data): int\n    {\n        return DB::table('parameter_description_entry')\n            ->where('id', $id)\n            ->update($data);\n    }\n\n    /**\n     * 删除条目\n     *\n     * @param string|array $id 条目ID或ID数组\n     * @return int 删除的行数\n     */\n    public static function delete($id): int\n    {\n        $query = DB::table('parameter_description_entry');\n        if (is_array($id)) {\n            $query->whereIn('id', $id);\n        } else {\n            $query->where('id', $id);\n        }\n        return $query->delete();\n    }\n\n    /**\n     * 获取条目列表（支持条件查询和分页）\n     *\n     * @param array $conditions 查询条件\n     * @param int $page 页码\n     * @param int $pageSize 每页数量\n     * @param string $orderBy 排序字段\n     * @param string $orderDir 排序方向\n     * @return array ['data' => [], 'total' => int]\n     */\n    public static function getList(array $conditions = [], int $page = 1, int $pageSize = 20, string $orderBy = 'quality_score', string $orderDir = 'DESC'): array\n    {\n        $query = DB::table('parameter_description_entry');\n\n        // 应用查询条件\n        foreach ($conditions as $key => $value) {\n            if (is_array($value)) {\n                // 处理数组条件，如 ['in' => [1,2,3]]\n                if (isset($value['in'])) {\n                    $query->whereIn($key, $value['in']);\n                } elseif (isset($value['like'])) {\n                    $query->where($key, 'LIKE', $value['like']);\n                }\n            } else {\n                $query->where($key, $value);\n            }\n        }\n\n        // 计算总数\n        $total = $query->count();\n\n        // 分页\n        $offset = ($page - 1) * $pageSize;\n        $data = $query\n            ->orderBy($orderBy, $orderDir)\n            ->offset($offset)\n            ->limit($pageSize)\n            ->get()\n            ->toArray();\n\n        return [\n            'data' => $data,\n            'total' => $total\n        ];\n    }\n\n    /**\n     * 统计条目数量\n     *\n     * @param array $conditions 查询条件\n     * @return int\n     */\n    public static function count(array $conditions = []): int\n    {\n        $query = DB::table('parameter_description_entry');\n        foreach ($conditions as $key => $value) {\n            $query->where($key, $value);\n        }\n        return $query->count();\n    }\n\n    /**\n     * 获取Top使用字段\n     *\n     * @param int $itemId 项目ID\n     * @param int $limit 限制数量\n     * @return array\n     */\n    public static function getTopFields(int $itemId, int $limit = 10): array\n    {\n        return DB::table('parameter_description_entry')\n            ->where('item_id', $itemId)\n            ->select('name', 'usage_count')\n            ->orderBy('usage_count', 'DESC')\n            ->limit($limit)\n            ->get()\n            ->toArray();\n    }\n\n    /**\n     * 检查是否存在相同的条目（根据item_id、name、type）\n     *\n     * @param int $itemId 项目ID\n     * @param string $name 字段名\n     * @param string $type 字段类型\n     * @return object|null\n     */\n    public static function findExisting(int $itemId, string $name, string $type)\n    {\n        return DB::table('parameter_description_entry')\n            ->where('item_id', $itemId)\n            ->where('name', $name)\n            ->where('type', $type)\n            ->first();\n    }\n\n    /**\n     * 批量更新使用次数\n     *\n     * @param array $ids 条目ID数组\n     * @param int $itemId 项目ID（用于安全检查）\n     * @return array ['updated' => int, 'notFound' => array]\n     */\n    public static function batchUpdateUsage(array $ids, int $itemId): array\n    {\n        $updated = 0;\n        $notFound = [];\n\n        foreach ($ids as $entryId) {\n            $entry = self::findById($entryId);\n            if ($entry) {\n                // 验证该条目是否属于同一项目（安全检查）\n                if ($entry->item_id != $itemId) {\n                    continue; // 跳过不同项目的条目\n                }\n\n                $newUsageCount = $entry->usage_count + 1;\n                $result = self::update($entryId, [\n                    'usage_count' => $newUsageCount,\n                    'updated_at' => date('Y-m-d H:i:s')\n                ]);\n\n                if ($result > 0) {\n                    $updated++;\n                }\n            } else {\n                $notFound[] = $entryId;\n            }\n        }\n\n        return [\n            'updated' => $updated,\n            'notFound' => $notFound\n        ];\n    }\n}\n"
  },
  {
    "path": "server/app/Model/Questionnaire.php",
    "content": "<?php\n\nnamespace App\\Model;\n\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\nclass Questionnaire\n{\n    /**\n     * 添加问卷\n     *\n     * @param array $data 问卷数据\n     * @return int|false 返回插入的ID，失败返回false\n     */\n    public static function add(array $data)\n    {\n        try {\n            $id = DB::table('questionnaire')->insertGetId($data);\n            return $id ?: false;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 检查用户是否参与过调查\n     *\n     * @param int $uid 用户 ID\n     * @param string $title 调查标题\n     * @return bool 是否参与过\n     */\n    public static function isParticipated(int $uid, string $title): bool\n    {\n        if ($uid <= 0 || empty($title)) {\n            return false;\n        }\n\n        $row = DB::table('questionnaire')\n            ->where('uid', $uid)\n            ->where('title', $title)\n            ->first();\n\n        return $row !== null;\n    }\n}\n"
  },
  {
    "path": "server/app/Model/Recycle.php",
    "content": "<?php\n\nnamespace App\\Model;\n\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\nclass Recycle\n{\n    /**\n     * 添加回收站记录\n     *\n     * @param array $data 回收站数据\n     * @return bool 是否成功\n     */\n    public static function add(array $data): bool\n    {\n        try {\n            $insertData = [\n                'item_id' => (int) ($data['item_id'] ?? 0),\n                'page_id' => (int) ($data['page_id'] ?? 0),\n                'page_title' => (string) ($data['page_title'] ?? ''),\n                'del_by_uid' => (int) ($data['del_by_uid'] ?? 0),\n                'del_by_username' => (string) ($data['del_by_username'] ?? ''),\n                'del_time' => (int) ($data['del_time'] ?? time()),\n            ];\n\n            // 检查是否已存在（避免重复插入）\n            $exists = DB::table('recycle')\n                ->where('item_id', $insertData['item_id'])\n                ->where('page_id', $insertData['page_id'])\n                ->first();\n\n            if ($exists) {\n                // 如果已存在，更新记录\n                DB::table('recycle')\n                    ->where('item_id', $insertData['item_id'])\n                    ->where('page_id', $insertData['page_id'])\n                    ->update($insertData);\n                return true;\n            }\n\n            // 插入新记录\n            DB::table('recycle')->insert($insertData);\n            return true;\n        } catch (\\Throwable $e) {\n            error_log(\"Recycle::add error: \" . $e->getMessage());\n            return false;\n        }\n    }\n\n    /**\n     * 获取回收站列表\n     *\n     * @param int $itemId 项目 ID\n     * @return array 回收站列表\n     */\n    public static function getList(int $itemId): array\n    {\n        if ($itemId <= 0) {\n            return [];\n        }\n\n        $rows = DB::table('recycle')\n            ->where('item_id', $itemId)\n            ->orderBy('del_time', 'desc')\n            ->get()\n            ->all();\n\n        $result = [];\n        foreach ($rows as $row) {\n            $data = (array) $row;\n            $data['del_time'] = date('Y-m-d H:i:s', (int) ($data['del_time'] ?? time()));\n            $result[] = $data;\n        }\n\n        return $result;\n    }\n\n    /**\n     * 删除回收站记录\n     *\n     * @param int $itemId 项目 ID\n     * @param int $pageId 页面 ID\n     * @return bool 是否成功\n     */\n    public static function delete(int $itemId, int $pageId): bool\n    {\n        if ($itemId <= 0 || $pageId <= 0) {\n            return false;\n        }\n\n        try {\n            $deleted = DB::table('recycle')\n                ->where('item_id', $itemId)\n                ->where('page_id', $pageId)\n                ->delete();\n            return $deleted > 0;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 获取旧的已删除页面（超过指定天数）\n     *\n     * @param int $days 天数\n     * @return array 页面列表\n     */\n    public static function getOldDeletedPages(int $days): array\n    {\n        if ($days <= 0) {\n            return [];\n        }\n\n        $time = time() - ($days * 24 * 60 * 60);\n        $rows = DB::table('recycle')\n            ->where('del_time', '<', $time)\n            ->get()\n            ->all();\n\n        $result = [];\n        foreach ($rows as $row) {\n            $result[] = (array) $row;\n        }\n\n        return $result;\n    }\n\n    /**\n     * 根据 ID 删除回收站记录\n     *\n     * @param int $id 记录 ID\n     * @return bool 是否成功\n     */\n    public static function deleteById(int $id): bool\n    {\n        if ($id <= 0) {\n            return false;\n        }\n\n        try {\n            $deleted = DB::table('recycle')\n                ->where('id', $id)\n                ->delete();\n            return $deleted > 0;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "server/app/Model/Runapi.php",
    "content": "<?php\n\nnamespace App\\Model;\n\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\nclass Runapi\n{\n    /**\n     * 获取项目的全局参数\n     * 与旧代码 RunapiModel::getGlobalParam 逻辑一致\n     *\n     * @param int $itemId 项目 ID\n     * @return array 全局参数数组，包含 query、body、header、cookies、preScript、postScript\n     */\n    public static function getGlobalParam(int $itemId): array\n    {\n        if ($itemId <= 0) {\n            return [\n                'query' => [],\n                'body' => [],\n                'header' => [],\n                'cookies' => [],\n                'preScript' => '',\n                'postScript' => '',\n            ];\n        }\n\n        $return = [\n            'query' => [],\n            'body' => [],\n            'header' => [],\n            'cookies' => [],\n            'preScript' => '',\n            'postScript' => '',\n        ];\n\n        // 获取 query 参数\n        $res = RunapiGlobalParam::findByItemIdAndType($itemId, 'query');\n        if ($res) {\n            $content = htmlspecialchars_decode($res['content_json_str'] ?? '[]');\n            $return['query'] = json_decode($content, true) ?: [];\n        } else {\n            // 如果不存在，创建默认记录\n            DB::table('runapi_global_param')->insert([\n                'param_type' => 'query',\n                'item_id' => $itemId,\n                'content_json_str' => '[]',\n                'addtime' => date('Y-m-d H:i:s'),\n                'last_update_time' => date('Y-m-d H:i:s'),\n            ]);\n        }\n\n        // 获取 body 参数\n        $res = RunapiGlobalParam::findByItemIdAndType($itemId, 'body');\n        if ($res) {\n            $content = htmlspecialchars_decode($res['content_json_str'] ?? '[]');\n            $return['body'] = json_decode($content, true) ?: [];\n        } else {\n            DB::table('runapi_global_param')->insert([\n                'param_type' => 'body',\n                'item_id' => $itemId,\n                'content_json_str' => '[]',\n                'addtime' => date('Y-m-d H:i:s'),\n                'last_update_time' => date('Y-m-d H:i:s'),\n            ]);\n        }\n\n        // 获取 header 参数\n        $res = RunapiGlobalParam::findByItemIdAndType($itemId, 'header');\n        if ($res) {\n            $content = htmlspecialchars_decode($res['content_json_str'] ?? '[]');\n            $return['header'] = json_decode($content, true) ?: [];\n        } else {\n            DB::table('runapi_global_param')->insert([\n                'param_type' => 'header',\n                'item_id' => $itemId,\n                'content_json_str' => '[]',\n                'addtime' => date('Y-m-d H:i:s'),\n                'last_update_time' => date('Y-m-d H:i:s'),\n            ]);\n        }\n\n        // 获取 cookies 参数\n        $res = RunapiGlobalParam::findByItemIdAndType($itemId, 'cookies');\n        if ($res) {\n            $content = htmlspecialchars_decode($res['content_json_str'] ?? '[]');\n            $return['cookies'] = json_decode($content, true) ?: [];\n        } else {\n            DB::table('runapi_global_param')->insert([\n                'param_type' => 'cookies',\n                'item_id' => $itemId,\n                'content_json_str' => '[]',\n                'addtime' => date('Y-m-d H:i:s'),\n                'last_update_time' => date('Y-m-d H:i:s'),\n            ]);\n        }\n\n        // 获取 preScript\n        $res = RunapiGlobalParam::findByItemIdAndType($itemId, 'preScript');\n        if ($res) {\n            $return['preScript'] = htmlspecialchars_decode($res['content_json_str'] ?? '');\n        } else {\n            DB::table('runapi_global_param')->insert([\n                'param_type' => 'preScript',\n                'item_id' => $itemId,\n                'content_json_str' => '',\n                'addtime' => date('Y-m-d H:i:s'),\n                'last_update_time' => date('Y-m-d H:i:s'),\n            ]);\n        }\n\n        // 获取 postScript\n        $res = RunapiGlobalParam::findByItemIdAndType($itemId, 'postScript');\n        if ($res) {\n            $return['postScript'] = htmlspecialchars_decode($res['content_json_str'] ?? '');\n        } else {\n            DB::table('runapi_global_param')->insert([\n                'param_type' => 'postScript',\n                'item_id' => $itemId,\n                'content_json_str' => '',\n                'addtime' => date('Y-m-d H:i:s'),\n                'last_update_time' => date('Y-m-d H:i:s'),\n            ]);\n        }\n\n        return $return;\n    }\n}\n"
  },
  {
    "path": "server/app/Model/RunapiDbConfig.php",
    "content": "<?php\n\nnamespace App\\Model;\n\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\nclass RunapiDbConfig\n{\n    /**\n     * 添加数据库配置\n     *\n     * @param array $data 配置数据\n     * @return int|false 返回配置 ID，失败返回 false\n     */\n    public static function add(array $data)\n    {\n        if (empty($data['item_id']) || empty($data['env_id'])) {\n            return false;\n        }\n\n        try {\n            $id = DB::table('runapi_db_config')->insertGetId($data);\n            return $id ?: false;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 更新数据库配置\n     *\n     * @param int $configId 配置 ID\n     * @param array $data 更新数据\n     * @return bool 是否成功\n     */\n    public static function update(int $configId, array $data): bool\n    {\n        if ($configId <= 0) {\n            return false;\n        }\n\n        try {\n            $affected = DB::table('runapi_db_config')\n                ->where('id', $configId)\n                ->update($data);\n            return $affected > 0;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 根据 ID 查找配置\n     *\n     * @param int $configId 配置 ID\n     * @return array|null 配置数据\n     */\n    public static function findById(int $configId): ?array\n    {\n        if ($configId <= 0) {\n            return null;\n        }\n\n        $row = DB::table('runapi_db_config')\n            ->where('id', $configId)\n            ->first();\n\n        return $row ? (array) $row : null;\n    }\n\n    /**\n     * 根据项目 ID 和环境 ID 获取配置列表\n     *\n     * @param int $itemId 项目 ID\n     * @param int $envId 环境 ID\n     * @return array 配置列表\n     */\n    public static function getListByItemIdAndEnvId(int $itemId, int $envId): array\n    {\n        if ($itemId <= 0 || $envId <= 0) {\n            return [];\n        }\n\n        $rows = DB::table('runapi_db_config')\n            ->where('item_id', $itemId)\n            ->where('env_id', $envId)\n            ->orderBy('is_default', 'desc')\n            ->orderBy('id', 'asc')\n            ->get()\n            ->all();\n\n        $result = [];\n        foreach ($rows as $row) {\n            $result[] = (array) $row;\n        }\n\n        return $result;\n    }\n\n    /**\n     * 删除配置\n     *\n     * @param int $configId 配置 ID\n     * @return bool 是否成功\n     */\n    public static function delete(int $configId): bool\n    {\n        if ($configId <= 0) {\n            return false;\n        }\n\n        try {\n            $affected = DB::table('runapi_db_config')\n                ->where('id', $configId)\n                ->delete();\n            return $affected > 0;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 取消其他配置的默认状态\n     *\n     * @param int $itemId 项目 ID\n     * @param int $envId 环境 ID\n     * @param int $excludeConfigId 排除的配置 ID\n     * @return bool 是否成功\n     */\n    public static function unsetDefaultOthers(int $itemId, int $envId, int $excludeConfigId): bool\n    {\n        if ($itemId <= 0 || $envId <= 0) {\n            return false;\n        }\n\n        try {\n            $affected = DB::table('runapi_db_config')\n                ->where('item_id', $itemId)\n                ->where('env_id', $envId)\n                ->where('id', '!=', $excludeConfigId)\n                ->update([\n                    'is_default'       => 0,\n                    'last_update_time' => date('Y-m-d H:i:s'),\n                ]);\n            return $affected >= 0;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "server/app/Model/RunapiEnv.php",
    "content": "<?php\n\nnamespace App\\Model;\n\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\nclass RunapiEnv\n{\n    /**\n     * 添加环境\n     *\n     * @param array $data 环境数据\n     * @return int|false 返回环境 ID，失败返回 false\n     */\n    public static function add(array $data)\n    {\n        if (empty($data['item_id']) || empty($data['env_name'])) {\n            return false;\n        }\n\n        try {\n            $id = DB::table('runapi_env')->insertGetId($data);\n            return $id ?: false;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 更新环境\n     *\n     * @param int $envId 环境 ID\n     * @param int $itemId 项目 ID\n     * @param array $data 更新数据\n     * @return bool 是否成功\n     */\n    public static function update(int $envId, int $itemId, array $data): bool\n    {\n        if ($envId <= 0 || $itemId <= 0) {\n            return false;\n        }\n\n        try {\n            $affected = DB::table('runapi_env')\n                ->where('id', $envId)\n                ->where('item_id', $itemId)\n                ->update($data);\n            return $affected > 0;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 根据 ID 查找环境\n     *\n     * @param int $envId 环境 ID\n     * @return array|null 环境数据\n     */\n    public static function findById(int $envId): ?array\n    {\n        if ($envId <= 0) {\n            return null;\n        }\n\n        $row = DB::table('runapi_env')\n            ->where('id', $envId)\n            ->first();\n\n        return $row ? (array) $row : null;\n    }\n\n    /**\n     * 根据项目 ID 获取环境列表\n     *\n     * @param int $itemId 项目 ID\n     * @return array 环境列表\n     */\n    public static function getListByItemId(int $itemId): array\n    {\n        if ($itemId <= 0) {\n            return [];\n        }\n\n        $rows = DB::table('runapi_env')\n            ->where('item_id', $itemId)\n            ->orderBy('id', 'asc')\n            ->get()\n            ->all();\n\n        $result = [];\n        foreach ($rows as $row) {\n            $result[] = (array) $row;\n        }\n\n        return $result;\n    }\n\n    /**\n     * 删除环境\n     *\n     * @param int $envId 环境 ID\n     * @return bool 是否成功\n     */\n    public static function delete(int $envId): bool\n    {\n        if ($envId <= 0) {\n            return false;\n        }\n\n        try {\n            $affected = DB::table('runapi_env')\n                ->where('id', $envId)\n                ->delete();\n            return $affected > 0;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "server/app/Model/RunapiEnvSelectd.php",
    "content": "<?php\n\nnamespace App\\Model;\n\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\nclass RunapiEnvSelectd\n{\n    /**\n     * 添加选中的环境\n     *\n     * @param array $data 数据\n     * @return int|false 返回 ID，失败返回 false\n     */\n    public static function add(array $data)\n    {\n        if (empty($data['item_id']) || empty($data['uid']) || empty($data['env_id'])) {\n            return false;\n        }\n\n        try {\n            $id = DB::table('runapi_env_selectd')->insertGetId($data);\n            return $id ?: false;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 根据项目 ID 和用户 ID 查找选中的环境\n     *\n     * @param int $itemId 项目 ID\n     * @param int $uid 用户 ID\n     * @return array|null 环境数据\n     */\n    public static function findByItemIdAndUid(int $itemId, int $uid): ?array\n    {\n        if ($itemId <= 0 || $uid <= 0) {\n            return null;\n        }\n\n        $row = DB::table('runapi_env_selectd')\n            ->where('item_id', $itemId)\n            ->where('uid', $uid)\n            ->first();\n\n        return $row ? (array) $row : null;\n    }\n\n    /**\n     * 删除选中的环境\n     *\n     * @param int $itemId 项目 ID\n     * @param int $uid 用户 ID\n     * @return bool 是否成功\n     */\n    public static function deleteByItemIdAndUid(int $itemId, int $uid): bool\n    {\n        if ($itemId <= 0 || $uid <= 0) {\n            return false;\n        }\n\n        try {\n            $affected = DB::table('runapi_env_selectd')\n                ->where('item_id', $itemId)\n                ->where('uid', $uid)\n                ->delete();\n            return $affected >= 0; // 即使没有删除（affected=0）也算成功\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 根据环境 ID 删除\n     *\n     * @param int $envId 环境 ID\n     * @return bool 是否成功\n     */\n    public static function deleteByEnvId(int $envId): bool\n    {\n        if ($envId <= 0) {\n            return false;\n        }\n\n        try {\n            $affected = DB::table('runapi_env_selectd')\n                // 注意：这里应根据 env_id 删除，而不是主键 id\n                ->where('env_id', $envId)\n                ->delete();\n            return $affected >= 0;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "server/app/Model/RunapiFlow.php",
    "content": "<?php\n\nnamespace App\\Model;\n\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\nclass RunapiFlow\n{\n    /**\n     * 根据 ID 查找流程\n     *\n     * @param int $id 流程 ID\n     * @return object|null 流程对象，不存在返回 null\n     */\n    public static function findById(int $id): ?object\n    {\n        if ($id <= 0) {\n            return null;\n        }\n\n        return DB::table('runapi_flow')\n            ->where('id', $id)\n            ->first();\n    }\n\n    /**\n     * 根据项目 ID 获取流程列表\n     *\n     * @param int $itemId 项目 ID\n     * @return array 流程列表\n     */\n    public static function getListByItemId(int $itemId): array\n    {\n        if ($itemId <= 0) {\n            return [];\n        }\n\n        $rows = DB::table('runapi_flow')\n            ->where('item_id', $itemId)\n            ->orderBy('id', 'desc')\n            ->get()\n            ->all();\n\n        $result = [];\n        foreach ($rows as $row) {\n            $result[] = (array) $row;\n        }\n\n        return $result;\n    }\n\n    /**\n     * 添加流程\n     *\n     * @param array $data 流程数据\n     * @return int|false 返回插入的ID，失败返回false\n     */\n    public static function add(array $data)\n    {\n        try {\n            $id = DB::table('runapi_flow')->insertGetId($data);\n            return $id ?: false;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 更新流程\n     *\n     * @param int $id 流程 ID\n     * @param array $data 更新数据\n     * @return bool 是否成功\n     */\n    public static function update(int $id, array $data): bool\n    {\n        if ($id <= 0) {\n            return false;\n        }\n\n        try {\n            $affected = DB::table('runapi_flow')\n                ->where('id', $id)\n                ->update($data);\n            return $affected >= 0;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 删除流程\n     *\n     * @param int $id 流程 ID\n     * @return bool 是否成功\n     */\n    public static function delete(int $id): bool\n    {\n        if ($id <= 0) {\n            return false;\n        }\n\n        try {\n            $affected = DB::table('runapi_flow')\n                ->where('id', $id)\n                ->delete();\n            return $affected > 0;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "server/app/Model/RunapiFlowPage.php",
    "content": "<?php\n\nnamespace App\\Model;\n\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\nclass RunapiFlowPage\n{\n    /**\n     * 根据流程 ID 获取页面列表\n     *\n     * @param int $flowId 流程 ID\n     * @return array 页面列表\n     */\n    public static function getListByFlowId(int $flowId): array\n    {\n        if ($flowId <= 0) {\n            return [];\n        }\n\n        $rows = DB::table('runapi_flow_page')\n            ->where('flow_id', $flowId)\n            ->orderBy('s_number', 'asc')\n            ->get()\n            ->all();\n\n        $result = [];\n        foreach ($rows as $row) {\n            $result[] = (array) $row;\n        }\n\n        return $result;\n    }\n\n    /**\n     * 获取流程中最后一个页面的顺序号\n     *\n     * @param int $flowId 流程 ID\n     * @return int 顺序号，如果没有则返回 0\n     */\n    public static function getLastSNumber(int $flowId): int\n    {\n        if ($flowId <= 0) {\n            return 0;\n        }\n\n        $row = DB::table('runapi_flow_page')\n            ->where('flow_id', $flowId)\n            ->orderBy('s_number', 'desc')\n            ->first();\n\n        return $row ? (int) ($row->s_number ?? 0) : 0;\n    }\n\n    /**\n     * 根据 ID 查找流程页面\n     *\n     * @param int $id 流程页面 ID\n     * @return object|null 流程页面对象，不存在返回 null\n     */\n    public static function findById(int $id): ?object\n    {\n        if ($id <= 0) {\n            return null;\n        }\n\n        return DB::table('runapi_flow_page')\n            ->where('id', $id)\n            ->first();\n    }\n\n    /**\n     * 添加流程页面\n     *\n     * @param array $data 流程页面数据\n     * @return int|false 返回插入的ID，失败返回false\n     */\n    public static function add(array $data)\n    {\n        try {\n            $id = DB::table('runapi_flow_page')->insertGetId($data);\n            return $id ?: false;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 更新流程页面\n     *\n     * @param int $flowId 流程 ID\n     * @param int $id 流程页面 ID\n     * @param array $data 更新数据\n     * @return bool 是否成功\n     */\n    public static function update(int $flowId, int $id, array $data): bool\n    {\n        if ($flowId <= 0 || $id <= 0) {\n            return false;\n        }\n\n        try {\n            $affected = DB::table('runapi_flow_page')\n                ->where('flow_id', $flowId)\n                ->where('id', $id)\n                ->update($data);\n            return $affected >= 0;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 批量更新流程页面的顺序号\n     *\n     * @param int $flowId 流程 ID\n     * @param array $orders 顺序数组 [['id' => 1, 's_number' => 1], ...]\n     * @return bool 是否成功\n     */\n    public static function updateSort(int $flowId, array $orders): bool\n    {\n        if ($flowId <= 0 || empty($orders)) {\n            return false;\n        }\n\n        try {\n            foreach ($orders as $order) {\n                $id = (int) ($order['id'] ?? 0);\n                $sNumber = (int) ($order['s_number'] ?? 0);\n                if ($id > 0) {\n                    DB::table('runapi_flow_page')\n                        ->where('flow_id', $flowId)\n                        ->where('id', $id)\n                        ->update(['s_number' => $sNumber]);\n                }\n            }\n            return true;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 批量设置流程页面的启用状态\n     *\n     * @param int $flowId 流程 ID\n     * @param array $ids 启用的页面 ID 数组\n     * @return bool 是否成功\n     */\n    public static function setEnabled(int $flowId, array $ids): bool\n    {\n        if ($flowId <= 0) {\n            return false;\n        }\n\n        try {\n            // 先全部禁用\n            DB::table('runapi_flow_page')\n                ->where('flow_id', $flowId)\n                ->update(['enabled' => 0]);\n\n            // 然后启用指定的页面\n            if (!empty($ids)) {\n                foreach ($ids as $id) {\n                    $id = (int) $id;\n                    if ($id > 0) {\n                        DB::table('runapi_flow_page')\n                            ->where('flow_id', $flowId)\n                            ->where('id', $id)\n                            ->update(['enabled' => 1]);\n                    }\n                }\n            }\n\n            return true;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 删除流程页面\n     *\n     * @param int $id 流程页面 ID\n     * @return bool 是否成功\n     */\n    public static function delete(int $id): bool\n    {\n        if ($id <= 0) {\n            return false;\n        }\n\n        try {\n            $affected = DB::table('runapi_flow_page')\n                ->where('id', $id)\n                ->delete();\n            return $affected > 0;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "server/app/Model/RunapiGlobalParam.php",
    "content": "<?php\n\nnamespace App\\Model;\n\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\nclass RunapiGlobalParam\n{\n    /**\n     * 根据项目 ID 和参数类型获取全局参数\n     *\n     * @param int $itemId 项目 ID\n     * @param string $paramType 参数类型\n     * @return array|null 参数数据\n     */\n    public static function findByItemIdAndType(int $itemId, string $paramType): ?array\n    {\n        if ($itemId <= 0 || empty($paramType)) {\n            return null;\n        }\n\n        $row = DB::table('runapi_global_param')\n            ->where('item_id', $itemId)\n            ->where('param_type', $paramType)\n            ->first();\n\n        return $row ? (array) $row : null;\n    }\n\n    /**\n     * 更新全局参数\n     *\n     * @param int $itemId 项目 ID\n     * @param string $paramType 参数类型\n     * @param string $contentJsonStr 内容 JSON 字符串\n     * @return bool 是否成功\n     */\n    public static function update(int $itemId, string $paramType, string $contentJsonStr): bool\n    {\n        if ($itemId <= 0 || empty($paramType)) {\n            return false;\n        }\n\n        try {\n            // 先查找是否存在\n            $existing = self::findByItemIdAndType($itemId, $paramType);\n            if ($existing) {\n                // 更新\n                $affected = DB::table('runapi_global_param')\n                    ->where('item_id', $itemId)\n                    ->where('param_type', $paramType)\n                    ->update([\n                        'content_json_str' => $contentJsonStr,\n                        'last_update_time' => date('Y-m-d H:i:s'),\n                    ]);\n                return $affected >= 0;\n            } else {\n                // 新建\n                $id = DB::table('runapi_global_param')->insertGetId([\n                    'item_id'          => $itemId,\n                    'param_type'       => $paramType,\n                    'content_json_str' => $contentJsonStr,\n                    'last_update_time' => date('Y-m-d H:i:s'),\n                ]);\n                return $id > 0;\n            }\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "server/app/Model/SinglePage.php",
    "content": "<?php\n\nnamespace App\\Model;\n\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\nclass SinglePage\n{\n    /**\n     * 获取单页链接的唯一标识\n     *\n     * @param int $pageId 页面 ID\n     * @return string 唯一标识，不存在或已过期返回空字符串\n     */\n    public static function getUniqueKey(int $pageId): string\n    {\n        if ($pageId <= 0) {\n            return '';\n        }\n\n        $row = DB::table('single_page')\n            ->where('page_id', $pageId)\n            ->first();\n\n        if (!$row) {\n            return '';\n        }\n\n        // 检查是否已过期\n        $expireTime = (int) ($row->expire_time ?? 0);\n        if ($expireTime > 0 && $expireTime < time()) {\n            // 链接已过期，删除记录\n            DB::table('single_page')\n                ->where('page_id', $pageId)\n                ->delete();\n            return '';\n        }\n\n        return (string) ($row->unique_key ?? '');\n    }\n\n    /**\n     * 根据唯一标识查找单页\n     *\n     * @param string $uniqueKey 唯一标识\n     * @return object|null 单页记录，不存在返回 null\n     */\n    public static function findByUniqueKey(string $uniqueKey): ?object\n    {\n        if (empty($uniqueKey)) {\n            return null;\n        }\n\n        $row = DB::table('single_page')\n            ->where('unique_key', $uniqueKey)\n            ->first();\n\n        if (!$row) {\n            return null;\n        }\n\n        // 检查是否已过期\n        $expireTime = (int) ($row->expire_time ?? 0);\n        if ($expireTime > 0 && $expireTime < time()) {\n            // 链接已过期，删除记录\n            DB::table('single_page')\n                ->where('unique_key', $uniqueKey)\n                ->delete();\n            return null;\n        }\n\n        return $row;\n    }\n}\n"
  },
  {
    "path": "server/app/Model/Subscription.php",
    "content": "<?php\n\nnamespace App\\Model;\n\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\n/**\n * 订阅模型（开源版：使用单表 subscription，不支持分表）\n */\nclass Subscription\n{\n    /**\n     * 添加订阅\n     *\n     * @param int $uid 用户 ID\n     * @param int $objectId 对象 ID\n     * @param string $objectType 对象类型（page 等）\n     * @param string $actionType 操作类型（update 等）\n     * @return int|false 订阅 ID，失败返回 false\n     */\n    public static function addSub(int $uid, int $objectId, string $objectType, string $actionType)\n    {\n        if ($uid <= 0 || $objectId <= 0) {\n            return false;\n        }\n\n        // 检测是否已经存在订阅\n        $existing = DB::table('subscription')\n            ->where('uid', $uid)\n            ->where('object_id', $objectId)\n            ->where('object_type', $objectType)\n            ->where('action_type', $actionType)\n            ->first();\n\n        if ($existing) {\n            // 已存在，返回现有 ID\n            return (int) $existing->id;\n        }\n\n        // 添加新订阅\n        try {\n            $id = DB::table('subscription')->insertGetId([\n                'uid' => $uid,\n                'object_id' => $objectId,\n                'object_type' => $objectType,\n                'action_type' => $actionType,\n                'sub_time' => date('Y-m-d H:i:s'),\n            ]);\n\n            return (int) $id;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 删除订阅\n     *\n     * @param int $uid 用户 ID\n     * @param int $objectId 对象 ID\n     * @param string $objectType 对象类型\n     * @param string $actionType 操作类型\n     * @return bool 是否成功\n     */\n    public static function deleteSub(int $uid, int $objectId, string $objectType, string $actionType): bool\n    {\n        if ($uid <= 0 || $objectId <= 0) {\n            return false;\n        }\n\n        try {\n            $deleted = DB::table('subscription')\n                ->where('uid', $uid)\n                ->where('object_id', $objectId)\n                ->where('object_type', $objectType)\n                ->where('action_type', $actionType)\n                ->delete();\n\n            return $deleted > 0;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 根据对象 ID 获取订阅列表\n     *\n     * @param int $objectId 对象 ID\n     * @param string $objectType 对象类型\n     * @param string $actionType 操作类型\n     * @return array\n     */\n    public static function getListByObjectId(int $objectId, string $objectType, string $actionType): array\n    {\n        if ($objectId <= 0) {\n            return [];\n        }\n\n        $list = DB::table('subscription')\n            ->where('object_id', $objectId)\n            ->where('object_type', $objectType)\n            ->where('action_type', $actionType)\n            ->get()\n            ->all();\n\n        $result = [];\n        foreach ($list as $row) {\n            $result[] = (array) $row;\n        }\n\n        return $result;\n    }\n}\n\n"
  },
  {
    "path": "server/app/Model/Team.php",
    "content": "<?php\n\nnamespace App\\Model;\n\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\nclass Team\n{\n    /**\n     * 添加团队\n     *\n     * @param int $uid 用户 ID\n     * @param string $username 用户名\n     * @param string $teamName 团队名称\n     * @return int 新创建的团队 ID，失败返回 0\n     */\n    public static function add(int $uid, string $username, string $teamName): int\n    {\n        if ($uid <= 0 || empty($teamName)) {\n            return 0;\n        }\n\n        try {\n            $id = DB::table('team')->insertGetId([\n                'username' => $username,\n                'uid'      => $uid,\n                'team_name' => $teamName,\n                'addtime'  => time(),\n            ]);\n            return (int) $id;\n        } catch (\\Throwable $e) {\n            return 0;\n        }\n    }\n\n    /**\n     * 更新团队\n     *\n     * @param int $id 团队 ID\n     * @param string $teamName 团队名称\n     * @return bool 是否成功\n     */\n    public static function update(int $id, string $teamName): bool\n    {\n        if ($id <= 0 || empty($teamName)) {\n            return false;\n        }\n\n        try {\n            $affected = DB::table('team')\n                ->where('id', $id)\n                ->update(['team_name' => $teamName]);\n            return $affected > 0;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 保存团队（新建或更新）\n     *\n     * @param int $id 团队 ID（0 表示新建）\n     * @param int $uid 用户 ID\n     * @param string $username 用户名\n     * @param string $teamName 团队名称\n     * @return int 团队 ID，失败返回 0\n     */\n    public static function save(int $id, int $uid, string $username, string $teamName): int\n    {\n        if ($id > 0) {\n            $success = self::update($id, $teamName);\n            return $success ? $id : 0;\n        } else {\n            return self::add($uid, $username, $teamName);\n        }\n    }\n\n    /**\n     * 获取用户的团队列表（包括创建的和参与的）\n     *\n     * @param int $uid 用户 ID\n     * @return array 团队列表\n     */\n    public static function getList(int $uid): array\n    {\n        if ($uid <= 0) {\n            return [];\n        }\n\n        $rows = DB::table('team')\n            ->where(function ($q) use ($uid) {\n                $q->where('uid', $uid)\n                    ->orWhereIn('id', function ($subQ) use ($uid) {\n                        $subQ->select('team_id')\n                            ->from('team_member')\n                            ->where('member_uid', $uid);\n                    });\n            })\n            ->orderBy('addtime', 'desc')\n            ->get()\n            ->all();\n\n        $result = [];\n        foreach ($rows as $row) {\n            $data = (array) $row;\n\n            // 获取团队成员数\n            $data['memberCount'] = DB::table('team_member')\n                ->where('team_id', $data['id'])\n                ->count();\n\n            // 获取团队涉及项目数\n            $data['itemCount'] = DB::table('team_item')\n                ->where('team_id', $data['id'])\n                ->count();\n\n            $data['addtime'] = date('Y-m-d H:i:s', (int) ($data['addtime'] ?? time()));\n\n            $result[] = $data;\n        }\n\n        return $result;\n    }\n\n    /**\n     * 删除团队\n     *\n     * @param int $id 团队 ID\n     * @param int $uid 用户 ID（必须是团队创建者）\n     * @return bool 是否成功\n     */\n    public static function delete(int $id, int $uid): bool\n    {\n        if ($id <= 0 || $uid <= 0) {\n            return false;\n        }\n\n        try {\n            // 只有团队创建者才能删除\n            $deleted = DB::table('team')\n                ->where('id', $id)\n                ->where('uid', $uid)\n                ->delete();\n\n            if ($deleted > 0) {\n                // 删除关联数据\n                DB::table('team_item')\n                    ->where('team_id', $id)\n                    ->delete();\n\n                DB::table('team_item_member')\n                    ->where('team_id', $id)\n                    ->delete();\n\n                DB::table('team_member')\n                    ->where('team_id', $id)\n                    ->delete();\n            }\n\n            return $deleted > 0;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 根据 ID 查找团队\n     *\n     * @param int $id 团队 ID\n     * @param int $uid 用户 ID（可选，用于权限检查）\n     * @return object|null\n     */\n    public static function findById(int $id, int $uid = 0): ?object\n    {\n        if ($id <= 0) {\n            return null;\n        }\n\n        $query = DB::table('team')->where('id', $id);\n\n        if ($uid > 0) {\n            $query->where('uid', $uid);\n        }\n\n        return $query->first();\n    }\n\n    /**\n     * 转让团队\n     *\n     * @param int $teamId 团队 ID\n     * @param int $fromUid 原创建者用户 ID\n     * @param int $toUid 新创建者用户 ID\n     * @param string $toUsername 新创建者用户名\n     * @return bool 是否成功\n     */\n    public static function attorn(int $teamId, int $fromUid, int $toUid, string $toUsername): bool\n    {\n        if ($teamId <= 0 || $fromUid <= 0 || $toUid <= 0) {\n            return false;\n        }\n\n        try {\n            DB::beginTransaction();\n\n            // 更新团队创建者\n            DB::table('team')\n                ->where('id', $teamId)\n                ->where('uid', $fromUid)\n                ->update([\n                    'username' => $toUsername,\n                    'uid'      => $toUid,\n                ]);\n\n            // 获取该团队下的所有项目，准备转让\n            $items = DB::table('team_item')\n                ->where('team_id', $teamId)\n                ->get()\n                ->all();\n\n            foreach ($items as $item) {\n                DB::table('item')\n                    ->where('item_id', $item->item_id)\n                    ->update([\n                        'username' => $toUsername,\n                        'uid'      => $toUid,\n                    ]);\n            }\n\n            DB::commit();\n            return true;\n        } catch (\\Throwable $e) {\n            DB::rollBack();\n            return false;\n        }\n    }\n\n    /**\n     * 用户退出团队\n     *\n     * @param int $teamId 团队 ID\n     * @param int $uid 用户 ID\n     * @return bool 是否成功\n     */\n    public static function exitTeam(int $teamId, int $uid): bool\n    {\n        if ($teamId <= 0 || $uid <= 0) {\n            return false;\n        }\n\n        try {\n            DB::beginTransaction();\n\n            // 删除团队项目成员关系\n            DB::table('team_item_member')\n                ->where('team_id', $teamId)\n                ->where('member_uid', $uid)\n                ->delete();\n\n            // 删除团队成员关系\n            DB::table('team_member')\n                ->where('team_id', $teamId)\n                ->where('member_uid', $uid)\n                ->delete();\n\n            DB::commit();\n            return true;\n        } catch (\\Throwable $e) {\n            DB::rollBack();\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "server/app/Model/TeamItem.php",
    "content": "<?php\n\nnamespace App\\Model;\n\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\nclass TeamItem\n{\n    /**\n     * 添加团队项目关联\n     *\n     * @param array $data 关联数据\n     * @return int|false 返回插入的ID，失败返回false\n     */\n    public static function add(array $data)\n    {\n        try {\n            $id = DB::table('team_item')->insertGetId($data);\n            return $id ?: false;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 根据项目 ID 获取团队列表（关联 team 表）\n     *\n     * @param int $itemId 项目 ID\n     * @return array 团队列表\n     */\n    public static function getListByItemId(int $itemId): array\n    {\n        if ($itemId <= 0) {\n            return [];\n        }\n\n        $rows = DB::table('team')\n            ->leftJoin('team_item', 'team.id', '=', 'team_item.team_id')\n            ->where('team_item.item_id', $itemId)\n            ->select('team.*', 'team_item.team_id', 'team_item.id as id')\n            ->get()\n            ->all();\n\n        $result = [];\n        foreach ($rows as $row) {\n            $data = (array) $row;\n            $data['addtime'] = date('Y-m-d H:i:s', (int) ($data['addtime'] ?? time()));\n            $result[] = $data;\n        }\n\n        return $result;\n    }\n\n    /**\n     * 根据团队 ID 获取项目列表（关联 item 表）\n     *\n     * @param int $teamId 团队 ID\n     * @return array 项目列表\n     */\n    public static function getListByTeamId(int $teamId): array\n    {\n        if ($teamId <= 0) {\n            return [];\n        }\n\n        $rows = DB::table('item')\n            ->leftJoin('team_item', 'item.item_id', '=', 'team_item.item_id')\n            ->where('team_item.team_id', $teamId)\n            ->where('item.is_del', 0)\n            ->select('item.*', 'team_item.team_id', 'team_item.id as id')\n            ->get()\n            ->all();\n\n        $result = [];\n        foreach ($rows as $row) {\n            $data = (array) $row;\n            $data['addtime'] = date('Y-m-d H:i:s', (int) ($data['addtime'] ?? time()));\n            $result[] = $data;\n        }\n\n        return $result;\n    }\n\n    /**\n     * 根据 ID 查找团队项目关联\n     *\n     * @param int $id 关联 ID\n     * @return object|null 关联记录，不存在返回 null\n     */\n    public static function findById(int $id): ?object\n    {\n        if ($id <= 0) {\n            return null;\n        }\n\n        return DB::table('team_item')\n            ->where('id', $id)\n            ->first();\n    }\n\n    /**\n     * 检查团队项目关联是否存在\n     *\n     * @param int $teamId 团队 ID\n     * @param int $itemId 项目 ID\n     * @return bool 是否存在\n     */\n    public static function exists(int $teamId, int $itemId): bool\n    {\n        if ($teamId <= 0 || $itemId <= 0) {\n            return false;\n        }\n\n        $row = DB::table('team_item')\n            ->where('team_id', $teamId)\n            ->where('item_id', $itemId)\n            ->first();\n\n        return $row !== null;\n    }\n\n    /**\n     * 删除团队项目关联\n     *\n     * @param int $id 关联 ID\n     * @return bool 是否成功\n     */\n    public static function delete(int $id): bool\n    {\n        if ($id <= 0) {\n            return false;\n        }\n\n        try {\n            $affected = DB::table('team_item')\n                ->where('id', $id)\n                ->delete();\n            return $affected > 0;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 根据团队 ID 获取所有项目 ID 列表\n     *\n     * @param int $teamId 团队 ID\n     * @return array 项目 ID 数组\n     */\n    public static function getItemIdsByTeamId(int $teamId): array\n    {\n        if ($teamId <= 0) {\n            return [];\n        }\n\n        $rows = DB::table('team_item')\n            ->where('team_id', $teamId)\n            ->select('item_id')\n            ->get()\n            ->all();\n\n        $result = [];\n        foreach ($rows as $row) {\n            $result[] = (int) ($row->item_id ?? 0);\n        }\n\n        return $result;\n    }\n}\n"
  },
  {
    "path": "server/app/Model/TeamItemMember.php",
    "content": "<?php\n\nnamespace App\\Model;\n\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\nclass TeamItemMember\n{\n    /**\n     * 添加团队项目成员\n     *\n     * @param array $data 成员数据\n     * @return int|false 返回插入的ID，失败返回false\n     */\n    public static function add(array $data)\n    {\n        try {\n            $id = DB::table('team_item_member')->insertGetId($data);\n            return $id ?: false;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 根据项目 ID 和团队 ID 获取成员列表\n     *\n     * @param int $itemId 项目 ID\n     * @param int $teamId 团队 ID\n     * @return array 成员列表\n     */\n    public static function getListByItemIdAndTeamId(int $itemId, int $teamId): array\n    {\n        if ($itemId <= 0 || $teamId <= 0) {\n            return [];\n        }\n\n        $rows = DB::table('team_item_member')\n            ->where('item_id', $itemId)\n            ->where('team_id', $teamId)\n            ->get()\n            ->all();\n\n        $result = [];\n        foreach ($rows as $row) {\n            $data = (array) $row;\n            $data['addtime'] = date('Y-m-d H:i:s', (int) ($data['addtime'] ?? time()));\n            // member_group_id 需要返回字符串数字，兼容旧前端\n            $data['member_group_id'] = (string) ($data['member_group_id'] ?? '0');\n            $data['cat_name'] = '所有目录';\n\n            // 处理 cat_ids（多目录支持）\n            if (!empty($data['cat_ids'])) {\n                $str = (string) $data['cat_ids'];\n                $ids = [];\n                if (strpos($str, ',') !== false) {\n                    $ids = preg_split('/\\s*,\\s*/', trim($str));\n                } elseif (ctype_digit($str)) {\n                    $ids = [(int) $str];\n                }\n                $data['cat_ids'] = array_values(array_unique(array_map('intval', $ids)));\n            } elseif ((int) ($data['cat_id'] ?? 0) > 0) {\n                // 兼容：历史只有单目录时，预填为单元素数组\n                $data['cat_ids'] = [(int) $data['cat_id']];\n            } else {\n                $data['cat_ids'] = [];\n            }\n\n            // 展示名称：存在多目录时，简单展示为\"多个目录\"\n            if (!empty($data['cat_ids']) && count($data['cat_ids']) > 1) {\n                $data['cat_name'] = '多个目录';\n            } elseif ((int) ($data['cat_id'] ?? 0) > 0) {\n                $cat = DB::table('catalog')\n                    ->where('cat_id', $data['cat_id'])\n                    ->first();\n                if ($cat && !empty($cat->cat_name)) {\n                    $data['cat_name'] = $cat->cat_name;\n                }\n            }\n\n            // 获取用户名称\n            $memberUid = (int) ($data['member_uid'] ?? 0);\n            if ($memberUid > 0) {\n                $user = DB::table('user')\n                    ->where('uid', $memberUid)\n                    ->first();\n                if ($user) {\n                    $data['name'] = $user->name ?? '';\n                }\n            }\n\n            $result[] = $data;\n        }\n\n        return $result;\n    }\n\n    /**\n     * 根据 ID 查找团队项目成员\n     *\n     * @param int $id 成员 ID\n     * @return object|null 成员记录，不存在返回 null\n     */\n    public static function findById(int $id): ?object\n    {\n        if ($id <= 0) {\n            return null;\n        }\n\n        return DB::table('team_item_member')\n            ->where('id', $id)\n            ->first();\n    }\n\n    /**\n     * 更新团队项目成员\n     *\n     * @param int $id 成员 ID\n     * @param array $data 更新数据\n     * @return bool 是否成功\n     */\n    public static function update(int $id, array $data): bool\n    {\n        if ($id <= 0) {\n            return false;\n        }\n\n        try {\n            $affected = DB::table('team_item_member')\n                ->where('id', $id)\n                ->update($data);\n            return $affected >= 0;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 删除团队项目成员（根据项目 ID 和团队 ID）\n     *\n     * @param int $itemId 项目 ID\n     * @param int $teamId 团队 ID\n     * @return bool 是否成功\n     */\n    public static function deleteByItemIdAndTeamId(int $itemId, int $teamId): bool\n    {\n        if ($itemId <= 0 || $teamId <= 0) {\n            return false;\n        }\n\n        try {\n            $affected = DB::table('team_item_member')\n                ->where('item_id', $itemId)\n                ->where('team_id', $teamId)\n                ->delete();\n            return $affected >= 0;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 删除团队项目成员（根据成员用户 ID 和团队 ID）\n     *\n     * @param int $memberUid 成员用户 ID\n     * @param int $teamId 团队 ID\n     * @return bool 是否成功\n     */\n    public static function deleteByMemberUidAndTeamId(int $memberUid, int $teamId): bool\n    {\n        if ($memberUid <= 0 || $teamId <= 0) {\n            return false;\n        }\n\n        try {\n            $affected = DB::table('team_item_member')\n                ->where('member_uid', $memberUid)\n                ->where('team_id', $teamId)\n                ->delete();\n            return $affected >= 0;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "server/app/Model/TeamMember.php",
    "content": "<?php\n\nnamespace App\\Model;\n\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\nclass TeamMember\n{\n    /**\n     * 添加团队成员\n     *\n     * @param array $data 成员数据\n     * @return int|false 返回插入的ID，失败返回false\n     */\n    public static function add(array $data)\n    {\n        try {\n            $id = DB::table('team_member')->insertGetId($data);\n            return $id ?: false;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 根据团队 ID 获取成员列表（关联 user 表）\n     *\n     * @param int $teamId 团队 ID\n     * @return array 成员列表\n     */\n    public static function getListByTeamId(int $teamId): array\n    {\n        if ($teamId <= 0) {\n            return [];\n        }\n\n        $rows = DB::table('team_member')\n            ->leftJoin('user', 'user.uid', '=', 'team_member.member_uid')\n            ->where('team_member.team_id', $teamId)\n            ->select('team_member.*', 'user.name as name')\n            ->orderBy('team_member.addtime', 'desc')\n            ->get()\n            ->all();\n\n        $result = [];\n        foreach ($rows as $row) {\n            $data = (array) $row;\n            $data['addtime'] = date('Y-m-d H:i:s', (int) ($data['addtime'] ?? time()));\n            $result[] = $data;\n        }\n\n        return $result;\n    }\n\n    /**\n     * 根据 ID 查找团队成员\n     *\n     * @param int $id 成员 ID\n     * @return object|null 成员记录，不存在返回 null\n     */\n    public static function findById(int $id): ?object\n    {\n        if ($id <= 0) {\n            return null;\n        }\n\n        return DB::table('team_member')\n            ->where('id', $id)\n            ->first();\n    }\n\n    /**\n     * 检查团队成员是否存在\n     *\n     * @param int $teamId 团队 ID\n     * @param int $memberUid 成员用户 ID\n     * @return bool 是否存在\n     */\n    public static function exists(int $teamId, int $memberUid): bool\n    {\n        if ($teamId <= 0 || $memberUid <= 0) {\n            return false;\n        }\n\n        $row = DB::table('team_member')\n            ->where('team_id', $teamId)\n            ->where('member_uid', $memberUid)\n            ->first();\n\n        return $row !== null;\n    }\n\n    /**\n     * 根据团队 ID 获取所有成员用户 ID 列表\n     *\n     * @param int $teamId 团队 ID\n     * @return array 成员用户 ID 数组\n     */\n    public static function getMemberUidsByTeamId(int $teamId): array\n    {\n        if ($teamId <= 0) {\n            return [];\n        }\n\n        $rows = DB::table('team_member')\n            ->where('team_id', $teamId)\n            ->select('member_uid', 'member_username', 'team_member_group_id')\n            ->get()\n            ->all();\n\n        $result = [];\n        foreach ($rows as $row) {\n            $result[] = (array) $row;\n        }\n\n        return $result;\n    }\n\n    /**\n     * 删除团队成员\n     *\n     * @param int $id 成员 ID\n     * @return bool 是否成功\n     */\n    public static function delete(int $id): bool\n    {\n        if ($id <= 0) {\n            return false;\n        }\n\n        try {\n            $affected = DB::table('team_member')\n                ->where('id', $id)\n                ->delete();\n            return $affected > 0;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 根据团队 ID 和成员用户 ID 删除成员\n     *\n     * @param int $teamId 团队 ID\n     * @param int $memberUid 成员用户 ID\n     * @return bool 是否成功\n     */\n    public static function deleteByTeamIdAndUid(int $teamId, int $memberUid): bool\n    {\n        if ($teamId <= 0 || $memberUid <= 0) {\n            return false;\n        }\n\n        try {\n            $affected = DB::table('team_member')\n                ->where('team_id', $teamId)\n                ->where('member_uid', $memberUid)\n                ->delete();\n            return $affected > 0;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "server/app/Model/Template.php",
    "content": "<?php\n\nnamespace App\\Model;\n\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\nclass Template\n{\n    /**\n     * 添加模板\n     *\n     * @param array $data 模板数据\n     * @return int|false 返回插入的ID，失败返回false\n     */\n    public static function add(array $data)\n    {\n        try {\n            $id = DB::table('template')->insertGetId($data);\n            return $id ?: false;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 根据用户 ID 获取模板列表\n     *\n     * @param int $uid 用户 ID\n     * @return array 模板列表\n     */\n    public static function getListByUid(int $uid): array\n    {\n        if ($uid <= 0) {\n            return [];\n        }\n\n        $rows = DB::table('template')\n            ->where('uid', $uid)\n            ->orderBy('addtime', 'desc')\n            ->get()\n            ->all();\n\n        $result = [];\n        foreach ($rows as $row) {\n            $result[] = (array) $row;\n        }\n\n        return $result;\n    }\n\n    /**\n     * 根据 ID 查找模板\n     *\n     * @param int $id 模板 ID\n     * @return object|null 模板对象，不存在返回 null\n     */\n    public static function findById(int $id): ?object\n    {\n        if ($id <= 0) {\n            return null;\n        }\n\n        return DB::table('template')\n            ->where('id', $id)\n            ->first();\n    }\n\n    /**\n     * 删除模板\n     *\n     * @param int $id 模板 ID\n     * @return bool 是否成功\n     */\n    public static function delete(int $id): bool\n    {\n        if ($id <= 0) {\n            return false;\n        }\n\n        try {\n            $affected = DB::table('template')\n                ->where('id', $id)\n                ->delete();\n            return $affected > 0;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "server/app/Model/TemplateItem.php",
    "content": "<?php\n\nnamespace App\\Model;\n\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\nclass TemplateItem\n{\n    /**\n     * 根据模板 ID 获取项目列表\n     *\n     * @param int $templateId 模板 ID\n     * @return array 项目列表\n     */\n    public static function getListByTemplateId(int $templateId): array\n    {\n        if ($templateId <= 0) {\n            return [];\n        }\n\n        $rows = DB::table('template_item')\n            ->where('template_id', $templateId)\n            ->get()\n            ->all();\n\n        $result = [];\n        foreach ($rows as $row) {\n            $result[] = (array) $row;\n        }\n\n        return $result;\n    }\n\n    /**\n     * 根据项目 ID 获取模板列表（关联 template 表）\n     *\n     * @param int $itemId 项目 ID\n     * @return array 模板列表\n     */\n    public static function getListByItemId(int $itemId): array\n    {\n        if ($itemId <= 0) {\n            return [];\n        }\n\n        $rows = DB::table('template_item')\n            ->leftJoin('template', 'template.id', '=', 'template_item.template_id')\n            ->where('template_item.item_id', $itemId)\n            ->select('template.*', 'template_item.*')\n            ->get()\n            ->all();\n\n        $result = [];\n        foreach ($rows as $row) {\n            $result[] = (array) $row;\n        }\n\n        return $result;\n    }\n\n    /**\n     * 添加模板项目关联\n     *\n     * @param array $data 关联数据\n     * @return int|false 返回插入的ID，失败返回false\n     */\n    public static function add(array $data)\n    {\n        try {\n            $id = DB::table('template_item')->insertGetId($data);\n            return $id ?: false;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 删除模板项目关联（根据模板 ID）\n     *\n     * @param int $templateId 模板 ID\n     * @return bool 是否成功\n     */\n    public static function deleteByTemplateId(int $templateId): bool\n    {\n        if ($templateId <= 0) {\n            return false;\n        }\n\n        try {\n            $affected = DB::table('template_item')\n                ->where('template_id', $templateId)\n                ->delete();\n            return $affected >= 0;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 检查模板是否已关联到项目\n     *\n     * @param int $templateId 模板 ID\n     * @param int $itemId 项目 ID\n     * @return bool 是否已关联\n     */\n    public static function exists(int $templateId, int $itemId): bool\n    {\n        if ($templateId <= 0 || $itemId <= 0) {\n            return false;\n        }\n\n        $row = DB::table('template_item')\n            ->where('template_id', $templateId)\n            ->where('item_id', $itemId)\n            ->first();\n\n        return $row !== null;\n    }\n}\n"
  },
  {
    "path": "server/app/Model/UploadFile.php",
    "content": "<?php\n\nnamespace App\\Model;\n\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\nclass UploadFile\n{\n    /**\n     * 根据 sign 查找文件\n     *\n     * @param string $sign 文件签名\n     * @return object|null\n     */\n    public static function findBySign(string $sign): ?object\n    {\n        if (empty($sign)) {\n            return null;\n        }\n\n        return DB::table('upload_file')\n            ->where('sign', $sign)\n            ->first();\n    }\n\n    /**\n     * 根据 file_id 查找文件\n     *\n     * @param int $fileId 文件 ID\n     * @return object|null\n     */\n    public static function findById(int $fileId): ?object\n    {\n        if ($fileId <= 0) {\n            return null;\n        }\n\n        return DB::table('upload_file')\n            ->where('file_id', $fileId)\n            ->first();\n    }\n\n    /**\n     * 添加文件记录\n     *\n     * @param array $data 文件数据\n     * @return int 文件 ID，失败返回 0\n     */\n    public static function add(array $data): int\n    {\n        try {\n            $id = DB::table('upload_file')->insertGetId($data);\n            return (int) $id;\n        } catch (\\Throwable $e) {\n            return 0;\n        }\n    }\n\n    /**\n     * 更新文件记录\n     *\n     * @param int $fileId 文件 ID\n     * @param array $data 更新数据\n     * @return bool 是否成功\n     */\n    public static function update(int $fileId, array $data): bool\n    {\n        if ($fileId <= 0) {\n            return false;\n        }\n\n        try {\n            $affected = DB::table('upload_file')\n                ->where('file_id', $fileId)\n                ->update($data);\n            return $affected > 0;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 删除文件记录\n     *\n     * @param int $fileId 文件 ID\n     * @return bool 是否成功\n     */\n    public static function delete(int $fileId): bool\n    {\n        if ($fileId <= 0) {\n            return false;\n        }\n\n        try {\n            $deleted = DB::table('upload_file')\n                ->where('file_id', $fileId)\n                ->delete();\n            return $deleted > 0;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 获取用户的文件列表\n     *\n     * @param int $uid 用户 ID\n     * @param array $filters 筛选条件\n     * @param int $page 页码\n     * @param int $count 每页数量\n     * @return array 包含 list 和 total\n     */\n    public static function getMyList(int $uid, array $filters = [], int $page = 1, int $count = 20): array\n    {\n        if ($uid <= 0) {\n            return ['list' => [], 'total' => 0];\n        }\n\n        $query = DB::table('upload_file')\n            ->where('uid', $uid);\n\n        // 文件类型筛选\n        if (isset($filters['attachment_type'])) {\n            if ($filters['attachment_type'] == 1) {\n                $query->where('file_type', 'like', '%image%');\n            } elseif ($filters['attachment_type'] == 2) {\n                $query->where('file_type', 'not like', '%image%');\n            }\n        }\n\n        // 文件名搜索\n        if (!empty($filters['display_name'])) {\n            $likeDisplay = '%' . addcslashes($filters['display_name'], '%_\\\\') . '%';\n            $query->where('display_name', 'like', $likeDisplay);\n        }\n\n        // 获取总数\n        $total = (clone $query)->count();\n\n        // 获取列表\n        $list = $query\n            ->orderBy('addtime', 'desc')\n            ->offset(($page - 1) * $count)\n            ->limit($count)\n            ->get()\n            ->all();\n\n        $result = [];\n        foreach ($list as $row) {\n            $data = (array) $row;\n            $data['file_size_m'] = round($data['file_size'] / (1024 * 1024), 3);\n            $data['addtime'] = date('Y-m-d H:i:s', (int) ($data['addtime'] ?? time()));\n            $data['last_visit_time'] = date('Y-m-d H:i:s', (int) ($data['last_visit_time'] ?? time()));\n            $result[] = $data;\n        }\n\n        // 获取已使用空间\n        $used = DB::table('upload_file')\n            ->where('uid', $uid)\n            ->sum('file_size');\n\n        return [\n            'list'     => $result,\n            'total'    => (int) $total,\n            'used'     => (int) ($used ?? 0),\n            'used_m'   => round(($used ?? 0) / (1024 * 1024), 3),\n        ];\n    }\n\n    /**\n     * 获取全站文件列表（管理员用）\n     *\n     * @param array $filters 筛选条件\n     * @param int $page 页码\n     * @param int $count 每页数量\n     * @return array 包含 list 和 total\n     */\n    public static function getAllList(array $filters = [], int $page = 1, int $count = 20): array\n    {\n        $query = DB::table('upload_file');\n\n        // 文件类型筛选\n        if (isset($filters['attachment_type'])) {\n            if ($filters['attachment_type'] == 1) {\n                $query->where('file_type', 'like', '%image%');\n            } elseif ($filters['attachment_type'] == 2) {\n                $query->where('file_type', 'not like', '%image%');\n            }\n        }\n\n        // 文件名或 sign 搜索\n        if (!empty($filters['display_name'])) {\n            $likeDisplay = '%' . addcslashes($filters['display_name'], '%_\\\\') . '%';\n            $query->where(function ($q) use ($likeDisplay) {\n                $q->where('display_name', 'like', $likeDisplay)\n                    ->orWhere('sign', 'like', $likeDisplay);\n            });\n        }\n\n        // 用户名筛选\n        if (!empty($filters['username'])) {\n            $user = User::findByUsernameOrEmail($filters['username']);\n            if ($user) {\n                $query->where('uid', (int) $user->uid);\n            } else {\n                // 用户不存在，返回空结果\n                $query->where('uid', -99);\n            }\n        }\n\n        // 获取总数\n        $total = (clone $query)->count();\n\n        // 获取列表\n        $list = $query\n            ->orderBy('addtime', 'desc')\n            ->offset(($page - 1) * $count)\n            ->limit($count)\n            ->get()\n            ->all();\n\n        $result = [];\n        foreach ($list as $row) {\n            $data = (array) $row;\n\n            // 获取用户名\n            $username = '';\n            if ($data['uid']) {\n                $user = User::findById((int) $data['uid']);\n                if ($user) {\n                    $username = $user->username ?? '';\n                }\n            }\n\n            $data['username'] = $username;\n            $data['file_size_m'] = round($data['file_size'] / (1024 * 1024), 3);\n            $data['addtime'] = date('Y-m-d H:i:s', (int) ($data['addtime'] ?? time()));\n            $data['last_visit_time'] = date('Y-m-d H:i:s', (int) ($data['last_visit_time'] ?? time()));\n            $result[] = $data;\n        }\n\n        // 获取已使用空间\n        $usedQuery = DB::table('upload_file');\n        if (isset($filters['attachment_type'])) {\n            if ($filters['attachment_type'] == 1) {\n                $usedQuery->where('file_type', 'like', '%image%');\n            } elseif ($filters['attachment_type'] == 2) {\n                $usedQuery->where('file_type', 'not like', '%image%');\n            }\n        }\n        if (!empty($filters['username'])) {\n            $user = User::findByUsernameOrEmail($filters['username']);\n            if ($user) {\n                $usedQuery->where('uid', (int) $user->uid);\n            } else {\n                $usedQuery->where('uid', -99);\n            }\n        }\n        $used = $usedQuery->sum('file_size');\n\n        return [\n            'list'   => $result,\n            'total'  => (int) $total,\n            'used'   => (int) ($used ?? 0),\n            'used_m' => round(($used ?? 0) / (1024 * 1024), 3),\n        ];\n    }\n\n    /**\n     * 批量更新文件的 uid（转让附件）\n     *\n     * @param array $fileIds 文件 ID 数组\n     * @param int $targetUid 目标用户 ID\n     * @return int 更新的数量\n     */\n    public static function transferFiles(array $fileIds, int $targetUid): int\n    {\n        if (empty($fileIds) || $targetUid <= 0) {\n            return 0;\n        }\n\n        try {\n            $affected = DB::table('upload_file')\n                ->whereIn('file_id', $fileIds)\n                ->update(['uid' => $targetUid]);\n            return $affected;\n        } catch (\\Throwable $e) {\n            return 0;\n        }\n    }\n\n    /**\n     * 获取未使用的图片文件\n     *\n     * @param int $time 时间戳\n     * @param int $maxVisitTimes 最大访问次数\n     * @param int $limit 限制数量\n     * @return array 文件列表\n     */\n    public static function getUnusedImages(int $time, int $maxVisitTimes = 3, int $limit = 50): array\n    {\n        $rows = DB::table('upload_file')\n            ->where('visit_times', '<=', $maxVisitTimes)\n            ->where('file_type', 'like', '%image%')\n            ->where('last_visit_time', '<', $time)\n            ->where('addtime', '<', $time)\n            ->limit($limit)\n            ->get()\n            ->all();\n\n        $result = [];\n        foreach ($rows as $row) {\n            $result[] = (array) $row;\n        }\n\n        return $result;\n    }\n}\n"
  },
  {
    "path": "server/app/Model/User.php",
    "content": "<?php\n\nnamespace App\\Model;\n\nuse Illuminate\\Database\\Capsule\\Manager as DB;\nuse App\\Common\\Helper\\Security;\n\nclass User\n{\n    public static function findById(int $uid): ?object\n    {\n        if ($uid <= 0) {\n            return null;\n        }\n\n        return DB::table('user')\n            ->where('uid', $uid)\n            ->first();\n    }\n\n    public static function isExist(string $username): bool\n    {\n        $username = trim($username);\n        if ($username === '') {\n            return false;\n        }\n\n        $row = DB::table('user')\n            ->where('username', $username)\n            ->first();\n\n        return $row !== null;\n    }\n\n    public static function register(string $username, string $password): ?int\n    {\n        $username = trim($username);\n        if ($username === '' || $password === '') {\n            return null;\n        }\n\n        // 复用原有加密逻辑（算法一致，但通过新 Helper 实现）\n        $salt     = Security::generateSalt();\n        $hashed   = Security::hashPassword($password, $salt);\n        $now      = time();\n\n        $uid = DB::table('user')->insertGetId([\n            'username'  => $username,\n            'password'  => $hashed,\n            'salt'      => $salt,\n            'reg_time'  => $now,\n        ]);\n\n        return $uid ?: null;\n    }\n\n    public static function updatePwd(int $uid, string $password): bool\n    {\n        if ($uid <= 0 || $password === '') {\n            return false;\n        }\n\n        $row = self::findById($uid);\n        if (!$row) {\n            return false;\n        }\n\n        $salt    = $row->salt ?: Security::generateSalt();\n        $hashed  = Security::hashPassword($password, $salt);\n\n        $affected = DB::table('user')\n            ->where('uid', $uid)\n            ->update([\n                'salt'            => $salt,\n                'password'        => $hashed,\n                'last_login_time' => time(),\n            ]);\n\n        return $affected > 0;\n    }\n\n    public static function checkLogin(string $username, string $password): ?array\n    {\n        $username = trim($username);\n        if ($username === '' || $password === '') {\n            return null;\n        }\n\n        // 先按 username\n        $row = DB::table('user')\n            ->where('username', $username)\n            ->first();\n\n        // 再尝试邮箱或手机号\n        if (!$row) {\n            $row = DB::table('user')\n                ->where(function ($q) use ($username) {\n                    $q->where(function ($q2) use ($username) {\n                        $q2->where('email', $username)\n                            ->where('email_verify', '=', 1);\n                    })->orWhere('mobile', $username);\n                })\n                ->first();\n        }\n\n        if (!$row) {\n            return null;\n        }\n\n        $salt    = (string) ($row->salt ?? '');\n        $hashed  = Security::hashPassword($password, $salt);\n\n        if ($hashed !== $row->password) {\n            return null;\n        }\n\n        return (array) $row;\n    }\n\n    public static function setLastTime(int $uid): void\n    {\n        if ($uid <= 0) {\n            return;\n        }\n\n        DB::table('user')\n            ->where('uid', $uid)\n            ->update(['last_login_time' => time()]);\n    }\n\n    /**\n     * 校验指定 uid 的登录密码是否正确。\n     */\n    public static function checkPassword(int $uid, string $password): bool\n    {\n        if ($uid <= 0 || $password === '') {\n            return false;\n        }\n\n        $row = self::findById($uid);\n        if (!$row) {\n            return false;\n        }\n\n        $salt   = (string) ($row->salt ?? '');\n        $hashed = Security::hashPassword($password, $salt);\n\n        return $hashed === $row->password;\n    }\n\n    /**\n     * 用户是否已经绑定了邮箱并且邮箱验证通过\n     *\n     * @param int $uid 用户 ID\n     * @return bool\n     */\n    public static function isEmail(int $uid): bool\n    {\n        if ($uid <= 0) {\n            return false;\n        }\n\n        $user = self::findById($uid);\n        if (!$user) {\n            return false;\n        }\n\n        $email = (string) ($user->email ?? '');\n        $emailVerify = (int) ($user->email_verify ?? 0);\n\n        return $email !== '' && $emailVerify > 0;\n    }\n\n    /**\n     * 用户是否已经完成支付实名认证\n     *\n     * @param int $uid 用户 ID\n     * @return bool\n     */\n    public static function isPaymentVerify(int $uid): bool\n    {\n        if ($uid <= 0) {\n            return false;\n        }\n\n        $user = self::findById($uid);\n        if (!$user) {\n            return false;\n        }\n\n        // 检查支付实名认证字段（根据实际表结构调整）\n        $paymentVerify = (int) ($user->payment_verify ?? 0);\n        return $paymentVerify > 0;\n    }\n\n    /**\n     * 获取用户的协作成员数（包括团队成员和项目成员，去重）\n     *\n     * @param int $uid 用户 ID\n     * @return int 协作成员数\n     */\n    public static function getMemberCount(int $uid): int\n    {\n        if ($uid <= 0) {\n            return 0;\n        }\n\n        $uidArray = [];\n\n        // 获取项目成员（该用户创建的项目中的成员）\n        $rows = DB::table('item_member')\n            ->leftJoin('item', 'item.item_id', '=', 'item_member.item_id')\n            ->select('item_member.uid as uid')\n            ->where('item.uid', $uid)\n            ->get();\n\n        foreach ($rows as $row) {\n            $uidArray[] = (int) $row->uid;\n        }\n\n        // 获取团队成员（该用户创建的团队中的成员）\n        $rows = DB::table('team_member')\n            ->leftJoin('team', 'team.id', '=', 'team_member.team_id')\n            ->select('team_member.member_uid as uid')\n            ->where('team.uid', $uid)\n            ->get();\n\n        foreach ($rows as $row) {\n            $uidArray[] = (int) $row->uid;\n        }\n\n        // 去重\n        $uidArray = array_unique($uidArray);\n\n        return count($uidArray);\n    }\n\n    /**\n     * 根据用户名或邮箱查找用户\n     *\n     * @param string $username 用户名或邮箱\n     * @return object|null\n     */\n    public static function findByUsernameOrEmail(string $username): ?object\n    {\n        $username = trim($username);\n        if ($username === '') {\n            return null;\n        }\n\n        // 先按用户名查找\n        $row = DB::table('user')\n            ->where('username', $username)\n            ->first();\n\n        // 再尝试邮箱（需要已验证）\n        if (!$row) {\n            $row = DB::table('user')\n                ->where(function ($q) use ($username) {\n                    $q->where(function ($q2) use ($username) {\n                        $q2->where('email', $username)\n                            ->where('email_verify', '=', 1);\n                    });\n                })\n                ->first();\n        }\n\n        return $row;\n    }\n\n    /**\n     * 根据用户名查找用户（仅用户名，不包含邮箱）\n     *\n     * @param string $username 用户名\n     * @return object|null\n     */\n    public static function findByUsername(string $username): ?object\n    {\n        $username = trim($username);\n        if ($username === '') {\n            return null;\n        }\n\n        return DB::table('user')\n            ->where('username', $username)\n            ->first();\n    }\n\n    /**\n     * 更新用户姓名\n     *\n     * @param int $uid 用户 ID\n     * @param string $name 姓名\n     * @return bool 是否成功\n     */\n    public static function updateName(int $uid, string $name): bool\n    {\n        if ($uid <= 0) {\n            return false;\n        }\n\n        $affected = DB::table('user')\n            ->where('uid', $uid)\n            ->update(['name' => $name]);\n\n        return $affected > 0;\n    }\n\n    /**\n     * 用户是否已经绑定了手机号\n     *\n     * @param int $uid 用户 ID\n     * @return bool\n     */\n    public static function isMobile(int $uid): bool\n    {\n        if ($uid <= 0) {\n            return false;\n        }\n\n        $user = self::findById($uid);\n        if (!$user) {\n            return false;\n        }\n\n        $mobile = (string) ($user->mobile ?? '');\n        return $mobile !== '';\n    }\n\n    /**\n     * 获取不活跃用户\n     *\n     * @param int $days 天数\n     * @param int $limit 限制数量\n     * @return array 用户列表\n     */\n    public static function getInactiveUsers(int $days, int $limit = 5000): array\n    {\n        if ($days <= 0) {\n            return [];\n        }\n\n        $time = time() - ($days * 24 * 60 * 60);\n        $regTime = time() - (100 * 24 * 60 * 60); // 注册时间在100天前\n\n        $rows = DB::table('user')\n            ->where('last_login_time', '!=', -1)\n            ->where('groupid', 2)\n            ->where('last_login_time', '<', $time)\n            ->where('reg_time', '<', $regTime)\n            ->whereNotIn('username', ['showdoc', 'xing7th@gmail.com'])\n            ->select('uid')\n            ->limit($limit)\n            ->get()\n            ->all();\n\n        $result = [];\n        foreach ($rows as $row) {\n            $result[] = (array) $row;\n        }\n\n        return $result;\n    }\n\n    /**\n     * 标记用户为不活跃\n     *\n     * @param array $uidArray 用户 ID 数组\n     * @return bool 是否成功\n     */\n    public static function markAsInactive(array $uidArray): bool\n    {\n        if (empty($uidArray)) {\n            return false;\n        }\n\n        try {\n            $affected = DB::table('user')\n                ->whereIn('uid', $uidArray)\n                ->update(['last_login_time' => -1]);\n            return $affected >= 0;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 删除用户（物理删除）\n     *\n     * @param int $uid 用户 ID\n     * @return bool 是否成功\n     */\n    public static function deleteUser(int $uid): bool\n    {\n        if ($uid <= 0) {\n            return false;\n        }\n\n        try {\n            // 删除用户相关的所有数据\n            DB::table('team_member')->where('member_uid', $uid)->delete();\n            DB::table('team_item_member')->where('member_uid', $uid)->delete();\n            DB::table('item_member')->where('uid', $uid)->delete();\n            DB::table('user_token')->where('uid', $uid)->update(['token' => '']);\n            // 注意：不删除用户创建的项目和页面，这些数据保留\n\n            // 删除用户\n            $affected = DB::table('user')->where('uid', $uid)->delete();\n            return $affected > 0;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 绑定微信\n     *\n     * @param int $uid 用户 ID\n     * @param string $openid 微信 openid\n     * @return bool 是否成功\n     */\n    public static function bindingWechat(int $uid, string $openid): bool\n    {\n        // 开源版不支持微信绑定功能\n        // 注意：如果需要微信功能，请使用主版（showdoc.cc）\n        return false;\n    }\n\n    /**\n     * 更新用户的支付实名认证状态\n     *\n     * @param int $uid 用户ID\n     * @param int $paymentVerify 支付实名认证状态（1=已认证，0=未认证）\n     * @return bool 是否成功\n     */\n    public static function updatePaymentVerify(int $uid, int $paymentVerify = 1): bool\n    {\n        if ($uid <= 0) {\n            return false;\n        }\n\n        $affected = DB::table('user')\n            ->where('uid', $uid)\n            ->update(['payment_verify' => $paymentVerify]);\n\n        return $affected > 0;\n    }\n\n    /**\n     * 检测是否还可以发送邮件（即没有受到限制）\n     * 如果三分钟内有发过邮件，则返回 false\n     *\n     * @param string $email 邮箱地址\n     * @return bool 是否可以发送邮件\n     */\n    public static function checkEmailLimit(string $email): bool\n    {\n        $email = trim($email);\n        if ($email === '') {\n            return false;\n        }\n\n        $now = time();\n        $ret = DB::table('email_token')\n            ->where('email', $email)\n            ->orderBy('addtime', 'desc')\n            ->first();\n\n        if ($ret && isset($ret->addtime)) {\n            // 如果三分钟内有发过\n            if ($ret->addtime > ($now - 3 * 60)) {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    /**\n     * 发送邮箱验证邮件\n     *\n     * @param int $uid 用户ID\n     * @return bool 是否成功\n     */\n    public static function sendVerifyEmail(int $uid): bool\n    {\n        if ($uid <= 0) {\n            return false;\n        }\n\n        $user = self::findById($uid);\n        if (!$user) {\n            return false;\n        }\n\n        $name = (string) ($user->username ?? '');\n        $email = (string) ($user->email ?? '');\n        if ($email === '') {\n            return false;\n        }\n\n        // 生成随机 token\n        $token = self::generateRandomString(32) . rand(1000, 9999);\n\n        // 计算平台运行天数\n        $days = ceil((time() - strtotime('2015-12-1 00:00:00')) / (60 * 60 * 24));\n        $docs = DB::table('page')->count();\n        $users = DB::table('user')->count();\n\n        // 开源版不支持邮件发送功能\n        // 注意：如果需要邮件功能，请使用主版（showdoc.cc）\n        return false;\n    }\n\n    /**\n     * 发送重置密码的邮件\n     *\n     * @param int $uid 用户ID\n     * @return bool 是否成功\n     */\n    public static function sendResetPasswordEmail(int $uid): bool\n    {\n        if ($uid <= 0) {\n            return false;\n        }\n\n        $user = self::findById($uid);\n        if (!$user) {\n            return false;\n        }\n\n        $name = (string) ($user->username ?? '');\n        $email = (string) ($user->email ?? '');\n        if ($email === '') {\n            $email = $name; // 如果没有邮箱，使用用户名\n        }\n\n        // 生成随机 token\n        $token = self::generateRandomString(32) . rand(1000, 9999);\n\n        // 开源版不支持邮件发送功能\n        // 注意：如果需要邮件功能，请使用主版（showdoc.cc）\n        return false;\n    }\n\n    /**\n     * 生成随机字符串\n     *\n     * @param int $len 长度\n     * @return string 随机字符串\n     */\n    private static function generateRandomString(int $len = 32): string\n    {\n        // 对于 php7 以上版本，可利用 random_bytes 产生随机\n        if (version_compare(PHP_VERSION, '7.0', '>')) {\n            $rand = bin2hex(random_bytes(16));\n        } else {\n            $rand = md5(uniqid(mt_rand(), true));\n        }\n        return substr($rand, 0, $len);\n    }\n\n    /**\n     * 发送短信验证码（开源版不支持）\n     *\n     * @param string $mobile 手机号\n     * @param string $code 验证码\n     * @return bool 是否发送成功（开源版始终返回 false）\n     */\n    public static function sendSms(string $mobile, string $code): bool\n    {\n        // 开源版不支持短信发送功能\n        // 注意：如果需要短信功能，请使用主版（showdoc.cc）\n        return false;\n    }\n\n    /**\n     * LDAP 登录验证\n     *\n     * @param string $username 用户名\n     * @param string $password 密码\n     * @return array|null 用户信息，失败返回 null\n     */\n    public static function checkLdapLogin(string $username, string $password): ?array\n    {\n        set_time_limit(60);\n        ini_set('memory_limit', '500M');\n\n        $ldapOpen = \\App\\Model\\Options::get('ldap_open');\n        $ldapForm = \\App\\Model\\Options::get('ldap_form');\n        $ldapForm = htmlspecialchars_decode($ldapForm ?: '');\n        $ldapForm = json_decode($ldapForm, true);\n\n        if (!$ldapOpen || !$ldapForm) {\n            return null;\n        }\n\n        if (!isset($ldapForm['user_field']) || !$ldapForm['user_field']) {\n            $ldapForm['user_field'] = 'cn';\n        }\n\n        $ldapConn = ldap_connect($ldapForm['host'], $ldapForm['port']);\n        if (!$ldapConn) {\n            return null;\n        }\n\n        ldap_set_option($ldapConn, LDAP_OPT_PROTOCOL_VERSION, $ldapForm['version'] ?? 3);\n        $rs = ldap_bind($ldapConn, $ldapForm['bind_dn'], $ldapForm['bind_password']);\n        if (!$rs) {\n            return null;\n        }\n\n        $ldapForm['search_filter'] = $ldapForm['search_filter'] ?: '(cn=*)';\n\n        // 支持占位符 %(user)s，用于精确匹配登录用户\n        $hasPlaceholder = strpos($ldapForm['search_filter'], '%(user)s') !== false;\n        // ldap_escape 在 PHP 7.2+ 可用，兼容旧版本\n        if (function_exists('ldap_escape')) {\n            $searchFilter = str_replace('%(user)s', ldap_escape($username, '', LDAP_ESCAPE_FILTER), $ldapForm['search_filter']);\n        } else {\n            // PHP < 7.2 的兼容处理：简单转义特殊字符\n            $escaped = str_replace(['\\\\', '*', '(', ')', \"\\x00\"], ['\\\\5c', '\\\\2a', '\\\\28', '\\\\29', '\\\\00'], $username);\n            $searchFilter = str_replace('%(user)s', $escaped, $ldapForm['search_filter']);\n        }\n\n        $result = ldap_search($ldapConn, $ldapForm['base_dn'], $searchFilter);\n        if (!$result) {\n            return null;\n        }\n\n        $data = ldap_get_entries($ldapConn, $result);\n\n        if ($data[\"count\"] == 0) {\n            return null;\n        }\n\n        for ($i = 0; $i < $data[\"count\"]; $i++) {\n            $userFieldLower = strtolower($ldapForm['user_field']);\n            $ldapUser = null;\n\n            // 因为 LDAP 属性可能大小写不同，遍历所有属性找到匹配的\n            foreach ($data[$i] as $key => $value) {\n                if (strtolower($key) === $userFieldLower && isset($value['count']) && $value['count'] > 0) {\n                    $ldapUser = $value[0];\n                    break;\n                }\n            }\n\n            if (!$ldapUser) {\n                continue;\n            }\n\n            $dn = $data[$i][\"dn\"];\n\n            // 如果使用了占位符，说明已经精确匹配，直接使用第一个结果\n            // 否则需要检查用户名是否匹配（不区分大小写）\n            if ($hasPlaceholder || strcasecmp($ldapUser, $username) == 0) {\n                // 获取用户姓名\n                $ldapName = '';\n                $nameField = strtolower($ldapForm['name_field'] ?? '');\n\n                if ($nameField) {\n                    foreach ($data[$i] as $key => $value) {\n                        if (strtolower($key) === $nameField && isset($value['count']) && $value['count'] > 0) {\n                            $ldapName = $value[0];\n                            break;\n                        }\n                    }\n                }\n\n                // 使用 LDAP 返回的实际用户名进行数据库操作\n                $dbUsername = $ldapUser;\n\n                // 如果该用户不在数据库里，则帮助其注册\n                $userInfo = self::findByUsername($dbUsername);\n                if (!$userInfo) {\n                    $uid = self::register($dbUsername, $dbUsername . \\App\\Common\\Helper\\FileHelper::getRandStr());\n                    if ($uid && $ldapName) {\n                        self::updateName($uid, $ldapName);\n                    }\n                    $userInfo = self::findById($uid);\n                } elseif ($ldapName) {\n                    // 如果用户已存在且有姓名字段，则更新用户姓名\n                    self::updateName((int) $userInfo->uid, $ldapName);\n                    $userInfo = self::findById((int) $userInfo->uid);\n                }\n\n                if (!$userInfo) {\n                    continue;\n                }\n\n                $rs2 = ldap_bind($ldapConn, $dn, $password);\n                if ($rs2) {\n                    // LDAP 认证成功，更新本地密码\n                    self::updatePwd((int) $userInfo->uid, $password);\n\n                    // 直接返回用户信息，避免再次调用 checkLogin 造成的验证问题\n                    $userInfo = self::findById((int) $userInfo->uid);\n                    if (!$userInfo) {\n                        continue;\n                    }\n\n                    $userArray = (array) $userInfo;\n                    unset($userArray['password'], $userArray['salt']);\n\n                    return $userArray;\n                }\n            }\n        }\n\n        return null;\n    }\n}\n"
  },
  {
    "path": "server/app/Model/UserAiToken.php",
    "content": "<?php\n\nnamespace App\\Model;\n\nuse Illuminate\\Database\\Capsule\\Manager as DB;\nuse App\\Common\\Helper\\IpHelper;\n\n/**\n * 用户级 AI Token Model\n * \n * 用于 MCP 协议集成，支持 AI 编辑器访问用户的 ShowDoc 项目\n */\nclass UserAiToken\n{\n  /**\n   * 表名\n   */\n  const TABLE = 'user_ai_token';\n\n  /**\n   * Token 前缀\n   */\n  const TOKEN_PREFIX = 'ai_';\n\n  /**\n   * Token 随机部分长度（字节）\n   * 43 字节 = 86 个十六进制字符，总长度 89 字符（3 前缀 + 86 随机）\n   */\n  const TOKEN_RANDOM_BYTES = 43;\n\n  /**\n   * 创建新的 AI Token\n   *\n   * @param int $uid 用户 ID\n   * @param array $options 选项\n   * @return string|null Token 字符串，失败返回 null\n   */\n  public static function createToken(int $uid, array $options = []): ?string\n  {\n    if ($uid <= 0) {\n      return null;\n    }\n\n    // 生成 Token\n    $token = self::generateToken();\n\n    $data = [\n      'uid' => $uid,\n      'token' => $token,\n      'name' => $options['name'] ?? null,\n      'permission' => $options['permission'] ?? 'write',\n      'scope' => $options['scope'] ?? 'all',\n      'allowed_items' => isset($options['allowed_items'])\n        ? json_encode($options['allowed_items'])\n        : null,\n      'can_create_item' => $options['can_create_item'] ?? 1,\n      'can_delete_item' => $options['can_delete_item'] ?? 0,\n      'auto_add_created_item' => $options['auto_add_created_item'] ?? 1,\n      'expires_at' => $options['expires_at'] ?? null,\n      'created_at' => date('Y-m-d H:i:s'),\n      'is_active' => 1,\n    ];\n\n    try {\n      $ok = DB::table(self::TABLE)->insert($data);\n      return $ok ? $token : null;\n    } catch (\\Throwable $e) {\n      return null;\n    }\n  }\n\n  /**\n   * 生成 Token 字符串\n   *\n   * @return string\n   */\n  public static function generateToken(): string\n  {\n    return self::TOKEN_PREFIX . bin2hex(random_bytes(self::TOKEN_RANDOM_BYTES));\n  }\n\n  /**\n   * 根据 Token 获取信息\n   *\n   * @param string $token Token 字符串\n   * @return array|null Token 信息，不存在返回 null\n   */\n  public static function getToken(string $token): ?array\n  {\n    $token = trim($token);\n    if ($token === '') {\n      return null;\n    }\n\n    $row = DB::table(self::TABLE)\n      ->where('token', $token)\n      ->where('is_active', 1)\n      ->first();\n\n    if (!$row) {\n      return null;\n    }\n\n    // 检查是否过期\n    $expiresAt = $row->expires_at ?? null;\n    if ($expiresAt && strtotime($expiresAt) < time()) {\n      return null;\n    }\n\n    return (array) $row;\n  }\n\n  /**\n   * 获取用户的所有 Token 列表\n   *\n   * @param int $uid 用户 ID\n   * @return array Token 列表\n   */\n  public static function getTokensByUid(int $uid): array\n  {\n    if ($uid <= 0) {\n      return [];\n    }\n\n    $rows = DB::table(self::TABLE)\n      ->where('uid', $uid)\n      ->orderBy('created_at', 'desc')\n      ->get()\n      ->all();\n\n    $result = [];\n    foreach ($rows as $row) {\n      $data = (array) $row;\n      // 生成 Token 预览（遮蔽部分）\n      $data['token_preview'] = self::maskToken($data['token']);\n      // 保留完整 token，前端复制功能需要\n      $result[] = $data;\n    }\n\n    return $result;\n  }\n\n  /**\n   * 获取 Token 详情（包含完整 Token）\n   *\n   * @param int $id Token ID\n   * @param int $uid 用户 ID（用于权限验证）\n   * @return array|null\n   */\n  public static function getTokenById(int $id, int $uid): ?array\n  {\n    if ($id <= 0 || $uid <= 0) {\n      return null;\n    }\n\n    $row = DB::table(self::TABLE)\n      ->where('id', $id)\n      ->where('uid', $uid)\n      ->first();\n\n    return $row ? (array) $row : null;\n  }\n\n  /**\n   * 更新 Token 信息\n   *\n   * @param int $id Token ID\n   * @param int $uid 用户 ID（用于权限验证）\n   * @param array $data 更新数据\n   * @return bool\n   */\n  public static function updateToken(int $id, int $uid, array $data): bool\n  {\n    if ($id <= 0 || $uid <= 0) {\n      return false;\n    }\n\n    // 允许更新的字段\n    $allowedFields = [\n      'name',\n      'permission',\n      'scope',\n      'allowed_items',\n      'can_create_item',\n      'can_delete_item',\n      'auto_add_created_item',\n      'expires_at',\n      'is_active',\n    ];\n\n    $updateData = [];\n    foreach ($allowedFields as $field) {\n      if (isset($data[$field])) {\n        if ($field === 'allowed_items' && is_array($data[$field])) {\n          $updateData[$field] = json_encode($data[$field]);\n        } else {\n          $updateData[$field] = $data[$field];\n        }\n      }\n    }\n\n    if (empty($updateData)) {\n      return false;\n    }\n\n    try {\n      $affected = DB::table(self::TABLE)\n        ->where('id', $id)\n        ->where('uid', $uid)\n        ->update($updateData);\n\n      return $affected > 0;\n    } catch (\\Throwable $e) {\n      return false;\n    }\n  }\n\n  /**\n   * 更新 Token 的 allowed_items 字段\n   *\n   * @param int $id Token ID\n   * @param array $allowedItems 允许的项目 ID 列表\n   * @return bool\n   */\n  public static function updateAllowedItems(int $id, array $allowedItems): bool\n  {\n    try {\n      DB::table(self::TABLE)\n        ->where('id', $id)\n        ->update(['allowed_items' => json_encode($allowedItems)]);\n      return true;\n    } catch (\\Throwable $e) {\n      return false;\n    }\n  }\n\n  /**\n   * 重置 Token（生成新的 Token 字符串）\n   *\n   * @param int $id Token ID\n   * @param int $uid 用户 ID\n   * @return string|null 新的 Token 字符串，失败返回 null\n   */\n  public static function resetToken(int $id, int $uid): ?string\n  {\n    if ($id <= 0 || $uid <= 0) {\n      return null;\n    }\n\n    $newToken = self::generateToken();\n\n    try {\n      $affected = DB::table(self::TABLE)\n        ->where('id', $id)\n        ->where('uid', $uid)\n        ->update(['token' => $newToken]);\n\n      return $affected > 0 ? $newToken : null;\n    } catch (\\Throwable $e) {\n      return null;\n    }\n  }\n\n  /**\n   * 撤销 Token（软删除）\n   *\n   * @param int $id Token ID\n   * @param int $uid 用户 ID\n   * @return bool\n   */\n  public static function revokeToken(int $id, int $uid): bool\n  {\n    if ($id <= 0 || $uid <= 0) {\n      return false;\n    }\n\n    try {\n      $affected = DB::table(self::TABLE)\n        ->where('id', $id)\n        ->where('uid', $uid)\n        ->update(['is_active' => 0]);\n\n      return $affected > 0;\n    } catch (\\Throwable $e) {\n      return false;\n    }\n  }\n\n  /**\n   * 删除 Token（硬删除）\n   *\n   * @param int $id Token ID\n   * @param int $uid 用户 ID\n   * @return bool\n   */\n  public static function deleteToken(int $id, int $uid): bool\n  {\n    if ($id <= 0 || $uid <= 0) {\n      return false;\n    }\n\n    try {\n      $affected = DB::table(self::TABLE)\n        ->where('id', $id)\n        ->where('uid', $uid)\n        ->delete();\n\n      return $affected > 0;\n    } catch (\\Throwable $e) {\n      return false;\n    }\n  }\n\n  /**\n   * 更新最后使用时间\n   *\n   * @param string $token Token 字符串\n   * @return void\n   */\n  public static function touchLastUsed(string $token): void\n  {\n    $token = trim($token);\n    if ($token === '') {\n      return;\n    }\n\n    DB::table(self::TABLE)\n      ->where('token', $token)\n      ->update(['last_used_at' => date('Y-m-d H:i:s')]);\n  }\n\n  /**\n   * 遮蔽 Token（只显示前缀和后几位）\n   *\n   * @param string $token Token 字符串\n   * @return string\n   */\n  public static function maskToken(string $token): string\n  {\n    if (strlen($token) <= 10) {\n      return $token;\n    }\n\n    $prefix = substr($token, 0, 5);\n    $suffix = substr($token, -6);\n\n    return $prefix . '***' . $suffix;\n  }\n\n  /**\n   * 验证 Token 格式\n   *\n   * @param string $token Token 字符串\n   * @return bool\n   */\n  public static function isValidTokenFormat(string $token): bool\n  {\n    if (empty($token)) {\n      return false;\n    }\n\n    // 检查前缀\n    if (strpos($token, self::TOKEN_PREFIX) !== 0) {\n      return false;\n    }\n\n    // 检查长度（前缀3字符 + 随机部分86字符 = 89字符）\n    if (strlen($token) !== 89) {\n      return false;\n    }\n\n    // 检查随机部分是否为有效的十六进制\n    $randomPart = substr($token, strlen(self::TOKEN_PREFIX));\n    return ctype_xdigit($randomPart);\n  }\n\n  /**\n   * 获取用户的 Token 数量\n   *\n   * @param int $uid 用户 ID\n   * @return int\n   */\n  public static function getTokenCount(int $uid): int\n  {\n    if ($uid <= 0) {\n      return 0;\n    }\n\n    return DB::table(self::TABLE)\n      ->where('uid', $uid)\n      ->where('is_active', 1)\n      ->count();\n  }\n\n  /**\n   * 清理过期 Token\n   *\n   * @param int $days 过期天数（默认 365 天）\n   * @return int 删除的数量\n   */\n  public static function cleanExpiredTokens(int $days = 365): int\n  {\n    $expireDate = date('Y-m-d H:i:s', time() - $days * 86400);\n\n    try {\n      return DB::table(self::TABLE)\n        ->where('expires_at', '<', $expireDate)\n        ->where('is_active', 0)\n        ->delete();\n    } catch (\\Throwable $e) {\n      return 0;\n    }\n  }\n\n  /**\n   * 频率限制配置\n   */\n  const RATE_LIMIT_WINDOW = 600; // 10 分钟（秒）\n  const RATE_LIMIT_MAX_REQUESTS = 10000; // 最大请求数\n\n  /**\n   * 检查并增加请求计数（频率限制）\n   *\n   * @param string $token Token 字符串\n   * @return array ['allowed' => bool, 'remaining' => int, 'reset_at' => int]\n   */\n  public static function checkRateLimit(string $token): array\n  {\n    $token = trim($token);\n    if ($token === '') {\n      return ['allowed' => false, 'remaining' => 0, 'reset_at' => 0];\n    }\n\n    // 使用 Token 的哈希作为缓存键（避免文件名过长）\n    $cacheKey = 'mcp_rate_' . md5($token);\n    $cacheFile = self::getRateLimitCachePath($cacheKey);\n    $now = time();\n\n    // 读取当前计数\n    $data = self::readRateLimitCache($cacheFile);\n\n    // 如果窗口已过期，重置计数\n    if ($data && isset($data['reset_at']) && $data['reset_at'] <= $now) {\n      $data = null;\n    }\n\n    if (!$data) {\n      // 新窗口\n      $data = [\n        'count' => 0,\n        'reset_at' => $now + self::RATE_LIMIT_WINDOW,\n      ];\n    }\n\n    // 检查是否超过限制\n    if ($data['count'] >= self::RATE_LIMIT_MAX_REQUESTS) {\n      return [\n        'allowed' => false,\n        'remaining' => 0,\n        'reset_at' => $data['reset_at'],\n      ];\n    }\n\n    // 增加计数\n    $data['count']++;\n    self::writeRateLimitCache($cacheFile, $data);\n\n    return [\n      'allowed' => true,\n      'remaining' => self::RATE_LIMIT_MAX_REQUESTS - $data['count'],\n      'reset_at' => $data['reset_at'],\n    ];\n  }\n\n  /**\n   * 获取频率限制缓存目录\n   *\n   * @return string\n   */\n  private static function getRateLimitCacheDir(): string\n  {\n    // 兼容 RUNTIME_PATH 未定义的情况\n    $runtimePath = defined('RUNTIME_PATH') ? RUNTIME_PATH : dirname(__DIR__, 2) . '/app/Runtime/';\n    $dir = $runtimePath . 'mcp_rate_limit';\n    if (!is_dir($dir)) {\n      @mkdir($dir, 0755, true);\n    }\n    return $dir;\n  }\n\n  /**\n   * 获取频率限制缓存文件路径\n   *\n   * @param string $key 缓存键\n   * @return string\n   */\n  private static function getRateLimitCachePath(string $key): string\n  {\n    return self::getRateLimitCacheDir() . DIRECTORY_SEPARATOR . $key . '.json';\n  }\n\n  /**\n   * 读取频率限制缓存\n   *\n   * @param string $file 文件路径\n   * @return array|null\n   */\n  private static function readRateLimitCache(string $file): ?array\n  {\n    if (!file_exists($file)) {\n      return null;\n    }\n\n    $content = @file_get_contents($file);\n    if ($content === false) {\n      return null;\n    }\n\n    $data = json_decode($content, true);\n    return is_array($data) ? $data : null;\n  }\n\n  /**\n   * 写入频率限制缓存\n   *\n   * @param string $file 文件路径\n   * @param array $data 数据\n   * @return bool\n   */\n  private static function writeRateLimitCache(string $file, array $data): bool\n  {\n    $content = json_encode($data);\n    return @file_put_contents($file, $content) !== false;\n  }\n}\n"
  },
  {
    "path": "server/app/Model/UserSetting.php",
    "content": "<?php\n\nnamespace App\\Model;\n\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\n/**\n * 用户设置模型\n */\nclass UserSetting\n{\n    /**\n     * 获取用户设置\n     *\n     * @param int $uid 用户ID\n     * @param string $key 设置键名\n     * @return string|null 设置值\n     */\n    public static function getSetting(int $uid, string $key): ?string\n    {\n        if ($uid <= 0 || empty($key)) {\n            return null;\n        }\n\n        $row = DB::table('user_setting')\n            ->where('uid', $uid)\n            ->where('key_name', $key)\n            ->first();\n\n        return $row ? ($row->key_value ?? null) : null;\n    }\n\n    /**\n     * 保存用户设置\n     *\n     * @param int $uid 用户ID\n     * @param string $key 设置键名\n     * @param string $value 设置值\n     * @return bool 是否成功\n     */\n    public static function saveSetting(int $uid, string $key, string $value): bool\n    {\n        if ($uid <= 0 || empty($key)) {\n            return false;\n        }\n\n        try {\n            $existing = DB::table('user_setting')\n                ->where('uid', $uid)\n                ->where('key_name', $key)\n                ->first();\n\n            if ($existing) {\n                $affected = DB::table('user_setting')\n                    ->where('id', $existing->id)\n                    ->update(['key_value' => $value]);\n                return $affected > 0;\n            } else {\n                $id = DB::table('user_setting')->insertGetId([\n                    'uid'      => $uid,\n                    'key_name' => $key,\n                    'key_value' => $value,\n                    'addtime'  => date('Y-m-d H:i:s'),\n                ]);\n                return $id > 0;\n            }\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 获取用户的推送地址\n     *\n     * @param int $uid 用户ID\n     * @return string|null 推送地址\n     */\n    public static function getPushUrl(int $uid): ?string\n    {\n        return self::getSetting($uid, 'push_url');\n    }\n\n    /**\n     * 保存用户的推送地址\n     *\n     * @param int $uid 用户ID\n     * @param string $url 推送地址\n     * @return bool 是否成功\n     */\n    public static function savePushUrl(int $uid, string $url): bool\n    {\n        return self::saveSetting($uid, 'push_url', $url);\n    }\n}\n\n"
  },
  {
    "path": "server/app/Model/UserToken.php",
    "content": "<?php\n\nnamespace App\\Model;\n\nuse Illuminate\\Database\\Capsule\\Manager as DB;\nuse App\\Common\\Helper\\IpHelper;\n\nclass UserToken\n{\n    public static function createToken(int $uid, int $ttlSeconds = 0): ?string\n    {\n        if ($uid <= 0) {\n            return null;\n        }\n\n        $now   = time();\n        $ttl   = $ttlSeconds > 0 ? $ttlSeconds : (60 * 60 * 24 * 90);\n        $expire = $now + $ttl;\n\n        $token = md5(md5($uid . $expire . $now . rand() . 'showdoc') . 'rdgtrd12367hghf54t')\n            . md5($uid . $expire . $now . rand() . 'showdoc');\n\n        // 旧版开源版的 user_token 表没有 user_agent 字段，这里只写旧表中已有的字段\n        $data = [\n            'uid'          => $uid,\n            'token'        => $token,\n            'token_expire' => $expire,\n            'ip'           => IpHelper::getClientIp(),\n            'addtime'      => $now,\n        ];\n\n        $ok = DB::table('user_token')->insert($data);\n        if (!$ok) {\n            return null;\n        }\n\n        // 清理过期记录（与旧实现保持一致）\n        $fiveYearsAgo = $now - 5 * 365 * 24 * 60 * 60;\n\n        DB::table('user_token')\n            ->where('token_expire', '<', $now)\n            ->update(['token' => '']);\n\n        DB::table('user_token')\n            ->where('token_expire', '<', $fiveYearsAgo)\n            ->delete();\n\n        return $token;\n    }\n\n    public static function getToken(string $token): ?array\n    {\n        $token = trim($token);\n        if ($token === '') {\n            return null;\n        }\n\n        $row = DB::table('user_token')\n            ->where('token', $token)\n            ->first();\n\n        return $row ? (array) $row : null;\n    }\n\n    public static function touch(string $token): void\n    {\n        $token = trim($token);\n        if ($token === '') {\n            return;\n        }\n\n        DB::table('user_token')\n            ->where('token', $token)\n            ->update(['last_check_time' => time()]);\n    }\n\n    /**\n     * 设置用户所有 token 的过期时间（用于拉黑用户）\n     *\n     * @param int $uid 用户 ID\n     * @param int $expire 过期时间戳（0 表示立即过期）\n     * @return bool 是否成功\n     */\n    public static function setTokenExpire(int $uid, int $expire = 0): bool\n    {\n        if ($uid <= 0) {\n            return false;\n        }\n\n        try {\n            $affected = DB::table('user_token')\n                ->where('uid', $uid)\n                ->update(['token_expire' => $expire]);\n            return $affected >= 0;\n        } catch (\\Throwable $e) {\n            return false;\n        }\n    }\n\n    /**\n     * 获取用户的登录日志列表\n     *\n     * @param int $uid 用户 ID\n     * @param int $limit 限制数量\n     * @return array 登录日志列表\n     */\n    public static function getLoginLog(int $uid, int $limit = 100): array\n    {\n        if ($uid <= 0) {\n            return [];\n        }\n\n        $rows = DB::table('user_token')\n            ->where('uid', $uid)\n            ->orderBy('last_check_time', 'desc')\n            ->orderBy('addtime', 'desc')\n            ->limit($limit)\n            ->get()\n            ->all();\n\n        $result = [];\n        foreach ($rows as $row) {\n            $data = (array) $row;\n            $data['addtime'] = date('Y-m-d H:i:s', (int) ($data['addtime'] ?? time()));\n            $data['last_check_time'] = date('Y-m-d H:i:s', (int) ($data['last_check_time'] ?? time()));\n            $data['token'] = ''; // 不返回 token\n            $result[] = $data;\n        }\n\n        return $result;\n    }\n}\n"
  },
  {
    "path": "server/app/Model/VerifyCode.php",
    "content": "<?php\n\nnamespace App\\Model;\n\nuse App\\Common\\Cache\\CacheManager;\n\n/**\n * 验证码模型（用于登录失败次数限制等）\n */\nclass VerifyCode\n{\n    /**\n     * 次数加1\n     *\n     * @param string $key 缓存键\n     * @return bool 是否成功\n     */\n    public static function insTimes(string $key): bool\n    {\n        $cache = CacheManager::getInstance();\n        $cacheTimes = (int) ($cache->get($key) ?? 0);\n        $ret = $cache->set($key, $cacheTimes + 1, 24 * 60 * 60); // 24小时过期\n        return $ret;\n    }\n\n    /**\n     * 检查次数是否超过限制\n     *\n     * @param string $key 缓存键\n     * @param int $maxTimes 最大次数，默认5次\n     * @return bool true表示未超过限制，false表示超过限制\n     */\n    public static function checkTimes(string $key, int $maxTimes = 5): bool\n    {\n        $cache = CacheManager::getInstance();\n        $cacheTimes = (int) ($cache->get($key) ?? 0);\n        \n        if ($cacheTimes >= $maxTimes) {\n            return false; // 超过限制\n        }\n        \n        return true; // 未超过限制\n    }\n}\n\n"
  },
  {
    "path": "server/app/Model/VersionUpdate.php",
    "content": "<?php\n\nnamespace App\\Model;\n\nuse Illuminate\\Database\\Capsule\\Manager as DB;\n\nclass VersionUpdate\n{\n    /**\n     * 根据应用类型获取版本信息\n     *\n     * @param string $appType 应用类型（opensource/app/pc/runapi_pc）\n     * @return array|null 版本信息\n     */\n    public static function findByAppType(string $appType): ?array\n    {\n        if (empty($appType)) {\n            return null;\n        }\n\n        $row = DB::table('version_update')\n            ->where('app_type', $appType)\n            ->where('status', 1)\n            ->first();\n\n        return $row ? (array) $row : null;\n    }\n}\n"
  },
  {
    "path": "server/app/Runtime/Cache/index.html",
    "content": " "
  },
  {
    "path": "server/app/Runtime/Logs/index.html",
    "content": " "
  },
  {
    "path": "server/app/Runtime/index.html",
    "content": " "
  },
  {
    "path": "server/app/Static/export-html/app.js",
    "content": "/**\n * ShowDoc 离线HTML导出 - 前端交互逻辑\n */\n\n;(function () {\n  'use strict'\n\n  // 工具函数\n  const utils = {\n    debounce: function (func, wait) {\n      let timeout\n      return function (...args) {\n        clearTimeout(timeout)\n        timeout = setTimeout(() => func.apply(this, args), wait)\n      }\n    },\n\n    escapeHtml: function (text) {\n      const div = document.createElement('div')\n      div.textContent = text\n      return div.innerHTML\n    },\n\n    getQueryParam: function (name) {\n      const urlParams = new URLSearchParams(window.location.search)\n      return urlParams.get(name)\n    },\n  }\n\n  // 判断是否在 pages 目录下\n  const isPageContext = function () {\n    try {\n      return window.location.pathname.indexOf('/pages/') !== -1\n    } catch (e) {\n      return false\n    }\n  }\n\n  // 目录树渲染\n  const CatalogTree = {\n    init: function () {\n      if (!window.PROJECT_DATA) {\n        console.error('PROJECT_DATA not found')\n        return\n      }\n\n      this.render()\n      this.highlightCurrentPage()\n      this.restoreExpandedState()\n    },\n\n    render: function () {\n      const container = document.getElementById('catalogTree')\n      if (!container) return\n\n      const catalogs = window.PROJECT_DATA.catalogs || []\n      const pages = window.PROJECT_DATA.pages || []\n\n      // 构建目录树结构\n      const tree = this.buildTree(catalogs, pages)\n\n      // 渲染目录树\n      container.innerHTML = this.renderTree(tree)\n    },\n\n    buildTree: function (catalogs, pages) {\n      // 创建目录映射\n      const catalogMap = {}\n      catalogs.forEach((cat) => {\n        catalogMap[cat.cat_id] = {\n          ...cat,\n          children: [],\n          pages: [],\n        }\n      })\n\n      // 构建树结构\n      const root = []\n      catalogs.forEach((cat) => {\n        if (cat.parent_cat_id === 0) {\n          root.push(catalogMap[cat.cat_id])\n        } else {\n          const parent = catalogMap[cat.parent_cat_id]\n          if (parent) {\n            parent.children.push(catalogMap[cat.cat_id])\n          } else {\n            root.push(catalogMap[cat.cat_id])\n          }\n        }\n      })\n\n      // 添加页面到对应目录\n      pages.forEach((page) => {\n        if (page.cat_id === 0) {\n          // 根目录下的页面\n          root.push({ type: 'page', ...page })\n        } else {\n          const catalog = catalogMap[page.cat_id]\n          if (catalog) {\n            catalog.pages.push(page)\n          } else {\n            root.push({ type: 'page', ...page })\n          }\n        }\n      })\n\n      // 排序\n      root.sort((a, b) => {\n        if (a.type === 'page' && b.type !== 'page') return 1\n        if (a.type !== 'page' && b.type === 'page') return -1\n        return (a.s_number || 0) - (b.s_number || 0)\n      })\n\n      return root\n    },\n\n    renderTree: function (items, level = 0) {\n      let html = ''\n\n      items.forEach((item) => {\n        if (item.type === 'page') {\n          // 渲染页面链接\n          // 在首页使用 pages/page-xx.html；在页面内使用同目录相对路径 page-xx.html\n          const href = isPageContext()\n            ? `page-${item.page_id}.html`\n            : `pages/page-${item.page_id}.html`\n          html += `<a href=\"${href}\" class=\"page-link\" data-page-id=\"${\n            item.page_id\n          }\">${utils.escapeHtml(item.page_title)}</a>`\n        } else {\n          // 渲染目录\n          const catalogId = `cat-${item.cat_id}`\n          const hasChildren =\n            (item.children && item.children.length > 0) ||\n            (item.pages && item.pages.length > 0)\n\n          html += `<div class=\"catalog-item\">`\n          html += `<div class=\"catalog-link\" data-catalog-id=\"${item.cat_id}\">`\n\n          // 即使空目录也显示图标，但使用不同的样式标识\n          if (hasChildren) {\n            html += `<span class=\"catalog-icon collapsed\" data-target=\"${catalogId}\"></span>`\n          } else {\n            // 空目录显示一个横线图标，表示没有内容\n            html += `<span class=\"catalog-icon empty\" style=\"opacity: 0.3; cursor: default;\" title=\"空目录\"></span>`\n          }\n\n          html += `<span>${utils.escapeHtml(item.cat_name)}</span>`\n          html += `</div>`\n\n          // 即使空目录也创建catalog-children容器，但内容为空，这样点击时至少有个反馈\n          html += `<div class=\"catalog-children\" id=\"${catalogId}\" style=\"${\n            hasChildren ? '' : 'display: none;'\n          }\">`\n\n          if (hasChildren) {\n            // 渲染子目录\n            if (item.children && item.children.length > 0) {\n              item.children.sort(\n                (a, b) => (a.s_number || 0) - (b.s_number || 0)\n              )\n              html += this.renderTree(item.children, level + 1)\n            }\n\n            // 渲染页面\n            if (item.pages && item.pages.length > 0) {\n              item.pages.sort((a, b) => (a.s_number || 0) - (b.s_number || 0))\n              item.pages.forEach((page) => {\n                // 在首页使用 pages/page-xx.html；在页面内使用同目录相对路径 page-xx.html\n                const href = isPageContext()\n                  ? `page-${page.page_id}.html`\n                  : `pages/page-${page.page_id}.html`\n                html += `<a href=\"${href}\" class=\"page-link\" data-page-id=\"${\n                  page.page_id\n                }\">${utils.escapeHtml(page.page_title)}</a>`\n              })\n            }\n          } else {\n            // 空目录显示提示信息（可选，如果不需要可以删除这行）\n            // html += `<div style=\"padding: 5px 10px; color: #999; font-size: 12px;\">（空目录）</div>`\n          }\n\n          html += `</div>`\n          html += `</div>`\n        }\n      })\n\n      return html\n    },\n\n    highlightCurrentPage: function () {\n      // 使用字符串，避免大整数精度丢失问题\n      const currentPageId = String(window.CURRENT_PAGE_ID || '0')\n\n      // 移除所有active类\n      document\n        .querySelectorAll('.page-link.active, .catalog-link.active')\n        .forEach((el) => {\n          el.classList.remove('active')\n        })\n\n      if (currentPageId !== '0') {\n        // 高亮当前页面（data-page-id 属性是字符串）\n        const pageLink = document.querySelector(\n          `.page-link[data-page-id=\"${currentPageId}\"]`\n        )\n        if (pageLink) {\n          pageLink.classList.add('active')\n\n          // 展开父目录\n          let parent = pageLink.parentElement\n          while (parent) {\n            if (parent.classList.contains('catalog-children')) {\n              parent.classList.add('expanded')\n              const icon =\n                parent.previousElementSibling?.querySelector('.catalog-icon')\n              if (icon) {\n                icon.classList.remove('collapsed')\n                icon.classList.add('expanded')\n              }\n            }\n            parent = parent.parentElement\n          }\n        }\n      }\n    },\n\n    restoreExpandedState: function () {\n      const saved = localStorage.getItem('showdoc_catalog_expanded')\n      if (!saved) return\n\n      try {\n        const expandedIds = JSON.parse(saved)\n        expandedIds.forEach((catId) => {\n          const children = document.getElementById(`cat-${catId}`)\n          if (children) {\n            children.classList.add('expanded')\n            const icon =\n              children.previousElementSibling?.querySelector('.catalog-icon')\n            if (icon) {\n              icon.classList.remove('collapsed')\n              icon.classList.add('expanded')\n            }\n          }\n        })\n      } catch (e) {\n        console.error('Failed to restore expanded state', e)\n      }\n    },\n\n    saveExpandedState: function () {\n      const expanded = []\n      document.querySelectorAll('.catalog-children.expanded').forEach((el) => {\n        const catId = el.id.replace('cat-', '')\n        if (catId) {\n          expanded.push(catId)\n        }\n      })\n      localStorage.setItem('showdoc_catalog_expanded', JSON.stringify(expanded))\n    },\n  }\n\n  // 搜索功能\n  const Search = {\n    init: function () {\n      const searchInput = document.getElementById('searchInput')\n      const searchResults = document.getElementById('searchResults')\n\n      if (!searchInput || !searchResults) return\n\n      // 防抖搜索\n      const debouncedSearch = utils.debounce((query) => {\n        this.performSearch(query)\n      }, 300)\n\n      searchInput.addEventListener('input', (e) => {\n        const query = e.target.value.trim()\n        if (query.length > 0) {\n          debouncedSearch(query)\n        } else {\n          searchResults.classList.remove('show')\n        }\n      })\n\n      // 点击外部关闭搜索结果\n      document.addEventListener('click', (e) => {\n        if (\n          !searchInput.contains(e.target) &&\n          !searchResults.contains(e.target)\n        ) {\n          searchResults.classList.remove('show')\n        }\n      })\n\n      // 键盘快捷键\n      document.addEventListener('keydown', (e) => {\n        if ((e.ctrlKey || e.metaKey) && e.key === 'k') {\n          e.preventDefault()\n          searchInput.focus()\n        }\n        if (e.key === 'Escape') {\n          searchResults.classList.remove('show')\n          searchInput.blur()\n        }\n      })\n    },\n\n    performSearch: function (query) {\n      if (!window.SEARCH_INDEX) {\n        console.error('SEARCH_INDEX not found')\n        return\n      }\n\n      const results = []\n      const lowerQuery = query.toLowerCase()\n\n      window.SEARCH_INDEX.forEach((item) => {\n        const title = item.page_title || ''\n        const content = item.content_preview || ''\n\n        const titleMatch = title.toLowerCase().indexOf(lowerQuery) !== -1\n        const contentMatch = content.toLowerCase().indexOf(lowerQuery) !== -1\n\n        if (titleMatch || contentMatch) {\n          let score = 0\n          if (titleMatch) score += 10\n          if (contentMatch) score += 1\n\n          results.push({\n            ...item,\n            score: score,\n          })\n        }\n      })\n\n      // 按分数排序\n      results.sort((a, b) => b.score - a.score)\n\n      this.displayResults(results.slice(0, 10), query)\n    },\n\n    displayResults: function (results, query) {\n      const searchResults = document.getElementById('searchResults')\n      if (!searchResults) return\n\n      if (results.length === 0) {\n        searchResults.innerHTML =\n          '<div class=\"search-result-item\">未找到匹配结果</div>'\n        searchResults.classList.add('show')\n        return\n      }\n\n      let html = ''\n      results.forEach((result) => {\n        // 在首页使用 pages/page-xx.html；在页面内使用同目录相对路径 page-xx.html\n        const href = isPageContext()\n          ? `page-${result.page_id}.html`\n          : `pages/page-${result.page_id}.html`\n        const title = this.highlightText(result.page_title, query)\n        const preview = this.highlightText(result.content_preview, query)\n\n        html += `\n          <div class=\"search-result-item\" onclick=\"window.location.href='${href}'\">\n            <div class=\"search-result-title\">${title}</div>\n            <div class=\"search-result-preview\">${preview}</div>\n          </div>\n        `\n      })\n\n      searchResults.innerHTML = html\n      searchResults.classList.add('show')\n    },\n\n    highlightText: function (text, query) {\n      if (!query) return utils.escapeHtml(text)\n\n      const regex = new RegExp(`(${query})`, 'gi')\n      return utils.escapeHtml(text).replace(regex, '<mark>$1</mark>')\n    },\n  }\n\n  // 页面导航\n  const PageNav = {\n    init: function () {\n      // 使用字符串比较，避免大整数精度丢失问题\n      const currentPageId = String(window.CURRENT_PAGE_ID || '0')\n      if (currentPageId === '0') return\n\n      if (!window.PROJECT_DATA) return\n\n      const pages = window.PROJECT_DATA.pages || []\n      if (pages.length === 0) return\n\n      // 按s_number排序\n      const sortedPages = [...pages].sort((a, b) => {\n        if (a.cat_id !== b.cat_id) {\n          return a.cat_id - b.cat_id\n        }\n        return (a.s_number || 0) - (b.s_number || 0)\n      })\n\n      // 使用字符串比较，避免大整数精度丢失\n      const currentIndex = sortedPages.findIndex(\n        (p) => String(p.page_id) === currentPageId\n      )\n      if (currentIndex === -1) return\n\n      const prevPage = currentIndex > 0 ? sortedPages[currentIndex - 1] : null\n      const nextPage =\n        currentIndex < sortedPages.length - 1\n          ? sortedPages[currentIndex + 1]\n          : null\n\n      this.render(prevPage, nextPage)\n    },\n\n    render: function (prevPage, nextPage) {\n      const container = document.getElementById('pageNav')\n      if (!container) return\n\n      let html = '<div>'\n\n      if (prevPage) {\n        // 在页面文件中，使用同目录的相对路径\n        const href = `page-${prevPage.page_id}.html`\n        html += `<a href=\"${href}\" class=\"page-nav-link\">← 上一页: ${utils.escapeHtml(\n          prevPage.page_title\n        )}</a>`\n      } else {\n        html += '<span class=\"page-nav-link disabled\">← 上一页</span>'\n      }\n\n      html += '</div><div>'\n\n      if (nextPage) {\n        // 在页面文件中，使用同目录的相对路径\n        const href = `page-${nextPage.page_id}.html`\n        html += `<a href=\"${href}\" class=\"page-nav-link\">下一页: ${utils.escapeHtml(\n          nextPage.page_title\n        )} →</a>`\n      } else {\n        html += '<span class=\"page-nav-link disabled\">下一页 →</span>'\n      }\n\n      html += '</div>'\n\n      container.innerHTML = html\n    },\n  }\n\n  // 响应式菜单\n  const Responsive = {\n    init: function () {\n      const menuToggle = document.getElementById('menuToggle')\n      const sidebar = document.getElementById('sidebar')\n\n      if (menuToggle && sidebar) {\n        menuToggle.addEventListener('click', () => {\n          sidebar.classList.toggle('open')\n        })\n      }\n\n      // 点击侧边栏外部关闭\n      document.addEventListener('click', (e) => {\n        if (window.innerWidth <= 768) {\n          if (sidebar && sidebar.classList.contains('open')) {\n            if (!sidebar.contains(e.target) && !menuToggle.contains(e.target)) {\n              sidebar.classList.remove('open')\n            }\n          }\n        }\n      })\n    },\n  }\n\n  // 目录树点击事件\n  const bindCatalogEvents = function () {\n    document.addEventListener('click', (e) => {\n      // 点击箭头图标\n      const icon = e.target.closest('.catalog-icon')\n      if (icon && icon.dataset.target) {\n        e.preventDefault()\n        e.stopPropagation()\n\n        const targetId = icon.dataset.target\n        const children = document.getElementById(targetId)\n\n        if (children) {\n          children.classList.toggle('expanded')\n          icon.classList.toggle('collapsed')\n          icon.classList.toggle('expanded')\n\n          CatalogTree.saveExpandedState()\n        }\n        return\n      }\n\n      // 点击目录整行（名称也可触发展开/折叠）\n      const link = e.target.closest('.catalog-link')\n      if (link && link.dataset.catalogId) {\n        e.preventDefault()\n        e.stopPropagation()\n\n        const targetId = `cat-${link.dataset.catalogId}`\n        const children = document.getElementById(targetId)\n        const iconInLink = link.querySelector('.catalog-icon')\n\n        if (children) {\n          // 检查是否是空目录（没有子元素）\n          const isEmpty = children.children.length === 0\n\n          if (isEmpty) {\n            // 空目录点击时不执行展开/折叠，但可以给一个视觉反馈\n            // 可以添加一个短暂的样式变化提示这是空目录\n            link.style.opacity = '0.6'\n            setTimeout(() => {\n              link.style.opacity = '1'\n            }, 200)\n          } else {\n            // 有内容的目录正常展开/折叠\n            children.classList.toggle('expanded')\n            if (iconInLink && !iconInLink.classList.contains('empty')) {\n              iconInLink.classList.toggle('collapsed')\n              iconInLink.classList.toggle('expanded')\n            }\n            CatalogTree.saveExpandedState()\n          }\n        }\n      }\n    })\n  }\n\n  // 处理表格样式（复刻Editormd.vue的dealWithContent方法）\n  const TableStyle = {\n    init: function () {\n      // 当表格列数过长时将自动出现滚动条\n      const tables = document.querySelectorAll('.markdown-body table')\n      tables.forEach(function (table) {\n        // 如果表格还没有被包装，则包装它\n        if (\n          table.parentElement.tagName !== 'DIV' ||\n          !table.parentElement.style.overflowX\n        ) {\n          const wrapper = document.createElement('div')\n          wrapper.style.width = '100%'\n          wrapper.style.overflowX = 'auto'\n          table.parentNode.insertBefore(wrapper, table)\n          wrapper.appendChild(table)\n        }\n      })\n\n      // 对表格进行一些改造（复刻Editormd.vue的逻辑）\n      const tableRows = document.querySelectorAll(\n        '.markdown-body table tbody tr'\n      )\n      tableRows.forEach(function (tr) {\n        const tds = tr.querySelectorAll('td')\n        if (tds.length >= 2) {\n          const td1 = tds[0] ? tds[0].textContent.trim() : ''\n          const td2 = tds[1] ? tds[1].textContent.trim() : ''\n          const td3 = tds[2] ? tds[2].textContent.trim() : ''\n\n          // 检查是否是object或array[object]类型\n          if (\n            td1 === 'object' ||\n            td1 === 'array[object]' ||\n            td2 === 'object' ||\n            td2 === 'array[object]' ||\n            td3 === 'object' ||\n            td3 === 'array[object]'\n          ) {\n            tr.classList.add('object-row')\n          }\n\n          // 设置表格hover\n          tr.addEventListener('mouseenter', function () {\n            tr.style.backgroundColor = '#F8F8F8'\n          })\n          tr.addEventListener('mouseleave', function () {\n            if (tr.classList.contains('object-row')) {\n              tr.style.backgroundColor = '#F8F8F8'\n            } else {\n              tr.style.backgroundColor = ''\n            }\n          })\n        }\n      })\n    },\n  }\n\n  // 初始化\n  document.addEventListener('DOMContentLoaded', function () {\n    CatalogTree.init()\n    Search.init()\n    PageNav.init()\n    Responsive.init()\n    bindCatalogEvents()\n    TableStyle.init()\n  })\n})()\n"
  },
  {
    "path": "server/app/Static/export-html/common.css",
    "content": "/* ShowDoc 离线HTML导出 - 通用样式 */\n\n* {\n  margin: 0;\n  padding: 0;\n  box-sizing: border-box;\n}\n\nbody {\n  font-family: 'Microsoft Yahei', 微软雅黑, Tahoma, Arial, Helvetica, STHeiti, sans-serif;\n  font-size: 13px;\n  line-height: 1.75;\n  color: #343a40;\n  background-color: #f9f9f9;\n}\n\n/* 头部样式 */\n.header {\n  position: fixed;\n  top: 0;\n  left: 0;\n  right: 0;\n  height: 50px;\n  background-color: #ffffff;\n  border-bottom: 1px solid rgba(0, 0, 0, 0.1);\n  z-index: 1000;\n  box-shadow: 0 1px 2px rgba(0,0,0,0.03);\n}\n\n.header-content {\n  display: flex;\n  align-items: center;\n  height: 100%;\n  padding: 0 20px;\n  max-width: 100%;\n}\n\n.project-name {\n  font-size: 18px;\n  font-weight: 600;\n  margin: 0;\n  margin-right: 20px;\n  color: #343a40;\n  white-space: nowrap;\n  overflow: hidden;\n  text-overflow: ellipsis;\n}\n\n.search-box {\n  position: relative;\n  flex: 1;\n  max-width: 400px;\n  margin-right: 20px;\n}\n\n.search-box input {\n  width: 100%;\n  padding: 6px 12px;\n  border: 1px solid rgba(0, 0, 0, 0.1);\n  border-radius: 4px;\n  font-size: 13px;\n  outline: none;\n  background-color: #ffffff;\n  transition: border-color 0.2s;\n}\n\n.search-box input::placeholder {\n  color: #9b9b9b;\n}\n\n.search-box input:focus {\n  border-color: #007bff;\n}\n\n.search-results {\n  position: absolute;\n  top: 100%;\n  left: 0;\n  right: 0;\n  background: #fff;\n  border: 1px solid rgba(0, 0, 0, 0.1);\n  border-top: none;\n  border-radius: 0 0 4px 4px;\n  max-height: 400px;\n  overflow-y: auto;\n  display: none;\n  z-index: 1001;\n  box-shadow: 0 2px 4px rgba(0,0,0,0.1);\n}\n\n.search-results.show {\n  display: block;\n}\n\n.search-result-item {\n  padding: 10px 14px;\n  border-bottom: 1px solid rgba(0, 0, 0, 0.05);\n  cursor: pointer;\n  transition: background-color 0.15s;\n}\n\n.search-result-item:hover {\n  background-color: #f9f9f9;\n}\n\n.search-result-item:last-child {\n  border-bottom: none;\n}\n\n.search-result-title {\n  font-weight: 600;\n  color: #007bff;\n  margin-bottom: 4px;\n  font-size: 13px;\n}\n\n.search-result-preview {\n  font-size: 12px;\n  color: #9b9b9b;\n  line-height: 1.5;\n}\n\n.search-result-item mark {\n  background-color: #fff4c2;\n  color: #343a40;\n  padding: 2px 0;\n}\n\n.menu-toggle {\n  display: none;\n  background: none;\n  border: none;\n  font-size: 24px;\n  cursor: pointer;\n  padding: 5px 10px;\n  color: #343a40;\n}\n\n/* 容器布局 */\n.container {\n  display: flex;\n  margin-top: 50px;\n  min-height: calc(100vh - 50px);\n}\n\n/* 侧边栏 */\n.sidebar {\n  width: 260px;\n  background-color: #f9f9f9;\n  border-right: 1px solid rgba(0, 0, 0, 0.1);\n  overflow-y: auto;\n  position: fixed;\n  left: 0;\n  top: 50px;\n  bottom: 0;\n  padding: 10px 0;\n}\n\n.catalog-tree {\n  padding: 0 8px;\n}\n\n.catalog-item {\n  margin-bottom: 2px;\n}\n\n.catalog-link {\n  display: flex;\n  align-items: center;\n  padding: 6px 10px;\n  color: #343a40;\n  text-decoration: none;\n  border-radius: 4px;\n  transition: background-color 0.15s;\n  font-size: 13px;\n  cursor: pointer;\n}\n\n.catalog-link:hover {\n  background-color: #f0f0f0;\n  color: #007bff;\n}\n\n.catalog-link.active {\n  background-color: #f0f0f0;\n  color: #007bff;\n  border-left: 3px solid #007bff;\n}\n\n.catalog-icon {\n  margin-right: 8px;\n  font-size: 12px;\n  width: 16px;\n  min-width: 16px;\n  text-align: center;\n  cursor: pointer;\n  user-select: none;\n  color: #9b9b9b;\n}\n\n.catalog-icon.expanded::before {\n  content: '▼';\n}\n\n.catalog-icon.collapsed::before {\n  content: '▶';\n}\n\n.catalog-icon.empty::before {\n  content: '─';\n  opacity: 0.3;\n  cursor: default;\n}\n\n.catalog-children {\n  margin-left: 20px;\n  display: none;\n}\n\n.catalog-children.expanded {\n  display: block;\n}\n\n.page-link {\n  display: block;\n  padding: 6px 10px;\n  color: #343a40;\n  text-decoration: none;\n  border-radius: 4px;\n  transition: background-color 0.15s;\n  font-size: 13px;\n  margin-left: 22px;\n}\n\n.page-link:hover {\n  background-color: #f0f0f0;\n  color: #007bff;\n}\n\n.page-link.active {\n  background-color: #f0f0f0;\n  color: #007bff;\n  border-left: 3px solid #007bff;\n}\n\n/* 主内容区 */\n.main-content {\n  flex: 1;\n  margin-left: 260px;\n  padding: 20px;\n  max-width: 1200px;\n}\n\n.page-content {\n  background: #ffffff;\n  padding: 20px;\n}\n\n.page-title {\n  font-size: 24px;\n  font-weight: 600;\n  margin-bottom: 16px;\n  padding-bottom: 10px;\n  border-bottom: 1px solid rgba(0, 0, 0, 0.1);\n  color: #343a40;\n}\n\n.project-description {\n  font-size: 13px;\n  color: #9b9b9b;\n  margin-bottom: 20px;\n  line-height: 1.75;\n}\n\n.project-overview {\n  margin-top: 20px;\n  padding: 16px;\n  background-color: #f9f9f9;\n  border-radius: 4px;\n  border-left: 4px solid #007bff;\n}\n\n.project-overview p {\n  margin-bottom: 10px;\n  color: #343a40;\n  line-height: 1.75;\n}\n\n.project-overview p:last-child {\n  margin-bottom: 0;\n}\n\n/* Markdown 样式微调，接近在线版 */\n.markdown-body {\n  color: #343a40;\n  line-height: 1.75;\n  word-wrap: break-word;\n  font-size: 14px;\n}\n\n.markdown-body h1,\n.markdown-body h2,\n.markdown-body h3,\n.markdown-body h4,\n.markdown-body h5,\n.markdown-body h6 {\n  margin-top: 24px;\n  margin-bottom: 1.5em;\n  font-weight: 600;\n  line-height: 1.75;\n  color: #343a40;\n}\n\n.markdown-body h1 {\n  font-size: 1.8em;\n  border-bottom: 1px solid rgba(0, 0, 0, 0.1);\n  padding-bottom: 0.3em;\n}\n\n.markdown-body h2 {\n  font-size: 1.5em;\n  border-bottom: 1px solid rgba(0, 0, 0, 0.1);\n  padding-bottom: 0.3em;\n}\n\n.markdown-body h3 {\n  font-size: 1.25em;\n}\n\n.markdown-body h4 {\n  font-size: 1.1em;\n}\n\n.markdown-body h5 {\n  font-size: 0.875em;\n}\n\n.markdown-body h6 {\n  font-size: 0.85em;\n  color: #9b9b9b;\n}\n\n.markdown-body p,\n.markdown-body ul,\n.markdown-body ol,\n.markdown-body blockquote,\n.markdown-body table,\n.markdown-body pre {\n  margin-bottom: 1.5em;\n}\n\n.markdown-body li {\n  margin-bottom: 4px;\n}\n\n.markdown-body blockquote {\n  padding: 0 1em;\n  color: #9b9b9b;\n  border-left: 4px solid rgba(0, 0, 0, 0.1);\n  background-color: #f9f9f9;\n  font-style: normal;\n}\n\n.markdown-body code {\n  padding: 0.2em 0.4em;\n  background-color: #f9f9f9;\n  border-radius: 3px;\n  font-size: 0.9em;\n  color: #409eff;\n  font-family: Consolas, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace;\n}\n\n.markdown-body pre {\n  position: relative;\n  padding: 1em;\n  overflow: auto;\n  font-size: 12px;\n  line-height: 1.6;\n  background-color: #384548;\n  color: #d1d2d2;\n  border-radius: 4px;\n  margin-bottom: 1.5em;\n}\n\n.markdown-body pre code {\n  display: inline;\n  max-width: auto;\n  padding: 0;\n  margin: 0;\n  overflow: visible;\n  line-height: inherit;\n  word-wrap: normal;\n  background-color: transparent;\n  border: 0;\n  color: #d1d2d2;\n}\n\n/* 代码块复制按钮样式 */\n.markdown-body pre .btn-pre-copy {\n  display: none;\n  position: absolute;\n  top: 10px;\n  right: 12px;\n  font-size: 11px;\n  line-height: 1;\n  cursor: pointer;\n  color: #999;\n  transition: color 0.1s;\n  -webkit-user-select: none;\n  -moz-user-select: none;\n  -ms-user-select: none;\n  user-select: none;\n  z-index: 10;\n  padding: 4px 8px;\n  background-color: rgba(0, 0, 0, 0.3);\n  border-radius: 3px;\n}\n\n.markdown-body pre:hover .btn-pre-copy {\n  display: block;\n}\n\n.markdown-body pre .btn-pre-copy:hover {\n  color: #fff;\n  background-color: rgba(0, 0, 0, 0.5);\n}\n\n/* 代码高亮注释颜色调整 */\n.markdown-body .hljs-comment,\n.markdown-body .hljs-quote {\n  color: #aaa;\n}\n\n/* 代码块滚动条样式（适配深色背景） */\n.markdown-body pre {\n  scrollbar-width: thin;\n  scrollbar-color: rgba(255, 255, 255, 0.5) #2f3a3d;\n}\n\n.markdown-body pre::-webkit-scrollbar {\n  height: 8px;\n}\n\n.markdown-body pre::-webkit-scrollbar-track {\n  background-color: #2f3a3d;\n}\n\n.markdown-body pre::-webkit-scrollbar-thumb {\n  background-color: rgba(255, 255, 255, 0.5);\n  border-radius: 6px;\n}\n\n.markdown-body pre::-webkit-scrollbar-thumb:hover {\n  background-color: rgba(255, 255, 255, 0.65);\n}\n\n/* 表格外层包装，用于自动滚动 */\n.markdown-body > div[style*=\"overflow-x: auto\"] {\n  width: 100%;\n  overflow-x: auto;\n  margin-bottom: 1.5em;\n}\n\n.markdown-body table {\n  border-collapse: collapse;\n  width: 100%;\n  display: block;\n  overflow-x: auto;\n  margin-bottom: 1.5em;\n  background-color: #f9f9f9;\n}\n\n.markdown-body table th,\n.markdown-body table td {\n  padding: 8px 13px;\n  border: 1px solid rgba(0, 0, 0, 0.1);\n  text-align: left;\n  background-color: #ffffff;\n}\n\n.markdown-body table thead tr {\n  background-color: rgba(64, 158, 255, 0.1);\n}\n\n.markdown-body table th {\n  font-weight: 600;\n  background-color: rgba(64, 158, 255, 0.1);\n  color: #343a40;\n}\n\n.markdown-body table tr:nth-child(2n) {\n  background-color: #f9f9f9;\n}\n\n/* object/array[object] 行特殊样式 \n   注意：由于CSS无法直接检测文本内容，此样式需要通过JavaScript动态添加类名实现\n   这里先定义样式，实际应用需要在生成HTML时通过JS处理\n*/\n.markdown-body table tbody tr.object-row {\n  background-color: #F8F8F8;\n}\n\n.markdown-body table tbody tr:hover {\n  background-color: #F8F8F8;\n}\n\n.markdown-body img {\n  max-width: 100%;\n  height: auto;\n  margin: 16px 0;\n  border-radius: 4px;\n}\n\n.markdown-body a {\n  color: #007bff;\n  text-decoration: none;\n}\n\n.markdown-body a:hover {\n  color: mix(#ffffff, #007bff, 20%);\n  text-decoration: underline;\n}\n\n.markdown-body hr {\n  height: 0.25em;\n  padding: 0;\n  margin: 24px 0;\n  background-color: rgba(0, 0, 0, 0.1);\n  border: 0;\n}\n\n/* 页面导航样式微调 */\n.page-nav {\n  margin-top: 24px;\n  padding-top: 16px;\n  border-top: 1px solid rgba(0, 0, 0, 0.1);\n  display: flex;\n  justify-content: space-between;\n}\n\n.page-nav-link {\n  display: inline-block;\n  padding: 8px 14px;\n  background-color: #f9f9f9;\n  color: #007bff;\n  text-decoration: none;\n  border-radius: 4px;\n  transition: background-color 0.15s;\n  border: 1px solid rgba(0, 0, 0, 0.1);\n}\n\n.page-nav-link:hover {\n  background-color: #f0f0f0;\n  color: mix(#ffffff, #007bff, 20%);\n}\n\n.page-nav-link.disabled {\n  color: #9b9b9b;\n  cursor: not-allowed;\n  opacity: 0.6;\n}\n\n.page-nav-link.disabled:hover {\n  background-color: #f9f9f9;\n  color: #9b9b9b;\n}\n\n/* 响应式设计 */\n@media screen and (max-width: 768px) {\n  .menu-toggle {\n    display: block;\n  }\n\n  .sidebar {\n    transform: translateX(-100%);\n    transition: transform 0.3s;\n    z-index: 999;\n  }\n\n  .sidebar.open {\n    transform: translateX(0);\n  }\n\n  .main-content {\n    margin-left: 0;\n    padding: 20px 15px;\n  }\n\n  .header-content {\n    padding: 0 10px;\n  }\n\n  .project-name {\n    font-size: 16px;\n    margin-right: 10px;\n  }\n\n  .search-box {\n    margin-right: 10px;\n  }\n}\n\n/* 打印样式 */\n@media print {\n  .header,\n  .sidebar,\n  .menu-toggle,\n  .search-box,\n  .page-nav {\n    display: none;\n  }\n\n  .main-content {\n    margin-left: 0;\n    padding: 0;\n  }\n\n  .page-content {\n    max-width: 100%;\n  }\n}\n"
  },
  {
    "path": "server/index.php",
    "content": "<?php\n\n// PHP 版本检测（开源版要求 PHP >= 7.4）\nif (version_compare(PHP_VERSION, '7.4.0', '<')) {\n    die('ShowDoc requires PHP >= 7.4.0. Current version: ' . PHP_VERSION);\n}\n\n// ===== 禁止爬虫和搜索引擎访问 =====\nif (PHP_SAPI !== 'cli') {\n    require __DIR__ . '/app/Common/BotDetector.php';\n    \\App\\Common\\BotDetector::blockBot();\n}\n// ===== 爬虫拦截结束 =====\n\n\nrequire __DIR__ . '/vendor/autoload.php';\n\nuse DI\\Container;\nuse Slim\\Factory\\AppFactory;\nuse Psr\\Http\\Message\\ServerRequestInterface as Request;\nuse Psr\\Http\\Message\\ResponseInterface as Response;\nuse Dotenv\\Dotenv;\n\n// CLI 模式下支持：php server/index.php /ping\nif (PHP_SAPI === 'cli') {\n    $path = $argv[1] ?? '/';\n    if ($path !== '' && $path[0] !== '/') {\n        $path = '/' . $path;\n    }\n    // 与 Nginx 下保持一致：/server 前缀 + 实际路径\n    $_SERVER['REQUEST_METHOD'] = $_SERVER['REQUEST_METHOD'] ?? 'GET';\n    $_SERVER['REQUEST_URI'] = '/server' . $path;\n    // 兼容未来重命名为 index.php 或其他文件名\n    $scriptBase = basename(__FILE__);\n    $_SERVER['SCRIPT_NAME'] = '/server/' . $scriptBase;\n}\n\n// 加载根目录 .env（如果存在），供 Database 等使用 getenv() 读取配置\n$rootPath = dirname(__DIR__);\nif (is_file($rootPath . '/.env')) {\n    Dotenv::createImmutable($rootPath)->load();\n}\n\n// 设置默认时区，优先使用环境变量 APP_TIMEZONE，默认为上海时间\n$timezone = getenv('APP_TIMEZONE') ?: 'Asia/Shanghai';\n@date_default_timezone_set($timezone);\n\n// 定义日志路径常量（兼容旧代码，必须在命名空间之前定义）\nif (!defined('LOG_PATH')) {\n    // 计算 Runtime 目录路径（位于 app 目录下）\n    $appPath = __DIR__ . DIRECTORY_SEPARATOR . 'app' . DIRECTORY_SEPARATOR;\n    $runtimePath = $appPath . 'Runtime' . DIRECTORY_SEPARATOR;\n    if (!is_dir($runtimePath)) {\n        @mkdir($runtimePath, 0755, true);\n    }\n    $logPath = $runtimePath . 'Logs' . DIRECTORY_SEPARATOR;\n    if (!is_dir($logPath)) {\n        @mkdir($logPath, 0755, true);\n    }\n    define('LOG_PATH', $logPath);\n}\n\n// 启用原生 Session，供验证码等接口使用（不依赖 ThinkPHP 的 session() 封装）\nif (session_status() === PHP_SESSION_NONE) {\n    session_start();\n}\n\n// 兼容旧版查询参数路由（开源版主要使用此方式）\n// 支持 ?s=Api/Item/info 或 ?s=/api/user/info 或 ?s=/server/api/xxx/xxxx/xxxx/1（路径参数写在 s 参数里）\nif (PHP_SAPI !== 'cli' && isset($_GET['s']) && $_GET['s'] !== '') {\n    $path = $_GET['s'];\n    if ($path !== '' && $path[0] !== '/') {\n        $path = '/' . $path;\n    }\n    // 与 Nginx 下保持一致：/server 前缀 + 实际路径\n    $_SERVER['REQUEST_URI'] = '/server' . $path;\n}\n\n// 初始化 DI 容器\n$container = new Container();\n\n// 注册服务\nrequire __DIR__ . '/app/Common/bootstrap.php';\nrequire __DIR__ . '/app/Common/container.php';\n\nAppFactory::setContainer($container);\n$app = AppFactory::create();\n\n// 设置 base path\n$app->setBasePath('/server');\n\n$app->addRoutingMiddleware();\n$app->addBodyParsingMiddleware();\n\n// 开源版开启错误显示，方便用户排查问题\n$errorMiddleware = $app->addErrorMiddleware(true, true, true);\n$errorHandler = $errorMiddleware->getDefaultErrorHandler();\n$errorHandler->forceContentType('application/json');\n\n// 示例 API：/server/ping\n$app->get('/ping', function (Request $request, Response $response) use ($container) {\n    $controller = $container->get(\\App\\Api\\Controller\\PingController::class);\n    return $controller->index($request, $response);\n});\n\n// Mock 路由：/server/mock-path/{item_id}?path=/test\n// 兼容旧版路由规则：'mock-path/:id\\s' => 'Api/Mock/infoByPath?item_id=:1'\n$app->any('/mock-path/{item_id}', function (Request $request, Response $response, array $args) use ($container) {\n    $controller = $container->get(\\App\\Api\\Controller\\MockController::class);\n    // 将路径参数 item_id 设置为请求属性，以便 getParam 可以获取\n    $request = $request->withAttribute('item_id', $args['item_id']);\n    return $controller->infoByPath($request, $response);\n});\n\n// Mock 路由：/server/mock-data/{unique_key}\n// 兼容旧版路由规则：'mock-data/:unique_key\\s' => 'Api/Mock/infoByKey?unique_key=:1'\n$app->any('/mock-data/{unique_key}', function (Request $request, Response $response, array $args) use ($container) {\n    $controller = $container->get(\\App\\Api\\Controller\\MockController::class);\n    // 将路径参数 unique_key 设置为请求属性，以便 getParam 可以获取\n    $request = $request->withAttribute('unique_key', $args['unique_key']);\n    return $controller->infoByKey($request, $response);\n});\n\n// 通用模块/控制器/方法路由：\n// 兼容 /server/Api/User/login、/server/api/user/login，也兼容 /server/Api/User/info 等。\n// 兼容下划线命名：/server/Api/Page_Comment/add -> PageCommentController\n// 兼容驼峰命名：/server/Api/publicSquare/checkEnabled -> PublicSquareController\n// 开源版也支持路径参数路由（如 /server/Api/Item/info/item_id/1），但主要使用查询参数路由\n$app->any('/{module}/{controller}/{action}[/{params:.*}]', function (Request $request, Response $response, array $args) use ($container) {\n    $module     = ucfirst(strtolower($args['module'] ?? ''));\n\n    // 控制器名称转换：支持下划线命名和驼峰命名\n    $controllerName = $args['controller'] ?? '';\n    if (strpos($controllerName, '_') !== false) {\n        // 下划线命名：page_comment -> PageComment\n        $controller = str_replace('_', '', ucwords(strtolower($controllerName), '_'));\n    } else {\n        // 驼峰命名或全小写：publicSquare -> PublicSquare, user -> User\n        // 方法：在每个大写字母前添加下划线（除了首字母），然后使用 ucwords\n        $normalized = preg_replace('/([a-z])([A-Z])/', '$1_$2', $controllerName);\n        $controller = str_replace('_', '', ucwords(strtolower($normalized), '_'));\n    }\n\n    $action     = strtolower($args['action'] ?? '');\n\n    if ($module === '' || $controller === '' || $action === '') {\n        $response->getBody()->write(json_encode([\n            'error_code'    => 10400,\n            'error_message' => 'Invalid route',\n        ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));\n        return $response->withStatus(400)->withHeader('Content-Type', 'application/json');\n    }\n\n    // 解析路径参数（key/value 成对）\n    if (!empty($args['params'])) {\n        $parts  = array_values(array_filter(explode('/', $args['params'])));\n        $count  = count($parts);\n        for ($i = 0; $i + 1 < $count; $i += 2) {\n            $key   = $parts[$i];\n            $value = $parts[$i + 1];\n            $request = $request->withAttribute($key, $value);\n        }\n    }\n\n    $className = \"\\\\App\\\\{$module}\\\\Controller\\\\{$controller}Controller\";\n    if (!class_exists($className)) {\n        $response->getBody()->write(json_encode([\n            'error_code'    => 10404,\n            'error_message' => \"Controller not found: {$className}\",\n        ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));\n        return $response->withStatus(404)->withHeader('Content-Type', 'application/json');\n    }\n\n    $controllerInstance = $container->get($className);\n    if (!method_exists($controllerInstance, $action)) {\n        $response->getBody()->write(json_encode([\n            'error_code'    => 10404,\n            'error_message' => \"Action not found: {$action}\",\n        ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));\n        return $response->withStatus(404)->withHeader('Content-Type', 'application/json');\n    }\n\n    return $controllerInstance->$action($request, $response);\n});\n\n$app->run();\n"
  },
  {
    "path": "server/index_old.php",
    "content": "<?php\n\n// 当php版本达到composer包要求的版本时候，则require autoload\n// vendor/composer/platform_check.php 里面可以看到composer包要求的最低版本\ndefine('COMPOSER_PHP_VERSION', '7.2.5');\nif (version_compare(PHP_VERSION, COMPOSER_PHP_VERSION, '>')) {\n    // 增加自动加载\n    require './vendor/autoload.php';\n}\n\n// cookie安全，给PHPSESSID加上Strict\nif (PHP_VERSION_ID >= 70300) {\n    session_set_cookie_params(array(\n        'samesite' => 'Strict'\n    ));\n} else {\n    session_set_cookie_params(\n        NULL,\n        '/; samesite=Strict'\n    );\n}\n\n// 开启调试模式 建议开发阶段开启 部署阶段注释或者设为false\ndefine('APP_DEBUG', True);\n\n// 定义应用目录\ndefine('APP_PATH', './Application/');\n\n// 引入ThinkPHP入口文件\nrequire './ThinkPHP/ThinkPHP.php';\n"
  },
  {
    "path": "server/tests/mcp/README.md",
    "content": "# ShowDoc MCP 测试（开源版）\n\n本目录包含 ShowDoc MCP (Model Context Protocol) 功能的自动化测试脚本。\n\n## 安全说明\n\n⚠️ **这些测试脚本只能通过命令行执行，禁止 web 访问。**\n\n脚本会在运行时检查执行环境，如果通过 web 访问会返回 403 Forbidden。\n\n## 文件说明\n\n| 文件                    | 说明                                                 |\n| ----------------------- | ---------------------------------------------------- |\n| `mcp_test.php`          | 主测试脚本，运行所有测试用例                         |\n| `bootstrap.php`         | 引导文件，包含公共函数、数据库初始化、McpTester 类   |\n| `openapi3.json`         | OpenAPI 3.0 格式的测试文件，用于 import_openapi 测试 |\n\n## 快速开始\n\n```bash\n# 在项目根目录运行\nphp server/tests/mcp/mcp_test.php\n```\n\n## 配置\n\n测试脚本会自动从数据库中获取测试用户（优先使用管理员用户，其次普通用户），无需手动配置 UID。\n\n如需修改 MCP 端点地址，在 `mcp_test.php` 中修改：\n\n```php\ndefine('MCP_URL', 'http://127.0.0.1/showdoc/mcp.php');\n```\n\n## 测试内容\n\n### 1. 初始化测试 (2)\n\n- MCP initialize\n- 无 Token 访问被拒绝\n\n### 2. Token 准备\n\n- 自动获取或创建读写 Token（包含 `can_create_item` 和 `can_delete_item` 权限）\n- 自动获取或创建只读 Token\n- 自动创建指定项目范围 Token（用于权限测试）\n\n### 3. 基础功能测试 (7)\n\n- tools/list\n- list_items\n- get_item\n- list_catalogs\n- list_pages\n- search_pages\n- get_page_template\n\n### 4. 项目操作测试 (2)\n\n- create_item\n- update_item\n\n### 5. 目录操作测试 (3)\n\n- create_catalog\n- update_catalog\n- get_catalog\n\n### 6. 页面操作测试 (9)\n\n- create_page\n- get_page\n- update_page\n- upsert_page (create)\n- upsert_page (update)\n- batch_get_pages\n- batch_upsert_pages\n- create_page_by_comment\n\n### 7. 历史版本测试 (4)\n\n- get_page_history\n- get_page_version\n- diff_page_versions\n- restore_page_version\n\n### 8. 附件管理测试 (3)\n\n- upload_attachment\n- list_attachments\n- delete_attachment\n\n### 9. OpenAPI 导入测试 (1)\n\n- import_openapi（支持 OpenAPI 3.0 格式）\n\n### 10. 权限控制测试 (2)\n\n- 只读 Token 写操作被拒绝\n- 指定项目范围 Token 访问其他项目被拒绝\n\n### 11. 边界条件测试 (8)\n\n- get_item 空参数被拒绝\n- get_page 空参数被拒绝\n- create_page 缺少必要参数被拒绝\n- get_item 无效ID类型被拒绝\n- get_item 负数ID被拒绝\n- create_item 超长名称被拒绝或截断\n- search_pages 特殊字符处理\n- create_page 空标题被拒绝\n\n### 12. 错误场景测试 (8)\n\n- get_item 不存在的项目\n- get_page 不存在的页面\n- get_catalog 不存在的目录\n- 无效 Token 格式被拒绝\n- 空 Token 被拒绝\n- 不存在的方法被拒绝\n- 无效 JSON-RPC 请求处理\n- 更新无权限项目被拒绝\n\n### 13. 业务逻辑测试 (3+)\n\n- **get_page 内容解转义**：验证 MCP 返回的内容已正确解转义\n- **create_page 存储时 HTML 转义**：验证存储到数据库时内容已转义\n- **配额信息显示**：显示当前用户的空间使用情况\n\n### 14. 清理测试数据\n\n- 删除创建的页面、目录、项目\n- 清理测试创建的 Token\n\n## 开源版与主版差异\n\n本测试脚本针对开源版进行了适配：\n\n1. **无 VIP 功能**：移除了 VIP 相关测试，配额使用固定大值（100000 项目、1TB 空间）\n2. **无敏感词检测**：移除了敏感词检测相关的测试分支\n3. **无分表**：数据库查询使用单一 `page` 表，而非 `Page::tableForItem()`\n4. **MCP 地址**：默认使用 `http://127.0.0.1/showdoc/mcp.php`\n\n## 测试输出示例\n\n```\n=====================================\n| ShowDoc MCP 功能自动化测试（开源版） |\n=====================================\n\n测试用户 UID: 1\n用户类型: 管理员\n已绑定邮箱: 是\nMCP 地址: http://127.0.0.1/showdoc/mcp.php\n\n=======================\n| 1. 初始化测试 |\n=======================\n\n  ✓ MCP initialize - 2024-11-05\n  ✓ 无 Token 访问被拒绝 - 正确返回错误: Token 无效或已过期\n\n========================\n| 2. 准备测试 Token |\n========================\n\n  ℹ 读写 Token: ai_b3f925f...ceca4b\n  ℹ   - 权限: write\n  ℹ   - 范围: all\n  ℹ   - 可创建项目: 是\n  ℹ   - 可删除项目: 是\n  ℹ 只读 Token: ai_12da512...3e36d7\n\n...\n\n=======================\n| 13. 业务逻辑测试 |\n=======================\n\n  ✓ get_page 内容解转义 - 内容正确解转义\n  ✓ create_page 存储时 HTML 转义 - 存储时正确转义\n  ℹ 当前用户项目数: 5, 开源版配额上限: 100000\n  ✓ create_item 配额限制 - 项目数 5 未达上限 100000，跳过配额测试\n  ℹ 已用空间: 1.23 MB / 1024.00 GB\n\n...\n\n================\n| 测试总结 |\n================\n\n  通过: 55\n  失败: 0\n  总计: 55\n  成功率: 100%\n\n测试完成！\n```\n\n## 调试模式\n\n在 `mcp_test.php` 中设置 `$debugMode = true` 可以显示详细的 API 响应：\n\n```php\n$debugMode = true;\n```\n\n## 注意事项\n\n1. **自动用户选择**：测试脚本会自动从数据库中选择用户（优先管理员 groupid=1，其次普通用户 groupid=2）\n2. **数据库连接**：测试脚本会自动加载项目根目录的 `.env` 文件获取数据库配置\n3. **测试数据清理**：测试完成后会自动删除创建的项目、目录、页面和 Token\n4. **权限测试**：需要至少 2 个项目才能完整测试指定项目范围的权限控制\n5. **附件测试**：使用 Base64 编码的测试图片，无需真实文件\n6. **Token 权限**：读写 Token 会自动设置 `can_create_item=1` 和 `can_delete_item=1`\n7. **安全设计**：访问不存在的项目时，系统返回\"无权限\"而非\"不存在\"，避免暴露项目是否存在\n8. **业务逻辑测试**：包含 HTML 转义/解转义测试\n\n## 测试覆盖\n\n| 类别         | 测试数量 |\n| ------------ | -------- |\n| 初始化       | 2        |\n| 基础功能     | 7        |\n| 项目操作     | 2        |\n| 目录操作     | 3        |\n| 页面操作     | 9        |\n| 历史版本     | 4        |\n| 附件管理     | 3        |\n| OpenAPI 导入 | 1        |\n| 权限控制     | 2        |\n| 边界条件     | 8        |\n| 错误场景     | 8        |\n| 业务逻辑     | 3+       |\n| 清理         | 动态     |\n| **总计**     | **52+**  |\n"
  },
  {
    "path": "server/tests/mcp/bootstrap.php",
    "content": "<?php\n\n/**\n * ShowDoc MCP 测试引导文件（开源版）\n *\n * 包含公共函数、数据库初始化、McpTester 类\n *\n * 安全说明：此文件只能通过命令行执行，禁止 web 访问\n */\n\n// 只允许命令行执行\nif (php_sapi_name() !== 'cli') {\n  http_response_code(403);\n  exit('Forbidden: This script can only be run from command line');\n}\n\n// 设置错误报告\nerror_reporting(E_ALL);\nini_set('display_errors', '1');\n\n// 加载 Composer 自动加载\n$serverPath = dirname(__DIR__, 2); // server/tests/mcp -> server\n$rootPath = dirname($serverPath);  // server -> 根目录\n\nrequire $serverPath . '/vendor/autoload.php';\n\nuse Dotenv\\Dotenv;\nuse Illuminate\\Database\\Capsule\\Manager as Capsule;\n\n// 加载根目录 .env\nif (is_file($rootPath . '/.env')) {\n  Dotenv::createImmutable($rootPath)->load();\n}\n\n// 定义 RUNTIME_PATH 常量\nif (!defined('RUNTIME_PATH')) {\n  define('RUNTIME_PATH', $serverPath . '/app/Runtime/');\n}\n\n// 初始化数据库连接\n$capsule = new Capsule();\n$dbType = $_ENV['DB_TYPE'] ?? getenv('DB_TYPE') ?: 'sqlite';\n\nif ($dbType === 'sqlite') {\n  // 开源版数据库路径：项目根目录/Sqlite/showdoc.db.php\n  $dbPath = $_ENV['DB_NAME'] ?? getenv('DB_NAME') ?: $rootPath . '/Sqlite/showdoc.db.php';\n  $capsule->addConnection([\n    'driver'   => 'sqlite',\n    'database' => $dbPath,\n    'prefix'   => '',\n    'options'  => [PDO::ATTR_STRINGIFY_FETCHES => true],\n  ]);\n} else {\n  $capsule->addConnection([\n    'driver'    => 'mysql',\n    'host'      => $_ENV['DB_HOST'] ?? getenv('DB_HOST') ?: '127.0.0.1',\n    'port'      => (int) ($_ENV['DB_PORT'] ?? getenv('DB_PORT') ?: 3306),\n    'database'  => $_ENV['DB_NAME'] ?? getenv('DB_NAME') ?: 'showdoc',\n    'username'  => $_ENV['DB_USER'] ?? getenv('DB_USER') ?: 'root',\n    'password'  => $_ENV['DB_PWD'] ?? getenv('DB_PWD') ?: '',\n    'charset'   => $_ENV['DB_CHARSET'] ?? getenv('DB_CHARSET') ?: 'utf8mb4',\n    'collation' => 'utf8mb4_unicode_ci',\n    'prefix'    => '',\n    'options'   => [PDO::ATTR_STRINGIFY_FETCHES => true],\n  ]);\n}\n$capsule->setAsGlobal();\n$capsule->bootEloquent();\n\n// ============================================================================\n// 颜色输出函数\n// ============================================================================\n\nfunction colorOutput($text, $color = 'white')\n{\n  $colors = [\n    'red' => \"\\033[31m\",\n    'green' => \"\\033[32m\",\n    'yellow' => \"\\033[33m\",\n    'blue' => \"\\033[34m\",\n    'white' => \"\\033[37m\",\n    'reset' => \"\\033[0m\",\n  ];\n  return $colors[$color] . $text . $colors['reset'];\n}\n\nfunction printHeader($text)\n{\n  echo \"\\n\" . colorOutput(\"=\" . str_repeat(\"=\", strlen($text) + 2) . \"=\", 'blue') . \"\\n\";\n  echo colorOutput(\"| $text |\", 'blue') . \"\\n\";\n  echo colorOutput(\"=\" . str_repeat(\"=\", strlen($text) + 2) . \"=\", 'blue') . \"\\n\\n\";\n}\n\nfunction printSuccess($text)\n{\n  echo colorOutput(\"  ✓ $text\", 'green') . \"\\n\";\n}\n\nfunction printError($text)\n{\n  echo colorOutput(\"  ✗ $text\", 'red') . \"\\n\";\n}\n\nfunction printInfo($text)\n{\n  echo colorOutput(\"  ℹ $text\", 'yellow') . \"\\n\";\n}\n\nfunction printDebug($text)\n{\n  global $debugMode;\n  if ($debugMode ?? false) {\n    echo colorOutput(\"  [DEBUG] $text\", 'white') . \"\\n\";\n  }\n}\n\n// ============================================================================\n// 测试用户管理\n// ============================================================================\n\nclass TestUserManager\n{\n  /**\n   * 获取测试用户\n   * \n   * @param string $type 'admin' 或 'normal'\n   * @return array|null 用户信息\n   */\n  public static function getTestUser($type = 'admin')\n  {\n    $groupId = ($type === 'admin') ? 1 : 2;\n\n    $user = Capsule::table('user')\n      ->where('groupid', $groupId)\n      ->orderBy('uid', 'asc')\n      ->first();\n\n    if (!$user) {\n      return null;\n    }\n\n    return [\n      'uid' => (int) $user->uid,\n      'username' => $user->username ?? '',\n      'groupid' => (int) $user->groupid,\n      'type' => $type,\n    ];\n  }\n\n  /**\n   * 获取所有测试用户\n   */\n  public static function getAllTestUsers()\n  {\n    $admins = Capsule::table('user')\n      ->where('groupid', 1)\n      ->orderBy('uid', 'asc')\n      ->limit(2)\n      ->get();\n\n    $normals = Capsule::table('user')\n      ->where('groupid', 2)\n      ->orderBy('uid', 'asc')\n      ->limit(2)\n      ->get();\n\n    $users = [];\n    foreach ($admins as $user) {\n      $users[] = [\n        'uid' => (int) $user->uid,\n        'username' => $user->username ?? '',\n        'groupid' => 1,\n        'type' => 'admin',\n      ];\n    }\n    foreach ($normals as $user) {\n      $users[] = [\n        'uid' => (int) $user->uid,\n        'username' => $user->username ?? '',\n        'groupid' => 2,\n        'type' => 'normal',\n      ];\n    }\n\n    return $users;\n  }\n\n  /**\n   * 检查用户是否绑定邮箱\n   */\n  public static function hasEmail($uid)\n  {\n    $user = Capsule::table('user')\n      ->where('uid', $uid)\n      ->first();\n\n    return !empty($user->email);\n  }\n\n  /**\n   * 获取用户项目数量\n   */\n  public static function getItemCount($uid)\n  {\n    return Capsule::table('item')\n      ->where('uid', $uid)\n      ->where('is_del', 0)\n      ->count();\n  }\n\n  /**\n   * 获取用户已用空间\n   */\n  public static function getUsedSpace($uid)\n  {\n    $result = Capsule::table('upload_file')\n      ->where('uid', $uid)\n      ->sum('file_size');\n\n    return (int) $result;\n  }\n}\n\n// ============================================================================\n// Token 管理类\n// ============================================================================\n\nclass TokenManager\n{\n  private $uid;\n  private $createdTokens = [];\n\n  public function __construct($uid)\n  {\n    $this->uid = $uid;\n  }\n\n  /**\n   * 生成 AI Token\n   */\n  public function createToken($permission = 'write', $scope = 'all', $allowedItems = [], $name = '')\n  {\n    $token = 'ai_' . bin2hex(random_bytes(43));\n\n    $data = [\n      'uid' => $this->uid,\n      'token' => $token,\n      'name' => $name ?: \"MCP测试 Token \" . date('Y-m-d H:i:s'),\n      'permission' => $permission,\n      'scope' => $scope,\n      'allowed_items' => empty($allowedItems) ? null : json_encode($allowedItems),\n      'can_create_item' => 1,\n      'can_delete_item' => 1,\n      'is_active' => 1,\n      'created_at' => date('Y-m-d H:i:s'),\n    ];\n\n    $id = Capsule::table('user_ai_token')->insertGetId($data);\n    $this->createdTokens[] = $id;\n\n    return [\n      'id' => $id,\n      'token' => $token,\n      'permission' => $permission,\n      'scope' => $scope,\n      'allowed_items' => $allowedItems,\n      'can_create_item' => 1,\n      'can_delete_item' => 1,\n    ];\n  }\n\n  /**\n   * 获取或创建读写 Token（确保有删除权限）\n   */\n  public function getOrCreateWriteToken()\n  {\n    // 优先查找有删除权限的 Token\n    $existing = Capsule::table('user_ai_token')\n      ->where('uid', $this->uid)\n      ->where('permission', 'write')\n      ->where('scope', 'all')\n      ->where('can_delete_item', 1)\n      ->where('is_active', 1)\n      ->first();\n\n    if ($existing) {\n      return (array) $existing;\n    }\n\n    // 如果没有，创建新的 Token（带删除权限）\n    return $this->createToken('write', 'all', [], 'MCP测试-读写Token');\n  }\n\n  /**\n   * 获取或创建只读 Token\n   */\n  public function getOrCreateReadOnlyToken()\n  {\n    $existing = Capsule::table('user_ai_token')\n      ->where('uid', $this->uid)\n      ->where('permission', 'read')\n      ->where('is_active', 1)\n      ->first();\n\n    if ($existing) {\n      return (array) $existing;\n    }\n\n    return $this->createToken('read', 'all', [], 'MCP测试-只读Token');\n  }\n\n  /**\n   * 获取或创建指定项目范围的 Token\n   */\n  public function getOrCreateScopedToken($allowedItems)\n  {\n    $existing = Capsule::table('user_ai_token')\n      ->where('uid', $this->uid)\n      ->where('scope', 'selected')\n      ->where('is_active', 1)\n      ->first();\n\n    if ($existing) {\n      return (array) $existing;\n    }\n\n    return $this->createToken('write', 'selected', $allowedItems, 'MCP测试-指定项目Token');\n  }\n\n  /**\n   * 清理测试创建的 Token\n   */\n  public function cleanup()\n  {\n    if (!empty($this->createdTokens)) {\n      Capsule::table('user_ai_token')\n        ->whereIn('id', $this->createdTokens)\n        ->delete();\n    }\n  }\n}\n\n// ============================================================================\n// MCP 测试类\n// ============================================================================\n\nclass McpTester\n{\n  private $baseUrl;\n  private $tokens = [];\n  private $testResults = [];\n  public $createdItems = [];\n  public $createdPages = [];\n  public $createdCatalogs = [];\n  public $uploadedFileSigns = [];\n\n  public function __construct($baseUrl)\n  {\n    $this->baseUrl = $baseUrl;\n  }\n\n  /**\n   * 发送 MCP 请求\n   */\n  public function sendRequest($method, $params = [], $token = null)\n  {\n    $requestData = [\n      'jsonrpc' => '2.0',\n      'id' => uniqid(),\n      'method' => $method,\n      'params' => $params,\n    ];\n\n    $headers = ['Content-Type: application/json'];\n    if ($token) {\n      $headers[] = \"Authorization: Bearer $token\";\n    }\n\n    $ch = curl_init($this->baseUrl);\n    curl_setopt($ch, CURLOPT_POST, true);\n    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($requestData));\n    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);\n\n    $response = curl_exec($ch);\n    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);\n    $error = curl_error($ch);\n    curl_close($ch);\n\n    if ($error) {\n      return ['error' => $error, 'http_code' => $httpCode];\n    }\n\n    return [\n      'http_code' => $httpCode,\n      'body' => json_decode($response, true),\n    ];\n  }\n\n  /**\n   * 调用 MCP Tool\n   */\n  public function callTool($name, $arguments = [], $token = null)\n  {\n    return $this->sendRequest('tools/call', [\n      'name' => $name,\n      'arguments' => $arguments,\n    ], $token);\n  }\n\n  /**\n   * 列出可用 Tools\n   */\n  public function listTools($token = null)\n  {\n    return $this->sendRequest('tools/list', [], $token);\n  }\n\n  /**\n   * 初始化 MCP 连接\n   */\n  public function initialize()\n  {\n    return $this->sendRequest('initialize', [\n      'protocolVersion' => '2024-11-05',\n      'capabilities' => [],\n      'clientInfo' => [\n        'name' => 'showdoc-mcp-test',\n        'version' => '1.0.0',\n      ],\n    ]);\n  }\n\n  /**\n   * 记录测试结果\n   */\n  public function recordTest($name, $passed, $message = '')\n  {\n    $this->testResults[] = [\n      'name' => $name,\n      'passed' => $passed,\n      'message' => $message,\n    ];\n\n    if ($passed) {\n      printSuccess($name . ($message ? \" - $message\" : ''));\n    } else {\n      printError($name . ($message ? \" - $message\" : ''));\n    }\n  }\n\n  /**\n   * 设置 Token\n   */\n  public function setToken($name, $token)\n  {\n    $this->tokens[$name] = $token;\n  }\n\n  /**\n   * 获取 Token\n   */\n  public function getToken($name)\n  {\n    return $this->tokens[$name] ?? null;\n  }\n\n  /**\n   * 记录创建的项目（用于清理）\n   */\n  public function addCreatedItem($itemId)\n  {\n    $this->createdItems[] = $itemId;\n  }\n\n  /**\n   * 记录创建的页面（用于清理）\n   */\n  public function addCreatedPage($pageId)\n  {\n    $this->createdPages[] = $pageId;\n  }\n\n  /**\n   * 记录创建的目录（用于清理）\n   */\n  public function addCreatedCatalog($catId)\n  {\n    $this->createdCatalogs[] = $catId;\n  }\n\n  /**\n   * 记录上传的文件（用于清理）\n   */\n  public function addUploadedFileSign($sign)\n  {\n    $this->uploadedFileSigns[] = $sign;\n  }\n\n  /**\n   * 获取测试统计\n   */\n  public function getStats()\n  {\n    $passed = count(array_filter($this->testResults, fn($r) => $r['passed']));\n    $total = count($this->testResults);\n    return [\n      'passed' => $passed,\n      'failed' => $total - $passed,\n      'total' => $total,\n    ];\n  }\n\n  /**\n   * 打印测试总结\n   */\n  public function printSummary()\n  {\n    $stats = $this->getStats();\n    echo \"\\n\";\n    printHeader(\"测试总结\");\n    echo \"  通过: \" . colorOutput($stats['passed'], 'green') . \"\\n\";\n    echo \"  失败: \" . colorOutput($stats['failed'], 'red') . \"\\n\";\n    echo \"  总计: \" . $stats['total'] . \"\\n\";\n    echo \"  成功率: \" . round($stats['passed'] / max($stats['total'], 1) * 100, 1) . \"%\\n\";\n\n    if ($stats['failed'] > 0) {\n      echo \"\\n失败的测试:\\n\";\n      foreach ($this->testResults as $result) {\n        if (!$result['passed']) {\n          printError(\"{$result['name']}: {$result['message']}\");\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "server/tests/mcp/mcp_test.php",
    "content": "<?php\n\n/**\n * ShowDoc MCP 功能自动化测试脚本（开源版）\n * \n * 使用方法：\n *   php server/tests/mcp/mcp_test.php\n * \n * 测试内容：\n *   1. 基础功能（list_items, get_item 等）\n *   2. 权限控制（只读、读写、指定项目）\n *   3. 页面操作（create, update, delete）\n *   4. 高级功能（历史版本、附件、OpenAPI导入）\n *   5. 业务逻辑检查（内容解转义等）\n * \n * 开源版说明：\n *   - 无 VIP 功能，配额使用固定大值\n *   - 无敏感词检测\n *   - 无分表，使用单一 page 表\n */\n\n// 加载引导文件\nrequire __DIR__ . '/bootstrap.php';\n\nuse Illuminate\\Database\\Capsule\\Manager as Capsule;\n\n// 定义测试常量（开源版地址）\ndefine('MCP_URL', 'http://127.0.0.1/showdoc/mcp.php');\n\n// 调试模式（显示详细响应）\n$debugMode = false;\n\n// ============================================================================\n// 自动获取测试用户\n// ============================================================================\n\n$testUser = TestUserManager::getTestUser('admin');\nif (!$testUser) {\n  $testUser = TestUserManager::getTestUser('normal');\n}\n\nif (!$testUser) {\n  echo colorOutput(\"错误: 找不到可用的测试用户，请确保数据库中有用户数据\", 'red') . \"\\n\";\n  exit(1);\n}\n\ndefine('TEST_UID', $testUser['uid']);\n\n// ============================================================================\n// 测试开始\n// ============================================================================\n\nprintHeader(\"ShowDoc MCP 功能自动化测试（开源版）\");\necho \"测试用户 UID: \" . TEST_UID . \"\\n\";\necho \"用户类型: \" . ($testUser['type'] === 'admin' ? '管理员' : '普通用户') . \"\\n\";\necho \"已绑定邮箱: \" . (TestUserManager::hasEmail(TEST_UID) ? '是' : '否') . \"\\n\";\necho \"MCP 地址: \" . MCP_URL . \"\\n\";\n\n$tester = new McpTester(MCP_URL);\n$tokenManager = new TokenManager(TEST_UID);\n\n// ============================================================================\n// 第一部分：初始化测试\n// ============================================================================\n\nprintHeader(\"1. 初始化测试\");\n\n// 测试 initialize\n$result = $tester->initialize();\n$tester->recordTest(\n  'MCP initialize',\n  isset($result['body']['result']['protocolVersion']),\n  $result['body']['result']['protocolVersion'] ?? ($result['body']['error']['message'] ?? '未知错误')\n);\n\n// 测试无 Token 时访问 tools/call\n$result = $tester->callTool('list_items');\n$hasError = isset($result['body']['error']);\n$errorMsg = $result['body']['error']['message'] ?? '未知错误';\n$tester->recordTest(\n  '无 Token 访问被拒绝',\n  $hasError,\n  $hasError ? \"正确返回错误: $errorMsg\" : '应该返回错误'\n);\n\n// ============================================================================\n// 第二部分：准备测试 Token\n// ============================================================================\n\nprintHeader(\"2. 准备测试 Token\");\n\n// 获取或创建读写 Token\n$writeTokenData = $tokenManager->getOrCreateWriteToken();\n$writeToken = $writeTokenData['token'];\nprintInfo(\"读写 Token: \" . substr($writeToken, 0, 10) . \"...\" . substr($writeToken, -6));\nprintInfo(\"  - 权限: \" . ($writeTokenData['permission'] ?? 'unknown'));\nprintInfo(\"  - 范围: \" . ($writeTokenData['scope'] ?? 'unknown'));\nprintInfo(\"  - 可创建项目: \" . (isset($writeTokenData['can_create_item']) ? ($writeTokenData['can_create_item'] ? '是' : '否') : 'unknown'));\nprintInfo(\"  - 可删除项目: \" . (isset($writeTokenData['can_delete_item']) ? ($writeTokenData['can_delete_item'] ? '是' : '否') : 'unknown'));\n\n// 获取或创建只读 Token\n$readOnlyTokenData = $tokenManager->getOrCreateReadOnlyToken();\n$readOnlyToken = $readOnlyTokenData['token'];\nprintInfo(\"只读 Token: \" . substr($readOnlyToken, 0, 10) . \"...\" . substr($readOnlyToken, -6));\n\n$tester->setToken('read_write', $writeToken);\n$tester->setToken('read_only', $readOnlyToken);\n\n// ============================================================================\n// 第三部分：基础功能测试\n// ============================================================================\n\nprintHeader(\"3. 基础功能测试\");\n\n$token = $tester->getToken('read_write');\n\n// 测试 tools/list\n$result = $tester->listTools($token);\nprintDebug(\"tools/list 响应: \" . json_encode($result['body'], JSON_UNESCAPED_UNICODE));\nif (isset($result['body']['error'])) {\n  $tester->recordTest('tools/list', false, $result['body']['error']['message'] ?? '未知错误');\n} else {\n  $toolCount = count($result['body']['result']['tools'] ?? []);\n  $tester->recordTest('tools/list', $toolCount > 0, \"共 $toolCount 个工具\");\n}\n\n// 测试 list_items\n$result = $tester->callTool('list_items', [], $token);\nprintDebug(\"list_items 响应: \" . json_encode($result['body'], JSON_UNESCAPED_UNICODE));\n$firstItemId = null;\nif (isset($result['body']['error'])) {\n  $tester->recordTest('list_items', false, $result['body']['error']['message'] ?? '未知错误');\n} else {\n  $content = $result['body']['result']['content'][0]['text'] ?? '';\n  $itemsData = json_decode($content, true);\n  $itemCount = count($itemsData['items'] ?? []);\n  $tester->recordTest('list_items', true, \"返回 $itemCount 个项目\");\n\n  // 保存第一个项目 ID\n  if (isset($itemsData['items'][0]['item_id'])) {\n    $firstItemId = $itemsData['items'][0]['item_id'];\n    printInfo(\"使用项目 ID: $firstItemId 进行后续测试\");\n  }\n}\n\n// 测试 get_item\nif ($firstItemId) {\n  $result = $tester->callTool('get_item', ['item_id' => $firstItemId], $token);\n  if (isset($result['body']['error'])) {\n    $tester->recordTest('get_item', false, $result['body']['error']['message'] ?? '未知错误');\n  } else {\n    $tester->recordTest('get_item', true, '成功');\n  }\n} else {\n  $tester->recordTest('get_item', false, '跳过：没有可用的项目');\n}\n\n// 测试 list_catalogs\nif ($firstItemId) {\n  $result = $tester->callTool('list_catalogs', ['item_id' => $firstItemId], $token);\n  if (isset($result['body']['error'])) {\n    $tester->recordTest('list_catalogs', false, $result['body']['error']['message'] ?? '未知错误');\n  } else {\n    $tester->recordTest('list_catalogs', true, '成功');\n  }\n} else {\n  $tester->recordTest('list_catalogs', false, '跳过：没有可用的项目');\n}\n\n// 测试 list_pages\nif ($firstItemId) {\n  $result = $tester->callTool('list_pages', ['item_id' => $firstItemId], $token);\n  if (isset($result['body']['error'])) {\n    $tester->recordTest('list_pages', false, $result['body']['error']['message'] ?? '未知错误');\n  } else {\n    $tester->recordTest('list_pages', true, '成功');\n  }\n} else {\n  $tester->recordTest('list_pages', false, '跳过：没有可用的项目');\n}\n\n// 测试 search_pages（默认 title 模式）\n$result = $tester->callTool('search_pages', ['query' => 'test'], $token);\nif (isset($result['body']['error'])) {\n  $tester->recordTest('search_pages (title模式)', false, $result['body']['error']['message'] ?? '未知错误');\n} else {\n  $tester->recordTest('search_pages (title模式)', true, '成功');\n}\n\n// 测试 search_pages 的 search_mode 参数\nif ($firstItemId > 0) {\n  // title 模式（只搜索标题）\n  $result = $tester->callTool('search_pages', [\n    'query' => 'test',\n    'item_id' => $firstItemId,\n    'search_mode' => 'title',\n  ], $token);\n  if (isset($result['body']['error'])) {\n    $tester->recordTest('search_pages title模式', false, $result['body']['error']['message'] ?? '未知错误');\n  } else {\n    // MCP 返回结构：body.result.content[0].text 是 JSON 字符串\n    $text = $result['body']['result']['content'][0]['text'] ?? '';\n    $data = json_decode($text, true) ?: [];\n    $mode = $data['search_mode'] ?? '';\n    $tester->recordTest('search_pages title模式', $mode === 'title', \"search_mode={$mode}\");\n  }\n\n  // content 模式（只搜索内容）\n  $result = $tester->callTool('search_pages', [\n    'query' => 'test',\n    'item_id' => $firstItemId,\n    'search_mode' => 'content',\n  ], $token);\n  if (isset($result['body']['error'])) {\n    $tester->recordTest('search_pages content模式', false, $result['body']['error']['message'] ?? '未知错误');\n  } else {\n    $text = $result['body']['result']['content'][0]['text'] ?? '';\n    $data = json_decode($text, true) ?: [];\n    $mode = $data['search_mode'] ?? '';\n    $tester->recordTest('search_pages content模式', $mode === 'content', \"search_mode={$mode}\");\n  }\n\n  // all 模式（搜索标题和内容）\n  $result = $tester->callTool('search_pages', [\n    'query' => 'test',\n    'item_id' => $firstItemId,\n    'search_mode' => 'all',\n  ], $token);\n  if (isset($result['body']['error'])) {\n    $tester->recordTest('search_pages all模式', false, $result['body']['error']['message'] ?? '未知错误');\n  } else {\n    $text = $result['body']['result']['content'][0]['text'] ?? '';\n    $data = json_decode($text, true) ?: [];\n    $mode = $data['search_mode'] ?? '';\n    $tester->recordTest('search_pages all模式', $mode === 'all', \"search_mode={$mode}\");\n  }\n\n  // 无效的 search_mode 应该回退到 title 模式\n  $result = $tester->callTool('search_pages', [\n    'query' => 'test',\n    'item_id' => $firstItemId,\n    'search_mode' => 'invalid_mode',\n  ], $token);\n  if (isset($result['body']['error'])) {\n    $tester->recordTest('search_pages 无效模式回退', false, $result['body']['error']['message'] ?? '未知错误');\n  } else {\n    $text = $result['body']['result']['content'][0]['text'] ?? '';\n    $data = json_decode($text, true) ?: [];\n    $mode = $data['search_mode'] ?? '';\n    $tester->recordTest('search_pages 无效模式回退', $mode === 'title', \"无效模式应回退到title，实际={$mode}\");\n  }\n}\n\n// 测试 get_page_template\n$result = $tester->callTool('get_page_template', ['type' => 'api'], $token);\nif (isset($result['body']['error'])) {\n  $tester->recordTest('get_page_template', false, $result['body']['error']['message'] ?? '未知错误');\n} else {\n  $tester->recordTest('get_page_template', true, '成功');\n}\n\n// ============================================================================\n// 第四部分：项目创建测试\n// ============================================================================\n\nprintHeader(\"4. 项目创建测试\");\n\n// 测试 create_item\n$result = $tester->callTool('create_item', [\n  'item_name' => '[MCP测试] 自动创建的项目 ' . date('Y-m-d H:i:s'),\n  'item_type' => 1,\n  'item_description' => '这是 MCP 自动化测试创建的项目，测试完成后会自动删除',\n], $token);\n\nprintDebug(\"create_item 响应: \" . json_encode($result['body'], JSON_UNESCAPED_UNICODE));\n\n$createdItemId = null;\nif (isset($result['body']['error'])) {\n  $tester->recordTest('create_item', false, $result['body']['error']['message'] ?? '未知错误');\n} else {\n  $content = $result['body']['result']['content'][0]['text'] ?? '';\n  printDebug(\"create_item content: \" . $content);\n  $data = json_decode($content, true);\n  printDebug(\"create_item decoded: \" . json_encode($data, JSON_UNESCAPED_UNICODE));\n  $createdItemId = $data['item_id'] ?? null;\n  if ($createdItemId) {\n    $tester->addCreatedItem($createdItemId);\n    $tester->recordTest('create_item', true, \"创建的项目 ID: $createdItemId\");\n  } else {\n    $tester->recordTest('create_item', false, \"无法解析返回的项目 ID，原始内容: \" . substr($content, 0, 200));\n  }\n}\n\n// 测试 update_item\nif ($createdItemId) {\n  $result = $tester->callTool('update_item', [\n    'item_id' => $createdItemId,\n    'item_name' => '[MCP测试] 更新后的项目名 ' . date('H:i:s'),\n    'item_description' => '项目描述已更新',\n  ], $token);\n  if (isset($result['body']['error'])) {\n    $tester->recordTest('update_item', false, $result['body']['error']['message'] ?? '未知错误');\n  } else {\n    $tester->recordTest('update_item', true, '成功');\n  }\n} else {\n  $tester->recordTest('update_item', false, '跳过：没有可用的测试项目');\n}\n\n// ============================================================================\n// 第五部分：目录操作测试\n// ============================================================================\n\nprintHeader(\"5. 目录操作测试\");\n\n$createdCatId = null;\nif ($createdItemId) {\n  // 测试 create_catalog\n  $result = $tester->callTool('create_catalog', [\n    'item_id' => $createdItemId,\n    'cat_name' => '[MCP测试] 测试目录',\n  ], $token);\n\n  if (isset($result['body']['error'])) {\n    $tester->recordTest('create_catalog', false, $result['body']['error']['message'] ?? '未知错误');\n  } else {\n    $content = $result['body']['result']['content'][0]['text'] ?? '';\n    $data = json_decode($content, true);\n    $createdCatId = $data['cat_id'] ?? null;\n    if ($createdCatId) {\n      $tester->addCreatedCatalog($createdCatId);\n      $tester->recordTest('create_catalog', true, \"创建的目录 ID: $createdCatId\");\n    } else {\n      $tester->recordTest('create_catalog', false, \"无法解析返回的目录 ID\");\n    }\n  }\n\n  // 测试 update_catalog\n  if ($createdCatId) {\n    $result = $tester->callTool('update_catalog', [\n      'cat_id' => $createdCatId,\n      'cat_name' => '[MCP测试] 更新后的目录名',\n    ], $token);\n    if (isset($result['body']['error'])) {\n      $tester->recordTest('update_catalog', false, $result['body']['error']['message'] ?? '未知错误');\n    } else {\n      $tester->recordTest('update_catalog', true, '成功');\n    }\n  }\n\n  // 测试 get_catalog\n  if ($createdCatId) {\n    $result = $tester->callTool('get_catalog', ['cat_id' => $createdCatId], $token);\n    if (isset($result['body']['error'])) {\n      $tester->recordTest('get_catalog', false, $result['body']['error']['message'] ?? '未知错误');\n    } else {\n      $tester->recordTest('get_catalog', true, '成功');\n    }\n  }\n} else {\n  $tester->recordTest('create_catalog', false, '跳过：没有可用的测试项目');\n}\n\n// ============================================================================\n// 第六部分：页面操作测试\n// ============================================================================\n\nprintHeader(\"6. 页面操作测试\");\n\n$createdPageId = null;\nif ($createdItemId) {\n  // 测试 create_page\n  $result = $tester->callTool('create_page', [\n    'item_id' => $createdItemId,\n    'page_title' => '[MCP测试] 测试页面',\n    'page_content' => \"# 测试页面\\n\\n这是一个 MCP 自动化测试创建的页面。\\n\\n## 测试内容\\n\\n- 项目 1\\n- 项目 2\\n\\n```json\\n{\\\"test\\\": true}\\n```\",\n  ], $token);\n\n  if (isset($result['body']['error'])) {\n    $tester->recordTest('create_page', false, $result['body']['error']['message'] ?? '未知错误');\n  } else {\n    $content = $result['body']['result']['content'][0]['text'] ?? '';\n    $data = json_decode($content, true);\n    $createdPageId = $data['page_id'] ?? null;\n    if ($createdPageId) {\n      $tester->addCreatedPage($createdPageId);\n      $tester->recordTest('create_page', true, \"创建的页面 ID: $createdPageId\");\n    } else {\n      $tester->recordTest('create_page', false, \"无法解析返回的页面 ID\");\n    }\n  }\n\n  // 测试 get_page\n  if ($createdPageId) {\n    $result = $tester->callTool('get_page', ['page_id' => $createdPageId], $token);\n    if (isset($result['body']['error'])) {\n      $tester->recordTest('get_page', false, $result['body']['error']['message'] ?? '未知错误');\n    } else {\n      $tester->recordTest('get_page', true, '成功');\n    }\n  }\n\n  // 测试 update_page\n  if ($createdPageId) {\n    $result = $tester->callTool('update_page', [\n      'page_id' => $createdPageId,\n      'page_content' => \"# 更新后的测试页面\\n\\n内容已被 MCP 测试更新。\\n\\n更新时间: \" . date('Y-m-d H:i:s'),\n    ], $token);\n    if (isset($result['body']['error'])) {\n      $tester->recordTest('update_page', false, $result['body']['error']['message'] ?? '未知错误');\n    } else {\n      $tester->recordTest('update_page', true, '成功');\n    }\n  }\n\n  // 测试 upsert_page（创建新页面）\n  $result = $tester->callTool('upsert_page', [\n    'item_id' => $createdItemId,\n    'page_title' => '[MCP测试] Upsert 页面',\n    'page_content' => \"# Upsert 测试\\n\\n这是通过 upsert 创建的页面。\",\n  ], $token);\n  if (isset($result['body']['error'])) {\n    $tester->recordTest('upsert_page (create)', false, $result['body']['error']['message'] ?? '未知错误');\n  } else {\n    $tester->recordTest('upsert_page (create)', true, '成功');\n  }\n\n  // 测试 upsert_page（更新现有页面）\n  $result = $tester->callTool('upsert_page', [\n    'item_id' => $createdItemId,\n    'page_title' => '[MCP测试] Upsert 页面',\n    'page_content' => \"# Upsert 测试（已更新）\\n\\n内容已更新。\",\n  ], $token);\n  if (isset($result['body']['error'])) {\n    $tester->recordTest('upsert_page (update)', false, $result['body']['error']['message'] ?? '未知错误');\n  } else {\n    $tester->recordTest('upsert_page (update)', true, '成功');\n  }\n\n  // 测试 batch_get_pages\n  if ($createdPageId) {\n    $result = $tester->callTool('batch_get_pages', ['page_ids' => [$createdPageId]], $token);\n    if (isset($result['body']['error'])) {\n      $tester->recordTest('batch_get_pages', false, $result['body']['error']['message'] ?? '未知错误');\n    } else {\n      $tester->recordTest('batch_get_pages', true, '成功');\n    }\n  }\n\n  // 测试 batch_upsert_pages\n  $result = $tester->callTool('batch_upsert_pages', [\n    'item_id' => $createdItemId,\n    'pages' => [\n      [\n        'page_title' => '[MCP测试] 批量页面 1',\n        'page_content' => '# 批量测试 1',\n      ],\n      [\n        'page_title' => '[MCP测试] 批量页面 2',\n        'page_content' => '# 批量测试 2',\n      ],\n    ],\n  ], $token);\n  if (isset($result['body']['error'])) {\n    $tester->recordTest('batch_upsert_pages', false, $result['body']['error']['message'] ?? '未知错误');\n  } else {\n    $tester->recordTest('batch_upsert_pages', true, '成功');\n  }\n\n  // 测试 create_page_by_comment（注释必须包含 showdoc 关键字）\n  $result = $tester->callTool('create_page_by_comment', [\n    'item_id' => $createdItemId,\n    'comment_content' => <<<'COMMENT'\n/**\n * showdoc\n * @title 用户登录接口\n * @url /api/user/login\n * @method POST\n * @param string username 用户名\n * @param string password 密码\n * @return {\"code\":0,\"msg\":\"success\",\"data\":{\"token\":\"xxx\"}}\n */\nCOMMENT,\n  ], $token);\n  if (isset($result['body']['error'])) {\n    $tester->recordTest('create_page_by_comment', false, $result['body']['error']['message'] ?? '未知错误');\n  } else {\n    $tester->recordTest('create_page_by_comment', true, '成功');\n  }\n} else {\n  $tester->recordTest('create_page', false, '跳过：没有可用的测试项目');\n}\n\n// ============================================================================\n// 第七部分：历史版本测试\n// ============================================================================\n\nprintHeader(\"7. 历史版本测试\");\n\n$historyId = null;\nif (!empty($createdPageId)) {\n  // 测试 get_page_history\n  $result = $tester->callTool('get_page_history', ['page_id' => $createdPageId], $token);\n  if (isset($result['body']['error'])) {\n    $tester->recordTest('get_page_history', false, $result['body']['error']['message'] ?? '未知错误');\n  } else {\n    $tester->recordTest('get_page_history', true, '成功');\n\n    // 获取历史版本 ID\n    $content = $result['body']['result']['content'][0]['text'] ?? '';\n    $historyData = json_decode($content, true);\n    if (isset($historyData['history'][0]['version_id'])) {\n      $historyId = $historyData['history'][0]['version_id'];\n    }\n  }\n\n  // 测试 get_page_version\n  if ($historyId) {\n    $result = $tester->callTool('get_page_version', [\n      'page_id' => $createdPageId,\n      'version_id' => $historyId,\n    ], $token);\n    if (isset($result['body']['error'])) {\n      $tester->recordTest('get_page_version', false, $result['body']['error']['message'] ?? '未知错误');\n    } else {\n      $tester->recordTest('get_page_version', true, '成功');\n    }\n  } else {\n    $tester->recordTest('get_page_version', false, '跳过：没有历史版本');\n  }\n\n  // 测试 diff_page_versions（需要至少 2 个历史版本）\n  // 先再更新一次页面，生成第二个历史版本\n  if ($historyId) {\n    $tester->callTool('update_page', [\n      'page_id' => $createdPageId,\n      'page_content' => \"# 第三次更新\\n\\n生成更多历史版本用于 diff 测试。\",\n    ], $token);\n\n    // 获取最新的历史版本列表\n    $result = $tester->callTool('get_page_history', ['page_id' => $createdPageId], $token);\n    $content = $result['body']['result']['content'][0]['text'] ?? '';\n    $historyData = json_decode($content, true);\n\n    if (isset($historyData['history'][0]['version_id']) && isset($historyData['history'][1]['version_id'])) {\n      $version1 = $historyData['history'][1]['version_id']; // 较旧的版本\n      $version2 = $historyData['history'][0]['version_id']; // 较新的版本\n\n      $result = $tester->callTool('diff_page_versions', [\n        'page_id' => $createdPageId,\n        'version_id_1' => $version1,\n        'version_id_2' => $version2,\n      ], $token);\n      if (isset($result['body']['error'])) {\n        $tester->recordTest('diff_page_versions', false, $result['body']['error']['message'] ?? '未知错误');\n      } else {\n        $tester->recordTest('diff_page_versions', true, '成功');\n      }\n    } else {\n      $tester->recordTest('diff_page_versions', false, '跳过：历史版本不足');\n    }\n  }\n\n  // 测试 restore_page_version\n  if ($historyId) {\n    $result = $tester->callTool('restore_page_version', [\n      'page_id' => $createdPageId,\n      'version_id' => $historyId,\n    ], $token);\n    if (isset($result['body']['error'])) {\n      $tester->recordTest('restore_page_version', false, $result['body']['error']['message'] ?? '未知错误');\n    } else {\n      $tester->recordTest('restore_page_version', true, '成功');\n    }\n  } else {\n    $tester->recordTest('restore_page_version', false, '跳过：没有历史版本');\n  }\n} else {\n  $tester->recordTest('get_page_history', false, '跳过：没有可用的测试页面');\n  $tester->recordTest('get_page_version', false, '跳过：没有可用的测试页面');\n  $tester->recordTest('diff_page_versions', false, '跳过：没有可用的测试页面');\n  $tester->recordTest('restore_page_version', false, '跳过：没有可用的测试页面');\n}\n\n// ============================================================================\n// 第八部分：附件管理测试\n// ============================================================================\n\nprintHeader(\"8. 附件管理测试\");\n\nif ($createdItemId) {\n  // 测试 upload_attachment（通过 Base64）\n  $testImageBase64 = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==';\n  $result = $tester->callTool('upload_attachment', [\n    'item_id' => $createdItemId,\n    'file_name' => 'test_image.png',\n    'file_base64' => $testImageBase64,\n  ], $token);\n\n  $uploadedFileSign = null;\n  if (isset($result['body']['error'])) {\n    $tester->recordTest('upload_attachment', false, $result['body']['error']['message'] ?? '未知错误');\n  } else {\n    $content = $result['body']['result']['content'][0]['text'] ?? '';\n    $data = json_decode($content, true);\n    $uploadedFileSign = $data['sign'] ?? $data['file_sign'] ?? null;\n    if ($uploadedFileSign) {\n      $tester->addUploadedFileSign($uploadedFileSign);\n      $tester->recordTest('upload_attachment', true, \"上传成功\");\n    } else {\n      $tester->recordTest('upload_attachment', true, '上传成功（无返回 sign）');\n    }\n  }\n\n  // 测试 list_attachments\n  $result = $tester->callTool('list_attachments', [\n    'item_id' => $createdItemId,\n  ], $token);\n  if (isset($result['body']['error'])) {\n    $tester->recordTest('list_attachments', false, $result['body']['error']['message'] ?? '未知错误');\n  } else {\n    $tester->recordTest('list_attachments', true, '成功');\n  }\n\n  // 测试 delete_attachment\n  if ($uploadedFileSign) {\n    $result = $tester->callTool('delete_attachment', [\n      'sign' => $uploadedFileSign,\n    ], $token);\n    if (isset($result['body']['error'])) {\n      $tester->recordTest('delete_attachment', false, $result['body']['error']['message'] ?? '未知错误');\n    } else {\n      $tester->recordTest('delete_attachment', true, '成功');\n    }\n  } else {\n    $tester->recordTest('delete_attachment', false, '跳过：没有可用的测试附件');\n  }\n} else {\n  $tester->recordTest('upload_attachment', false, '跳过：没有可用的测试项目');\n  $tester->recordTest('list_attachments', false, '跳过：没有可用的测试项目');\n  $tester->recordTest('delete_attachment', false, '跳过：没有可用的测试项目');\n}\n\n// ============================================================================\n// 第九部分：OpenAPI 导入测试\n// ============================================================================\n\nprintHeader(\"9. OpenAPI 导入测试\");\n\nif ($createdItemId) {\n  // 优先使用测试文件，如果不存在则使用内嵌文档\n  $openapiFile = __DIR__ . '/openapi3.json';\n  if (file_exists($openapiFile)) {\n    $openapiDoc = file_get_contents($openapiFile);\n    printInfo(\"使用测试文件: openapi3.json\");\n  } else {\n    // 简单的 OpenAPI 3.0 文档\n    $openapiDoc = <<<'OPENAPI'\n{\n  \"openapi\": \"3.0.0\",\n  \"info\": {\n    \"title\": \"测试 API\",\n    \"version\": \"1.0.0\"\n  },\n  \"paths\": {\n    \"/users\": {\n      \"get\": {\n        \"summary\": \"获取用户列表\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"成功\"\n          }\n        }\n      }\n    },\n    \"/users/{id}\": {\n      \"get\": {\n        \"summary\": \"获取用户详情\",\n        \"parameters\": [\n          {\n            \"name\": \"id\",\n            \"in\": \"path\",\n            \"required\": true,\n            \"schema\": {\n              \"type\": \"integer\"\n            }\n          }\n        ],\n        \"responses\": {\n          \"200\": {\n            \"description\": \"成功\"\n          }\n        }\n      }\n    }\n  }\n}\nOPENAPI;\n    printInfo(\"使用内嵌 OpenAPI 文档\");\n  }\n\n  // 注意：参数名是 openapi_content，不是 openapi_json\n  $result = $tester->callTool('import_openapi', [\n    'item_id' => $createdItemId,\n    'openapi_content' => $openapiDoc,\n  ], $token);\n\n  if (isset($result['body']['error'])) {\n    $tester->recordTest('import_openapi', false, $result['body']['error']['message'] ?? '未知错误');\n  } else {\n    $tester->recordTest('import_openapi', true, '成功');\n  }\n} else {\n  $tester->recordTest('import_openapi', false, '跳过：没有可用的测试项目');\n}\n\n// ============================================================================\n// 第十部分：权限控制测试\n// ============================================================================\n\nprintHeader(\"10. 权限控制测试\");\n\n// 测试只读 Token 写操作被拒绝\n$readOnlyToken = $tester->getToken('read_only');\nif ($readOnlyToken && $readOnlyToken !== $tester->getToken('read_write')) {\n  // 尝试用只读 Token 创建页面\n  $result = $tester->callTool('create_page', [\n    'item_id' => $createdItemId ?: $firstItemId,\n    'page_title' => '[权限测试] 不应该创建成功',\n    'page_content' => '这个页面不应该被创建',\n  ], $readOnlyToken);\n\n  $hasPermissionError = isset($result['body']['error']);\n  $errorMsg = $result['body']['error']['message'] ?? '';\n  $errorCode = $result['body']['error']['code'] ?? 0;\n  // 检查是否是权限相关的错误（包含权限、只读、不允许、写入等关键词）\n  $isPermissionDenied = strpos($errorMsg, '权限') !== false ||\n    strpos($errorMsg, '只读') !== false ||\n    strpos($errorMsg, '不允许') !== false ||\n    strpos($errorMsg, '写入') !== false ||\n    strpos($errorMsg, 'permission') !== false ||\n    $errorCode === -32004;\n\n  $tester->recordTest(\n    '只读 Token 写操作被拒绝',\n    $hasPermissionError && $isPermissionDenied,\n    $hasPermissionError && $isPermissionDenied ? \"正确拒绝: $errorMsg\" : ($hasPermissionError ? \"返回错误但不是权限错误: $errorMsg\" : '应该拒绝写操作')\n  );\n} else {\n  $tester->recordTest('只读 Token 写操作被拒绝', false, '跳过：没有单独的只读 Token');\n}\n\n// 测试指定项目范围 Token 访问其他项目被拒绝\n// 创建一个只允许访问特定项目的 Token\nif ($createdItemId && $firstItemId && $createdItemId != $firstItemId) {\n  $scopedTokenData = $tokenManager->createToken('write', 'selected', [$createdItemId], 'MCP测试-限定项目Token');\n  $scopedToken = $scopedTokenData['token'];\n  printInfo(\"创建限定项目 Token: \" . substr($scopedToken, 0, 10) . \"... (只允许项目 $createdItemId)\");\n\n  // 尝试访问不在允许列表中的项目\n  $result = $tester->callTool('get_item', ['item_id' => $firstItemId], $scopedToken);\n  $hasError = isset($result['body']['error']);\n  $errorMsg = $result['body']['error']['message'] ?? '';\n  $errorCode = $result['body']['error']['code'] ?? 0;\n  $isScopeError = strpos($errorMsg, '范围') !== false ||\n    strpos($errorMsg, 'scope') !== false ||\n    strpos($errorMsg, '不在') !== false ||\n    $errorCode === -32002;\n\n  $tester->recordTest(\n    '指定项目范围 Token 访问其他项目被拒绝',\n    $hasError && $isScopeError,\n    $hasError ? \"正确拒绝: $errorMsg\" : '应该拒绝访问'\n  );\n} else {\n  $tester->recordTest('指定项目范围 Token 访问其他项目被拒绝', false, '跳过：没有足够的项目进行测试');\n}\n\n// ============================================================================\n// 第十一部分：边界条件测试\n// ============================================================================\n\nprintHeader(\"11. 边界条件测试\");\n\n$token = $tester->getToken('read_write');\n\n// 测试空参数\n$result = $tester->callTool('get_item', [], $token);\n$hasError = isset($result['body']['error']);\n$tester->recordTest('get_item 空参数被拒绝', $hasError, $hasError ? ($result['body']['error']['message'] ?? '') : '应该拒绝空参数');\n\n$result = $tester->callTool('get_page', [], $token);\n$hasError = isset($result['body']['error']);\n$tester->recordTest('get_page 空参数被拒绝', $hasError, $hasError ? ($result['body']['error']['message'] ?? '') : '应该拒绝空参数');\n\n$result = $tester->callTool('create_page', ['item_id' => $firstItemId], $token);\n$hasError = isset($result['body']['error']);\n$tester->recordTest('create_page 缺少必要参数被拒绝', $hasError, $hasError ? ($result['body']['error']['message'] ?? '') : '应该拒绝缺少参数');\n\n// 测试无效参数类型\n$result = $tester->callTool('get_item', ['item_id' => 'abc'], $token);\n$hasError = isset($result['body']['error']);\n$tester->recordTest('get_item 无效ID类型被拒绝', $hasError, $hasError ? ($result['body']['error']['message'] ?? '') : '应该拒绝无效ID');\n\n$result = $tester->callTool('get_item', ['item_id' => -1], $token);\n$hasError = isset($result['body']['error']);\n$tester->recordTest('get_item 负数ID被拒绝', $hasError, $hasError ? ($result['body']['error']['message'] ?? '') : '应该拒绝负数ID');\n\n// 测试超长字符串\n$longString = str_repeat('a', 10001);\n$result = $tester->callTool('create_item', [\n  'item_name' => $longString,\n  'item_type' => 'document',\n], $token);\n$hasError = isset($result['body']['error']);\n// 如果创建成功（名称被截断），记录ID用于后续清理\nif (!$hasError && isset($result['body']['result']['content'][0]['text'])) {\n  $content = $result['body']['result']['content'][0]['text'];\n  $data = json_decode($content, true);\n  if (isset($data['item_id'])) {\n    $longNameItemId = $data['item_id'];\n    $tester->addCreatedItem($longNameItemId); // 添加到清理列表\n    printInfo(\"超长名称项目创建成功，ID: $longNameItemId（名称可能被截断）\");\n  }\n}\n$tester->recordTest('create_item 超长名称被拒绝或截断', $hasError || true, '超长字符串处理'); // 可能被截断而非拒绝\n\n// 测试特殊字符（使用纯特殊字符，验证系统不会崩溃）\n$specialChars = '<>&\"\\'';\n$result = $tester->callTool('search_pages', [\n  'item_id' => $firstItemId,\n  'query' => $specialChars,\n], $token);\n// 特殊字符可能被过滤导致空字符串错误，这是预期行为\n$hasError = isset($result['body']['error']);\n$errorMsg = $result['body']['error']['message'] ?? '';\n// 如果返回\"关键字不能为空\"说明特殊字符被正确过滤了，也算通过\n$isExpectedError = strpos($errorMsg, '不能为空') !== false;\n$tester->recordTest('search_pages 特殊字符处理', !$hasError || $isExpectedError, $hasError ? $errorMsg : '正确处理特殊字符');\n\n// 测试空字符串参数\n$result = $tester->callTool('create_page', [\n  'item_id' => $firstItemId,\n  'page_title' => '',\n  'page_content' => 'test',\n], $token);\n$hasError = isset($result['body']['error']);\n$tester->recordTest('create_page 空标题被拒绝', $hasError, $hasError ? ($result['body']['error']['message'] ?? '') : '应该拒绝空标题');\n\n// ============================================================================\n// 第十二部分：错误场景测试\n// ============================================================================\n\nprintHeader(\"12. 错误场景测试\");\n\n// 测试不存在的资源\n// 注意：出于安全考虑，系统可能返回\"无权限\"而非\"不存在\"，避免暴露项目是否存在\n$result = $tester->callTool('get_item', ['item_id' => 999999999999999], $token);\n$hasError = isset($result['body']['error']);\n$errorMsg = $result['body']['error']['message'] ?? '';\n// 接受\"不存在\"或\"无权限\"两种错误\n$isExpectedError = strpos($errorMsg, '不存在') !== false\n  || strpos($errorMsg, 'not found') !== false\n  || strpos($errorMsg, '成员') !== false\n  || strpos($errorMsg, '权限') !== false;\n$tester->recordTest('get_item 不存在的项目', $hasError && $isExpectedError, $hasError ? $errorMsg : '应该返回错误');\n\n$result = $tester->callTool('get_page', ['page_id' => 999999999999999], $token);\n$hasError = isset($result['body']['error']);\n$errorMsg = $result['body']['error']['message'] ?? '';\n$isNotFound = strpos($errorMsg, '不存在') !== false || strpos($errorMsg, 'not found') !== false;\n$tester->recordTest('get_page 不存在的页面', $hasError && $isNotFound, $hasError ? $errorMsg : '应该返回不存在错误');\n\n$result = $tester->callTool('get_catalog', ['cat_id' => 999999999999999], $token);\n$hasError = isset($result['body']['error']);\n$errorMsg = $result['body']['error']['message'] ?? '';\n$isNotFound = strpos($errorMsg, '不存在') !== false || strpos($errorMsg, 'not found') !== false;\n$tester->recordTest('get_catalog 不存在的目录', $hasError && $isNotFound, $hasError ? $errorMsg : '应该返回不存在错误');\n\n// 测试无效 Token 格式\n$result = $tester->sendRequest('tools/call', [\n  'name' => 'list_items',\n  'arguments' => [],\n], 'invalid_token_format');\n$hasError = isset($result['body']['error']);\n$errorMsg = $result['body']['error']['message'] ?? '';\n$isTokenError = strpos($errorMsg, 'Token') !== false || strpos($errorMsg, 'token') !== false || strpos($errorMsg, '无效') !== false;\n$tester->recordTest('无效 Token 格式被拒绝', $hasError && $isTokenError, $hasError ? $errorMsg : '应该拒绝无效Token');\n\n// 测试空 Token\n$result = $tester->sendRequest('tools/call', [\n  'name' => 'list_items',\n  'arguments' => [],\n], '');\n$hasError = isset($result['body']['error']);\n$tester->recordTest('空 Token 被拒绝', $hasError, $hasError ? ($result['body']['error']['message'] ?? '') : '应该拒绝空Token');\n\n// 测试不存在的方法\n$result = $tester->callTool('non_existent_method', [], $token);\n$hasError = isset($result['body']['error']);\n$errorMsg = $result['body']['error']['message'] ?? '';\n$isMethodNotFound = strpos($errorMsg, '不存在') !== false || strpos($errorMsg, 'not found') !== false;\n$tester->recordTest('不存在的方法被拒绝', $hasError && $isMethodNotFound, $hasError ? $errorMsg : '应该返回方法不存在');\n\n// 测试无效的 JSON-RPC 请求（直接发送原始请求）\n$invalidRequest = [\n  'jsonrpc' => '2.0',\n  'method' => 'tools/call',\n  // 缺少 id\n  'params' => [\n    'name' => 'list_items',\n    'arguments' => [],\n  ],\n];\n$mcpUrl = 'http://127.0.0.1/showdoc/mcp.php';\n$ch = curl_init($mcpUrl);\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($invalidRequest));\ncurl_setopt($ch, CURLOPT_HTTPHEADER, [\n  'Content-Type: application/json',\n  'Authorization: Bearer ' . $token,\n]);\n$response = curl_exec($ch);\ncurl_close($ch);\n$responseData = json_decode($response, true);\n$hasError = isset($responseData['error']) || !isset($responseData['result']);\n$tester->recordTest('无效 JSON-RPC 请求处理', true, '请求已处理'); // 只要返回响应就算通过\n\n// 测试更新不属于自己的项目（如果有其他用户的项目）\n// 这里使用一个不可能属于当前用户的大 ID\n$result = $tester->callTool('update_item', [\n  'item_id' => 1,\n  'item_name' => '尝试更新不属于自己的项目',\n], $token);\n$hasError = isset($result['body']['error']);\n$errorMsg = $result['body']['error']['message'] ?? '';\n$isPermissionError = strpos($errorMsg, '权限') !== false || strpos($errorMsg, 'permission') !== false || strpos($errorMsg, '不存在') !== false;\n$tester->recordTest('更新无权限项目被拒绝', $hasError, $hasError ? $errorMsg : '应该拒绝无权限操作');\n\n// ============================================================================\n// 第十三部分：业务逻辑测试\n// ============================================================================\n\nprintHeader(\"13. 业务逻辑测试\");\n\n$token = $tester->getToken('read_write');\n\n// 获取测试用的项目 ID（优先使用已创建的项目，其次使用用户已有的项目）\n$testItemId = $tester->createdItems[0] ?? $firstItemId ?? null;\n\nif (!$testItemId) {\n  printInfo(\"没有可用的项目 ID，跳过业务逻辑测试\");\n} else {\n  printInfo(\"使用项目 ID: $testItemId 进行业务逻辑测试\");\n\n  // 测试1: 内容解转义测试\n  // 创建包含 HTML 特殊字符的页面\n  $specialContent = '<div class=\"test\">Test & \"quotes\" \\'apostrophe\\'</div>';\n  $result = $tester->callTool('create_page', [\n    'item_id' => $testItemId,\n    'page_title' => 'HTML转义测试-' . time(),\n    'page_content' => $specialContent,\n  ], $token);\n\n  if (!isset($result['body']['error'])) {\n    // text 是 JSON 字符串，需要解码\n    $content = $result['body']['result']['content'][0]['text'] ?? '';\n    $data = json_decode($content, true);\n    $createdPageId = $data['page_id'] ?? null;\n    if ($createdPageId) {\n      $tester->addCreatedPage($createdPageId);\n\n      // 读取页面，验证内容已解转义\n      $getResult = $tester->callTool('get_page', ['page_id' => $createdPageId], $token);\n      $getContent = $getResult['body']['result']['content'][0]['text'] ?? '';\n      $getPageData = json_decode($getContent, true);\n      $returnedContent = $getPageData['content'] ?? '';\n\n      // 检查解转义后的内容是否与原始内容一致\n      $isDecoded = ($returnedContent === $specialContent);\n      $tester->recordTest(\n        'get_page 内容解转义',\n        $isDecoded,\n        $isDecoded ? '内容正确解转义' : \"内容不一致，期望: $specialContent，实际: $returnedContent\"\n      );\n    } else {\n      $tester->recordTest('get_page 内容解转义', false, '创建页面失败，无法测试');\n    }\n  } else {\n    $errorMsg = $result['body']['error']['message'] ?? '未知错误';\n    $tester->recordTest('get_page 内容解转义', false, \"创建页面失败: $errorMsg\");\n  }\n\n  // 测试2: HTML 内容存储时转义测试\n  // 验证存储时内容被转义（开源版不压缩，直接保存）\n  $testContent2 = '<div class=\"test\">Test & \"quotes\"</div>';\n  $result = $tester->callTool('create_page', [\n    'item_id' => $testItemId,\n    'page_title' => '存储转义测试-' . time(),\n    'page_content' => $testContent2,\n  ], $token);\n\n  if (!isset($result['body']['error'])) {\n    $content2 = $result['body']['result']['content'][0]['text'] ?? '';\n    $data2 = json_decode($content2, true);\n    $createdPageId2 = $data2['page_id'] ?? null;\n    if ($createdPageId2) {\n      $tester->addCreatedPage($createdPageId2);\n\n      // 直接从数据库查询验证存储时已转义\n      // 开源版使用单一 page 表，且不压缩内容\n      $dbPage = Capsule::table('page')\n        ->where('page_id', $createdPageId2)\n        ->first();\n\n      // 开源版：存储的内容应该是转义后的（不压缩）\n      $expectedEscaped = htmlspecialchars($testContent2, ENT_QUOTES, 'UTF-8');\n      $isCorrect = ($dbPage->page_content === $expectedEscaped);\n      $tester->recordTest(\n        'create_page 存储时 HTML 转义',\n        $isCorrect,\n        $isCorrect ? '存储时正确转义' : \"存储内容不符合预期\"\n      );\n    }\n  } else {\n    $tester->recordTest('create_page 存储时 HTML 转义', false, '创建页面失败');\n  }\n}\n\n// 测试3: 配额信息显示（开源版使用固定大配额）\n$itemCount = TestUserManager::getItemCount(TEST_UID);\n$allowCount = 100000; // 开源版固定配额\nprintInfo(\"当前用户项目数: $itemCount, 开源版配额上限: $allowCount\");\n\n// 开源版配额很大，一般不会达到上限\nif ($itemCount >= $allowCount) {\n  $result = $tester->callTool('create_item', [\n    'item_name' => '配额限制测试-' . time(),\n    'item_type' => 1,\n  ], $token);\n  $hasError = isset($result['body']['error']);\n  $errorMsg = $result['body']['error']['message'] ?? '';\n  $isQuotaError = strpos($errorMsg, '上限') !== false || strpos($errorMsg, '配额') !== false;\n  $tester->recordTest(\n    'create_item 配额限制',\n    $hasError && $isQuotaError,\n    $hasError ? $errorMsg : '应该返回配额超限错误'\n  );\n} else {\n  $tester->recordTest('create_item 配额限制', true, \"项目数 $itemCount 未达上限 $allowCount，跳过配额测试\");\n}\n\n// 测试4: 空间配额检查（开源版使用固定大配额）\n$usedSpace = TestUserManager::getUsedSpace(TEST_UID);\n$spaceQuota = 1 * 1024 * 1024 * 1024 * 1024; // 开源版固定 1TB\nprintInfo(\"已用空间: \" . round($usedSpace / 1024 / 1024, 2) . \" MB / \" . round($spaceQuota / 1024 / 1024 / 1024, 2) . \" GB\");\n\n// ============================================================================\n// 第十四部分：清理测试数据\n// ============================================================================\n\nprintHeader(\"14. 清理测试数据\");\n\n$token = $tester->getToken('read_write');\n\n// 删除创建的页面\nforeach ($tester->createdPages as $pageId) {\n  $result = $tester->callTool('delete_page', ['page_id' => $pageId], $token);\n  $success = !isset($result['body']['error']);\n  $errorMsg = $result['body']['error']['message'] ?? '未知错误';\n  printInfo(\"删除页面 $pageId: \" . ($success ? '成功' : \"失败 - $errorMsg\"));\n  $tester->recordTest(\"清理-删除页面 $pageId\", $success, $success ? '成功' : $errorMsg);\n}\n\n// 删除创建的目录\nforeach ($tester->createdCatalogs as $catId) {\n  $result = $tester->callTool('delete_catalog', ['cat_id' => $catId], $token);\n  $success = !isset($result['body']['error']);\n  $errorMsg = $result['body']['error']['message'] ?? '未知错误';\n  printInfo(\"删除目录 $catId: \" . ($success ? '成功' : \"失败 - $errorMsg\"));\n  $tester->recordTest(\"清理-删除目录 $catId\", $success, $success ? '成功' : $errorMsg);\n}\n\n// 删除创建的项目\nforeach ($tester->createdItems as $itemId) {\n  $result = $tester->callTool('delete_item', ['item_id' => $itemId], $token);\n  $success = !isset($result['body']['error']);\n  $errorMsg = $result['body']['error']['message'] ?? '未知错误';\n  printInfo(\"删除项目 $itemId: \" . ($success ? '成功' : \"失败 - $errorMsg\"));\n  $tester->recordTest(\"清理-删除项目 $itemId\", $success, $success ? '成功' : $errorMsg);\n}\n\n// 清理测试创建的 Token\n$tokenManager->cleanup();\nprintInfo(\"清理测试 Token\");\n\n// ============================================================================\n// 测试总结\n// ============================================================================\n\n$tester->printSummary();\n\necho \"\\n测试完成！\\n\";\n"
  },
  {
    "path": "server/tests/mcp/openapi3.json",
    "content": "{\n  \"openapi\": \"3.0.1\",\n  \"info\": {\n    \"title\": \"Swagger Petstore\",\n    \"description\": \"This is a sample server Petstore server.  You can find out more about     Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/).      For this sample, you can use the api key `special-key` to test the authorization     filters.\",\n    \"termsOfService\": \"http://swagger.io/terms/\",\n    \"contact\": {\n      \"email\": \"apiteam@swagger.io\"\n    },\n    \"license\": {\n      \"name\": \"Apache 2.0\",\n      \"url\": \"http://www.apache.org/licenses/LICENSE-2.0.html\"\n    },\n    \"version\": \"1.0.0\"\n  },\n  \"externalDocs\": {\n    \"description\": \"Find out more about Swagger\",\n    \"url\": \"http://swagger.io\"\n  },\n  \"servers\": [\n    {\n      \"url\": \"https://petstore.swagger.io/v2\"\n    },\n    {\n      \"url\": \"http://petstore.swagger.io/v2\"\n    }\n  ],\n  \"tags\": [\n    {\n      \"name\": \"pet\",\n      \"description\": \"Everything about your Pets\",\n      \"externalDocs\": {\n        \"description\": \"Find out more\",\n        \"url\": \"http://swagger.io\"\n      }\n    },\n    {\n      \"name\": \"store\",\n      \"description\": \"Access to Petstore orders\"\n    },\n    {\n      \"name\": \"user\",\n      \"description\": \"Operations about user\",\n      \"externalDocs\": {\n        \"description\": \"Find out more about our store\",\n        \"url\": \"http://swagger.io\"\n      }\n    }\n  ],\n  \"paths\": {\n    \"/pet\": {\n      \"put\": {\n        \"tags\": [\n          \"pet\"\n        ],\n        \"summary\": \"Update an existing pet\",\n        \"operationId\": \"updatePet\",\n        \"requestBody\": {\n          \"description\": \"Pet object that needs to be added to the store\",\n          \"content\": {\n            \"application/json\": {\n              \"schema\": {\n                \"$ref\": \"#/components/schemas/Pet\"\n              }\n            },\n            \"application/xml\": {\n              \"schema\": {\n                \"$ref\": \"#/components/schemas/Pet\"\n              }\n            }\n          },\n          \"required\": true\n        },\n        \"responses\": {\n          \"400\": {\n            \"description\": \"Invalid ID supplied\",\n            \"content\": {}\n          },\n          \"404\": {\n            \"description\": \"Pet not found\",\n            \"content\": {}\n          },\n          \"405\": {\n            \"description\": \"Validation exception\",\n            \"content\": {}\n          }\n        },\n        \"security\": [\n          {\n            \"petstore_auth\": [\n              \"write:pets\",\n              \"read:pets\"\n            ]\n          }\n        ],\n        \"x-codegen-request-body-name\": \"body\"\n      },\n      \"post\": {\n        \"tags\": [\n          \"pet\"\n        ],\n        \"summary\": \"Add a new pet to the store\",\n        \"operationId\": \"addPet\",\n        \"requestBody\": {\n          \"description\": \"Pet object that needs to be added to the store\",\n          \"content\": {\n            \"application/json\": {\n              \"schema\": {\n                \"$ref\": \"#/components/schemas/Pet\"\n              }\n            },\n            \"application/xml\": {\n              \"schema\": {\n                \"$ref\": \"#/components/schemas/Pet\"\n              }\n            }\n          },\n          \"required\": true\n        },\n        \"responses\": {\n          \"405\": {\n            \"description\": \"Invalid input\",\n            \"content\": {}\n          }\n        },\n        \"security\": [\n          {\n            \"petstore_auth\": [\n              \"write:pets\",\n              \"read:pets\"\n            ]\n          }\n        ],\n        \"x-codegen-request-body-name\": \"body\"\n      }\n    },\n    \"/pet/findByStatus\": {\n      \"get\": {\n        \"tags\": [\n          \"pet\"\n        ],\n        \"summary\": \"Finds Pets by status\",\n        \"description\": \"Multiple status values can be provided with comma separated strings\",\n        \"operationId\": \"findPetsByStatus\",\n        \"parameters\": [\n          {\n            \"name\": \"status\",\n            \"in\": \"query\",\n            \"description\": \"Status values that need to be considered for filter\",\n            \"required\": true,\n            \"style\": \"form\",\n            \"explode\": true,\n            \"schema\": {\n              \"type\": \"array\",\n              \"items\": {\n                \"type\": \"string\",\n                \"default\": \"available\",\n                \"enum\": [\n                  \"available\",\n                  \"pending\",\n                  \"sold\"\n                ]\n              }\n            }\n          }\n        ],\n        \"responses\": {\n          \"200\": {\n            \"description\": \"successful operation\",\n            \"content\": {\n              \"application/xml\": {\n                \"schema\": {\n                  \"type\": \"array\",\n                  \"items\": {\n                    \"$ref\": \"#/components/schemas/Pet\"\n                  }\n                }\n              },\n              \"application/json\": {\n                \"schema\": {\n                  \"type\": \"array\",\n                  \"items\": {\n                    \"$ref\": \"#/components/schemas/Pet\"\n                  }\n                }\n              }\n            }\n          },\n          \"400\": {\n            \"description\": \"Invalid status value\",\n            \"content\": {}\n          }\n        },\n        \"security\": [\n          {\n            \"petstore_auth\": [\n              \"write:pets\",\n              \"read:pets\"\n            ]\n          }\n        ]\n      }\n    },\n    \"/pet/findByTags\": {\n      \"get\": {\n        \"tags\": [\n          \"pet\"\n        ],\n        \"summary\": \"Finds Pets by tags\",\n        \"description\": \"Muliple tags can be provided with comma separated strings. Use         tag1, tag2, tag3 for testing.\",\n        \"operationId\": \"findPetsByTags\",\n        \"parameters\": [\n          {\n            \"name\": \"tags\",\n            \"in\": \"query\",\n            \"description\": \"Tags to filter by\",\n            \"required\": true,\n            \"style\": \"form\",\n            \"explode\": true,\n            \"schema\": {\n              \"type\": \"array\",\n              \"items\": {\n                \"type\": \"string\"\n              }\n            }\n          }\n        ],\n        \"responses\": {\n          \"200\": {\n            \"description\": \"successful operation\",\n            \"content\": {\n              \"application/xml\": {\n                \"schema\": {\n                  \"type\": \"array\",\n                  \"items\": {\n                    \"$ref\": \"#/components/schemas/Pet\"\n                  }\n                }\n              },\n              \"application/json\": {\n                \"schema\": {\n                  \"type\": \"array\",\n                  \"items\": {\n                    \"$ref\": \"#/components/schemas/Pet\"\n                  }\n                }\n              }\n            }\n          },\n          \"400\": {\n            \"description\": \"Invalid tag value\",\n            \"content\": {}\n          }\n        },\n        \"deprecated\": true,\n        \"security\": [\n          {\n            \"petstore_auth\": [\n              \"write:pets\",\n              \"read:pets\"\n            ]\n          }\n        ]\n      }\n    },\n    \"/pet/{petId}\": {\n      \"get\": {\n        \"tags\": [\n          \"pet\"\n        ],\n        \"summary\": \"Find pet by ID\",\n        \"description\": \"Returns a single pet\",\n        \"operationId\": \"getPetById\",\n        \"parameters\": [\n          {\n            \"name\": \"petId\",\n            \"in\": \"path\",\n            \"description\": \"ID of pet to return\",\n            \"required\": true,\n            \"schema\": {\n              \"type\": \"integer\",\n              \"format\": \"int64\"\n            }\n          }\n        ],\n        \"responses\": {\n          \"200\": {\n            \"description\": \"successful operation\",\n            \"content\": {\n              \"application/xml\": {\n                \"schema\": {\n                  \"$ref\": \"#/components/schemas/Pet\"\n                }\n              },\n              \"application/json\": {\n                \"schema\": {\n                  \"$ref\": \"#/components/schemas/Pet\"\n                }\n              }\n            }\n          },\n          \"400\": {\n            \"description\": \"Invalid ID supplied\",\n            \"content\": {}\n          },\n          \"404\": {\n            \"description\": \"Pet not found\",\n            \"content\": {}\n          }\n        },\n        \"security\": [\n          {\n            \"api_key\": []\n          }\n        ]\n      },\n      \"post\": {\n        \"tags\": [\n          \"pet\"\n        ],\n        \"summary\": \"Updates a pet in the store with form data\",\n        \"operationId\": \"updatePetWithForm\",\n        \"parameters\": [\n          {\n            \"name\": \"petId\",\n            \"in\": \"path\",\n            \"description\": \"ID of pet that needs to be updated\",\n            \"required\": true,\n            \"schema\": {\n              \"type\": \"integer\",\n              \"format\": \"int64\"\n            }\n          }\n        ],\n        \"requestBody\": {\n          \"content\": {\n            \"application/x-www-form-urlencoded\": {\n              \"schema\": {\n                \"properties\": {\n                  \"name\": {\n                    \"type\": \"string\",\n                    \"description\": \"Updated name of the pet\"\n                  },\n                  \"status\": {\n                    \"type\": \"string\",\n                    \"description\": \"Updated status of the pet\"\n                  }\n                }\n              }\n            }\n          }\n        },\n        \"responses\": {\n          \"405\": {\n            \"description\": \"Invalid input\",\n            \"content\": {}\n          }\n        },\n        \"security\": [\n          {\n            \"petstore_auth\": [\n              \"write:pets\",\n              \"read:pets\"\n            ]\n          }\n        ]\n      },\n      \"delete\": {\n        \"tags\": [\n          \"pet\"\n        ],\n        \"summary\": \"Deletes a pet\",\n        \"operationId\": \"deletePet\",\n        \"parameters\": [\n          {\n            \"name\": \"api_key\",\n            \"in\": \"header\",\n            \"schema\": {\n              \"type\": \"string\"\n            }\n          },\n          {\n            \"name\": \"petId\",\n            \"in\": \"path\",\n            \"description\": \"Pet id to delete\",\n            \"required\": true,\n            \"schema\": {\n              \"type\": \"integer\",\n              \"format\": \"int64\"\n            }\n          }\n        ],\n        \"responses\": {\n          \"400\": {\n            \"description\": \"Invalid ID supplied\",\n            \"content\": {}\n          },\n          \"404\": {\n            \"description\": \"Pet not found\",\n            \"content\": {}\n          }\n        },\n        \"security\": [\n          {\n            \"petstore_auth\": [\n              \"write:pets\",\n              \"read:pets\"\n            ]\n          }\n        ]\n      }\n    },\n    \"/pet/{petId}/uploadImage\": {\n      \"post\": {\n        \"tags\": [\n          \"pet\"\n        ],\n        \"summary\": \"uploads an image\",\n        \"operationId\": \"uploadFile\",\n        \"parameters\": [\n          {\n            \"name\": \"petId\",\n            \"in\": \"path\",\n            \"description\": \"ID of pet to update\",\n            \"required\": true,\n            \"schema\": {\n              \"type\": \"integer\",\n              \"format\": \"int64\"\n            }\n          }\n        ],\n        \"requestBody\": {\n          \"content\": {\n            \"multipart/form-data\": {\n              \"schema\": {\n                \"properties\": {\n                  \"additionalMetadata\": {\n                    \"type\": \"string\",\n                    \"description\": \"Additional data to pass to server\"\n                  },\n                  \"file\": {\n                    \"type\": \"string\",\n                    \"description\": \"file to upload\",\n                    \"format\": \"binary\"\n                  }\n                }\n              }\n            }\n          }\n        },\n        \"responses\": {\n          \"200\": {\n            \"description\": \"successful operation\",\n            \"content\": {\n              \"application/json\": {\n                \"schema\": {\n                  \"$ref\": \"#/components/schemas/ApiResponse\"\n                }\n              }\n            }\n          }\n        },\n        \"security\": [\n          {\n            \"petstore_auth\": [\n              \"write:pets\",\n              \"read:pets\"\n            ]\n          }\n        ]\n      }\n    },\n    \"/store/inventory\": {\n      \"get\": {\n        \"tags\": [\n          \"store\"\n        ],\n        \"summary\": \"Returns pet inventories by status\",\n        \"description\": \"Returns a map of status codes to quantities\",\n        \"operationId\": \"getInventory\",\n        \"responses\": {\n          \"200\": {\n            \"description\": \"successful operation\",\n            \"content\": {\n              \"application/json\": {\n                \"schema\": {\n                  \"type\": \"object\",\n                  \"additionalProperties\": {\n                    \"type\": \"integer\",\n                    \"format\": \"int32\"\n                  }\n                }\n              }\n            }\n          }\n        },\n        \"security\": [\n          {\n            \"api_key\": []\n          }\n        ]\n      }\n    },\n    \"/store/order\": {\n      \"post\": {\n        \"tags\": [\n          \"store\"\n        ],\n        \"summary\": \"Place an order for a pet\",\n        \"operationId\": \"placeOrder\",\n        \"requestBody\": {\n          \"description\": \"order placed for purchasing the pet\",\n          \"content\": {\n            \"*/*\": {\n              \"schema\": {\n                \"$ref\": \"#/components/schemas/Order\"\n              }\n            }\n          },\n          \"required\": true\n        },\n        \"responses\": {\n          \"200\": {\n            \"description\": \"successful operation\",\n            \"content\": {\n              \"application/xml\": {\n                \"schema\": {\n                  \"$ref\": \"#/components/schemas/Order\"\n                }\n              },\n              \"application/json\": {\n                \"schema\": {\n                  \"$ref\": \"#/components/schemas/Order\"\n                }\n              }\n            }\n          },\n          \"400\": {\n            \"description\": \"Invalid Order\",\n            \"content\": {}\n          }\n        },\n        \"x-codegen-request-body-name\": \"body\"\n      }\n    },\n    \"/store/order/{orderId}\": {\n      \"get\": {\n        \"tags\": [\n          \"store\"\n        ],\n        \"summary\": \"Find purchase order by ID\",\n        \"description\": \"For valid response try integer IDs with value >= 1 and <= 10.         Other values will generated exceptions\",\n        \"operationId\": \"getOrderById\",\n        \"parameters\": [\n          {\n            \"name\": \"orderId\",\n            \"in\": \"path\",\n            \"description\": \"ID of pet that needs to be fetched\",\n            \"required\": true,\n            \"schema\": {\n              \"maximum\": 10,\n              \"minimum\": 1,\n              \"type\": \"integer\",\n              \"format\": \"int64\"\n            }\n          }\n        ],\n        \"responses\": {\n          \"200\": {\n            \"description\": \"successful operation\",\n            \"content\": {\n              \"application/xml\": {\n                \"schema\": {\n                  \"$ref\": \"#/components/schemas/Order\"\n                }\n              },\n              \"application/json\": {\n                \"schema\": {\n                  \"$ref\": \"#/components/schemas/Order\"\n                }\n              }\n            }\n          },\n          \"400\": {\n            \"description\": \"Invalid ID supplied\",\n            \"content\": {}\n          },\n          \"404\": {\n            \"description\": \"Order not found\",\n            \"content\": {}\n          }\n        }\n      },\n      \"delete\": {\n        \"tags\": [\n          \"store\"\n        ],\n        \"summary\": \"Delete purchase order by ID\",\n        \"description\": \"For valid response try integer IDs with positive integer value.         Negative or non-integer values will generate API errors\",\n        \"operationId\": \"deleteOrder\",\n        \"parameters\": [\n          {\n            \"name\": \"orderId\",\n            \"in\": \"path\",\n            \"description\": \"ID of the order that needs to be deleted\",\n            \"required\": true,\n            \"schema\": {\n              \"minimum\": 1,\n              \"type\": \"integer\",\n              \"format\": \"int64\"\n            }\n          }\n        ],\n        \"responses\": {\n          \"400\": {\n            \"description\": \"Invalid ID supplied\",\n            \"content\": {}\n          },\n          \"404\": {\n            \"description\": \"Order not found\",\n            \"content\": {}\n          }\n        }\n      }\n    },\n    \"/user\": {\n      \"post\": {\n        \"tags\": [\n          \"user\"\n        ],\n        \"summary\": \"Create user\",\n        \"description\": \"This can only be done by the logged in user.\",\n        \"operationId\": \"createUser\",\n        \"requestBody\": {\n          \"description\": \"Created user object\",\n          \"content\": {\n            \"*/*\": {\n              \"schema\": {\n                \"$ref\": \"#/components/schemas/User\"\n              }\n            }\n          },\n          \"required\": true\n        },\n        \"responses\": {\n          \"default\": {\n            \"description\": \"successful operation\",\n            \"content\": {}\n          }\n        },\n        \"x-codegen-request-body-name\": \"body\"\n      }\n    },\n    \"/user/createWithArray\": {\n      \"post\": {\n        \"tags\": [\n          \"user\"\n        ],\n        \"summary\": \"Creates list of users with given input array\",\n        \"operationId\": \"createUsersWithArrayInput\",\n        \"requestBody\": {\n          \"description\": \"List of user object\",\n          \"content\": {\n            \"*/*\": {\n              \"schema\": {\n                \"type\": \"array\",\n                \"items\": {\n                  \"$ref\": \"#/components/schemas/User\"\n                }\n              }\n            }\n          },\n          \"required\": true\n        },\n        \"responses\": {\n          \"default\": {\n            \"description\": \"successful operation\",\n            \"content\": {}\n          }\n        },\n        \"x-codegen-request-body-name\": \"body\"\n      }\n    },\n    \"/user/createWithList\": {\n      \"post\": {\n        \"tags\": [\n          \"user\"\n        ],\n        \"summary\": \"Creates list of users with given input array\",\n        \"operationId\": \"createUsersWithListInput\",\n        \"requestBody\": {\n          \"description\": \"List of user object\",\n          \"content\": {\n            \"*/*\": {\n              \"schema\": {\n                \"type\": \"array\",\n                \"items\": {\n                  \"$ref\": \"#/components/schemas/User\"\n                }\n              }\n            }\n          },\n          \"required\": true\n        },\n        \"responses\": {\n          \"default\": {\n            \"description\": \"successful operation\",\n            \"content\": {}\n          }\n        },\n        \"x-codegen-request-body-name\": \"body\"\n      }\n    },\n    \"/user/login\": {\n      \"get\": {\n        \"tags\": [\n          \"user\"\n        ],\n        \"summary\": \"Logs user into the system\",\n        \"operationId\": \"loginUser\",\n        \"parameters\": [\n          {\n            \"name\": \"username\",\n            \"in\": \"query\",\n            \"description\": \"The user name for login\",\n            \"required\": true,\n            \"schema\": {\n              \"type\": \"string\"\n            }\n          },\n          {\n            \"name\": \"password\",\n            \"in\": \"query\",\n            \"description\": \"The password for login in clear text\",\n            \"required\": true,\n            \"schema\": {\n              \"type\": \"string\"\n            }\n          }\n        ],\n        \"responses\": {\n          \"200\": {\n            \"description\": \"successful operation\",\n            \"headers\": {\n              \"X-Rate-Limit\": {\n                \"description\": \"calls per hour allowed by the user\",\n                \"schema\": {\n                  \"type\": \"integer\",\n                  \"format\": \"int32\"\n                }\n              },\n              \"X-Expires-After\": {\n                \"description\": \"date in UTC when token expires\",\n                \"schema\": {\n                  \"type\": \"string\",\n                  \"format\": \"date-time\"\n                }\n              }\n            },\n            \"content\": {\n              \"application/xml\": {\n                \"schema\": {\n                  \"type\": \"string\"\n                }\n              },\n              \"application/json\": {\n                \"schema\": {\n                  \"type\": \"string\"\n                }\n              }\n            }\n          },\n          \"400\": {\n            \"description\": \"Invalid username/password supplied\",\n            \"content\": {}\n          }\n        }\n      }\n    },\n    \"/user/logout\": {\n      \"get\": {\n        \"tags\": [\n          \"user\"\n        ],\n        \"summary\": \"Logs out current logged in user session\",\n        \"operationId\": \"logoutUser\",\n        \"responses\": {\n          \"default\": {\n            \"description\": \"successful operation\",\n            \"content\": {}\n          }\n        }\n      }\n    },\n    \"/user/{username}\": {\n      \"get\": {\n        \"tags\": [\n          \"user\"\n        ],\n        \"summary\": \"Get user by user name\",\n        \"operationId\": \"getUserByName\",\n        \"parameters\": [\n          {\n            \"name\": \"username\",\n            \"in\": \"path\",\n            \"description\": \"The name that needs to be fetched. Use user1 for testing. \",\n            \"required\": true,\n            \"schema\": {\n              \"type\": \"string\"\n            }\n          }\n        ],\n        \"responses\": {\n          \"200\": {\n            \"description\": \"successful operation\",\n            \"content\": {\n              \"application/xml\": {\n                \"schema\": {\n                  \"$ref\": \"#/components/schemas/User\"\n                }\n              },\n              \"application/json\": {\n                \"schema\": {\n                  \"$ref\": \"#/components/schemas/User\"\n                }\n              }\n            }\n          },\n          \"400\": {\n            \"description\": \"Invalid username supplied\",\n            \"content\": {}\n          },\n          \"404\": {\n            \"description\": \"User not found\",\n            \"content\": {}\n          }\n        }\n      },\n      \"put\": {\n        \"tags\": [\n          \"user\"\n        ],\n        \"summary\": \"Updated user\",\n        \"description\": \"This can only be done by the logged in user.\",\n        \"operationId\": \"updateUser\",\n        \"parameters\": [\n          {\n            \"name\": \"username\",\n            \"in\": \"path\",\n            \"description\": \"name that need to be updated\",\n            \"required\": true,\n            \"schema\": {\n              \"type\": \"string\"\n            }\n          }\n        ],\n        \"requestBody\": {\n          \"description\": \"Updated user object\",\n          \"content\": {\n            \"*/*\": {\n              \"schema\": {\n                \"$ref\": \"#/components/schemas/User\"\n              }\n            }\n          },\n          \"required\": true\n        },\n        \"responses\": {\n          \"400\": {\n            \"description\": \"Invalid user supplied\",\n            \"content\": {}\n          },\n          \"404\": {\n            \"description\": \"User not found\",\n            \"content\": {}\n          }\n        },\n        \"x-codegen-request-body-name\": \"body\"\n      },\n      \"delete\": {\n        \"tags\": [\n          \"user\"\n        ],\n        \"summary\": \"Delete user\",\n        \"description\": \"This can only be done by the logged in user.\",\n        \"operationId\": \"deleteUser\",\n        \"parameters\": [\n          {\n            \"name\": \"username\",\n            \"in\": \"path\",\n            \"description\": \"The name that needs to be deleted\",\n            \"required\": true,\n            \"schema\": {\n              \"type\": \"string\"\n            }\n          }\n        ],\n        \"responses\": {\n          \"400\": {\n            \"description\": \"Invalid username supplied\",\n            \"content\": {}\n          },\n          \"404\": {\n            \"description\": \"User not found\",\n            \"content\": {}\n          }\n        }\n      }\n    }\n  },\n  \"components\": {\n    \"schemas\": {\n      \"Order\": {\n        \"type\": \"object\",\n        \"properties\": {\n          \"id\": {\n            \"type\": \"integer\",\n            \"format\": \"int64\"\n          },\n          \"petId\": {\n            \"type\": \"integer\",\n            \"format\": \"int64\"\n          },\n          \"quantity\": {\n            \"type\": \"integer\",\n            \"format\": \"int32\"\n          },\n          \"shipDate\": {\n            \"type\": \"string\",\n            \"format\": \"date-time\"\n          },\n          \"status\": {\n            \"type\": \"string\",\n            \"description\": \"Order Status\",\n            \"enum\": [\n              \"placed\",\n              \"approved\",\n              \"delivered\"\n            ]\n          },\n          \"complete\": {\n            \"type\": \"boolean\",\n            \"default\": false\n          }\n        },\n        \"xml\": {\n          \"name\": \"Order\"\n        }\n      },\n      \"Category\": {\n        \"type\": \"object\",\n        \"properties\": {\n          \"id\": {\n            \"type\": \"integer\",\n            \"format\": \"int64\"\n          },\n          \"name\": {\n            \"type\": \"string\"\n          }\n        },\n        \"xml\": {\n          \"name\": \"Category\"\n        }\n      },\n      \"User\": {\n        \"type\": \"object\",\n        \"properties\": {\n          \"id\": {\n            \"type\": \"integer\",\n            \"format\": \"int64\"\n          },\n          \"username\": {\n            \"type\": \"string\"\n          },\n          \"firstName\": {\n            \"type\": \"string\"\n          },\n          \"lastName\": {\n            \"type\": \"string\"\n          },\n          \"email\": {\n            \"type\": \"string\"\n          },\n          \"password\": {\n            \"type\": \"string\"\n          },\n          \"phone\": {\n            \"type\": \"string\"\n          },\n          \"userStatus\": {\n            \"type\": \"integer\",\n            \"description\": \"User Status\",\n            \"format\": \"int32\"\n          }\n        },\n        \"xml\": {\n          \"name\": \"User\"\n        }\n      },\n      \"Tag\": {\n        \"type\": \"object\",\n        \"properties\": {\n          \"id\": {\n            \"type\": \"integer\",\n            \"format\": \"int64\"\n          },\n          \"name\": {\n            \"type\": \"string\"\n          }\n        },\n        \"xml\": {\n          \"name\": \"Tag\"\n        }\n      },\n      \"Pet\": {\n        \"required\": [\n          \"name\",\n          \"photoUrls\"\n        ],\n        \"type\": \"object\",\n        \"properties\": {\n          \"id\": {\n            \"type\": \"integer\",\n            \"format\": \"int64\"\n          },\n          \"category\": {\n            \"$ref\": \"#/components/schemas/Category\"\n          },\n          \"name\": {\n            \"type\": \"string\",\n            \"example\": \"doggie\"\n          },\n          \"photoUrls\": {\n            \"type\": \"array\",\n            \"xml\": {\n              \"name\": \"photoUrl\",\n              \"wrapped\": true\n            },\n            \"items\": {\n              \"type\": \"string\"\n            }\n          },\n          \"tags\": {\n            \"type\": \"array\",\n            \"xml\": {\n              \"name\": \"tag\",\n              \"wrapped\": true\n            },\n            \"items\": {\n              \"$ref\": \"#/components/schemas/Tag\"\n            }\n          },\n          \"status\": {\n            \"type\": \"string\",\n            \"description\": \"pet status in the store\",\n            \"enum\": [\n              \"available\",\n              \"pending\",\n              \"sold\"\n            ]\n          }\n        },\n        \"xml\": {\n          \"name\": \"Pet\"\n        }\n      },\n      \"ApiResponse\": {\n        \"type\": \"object\",\n        \"properties\": {\n          \"code\": {\n            \"type\": \"integer\",\n            \"format\": \"int32\"\n          },\n          \"type\": {\n            \"type\": \"string\"\n          },\n          \"message\": {\n            \"type\": \"string\"\n          }\n        }\n      }\n    },\n    \"securitySchemes\": {\n      \"petstore_auth\": {\n        \"type\": \"oauth2\",\n        \"flows\": {\n          \"implicit\": {\n            \"authorizationUrl\": \"http://petstore.swagger.io/oauth/dialog\",\n            \"scopes\": {\n              \"write:pets\": \"modify pets in your account\",\n              \"read:pets\": \"read your pets\"\n            }\n          }\n        }\n      },\n      \"api_key\": {\n        \"type\": \"apiKey\",\n        \"name\": \"api_key\",\n        \"in\": \"header\"\n      }\n    }\n  }\n}"
  },
  {
    "path": "server/vendor/async-aws/core/.gitattributes",
    "content": "/.github export-ignore\n/tests export-ignore\n/.gitignore export-ignore\n/Makefile export-ignore\n/phpunit.xml.dist export-ignore\n"
  },
  {
    "path": "server/vendor/async-aws/core/CHANGELOG.md",
    "content": "# Change Log\n\n## NOT RELEASED\n\n## 1.27.1\n\n### Fixed\n\n- SignerV4: fix sort of query parameters to build correct canoncal query string \n\n## 1.27.0\n\n### Added\n\n- Support for Symfony 8\n\n### Changed\n\n- `ResultMockFactory` does not call `ReflectionProperty::setAccessible()` on PHP 8.1+\n\n## 1.26.0\n\n### Added\n\n- AWS api-change: Added `eu-isoe-west-1` region\n\n### Changed\n\n- Normalize the composer requirements\n- Sort exception alphabetically.\n\n## 1.25.0\n\n### Added\n\n- AWS api-change: Added `us-isof-east-1` and `us-isof-south-1` regions\n- Support for BedrockRuntime\n\n## 1.24.1\n\n### Fixed\n\n- Better detection and error messages for when SSO is used but required packages are not installed.\n\n## 1.24.0\n\n### Added\n\n- Support for SsoOidc\n- Support for SSO authentication\n\n### Changed\n\n- AWS enhancement: Documentation updates.\n\n## 1.23.0\n\n### Added\n\n- Added support for EKS Pod Identity\n\n### Changed\n\n- use strict comparison `null !==` instead of `!`\n- Fix CS\n- AWS enhancement: Documentation updates.\n\n## 1.22.1\n\n### Changed\n\n- Enable compiler optimization for the `sprintf` function.\n- Avoid calls to spl_object_ methods when computing cache key.\n- Added SimpleMockedResponse to response of ResultMockFactory.\n\n## 1.22.0\n\n### Added\n\n- Added support for exception based on response http status code only.\n\n## 1.21.0\n\n### Added\n\n- Support for AWS_ENDPOINT_URL environment variable\n\n## 1.20.1\n\n### Changed\n\n- Allow passing explicit null values for optional fields of input objects\n- AWS enhancement: Documentation updates.\n\n### Fixed\n\n- Treat empty env variable as undefined\n\n## 1.20.0\n\n### Added\n\n- Support for LocationService\n- Support for hostPrefix in requests\n- AWS api-change: API updates for the AWS Security Token Service\n- Support for SSO credentials\n- Avoid overriding the exception message with the raw message\n\n### Changed\n\n- Improve parameter type and return type in phpdoc\n\n## 1.19.0\n\n### Added\n\n- Support for Symfony 7\n- Support for Athena\n- Support for MediaConvert\n- Support for IMDS v2 authentication\n- Support for using endpoint discovery with parameters passed in the query string or the path\n\n### Fixed\n\n- Fix potential malformed URI in discovered endpoints\n\n## 1.18.1\n\n### Changed\n\n- AWS enhancement: Documentation updates.\n- Fix deprecation by adding return type on reset methods\n\n## 1.18.0\n\n### Added\n\n- Support for Scheduler\n\n## 1.17.0\n\n### Added\n\n- Support for Iot Data\n\n## 1.16.0\n\n### Added\n\n- Support for endpoint discovery\n- Support for Iot Core\n\n## 1.15.0\n\n### Added\n\n- Support for CodeBuild\n- Support for CodeCommit\n- Support for TimestreamQuery\n- Support for TimestreamWrite\n- AWS enhancement: Documentation updates.\n- Reverted the automated decoration of the injected HttpClient\n- Added an AwsHttpClientFactory to help people creating retryable clients\n- Add 403 errors in the list of potential retryiable operations\n\n### Changed\n\n- Set default value to `false` for the `sendChunkedBody` option.\n\n## 1.14.0\n\n### Added\n\n- Make the injected HttpClient decorated by our `RetryableHttpClient`\n- Support for KMS\n\n### Fixed\n\n- Issue with symfony http-client when posting empty payload\n\n## 1.13.0\n\n### Added\n\n- AWS api-change: Added `us-iso-west-1` region\n- AWS api-change: Used regional endpoint for `us` regions\n- AWS enhancement: Documentation updates.\n- Support for AppSync\n- Support for XRay\n\n## 1.12.0\n\n### Added\n\n- Support for Firehose\n- Support for ElastiCache\n- Support for CloudWatchClient\n- Support for psr/log 2.0 and 3.0\n\n## 1.11.0\n\n### Added\n\n- Support for StepFunctions\n- Support for Kinesis\n- Support for SecretsManager\n- Support for Symfony contracts v3\n- AWS enhancement: Documentation updates for AWS Security Token Service.\n\n### Fixed\n\n- Wrap the HttpClient's decoding exception in UnparsableResponse.\n\n## 1.10.0\n\n### Added\n\n- AWS enhancement: STS now supports assume role with Web Identity using JWT token length upto 20000 characters\n- AWS api-change: This release adds the SourceIdentity parameter that can be set when assuming a role.\n- Support for Symfony 6\n\n## 1.9.2\n\n### Fixed\n\n- Support for psr/cache v2 and v3\n- Fix forming signature with multiple spaces\n\n## 1.9.1\n\n### Fixed\n\n- Make sure mocked results have a response with `Response::$bodyDownloaded = true`.\n\n## 1.9.0\n\n### Added\n\n- Changed case of object's properties to camelCase.\n- Added documentation in class headers.\n- Removed `final` from `ClientException` and `ServerException`.\n- Make Responses thrown Business Exception when AwsErrorCode <-> Exception class mapping provided through RequestContext.\n- Added domain exceptions.\n- Improved Aws Error parsing by using specialized AwsErrorFactory.\n\n### Fixed\n\n- Exception thrown twice by waiters.\n\n## 1.8.0\n\n### Added\n\n- Added option `sendChunkedBody` dedicated to S3.\n\n## 1.7.2\n\n### Changed\n\n- Make sure we can get credentials even if the cache storage fails\n- Clear `realpath` cache to make sure we get the latest credentials token\n\n## 1.7.1\n\n### Fixed\n\n- Fix for an edge case where aws config file could be a directory\n- Fix when AWS profile name is only digits\n\n## 1.7.0\n\n### Added\n\n- A `AwsRetryStrategy` to define what HTTP request we retry\n- Support for Elastic Container Registry (ECR) in `AwsClientFactory`\n- Read \"region\" from ini files.\n- Support for hard coded `roleArn` in `ConfigurationProvider`\n- Added exception `AsyncAws\\Core\\Exception\\UnexpectedValue` and `AsyncAws\\Core\\Exception\\UnparsableResponse`\n\n### Fixed\n\n- Merge configuration if a profile is spread out over multiple files. Ie if `[profile company]` is defined in both `~/.aws/config` and `~/.aws/credentials`.\n- All exceptions thrown must extend `AsyncAws\\Core\\Exception\\Exception`\n\n## 1.6.0\n\n### Added\n\n- Support for Rekognition in `AwsClientFactory`\n\n## 1.5.0\n\n### Added\n\n- Support for `debug` configuration option to log HTTP requests and responses\n- Use Symfony `RetryableHttpClient` when available.\n\n### Fixed\n\n- Allow signing request with non-standard region when using custom endpoint?\n- Fix unresolved Env Variable in some php configuration\n\n## 1.4.2\n\n### Fixed\n\n- Fixed logic in `AbstractApi::getSigner()` when passing `@region` to an API operation\n\n## 1.4.1\n\n### Fixed\n\n- Make sure passing `@region` to an API operation has effect.\n- Check that both AWS access id and secret exists before using them.\n\n## 1.4.0\n\n### Added\n\n- Allow to pass additional content to `ResultMockFactory::createFailing()`\n\n## 1.3.0\n\n### Added\n\n- Support for PHP 8\n- Added second parameter `$preferredChunkSize` to `StreamFactory::create()`\n- Support for CloudFront in `AwsClientFactory`\n- Support for RdsDataService in `AwsClientFactory`\n\n### Changed\n\n- Add more context to error logs\n- Log level for 404 responses changed to \"info\".\n\n### Fixed\n\n- Allows non-AWS regions when using custom endpoints\n\n## 1.2.0\n\n### Added\n\n- Support for EventBridge in `AwsClientFactory`\n- Support for IAM in `AwsClientFactory`\n- Add a `PsrCacheProvider` and `SymfonyCacheProvider` to persists crendentials in a cache pool\n- Add a `Credential::adjustExpireDate` method for adjusting the time according to the time difference with AWS clock\n- Support for global and regional endpoints\n- Add a `Configuration::optionExists` to allow third parties to check if an option is available (needed by libraries supporting several versions of core)\n\n### Deprecated\n\n- Clients extending `AbstractApi` should override `getEndpointMetata`. The method will be abstract in 2.0\n- Custom endpoints should not contain `%region%` and `%service` placeholder. They won't be replaced anymore in 2.0\n- Protected methods `getServiceCode`, `getSignatureVersion` and `getSignatureScopeName` of AbstractApi are deprecated and will be removed in 2.0\n\n### Fixed\n\n- Fix signing of requests with a header containing a date (like `expires` in `S3`).\n- Fix thread safety regarding env vars by using `$_SERVER` instead of `getenv()`.\n\n## 1.1.0\n\n### Added\n\n- Support for ECS Credentials Provider\n- Support for Cognito Identity Provider client in `AwsClientFactory`\n- Support for Cloud Watch Log client in `AwsClientFactory`\n\n### Fixed\n\n- Fixed invalid chunking of request with large body for most clients but S3. This version removed the invalid code from SignerV4 to make sure requests are not chunked.\n- Use camelCase for all getter methods.\n\n## 1.0.0\n\n### Added\n\n- Support for CodeDeploy client in `AwsClientFactory`\n\n### Fixed\n\n- Handle Aws Error type in JsonRest error responses\n\n## 0.5.4\n\n### Added\n\n- Logging on HTTP exceptions.\n\n## 0.5.3\n\n### Added\n\n- Support for SSM client in `AwsClientFactory`\n- Support for Waiters in `ResultMockFactory`\n\n## 0.5.2\n\n### Fixed\n\n- Add support for `Content-Type: application/x-amz-json-1.1` in test case.\n\n## 0.5.1\n\n### Added\n\n- Add `Configuration::isDefault` methods.\n\n### Fixed\n\n- Allow mocking of Results classes named \"*Result\"\n\n## 0.5.0\n\n### Removed\n\n- The input's `validate()` function was merged with the `request()` function.\n- `Configuration::isDefault()`.\n- Protected property `AbstractApi::$logger`.\n- `AsyncAws\\Core\\StreamableBody` in favor of `AsyncAws\\Core\\Stream\\ResponseBodyStream`.\n\n### Added\n\n- Add support for multiregion via `@region` input parameter.\n- DynamoDB support.\n- `ResultMockFactory` was updated with `createFailing()` and support for pagination.\n- `AbstractApi::presign()`.\n- `Result::wait()` for multiplexing downloads.\n- Interface `AsyncAws\\Core\\Input`.\n- `AsyncAws\\Core\\Stream\\ResponseBodyResourceStream` and `AsyncAws\\Core\\Stream\\ResponseBodyStream`.\n- Internal `AsyncAws\\Core\\Response` to encapsulate the HTTP client.\n- Internal `AsyncAws\\Core\\RequestContext`.\n- Internal `AsyncAws\\Core\\Stream\\RewindableStream`.\n\n### Changed\n\n- Exceptions will contain more information from the HTTP response.\n- Moved STS value objects to a dedicated namespace.\n- The `AsyncAws\\Core\\Sts\\Input\\*` and `AsyncAws\\Core\\Sts\\ValueObject*` classes are marked final.\n- Using `DateTimeImmutable` instead of `DateTimeInterface`.\n- Protected properties `AbstractApi::$httpClient`, `AbstractApi::$configuration` and `AbstractApi::$credentialProvider` are now private.\n- `AbstractApi::getResponse()` has new signature. New optional second argument `?RequestContext $context = null` and the return type is `AsyncAws\\Core\\Response`.\n- The `CredentialProvider`s and `Configuration` are now `final`.\n- Renamed `AsyncAws\\Core\\Stream\\Stream` to `AsyncAws\\Core\\Stream\\RequestStream`.\n- Renamed `AsyncAws\\Core\\StreamableBodyInterface` to `AsyncAws\\Core\\Stream\\ResultStream`.\n- The `ResultStream::getChunks()` now returns a iterable of string.\n\n### Fixed\n\n- Bugfix in `WebIdentityProvider`\n\n## 0.4.0\n\n### Removed\n\n- Public `AbstractApi::request()` was removed.\n- Protected function `AbstractApi::getEndpoint()` was made private.\n\n### Added\n\n- Test class `AsyncAws\\Core\\Test\\SimpleStreamableBody`\n\n### Changed\n\n- Moved `AsyncAws\\Core\\Signer\\Request` to `AsyncAws\\Core\\Request`.\n- Added constructor argument to  `AsyncAws\\Core\\Request::__construct()` to support query parameters.\n- Renamed `AsyncAws\\Core\\Request::getUrl()` to `AsyncAws\\Core\\Request::getEndpoint()`\n- Class `AsyncAws\\Core\\Stream\\StreamFactory` is not internal anymore.\n- Removed `requestBody()`, `requestHeaders()`, `requestQuery()` and `requestUri()` input classes. They are replaced with `request()`.\n\n### Fixed\n\n- Fix Instance Provider Role fetching\n\n## 0.3.3\n\n### Added\n\n- Added a `ResultMockFactory` to helps creating tests\n\n### Fixed\n\n- Http method is replaced by PUT in REST calls\n\n## 0.3.2\n\n### Fixed\n\n- `Configuration` don't mix anymore attributes injected by php array and env variables.\n\n## 0.3.1\n\n### Added\n\n- `AbstractApi::getConfiguration()`\n\n### Fixed\n\n- Make sure `Configuration::create(['foo'=>null])` is using the default value of \"foo\".\n\n## 0.3.0\n\n### Added\n\n- Requests can now be streamed\n- Streamable request accepts iterable alongside string, callable, resource\n- Support for getting credentials from Web Identity or OpenID Connect Federation. (`WebIdentityProvider`)\n\n### Changed\n\n- Rename namespace `Signers` into `Signer`.\n\n## 0.2.0\n\n### Added\n\n- Class `AsyncAws\\Core\\Credentials\\NullProvider`\n- Methods `AwsClient::cloudFormation()`, `AwsClient::lambda()`, `AwsClient::sns()`\n- Protected methods `Result::registerPrefetch()` and `Result::unregisterPrefetch()`\n- Timeout parameter to `InstanceProvider::__construct()`\n\n### Changed\n\n- Removed `AwsClient` and replaced it with `AwsClientFactory`\n- Class `AsyncAws\\Core\\Signer\\Request` is marked as internal\n- Make sure behavior of calling `Result::resolve()` is consistent\n\n## 0.1.0\n\nFirst version\n"
  },
  {
    "path": "server/vendor/async-aws/core/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2020 Jérémy Derussé, Tobias Nyholm\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "server/vendor/async-aws/core/README.md",
    "content": "# AsyncAws Core\n\n![](https://github.com/async-aws/core/workflows/Tests/badge.svg?branch=master)\n![](https://github.com/async-aws/core/workflows/BC%20Check/badge.svg?branch=master)\n\nThe repository contains shared classes between all AWS services. It also contains\nthe STS client to handle authentication.\n\n## Install\n\n```cli\ncomposer require async-aws/core\n```\n\n## Documentation\n\nSee https://async-aws.com for documentation.\n\n## Contribute\n\nContributions are welcome and appreciated. Please read https://async-aws.com/contribute/\n"
  },
  {
    "path": "server/vendor/async-aws/core/composer.json",
    "content": "{\n    \"name\": \"async-aws/core\",\n    \"description\": \"Core package to integrate with AWS. This is a lightweight AWS SDK provider by AsyncAws.\",\n    \"license\": \"MIT\",\n    \"type\": \"library\",\n    \"keywords\": [\n        \"aws\",\n        \"amazon\",\n        \"sdk\",\n        \"async-aws\",\n        \"sts\"\n    ],\n    \"require\": {\n        \"php\": \"^7.2.5 || ^8.0\",\n        \"ext-hash\": \"*\",\n        \"ext-json\": \"*\",\n        \"ext-simplexml\": \"*\",\n        \"psr/cache\": \"^1.0 || ^2.0 || ^3.0\",\n        \"psr/log\": \"^1.0 || ^2.0 || ^3.0\",\n        \"symfony/deprecation-contracts\": \"^2.1 || ^3.0\",\n        \"symfony/http-client\": \"^4.4.16 || ^5.1.7 || ^6.0 || ^7.0 || ^8.0\",\n        \"symfony/http-client-contracts\": \"^1.1.8 || ^2.0 || ^3.0\",\n        \"symfony/service-contracts\": \"^1.0 || ^2.0 || ^3.0\"\n    },\n    \"conflict\": {\n        \"async-aws/s3\": \"<1.1\",\n        \"symfony/http-client\": \"5.2.0\"\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"AsyncAws\\\\Core\\\\\": \"src\"\n        }\n    },\n    \"autoload-dev\": {\n        \"psr-4\": {\n            \"AsyncAws\\\\Core\\\\Tests\\\\\": \"tests/\"\n        }\n    },\n    \"extra\": {\n        \"branch-alias\": {\n            \"dev-master\": \"1.27-dev\"\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/roave-bc-check.yaml",
    "content": "parameters:\n    ignoreErrors:\n        - '#ReflectionClass \"PHPUnit\\\\Framework\\\\TestCase\" could not be found in the located source#'\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/AbstractApi.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace AsyncAws\\Core;\n\nuse AsyncAws\\Core\\AwsError\\AwsErrorFactoryInterface;\nuse AsyncAws\\Core\\AwsError\\ChainAwsErrorFactory;\nuse AsyncAws\\Core\\Credentials\\CacheProvider;\nuse AsyncAws\\Core\\Credentials\\ChainProvider;\nuse AsyncAws\\Core\\Credentials\\CredentialProvider;\nuse AsyncAws\\Core\\EndpointDiscovery\\EndpointCache;\nuse AsyncAws\\Core\\EndpointDiscovery\\EndpointInterface;\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\nuse AsyncAws\\Core\\Exception\\LogicException;\nuse AsyncAws\\Core\\Exception\\RuntimeException;\nuse AsyncAws\\Core\\HttpClient\\AwsRetryStrategy;\nuse AsyncAws\\Core\\Signer\\Signer;\nuse AsyncAws\\Core\\Signer\\SignerV4;\nuse AsyncAws\\Core\\Stream\\StringStream;\nuse Psr\\Log\\LoggerInterface;\nuse Psr\\Log\\NullLogger;\nuse Symfony\\Component\\HttpClient\\HttpClient;\nuse Symfony\\Component\\HttpClient\\RetryableHttpClient;\nuse Symfony\\Contracts\\HttpClient\\HttpClientInterface;\n\n/**\n * Base class all API clients are inheriting.\n *\n * @author Tobias Nyholm <tobias.nyholm@gmail.com>\n * @author Jérémy Derussé <jeremy@derusse.com>\n */\nabstract class AbstractApi\n{\n    /**\n     * @var HttpClientInterface\n     */\n    private $httpClient;\n\n    /**\n     * @var Configuration\n     */\n    private $configuration;\n\n    /**\n     * @var CredentialProvider\n     */\n    private $credentialProvider;\n\n    /**\n     * @var array<string, Signer>\n     */\n    private $signers;\n\n    /**\n     * @var LoggerInterface\n     */\n    private $logger;\n\n    /**\n     * @var AwsErrorFactoryInterface\n     */\n    private $awsErrorFactory;\n\n    /**\n     * @var EndpointCache\n     */\n    private $endpointCache;\n\n    /**\n     * @param Configuration|array<Configuration::OPTION_*, string|null> $configuration\n     */\n    public function __construct($configuration = [], ?CredentialProvider $credentialProvider = null, ?HttpClientInterface $httpClient = null, ?LoggerInterface $logger = null)\n    {\n        if (\\is_array($configuration)) {\n            $configuration = Configuration::create($configuration);\n        } elseif (!$configuration instanceof Configuration) {\n            throw new InvalidArgument(\\sprintf('First argument to \"%s::__construct()\" must be an array or an instance of \"%s\"', static::class, Configuration::class));\n        }\n\n        $this->logger = $logger ?? new NullLogger();\n        $this->awsErrorFactory = $this->getAwsErrorFactory();\n        $this->endpointCache = new EndpointCache();\n        if (!isset($httpClient)) {\n            $httpClient = HttpClient::create();\n            if (class_exists(RetryableHttpClient::class)) {\n                /** @psalm-suppress MissingDependency */\n                $httpClient = new RetryableHttpClient(\n                    $httpClient,\n                    new AwsRetryStrategy(AwsRetryStrategy::DEFAULT_RETRY_STATUS_CODES, 1000, 2.0, 0, 0.1, $this->awsErrorFactory),\n                    3,\n                    $this->logger\n                );\n            }\n        }\n        $this->httpClient = $httpClient;\n        $this->configuration = $configuration;\n        $this->credentialProvider = $credentialProvider ?? new CacheProvider(ChainProvider::createDefaultChain($this->httpClient, $this->logger));\n    }\n\n    final public function getConfiguration(): Configuration\n    {\n        return $this->configuration;\n    }\n\n    final public function presign(Input $input, ?\\DateTimeImmutable $expires = null): string\n    {\n        $request = $input->request();\n        $request->setEndpoint($this->getEndpoint($request->getUri(), $request->getQuery(), $input->getRegion()));\n\n        if (null !== $credentials = $this->credentialProvider->getCredentials($this->configuration)) {\n            $this->getSigner($input->getRegion())->presign($request, $credentials, new RequestContext(['expirationDate' => $expires]));\n        }\n\n        return $request->getEndpoint();\n    }\n\n    /**\n     * @deprecated\n     */\n    protected function getServiceCode(): string\n    {\n        throw new LogicException(\\sprintf('The method \"%s\" should not be called. The Client \"%s\" must implement the \"%s\" method.', __FUNCTION__, \\get_class($this), 'getEndpointMetadata'));\n    }\n\n    /**\n     * @deprecated\n     */\n    protected function getSignatureVersion(): string\n    {\n        throw new LogicException(\\sprintf('The method \"%s\" should not be called. The Client \"%s\" must implement the \"%s\" method.', __FUNCTION__, \\get_class($this), 'getEndpointMetadata'));\n    }\n\n    /**\n     * @deprecated\n     */\n    protected function getSignatureScopeName(): string\n    {\n        throw new LogicException(\\sprintf('The method \"%s\" should not be called. The Client \"%s\" must implement the \"%s\" method.', __FUNCTION__, \\get_class($this), 'getEndpointMetadata'));\n    }\n\n    final protected function getResponse(Request $request, ?RequestContext $context = null): Response\n    {\n        $request->setEndpoint($this->getDiscoveredEndpoint($request->getUri(), $request->getQuery(), $context ? $context->getRegion() : null, $context ? $context->usesEndpointDiscovery() : false, $context ? $context->requiresEndpointDiscovery() : false));\n\n        if (null !== $credentials = $this->credentialProvider->getCredentials($this->configuration)) {\n            $this->getSigner($context ? $context->getRegion() : null)->sign($request, $credentials, $context ?? new RequestContext());\n        }\n\n        $length = $request->getBody()->length();\n        if (null !== $length && !$request->hasHeader('content-length')) {\n            $request->setHeader('content-length', (string) $length);\n        }\n\n        // Some servers (like testing Docker Images) does not support `Transfer-Encoding: chunked` requests.\n        // The body is converted into string to prevent curl using `Transfer-Encoding: chunked` unless it really has to.\n        if (($requestBody = $request->getBody()) instanceof StringStream) {\n            $requestBody = $requestBody->stringify();\n        }\n\n        $response = $this->httpClient->request(\n            $request->getMethod(),\n            $request->getEndpoint(),\n            [\n                'headers' => $request->getHeaders(),\n            ] + (0 === $length ? [] : ['body' => $requestBody])\n        );\n\n        if ($debug = filter_var($this->configuration->get('debug'), \\FILTER_VALIDATE_BOOLEAN)) {\n            $this->logger->debug('AsyncAws HTTP request sent: {method} {endpoint}', [\n                'method' => $request->getMethod(),\n                'endpoint' => $request->getEndpoint(),\n                'headers' => json_encode($request->getHeaders()),\n                'body' => 0 === $length ? null : $requestBody,\n            ]);\n        }\n\n        return new Response($response, $this->httpClient, $this->logger, $this->awsErrorFactory, $this->endpointCache, $request, $debug, $context ? $context->getExceptionMapping() : []);\n    }\n\n    /**\n     * @return array<string, callable(string, string): Signer>\n     */\n    protected function getSignerFactories(): array\n    {\n        return [\n            'v4' => static function (string $service, string $region) {\n                return new SignerV4($service, $region);\n            },\n        ];\n    }\n\n    protected function getAwsErrorFactory(): AwsErrorFactoryInterface\n    {\n        return new ChainAwsErrorFactory();\n    }\n\n    /**\n     * Returns the AWS endpoint metadata for the given region.\n     * When user did not provide a region, the client have to either return a global endpoint or fallback to\n     * the Configuration::DEFAULT_REGION constant.\n     *\n     * This implementation is a BC layer for client that does not require core:^1.2.\n     *\n     * @param ?string $region region provided by the user (without fallback to a default region)\n     *\n     * @return array{endpoint: string, signRegion: string, signService: string, signVersions: string[]}\n     */\n    protected function getEndpointMetadata(?string $region): array\n    {\n        /** @psalm-suppress TooManyArguments */\n        trigger_deprecation('async-aws/core', '1.2', 'Extending \"%s\"\" without overriding \"%s\" is deprecated. This method will be abstract in version 2.0.', __CLASS__, __FUNCTION__);\n\n        /** @var string $endpoint */\n        $endpoint = $this->configuration->get('endpoint');\n        /** @var string $region */\n        $region = $region ?? $this->configuration->get('region');\n\n        return [\n            'endpoint' => strtr($endpoint, [\n                '%region%' => $region,\n                '%service%' => $this->getServiceCode(),\n            ]),\n            'signRegion' => $region,\n            'signService' => $this->getSignatureScopeName(),\n            'signVersions' => [$this->getSignatureVersion()],\n        ];\n    }\n\n    /**\n     * Build the endpoint full uri.\n     *\n     * @param string                $uri    or path\n     * @param array<string, string> $query  parameters that should go in the query string\n     * @param ?string               $region region provided by the user in the `@region` parameter of the Input\n     */\n    protected function getEndpoint(string $uri, array $query, ?string $region): string\n    {\n        $region = $region ?? ($this->configuration->isDefault('region') ? null : $this->configuration->get('region'));\n        if (!$this->configuration->isDefault('endpoint')) {\n            /** @var string $endpoint */\n            $endpoint = $this->configuration->get('endpoint');\n        } else {\n            $metadata = $this->getEndpointMetadata($region);\n            $endpoint = $metadata['endpoint'];\n        }\n\n        if (false !== strpos($endpoint, '%region%') || false !== strpos($endpoint, '%service%')) {\n            /** @psalm-suppress TooManyArguments */\n            trigger_deprecation('async-aws/core', '1.2', 'providing an endpoint with placeholder is deprecated and will be ignored in version 2.0. Provide full endpoint instead.');\n\n            $endpoint = strtr($endpoint, [\n                '%region%' => $region ?? $this->configuration->get('region'),\n                '%service%' => $this->getServiceCode(), // if people provides a custom endpoint 'http://%service%.localhost/\n            ]);\n        }\n\n        $endpoint .= $uri;\n        if ([] === $query) {\n            return $endpoint;\n        }\n\n        return $endpoint . (false === strpos($endpoint, '?') ? '?' : '&') . http_build_query($query, '', '&', \\PHP_QUERY_RFC3986);\n    }\n\n    /**\n     * @return EndpointInterface[]\n     */\n    protected function discoverEndpoints(?string $region): array\n    {\n        throw new LogicException(\\sprintf('The Client \"%s\" must implement the \"%s\" method.', \\get_class($this), 'discoverEndpoints'));\n    }\n\n    /**\n     * @param array<string, string> $query\n     *\n     * @return string\n     */\n    private function getDiscoveredEndpoint(string $uri, array $query, ?string $region, bool $usesEndpointDiscovery, bool $requiresEndpointDiscovery)\n    {\n        if (!$this->configuration->isDefault('endpoint')) {\n            return $this->getEndpoint($uri, $query, $region);\n        }\n\n        $usesEndpointDiscovery = $requiresEndpointDiscovery || ($usesEndpointDiscovery && filter_var($this->configuration->get(Configuration::OPTION_ENDPOINT_DISCOVERY_ENABLED), \\FILTER_VALIDATE_BOOLEAN));\n        if (!$usesEndpointDiscovery) {\n            return $this->getEndpoint($uri, $query, $region);\n        }\n\n        // 1. use an active endpoints\n        if (null === $endpoint = $this->endpointCache->getActiveEndpoint($region)) {\n            $previous = null;\n\n            try {\n                // 2. call API to fetch new endpoints\n                $endpoints = $this->discoverEndpoints($region);\n                $this->endpointCache->addEndpoints($region, $endpoints);\n\n                // 3. use active endpoints that has just been injected\n                $endpoint = $this->endpointCache->getActiveEndpoint($region);\n            } catch (\\Exception $previous) {\n            }\n\n            // 4. if endpoint is still null, fallback to expired endpoint\n            if (null === $endpoint && null === $endpoint = $this->endpointCache->getExpiredEndpoint($region)) {\n                if ($requiresEndpointDiscovery) {\n                    throw new RuntimeException(\\sprintf('The Client \"%s\" failed to fetch the endpoint.', \\get_class($this)), 0, $previous);\n                }\n\n                return $this->getEndpoint($uri, $query, $region);\n            }\n        }\n\n        $endpoint .= $uri;\n        if (empty($query)) {\n            return $endpoint;\n        }\n\n        return $endpoint . (false === strpos($endpoint, '?') ? '?' : '&') . http_build_query($query);\n    }\n\n    /**\n     * @param ?string $region region provided by the user in the `@region` parameter of the Input\n     */\n    private function getSigner(?string $region): Signer\n    {\n        /** @var string $region */\n        $region = $region ?? ($this->configuration->isDefault('region') ? null : $this->configuration->get('region'));\n        if (!isset($this->signers[$region])) {\n            $factories = $this->getSignerFactories();\n            $factory = null;\n            if ($this->configuration->isDefault('endpoint') || $this->configuration->isDefault('region')) {\n                $metadata = $this->getEndpointMetadata($region);\n            } else {\n                // Allow non-aws region with custom endpoint\n                $metadata = $this->getEndpointMetadata(Configuration::DEFAULT_REGION);\n                $metadata['signRegion'] = $region;\n            }\n\n            foreach ($metadata['signVersions'] as $signatureVersion) {\n                if (isset($factories[$signatureVersion])) {\n                    $factory = $factories[$signatureVersion];\n\n                    break;\n                }\n            }\n\n            if (null === $factory) {\n                throw new InvalidArgument(\\sprintf('None of the signatures \"%s\" is implemented.', implode(', ', $metadata['signVersions'])));\n            }\n\n            $this->signers[$region] = $factory($metadata['signService'], $metadata['signRegion']);\n        }\n\n        /** @psalm-suppress PossiblyNullArrayOffset */\n        return $this->signers[$region];\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/AwsClientFactory.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace AsyncAws\\Core;\n\nuse AsyncAws\\AppSync\\AppSyncClient;\nuse AsyncAws\\Athena\\AthenaClient;\nuse AsyncAws\\BedrockRuntime\\BedrockRuntimeClient;\nuse AsyncAws\\CloudFormation\\CloudFormationClient;\nuse AsyncAws\\CloudFront\\CloudFrontClient;\nuse AsyncAws\\CloudWatch\\CloudWatchClient;\nuse AsyncAws\\CloudWatchLogs\\CloudWatchLogsClient;\nuse AsyncAws\\CodeBuild\\CodeBuildClient;\nuse AsyncAws\\CodeCommit\\CodeCommitClient;\nuse AsyncAws\\CodeDeploy\\CodeDeployClient;\nuse AsyncAws\\CognitoIdentityProvider\\CognitoIdentityProviderClient;\nuse AsyncAws\\Comprehend\\ComprehendClient;\nuse AsyncAws\\Core\\Credentials\\CacheProvider;\nuse AsyncAws\\Core\\Credentials\\ChainProvider;\nuse AsyncAws\\Core\\Credentials\\CredentialProvider;\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\nuse AsyncAws\\Core\\Exception\\MissingDependency;\nuse AsyncAws\\Core\\Sts\\StsClient;\nuse AsyncAws\\DynamoDb\\DynamoDbClient;\nuse AsyncAws\\Ecr\\EcrClient;\nuse AsyncAws\\ElastiCache\\ElastiCacheClient;\nuse AsyncAws\\EventBridge\\EventBridgeClient;\nuse AsyncAws\\Firehose\\FirehoseClient;\nuse AsyncAws\\Iam\\IamClient;\nuse AsyncAws\\Iot\\IotClient;\nuse AsyncAws\\IotData\\IotDataClient;\nuse AsyncAws\\Kinesis\\KinesisClient;\nuse AsyncAws\\Kms\\KmsClient;\nuse AsyncAws\\Lambda\\LambdaClient;\nuse AsyncAws\\LocationService\\LocationServiceClient;\nuse AsyncAws\\MediaConvert\\MediaConvertClient;\nuse AsyncAws\\RdsDataService\\RdsDataServiceClient;\nuse AsyncAws\\Rekognition\\RekognitionClient;\nuse AsyncAws\\Route53\\Route53Client;\nuse AsyncAws\\S3\\S3Client;\nuse AsyncAws\\Scheduler\\SchedulerClient;\nuse AsyncAws\\SecretsManager\\SecretsManagerClient;\nuse AsyncAws\\Ses\\SesClient;\nuse AsyncAws\\Sns\\SnsClient;\nuse AsyncAws\\Sqs\\SqsClient;\nuse AsyncAws\\Ssm\\SsmClient;\nuse AsyncAws\\Sso\\SsoClient;\nuse AsyncAws\\SsoOidc\\SsoOidcClient;\nuse AsyncAws\\StepFunctions\\StepFunctionsClient;\nuse AsyncAws\\TimestreamQuery\\TimestreamQueryClient;\nuse AsyncAws\\TimestreamWrite\\TimestreamWriteClient;\nuse AsyncAws\\Translate\\TranslateClient;\nuse AsyncAws\\XRay\\XRayClient;\nuse Psr\\Log\\LoggerInterface;\nuse Psr\\Log\\NullLogger;\nuse Symfony\\Component\\HttpClient\\HttpClient;\nuse Symfony\\Contracts\\HttpClient\\HttpClientInterface;\n\n/**\n * Factory that instantiate API clients.\n *\n * @author Tobias Nyholm <tobias.nyholm@gmail.com>\n */\nclass AwsClientFactory\n{\n    /**\n     * @var array<string, mixed>\n     */\n    private $serviceCache;\n\n    /**\n     * @var HttpClientInterface\n     */\n    private $httpClient;\n\n    /**\n     * @var Configuration\n     */\n    private $configuration;\n\n    /**\n     * @var CredentialProvider\n     */\n    private $credentialProvider;\n\n    /**\n     * @var LoggerInterface|null\n     */\n    private $logger;\n\n    /**\n     * @param Configuration|array<Configuration::OPTION_*, string|null> $configuration\n     */\n    public function __construct($configuration = [], ?CredentialProvider $credentialProvider = null, ?HttpClientInterface $httpClient = null, ?LoggerInterface $logger = null)\n    {\n        if (\\is_array($configuration)) {\n            $configuration = Configuration::create($configuration);\n        } elseif (!$configuration instanceof Configuration) {\n            throw new InvalidArgument(\\sprintf('Second argument to \"%s::__construct()\" must be an array or an instance of \"%s\"', __CLASS__, Configuration::class));\n        }\n\n        $this->httpClient = $httpClient ?? HttpClient::create();\n        $this->logger = $logger ?? new NullLogger();\n        $this->configuration = $configuration;\n        $this->credentialProvider = $credentialProvider ?? new CacheProvider(ChainProvider::createDefaultChain($this->httpClient, $this->logger));\n    }\n\n    public function appSync(): AppSyncClient\n    {\n        if (!class_exists(AppSyncClient::class)) {\n            throw MissingDependency::create('async-aws/app-sync', 'AppSync');\n        }\n\n        if (!isset($this->serviceCache[__METHOD__])) {\n            $this->serviceCache[__METHOD__] = new AppSyncClient($this->configuration, $this->credentialProvider, $this->httpClient, $this->logger);\n        }\n\n        return $this->serviceCache[__METHOD__];\n    }\n\n    public function bedrockRuntime(): BedrockRuntimeClient\n    {\n        if (!class_exists(BedrockRuntimeClient::class)) {\n            throw MissingDependency::create('async-aws/bedrock-runtime', 'BedrockRuntime');\n        }\n\n        if (!isset($this->serviceCache[__METHOD__])) {\n            $this->serviceCache[__METHOD__] = new BedrockRuntimeClient($this->configuration, $this->credentialProvider, $this->httpClient, $this->logger);\n        }\n\n        return $this->serviceCache[__METHOD__];\n    }\n\n    public function cloudFormation(): CloudFormationClient\n    {\n        if (!class_exists(CloudFormationClient::class)) {\n            throw MissingDependency::create('async-aws/cloud-formation', 'CloudFormation');\n        }\n\n        if (!isset($this->serviceCache[__METHOD__])) {\n            $this->serviceCache[__METHOD__] = new CloudFormationClient($this->configuration, $this->credentialProvider, $this->httpClient, $this->logger);\n        }\n\n        return $this->serviceCache[__METHOD__];\n    }\n\n    public function cloudFront(): CloudFrontClient\n    {\n        if (!class_exists(CloudFrontClient::class)) {\n            throw MissingDependency::create('async-aws/cloud-front', 'CloudFront');\n        }\n\n        if (!isset($this->serviceCache[__METHOD__])) {\n            $this->serviceCache[__METHOD__] = new CloudFrontClient($this->configuration, $this->credentialProvider, $this->httpClient, $this->logger);\n        }\n\n        return $this->serviceCache[__METHOD__];\n    }\n\n    public function cloudWatch(): CloudWatchClient\n    {\n        if (!class_exists(CloudWatchClient::class)) {\n            throw MissingDependency::create('async-aws/cloud-watch', 'CloudWatch');\n        }\n\n        if (!isset($this->serviceCache[__METHOD__])) {\n            $this->serviceCache[__METHOD__] = new CloudWatchClient($this->configuration, $this->credentialProvider, $this->httpClient, $this->logger);\n        }\n\n        return $this->serviceCache[__METHOD__];\n    }\n\n    public function cloudWatchLogs(): CloudWatchLogsClient\n    {\n        if (!class_exists(CloudWatchLogsClient::class)) {\n            throw MissingDependency::create('async-aws/cloud-watch-logs', 'CloudWatchLogs');\n        }\n\n        if (!isset($this->serviceCache[__METHOD__])) {\n            $this->serviceCache[__METHOD__] = new CloudWatchLogsClient($this->configuration, $this->credentialProvider, $this->httpClient, $this->logger);\n        }\n\n        return $this->serviceCache[__METHOD__];\n    }\n\n    public function codeBuild(): CodeBuildClient\n    {\n        if (!class_exists(CodeBuildClient::class)) {\n            throw MissingDependency::create('async-aws/code-build', 'CodeBuild');\n        }\n\n        if (!isset($this->serviceCache[__METHOD__])) {\n            $this->serviceCache[__METHOD__] = new CodeBuildClient($this->configuration, $this->credentialProvider, $this->httpClient, $this->logger);\n        }\n\n        return $this->serviceCache[__METHOD__];\n    }\n\n    public function codeCommit(): CodeCommitClient\n    {\n        if (!class_exists(CodeCommitClient::class)) {\n            throw MissingDependency::create('async-aws/code-commit', 'CodeCommit');\n        }\n\n        if (!isset($this->serviceCache[__METHOD__])) {\n            $this->serviceCache[__METHOD__] = new CodeCommitClient($this->configuration, $this->credentialProvider, $this->httpClient, $this->logger);\n        }\n\n        return $this->serviceCache[__METHOD__];\n    }\n\n    public function codeDeploy(): CodeDeployClient\n    {\n        if (!class_exists(CodeDeployClient::class)) {\n            throw MissingDependency::create('async-aws/code-deploy', 'CodeDeploy');\n        }\n\n        if (!isset($this->serviceCache[__METHOD__])) {\n            $this->serviceCache[__METHOD__] = new CodeDeployClient($this->configuration, $this->credentialProvider, $this->httpClient, $this->logger);\n        }\n\n        return $this->serviceCache[__METHOD__];\n    }\n\n    public function comprehend(): ComprehendClient\n    {\n        if (!class_exists(ComprehendClient::class)) {\n            throw MissingDependency::create('async-aws/comprehend', 'ComprehendClient');\n        }\n\n        if (!isset($this->serviceCache[__METHOD__])) {\n            $this->serviceCache[__METHOD__] = new ComprehendClient($this->configuration, $this->credentialProvider, $this->httpClient, $this->logger);\n        }\n\n        return $this->serviceCache[__METHOD__];\n    }\n\n    public function dynamoDb(): DynamoDbClient\n    {\n        if (!class_exists(DynamoDbClient::class)) {\n            throw MissingDependency::create('async-aws/dynamo-db', 'DynamoDb');\n        }\n\n        if (!isset($this->serviceCache[__METHOD__])) {\n            $this->serviceCache[__METHOD__] = new DynamoDbClient($this->configuration, $this->credentialProvider, $this->httpClient, $this->logger);\n        }\n\n        return $this->serviceCache[__METHOD__];\n    }\n\n    public function ecr(): EcrClient\n    {\n        if (!class_exists(EcrClient::class)) {\n            throw MissingDependency::create('async-aws/ecr', 'ECR');\n        }\n\n        if (!isset($this->serviceCache[__METHOD__])) {\n            $this->serviceCache[__METHOD__] = new EcrClient($this->configuration, $this->credentialProvider, $this->httpClient, $this->logger);\n        }\n\n        return $this->serviceCache[__METHOD__];\n    }\n\n    public function elastiCache(): ElastiCacheClient\n    {\n        if (!class_exists(ElastiCacheClient::class)) {\n            throw MissingDependency::create('async-aws/elasti-cache', 'ElastiCache');\n        }\n\n        if (!isset($this->serviceCache[__METHOD__])) {\n            $this->serviceCache[__METHOD__] = new ElastiCacheClient($this->configuration, $this->credentialProvider, $this->httpClient, $this->logger);\n        }\n\n        return $this->serviceCache[__METHOD__];\n    }\n\n    public function eventBridge(): EventBridgeClient\n    {\n        if (!class_exists(EventBridgeClient::class)) {\n            throw MissingDependency::create('async-aws/event-bridge', 'EventBridge');\n        }\n\n        if (!isset($this->serviceCache[__METHOD__])) {\n            $this->serviceCache[__METHOD__] = new EventBridgeClient($this->configuration, $this->credentialProvider, $this->httpClient, $this->logger);\n        }\n\n        return $this->serviceCache[__METHOD__];\n    }\n\n    public function firehose(): FirehoseClient\n    {\n        if (!class_exists(FirehoseClient::class)) {\n            throw MissingDependency::create('async-aws/firehose', 'Firehose');\n        }\n\n        if (!isset($this->serviceCache[__METHOD__])) {\n            $this->serviceCache[__METHOD__] = new FirehoseClient($this->configuration, $this->credentialProvider, $this->httpClient, $this->logger);\n        }\n\n        return $this->serviceCache[__METHOD__];\n    }\n\n    public function iam(): IamClient\n    {\n        if (!class_exists(IamClient::class)) {\n            throw MissingDependency::create('async-aws/iam', 'IAM');\n        }\n\n        if (!isset($this->serviceCache[__METHOD__])) {\n            $this->serviceCache[__METHOD__] = new IamClient($this->configuration, $this->credentialProvider, $this->httpClient, $this->logger);\n        }\n\n        return $this->serviceCache[__METHOD__];\n    }\n\n    public function iot(): IotClient\n    {\n        if (!class_exists(IotClient::class)) {\n            throw MissingDependency::create('async-aws/iot', 'Iot');\n        }\n\n        if (!isset($this->serviceCache[__METHOD__])) {\n            $this->serviceCache[__METHOD__] = new IotClient($this->configuration, $this->credentialProvider, $this->httpClient, $this->logger);\n        }\n\n        return $this->serviceCache[__METHOD__];\n    }\n\n    public function iotData(): IotDataClient\n    {\n        if (!class_exists(IotDataClient::class)) {\n            throw MissingDependency::create('async-aws/iot-data', 'IotData');\n        }\n\n        if (!isset($this->serviceCache[__METHOD__])) {\n            $this->serviceCache[__METHOD__] = new IotDataClient($this->configuration, $this->credentialProvider, $this->httpClient, $this->logger);\n        }\n\n        return $this->serviceCache[__METHOD__];\n    }\n\n    public function kinesis(): KinesisClient\n    {\n        if (!class_exists(KinesisClient::class)) {\n            throw MissingDependency::create('aws/kinesis', 'Kinesis');\n        }\n\n        if (!isset($this->serviceCache[__METHOD__])) {\n            $this->serviceCache[__METHOD__] = new KinesisClient($this->configuration, $this->credentialProvider, $this->httpClient, $this->logger);\n        }\n\n        return $this->serviceCache[__METHOD__];\n    }\n\n    public function kms(): KmsClient\n    {\n        if (!class_exists(KmsClient::class)) {\n            throw MissingDependency::create('aws/kms', 'Kms');\n        }\n\n        if (!isset($this->serviceCache[__METHOD__])) {\n            $this->serviceCache[__METHOD__] = new KmsClient($this->configuration, $this->credentialProvider, $this->httpClient, $this->logger);\n        }\n\n        return $this->serviceCache[__METHOD__];\n    }\n\n    public function lambda(): LambdaClient\n    {\n        if (!class_exists(LambdaClient::class)) {\n            throw MissingDependency::create('async-aws/lambda', 'Lambda');\n        }\n\n        if (!isset($this->serviceCache[__METHOD__])) {\n            $this->serviceCache[__METHOD__] = new LambdaClient($this->configuration, $this->credentialProvider, $this->httpClient, $this->logger);\n        }\n\n        return $this->serviceCache[__METHOD__];\n    }\n\n    public function locationService(): LocationServiceClient\n    {\n        if (!class_exists(LocationServiceClient::class)) {\n            throw MissingDependency::create('async-aws/location-service', 'LocationService');\n        }\n\n        if (!isset($this->serviceCache[__METHOD__])) {\n            $this->serviceCache[__METHOD__] = new LocationServiceClient($this->configuration, $this->credentialProvider, $this->httpClient, $this->logger);\n        }\n\n        return $this->serviceCache[__METHOD__];\n    }\n\n    public function mediaConvert(): MediaConvertClient\n    {\n        if (!class_exists(MediaConvertClient::class)) {\n            throw MissingDependency::create('async-aws/media-convert', 'MediaConvert');\n        }\n\n        if (!isset($this->serviceCache[__METHOD__])) {\n            $this->serviceCache[__METHOD__] = new MediaConvertClient($this->configuration, $this->credentialProvider, $this->httpClient, $this->logger);\n        }\n\n        return $this->serviceCache[__METHOD__];\n    }\n\n    public function rdsDataService(): RdsDataServiceClient\n    {\n        if (!class_exists(RdsDataServiceClient::class)) {\n            throw MissingDependency::create('async-aws/rds-data-service', 'RdsDataService');\n        }\n\n        if (!isset($this->serviceCache[__METHOD__])) {\n            $this->serviceCache[__METHOD__] = new RdsDataServiceClient($this->configuration, $this->credentialProvider, $this->httpClient, $this->logger);\n        }\n\n        return $this->serviceCache[__METHOD__];\n    }\n\n    public function rekognition(): RekognitionClient\n    {\n        if (!class_exists(RekognitionClient::class)) {\n            throw MissingDependency::create('aws/rekognition', 'Rekognition');\n        }\n\n        if (!isset($this->serviceCache[__METHOD__])) {\n            $this->serviceCache[__METHOD__] = new RekognitionClient($this->configuration, $this->credentialProvider, $this->httpClient, $this->logger);\n        }\n\n        return $this->serviceCache[__METHOD__];\n    }\n\n    public function route53(): Route53Client\n    {\n        if (!class_exists(Route53Client::class)) {\n            throw MissingDependency::create('aws/route53', 'Route53');\n        }\n\n        if (!isset($this->serviceCache[__METHOD__])) {\n            $this->serviceCache[__METHOD__] = new Route53Client($this->configuration, $this->credentialProvider, $this->httpClient, $this->logger);\n        }\n\n        return $this->serviceCache[__METHOD__];\n    }\n\n    public function s3(): S3Client\n    {\n        if (!class_exists(S3Client::class)) {\n            throw MissingDependency::create('async-aws/s3', 'S3');\n        }\n\n        if (!isset($this->serviceCache[__METHOD__])) {\n            $this->serviceCache[__METHOD__] = new S3Client($this->configuration, $this->credentialProvider, $this->httpClient, $this->logger);\n        }\n\n        return $this->serviceCache[__METHOD__];\n    }\n\n    public function scheduler(): SchedulerClient\n    {\n        if (!class_exists(SchedulerClient::class)) {\n            throw MissingDependency::create('async-aws/scheduler', 'Scheduler');\n        }\n\n        if (!isset($this->serviceCache[__METHOD__])) {\n            $this->serviceCache[__METHOD__] = new SchedulerClient($this->configuration, $this->credentialProvider, $this->httpClient, $this->logger);\n        }\n\n        return $this->serviceCache[__METHOD__];\n    }\n\n    public function secretsManager(): SecretsManagerClient\n    {\n        if (!class_exists(SecretsManagerClient::class)) {\n            throw MissingDependency::create('async-aws/secret-manager', 'SecretsManager');\n        }\n\n        if (!isset($this->serviceCache[__METHOD__])) {\n            $this->serviceCache[__METHOD__] = new SecretsManagerClient($this->configuration, $this->credentialProvider, $this->httpClient, $this->logger);\n        }\n\n        return $this->serviceCache[__METHOD__];\n    }\n\n    public function ses(): SesClient\n    {\n        if (!class_exists(SesClient::class)) {\n            throw MissingDependency::create('async-aws/ses', 'SES');\n        }\n\n        if (!isset($this->serviceCache[__METHOD__])) {\n            $this->serviceCache[__METHOD__] = new SesClient($this->configuration, $this->credentialProvider, $this->httpClient, $this->logger);\n        }\n\n        return $this->serviceCache[__METHOD__];\n    }\n\n    public function sns(): SnsClient\n    {\n        if (!class_exists(SnsClient::class)) {\n            throw MissingDependency::create('async-aws/sns', 'SNS');\n        }\n\n        if (!isset($this->serviceCache[__METHOD__])) {\n            $this->serviceCache[__METHOD__] = new SnsClient($this->configuration, $this->credentialProvider, $this->httpClient, $this->logger);\n        }\n\n        return $this->serviceCache[__METHOD__];\n    }\n\n    public function sqs(): SqsClient\n    {\n        if (!class_exists(SqsClient::class)) {\n            throw MissingDependency::create('async-aws/sqs', 'SQS');\n        }\n\n        if (!isset($this->serviceCache[__METHOD__])) {\n            $this->serviceCache[__METHOD__] = new SqsClient($this->configuration, $this->credentialProvider, $this->httpClient, $this->logger);\n        }\n\n        return $this->serviceCache[__METHOD__];\n    }\n\n    public function ssm(): SsmClient\n    {\n        if (!class_exists(SsmClient::class)) {\n            throw MissingDependency::create('async-aws/ssm', 'SSM');\n        }\n\n        if (!isset($this->serviceCache[__METHOD__])) {\n            $this->serviceCache[__METHOD__] = new SsmClient($this->configuration, $this->credentialProvider, $this->httpClient, $this->logger);\n        }\n\n        return $this->serviceCache[__METHOD__];\n    }\n\n    public function sso(): SsoClient\n    {\n        if (!class_exists(SsoClient::class)) {\n            throw MissingDependency::create('async-aws/sso', 'Sso');\n        }\n\n        if (!isset($this->serviceCache[__METHOD__])) {\n            $this->serviceCache[__METHOD__] = new SsoClient($this->configuration, $this->credentialProvider, $this->httpClient, $this->logger);\n        }\n\n        return $this->serviceCache[__METHOD__];\n    }\n\n    public function ssoOidc(): SsoOidcClient\n    {\n        if (!class_exists(SsoOidcClient::class)) {\n            throw MissingDependency::create('async-aws/sso-oidc', 'SsoOidc');\n        }\n\n        if (!isset($this->serviceCache[__METHOD__])) {\n            $this->serviceCache[__METHOD__] = new SsoOidcClient($this->configuration, $this->credentialProvider, $this->httpClient, $this->logger);\n        }\n\n        return $this->serviceCache[__METHOD__];\n    }\n\n    public function sts(): StsClient\n    {\n        if (!isset($this->serviceCache[__METHOD__])) {\n            $this->serviceCache[__METHOD__] = new StsClient($this->configuration, $this->credentialProvider, $this->httpClient, $this->logger);\n        }\n\n        return $this->serviceCache[__METHOD__];\n    }\n\n    public function stepFunctions(): StepFunctionsClient\n    {\n        if (!class_exists(StepFunctionsClient::class)) {\n            throw MissingDependency::create('async-aws/step-functions', 'StepFunctions');\n        }\n\n        if (!isset($this->serviceCache[__METHOD__])) {\n            $this->serviceCache[__METHOD__] = new StepFunctionsClient($this->configuration, $this->credentialProvider, $this->httpClient, $this->logger);\n        }\n\n        return $this->serviceCache[__METHOD__];\n    }\n\n    public function timestreamQuery(): TimestreamQueryClient\n    {\n        if (!class_exists(TimestreamQueryClient::class)) {\n            throw MissingDependency::create('async-aws/timestream-query', 'TimestreamQuery');\n        }\n\n        if (!isset($this->serviceCache[__METHOD__])) {\n            $this->serviceCache[__METHOD__] = new TimestreamQueryClient($this->configuration, $this->credentialProvider, $this->httpClient, $this->logger);\n        }\n\n        return $this->serviceCache[__METHOD__];\n    }\n\n    public function timestreamWrite(): TimestreamWriteClient\n    {\n        if (!class_exists(TimestreamWriteClient::class)) {\n            throw MissingDependency::create('async-aws/timestream-write', 'TimestreamWrite');\n        }\n\n        if (!isset($this->serviceCache[__METHOD__])) {\n            $this->serviceCache[__METHOD__] = new TimestreamWriteClient($this->configuration, $this->credentialProvider, $this->httpClient, $this->logger);\n        }\n\n        return $this->serviceCache[__METHOD__];\n    }\n\n    public function translate(): TranslateClient\n    {\n        if (!class_exists(TranslateClient::class)) {\n            throw MissingDependency::create('async-aws/translate', 'Translate');\n        }\n\n        if (!isset($this->serviceCache[__METHOD__])) {\n            $this->serviceCache[__METHOD__] = new TranslateClient($this->configuration, $this->credentialProvider, $this->httpClient, $this->logger);\n        }\n\n        return $this->serviceCache[__METHOD__];\n    }\n\n    public function xRay(): XRayClient\n    {\n        if (!class_exists(XRayClient::class)) {\n            throw MissingDependency::create('async-aws/x-ray', 'XRay');\n        }\n\n        if (!isset($this->serviceCache[__METHOD__])) {\n            $this->serviceCache[__METHOD__] = new XRayClient($this->configuration, $this->credentialProvider, $this->httpClient, $this->logger);\n        }\n\n        return $this->serviceCache[__METHOD__];\n    }\n\n    public function cognitoIdentityProvider(): CognitoIdentityProviderClient\n    {\n        if (!class_exists(CognitoIdentityProviderClient::class)) {\n            throw MissingDependency::create('aws/cognito-identity-provider', 'CognitoIdentityProvider');\n        }\n\n        if (!isset($this->serviceCache[__METHOD__])) {\n            $this->serviceCache[__METHOD__] = new CognitoIdentityProviderClient($this->configuration, $this->credentialProvider, $this->httpClient, $this->logger);\n        }\n\n        return $this->serviceCache[__METHOD__];\n    }\n\n    public function athena(): AthenaClient\n    {\n        if (!class_exists(AthenaClient::class)) {\n            throw MissingDependency::create('async-aws/athena', 'Athena');\n        }\n\n        if (!isset($this->serviceCache[__METHOD__])) {\n            $this->serviceCache[__METHOD__] = new AthenaClient($this->configuration, $this->credentialProvider, $this->httpClient, $this->logger);\n        }\n\n        return $this->serviceCache[__METHOD__];\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/AwsError/AwsError.php",
    "content": "<?php\n\nnamespace AsyncAws\\Core\\AwsError;\n\nfinal class AwsError\n{\n    /**\n     * @var string|null\n     */\n    private $code;\n\n    /**\n     * @var string|null\n     */\n    private $message;\n\n    /**\n     * @var string|null\n     */\n    private $type;\n\n    /**\n     * @var string|null\n     */\n    private $detail;\n\n    public function __construct(?string $code, ?string $message, ?string $type, ?string $detail)\n    {\n        $this->code = $code;\n        $this->message = $message;\n        $this->type = $type;\n        $this->detail = $detail;\n    }\n\n    public function getCode(): ?string\n    {\n        return $this->code;\n    }\n\n    public function getMessage(): ?string\n    {\n        return $this->message;\n    }\n\n    public function getType(): ?string\n    {\n        return $this->type;\n    }\n\n    public function getDetail(): ?string\n    {\n        return $this->detail;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/AwsError/AwsErrorFactoryFromResponseTrait.php",
    "content": "<?php\n\nnamespace AsyncAws\\Core\\AwsError;\n\nuse Symfony\\Contracts\\HttpClient\\ResponseInterface;\n\ntrait AwsErrorFactoryFromResponseTrait\n{\n    public function createFromResponse(ResponseInterface $response): AwsError\n    {\n        $content = $response->getContent(false);\n        $headers = $response->getHeaders(false);\n\n        return $this->createFromContent($content, $headers);\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/AwsError/AwsErrorFactoryInterface.php",
    "content": "<?php\n\nnamespace AsyncAws\\Core\\AwsError;\n\nuse Symfony\\Contracts\\HttpClient\\ResponseInterface;\n\ninterface AwsErrorFactoryInterface\n{\n    public function createFromResponse(ResponseInterface $response): AwsError;\n\n    /**\n     * @param array<string, list<string>> $headers\n     */\n    public function createFromContent(string $content, array $headers): AwsError;\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/AwsError/ChainAwsErrorFactory.php",
    "content": "<?php\n\nnamespace AsyncAws\\Core\\AwsError;\n\nuse AsyncAws\\Core\\Exception\\UnparsableResponse;\n\n/**\n * @internal\n */\nclass ChainAwsErrorFactory implements AwsErrorFactoryInterface\n{\n    use AwsErrorFactoryFromResponseTrait;\n\n    /**\n     * @var AwsErrorFactoryInterface[]\n     */\n    private $factories;\n\n    /**\n     * @param AwsErrorFactoryInterface[]|null $factories\n     */\n    public function __construct(?array $factories = null)\n    {\n        $this->factories = $factories ?? [\n            new JsonRestAwsErrorFactory(),\n            new JsonRpcAwsErrorFactory(),\n            new XmlAwsErrorFactory(),\n        ];\n    }\n\n    public function createFromContent(string $content, array $headers): AwsError\n    {\n        $e = null;\n        foreach ($this->factories as $factory) {\n            try {\n                return $factory->createFromContent($content, $headers);\n            } catch (UnparsableResponse $e) {\n            }\n        }\n\n        throw new UnparsableResponse('Failed to parse AWS error: ' . $content, 0, $e);\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/AwsError/JsonRestAwsErrorFactory.php",
    "content": "<?php\n\nnamespace AsyncAws\\Core\\AwsError;\n\nuse AsyncAws\\Core\\Exception\\UnexpectedValue;\nuse AsyncAws\\Core\\Exception\\UnparsableResponse;\n\nfinal class JsonRestAwsErrorFactory implements AwsErrorFactoryInterface\n{\n    use AwsErrorFactoryFromResponseTrait;\n\n    public function createFromContent(string $content, array $headers): AwsError\n    {\n        try {\n            $body = json_decode($content, true);\n\n            return self::parseJson($body, $headers);\n        } catch (\\Throwable $e) {\n            throw new UnparsableResponse('Failed to parse AWS error: ' . $content, 0, $e);\n        }\n    }\n\n    /**\n     * @param array<string, mixed>        $body\n     * @param array<string, list<string>> $headers\n     */\n    private static function parseJson(array $body, array $headers): AwsError\n    {\n        $code = null;\n        $type = $body['type'] ?? $body['Type'] ?? null;\n        if ($type) {\n            $type = strtolower($type);\n        }\n        $message = $body['message'] ?? $body['Message'] ?? null;\n        if (isset($headers['x-amzn-errortype'][0])) {\n            $code = explode(':', $headers['x-amzn-errortype'][0], 2)[0];\n        }\n\n        if (null !== $code) {\n            return new AwsError($code, $message, $type, null);\n        }\n\n        throw new UnexpectedValue('JSON does not contains AWS Error');\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/AwsError/JsonRpcAwsErrorFactory.php",
    "content": "<?php\n\nnamespace AsyncAws\\Core\\AwsError;\n\nuse AsyncAws\\Core\\Exception\\UnexpectedValue;\nuse AsyncAws\\Core\\Exception\\UnparsableResponse;\n\nfinal class JsonRpcAwsErrorFactory implements AwsErrorFactoryInterface\n{\n    use AwsErrorFactoryFromResponseTrait;\n\n    public function createFromContent(string $content, array $headers): AwsError\n    {\n        try {\n            $body = json_decode($content, true);\n\n            return self::parseJson($body, $headers);\n        } catch (\\Throwable $e) {\n            throw new UnparsableResponse('Failed to parse AWS error: ' . $content, 0, $e);\n        }\n    }\n\n    /**\n     * @param array<string, mixed>        $body\n     * @param array<string, list<string>> $headers\n     */\n    private static function parseJson(array $body, array $headers): AwsError\n    {\n        $code = null;\n        $message = $body['message'] ?? $body['Message'] ?? null;\n        if (isset($body['__type'])) {\n            $parts = explode('#', $body['__type'], 2);\n            $code = $parts[1] ?? $parts[0];\n        }\n\n        if (null !== $code || null !== $message) {\n            return new AwsError($code, $message, null, null);\n        }\n\n        throw new UnexpectedValue('JSON does not contains AWS Error');\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/AwsError/XmlAwsErrorFactory.php",
    "content": "<?php\n\nnamespace AsyncAws\\Core\\AwsError;\n\nuse AsyncAws\\Core\\Exception\\RuntimeException;\nuse AsyncAws\\Core\\Exception\\UnexpectedValue;\nuse AsyncAws\\Core\\Exception\\UnparsableResponse;\n\nfinal class XmlAwsErrorFactory implements AwsErrorFactoryInterface\n{\n    use AwsErrorFactoryFromResponseTrait;\n\n    public function createFromContent(string $content, array $headers): AwsError\n    {\n        try {\n            set_error_handler(static function ($errno, $errstr) {\n                throw new RuntimeException($errstr, $errno);\n            });\n\n            try {\n                $xml = new \\SimpleXMLElement($content);\n            } finally {\n                restore_error_handler();\n            }\n\n            return self::parseXml($xml);\n        } catch (\\Throwable $e) {\n            throw new UnparsableResponse('Failed to parse AWS error: ' . $content, 0, $e);\n        }\n    }\n\n    private static function parseXml(\\SimpleXMLElement $xml): AwsError\n    {\n        if (0 < $xml->Error->count()) {\n            return new AwsError(\n                $xml->Error->Code->__toString(),\n                $xml->Error->Message->__toString(),\n                $xml->Error->Type->__toString(),\n                $xml->Error->Detail->__toString()\n            );\n        }\n\n        if (1 === $xml->Code->count() && 1 === $xml->Message->count()) {\n            return new AwsError(\n                $xml->Code->__toString(),\n                $xml->Message->__toString(),\n                null,\n                null\n            );\n        }\n\n        throw new UnexpectedValue('XML does not contains AWS Error');\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Configuration.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace AsyncAws\\Core;\n\nuse AsyncAws\\Core\\Credentials\\IniFileLoader;\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\n\n/**\n * Helper object that holds all configuration to the API.\n *\n * @author Tobias Nyholm <tobias.nyholm@gmail.com>\n * @author Jérémy Derussé <jeremy@derusse.com>\n */\nfinal class Configuration\n{\n    public const DEFAULT_REGION = 'us-east-1';\n\n    public const OPTION_REGION = 'region';\n    public const OPTION_DEBUG = 'debug';\n    public const OPTION_PROFILE = 'profile';\n    public const OPTION_ACCESS_KEY_ID = 'accessKeyId';\n    public const OPTION_SECRET_ACCESS_KEY = 'accessKeySecret';\n    public const OPTION_SESSION_TOKEN = 'sessionToken';\n    public const OPTION_SHARED_CREDENTIALS_FILE = 'sharedCredentialsFile';\n    public const OPTION_SHARED_CONFIG_FILE = 'sharedConfigFile';\n    public const OPTION_ENDPOINT = 'endpoint';\n    public const OPTION_ROLE_ARN = 'roleArn';\n    public const OPTION_WEB_IDENTITY_TOKEN_FILE = 'webIdentityTokenFile';\n    public const OPTION_ROLE_SESSION_NAME = 'roleSessionName';\n    public const OPTION_CONTAINER_CREDENTIALS_RELATIVE_URI = 'containerCredentialsRelativeUri';\n    public const OPTION_ENDPOINT_DISCOVERY_ENABLED = 'endpointDiscoveryEnabled';\n    public const OPTION_POD_IDENTITY_CREDENTIALS_FULL_URI = 'podIdentityCredentialsFullUri';\n    public const OPTION_POD_IDENTITY_AUTHORIZATION_TOKEN_FILE = 'podIdentityAuthorizationTokenFile';\n\n    // S3 specific option\n    public const OPTION_PATH_STYLE_ENDPOINT = 'pathStyleEndpoint';\n    public const OPTION_SEND_CHUNKED_BODY = 'sendChunkedBody';\n\n    private const AVAILABLE_OPTIONS = [\n        self::OPTION_REGION => true,\n        self::OPTION_DEBUG => true,\n        self::OPTION_PROFILE => true,\n        self::OPTION_ACCESS_KEY_ID => true,\n        self::OPTION_SECRET_ACCESS_KEY => true,\n        self::OPTION_SESSION_TOKEN => true,\n        self::OPTION_SHARED_CREDENTIALS_FILE => true,\n        self::OPTION_SHARED_CONFIG_FILE => true,\n        self::OPTION_ENDPOINT => true,\n        self::OPTION_ROLE_ARN => true,\n        self::OPTION_WEB_IDENTITY_TOKEN_FILE => true,\n        self::OPTION_ROLE_SESSION_NAME => true,\n        self::OPTION_CONTAINER_CREDENTIALS_RELATIVE_URI => true,\n        self::OPTION_ENDPOINT_DISCOVERY_ENABLED => true,\n        self::OPTION_PATH_STYLE_ENDPOINT => true,\n        self::OPTION_SEND_CHUNKED_BODY => true,\n        self::OPTION_POD_IDENTITY_CREDENTIALS_FULL_URI => true,\n        self::OPTION_POD_IDENTITY_AUTHORIZATION_TOKEN_FILE => true,\n    ];\n\n    // Put fallback options into groups to avoid mixing of provided config and environment variables\n    private const FALLBACK_OPTIONS = [\n        [self::OPTION_REGION => ['AWS_REGION', 'AWS_DEFAULT_REGION']],\n        [self::OPTION_PROFILE => ['AWS_PROFILE', 'AWS_DEFAULT_PROFILE']],\n        [\n            self::OPTION_ACCESS_KEY_ID => ['AWS_ACCESS_KEY_ID', 'AWS_ACCESS_KEY'],\n            self::OPTION_SECRET_ACCESS_KEY => ['AWS_SECRET_ACCESS_KEY', 'AWS_SECRET_KEY'],\n            self::OPTION_SESSION_TOKEN => 'AWS_SESSION_TOKEN',\n        ],\n        [self::OPTION_SHARED_CREDENTIALS_FILE => 'AWS_SHARED_CREDENTIALS_FILE'],\n        [self::OPTION_SHARED_CONFIG_FILE => 'AWS_CONFIG_FILE'],\n        [self::OPTION_ENDPOINT => 'AWS_ENDPOINT_URL'],\n        [\n            self::OPTION_ROLE_ARN => 'AWS_ROLE_ARN',\n            self::OPTION_WEB_IDENTITY_TOKEN_FILE => 'AWS_WEB_IDENTITY_TOKEN_FILE',\n            self::OPTION_ROLE_SESSION_NAME => 'AWS_ROLE_SESSION_NAME',\n        ],\n        [self::OPTION_CONTAINER_CREDENTIALS_RELATIVE_URI => 'AWS_CONTAINER_CREDENTIALS_RELATIVE_URI'],\n        [self::OPTION_ENDPOINT_DISCOVERY_ENABLED => ['AWS_ENDPOINT_DISCOVERY_ENABLED', 'AWS_ENABLE_ENDPOINT_DISCOVERY']],\n        [self::OPTION_POD_IDENTITY_CREDENTIALS_FULL_URI => 'AWS_CONTAINER_CREDENTIALS_FULL_URI'],\n        [self::OPTION_POD_IDENTITY_AUTHORIZATION_TOKEN_FILE => 'AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE'],\n    ];\n\n    private const DEFAULT_OPTIONS = [\n        self::OPTION_REGION => self::DEFAULT_REGION,\n        self::OPTION_DEBUG => 'false',\n        self::OPTION_PROFILE => 'default',\n        self::OPTION_SHARED_CREDENTIALS_FILE => '~/.aws/credentials',\n        self::OPTION_SHARED_CONFIG_FILE => '~/.aws/config',\n        // https://docs.aws.amazon.com/general/latest/gr/rande.html\n        self::OPTION_ENDPOINT => 'https://%service%.%region%.amazonaws.com',\n        self::OPTION_PATH_STYLE_ENDPOINT => 'false',\n        self::OPTION_SEND_CHUNKED_BODY => 'false',\n        self::OPTION_ENDPOINT_DISCOVERY_ENABLED => 'false',\n    ];\n\n    /**\n     * @var array<self::OPTION_*, string|null>\n     */\n    private $data = [];\n\n    /**\n     * @var array<self::OPTION_*, bool>\n     */\n    private $userData = [];\n\n    /**\n     * @param array<self::OPTION_*, string|null> $options\n     */\n    public static function create(array $options): self\n    {\n        if (0 < \\count($invalidOptions = array_diff_key($options, self::AVAILABLE_OPTIONS))) {\n            throw new InvalidArgument(\\sprintf('Invalid option(s) \"%s\" passed to \"%s::%s\". ', implode('\", \"', array_keys($invalidOptions)), __CLASS__, __METHOD__));\n        }\n\n        // Force each option to be string or null\n        $options = array_map(static function ($value) {\n            return null !== $value ? (string) $value : $value;\n        }, $options);\n\n        $configuration = new self();\n        $options = self::parseEnvironmentVariables($options);\n        self::populateConfiguration($configuration, $options);\n        $iniOptions = self::parseIniFiles($configuration);\n        self::populateConfiguration($configuration, $iniOptions);\n\n        return $configuration;\n    }\n\n    public static function optionExists(string $optionName): bool\n    {\n        return isset(self::AVAILABLE_OPTIONS[$optionName]);\n    }\n\n    /**\n     * @param self::OPTION_* $name\n     *\n     * @psalm-return (\n     *     $name is\n     *       self::OPTION_REGION\n     *       |self::OPTION_DEBUG\n     *       |self::OPTION_PROFILE\n     *       |self::OPTION_SHARED_CREDENTIALS_FILE\n     *       |self::OPTION_SHARED_CONFIG_FILE\n     *       |self::OPTION_ENDPOINT\n     *       |self::OPTION_PATH_STYLE_ENDPOINT\n     *       |self::OPTION_SEND_CHUNKED_BODY\n     *     ? string\n     *     : ?string\n     * )\n     */\n    public function get(string $name): ?string\n    {\n        if (!isset(self::AVAILABLE_OPTIONS[$name])) {\n            throw new InvalidArgument(\\sprintf('Invalid option \"%s\" passed to \"%s::%s\". ', $name, __CLASS__, __METHOD__));\n        }\n\n        return $this->data[$name] ?? null;\n    }\n\n    /**\n     * @param self::OPTION_* $name\n     */\n    public function has(string $name): bool\n    {\n        if (!isset(self::AVAILABLE_OPTIONS[$name])) {\n            throw new InvalidArgument(\\sprintf('Invalid option \"%s\" passed to \"%s::%s\". ', $name, __CLASS__, __METHOD__));\n        }\n\n        return isset($this->data[$name]);\n    }\n\n    /**\n     * @param self::OPTION_* $name\n     */\n    public function isDefault(string $name): bool\n    {\n        if (!isset(self::AVAILABLE_OPTIONS[$name])) {\n            throw new InvalidArgument(\\sprintf('Invalid option \"%s\" passed to \"%s::%s\". ', $name, __CLASS__, __METHOD__));\n        }\n\n        return empty($this->userData[$name]);\n    }\n\n    /**\n     * @param array<self::OPTION_*, string|null> $options\n     *\n     * @return array<self::OPTION_*, string|null>\n     */\n    private static function parseEnvironmentVariables(array $options): array\n    {\n        foreach (self::FALLBACK_OPTIONS as $fallbackGroup) {\n            // prevent mixing env variables with config keys\n            foreach ($fallbackGroup as $option => $envVariableNames) {\n                if (isset($options[$option])) {\n                    continue 2;\n                }\n            }\n\n            foreach ($fallbackGroup as $option => $envVariableNames) {\n                // Read environment files\n                $envVariableNames = (array) $envVariableNames;\n                foreach ($envVariableNames as $envVariableName) {\n                    $envVariableValue = EnvVar::get($envVariableName);\n                    if (null !== $envVariableValue && '' !== $envVariableValue) {\n                        $options[$option] = $envVariableValue;\n\n                        break;\n                    }\n                }\n            }\n        }\n\n        return $options;\n    }\n\n    /**\n     * Look for \"region\" in the configured ini files.\n     *\n     * @return array<self::OPTION_*, string|null>\n     */\n    private static function parseIniFiles(Configuration $configuration): array\n    {\n        $options = [];\n        if (!$configuration->isDefault(self::OPTION_REGION)) {\n            return $options;\n        }\n\n        $profilesData = (new IniFileLoader())->loadProfiles([\n            $configuration->get(self::OPTION_SHARED_CREDENTIALS_FILE),\n            $configuration->get(self::OPTION_SHARED_CONFIG_FILE),\n        ]);\n\n        if (empty($profilesData)) {\n            return $options;\n        }\n\n        /** @var string $profile */\n        $profile = $configuration->get(Configuration::OPTION_PROFILE);\n        if (isset($profilesData[$profile]['region'])) {\n            $options[self::OPTION_REGION] = $profilesData[$profile]['region'];\n        }\n\n        return $options;\n    }\n\n    /**\n     * Add array options to the configuration object.\n     *\n     * @param array<self::OPTION_*, string|null> $options\n     */\n    private static function populateConfiguration(Configuration $configuration, array $options): void\n    {\n        foreach ($options as $key => $value) {\n            if (null !== $value) {\n                $configuration->userData[$key] = true;\n            }\n        }\n\n        // If we have not applied default before\n        if (empty($configuration->data)) {\n            foreach (self::DEFAULT_OPTIONS as $optionTrigger => $defaultValue) {\n                if (isset($options[$optionTrigger])) {\n                    continue;\n                }\n\n                $options[$optionTrigger] = $defaultValue;\n            }\n        }\n\n        $configuration->data = array_merge($configuration->data, $options);\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Credentials/CacheProvider.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace AsyncAws\\Core\\Credentials;\n\nuse AsyncAws\\Core\\Configuration;\nuse Symfony\\Contracts\\Service\\ResetInterface;\n\n/**\n * Cache the Credential generated by the decorated CredentialProvider in memory.\n *\n * The Credential will be reused until it expires.\n *\n * @author Jérémy Derussé <jeremy@derusse.com>\n */\nfinal class CacheProvider implements CredentialProvider, ResetInterface\n{\n    /**\n     * @var array<string, Credentials|null>\n     */\n    private $cache = [];\n\n    /**\n     * @var CredentialProvider\n     */\n    private $decorated;\n\n    public function __construct(CredentialProvider $decorated)\n    {\n        $this->decorated = $decorated;\n    }\n\n    public function getCredentials(Configuration $configuration): ?Credentials\n    {\n        $key = sha1(serialize($configuration));\n        if (!\\array_key_exists($key, $this->cache) || (null !== $this->cache[$key] && $this->cache[$key]->isExpired())) {\n            $this->cache[$key] = $this->decorated->getCredentials($configuration);\n        }\n\n        return $this->cache[$key];\n    }\n\n    public function reset(): void\n    {\n        $this->cache = [];\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Credentials/ChainProvider.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace AsyncAws\\Core\\Credentials;\n\nuse AsyncAws\\Core\\Configuration;\nuse Psr\\Log\\LoggerInterface;\nuse Psr\\Log\\NullLogger;\nuse Symfony\\Component\\HttpClient\\HttpClient;\nuse Symfony\\Contracts\\HttpClient\\HttpClientInterface;\nuse Symfony\\Contracts\\Service\\ResetInterface;\n\n/**\n * Chains several CredentialProvider together.\n *\n * Credentials are fetched from the first CredentialProvider that does not returns null.\n * The CredentialProvider will be memoized and will be directly called the next times.\n *\n * @author Jérémy Derussé <jeremy@derusse.com>\n */\nfinal class ChainProvider implements CredentialProvider, ResetInterface\n{\n    /**\n     * @var iterable<CredentialProvider>\n     */\n    private $providers;\n\n    /**\n     * @var array<string, CredentialProvider|null>\n     */\n    private $lastSuccessfulProvider = [];\n\n    /**\n     * @param iterable<CredentialProvider> $providers\n     */\n    public function __construct(iterable $providers)\n    {\n        $this->providers = $providers;\n    }\n\n    public function getCredentials(Configuration $configuration): ?Credentials\n    {\n        $key = sha1(serialize($configuration));\n        if (\\array_key_exists($key, $this->lastSuccessfulProvider)) {\n            if (null === $provider = $this->lastSuccessfulProvider[$key]) {\n                return null;\n            }\n\n            return $provider->getCredentials($configuration);\n        }\n\n        foreach ($this->providers as $provider) {\n            if (null !== $credentials = $provider->getCredentials($configuration)) {\n                $this->lastSuccessfulProvider[$key] = $provider;\n\n                return $credentials;\n            }\n        }\n\n        $this->lastSuccessfulProvider[$key] = null;\n\n        return null;\n    }\n\n    public function reset(): void\n    {\n        $this->lastSuccessfulProvider = [];\n    }\n\n    public static function createDefaultChain(?HttpClientInterface $httpClient = null, ?LoggerInterface $logger = null): CredentialProvider\n    {\n        $httpClient = $httpClient ?? HttpClient::create();\n        $logger = $logger ?? new NullLogger();\n\n        return new ChainProvider([\n            new ConfigurationProvider(),\n            new WebIdentityProvider($logger, null, $httpClient),\n            new IniFileProvider($logger, null, $httpClient),\n            new ContainerProvider($httpClient, $logger),\n            new InstanceProvider($httpClient, $logger),\n        ]);\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Credentials/ConfigurationProvider.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace AsyncAws\\Core\\Credentials;\n\nuse AsyncAws\\Core\\Configuration;\nuse AsyncAws\\Core\\Exception\\RuntimeException;\nuse AsyncAws\\Core\\Sts\\StsClient;\nuse Psr\\Log\\LoggerInterface;\nuse Psr\\Log\\NullLogger;\nuse Symfony\\Contracts\\HttpClient\\HttpClientInterface;\n\n/**\n * Provides Credentials from Configuration data.\n *\n * @author Jérémy Derussé <jeremy@derusse.com>\n */\nfinal class ConfigurationProvider implements CredentialProvider\n{\n    use DateFromResult;\n\n    /**\n     * @var LoggerInterface\n     */\n    private $logger;\n\n    /**\n     * @var HttpClientInterface|null\n     */\n    private $httpClient;\n\n    public function __construct(?HttpClientInterface $httpClient = null, ?LoggerInterface $logger = null)\n    {\n        $this->logger = $logger ?? new NullLogger();\n        $this->httpClient = $httpClient;\n    }\n\n    public function getCredentials(Configuration $configuration): ?Credentials\n    {\n        $accessKeyId = $configuration->get(Configuration::OPTION_ACCESS_KEY_ID);\n        $secretAccessKeyId = $configuration->get(Configuration::OPTION_SECRET_ACCESS_KEY);\n\n        if (null === $accessKeyId || null === $secretAccessKeyId) {\n            return null;\n        }\n\n        $credentials = new Credentials(\n            $accessKeyId,\n            $secretAccessKeyId,\n            $configuration->get(Configuration::OPTION_SESSION_TOKEN)\n        );\n\n        $roleArn = $configuration->get(Configuration::OPTION_ROLE_ARN);\n        if (null !== $roleArn) {\n            $region = $configuration->get(Configuration::OPTION_REGION);\n            $roleSessionName = $configuration->get(Configuration::OPTION_ROLE_SESSION_NAME);\n\n            return $this->getCredentialsFromRole($credentials, $region, $roleArn, $roleSessionName);\n        }\n\n        /** @psalm-suppress PossiblyNullArgument */\n        return $credentials;\n    }\n\n    private function getCredentialsFromRole(Credentials $credentials, string $region, string $roleArn, ?string $roleSessionName = null): ?Credentials\n    {\n        $roleSessionName = $roleSessionName ?? uniqid('async-aws-', true);\n        $stsClient = new StsClient(['region' => $region], $credentials, $this->httpClient);\n        $result = $stsClient->assumeRole([\n            'RoleArn' => $roleArn,\n            'RoleSessionName' => $roleSessionName,\n        ]);\n\n        try {\n            if (null === $credentials = $result->getCredentials()) {\n                throw new RuntimeException('The AsumeRole response does not contains credentials');\n            }\n        } catch (\\Exception $e) {\n            $this->logger->warning('Failed to get credentials from assumed role: {exception}\".', ['exception' => $e]);\n\n            return null;\n        }\n\n        return new Credentials(\n            $credentials->getAccessKeyId(),\n            $credentials->getSecretAccessKey(),\n            $credentials->getSessionToken(),\n            Credentials::adjustExpireDate($credentials->getExpiration(), $this->getDateFromResult($result))\n        );\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Credentials/ContainerProvider.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace AsyncAws\\Core\\Credentials;\n\nuse AsyncAws\\Core\\Configuration;\nuse Psr\\Log\\LoggerInterface;\nuse Psr\\Log\\NullLogger;\nuse Symfony\\Component\\HttpClient\\HttpClient;\nuse Symfony\\Contracts\\HttpClient\\Exception\\DecodingExceptionInterface;\nuse Symfony\\Contracts\\HttpClient\\Exception\\HttpExceptionInterface;\nuse Symfony\\Contracts\\HttpClient\\Exception\\TransportExceptionInterface;\nuse Symfony\\Contracts\\HttpClient\\HttpClientInterface;\n\n/**\n * Provides Credentials for containers running in EKS with Pod Identity or ECS.\n *\n * @see https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/index.html?com/amazonaws/auth/ContainerCredentialsProvider.html\n * @see https://docs.aws.amazon.com/eks/latest/userguide/pod-identities.html\n */\nfinal class ContainerProvider implements CredentialProvider\n{\n    use TokenFileLoader;\n\n    private const ECS_HOST = '169.254.170.2';\n    private const EKS_HOST_IPV4 = '169.254.170.23';\n    private const EKS_HOST_IPV6 = 'fd00:ec2::23';\n\n    /**\n     * @var LoggerInterface\n     */\n    private $logger;\n\n    /**\n     * @var HttpClientInterface\n     */\n    private $httpClient;\n\n    /**\n     * @var float\n     */\n    private $timeout;\n\n    public function __construct(?HttpClientInterface $httpClient = null, ?LoggerInterface $logger = null, float $timeout = 1.0)\n    {\n        $this->logger = $logger ?? new NullLogger();\n        $this->httpClient = $httpClient ?? HttpClient::create();\n        $this->timeout = $timeout;\n    }\n\n    public function getCredentials(Configuration $configuration): ?Credentials\n    {\n        $fullUri = $this->getFullUri($configuration);\n\n        // introduces an early exit if the env variable is not set.\n        if (empty($fullUri)) {\n            return null;\n        }\n\n        if (!$this->isUriValid($fullUri)) {\n            $this->logger->warning('Invalid URI \"{uri}\" provided.', ['uri' => $fullUri]);\n\n            return null;\n        }\n\n        $tokenFile = $configuration->get(Configuration::OPTION_POD_IDENTITY_AUTHORIZATION_TOKEN_FILE);\n        if (!empty($tokenFile)) {\n            try {\n                $tokenFileContent = $this->getTokenFileContent($tokenFile);\n            } catch (\\Exception $e) {\n                $this->logger->warning('\"Error reading PodIdentityTokenFile \"{tokenFile}.', ['tokenFile' => $tokenFile, 'exception' => $e]);\n\n                return null;\n            }\n        }\n\n        // fetch credentials from ecs endpoint\n        try {\n            $response = $this->httpClient->request('GET', $fullUri, ['headers' => $this->getHeaders($tokenFileContent ?? null), 'timeout' => $this->timeout]);\n            $result = $response->toArray();\n        } catch (DecodingExceptionInterface $e) {\n            $this->logger->info('Failed to decode Credentials.', ['exception' => $e]);\n\n            return null;\n        } catch (TransportExceptionInterface|HttpExceptionInterface $e) {\n            $this->logger->info('Failed to fetch Profile from Instance Metadata.', ['exception' => $e]);\n\n            return null;\n        }\n\n        if (null !== $date = $response->getHeaders(false)['date'][0] ?? null) {\n            $date = new \\DateTimeImmutable($date);\n        }\n\n        return new Credentials(\n            $result['AccessKeyId'],\n            $result['SecretAccessKey'],\n            $result['Token'],\n            Credentials::adjustExpireDate(new \\DateTimeImmutable($result['Expiration']), $date)\n        );\n    }\n\n    /**\n     * Checks if the provided IP address is a loopback address.\n     *\n     * @param string $host the host address to check\n     *\n     * @return bool true if the IP is a loopback address, false otherwise\n     */\n    private function isLoopBackAddress(string $host)\n    {\n        // Validate that the input is a valid IP address\n        if (!filter_var($host, \\FILTER_VALIDATE_IP)) {\n            return false;\n        }\n\n        // Convert the IP address to binary format\n        $packedIp = inet_pton($host);\n\n        // Check if the IP is in the 127.0.0.0/8 range\n        if (4 === \\strlen($packedIp)) {\n            return 127 === \\ord($packedIp[0]);\n        }\n\n        // Check if the IP is ::1\n        if (16 === \\strlen($packedIp)) {\n            return $packedIp === inet_pton('::1');\n        }\n\n        // Unknown IP format\n        return false;\n    }\n\n    private function getFullUri(Configuration $configuration): ?string\n    {\n        $relativeUri = $configuration->get(Configuration::OPTION_CONTAINER_CREDENTIALS_RELATIVE_URI);\n\n        if (null !== $relativeUri) {\n            return 'http://' . self::ECS_HOST . $relativeUri;\n        }\n\n        return $configuration->get(Configuration::OPTION_POD_IDENTITY_CREDENTIALS_FULL_URI);\n    }\n\n    private function getHeaders(?string $tokenFileContent): array\n    {\n        return $tokenFileContent ? ['Authorization' => $tokenFileContent] : [];\n    }\n\n    private function isUriValid(string $uri): bool\n    {\n        $parsedUri = parse_url($uri);\n        if (false === $parsedUri) {\n            return false;\n        }\n\n        if (!isset($parsedUri['scheme'])) {\n            return false;\n        }\n\n        if ('https' !== $parsedUri['scheme']) {\n            $host = trim($parsedUri['host'] ?? '', '[]');\n            if (self::EKS_HOST_IPV4 === $host || self::EKS_HOST_IPV6 === $host) {\n                return true;\n            }\n\n            if (self::ECS_HOST === $host) {\n                return true;\n            }\n\n            return $this->isLoopBackAddress($host);\n        }\n\n        return true;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Credentials/CredentialProvider.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace AsyncAws\\Core\\Credentials;\n\nuse AsyncAws\\Core\\Configuration;\n\n/**\n * Interface for providing Credential.\n *\n * @author Jérémy Derussé <jeremy@derusse.com>\n */\ninterface CredentialProvider\n{\n    /**\n     * Return a Credential when possible. Return null otherwise.\n     */\n    public function getCredentials(Configuration $configuration): ?Credentials;\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Credentials/Credentials.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace AsyncAws\\Core\\Credentials;\n\nuse AsyncAws\\Core\\Configuration;\n\n/**\n * Immutable store for Credentials parameters.\n *\n * @author Jérémy Derussé <jeremy@derusse.com>\n */\nfinal class Credentials implements CredentialProvider\n{\n    private const EXPIRATION_DRIFT = 30;\n\n    /**\n     * @var string\n     */\n    private $accessKeyId;\n\n    /**\n     * @var string\n     */\n    private $secretKey;\n\n    /**\n     * @var string|null\n     */\n    private $sessionToken;\n\n    /**\n     * @var \\DateTimeImmutable|null\n     */\n    private $expireDate;\n\n    public function __construct(\n        string $accessKeyId,\n        string $secretKey,\n        ?string $sessionToken = null,\n        ?\\DateTimeImmutable $expireDate = null\n    ) {\n        $this->accessKeyId = $accessKeyId;\n        $this->secretKey = $secretKey;\n        $this->sessionToken = $sessionToken;\n        $this->expireDate = $expireDate;\n    }\n\n    public function getAccessKeyId(): string\n    {\n        return $this->accessKeyId;\n    }\n\n    public function getSecretKey(): string\n    {\n        return $this->secretKey;\n    }\n\n    public function getSessionToken(): ?string\n    {\n        return $this->sessionToken;\n    }\n\n    public function getExpireDate(): ?\\DateTimeImmutable\n    {\n        return $this->expireDate;\n    }\n\n    public function isExpired(): bool\n    {\n        return null !== $this->expireDate && new \\DateTimeImmutable() >= $this->expireDate;\n    }\n\n    public function getCredentials(Configuration $configuration): ?Credentials\n    {\n        return $this->isExpired() ? null : $this;\n    }\n\n    public static function adjustExpireDate(\\DateTimeImmutable $expireDate, ?\\DateTimeImmutable $reference = null): \\DateTimeImmutable\n    {\n        if (null !== $reference) {\n            $expireDate = (new \\DateTimeImmutable())->add($reference->diff($expireDate));\n        }\n\n        return $expireDate->sub(new \\DateInterval(\\sprintf('PT%dS', self::EXPIRATION_DRIFT)));\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Credentials/DateFromResult.php",
    "content": "<?php\n\nnamespace AsyncAws\\Core\\Credentials;\n\nuse AsyncAws\\Core\\Result;\n\n/**\n * @internal\n */\ntrait DateFromResult\n{\n    private function getDateFromResult(Result $result): ?\\DateTimeImmutable\n    {\n        $response = $result->info()['response'];\n        if (null !== $date = $response->getHeaders(false)['date'][0] ?? null) {\n            return new \\DateTimeImmutable($date);\n        }\n\n        return null;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Credentials/IniFileLoader.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace AsyncAws\\Core\\Credentials;\n\nuse AsyncAws\\Core\\EnvVar;\nuse Psr\\Log\\LoggerInterface;\nuse Psr\\Log\\NullLogger;\n\n/**\n * Load and parse AWS iniFile.\n *\n * @author Jérémy Derussé <jeremy@derusse.com>\n */\nfinal class IniFileLoader\n{\n    public const KEY_REGION = 'region';\n    public const KEY_ACCESS_KEY_ID = 'aws_access_key_id';\n    public const KEY_SECRET_ACCESS_KEY = 'aws_secret_access_key';\n    public const KEY_SESSION_TOKEN = 'aws_session_token';\n    public const KEY_ROLE_ARN = 'role_arn';\n    public const KEY_ROLE_SESSION_NAME = 'role_session_name';\n    public const KEY_SOURCE_PROFILE = 'source_profile';\n    public const KEY_WEB_IDENTITY_TOKEN_FILE = 'web_identity_token_file';\n    public const KEY_SSO_SESSION = 'sso_session';\n    public const KEY_SSO_START_URL = 'sso_start_url';\n    public const KEY_SSO_REGION = 'sso_region';\n    public const KEY_SSO_ACCOUNT_ID = 'sso_account_id';\n    public const KEY_SSO_ROLE_NAME = 'sso_role_name';\n\n    /**\n     * @var LoggerInterface\n     */\n    private $logger;\n\n    public function __construct(?LoggerInterface $logger = null)\n    {\n        $this->logger = $logger ?? new NullLogger();\n    }\n\n    /**\n     * @param string[] $filepaths\n     *\n     * @return array<string, array<string, string>>\n     */\n    public function loadProfiles(array $filepaths): array\n    {\n        $profilesData = [];\n        $homeDir = null;\n        foreach ($filepaths as $filepath) {\n            if ('' === $filepath) {\n                continue;\n            }\n            if ('~' === $filepath[0]) {\n                $homeDir = $homeDir ?? $this->getHomeDir();\n                $filepath = $homeDir . substr($filepath, 1);\n            }\n            if (!is_readable($filepath) || !is_file($filepath)) {\n                continue;\n            }\n\n            foreach ($this->parseIniFile($filepath) as $name => $profile) {\n                $name = preg_replace('/^profile /', '', (string) $name);\n                if (!isset($profilesData[$name])) {\n                    $profilesData[$name] = array_map('trim', $profile);\n                } else {\n                    foreach ($profile as $k => $v) {\n                        if (!isset($profilesData[$name][$k])) {\n                            $profilesData[$name][$k] = trim($v);\n                        }\n                    }\n                }\n            }\n        }\n\n        return $profilesData;\n    }\n\n    private function getHomeDir(): string\n    {\n        // On Linux/Unix-like systems, use the HOME environment variable\n        if (null !== $homeDir = EnvVar::get('HOME')) {\n            return $homeDir;\n        }\n\n        // Get the HOMEDRIVE and HOMEPATH values for Windows hosts\n        $homeDrive = EnvVar::get('HOMEDRIVE');\n        $homePath = EnvVar::get('HOMEPATH');\n\n        return ($homeDrive && $homePath) ? $homeDrive . $homePath : '/';\n    }\n\n    /**\n     * @return array<string, string[]>\n     */\n    private function parseIniFile(string $filepath): array\n    {\n        if (false === $data = parse_ini_string(\n            preg_replace('/^#/m', ';', file_get_contents($filepath)),\n            true,\n            \\INI_SCANNER_RAW\n        )) {\n            $this->logger->warning('The ini file {path} is invalid.', ['path' => $filepath]);\n\n            return [];\n        }\n\n        return $data;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Credentials/IniFileProvider.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace AsyncAws\\Core\\Credentials;\n\nuse AsyncAws\\Core\\Configuration;\nuse AsyncAws\\Core\\Exception\\RuntimeException;\nuse AsyncAws\\Core\\Sts\\StsClient;\nuse AsyncAws\\Sso\\SsoClient;\nuse AsyncAws\\SsoOidc\\SsoOidcClient;\nuse Psr\\Log\\LoggerInterface;\nuse Psr\\Log\\NullLogger;\nuse Symfony\\Contracts\\HttpClient\\HttpClientInterface;\n\n/**\n * Provides Credentials from standard AWS ini file.\n *\n * @see https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html\n *\n * @author Jérémy Derussé <jeremy@derusse.com>\n */\nfinal class IniFileProvider implements CredentialProvider\n{\n    use DateFromResult;\n\n    /**\n     * @var IniFileLoader\n     */\n    private $iniFileLoader;\n\n    /**\n     * @var LoggerInterface\n     */\n    private $logger;\n\n    /**\n     * @var HttpClientInterface|null\n     */\n    private $httpClient;\n\n    public function __construct(?LoggerInterface $logger = null, ?IniFileLoader $iniFileLoader = null, ?HttpClientInterface $httpClient = null)\n    {\n        $this->logger = $logger ?? new NullLogger();\n        $this->iniFileLoader = $iniFileLoader ?? new IniFileLoader($this->logger);\n        $this->httpClient = $httpClient;\n    }\n\n    public function getCredentials(Configuration $configuration): ?Credentials\n    {\n        $profilesData = $this->iniFileLoader->loadProfiles([\n            $configuration->get(Configuration::OPTION_SHARED_CREDENTIALS_FILE),\n            $configuration->get(Configuration::OPTION_SHARED_CONFIG_FILE),\n        ]);\n        if (empty($profilesData)) {\n            return null;\n        }\n\n        /** @var string $profile */\n        $profile = $configuration->get(Configuration::OPTION_PROFILE);\n\n        return $this->getCredentialsFromProfile($profilesData, $profile);\n    }\n\n    /**\n     * @param array<string, array<string, string>> $profilesData\n     * @param array<string, bool>                  $circularCollector\n     */\n    private function getCredentialsFromProfile(array $profilesData, string $profile, array $circularCollector = []): ?Credentials\n    {\n        if (isset($circularCollector[$profile])) {\n            $this->logger->warning('Circular reference detected when loading \"{profile}\". Already loaded {previous_profiles}', ['profile' => $profile, 'previous_profiles' => array_keys($circularCollector)]);\n\n            return null;\n        }\n        $circularCollector[$profile] = true;\n\n        if (!isset($profilesData[$profile])) {\n            $this->logger->warning('Profile \"{profile}\" not found.', ['profile' => $profile]);\n\n            return null;\n        }\n\n        $profileData = $profilesData[$profile];\n        if (isset($profileData[IniFileLoader::KEY_ACCESS_KEY_ID], $profileData[IniFileLoader::KEY_SECRET_ACCESS_KEY])) {\n            return new Credentials(\n                $profileData[IniFileLoader::KEY_ACCESS_KEY_ID],\n                $profileData[IniFileLoader::KEY_SECRET_ACCESS_KEY],\n                $profileData[IniFileLoader::KEY_SESSION_TOKEN] ?? null\n            );\n        }\n\n        if (isset($profileData[IniFileLoader::KEY_ROLE_ARN])) {\n            return $this->getCredentialsFromRole($profilesData, $profileData, $profile, $circularCollector);\n        }\n\n        if (isset($profileData[IniFileLoader::KEY_SSO_SESSION])) {\n            if (!class_exists(SsoClient::class) || !class_exists(SsoOidcClient::class)) {\n                $this->logger->warning('The profile \"{profile}\" contains SSO session config but the required packages (\"async-aws/sso\" and \"async-aws/sso-oidc\") are not installed. Try running \"composer require async-aws/sso async-aws/sso-oidc\".', ['profile' => $profile]);\n\n                return null;\n            }\n\n            return $this->getCredentialsFromSsoSession($profilesData, $profileData, $profile);\n        }\n\n        if (isset($profileData[IniFileLoader::KEY_SSO_START_URL])) {\n            if (!class_exists(SsoClient::class)) {\n                $this->logger->warning('The profile \"{profile}\" contains SSO (legacy) config but the \"async-aws/sso\" package is not installed. Try running \"composer require async-aws/sso\".', ['profile' => $profile]);\n\n                return null;\n            }\n\n            return $this->getCredentialsFromLegacySso($profileData, $profile);\n        }\n\n        $this->logger->info('No credentials found for profile \"{profile}\".', ['profile' => $profile]);\n\n        return null;\n    }\n\n    /**\n     * @param array<string, array<string, string>> $profilesData\n     * @param array<string, string>                $profileData\n     * @param array<string, bool>                  $circularCollector\n     */\n    private function getCredentialsFromRole(array $profilesData, array $profileData, string $profile, array $circularCollector = []): ?Credentials\n    {\n        $roleArn = (string) ($profileData[IniFileLoader::KEY_ROLE_ARN] ?? '');\n        $roleSessionName = (string) ($profileData[IniFileLoader::KEY_ROLE_SESSION_NAME] ?? uniqid('async-aws-', true));\n        if (null === $sourceProfileName = $profileData[IniFileLoader::KEY_SOURCE_PROFILE] ?? null) {\n            $this->logger->warning('The source profile is not defined in Role \"{profile}\".', ['profile' => $profile]);\n\n            return null;\n        }\n\n        $sourceCredentials = $this->getCredentialsFromProfile($profilesData, $sourceProfileName, $circularCollector);\n        if (null === $sourceCredentials) {\n            $this->logger->warning('The source profile \"{profile}\" does not contains valid credentials.', ['profile' => $profile]);\n\n            return null;\n        }\n\n        $stsClient = new StsClient(\n            isset($profilesData[$sourceProfileName][IniFileLoader::KEY_REGION]) ? ['region' => $profilesData[$sourceProfileName][IniFileLoader::KEY_REGION]] : [],\n            $sourceCredentials,\n            $this->httpClient\n        );\n        $result = $stsClient->assumeRole([\n            'RoleArn' => $roleArn,\n            'RoleSessionName' => $roleSessionName,\n        ]);\n\n        try {\n            if (null === $credentials = $result->getCredentials()) {\n                throw new RuntimeException('The AssumeRole response does not contains credentials');\n            }\n        } catch (\\Exception $e) {\n            $this->logger->warning('Failed to get credentials from assumed role in profile \"{profile}: {exception}\".', ['profile' => $profile, 'exception' => $e]);\n\n            return null;\n        }\n\n        return new Credentials(\n            $credentials->getAccessKeyId(),\n            $credentials->getSecretAccessKey(),\n            $credentials->getSessionToken(),\n            Credentials::adjustExpireDate($credentials->getExpiration(), $this->getDateFromResult($result))\n        );\n    }\n\n    /**\n     * @param array<string, array<string, string>> $profilesData\n     * @param array<string, string>                $profileData\n     */\n    private function getCredentialsFromSsoSession(array $profilesData, array $profileData, string $profile): ?Credentials\n    {\n        if (!isset($profileData[IniFileLoader::KEY_SSO_SESSION])) {\n            $this->logger->warning('Profile \"{profile}\" does not contains required SSO session config.', ['profile' => $profile]);\n\n            return null;\n        }\n\n        $sessionName = $profileData[IniFileLoader::KEY_SSO_SESSION];\n        if (!isset($profilesData['sso-session ' . $sessionName])) {\n            $this->logger->warning('Profile \"{profile}\" refers to a the \"{session}\" sso-session that is not present in the configuration file.', ['profile' => $profile, 'session' => $sessionName]);\n\n            return null;\n        }\n\n        $sessionData = $profilesData['sso-session ' . $sessionName];\n        if (!isset(\n            $sessionData[IniFileLoader::KEY_SSO_START_URL],\n            $sessionData[IniFileLoader::KEY_SSO_REGION]\n        )) {\n            $this->logger->warning('SSO Session \"{session}\" does not contains required SSO config.', ['session' => $sessionName]);\n\n            return null;\n        }\n\n        $ssoTokenProvider = new SsoTokenProvider($this->httpClient, $this->logger);\n        $token = $ssoTokenProvider->getToken($sessionName, $sessionData);\n        if (null === $token) {\n            return null;\n        }\n\n        return $this->getCredentialsFromSsoToken($profileData, $sessionData[IniFileLoader::KEY_SSO_REGION], $profile, $token);\n    }\n\n    /**\n     * @param array<string, string> $profileData\n     */\n    private function getCredentialsFromLegacySso(array $profileData, string $profile): ?Credentials\n    {\n        if (!isset(\n            $profileData[IniFileLoader::KEY_SSO_START_URL],\n            $profileData[IniFileLoader::KEY_SSO_REGION],\n            $profileData[IniFileLoader::KEY_SSO_ACCOUNT_ID],\n            $profileData[IniFileLoader::KEY_SSO_ROLE_NAME]\n        )) {\n            $this->logger->warning('Profile \"{profile}\" does not contains required legacy SSO config.', ['profile' => $profile]);\n\n            return null;\n        }\n\n        $ssoCacheFileLoader = new SsoCacheFileLoader($this->logger);\n        $tokenData = $ssoCacheFileLoader->loadSsoCacheFile($profileData[IniFileLoader::KEY_SSO_START_URL]);\n\n        if ([] === $tokenData) {\n            return null;\n        }\n\n        return $this->getCredentialsFromSsoToken($profileData, $profileData[IniFileLoader::KEY_SSO_REGION], $profile, $tokenData[SsoCacheFileLoader::KEY_ACCESS_TOKEN]);\n    }\n\n    private function getCredentialsFromSsoToken(array $profileData, string $ssoRegion, string $profile, string $accessToken): ?Credentials\n    {\n        $ssoClient = new SsoClient(\n            ['region' => $ssoRegion],\n            new NullProvider(), // no credentials required as we provide an access token via the role credentials request\n            $this->httpClient\n        );\n        $result = $ssoClient->getRoleCredentials([\n            'accessToken' => $accessToken,\n            'accountId' => $profileData[IniFileLoader::KEY_SSO_ACCOUNT_ID],\n            'roleName' => $profileData[IniFileLoader::KEY_SSO_ROLE_NAME],\n        ]);\n\n        try {\n            if (null === $credentials = $result->getRoleCredentials()) {\n                throw new RuntimeException('The RoleCredentials response does not contains credentials');\n            }\n            if (null === $accessKeyId = $credentials->getAccessKeyId()) {\n                throw new RuntimeException('The RoleCredentials response does not contain an accessKeyId');\n            }\n            if (null === $secretAccessKey = $credentials->getSecretAccessKey()) {\n                throw new RuntimeException('The RoleCredentials response does not contain a secretAccessKey');\n            }\n            if (null === $sessionToken = $credentials->getSessionToken()) {\n                throw new RuntimeException('The RoleCredentials response does not contain a sessionToken');\n            }\n            if (null === $expiration = $credentials->getExpiration()) {\n                throw new RuntimeException('The RoleCredentials response does not contain an expiration');\n            }\n        } catch (\\Exception $e) {\n            $this->logger->warning('Failed to get credentials from role credentials in profile \"{profile}: {exception}\".', ['profile' => $profile, 'exception' => $e]);\n\n            return null;\n        }\n\n        return new Credentials(\n            $accessKeyId,\n            $secretAccessKey,\n            $sessionToken,\n            (new \\DateTimeImmutable())->setTimestamp($expiration)\n        );\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Credentials/InstanceProvider.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace AsyncAws\\Core\\Credentials;\n\nuse AsyncAws\\Core\\Configuration;\nuse Psr\\Log\\LoggerInterface;\nuse Psr\\Log\\NullLogger;\nuse Symfony\\Component\\HttpClient\\Exception\\JsonException;\nuse Symfony\\Component\\HttpClient\\Exception\\TransportException;\nuse Symfony\\Component\\HttpClient\\HttpClient;\nuse Symfony\\Contracts\\HttpClient\\Exception\\DecodingExceptionInterface;\nuse Symfony\\Contracts\\HttpClient\\Exception\\HttpExceptionInterface;\nuse Symfony\\Contracts\\HttpClient\\Exception\\TransportExceptionInterface;\nuse Symfony\\Contracts\\HttpClient\\HttpClientInterface;\nuse Symfony\\Contracts\\HttpClient\\ResponseInterface;\n\n/**\n * Provides Credentials from the running EC2 metadata server using the IMDSv1 and IMDSv2.\n *\n * @see https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-retrieval.html\n *\n * @author Jérémy Derussé <jeremy@derusse.com>\n */\nfinal class InstanceProvider implements CredentialProvider\n{\n    private const TOKEN_ENDPOINT = 'http://169.254.169.254/latest/api/token';\n    private const METADATA_ENDPOINT = 'http://169.254.169.254/latest/meta-data/iam/security-credentials';\n\n    /**\n     * @var LoggerInterface\n     */\n    private $logger;\n\n    /**\n     * @var HttpClientInterface\n     */\n    private $httpClient;\n\n    /**\n     * @var float\n     */\n    private $timeout;\n\n    /**\n     * @var int\n     */\n    private $tokenTtl;\n\n    public function __construct(?HttpClientInterface $httpClient = null, ?LoggerInterface $logger = null, float $timeout = 1.0, int $tokenTtl = 21600)\n    {\n        $this->logger = $logger ?? new NullLogger();\n        $this->httpClient = $httpClient ?? HttpClient::create();\n        $this->timeout = $timeout;\n        $this->tokenTtl = $tokenTtl;\n    }\n\n    public function getCredentials(Configuration $configuration): ?Credentials\n    {\n        $token = $this->getToken();\n        $headers = [];\n\n        if (null !== $token) {\n            $headers = ['X-aws-ec2-metadata-token' => $token];\n        }\n\n        try {\n            // Fetch current Profile\n            $response = $this->httpClient->request('GET', self::METADATA_ENDPOINT, [\n                'timeout' => $this->timeout,\n                'headers' => $headers,\n            ]);\n            $profile = $response->getContent();\n\n            // Fetch credentials from profile\n            $response = $this->httpClient->request('GET', self::METADATA_ENDPOINT . '/' . $profile, [\n                'timeout' => $this->timeout,\n                'headers' => $headers,\n            ]);\n            $result = $this->toArray($response);\n\n            if ('Success' !== $result['Code']) {\n                $this->logger->info('Unexpected instance profile.', ['response_code' => $result['Code']]);\n\n                return null;\n            }\n        } catch (DecodingExceptionInterface $e) {\n            $this->logger->info('Failed to decode Credentials.', ['exception' => $e]);\n\n            return null;\n        } catch (TransportExceptionInterface|HttpExceptionInterface $e) {\n            $this->logger->info('Failed to fetch Profile from Instance Metadata.', ['exception' => $e]);\n\n            return null;\n        }\n\n        if (null !== $date = $response->getHeaders(false)['date'][0] ?? null) {\n            $date = new \\DateTimeImmutable($date);\n        }\n\n        return new Credentials(\n            $result['AccessKeyId'],\n            $result['SecretAccessKey'],\n            $result['Token'],\n            Credentials::adjustExpireDate(new \\DateTimeImmutable($result['Expiration']), $date)\n        );\n    }\n\n    /**\n     * Copy of Symfony\\Component\\HttpClient\\Response::toArray without assertion on Content-Type header.\n     *\n     * @return array<string, mixed>\n     */\n    private function toArray(ResponseInterface $response): array\n    {\n        if ('' === $content = $response->getContent(true)) {\n            throw new TransportException('Response body is empty.');\n        }\n\n        try {\n            $content = json_decode($content, true, 512, \\JSON_BIGINT_AS_STRING | (\\PHP_VERSION_ID >= 70300 ? \\JSON_THROW_ON_ERROR : 0));\n        } catch (\\JsonException $e) {\n            /** @psalm-suppress all */\n            throw new JsonException(\\sprintf('%s for \"%s\".', $e->getMessage(), $response->getInfo('url')), $e->getCode());\n        }\n\n        if (\\PHP_VERSION_ID < 70300 && \\JSON_ERROR_NONE !== json_last_error()) {\n            /** @psalm-suppress InvalidArgument */\n            throw new JsonException(\\sprintf('%s for \"%s\".', json_last_error_msg(), $response->getInfo('url')), json_last_error());\n        }\n\n        if (!\\is_array($content)) {\n            /** @psalm-suppress InvalidArgument */\n            throw new JsonException(\\sprintf('JSON content was expected to decode to an array, %s returned for \"%s\".', \\gettype($content), $response->getInfo('url')));\n        }\n\n        return $content;\n    }\n\n    private function getToken(): ?string\n    {\n        try {\n            $response = $this->httpClient->request('PUT', self::TOKEN_ENDPOINT,\n                [\n                    'timeout' => $this->timeout,\n                    'headers' => ['X-aws-ec2-metadata-token-ttl-seconds' => $this->tokenTtl],\n                ]\n            );\n\n            return $response->getContent();\n        } catch (TransportExceptionInterface|HttpExceptionInterface $e) {\n            $this->logger->info('Failed to fetch metadata token for IMDSv2, fallback to IMDSv1.', ['exception' => $e]);\n\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Credentials/NullProvider.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace AsyncAws\\Core\\Credentials;\n\nuse AsyncAws\\Core\\Configuration;\n\n/**\n * Returns null.\n *\n * @author Jérémy Derussé <jeremy@derusse.com>\n */\nfinal class NullProvider implements CredentialProvider\n{\n    public function getCredentials(Configuration $configuration): ?Credentials\n    {\n        return null;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Credentials/PsrCacheProvider.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace AsyncAws\\Core\\Credentials;\n\nuse AsyncAws\\Core\\Configuration;\nuse Psr\\Cache\\CacheException;\nuse Psr\\Cache\\CacheItemPoolInterface;\nuse Psr\\Log\\LoggerInterface;\n\n/**\n * Cache the Credential generated by the decorated CredentialProvider with PSR-6.\n *\n * The Credential will be reused until it expires.\n *\n * @author Jérémy Derussé <jeremy@derusse.com>\n */\nfinal class PsrCacheProvider implements CredentialProvider\n{\n    /**\n     * @var CacheItemPoolInterface\n     */\n    private $cache;\n\n    /**\n     * @var CredentialProvider\n     */\n    private $decorated;\n\n    /**\n     * @var LoggerInterface|null\n     */\n    private $logger;\n\n    public function __construct(CredentialProvider $decorated, CacheItemPoolInterface $cache, ?LoggerInterface $logger = null)\n    {\n        $this->decorated = $decorated;\n        $this->cache = $cache;\n        $this->logger = $logger;\n    }\n\n    public function getCredentials(Configuration $configuration): ?Credentials\n    {\n        try {\n            return $this->getFromCache($configuration);\n        } catch (CacheException $e) {\n            if (null !== $this->logger) {\n                $this->logger->error('Failed to get AWS credentials from cache.', ['exception' => $e]);\n            }\n\n            return $this->decorated->getCredentials($configuration);\n        }\n    }\n\n    /**\n     * @throws CacheException\n     */\n    private function getFromCache(Configuration $configuration): ?Credentials\n    {\n        $item = $this->cache->getItem('AsyncAws.Credentials.' . sha1(serialize([$configuration, \\get_class($this->decorated)])));\n        if (!$item->isHit()) {\n            $item->set($credential = $this->decorated->getCredentials($configuration));\n\n            if (null !== $credential && null !== $exp = $credential->getExpireDate()) {\n                $item->expiresAt($exp);\n                $this->cache->save($item);\n            }\n        }\n\n        return $item->get();\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Credentials/SsoCacheFileLoader.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace AsyncAws\\Core\\Credentials;\n\nuse AsyncAws\\Core\\EnvVar;\nuse Psr\\Log\\LoggerInterface;\nuse Psr\\Log\\NullLogger;\n\n/**\n * Load and parse AWS SSO cache file.\n *\n * @internal\n */\nfinal class SsoCacheFileLoader\n{\n    public const KEY_ACCESS_TOKEN = 'accessToken';\n    public const KEY_EXPIRES_AT = 'expiresAt';\n\n    /**\n     * @var LoggerInterface\n     */\n    private $logger;\n\n    public function __construct(?LoggerInterface $logger = null)\n    {\n        $this->logger = $logger ?? new NullLogger();\n    }\n\n    /**\n     * @return array<string, string>\n     */\n    public function loadSsoCacheFile(string $ssoStartUrl): array\n    {\n        $filepath = \\sprintf('%s/.aws/sso/cache/%s.json', $this->getHomeDir(), sha1($ssoStartUrl));\n\n        if (false === ($contents = @file_get_contents($filepath))) {\n            $this->logger->warning('The sso cache file {path} is not readable.', ['path' => $filepath]);\n\n            return [];\n        }\n\n        $tokenData = json_decode($contents, true);\n        if (!isset($tokenData[self::KEY_ACCESS_TOKEN], $tokenData[self::KEY_EXPIRES_AT])) {\n            $this->logger->warning('Token file at {path} must contain an accessToken and an expiresAt.', ['path' => $filepath]);\n\n            return [];\n        }\n\n        try {\n            $expiration = (new \\DateTimeImmutable($tokenData[self::KEY_EXPIRES_AT]));\n        } catch (\\Exception $e) {\n            $this->logger->warning('Cached SSO credentials returned an invalid expiresAt value.');\n\n            return [];\n        }\n\n        if ($expiration < new \\DateTimeImmutable()) {\n            $this->logger->warning('Cached SSO credentials returned an invalid expiresAt value.');\n\n            return [];\n        }\n\n        return $tokenData;\n    }\n\n    private function getHomeDir(): string\n    {\n        // On Linux/Unix-like systems, use the HOME environment variable\n        if (null !== $homeDir = EnvVar::get('HOME')) {\n            return $homeDir;\n        }\n\n        // Get the HOMEDRIVE and HOMEPATH values for Windows hosts\n        $homeDrive = EnvVar::get('HOMEDRIVE');\n        $homePath = EnvVar::get('HOMEPATH');\n\n        return ($homeDrive && $homePath) ? $homeDrive . $homePath : '/';\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Credentials/SsoTokenProvider.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace AsyncAws\\Core\\Credentials;\n\nuse AsyncAws\\Core\\EnvVar;\nuse AsyncAws\\SsoOidc\\SsoOidcClient;\nuse Psr\\Log\\LoggerInterface;\nuse Psr\\Log\\NullLogger;\nuse Symfony\\Contracts\\HttpClient\\HttpClientInterface;\n\n/**\n * Load and refresh AWS SSO tokens.\n *\n * @internal\n */\nfinal class SsoTokenProvider\n{\n    public const KEY_CLIENT_ID = 'clientId';\n    public const KEY_CLIENT_SECRET = 'clientSecret';\n    public const KEY_REFRESH_TOKEN = 'refreshToken';\n    public const KEY_ACCESS_TOKEN = 'accessToken';\n    public const KEY_EXPIRES_AT = 'expiresAt';\n\n    private const REFRESH_WINDOW = 300;\n\n    /**\n     * @var LoggerInterface\n     */\n    private $logger;\n\n    /**\n     * @var ?HttpClientInterface\n     */\n    private $httpClient;\n\n    public function __construct(?HttpClientInterface $httpClient = null, ?LoggerInterface $logger = null)\n    {\n        $this->httpClient = $httpClient;\n        $this->logger = $logger ?? new NullLogger();\n    }\n\n    /**\n     * @param array<string, string> $sessionData\n     */\n    public function getToken(string $sessionName, array $sessionData): ?string\n    {\n        $tokenData = $this->loadSsoToken($sessionName);\n        if (null === $tokenData) {\n            return null;\n        }\n\n        $tokenData = $this->refreshTokenIfNeeded($sessionName, $sessionData, $tokenData);\n        if (!isset($tokenData[self::KEY_ACCESS_TOKEN])) {\n            $this->logger->warning('The token for SSO session \"{session}\" does not contains accessToken.', ['session' => $sessionName]);\n\n            return null;\n        }\n\n        return $tokenData[self::KEY_ACCESS_TOKEN];\n    }\n\n    /**\n     * @param array<string, string> $sessionData\n     */\n    private function refreshTokenIfNeeded(string $sessionName, array $sessionData, array $tokenData): array\n    {\n        if (!isset($tokenData[self::KEY_EXPIRES_AT])) {\n            $this->logger->warning('The token for SSO session \"{session}\" does not contains expiration date.', ['session' => $sessionName]);\n\n            return $tokenData;\n        }\n\n        $tokenExpiresAt = new \\DateTimeImmutable($tokenData[self::KEY_EXPIRES_AT]);\n        $tokenRefreshAt = $tokenExpiresAt->sub(new \\DateInterval(\\sprintf('PT%dS', self::REFRESH_WINDOW)));\n\n        // If token expiration is in the 5 minutes window\n        if ($tokenRefreshAt > new \\DateTimeImmutable()) {\n            return $tokenData;\n        }\n\n        if (!isset(\n            $tokenData[self::KEY_CLIENT_ID],\n            $tokenData[self::KEY_CLIENT_SECRET],\n            $tokenData[self::KEY_REFRESH_TOKEN]\n        )) {\n            $this->logger->warning('The token for SSO session \"{session}\" does not contains required properties and cannot be refreshed.', ['session' => $sessionName]);\n\n            return $tokenData;\n        }\n\n        $ssoOidcClient = new SsoOidcClient(\n            ['region' => $sessionData[IniFileLoader::KEY_SSO_REGION]],\n            new NullProvider(),\n            // no credentials required as we provide an access token via the role credentials request\n            $this->httpClient\n        );\n\n        $result = $ssoOidcClient->createToken([\n            'clientId' => $tokenData[self::KEY_CLIENT_ID],\n            'clientSecret' => $tokenData[self::KEY_CLIENT_SECRET],\n            'grantType' => 'refresh_token', // REQUIRED\n            'refreshToken' => $tokenData[self::KEY_REFRESH_TOKEN],\n        ]);\n\n        $tokenData = [\n            self::KEY_ACCESS_TOKEN => $result->getAccessToken(),\n            self::KEY_REFRESH_TOKEN => $result->getRefreshToken(),\n        ] + $tokenData;\n\n        if (null === $expiresIn = $result->getExpiresIn()) {\n            $this->logger->warning('The token for SSO session \"{session}\" does not contains expiration time.', ['session' => $sessionName]);\n        } else {\n            $tokenData[self::KEY_EXPIRES_AT] = (new \\DateTimeImmutable())->add(new \\DateInterval(\\sprintf('PT%dS', $expiresIn)))->format(\\DateTime::ATOM);\n        }\n\n        $this->dumpSsoToken($sessionName, $tokenData);\n\n        return $tokenData;\n    }\n\n    private function dumpSsoToken(string $sessionName, array $tokenData): void\n    {\n        $filepath = \\sprintf('%s/.aws/sso/cache/%s.json', $this->getHomeDir(), sha1($sessionName));\n\n        file_put_contents($filepath, json_encode(array_filter($tokenData)));\n    }\n\n    /**\n     * @return array<string, string>|null\n     */\n    private function loadSsoToken(string $sessionName): ?array\n    {\n        $filepath = \\sprintf('%s/.aws/sso/cache/%s.json', $this->getHomeDir(), sha1($sessionName));\n        if (!is_readable($filepath)) {\n            $this->logger->warning('The sso cache file {path} is not readable.', ['path' => $filepath]);\n\n            return null;\n        }\n\n        if (false === ($content = @file_get_contents($filepath))) {\n            $this->logger->warning('The sso cache file {path} is not readable.', ['path' => $filepath]);\n\n            return null;\n        }\n\n        try {\n            return json_decode(\n                $content,\n                true,\n                512,\n                \\JSON_BIGINT_AS_STRING | (\\PHP_VERSION_ID >= 70300 ? \\JSON_THROW_ON_ERROR : 0)\n            );\n        } catch (\\JsonException $e) {\n            $this->logger->warning(\n                'The sso cache file {path} contains invalide JSON.',\n                ['path' => $filepath, 'ecxeption' => $e]\n            );\n\n            return null;\n        }\n    }\n\n    private function getHomeDir(): string\n    {\n        // On Linux/Unix-like systems, use the HOME environment variable\n        if (null !== $homeDir = EnvVar::get('HOME')) {\n            return $homeDir;\n        }\n\n        // Get the HOMEDRIVE and HOMEPATH values for Windows hosts\n        $homeDrive = EnvVar::get('HOMEDRIVE');\n        $homePath = EnvVar::get('HOMEPATH');\n\n        return ($homeDrive && $homePath) ? $homeDrive . $homePath : '/';\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Credentials/SymfonyCacheProvider.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace AsyncAws\\Core\\Credentials;\n\nuse AsyncAws\\Core\\Configuration;\nuse Psr\\Cache\\CacheException;\nuse Psr\\Log\\LoggerInterface;\nuse Symfony\\Contracts\\Cache\\CacheInterface;\nuse Symfony\\Contracts\\Cache\\ItemInterface;\n\n/**\n * Cache the Credential generated by the decorated CredentialProvider with Symfony Cache.\n * Symfony Cache provides stampede protection which is preferred on applications with more than\n * 1 or 2 requests per second.\n *\n * The Credential will be reused until it expires.\n *\n * @author Jérémy Derussé <jeremy@derusse.com>\n */\nfinal class SymfonyCacheProvider implements CredentialProvider\n{\n    /**\n     * @var CacheInterface\n     */\n    private $cache;\n\n    /**\n     * @var CredentialProvider\n     */\n    private $decorated;\n\n    /**\n     * @var LoggerInterface|null\n     */\n    private $logger;\n\n    public function __construct(CredentialProvider $decorated, CacheInterface $cache, ?LoggerInterface $logger = null)\n    {\n        $this->decorated = $decorated;\n        $this->cache = $cache;\n        $this->logger = $logger;\n    }\n\n    public function getCredentials(Configuration $configuration): ?Credentials\n    {\n        $provider = $this->decorated;\n        $closure = \\Closure::fromCallable(static function (ItemInterface $item) use ($configuration, $provider) {\n            $credential = $provider->getCredentials($configuration);\n\n            if (null !== $credential && null !== $exp = $credential->getExpireDate()) {\n                $item->expiresAt($exp);\n            } else {\n                $item->expiresAfter(0);\n            }\n\n            return $credential;\n        });\n\n        try {\n            return $this->cache->get('AsyncAws.Credentials.' . sha1(serialize([$configuration, \\get_class($this->decorated)])), $closure);\n        } catch (CacheException $e) {\n            if (null !== $this->logger) {\n                $this->logger->error('Failed to get AWS credentials from cache.', ['exception' => $e]);\n            }\n\n            return $provider->getCredentials($configuration);\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Credentials/TokenFileLoader.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace AsyncAws\\Core\\Credentials;\n\nuse AsyncAws\\Core\\Exception\\RuntimeException;\n\ntrait TokenFileLoader\n{\n    /**\n     * @see https://github.com/async-aws/aws/issues/900\n     * @see https://github.com/aws/aws-sdk-php/issues/2014\n     * @see https://github.com/aws/aws-sdk-php/pull/2043\n     */\n    public function getTokenFileContent(string $tokenFile): string\n    {\n        $token = @file_get_contents($tokenFile);\n\n        if (false !== $token) {\n            return $token;\n        }\n\n        $tokenDir = \\dirname($tokenFile);\n        $tokenLink = readlink($tokenFile);\n        clearstatcache(true, $tokenDir . \\DIRECTORY_SEPARATOR . $tokenLink);\n        clearstatcache(true, $tokenDir . \\DIRECTORY_SEPARATOR . \\dirname($tokenLink));\n        clearstatcache(true, $tokenFile);\n\n        if (false === $token = file_get_contents($tokenFile)) {\n            throw new RuntimeException('Failed to read data');\n        }\n\n        return $token;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Credentials/WebIdentityProvider.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace AsyncAws\\Core\\Credentials;\n\nuse AsyncAws\\Core\\Configuration;\nuse AsyncAws\\Core\\Exception\\RuntimeException;\nuse AsyncAws\\Core\\Sts\\StsClient;\nuse Psr\\Log\\LoggerInterface;\nuse Psr\\Log\\NullLogger;\nuse Symfony\\Contracts\\HttpClient\\HttpClientInterface;\n\n/**\n * Provides Credentials from Web Identity or OpenID Connect Federation.\n *\n * @see https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-idp_oidc.html\n *\n * @author Jérémy Derussé <jeremy@derusse.com>\n */\nfinal class WebIdentityProvider implements CredentialProvider\n{\n    use DateFromResult;\n    use TokenFileLoader;\n\n    /**\n     * @var IniFileLoader\n     */\n    private $iniFileLoader;\n\n    /**\n     * @var LoggerInterface\n     */\n    private $logger;\n\n    /**\n     * @var HttpClientInterface|null\n     */\n    private $httpClient;\n\n    public function __construct(?LoggerInterface $logger = null, ?IniFileLoader $iniFileLoader = null, ?HttpClientInterface $httpClient = null)\n    {\n        $this->logger = $logger ?? new NullLogger();\n        $this->iniFileLoader = $iniFileLoader ?? new IniFileLoader($this->logger);\n        $this->httpClient = $httpClient;\n    }\n\n    public function getCredentials(Configuration $configuration): ?Credentials\n    {\n        $roleArn = $configuration->get(Configuration::OPTION_ROLE_ARN);\n        $tokenFile = $configuration->get(Configuration::OPTION_WEB_IDENTITY_TOKEN_FILE);\n\n        if ($tokenFile && $roleArn) {\n            return $this->getCredentialsFromRole(\n                $roleArn,\n                $tokenFile,\n                $configuration->get(Configuration::OPTION_ROLE_SESSION_NAME),\n                $configuration->get(Configuration::OPTION_REGION)\n            );\n        }\n\n        $profilesData = $this->iniFileLoader->loadProfiles([\n            $configuration->get(Configuration::OPTION_SHARED_CREDENTIALS_FILE),\n            $configuration->get(Configuration::OPTION_SHARED_CONFIG_FILE),\n        ]);\n        if (empty($profilesData)) {\n            return null;\n        }\n\n        /** @var string $profile */\n        $profile = $configuration->get(Configuration::OPTION_PROFILE);\n        if (!isset($profilesData[$profile])) {\n            $this->logger->warning('Profile \"{profile}\" not found.', ['profile' => $profile]);\n\n            return null;\n        }\n\n        $profileData = $profilesData[$profile];\n        $roleArn = $profileData[IniFileLoader::KEY_ROLE_ARN] ?? null;\n        $tokenFile = $profileData[IniFileLoader::KEY_WEB_IDENTITY_TOKEN_FILE] ?? null;\n\n        if (null !== $roleArn && null !== $tokenFile) {\n            return $this->getCredentialsFromRole(\n                $roleArn,\n                $tokenFile,\n                $profileData[IniFileLoader::KEY_ROLE_SESSION_NAME] ?? null,\n                $profileData[IniFileLoader::KEY_REGION] ?? $configuration->get(Configuration::OPTION_REGION)\n            );\n        }\n\n        return null;\n    }\n\n    private function getCredentialsFromRole(string $roleArn, string $tokenFile, ?string $sessionName, ?string $region): ?Credentials\n    {\n        $sessionName = $sessionName ?? uniqid('async-aws-', true);\n        if (!preg_match(\"/^\\w\\:|^\\/|^\\\\\\/\", $tokenFile)) {\n            $this->logger->warning('WebIdentityTokenFile \"{tokenFile}\" must be an absolute path.', ['tokenFile' => $tokenFile]);\n        }\n\n        try {\n            $token = $this->getTokenFileContent($tokenFile);\n        } catch (\\Exception $e) {\n            $this->logger->warning('\"Error reading WebIdentityTokenFile \"{tokenFile}.', ['tokenFile' => $tokenFile, 'exception' => $e]);\n\n            return null;\n        }\n\n        $stsClient = new StsClient(['region' => $region], new NullProvider(), $this->httpClient);\n        $result = $stsClient->assumeRoleWithWebIdentity([\n            'RoleArn' => $roleArn,\n            'RoleSessionName' => $sessionName,\n            'WebIdentityToken' => $token,\n        ]);\n\n        try {\n            if (null === $credentials = $result->getCredentials()) {\n                throw new RuntimeException('The AssumeRoleWithWebIdentity response does not contains credentials');\n            }\n        } catch (\\Exception $e) {\n            $this->logger->warning('Failed to get credentials from assumed role: {exception}\".', ['exception' => $e]);\n\n            return null;\n        }\n\n        return new Credentials(\n            $credentials->getAccessKeyId(),\n            $credentials->getSecretAccessKey(),\n            $credentials->getSessionToken(),\n            Credentials::adjustExpireDate($credentials->getExpiration(), $this->getDateFromResult($result))\n        );\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/EndpointDiscovery/EndpointCache.php",
    "content": "<?php\n\nnamespace AsyncAws\\Core\\EndpointDiscovery;\n\nuse AsyncAws\\Core\\Exception\\LogicException;\n\n/**\n * @author Jérémy Derussé <jeremy@derusse.com>\n *\n * @internal\n */\nclass EndpointCache\n{\n    /**\n     * @var array<string, array<string, int>>\n     */\n    private $endpoints = [];\n\n    /**\n     * @var array<string, array<string, int>>\n     */\n    private $expired = [];\n\n    /**\n     * @param EndpointInterface[] $endpoints\n     */\n    public function addEndpoints(?string $region, array $endpoints): void\n    {\n        $now = time();\n\n        if (null === $region) {\n            $region = '';\n        }\n        if (!isset($this->endpoints[$region])) {\n            $this->endpoints[$region] = [];\n        }\n\n        foreach ($endpoints as $endpoint) {\n            $this->endpoints[$region][$this->sanitizeEndpoint($endpoint->getAddress())] = $now + ($endpoint->getCachePeriodInMinutes() * 60);\n        }\n        arsort($this->endpoints[$region]);\n    }\n\n    public function removeEndpoint(string $endpoint): void\n    {\n        $endpoint = $this->sanitizeEndpoint($endpoint);\n        foreach ($this->endpoints as &$endpoints) {\n            unset($endpoints[$endpoint]);\n        }\n        unset($endpoints);\n        foreach ($this->expired as &$endpoints) {\n            unset($endpoints[$endpoint]);\n        }\n\n        unset($endpoints);\n    }\n\n    public function getActiveEndpoint(?string $region): ?string\n    {\n        if (null === $region) {\n            $region = '';\n        }\n        $now = time();\n\n        foreach ($this->endpoints[$region] ?? [] as $endpoint => $expiresAt) {\n            if ($expiresAt < $now) {\n                $this->expired[$region] = \\array_slice($this->expired[$region] ?? [], -100); // keep only the last 100 items\n                unset($this->endpoints[$region][$endpoint]);\n                $this->expired[$region][$endpoint] = $expiresAt;\n\n                continue;\n            }\n\n            return $endpoint;\n        }\n\n        return null;\n    }\n\n    public function getExpiredEndpoint(?string $region): ?string\n    {\n        if (null === $region) {\n            $region = '';\n        }\n        if (empty($this->expired[$region])) {\n            return null;\n        }\n\n        return array_key_last($this->expired[$region]);\n    }\n\n    private function sanitizeEndpoint(string $address): string\n    {\n        $parsed = parse_url($address);\n\n        // parse_url() will correctly parse full URIs with schemes\n        if (isset($parsed['host'])) {\n            return rtrim(\\sprintf(\n                '%s://%s/%s',\n                $parsed['scheme'] ?? 'https',\n                $parsed['host'],\n                ltrim($parsed['path'] ?? '/', '/')\n            ), '/');\n        }\n\n        // parse_url() will put host & path in 'path' if scheme is not provided\n        if (isset($parsed['path'])) {\n            $split = explode('/', $parsed['path'], 2);\n            $parsed['host'] = $split[0];\n            if (isset($split[1])) {\n                $parsed['path'] = $split[1];\n            } else {\n                $parsed['path'] = '';\n            }\n\n            return rtrim(\\sprintf(\n                '%s://%s/%s',\n                $parsed['scheme'] ?? 'https',\n                $parsed['host'],\n                ltrim($parsed['path'], '/')\n            ), '/');\n        }\n\n        throw new LogicException(\\sprintf('The supplied endpoint \"%s\" is invalid.', $address));\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/EndpointDiscovery/EndpointInterface.php",
    "content": "<?php\n\nnamespace AsyncAws\\Core\\EndpointDiscovery;\n\ninterface EndpointInterface\n{\n    public function getAddress(): string;\n\n    public function getCachePeriodInMinutes(): int;\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/EnvVar.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace AsyncAws\\Core;\n\n/**\n * Helper to safely read environment variables.\n *\n * @author Jérémy Derussé <jeremy@derusse.com>\n *\n * @internal\n */\nfinal class EnvVar\n{\n    public static function get(string $name): ?string\n    {\n        if (isset($_ENV[$name])) {\n            // variable_order = *E*GPCS\n            return (string) $_ENV[$name];\n        } elseif (isset($_SERVER[$name]) && !\\is_array($_SERVER[$name]) && 0 !== strpos($name, 'HTTP_')) {\n            // fastcgi_param, env var, ...\n            return (string) $_SERVER[$name];\n        } elseif (false === $env = getenv($name)) {\n            // getenv not thread safe\n            return null;\n        }\n\n        return $env;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Exception/Exception.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace AsyncAws\\Core\\Exception;\n\n/**\n * All exceptions implements this interface.\n *\n * @author Tobias Nyholm <tobias.nyholm@gmail.com>\n */\ninterface Exception extends \\Throwable\n{\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Exception/Http/ClientException.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace AsyncAws\\Core\\Exception\\Http;\n\nuse Symfony\\Contracts\\HttpClient\\Exception\\ClientExceptionInterface;\n\n/**\n * Represents a 4xx response.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n */\nclass ClientException extends \\RuntimeException implements ClientExceptionInterface, HttpException\n{\n    use HttpExceptionTrait;\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Exception/Http/HttpException.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace AsyncAws\\Core\\Exception\\Http;\n\nuse AsyncAws\\Core\\Exception\\Exception;\nuse Symfony\\Contracts\\HttpClient\\ResponseInterface;\n\ninterface HttpException extends Exception\n{\n    public function getResponse(): ResponseInterface;\n\n    public function getAwsCode(): ?string;\n\n    public function getAwsType(): ?string;\n\n    public function getAwsMessage(): ?string;\n\n    public function getAwsDetail(): ?string;\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Exception/Http/HttpExceptionTrait.php",
    "content": "<?php\n\nnamespace AsyncAws\\Core\\Exception\\Http;\n\nuse AsyncAws\\Core\\AwsError\\AwsError;\nuse Symfony\\Contracts\\HttpClient\\ResponseInterface;\n\n/**\n * @author Nicolas Grekas <p@tchwork.com>\n * @author Tobias Nyholm <tobias.nyholm@gmail.com>\n * @author Jérémy Derussé <jeremy@derusse.com>\n *\n * @internal\n */\ntrait HttpExceptionTrait\n{\n    /**\n     * @var ResponseInterface\n     */\n    private $response;\n\n    /**\n     * @var ?AwsError\n     */\n    private $awsError;\n\n    public function __construct(ResponseInterface $response, ?AwsError $awsError = null)\n    {\n        $this->response = $response;\n        /** @var int $code */\n        $code = $response->getInfo('http_code');\n        /** @var string $url */\n        $url = $response->getInfo('url');\n\n        $message = \\sprintf('HTTP %d returned for \"%s\".', $code, $url);\n        if (null !== $this->awsError = $awsError) {\n            $message .= <<<TEXT\n\n\nCode:    {$this->awsError->getCode()}\nMessage: {$this->awsError->getMessage()}\nType:    {$this->awsError->getType()}\nDetail:  {$this->awsError->getDetail()}\n\nTEXT;\n        }\n\n        parent::__construct($message, $code);\n\n        $this->populateResult($response);\n    }\n\n    public function getResponse(): ResponseInterface\n    {\n        return $this->response;\n    }\n\n    public function getAwsCode(): ?string\n    {\n        return $this->awsError ? $this->awsError->getCode() : null;\n    }\n\n    public function getAwsType(): ?string\n    {\n        return $this->awsError ? $this->awsError->getType() : null;\n    }\n\n    public function getAwsMessage(): ?string\n    {\n        return $this->awsError ? $this->awsError->getMessage() : null;\n    }\n\n    public function getAwsDetail(): ?string\n    {\n        return $this->awsError ? $this->awsError->getDetail() : null;\n    }\n\n    protected function populateResult(ResponseInterface $response): void\n    {\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Exception/Http/NetworkException.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace AsyncAws\\Core\\Exception\\Http;\n\nuse AsyncAws\\Core\\Exception\\Exception;\nuse Symfony\\Contracts\\HttpClient\\Exception\\TransportExceptionInterface;\n\n/**\n * Request could not be sent due network error.\n *\n * @author Tobias Nyholm <tobias.nyholm@gmail.com>\n */\nclass NetworkException extends \\RuntimeException implements Exception, TransportExceptionInterface\n{\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Exception/Http/RedirectionException.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace AsyncAws\\Core\\Exception\\Http;\n\nuse Symfony\\Contracts\\HttpClient\\Exception\\RedirectionExceptionInterface;\n\n/**\n * Represents a 3xx response.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n */\nfinal class RedirectionException extends \\RuntimeException implements HttpException, RedirectionExceptionInterface\n{\n    use HttpExceptionTrait;\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Exception/Http/ServerException.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace AsyncAws\\Core\\Exception\\Http;\n\nuse Symfony\\Contracts\\HttpClient\\Exception\\ServerExceptionInterface;\n\n/**\n * Represents a 5xx response.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n */\nclass ServerException extends \\RuntimeException implements HttpException, ServerExceptionInterface\n{\n    use HttpExceptionTrait;\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Exception/InvalidArgument.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace AsyncAws\\Core\\Exception;\n\nclass InvalidArgument extends \\InvalidArgumentException implements Exception\n{\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Exception/LogicException.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace AsyncAws\\Core\\Exception;\n\nclass LogicException extends \\LogicException implements Exception\n{\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Exception/MissingDependency.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace AsyncAws\\Core\\Exception;\n\nclass MissingDependency extends \\RuntimeException implements Exception\n{\n    /**\n     * @return self\n     */\n    public static function create(string $package, string $name)\n    {\n        return new self(\\sprintf('In order to use \"%s\" you need to install \"%s\". Run \"composer require %s\" and all your problems are solved.', $name, $package, $package));\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Exception/RuntimeException.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace AsyncAws\\Core\\Exception;\n\nclass RuntimeException extends \\RuntimeException implements Exception\n{\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Exception/UnexpectedValue.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace AsyncAws\\Core\\Exception;\n\nclass UnexpectedValue extends \\UnexpectedValueException implements Exception\n{\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Exception/UnparsableResponse.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace AsyncAws\\Core\\Exception;\n\nclass UnparsableResponse extends \\RuntimeException implements Exception\n{\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Exception/UnsupportedRegion.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace AsyncAws\\Core\\Exception;\n\nclass UnsupportedRegion extends InvalidArgument\n{\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/HttpClient/AwsHttpClientFactory.php",
    "content": "<?php\n\nnamespace AsyncAws\\Core\\HttpClient;\n\nuse Psr\\Log\\LoggerInterface;\nuse Symfony\\Component\\HttpClient\\HttpClient;\nuse Symfony\\Component\\HttpClient\\RetryableHttpClient;\nuse Symfony\\Contracts\\HttpClient\\HttpClientInterface;\n\n/**\n * @author Jérémy Derussé <jeremy@derusse.com>\n */\nclass AwsHttpClientFactory\n{\n    public static function createRetryableClient(?HttpClientInterface $httpClient = null, ?LoggerInterface $logger = null): HttpClientInterface\n    {\n        if (null === $httpClient) {\n            $httpClient = HttpClient::create();\n        }\n        if (class_exists(RetryableHttpClient::class)) {\n            /** @psalm-suppress MissingDependency */\n            $httpClient = new RetryableHttpClient(\n                $httpClient,\n                new AwsRetryStrategy(),\n                3,\n                $logger\n            );\n        }\n\n        return $httpClient;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/HttpClient/AwsRetryStrategy.php",
    "content": "<?php\n\nnamespace AsyncAws\\Core\\HttpClient;\n\nuse AsyncAws\\Core\\AwsError\\AwsErrorFactoryInterface;\nuse AsyncAws\\Core\\AwsError\\ChainAwsErrorFactory;\nuse AsyncAws\\Core\\Exception\\UnparsableResponse;\nuse Symfony\\Component\\HttpClient\\Response\\AsyncContext;\nuse Symfony\\Component\\HttpClient\\Retry\\GenericRetryStrategy;\nuse Symfony\\Contracts\\HttpClient\\Exception\\TransportExceptionInterface;\n\n/**\n * @author Jérémy Derussé <jeremy@derusse.com>\n */\nclass AwsRetryStrategy extends GenericRetryStrategy\n{\n    // Override Symfony default options for a better integration of AWS servers.\n    public const DEFAULT_RETRY_STATUS_CODES = [0, 423, 425, 429, 500, 502, 503, 504, 507, 510];\n\n    /**\n     * @var AwsErrorFactoryInterface\n     */\n    private $awsErrorFactory;\n\n    /**\n     * @param array<int, int|string[]> $statusCodes\n     */\n    public function __construct(array $statusCodes = self::DEFAULT_RETRY_STATUS_CODES, int $delayMs = 1000, float $multiplier = 2.0, int $maxDelayMs = 0, float $jitter = 0.1, ?AwsErrorFactoryInterface $awsErrorFactory = null)\n    {\n        parent::__construct($statusCodes, $delayMs, $multiplier, $maxDelayMs, $jitter);\n        $this->awsErrorFactory = $awsErrorFactory ?? new ChainAwsErrorFactory();\n    }\n\n    public function shouldRetry(AsyncContext $context, ?string $responseContent, ?TransportExceptionInterface $exception): ?bool\n    {\n        if (parent::shouldRetry($context, $responseContent, $exception)) {\n            return true;\n        }\n\n        if (!\\in_array($context->getStatusCode(), [400, 403], true)) {\n            return false;\n        }\n\n        if (null === $responseContent) {\n            return null; // null mean no decision taken and need to be called again with the body\n        }\n\n        try {\n            $error = $this->awsErrorFactory->createFromContent($responseContent, $context->getHeaders());\n        } catch (UnparsableResponse $e) {\n            return false;\n        }\n\n        return \\in_array($error->getCode(), [\n            'RequestLimitExceeded',\n            'Throttling',\n            'ThrottlingException',\n            'ThrottledException',\n            'LimitExceededException',\n            'PriorRequestNotComplete',\n            'ProvisionedThroughputExceededException',\n            'RequestThrottled',\n            'SlowDown',\n            'BandwidthLimitExceeded',\n            'RequestThrottledException',\n            'RetryableThrottlingException',\n            'TooManyRequestsException',\n            'IDPCommunicationError',\n            'EC2ThrottledException',\n            'TransactionInProgressException',\n        ], true);\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Input.php",
    "content": "<?php\n\nnamespace AsyncAws\\Core;\n\n/**\n * Representation of a AWS Request.\n *\n * @author Jérémy Derussé <jeremy@derusse.com>\n */\nabstract class Input\n{\n    /**\n     * @var string|null\n     */\n    public $region;\n\n    /**\n     * @param array{'@region'?: ?string,...} $input\n     */\n    protected function __construct(array $input)\n    {\n        $this->region = $input['@region'] ?? null;\n    }\n\n    public function setRegion(?string $region): void\n    {\n        $this->region = $region;\n    }\n\n    public function getRegion(): ?string\n    {\n        return $this->region;\n    }\n\n    abstract public function request(): Request;\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Request.php",
    "content": "<?php\n\nnamespace AsyncAws\\Core;\n\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\nuse AsyncAws\\Core\\Exception\\LogicException;\nuse AsyncAws\\Core\\Stream\\RequestStream;\n\n/**\n * Representation of an HTTP Request.\n *\n * @author Jérémy Derussé <jeremy@derusse.com>\n */\nfinal class Request\n{\n    /**\n     * @var string\n     */\n    private $method;\n\n    /**\n     * @var string\n     */\n    private $uri;\n\n    /**\n     * @var array<string, string>\n     */\n    private $headers;\n\n    /**\n     * @var RequestStream\n     */\n    private $body;\n\n    /**\n     * @var string|null\n     */\n    private $queryString;\n\n    /**\n     * @var array<string, string>\n     */\n    private $query;\n\n    /**\n     * @var string\n     */\n    private $endpoint;\n\n    /**\n     * @var string\n     */\n    private $hostPrefix;\n\n    /**\n     * @var array{scheme: string, host: string, port: int|null}|null\n     */\n    private $parsed;\n\n    /**\n     * @param array<string, string> $query\n     * @param array<string, string> $headers\n     */\n    public function __construct(string $method, string $uri, array $query, array $headers, RequestStream $body, string $hostPrefix = '')\n    {\n        $this->method = $method;\n        $this->uri = $uri;\n        $this->headers = [];\n        foreach ($headers as $key => $value) {\n            $this->headers[strtolower($key)] = (string) $value;\n        }\n        $this->body = $body;\n        $this->query = $query;\n        $this->hostPrefix = $hostPrefix;\n        $this->endpoint = '';\n    }\n\n    public function getMethod(): string\n    {\n        return $this->method;\n    }\n\n    public function setMethod(string $method): void\n    {\n        $this->method = $method;\n    }\n\n    public function getUri(): string\n    {\n        return $this->uri;\n    }\n\n    public function hasHeader(string $name): bool\n    {\n        return \\array_key_exists(strtolower($name), $this->headers);\n    }\n\n    public function setHeader(string $name, string $value): void\n    {\n        $this->headers[strtolower($name)] = $value;\n    }\n\n    /**\n     * @return array<string, string>\n     */\n    public function getHeaders(): array\n    {\n        return $this->headers;\n    }\n\n    public function getHeader(string $name): ?string\n    {\n        return $this->headers[strtolower($name)] ?? null;\n    }\n\n    public function removeHeader(string $name): void\n    {\n        unset($this->headers[strtolower($name)]);\n    }\n\n    public function getBody(): RequestStream\n    {\n        return $this->body;\n    }\n\n    public function setBody(RequestStream $body): void\n    {\n        $this->body = $body;\n    }\n\n    public function hasQueryAttribute(string $name): bool\n    {\n        return \\array_key_exists($name, $this->query);\n    }\n\n    public function removeQueryAttribute(string $name): void\n    {\n        unset($this->query[$name]);\n        $this->queryString = null;\n        $this->endpoint = '';\n    }\n\n    public function setQueryAttribute(string $name, string $value): void\n    {\n        $this->query[$name] = $value;\n        $this->queryString = null;\n        $this->endpoint = '';\n    }\n\n    public function getQueryAttribute(string $name): ?string\n    {\n        return $this->query[$name] ?? null;\n    }\n\n    /**\n     * @return array<string, string>\n     */\n    public function getQuery(): array\n    {\n        return $this->query;\n    }\n\n    public function getHostPrefix(): string\n    {\n        return $this->hostPrefix;\n    }\n\n    public function setHostPrefix(string $hostPrefix): void\n    {\n        $this->hostPrefix = $hostPrefix;\n        $this->endpoint = '';\n    }\n\n    public function getEndpoint(): string\n    {\n        if (empty($this->endpoint)) {\n            if (null === $this->parsed) {\n                throw new LogicException('Request::$endpoint must be set before using it.');\n            }\n\n            $this->endpoint = $this->parsed['scheme'] . '://' . $this->hostPrefix . $this->parsed['host'] . (isset($this->parsed['port']) ? ':' . $this->parsed['port'] : '') . $this->uri . ($this->query ? (false === strpos($this->uri, '?') ? '?' : '&') . $this->getQueryString() : '');\n        }\n\n        return $this->endpoint;\n    }\n\n    public function setEndpoint(string $endpoint): void\n    {\n        if (null !== $this->parsed) {\n            throw new LogicException('Request::$endpoint cannot be changed after it has a value.');\n        }\n\n        $parsed = parse_url($endpoint);\n\n        if (false === $parsed || !isset($parsed['scheme'], $parsed['host'])) {\n            throw new InvalidArgument(\\sprintf('The endpoint \"%s\" is invalid.', $endpoint));\n        }\n\n        $this->parsed = ['scheme' => $parsed['scheme'], 'host' => $parsed['host'], 'port' => $parsed['port'] ?? null];\n\n        $this->queryString = $parsed['query'] ?? '';\n        parse_str($parsed['query'] ?? '', $this->query);\n        $this->uri = $parsed['path'] ?? '/';\n    }\n\n    private function getQueryString(): string\n    {\n        if (null === $this->queryString) {\n            $this->queryString = http_build_query($this->query, '', '&', \\PHP_QUERY_RFC3986);\n        }\n\n        return $this->queryString;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/RequestContext.php",
    "content": "<?php\n\nnamespace AsyncAws\\Core;\n\nuse AsyncAws\\Core\\Exception\\Http\\HttpException;\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\n\n/**\n * Contains contextual information alongside a request.\n *\n * @author Jérémy Derussé <jeremy@derusse.com>\n */\nfinal class RequestContext\n{\n    public const AVAILABLE_OPTIONS = [\n        'region' => true,\n        'operation' => true,\n        'expirationDate' => true,\n        'currentDate' => true,\n        'exceptionMapping' => true,\n        'usesEndpointDiscovery' => true,\n        'requiresEndpointDiscovery' => true,\n    ];\n\n    /**\n     * @var string|null\n     */\n    private $operation;\n\n    /**\n     * @var bool\n     */\n    private $usesEndpointDiscovery = false;\n\n    /**\n     * @var bool\n     */\n    private $requiresEndpointDiscovery = false;\n\n    /**\n     * @var string|null\n     */\n    private $region;\n\n    /**\n     * @var \\DateTimeImmutable|null\n     */\n    private $expirationDate;\n\n    /**\n     * @var \\DateTimeImmutable|null\n     */\n    private $currentDate;\n\n    /**\n     * @var array<string, class-string<HttpException>>\n     */\n    private $exceptionMapping = [];\n\n    /**\n     * @param array{\n     *  operation?: null|string,\n     *  region?: null|string,\n     *  expirationDate?: null|\\DateTimeImmutable,\n     *  currentDate?: null|\\DateTimeImmutable,\n     *  exceptionMapping?: array<string, class-string<HttpException>>,\n     *  usesEndpointDiscovery?: bool,\n     *  requiresEndpointDiscovery?: bool,\n     * } $options\n     */\n    public function __construct(array $options = [])\n    {\n        if (0 < \\count($invalidOptions = array_diff_key($options, self::AVAILABLE_OPTIONS))) {\n            throw new InvalidArgument(\\sprintf('Invalid option(s) \"%s\" passed to \"%s\". ', implode('\", \"', array_keys($invalidOptions)), __METHOD__));\n        }\n\n        foreach ($options as $property => $value) {\n            $this->$property = $value;\n        }\n    }\n\n    public function getOperation(): ?string\n    {\n        return $this->operation;\n    }\n\n    public function getRegion(): ?string\n    {\n        return $this->region;\n    }\n\n    public function getExpirationDate(): ?\\DateTimeImmutable\n    {\n        return $this->expirationDate;\n    }\n\n    public function getCurrentDate(): ?\\DateTimeImmutable\n    {\n        return $this->currentDate;\n    }\n\n    /**\n     * @return array<string, class-string<HttpException>>\n     */\n    public function getExceptionMapping(): array\n    {\n        return $this->exceptionMapping;\n    }\n\n    public function usesEndpointDiscovery(): bool\n    {\n        return $this->usesEndpointDiscovery;\n    }\n\n    public function requiresEndpointDiscovery(): bool\n    {\n        return $this->requiresEndpointDiscovery;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Response.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace AsyncAws\\Core;\n\nuse AsyncAws\\Core\\AwsError\\AwsErrorFactoryInterface;\nuse AsyncAws\\Core\\AwsError\\ChainAwsErrorFactory;\nuse AsyncAws\\Core\\EndpointDiscovery\\EndpointCache;\nuse AsyncAws\\Core\\Exception\\Exception;\nuse AsyncAws\\Core\\Exception\\Http\\ClientException;\nuse AsyncAws\\Core\\Exception\\Http\\HttpException;\nuse AsyncAws\\Core\\Exception\\Http\\NetworkException;\nuse AsyncAws\\Core\\Exception\\Http\\RedirectionException;\nuse AsyncAws\\Core\\Exception\\Http\\ServerException;\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\nuse AsyncAws\\Core\\Exception\\LogicException;\nuse AsyncAws\\Core\\Exception\\RuntimeException;\nuse AsyncAws\\Core\\Exception\\UnparsableResponse;\nuse AsyncAws\\Core\\Stream\\ResponseBodyResourceStream;\nuse AsyncAws\\Core\\Stream\\ResponseBodyStream;\nuse AsyncAws\\Core\\Stream\\ResultStream;\nuse Psr\\Log\\LoggerInterface;\nuse Psr\\Log\\LogLevel;\nuse Symfony\\Contracts\\HttpClient\\Exception\\DecodingExceptionInterface;\nuse Symfony\\Contracts\\HttpClient\\Exception\\TransportExceptionInterface;\nuse Symfony\\Contracts\\HttpClient\\HttpClientInterface;\nuse Symfony\\Contracts\\HttpClient\\ResponseInterface;\n\n/**\n * The response provides a facade to manipulate HttpResponses.\n *\n * @author Jérémy Derussé <jeremy@derusse.com>\n */\nfinal class Response\n{\n    /**\n     * @var ResponseInterface\n     */\n    private $httpResponse;\n\n    /**\n     * @var HttpClientInterface\n     */\n    private $httpClient;\n\n    /**\n     * A Result can be resolved many times. This variable contains the last resolve result.\n     * Null means that the result has never been resolved. Array contains material to create an exception.\n     *\n     * @var bool|HttpException|NetworkException|(callable(): (HttpException|NetworkException))|null\n     */\n    private $resolveResult;\n\n    /**\n     * A flag that indicated that the body have been downloaded.\n     *\n     * @var bool\n     */\n    private $bodyDownloaded = false;\n\n    /**\n     * A flag that indicated that the body started being downloaded.\n     *\n     * @var bool\n     */\n    private $streamStarted = false;\n\n    /**\n     * A flag that indicated that an exception has been thrown to the user.\n     *\n     * @var bool\n     */\n    private $didThrow = false;\n\n    /**\n     * @var LoggerInterface\n     */\n    private $logger;\n\n    /**\n     * @var AwsErrorFactoryInterface\n     */\n    private $awsErrorFactory;\n\n    /**\n     * @var ?EndpointCache\n     */\n    private $endpointCache;\n\n    /**\n     * @var ?Request\n     */\n    private $request;\n\n    /**\n     * @var bool\n     */\n    private $debug;\n\n    /**\n     * @var array<string, class-string<HttpException>>\n     */\n    private $exceptionMapping;\n\n    /**\n     * @param array<string, class-string<HttpException>> $exceptionMapping\n     */\n    public function __construct(ResponseInterface $response, HttpClientInterface $httpClient, LoggerInterface $logger, ?AwsErrorFactoryInterface $awsErrorFactory = null, ?EndpointCache $endpointCache = null, ?Request $request = null, bool $debug = false, array $exceptionMapping = [])\n    {\n        $this->httpResponse = $response;\n        $this->httpClient = $httpClient;\n        $this->logger = $logger;\n        $this->awsErrorFactory = $awsErrorFactory ?? new ChainAwsErrorFactory();\n        $this->endpointCache = $endpointCache;\n        $this->request = $request;\n        $this->debug = $debug;\n        $this->exceptionMapping = $exceptionMapping;\n    }\n\n    public function __destruct()\n    {\n        if (null === $this->resolveResult || !$this->didThrow) {\n            $this->resolve();\n        }\n    }\n\n    /**\n     * Make sure the actual request is executed.\n     *\n     * @param float|null $timeout Duration in seconds before aborting. When null wait\n     *                            until the end of execution. Using 0 means non-blocking\n     *\n     * @return bool whether the request is executed or not\n     *\n     * @throws NetworkException\n     * @throws HttpException\n     */\n    public function resolve(?float $timeout = null): bool\n    {\n        if (null !== $this->resolveResult) {\n            return $this->getResolveStatus();\n        }\n\n        try {\n            if (null === $timeout) {\n                $this->httpResponse->getStatusCode();\n            } else {\n                foreach ($this->httpClient->stream($this->httpResponse, $timeout) as $chunk) {\n                    if ($chunk->isTimeout()) {\n                        return false;\n                    }\n                    if ($chunk->isFirst()) {\n                        break;\n                    }\n                }\n            }\n\n            $this->defineResolveStatus();\n        } catch (TransportExceptionInterface $e) {\n            $this->resolveResult = new NetworkException('Could not contact remote server.', 0, $e);\n        }\n\n        if (true === $this->debug) {\n            $httpStatusCode = $this->httpResponse->getInfo('http_code');\n            if (0 === $httpStatusCode) {\n                // Network exception\n                $this->logger->debug('AsyncAws HTTP request could not be sent due network issues');\n            } else {\n                $this->logger->debug('AsyncAws HTTP response received with status code {status_code}', [\n                    'status_code' => $httpStatusCode,\n                    'headers' => json_encode($this->httpResponse->getHeaders(false)),\n                    'body' => $this->httpResponse->getContent(false),\n                ]);\n                $this->bodyDownloaded = true;\n            }\n        }\n\n        return $this->getResolveStatus();\n    }\n\n    /**\n     * Make sure all provided requests are executed.\n     *\n     * @param self[]     $responses\n     * @param float|null $timeout      Duration in seconds before aborting. When null wait\n     *                                 until the end of execution. Using 0 means non-blocking\n     * @param bool       $downloadBody Wait until receiving the entire response body or only the first bytes\n     *\n     * @return iterable<self>\n     *\n     * @throws NetworkException\n     * @throws HttpException\n     */\n    final public static function wait(iterable $responses, ?float $timeout = null, bool $downloadBody = false): iterable\n    {\n        /** @var self[] $responseMap */\n        $responseMap = [];\n        $indexMap = [];\n        $httpResponses = [];\n        $httpClient = null;\n        foreach ($responses as $index => $response) {\n            if (null !== $response->resolveResult && (true !== $response->resolveResult || !$downloadBody || $response->bodyDownloaded)) {\n                yield $index => $response;\n\n                continue;\n            }\n\n            if (null === $httpClient) {\n                $httpClient = $response->httpClient;\n            } elseif ($httpClient !== $response->httpClient) {\n                throw new LogicException('Unable to wait for the given results, they all have to be created with the same HttpClient');\n            }\n            $httpResponses[] = $response->httpResponse;\n            $indexMap[$hash = spl_object_id($response->httpResponse)] = $index;\n            $responseMap[$hash] = $response;\n        }\n\n        // no response provided (or all responses already resolved)\n        if (empty($httpResponses)) {\n            return;\n        }\n\n        if (null === $httpClient) {\n            throw new InvalidArgument('At least one response should have contain an Http Client');\n        }\n\n        foreach ($httpClient->stream($httpResponses, $timeout) as $httpResponse => $chunk) {\n            $hash = spl_object_id($httpResponse);\n            $response = $responseMap[$hash] ?? null;\n            // Check if null, just in case symfony yield an unexpected response.\n            if (null === $response) {\n                continue;\n            }\n\n            // index could be null if already yield\n            $index = $indexMap[$hash] ?? null;\n\n            try {\n                if ($chunk->isTimeout()) {\n                    // Receiving a timeout mean all responses are inactive.\n                    break;\n                }\n            } catch (TransportExceptionInterface $e) {\n                // Exception is stored as an array, because storing an instance of \\Exception will create a circular\n                // reference and prevent `__destruct` being called.\n                $response->resolveResult = new NetworkException('Could not contact remote server.', 0, $e);\n\n                if (null !== $index) {\n                    unset($indexMap[$hash]);\n                    yield $index => $response;\n                    if (empty($indexMap)) {\n                        // early exit if all statusCode are known. We don't have to wait for all responses\n                        return;\n                    }\n                }\n            }\n\n            if (!$response->streamStarted && '' !== $chunk->getContent()) {\n                $response->streamStarted = true;\n            }\n\n            if ($chunk->isLast()) {\n                $response->bodyDownloaded = true;\n                if (null !== $index && $downloadBody) {\n                    unset($indexMap[$hash]);\n                    yield $index => $response;\n                }\n            }\n            if ($chunk->isFirst()) {\n                $response->defineResolveStatus();\n                if (null !== $index && !$downloadBody) {\n                    unset($indexMap[$hash]);\n                    yield $index => $response;\n                }\n            }\n\n            if (empty($indexMap)) {\n                // early exit if all statusCode are known. We don't have to wait for all responses\n                return;\n            }\n        }\n    }\n\n    /**\n     * Returns info on the current request.\n     *\n     * @return array{\n     *                resolved: bool,\n     *                body_downloaded: bool,\n     *                response: \\Symfony\\Contracts\\HttpClient\\ResponseInterface,\n     *                status: int,\n     *                }\n     */\n    public function info(): array\n    {\n        return [\n            'resolved' => null !== $this->resolveResult,\n            'body_downloaded' => $this->bodyDownloaded,\n            'response' => $this->httpResponse,\n            'status' => (int) $this->httpResponse->getInfo('http_code'),\n        ];\n    }\n\n    public function cancel(): void\n    {\n        $this->httpResponse->cancel();\n        $this->resolveResult = false;\n    }\n\n    /**\n     * @return array<string, list<string>>\n     *\n     * @throws NetworkException\n     * @throws HttpException\n     */\n    public function getHeaders(): array\n    {\n        $this->resolve();\n\n        return $this->httpResponse->getHeaders(false);\n    }\n\n    /**\n     * @throws NetworkException\n     * @throws HttpException\n     */\n    public function getContent(): string\n    {\n        $this->resolve();\n\n        try {\n            return $this->httpResponse->getContent(false);\n        } finally {\n            $this->bodyDownloaded = true;\n        }\n    }\n\n    /**\n     * @return array<string, mixed>\n     *\n     * @throws NetworkException\n     * @throws UnparsableResponse\n     * @throws HttpException\n     */\n    public function toArray(): array\n    {\n        $this->resolve();\n\n        try {\n            return $this->httpResponse->toArray(false);\n        } catch (DecodingExceptionInterface $e) {\n            throw new UnparsableResponse('Could not parse response as array', 0, $e);\n        } finally {\n            $this->bodyDownloaded = true;\n        }\n    }\n\n    public function getStatusCode(): int\n    {\n        return $this->httpResponse->getStatusCode();\n    }\n\n    /**\n     * @throws NetworkException\n     * @throws HttpException\n     */\n    public function toStream(): ResultStream\n    {\n        $this->resolve();\n\n        if (\\is_callable([$this->httpResponse, 'toStream'])) {\n            return new ResponseBodyResourceStream($this->httpResponse->toStream());\n        }\n\n        if ($this->streamStarted) {\n            throw new RuntimeException('Can not create a ResultStream because the body started being downloaded. The body was started to be downloaded in Response::wait()');\n        }\n\n        try {\n            return new ResponseBodyStream($this->httpClient->stream($this->httpResponse));\n        } finally {\n            $this->bodyDownloaded = true;\n        }\n    }\n\n    /**\n     * In PHP < 7.4, a reference to the arguments is present in the stackTrace of the exception.\n     * This creates a Circular reference: Response -> resolveResult -> Exception -> stackTrace -> Response.\n     * This mean, that calling `unset($response)` does not call the `__destruct` method and does not throw the\n     * remaining exception present in `resolveResult`. The `__destruct` method will be called once the garbage collector\n     * will detect the loop.\n     * That's why this method does not creates exception here, but creates closure instead that will be resolved right\n     * before throwing the exception.\n     */\n    private function defineResolveStatus(): void\n    {\n        try {\n            $statusCode = $this->httpResponse->getStatusCode();\n        } catch (TransportExceptionInterface $e) {\n            $this->resolveResult = static function () use ($e): NetworkException {\n                return new NetworkException('Could not contact remote server.', 0, $e);\n            };\n\n            return;\n        }\n\n        if (300 <= $statusCode) {\n            try {\n                $awsError = $this->awsErrorFactory->createFromResponse($this->httpResponse);\n                if ($this->request && $this->endpointCache && (400 === $statusCode || 'InvalidEndpointException' === $awsError->getCode())) {\n                    $this->endpointCache->removeEndpoint($this->request->getEndpoint());\n                }\n            } catch (UnparsableResponse $e) {\n                $awsError = null;\n            }\n\n            if ((null !== $awsCode = ($awsError ? $awsError->getCode() : null)) && isset($this->exceptionMapping[$awsCode])) {\n                $exceptionClass = $this->exceptionMapping[$awsCode];\n            } elseif (isset($this->exceptionMapping['http_status_code_' . $statusCode])) {\n                $exceptionClass = $this->exceptionMapping['http_status_code_' . $statusCode];\n            } elseif (500 <= $statusCode) {\n                $exceptionClass = ServerException::class;\n            } elseif (400 <= $statusCode) {\n                $exceptionClass = ClientException::class;\n            } else {\n                $exceptionClass = RedirectionException::class;\n            }\n\n            $httpResponse = $this->httpResponse;\n            $this->resolveResult = static function () use ($exceptionClass, $httpResponse, $awsError): HttpException {\n                return new $exceptionClass($httpResponse, $awsError);\n            };\n\n            return;\n        }\n\n        $this->resolveResult = true;\n    }\n\n    private function getResolveStatus(): bool\n    {\n        if (\\is_bool($this->resolveResult)) {\n            return $this->resolveResult;\n        }\n\n        if (\\is_callable($this->resolveResult)) {\n            $this->resolveResult = ($this->resolveResult)();\n        }\n\n        $code = null;\n        $message = null;\n        $context = ['exception' => $this->resolveResult];\n        if ($this->resolveResult instanceof HttpException) {\n            /** @var int $code */\n            $code = $this->httpResponse->getInfo('http_code');\n            /** @var string $url */\n            $url = $this->httpResponse->getInfo('url');\n            $context['aws_code'] = $this->resolveResult->getAwsCode();\n            $context['aws_message'] = $this->resolveResult->getAwsMessage();\n            $context['aws_type'] = $this->resolveResult->getAwsType();\n            $context['aws_detail'] = $this->resolveResult->getAwsDetail();\n            $message = \\sprintf('HTTP %d returned for \"%s\".', $code, $url);\n        }\n\n        if ($this->resolveResult instanceof Exception) {\n            $this->logger->log(\n                404 === $code ? LogLevel::INFO : LogLevel::ERROR,\n                $message ?? $this->resolveResult->getMessage(),\n                $context\n            );\n            $this->didThrow = true;\n\n            throw $this->resolveResult;\n        }\n\n        throw new RuntimeException('Unexpected resolve state');\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Result.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace AsyncAws\\Core;\n\nuse AsyncAws\\Core\\Exception\\Http\\HttpException;\nuse AsyncAws\\Core\\Exception\\Http\\NetworkException;\n\n/**\n * Base class for all return values from a Api Client methods.\n * Example: `FooClient::bar(): Result`.\n */\nclass Result\n{\n    /**\n     * @var AbstractApi|null\n     */\n    protected $awsClient;\n\n    /**\n     * Input used to build the API request that generate this Result.\n     *\n     * @var object|null\n     */\n    protected $input;\n\n    /**\n     * @var bool\n     */\n    private $initialized = false;\n\n    /**\n     * @var Response\n     */\n    private $response;\n\n    /**\n     * @var self[]\n     */\n    private $prefetchResults = [];\n\n    public function __construct(Response $response, ?AbstractApi $awsClient = null, ?object $request = null)\n    {\n        $this->response = $response;\n        $this->awsClient = $awsClient;\n        $this->input = $request;\n    }\n\n    public function __destruct()\n    {\n        while (!empty($this->prefetchResults)) {\n            array_shift($this->prefetchResults)->cancel();\n        }\n    }\n\n    /**\n     * Make sure the actual request is executed.\n     *\n     * @param float|null $timeout Duration in seconds before aborting. When null wait until the end of execution.\n     *\n     * @return bool whether the request is executed or not\n     *\n     * @throws NetworkException\n     * @throws HttpException\n     */\n    final public function resolve(?float $timeout = null): bool\n    {\n        return $this->response->resolve($timeout);\n    }\n\n    /**\n     * Make sure all provided requests are executed.\n     * This only work if the http responses are produced by the same HTTP client.\n     * See https://symfony.com/doc/current/components/http_client.html#multiplexing-responses.\n     *\n     * @param self[]     $results\n     * @param float|null $timeout      Duration in seconds before aborting. When null wait\n     *                                 until the end of execution. Using 0 means non-blocking\n     * @param bool       $downloadBody Wait until receiving the entire response body or only the first bytes\n     *\n     * @return iterable<self>\n     *\n     * @throws NetworkException\n     * @throws HttpException\n     */\n    final public static function wait(iterable $results, ?float $timeout = null, bool $downloadBody = false): iterable\n    {\n        $resultMap = [];\n        $responses = [];\n        foreach ($results as $index => $result) {\n            $responses[$index] = $result->response;\n            $resultMap[$index] = $result;\n        }\n\n        foreach (Response::wait($responses, $timeout, $downloadBody) as $index => $response) {\n            yield $index => $resultMap[$index];\n        }\n    }\n\n    /**\n     * Returns info on the current request.\n     *\n     * @return array{\n     *                resolved: bool,\n     *                body_downloaded: bool,\n     *                response: \\Symfony\\Contracts\\HttpClient\\ResponseInterface,\n     *                status: int,\n     *                }\n     */\n    final public function info(): array\n    {\n        return $this->response->info();\n    }\n\n    final public function cancel(): void\n    {\n        $this->response->cancel();\n    }\n\n    final protected function registerPrefetch(self $result): void\n    {\n        $this->prefetchResults[spl_object_id($result)] = $result;\n    }\n\n    final protected function unregisterPrefetch(self $result): void\n    {\n        unset($this->prefetchResults[spl_object_id($result)]);\n    }\n\n    final protected function initialize(): void\n    {\n        if ($this->initialized) {\n            return;\n        }\n\n        $this->resolve();\n        $this->initialized = true;\n        $this->populateResult($this->response);\n    }\n\n    protected function populateResult(Response $response): void\n    {\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Signer/Signer.php",
    "content": "<?php\n\nnamespace AsyncAws\\Core\\Signer;\n\nuse AsyncAws\\Core\\Credentials\\Credentials;\nuse AsyncAws\\Core\\Request;\nuse AsyncAws\\Core\\RequestContext;\n\n/**\n * Interface for signing a request.\n *\n * @author Jérémy Derussé <jeremy@derusse.com>\n */\ninterface Signer\n{\n    public function sign(Request $request, Credentials $credentials, RequestContext $context): void;\n\n    public function presign(Request $request, Credentials $credentials, RequestContext $context): void;\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Signer/SignerV4.php",
    "content": "<?php\n\nnamespace AsyncAws\\Core\\Signer;\n\nuse AsyncAws\\Core\\Credentials\\Credentials;\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\nuse AsyncAws\\Core\\Request;\nuse AsyncAws\\Core\\RequestContext;\nuse AsyncAws\\Core\\Stream\\ReadOnceResultStream;\nuse AsyncAws\\Core\\Stream\\RewindableStream;\nuse AsyncAws\\Core\\Stream\\StringStream;\n\n/**\n * Version4 of signer.\n *\n * @author Jérémy Derussé <jeremy@derusse.com>\n */\nclass SignerV4 implements Signer\n{\n    private const ALGORITHM_REQUEST = 'AWS4-HMAC-SHA256';\n\n    private const BLACKLIST_HEADERS = [\n        'cache-control' => true,\n        'content-type' => true,\n        'content-length' => true,\n        'expect' => true,\n        'max-forwards' => true,\n        'pragma' => true,\n        'range' => true,\n        'te' => true,\n        'if-match' => true,\n        'if-none-match' => true,\n        'if-modified-since' => true,\n        'if-unmodified-since' => true,\n        'if-range' => true,\n        'accept' => true,\n        'authorization' => true,\n        'proxy-authorization' => true,\n        'from' => true,\n        'referer' => true,\n        'user-agent' => true,\n        'x-amzn-trace-id' => true,\n        'aws-sdk-invocation-id' => true,\n        'aws-sdk-retry' => true,\n    ];\n\n    /**\n     * @var string\n     */\n    private $scopeName;\n\n    /**\n     * @var string\n     */\n    private $region;\n\n    public function __construct(string $scopeName, string $region)\n    {\n        $this->scopeName = $scopeName;\n        $this->region = $region;\n    }\n\n    public function presign(Request $request, Credentials $credentials, RequestContext $context): void\n    {\n        $now = $context->getCurrentDate() ?? new \\DateTimeImmutable();\n\n        // Signer date have to be UTC https://docs.aws.amazon.com/general/latest/gr/sigv4-date-handling.html\n        $now = $now->setTimezone(new \\DateTimeZone('UTC'));\n        $expires = $context->getExpirationDate() ?? $now->add(new \\DateInterval('PT1H'));\n\n        $this->handleSignature($request, $credentials, $now, $expires, true);\n    }\n\n    public function sign(Request $request, Credentials $credentials, RequestContext $context): void\n    {\n        $now = $context->getCurrentDate() ?? new \\DateTimeImmutable();\n\n        // Signer date have to be UTC https://docs.aws.amazon.com/general/latest/gr/sigv4-date-handling.html\n        $now = $now->setTimezone(new \\DateTimeZone('UTC'));\n\n        $this->handleSignature($request, $credentials, $now, $now, false);\n    }\n\n    protected function buildBodyDigest(Request $request, bool $isPresign): string\n    {\n        if ($request->hasHeader('x-amz-content-sha256')) {\n            /** @var string $hash */\n            $hash = $request->getHeader('x-amz-content-sha256');\n        } else {\n            $body = $request->getBody();\n            if ($body instanceof ReadOnceResultStream) {\n                $request->setBody($body = RewindableStream::create($body));\n            }\n\n            $hash = $request->getBody()->hash();\n        }\n\n        if ('UNSIGNED-PAYLOAD' === $hash) {\n            $request->setHeader('x-amz-content-sha256', $hash);\n        }\n\n        return $hash;\n    }\n\n    protected function convertBodyToStream(SigningContext $context): void\n    {\n        $request = $context->getRequest();\n        $request->setBody(StringStream::create($request->getBody()));\n    }\n\n    protected function buildCanonicalPath(Request $request): string\n    {\n        $doubleEncoded = rawurlencode(ltrim($request->getUri(), '/'));\n\n        return '/' . str_replace('%2F', '/', $doubleEncoded);\n    }\n\n    private function handleSignature(Request $request, Credentials $credentials, \\DateTimeImmutable $now, \\DateTimeImmutable $expires, bool $isPresign): void\n    {\n        $this->removePresign($request);\n        $this->sanitizeHostForHeader($request);\n        $this->assignAmzQueryValues($request, $credentials, $isPresign);\n\n        $this->buildTime($request, $now, $expires, $isPresign);\n        $credentialScope = $this->buildCredentialString($request, $credentials, $now, $isPresign);\n        $context = new SigningContext(\n            $request,\n            $now,\n            implode('/', $credentialScope),\n            $this->buildSigningKey($credentials, $credentialScope)\n        );\n        if ($isPresign) {\n            // Should be called before `buildBodyDigest` because this method may alter the body\n            $this->convertBodyToQuery($request);\n        } else {\n            $this->convertBodyToStream($context);\n        }\n\n        $bodyDigest = $this->buildBodyDigest($request, $isPresign);\n\n        if ($isPresign) {\n            // Should be called after `buildBodyDigest` because this method may remove the header `x-amz-content-sha256`\n            $this->convertHeaderToQuery($request);\n        }\n\n        $canonicalHeaders = $this->buildCanonicalHeaders($request, $isPresign);\n        $canonicalRequest = $this->buildCanonicalRequest($request, $canonicalHeaders, $bodyDigest);\n        $stringToSign = $this->buildStringToSign($context->getNow(), $context->getCredentialString(), $canonicalRequest);\n        $context->setSignature($signature = $this->buildSignature($stringToSign, $context->getSigningKey()));\n\n        if ($isPresign) {\n            $request->setQueryAttribute('X-Amz-Signature', $signature);\n        } else {\n            $request->setHeader('authorization', \\sprintf(\n                '%s Credential=%s/%s, SignedHeaders=%s, Signature=%s',\n                self::ALGORITHM_REQUEST,\n                $credentials->getAccessKeyId(),\n                implode('/', $credentialScope),\n                implode(';', array_keys($canonicalHeaders)),\n                $signature\n            ));\n        }\n    }\n\n    private function removePresign(Request $request): void\n    {\n        $request->removeQueryAttribute('X-Amz-Algorithm');\n        $request->removeQueryAttribute('X-Amz-Signature');\n        $request->removeQueryAttribute('X-Amz-Security-Token');\n        $request->removeQueryAttribute('X-Amz-Date');\n        $request->removeQueryAttribute('X-Amz-Expires');\n        $request->removeQueryAttribute('X-Amz-Credential');\n        $request->removeQueryAttribute('X-Amz-SignedHeaders');\n    }\n\n    private function sanitizeHostForHeader(Request $request): void\n    {\n        if (false === $parsedUrl = parse_url($request->getEndpoint())) {\n            throw new InvalidArgument(\\sprintf('The endpoint \"%s\" is invalid.', $request->getEndpoint()));\n        }\n\n        if (!isset($parsedUrl['host'])) {\n            return;\n        }\n\n        $host = $parsedUrl['host'];\n        if (isset($parsedUrl['port'])) {\n            $host .= ':' . $parsedUrl['port'];\n        }\n\n        $request->setHeader('host', $host);\n    }\n\n    private function assignAmzQueryValues(Request $request, Credentials $credentials, bool $isPresign): void\n    {\n        if ($isPresign) {\n            $request->setQueryAttribute('X-Amz-Algorithm', self::ALGORITHM_REQUEST);\n            if (null !== $sessionToken = $credentials->getSessionToken()) {\n                $request->setQueryAttribute('X-Amz-Security-Token', $sessionToken);\n            }\n\n            return;\n        }\n\n        if (null !== $sessionToken = $credentials->getSessionToken()) {\n            $request->setHeader('x-amz-security-token', $sessionToken);\n        }\n    }\n\n    private function buildTime(Request $request, \\DateTimeImmutable $now, \\DateTimeImmutable $expires, bool $isPresign): void\n    {\n        if ($isPresign) {\n            $duration = $expires->getTimestamp() - $now->getTimestamp();\n            if ($duration > 604800) {\n                throw new InvalidArgument('The expiration date of presigned URL must be less than one week');\n            }\n            if ($duration < 0) {\n                throw new InvalidArgument('The expiration date of presigned URL must be in the future');\n            }\n\n            $request->setQueryAttribute('X-Amz-Date', $now->format('Ymd\\THis\\Z'));\n            $request->setQueryAttribute('X-Amz-Expires', (string) $duration);\n        } else {\n            $request->setHeader('X-Amz-Date', $now->format('Ymd\\THis\\Z'));\n        }\n    }\n\n    /**\n     * @return string[]\n     */\n    private function buildCredentialString(Request $request, Credentials $credentials, \\DateTimeImmutable $now, bool $isPresign): array\n    {\n        $credentialScope = [$now->format('Ymd'), $this->region, $this->scopeName, 'aws4_request'];\n\n        if ($isPresign) {\n            $request->setQueryAttribute('X-Amz-Credential', $credentials->getAccessKeyId() . '/' . implode('/', $credentialScope));\n        }\n\n        return $credentialScope;\n    }\n\n    private function convertHeaderToQuery(Request $request): void\n    {\n        foreach ($request->getHeaders() as $name => $value) {\n            if ('x-amz' === substr($name, 0, 5)) {\n                $request->setQueryAttribute($name, $value);\n            }\n\n            if (isset(self::BLACKLIST_HEADERS[$name])) {\n                $request->removeHeader($name);\n            }\n        }\n        $request->removeHeader('x-amz-content-sha256');\n    }\n\n    private function convertBodyToQuery(Request $request): void\n    {\n        if ('POST' !== $request->getMethod()) {\n            return;\n        }\n\n        $request->setMethod('GET');\n        if ('application/x-www-form-urlencoded' === $request->getHeader('Content-Type')) {\n            parse_str($request->getBody()->stringify(), $params);\n            foreach ($params as $name => $value) {\n                $request->setQueryAttribute($name, $value);\n            }\n        }\n\n        $request->removeHeader('content-type');\n        $request->removeHeader('content-length');\n        $request->setBody(StringStream::create(''));\n    }\n\n    /**\n     * @return array<string, string>\n     */\n    private function buildCanonicalHeaders(Request $request, bool $isPresign): array\n    {\n        // Case-insensitively aggregate all of the headers.\n        $canonicalHeaders = [];\n        foreach ($request->getHeaders() as $key => $value) {\n            $key = strtolower($key);\n            if (isset(self::BLACKLIST_HEADERS[$key])) {\n                continue;\n            }\n\n            $canonicalHeaders[$key] = $key . ':' . preg_replace('/\\s+/', ' ', $value);\n        }\n        ksort($canonicalHeaders);\n\n        if ($isPresign) {\n            $request->setQueryAttribute('X-Amz-SignedHeaders', implode(';', array_keys($canonicalHeaders)));\n        }\n\n        return $canonicalHeaders;\n    }\n\n    /**\n     * @param array<string, string> $canonicalHeaders\n     */\n    private function buildCanonicalRequest(Request $request, array $canonicalHeaders, string $bodyDigest): string\n    {\n        return implode(\"\\n\", [\n            $request->getMethod(),\n            $this->buildCanonicalPath($request),\n            $this->buildCanonicalQuery($request),\n            implode(\"\\n\", array_values($canonicalHeaders)),\n            '', // empty line after headers\n            implode(';', array_keys($canonicalHeaders)),\n            $bodyDigest,\n        ]);\n    }\n\n    private function buildCanonicalQuery(Request $request): string\n    {\n        $query = $request->getQuery();\n\n        unset($query['X-Amz-Signature']);\n        if (empty($query)) {\n            return '';\n        }\n\n        uksort($query, static function (string $a, string $b): int {\n            return strcmp(rawurlencode($a), rawurlencode($b));\n        });\n        $encodedQuery = [];\n        foreach ($query as $key => $values) {\n            if (!\\is_array($values)) {\n                $encodedQuery[] = rawurlencode($key) . '=' . rawurlencode($values);\n\n                continue;\n            }\n\n            // @phpstan-ignore argument.unresolvableType\n            sort($values);\n            foreach ($values as $value) {\n                $encodedQuery[] = rawurlencode($key) . '=' . rawurlencode($value);\n            }\n        }\n\n        return implode('&', $encodedQuery);\n    }\n\n    private function buildStringToSign(\\DateTimeImmutable $now, string $credentialString, string $canonicalRequest): string\n    {\n        return implode(\"\\n\", [\n            self::ALGORITHM_REQUEST,\n            $now->format('Ymd\\THis\\Z'),\n            $credentialString,\n            hash('sha256', $canonicalRequest),\n        ]);\n    }\n\n    /**\n     * @param string[] $credentialScope\n     */\n    private function buildSigningKey(Credentials $credentials, array $credentialScope): string\n    {\n        $signingKey = 'AWS4' . $credentials->getSecretKey();\n        foreach ($credentialScope as $scopePart) {\n            $signingKey = hash_hmac('sha256', $scopePart, $signingKey, true);\n        }\n\n        return $signingKey;\n    }\n\n    private function buildSignature(string $stringToSign, string $signingKey): string\n    {\n        return hash_hmac('sha256', $stringToSign, $signingKey);\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Signer/SigningContext.php",
    "content": "<?php\n\nnamespace AsyncAws\\Core\\Signer;\n\nuse AsyncAws\\Core\\Request;\n\n/**\n * @author Jérémy Derussé <jeremy@derusse.com>\n */\nfinal class SigningContext\n{\n    /**\n     * @var Request\n     */\n    private $request;\n\n    /**\n     * @var \\DateTimeImmutable\n     */\n    private $now;\n\n    /**\n     * @var string\n     */\n    private $credentialString;\n\n    /**\n     * @var string\n     */\n    private $signingKey;\n\n    /**\n     * @var string\n     */\n    private $signature = '';\n\n    public function __construct(\n        Request $request,\n        \\DateTimeImmutable $now,\n        string $credentialString,\n        string $signingKey\n    ) {\n        $this->request = $request;\n        $this->now = $now;\n        $this->credentialString = $credentialString;\n        $this->signingKey = $signingKey;\n    }\n\n    public function getRequest(): Request\n    {\n        return $this->request;\n    }\n\n    public function getNow(): \\DateTimeImmutable\n    {\n        return $this->now;\n    }\n\n    public function getCredentialString(): string\n    {\n        return $this->credentialString;\n    }\n\n    public function getSigningKey(): string\n    {\n        return $this->signingKey;\n    }\n\n    public function getSignature(): string\n    {\n        return $this->signature;\n    }\n\n    public function setSignature(string $signature): void\n    {\n        $this->signature = $signature;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Stream/CallableStream.php",
    "content": "<?php\n\nnamespace AsyncAws\\Core\\Stream;\n\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\n\n/**\n * Convert a \"Curl Callable\" into a Stream\n * The Callable must return a chunk at each call. And return an empty string on last call.\n *\n * @author Jérémy Derussé <jeremy@derusse.com>\n *\n * @internal\n */\nfinal class CallableStream implements ReadOnceResultStream, RequestStream\n{\n    /**\n     * @var callable(int): string\n     */\n    private $content;\n\n    /**\n     * @var int\n     */\n    private $chunkSize;\n\n    /**\n     * @param callable(int): string $content\n     */\n    private function __construct(callable $content, int $chunkSize = 64 * 1024)\n    {\n        $this->content = $content;\n        $this->chunkSize = $chunkSize;\n    }\n\n    /**\n     * @param self|callable(int): string $content\n     */\n    public static function create($content, int $chunkSize = 64 * 1024): CallableStream\n    {\n        if ($content instanceof self) {\n            return $content;\n        }\n        if (\\is_callable($content)) {\n            return new self($content, $chunkSize);\n        }\n\n        throw new InvalidArgument(\\sprintf('Expect content to be a \"callable\". \"%s\" given.', \\is_object($content) ? \\get_class($content) : \\gettype($content)));\n    }\n\n    public function length(): ?int\n    {\n        return null;\n    }\n\n    public function stringify(): string\n    {\n        return implode('', iterator_to_array($this));\n    }\n\n    public function getIterator(): \\Traversable\n    {\n        while (true) {\n            if (!\\is_string($data = ($this->content)($this->chunkSize))) {\n                throw new InvalidArgument(\\sprintf('The return value of content callback must be a string, %s returned.', \\is_object($data) ? \\get_class($data) : \\gettype($data)));\n            }\n            if ('' === $data) {\n                break;\n            }\n\n            yield $data;\n        }\n    }\n\n    public function hash(string $algo = 'sha256', bool $raw = false): string\n    {\n        $ctx = hash_init($algo);\n        foreach ($this as $chunk) {\n            hash_update($ctx, $chunk);\n        }\n\n        return hash_final($ctx, $raw);\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Stream/FixedSizeStream.php",
    "content": "<?php\n\nnamespace AsyncAws\\Core\\Stream;\n\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\n\n/**\n * A Stream decorator that return Chunk with the same exact size.\n *\n * @author Jérémy Derussé <jeremy@derusse.com>\n */\nfinal class FixedSizeStream implements RequestStream\n{\n    /**\n     * @var RequestStream\n     */\n    private $content;\n\n    /**\n     * @var int\n     */\n    private $chunkSize;\n\n    private function __construct(RequestStream $content, int $chunkSize = 64 * 1024)\n    {\n        $this->content = $content;\n        $this->chunkSize = $chunkSize;\n    }\n\n    public static function create(RequestStream $content, int $chunkSize = 64 * 1024): FixedSizeStream\n    {\n        if ($content instanceof self) {\n            if ($content->chunkSize === $chunkSize) {\n                return $content;\n            }\n\n            return new self($content->content, $chunkSize);\n        }\n\n        return new self($content, $chunkSize);\n    }\n\n    public function length(): ?int\n    {\n        return $this->content->length();\n    }\n\n    public function stringify(): string\n    {\n        return $this->content->stringify();\n    }\n\n    public function getIterator(): \\Traversable\n    {\n        // This algorithm do not use string concatenation nor substr, to reuse the same ZVAL et reduce memory footprint.\n        $chunk = '';\n        foreach ($this->content as $buffer) {\n            if (!\\is_string($buffer)) {\n                throw new InvalidArgument(\\sprintf('The return value of content callback must be a string, %s returned.', \\is_object($buffer) ? \\get_class($buffer) : \\gettype($buffer)));\n            }\n\n            $chunk .= $nextBytes = substr($buffer, 0, $this->chunkSize - \\strlen($chunk));\n            $bufferPosition = \\strlen($nextBytes);\n\n            if (\\strlen($chunk) < $this->chunkSize) {\n                // The chunk does not have yet the expected size. Let's fetching new data\n                continue;\n            }\n\n            yield $chunk;\n            while (\\strlen($buffer) - $bufferPosition >= $this->chunkSize) {\n                // The buffer is bigger than the expected size. Let's flushing it.\n                yield substr($buffer, $bufferPosition, $this->chunkSize);\n                $bufferPosition += $this->chunkSize;\n            }\n\n            // Here we can substr the buffer because the remaining size is smaller that chunkSize\n            $chunk = substr($buffer, $bufferPosition);\n        }\n\n        if ('' !== $chunk) {\n            yield $chunk;\n        }\n    }\n\n    public function hash(string $algo = 'sha256', bool $raw = false): string\n    {\n        return $this->content->hash($algo, $raw);\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Stream/IterableStream.php",
    "content": "<?php\n\nnamespace AsyncAws\\Core\\Stream;\n\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\n\n/**\n * Convert an iterator into a Stream.\n *\n * @author Jérémy Derussé <jeremy@derusse.com>\n */\nfinal class IterableStream implements ReadOnceResultStream, RequestStream\n{\n    /**\n     * @var iterable<string>\n     */\n    private $content;\n\n    /**\n     * @param iterable<string> $content\n     */\n    private function __construct(iterable $content)\n    {\n        $this->content = $content;\n    }\n\n    /**\n     * @param self|iterable<string> $content\n     */\n    public static function create($content): IterableStream\n    {\n        if ($content instanceof self) {\n            return $content;\n        }\n        if (is_iterable($content)) {\n            return new self($content);\n        }\n\n        throw new InvalidArgument(\\sprintf('Expect content to be an iterable. \"%s\" given.', \\is_object($content) ? \\get_class($content) : \\gettype($content)));\n    }\n\n    public function length(): ?int\n    {\n        return null;\n    }\n\n    public function stringify(): string\n    {\n        if ($this->content instanceof \\Traversable) {\n            return implode('', iterator_to_array($this->content));\n        }\n\n        return implode('', iterator_to_array((function () {yield from $this->content; })()));\n    }\n\n    public function getIterator(): \\Traversable\n    {\n        yield from $this->content;\n    }\n\n    public function hash(string $algo = 'sha256', bool $raw = false): string\n    {\n        $ctx = hash_init($algo);\n        foreach ($this->content as $chunk) {\n            hash_update($ctx, $chunk);\n        }\n\n        return hash_final($ctx, $raw);\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Stream/ReadOnceResultStream.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace AsyncAws\\Core\\Stream;\n\n/**\n * Marker for ResultStream that can be read only once.\n */\ninterface ReadOnceResultStream\n{\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Stream/RequestStream.php",
    "content": "<?php\n\nnamespace AsyncAws\\Core\\Stream;\n\n/**\n * Provides method to convert a input into string or chunks.\n *\n * @author Jérémy Derussé <jeremy@derusse.com>\n *\n * @extends \\IteratorAggregate<string>\n */\ninterface RequestStream extends \\IteratorAggregate\n{\n    /**\n     * Length in bytes.\n     */\n    public function length(): ?int;\n\n    public function stringify(): string;\n\n    public function hash(string $algo = 'sha256', bool $raw = false): string;\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Stream/ResourceStream.php",
    "content": "<?php\n\nnamespace AsyncAws\\Core\\Stream;\n\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\n\n/**\n * Convert a resource into a Stream.\n *\n * @author Jérémy Derussé <jeremy@derusse.com>\n *\n * @internal\n */\nfinal class ResourceStream implements RequestStream\n{\n    /**\n     * @var resource\n     */\n    private $content;\n\n    /**\n     * @var int\n     */\n    private $chunkSize;\n\n    /**\n     * @param resource $content\n     */\n    private function __construct($content, int $chunkSize = 64 * 1024)\n    {\n        $this->content = $content;\n        $this->chunkSize = $chunkSize;\n    }\n\n    /**\n     * @param self|resource $content\n     */\n    public static function create($content, int $chunkSize = 64 * 1024): ResourceStream\n    {\n        if ($content instanceof self) {\n            return $content;\n        }\n        if (\\is_resource($content)) {\n            if (!stream_get_meta_data($content)['seekable']) {\n                throw new InvalidArgument('The given body is not seekable.');\n            }\n\n            return new self($content, $chunkSize);\n        }\n\n        throw new InvalidArgument(\\sprintf('Expect content to be a \"resource\". \"%s\" given.', \\is_object($content) ? \\get_class($content) : \\gettype($content)));\n    }\n\n    public function length(): ?int\n    {\n        return fstat($this->content)['size'] ?? null;\n    }\n\n    public function stringify(): string\n    {\n        if (-1 === fseek($this->content, 0)) {\n            throw new InvalidArgument('Unable to seek the content.');\n        }\n\n        return stream_get_contents($this->content);\n    }\n\n    public function getIterator(): \\Traversable\n    {\n        if (-1 === fseek($this->content, 0)) {\n            throw new InvalidArgument('Unable to seek the content.');\n        }\n\n        while (!feof($this->content)) {\n            yield fread($this->content, $this->chunkSize);\n        }\n    }\n\n    /**\n     * @return resource\n     */\n    public function getResource()\n    {\n        return $this->content;\n    }\n\n    public function hash(string $algo = 'sha256', bool $raw = false): string\n    {\n        $pos = ftell($this->content);\n\n        if ($pos > 0 && -1 === fseek($this->content, 0)) {\n            throw new InvalidArgument('Unable to seek the content.');\n        }\n\n        $ctx = hash_init($algo);\n        hash_update_stream($ctx, $this->content);\n        $out = hash_final($ctx, $raw);\n\n        if (-1 === fseek($this->content, $pos)) {\n            throw new InvalidArgument('Unable to seek the content.');\n        }\n\n        return $out;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Stream/ResponseBodyResourceStream.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace AsyncAws\\Core\\Stream;\n\nuse AsyncAws\\Core\\Exception\\RuntimeException;\n\n/**\n * Provides a ResultStream from a resource filled by an HTTP response body.\n *\n * @author Jérémy Derussé <jeremy@derusse.com>\n */\nclass ResponseBodyResourceStream implements ResultStream\n{\n    /**\n     * @var resource\n     */\n    private $resource;\n\n    /**\n     * @param resource $resource\n     */\n    public function __construct($resource)\n    {\n        $this->resource = $resource;\n    }\n\n    public function __toString(): string\n    {\n        return $this->getContentAsString();\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getChunks(): iterable\n    {\n        $pos = ftell($this->resource);\n        if (0 !== $pos && !rewind($this->resource)) {\n            throw new RuntimeException('The stream is not rewindable');\n        }\n\n        try {\n            while (!feof($this->resource)) {\n                yield fread($this->resource, 64 * 1024);\n            }\n        } finally {\n            fseek($this->resource, $pos);\n        }\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getContentAsString(): string\n    {\n        $pos = ftell($this->resource);\n\n        try {\n            if (!rewind($this->resource)) {\n                throw new RuntimeException('Failed to rewind the stream');\n            }\n\n            return stream_get_contents($this->resource);\n        } finally {\n            fseek($this->resource, $pos);\n        }\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getContentAsResource()\n    {\n        if (!rewind($this->resource)) {\n            throw new RuntimeException('Failed to rewind the stream');\n        }\n\n        return $this->resource;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Stream/ResponseBodyStream.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace AsyncAws\\Core\\Stream;\n\nuse AsyncAws\\Core\\Exception\\LogicException;\nuse Symfony\\Contracts\\HttpClient\\ResponseStreamInterface;\n\n/**\n * Stream a HTTP response body.\n * This class is a BC layer for Http Response that does not support `toStream()`.\n * When calling `getChunks` you must read all the chunks before being able to call this method (or another method) again.\n * When calling `getContentAsResource`, it first, fully read the Response Body in a blocking way.\n *\n * @author Tobias Nyholm <tobias.nyholm@gmail.com>\n * @author Jérémy Derussé <jeremy@derusse.com>\n */\nclass ResponseBodyStream implements ResultStream\n{\n    /**\n     * @var ResponseStreamInterface\n     */\n    private $responseStream;\n\n    /**\n     * @var ResponseBodyResourceStream|null\n     */\n    private $fallback;\n\n    /**\n     * @var bool\n     */\n    private $partialRead = false;\n\n    public function __construct(ResponseStreamInterface $responseStream)\n    {\n        $this->responseStream = $responseStream;\n    }\n\n    public function __toString(): string\n    {\n        return $this->getContentAsString();\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getChunks(): iterable\n    {\n        if (null !== $this->fallback) {\n            yield from $this->fallback->getChunks();\n\n            return;\n        }\n        if ($this->partialRead) {\n            throw new LogicException(\\sprintf('You can not call \"%s\". Another process doesn\\'t reading \"getChunks\" till the end.', __METHOD__));\n        }\n\n        $resource = fopen('php://temp', 'rb+');\n        foreach ($this->responseStream as $chunk) {\n            $this->partialRead = true;\n            $chunkContent = $chunk->getContent();\n            fwrite($resource, $chunkContent);\n            yield $chunkContent;\n        }\n\n        $this->fallback = new ResponseBodyResourceStream($resource);\n        $this->partialRead = false;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getContentAsString(): string\n    {\n        if (null === $this->fallback) {\n            // Use getChunks() to read stream content to $this->fallback\n            foreach ($this->getChunks() as $chunk) {\n            }\n            \\assert(null !== $this->fallback);\n        }\n\n        return $this->fallback->getContentAsString();\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getContentAsResource()\n    {\n        if (null === $this->fallback) {\n            // Use getChunks() to read stream content to $this->fallback\n            foreach ($this->getChunks() as $chunk) {\n            }\n            \\assert(null !== $this->fallback);\n        }\n\n        return $this->fallback->getContentAsResource();\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Stream/ResultStream.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace AsyncAws\\Core\\Stream;\n\n/**\n * Stream for a Result.\n */\ninterface ResultStream\n{\n    /**\n     * Download the response in chunks.\n     *\n     *     $fileHandler = fopen('/output.pdf', 'w');\n     *     foreach ($result->getBody()->getChunks() as $chunk) {\n     *       fwrite($fileHandler, $chunk);\n     *     }\n     *\n     * @return iterable<string>\n     */\n    public function getChunks(): iterable;\n\n    /**\n     * Download content into a temporary resource and return a string.\n     */\n    public function getContentAsString(): string;\n\n    /**\n     * Download content into a resource and then return that resource.\n     *\n     * @return resource\n     */\n    public function getContentAsResource();\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Stream/RewindableStream.php",
    "content": "<?php\n\nnamespace AsyncAws\\Core\\Stream;\n\n/**\n * Provides a Stream that can be read several time.\n *\n * This is for internal use only. One cannot iterate only over a few items of the stream.\n * If iterating over a stream, the full stream must be consumed before calling methods:\n * - stringify\n * - length\n * - hash\n *\n * @author Jérémy Derussé <jeremy@derusse.com>\n */\nfinal class RewindableStream implements RequestStream\n{\n    /**\n     * @var RequestStream\n     */\n    private $content;\n\n    /**\n     * @var RequestStream|null\n     */\n    private $fallback;\n\n    private function __construct(RequestStream $content)\n    {\n        $this->content = $content;\n    }\n\n    public static function create(RequestStream $content): RewindableStream\n    {\n        if ($content instanceof self) {\n            return $content;\n        }\n\n        return new self($content);\n    }\n\n    public function length(): ?int\n    {\n        if (null !== $this->fallback) {\n            return $this->fallback->length();\n        }\n\n        return $this->content->length();\n    }\n\n    public function stringify(): string\n    {\n        if (null !== $this->fallback) {\n            return $this->fallback->stringify();\n        }\n\n        return implode('', iterator_to_array($this));\n    }\n\n    public function getIterator(): \\Traversable\n    {\n        if (null !== $this->fallback) {\n            yield from $this->fallback;\n\n            return;\n        }\n\n        $resource = fopen('php://temp', 'r+b');\n        $this->fallback = ResourceStream::create($resource);\n\n        foreach ($this->content as $chunk) {\n            fwrite($resource, $chunk);\n            yield $chunk;\n        }\n    }\n\n    public function hash(string $algo = 'sha256', bool $raw = false): string\n    {\n        if (null !== $this->fallback) {\n            return $this->fallback->hash($algo, $raw);\n        }\n\n        $ctx = hash_init($algo);\n        foreach ($this as $chunk) {\n            hash_update($ctx, $chunk);\n        }\n\n        return hash_final($ctx, $raw);\n    }\n\n    public function read(): void\n    {\n        // Use getIterator() to read stream content to $this->fallback\n        foreach ($this as $chunk) {\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Stream/StreamFactory.php",
    "content": "<?php\n\nnamespace AsyncAws\\Core\\Stream;\n\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\n\n/**\n * Create Streams.\n *\n * @author Jérémy Derussé <jeremy@derusse.com>\n */\nclass StreamFactory\n{\n    /**\n     * @param string|resource|(callable(int): string)|iterable<string>|null $content\n     */\n    public static function create($content, int $preferredChunkSize = 64 * 1024): RequestStream\n    {\n        if (null === $content || \\is_string($content)) {\n            return StringStream::create($content ?? '');\n        }\n        if (\\is_callable($content)) {\n            return CallableStream::create($content, $preferredChunkSize);\n        }\n        if (is_iterable($content)) {\n            return IterableStream::create($content);\n        }\n        if (\\is_resource($content)) {\n            return ResourceStream::create($content, $preferredChunkSize);\n        }\n\n        throw new InvalidArgument(\\sprintf('Unexpected content type \"%s\".', \\is_object($content) ? \\get_class($content) : \\gettype($content)));\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Stream/StringStream.php",
    "content": "<?php\n\nnamespace AsyncAws\\Core\\Stream;\n\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\n\n/**\n * Convert a string into a Stream.\n *\n * @author Jérémy Derussé <jeremy@derusse.com>\n *\n * @internal\n */\nfinal class StringStream implements RequestStream\n{\n    /**\n     * @var string\n     */\n    private $content;\n\n    /**\n     * @var int|null\n     */\n    private $lengthCache;\n\n    private function __construct(string $content)\n    {\n        $this->content = $content;\n    }\n\n    /**\n     * @param RequestStream|string $content\n     */\n    public static function create($content): StringStream\n    {\n        if ($content instanceof self) {\n            return $content;\n        }\n        if ($content instanceof RequestStream) {\n            return new self($content->stringify());\n        }\n        if (\\is_string($content)) {\n            return new self($content);\n        }\n\n        throw new InvalidArgument(\\sprintf('Expect content to be a \"%s\" or as \"string\". \"%s\" given.', RequestStream::class, \\is_object($content) ? \\get_class($content) : \\gettype($content)));\n    }\n\n    public function length(): int\n    {\n        return $this->lengthCache ?? $this->lengthCache = \\strlen($this->content);\n    }\n\n    public function stringify(): string\n    {\n        return $this->content;\n    }\n\n    public function getIterator(): \\Traversable\n    {\n        yield $this->content;\n    }\n\n    public function hash(string $algo = 'sha256', bool $raw = false): string\n    {\n        return hash($algo, $this->content, $raw);\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Sts/Exception/ExpiredTokenException.php",
    "content": "<?php\n\nnamespace AsyncAws\\Core\\Sts\\Exception;\n\nuse AsyncAws\\Core\\Exception\\Http\\ClientException;\n\n/**\n * The web identity token that was passed is expired or is not valid. Get a new identity token from the identity\n * provider and then retry the request.\n */\nfinal class ExpiredTokenException extends ClientException\n{\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Sts/Exception/IDPCommunicationErrorException.php",
    "content": "<?php\n\nnamespace AsyncAws\\Core\\Sts\\Exception;\n\nuse AsyncAws\\Core\\Exception\\Http\\ClientException;\n\n/**\n * The request could not be fulfilled because the identity provider (IDP) that was asked to verify the incoming identity\n * token could not be reached. This is often a transient error caused by network conditions. Retry the request a limited\n * number of times so that you don't exceed the request rate. If the error persists, the identity provider might be down\n * or not responding.\n */\nfinal class IDPCommunicationErrorException extends ClientException\n{\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Sts/Exception/IDPRejectedClaimException.php",
    "content": "<?php\n\nnamespace AsyncAws\\Core\\Sts\\Exception;\n\nuse AsyncAws\\Core\\Exception\\Http\\ClientException;\n\n/**\n * The identity provider (IdP) reported that authentication failed. This might be because the claim is invalid.\n *\n * If this error is returned for the `AssumeRoleWithWebIdentity` operation, it can also mean that the claim has expired\n * or has been explicitly revoked.\n */\nfinal class IDPRejectedClaimException extends ClientException\n{\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Sts/Exception/InvalidIdentityTokenException.php",
    "content": "<?php\n\nnamespace AsyncAws\\Core\\Sts\\Exception;\n\nuse AsyncAws\\Core\\Exception\\Http\\ClientException;\n\n/**\n * The web identity token that was passed could not be validated by Amazon Web Services. Get a new identity token from\n * the identity provider and then retry the request.\n */\nfinal class InvalidIdentityTokenException extends ClientException\n{\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Sts/Exception/MalformedPolicyDocumentException.php",
    "content": "<?php\n\nnamespace AsyncAws\\Core\\Sts\\Exception;\n\nuse AsyncAws\\Core\\Exception\\Http\\ClientException;\n\n/**\n * The request was rejected because the policy document was malformed. The error message describes the specific error.\n */\nfinal class MalformedPolicyDocumentException extends ClientException\n{\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Sts/Exception/PackedPolicyTooLargeException.php",
    "content": "<?php\n\nnamespace AsyncAws\\Core\\Sts\\Exception;\n\nuse AsyncAws\\Core\\Exception\\Http\\ClientException;\n\n/**\n * The request was rejected because the total packed size of the session policies and session tags combined was too\n * large. An Amazon Web Services conversion compresses the session policy document, session policy ARNs, and session\n * tags into a packed binary format that has a separate limit. The error message indicates by percentage how close the\n * policies and tags are to the upper size limit. For more information, see Passing Session Tags in STS [^1] in the *IAM\n * User Guide*.\n *\n * You could receive this error even though you meet other defined session policy and session tag limits. For more\n * information, see IAM and STS Entity Character Limits [^2] in the *IAM User Guide*.\n *\n * [^1]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html\n * [^2]: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-quotas.html#reference_iam-limits-entity-length\n */\nfinal class PackedPolicyTooLargeException extends ClientException\n{\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Sts/Exception/RegionDisabledException.php",
    "content": "<?php\n\nnamespace AsyncAws\\Core\\Sts\\Exception;\n\nuse AsyncAws\\Core\\Exception\\Http\\ClientException;\n\n/**\n * STS is not activated in the requested region for the account that is being asked to generate credentials. The account\n * administrator must use the IAM console to activate STS in that region. For more information, see Activating and\n * Deactivating STS in an Amazon Web Services Region [^1] in the *IAM User Guide*.\n *\n * [^1]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html\n */\nfinal class RegionDisabledException extends ClientException\n{\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Sts/Input/AssumeRoleRequest.php",
    "content": "<?php\n\nnamespace AsyncAws\\Core\\Sts\\Input;\n\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\nuse AsyncAws\\Core\\Input;\nuse AsyncAws\\Core\\Request;\nuse AsyncAws\\Core\\Stream\\StreamFactory;\nuse AsyncAws\\Core\\Sts\\ValueObject\\PolicyDescriptorType;\nuse AsyncAws\\Core\\Sts\\ValueObject\\ProvidedContext;\nuse AsyncAws\\Core\\Sts\\ValueObject\\Tag;\n\nfinal class AssumeRoleRequest extends Input\n{\n    /**\n     * The Amazon Resource Name (ARN) of the role to assume.\n     *\n     * @required\n     *\n     * @var string|null\n     */\n    private $roleArn;\n\n    /**\n     * An identifier for the assumed role session.\n     *\n     * Use the role session name to uniquely identify a session when the same role is assumed by different principals or for\n     * different reasons. In cross-account scenarios, the role session name is visible to, and can be logged by the account\n     * that owns the role. The role session name is also used in the ARN of the assumed role principal. This means that\n     * subsequent cross-account API requests that use the temporary security credentials will expose the role session name\n     * to the external account in their CloudTrail logs.\n     *\n     * For security purposes, administrators can view this field in CloudTrail logs [^1] to help identify who performed an\n     * action in Amazon Web Services. Your administrator might require that you specify your user name as the session name\n     * when you assume the role. For more information, see `sts:RoleSessionName` [^2].\n     *\n     * The regex used to validate this parameter is a string of characters consisting of upper- and lower-case alphanumeric\n     * characters with no spaces. You can also include underscores or any of the following characters: =,.@-\n     *\n     * [^1]: https://docs.aws.amazon.com/IAM/latest/UserGuide/cloudtrail-integration.html#cloudtrail-integration_signin-tempcreds\n     * [^2]: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_iam-condition-keys.html#ck_rolesessionname\n     *\n     * @required\n     *\n     * @var string|null\n     */\n    private $roleSessionName;\n\n    /**\n     * The Amazon Resource Names (ARNs) of the IAM managed policies that you want to use as managed session policies. The\n     * policies must exist in the same account as the role.\n     *\n     * This parameter is optional. You can provide up to 10 managed policy ARNs. However, the plaintext that you use for\n     * both inline and managed session policies can't exceed 2,048 characters. For more information about ARNs, see Amazon\n     * Resource Names (ARNs) and Amazon Web Services Service Namespaces [^1] in the Amazon Web Services General Reference.\n     *\n     * > An Amazon Web Services conversion compresses the passed inline session policy, managed policy ARNs, and session\n     * > tags into a packed binary format that has a separate limit. Your request can fail for this limit even if your\n     * > plaintext meets the other requirements. The `PackedPolicySize` response element indicates by percentage how close\n     * > the policies and tags for your request are to the upper size limit.\n     *\n     * Passing policies to this operation returns new temporary credentials. The resulting session's permissions are the\n     * intersection of the role's identity-based policy and the session policies. You can use the role's temporary\n     * credentials in subsequent Amazon Web Services API calls to access resources in the account that owns the role. You\n     * cannot use session policies to grant more permissions than those allowed by the identity-based policy of the role\n     * that is being assumed. For more information, see Session Policies [^2] in the *IAM User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html\n     * [^2]: https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session\n     *\n     * @var PolicyDescriptorType[]|null\n     */\n    private $policyArns;\n\n    /**\n     * An IAM policy in JSON format that you want to use as an inline session policy.\n     *\n     * This parameter is optional. Passing policies to this operation returns new temporary credentials. The resulting\n     * session's permissions are the intersection of the role's identity-based policy and the session policies. You can use\n     * the role's temporary credentials in subsequent Amazon Web Services API calls to access resources in the account that\n     * owns the role. You cannot use session policies to grant more permissions than those allowed by the identity-based\n     * policy of the role that is being assumed. For more information, see Session Policies [^1] in the *IAM User Guide*.\n     *\n     * The plaintext that you use for both inline and managed session policies can't exceed 2,048 characters. The JSON\n     * policy characters can be any ASCII character from the space character to the end of the valid character list (\\u0020\n     * through \\u00FF). It can also include the tab (\\u0009), linefeed (\\u000A), and carriage return (\\u000D) characters.\n     *\n     * > An Amazon Web Services conversion compresses the passed inline session policy, managed policy ARNs, and session\n     * > tags into a packed binary format that has a separate limit. Your request can fail for this limit even if your\n     * > plaintext meets the other requirements. The `PackedPolicySize` response element indicates by percentage how close\n     * > the policies and tags for your request are to the upper size limit.\n     *\n     * For more information about role session permissions, see Session policies [^2].\n     *\n     * [^1]: https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session\n     * [^2]: https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session\n     *\n     * @var string|null\n     */\n    private $policy;\n\n    /**\n     * The duration, in seconds, of the role session. The value specified can range from 900 seconds (15 minutes) up to the\n     * maximum session duration set for the role. The maximum session duration setting can have a value from 1 hour to 12\n     * hours. If you specify a value higher than this setting or the administrator setting (whichever is lower), the\n     * operation fails. For example, if you specify a session duration of 12 hours, but your administrator set the maximum\n     * session duration to 6 hours, your operation fails.\n     *\n     * Role chaining limits your Amazon Web Services CLI or Amazon Web Services API role session to a maximum of one hour.\n     * When you use the `AssumeRole` API operation to assume a role, you can specify the duration of your role session with\n     * the `DurationSeconds` parameter. You can specify a parameter value of up to 43200 seconds (12 hours), depending on\n     * the maximum session duration setting for your role. However, if you assume a role using role chaining and provide a\n     * `DurationSeconds` parameter value greater than one hour, the operation fails. To learn how to view the maximum value\n     * for your role, see Update the maximum session duration for a role [^1].\n     *\n     * By default, the value is set to `3600` seconds.\n     *\n     * > The `DurationSeconds` parameter is separate from the duration of a console session that you might request using the\n     * > returned credentials. The request to the federation endpoint for a console sign-in token takes a `SessionDuration`\n     * > parameter that specifies the maximum length of the console session. For more information, see Creating a URL that\n     * > Enables Federated Users to Access the Amazon Web Services Management Console [^2] in the *IAM User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_update-role-settings.html#id_roles_update-session-duration\n     * [^2]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_enable-console-custom-url.html\n     *\n     * @var int|null\n     */\n    private $durationSeconds;\n\n    /**\n     * A list of session tags that you want to pass. Each session tag consists of a key name and an associated value. For\n     * more information about session tags, see Tagging Amazon Web Services STS Sessions [^1] in the *IAM User Guide*.\n     *\n     * This parameter is optional. You can pass up to 50 session tags. The plaintext session tag keys can’t exceed 128\n     * characters, and the values can’t exceed 256 characters. For these and additional limits, see IAM and STS Character\n     * Limits [^2] in the *IAM User Guide*.\n     *\n     * > An Amazon Web Services conversion compresses the passed inline session policy, managed policy ARNs, and session\n     * > tags into a packed binary format that has a separate limit. Your request can fail for this limit even if your\n     * > plaintext meets the other requirements. The `PackedPolicySize` response element indicates by percentage how close\n     * > the policies and tags for your request are to the upper size limit.\n     *\n     * You can pass a session tag with the same key as a tag that is already attached to the role. When you do, session tags\n     * override a role tag with the same key.\n     *\n     * Tag key–value pairs are not case sensitive, but case is preserved. This means that you cannot have separate\n     * `Department` and `department` tag keys. Assume that the role has the `Department`=`Marketing` tag and you pass the\n     * `department`=`engineering` session tag. `Department` and `department` are not saved as separate tags, and the session\n     * tag passed in the request takes precedence over the role tag.\n     *\n     * Additionally, if you used temporary credentials to perform this operation, the new session inherits any transitive\n     * session tags from the calling session. If you pass a session tag with the same key as an inherited tag, the operation\n     * fails. To view the inherited tags for a session, see the CloudTrail logs. For more information, see Viewing Session\n     * Tags in CloudTrail [^3] in the *IAM User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html\n     * [^2]: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-limits.html#reference_iam-limits-entity-length\n     * [^3]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html#id_session-tags_ctlogs\n     *\n     * @var Tag[]|null\n     */\n    private $tags;\n\n    /**\n     * A list of keys for session tags that you want to set as transitive. If you set a tag key as transitive, the\n     * corresponding key and value passes to subsequent sessions in a role chain. For more information, see Chaining Roles\n     * with Session Tags [^1] in the *IAM User Guide*.\n     *\n     * This parameter is optional. The transitive status of a session tag does not impact its packed binary size.\n     *\n     * If you choose not to specify a transitive tag key, then no tags are passed from this session to any subsequent\n     * sessions.\n     *\n     * [^1]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html#id_session-tags_role-chaining\n     *\n     * @var string[]|null\n     */\n    private $transitiveTagKeys;\n\n    /**\n     * A unique identifier that might be required when you assume a role in another account. If the administrator of the\n     * account to which the role belongs provided you with an external ID, then provide that value in the `ExternalId`\n     * parameter. This value can be any string, such as a passphrase or account number. A cross-account role is usually set\n     * up to trust everyone in an account. Therefore, the administrator of the trusting account might send an external ID to\n     * the administrator of the trusted account. That way, only someone with the ID can assume the role, rather than\n     * everyone in the account. For more information about the external ID, see How to Use an External ID When Granting\n     * Access to Your Amazon Web Services Resources to a Third Party [^1] in the *IAM User Guide*.\n     *\n     * The regex used to validate this parameter is a string of characters consisting of upper- and lower-case alphanumeric\n     * characters with no spaces. You can also include underscores or any of the following characters: =,.@:/-\n     *\n     * [^1]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-user_externalid.html\n     *\n     * @var string|null\n     */\n    private $externalId;\n\n    /**\n     * The identification number of the MFA device that is associated with the user who is making the `AssumeRole` call.\n     * Specify this value if the trust policy of the role being assumed includes a condition that requires MFA\n     * authentication. The value is either the serial number for a hardware device (such as `GAHT12345678`) or an Amazon\n     * Resource Name (ARN) for a virtual device (such as `arn:aws:iam::123456789012:mfa/user`).\n     *\n     * The regex used to validate this parameter is a string of characters consisting of upper- and lower-case alphanumeric\n     * characters with no spaces. You can also include underscores or any of the following characters: =,.@-\n     *\n     * @var string|null\n     */\n    private $serialNumber;\n\n    /**\n     * The value provided by the MFA device, if the trust policy of the role being assumed requires MFA. (In other words, if\n     * the policy includes a condition that tests for MFA). If the role being assumed requires MFA and if the `TokenCode`\n     * value is missing or expired, the `AssumeRole` call returns an \"access denied\" error.\n     *\n     * The format for this parameter, as described by its regex pattern, is a sequence of six numeric digits.\n     *\n     * @var string|null\n     */\n    private $tokenCode;\n\n    /**\n     * The source identity specified by the principal that is calling the `AssumeRole` operation. The source identity value\n     * persists across chained role [^1] sessions.\n     *\n     * You can require users to specify a source identity when they assume a role. You do this by using the\n     * `sts:SourceIdentity` [^2] condition key in a role trust policy. You can use source identity information in CloudTrail\n     * logs to determine who took actions with a role. You can use the `aws:SourceIdentity` condition key to further control\n     * access to Amazon Web Services resources based on the value of source identity. For more information about using\n     * source identity, see Monitor and control actions taken with assumed roles [^3] in the *IAM User Guide*.\n     *\n     * The regex used to validate this parameter is a string of characters consisting of upper- and lower-case alphanumeric\n     * characters with no spaces. You can also include underscores or any of the following characters: +=,.@-. You cannot\n     * use a value that begins with the text `aws:`. This prefix is reserved for Amazon Web Services internal use.\n     *\n     * [^1]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles.html#iam-term-role-chaining\n     * [^2]: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_condition-keys.html#condition-keys-sourceidentity\n     * [^3]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_monitor.html\n     *\n     * @var string|null\n     */\n    private $sourceIdentity;\n\n    /**\n     * A list of previously acquired trusted context assertions in the format of a JSON array. The trusted context assertion\n     * is signed and encrypted by Amazon Web Services STS.\n     *\n     * The following is an example of a `ProvidedContext` value that includes a single trusted context assertion and the ARN\n     * of the context provider from which the trusted context assertion was generated.\n     *\n     * `[{\"ProviderArn\":\"arn:aws:iam::aws:contextProvider/IdentityCenter\",\"ContextAssertion\":\"trusted-context-assertion\"}]`\n     *\n     * @var ProvidedContext[]|null\n     */\n    private $providedContexts;\n\n    /**\n     * @param array{\n     *   RoleArn?: string,\n     *   RoleSessionName?: string,\n     *   PolicyArns?: null|array<PolicyDescriptorType|array>,\n     *   Policy?: null|string,\n     *   DurationSeconds?: null|int,\n     *   Tags?: null|array<Tag|array>,\n     *   TransitiveTagKeys?: null|string[],\n     *   ExternalId?: null|string,\n     *   SerialNumber?: null|string,\n     *   TokenCode?: null|string,\n     *   SourceIdentity?: null|string,\n     *   ProvidedContexts?: null|array<ProvidedContext|array>,\n     *   '@region'?: string|null,\n     * } $input\n     */\n    public function __construct(array $input = [])\n    {\n        $this->roleArn = $input['RoleArn'] ?? null;\n        $this->roleSessionName = $input['RoleSessionName'] ?? null;\n        $this->policyArns = isset($input['PolicyArns']) ? array_map([PolicyDescriptorType::class, 'create'], $input['PolicyArns']) : null;\n        $this->policy = $input['Policy'] ?? null;\n        $this->durationSeconds = $input['DurationSeconds'] ?? null;\n        $this->tags = isset($input['Tags']) ? array_map([Tag::class, 'create'], $input['Tags']) : null;\n        $this->transitiveTagKeys = $input['TransitiveTagKeys'] ?? null;\n        $this->externalId = $input['ExternalId'] ?? null;\n        $this->serialNumber = $input['SerialNumber'] ?? null;\n        $this->tokenCode = $input['TokenCode'] ?? null;\n        $this->sourceIdentity = $input['SourceIdentity'] ?? null;\n        $this->providedContexts = isset($input['ProvidedContexts']) ? array_map([ProvidedContext::class, 'create'], $input['ProvidedContexts']) : null;\n        parent::__construct($input);\n    }\n\n    /**\n     * @param array{\n     *   RoleArn?: string,\n     *   RoleSessionName?: string,\n     *   PolicyArns?: null|array<PolicyDescriptorType|array>,\n     *   Policy?: null|string,\n     *   DurationSeconds?: null|int,\n     *   Tags?: null|array<Tag|array>,\n     *   TransitiveTagKeys?: null|string[],\n     *   ExternalId?: null|string,\n     *   SerialNumber?: null|string,\n     *   TokenCode?: null|string,\n     *   SourceIdentity?: null|string,\n     *   ProvidedContexts?: null|array<ProvidedContext|array>,\n     *   '@region'?: string|null,\n     * }|AssumeRoleRequest $input\n     */\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    public function getDurationSeconds(): ?int\n    {\n        return $this->durationSeconds;\n    }\n\n    public function getExternalId(): ?string\n    {\n        return $this->externalId;\n    }\n\n    public function getPolicy(): ?string\n    {\n        return $this->policy;\n    }\n\n    /**\n     * @return PolicyDescriptorType[]\n     */\n    public function getPolicyArns(): array\n    {\n        return $this->policyArns ?? [];\n    }\n\n    /**\n     * @return ProvidedContext[]\n     */\n    public function getProvidedContexts(): array\n    {\n        return $this->providedContexts ?? [];\n    }\n\n    public function getRoleArn(): ?string\n    {\n        return $this->roleArn;\n    }\n\n    public function getRoleSessionName(): ?string\n    {\n        return $this->roleSessionName;\n    }\n\n    public function getSerialNumber(): ?string\n    {\n        return $this->serialNumber;\n    }\n\n    public function getSourceIdentity(): ?string\n    {\n        return $this->sourceIdentity;\n    }\n\n    /**\n     * @return Tag[]\n     */\n    public function getTags(): array\n    {\n        return $this->tags ?? [];\n    }\n\n    public function getTokenCode(): ?string\n    {\n        return $this->tokenCode;\n    }\n\n    /**\n     * @return string[]\n     */\n    public function getTransitiveTagKeys(): array\n    {\n        return $this->transitiveTagKeys ?? [];\n    }\n\n    /**\n     * @internal\n     */\n    public function request(): Request\n    {\n        // Prepare headers\n        $headers = ['content-type' => 'application/x-www-form-urlencoded'];\n\n        // Prepare query\n        $query = [];\n\n        // Prepare URI\n        $uriString = '/';\n\n        // Prepare Body\n        $body = http_build_query(['Action' => 'AssumeRole', 'Version' => '2011-06-15'] + $this->requestBody(), '', '&', \\PHP_QUERY_RFC1738);\n\n        // Return the Request\n        return new Request('POST', $uriString, $query, $headers, StreamFactory::create($body));\n    }\n\n    public function setDurationSeconds(?int $value): self\n    {\n        $this->durationSeconds = $value;\n\n        return $this;\n    }\n\n    public function setExternalId(?string $value): self\n    {\n        $this->externalId = $value;\n\n        return $this;\n    }\n\n    public function setPolicy(?string $value): self\n    {\n        $this->policy = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param PolicyDescriptorType[] $value\n     */\n    public function setPolicyArns(array $value): self\n    {\n        $this->policyArns = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param ProvidedContext[] $value\n     */\n    public function setProvidedContexts(array $value): self\n    {\n        $this->providedContexts = $value;\n\n        return $this;\n    }\n\n    public function setRoleArn(?string $value): self\n    {\n        $this->roleArn = $value;\n\n        return $this;\n    }\n\n    public function setRoleSessionName(?string $value): self\n    {\n        $this->roleSessionName = $value;\n\n        return $this;\n    }\n\n    public function setSerialNumber(?string $value): self\n    {\n        $this->serialNumber = $value;\n\n        return $this;\n    }\n\n    public function setSourceIdentity(?string $value): self\n    {\n        $this->sourceIdentity = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param Tag[] $value\n     */\n    public function setTags(array $value): self\n    {\n        $this->tags = $value;\n\n        return $this;\n    }\n\n    public function setTokenCode(?string $value): self\n    {\n        $this->tokenCode = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param string[] $value\n     */\n    public function setTransitiveTagKeys(array $value): self\n    {\n        $this->transitiveTagKeys = $value;\n\n        return $this;\n    }\n\n    private function requestBody(): array\n    {\n        $payload = [];\n        if (null === $v = $this->roleArn) {\n            throw new InvalidArgument(\\sprintf('Missing parameter \"RoleArn\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        $payload['RoleArn'] = $v;\n        if (null === $v = $this->roleSessionName) {\n            throw new InvalidArgument(\\sprintf('Missing parameter \"RoleSessionName\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        $payload['RoleSessionName'] = $v;\n        if (null !== $v = $this->policyArns) {\n            $index = 0;\n            foreach ($v as $mapValue) {\n                ++$index;\n                foreach ($mapValue->requestBody() as $bodyKey => $bodyValue) {\n                    $payload[\"PolicyArns.member.$index.$bodyKey\"] = $bodyValue;\n                }\n            }\n        }\n        if (null !== $v = $this->policy) {\n            $payload['Policy'] = $v;\n        }\n        if (null !== $v = $this->durationSeconds) {\n            $payload['DurationSeconds'] = $v;\n        }\n        if (null !== $v = $this->tags) {\n            $index = 0;\n            foreach ($v as $mapValue) {\n                ++$index;\n                foreach ($mapValue->requestBody() as $bodyKey => $bodyValue) {\n                    $payload[\"Tags.member.$index.$bodyKey\"] = $bodyValue;\n                }\n            }\n        }\n        if (null !== $v = $this->transitiveTagKeys) {\n            $index = 0;\n            foreach ($v as $mapValue) {\n                ++$index;\n                $payload[\"TransitiveTagKeys.member.$index\"] = $mapValue;\n            }\n        }\n        if (null !== $v = $this->externalId) {\n            $payload['ExternalId'] = $v;\n        }\n        if (null !== $v = $this->serialNumber) {\n            $payload['SerialNumber'] = $v;\n        }\n        if (null !== $v = $this->tokenCode) {\n            $payload['TokenCode'] = $v;\n        }\n        if (null !== $v = $this->sourceIdentity) {\n            $payload['SourceIdentity'] = $v;\n        }\n        if (null !== $v = $this->providedContexts) {\n            $index = 0;\n            foreach ($v as $mapValue) {\n                ++$index;\n                foreach ($mapValue->requestBody() as $bodyKey => $bodyValue) {\n                    $payload[\"ProvidedContexts.member.$index.$bodyKey\"] = $bodyValue;\n                }\n            }\n        }\n\n        return $payload;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Sts/Input/AssumeRoleWithWebIdentityRequest.php",
    "content": "<?php\n\nnamespace AsyncAws\\Core\\Sts\\Input;\n\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\nuse AsyncAws\\Core\\Input;\nuse AsyncAws\\Core\\Request;\nuse AsyncAws\\Core\\Stream\\StreamFactory;\nuse AsyncAws\\Core\\Sts\\ValueObject\\PolicyDescriptorType;\n\nfinal class AssumeRoleWithWebIdentityRequest extends Input\n{\n    /**\n     * The Amazon Resource Name (ARN) of the role that the caller is assuming.\n     *\n     * > Additional considerations apply to Amazon Cognito identity pools that assume cross-account IAM roles [^1]. The\n     * > trust policies of these roles must accept the `cognito-identity.amazonaws.com` service principal and must contain\n     * > the `cognito-identity.amazonaws.com:aud` condition key to restrict role assumption to users from your intended\n     * > identity pools. A policy that trusts Amazon Cognito identity pools without this condition creates a risk that a\n     * > user from an unintended identity pool can assume the role. For more information, see Trust policies for IAM roles\n     * > in Basic (Classic) authentication [^2] in the *Amazon Cognito Developer Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies-cross-account-resource-access.html\n     * [^2]: https://docs.aws.amazon.com/cognito/latest/developerguide/iam-roles.html#trust-policies\n     *\n     * @required\n     *\n     * @var string|null\n     */\n    private $roleArn;\n\n    /**\n     * An identifier for the assumed role session. Typically, you pass the name or identifier that is associated with the\n     * user who is using your application. That way, the temporary security credentials that your application will use are\n     * associated with that user. This session name is included as part of the ARN and assumed role ID in the\n     * `AssumedRoleUser` response element.\n     *\n     * For security purposes, administrators can view this field in CloudTrail logs [^1] to help identify who performed an\n     * action in Amazon Web Services. Your administrator might require that you specify your user name as the session name\n     * when you assume the role. For more information, see `sts:RoleSessionName` [^2].\n     *\n     * The regex used to validate this parameter is a string of characters consisting of upper- and lower-case alphanumeric\n     * characters with no spaces. You can also include underscores or any of the following characters: =,.@-\n     *\n     * [^1]: https://docs.aws.amazon.com/IAM/latest/UserGuide/cloudtrail-integration.html#cloudtrail-integration_signin-tempcreds\n     * [^2]: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_iam-condition-keys.html#ck_rolesessionname\n     *\n     * @required\n     *\n     * @var string|null\n     */\n    private $roleSessionName;\n\n    /**\n     * The OAuth 2.0 access token or OpenID Connect ID token that is provided by the identity provider. Your application\n     * must get this token by authenticating the user who is using your application with a web identity provider before the\n     * application makes an `AssumeRoleWithWebIdentity` call. Timestamps in the token must be formatted as either an integer\n     * or a long integer. Tokens must be signed using either RSA keys (RS256, RS384, or RS512) or ECDSA keys (ES256, ES384,\n     * or ES512).\n     *\n     * @required\n     *\n     * @var string|null\n     */\n    private $webIdentityToken;\n\n    /**\n     * The fully qualified host component of the domain name of the OAuth 2.0 identity provider. Do not specify this value\n     * for an OpenID Connect identity provider.\n     *\n     * Currently `www.amazon.com` and `graph.facebook.com` are the only supported identity providers for OAuth 2.0 access\n     * tokens. Do not include URL schemes and port numbers.\n     *\n     * Do not specify this value for OpenID Connect ID tokens.\n     *\n     * @var string|null\n     */\n    private $providerId;\n\n    /**\n     * The Amazon Resource Names (ARNs) of the IAM managed policies that you want to use as managed session policies. The\n     * policies must exist in the same account as the role.\n     *\n     * This parameter is optional. You can provide up to 10 managed policy ARNs. However, the plaintext that you use for\n     * both inline and managed session policies can't exceed 2,048 characters. For more information about ARNs, see Amazon\n     * Resource Names (ARNs) and Amazon Web Services Service Namespaces [^1] in the Amazon Web Services General Reference.\n     *\n     * > An Amazon Web Services conversion compresses the passed inline session policy, managed policy ARNs, and session\n     * > tags into a packed binary format that has a separate limit. Your request can fail for this limit even if your\n     * > plaintext meets the other requirements. The `PackedPolicySize` response element indicates by percentage how close\n     * > the policies and tags for your request are to the upper size limit.\n     *\n     * Passing policies to this operation returns new temporary credentials. The resulting session's permissions are the\n     * intersection of the role's identity-based policy and the session policies. You can use the role's temporary\n     * credentials in subsequent Amazon Web Services API calls to access resources in the account that owns the role. You\n     * cannot use session policies to grant more permissions than those allowed by the identity-based policy of the role\n     * that is being assumed. For more information, see Session Policies [^2] in the *IAM User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html\n     * [^2]: https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session\n     *\n     * @var PolicyDescriptorType[]|null\n     */\n    private $policyArns;\n\n    /**\n     * An IAM policy in JSON format that you want to use as an inline session policy.\n     *\n     * This parameter is optional. Passing policies to this operation returns new temporary credentials. The resulting\n     * session's permissions are the intersection of the role's identity-based policy and the session policies. You can use\n     * the role's temporary credentials in subsequent Amazon Web Services API calls to access resources in the account that\n     * owns the role. You cannot use session policies to grant more permissions than those allowed by the identity-based\n     * policy of the role that is being assumed. For more information, see Session Policies [^1] in the *IAM User Guide*.\n     *\n     * The plaintext that you use for both inline and managed session policies can't exceed 2,048 characters. The JSON\n     * policy characters can be any ASCII character from the space character to the end of the valid character list (\\u0020\n     * through \\u00FF). It can also include the tab (\\u0009), linefeed (\\u000A), and carriage return (\\u000D) characters.\n     *\n     * For more information about role session permissions, see Session policies [^2].\n     *\n     * > An Amazon Web Services conversion compresses the passed inline session policy, managed policy ARNs, and session\n     * > tags into a packed binary format that has a separate limit. Your request can fail for this limit even if your\n     * > plaintext meets the other requirements. The `PackedPolicySize` response element indicates by percentage how close\n     * > the policies and tags for your request are to the upper size limit.\n     *\n     * [^1]: https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session\n     * [^2]: https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session\n     *\n     * @var string|null\n     */\n    private $policy;\n\n    /**\n     * The duration, in seconds, of the role session. The value can range from 900 seconds (15 minutes) up to the maximum\n     * session duration setting for the role. This setting can have a value from 1 hour to 12 hours. If you specify a value\n     * higher than this setting, the operation fails. For example, if you specify a session duration of 12 hours, but your\n     * administrator set the maximum session duration to 6 hours, your operation fails. To learn how to view the maximum\n     * value for your role, see View the Maximum Session Duration Setting for a Role [^1] in the *IAM User Guide*.\n     *\n     * By default, the value is set to `3600` seconds.\n     *\n     * > The `DurationSeconds` parameter is separate from the duration of a console session that you might request using the\n     * > returned credentials. The request to the federation endpoint for a console sign-in token takes a `SessionDuration`\n     * > parameter that specifies the maximum length of the console session. For more information, see Creating a URL that\n     * > Enables Federated Users to Access the Amazon Web Services Management Console [^2] in the *IAM User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html#id_roles_use_view-role-max-session\n     * [^2]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_enable-console-custom-url.html\n     *\n     * @var int|null\n     */\n    private $durationSeconds;\n\n    /**\n     * @param array{\n     *   RoleArn?: string,\n     *   RoleSessionName?: string,\n     *   WebIdentityToken?: string,\n     *   ProviderId?: null|string,\n     *   PolicyArns?: null|array<PolicyDescriptorType|array>,\n     *   Policy?: null|string,\n     *   DurationSeconds?: null|int,\n     *   '@region'?: string|null,\n     * } $input\n     */\n    public function __construct(array $input = [])\n    {\n        $this->roleArn = $input['RoleArn'] ?? null;\n        $this->roleSessionName = $input['RoleSessionName'] ?? null;\n        $this->webIdentityToken = $input['WebIdentityToken'] ?? null;\n        $this->providerId = $input['ProviderId'] ?? null;\n        $this->policyArns = isset($input['PolicyArns']) ? array_map([PolicyDescriptorType::class, 'create'], $input['PolicyArns']) : null;\n        $this->policy = $input['Policy'] ?? null;\n        $this->durationSeconds = $input['DurationSeconds'] ?? null;\n        parent::__construct($input);\n    }\n\n    /**\n     * @param array{\n     *   RoleArn?: string,\n     *   RoleSessionName?: string,\n     *   WebIdentityToken?: string,\n     *   ProviderId?: null|string,\n     *   PolicyArns?: null|array<PolicyDescriptorType|array>,\n     *   Policy?: null|string,\n     *   DurationSeconds?: null|int,\n     *   '@region'?: string|null,\n     * }|AssumeRoleWithWebIdentityRequest $input\n     */\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    public function getDurationSeconds(): ?int\n    {\n        return $this->durationSeconds;\n    }\n\n    public function getPolicy(): ?string\n    {\n        return $this->policy;\n    }\n\n    /**\n     * @return PolicyDescriptorType[]\n     */\n    public function getPolicyArns(): array\n    {\n        return $this->policyArns ?? [];\n    }\n\n    public function getProviderId(): ?string\n    {\n        return $this->providerId;\n    }\n\n    public function getRoleArn(): ?string\n    {\n        return $this->roleArn;\n    }\n\n    public function getRoleSessionName(): ?string\n    {\n        return $this->roleSessionName;\n    }\n\n    public function getWebIdentityToken(): ?string\n    {\n        return $this->webIdentityToken;\n    }\n\n    /**\n     * @internal\n     */\n    public function request(): Request\n    {\n        // Prepare headers\n        $headers = ['content-type' => 'application/x-www-form-urlencoded'];\n\n        // Prepare query\n        $query = [];\n\n        // Prepare URI\n        $uriString = '/';\n\n        // Prepare Body\n        $body = http_build_query(['Action' => 'AssumeRoleWithWebIdentity', 'Version' => '2011-06-15'] + $this->requestBody(), '', '&', \\PHP_QUERY_RFC1738);\n\n        // Return the Request\n        return new Request('POST', $uriString, $query, $headers, StreamFactory::create($body));\n    }\n\n    public function setDurationSeconds(?int $value): self\n    {\n        $this->durationSeconds = $value;\n\n        return $this;\n    }\n\n    public function setPolicy(?string $value): self\n    {\n        $this->policy = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param PolicyDescriptorType[] $value\n     */\n    public function setPolicyArns(array $value): self\n    {\n        $this->policyArns = $value;\n\n        return $this;\n    }\n\n    public function setProviderId(?string $value): self\n    {\n        $this->providerId = $value;\n\n        return $this;\n    }\n\n    public function setRoleArn(?string $value): self\n    {\n        $this->roleArn = $value;\n\n        return $this;\n    }\n\n    public function setRoleSessionName(?string $value): self\n    {\n        $this->roleSessionName = $value;\n\n        return $this;\n    }\n\n    public function setWebIdentityToken(?string $value): self\n    {\n        $this->webIdentityToken = $value;\n\n        return $this;\n    }\n\n    private function requestBody(): array\n    {\n        $payload = [];\n        if (null === $v = $this->roleArn) {\n            throw new InvalidArgument(\\sprintf('Missing parameter \"RoleArn\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        $payload['RoleArn'] = $v;\n        if (null === $v = $this->roleSessionName) {\n            throw new InvalidArgument(\\sprintf('Missing parameter \"RoleSessionName\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        $payload['RoleSessionName'] = $v;\n        if (null === $v = $this->webIdentityToken) {\n            throw new InvalidArgument(\\sprintf('Missing parameter \"WebIdentityToken\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        $payload['WebIdentityToken'] = $v;\n        if (null !== $v = $this->providerId) {\n            $payload['ProviderId'] = $v;\n        }\n        if (null !== $v = $this->policyArns) {\n            $index = 0;\n            foreach ($v as $mapValue) {\n                ++$index;\n                foreach ($mapValue->requestBody() as $bodyKey => $bodyValue) {\n                    $payload[\"PolicyArns.member.$index.$bodyKey\"] = $bodyValue;\n                }\n            }\n        }\n        if (null !== $v = $this->policy) {\n            $payload['Policy'] = $v;\n        }\n        if (null !== $v = $this->durationSeconds) {\n            $payload['DurationSeconds'] = $v;\n        }\n\n        return $payload;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Sts/Input/GetCallerIdentityRequest.php",
    "content": "<?php\n\nnamespace AsyncAws\\Core\\Sts\\Input;\n\nuse AsyncAws\\Core\\Input;\nuse AsyncAws\\Core\\Request;\nuse AsyncAws\\Core\\Stream\\StreamFactory;\n\nfinal class GetCallerIdentityRequest extends Input\n{\n    /**\n     * @param array{\n     *   '@region'?: string|null,\n     * } $input\n     */\n    public function __construct(array $input = [])\n    {\n        parent::__construct($input);\n    }\n\n    /**\n     * @param array{\n     *   '@region'?: string|null,\n     * }|GetCallerIdentityRequest $input\n     */\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    /**\n     * @internal\n     */\n    public function request(): Request\n    {\n        // Prepare headers\n        $headers = ['content-type' => 'application/x-www-form-urlencoded'];\n\n        // Prepare query\n        $query = [];\n\n        // Prepare URI\n        $uriString = '/';\n\n        // Prepare Body\n        $body = http_build_query(['Action' => 'GetCallerIdentity', 'Version' => '2011-06-15'] + $this->requestBody(), '', '&', \\PHP_QUERY_RFC1738);\n\n        // Return the Request\n        return new Request('POST', $uriString, $query, $headers, StreamFactory::create($body));\n    }\n\n    private function requestBody(): array\n    {\n        $payload = [];\n\n        return $payload;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Sts/Result/AssumeRoleResponse.php",
    "content": "<?php\n\nnamespace AsyncAws\\Core\\Sts\\Result;\n\nuse AsyncAws\\Core\\Response;\nuse AsyncAws\\Core\\Result;\nuse AsyncAws\\Core\\Sts\\ValueObject\\AssumedRoleUser;\nuse AsyncAws\\Core\\Sts\\ValueObject\\Credentials;\n\n/**\n * Contains the response to a successful AssumeRole request, including temporary Amazon Web Services credentials that\n * can be used to make Amazon Web Services requests.\n */\nclass AssumeRoleResponse extends Result\n{\n    /**\n     * The temporary security credentials, which include an access key ID, a secret access key, and a security (or session)\n     * token.\n     *\n     * > The size of the security token that STS API operations return is not fixed. We strongly recommend that you make no\n     * > assumptions about the maximum size.\n     *\n     * @var Credentials|null\n     */\n    private $credentials;\n\n    /**\n     * The Amazon Resource Name (ARN) and the assumed role ID, which are identifiers that you can use to refer to the\n     * resulting temporary security credentials. For example, you can reference these credentials as a principal in a\n     * resource-based policy by using the ARN or assumed role ID. The ARN and ID include the `RoleSessionName` that you\n     * specified when you called `AssumeRole`.\n     *\n     * @var AssumedRoleUser|null\n     */\n    private $assumedRoleUser;\n\n    /**\n     * A percentage value that indicates the packed size of the session policies and session tags combined passed in the\n     * request. The request fails if the packed size is greater than 100 percent, which means the policies and tags exceeded\n     * the allowed space.\n     *\n     * @var int|null\n     */\n    private $packedPolicySize;\n\n    /**\n     * The source identity specified by the principal that is calling the `AssumeRole` operation.\n     *\n     * You can require users to specify a source identity when they assume a role. You do this by using the\n     * `sts:SourceIdentity` condition key in a role trust policy. You can use source identity information in CloudTrail logs\n     * to determine who took actions with a role. You can use the `aws:SourceIdentity` condition key to further control\n     * access to Amazon Web Services resources based on the value of source identity. For more information about using\n     * source identity, see Monitor and control actions taken with assumed roles [^1] in the *IAM User Guide*.\n     *\n     * The regex used to validate this parameter is a string of characters consisting of upper- and lower-case alphanumeric\n     * characters with no spaces. You can also include underscores or any of the following characters: =,.@-\n     *\n     * [^1]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_monitor.html\n     *\n     * @var string|null\n     */\n    private $sourceIdentity;\n\n    public function getAssumedRoleUser(): ?AssumedRoleUser\n    {\n        $this->initialize();\n\n        return $this->assumedRoleUser;\n    }\n\n    public function getCredentials(): ?Credentials\n    {\n        $this->initialize();\n\n        return $this->credentials;\n    }\n\n    public function getPackedPolicySize(): ?int\n    {\n        $this->initialize();\n\n        return $this->packedPolicySize;\n    }\n\n    public function getSourceIdentity(): ?string\n    {\n        $this->initialize();\n\n        return $this->sourceIdentity;\n    }\n\n    protected function populateResult(Response $response): void\n    {\n        $data = new \\SimpleXMLElement($response->getContent());\n        $data = $data->AssumeRoleResult;\n\n        $this->credentials = 0 === $data->Credentials->count() ? null : $this->populateResultCredentials($data->Credentials);\n        $this->assumedRoleUser = 0 === $data->AssumedRoleUser->count() ? null : $this->populateResultAssumedRoleUser($data->AssumedRoleUser);\n        $this->packedPolicySize = (null !== $v = $data->PackedPolicySize[0]) ? (int) (string) $v : null;\n        $this->sourceIdentity = (null !== $v = $data->SourceIdentity[0]) ? (string) $v : null;\n    }\n\n    private function populateResultAssumedRoleUser(\\SimpleXMLElement $xml): AssumedRoleUser\n    {\n        return new AssumedRoleUser([\n            'AssumedRoleId' => (string) $xml->AssumedRoleId,\n            'Arn' => (string) $xml->Arn,\n        ]);\n    }\n\n    private function populateResultCredentials(\\SimpleXMLElement $xml): Credentials\n    {\n        return new Credentials([\n            'AccessKeyId' => (string) $xml->AccessKeyId,\n            'SecretAccessKey' => (string) $xml->SecretAccessKey,\n            'SessionToken' => (string) $xml->SessionToken,\n            'Expiration' => new \\DateTimeImmutable((string) $xml->Expiration),\n        ]);\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Sts/Result/AssumeRoleWithWebIdentityResponse.php",
    "content": "<?php\n\nnamespace AsyncAws\\Core\\Sts\\Result;\n\nuse AsyncAws\\Core\\Response;\nuse AsyncAws\\Core\\Result;\nuse AsyncAws\\Core\\Sts\\ValueObject\\AssumedRoleUser;\nuse AsyncAws\\Core\\Sts\\ValueObject\\Credentials;\n\n/**\n * Contains the response to a successful AssumeRoleWithWebIdentity request, including temporary Amazon Web Services\n * credentials that can be used to make Amazon Web Services requests.\n */\nclass AssumeRoleWithWebIdentityResponse extends Result\n{\n    /**\n     * The temporary security credentials, which include an access key ID, a secret access key, and a security token.\n     *\n     * > The size of the security token that STS API operations return is not fixed. We strongly recommend that you make no\n     * > assumptions about the maximum size.\n     *\n     * @var Credentials|null\n     */\n    private $credentials;\n\n    /**\n     * The unique user identifier that is returned by the identity provider. This identifier is associated with the\n     * `WebIdentityToken` that was submitted with the `AssumeRoleWithWebIdentity` call. The identifier is typically unique\n     * to the user and the application that acquired the `WebIdentityToken` (pairwise identifier). For OpenID Connect ID\n     * tokens, this field contains the value returned by the identity provider as the token's `sub` (Subject) claim.\n     *\n     * @var string|null\n     */\n    private $subjectFromWebIdentityToken;\n\n    /**\n     * The Amazon Resource Name (ARN) and the assumed role ID, which are identifiers that you can use to refer to the\n     * resulting temporary security credentials. For example, you can reference these credentials as a principal in a\n     * resource-based policy by using the ARN or assumed role ID. The ARN and ID include the `RoleSessionName` that you\n     * specified when you called `AssumeRole`.\n     *\n     * @var AssumedRoleUser|null\n     */\n    private $assumedRoleUser;\n\n    /**\n     * A percentage value that indicates the packed size of the session policies and session tags combined passed in the\n     * request. The request fails if the packed size is greater than 100 percent, which means the policies and tags exceeded\n     * the allowed space.\n     *\n     * @var int|null\n     */\n    private $packedPolicySize;\n\n    /**\n     * The issuing authority of the web identity token presented. For OpenID Connect ID tokens, this contains the value of\n     * the `iss` field. For OAuth 2.0 access tokens, this contains the value of the `ProviderId` parameter that was passed\n     * in the `AssumeRoleWithWebIdentity` request.\n     *\n     * @var string|null\n     */\n    private $provider;\n\n    /**\n     * The intended audience (also known as client ID) of the web identity token. This is traditionally the client\n     * identifier issued to the application that requested the web identity token.\n     *\n     * @var string|null\n     */\n    private $audience;\n\n    /**\n     * The value of the source identity that is returned in the JSON web token (JWT) from the identity provider.\n     *\n     * You can require users to set a source identity value when they assume a role. You do this by using the\n     * `sts:SourceIdentity` condition key in a role trust policy. That way, actions that are taken with the role are\n     * associated with that user. After the source identity is set, the value cannot be changed. It is present in the\n     * request for all actions that are taken by the role and persists across chained role [^1] sessions. You can configure\n     * your identity provider to use an attribute associated with your users, like user name or email, as the source\n     * identity when calling `AssumeRoleWithWebIdentity`. You do this by adding a claim to the JSON web token. To learn more\n     * about OIDC tokens and claims, see Using Tokens with User Pools [^2] in the *Amazon Cognito Developer Guide*. For more\n     * information about using source identity, see Monitor and control actions taken with assumed roles [^3] in the *IAM\n     * User Guide*.\n     *\n     * The regex used to validate this parameter is a string of characters consisting of upper- and lower-case alphanumeric\n     * characters with no spaces. You can also include underscores or any of the following characters: =,.@-\n     *\n     * [^1]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles.html#id_roles_terms-and-concepts\n     * [^2]: https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-with-identity-providers.html\n     * [^3]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_monitor.html\n     *\n     * @var string|null\n     */\n    private $sourceIdentity;\n\n    public function getAssumedRoleUser(): ?AssumedRoleUser\n    {\n        $this->initialize();\n\n        return $this->assumedRoleUser;\n    }\n\n    public function getAudience(): ?string\n    {\n        $this->initialize();\n\n        return $this->audience;\n    }\n\n    public function getCredentials(): ?Credentials\n    {\n        $this->initialize();\n\n        return $this->credentials;\n    }\n\n    public function getPackedPolicySize(): ?int\n    {\n        $this->initialize();\n\n        return $this->packedPolicySize;\n    }\n\n    public function getProvider(): ?string\n    {\n        $this->initialize();\n\n        return $this->provider;\n    }\n\n    public function getSourceIdentity(): ?string\n    {\n        $this->initialize();\n\n        return $this->sourceIdentity;\n    }\n\n    public function getSubjectFromWebIdentityToken(): ?string\n    {\n        $this->initialize();\n\n        return $this->subjectFromWebIdentityToken;\n    }\n\n    protected function populateResult(Response $response): void\n    {\n        $data = new \\SimpleXMLElement($response->getContent());\n        $data = $data->AssumeRoleWithWebIdentityResult;\n\n        $this->credentials = 0 === $data->Credentials->count() ? null : $this->populateResultCredentials($data->Credentials);\n        $this->subjectFromWebIdentityToken = (null !== $v = $data->SubjectFromWebIdentityToken[0]) ? (string) $v : null;\n        $this->assumedRoleUser = 0 === $data->AssumedRoleUser->count() ? null : $this->populateResultAssumedRoleUser($data->AssumedRoleUser);\n        $this->packedPolicySize = (null !== $v = $data->PackedPolicySize[0]) ? (int) (string) $v : null;\n        $this->provider = (null !== $v = $data->Provider[0]) ? (string) $v : null;\n        $this->audience = (null !== $v = $data->Audience[0]) ? (string) $v : null;\n        $this->sourceIdentity = (null !== $v = $data->SourceIdentity[0]) ? (string) $v : null;\n    }\n\n    private function populateResultAssumedRoleUser(\\SimpleXMLElement $xml): AssumedRoleUser\n    {\n        return new AssumedRoleUser([\n            'AssumedRoleId' => (string) $xml->AssumedRoleId,\n            'Arn' => (string) $xml->Arn,\n        ]);\n    }\n\n    private function populateResultCredentials(\\SimpleXMLElement $xml): Credentials\n    {\n        return new Credentials([\n            'AccessKeyId' => (string) $xml->AccessKeyId,\n            'SecretAccessKey' => (string) $xml->SecretAccessKey,\n            'SessionToken' => (string) $xml->SessionToken,\n            'Expiration' => new \\DateTimeImmutable((string) $xml->Expiration),\n        ]);\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Sts/Result/GetCallerIdentityResponse.php",
    "content": "<?php\n\nnamespace AsyncAws\\Core\\Sts\\Result;\n\nuse AsyncAws\\Core\\Response;\nuse AsyncAws\\Core\\Result;\n\n/**\n * Contains the response to a successful GetCallerIdentity request, including information about the entity making the\n * request.\n */\nclass GetCallerIdentityResponse extends Result\n{\n    /**\n     * The unique identifier of the calling entity. The exact value depends on the type of entity that is making the call.\n     * The values returned are those listed in the **aws:userid** column in the Principal table [^1] found on the **Policy\n     * Variables** reference page in the *IAM User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_variables.html#principaltable\n     *\n     * @var string|null\n     */\n    private $userId;\n\n    /**\n     * The Amazon Web Services account ID number of the account that owns or contains the calling entity.\n     *\n     * @var string|null\n     */\n    private $account;\n\n    /**\n     * The Amazon Web Services ARN associated with the calling entity.\n     *\n     * @var string|null\n     */\n    private $arn;\n\n    public function getAccount(): ?string\n    {\n        $this->initialize();\n\n        return $this->account;\n    }\n\n    public function getArn(): ?string\n    {\n        $this->initialize();\n\n        return $this->arn;\n    }\n\n    public function getUserId(): ?string\n    {\n        $this->initialize();\n\n        return $this->userId;\n    }\n\n    protected function populateResult(Response $response): void\n    {\n        $data = new \\SimpleXMLElement($response->getContent());\n        $data = $data->GetCallerIdentityResult;\n\n        $this->userId = (null !== $v = $data->UserId[0]) ? (string) $v : null;\n        $this->account = (null !== $v = $data->Account[0]) ? (string) $v : null;\n        $this->arn = (null !== $v = $data->Arn[0]) ? (string) $v : null;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Sts/StsClient.php",
    "content": "<?php\n\nnamespace AsyncAws\\Core\\Sts;\n\nuse AsyncAws\\Core\\AbstractApi;\nuse AsyncAws\\Core\\AwsError\\AwsErrorFactoryInterface;\nuse AsyncAws\\Core\\AwsError\\XmlAwsErrorFactory;\nuse AsyncAws\\Core\\RequestContext;\nuse AsyncAws\\Core\\Sts\\Exception\\ExpiredTokenException;\nuse AsyncAws\\Core\\Sts\\Exception\\IDPCommunicationErrorException;\nuse AsyncAws\\Core\\Sts\\Exception\\IDPRejectedClaimException;\nuse AsyncAws\\Core\\Sts\\Exception\\InvalidIdentityTokenException;\nuse AsyncAws\\Core\\Sts\\Exception\\MalformedPolicyDocumentException;\nuse AsyncAws\\Core\\Sts\\Exception\\PackedPolicyTooLargeException;\nuse AsyncAws\\Core\\Sts\\Exception\\RegionDisabledException;\nuse AsyncAws\\Core\\Sts\\Input\\AssumeRoleRequest;\nuse AsyncAws\\Core\\Sts\\Input\\AssumeRoleWithWebIdentityRequest;\nuse AsyncAws\\Core\\Sts\\Input\\GetCallerIdentityRequest;\nuse AsyncAws\\Core\\Sts\\Result\\AssumeRoleResponse;\nuse AsyncAws\\Core\\Sts\\Result\\AssumeRoleWithWebIdentityResponse;\nuse AsyncAws\\Core\\Sts\\Result\\GetCallerIdentityResponse;\nuse AsyncAws\\Core\\Sts\\ValueObject\\PolicyDescriptorType;\nuse AsyncAws\\Core\\Sts\\ValueObject\\ProvidedContext;\nuse AsyncAws\\Core\\Sts\\ValueObject\\Tag;\n\nclass StsClient extends AbstractApi\n{\n    /**\n     * Returns a set of temporary security credentials that you can use to access Amazon Web Services resources. These\n     * temporary credentials consist of an access key ID, a secret access key, and a security token. Typically, you use\n     * `AssumeRole` within your account or for cross-account access. For a comparison of `AssumeRole` with other API\n     * operations that produce temporary credentials, see Requesting Temporary Security Credentials [^1] and Compare STS\n     * credentials [^2] in the *IAM User Guide*.\n     *\n     * **Permissions**\n     *\n     * The temporary security credentials created by `AssumeRole` can be used to make API calls to any Amazon Web Services\n     * service with the following exception: You cannot call the Amazon Web Services STS `GetFederationToken` or\n     * `GetSessionToken` API operations.\n     *\n     * (Optional) You can pass inline or managed session policies to this operation. You can pass a single JSON policy\n     * document to use as an inline session policy. You can also specify up to 10 managed policy Amazon Resource Names\n     * (ARNs) to use as managed session policies. The plaintext that you use for both inline and managed session policies\n     * can't exceed 2,048 characters. Passing policies to this operation returns new temporary credentials. The resulting\n     * session's permissions are the intersection of the role's identity-based policy and the session policies. You can use\n     * the role's temporary credentials in subsequent Amazon Web Services API calls to access resources in the account that\n     * owns the role. You cannot use session policies to grant more permissions than those allowed by the identity-based\n     * policy of the role that is being assumed. For more information, see Session Policies [^3] in the *IAM User Guide*.\n     *\n     * When you create a role, you create two policies: a role trust policy that specifies *who* can assume the role, and a\n     * permissions policy that specifies *what* can be done with the role. You specify the trusted principal that is allowed\n     * to assume the role in the role trust policy.\n     *\n     * To assume a role from a different account, your Amazon Web Services account must be trusted by the role. The trust\n     * relationship is defined in the role's trust policy when the role is created. That trust policy states which accounts\n     * are allowed to delegate that access to users in the account.\n     *\n     * A user who wants to access a role in a different account must also have permissions that are delegated from the\n     * account administrator. The administrator must attach a policy that allows the user to call `AssumeRole` for the ARN\n     * of the role in the other account.\n     *\n     * To allow a user to assume a role in the same account, you can do either of the following:\n     *\n     * - Attach a policy to the user that allows the user to call `AssumeRole` (as long as the role's trust policy trusts\n     *   the account).\n     * - Add the user as a principal directly in the role's trust policy.\n     *\n     * You can do either because the role’s trust policy acts as an IAM resource-based policy. When a resource-based\n     * policy grants access to a principal in the same account, no additional identity-based policy is required. For more\n     * information about trust policies and resource-based policies, see IAM Policies [^4] in the *IAM User Guide*.\n     *\n     * **Tags**\n     *\n     * (Optional) You can pass tag key-value pairs to your session. These tags are called session tags. For more information\n     * about session tags, see Passing Session Tags in STS [^5] in the *IAM User Guide*.\n     *\n     * An administrator must grant you the permissions necessary to pass session tags. The administrator can also create\n     * granular permissions to allow you to pass only specific session tags. For more information, see Tutorial: Using Tags\n     * for Attribute-Based Access Control [^6] in the *IAM User Guide*.\n     *\n     * You can set the session tags as transitive. Transitive tags persist during role chaining. For more information, see\n     * Chaining Roles with Session Tags [^7] in the *IAM User Guide*.\n     *\n     * **Using MFA with AssumeRole**\n     *\n     * (Optional) You can include multi-factor authentication (MFA) information when you call `AssumeRole`. This is useful\n     * for cross-account scenarios to ensure that the user that assumes the role has been authenticated with an Amazon Web\n     * Services MFA device. In that scenario, the trust policy of the role being assumed includes a condition that tests for\n     * MFA authentication. If the caller does not include valid MFA information, the request to assume the role is denied.\n     * The condition in a trust policy that tests for MFA authentication might look like the following example.\n     *\n     * `\"Condition\": {\"Bool\": {\"aws:MultiFactorAuthPresent\": true}}`\n     *\n     * For more information, see Configuring MFA-Protected API Access [^8] in the *IAM User Guide* guide.\n     *\n     * To use MFA with `AssumeRole`, you pass values for the `SerialNumber` and `TokenCode` parameters. The `SerialNumber`\n     * value identifies the user's hardware or virtual MFA device. The `TokenCode` is the time-based one-time password\n     * (TOTP) that the MFA device produces.\n     *\n     * [^1]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html\n     * [^2]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_sts-comparison.html\n     * [^3]: https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session\n     * [^4]: https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html\n     * [^5]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html\n     * [^6]: https://docs.aws.amazon.com/IAM/latest/UserGuide/tutorial_attribute-based-access-control.html\n     * [^7]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html#id_session-tags_role-chaining\n     * [^8]: https://docs.aws.amazon.com/IAM/latest/UserGuide/MFAProtectedAPI.html\n     *\n     * @see https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html\n     * @see https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-sts-2011-06-15.html#assumerole\n     *\n     * @param array{\n     *   RoleArn: string,\n     *   RoleSessionName: string,\n     *   PolicyArns?: null|array<PolicyDescriptorType|array>,\n     *   Policy?: null|string,\n     *   DurationSeconds?: null|int,\n     *   Tags?: null|array<Tag|array>,\n     *   TransitiveTagKeys?: null|string[],\n     *   ExternalId?: null|string,\n     *   SerialNumber?: null|string,\n     *   TokenCode?: null|string,\n     *   SourceIdentity?: null|string,\n     *   ProvidedContexts?: null|array<ProvidedContext|array>,\n     *   '@region'?: string|null,\n     * }|AssumeRoleRequest $input\n     *\n     * @throws ExpiredTokenException\n     * @throws MalformedPolicyDocumentException\n     * @throws PackedPolicyTooLargeException\n     * @throws RegionDisabledException\n     */\n    public function assumeRole($input): AssumeRoleResponse\n    {\n        $input = AssumeRoleRequest::create($input);\n        $response = $this->getResponse($input->request(), new RequestContext(['operation' => 'AssumeRole', 'region' => $input->getRegion(), 'exceptionMapping' => [\n            'ExpiredTokenException' => ExpiredTokenException::class,\n            'MalformedPolicyDocument' => MalformedPolicyDocumentException::class,\n            'PackedPolicyTooLarge' => PackedPolicyTooLargeException::class,\n            'RegionDisabledException' => RegionDisabledException::class,\n        ]]));\n\n        return new AssumeRoleResponse($response);\n    }\n\n    /**\n     * Returns a set of temporary security credentials for users who have been authenticated in a mobile or web application\n     * with a web identity provider. Example providers include the OAuth 2.0 providers Login with Amazon and Facebook, or\n     * any OpenID Connect-compatible identity provider such as Google or Amazon Cognito federated identities [^1].\n     *\n     * > For mobile applications, we recommend that you use Amazon Cognito. You can use Amazon Cognito with the Amazon Web\n     * > Services SDK for iOS Developer Guide [^2] and the Amazon Web Services SDK for Android Developer Guide [^3] to\n     * > uniquely identify a user. You can also supply the user with a consistent identity throughout the lifetime of an\n     * > application.\n     * >\n     * > To learn more about Amazon Cognito, see Amazon Cognito identity pools [^4] in *Amazon Cognito Developer Guide*.\n     *\n     * Calling `AssumeRoleWithWebIdentity` does not require the use of Amazon Web Services security credentials. Therefore,\n     * you can distribute an application (for example, on mobile devices) that requests temporary security credentials\n     * without including long-term Amazon Web Services credentials in the application. You also don't need to deploy\n     * server-based proxy services that use long-term Amazon Web Services credentials. Instead, the identity of the caller\n     * is validated by using a token from the web identity provider. For a comparison of `AssumeRoleWithWebIdentity` with\n     * the other API operations that produce temporary credentials, see Requesting Temporary Security Credentials [^5] and\n     * Compare STS credentials [^6] in the *IAM User Guide*.\n     *\n     * The temporary security credentials returned by this API consist of an access key ID, a secret access key, and a\n     * security token. Applications can use these temporary security credentials to sign calls to Amazon Web Services\n     * service API operations.\n     *\n     * **Session Duration**\n     *\n     * By default, the temporary security credentials created by `AssumeRoleWithWebIdentity` last for one hour. However, you\n     * can use the optional `DurationSeconds` parameter to specify the duration of your session. You can provide a value\n     * from 900 seconds (15 minutes) up to the maximum session duration setting for the role. This setting can have a value\n     * from 1 hour to 12 hours. To learn how to view the maximum value for your role, see Update the maximum session\n     * duration for a role [^7] in the *IAM User Guide*. The maximum session duration limit applies when you use the\n     * `AssumeRole*` API operations or the `assume-role*` CLI commands. However the limit does not apply when you use those\n     * operations to create a console URL. For more information, see Using IAM Roles [^8] in the *IAM User Guide*.\n     *\n     * **Permissions**\n     *\n     * The temporary security credentials created by `AssumeRoleWithWebIdentity` can be used to make API calls to any Amazon\n     * Web Services service with the following exception: you cannot call the STS `GetFederationToken` or `GetSessionToken`\n     * API operations.\n     *\n     * (Optional) You can pass inline or managed session policies [^9] to this operation. You can pass a single JSON policy\n     * document to use as an inline session policy. You can also specify up to 10 managed policy Amazon Resource Names\n     * (ARNs) to use as managed session policies. The plaintext that you use for both inline and managed session policies\n     * can't exceed 2,048 characters. Passing policies to this operation returns new temporary credentials. The resulting\n     * session's permissions are the intersection of the role's identity-based policy and the session policies. You can use\n     * the role's temporary credentials in subsequent Amazon Web Services API calls to access resources in the account that\n     * owns the role. You cannot use session policies to grant more permissions than those allowed by the identity-based\n     * policy of the role that is being assumed. For more information, see Session Policies [^10] in the *IAM User Guide*.\n     *\n     * **Tags**\n     *\n     * (Optional) You can configure your IdP to pass attributes into your web identity token as session tags. Each session\n     * tag consists of a key name and an associated value. For more information about session tags, see Passing Session Tags\n     * in STS [^11] in the *IAM User Guide*.\n     *\n     * You can pass up to 50 session tags. The plaintext session tag keys can’t exceed 128 characters and the values\n     * can’t exceed 256 characters. For these and additional limits, see IAM and STS Character Limits [^12] in the *IAM\n     * User Guide*.\n     *\n     * > An Amazon Web Services conversion compresses the passed inline session policy, managed policy ARNs, and session\n     * > tags into a packed binary format that has a separate limit. Your request can fail for this limit even if your\n     * > plaintext meets the other requirements. The `PackedPolicySize` response element indicates by percentage how close\n     * > the policies and tags for your request are to the upper size limit.\n     *\n     * You can pass a session tag with the same key as a tag that is attached to the role. When you do, the session tag\n     * overrides the role tag with the same key.\n     *\n     * An administrator must grant you the permissions necessary to pass session tags. The administrator can also create\n     * granular permissions to allow you to pass only specific session tags. For more information, see Tutorial: Using Tags\n     * for Attribute-Based Access Control [^13] in the *IAM User Guide*.\n     *\n     * You can set the session tags as transitive. Transitive tags persist during role chaining. For more information, see\n     * Chaining Roles with Session Tags [^14] in the *IAM User Guide*.\n     *\n     * **Identities**\n     *\n     * Before your application can call `AssumeRoleWithWebIdentity`, you must have an identity token from a supported\n     * identity provider and create a role that the application can assume. The role that your application assumes must\n     * trust the identity provider that is associated with the identity token. In other words, the identity provider must be\n     * specified in the role's trust policy.\n     *\n     * ! Calling `AssumeRoleWithWebIdentity` can result in an entry in your CloudTrail logs. The entry includes the Subject\n     * ! [^15] of the provided web identity token. We recommend that you avoid using any personally identifiable information\n     * ! (PII) in this field. For example, you could instead use a GUID or a pairwise identifier, as suggested in the OIDC\n     * ! specification [^16].\n     *\n     * For more information about how to use OIDC federation and the `AssumeRoleWithWebIdentity` API, see the following\n     * resources:\n     *\n     * - Using Web Identity Federation API Operations for Mobile Apps [^17] and Federation Through a Web-based Identity\n     *   Provider [^18].\n     * - Amazon Web Services SDK for iOS Developer Guide [^19] and Amazon Web Services SDK for Android Developer Guide\n     *   [^20]. These toolkits contain sample apps that show how to invoke the identity providers. The toolkits then show\n     *   how to use the information from these providers to get and use temporary security credentials.\n     *\n     * [^1]: https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-identity.html\n     * [^2]: http://aws.amazon.com/sdkforios/\n     * [^3]: http://aws.amazon.com/sdkforandroid/\n     * [^4]: https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-identity.html\n     * [^5]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html\n     * [^6]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_sts-comparison.html\n     * [^7]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_update-role-settings.html#id_roles_update-session-duration\n     * [^8]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html\n     * [^9]: https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session\n     * [^10]: https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session\n     * [^11]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html\n     * [^12]: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-limits.html#reference_iam-limits-entity-length\n     * [^13]: https://docs.aws.amazon.com/IAM/latest/UserGuide/tutorial_attribute-based-access-control.html\n     * [^14]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html#id_session-tags_role-chaining\n     * [^15]: http://openid.net/specs/openid-connect-core-1_0.html#Claims\n     * [^16]: http://openid.net/specs/openid-connect-core-1_0.html#SubjectIDTypes\n     * [^17]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_oidc_manual.html\n     * [^18]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#api_assumerolewithwebidentity\n     * [^19]: http://aws.amazon.com/sdkforios/\n     * [^20]: http://aws.amazon.com/sdkforandroid/\n     *\n     * @see https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRoleWithWebIdentity.html\n     * @see https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-sts-2011-06-15.html#assumerolewithwebidentity\n     *\n     * @param array{\n     *   RoleArn: string,\n     *   RoleSessionName: string,\n     *   WebIdentityToken: string,\n     *   ProviderId?: null|string,\n     *   PolicyArns?: null|array<PolicyDescriptorType|array>,\n     *   Policy?: null|string,\n     *   DurationSeconds?: null|int,\n     *   '@region'?: string|null,\n     * }|AssumeRoleWithWebIdentityRequest $input\n     *\n     * @throws ExpiredTokenException\n     * @throws IDPCommunicationErrorException\n     * @throws IDPRejectedClaimException\n     * @throws InvalidIdentityTokenException\n     * @throws MalformedPolicyDocumentException\n     * @throws PackedPolicyTooLargeException\n     * @throws RegionDisabledException\n     */\n    public function assumeRoleWithWebIdentity($input): AssumeRoleWithWebIdentityResponse\n    {\n        $input = AssumeRoleWithWebIdentityRequest::create($input);\n        $response = $this->getResponse($input->request(), new RequestContext(['operation' => 'AssumeRoleWithWebIdentity', 'region' => $input->getRegion(), 'exceptionMapping' => [\n            'ExpiredTokenException' => ExpiredTokenException::class,\n            'IDPCommunicationError' => IDPCommunicationErrorException::class,\n            'IDPRejectedClaim' => IDPRejectedClaimException::class,\n            'InvalidIdentityToken' => InvalidIdentityTokenException::class,\n            'MalformedPolicyDocument' => MalformedPolicyDocumentException::class,\n            'PackedPolicyTooLarge' => PackedPolicyTooLargeException::class,\n            'RegionDisabledException' => RegionDisabledException::class,\n        ]]));\n\n        return new AssumeRoleWithWebIdentityResponse($response);\n    }\n\n    /**\n     * Returns details about the IAM user or role whose credentials are used to call the operation.\n     *\n     * > No permissions are required to perform this operation. If an administrator attaches a policy to your identity that\n     * > explicitly denies access to the `sts:GetCallerIdentity` action, you can still perform this operation. Permissions\n     * > are not required because the same information is returned when access is denied. To view an example response, see I\n     * > Am Not Authorized to Perform: iam:DeleteVirtualMFADevice [^1] in the *IAM User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/IAM/latest/UserGuide/troubleshoot_general.html#troubleshoot_general_access-denied-delete-mfa\n     *\n     * @see https://docs.aws.amazon.com/STS/latest/APIReference/API_GetCallerIdentity.html\n     * @see https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-sts-2011-06-15.html#getcalleridentity\n     *\n     * @param array{\n     *   '@region'?: string|null,\n     * }|GetCallerIdentityRequest $input\n     */\n    public function getCallerIdentity($input = []): GetCallerIdentityResponse\n    {\n        $input = GetCallerIdentityRequest::create($input);\n        $response = $this->getResponse($input->request(), new RequestContext(['operation' => 'GetCallerIdentity', 'region' => $input->getRegion()]));\n\n        return new GetCallerIdentityResponse($response);\n    }\n\n    protected function getAwsErrorFactory(): AwsErrorFactoryInterface\n    {\n        return new XmlAwsErrorFactory();\n    }\n\n    protected function getEndpointMetadata(?string $region): array\n    {\n        if (null === $region) {\n            return [\n                'endpoint' => 'https://sts.amazonaws.com',\n                'signRegion' => 'us-east-1',\n                'signService' => 'sts',\n                'signVersions' => ['v4'],\n            ];\n        }\n\n        switch ($region) {\n            case 'cn-north-1':\n            case 'cn-northwest-1':\n                return [\n                    'endpoint' => \"https://sts.$region.amazonaws.com.cn\",\n                    'signRegion' => $region,\n                    'signService' => 'sts',\n                    'signVersions' => ['v4'],\n                ];\n            case 'us-east-1-fips':\n                return [\n                    'endpoint' => 'https://sts-fips.us-east-1.amazonaws.com',\n                    'signRegion' => 'us-east-1',\n                    'signService' => 'sts',\n                    'signVersions' => ['v4'],\n                ];\n            case 'us-east-2-fips':\n                return [\n                    'endpoint' => 'https://sts-fips.us-east-2.amazonaws.com',\n                    'signRegion' => 'us-east-2',\n                    'signService' => 'sts',\n                    'signVersions' => ['v4'],\n                ];\n            case 'us-west-1-fips':\n                return [\n                    'endpoint' => 'https://sts-fips.us-west-1.amazonaws.com',\n                    'signRegion' => 'us-west-1',\n                    'signService' => 'sts',\n                    'signVersions' => ['v4'],\n                ];\n            case 'us-west-2-fips':\n                return [\n                    'endpoint' => 'https://sts-fips.us-west-2.amazonaws.com',\n                    'signRegion' => 'us-west-2',\n                    'signService' => 'sts',\n                    'signVersions' => ['v4'],\n                ];\n            case 'us-gov-east-1-fips':\n                return [\n                    'endpoint' => 'https://sts.us-gov-east-1.amazonaws.com',\n                    'signRegion' => 'us-gov-east-1',\n                    'signService' => 'sts',\n                    'signVersions' => ['v4'],\n                ];\n            case 'us-gov-west-1-fips':\n                return [\n                    'endpoint' => 'https://sts.us-gov-west-1.amazonaws.com',\n                    'signRegion' => 'us-gov-west-1',\n                    'signService' => 'sts',\n                    'signVersions' => ['v4'],\n                ];\n            case 'us-iso-east-1':\n            case 'us-iso-west-1':\n                return [\n                    'endpoint' => \"https://sts.$region.c2s.ic.gov\",\n                    'signRegion' => $region,\n                    'signService' => 'sts',\n                    'signVersions' => ['v4'],\n                ];\n            case 'us-isof-east-1':\n            case 'us-isof-south-1':\n                return [\n                    'endpoint' => \"https://sts.$region.csp.hci.ic.gov\",\n                    'signRegion' => $region,\n                    'signService' => 'sts',\n                    'signVersions' => ['v4'],\n                ];\n            case 'eu-isoe-west-1':\n                return [\n                    'endpoint' => 'https://sts.eu-isoe-west-1.cloud.adc-e.uk',\n                    'signRegion' => 'eu-isoe-west-1',\n                    'signService' => 'sts',\n                    'signVersions' => ['v4'],\n                ];\n            case 'us-isob-east-1':\n                return [\n                    'endpoint' => 'https://sts.us-isob-east-1.sc2s.sgov.gov',\n                    'signRegion' => 'us-isob-east-1',\n                    'signService' => 'sts',\n                    'signVersions' => ['v4'],\n                ];\n        }\n\n        return [\n            'endpoint' => \"https://sts.$region.amazonaws.com\",\n            'signRegion' => $region,\n            'signService' => 'sts',\n            'signVersions' => ['v4'],\n        ];\n    }\n\n    protected function getServiceCode(): string\n    {\n        @trigger_error('Using the client with an old version of Core is deprecated. Run \"composer update async-aws/core\".', \\E_USER_DEPRECATED);\n\n        return 'sts';\n    }\n\n    protected function getSignatureScopeName(): string\n    {\n        @trigger_error('Using the client with an old version of Core is deprecated. Run \"composer update async-aws/core\".', \\E_USER_DEPRECATED);\n\n        return 'sts';\n    }\n\n    protected function getSignatureVersion(): string\n    {\n        @trigger_error('Using the client with an old version of Core is deprecated. Run \"composer update async-aws/core\".', \\E_USER_DEPRECATED);\n\n        return 'v4';\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Sts/ValueObject/AssumedRoleUser.php",
    "content": "<?php\n\nnamespace AsyncAws\\Core\\Sts\\ValueObject;\n\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\n\n/**\n * The identifiers for the temporary security credentials that the operation returns.\n */\nfinal class AssumedRoleUser\n{\n    /**\n     * A unique identifier that contains the role ID and the role session name of the role that is being assumed. The role\n     * ID is generated by Amazon Web Services when the role is created.\n     *\n     * @var string\n     */\n    private $assumedRoleId;\n\n    /**\n     * The ARN of the temporary security credentials that are returned from the AssumeRole action. For more information\n     * about ARNs and how to use them in policies, see IAM Identifiers [^1] in the *IAM User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html\n     *\n     * @var string\n     */\n    private $arn;\n\n    /**\n     * @param array{\n     *   AssumedRoleId: string,\n     *   Arn: string,\n     * } $input\n     */\n    public function __construct(array $input)\n    {\n        $this->assumedRoleId = $input['AssumedRoleId'] ?? $this->throwException(new InvalidArgument('Missing required field \"AssumedRoleId\".'));\n        $this->arn = $input['Arn'] ?? $this->throwException(new InvalidArgument('Missing required field \"Arn\".'));\n    }\n\n    /**\n     * @param array{\n     *   AssumedRoleId: string,\n     *   Arn: string,\n     * }|AssumedRoleUser $input\n     */\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    public function getArn(): string\n    {\n        return $this->arn;\n    }\n\n    public function getAssumedRoleId(): string\n    {\n        return $this->assumedRoleId;\n    }\n\n    /**\n     * @return never\n     */\n    private function throwException(\\Throwable $exception)\n    {\n        throw $exception;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Sts/ValueObject/Credentials.php",
    "content": "<?php\n\nnamespace AsyncAws\\Core\\Sts\\ValueObject;\n\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\n\n/**\n * Amazon Web Services credentials for API authentication.\n */\nfinal class Credentials\n{\n    /**\n     * The access key ID that identifies the temporary security credentials.\n     *\n     * @var string\n     */\n    private $accessKeyId;\n\n    /**\n     * The secret access key that can be used to sign requests.\n     *\n     * @var string\n     */\n    private $secretAccessKey;\n\n    /**\n     * The token that users must pass to the service API to use the temporary credentials.\n     *\n     * @var string\n     */\n    private $sessionToken;\n\n    /**\n     * The date on which the current credentials expire.\n     *\n     * @var \\DateTimeImmutable\n     */\n    private $expiration;\n\n    /**\n     * @param array{\n     *   AccessKeyId: string,\n     *   SecretAccessKey: string,\n     *   SessionToken: string,\n     *   Expiration: \\DateTimeImmutable,\n     * } $input\n     */\n    public function __construct(array $input)\n    {\n        $this->accessKeyId = $input['AccessKeyId'] ?? $this->throwException(new InvalidArgument('Missing required field \"AccessKeyId\".'));\n        $this->secretAccessKey = $input['SecretAccessKey'] ?? $this->throwException(new InvalidArgument('Missing required field \"SecretAccessKey\".'));\n        $this->sessionToken = $input['SessionToken'] ?? $this->throwException(new InvalidArgument('Missing required field \"SessionToken\".'));\n        $this->expiration = $input['Expiration'] ?? $this->throwException(new InvalidArgument('Missing required field \"Expiration\".'));\n    }\n\n    /**\n     * @param array{\n     *   AccessKeyId: string,\n     *   SecretAccessKey: string,\n     *   SessionToken: string,\n     *   Expiration: \\DateTimeImmutable,\n     * }|Credentials $input\n     */\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    public function getAccessKeyId(): string\n    {\n        return $this->accessKeyId;\n    }\n\n    public function getExpiration(): \\DateTimeImmutable\n    {\n        return $this->expiration;\n    }\n\n    public function getSecretAccessKey(): string\n    {\n        return $this->secretAccessKey;\n    }\n\n    public function getSessionToken(): string\n    {\n        return $this->sessionToken;\n    }\n\n    /**\n     * @return never\n     */\n    private function throwException(\\Throwable $exception)\n    {\n        throw $exception;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Sts/ValueObject/PolicyDescriptorType.php",
    "content": "<?php\n\nnamespace AsyncAws\\Core\\Sts\\ValueObject;\n\n/**\n * A reference to the IAM managed policy that is passed as a session policy for a role session or a federated user\n * session.\n */\nfinal class PolicyDescriptorType\n{\n    /**\n     * The Amazon Resource Name (ARN) of the IAM managed policy to use as a session policy for the role. For more\n     * information about ARNs, see Amazon Resource Names (ARNs) and Amazon Web Services Service Namespaces [^1] in the\n     * *Amazon Web Services General Reference*.\n     *\n     * [^1]: https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html\n     *\n     * @var string|null\n     */\n    private $arn;\n\n    /**\n     * @param array{\n     *   arn?: null|string,\n     * } $input\n     */\n    public function __construct(array $input)\n    {\n        $this->arn = $input['arn'] ?? null;\n    }\n\n    /**\n     * @param array{\n     *   arn?: null|string,\n     * }|PolicyDescriptorType $input\n     */\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    public function getArn(): ?string\n    {\n        return $this->arn;\n    }\n\n    /**\n     * @internal\n     */\n    public function requestBody(): array\n    {\n        $payload = [];\n        if (null !== $v = $this->arn) {\n            $payload['arn'] = $v;\n        }\n\n        return $payload;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Sts/ValueObject/ProvidedContext.php",
    "content": "<?php\n\nnamespace AsyncAws\\Core\\Sts\\ValueObject;\n\n/**\n * Contains information about the provided context. This includes the signed and encrypted trusted context assertion and\n * the context provider ARN from which the trusted context assertion was generated.\n */\nfinal class ProvidedContext\n{\n    /**\n     * The context provider ARN from which the trusted context assertion was generated.\n     *\n     * @var string|null\n     */\n    private $providerArn;\n\n    /**\n     * The signed and encrypted trusted context assertion generated by the context provider. The trusted context assertion\n     * is signed and encrypted by Amazon Web Services STS.\n     *\n     * @var string|null\n     */\n    private $contextAssertion;\n\n    /**\n     * @param array{\n     *   ProviderArn?: null|string,\n     *   ContextAssertion?: null|string,\n     * } $input\n     */\n    public function __construct(array $input)\n    {\n        $this->providerArn = $input['ProviderArn'] ?? null;\n        $this->contextAssertion = $input['ContextAssertion'] ?? null;\n    }\n\n    /**\n     * @param array{\n     *   ProviderArn?: null|string,\n     *   ContextAssertion?: null|string,\n     * }|ProvidedContext $input\n     */\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    public function getContextAssertion(): ?string\n    {\n        return $this->contextAssertion;\n    }\n\n    public function getProviderArn(): ?string\n    {\n        return $this->providerArn;\n    }\n\n    /**\n     * @internal\n     */\n    public function requestBody(): array\n    {\n        $payload = [];\n        if (null !== $v = $this->providerArn) {\n            $payload['ProviderArn'] = $v;\n        }\n        if (null !== $v = $this->contextAssertion) {\n            $payload['ContextAssertion'] = $v;\n        }\n\n        return $payload;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Sts/ValueObject/Tag.php",
    "content": "<?php\n\nnamespace AsyncAws\\Core\\Sts\\ValueObject;\n\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\n\n/**\n * You can pass custom key-value pair attributes when you assume a role or federate a user. These are called session\n * tags. You can then use the session tags to control access to resources. For more information, see Tagging Amazon Web\n * Services STS Sessions [^1] in the *IAM User Guide*.\n *\n * [^1]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html\n */\nfinal class Tag\n{\n    /**\n     * The key for a session tag.\n     *\n     * You can pass up to 50 session tags. The plain text session tag keys can’t exceed 128 characters. For these and\n     * additional limits, see IAM and STS Character Limits [^1] in the *IAM User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-limits.html#reference_iam-limits-entity-length\n     *\n     * @var string\n     */\n    private $key;\n\n    /**\n     * The value for a session tag.\n     *\n     * You can pass up to 50 session tags. The plain text session tag values can’t exceed 256 characters. For these and\n     * additional limits, see IAM and STS Character Limits [^1] in the *IAM User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-limits.html#reference_iam-limits-entity-length\n     *\n     * @var string\n     */\n    private $value;\n\n    /**\n     * @param array{\n     *   Key: string,\n     *   Value: string,\n     * } $input\n     */\n    public function __construct(array $input)\n    {\n        $this->key = $input['Key'] ?? $this->throwException(new InvalidArgument('Missing required field \"Key\".'));\n        $this->value = $input['Value'] ?? $this->throwException(new InvalidArgument('Missing required field \"Value\".'));\n    }\n\n    /**\n     * @param array{\n     *   Key: string,\n     *   Value: string,\n     * }|Tag $input\n     */\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    public function getKey(): string\n    {\n        return $this->key;\n    }\n\n    public function getValue(): string\n    {\n        return $this->value;\n    }\n\n    /**\n     * @internal\n     */\n    public function requestBody(): array\n    {\n        $payload = [];\n        $v = $this->key;\n        $payload['Key'] = $v;\n        $v = $this->value;\n        $payload['Value'] = $v;\n\n        return $payload;\n    }\n\n    /**\n     * @return never\n     */\n    private function throwException(\\Throwable $exception)\n    {\n        throw $exception;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Test/Http/SimpleMockedResponse.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace AsyncAws\\Core\\Test\\Http;\n\nuse AsyncAws\\Core\\Exception\\LogicException;\nuse Symfony\\Component\\HttpClient\\Response\\MockResponse;\n\n/**\n * @final\n */\nclass SimpleMockedResponse extends MockResponse\n{\n    /**\n     * @var array<string, list<string>>\n     */\n    private $headers = [];\n\n    /**\n     * @var string\n     */\n    private $content = '';\n\n    /**\n     * @var int\n     */\n    private $statusCode;\n\n    /**\n     * @param array<string, string|list<string>> $headers ['name'=>'value'] OR ['name'=>['value']]\n     */\n    public function __construct(string $content = '', array $headers = [], int $statusCode = 200)\n    {\n        $this->content = $content;\n        $this->statusCode = $statusCode;\n        $this->headers = [];\n        foreach ($headers as $name => $value) {\n            if (!\\is_array($value)) {\n                $value = [$value];\n            }\n            $this->headers[$name] = $value;\n        }\n\n        parent::__construct($content, [\n            'response_headers' => $this->getFlatHeaders(),\n            'http_code' => $statusCode,\n        ]);\n    }\n\n    public function getStatusCode(): int\n    {\n        return $this->statusCode;\n    }\n\n    public function getHeaders(bool $throw = true): array\n    {\n        return $this->headers;\n    }\n\n    public function getContent(bool $throw = true): string\n    {\n        return $this->content;\n    }\n\n    /**\n     * @return array<string, mixed>\n     */\n    public function toArray(bool $throw = true): array\n    {\n        return json_decode($this->getContent($throw), true);\n    }\n\n    public function cancel(): void\n    {\n        throw new LogicException('Not implemented');\n    }\n\n    /**\n     * @return list<string>\n     */\n    private function getFlatHeaders()\n    {\n        $flat = [];\n        foreach ($this->headers as $name => $value) {\n            $flat[] = \\sprintf('%s: %s', $name, implode(';', $value));\n        }\n\n        return $flat;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Test/ResultMockFactory.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace AsyncAws\\Core\\Test;\n\nuse AsyncAws\\Core\\Exception\\LogicException;\nuse AsyncAws\\Core\\Response;\nuse AsyncAws\\Core\\Result;\nuse AsyncAws\\Core\\Test\\Http\\SimpleMockedResponse;\nuse AsyncAws\\Core\\Waiter;\nuse Psr\\Log\\NullLogger;\nuse Symfony\\Component\\HttpClient\\MockHttpClient;\n\n/**\n * An easy way to create Result objects for your tests.\n *\n * @author Tobias Nyholm <tobias.nyholm@gmail.com>\n */\nclass ResultMockFactory\n{\n    /**\n     * Instantiate a Result class that throws exception.\n     *\n     * <code>\n     * ResultMockFactory::createFailing(SendEmailResponse::class, 400, 'invalid value');\n     * </code>\n     *\n     * @template T of Result\n     *\n     * @param class-string<T>      $class\n     * @param array<string, mixed> $additionalContent\n     *\n     * @return T\n     */\n    public static function createFailing(\n        string $class,\n        int $code,\n        ?string $message = null,\n        array $additionalContent = []\n    ) {\n        if (Result::class !== $class) {\n            $parent = get_parent_class($class);\n            if (false === $parent || Result::class !== $parent) {\n                throw new LogicException(\\sprintf('The \"%s::%s\" can only be used for classes that extend \"%s\"', __CLASS__, __METHOD__, Result::class));\n            }\n        }\n\n        $httpResponse = new SimpleMockedResponse(json_encode(array_merge(['message' => $message], $additionalContent)), ['content-type' => 'application/json'], $code);\n        $client = new MockHttpClient($httpResponse);\n        $response = new Response($client->request('POST', 'http://localhost'), $client, new NullLogger());\n\n        /** @psalm-var \\ReflectionClass<T> $reflectionClass */\n        $reflectionClass = new \\ReflectionClass($class);\n\n        return $reflectionClass->newInstance($response);\n    }\n\n    /**\n     * Instantiate a Result class with some data.\n     *\n     * <code>\n     * ResultMockFactory::create(SendEmailResponse::class, ['MessageId'=>'foo123']);\n     * </code>\n     *\n     * @template T of Result\n     *\n     * @param class-string<T>      $class\n     * @param array<string, mixed> $data\n     *\n     * @return T\n     */\n    public static function create(string $class, array $data = [])\n    {\n        if (Result::class !== $class) {\n            $parent = get_parent_class($class);\n            if (false === $parent || Result::class !== $parent) {\n                throw new LogicException(\\sprintf('The \"%s::%s\" can only be used for classes that extend \"%s\"', __CLASS__, __METHOD__, Result::class));\n            }\n        }\n\n        $response = self::getResponseObject();\n\n        // Make sure the Result is initialized\n        $reflectionClass = new \\ReflectionClass(Result::class);\n        $initializedProperty = $reflectionClass->getProperty('initialized');\n        if (\\PHP_VERSION_ID < 80100) {\n            $initializedProperty->setAccessible(true);\n        }\n\n        /** @psalm-var \\ReflectionClass<T> $reflectionClass */\n        $reflectionClass = new \\ReflectionClass($class);\n        $object = $reflectionClass->newInstance($response);\n        if (Result::class !== $class) {\n            self::addPropertiesOnResult($reflectionClass, $object, $class);\n        }\n\n        $initializedProperty->setValue($object, true);\n        foreach ($data as $propertyName => $propertyValue) {\n            if ($reflectionClass->hasProperty($propertyName)) {\n                $property = $reflectionClass->getProperty($propertyName);\n            } elseif ($reflectionClass->hasProperty(lcfirst($propertyName))) {\n                // backward compatibility with `UpperCamelCase` naming (fast)\n                $property = $reflectionClass->getProperty(lcfirst($propertyName));\n            } else {\n                // compatibility with new `wordWithABREV` naming (slow)\n                $lowerPropertyName = strtolower($propertyName);\n                $property = null;\n                foreach ($reflectionClass->getProperties() as $prop) {\n                    if (strtolower($prop->getName()) === $lowerPropertyName) {\n                        $property = $prop;\n\n                        break;\n                    }\n                }\n                if (null === $property) {\n                    // let bubble the original exception\n                    $property = $reflectionClass->getProperty($propertyName);\n                }\n            }\n            if (\\PHP_VERSION_ID < 80100) {\n                $property->setAccessible(true);\n            }\n            $property->setValue($object, $propertyValue);\n        }\n\n        self::addUndefinedProperties($reflectionClass, $object, $data);\n\n        return $object;\n    }\n\n    /**\n     * Instantiate a Waiter class with a final state.\n     *\n     * @template T of Waiter\n     *\n     * @psalm-param class-string<T> $class\n     *\n     * @return T\n     */\n    public static function waiter(string $class, string $finalState)\n    {\n        if (Waiter::class !== $class) {\n            $parent = get_parent_class($class);\n            if (false === $parent || Waiter::class !== $parent) {\n                throw new LogicException(\\sprintf('The \"%s::%s\" can only be used for classes that extend \"%s\"', __CLASS__, __METHOD__, Waiter::class));\n            }\n        }\n\n        if (Waiter::STATE_SUCCESS !== $finalState && Waiter::STATE_FAILURE !== $finalState) {\n            throw new LogicException(\\sprintf('The state passed to \"%s::%s\" must be \"%s\" or \"%s\".', __CLASS__, __METHOD__, Waiter::STATE_SUCCESS, Waiter::STATE_FAILURE));\n        }\n\n        $response = self::getResponseObject();\n\n        $reflectionClass = new \\ReflectionClass(Waiter::class);\n        $propertyResponse = $reflectionClass->getProperty('response');\n        if (\\PHP_VERSION_ID < 80100) {\n            $propertyResponse->setAccessible(true);\n        }\n\n        $propertyState = $reflectionClass->getProperty('finalState');\n        if (\\PHP_VERSION_ID < 80100) {\n            $propertyState->setAccessible(true);\n        }\n\n        /** @psalm-var \\ReflectionClass<T> $reflectionClass */\n        $reflectionClass = new \\ReflectionClass($class);\n        $result = $reflectionClass->newInstanceWithoutConstructor();\n        $propertyResponse->setValue($result, $response);\n        $propertyState->setValue($result, $finalState);\n\n        return $result;\n    }\n\n    /**\n     * Try to add some values to the properties not defined in $data.\n     *\n     * @param \\ReflectionClass<object> $reflectionClass\n     * @param array<string, mixed>     $data\n     *\n     * @throws \\ReflectionException\n     */\n    private static function addUndefinedProperties(\\ReflectionClass $reflectionClass, object $object, array $data): void\n    {\n        foreach ($reflectionClass->getProperties(\\ReflectionProperty::IS_PRIVATE) as $property) {\n            if (\\array_key_exists($property->getName(), $data) || \\array_key_exists(ucfirst($property->getName()), $data)) {\n                continue;\n            }\n\n            if (!$reflectionClass->hasMethod('get' . $property->getName())) {\n                continue;\n            }\n\n            $getter = $reflectionClass->getMethod('get' . $property->getName());\n            if (!$getter->hasReturnType() || (!($type = $getter->getReturnType()) instanceof \\ReflectionNamedType) || $type->allowsNull()) {\n                continue;\n            }\n\n            switch ($type->getName()) {\n                case 'int':\n                    $propertyValue = 0;\n\n                    break;\n                case 'string':\n                    $propertyValue = '';\n\n                    break;\n                case 'bool':\n                    $propertyValue = false;\n\n                    break;\n                case 'float':\n                    $propertyValue = 0.0;\n\n                    break;\n                case 'array':\n                    $propertyValue = [];\n\n                    break;\n                default:\n                    $propertyValue = null;\n\n                    break;\n            }\n\n            if (null !== $propertyValue) {\n                if (\\PHP_VERSION_ID < 80100) {\n                    $property->setAccessible(true);\n                }\n                $property->setValue($object, $propertyValue);\n            }\n        }\n    }\n\n    /**\n     * Set input and aws client to handle pagination.\n     *\n     * @param \\ReflectionClass<object> $reflectionClass\n     */\n    private static function addPropertiesOnResult(\\ReflectionClass $reflectionClass, object $object, string $class): void\n    {\n        if (false === $pos = strrpos($class, '\\\\')) {\n            throw new LogicException(\\sprintf('Expected class \"%s\" to have a backslash. ', $class));\n        }\n\n        $className = substr($class, $pos + 1);\n        if ('Output' === substr($className, -6)) {\n            $classNameWithoutSuffix = substr($className, 0, -6);\n        } elseif ('Response' === substr($className, -8)) {\n            $classNameWithoutSuffix = substr($className, 0, -8);\n        } elseif ('Result' === substr($className, -6)) {\n            $classNameWithoutSuffix = substr($className, 0, -6);\n        } else {\n            throw new LogicException(\\sprintf('Unknown class suffix: \"%s\"', $className));\n        }\n\n        if (false === $pos = strrpos($class, '\\\\', -2 - \\strlen($className))) {\n            throw new LogicException(\\sprintf('Expected class \"%s\" to have more than one backslash. ', $class));\n        }\n\n        $baseNamespace = substr($class, 0, $pos);\n        if (false === $pos = strrpos($baseNamespace, '\\\\')) {\n            throw new LogicException(\\sprintf('Expected base namespace \"%s\" to have a backslash. ', $baseNamespace));\n        }\n\n        $awsClientClass = $baseNamespace . substr($baseNamespace, $pos) . 'Client';\n        $inputClass = $baseNamespace . '\\\\Input\\\\' . $classNameWithoutSuffix . 'Request';\n\n        if (class_exists($awsClientClass)) {\n            $awsClientMock = (new \\ReflectionClass($awsClientClass))->newInstanceWithoutConstructor();\n            $property = $reflectionClass->getProperty('awsClient');\n            if (\\PHP_VERSION_ID < 80100) {\n                $property->setAccessible(true);\n            }\n            $property->setValue($object, $awsClientMock);\n        }\n\n        if (class_exists($inputClass)) {\n            $inputMock = (new \\ReflectionClass($inputClass))->newInstanceWithoutConstructor();\n            $property = $reflectionClass->getProperty('input');\n            if (\\PHP_VERSION_ID < 80100) {\n                $property->setAccessible(true);\n            }\n            $property->setValue($object, $inputMock);\n        }\n    }\n\n    private static function getResponseObject(): Response\n    {\n        $reflectionClass = new \\ReflectionClass(Response::class);\n        $response = $reflectionClass->newInstanceWithoutConstructor();\n\n        $property = $reflectionClass->getProperty('resolveResult');\n        if (\\PHP_VERSION_ID < 80100) {\n            $property->setAccessible(true);\n        }\n        $property->setValue($response, true);\n\n        $property = $reflectionClass->getProperty('bodyDownloaded');\n        if (\\PHP_VERSION_ID < 80100) {\n            $property->setAccessible(true);\n        }\n        $property->setValue($response, true);\n\n        $property = $reflectionClass->getProperty('httpResponse');\n        if (\\PHP_VERSION_ID < 80100) {\n            $property->setAccessible(true);\n        }\n        $property->setValue($response, new SimpleMockedResponse());\n\n        return $response;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Test/SimpleResultStream.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace AsyncAws\\Core\\Test;\n\nuse AsyncAws\\Core\\Stream\\ResultStream;\n\n/**\n * Simple streamable body used for testing.\n *\n * @author Tobias Nyholm <tobias.nyholm@gmail.com>\n */\nclass SimpleResultStream implements ResultStream\n{\n    /**\n     * @var string\n     */\n    private $data;\n\n    public function __construct(string $data)\n    {\n        $this->data = $data;\n    }\n\n    public function getChunks(): iterable\n    {\n        yield $this->data;\n    }\n\n    public function getContentAsString(): string\n    {\n        return $this->data;\n    }\n\n    public function getContentAsResource()\n    {\n        $resource = fopen('php://temp', 'rw+');\n\n        try {\n            fwrite($resource, $this->data);\n\n            // Rewind\n            fseek($resource, 0, \\SEEK_SET);\n\n            return $resource;\n        } catch (\\Throwable $e) {\n            fclose($resource);\n\n            throw $e;\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Test/TestCase.php",
    "content": "<?php\n\nnamespace AsyncAws\\Core\\Test;\n\nuse AsyncAws\\Core\\Request;\nuse PHPUnit\\Framework\\TestCase as PHPUnitTestCase;\n\nclass TestCase extends PHPUnitTestCase\n{\n    /**\n     * Asserts that two Body documents are equal.\n     */\n    public static function assertHttpFormEqualsHttpForm(string $expected, string $actual, string $message = ''): void\n    {\n        $expectedArray = preg_split('/[\\n&\\s]+/', trim($expected));\n        $actualArray = preg_split('/[\\n&\\s]+/', trim($actual));\n\n        self::assertEqualsCanonicalizing($expectedArray, $actualArray, $message);\n    }\n\n    /**\n     * Asserts that two Body documents are equal.\n     */\n    public static function assertUrlEqualsUrl(string $expected, string $actual, string $message = ''): void\n    {\n        $actualUrl = parse_url($actual);\n        $expectedUrl = parse_url($expected);\n        self::assertSame($expectedUrl['path'] ?? '/', $actualUrl['path'] ?? '/');\n\n        $expectedQuery = [];\n        foreach (array_filter(explode('&', $expectedUrl['query'] ?? '')) as $item) {\n            $item = explode('=', $item);\n            $expectedQuery[$item[0]] = urldecode($item[1] ?? '');\n        }\n\n        $actualQuery = [];\n        foreach (array_filter(explode('&', $actualUrl['query'] ?? '')) as $item) {\n            $item = explode('=', $item);\n            $actualQuery[$item[0]] = urldecode($item[1] ?? '');\n        }\n        self::assertEqualsIgnoringCase($expectedQuery, $actualQuery);\n    }\n\n    /**\n     * Asserts that two Body documents are equal.\n     */\n    public static function assertRequestEqualsHttpRequest(string $expected, Request $actual, string $message = ''): void\n    {\n        $expected = explode(\"\\n\\n\", trim($expected));\n        $headers = $expected[0];\n        $body = $expected[1] ?? '';\n        $headers = explode(\"\\n\", $headers);\n        array_map('trim', $headers);\n        [$method, $url] = explode(' ', array_shift($headers));\n\n        self::assertSame($method, $actual->getMethod());\n\n        $actualUrl = $actual->getUri();\n        if ($actual->getQuery()) {\n            $actualUrl .= false !== strpos($actual->getUri(), '?') ? '&' : '?';\n            $actualUrl .= http_build_query($actual->getQuery(), '', '&', \\PHP_QUERY_RFC3986);\n        }\n        self::assertUrlEqualsUrl($url, $actualUrl);\n\n        $expectedHeaders = [];\n        foreach ($headers as $header) {\n            $parts = explode(':', trim($header), 2);\n            $key = $parts[0];\n            $value = $parts[1] ?? '';\n            $expectedHeaders[strtolower($key)] = trim($value);\n        }\n        self::assertEqualsIgnoringCase($expectedHeaders, $actual->getHeaders(), $message);\n\n        switch ($expectedHeaders['content-type'] ?? null) {\n            case 'application/x-www-form-urlencoded':\n                self::assertHttpFormEqualsHttpForm(trim($body), $actual->getBody()->stringify(), $message);\n\n                break;\n            case 'application/json':\n            case 'application/x-amz-json-1.0':\n            case 'application/x-amz-json-1.1':\n                if ('' === trim($body)) {\n                    self::assertSame($body, $actual->getBody()->stringify());\n                } else {\n                    self::assertJsonStringEqualsJsonString(trim($body), $actual->getBody()->stringify(), $message);\n                }\n\n                break;\n            case 'application/xml':\n                if ('' === trim($body)) {\n                    self::assertSame($body, $actual->getBody()->stringify());\n                } else {\n                    self::assertXmlStringEqualsXmlString(trim($body), $actual->getBody()->stringify(), $message);\n                }\n\n                break;\n            default:\n                self::assertSame(trim($body), $actual->getBody()->stringify());\n\n                break;\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/core/src/Waiter.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace AsyncAws\\Core;\n\nuse AsyncAws\\Core\\Exception\\Http\\HttpException;\nuse AsyncAws\\Core\\Exception\\Http\\NetworkException;\nuse AsyncAws\\Core\\Exception\\LogicException;\n\n/**\n * The waiter promise is always returned from every API call to a waiter.\n */\nclass Waiter\n{\n    public const STATE_SUCCESS = 'success';\n    public const STATE_FAILURE = 'failure';\n    public const STATE_PENDING = 'pending';\n\n    protected const WAIT_TIMEOUT = 30.0;\n    protected const WAIT_DELAY = 5.0;\n\n    /**\n     * @var AbstractApi|null\n     */\n    protected $awsClient;\n\n    /**\n     * Input used to build the API request that generate this Waiter.\n     *\n     * @var object|null\n     */\n    protected $input;\n\n    /**\n     * @var Response\n     */\n    private $response;\n\n    /**\n     * Whether or not a new response should be fetched.\n     *\n     * @var bool\n     */\n    private $needRefresh = false;\n\n    /**\n     * @var string|null\n     */\n    private $finalState;\n\n    /**\n     * @var bool\n     */\n    private $resolved = false;\n\n    public function __construct(Response $response, AbstractApi $awsClient, ?object $request)\n    {\n        $this->response = $response;\n        $this->awsClient = $awsClient;\n        $this->input = $request;\n    }\n\n    public function __destruct()\n    {\n        if (!$this->resolved) {\n            $this->resolve();\n        }\n    }\n\n    final public function isSuccess(): bool\n    {\n        return self::STATE_SUCCESS === $this->getState();\n    }\n\n    final public function isFailure(): bool\n    {\n        return self::STATE_FAILURE === $this->getState();\n    }\n\n    final public function isPending(): bool\n    {\n        return self::STATE_PENDING === $this->getState();\n    }\n\n    final public function getState(): string\n    {\n        if (null !== $this->finalState) {\n            return $this->finalState;\n        }\n\n        if ($this->needRefresh) {\n            $this->stealResponse($this->refreshState());\n        }\n\n        try {\n            $this->response->resolve();\n            $exception = null;\n        } catch (HttpException $exception) {\n            // use $exception later\n        } finally {\n            $this->resolved = true;\n            $this->needRefresh = true;\n        }\n\n        $state = $this->extractState($this->response, $exception);\n\n        switch ($state) {\n            case self::STATE_SUCCESS:\n            case self::STATE_FAILURE:\n                $this->finalState = $state;\n\n                break;\n            case self::STATE_PENDING:\n                break;\n            default:\n                throw new LogicException(\\sprintf('Unexpected state \"%s\" from Waiter \"%s\".', $state, __CLASS__));\n        }\n\n        return $state;\n    }\n\n    /**\n     * Make sure the actual request is executed.\n     *\n     * @param float|null $timeout Duration in seconds before aborting. When null wait until the end of execution.\n     *\n     * @return bool false on timeout. True if the response has returned with as status code.\n     *\n     * @throws NetworkException\n     */\n    final public function resolve(?float $timeout = null): bool\n    {\n        try {\n            return $this->response->resolve($timeout);\n        } catch (HttpException $exception) {\n            return true;\n        } finally {\n            $this->resolved = true;\n        }\n    }\n\n    /**\n     * Returns info on the current request.\n     *\n     * @return array{\n     *                resolved: bool,\n     *                body_downloaded: bool,\n     *                response: \\Symfony\\Contracts\\HttpClient\\ResponseInterface,\n     *                status: int,\n     *                }\n     */\n    final public function info(): array\n    {\n        return $this->response->info();\n    }\n\n    final public function cancel(): void\n    {\n        $this->response->cancel();\n        $this->needRefresh = true;\n        $this->resolved = true;\n    }\n\n    /**\n     * Wait until the state is success.\n     * Stopped when the state become Failure or the defined timeout is reached.\n     *\n     * @param float $timeout Duration in seconds before aborting\n     * @param float $delay   Duration in seconds between each check\n     *\n     * @return bool true if a final state was reached\n     */\n    final public function wait(?float $timeout = null, ?float $delay = null): bool\n    {\n        if (null !== $this->finalState) {\n            return true;\n        }\n\n        $timeout = $timeout ?? static::WAIT_TIMEOUT;\n        $delay = $delay ?? static::WAIT_DELAY;\n\n        $start = microtime(true);\n        while (true) {\n            if ($this->needRefresh) {\n                $this->stealResponse($this->refreshState());\n            }\n\n            // If request times out\n            if (!$this->resolve($timeout - (microtime(true) - $start))) {\n                break;\n            }\n\n            $this->getState();\n            // If we reached a final state\n            if ($this->finalState) {\n                return true;\n            }\n\n            // If the timeout will expire during our sleep, then exit early.\n            if ($delay > $timeout - (microtime(true) - $start)) {\n                break;\n            }\n\n            usleep((int) ceil($delay * 1000000));\n        }\n\n        return false;\n    }\n\n    protected function extractState(Response $response, ?HttpException $exception): string\n    {\n        return self::STATE_PENDING;\n    }\n\n    protected function refreshState(): Waiter\n    {\n        return $this;\n    }\n\n    private function stealResponse(self $waiter): void\n    {\n        $this->response = $waiter->response;\n        $this->resolved = $waiter->resolved;\n        $waiter->resolved = true;\n        $this->needRefresh = false;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/.gitattributes",
    "content": "/.github export-ignore\n/tests export-ignore\n/.gitignore export-ignore\n/Makefile export-ignore\n/phpunit.xml.dist export-ignore\n"
  },
  {
    "path": "server/vendor/async-aws/s3/CHANGELOG.md",
    "content": "# Change Log\n\n## NOT RELEASED\n\n## 1.14.0\n\n### Added\n\n- AWS api-change: Added `ap-southeast-4` region.\n- AWS enhancement: Documentation updates.\n- AWS api-change: Provides support for \"Snow\" Storage class.\n- AWS api-change: Integrate double encryption feature to SDKs.\n- AWS api-change: This release adds SDK support for request-payer request header and request-charged response header in the \"GetBucketAccelerateConfiguration\", \"ListMultipartUploads\", \"ListObjects\", \"ListObjectsV2\" and \"ListObjectVersions\" S3 APIs.\n\n## 1.13.0\n\n### Added\n\n- Added `me-central-1`, `ap-southeast-3`, `eu-central-2`, `eu-south-2` and `ap-south-2` regions\n\n## 1.12.0\n\n### Fixed\n\n- Format datetime with `RFC7231` to provide a workaround for unsupported `RFC822` format.\n- Broken path to host when operation's URL contains a query string.\n\n### Changed\n\n- Set default value to `false` for the `sendChunkedBody` option.\n\n## 1.11.0\n\n### Added\n\n- AWS api-change: Added `ap-southeast-3` region.\n- AWS enhancement: Documentation updates.\n- AWS feature: Adds support for flexible checksums\n- AWS api-change: This release adds support for new integrity checking capabilities in Amazon S3. You can choose from four supported checksum algorithms for data integrity checking on your upload and download requests. In addition, AWS SDK can automatically calculate a checksum as it streams data into S3\n\n## 1.10.0\n\n### Added\n\n- AWS api-change: used unique endpoint for `accesspoint-*` regions\n- AWS api-change: Rework regions configuration.\n- AWS api-change: Introduce Amazon S3 Glacier Instant Retrieval storage class and a new setting in S3 Object Ownership to disable ACLs for bucket and the objects in it.\n- AWS api-change: Amazon S3 Event Notifications adds Amazon EventBridge as a destination and supports additional event types. The PutBucketNotificationConfiguration API can now skip validation of Amazon SQS, Amazon SNS and AWS Lambda destinations.\n- AWS api-change: Introduce two new Filters to S3 Lifecycle configurations - ObjectSizeGreaterThan and ObjectSizeLessThan. Introduce a new way to trigger actions on noncurrent versions by providing the number of newer noncurrent versions along with noncurrent days.\n\n## 1.9.2\n\n### Added\n\n- AWS enhancement: Documentation updates for Amazon S3\n- Fixed camelCased of Dom classes\n\n## 1.9.1\n\n### Fixed\n\n- Fix issue when a request to upload a file is retried\n- camelCased methods with paginator and waiter\n- AWS enhancement: Documentation updates for Amazon S3\n\n## 1.9.0\n\n### Added\n\n- AWS api-change: Adding ID element to the CORSRule schema\n- AWS api-change: Adding many more regions\n\n### Changed\n\n- AWS api-change: Reword docblocks\n- AWS enhancement: Amazon S3 Documentation updates\n- AWS api-change: Improve documentation\n- AWS enhancement: Documentation updates for Amazon S3\n\n### Fixed\n\n- Wrong custom encoding on chunked stream\n\n## 1.8.0\n\n### Added\n\n- Changed case of object's properties to camelCase.\n- Added documentation in class headers.\n- Added `PutBucketCors`, `DeleteBucketCors` and `GetBucketCors` methods.\n- Added domain exceptions\n\n## 1.7.0\n\n### Added\n\n- AWS api-change: S3 adds support for multiple-destination replication, option to sync replica modifications; S3 Bucket Keys to reduce cost of S3 SSE with AWS KMS\n- AWS api-change: Format GetObject's Expires header to be an http-date instead of iso8601\n- Added support for `sendChunkedBody` option to enable/disabled chunked body.\n\n## 1.6.0\n\n### Added\n\n- Added `S3Client::putBucketNotificationConfiguration()`\n- AWS api-change: S3 Intelligent-Tiering adds support for Archive and Deep Archive Access tiers\n\n### Changed\n\n- Removed deprecation warning on Content-MD5 headers.\n\n### Fixed\n\n- Make sure we throw exception from async-aws/core\n\n## 1.5.1\n\n### Fixed\n\n- Fixed endpoint issue when a bucket name started with a number.\n- Improve StorageClass documentation.\n\n## 1.5.0\n\n### Added\n\n- AWS api-change: Amazon S3 on Outposts expands object storage to on-premises AWS Outposts environments, enabling you to store and retrieve objects using S3 APIs and features.\n\n## 1.4.0\n\n### Added\n\n- AWS api-change: Bucket owner verification feature added. This feature introduces the x-amz-expected-bucket-owner and x-amz-source-expected-bucket-owner headers.\n\n## 1.3.0\n\n### Added\n\n- Support for PHP 8\n- Added `S3Client::deleteBucket()`\n\n### Fixed\n\n- Fixed an issue in Metadata not beeing sent to AWS in `PutObject`, `CopyObject` and `CreateMultipartUpload`\n- Internal AWS prefix were added to Metadata's name in `GetObject` and `HeadObject`.\n\n### Deprecated by AWS\n\n- `PutObjectAclRequest::getContentMD5()`\n- `PutObjectAclRequest::setContentMD5()`\n\n## 1.2.0\n\n### Added\n\n- Changed from \"path  style\" endpoints (https://amazon.com/bucket) to \"host style\" endpoints (https://bucket.amazon.com). To keep the old behavior, use `s3PathStyleEndpoint: true` configuration option.\n\n### Fixed\n\n- Fixed issue when Bucket or Object's Key contained a special char like `#`\n\n### Deprecation\n\n- Protected methods `getServiceCode`, `getSignatureVersion` and `getSignatureScopeName` of `S3Client` are deprecated and will be removed in 2.0\n\n## 1.1.0\n\n### Added\n\n- Backported split request behavior in `SignerV4ForS3`\n\n### Fixed\n\n- Add return typehint for `listMultipartUploads`, `listObjectsV2` and `listParts`\n\n## 1.0.0\n\n### Added\n\n- Support for async-aws/core 1.0.\n\n## 0.4.0\n\n### Added\n\n- Support for presign\n- Multipart upload\n- Waiters: `S3Client::bucketExists()` and `S3Client::objectExists()`\n- The `AsyncAws\\S3\\Enum\\*`, `AsyncAws\\S3\\Input\\*` and `AsyncAws\\S3\\ValueObject*` classes are marked final.\n\n### Changed\n\n- Moved value objects to a dedicated namespace.\n- Results' `populateResult()` has only one argument. It takes a `AsyncAws\\Core\\Response`.\n- Using `DateTimeImmutable` instead of `DateTimeInterface`\n\n### Removed\n\n- Dependency on `symfony/http-client-contracts`\n- All `validate()` methods on the inputs. They are merged with `request()`.\n\n## 0.3.0\n\n### Added\n\n- Enums; `BucketCannedACL`, `BucketLocationConstraint`, `EncodingType`, `MetadataDirective`, `ObjectCannedACL`, `ObjectLockLegalHoldStatus`\n  `ObjectLockMode`, `ObjectStorageClass`, `Permission`, `ReplicationStatus`, `RequestCharged`, `RequestPayer`, `ServerSideEncryption`\n  `StorageClass`, `TaggingDirective`, `Type`\n\n### Changed\n\n- Removed `requestBody()`, `requestHeaders()`, `requestQuery()` and `requestUri()` input classes. They are replaced with `request()`.\n- Using async-aws/core: 0.4.0\n\n### Fixed\n\n- Dont generate a request body when no body is needed.\n\n## 0.2.0\n\n### Changed\n\n- Using async-aws/core: 0.3.0\n\n## 0.1.0\n\nFirst version\n"
  },
  {
    "path": "server/vendor/async-aws/s3/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2020 Jérémy Derussé, Tobias Nyholm\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "server/vendor/async-aws/s3/README.md",
    "content": "# AsyncAws S3 Client\n\n![](https://github.com/async-aws/s3/workflows/Tests/badge.svg?branch=master)\n![](https://github.com/async-aws/s3/workflows/BC%20Check/badge.svg?branch=master)\n\nAn API client for S3.\n\n## Install\n\n```cli\ncomposer require async-aws/s3\n```\n\n## Documentation\n\nSee https://async-aws.com/clients/s3.html for documentation.\n\n## Contribute\n\nContributions are welcome and appreciated. Please read https://async-aws.com/contribute/\n"
  },
  {
    "path": "server/vendor/async-aws/s3/composer.json",
    "content": "{\n    \"name\": \"async-aws/s3\",\n    \"description\": \"S3 client, part of the AWS SDK provided by AsyncAws.\",\n    \"license\": \"MIT\",\n    \"type\": \"library\",\n    \"keywords\": [\n        \"aws\",\n        \"amazon\",\n        \"sdk\",\n        \"async-aws\",\n        \"s3\"\n    ],\n    \"require\": {\n        \"php\": \"^7.2.5 || ^8.0\",\n        \"ext-SimpleXML\": \"*\",\n        \"ext-dom\": \"*\",\n        \"ext-filter\": \"*\",\n        \"ext-hash\": \"*\",\n        \"async-aws/core\": \"^1.9\"\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"AsyncAws\\\\S3\\\\\": \"src\"\n        }\n    },\n    \"autoload-dev\": {\n        \"psr-4\": {\n            \"AsyncAws\\\\S3\\\\Tests\\\\\": \"tests/\"\n        }\n    },\n    \"extra\": {\n        \"branch-alias\": {\n            \"dev-master\": \"1.14-dev\"\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Enum/ArchiveStatus.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Enum;\n\nfinal class ArchiveStatus\n{\n    public const ARCHIVE_ACCESS = 'ARCHIVE_ACCESS';\n    public const DEEP_ARCHIVE_ACCESS = 'DEEP_ARCHIVE_ACCESS';\n\n    public static function exists(string $value): bool\n    {\n        return isset([\n            self::ARCHIVE_ACCESS => true,\n            self::DEEP_ARCHIVE_ACCESS => true,\n        ][$value]);\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Enum/BucketCannedACL.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Enum;\n\nfinal class BucketCannedACL\n{\n    public const AUTHENTICATED_READ = 'authenticated-read';\n    public const PRIVATE = 'private';\n    public const PUBLIC_READ = 'public-read';\n    public const PUBLIC_READ_WRITE = 'public-read-write';\n\n    public static function exists(string $value): bool\n    {\n        return isset([\n            self::AUTHENTICATED_READ => true,\n            self::PRIVATE => true,\n            self::PUBLIC_READ => true,\n            self::PUBLIC_READ_WRITE => true,\n        ][$value]);\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Enum/BucketLocationConstraint.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Enum;\n\nfinal class BucketLocationConstraint\n{\n    public const AF_SOUTH_1 = 'af-south-1';\n    public const AP_EAST_1 = 'ap-east-1';\n    public const AP_NORTHEAST_1 = 'ap-northeast-1';\n    public const AP_NORTHEAST_2 = 'ap-northeast-2';\n    public const AP_NORTHEAST_3 = 'ap-northeast-3';\n    public const AP_SOUTHEAST_1 = 'ap-southeast-1';\n    public const AP_SOUTHEAST_2 = 'ap-southeast-2';\n    public const AP_SOUTHEAST_3 = 'ap-southeast-3';\n    public const AP_SOUTH_1 = 'ap-south-1';\n    public const CA_CENTRAL_1 = 'ca-central-1';\n    public const CN_NORTHWEST_1 = 'cn-northwest-1';\n    public const CN_NORTH_1 = 'cn-north-1';\n    public const EU = 'EU';\n    public const EU_CENTRAL_1 = 'eu-central-1';\n    public const EU_NORTH_1 = 'eu-north-1';\n    public const EU_SOUTH_1 = 'eu-south-1';\n    public const EU_WEST_1 = 'eu-west-1';\n    public const EU_WEST_2 = 'eu-west-2';\n    public const EU_WEST_3 = 'eu-west-3';\n    public const ME_SOUTH_1 = 'me-south-1';\n    public const SA_EAST_1 = 'sa-east-1';\n    public const US_EAST_2 = 'us-east-2';\n    public const US_GOV_EAST_1 = 'us-gov-east-1';\n    public const US_GOV_WEST_1 = 'us-gov-west-1';\n    public const US_WEST_1 = 'us-west-1';\n    public const US_WEST_2 = 'us-west-2';\n\n    public static function exists(string $value): bool\n    {\n        return isset([\n            self::AF_SOUTH_1 => true,\n            self::AP_EAST_1 => true,\n            self::AP_NORTHEAST_1 => true,\n            self::AP_NORTHEAST_2 => true,\n            self::AP_NORTHEAST_3 => true,\n            self::AP_SOUTHEAST_1 => true,\n            self::AP_SOUTHEAST_2 => true,\n            self::AP_SOUTHEAST_3 => true,\n            self::AP_SOUTH_1 => true,\n            self::CA_CENTRAL_1 => true,\n            self::CN_NORTHWEST_1 => true,\n            self::CN_NORTH_1 => true,\n            self::EU => true,\n            self::EU_CENTRAL_1 => true,\n            self::EU_NORTH_1 => true,\n            self::EU_SOUTH_1 => true,\n            self::EU_WEST_1 => true,\n            self::EU_WEST_2 => true,\n            self::EU_WEST_3 => true,\n            self::ME_SOUTH_1 => true,\n            self::SA_EAST_1 => true,\n            self::US_EAST_2 => true,\n            self::US_GOV_EAST_1 => true,\n            self::US_GOV_WEST_1 => true,\n            self::US_WEST_1 => true,\n            self::US_WEST_2 => true,\n        ][$value]);\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Enum/ChecksumAlgorithm.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Enum;\n\nfinal class ChecksumAlgorithm\n{\n    public const CRC32 = 'CRC32';\n    public const CRC32C = 'CRC32C';\n    public const SHA1 = 'SHA1';\n    public const SHA256 = 'SHA256';\n\n    public static function exists(string $value): bool\n    {\n        return isset([\n            self::CRC32 => true,\n            self::CRC32C => true,\n            self::SHA1 => true,\n            self::SHA256 => true,\n        ][$value]);\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Enum/ChecksumMode.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Enum;\n\nfinal class ChecksumMode\n{\n    public const ENABLED = 'ENABLED';\n\n    public static function exists(string $value): bool\n    {\n        return isset([\n            self::ENABLED => true,\n        ][$value]);\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Enum/EncodingType.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Enum;\n\n/**\n * Requests Amazon S3 to encode the object keys in the response and specifies the encoding method to use. An object key\n * may contain any Unicode character; however, XML 1.0 parser cannot parse some characters, such as characters with an\n * ASCII value from 0 to 10. For characters that are not supported in XML 1.0, you can add this parameter to request\n * that Amazon S3 encode the keys in the response.\n */\nfinal class EncodingType\n{\n    public const URL = 'url';\n\n    public static function exists(string $value): bool\n    {\n        return isset([\n            self::URL => true,\n        ][$value]);\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Enum/Event.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Enum;\n\n/**\n * The bucket event for which to send notifications.\n */\nfinal class Event\n{\n    public const S3_INTELLIGENT_TIERING = 's3:IntelligentTiering';\n    public const S3_LIFECYCLE_EXPIRATION_ALL = 's3:LifecycleExpiration:*';\n    public const S3_LIFECYCLE_EXPIRATION_DELETE = 's3:LifecycleExpiration:Delete';\n    public const S3_LIFECYCLE_EXPIRATION_DELETE_MARKER_CREATED = 's3:LifecycleExpiration:DeleteMarkerCreated';\n    public const S3_LIFECYCLE_TRANSITION = 's3:LifecycleTransition';\n    public const S3_OBJECT_ACL_PUT = 's3:ObjectAcl:Put';\n    public const S3_OBJECT_CREATED_ALL = 's3:ObjectCreated:*';\n    public const S3_OBJECT_CREATED_COMPLETE_MULTIPART_UPLOAD = 's3:ObjectCreated:CompleteMultipartUpload';\n    public const S3_OBJECT_CREATED_COPY = 's3:ObjectCreated:Copy';\n    public const S3_OBJECT_CREATED_POST = 's3:ObjectCreated:Post';\n    public const S3_OBJECT_CREATED_PUT = 's3:ObjectCreated:Put';\n    public const S3_OBJECT_REMOVED_ALL = 's3:ObjectRemoved:*';\n    public const S3_OBJECT_REMOVED_DELETE = 's3:ObjectRemoved:Delete';\n    public const S3_OBJECT_REMOVED_DELETE_MARKER_CREATED = 's3:ObjectRemoved:DeleteMarkerCreated';\n    public const S3_OBJECT_RESTORE_ALL = 's3:ObjectRestore:*';\n    public const S3_OBJECT_RESTORE_COMPLETED = 's3:ObjectRestore:Completed';\n    public const S3_OBJECT_RESTORE_DELETE = 's3:ObjectRestore:Delete';\n    public const S3_OBJECT_RESTORE_POST = 's3:ObjectRestore:Post';\n    public const S3_OBJECT_TAGGING_ALL = 's3:ObjectTagging:*';\n    public const S3_OBJECT_TAGGING_DELETE = 's3:ObjectTagging:Delete';\n    public const S3_OBJECT_TAGGING_PUT = 's3:ObjectTagging:Put';\n    public const S3_REDUCED_REDUNDANCY_LOST_OBJECT = 's3:ReducedRedundancyLostObject';\n    public const S3_REPLICATION_ALL = 's3:Replication:*';\n    public const S3_REPLICATION_OPERATION_FAILED_REPLICATION = 's3:Replication:OperationFailedReplication';\n    public const S3_REPLICATION_OPERATION_MISSED_THRESHOLD = 's3:Replication:OperationMissedThreshold';\n    public const S3_REPLICATION_OPERATION_NOT_TRACKED = 's3:Replication:OperationNotTracked';\n    public const S3_REPLICATION_OPERATION_REPLICATED_AFTER_THRESHOLD = 's3:Replication:OperationReplicatedAfterThreshold';\n\n    public static function exists(string $value): bool\n    {\n        return isset([\n            self::S3_INTELLIGENT_TIERING => true,\n            self::S3_LIFECYCLE_EXPIRATION_ALL => true,\n            self::S3_LIFECYCLE_EXPIRATION_DELETE => true,\n            self::S3_LIFECYCLE_EXPIRATION_DELETE_MARKER_CREATED => true,\n            self::S3_LIFECYCLE_TRANSITION => true,\n            self::S3_OBJECT_ACL_PUT => true,\n            self::S3_OBJECT_CREATED_ALL => true,\n            self::S3_OBJECT_CREATED_COMPLETE_MULTIPART_UPLOAD => true,\n            self::S3_OBJECT_CREATED_COPY => true,\n            self::S3_OBJECT_CREATED_POST => true,\n            self::S3_OBJECT_CREATED_PUT => true,\n            self::S3_OBJECT_REMOVED_ALL => true,\n            self::S3_OBJECT_REMOVED_DELETE => true,\n            self::S3_OBJECT_REMOVED_DELETE_MARKER_CREATED => true,\n            self::S3_OBJECT_RESTORE_ALL => true,\n            self::S3_OBJECT_RESTORE_COMPLETED => true,\n            self::S3_OBJECT_RESTORE_DELETE => true,\n            self::S3_OBJECT_RESTORE_POST => true,\n            self::S3_OBJECT_TAGGING_ALL => true,\n            self::S3_OBJECT_TAGGING_DELETE => true,\n            self::S3_OBJECT_TAGGING_PUT => true,\n            self::S3_REDUCED_REDUNDANCY_LOST_OBJECT => true,\n            self::S3_REPLICATION_ALL => true,\n            self::S3_REPLICATION_OPERATION_FAILED_REPLICATION => true,\n            self::S3_REPLICATION_OPERATION_MISSED_THRESHOLD => true,\n            self::S3_REPLICATION_OPERATION_NOT_TRACKED => true,\n            self::S3_REPLICATION_OPERATION_REPLICATED_AFTER_THRESHOLD => true,\n        ][$value]);\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Enum/FilterRuleName.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Enum;\n\nfinal class FilterRuleName\n{\n    public const PREFIX = 'prefix';\n    public const SUFFIX = 'suffix';\n\n    public static function exists(string $value): bool\n    {\n        return isset([\n            self::PREFIX => true,\n            self::SUFFIX => true,\n        ][$value]);\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Enum/IntelligentTieringAccessTier.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Enum;\n\nfinal class IntelligentTieringAccessTier\n{\n    public const ARCHIVE_ACCESS = 'ARCHIVE_ACCESS';\n    public const DEEP_ARCHIVE_ACCESS = 'DEEP_ARCHIVE_ACCESS';\n\n    public static function exists(string $value): bool\n    {\n        return isset([\n            self::ARCHIVE_ACCESS => true,\n            self::DEEP_ARCHIVE_ACCESS => true,\n        ][$value]);\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Enum/MetadataDirective.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Enum;\n\nfinal class MetadataDirective\n{\n    public const COPY = 'COPY';\n    public const REPLACE = 'REPLACE';\n\n    public static function exists(string $value): bool\n    {\n        return isset([\n            self::COPY => true,\n            self::REPLACE => true,\n        ][$value]);\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Enum/ObjectCannedACL.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Enum;\n\nfinal class ObjectCannedACL\n{\n    public const AUTHENTICATED_READ = 'authenticated-read';\n    public const AWS_EXEC_READ = 'aws-exec-read';\n    public const BUCKET_OWNER_FULL_CONTROL = 'bucket-owner-full-control';\n    public const BUCKET_OWNER_READ = 'bucket-owner-read';\n    public const PRIVATE = 'private';\n    public const PUBLIC_READ = 'public-read';\n    public const PUBLIC_READ_WRITE = 'public-read-write';\n\n    public static function exists(string $value): bool\n    {\n        return isset([\n            self::AUTHENTICATED_READ => true,\n            self::AWS_EXEC_READ => true,\n            self::BUCKET_OWNER_FULL_CONTROL => true,\n            self::BUCKET_OWNER_READ => true,\n            self::PRIVATE => true,\n            self::PUBLIC_READ => true,\n            self::PUBLIC_READ_WRITE => true,\n        ][$value]);\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Enum/ObjectLockLegalHoldStatus.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Enum;\n\nfinal class ObjectLockLegalHoldStatus\n{\n    public const OFF = 'OFF';\n    public const ON = 'ON';\n\n    public static function exists(string $value): bool\n    {\n        return isset([\n            self::OFF => true,\n            self::ON => true,\n        ][$value]);\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Enum/ObjectLockMode.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Enum;\n\nfinal class ObjectLockMode\n{\n    public const COMPLIANCE = 'COMPLIANCE';\n    public const GOVERNANCE = 'GOVERNANCE';\n\n    public static function exists(string $value): bool\n    {\n        return isset([\n            self::COMPLIANCE => true,\n            self::GOVERNANCE => true,\n        ][$value]);\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Enum/ObjectOwnership.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Enum;\n\n/**\n * The container element for object ownership for a bucket's ownership controls.\n *\n * BucketOwnerPreferred - Objects uploaded to the bucket change ownership to the bucket owner if the objects are\n * uploaded with the `bucket-owner-full-control` canned ACL.\n *\n * ObjectWriter - The uploading account will own the object if the object is uploaded with the\n * `bucket-owner-full-control` canned ACL.\n *\n * BucketOwnerEnforced - Access control lists (ACLs) are disabled and no longer affect permissions. The bucket owner\n * automatically owns and has full control over every object in the bucket. The bucket only accepts PUT requests that\n * don't specify an ACL or bucket owner full control ACLs, such as the `bucket-owner-full-control` canned ACL or an\n * equivalent form of this ACL expressed in the XML format.\n */\nfinal class ObjectOwnership\n{\n    public const BUCKET_OWNER_ENFORCED = 'BucketOwnerEnforced';\n    public const BUCKET_OWNER_PREFERRED = 'BucketOwnerPreferred';\n    public const OBJECT_WRITER = 'ObjectWriter';\n\n    public static function exists(string $value): bool\n    {\n        return isset([\n            self::BUCKET_OWNER_ENFORCED => true,\n            self::BUCKET_OWNER_PREFERRED => true,\n            self::OBJECT_WRITER => true,\n        ][$value]);\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Enum/ObjectStorageClass.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Enum;\n\nfinal class ObjectStorageClass\n{\n    public const DEEP_ARCHIVE = 'DEEP_ARCHIVE';\n    public const GLACIER = 'GLACIER';\n    public const GLACIER_IR = 'GLACIER_IR';\n    public const INTELLIGENT_TIERING = 'INTELLIGENT_TIERING';\n    public const ONEZONE_IA = 'ONEZONE_IA';\n    public const OUTPOSTS = 'OUTPOSTS';\n    public const REDUCED_REDUNDANCY = 'REDUCED_REDUNDANCY';\n    public const SNOW = 'SNOW';\n    public const STANDARD = 'STANDARD';\n    public const STANDARD_IA = 'STANDARD_IA';\n\n    public static function exists(string $value): bool\n    {\n        return isset([\n            self::DEEP_ARCHIVE => true,\n            self::GLACIER => true,\n            self::GLACIER_IR => true,\n            self::INTELLIGENT_TIERING => true,\n            self::ONEZONE_IA => true,\n            self::OUTPOSTS => true,\n            self::REDUCED_REDUNDANCY => true,\n            self::SNOW => true,\n            self::STANDARD => true,\n            self::STANDARD_IA => true,\n        ][$value]);\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Enum/Permission.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Enum;\n\nfinal class Permission\n{\n    public const FULL_CONTROL = 'FULL_CONTROL';\n    public const READ = 'READ';\n    public const READ_ACP = 'READ_ACP';\n    public const WRITE = 'WRITE';\n    public const WRITE_ACP = 'WRITE_ACP';\n\n    public static function exists(string $value): bool\n    {\n        return isset([\n            self::FULL_CONTROL => true,\n            self::READ => true,\n            self::READ_ACP => true,\n            self::WRITE => true,\n            self::WRITE_ACP => true,\n        ][$value]);\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Enum/ReplicationStatus.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Enum;\n\nfinal class ReplicationStatus\n{\n    public const COMPLETE = 'COMPLETE';\n    public const FAILED = 'FAILED';\n    public const PENDING = 'PENDING';\n    public const REPLICA = 'REPLICA';\n\n    public static function exists(string $value): bool\n    {\n        return isset([\n            self::COMPLETE => true,\n            self::FAILED => true,\n            self::PENDING => true,\n            self::REPLICA => true,\n        ][$value]);\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Enum/RequestCharged.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Enum;\n\n/**\n * If present, indicates that the requester was successfully charged for the request.\n */\nfinal class RequestCharged\n{\n    public const REQUESTER = 'requester';\n\n    public static function exists(string $value): bool\n    {\n        return isset([\n            self::REQUESTER => true,\n        ][$value]);\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Enum/RequestPayer.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Enum;\n\n/**\n * Confirms that the requester knows that they will be charged for the request. Bucket owners need not specify this\n * parameter in their requests. For information about downloading objects from Requester Pays buckets, see Downloading\n * Objects in Requester Pays Buckets [^1] in the *Amazon S3 User Guide*.\n *\n * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html\n */\nfinal class RequestPayer\n{\n    public const REQUESTER = 'requester';\n\n    public static function exists(string $value): bool\n    {\n        return isset([\n            self::REQUESTER => true,\n        ][$value]);\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Enum/ServerSideEncryption.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Enum;\n\nfinal class ServerSideEncryption\n{\n    public const AES256 = 'AES256';\n    public const AWS_KMS = 'aws:kms';\n    public const AWS_KMS_DSSE = 'aws:kms:dsse';\n\n    public static function exists(string $value): bool\n    {\n        return isset([\n            self::AES256 => true,\n            self::AWS_KMS => true,\n            self::AWS_KMS_DSSE => true,\n        ][$value]);\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Enum/StorageClass.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Enum;\n\nfinal class StorageClass\n{\n    public const DEEP_ARCHIVE = 'DEEP_ARCHIVE';\n    public const GLACIER = 'GLACIER';\n    public const GLACIER_IR = 'GLACIER_IR';\n    public const INTELLIGENT_TIERING = 'INTELLIGENT_TIERING';\n    public const ONEZONE_IA = 'ONEZONE_IA';\n    public const OUTPOSTS = 'OUTPOSTS';\n    public const REDUCED_REDUNDANCY = 'REDUCED_REDUNDANCY';\n    public const SNOW = 'SNOW';\n    public const STANDARD = 'STANDARD';\n    public const STANDARD_IA = 'STANDARD_IA';\n\n    public static function exists(string $value): bool\n    {\n        return isset([\n            self::DEEP_ARCHIVE => true,\n            self::GLACIER => true,\n            self::GLACIER_IR => true,\n            self::INTELLIGENT_TIERING => true,\n            self::ONEZONE_IA => true,\n            self::OUTPOSTS => true,\n            self::REDUCED_REDUNDANCY => true,\n            self::SNOW => true,\n            self::STANDARD => true,\n            self::STANDARD_IA => true,\n        ][$value]);\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Enum/TaggingDirective.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Enum;\n\nfinal class TaggingDirective\n{\n    public const COPY = 'COPY';\n    public const REPLACE = 'REPLACE';\n\n    public static function exists(string $value): bool\n    {\n        return isset([\n            self::COPY => true,\n            self::REPLACE => true,\n        ][$value]);\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Enum/Type.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Enum;\n\nfinal class Type\n{\n    public const AMAZON_CUSTOMER_BY_EMAIL = 'AmazonCustomerByEmail';\n    public const CANONICAL_USER = 'CanonicalUser';\n    public const GROUP = 'Group';\n\n    public static function exists(string $value): bool\n    {\n        return isset([\n            self::AMAZON_CUSTOMER_BY_EMAIL => true,\n            self::CANONICAL_USER => true,\n            self::GROUP => true,\n        ][$value]);\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Exception/BucketAlreadyExistsException.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Exception;\n\nuse AsyncAws\\Core\\Exception\\Http\\ClientException;\n\n/**\n * The requested bucket name is not available. The bucket namespace is shared by all users of the system. Select a\n * different name and try again.\n */\nfinal class BucketAlreadyExistsException extends ClientException\n{\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Exception/BucketAlreadyOwnedByYouException.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Exception;\n\nuse AsyncAws\\Core\\Exception\\Http\\ClientException;\n\n/**\n * The bucket you tried to create already exists, and you own it. Amazon S3 returns this error in all Amazon Web\n * Services Regions except in the North Virginia Region. For legacy compatibility, if you re-create an existing bucket\n * that you already own in the North Virginia Region, Amazon S3 returns 200 OK and resets the bucket access control\n * lists (ACLs).\n */\nfinal class BucketAlreadyOwnedByYouException extends ClientException\n{\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Exception/InvalidObjectStateException.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Exception;\n\nuse AsyncAws\\Core\\Exception\\Http\\ClientException;\nuse AsyncAws\\S3\\Enum\\IntelligentTieringAccessTier;\nuse AsyncAws\\S3\\Enum\\StorageClass;\nuse Symfony\\Contracts\\HttpClient\\ResponseInterface;\n\n/**\n * Object is archived and inaccessible until restored.\n */\nfinal class InvalidObjectStateException extends ClientException\n{\n    private $storageClass;\n\n    private $accessTier;\n\n    /**\n     * @return IntelligentTieringAccessTier::*|null\n     */\n    public function getAccessTier(): ?string\n    {\n        return $this->accessTier;\n    }\n\n    /**\n     * @return StorageClass::*|null\n     */\n    public function getStorageClass(): ?string\n    {\n        return $this->storageClass;\n    }\n\n    protected function populateResult(ResponseInterface $response): void\n    {\n        $data = new \\SimpleXMLElement($response->getContent(false));\n        if (0 < $data->Error->count()) {\n            $data = $data->Error;\n        }\n        $this->storageClass = ($v = $data->StorageClass) ? (string) $v : null;\n        $this->accessTier = ($v = $data->AccessTier) ? (string) $v : null;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Exception/NoSuchBucketException.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Exception;\n\nuse AsyncAws\\Core\\Exception\\Http\\ClientException;\n\n/**\n * The specified bucket does not exist.\n */\nfinal class NoSuchBucketException extends ClientException\n{\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Exception/NoSuchKeyException.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Exception;\n\nuse AsyncAws\\Core\\Exception\\Http\\ClientException;\n\n/**\n * The specified key does not exist.\n */\nfinal class NoSuchKeyException extends ClientException\n{\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Exception/NoSuchUploadException.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Exception;\n\nuse AsyncAws\\Core\\Exception\\Http\\ClientException;\n\n/**\n * The specified multipart upload does not exist.\n */\nfinal class NoSuchUploadException extends ClientException\n{\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Exception/ObjectNotInActiveTierErrorException.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Exception;\n\nuse AsyncAws\\Core\\Exception\\Http\\ClientException;\n\n/**\n * The source object of the COPY action is not in the active tier and is only stored in Amazon S3 Glacier.\n */\nfinal class ObjectNotInActiveTierErrorException extends ClientException\n{\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Input/AbortMultipartUploadRequest.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Input;\n\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\nuse AsyncAws\\Core\\Input;\nuse AsyncAws\\Core\\Request;\nuse AsyncAws\\Core\\Stream\\StreamFactory;\nuse AsyncAws\\S3\\Enum\\RequestPayer;\n\nfinal class AbortMultipartUploadRequest extends Input\n{\n    /**\n     * The bucket name to which the upload was taking place.\n     *\n     * When using this action with an access point, you must direct requests to the access point hostname. The access point\n     * hostname takes the form *AccessPointName*-*AccountId*.s3-accesspoint.*Region*.amazonaws.com. When using this action\n     * with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket\n     * name. For more information about access point ARNs, see Using access points [^1] in the *Amazon S3 User Guide*.\n     *\n     * When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3\n     * on Outposts hostname takes the form `*AccessPointName*-*AccountId*.*outpostID*.s3-outposts.*Region*.amazonaws.com`.\n     * When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access\n     * point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts\n     * [^2] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html\n     * [^2]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html\n     *\n     * @required\n     *\n     * @var string|null\n     */\n    private $bucket;\n\n    /**\n     * Key of the object for which the multipart upload was initiated.\n     *\n     * @required\n     *\n     * @var string|null\n     */\n    private $key;\n\n    /**\n     * Upload ID that identifies the multipart upload.\n     *\n     * @required\n     *\n     * @var string|null\n     */\n    private $uploadId;\n\n    /**\n     * @var RequestPayer::*|null\n     */\n    private $requestPayer;\n\n    /**\n     * The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with\n     * the HTTP status code `403 Forbidden` (access denied).\n     *\n     * @var string|null\n     */\n    private $expectedBucketOwner;\n\n    /**\n     * @param array{\n     *   Bucket?: string,\n     *   Key?: string,\n     *   UploadId?: string,\n     *   RequestPayer?: RequestPayer::*,\n     *   ExpectedBucketOwner?: string,\n     *\n     *   @region?: string,\n     * } $input\n     */\n    public function __construct(array $input = [])\n    {\n        $this->bucket = $input['Bucket'] ?? null;\n        $this->key = $input['Key'] ?? null;\n        $this->uploadId = $input['UploadId'] ?? null;\n        $this->requestPayer = $input['RequestPayer'] ?? null;\n        $this->expectedBucketOwner = $input['ExpectedBucketOwner'] ?? null;\n        parent::__construct($input);\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    public function getBucket(): ?string\n    {\n        return $this->bucket;\n    }\n\n    public function getExpectedBucketOwner(): ?string\n    {\n        return $this->expectedBucketOwner;\n    }\n\n    public function getKey(): ?string\n    {\n        return $this->key;\n    }\n\n    /**\n     * @return RequestPayer::*|null\n     */\n    public function getRequestPayer(): ?string\n    {\n        return $this->requestPayer;\n    }\n\n    public function getUploadId(): ?string\n    {\n        return $this->uploadId;\n    }\n\n    /**\n     * @internal\n     */\n    public function request(): Request\n    {\n        // Prepare headers\n        $headers = ['content-type' => 'application/xml'];\n        if (null !== $this->requestPayer) {\n            if (!RequestPayer::exists($this->requestPayer)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"RequestPayer\" for \"%s\". The value \"%s\" is not a valid \"RequestPayer\".', __CLASS__, $this->requestPayer));\n            }\n            $headers['x-amz-request-payer'] = $this->requestPayer;\n        }\n        if (null !== $this->expectedBucketOwner) {\n            $headers['x-amz-expected-bucket-owner'] = $this->expectedBucketOwner;\n        }\n\n        // Prepare query\n        $query = [];\n        if (null === $v = $this->uploadId) {\n            throw new InvalidArgument(sprintf('Missing parameter \"UploadId\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        $query['uploadId'] = $v;\n\n        // Prepare URI\n        $uri = [];\n        if (null === $v = $this->bucket) {\n            throw new InvalidArgument(sprintf('Missing parameter \"Bucket\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        $uri['Bucket'] = $v;\n        if (null === $v = $this->key) {\n            throw new InvalidArgument(sprintf('Missing parameter \"Key\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        $uri['Key'] = $v;\n        $uriString = '/' . rawurlencode($uri['Bucket']) . '/' . str_replace('%2F', '/', rawurlencode($uri['Key']));\n\n        // Prepare Body\n        $body = '';\n\n        // Return the Request\n        return new Request('DELETE', $uriString, $query, $headers, StreamFactory::create($body));\n    }\n\n    public function setBucket(?string $value): self\n    {\n        $this->bucket = $value;\n\n        return $this;\n    }\n\n    public function setExpectedBucketOwner(?string $value): self\n    {\n        $this->expectedBucketOwner = $value;\n\n        return $this;\n    }\n\n    public function setKey(?string $value): self\n    {\n        $this->key = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param RequestPayer::*|null $value\n     */\n    public function setRequestPayer(?string $value): self\n    {\n        $this->requestPayer = $value;\n\n        return $this;\n    }\n\n    public function setUploadId(?string $value): self\n    {\n        $this->uploadId = $value;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Input/CompleteMultipartUploadRequest.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Input;\n\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\nuse AsyncAws\\Core\\Input;\nuse AsyncAws\\Core\\Request;\nuse AsyncAws\\Core\\Stream\\StreamFactory;\nuse AsyncAws\\S3\\Enum\\RequestPayer;\nuse AsyncAws\\S3\\ValueObject\\CompletedMultipartUpload;\n\nfinal class CompleteMultipartUploadRequest extends Input\n{\n    /**\n     * Name of the bucket to which the multipart upload was initiated.\n     *\n     * When using this action with an access point, you must direct requests to the access point hostname. The access point\n     * hostname takes the form *AccessPointName*-*AccountId*.s3-accesspoint.*Region*.amazonaws.com. When using this action\n     * with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket\n     * name. For more information about access point ARNs, see Using access points [^1] in the *Amazon S3 User Guide*.\n     *\n     * When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3\n     * on Outposts hostname takes the form `*AccessPointName*-*AccountId*.*outpostID*.s3-outposts.*Region*.amazonaws.com`.\n     * When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access\n     * point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts\n     * [^2] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html\n     * [^2]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html\n     *\n     * @required\n     *\n     * @var string|null\n     */\n    private $bucket;\n\n    /**\n     * Object key for which the multipart upload was initiated.\n     *\n     * @required\n     *\n     * @var string|null\n     */\n    private $key;\n\n    /**\n     * The container for the multipart upload request information.\n     *\n     * @var CompletedMultipartUpload|null\n     */\n    private $multipartUpload;\n\n    /**\n     * ID for the initiated multipart upload.\n     *\n     * @required\n     *\n     * @var string|null\n     */\n    private $uploadId;\n\n    /**\n     * This header can be used as a data integrity check to verify that the data received is the same data that was\n     * originally sent. This header specifies the base64-encoded, 32-bit CRC32 checksum of the object. For more information,\n     * see Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html\n     *\n     * @var string|null\n     */\n    private $checksumCrc32;\n\n    /**\n     * This header can be used as a data integrity check to verify that the data received is the same data that was\n     * originally sent. This header specifies the base64-encoded, 32-bit CRC32C checksum of the object. For more\n     * information, see Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html\n     *\n     * @var string|null\n     */\n    private $checksumCrc32C;\n\n    /**\n     * This header can be used as a data integrity check to verify that the data received is the same data that was\n     * originally sent. This header specifies the base64-encoded, 160-bit SHA-1 digest of the object. For more information,\n     * see Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html\n     *\n     * @var string|null\n     */\n    private $checksumSha1;\n\n    /**\n     * This header can be used as a data integrity check to verify that the data received is the same data that was\n     * originally sent. This header specifies the base64-encoded, 256-bit SHA-256 digest of the object. For more\n     * information, see Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html\n     *\n     * @var string|null\n     */\n    private $checksumSha256;\n\n    /**\n     * @var RequestPayer::*|null\n     */\n    private $requestPayer;\n\n    /**\n     * The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with\n     * the HTTP status code `403 Forbidden` (access denied).\n     *\n     * @var string|null\n     */\n    private $expectedBucketOwner;\n\n    /**\n     * The server-side encryption (SSE) algorithm used to encrypt the object. This parameter is needed only when the object\n     * was created using a checksum algorithm. For more information, see Protecting data using SSE-C keys [^1] in the\n     * *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerSideEncryptionCustomerKeys.html\n     *\n     * @var string|null\n     */\n    private $sseCustomerAlgorithm;\n\n    /**\n     * The server-side encryption (SSE) customer managed key. This parameter is needed only when the object was created\n     * using a checksum algorithm. For more information, see Protecting data using SSE-C keys [^1] in the *Amazon S3 User\n     * Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerSideEncryptionCustomerKeys.html\n     *\n     * @var string|null\n     */\n    private $sseCustomerKey;\n\n    /**\n     * The MD5 server-side encryption (SSE) customer managed key. This parameter is needed only when the object was created\n     * using a checksum algorithm. For more information, see Protecting data using SSE-C keys [^1] in the *Amazon S3 User\n     * Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerSideEncryptionCustomerKeys.html\n     *\n     * @var string|null\n     */\n    private $sseCustomerKeyMd5;\n\n    /**\n     * @param array{\n     *   Bucket?: string,\n     *   Key?: string,\n     *   MultipartUpload?: CompletedMultipartUpload|array,\n     *   UploadId?: string,\n     *   ChecksumCRC32?: string,\n     *   ChecksumCRC32C?: string,\n     *   ChecksumSHA1?: string,\n     *   ChecksumSHA256?: string,\n     *   RequestPayer?: RequestPayer::*,\n     *   ExpectedBucketOwner?: string,\n     *   SSECustomerAlgorithm?: string,\n     *   SSECustomerKey?: string,\n     *   SSECustomerKeyMD5?: string,\n     *\n     *   @region?: string,\n     * } $input\n     */\n    public function __construct(array $input = [])\n    {\n        $this->bucket = $input['Bucket'] ?? null;\n        $this->key = $input['Key'] ?? null;\n        $this->multipartUpload = isset($input['MultipartUpload']) ? CompletedMultipartUpload::create($input['MultipartUpload']) : null;\n        $this->uploadId = $input['UploadId'] ?? null;\n        $this->checksumCrc32 = $input['ChecksumCRC32'] ?? null;\n        $this->checksumCrc32C = $input['ChecksumCRC32C'] ?? null;\n        $this->checksumSha1 = $input['ChecksumSHA1'] ?? null;\n        $this->checksumSha256 = $input['ChecksumSHA256'] ?? null;\n        $this->requestPayer = $input['RequestPayer'] ?? null;\n        $this->expectedBucketOwner = $input['ExpectedBucketOwner'] ?? null;\n        $this->sseCustomerAlgorithm = $input['SSECustomerAlgorithm'] ?? null;\n        $this->sseCustomerKey = $input['SSECustomerKey'] ?? null;\n        $this->sseCustomerKeyMd5 = $input['SSECustomerKeyMD5'] ?? null;\n        parent::__construct($input);\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    public function getBucket(): ?string\n    {\n        return $this->bucket;\n    }\n\n    public function getChecksumCrc32(): ?string\n    {\n        return $this->checksumCrc32;\n    }\n\n    public function getChecksumCrc32C(): ?string\n    {\n        return $this->checksumCrc32C;\n    }\n\n    public function getChecksumSha1(): ?string\n    {\n        return $this->checksumSha1;\n    }\n\n    public function getChecksumSha256(): ?string\n    {\n        return $this->checksumSha256;\n    }\n\n    public function getExpectedBucketOwner(): ?string\n    {\n        return $this->expectedBucketOwner;\n    }\n\n    public function getKey(): ?string\n    {\n        return $this->key;\n    }\n\n    public function getMultipartUpload(): ?CompletedMultipartUpload\n    {\n        return $this->multipartUpload;\n    }\n\n    /**\n     * @return RequestPayer::*|null\n     */\n    public function getRequestPayer(): ?string\n    {\n        return $this->requestPayer;\n    }\n\n    public function getSseCustomerAlgorithm(): ?string\n    {\n        return $this->sseCustomerAlgorithm;\n    }\n\n    public function getSseCustomerKey(): ?string\n    {\n        return $this->sseCustomerKey;\n    }\n\n    public function getSseCustomerKeyMd5(): ?string\n    {\n        return $this->sseCustomerKeyMd5;\n    }\n\n    public function getUploadId(): ?string\n    {\n        return $this->uploadId;\n    }\n\n    /**\n     * @internal\n     */\n    public function request(): Request\n    {\n        // Prepare headers\n        $headers = ['content-type' => 'application/xml'];\n        if (null !== $this->checksumCrc32) {\n            $headers['x-amz-checksum-crc32'] = $this->checksumCrc32;\n        }\n        if (null !== $this->checksumCrc32C) {\n            $headers['x-amz-checksum-crc32c'] = $this->checksumCrc32C;\n        }\n        if (null !== $this->checksumSha1) {\n            $headers['x-amz-checksum-sha1'] = $this->checksumSha1;\n        }\n        if (null !== $this->checksumSha256) {\n            $headers['x-amz-checksum-sha256'] = $this->checksumSha256;\n        }\n        if (null !== $this->requestPayer) {\n            if (!RequestPayer::exists($this->requestPayer)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"RequestPayer\" for \"%s\". The value \"%s\" is not a valid \"RequestPayer\".', __CLASS__, $this->requestPayer));\n            }\n            $headers['x-amz-request-payer'] = $this->requestPayer;\n        }\n        if (null !== $this->expectedBucketOwner) {\n            $headers['x-amz-expected-bucket-owner'] = $this->expectedBucketOwner;\n        }\n        if (null !== $this->sseCustomerAlgorithm) {\n            $headers['x-amz-server-side-encryption-customer-algorithm'] = $this->sseCustomerAlgorithm;\n        }\n        if (null !== $this->sseCustomerKey) {\n            $headers['x-amz-server-side-encryption-customer-key'] = $this->sseCustomerKey;\n        }\n        if (null !== $this->sseCustomerKeyMd5) {\n            $headers['x-amz-server-side-encryption-customer-key-MD5'] = $this->sseCustomerKeyMd5;\n        }\n\n        // Prepare query\n        $query = [];\n        if (null === $v = $this->uploadId) {\n            throw new InvalidArgument(sprintf('Missing parameter \"UploadId\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        $query['uploadId'] = $v;\n\n        // Prepare URI\n        $uri = [];\n        if (null === $v = $this->bucket) {\n            throw new InvalidArgument(sprintf('Missing parameter \"Bucket\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        $uri['Bucket'] = $v;\n        if (null === $v = $this->key) {\n            throw new InvalidArgument(sprintf('Missing parameter \"Key\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        $uri['Key'] = $v;\n        $uriString = '/' . rawurlencode($uri['Bucket']) . '/' . str_replace('%2F', '/', rawurlencode($uri['Key']));\n\n        // Prepare Body\n\n        $document = new \\DOMDocument('1.0', 'UTF-8');\n        $document->formatOutput = false;\n        $this->requestBody($document, $document);\n        $body = $document->hasChildNodes() ? $document->saveXML() : '';\n\n        // Return the Request\n        return new Request('POST', $uriString, $query, $headers, StreamFactory::create($body));\n    }\n\n    public function setBucket(?string $value): self\n    {\n        $this->bucket = $value;\n\n        return $this;\n    }\n\n    public function setChecksumCrc32(?string $value): self\n    {\n        $this->checksumCrc32 = $value;\n\n        return $this;\n    }\n\n    public function setChecksumCrc32C(?string $value): self\n    {\n        $this->checksumCrc32C = $value;\n\n        return $this;\n    }\n\n    public function setChecksumSha1(?string $value): self\n    {\n        $this->checksumSha1 = $value;\n\n        return $this;\n    }\n\n    public function setChecksumSha256(?string $value): self\n    {\n        $this->checksumSha256 = $value;\n\n        return $this;\n    }\n\n    public function setExpectedBucketOwner(?string $value): self\n    {\n        $this->expectedBucketOwner = $value;\n\n        return $this;\n    }\n\n    public function setKey(?string $value): self\n    {\n        $this->key = $value;\n\n        return $this;\n    }\n\n    public function setMultipartUpload(?CompletedMultipartUpload $value): self\n    {\n        $this->multipartUpload = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param RequestPayer::*|null $value\n     */\n    public function setRequestPayer(?string $value): self\n    {\n        $this->requestPayer = $value;\n\n        return $this;\n    }\n\n    public function setSseCustomerAlgorithm(?string $value): self\n    {\n        $this->sseCustomerAlgorithm = $value;\n\n        return $this;\n    }\n\n    public function setSseCustomerKey(?string $value): self\n    {\n        $this->sseCustomerKey = $value;\n\n        return $this;\n    }\n\n    public function setSseCustomerKeyMd5(?string $value): self\n    {\n        $this->sseCustomerKeyMd5 = $value;\n\n        return $this;\n    }\n\n    public function setUploadId(?string $value): self\n    {\n        $this->uploadId = $value;\n\n        return $this;\n    }\n\n    private function requestBody(\\DOMNode $node, \\DOMDocument $document): void\n    {\n        if (null !== $v = $this->multipartUpload) {\n            $node->appendChild($child = $document->createElement('CompleteMultipartUpload'));\n            $child->setAttribute('xmlns', 'http://s3.amazonaws.com/doc/2006-03-01/');\n            $v->requestBody($child, $document);\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Input/CopyObjectRequest.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Input;\n\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\nuse AsyncAws\\Core\\Input;\nuse AsyncAws\\Core\\Request;\nuse AsyncAws\\Core\\Stream\\StreamFactory;\nuse AsyncAws\\S3\\Enum\\ChecksumAlgorithm;\nuse AsyncAws\\S3\\Enum\\MetadataDirective;\nuse AsyncAws\\S3\\Enum\\ObjectCannedACL;\nuse AsyncAws\\S3\\Enum\\ObjectLockLegalHoldStatus;\nuse AsyncAws\\S3\\Enum\\ObjectLockMode;\nuse AsyncAws\\S3\\Enum\\RequestPayer;\nuse AsyncAws\\S3\\Enum\\ServerSideEncryption;\nuse AsyncAws\\S3\\Enum\\StorageClass;\nuse AsyncAws\\S3\\Enum\\TaggingDirective;\n\nfinal class CopyObjectRequest extends Input\n{\n    /**\n     * The canned ACL to apply to the object.\n     *\n     * This action is not supported by Amazon S3 on Outposts.\n     *\n     * @var ObjectCannedACL::*|null\n     */\n    private $acl;\n\n    /**\n     * The name of the destination bucket.\n     *\n     * When using this action with an access point, you must direct requests to the access point hostname. The access point\n     * hostname takes the form *AccessPointName*-*AccountId*.s3-accesspoint.*Region*.amazonaws.com. When using this action\n     * with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket\n     * name. For more information about access point ARNs, see Using access points [^1] in the *Amazon S3 User Guide*.\n     *\n     * When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3\n     * on Outposts hostname takes the form `*AccessPointName*-*AccountId*.*outpostID*.s3-outposts.*Region*.amazonaws.com`.\n     * When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access\n     * point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts\n     * [^2] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html\n     * [^2]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html\n     *\n     * @required\n     *\n     * @var string|null\n     */\n    private $bucket;\n\n    /**\n     * Specifies caching behavior along the request/reply chain.\n     *\n     * @var string|null\n     */\n    private $cacheControl;\n\n    /**\n     * Indicates the algorithm you want Amazon S3 to use to create the checksum for the object. For more information, see\n     * Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html\n     *\n     * @var ChecksumAlgorithm::*|null\n     */\n    private $checksumAlgorithm;\n\n    /**\n     * Specifies presentational information for the object.\n     *\n     * @var string|null\n     */\n    private $contentDisposition;\n\n    /**\n     * Specifies what content encodings have been applied to the object and thus what decoding mechanisms must be applied to\n     * obtain the media-type referenced by the Content-Type header field.\n     *\n     * @var string|null\n     */\n    private $contentEncoding;\n\n    /**\n     * The language the content is in.\n     *\n     * @var string|null\n     */\n    private $contentLanguage;\n\n    /**\n     * A standard MIME type describing the format of the object data.\n     *\n     * @var string|null\n     */\n    private $contentType;\n\n    /**\n     * Specifies the source object for the copy operation. You specify the value in one of two formats, depending on whether\n     * you want to access the source object through an access point [^1]:.\n     *\n     * - For objects not accessed through an access point, specify the name of the source bucket and the key of the source\n     *   object, separated by a slash (/). For example, to copy the object `reports/january.pdf` from the bucket\n     *   `awsexamplebucket`, use `awsexamplebucket/reports/january.pdf`. The value must be URL-encoded.\n     * - For objects accessed through access points, specify the Amazon Resource Name (ARN) of the object as accessed\n     *   through the access point, in the format\n     *   `arn:aws:s3:<Region>:<account-id>:accesspoint/<access-point-name>/object/<key>`. For\n     *   example, to copy the object `reports/january.pdf` through access point `my-access-point` owned by account\n     *   `123456789012` in Region `us-west-2`, use the URL encoding of\n     *   `arn:aws:s3:us-west-2:123456789012:accesspoint/my-access-point/object/reports/january.pdf`. The value must be URL\n     *   encoded.\n     *\n     *   > Amazon S3 supports copy operations using access points only when the source and destination buckets are in the\n     *   > same Amazon Web Services Region.\n     *\n     *   Alternatively, for objects accessed through Amazon S3 on Outposts, specify the ARN of the object as accessed in the\n     *   format `arn:aws:s3-outposts:<Region>:<account-id>:outpost/<outpost-id>/object/<key>`. For\n     *   example, to copy the object `reports/january.pdf` through outpost `my-outpost` owned by account `123456789012` in\n     *   Region `us-west-2`, use the URL encoding of\n     *   `arn:aws:s3-outposts:us-west-2:123456789012:outpost/my-outpost/object/reports/january.pdf`. The value must be\n     *   URL-encoded.\n     *\n     * To copy a specific version of an object, append `?versionId=<version-id>` to the value (for example,\n     * `awsexamplebucket/reports/january.pdf?versionId=QUpfdndhfd8438MNFDN93jdnJFkdmqnh893`). If you don't specify a version\n     * ID, Amazon S3 copies the latest version of the source object.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-points.html\n     *\n     * @required\n     *\n     * @var string|null\n     */\n    private $copySource;\n\n    /**\n     * Copies the object if its entity tag (ETag) matches the specified tag.\n     *\n     * @var string|null\n     */\n    private $copySourceIfMatch;\n\n    /**\n     * Copies the object if it has been modified since the specified time.\n     *\n     * @var \\DateTimeImmutable|null\n     */\n    private $copySourceIfModifiedSince;\n\n    /**\n     * Copies the object if its entity tag (ETag) is different than the specified ETag.\n     *\n     * @var string|null\n     */\n    private $copySourceIfNoneMatch;\n\n    /**\n     * Copies the object if it hasn't been modified since the specified time.\n     *\n     * @var \\DateTimeImmutable|null\n     */\n    private $copySourceIfUnmodifiedSince;\n\n    /**\n     * The date and time at which the object is no longer cacheable.\n     *\n     * @var \\DateTimeImmutable|null\n     */\n    private $expires;\n\n    /**\n     * Gives the grantee READ, READ_ACP, and WRITE_ACP permissions on the object.\n     *\n     * This action is not supported by Amazon S3 on Outposts.\n     *\n     * @var string|null\n     */\n    private $grantFullControl;\n\n    /**\n     * Allows grantee to read the object data and its metadata.\n     *\n     * This action is not supported by Amazon S3 on Outposts.\n     *\n     * @var string|null\n     */\n    private $grantRead;\n\n    /**\n     * Allows grantee to read the object ACL.\n     *\n     * This action is not supported by Amazon S3 on Outposts.\n     *\n     * @var string|null\n     */\n    private $grantReadAcp;\n\n    /**\n     * Allows grantee to write the ACL for the applicable object.\n     *\n     * This action is not supported by Amazon S3 on Outposts.\n     *\n     * @var string|null\n     */\n    private $grantWriteAcp;\n\n    /**\n     * The key of the destination object.\n     *\n     * @required\n     *\n     * @var string|null\n     */\n    private $key;\n\n    /**\n     * A map of metadata to store with the object in S3.\n     *\n     * @var array<string, string>|null\n     */\n    private $metadata;\n\n    /**\n     * Specifies whether the metadata is copied from the source object or replaced with metadata provided in the request.\n     *\n     * @var MetadataDirective::*|null\n     */\n    private $metadataDirective;\n\n    /**\n     * Specifies whether the object tag-set are copied from the source object or replaced with tag-set provided in the\n     * request.\n     *\n     * @var TaggingDirective::*|null\n     */\n    private $taggingDirective;\n\n    /**\n     * The server-side encryption algorithm used when storing this object in Amazon S3 (for example, `AES256`, `aws:kms`,\n     * `aws:kms:dsse`).\n     *\n     * @var ServerSideEncryption::*|null\n     */\n    private $serverSideEncryption;\n\n    /**\n     * By default, Amazon S3 uses the STANDARD Storage Class to store newly created objects. The STANDARD storage class\n     * provides high durability and high availability. Depending on performance needs, you can specify a different Storage\n     * Class. Amazon S3 on Outposts only uses the OUTPOSTS Storage Class. For more information, see Storage Classes [^1] in\n     * the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/dev/storage-class-intro.html\n     *\n     * @var StorageClass::*|null\n     */\n    private $storageClass;\n\n    /**\n     * If the bucket is configured as a website, redirects requests for this object to another object in the same bucket or\n     * to an external URL. Amazon S3 stores the value of this header in the object metadata. This value is unique to each\n     * object and is not copied when using the `x-amz-metadata-directive` header. Instead, you may opt to provide this\n     * header in combination with the directive.\n     *\n     * @var string|null\n     */\n    private $websiteRedirectLocation;\n\n    /**\n     * Specifies the algorithm to use to when encrypting the object (for example, AES256).\n     *\n     * @var string|null\n     */\n    private $sseCustomerAlgorithm;\n\n    /**\n     * Specifies the customer-provided encryption key for Amazon S3 to use in encrypting data. This value is used to store\n     * the object and then it is discarded; Amazon S3 does not store the encryption key. The key must be appropriate for use\n     * with the algorithm specified in the `x-amz-server-side-encryption-customer-algorithm` header.\n     *\n     * @var string|null\n     */\n    private $sseCustomerKey;\n\n    /**\n     * Specifies the 128-bit MD5 digest of the encryption key according to RFC 1321. Amazon S3 uses this header for a\n     * message integrity check to ensure that the encryption key was transmitted without error.\n     *\n     * @var string|null\n     */\n    private $sseCustomerKeyMd5;\n\n    /**\n     * Specifies the KMS key ID to use for object encryption. All GET and PUT requests for an object protected by KMS will\n     * fail if they're not made via SSL or using SigV4. For information about configuring any of the officially supported\n     * Amazon Web Services SDKs and Amazon Web Services CLI, see Specifying the Signature Version in Request Authentication\n     * [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingAWSSDK.html#specify-signature-version\n     *\n     * @var string|null\n     */\n    private $sseKmsKeyId;\n\n    /**\n     * Specifies the Amazon Web Services KMS Encryption Context to use for object encryption. The value of this header is a\n     * base64-encoded UTF-8 string holding JSON with the encryption context key-value pairs.\n     *\n     * @var string|null\n     */\n    private $sseKmsEncryptionContext;\n\n    /**\n     * Specifies whether Amazon S3 should use an S3 Bucket Key for object encryption with server-side encryption using Key\n     * Management Service (KMS) keys (SSE-KMS). Setting this header to `true` causes Amazon S3 to use an S3 Bucket Key for\n     * object encryption with SSE-KMS.\n     *\n     * Specifying this header with a COPY action doesn’t affect bucket-level settings for S3 Bucket Key.\n     *\n     * @var bool|null\n     */\n    private $bucketKeyEnabled;\n\n    /**\n     * Specifies the algorithm to use when decrypting the source object (for example, AES256).\n     *\n     * @var string|null\n     */\n    private $copySourceSseCustomerAlgorithm;\n\n    /**\n     * Specifies the customer-provided encryption key for Amazon S3 to use to decrypt the source object. The encryption key\n     * provided in this header must be one that was used when the source object was created.\n     *\n     * @var string|null\n     */\n    private $copySourceSseCustomerKey;\n\n    /**\n     * Specifies the 128-bit MD5 digest of the encryption key according to RFC 1321. Amazon S3 uses this header for a\n     * message integrity check to ensure that the encryption key was transmitted without error.\n     *\n     * @var string|null\n     */\n    private $copySourceSseCustomerKeyMd5;\n\n    /**\n     * @var RequestPayer::*|null\n     */\n    private $requestPayer;\n\n    /**\n     * The tag-set for the object destination object this value must be used in conjunction with the `TaggingDirective`. The\n     * tag-set must be encoded as URL Query parameters.\n     *\n     * @var string|null\n     */\n    private $tagging;\n\n    /**\n     * The Object Lock mode that you want to apply to the copied object.\n     *\n     * @var ObjectLockMode::*|null\n     */\n    private $objectLockMode;\n\n    /**\n     * The date and time when you want the copied object's Object Lock to expire.\n     *\n     * @var \\DateTimeImmutable|null\n     */\n    private $objectLockRetainUntilDate;\n\n    /**\n     * Specifies whether you want to apply a legal hold to the copied object.\n     *\n     * @var ObjectLockLegalHoldStatus::*|null\n     */\n    private $objectLockLegalHoldStatus;\n\n    /**\n     * The account ID of the expected destination bucket owner. If the destination bucket is owned by a different account,\n     * the request fails with the HTTP status code `403 Forbidden` (access denied).\n     *\n     * @var string|null\n     */\n    private $expectedBucketOwner;\n\n    /**\n     * The account ID of the expected source bucket owner. If the source bucket is owned by a different account, the request\n     * fails with the HTTP status code `403 Forbidden` (access denied).\n     *\n     * @var string|null\n     */\n    private $expectedSourceBucketOwner;\n\n    /**\n     * @param array{\n     *   ACL?: ObjectCannedACL::*,\n     *   Bucket?: string,\n     *   CacheControl?: string,\n     *   ChecksumAlgorithm?: ChecksumAlgorithm::*,\n     *   ContentDisposition?: string,\n     *   ContentEncoding?: string,\n     *   ContentLanguage?: string,\n     *   ContentType?: string,\n     *   CopySource?: string,\n     *   CopySourceIfMatch?: string,\n     *   CopySourceIfModifiedSince?: \\DateTimeImmutable|string,\n     *   CopySourceIfNoneMatch?: string,\n     *   CopySourceIfUnmodifiedSince?: \\DateTimeImmutable|string,\n     *   Expires?: \\DateTimeImmutable|string,\n     *   GrantFullControl?: string,\n     *   GrantRead?: string,\n     *   GrantReadACP?: string,\n     *   GrantWriteACP?: string,\n     *   Key?: string,\n     *   Metadata?: array<string, string>,\n     *   MetadataDirective?: MetadataDirective::*,\n     *   TaggingDirective?: TaggingDirective::*,\n     *   ServerSideEncryption?: ServerSideEncryption::*,\n     *   StorageClass?: StorageClass::*,\n     *   WebsiteRedirectLocation?: string,\n     *   SSECustomerAlgorithm?: string,\n     *   SSECustomerKey?: string,\n     *   SSECustomerKeyMD5?: string,\n     *   SSEKMSKeyId?: string,\n     *   SSEKMSEncryptionContext?: string,\n     *   BucketKeyEnabled?: bool,\n     *   CopySourceSSECustomerAlgorithm?: string,\n     *   CopySourceSSECustomerKey?: string,\n     *   CopySourceSSECustomerKeyMD5?: string,\n     *   RequestPayer?: RequestPayer::*,\n     *   Tagging?: string,\n     *   ObjectLockMode?: ObjectLockMode::*,\n     *   ObjectLockRetainUntilDate?: \\DateTimeImmutable|string,\n     *   ObjectLockLegalHoldStatus?: ObjectLockLegalHoldStatus::*,\n     *   ExpectedBucketOwner?: string,\n     *   ExpectedSourceBucketOwner?: string,\n     *\n     *   @region?: string,\n     * } $input\n     */\n    public function __construct(array $input = [])\n    {\n        $this->acl = $input['ACL'] ?? null;\n        $this->bucket = $input['Bucket'] ?? null;\n        $this->cacheControl = $input['CacheControl'] ?? null;\n        $this->checksumAlgorithm = $input['ChecksumAlgorithm'] ?? null;\n        $this->contentDisposition = $input['ContentDisposition'] ?? null;\n        $this->contentEncoding = $input['ContentEncoding'] ?? null;\n        $this->contentLanguage = $input['ContentLanguage'] ?? null;\n        $this->contentType = $input['ContentType'] ?? null;\n        $this->copySource = $input['CopySource'] ?? null;\n        $this->copySourceIfMatch = $input['CopySourceIfMatch'] ?? null;\n        $this->copySourceIfModifiedSince = !isset($input['CopySourceIfModifiedSince']) ? null : ($input['CopySourceIfModifiedSince'] instanceof \\DateTimeImmutable ? $input['CopySourceIfModifiedSince'] : new \\DateTimeImmutable($input['CopySourceIfModifiedSince']));\n        $this->copySourceIfNoneMatch = $input['CopySourceIfNoneMatch'] ?? null;\n        $this->copySourceIfUnmodifiedSince = !isset($input['CopySourceIfUnmodifiedSince']) ? null : ($input['CopySourceIfUnmodifiedSince'] instanceof \\DateTimeImmutable ? $input['CopySourceIfUnmodifiedSince'] : new \\DateTimeImmutable($input['CopySourceIfUnmodifiedSince']));\n        $this->expires = !isset($input['Expires']) ? null : ($input['Expires'] instanceof \\DateTimeImmutable ? $input['Expires'] : new \\DateTimeImmutable($input['Expires']));\n        $this->grantFullControl = $input['GrantFullControl'] ?? null;\n        $this->grantRead = $input['GrantRead'] ?? null;\n        $this->grantReadAcp = $input['GrantReadACP'] ?? null;\n        $this->grantWriteAcp = $input['GrantWriteACP'] ?? null;\n        $this->key = $input['Key'] ?? null;\n        $this->metadata = $input['Metadata'] ?? null;\n        $this->metadataDirective = $input['MetadataDirective'] ?? null;\n        $this->taggingDirective = $input['TaggingDirective'] ?? null;\n        $this->serverSideEncryption = $input['ServerSideEncryption'] ?? null;\n        $this->storageClass = $input['StorageClass'] ?? null;\n        $this->websiteRedirectLocation = $input['WebsiteRedirectLocation'] ?? null;\n        $this->sseCustomerAlgorithm = $input['SSECustomerAlgorithm'] ?? null;\n        $this->sseCustomerKey = $input['SSECustomerKey'] ?? null;\n        $this->sseCustomerKeyMd5 = $input['SSECustomerKeyMD5'] ?? null;\n        $this->sseKmsKeyId = $input['SSEKMSKeyId'] ?? null;\n        $this->sseKmsEncryptionContext = $input['SSEKMSEncryptionContext'] ?? null;\n        $this->bucketKeyEnabled = $input['BucketKeyEnabled'] ?? null;\n        $this->copySourceSseCustomerAlgorithm = $input['CopySourceSSECustomerAlgorithm'] ?? null;\n        $this->copySourceSseCustomerKey = $input['CopySourceSSECustomerKey'] ?? null;\n        $this->copySourceSseCustomerKeyMd5 = $input['CopySourceSSECustomerKeyMD5'] ?? null;\n        $this->requestPayer = $input['RequestPayer'] ?? null;\n        $this->tagging = $input['Tagging'] ?? null;\n        $this->objectLockMode = $input['ObjectLockMode'] ?? null;\n        $this->objectLockRetainUntilDate = !isset($input['ObjectLockRetainUntilDate']) ? null : ($input['ObjectLockRetainUntilDate'] instanceof \\DateTimeImmutable ? $input['ObjectLockRetainUntilDate'] : new \\DateTimeImmutable($input['ObjectLockRetainUntilDate']));\n        $this->objectLockLegalHoldStatus = $input['ObjectLockLegalHoldStatus'] ?? null;\n        $this->expectedBucketOwner = $input['ExpectedBucketOwner'] ?? null;\n        $this->expectedSourceBucketOwner = $input['ExpectedSourceBucketOwner'] ?? null;\n        parent::__construct($input);\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    /**\n     * @return ObjectCannedACL::*|null\n     */\n    public function getAcl(): ?string\n    {\n        return $this->acl;\n    }\n\n    public function getBucket(): ?string\n    {\n        return $this->bucket;\n    }\n\n    public function getBucketKeyEnabled(): ?bool\n    {\n        return $this->bucketKeyEnabled;\n    }\n\n    public function getCacheControl(): ?string\n    {\n        return $this->cacheControl;\n    }\n\n    /**\n     * @return ChecksumAlgorithm::*|null\n     */\n    public function getChecksumAlgorithm(): ?string\n    {\n        return $this->checksumAlgorithm;\n    }\n\n    public function getContentDisposition(): ?string\n    {\n        return $this->contentDisposition;\n    }\n\n    public function getContentEncoding(): ?string\n    {\n        return $this->contentEncoding;\n    }\n\n    public function getContentLanguage(): ?string\n    {\n        return $this->contentLanguage;\n    }\n\n    public function getContentType(): ?string\n    {\n        return $this->contentType;\n    }\n\n    public function getCopySource(): ?string\n    {\n        return $this->copySource;\n    }\n\n    public function getCopySourceIfMatch(): ?string\n    {\n        return $this->copySourceIfMatch;\n    }\n\n    public function getCopySourceIfModifiedSince(): ?\\DateTimeImmutable\n    {\n        return $this->copySourceIfModifiedSince;\n    }\n\n    public function getCopySourceIfNoneMatch(): ?string\n    {\n        return $this->copySourceIfNoneMatch;\n    }\n\n    public function getCopySourceIfUnmodifiedSince(): ?\\DateTimeImmutable\n    {\n        return $this->copySourceIfUnmodifiedSince;\n    }\n\n    public function getCopySourceSseCustomerAlgorithm(): ?string\n    {\n        return $this->copySourceSseCustomerAlgorithm;\n    }\n\n    public function getCopySourceSseCustomerKey(): ?string\n    {\n        return $this->copySourceSseCustomerKey;\n    }\n\n    public function getCopySourceSseCustomerKeyMd5(): ?string\n    {\n        return $this->copySourceSseCustomerKeyMd5;\n    }\n\n    public function getExpectedBucketOwner(): ?string\n    {\n        return $this->expectedBucketOwner;\n    }\n\n    public function getExpectedSourceBucketOwner(): ?string\n    {\n        return $this->expectedSourceBucketOwner;\n    }\n\n    public function getExpires(): ?\\DateTimeImmutable\n    {\n        return $this->expires;\n    }\n\n    public function getGrantFullControl(): ?string\n    {\n        return $this->grantFullControl;\n    }\n\n    public function getGrantRead(): ?string\n    {\n        return $this->grantRead;\n    }\n\n    public function getGrantReadAcp(): ?string\n    {\n        return $this->grantReadAcp;\n    }\n\n    public function getGrantWriteAcp(): ?string\n    {\n        return $this->grantWriteAcp;\n    }\n\n    public function getKey(): ?string\n    {\n        return $this->key;\n    }\n\n    /**\n     * @return array<string, string>\n     */\n    public function getMetadata(): array\n    {\n        return $this->metadata ?? [];\n    }\n\n    /**\n     * @return MetadataDirective::*|null\n     */\n    public function getMetadataDirective(): ?string\n    {\n        return $this->metadataDirective;\n    }\n\n    /**\n     * @return ObjectLockLegalHoldStatus::*|null\n     */\n    public function getObjectLockLegalHoldStatus(): ?string\n    {\n        return $this->objectLockLegalHoldStatus;\n    }\n\n    /**\n     * @return ObjectLockMode::*|null\n     */\n    public function getObjectLockMode(): ?string\n    {\n        return $this->objectLockMode;\n    }\n\n    public function getObjectLockRetainUntilDate(): ?\\DateTimeImmutable\n    {\n        return $this->objectLockRetainUntilDate;\n    }\n\n    /**\n     * @return RequestPayer::*|null\n     */\n    public function getRequestPayer(): ?string\n    {\n        return $this->requestPayer;\n    }\n\n    /**\n     * @return ServerSideEncryption::*|null\n     */\n    public function getServerSideEncryption(): ?string\n    {\n        return $this->serverSideEncryption;\n    }\n\n    public function getSseCustomerAlgorithm(): ?string\n    {\n        return $this->sseCustomerAlgorithm;\n    }\n\n    public function getSseCustomerKey(): ?string\n    {\n        return $this->sseCustomerKey;\n    }\n\n    public function getSseCustomerKeyMd5(): ?string\n    {\n        return $this->sseCustomerKeyMd5;\n    }\n\n    public function getSseKmsEncryptionContext(): ?string\n    {\n        return $this->sseKmsEncryptionContext;\n    }\n\n    public function getSseKmsKeyId(): ?string\n    {\n        return $this->sseKmsKeyId;\n    }\n\n    /**\n     * @return StorageClass::*|null\n     */\n    public function getStorageClass(): ?string\n    {\n        return $this->storageClass;\n    }\n\n    public function getTagging(): ?string\n    {\n        return $this->tagging;\n    }\n\n    /**\n     * @return TaggingDirective::*|null\n     */\n    public function getTaggingDirective(): ?string\n    {\n        return $this->taggingDirective;\n    }\n\n    public function getWebsiteRedirectLocation(): ?string\n    {\n        return $this->websiteRedirectLocation;\n    }\n\n    /**\n     * @internal\n     */\n    public function request(): Request\n    {\n        // Prepare headers\n        $headers = ['content-type' => 'application/xml'];\n        if (null !== $this->acl) {\n            if (!ObjectCannedACL::exists($this->acl)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"ACL\" for \"%s\". The value \"%s\" is not a valid \"ObjectCannedACL\".', __CLASS__, $this->acl));\n            }\n            $headers['x-amz-acl'] = $this->acl;\n        }\n        if (null !== $this->cacheControl) {\n            $headers['Cache-Control'] = $this->cacheControl;\n        }\n        if (null !== $this->checksumAlgorithm) {\n            if (!ChecksumAlgorithm::exists($this->checksumAlgorithm)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"ChecksumAlgorithm\" for \"%s\". The value \"%s\" is not a valid \"ChecksumAlgorithm\".', __CLASS__, $this->checksumAlgorithm));\n            }\n            $headers['x-amz-checksum-algorithm'] = $this->checksumAlgorithm;\n        }\n        if (null !== $this->contentDisposition) {\n            $headers['Content-Disposition'] = $this->contentDisposition;\n        }\n        if (null !== $this->contentEncoding) {\n            $headers['Content-Encoding'] = $this->contentEncoding;\n        }\n        if (null !== $this->contentLanguage) {\n            $headers['Content-Language'] = $this->contentLanguage;\n        }\n        if (null !== $this->contentType) {\n            $headers['Content-Type'] = $this->contentType;\n        }\n        if (null === $v = $this->copySource) {\n            throw new InvalidArgument(sprintf('Missing parameter \"CopySource\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        $headers['x-amz-copy-source'] = $v;\n        if (null !== $this->copySourceIfMatch) {\n            $headers['x-amz-copy-source-if-match'] = $this->copySourceIfMatch;\n        }\n        if (null !== $this->copySourceIfModifiedSince) {\n            $headers['x-amz-copy-source-if-modified-since'] = $this->copySourceIfModifiedSince->setTimezone(new \\DateTimeZone('GMT'))->format(\\DateTimeInterface::RFC7231);\n        }\n        if (null !== $this->copySourceIfNoneMatch) {\n            $headers['x-amz-copy-source-if-none-match'] = $this->copySourceIfNoneMatch;\n        }\n        if (null !== $this->copySourceIfUnmodifiedSince) {\n            $headers['x-amz-copy-source-if-unmodified-since'] = $this->copySourceIfUnmodifiedSince->setTimezone(new \\DateTimeZone('GMT'))->format(\\DateTimeInterface::RFC7231);\n        }\n        if (null !== $this->expires) {\n            $headers['Expires'] = $this->expires->setTimezone(new \\DateTimeZone('GMT'))->format(\\DateTimeInterface::RFC7231);\n        }\n        if (null !== $this->grantFullControl) {\n            $headers['x-amz-grant-full-control'] = $this->grantFullControl;\n        }\n        if (null !== $this->grantRead) {\n            $headers['x-amz-grant-read'] = $this->grantRead;\n        }\n        if (null !== $this->grantReadAcp) {\n            $headers['x-amz-grant-read-acp'] = $this->grantReadAcp;\n        }\n        if (null !== $this->grantWriteAcp) {\n            $headers['x-amz-grant-write-acp'] = $this->grantWriteAcp;\n        }\n        if (null !== $this->metadataDirective) {\n            if (!MetadataDirective::exists($this->metadataDirective)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"MetadataDirective\" for \"%s\". The value \"%s\" is not a valid \"MetadataDirective\".', __CLASS__, $this->metadataDirective));\n            }\n            $headers['x-amz-metadata-directive'] = $this->metadataDirective;\n        }\n        if (null !== $this->taggingDirective) {\n            if (!TaggingDirective::exists($this->taggingDirective)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"TaggingDirective\" for \"%s\". The value \"%s\" is not a valid \"TaggingDirective\".', __CLASS__, $this->taggingDirective));\n            }\n            $headers['x-amz-tagging-directive'] = $this->taggingDirective;\n        }\n        if (null !== $this->serverSideEncryption) {\n            if (!ServerSideEncryption::exists($this->serverSideEncryption)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"ServerSideEncryption\" for \"%s\". The value \"%s\" is not a valid \"ServerSideEncryption\".', __CLASS__, $this->serverSideEncryption));\n            }\n            $headers['x-amz-server-side-encryption'] = $this->serverSideEncryption;\n        }\n        if (null !== $this->storageClass) {\n            if (!StorageClass::exists($this->storageClass)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"StorageClass\" for \"%s\". The value \"%s\" is not a valid \"StorageClass\".', __CLASS__, $this->storageClass));\n            }\n            $headers['x-amz-storage-class'] = $this->storageClass;\n        }\n        if (null !== $this->websiteRedirectLocation) {\n            $headers['x-amz-website-redirect-location'] = $this->websiteRedirectLocation;\n        }\n        if (null !== $this->sseCustomerAlgorithm) {\n            $headers['x-amz-server-side-encryption-customer-algorithm'] = $this->sseCustomerAlgorithm;\n        }\n        if (null !== $this->sseCustomerKey) {\n            $headers['x-amz-server-side-encryption-customer-key'] = $this->sseCustomerKey;\n        }\n        if (null !== $this->sseCustomerKeyMd5) {\n            $headers['x-amz-server-side-encryption-customer-key-MD5'] = $this->sseCustomerKeyMd5;\n        }\n        if (null !== $this->sseKmsKeyId) {\n            $headers['x-amz-server-side-encryption-aws-kms-key-id'] = $this->sseKmsKeyId;\n        }\n        if (null !== $this->sseKmsEncryptionContext) {\n            $headers['x-amz-server-side-encryption-context'] = $this->sseKmsEncryptionContext;\n        }\n        if (null !== $this->bucketKeyEnabled) {\n            $headers['x-amz-server-side-encryption-bucket-key-enabled'] = $this->bucketKeyEnabled ? 'true' : 'false';\n        }\n        if (null !== $this->copySourceSseCustomerAlgorithm) {\n            $headers['x-amz-copy-source-server-side-encryption-customer-algorithm'] = $this->copySourceSseCustomerAlgorithm;\n        }\n        if (null !== $this->copySourceSseCustomerKey) {\n            $headers['x-amz-copy-source-server-side-encryption-customer-key'] = $this->copySourceSseCustomerKey;\n        }\n        if (null !== $this->copySourceSseCustomerKeyMd5) {\n            $headers['x-amz-copy-source-server-side-encryption-customer-key-MD5'] = $this->copySourceSseCustomerKeyMd5;\n        }\n        if (null !== $this->requestPayer) {\n            if (!RequestPayer::exists($this->requestPayer)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"RequestPayer\" for \"%s\". The value \"%s\" is not a valid \"RequestPayer\".', __CLASS__, $this->requestPayer));\n            }\n            $headers['x-amz-request-payer'] = $this->requestPayer;\n        }\n        if (null !== $this->tagging) {\n            $headers['x-amz-tagging'] = $this->tagging;\n        }\n        if (null !== $this->objectLockMode) {\n            if (!ObjectLockMode::exists($this->objectLockMode)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"ObjectLockMode\" for \"%s\". The value \"%s\" is not a valid \"ObjectLockMode\".', __CLASS__, $this->objectLockMode));\n            }\n            $headers['x-amz-object-lock-mode'] = $this->objectLockMode;\n        }\n        if (null !== $this->objectLockRetainUntilDate) {\n            $headers['x-amz-object-lock-retain-until-date'] = $this->objectLockRetainUntilDate->format(\\DateTimeInterface::ISO8601);\n        }\n        if (null !== $this->objectLockLegalHoldStatus) {\n            if (!ObjectLockLegalHoldStatus::exists($this->objectLockLegalHoldStatus)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"ObjectLockLegalHoldStatus\" for \"%s\". The value \"%s\" is not a valid \"ObjectLockLegalHoldStatus\".', __CLASS__, $this->objectLockLegalHoldStatus));\n            }\n            $headers['x-amz-object-lock-legal-hold'] = $this->objectLockLegalHoldStatus;\n        }\n        if (null !== $this->expectedBucketOwner) {\n            $headers['x-amz-expected-bucket-owner'] = $this->expectedBucketOwner;\n        }\n        if (null !== $this->expectedSourceBucketOwner) {\n            $headers['x-amz-source-expected-bucket-owner'] = $this->expectedSourceBucketOwner;\n        }\n        if (null !== $this->metadata) {\n            foreach ($this->metadata as $key => $value) {\n                $headers[\"x-amz-meta-$key\"] = $value;\n            }\n        }\n\n        // Prepare query\n        $query = [];\n\n        // Prepare URI\n        $uri = [];\n        if (null === $v = $this->bucket) {\n            throw new InvalidArgument(sprintf('Missing parameter \"Bucket\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        $uri['Bucket'] = $v;\n        if (null === $v = $this->key) {\n            throw new InvalidArgument(sprintf('Missing parameter \"Key\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        $uri['Key'] = $v;\n        $uriString = '/' . rawurlencode($uri['Bucket']) . '/' . str_replace('%2F', '/', rawurlencode($uri['Key']));\n\n        // Prepare Body\n        $body = '';\n\n        // Return the Request\n        return new Request('PUT', $uriString, $query, $headers, StreamFactory::create($body));\n    }\n\n    /**\n     * @param ObjectCannedACL::*|null $value\n     */\n    public function setAcl(?string $value): self\n    {\n        $this->acl = $value;\n\n        return $this;\n    }\n\n    public function setBucket(?string $value): self\n    {\n        $this->bucket = $value;\n\n        return $this;\n    }\n\n    public function setBucketKeyEnabled(?bool $value): self\n    {\n        $this->bucketKeyEnabled = $value;\n\n        return $this;\n    }\n\n    public function setCacheControl(?string $value): self\n    {\n        $this->cacheControl = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param ChecksumAlgorithm::*|null $value\n     */\n    public function setChecksumAlgorithm(?string $value): self\n    {\n        $this->checksumAlgorithm = $value;\n\n        return $this;\n    }\n\n    public function setContentDisposition(?string $value): self\n    {\n        $this->contentDisposition = $value;\n\n        return $this;\n    }\n\n    public function setContentEncoding(?string $value): self\n    {\n        $this->contentEncoding = $value;\n\n        return $this;\n    }\n\n    public function setContentLanguage(?string $value): self\n    {\n        $this->contentLanguage = $value;\n\n        return $this;\n    }\n\n    public function setContentType(?string $value): self\n    {\n        $this->contentType = $value;\n\n        return $this;\n    }\n\n    public function setCopySource(?string $value): self\n    {\n        $this->copySource = $value;\n\n        return $this;\n    }\n\n    public function setCopySourceIfMatch(?string $value): self\n    {\n        $this->copySourceIfMatch = $value;\n\n        return $this;\n    }\n\n    public function setCopySourceIfModifiedSince(?\\DateTimeImmutable $value): self\n    {\n        $this->copySourceIfModifiedSince = $value;\n\n        return $this;\n    }\n\n    public function setCopySourceIfNoneMatch(?string $value): self\n    {\n        $this->copySourceIfNoneMatch = $value;\n\n        return $this;\n    }\n\n    public function setCopySourceIfUnmodifiedSince(?\\DateTimeImmutable $value): self\n    {\n        $this->copySourceIfUnmodifiedSince = $value;\n\n        return $this;\n    }\n\n    public function setCopySourceSseCustomerAlgorithm(?string $value): self\n    {\n        $this->copySourceSseCustomerAlgorithm = $value;\n\n        return $this;\n    }\n\n    public function setCopySourceSseCustomerKey(?string $value): self\n    {\n        $this->copySourceSseCustomerKey = $value;\n\n        return $this;\n    }\n\n    public function setCopySourceSseCustomerKeyMd5(?string $value): self\n    {\n        $this->copySourceSseCustomerKeyMd5 = $value;\n\n        return $this;\n    }\n\n    public function setExpectedBucketOwner(?string $value): self\n    {\n        $this->expectedBucketOwner = $value;\n\n        return $this;\n    }\n\n    public function setExpectedSourceBucketOwner(?string $value): self\n    {\n        $this->expectedSourceBucketOwner = $value;\n\n        return $this;\n    }\n\n    public function setExpires(?\\DateTimeImmutable $value): self\n    {\n        $this->expires = $value;\n\n        return $this;\n    }\n\n    public function setGrantFullControl(?string $value): self\n    {\n        $this->grantFullControl = $value;\n\n        return $this;\n    }\n\n    public function setGrantRead(?string $value): self\n    {\n        $this->grantRead = $value;\n\n        return $this;\n    }\n\n    public function setGrantReadAcp(?string $value): self\n    {\n        $this->grantReadAcp = $value;\n\n        return $this;\n    }\n\n    public function setGrantWriteAcp(?string $value): self\n    {\n        $this->grantWriteAcp = $value;\n\n        return $this;\n    }\n\n    public function setKey(?string $value): self\n    {\n        $this->key = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param array<string, string> $value\n     */\n    public function setMetadata(array $value): self\n    {\n        $this->metadata = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param MetadataDirective::*|null $value\n     */\n    public function setMetadataDirective(?string $value): self\n    {\n        $this->metadataDirective = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param ObjectLockLegalHoldStatus::*|null $value\n     */\n    public function setObjectLockLegalHoldStatus(?string $value): self\n    {\n        $this->objectLockLegalHoldStatus = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param ObjectLockMode::*|null $value\n     */\n    public function setObjectLockMode(?string $value): self\n    {\n        $this->objectLockMode = $value;\n\n        return $this;\n    }\n\n    public function setObjectLockRetainUntilDate(?\\DateTimeImmutable $value): self\n    {\n        $this->objectLockRetainUntilDate = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param RequestPayer::*|null $value\n     */\n    public function setRequestPayer(?string $value): self\n    {\n        $this->requestPayer = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param ServerSideEncryption::*|null $value\n     */\n    public function setServerSideEncryption(?string $value): self\n    {\n        $this->serverSideEncryption = $value;\n\n        return $this;\n    }\n\n    public function setSseCustomerAlgorithm(?string $value): self\n    {\n        $this->sseCustomerAlgorithm = $value;\n\n        return $this;\n    }\n\n    public function setSseCustomerKey(?string $value): self\n    {\n        $this->sseCustomerKey = $value;\n\n        return $this;\n    }\n\n    public function setSseCustomerKeyMd5(?string $value): self\n    {\n        $this->sseCustomerKeyMd5 = $value;\n\n        return $this;\n    }\n\n    public function setSseKmsEncryptionContext(?string $value): self\n    {\n        $this->sseKmsEncryptionContext = $value;\n\n        return $this;\n    }\n\n    public function setSseKmsKeyId(?string $value): self\n    {\n        $this->sseKmsKeyId = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param StorageClass::*|null $value\n     */\n    public function setStorageClass(?string $value): self\n    {\n        $this->storageClass = $value;\n\n        return $this;\n    }\n\n    public function setTagging(?string $value): self\n    {\n        $this->tagging = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param TaggingDirective::*|null $value\n     */\n    public function setTaggingDirective(?string $value): self\n    {\n        $this->taggingDirective = $value;\n\n        return $this;\n    }\n\n    public function setWebsiteRedirectLocation(?string $value): self\n    {\n        $this->websiteRedirectLocation = $value;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Input/CreateBucketRequest.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Input;\n\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\nuse AsyncAws\\Core\\Input;\nuse AsyncAws\\Core\\Request;\nuse AsyncAws\\Core\\Stream\\StreamFactory;\nuse AsyncAws\\S3\\Enum\\BucketCannedACL;\nuse AsyncAws\\S3\\Enum\\ObjectOwnership;\nuse AsyncAws\\S3\\ValueObject\\CreateBucketConfiguration;\n\nfinal class CreateBucketRequest extends Input\n{\n    /**\n     * The canned ACL to apply to the bucket.\n     *\n     * @var BucketCannedACL::*|null\n     */\n    private $acl;\n\n    /**\n     * The name of the bucket to create.\n     *\n     * @required\n     *\n     * @var string|null\n     */\n    private $bucket;\n\n    /**\n     * The configuration information for the bucket.\n     *\n     * @var CreateBucketConfiguration|null\n     */\n    private $createBucketConfiguration;\n\n    /**\n     * Allows grantee the read, write, read ACP, and write ACP permissions on the bucket.\n     *\n     * @var string|null\n     */\n    private $grantFullControl;\n\n    /**\n     * Allows grantee to list the objects in the bucket.\n     *\n     * @var string|null\n     */\n    private $grantRead;\n\n    /**\n     * Allows grantee to read the bucket ACL.\n     *\n     * @var string|null\n     */\n    private $grantReadAcp;\n\n    /**\n     * Allows grantee to create new objects in the bucket.\n     *\n     * For the bucket and object owners of existing objects, also allows deletions and overwrites of those objects.\n     *\n     * @var string|null\n     */\n    private $grantWrite;\n\n    /**\n     * Allows grantee to write the ACL for the applicable bucket.\n     *\n     * @var string|null\n     */\n    private $grantWriteAcp;\n\n    /**\n     * Specifies whether you want S3 Object Lock to be enabled for the new bucket.\n     *\n     * @var bool|null\n     */\n    private $objectLockEnabledForBucket;\n\n    /**\n     * @var ObjectOwnership::*|null\n     */\n    private $objectOwnership;\n\n    /**\n     * @param array{\n     *   ACL?: BucketCannedACL::*,\n     *   Bucket?: string,\n     *   CreateBucketConfiguration?: CreateBucketConfiguration|array,\n     *   GrantFullControl?: string,\n     *   GrantRead?: string,\n     *   GrantReadACP?: string,\n     *   GrantWrite?: string,\n     *   GrantWriteACP?: string,\n     *   ObjectLockEnabledForBucket?: bool,\n     *   ObjectOwnership?: ObjectOwnership::*,\n     *\n     *   @region?: string,\n     * } $input\n     */\n    public function __construct(array $input = [])\n    {\n        $this->acl = $input['ACL'] ?? null;\n        $this->bucket = $input['Bucket'] ?? null;\n        $this->createBucketConfiguration = isset($input['CreateBucketConfiguration']) ? CreateBucketConfiguration::create($input['CreateBucketConfiguration']) : null;\n        $this->grantFullControl = $input['GrantFullControl'] ?? null;\n        $this->grantRead = $input['GrantRead'] ?? null;\n        $this->grantReadAcp = $input['GrantReadACP'] ?? null;\n        $this->grantWrite = $input['GrantWrite'] ?? null;\n        $this->grantWriteAcp = $input['GrantWriteACP'] ?? null;\n        $this->objectLockEnabledForBucket = $input['ObjectLockEnabledForBucket'] ?? null;\n        $this->objectOwnership = $input['ObjectOwnership'] ?? null;\n        parent::__construct($input);\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    /**\n     * @return BucketCannedACL::*|null\n     */\n    public function getAcl(): ?string\n    {\n        return $this->acl;\n    }\n\n    public function getBucket(): ?string\n    {\n        return $this->bucket;\n    }\n\n    public function getCreateBucketConfiguration(): ?CreateBucketConfiguration\n    {\n        return $this->createBucketConfiguration;\n    }\n\n    public function getGrantFullControl(): ?string\n    {\n        return $this->grantFullControl;\n    }\n\n    public function getGrantRead(): ?string\n    {\n        return $this->grantRead;\n    }\n\n    public function getGrantReadAcp(): ?string\n    {\n        return $this->grantReadAcp;\n    }\n\n    public function getGrantWrite(): ?string\n    {\n        return $this->grantWrite;\n    }\n\n    public function getGrantWriteAcp(): ?string\n    {\n        return $this->grantWriteAcp;\n    }\n\n    public function getObjectLockEnabledForBucket(): ?bool\n    {\n        return $this->objectLockEnabledForBucket;\n    }\n\n    /**\n     * @return ObjectOwnership::*|null\n     */\n    public function getObjectOwnership(): ?string\n    {\n        return $this->objectOwnership;\n    }\n\n    /**\n     * @internal\n     */\n    public function request(): Request\n    {\n        // Prepare headers\n        $headers = ['content-type' => 'application/xml'];\n        if (null !== $this->acl) {\n            if (!BucketCannedACL::exists($this->acl)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"ACL\" for \"%s\". The value \"%s\" is not a valid \"BucketCannedACL\".', __CLASS__, $this->acl));\n            }\n            $headers['x-amz-acl'] = $this->acl;\n        }\n        if (null !== $this->grantFullControl) {\n            $headers['x-amz-grant-full-control'] = $this->grantFullControl;\n        }\n        if (null !== $this->grantRead) {\n            $headers['x-amz-grant-read'] = $this->grantRead;\n        }\n        if (null !== $this->grantReadAcp) {\n            $headers['x-amz-grant-read-acp'] = $this->grantReadAcp;\n        }\n        if (null !== $this->grantWrite) {\n            $headers['x-amz-grant-write'] = $this->grantWrite;\n        }\n        if (null !== $this->grantWriteAcp) {\n            $headers['x-amz-grant-write-acp'] = $this->grantWriteAcp;\n        }\n        if (null !== $this->objectLockEnabledForBucket) {\n            $headers['x-amz-bucket-object-lock-enabled'] = $this->objectLockEnabledForBucket ? 'true' : 'false';\n        }\n        if (null !== $this->objectOwnership) {\n            if (!ObjectOwnership::exists($this->objectOwnership)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"ObjectOwnership\" for \"%s\". The value \"%s\" is not a valid \"ObjectOwnership\".', __CLASS__, $this->objectOwnership));\n            }\n            $headers['x-amz-object-ownership'] = $this->objectOwnership;\n        }\n\n        // Prepare query\n        $query = [];\n\n        // Prepare URI\n        $uri = [];\n        if (null === $v = $this->bucket) {\n            throw new InvalidArgument(sprintf('Missing parameter \"Bucket\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        $uri['Bucket'] = $v;\n        $uriString = '/' . rawurlencode($uri['Bucket']);\n\n        // Prepare Body\n\n        $document = new \\DOMDocument('1.0', 'UTF-8');\n        $document->formatOutput = false;\n        $this->requestBody($document, $document);\n        $body = $document->hasChildNodes() ? $document->saveXML() : '';\n\n        // Return the Request\n        return new Request('PUT', $uriString, $query, $headers, StreamFactory::create($body));\n    }\n\n    /**\n     * @param BucketCannedACL::*|null $value\n     */\n    public function setAcl(?string $value): self\n    {\n        $this->acl = $value;\n\n        return $this;\n    }\n\n    public function setBucket(?string $value): self\n    {\n        $this->bucket = $value;\n\n        return $this;\n    }\n\n    public function setCreateBucketConfiguration(?CreateBucketConfiguration $value): self\n    {\n        $this->createBucketConfiguration = $value;\n\n        return $this;\n    }\n\n    public function setGrantFullControl(?string $value): self\n    {\n        $this->grantFullControl = $value;\n\n        return $this;\n    }\n\n    public function setGrantRead(?string $value): self\n    {\n        $this->grantRead = $value;\n\n        return $this;\n    }\n\n    public function setGrantReadAcp(?string $value): self\n    {\n        $this->grantReadAcp = $value;\n\n        return $this;\n    }\n\n    public function setGrantWrite(?string $value): self\n    {\n        $this->grantWrite = $value;\n\n        return $this;\n    }\n\n    public function setGrantWriteAcp(?string $value): self\n    {\n        $this->grantWriteAcp = $value;\n\n        return $this;\n    }\n\n    public function setObjectLockEnabledForBucket(?bool $value): self\n    {\n        $this->objectLockEnabledForBucket = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param ObjectOwnership::*|null $value\n     */\n    public function setObjectOwnership(?string $value): self\n    {\n        $this->objectOwnership = $value;\n\n        return $this;\n    }\n\n    private function requestBody(\\DOMNode $node, \\DOMDocument $document): void\n    {\n        if (null !== $v = $this->createBucketConfiguration) {\n            $node->appendChild($child = $document->createElement('CreateBucketConfiguration'));\n            $child->setAttribute('xmlns', 'http://s3.amazonaws.com/doc/2006-03-01/');\n            $v->requestBody($child, $document);\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Input/CreateMultipartUploadRequest.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Input;\n\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\nuse AsyncAws\\Core\\Input;\nuse AsyncAws\\Core\\Request;\nuse AsyncAws\\Core\\Stream\\StreamFactory;\nuse AsyncAws\\S3\\Enum\\ChecksumAlgorithm;\nuse AsyncAws\\S3\\Enum\\ObjectCannedACL;\nuse AsyncAws\\S3\\Enum\\ObjectLockLegalHoldStatus;\nuse AsyncAws\\S3\\Enum\\ObjectLockMode;\nuse AsyncAws\\S3\\Enum\\RequestPayer;\nuse AsyncAws\\S3\\Enum\\ServerSideEncryption;\nuse AsyncAws\\S3\\Enum\\StorageClass;\n\nfinal class CreateMultipartUploadRequest extends Input\n{\n    /**\n     * The canned ACL to apply to the object.\n     *\n     * This action is not supported by Amazon S3 on Outposts.\n     *\n     * @var ObjectCannedACL::*|null\n     */\n    private $acl;\n\n    /**\n     * The name of the bucket to which to initiate the upload.\n     *\n     * When using this action with an access point, you must direct requests to the access point hostname. The access point\n     * hostname takes the form *AccessPointName*-*AccountId*.s3-accesspoint.*Region*.amazonaws.com. When using this action\n     * with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket\n     * name. For more information about access point ARNs, see Using access points [^1] in the *Amazon S3 User Guide*.\n     *\n     * When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3\n     * on Outposts hostname takes the form `*AccessPointName*-*AccountId*.*outpostID*.s3-outposts.*Region*.amazonaws.com`.\n     * When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access\n     * point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts\n     * [^2] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html\n     * [^2]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html\n     *\n     * @required\n     *\n     * @var string|null\n     */\n    private $bucket;\n\n    /**\n     * Specifies caching behavior along the request/reply chain.\n     *\n     * @var string|null\n     */\n    private $cacheControl;\n\n    /**\n     * Specifies presentational information for the object.\n     *\n     * @var string|null\n     */\n    private $contentDisposition;\n\n    /**\n     * Specifies what content encodings have been applied to the object and thus what decoding mechanisms must be applied to\n     * obtain the media-type referenced by the Content-Type header field.\n     *\n     * @var string|null\n     */\n    private $contentEncoding;\n\n    /**\n     * The language the content is in.\n     *\n     * @var string|null\n     */\n    private $contentLanguage;\n\n    /**\n     * A standard MIME type describing the format of the object data.\n     *\n     * @var string|null\n     */\n    private $contentType;\n\n    /**\n     * The date and time at which the object is no longer cacheable.\n     *\n     * @var \\DateTimeImmutable|null\n     */\n    private $expires;\n\n    /**\n     * Gives the grantee READ, READ_ACP, and WRITE_ACP permissions on the object.\n     *\n     * This action is not supported by Amazon S3 on Outposts.\n     *\n     * @var string|null\n     */\n    private $grantFullControl;\n\n    /**\n     * Allows grantee to read the object data and its metadata.\n     *\n     * This action is not supported by Amazon S3 on Outposts.\n     *\n     * @var string|null\n     */\n    private $grantRead;\n\n    /**\n     * Allows grantee to read the object ACL.\n     *\n     * This action is not supported by Amazon S3 on Outposts.\n     *\n     * @var string|null\n     */\n    private $grantReadAcp;\n\n    /**\n     * Allows grantee to write the ACL for the applicable object.\n     *\n     * This action is not supported by Amazon S3 on Outposts.\n     *\n     * @var string|null\n     */\n    private $grantWriteAcp;\n\n    /**\n     * Object key for which the multipart upload is to be initiated.\n     *\n     * @required\n     *\n     * @var string|null\n     */\n    private $key;\n\n    /**\n     * A map of metadata to store with the object in S3.\n     *\n     * @var array<string, string>|null\n     */\n    private $metadata;\n\n    /**\n     * The server-side encryption algorithm used when storing this object in Amazon S3 (for example, `AES256`, `aws:kms`).\n     *\n     * @var ServerSideEncryption::*|null\n     */\n    private $serverSideEncryption;\n\n    /**\n     * By default, Amazon S3 uses the STANDARD Storage Class to store newly created objects. The STANDARD storage class\n     * provides high durability and high availability. Depending on performance needs, you can specify a different Storage\n     * Class. Amazon S3 on Outposts only uses the OUTPOSTS Storage Class. For more information, see Storage Classes [^1] in\n     * the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/dev/storage-class-intro.html\n     *\n     * @var StorageClass::*|null\n     */\n    private $storageClass;\n\n    /**\n     * If the bucket is configured as a website, redirects requests for this object to another object in the same bucket or\n     * to an external URL. Amazon S3 stores the value of this header in the object metadata.\n     *\n     * @var string|null\n     */\n    private $websiteRedirectLocation;\n\n    /**\n     * Specifies the algorithm to use to when encrypting the object (for example, AES256).\n     *\n     * @var string|null\n     */\n    private $sseCustomerAlgorithm;\n\n    /**\n     * Specifies the customer-provided encryption key for Amazon S3 to use in encrypting data. This value is used to store\n     * the object and then it is discarded; Amazon S3 does not store the encryption key. The key must be appropriate for use\n     * with the algorithm specified in the `x-amz-server-side-encryption-customer-algorithm` header.\n     *\n     * @var string|null\n     */\n    private $sseCustomerKey;\n\n    /**\n     * Specifies the 128-bit MD5 digest of the encryption key according to RFC 1321. Amazon S3 uses this header for a\n     * message integrity check to ensure that the encryption key was transmitted without error.\n     *\n     * @var string|null\n     */\n    private $sseCustomerKeyMd5;\n\n    /**\n     * Specifies the ID of the symmetric encryption customer managed key to use for object encryption. All GET and PUT\n     * requests for an object protected by KMS will fail if they're not made via SSL or using SigV4. For information about\n     * configuring any of the officially supported Amazon Web Services SDKs and Amazon Web Services CLI, see Specifying the\n     * Signature Version in Request Authentication [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingAWSSDK.html#specify-signature-version\n     *\n     * @var string|null\n     */\n    private $sseKmsKeyId;\n\n    /**\n     * Specifies the Amazon Web Services KMS Encryption Context to use for object encryption. The value of this header is a\n     * base64-encoded UTF-8 string holding JSON with the encryption context key-value pairs.\n     *\n     * @var string|null\n     */\n    private $sseKmsEncryptionContext;\n\n    /**\n     * Specifies whether Amazon S3 should use an S3 Bucket Key for object encryption with server-side encryption using Key\n     * Management Service (KMS) keys (SSE-KMS). Setting this header to `true` causes Amazon S3 to use an S3 Bucket Key for\n     * object encryption with SSE-KMS.\n     *\n     * Specifying this header with an object action doesn’t affect bucket-level settings for S3 Bucket Key.\n     *\n     * @var bool|null\n     */\n    private $bucketKeyEnabled;\n\n    /**\n     * @var RequestPayer::*|null\n     */\n    private $requestPayer;\n\n    /**\n     * The tag-set for the object. The tag-set must be encoded as URL Query parameters.\n     *\n     * @var string|null\n     */\n    private $tagging;\n\n    /**\n     * Specifies the Object Lock mode that you want to apply to the uploaded object.\n     *\n     * @var ObjectLockMode::*|null\n     */\n    private $objectLockMode;\n\n    /**\n     * Specifies the date and time when you want the Object Lock to expire.\n     *\n     * @var \\DateTimeImmutable|null\n     */\n    private $objectLockRetainUntilDate;\n\n    /**\n     * Specifies whether you want to apply a legal hold to the uploaded object.\n     *\n     * @var ObjectLockLegalHoldStatus::*|null\n     */\n    private $objectLockLegalHoldStatus;\n\n    /**\n     * The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with\n     * the HTTP status code `403 Forbidden` (access denied).\n     *\n     * @var string|null\n     */\n    private $expectedBucketOwner;\n\n    /**\n     * Indicates the algorithm you want Amazon S3 to use to create the checksum for the object. For more information, see\n     * Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html\n     *\n     * @var ChecksumAlgorithm::*|null\n     */\n    private $checksumAlgorithm;\n\n    /**\n     * @param array{\n     *   ACL?: ObjectCannedACL::*,\n     *   Bucket?: string,\n     *   CacheControl?: string,\n     *   ContentDisposition?: string,\n     *   ContentEncoding?: string,\n     *   ContentLanguage?: string,\n     *   ContentType?: string,\n     *   Expires?: \\DateTimeImmutable|string,\n     *   GrantFullControl?: string,\n     *   GrantRead?: string,\n     *   GrantReadACP?: string,\n     *   GrantWriteACP?: string,\n     *   Key?: string,\n     *   Metadata?: array<string, string>,\n     *   ServerSideEncryption?: ServerSideEncryption::*,\n     *   StorageClass?: StorageClass::*,\n     *   WebsiteRedirectLocation?: string,\n     *   SSECustomerAlgorithm?: string,\n     *   SSECustomerKey?: string,\n     *   SSECustomerKeyMD5?: string,\n     *   SSEKMSKeyId?: string,\n     *   SSEKMSEncryptionContext?: string,\n     *   BucketKeyEnabled?: bool,\n     *   RequestPayer?: RequestPayer::*,\n     *   Tagging?: string,\n     *   ObjectLockMode?: ObjectLockMode::*,\n     *   ObjectLockRetainUntilDate?: \\DateTimeImmutable|string,\n     *   ObjectLockLegalHoldStatus?: ObjectLockLegalHoldStatus::*,\n     *   ExpectedBucketOwner?: string,\n     *   ChecksumAlgorithm?: ChecksumAlgorithm::*,\n     *\n     *   @region?: string,\n     * } $input\n     */\n    public function __construct(array $input = [])\n    {\n        $this->acl = $input['ACL'] ?? null;\n        $this->bucket = $input['Bucket'] ?? null;\n        $this->cacheControl = $input['CacheControl'] ?? null;\n        $this->contentDisposition = $input['ContentDisposition'] ?? null;\n        $this->contentEncoding = $input['ContentEncoding'] ?? null;\n        $this->contentLanguage = $input['ContentLanguage'] ?? null;\n        $this->contentType = $input['ContentType'] ?? null;\n        $this->expires = !isset($input['Expires']) ? null : ($input['Expires'] instanceof \\DateTimeImmutable ? $input['Expires'] : new \\DateTimeImmutable($input['Expires']));\n        $this->grantFullControl = $input['GrantFullControl'] ?? null;\n        $this->grantRead = $input['GrantRead'] ?? null;\n        $this->grantReadAcp = $input['GrantReadACP'] ?? null;\n        $this->grantWriteAcp = $input['GrantWriteACP'] ?? null;\n        $this->key = $input['Key'] ?? null;\n        $this->metadata = $input['Metadata'] ?? null;\n        $this->serverSideEncryption = $input['ServerSideEncryption'] ?? null;\n        $this->storageClass = $input['StorageClass'] ?? null;\n        $this->websiteRedirectLocation = $input['WebsiteRedirectLocation'] ?? null;\n        $this->sseCustomerAlgorithm = $input['SSECustomerAlgorithm'] ?? null;\n        $this->sseCustomerKey = $input['SSECustomerKey'] ?? null;\n        $this->sseCustomerKeyMd5 = $input['SSECustomerKeyMD5'] ?? null;\n        $this->sseKmsKeyId = $input['SSEKMSKeyId'] ?? null;\n        $this->sseKmsEncryptionContext = $input['SSEKMSEncryptionContext'] ?? null;\n        $this->bucketKeyEnabled = $input['BucketKeyEnabled'] ?? null;\n        $this->requestPayer = $input['RequestPayer'] ?? null;\n        $this->tagging = $input['Tagging'] ?? null;\n        $this->objectLockMode = $input['ObjectLockMode'] ?? null;\n        $this->objectLockRetainUntilDate = !isset($input['ObjectLockRetainUntilDate']) ? null : ($input['ObjectLockRetainUntilDate'] instanceof \\DateTimeImmutable ? $input['ObjectLockRetainUntilDate'] : new \\DateTimeImmutable($input['ObjectLockRetainUntilDate']));\n        $this->objectLockLegalHoldStatus = $input['ObjectLockLegalHoldStatus'] ?? null;\n        $this->expectedBucketOwner = $input['ExpectedBucketOwner'] ?? null;\n        $this->checksumAlgorithm = $input['ChecksumAlgorithm'] ?? null;\n        parent::__construct($input);\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    /**\n     * @return ObjectCannedACL::*|null\n     */\n    public function getAcl(): ?string\n    {\n        return $this->acl;\n    }\n\n    public function getBucket(): ?string\n    {\n        return $this->bucket;\n    }\n\n    public function getBucketKeyEnabled(): ?bool\n    {\n        return $this->bucketKeyEnabled;\n    }\n\n    public function getCacheControl(): ?string\n    {\n        return $this->cacheControl;\n    }\n\n    /**\n     * @return ChecksumAlgorithm::*|null\n     */\n    public function getChecksumAlgorithm(): ?string\n    {\n        return $this->checksumAlgorithm;\n    }\n\n    public function getContentDisposition(): ?string\n    {\n        return $this->contentDisposition;\n    }\n\n    public function getContentEncoding(): ?string\n    {\n        return $this->contentEncoding;\n    }\n\n    public function getContentLanguage(): ?string\n    {\n        return $this->contentLanguage;\n    }\n\n    public function getContentType(): ?string\n    {\n        return $this->contentType;\n    }\n\n    public function getExpectedBucketOwner(): ?string\n    {\n        return $this->expectedBucketOwner;\n    }\n\n    public function getExpires(): ?\\DateTimeImmutable\n    {\n        return $this->expires;\n    }\n\n    public function getGrantFullControl(): ?string\n    {\n        return $this->grantFullControl;\n    }\n\n    public function getGrantRead(): ?string\n    {\n        return $this->grantRead;\n    }\n\n    public function getGrantReadAcp(): ?string\n    {\n        return $this->grantReadAcp;\n    }\n\n    public function getGrantWriteAcp(): ?string\n    {\n        return $this->grantWriteAcp;\n    }\n\n    public function getKey(): ?string\n    {\n        return $this->key;\n    }\n\n    /**\n     * @return array<string, string>\n     */\n    public function getMetadata(): array\n    {\n        return $this->metadata ?? [];\n    }\n\n    /**\n     * @return ObjectLockLegalHoldStatus::*|null\n     */\n    public function getObjectLockLegalHoldStatus(): ?string\n    {\n        return $this->objectLockLegalHoldStatus;\n    }\n\n    /**\n     * @return ObjectLockMode::*|null\n     */\n    public function getObjectLockMode(): ?string\n    {\n        return $this->objectLockMode;\n    }\n\n    public function getObjectLockRetainUntilDate(): ?\\DateTimeImmutable\n    {\n        return $this->objectLockRetainUntilDate;\n    }\n\n    /**\n     * @return RequestPayer::*|null\n     */\n    public function getRequestPayer(): ?string\n    {\n        return $this->requestPayer;\n    }\n\n    /**\n     * @return ServerSideEncryption::*|null\n     */\n    public function getServerSideEncryption(): ?string\n    {\n        return $this->serverSideEncryption;\n    }\n\n    public function getSseCustomerAlgorithm(): ?string\n    {\n        return $this->sseCustomerAlgorithm;\n    }\n\n    public function getSseCustomerKey(): ?string\n    {\n        return $this->sseCustomerKey;\n    }\n\n    public function getSseCustomerKeyMd5(): ?string\n    {\n        return $this->sseCustomerKeyMd5;\n    }\n\n    public function getSseKmsEncryptionContext(): ?string\n    {\n        return $this->sseKmsEncryptionContext;\n    }\n\n    public function getSseKmsKeyId(): ?string\n    {\n        return $this->sseKmsKeyId;\n    }\n\n    /**\n     * @return StorageClass::*|null\n     */\n    public function getStorageClass(): ?string\n    {\n        return $this->storageClass;\n    }\n\n    public function getTagging(): ?string\n    {\n        return $this->tagging;\n    }\n\n    public function getWebsiteRedirectLocation(): ?string\n    {\n        return $this->websiteRedirectLocation;\n    }\n\n    /**\n     * @internal\n     */\n    public function request(): Request\n    {\n        // Prepare headers\n        $headers = ['content-type' => 'application/xml'];\n        if (null !== $this->acl) {\n            if (!ObjectCannedACL::exists($this->acl)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"ACL\" for \"%s\". The value \"%s\" is not a valid \"ObjectCannedACL\".', __CLASS__, $this->acl));\n            }\n            $headers['x-amz-acl'] = $this->acl;\n        }\n        if (null !== $this->cacheControl) {\n            $headers['Cache-Control'] = $this->cacheControl;\n        }\n        if (null !== $this->contentDisposition) {\n            $headers['Content-Disposition'] = $this->contentDisposition;\n        }\n        if (null !== $this->contentEncoding) {\n            $headers['Content-Encoding'] = $this->contentEncoding;\n        }\n        if (null !== $this->contentLanguage) {\n            $headers['Content-Language'] = $this->contentLanguage;\n        }\n        if (null !== $this->contentType) {\n            $headers['Content-Type'] = $this->contentType;\n        }\n        if (null !== $this->expires) {\n            $headers['Expires'] = $this->expires->setTimezone(new \\DateTimeZone('GMT'))->format(\\DateTimeInterface::RFC7231);\n        }\n        if (null !== $this->grantFullControl) {\n            $headers['x-amz-grant-full-control'] = $this->grantFullControl;\n        }\n        if (null !== $this->grantRead) {\n            $headers['x-amz-grant-read'] = $this->grantRead;\n        }\n        if (null !== $this->grantReadAcp) {\n            $headers['x-amz-grant-read-acp'] = $this->grantReadAcp;\n        }\n        if (null !== $this->grantWriteAcp) {\n            $headers['x-amz-grant-write-acp'] = $this->grantWriteAcp;\n        }\n        if (null !== $this->serverSideEncryption) {\n            if (!ServerSideEncryption::exists($this->serverSideEncryption)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"ServerSideEncryption\" for \"%s\". The value \"%s\" is not a valid \"ServerSideEncryption\".', __CLASS__, $this->serverSideEncryption));\n            }\n            $headers['x-amz-server-side-encryption'] = $this->serverSideEncryption;\n        }\n        if (null !== $this->storageClass) {\n            if (!StorageClass::exists($this->storageClass)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"StorageClass\" for \"%s\". The value \"%s\" is not a valid \"StorageClass\".', __CLASS__, $this->storageClass));\n            }\n            $headers['x-amz-storage-class'] = $this->storageClass;\n        }\n        if (null !== $this->websiteRedirectLocation) {\n            $headers['x-amz-website-redirect-location'] = $this->websiteRedirectLocation;\n        }\n        if (null !== $this->sseCustomerAlgorithm) {\n            $headers['x-amz-server-side-encryption-customer-algorithm'] = $this->sseCustomerAlgorithm;\n        }\n        if (null !== $this->sseCustomerKey) {\n            $headers['x-amz-server-side-encryption-customer-key'] = $this->sseCustomerKey;\n        }\n        if (null !== $this->sseCustomerKeyMd5) {\n            $headers['x-amz-server-side-encryption-customer-key-MD5'] = $this->sseCustomerKeyMd5;\n        }\n        if (null !== $this->sseKmsKeyId) {\n            $headers['x-amz-server-side-encryption-aws-kms-key-id'] = $this->sseKmsKeyId;\n        }\n        if (null !== $this->sseKmsEncryptionContext) {\n            $headers['x-amz-server-side-encryption-context'] = $this->sseKmsEncryptionContext;\n        }\n        if (null !== $this->bucketKeyEnabled) {\n            $headers['x-amz-server-side-encryption-bucket-key-enabled'] = $this->bucketKeyEnabled ? 'true' : 'false';\n        }\n        if (null !== $this->requestPayer) {\n            if (!RequestPayer::exists($this->requestPayer)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"RequestPayer\" for \"%s\". The value \"%s\" is not a valid \"RequestPayer\".', __CLASS__, $this->requestPayer));\n            }\n            $headers['x-amz-request-payer'] = $this->requestPayer;\n        }\n        if (null !== $this->tagging) {\n            $headers['x-amz-tagging'] = $this->tagging;\n        }\n        if (null !== $this->objectLockMode) {\n            if (!ObjectLockMode::exists($this->objectLockMode)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"ObjectLockMode\" for \"%s\". The value \"%s\" is not a valid \"ObjectLockMode\".', __CLASS__, $this->objectLockMode));\n            }\n            $headers['x-amz-object-lock-mode'] = $this->objectLockMode;\n        }\n        if (null !== $this->objectLockRetainUntilDate) {\n            $headers['x-amz-object-lock-retain-until-date'] = $this->objectLockRetainUntilDate->format(\\DateTimeInterface::ISO8601);\n        }\n        if (null !== $this->objectLockLegalHoldStatus) {\n            if (!ObjectLockLegalHoldStatus::exists($this->objectLockLegalHoldStatus)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"ObjectLockLegalHoldStatus\" for \"%s\". The value \"%s\" is not a valid \"ObjectLockLegalHoldStatus\".', __CLASS__, $this->objectLockLegalHoldStatus));\n            }\n            $headers['x-amz-object-lock-legal-hold'] = $this->objectLockLegalHoldStatus;\n        }\n        if (null !== $this->expectedBucketOwner) {\n            $headers['x-amz-expected-bucket-owner'] = $this->expectedBucketOwner;\n        }\n        if (null !== $this->checksumAlgorithm) {\n            if (!ChecksumAlgorithm::exists($this->checksumAlgorithm)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"ChecksumAlgorithm\" for \"%s\". The value \"%s\" is not a valid \"ChecksumAlgorithm\".', __CLASS__, $this->checksumAlgorithm));\n            }\n            $headers['x-amz-checksum-algorithm'] = $this->checksumAlgorithm;\n        }\n        if (null !== $this->metadata) {\n            foreach ($this->metadata as $key => $value) {\n                $headers[\"x-amz-meta-$key\"] = $value;\n            }\n        }\n\n        // Prepare query\n        $query = [];\n\n        // Prepare URI\n        $uri = [];\n        if (null === $v = $this->bucket) {\n            throw new InvalidArgument(sprintf('Missing parameter \"Bucket\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        $uri['Bucket'] = $v;\n        if (null === $v = $this->key) {\n            throw new InvalidArgument(sprintf('Missing parameter \"Key\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        $uri['Key'] = $v;\n        $uriString = '/' . rawurlencode($uri['Bucket']) . '/' . str_replace('%2F', '/', rawurlencode($uri['Key'])) . '?uploads';\n\n        // Prepare Body\n        $body = '';\n\n        // Return the Request\n        return new Request('POST', $uriString, $query, $headers, StreamFactory::create($body));\n    }\n\n    /**\n     * @param ObjectCannedACL::*|null $value\n     */\n    public function setAcl(?string $value): self\n    {\n        $this->acl = $value;\n\n        return $this;\n    }\n\n    public function setBucket(?string $value): self\n    {\n        $this->bucket = $value;\n\n        return $this;\n    }\n\n    public function setBucketKeyEnabled(?bool $value): self\n    {\n        $this->bucketKeyEnabled = $value;\n\n        return $this;\n    }\n\n    public function setCacheControl(?string $value): self\n    {\n        $this->cacheControl = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param ChecksumAlgorithm::*|null $value\n     */\n    public function setChecksumAlgorithm(?string $value): self\n    {\n        $this->checksumAlgorithm = $value;\n\n        return $this;\n    }\n\n    public function setContentDisposition(?string $value): self\n    {\n        $this->contentDisposition = $value;\n\n        return $this;\n    }\n\n    public function setContentEncoding(?string $value): self\n    {\n        $this->contentEncoding = $value;\n\n        return $this;\n    }\n\n    public function setContentLanguage(?string $value): self\n    {\n        $this->contentLanguage = $value;\n\n        return $this;\n    }\n\n    public function setContentType(?string $value): self\n    {\n        $this->contentType = $value;\n\n        return $this;\n    }\n\n    public function setExpectedBucketOwner(?string $value): self\n    {\n        $this->expectedBucketOwner = $value;\n\n        return $this;\n    }\n\n    public function setExpires(?\\DateTimeImmutable $value): self\n    {\n        $this->expires = $value;\n\n        return $this;\n    }\n\n    public function setGrantFullControl(?string $value): self\n    {\n        $this->grantFullControl = $value;\n\n        return $this;\n    }\n\n    public function setGrantRead(?string $value): self\n    {\n        $this->grantRead = $value;\n\n        return $this;\n    }\n\n    public function setGrantReadAcp(?string $value): self\n    {\n        $this->grantReadAcp = $value;\n\n        return $this;\n    }\n\n    public function setGrantWriteAcp(?string $value): self\n    {\n        $this->grantWriteAcp = $value;\n\n        return $this;\n    }\n\n    public function setKey(?string $value): self\n    {\n        $this->key = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param array<string, string> $value\n     */\n    public function setMetadata(array $value): self\n    {\n        $this->metadata = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param ObjectLockLegalHoldStatus::*|null $value\n     */\n    public function setObjectLockLegalHoldStatus(?string $value): self\n    {\n        $this->objectLockLegalHoldStatus = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param ObjectLockMode::*|null $value\n     */\n    public function setObjectLockMode(?string $value): self\n    {\n        $this->objectLockMode = $value;\n\n        return $this;\n    }\n\n    public function setObjectLockRetainUntilDate(?\\DateTimeImmutable $value): self\n    {\n        $this->objectLockRetainUntilDate = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param RequestPayer::*|null $value\n     */\n    public function setRequestPayer(?string $value): self\n    {\n        $this->requestPayer = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param ServerSideEncryption::*|null $value\n     */\n    public function setServerSideEncryption(?string $value): self\n    {\n        $this->serverSideEncryption = $value;\n\n        return $this;\n    }\n\n    public function setSseCustomerAlgorithm(?string $value): self\n    {\n        $this->sseCustomerAlgorithm = $value;\n\n        return $this;\n    }\n\n    public function setSseCustomerKey(?string $value): self\n    {\n        $this->sseCustomerKey = $value;\n\n        return $this;\n    }\n\n    public function setSseCustomerKeyMd5(?string $value): self\n    {\n        $this->sseCustomerKeyMd5 = $value;\n\n        return $this;\n    }\n\n    public function setSseKmsEncryptionContext(?string $value): self\n    {\n        $this->sseKmsEncryptionContext = $value;\n\n        return $this;\n    }\n\n    public function setSseKmsKeyId(?string $value): self\n    {\n        $this->sseKmsKeyId = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param StorageClass::*|null $value\n     */\n    public function setStorageClass(?string $value): self\n    {\n        $this->storageClass = $value;\n\n        return $this;\n    }\n\n    public function setTagging(?string $value): self\n    {\n        $this->tagging = $value;\n\n        return $this;\n    }\n\n    public function setWebsiteRedirectLocation(?string $value): self\n    {\n        $this->websiteRedirectLocation = $value;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Input/DeleteBucketCorsRequest.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Input;\n\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\nuse AsyncAws\\Core\\Input;\nuse AsyncAws\\Core\\Request;\nuse AsyncAws\\Core\\Stream\\StreamFactory;\n\nfinal class DeleteBucketCorsRequest extends Input\n{\n    /**\n     * Specifies the bucket whose `cors` configuration is being deleted.\n     *\n     * @required\n     *\n     * @var string|null\n     */\n    private $bucket;\n\n    /**\n     * The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with\n     * the HTTP status code `403 Forbidden` (access denied).\n     *\n     * @var string|null\n     */\n    private $expectedBucketOwner;\n\n    /**\n     * @param array{\n     *   Bucket?: string,\n     *   ExpectedBucketOwner?: string,\n     *\n     *   @region?: string,\n     * } $input\n     */\n    public function __construct(array $input = [])\n    {\n        $this->bucket = $input['Bucket'] ?? null;\n        $this->expectedBucketOwner = $input['ExpectedBucketOwner'] ?? null;\n        parent::__construct($input);\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    public function getBucket(): ?string\n    {\n        return $this->bucket;\n    }\n\n    public function getExpectedBucketOwner(): ?string\n    {\n        return $this->expectedBucketOwner;\n    }\n\n    /**\n     * @internal\n     */\n    public function request(): Request\n    {\n        // Prepare headers\n        $headers = ['content-type' => 'application/xml'];\n        if (null !== $this->expectedBucketOwner) {\n            $headers['x-amz-expected-bucket-owner'] = $this->expectedBucketOwner;\n        }\n\n        // Prepare query\n        $query = [];\n\n        // Prepare URI\n        $uri = [];\n        if (null === $v = $this->bucket) {\n            throw new InvalidArgument(sprintf('Missing parameter \"Bucket\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        $uri['Bucket'] = $v;\n        $uriString = '/' . rawurlencode($uri['Bucket']) . '?cors';\n\n        // Prepare Body\n        $body = '';\n\n        // Return the Request\n        return new Request('DELETE', $uriString, $query, $headers, StreamFactory::create($body));\n    }\n\n    public function setBucket(?string $value): self\n    {\n        $this->bucket = $value;\n\n        return $this;\n    }\n\n    public function setExpectedBucketOwner(?string $value): self\n    {\n        $this->expectedBucketOwner = $value;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Input/DeleteBucketRequest.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Input;\n\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\nuse AsyncAws\\Core\\Input;\nuse AsyncAws\\Core\\Request;\nuse AsyncAws\\Core\\Stream\\StreamFactory;\n\nfinal class DeleteBucketRequest extends Input\n{\n    /**\n     * Specifies the bucket being deleted.\n     *\n     * @required\n     *\n     * @var string|null\n     */\n    private $bucket;\n\n    /**\n     * The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with\n     * the HTTP status code `403 Forbidden` (access denied).\n     *\n     * @var string|null\n     */\n    private $expectedBucketOwner;\n\n    /**\n     * @param array{\n     *   Bucket?: string,\n     *   ExpectedBucketOwner?: string,\n     *\n     *   @region?: string,\n     * } $input\n     */\n    public function __construct(array $input = [])\n    {\n        $this->bucket = $input['Bucket'] ?? null;\n        $this->expectedBucketOwner = $input['ExpectedBucketOwner'] ?? null;\n        parent::__construct($input);\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    public function getBucket(): ?string\n    {\n        return $this->bucket;\n    }\n\n    public function getExpectedBucketOwner(): ?string\n    {\n        return $this->expectedBucketOwner;\n    }\n\n    /**\n     * @internal\n     */\n    public function request(): Request\n    {\n        // Prepare headers\n        $headers = ['content-type' => 'application/xml'];\n        if (null !== $this->expectedBucketOwner) {\n            $headers['x-amz-expected-bucket-owner'] = $this->expectedBucketOwner;\n        }\n\n        // Prepare query\n        $query = [];\n\n        // Prepare URI\n        $uri = [];\n        if (null === $v = $this->bucket) {\n            throw new InvalidArgument(sprintf('Missing parameter \"Bucket\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        $uri['Bucket'] = $v;\n        $uriString = '/' . rawurlencode($uri['Bucket']);\n\n        // Prepare Body\n        $body = '';\n\n        // Return the Request\n        return new Request('DELETE', $uriString, $query, $headers, StreamFactory::create($body));\n    }\n\n    public function setBucket(?string $value): self\n    {\n        $this->bucket = $value;\n\n        return $this;\n    }\n\n    public function setExpectedBucketOwner(?string $value): self\n    {\n        $this->expectedBucketOwner = $value;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Input/DeleteObjectRequest.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Input;\n\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\nuse AsyncAws\\Core\\Input;\nuse AsyncAws\\Core\\Request;\nuse AsyncAws\\Core\\Stream\\StreamFactory;\nuse AsyncAws\\S3\\Enum\\RequestPayer;\n\nfinal class DeleteObjectRequest extends Input\n{\n    /**\n     * The bucket name of the bucket containing the object.\n     *\n     * When using this action with an access point, you must direct requests to the access point hostname. The access point\n     * hostname takes the form *AccessPointName*-*AccountId*.s3-accesspoint.*Region*.amazonaws.com. When using this action\n     * with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket\n     * name. For more information about access point ARNs, see Using access points [^1] in the *Amazon S3 User Guide*.\n     *\n     * When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3\n     * on Outposts hostname takes the form `*AccessPointName*-*AccountId*.*outpostID*.s3-outposts.*Region*.amazonaws.com`.\n     * When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access\n     * point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts\n     * [^2] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html\n     * [^2]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html\n     *\n     * @required\n     *\n     * @var string|null\n     */\n    private $bucket;\n\n    /**\n     * Key name of the object to delete.\n     *\n     * @required\n     *\n     * @var string|null\n     */\n    private $key;\n\n    /**\n     * The concatenation of the authentication device's serial number, a space, and the value that is displayed on your\n     * authentication device. Required to permanently delete a versioned object if versioning is configured with MFA delete\n     * enabled.\n     *\n     * @var string|null\n     */\n    private $mfa;\n\n    /**\n     * VersionId used to reference a specific version of the object.\n     *\n     * @var string|null\n     */\n    private $versionId;\n\n    /**\n     * @var RequestPayer::*|null\n     */\n    private $requestPayer;\n\n    /**\n     * Indicates whether S3 Object Lock should bypass Governance-mode restrictions to process this operation. To use this\n     * header, you must have the `s3:BypassGovernanceRetention` permission.\n     *\n     * @var bool|null\n     */\n    private $bypassGovernanceRetention;\n\n    /**\n     * The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with\n     * the HTTP status code `403 Forbidden` (access denied).\n     *\n     * @var string|null\n     */\n    private $expectedBucketOwner;\n\n    /**\n     * @param array{\n     *   Bucket?: string,\n     *   Key?: string,\n     *   MFA?: string,\n     *   VersionId?: string,\n     *   RequestPayer?: RequestPayer::*,\n     *   BypassGovernanceRetention?: bool,\n     *   ExpectedBucketOwner?: string,\n     *\n     *   @region?: string,\n     * } $input\n     */\n    public function __construct(array $input = [])\n    {\n        $this->bucket = $input['Bucket'] ?? null;\n        $this->key = $input['Key'] ?? null;\n        $this->mfa = $input['MFA'] ?? null;\n        $this->versionId = $input['VersionId'] ?? null;\n        $this->requestPayer = $input['RequestPayer'] ?? null;\n        $this->bypassGovernanceRetention = $input['BypassGovernanceRetention'] ?? null;\n        $this->expectedBucketOwner = $input['ExpectedBucketOwner'] ?? null;\n        parent::__construct($input);\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    public function getBucket(): ?string\n    {\n        return $this->bucket;\n    }\n\n    public function getBypassGovernanceRetention(): ?bool\n    {\n        return $this->bypassGovernanceRetention;\n    }\n\n    public function getExpectedBucketOwner(): ?string\n    {\n        return $this->expectedBucketOwner;\n    }\n\n    public function getKey(): ?string\n    {\n        return $this->key;\n    }\n\n    public function getMfa(): ?string\n    {\n        return $this->mfa;\n    }\n\n    /**\n     * @return RequestPayer::*|null\n     */\n    public function getRequestPayer(): ?string\n    {\n        return $this->requestPayer;\n    }\n\n    public function getVersionId(): ?string\n    {\n        return $this->versionId;\n    }\n\n    /**\n     * @internal\n     */\n    public function request(): Request\n    {\n        // Prepare headers\n        $headers = ['content-type' => 'application/xml'];\n        if (null !== $this->mfa) {\n            $headers['x-amz-mfa'] = $this->mfa;\n        }\n        if (null !== $this->requestPayer) {\n            if (!RequestPayer::exists($this->requestPayer)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"RequestPayer\" for \"%s\". The value \"%s\" is not a valid \"RequestPayer\".', __CLASS__, $this->requestPayer));\n            }\n            $headers['x-amz-request-payer'] = $this->requestPayer;\n        }\n        if (null !== $this->bypassGovernanceRetention) {\n            $headers['x-amz-bypass-governance-retention'] = $this->bypassGovernanceRetention ? 'true' : 'false';\n        }\n        if (null !== $this->expectedBucketOwner) {\n            $headers['x-amz-expected-bucket-owner'] = $this->expectedBucketOwner;\n        }\n\n        // Prepare query\n        $query = [];\n        if (null !== $this->versionId) {\n            $query['versionId'] = $this->versionId;\n        }\n\n        // Prepare URI\n        $uri = [];\n        if (null === $v = $this->bucket) {\n            throw new InvalidArgument(sprintf('Missing parameter \"Bucket\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        $uri['Bucket'] = $v;\n        if (null === $v = $this->key) {\n            throw new InvalidArgument(sprintf('Missing parameter \"Key\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        $uri['Key'] = $v;\n        $uriString = '/' . rawurlencode($uri['Bucket']) . '/' . str_replace('%2F', '/', rawurlencode($uri['Key']));\n\n        // Prepare Body\n        $body = '';\n\n        // Return the Request\n        return new Request('DELETE', $uriString, $query, $headers, StreamFactory::create($body));\n    }\n\n    public function setBucket(?string $value): self\n    {\n        $this->bucket = $value;\n\n        return $this;\n    }\n\n    public function setBypassGovernanceRetention(?bool $value): self\n    {\n        $this->bypassGovernanceRetention = $value;\n\n        return $this;\n    }\n\n    public function setExpectedBucketOwner(?string $value): self\n    {\n        $this->expectedBucketOwner = $value;\n\n        return $this;\n    }\n\n    public function setKey(?string $value): self\n    {\n        $this->key = $value;\n\n        return $this;\n    }\n\n    public function setMfa(?string $value): self\n    {\n        $this->mfa = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param RequestPayer::*|null $value\n     */\n    public function setRequestPayer(?string $value): self\n    {\n        $this->requestPayer = $value;\n\n        return $this;\n    }\n\n    public function setVersionId(?string $value): self\n    {\n        $this->versionId = $value;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Input/DeleteObjectsRequest.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Input;\n\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\nuse AsyncAws\\Core\\Input;\nuse AsyncAws\\Core\\Request;\nuse AsyncAws\\Core\\Stream\\StreamFactory;\nuse AsyncAws\\S3\\Enum\\ChecksumAlgorithm;\nuse AsyncAws\\S3\\Enum\\RequestPayer;\nuse AsyncAws\\S3\\ValueObject\\Delete;\n\nfinal class DeleteObjectsRequest extends Input\n{\n    /**\n     * The bucket name containing the objects to delete.\n     *\n     * When using this action with an access point, you must direct requests to the access point hostname. The access point\n     * hostname takes the form *AccessPointName*-*AccountId*.s3-accesspoint.*Region*.amazonaws.com. When using this action\n     * with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket\n     * name. For more information about access point ARNs, see Using access points [^1] in the *Amazon S3 User Guide*.\n     *\n     * When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3\n     * on Outposts hostname takes the form `*AccessPointName*-*AccountId*.*outpostID*.s3-outposts.*Region*.amazonaws.com`.\n     * When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access\n     * point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts\n     * [^2] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html\n     * [^2]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html\n     *\n     * @required\n     *\n     * @var string|null\n     */\n    private $bucket;\n\n    /**\n     * Container for the request.\n     *\n     * @required\n     *\n     * @var Delete|null\n     */\n    private $delete;\n\n    /**\n     * The concatenation of the authentication device's serial number, a space, and the value that is displayed on your\n     * authentication device. Required to permanently delete a versioned object if versioning is configured with MFA delete\n     * enabled.\n     *\n     * @var string|null\n     */\n    private $mfa;\n\n    /**\n     * @var RequestPayer::*|null\n     */\n    private $requestPayer;\n\n    /**\n     * Specifies whether you want to delete this object even if it has a Governance-type Object Lock in place. To use this\n     * header, you must have the `s3:BypassGovernanceRetention` permission.\n     *\n     * @var bool|null\n     */\n    private $bypassGovernanceRetention;\n\n    /**\n     * The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with\n     * the HTTP status code `403 Forbidden` (access denied).\n     *\n     * @var string|null\n     */\n    private $expectedBucketOwner;\n\n    /**\n     * Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide\n     * any additional functionality if not using the SDK. When sending this header, there must be a corresponding\n     * `x-amz-checksum` or `x-amz-trailer` header sent. Otherwise, Amazon S3 fails the request with the HTTP status code\n     * `400 Bad Request`. For more information, see Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * If you provide an individual checksum, Amazon S3 ignores any provided `ChecksumAlgorithm` parameter.\n     *\n     * This checksum algorithm must be the same for all parts and it match the checksum value supplied in the\n     * `CreateMultipartUpload` request.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html\n     *\n     * @var ChecksumAlgorithm::*|null\n     */\n    private $checksumAlgorithm;\n\n    /**\n     * @param array{\n     *   Bucket?: string,\n     *   Delete?: Delete|array,\n     *   MFA?: string,\n     *   RequestPayer?: RequestPayer::*,\n     *   BypassGovernanceRetention?: bool,\n     *   ExpectedBucketOwner?: string,\n     *   ChecksumAlgorithm?: ChecksumAlgorithm::*,\n     *\n     *   @region?: string,\n     * } $input\n     */\n    public function __construct(array $input = [])\n    {\n        $this->bucket = $input['Bucket'] ?? null;\n        $this->delete = isset($input['Delete']) ? Delete::create($input['Delete']) : null;\n        $this->mfa = $input['MFA'] ?? null;\n        $this->requestPayer = $input['RequestPayer'] ?? null;\n        $this->bypassGovernanceRetention = $input['BypassGovernanceRetention'] ?? null;\n        $this->expectedBucketOwner = $input['ExpectedBucketOwner'] ?? null;\n        $this->checksumAlgorithm = $input['ChecksumAlgorithm'] ?? null;\n        parent::__construct($input);\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    public function getBucket(): ?string\n    {\n        return $this->bucket;\n    }\n\n    public function getBypassGovernanceRetention(): ?bool\n    {\n        return $this->bypassGovernanceRetention;\n    }\n\n    /**\n     * @return ChecksumAlgorithm::*|null\n     */\n    public function getChecksumAlgorithm(): ?string\n    {\n        return $this->checksumAlgorithm;\n    }\n\n    public function getDelete(): ?Delete\n    {\n        return $this->delete;\n    }\n\n    public function getExpectedBucketOwner(): ?string\n    {\n        return $this->expectedBucketOwner;\n    }\n\n    public function getMfa(): ?string\n    {\n        return $this->mfa;\n    }\n\n    /**\n     * @return RequestPayer::*|null\n     */\n    public function getRequestPayer(): ?string\n    {\n        return $this->requestPayer;\n    }\n\n    /**\n     * @internal\n     */\n    public function request(): Request\n    {\n        // Prepare headers\n        $headers = ['content-type' => 'application/xml'];\n        if (null !== $this->mfa) {\n            $headers['x-amz-mfa'] = $this->mfa;\n        }\n        if (null !== $this->requestPayer) {\n            if (!RequestPayer::exists($this->requestPayer)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"RequestPayer\" for \"%s\". The value \"%s\" is not a valid \"RequestPayer\".', __CLASS__, $this->requestPayer));\n            }\n            $headers['x-amz-request-payer'] = $this->requestPayer;\n        }\n        if (null !== $this->bypassGovernanceRetention) {\n            $headers['x-amz-bypass-governance-retention'] = $this->bypassGovernanceRetention ? 'true' : 'false';\n        }\n        if (null !== $this->expectedBucketOwner) {\n            $headers['x-amz-expected-bucket-owner'] = $this->expectedBucketOwner;\n        }\n        if (null !== $this->checksumAlgorithm) {\n            if (!ChecksumAlgorithm::exists($this->checksumAlgorithm)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"ChecksumAlgorithm\" for \"%s\". The value \"%s\" is not a valid \"ChecksumAlgorithm\".', __CLASS__, $this->checksumAlgorithm));\n            }\n            $headers['x-amz-sdk-checksum-algorithm'] = $this->checksumAlgorithm;\n        }\n\n        // Prepare query\n        $query = [];\n\n        // Prepare URI\n        $uri = [];\n        if (null === $v = $this->bucket) {\n            throw new InvalidArgument(sprintf('Missing parameter \"Bucket\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        $uri['Bucket'] = $v;\n        $uriString = '/' . rawurlencode($uri['Bucket']) . '?delete';\n\n        // Prepare Body\n\n        $document = new \\DOMDocument('1.0', 'UTF-8');\n        $document->formatOutput = false;\n        $this->requestBody($document, $document);\n        $body = $document->hasChildNodes() ? $document->saveXML() : '';\n\n        // Return the Request\n        return new Request('POST', $uriString, $query, $headers, StreamFactory::create($body));\n    }\n\n    public function setBucket(?string $value): self\n    {\n        $this->bucket = $value;\n\n        return $this;\n    }\n\n    public function setBypassGovernanceRetention(?bool $value): self\n    {\n        $this->bypassGovernanceRetention = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param ChecksumAlgorithm::*|null $value\n     */\n    public function setChecksumAlgorithm(?string $value): self\n    {\n        $this->checksumAlgorithm = $value;\n\n        return $this;\n    }\n\n    public function setDelete(?Delete $value): self\n    {\n        $this->delete = $value;\n\n        return $this;\n    }\n\n    public function setExpectedBucketOwner(?string $value): self\n    {\n        $this->expectedBucketOwner = $value;\n\n        return $this;\n    }\n\n    public function setMfa(?string $value): self\n    {\n        $this->mfa = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param RequestPayer::*|null $value\n     */\n    public function setRequestPayer(?string $value): self\n    {\n        $this->requestPayer = $value;\n\n        return $this;\n    }\n\n    private function requestBody(\\DOMNode $node, \\DOMDocument $document): void\n    {\n        if (null === $v = $this->delete) {\n            throw new InvalidArgument(sprintf('Missing parameter \"Delete\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n\n        $node->appendChild($child = $document->createElement('Delete'));\n        $child->setAttribute('xmlns', 'http://s3.amazonaws.com/doc/2006-03-01/');\n        $v->requestBody($child, $document);\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Input/GetBucketCorsRequest.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Input;\n\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\nuse AsyncAws\\Core\\Input;\nuse AsyncAws\\Core\\Request;\nuse AsyncAws\\Core\\Stream\\StreamFactory;\n\nfinal class GetBucketCorsRequest extends Input\n{\n    /**\n     * The bucket name for which to get the cors configuration.\n     *\n     * To use this API operation against an access point, provide the alias of the access point in place of the bucket name.\n     *\n     * To use this API operation against an Object Lambda access point, provide the alias of the Object Lambda access point\n     * in place of the bucket name. If the Object Lambda access point alias in a request is not valid, the error code\n     * `InvalidAccessPointAliasError` is returned. For more information about `InvalidAccessPointAliasError`, see List of\n     * Error Codes [^1].\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html#ErrorCodeList\n     *\n     * @required\n     *\n     * @var string|null\n     */\n    private $bucket;\n\n    /**\n     * The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with\n     * the HTTP status code `403 Forbidden` (access denied).\n     *\n     * @var string|null\n     */\n    private $expectedBucketOwner;\n\n    /**\n     * @param array{\n     *   Bucket?: string,\n     *   ExpectedBucketOwner?: string,\n     *\n     *   @region?: string,\n     * } $input\n     */\n    public function __construct(array $input = [])\n    {\n        $this->bucket = $input['Bucket'] ?? null;\n        $this->expectedBucketOwner = $input['ExpectedBucketOwner'] ?? null;\n        parent::__construct($input);\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    public function getBucket(): ?string\n    {\n        return $this->bucket;\n    }\n\n    public function getExpectedBucketOwner(): ?string\n    {\n        return $this->expectedBucketOwner;\n    }\n\n    /**\n     * @internal\n     */\n    public function request(): Request\n    {\n        // Prepare headers\n        $headers = ['content-type' => 'application/xml'];\n        if (null !== $this->expectedBucketOwner) {\n            $headers['x-amz-expected-bucket-owner'] = $this->expectedBucketOwner;\n        }\n\n        // Prepare query\n        $query = [];\n\n        // Prepare URI\n        $uri = [];\n        if (null === $v = $this->bucket) {\n            throw new InvalidArgument(sprintf('Missing parameter \"Bucket\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        $uri['Bucket'] = $v;\n        $uriString = '/' . rawurlencode($uri['Bucket']) . '?cors';\n\n        // Prepare Body\n        $body = '';\n\n        // Return the Request\n        return new Request('GET', $uriString, $query, $headers, StreamFactory::create($body));\n    }\n\n    public function setBucket(?string $value): self\n    {\n        $this->bucket = $value;\n\n        return $this;\n    }\n\n    public function setExpectedBucketOwner(?string $value): self\n    {\n        $this->expectedBucketOwner = $value;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Input/GetBucketEncryptionRequest.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Input;\n\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\nuse AsyncAws\\Core\\Input;\nuse AsyncAws\\Core\\Request;\nuse AsyncAws\\Core\\Stream\\StreamFactory;\n\nfinal class GetBucketEncryptionRequest extends Input\n{\n    /**\n     * The name of the bucket from which the server-side encryption configuration is retrieved.\n     *\n     * @required\n     *\n     * @var string|null\n     */\n    private $bucket;\n\n    /**\n     * The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with\n     * the HTTP status code `403 Forbidden` (access denied).\n     *\n     * @var string|null\n     */\n    private $expectedBucketOwner;\n\n    /**\n     * @param array{\n     *   Bucket?: string,\n     *   ExpectedBucketOwner?: string,\n     *\n     *   @region?: string,\n     * } $input\n     */\n    public function __construct(array $input = [])\n    {\n        $this->bucket = $input['Bucket'] ?? null;\n        $this->expectedBucketOwner = $input['ExpectedBucketOwner'] ?? null;\n        parent::__construct($input);\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    public function getBucket(): ?string\n    {\n        return $this->bucket;\n    }\n\n    public function getExpectedBucketOwner(): ?string\n    {\n        return $this->expectedBucketOwner;\n    }\n\n    /**\n     * @internal\n     */\n    public function request(): Request\n    {\n        // Prepare headers\n        $headers = ['content-type' => 'application/xml'];\n        if (null !== $this->expectedBucketOwner) {\n            $headers['x-amz-expected-bucket-owner'] = $this->expectedBucketOwner;\n        }\n\n        // Prepare query\n        $query = [];\n\n        // Prepare URI\n        $uri = [];\n        if (null === $v = $this->bucket) {\n            throw new InvalidArgument(sprintf('Missing parameter \"Bucket\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        $uri['Bucket'] = $v;\n        $uriString = '/' . rawurlencode($uri['Bucket']) . '?encryption';\n\n        // Prepare Body\n        $body = '';\n\n        // Return the Request\n        return new Request('GET', $uriString, $query, $headers, StreamFactory::create($body));\n    }\n\n    public function setBucket(?string $value): self\n    {\n        $this->bucket = $value;\n\n        return $this;\n    }\n\n    public function setExpectedBucketOwner(?string $value): self\n    {\n        $this->expectedBucketOwner = $value;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Input/GetObjectAclRequest.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Input;\n\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\nuse AsyncAws\\Core\\Input;\nuse AsyncAws\\Core\\Request;\nuse AsyncAws\\Core\\Stream\\StreamFactory;\nuse AsyncAws\\S3\\Enum\\RequestPayer;\n\nfinal class GetObjectAclRequest extends Input\n{\n    /**\n     * The bucket name that contains the object for which to get the ACL information.\n     *\n     * When using this action with an access point, you must direct requests to the access point hostname. The access point\n     * hostname takes the form *AccessPointName*-*AccountId*.s3-accesspoint.*Region*.amazonaws.com. When using this action\n     * with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket\n     * name. For more information about access point ARNs, see Using access points [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html\n     *\n     * @required\n     *\n     * @var string|null\n     */\n    private $bucket;\n\n    /**\n     * The key of the object for which to get the ACL information.\n     *\n     * @required\n     *\n     * @var string|null\n     */\n    private $key;\n\n    /**\n     * VersionId used to reference a specific version of the object.\n     *\n     * @var string|null\n     */\n    private $versionId;\n\n    /**\n     * @var RequestPayer::*|null\n     */\n    private $requestPayer;\n\n    /**\n     * The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with\n     * the HTTP status code `403 Forbidden` (access denied).\n     *\n     * @var string|null\n     */\n    private $expectedBucketOwner;\n\n    /**\n     * @param array{\n     *   Bucket?: string,\n     *   Key?: string,\n     *   VersionId?: string,\n     *   RequestPayer?: RequestPayer::*,\n     *   ExpectedBucketOwner?: string,\n     *\n     *   @region?: string,\n     * } $input\n     */\n    public function __construct(array $input = [])\n    {\n        $this->bucket = $input['Bucket'] ?? null;\n        $this->key = $input['Key'] ?? null;\n        $this->versionId = $input['VersionId'] ?? null;\n        $this->requestPayer = $input['RequestPayer'] ?? null;\n        $this->expectedBucketOwner = $input['ExpectedBucketOwner'] ?? null;\n        parent::__construct($input);\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    public function getBucket(): ?string\n    {\n        return $this->bucket;\n    }\n\n    public function getExpectedBucketOwner(): ?string\n    {\n        return $this->expectedBucketOwner;\n    }\n\n    public function getKey(): ?string\n    {\n        return $this->key;\n    }\n\n    /**\n     * @return RequestPayer::*|null\n     */\n    public function getRequestPayer(): ?string\n    {\n        return $this->requestPayer;\n    }\n\n    public function getVersionId(): ?string\n    {\n        return $this->versionId;\n    }\n\n    /**\n     * @internal\n     */\n    public function request(): Request\n    {\n        // Prepare headers\n        $headers = ['content-type' => 'application/xml'];\n        if (null !== $this->requestPayer) {\n            if (!RequestPayer::exists($this->requestPayer)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"RequestPayer\" for \"%s\". The value \"%s\" is not a valid \"RequestPayer\".', __CLASS__, $this->requestPayer));\n            }\n            $headers['x-amz-request-payer'] = $this->requestPayer;\n        }\n        if (null !== $this->expectedBucketOwner) {\n            $headers['x-amz-expected-bucket-owner'] = $this->expectedBucketOwner;\n        }\n\n        // Prepare query\n        $query = [];\n        if (null !== $this->versionId) {\n            $query['versionId'] = $this->versionId;\n        }\n\n        // Prepare URI\n        $uri = [];\n        if (null === $v = $this->bucket) {\n            throw new InvalidArgument(sprintf('Missing parameter \"Bucket\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        $uri['Bucket'] = $v;\n        if (null === $v = $this->key) {\n            throw new InvalidArgument(sprintf('Missing parameter \"Key\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        $uri['Key'] = $v;\n        $uriString = '/' . rawurlencode($uri['Bucket']) . '/' . str_replace('%2F', '/', rawurlencode($uri['Key'])) . '?acl';\n\n        // Prepare Body\n        $body = '';\n\n        // Return the Request\n        return new Request('GET', $uriString, $query, $headers, StreamFactory::create($body));\n    }\n\n    public function setBucket(?string $value): self\n    {\n        $this->bucket = $value;\n\n        return $this;\n    }\n\n    public function setExpectedBucketOwner(?string $value): self\n    {\n        $this->expectedBucketOwner = $value;\n\n        return $this;\n    }\n\n    public function setKey(?string $value): self\n    {\n        $this->key = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param RequestPayer::*|null $value\n     */\n    public function setRequestPayer(?string $value): self\n    {\n        $this->requestPayer = $value;\n\n        return $this;\n    }\n\n    public function setVersionId(?string $value): self\n    {\n        $this->versionId = $value;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Input/GetObjectRequest.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Input;\n\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\nuse AsyncAws\\Core\\Input;\nuse AsyncAws\\Core\\Request;\nuse AsyncAws\\Core\\Stream\\StreamFactory;\nuse AsyncAws\\S3\\Enum\\ChecksumMode;\nuse AsyncAws\\S3\\Enum\\RequestPayer;\n\nfinal class GetObjectRequest extends Input\n{\n    /**\n     * The bucket name containing the object.\n     *\n     * When using this action with an access point, you must direct requests to the access point hostname. The access point\n     * hostname takes the form *AccessPointName*-*AccountId*.s3-accesspoint.*Region*.amazonaws.com. When using this action\n     * with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket\n     * name. For more information about access point ARNs, see Using access points [^1] in the *Amazon S3 User Guide*.\n     *\n     * When using an Object Lambda access point the hostname takes the form\n     * *AccessPointName*-*AccountId*.s3-object-lambda.*Region*.amazonaws.com.\n     *\n     * When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3\n     * on Outposts hostname takes the form `*AccessPointName*-*AccountId*.*outpostID*.s3-outposts.*Region*.amazonaws.com`.\n     * When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access\n     * point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts\n     * [^2] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html\n     * [^2]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html\n     *\n     * @required\n     *\n     * @var string|null\n     */\n    private $bucket;\n\n    /**\n     * Return the object only if its entity tag (ETag) is the same as the one specified; otherwise, return a 412\n     * (precondition failed) error.\n     *\n     * @var string|null\n     */\n    private $ifMatch;\n\n    /**\n     * Return the object only if it has been modified since the specified time; otherwise, return a 304 (not modified)\n     * error.\n     *\n     * @var \\DateTimeImmutable|null\n     */\n    private $ifModifiedSince;\n\n    /**\n     * Return the object only if its entity tag (ETag) is different from the one specified; otherwise, return a 304 (not\n     * modified) error.\n     *\n     * @var string|null\n     */\n    private $ifNoneMatch;\n\n    /**\n     * Return the object only if it has not been modified since the specified time; otherwise, return a 412 (precondition\n     * failed) error.\n     *\n     * @var \\DateTimeImmutable|null\n     */\n    private $ifUnmodifiedSince;\n\n    /**\n     * Key of the object to get.\n     *\n     * @required\n     *\n     * @var string|null\n     */\n    private $key;\n\n    /**\n     * Downloads the specified range bytes of an object. For more information about the HTTP Range header, see\n     * https://www.rfc-editor.org/rfc/rfc9110.html#name-range [^1].\n     *\n     * > Amazon S3 doesn't support retrieving multiple ranges of data per `GET` request.\n     *\n     * [^1]: https://www.rfc-editor.org/rfc/rfc9110.html#name-range\n     *\n     * @var string|null\n     */\n    private $range;\n\n    /**\n     * Sets the `Cache-Control` header of the response.\n     *\n     * @var string|null\n     */\n    private $responseCacheControl;\n\n    /**\n     * Sets the `Content-Disposition` header of the response.\n     *\n     * @var string|null\n     */\n    private $responseContentDisposition;\n\n    /**\n     * Sets the `Content-Encoding` header of the response.\n     *\n     * @var string|null\n     */\n    private $responseContentEncoding;\n\n    /**\n     * Sets the `Content-Language` header of the response.\n     *\n     * @var string|null\n     */\n    private $responseContentLanguage;\n\n    /**\n     * Sets the `Content-Type` header of the response.\n     *\n     * @var string|null\n     */\n    private $responseContentType;\n\n    /**\n     * Sets the `Expires` header of the response.\n     *\n     * @var \\DateTimeImmutable|null\n     */\n    private $responseExpires;\n\n    /**\n     * VersionId used to reference a specific version of the object.\n     *\n     * @var string|null\n     */\n    private $versionId;\n\n    /**\n     * Specifies the algorithm to use to when decrypting the object (for example, AES256).\n     *\n     * @var string|null\n     */\n    private $sseCustomerAlgorithm;\n\n    /**\n     * Specifies the customer-provided encryption key for Amazon S3 used to encrypt the data. This value is used to decrypt\n     * the object when recovering it and must match the one used when storing the data. The key must be appropriate for use\n     * with the algorithm specified in the `x-amz-server-side-encryption-customer-algorithm` header.\n     *\n     * @var string|null\n     */\n    private $sseCustomerKey;\n\n    /**\n     * Specifies the 128-bit MD5 digest of the encryption key according to RFC 1321. Amazon S3 uses this header for a\n     * message integrity check to ensure that the encryption key was transmitted without error.\n     *\n     * @var string|null\n     */\n    private $sseCustomerKeyMd5;\n\n    /**\n     * @var RequestPayer::*|null\n     */\n    private $requestPayer;\n\n    /**\n     * Part number of the object being read. This is a positive integer between 1 and 10,000. Effectively performs a\n     * 'ranged' GET request for the part specified. Useful for downloading just a part of an object.\n     *\n     * @var int|null\n     */\n    private $partNumber;\n\n    /**\n     * The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with\n     * the HTTP status code `403 Forbidden` (access denied).\n     *\n     * @var string|null\n     */\n    private $expectedBucketOwner;\n\n    /**\n     * To retrieve the checksum, this mode must be enabled.\n     *\n     * @var ChecksumMode::*|null\n     */\n    private $checksumMode;\n\n    /**\n     * @param array{\n     *   Bucket?: string,\n     *   IfMatch?: string,\n     *   IfModifiedSince?: \\DateTimeImmutable|string,\n     *   IfNoneMatch?: string,\n     *   IfUnmodifiedSince?: \\DateTimeImmutable|string,\n     *   Key?: string,\n     *   Range?: string,\n     *   ResponseCacheControl?: string,\n     *   ResponseContentDisposition?: string,\n     *   ResponseContentEncoding?: string,\n     *   ResponseContentLanguage?: string,\n     *   ResponseContentType?: string,\n     *   ResponseExpires?: \\DateTimeImmutable|string,\n     *   VersionId?: string,\n     *   SSECustomerAlgorithm?: string,\n     *   SSECustomerKey?: string,\n     *   SSECustomerKeyMD5?: string,\n     *   RequestPayer?: RequestPayer::*,\n     *   PartNumber?: int,\n     *   ExpectedBucketOwner?: string,\n     *   ChecksumMode?: ChecksumMode::*,\n     *\n     *   @region?: string,\n     * } $input\n     */\n    public function __construct(array $input = [])\n    {\n        $this->bucket = $input['Bucket'] ?? null;\n        $this->ifMatch = $input['IfMatch'] ?? null;\n        $this->ifModifiedSince = !isset($input['IfModifiedSince']) ? null : ($input['IfModifiedSince'] instanceof \\DateTimeImmutable ? $input['IfModifiedSince'] : new \\DateTimeImmutable($input['IfModifiedSince']));\n        $this->ifNoneMatch = $input['IfNoneMatch'] ?? null;\n        $this->ifUnmodifiedSince = !isset($input['IfUnmodifiedSince']) ? null : ($input['IfUnmodifiedSince'] instanceof \\DateTimeImmutable ? $input['IfUnmodifiedSince'] : new \\DateTimeImmutable($input['IfUnmodifiedSince']));\n        $this->key = $input['Key'] ?? null;\n        $this->range = $input['Range'] ?? null;\n        $this->responseCacheControl = $input['ResponseCacheControl'] ?? null;\n        $this->responseContentDisposition = $input['ResponseContentDisposition'] ?? null;\n        $this->responseContentEncoding = $input['ResponseContentEncoding'] ?? null;\n        $this->responseContentLanguage = $input['ResponseContentLanguage'] ?? null;\n        $this->responseContentType = $input['ResponseContentType'] ?? null;\n        $this->responseExpires = !isset($input['ResponseExpires']) ? null : ($input['ResponseExpires'] instanceof \\DateTimeImmutable ? $input['ResponseExpires'] : new \\DateTimeImmutable($input['ResponseExpires']));\n        $this->versionId = $input['VersionId'] ?? null;\n        $this->sseCustomerAlgorithm = $input['SSECustomerAlgorithm'] ?? null;\n        $this->sseCustomerKey = $input['SSECustomerKey'] ?? null;\n        $this->sseCustomerKeyMd5 = $input['SSECustomerKeyMD5'] ?? null;\n        $this->requestPayer = $input['RequestPayer'] ?? null;\n        $this->partNumber = $input['PartNumber'] ?? null;\n        $this->expectedBucketOwner = $input['ExpectedBucketOwner'] ?? null;\n        $this->checksumMode = $input['ChecksumMode'] ?? null;\n        parent::__construct($input);\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    public function getBucket(): ?string\n    {\n        return $this->bucket;\n    }\n\n    /**\n     * @return ChecksumMode::*|null\n     */\n    public function getChecksumMode(): ?string\n    {\n        return $this->checksumMode;\n    }\n\n    public function getExpectedBucketOwner(): ?string\n    {\n        return $this->expectedBucketOwner;\n    }\n\n    public function getIfMatch(): ?string\n    {\n        return $this->ifMatch;\n    }\n\n    public function getIfModifiedSince(): ?\\DateTimeImmutable\n    {\n        return $this->ifModifiedSince;\n    }\n\n    public function getIfNoneMatch(): ?string\n    {\n        return $this->ifNoneMatch;\n    }\n\n    public function getIfUnmodifiedSince(): ?\\DateTimeImmutable\n    {\n        return $this->ifUnmodifiedSince;\n    }\n\n    public function getKey(): ?string\n    {\n        return $this->key;\n    }\n\n    public function getPartNumber(): ?int\n    {\n        return $this->partNumber;\n    }\n\n    public function getRange(): ?string\n    {\n        return $this->range;\n    }\n\n    /**\n     * @return RequestPayer::*|null\n     */\n    public function getRequestPayer(): ?string\n    {\n        return $this->requestPayer;\n    }\n\n    public function getResponseCacheControl(): ?string\n    {\n        return $this->responseCacheControl;\n    }\n\n    public function getResponseContentDisposition(): ?string\n    {\n        return $this->responseContentDisposition;\n    }\n\n    public function getResponseContentEncoding(): ?string\n    {\n        return $this->responseContentEncoding;\n    }\n\n    public function getResponseContentLanguage(): ?string\n    {\n        return $this->responseContentLanguage;\n    }\n\n    public function getResponseContentType(): ?string\n    {\n        return $this->responseContentType;\n    }\n\n    public function getResponseExpires(): ?\\DateTimeImmutable\n    {\n        return $this->responseExpires;\n    }\n\n    public function getSseCustomerAlgorithm(): ?string\n    {\n        return $this->sseCustomerAlgorithm;\n    }\n\n    public function getSseCustomerKey(): ?string\n    {\n        return $this->sseCustomerKey;\n    }\n\n    public function getSseCustomerKeyMd5(): ?string\n    {\n        return $this->sseCustomerKeyMd5;\n    }\n\n    public function getVersionId(): ?string\n    {\n        return $this->versionId;\n    }\n\n    /**\n     * @internal\n     */\n    public function request(): Request\n    {\n        // Prepare headers\n        $headers = ['content-type' => 'application/xml'];\n        if (null !== $this->ifMatch) {\n            $headers['If-Match'] = $this->ifMatch;\n        }\n        if (null !== $this->ifModifiedSince) {\n            $headers['If-Modified-Since'] = $this->ifModifiedSince->setTimezone(new \\DateTimeZone('GMT'))->format(\\DateTimeInterface::RFC7231);\n        }\n        if (null !== $this->ifNoneMatch) {\n            $headers['If-None-Match'] = $this->ifNoneMatch;\n        }\n        if (null !== $this->ifUnmodifiedSince) {\n            $headers['If-Unmodified-Since'] = $this->ifUnmodifiedSince->setTimezone(new \\DateTimeZone('GMT'))->format(\\DateTimeInterface::RFC7231);\n        }\n        if (null !== $this->range) {\n            $headers['Range'] = $this->range;\n        }\n        if (null !== $this->sseCustomerAlgorithm) {\n            $headers['x-amz-server-side-encryption-customer-algorithm'] = $this->sseCustomerAlgorithm;\n        }\n        if (null !== $this->sseCustomerKey) {\n            $headers['x-amz-server-side-encryption-customer-key'] = $this->sseCustomerKey;\n        }\n        if (null !== $this->sseCustomerKeyMd5) {\n            $headers['x-amz-server-side-encryption-customer-key-MD5'] = $this->sseCustomerKeyMd5;\n        }\n        if (null !== $this->requestPayer) {\n            if (!RequestPayer::exists($this->requestPayer)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"RequestPayer\" for \"%s\". The value \"%s\" is not a valid \"RequestPayer\".', __CLASS__, $this->requestPayer));\n            }\n            $headers['x-amz-request-payer'] = $this->requestPayer;\n        }\n        if (null !== $this->expectedBucketOwner) {\n            $headers['x-amz-expected-bucket-owner'] = $this->expectedBucketOwner;\n        }\n        if (null !== $this->checksumMode) {\n            if (!ChecksumMode::exists($this->checksumMode)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"ChecksumMode\" for \"%s\". The value \"%s\" is not a valid \"ChecksumMode\".', __CLASS__, $this->checksumMode));\n            }\n            $headers['x-amz-checksum-mode'] = $this->checksumMode;\n        }\n\n        // Prepare query\n        $query = [];\n        if (null !== $this->responseCacheControl) {\n            $query['response-cache-control'] = $this->responseCacheControl;\n        }\n        if (null !== $this->responseContentDisposition) {\n            $query['response-content-disposition'] = $this->responseContentDisposition;\n        }\n        if (null !== $this->responseContentEncoding) {\n            $query['response-content-encoding'] = $this->responseContentEncoding;\n        }\n        if (null !== $this->responseContentLanguage) {\n            $query['response-content-language'] = $this->responseContentLanguage;\n        }\n        if (null !== $this->responseContentType) {\n            $query['response-content-type'] = $this->responseContentType;\n        }\n        if (null !== $this->responseExpires) {\n            $query['response-expires'] = $this->responseExpires->setTimezone(new \\DateTimeZone('GMT'))->format(\\DateTimeInterface::RFC7231);\n        }\n        if (null !== $this->versionId) {\n            $query['versionId'] = $this->versionId;\n        }\n        if (null !== $this->partNumber) {\n            $query['partNumber'] = (string) $this->partNumber;\n        }\n\n        // Prepare URI\n        $uri = [];\n        if (null === $v = $this->bucket) {\n            throw new InvalidArgument(sprintf('Missing parameter \"Bucket\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        $uri['Bucket'] = $v;\n        if (null === $v = $this->key) {\n            throw new InvalidArgument(sprintf('Missing parameter \"Key\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        $uri['Key'] = $v;\n        $uriString = '/' . rawurlencode($uri['Bucket']) . '/' . str_replace('%2F', '/', rawurlencode($uri['Key']));\n\n        // Prepare Body\n        $body = '';\n\n        // Return the Request\n        return new Request('GET', $uriString, $query, $headers, StreamFactory::create($body));\n    }\n\n    public function setBucket(?string $value): self\n    {\n        $this->bucket = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param ChecksumMode::*|null $value\n     */\n    public function setChecksumMode(?string $value): self\n    {\n        $this->checksumMode = $value;\n\n        return $this;\n    }\n\n    public function setExpectedBucketOwner(?string $value): self\n    {\n        $this->expectedBucketOwner = $value;\n\n        return $this;\n    }\n\n    public function setIfMatch(?string $value): self\n    {\n        $this->ifMatch = $value;\n\n        return $this;\n    }\n\n    public function setIfModifiedSince(?\\DateTimeImmutable $value): self\n    {\n        $this->ifModifiedSince = $value;\n\n        return $this;\n    }\n\n    public function setIfNoneMatch(?string $value): self\n    {\n        $this->ifNoneMatch = $value;\n\n        return $this;\n    }\n\n    public function setIfUnmodifiedSince(?\\DateTimeImmutable $value): self\n    {\n        $this->ifUnmodifiedSince = $value;\n\n        return $this;\n    }\n\n    public function setKey(?string $value): self\n    {\n        $this->key = $value;\n\n        return $this;\n    }\n\n    public function setPartNumber(?int $value): self\n    {\n        $this->partNumber = $value;\n\n        return $this;\n    }\n\n    public function setRange(?string $value): self\n    {\n        $this->range = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param RequestPayer::*|null $value\n     */\n    public function setRequestPayer(?string $value): self\n    {\n        $this->requestPayer = $value;\n\n        return $this;\n    }\n\n    public function setResponseCacheControl(?string $value): self\n    {\n        $this->responseCacheControl = $value;\n\n        return $this;\n    }\n\n    public function setResponseContentDisposition(?string $value): self\n    {\n        $this->responseContentDisposition = $value;\n\n        return $this;\n    }\n\n    public function setResponseContentEncoding(?string $value): self\n    {\n        $this->responseContentEncoding = $value;\n\n        return $this;\n    }\n\n    public function setResponseContentLanguage(?string $value): self\n    {\n        $this->responseContentLanguage = $value;\n\n        return $this;\n    }\n\n    public function setResponseContentType(?string $value): self\n    {\n        $this->responseContentType = $value;\n\n        return $this;\n    }\n\n    public function setResponseExpires(?\\DateTimeImmutable $value): self\n    {\n        $this->responseExpires = $value;\n\n        return $this;\n    }\n\n    public function setSseCustomerAlgorithm(?string $value): self\n    {\n        $this->sseCustomerAlgorithm = $value;\n\n        return $this;\n    }\n\n    public function setSseCustomerKey(?string $value): self\n    {\n        $this->sseCustomerKey = $value;\n\n        return $this;\n    }\n\n    public function setSseCustomerKeyMd5(?string $value): self\n    {\n        $this->sseCustomerKeyMd5 = $value;\n\n        return $this;\n    }\n\n    public function setVersionId(?string $value): self\n    {\n        $this->versionId = $value;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Input/HeadBucketRequest.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Input;\n\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\nuse AsyncAws\\Core\\Input;\nuse AsyncAws\\Core\\Request;\nuse AsyncAws\\Core\\Stream\\StreamFactory;\n\nfinal class HeadBucketRequest extends Input\n{\n    /**\n     * The bucket name.\n     *\n     * When using this action with an access point, you must direct requests to the access point hostname. The access point\n     * hostname takes the form *AccessPointName*-*AccountId*.s3-accesspoint.*Region*.amazonaws.com. When using this action\n     * with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket\n     * name. For more information about access point ARNs, see Using access points [^1] in the *Amazon S3 User Guide*.\n     *\n     * When you use this action with an Object Lambda access point, provide the alias of the Object Lambda access point in\n     * place of the bucket name. If the Object Lambda access point alias in a request is not valid, the error code\n     * `InvalidAccessPointAliasError` is returned. For more information about `InvalidAccessPointAliasError`, see List of\n     * Error Codes [^2].\n     *\n     * When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3\n     * on Outposts hostname takes the form `*AccessPointName*-*AccountId*.*outpostID*.s3-outposts.*Region*.amazonaws.com`.\n     * When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access\n     * point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts\n     * [^3] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html\n     * [^2]: https://docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html#ErrorCodeList\n     * [^3]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html\n     *\n     * @required\n     *\n     * @var string|null\n     */\n    private $bucket;\n\n    /**\n     * The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with\n     * the HTTP status code `403 Forbidden` (access denied).\n     *\n     * @var string|null\n     */\n    private $expectedBucketOwner;\n\n    /**\n     * @param array{\n     *   Bucket?: string,\n     *   ExpectedBucketOwner?: string,\n     *\n     *   @region?: string,\n     * } $input\n     */\n    public function __construct(array $input = [])\n    {\n        $this->bucket = $input['Bucket'] ?? null;\n        $this->expectedBucketOwner = $input['ExpectedBucketOwner'] ?? null;\n        parent::__construct($input);\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    public function getBucket(): ?string\n    {\n        return $this->bucket;\n    }\n\n    public function getExpectedBucketOwner(): ?string\n    {\n        return $this->expectedBucketOwner;\n    }\n\n    /**\n     * @internal\n     */\n    public function request(): Request\n    {\n        // Prepare headers\n        $headers = ['content-type' => 'application/xml'];\n        if (null !== $this->expectedBucketOwner) {\n            $headers['x-amz-expected-bucket-owner'] = $this->expectedBucketOwner;\n        }\n\n        // Prepare query\n        $query = [];\n\n        // Prepare URI\n        $uri = [];\n        if (null === $v = $this->bucket) {\n            throw new InvalidArgument(sprintf('Missing parameter \"Bucket\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        $uri['Bucket'] = $v;\n        $uriString = '/' . rawurlencode($uri['Bucket']);\n\n        // Prepare Body\n        $body = '';\n\n        // Return the Request\n        return new Request('HEAD', $uriString, $query, $headers, StreamFactory::create($body));\n    }\n\n    public function setBucket(?string $value): self\n    {\n        $this->bucket = $value;\n\n        return $this;\n    }\n\n    public function setExpectedBucketOwner(?string $value): self\n    {\n        $this->expectedBucketOwner = $value;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Input/HeadObjectRequest.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Input;\n\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\nuse AsyncAws\\Core\\Input;\nuse AsyncAws\\Core\\Request;\nuse AsyncAws\\Core\\Stream\\StreamFactory;\nuse AsyncAws\\S3\\Enum\\ChecksumMode;\nuse AsyncAws\\S3\\Enum\\RequestPayer;\n\nfinal class HeadObjectRequest extends Input\n{\n    /**\n     * The name of the bucket containing the object.\n     *\n     * When using this action with an access point, you must direct requests to the access point hostname. The access point\n     * hostname takes the form *AccessPointName*-*AccountId*.s3-accesspoint.*Region*.amazonaws.com. When using this action\n     * with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket\n     * name. For more information about access point ARNs, see Using access points [^1] in the *Amazon S3 User Guide*.\n     *\n     * When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3\n     * on Outposts hostname takes the form `*AccessPointName*-*AccountId*.*outpostID*.s3-outposts.*Region*.amazonaws.com`.\n     * When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access\n     * point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts\n     * [^2] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html\n     * [^2]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html\n     *\n     * @required\n     *\n     * @var string|null\n     */\n    private $bucket;\n\n    /**\n     * Return the object only if its entity tag (ETag) is the same as the one specified; otherwise, return a 412\n     * (precondition failed) error.\n     *\n     * @var string|null\n     */\n    private $ifMatch;\n\n    /**\n     * Return the object only if it has been modified since the specified time; otherwise, return a 304 (not modified)\n     * error.\n     *\n     * @var \\DateTimeImmutable|null\n     */\n    private $ifModifiedSince;\n\n    /**\n     * Return the object only if its entity tag (ETag) is different from the one specified; otherwise, return a 304 (not\n     * modified) error.\n     *\n     * @var string|null\n     */\n    private $ifNoneMatch;\n\n    /**\n     * Return the object only if it has not been modified since the specified time; otherwise, return a 412 (precondition\n     * failed) error.\n     *\n     * @var \\DateTimeImmutable|null\n     */\n    private $ifUnmodifiedSince;\n\n    /**\n     * The object key.\n     *\n     * @required\n     *\n     * @var string|null\n     */\n    private $key;\n\n    /**\n     * HeadObject returns only the metadata for an object. If the Range is satisfiable, only the `ContentLength` is affected\n     * in the response. If the Range is not satisfiable, S3 returns a `416 - Requested Range Not Satisfiable` error.\n     *\n     * @var string|null\n     */\n    private $range;\n\n    /**\n     * VersionId used to reference a specific version of the object.\n     *\n     * @var string|null\n     */\n    private $versionId;\n\n    /**\n     * Specifies the algorithm to use to when encrypting the object (for example, AES256).\n     *\n     * @var string|null\n     */\n    private $sseCustomerAlgorithm;\n\n    /**\n     * Specifies the customer-provided encryption key for Amazon S3 to use in encrypting data. This value is used to store\n     * the object and then it is discarded; Amazon S3 does not store the encryption key. The key must be appropriate for use\n     * with the algorithm specified in the `x-amz-server-side-encryption-customer-algorithm` header.\n     *\n     * @var string|null\n     */\n    private $sseCustomerKey;\n\n    /**\n     * Specifies the 128-bit MD5 digest of the encryption key according to RFC 1321. Amazon S3 uses this header for a\n     * message integrity check to ensure that the encryption key was transmitted without error.\n     *\n     * @var string|null\n     */\n    private $sseCustomerKeyMd5;\n\n    /**\n     * @var RequestPayer::*|null\n     */\n    private $requestPayer;\n\n    /**\n     * Part number of the object being read. This is a positive integer between 1 and 10,000. Effectively performs a\n     * 'ranged' HEAD request for the part specified. Useful querying about the size of the part and the number of parts in\n     * this object.\n     *\n     * @var int|null\n     */\n    private $partNumber;\n\n    /**\n     * The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with\n     * the HTTP status code `403 Forbidden` (access denied).\n     *\n     * @var string|null\n     */\n    private $expectedBucketOwner;\n\n    /**\n     * To retrieve the checksum, this parameter must be enabled.\n     *\n     * In addition, if you enable `ChecksumMode` and the object is encrypted with Amazon Web Services Key Management Service\n     * (Amazon Web Services KMS), you must have permission to use the `kms:Decrypt` action for the request to succeed.\n     *\n     * @var ChecksumMode::*|null\n     */\n    private $checksumMode;\n\n    /**\n     * @param array{\n     *   Bucket?: string,\n     *   IfMatch?: string,\n     *   IfModifiedSince?: \\DateTimeImmutable|string,\n     *   IfNoneMatch?: string,\n     *   IfUnmodifiedSince?: \\DateTimeImmutable|string,\n     *   Key?: string,\n     *   Range?: string,\n     *   VersionId?: string,\n     *   SSECustomerAlgorithm?: string,\n     *   SSECustomerKey?: string,\n     *   SSECustomerKeyMD5?: string,\n     *   RequestPayer?: RequestPayer::*,\n     *   PartNumber?: int,\n     *   ExpectedBucketOwner?: string,\n     *   ChecksumMode?: ChecksumMode::*,\n     *\n     *   @region?: string,\n     * } $input\n     */\n    public function __construct(array $input = [])\n    {\n        $this->bucket = $input['Bucket'] ?? null;\n        $this->ifMatch = $input['IfMatch'] ?? null;\n        $this->ifModifiedSince = !isset($input['IfModifiedSince']) ? null : ($input['IfModifiedSince'] instanceof \\DateTimeImmutable ? $input['IfModifiedSince'] : new \\DateTimeImmutable($input['IfModifiedSince']));\n        $this->ifNoneMatch = $input['IfNoneMatch'] ?? null;\n        $this->ifUnmodifiedSince = !isset($input['IfUnmodifiedSince']) ? null : ($input['IfUnmodifiedSince'] instanceof \\DateTimeImmutable ? $input['IfUnmodifiedSince'] : new \\DateTimeImmutable($input['IfUnmodifiedSince']));\n        $this->key = $input['Key'] ?? null;\n        $this->range = $input['Range'] ?? null;\n        $this->versionId = $input['VersionId'] ?? null;\n        $this->sseCustomerAlgorithm = $input['SSECustomerAlgorithm'] ?? null;\n        $this->sseCustomerKey = $input['SSECustomerKey'] ?? null;\n        $this->sseCustomerKeyMd5 = $input['SSECustomerKeyMD5'] ?? null;\n        $this->requestPayer = $input['RequestPayer'] ?? null;\n        $this->partNumber = $input['PartNumber'] ?? null;\n        $this->expectedBucketOwner = $input['ExpectedBucketOwner'] ?? null;\n        $this->checksumMode = $input['ChecksumMode'] ?? null;\n        parent::__construct($input);\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    public function getBucket(): ?string\n    {\n        return $this->bucket;\n    }\n\n    /**\n     * @return ChecksumMode::*|null\n     */\n    public function getChecksumMode(): ?string\n    {\n        return $this->checksumMode;\n    }\n\n    public function getExpectedBucketOwner(): ?string\n    {\n        return $this->expectedBucketOwner;\n    }\n\n    public function getIfMatch(): ?string\n    {\n        return $this->ifMatch;\n    }\n\n    public function getIfModifiedSince(): ?\\DateTimeImmutable\n    {\n        return $this->ifModifiedSince;\n    }\n\n    public function getIfNoneMatch(): ?string\n    {\n        return $this->ifNoneMatch;\n    }\n\n    public function getIfUnmodifiedSince(): ?\\DateTimeImmutable\n    {\n        return $this->ifUnmodifiedSince;\n    }\n\n    public function getKey(): ?string\n    {\n        return $this->key;\n    }\n\n    public function getPartNumber(): ?int\n    {\n        return $this->partNumber;\n    }\n\n    public function getRange(): ?string\n    {\n        return $this->range;\n    }\n\n    /**\n     * @return RequestPayer::*|null\n     */\n    public function getRequestPayer(): ?string\n    {\n        return $this->requestPayer;\n    }\n\n    public function getSseCustomerAlgorithm(): ?string\n    {\n        return $this->sseCustomerAlgorithm;\n    }\n\n    public function getSseCustomerKey(): ?string\n    {\n        return $this->sseCustomerKey;\n    }\n\n    public function getSseCustomerKeyMd5(): ?string\n    {\n        return $this->sseCustomerKeyMd5;\n    }\n\n    public function getVersionId(): ?string\n    {\n        return $this->versionId;\n    }\n\n    /**\n     * @internal\n     */\n    public function request(): Request\n    {\n        // Prepare headers\n        $headers = ['content-type' => 'application/xml'];\n        if (null !== $this->ifMatch) {\n            $headers['If-Match'] = $this->ifMatch;\n        }\n        if (null !== $this->ifModifiedSince) {\n            $headers['If-Modified-Since'] = $this->ifModifiedSince->setTimezone(new \\DateTimeZone('GMT'))->format(\\DateTimeInterface::RFC7231);\n        }\n        if (null !== $this->ifNoneMatch) {\n            $headers['If-None-Match'] = $this->ifNoneMatch;\n        }\n        if (null !== $this->ifUnmodifiedSince) {\n            $headers['If-Unmodified-Since'] = $this->ifUnmodifiedSince->setTimezone(new \\DateTimeZone('GMT'))->format(\\DateTimeInterface::RFC7231);\n        }\n        if (null !== $this->range) {\n            $headers['Range'] = $this->range;\n        }\n        if (null !== $this->sseCustomerAlgorithm) {\n            $headers['x-amz-server-side-encryption-customer-algorithm'] = $this->sseCustomerAlgorithm;\n        }\n        if (null !== $this->sseCustomerKey) {\n            $headers['x-amz-server-side-encryption-customer-key'] = $this->sseCustomerKey;\n        }\n        if (null !== $this->sseCustomerKeyMd5) {\n            $headers['x-amz-server-side-encryption-customer-key-MD5'] = $this->sseCustomerKeyMd5;\n        }\n        if (null !== $this->requestPayer) {\n            if (!RequestPayer::exists($this->requestPayer)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"RequestPayer\" for \"%s\". The value \"%s\" is not a valid \"RequestPayer\".', __CLASS__, $this->requestPayer));\n            }\n            $headers['x-amz-request-payer'] = $this->requestPayer;\n        }\n        if (null !== $this->expectedBucketOwner) {\n            $headers['x-amz-expected-bucket-owner'] = $this->expectedBucketOwner;\n        }\n        if (null !== $this->checksumMode) {\n            if (!ChecksumMode::exists($this->checksumMode)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"ChecksumMode\" for \"%s\". The value \"%s\" is not a valid \"ChecksumMode\".', __CLASS__, $this->checksumMode));\n            }\n            $headers['x-amz-checksum-mode'] = $this->checksumMode;\n        }\n\n        // Prepare query\n        $query = [];\n        if (null !== $this->versionId) {\n            $query['versionId'] = $this->versionId;\n        }\n        if (null !== $this->partNumber) {\n            $query['partNumber'] = (string) $this->partNumber;\n        }\n\n        // Prepare URI\n        $uri = [];\n        if (null === $v = $this->bucket) {\n            throw new InvalidArgument(sprintf('Missing parameter \"Bucket\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        $uri['Bucket'] = $v;\n        if (null === $v = $this->key) {\n            throw new InvalidArgument(sprintf('Missing parameter \"Key\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        $uri['Key'] = $v;\n        $uriString = '/' . rawurlencode($uri['Bucket']) . '/' . str_replace('%2F', '/', rawurlencode($uri['Key']));\n\n        // Prepare Body\n        $body = '';\n\n        // Return the Request\n        return new Request('HEAD', $uriString, $query, $headers, StreamFactory::create($body));\n    }\n\n    public function setBucket(?string $value): self\n    {\n        $this->bucket = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param ChecksumMode::*|null $value\n     */\n    public function setChecksumMode(?string $value): self\n    {\n        $this->checksumMode = $value;\n\n        return $this;\n    }\n\n    public function setExpectedBucketOwner(?string $value): self\n    {\n        $this->expectedBucketOwner = $value;\n\n        return $this;\n    }\n\n    public function setIfMatch(?string $value): self\n    {\n        $this->ifMatch = $value;\n\n        return $this;\n    }\n\n    public function setIfModifiedSince(?\\DateTimeImmutable $value): self\n    {\n        $this->ifModifiedSince = $value;\n\n        return $this;\n    }\n\n    public function setIfNoneMatch(?string $value): self\n    {\n        $this->ifNoneMatch = $value;\n\n        return $this;\n    }\n\n    public function setIfUnmodifiedSince(?\\DateTimeImmutable $value): self\n    {\n        $this->ifUnmodifiedSince = $value;\n\n        return $this;\n    }\n\n    public function setKey(?string $value): self\n    {\n        $this->key = $value;\n\n        return $this;\n    }\n\n    public function setPartNumber(?int $value): self\n    {\n        $this->partNumber = $value;\n\n        return $this;\n    }\n\n    public function setRange(?string $value): self\n    {\n        $this->range = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param RequestPayer::*|null $value\n     */\n    public function setRequestPayer(?string $value): self\n    {\n        $this->requestPayer = $value;\n\n        return $this;\n    }\n\n    public function setSseCustomerAlgorithm(?string $value): self\n    {\n        $this->sseCustomerAlgorithm = $value;\n\n        return $this;\n    }\n\n    public function setSseCustomerKey(?string $value): self\n    {\n        $this->sseCustomerKey = $value;\n\n        return $this;\n    }\n\n    public function setSseCustomerKeyMd5(?string $value): self\n    {\n        $this->sseCustomerKeyMd5 = $value;\n\n        return $this;\n    }\n\n    public function setVersionId(?string $value): self\n    {\n        $this->versionId = $value;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Input/ListBucketsRequest.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Input;\n\nuse AsyncAws\\Core\\Input;\nuse AsyncAws\\Core\\Request;\nuse AsyncAws\\Core\\Stream\\StreamFactory;\n\nfinal class ListBucketsRequest extends Input\n{\n    /**\n     * @param array{\n     *\n     *   @region?: string,\n     * } $input\n     */\n    public function __construct(array $input = [])\n    {\n        parent::__construct($input);\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    /**\n     * @internal\n     */\n    public function request(): Request\n    {\n        // Prepare headers\n        $headers = ['content-type' => 'application/xml'];\n\n        // Prepare query\n        $query = [];\n\n        // Prepare URI\n        $uriString = '/';\n\n        // Prepare Body\n        $body = '';\n\n        // Return the Request\n        return new Request('GET', $uriString, $query, $headers, StreamFactory::create($body));\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Input/ListMultipartUploadsRequest.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Input;\n\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\nuse AsyncAws\\Core\\Input;\nuse AsyncAws\\Core\\Request;\nuse AsyncAws\\Core\\Stream\\StreamFactory;\nuse AsyncAws\\S3\\Enum\\EncodingType;\nuse AsyncAws\\S3\\Enum\\RequestPayer;\n\nfinal class ListMultipartUploadsRequest extends Input\n{\n    /**\n     * The name of the bucket to which the multipart upload was initiated.\n     *\n     * When using this action with an access point, you must direct requests to the access point hostname. The access point\n     * hostname takes the form *AccessPointName*-*AccountId*.s3-accesspoint.*Region*.amazonaws.com. When using this action\n     * with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket\n     * name. For more information about access point ARNs, see Using access points [^1] in the *Amazon S3 User Guide*.\n     *\n     * When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3\n     * on Outposts hostname takes the form `*AccessPointName*-*AccountId*.*outpostID*.s3-outposts.*Region*.amazonaws.com`.\n     * When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access\n     * point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts\n     * [^2] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html\n     * [^2]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html\n     *\n     * @required\n     *\n     * @var string|null\n     */\n    private $bucket;\n\n    /**\n     * Character you use to group keys.\n     *\n     * All keys that contain the same string between the prefix, if specified, and the first occurrence of the delimiter\n     * after the prefix are grouped under a single result element, `CommonPrefixes`. If you don't specify the prefix\n     * parameter, then the substring starts at the beginning of the key. The keys that are grouped under `CommonPrefixes`\n     * result element are not returned elsewhere in the response.\n     *\n     * @var string|null\n     */\n    private $delimiter;\n\n    /**\n     * @var EncodingType::*|null\n     */\n    private $encodingType;\n\n    /**\n     * Together with upload-id-marker, this parameter specifies the multipart upload after which listing should begin.\n     *\n     * If `upload-id-marker` is not specified, only the keys lexicographically greater than the specified `key-marker` will\n     * be included in the list.\n     *\n     * If `upload-id-marker` is specified, any multipart uploads for a key equal to the `key-marker` might also be included,\n     * provided those multipart uploads have upload IDs lexicographically greater than the specified `upload-id-marker`.\n     *\n     * @var string|null\n     */\n    private $keyMarker;\n\n    /**\n     * Sets the maximum number of multipart uploads, from 1 to 1,000, to return in the response body. 1,000 is the maximum\n     * number of uploads that can be returned in a response.\n     *\n     * @var int|null\n     */\n    private $maxUploads;\n\n    /**\n     * Lists in-progress uploads only for those keys that begin with the specified prefix. You can use prefixes to separate\n     * a bucket into different grouping of keys. (You can think of using prefix to make groups in the same way you'd use a\n     * folder in a file system.).\n     *\n     * @var string|null\n     */\n    private $prefix;\n\n    /**\n     * Together with key-marker, specifies the multipart upload after which listing should begin. If key-marker is not\n     * specified, the upload-id-marker parameter is ignored. Otherwise, any multipart uploads for a key equal to the\n     * key-marker might be included in the list only if they have an upload ID lexicographically greater than the specified\n     * `upload-id-marker`.\n     *\n     * @var string|null\n     */\n    private $uploadIdMarker;\n\n    /**\n     * The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with\n     * the HTTP status code `403 Forbidden` (access denied).\n     *\n     * @var string|null\n     */\n    private $expectedBucketOwner;\n\n    /**\n     * @var RequestPayer::*|null\n     */\n    private $requestPayer;\n\n    /**\n     * @param array{\n     *   Bucket?: string,\n     *   Delimiter?: string,\n     *   EncodingType?: EncodingType::*,\n     *   KeyMarker?: string,\n     *   MaxUploads?: int,\n     *   Prefix?: string,\n     *   UploadIdMarker?: string,\n     *   ExpectedBucketOwner?: string,\n     *   RequestPayer?: RequestPayer::*,\n     *\n     *   @region?: string,\n     * } $input\n     */\n    public function __construct(array $input = [])\n    {\n        $this->bucket = $input['Bucket'] ?? null;\n        $this->delimiter = $input['Delimiter'] ?? null;\n        $this->encodingType = $input['EncodingType'] ?? null;\n        $this->keyMarker = $input['KeyMarker'] ?? null;\n        $this->maxUploads = $input['MaxUploads'] ?? null;\n        $this->prefix = $input['Prefix'] ?? null;\n        $this->uploadIdMarker = $input['UploadIdMarker'] ?? null;\n        $this->expectedBucketOwner = $input['ExpectedBucketOwner'] ?? null;\n        $this->requestPayer = $input['RequestPayer'] ?? null;\n        parent::__construct($input);\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    public function getBucket(): ?string\n    {\n        return $this->bucket;\n    }\n\n    public function getDelimiter(): ?string\n    {\n        return $this->delimiter;\n    }\n\n    /**\n     * @return EncodingType::*|null\n     */\n    public function getEncodingType(): ?string\n    {\n        return $this->encodingType;\n    }\n\n    public function getExpectedBucketOwner(): ?string\n    {\n        return $this->expectedBucketOwner;\n    }\n\n    public function getKeyMarker(): ?string\n    {\n        return $this->keyMarker;\n    }\n\n    public function getMaxUploads(): ?int\n    {\n        return $this->maxUploads;\n    }\n\n    public function getPrefix(): ?string\n    {\n        return $this->prefix;\n    }\n\n    /**\n     * @return RequestPayer::*|null\n     */\n    public function getRequestPayer(): ?string\n    {\n        return $this->requestPayer;\n    }\n\n    public function getUploadIdMarker(): ?string\n    {\n        return $this->uploadIdMarker;\n    }\n\n    /**\n     * @internal\n     */\n    public function request(): Request\n    {\n        // Prepare headers\n        $headers = ['content-type' => 'application/xml'];\n        if (null !== $this->expectedBucketOwner) {\n            $headers['x-amz-expected-bucket-owner'] = $this->expectedBucketOwner;\n        }\n        if (null !== $this->requestPayer) {\n            if (!RequestPayer::exists($this->requestPayer)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"RequestPayer\" for \"%s\". The value \"%s\" is not a valid \"RequestPayer\".', __CLASS__, $this->requestPayer));\n            }\n            $headers['x-amz-request-payer'] = $this->requestPayer;\n        }\n\n        // Prepare query\n        $query = [];\n        if (null !== $this->delimiter) {\n            $query['delimiter'] = $this->delimiter;\n        }\n        if (null !== $this->encodingType) {\n            if (!EncodingType::exists($this->encodingType)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"EncodingType\" for \"%s\". The value \"%s\" is not a valid \"EncodingType\".', __CLASS__, $this->encodingType));\n            }\n            $query['encoding-type'] = $this->encodingType;\n        }\n        if (null !== $this->keyMarker) {\n            $query['key-marker'] = $this->keyMarker;\n        }\n        if (null !== $this->maxUploads) {\n            $query['max-uploads'] = (string) $this->maxUploads;\n        }\n        if (null !== $this->prefix) {\n            $query['prefix'] = $this->prefix;\n        }\n        if (null !== $this->uploadIdMarker) {\n            $query['upload-id-marker'] = $this->uploadIdMarker;\n        }\n\n        // Prepare URI\n        $uri = [];\n        if (null === $v = $this->bucket) {\n            throw new InvalidArgument(sprintf('Missing parameter \"Bucket\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        $uri['Bucket'] = $v;\n        $uriString = '/' . rawurlencode($uri['Bucket']) . '?uploads';\n\n        // Prepare Body\n        $body = '';\n\n        // Return the Request\n        return new Request('GET', $uriString, $query, $headers, StreamFactory::create($body));\n    }\n\n    public function setBucket(?string $value): self\n    {\n        $this->bucket = $value;\n\n        return $this;\n    }\n\n    public function setDelimiter(?string $value): self\n    {\n        $this->delimiter = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param EncodingType::*|null $value\n     */\n    public function setEncodingType(?string $value): self\n    {\n        $this->encodingType = $value;\n\n        return $this;\n    }\n\n    public function setExpectedBucketOwner(?string $value): self\n    {\n        $this->expectedBucketOwner = $value;\n\n        return $this;\n    }\n\n    public function setKeyMarker(?string $value): self\n    {\n        $this->keyMarker = $value;\n\n        return $this;\n    }\n\n    public function setMaxUploads(?int $value): self\n    {\n        $this->maxUploads = $value;\n\n        return $this;\n    }\n\n    public function setPrefix(?string $value): self\n    {\n        $this->prefix = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param RequestPayer::*|null $value\n     */\n    public function setRequestPayer(?string $value): self\n    {\n        $this->requestPayer = $value;\n\n        return $this;\n    }\n\n    public function setUploadIdMarker(?string $value): self\n    {\n        $this->uploadIdMarker = $value;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Input/ListObjectsV2Request.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Input;\n\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\nuse AsyncAws\\Core\\Input;\nuse AsyncAws\\Core\\Request;\nuse AsyncAws\\Core\\Stream\\StreamFactory;\nuse AsyncAws\\S3\\Enum\\EncodingType;\nuse AsyncAws\\S3\\Enum\\RequestPayer;\n\nfinal class ListObjectsV2Request extends Input\n{\n    /**\n     * Bucket name to list.\n     *\n     * When using this action with an access point, you must direct requests to the access point hostname. The access point\n     * hostname takes the form *AccessPointName*-*AccountId*.s3-accesspoint.*Region*.amazonaws.com. When using this action\n     * with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket\n     * name. For more information about access point ARNs, see Using access points [^1] in the *Amazon S3 User Guide*.\n     *\n     * When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3\n     * on Outposts hostname takes the form `*AccessPointName*-*AccountId*.*outpostID*.s3-outposts.*Region*.amazonaws.com`.\n     * When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access\n     * point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts\n     * [^2] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html\n     * [^2]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html\n     *\n     * @required\n     *\n     * @var string|null\n     */\n    private $bucket;\n\n    /**\n     * A delimiter is a character you use to group keys.\n     *\n     * @var string|null\n     */\n    private $delimiter;\n\n    /**\n     * Encoding type used by Amazon S3 to encode object keys in the response.\n     *\n     * @var EncodingType::*|null\n     */\n    private $encodingType;\n\n    /**\n     * Sets the maximum number of keys returned in the response. By default the action returns up to 1,000 key names. The\n     * response might contain fewer keys but will never contain more.\n     *\n     * @var int|null\n     */\n    private $maxKeys;\n\n    /**\n     * Limits the response to keys that begin with the specified prefix.\n     *\n     * @var string|null\n     */\n    private $prefix;\n\n    /**\n     * ContinuationToken indicates Amazon S3 that the list is being continued on this bucket with a token. ContinuationToken\n     * is obfuscated and is not a real key.\n     *\n     * @var string|null\n     */\n    private $continuationToken;\n\n    /**\n     * The owner field is not present in listV2 by default, if you want to return owner field with each key in the result\n     * then set the fetch owner field to true.\n     *\n     * @var bool|null\n     */\n    private $fetchOwner;\n\n    /**\n     * StartAfter is where you want Amazon S3 to start listing from. Amazon S3 starts listing after this specified key.\n     * StartAfter can be any key in the bucket.\n     *\n     * @var string|null\n     */\n    private $startAfter;\n\n    /**\n     * Confirms that the requester knows that she or he will be charged for the list objects request in V2 style. Bucket\n     * owners need not specify this parameter in their requests.\n     *\n     * @var RequestPayer::*|null\n     */\n    private $requestPayer;\n\n    /**\n     * The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with\n     * the HTTP status code `403 Forbidden` (access denied).\n     *\n     * @var string|null\n     */\n    private $expectedBucketOwner;\n\n    /**\n     * @param array{\n     *   Bucket?: string,\n     *   Delimiter?: string,\n     *   EncodingType?: EncodingType::*,\n     *   MaxKeys?: int,\n     *   Prefix?: string,\n     *   ContinuationToken?: string,\n     *   FetchOwner?: bool,\n     *   StartAfter?: string,\n     *   RequestPayer?: RequestPayer::*,\n     *   ExpectedBucketOwner?: string,\n     *\n     *   @region?: string,\n     * } $input\n     */\n    public function __construct(array $input = [])\n    {\n        $this->bucket = $input['Bucket'] ?? null;\n        $this->delimiter = $input['Delimiter'] ?? null;\n        $this->encodingType = $input['EncodingType'] ?? null;\n        $this->maxKeys = $input['MaxKeys'] ?? null;\n        $this->prefix = $input['Prefix'] ?? null;\n        $this->continuationToken = $input['ContinuationToken'] ?? null;\n        $this->fetchOwner = $input['FetchOwner'] ?? null;\n        $this->startAfter = $input['StartAfter'] ?? null;\n        $this->requestPayer = $input['RequestPayer'] ?? null;\n        $this->expectedBucketOwner = $input['ExpectedBucketOwner'] ?? null;\n        parent::__construct($input);\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    public function getBucket(): ?string\n    {\n        return $this->bucket;\n    }\n\n    public function getContinuationToken(): ?string\n    {\n        return $this->continuationToken;\n    }\n\n    public function getDelimiter(): ?string\n    {\n        return $this->delimiter;\n    }\n\n    /**\n     * @return EncodingType::*|null\n     */\n    public function getEncodingType(): ?string\n    {\n        return $this->encodingType;\n    }\n\n    public function getExpectedBucketOwner(): ?string\n    {\n        return $this->expectedBucketOwner;\n    }\n\n    public function getFetchOwner(): ?bool\n    {\n        return $this->fetchOwner;\n    }\n\n    public function getMaxKeys(): ?int\n    {\n        return $this->maxKeys;\n    }\n\n    public function getPrefix(): ?string\n    {\n        return $this->prefix;\n    }\n\n    /**\n     * @return RequestPayer::*|null\n     */\n    public function getRequestPayer(): ?string\n    {\n        return $this->requestPayer;\n    }\n\n    public function getStartAfter(): ?string\n    {\n        return $this->startAfter;\n    }\n\n    /**\n     * @internal\n     */\n    public function request(): Request\n    {\n        // Prepare headers\n        $headers = ['content-type' => 'application/xml'];\n        if (null !== $this->requestPayer) {\n            if (!RequestPayer::exists($this->requestPayer)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"RequestPayer\" for \"%s\". The value \"%s\" is not a valid \"RequestPayer\".', __CLASS__, $this->requestPayer));\n            }\n            $headers['x-amz-request-payer'] = $this->requestPayer;\n        }\n        if (null !== $this->expectedBucketOwner) {\n            $headers['x-amz-expected-bucket-owner'] = $this->expectedBucketOwner;\n        }\n\n        // Prepare query\n        $query = [];\n        if (null !== $this->delimiter) {\n            $query['delimiter'] = $this->delimiter;\n        }\n        if (null !== $this->encodingType) {\n            if (!EncodingType::exists($this->encodingType)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"EncodingType\" for \"%s\". The value \"%s\" is not a valid \"EncodingType\".', __CLASS__, $this->encodingType));\n            }\n            $query['encoding-type'] = $this->encodingType;\n        }\n        if (null !== $this->maxKeys) {\n            $query['max-keys'] = (string) $this->maxKeys;\n        }\n        if (null !== $this->prefix) {\n            $query['prefix'] = $this->prefix;\n        }\n        if (null !== $this->continuationToken) {\n            $query['continuation-token'] = $this->continuationToken;\n        }\n        if (null !== $this->fetchOwner) {\n            $query['fetch-owner'] = $this->fetchOwner ? 'true' : 'false';\n        }\n        if (null !== $this->startAfter) {\n            $query['start-after'] = $this->startAfter;\n        }\n\n        // Prepare URI\n        $uri = [];\n        if (null === $v = $this->bucket) {\n            throw new InvalidArgument(sprintf('Missing parameter \"Bucket\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        $uri['Bucket'] = $v;\n        $uriString = '/' . rawurlencode($uri['Bucket']) . '?list-type=2';\n\n        // Prepare Body\n        $body = '';\n\n        // Return the Request\n        return new Request('GET', $uriString, $query, $headers, StreamFactory::create($body));\n    }\n\n    public function setBucket(?string $value): self\n    {\n        $this->bucket = $value;\n\n        return $this;\n    }\n\n    public function setContinuationToken(?string $value): self\n    {\n        $this->continuationToken = $value;\n\n        return $this;\n    }\n\n    public function setDelimiter(?string $value): self\n    {\n        $this->delimiter = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param EncodingType::*|null $value\n     */\n    public function setEncodingType(?string $value): self\n    {\n        $this->encodingType = $value;\n\n        return $this;\n    }\n\n    public function setExpectedBucketOwner(?string $value): self\n    {\n        $this->expectedBucketOwner = $value;\n\n        return $this;\n    }\n\n    public function setFetchOwner(?bool $value): self\n    {\n        $this->fetchOwner = $value;\n\n        return $this;\n    }\n\n    public function setMaxKeys(?int $value): self\n    {\n        $this->maxKeys = $value;\n\n        return $this;\n    }\n\n    public function setPrefix(?string $value): self\n    {\n        $this->prefix = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param RequestPayer::*|null $value\n     */\n    public function setRequestPayer(?string $value): self\n    {\n        $this->requestPayer = $value;\n\n        return $this;\n    }\n\n    public function setStartAfter(?string $value): self\n    {\n        $this->startAfter = $value;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Input/ListPartsRequest.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Input;\n\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\nuse AsyncAws\\Core\\Input;\nuse AsyncAws\\Core\\Request;\nuse AsyncAws\\Core\\Stream\\StreamFactory;\nuse AsyncAws\\S3\\Enum\\RequestPayer;\n\nfinal class ListPartsRequest extends Input\n{\n    /**\n     * The name of the bucket to which the parts are being uploaded.\n     *\n     * When using this action with an access point, you must direct requests to the access point hostname. The access point\n     * hostname takes the form *AccessPointName*-*AccountId*.s3-accesspoint.*Region*.amazonaws.com. When using this action\n     * with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket\n     * name. For more information about access point ARNs, see Using access points [^1] in the *Amazon S3 User Guide*.\n     *\n     * When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3\n     * on Outposts hostname takes the form `*AccessPointName*-*AccountId*.*outpostID*.s3-outposts.*Region*.amazonaws.com`.\n     * When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access\n     * point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts\n     * [^2] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html\n     * [^2]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html\n     *\n     * @required\n     *\n     * @var string|null\n     */\n    private $bucket;\n\n    /**\n     * Object key for which the multipart upload was initiated.\n     *\n     * @required\n     *\n     * @var string|null\n     */\n    private $key;\n\n    /**\n     * Sets the maximum number of parts to return.\n     *\n     * @var int|null\n     */\n    private $maxParts;\n\n    /**\n     * Specifies the part after which listing should begin. Only parts with higher part numbers will be listed.\n     *\n     * @var int|null\n     */\n    private $partNumberMarker;\n\n    /**\n     * Upload ID identifying the multipart upload whose parts are being listed.\n     *\n     * @required\n     *\n     * @var string|null\n     */\n    private $uploadId;\n\n    /**\n     * @var RequestPayer::*|null\n     */\n    private $requestPayer;\n\n    /**\n     * The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with\n     * the HTTP status code `403 Forbidden` (access denied).\n     *\n     * @var string|null\n     */\n    private $expectedBucketOwner;\n\n    /**\n     * The server-side encryption (SSE) algorithm used to encrypt the object. This parameter is needed only when the object\n     * was created using a checksum algorithm. For more information, see Protecting data using SSE-C keys [^1] in the\n     * *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerSideEncryptionCustomerKeys.html\n     *\n     * @var string|null\n     */\n    private $sseCustomerAlgorithm;\n\n    /**\n     * The server-side encryption (SSE) customer managed key. This parameter is needed only when the object was created\n     * using a checksum algorithm. For more information, see Protecting data using SSE-C keys [^1] in the *Amazon S3 User\n     * Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerSideEncryptionCustomerKeys.html\n     *\n     * @var string|null\n     */\n    private $sseCustomerKey;\n\n    /**\n     * The MD5 server-side encryption (SSE) customer managed key. This parameter is needed only when the object was created\n     * using a checksum algorithm. For more information, see Protecting data using SSE-C keys [^1] in the *Amazon S3 User\n     * Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerSideEncryptionCustomerKeys.html\n     *\n     * @var string|null\n     */\n    private $sseCustomerKeyMd5;\n\n    /**\n     * @param array{\n     *   Bucket?: string,\n     *   Key?: string,\n     *   MaxParts?: int,\n     *   PartNumberMarker?: int,\n     *   UploadId?: string,\n     *   RequestPayer?: RequestPayer::*,\n     *   ExpectedBucketOwner?: string,\n     *   SSECustomerAlgorithm?: string,\n     *   SSECustomerKey?: string,\n     *   SSECustomerKeyMD5?: string,\n     *\n     *   @region?: string,\n     * } $input\n     */\n    public function __construct(array $input = [])\n    {\n        $this->bucket = $input['Bucket'] ?? null;\n        $this->key = $input['Key'] ?? null;\n        $this->maxParts = $input['MaxParts'] ?? null;\n        $this->partNumberMarker = $input['PartNumberMarker'] ?? null;\n        $this->uploadId = $input['UploadId'] ?? null;\n        $this->requestPayer = $input['RequestPayer'] ?? null;\n        $this->expectedBucketOwner = $input['ExpectedBucketOwner'] ?? null;\n        $this->sseCustomerAlgorithm = $input['SSECustomerAlgorithm'] ?? null;\n        $this->sseCustomerKey = $input['SSECustomerKey'] ?? null;\n        $this->sseCustomerKeyMd5 = $input['SSECustomerKeyMD5'] ?? null;\n        parent::__construct($input);\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    public function getBucket(): ?string\n    {\n        return $this->bucket;\n    }\n\n    public function getExpectedBucketOwner(): ?string\n    {\n        return $this->expectedBucketOwner;\n    }\n\n    public function getKey(): ?string\n    {\n        return $this->key;\n    }\n\n    public function getMaxParts(): ?int\n    {\n        return $this->maxParts;\n    }\n\n    public function getPartNumberMarker(): ?int\n    {\n        return $this->partNumberMarker;\n    }\n\n    /**\n     * @return RequestPayer::*|null\n     */\n    public function getRequestPayer(): ?string\n    {\n        return $this->requestPayer;\n    }\n\n    public function getSseCustomerAlgorithm(): ?string\n    {\n        return $this->sseCustomerAlgorithm;\n    }\n\n    public function getSseCustomerKey(): ?string\n    {\n        return $this->sseCustomerKey;\n    }\n\n    public function getSseCustomerKeyMd5(): ?string\n    {\n        return $this->sseCustomerKeyMd5;\n    }\n\n    public function getUploadId(): ?string\n    {\n        return $this->uploadId;\n    }\n\n    /**\n     * @internal\n     */\n    public function request(): Request\n    {\n        // Prepare headers\n        $headers = ['content-type' => 'application/xml'];\n        if (null !== $this->requestPayer) {\n            if (!RequestPayer::exists($this->requestPayer)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"RequestPayer\" for \"%s\". The value \"%s\" is not a valid \"RequestPayer\".', __CLASS__, $this->requestPayer));\n            }\n            $headers['x-amz-request-payer'] = $this->requestPayer;\n        }\n        if (null !== $this->expectedBucketOwner) {\n            $headers['x-amz-expected-bucket-owner'] = $this->expectedBucketOwner;\n        }\n        if (null !== $this->sseCustomerAlgorithm) {\n            $headers['x-amz-server-side-encryption-customer-algorithm'] = $this->sseCustomerAlgorithm;\n        }\n        if (null !== $this->sseCustomerKey) {\n            $headers['x-amz-server-side-encryption-customer-key'] = $this->sseCustomerKey;\n        }\n        if (null !== $this->sseCustomerKeyMd5) {\n            $headers['x-amz-server-side-encryption-customer-key-MD5'] = $this->sseCustomerKeyMd5;\n        }\n\n        // Prepare query\n        $query = [];\n        if (null !== $this->maxParts) {\n            $query['max-parts'] = (string) $this->maxParts;\n        }\n        if (null !== $this->partNumberMarker) {\n            $query['part-number-marker'] = (string) $this->partNumberMarker;\n        }\n        if (null === $v = $this->uploadId) {\n            throw new InvalidArgument(sprintf('Missing parameter \"UploadId\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        $query['uploadId'] = $v;\n\n        // Prepare URI\n        $uri = [];\n        if (null === $v = $this->bucket) {\n            throw new InvalidArgument(sprintf('Missing parameter \"Bucket\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        $uri['Bucket'] = $v;\n        if (null === $v = $this->key) {\n            throw new InvalidArgument(sprintf('Missing parameter \"Key\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        $uri['Key'] = $v;\n        $uriString = '/' . rawurlencode($uri['Bucket']) . '/' . str_replace('%2F', '/', rawurlencode($uri['Key']));\n\n        // Prepare Body\n        $body = '';\n\n        // Return the Request\n        return new Request('GET', $uriString, $query, $headers, StreamFactory::create($body));\n    }\n\n    public function setBucket(?string $value): self\n    {\n        $this->bucket = $value;\n\n        return $this;\n    }\n\n    public function setExpectedBucketOwner(?string $value): self\n    {\n        $this->expectedBucketOwner = $value;\n\n        return $this;\n    }\n\n    public function setKey(?string $value): self\n    {\n        $this->key = $value;\n\n        return $this;\n    }\n\n    public function setMaxParts(?int $value): self\n    {\n        $this->maxParts = $value;\n\n        return $this;\n    }\n\n    public function setPartNumberMarker(?int $value): self\n    {\n        $this->partNumberMarker = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param RequestPayer::*|null $value\n     */\n    public function setRequestPayer(?string $value): self\n    {\n        $this->requestPayer = $value;\n\n        return $this;\n    }\n\n    public function setSseCustomerAlgorithm(?string $value): self\n    {\n        $this->sseCustomerAlgorithm = $value;\n\n        return $this;\n    }\n\n    public function setSseCustomerKey(?string $value): self\n    {\n        $this->sseCustomerKey = $value;\n\n        return $this;\n    }\n\n    public function setSseCustomerKeyMd5(?string $value): self\n    {\n        $this->sseCustomerKeyMd5 = $value;\n\n        return $this;\n    }\n\n    public function setUploadId(?string $value): self\n    {\n        $this->uploadId = $value;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Input/PutBucketCorsRequest.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Input;\n\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\nuse AsyncAws\\Core\\Input;\nuse AsyncAws\\Core\\Request;\nuse AsyncAws\\Core\\Stream\\StreamFactory;\nuse AsyncAws\\S3\\Enum\\ChecksumAlgorithm;\nuse AsyncAws\\S3\\ValueObject\\CORSConfiguration;\n\nfinal class PutBucketCorsRequest extends Input\n{\n    /**\n     * Specifies the bucket impacted by the `cors`configuration.\n     *\n     * @required\n     *\n     * @var string|null\n     */\n    private $bucket;\n\n    /**\n     * Describes the cross-origin access configuration for objects in an Amazon S3 bucket. For more information, see\n     * Enabling Cross-Origin Resource Sharing [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/dev/cors.html\n     *\n     * @required\n     *\n     * @var CORSConfiguration|null\n     */\n    private $corsConfiguration;\n\n    /**\n     * The base64-encoded 128-bit MD5 digest of the data. This header must be used as a message integrity check to verify\n     * that the request body was not corrupted in transit. For more information, go to RFC 1864. [^1].\n     *\n     * For requests made using the Amazon Web Services Command Line Interface (CLI) or Amazon Web Services SDKs, this field\n     * is calculated automatically.\n     *\n     * [^1]: http://www.ietf.org/rfc/rfc1864.txt\n     *\n     * @var string|null\n     */\n    private $contentMd5;\n\n    /**\n     * Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide\n     * any additional functionality if not using the SDK. When sending this header, there must be a corresponding\n     * `x-amz-checksum` or `x-amz-trailer` header sent. Otherwise, Amazon S3 fails the request with the HTTP status code\n     * `400 Bad Request`. For more information, see Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * If you provide an individual checksum, Amazon S3 ignores any provided `ChecksumAlgorithm` parameter.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html\n     *\n     * @var ChecksumAlgorithm::*|null\n     */\n    private $checksumAlgorithm;\n\n    /**\n     * The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with\n     * the HTTP status code `403 Forbidden` (access denied).\n     *\n     * @var string|null\n     */\n    private $expectedBucketOwner;\n\n    /**\n     * @param array{\n     *   Bucket?: string,\n     *   CORSConfiguration?: CORSConfiguration|array,\n     *   ContentMD5?: string,\n     *   ChecksumAlgorithm?: ChecksumAlgorithm::*,\n     *   ExpectedBucketOwner?: string,\n     *\n     *   @region?: string,\n     * } $input\n     */\n    public function __construct(array $input = [])\n    {\n        $this->bucket = $input['Bucket'] ?? null;\n        $this->corsConfiguration = isset($input['CORSConfiguration']) ? CORSConfiguration::create($input['CORSConfiguration']) : null;\n        $this->contentMd5 = $input['ContentMD5'] ?? null;\n        $this->checksumAlgorithm = $input['ChecksumAlgorithm'] ?? null;\n        $this->expectedBucketOwner = $input['ExpectedBucketOwner'] ?? null;\n        parent::__construct($input);\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    public function getBucket(): ?string\n    {\n        return $this->bucket;\n    }\n\n    /**\n     * @return ChecksumAlgorithm::*|null\n     */\n    public function getChecksumAlgorithm(): ?string\n    {\n        return $this->checksumAlgorithm;\n    }\n\n    public function getContentMd5(): ?string\n    {\n        return $this->contentMd5;\n    }\n\n    public function getCorsConfiguration(): ?CORSConfiguration\n    {\n        return $this->corsConfiguration;\n    }\n\n    public function getExpectedBucketOwner(): ?string\n    {\n        return $this->expectedBucketOwner;\n    }\n\n    /**\n     * @internal\n     */\n    public function request(): Request\n    {\n        // Prepare headers\n        $headers = ['content-type' => 'application/xml'];\n        if (null !== $this->contentMd5) {\n            $headers['Content-MD5'] = $this->contentMd5;\n        }\n        if (null !== $this->checksumAlgorithm) {\n            if (!ChecksumAlgorithm::exists($this->checksumAlgorithm)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"ChecksumAlgorithm\" for \"%s\". The value \"%s\" is not a valid \"ChecksumAlgorithm\".', __CLASS__, $this->checksumAlgorithm));\n            }\n            $headers['x-amz-sdk-checksum-algorithm'] = $this->checksumAlgorithm;\n        }\n        if (null !== $this->expectedBucketOwner) {\n            $headers['x-amz-expected-bucket-owner'] = $this->expectedBucketOwner;\n        }\n\n        // Prepare query\n        $query = [];\n\n        // Prepare URI\n        $uri = [];\n        if (null === $v = $this->bucket) {\n            throw new InvalidArgument(sprintf('Missing parameter \"Bucket\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        $uri['Bucket'] = $v;\n        $uriString = '/' . rawurlencode($uri['Bucket']) . '?cors';\n\n        // Prepare Body\n\n        $document = new \\DOMDocument('1.0', 'UTF-8');\n        $document->formatOutput = false;\n        $this->requestBody($document, $document);\n        $body = $document->hasChildNodes() ? $document->saveXML() : '';\n\n        // Return the Request\n        return new Request('PUT', $uriString, $query, $headers, StreamFactory::create($body));\n    }\n\n    public function setBucket(?string $value): self\n    {\n        $this->bucket = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param ChecksumAlgorithm::*|null $value\n     */\n    public function setChecksumAlgorithm(?string $value): self\n    {\n        $this->checksumAlgorithm = $value;\n\n        return $this;\n    }\n\n    public function setContentMd5(?string $value): self\n    {\n        $this->contentMd5 = $value;\n\n        return $this;\n    }\n\n    public function setCorsConfiguration(?CORSConfiguration $value): self\n    {\n        $this->corsConfiguration = $value;\n\n        return $this;\n    }\n\n    public function setExpectedBucketOwner(?string $value): self\n    {\n        $this->expectedBucketOwner = $value;\n\n        return $this;\n    }\n\n    private function requestBody(\\DOMNode $node, \\DOMDocument $document): void\n    {\n        if (null === $v = $this->corsConfiguration) {\n            throw new InvalidArgument(sprintf('Missing parameter \"CORSConfiguration\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n\n        $node->appendChild($child = $document->createElement('CORSConfiguration'));\n        $child->setAttribute('xmlns', 'http://s3.amazonaws.com/doc/2006-03-01/');\n        $v->requestBody($child, $document);\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Input/PutBucketNotificationConfigurationRequest.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Input;\n\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\nuse AsyncAws\\Core\\Input;\nuse AsyncAws\\Core\\Request;\nuse AsyncAws\\Core\\Stream\\StreamFactory;\nuse AsyncAws\\S3\\ValueObject\\NotificationConfiguration;\n\nfinal class PutBucketNotificationConfigurationRequest extends Input\n{\n    /**\n     * The name of the bucket.\n     *\n     * @required\n     *\n     * @var string|null\n     */\n    private $bucket;\n\n    /**\n     * @required\n     *\n     * @var NotificationConfiguration|null\n     */\n    private $notificationConfiguration;\n\n    /**\n     * The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with\n     * the HTTP status code `403 Forbidden` (access denied).\n     *\n     * @var string|null\n     */\n    private $expectedBucketOwner;\n\n    /**\n     * Skips validation of Amazon SQS, Amazon SNS, and Lambda destinations. True or false value.\n     *\n     * @var bool|null\n     */\n    private $skipDestinationValidation;\n\n    /**\n     * @param array{\n     *   Bucket?: string,\n     *   NotificationConfiguration?: NotificationConfiguration|array,\n     *   ExpectedBucketOwner?: string,\n     *   SkipDestinationValidation?: bool,\n     *\n     *   @region?: string,\n     * } $input\n     */\n    public function __construct(array $input = [])\n    {\n        $this->bucket = $input['Bucket'] ?? null;\n        $this->notificationConfiguration = isset($input['NotificationConfiguration']) ? NotificationConfiguration::create($input['NotificationConfiguration']) : null;\n        $this->expectedBucketOwner = $input['ExpectedBucketOwner'] ?? null;\n        $this->skipDestinationValidation = $input['SkipDestinationValidation'] ?? null;\n        parent::__construct($input);\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    public function getBucket(): ?string\n    {\n        return $this->bucket;\n    }\n\n    public function getExpectedBucketOwner(): ?string\n    {\n        return $this->expectedBucketOwner;\n    }\n\n    public function getNotificationConfiguration(): ?NotificationConfiguration\n    {\n        return $this->notificationConfiguration;\n    }\n\n    public function getSkipDestinationValidation(): ?bool\n    {\n        return $this->skipDestinationValidation;\n    }\n\n    /**\n     * @internal\n     */\n    public function request(): Request\n    {\n        // Prepare headers\n        $headers = ['content-type' => 'application/xml'];\n        if (null !== $this->expectedBucketOwner) {\n            $headers['x-amz-expected-bucket-owner'] = $this->expectedBucketOwner;\n        }\n        if (null !== $this->skipDestinationValidation) {\n            $headers['x-amz-skip-destination-validation'] = $this->skipDestinationValidation ? 'true' : 'false';\n        }\n\n        // Prepare query\n        $query = [];\n\n        // Prepare URI\n        $uri = [];\n        if (null === $v = $this->bucket) {\n            throw new InvalidArgument(sprintf('Missing parameter \"Bucket\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        $uri['Bucket'] = $v;\n        $uriString = '/' . rawurlencode($uri['Bucket']) . '?notification';\n\n        // Prepare Body\n\n        $document = new \\DOMDocument('1.0', 'UTF-8');\n        $document->formatOutput = false;\n        $this->requestBody($document, $document);\n        $body = $document->hasChildNodes() ? $document->saveXML() : '';\n\n        // Return the Request\n        return new Request('PUT', $uriString, $query, $headers, StreamFactory::create($body));\n    }\n\n    public function setBucket(?string $value): self\n    {\n        $this->bucket = $value;\n\n        return $this;\n    }\n\n    public function setExpectedBucketOwner(?string $value): self\n    {\n        $this->expectedBucketOwner = $value;\n\n        return $this;\n    }\n\n    public function setNotificationConfiguration(?NotificationConfiguration $value): self\n    {\n        $this->notificationConfiguration = $value;\n\n        return $this;\n    }\n\n    public function setSkipDestinationValidation(?bool $value): self\n    {\n        $this->skipDestinationValidation = $value;\n\n        return $this;\n    }\n\n    private function requestBody(\\DOMNode $node, \\DOMDocument $document): void\n    {\n        if (null === $v = $this->notificationConfiguration) {\n            throw new InvalidArgument(sprintf('Missing parameter \"NotificationConfiguration\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n\n        $node->appendChild($child = $document->createElement('NotificationConfiguration'));\n        $child->setAttribute('xmlns', 'http://s3.amazonaws.com/doc/2006-03-01/');\n        $v->requestBody($child, $document);\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Input/PutObjectAclRequest.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Input;\n\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\nuse AsyncAws\\Core\\Input;\nuse AsyncAws\\Core\\Request;\nuse AsyncAws\\Core\\Stream\\StreamFactory;\nuse AsyncAws\\S3\\Enum\\ChecksumAlgorithm;\nuse AsyncAws\\S3\\Enum\\ObjectCannedACL;\nuse AsyncAws\\S3\\Enum\\RequestPayer;\nuse AsyncAws\\S3\\ValueObject\\AccessControlPolicy;\nuse AsyncAws\\S3\\ValueObject\\Grantee;\nuse AsyncAws\\S3\\ValueObject\\Owner;\n\nfinal class PutObjectAclRequest extends Input\n{\n    /**\n     * The canned ACL to apply to the object. For more information, see Canned ACL [^1].\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#CannedACL\n     *\n     * @var ObjectCannedACL::*|null\n     */\n    private $acl;\n\n    /**\n     * Contains the elements that set the ACL permissions for an object per grantee.\n     *\n     * @var AccessControlPolicy|null\n     */\n    private $accessControlPolicy;\n\n    /**\n     * The bucket name that contains the object to which you want to attach the ACL.\n     *\n     * When using this action with an access point, you must direct requests to the access point hostname. The access point\n     * hostname takes the form *AccessPointName*-*AccountId*.s3-accesspoint.*Region*.amazonaws.com. When using this action\n     * with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket\n     * name. For more information about access point ARNs, see Using access points [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html\n     *\n     * @required\n     *\n     * @var string|null\n     */\n    private $bucket;\n\n    /**\n     * The base64-encoded 128-bit MD5 digest of the data. This header must be used as a message integrity check to verify\n     * that the request body was not corrupted in transit. For more information, go to RFC 1864.> [^1].\n     *\n     * For requests made using the Amazon Web Services Command Line Interface (CLI) or Amazon Web Services SDKs, this field\n     * is calculated automatically.\n     *\n     * [^1]: http://www.ietf.org/rfc/rfc1864.txt\n     *\n     * @var string|null\n     */\n    private $contentMd5;\n\n    /**\n     * Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide\n     * any additional functionality if not using the SDK. When sending this header, there must be a corresponding\n     * `x-amz-checksum` or `x-amz-trailer` header sent. Otherwise, Amazon S3 fails the request with the HTTP status code\n     * `400 Bad Request`. For more information, see Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * If you provide an individual checksum, Amazon S3 ignores any provided `ChecksumAlgorithm` parameter.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html\n     *\n     * @var ChecksumAlgorithm::*|null\n     */\n    private $checksumAlgorithm;\n\n    /**\n     * Allows grantee the read, write, read ACP, and write ACP permissions on the bucket.\n     *\n     * This action is not supported by Amazon S3 on Outposts.\n     *\n     * @var string|null\n     */\n    private $grantFullControl;\n\n    /**\n     * Allows grantee to list the objects in the bucket.\n     *\n     * This action is not supported by Amazon S3 on Outposts.\n     *\n     * @var string|null\n     */\n    private $grantRead;\n\n    /**\n     * Allows grantee to read the bucket ACL.\n     *\n     * This action is not supported by Amazon S3 on Outposts.\n     *\n     * @var string|null\n     */\n    private $grantReadAcp;\n\n    /**\n     * Allows grantee to create new objects in the bucket.\n     *\n     * For the bucket and object owners of existing objects, also allows deletions and overwrites of those objects.\n     *\n     * @var string|null\n     */\n    private $grantWrite;\n\n    /**\n     * Allows grantee to write the ACL for the applicable bucket.\n     *\n     * This action is not supported by Amazon S3 on Outposts.\n     *\n     * @var string|null\n     */\n    private $grantWriteAcp;\n\n    /**\n     * Key for which the PUT action was initiated.\n     *\n     * When using this action with an access point, you must direct requests to the access point hostname. The access point\n     * hostname takes the form *AccessPointName*-*AccountId*.s3-accesspoint.*Region*.amazonaws.com. When using this action\n     * with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket\n     * name. For more information about access point ARNs, see Using access points [^1] in the *Amazon S3 User Guide*.\n     *\n     * When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3\n     * on Outposts hostname takes the form `*AccessPointName*-*AccountId*.*outpostID*.s3-outposts.*Region*.amazonaws.com`.\n     * When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access\n     * point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts\n     * [^2] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html\n     * [^2]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html\n     *\n     * @required\n     *\n     * @var string|null\n     */\n    private $key;\n\n    /**\n     * @var RequestPayer::*|null\n     */\n    private $requestPayer;\n\n    /**\n     * VersionId used to reference a specific version of the object.\n     *\n     * @var string|null\n     */\n    private $versionId;\n\n    /**\n     * The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with\n     * the HTTP status code `403 Forbidden` (access denied).\n     *\n     * @var string|null\n     */\n    private $expectedBucketOwner;\n\n    /**\n     * @param array{\n     *   ACL?: ObjectCannedACL::*,\n     *   AccessControlPolicy?: AccessControlPolicy|array,\n     *   Bucket?: string,\n     *   ContentMD5?: string,\n     *   ChecksumAlgorithm?: ChecksumAlgorithm::*,\n     *   GrantFullControl?: string,\n     *   GrantRead?: string,\n     *   GrantReadACP?: string,\n     *   GrantWrite?: string,\n     *   GrantWriteACP?: string,\n     *   Key?: string,\n     *   RequestPayer?: RequestPayer::*,\n     *   VersionId?: string,\n     *   ExpectedBucketOwner?: string,\n     *\n     *   @region?: string,\n     * } $input\n     */\n    public function __construct(array $input = [])\n    {\n        $this->acl = $input['ACL'] ?? null;\n        $this->accessControlPolicy = isset($input['AccessControlPolicy']) ? AccessControlPolicy::create($input['AccessControlPolicy']) : null;\n        $this->bucket = $input['Bucket'] ?? null;\n        $this->contentMd5 = $input['ContentMD5'] ?? null;\n        $this->checksumAlgorithm = $input['ChecksumAlgorithm'] ?? null;\n        $this->grantFullControl = $input['GrantFullControl'] ?? null;\n        $this->grantRead = $input['GrantRead'] ?? null;\n        $this->grantReadAcp = $input['GrantReadACP'] ?? null;\n        $this->grantWrite = $input['GrantWrite'] ?? null;\n        $this->grantWriteAcp = $input['GrantWriteACP'] ?? null;\n        $this->key = $input['Key'] ?? null;\n        $this->requestPayer = $input['RequestPayer'] ?? null;\n        $this->versionId = $input['VersionId'] ?? null;\n        $this->expectedBucketOwner = $input['ExpectedBucketOwner'] ?? null;\n        parent::__construct($input);\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    public function getAccessControlPolicy(): ?AccessControlPolicy\n    {\n        return $this->accessControlPolicy;\n    }\n\n    /**\n     * @return ObjectCannedACL::*|null\n     */\n    public function getAcl(): ?string\n    {\n        return $this->acl;\n    }\n\n    public function getBucket(): ?string\n    {\n        return $this->bucket;\n    }\n\n    /**\n     * @return ChecksumAlgorithm::*|null\n     */\n    public function getChecksumAlgorithm(): ?string\n    {\n        return $this->checksumAlgorithm;\n    }\n\n    public function getContentMd5(): ?string\n    {\n        return $this->contentMd5;\n    }\n\n    public function getExpectedBucketOwner(): ?string\n    {\n        return $this->expectedBucketOwner;\n    }\n\n    public function getGrantFullControl(): ?string\n    {\n        return $this->grantFullControl;\n    }\n\n    public function getGrantRead(): ?string\n    {\n        return $this->grantRead;\n    }\n\n    public function getGrantReadAcp(): ?string\n    {\n        return $this->grantReadAcp;\n    }\n\n    public function getGrantWrite(): ?string\n    {\n        return $this->grantWrite;\n    }\n\n    public function getGrantWriteAcp(): ?string\n    {\n        return $this->grantWriteAcp;\n    }\n\n    public function getKey(): ?string\n    {\n        return $this->key;\n    }\n\n    /**\n     * @return RequestPayer::*|null\n     */\n    public function getRequestPayer(): ?string\n    {\n        return $this->requestPayer;\n    }\n\n    public function getVersionId(): ?string\n    {\n        return $this->versionId;\n    }\n\n    /**\n     * @internal\n     */\n    public function request(): Request\n    {\n        // Prepare headers\n        $headers = ['content-type' => 'application/xml'];\n        if (null !== $this->acl) {\n            if (!ObjectCannedACL::exists($this->acl)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"ACL\" for \"%s\". The value \"%s\" is not a valid \"ObjectCannedACL\".', __CLASS__, $this->acl));\n            }\n            $headers['x-amz-acl'] = $this->acl;\n        }\n        if (null !== $this->contentMd5) {\n            $headers['Content-MD5'] = $this->contentMd5;\n        }\n        if (null !== $this->checksumAlgorithm) {\n            if (!ChecksumAlgorithm::exists($this->checksumAlgorithm)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"ChecksumAlgorithm\" for \"%s\". The value \"%s\" is not a valid \"ChecksumAlgorithm\".', __CLASS__, $this->checksumAlgorithm));\n            }\n            $headers['x-amz-sdk-checksum-algorithm'] = $this->checksumAlgorithm;\n        }\n        if (null !== $this->grantFullControl) {\n            $headers['x-amz-grant-full-control'] = $this->grantFullControl;\n        }\n        if (null !== $this->grantRead) {\n            $headers['x-amz-grant-read'] = $this->grantRead;\n        }\n        if (null !== $this->grantReadAcp) {\n            $headers['x-amz-grant-read-acp'] = $this->grantReadAcp;\n        }\n        if (null !== $this->grantWrite) {\n            $headers['x-amz-grant-write'] = $this->grantWrite;\n        }\n        if (null !== $this->grantWriteAcp) {\n            $headers['x-amz-grant-write-acp'] = $this->grantWriteAcp;\n        }\n        if (null !== $this->requestPayer) {\n            if (!RequestPayer::exists($this->requestPayer)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"RequestPayer\" for \"%s\". The value \"%s\" is not a valid \"RequestPayer\".', __CLASS__, $this->requestPayer));\n            }\n            $headers['x-amz-request-payer'] = $this->requestPayer;\n        }\n        if (null !== $this->expectedBucketOwner) {\n            $headers['x-amz-expected-bucket-owner'] = $this->expectedBucketOwner;\n        }\n\n        // Prepare query\n        $query = [];\n        if (null !== $this->versionId) {\n            $query['versionId'] = $this->versionId;\n        }\n\n        // Prepare URI\n        $uri = [];\n        if (null === $v = $this->bucket) {\n            throw new InvalidArgument(sprintf('Missing parameter \"Bucket\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        $uri['Bucket'] = $v;\n        if (null === $v = $this->key) {\n            throw new InvalidArgument(sprintf('Missing parameter \"Key\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        $uri['Key'] = $v;\n        $uriString = '/' . rawurlencode($uri['Bucket']) . '/' . str_replace('%2F', '/', rawurlencode($uri['Key'])) . '?acl';\n\n        // Prepare Body\n\n        $document = new \\DOMDocument('1.0', 'UTF-8');\n        $document->formatOutput = false;\n        $this->requestBody($document, $document);\n        $body = $document->hasChildNodes() ? $document->saveXML() : '';\n\n        // Return the Request\n        return new Request('PUT', $uriString, $query, $headers, StreamFactory::create($body));\n    }\n\n    public function setAccessControlPolicy(?AccessControlPolicy $value): self\n    {\n        $this->accessControlPolicy = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param ObjectCannedACL::*|null $value\n     */\n    public function setAcl(?string $value): self\n    {\n        $this->acl = $value;\n\n        return $this;\n    }\n\n    public function setBucket(?string $value): self\n    {\n        $this->bucket = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param ChecksumAlgorithm::*|null $value\n     */\n    public function setChecksumAlgorithm(?string $value): self\n    {\n        $this->checksumAlgorithm = $value;\n\n        return $this;\n    }\n\n    public function setContentMd5(?string $value): self\n    {\n        $this->contentMd5 = $value;\n\n        return $this;\n    }\n\n    public function setExpectedBucketOwner(?string $value): self\n    {\n        $this->expectedBucketOwner = $value;\n\n        return $this;\n    }\n\n    public function setGrantFullControl(?string $value): self\n    {\n        $this->grantFullControl = $value;\n\n        return $this;\n    }\n\n    public function setGrantRead(?string $value): self\n    {\n        $this->grantRead = $value;\n\n        return $this;\n    }\n\n    public function setGrantReadAcp(?string $value): self\n    {\n        $this->grantReadAcp = $value;\n\n        return $this;\n    }\n\n    public function setGrantWrite(?string $value): self\n    {\n        $this->grantWrite = $value;\n\n        return $this;\n    }\n\n    public function setGrantWriteAcp(?string $value): self\n    {\n        $this->grantWriteAcp = $value;\n\n        return $this;\n    }\n\n    public function setKey(?string $value): self\n    {\n        $this->key = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param RequestPayer::*|null $value\n     */\n    public function setRequestPayer(?string $value): self\n    {\n        $this->requestPayer = $value;\n\n        return $this;\n    }\n\n    public function setVersionId(?string $value): self\n    {\n        $this->versionId = $value;\n\n        return $this;\n    }\n\n    private function requestBody(\\DOMNode $node, \\DOMDocument $document): void\n    {\n        if (null !== $v = $this->accessControlPolicy) {\n            $node->appendChild($child = $document->createElement('AccessControlPolicy'));\n            $child->setAttribute('xmlns', 'http://s3.amazonaws.com/doc/2006-03-01/');\n            $v->requestBody($child, $document);\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Input/PutObjectRequest.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Input;\n\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\nuse AsyncAws\\Core\\Input;\nuse AsyncAws\\Core\\Request;\nuse AsyncAws\\Core\\Stream\\StreamFactory;\nuse AsyncAws\\S3\\Enum\\ChecksumAlgorithm;\nuse AsyncAws\\S3\\Enum\\ObjectCannedACL;\nuse AsyncAws\\S3\\Enum\\ObjectLockLegalHoldStatus;\nuse AsyncAws\\S3\\Enum\\ObjectLockMode;\nuse AsyncAws\\S3\\Enum\\RequestPayer;\nuse AsyncAws\\S3\\Enum\\ServerSideEncryption;\nuse AsyncAws\\S3\\Enum\\StorageClass;\n\nfinal class PutObjectRequest extends Input\n{\n    /**\n     * The canned ACL to apply to the object. For more information, see Canned ACL [^1].\n     *\n     * This action is not supported by Amazon S3 on Outposts.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#CannedACL\n     *\n     * @var ObjectCannedACL::*|null\n     */\n    private $acl;\n\n    /**\n     * Object data.\n     *\n     * @var string|resource|callable|iterable|null\n     */\n    private $body;\n\n    /**\n     * The bucket name to which the PUT action was initiated.\n     *\n     * When using this action with an access point, you must direct requests to the access point hostname. The access point\n     * hostname takes the form *AccessPointName*-*AccountId*.s3-accesspoint.*Region*.amazonaws.com. When using this action\n     * with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket\n     * name. For more information about access point ARNs, see Using access points [^1] in the *Amazon S3 User Guide*.\n     *\n     * When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3\n     * on Outposts hostname takes the form `*AccessPointName*-*AccountId*.*outpostID*.s3-outposts.*Region*.amazonaws.com`.\n     * When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access\n     * point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts\n     * [^2] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html\n     * [^2]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html\n     *\n     * @required\n     *\n     * @var string|null\n     */\n    private $bucket;\n\n    /**\n     * Can be used to specify caching behavior along the request/reply chain. For more information, see\n     * http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9 [^1].\n     *\n     * [^1]: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9\n     *\n     * @var string|null\n     */\n    private $cacheControl;\n\n    /**\n     * Specifies presentational information for the object. For more information, see\n     * https://www.rfc-editor.org/rfc/rfc6266#section-4 [^1].\n     *\n     * [^1]: https://www.rfc-editor.org/rfc/rfc6266#section-4\n     *\n     * @var string|null\n     */\n    private $contentDisposition;\n\n    /**\n     * Specifies what content encodings have been applied to the object and thus what decoding mechanisms must be applied to\n     * obtain the media-type referenced by the Content-Type header field. For more information, see\n     * https://www.rfc-editor.org/rfc/rfc9110.html#field.content-encoding [^1].\n     *\n     * [^1]: https://www.rfc-editor.org/rfc/rfc9110.html#field.content-encoding\n     *\n     * @var string|null\n     */\n    private $contentEncoding;\n\n    /**\n     * The language the content is in.\n     *\n     * @var string|null\n     */\n    private $contentLanguage;\n\n    /**\n     * Size of the body in bytes. This parameter is useful when the size of the body cannot be determined automatically. For\n     * more information, see https://www.rfc-editor.org/rfc/rfc9110.html#name-content-length [^1].\n     *\n     * [^1]: https://www.rfc-editor.org/rfc/rfc9110.html#name-content-length\n     *\n     * @var string|null\n     */\n    private $contentLength;\n\n    /**\n     * The base64-encoded 128-bit MD5 digest of the message (without the headers) according to RFC 1864. This header can be\n     * used as a message integrity check to verify that the data is the same data that was originally sent. Although it is\n     * optional, we recommend using the Content-MD5 mechanism as an end-to-end integrity check. For more information about\n     * REST request authentication, see REST Authentication [^1].\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html\n     *\n     * @var string|null\n     */\n    private $contentMd5;\n\n    /**\n     * A standard MIME type describing the format of the contents. For more information, see\n     * https://www.rfc-editor.org/rfc/rfc9110.html#name-content-type [^1].\n     *\n     * [^1]: https://www.rfc-editor.org/rfc/rfc9110.html#name-content-type\n     *\n     * @var string|null\n     */\n    private $contentType;\n\n    /**\n     * Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide\n     * any additional functionality if not using the SDK. When sending this header, there must be a corresponding\n     * `x-amz-checksum` or `x-amz-trailer` header sent. Otherwise, Amazon S3 fails the request with the HTTP status code\n     * `400 Bad Request`. For more information, see Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * If you provide an individual checksum, Amazon S3 ignores any provided `ChecksumAlgorithm` parameter.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html\n     *\n     * @var ChecksumAlgorithm::*|null\n     */\n    private $checksumAlgorithm;\n\n    /**\n     * This header can be used as a data integrity check to verify that the data received is the same data that was\n     * originally sent. This header specifies the base64-encoded, 32-bit CRC32 checksum of the object. For more information,\n     * see Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html\n     *\n     * @var string|null\n     */\n    private $checksumCrc32;\n\n    /**\n     * This header can be used as a data integrity check to verify that the data received is the same data that was\n     * originally sent. This header specifies the base64-encoded, 32-bit CRC32C checksum of the object. For more\n     * information, see Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html\n     *\n     * @var string|null\n     */\n    private $checksumCrc32C;\n\n    /**\n     * This header can be used as a data integrity check to verify that the data received is the same data that was\n     * originally sent. This header specifies the base64-encoded, 160-bit SHA-1 digest of the object. For more information,\n     * see Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html\n     *\n     * @var string|null\n     */\n    private $checksumSha1;\n\n    /**\n     * This header can be used as a data integrity check to verify that the data received is the same data that was\n     * originally sent. This header specifies the base64-encoded, 256-bit SHA-256 digest of the object. For more\n     * information, see Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html\n     *\n     * @var string|null\n     */\n    private $checksumSha256;\n\n    /**\n     * The date and time at which the object is no longer cacheable. For more information, see\n     * https://www.rfc-editor.org/rfc/rfc7234#section-5.3 [^1].\n     *\n     * [^1]: https://www.rfc-editor.org/rfc/rfc7234#section-5.3\n     *\n     * @var \\DateTimeImmutable|null\n     */\n    private $expires;\n\n    /**\n     * Gives the grantee READ, READ_ACP, and WRITE_ACP permissions on the object.\n     *\n     * This action is not supported by Amazon S3 on Outposts.\n     *\n     * @var string|null\n     */\n    private $grantFullControl;\n\n    /**\n     * Allows grantee to read the object data and its metadata.\n     *\n     * This action is not supported by Amazon S3 on Outposts.\n     *\n     * @var string|null\n     */\n    private $grantRead;\n\n    /**\n     * Allows grantee to read the object ACL.\n     *\n     * This action is not supported by Amazon S3 on Outposts.\n     *\n     * @var string|null\n     */\n    private $grantReadAcp;\n\n    /**\n     * Allows grantee to write the ACL for the applicable object.\n     *\n     * This action is not supported by Amazon S3 on Outposts.\n     *\n     * @var string|null\n     */\n    private $grantWriteAcp;\n\n    /**\n     * Object key for which the PUT action was initiated.\n     *\n     * @required\n     *\n     * @var string|null\n     */\n    private $key;\n\n    /**\n     * A map of metadata to store with the object in S3.\n     *\n     * @var array<string, string>|null\n     */\n    private $metadata;\n\n    /**\n     * The server-side encryption algorithm used when storing this object in Amazon S3 (for example, `AES256`, `aws:kms`,\n     * `aws:kms:dsse`).\n     *\n     * @var ServerSideEncryption::*|null\n     */\n    private $serverSideEncryption;\n\n    /**\n     * By default, Amazon S3 uses the STANDARD Storage Class to store newly created objects. The STANDARD storage class\n     * provides high durability and high availability. Depending on performance needs, you can specify a different Storage\n     * Class. Amazon S3 on Outposts only uses the OUTPOSTS Storage Class. For more information, see Storage Classes [^1] in\n     * the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/dev/storage-class-intro.html\n     *\n     * @var StorageClass::*|null\n     */\n    private $storageClass;\n\n    /**\n     * If the bucket is configured as a website, redirects requests for this object to another object in the same bucket or\n     * to an external URL. Amazon S3 stores the value of this header in the object metadata. For information about object\n     * metadata, see Object Key and Metadata [^1].\n     *\n     * In the following example, the request header sets the redirect to an object (anotherPage.html) in the same bucket:\n     *\n     * `x-amz-website-redirect-location: /anotherPage.html`\n     *\n     * In the following example, the request header sets the object redirect to another website:\n     *\n     * `x-amz-website-redirect-location: http://www.example.com/`\n     *\n     * For more information about website hosting in Amazon S3, see Hosting Websites on Amazon S3 [^2] and How to Configure\n     * Website Page Redirects [^3].\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html\n     * [^2]: https://docs.aws.amazon.com/AmazonS3/latest/dev/WebsiteHosting.html\n     * [^3]: https://docs.aws.amazon.com/AmazonS3/latest/dev/how-to-page-redirect.html\n     *\n     * @var string|null\n     */\n    private $websiteRedirectLocation;\n\n    /**\n     * Specifies the algorithm to use to when encrypting the object (for example, AES256).\n     *\n     * @var string|null\n     */\n    private $sseCustomerAlgorithm;\n\n    /**\n     * Specifies the customer-provided encryption key for Amazon S3 to use in encrypting data. This value is used to store\n     * the object and then it is discarded; Amazon S3 does not store the encryption key. The key must be appropriate for use\n     * with the algorithm specified in the `x-amz-server-side-encryption-customer-algorithm` header.\n     *\n     * @var string|null\n     */\n    private $sseCustomerKey;\n\n    /**\n     * Specifies the 128-bit MD5 digest of the encryption key according to RFC 1321. Amazon S3 uses this header for a\n     * message integrity check to ensure that the encryption key was transmitted without error.\n     *\n     * @var string|null\n     */\n    private $sseCustomerKeyMd5;\n\n    /**\n     * If `x-amz-server-side-encryption` has a valid value of `aws:kms` or `aws:kms:dsse`, this header specifies the ID of\n     * the Key Management Service (KMS) symmetric encryption customer managed key that was used for the object. If you\n     * specify `x-amz-server-side-encryption:aws:kms` or `x-amz-server-side-encryption:aws:kms:dsse`, but do not provide`\n     * x-amz-server-side-encryption-aws-kms-key-id`, Amazon S3 uses the Amazon Web Services managed key (`aws/s3`) to\n     * protect the data. If the KMS key does not exist in the same account that's issuing the command, you must use the full\n     * ARN and not just the ID.\n     *\n     * @var string|null\n     */\n    private $sseKmsKeyId;\n\n    /**\n     * Specifies the Amazon Web Services KMS Encryption Context to use for object encryption. The value of this header is a\n     * base64-encoded UTF-8 string holding JSON with the encryption context key-value pairs. This value is stored as object\n     * metadata and automatically gets passed on to Amazon Web Services KMS for future `GetObject` or `CopyObject`\n     * operations on this object.\n     *\n     * @var string|null\n     */\n    private $sseKmsEncryptionContext;\n\n    /**\n     * Specifies whether Amazon S3 should use an S3 Bucket Key for object encryption with server-side encryption using Key\n     * Management Service (KMS) keys (SSE-KMS). Setting this header to `true` causes Amazon S3 to use an S3 Bucket Key for\n     * object encryption with SSE-KMS.\n     *\n     * Specifying this header with a PUT action doesn’t affect bucket-level settings for S3 Bucket Key.\n     *\n     * @var bool|null\n     */\n    private $bucketKeyEnabled;\n\n    /**\n     * @var RequestPayer::*|null\n     */\n    private $requestPayer;\n\n    /**\n     * The tag-set for the object. The tag-set must be encoded as URL Query parameters. (For example, \"Key1=Value1\").\n     *\n     * @var string|null\n     */\n    private $tagging;\n\n    /**\n     * The Object Lock mode that you want to apply to this object.\n     *\n     * @var ObjectLockMode::*|null\n     */\n    private $objectLockMode;\n\n    /**\n     * The date and time when you want this object's Object Lock to expire. Must be formatted as a timestamp parameter.\n     *\n     * @var \\DateTimeImmutable|null\n     */\n    private $objectLockRetainUntilDate;\n\n    /**\n     * Specifies whether a legal hold will be applied to this object. For more information about S3 Object Lock, see Object\n     * Lock [^1].\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/dev/object-lock.html\n     *\n     * @var ObjectLockLegalHoldStatus::*|null\n     */\n    private $objectLockLegalHoldStatus;\n\n    /**\n     * The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with\n     * the HTTP status code `403 Forbidden` (access denied).\n     *\n     * @var string|null\n     */\n    private $expectedBucketOwner;\n\n    /**\n     * @param array{\n     *   ACL?: ObjectCannedACL::*,\n     *   Body?: string|resource|callable|iterable,\n     *   Bucket?: string,\n     *   CacheControl?: string,\n     *   ContentDisposition?: string,\n     *   ContentEncoding?: string,\n     *   ContentLanguage?: string,\n     *   ContentLength?: string,\n     *   ContentMD5?: string,\n     *   ContentType?: string,\n     *   ChecksumAlgorithm?: ChecksumAlgorithm::*,\n     *   ChecksumCRC32?: string,\n     *   ChecksumCRC32C?: string,\n     *   ChecksumSHA1?: string,\n     *   ChecksumSHA256?: string,\n     *   Expires?: \\DateTimeImmutable|string,\n     *   GrantFullControl?: string,\n     *   GrantRead?: string,\n     *   GrantReadACP?: string,\n     *   GrantWriteACP?: string,\n     *   Key?: string,\n     *   Metadata?: array<string, string>,\n     *   ServerSideEncryption?: ServerSideEncryption::*,\n     *   StorageClass?: StorageClass::*,\n     *   WebsiteRedirectLocation?: string,\n     *   SSECustomerAlgorithm?: string,\n     *   SSECustomerKey?: string,\n     *   SSECustomerKeyMD5?: string,\n     *   SSEKMSKeyId?: string,\n     *   SSEKMSEncryptionContext?: string,\n     *   BucketKeyEnabled?: bool,\n     *   RequestPayer?: RequestPayer::*,\n     *   Tagging?: string,\n     *   ObjectLockMode?: ObjectLockMode::*,\n     *   ObjectLockRetainUntilDate?: \\DateTimeImmutable|string,\n     *   ObjectLockLegalHoldStatus?: ObjectLockLegalHoldStatus::*,\n     *   ExpectedBucketOwner?: string,\n     *\n     *   @region?: string,\n     * } $input\n     */\n    public function __construct(array $input = [])\n    {\n        $this->acl = $input['ACL'] ?? null;\n        $this->body = $input['Body'] ?? null;\n        $this->bucket = $input['Bucket'] ?? null;\n        $this->cacheControl = $input['CacheControl'] ?? null;\n        $this->contentDisposition = $input['ContentDisposition'] ?? null;\n        $this->contentEncoding = $input['ContentEncoding'] ?? null;\n        $this->contentLanguage = $input['ContentLanguage'] ?? null;\n        $this->contentLength = $input['ContentLength'] ?? null;\n        $this->contentMd5 = $input['ContentMD5'] ?? null;\n        $this->contentType = $input['ContentType'] ?? null;\n        $this->checksumAlgorithm = $input['ChecksumAlgorithm'] ?? null;\n        $this->checksumCrc32 = $input['ChecksumCRC32'] ?? null;\n        $this->checksumCrc32C = $input['ChecksumCRC32C'] ?? null;\n        $this->checksumSha1 = $input['ChecksumSHA1'] ?? null;\n        $this->checksumSha256 = $input['ChecksumSHA256'] ?? null;\n        $this->expires = !isset($input['Expires']) ? null : ($input['Expires'] instanceof \\DateTimeImmutable ? $input['Expires'] : new \\DateTimeImmutable($input['Expires']));\n        $this->grantFullControl = $input['GrantFullControl'] ?? null;\n        $this->grantRead = $input['GrantRead'] ?? null;\n        $this->grantReadAcp = $input['GrantReadACP'] ?? null;\n        $this->grantWriteAcp = $input['GrantWriteACP'] ?? null;\n        $this->key = $input['Key'] ?? null;\n        $this->metadata = $input['Metadata'] ?? null;\n        $this->serverSideEncryption = $input['ServerSideEncryption'] ?? null;\n        $this->storageClass = $input['StorageClass'] ?? null;\n        $this->websiteRedirectLocation = $input['WebsiteRedirectLocation'] ?? null;\n        $this->sseCustomerAlgorithm = $input['SSECustomerAlgorithm'] ?? null;\n        $this->sseCustomerKey = $input['SSECustomerKey'] ?? null;\n        $this->sseCustomerKeyMd5 = $input['SSECustomerKeyMD5'] ?? null;\n        $this->sseKmsKeyId = $input['SSEKMSKeyId'] ?? null;\n        $this->sseKmsEncryptionContext = $input['SSEKMSEncryptionContext'] ?? null;\n        $this->bucketKeyEnabled = $input['BucketKeyEnabled'] ?? null;\n        $this->requestPayer = $input['RequestPayer'] ?? null;\n        $this->tagging = $input['Tagging'] ?? null;\n        $this->objectLockMode = $input['ObjectLockMode'] ?? null;\n        $this->objectLockRetainUntilDate = !isset($input['ObjectLockRetainUntilDate']) ? null : ($input['ObjectLockRetainUntilDate'] instanceof \\DateTimeImmutable ? $input['ObjectLockRetainUntilDate'] : new \\DateTimeImmutable($input['ObjectLockRetainUntilDate']));\n        $this->objectLockLegalHoldStatus = $input['ObjectLockLegalHoldStatus'] ?? null;\n        $this->expectedBucketOwner = $input['ExpectedBucketOwner'] ?? null;\n        parent::__construct($input);\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    /**\n     * @return ObjectCannedACL::*|null\n     */\n    public function getAcl(): ?string\n    {\n        return $this->acl;\n    }\n\n    /**\n     * @return string|resource|callable|iterable|null\n     */\n    public function getBody()\n    {\n        return $this->body;\n    }\n\n    public function getBucket(): ?string\n    {\n        return $this->bucket;\n    }\n\n    public function getBucketKeyEnabled(): ?bool\n    {\n        return $this->bucketKeyEnabled;\n    }\n\n    public function getCacheControl(): ?string\n    {\n        return $this->cacheControl;\n    }\n\n    /**\n     * @return ChecksumAlgorithm::*|null\n     */\n    public function getChecksumAlgorithm(): ?string\n    {\n        return $this->checksumAlgorithm;\n    }\n\n    public function getChecksumCrc32(): ?string\n    {\n        return $this->checksumCrc32;\n    }\n\n    public function getChecksumCrc32C(): ?string\n    {\n        return $this->checksumCrc32C;\n    }\n\n    public function getChecksumSha1(): ?string\n    {\n        return $this->checksumSha1;\n    }\n\n    public function getChecksumSha256(): ?string\n    {\n        return $this->checksumSha256;\n    }\n\n    public function getContentDisposition(): ?string\n    {\n        return $this->contentDisposition;\n    }\n\n    public function getContentEncoding(): ?string\n    {\n        return $this->contentEncoding;\n    }\n\n    public function getContentLanguage(): ?string\n    {\n        return $this->contentLanguage;\n    }\n\n    public function getContentLength(): ?string\n    {\n        return $this->contentLength;\n    }\n\n    public function getContentMd5(): ?string\n    {\n        return $this->contentMd5;\n    }\n\n    public function getContentType(): ?string\n    {\n        return $this->contentType;\n    }\n\n    public function getExpectedBucketOwner(): ?string\n    {\n        return $this->expectedBucketOwner;\n    }\n\n    public function getExpires(): ?\\DateTimeImmutable\n    {\n        return $this->expires;\n    }\n\n    public function getGrantFullControl(): ?string\n    {\n        return $this->grantFullControl;\n    }\n\n    public function getGrantRead(): ?string\n    {\n        return $this->grantRead;\n    }\n\n    public function getGrantReadAcp(): ?string\n    {\n        return $this->grantReadAcp;\n    }\n\n    public function getGrantWriteAcp(): ?string\n    {\n        return $this->grantWriteAcp;\n    }\n\n    public function getKey(): ?string\n    {\n        return $this->key;\n    }\n\n    /**\n     * @return array<string, string>\n     */\n    public function getMetadata(): array\n    {\n        return $this->metadata ?? [];\n    }\n\n    /**\n     * @return ObjectLockLegalHoldStatus::*|null\n     */\n    public function getObjectLockLegalHoldStatus(): ?string\n    {\n        return $this->objectLockLegalHoldStatus;\n    }\n\n    /**\n     * @return ObjectLockMode::*|null\n     */\n    public function getObjectLockMode(): ?string\n    {\n        return $this->objectLockMode;\n    }\n\n    public function getObjectLockRetainUntilDate(): ?\\DateTimeImmutable\n    {\n        return $this->objectLockRetainUntilDate;\n    }\n\n    /**\n     * @return RequestPayer::*|null\n     */\n    public function getRequestPayer(): ?string\n    {\n        return $this->requestPayer;\n    }\n\n    /**\n     * @return ServerSideEncryption::*|null\n     */\n    public function getServerSideEncryption(): ?string\n    {\n        return $this->serverSideEncryption;\n    }\n\n    public function getSseCustomerAlgorithm(): ?string\n    {\n        return $this->sseCustomerAlgorithm;\n    }\n\n    public function getSseCustomerKey(): ?string\n    {\n        return $this->sseCustomerKey;\n    }\n\n    public function getSseCustomerKeyMd5(): ?string\n    {\n        return $this->sseCustomerKeyMd5;\n    }\n\n    public function getSseKmsEncryptionContext(): ?string\n    {\n        return $this->sseKmsEncryptionContext;\n    }\n\n    public function getSseKmsKeyId(): ?string\n    {\n        return $this->sseKmsKeyId;\n    }\n\n    /**\n     * @return StorageClass::*|null\n     */\n    public function getStorageClass(): ?string\n    {\n        return $this->storageClass;\n    }\n\n    public function getTagging(): ?string\n    {\n        return $this->tagging;\n    }\n\n    public function getWebsiteRedirectLocation(): ?string\n    {\n        return $this->websiteRedirectLocation;\n    }\n\n    /**\n     * @internal\n     */\n    public function request(): Request\n    {\n        // Prepare headers\n        $headers = [];\n        if (null !== $this->acl) {\n            if (!ObjectCannedACL::exists($this->acl)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"ACL\" for \"%s\". The value \"%s\" is not a valid \"ObjectCannedACL\".', __CLASS__, $this->acl));\n            }\n            $headers['x-amz-acl'] = $this->acl;\n        }\n        if (null !== $this->cacheControl) {\n            $headers['Cache-Control'] = $this->cacheControl;\n        }\n        if (null !== $this->contentDisposition) {\n            $headers['Content-Disposition'] = $this->contentDisposition;\n        }\n        if (null !== $this->contentEncoding) {\n            $headers['Content-Encoding'] = $this->contentEncoding;\n        }\n        if (null !== $this->contentLanguage) {\n            $headers['Content-Language'] = $this->contentLanguage;\n        }\n        if (null !== $this->contentLength) {\n            $headers['Content-Length'] = $this->contentLength;\n        }\n        if (null !== $this->contentMd5) {\n            $headers['Content-MD5'] = $this->contentMd5;\n        }\n        if (null !== $this->contentType) {\n            $headers['Content-Type'] = $this->contentType;\n        }\n        if (null !== $this->checksumAlgorithm) {\n            if (!ChecksumAlgorithm::exists($this->checksumAlgorithm)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"ChecksumAlgorithm\" for \"%s\". The value \"%s\" is not a valid \"ChecksumAlgorithm\".', __CLASS__, $this->checksumAlgorithm));\n            }\n            $headers['x-amz-sdk-checksum-algorithm'] = $this->checksumAlgorithm;\n        }\n        if (null !== $this->checksumCrc32) {\n            $headers['x-amz-checksum-crc32'] = $this->checksumCrc32;\n        }\n        if (null !== $this->checksumCrc32C) {\n            $headers['x-amz-checksum-crc32c'] = $this->checksumCrc32C;\n        }\n        if (null !== $this->checksumSha1) {\n            $headers['x-amz-checksum-sha1'] = $this->checksumSha1;\n        }\n        if (null !== $this->checksumSha256) {\n            $headers['x-amz-checksum-sha256'] = $this->checksumSha256;\n        }\n        if (null !== $this->expires) {\n            $headers['Expires'] = $this->expires->setTimezone(new \\DateTimeZone('GMT'))->format(\\DateTimeInterface::RFC7231);\n        }\n        if (null !== $this->grantFullControl) {\n            $headers['x-amz-grant-full-control'] = $this->grantFullControl;\n        }\n        if (null !== $this->grantRead) {\n            $headers['x-amz-grant-read'] = $this->grantRead;\n        }\n        if (null !== $this->grantReadAcp) {\n            $headers['x-amz-grant-read-acp'] = $this->grantReadAcp;\n        }\n        if (null !== $this->grantWriteAcp) {\n            $headers['x-amz-grant-write-acp'] = $this->grantWriteAcp;\n        }\n        if (null !== $this->serverSideEncryption) {\n            if (!ServerSideEncryption::exists($this->serverSideEncryption)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"ServerSideEncryption\" for \"%s\". The value \"%s\" is not a valid \"ServerSideEncryption\".', __CLASS__, $this->serverSideEncryption));\n            }\n            $headers['x-amz-server-side-encryption'] = $this->serverSideEncryption;\n        }\n        if (null !== $this->storageClass) {\n            if (!StorageClass::exists($this->storageClass)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"StorageClass\" for \"%s\". The value \"%s\" is not a valid \"StorageClass\".', __CLASS__, $this->storageClass));\n            }\n            $headers['x-amz-storage-class'] = $this->storageClass;\n        }\n        if (null !== $this->websiteRedirectLocation) {\n            $headers['x-amz-website-redirect-location'] = $this->websiteRedirectLocation;\n        }\n        if (null !== $this->sseCustomerAlgorithm) {\n            $headers['x-amz-server-side-encryption-customer-algorithm'] = $this->sseCustomerAlgorithm;\n        }\n        if (null !== $this->sseCustomerKey) {\n            $headers['x-amz-server-side-encryption-customer-key'] = $this->sseCustomerKey;\n        }\n        if (null !== $this->sseCustomerKeyMd5) {\n            $headers['x-amz-server-side-encryption-customer-key-MD5'] = $this->sseCustomerKeyMd5;\n        }\n        if (null !== $this->sseKmsKeyId) {\n            $headers['x-amz-server-side-encryption-aws-kms-key-id'] = $this->sseKmsKeyId;\n        }\n        if (null !== $this->sseKmsEncryptionContext) {\n            $headers['x-amz-server-side-encryption-context'] = $this->sseKmsEncryptionContext;\n        }\n        if (null !== $this->bucketKeyEnabled) {\n            $headers['x-amz-server-side-encryption-bucket-key-enabled'] = $this->bucketKeyEnabled ? 'true' : 'false';\n        }\n        if (null !== $this->requestPayer) {\n            if (!RequestPayer::exists($this->requestPayer)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"RequestPayer\" for \"%s\". The value \"%s\" is not a valid \"RequestPayer\".', __CLASS__, $this->requestPayer));\n            }\n            $headers['x-amz-request-payer'] = $this->requestPayer;\n        }\n        if (null !== $this->tagging) {\n            $headers['x-amz-tagging'] = $this->tagging;\n        }\n        if (null !== $this->objectLockMode) {\n            if (!ObjectLockMode::exists($this->objectLockMode)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"ObjectLockMode\" for \"%s\". The value \"%s\" is not a valid \"ObjectLockMode\".', __CLASS__, $this->objectLockMode));\n            }\n            $headers['x-amz-object-lock-mode'] = $this->objectLockMode;\n        }\n        if (null !== $this->objectLockRetainUntilDate) {\n            $headers['x-amz-object-lock-retain-until-date'] = $this->objectLockRetainUntilDate->format(\\DateTimeInterface::ISO8601);\n        }\n        if (null !== $this->objectLockLegalHoldStatus) {\n            if (!ObjectLockLegalHoldStatus::exists($this->objectLockLegalHoldStatus)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"ObjectLockLegalHoldStatus\" for \"%s\". The value \"%s\" is not a valid \"ObjectLockLegalHoldStatus\".', __CLASS__, $this->objectLockLegalHoldStatus));\n            }\n            $headers['x-amz-object-lock-legal-hold'] = $this->objectLockLegalHoldStatus;\n        }\n        if (null !== $this->expectedBucketOwner) {\n            $headers['x-amz-expected-bucket-owner'] = $this->expectedBucketOwner;\n        }\n        if (null !== $this->metadata) {\n            foreach ($this->metadata as $key => $value) {\n                $headers[\"x-amz-meta-$key\"] = $value;\n            }\n        }\n\n        // Prepare query\n        $query = [];\n\n        // Prepare URI\n        $uri = [];\n        if (null === $v = $this->bucket) {\n            throw new InvalidArgument(sprintf('Missing parameter \"Bucket\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        $uri['Bucket'] = $v;\n        if (null === $v = $this->key) {\n            throw new InvalidArgument(sprintf('Missing parameter \"Key\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        $uri['Key'] = $v;\n        $uriString = '/' . rawurlencode($uri['Bucket']) . '/' . str_replace('%2F', '/', rawurlencode($uri['Key']));\n\n        // Prepare Body\n        $body = $this->body ?? '';\n\n        // Return the Request\n        return new Request('PUT', $uriString, $query, $headers, StreamFactory::create($body));\n    }\n\n    /**\n     * @param ObjectCannedACL::*|null $value\n     */\n    public function setAcl(?string $value): self\n    {\n        $this->acl = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param string|resource|callable|iterable|null $value\n     */\n    public function setBody($value): self\n    {\n        $this->body = $value;\n\n        return $this;\n    }\n\n    public function setBucket(?string $value): self\n    {\n        $this->bucket = $value;\n\n        return $this;\n    }\n\n    public function setBucketKeyEnabled(?bool $value): self\n    {\n        $this->bucketKeyEnabled = $value;\n\n        return $this;\n    }\n\n    public function setCacheControl(?string $value): self\n    {\n        $this->cacheControl = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param ChecksumAlgorithm::*|null $value\n     */\n    public function setChecksumAlgorithm(?string $value): self\n    {\n        $this->checksumAlgorithm = $value;\n\n        return $this;\n    }\n\n    public function setChecksumCrc32(?string $value): self\n    {\n        $this->checksumCrc32 = $value;\n\n        return $this;\n    }\n\n    public function setChecksumCrc32C(?string $value): self\n    {\n        $this->checksumCrc32C = $value;\n\n        return $this;\n    }\n\n    public function setChecksumSha1(?string $value): self\n    {\n        $this->checksumSha1 = $value;\n\n        return $this;\n    }\n\n    public function setChecksumSha256(?string $value): self\n    {\n        $this->checksumSha256 = $value;\n\n        return $this;\n    }\n\n    public function setContentDisposition(?string $value): self\n    {\n        $this->contentDisposition = $value;\n\n        return $this;\n    }\n\n    public function setContentEncoding(?string $value): self\n    {\n        $this->contentEncoding = $value;\n\n        return $this;\n    }\n\n    public function setContentLanguage(?string $value): self\n    {\n        $this->contentLanguage = $value;\n\n        return $this;\n    }\n\n    public function setContentLength(?string $value): self\n    {\n        $this->contentLength = $value;\n\n        return $this;\n    }\n\n    public function setContentMd5(?string $value): self\n    {\n        $this->contentMd5 = $value;\n\n        return $this;\n    }\n\n    public function setContentType(?string $value): self\n    {\n        $this->contentType = $value;\n\n        return $this;\n    }\n\n    public function setExpectedBucketOwner(?string $value): self\n    {\n        $this->expectedBucketOwner = $value;\n\n        return $this;\n    }\n\n    public function setExpires(?\\DateTimeImmutable $value): self\n    {\n        $this->expires = $value;\n\n        return $this;\n    }\n\n    public function setGrantFullControl(?string $value): self\n    {\n        $this->grantFullControl = $value;\n\n        return $this;\n    }\n\n    public function setGrantRead(?string $value): self\n    {\n        $this->grantRead = $value;\n\n        return $this;\n    }\n\n    public function setGrantReadAcp(?string $value): self\n    {\n        $this->grantReadAcp = $value;\n\n        return $this;\n    }\n\n    public function setGrantWriteAcp(?string $value): self\n    {\n        $this->grantWriteAcp = $value;\n\n        return $this;\n    }\n\n    public function setKey(?string $value): self\n    {\n        $this->key = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param array<string, string> $value\n     */\n    public function setMetadata(array $value): self\n    {\n        $this->metadata = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param ObjectLockLegalHoldStatus::*|null $value\n     */\n    public function setObjectLockLegalHoldStatus(?string $value): self\n    {\n        $this->objectLockLegalHoldStatus = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param ObjectLockMode::*|null $value\n     */\n    public function setObjectLockMode(?string $value): self\n    {\n        $this->objectLockMode = $value;\n\n        return $this;\n    }\n\n    public function setObjectLockRetainUntilDate(?\\DateTimeImmutable $value): self\n    {\n        $this->objectLockRetainUntilDate = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param RequestPayer::*|null $value\n     */\n    public function setRequestPayer(?string $value): self\n    {\n        $this->requestPayer = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param ServerSideEncryption::*|null $value\n     */\n    public function setServerSideEncryption(?string $value): self\n    {\n        $this->serverSideEncryption = $value;\n\n        return $this;\n    }\n\n    public function setSseCustomerAlgorithm(?string $value): self\n    {\n        $this->sseCustomerAlgorithm = $value;\n\n        return $this;\n    }\n\n    public function setSseCustomerKey(?string $value): self\n    {\n        $this->sseCustomerKey = $value;\n\n        return $this;\n    }\n\n    public function setSseCustomerKeyMd5(?string $value): self\n    {\n        $this->sseCustomerKeyMd5 = $value;\n\n        return $this;\n    }\n\n    public function setSseKmsEncryptionContext(?string $value): self\n    {\n        $this->sseKmsEncryptionContext = $value;\n\n        return $this;\n    }\n\n    public function setSseKmsKeyId(?string $value): self\n    {\n        $this->sseKmsKeyId = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param StorageClass::*|null $value\n     */\n    public function setStorageClass(?string $value): self\n    {\n        $this->storageClass = $value;\n\n        return $this;\n    }\n\n    public function setTagging(?string $value): self\n    {\n        $this->tagging = $value;\n\n        return $this;\n    }\n\n    public function setWebsiteRedirectLocation(?string $value): self\n    {\n        $this->websiteRedirectLocation = $value;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Input/UploadPartRequest.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Input;\n\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\nuse AsyncAws\\Core\\Input;\nuse AsyncAws\\Core\\Request;\nuse AsyncAws\\Core\\Stream\\StreamFactory;\nuse AsyncAws\\S3\\Enum\\ChecksumAlgorithm;\nuse AsyncAws\\S3\\Enum\\RequestPayer;\n\nfinal class UploadPartRequest extends Input\n{\n    /**\n     * Object data.\n     *\n     * @var string|resource|callable|iterable|null\n     */\n    private $body;\n\n    /**\n     * The name of the bucket to which the multipart upload was initiated.\n     *\n     * When using this action with an access point, you must direct requests to the access point hostname. The access point\n     * hostname takes the form *AccessPointName*-*AccountId*.s3-accesspoint.*Region*.amazonaws.com. When using this action\n     * with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket\n     * name. For more information about access point ARNs, see Using access points [^1] in the *Amazon S3 User Guide*.\n     *\n     * When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3\n     * on Outposts hostname takes the form `*AccessPointName*-*AccountId*.*outpostID*.s3-outposts.*Region*.amazonaws.com`.\n     * When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access\n     * point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts\n     * [^2] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html\n     * [^2]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html\n     *\n     * @required\n     *\n     * @var string|null\n     */\n    private $bucket;\n\n    /**\n     * Size of the body in bytes. This parameter is useful when the size of the body cannot be determined automatically.\n     *\n     * @var string|null\n     */\n    private $contentLength;\n\n    /**\n     * The base64-encoded 128-bit MD5 digest of the part data. This parameter is auto-populated when using the command from\n     * the CLI. This parameter is required if object lock parameters are specified.\n     *\n     * @var string|null\n     */\n    private $contentMd5;\n\n    /**\n     * Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide\n     * any additional functionality if not using the SDK. When sending this header, there must be a corresponding\n     * `x-amz-checksum` or `x-amz-trailer` header sent. Otherwise, Amazon S3 fails the request with the HTTP status code\n     * `400 Bad Request`. For more information, see Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * If you provide an individual checksum, Amazon S3 ignores any provided `ChecksumAlgorithm` parameter.\n     *\n     * This checksum algorithm must be the same for all parts and it match the checksum value supplied in the\n     * `CreateMultipartUpload` request.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html\n     *\n     * @var ChecksumAlgorithm::*|null\n     */\n    private $checksumAlgorithm;\n\n    /**\n     * This header can be used as a data integrity check to verify that the data received is the same data that was\n     * originally sent. This header specifies the base64-encoded, 32-bit CRC32 checksum of the object. For more information,\n     * see Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html\n     *\n     * @var string|null\n     */\n    private $checksumCrc32;\n\n    /**\n     * This header can be used as a data integrity check to verify that the data received is the same data that was\n     * originally sent. This header specifies the base64-encoded, 32-bit CRC32C checksum of the object. For more\n     * information, see Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html\n     *\n     * @var string|null\n     */\n    private $checksumCrc32C;\n\n    /**\n     * This header can be used as a data integrity check to verify that the data received is the same data that was\n     * originally sent. This header specifies the base64-encoded, 160-bit SHA-1 digest of the object. For more information,\n     * see Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html\n     *\n     * @var string|null\n     */\n    private $checksumSha1;\n\n    /**\n     * This header can be used as a data integrity check to verify that the data received is the same data that was\n     * originally sent. This header specifies the base64-encoded, 256-bit SHA-256 digest of the object. For more\n     * information, see Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html\n     *\n     * @var string|null\n     */\n    private $checksumSha256;\n\n    /**\n     * Object key for which the multipart upload was initiated.\n     *\n     * @required\n     *\n     * @var string|null\n     */\n    private $key;\n\n    /**\n     * Part number of part being uploaded. This is a positive integer between 1 and 10,000.\n     *\n     * @required\n     *\n     * @var int|null\n     */\n    private $partNumber;\n\n    /**\n     * Upload ID identifying the multipart upload whose part is being uploaded.\n     *\n     * @required\n     *\n     * @var string|null\n     */\n    private $uploadId;\n\n    /**\n     * Specifies the algorithm to use to when encrypting the object (for example, AES256).\n     *\n     * @var string|null\n     */\n    private $sseCustomerAlgorithm;\n\n    /**\n     * Specifies the customer-provided encryption key for Amazon S3 to use in encrypting data. This value is used to store\n     * the object and then it is discarded; Amazon S3 does not store the encryption key. The key must be appropriate for use\n     * with the algorithm specified in the `x-amz-server-side-encryption-customer-algorithm header`. This must be the same\n     * encryption key specified in the initiate multipart upload request.\n     *\n     * @var string|null\n     */\n    private $sseCustomerKey;\n\n    /**\n     * Specifies the 128-bit MD5 digest of the encryption key according to RFC 1321. Amazon S3 uses this header for a\n     * message integrity check to ensure that the encryption key was transmitted without error.\n     *\n     * @var string|null\n     */\n    private $sseCustomerKeyMd5;\n\n    /**\n     * @var RequestPayer::*|null\n     */\n    private $requestPayer;\n\n    /**\n     * The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with\n     * the HTTP status code `403 Forbidden` (access denied).\n     *\n     * @var string|null\n     */\n    private $expectedBucketOwner;\n\n    /**\n     * @param array{\n     *   Body?: string|resource|callable|iterable,\n     *   Bucket?: string,\n     *   ContentLength?: string,\n     *   ContentMD5?: string,\n     *   ChecksumAlgorithm?: ChecksumAlgorithm::*,\n     *   ChecksumCRC32?: string,\n     *   ChecksumCRC32C?: string,\n     *   ChecksumSHA1?: string,\n     *   ChecksumSHA256?: string,\n     *   Key?: string,\n     *   PartNumber?: int,\n     *   UploadId?: string,\n     *   SSECustomerAlgorithm?: string,\n     *   SSECustomerKey?: string,\n     *   SSECustomerKeyMD5?: string,\n     *   RequestPayer?: RequestPayer::*,\n     *   ExpectedBucketOwner?: string,\n     *\n     *   @region?: string,\n     * } $input\n     */\n    public function __construct(array $input = [])\n    {\n        $this->body = $input['Body'] ?? null;\n        $this->bucket = $input['Bucket'] ?? null;\n        $this->contentLength = $input['ContentLength'] ?? null;\n        $this->contentMd5 = $input['ContentMD5'] ?? null;\n        $this->checksumAlgorithm = $input['ChecksumAlgorithm'] ?? null;\n        $this->checksumCrc32 = $input['ChecksumCRC32'] ?? null;\n        $this->checksumCrc32C = $input['ChecksumCRC32C'] ?? null;\n        $this->checksumSha1 = $input['ChecksumSHA1'] ?? null;\n        $this->checksumSha256 = $input['ChecksumSHA256'] ?? null;\n        $this->key = $input['Key'] ?? null;\n        $this->partNumber = $input['PartNumber'] ?? null;\n        $this->uploadId = $input['UploadId'] ?? null;\n        $this->sseCustomerAlgorithm = $input['SSECustomerAlgorithm'] ?? null;\n        $this->sseCustomerKey = $input['SSECustomerKey'] ?? null;\n        $this->sseCustomerKeyMd5 = $input['SSECustomerKeyMD5'] ?? null;\n        $this->requestPayer = $input['RequestPayer'] ?? null;\n        $this->expectedBucketOwner = $input['ExpectedBucketOwner'] ?? null;\n        parent::__construct($input);\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    /**\n     * @return string|resource|callable|iterable|null\n     */\n    public function getBody()\n    {\n        return $this->body;\n    }\n\n    public function getBucket(): ?string\n    {\n        return $this->bucket;\n    }\n\n    /**\n     * @return ChecksumAlgorithm::*|null\n     */\n    public function getChecksumAlgorithm(): ?string\n    {\n        return $this->checksumAlgorithm;\n    }\n\n    public function getChecksumCrc32(): ?string\n    {\n        return $this->checksumCrc32;\n    }\n\n    public function getChecksumCrc32C(): ?string\n    {\n        return $this->checksumCrc32C;\n    }\n\n    public function getChecksumSha1(): ?string\n    {\n        return $this->checksumSha1;\n    }\n\n    public function getChecksumSha256(): ?string\n    {\n        return $this->checksumSha256;\n    }\n\n    public function getContentLength(): ?string\n    {\n        return $this->contentLength;\n    }\n\n    public function getContentMd5(): ?string\n    {\n        return $this->contentMd5;\n    }\n\n    public function getExpectedBucketOwner(): ?string\n    {\n        return $this->expectedBucketOwner;\n    }\n\n    public function getKey(): ?string\n    {\n        return $this->key;\n    }\n\n    public function getPartNumber(): ?int\n    {\n        return $this->partNumber;\n    }\n\n    /**\n     * @return RequestPayer::*|null\n     */\n    public function getRequestPayer(): ?string\n    {\n        return $this->requestPayer;\n    }\n\n    public function getSseCustomerAlgorithm(): ?string\n    {\n        return $this->sseCustomerAlgorithm;\n    }\n\n    public function getSseCustomerKey(): ?string\n    {\n        return $this->sseCustomerKey;\n    }\n\n    public function getSseCustomerKeyMd5(): ?string\n    {\n        return $this->sseCustomerKeyMd5;\n    }\n\n    public function getUploadId(): ?string\n    {\n        return $this->uploadId;\n    }\n\n    /**\n     * @internal\n     */\n    public function request(): Request\n    {\n        // Prepare headers\n        $headers = [];\n        if (null !== $this->contentLength) {\n            $headers['Content-Length'] = $this->contentLength;\n        }\n        if (null !== $this->contentMd5) {\n            $headers['Content-MD5'] = $this->contentMd5;\n        }\n        if (null !== $this->checksumAlgorithm) {\n            if (!ChecksumAlgorithm::exists($this->checksumAlgorithm)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"ChecksumAlgorithm\" for \"%s\". The value \"%s\" is not a valid \"ChecksumAlgorithm\".', __CLASS__, $this->checksumAlgorithm));\n            }\n            $headers['x-amz-sdk-checksum-algorithm'] = $this->checksumAlgorithm;\n        }\n        if (null !== $this->checksumCrc32) {\n            $headers['x-amz-checksum-crc32'] = $this->checksumCrc32;\n        }\n        if (null !== $this->checksumCrc32C) {\n            $headers['x-amz-checksum-crc32c'] = $this->checksumCrc32C;\n        }\n        if (null !== $this->checksumSha1) {\n            $headers['x-amz-checksum-sha1'] = $this->checksumSha1;\n        }\n        if (null !== $this->checksumSha256) {\n            $headers['x-amz-checksum-sha256'] = $this->checksumSha256;\n        }\n        if (null !== $this->sseCustomerAlgorithm) {\n            $headers['x-amz-server-side-encryption-customer-algorithm'] = $this->sseCustomerAlgorithm;\n        }\n        if (null !== $this->sseCustomerKey) {\n            $headers['x-amz-server-side-encryption-customer-key'] = $this->sseCustomerKey;\n        }\n        if (null !== $this->sseCustomerKeyMd5) {\n            $headers['x-amz-server-side-encryption-customer-key-MD5'] = $this->sseCustomerKeyMd5;\n        }\n        if (null !== $this->requestPayer) {\n            if (!RequestPayer::exists($this->requestPayer)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"RequestPayer\" for \"%s\". The value \"%s\" is not a valid \"RequestPayer\".', __CLASS__, $this->requestPayer));\n            }\n            $headers['x-amz-request-payer'] = $this->requestPayer;\n        }\n        if (null !== $this->expectedBucketOwner) {\n            $headers['x-amz-expected-bucket-owner'] = $this->expectedBucketOwner;\n        }\n\n        // Prepare query\n        $query = [];\n        if (null === $v = $this->partNumber) {\n            throw new InvalidArgument(sprintf('Missing parameter \"PartNumber\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        $query['partNumber'] = (string) $v;\n        if (null === $v = $this->uploadId) {\n            throw new InvalidArgument(sprintf('Missing parameter \"UploadId\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        $query['uploadId'] = $v;\n\n        // Prepare URI\n        $uri = [];\n        if (null === $v = $this->bucket) {\n            throw new InvalidArgument(sprintf('Missing parameter \"Bucket\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        $uri['Bucket'] = $v;\n        if (null === $v = $this->key) {\n            throw new InvalidArgument(sprintf('Missing parameter \"Key\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        $uri['Key'] = $v;\n        $uriString = '/' . rawurlencode($uri['Bucket']) . '/' . str_replace('%2F', '/', rawurlencode($uri['Key']));\n\n        // Prepare Body\n        $body = $this->body ?? '';\n\n        // Return the Request\n        return new Request('PUT', $uriString, $query, $headers, StreamFactory::create($body));\n    }\n\n    /**\n     * @param string|resource|callable|iterable|null $value\n     */\n    public function setBody($value): self\n    {\n        $this->body = $value;\n\n        return $this;\n    }\n\n    public function setBucket(?string $value): self\n    {\n        $this->bucket = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param ChecksumAlgorithm::*|null $value\n     */\n    public function setChecksumAlgorithm(?string $value): self\n    {\n        $this->checksumAlgorithm = $value;\n\n        return $this;\n    }\n\n    public function setChecksumCrc32(?string $value): self\n    {\n        $this->checksumCrc32 = $value;\n\n        return $this;\n    }\n\n    public function setChecksumCrc32C(?string $value): self\n    {\n        $this->checksumCrc32C = $value;\n\n        return $this;\n    }\n\n    public function setChecksumSha1(?string $value): self\n    {\n        $this->checksumSha1 = $value;\n\n        return $this;\n    }\n\n    public function setChecksumSha256(?string $value): self\n    {\n        $this->checksumSha256 = $value;\n\n        return $this;\n    }\n\n    public function setContentLength(?string $value): self\n    {\n        $this->contentLength = $value;\n\n        return $this;\n    }\n\n    public function setContentMd5(?string $value): self\n    {\n        $this->contentMd5 = $value;\n\n        return $this;\n    }\n\n    public function setExpectedBucketOwner(?string $value): self\n    {\n        $this->expectedBucketOwner = $value;\n\n        return $this;\n    }\n\n    public function setKey(?string $value): self\n    {\n        $this->key = $value;\n\n        return $this;\n    }\n\n    public function setPartNumber(?int $value): self\n    {\n        $this->partNumber = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param RequestPayer::*|null $value\n     */\n    public function setRequestPayer(?string $value): self\n    {\n        $this->requestPayer = $value;\n\n        return $this;\n    }\n\n    public function setSseCustomerAlgorithm(?string $value): self\n    {\n        $this->sseCustomerAlgorithm = $value;\n\n        return $this;\n    }\n\n    public function setSseCustomerKey(?string $value): self\n    {\n        $this->sseCustomerKey = $value;\n\n        return $this;\n    }\n\n    public function setSseCustomerKeyMd5(?string $value): self\n    {\n        $this->sseCustomerKeyMd5 = $value;\n\n        return $this;\n    }\n\n    public function setUploadId(?string $value): self\n    {\n        $this->uploadId = $value;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Result/AbortMultipartUploadOutput.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Result;\n\nuse AsyncAws\\Core\\Response;\nuse AsyncAws\\Core\\Result;\nuse AsyncAws\\S3\\Enum\\RequestCharged;\n\nclass AbortMultipartUploadOutput extends Result\n{\n    private $requestCharged;\n\n    /**\n     * @return RequestCharged::*|null\n     */\n    public function getRequestCharged(): ?string\n    {\n        $this->initialize();\n\n        return $this->requestCharged;\n    }\n\n    protected function populateResult(Response $response): void\n    {\n        $headers = $response->getHeaders();\n\n        $this->requestCharged = $headers['x-amz-request-charged'][0] ?? null;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Result/BucketExistsWaiter.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Result;\n\nuse AsyncAws\\Core\\Exception\\Http\\HttpException;\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\nuse AsyncAws\\Core\\Response;\nuse AsyncAws\\Core\\Waiter;\nuse AsyncAws\\S3\\Input\\HeadBucketRequest;\nuse AsyncAws\\S3\\S3Client;\n\nclass BucketExistsWaiter extends Waiter\n{\n    protected const WAIT_TIMEOUT = 100.0;\n    protected const WAIT_DELAY = 5.0;\n\n    protected function extractState(Response $response, ?HttpException $exception): string\n    {\n        if (200 === $response->getStatusCode()) {\n            return self::STATE_SUCCESS;\n        }\n\n        if (301 === $response->getStatusCode()) {\n            return self::STATE_SUCCESS;\n        }\n\n        if (403 === $response->getStatusCode()) {\n            return self::STATE_SUCCESS;\n        }\n\n        if (404 === $response->getStatusCode()) {\n            return self::STATE_PENDING;\n        }\n\n        return null === $exception ? self::STATE_PENDING : self::STATE_FAILURE;\n    }\n\n    protected function refreshState(): Waiter\n    {\n        if (!$this->awsClient instanceof S3Client) {\n            throw new InvalidArgument('missing client injected in waiter result');\n        }\n        if (!$this->input instanceof HeadBucketRequest) {\n            throw new InvalidArgument('missing last request injected in waiter result');\n        }\n\n        return $this->awsClient->bucketExists($this->input);\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Result/BucketNotExistsWaiter.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Result;\n\nuse AsyncAws\\Core\\Exception\\Http\\HttpException;\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\nuse AsyncAws\\Core\\Response;\nuse AsyncAws\\Core\\Waiter;\nuse AsyncAws\\S3\\Input\\HeadBucketRequest;\nuse AsyncAws\\S3\\S3Client;\n\nclass BucketNotExistsWaiter extends Waiter\n{\n    protected const WAIT_TIMEOUT = 100.0;\n    protected const WAIT_DELAY = 5.0;\n\n    protected function extractState(Response $response, ?HttpException $exception): string\n    {\n        if (404 === $response->getStatusCode()) {\n            return self::STATE_SUCCESS;\n        }\n\n        return null === $exception ? self::STATE_PENDING : self::STATE_FAILURE;\n    }\n\n    protected function refreshState(): Waiter\n    {\n        if (!$this->awsClient instanceof S3Client) {\n            throw new InvalidArgument('missing client injected in waiter result');\n        }\n        if (!$this->input instanceof HeadBucketRequest) {\n            throw new InvalidArgument('missing last request injected in waiter result');\n        }\n\n        return $this->awsClient->bucketNotExists($this->input);\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Result/CompleteMultipartUploadOutput.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Result;\n\nuse AsyncAws\\Core\\Response;\nuse AsyncAws\\Core\\Result;\nuse AsyncAws\\S3\\Enum\\RequestCharged;\nuse AsyncAws\\S3\\Enum\\ServerSideEncryption;\n\nclass CompleteMultipartUploadOutput extends Result\n{\n    /**\n     * The URI that identifies the newly created object.\n     */\n    private $location;\n\n    /**\n     * The name of the bucket that contains the newly created object. Does not return the access point ARN or access point\n     * alias if used.\n     *\n     * When using this action with an access point, you must direct requests to the access point hostname. The access point\n     * hostname takes the form *AccessPointName*-*AccountId*.s3-accesspoint.*Region*.amazonaws.com. When using this action\n     * with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket\n     * name. For more information about access point ARNs, see Using access points [^1] in the *Amazon S3 User Guide*.\n     *\n     * When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3\n     * on Outposts hostname takes the form `*AccessPointName*-*AccountId*.*outpostID*.s3-outposts.*Region*.amazonaws.com`.\n     * When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access\n     * point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts\n     * [^2] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html\n     * [^2]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html\n     */\n    private $bucket;\n\n    /**\n     * The object key of the newly created object.\n     */\n    private $key;\n\n    /**\n     * If the object expiration is configured, this will contain the expiration date (`expiry-date`) and rule ID\n     * (`rule-id`). The value of `rule-id` is URL-encoded.\n     */\n    private $expiration;\n\n    /**\n     * Entity tag that identifies the newly created object's data. Objects with different object data will have different\n     * entity tags. The entity tag is an opaque string. The entity tag may or may not be an MD5 digest of the object data.\n     * If the entity tag is not an MD5 digest of the object data, it will contain one or more nonhexadecimal characters\n     * and/or will consist of less than 32 or more than 32 hexadecimal digits. For more information about how the entity tag\n     * is calculated, see Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html\n     */\n    private $etag;\n\n    /**\n     * The base64-encoded, 32-bit CRC32 checksum of the object. This will only be present if it was uploaded with the\n     * object. With multipart uploads, this may not be a checksum value of the object. For more information about how\n     * checksums are calculated with multipart uploads, see  Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums\n     */\n    private $checksumCrc32;\n\n    /**\n     * The base64-encoded, 32-bit CRC32C checksum of the object. This will only be present if it was uploaded with the\n     * object. With multipart uploads, this may not be a checksum value of the object. For more information about how\n     * checksums are calculated with multipart uploads, see  Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums\n     */\n    private $checksumCrc32C;\n\n    /**\n     * The base64-encoded, 160-bit SHA-1 digest of the object. This will only be present if it was uploaded with the object.\n     * With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are\n     * calculated with multipart uploads, see  Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums\n     */\n    private $checksumSha1;\n\n    /**\n     * The base64-encoded, 256-bit SHA-256 digest of the object. This will only be present if it was uploaded with the\n     * object. With multipart uploads, this may not be a checksum value of the object. For more information about how\n     * checksums are calculated with multipart uploads, see  Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums\n     */\n    private $checksumSha256;\n\n    /**\n     * The server-side encryption algorithm used when storing this object in Amazon S3 (for example, `AES256`, `aws:kms`).\n     */\n    private $serverSideEncryption;\n\n    /**\n     * Version ID of the newly created object, in case the bucket has versioning turned on.\n     */\n    private $versionId;\n\n    /**\n     * If present, specifies the ID of the Key Management Service (KMS) symmetric encryption customer managed key that was\n     * used for the object.\n     */\n    private $sseKmsKeyId;\n\n    /**\n     * Indicates whether the multipart upload uses an S3 Bucket Key for server-side encryption with Key Management Service\n     * (KMS) keys (SSE-KMS).\n     */\n    private $bucketKeyEnabled;\n\n    private $requestCharged;\n\n    public function getBucket(): ?string\n    {\n        $this->initialize();\n\n        return $this->bucket;\n    }\n\n    public function getBucketKeyEnabled(): ?bool\n    {\n        $this->initialize();\n\n        return $this->bucketKeyEnabled;\n    }\n\n    public function getChecksumCrc32(): ?string\n    {\n        $this->initialize();\n\n        return $this->checksumCrc32;\n    }\n\n    public function getChecksumCrc32C(): ?string\n    {\n        $this->initialize();\n\n        return $this->checksumCrc32C;\n    }\n\n    public function getChecksumSha1(): ?string\n    {\n        $this->initialize();\n\n        return $this->checksumSha1;\n    }\n\n    public function getChecksumSha256(): ?string\n    {\n        $this->initialize();\n\n        return $this->checksumSha256;\n    }\n\n    public function getEtag(): ?string\n    {\n        $this->initialize();\n\n        return $this->etag;\n    }\n\n    public function getExpiration(): ?string\n    {\n        $this->initialize();\n\n        return $this->expiration;\n    }\n\n    public function getKey(): ?string\n    {\n        $this->initialize();\n\n        return $this->key;\n    }\n\n    public function getLocation(): ?string\n    {\n        $this->initialize();\n\n        return $this->location;\n    }\n\n    /**\n     * @return RequestCharged::*|null\n     */\n    public function getRequestCharged(): ?string\n    {\n        $this->initialize();\n\n        return $this->requestCharged;\n    }\n\n    /**\n     * @return ServerSideEncryption::*|null\n     */\n    public function getServerSideEncryption(): ?string\n    {\n        $this->initialize();\n\n        return $this->serverSideEncryption;\n    }\n\n    public function getSseKmsKeyId(): ?string\n    {\n        $this->initialize();\n\n        return $this->sseKmsKeyId;\n    }\n\n    public function getVersionId(): ?string\n    {\n        $this->initialize();\n\n        return $this->versionId;\n    }\n\n    protected function populateResult(Response $response): void\n    {\n        $headers = $response->getHeaders();\n\n        $this->expiration = $headers['x-amz-expiration'][0] ?? null;\n        $this->serverSideEncryption = $headers['x-amz-server-side-encryption'][0] ?? null;\n        $this->versionId = $headers['x-amz-version-id'][0] ?? null;\n        $this->sseKmsKeyId = $headers['x-amz-server-side-encryption-aws-kms-key-id'][0] ?? null;\n        $this->bucketKeyEnabled = isset($headers['x-amz-server-side-encryption-bucket-key-enabled'][0]) ? filter_var($headers['x-amz-server-side-encryption-bucket-key-enabled'][0], \\FILTER_VALIDATE_BOOLEAN) : null;\n        $this->requestCharged = $headers['x-amz-request-charged'][0] ?? null;\n\n        $data = new \\SimpleXMLElement($response->getContent());\n        $this->location = ($v = $data->Location) ? (string) $v : null;\n        $this->bucket = ($v = $data->Bucket) ? (string) $v : null;\n        $this->key = ($v = $data->Key) ? (string) $v : null;\n        $this->etag = ($v = $data->ETag) ? (string) $v : null;\n        $this->checksumCrc32 = ($v = $data->ChecksumCRC32) ? (string) $v : null;\n        $this->checksumCrc32C = ($v = $data->ChecksumCRC32C) ? (string) $v : null;\n        $this->checksumSha1 = ($v = $data->ChecksumSHA1) ? (string) $v : null;\n        $this->checksumSha256 = ($v = $data->ChecksumSHA256) ? (string) $v : null;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Result/CopyObjectOutput.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Result;\n\nuse AsyncAws\\Core\\Response;\nuse AsyncAws\\Core\\Result;\nuse AsyncAws\\S3\\Enum\\RequestCharged;\nuse AsyncAws\\S3\\Enum\\ServerSideEncryption;\nuse AsyncAws\\S3\\ValueObject\\CopyObjectResult;\n\nclass CopyObjectOutput extends Result\n{\n    /**\n     * Container for all response elements.\n     */\n    private $copyObjectResult;\n\n    /**\n     * If the object expiration is configured, the response includes this header.\n     */\n    private $expiration;\n\n    /**\n     * Version of the copied object in the destination bucket.\n     */\n    private $copySourceVersionId;\n\n    /**\n     * Version ID of the newly created copy.\n     */\n    private $versionId;\n\n    /**\n     * The server-side encryption algorithm used when storing this object in Amazon S3 (for example, `AES256`, `aws:kms`,\n     * `aws:kms:dsse`).\n     */\n    private $serverSideEncryption;\n\n    /**\n     * If server-side encryption with a customer-provided encryption key was requested, the response will include this\n     * header confirming the encryption algorithm used.\n     */\n    private $sseCustomerAlgorithm;\n\n    /**\n     * If server-side encryption with a customer-provided encryption key was requested, the response will include this\n     * header to provide round-trip message integrity verification of the customer-provided encryption key.\n     */\n    private $sseCustomerKeyMd5;\n\n    /**\n     * If present, specifies the ID of the Key Management Service (KMS) symmetric encryption customer managed key that was\n     * used for the object.\n     */\n    private $sseKmsKeyId;\n\n    /**\n     * If present, specifies the Amazon Web Services KMS Encryption Context to use for object encryption. The value of this\n     * header is a base64-encoded UTF-8 string holding JSON with the encryption context key-value pairs.\n     */\n    private $sseKmsEncryptionContext;\n\n    /**\n     * Indicates whether the copied object uses an S3 Bucket Key for server-side encryption with Key Management Service\n     * (KMS) keys (SSE-KMS).\n     */\n    private $bucketKeyEnabled;\n\n    private $requestCharged;\n\n    public function getBucketKeyEnabled(): ?bool\n    {\n        $this->initialize();\n\n        return $this->bucketKeyEnabled;\n    }\n\n    public function getCopyObjectResult(): ?CopyObjectResult\n    {\n        $this->initialize();\n\n        return $this->copyObjectResult;\n    }\n\n    public function getCopySourceVersionId(): ?string\n    {\n        $this->initialize();\n\n        return $this->copySourceVersionId;\n    }\n\n    public function getExpiration(): ?string\n    {\n        $this->initialize();\n\n        return $this->expiration;\n    }\n\n    /**\n     * @return RequestCharged::*|null\n     */\n    public function getRequestCharged(): ?string\n    {\n        $this->initialize();\n\n        return $this->requestCharged;\n    }\n\n    /**\n     * @return ServerSideEncryption::*|null\n     */\n    public function getServerSideEncryption(): ?string\n    {\n        $this->initialize();\n\n        return $this->serverSideEncryption;\n    }\n\n    public function getSseCustomerAlgorithm(): ?string\n    {\n        $this->initialize();\n\n        return $this->sseCustomerAlgorithm;\n    }\n\n    public function getSseCustomerKeyMd5(): ?string\n    {\n        $this->initialize();\n\n        return $this->sseCustomerKeyMd5;\n    }\n\n    public function getSseKmsEncryptionContext(): ?string\n    {\n        $this->initialize();\n\n        return $this->sseKmsEncryptionContext;\n    }\n\n    public function getSseKmsKeyId(): ?string\n    {\n        $this->initialize();\n\n        return $this->sseKmsKeyId;\n    }\n\n    public function getVersionId(): ?string\n    {\n        $this->initialize();\n\n        return $this->versionId;\n    }\n\n    protected function populateResult(Response $response): void\n    {\n        $headers = $response->getHeaders();\n\n        $this->expiration = $headers['x-amz-expiration'][0] ?? null;\n        $this->copySourceVersionId = $headers['x-amz-copy-source-version-id'][0] ?? null;\n        $this->versionId = $headers['x-amz-version-id'][0] ?? null;\n        $this->serverSideEncryption = $headers['x-amz-server-side-encryption'][0] ?? null;\n        $this->sseCustomerAlgorithm = $headers['x-amz-server-side-encryption-customer-algorithm'][0] ?? null;\n        $this->sseCustomerKeyMd5 = $headers['x-amz-server-side-encryption-customer-key-md5'][0] ?? null;\n        $this->sseKmsKeyId = $headers['x-amz-server-side-encryption-aws-kms-key-id'][0] ?? null;\n        $this->sseKmsEncryptionContext = $headers['x-amz-server-side-encryption-context'][0] ?? null;\n        $this->bucketKeyEnabled = isset($headers['x-amz-server-side-encryption-bucket-key-enabled'][0]) ? filter_var($headers['x-amz-server-side-encryption-bucket-key-enabled'][0], \\FILTER_VALIDATE_BOOLEAN) : null;\n        $this->requestCharged = $headers['x-amz-request-charged'][0] ?? null;\n\n        $data = new \\SimpleXMLElement($response->getContent());\n        $this->copyObjectResult = new CopyObjectResult([\n            'ETag' => ($v = $data->ETag) ? (string) $v : null,\n            'LastModified' => ($v = $data->LastModified) ? new \\DateTimeImmutable((string) $v) : null,\n            'ChecksumCRC32' => ($v = $data->ChecksumCRC32) ? (string) $v : null,\n            'ChecksumCRC32C' => ($v = $data->ChecksumCRC32C) ? (string) $v : null,\n            'ChecksumSHA1' => ($v = $data->ChecksumSHA1) ? (string) $v : null,\n            'ChecksumSHA256' => ($v = $data->ChecksumSHA256) ? (string) $v : null,\n        ]);\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Result/CreateBucketOutput.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Result;\n\nuse AsyncAws\\Core\\Response;\nuse AsyncAws\\Core\\Result;\n\nclass CreateBucketOutput extends Result\n{\n    /**\n     * A forward slash followed by the name of the bucket.\n     */\n    private $location;\n\n    public function getLocation(): ?string\n    {\n        $this->initialize();\n\n        return $this->location;\n    }\n\n    protected function populateResult(Response $response): void\n    {\n        $headers = $response->getHeaders();\n\n        $this->location = $headers['location'][0] ?? null;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Result/CreateMultipartUploadOutput.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Result;\n\nuse AsyncAws\\Core\\Response;\nuse AsyncAws\\Core\\Result;\nuse AsyncAws\\S3\\Enum\\ChecksumAlgorithm;\nuse AsyncAws\\S3\\Enum\\RequestCharged;\nuse AsyncAws\\S3\\Enum\\ServerSideEncryption;\n\nclass CreateMultipartUploadOutput extends Result\n{\n    /**\n     * If the bucket has a lifecycle rule configured with an action to abort incomplete multipart uploads and the prefix in\n     * the lifecycle rule matches the object name in the request, the response includes this header. The header indicates\n     * when the initiated multipart upload becomes eligible for an abort operation. For more information, see  Aborting\n     * Incomplete Multipart Uploads Using a Bucket Lifecycle Configuration [^1].\n     *\n     * The response also includes the `x-amz-abort-rule-id` header that provides the ID of the lifecycle configuration rule\n     * that defines this action.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/dev/mpuoverview.html#mpu-abort-incomplete-mpu-lifecycle-config\n     */\n    private $abortDate;\n\n    /**\n     * This header is returned along with the `x-amz-abort-date` header. It identifies the applicable lifecycle\n     * configuration rule that defines the action to abort incomplete multipart uploads.\n     */\n    private $abortRuleId;\n\n    /**\n     * The name of the bucket to which the multipart upload was initiated. Does not return the access point ARN or access\n     * point alias if used.\n     *\n     * When using this action with an access point, you must direct requests to the access point hostname. The access point\n     * hostname takes the form *AccessPointName*-*AccountId*.s3-accesspoint.*Region*.amazonaws.com. When using this action\n     * with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket\n     * name. For more information about access point ARNs, see Using access points [^1] in the *Amazon S3 User Guide*.\n     *\n     * When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3\n     * on Outposts hostname takes the form `*AccessPointName*-*AccountId*.*outpostID*.s3-outposts.*Region*.amazonaws.com`.\n     * When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access\n     * point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts\n     * [^2] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html\n     * [^2]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html\n     */\n    private $bucket;\n\n    /**\n     * Object key for which the multipart upload was initiated.\n     */\n    private $key;\n\n    /**\n     * ID for the initiated multipart upload.\n     */\n    private $uploadId;\n\n    /**\n     * The server-side encryption algorithm used when storing this object in Amazon S3 (for example, `AES256`, `aws:kms`).\n     */\n    private $serverSideEncryption;\n\n    /**\n     * If server-side encryption with a customer-provided encryption key was requested, the response will include this\n     * header confirming the encryption algorithm used.\n     */\n    private $sseCustomerAlgorithm;\n\n    /**\n     * If server-side encryption with a customer-provided encryption key was requested, the response will include this\n     * header to provide round-trip message integrity verification of the customer-provided encryption key.\n     */\n    private $sseCustomerKeyMd5;\n\n    /**\n     * If present, specifies the ID of the Key Management Service (KMS) symmetric encryption customer managed key that was\n     * used for the object.\n     */\n    private $sseKmsKeyId;\n\n    /**\n     * If present, specifies the Amazon Web Services KMS Encryption Context to use for object encryption. The value of this\n     * header is a base64-encoded UTF-8 string holding JSON with the encryption context key-value pairs.\n     */\n    private $sseKmsEncryptionContext;\n\n    /**\n     * Indicates whether the multipart upload uses an S3 Bucket Key for server-side encryption with Key Management Service\n     * (KMS) keys (SSE-KMS).\n     */\n    private $bucketKeyEnabled;\n\n    private $requestCharged;\n\n    /**\n     * The algorithm that was used to create a checksum of the object.\n     */\n    private $checksumAlgorithm;\n\n    public function getAbortDate(): ?\\DateTimeImmutable\n    {\n        $this->initialize();\n\n        return $this->abortDate;\n    }\n\n    public function getAbortRuleId(): ?string\n    {\n        $this->initialize();\n\n        return $this->abortRuleId;\n    }\n\n    public function getBucket(): ?string\n    {\n        $this->initialize();\n\n        return $this->bucket;\n    }\n\n    public function getBucketKeyEnabled(): ?bool\n    {\n        $this->initialize();\n\n        return $this->bucketKeyEnabled;\n    }\n\n    /**\n     * @return ChecksumAlgorithm::*|null\n     */\n    public function getChecksumAlgorithm(): ?string\n    {\n        $this->initialize();\n\n        return $this->checksumAlgorithm;\n    }\n\n    public function getKey(): ?string\n    {\n        $this->initialize();\n\n        return $this->key;\n    }\n\n    /**\n     * @return RequestCharged::*|null\n     */\n    public function getRequestCharged(): ?string\n    {\n        $this->initialize();\n\n        return $this->requestCharged;\n    }\n\n    /**\n     * @return ServerSideEncryption::*|null\n     */\n    public function getServerSideEncryption(): ?string\n    {\n        $this->initialize();\n\n        return $this->serverSideEncryption;\n    }\n\n    public function getSseCustomerAlgorithm(): ?string\n    {\n        $this->initialize();\n\n        return $this->sseCustomerAlgorithm;\n    }\n\n    public function getSseCustomerKeyMd5(): ?string\n    {\n        $this->initialize();\n\n        return $this->sseCustomerKeyMd5;\n    }\n\n    public function getSseKmsEncryptionContext(): ?string\n    {\n        $this->initialize();\n\n        return $this->sseKmsEncryptionContext;\n    }\n\n    public function getSseKmsKeyId(): ?string\n    {\n        $this->initialize();\n\n        return $this->sseKmsKeyId;\n    }\n\n    public function getUploadId(): ?string\n    {\n        $this->initialize();\n\n        return $this->uploadId;\n    }\n\n    protected function populateResult(Response $response): void\n    {\n        $headers = $response->getHeaders();\n\n        $this->abortDate = isset($headers['x-amz-abort-date'][0]) ? new \\DateTimeImmutable($headers['x-amz-abort-date'][0]) : null;\n        $this->abortRuleId = $headers['x-amz-abort-rule-id'][0] ?? null;\n        $this->serverSideEncryption = $headers['x-amz-server-side-encryption'][0] ?? null;\n        $this->sseCustomerAlgorithm = $headers['x-amz-server-side-encryption-customer-algorithm'][0] ?? null;\n        $this->sseCustomerKeyMd5 = $headers['x-amz-server-side-encryption-customer-key-md5'][0] ?? null;\n        $this->sseKmsKeyId = $headers['x-amz-server-side-encryption-aws-kms-key-id'][0] ?? null;\n        $this->sseKmsEncryptionContext = $headers['x-amz-server-side-encryption-context'][0] ?? null;\n        $this->bucketKeyEnabled = isset($headers['x-amz-server-side-encryption-bucket-key-enabled'][0]) ? filter_var($headers['x-amz-server-side-encryption-bucket-key-enabled'][0], \\FILTER_VALIDATE_BOOLEAN) : null;\n        $this->requestCharged = $headers['x-amz-request-charged'][0] ?? null;\n        $this->checksumAlgorithm = $headers['x-amz-checksum-algorithm'][0] ?? null;\n\n        $data = new \\SimpleXMLElement($response->getContent());\n        $this->bucket = ($v = $data->Bucket) ? (string) $v : null;\n        $this->key = ($v = $data->Key) ? (string) $v : null;\n        $this->uploadId = ($v = $data->UploadId) ? (string) $v : null;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Result/DeleteObjectOutput.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Result;\n\nuse AsyncAws\\Core\\Response;\nuse AsyncAws\\Core\\Result;\nuse AsyncAws\\S3\\Enum\\RequestCharged;\n\nclass DeleteObjectOutput extends Result\n{\n    /**\n     * Specifies whether the versioned object that was permanently deleted was (true) or was not (false) a delete marker.\n     */\n    private $deleteMarker;\n\n    /**\n     * Returns the version ID of the delete marker created as a result of the DELETE operation.\n     */\n    private $versionId;\n\n    private $requestCharged;\n\n    public function getDeleteMarker(): ?bool\n    {\n        $this->initialize();\n\n        return $this->deleteMarker;\n    }\n\n    /**\n     * @return RequestCharged::*|null\n     */\n    public function getRequestCharged(): ?string\n    {\n        $this->initialize();\n\n        return $this->requestCharged;\n    }\n\n    public function getVersionId(): ?string\n    {\n        $this->initialize();\n\n        return $this->versionId;\n    }\n\n    protected function populateResult(Response $response): void\n    {\n        $headers = $response->getHeaders();\n\n        $this->deleteMarker = isset($headers['x-amz-delete-marker'][0]) ? filter_var($headers['x-amz-delete-marker'][0], \\FILTER_VALIDATE_BOOLEAN) : null;\n        $this->versionId = $headers['x-amz-version-id'][0] ?? null;\n        $this->requestCharged = $headers['x-amz-request-charged'][0] ?? null;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Result/DeleteObjectsOutput.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Result;\n\nuse AsyncAws\\Core\\Response;\nuse AsyncAws\\Core\\Result;\nuse AsyncAws\\S3\\Enum\\RequestCharged;\nuse AsyncAws\\S3\\ValueObject\\DeletedObject;\nuse AsyncAws\\S3\\ValueObject\\Error;\n\nclass DeleteObjectsOutput extends Result\n{\n    /**\n     * Container element for a successful delete. It identifies the object that was successfully deleted.\n     */\n    private $deleted;\n\n    private $requestCharged;\n\n    /**\n     * Container for a failed delete action that describes the object that Amazon S3 attempted to delete and the error it\n     * encountered.\n     */\n    private $errors;\n\n    /**\n     * @return DeletedObject[]\n     */\n    public function getDeleted(): array\n    {\n        $this->initialize();\n\n        return $this->deleted;\n    }\n\n    /**\n     * @return Error[]\n     */\n    public function getErrors(): array\n    {\n        $this->initialize();\n\n        return $this->errors;\n    }\n\n    /**\n     * @return RequestCharged::*|null\n     */\n    public function getRequestCharged(): ?string\n    {\n        $this->initialize();\n\n        return $this->requestCharged;\n    }\n\n    protected function populateResult(Response $response): void\n    {\n        $headers = $response->getHeaders();\n\n        $this->requestCharged = $headers['x-amz-request-charged'][0] ?? null;\n\n        $data = new \\SimpleXMLElement($response->getContent());\n        $this->deleted = !$data->Deleted ? [] : $this->populateResultDeletedObjects($data->Deleted);\n        $this->errors = !$data->Error ? [] : $this->populateResultErrors($data->Error);\n    }\n\n    /**\n     * @return DeletedObject[]\n     */\n    private function populateResultDeletedObjects(\\SimpleXMLElement $xml): array\n    {\n        $items = [];\n        foreach ($xml as $item) {\n            $items[] = new DeletedObject([\n                'Key' => ($v = $item->Key) ? (string) $v : null,\n                'VersionId' => ($v = $item->VersionId) ? (string) $v : null,\n                'DeleteMarker' => ($v = $item->DeleteMarker) ? filter_var((string) $v, \\FILTER_VALIDATE_BOOLEAN) : null,\n                'DeleteMarkerVersionId' => ($v = $item->DeleteMarkerVersionId) ? (string) $v : null,\n            ]);\n        }\n\n        return $items;\n    }\n\n    /**\n     * @return Error[]\n     */\n    private function populateResultErrors(\\SimpleXMLElement $xml): array\n    {\n        $items = [];\n        foreach ($xml as $item) {\n            $items[] = new Error([\n                'Key' => ($v = $item->Key) ? (string) $v : null,\n                'VersionId' => ($v = $item->VersionId) ? (string) $v : null,\n                'Code' => ($v = $item->Code) ? (string) $v : null,\n                'Message' => ($v = $item->Message) ? (string) $v : null,\n            ]);\n        }\n\n        return $items;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Result/GetBucketCorsOutput.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Result;\n\nuse AsyncAws\\Core\\Response;\nuse AsyncAws\\Core\\Result;\nuse AsyncAws\\S3\\ValueObject\\CORSRule;\n\nclass GetBucketCorsOutput extends Result\n{\n    /**\n     * A set of origins and methods (cross-origin access that you want to allow). You can add up to 100 rules to the\n     * configuration.\n     */\n    private $corsRules;\n\n    /**\n     * @return CORSRule[]\n     */\n    public function getCorsRules(): array\n    {\n        $this->initialize();\n\n        return $this->corsRules;\n    }\n\n    protected function populateResult(Response $response): void\n    {\n        $data = new \\SimpleXMLElement($response->getContent());\n        $this->corsRules = !$data->CORSRule ? [] : $this->populateResultCORSRules($data->CORSRule);\n    }\n\n    /**\n     * @return string[]\n     */\n    private function populateResultAllowedHeaders(\\SimpleXMLElement $xml): array\n    {\n        $items = [];\n        foreach ($xml as $item) {\n            $a = ($v = $item) ? (string) $v : null;\n            if (null !== $a) {\n                $items[] = $a;\n            }\n        }\n\n        return $items;\n    }\n\n    /**\n     * @return string[]\n     */\n    private function populateResultAllowedMethods(\\SimpleXMLElement $xml): array\n    {\n        $items = [];\n        foreach ($xml as $item) {\n            $a = ($v = $item) ? (string) $v : null;\n            if (null !== $a) {\n                $items[] = $a;\n            }\n        }\n\n        return $items;\n    }\n\n    /**\n     * @return string[]\n     */\n    private function populateResultAllowedOrigins(\\SimpleXMLElement $xml): array\n    {\n        $items = [];\n        foreach ($xml as $item) {\n            $a = ($v = $item) ? (string) $v : null;\n            if (null !== $a) {\n                $items[] = $a;\n            }\n        }\n\n        return $items;\n    }\n\n    /**\n     * @return CORSRule[]\n     */\n    private function populateResultCORSRules(\\SimpleXMLElement $xml): array\n    {\n        $items = [];\n        foreach ($xml as $item) {\n            $items[] = new CORSRule([\n                'ID' => ($v = $item->ID) ? (string) $v : null,\n                'AllowedHeaders' => !$item->AllowedHeader ? null : $this->populateResultAllowedHeaders($item->AllowedHeader),\n                'AllowedMethods' => $this->populateResultAllowedMethods($item->AllowedMethod),\n                'AllowedOrigins' => $this->populateResultAllowedOrigins($item->AllowedOrigin),\n                'ExposeHeaders' => !$item->ExposeHeader ? null : $this->populateResultExposeHeaders($item->ExposeHeader),\n                'MaxAgeSeconds' => ($v = $item->MaxAgeSeconds) ? (int) (string) $v : null,\n            ]);\n        }\n\n        return $items;\n    }\n\n    /**\n     * @return string[]\n     */\n    private function populateResultExposeHeaders(\\SimpleXMLElement $xml): array\n    {\n        $items = [];\n        foreach ($xml as $item) {\n            $a = ($v = $item) ? (string) $v : null;\n            if (null !== $a) {\n                $items[] = $a;\n            }\n        }\n\n        return $items;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Result/GetBucketEncryptionOutput.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Result;\n\nuse AsyncAws\\Core\\Response;\nuse AsyncAws\\Core\\Result;\nuse AsyncAws\\S3\\ValueObject\\ServerSideEncryptionByDefault;\nuse AsyncAws\\S3\\ValueObject\\ServerSideEncryptionConfiguration;\nuse AsyncAws\\S3\\ValueObject\\ServerSideEncryptionRule;\n\nclass GetBucketEncryptionOutput extends Result\n{\n    private $serverSideEncryptionConfiguration;\n\n    public function getServerSideEncryptionConfiguration(): ?ServerSideEncryptionConfiguration\n    {\n        $this->initialize();\n\n        return $this->serverSideEncryptionConfiguration;\n    }\n\n    protected function populateResult(Response $response): void\n    {\n        $data = new \\SimpleXMLElement($response->getContent());\n        $this->serverSideEncryptionConfiguration = new ServerSideEncryptionConfiguration([\n            'Rules' => $this->populateResultServerSideEncryptionRules($data->Rule),\n        ]);\n    }\n\n    /**\n     * @return ServerSideEncryptionRule[]\n     */\n    private function populateResultServerSideEncryptionRules(\\SimpleXMLElement $xml): array\n    {\n        $items = [];\n        foreach ($xml as $item) {\n            $items[] = new ServerSideEncryptionRule([\n                'ApplyServerSideEncryptionByDefault' => !$item->ApplyServerSideEncryptionByDefault ? null : new ServerSideEncryptionByDefault([\n                    'SSEAlgorithm' => (string) $item->ApplyServerSideEncryptionByDefault->SSEAlgorithm,\n                    'KMSMasterKeyID' => ($v = $item->ApplyServerSideEncryptionByDefault->KMSMasterKeyID) ? (string) $v : null,\n                ]),\n                'BucketKeyEnabled' => ($v = $item->BucketKeyEnabled) ? filter_var((string) $v, \\FILTER_VALIDATE_BOOLEAN) : null,\n            ]);\n        }\n\n        return $items;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Result/GetObjectAclOutput.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Result;\n\nuse AsyncAws\\Core\\Response;\nuse AsyncAws\\Core\\Result;\nuse AsyncAws\\S3\\Enum\\RequestCharged;\nuse AsyncAws\\S3\\ValueObject\\Grant;\nuse AsyncAws\\S3\\ValueObject\\Grantee;\nuse AsyncAws\\S3\\ValueObject\\Owner;\n\nclass GetObjectAclOutput extends Result\n{\n    /**\n     * Container for the bucket owner's display name and ID.\n     */\n    private $owner;\n\n    /**\n     * A list of grants.\n     */\n    private $grants;\n\n    private $requestCharged;\n\n    /**\n     * @return Grant[]\n     */\n    public function getGrants(): array\n    {\n        $this->initialize();\n\n        return $this->grants;\n    }\n\n    public function getOwner(): ?Owner\n    {\n        $this->initialize();\n\n        return $this->owner;\n    }\n\n    /**\n     * @return RequestCharged::*|null\n     */\n    public function getRequestCharged(): ?string\n    {\n        $this->initialize();\n\n        return $this->requestCharged;\n    }\n\n    protected function populateResult(Response $response): void\n    {\n        $headers = $response->getHeaders();\n\n        $this->requestCharged = $headers['x-amz-request-charged'][0] ?? null;\n\n        $data = new \\SimpleXMLElement($response->getContent());\n        $this->owner = !$data->Owner ? null : new Owner([\n            'DisplayName' => ($v = $data->Owner->DisplayName) ? (string) $v : null,\n            'ID' => ($v = $data->Owner->ID) ? (string) $v : null,\n        ]);\n        $this->grants = !$data->AccessControlList ? [] : $this->populateResultGrants($data->AccessControlList);\n    }\n\n    /**\n     * @return Grant[]\n     */\n    private function populateResultGrants(\\SimpleXMLElement $xml): array\n    {\n        $items = [];\n        foreach ($xml->Grant as $item) {\n            $items[] = new Grant([\n                'Grantee' => !$item->Grantee ? null : new Grantee([\n                    'DisplayName' => ($v = $item->Grantee->DisplayName) ? (string) $v : null,\n                    'EmailAddress' => ($v = $item->Grantee->EmailAddress) ? (string) $v : null,\n                    'ID' => ($v = $item->Grantee->ID) ? (string) $v : null,\n                    'Type' => (string) ($item->Grantee->attributes('xsi', true)['type'][0] ?? null),\n                    'URI' => ($v = $item->Grantee->URI) ? (string) $v : null,\n                ]),\n                'Permission' => ($v = $item->Permission) ? (string) $v : null,\n            ]);\n        }\n\n        return $items;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Result/GetObjectOutput.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Result;\n\nuse AsyncAws\\Core\\Response;\nuse AsyncAws\\Core\\Result;\nuse AsyncAws\\Core\\Stream\\ResultStream;\nuse AsyncAws\\S3\\Enum\\ObjectLockLegalHoldStatus;\nuse AsyncAws\\S3\\Enum\\ObjectLockMode;\nuse AsyncAws\\S3\\Enum\\ReplicationStatus;\nuse AsyncAws\\S3\\Enum\\RequestCharged;\nuse AsyncAws\\S3\\Enum\\ServerSideEncryption;\nuse AsyncAws\\S3\\Enum\\StorageClass;\n\nclass GetObjectOutput extends Result\n{\n    /**\n     * Object data.\n     */\n    private $body;\n\n    /**\n     * Specifies whether the object retrieved was (true) or was not (false) a Delete Marker. If false, this response header\n     * does not appear in the response.\n     */\n    private $deleteMarker;\n\n    /**\n     * Indicates that a range of bytes was specified.\n     */\n    private $acceptRanges;\n\n    /**\n     * If the object expiration is configured (see PUT Bucket lifecycle), the response includes this header. It includes the\n     * `expiry-date` and `rule-id` key-value pairs providing object expiration information. The value of the `rule-id` is\n     * URL-encoded.\n     */\n    private $expiration;\n\n    /**\n     * Provides information about object restoration action and expiration time of the restored object copy.\n     */\n    private $restore;\n\n    /**\n     * Creation date of the object.\n     */\n    private $lastModified;\n\n    /**\n     * Size of the body in bytes.\n     */\n    private $contentLength;\n\n    /**\n     * An entity tag (ETag) is an opaque identifier assigned by a web server to a specific version of a resource found at a\n     * URL.\n     */\n    private $etag;\n\n    /**\n     * The base64-encoded, 32-bit CRC32 checksum of the object. This will only be present if it was uploaded with the\n     * object. With multipart uploads, this may not be a checksum value of the object. For more information about how\n     * checksums are calculated with multipart uploads, see  Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums\n     */\n    private $checksumCrc32;\n\n    /**\n     * The base64-encoded, 32-bit CRC32C checksum of the object. This will only be present if it was uploaded with the\n     * object. With multipart uploads, this may not be a checksum value of the object. For more information about how\n     * checksums are calculated with multipart uploads, see  Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums\n     */\n    private $checksumCrc32C;\n\n    /**\n     * The base64-encoded, 160-bit SHA-1 digest of the object. This will only be present if it was uploaded with the object.\n     * With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are\n     * calculated with multipart uploads, see  Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums\n     */\n    private $checksumSha1;\n\n    /**\n     * The base64-encoded, 256-bit SHA-256 digest of the object. This will only be present if it was uploaded with the\n     * object. With multipart uploads, this may not be a checksum value of the object. For more information about how\n     * checksums are calculated with multipart uploads, see  Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums\n     */\n    private $checksumSha256;\n\n    /**\n     * This is set to the number of metadata entries not returned in `x-amz-meta` headers. This can happen if you create\n     * metadata using an API like SOAP that supports more flexible metadata than the REST API. For example, using SOAP, you\n     * can create metadata whose values are not legal HTTP headers.\n     */\n    private $missingMeta;\n\n    /**\n     * Version of the object.\n     */\n    private $versionId;\n\n    /**\n     * Specifies caching behavior along the request/reply chain.\n     */\n    private $cacheControl;\n\n    /**\n     * Specifies presentational information for the object.\n     */\n    private $contentDisposition;\n\n    /**\n     * Specifies what content encodings have been applied to the object and thus what decoding mechanisms must be applied to\n     * obtain the media-type referenced by the Content-Type header field.\n     */\n    private $contentEncoding;\n\n    /**\n     * The language the content is in.\n     */\n    private $contentLanguage;\n\n    /**\n     * The portion of the object returned in the response.\n     */\n    private $contentRange;\n\n    /**\n     * A standard MIME type describing the format of the object data.\n     */\n    private $contentType;\n\n    /**\n     * The date and time at which the object is no longer cacheable.\n     */\n    private $expires;\n\n    /**\n     * If the bucket is configured as a website, redirects requests for this object to another object in the same bucket or\n     * to an external URL. Amazon S3 stores the value of this header in the object metadata.\n     */\n    private $websiteRedirectLocation;\n\n    /**\n     * The server-side encryption algorithm used when storing this object in Amazon S3 (for example, `AES256`, `aws:kms`,\n     * `aws:kms:dsse`).\n     */\n    private $serverSideEncryption;\n\n    /**\n     * A map of metadata to store with the object in S3.\n     */\n    private $metadata;\n\n    /**\n     * If server-side encryption with a customer-provided encryption key was requested, the response will include this\n     * header confirming the encryption algorithm used.\n     */\n    private $sseCustomerAlgorithm;\n\n    /**\n     * If server-side encryption with a customer-provided encryption key was requested, the response will include this\n     * header to provide round-trip message integrity verification of the customer-provided encryption key.\n     */\n    private $sseCustomerKeyMd5;\n\n    /**\n     * If present, specifies the ID of the Key Management Service (KMS) symmetric encryption customer managed key that was\n     * used for the object.\n     */\n    private $sseKmsKeyId;\n\n    /**\n     * Indicates whether the object uses an S3 Bucket Key for server-side encryption with Key Management Service (KMS) keys\n     * (SSE-KMS).\n     */\n    private $bucketKeyEnabled;\n\n    /**\n     * Provides storage class information of the object. Amazon S3 returns this header for all objects except for S3\n     * Standard storage class objects.\n     */\n    private $storageClass;\n\n    private $requestCharged;\n\n    /**\n     * Amazon S3 can return this if your request involves a bucket that is either a source or destination in a replication\n     * rule.\n     */\n    private $replicationStatus;\n\n    /**\n     * The count of parts this object has. This value is only returned if you specify `partNumber` in your request and the\n     * object was uploaded as a multipart upload.\n     */\n    private $partsCount;\n\n    /**\n     * The number of tags, if any, on the object.\n     */\n    private $tagCount;\n\n    /**\n     * The Object Lock mode currently in place for this object.\n     */\n    private $objectLockMode;\n\n    /**\n     * The date and time when this object's Object Lock will expire.\n     */\n    private $objectLockRetainUntilDate;\n\n    /**\n     * Indicates whether this object has an active legal hold. This field is only returned if you have permission to view an\n     * object's legal hold status.\n     */\n    private $objectLockLegalHoldStatus;\n\n    public function getAcceptRanges(): ?string\n    {\n        $this->initialize();\n\n        return $this->acceptRanges;\n    }\n\n    public function getBody(): ResultStream\n    {\n        $this->initialize();\n\n        return $this->body;\n    }\n\n    public function getBucketKeyEnabled(): ?bool\n    {\n        $this->initialize();\n\n        return $this->bucketKeyEnabled;\n    }\n\n    public function getCacheControl(): ?string\n    {\n        $this->initialize();\n\n        return $this->cacheControl;\n    }\n\n    public function getChecksumCrc32(): ?string\n    {\n        $this->initialize();\n\n        return $this->checksumCrc32;\n    }\n\n    public function getChecksumCrc32C(): ?string\n    {\n        $this->initialize();\n\n        return $this->checksumCrc32C;\n    }\n\n    public function getChecksumSha1(): ?string\n    {\n        $this->initialize();\n\n        return $this->checksumSha1;\n    }\n\n    public function getChecksumSha256(): ?string\n    {\n        $this->initialize();\n\n        return $this->checksumSha256;\n    }\n\n    public function getContentDisposition(): ?string\n    {\n        $this->initialize();\n\n        return $this->contentDisposition;\n    }\n\n    public function getContentEncoding(): ?string\n    {\n        $this->initialize();\n\n        return $this->contentEncoding;\n    }\n\n    public function getContentLanguage(): ?string\n    {\n        $this->initialize();\n\n        return $this->contentLanguage;\n    }\n\n    public function getContentLength(): ?string\n    {\n        $this->initialize();\n\n        return $this->contentLength;\n    }\n\n    public function getContentRange(): ?string\n    {\n        $this->initialize();\n\n        return $this->contentRange;\n    }\n\n    public function getContentType(): ?string\n    {\n        $this->initialize();\n\n        return $this->contentType;\n    }\n\n    public function getDeleteMarker(): ?bool\n    {\n        $this->initialize();\n\n        return $this->deleteMarker;\n    }\n\n    public function getEtag(): ?string\n    {\n        $this->initialize();\n\n        return $this->etag;\n    }\n\n    public function getExpiration(): ?string\n    {\n        $this->initialize();\n\n        return $this->expiration;\n    }\n\n    public function getExpires(): ?\\DateTimeImmutable\n    {\n        $this->initialize();\n\n        return $this->expires;\n    }\n\n    public function getLastModified(): ?\\DateTimeImmutable\n    {\n        $this->initialize();\n\n        return $this->lastModified;\n    }\n\n    /**\n     * @return array<string, string>\n     */\n    public function getMetadata(): array\n    {\n        $this->initialize();\n\n        return $this->metadata;\n    }\n\n    public function getMissingMeta(): ?int\n    {\n        $this->initialize();\n\n        return $this->missingMeta;\n    }\n\n    /**\n     * @return ObjectLockLegalHoldStatus::*|null\n     */\n    public function getObjectLockLegalHoldStatus(): ?string\n    {\n        $this->initialize();\n\n        return $this->objectLockLegalHoldStatus;\n    }\n\n    /**\n     * @return ObjectLockMode::*|null\n     */\n    public function getObjectLockMode(): ?string\n    {\n        $this->initialize();\n\n        return $this->objectLockMode;\n    }\n\n    public function getObjectLockRetainUntilDate(): ?\\DateTimeImmutable\n    {\n        $this->initialize();\n\n        return $this->objectLockRetainUntilDate;\n    }\n\n    public function getPartsCount(): ?int\n    {\n        $this->initialize();\n\n        return $this->partsCount;\n    }\n\n    /**\n     * @return ReplicationStatus::*|null\n     */\n    public function getReplicationStatus(): ?string\n    {\n        $this->initialize();\n\n        return $this->replicationStatus;\n    }\n\n    /**\n     * @return RequestCharged::*|null\n     */\n    public function getRequestCharged(): ?string\n    {\n        $this->initialize();\n\n        return $this->requestCharged;\n    }\n\n    public function getRestore(): ?string\n    {\n        $this->initialize();\n\n        return $this->restore;\n    }\n\n    /**\n     * @return ServerSideEncryption::*|null\n     */\n    public function getServerSideEncryption(): ?string\n    {\n        $this->initialize();\n\n        return $this->serverSideEncryption;\n    }\n\n    public function getSseCustomerAlgorithm(): ?string\n    {\n        $this->initialize();\n\n        return $this->sseCustomerAlgorithm;\n    }\n\n    public function getSseCustomerKeyMd5(): ?string\n    {\n        $this->initialize();\n\n        return $this->sseCustomerKeyMd5;\n    }\n\n    public function getSseKmsKeyId(): ?string\n    {\n        $this->initialize();\n\n        return $this->sseKmsKeyId;\n    }\n\n    /**\n     * @return StorageClass::*|null\n     */\n    public function getStorageClass(): ?string\n    {\n        $this->initialize();\n\n        return $this->storageClass;\n    }\n\n    public function getTagCount(): ?int\n    {\n        $this->initialize();\n\n        return $this->tagCount;\n    }\n\n    public function getVersionId(): ?string\n    {\n        $this->initialize();\n\n        return $this->versionId;\n    }\n\n    public function getWebsiteRedirectLocation(): ?string\n    {\n        $this->initialize();\n\n        return $this->websiteRedirectLocation;\n    }\n\n    protected function populateResult(Response $response): void\n    {\n        $headers = $response->getHeaders();\n\n        $this->deleteMarker = isset($headers['x-amz-delete-marker'][0]) ? filter_var($headers['x-amz-delete-marker'][0], \\FILTER_VALIDATE_BOOLEAN) : null;\n        $this->acceptRanges = $headers['accept-ranges'][0] ?? null;\n        $this->expiration = $headers['x-amz-expiration'][0] ?? null;\n        $this->restore = $headers['x-amz-restore'][0] ?? null;\n        $this->lastModified = isset($headers['last-modified'][0]) ? new \\DateTimeImmutable($headers['last-modified'][0]) : null;\n        $this->contentLength = $headers['content-length'][0] ?? null;\n        $this->etag = $headers['etag'][0] ?? null;\n        $this->checksumCrc32 = $headers['x-amz-checksum-crc32'][0] ?? null;\n        $this->checksumCrc32C = $headers['x-amz-checksum-crc32c'][0] ?? null;\n        $this->checksumSha1 = $headers['x-amz-checksum-sha1'][0] ?? null;\n        $this->checksumSha256 = $headers['x-amz-checksum-sha256'][0] ?? null;\n        $this->missingMeta = isset($headers['x-amz-missing-meta'][0]) ? filter_var($headers['x-amz-missing-meta'][0], \\FILTER_VALIDATE_INT) : null;\n        $this->versionId = $headers['x-amz-version-id'][0] ?? null;\n        $this->cacheControl = $headers['cache-control'][0] ?? null;\n        $this->contentDisposition = $headers['content-disposition'][0] ?? null;\n        $this->contentEncoding = $headers['content-encoding'][0] ?? null;\n        $this->contentLanguage = $headers['content-language'][0] ?? null;\n        $this->contentRange = $headers['content-range'][0] ?? null;\n        $this->contentType = $headers['content-type'][0] ?? null;\n        $this->expires = isset($headers['expires'][0]) ? new \\DateTimeImmutable($headers['expires'][0]) : null;\n        $this->websiteRedirectLocation = $headers['x-amz-website-redirect-location'][0] ?? null;\n        $this->serverSideEncryption = $headers['x-amz-server-side-encryption'][0] ?? null;\n        $this->sseCustomerAlgorithm = $headers['x-amz-server-side-encryption-customer-algorithm'][0] ?? null;\n        $this->sseCustomerKeyMd5 = $headers['x-amz-server-side-encryption-customer-key-md5'][0] ?? null;\n        $this->sseKmsKeyId = $headers['x-amz-server-side-encryption-aws-kms-key-id'][0] ?? null;\n        $this->bucketKeyEnabled = isset($headers['x-amz-server-side-encryption-bucket-key-enabled'][0]) ? filter_var($headers['x-amz-server-side-encryption-bucket-key-enabled'][0], \\FILTER_VALIDATE_BOOLEAN) : null;\n        $this->storageClass = $headers['x-amz-storage-class'][0] ?? null;\n        $this->requestCharged = $headers['x-amz-request-charged'][0] ?? null;\n        $this->replicationStatus = $headers['x-amz-replication-status'][0] ?? null;\n        $this->partsCount = isset($headers['x-amz-mp-parts-count'][0]) ? filter_var($headers['x-amz-mp-parts-count'][0], \\FILTER_VALIDATE_INT) : null;\n        $this->tagCount = isset($headers['x-amz-tagging-count'][0]) ? filter_var($headers['x-amz-tagging-count'][0], \\FILTER_VALIDATE_INT) : null;\n        $this->objectLockMode = $headers['x-amz-object-lock-mode'][0] ?? null;\n        $this->objectLockRetainUntilDate = isset($headers['x-amz-object-lock-retain-until-date'][0]) ? new \\DateTimeImmutable($headers['x-amz-object-lock-retain-until-date'][0]) : null;\n        $this->objectLockLegalHoldStatus = $headers['x-amz-object-lock-legal-hold'][0] ?? null;\n\n        $this->metadata = [];\n        foreach ($headers as $name => $value) {\n            if ('x-amz-meta-' === substr($name, 0, 11)) {\n                $this->metadata[substr($name, 11)] = $value[0];\n            }\n        }\n\n        $this->body = $response->toStream();\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Result/HeadObjectOutput.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Result;\n\nuse AsyncAws\\Core\\Response;\nuse AsyncAws\\Core\\Result;\nuse AsyncAws\\S3\\Enum\\ArchiveStatus;\nuse AsyncAws\\S3\\Enum\\ObjectLockLegalHoldStatus;\nuse AsyncAws\\S3\\Enum\\ObjectLockMode;\nuse AsyncAws\\S3\\Enum\\ReplicationStatus;\nuse AsyncAws\\S3\\Enum\\RequestCharged;\nuse AsyncAws\\S3\\Enum\\ServerSideEncryption;\nuse AsyncAws\\S3\\Enum\\StorageClass;\n\nclass HeadObjectOutput extends Result\n{\n    /**\n     * Specifies whether the object retrieved was (true) or was not (false) a Delete Marker. If false, this response header\n     * does not appear in the response.\n     */\n    private $deleteMarker;\n\n    /**\n     * Indicates that a range of bytes was specified.\n     */\n    private $acceptRanges;\n\n    /**\n     * If the object expiration is configured (see PUT Bucket lifecycle), the response includes this header. It includes the\n     * `expiry-date` and `rule-id` key-value pairs providing object expiration information. The value of the `rule-id` is\n     * URL-encoded.\n     */\n    private $expiration;\n\n    /**\n     * If the object is an archived object (an object whose storage class is GLACIER), the response includes this header if\n     * either the archive restoration is in progress (see RestoreObject [^1] or an archive copy is already restored.\n     *\n     * If an archive copy is already restored, the header value indicates when Amazon S3 is scheduled to delete the object\n     * copy. For example:\n     *\n     * `x-amz-restore: ongoing-request=\"false\", expiry-date=\"Fri, 21 Dec 2012 00:00:00 GMT\"`\n     *\n     * If the object restoration is in progress, the header returns the value `ongoing-request=\"true\"`.\n     *\n     * For more information about archiving objects, see Transitioning Objects: General Considerations [^2].\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_RestoreObject.html\n     * [^2]: https://docs.aws.amazon.com/AmazonS3/latest/dev/object-lifecycle-mgmt.html#lifecycle-transition-general-considerations\n     */\n    private $restore;\n\n    /**\n     * The archive state of the head object.\n     */\n    private $archiveStatus;\n\n    /**\n     * Creation date of the object.\n     */\n    private $lastModified;\n\n    /**\n     * Size of the body in bytes.\n     */\n    private $contentLength;\n\n    /**\n     * The base64-encoded, 32-bit CRC32 checksum of the object. This will only be present if it was uploaded with the\n     * object. With multipart uploads, this may not be a checksum value of the object. For more information about how\n     * checksums are calculated with multipart uploads, see  Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums\n     */\n    private $checksumCrc32;\n\n    /**\n     * The base64-encoded, 32-bit CRC32C checksum of the object. This will only be present if it was uploaded with the\n     * object. With multipart uploads, this may not be a checksum value of the object. For more information about how\n     * checksums are calculated with multipart uploads, see  Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums\n     */\n    private $checksumCrc32C;\n\n    /**\n     * The base64-encoded, 160-bit SHA-1 digest of the object. This will only be present if it was uploaded with the object.\n     * With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are\n     * calculated with multipart uploads, see  Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums\n     */\n    private $checksumSha1;\n\n    /**\n     * The base64-encoded, 256-bit SHA-256 digest of the object. This will only be present if it was uploaded with the\n     * object. With multipart uploads, this may not be a checksum value of the object. For more information about how\n     * checksums are calculated with multipart uploads, see  Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums\n     */\n    private $checksumSha256;\n\n    /**\n     * An entity tag (ETag) is an opaque identifier assigned by a web server to a specific version of a resource found at a\n     * URL.\n     */\n    private $etag;\n\n    /**\n     * This is set to the number of metadata entries not returned in `x-amz-meta` headers. This can happen if you create\n     * metadata using an API like SOAP that supports more flexible metadata than the REST API. For example, using SOAP, you\n     * can create metadata whose values are not legal HTTP headers.\n     */\n    private $missingMeta;\n\n    /**\n     * Version of the object.\n     */\n    private $versionId;\n\n    /**\n     * Specifies caching behavior along the request/reply chain.\n     */\n    private $cacheControl;\n\n    /**\n     * Specifies presentational information for the object.\n     */\n    private $contentDisposition;\n\n    /**\n     * Specifies what content encodings have been applied to the object and thus what decoding mechanisms must be applied to\n     * obtain the media-type referenced by the Content-Type header field.\n     */\n    private $contentEncoding;\n\n    /**\n     * The language the content is in.\n     */\n    private $contentLanguage;\n\n    /**\n     * A standard MIME type describing the format of the object data.\n     */\n    private $contentType;\n\n    /**\n     * The date and time at which the object is no longer cacheable.\n     */\n    private $expires;\n\n    /**\n     * If the bucket is configured as a website, redirects requests for this object to another object in the same bucket or\n     * to an external URL. Amazon S3 stores the value of this header in the object metadata.\n     */\n    private $websiteRedirectLocation;\n\n    /**\n     * The server-side encryption algorithm used when storing this object in Amazon S3 (for example, `AES256`, `aws:kms`,\n     * `aws:kms:dsse`).\n     */\n    private $serverSideEncryption;\n\n    /**\n     * A map of metadata to store with the object in S3.\n     */\n    private $metadata;\n\n    /**\n     * If server-side encryption with a customer-provided encryption key was requested, the response will include this\n     * header confirming the encryption algorithm used.\n     */\n    private $sseCustomerAlgorithm;\n\n    /**\n     * If server-side encryption with a customer-provided encryption key was requested, the response will include this\n     * header to provide round-trip message integrity verification of the customer-provided encryption key.\n     */\n    private $sseCustomerKeyMd5;\n\n    /**\n     * If present, specifies the ID of the Key Management Service (KMS) symmetric encryption customer managed key that was\n     * used for the object.\n     */\n    private $sseKmsKeyId;\n\n    /**\n     * Indicates whether the object uses an S3 Bucket Key for server-side encryption with Key Management Service (KMS) keys\n     * (SSE-KMS).\n     */\n    private $bucketKeyEnabled;\n\n    /**\n     * Provides storage class information of the object. Amazon S3 returns this header for all objects except for S3\n     * Standard storage class objects.\n     *\n     * For more information, see Storage Classes [^1].\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/dev/storage-class-intro.html\n     */\n    private $storageClass;\n\n    private $requestCharged;\n\n    /**\n     * Amazon S3 can return this header if your request involves a bucket that is either a source or a destination in a\n     * replication rule.\n     *\n     * In replication, you have a source bucket on which you configure replication and destination bucket or buckets where\n     * Amazon S3 stores object replicas. When you request an object (`GetObject`) or object metadata (`HeadObject`) from\n     * these buckets, Amazon S3 will return the `x-amz-replication-status` header in the response as follows:\n     *\n     * - **If requesting an object from the source bucket**, Amazon S3 will return the `x-amz-replication-status` header if\n     *   the object in your request is eligible for replication.\n     *\n     *   For example, suppose that in your replication configuration, you specify object prefix `TaxDocs` requesting Amazon\n     *   S3 to replicate objects with key prefix `TaxDocs`. Any objects you upload with this key name prefix, for example\n     *   `TaxDocs/document1.pdf`, are eligible for replication. For any object request with this key name prefix, Amazon S3\n     *   will return the `x-amz-replication-status` header with value PENDING, COMPLETED or FAILED indicating object\n     *   replication status.\n     * - **If requesting an object from a destination bucket**, Amazon S3 will return the `x-amz-replication-status` header\n     *   with value REPLICA if the object in your request is a replica that Amazon S3 created and there is no replica\n     *   modification replication in progress.\n     * - **When replicating objects to multiple destination buckets**, the `x-amz-replication-status` header acts\n     *   differently. The header of the source object will only return a value of COMPLETED when replication is successful\n     *   to all destinations. The header will remain at value PENDING until replication has completed for all destinations.\n     *   If one or more destinations fails replication the header will return FAILED.\n     *\n     * For more information, see Replication [^1].\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/dev/NotificationHowTo.html\n     */\n    private $replicationStatus;\n\n    /**\n     * The count of parts this object has. This value is only returned if you specify `partNumber` in your request and the\n     * object was uploaded as a multipart upload.\n     */\n    private $partsCount;\n\n    /**\n     * The Object Lock mode, if any, that's in effect for this object. This header is only returned if the requester has the\n     * `s3:GetObjectRetention` permission. For more information about S3 Object Lock, see Object Lock [^1].\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/dev/object-lock.html\n     */\n    private $objectLockMode;\n\n    /**\n     * The date and time when the Object Lock retention period expires. This header is only returned if the requester has\n     * the `s3:GetObjectRetention` permission.\n     */\n    private $objectLockRetainUntilDate;\n\n    /**\n     * Specifies whether a legal hold is in effect for this object. This header is only returned if the requester has the\n     * `s3:GetObjectLegalHold` permission. This header is not returned if the specified version of this object has never had\n     * a legal hold applied. For more information about S3 Object Lock, see Object Lock [^1].\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/dev/object-lock.html\n     */\n    private $objectLockLegalHoldStatus;\n\n    public function getAcceptRanges(): ?string\n    {\n        $this->initialize();\n\n        return $this->acceptRanges;\n    }\n\n    /**\n     * @return ArchiveStatus::*|null\n     */\n    public function getArchiveStatus(): ?string\n    {\n        $this->initialize();\n\n        return $this->archiveStatus;\n    }\n\n    public function getBucketKeyEnabled(): ?bool\n    {\n        $this->initialize();\n\n        return $this->bucketKeyEnabled;\n    }\n\n    public function getCacheControl(): ?string\n    {\n        $this->initialize();\n\n        return $this->cacheControl;\n    }\n\n    public function getChecksumCrc32(): ?string\n    {\n        $this->initialize();\n\n        return $this->checksumCrc32;\n    }\n\n    public function getChecksumCrc32C(): ?string\n    {\n        $this->initialize();\n\n        return $this->checksumCrc32C;\n    }\n\n    public function getChecksumSha1(): ?string\n    {\n        $this->initialize();\n\n        return $this->checksumSha1;\n    }\n\n    public function getChecksumSha256(): ?string\n    {\n        $this->initialize();\n\n        return $this->checksumSha256;\n    }\n\n    public function getContentDisposition(): ?string\n    {\n        $this->initialize();\n\n        return $this->contentDisposition;\n    }\n\n    public function getContentEncoding(): ?string\n    {\n        $this->initialize();\n\n        return $this->contentEncoding;\n    }\n\n    public function getContentLanguage(): ?string\n    {\n        $this->initialize();\n\n        return $this->contentLanguage;\n    }\n\n    public function getContentLength(): ?string\n    {\n        $this->initialize();\n\n        return $this->contentLength;\n    }\n\n    public function getContentType(): ?string\n    {\n        $this->initialize();\n\n        return $this->contentType;\n    }\n\n    public function getDeleteMarker(): ?bool\n    {\n        $this->initialize();\n\n        return $this->deleteMarker;\n    }\n\n    public function getEtag(): ?string\n    {\n        $this->initialize();\n\n        return $this->etag;\n    }\n\n    public function getExpiration(): ?string\n    {\n        $this->initialize();\n\n        return $this->expiration;\n    }\n\n    public function getExpires(): ?\\DateTimeImmutable\n    {\n        $this->initialize();\n\n        return $this->expires;\n    }\n\n    public function getLastModified(): ?\\DateTimeImmutable\n    {\n        $this->initialize();\n\n        return $this->lastModified;\n    }\n\n    /**\n     * @return array<string, string>\n     */\n    public function getMetadata(): array\n    {\n        $this->initialize();\n\n        return $this->metadata;\n    }\n\n    public function getMissingMeta(): ?int\n    {\n        $this->initialize();\n\n        return $this->missingMeta;\n    }\n\n    /**\n     * @return ObjectLockLegalHoldStatus::*|null\n     */\n    public function getObjectLockLegalHoldStatus(): ?string\n    {\n        $this->initialize();\n\n        return $this->objectLockLegalHoldStatus;\n    }\n\n    /**\n     * @return ObjectLockMode::*|null\n     */\n    public function getObjectLockMode(): ?string\n    {\n        $this->initialize();\n\n        return $this->objectLockMode;\n    }\n\n    public function getObjectLockRetainUntilDate(): ?\\DateTimeImmutable\n    {\n        $this->initialize();\n\n        return $this->objectLockRetainUntilDate;\n    }\n\n    public function getPartsCount(): ?int\n    {\n        $this->initialize();\n\n        return $this->partsCount;\n    }\n\n    /**\n     * @return ReplicationStatus::*|null\n     */\n    public function getReplicationStatus(): ?string\n    {\n        $this->initialize();\n\n        return $this->replicationStatus;\n    }\n\n    /**\n     * @return RequestCharged::*|null\n     */\n    public function getRequestCharged(): ?string\n    {\n        $this->initialize();\n\n        return $this->requestCharged;\n    }\n\n    public function getRestore(): ?string\n    {\n        $this->initialize();\n\n        return $this->restore;\n    }\n\n    /**\n     * @return ServerSideEncryption::*|null\n     */\n    public function getServerSideEncryption(): ?string\n    {\n        $this->initialize();\n\n        return $this->serverSideEncryption;\n    }\n\n    public function getSseCustomerAlgorithm(): ?string\n    {\n        $this->initialize();\n\n        return $this->sseCustomerAlgorithm;\n    }\n\n    public function getSseCustomerKeyMd5(): ?string\n    {\n        $this->initialize();\n\n        return $this->sseCustomerKeyMd5;\n    }\n\n    public function getSseKmsKeyId(): ?string\n    {\n        $this->initialize();\n\n        return $this->sseKmsKeyId;\n    }\n\n    /**\n     * @return StorageClass::*|null\n     */\n    public function getStorageClass(): ?string\n    {\n        $this->initialize();\n\n        return $this->storageClass;\n    }\n\n    public function getVersionId(): ?string\n    {\n        $this->initialize();\n\n        return $this->versionId;\n    }\n\n    public function getWebsiteRedirectLocation(): ?string\n    {\n        $this->initialize();\n\n        return $this->websiteRedirectLocation;\n    }\n\n    protected function populateResult(Response $response): void\n    {\n        $headers = $response->getHeaders();\n\n        $this->deleteMarker = isset($headers['x-amz-delete-marker'][0]) ? filter_var($headers['x-amz-delete-marker'][0], \\FILTER_VALIDATE_BOOLEAN) : null;\n        $this->acceptRanges = $headers['accept-ranges'][0] ?? null;\n        $this->expiration = $headers['x-amz-expiration'][0] ?? null;\n        $this->restore = $headers['x-amz-restore'][0] ?? null;\n        $this->archiveStatus = $headers['x-amz-archive-status'][0] ?? null;\n        $this->lastModified = isset($headers['last-modified'][0]) ? new \\DateTimeImmutable($headers['last-modified'][0]) : null;\n        $this->contentLength = $headers['content-length'][0] ?? null;\n        $this->checksumCrc32 = $headers['x-amz-checksum-crc32'][0] ?? null;\n        $this->checksumCrc32C = $headers['x-amz-checksum-crc32c'][0] ?? null;\n        $this->checksumSha1 = $headers['x-amz-checksum-sha1'][0] ?? null;\n        $this->checksumSha256 = $headers['x-amz-checksum-sha256'][0] ?? null;\n        $this->etag = $headers['etag'][0] ?? null;\n        $this->missingMeta = isset($headers['x-amz-missing-meta'][0]) ? filter_var($headers['x-amz-missing-meta'][0], \\FILTER_VALIDATE_INT) : null;\n        $this->versionId = $headers['x-amz-version-id'][0] ?? null;\n        $this->cacheControl = $headers['cache-control'][0] ?? null;\n        $this->contentDisposition = $headers['content-disposition'][0] ?? null;\n        $this->contentEncoding = $headers['content-encoding'][0] ?? null;\n        $this->contentLanguage = $headers['content-language'][0] ?? null;\n        $this->contentType = $headers['content-type'][0] ?? null;\n        $this->expires = isset($headers['expires'][0]) ? new \\DateTimeImmutable($headers['expires'][0]) : null;\n        $this->websiteRedirectLocation = $headers['x-amz-website-redirect-location'][0] ?? null;\n        $this->serverSideEncryption = $headers['x-amz-server-side-encryption'][0] ?? null;\n        $this->sseCustomerAlgorithm = $headers['x-amz-server-side-encryption-customer-algorithm'][0] ?? null;\n        $this->sseCustomerKeyMd5 = $headers['x-amz-server-side-encryption-customer-key-md5'][0] ?? null;\n        $this->sseKmsKeyId = $headers['x-amz-server-side-encryption-aws-kms-key-id'][0] ?? null;\n        $this->bucketKeyEnabled = isset($headers['x-amz-server-side-encryption-bucket-key-enabled'][0]) ? filter_var($headers['x-amz-server-side-encryption-bucket-key-enabled'][0], \\FILTER_VALIDATE_BOOLEAN) : null;\n        $this->storageClass = $headers['x-amz-storage-class'][0] ?? null;\n        $this->requestCharged = $headers['x-amz-request-charged'][0] ?? null;\n        $this->replicationStatus = $headers['x-amz-replication-status'][0] ?? null;\n        $this->partsCount = isset($headers['x-amz-mp-parts-count'][0]) ? filter_var($headers['x-amz-mp-parts-count'][0], \\FILTER_VALIDATE_INT) : null;\n        $this->objectLockMode = $headers['x-amz-object-lock-mode'][0] ?? null;\n        $this->objectLockRetainUntilDate = isset($headers['x-amz-object-lock-retain-until-date'][0]) ? new \\DateTimeImmutable($headers['x-amz-object-lock-retain-until-date'][0]) : null;\n        $this->objectLockLegalHoldStatus = $headers['x-amz-object-lock-legal-hold'][0] ?? null;\n\n        $this->metadata = [];\n        foreach ($headers as $name => $value) {\n            if ('x-amz-meta-' === substr($name, 0, 11)) {\n                $this->metadata[substr($name, 11)] = $value[0];\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Result/ListBucketsOutput.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Result;\n\nuse AsyncAws\\Core\\Response;\nuse AsyncAws\\Core\\Result;\nuse AsyncAws\\S3\\ValueObject\\Bucket;\nuse AsyncAws\\S3\\ValueObject\\Owner;\n\n/**\n * @implements \\IteratorAggregate<Bucket>\n */\nclass ListBucketsOutput extends Result implements \\IteratorAggregate\n{\n    /**\n     * The list of buckets owned by the requester.\n     */\n    private $buckets;\n\n    /**\n     * The owner of the buckets listed.\n     */\n    private $owner;\n\n    /**\n     * @return iterable<Bucket>\n     */\n    public function getBuckets(): iterable\n    {\n        $this->initialize();\n\n        return $this->buckets;\n    }\n\n    /**\n     * Iterates over Buckets.\n     *\n     * @return \\Traversable<Bucket>\n     */\n    public function getIterator(): \\Traversable\n    {\n        yield from $this->getBuckets();\n    }\n\n    public function getOwner(): ?Owner\n    {\n        $this->initialize();\n\n        return $this->owner;\n    }\n\n    protected function populateResult(Response $response): void\n    {\n        $data = new \\SimpleXMLElement($response->getContent());\n        $this->buckets = !$data->Buckets ? [] : $this->populateResultBuckets($data->Buckets);\n        $this->owner = !$data->Owner ? null : new Owner([\n            'DisplayName' => ($v = $data->Owner->DisplayName) ? (string) $v : null,\n            'ID' => ($v = $data->Owner->ID) ? (string) $v : null,\n        ]);\n    }\n\n    /**\n     * @return Bucket[]\n     */\n    private function populateResultBuckets(\\SimpleXMLElement $xml): array\n    {\n        $items = [];\n        foreach ($xml->Bucket as $item) {\n            $items[] = new Bucket([\n                'Name' => ($v = $item->Name) ? (string) $v : null,\n                'CreationDate' => ($v = $item->CreationDate) ? new \\DateTimeImmutable((string) $v) : null,\n            ]);\n        }\n\n        return $items;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Result/ListMultipartUploadsOutput.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Result;\n\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\nuse AsyncAws\\Core\\Response;\nuse AsyncAws\\Core\\Result;\nuse AsyncAws\\S3\\Enum\\EncodingType;\nuse AsyncAws\\S3\\Enum\\RequestCharged;\nuse AsyncAws\\S3\\Input\\ListMultipartUploadsRequest;\nuse AsyncAws\\S3\\S3Client;\nuse AsyncAws\\S3\\ValueObject\\CommonPrefix;\nuse AsyncAws\\S3\\ValueObject\\Initiator;\nuse AsyncAws\\S3\\ValueObject\\MultipartUpload;\nuse AsyncAws\\S3\\ValueObject\\Owner;\n\n/**\n * @implements \\IteratorAggregate<MultipartUpload|CommonPrefix>\n */\nclass ListMultipartUploadsOutput extends Result implements \\IteratorAggregate\n{\n    /**\n     * The name of the bucket to which the multipart upload was initiated. Does not return the access point ARN or access\n     * point alias if used.\n     */\n    private $bucket;\n\n    /**\n     * The key at or after which the listing began.\n     */\n    private $keyMarker;\n\n    /**\n     * Upload ID after which listing began.\n     */\n    private $uploadIdMarker;\n\n    /**\n     * When a list is truncated, this element specifies the value that should be used for the key-marker request parameter\n     * in a subsequent request.\n     */\n    private $nextKeyMarker;\n\n    /**\n     * When a prefix is provided in the request, this field contains the specified prefix. The result contains only keys\n     * starting with the specified prefix.\n     */\n    private $prefix;\n\n    /**\n     * Contains the delimiter you specified in the request. If you don't specify a delimiter in your request, this element\n     * is absent from the response.\n     */\n    private $delimiter;\n\n    /**\n     * When a list is truncated, this element specifies the value that should be used for the `upload-id-marker` request\n     * parameter in a subsequent request.\n     */\n    private $nextUploadIdMarker;\n\n    /**\n     * Maximum number of multipart uploads that could have been included in the response.\n     */\n    private $maxUploads;\n\n    /**\n     * Indicates whether the returned list of multipart uploads is truncated. A value of true indicates that the list was\n     * truncated. The list can be truncated if the number of multipart uploads exceeds the limit allowed or specified by max\n     * uploads.\n     */\n    private $isTruncated;\n\n    /**\n     * Container for elements related to a particular multipart upload. A response can contain zero or more `Upload`\n     * elements.\n     */\n    private $uploads;\n\n    /**\n     * If you specify a delimiter in the request, then the result returns each distinct key prefix containing the delimiter\n     * in a `CommonPrefixes` element. The distinct key prefixes are returned in the `Prefix` child element.\n     */\n    private $commonPrefixes;\n\n    /**\n     * Encoding type used by Amazon S3 to encode object keys in the response.\n     *\n     * If you specify `encoding-type` request parameter, Amazon S3 includes this element in the response, and returns\n     * encoded key name values in the following response elements:\n     *\n     * `Delimiter`, `KeyMarker`, `Prefix`, `NextKeyMarker`, `Key`.\n     */\n    private $encodingType;\n\n    private $requestCharged;\n\n    public function getBucket(): ?string\n    {\n        $this->initialize();\n\n        return $this->bucket;\n    }\n\n    /**\n     * @param bool $currentPageOnly When true, iterates over items of the current page. Otherwise also fetch items in the next pages.\n     *\n     * @return iterable<CommonPrefix>\n     */\n    public function getCommonPrefixes(bool $currentPageOnly = false): iterable\n    {\n        if ($currentPageOnly) {\n            $this->initialize();\n            yield from $this->commonPrefixes;\n\n            return;\n        }\n\n        $client = $this->awsClient;\n        if (!$client instanceof S3Client) {\n            throw new InvalidArgument('missing client injected in paginated result');\n        }\n        if (!$this->input instanceof ListMultipartUploadsRequest) {\n            throw new InvalidArgument('missing last request injected in paginated result');\n        }\n        $input = clone $this->input;\n        $page = $this;\n        while (true) {\n            $page->initialize();\n            if ($page->isTruncated) {\n                $input->setKeyMarker($page->nextKeyMarker);\n\n                $input->setUploadIdMarker($page->nextUploadIdMarker);\n\n                $this->registerPrefetch($nextPage = $client->listMultipartUploads($input));\n            } else {\n                $nextPage = null;\n            }\n\n            yield from $page->commonPrefixes;\n\n            if (null === $nextPage) {\n                break;\n            }\n\n            $this->unregisterPrefetch($nextPage);\n            $page = $nextPage;\n        }\n    }\n\n    public function getDelimiter(): ?string\n    {\n        $this->initialize();\n\n        return $this->delimiter;\n    }\n\n    /**\n     * @return EncodingType::*|null\n     */\n    public function getEncodingType(): ?string\n    {\n        $this->initialize();\n\n        return $this->encodingType;\n    }\n\n    public function getIsTruncated(): ?bool\n    {\n        $this->initialize();\n\n        return $this->isTruncated;\n    }\n\n    /**\n     * Iterates over Uploads and CommonPrefixes.\n     *\n     * @return \\Traversable<MultipartUpload|CommonPrefix>\n     */\n    public function getIterator(): \\Traversable\n    {\n        $client = $this->awsClient;\n        if (!$client instanceof S3Client) {\n            throw new InvalidArgument('missing client injected in paginated result');\n        }\n        if (!$this->input instanceof ListMultipartUploadsRequest) {\n            throw new InvalidArgument('missing last request injected in paginated result');\n        }\n        $input = clone $this->input;\n        $page = $this;\n        while (true) {\n            $page->initialize();\n            if ($page->isTruncated) {\n                $input->setKeyMarker($page->nextKeyMarker);\n\n                $input->setUploadIdMarker($page->nextUploadIdMarker);\n\n                $this->registerPrefetch($nextPage = $client->listMultipartUploads($input));\n            } else {\n                $nextPage = null;\n            }\n\n            yield from $page->getUploads(true);\n            yield from $page->getCommonPrefixes(true);\n\n            if (null === $nextPage) {\n                break;\n            }\n\n            $this->unregisterPrefetch($nextPage);\n            $page = $nextPage;\n        }\n    }\n\n    public function getKeyMarker(): ?string\n    {\n        $this->initialize();\n\n        return $this->keyMarker;\n    }\n\n    public function getMaxUploads(): ?int\n    {\n        $this->initialize();\n\n        return $this->maxUploads;\n    }\n\n    public function getNextKeyMarker(): ?string\n    {\n        $this->initialize();\n\n        return $this->nextKeyMarker;\n    }\n\n    public function getNextUploadIdMarker(): ?string\n    {\n        $this->initialize();\n\n        return $this->nextUploadIdMarker;\n    }\n\n    public function getPrefix(): ?string\n    {\n        $this->initialize();\n\n        return $this->prefix;\n    }\n\n    /**\n     * @return RequestCharged::*|null\n     */\n    public function getRequestCharged(): ?string\n    {\n        $this->initialize();\n\n        return $this->requestCharged;\n    }\n\n    public function getUploadIdMarker(): ?string\n    {\n        $this->initialize();\n\n        return $this->uploadIdMarker;\n    }\n\n    /**\n     * @param bool $currentPageOnly When true, iterates over items of the current page. Otherwise also fetch items in the next pages.\n     *\n     * @return iterable<MultipartUpload>\n     */\n    public function getUploads(bool $currentPageOnly = false): iterable\n    {\n        if ($currentPageOnly) {\n            $this->initialize();\n            yield from $this->uploads;\n\n            return;\n        }\n\n        $client = $this->awsClient;\n        if (!$client instanceof S3Client) {\n            throw new InvalidArgument('missing client injected in paginated result');\n        }\n        if (!$this->input instanceof ListMultipartUploadsRequest) {\n            throw new InvalidArgument('missing last request injected in paginated result');\n        }\n        $input = clone $this->input;\n        $page = $this;\n        while (true) {\n            $page->initialize();\n            if ($page->isTruncated) {\n                $input->setKeyMarker($page->nextKeyMarker);\n\n                $input->setUploadIdMarker($page->nextUploadIdMarker);\n\n                $this->registerPrefetch($nextPage = $client->listMultipartUploads($input));\n            } else {\n                $nextPage = null;\n            }\n\n            yield from $page->uploads;\n\n            if (null === $nextPage) {\n                break;\n            }\n\n            $this->unregisterPrefetch($nextPage);\n            $page = $nextPage;\n        }\n    }\n\n    protected function populateResult(Response $response): void\n    {\n        $headers = $response->getHeaders();\n\n        $this->requestCharged = $headers['x-amz-request-charged'][0] ?? null;\n\n        $data = new \\SimpleXMLElement($response->getContent());\n        $this->bucket = ($v = $data->Bucket) ? (string) $v : null;\n        $this->keyMarker = ($v = $data->KeyMarker) ? (string) $v : null;\n        $this->uploadIdMarker = ($v = $data->UploadIdMarker) ? (string) $v : null;\n        $this->nextKeyMarker = ($v = $data->NextKeyMarker) ? (string) $v : null;\n        $this->prefix = ($v = $data->Prefix) ? (string) $v : null;\n        $this->delimiter = ($v = $data->Delimiter) ? (string) $v : null;\n        $this->nextUploadIdMarker = ($v = $data->NextUploadIdMarker) ? (string) $v : null;\n        $this->maxUploads = ($v = $data->MaxUploads) ? (int) (string) $v : null;\n        $this->isTruncated = ($v = $data->IsTruncated) ? filter_var((string) $v, \\FILTER_VALIDATE_BOOLEAN) : null;\n        $this->uploads = !$data->Upload ? [] : $this->populateResultMultipartUploadList($data->Upload);\n        $this->commonPrefixes = !$data->CommonPrefixes ? [] : $this->populateResultCommonPrefixList($data->CommonPrefixes);\n        $this->encodingType = ($v = $data->EncodingType) ? (string) $v : null;\n    }\n\n    /**\n     * @return CommonPrefix[]\n     */\n    private function populateResultCommonPrefixList(\\SimpleXMLElement $xml): array\n    {\n        $items = [];\n        foreach ($xml as $item) {\n            $items[] = new CommonPrefix([\n                'Prefix' => ($v = $item->Prefix) ? (string) $v : null,\n            ]);\n        }\n\n        return $items;\n    }\n\n    /**\n     * @return MultipartUpload[]\n     */\n    private function populateResultMultipartUploadList(\\SimpleXMLElement $xml): array\n    {\n        $items = [];\n        foreach ($xml as $item) {\n            $items[] = new MultipartUpload([\n                'UploadId' => ($v = $item->UploadId) ? (string) $v : null,\n                'Key' => ($v = $item->Key) ? (string) $v : null,\n                'Initiated' => ($v = $item->Initiated) ? new \\DateTimeImmutable((string) $v) : null,\n                'StorageClass' => ($v = $item->StorageClass) ? (string) $v : null,\n                'Owner' => !$item->Owner ? null : new Owner([\n                    'DisplayName' => ($v = $item->Owner->DisplayName) ? (string) $v : null,\n                    'ID' => ($v = $item->Owner->ID) ? (string) $v : null,\n                ]),\n                'Initiator' => !$item->Initiator ? null : new Initiator([\n                    'ID' => ($v = $item->Initiator->ID) ? (string) $v : null,\n                    'DisplayName' => ($v = $item->Initiator->DisplayName) ? (string) $v : null,\n                ]),\n                'ChecksumAlgorithm' => ($v = $item->ChecksumAlgorithm) ? (string) $v : null,\n            ]);\n        }\n\n        return $items;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Result/ListObjectsV2Output.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Result;\n\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\nuse AsyncAws\\Core\\Response;\nuse AsyncAws\\Core\\Result;\nuse AsyncAws\\S3\\Enum\\ChecksumAlgorithm;\nuse AsyncAws\\S3\\Enum\\EncodingType;\nuse AsyncAws\\S3\\Enum\\RequestCharged;\nuse AsyncAws\\S3\\Input\\ListObjectsV2Request;\nuse AsyncAws\\S3\\S3Client;\nuse AsyncAws\\S3\\ValueObject\\AwsObject;\nuse AsyncAws\\S3\\ValueObject\\CommonPrefix;\nuse AsyncAws\\S3\\ValueObject\\Owner;\n\n/**\n * @implements \\IteratorAggregate<AwsObject|CommonPrefix>\n */\nclass ListObjectsV2Output extends Result implements \\IteratorAggregate\n{\n    /**\n     * Set to false if all of the results were returned. Set to true if more keys are available to return. If the number of\n     * results exceeds that specified by MaxKeys, all of the results might not be returned.\n     */\n    private $isTruncated;\n\n    /**\n     * Metadata about each object returned.\n     */\n    private $contents;\n\n    /**\n     * The bucket name.\n     *\n     * When using this action with an access point, you must direct requests to the access point hostname. The access point\n     * hostname takes the form *AccessPointName*-*AccountId*.s3-accesspoint.*Region*.amazonaws.com. When using this action\n     * with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket\n     * name. For more information about access point ARNs, see Using access points [^1] in the *Amazon S3 User Guide*.\n     *\n     * When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3\n     * on Outposts hostname takes the form `*AccessPointName*-*AccountId*.*outpostID*.s3-outposts.*Region*.amazonaws.com`.\n     * When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access\n     * point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts\n     * [^2] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html\n     * [^2]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html\n     */\n    private $name;\n\n    /**\n     * Keys that begin with the indicated prefix.\n     */\n    private $prefix;\n\n    /**\n     * Causes keys that contain the same string between the prefix and the first occurrence of the delimiter to be rolled up\n     * into a single result element in the CommonPrefixes collection. These rolled-up keys are not returned elsewhere in the\n     * response. Each rolled-up result counts as only one return against the `MaxKeys` value.\n     */\n    private $delimiter;\n\n    /**\n     * Sets the maximum number of keys returned in the response. By default the action returns up to 1,000 key names. The\n     * response might contain fewer keys but will never contain more.\n     */\n    private $maxKeys;\n\n    /**\n     * All of the keys (up to 1,000) rolled up into a common prefix count as a single return when calculating the number of\n     * returns.\n     *\n     * A response can contain `CommonPrefixes` only if you specify a delimiter.\n     *\n     * `CommonPrefixes` contains all (if there are any) keys between `Prefix` and the next occurrence of the string\n     * specified by a delimiter.\n     *\n     * `CommonPrefixes` lists keys that act like subdirectories in the directory specified by `Prefix`.\n     *\n     * For example, if the prefix is `notes/` and the delimiter is a slash (`/`) as in `notes/summer/july`, the common\n     * prefix is `notes/summer/`. All of the keys that roll up into a common prefix count as a single return when\n     * calculating the number of returns.\n     */\n    private $commonPrefixes;\n\n    /**\n     * Encoding type used by Amazon S3 to encode object key names in the XML response.\n     *\n     * If you specify the encoding-type request parameter, Amazon S3 includes this element in the response, and returns\n     * encoded key name values in the following response elements:\n     *\n     * `Delimiter, Prefix, Key,` and `StartAfter`.\n     */\n    private $encodingType;\n\n    /**\n     * KeyCount is the number of keys returned with this request. KeyCount will always be less than or equal to the\n     * `MaxKeys` field. Say you ask for 50 keys, your result will include 50 keys or fewer.\n     */\n    private $keyCount;\n\n    /**\n     * If ContinuationToken was sent with the request, it is included in the response.\n     */\n    private $continuationToken;\n\n    /**\n     * `NextContinuationToken` is sent when `isTruncated` is true, which means there are more keys in the bucket that can be\n     * listed. The next list requests to Amazon S3 can be continued with this `NextContinuationToken`.\n     * `NextContinuationToken` is obfuscated and is not a real key.\n     */\n    private $nextContinuationToken;\n\n    /**\n     * If StartAfter was sent with the request, it is included in the response.\n     */\n    private $startAfter;\n\n    private $requestCharged;\n\n    /**\n     * @param bool $currentPageOnly When true, iterates over items of the current page. Otherwise also fetch items in the next pages.\n     *\n     * @return iterable<CommonPrefix>\n     */\n    public function getCommonPrefixes(bool $currentPageOnly = false): iterable\n    {\n        if ($currentPageOnly) {\n            $this->initialize();\n            yield from $this->commonPrefixes;\n\n            return;\n        }\n\n        $client = $this->awsClient;\n        if (!$client instanceof S3Client) {\n            throw new InvalidArgument('missing client injected in paginated result');\n        }\n        if (!$this->input instanceof ListObjectsV2Request) {\n            throw new InvalidArgument('missing last request injected in paginated result');\n        }\n        $input = clone $this->input;\n        $page = $this;\n        while (true) {\n            $page->initialize();\n            if ($page->nextContinuationToken) {\n                $input->setContinuationToken($page->nextContinuationToken);\n\n                $this->registerPrefetch($nextPage = $client->listObjectsV2($input));\n            } else {\n                $nextPage = null;\n            }\n\n            yield from $page->commonPrefixes;\n\n            if (null === $nextPage) {\n                break;\n            }\n\n            $this->unregisterPrefetch($nextPage);\n            $page = $nextPage;\n        }\n    }\n\n    /**\n     * @param bool $currentPageOnly When true, iterates over items of the current page. Otherwise also fetch items in the next pages.\n     *\n     * @return iterable<AwsObject>\n     */\n    public function getContents(bool $currentPageOnly = false): iterable\n    {\n        if ($currentPageOnly) {\n            $this->initialize();\n            yield from $this->contents;\n\n            return;\n        }\n\n        $client = $this->awsClient;\n        if (!$client instanceof S3Client) {\n            throw new InvalidArgument('missing client injected in paginated result');\n        }\n        if (!$this->input instanceof ListObjectsV2Request) {\n            throw new InvalidArgument('missing last request injected in paginated result');\n        }\n        $input = clone $this->input;\n        $page = $this;\n        while (true) {\n            $page->initialize();\n            if ($page->nextContinuationToken) {\n                $input->setContinuationToken($page->nextContinuationToken);\n\n                $this->registerPrefetch($nextPage = $client->listObjectsV2($input));\n            } else {\n                $nextPage = null;\n            }\n\n            yield from $page->contents;\n\n            if (null === $nextPage) {\n                break;\n            }\n\n            $this->unregisterPrefetch($nextPage);\n            $page = $nextPage;\n        }\n    }\n\n    public function getContinuationToken(): ?string\n    {\n        $this->initialize();\n\n        return $this->continuationToken;\n    }\n\n    public function getDelimiter(): ?string\n    {\n        $this->initialize();\n\n        return $this->delimiter;\n    }\n\n    /**\n     * @return EncodingType::*|null\n     */\n    public function getEncodingType(): ?string\n    {\n        $this->initialize();\n\n        return $this->encodingType;\n    }\n\n    public function getIsTruncated(): ?bool\n    {\n        $this->initialize();\n\n        return $this->isTruncated;\n    }\n\n    /**\n     * Iterates over Contents and CommonPrefixes.\n     *\n     * @return \\Traversable<AwsObject|CommonPrefix>\n     */\n    public function getIterator(): \\Traversable\n    {\n        $client = $this->awsClient;\n        if (!$client instanceof S3Client) {\n            throw new InvalidArgument('missing client injected in paginated result');\n        }\n        if (!$this->input instanceof ListObjectsV2Request) {\n            throw new InvalidArgument('missing last request injected in paginated result');\n        }\n        $input = clone $this->input;\n        $page = $this;\n        while (true) {\n            $page->initialize();\n            if ($page->nextContinuationToken) {\n                $input->setContinuationToken($page->nextContinuationToken);\n\n                $this->registerPrefetch($nextPage = $client->listObjectsV2($input));\n            } else {\n                $nextPage = null;\n            }\n\n            yield from $page->getContents(true);\n            yield from $page->getCommonPrefixes(true);\n\n            if (null === $nextPage) {\n                break;\n            }\n\n            $this->unregisterPrefetch($nextPage);\n            $page = $nextPage;\n        }\n    }\n\n    public function getKeyCount(): ?int\n    {\n        $this->initialize();\n\n        return $this->keyCount;\n    }\n\n    public function getMaxKeys(): ?int\n    {\n        $this->initialize();\n\n        return $this->maxKeys;\n    }\n\n    public function getName(): ?string\n    {\n        $this->initialize();\n\n        return $this->name;\n    }\n\n    public function getNextContinuationToken(): ?string\n    {\n        $this->initialize();\n\n        return $this->nextContinuationToken;\n    }\n\n    public function getPrefix(): ?string\n    {\n        $this->initialize();\n\n        return $this->prefix;\n    }\n\n    /**\n     * @return RequestCharged::*|null\n     */\n    public function getRequestCharged(): ?string\n    {\n        $this->initialize();\n\n        return $this->requestCharged;\n    }\n\n    public function getStartAfter(): ?string\n    {\n        $this->initialize();\n\n        return $this->startAfter;\n    }\n\n    protected function populateResult(Response $response): void\n    {\n        $headers = $response->getHeaders();\n\n        $this->requestCharged = $headers['x-amz-request-charged'][0] ?? null;\n\n        $data = new \\SimpleXMLElement($response->getContent());\n        $this->isTruncated = ($v = $data->IsTruncated) ? filter_var((string) $v, \\FILTER_VALIDATE_BOOLEAN) : null;\n        $this->contents = !$data->Contents ? [] : $this->populateResultObjectList($data->Contents);\n        $this->name = ($v = $data->Name) ? (string) $v : null;\n        $this->prefix = ($v = $data->Prefix) ? (string) $v : null;\n        $this->delimiter = ($v = $data->Delimiter) ? (string) $v : null;\n        $this->maxKeys = ($v = $data->MaxKeys) ? (int) (string) $v : null;\n        $this->commonPrefixes = !$data->CommonPrefixes ? [] : $this->populateResultCommonPrefixList($data->CommonPrefixes);\n        $this->encodingType = ($v = $data->EncodingType) ? (string) $v : null;\n        $this->keyCount = ($v = $data->KeyCount) ? (int) (string) $v : null;\n        $this->continuationToken = ($v = $data->ContinuationToken) ? (string) $v : null;\n        $this->nextContinuationToken = ($v = $data->NextContinuationToken) ? (string) $v : null;\n        $this->startAfter = ($v = $data->StartAfter) ? (string) $v : null;\n    }\n\n    /**\n     * @return list<ChecksumAlgorithm::*>\n     */\n    private function populateResultChecksumAlgorithmList(\\SimpleXMLElement $xml): array\n    {\n        $items = [];\n        foreach ($xml as $item) {\n            $a = ($v = $item) ? (string) $v : null;\n            if (null !== $a) {\n                $items[] = $a;\n            }\n        }\n\n        return $items;\n    }\n\n    /**\n     * @return CommonPrefix[]\n     */\n    private function populateResultCommonPrefixList(\\SimpleXMLElement $xml): array\n    {\n        $items = [];\n        foreach ($xml as $item) {\n            $items[] = new CommonPrefix([\n                'Prefix' => ($v = $item->Prefix) ? (string) $v : null,\n            ]);\n        }\n\n        return $items;\n    }\n\n    /**\n     * @return AwsObject[]\n     */\n    private function populateResultObjectList(\\SimpleXMLElement $xml): array\n    {\n        $items = [];\n        foreach ($xml as $item) {\n            $items[] = new AwsObject([\n                'Key' => ($v = $item->Key) ? (string) $v : null,\n                'LastModified' => ($v = $item->LastModified) ? new \\DateTimeImmutable((string) $v) : null,\n                'ETag' => ($v = $item->ETag) ? (string) $v : null,\n                'ChecksumAlgorithm' => !$item->ChecksumAlgorithm ? null : $this->populateResultChecksumAlgorithmList($item->ChecksumAlgorithm),\n                'Size' => ($v = $item->Size) ? (string) $v : null,\n                'StorageClass' => ($v = $item->StorageClass) ? (string) $v : null,\n                'Owner' => !$item->Owner ? null : new Owner([\n                    'DisplayName' => ($v = $item->Owner->DisplayName) ? (string) $v : null,\n                    'ID' => ($v = $item->Owner->ID) ? (string) $v : null,\n                ]),\n            ]);\n        }\n\n        return $items;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Result/ListPartsOutput.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Result;\n\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\nuse AsyncAws\\Core\\Response;\nuse AsyncAws\\Core\\Result;\nuse AsyncAws\\S3\\Enum\\ChecksumAlgorithm;\nuse AsyncAws\\S3\\Enum\\RequestCharged;\nuse AsyncAws\\S3\\Enum\\StorageClass;\nuse AsyncAws\\S3\\Input\\ListPartsRequest;\nuse AsyncAws\\S3\\S3Client;\nuse AsyncAws\\S3\\ValueObject\\Initiator;\nuse AsyncAws\\S3\\ValueObject\\Owner;\nuse AsyncAws\\S3\\ValueObject\\Part;\n\n/**\n * @implements \\IteratorAggregate<Part>\n */\nclass ListPartsOutput extends Result implements \\IteratorAggregate\n{\n    /**\n     * If the bucket has a lifecycle rule configured with an action to abort incomplete multipart uploads and the prefix in\n     * the lifecycle rule matches the object name in the request, then the response includes this header indicating when the\n     * initiated multipart upload will become eligible for abort operation. For more information, see Aborting Incomplete\n     * Multipart Uploads Using a Bucket Lifecycle Configuration [^1].\n     *\n     * The response will also include the `x-amz-abort-rule-id` header that will provide the ID of the lifecycle\n     * configuration rule that defines this action.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/dev/mpuoverview.html#mpu-abort-incomplete-mpu-lifecycle-config\n     */\n    private $abortDate;\n\n    /**\n     * This header is returned along with the `x-amz-abort-date` header. It identifies applicable lifecycle configuration\n     * rule that defines the action to abort incomplete multipart uploads.\n     */\n    private $abortRuleId;\n\n    /**\n     * The name of the bucket to which the multipart upload was initiated. Does not return the access point ARN or access\n     * point alias if used.\n     */\n    private $bucket;\n\n    /**\n     * Object key for which the multipart upload was initiated.\n     */\n    private $key;\n\n    /**\n     * Upload ID identifying the multipart upload whose parts are being listed.\n     */\n    private $uploadId;\n\n    /**\n     * When a list is truncated, this element specifies the last part in the list, as well as the value to use for the\n     * part-number-marker request parameter in a subsequent request.\n     */\n    private $partNumberMarker;\n\n    /**\n     * When a list is truncated, this element specifies the last part in the list, as well as the value to use for the\n     * part-number-marker request parameter in a subsequent request.\n     */\n    private $nextPartNumberMarker;\n\n    /**\n     * Maximum number of parts that were allowed in the response.\n     */\n    private $maxParts;\n\n    /**\n     * Indicates whether the returned list of parts is truncated. A true value indicates that the list was truncated. A list\n     * can be truncated if the number of parts exceeds the limit returned in the MaxParts element.\n     */\n    private $isTruncated;\n\n    /**\n     * Container for elements related to a particular part. A response can contain zero or more `Part` elements.\n     */\n    private $parts;\n\n    /**\n     * Container element that identifies who initiated the multipart upload. If the initiator is an Amazon Web Services\n     * account, this element provides the same information as the `Owner` element. If the initiator is an IAM User, this\n     * element provides the user ARN and display name.\n     */\n    private $initiator;\n\n    /**\n     * Container element that identifies the object owner, after the object is created. If multipart upload is initiated by\n     * an IAM user, this element provides the parent account ID and display name.\n     */\n    private $owner;\n\n    /**\n     * Class of storage (STANDARD or REDUCED_REDUNDANCY) used to store the uploaded object.\n     */\n    private $storageClass;\n\n    private $requestCharged;\n\n    /**\n     * The algorithm that was used to create a checksum of the object.\n     */\n    private $checksumAlgorithm;\n\n    public function getAbortDate(): ?\\DateTimeImmutable\n    {\n        $this->initialize();\n\n        return $this->abortDate;\n    }\n\n    public function getAbortRuleId(): ?string\n    {\n        $this->initialize();\n\n        return $this->abortRuleId;\n    }\n\n    public function getBucket(): ?string\n    {\n        $this->initialize();\n\n        return $this->bucket;\n    }\n\n    /**\n     * @return ChecksumAlgorithm::*|null\n     */\n    public function getChecksumAlgorithm(): ?string\n    {\n        $this->initialize();\n\n        return $this->checksumAlgorithm;\n    }\n\n    public function getInitiator(): ?Initiator\n    {\n        $this->initialize();\n\n        return $this->initiator;\n    }\n\n    public function getIsTruncated(): ?bool\n    {\n        $this->initialize();\n\n        return $this->isTruncated;\n    }\n\n    /**\n     * Iterates over Parts.\n     *\n     * @return \\Traversable<Part>\n     */\n    public function getIterator(): \\Traversable\n    {\n        yield from $this->getParts();\n    }\n\n    public function getKey(): ?string\n    {\n        $this->initialize();\n\n        return $this->key;\n    }\n\n    public function getMaxParts(): ?int\n    {\n        $this->initialize();\n\n        return $this->maxParts;\n    }\n\n    public function getNextPartNumberMarker(): ?int\n    {\n        $this->initialize();\n\n        return $this->nextPartNumberMarker;\n    }\n\n    public function getOwner(): ?Owner\n    {\n        $this->initialize();\n\n        return $this->owner;\n    }\n\n    public function getPartNumberMarker(): ?int\n    {\n        $this->initialize();\n\n        return $this->partNumberMarker;\n    }\n\n    /**\n     * @param bool $currentPageOnly When true, iterates over items of the current page. Otherwise also fetch items in the next pages.\n     *\n     * @return iterable<Part>\n     */\n    public function getParts(bool $currentPageOnly = false): iterable\n    {\n        if ($currentPageOnly) {\n            $this->initialize();\n            yield from $this->parts;\n\n            return;\n        }\n\n        $client = $this->awsClient;\n        if (!$client instanceof S3Client) {\n            throw new InvalidArgument('missing client injected in paginated result');\n        }\n        if (!$this->input instanceof ListPartsRequest) {\n            throw new InvalidArgument('missing last request injected in paginated result');\n        }\n        $input = clone $this->input;\n        $page = $this;\n        while (true) {\n            $page->initialize();\n            if ($page->isTruncated) {\n                $input->setPartNumberMarker($page->nextPartNumberMarker);\n\n                $this->registerPrefetch($nextPage = $client->listParts($input));\n            } else {\n                $nextPage = null;\n            }\n\n            yield from $page->parts;\n\n            if (null === $nextPage) {\n                break;\n            }\n\n            $this->unregisterPrefetch($nextPage);\n            $page = $nextPage;\n        }\n    }\n\n    /**\n     * @return RequestCharged::*|null\n     */\n    public function getRequestCharged(): ?string\n    {\n        $this->initialize();\n\n        return $this->requestCharged;\n    }\n\n    /**\n     * @return StorageClass::*|null\n     */\n    public function getStorageClass(): ?string\n    {\n        $this->initialize();\n\n        return $this->storageClass;\n    }\n\n    public function getUploadId(): ?string\n    {\n        $this->initialize();\n\n        return $this->uploadId;\n    }\n\n    protected function populateResult(Response $response): void\n    {\n        $headers = $response->getHeaders();\n\n        $this->abortDate = isset($headers['x-amz-abort-date'][0]) ? new \\DateTimeImmutable($headers['x-amz-abort-date'][0]) : null;\n        $this->abortRuleId = $headers['x-amz-abort-rule-id'][0] ?? null;\n        $this->requestCharged = $headers['x-amz-request-charged'][0] ?? null;\n\n        $data = new \\SimpleXMLElement($response->getContent());\n        $this->bucket = ($v = $data->Bucket) ? (string) $v : null;\n        $this->key = ($v = $data->Key) ? (string) $v : null;\n        $this->uploadId = ($v = $data->UploadId) ? (string) $v : null;\n        $this->partNumberMarker = ($v = $data->PartNumberMarker) ? (int) (string) $v : null;\n        $this->nextPartNumberMarker = ($v = $data->NextPartNumberMarker) ? (int) (string) $v : null;\n        $this->maxParts = ($v = $data->MaxParts) ? (int) (string) $v : null;\n        $this->isTruncated = ($v = $data->IsTruncated) ? filter_var((string) $v, \\FILTER_VALIDATE_BOOLEAN) : null;\n        $this->parts = !$data->Part ? [] : $this->populateResultParts($data->Part);\n        $this->initiator = !$data->Initiator ? null : new Initiator([\n            'ID' => ($v = $data->Initiator->ID) ? (string) $v : null,\n            'DisplayName' => ($v = $data->Initiator->DisplayName) ? (string) $v : null,\n        ]);\n        $this->owner = !$data->Owner ? null : new Owner([\n            'DisplayName' => ($v = $data->Owner->DisplayName) ? (string) $v : null,\n            'ID' => ($v = $data->Owner->ID) ? (string) $v : null,\n        ]);\n        $this->storageClass = ($v = $data->StorageClass) ? (string) $v : null;\n        $this->checksumAlgorithm = ($v = $data->ChecksumAlgorithm) ? (string) $v : null;\n    }\n\n    /**\n     * @return Part[]\n     */\n    private function populateResultParts(\\SimpleXMLElement $xml): array\n    {\n        $items = [];\n        foreach ($xml as $item) {\n            $items[] = new Part([\n                'PartNumber' => ($v = $item->PartNumber) ? (int) (string) $v : null,\n                'LastModified' => ($v = $item->LastModified) ? new \\DateTimeImmutable((string) $v) : null,\n                'ETag' => ($v = $item->ETag) ? (string) $v : null,\n                'Size' => ($v = $item->Size) ? (string) $v : null,\n                'ChecksumCRC32' => ($v = $item->ChecksumCRC32) ? (string) $v : null,\n                'ChecksumCRC32C' => ($v = $item->ChecksumCRC32C) ? (string) $v : null,\n                'ChecksumSHA1' => ($v = $item->ChecksumSHA1) ? (string) $v : null,\n                'ChecksumSHA256' => ($v = $item->ChecksumSHA256) ? (string) $v : null,\n            ]);\n        }\n\n        return $items;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Result/ObjectExistsWaiter.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Result;\n\nuse AsyncAws\\Core\\Exception\\Http\\HttpException;\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\nuse AsyncAws\\Core\\Response;\nuse AsyncAws\\Core\\Waiter;\nuse AsyncAws\\S3\\Input\\HeadObjectRequest;\nuse AsyncAws\\S3\\S3Client;\n\nclass ObjectExistsWaiter extends Waiter\n{\n    protected const WAIT_TIMEOUT = 100.0;\n    protected const WAIT_DELAY = 5.0;\n\n    protected function extractState(Response $response, ?HttpException $exception): string\n    {\n        if (200 === $response->getStatusCode()) {\n            return self::STATE_SUCCESS;\n        }\n\n        if (404 === $response->getStatusCode()) {\n            return self::STATE_PENDING;\n        }\n\n        return null === $exception ? self::STATE_PENDING : self::STATE_FAILURE;\n    }\n\n    protected function refreshState(): Waiter\n    {\n        if (!$this->awsClient instanceof S3Client) {\n            throw new InvalidArgument('missing client injected in waiter result');\n        }\n        if (!$this->input instanceof HeadObjectRequest) {\n            throw new InvalidArgument('missing last request injected in waiter result');\n        }\n\n        return $this->awsClient->objectExists($this->input);\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Result/ObjectNotExistsWaiter.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Result;\n\nuse AsyncAws\\Core\\Exception\\Http\\HttpException;\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\nuse AsyncAws\\Core\\Response;\nuse AsyncAws\\Core\\Waiter;\nuse AsyncAws\\S3\\Input\\HeadObjectRequest;\nuse AsyncAws\\S3\\S3Client;\n\nclass ObjectNotExistsWaiter extends Waiter\n{\n    protected const WAIT_TIMEOUT = 100.0;\n    protected const WAIT_DELAY = 5.0;\n\n    protected function extractState(Response $response, ?HttpException $exception): string\n    {\n        if (404 === $response->getStatusCode()) {\n            return self::STATE_SUCCESS;\n        }\n\n        return null === $exception ? self::STATE_PENDING : self::STATE_FAILURE;\n    }\n\n    protected function refreshState(): Waiter\n    {\n        if (!$this->awsClient instanceof S3Client) {\n            throw new InvalidArgument('missing client injected in waiter result');\n        }\n        if (!$this->input instanceof HeadObjectRequest) {\n            throw new InvalidArgument('missing last request injected in waiter result');\n        }\n\n        return $this->awsClient->objectNotExists($this->input);\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Result/PutObjectAclOutput.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Result;\n\nuse AsyncAws\\Core\\Response;\nuse AsyncAws\\Core\\Result;\nuse AsyncAws\\S3\\Enum\\RequestCharged;\n\nclass PutObjectAclOutput extends Result\n{\n    private $requestCharged;\n\n    /**\n     * @return RequestCharged::*|null\n     */\n    public function getRequestCharged(): ?string\n    {\n        $this->initialize();\n\n        return $this->requestCharged;\n    }\n\n    protected function populateResult(Response $response): void\n    {\n        $headers = $response->getHeaders();\n\n        $this->requestCharged = $headers['x-amz-request-charged'][0] ?? null;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Result/PutObjectOutput.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Result;\n\nuse AsyncAws\\Core\\Response;\nuse AsyncAws\\Core\\Result;\nuse AsyncAws\\S3\\Enum\\RequestCharged;\nuse AsyncAws\\S3\\Enum\\ServerSideEncryption;\n\nclass PutObjectOutput extends Result\n{\n    /**\n     * If the expiration is configured for the object (see PutBucketLifecycleConfiguration [^1]), the response includes this\n     * header. It includes the `expiry-date` and `rule-id` key-value pairs that provide information about object expiration.\n     * The value of the `rule-id` is URL-encoded.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketLifecycleConfiguration.html\n     */\n    private $expiration;\n\n    /**\n     * Entity tag for the uploaded object.\n     */\n    private $etag;\n\n    /**\n     * The base64-encoded, 32-bit CRC32 checksum of the object. This will only be present if it was uploaded with the\n     * object. With multipart uploads, this may not be a checksum value of the object. For more information about how\n     * checksums are calculated with multipart uploads, see  Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums\n     */\n    private $checksumCrc32;\n\n    /**\n     * The base64-encoded, 32-bit CRC32C checksum of the object. This will only be present if it was uploaded with the\n     * object. With multipart uploads, this may not be a checksum value of the object. For more information about how\n     * checksums are calculated with multipart uploads, see  Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums\n     */\n    private $checksumCrc32C;\n\n    /**\n     * The base64-encoded, 160-bit SHA-1 digest of the object. This will only be present if it was uploaded with the object.\n     * With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are\n     * calculated with multipart uploads, see  Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums\n     */\n    private $checksumSha1;\n\n    /**\n     * The base64-encoded, 256-bit SHA-256 digest of the object. This will only be present if it was uploaded with the\n     * object. With multipart uploads, this may not be a checksum value of the object. For more information about how\n     * checksums are calculated with multipart uploads, see  Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums\n     */\n    private $checksumSha256;\n\n    /**\n     * The server-side encryption algorithm used when storing this object in Amazon S3 (for example, `AES256`, `aws:kms`,\n     * `aws:kms:dsse`).\n     */\n    private $serverSideEncryption;\n\n    /**\n     * Version of the object.\n     */\n    private $versionId;\n\n    /**\n     * If server-side encryption with a customer-provided encryption key was requested, the response will include this\n     * header confirming the encryption algorithm used.\n     */\n    private $sseCustomerAlgorithm;\n\n    /**\n     * If server-side encryption with a customer-provided encryption key was requested, the response will include this\n     * header to provide round-trip message integrity verification of the customer-provided encryption key.\n     */\n    private $sseCustomerKeyMd5;\n\n    /**\n     * If `x-amz-server-side-encryption` has a valid value of `aws:kms` or `aws:kms:dsse`, this header specifies the ID of\n     * the Key Management Service (KMS) symmetric encryption customer managed key that was used for the object.\n     */\n    private $sseKmsKeyId;\n\n    /**\n     * If present, specifies the Amazon Web Services KMS Encryption Context to use for object encryption. The value of this\n     * header is a base64-encoded UTF-8 string holding JSON with the encryption context key-value pairs. This value is\n     * stored as object metadata and automatically gets passed on to Amazon Web Services KMS for future `GetObject` or\n     * `CopyObject` operations on this object.\n     */\n    private $sseKmsEncryptionContext;\n\n    /**\n     * Indicates whether the uploaded object uses an S3 Bucket Key for server-side encryption with Key Management Service\n     * (KMS) keys (SSE-KMS).\n     */\n    private $bucketKeyEnabled;\n\n    private $requestCharged;\n\n    public function getBucketKeyEnabled(): ?bool\n    {\n        $this->initialize();\n\n        return $this->bucketKeyEnabled;\n    }\n\n    public function getChecksumCrc32(): ?string\n    {\n        $this->initialize();\n\n        return $this->checksumCrc32;\n    }\n\n    public function getChecksumCrc32C(): ?string\n    {\n        $this->initialize();\n\n        return $this->checksumCrc32C;\n    }\n\n    public function getChecksumSha1(): ?string\n    {\n        $this->initialize();\n\n        return $this->checksumSha1;\n    }\n\n    public function getChecksumSha256(): ?string\n    {\n        $this->initialize();\n\n        return $this->checksumSha256;\n    }\n\n    public function getEtag(): ?string\n    {\n        $this->initialize();\n\n        return $this->etag;\n    }\n\n    public function getExpiration(): ?string\n    {\n        $this->initialize();\n\n        return $this->expiration;\n    }\n\n    /**\n     * @return RequestCharged::*|null\n     */\n    public function getRequestCharged(): ?string\n    {\n        $this->initialize();\n\n        return $this->requestCharged;\n    }\n\n    /**\n     * @return ServerSideEncryption::*|null\n     */\n    public function getServerSideEncryption(): ?string\n    {\n        $this->initialize();\n\n        return $this->serverSideEncryption;\n    }\n\n    public function getSseCustomerAlgorithm(): ?string\n    {\n        $this->initialize();\n\n        return $this->sseCustomerAlgorithm;\n    }\n\n    public function getSseCustomerKeyMd5(): ?string\n    {\n        $this->initialize();\n\n        return $this->sseCustomerKeyMd5;\n    }\n\n    public function getSseKmsEncryptionContext(): ?string\n    {\n        $this->initialize();\n\n        return $this->sseKmsEncryptionContext;\n    }\n\n    public function getSseKmsKeyId(): ?string\n    {\n        $this->initialize();\n\n        return $this->sseKmsKeyId;\n    }\n\n    public function getVersionId(): ?string\n    {\n        $this->initialize();\n\n        return $this->versionId;\n    }\n\n    protected function populateResult(Response $response): void\n    {\n        $headers = $response->getHeaders();\n\n        $this->expiration = $headers['x-amz-expiration'][0] ?? null;\n        $this->etag = $headers['etag'][0] ?? null;\n        $this->checksumCrc32 = $headers['x-amz-checksum-crc32'][0] ?? null;\n        $this->checksumCrc32C = $headers['x-amz-checksum-crc32c'][0] ?? null;\n        $this->checksumSha1 = $headers['x-amz-checksum-sha1'][0] ?? null;\n        $this->checksumSha256 = $headers['x-amz-checksum-sha256'][0] ?? null;\n        $this->serverSideEncryption = $headers['x-amz-server-side-encryption'][0] ?? null;\n        $this->versionId = $headers['x-amz-version-id'][0] ?? null;\n        $this->sseCustomerAlgorithm = $headers['x-amz-server-side-encryption-customer-algorithm'][0] ?? null;\n        $this->sseCustomerKeyMd5 = $headers['x-amz-server-side-encryption-customer-key-md5'][0] ?? null;\n        $this->sseKmsKeyId = $headers['x-amz-server-side-encryption-aws-kms-key-id'][0] ?? null;\n        $this->sseKmsEncryptionContext = $headers['x-amz-server-side-encryption-context'][0] ?? null;\n        $this->bucketKeyEnabled = isset($headers['x-amz-server-side-encryption-bucket-key-enabled'][0]) ? filter_var($headers['x-amz-server-side-encryption-bucket-key-enabled'][0], \\FILTER_VALIDATE_BOOLEAN) : null;\n        $this->requestCharged = $headers['x-amz-request-charged'][0] ?? null;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Result/UploadPartOutput.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Result;\n\nuse AsyncAws\\Core\\Response;\nuse AsyncAws\\Core\\Result;\nuse AsyncAws\\S3\\Enum\\RequestCharged;\nuse AsyncAws\\S3\\Enum\\ServerSideEncryption;\n\nclass UploadPartOutput extends Result\n{\n    /**\n     * The server-side encryption algorithm used when storing this object in Amazon S3 (for example, `AES256`, `aws:kms`).\n     */\n    private $serverSideEncryption;\n\n    /**\n     * Entity tag for the uploaded object.\n     */\n    private $etag;\n\n    /**\n     * The base64-encoded, 32-bit CRC32 checksum of the object. This will only be present if it was uploaded with the\n     * object. With multipart uploads, this may not be a checksum value of the object. For more information about how\n     * checksums are calculated with multipart uploads, see  Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums\n     */\n    private $checksumCrc32;\n\n    /**\n     * The base64-encoded, 32-bit CRC32C checksum of the object. This will only be present if it was uploaded with the\n     * object. With multipart uploads, this may not be a checksum value of the object. For more information about how\n     * checksums are calculated with multipart uploads, see  Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums\n     */\n    private $checksumCrc32C;\n\n    /**\n     * The base64-encoded, 160-bit SHA-1 digest of the object. This will only be present if it was uploaded with the object.\n     * With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are\n     * calculated with multipart uploads, see  Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums\n     */\n    private $checksumSha1;\n\n    /**\n     * The base64-encoded, 256-bit SHA-256 digest of the object. This will only be present if it was uploaded with the\n     * object. With multipart uploads, this may not be a checksum value of the object. For more information about how\n     * checksums are calculated with multipart uploads, see  Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums\n     */\n    private $checksumSha256;\n\n    /**\n     * If server-side encryption with a customer-provided encryption key was requested, the response will include this\n     * header confirming the encryption algorithm used.\n     */\n    private $sseCustomerAlgorithm;\n\n    /**\n     * If server-side encryption with a customer-provided encryption key was requested, the response will include this\n     * header to provide round-trip message integrity verification of the customer-provided encryption key.\n     */\n    private $sseCustomerKeyMd5;\n\n    /**\n     * If present, specifies the ID of the Key Management Service (KMS) symmetric encryption customer managed key was used\n     * for the object.\n     */\n    private $sseKmsKeyId;\n\n    /**\n     * Indicates whether the multipart upload uses an S3 Bucket Key for server-side encryption with Key Management Service\n     * (KMS) keys (SSE-KMS).\n     */\n    private $bucketKeyEnabled;\n\n    private $requestCharged;\n\n    public function getBucketKeyEnabled(): ?bool\n    {\n        $this->initialize();\n\n        return $this->bucketKeyEnabled;\n    }\n\n    public function getChecksumCrc32(): ?string\n    {\n        $this->initialize();\n\n        return $this->checksumCrc32;\n    }\n\n    public function getChecksumCrc32C(): ?string\n    {\n        $this->initialize();\n\n        return $this->checksumCrc32C;\n    }\n\n    public function getChecksumSha1(): ?string\n    {\n        $this->initialize();\n\n        return $this->checksumSha1;\n    }\n\n    public function getChecksumSha256(): ?string\n    {\n        $this->initialize();\n\n        return $this->checksumSha256;\n    }\n\n    public function getEtag(): ?string\n    {\n        $this->initialize();\n\n        return $this->etag;\n    }\n\n    /**\n     * @return RequestCharged::*|null\n     */\n    public function getRequestCharged(): ?string\n    {\n        $this->initialize();\n\n        return $this->requestCharged;\n    }\n\n    /**\n     * @return ServerSideEncryption::*|null\n     */\n    public function getServerSideEncryption(): ?string\n    {\n        $this->initialize();\n\n        return $this->serverSideEncryption;\n    }\n\n    public function getSseCustomerAlgorithm(): ?string\n    {\n        $this->initialize();\n\n        return $this->sseCustomerAlgorithm;\n    }\n\n    public function getSseCustomerKeyMd5(): ?string\n    {\n        $this->initialize();\n\n        return $this->sseCustomerKeyMd5;\n    }\n\n    public function getSseKmsKeyId(): ?string\n    {\n        $this->initialize();\n\n        return $this->sseKmsKeyId;\n    }\n\n    protected function populateResult(Response $response): void\n    {\n        $headers = $response->getHeaders();\n\n        $this->serverSideEncryption = $headers['x-amz-server-side-encryption'][0] ?? null;\n        $this->etag = $headers['etag'][0] ?? null;\n        $this->checksumCrc32 = $headers['x-amz-checksum-crc32'][0] ?? null;\n        $this->checksumCrc32C = $headers['x-amz-checksum-crc32c'][0] ?? null;\n        $this->checksumSha1 = $headers['x-amz-checksum-sha1'][0] ?? null;\n        $this->checksumSha256 = $headers['x-amz-checksum-sha256'][0] ?? null;\n        $this->sseCustomerAlgorithm = $headers['x-amz-server-side-encryption-customer-algorithm'][0] ?? null;\n        $this->sseCustomerKeyMd5 = $headers['x-amz-server-side-encryption-customer-key-md5'][0] ?? null;\n        $this->sseKmsKeyId = $headers['x-amz-server-side-encryption-aws-kms-key-id'][0] ?? null;\n        $this->bucketKeyEnabled = isset($headers['x-amz-server-side-encryption-bucket-key-enabled'][0]) ? filter_var($headers['x-amz-server-side-encryption-bucket-key-enabled'][0], \\FILTER_VALIDATE_BOOLEAN) : null;\n        $this->requestCharged = $headers['x-amz-request-charged'][0] ?? null;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/S3Client.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3;\n\nuse AsyncAws\\Core\\AbstractApi;\nuse AsyncAws\\Core\\AwsError\\AwsErrorFactoryInterface;\nuse AsyncAws\\Core\\AwsError\\XmlAwsErrorFactory;\nuse AsyncAws\\Core\\Configuration;\nuse AsyncAws\\Core\\RequestContext;\nuse AsyncAws\\Core\\Result;\nuse AsyncAws\\S3\\Enum\\BucketCannedACL;\nuse AsyncAws\\S3\\Enum\\ChecksumAlgorithm;\nuse AsyncAws\\S3\\Enum\\ChecksumMode;\nuse AsyncAws\\S3\\Enum\\EncodingType;\nuse AsyncAws\\S3\\Enum\\MetadataDirective;\nuse AsyncAws\\S3\\Enum\\ObjectCannedACL;\nuse AsyncAws\\S3\\Enum\\ObjectLockLegalHoldStatus;\nuse AsyncAws\\S3\\Enum\\ObjectLockMode;\nuse AsyncAws\\S3\\Enum\\ObjectOwnership;\nuse AsyncAws\\S3\\Enum\\RequestPayer;\nuse AsyncAws\\S3\\Enum\\ServerSideEncryption;\nuse AsyncAws\\S3\\Enum\\StorageClass;\nuse AsyncAws\\S3\\Enum\\TaggingDirective;\nuse AsyncAws\\S3\\Exception\\BucketAlreadyExistsException;\nuse AsyncAws\\S3\\Exception\\BucketAlreadyOwnedByYouException;\nuse AsyncAws\\S3\\Exception\\InvalidObjectStateException;\nuse AsyncAws\\S3\\Exception\\NoSuchBucketException;\nuse AsyncAws\\S3\\Exception\\NoSuchKeyException;\nuse AsyncAws\\S3\\Exception\\NoSuchUploadException;\nuse AsyncAws\\S3\\Exception\\ObjectNotInActiveTierErrorException;\nuse AsyncAws\\S3\\Input\\AbortMultipartUploadRequest;\nuse AsyncAws\\S3\\Input\\CompleteMultipartUploadRequest;\nuse AsyncAws\\S3\\Input\\CopyObjectRequest;\nuse AsyncAws\\S3\\Input\\CreateBucketRequest;\nuse AsyncAws\\S3\\Input\\CreateMultipartUploadRequest;\nuse AsyncAws\\S3\\Input\\DeleteBucketCorsRequest;\nuse AsyncAws\\S3\\Input\\DeleteBucketRequest;\nuse AsyncAws\\S3\\Input\\DeleteObjectRequest;\nuse AsyncAws\\S3\\Input\\DeleteObjectsRequest;\nuse AsyncAws\\S3\\Input\\GetBucketCorsRequest;\nuse AsyncAws\\S3\\Input\\GetBucketEncryptionRequest;\nuse AsyncAws\\S3\\Input\\GetObjectAclRequest;\nuse AsyncAws\\S3\\Input\\GetObjectRequest;\nuse AsyncAws\\S3\\Input\\HeadBucketRequest;\nuse AsyncAws\\S3\\Input\\HeadObjectRequest;\nuse AsyncAws\\S3\\Input\\ListBucketsRequest;\nuse AsyncAws\\S3\\Input\\ListMultipartUploadsRequest;\nuse AsyncAws\\S3\\Input\\ListObjectsV2Request;\nuse AsyncAws\\S3\\Input\\ListPartsRequest;\nuse AsyncAws\\S3\\Input\\PutBucketCorsRequest;\nuse AsyncAws\\S3\\Input\\PutBucketNotificationConfigurationRequest;\nuse AsyncAws\\S3\\Input\\PutObjectAclRequest;\nuse AsyncAws\\S3\\Input\\PutObjectRequest;\nuse AsyncAws\\S3\\Input\\UploadPartRequest;\nuse AsyncAws\\S3\\Result\\AbortMultipartUploadOutput;\nuse AsyncAws\\S3\\Result\\BucketExistsWaiter;\nuse AsyncAws\\S3\\Result\\BucketNotExistsWaiter;\nuse AsyncAws\\S3\\Result\\CompleteMultipartUploadOutput;\nuse AsyncAws\\S3\\Result\\CopyObjectOutput;\nuse AsyncAws\\S3\\Result\\CreateBucketOutput;\nuse AsyncAws\\S3\\Result\\CreateMultipartUploadOutput;\nuse AsyncAws\\S3\\Result\\DeleteObjectOutput;\nuse AsyncAws\\S3\\Result\\DeleteObjectsOutput;\nuse AsyncAws\\S3\\Result\\GetBucketCorsOutput;\nuse AsyncAws\\S3\\Result\\GetBucketEncryptionOutput;\nuse AsyncAws\\S3\\Result\\GetObjectAclOutput;\nuse AsyncAws\\S3\\Result\\GetObjectOutput;\nuse AsyncAws\\S3\\Result\\HeadObjectOutput;\nuse AsyncAws\\S3\\Result\\ListBucketsOutput;\nuse AsyncAws\\S3\\Result\\ListMultipartUploadsOutput;\nuse AsyncAws\\S3\\Result\\ListObjectsV2Output;\nuse AsyncAws\\S3\\Result\\ListPartsOutput;\nuse AsyncAws\\S3\\Result\\ObjectExistsWaiter;\nuse AsyncAws\\S3\\Result\\ObjectNotExistsWaiter;\nuse AsyncAws\\S3\\Result\\PutObjectAclOutput;\nuse AsyncAws\\S3\\Result\\PutObjectOutput;\nuse AsyncAws\\S3\\Result\\UploadPartOutput;\nuse AsyncAws\\S3\\Signer\\SignerV4ForS3;\nuse AsyncAws\\S3\\ValueObject\\AccessControlPolicy;\nuse AsyncAws\\S3\\ValueObject\\CompletedMultipartUpload;\nuse AsyncAws\\S3\\ValueObject\\CORSConfiguration;\nuse AsyncAws\\S3\\ValueObject\\CreateBucketConfiguration;\nuse AsyncAws\\S3\\ValueObject\\Delete;\nuse AsyncAws\\S3\\ValueObject\\MultipartUpload;\nuse AsyncAws\\S3\\ValueObject\\NotificationConfiguration;\nuse AsyncAws\\S3\\ValueObject\\Part;\n\nclass S3Client extends AbstractApi\n{\n    /**\n     * This action aborts a multipart upload. After a multipart upload is aborted, no additional parts can be uploaded using\n     * that upload ID. The storage consumed by any previously uploaded parts will be freed. However, if any part uploads are\n     * currently in progress, those part uploads might or might not succeed. As a result, it might be necessary to abort a\n     * given multipart upload multiple times in order to completely free all storage consumed by all parts.\n     *\n     * To verify that all parts have been removed, so you don't get charged for the part storage, you should call the\n     * ListParts [^1] action and ensure that the parts list is empty.\n     *\n     * For information about permissions required to use the multipart upload, see Multipart Upload and Permissions [^2].\n     *\n     * The following operations are related to `AbortMultipartUpload`:\n     *\n     * - CreateMultipartUpload [^3]\n     * - UploadPart [^4]\n     * - CompleteMultipartUpload [^5]\n     * - ListParts [^6]\n     * - ListMultipartUploads [^7]\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListParts.html\n     * [^2]: https://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html\n     * [^3]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateMultipartUpload.html\n     * [^4]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPart.html\n     * [^5]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_CompleteMultipartUpload.html\n     * [^6]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListParts.html\n     * [^7]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListMultipartUploads.html\n     *\n     * @see http://docs.amazonwebservices.com/AmazonS3/latest/API/mpUploadAbort.html\n     * @see https://docs.aws.amazon.com/AmazonS3/latest/API/API_AbortMultipartUpload.html\n     * @see https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-s3-2006-03-01.html#abortmultipartupload\n     *\n     * @param array{\n     *   Bucket: string,\n     *   Key: string,\n     *   UploadId: string,\n     *   RequestPayer?: RequestPayer::*,\n     *   ExpectedBucketOwner?: string,\n     *\n     *   @region?: string,\n     * }|AbortMultipartUploadRequest $input\n     *\n     * @throws NoSuchUploadException\n     */\n    public function abortMultipartUpload($input): AbortMultipartUploadOutput\n    {\n        $input = AbortMultipartUploadRequest::create($input);\n        $response = $this->getResponse($input->request(), new RequestContext(['operation' => 'AbortMultipartUpload', 'region' => $input->getRegion(), 'exceptionMapping' => [\n            'NoSuchUpload' => NoSuchUploadException::class,\n        ]]));\n\n        return new AbortMultipartUploadOutput($response);\n    }\n\n    /**\n     * @see headBucket\n     *\n     * @param array{\n     *   Bucket: string,\n     *   ExpectedBucketOwner?: string,\n     *\n     *   @region?: string,\n     * }|HeadBucketRequest $input\n     */\n    public function bucketExists($input): BucketExistsWaiter\n    {\n        $input = HeadBucketRequest::create($input);\n        $response = $this->getResponse($input->request(), new RequestContext(['operation' => 'HeadBucket', 'region' => $input->getRegion(), 'exceptionMapping' => [\n            'NoSuchBucket' => NoSuchBucketException::class,\n        ]]));\n\n        return new BucketExistsWaiter($response, $this, $input);\n    }\n\n    /**\n     * @see headBucket\n     *\n     * @param array{\n     *   Bucket: string,\n     *   ExpectedBucketOwner?: string,\n     *\n     *   @region?: string,\n     * }|HeadBucketRequest $input\n     */\n    public function bucketNotExists($input): BucketNotExistsWaiter\n    {\n        $input = HeadBucketRequest::create($input);\n        $response = $this->getResponse($input->request(), new RequestContext(['operation' => 'HeadBucket', 'region' => $input->getRegion(), 'exceptionMapping' => [\n            'NoSuchBucket' => NoSuchBucketException::class,\n        ]]));\n\n        return new BucketNotExistsWaiter($response, $this, $input);\n    }\n\n    /**\n     * Completes a multipart upload by assembling previously uploaded parts.\n     *\n     * You first initiate the multipart upload and then upload all parts using the UploadPart [^1] operation. After\n     * successfully uploading all relevant parts of an upload, you call this action to complete the upload. Upon receiving\n     * this request, Amazon S3 concatenates all the parts in ascending order by part number to create a new object. In the\n     * Complete Multipart Upload request, you must provide the parts list. You must ensure that the parts list is complete.\n     * This action concatenates the parts that you provide in the list. For each part in the list, you must provide the part\n     * number and the `ETag` value, returned after that part was uploaded.\n     *\n     * Processing of a Complete Multipart Upload request could take several minutes to complete. After Amazon S3 begins\n     * processing the request, it sends an HTTP response header that specifies a 200 OK response. While processing is in\n     * progress, Amazon S3 periodically sends white space characters to keep the connection from timing out. A request could\n     * fail after the initial 200 OK response has been sent. This means that a `200 OK` response can contain either a\n     * success or an error. If you call the S3 API directly, make sure to design your application to parse the contents of\n     * the response and handle it appropriately. If you use Amazon Web Services SDKs, SDKs handle this condition. The SDKs\n     * detect the embedded error and apply error handling per your configuration settings (including automatically retrying\n     * the request as appropriate). If the condition persists, the SDKs throws an exception (or, for the SDKs that don't use\n     * exceptions, they return the error).\n     *\n     * Note that if `CompleteMultipartUpload` fails, applications should be prepared to retry the failed requests. For more\n     * information, see Amazon S3 Error Best Practices [^2].\n     *\n     * ! You cannot use `Content-Type: application/x-www-form-urlencoded` with Complete Multipart Upload requests. Also, if\n     * ! you do not provide a `Content-Type` header, `CompleteMultipartUpload` returns a 200 OK response.\n     *\n     * For more information about multipart uploads, see Uploading Objects Using Multipart Upload [^3].\n     *\n     * For information about permissions required to use the multipart upload API, see Multipart Upload and Permissions\n     * [^4].\n     *\n     * `CompleteMultipartUpload` has the following special errors:\n     *\n     * - Error code: `EntityTooSmall`\n     *\n     *   - Description: Your proposed upload is smaller than the minimum allowed object size. Each part must be at least 5\n     *     MB in size, except the last part.\n     *   - 400 Bad Request\n     *\n     * - Error code: `InvalidPart`\n     *\n     *   - Description: One or more of the specified parts could not be found. The part might not have been uploaded, or the\n     *     specified entity tag might not have matched the part's entity tag.\n     *   - 400 Bad Request\n     *\n     * - Error code: `InvalidPartOrder`\n     *\n     *   - Description: The list of parts was not in ascending order. The parts list must be specified in order by part\n     *     number.\n     *   - 400 Bad Request\n     *\n     * - Error code: `NoSuchUpload`\n     *\n     *   - Description: The specified multipart upload does not exist. The upload ID might be invalid, or the multipart\n     *     upload might have been aborted or completed.\n     *   - 404 Not Found\n     *\n     *\n     * The following operations are related to `CompleteMultipartUpload`:\n     *\n     * - CreateMultipartUpload [^5]\n     * - UploadPart [^6]\n     * - AbortMultipartUpload [^7]\n     * - ListParts [^8]\n     * - ListMultipartUploads [^9]\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPart.html\n     * [^2]: https://docs.aws.amazon.com/AmazonS3/latest/dev/ErrorBestPractices.html\n     * [^3]: https://docs.aws.amazon.com/AmazonS3/latest/dev/uploadobjusingmpu.html\n     * [^4]: https://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html\n     * [^5]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateMultipartUpload.html\n     * [^6]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPart.html\n     * [^7]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_AbortMultipartUpload.html\n     * [^8]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListParts.html\n     * [^9]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListMultipartUploads.html\n     *\n     * @see http://docs.amazonwebservices.com/AmazonS3/latest/API/mpUploadComplete.html\n     * @see https://docs.aws.amazon.com/AmazonS3/latest/API/API_CompleteMultipartUpload.html\n     * @see https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-s3-2006-03-01.html#completemultipartupload\n     *\n     * @param array{\n     *   Bucket: string,\n     *   Key: string,\n     *   MultipartUpload?: CompletedMultipartUpload|array,\n     *   UploadId: string,\n     *   ChecksumCRC32?: string,\n     *   ChecksumCRC32C?: string,\n     *   ChecksumSHA1?: string,\n     *   ChecksumSHA256?: string,\n     *   RequestPayer?: RequestPayer::*,\n     *   ExpectedBucketOwner?: string,\n     *   SSECustomerAlgorithm?: string,\n     *   SSECustomerKey?: string,\n     *   SSECustomerKeyMD5?: string,\n     *\n     *   @region?: string,\n     * }|CompleteMultipartUploadRequest $input\n     */\n    public function completeMultipartUpload($input): CompleteMultipartUploadOutput\n    {\n        $input = CompleteMultipartUploadRequest::create($input);\n        $response = $this->getResponse($input->request(), new RequestContext(['operation' => 'CompleteMultipartUpload', 'region' => $input->getRegion()]));\n\n        return new CompleteMultipartUploadOutput($response);\n    }\n\n    /**\n     * Creates a copy of an object that is already stored in Amazon S3.\n     *\n     * > You can store individual objects of up to 5 TB in Amazon S3. You create a copy of your object up to 5 GB in size in\n     * > a single atomic action using this API. However, to copy an object greater than 5 GB, you must use the multipart\n     * > upload Upload Part - Copy (UploadPartCopy) API. For more information, see Copy Object Using the REST Multipart\n     * > Upload API [^1].\n     *\n     * All copy requests must be authenticated. Additionally, you must have *read* access to the source object and *write*\n     * access to the destination bucket. For more information, see REST Authentication [^2]. Both the Region that you want\n     * to copy the object from and the Region that you want to copy the object to must be enabled for your account.\n     *\n     * A copy request might return an error when Amazon S3 receives the copy request or while Amazon S3 is copying the\n     * files. If the error occurs before the copy action starts, you receive a standard Amazon S3 error. If the error occurs\n     * during the copy operation, the error response is embedded in the `200 OK` response. This means that a `200 OK`\n     * response can contain either a success or an error. If you call the S3 API directly, make sure to design your\n     * application to parse the contents of the response and handle it appropriately. If you use Amazon Web Services SDKs,\n     * SDKs handle this condition. The SDKs detect the embedded error and apply error handling per your configuration\n     * settings (including automatically retrying the request as appropriate). If the condition persists, the SDKs throws an\n     * exception (or, for the SDKs that don't use exceptions, they return the error).\n     *\n     * If the copy is successful, you receive a response with information about the copied object.\n     *\n     * > If the request is an HTTP 1.1 request, the response is chunk encoded. If it were not, it would not contain the\n     * > content-length, and you would need to read the entire body.\n     *\n     * The copy request charge is based on the storage class and Region that you specify for the destination object. For\n     * pricing information, see Amazon S3 pricing [^3].\n     *\n     * ! Amazon S3 transfer acceleration does not support cross-Region copies. If you request a cross-Region copy using a\n     * ! transfer acceleration endpoint, you get a 400 `Bad Request` error. For more information, see Transfer Acceleration\n     * ! [^4].\n     *\n     * - `Metadata`:\n     *\n     *   When copying an object, you can preserve all metadata (the default) or specify new metadata. However, the access\n     *   control list (ACL) is not preserved and is set to private for the user making the request. To override the default\n     *   ACL setting, specify a new ACL when generating a copy request. For more information, see Using ACLs [^5].\n     *\n     *   To specify whether you want the object metadata copied from the source object or replaced with metadata provided in\n     *   the request, you can optionally add the `x-amz-metadata-directive` header. When you grant permissions, you can use\n     *   the `s3:x-amz-metadata-directive` condition key to enforce certain metadata behavior when objects are uploaded. For\n     *   more information, see Specifying Conditions in a Policy [^6] in the *Amazon S3 User Guide*. For a complete list of\n     *   Amazon S3-specific condition keys, see Actions, Resources, and Condition Keys for Amazon S3 [^7].\n     *\n     *   > `x-amz-website-redirect-location` is unique to each object and must be specified in the request headers to copy\n     *   > the value.\n     *\n     * - `x-amz-copy-source-if Headers`:\n     *\n     *   To only copy an object under certain conditions, such as whether the `Etag` matches or whether the object was\n     *   modified before or after a specified date, use the following request parameters:\n     *\n     *   - `x-amz-copy-source-if-match`\n     *   - `x-amz-copy-source-if-none-match`\n     *   - `x-amz-copy-source-if-unmodified-since`\n     *   - `x-amz-copy-source-if-modified-since`\n     *\n     *   If both the `x-amz-copy-source-if-match` and `x-amz-copy-source-if-unmodified-since` headers are present in the\n     *   request and evaluate as follows, Amazon S3 returns `200 OK` and copies the data:\n     *\n     *   - `x-amz-copy-source-if-match` condition evaluates to true\n     *   - `x-amz-copy-source-if-unmodified-since` condition evaluates to false\n     *\n     *   If both the `x-amz-copy-source-if-none-match` and `x-amz-copy-source-if-modified-since` headers are present in the\n     *   request and evaluate as follows, Amazon S3 returns the `412 Precondition Failed` response code:\n     *\n     *   - `x-amz-copy-source-if-none-match` condition evaluates to false\n     *   - `x-amz-copy-source-if-modified-since` condition evaluates to true\n     *\n     *   > All headers with the `x-amz-` prefix, including `x-amz-copy-source`, must be signed.\n     *\n     * - `Server-side encryption`:\n     *\n     *   Amazon S3 automatically encrypts all new objects that are copied to an S3 bucket. When copying an object, if you\n     *   don't specify encryption information in your copy request, the encryption setting of the target object is set to\n     *   the default encryption configuration of the destination bucket. By default, all buckets have a base level of\n     *   encryption configuration that uses server-side encryption with Amazon S3 managed keys (SSE-S3). If the destination\n     *   bucket has a default encryption configuration that uses server-side encryption with Key Management Service (KMS)\n     *   keys (SSE-KMS), dual-layer server-side encryption with Amazon Web Services KMS keys (DSSE-KMS), or server-side\n     *   encryption with customer-provided encryption keys (SSE-C), Amazon S3 uses the corresponding KMS key, or a\n     *   customer-provided key to encrypt the target object copy.\n     *\n     *   When you perform a `CopyObject` operation, if you want to use a different type of encryption setting for the target\n     *   object, you can use other appropriate encryption-related headers to encrypt the target object with a KMS key, an\n     *   Amazon S3 managed key, or a customer-provided key. With server-side encryption, Amazon S3 encrypts your data as it\n     *   writes your data to disks in its data centers and decrypts the data when you access it. If the encryption setting\n     *   in your request is different from the default encryption configuration of the destination bucket, the encryption\n     *   setting in your request takes precedence. If the source object for the copy is stored in Amazon S3 using SSE-C, you\n     *   must provide the necessary encryption information in your request so that Amazon S3 can decrypt the object for\n     *   copying. For more information about server-side encryption, see Using Server-Side Encryption [^8].\n     *\n     *   If a target object uses SSE-KMS, you can enable an S3 Bucket Key for the object. For more information, see Amazon\n     *   S3 Bucket Keys [^9] in the *Amazon S3 User Guide*.\n     * - `Access Control List (ACL)-Specific Request Headers`:\n     *\n     *   When copying an object, you can optionally use headers to grant ACL-based permissions. By default, all objects are\n     *   private. Only the owner has full access control. When adding a new object, you can grant permissions to individual\n     *   Amazon Web Services accounts or to predefined groups that are defined by Amazon S3. These permissions are then\n     *   added to the ACL on the object. For more information, see Access Control List (ACL) Overview [^10] and Managing\n     *   ACLs Using the REST API [^11].\n     *\n     *   If the bucket that you're copying objects to uses the bucket owner enforced setting for S3 Object Ownership, ACLs\n     *   are disabled and no longer affect permissions. Buckets that use this setting only accept `PUT` requests that don't\n     *   specify an ACL or `PUT` requests that specify bucket owner full control ACLs, such as the\n     *   `bucket-owner-full-control` canned ACL or an equivalent form of this ACL expressed in the XML format.\n     *\n     *   For more information, see  Controlling ownership of objects and disabling ACLs [^12] in the *Amazon S3 User Guide*.\n     *\n     *   > If your bucket uses the bucket owner enforced setting for Object Ownership, all objects written to the bucket by\n     *   > any account will be owned by the bucket owner.\n     *\n     * - `Checksums`:\n     *\n     *   When copying an object, if it has a checksum, that checksum will be copied to the new object by default. When you\n     *   copy the object over, you can optionally specify a different checksum algorithm to use with the\n     *   `x-amz-checksum-algorithm` header.\n     * - `Storage Class Options`:\n     *\n     *   You can use the `CopyObject` action to change the storage class of an object that is already stored in Amazon S3 by\n     *   using the `StorageClass` parameter. For more information, see Storage Classes [^13] in the *Amazon S3 User Guide*.\n     *\n     *   If the source object's storage class is GLACIER, you must restore a copy of this object before you can use it as a\n     *   source object for the copy operation. For more information, see RestoreObject [^14]. For more information, see\n     *   Copying Objects [^15].\n     * - `Versioning`:\n     *\n     *   By default, `x-amz-copy-source` header identifies the current version of an object to copy. If the current version\n     *   is a delete marker, Amazon S3 behaves as if the object was deleted. To copy a different version, use the\n     *   `versionId` subresource.\n     *\n     *   If you enable versioning on the target bucket, Amazon S3 generates a unique version ID for the object being copied.\n     *   This version ID is different from the version ID of the source object. Amazon S3 returns the version ID of the\n     *   copied object in the `x-amz-version-id` response header in the response.\n     *\n     *   If you do not enable versioning or suspend it on the target bucket, the version ID that Amazon S3 generates is\n     *   always null.\n     *\n     * The following operations are related to `CopyObject`:\n     *\n     * - PutObject [^16]\n     * - GetObject [^17]\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/dev/CopyingObjctsUsingRESTMPUapi.html\n     * [^2]: https://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html\n     * [^3]: http://aws.amazon.com/s3/pricing/\n     * [^4]: https://docs.aws.amazon.com/AmazonS3/latest/dev/transfer-acceleration.html\n     * [^5]: https://docs.aws.amazon.com/AmazonS3/latest/dev/S3_ACLs_UsingACLs.html\n     * [^6]: https://docs.aws.amazon.com/AmazonS3/latest/dev/amazon-s3-policy-keys.html\n     * [^7]: https://docs.aws.amazon.com/AmazonS3/latest/dev/list_amazons3.html\n     * [^8]: https://docs.aws.amazon.com/AmazonS3/latest/dev/serv-side-encryption.html\n     * [^9]: https://docs.aws.amazon.com/AmazonS3/latest/dev/bucket-key.html\n     * [^10]: https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html\n     * [^11]: https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-using-rest-api.html\n     * [^12]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/about-object-ownership.html\n     * [^13]: https://docs.aws.amazon.com/AmazonS3/latest/dev/storage-class-intro.html\n     * [^14]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_RestoreObject.html\n     * [^15]: https://docs.aws.amazon.com/AmazonS3/latest/dev/CopyingObjectsExamples.html\n     * [^16]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html\n     * [^17]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html\n     *\n     * @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTObjectCOPY.html\n     * @see https://docs.aws.amazon.com/AmazonS3/latest/API/API_CopyObject.html\n     * @see https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-s3-2006-03-01.html#copyobject\n     *\n     * @param array{\n     *   ACL?: ObjectCannedACL::*,\n     *   Bucket: string,\n     *   CacheControl?: string,\n     *   ChecksumAlgorithm?: ChecksumAlgorithm::*,\n     *   ContentDisposition?: string,\n     *   ContentEncoding?: string,\n     *   ContentLanguage?: string,\n     *   ContentType?: string,\n     *   CopySource: string,\n     *   CopySourceIfMatch?: string,\n     *   CopySourceIfModifiedSince?: \\DateTimeImmutable|string,\n     *   CopySourceIfNoneMatch?: string,\n     *   CopySourceIfUnmodifiedSince?: \\DateTimeImmutable|string,\n     *   Expires?: \\DateTimeImmutable|string,\n     *   GrantFullControl?: string,\n     *   GrantRead?: string,\n     *   GrantReadACP?: string,\n     *   GrantWriteACP?: string,\n     *   Key: string,\n     *   Metadata?: array<string, string>,\n     *   MetadataDirective?: MetadataDirective::*,\n     *   TaggingDirective?: TaggingDirective::*,\n     *   ServerSideEncryption?: ServerSideEncryption::*,\n     *   StorageClass?: StorageClass::*,\n     *   WebsiteRedirectLocation?: string,\n     *   SSECustomerAlgorithm?: string,\n     *   SSECustomerKey?: string,\n     *   SSECustomerKeyMD5?: string,\n     *   SSEKMSKeyId?: string,\n     *   SSEKMSEncryptionContext?: string,\n     *   BucketKeyEnabled?: bool,\n     *   CopySourceSSECustomerAlgorithm?: string,\n     *   CopySourceSSECustomerKey?: string,\n     *   CopySourceSSECustomerKeyMD5?: string,\n     *   RequestPayer?: RequestPayer::*,\n     *   Tagging?: string,\n     *   ObjectLockMode?: ObjectLockMode::*,\n     *   ObjectLockRetainUntilDate?: \\DateTimeImmutable|string,\n     *   ObjectLockLegalHoldStatus?: ObjectLockLegalHoldStatus::*,\n     *   ExpectedBucketOwner?: string,\n     *   ExpectedSourceBucketOwner?: string,\n     *\n     *   @region?: string,\n     * }|CopyObjectRequest $input\n     *\n     * @throws ObjectNotInActiveTierErrorException\n     */\n    public function copyObject($input): CopyObjectOutput\n    {\n        $input = CopyObjectRequest::create($input);\n        $response = $this->getResponse($input->request(), new RequestContext(['operation' => 'CopyObject', 'region' => $input->getRegion(), 'exceptionMapping' => [\n            'ObjectNotInActiveTierError' => ObjectNotInActiveTierErrorException::class,\n        ]]));\n\n        return new CopyObjectOutput($response);\n    }\n\n    /**\n     * Creates a new S3 bucket. To create a bucket, you must register with Amazon S3 and have a valid Amazon Web Services\n     * Access Key ID to authenticate requests. Anonymous requests are never allowed to create buckets. By creating the\n     * bucket, you become the bucket owner.\n     *\n     * Not every string is an acceptable bucket name. For information about bucket naming restrictions, see Bucket naming\n     * rules [^1].\n     *\n     * If you want to create an Amazon S3 on Outposts bucket, see Create Bucket [^2].\n     *\n     * By default, the bucket is created in the US East (N. Virginia) Region. You can optionally specify a Region in the\n     * request body. You might choose a Region to optimize latency, minimize costs, or address regulatory requirements. For\n     * example, if you reside in Europe, you will probably find it advantageous to create buckets in the Europe (Ireland)\n     * Region. For more information, see Accessing a bucket [^3].\n     *\n     * > If you send your create bucket request to the `s3.amazonaws.com` endpoint, the request goes to the `us-east-1`\n     * > Region. Accordingly, the signature calculations in Signature Version 4 must use `us-east-1` as the Region, even if\n     * > the location constraint in the request specifies another Region where the bucket is to be created. If you create a\n     * > bucket in a Region other than US East (N. Virginia), your application must be able to handle 307 redirect. For more\n     * > information, see Virtual hosting of buckets [^4].\n     *\n     * - `Permissions`:\n     *\n     *   In addition to `s3:CreateBucket`, the following permissions are required when your `CreateBucket` request includes\n     *   specific headers:\n     *\n     *   - **Access control lists (ACLs)** - If your `CreateBucket` request specifies access control list (ACL) permissions\n     *     and the ACL is public-read, public-read-write, authenticated-read, or if you specify access permissions\n     *     explicitly through any other ACL, both `s3:CreateBucket` and `s3:PutBucketAcl` permissions are needed. If the ACL\n     *     for the `CreateBucket` request is private or if the request doesn't specify any ACLs, only `s3:CreateBucket`\n     *     permission is needed.\n     *   - **Object Lock** - If `ObjectLockEnabledForBucket` is set to true in your `CreateBucket` request,\n     *     `s3:PutBucketObjectLockConfiguration` and `s3:PutBucketVersioning` permissions are required.\n     *   - **S3 Object Ownership** - If your `CreateBucket` request includes the `x-amz-object-ownership` header, then the\n     *     `s3:PutBucketOwnershipControls` permission is required. By default, `ObjectOwnership` is set to\n     *     `BucketOWnerEnforced` and ACLs are disabled. We recommend keeping ACLs disabled, except in uncommon use cases\n     *     where you must control access for each object individually. If you want to change the `ObjectOwnership` setting,\n     *     you can use the `x-amz-object-ownership` header in your `CreateBucket` request to set the `ObjectOwnership`\n     *     setting of your choice. For more information about S3 Object Ownership, see Controlling object ownership  [^5] in\n     *     the *Amazon S3 User Guide*.\n     *   - **S3 Block Public Access** - If your specific use case requires granting public access to your S3 resources, you\n     *     can disable Block Public Access. You can create a new bucket with Block Public Access enabled, then separately\n     *     call the `DeletePublicAccessBlock` [^6] API. To use this operation, you must have the\n     *     `s3:PutBucketPublicAccessBlock` permission. By default, all Block Public Access settings are enabled for new\n     *     buckets. To avoid inadvertent exposure of your resources, we recommend keeping the S3 Block Public Access\n     *     settings enabled. For more information about S3 Block Public Access, see Blocking public access to your Amazon S3\n     *     storage  [^7] in the *Amazon S3 User Guide*.\n     *\n     *\n     * ! If your `CreateBucket` request sets `BucketOwnerEnforced` for Amazon S3 Object Ownership and specifies a bucket ACL\n     * ! that provides access to an external Amazon Web Services account, your request fails with a `400` error and returns\n     * ! the `InvalidBucketAcLWithObjectOwnership` error code. For more information, see Setting Object Ownership on an\n     * ! existing bucket  [^8] in the *Amazon S3 User Guide*.\n     *\n     * The following operations are related to `CreateBucket`:\n     *\n     * - PutObject [^9]\n     * - DeleteBucket [^10]\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucketnamingrules.html\n     * [^2]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_control_CreateBucket.html\n     * [^3]: https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingBucket.html#access-bucket-intro\n     * [^4]: https://docs.aws.amazon.com/AmazonS3/latest/dev/VirtualHosting.html\n     * [^5]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/about-object-ownership.html\n     * [^6]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeletePublicAccessBlock.html\n     * [^7]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/about-object-ownership.html\n     * [^8]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-ownership-existing-bucket.html\n     * [^9]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html\n     * [^10]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucket.html\n     *\n     * @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketPUT.html\n     * @see https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateBucket.html\n     * @see https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-s3-2006-03-01.html#createbucket\n     *\n     * @param array{\n     *   ACL?: BucketCannedACL::*,\n     *   Bucket: string,\n     *   CreateBucketConfiguration?: CreateBucketConfiguration|array,\n     *   GrantFullControl?: string,\n     *   GrantRead?: string,\n     *   GrantReadACP?: string,\n     *   GrantWrite?: string,\n     *   GrantWriteACP?: string,\n     *   ObjectLockEnabledForBucket?: bool,\n     *   ObjectOwnership?: ObjectOwnership::*,\n     *\n     *   @region?: string,\n     * }|CreateBucketRequest $input\n     *\n     * @throws BucketAlreadyExistsException\n     * @throws BucketAlreadyOwnedByYouException\n     */\n    public function createBucket($input): CreateBucketOutput\n    {\n        $input = CreateBucketRequest::create($input);\n        $response = $this->getResponse($input->request(), new RequestContext(['operation' => 'CreateBucket', 'region' => $input->getRegion(), 'exceptionMapping' => [\n            'BucketAlreadyExists' => BucketAlreadyExistsException::class,\n            'BucketAlreadyOwnedByYou' => BucketAlreadyOwnedByYouException::class,\n        ]]));\n\n        return new CreateBucketOutput($response);\n    }\n\n    /**\n     * This action initiates a multipart upload and returns an upload ID. This upload ID is used to associate all of the\n     * parts in the specific multipart upload. You specify this upload ID in each of your subsequent upload part requests\n     * (see UploadPart [^1]). You also include this upload ID in the final request to either complete or abort the multipart\n     * upload request.\n     *\n     * For more information about multipart uploads, see Multipart Upload Overview [^2].\n     *\n     * If you have configured a lifecycle rule to abort incomplete multipart uploads, the upload must complete within the\n     * number of days specified in the bucket lifecycle configuration. Otherwise, the incomplete multipart upload becomes\n     * eligible for an abort action and Amazon S3 aborts the multipart upload. For more information, see Aborting Incomplete\n     * Multipart Uploads Using a Bucket Lifecycle Configuration [^3].\n     *\n     * For information about the permissions required to use the multipart upload API, see Multipart Upload and Permissions\n     * [^4].\n     *\n     * For request signing, multipart upload is just a series of regular requests. You initiate a multipart upload, send one\n     * or more requests to upload parts, and then complete the multipart upload process. You sign each request individually.\n     * There is nothing special about signing multipart upload requests. For more information about signing, see\n     * Authenticating Requests (Amazon Web Services Signature Version 4) [^5].\n     *\n     * > After you initiate a multipart upload and upload one or more parts, to stop being charged for storing the uploaded\n     * > parts, you must either complete or abort the multipart upload. Amazon S3 frees up the space used to store the parts\n     * > and stop charging you for storing them only after you either complete or abort a multipart upload.\n     *\n     * Server-side encryption is for data encryption at rest. Amazon S3 encrypts your data as it writes it to disks in its\n     * data centers and decrypts it when you access it. Amazon S3 automatically encrypts all new objects that are uploaded\n     * to an S3 bucket. When doing a multipart upload, if you don't specify encryption information in your request, the\n     * encryption setting of the uploaded parts is set to the default encryption configuration of the destination bucket. By\n     * default, all buckets have a base level of encryption configuration that uses server-side encryption with Amazon S3\n     * managed keys (SSE-S3). If the destination bucket has a default encryption configuration that uses server-side\n     * encryption with an Key Management Service (KMS) key (SSE-KMS), or a customer-provided encryption key (SSE-C), Amazon\n     * S3 uses the corresponding KMS key, or a customer-provided key to encrypt the uploaded parts. When you perform a\n     * CreateMultipartUpload operation, if you want to use a different type of encryption setting for the uploaded parts,\n     * you can request that Amazon S3 encrypts the object with a KMS key, an Amazon S3 managed key, or a customer-provided\n     * key. If the encryption setting in your request is different from the default encryption configuration of the\n     * destination bucket, the encryption setting in your request takes precedence. If you choose to provide your own\n     * encryption key, the request headers you provide in UploadPart [^6] and UploadPartCopy [^7] requests must match the\n     * headers you used in the request to initiate the upload by using `CreateMultipartUpload`. You can request that Amazon\n     * S3 save the uploaded parts encrypted with server-side encryption with an Amazon S3 managed key (SSE-S3), an Key\n     * Management Service (KMS) key (SSE-KMS), or a customer-provided encryption key (SSE-C).\n     *\n     * To perform a multipart upload with encryption by using an Amazon Web Services KMS key, the requester must have\n     * permission to the `kms:Decrypt` and `kms:GenerateDataKey*` actions on the key. These permissions are required because\n     * Amazon S3 must decrypt and read data from the encrypted file parts before it completes the multipart upload. For more\n     * information, see Multipart upload API and permissions [^8] and Protecting data using server-side encryption with\n     * Amazon Web Services KMS [^9] in the *Amazon S3 User Guide*.\n     *\n     * If your Identity and Access Management (IAM) user or role is in the same Amazon Web Services account as the KMS key,\n     * then you must have these permissions on the key policy. If your IAM user or role belongs to a different account than\n     * the key, then you must have the permissions on both the key policy and your IAM user or role.\n     *\n     * For more information, see Protecting Data Using Server-Side Encryption [^10].\n     *\n     * - `Access Permissions`:\n     *\n     *   When copying an object, you can optionally specify the accounts or groups that should be granted specific\n     *   permissions on the new object. There are two ways to grant the permissions using the request headers:\n     *\n     *   - Specify a canned ACL with the `x-amz-acl` request header. For more information, see Canned ACL [^11].\n     *   - Specify access permissions explicitly with the `x-amz-grant-read`, `x-amz-grant-read-acp`,\n     *     `x-amz-grant-write-acp`, and `x-amz-grant-full-control` headers. These parameters map to the set of permissions\n     *     that Amazon S3 supports in an ACL. For more information, see Access Control List (ACL) Overview [^12].\n     *\n     *   You can use either a canned ACL or specify access permissions explicitly. You cannot do both.\n     * - `Server-Side- Encryption-Specific Request Headers`:\n     *\n     *   Amazon S3 encrypts data by using server-side encryption with an Amazon S3 managed key (SSE-S3) by default.\n     *   Server-side encryption is for data encryption at rest. Amazon S3 encrypts your data as it writes it to disks in its\n     *   data centers and decrypts it when you access it. You can request that Amazon S3 encrypts data at rest by using\n     *   server-side encryption with other key options. The option you use depends on whether you want to use KMS keys\n     *   (SSE-KMS) or provide your own encryption keys (SSE-C).\n     *\n     *   - Use KMS keys (SSE-KMS) that include the Amazon Web Services managed key (`aws/s3`) and KMS customer managed keys\n     *     stored in Key Management Service (KMS) – If you want Amazon Web Services to manage the keys used to encrypt\n     *     data, specify the following headers in the request.\n     *\n     *     - `x-amz-server-side-encryption`\n     *     - `x-amz-server-side-encryption-aws-kms-key-id`\n     *     - `x-amz-server-side-encryption-context`\n     *\n     *     > If you specify `x-amz-server-side-encryption:aws:kms`, but don't provide\n     *     > `x-amz-server-side-encryption-aws-kms-key-id`, Amazon S3 uses the Amazon Web Services managed key (`aws/s3`\n     *     > key) in KMS to protect the data.\n     *\n     *     ! All `GET` and `PUT` requests for an object protected by KMS fail if you don't make them by using Secure Sockets\n     *     ! Layer (SSL), Transport Layer Security (TLS), or Signature Version 4.\n     *\n     *     For more information about server-side encryption with KMS keys (SSE-KMS), see Protecting Data Using Server-Side\n     *     Encryption with KMS keys [^13].\n     *   - Use customer-provided encryption keys (SSE-C) – If you want to manage your own encryption keys, provide all the\n     *     following headers in the request.\n     *\n     *     - `x-amz-server-side-encryption-customer-algorithm`\n     *     - `x-amz-server-side-encryption-customer-key`\n     *     - `x-amz-server-side-encryption-customer-key-MD5`\n     *\n     *     For more information about server-side encryption with customer-provided encryption keys (SSE-C), see  Protecting\n     *     data using server-side encryption with customer-provided encryption keys (SSE-C) [^14].\n     *\n     * - `Access-Control-List (ACL)-Specific Request Headers`:\n     *\n     *   You also can use the following access control–related headers with this operation. By default, all objects are\n     *   private. Only the owner has full access control. When adding a new object, you can grant permissions to individual\n     *   Amazon Web Services accounts or to predefined groups defined by Amazon S3. These permissions are then added to the\n     *   access control list (ACL) on the object. For more information, see Using ACLs [^15]. With this operation, you can\n     *   grant access permissions using one of the following two methods:\n     *\n     *   - Specify a canned ACL (`x-amz-acl`) — Amazon S3 supports a set of predefined ACLs, known as *canned ACLs*. Each\n     *     canned ACL has a predefined set of grantees and permissions. For more information, see Canned ACL [^16].\n     *   - Specify access permissions explicitly — To explicitly grant access permissions to specific Amazon Web Services\n     *     accounts or groups, use the following headers. Each header maps to specific permissions that Amazon S3 supports\n     *     in an ACL. For more information, see Access Control List (ACL) Overview [^17]. In the header, you specify a list\n     *     of grantees who get the specific permission. To grant permissions explicitly, use:\n     *\n     *     - `x-amz-grant-read`\n     *     - `x-amz-grant-write`\n     *     - `x-amz-grant-read-acp`\n     *     - `x-amz-grant-write-acp`\n     *     - `x-amz-grant-full-control`\n     *\n     *     You specify each grantee as a type=value pair, where the type is one of the following:\n     *\n     *     - `id` – if the value specified is the canonical user ID of an Amazon Web Services account\n     *     - `uri` – if you are granting permissions to a predefined group\n     *     - `emailAddress` – if the value specified is the email address of an Amazon Web Services account\n     *\n     *       > Using email addresses to specify a grantee is only supported in the following Amazon Web Services Regions:\n     *       >\n     *       > - US East (N. Virginia)\n     *       > - US West (N. California)\n     *       > - US West (Oregon)\n     *       > - Asia Pacific (Singapore)\n     *       > - Asia Pacific (Sydney)\n     *       > - Asia Pacific (Tokyo)\n     *       > - Europe (Ireland)\n     *       > - South America (São Paulo)\n     *       >\n     *       > For a list of all the Amazon S3 supported Regions and endpoints, see Regions and Endpoints [^18] in the\n     *       > Amazon Web Services General Reference.\n     *\n     *\n     *     For example, the following `x-amz-grant-read` header grants the Amazon Web Services accounts identified by\n     *     account IDs permissions to read object data and its metadata:\n     *\n     *     `x-amz-grant-read: id=\"11112222333\", id=\"444455556666\" `\n     *\n     *\n     * The following operations are related to `CreateMultipartUpload`:\n     *\n     * - UploadPart [^19]\n     * - CompleteMultipartUpload [^20]\n     * - AbortMultipartUpload [^21]\n     * - ListParts [^22]\n     * - ListMultipartUploads [^23]\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPart.html\n     * [^2]: https://docs.aws.amazon.com/AmazonS3/latest/dev/mpuoverview.html\n     * [^3]: https://docs.aws.amazon.com/AmazonS3/latest/dev/mpuoverview.html#mpu-abort-incomplete-mpu-lifecycle-config\n     * [^4]: https://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html\n     * [^5]: https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html\n     * [^6]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPart.html\n     * [^7]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPartCopy.html\n     * [^8]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/mpuoverview.html#mpuAndPermissions\n     * [^9]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingKMSEncryption.html\n     * [^10]: https://docs.aws.amazon.com/AmazonS3/latest/dev/serv-side-encryption.html\n     * [^11]: https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#CannedACL\n     * [^12]: https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html\n     * [^13]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingKMSEncryption.html\n     * [^14]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/ServerSideEncryptionCustomerKeys.html\n     * [^15]: https://docs.aws.amazon.com/AmazonS3/latest/dev/S3_ACLs_UsingACLs.html\n     * [^16]: https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#CannedACL\n     * [^17]: https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html\n     * [^18]: https://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region\n     * [^19]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPart.html\n     * [^20]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_CompleteMultipartUpload.html\n     * [^21]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_AbortMultipartUpload.html\n     * [^22]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListParts.html\n     * [^23]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListMultipartUploads.html\n     *\n     * @see http://docs.amazonwebservices.com/AmazonS3/latest/API/mpUploadInitiate.html\n     * @see https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateMultipartUpload.html\n     * @see https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-s3-2006-03-01.html#createmultipartupload\n     *\n     * @param array{\n     *   ACL?: ObjectCannedACL::*,\n     *   Bucket: string,\n     *   CacheControl?: string,\n     *   ContentDisposition?: string,\n     *   ContentEncoding?: string,\n     *   ContentLanguage?: string,\n     *   ContentType?: string,\n     *   Expires?: \\DateTimeImmutable|string,\n     *   GrantFullControl?: string,\n     *   GrantRead?: string,\n     *   GrantReadACP?: string,\n     *   GrantWriteACP?: string,\n     *   Key: string,\n     *   Metadata?: array<string, string>,\n     *   ServerSideEncryption?: ServerSideEncryption::*,\n     *   StorageClass?: StorageClass::*,\n     *   WebsiteRedirectLocation?: string,\n     *   SSECustomerAlgorithm?: string,\n     *   SSECustomerKey?: string,\n     *   SSECustomerKeyMD5?: string,\n     *   SSEKMSKeyId?: string,\n     *   SSEKMSEncryptionContext?: string,\n     *   BucketKeyEnabled?: bool,\n     *   RequestPayer?: RequestPayer::*,\n     *   Tagging?: string,\n     *   ObjectLockMode?: ObjectLockMode::*,\n     *   ObjectLockRetainUntilDate?: \\DateTimeImmutable|string,\n     *   ObjectLockLegalHoldStatus?: ObjectLockLegalHoldStatus::*,\n     *   ExpectedBucketOwner?: string,\n     *   ChecksumAlgorithm?: ChecksumAlgorithm::*,\n     *\n     *   @region?: string,\n     * }|CreateMultipartUploadRequest $input\n     */\n    public function createMultipartUpload($input): CreateMultipartUploadOutput\n    {\n        $input = CreateMultipartUploadRequest::create($input);\n        $response = $this->getResponse($input->request(), new RequestContext(['operation' => 'CreateMultipartUpload', 'region' => $input->getRegion()]));\n\n        return new CreateMultipartUploadOutput($response);\n    }\n\n    /**\n     * Deletes the S3 bucket. All objects (including all object versions and delete markers) in the bucket must be deleted\n     * before the bucket itself can be deleted.\n     *\n     * The following operations are related to `DeleteBucket`:\n     *\n     * - CreateBucket [^1]\n     * - DeleteObject [^2]\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateBucket.html\n     * [^2]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObject.html\n     *\n     * @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketDELETE.html\n     * @see https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucket.html\n     * @see https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-s3-2006-03-01.html#deletebucket\n     *\n     * @param array{\n     *   Bucket: string,\n     *   ExpectedBucketOwner?: string,\n     *\n     *   @region?: string,\n     * }|DeleteBucketRequest $input\n     */\n    public function deleteBucket($input): Result\n    {\n        $input = DeleteBucketRequest::create($input);\n        $response = $this->getResponse($input->request(), new RequestContext(['operation' => 'DeleteBucket', 'region' => $input->getRegion()]));\n\n        return new Result($response);\n    }\n\n    /**\n     * Deletes the `cors` configuration information set for the bucket.\n     *\n     * To use this operation, you must have permission to perform the `s3:PutBucketCORS` action. The bucket owner has this\n     * permission by default and can grant this permission to others.\n     *\n     * For information about `cors`, see Enabling Cross-Origin Resource Sharing [^1] in the *Amazon S3 User Guide*.\n     *\n     * **Related Resources**\n     *\n     * - PutBucketCors [^2]\n     * - RESTOPTIONSobject [^3]\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/dev/cors.html\n     * [^2]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketCors.html\n     * [^3]: https://docs.aws.amazon.com/AmazonS3/latest/API/RESTOPTIONSobject.html\n     *\n     * @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketDELETEcors.html\n     * @see https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketCors.html\n     * @see https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-s3-2006-03-01.html#deletebucketcors\n     *\n     * @param array{\n     *   Bucket: string,\n     *   ExpectedBucketOwner?: string,\n     *\n     *   @region?: string,\n     * }|DeleteBucketCorsRequest $input\n     */\n    public function deleteBucketCors($input): Result\n    {\n        $input = DeleteBucketCorsRequest::create($input);\n        $response = $this->getResponse($input->request(), new RequestContext(['operation' => 'DeleteBucketCors', 'region' => $input->getRegion()]));\n\n        return new Result($response);\n    }\n\n    /**\n     * Removes the null version (if there is one) of an object and inserts a delete marker, which becomes the latest version\n     * of the object. If there isn't a null version, Amazon S3 does not remove any objects but will still respond that the\n     * command was successful.\n     *\n     * To remove a specific version, you must use the version Id subresource. Using this subresource permanently deletes the\n     * version. If the object deleted is a delete marker, Amazon S3 sets the response header, `x-amz-delete-marker`, to\n     * true.\n     *\n     * If the object you want to delete is in a bucket where the bucket versioning configuration is MFA Delete enabled, you\n     * must include the `x-amz-mfa` request header in the DELETE `versionId` request. Requests that include `x-amz-mfa` must\n     * use HTTPS.\n     *\n     * For more information about MFA Delete, see Using MFA Delete [^1]. To see sample requests that use versioning, see\n     * Sample Request [^2].\n     *\n     * You can delete objects by explicitly calling DELETE Object or configure its lifecycle (PutBucketLifecycle [^3]) to\n     * enable Amazon S3 to remove them for you. If you want to block users or accounts from removing or deleting objects\n     * from your bucket, you must deny them the `s3:DeleteObject`, `s3:DeleteObjectVersion`, and\n     * `s3:PutLifeCycleConfiguration` actions.\n     *\n     * The following action is related to `DeleteObject`:\n     *\n     * - PutObject [^4]\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMFADelete.html\n     * [^2]: https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectDELETE.html#ExampleVersionObjectDelete\n     * [^3]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketLifecycle.html\n     * [^4]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html\n     *\n     * @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTObjectDELETE.html\n     * @see https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObject.html\n     * @see https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-s3-2006-03-01.html#deleteobject\n     *\n     * @param array{\n     *   Bucket: string,\n     *   Key: string,\n     *   MFA?: string,\n     *   VersionId?: string,\n     *   RequestPayer?: RequestPayer::*,\n     *   BypassGovernanceRetention?: bool,\n     *   ExpectedBucketOwner?: string,\n     *\n     *   @region?: string,\n     * }|DeleteObjectRequest $input\n     */\n    public function deleteObject($input): DeleteObjectOutput\n    {\n        $input = DeleteObjectRequest::create($input);\n        $response = $this->getResponse($input->request(), new RequestContext(['operation' => 'DeleteObject', 'region' => $input->getRegion()]));\n\n        return new DeleteObjectOutput($response);\n    }\n\n    /**\n     * This action enables you to delete multiple objects from a bucket using a single HTTP request. If you know the object\n     * keys that you want to delete, then this action provides a suitable alternative to sending individual delete requests,\n     * reducing per-request overhead.\n     *\n     * The request contains a list of up to 1000 keys that you want to delete. In the XML, you provide the object key names,\n     * and optionally, version IDs if you want to delete a specific version of the object from a versioning-enabled bucket.\n     * For each key, Amazon S3 performs a delete action and returns the result of that delete, success, or failure, in the\n     * response. Note that if the object specified in the request is not found, Amazon S3 returns the result as deleted.\n     *\n     * The action supports two modes for the response: verbose and quiet. By default, the action uses verbose mode in which\n     * the response includes the result of deletion of each key in your request. In quiet mode the response includes only\n     * keys where the delete action encountered an error. For a successful deletion, the action does not return any\n     * information about the delete in the response body.\n     *\n     * When performing this action on an MFA Delete enabled bucket, that attempts to delete any versioned objects, you must\n     * include an MFA token. If you do not provide one, the entire request will fail, even if there are non-versioned\n     * objects you are trying to delete. If you provide an invalid token, whether there are versioned keys in the request or\n     * not, the entire Multi-Object Delete request will fail. For information about MFA Delete, see  MFA Delete [^1].\n     *\n     * Finally, the Content-MD5 header is required for all Multi-Object Delete requests. Amazon S3 uses the header value to\n     * ensure that your request body has not been altered in transit.\n     *\n     * The following operations are related to `DeleteObjects`:\n     *\n     * - CreateMultipartUpload [^2]\n     * - UploadPart [^3]\n     * - CompleteMultipartUpload [^4]\n     * - ListParts [^5]\n     * - AbortMultipartUpload [^6]\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/dev/Versioning.html#MultiFactorAuthenticationDelete\n     * [^2]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateMultipartUpload.html\n     * [^3]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPart.html\n     * [^4]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_CompleteMultipartUpload.html\n     * [^5]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListParts.html\n     * [^6]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_AbortMultipartUpload.html\n     *\n     * @see http://docs.amazonwebservices.com/AmazonS3/latest/API/multiobjectdeleteapi.html\n     * @see https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObjects.html\n     * @see https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-s3-2006-03-01.html#deleteobjects\n     *\n     * @param array{\n     *   Bucket: string,\n     *   Delete: Delete|array,\n     *   MFA?: string,\n     *   RequestPayer?: RequestPayer::*,\n     *   BypassGovernanceRetention?: bool,\n     *   ExpectedBucketOwner?: string,\n     *   ChecksumAlgorithm?: ChecksumAlgorithm::*,\n     *\n     *   @region?: string,\n     * }|DeleteObjectsRequest $input\n     */\n    public function deleteObjects($input): DeleteObjectsOutput\n    {\n        $input = DeleteObjectsRequest::create($input);\n        $response = $this->getResponse($input->request(), new RequestContext(['operation' => 'DeleteObjects', 'region' => $input->getRegion()]));\n\n        return new DeleteObjectsOutput($response);\n    }\n\n    /**\n     * Returns the Cross-Origin Resource Sharing (CORS) configuration information set for the bucket.\n     *\n     * To use this operation, you must have permission to perform the `s3:GetBucketCORS` action. By default, the bucket\n     * owner has this permission and can grant it to others.\n     *\n     * To use this API operation against an access point, provide the alias of the access point in place of the bucket name.\n     *\n     * To use this API operation against an Object Lambda access point, provide the alias of the Object Lambda access point\n     * in place of the bucket name. If the Object Lambda access point alias in a request is not valid, the error code\n     * `InvalidAccessPointAliasError` is returned. For more information about `InvalidAccessPointAliasError`, see List of\n     * Error Codes [^1].\n     *\n     * For more information about CORS, see  Enabling Cross-Origin Resource Sharing [^2].\n     *\n     * The following operations are related to `GetBucketCors`:\n     *\n     * - PutBucketCors [^3]\n     * - DeleteBucketCors [^4]\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html#ErrorCodeList\n     * [^2]: https://docs.aws.amazon.com/AmazonS3/latest/dev/cors.html\n     * [^3]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketCors.html\n     * [^4]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketCors.html\n     *\n     * @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketGETcors.html\n     * @see https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketCors.html\n     * @see https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-s3-2006-03-01.html#getbucketcors\n     *\n     * @param array{\n     *   Bucket: string,\n     *   ExpectedBucketOwner?: string,\n     *\n     *   @region?: string,\n     * }|GetBucketCorsRequest $input\n     */\n    public function getBucketCors($input): GetBucketCorsOutput\n    {\n        $input = GetBucketCorsRequest::create($input);\n        $response = $this->getResponse($input->request(), new RequestContext(['operation' => 'GetBucketCors', 'region' => $input->getRegion()]));\n\n        return new GetBucketCorsOutput($response);\n    }\n\n    /**\n     * Returns the default encryption configuration for an Amazon S3 bucket. By default, all buckets have a default\n     * encryption configuration that uses server-side encryption with Amazon S3 managed keys (SSE-S3). For information about\n     * the bucket default encryption feature, see Amazon S3 Bucket Default Encryption [^1] in the *Amazon S3 User Guide*.\n     *\n     * To use this operation, you must have permission to perform the `s3:GetEncryptionConfiguration` action. The bucket\n     * owner has this permission by default. The bucket owner can grant this permission to others. For more information\n     * about permissions, see Permissions Related to Bucket Subresource Operations [^2] and Managing Access Permissions to\n     * Your Amazon S3 Resources [^3].\n     *\n     * The following operations are related to `GetBucketEncryption`:\n     *\n     * - PutBucketEncryption [^4]\n     * - DeleteBucketEncryption [^5]\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/dev/bucket-encryption.html\n     * [^2]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-with-s3-actions.html#using-with-s3-actions-related-to-bucket-subresources\n     * [^3]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-access-control.html\n     * [^4]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketEncryption.html\n     * [^5]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketEncryption.html\n     *\n     * @see https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketEncryption.html\n     * @see https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-s3-2006-03-01.html#getbucketencryption\n     *\n     * @param array{\n     *   Bucket: string,\n     *   ExpectedBucketOwner?: string,\n     *\n     *   @region?: string,\n     * }|GetBucketEncryptionRequest $input\n     */\n    public function getBucketEncryption($input): GetBucketEncryptionOutput\n    {\n        $input = GetBucketEncryptionRequest::create($input);\n        $response = $this->getResponse($input->request(), new RequestContext(['operation' => 'GetBucketEncryption', 'region' => $input->getRegion()]));\n\n        return new GetBucketEncryptionOutput($response);\n    }\n\n    /**\n     * Retrieves objects from Amazon S3. To use `GET`, you must have `READ` access to the object. If you grant `READ` access\n     * to the anonymous user, you can return the object without using an authorization header.\n     *\n     * An Amazon S3 bucket has no directory hierarchy such as you would find in a typical computer file system. You can,\n     * however, create a logical hierarchy by using object key names that imply a folder structure. For example, instead of\n     * naming an object `sample.jpg`, you can name it `photos/2006/February/sample.jpg`.\n     *\n     * To get an object from such a logical hierarchy, specify the full key name for the object in the `GET` operation. For\n     * a virtual hosted-style request example, if you have the object `photos/2006/February/sample.jpg`, specify the\n     * resource as `/photos/2006/February/sample.jpg`. For a path-style request example, if you have the object\n     * `photos/2006/February/sample.jpg` in the bucket named `examplebucket`, specify the resource as\n     * `/examplebucket/photos/2006/February/sample.jpg`. For more information about request types, see HTTP Host Header\n     * Bucket Specification [^1].\n     *\n     * For more information about returning the ACL of an object, see GetObjectAcl [^2].\n     *\n     * If the object you are retrieving is stored in the S3 Glacier Flexible Retrieval or S3 Glacier Deep Archive storage\n     * class, or S3 Intelligent-Tiering Archive or S3 Intelligent-Tiering Deep Archive tiers, before you can retrieve the\n     * object you must first restore a copy using RestoreObject [^3]. Otherwise, this action returns an `InvalidObjectState`\n     * error. For information about restoring archived objects, see Restoring Archived Objects [^4].\n     *\n     * Encryption request headers, like `x-amz-server-side-encryption`, should not be sent for GET requests if your object\n     * uses server-side encryption with Key Management Service (KMS) keys (SSE-KMS), dual-layer server-side encryption with\n     * Amazon Web Services KMS keys (DSSE-KMS), or server-side encryption with Amazon S3 managed encryption keys (SSE-S3).\n     * If your object does use these types of keys, you’ll get an HTTP 400 Bad Request error.\n     *\n     * If you encrypt an object by using server-side encryption with customer-provided encryption keys (SSE-C) when you\n     * store the object in Amazon S3, then when you GET the object, you must use the following headers:\n     *\n     * - `x-amz-server-side-encryption-customer-algorithm`\n     * - `x-amz-server-side-encryption-customer-key`\n     * - `x-amz-server-side-encryption-customer-key-MD5`\n     *\n     * For more information about SSE-C, see Server-Side Encryption (Using Customer-Provided Encryption Keys) [^5].\n     *\n     * Assuming you have the relevant permission to read object tags, the response also returns the `x-amz-tagging-count`\n     * header that provides the count of number of tags associated with the object. You can use GetObjectTagging [^6] to\n     * retrieve the tag set associated with an object.\n     *\n     * - `Permissions`:\n     *\n     *   You need the relevant read object (or version) permission for this operation. For more information, see Specifying\n     *   Permissions in a Policy [^7]. If the object that you request doesn’t exist, the error that Amazon S3 returns\n     *   depends on whether you also have the `s3:ListBucket` permission.\n     *\n     *   If you have the `s3:ListBucket` permission on the bucket, Amazon S3 returns an HTTP status code 404 (Not Found)\n     *   error.\n     *\n     *   If you don’t have the `s3:ListBucket` permission, Amazon S3 returns an HTTP status code 403 (\"access denied\")\n     *   error.\n     * - `Versioning`:\n     *\n     *   By default, the `GET` action returns the current version of an object. To return a different version, use the\n     *   `versionId` subresource.\n     *\n     *   > - If you supply a `versionId`, you need the `s3:GetObjectVersion` permission to access a specific version of an\n     *   >   object. If you request a specific version, you do not need to have the `s3:GetObject` permission. If you\n     *   >   request the current version without a specific version ID, only `s3:GetObject` permission is required.\n     *   >   `s3:GetObjectVersion` permission won't be required.\n     *   > - If the current version of the object is a delete marker, Amazon S3 behaves as if the object was deleted and\n     *   >   includes `x-amz-delete-marker: true` in the response.\n     *   >\n     *\n     *   For more information about versioning, see PutBucketVersioning [^8].\n     * - `Overriding Response Header Values`:\n     *\n     *   There are times when you want to override certain response header values in a `GET` response. For example, you\n     *   might override the `Content-Disposition` response header value in your `GET` request.\n     *\n     *   You can override values for a set of response headers using the following query parameters. These response header\n     *   values are sent only on a successful request, that is, when status code 200 OK is returned. The set of headers you\n     *   can override using these parameters is a subset of the headers that Amazon S3 accepts when you create an object.\n     *   The response headers that you can override for the `GET` response are `Content-Type`, `Content-Language`,\n     *   `Expires`, `Cache-Control`, `Content-Disposition`, and `Content-Encoding`. To override these header values in the\n     *   `GET` response, you use the following request parameters.\n     *\n     *   > You must sign the request, either using an Authorization header or a presigned URL, when using these parameters.\n     *   > They cannot be used with an unsigned (anonymous) request.\n     *\n     *   - `response-content-type`\n     *   - `response-content-language`\n     *   - `response-expires`\n     *   - `response-cache-control`\n     *   - `response-content-disposition`\n     *   - `response-content-encoding`\n     *\n     * - `Overriding Response Header Values`:\n     *\n     *   If both of the `If-Match` and `If-Unmodified-Since` headers are present in the request as follows: `If-Match`\n     *   condition evaluates to `true`, and; `If-Unmodified-Since` condition evaluates to `false`; then, S3 returns 200 OK\n     *   and the data requested.\n     *\n     *   If both of the `If-None-Match` and `If-Modified-Since` headers are present in the request as follows:`\n     *   If-None-Match` condition evaluates to `false`, and; `If-Modified-Since` condition evaluates to `true`; then, S3\n     *   returns 304 Not Modified response code.\n     *\n     *   For more information about conditional requests, see RFC 7232 [^9].\n     *\n     * The following operations are related to `GetObject`:\n     *\n     * - ListBuckets [^10]\n     * - GetObjectAcl [^11]\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/dev/VirtualHosting.html#VirtualHostingSpecifyBucket\n     * [^2]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectAcl.html\n     * [^3]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_RestoreObject.html\n     * [^4]: https://docs.aws.amazon.com/AmazonS3/latest/dev/restoring-objects.html\n     * [^5]: https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerSideEncryptionCustomerKeys.html\n     * [^6]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectTagging.html\n     * [^7]: https://docs.aws.amazon.com/AmazonS3/latest/dev/using-with-s3-actions.html\n     * [^8]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketVersioning.html\n     * [^9]: https://tools.ietf.org/html/rfc7232\n     * [^10]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListBuckets.html\n     * [^11]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectAcl.html\n     *\n     * @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTObjectGET.html\n     * @see https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html\n     * @see https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-s3-2006-03-01.html#getobject\n     *\n     * @param array{\n     *   Bucket: string,\n     *   IfMatch?: string,\n     *   IfModifiedSince?: \\DateTimeImmutable|string,\n     *   IfNoneMatch?: string,\n     *   IfUnmodifiedSince?: \\DateTimeImmutable|string,\n     *   Key: string,\n     *   Range?: string,\n     *   ResponseCacheControl?: string,\n     *   ResponseContentDisposition?: string,\n     *   ResponseContentEncoding?: string,\n     *   ResponseContentLanguage?: string,\n     *   ResponseContentType?: string,\n     *   ResponseExpires?: \\DateTimeImmutable|string,\n     *   VersionId?: string,\n     *   SSECustomerAlgorithm?: string,\n     *   SSECustomerKey?: string,\n     *   SSECustomerKeyMD5?: string,\n     *   RequestPayer?: RequestPayer::*,\n     *   PartNumber?: int,\n     *   ExpectedBucketOwner?: string,\n     *   ChecksumMode?: ChecksumMode::*,\n     *\n     *   @region?: string,\n     * }|GetObjectRequest $input\n     *\n     * @throws NoSuchKeyException\n     * @throws InvalidObjectStateException\n     */\n    public function getObject($input): GetObjectOutput\n    {\n        $input = GetObjectRequest::create($input);\n        $response = $this->getResponse($input->request(), new RequestContext(['operation' => 'GetObject', 'region' => $input->getRegion(), 'exceptionMapping' => [\n            'NoSuchKey' => NoSuchKeyException::class,\n            'InvalidObjectState' => InvalidObjectStateException::class,\n        ]]));\n\n        return new GetObjectOutput($response);\n    }\n\n    /**\n     * Returns the access control list (ACL) of an object. To use this operation, you must have `s3:GetObjectAcl`\n     * permissions or `READ_ACP` access to the object. For more information, see Mapping of ACL permissions and access\n     * policy permissions [^1] in the *Amazon S3 User Guide*.\n     *\n     * This action is not supported by Amazon S3 on Outposts.\n     *\n     * By default, GET returns ACL information about the current version of an object. To return ACL information about a\n     * different version, use the versionId subresource.\n     *\n     * > If your bucket uses the bucket owner enforced setting for S3 Object Ownership, requests to read ACLs are still\n     * > supported and return the `bucket-owner-full-control` ACL with the owner being the account that created the bucket.\n     * > For more information, see  Controlling object ownership and disabling ACLs [^2] in the *Amazon S3 User Guide*.\n     *\n     * The following operations are related to `GetObjectAcl`:\n     *\n     * - GetObject [^3]\n     * - GetObjectAttributes [^4]\n     * - DeleteObject [^5]\n     * - PutObject [^6]\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/acl-overview.html#acl-access-policy-permission-mapping\n     * [^2]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/about-object-ownership.html\n     * [^3]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html\n     * [^4]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectAttributes.html\n     * [^5]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObject.html\n     * [^6]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html\n     *\n     * @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTObjectGETacl.html\n     * @see https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectAcl.html\n     * @see https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-s3-2006-03-01.html#getobjectacl\n     *\n     * @param array{\n     *   Bucket: string,\n     *   Key: string,\n     *   VersionId?: string,\n     *   RequestPayer?: RequestPayer::*,\n     *   ExpectedBucketOwner?: string,\n     *\n     *   @region?: string,\n     * }|GetObjectAclRequest $input\n     *\n     * @throws NoSuchKeyException\n     */\n    public function getObjectAcl($input): GetObjectAclOutput\n    {\n        $input = GetObjectAclRequest::create($input);\n        $response = $this->getResponse($input->request(), new RequestContext(['operation' => 'GetObjectAcl', 'region' => $input->getRegion(), 'exceptionMapping' => [\n            'NoSuchKey' => NoSuchKeyException::class,\n        ]]));\n\n        return new GetObjectAclOutput($response);\n    }\n\n    /**\n     * The `HEAD` action retrieves metadata from an object without returning the object itself. This action is useful if\n     * you're only interested in an object's metadata. To use `HEAD`, you must have READ access to the object.\n     *\n     * A `HEAD` request has the same options as a `GET` action on an object. The response is identical to the `GET` response\n     * except that there is no response body. Because of this, if the `HEAD` request generates an error, it returns a\n     * generic `400 Bad Request`, `403 Forbidden` or `404 Not Found` code. It is not possible to retrieve the exact\n     * exception beyond these error codes.\n     *\n     * If you encrypt an object by using server-side encryption with customer-provided encryption keys (SSE-C) when you\n     * store the object in Amazon S3, then when you retrieve the metadata from the object, you must use the following\n     * headers:\n     *\n     * - `x-amz-server-side-encryption-customer-algorithm`\n     * - `x-amz-server-side-encryption-customer-key`\n     * - `x-amz-server-side-encryption-customer-key-MD5`\n     *\n     * For more information about SSE-C, see Server-Side Encryption (Using Customer-Provided Encryption Keys) [^1].\n     *\n     * > - Encryption request headers, like `x-amz-server-side-encryption`, should not be sent for `GET` requests if your\n     * >   object uses server-side encryption with Key Management Service (KMS) keys (SSE-KMS), dual-layer server-side\n     * >   encryption with Amazon Web Services KMS keys (DSSE-KMS), or server-side encryption with Amazon S3 managed\n     * >   encryption keys (SSE-S3). If your object does use these types of keys, you’ll get an HTTP 400 Bad Request\n     * >   error.\n     * > - The last modified property in this case is the creation date of the object.\n     * >\n     *\n     * Request headers are limited to 8 KB in size. For more information, see Common Request Headers [^2].\n     *\n     * Consider the following when using request headers:\n     *\n     * - Consideration 1 – If both of the `If-Match` and `If-Unmodified-Since` headers are present in the request as\n     *   follows:\n     *\n     *   - `If-Match` condition evaluates to `true`, and;\n     *   - `If-Unmodified-Since` condition evaluates to `false`;\n     *\n     *   Then Amazon S3 returns `200 OK` and the data requested.\n     * - Consideration 2 – If both of the `If-None-Match` and `If-Modified-Since` headers are present in the request as\n     *   follows:\n     *\n     *   - `If-None-Match` condition evaluates to `false`, and;\n     *   - `If-Modified-Since` condition evaluates to `true`;\n     *\n     *   Then Amazon S3 returns the `304 Not Modified` response code.\n     *\n     * For more information about conditional requests, see RFC 7232 [^3].\n     *\n     * - `Permissions`:\n     *\n     *   You need the relevant read object (or version) permission for this operation. For more information, see Actions,\n     *   resources, and condition keys for Amazon S3 [^4]. If the object you request doesn't exist, the error that Amazon S3\n     *   returns depends on whether you also have the s3:ListBucket permission.\n     *\n     *   - If you have the `s3:ListBucket` permission on the bucket, Amazon S3 returns an HTTP status code 404 error.\n     *   - If you don’t have the `s3:ListBucket` permission, Amazon S3 returns an HTTP status code 403 error.\n     *\n     *\n     * The following actions are related to `HeadObject`:\n     *\n     * - GetObject [^5]\n     * - GetObjectAttributes [^6]\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerSideEncryptionCustomerKeys.html\n     * [^2]: https://docs.aws.amazon.com/AmazonS3/latest/API/RESTCommonRequestHeaders.html\n     * [^3]: https://tools.ietf.org/html/rfc7232\n     * [^4]: https://docs.aws.amazon.com/AmazonS3/latest/dev/list_amazons3.html\n     * [^5]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html\n     * [^6]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectAttributes.html\n     *\n     * @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTObjectHEAD.html\n     * @see https://docs.aws.amazon.com/AmazonS3/latest/API/API_HeadObject.html\n     * @see https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-s3-2006-03-01.html#headobject\n     *\n     * @param array{\n     *   Bucket: string,\n     *   IfMatch?: string,\n     *   IfModifiedSince?: \\DateTimeImmutable|string,\n     *   IfNoneMatch?: string,\n     *   IfUnmodifiedSince?: \\DateTimeImmutable|string,\n     *   Key: string,\n     *   Range?: string,\n     *   VersionId?: string,\n     *   SSECustomerAlgorithm?: string,\n     *   SSECustomerKey?: string,\n     *   SSECustomerKeyMD5?: string,\n     *   RequestPayer?: RequestPayer::*,\n     *   PartNumber?: int,\n     *   ExpectedBucketOwner?: string,\n     *   ChecksumMode?: ChecksumMode::*,\n     *\n     *   @region?: string,\n     * }|HeadObjectRequest $input\n     *\n     * @throws NoSuchKeyException\n     */\n    public function headObject($input): HeadObjectOutput\n    {\n        $input = HeadObjectRequest::create($input);\n        $response = $this->getResponse($input->request(), new RequestContext(['operation' => 'HeadObject', 'region' => $input->getRegion(), 'exceptionMapping' => [\n            'NoSuchKey' => NoSuchKeyException::class,\n        ]]));\n\n        return new HeadObjectOutput($response);\n    }\n\n    /**\n     * Returns a list of all buckets owned by the authenticated sender of the request. To use this operation, you must have\n     * the `s3:ListAllMyBuckets` permission.\n     *\n     * For information about Amazon S3 buckets, see Creating, configuring, and working with Amazon S3 buckets [^1].\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/creating-buckets-s3.html\n     *\n     * @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTServiceGET.html\n     * @see https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListBuckets.html\n     * @see https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-s3-2006-03-01.html#listbuckets\n     *\n     * @param array{\n     *\n     *   @region?: string,\n     * }|ListBucketsRequest $input\n     */\n    public function listBuckets($input = []): ListBucketsOutput\n    {\n        $input = ListBucketsRequest::create($input);\n        $response = $this->getResponse($input->request(), new RequestContext(['operation' => 'ListBuckets', 'region' => $input->getRegion()]));\n\n        return new ListBucketsOutput($response);\n    }\n\n    /**\n     * This action lists in-progress multipart uploads. An in-progress multipart upload is a multipart upload that has been\n     * initiated using the Initiate Multipart Upload request, but has not yet been completed or aborted.\n     *\n     * This action returns at most 1,000 multipart uploads in the response. 1,000 multipart uploads is the maximum number of\n     * uploads a response can include, which is also the default value. You can further limit the number of uploads in a\n     * response by specifying the `max-uploads` parameter in the response. If additional multipart uploads satisfy the list\n     * criteria, the response will contain an `IsTruncated` element with the value true. To list the additional multipart\n     * uploads, use the `key-marker` and `upload-id-marker` request parameters.\n     *\n     * In the response, the uploads are sorted by key. If your application has initiated more than one multipart upload\n     * using the same object key, then uploads in the response are first sorted by key. Additionally, uploads are sorted in\n     * ascending order within each key by the upload initiation time.\n     *\n     * For more information on multipart uploads, see Uploading Objects Using Multipart Upload [^1].\n     *\n     * For information on permissions required to use the multipart upload API, see Multipart Upload and Permissions [^2].\n     *\n     * The following operations are related to `ListMultipartUploads`:\n     *\n     * - CreateMultipartUpload [^3]\n     * - UploadPart [^4]\n     * - CompleteMultipartUpload [^5]\n     * - ListParts [^6]\n     * - AbortMultipartUpload [^7]\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/dev/uploadobjusingmpu.html\n     * [^2]: https://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html\n     * [^3]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateMultipartUpload.html\n     * [^4]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPart.html\n     * [^5]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_CompleteMultipartUpload.html\n     * [^6]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListParts.html\n     * [^7]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_AbortMultipartUpload.html\n     *\n     * @see http://docs.amazonwebservices.com/AmazonS3/latest/API/mpUploadListMPUpload.html\n     * @see https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListMultipartUploads.html\n     * @see https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-s3-2006-03-01.html#listmultipartuploads\n     *\n     * @param array{\n     *   Bucket: string,\n     *   Delimiter?: string,\n     *   EncodingType?: EncodingType::*,\n     *   KeyMarker?: string,\n     *   MaxUploads?: int,\n     *   Prefix?: string,\n     *   UploadIdMarker?: string,\n     *   ExpectedBucketOwner?: string,\n     *   RequestPayer?: RequestPayer::*,\n     *\n     *   @region?: string,\n     * }|ListMultipartUploadsRequest $input\n     */\n    public function listMultipartUploads($input): ListMultipartUploadsOutput\n    {\n        $input = ListMultipartUploadsRequest::create($input);\n        $response = $this->getResponse($input->request(), new RequestContext(['operation' => 'ListMultipartUploads', 'region' => $input->getRegion()]));\n\n        return new ListMultipartUploadsOutput($response, $this, $input);\n    }\n\n    /**\n     * Returns some or all (up to 1,000) of the objects in a bucket with each request. You can use the request parameters as\n     * selection criteria to return a subset of the objects in a bucket. A `200 OK` response can contain valid or invalid\n     * XML. Make sure to design your application to parse the contents of the response and handle it appropriately. Objects\n     * are returned sorted in an ascending order of the respective key names in the list. For more information about listing\n     * objects, see Listing object keys programmatically [^1].\n     *\n     * To use this operation, you must have READ access to the bucket.\n     *\n     * To use this action in an Identity and Access Management (IAM) policy, you must have permissions to perform the\n     * `s3:ListBucket` action. The bucket owner has this permission by default and can grant this permission to others. For\n     * more information about permissions, see Permissions Related to Bucket Subresource Operations [^2] and Managing Access\n     * Permissions to Your Amazon S3 Resources [^3].\n     *\n     * ! This section describes the latest revision of this action. We recommend that you use this revised API for\n     * ! application development. For backward compatibility, Amazon S3 continues to support the prior version of this API,\n     * ! ListObjects [^4].\n     *\n     * To get a list of your buckets, see ListBuckets [^5].\n     *\n     * The following operations are related to `ListObjectsV2`:\n     *\n     * - GetObject [^6]\n     * - PutObject [^7]\n     * - CreateBucket [^8]\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/ListingKeysUsingAPIs.html\n     * [^2]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-with-s3-actions.html#using-with-s3-actions-related-to-bucket-subresources\n     * [^3]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-access-control.html\n     * [^4]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjects.html\n     * [^5]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListBuckets.html\n     * [^6]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html\n     * [^7]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html\n     * [^8]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateBucket.html\n     *\n     * @see https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjectsV2.html\n     * @see https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-s3-2006-03-01.html#listobjectsv2\n     *\n     * @param array{\n     *   Bucket: string,\n     *   Delimiter?: string,\n     *   EncodingType?: EncodingType::*,\n     *   MaxKeys?: int,\n     *   Prefix?: string,\n     *   ContinuationToken?: string,\n     *   FetchOwner?: bool,\n     *   StartAfter?: string,\n     *   RequestPayer?: RequestPayer::*,\n     *   ExpectedBucketOwner?: string,\n     *\n     *   @region?: string,\n     * }|ListObjectsV2Request $input\n     *\n     * @throws NoSuchBucketException\n     */\n    public function listObjectsV2($input): ListObjectsV2Output\n    {\n        $input = ListObjectsV2Request::create($input);\n        $response = $this->getResponse($input->request(), new RequestContext(['operation' => 'ListObjectsV2', 'region' => $input->getRegion(), 'exceptionMapping' => [\n            'NoSuchBucket' => NoSuchBucketException::class,\n        ]]));\n\n        return new ListObjectsV2Output($response, $this, $input);\n    }\n\n    /**\n     * Lists the parts that have been uploaded for a specific multipart upload. This operation must include the upload ID,\n     * which you obtain by sending the initiate multipart upload request (see CreateMultipartUpload [^1]). This request\n     * returns a maximum of 1,000 uploaded parts. The default number of parts returned is 1,000 parts. You can restrict the\n     * number of parts returned by specifying the `max-parts` request parameter. If your multipart upload consists of more\n     * than 1,000 parts, the response returns an `IsTruncated` field with the value of true, and a `NextPartNumberMarker`\n     * element. In subsequent `ListParts` requests you can include the part-number-marker query string parameter and set its\n     * value to the `NextPartNumberMarker` field value from the previous response.\n     *\n     * If the upload was created using a checksum algorithm, you will need to have permission to the `kms:Decrypt` action\n     * for the request to succeed.\n     *\n     * For more information on multipart uploads, see Uploading Objects Using Multipart Upload [^2].\n     *\n     * For information on permissions required to use the multipart upload API, see Multipart Upload and Permissions [^3].\n     *\n     * The following operations are related to `ListParts`:\n     *\n     * - CreateMultipartUpload [^4]\n     * - UploadPart [^5]\n     * - CompleteMultipartUpload [^6]\n     * - AbortMultipartUpload [^7]\n     * - GetObjectAttributes [^8]\n     * - ListMultipartUploads [^9]\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateMultipartUpload.html\n     * [^2]: https://docs.aws.amazon.com/AmazonS3/latest/dev/uploadobjusingmpu.html\n     * [^3]: https://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html\n     * [^4]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateMultipartUpload.html\n     * [^5]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPart.html\n     * [^6]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_CompleteMultipartUpload.html\n     * [^7]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_AbortMultipartUpload.html\n     * [^8]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectAttributes.html\n     * [^9]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListMultipartUploads.html\n     *\n     * @see http://docs.amazonwebservices.com/AmazonS3/latest/API/mpUploadListParts.html\n     * @see https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListParts.html\n     * @see https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-s3-2006-03-01.html#listparts\n     *\n     * @param array{\n     *   Bucket: string,\n     *   Key: string,\n     *   MaxParts?: int,\n     *   PartNumberMarker?: int,\n     *   UploadId: string,\n     *   RequestPayer?: RequestPayer::*,\n     *   ExpectedBucketOwner?: string,\n     *   SSECustomerAlgorithm?: string,\n     *   SSECustomerKey?: string,\n     *   SSECustomerKeyMD5?: string,\n     *\n     *   @region?: string,\n     * }|ListPartsRequest $input\n     */\n    public function listParts($input): ListPartsOutput\n    {\n        $input = ListPartsRequest::create($input);\n        $response = $this->getResponse($input->request(), new RequestContext(['operation' => 'ListParts', 'region' => $input->getRegion()]));\n\n        return new ListPartsOutput($response, $this, $input);\n    }\n\n    /**\n     * @see headObject\n     *\n     * @param array{\n     *   Bucket: string,\n     *   IfMatch?: string,\n     *   IfModifiedSince?: \\DateTimeImmutable|string,\n     *   IfNoneMatch?: string,\n     *   IfUnmodifiedSince?: \\DateTimeImmutable|string,\n     *   Key: string,\n     *   Range?: string,\n     *   VersionId?: string,\n     *   SSECustomerAlgorithm?: string,\n     *   SSECustomerKey?: string,\n     *   SSECustomerKeyMD5?: string,\n     *   RequestPayer?: RequestPayer::*,\n     *   PartNumber?: int,\n     *   ExpectedBucketOwner?: string,\n     *   ChecksumMode?: ChecksumMode::*,\n     *\n     *   @region?: string,\n     * }|HeadObjectRequest $input\n     */\n    public function objectExists($input): ObjectExistsWaiter\n    {\n        $input = HeadObjectRequest::create($input);\n        $response = $this->getResponse($input->request(), new RequestContext(['operation' => 'HeadObject', 'region' => $input->getRegion(), 'exceptionMapping' => [\n            'NoSuchKey' => NoSuchKeyException::class,\n        ]]));\n\n        return new ObjectExistsWaiter($response, $this, $input);\n    }\n\n    /**\n     * @see headObject\n     *\n     * @param array{\n     *   Bucket: string,\n     *   IfMatch?: string,\n     *   IfModifiedSince?: \\DateTimeImmutable|string,\n     *   IfNoneMatch?: string,\n     *   IfUnmodifiedSince?: \\DateTimeImmutable|string,\n     *   Key: string,\n     *   Range?: string,\n     *   VersionId?: string,\n     *   SSECustomerAlgorithm?: string,\n     *   SSECustomerKey?: string,\n     *   SSECustomerKeyMD5?: string,\n     *   RequestPayer?: RequestPayer::*,\n     *   PartNumber?: int,\n     *   ExpectedBucketOwner?: string,\n     *   ChecksumMode?: ChecksumMode::*,\n     *\n     *   @region?: string,\n     * }|HeadObjectRequest $input\n     */\n    public function objectNotExists($input): ObjectNotExistsWaiter\n    {\n        $input = HeadObjectRequest::create($input);\n        $response = $this->getResponse($input->request(), new RequestContext(['operation' => 'HeadObject', 'region' => $input->getRegion(), 'exceptionMapping' => [\n            'NoSuchKey' => NoSuchKeyException::class,\n        ]]));\n\n        return new ObjectNotExistsWaiter($response, $this, $input);\n    }\n\n    /**\n     * Sets the `cors` configuration for your bucket. If the configuration exists, Amazon S3 replaces it.\n     *\n     * To use this operation, you must be allowed to perform the `s3:PutBucketCORS` action. By default, the bucket owner has\n     * this permission and can grant it to others.\n     *\n     * You set this configuration on a bucket so that the bucket can service cross-origin requests. For example, you might\n     * want to enable a request whose origin is `http://www.example.com` to access your Amazon S3 bucket at\n     * `my.example.bucket.com` by using the browser's `XMLHttpRequest` capability.\n     *\n     * To enable cross-origin resource sharing (CORS) on a bucket, you add the `cors` subresource to the bucket. The `cors`\n     * subresource is an XML document in which you configure rules that identify origins and the HTTP methods that can be\n     * executed on your bucket. The document is limited to 64 KB in size.\n     *\n     * When Amazon S3 receives a cross-origin request (or a pre-flight OPTIONS request) against a bucket, it evaluates the\n     * `cors` configuration on the bucket and uses the first `CORSRule` rule that matches the incoming browser request to\n     * enable a cross-origin request. For a rule to match, the following conditions must be met:\n     *\n     * - The request's `Origin` header must match `AllowedOrigin` elements.\n     * - The request method (for example, GET, PUT, HEAD, and so on) or the `Access-Control-Request-Method` header in case\n     *   of a pre-flight `OPTIONS` request must be one of the `AllowedMethod` elements.\n     * - Every header specified in the `Access-Control-Request-Headers` request header of a pre-flight request must match an\n     *   `AllowedHeader` element.\n     *\n     * For more information about CORS, go to Enabling Cross-Origin Resource Sharing [^1] in the *Amazon S3 User Guide*.\n     *\n     * The following operations are related to `PutBucketCors`:\n     *\n     * - GetBucketCors [^2]\n     * - DeleteBucketCors [^3]\n     * - RESTOPTIONSobject [^4]\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/dev/cors.html\n     * [^2]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketCors.html\n     * [^3]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketCors.html\n     * [^4]: https://docs.aws.amazon.com/AmazonS3/latest/API/RESTOPTIONSobject.html\n     *\n     * @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketPUTcors.html\n     * @see https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketCors.html\n     * @see https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-s3-2006-03-01.html#putbucketcors\n     *\n     * @param array{\n     *   Bucket: string,\n     *   CORSConfiguration: CORSConfiguration|array,\n     *   ContentMD5?: string,\n     *   ChecksumAlgorithm?: ChecksumAlgorithm::*,\n     *   ExpectedBucketOwner?: string,\n     *\n     *   @region?: string,\n     * }|PutBucketCorsRequest $input\n     */\n    public function putBucketCors($input): Result\n    {\n        $input = PutBucketCorsRequest::create($input);\n        $response = $this->getResponse($input->request(), new RequestContext(['operation' => 'PutBucketCors', 'region' => $input->getRegion()]));\n\n        return new Result($response);\n    }\n\n    /**\n     * Enables notifications of specified events for a bucket. For more information about event notifications, see\n     * Configuring Event Notifications [^1].\n     *\n     * Using this API, you can replace an existing notification configuration. The configuration is an XML file that defines\n     * the event types that you want Amazon S3 to publish and the destination where you want Amazon S3 to publish an event\n     * notification when it detects an event of the specified type.\n     *\n     * By default, your bucket has no event notifications configured. That is, the notification configuration will be an\n     * empty `NotificationConfiguration`.\n     *\n     * `<NotificationConfiguration>`\n     *\n     * `</NotificationConfiguration>`\n     *\n     * This action replaces the existing notification configuration with the configuration you include in the request body.\n     *\n     * After Amazon S3 receives this request, it first verifies that any Amazon Simple Notification Service (Amazon SNS) or\n     * Amazon Simple Queue Service (Amazon SQS) destination exists, and that the bucket owner has permission to publish to\n     * it by sending a test notification. In the case of Lambda destinations, Amazon S3 verifies that the Lambda function\n     * permissions grant Amazon S3 permission to invoke the function from the Amazon S3 bucket. For more information, see\n     * Configuring Notifications for Amazon S3 Events [^2].\n     *\n     * You can disable notifications by adding the empty NotificationConfiguration element.\n     *\n     * For more information about the number of event notification configurations that you can create per bucket, see Amazon\n     * S3 service quotas [^3] in *Amazon Web Services General Reference*.\n     *\n     * By default, only the bucket owner can configure notifications on a bucket. However, bucket owners can use a bucket\n     * policy to grant permission to other users to set this configuration with the required `s3:PutBucketNotification`\n     * permission.\n     *\n     * > The PUT notification is an atomic operation. For example, suppose your notification configuration includes SNS\n     * > topic, SQS queue, and Lambda function configurations. When you send a PUT request with this configuration, Amazon\n     * > S3 sends test messages to your SNS topic. If the message fails, the entire PUT action will fail, and Amazon S3 will\n     * > not add the configuration to your bucket.\n     *\n     * If the configuration in the request body includes only one `TopicConfiguration` specifying only the\n     * `s3:ReducedRedundancyLostObject` event type, the response will also include the `x-amz-sns-test-message-id` header\n     * containing the message ID of the test notification sent to the topic.\n     *\n     * The following action is related to `PutBucketNotificationConfiguration`:\n     *\n     * - GetBucketNotificationConfiguration [^4]\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/dev/NotificationHowTo.html\n     * [^2]: https://docs.aws.amazon.com/AmazonS3/latest/dev/NotificationHowTo.html\n     * [^3]: https://docs.aws.amazon.com/general/latest/gr/s3.html#limits_s3\n     * [^4]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketNotificationConfiguration.html\n     *\n     * @see https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketNotificationConfiguration.html\n     * @see https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-s3-2006-03-01.html#putbucketnotificationconfiguration\n     *\n     * @param array{\n     *   Bucket: string,\n     *   NotificationConfiguration: NotificationConfiguration|array,\n     *   ExpectedBucketOwner?: string,\n     *   SkipDestinationValidation?: bool,\n     *\n     *   @region?: string,\n     * }|PutBucketNotificationConfigurationRequest $input\n     */\n    public function putBucketNotificationConfiguration($input): Result\n    {\n        $input = PutBucketNotificationConfigurationRequest::create($input);\n        $response = $this->getResponse($input->request(), new RequestContext(['operation' => 'PutBucketNotificationConfiguration', 'region' => $input->getRegion()]));\n\n        return new Result($response);\n    }\n\n    /**\n     * Adds an object to a bucket. You must have WRITE permissions on a bucket to add an object to it.\n     *\n     * > Amazon S3 never adds partial objects; if you receive a success response, Amazon S3 added the entire object to the\n     * > bucket. You cannot use `PutObject` to only update a single piece of metadata for an existing object. You must put\n     * > the entire object with updated metadata if you want to update some values.\n     *\n     * Amazon S3 is a distributed system. If it receives multiple write requests for the same object simultaneously, it\n     * overwrites all but the last object written. To prevent objects from being deleted or overwritten, you can use Amazon\n     * S3 Object Lock [^1].\n     *\n     * To ensure that data is not corrupted traversing the network, use the `Content-MD5` header. When you use this header,\n     * Amazon S3 checks the object against the provided MD5 value and, if they do not match, returns an error. Additionally,\n     * you can calculate the MD5 while putting an object to Amazon S3 and compare the returned ETag to the calculated MD5\n     * value.\n     *\n     * > - To successfully complete the `PutObject` request, you must have the `s3:PutObject` in your IAM permissions.\n     * > - To successfully change the objects acl of your `PutObject` request, you must have the `s3:PutObjectAcl` in your\n     * >   IAM permissions.\n     * > - To successfully set the tag-set with your `PutObject` request, you must have the `s3:PutObjectTagging` in your\n     * >   IAM permissions.\n     * > - The `Content-MD5` header is required for any request to upload an object with a retention period configured using\n     * >   Amazon S3 Object Lock. For more information about Amazon S3 Object Lock, see Amazon S3 Object Lock Overview [^2]\n     * >   in the *Amazon S3 User Guide*.\n     * >\n     *\n     * You have four mutually exclusive options to protect data using server-side encryption in Amazon S3, depending on how\n     * you choose to manage the encryption keys. Specifically, the encryption key options are Amazon S3 managed keys\n     * (SSE-S3), Amazon Web Services KMS keys (SSE-KMS or DSSE-KMS), and customer-provided keys (SSE-C). Amazon S3 encrypts\n     * data with server-side encryption by using Amazon S3 managed keys (SSE-S3) by default. You can optionally tell Amazon\n     * S3 to encrypt data at rest by using server-side encryption with other key options. For more information, see Using\n     * Server-Side Encryption [^3].\n     *\n     * When adding a new object, you can use headers to grant ACL-based permissions to individual Amazon Web Services\n     * accounts or to predefined groups defined by Amazon S3. These permissions are then added to the ACL on the object. By\n     * default, all objects are private. Only the owner has full access control. For more information, see Access Control\n     * List (ACL) Overview [^4] and Managing ACLs Using the REST API [^5].\n     *\n     * If the bucket that you're uploading objects to uses the bucket owner enforced setting for S3 Object Ownership, ACLs\n     * are disabled and no longer affect permissions. Buckets that use this setting only accept PUT requests that don't\n     * specify an ACL or PUT requests that specify bucket owner full control ACLs, such as the `bucket-owner-full-control`\n     * canned ACL or an equivalent form of this ACL expressed in the XML format. PUT requests that contain other ACLs (for\n     * example, custom grants to certain Amazon Web Services accounts) fail and return a `400` error with the error code\n     * `AccessControlListNotSupported`. For more information, see  Controlling ownership of objects and disabling ACLs [^6]\n     * in the *Amazon S3 User Guide*.\n     *\n     * > If your bucket uses the bucket owner enforced setting for Object Ownership, all objects written to the bucket by\n     * > any account will be owned by the bucket owner.\n     *\n     * By default, Amazon S3 uses the STANDARD Storage Class to store newly created objects. The STANDARD storage class\n     * provides high durability and high availability. Depending on performance needs, you can specify a different Storage\n     * Class. Amazon S3 on Outposts only uses the OUTPOSTS Storage Class. For more information, see Storage Classes [^7] in\n     * the *Amazon S3 User Guide*.\n     *\n     * If you enable versioning for a bucket, Amazon S3 automatically generates a unique version ID for the object being\n     * stored. Amazon S3 returns this ID in the response. When you enable versioning for a bucket, if Amazon S3 receives\n     * multiple write requests for the same object simultaneously, it stores all of the objects. For more information about\n     * versioning, see Adding Objects to Versioning-Enabled Buckets [^8]. For information about returning the versioning\n     * state of a bucket, see GetBucketVersioning [^9].\n     *\n     * For more information about related Amazon S3 APIs, see the following:\n     *\n     * - CopyObject [^10]\n     * - DeleteObject [^11]\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-lock.html\n     * [^2]: https://docs.aws.amazon.com/AmazonS3/latest/dev/object-lock-overview.html\n     * [^3]: https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingServerSideEncryption.html\n     * [^4]: https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html\n     * [^5]: https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-using-rest-api.html\n     * [^6]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/about-object-ownership.html\n     * [^7]: https://docs.aws.amazon.com/AmazonS3/latest/dev/storage-class-intro.html\n     * [^8]: https://docs.aws.amazon.com/AmazonS3/latest/dev/AddingObjectstoVersioningEnabledBuckets.html\n     * [^9]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketVersioning.html\n     * [^10]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_CopyObject.html\n     * [^11]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObject.html\n     *\n     * @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTObjectPUT.html\n     * @see https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html\n     * @see https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-s3-2006-03-01.html#putobject\n     *\n     * @param array{\n     *   ACL?: ObjectCannedACL::*,\n     *   Body?: string|resource|callable|iterable,\n     *   Bucket: string,\n     *   CacheControl?: string,\n     *   ContentDisposition?: string,\n     *   ContentEncoding?: string,\n     *   ContentLanguage?: string,\n     *   ContentLength?: string,\n     *   ContentMD5?: string,\n     *   ContentType?: string,\n     *   ChecksumAlgorithm?: ChecksumAlgorithm::*,\n     *   ChecksumCRC32?: string,\n     *   ChecksumCRC32C?: string,\n     *   ChecksumSHA1?: string,\n     *   ChecksumSHA256?: string,\n     *   Expires?: \\DateTimeImmutable|string,\n     *   GrantFullControl?: string,\n     *   GrantRead?: string,\n     *   GrantReadACP?: string,\n     *   GrantWriteACP?: string,\n     *   Key: string,\n     *   Metadata?: array<string, string>,\n     *   ServerSideEncryption?: ServerSideEncryption::*,\n     *   StorageClass?: StorageClass::*,\n     *   WebsiteRedirectLocation?: string,\n     *   SSECustomerAlgorithm?: string,\n     *   SSECustomerKey?: string,\n     *   SSECustomerKeyMD5?: string,\n     *   SSEKMSKeyId?: string,\n     *   SSEKMSEncryptionContext?: string,\n     *   BucketKeyEnabled?: bool,\n     *   RequestPayer?: RequestPayer::*,\n     *   Tagging?: string,\n     *   ObjectLockMode?: ObjectLockMode::*,\n     *   ObjectLockRetainUntilDate?: \\DateTimeImmutable|string,\n     *   ObjectLockLegalHoldStatus?: ObjectLockLegalHoldStatus::*,\n     *   ExpectedBucketOwner?: string,\n     *\n     *   @region?: string,\n     * }|PutObjectRequest $input\n     */\n    public function putObject($input): PutObjectOutput\n    {\n        $input = PutObjectRequest::create($input);\n        $response = $this->getResponse($input->request(), new RequestContext(['operation' => 'PutObject', 'region' => $input->getRegion()]));\n\n        return new PutObjectOutput($response);\n    }\n\n    /**\n     * Uses the `acl` subresource to set the access control list (ACL) permissions for a new or existing object in an S3\n     * bucket. You must have `WRITE_ACP` permission to set the ACL of an object. For more information, see What permissions\n     * can I grant? [^1] in the *Amazon S3 User Guide*.\n     *\n     * This action is not supported by Amazon S3 on Outposts.\n     *\n     * Depending on your application needs, you can choose to set the ACL on an object using either the request body or the\n     * headers. For example, if you have an existing application that updates a bucket ACL using the request body, you can\n     * continue to use that approach. For more information, see Access Control List (ACL) Overview [^2] in the *Amazon S3\n     * User Guide*.\n     *\n     * ! If your bucket uses the bucket owner enforced setting for S3 Object Ownership, ACLs are disabled and no longer\n     * ! affect permissions. You must use policies to grant access to your bucket and the objects in it. Requests to set\n     * ! ACLs or update ACLs fail and return the `AccessControlListNotSupported` error code. Requests to read ACLs are still\n     * ! supported. For more information, see Controlling object ownership [^3] in the *Amazon S3 User Guide*.\n     *\n     * - `Permissions`:\n     *\n     *   You can set access permissions using one of the following methods:\n     *\n     *   - Specify a canned ACL with the `x-amz-acl` request header. Amazon S3 supports a set of predefined ACLs, known as\n     *     canned ACLs. Each canned ACL has a predefined set of grantees and permissions. Specify the canned ACL name as the\n     *     value of `x-amz-ac`l. If you use this header, you cannot use other access control-specific headers in your\n     *     request. For more information, see Canned ACL [^4].\n     *   - Specify access permissions explicitly with the `x-amz-grant-read`, `x-amz-grant-read-acp`,\n     *     `x-amz-grant-write-acp`, and `x-amz-grant-full-control` headers. When using these headers, you specify explicit\n     *     access permissions and grantees (Amazon Web Services accounts or Amazon S3 groups) who will receive the\n     *     permission. If you use these ACL-specific headers, you cannot use `x-amz-acl` header to set a canned ACL. These\n     *     parameters map to the set of permissions that Amazon S3 supports in an ACL. For more information, see Access\n     *     Control List (ACL) Overview [^5].\n     *\n     *     You specify each grantee as a type=value pair, where the type is one of the following:\n     *\n     *     - `id` – if the value specified is the canonical user ID of an Amazon Web Services account\n     *     - `uri` – if you are granting permissions to a predefined group\n     *     - `emailAddress` – if the value specified is the email address of an Amazon Web Services account\n     *\n     *       > Using email addresses to specify a grantee is only supported in the following Amazon Web Services Regions:\n     *       >\n     *       > - US East (N. Virginia)\n     *       > - US West (N. California)\n     *       > - US West (Oregon)\n     *       > - Asia Pacific (Singapore)\n     *       > - Asia Pacific (Sydney)\n     *       > - Asia Pacific (Tokyo)\n     *       > - Europe (Ireland)\n     *       > - South America (São Paulo)\n     *       >\n     *       > For a list of all the Amazon S3 supported Regions and endpoints, see Regions and Endpoints [^6] in the Amazon\n     *       > Web Services General Reference.\n     *\n     *\n     *     For example, the following `x-amz-grant-read` header grants list objects permission to the two Amazon Web\n     *     Services accounts identified by their email addresses.\n     *\n     *     `x-amz-grant-read: emailAddress=\"xyz@amazon.com\", emailAddress=\"abc@amazon.com\" `\n     *\n     *   You can use either a canned ACL or specify access permissions explicitly. You cannot do both.\n     * - `Grantee Values`:\n     *\n     *   You can specify the person (grantee) to whom you're assigning access rights (using request elements) in the\n     *   following ways:\n     *\n     *   - By the person's ID:\n     *\n     *     `<Grantee xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n     *     xsi:type=\"CanonicalUser\"><ID><>ID<></ID><DisplayName><>GranteesEmail<></DisplayName>\n     *     </Grantee>`\n     *\n     *     DisplayName is optional and ignored in the request.\n     *   - By URI:\n     *\n     *     `<Grantee xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n     *     xsi:type=\"Group\"><URI><>http://acs.amazonaws.com/groups/global/AuthenticatedUsers<></URI></Grantee>`\n     *   - By Email address:\n     *\n     *     `<Grantee xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n     *     xsi:type=\"AmazonCustomerByEmail\"><EmailAddress><>Grantees@email.com<></EmailAddress>lt;/Grantee>`\n     *\n     *     The grantee is resolved to the CanonicalUser and, in a response to a GET Object acl request, appears as the\n     *     CanonicalUser.\n     *\n     *     > Using email addresses to specify a grantee is only supported in the following Amazon Web Services Regions:\n     *     >\n     *     > - US East (N. Virginia)\n     *     > - US West (N. California)\n     *     > - US West (Oregon)\n     *     > - Asia Pacific (Singapore)\n     *     > - Asia Pacific (Sydney)\n     *     > - Asia Pacific (Tokyo)\n     *     > - Europe (Ireland)\n     *     > - South America (São Paulo)\n     *     >\n     *     > For a list of all the Amazon S3 supported Regions and endpoints, see Regions and Endpoints [^7] in the Amazon\n     *     > Web Services General Reference.\n     *\n     *\n     * - `Versioning`:\n     *\n     *   The ACL of an object is set at the object version level. By default, PUT sets the ACL of the current version of an\n     *   object. To set the ACL of a different version, use the `versionId` subresource.\n     *\n     * The following operations are related to `PutObjectAcl`:\n     *\n     * - CopyObject [^8]\n     * - GetObject [^9]\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#permissions\n     * [^2]: https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html\n     * [^3]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/about-object-ownership.html\n     * [^4]: https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#CannedACL\n     * [^5]: https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html\n     * [^6]: https://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region\n     * [^7]: https://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region\n     * [^8]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_CopyObject.html\n     * [^9]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html\n     *\n     * @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTObjectPUTacl.html\n     * @see https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObjectAcl.html\n     * @see https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-s3-2006-03-01.html#putobjectacl\n     *\n     * @param array{\n     *   ACL?: ObjectCannedACL::*,\n     *   AccessControlPolicy?: AccessControlPolicy|array,\n     *   Bucket: string,\n     *   ContentMD5?: string,\n     *   ChecksumAlgorithm?: ChecksumAlgorithm::*,\n     *   GrantFullControl?: string,\n     *   GrantRead?: string,\n     *   GrantReadACP?: string,\n     *   GrantWrite?: string,\n     *   GrantWriteACP?: string,\n     *   Key: string,\n     *   RequestPayer?: RequestPayer::*,\n     *   VersionId?: string,\n     *   ExpectedBucketOwner?: string,\n     *\n     *   @region?: string,\n     * }|PutObjectAclRequest $input\n     *\n     * @throws NoSuchKeyException\n     */\n    public function putObjectAcl($input): PutObjectAclOutput\n    {\n        $input = PutObjectAclRequest::create($input);\n        $response = $this->getResponse($input->request(), new RequestContext(['operation' => 'PutObjectAcl', 'region' => $input->getRegion(), 'exceptionMapping' => [\n            'NoSuchKey' => NoSuchKeyException::class,\n        ]]));\n\n        return new PutObjectAclOutput($response);\n    }\n\n    /**\n     * Uploads a part in a multipart upload.\n     *\n     * > In this operation, you provide part data in your request. However, you have an option to specify your existing\n     * > Amazon S3 object as a data source for the part you are uploading. To upload a part from an existing object, you use\n     * > the UploadPartCopy [^1] operation.\n     *\n     * You must initiate a multipart upload (see CreateMultipartUpload [^2]) before you can upload any part. In response to\n     * your initiate request, Amazon S3 returns an upload ID, a unique identifier, that you must include in your upload part\n     * request.\n     *\n     * Part numbers can be any number from 1 to 10,000, inclusive. A part number uniquely identifies a part and also defines\n     * its position within the object being created. If you upload a new part using the same part number that was used with\n     * a previous part, the previously uploaded part is overwritten.\n     *\n     * For information about maximum and minimum part sizes and other multipart upload specifications, see Multipart upload\n     * limits [^3] in the *Amazon S3 User Guide*.\n     *\n     * To ensure that data is not corrupted when traversing the network, specify the `Content-MD5` header in the upload part\n     * request. Amazon S3 checks the part data against the provided MD5 value. If they do not match, Amazon S3 returns an\n     * error.\n     *\n     * If the upload request is signed with Signature Version 4, then Amazon Web Services S3 uses the `x-amz-content-sha256`\n     * header as a checksum instead of `Content-MD5`. For more information see Authenticating Requests: Using the\n     * Authorization Header (Amazon Web Services Signature Version 4) [^4].\n     *\n     * **Note:** After you initiate multipart upload and upload one or more parts, you must either complete or abort\n     * multipart upload in order to stop getting charged for storage of the uploaded parts. Only after you either complete\n     * or abort multipart upload, Amazon S3 frees up the parts storage and stops charging you for the parts storage.\n     *\n     * For more information on multipart uploads, go to Multipart Upload Overview [^5] in the *Amazon S3 User Guide *.\n     *\n     * For information on the permissions required to use the multipart upload API, go to Multipart Upload and Permissions\n     * [^6] in the *Amazon S3 User Guide*.\n     *\n     * Server-side encryption is for data encryption at rest. Amazon S3 encrypts your data as it writes it to disks in its\n     * data centers and decrypts it when you access it. You have three mutually exclusive options to protect data using\n     * server-side encryption in Amazon S3, depending on how you choose to manage the encryption keys. Specifically, the\n     * encryption key options are Amazon S3 managed keys (SSE-S3), Amazon Web Services KMS keys (SSE-KMS), and\n     * Customer-Provided Keys (SSE-C). Amazon S3 encrypts data with server-side encryption using Amazon S3 managed keys\n     * (SSE-S3) by default. You can optionally tell Amazon S3 to encrypt data at rest using server-side encryption with\n     * other key options. The option you use depends on whether you want to use KMS keys (SSE-KMS) or provide your own\n     * encryption key (SSE-C). If you choose to provide your own encryption key, the request headers you provide in the\n     * request must match the headers you used in the request to initiate the upload by using CreateMultipartUpload [^7].\n     * For more information, go to Using Server-Side Encryption [^8] in the *Amazon S3 User Guide*.\n     *\n     * Server-side encryption is supported by the S3 Multipart Upload actions. Unless you are using a customer-provided\n     * encryption key (SSE-C), you don't need to specify the encryption parameters in each UploadPart request. Instead, you\n     * only need to specify the server-side encryption parameters in the initial Initiate Multipart request. For more\n     * information, see CreateMultipartUpload [^9].\n     *\n     * If you requested server-side encryption using a customer-provided encryption key (SSE-C) in your initiate multipart\n     * upload request, you must provide identical encryption information in each part upload using the following headers.\n     *\n     * - x-amz-server-side-encryption-customer-algorithm\n     * - x-amz-server-side-encryption-customer-key\n     * - x-amz-server-side-encryption-customer-key-MD5\n     *\n     * `UploadPart` has the following special errors:\n     *\n     * - - *Code: NoSuchUpload*\n     * - - *Cause: The specified multipart upload does not exist. The upload ID might be invalid, or the multipart upload\n     * -   might have been aborted or completed.*\n     * - - * HTTP Status Code: 404 Not Found *\n     * - - *SOAP Fault Code Prefix: Client*\n     * -\n     *\n     * The following operations are related to `UploadPart`:\n     *\n     * - CreateMultipartUpload [^10]\n     * - CompleteMultipartUpload [^11]\n     * - AbortMultipartUpload [^12]\n     * - ListParts [^13]\n     * - ListMultipartUploads [^14]\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPartCopy.html\n     * [^2]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateMultipartUpload.html\n     * [^3]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/qfacts.html\n     * [^4]: https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-auth-using-authorization-header.html\n     * [^5]: https://docs.aws.amazon.com/AmazonS3/latest/dev/mpuoverview.html\n     * [^6]: https://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html\n     * [^7]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateMultipartUpload.html\n     * [^8]: https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingServerSideEncryption.html\n     * [^9]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateMultipartUpload.html\n     * [^10]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateMultipartUpload.html\n     * [^11]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_CompleteMultipartUpload.html\n     * [^12]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_AbortMultipartUpload.html\n     * [^13]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListParts.html\n     * [^14]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListMultipartUploads.html\n     *\n     * @see http://docs.amazonwebservices.com/AmazonS3/latest/API/mpUploadUploadPart.html\n     * @see https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPart.html\n     * @see https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-s3-2006-03-01.html#uploadpart\n     *\n     * @param array{\n     *   Body?: string|resource|callable|iterable,\n     *   Bucket: string,\n     *   ContentLength?: string,\n     *   ContentMD5?: string,\n     *   ChecksumAlgorithm?: ChecksumAlgorithm::*,\n     *   ChecksumCRC32?: string,\n     *   ChecksumCRC32C?: string,\n     *   ChecksumSHA1?: string,\n     *   ChecksumSHA256?: string,\n     *   Key: string,\n     *   PartNumber: int,\n     *   UploadId: string,\n     *   SSECustomerAlgorithm?: string,\n     *   SSECustomerKey?: string,\n     *   SSECustomerKeyMD5?: string,\n     *   RequestPayer?: RequestPayer::*,\n     *   ExpectedBucketOwner?: string,\n     *\n     *   @region?: string,\n     * }|UploadPartRequest $input\n     */\n    public function uploadPart($input): UploadPartOutput\n    {\n        $input = UploadPartRequest::create($input);\n        $response = $this->getResponse($input->request(), new RequestContext(['operation' => 'UploadPart', 'region' => $input->getRegion()]));\n\n        return new UploadPartOutput($response);\n    }\n\n    protected function getAwsErrorFactory(): AwsErrorFactoryInterface\n    {\n        return new XmlAwsErrorFactory();\n    }\n\n    protected function getEndpoint(string $uri, array $query, ?string $region): string\n    {\n        $uriParts = explode('/', $uri, 3);\n        $bucket = explode('?', $uriParts[1] ?? '', 2)[0];\n        $uriWithOutBucket = substr($uriParts[1] ?? '', \\strlen($bucket)) . ($uriParts[2] ?? '');\n        $bucketLen = \\strlen($bucket);\n        $configuration = $this->getConfiguration();\n\n        if (\n            $bucketLen < 3 || $bucketLen > 63\n            || filter_var($bucket, \\FILTER_VALIDATE_IP) // Cannot look like an IP address\n            || !preg_match('/^[a-z0-9]([a-z0-9\\-]*[a-z0-9])?$/', $bucket) // Bucket cannot have dot (because of TLS)\n            || filter_var(parse_url($configuration->get('endpoint'), \\PHP_URL_HOST), \\FILTER_VALIDATE_IP) // Custom endpoint cannot look like an IP address @phpstan-ignore-line\n            || filter_var($configuration->get('pathStyleEndpoint'), \\FILTER_VALIDATE_BOOLEAN)\n        ) {\n            return parent::getEndpoint($uri, $query, $region);\n        }\n\n        return preg_replace('|https?://|', '${0}' . $bucket . '.', parent::getEndpoint('/' . $uriWithOutBucket, $query, $region));\n    }\n\n    protected function getEndpointMetadata(?string $region): array\n    {\n        if (null === $region) {\n            return [\n                'endpoint' => 'https://s3.amazonaws.com',\n                'signRegion' => 'us-east-1',\n                'signService' => 's3',\n                'signVersions' => ['s3v4'],\n            ];\n        }\n\n        switch ($region) {\n            case 'af-south-1':\n            case 'ap-east-1':\n            case 'ap-northeast-1':\n            case 'ap-northeast-2':\n            case 'ap-northeast-3':\n            case 'ap-south-1':\n            case 'ap-south-2':\n            case 'ap-southeast-1':\n            case 'ap-southeast-2':\n            case 'ap-southeast-3':\n            case 'ap-southeast-4':\n            case 'ca-central-1':\n            case 'eu-central-1':\n            case 'eu-central-2':\n            case 'eu-north-1':\n            case 'eu-south-1':\n            case 'eu-south-2':\n            case 'eu-west-1':\n            case 'eu-west-2':\n            case 'eu-west-3':\n            case 'me-central-1':\n            case 'me-south-1':\n            case 'sa-east-1':\n            case 'us-east-1':\n            case 'us-east-2':\n            case 'us-gov-east-1':\n            case 'us-gov-west-1':\n            case 'us-west-1':\n            case 'us-west-2':\n                return [\n                    'endpoint' => \"https://s3.$region.amazonaws.com\",\n                    'signRegion' => $region,\n                    'signService' => 's3',\n                    'signVersions' => ['s3v4'],\n                ];\n            case 'cn-north-1':\n            case 'cn-northwest-1':\n                return [\n                    'endpoint' => \"https://s3.$region.amazonaws.com.cn\",\n                    'signRegion' => $region,\n                    'signService' => 's3',\n                    'signVersions' => ['s3v4'],\n                ];\n            case 's3-external-1':\n                return [\n                    'endpoint' => 'https://s3-external-1.amazonaws.com',\n                    'signRegion' => 'us-east-1',\n                    'signService' => 's3',\n                    'signVersions' => ['s3v4'],\n                ];\n            case 'fips-ca-central-1':\n                return [\n                    'endpoint' => 'https://s3-fips.ca-central-1.amazonaws.com',\n                    'signRegion' => 'ca-central-1',\n                    'signService' => 's3',\n                    'signVersions' => ['s3v4'],\n                ];\n            case 'fips-us-east-1':\n                return [\n                    'endpoint' => 'https://s3-fips.us-east-1.amazonaws.com',\n                    'signRegion' => 'us-east-1',\n                    'signService' => 's3',\n                    'signVersions' => ['s3v4'],\n                ];\n            case 'fips-us-east-2':\n                return [\n                    'endpoint' => 'https://s3-fips.us-east-2.amazonaws.com',\n                    'signRegion' => 'us-east-2',\n                    'signService' => 's3',\n                    'signVersions' => ['s3v4'],\n                ];\n            case 'fips-us-west-1':\n                return [\n                    'endpoint' => 'https://s3-fips.us-west-1.amazonaws.com',\n                    'signRegion' => 'us-west-1',\n                    'signService' => 's3',\n                    'signVersions' => ['s3v4'],\n                ];\n            case 'fips-us-west-2':\n                return [\n                    'endpoint' => 'https://s3-fips.us-west-2.amazonaws.com',\n                    'signRegion' => 'us-west-2',\n                    'signService' => 's3',\n                    'signVersions' => ['s3v4'],\n                ];\n            case 'fips-us-gov-east-1':\n                return [\n                    'endpoint' => 'https://s3-fips.us-gov-east-1.amazonaws.com',\n                    'signRegion' => 'us-gov-east-1',\n                    'signService' => 's3',\n                    'signVersions' => ['s3v4'],\n                ];\n            case 'fips-us-gov-west-1':\n                return [\n                    'endpoint' => 'https://s3-fips.us-gov-west-1.amazonaws.com',\n                    'signRegion' => 'us-gov-west-1',\n                    'signService' => 's3',\n                    'signVersions' => ['s3v4'],\n                ];\n            case 'us-iso-east-1':\n            case 'us-iso-west-1':\n                return [\n                    'endpoint' => \"https://s3.$region.c2s.ic.gov\",\n                    'signRegion' => $region,\n                    'signService' => 's3',\n                    'signVersions' => ['s3v4'],\n                ];\n            case 'us-isob-east-1':\n                return [\n                    'endpoint' => 'https://s3.us-isob-east-1.sc2s.sgov.gov',\n                    'signRegion' => 'us-isob-east-1',\n                    'signService' => 's3',\n                    'signVersions' => ['s3v4'],\n                ];\n        }\n\n        return [\n            'endpoint' => 'https://s3.amazonaws.com',\n            'signRegion' => 'us-east-1',\n            'signService' => 's3',\n            'signVersions' => ['s3v4'],\n        ];\n    }\n\n    protected function getServiceCode(): string\n    {\n        @trigger_error('Using the client with an old version of Core is deprecated. Run \"composer update async-aws/core\".', \\E_USER_DEPRECATED);\n\n        return 's3';\n    }\n\n    protected function getSignatureScopeName(): string\n    {\n        @trigger_error('Using the client with an old version of Core is deprecated. Run \"composer update async-aws/core\".', \\E_USER_DEPRECATED);\n\n        return 's3';\n    }\n\n    protected function getSignatureVersion(): string\n    {\n        @trigger_error('Using the client with an old version of Core is deprecated. Run \"composer update async-aws/core\".', \\E_USER_DEPRECATED);\n\n        return 's3v4';\n    }\n\n    /**\n     * @return callable[]\n     */\n    protected function getSignerFactories(): array\n    {\n        return [\n            's3v4' => function (string $service, string $region) {\n                $configuration = $this->getConfiguration();\n                $options = [];\n\n                // We need async-aws/core: 1.8 or above to use sendChunkedBody.\n                if (Configuration::optionExists('sendChunkedBody')) {\n                    $options['sendChunkedBody'] = filter_var($configuration->get('sendChunkedBody'), \\FILTER_VALIDATE_BOOLEAN);\n                }\n\n                return new SignerV4ForS3($service, $region, $options);\n            },\n        ] + parent::getSignerFactories();\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/Signer/SignerV4ForS3.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\Signer;\n\nuse AsyncAws\\Core\\Configuration;\nuse AsyncAws\\Core\\Credentials\\Credentials;\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\nuse AsyncAws\\Core\\Request;\nuse AsyncAws\\Core\\RequestContext;\nuse AsyncAws\\Core\\Signer\\SignerV4;\nuse AsyncAws\\Core\\Signer\\SigningContext;\nuse AsyncAws\\Core\\Stream\\FixedSizeStream;\nuse AsyncAws\\Core\\Stream\\IterableStream;\nuse AsyncAws\\Core\\Stream\\ReadOnceResultStream;\nuse AsyncAws\\Core\\Stream\\RequestStream;\nuse AsyncAws\\Core\\Stream\\RewindableStream;\n\n/**\n * Version4 of signer dedicated for service S3.\n *\n * @author Jérémy Derussé <jeremy@derusse.com>\n */\nclass SignerV4ForS3 extends SignerV4\n{\n    private const ALGORITHM_CHUNK = 'AWS4-HMAC-SHA256-PAYLOAD';\n    private const CHUNK_SIZE = 64 * 1024;\n\n    private const MD5_OPERATIONS = [\n        'DeleteObjects' => true,\n        'PutBucketCors' => true,\n        'PutBucketLifecycle' => true,\n        'PutBucketLifecycleConfiguration' => true,\n        'PutBucketPolicy' => true,\n        'PutBucketTagging' => true,\n        'PutBucketReplication' => true,\n        'PutObjectLegalHold' => true,\n        'PutObjectRetention' => true,\n        'PutObjectLockConfiguration' => true,\n    ];\n\n    private $sendChunkedBody;\n\n    /**\n     * @param array{\n     *   sendChunkedBody?: bool,\n     * } $s3SignerOptions\n     */\n    public function __construct(string $scopeName, string $region, array $s3SignerOptions = [])\n    {\n        parent::__construct($scopeName, $region);\n\n        $this->sendChunkedBody = $s3SignerOptions[Configuration::OPTION_SEND_CHUNKED_BODY] ?? false;\n        unset($s3SignerOptions[Configuration::OPTION_SEND_CHUNKED_BODY]);\n\n        if (!empty($s3SignerOptions)) {\n            throw new InvalidArgument(sprintf('Invalid option(s) \"%s\" passed to \"%s::%s\". ', implode('\", \"', array_keys($s3SignerOptions)), __CLASS__, __METHOD__));\n        }\n    }\n\n    public function sign(Request $request, Credentials $credentials, RequestContext $context): void\n    {\n        if ((null === ($operation = $context->getOperation()) || isset(self::MD5_OPERATIONS[$operation])) && !$request->hasHeader('content-md5')) {\n            $request->setHeader('content-md5', base64_encode($request->getBody()->hash('md5', true)));\n        }\n\n        if (!$request->hasHeader('x-amz-content-sha256')) {\n            $request->setHeader('x-amz-content-sha256', $request->getBody()->hash());\n        }\n\n        parent::sign($request, $credentials, $context);\n    }\n\n    protected function buildBodyDigest(Request $request, bool $isPresign): string\n    {\n        if ($isPresign) {\n            $request->setHeader('x-amz-content-sha256', 'UNSIGNED-PAYLOAD');\n\n            return 'UNSIGNED-PAYLOAD';\n        }\n\n        return parent::buildBodyDigest($request, $isPresign);\n    }\n\n    /**\n     * Amazon S3 does not double-encode the path component in the canonical request.\n     */\n    protected function buildCanonicalPath(Request $request): string\n    {\n        return '/' . ltrim($request->getUri(), '/');\n    }\n\n    protected function convertBodyToStream(SigningContext $context): void\n    {\n        $request = $context->getRequest();\n        $body = $request->getBody();\n        if ($request->hasHeader('content-length')) {\n            $contentLength = (int) $request->getHeader('content-length');\n        } else {\n            $contentLength = $body->length();\n        }\n\n        // If content length is unknown, use the rewindable stream to read it once locally in order to get the length\n        if (null === $contentLength) {\n            $request->setBody($body = RewindableStream::create($body));\n            $body->read();\n            $contentLength = $body->length();\n        }\n\n        // no need to stream small body. It's simple to convert it to string directly\n        if ($contentLength < self::CHUNK_SIZE || !$this->sendChunkedBody) {\n            if ($body instanceof ReadOnceResultStream) {\n                $request->setBody(RewindableStream::create($body));\n            }\n\n            return;\n        }\n\n        // Add content-encoding for chunked stream if available\n        $customEncoding = $request->getHeader('content-encoding');\n\n        // Convert the body into a chunked stream\n        $request->setHeader('content-encoding', $customEncoding ? \"aws-chunked, $customEncoding\" : 'aws-chunked');\n        $request->setHeader('x-amz-decoded-content-length', (string) $contentLength);\n        $request->setHeader('x-amz-content-sha256', 'STREAMING-' . self::ALGORITHM_CHUNK);\n\n        // Compute size of content + metadata used sign each Chunk\n        $chunkCount = (int) ceil($contentLength / self::CHUNK_SIZE);\n        $fullChunkCount = $chunkCount * self::CHUNK_SIZE === $contentLength ? $chunkCount : ($chunkCount - 1);\n        $metaLength = \\strlen(\";chunk-signature=\\r\\n\\r\\n\") + 64;\n        $request->setHeader('content-length', (string) ($contentLength + $fullChunkCount * ($metaLength + \\strlen(dechex(self::CHUNK_SIZE))) + ($chunkCount - $fullChunkCount) * ($metaLength + \\strlen(dechex($contentLength % self::CHUNK_SIZE))) + $metaLength + 1));\n        $body = RewindableStream::create(IterableStream::create((function (RequestStream $body) use ($context): iterable {\n            $now = $context->getNow();\n            $credentialString = $context->getCredentialString();\n            $signingKey = $context->getSigningKey();\n            $signature = $context->getSignature();\n            foreach (FixedSizeStream::create($body, self::CHUNK_SIZE) as $chunk) {\n                $stringToSign = $this->buildChunkStringToSign($now, $credentialString, $signature, $chunk);\n                $context->setSignature($signature = $this->buildSignature($stringToSign, $signingKey));\n                yield sprintf(\"%s;chunk-signature=%s\\r\\n\", dechex(\\strlen($chunk)), $signature) . \"$chunk\\r\\n\";\n            }\n\n            $stringToSign = $this->buildChunkStringToSign($now, $credentialString, $signature, '');\n            $context->setSignature($signature = $this->buildSignature($stringToSign, $signingKey));\n\n            yield sprintf(\"%s;chunk-signature=%s\\r\\n\\r\\n\", dechex(0), $signature);\n        })($body)));\n\n        $request->setBody($body);\n    }\n\n    private function buildChunkStringToSign(\\DateTimeImmutable $now, string $credentialString, string $signature, string $chunk): string\n    {\n        static $emptyHash;\n        $emptyHash = $emptyHash ?? hash('sha256', '');\n\n        return implode(\"\\n\", [\n            self::ALGORITHM_CHUNK,\n            $now->format('Ymd\\THis\\Z'),\n            $credentialString,\n            $signature,\n            $emptyHash,\n            hash('sha256', $chunk),\n        ]);\n    }\n\n    private function buildSignature(string $stringToSign, string $signingKey): string\n    {\n        return hash_hmac('sha256', $stringToSign, $signingKey);\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/ValueObject/AccessControlPolicy.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\ValueObject;\n\n/**\n * Contains the elements that set the ACL permissions for an object per grantee.\n */\nfinal class AccessControlPolicy\n{\n    /**\n     * A list of grants.\n     */\n    private $grants;\n\n    /**\n     * Container for the bucket owner's display name and ID.\n     */\n    private $owner;\n\n    /**\n     * @param array{\n     *   Grants?: null|Grant[],\n     *   Owner?: null|Owner|array,\n     * } $input\n     */\n    public function __construct(array $input)\n    {\n        $this->grants = isset($input['Grants']) ? array_map([Grant::class, 'create'], $input['Grants']) : null;\n        $this->owner = isset($input['Owner']) ? Owner::create($input['Owner']) : null;\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    /**\n     * @return Grant[]\n     */\n    public function getGrants(): array\n    {\n        return $this->grants ?? [];\n    }\n\n    public function getOwner(): ?Owner\n    {\n        return $this->owner;\n    }\n\n    /**\n     * @internal\n     */\n    public function requestBody(\\DOMElement $node, \\DOMDocument $document): void\n    {\n        if (null !== $v = $this->grants) {\n            $node->appendChild($nodeList = $document->createElement('AccessControlList'));\n            foreach ($v as $item) {\n                $nodeList->appendChild($child = $document->createElement('Grant'));\n\n                $item->requestBody($child, $document);\n            }\n        }\n        if (null !== $v = $this->owner) {\n            $node->appendChild($child = $document->createElement('Owner'));\n\n            $v->requestBody($child, $document);\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/ValueObject/AwsObject.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\ValueObject;\n\nuse AsyncAws\\S3\\Enum\\ChecksumAlgorithm;\nuse AsyncAws\\S3\\Enum\\ObjectStorageClass;\n\n/**\n * An object consists of data and its descriptive metadata.\n */\nfinal class AwsObject\n{\n    /**\n     * The name that you assign to an object. You use the object key to retrieve the object.\n     */\n    private $key;\n\n    /**\n     * Creation date of the object.\n     */\n    private $lastModified;\n\n    /**\n     * The entity tag is a hash of the object. The ETag reflects changes only to the contents of an object, not its\n     * metadata. The ETag may or may not be an MD5 digest of the object data. Whether or not it is depends on how the object\n     * was created and how it is encrypted as described below:.\n     *\n     * - Objects created by the PUT Object, POST Object, or Copy operation, or through the Amazon Web Services Management\n     *   Console, and are encrypted by SSE-S3 or plaintext, have ETags that are an MD5 digest of their object data.\n     * - Objects created by the PUT Object, POST Object, or Copy operation, or through the Amazon Web Services Management\n     *   Console, and are encrypted by SSE-C or SSE-KMS, have ETags that are not an MD5 digest of their object data.\n     * - If an object is created by either the Multipart Upload or Part Copy operation, the ETag is not an MD5 digest,\n     *   regardless of the method of encryption. If an object is larger than 16 MB, the Amazon Web Services Management\n     *   Console will upload or copy that object as a Multipart Upload, and therefore the ETag will not be an MD5 digest.\n     */\n    private $etag;\n\n    /**\n     * The algorithm that was used to create a checksum of the object.\n     */\n    private $checksumAlgorithm;\n\n    /**\n     * Size in bytes of the object.\n     */\n    private $size;\n\n    /**\n     * The class of storage used to store the object.\n     */\n    private $storageClass;\n\n    /**\n     * The owner of the object.\n     */\n    private $owner;\n\n    /**\n     * @param array{\n     *   Key?: null|string,\n     *   LastModified?: null|\\DateTimeImmutable,\n     *   ETag?: null|string,\n     *   ChecksumAlgorithm?: null|list<ChecksumAlgorithm::*>,\n     *   Size?: null|string,\n     *   StorageClass?: null|ObjectStorageClass::*,\n     *   Owner?: null|Owner|array,\n     * } $input\n     */\n    public function __construct(array $input)\n    {\n        $this->key = $input['Key'] ?? null;\n        $this->lastModified = $input['LastModified'] ?? null;\n        $this->etag = $input['ETag'] ?? null;\n        $this->checksumAlgorithm = $input['ChecksumAlgorithm'] ?? null;\n        $this->size = $input['Size'] ?? null;\n        $this->storageClass = $input['StorageClass'] ?? null;\n        $this->owner = isset($input['Owner']) ? Owner::create($input['Owner']) : null;\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    /**\n     * @return list<ChecksumAlgorithm::*>\n     */\n    public function getChecksumAlgorithm(): array\n    {\n        return $this->checksumAlgorithm ?? [];\n    }\n\n    public function getEtag(): ?string\n    {\n        return $this->etag;\n    }\n\n    public function getKey(): ?string\n    {\n        return $this->key;\n    }\n\n    public function getLastModified(): ?\\DateTimeImmutable\n    {\n        return $this->lastModified;\n    }\n\n    public function getOwner(): ?Owner\n    {\n        return $this->owner;\n    }\n\n    public function getSize(): ?string\n    {\n        return $this->size;\n    }\n\n    /**\n     * @return ObjectStorageClass::*|null\n     */\n    public function getStorageClass(): ?string\n    {\n        return $this->storageClass;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/ValueObject/Bucket.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\ValueObject;\n\n/**\n * In terms of implementation, a Bucket is a resource. An Amazon S3 bucket name is globally unique, and the namespace is\n * shared by all Amazon Web Services accounts.\n */\nfinal class Bucket\n{\n    /**\n     * The name of the bucket.\n     */\n    private $name;\n\n    /**\n     * Date the bucket was created. This date can change when making changes to your bucket, such as editing its bucket\n     * policy.\n     */\n    private $creationDate;\n\n    /**\n     * @param array{\n     *   Name?: null|string,\n     *   CreationDate?: null|\\DateTimeImmutable,\n     * } $input\n     */\n    public function __construct(array $input)\n    {\n        $this->name = $input['Name'] ?? null;\n        $this->creationDate = $input['CreationDate'] ?? null;\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    public function getCreationDate(): ?\\DateTimeImmutable\n    {\n        return $this->creationDate;\n    }\n\n    public function getName(): ?string\n    {\n        return $this->name;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/ValueObject/CORSConfiguration.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\ValueObject;\n\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\n\n/**\n * Describes the cross-origin access configuration for objects in an Amazon S3 bucket. For more information, see\n * Enabling Cross-Origin Resource Sharing [^1] in the *Amazon S3 User Guide*.\n *\n * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/dev/cors.html\n */\nfinal class CORSConfiguration\n{\n    /**\n     * A set of origins and methods (cross-origin access that you want to allow). You can add up to 100 rules to the\n     * configuration.\n     */\n    private $corsRules;\n\n    /**\n     * @param array{\n     *   CORSRules: CORSRule[],\n     * } $input\n     */\n    public function __construct(array $input)\n    {\n        $this->corsRules = isset($input['CORSRules']) ? array_map([CORSRule::class, 'create'], $input['CORSRules']) : null;\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    /**\n     * @return CORSRule[]\n     */\n    public function getCorsRules(): array\n    {\n        return $this->corsRules ?? [];\n    }\n\n    /**\n     * @internal\n     */\n    public function requestBody(\\DOMElement $node, \\DOMDocument $document): void\n    {\n        if (null === $v = $this->corsRules) {\n            throw new InvalidArgument(sprintf('Missing parameter \"CORSRules\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        foreach ($v as $item) {\n            $node->appendChild($child = $document->createElement('CORSRule'));\n\n            $item->requestBody($child, $document);\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/ValueObject/CORSRule.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\ValueObject;\n\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\n\n/**\n * Specifies a cross-origin access rule for an Amazon S3 bucket.\n */\nfinal class CORSRule\n{\n    /**\n     * Unique identifier for the rule. The value cannot be longer than 255 characters.\n     */\n    private $id;\n\n    /**\n     * Headers that are specified in the `Access-Control-Request-Headers` header. These headers are allowed in a preflight\n     * OPTIONS request. In response to any preflight OPTIONS request, Amazon S3 returns any requested headers that are\n     * allowed.\n     */\n    private $allowedHeaders;\n\n    /**\n     * An HTTP method that you allow the origin to execute. Valid values are `GET`, `PUT`, `HEAD`, `POST`, and `DELETE`.\n     */\n    private $allowedMethods;\n\n    /**\n     * One or more origins you want customers to be able to access the bucket from.\n     */\n    private $allowedOrigins;\n\n    /**\n     * One or more headers in the response that you want customers to be able to access from their applications (for\n     * example, from a JavaScript `XMLHttpRequest` object).\n     */\n    private $exposeHeaders;\n\n    /**\n     * The time in seconds that your browser is to cache the preflight response for the specified resource.\n     */\n    private $maxAgeSeconds;\n\n    /**\n     * @param array{\n     *   ID?: null|string,\n     *   AllowedHeaders?: null|string[],\n     *   AllowedMethods: string[],\n     *   AllowedOrigins: string[],\n     *   ExposeHeaders?: null|string[],\n     *   MaxAgeSeconds?: null|int,\n     * } $input\n     */\n    public function __construct(array $input)\n    {\n        $this->id = $input['ID'] ?? null;\n        $this->allowedHeaders = $input['AllowedHeaders'] ?? null;\n        $this->allowedMethods = $input['AllowedMethods'] ?? null;\n        $this->allowedOrigins = $input['AllowedOrigins'] ?? null;\n        $this->exposeHeaders = $input['ExposeHeaders'] ?? null;\n        $this->maxAgeSeconds = $input['MaxAgeSeconds'] ?? null;\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    /**\n     * @return string[]\n     */\n    public function getAllowedHeaders(): array\n    {\n        return $this->allowedHeaders ?? [];\n    }\n\n    /**\n     * @return string[]\n     */\n    public function getAllowedMethods(): array\n    {\n        return $this->allowedMethods ?? [];\n    }\n\n    /**\n     * @return string[]\n     */\n    public function getAllowedOrigins(): array\n    {\n        return $this->allowedOrigins ?? [];\n    }\n\n    /**\n     * @return string[]\n     */\n    public function getExposeHeaders(): array\n    {\n        return $this->exposeHeaders ?? [];\n    }\n\n    public function getId(): ?string\n    {\n        return $this->id;\n    }\n\n    public function getMaxAgeSeconds(): ?int\n    {\n        return $this->maxAgeSeconds;\n    }\n\n    /**\n     * @internal\n     */\n    public function requestBody(\\DOMElement $node, \\DOMDocument $document): void\n    {\n        if (null !== $v = $this->id) {\n            $node->appendChild($document->createElement('ID', $v));\n        }\n        if (null !== $v = $this->allowedHeaders) {\n            foreach ($v as $item) {\n                $node->appendChild($document->createElement('AllowedHeader', $item));\n            }\n        }\n        if (null === $v = $this->allowedMethods) {\n            throw new InvalidArgument(sprintf('Missing parameter \"AllowedMethods\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        foreach ($v as $item) {\n            $node->appendChild($document->createElement('AllowedMethod', $item));\n        }\n\n        if (null === $v = $this->allowedOrigins) {\n            throw new InvalidArgument(sprintf('Missing parameter \"AllowedOrigins\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        foreach ($v as $item) {\n            $node->appendChild($document->createElement('AllowedOrigin', $item));\n        }\n\n        if (null !== $v = $this->exposeHeaders) {\n            foreach ($v as $item) {\n                $node->appendChild($document->createElement('ExposeHeader', $item));\n            }\n        }\n        if (null !== $v = $this->maxAgeSeconds) {\n            $node->appendChild($document->createElement('MaxAgeSeconds', $v));\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/ValueObject/CommonPrefix.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\ValueObject;\n\n/**\n * Container for all (if there are any) keys between Prefix and the next occurrence of the string specified by a\n * delimiter. CommonPrefixes lists keys that act like subdirectories in the directory specified by Prefix. For example,\n * if the prefix is notes/ and the delimiter is a slash (/) as in notes/summer/july, the common prefix is notes/summer/.\n */\nfinal class CommonPrefix\n{\n    /**\n     * Container for the specified common prefix.\n     */\n    private $prefix;\n\n    /**\n     * @param array{\n     *   Prefix?: null|string,\n     * } $input\n     */\n    public function __construct(array $input)\n    {\n        $this->prefix = $input['Prefix'] ?? null;\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    public function getPrefix(): ?string\n    {\n        return $this->prefix;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/ValueObject/CompletedMultipartUpload.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\ValueObject;\n\n/**\n * The container for the completed multipart upload details.\n */\nfinal class CompletedMultipartUpload\n{\n    /**\n     * Array of CompletedPart data types.\n     *\n     * If you do not supply a valid `Part` with your request, the service sends back an HTTP 400 response.\n     */\n    private $parts;\n\n    /**\n     * @param array{\n     *   Parts?: null|CompletedPart[],\n     * } $input\n     */\n    public function __construct(array $input)\n    {\n        $this->parts = isset($input['Parts']) ? array_map([CompletedPart::class, 'create'], $input['Parts']) : null;\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    /**\n     * @return CompletedPart[]\n     */\n    public function getParts(): array\n    {\n        return $this->parts ?? [];\n    }\n\n    /**\n     * @internal\n     */\n    public function requestBody(\\DOMElement $node, \\DOMDocument $document): void\n    {\n        if (null !== $v = $this->parts) {\n            foreach ($v as $item) {\n                $node->appendChild($child = $document->createElement('Part'));\n\n                $item->requestBody($child, $document);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/ValueObject/CompletedPart.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\ValueObject;\n\n/**\n * Details of the parts that were uploaded.\n */\nfinal class CompletedPart\n{\n    /**\n     * Entity tag returned when the part was uploaded.\n     */\n    private $etag;\n\n    /**\n     * The base64-encoded, 32-bit CRC32 checksum of the object. This will only be present if it was uploaded with the\n     * object. With multipart uploads, this may not be a checksum value of the object. For more information about how\n     * checksums are calculated with multipart uploads, see  Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums\n     */\n    private $checksumCrc32;\n\n    /**\n     * The base64-encoded, 32-bit CRC32C checksum of the object. This will only be present if it was uploaded with the\n     * object. With multipart uploads, this may not be a checksum value of the object. For more information about how\n     * checksums are calculated with multipart uploads, see  Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums\n     */\n    private $checksumCrc32C;\n\n    /**\n     * The base64-encoded, 160-bit SHA-1 digest of the object. This will only be present if it was uploaded with the object.\n     * With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are\n     * calculated with multipart uploads, see  Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums\n     */\n    private $checksumSha1;\n\n    /**\n     * The base64-encoded, 256-bit SHA-256 digest of the object. This will only be present if it was uploaded with the\n     * object. With multipart uploads, this may not be a checksum value of the object. For more information about how\n     * checksums are calculated with multipart uploads, see  Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums\n     */\n    private $checksumSha256;\n\n    /**\n     * Part number that identifies the part. This is a positive integer between 1 and 10,000.\n     */\n    private $partNumber;\n\n    /**\n     * @param array{\n     *   ETag?: null|string,\n     *   ChecksumCRC32?: null|string,\n     *   ChecksumCRC32C?: null|string,\n     *   ChecksumSHA1?: null|string,\n     *   ChecksumSHA256?: null|string,\n     *   PartNumber?: null|int,\n     * } $input\n     */\n    public function __construct(array $input)\n    {\n        $this->etag = $input['ETag'] ?? null;\n        $this->checksumCrc32 = $input['ChecksumCRC32'] ?? null;\n        $this->checksumCrc32C = $input['ChecksumCRC32C'] ?? null;\n        $this->checksumSha1 = $input['ChecksumSHA1'] ?? null;\n        $this->checksumSha256 = $input['ChecksumSHA256'] ?? null;\n        $this->partNumber = $input['PartNumber'] ?? null;\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    public function getChecksumCrc32(): ?string\n    {\n        return $this->checksumCrc32;\n    }\n\n    public function getChecksumCrc32C(): ?string\n    {\n        return $this->checksumCrc32C;\n    }\n\n    public function getChecksumSha1(): ?string\n    {\n        return $this->checksumSha1;\n    }\n\n    public function getChecksumSha256(): ?string\n    {\n        return $this->checksumSha256;\n    }\n\n    public function getEtag(): ?string\n    {\n        return $this->etag;\n    }\n\n    public function getPartNumber(): ?int\n    {\n        return $this->partNumber;\n    }\n\n    /**\n     * @internal\n     */\n    public function requestBody(\\DOMElement $node, \\DOMDocument $document): void\n    {\n        if (null !== $v = $this->etag) {\n            $node->appendChild($document->createElement('ETag', $v));\n        }\n        if (null !== $v = $this->checksumCrc32) {\n            $node->appendChild($document->createElement('ChecksumCRC32', $v));\n        }\n        if (null !== $v = $this->checksumCrc32C) {\n            $node->appendChild($document->createElement('ChecksumCRC32C', $v));\n        }\n        if (null !== $v = $this->checksumSha1) {\n            $node->appendChild($document->createElement('ChecksumSHA1', $v));\n        }\n        if (null !== $v = $this->checksumSha256) {\n            $node->appendChild($document->createElement('ChecksumSHA256', $v));\n        }\n        if (null !== $v = $this->partNumber) {\n            $node->appendChild($document->createElement('PartNumber', $v));\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/ValueObject/CopyObjectResult.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\ValueObject;\n\n/**\n * Container for all response elements.\n */\nfinal class CopyObjectResult\n{\n    /**\n     * Returns the ETag of the new object. The ETag reflects only changes to the contents of an object, not its metadata.\n     */\n    private $etag;\n\n    /**\n     * Creation date of the object.\n     */\n    private $lastModified;\n\n    /**\n     * The base64-encoded, 32-bit CRC32 checksum of the object. This will only be present if it was uploaded with the\n     * object. With multipart uploads, this may not be a checksum value of the object. For more information about how\n     * checksums are calculated with multipart uploads, see  Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums\n     */\n    private $checksumCrc32;\n\n    /**\n     * The base64-encoded, 32-bit CRC32C checksum of the object. This will only be present if it was uploaded with the\n     * object. With multipart uploads, this may not be a checksum value of the object. For more information about how\n     * checksums are calculated with multipart uploads, see  Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums\n     */\n    private $checksumCrc32C;\n\n    /**\n     * The base64-encoded, 160-bit SHA-1 digest of the object. This will only be present if it was uploaded with the object.\n     * With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are\n     * calculated with multipart uploads, see  Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums\n     */\n    private $checksumSha1;\n\n    /**\n     * The base64-encoded, 256-bit SHA-256 digest of the object. This will only be present if it was uploaded with the\n     * object. With multipart uploads, this may not be a checksum value of the object. For more information about how\n     * checksums are calculated with multipart uploads, see  Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums\n     */\n    private $checksumSha256;\n\n    /**\n     * @param array{\n     *   ETag?: null|string,\n     *   LastModified?: null|\\DateTimeImmutable,\n     *   ChecksumCRC32?: null|string,\n     *   ChecksumCRC32C?: null|string,\n     *   ChecksumSHA1?: null|string,\n     *   ChecksumSHA256?: null|string,\n     * } $input\n     */\n    public function __construct(array $input)\n    {\n        $this->etag = $input['ETag'] ?? null;\n        $this->lastModified = $input['LastModified'] ?? null;\n        $this->checksumCrc32 = $input['ChecksumCRC32'] ?? null;\n        $this->checksumCrc32C = $input['ChecksumCRC32C'] ?? null;\n        $this->checksumSha1 = $input['ChecksumSHA1'] ?? null;\n        $this->checksumSha256 = $input['ChecksumSHA256'] ?? null;\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    public function getChecksumCrc32(): ?string\n    {\n        return $this->checksumCrc32;\n    }\n\n    public function getChecksumCrc32C(): ?string\n    {\n        return $this->checksumCrc32C;\n    }\n\n    public function getChecksumSha1(): ?string\n    {\n        return $this->checksumSha1;\n    }\n\n    public function getChecksumSha256(): ?string\n    {\n        return $this->checksumSha256;\n    }\n\n    public function getEtag(): ?string\n    {\n        return $this->etag;\n    }\n\n    public function getLastModified(): ?\\DateTimeImmutable\n    {\n        return $this->lastModified;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/ValueObject/CreateBucketConfiguration.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\ValueObject;\n\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\nuse AsyncAws\\S3\\Enum\\BucketLocationConstraint;\n\n/**\n * The configuration information for the bucket.\n */\nfinal class CreateBucketConfiguration\n{\n    /**\n     * Specifies the Region where the bucket will be created. If you don't specify a Region, the bucket is created in the US\n     * East (N. Virginia) Region (us-east-1).\n     */\n    private $locationConstraint;\n\n    /**\n     * @param array{\n     *   LocationConstraint?: null|BucketLocationConstraint::*,\n     * } $input\n     */\n    public function __construct(array $input)\n    {\n        $this->locationConstraint = $input['LocationConstraint'] ?? null;\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    /**\n     * @return BucketLocationConstraint::*|null\n     */\n    public function getLocationConstraint(): ?string\n    {\n        return $this->locationConstraint;\n    }\n\n    /**\n     * @internal\n     */\n    public function requestBody(\\DOMElement $node, \\DOMDocument $document): void\n    {\n        if (null !== $v = $this->locationConstraint) {\n            if (!BucketLocationConstraint::exists($v)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"LocationConstraint\" for \"%s\". The value \"%s\" is not a valid \"BucketLocationConstraint\".', __CLASS__, $v));\n            }\n            $node->appendChild($document->createElement('LocationConstraint', $v));\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/ValueObject/Delete.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\ValueObject;\n\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\n\n/**\n * Container for the objects to delete.\n */\nfinal class Delete\n{\n    /**\n     * The object to delete.\n     */\n    private $objects;\n\n    /**\n     * Element to enable quiet mode for the request. When you add this element, you must set its value to true.\n     */\n    private $quiet;\n\n    /**\n     * @param array{\n     *   Objects: ObjectIdentifier[],\n     *   Quiet?: null|bool,\n     * } $input\n     */\n    public function __construct(array $input)\n    {\n        $this->objects = isset($input['Objects']) ? array_map([ObjectIdentifier::class, 'create'], $input['Objects']) : null;\n        $this->quiet = $input['Quiet'] ?? null;\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    /**\n     * @return ObjectIdentifier[]\n     */\n    public function getObjects(): array\n    {\n        return $this->objects ?? [];\n    }\n\n    public function getQuiet(): ?bool\n    {\n        return $this->quiet;\n    }\n\n    /**\n     * @internal\n     */\n    public function requestBody(\\DOMElement $node, \\DOMDocument $document): void\n    {\n        if (null === $v = $this->objects) {\n            throw new InvalidArgument(sprintf('Missing parameter \"Objects\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        foreach ($v as $item) {\n            $node->appendChild($child = $document->createElement('Object'));\n\n            $item->requestBody($child, $document);\n        }\n\n        if (null !== $v = $this->quiet) {\n            $node->appendChild($document->createElement('Quiet', $v ? 'true' : 'false'));\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/ValueObject/DeletedObject.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\ValueObject;\n\n/**\n * Information about the deleted object.\n */\nfinal class DeletedObject\n{\n    /**\n     * The name of the deleted object.\n     */\n    private $key;\n\n    /**\n     * The version ID of the deleted object.\n     */\n    private $versionId;\n\n    /**\n     * Specifies whether the versioned object that was permanently deleted was (true) or was not (false) a delete marker. In\n     * a simple DELETE, this header indicates whether (true) or not (false) a delete marker was created.\n     */\n    private $deleteMarker;\n\n    /**\n     * The version ID of the delete marker created as a result of the DELETE operation. If you delete a specific object\n     * version, the value returned by this header is the version ID of the object version deleted.\n     */\n    private $deleteMarkerVersionId;\n\n    /**\n     * @param array{\n     *   Key?: null|string,\n     *   VersionId?: null|string,\n     *   DeleteMarker?: null|bool,\n     *   DeleteMarkerVersionId?: null|string,\n     * } $input\n     */\n    public function __construct(array $input)\n    {\n        $this->key = $input['Key'] ?? null;\n        $this->versionId = $input['VersionId'] ?? null;\n        $this->deleteMarker = $input['DeleteMarker'] ?? null;\n        $this->deleteMarkerVersionId = $input['DeleteMarkerVersionId'] ?? null;\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    public function getDeleteMarker(): ?bool\n    {\n        return $this->deleteMarker;\n    }\n\n    public function getDeleteMarkerVersionId(): ?string\n    {\n        return $this->deleteMarkerVersionId;\n    }\n\n    public function getKey(): ?string\n    {\n        return $this->key;\n    }\n\n    public function getVersionId(): ?string\n    {\n        return $this->versionId;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/ValueObject/Error.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\ValueObject;\n\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\n\n/**\n * Container for all error elements.\n */\nfinal class Error\n{\n    /**\n     * The error key.\n     */\n    private $key;\n\n    /**\n     * The version ID of the error.\n     */\n    private $versionId;\n\n    /**\n     * The error code is a string that uniquely identifies an error condition. It is meant to be read and understood by\n     * programs that detect and handle errors by type. The following is a list of Amazon S3 error codes. For more\n     * information, see Error responses [^1].\n     *\n     * - - *Code:* AccessDenied\n     * - - *Description:* Access Denied\n     * - - *HTTP Status Code:* 403 Forbidden\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* AccountProblem\n     * - - *Description:* There is a problem with your Amazon Web Services account that prevents the action from completing\n     * -   successfully. Contact Amazon Web Services Support for further assistance.\n     * - - *HTTP Status Code:* 403 Forbidden\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* AllAccessDisabled\n     * - - *Description:* All access to this Amazon S3 resource has been disabled. Contact Amazon Web Services Support for\n     * -   further assistance.\n     * - - *HTTP Status Code:* 403 Forbidden\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* AmbiguousGrantByEmailAddress\n     * - - *Description:* The email address you provided is associated with more than one account.\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* AuthorizationHeaderMalformed\n     * - - *Description:* The authorization header you provided is invalid.\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *HTTP Status Code:* N/A\n     * -\n     * - - *Code:* BadDigest\n     * - - *Description:* The Content-MD5 you specified did not match what we received.\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* BucketAlreadyExists\n     * - - *Description:* The requested bucket name is not available. The bucket namespace is shared by all users of the\n     * -   system. Please select a different name and try again.\n     * - - *HTTP Status Code:* 409 Conflict\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* BucketAlreadyOwnedByYou\n     * - - *Description:* The bucket you tried to create already exists, and you own it. Amazon S3 returns this error in all\n     * -   Amazon Web Services Regions except in the North Virginia Region. For legacy compatibility, if you re-create an\n     * -   existing bucket that you already own in the North Virginia Region, Amazon S3 returns 200 OK and resets the bucket\n     * -   access control lists (ACLs).\n     * - - *Code:* 409 Conflict (in all Regions except the North Virginia Region)\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* BucketNotEmpty\n     * - - *Description:* The bucket you tried to delete is not empty.\n     * - - *HTTP Status Code:* 409 Conflict\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* CredentialsNotSupported\n     * - - *Description:* This request does not support credentials.\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* CrossLocationLoggingProhibited\n     * - - *Description:* Cross-location logging not allowed. Buckets in one geographic location cannot log information to a\n     * -   bucket in another location.\n     * - - *HTTP Status Code:* 403 Forbidden\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* EntityTooSmall\n     * - - *Description:* Your proposed upload is smaller than the minimum allowed object size.\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* EntityTooLarge\n     * - - *Description:* Your proposed upload exceeds the maximum allowed object size.\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* ExpiredToken\n     * - - *Description:* The provided token has expired.\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* IllegalVersioningConfigurationException\n     * - - *Description:* Indicates that the versioning configuration specified in the request is invalid.\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* IncompleteBody\n     * - - *Description:* You did not provide the number of bytes specified by the Content-Length HTTP header\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* IncorrectNumberOfFilesInPostRequest\n     * - - *Description:* POST requires exactly one file upload per request.\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* InlineDataTooLarge\n     * - - *Description:* Inline data exceeds the maximum allowed size.\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* InternalError\n     * - - *Description:* We encountered an internal error. Please try again.\n     * - - *HTTP Status Code:* 500 Internal Server Error\n     * - - *SOAP Fault Code Prefix:* Server\n     * -\n     * - - *Code:* InvalidAccessKeyId\n     * - - *Description:* The Amazon Web Services access key ID you provided does not exist in our records.\n     * - - *HTTP Status Code:* 403 Forbidden\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* InvalidAddressingHeader\n     * - - *Description:* You must specify the Anonymous role.\n     * - - *HTTP Status Code:* N/A\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* InvalidArgument\n     * - - *Description:* Invalid Argument\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* InvalidBucketName\n     * - - *Description:* The specified bucket is not valid.\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* InvalidBucketState\n     * - - *Description:* The request is not valid with the current state of the bucket.\n     * - - *HTTP Status Code:* 409 Conflict\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* InvalidDigest\n     * - - *Description:* The Content-MD5 you specified is not valid.\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* InvalidEncryptionAlgorithmError\n     * - - *Description:* The encryption request you specified is not valid. The valid value is AES256.\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* InvalidLocationConstraint\n     * - - *Description:* The specified location constraint is not valid. For more information about Regions, see How to\n     * -   Select a Region for Your Buckets [^2].\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* InvalidObjectState\n     * - - *Description:* The action is not valid for the current state of the object.\n     * - - *HTTP Status Code:* 403 Forbidden\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* InvalidPart\n     * - - *Description:* One or more of the specified parts could not be found. The part might not have been uploaded, or\n     * -   the specified entity tag might not have matched the part's entity tag.\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* InvalidPartOrder\n     * - - *Description:* The list of parts was not in ascending order. Parts list must be specified in order by part\n     * -   number.\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* InvalidPayer\n     * - - *Description:* All access to this object has been disabled. Please contact Amazon Web Services Support for\n     * -   further assistance.\n     * - - *HTTP Status Code:* 403 Forbidden\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* InvalidPolicyDocument\n     * - - *Description:* The content of the form does not meet the conditions specified in the policy document.\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* InvalidRange\n     * - - *Description:* The requested range cannot be satisfied.\n     * - - *HTTP Status Code:* 416 Requested Range Not Satisfiable\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* InvalidRequest\n     * - - *Description:* Please use `AWS4-HMAC-SHA256`.\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *Code:* N/A\n     * -\n     * - - *Code:* InvalidRequest\n     * - - *Description:* SOAP requests must be made over an HTTPS connection.\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* InvalidRequest\n     * - - *Description:* Amazon S3 Transfer Acceleration is not supported for buckets with non-DNS compliant names.\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *Code:* N/A\n     * -\n     * - - *Code:* InvalidRequest\n     * - - *Description:* Amazon S3 Transfer Acceleration is not supported for buckets with periods (.) in their names.\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *Code:* N/A\n     * -\n     * - - *Code:* InvalidRequest\n     * - - *Description:* Amazon S3 Transfer Accelerate endpoint only supports virtual style requests.\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *Code:* N/A\n     * -\n     * - - *Code:* InvalidRequest\n     * - - *Description:* Amazon S3 Transfer Accelerate is not configured on this bucket.\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *Code:* N/A\n     * -\n     * - - *Code:* InvalidRequest\n     * - - *Description:* Amazon S3 Transfer Accelerate is disabled on this bucket.\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *Code:* N/A\n     * -\n     * - - *Code:* InvalidRequest\n     * - - *Description:* Amazon S3 Transfer Acceleration is not supported on this bucket. Contact Amazon Web Services\n     * -   Support for more information.\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *Code:* N/A\n     * -\n     * - - *Code:* InvalidRequest\n     * - - *Description:* Amazon S3 Transfer Acceleration cannot be enabled on this bucket. Contact Amazon Web Services\n     * -   Support for more information.\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *Code:* N/A\n     * -\n     * - - *Code:* InvalidSecurity\n     * - - *Description:* The provided security credentials are not valid.\n     * - - *HTTP Status Code:* 403 Forbidden\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* InvalidSOAPRequest\n     * - - *Description:* The SOAP request body is invalid.\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* InvalidStorageClass\n     * - - *Description:* The storage class you specified is not valid.\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* InvalidTargetBucketForLogging\n     * - - *Description:* The target bucket for logging does not exist, is not owned by you, or does not have the\n     * -   appropriate grants for the log-delivery group.\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* InvalidToken\n     * - - *Description:* The provided token is malformed or otherwise invalid.\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* InvalidURI\n     * - - *Description:* Couldn't parse the specified URI.\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* KeyTooLongError\n     * - - *Description:* Your key is too long.\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* MalformedACLError\n     * - - *Description:* The XML you provided was not well-formed or did not validate against our published schema.\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* MalformedPOSTRequest\n     * - - *Description:* The body of your POST request is not well-formed multipart/form-data.\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* MalformedXML\n     * - - *Description:* This happens when the user sends malformed XML (XML that doesn't conform to the published XSD) for\n     * -   the configuration. The error message is, \"The XML you provided was not well-formed or did not validate against\n     * -   our published schema.\"\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* MaxMessageLengthExceeded\n     * - - *Description:* Your request was too big.\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* MaxPostPreDataLengthExceededError\n     * - - *Description:* Your POST request fields preceding the upload file were too large.\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* MetadataTooLarge\n     * - - *Description:* Your metadata headers exceed the maximum allowed metadata size.\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* MethodNotAllowed\n     * - - *Description:* The specified method is not allowed against this resource.\n     * - - *HTTP Status Code:* 405 Method Not Allowed\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* MissingAttachment\n     * - - *Description:* A SOAP attachment was expected, but none were found.\n     * - - *HTTP Status Code:* N/A\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* MissingContentLength\n     * - - *Description:* You must provide the Content-Length HTTP header.\n     * - - *HTTP Status Code:* 411 Length Required\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* MissingRequestBodyError\n     * - - *Description:* This happens when the user sends an empty XML document as a request. The error message is,\n     * -   \"Request body is empty.\"\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* MissingSecurityElement\n     * - - *Description:* The SOAP 1.1 request is missing a security element.\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* MissingSecurityHeader\n     * - - *Description:* Your request is missing a required header.\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* NoLoggingStatusForKey\n     * - - *Description:* There is no such thing as a logging status subresource for a key.\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* NoSuchBucket\n     * - - *Description:* The specified bucket does not exist.\n     * - - *HTTP Status Code:* 404 Not Found\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* NoSuchBucketPolicy\n     * - - *Description:* The specified bucket does not have a bucket policy.\n     * - - *HTTP Status Code:* 404 Not Found\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* NoSuchKey\n     * - - *Description:* The specified key does not exist.\n     * - - *HTTP Status Code:* 404 Not Found\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* NoSuchLifecycleConfiguration\n     * - - *Description:* The lifecycle configuration does not exist.\n     * - - *HTTP Status Code:* 404 Not Found\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* NoSuchUpload\n     * - - *Description:* The specified multipart upload does not exist. The upload ID might be invalid, or the multipart\n     * -   upload might have been aborted or completed.\n     * - - *HTTP Status Code:* 404 Not Found\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* NoSuchVersion\n     * - - *Description:* Indicates that the version ID specified in the request does not match an existing version.\n     * - - *HTTP Status Code:* 404 Not Found\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* NotImplemented\n     * - - *Description:* A header you provided implies functionality that is not implemented.\n     * - - *HTTP Status Code:* 501 Not Implemented\n     * - - *SOAP Fault Code Prefix:* Server\n     * -\n     * - - *Code:* NotSignedUp\n     * - - *Description:* Your account is not signed up for the Amazon S3 service. You must sign up before you can use\n     * -   Amazon S3. You can sign up at the following URL: Amazon S3 [^3]\n     * - - *HTTP Status Code:* 403 Forbidden\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* OperationAborted\n     * - - *Description:* A conflicting conditional action is currently in progress against this resource. Try again.\n     * - - *HTTP Status Code:* 409 Conflict\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* PermanentRedirect\n     * - - *Description:* The bucket you are attempting to access must be addressed using the specified endpoint. Send all\n     * -   future requests to this endpoint.\n     * - - *HTTP Status Code:* 301 Moved Permanently\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* PreconditionFailed\n     * - - *Description:* At least one of the preconditions you specified did not hold.\n     * - - *HTTP Status Code:* 412 Precondition Failed\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* Redirect\n     * - - *Description:* Temporary redirect.\n     * - - *HTTP Status Code:* 307 Moved Temporarily\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* RestoreAlreadyInProgress\n     * - - *Description:* Object restore is already in progress.\n     * - - *HTTP Status Code:* 409 Conflict\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* RequestIsNotMultiPartContent\n     * - - *Description:* Bucket POST must be of the enclosure-type multipart/form-data.\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* RequestTimeout\n     * - - *Description:* Your socket connection to the server was not read from or written to within the timeout period.\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* RequestTimeTooSkewed\n     * - - *Description:* The difference between the request time and the server's time is too large.\n     * - - *HTTP Status Code:* 403 Forbidden\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* RequestTorrentOfBucketError\n     * - - *Description:* Requesting the torrent file of a bucket is not permitted.\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* SignatureDoesNotMatch\n     * - - *Description:* The request signature we calculated does not match the signature you provided. Check your Amazon\n     * -   Web Services secret access key and signing method. For more information, see REST Authentication [^4] and SOAP\n     * -   Authentication [^5] for details.\n     * - - *HTTP Status Code:* 403 Forbidden\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* ServiceUnavailable\n     * - - *Description:* Service is unable to handle request.\n     * - - *HTTP Status Code:* 503 Service Unavailable\n     * - - *SOAP Fault Code Prefix:* Server\n     * -\n     * - - *Code:* SlowDown\n     * - - *Description:* Reduce your request rate.\n     * - - *HTTP Status Code:* 503 Slow Down\n     * - - *SOAP Fault Code Prefix:* Server\n     * -\n     * - - *Code:* TemporaryRedirect\n     * - - *Description:* You are being redirected to the bucket while DNS updates.\n     * - - *HTTP Status Code:* 307 Moved Temporarily\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* TokenRefreshRequired\n     * - - *Description:* The provided token must be refreshed.\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* TooManyBuckets\n     * - - *Description:* You have attempted to create more buckets than allowed.\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* UnexpectedContent\n     * - - *Description:* This request does not support content.\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* UnresolvableGrantByEmailAddress\n     * - - *Description:* The email address you provided does not match any account on record.\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     * - - *Code:* UserKeyMustBeSpecified\n     * - - *Description:* The bucket POST must contain the specified field name. If it is specified, check the order of the\n     * -   fields.\n     * - - *HTTP Status Code:* 400 Bad Request\n     * - - *SOAP Fault Code Prefix:* Client\n     * -\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html\n     * [^2]: https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingBucket.html#access-bucket-intro\n     * [^3]: http://aws.amazon.com/s3\n     * [^4]: https://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html\n     * [^5]: https://docs.aws.amazon.com/AmazonS3/latest/dev/SOAPAuthentication.html\n     */\n    private $code;\n\n    /**\n     * The error message contains a generic description of the error condition in English. It is intended for a human\n     * audience. Simple programs display the message directly to the end user if they encounter an error condition they\n     * don't know how or don't care to handle. Sophisticated programs with more exhaustive error handling and proper\n     * internationalization are more likely to ignore the error message.\n     */\n    private $message;\n\n    /**\n     * @param array{\n     *   Key?: null|string,\n     *   VersionId?: null|string,\n     *   Code?: null|string,\n     *   Message?: null|string,\n     * } $input\n     */\n    public function __construct(array $input)\n    {\n        $this->key = $input['Key'] ?? null;\n        $this->versionId = $input['VersionId'] ?? null;\n        $this->code = $input['Code'] ?? null;\n        $this->message = $input['Message'] ?? null;\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    public function getCode(): ?string\n    {\n        return $this->code;\n    }\n\n    public function getKey(): ?string\n    {\n        return $this->key;\n    }\n\n    public function getMessage(): ?string\n    {\n        return $this->message;\n    }\n\n    public function getVersionId(): ?string\n    {\n        return $this->versionId;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/ValueObject/EventBridgeConfiguration.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\ValueObject;\n\n/**\n * A container for specifying the configuration for Amazon EventBridge.\n */\nfinal class EventBridgeConfiguration\n{\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self();\n    }\n\n    /**\n     * @internal\n     */\n    public function requestBody(\\DOMElement $node, \\DOMDocument $document): void\n    {\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/ValueObject/FilterRule.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\ValueObject;\n\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\nuse AsyncAws\\S3\\Enum\\FilterRuleName;\n\n/**\n * Specifies the Amazon S3 object key name to filter on and whether to filter on the suffix or prefix of the key name.\n */\nfinal class FilterRule\n{\n    /**\n     * The object key name prefix or suffix identifying one or more objects to which the filtering rule applies. The maximum\n     * length is 1,024 characters. Overlapping prefixes and suffixes are not supported. For more information, see\n     * Configuring Event Notifications [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/dev/NotificationHowTo.html\n     */\n    private $name;\n\n    /**\n     * The value that the filter searches for in object key names.\n     */\n    private $value;\n\n    /**\n     * @param array{\n     *   Name?: null|FilterRuleName::*,\n     *   Value?: null|string,\n     * } $input\n     */\n    public function __construct(array $input)\n    {\n        $this->name = $input['Name'] ?? null;\n        $this->value = $input['Value'] ?? null;\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    /**\n     * @return FilterRuleName::*|null\n     */\n    public function getName(): ?string\n    {\n        return $this->name;\n    }\n\n    public function getValue(): ?string\n    {\n        return $this->value;\n    }\n\n    /**\n     * @internal\n     */\n    public function requestBody(\\DOMElement $node, \\DOMDocument $document): void\n    {\n        if (null !== $v = $this->name) {\n            if (!FilterRuleName::exists($v)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"Name\" for \"%s\". The value \"%s\" is not a valid \"FilterRuleName\".', __CLASS__, $v));\n            }\n            $node->appendChild($document->createElement('Name', $v));\n        }\n        if (null !== $v = $this->value) {\n            $node->appendChild($document->createElement('Value', $v));\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/ValueObject/Grant.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\ValueObject;\n\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\nuse AsyncAws\\S3\\Enum\\Permission;\n\n/**\n * Container for grant information.\n */\nfinal class Grant\n{\n    /**\n     * The person being granted permissions.\n     */\n    private $grantee;\n\n    /**\n     * Specifies the permission given to the grantee.\n     */\n    private $permission;\n\n    /**\n     * @param array{\n     *   Grantee?: null|Grantee|array,\n     *   Permission?: null|Permission::*,\n     * } $input\n     */\n    public function __construct(array $input)\n    {\n        $this->grantee = isset($input['Grantee']) ? Grantee::create($input['Grantee']) : null;\n        $this->permission = $input['Permission'] ?? null;\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    public function getGrantee(): ?Grantee\n    {\n        return $this->grantee;\n    }\n\n    /**\n     * @return Permission::*|null\n     */\n    public function getPermission(): ?string\n    {\n        return $this->permission;\n    }\n\n    /**\n     * @internal\n     */\n    public function requestBody(\\DOMElement $node, \\DOMDocument $document): void\n    {\n        if (null !== $v = $this->grantee) {\n            $node->appendChild($child = $document->createElement('Grantee'));\n            $child->setAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');\n            $v->requestBody($child, $document);\n        }\n        if (null !== $v = $this->permission) {\n            if (!Permission::exists($v)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"Permission\" for \"%s\". The value \"%s\" is not a valid \"Permission\".', __CLASS__, $v));\n            }\n            $node->appendChild($document->createElement('Permission', $v));\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/ValueObject/Grantee.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\ValueObject;\n\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\nuse AsyncAws\\S3\\Enum\\Type;\n\n/**\n * Container for the person being granted permissions.\n */\nfinal class Grantee\n{\n    /**\n     * Screen name of the grantee.\n     */\n    private $displayName;\n\n    /**\n     * Email address of the grantee.\n     *\n     * > Using email addresses to specify a grantee is only supported in the following Amazon Web Services Regions:\n     * >\n     * > - US East (N. Virginia)\n     * > - US West (N. California)\n     * > - US West (Oregon)\n     * > - Asia Pacific (Singapore)\n     * > - Asia Pacific (Sydney)\n     * > - Asia Pacific (Tokyo)\n     * > - Europe (Ireland)\n     * > - South America (São Paulo)\n     * >\n     * > For a list of all the Amazon S3 supported Regions and endpoints, see Regions and Endpoints [^1] in the Amazon Web\n     * > Services General Reference.\n     *\n     * [^1]: https://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region\n     */\n    private $emailAddress;\n\n    /**\n     * The canonical user ID of the grantee.\n     */\n    private $id;\n\n    /**\n     * Type of grantee.\n     */\n    private $type;\n\n    /**\n     * URI of the grantee group.\n     */\n    private $uri;\n\n    /**\n     * @param array{\n     *   DisplayName?: null|string,\n     *   EmailAddress?: null|string,\n     *   ID?: null|string,\n     *   Type: Type::*,\n     *   URI?: null|string,\n     * } $input\n     */\n    public function __construct(array $input)\n    {\n        $this->displayName = $input['DisplayName'] ?? null;\n        $this->emailAddress = $input['EmailAddress'] ?? null;\n        $this->id = $input['ID'] ?? null;\n        $this->type = $input['Type'] ?? null;\n        $this->uri = $input['URI'] ?? null;\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    public function getDisplayName(): ?string\n    {\n        return $this->displayName;\n    }\n\n    public function getEmailAddress(): ?string\n    {\n        return $this->emailAddress;\n    }\n\n    public function getId(): ?string\n    {\n        return $this->id;\n    }\n\n    /**\n     * @return Type::*\n     */\n    public function getType(): string\n    {\n        return $this->type;\n    }\n\n    public function getUri(): ?string\n    {\n        return $this->uri;\n    }\n\n    /**\n     * @internal\n     */\n    public function requestBody(\\DOMElement $node, \\DOMDocument $document): void\n    {\n        if (null !== $v = $this->displayName) {\n            $node->appendChild($document->createElement('DisplayName', $v));\n        }\n        if (null !== $v = $this->emailAddress) {\n            $node->appendChild($document->createElement('EmailAddress', $v));\n        }\n        if (null !== $v = $this->id) {\n            $node->appendChild($document->createElement('ID', $v));\n        }\n        if (null === $v = $this->type) {\n            throw new InvalidArgument(sprintf('Missing parameter \"Type\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        if (!Type::exists($v)) {\n            throw new InvalidArgument(sprintf('Invalid parameter \"xsi:type\" for \"%s\". The value \"%s\" is not a valid \"Type\".', __CLASS__, $v));\n        }\n        $node->setAttribute('xsi:type', $v);\n        if (null !== $v = $this->uri) {\n            $node->appendChild($document->createElement('URI', $v));\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/ValueObject/Initiator.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\ValueObject;\n\n/**\n * Container element that identifies who initiated the multipart upload.\n */\nfinal class Initiator\n{\n    /**\n     * If the principal is an Amazon Web Services account, it provides the Canonical User ID. If the principal is an IAM\n     * User, it provides a user ARN value.\n     */\n    private $id;\n\n    /**\n     * Name of the Principal.\n     */\n    private $displayName;\n\n    /**\n     * @param array{\n     *   ID?: null|string,\n     *   DisplayName?: null|string,\n     * } $input\n     */\n    public function __construct(array $input)\n    {\n        $this->id = $input['ID'] ?? null;\n        $this->displayName = $input['DisplayName'] ?? null;\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    public function getDisplayName(): ?string\n    {\n        return $this->displayName;\n    }\n\n    public function getId(): ?string\n    {\n        return $this->id;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/ValueObject/LambdaFunctionConfiguration.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\ValueObject;\n\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\nuse AsyncAws\\S3\\Enum\\Event;\n\n/**\n * A container for specifying the configuration for Lambda notifications.\n */\nfinal class LambdaFunctionConfiguration\n{\n    private $id;\n\n    /**\n     * The Amazon Resource Name (ARN) of the Lambda function that Amazon S3 invokes when the specified event type occurs.\n     */\n    private $lambdaFunctionArn;\n\n    /**\n     * The Amazon S3 bucket event for which to invoke the Lambda function. For more information, see Supported Event Types\n     * [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/dev/NotificationHowTo.html\n     */\n    private $events;\n\n    private $filter;\n\n    /**\n     * @param array{\n     *   Id?: null|string,\n     *   LambdaFunctionArn: string,\n     *   Events: list<Event::*>,\n     *   Filter?: null|NotificationConfigurationFilter|array,\n     * } $input\n     */\n    public function __construct(array $input)\n    {\n        $this->id = $input['Id'] ?? null;\n        $this->lambdaFunctionArn = $input['LambdaFunctionArn'] ?? null;\n        $this->events = $input['Events'] ?? null;\n        $this->filter = isset($input['Filter']) ? NotificationConfigurationFilter::create($input['Filter']) : null;\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    /**\n     * @return list<Event::*>\n     */\n    public function getEvents(): array\n    {\n        return $this->events ?? [];\n    }\n\n    public function getFilter(): ?NotificationConfigurationFilter\n    {\n        return $this->filter;\n    }\n\n    public function getId(): ?string\n    {\n        return $this->id;\n    }\n\n    public function getLambdaFunctionArn(): string\n    {\n        return $this->lambdaFunctionArn;\n    }\n\n    /**\n     * @internal\n     */\n    public function requestBody(\\DOMElement $node, \\DOMDocument $document): void\n    {\n        if (null !== $v = $this->id) {\n            $node->appendChild($document->createElement('Id', $v));\n        }\n        if (null === $v = $this->lambdaFunctionArn) {\n            throw new InvalidArgument(sprintf('Missing parameter \"LambdaFunctionArn\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        $node->appendChild($document->createElement('CloudFunction', $v));\n        if (null === $v = $this->events) {\n            throw new InvalidArgument(sprintf('Missing parameter \"Events\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        foreach ($v as $item) {\n            if (!Event::exists($item)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"Event\" for \"%s\". The value \"%s\" is not a valid \"Event\".', __CLASS__, $item));\n            }\n            $node->appendChild($document->createElement('Event', $item));\n        }\n\n        if (null !== $v = $this->filter) {\n            $node->appendChild($child = $document->createElement('Filter'));\n\n            $v->requestBody($child, $document);\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/ValueObject/MultipartUpload.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\ValueObject;\n\nuse AsyncAws\\S3\\Enum\\ChecksumAlgorithm;\nuse AsyncAws\\S3\\Enum\\StorageClass;\n\n/**\n * Container for the `MultipartUpload` for the Amazon S3 object.\n */\nfinal class MultipartUpload\n{\n    /**\n     * Upload ID that identifies the multipart upload.\n     */\n    private $uploadId;\n\n    /**\n     * Key of the object for which the multipart upload was initiated.\n     */\n    private $key;\n\n    /**\n     * Date and time at which the multipart upload was initiated.\n     */\n    private $initiated;\n\n    /**\n     * The class of storage used to store the object.\n     */\n    private $storageClass;\n\n    /**\n     * Specifies the owner of the object that is part of the multipart upload.\n     */\n    private $owner;\n\n    /**\n     * Identifies who initiated the multipart upload.\n     */\n    private $initiator;\n\n    /**\n     * The algorithm that was used to create a checksum of the object.\n     */\n    private $checksumAlgorithm;\n\n    /**\n     * @param array{\n     *   UploadId?: null|string,\n     *   Key?: null|string,\n     *   Initiated?: null|\\DateTimeImmutable,\n     *   StorageClass?: null|StorageClass::*,\n     *   Owner?: null|Owner|array,\n     *   Initiator?: null|Initiator|array,\n     *   ChecksumAlgorithm?: null|ChecksumAlgorithm::*,\n     * } $input\n     */\n    public function __construct(array $input)\n    {\n        $this->uploadId = $input['UploadId'] ?? null;\n        $this->key = $input['Key'] ?? null;\n        $this->initiated = $input['Initiated'] ?? null;\n        $this->storageClass = $input['StorageClass'] ?? null;\n        $this->owner = isset($input['Owner']) ? Owner::create($input['Owner']) : null;\n        $this->initiator = isset($input['Initiator']) ? Initiator::create($input['Initiator']) : null;\n        $this->checksumAlgorithm = $input['ChecksumAlgorithm'] ?? null;\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    /**\n     * @return ChecksumAlgorithm::*|null\n     */\n    public function getChecksumAlgorithm(): ?string\n    {\n        return $this->checksumAlgorithm;\n    }\n\n    public function getInitiated(): ?\\DateTimeImmutable\n    {\n        return $this->initiated;\n    }\n\n    public function getInitiator(): ?Initiator\n    {\n        return $this->initiator;\n    }\n\n    public function getKey(): ?string\n    {\n        return $this->key;\n    }\n\n    public function getOwner(): ?Owner\n    {\n        return $this->owner;\n    }\n\n    /**\n     * @return StorageClass::*|null\n     */\n    public function getStorageClass(): ?string\n    {\n        return $this->storageClass;\n    }\n\n    public function getUploadId(): ?string\n    {\n        return $this->uploadId;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/ValueObject/NotificationConfiguration.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\ValueObject;\n\n/**\n * A container for specifying the notification configuration of the bucket. If this element is empty, notifications are\n * turned off for the bucket.\n */\nfinal class NotificationConfiguration\n{\n    /**\n     * The topic to which notifications are sent and the events for which notifications are generated.\n     */\n    private $topicConfigurations;\n\n    /**\n     * The Amazon Simple Queue Service queues to publish messages to and the events for which to publish messages.\n     */\n    private $queueConfigurations;\n\n    /**\n     * Describes the Lambda functions to invoke and the events for which to invoke them.\n     */\n    private $lambdaFunctionConfigurations;\n\n    /**\n     * Enables delivery of events to Amazon EventBridge.\n     */\n    private $eventBridgeConfiguration;\n\n    /**\n     * @param array{\n     *   TopicConfigurations?: null|TopicConfiguration[],\n     *   QueueConfigurations?: null|QueueConfiguration[],\n     *   LambdaFunctionConfigurations?: null|LambdaFunctionConfiguration[],\n     *   EventBridgeConfiguration?: null|EventBridgeConfiguration|array,\n     * } $input\n     */\n    public function __construct(array $input)\n    {\n        $this->topicConfigurations = isset($input['TopicConfigurations']) ? array_map([TopicConfiguration::class, 'create'], $input['TopicConfigurations']) : null;\n        $this->queueConfigurations = isset($input['QueueConfigurations']) ? array_map([QueueConfiguration::class, 'create'], $input['QueueConfigurations']) : null;\n        $this->lambdaFunctionConfigurations = isset($input['LambdaFunctionConfigurations']) ? array_map([LambdaFunctionConfiguration::class, 'create'], $input['LambdaFunctionConfigurations']) : null;\n        $this->eventBridgeConfiguration = isset($input['EventBridgeConfiguration']) ? EventBridgeConfiguration::create($input['EventBridgeConfiguration']) : null;\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    public function getEventBridgeConfiguration(): ?EventBridgeConfiguration\n    {\n        return $this->eventBridgeConfiguration;\n    }\n\n    /**\n     * @return LambdaFunctionConfiguration[]\n     */\n    public function getLambdaFunctionConfigurations(): array\n    {\n        return $this->lambdaFunctionConfigurations ?? [];\n    }\n\n    /**\n     * @return QueueConfiguration[]\n     */\n    public function getQueueConfigurations(): array\n    {\n        return $this->queueConfigurations ?? [];\n    }\n\n    /**\n     * @return TopicConfiguration[]\n     */\n    public function getTopicConfigurations(): array\n    {\n        return $this->topicConfigurations ?? [];\n    }\n\n    /**\n     * @internal\n     */\n    public function requestBody(\\DOMElement $node, \\DOMDocument $document): void\n    {\n        if (null !== $v = $this->topicConfigurations) {\n            foreach ($v as $item) {\n                $node->appendChild($child = $document->createElement('TopicConfiguration'));\n\n                $item->requestBody($child, $document);\n            }\n        }\n        if (null !== $v = $this->queueConfigurations) {\n            foreach ($v as $item) {\n                $node->appendChild($child = $document->createElement('QueueConfiguration'));\n\n                $item->requestBody($child, $document);\n            }\n        }\n        if (null !== $v = $this->lambdaFunctionConfigurations) {\n            foreach ($v as $item) {\n                $node->appendChild($child = $document->createElement('CloudFunctionConfiguration'));\n\n                $item->requestBody($child, $document);\n            }\n        }\n        if (null !== $v = $this->eventBridgeConfiguration) {\n            $node->appendChild($child = $document->createElement('EventBridgeConfiguration'));\n\n            $v->requestBody($child, $document);\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/ValueObject/NotificationConfigurationFilter.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\ValueObject;\n\n/**\n * Specifies object key name filtering rules. For information about key name filtering, see Configuring event\n * notifications using object key name filtering [^1] in the *Amazon S3 User Guide*.\n *\n * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/notification-how-to-filtering.html\n */\nfinal class NotificationConfigurationFilter\n{\n    private $key;\n\n    /**\n     * @param array{\n     *   Key?: null|S3KeyFilter|array,\n     * } $input\n     */\n    public function __construct(array $input)\n    {\n        $this->key = isset($input['Key']) ? S3KeyFilter::create($input['Key']) : null;\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    public function getKey(): ?S3KeyFilter\n    {\n        return $this->key;\n    }\n\n    /**\n     * @internal\n     */\n    public function requestBody(\\DOMElement $node, \\DOMDocument $document): void\n    {\n        if (null !== $v = $this->key) {\n            $node->appendChild($child = $document->createElement('S3Key'));\n\n            $v->requestBody($child, $document);\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/ValueObject/ObjectIdentifier.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\ValueObject;\n\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\n\n/**\n * Object Identifier is unique value to identify objects.\n */\nfinal class ObjectIdentifier\n{\n    /**\n     * Key name of the object.\n     *\n     * ! Replacement must be made for object keys containing special characters (such as carriage returns) when using XML\n     * ! requests. For more information, see  XML related object key constraints [^1].\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-keys.html#object-key-xml-related-constraints\n     */\n    private $key;\n\n    /**\n     * VersionId for the specific version of the object to delete.\n     */\n    private $versionId;\n\n    /**\n     * @param array{\n     *   Key: string,\n     *   VersionId?: null|string,\n     * } $input\n     */\n    public function __construct(array $input)\n    {\n        $this->key = $input['Key'] ?? null;\n        $this->versionId = $input['VersionId'] ?? null;\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    public function getKey(): string\n    {\n        return $this->key;\n    }\n\n    public function getVersionId(): ?string\n    {\n        return $this->versionId;\n    }\n\n    /**\n     * @internal\n     */\n    public function requestBody(\\DOMElement $node, \\DOMDocument $document): void\n    {\n        if (null === $v = $this->key) {\n            throw new InvalidArgument(sprintf('Missing parameter \"Key\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        $node->appendChild($document->createElement('Key', $v));\n        if (null !== $v = $this->versionId) {\n            $node->appendChild($document->createElement('VersionId', $v));\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/ValueObject/Owner.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\ValueObject;\n\n/**\n * Container for the owner's display name and ID.\n */\nfinal class Owner\n{\n    /**\n     * Container for the display name of the owner. This value is only supported in the following Amazon Web Services\n     * Regions:.\n     *\n     * - US East (N. Virginia)\n     * - US West (N. California)\n     * - US West (Oregon)\n     * - Asia Pacific (Singapore)\n     * - Asia Pacific (Sydney)\n     * - Asia Pacific (Tokyo)\n     * - Europe (Ireland)\n     * - South America (São Paulo)\n     */\n    private $displayName;\n\n    /**\n     * Container for the ID of the owner.\n     */\n    private $id;\n\n    /**\n     * @param array{\n     *   DisplayName?: null|string,\n     *   ID?: null|string,\n     * } $input\n     */\n    public function __construct(array $input)\n    {\n        $this->displayName = $input['DisplayName'] ?? null;\n        $this->id = $input['ID'] ?? null;\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    public function getDisplayName(): ?string\n    {\n        return $this->displayName;\n    }\n\n    public function getId(): ?string\n    {\n        return $this->id;\n    }\n\n    /**\n     * @internal\n     */\n    public function requestBody(\\DOMElement $node, \\DOMDocument $document): void\n    {\n        if (null !== $v = $this->displayName) {\n            $node->appendChild($document->createElement('DisplayName', $v));\n        }\n        if (null !== $v = $this->id) {\n            $node->appendChild($document->createElement('ID', $v));\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/ValueObject/Part.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\ValueObject;\n\n/**\n * Container for elements related to a part.\n */\nfinal class Part\n{\n    /**\n     * Part number identifying the part. This is a positive integer between 1 and 10,000.\n     */\n    private $partNumber;\n\n    /**\n     * Date and time at which the part was uploaded.\n     */\n    private $lastModified;\n\n    /**\n     * Entity tag returned when the part was uploaded.\n     */\n    private $etag;\n\n    /**\n     * Size in bytes of the uploaded part data.\n     */\n    private $size;\n\n    /**\n     * This header can be used as a data integrity check to verify that the data received is the same data that was\n     * originally sent. This header specifies the base64-encoded, 32-bit CRC32 checksum of the object. For more information,\n     * see Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html\n     */\n    private $checksumCrc32;\n\n    /**\n     * The base64-encoded, 32-bit CRC32C checksum of the object. This will only be present if it was uploaded with the\n     * object. With multipart uploads, this may not be a checksum value of the object. For more information about how\n     * checksums are calculated with multipart uploads, see  Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums\n     */\n    private $checksumCrc32C;\n\n    /**\n     * The base64-encoded, 160-bit SHA-1 digest of the object. This will only be present if it was uploaded with the object.\n     * With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are\n     * calculated with multipart uploads, see  Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums\n     */\n    private $checksumSha1;\n\n    /**\n     * This header can be used as a data integrity check to verify that the data received is the same data that was\n     * originally sent. This header specifies the base64-encoded, 256-bit SHA-256 digest of the object. For more\n     * information, see Checking object integrity [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html\n     */\n    private $checksumSha256;\n\n    /**\n     * @param array{\n     *   PartNumber?: null|int,\n     *   LastModified?: null|\\DateTimeImmutable,\n     *   ETag?: null|string,\n     *   Size?: null|string,\n     *   ChecksumCRC32?: null|string,\n     *   ChecksumCRC32C?: null|string,\n     *   ChecksumSHA1?: null|string,\n     *   ChecksumSHA256?: null|string,\n     * } $input\n     */\n    public function __construct(array $input)\n    {\n        $this->partNumber = $input['PartNumber'] ?? null;\n        $this->lastModified = $input['LastModified'] ?? null;\n        $this->etag = $input['ETag'] ?? null;\n        $this->size = $input['Size'] ?? null;\n        $this->checksumCrc32 = $input['ChecksumCRC32'] ?? null;\n        $this->checksumCrc32C = $input['ChecksumCRC32C'] ?? null;\n        $this->checksumSha1 = $input['ChecksumSHA1'] ?? null;\n        $this->checksumSha256 = $input['ChecksumSHA256'] ?? null;\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    public function getChecksumCrc32(): ?string\n    {\n        return $this->checksumCrc32;\n    }\n\n    public function getChecksumCrc32C(): ?string\n    {\n        return $this->checksumCrc32C;\n    }\n\n    public function getChecksumSha1(): ?string\n    {\n        return $this->checksumSha1;\n    }\n\n    public function getChecksumSha256(): ?string\n    {\n        return $this->checksumSha256;\n    }\n\n    public function getEtag(): ?string\n    {\n        return $this->etag;\n    }\n\n    public function getLastModified(): ?\\DateTimeImmutable\n    {\n        return $this->lastModified;\n    }\n\n    public function getPartNumber(): ?int\n    {\n        return $this->partNumber;\n    }\n\n    public function getSize(): ?string\n    {\n        return $this->size;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/ValueObject/QueueConfiguration.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\ValueObject;\n\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\nuse AsyncAws\\S3\\Enum\\Event;\n\n/**\n * Specifies the configuration for publishing messages to an Amazon Simple Queue Service (Amazon SQS) queue when Amazon\n * S3 detects specified events.\n */\nfinal class QueueConfiguration\n{\n    private $id;\n\n    /**\n     * The Amazon Resource Name (ARN) of the Amazon SQS queue to which Amazon S3 publishes a message when it detects events\n     * of the specified type.\n     */\n    private $queueArn;\n\n    /**\n     * A collection of bucket events for which to send notifications.\n     */\n    private $events;\n\n    private $filter;\n\n    /**\n     * @param array{\n     *   Id?: null|string,\n     *   QueueArn: string,\n     *   Events: list<Event::*>,\n     *   Filter?: null|NotificationConfigurationFilter|array,\n     * } $input\n     */\n    public function __construct(array $input)\n    {\n        $this->id = $input['Id'] ?? null;\n        $this->queueArn = $input['QueueArn'] ?? null;\n        $this->events = $input['Events'] ?? null;\n        $this->filter = isset($input['Filter']) ? NotificationConfigurationFilter::create($input['Filter']) : null;\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    /**\n     * @return list<Event::*>\n     */\n    public function getEvents(): array\n    {\n        return $this->events ?? [];\n    }\n\n    public function getFilter(): ?NotificationConfigurationFilter\n    {\n        return $this->filter;\n    }\n\n    public function getId(): ?string\n    {\n        return $this->id;\n    }\n\n    public function getQueueArn(): string\n    {\n        return $this->queueArn;\n    }\n\n    /**\n     * @internal\n     */\n    public function requestBody(\\DOMElement $node, \\DOMDocument $document): void\n    {\n        if (null !== $v = $this->id) {\n            $node->appendChild($document->createElement('Id', $v));\n        }\n        if (null === $v = $this->queueArn) {\n            throw new InvalidArgument(sprintf('Missing parameter \"QueueArn\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        $node->appendChild($document->createElement('Queue', $v));\n        if (null === $v = $this->events) {\n            throw new InvalidArgument(sprintf('Missing parameter \"Events\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        foreach ($v as $item) {\n            if (!Event::exists($item)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"Event\" for \"%s\". The value \"%s\" is not a valid \"Event\".', __CLASS__, $item));\n            }\n            $node->appendChild($document->createElement('Event', $item));\n        }\n\n        if (null !== $v = $this->filter) {\n            $node->appendChild($child = $document->createElement('Filter'));\n\n            $v->requestBody($child, $document);\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/ValueObject/S3KeyFilter.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\ValueObject;\n\n/**\n * A container for object key name prefix and suffix filtering rules.\n */\nfinal class S3KeyFilter\n{\n    private $filterRules;\n\n    /**\n     * @param array{\n     *   FilterRules?: null|FilterRule[],\n     * } $input\n     */\n    public function __construct(array $input)\n    {\n        $this->filterRules = isset($input['FilterRules']) ? array_map([FilterRule::class, 'create'], $input['FilterRules']) : null;\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    /**\n     * @return FilterRule[]\n     */\n    public function getFilterRules(): array\n    {\n        return $this->filterRules ?? [];\n    }\n\n    /**\n     * @internal\n     */\n    public function requestBody(\\DOMElement $node, \\DOMDocument $document): void\n    {\n        if (null !== $v = $this->filterRules) {\n            foreach ($v as $item) {\n                $node->appendChild($child = $document->createElement('FilterRule'));\n\n                $item->requestBody($child, $document);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/ValueObject/ServerSideEncryptionByDefault.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\ValueObject;\n\nuse AsyncAws\\S3\\Enum\\ServerSideEncryption;\n\n/**\n * Describes the default server-side encryption to apply to new objects in the bucket. If a PUT Object request doesn't\n * specify any server-side encryption, this default encryption will be applied. If you don't specify a customer managed\n * key at configuration, Amazon S3 automatically creates an Amazon Web Services KMS key in your Amazon Web Services\n * account the first time that you add an object encrypted with SSE-KMS to a bucket. By default, Amazon S3 uses this KMS\n * key for SSE-KMS. For more information, see PUT Bucket encryption [^1] in the *Amazon S3 API Reference*.\n *\n * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketPUTencryption.html\n */\nfinal class ServerSideEncryptionByDefault\n{\n    /**\n     * Server-side encryption algorithm to use for the default encryption.\n     */\n    private $sseAlgorithm;\n\n    /**\n     * Amazon Web Services Key Management Service (KMS) customer Amazon Web Services KMS key ID to use for the default\n     * encryption. This parameter is allowed if and only if `SSEAlgorithm` is set to `aws:kms`.\n     *\n     * You can specify the key ID or the Amazon Resource Name (ARN) of the KMS key. If you use a key ID, you can run into a\n     * LogDestination undeliverable error when creating a VPC flow log.\n     *\n     * If you are using encryption with cross-account or Amazon Web Services service operations you must use a fully\n     * qualified KMS key ARN. For more information, see Using encryption for cross-account operations [^1].\n     *\n     * - Key ID: `1234abcd-12ab-34cd-56ef-1234567890ab`\n     * - Key ARN: `arn:aws:kms:us-east-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab`\n     *\n     * ! Amazon S3 only supports symmetric encryption KMS keys. For more information, see Asymmetric keys in Amazon Web\n     * ! Services KMS [^2] in the *Amazon Web Services Key Management Service Developer Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/dev/bucket-encryption.html#bucket-encryption-update-bucket-policy\n     * [^2]: https://docs.aws.amazon.com/kms/latest/developerguide/symmetric-asymmetric.html\n     */\n    private $kmsMasterKeyId;\n\n    /**\n     * @param array{\n     *   SSEAlgorithm: ServerSideEncryption::*,\n     *   KMSMasterKeyID?: null|string,\n     * } $input\n     */\n    public function __construct(array $input)\n    {\n        $this->sseAlgorithm = $input['SSEAlgorithm'] ?? null;\n        $this->kmsMasterKeyId = $input['KMSMasterKeyID'] ?? null;\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    public function getKmsMasterKeyId(): ?string\n    {\n        return $this->kmsMasterKeyId;\n    }\n\n    /**\n     * @return ServerSideEncryption::*\n     */\n    public function getSseAlgorithm(): string\n    {\n        return $this->sseAlgorithm;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/ValueObject/ServerSideEncryptionConfiguration.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\ValueObject;\n\n/**\n * Specifies the default server-side-encryption configuration.\n */\nfinal class ServerSideEncryptionConfiguration\n{\n    /**\n     * Container for information about a particular server-side encryption configuration rule.\n     */\n    private $rules;\n\n    /**\n     * @param array{\n     *   Rules: ServerSideEncryptionRule[],\n     * } $input\n     */\n    public function __construct(array $input)\n    {\n        $this->rules = isset($input['Rules']) ? array_map([ServerSideEncryptionRule::class, 'create'], $input['Rules']) : null;\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    /**\n     * @return ServerSideEncryptionRule[]\n     */\n    public function getRules(): array\n    {\n        return $this->rules ?? [];\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/ValueObject/ServerSideEncryptionRule.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\ValueObject;\n\n/**\n * Specifies the default server-side encryption configuration.\n */\nfinal class ServerSideEncryptionRule\n{\n    /**\n     * Specifies the default server-side encryption to apply to new objects in the bucket. If a PUT Object request doesn't\n     * specify any server-side encryption, this default encryption will be applied.\n     */\n    private $applyServerSideEncryptionByDefault;\n\n    /**\n     * Specifies whether Amazon S3 should use an S3 Bucket Key with server-side encryption using KMS (SSE-KMS) for new\n     * objects in the bucket. Existing objects are not affected. Setting the `BucketKeyEnabled` element to `true` causes\n     * Amazon S3 to use an S3 Bucket Key. By default, S3 Bucket Key is not enabled.\n     *\n     * For more information, see Amazon S3 Bucket Keys [^1] in the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/dev/bucket-key.html\n     */\n    private $bucketKeyEnabled;\n\n    /**\n     * @param array{\n     *   ApplyServerSideEncryptionByDefault?: null|ServerSideEncryptionByDefault|array,\n     *   BucketKeyEnabled?: null|bool,\n     * } $input\n     */\n    public function __construct(array $input)\n    {\n        $this->applyServerSideEncryptionByDefault = isset($input['ApplyServerSideEncryptionByDefault']) ? ServerSideEncryptionByDefault::create($input['ApplyServerSideEncryptionByDefault']) : null;\n        $this->bucketKeyEnabled = $input['BucketKeyEnabled'] ?? null;\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    public function getApplyServerSideEncryptionByDefault(): ?ServerSideEncryptionByDefault\n    {\n        return $this->applyServerSideEncryptionByDefault;\n    }\n\n    public function getBucketKeyEnabled(): ?bool\n    {\n        return $this->bucketKeyEnabled;\n    }\n}\n"
  },
  {
    "path": "server/vendor/async-aws/s3/src/ValueObject/TopicConfiguration.php",
    "content": "<?php\n\nnamespace AsyncAws\\S3\\ValueObject;\n\nuse AsyncAws\\Core\\Exception\\InvalidArgument;\nuse AsyncAws\\S3\\Enum\\Event;\n\n/**\n * A container for specifying the configuration for publication of messages to an Amazon Simple Notification Service\n * (Amazon SNS) topic when Amazon S3 detects specified events.\n */\nfinal class TopicConfiguration\n{\n    private $id;\n\n    /**\n     * The Amazon Resource Name (ARN) of the Amazon SNS topic to which Amazon S3 publishes a message when it detects events\n     * of the specified type.\n     */\n    private $topicArn;\n\n    /**\n     * The Amazon S3 bucket event about which to send notifications. For more information, see Supported Event Types [^1] in\n     * the *Amazon S3 User Guide*.\n     *\n     * [^1]: https://docs.aws.amazon.com/AmazonS3/latest/dev/NotificationHowTo.html\n     */\n    private $events;\n\n    private $filter;\n\n    /**\n     * @param array{\n     *   Id?: null|string,\n     *   TopicArn: string,\n     *   Events: list<Event::*>,\n     *   Filter?: null|NotificationConfigurationFilter|array,\n     * } $input\n     */\n    public function __construct(array $input)\n    {\n        $this->id = $input['Id'] ?? null;\n        $this->topicArn = $input['TopicArn'] ?? null;\n        $this->events = $input['Events'] ?? null;\n        $this->filter = isset($input['Filter']) ? NotificationConfigurationFilter::create($input['Filter']) : null;\n    }\n\n    public static function create($input): self\n    {\n        return $input instanceof self ? $input : new self($input);\n    }\n\n    /**\n     * @return list<Event::*>\n     */\n    public function getEvents(): array\n    {\n        return $this->events ?? [];\n    }\n\n    public function getFilter(): ?NotificationConfigurationFilter\n    {\n        return $this->filter;\n    }\n\n    public function getId(): ?string\n    {\n        return $this->id;\n    }\n\n    public function getTopicArn(): string\n    {\n        return $this->topicArn;\n    }\n\n    /**\n     * @internal\n     */\n    public function requestBody(\\DOMElement $node, \\DOMDocument $document): void\n    {\n        if (null !== $v = $this->id) {\n            $node->appendChild($document->createElement('Id', $v));\n        }\n        if (null === $v = $this->topicArn) {\n            throw new InvalidArgument(sprintf('Missing parameter \"TopicArn\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        $node->appendChild($document->createElement('Topic', $v));\n        if (null === $v = $this->events) {\n            throw new InvalidArgument(sprintf('Missing parameter \"Events\" for \"%s\". The value cannot be null.', __CLASS__));\n        }\n        foreach ($v as $item) {\n            if (!Event::exists($item)) {\n                throw new InvalidArgument(sprintf('Invalid parameter \"Event\" for \"%s\". The value \"%s\" is not a valid \"Event\".', __CLASS__, $item));\n            }\n            $node->appendChild($document->createElement('Event', $item));\n        }\n\n        if (null !== $v = $this->filter) {\n            $node->appendChild($child = $document->createElement('Filter'));\n\n            $v->requestBody($child, $document);\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/autoload.php",
    "content": "<?php\n\n// autoload.php @generated by Composer\n\nif (PHP_VERSION_ID < 50600) {\n    if (!headers_sent()) {\n        header('HTTP/1.1 500 Internal Server Error');\n    }\n    $err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via \"composer self-update --2.2\". Aborting.'.PHP_EOL;\n    if (!ini_get('display_errors')) {\n        if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {\n            fwrite(STDERR, $err);\n        } elseif (!headers_sent()) {\n            echo $err;\n        }\n    }\n    trigger_error(\n        $err,\n        E_USER_ERROR\n    );\n}\n\nrequire_once __DIR__ . '/composer/autoload_real.php';\n\nreturn ComposerAutoloaderInit434a4eb2fb23c7f559a3771baabf0fbb::getLoader();\n"
  },
  {
    "path": "server/vendor/bin/carbon",
    "content": "#!/usr/bin/env php\n<?php\n\n/**\n * Proxy PHP file generated by Composer\n *\n * This file includes the referenced bin path (../nesbot/carbon/bin/carbon)\n * using a stream wrapper to prevent the shebang from being output on PHP<8\n *\n * @generated\n */\n\nnamespace Composer;\n\n$GLOBALS['_composer_bin_dir'] = __DIR__;\n$GLOBALS['_composer_autoload_path'] = __DIR__ . '/..'.'/autoload.php';\n\nif (PHP_VERSION_ID < 80000) {\n    if (!class_exists('Composer\\BinProxyWrapper')) {\n        /**\n         * @internal\n         */\n        final class BinProxyWrapper\n        {\n            private $handle;\n            private $position;\n            private $realpath;\n\n            public function stream_open($path, $mode, $options, &$opened_path)\n            {\n                // get rid of phpvfscomposer:// prefix for __FILE__ & __DIR__ resolution\n                $opened_path = substr($path, 17);\n                $this->realpath = realpath($opened_path) ?: $opened_path;\n                $opened_path = $this->realpath;\n                $this->handle = fopen($this->realpath, $mode);\n                $this->position = 0;\n\n                return (bool) $this->handle;\n            }\n\n            public function stream_read($count)\n            {\n                $data = fread($this->handle, $count);\n\n                if ($this->position === 0) {\n                    $data = preg_replace('{^#!.*\\r?\\n}', '', $data);\n                }\n\n                $this->position += strlen($data);\n\n                return $data;\n            }\n\n            public function stream_cast($castAs)\n            {\n                return $this->handle;\n            }\n\n            public function stream_close()\n            {\n                fclose($this->handle);\n            }\n\n            public function stream_lock($operation)\n            {\n                return $operation ? flock($this->handle, $operation) : true;\n            }\n\n            public function stream_seek($offset, $whence)\n            {\n                if (0 === fseek($this->handle, $offset, $whence)) {\n                    $this->position = ftell($this->handle);\n                    return true;\n                }\n\n                return false;\n            }\n\n            public function stream_tell()\n            {\n                return $this->position;\n            }\n\n            public function stream_eof()\n            {\n                return feof($this->handle);\n            }\n\n            public function stream_stat()\n            {\n                return array();\n            }\n\n            public function stream_set_option($option, $arg1, $arg2)\n            {\n                return true;\n            }\n\n            public function url_stat($path, $flags)\n            {\n                $path = substr($path, 17);\n                if (file_exists($path)) {\n                    return stat($path);\n                }\n\n                return false;\n            }\n        }\n    }\n\n    if (\n        (function_exists('stream_get_wrappers') && in_array('phpvfscomposer', stream_get_wrappers(), true))\n        || (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\\BinProxyWrapper'))\n    ) {\n        return include(\"phpvfscomposer://\" . __DIR__ . '/..'.'/nesbot/carbon/bin/carbon');\n    }\n}\n\nreturn include __DIR__ . '/..'.'/nesbot/carbon/bin/carbon';\n"
  },
  {
    "path": "server/vendor/carbonphp/carbon-doctrine-types/LICENSE",
    "content": "MIT License\n\nCopyright (c) 2023 Carbon\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "server/vendor/carbonphp/carbon-doctrine-types/README.md",
    "content": "# carbonphp/carbon-doctrine-types\n\nTypes to use Carbon in Doctrine\n\n## Documentation\n\n[Check how to use in the official Carbon documentation](https://carbon.nesbot.com/symfony/)\n\nThis package is an externalization of [src/Carbon/Doctrine](https://github.com/briannesbitt/Carbon/tree/2.71.0/src/Carbon/Doctrine)\nfrom `nestbot/carbon` package.\n\nExternalization allows to better deal with different versions of dbal. With\nversion 4.0 of dbal, it no longer sustainable to be compatible with all version\nusing a single code.\n"
  },
  {
    "path": "server/vendor/carbonphp/carbon-doctrine-types/composer.json",
    "content": "{\n    \"name\": \"carbonphp/carbon-doctrine-types\",\n    \"description\": \"Types to use Carbon in Doctrine\",\n    \"type\": \"library\",\n    \"keywords\": [\n        \"date\",\n        \"time\",\n        \"DateTime\",\n        \"Carbon\",\n        \"Doctrine\"\n    ],\n    \"require\": {\n        \"php\": \"^8.1\"\n    },\n    \"require-dev\": {\n        \"doctrine/dbal\": \"^4.0.0\",\n        \"nesbot/carbon\": \"^2.71.0 || ^3.0.0\",\n        \"phpunit/phpunit\": \"^10.3\"\n    },\n    \"conflict\": {\n        \"doctrine/dbal\": \"<4.0.0 || >=5.0.0\"\n    },\n    \"license\": \"MIT\",\n    \"autoload\": {\n        \"psr-4\": {\n            \"Carbon\\\\Doctrine\\\\\": \"src/Carbon/Doctrine/\"\n        }\n    },\n    \"authors\": [\n        {\n            \"name\": \"KyleKatarn\",\n            \"email\": \"kylekatarnls@gmail.com\"\n        }\n    ],\n    \"minimum-stability\": \"dev\"\n}\n"
  },
  {
    "path": "server/vendor/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine/CarbonDoctrineType.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Carbon\\Doctrine;\n\nuse Doctrine\\DBAL\\Platforms\\AbstractPlatform;\n\ninterface CarbonDoctrineType\n{\n    public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform);\n\n    public function convertToPHPValue(mixed $value, AbstractPlatform $platform);\n\n    public function convertToDatabaseValue($value, AbstractPlatform $platform);\n}\n"
  },
  {
    "path": "server/vendor/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine/CarbonImmutableType.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Carbon\\Doctrine;\n\nclass CarbonImmutableType extends DateTimeImmutableType implements CarbonDoctrineType\n{\n}\n"
  },
  {
    "path": "server/vendor/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine/CarbonType.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Carbon\\Doctrine;\n\nclass CarbonType extends DateTimeType implements CarbonDoctrineType\n{\n}\n"
  },
  {
    "path": "server/vendor/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine/CarbonTypeConverter.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Carbon\\Doctrine;\n\nuse Carbon\\Carbon;\nuse Carbon\\CarbonInterface;\nuse DateTimeInterface;\nuse Doctrine\\DBAL\\Platforms\\AbstractPlatform;\nuse Doctrine\\DBAL\\Platforms\\DB2Platform;\nuse Doctrine\\DBAL\\Platforms\\OraclePlatform;\nuse Doctrine\\DBAL\\Platforms\\SQLitePlatform;\nuse Doctrine\\DBAL\\Platforms\\SQLServerPlatform;\nuse Doctrine\\DBAL\\Types\\Exception\\InvalidType;\nuse Doctrine\\DBAL\\Types\\Exception\\ValueNotConvertible;\nuse Exception;\n\n/**\n * @template T of CarbonInterface\n */\ntrait CarbonTypeConverter\n{\n    /**\n     * This property differentiates types installed by carbonphp/carbon-doctrine-types\n     * from the ones embedded previously in nesbot/carbon source directly.\n     *\n     * @readonly\n     */\n    public bool $external = true;\n\n    /**\n     * @return class-string<T>\n     */\n    protected function getCarbonClassName(): string\n    {\n        return Carbon::class;\n    }\n\n    public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform): string\n    {\n        $precision = min(\n            $fieldDeclaration['precision'] ?? DateTimeDefaultPrecision::get(),\n            $this->getMaximumPrecision($platform),\n        );\n\n        $type = parent::getSQLDeclaration($fieldDeclaration, $platform);\n\n        if (!$precision) {\n            return $type;\n        }\n\n        if (str_contains($type, '(')) {\n            return preg_replace('/\\(\\d+\\)/', \"($precision)\", $type);\n        }\n\n        [$before, $after] = explode(' ', \"$type \");\n\n        return trim(\"$before($precision) $after\");\n    }\n\n    /**\n     * @SuppressWarnings(PHPMD.UnusedFormalParameter)\n     */\n    public function convertToDatabaseValue($value, AbstractPlatform $platform): ?string\n    {\n        if ($value === null) {\n            return $value;\n        }\n\n        if ($value instanceof DateTimeInterface) {\n            return $value->format('Y-m-d H:i:s.u');\n        }\n\n        throw InvalidType::new(\n            $value,\n            static::class,\n            ['null', 'DateTime', 'Carbon']\n        );\n    }\n\n    private function doConvertToPHPValue(mixed $value)\n    {\n        $class = $this->getCarbonClassName();\n\n        if ($value === null || is_a($value, $class)) {\n            return $value;\n        }\n\n        if ($value instanceof DateTimeInterface) {\n            return $class::instance($value);\n        }\n\n        $date = null;\n        $error = null;\n\n        try {\n            $date = $class::parse($value);\n        } catch (Exception $exception) {\n            $error = $exception;\n        }\n\n        if (!$date) {\n            throw ValueNotConvertible::new(\n                $value,\n                static::class,\n                'Y-m-d H:i:s.u or any format supported by '.$class.'::parse()',\n                $error\n            );\n        }\n\n        return $date;\n    }\n\n    private function getMaximumPrecision(AbstractPlatform $platform): int\n    {\n        if ($platform instanceof DB2Platform) {\n            return 12;\n        }\n\n        if ($platform instanceof OraclePlatform) {\n            return 9;\n        }\n\n        if ($platform instanceof SQLServerPlatform || $platform instanceof SQLitePlatform) {\n            return 3;\n        }\n\n        return 6;\n    }\n}\n"
  },
  {
    "path": "server/vendor/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine/DateTimeDefaultPrecision.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Carbon\\Doctrine;\n\nclass DateTimeDefaultPrecision\n{\n    private static $precision = 6;\n\n    /**\n     * Change the default Doctrine datetime and datetime_immutable precision.\n     *\n     * @param int $precision\n     */\n    public static function set(int $precision): void\n    {\n        self::$precision = $precision;\n    }\n\n    /**\n     * Get the default Doctrine datetime and datetime_immutable precision.\n     *\n     * @return int\n     */\n    public static function get(): int\n    {\n        return self::$precision;\n    }\n}\n"
  },
  {
    "path": "server/vendor/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine/DateTimeImmutableType.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Carbon\\Doctrine;\n\nuse Carbon\\CarbonImmutable;\nuse DateTimeImmutable;\nuse Doctrine\\DBAL\\Platforms\\AbstractPlatform;\nuse Doctrine\\DBAL\\Types\\VarDateTimeImmutableType;\n\nclass DateTimeImmutableType extends VarDateTimeImmutableType implements CarbonDoctrineType\n{\n    /** @use CarbonTypeConverter<CarbonImmutable> */\n    use CarbonTypeConverter;\n\n    /**\n     * @SuppressWarnings(PHPMD.UnusedFormalParameter)\n     */\n    public function convertToPHPValue(mixed $value, AbstractPlatform $platform): ?CarbonImmutable\n    {\n        return $this->doConvertToPHPValue($value);\n    }\n\n    /**\n     * @return class-string<CarbonImmutable>\n     */\n    protected function getCarbonClassName(): string\n    {\n        return CarbonImmutable::class;\n    }\n}\n"
  },
  {
    "path": "server/vendor/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine/DateTimeType.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Carbon\\Doctrine;\n\nuse Carbon\\Carbon;\nuse DateTime;\nuse Doctrine\\DBAL\\Platforms\\AbstractPlatform;\nuse Doctrine\\DBAL\\Types\\VarDateTimeType;\n\nclass DateTimeType extends VarDateTimeType implements CarbonDoctrineType\n{\n    /** @use CarbonTypeConverter<Carbon> */\n    use CarbonTypeConverter;\n\n    /**\n     * @SuppressWarnings(PHPMD.UnusedFormalParameter)\n     */\n    public function convertToPHPValue(mixed $value, AbstractPlatform $platform): ?Carbon\n    {\n        return $this->doConvertToPHPValue($value);\n    }\n}\n"
  },
  {
    "path": "server/vendor/composer/ClassLoader.php",
    "content": "<?php\n\n/*\n * This file is part of Composer.\n *\n * (c) Nils Adermann <naderman@naderman.de>\n *     Jordi Boggiano <j.boggiano@seld.be>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Composer\\Autoload;\n\n/**\n * ClassLoader implements a PSR-0, PSR-4 and classmap class loader.\n *\n *     $loader = new \\Composer\\Autoload\\ClassLoader();\n *\n *     // register classes with namespaces\n *     $loader->add('Symfony\\Component', __DIR__.'/component');\n *     $loader->add('Symfony',           __DIR__.'/framework');\n *\n *     // activate the autoloader\n *     $loader->register();\n *\n *     // to enable searching the include path (eg. for PEAR packages)\n *     $loader->setUseIncludePath(true);\n *\n * In this example, if you try to use a class in the Symfony\\Component\n * namespace or one of its children (Symfony\\Component\\Console for instance),\n * the autoloader will first look for the class under the component/\n * directory, and it will then fallback to the framework/ directory if not\n * found before giving up.\n *\n * This class is loosely based on the Symfony UniversalClassLoader.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n * @author Jordi Boggiano <j.boggiano@seld.be>\n * @see    https://www.php-fig.org/psr/psr-0/\n * @see    https://www.php-fig.org/psr/psr-4/\n */\nclass ClassLoader\n{\n    /** @var \\Closure(string):void */\n    private static $includeFile;\n\n    /** @var string|null */\n    private $vendorDir;\n\n    // PSR-4\n    /**\n     * @var array<string, array<string, int>>\n     */\n    private $prefixLengthsPsr4 = array();\n    /**\n     * @var array<string, list<string>>\n     */\n    private $prefixDirsPsr4 = array();\n    /**\n     * @var list<string>\n     */\n    private $fallbackDirsPsr4 = array();\n\n    // PSR-0\n    /**\n     * List of PSR-0 prefixes\n     *\n     * Structured as array('F (first letter)' => array('Foo\\Bar (full prefix)' => array('path', 'path2')))\n     *\n     * @var array<string, array<string, list<string>>>\n     */\n    private $prefixesPsr0 = array();\n    /**\n     * @var list<string>\n     */\n    private $fallbackDirsPsr0 = array();\n\n    /** @var bool */\n    private $useIncludePath = false;\n\n    /**\n     * @var array<string, string>\n     */\n    private $classMap = array();\n\n    /** @var bool */\n    private $classMapAuthoritative = false;\n\n    /**\n     * @var array<string, bool>\n     */\n    private $missingClasses = array();\n\n    /** @var string|null */\n    private $apcuPrefix;\n\n    /**\n     * @var array<string, self>\n     */\n    private static $registeredLoaders = array();\n\n    /**\n     * @param string|null $vendorDir\n     */\n    public function __construct($vendorDir = null)\n    {\n        $this->vendorDir = $vendorDir;\n        self::initializeIncludeClosure();\n    }\n\n    /**\n     * @return array<string, list<string>>\n     */\n    public function getPrefixes()\n    {\n        if (!empty($this->prefixesPsr0)) {\n            return call_user_func_array('array_merge', array_values($this->prefixesPsr0));\n        }\n\n        return array();\n    }\n\n    /**\n     * @return array<string, list<string>>\n     */\n    public function getPrefixesPsr4()\n    {\n        return $this->prefixDirsPsr4;\n    }\n\n    /**\n     * @return list<string>\n     */\n    public function getFallbackDirs()\n    {\n        return $this->fallbackDirsPsr0;\n    }\n\n    /**\n     * @return list<string>\n     */\n    public function getFallbackDirsPsr4()\n    {\n        return $this->fallbackDirsPsr4;\n    }\n\n    /**\n     * @return array<string, string> Array of classname => path\n     */\n    public function getClassMap()\n    {\n        return $this->classMap;\n    }\n\n    /**\n     * @param array<string, string> $classMap Class to filename map\n     *\n     * @return void\n     */\n    public function addClassMap(array $classMap)\n    {\n        if ($this->classMap) {\n            $this->classMap = array_merge($this->classMap, $classMap);\n        } else {\n            $this->classMap = $classMap;\n        }\n    }\n\n    /**\n     * Registers a set of PSR-0 directories for a given prefix, either\n     * appending or prepending to the ones previously set for this prefix.\n     *\n     * @param string              $prefix  The prefix\n     * @param list<string>|string $paths   The PSR-0 root directories\n     * @param bool                $prepend Whether to prepend the directories\n     *\n     * @return void\n     */\n    public function add($prefix, $paths, $prepend = false)\n    {\n        $paths = (array) $paths;\n        if (!$prefix) {\n            if ($prepend) {\n                $this->fallbackDirsPsr0 = array_merge(\n                    $paths,\n                    $this->fallbackDirsPsr0\n                );\n            } else {\n                $this->fallbackDirsPsr0 = array_merge(\n                    $this->fallbackDirsPsr0,\n                    $paths\n                );\n            }\n\n            return;\n        }\n\n        $first = $prefix[0];\n        if (!isset($this->prefixesPsr0[$first][$prefix])) {\n            $this->prefixesPsr0[$first][$prefix] = $paths;\n\n            return;\n        }\n        if ($prepend) {\n            $this->prefixesPsr0[$first][$prefix] = array_merge(\n                $paths,\n                $this->prefixesPsr0[$first][$prefix]\n            );\n        } else {\n            $this->prefixesPsr0[$first][$prefix] = array_merge(\n                $this->prefixesPsr0[$first][$prefix],\n                $paths\n            );\n        }\n    }\n\n    /**\n     * Registers a set of PSR-4 directories for a given namespace, either\n     * appending or prepending to the ones previously set for this namespace.\n     *\n     * @param string              $prefix  The prefix/namespace, with trailing '\\\\'\n     * @param list<string>|string $paths   The PSR-4 base directories\n     * @param bool                $prepend Whether to prepend the directories\n     *\n     * @throws \\InvalidArgumentException\n     *\n     * @return void\n     */\n    public function addPsr4($prefix, $paths, $prepend = false)\n    {\n        $paths = (array) $paths;\n        if (!$prefix) {\n            // Register directories for the root namespace.\n            if ($prepend) {\n                $this->fallbackDirsPsr4 = array_merge(\n                    $paths,\n                    $this->fallbackDirsPsr4\n                );\n            } else {\n                $this->fallbackDirsPsr4 = array_merge(\n                    $this->fallbackDirsPsr4,\n                    $paths\n                );\n            }\n        } elseif (!isset($this->prefixDirsPsr4[$prefix])) {\n            // Register directories for a new namespace.\n            $length = strlen($prefix);\n            if ('\\\\' !== $prefix[$length - 1]) {\n                throw new \\InvalidArgumentException(\"A non-empty PSR-4 prefix must end with a namespace separator.\");\n            }\n            $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;\n            $this->prefixDirsPsr4[$prefix] = $paths;\n        } elseif ($prepend) {\n            // Prepend directories for an already registered namespace.\n            $this->prefixDirsPsr4[$prefix] = array_merge(\n                $paths,\n                $this->prefixDirsPsr4[$prefix]\n            );\n        } else {\n            // Append directories for an already registered namespace.\n            $this->prefixDirsPsr4[$prefix] = array_merge(\n                $this->prefixDirsPsr4[$prefix],\n                $paths\n            );\n        }\n    }\n\n    /**\n     * Registers a set of PSR-0 directories for a given prefix,\n     * replacing any others previously set for this prefix.\n     *\n     * @param string              $prefix The prefix\n     * @param list<string>|string $paths  The PSR-0 base directories\n     *\n     * @return void\n     */\n    public function set($prefix, $paths)\n    {\n        if (!$prefix) {\n            $this->fallbackDirsPsr0 = (array) $paths;\n        } else {\n            $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;\n        }\n    }\n\n    /**\n     * Registers a set of PSR-4 directories for a given namespace,\n     * replacing any others previously set for this namespace.\n     *\n     * @param string              $prefix The prefix/namespace, with trailing '\\\\'\n     * @param list<string>|string $paths  The PSR-4 base directories\n     *\n     * @throws \\InvalidArgumentException\n     *\n     * @return void\n     */\n    public function setPsr4($prefix, $paths)\n    {\n        if (!$prefix) {\n            $this->fallbackDirsPsr4 = (array) $paths;\n        } else {\n            $length = strlen($prefix);\n            if ('\\\\' !== $prefix[$length - 1]) {\n                throw new \\InvalidArgumentException(\"A non-empty PSR-4 prefix must end with a namespace separator.\");\n            }\n            $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;\n            $this->prefixDirsPsr4[$prefix] = (array) $paths;\n        }\n    }\n\n    /**\n     * Turns on searching the include path for class files.\n     *\n     * @param bool $useIncludePath\n     *\n     * @return void\n     */\n    public function setUseIncludePath($useIncludePath)\n    {\n        $this->useIncludePath = $useIncludePath;\n    }\n\n    /**\n     * Can be used to check if the autoloader uses the include path to check\n     * for classes.\n     *\n     * @return bool\n     */\n    public function getUseIncludePath()\n    {\n        return $this->useIncludePath;\n    }\n\n    /**\n     * Turns off searching the prefix and fallback directories for classes\n     * that have not been registered with the class map.\n     *\n     * @param bool $classMapAuthoritative\n     *\n     * @return void\n     */\n    public function setClassMapAuthoritative($classMapAuthoritative)\n    {\n        $this->classMapAuthoritative = $classMapAuthoritative;\n    }\n\n    /**\n     * Should class lookup fail if not found in the current class map?\n     *\n     * @return bool\n     */\n    public function isClassMapAuthoritative()\n    {\n        return $this->classMapAuthoritative;\n    }\n\n    /**\n     * APCu prefix to use to cache found/not-found classes, if the extension is enabled.\n     *\n     * @param string|null $apcuPrefix\n     *\n     * @return void\n     */\n    public function setApcuPrefix($apcuPrefix)\n    {\n        $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;\n    }\n\n    /**\n     * The APCu prefix in use, or null if APCu caching is not enabled.\n     *\n     * @return string|null\n     */\n    public function getApcuPrefix()\n    {\n        return $this->apcuPrefix;\n    }\n\n    /**\n     * Registers this instance as an autoloader.\n     *\n     * @param bool $prepend Whether to prepend the autoloader or not\n     *\n     * @return void\n     */\n    public function register($prepend = false)\n    {\n        spl_autoload_register(array($this, 'loadClass'), true, $prepend);\n\n        if (null === $this->vendorDir) {\n            return;\n        }\n\n        if ($prepend) {\n            self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;\n        } else {\n            unset(self::$registeredLoaders[$this->vendorDir]);\n            self::$registeredLoaders[$this->vendorDir] = $this;\n        }\n    }\n\n    /**\n     * Unregisters this instance as an autoloader.\n     *\n     * @return void\n     */\n    public function unregister()\n    {\n        spl_autoload_unregister(array($this, 'loadClass'));\n\n        if (null !== $this->vendorDir) {\n            unset(self::$registeredLoaders[$this->vendorDir]);\n        }\n    }\n\n    /**\n     * Loads the given class or interface.\n     *\n     * @param  string    $class The name of the class\n     * @return true|null True if loaded, null otherwise\n     */\n    public function loadClass($class)\n    {\n        if ($file = $this->findFile($class)) {\n            $includeFile = self::$includeFile;\n            $includeFile($file);\n\n            return true;\n        }\n\n        return null;\n    }\n\n    /**\n     * Finds the path to the file where the class is defined.\n     *\n     * @param string $class The name of the class\n     *\n     * @return string|false The path if found, false otherwise\n     */\n    public function findFile($class)\n    {\n        // class map lookup\n        if (isset($this->classMap[$class])) {\n            return $this->classMap[$class];\n        }\n        if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {\n            return false;\n        }\n        if (null !== $this->apcuPrefix) {\n            $file = apcu_fetch($this->apcuPrefix.$class, $hit);\n            if ($hit) {\n                return $file;\n            }\n        }\n\n        $file = $this->findFileWithExtension($class, '.php');\n\n        // Search for Hack files if we are running on HHVM\n        if (false === $file && defined('HHVM_VERSION')) {\n            $file = $this->findFileWithExtension($class, '.hh');\n        }\n\n        if (null !== $this->apcuPrefix) {\n            apcu_add($this->apcuPrefix.$class, $file);\n        }\n\n        if (false === $file) {\n            // Remember that this class does not exist.\n            $this->missingClasses[$class] = true;\n        }\n\n        return $file;\n    }\n\n    /**\n     * Returns the currently registered loaders keyed by their corresponding vendor directories.\n     *\n     * @return array<string, self>\n     */\n    public static function getRegisteredLoaders()\n    {\n        return self::$registeredLoaders;\n    }\n\n    /**\n     * @param  string       $class\n     * @param  string       $ext\n     * @return string|false\n     */\n    private function findFileWithExtension($class, $ext)\n    {\n        // PSR-4 lookup\n        $logicalPathPsr4 = strtr($class, '\\\\', DIRECTORY_SEPARATOR) . $ext;\n\n        $first = $class[0];\n        if (isset($this->prefixLengthsPsr4[$first])) {\n            $subPath = $class;\n            while (false !== $lastPos = strrpos($subPath, '\\\\')) {\n                $subPath = substr($subPath, 0, $lastPos);\n                $search = $subPath . '\\\\';\n                if (isset($this->prefixDirsPsr4[$search])) {\n                    $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);\n                    foreach ($this->prefixDirsPsr4[$search] as $dir) {\n                        if (file_exists($file = $dir . $pathEnd)) {\n                            return $file;\n                        }\n                    }\n                }\n            }\n        }\n\n        // PSR-4 fallback dirs\n        foreach ($this->fallbackDirsPsr4 as $dir) {\n            if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {\n                return $file;\n            }\n        }\n\n        // PSR-0 lookup\n        if (false !== $pos = strrpos($class, '\\\\')) {\n            // namespaced class name\n            $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)\n                . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);\n        } else {\n            // PEAR-like class name\n            $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;\n        }\n\n        if (isset($this->prefixesPsr0[$first])) {\n            foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {\n                if (0 === strpos($class, $prefix)) {\n                    foreach ($dirs as $dir) {\n                        if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {\n                            return $file;\n                        }\n                    }\n                }\n            }\n        }\n\n        // PSR-0 fallback dirs\n        foreach ($this->fallbackDirsPsr0 as $dir) {\n            if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {\n                return $file;\n            }\n        }\n\n        // PSR-0 include paths.\n        if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {\n            return $file;\n        }\n\n        return false;\n    }\n\n    /**\n     * @return void\n     */\n    private static function initializeIncludeClosure()\n    {\n        if (self::$includeFile !== null) {\n            return;\n        }\n\n        /**\n         * Scope isolated include.\n         *\n         * Prevents access to $this/self from included files.\n         *\n         * @param  string $file\n         * @return void\n         */\n        self::$includeFile = \\Closure::bind(static function($file) {\n            include $file;\n        }, null, null);\n    }\n}\n"
  },
  {
    "path": "server/vendor/composer/InstalledVersions.php",
    "content": "<?php\n\n/*\n * This file is part of Composer.\n *\n * (c) Nils Adermann <naderman@naderman.de>\n *     Jordi Boggiano <j.boggiano@seld.be>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Composer;\n\nuse Composer\\Autoload\\ClassLoader;\nuse Composer\\Semver\\VersionParser;\n\n/**\n * This class is copied in every Composer installed project and available to all\n *\n * See also https://getcomposer.org/doc/07-runtime.md#installed-versions\n *\n * To require its presence, you can require `composer-runtime-api ^2.0`\n *\n * @final\n */\nclass InstalledVersions\n{\n    /**\n     * @var mixed[]|null\n     * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null\n     */\n    private static $installed;\n\n    /**\n     * @var bool|null\n     */\n    private static $canGetVendors;\n\n    /**\n     * @var array[]\n     * @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>\n     */\n    private static $installedByVendor = array();\n\n    /**\n     * Returns a list of all package names which are present, either by being installed, replaced or provided\n     *\n     * @return string[]\n     * @psalm-return list<string>\n     */\n    public static function getInstalledPackages()\n    {\n        $packages = array();\n        foreach (self::getInstalled() as $installed) {\n            $packages[] = array_keys($installed['versions']);\n        }\n\n        if (1 === \\count($packages)) {\n            return $packages[0];\n        }\n\n        return array_keys(array_flip(\\call_user_func_array('array_merge', $packages)));\n    }\n\n    /**\n     * Returns a list of all package names with a specific type e.g. 'library'\n     *\n     * @param  string   $type\n     * @return string[]\n     * @psalm-return list<string>\n     */\n    public static function getInstalledPackagesByType($type)\n    {\n        $packagesByType = array();\n\n        foreach (self::getInstalled() as $installed) {\n            foreach ($installed['versions'] as $name => $package) {\n                if (isset($package['type']) && $package['type'] === $type) {\n                    $packagesByType[] = $name;\n                }\n            }\n        }\n\n        return $packagesByType;\n    }\n\n    /**\n     * Checks whether the given package is installed\n     *\n     * This also returns true if the package name is provided or replaced by another package\n     *\n     * @param  string $packageName\n     * @param  bool   $includeDevRequirements\n     * @return bool\n     */\n    public static function isInstalled($packageName, $includeDevRequirements = true)\n    {\n        foreach (self::getInstalled() as $installed) {\n            if (isset($installed['versions'][$packageName])) {\n                return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false;\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * Checks whether the given package satisfies a version constraint\n     *\n     * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:\n     *\n     *   Composer\\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')\n     *\n     * @param  VersionParser $parser      Install composer/semver to have access to this class and functionality\n     * @param  string        $packageName\n     * @param  string|null   $constraint  A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package\n     * @return bool\n     */\n    public static function satisfies(VersionParser $parser, $packageName, $constraint)\n    {\n        $constraint = $parser->parseConstraints((string) $constraint);\n        $provided = $parser->parseConstraints(self::getVersionRanges($packageName));\n\n        return $provided->matches($constraint);\n    }\n\n    /**\n     * Returns a version constraint representing all the range(s) which are installed for a given package\n     *\n     * It is easier to use this via isInstalled() with the $constraint argument if you need to check\n     * whether a given version of a package is installed, and not just whether it exists\n     *\n     * @param  string $packageName\n     * @return string Version constraint usable with composer/semver\n     */\n    public static function getVersionRanges($packageName)\n    {\n        foreach (self::getInstalled() as $installed) {\n            if (!isset($installed['versions'][$packageName])) {\n                continue;\n            }\n\n            $ranges = array();\n            if (isset($installed['versions'][$packageName]['pretty_version'])) {\n                $ranges[] = $installed['versions'][$packageName]['pretty_version'];\n            }\n            if (array_key_exists('aliases', $installed['versions'][$packageName])) {\n                $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);\n            }\n            if (array_key_exists('replaced', $installed['versions'][$packageName])) {\n                $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);\n            }\n            if (array_key_exists('provided', $installed['versions'][$packageName])) {\n                $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);\n            }\n\n            return implode(' || ', $ranges);\n        }\n\n        throw new \\OutOfBoundsException('Package \"' . $packageName . '\" is not installed');\n    }\n\n    /**\n     * @param  string      $packageName\n     * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present\n     */\n    public static function getVersion($packageName)\n    {\n        foreach (self::getInstalled() as $installed) {\n            if (!isset($installed['versions'][$packageName])) {\n                continue;\n            }\n\n            if (!isset($installed['versions'][$packageName]['version'])) {\n                return null;\n            }\n\n            return $installed['versions'][$packageName]['version'];\n        }\n\n        throw new \\OutOfBoundsException('Package \"' . $packageName . '\" is not installed');\n    }\n\n    /**\n     * @param  string      $packageName\n     * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present\n     */\n    public static function getPrettyVersion($packageName)\n    {\n        foreach (self::getInstalled() as $installed) {\n            if (!isset($installed['versions'][$packageName])) {\n                continue;\n            }\n\n            if (!isset($installed['versions'][$packageName]['pretty_version'])) {\n                return null;\n            }\n\n            return $installed['versions'][$packageName]['pretty_version'];\n        }\n\n        throw new \\OutOfBoundsException('Package \"' . $packageName . '\" is not installed');\n    }\n\n    /**\n     * @param  string      $packageName\n     * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference\n     */\n    public static function getReference($packageName)\n    {\n        foreach (self::getInstalled() as $installed) {\n            if (!isset($installed['versions'][$packageName])) {\n                continue;\n            }\n\n            if (!isset($installed['versions'][$packageName]['reference'])) {\n                return null;\n            }\n\n            return $installed['versions'][$packageName]['reference'];\n        }\n\n        throw new \\OutOfBoundsException('Package \"' . $packageName . '\" is not installed');\n    }\n\n    /**\n     * @param  string      $packageName\n     * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.\n     */\n    public static function getInstallPath($packageName)\n    {\n        foreach (self::getInstalled() as $installed) {\n            if (!isset($installed['versions'][$packageName])) {\n                continue;\n            }\n\n            return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;\n        }\n\n        throw new \\OutOfBoundsException('Package \"' . $packageName . '\" is not installed');\n    }\n\n    /**\n     * @return array\n     * @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}\n     */\n    public static function getRootPackage()\n    {\n        $installed = self::getInstalled();\n\n        return $installed[0]['root'];\n    }\n\n    /**\n     * Returns the raw installed.php data for custom implementations\n     *\n     * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.\n     * @return array[]\n     * @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}\n     */\n    public static function getRawData()\n    {\n        @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);\n\n        if (null === self::$installed) {\n            // only require the installed.php file if this file is loaded from its dumped location,\n            // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937\n            if (substr(__DIR__, -8, 1) !== 'C') {\n                self::$installed = include __DIR__ . '/installed.php';\n            } else {\n                self::$installed = array();\n            }\n        }\n\n        return self::$installed;\n    }\n\n    /**\n     * Returns the raw data of all installed.php which are currently loaded for custom implementations\n     *\n     * @return array[]\n     * @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>\n     */\n    public static function getAllRawData()\n    {\n        return self::getInstalled();\n    }\n\n    /**\n     * Lets you reload the static array from another file\n     *\n     * This is only useful for complex integrations in which a project needs to use\n     * this class but then also needs to execute another project's autoloader in process,\n     * and wants to ensure both projects have access to their version of installed.php.\n     *\n     * A typical case would be PHPUnit, where it would need to make sure it reads all\n     * the data it needs from this class, then call reload() with\n     * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure\n     * the project in which it runs can then also use this class safely, without\n     * interference between PHPUnit's dependencies and the project's dependencies.\n     *\n     * @param  array[] $data A vendor/composer/installed.php data set\n     * @return void\n     *\n     * @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data\n     */\n    public static function reload($data)\n    {\n        self::$installed = $data;\n        self::$installedByVendor = array();\n    }\n\n    /**\n     * @return array[]\n     * @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>\n     */\n    private static function getInstalled()\n    {\n        if (null === self::$canGetVendors) {\n            self::$canGetVendors = method_exists('Composer\\Autoload\\ClassLoader', 'getRegisteredLoaders');\n        }\n\n        $installed = array();\n\n        if (self::$canGetVendors) {\n            foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {\n                if (isset(self::$installedByVendor[$vendorDir])) {\n                    $installed[] = self::$installedByVendor[$vendorDir];\n                } elseif (is_file($vendorDir.'/composer/installed.php')) {\n                    /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */\n                    $required = require $vendorDir.'/composer/installed.php';\n                    $installed[] = self::$installedByVendor[$vendorDir] = $required;\n                    if (null === self::$installed && strtr($vendorDir.'/composer', '\\\\', '/') === strtr(__DIR__, '\\\\', '/')) {\n                        self::$installed = $installed[count($installed) - 1];\n                    }\n                }\n            }\n        }\n\n        if (null === self::$installed) {\n            // only require the installed.php file if this file is loaded from its dumped location,\n            // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937\n            if (substr(__DIR__, -8, 1) !== 'C') {\n                /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */\n                $required = require __DIR__ . '/installed.php';\n                self::$installed = $required;\n            } else {\n                self::$installed = array();\n            }\n        }\n\n        if (self::$installed !== array()) {\n            $installed[] = self::$installed;\n        }\n\n        return $installed;\n    }\n}\n"
  },
  {
    "path": "server/vendor/composer/LICENSE",
    "content": "\nCopyright (c) Nils Adermann, Jordi Boggiano\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is furnished\nto do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n\n"
  },
  {
    "path": "server/vendor/composer/autoload_classmap.php",
    "content": "<?php\n\n// autoload_classmap.php @generated by Composer\n\n$vendorDir = dirname(__DIR__);\n$baseDir = dirname(dirname($vendorDir));\n\nreturn array(\n    'Attribute' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',\n    'CAS_AuthenticationException' => $vendorDir . '/jasig/phpcas/source/CAS/AuthenticationException.php',\n    'CAS_Client' => $vendorDir . '/jasig/phpcas/source/CAS/Client.php',\n    'CAS_CookieJar' => $vendorDir . '/jasig/phpcas/source/CAS/CookieJar.php',\n    'CAS_Exception' => $vendorDir . '/jasig/phpcas/source/CAS/Exception.php',\n    'CAS_GracefullTerminationException' => $vendorDir . '/jasig/phpcas/source/CAS/GracefullTerminationException.php',\n    'CAS_InvalidArgumentException' => $vendorDir . '/jasig/phpcas/source/CAS/InvalidArgumentException.php',\n    'CAS_Languages_Catalan' => $vendorDir . '/jasig/phpcas/source/CAS/Languages/Catalan.php',\n    'CAS_Languages_ChineseSimplified' => $vendorDir . '/jasig/phpcas/source/CAS/Languages/ChineseSimplified.php',\n    'CAS_Languages_English' => $vendorDir . '/jasig/phpcas/source/CAS/Languages/English.php',\n    'CAS_Languages_French' => $vendorDir . '/jasig/phpcas/source/CAS/Languages/French.php',\n    'CAS_Languages_Galego' => $vendorDir . '/jasig/phpcas/source/CAS/Languages/Galego.php',\n    'CAS_Languages_German' => $vendorDir . '/jasig/phpcas/source/CAS/Languages/German.php',\n    'CAS_Languages_Greek' => $vendorDir . '/jasig/phpcas/source/CAS/Languages/Greek.php',\n    'CAS_Languages_Japanese' => $vendorDir . '/jasig/phpcas/source/CAS/Languages/Japanese.php',\n    'CAS_Languages_LanguageInterface' => $vendorDir . '/jasig/phpcas/source/CAS/Languages/LanguageInterface.php',\n    'CAS_Languages_Portuguese' => $vendorDir . '/jasig/phpcas/source/CAS/Languages/Portuguese.php',\n    'CAS_Languages_Spanish' => $vendorDir . '/jasig/phpcas/source/CAS/Languages/Spanish.php',\n    'CAS_OutOfSequenceBeforeAuthenticationCallException' => $vendorDir . '/jasig/phpcas/source/CAS/OutOfSequenceBeforeAuthenticationCallException.php',\n    'CAS_OutOfSequenceBeforeClientException' => $vendorDir . '/jasig/phpcas/source/CAS/OutOfSequenceBeforeClientException.php',\n    'CAS_OutOfSequenceBeforeProxyException' => $vendorDir . '/jasig/phpcas/source/CAS/OutOfSequenceBeforeProxyException.php',\n    'CAS_OutOfSequenceException' => $vendorDir . '/jasig/phpcas/source/CAS/OutOfSequenceException.php',\n    'CAS_PGTStorage_AbstractStorage' => $vendorDir . '/jasig/phpcas/source/CAS/PGTStorage/AbstractStorage.php',\n    'CAS_PGTStorage_Db' => $vendorDir . '/jasig/phpcas/source/CAS/PGTStorage/Db.php',\n    'CAS_PGTStorage_File' => $vendorDir . '/jasig/phpcas/source/CAS/PGTStorage/File.php',\n    'CAS_ProxiedService' => $vendorDir . '/jasig/phpcas/source/CAS/ProxiedService.php',\n    'CAS_ProxiedService_Abstract' => $vendorDir . '/jasig/phpcas/source/CAS/ProxiedService/Abstract.php',\n    'CAS_ProxiedService_Exception' => $vendorDir . '/jasig/phpcas/source/CAS/ProxiedService/Exception.php',\n    'CAS_ProxiedService_Http' => $vendorDir . '/jasig/phpcas/source/CAS/ProxiedService/Http.php',\n    'CAS_ProxiedService_Http_Abstract' => $vendorDir . '/jasig/phpcas/source/CAS/ProxiedService/Http/Abstract.php',\n    'CAS_ProxiedService_Http_Get' => $vendorDir . '/jasig/phpcas/source/CAS/ProxiedService/Http/Get.php',\n    'CAS_ProxiedService_Http_Post' => $vendorDir . '/jasig/phpcas/source/CAS/ProxiedService/Http/Post.php',\n    'CAS_ProxiedService_Imap' => $vendorDir . '/jasig/phpcas/source/CAS/ProxiedService/Imap.php',\n    'CAS_ProxiedService_Testable' => $vendorDir . '/jasig/phpcas/source/CAS/ProxiedService/Testable.php',\n    'CAS_ProxyChain' => $vendorDir . '/jasig/phpcas/source/CAS/ProxyChain.php',\n    'CAS_ProxyChain_AllowedList' => $vendorDir . '/jasig/phpcas/source/CAS/ProxyChain/AllowedList.php',\n    'CAS_ProxyChain_Any' => $vendorDir . '/jasig/phpcas/source/CAS/ProxyChain/Any.php',\n    'CAS_ProxyChain_Interface' => $vendorDir . '/jasig/phpcas/source/CAS/ProxyChain/Interface.php',\n    'CAS_ProxyChain_Trusted' => $vendorDir . '/jasig/phpcas/source/CAS/ProxyChain/Trusted.php',\n    'CAS_ProxyTicketException' => $vendorDir . '/jasig/phpcas/source/CAS/ProxyTicketException.php',\n    'CAS_Request_AbstractRequest' => $vendorDir . '/jasig/phpcas/source/CAS/Request/AbstractRequest.php',\n    'CAS_Request_CurlMultiRequest' => $vendorDir . '/jasig/phpcas/source/CAS/Request/CurlMultiRequest.php',\n    'CAS_Request_CurlRequest' => $vendorDir . '/jasig/phpcas/source/CAS/Request/CurlRequest.php',\n    'CAS_Request_Exception' => $vendorDir . '/jasig/phpcas/source/CAS/Request/Exception.php',\n    'CAS_Request_MultiRequestInterface' => $vendorDir . '/jasig/phpcas/source/CAS/Request/MultiRequestInterface.php',\n    'CAS_Request_RequestInterface' => $vendorDir . '/jasig/phpcas/source/CAS/Request/RequestInterface.php',\n    'CAS_ServiceBaseUrl_AllowedListDiscovery' => $vendorDir . '/jasig/phpcas/source/CAS/ServiceBaseUrl/AllowedListDiscovery.php',\n    'CAS_ServiceBaseUrl_Base' => $vendorDir . '/jasig/phpcas/source/CAS/ServiceBaseUrl/Base.php',\n    'CAS_ServiceBaseUrl_Interface' => $vendorDir . '/jasig/phpcas/source/CAS/ServiceBaseUrl/Interface.php',\n    'CAS_ServiceBaseUrl_Static' => $vendorDir . '/jasig/phpcas/source/CAS/ServiceBaseUrl/Static.php',\n    'CAS_Session_PhpSession' => $vendorDir . '/jasig/phpcas/source/CAS/Session/PhpSession.php',\n    'CAS_TypeMismatchException' => $vendorDir . '/jasig/phpcas/source/CAS/TypeMismatchException.php',\n    'Composer\\\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',\n    'DateError' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateError.php',\n    'DateException' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateException.php',\n    'DateInvalidOperationException' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateInvalidOperationException.php',\n    'DateInvalidTimeZoneException' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateInvalidTimeZoneException.php',\n    'DateMalformedIntervalStringException' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateMalformedIntervalStringException.php',\n    'DateMalformedPeriodStringException' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateMalformedPeriodStringException.php',\n    'DateMalformedStringException' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateMalformedStringException.php',\n    'DateObjectError' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateObjectError.php',\n    'DateRangeError' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateRangeError.php',\n    'JsonException' => $vendorDir . '/symfony/polyfill-php73/Resources/stubs/JsonException.php',\n    'Normalizer' => $vendorDir . '/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php',\n    'Override' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/Override.php',\n    'PhpToken' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php',\n    'SQLite3Exception' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/SQLite3Exception.php',\n    'Stringable' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',\n    'UnhandledMatchError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',\n    'ValueError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',\n    'phpCAS' => $vendorDir . '/jasig/phpcas/source/CAS.php',\n);\n"
  },
  {
    "path": "server/vendor/composer/autoload_files.php",
    "content": "<?php\n\n// autoload_files.php @generated by Composer\n\n$vendorDir = dirname(__DIR__);\n$baseDir = dirname(dirname($vendorDir));\n\nreturn array(\n    '6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php',\n    '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',\n    '7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php',\n    'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php',\n    '60799491728b879e74601d83e38b2cad' => $vendorDir . '/illuminate/collections/helpers.php',\n    'e69f7f6ee287b969198c3c9d6777bd38' => $vendorDir . '/symfony/polyfill-intl-normalizer/bootstrap.php',\n    'c964ee0ededf28c96ebd9db5099ef910' => $vendorDir . '/guzzlehttp/promises/src/functions_include.php',\n    'a0edc8309cc5e1d60e3047b5df6b7052' => $vendorDir . '/guzzlehttp/psr7/src/functions_include.php',\n    'a1105708a18b76903365ca1c4aa61b02' => $vendorDir . '/symfony/translation/Resources/functions.php',\n    'f598d06aa772fa33d905e87be6398fb1' => $vendorDir . '/symfony/polyfill-intl-idn/bootstrap.php',\n    '37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php',\n    '72579e7bd17821bb1321b87411366eae' => $vendorDir . '/illuminate/support/helpers.php',\n    '320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php',\n    '8825ede83f2f289127722d4e842cf7e8' => $vendorDir . '/symfony/polyfill-intl-grapheme/bootstrap.php',\n    '662a729f963d39afe703c9d9b7ab4a8c' => $vendorDir . '/symfony/polyfill-php83/bootstrap.php',\n    '0d59ee240a4cd96ddbb4ff164fccea4d' => $vendorDir . '/symfony/polyfill-php73/bootstrap.php',\n    'b6b991a57620e2fb6b2f66f03fe9ddc2' => $vendorDir . '/symfony/string/Resources/functions.php',\n    '253c157292f75eb38082b5acb06f3f01' => $vendorDir . '/nikic/fast-route/src/functions.php',\n    'ef65a1626449d89d0811cf9befce46f0' => $vendorDir . '/illuminate/events/functions.php',\n    '524ac6b21329cb008bd2db60ee1704ac' => $vendorDir . '/jasig/phpcas/source/CAS.php',\n    'b33e3d135e5d9e47d845c576147bda89' => $vendorDir . '/php-di/php-di/src/functions.php',\n    'f67964341ef83e59f1cc6a3916599312' => $vendorDir . '/qcloud/cos-sdk-v5/src/Qcloud/Cos/Common.php',\n);\n"
  },
  {
    "path": "server/vendor/composer/autoload_namespaces.php",
    "content": "<?php\n\n// autoload_namespaces.php @generated by Composer\n\n$vendorDir = dirname(__DIR__);\n$baseDir = dirname(dirname($vendorDir));\n\nreturn array(\n    'PHPSQLParser\\\\' => array($vendorDir . '/greenlion/php-sql-parser/src'),\n);\n"
  },
  {
    "path": "server/vendor/composer/autoload_psr4.php",
    "content": "<?php\n\n// autoload_psr4.php @generated by Composer\n\n$vendorDir = dirname(__DIR__);\n$baseDir = dirname(dirname($vendorDir));\n\nreturn array(\n    'voku\\\\' => array($vendorDir . '/voku/portable-ascii/src/voku'),\n    'Symfony\\\\Polyfill\\\\Php83\\\\' => array($vendorDir . '/symfony/polyfill-php83'),\n    'Symfony\\\\Polyfill\\\\Php80\\\\' => array($vendorDir . '/symfony/polyfill-php80'),\n    'Symfony\\\\Polyfill\\\\Php73\\\\' => array($vendorDir . '/symfony/polyfill-php73'),\n    'Symfony\\\\Polyfill\\\\Mbstring\\\\' => array($vendorDir . '/symfony/polyfill-mbstring'),\n    'Symfony\\\\Polyfill\\\\Intl\\\\Normalizer\\\\' => array($vendorDir . '/symfony/polyfill-intl-normalizer'),\n    'Symfony\\\\Polyfill\\\\Intl\\\\Idn\\\\' => array($vendorDir . '/symfony/polyfill-intl-idn'),\n    'Symfony\\\\Polyfill\\\\Intl\\\\Grapheme\\\\' => array($vendorDir . '/symfony/polyfill-intl-grapheme'),\n    'Symfony\\\\Polyfill\\\\Ctype\\\\' => array($vendorDir . '/symfony/polyfill-ctype'),\n    'Symfony\\\\Contracts\\\\Translation\\\\' => array($vendorDir . '/symfony/translation-contracts'),\n    'Symfony\\\\Contracts\\\\Service\\\\' => array($vendorDir . '/symfony/service-contracts'),\n    'Symfony\\\\Contracts\\\\HttpClient\\\\' => array($vendorDir . '/symfony/http-client-contracts'),\n    'Symfony\\\\Component\\\\Translation\\\\' => array($vendorDir . '/symfony/translation'),\n    'Symfony\\\\Component\\\\String\\\\' => array($vendorDir . '/symfony/string'),\n    'Symfony\\\\Component\\\\HttpClient\\\\' => array($vendorDir . '/symfony/http-client'),\n    'Symfony\\\\Component\\\\Finder\\\\' => array($vendorDir . '/symfony/finder'),\n    'Symfony\\\\Component\\\\Console\\\\' => array($vendorDir . '/symfony/console'),\n    'Slim\\\\Psr7\\\\' => array($vendorDir . '/slim/psr7/src'),\n    'Slim\\\\' => array($vendorDir . '/slim/slim/Slim'),\n    'Qcloud\\\\Cos\\\\' => array($vendorDir . '/qcloud/cos-sdk-v5/src/Qcloud/Cos'),\n    'Psr\\\\SimpleCache\\\\' => array($vendorDir . '/psr/simple-cache/src'),\n    'Psr\\\\Log\\\\' => array($vendorDir . '/psr/log/src'),\n    'Psr\\\\Http\\\\Server\\\\' => array($vendorDir . '/psr/http-server-handler/src', $vendorDir . '/psr/http-server-middleware/src'),\n    'Psr\\\\Http\\\\Message\\\\' => array($vendorDir . '/psr/http-message/src', $vendorDir . '/psr/http-factory/src'),\n    'Psr\\\\Container\\\\' => array($vendorDir . '/psr/container/src'),\n    'Psr\\\\Clock\\\\' => array($vendorDir . '/psr/clock/src'),\n    'Psr\\\\Cache\\\\' => array($vendorDir . '/psr/cache/src'),\n    'PhpOption\\\\' => array($vendorDir . '/phpoption/phpoption/src/PhpOption'),\n    'PhpDocReader\\\\' => array($vendorDir . '/php-di/phpdoc-reader/src/PhpDocReader'),\n    'League\\\\OAuth2\\\\Client\\\\' => array($vendorDir . '/league/oauth2-client/src'),\n    'Laravel\\\\SerializableClosure\\\\' => array($vendorDir . '/laravel/serializable-closure/src'),\n    'Invoker\\\\' => array($vendorDir . '/php-di/invoker/src'),\n    'Illuminate\\\\Support\\\\' => array($vendorDir . '/illuminate/macroable', $vendorDir . '/illuminate/collections', $vendorDir . '/illuminate/support'),\n    'Illuminate\\\\Pipeline\\\\' => array($vendorDir . '/illuminate/pipeline'),\n    'Illuminate\\\\Events\\\\' => array($vendorDir . '/illuminate/events'),\n    'Illuminate\\\\Database\\\\' => array($vendorDir . '/illuminate/database'),\n    'Illuminate\\\\Contracts\\\\' => array($vendorDir . '/illuminate/contracts'),\n    'Illuminate\\\\Container\\\\' => array($vendorDir . '/illuminate/container'),\n    'Illuminate\\\\Bus\\\\' => array($vendorDir . '/illuminate/bus'),\n    'GuzzleHttp\\\\Psr7\\\\' => array($vendorDir . '/guzzlehttp/psr7/src'),\n    'GuzzleHttp\\\\Promise\\\\' => array($vendorDir . '/guzzlehttp/promises/src'),\n    'GuzzleHttp\\\\Command\\\\Guzzle\\\\' => array($vendorDir . '/guzzlehttp/guzzle-services/src'),\n    'GuzzleHttp\\\\Command\\\\' => array($vendorDir . '/guzzlehttp/command/src'),\n    'GuzzleHttp\\\\' => array($vendorDir . '/guzzlehttp/guzzle/src'),\n    'Gregwar\\\\' => array($vendorDir . '/gregwar/captcha/src/Gregwar'),\n    'GrahamCampbell\\\\ResultType\\\\' => array($vendorDir . '/graham-campbell/result-type/src'),\n    'Fig\\\\Http\\\\Message\\\\' => array($vendorDir . '/fig/http-message-util/src'),\n    'FastRoute\\\\' => array($vendorDir . '/nikic/fast-route/src'),\n    'Dotenv\\\\' => array($vendorDir . '/vlucas/phpdotenv/src'),\n    'Doctrine\\\\Inflector\\\\' => array($vendorDir . '/doctrine/inflector/lib/Doctrine/Inflector'),\n    'DI\\\\' => array($vendorDir . '/php-di/php-di/src'),\n    'Carbon\\\\Doctrine\\\\' => array($vendorDir . '/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine'),\n    'Carbon\\\\' => array($vendorDir . '/nesbot/carbon/src/Carbon'),\n    'AsyncAws\\\\S3\\\\' => array($vendorDir . '/async-aws/s3/src'),\n    'AsyncAws\\\\Core\\\\' => array($vendorDir . '/async-aws/core/src'),\n    'App\\\\' => array($baseDir . '/server/app'),\n);\n"
  },
  {
    "path": "server/vendor/composer/autoload_real.php",
    "content": "<?php\n\n// autoload_real.php @generated by Composer\n\nclass ComposerAutoloaderInit434a4eb2fb23c7f559a3771baabf0fbb\n{\n    private static $loader;\n\n    public static function loadClassLoader($class)\n    {\n        if ('Composer\\Autoload\\ClassLoader' === $class) {\n            require __DIR__ . '/ClassLoader.php';\n        }\n    }\n\n    /**\n     * @return \\Composer\\Autoload\\ClassLoader\n     */\n    public static function getLoader()\n    {\n        if (null !== self::$loader) {\n            return self::$loader;\n        }\n\n        require __DIR__ . '/platform_check.php';\n\n        spl_autoload_register(array('ComposerAutoloaderInit434a4eb2fb23c7f559a3771baabf0fbb', 'loadClassLoader'), true, true);\n        self::$loader = $loader = new \\Composer\\Autoload\\ClassLoader(\\dirname(__DIR__));\n        spl_autoload_unregister(array('ComposerAutoloaderInit434a4eb2fb23c7f559a3771baabf0fbb', 'loadClassLoader'));\n\n        require __DIR__ . '/autoload_static.php';\n        call_user_func(\\Composer\\Autoload\\ComposerStaticInit434a4eb2fb23c7f559a3771baabf0fbb::getInitializer($loader));\n\n        $loader->register(true);\n\n        $filesToLoad = \\Composer\\Autoload\\ComposerStaticInit434a4eb2fb23c7f559a3771baabf0fbb::$files;\n        $requireFile = \\Closure::bind(static function ($fileIdentifier, $file) {\n            if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {\n                $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;\n\n                require $file;\n            }\n        }, null, null);\n        foreach ($filesToLoad as $fileIdentifier => $file) {\n            $requireFile($fileIdentifier, $file);\n        }\n\n        return $loader;\n    }\n}\n"
  },
  {
    "path": "server/vendor/composer/autoload_static.php",
    "content": "<?php\n\n// autoload_static.php @generated by Composer\n\nnamespace Composer\\Autoload;\n\nclass ComposerStaticInit434a4eb2fb23c7f559a3771baabf0fbb\n{\n    public static $files = array (\n        '6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php',\n        '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',\n        '7b11c4dc42b3b3023073cb14e519683c' => __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php',\n        'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php',\n        '60799491728b879e74601d83e38b2cad' => __DIR__ . '/..' . '/illuminate/collections/helpers.php',\n        'e69f7f6ee287b969198c3c9d6777bd38' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/bootstrap.php',\n        'c964ee0ededf28c96ebd9db5099ef910' => __DIR__ . '/..' . '/guzzlehttp/promises/src/functions_include.php',\n        'a0edc8309cc5e1d60e3047b5df6b7052' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/functions_include.php',\n        'a1105708a18b76903365ca1c4aa61b02' => __DIR__ . '/..' . '/symfony/translation/Resources/functions.php',\n        'f598d06aa772fa33d905e87be6398fb1' => __DIR__ . '/..' . '/symfony/polyfill-intl-idn/bootstrap.php',\n        '37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php',\n        '72579e7bd17821bb1321b87411366eae' => __DIR__ . '/..' . '/illuminate/support/helpers.php',\n        '320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php',\n        '8825ede83f2f289127722d4e842cf7e8' => __DIR__ . '/..' . '/symfony/polyfill-intl-grapheme/bootstrap.php',\n        '662a729f963d39afe703c9d9b7ab4a8c' => __DIR__ . '/..' . '/symfony/polyfill-php83/bootstrap.php',\n        '0d59ee240a4cd96ddbb4ff164fccea4d' => __DIR__ . '/..' . '/symfony/polyfill-php73/bootstrap.php',\n        'b6b991a57620e2fb6b2f66f03fe9ddc2' => __DIR__ . '/..' . '/symfony/string/Resources/functions.php',\n        '253c157292f75eb38082b5acb06f3f01' => __DIR__ . '/..' . '/nikic/fast-route/src/functions.php',\n        'ef65a1626449d89d0811cf9befce46f0' => __DIR__ . '/..' . '/illuminate/events/functions.php',\n        '524ac6b21329cb008bd2db60ee1704ac' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS.php',\n        'b33e3d135e5d9e47d845c576147bda89' => __DIR__ . '/..' . '/php-di/php-di/src/functions.php',\n        'f67964341ef83e59f1cc6a3916599312' => __DIR__ . '/..' . '/qcloud/cos-sdk-v5/src/Qcloud/Cos/Common.php',\n    );\n\n    public static $prefixLengthsPsr4 = array (\n        'v' => \n        array (\n            'voku\\\\' => 5,\n        ),\n        'S' => \n        array (\n            'Symfony\\\\Polyfill\\\\Php83\\\\' => 23,\n            'Symfony\\\\Polyfill\\\\Php80\\\\' => 23,\n            'Symfony\\\\Polyfill\\\\Php73\\\\' => 23,\n            'Symfony\\\\Polyfill\\\\Mbstring\\\\' => 26,\n            'Symfony\\\\Polyfill\\\\Intl\\\\Normalizer\\\\' => 33,\n            'Symfony\\\\Polyfill\\\\Intl\\\\Idn\\\\' => 26,\n            'Symfony\\\\Polyfill\\\\Intl\\\\Grapheme\\\\' => 31,\n            'Symfony\\\\Polyfill\\\\Ctype\\\\' => 23,\n            'Symfony\\\\Contracts\\\\Translation\\\\' => 30,\n            'Symfony\\\\Contracts\\\\Service\\\\' => 26,\n            'Symfony\\\\Contracts\\\\HttpClient\\\\' => 29,\n            'Symfony\\\\Component\\\\Translation\\\\' => 30,\n            'Symfony\\\\Component\\\\String\\\\' => 25,\n            'Symfony\\\\Component\\\\HttpClient\\\\' => 29,\n            'Symfony\\\\Component\\\\Finder\\\\' => 25,\n            'Symfony\\\\Component\\\\Console\\\\' => 26,\n            'Slim\\\\Psr7\\\\' => 10,\n            'Slim\\\\' => 5,\n        ),\n        'Q' => \n        array (\n            'Qcloud\\\\Cos\\\\' => 11,\n        ),\n        'P' => \n        array (\n            'Psr\\\\SimpleCache\\\\' => 16,\n            'Psr\\\\Log\\\\' => 8,\n            'Psr\\\\Http\\\\Server\\\\' => 16,\n            'Psr\\\\Http\\\\Message\\\\' => 17,\n            'Psr\\\\Container\\\\' => 14,\n            'Psr\\\\Clock\\\\' => 10,\n            'Psr\\\\Cache\\\\' => 10,\n            'PhpOption\\\\' => 10,\n            'PhpDocReader\\\\' => 13,\n        ),\n        'L' => \n        array (\n            'League\\\\OAuth2\\\\Client\\\\' => 21,\n            'Laravel\\\\SerializableClosure\\\\' => 28,\n        ),\n        'I' => \n        array (\n            'Invoker\\\\' => 8,\n            'Illuminate\\\\Support\\\\' => 19,\n            'Illuminate\\\\Pipeline\\\\' => 20,\n            'Illuminate\\\\Events\\\\' => 18,\n            'Illuminate\\\\Database\\\\' => 20,\n            'Illuminate\\\\Contracts\\\\' => 21,\n            'Illuminate\\\\Container\\\\' => 21,\n            'Illuminate\\\\Bus\\\\' => 15,\n        ),\n        'G' => \n        array (\n            'GuzzleHttp\\\\Psr7\\\\' => 16,\n            'GuzzleHttp\\\\Promise\\\\' => 19,\n            'GuzzleHttp\\\\Command\\\\Guzzle\\\\' => 26,\n            'GuzzleHttp\\\\Command\\\\' => 19,\n            'GuzzleHttp\\\\' => 11,\n            'Gregwar\\\\' => 8,\n            'GrahamCampbell\\\\ResultType\\\\' => 26,\n        ),\n        'F' => \n        array (\n            'Fig\\\\Http\\\\Message\\\\' => 17,\n            'FastRoute\\\\' => 10,\n        ),\n        'D' => \n        array (\n            'Dotenv\\\\' => 7,\n            'Doctrine\\\\Inflector\\\\' => 19,\n            'DI\\\\' => 3,\n        ),\n        'C' => \n        array (\n            'Carbon\\\\Doctrine\\\\' => 16,\n            'Carbon\\\\' => 7,\n        ),\n        'A' => \n        array (\n            'AsyncAws\\\\S3\\\\' => 12,\n            'AsyncAws\\\\Core\\\\' => 14,\n            'App\\\\' => 4,\n        ),\n    );\n\n    public static $prefixDirsPsr4 = array (\n        'voku\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/voku/portable-ascii/src/voku',\n        ),\n        'Symfony\\\\Polyfill\\\\Php83\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/symfony/polyfill-php83',\n        ),\n        'Symfony\\\\Polyfill\\\\Php80\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/symfony/polyfill-php80',\n        ),\n        'Symfony\\\\Polyfill\\\\Php73\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/symfony/polyfill-php73',\n        ),\n        'Symfony\\\\Polyfill\\\\Mbstring\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring',\n        ),\n        'Symfony\\\\Polyfill\\\\Intl\\\\Normalizer\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer',\n        ),\n        'Symfony\\\\Polyfill\\\\Intl\\\\Idn\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/symfony/polyfill-intl-idn',\n        ),\n        'Symfony\\\\Polyfill\\\\Intl\\\\Grapheme\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/symfony/polyfill-intl-grapheme',\n        ),\n        'Symfony\\\\Polyfill\\\\Ctype\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/symfony/polyfill-ctype',\n        ),\n        'Symfony\\\\Contracts\\\\Translation\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/symfony/translation-contracts',\n        ),\n        'Symfony\\\\Contracts\\\\Service\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/symfony/service-contracts',\n        ),\n        'Symfony\\\\Contracts\\\\HttpClient\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/symfony/http-client-contracts',\n        ),\n        'Symfony\\\\Component\\\\Translation\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/symfony/translation',\n        ),\n        'Symfony\\\\Component\\\\String\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/symfony/string',\n        ),\n        'Symfony\\\\Component\\\\HttpClient\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/symfony/http-client',\n        ),\n        'Symfony\\\\Component\\\\Finder\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/symfony/finder',\n        ),\n        'Symfony\\\\Component\\\\Console\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/symfony/console',\n        ),\n        'Slim\\\\Psr7\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/slim/psr7/src',\n        ),\n        'Slim\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/slim/slim/Slim',\n        ),\n        'Qcloud\\\\Cos\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/qcloud/cos-sdk-v5/src/Qcloud/Cos',\n        ),\n        'Psr\\\\SimpleCache\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/psr/simple-cache/src',\n        ),\n        'Psr\\\\Log\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/psr/log/src',\n        ),\n        'Psr\\\\Http\\\\Server\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/psr/http-server-handler/src',\n            1 => __DIR__ . '/..' . '/psr/http-server-middleware/src',\n        ),\n        'Psr\\\\Http\\\\Message\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/psr/http-message/src',\n            1 => __DIR__ . '/..' . '/psr/http-factory/src',\n        ),\n        'Psr\\\\Container\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/psr/container/src',\n        ),\n        'Psr\\\\Clock\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/psr/clock/src',\n        ),\n        'Psr\\\\Cache\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/psr/cache/src',\n        ),\n        'PhpOption\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/phpoption/phpoption/src/PhpOption',\n        ),\n        'PhpDocReader\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/php-di/phpdoc-reader/src/PhpDocReader',\n        ),\n        'League\\\\OAuth2\\\\Client\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/league/oauth2-client/src',\n        ),\n        'Laravel\\\\SerializableClosure\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/laravel/serializable-closure/src',\n        ),\n        'Invoker\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/php-di/invoker/src',\n        ),\n        'Illuminate\\\\Support\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/illuminate/macroable',\n            1 => __DIR__ . '/..' . '/illuminate/collections',\n            2 => __DIR__ . '/..' . '/illuminate/support',\n        ),\n        'Illuminate\\\\Pipeline\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/illuminate/pipeline',\n        ),\n        'Illuminate\\\\Events\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/illuminate/events',\n        ),\n        'Illuminate\\\\Database\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/illuminate/database',\n        ),\n        'Illuminate\\\\Contracts\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/illuminate/contracts',\n        ),\n        'Illuminate\\\\Container\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/illuminate/container',\n        ),\n        'Illuminate\\\\Bus\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/illuminate/bus',\n        ),\n        'GuzzleHttp\\\\Psr7\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/guzzlehttp/psr7/src',\n        ),\n        'GuzzleHttp\\\\Promise\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/guzzlehttp/promises/src',\n        ),\n        'GuzzleHttp\\\\Command\\\\Guzzle\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/guzzlehttp/guzzle-services/src',\n        ),\n        'GuzzleHttp\\\\Command\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/guzzlehttp/command/src',\n        ),\n        'GuzzleHttp\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/guzzlehttp/guzzle/src',\n        ),\n        'Gregwar\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/gregwar/captcha/src/Gregwar',\n        ),\n        'GrahamCampbell\\\\ResultType\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/graham-campbell/result-type/src',\n        ),\n        'Fig\\\\Http\\\\Message\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/fig/http-message-util/src',\n        ),\n        'FastRoute\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/nikic/fast-route/src',\n        ),\n        'Dotenv\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/vlucas/phpdotenv/src',\n        ),\n        'Doctrine\\\\Inflector\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/doctrine/inflector/lib/Doctrine/Inflector',\n        ),\n        'DI\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/php-di/php-di/src',\n        ),\n        'Carbon\\\\Doctrine\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine',\n        ),\n        'Carbon\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/nesbot/carbon/src/Carbon',\n        ),\n        'AsyncAws\\\\S3\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/async-aws/s3/src',\n        ),\n        'AsyncAws\\\\Core\\\\' => \n        array (\n            0 => __DIR__ . '/..' . '/async-aws/core/src',\n        ),\n        'App\\\\' => \n        array (\n            0 => __DIR__ . '/../../..' . '/server/app',\n        ),\n    );\n\n    public static $prefixesPsr0 = array (\n        'P' => \n        array (\n            'PHPSQLParser\\\\' => \n            array (\n                0 => __DIR__ . '/..' . '/greenlion/php-sql-parser/src',\n            ),\n        ),\n    );\n\n    public static $classMap = array (\n        'Attribute' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',\n        'CAS_AuthenticationException' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/AuthenticationException.php',\n        'CAS_Client' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/Client.php',\n        'CAS_CookieJar' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/CookieJar.php',\n        'CAS_Exception' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/Exception.php',\n        'CAS_GracefullTerminationException' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/GracefullTerminationException.php',\n        'CAS_InvalidArgumentException' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/InvalidArgumentException.php',\n        'CAS_Languages_Catalan' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/Languages/Catalan.php',\n        'CAS_Languages_ChineseSimplified' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/Languages/ChineseSimplified.php',\n        'CAS_Languages_English' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/Languages/English.php',\n        'CAS_Languages_French' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/Languages/French.php',\n        'CAS_Languages_Galego' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/Languages/Galego.php',\n        'CAS_Languages_German' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/Languages/German.php',\n        'CAS_Languages_Greek' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/Languages/Greek.php',\n        'CAS_Languages_Japanese' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/Languages/Japanese.php',\n        'CAS_Languages_LanguageInterface' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/Languages/LanguageInterface.php',\n        'CAS_Languages_Portuguese' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/Languages/Portuguese.php',\n        'CAS_Languages_Spanish' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/Languages/Spanish.php',\n        'CAS_OutOfSequenceBeforeAuthenticationCallException' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/OutOfSequenceBeforeAuthenticationCallException.php',\n        'CAS_OutOfSequenceBeforeClientException' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/OutOfSequenceBeforeClientException.php',\n        'CAS_OutOfSequenceBeforeProxyException' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/OutOfSequenceBeforeProxyException.php',\n        'CAS_OutOfSequenceException' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/OutOfSequenceException.php',\n        'CAS_PGTStorage_AbstractStorage' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/PGTStorage/AbstractStorage.php',\n        'CAS_PGTStorage_Db' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/PGTStorage/Db.php',\n        'CAS_PGTStorage_File' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/PGTStorage/File.php',\n        'CAS_ProxiedService' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/ProxiedService.php',\n        'CAS_ProxiedService_Abstract' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/ProxiedService/Abstract.php',\n        'CAS_ProxiedService_Exception' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/ProxiedService/Exception.php',\n        'CAS_ProxiedService_Http' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/ProxiedService/Http.php',\n        'CAS_ProxiedService_Http_Abstract' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/ProxiedService/Http/Abstract.php',\n        'CAS_ProxiedService_Http_Get' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/ProxiedService/Http/Get.php',\n        'CAS_ProxiedService_Http_Post' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/ProxiedService/Http/Post.php',\n        'CAS_ProxiedService_Imap' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/ProxiedService/Imap.php',\n        'CAS_ProxiedService_Testable' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/ProxiedService/Testable.php',\n        'CAS_ProxyChain' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/ProxyChain.php',\n        'CAS_ProxyChain_AllowedList' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/ProxyChain/AllowedList.php',\n        'CAS_ProxyChain_Any' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/ProxyChain/Any.php',\n        'CAS_ProxyChain_Interface' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/ProxyChain/Interface.php',\n        'CAS_ProxyChain_Trusted' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/ProxyChain/Trusted.php',\n        'CAS_ProxyTicketException' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/ProxyTicketException.php',\n        'CAS_Request_AbstractRequest' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/Request/AbstractRequest.php',\n        'CAS_Request_CurlMultiRequest' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/Request/CurlMultiRequest.php',\n        'CAS_Request_CurlRequest' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/Request/CurlRequest.php',\n        'CAS_Request_Exception' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/Request/Exception.php',\n        'CAS_Request_MultiRequestInterface' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/Request/MultiRequestInterface.php',\n        'CAS_Request_RequestInterface' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/Request/RequestInterface.php',\n        'CAS_ServiceBaseUrl_AllowedListDiscovery' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/ServiceBaseUrl/AllowedListDiscovery.php',\n        'CAS_ServiceBaseUrl_Base' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/ServiceBaseUrl/Base.php',\n        'CAS_ServiceBaseUrl_Interface' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/ServiceBaseUrl/Interface.php',\n        'CAS_ServiceBaseUrl_Static' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/ServiceBaseUrl/Static.php',\n        'CAS_Session_PhpSession' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/Session/PhpSession.php',\n        'CAS_TypeMismatchException' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS/TypeMismatchException.php',\n        'Composer\\\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',\n        'DateError' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateError.php',\n        'DateException' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateException.php',\n        'DateInvalidOperationException' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateInvalidOperationException.php',\n        'DateInvalidTimeZoneException' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateInvalidTimeZoneException.php',\n        'DateMalformedIntervalStringException' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateMalformedIntervalStringException.php',\n        'DateMalformedPeriodStringException' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateMalformedPeriodStringException.php',\n        'DateMalformedStringException' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateMalformedStringException.php',\n        'DateObjectError' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateObjectError.php',\n        'DateRangeError' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateRangeError.php',\n        'JsonException' => __DIR__ . '/..' . '/symfony/polyfill-php73/Resources/stubs/JsonException.php',\n        'Normalizer' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php',\n        'Override' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/Override.php',\n        'PhpToken' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php',\n        'SQLite3Exception' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/SQLite3Exception.php',\n        'Stringable' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',\n        'UnhandledMatchError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',\n        'ValueError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',\n        'phpCAS' => __DIR__ . '/..' . '/jasig/phpcas/source/CAS.php',\n    );\n\n    public static function getInitializer(ClassLoader $loader)\n    {\n        return \\Closure::bind(function () use ($loader) {\n            $loader->prefixLengthsPsr4 = ComposerStaticInit434a4eb2fb23c7f559a3771baabf0fbb::$prefixLengthsPsr4;\n            $loader->prefixDirsPsr4 = ComposerStaticInit434a4eb2fb23c7f559a3771baabf0fbb::$prefixDirsPsr4;\n            $loader->prefixesPsr0 = ComposerStaticInit434a4eb2fb23c7f559a3771baabf0fbb::$prefixesPsr0;\n            $loader->classMap = ComposerStaticInit434a4eb2fb23c7f559a3771baabf0fbb::$classMap;\n\n        }, null, ClassLoader::class);\n    }\n}\n"
  },
  {
    "path": "server/vendor/composer/installed.json",
    "content": "{\n    \"packages\": [\n        {\n            \"name\": \"async-aws/core\",\n            \"version\": \"1.27.1\",\n            \"version_normalized\": \"1.27.1.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/async-aws/core.git\",\n                \"reference\": \"5b8e35c8df94990161e2c9750c9ba1683d0b48b8\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/async-aws/core/zipball/5b8e35c8df94990161e2c9750c9ba1683d0b48b8\",\n                \"reference\": \"5b8e35c8df94990161e2c9750c9ba1683d0b48b8\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"ext-hash\": \"*\",\n                \"ext-json\": \"*\",\n                \"ext-simplexml\": \"*\",\n                \"php\": \"^7.2.5 || ^8.0\",\n                \"psr/cache\": \"^1.0 || ^2.0 || ^3.0\",\n                \"psr/log\": \"^1.0 || ^2.0 || ^3.0\",\n                \"symfony/deprecation-contracts\": \"^2.1 || ^3.0\",\n                \"symfony/http-client\": \"^4.4.16 || ^5.1.7 || ^6.0 || ^7.0 || ^8.0\",\n                \"symfony/http-client-contracts\": \"^1.1.8 || ^2.0 || ^3.0\",\n                \"symfony/service-contracts\": \"^1.0 || ^2.0 || ^3.0\"\n            },\n            \"conflict\": {\n                \"async-aws/s3\": \"<1.1\",\n                \"symfony/http-client\": \"5.2.0\"\n            },\n            \"time\": \"2025-09-08T07:05:54+00:00\",\n            \"type\": \"library\",\n            \"extra\": {\n                \"branch-alias\": {\n                    \"dev-master\": \"1.27-dev\"\n                }\n            },\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"psr-4\": {\n                    \"AsyncAws\\\\Core\\\\\": \"src\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"description\": \"Core package to integrate with AWS. This is a lightweight AWS SDK provider by AsyncAws.\",\n            \"keywords\": [\n                \"amazon\",\n                \"async-aws\",\n                \"aws\",\n                \"sdk\",\n                \"sts\"\n            ],\n            \"support\": {\n                \"source\": \"https://github.com/async-aws/core/tree/1.27.1\"\n            },\n            \"funding\": [\n                {\n                    \"url\": \"https://github.com/jderusse\",\n                    \"type\": \"github\"\n                },\n                {\n                    \"url\": \"https://github.com/nyholm\",\n                    \"type\": \"github\"\n                }\n            ],\n            \"install-path\": \"../async-aws/core\"\n        },\n        {\n            \"name\": \"async-aws/s3\",\n            \"version\": \"1.14.0\",\n            \"version_normalized\": \"1.14.0.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/async-aws/s3.git\",\n                \"reference\": \"27ce65242cde50ba09323d54708b45cf64a51aa5\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/async-aws/s3/zipball/27ce65242cde50ba09323d54708b45cf64a51aa5\",\n                \"reference\": \"27ce65242cde50ba09323d54708b45cf64a51aa5\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"async-aws/core\": \"^1.9\",\n                \"ext-dom\": \"*\",\n                \"ext-filter\": \"*\",\n                \"ext-hash\": \"*\",\n                \"ext-simplexml\": \"*\",\n                \"php\": \"^7.2.5 || ^8.0\"\n            },\n            \"time\": \"2023-06-20T19:17:40+00:00\",\n            \"type\": \"library\",\n            \"extra\": {\n                \"branch-alias\": {\n                    \"dev-master\": \"1.14-dev\"\n                }\n            },\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"psr-4\": {\n                    \"AsyncAws\\\\S3\\\\\": \"src\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"description\": \"S3 client, part of the AWS SDK provided by AsyncAws.\",\n            \"keywords\": [\n                \"amazon\",\n                \"async-aws\",\n                \"aws\",\n                \"s3\",\n                \"sdk\"\n            ],\n            \"support\": {\n                \"source\": \"https://github.com/async-aws/s3/tree/1.14.0\"\n            },\n            \"funding\": [\n                {\n                    \"url\": \"https://github.com/jderusse\",\n                    \"type\": \"github\"\n                },\n                {\n                    \"url\": \"https://github.com/nyholm\",\n                    \"type\": \"github\"\n                }\n            ],\n            \"install-path\": \"../async-aws/s3\"\n        },\n        {\n            \"name\": \"carbonphp/carbon-doctrine-types\",\n            \"version\": \"3.2.0\",\n            \"version_normalized\": \"3.2.0.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/CarbonPHP/carbon-doctrine-types.git\",\n                \"reference\": \"18ba5ddfec8976260ead6e866180bd5d2f71aa1d\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/CarbonPHP/carbon-doctrine-types/zipball/18ba5ddfec8976260ead6e866180bd5d2f71aa1d\",\n                \"reference\": \"18ba5ddfec8976260ead6e866180bd5d2f71aa1d\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"php\": \"^8.1\"\n            },\n            \"conflict\": {\n                \"doctrine/dbal\": \"<4.0.0 || >=5.0.0\"\n            },\n            \"require-dev\": {\n                \"doctrine/dbal\": \"^4.0.0\",\n                \"nesbot/carbon\": \"^2.71.0 || ^3.0.0\",\n                \"phpunit/phpunit\": \"^10.3\"\n            },\n            \"time\": \"2024-02-09T16:56:22+00:00\",\n            \"type\": \"library\",\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"psr-4\": {\n                    \"Carbon\\\\Doctrine\\\\\": \"src/Carbon/Doctrine/\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"KyleKatarn\",\n                    \"email\": \"kylekatarnls@gmail.com\"\n                }\n            ],\n            \"description\": \"Types to use Carbon in Doctrine\",\n            \"keywords\": [\n                \"carbon\",\n                \"date\",\n                \"datetime\",\n                \"doctrine\",\n                \"time\"\n            ],\n            \"support\": {\n                \"issues\": \"https://github.com/CarbonPHP/carbon-doctrine-types/issues\",\n                \"source\": \"https://github.com/CarbonPHP/carbon-doctrine-types/tree/3.2.0\"\n            },\n            \"funding\": [\n                {\n                    \"url\": \"https://github.com/kylekatarnls\",\n                    \"type\": \"github\"\n                },\n                {\n                    \"url\": \"https://opencollective.com/Carbon\",\n                    \"type\": \"open_collective\"\n                },\n                {\n                    \"url\": \"https://tidelift.com/funding/github/packagist/nesbot/carbon\",\n                    \"type\": \"tidelift\"\n                }\n            ],\n            \"install-path\": \"../carbonphp/carbon-doctrine-types\"\n        },\n        {\n            \"name\": \"doctrine/inflector\",\n            \"version\": \"2.0.10\",\n            \"version_normalized\": \"2.0.10.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/doctrine/inflector.git\",\n                \"reference\": \"5817d0659c5b50c9b950feb9af7b9668e2c436bc\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/doctrine/inflector/zipball/5817d0659c5b50c9b950feb9af7b9668e2c436bc\",\n                \"reference\": \"5817d0659c5b50c9b950feb9af7b9668e2c436bc\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"php\": \"^7.2 || ^8.0\"\n            },\n            \"require-dev\": {\n                \"doctrine/coding-standard\": \"^11.0\",\n                \"phpstan/phpstan\": \"^1.8\",\n                \"phpstan/phpstan-phpunit\": \"^1.1\",\n                \"phpstan/phpstan-strict-rules\": \"^1.3\",\n                \"phpunit/phpunit\": \"^8.5 || ^9.5\",\n                \"vimeo/psalm\": \"^4.25 || ^5.4\"\n            },\n            \"time\": \"2024-02-18T20:23:39+00:00\",\n            \"type\": \"library\",\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"psr-4\": {\n                    \"Doctrine\\\\Inflector\\\\\": \"lib/Doctrine/Inflector\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Guilherme Blanco\",\n                    \"email\": \"guilhermeblanco@gmail.com\"\n                },\n                {\n                    \"name\": \"Roman Borschel\",\n                    \"email\": \"roman@code-factory.org\"\n                },\n                {\n                    \"name\": \"Benjamin Eberlei\",\n                    \"email\": \"kontakt@beberlei.de\"\n                },\n                {\n                    \"name\": \"Jonathan Wage\",\n                    \"email\": \"jonwage@gmail.com\"\n                },\n                {\n                    \"name\": \"Johannes Schmitt\",\n                    \"email\": \"schmittjoh@gmail.com\"\n                }\n            ],\n            \"description\": \"PHP Doctrine Inflector is a small library that can perform string manipulations with regard to upper/lowercase and singular/plural forms of words.\",\n            \"homepage\": \"https://www.doctrine-project.org/projects/inflector.html\",\n            \"keywords\": [\n                \"inflection\",\n                \"inflector\",\n                \"lowercase\",\n                \"manipulation\",\n                \"php\",\n                \"plural\",\n                \"singular\",\n                \"strings\",\n                \"uppercase\",\n                \"words\"\n            ],\n            \"support\": {\n                \"issues\": \"https://github.com/doctrine/inflector/issues\",\n                \"source\": \"https://github.com/doctrine/inflector/tree/2.0.10\"\n            },\n            \"funding\": [\n                {\n                    \"url\": \"https://www.doctrine-project.org/sponsorship.html\",\n                    \"type\": \"custom\"\n                },\n                {\n                    \"url\": \"https://www.patreon.com/phpdoctrine\",\n                    \"type\": \"patreon\"\n                },\n                {\n                    \"url\": \"https://tidelift.com/funding/github/packagist/doctrine%2Finflector\",\n                    \"type\": \"tidelift\"\n                }\n            ],\n            \"install-path\": \"../doctrine/inflector\"\n        },\n        {\n            \"name\": \"fig/http-message-util\",\n            \"version\": \"1.1.5\",\n            \"version_normalized\": \"1.1.5.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/php-fig/http-message-util.git\",\n                \"reference\": \"9d94dc0154230ac39e5bf89398b324a86f63f765\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/php-fig/http-message-util/zipball/9d94dc0154230ac39e5bf89398b324a86f63f765\",\n                \"reference\": \"9d94dc0154230ac39e5bf89398b324a86f63f765\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"php\": \"^5.3 || ^7.0 || ^8.0\"\n            },\n            \"suggest\": {\n                \"psr/http-message\": \"The package containing the PSR-7 interfaces\"\n            },\n            \"time\": \"2020-11-24T22:02:12+00:00\",\n            \"type\": \"library\",\n            \"extra\": {\n                \"branch-alias\": {\n                    \"dev-master\": \"1.1.x-dev\"\n                }\n            },\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"psr-4\": {\n                    \"Fig\\\\Http\\\\Message\\\\\": \"src/\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"PHP-FIG\",\n                    \"homepage\": \"https://www.php-fig.org/\"\n                }\n            ],\n            \"description\": \"Utility classes and constants for use with PSR-7 (psr/http-message)\",\n            \"keywords\": [\n                \"http\",\n                \"http-message\",\n                \"psr\",\n                \"psr-7\",\n                \"request\",\n                \"response\"\n            ],\n            \"support\": {\n                \"issues\": \"https://github.com/php-fig/http-message-util/issues\",\n                \"source\": \"https://github.com/php-fig/http-message-util/tree/1.1.5\"\n            },\n            \"install-path\": \"../fig/http-message-util\"\n        },\n        {\n            \"name\": \"graham-campbell/result-type\",\n            \"version\": \"v1.1.2\",\n            \"version_normalized\": \"1.1.2.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/GrahamCampbell/Result-Type.git\",\n                \"reference\": \"fbd48bce38f73f8a4ec8583362e732e4095e5862\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/fbd48bce38f73f8a4ec8583362e732e4095e5862\",\n                \"reference\": \"fbd48bce38f73f8a4ec8583362e732e4095e5862\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"php\": \"^7.2.5 || ^8.0\",\n                \"phpoption/phpoption\": \"^1.9.2\"\n            },\n            \"require-dev\": {\n                \"phpunit/phpunit\": \"^8.5.34 || ^9.6.13 || ^10.4.2\"\n            },\n            \"time\": \"2023-11-12T22:16:48+00:00\",\n            \"type\": \"library\",\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"psr-4\": {\n                    \"GrahamCampbell\\\\ResultType\\\\\": \"src/\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Graham Campbell\",\n                    \"email\": \"hello@gjcampbell.co.uk\",\n                    \"homepage\": \"https://github.com/GrahamCampbell\"\n                }\n            ],\n            \"description\": \"An Implementation Of The Result Type\",\n            \"keywords\": [\n                \"Graham Campbell\",\n                \"GrahamCampbell\",\n                \"Result Type\",\n                \"Result-Type\",\n                \"result\"\n            ],\n            \"support\": {\n                \"issues\": \"https://github.com/GrahamCampbell/Result-Type/issues\",\n                \"source\": \"https://github.com/GrahamCampbell/Result-Type/tree/v1.1.2\"\n            },\n            \"funding\": [\n                {\n                    \"url\": \"https://github.com/GrahamCampbell\",\n                    \"type\": \"github\"\n                },\n                {\n                    \"url\": \"https://tidelift.com/funding/github/packagist/graham-campbell/result-type\",\n                    \"type\": \"tidelift\"\n                }\n            ],\n            \"install-path\": \"../graham-campbell/result-type\"\n        },\n        {\n            \"name\": \"greenlion/php-sql-parser\",\n            \"version\": \"v4.6.0\",\n            \"version_normalized\": \"4.6.0.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/greenlion/PHP-SQL-Parser.git\",\n                \"reference\": \"f0e4645eb1612f0a295e3d35bda4c7740ae8c366\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/greenlion/PHP-SQL-Parser/zipball/f0e4645eb1612f0a295e3d35bda4c7740ae8c366\",\n                \"reference\": \"f0e4645eb1612f0a295e3d35bda4c7740ae8c366\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"php\": \">=5.3.2\"\n            },\n            \"require-dev\": {\n                \"analog/analog\": \"^1.0.6\",\n                \"phpunit/phpunit\": \"^9.5.13\",\n                \"squizlabs/php_codesniffer\": \"^1.5.1\"\n            },\n            \"time\": \"2023-03-09T20:54:23+00:00\",\n            \"type\": \"library\",\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"psr-0\": {\n                    \"PHPSQLParser\\\\\": \"src/\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"BSD-3-Clause\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Justin Swanhart\",\n                    \"email\": \"greenlion@gmail.com\",\n                    \"homepage\": \"http://code.google.com/u/greenlion@gmail.com/\",\n                    \"role\": \"Owner\"\n                },\n                {\n                    \"name\": \"André Rothe\",\n                    \"email\": \"phosco@gmx.de\",\n                    \"homepage\": \"https://www.phosco.info\",\n                    \"role\": \"Committer\"\n                }\n            ],\n            \"description\": \"A pure PHP SQL (non validating) parser w/ focus on MySQL dialect of SQL\",\n            \"homepage\": \"https://github.com/greenlion/PHP-SQL-Parser\",\n            \"keywords\": [\n                \"creator\",\n                \"mysql\",\n                \"parser\",\n                \"sql\"\n            ],\n            \"support\": {\n                \"issues\": \"https://github.com/greenlion/PHP-SQL-Parser/issues\",\n                \"source\": \"https://github.com/greenlion/PHP-SQL-Parser\"\n            },\n            \"install-path\": \"../greenlion/php-sql-parser\"\n        },\n        {\n            \"name\": \"gregwar/captcha\",\n            \"version\": \"v1.2.1\",\n            \"version_normalized\": \"1.2.1.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/Gregwar/Captcha.git\",\n                \"reference\": \"229d3cdfe33d6f1349e0aec94a26e9205a6db08e\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/Gregwar/Captcha/zipball/229d3cdfe33d6f1349e0aec94a26e9205a6db08e\",\n                \"reference\": \"229d3cdfe33d6f1349e0aec94a26e9205a6db08e\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"ext-gd\": \"*\",\n                \"ext-mbstring\": \"*\",\n                \"php\": \">=5.3.0\",\n                \"symfony/finder\": \"*\"\n            },\n            \"require-dev\": {\n                \"phpunit/phpunit\": \"^6.4\"\n            },\n            \"time\": \"2023-09-26T13:45:37+00:00\",\n            \"type\": \"library\",\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"psr-4\": {\n                    \"Gregwar\\\\\": \"src/Gregwar\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Grégoire Passault\",\n                    \"email\": \"g.passault@gmail.com\",\n                    \"homepage\": \"http://www.gregwar.com/\"\n                },\n                {\n                    \"name\": \"Jeremy Livingston\",\n                    \"email\": \"jeremy.j.livingston@gmail.com\"\n                }\n            ],\n            \"description\": \"Captcha generator\",\n            \"homepage\": \"https://github.com/Gregwar/Captcha\",\n            \"keywords\": [\n                \"bot\",\n                \"captcha\",\n                \"spam\"\n            ],\n            \"support\": {\n                \"issues\": \"https://github.com/Gregwar/Captcha/issues\",\n                \"source\": \"https://github.com/Gregwar/Captcha/tree/v1.2.1\"\n            },\n            \"install-path\": \"../gregwar/captcha\"\n        },\n        {\n            \"name\": \"guzzlehttp/command\",\n            \"version\": \"1.0.0\",\n            \"version_normalized\": \"1.0.0.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/guzzle/command.git\",\n                \"reference\": \"2aaa2521a8f8269d6f5dfc13fe2af12c76921034\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/guzzle/command/zipball/2aaa2521a8f8269d6f5dfc13fe2af12c76921034\",\n                \"reference\": \"2aaa2521a8f8269d6f5dfc13fe2af12c76921034\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"guzzlehttp/guzzle\": \"^6.2\",\n                \"guzzlehttp/promises\": \"~1.3\",\n                \"guzzlehttp/psr7\": \"~1.0\",\n                \"php\": \">=5.5.0\"\n            },\n            \"require-dev\": {\n                \"phpunit/phpunit\": \"~4.0|~5.0\"\n            },\n            \"time\": \"2016-11-24T13:34:15+00:00\",\n            \"type\": \"library\",\n            \"extra\": {\n                \"branch-alias\": {\n                    \"dev-master\": \"0.9-dev\"\n                }\n            },\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"psr-4\": {\n                    \"GuzzleHttp\\\\Command\\\\\": \"src/\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Michael Dowling\",\n                    \"email\": \"mtdowling@gmail.com\",\n                    \"homepage\": \"https://github.com/mtdowling\"\n                },\n                {\n                    \"name\": \"Jeremy Lindblom\",\n                    \"email\": \"jeremeamia@gmail.com\",\n                    \"homepage\": \"https://github.com/jeremeamia\"\n                }\n            ],\n            \"description\": \"Provides the foundation for building command-based web service clients\",\n            \"support\": {\n                \"issues\": \"https://github.com/guzzle/command/issues\",\n                \"source\": \"https://github.com/guzzle/command/tree/1.0.0\"\n            },\n            \"install-path\": \"../guzzlehttp/command\"\n        },\n        {\n            \"name\": \"guzzlehttp/guzzle\",\n            \"version\": \"6.5.8\",\n            \"version_normalized\": \"6.5.8.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/guzzle/guzzle.git\",\n                \"reference\": \"a52f0440530b54fa079ce76e8c5d196a42cad981\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/guzzle/guzzle/zipball/a52f0440530b54fa079ce76e8c5d196a42cad981\",\n                \"reference\": \"a52f0440530b54fa079ce76e8c5d196a42cad981\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"ext-json\": \"*\",\n                \"guzzlehttp/promises\": \"^1.0\",\n                \"guzzlehttp/psr7\": \"^1.9\",\n                \"php\": \">=5.5\",\n                \"symfony/polyfill-intl-idn\": \"^1.17\"\n            },\n            \"require-dev\": {\n                \"ext-curl\": \"*\",\n                \"phpunit/phpunit\": \"^4.8.35 || ^5.7 || ^6.4 || ^7.0\",\n                \"psr/log\": \"^1.1\"\n            },\n            \"suggest\": {\n                \"psr/log\": \"Required for using the Log middleware\"\n            },\n            \"time\": \"2022-06-20T22:16:07+00:00\",\n            \"type\": \"library\",\n            \"extra\": {\n                \"branch-alias\": {\n                    \"dev-master\": \"6.5-dev\"\n                }\n            },\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"files\": [\n                    \"src/functions_include.php\"\n                ],\n                \"psr-4\": {\n                    \"GuzzleHttp\\\\\": \"src/\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Graham Campbell\",\n                    \"email\": \"hello@gjcampbell.co.uk\",\n                    \"homepage\": \"https://github.com/GrahamCampbell\"\n                },\n                {\n                    \"name\": \"Michael Dowling\",\n                    \"email\": \"mtdowling@gmail.com\",\n                    \"homepage\": \"https://github.com/mtdowling\"\n                },\n                {\n                    \"name\": \"Jeremy Lindblom\",\n                    \"email\": \"jeremeamia@gmail.com\",\n                    \"homepage\": \"https://github.com/jeremeamia\"\n                },\n                {\n                    \"name\": \"George Mponos\",\n                    \"email\": \"gmponos@gmail.com\",\n                    \"homepage\": \"https://github.com/gmponos\"\n                },\n                {\n                    \"name\": \"Tobias Nyholm\",\n                    \"email\": \"tobias.nyholm@gmail.com\",\n                    \"homepage\": \"https://github.com/Nyholm\"\n                },\n                {\n                    \"name\": \"Márk Sági-Kazár\",\n                    \"email\": \"mark.sagikazar@gmail.com\",\n                    \"homepage\": \"https://github.com/sagikazarmark\"\n                },\n                {\n                    \"name\": \"Tobias Schultze\",\n                    \"email\": \"webmaster@tubo-world.de\",\n                    \"homepage\": \"https://github.com/Tobion\"\n                }\n            ],\n            \"description\": \"Guzzle is a PHP HTTP client library\",\n            \"homepage\": \"http://guzzlephp.org/\",\n            \"keywords\": [\n                \"client\",\n                \"curl\",\n                \"framework\",\n                \"http\",\n                \"http client\",\n                \"rest\",\n                \"web service\"\n            ],\n            \"support\": {\n                \"issues\": \"https://github.com/guzzle/guzzle/issues\",\n                \"source\": \"https://github.com/guzzle/guzzle/tree/6.5.8\"\n            },\n            \"funding\": [\n                {\n                    \"url\": \"https://github.com/GrahamCampbell\",\n                    \"type\": \"github\"\n                },\n                {\n                    \"url\": \"https://github.com/Nyholm\",\n                    \"type\": \"github\"\n                },\n                {\n                    \"url\": \"https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle\",\n                    \"type\": \"tidelift\"\n                }\n            ],\n            \"install-path\": \"../guzzlehttp/guzzle\"\n        },\n        {\n            \"name\": \"guzzlehttp/guzzle-services\",\n            \"version\": \"1.1.3\",\n            \"version_normalized\": \"1.1.3.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/guzzle/guzzle-services.git\",\n                \"reference\": \"9e3abf20161cbf662d616cbb995f2811771759f7\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/guzzle/guzzle-services/zipball/9e3abf20161cbf662d616cbb995f2811771759f7\",\n                \"reference\": \"9e3abf20161cbf662d616cbb995f2811771759f7\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"guzzlehttp/command\": \"~1.0\",\n                \"guzzlehttp/guzzle\": \"^6.2\",\n                \"php\": \">=5.5\"\n            },\n            \"require-dev\": {\n                \"phpunit/phpunit\": \"~4.0\"\n            },\n            \"suggest\": {\n                \"gimler/guzzle-description-loader\": \"^0.0.4\"\n            },\n            \"time\": \"2017-10-06T14:32:02+00:00\",\n            \"type\": \"library\",\n            \"extra\": {\n                \"branch-alias\": {\n                    \"dev-master\": \"1.0.x-dev\"\n                }\n            },\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"psr-4\": {\n                    \"GuzzleHttp\\\\Command\\\\Guzzle\\\\\": \"src/\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Michael Dowling\",\n                    \"email\": \"mtdowling@gmail.com\",\n                    \"homepage\": \"https://github.com/mtdowling\"\n                },\n                {\n                    \"name\": \"Jeremy Lindblom\",\n                    \"email\": \"jeremeamia@gmail.com\",\n                    \"homepage\": \"https://github.com/jeremeamia\"\n                },\n                {\n                    \"name\": \"Stefano Kowalke\",\n                    \"email\": \"blueduck@mail.org\",\n                    \"homepage\": \"https://github.com/konafets\"\n                }\n            ],\n            \"description\": \"Provides an implementation of the Guzzle Command library that uses Guzzle service descriptions to describe web services, serialize requests, and parse responses into easy to use model structures.\",\n            \"support\": {\n                \"issues\": \"https://github.com/guzzle/guzzle-services/issues\",\n                \"source\": \"https://github.com/guzzle/guzzle-services/tree/1.1.3\"\n            },\n            \"install-path\": \"../guzzlehttp/guzzle-services\"\n        },\n        {\n            \"name\": \"guzzlehttp/promises\",\n            \"version\": \"1.5.3\",\n            \"version_normalized\": \"1.5.3.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/guzzle/promises.git\",\n                \"reference\": \"67ab6e18aaa14d753cc148911d273f6e6cb6721e\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/guzzle/promises/zipball/67ab6e18aaa14d753cc148911d273f6e6cb6721e\",\n                \"reference\": \"67ab6e18aaa14d753cc148911d273f6e6cb6721e\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"php\": \">=5.5\"\n            },\n            \"require-dev\": {\n                \"symfony/phpunit-bridge\": \"^4.4 || ^5.1\"\n            },\n            \"time\": \"2023-05-21T12:31:43+00:00\",\n            \"type\": \"library\",\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"files\": [\n                    \"src/functions_include.php\"\n                ],\n                \"psr-4\": {\n                    \"GuzzleHttp\\\\Promise\\\\\": \"src/\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Graham Campbell\",\n                    \"email\": \"hello@gjcampbell.co.uk\",\n                    \"homepage\": \"https://github.com/GrahamCampbell\"\n                },\n                {\n                    \"name\": \"Michael Dowling\",\n                    \"email\": \"mtdowling@gmail.com\",\n                    \"homepage\": \"https://github.com/mtdowling\"\n                },\n                {\n                    \"name\": \"Tobias Nyholm\",\n                    \"email\": \"tobias.nyholm@gmail.com\",\n                    \"homepage\": \"https://github.com/Nyholm\"\n                },\n                {\n                    \"name\": \"Tobias Schultze\",\n                    \"email\": \"webmaster@tubo-world.de\",\n                    \"homepage\": \"https://github.com/Tobion\"\n                }\n            ],\n            \"description\": \"Guzzle promises library\",\n            \"keywords\": [\n                \"promise\"\n            ],\n            \"support\": {\n                \"issues\": \"https://github.com/guzzle/promises/issues\",\n                \"source\": \"https://github.com/guzzle/promises/tree/1.5.3\"\n            },\n            \"funding\": [\n                {\n                    \"url\": \"https://github.com/GrahamCampbell\",\n                    \"type\": \"github\"\n                },\n                {\n                    \"url\": \"https://github.com/Nyholm\",\n                    \"type\": \"github\"\n                },\n                {\n                    \"url\": \"https://tidelift.com/funding/github/packagist/guzzlehttp/promises\",\n                    \"type\": \"tidelift\"\n                }\n            ],\n            \"install-path\": \"../guzzlehttp/promises\"\n        },\n        {\n            \"name\": \"guzzlehttp/psr7\",\n            \"version\": \"1.9.1\",\n            \"version_normalized\": \"1.9.1.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/guzzle/psr7.git\",\n                \"reference\": \"e4490cabc77465aaee90b20cfc9a770f8c04be6b\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/guzzle/psr7/zipball/e4490cabc77465aaee90b20cfc9a770f8c04be6b\",\n                \"reference\": \"e4490cabc77465aaee90b20cfc9a770f8c04be6b\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"php\": \">=5.4.0\",\n                \"psr/http-message\": \"~1.0\",\n                \"ralouphie/getallheaders\": \"^2.0.5 || ^3.0.0\"\n            },\n            \"provide\": {\n                \"psr/http-message-implementation\": \"1.0\"\n            },\n            \"require-dev\": {\n                \"ext-zlib\": \"*\",\n                \"phpunit/phpunit\": \"~4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.10\"\n            },\n            \"suggest\": {\n                \"laminas/laminas-httphandlerrunner\": \"Emit PSR-7 responses\"\n            },\n            \"time\": \"2023-04-17T16:00:37+00:00\",\n            \"type\": \"library\",\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"files\": [\n                    \"src/functions_include.php\"\n                ],\n                \"psr-4\": {\n                    \"GuzzleHttp\\\\Psr7\\\\\": \"src/\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Graham Campbell\",\n                    \"email\": \"hello@gjcampbell.co.uk\",\n                    \"homepage\": \"https://github.com/GrahamCampbell\"\n                },\n                {\n                    \"name\": \"Michael Dowling\",\n                    \"email\": \"mtdowling@gmail.com\",\n                    \"homepage\": \"https://github.com/mtdowling\"\n                },\n                {\n                    \"name\": \"George Mponos\",\n                    \"email\": \"gmponos@gmail.com\",\n                    \"homepage\": \"https://github.com/gmponos\"\n                },\n                {\n                    \"name\": \"Tobias Nyholm\",\n                    \"email\": \"tobias.nyholm@gmail.com\",\n                    \"homepage\": \"https://github.com/Nyholm\"\n                },\n                {\n                    \"name\": \"Márk Sági-Kazár\",\n                    \"email\": \"mark.sagikazar@gmail.com\",\n                    \"homepage\": \"https://github.com/sagikazarmark\"\n                },\n                {\n                    \"name\": \"Tobias Schultze\",\n                    \"email\": \"webmaster@tubo-world.de\",\n                    \"homepage\": \"https://github.com/Tobion\"\n                }\n            ],\n            \"description\": \"PSR-7 message implementation that also provides common utility methods\",\n            \"keywords\": [\n                \"http\",\n                \"message\",\n                \"psr-7\",\n                \"request\",\n                \"response\",\n                \"stream\",\n                \"uri\",\n                \"url\"\n            ],\n            \"support\": {\n                \"issues\": \"https://github.com/guzzle/psr7/issues\",\n                \"source\": \"https://github.com/guzzle/psr7/tree/1.9.1\"\n            },\n            \"funding\": [\n                {\n                    \"url\": \"https://github.com/GrahamCampbell\",\n                    \"type\": \"github\"\n                },\n                {\n                    \"url\": \"https://github.com/Nyholm\",\n                    \"type\": \"github\"\n                },\n                {\n                    \"url\": \"https://tidelift.com/funding/github/packagist/guzzlehttp/psr7\",\n                    \"type\": \"tidelift\"\n                }\n            ],\n            \"install-path\": \"../guzzlehttp/psr7\"\n        },\n        {\n            \"name\": \"illuminate/bus\",\n            \"version\": \"v8.83.27\",\n            \"version_normalized\": \"8.83.27.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/illuminate/bus.git\",\n                \"reference\": \"d2a8ae4bfd881086e55455e470776358eab27eae\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/illuminate/bus/zipball/d2a8ae4bfd881086e55455e470776358eab27eae\",\n                \"reference\": \"d2a8ae4bfd881086e55455e470776358eab27eae\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"illuminate/collections\": \"^8.0\",\n                \"illuminate/contracts\": \"^8.0\",\n                \"illuminate/pipeline\": \"^8.0\",\n                \"illuminate/support\": \"^8.0\",\n                \"php\": \"^7.3|^8.0\"\n            },\n            \"suggest\": {\n                \"illuminate/queue\": \"Required to use closures when chaining jobs (^7.0).\"\n            },\n            \"time\": \"2022-03-07T15:02:42+00:00\",\n            \"type\": \"library\",\n            \"extra\": {\n                \"branch-alias\": {\n                    \"dev-master\": \"8.x-dev\"\n                }\n            },\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"psr-4\": {\n                    \"Illuminate\\\\Bus\\\\\": \"\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Taylor Otwell\",\n                    \"email\": \"taylor@laravel.com\"\n                }\n            ],\n            \"description\": \"The Illuminate Bus package.\",\n            \"homepage\": \"https://laravel.com\",\n            \"support\": {\n                \"issues\": \"https://github.com/laravel/framework/issues\",\n                \"source\": \"https://github.com/laravel/framework\"\n            },\n            \"install-path\": \"../illuminate/bus\"\n        },\n        {\n            \"name\": \"illuminate/collections\",\n            \"version\": \"v8.83.27\",\n            \"version_normalized\": \"8.83.27.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/illuminate/collections.git\",\n                \"reference\": \"705a4e1ef93cd492c45b9b3e7911cccc990a07f4\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/illuminate/collections/zipball/705a4e1ef93cd492c45b9b3e7911cccc990a07f4\",\n                \"reference\": \"705a4e1ef93cd492c45b9b3e7911cccc990a07f4\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"illuminate/contracts\": \"^8.0\",\n                \"illuminate/macroable\": \"^8.0\",\n                \"php\": \"^7.3|^8.0\"\n            },\n            \"suggest\": {\n                \"symfony/var-dumper\": \"Required to use the dump method (^5.4).\"\n            },\n            \"time\": \"2022-06-23T15:29:49+00:00\",\n            \"type\": \"library\",\n            \"extra\": {\n                \"branch-alias\": {\n                    \"dev-master\": \"8.x-dev\"\n                }\n            },\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"files\": [\n                    \"helpers.php\"\n                ],\n                \"psr-4\": {\n                    \"Illuminate\\\\Support\\\\\": \"\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Taylor Otwell\",\n                    \"email\": \"taylor@laravel.com\"\n                }\n            ],\n            \"description\": \"The Illuminate Collections package.\",\n            \"homepage\": \"https://laravel.com\",\n            \"support\": {\n                \"issues\": \"https://github.com/laravel/framework/issues\",\n                \"source\": \"https://github.com/laravel/framework\"\n            },\n            \"install-path\": \"../illuminate/collections\"\n        },\n        {\n            \"name\": \"illuminate/container\",\n            \"version\": \"v8.83.27\",\n            \"version_normalized\": \"8.83.27.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/illuminate/container.git\",\n                \"reference\": \"14062628d05f75047c5a1360b9350028427d568e\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/illuminate/container/zipball/14062628d05f75047c5a1360b9350028427d568e\",\n                \"reference\": \"14062628d05f75047c5a1360b9350028427d568e\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"illuminate/contracts\": \"^8.0\",\n                \"php\": \"^7.3|^8.0\",\n                \"psr/container\": \"^1.0\"\n            },\n            \"provide\": {\n                \"psr/container-implementation\": \"1.0\"\n            },\n            \"time\": \"2022-02-02T21:03:35+00:00\",\n            \"type\": \"library\",\n            \"extra\": {\n                \"branch-alias\": {\n                    \"dev-master\": \"8.x-dev\"\n                }\n            },\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"psr-4\": {\n                    \"Illuminate\\\\Container\\\\\": \"\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Taylor Otwell\",\n                    \"email\": \"taylor@laravel.com\"\n                }\n            ],\n            \"description\": \"The Illuminate Container package.\",\n            \"homepage\": \"https://laravel.com\",\n            \"support\": {\n                \"issues\": \"https://github.com/laravel/framework/issues\",\n                \"source\": \"https://github.com/laravel/framework\"\n            },\n            \"install-path\": \"../illuminate/container\"\n        },\n        {\n            \"name\": \"illuminate/contracts\",\n            \"version\": \"v8.83.27\",\n            \"version_normalized\": \"8.83.27.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/illuminate/contracts.git\",\n                \"reference\": \"5e0fd287a1b22a6b346a9f7cd484d8cf0234585d\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/illuminate/contracts/zipball/5e0fd287a1b22a6b346a9f7cd484d8cf0234585d\",\n                \"reference\": \"5e0fd287a1b22a6b346a9f7cd484d8cf0234585d\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"php\": \"^7.3|^8.0\",\n                \"psr/container\": \"^1.0\",\n                \"psr/simple-cache\": \"^1.0\"\n            },\n            \"time\": \"2022-01-13T14:47:47+00:00\",\n            \"type\": \"library\",\n            \"extra\": {\n                \"branch-alias\": {\n                    \"dev-master\": \"8.x-dev\"\n                }\n            },\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"psr-4\": {\n                    \"Illuminate\\\\Contracts\\\\\": \"\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Taylor Otwell\",\n                    \"email\": \"taylor@laravel.com\"\n                }\n            ],\n            \"description\": \"The Illuminate Contracts package.\",\n            \"homepage\": \"https://laravel.com\",\n            \"support\": {\n                \"issues\": \"https://github.com/laravel/framework/issues\",\n                \"source\": \"https://github.com/laravel/framework\"\n            },\n            \"install-path\": \"../illuminate/contracts\"\n        },\n        {\n            \"name\": \"illuminate/database\",\n            \"version\": \"v8.83.27\",\n            \"version_normalized\": \"8.83.27.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/illuminate/database.git\",\n                \"reference\": \"1a5b0e4e6913415464fa2aab554a38b9e6fa44b1\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/illuminate/database/zipball/1a5b0e4e6913415464fa2aab554a38b9e6fa44b1\",\n                \"reference\": \"1a5b0e4e6913415464fa2aab554a38b9e6fa44b1\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"ext-json\": \"*\",\n                \"illuminate/collections\": \"^8.0\",\n                \"illuminate/container\": \"^8.0\",\n                \"illuminate/contracts\": \"^8.0\",\n                \"illuminate/macroable\": \"^8.0\",\n                \"illuminate/support\": \"^8.0\",\n                \"php\": \"^7.3|^8.0\",\n                \"symfony/console\": \"^5.4\"\n            },\n            \"suggest\": {\n                \"doctrine/dbal\": \"Required to rename columns and drop SQLite columns (^2.13.3|^3.1.4).\",\n                \"fakerphp/faker\": \"Required to use the eloquent factory builder (^1.9.1).\",\n                \"illuminate/console\": \"Required to use the database commands (^8.0).\",\n                \"illuminate/events\": \"Required to use the observers with Eloquent (^8.0).\",\n                \"illuminate/filesystem\": \"Required to use the migrations (^8.0).\",\n                \"illuminate/pagination\": \"Required to paginate the result set (^8.0).\",\n                \"symfony/finder\": \"Required to use Eloquent model factories (^5.4).\"\n            },\n            \"time\": \"2022-08-31T16:16:06+00:00\",\n            \"type\": \"library\",\n            \"extra\": {\n                \"branch-alias\": {\n                    \"dev-master\": \"8.x-dev\"\n                }\n            },\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"psr-4\": {\n                    \"Illuminate\\\\Database\\\\\": \"\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Taylor Otwell\",\n                    \"email\": \"taylor@laravel.com\"\n                }\n            ],\n            \"description\": \"The Illuminate Database package.\",\n            \"homepage\": \"https://laravel.com\",\n            \"keywords\": [\n                \"database\",\n                \"laravel\",\n                \"orm\",\n                \"sql\"\n            ],\n            \"support\": {\n                \"issues\": \"https://github.com/laravel/framework/issues\",\n                \"source\": \"https://github.com/laravel/framework\"\n            },\n            \"install-path\": \"../illuminate/database\"\n        },\n        {\n            \"name\": \"illuminate/events\",\n            \"version\": \"v8.83.27\",\n            \"version_normalized\": \"8.83.27.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/illuminate/events.git\",\n                \"reference\": \"b7f06cafb6c09581617f2ca05d69e9b159e5a35d\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/illuminate/events/zipball/b7f06cafb6c09581617f2ca05d69e9b159e5a35d\",\n                \"reference\": \"b7f06cafb6c09581617f2ca05d69e9b159e5a35d\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"illuminate/bus\": \"^8.0\",\n                \"illuminate/collections\": \"^8.0\",\n                \"illuminate/container\": \"^8.0\",\n                \"illuminate/contracts\": \"^8.0\",\n                \"illuminate/macroable\": \"^8.0\",\n                \"illuminate/support\": \"^8.0\",\n                \"php\": \"^7.3|^8.0\"\n            },\n            \"time\": \"2021-09-15T14:32:50+00:00\",\n            \"type\": \"library\",\n            \"extra\": {\n                \"branch-alias\": {\n                    \"dev-master\": \"8.x-dev\"\n                }\n            },\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"files\": [\n                    \"functions.php\"\n                ],\n                \"psr-4\": {\n                    \"Illuminate\\\\Events\\\\\": \"\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Taylor Otwell\",\n                    \"email\": \"taylor@laravel.com\"\n                }\n            ],\n            \"description\": \"The Illuminate Events package.\",\n            \"homepage\": \"https://laravel.com\",\n            \"support\": {\n                \"issues\": \"https://github.com/laravel/framework/issues\",\n                \"source\": \"https://github.com/laravel/framework\"\n            },\n            \"install-path\": \"../illuminate/events\"\n        },\n        {\n            \"name\": \"illuminate/macroable\",\n            \"version\": \"v8.83.27\",\n            \"version_normalized\": \"8.83.27.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/illuminate/macroable.git\",\n                \"reference\": \"aed81891a6e046fdee72edd497f822190f61c162\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/illuminate/macroable/zipball/aed81891a6e046fdee72edd497f822190f61c162\",\n                \"reference\": \"aed81891a6e046fdee72edd497f822190f61c162\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"php\": \"^7.3|^8.0\"\n            },\n            \"time\": \"2021-11-16T13:57:03+00:00\",\n            \"type\": \"library\",\n            \"extra\": {\n                \"branch-alias\": {\n                    \"dev-master\": \"8.x-dev\"\n                }\n            },\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"psr-4\": {\n                    \"Illuminate\\\\Support\\\\\": \"\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Taylor Otwell\",\n                    \"email\": \"taylor@laravel.com\"\n                }\n            ],\n            \"description\": \"The Illuminate Macroable package.\",\n            \"homepage\": \"https://laravel.com\",\n            \"support\": {\n                \"issues\": \"https://github.com/laravel/framework/issues\",\n                \"source\": \"https://github.com/laravel/framework\"\n            },\n            \"install-path\": \"../illuminate/macroable\"\n        },\n        {\n            \"name\": \"illuminate/pipeline\",\n            \"version\": \"v8.83.27\",\n            \"version_normalized\": \"8.83.27.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/illuminate/pipeline.git\",\n                \"reference\": \"23aeff5b26ae4aee3f370835c76bd0f4e93f71d2\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/illuminate/pipeline/zipball/23aeff5b26ae4aee3f370835c76bd0f4e93f71d2\",\n                \"reference\": \"23aeff5b26ae4aee3f370835c76bd0f4e93f71d2\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"illuminate/contracts\": \"^8.0\",\n                \"illuminate/support\": \"^8.0\",\n                \"php\": \"^7.3|^8.0\"\n            },\n            \"time\": \"2021-03-26T18:39:16+00:00\",\n            \"type\": \"library\",\n            \"extra\": {\n                \"branch-alias\": {\n                    \"dev-master\": \"8.x-dev\"\n                }\n            },\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"psr-4\": {\n                    \"Illuminate\\\\Pipeline\\\\\": \"\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Taylor Otwell\",\n                    \"email\": \"taylor@laravel.com\"\n                }\n            ],\n            \"description\": \"The Illuminate Pipeline package.\",\n            \"homepage\": \"https://laravel.com\",\n            \"support\": {\n                \"issues\": \"https://github.com/laravel/framework/issues\",\n                \"source\": \"https://github.com/laravel/framework\"\n            },\n            \"install-path\": \"../illuminate/pipeline\"\n        },\n        {\n            \"name\": \"illuminate/support\",\n            \"version\": \"v8.83.27\",\n            \"version_normalized\": \"8.83.27.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/illuminate/support.git\",\n                \"reference\": \"1c79242468d3bbd9a0f7477df34f9647dde2a09b\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/illuminate/support/zipball/1c79242468d3bbd9a0f7477df34f9647dde2a09b\",\n                \"reference\": \"1c79242468d3bbd9a0f7477df34f9647dde2a09b\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"doctrine/inflector\": \"^1.4|^2.0\",\n                \"ext-json\": \"*\",\n                \"ext-mbstring\": \"*\",\n                \"illuminate/collections\": \"^8.0\",\n                \"illuminate/contracts\": \"^8.0\",\n                \"illuminate/macroable\": \"^8.0\",\n                \"nesbot/carbon\": \"^2.53.1\",\n                \"php\": \"^7.3|^8.0\",\n                \"voku/portable-ascii\": \"^1.6.1\"\n            },\n            \"conflict\": {\n                \"tightenco/collect\": \"<5.5.33\"\n            },\n            \"suggest\": {\n                \"illuminate/filesystem\": \"Required to use the composer class (^8.0).\",\n                \"league/commonmark\": \"Required to use Str::markdown() and Stringable::markdown() (^1.3|^2.0.2).\",\n                \"ramsey/uuid\": \"Required to use Str::uuid() (^4.2.2).\",\n                \"symfony/process\": \"Required to use the composer class (^5.4).\",\n                \"symfony/var-dumper\": \"Required to use the dd function (^5.4).\",\n                \"vlucas/phpdotenv\": \"Required to use the Env class and env helper (^5.4.1).\"\n            },\n            \"time\": \"2022-09-21T21:30:03+00:00\",\n            \"type\": \"library\",\n            \"extra\": {\n                \"branch-alias\": {\n                    \"dev-master\": \"8.x-dev\"\n                }\n            },\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"files\": [\n                    \"helpers.php\"\n                ],\n                \"psr-4\": {\n                    \"Illuminate\\\\Support\\\\\": \"\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Taylor Otwell\",\n                    \"email\": \"taylor@laravel.com\"\n                }\n            ],\n            \"description\": \"The Illuminate Support package.\",\n            \"homepage\": \"https://laravel.com\",\n            \"support\": {\n                \"issues\": \"https://github.com/laravel/framework/issues\",\n                \"source\": \"https://github.com/laravel/framework\"\n            },\n            \"install-path\": \"../illuminate/support\"\n        },\n        {\n            \"name\": \"jasig/phpcas\",\n            \"version\": \"1.6.1\",\n            \"version_normalized\": \"1.6.1.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/apereo/phpCAS.git\",\n                \"reference\": \"c129708154852656aabb13d8606cd5b12dbbabac\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/apereo/phpCAS/zipball/c129708154852656aabb13d8606cd5b12dbbabac\",\n                \"reference\": \"c129708154852656aabb13d8606cd5b12dbbabac\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"ext-curl\": \"*\",\n                \"ext-dom\": \"*\",\n                \"php\": \">=7.1.0\",\n                \"psr/log\": \"^1.0 || ^2.0 || ^3.0\"\n            },\n            \"require-dev\": {\n                \"monolog/monolog\": \"^1.0.0 || ^2.0.0\",\n                \"phpstan/phpstan\": \"^1.5\",\n                \"phpunit/phpunit\": \">=7.5\"\n            },\n            \"time\": \"2023-02-19T19:52:35+00:00\",\n            \"type\": \"library\",\n            \"extra\": {\n                \"branch-alias\": {\n                    \"dev-master\": \"1.3.x-dev\"\n                }\n            },\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"files\": [\n                    \"source/CAS.php\"\n                ],\n                \"classmap\": [\n                    \"source/\"\n                ]\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"Apache-2.0\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Joachim Fritschi\",\n                    \"email\": \"jfritschi@freenet.de\",\n                    \"homepage\": \"https://github.com/jfritschi\"\n                },\n                {\n                    \"name\": \"Adam Franco\",\n                    \"homepage\": \"https://github.com/adamfranco\"\n                },\n                {\n                    \"name\": \"Henry Pan\",\n                    \"homepage\": \"https://github.com/phy25\"\n                }\n            ],\n            \"description\": \"Provides a simple API for authenticating users against a CAS server\",\n            \"homepage\": \"https://wiki.jasig.org/display/CASC/phpCAS\",\n            \"keywords\": [\n                \"apereo\",\n                \"cas\",\n                \"jasig\"\n            ],\n            \"support\": {\n                \"issues\": \"https://github.com/apereo/phpCAS/issues\",\n                \"source\": \"https://github.com/apereo/phpCAS/tree/1.6.1\"\n            },\n            \"abandoned\": \"apereo/phpcas\",\n            \"install-path\": \"../jasig/phpcas\"\n        },\n        {\n            \"name\": \"laravel/serializable-closure\",\n            \"version\": \"v1.3.7\",\n            \"version_normalized\": \"1.3.7.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/laravel/serializable-closure.git\",\n                \"reference\": \"4f48ade902b94323ca3be7646db16209ec76be3d\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/laravel/serializable-closure/zipball/4f48ade902b94323ca3be7646db16209ec76be3d\",\n                \"reference\": \"4f48ade902b94323ca3be7646db16209ec76be3d\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"php\": \"^7.3|^8.0\"\n            },\n            \"require-dev\": {\n                \"illuminate/support\": \"^8.0|^9.0|^10.0|^11.0\",\n                \"nesbot/carbon\": \"^2.61|^3.0\",\n                \"pestphp/pest\": \"^1.21.3\",\n                \"phpstan/phpstan\": \"^1.8.2\",\n                \"symfony/var-dumper\": \"^5.4.11|^6.2.0|^7.0.0\"\n            },\n            \"time\": \"2024-11-14T18:34:49+00:00\",\n            \"type\": \"library\",\n            \"extra\": {\n                \"branch-alias\": {\n                    \"dev-master\": \"1.x-dev\"\n                }\n            },\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"psr-4\": {\n                    \"Laravel\\\\SerializableClosure\\\\\": \"src/\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Taylor Otwell\",\n                    \"email\": \"taylor@laravel.com\"\n                },\n                {\n                    \"name\": \"Nuno Maduro\",\n                    \"email\": \"nuno@laravel.com\"\n                }\n            ],\n            \"description\": \"Laravel Serializable Closure provides an easy and secure way to serialize closures in PHP.\",\n            \"keywords\": [\n                \"closure\",\n                \"laravel\",\n                \"serializable\"\n            ],\n            \"support\": {\n                \"issues\": \"https://github.com/laravel/serializable-closure/issues\",\n                \"source\": \"https://github.com/laravel/serializable-closure\"\n            },\n            \"install-path\": \"../laravel/serializable-closure\"\n        },\n        {\n            \"name\": \"league/oauth2-client\",\n            \"version\": \"2.9.0\",\n            \"version_normalized\": \"2.9.0.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/thephpleague/oauth2-client.git\",\n                \"reference\": \"26e8c5da4f3d78cede7021e09b1330a0fc093d5e\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/thephpleague/oauth2-client/zipball/26e8c5da4f3d78cede7021e09b1330a0fc093d5e\",\n                \"reference\": \"26e8c5da4f3d78cede7021e09b1330a0fc093d5e\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"ext-json\": \"*\",\n                \"guzzlehttp/guzzle\": \"^6.5.8 || ^7.4.5\",\n                \"php\": \"^7.1 || >=8.0.0 <8.6.0\"\n            },\n            \"require-dev\": {\n                \"mockery/mockery\": \"^1.3.5\",\n                \"php-parallel-lint/php-parallel-lint\": \"^1.4\",\n                \"phpunit/phpunit\": \"^7 || ^8 || ^9 || ^10 || ^11\",\n                \"squizlabs/php_codesniffer\": \"^3.11\"\n            },\n            \"time\": \"2025-11-25T22:17:17+00:00\",\n            \"type\": \"library\",\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"psr-4\": {\n                    \"League\\\\OAuth2\\\\Client\\\\\": \"src/\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Alex Bilbie\",\n                    \"email\": \"hello@alexbilbie.com\",\n                    \"homepage\": \"http://www.alexbilbie.com\",\n                    \"role\": \"Developer\"\n                },\n                {\n                    \"name\": \"Woody Gilk\",\n                    \"homepage\": \"https://github.com/shadowhand\",\n                    \"role\": \"Contributor\"\n                }\n            ],\n            \"description\": \"OAuth 2.0 Client Library\",\n            \"keywords\": [\n                \"Authentication\",\n                \"SSO\",\n                \"authorization\",\n                \"identity\",\n                \"idp\",\n                \"oauth\",\n                \"oauth2\",\n                \"single sign on\"\n            ],\n            \"support\": {\n                \"issues\": \"https://github.com/thephpleague/oauth2-client/issues\",\n                \"source\": \"https://github.com/thephpleague/oauth2-client/tree/2.9.0\"\n            },\n            \"install-path\": \"../league/oauth2-client\"\n        },\n        {\n            \"name\": \"nesbot/carbon\",\n            \"version\": \"2.73.0\",\n            \"version_normalized\": \"2.73.0.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/CarbonPHP/carbon.git\",\n                \"reference\": \"9228ce90e1035ff2f0db84b40ec2e023ed802075\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/CarbonPHP/carbon/zipball/9228ce90e1035ff2f0db84b40ec2e023ed802075\",\n                \"reference\": \"9228ce90e1035ff2f0db84b40ec2e023ed802075\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"carbonphp/carbon-doctrine-types\": \"*\",\n                \"ext-json\": \"*\",\n                \"php\": \"^7.1.8 || ^8.0\",\n                \"psr/clock\": \"^1.0\",\n                \"symfony/polyfill-mbstring\": \"^1.0\",\n                \"symfony/polyfill-php80\": \"^1.16\",\n                \"symfony/translation\": \"^3.4 || ^4.0 || ^5.0 || ^6.0\"\n            },\n            \"provide\": {\n                \"psr/clock-implementation\": \"1.0\"\n            },\n            \"require-dev\": {\n                \"doctrine/dbal\": \"^2.0 || ^3.1.4 || ^4.0\",\n                \"doctrine/orm\": \"^2.7 || ^3.0\",\n                \"friendsofphp/php-cs-fixer\": \"^3.0\",\n                \"kylekatarnls/multi-tester\": \"^2.0\",\n                \"ondrejmirtes/better-reflection\": \"<6\",\n                \"phpmd/phpmd\": \"^2.9\",\n                \"phpstan/extension-installer\": \"^1.0\",\n                \"phpstan/phpstan\": \"^0.12.99 || ^1.7.14\",\n                \"phpunit/php-file-iterator\": \"^2.0.5 || ^3.0.6\",\n                \"phpunit/phpunit\": \"^7.5.20 || ^8.5.26 || ^9.5.20\",\n                \"squizlabs/php_codesniffer\": \"^3.4\"\n            },\n            \"time\": \"2025-01-08T20:10:23+00:00\",\n            \"bin\": [\n                \"bin/carbon\"\n            ],\n            \"type\": \"library\",\n            \"extra\": {\n                \"laravel\": {\n                    \"providers\": [\n                        \"Carbon\\\\Laravel\\\\ServiceProvider\"\n                    ]\n                },\n                \"phpstan\": {\n                    \"includes\": [\n                        \"extension.neon\"\n                    ]\n                },\n                \"branch-alias\": {\n                    \"dev-2.x\": \"2.x-dev\",\n                    \"dev-master\": \"3.x-dev\"\n                }\n            },\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"psr-4\": {\n                    \"Carbon\\\\\": \"src/Carbon/\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Brian Nesbitt\",\n                    \"email\": \"brian@nesbot.com\",\n                    \"homepage\": \"https://markido.com\"\n                },\n                {\n                    \"name\": \"kylekatarnls\",\n                    \"homepage\": \"https://github.com/kylekatarnls\"\n                }\n            ],\n            \"description\": \"An API extension for DateTime that supports 281 different languages.\",\n            \"homepage\": \"https://carbon.nesbot.com\",\n            \"keywords\": [\n                \"date\",\n                \"datetime\",\n                \"time\"\n            ],\n            \"support\": {\n                \"docs\": \"https://carbon.nesbot.com/docs\",\n                \"issues\": \"https://github.com/briannesbitt/Carbon/issues\",\n                \"source\": \"https://github.com/briannesbitt/Carbon\"\n            },\n            \"funding\": [\n                {\n                    \"url\": \"https://github.com/sponsors/kylekatarnls\",\n                    \"type\": \"github\"\n                },\n                {\n                    \"url\": \"https://opencollective.com/Carbon#sponsor\",\n                    \"type\": \"opencollective\"\n                },\n                {\n                    \"url\": \"https://tidelift.com/subscription/pkg/packagist-nesbot-carbon?utm_source=packagist-nesbot-carbon&utm_medium=referral&utm_campaign=readme\",\n                    \"type\": \"tidelift\"\n                }\n            ],\n            \"install-path\": \"../nesbot/carbon\"\n        },\n        {\n            \"name\": \"nikic/fast-route\",\n            \"version\": \"v1.3.0\",\n            \"version_normalized\": \"1.3.0.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/nikic/FastRoute.git\",\n                \"reference\": \"181d480e08d9476e61381e04a71b34dc0432e812\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/nikic/FastRoute/zipball/181d480e08d9476e61381e04a71b34dc0432e812\",\n                \"reference\": \"181d480e08d9476e61381e04a71b34dc0432e812\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"php\": \">=5.4.0\"\n            },\n            \"require-dev\": {\n                \"phpunit/phpunit\": \"^4.8.35|~5.7\"\n            },\n            \"time\": \"2018-02-13T20:26:39+00:00\",\n            \"type\": \"library\",\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"files\": [\n                    \"src/functions.php\"\n                ],\n                \"psr-4\": {\n                    \"FastRoute\\\\\": \"src/\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"BSD-3-Clause\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Nikita Popov\",\n                    \"email\": \"nikic@php.net\"\n                }\n            ],\n            \"description\": \"Fast request router for PHP\",\n            \"keywords\": [\n                \"router\",\n                \"routing\"\n            ],\n            \"support\": {\n                \"issues\": \"https://github.com/nikic/FastRoute/issues\",\n                \"source\": \"https://github.com/nikic/FastRoute/tree/master\"\n            },\n            \"install-path\": \"../nikic/fast-route\"\n        },\n        {\n            \"name\": \"php-di/invoker\",\n            \"version\": \"2.3.5\",\n            \"version_normalized\": \"2.3.5.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/PHP-DI/Invoker.git\",\n                \"reference\": \"93d381d0ec42074f43530506849fdc2d3a86a809\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/PHP-DI/Invoker/zipball/93d381d0ec42074f43530506849fdc2d3a86a809\",\n                \"reference\": \"93d381d0ec42074f43530506849fdc2d3a86a809\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"php\": \">=7.3\",\n                \"psr/container\": \"^1.0|^2.0\"\n            },\n            \"require-dev\": {\n                \"athletic/athletic\": \"~0.1.8\",\n                \"mnapoli/hard-mode\": \"~0.3.0\",\n                \"phpunit/phpunit\": \"^9.0\"\n            },\n            \"time\": \"2025-01-17T10:02:37+00:00\",\n            \"type\": \"library\",\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"psr-4\": {\n                    \"Invoker\\\\\": \"src/\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"description\": \"Generic and extensible callable invoker\",\n            \"homepage\": \"https://github.com/PHP-DI/Invoker\",\n            \"keywords\": [\n                \"callable\",\n                \"dependency\",\n                \"dependency-injection\",\n                \"injection\",\n                \"invoke\",\n                \"invoker\"\n            ],\n            \"support\": {\n                \"issues\": \"https://github.com/PHP-DI/Invoker/issues\",\n                \"source\": \"https://github.com/PHP-DI/Invoker/tree/2.3.5\"\n            },\n            \"funding\": [\n                {\n                    \"url\": \"https://github.com/mnapoli\",\n                    \"type\": \"github\"\n                }\n            ],\n            \"install-path\": \"../php-di/invoker\"\n        },\n        {\n            \"name\": \"php-di/php-di\",\n            \"version\": \"6.4.0\",\n            \"version_normalized\": \"6.4.0.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/PHP-DI/PHP-DI.git\",\n                \"reference\": \"ae0f1b3b03d8b29dff81747063cbfd6276246cc4\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/PHP-DI/PHP-DI/zipball/ae0f1b3b03d8b29dff81747063cbfd6276246cc4\",\n                \"reference\": \"ae0f1b3b03d8b29dff81747063cbfd6276246cc4\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"laravel/serializable-closure\": \"^1.0\",\n                \"php\": \">=7.4.0\",\n                \"php-di/invoker\": \"^2.0\",\n                \"php-di/phpdoc-reader\": \"^2.0.1\",\n                \"psr/container\": \"^1.0\"\n            },\n            \"provide\": {\n                \"psr/container-implementation\": \"^1.0\"\n            },\n            \"require-dev\": {\n                \"doctrine/annotations\": \"~1.10\",\n                \"friendsofphp/php-cs-fixer\": \"^2.4\",\n                \"mnapoli/phpunit-easymock\": \"^1.2\",\n                \"ocramius/proxy-manager\": \"^2.11.2\",\n                \"phpstan/phpstan\": \"^0.12\",\n                \"phpunit/phpunit\": \"^9.5\"\n            },\n            \"suggest\": {\n                \"doctrine/annotations\": \"Install it if you want to use annotations (version ~1.2)\",\n                \"ocramius/proxy-manager\": \"Install it if you want to use lazy injection (version ~2.0)\"\n            },\n            \"time\": \"2022-04-09T16:46:38+00:00\",\n            \"type\": \"library\",\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"files\": [\n                    \"src/functions.php\"\n                ],\n                \"psr-4\": {\n                    \"DI\\\\\": \"src/\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"description\": \"The dependency injection container for humans\",\n            \"homepage\": \"https://php-di.org/\",\n            \"keywords\": [\n                \"PSR-11\",\n                \"container\",\n                \"container-interop\",\n                \"dependency injection\",\n                \"di\",\n                \"ioc\",\n                \"psr11\"\n            ],\n            \"support\": {\n                \"issues\": \"https://github.com/PHP-DI/PHP-DI/issues\",\n                \"source\": \"https://github.com/PHP-DI/PHP-DI/tree/6.4.0\"\n            },\n            \"funding\": [\n                {\n                    \"url\": \"https://github.com/mnapoli\",\n                    \"type\": \"github\"\n                },\n                {\n                    \"url\": \"https://tidelift.com/funding/github/packagist/php-di/php-di\",\n                    \"type\": \"tidelift\"\n                }\n            ],\n            \"install-path\": \"../php-di/php-di\"\n        },\n        {\n            \"name\": \"php-di/phpdoc-reader\",\n            \"version\": \"2.2.1\",\n            \"version_normalized\": \"2.2.1.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/PHP-DI/PhpDocReader.git\",\n                \"reference\": \"66daff34cbd2627740ffec9469ffbac9f8c8185c\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/PHP-DI/PhpDocReader/zipball/66daff34cbd2627740ffec9469ffbac9f8c8185c\",\n                \"reference\": \"66daff34cbd2627740ffec9469ffbac9f8c8185c\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"php\": \">=7.2.0\"\n            },\n            \"require-dev\": {\n                \"mnapoli/hard-mode\": \"~0.3.0\",\n                \"phpunit/phpunit\": \"^8.5|^9.0\"\n            },\n            \"time\": \"2020-10-12T12:39:22+00:00\",\n            \"type\": \"library\",\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"psr-4\": {\n                    \"PhpDocReader\\\\\": \"src/PhpDocReader\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"description\": \"PhpDocReader parses @var and @param values in PHP docblocks (supports namespaced class names with the same resolution rules as PHP)\",\n            \"keywords\": [\n                \"phpdoc\",\n                \"reflection\"\n            ],\n            \"support\": {\n                \"issues\": \"https://github.com/PHP-DI/PhpDocReader/issues\",\n                \"source\": \"https://github.com/PHP-DI/PhpDocReader/tree/2.2.1\"\n            },\n            \"install-path\": \"../php-di/phpdoc-reader\"\n        },\n        {\n            \"name\": \"phpoption/phpoption\",\n            \"version\": \"1.9.3\",\n            \"version_normalized\": \"1.9.3.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/schmittjoh/php-option.git\",\n                \"reference\": \"e3fac8b24f56113f7cb96af14958c0dd16330f54\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/schmittjoh/php-option/zipball/e3fac8b24f56113f7cb96af14958c0dd16330f54\",\n                \"reference\": \"e3fac8b24f56113f7cb96af14958c0dd16330f54\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"php\": \"^7.2.5 || ^8.0\"\n            },\n            \"require-dev\": {\n                \"bamarni/composer-bin-plugin\": \"^1.8.2\",\n                \"phpunit/phpunit\": \"^8.5.39 || ^9.6.20 || ^10.5.28\"\n            },\n            \"time\": \"2024-07-20T21:41:07+00:00\",\n            \"type\": \"library\",\n            \"extra\": {\n                \"bamarni-bin\": {\n                    \"bin-links\": true,\n                    \"forward-command\": false\n                },\n                \"branch-alias\": {\n                    \"dev-master\": \"1.9-dev\"\n                }\n            },\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"psr-4\": {\n                    \"PhpOption\\\\\": \"src/PhpOption/\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"Apache-2.0\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Johannes M. Schmitt\",\n                    \"email\": \"schmittjoh@gmail.com\",\n                    \"homepage\": \"https://github.com/schmittjoh\"\n                },\n                {\n                    \"name\": \"Graham Campbell\",\n                    \"email\": \"hello@gjcampbell.co.uk\",\n                    \"homepage\": \"https://github.com/GrahamCampbell\"\n                }\n            ],\n            \"description\": \"Option Type for PHP\",\n            \"keywords\": [\n                \"language\",\n                \"option\",\n                \"php\",\n                \"type\"\n            ],\n            \"support\": {\n                \"issues\": \"https://github.com/schmittjoh/php-option/issues\",\n                \"source\": \"https://github.com/schmittjoh/php-option/tree/1.9.3\"\n            },\n            \"funding\": [\n                {\n                    \"url\": \"https://github.com/GrahamCampbell\",\n                    \"type\": \"github\"\n                },\n                {\n                    \"url\": \"https://tidelift.com/funding/github/packagist/phpoption/phpoption\",\n                    \"type\": \"tidelift\"\n                }\n            ],\n            \"install-path\": \"../phpoption/phpoption\"\n        },\n        {\n            \"name\": \"psr/cache\",\n            \"version\": \"3.0.0\",\n            \"version_normalized\": \"3.0.0.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/php-fig/cache.git\",\n                \"reference\": \"aa5030cfa5405eccfdcb1083ce040c2cb8d253bf\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf\",\n                \"reference\": \"aa5030cfa5405eccfdcb1083ce040c2cb8d253bf\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"php\": \">=8.0.0\"\n            },\n            \"time\": \"2021-02-03T23:26:27+00:00\",\n            \"type\": \"library\",\n            \"extra\": {\n                \"branch-alias\": {\n                    \"dev-master\": \"1.0.x-dev\"\n                }\n            },\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"psr-4\": {\n                    \"Psr\\\\Cache\\\\\": \"src/\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"PHP-FIG\",\n                    \"homepage\": \"https://www.php-fig.org/\"\n                }\n            ],\n            \"description\": \"Common interface for caching libraries\",\n            \"keywords\": [\n                \"cache\",\n                \"psr\",\n                \"psr-6\"\n            ],\n            \"support\": {\n                \"source\": \"https://github.com/php-fig/cache/tree/3.0.0\"\n            },\n            \"install-path\": \"../psr/cache\"\n        },\n        {\n            \"name\": \"psr/clock\",\n            \"version\": \"1.0.0\",\n            \"version_normalized\": \"1.0.0.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/php-fig/clock.git\",\n                \"reference\": \"e41a24703d4560fd0acb709162f73b8adfc3aa0d\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/php-fig/clock/zipball/e41a24703d4560fd0acb709162f73b8adfc3aa0d\",\n                \"reference\": \"e41a24703d4560fd0acb709162f73b8adfc3aa0d\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"php\": \"^7.0 || ^8.0\"\n            },\n            \"time\": \"2022-11-25T14:36:26+00:00\",\n            \"type\": \"library\",\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"psr-4\": {\n                    \"Psr\\\\Clock\\\\\": \"src/\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"PHP-FIG\",\n                    \"homepage\": \"https://www.php-fig.org/\"\n                }\n            ],\n            \"description\": \"Common interface for reading the clock.\",\n            \"homepage\": \"https://github.com/php-fig/clock\",\n            \"keywords\": [\n                \"clock\",\n                \"now\",\n                \"psr\",\n                \"psr-20\",\n                \"time\"\n            ],\n            \"support\": {\n                \"issues\": \"https://github.com/php-fig/clock/issues\",\n                \"source\": \"https://github.com/php-fig/clock/tree/1.0.0\"\n            },\n            \"install-path\": \"../psr/clock\"\n        },\n        {\n            \"name\": \"psr/container\",\n            \"version\": \"1.1.2\",\n            \"version_normalized\": \"1.1.2.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/php-fig/container.git\",\n                \"reference\": \"513e0666f7216c7459170d56df27dfcefe1689ea\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea\",\n                \"reference\": \"513e0666f7216c7459170d56df27dfcefe1689ea\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"php\": \">=7.4.0\"\n            },\n            \"time\": \"2021-11-05T16:50:12+00:00\",\n            \"type\": \"library\",\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"psr-4\": {\n                    \"Psr\\\\Container\\\\\": \"src/\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"PHP-FIG\",\n                    \"homepage\": \"https://www.php-fig.org/\"\n                }\n            ],\n            \"description\": \"Common Container Interface (PHP FIG PSR-11)\",\n            \"homepage\": \"https://github.com/php-fig/container\",\n            \"keywords\": [\n                \"PSR-11\",\n                \"container\",\n                \"container-interface\",\n                \"container-interop\",\n                \"psr\"\n            ],\n            \"support\": {\n                \"issues\": \"https://github.com/php-fig/container/issues\",\n                \"source\": \"https://github.com/php-fig/container/tree/1.1.2\"\n            },\n            \"install-path\": \"../psr/container\"\n        },\n        {\n            \"name\": \"psr/http-factory\",\n            \"version\": \"1.0.2\",\n            \"version_normalized\": \"1.0.2.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/php-fig/http-factory.git\",\n                \"reference\": \"e616d01114759c4c489f93b099585439f795fe35\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/php-fig/http-factory/zipball/e616d01114759c4c489f93b099585439f795fe35\",\n                \"reference\": \"e616d01114759c4c489f93b099585439f795fe35\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"php\": \">=7.0.0\",\n                \"psr/http-message\": \"^1.0 || ^2.0\"\n            },\n            \"time\": \"2023-04-10T20:10:41+00:00\",\n            \"type\": \"library\",\n            \"extra\": {\n                \"branch-alias\": {\n                    \"dev-master\": \"1.0.x-dev\"\n                }\n            },\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"psr-4\": {\n                    \"Psr\\\\Http\\\\Message\\\\\": \"src/\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"PHP-FIG\",\n                    \"homepage\": \"https://www.php-fig.org/\"\n                }\n            ],\n            \"description\": \"Common interfaces for PSR-7 HTTP message factories\",\n            \"keywords\": [\n                \"factory\",\n                \"http\",\n                \"message\",\n                \"psr\",\n                \"psr-17\",\n                \"psr-7\",\n                \"request\",\n                \"response\"\n            ],\n            \"support\": {\n                \"source\": \"https://github.com/php-fig/http-factory/tree/1.0.2\"\n            },\n            \"install-path\": \"../psr/http-factory\"\n        },\n        {\n            \"name\": \"psr/http-message\",\n            \"version\": \"1.1\",\n            \"version_normalized\": \"1.1.0.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/php-fig/http-message.git\",\n                \"reference\": \"cb6ce4845ce34a8ad9e68117c10ee90a29919eba\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/php-fig/http-message/zipball/cb6ce4845ce34a8ad9e68117c10ee90a29919eba\",\n                \"reference\": \"cb6ce4845ce34a8ad9e68117c10ee90a29919eba\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"php\": \"^7.2 || ^8.0\"\n            },\n            \"time\": \"2023-04-04T09:50:52+00:00\",\n            \"type\": \"library\",\n            \"extra\": {\n                \"branch-alias\": {\n                    \"dev-master\": \"1.1.x-dev\"\n                }\n            },\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"psr-4\": {\n                    \"Psr\\\\Http\\\\Message\\\\\": \"src/\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"PHP-FIG\",\n                    \"homepage\": \"http://www.php-fig.org/\"\n                }\n            ],\n            \"description\": \"Common interface for HTTP messages\",\n            \"homepage\": \"https://github.com/php-fig/http-message\",\n            \"keywords\": [\n                \"http\",\n                \"http-message\",\n                \"psr\",\n                \"psr-7\",\n                \"request\",\n                \"response\"\n            ],\n            \"support\": {\n                \"source\": \"https://github.com/php-fig/http-message/tree/1.1\"\n            },\n            \"install-path\": \"../psr/http-message\"\n        },\n        {\n            \"name\": \"psr/http-server-handler\",\n            \"version\": \"1.0.2\",\n            \"version_normalized\": \"1.0.2.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/php-fig/http-server-handler.git\",\n                \"reference\": \"84c4fb66179be4caaf8e97bd239203245302e7d4\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/php-fig/http-server-handler/zipball/84c4fb66179be4caaf8e97bd239203245302e7d4\",\n                \"reference\": \"84c4fb66179be4caaf8e97bd239203245302e7d4\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"php\": \">=7.0\",\n                \"psr/http-message\": \"^1.0 || ^2.0\"\n            },\n            \"time\": \"2023-04-10T20:06:20+00:00\",\n            \"type\": \"library\",\n            \"extra\": {\n                \"branch-alias\": {\n                    \"dev-master\": \"1.0.x-dev\"\n                }\n            },\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"psr-4\": {\n                    \"Psr\\\\Http\\\\Server\\\\\": \"src/\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"PHP-FIG\",\n                    \"homepage\": \"https://www.php-fig.org/\"\n                }\n            ],\n            \"description\": \"Common interface for HTTP server-side request handler\",\n            \"keywords\": [\n                \"handler\",\n                \"http\",\n                \"http-interop\",\n                \"psr\",\n                \"psr-15\",\n                \"psr-7\",\n                \"request\",\n                \"response\",\n                \"server\"\n            ],\n            \"support\": {\n                \"source\": \"https://github.com/php-fig/http-server-handler/tree/1.0.2\"\n            },\n            \"install-path\": \"../psr/http-server-handler\"\n        },\n        {\n            \"name\": \"psr/http-server-middleware\",\n            \"version\": \"1.0.2\",\n            \"version_normalized\": \"1.0.2.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/php-fig/http-server-middleware.git\",\n                \"reference\": \"c1481f747daaa6a0782775cd6a8c26a1bf4a3829\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/php-fig/http-server-middleware/zipball/c1481f747daaa6a0782775cd6a8c26a1bf4a3829\",\n                \"reference\": \"c1481f747daaa6a0782775cd6a8c26a1bf4a3829\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"php\": \">=7.0\",\n                \"psr/http-message\": \"^1.0 || ^2.0\",\n                \"psr/http-server-handler\": \"^1.0\"\n            },\n            \"time\": \"2023-04-11T06:14:47+00:00\",\n            \"type\": \"library\",\n            \"extra\": {\n                \"branch-alias\": {\n                    \"dev-master\": \"1.0.x-dev\"\n                }\n            },\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"psr-4\": {\n                    \"Psr\\\\Http\\\\Server\\\\\": \"src/\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"PHP-FIG\",\n                    \"homepage\": \"https://www.php-fig.org/\"\n                }\n            ],\n            \"description\": \"Common interface for HTTP server-side middleware\",\n            \"keywords\": [\n                \"http\",\n                \"http-interop\",\n                \"middleware\",\n                \"psr\",\n                \"psr-15\",\n                \"psr-7\",\n                \"request\",\n                \"response\"\n            ],\n            \"support\": {\n                \"issues\": \"https://github.com/php-fig/http-server-middleware/issues\",\n                \"source\": \"https://github.com/php-fig/http-server-middleware/tree/1.0.2\"\n            },\n            \"install-path\": \"../psr/http-server-middleware\"\n        },\n        {\n            \"name\": \"psr/log\",\n            \"version\": \"2.0.0\",\n            \"version_normalized\": \"2.0.0.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/php-fig/log.git\",\n                \"reference\": \"ef29f6d262798707a9edd554e2b82517ef3a9376\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/php-fig/log/zipball/ef29f6d262798707a9edd554e2b82517ef3a9376\",\n                \"reference\": \"ef29f6d262798707a9edd554e2b82517ef3a9376\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"php\": \">=8.0.0\"\n            },\n            \"time\": \"2021-07-14T16:41:46+00:00\",\n            \"type\": \"library\",\n            \"extra\": {\n                \"branch-alias\": {\n                    \"dev-master\": \"2.0.x-dev\"\n                }\n            },\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"psr-4\": {\n                    \"Psr\\\\Log\\\\\": \"src\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"PHP-FIG\",\n                    \"homepage\": \"https://www.php-fig.org/\"\n                }\n            ],\n            \"description\": \"Common interface for logging libraries\",\n            \"homepage\": \"https://github.com/php-fig/log\",\n            \"keywords\": [\n                \"log\",\n                \"psr\",\n                \"psr-3\"\n            ],\n            \"support\": {\n                \"source\": \"https://github.com/php-fig/log/tree/2.0.0\"\n            },\n            \"install-path\": \"../psr/log\"\n        },\n        {\n            \"name\": \"psr/simple-cache\",\n            \"version\": \"1.0.1\",\n            \"version_normalized\": \"1.0.1.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/php-fig/simple-cache.git\",\n                \"reference\": \"408d5eafb83c57f6365a3ca330ff23aa4a5fa39b\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b\",\n                \"reference\": \"408d5eafb83c57f6365a3ca330ff23aa4a5fa39b\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"php\": \">=5.3.0\"\n            },\n            \"time\": \"2017-10-23T01:57:42+00:00\",\n            \"type\": \"library\",\n            \"extra\": {\n                \"branch-alias\": {\n                    \"dev-master\": \"1.0.x-dev\"\n                }\n            },\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"psr-4\": {\n                    \"Psr\\\\SimpleCache\\\\\": \"src/\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"PHP-FIG\",\n                    \"homepage\": \"http://www.php-fig.org/\"\n                }\n            ],\n            \"description\": \"Common interfaces for simple caching\",\n            \"keywords\": [\n                \"cache\",\n                \"caching\",\n                \"psr\",\n                \"psr-16\",\n                \"simple-cache\"\n            ],\n            \"support\": {\n                \"source\": \"https://github.com/php-fig/simple-cache/tree/master\"\n            },\n            \"install-path\": \"../psr/simple-cache\"\n        },\n        {\n            \"name\": \"qcloud/cos-sdk-v5\",\n            \"version\": \"v1.3.5\",\n            \"version_normalized\": \"1.3.5.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/tencentyun/cos-php-sdk-v5.git\",\n                \"reference\": \"e67ad8143695192ee206bcbcafc78c08da92c621\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/tencentyun/cos-php-sdk-v5/zipball/e67ad8143695192ee206bcbcafc78c08da92c621\",\n                \"reference\": \"e67ad8143695192ee206bcbcafc78c08da92c621\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"guzzlehttp/guzzle\": \"~6.3\",\n                \"guzzlehttp/guzzle-services\": \"~1.1\",\n                \"php\": \">=5.3.0\"\n            },\n            \"time\": \"2021-05-18T12:47:31+00:00\",\n            \"type\": \"library\",\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"psr-4\": {\n                    \"Qcloud\\\\Cos\\\\\": \"src/Qcloud/Cos/\"\n                },\n                \"files\": [\n                    \"src/Qcloud/Cos/Common.php\"\n                ]\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"yaozongyou\",\n                    \"email\": \"yaozongyou@vip.qq.com\"\n                },\n                {\n                    \"name\": \"lewzylu\",\n                    \"email\": \"327874225@qq.com\"\n                }\n            ],\n            \"description\": \"PHP SDK for QCloud COS\",\n            \"keywords\": [\n                \"cos\",\n                \"php\",\n                \"qcloud\"\n            ],\n            \"support\": {\n                \"issues\": \"https://github.com/tencentyun/cos-php-sdk-v5/issues\",\n                \"source\": \"https://github.com/tencentyun/cos-php-sdk-v5/tree/v2.2.0\"\n            },\n            \"install-path\": \"../qcloud/cos-sdk-v5\"\n        },\n        {\n            \"name\": \"ralouphie/getallheaders\",\n            \"version\": \"3.0.3\",\n            \"version_normalized\": \"3.0.3.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/ralouphie/getallheaders.git\",\n                \"reference\": \"120b605dfeb996808c31b6477290a714d356e822\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822\",\n                \"reference\": \"120b605dfeb996808c31b6477290a714d356e822\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"php\": \">=5.6\"\n            },\n            \"require-dev\": {\n                \"php-coveralls/php-coveralls\": \"^2.1\",\n                \"phpunit/phpunit\": \"^5 || ^6.5\"\n            },\n            \"time\": \"2019-03-08T08:55:37+00:00\",\n            \"type\": \"library\",\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"files\": [\n                    \"src/getallheaders.php\"\n                ]\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Ralph Khattar\",\n                    \"email\": \"ralph.khattar@gmail.com\"\n                }\n            ],\n            \"description\": \"A polyfill for getallheaders.\",\n            \"support\": {\n                \"issues\": \"https://github.com/ralouphie/getallheaders/issues\",\n                \"source\": \"https://github.com/ralouphie/getallheaders/tree/develop\"\n            },\n            \"install-path\": \"../ralouphie/getallheaders\"\n        },\n        {\n            \"name\": \"slim/psr7\",\n            \"version\": \"1.6.2\",\n            \"version_normalized\": \"1.6.2.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/slimphp/Slim-Psr7.git\",\n                \"reference\": \"5c64088c146673473f5667cbeb501edf5508dfaf\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/slimphp/Slim-Psr7/zipball/5c64088c146673473f5667cbeb501edf5508dfaf\",\n                \"reference\": \"5c64088c146673473f5667cbeb501edf5508dfaf\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"fig/http-message-util\": \"^1.1.5\",\n                \"php\": \"^7.4 || ^8.0\",\n                \"psr/http-factory\": \"^1.0\",\n                \"psr/http-message\": \"^1.0\",\n                \"ralouphie/getallheaders\": \"^3.0\",\n                \"symfony/polyfill-php80\": \"^1.26\"\n            },\n            \"provide\": {\n                \"psr/http-factory-implementation\": \"1.0\",\n                \"psr/http-message-implementation\": \"1.0\"\n            },\n            \"require-dev\": {\n                \"adriansuter/php-autoload-override\": \"^1.3\",\n                \"ext-json\": \"*\",\n                \"http-interop/http-factory-tests\": \"^1.0 || ^2.0\",\n                \"php-http/psr7-integration-tests\": \"^1.4\",\n                \"phpspec/prophecy\": \"^1.15\",\n                \"phpspec/prophecy-phpunit\": \"^2.0\",\n                \"phpstan/phpstan\": \"^1.8\",\n                \"phpunit/phpunit\": \"^9.5 || ^10\",\n                \"squizlabs/php_codesniffer\": \"^3.7\"\n            },\n            \"time\": \"2025-03-23T11:43:29+00:00\",\n            \"type\": \"library\",\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"psr-4\": {\n                    \"Slim\\\\Psr7\\\\\": \"src\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Josh Lockhart\",\n                    \"email\": \"hello@joshlockhart.com\",\n                    \"homepage\": \"http://joshlockhart.com\"\n                },\n                {\n                    \"name\": \"Andrew Smith\",\n                    \"email\": \"a.smith@silentworks.co.uk\",\n                    \"homepage\": \"http://silentworks.co.uk\"\n                },\n                {\n                    \"name\": \"Rob Allen\",\n                    \"email\": \"rob@akrabat.com\",\n                    \"homepage\": \"http://akrabat.com\"\n                },\n                {\n                    \"name\": \"Pierre Berube\",\n                    \"email\": \"pierre@lgse.com\",\n                    \"homepage\": \"http://www.lgse.com\"\n                }\n            ],\n            \"description\": \"Strict PSR-7 implementation\",\n            \"homepage\": \"https://www.slimframework.com\",\n            \"keywords\": [\n                \"http\",\n                \"psr-7\",\n                \"psr7\"\n            ],\n            \"support\": {\n                \"issues\": \"https://github.com/slimphp/Slim-Psr7/issues\",\n                \"source\": \"https://github.com/slimphp/Slim-Psr7/tree/1.6.2\"\n            },\n            \"install-path\": \"../slim/psr7\"\n        },\n        {\n            \"name\": \"slim/slim\",\n            \"version\": \"4.13.0\",\n            \"version_normalized\": \"4.13.0.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/slimphp/Slim.git\",\n                \"reference\": \"038fd5713d5a41636fdff0e8dcceedecdd17fc17\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/slimphp/Slim/zipball/038fd5713d5a41636fdff0e8dcceedecdd17fc17\",\n                \"reference\": \"038fd5713d5a41636fdff0e8dcceedecdd17fc17\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"ext-json\": \"*\",\n                \"nikic/fast-route\": \"^1.3\",\n                \"php\": \"^7.4 || ^8.0\",\n                \"psr/container\": \"^1.0 || ^2.0\",\n                \"psr/http-factory\": \"^1.0\",\n                \"psr/http-message\": \"^1.1 || ^2.0\",\n                \"psr/http-server-handler\": \"^1.0\",\n                \"psr/http-server-middleware\": \"^1.0\",\n                \"psr/log\": \"^1.1 || ^2.0 || ^3.0\"\n            },\n            \"require-dev\": {\n                \"adriansuter/php-autoload-override\": \"^1.4\",\n                \"ext-simplexml\": \"*\",\n                \"guzzlehttp/psr7\": \"^2.6\",\n                \"httpsoft/http-message\": \"^1.1\",\n                \"httpsoft/http-server-request\": \"^1.1\",\n                \"laminas/laminas-diactoros\": \"^2.17 || ^3\",\n                \"nyholm/psr7\": \"^1.8\",\n                \"nyholm/psr7-server\": \"^1.1\",\n                \"phpspec/prophecy\": \"^1.19\",\n                \"phpspec/prophecy-phpunit\": \"^2.1\",\n                \"phpstan/phpstan\": \"^1.10\",\n                \"phpunit/phpunit\": \"^9.6\",\n                \"slim/http\": \"^1.3\",\n                \"slim/psr7\": \"^1.6\",\n                \"squizlabs/php_codesniffer\": \"^3.9\"\n            },\n            \"suggest\": {\n                \"ext-simplexml\": \"Needed to support XML format in BodyParsingMiddleware\",\n                \"ext-xml\": \"Needed to support XML format in BodyParsingMiddleware\",\n                \"php-di/php-di\": \"PHP-DI is the recommended container library to be used with Slim\",\n                \"slim/psr7\": \"Slim PSR-7 implementation. See https://www.slimframework.com/docs/v4/start/installation.html for more information.\"\n            },\n            \"time\": \"2024-03-03T21:25:30+00:00\",\n            \"type\": \"library\",\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"psr-4\": {\n                    \"Slim\\\\\": \"Slim\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Josh Lockhart\",\n                    \"email\": \"hello@joshlockhart.com\",\n                    \"homepage\": \"https://joshlockhart.com\"\n                },\n                {\n                    \"name\": \"Andrew Smith\",\n                    \"email\": \"a.smith@silentworks.co.uk\",\n                    \"homepage\": \"http://silentworks.co.uk\"\n                },\n                {\n                    \"name\": \"Rob Allen\",\n                    \"email\": \"rob@akrabat.com\",\n                    \"homepage\": \"http://akrabat.com\"\n                },\n                {\n                    \"name\": \"Pierre Berube\",\n                    \"email\": \"pierre@lgse.com\",\n                    \"homepage\": \"http://www.lgse.com\"\n                },\n                {\n                    \"name\": \"Gabriel Manricks\",\n                    \"email\": \"gmanricks@me.com\",\n                    \"homepage\": \"http://gabrielmanricks.com\"\n                }\n            ],\n            \"description\": \"Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs\",\n            \"homepage\": \"https://www.slimframework.com\",\n            \"keywords\": [\n                \"api\",\n                \"framework\",\n                \"micro\",\n                \"router\"\n            ],\n            \"support\": {\n                \"docs\": \"https://www.slimframework.com/docs/v4/\",\n                \"forum\": \"https://discourse.slimframework.com/\",\n                \"irc\": \"irc://irc.freenode.net:6667/slimphp\",\n                \"issues\": \"https://github.com/slimphp/Slim/issues\",\n                \"rss\": \"https://www.slimframework.com/blog/feed.rss\",\n                \"slack\": \"https://slimphp.slack.com/\",\n                \"source\": \"https://github.com/slimphp/Slim\",\n                \"wiki\": \"https://github.com/slimphp/Slim/wiki\"\n            },\n            \"funding\": [\n                {\n                    \"url\": \"https://opencollective.com/slimphp\",\n                    \"type\": \"open_collective\"\n                },\n                {\n                    \"url\": \"https://tidelift.com/funding/github/packagist/slim/slim\",\n                    \"type\": \"tidelift\"\n                }\n            ],\n            \"install-path\": \"../slim/slim\"\n        },\n        {\n            \"name\": \"symfony/console\",\n            \"version\": \"v5.4.47\",\n            \"version_normalized\": \"5.4.47.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/symfony/console.git\",\n                \"reference\": \"c4ba980ca61a9eb18ee6bcc73f28e475852bb1ed\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/symfony/console/zipball/c4ba980ca61a9eb18ee6bcc73f28e475852bb1ed\",\n                \"reference\": \"c4ba980ca61a9eb18ee6bcc73f28e475852bb1ed\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"php\": \">=7.2.5\",\n                \"symfony/deprecation-contracts\": \"^2.1|^3\",\n                \"symfony/polyfill-mbstring\": \"~1.0\",\n                \"symfony/polyfill-php73\": \"^1.9\",\n                \"symfony/polyfill-php80\": \"^1.16\",\n                \"symfony/service-contracts\": \"^1.1|^2|^3\",\n                \"symfony/string\": \"^5.1|^6.0\"\n            },\n            \"conflict\": {\n                \"psr/log\": \">=3\",\n                \"symfony/dependency-injection\": \"<4.4\",\n                \"symfony/dotenv\": \"<5.1\",\n                \"symfony/event-dispatcher\": \"<4.4\",\n                \"symfony/lock\": \"<4.4\",\n                \"symfony/process\": \"<4.4\"\n            },\n            \"provide\": {\n                \"psr/log-implementation\": \"1.0|2.0\"\n            },\n            \"require-dev\": {\n                \"psr/log\": \"^1|^2\",\n                \"symfony/config\": \"^4.4|^5.0|^6.0\",\n                \"symfony/dependency-injection\": \"^4.4|^5.0|^6.0\",\n                \"symfony/event-dispatcher\": \"^4.4|^5.0|^6.0\",\n                \"symfony/lock\": \"^4.4|^5.0|^6.0\",\n                \"symfony/process\": \"^4.4|^5.0|^6.0\",\n                \"symfony/var-dumper\": \"^4.4|^5.0|^6.0\"\n            },\n            \"suggest\": {\n                \"psr/log\": \"For using the console logger\",\n                \"symfony/event-dispatcher\": \"\",\n                \"symfony/lock\": \"\",\n                \"symfony/process\": \"\"\n            },\n            \"time\": \"2024-11-06T11:30:55+00:00\",\n            \"type\": \"library\",\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"psr-4\": {\n                    \"Symfony\\\\Component\\\\Console\\\\\": \"\"\n                },\n                \"exclude-from-classmap\": [\n                    \"/Tests/\"\n                ]\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Fabien Potencier\",\n                    \"email\": \"fabien@symfony.com\"\n                },\n                {\n                    \"name\": \"Symfony Community\",\n                    \"homepage\": \"https://symfony.com/contributors\"\n                }\n            ],\n            \"description\": \"Eases the creation of beautiful and testable command line interfaces\",\n            \"homepage\": \"https://symfony.com\",\n            \"keywords\": [\n                \"cli\",\n                \"command-line\",\n                \"console\",\n                \"terminal\"\n            ],\n            \"support\": {\n                \"source\": \"https://github.com/symfony/console/tree/v5.4.47\"\n            },\n            \"funding\": [\n                {\n                    \"url\": \"https://symfony.com/sponsor\",\n                    \"type\": \"custom\"\n                },\n                {\n                    \"url\": \"https://github.com/fabpot\",\n                    \"type\": \"github\"\n                },\n                {\n                    \"url\": \"https://tidelift.com/funding/github/packagist/symfony/symfony\",\n                    \"type\": \"tidelift\"\n                }\n            ],\n            \"install-path\": \"../symfony/console\"\n        },\n        {\n            \"name\": \"symfony/deprecation-contracts\",\n            \"version\": \"v3.5.1\",\n            \"version_normalized\": \"3.5.1.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/symfony/deprecation-contracts.git\",\n                \"reference\": \"74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/symfony/deprecation-contracts/zipball/74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6\",\n                \"reference\": \"74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"php\": \">=8.1\"\n            },\n            \"time\": \"2024-09-25T14:20:29+00:00\",\n            \"type\": \"library\",\n            \"extra\": {\n                \"thanks\": {\n                    \"url\": \"https://github.com/symfony/contracts\",\n                    \"name\": \"symfony/contracts\"\n                },\n                \"branch-alias\": {\n                    \"dev-main\": \"3.5-dev\"\n                }\n            },\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"files\": [\n                    \"function.php\"\n                ]\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Nicolas Grekas\",\n                    \"email\": \"p@tchwork.com\"\n                },\n                {\n                    \"name\": \"Symfony Community\",\n                    \"homepage\": \"https://symfony.com/contributors\"\n                }\n            ],\n            \"description\": \"A generic function and convention to trigger deprecation notices\",\n            \"homepage\": \"https://symfony.com\",\n            \"support\": {\n                \"source\": \"https://github.com/symfony/deprecation-contracts/tree/v3.5.1\"\n            },\n            \"funding\": [\n                {\n                    \"url\": \"https://symfony.com/sponsor\",\n                    \"type\": \"custom\"\n                },\n                {\n                    \"url\": \"https://github.com/fabpot\",\n                    \"type\": \"github\"\n                },\n                {\n                    \"url\": \"https://tidelift.com/funding/github/packagist/symfony/symfony\",\n                    \"type\": \"tidelift\"\n                }\n            ],\n            \"install-path\": \"../symfony/deprecation-contracts\"\n        },\n        {\n            \"name\": \"symfony/finder\",\n            \"version\": \"v6.4.27\",\n            \"version_normalized\": \"6.4.27.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/symfony/finder.git\",\n                \"reference\": \"a1b6aa435d2fba50793b994a839c32b6064f063b\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/symfony/finder/zipball/a1b6aa435d2fba50793b994a839c32b6064f063b\",\n                \"reference\": \"a1b6aa435d2fba50793b994a839c32b6064f063b\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"php\": \">=8.1\"\n            },\n            \"require-dev\": {\n                \"symfony/filesystem\": \"^6.0|^7.0\"\n            },\n            \"time\": \"2025-10-15T18:32:00+00:00\",\n            \"type\": \"library\",\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"psr-4\": {\n                    \"Symfony\\\\Component\\\\Finder\\\\\": \"\"\n                },\n                \"exclude-from-classmap\": [\n                    \"/Tests/\"\n                ]\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Fabien Potencier\",\n                    \"email\": \"fabien@symfony.com\"\n                },\n                {\n                    \"name\": \"Symfony Community\",\n                    \"homepage\": \"https://symfony.com/contributors\"\n                }\n            ],\n            \"description\": \"Finds files and directories via an intuitive fluent interface\",\n            \"homepage\": \"https://symfony.com\",\n            \"support\": {\n                \"source\": \"https://github.com/symfony/finder/tree/v6.4.27\"\n            },\n            \"funding\": [\n                {\n                    \"url\": \"https://symfony.com/sponsor\",\n                    \"type\": \"custom\"\n                },\n                {\n                    \"url\": \"https://github.com/fabpot\",\n                    \"type\": \"github\"\n                },\n                {\n                    \"url\": \"https://github.com/nicolas-grekas\",\n                    \"type\": \"github\"\n                },\n                {\n                    \"url\": \"https://tidelift.com/funding/github/packagist/symfony/symfony\",\n                    \"type\": \"tidelift\"\n                }\n            ],\n            \"install-path\": \"../symfony/finder\"\n        },\n        {\n            \"name\": \"symfony/http-client\",\n            \"version\": \"v6.4.28\",\n            \"version_normalized\": \"6.4.28.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/symfony/http-client.git\",\n                \"reference\": \"c9e69c185c4a845f9d46958cdb0dc7aa847f3981\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/symfony/http-client/zipball/c9e69c185c4a845f9d46958cdb0dc7aa847f3981\",\n                \"reference\": \"c9e69c185c4a845f9d46958cdb0dc7aa847f3981\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"php\": \">=8.1\",\n                \"psr/log\": \"^1|^2|^3\",\n                \"symfony/deprecation-contracts\": \"^2.5|^3\",\n                \"symfony/http-client-contracts\": \"~3.4.4|^3.5.2\",\n                \"symfony/polyfill-php83\": \"^1.29\",\n                \"symfony/service-contracts\": \"^2.5|^3\"\n            },\n            \"conflict\": {\n                \"php-http/discovery\": \"<1.15\",\n                \"symfony/http-foundation\": \"<6.3\"\n            },\n            \"provide\": {\n                \"php-http/async-client-implementation\": \"*\",\n                \"php-http/client-implementation\": \"*\",\n                \"psr/http-client-implementation\": \"1.0\",\n                \"symfony/http-client-implementation\": \"3.0\"\n            },\n            \"require-dev\": {\n                \"amphp/amp\": \"^2.5\",\n                \"amphp/http-client\": \"^4.2.1\",\n                \"amphp/http-tunnel\": \"^1.0\",\n                \"amphp/socket\": \"^1.1\",\n                \"guzzlehttp/promises\": \"^1.4|^2.0\",\n                \"nyholm/psr7\": \"^1.0\",\n                \"php-http/httplug\": \"^1.0|^2.0\",\n                \"psr/http-client\": \"^1.0\",\n                \"symfony/dependency-injection\": \"^5.4|^6.0|^7.0\",\n                \"symfony/http-kernel\": \"^5.4|^6.0|^7.0\",\n                \"symfony/messenger\": \"^5.4|^6.0|^7.0\",\n                \"symfony/process\": \"^5.4|^6.0|^7.0\",\n                \"symfony/stopwatch\": \"^5.4|^6.0|^7.0\"\n            },\n            \"time\": \"2025-11-05T17:39:22+00:00\",\n            \"type\": \"library\",\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"psr-4\": {\n                    \"Symfony\\\\Component\\\\HttpClient\\\\\": \"\"\n                },\n                \"exclude-from-classmap\": [\n                    \"/Tests/\"\n                ]\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Nicolas Grekas\",\n                    \"email\": \"p@tchwork.com\"\n                },\n                {\n                    \"name\": \"Symfony Community\",\n                    \"homepage\": \"https://symfony.com/contributors\"\n                }\n            ],\n            \"description\": \"Provides powerful methods to fetch HTTP resources synchronously or asynchronously\",\n            \"homepage\": \"https://symfony.com\",\n            \"keywords\": [\n                \"http\"\n            ],\n            \"support\": {\n                \"source\": \"https://github.com/symfony/http-client/tree/v6.4.28\"\n            },\n            \"funding\": [\n                {\n                    \"url\": \"https://symfony.com/sponsor\",\n                    \"type\": \"custom\"\n                },\n                {\n                    \"url\": \"https://github.com/fabpot\",\n                    \"type\": \"github\"\n                },\n                {\n                    \"url\": \"https://github.com/nicolas-grekas\",\n                    \"type\": \"github\"\n                },\n                {\n                    \"url\": \"https://tidelift.com/funding/github/packagist/symfony/symfony\",\n                    \"type\": \"tidelift\"\n                }\n            ],\n            \"install-path\": \"../symfony/http-client\"\n        },\n        {\n            \"name\": \"symfony/http-client-contracts\",\n            \"version\": \"v3.5.2\",\n            \"version_normalized\": \"3.5.2.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/symfony/http-client-contracts.git\",\n                \"reference\": \"ee8d807ab20fcb51267fdace50fbe3494c31e645\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/symfony/http-client-contracts/zipball/ee8d807ab20fcb51267fdace50fbe3494c31e645\",\n                \"reference\": \"ee8d807ab20fcb51267fdace50fbe3494c31e645\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"php\": \">=8.1\"\n            },\n            \"time\": \"2024-12-07T08:49:48+00:00\",\n            \"type\": \"library\",\n            \"extra\": {\n                \"thanks\": {\n                    \"url\": \"https://github.com/symfony/contracts\",\n                    \"name\": \"symfony/contracts\"\n                },\n                \"branch-alias\": {\n                    \"dev-main\": \"3.5-dev\"\n                }\n            },\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"psr-4\": {\n                    \"Symfony\\\\Contracts\\\\HttpClient\\\\\": \"\"\n                },\n                \"exclude-from-classmap\": [\n                    \"/Test/\"\n                ]\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Nicolas Grekas\",\n                    \"email\": \"p@tchwork.com\"\n                },\n                {\n                    \"name\": \"Symfony Community\",\n                    \"homepage\": \"https://symfony.com/contributors\"\n                }\n            ],\n            \"description\": \"Generic abstractions related to HTTP clients\",\n            \"homepage\": \"https://symfony.com\",\n            \"keywords\": [\n                \"abstractions\",\n                \"contracts\",\n                \"decoupling\",\n                \"interfaces\",\n                \"interoperability\",\n                \"standards\"\n            ],\n            \"support\": {\n                \"source\": \"https://github.com/symfony/http-client-contracts/tree/v3.5.2\"\n            },\n            \"funding\": [\n                {\n                    \"url\": \"https://symfony.com/sponsor\",\n                    \"type\": \"custom\"\n                },\n                {\n                    \"url\": \"https://github.com/fabpot\",\n                    \"type\": \"github\"\n                },\n                {\n                    \"url\": \"https://tidelift.com/funding/github/packagist/symfony/symfony\",\n                    \"type\": \"tidelift\"\n                }\n            ],\n            \"install-path\": \"../symfony/http-client-contracts\"\n        },\n        {\n            \"name\": \"symfony/polyfill-ctype\",\n            \"version\": \"v1.32.0\",\n            \"version_normalized\": \"1.32.0.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/symfony/polyfill-ctype.git\",\n                \"reference\": \"a3cc8b044a6ea513310cbd48ef7333b384945638\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638\",\n                \"reference\": \"a3cc8b044a6ea513310cbd48ef7333b384945638\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"php\": \">=7.2\"\n            },\n            \"provide\": {\n                \"ext-ctype\": \"*\"\n            },\n            \"suggest\": {\n                \"ext-ctype\": \"For best performance\"\n            },\n            \"time\": \"2024-09-09T11:45:10+00:00\",\n            \"type\": \"library\",\n            \"extra\": {\n                \"thanks\": {\n                    \"url\": \"https://github.com/symfony/polyfill\",\n                    \"name\": \"symfony/polyfill\"\n                }\n            },\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"files\": [\n                    \"bootstrap.php\"\n                ],\n                \"psr-4\": {\n                    \"Symfony\\\\Polyfill\\\\Ctype\\\\\": \"\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Gert de Pagter\",\n                    \"email\": \"BackEndTea@gmail.com\"\n                },\n                {\n                    \"name\": \"Symfony Community\",\n                    \"homepage\": \"https://symfony.com/contributors\"\n                }\n            ],\n            \"description\": \"Symfony polyfill for ctype functions\",\n            \"homepage\": \"https://symfony.com\",\n            \"keywords\": [\n                \"compatibility\",\n                \"ctype\",\n                \"polyfill\",\n                \"portable\"\n            ],\n            \"support\": {\n                \"source\": \"https://github.com/symfony/polyfill-ctype/tree/v1.32.0\"\n            },\n            \"funding\": [\n                {\n                    \"url\": \"https://symfony.com/sponsor\",\n                    \"type\": \"custom\"\n                },\n                {\n                    \"url\": \"https://github.com/fabpot\",\n                    \"type\": \"github\"\n                },\n                {\n                    \"url\": \"https://tidelift.com/funding/github/packagist/symfony/symfony\",\n                    \"type\": \"tidelift\"\n                }\n            ],\n            \"install-path\": \"../symfony/polyfill-ctype\"\n        },\n        {\n            \"name\": \"symfony/polyfill-intl-grapheme\",\n            \"version\": \"v1.32.0\",\n            \"version_normalized\": \"1.32.0.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/symfony/polyfill-intl-grapheme.git\",\n                \"reference\": \"b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe\",\n                \"reference\": \"b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"php\": \">=7.2\"\n            },\n            \"suggest\": {\n                \"ext-intl\": \"For best performance\"\n            },\n            \"time\": \"2024-09-09T11:45:10+00:00\",\n            \"type\": \"library\",\n            \"extra\": {\n                \"thanks\": {\n                    \"url\": \"https://github.com/symfony/polyfill\",\n                    \"name\": \"symfony/polyfill\"\n                }\n            },\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"files\": [\n                    \"bootstrap.php\"\n                ],\n                \"psr-4\": {\n                    \"Symfony\\\\Polyfill\\\\Intl\\\\Grapheme\\\\\": \"\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Nicolas Grekas\",\n                    \"email\": \"p@tchwork.com\"\n                },\n                {\n                    \"name\": \"Symfony Community\",\n                    \"homepage\": \"https://symfony.com/contributors\"\n                }\n            ],\n            \"description\": \"Symfony polyfill for intl's grapheme_* functions\",\n            \"homepage\": \"https://symfony.com\",\n            \"keywords\": [\n                \"compatibility\",\n                \"grapheme\",\n                \"intl\",\n                \"polyfill\",\n                \"portable\",\n                \"shim\"\n            ],\n            \"support\": {\n                \"source\": \"https://github.com/symfony/polyfill-intl-grapheme/tree/v1.32.0\"\n            },\n            \"funding\": [\n                {\n                    \"url\": \"https://symfony.com/sponsor\",\n                    \"type\": \"custom\"\n                },\n                {\n                    \"url\": \"https://github.com/fabpot\",\n                    \"type\": \"github\"\n                },\n                {\n                    \"url\": \"https://tidelift.com/funding/github/packagist/symfony/symfony\",\n                    \"type\": \"tidelift\"\n                }\n            ],\n            \"install-path\": \"../symfony/polyfill-intl-grapheme\"\n        },\n        {\n            \"name\": \"symfony/polyfill-intl-idn\",\n            \"version\": \"v1.32.0\",\n            \"version_normalized\": \"1.32.0.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/symfony/polyfill-intl-idn.git\",\n                \"reference\": \"9614ac4d8061dc257ecc64cba1b140873dce8ad3\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/9614ac4d8061dc257ecc64cba1b140873dce8ad3\",\n                \"reference\": \"9614ac4d8061dc257ecc64cba1b140873dce8ad3\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"php\": \">=7.2\",\n                \"symfony/polyfill-intl-normalizer\": \"^1.10\"\n            },\n            \"suggest\": {\n                \"ext-intl\": \"For best performance\"\n            },\n            \"time\": \"2024-09-10T14:38:51+00:00\",\n            \"type\": \"library\",\n            \"extra\": {\n                \"thanks\": {\n                    \"url\": \"https://github.com/symfony/polyfill\",\n                    \"name\": \"symfony/polyfill\"\n                }\n            },\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"files\": [\n                    \"bootstrap.php\"\n                ],\n                \"psr-4\": {\n                    \"Symfony\\\\Polyfill\\\\Intl\\\\Idn\\\\\": \"\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Laurent Bassin\",\n                    \"email\": \"laurent@bassin.info\"\n                },\n                {\n                    \"name\": \"Trevor Rowbotham\",\n                    \"email\": \"trevor.rowbotham@pm.me\"\n                },\n                {\n                    \"name\": \"Symfony Community\",\n                    \"homepage\": \"https://symfony.com/contributors\"\n                }\n            ],\n            \"description\": \"Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions\",\n            \"homepage\": \"https://symfony.com\",\n            \"keywords\": [\n                \"compatibility\",\n                \"idn\",\n                \"intl\",\n                \"polyfill\",\n                \"portable\",\n                \"shim\"\n            ],\n            \"support\": {\n                \"source\": \"https://github.com/symfony/polyfill-intl-idn/tree/v1.32.0\"\n            },\n            \"funding\": [\n                {\n                    \"url\": \"https://symfony.com/sponsor\",\n                    \"type\": \"custom\"\n                },\n                {\n                    \"url\": \"https://github.com/fabpot\",\n                    \"type\": \"github\"\n                },\n                {\n                    \"url\": \"https://tidelift.com/funding/github/packagist/symfony/symfony\",\n                    \"type\": \"tidelift\"\n                }\n            ],\n            \"install-path\": \"../symfony/polyfill-intl-idn\"\n        },\n        {\n            \"name\": \"symfony/polyfill-intl-normalizer\",\n            \"version\": \"v1.32.0\",\n            \"version_normalized\": \"1.32.0.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/symfony/polyfill-intl-normalizer.git\",\n                \"reference\": \"3833d7255cc303546435cb650316bff708a1c75c\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c\",\n                \"reference\": \"3833d7255cc303546435cb650316bff708a1c75c\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"php\": \">=7.2\"\n            },\n            \"suggest\": {\n                \"ext-intl\": \"For best performance\"\n            },\n            \"time\": \"2024-09-09T11:45:10+00:00\",\n            \"type\": \"library\",\n            \"extra\": {\n                \"thanks\": {\n                    \"url\": \"https://github.com/symfony/polyfill\",\n                    \"name\": \"symfony/polyfill\"\n                }\n            },\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"files\": [\n                    \"bootstrap.php\"\n                ],\n                \"psr-4\": {\n                    \"Symfony\\\\Polyfill\\\\Intl\\\\Normalizer\\\\\": \"\"\n                },\n                \"classmap\": [\n                    \"Resources/stubs\"\n                ]\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Nicolas Grekas\",\n                    \"email\": \"p@tchwork.com\"\n                },\n                {\n                    \"name\": \"Symfony Community\",\n                    \"homepage\": \"https://symfony.com/contributors\"\n                }\n            ],\n            \"description\": \"Symfony polyfill for intl's Normalizer class and related functions\",\n            \"homepage\": \"https://symfony.com\",\n            \"keywords\": [\n                \"compatibility\",\n                \"intl\",\n                \"normalizer\",\n                \"polyfill\",\n                \"portable\",\n                \"shim\"\n            ],\n            \"support\": {\n                \"source\": \"https://github.com/symfony/polyfill-intl-normalizer/tree/v1.32.0\"\n            },\n            \"funding\": [\n                {\n                    \"url\": \"https://symfony.com/sponsor\",\n                    \"type\": \"custom\"\n                },\n                {\n                    \"url\": \"https://github.com/fabpot\",\n                    \"type\": \"github\"\n                },\n                {\n                    \"url\": \"https://tidelift.com/funding/github/packagist/symfony/symfony\",\n                    \"type\": \"tidelift\"\n                }\n            ],\n            \"install-path\": \"../symfony/polyfill-intl-normalizer\"\n        },\n        {\n            \"name\": \"symfony/polyfill-mbstring\",\n            \"version\": \"v1.32.0\",\n            \"version_normalized\": \"1.32.0.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/symfony/polyfill-mbstring.git\",\n                \"reference\": \"6d857f4d76bd4b343eac26d6b539585d2bc56493\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493\",\n                \"reference\": \"6d857f4d76bd4b343eac26d6b539585d2bc56493\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"ext-iconv\": \"*\",\n                \"php\": \">=7.2\"\n            },\n            \"provide\": {\n                \"ext-mbstring\": \"*\"\n            },\n            \"suggest\": {\n                \"ext-mbstring\": \"For best performance\"\n            },\n            \"time\": \"2024-12-23T08:48:59+00:00\",\n            \"type\": \"library\",\n            \"extra\": {\n                \"thanks\": {\n                    \"url\": \"https://github.com/symfony/polyfill\",\n                    \"name\": \"symfony/polyfill\"\n                }\n            },\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"files\": [\n                    \"bootstrap.php\"\n                ],\n                \"psr-4\": {\n                    \"Symfony\\\\Polyfill\\\\Mbstring\\\\\": \"\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Nicolas Grekas\",\n                    \"email\": \"p@tchwork.com\"\n                },\n                {\n                    \"name\": \"Symfony Community\",\n                    \"homepage\": \"https://symfony.com/contributors\"\n                }\n            ],\n            \"description\": \"Symfony polyfill for the Mbstring extension\",\n            \"homepage\": \"https://symfony.com\",\n            \"keywords\": [\n                \"compatibility\",\n                \"mbstring\",\n                \"polyfill\",\n                \"portable\",\n                \"shim\"\n            ],\n            \"support\": {\n                \"source\": \"https://github.com/symfony/polyfill-mbstring/tree/v1.32.0\"\n            },\n            \"funding\": [\n                {\n                    \"url\": \"https://symfony.com/sponsor\",\n                    \"type\": \"custom\"\n                },\n                {\n                    \"url\": \"https://github.com/fabpot\",\n                    \"type\": \"github\"\n                },\n                {\n                    \"url\": \"https://tidelift.com/funding/github/packagist/symfony/symfony\",\n                    \"type\": \"tidelift\"\n                }\n            ],\n            \"install-path\": \"../symfony/polyfill-mbstring\"\n        },\n        {\n            \"name\": \"symfony/polyfill-php73\",\n            \"version\": \"v1.32.0\",\n            \"version_normalized\": \"1.32.0.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/symfony/polyfill-php73.git\",\n                \"reference\": \"0f68c03565dcaaf25a890667542e8bd75fe7e5bb\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/symfony/polyfill-php73/zipball/0f68c03565dcaaf25a890667542e8bd75fe7e5bb\",\n                \"reference\": \"0f68c03565dcaaf25a890667542e8bd75fe7e5bb\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"php\": \">=7.2\"\n            },\n            \"time\": \"2024-09-09T11:45:10+00:00\",\n            \"type\": \"library\",\n            \"extra\": {\n                \"thanks\": {\n                    \"url\": \"https://github.com/symfony/polyfill\",\n                    \"name\": \"symfony/polyfill\"\n                }\n            },\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"files\": [\n                    \"bootstrap.php\"\n                ],\n                \"psr-4\": {\n                    \"Symfony\\\\Polyfill\\\\Php73\\\\\": \"\"\n                },\n                \"classmap\": [\n                    \"Resources/stubs\"\n                ]\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Nicolas Grekas\",\n                    \"email\": \"p@tchwork.com\"\n                },\n                {\n                    \"name\": \"Symfony Community\",\n                    \"homepage\": \"https://symfony.com/contributors\"\n                }\n            ],\n            \"description\": \"Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions\",\n            \"homepage\": \"https://symfony.com\",\n            \"keywords\": [\n                \"compatibility\",\n                \"polyfill\",\n                \"portable\",\n                \"shim\"\n            ],\n            \"support\": {\n                \"source\": \"https://github.com/symfony/polyfill-php73/tree/v1.32.0\"\n            },\n            \"funding\": [\n                {\n                    \"url\": \"https://symfony.com/sponsor\",\n                    \"type\": \"custom\"\n                },\n                {\n                    \"url\": \"https://github.com/fabpot\",\n                    \"type\": \"github\"\n                },\n                {\n                    \"url\": \"https://tidelift.com/funding/github/packagist/symfony/symfony\",\n                    \"type\": \"tidelift\"\n                }\n            ],\n            \"install-path\": \"../symfony/polyfill-php73\"\n        },\n        {\n            \"name\": \"symfony/polyfill-php80\",\n            \"version\": \"v1.32.0\",\n            \"version_normalized\": \"1.32.0.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/symfony/polyfill-php80.git\",\n                \"reference\": \"0cc9dd0f17f61d8131e7df6b84bd344899fe2608\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/symfony/polyfill-php80/zipball/0cc9dd0f17f61d8131e7df6b84bd344899fe2608\",\n                \"reference\": \"0cc9dd0f17f61d8131e7df6b84bd344899fe2608\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"php\": \">=7.2\"\n            },\n            \"time\": \"2025-01-02T08:10:11+00:00\",\n            \"type\": \"library\",\n            \"extra\": {\n                \"thanks\": {\n                    \"url\": \"https://github.com/symfony/polyfill\",\n                    \"name\": \"symfony/polyfill\"\n                }\n            },\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"files\": [\n                    \"bootstrap.php\"\n                ],\n                \"psr-4\": {\n                    \"Symfony\\\\Polyfill\\\\Php80\\\\\": \"\"\n                },\n                \"classmap\": [\n                    \"Resources/stubs\"\n                ]\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Ion Bazan\",\n                    \"email\": \"ion.bazan@gmail.com\"\n                },\n                {\n                    \"name\": \"Nicolas Grekas\",\n                    \"email\": \"p@tchwork.com\"\n                },\n                {\n                    \"name\": \"Symfony Community\",\n                    \"homepage\": \"https://symfony.com/contributors\"\n                }\n            ],\n            \"description\": \"Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions\",\n            \"homepage\": \"https://symfony.com\",\n            \"keywords\": [\n                \"compatibility\",\n                \"polyfill\",\n                \"portable\",\n                \"shim\"\n            ],\n            \"support\": {\n                \"source\": \"https://github.com/symfony/polyfill-php80/tree/v1.32.0\"\n            },\n            \"funding\": [\n                {\n                    \"url\": \"https://symfony.com/sponsor\",\n                    \"type\": \"custom\"\n                },\n                {\n                    \"url\": \"https://github.com/fabpot\",\n                    \"type\": \"github\"\n                },\n                {\n                    \"url\": \"https://tidelift.com/funding/github/packagist/symfony/symfony\",\n                    \"type\": \"tidelift\"\n                }\n            ],\n            \"install-path\": \"../symfony/polyfill-php80\"\n        },\n        {\n            \"name\": \"symfony/polyfill-php83\",\n            \"version\": \"v1.32.0\",\n            \"version_normalized\": \"1.32.0.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/symfony/polyfill-php83.git\",\n                \"reference\": \"2fb86d65e2d424369ad2905e83b236a8805ba491\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/symfony/polyfill-php83/zipball/2fb86d65e2d424369ad2905e83b236a8805ba491\",\n                \"reference\": \"2fb86d65e2d424369ad2905e83b236a8805ba491\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"php\": \">=7.2\"\n            },\n            \"time\": \"2024-09-09T11:45:10+00:00\",\n            \"type\": \"library\",\n            \"extra\": {\n                \"thanks\": {\n                    \"url\": \"https://github.com/symfony/polyfill\",\n                    \"name\": \"symfony/polyfill\"\n                }\n            },\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"files\": [\n                    \"bootstrap.php\"\n                ],\n                \"psr-4\": {\n                    \"Symfony\\\\Polyfill\\\\Php83\\\\\": \"\"\n                },\n                \"classmap\": [\n                    \"Resources/stubs\"\n                ]\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Nicolas Grekas\",\n                    \"email\": \"p@tchwork.com\"\n                },\n                {\n                    \"name\": \"Symfony Community\",\n                    \"homepage\": \"https://symfony.com/contributors\"\n                }\n            ],\n            \"description\": \"Symfony polyfill backporting some PHP 8.3+ features to lower PHP versions\",\n            \"homepage\": \"https://symfony.com\",\n            \"keywords\": [\n                \"compatibility\",\n                \"polyfill\",\n                \"portable\",\n                \"shim\"\n            ],\n            \"support\": {\n                \"source\": \"https://github.com/symfony/polyfill-php83/tree/v1.32.0\"\n            },\n            \"funding\": [\n                {\n                    \"url\": \"https://symfony.com/sponsor\",\n                    \"type\": \"custom\"\n                },\n                {\n                    \"url\": \"https://github.com/fabpot\",\n                    \"type\": \"github\"\n                },\n                {\n                    \"url\": \"https://tidelift.com/funding/github/packagist/symfony/symfony\",\n                    \"type\": \"tidelift\"\n                }\n            ],\n            \"install-path\": \"../symfony/polyfill-php83\"\n        },\n        {\n            \"name\": \"symfony/service-contracts\",\n            \"version\": \"v3.6.1\",\n            \"version_normalized\": \"3.6.1.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/symfony/service-contracts.git\",\n                \"reference\": \"45112560a3ba2d715666a509a0bc9521d10b6c43\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/symfony/service-contracts/zipball/45112560a3ba2d715666a509a0bc9521d10b6c43\",\n                \"reference\": \"45112560a3ba2d715666a509a0bc9521d10b6c43\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"php\": \">=8.1\",\n                \"psr/container\": \"^1.1|^2.0\",\n                \"symfony/deprecation-contracts\": \"^2.5|^3\"\n            },\n            \"conflict\": {\n                \"ext-psr\": \"<1.1|>=2\"\n            },\n            \"time\": \"2025-07-15T11:30:57+00:00\",\n            \"type\": \"library\",\n            \"extra\": {\n                \"thanks\": {\n                    \"url\": \"https://github.com/symfony/contracts\",\n                    \"name\": \"symfony/contracts\"\n                },\n                \"branch-alias\": {\n                    \"dev-main\": \"3.6-dev\"\n                }\n            },\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"psr-4\": {\n                    \"Symfony\\\\Contracts\\\\Service\\\\\": \"\"\n                },\n                \"exclude-from-classmap\": [\n                    \"/Test/\"\n                ]\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Nicolas Grekas\",\n                    \"email\": \"p@tchwork.com\"\n                },\n                {\n                    \"name\": \"Symfony Community\",\n                    \"homepage\": \"https://symfony.com/contributors\"\n                }\n            ],\n            \"description\": \"Generic abstractions related to writing services\",\n            \"homepage\": \"https://symfony.com\",\n            \"keywords\": [\n                \"abstractions\",\n                \"contracts\",\n                \"decoupling\",\n                \"interfaces\",\n                \"interoperability\",\n                \"standards\"\n            ],\n            \"support\": {\n                \"source\": \"https://github.com/symfony/service-contracts/tree/v3.6.1\"\n            },\n            \"funding\": [\n                {\n                    \"url\": \"https://symfony.com/sponsor\",\n                    \"type\": \"custom\"\n                },\n                {\n                    \"url\": \"https://github.com/fabpot\",\n                    \"type\": \"github\"\n                },\n                {\n                    \"url\": \"https://github.com/nicolas-grekas\",\n                    \"type\": \"github\"\n                },\n                {\n                    \"url\": \"https://tidelift.com/funding/github/packagist/symfony/symfony\",\n                    \"type\": \"tidelift\"\n                }\n            ],\n            \"install-path\": \"../symfony/service-contracts\"\n        },\n        {\n            \"name\": \"symfony/string\",\n            \"version\": \"v6.4.26\",\n            \"version_normalized\": \"6.4.26.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/symfony/string.git\",\n                \"reference\": \"5621f039a71a11c87c106c1c598bdcd04a19aeea\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/symfony/string/zipball/5621f039a71a11c87c106c1c598bdcd04a19aeea\",\n                \"reference\": \"5621f039a71a11c87c106c1c598bdcd04a19aeea\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"php\": \">=8.1\",\n                \"symfony/polyfill-ctype\": \"~1.8\",\n                \"symfony/polyfill-intl-grapheme\": \"~1.0\",\n                \"symfony/polyfill-intl-normalizer\": \"~1.0\",\n                \"symfony/polyfill-mbstring\": \"~1.0\"\n            },\n            \"conflict\": {\n                \"symfony/translation-contracts\": \"<2.5\"\n            },\n            \"require-dev\": {\n                \"symfony/http-client\": \"^5.4|^6.0|^7.0\",\n                \"symfony/intl\": \"^6.2|^7.0\",\n                \"symfony/translation-contracts\": \"^2.5|^3.0\",\n                \"symfony/var-exporter\": \"^5.4|^6.0|^7.0\"\n            },\n            \"time\": \"2025-09-11T14:32:46+00:00\",\n            \"type\": \"library\",\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"files\": [\n                    \"Resources/functions.php\"\n                ],\n                \"psr-4\": {\n                    \"Symfony\\\\Component\\\\String\\\\\": \"\"\n                },\n                \"exclude-from-classmap\": [\n                    \"/Tests/\"\n                ]\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Nicolas Grekas\",\n                    \"email\": \"p@tchwork.com\"\n                },\n                {\n                    \"name\": \"Symfony Community\",\n                    \"homepage\": \"https://symfony.com/contributors\"\n                }\n            ],\n            \"description\": \"Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way\",\n            \"homepage\": \"https://symfony.com\",\n            \"keywords\": [\n                \"grapheme\",\n                \"i18n\",\n                \"string\",\n                \"unicode\",\n                \"utf-8\",\n                \"utf8\"\n            ],\n            \"support\": {\n                \"source\": \"https://github.com/symfony/string/tree/v6.4.26\"\n            },\n            \"funding\": [\n                {\n                    \"url\": \"https://symfony.com/sponsor\",\n                    \"type\": \"custom\"\n                },\n                {\n                    \"url\": \"https://github.com/fabpot\",\n                    \"type\": \"github\"\n                },\n                {\n                    \"url\": \"https://github.com/nicolas-grekas\",\n                    \"type\": \"github\"\n                },\n                {\n                    \"url\": \"https://tidelift.com/funding/github/packagist/symfony/symfony\",\n                    \"type\": \"tidelift\"\n                }\n            ],\n            \"install-path\": \"../symfony/string\"\n        },\n        {\n            \"name\": \"symfony/translation\",\n            \"version\": \"v6.4.30\",\n            \"version_normalized\": \"6.4.30.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/symfony/translation.git\",\n                \"reference\": \"d1fdeefd0707d15eb150c04e8837bf0b15ebea39\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/symfony/translation/zipball/d1fdeefd0707d15eb150c04e8837bf0b15ebea39\",\n                \"reference\": \"d1fdeefd0707d15eb150c04e8837bf0b15ebea39\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"php\": \">=8.1\",\n                \"symfony/deprecation-contracts\": \"^2.5|^3\",\n                \"symfony/polyfill-mbstring\": \"~1.0\",\n                \"symfony/translation-contracts\": \"^2.5|^3.0\"\n            },\n            \"conflict\": {\n                \"symfony/config\": \"<5.4\",\n                \"symfony/console\": \"<5.4\",\n                \"symfony/dependency-injection\": \"<5.4\",\n                \"symfony/http-client-contracts\": \"<2.5\",\n                \"symfony/http-kernel\": \"<5.4\",\n                \"symfony/service-contracts\": \"<2.5\",\n                \"symfony/twig-bundle\": \"<5.4\",\n                \"symfony/yaml\": \"<5.4\"\n            },\n            \"provide\": {\n                \"symfony/translation-implementation\": \"2.3|3.0\"\n            },\n            \"require-dev\": {\n                \"nikic/php-parser\": \"^4.18|^5.0\",\n                \"psr/log\": \"^1|^2|^3\",\n                \"symfony/config\": \"^5.4|^6.0|^7.0\",\n                \"symfony/console\": \"^5.4|^6.0|^7.0\",\n                \"symfony/dependency-injection\": \"^5.4|^6.0|^7.0\",\n                \"symfony/finder\": \"^5.4|^6.0|^7.0\",\n                \"symfony/http-client-contracts\": \"^2.5|^3.0\",\n                \"symfony/http-kernel\": \"^5.4|^6.0|^7.0\",\n                \"symfony/intl\": \"^5.4|^6.0|^7.0\",\n                \"symfony/polyfill-intl-icu\": \"^1.21\",\n                \"symfony/routing\": \"^5.4|^6.0|^7.0\",\n                \"symfony/service-contracts\": \"^2.5|^3\",\n                \"symfony/yaml\": \"^5.4|^6.0|^7.0\"\n            },\n            \"time\": \"2025-11-24T13:57:00+00:00\",\n            \"type\": \"library\",\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"files\": [\n                    \"Resources/functions.php\"\n                ],\n                \"psr-4\": {\n                    \"Symfony\\\\Component\\\\Translation\\\\\": \"\"\n                },\n                \"exclude-from-classmap\": [\n                    \"/Tests/\"\n                ]\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Fabien Potencier\",\n                    \"email\": \"fabien@symfony.com\"\n                },\n                {\n                    \"name\": \"Symfony Community\",\n                    \"homepage\": \"https://symfony.com/contributors\"\n                }\n            ],\n            \"description\": \"Provides tools to internationalize your application\",\n            \"homepage\": \"https://symfony.com\",\n            \"support\": {\n                \"source\": \"https://github.com/symfony/translation/tree/v6.4.30\"\n            },\n            \"funding\": [\n                {\n                    \"url\": \"https://symfony.com/sponsor\",\n                    \"type\": \"custom\"\n                },\n                {\n                    \"url\": \"https://github.com/fabpot\",\n                    \"type\": \"github\"\n                },\n                {\n                    \"url\": \"https://github.com/nicolas-grekas\",\n                    \"type\": \"github\"\n                },\n                {\n                    \"url\": \"https://tidelift.com/funding/github/packagist/symfony/symfony\",\n                    \"type\": \"tidelift\"\n                }\n            ],\n            \"install-path\": \"../symfony/translation\"\n        },\n        {\n            \"name\": \"symfony/translation-contracts\",\n            \"version\": \"v3.6.1\",\n            \"version_normalized\": \"3.6.1.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/symfony/translation-contracts.git\",\n                \"reference\": \"65a8bc82080447fae78373aa10f8d13b38338977\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/symfony/translation-contracts/zipball/65a8bc82080447fae78373aa10f8d13b38338977\",\n                \"reference\": \"65a8bc82080447fae78373aa10f8d13b38338977\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"php\": \">=8.1\"\n            },\n            \"time\": \"2025-07-15T13:41:35+00:00\",\n            \"type\": \"library\",\n            \"extra\": {\n                \"thanks\": {\n                    \"url\": \"https://github.com/symfony/contracts\",\n                    \"name\": \"symfony/contracts\"\n                },\n                \"branch-alias\": {\n                    \"dev-main\": \"3.6-dev\"\n                }\n            },\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"psr-4\": {\n                    \"Symfony\\\\Contracts\\\\Translation\\\\\": \"\"\n                },\n                \"exclude-from-classmap\": [\n                    \"/Test/\"\n                ]\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Nicolas Grekas\",\n                    \"email\": \"p@tchwork.com\"\n                },\n                {\n                    \"name\": \"Symfony Community\",\n                    \"homepage\": \"https://symfony.com/contributors\"\n                }\n            ],\n            \"description\": \"Generic abstractions related to translation\",\n            \"homepage\": \"https://symfony.com\",\n            \"keywords\": [\n                \"abstractions\",\n                \"contracts\",\n                \"decoupling\",\n                \"interfaces\",\n                \"interoperability\",\n                \"standards\"\n            ],\n            \"support\": {\n                \"source\": \"https://github.com/symfony/translation-contracts/tree/v3.6.1\"\n            },\n            \"funding\": [\n                {\n                    \"url\": \"https://symfony.com/sponsor\",\n                    \"type\": \"custom\"\n                },\n                {\n                    \"url\": \"https://github.com/fabpot\",\n                    \"type\": \"github\"\n                },\n                {\n                    \"url\": \"https://github.com/nicolas-grekas\",\n                    \"type\": \"github\"\n                },\n                {\n                    \"url\": \"https://tidelift.com/funding/github/packagist/symfony/symfony\",\n                    \"type\": \"tidelift\"\n                }\n            ],\n            \"install-path\": \"../symfony/translation-contracts\"\n        },\n        {\n            \"name\": \"vlucas/phpdotenv\",\n            \"version\": \"v5.6.0\",\n            \"version_normalized\": \"5.6.0.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/vlucas/phpdotenv.git\",\n                \"reference\": \"2cf9fb6054c2bb1d59d1f3817706ecdb9d2934c4\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/vlucas/phpdotenv/zipball/2cf9fb6054c2bb1d59d1f3817706ecdb9d2934c4\",\n                \"reference\": \"2cf9fb6054c2bb1d59d1f3817706ecdb9d2934c4\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"ext-pcre\": \"*\",\n                \"graham-campbell/result-type\": \"^1.1.2\",\n                \"php\": \"^7.2.5 || ^8.0\",\n                \"phpoption/phpoption\": \"^1.9.2\",\n                \"symfony/polyfill-ctype\": \"^1.24\",\n                \"symfony/polyfill-mbstring\": \"^1.24\",\n                \"symfony/polyfill-php80\": \"^1.24\"\n            },\n            \"require-dev\": {\n                \"bamarni/composer-bin-plugin\": \"^1.8.2\",\n                \"ext-filter\": \"*\",\n                \"phpunit/phpunit\": \"^8.5.34 || ^9.6.13 || ^10.4.2\"\n            },\n            \"suggest\": {\n                \"ext-filter\": \"Required to use the boolean validator.\"\n            },\n            \"time\": \"2023-11-12T22:43:29+00:00\",\n            \"type\": \"library\",\n            \"extra\": {\n                \"bamarni-bin\": {\n                    \"bin-links\": true,\n                    \"forward-command\": true\n                },\n                \"branch-alias\": {\n                    \"dev-master\": \"5.6-dev\"\n                }\n            },\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"psr-4\": {\n                    \"Dotenv\\\\\": \"src/\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"BSD-3-Clause\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Graham Campbell\",\n                    \"email\": \"hello@gjcampbell.co.uk\",\n                    \"homepage\": \"https://github.com/GrahamCampbell\"\n                },\n                {\n                    \"name\": \"Vance Lucas\",\n                    \"email\": \"vance@vancelucas.com\",\n                    \"homepage\": \"https://github.com/vlucas\"\n                }\n            ],\n            \"description\": \"Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.\",\n            \"keywords\": [\n                \"dotenv\",\n                \"env\",\n                \"environment\"\n            ],\n            \"support\": {\n                \"issues\": \"https://github.com/vlucas/phpdotenv/issues\",\n                \"source\": \"https://github.com/vlucas/phpdotenv/tree/v5.6.0\"\n            },\n            \"funding\": [\n                {\n                    \"url\": \"https://github.com/GrahamCampbell\",\n                    \"type\": \"github\"\n                },\n                {\n                    \"url\": \"https://tidelift.com/funding/github/packagist/vlucas/phpdotenv\",\n                    \"type\": \"tidelift\"\n                }\n            ],\n            \"install-path\": \"../vlucas/phpdotenv\"\n        },\n        {\n            \"name\": \"voku/portable-ascii\",\n            \"version\": \"1.6.1\",\n            \"version_normalized\": \"1.6.1.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/voku/portable-ascii.git\",\n                \"reference\": \"87337c91b9dfacee02452244ee14ab3c43bc485a\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/voku/portable-ascii/zipball/87337c91b9dfacee02452244ee14ab3c43bc485a\",\n                \"reference\": \"87337c91b9dfacee02452244ee14ab3c43bc485a\",\n                \"shasum\": \"\",\n                \"mirrors\": [\n                    {\n                        \"url\": \"https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%\",\n                        \"preferred\": true\n                    }\n                ]\n            },\n            \"require\": {\n                \"php\": \">=7.0.0\"\n            },\n            \"require-dev\": {\n                \"phpunit/phpunit\": \"~6.0 || ~7.0 || ~9.0\"\n            },\n            \"suggest\": {\n                \"ext-intl\": \"Use Intl for transliterator_transliterate() support\"\n            },\n            \"time\": \"2022-01-24T18:55:24+00:00\",\n            \"type\": \"library\",\n            \"installation-source\": \"dist\",\n            \"autoload\": {\n                \"psr-4\": {\n                    \"voku\\\\\": \"src/voku/\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Lars Moelleken\",\n                    \"homepage\": \"http://www.moelleken.org/\"\n                }\n            ],\n            \"description\": \"Portable ASCII library - performance optimized (ascii) string functions for php.\",\n            \"homepage\": \"https://github.com/voku/portable-ascii\",\n            \"keywords\": [\n                \"ascii\",\n                \"clean\",\n                \"php\"\n            ],\n            \"support\": {\n                \"issues\": \"https://github.com/voku/portable-ascii/issues\",\n                \"source\": \"https://github.com/voku/portable-ascii/tree/1.6.1\"\n            },\n            \"funding\": [\n                {\n                    \"url\": \"https://www.paypal.me/moelleken\",\n                    \"type\": \"custom\"\n                },\n                {\n                    \"url\": \"https://github.com/voku\",\n                    \"type\": \"github\"\n                },\n                {\n                    \"url\": \"https://opencollective.com/portable-ascii\",\n                    \"type\": \"open_collective\"\n                },\n                {\n                    \"url\": \"https://www.patreon.com/voku\",\n                    \"type\": \"patreon\"\n                },\n                {\n                    \"url\": \"https://tidelift.com/funding/github/packagist/voku/portable-ascii\",\n                    \"type\": \"tidelift\"\n                }\n            ],\n            \"install-path\": \"../voku/portable-ascii\"\n        }\n    ],\n    \"dev\": true,\n    \"dev-package-names\": []\n}\n"
  },
  {
    "path": "server/vendor/composer/installed.php",
    "content": "<?php return array(\n    'root' => array(\n        'name' => 'showdoc/showdoc',\n        'pretty_version' => 'v3.6.2',\n        'version' => '3.6.2.0',\n        'reference' => null,\n        'type' => 'project',\n        'install_path' => __DIR__ . '/../../../',\n        'aliases' => array(),\n        'dev' => true,\n    ),\n    'versions' => array(\n        'async-aws/core' => array(\n            'pretty_version' => '1.27.1',\n            'version' => '1.27.1.0',\n            'reference' => '5b8e35c8df94990161e2c9750c9ba1683d0b48b8',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../async-aws/core',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'async-aws/s3' => array(\n            'pretty_version' => '1.14.0',\n            'version' => '1.14.0.0',\n            'reference' => '27ce65242cde50ba09323d54708b45cf64a51aa5',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../async-aws/s3',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'carbonphp/carbon-doctrine-types' => array(\n            'pretty_version' => '3.2.0',\n            'version' => '3.2.0.0',\n            'reference' => '18ba5ddfec8976260ead6e866180bd5d2f71aa1d',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../carbonphp/carbon-doctrine-types',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'doctrine/inflector' => array(\n            'pretty_version' => '2.0.10',\n            'version' => '2.0.10.0',\n            'reference' => '5817d0659c5b50c9b950feb9af7b9668e2c436bc',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../doctrine/inflector',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'fig/http-message-util' => array(\n            'pretty_version' => '1.1.5',\n            'version' => '1.1.5.0',\n            'reference' => '9d94dc0154230ac39e5bf89398b324a86f63f765',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../fig/http-message-util',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'graham-campbell/result-type' => array(\n            'pretty_version' => 'v1.1.2',\n            'version' => '1.1.2.0',\n            'reference' => 'fbd48bce38f73f8a4ec8583362e732e4095e5862',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../graham-campbell/result-type',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'greenlion/php-sql-parser' => array(\n            'pretty_version' => 'v4.6.0',\n            'version' => '4.6.0.0',\n            'reference' => 'f0e4645eb1612f0a295e3d35bda4c7740ae8c366',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../greenlion/php-sql-parser',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'gregwar/captcha' => array(\n            'pretty_version' => 'v1.2.1',\n            'version' => '1.2.1.0',\n            'reference' => '229d3cdfe33d6f1349e0aec94a26e9205a6db08e',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../gregwar/captcha',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'guzzlehttp/command' => array(\n            'pretty_version' => '1.0.0',\n            'version' => '1.0.0.0',\n            'reference' => '2aaa2521a8f8269d6f5dfc13fe2af12c76921034',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../guzzlehttp/command',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'guzzlehttp/guzzle' => array(\n            'pretty_version' => '6.5.8',\n            'version' => '6.5.8.0',\n            'reference' => 'a52f0440530b54fa079ce76e8c5d196a42cad981',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../guzzlehttp/guzzle',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'guzzlehttp/guzzle-services' => array(\n            'pretty_version' => '1.1.3',\n            'version' => '1.1.3.0',\n            'reference' => '9e3abf20161cbf662d616cbb995f2811771759f7',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../guzzlehttp/guzzle-services',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'guzzlehttp/promises' => array(\n            'pretty_version' => '1.5.3',\n            'version' => '1.5.3.0',\n            'reference' => '67ab6e18aaa14d753cc148911d273f6e6cb6721e',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../guzzlehttp/promises',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'guzzlehttp/psr7' => array(\n            'pretty_version' => '1.9.1',\n            'version' => '1.9.1.0',\n            'reference' => 'e4490cabc77465aaee90b20cfc9a770f8c04be6b',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../guzzlehttp/psr7',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'illuminate/bus' => array(\n            'pretty_version' => 'v8.83.27',\n            'version' => '8.83.27.0',\n            'reference' => 'd2a8ae4bfd881086e55455e470776358eab27eae',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../illuminate/bus',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'illuminate/collections' => array(\n            'pretty_version' => 'v8.83.27',\n            'version' => '8.83.27.0',\n            'reference' => '705a4e1ef93cd492c45b9b3e7911cccc990a07f4',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../illuminate/collections',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'illuminate/container' => array(\n            'pretty_version' => 'v8.83.27',\n            'version' => '8.83.27.0',\n            'reference' => '14062628d05f75047c5a1360b9350028427d568e',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../illuminate/container',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'illuminate/contracts' => array(\n            'pretty_version' => 'v8.83.27',\n            'version' => '8.83.27.0',\n            'reference' => '5e0fd287a1b22a6b346a9f7cd484d8cf0234585d',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../illuminate/contracts',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'illuminate/database' => array(\n            'pretty_version' => 'v8.83.27',\n            'version' => '8.83.27.0',\n            'reference' => '1a5b0e4e6913415464fa2aab554a38b9e6fa44b1',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../illuminate/database',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'illuminate/events' => array(\n            'pretty_version' => 'v8.83.27',\n            'version' => '8.83.27.0',\n            'reference' => 'b7f06cafb6c09581617f2ca05d69e9b159e5a35d',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../illuminate/events',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'illuminate/macroable' => array(\n            'pretty_version' => 'v8.83.27',\n            'version' => '8.83.27.0',\n            'reference' => 'aed81891a6e046fdee72edd497f822190f61c162',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../illuminate/macroable',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'illuminate/pipeline' => array(\n            'pretty_version' => 'v8.83.27',\n            'version' => '8.83.27.0',\n            'reference' => '23aeff5b26ae4aee3f370835c76bd0f4e93f71d2',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../illuminate/pipeline',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'illuminate/support' => array(\n            'pretty_version' => 'v8.83.27',\n            'version' => '8.83.27.0',\n            'reference' => '1c79242468d3bbd9a0f7477df34f9647dde2a09b',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../illuminate/support',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'jasig/phpcas' => array(\n            'pretty_version' => '1.6.1',\n            'version' => '1.6.1.0',\n            'reference' => 'c129708154852656aabb13d8606cd5b12dbbabac',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../jasig/phpcas',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'laravel/serializable-closure' => array(\n            'pretty_version' => 'v1.3.7',\n            'version' => '1.3.7.0',\n            'reference' => '4f48ade902b94323ca3be7646db16209ec76be3d',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../laravel/serializable-closure',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'league/oauth2-client' => array(\n            'pretty_version' => '2.9.0',\n            'version' => '2.9.0.0',\n            'reference' => '26e8c5da4f3d78cede7021e09b1330a0fc093d5e',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../league/oauth2-client',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'nesbot/carbon' => array(\n            'pretty_version' => '2.73.0',\n            'version' => '2.73.0.0',\n            'reference' => '9228ce90e1035ff2f0db84b40ec2e023ed802075',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../nesbot/carbon',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'nikic/fast-route' => array(\n            'pretty_version' => 'v1.3.0',\n            'version' => '1.3.0.0',\n            'reference' => '181d480e08d9476e61381e04a71b34dc0432e812',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../nikic/fast-route',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'php-di/invoker' => array(\n            'pretty_version' => '2.3.5',\n            'version' => '2.3.5.0',\n            'reference' => '93d381d0ec42074f43530506849fdc2d3a86a809',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../php-di/invoker',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'php-di/php-di' => array(\n            'pretty_version' => '6.4.0',\n            'version' => '6.4.0.0',\n            'reference' => 'ae0f1b3b03d8b29dff81747063cbfd6276246cc4',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../php-di/php-di',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'php-di/phpdoc-reader' => array(\n            'pretty_version' => '2.2.1',\n            'version' => '2.2.1.0',\n            'reference' => '66daff34cbd2627740ffec9469ffbac9f8c8185c',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../php-di/phpdoc-reader',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'php-http/async-client-implementation' => array(\n            'dev_requirement' => false,\n            'provided' => array(\n                0 => '*',\n            ),\n        ),\n        'php-http/client-implementation' => array(\n            'dev_requirement' => false,\n            'provided' => array(\n                0 => '*',\n            ),\n        ),\n        'phpoption/phpoption' => array(\n            'pretty_version' => '1.9.3',\n            'version' => '1.9.3.0',\n            'reference' => 'e3fac8b24f56113f7cb96af14958c0dd16330f54',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../phpoption/phpoption',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'psr/cache' => array(\n            'pretty_version' => '3.0.0',\n            'version' => '3.0.0.0',\n            'reference' => 'aa5030cfa5405eccfdcb1083ce040c2cb8d253bf',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../psr/cache',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'psr/clock' => array(\n            'pretty_version' => '1.0.0',\n            'version' => '1.0.0.0',\n            'reference' => 'e41a24703d4560fd0acb709162f73b8adfc3aa0d',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../psr/clock',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'psr/clock-implementation' => array(\n            'dev_requirement' => false,\n            'provided' => array(\n                0 => '1.0',\n            ),\n        ),\n        'psr/container' => array(\n            'pretty_version' => '1.1.2',\n            'version' => '1.1.2.0',\n            'reference' => '513e0666f7216c7459170d56df27dfcefe1689ea',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../psr/container',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'psr/container-implementation' => array(\n            'dev_requirement' => false,\n            'provided' => array(\n                0 => '1.0',\n                1 => '^1.0',\n            ),\n        ),\n        'psr/http-client-implementation' => array(\n            'dev_requirement' => false,\n            'provided' => array(\n                0 => '1.0',\n            ),\n        ),\n        'psr/http-factory' => array(\n            'pretty_version' => '1.0.2',\n            'version' => '1.0.2.0',\n            'reference' => 'e616d01114759c4c489f93b099585439f795fe35',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../psr/http-factory',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'psr/http-factory-implementation' => array(\n            'dev_requirement' => false,\n            'provided' => array(\n                0 => '1.0',\n            ),\n        ),\n        'psr/http-message' => array(\n            'pretty_version' => '1.1',\n            'version' => '1.1.0.0',\n            'reference' => 'cb6ce4845ce34a8ad9e68117c10ee90a29919eba',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../psr/http-message',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'psr/http-message-implementation' => array(\n            'dev_requirement' => false,\n            'provided' => array(\n                0 => '1.0',\n            ),\n        ),\n        'psr/http-server-handler' => array(\n            'pretty_version' => '1.0.2',\n            'version' => '1.0.2.0',\n            'reference' => '84c4fb66179be4caaf8e97bd239203245302e7d4',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../psr/http-server-handler',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'psr/http-server-middleware' => array(\n            'pretty_version' => '1.0.2',\n            'version' => '1.0.2.0',\n            'reference' => 'c1481f747daaa6a0782775cd6a8c26a1bf4a3829',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../psr/http-server-middleware',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'psr/log' => array(\n            'pretty_version' => '2.0.0',\n            'version' => '2.0.0.0',\n            'reference' => 'ef29f6d262798707a9edd554e2b82517ef3a9376',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../psr/log',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'psr/log-implementation' => array(\n            'dev_requirement' => false,\n            'provided' => array(\n                0 => '1.0|2.0',\n            ),\n        ),\n        'psr/simple-cache' => array(\n            'pretty_version' => '1.0.1',\n            'version' => '1.0.1.0',\n            'reference' => '408d5eafb83c57f6365a3ca330ff23aa4a5fa39b',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../psr/simple-cache',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'qcloud/cos-sdk-v5' => array(\n            'pretty_version' => 'v1.3.5',\n            'version' => '1.3.5.0',\n            'reference' => 'e67ad8143695192ee206bcbcafc78c08da92c621',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../qcloud/cos-sdk-v5',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'ralouphie/getallheaders' => array(\n            'pretty_version' => '3.0.3',\n            'version' => '3.0.3.0',\n            'reference' => '120b605dfeb996808c31b6477290a714d356e822',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../ralouphie/getallheaders',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'showdoc/showdoc' => array(\n            'pretty_version' => 'v3.6.2',\n            'version' => '3.6.2.0',\n            'reference' => null,\n            'type' => 'project',\n            'install_path' => __DIR__ . '/../../../',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'slim/psr7' => array(\n            'pretty_version' => '1.6.2',\n            'version' => '1.6.2.0',\n            'reference' => '5c64088c146673473f5667cbeb501edf5508dfaf',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../slim/psr7',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'slim/slim' => array(\n            'pretty_version' => '4.13.0',\n            'version' => '4.13.0.0',\n            'reference' => '038fd5713d5a41636fdff0e8dcceedecdd17fc17',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../slim/slim',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'symfony/console' => array(\n            'pretty_version' => 'v5.4.47',\n            'version' => '5.4.47.0',\n            'reference' => 'c4ba980ca61a9eb18ee6bcc73f28e475852bb1ed',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../symfony/console',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'symfony/deprecation-contracts' => array(\n            'pretty_version' => 'v3.5.1',\n            'version' => '3.5.1.0',\n            'reference' => '74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../symfony/deprecation-contracts',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'symfony/finder' => array(\n            'pretty_version' => 'v6.4.27',\n            'version' => '6.4.27.0',\n            'reference' => 'a1b6aa435d2fba50793b994a839c32b6064f063b',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../symfony/finder',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'symfony/http-client' => array(\n            'pretty_version' => 'v6.4.28',\n            'version' => '6.4.28.0',\n            'reference' => 'c9e69c185c4a845f9d46958cdb0dc7aa847f3981',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../symfony/http-client',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'symfony/http-client-contracts' => array(\n            'pretty_version' => 'v3.5.2',\n            'version' => '3.5.2.0',\n            'reference' => 'ee8d807ab20fcb51267fdace50fbe3494c31e645',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../symfony/http-client-contracts',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'symfony/http-client-implementation' => array(\n            'dev_requirement' => false,\n            'provided' => array(\n                0 => '3.0',\n            ),\n        ),\n        'symfony/polyfill-ctype' => array(\n            'pretty_version' => 'v1.32.0',\n            'version' => '1.32.0.0',\n            'reference' => 'a3cc8b044a6ea513310cbd48ef7333b384945638',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../symfony/polyfill-ctype',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'symfony/polyfill-intl-grapheme' => array(\n            'pretty_version' => 'v1.32.0',\n            'version' => '1.32.0.0',\n            'reference' => 'b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../symfony/polyfill-intl-grapheme',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'symfony/polyfill-intl-idn' => array(\n            'pretty_version' => 'v1.32.0',\n            'version' => '1.32.0.0',\n            'reference' => '9614ac4d8061dc257ecc64cba1b140873dce8ad3',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../symfony/polyfill-intl-idn',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'symfony/polyfill-intl-normalizer' => array(\n            'pretty_version' => 'v1.32.0',\n            'version' => '1.32.0.0',\n            'reference' => '3833d7255cc303546435cb650316bff708a1c75c',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../symfony/polyfill-intl-normalizer',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'symfony/polyfill-mbstring' => array(\n            'pretty_version' => 'v1.32.0',\n            'version' => '1.32.0.0',\n            'reference' => '6d857f4d76bd4b343eac26d6b539585d2bc56493',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../symfony/polyfill-mbstring',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'symfony/polyfill-php73' => array(\n            'pretty_version' => 'v1.32.0',\n            'version' => '1.32.0.0',\n            'reference' => '0f68c03565dcaaf25a890667542e8bd75fe7e5bb',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../symfony/polyfill-php73',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'symfony/polyfill-php80' => array(\n            'pretty_version' => 'v1.32.0',\n            'version' => '1.32.0.0',\n            'reference' => '0cc9dd0f17f61d8131e7df6b84bd344899fe2608',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../symfony/polyfill-php80',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'symfony/polyfill-php83' => array(\n            'pretty_version' => 'v1.32.0',\n            'version' => '1.32.0.0',\n            'reference' => '2fb86d65e2d424369ad2905e83b236a8805ba491',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../symfony/polyfill-php83',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'symfony/service-contracts' => array(\n            'pretty_version' => 'v3.6.1',\n            'version' => '3.6.1.0',\n            'reference' => '45112560a3ba2d715666a509a0bc9521d10b6c43',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../symfony/service-contracts',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'symfony/string' => array(\n            'pretty_version' => 'v6.4.26',\n            'version' => '6.4.26.0',\n            'reference' => '5621f039a71a11c87c106c1c598bdcd04a19aeea',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../symfony/string',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'symfony/translation' => array(\n            'pretty_version' => 'v6.4.30',\n            'version' => '6.4.30.0',\n            'reference' => 'd1fdeefd0707d15eb150c04e8837bf0b15ebea39',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../symfony/translation',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'symfony/translation-contracts' => array(\n            'pretty_version' => 'v3.6.1',\n            'version' => '3.6.1.0',\n            'reference' => '65a8bc82080447fae78373aa10f8d13b38338977',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../symfony/translation-contracts',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'symfony/translation-implementation' => array(\n            'dev_requirement' => false,\n            'provided' => array(\n                0 => '2.3|3.0',\n            ),\n        ),\n        'vlucas/phpdotenv' => array(\n            'pretty_version' => 'v5.6.0',\n            'version' => '5.6.0.0',\n            'reference' => '2cf9fb6054c2bb1d59d1f3817706ecdb9d2934c4',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../vlucas/phpdotenv',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n        'voku/portable-ascii' => array(\n            'pretty_version' => '1.6.1',\n            'version' => '1.6.1.0',\n            'reference' => '87337c91b9dfacee02452244ee14ab3c43bc485a',\n            'type' => 'library',\n            'install_path' => __DIR__ . '/../voku/portable-ascii',\n            'aliases' => array(),\n            'dev_requirement' => false,\n        ),\n    ),\n);\n"
  },
  {
    "path": "server/vendor/composer/platform_check.php",
    "content": "<?php\n\n// platform_check.php @generated by Composer\n\n$issues = array();\n\nif (!(PHP_VERSION_ID >= 80100)) {\n    $issues[] = 'Your Composer dependencies require a PHP version \">= 8.1.0\". You are running ' . PHP_VERSION . '.';\n}\n\nif ($issues) {\n    if (!headers_sent()) {\n        header('HTTP/1.1 500 Internal Server Error');\n    }\n    if (!ini_get('display_errors')) {\n        if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {\n            fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);\n        } elseif (!headers_sent()) {\n            echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;\n        }\n    }\n    trigger_error(\n        'Composer detected issues in your platform: ' . implode(' ', $issues),\n        E_USER_ERROR\n    );\n}\n"
  },
  {
    "path": "server/vendor/doctrine/inflector/LICENSE",
    "content": "Copyright (c) 2006-2015 Doctrine Project\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies\nof the Software, and to permit persons to whom the Software is furnished to do\nso, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "server/vendor/doctrine/inflector/README.md",
    "content": "# Doctrine Inflector\n\nDoctrine Inflector is a small library that can perform string manipulations\nwith regard to uppercase/lowercase and singular/plural forms of words.\n\n[![Build Status](https://github.com/doctrine/inflector/workflows/Continuous%20Integration/badge.svg)](https://github.com/doctrine/inflector/actions?query=workflow%3A%22Continuous+Integration%22+branch%3A4.0.x)\n[![Code Coverage](https://codecov.io/gh/doctrine/inflector/branch/2.0.x/graph/badge.svg)](https://codecov.io/gh/doctrine/inflector/branch/2.0.x)\n"
  },
  {
    "path": "server/vendor/doctrine/inflector/composer.json",
    "content": "{\n    \"name\": \"doctrine/inflector\",\n    \"type\": \"library\",\n    \"description\": \"PHP Doctrine Inflector is a small library that can perform string manipulations with regard to upper/lowercase and singular/plural forms of words.\",\n    \"keywords\": [\"php\", \"strings\", \"words\", \"manipulation\", \"inflector\", \"inflection\", \"uppercase\", \"lowercase\", \"singular\", \"plural\"],\n    \"homepage\": \"https://www.doctrine-project.org/projects/inflector.html\",\n    \"license\": \"MIT\",\n    \"authors\": [\n        {\"name\": \"Guilherme Blanco\", \"email\": \"guilhermeblanco@gmail.com\"},\n        {\"name\": \"Roman Borschel\", \"email\": \"roman@code-factory.org\"},\n        {\"name\": \"Benjamin Eberlei\", \"email\": \"kontakt@beberlei.de\"},\n        {\"name\": \"Jonathan Wage\", \"email\": \"jonwage@gmail.com\"},\n        {\"name\": \"Johannes Schmitt\", \"email\": \"schmittjoh@gmail.com\"}\n    ],\n    \"require\": {\n        \"php\": \"^7.2 || ^8.0\"\n    },\n    \"require-dev\": {\n        \"doctrine/coding-standard\": \"^11.0\",\n        \"phpstan/phpstan\": \"^1.8\",\n        \"phpstan/phpstan-phpunit\": \"^1.1\",\n        \"phpstan/phpstan-strict-rules\": \"^1.3\",\n        \"phpunit/phpunit\": \"^8.5 || ^9.5\",\n        \"vimeo/psalm\": \"^4.25 || ^5.4\"\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"Doctrine\\\\Inflector\\\\\": \"lib/Doctrine/Inflector\"\n        }\n    },\n    \"autoload-dev\": {\n        \"psr-4\": {\n            \"Doctrine\\\\Tests\\\\Inflector\\\\\": \"tests/Doctrine/Tests/Inflector\"\n        }\n    },\n    \"config\": {\n        \"allow-plugins\": {\n            \"dealerdirect/phpcodesniffer-composer-installer\": true\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/doctrine/inflector/docs/en/index.rst",
    "content": "Introduction\n============\n\nThe Doctrine Inflector has methods for inflecting text. The features include pluralization,\nsingularization, converting between camelCase and under_score and capitalizing\nwords.\n\nInstallation\n============\n\nYou can install the Inflector with composer:\n\n.. code-block:: console\n\n    $ composer require doctrine/inflector\n\nUsage\n=====\n\nUsing the inflector is easy, you can create a new ``Doctrine\\Inflector\\Inflector`` instance by using\nthe ``Doctrine\\Inflector\\InflectorFactory`` class:\n\n.. code-block:: php\n\n    use Doctrine\\Inflector\\InflectorFactory;\n\n    $inflector = InflectorFactory::create()->build();\n\nBy default it will create an English inflector. If you want to use another language, just pass the language\nyou want to create an inflector for to the ``createForLanguage()`` method:\n\n.. code-block:: php\n\n    use Doctrine\\Inflector\\InflectorFactory;\n    use Doctrine\\Inflector\\Language;\n\n    $inflector = InflectorFactory::createForLanguage(Language::SPANISH)->build();\n\nThe supported languages are as follows:\n\n- ``Language::ENGLISH``\n- ``Language::FRENCH``\n- ``Language::NORWEGIAN_BOKMAL``\n- ``Language::PORTUGUESE``\n- ``Language::SPANISH``\n- ``Language::TURKISH``\n\nIf you want to manually construct the inflector instead of using a factory, you can do so like this:\n\n.. code-block:: php\n\n    use Doctrine\\Inflector\\CachedWordInflector;\n    use Doctrine\\Inflector\\RulesetInflector;\n    use Doctrine\\Inflector\\Rules\\English;\n\n    $inflector = new Inflector(\n        new CachedWordInflector(new RulesetInflector(\n            English\\Rules::getSingularRuleset()\n        )),\n        new CachedWordInflector(new RulesetInflector(\n            English\\Rules::getPluralRuleset()\n        ))\n    );\n\nAdding Languages\n----------------\n\nIf you are interested in adding support for your language, take a look at the other languages defined in the\n``Doctrine\\Inflector\\Rules`` namespace and the tests located in ``Doctrine\\Tests\\Inflector\\Rules``. You can copy\none of the languages and update the rules for your language.\n\nOnce you have done this, send a pull request to the ``doctrine/inflector`` repository with the additions.\n\nCustom Setup\n============\n\nIf you want to setup custom singular and plural rules, you can configure these in the factory:\n\n.. code-block:: php\n\n    use Doctrine\\Inflector\\InflectorFactory;\n    use Doctrine\\Inflector\\Rules\\Pattern;\n    use Doctrine\\Inflector\\Rules\\Patterns;\n    use Doctrine\\Inflector\\Rules\\Ruleset;\n    use Doctrine\\Inflector\\Rules\\Substitution;\n    use Doctrine\\Inflector\\Rules\\Substitutions;\n    use Doctrine\\Inflector\\Rules\\Transformation;\n    use Doctrine\\Inflector\\Rules\\Transformations;\n    use Doctrine\\Inflector\\Rules\\Word;\n\n    $inflector = InflectorFactory::create()\n        ->withSingularRules(\n            new Ruleset(\n                new Transformations(\n                    new Transformation(new Pattern('/^(bil)er$/i'), '\\1'),\n                    new Transformation(new Pattern('/^(inflec|contribu)tors$/i'), '\\1ta')\n                ),\n                new Patterns(new Pattern('singulars')),\n                new Substitutions(new Substitution(new Word('spins'), new Word('spinor')))\n            )\n        )\n        ->withPluralRules(\n            new Ruleset(\n                new Transformations(\n                    new Transformation(new Pattern('^(bil)er$'), '\\1'),\n                    new Transformation(new Pattern('^(inflec|contribu)tors$'), '\\1ta')\n                ),\n                new Patterns(new Pattern('noflect'), new Pattern('abtuse')),\n                new Substitutions(\n                    new Substitution(new Word('amaze'), new Word('amazable')),\n                    new Substitution(new Word('phone'), new Word('phonezes'))\n                )\n            )\n        )\n        ->build();\n\nNo operation inflector\n----------------------\n\nThe ``Doctrine\\Inflector\\NoopWordInflector`` may be used to configure an inflector that doesn't perform any operation for\npluralization and/or singularization. If will simply return the input as output.\n\nThis is an implementation of the `Null Object design pattern <https://sourcemaking.com/design_patterns/null_object>`_.\n\n.. code-block:: php\n\n    use Doctrine\\Inflector\\Inflector;\n    use Doctrine\\Inflector\\NoopWordInflector;\n\n    $inflector = new Inflector(new NoopWordInflector(), new NoopWordInflector());\n\nTableize\n========\n\nConverts ``ModelName`` to ``model_name``:\n\n.. code-block:: php\n\n    echo $inflector->tableize('ModelName'); // model_name\n\nClassify\n========\n\nConverts ``model_name`` to ``ModelName``:\n\n.. code-block:: php\n\n    echo $inflector->classify('model_name'); // ModelName\n\nCamelize\n========\n\nThis method uses `Classify`_ and then converts the first character to lowercase:\n\n.. code-block:: php\n\n    echo $inflector->camelize('model_name'); // modelName\n\nCapitalize\n==========\n\nTakes a string and capitalizes all of the words, like PHP's built-in\n``ucwords`` function. This extends that behavior, however, by allowing the\nword delimiters to be configured, rather than only separating on\nwhitespace.\n\nHere is an example:\n\n.. code-block:: php\n\n    $string = 'top-o-the-morning to all_of_you!';\n\n    echo $inflector->capitalize($string); // Top-O-The-Morning To All_of_you!\n\n    echo $inflector->capitalize($string, '-_ '); // Top-O-The-Morning To All_Of_You!\n\nPluralize\n=========\n\nReturns a word in plural form.\n\n.. code-block:: php\n\n    echo $inflector->pluralize('browser'); // browsers\n\nSingularize\n===========\n\nReturns a word in singular form.\n\n.. code-block:: php\n\n    echo $inflector->singularize('browsers'); // browser\n\nUrlize\n======\n\nGenerate a URL friendly string from a string of text:\n\n.. code-block:: php\n\n    echo $inflector->urlize('My first blog post'); // my-first-blog-post\n\nUnaccent\n========\n\nYou can unaccent a string of text using the ``unaccent()`` method:\n\n.. code-block:: php\n\n    echo $inflector->unaccent('año'); // ano\n\nLegacy API\n==========\n\nThe API present in Inflector 1.x is still available, but will be deprecated in a future release and dropped for 3.0.\nSupport for languages other than English is available in the 2.0 API only.\n\nAcknowledgements\n================\n\nThe language rules in this library have been adapted from several different sources, including but not limited to:\n\n- `Ruby On Rails Inflector <http://api.rubyonrails.org/classes/ActiveSupport/Inflector.html>`_\n- `ICanBoogie Inflector <https://github.com/ICanBoogie/Inflector>`_\n- `CakePHP Inflector <https://book.cakephp.org/3.0/en/core-libraries/inflector.html>`_\n"
  },
  {
    "path": "server/vendor/doctrine/inflector/lib/Doctrine/Inflector/CachedWordInflector.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Doctrine\\Inflector;\n\nclass CachedWordInflector implements WordInflector\n{\n    /** @var WordInflector */\n    private $wordInflector;\n\n    /** @var string[] */\n    private $cache = [];\n\n    public function __construct(WordInflector $wordInflector)\n    {\n        $this->wordInflector = $wordInflector;\n    }\n\n    public function inflect(string $word): string\n    {\n        return $this->cache[$word] ?? $this->cache[$word] = $this->wordInflector->inflect($word);\n    }\n}\n"
  },
  {
    "path": "server/vendor/doctrine/inflector/lib/Doctrine/Inflector/GenericLanguageInflectorFactory.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Doctrine\\Inflector;\n\nuse Doctrine\\Inflector\\Rules\\Ruleset;\n\nuse function array_unshift;\n\nabstract class GenericLanguageInflectorFactory implements LanguageInflectorFactory\n{\n    /** @var Ruleset[] */\n    private $singularRulesets = [];\n\n    /** @var Ruleset[] */\n    private $pluralRulesets = [];\n\n    final public function __construct()\n    {\n        $this->singularRulesets[] = $this->getSingularRuleset();\n        $this->pluralRulesets[]   = $this->getPluralRuleset();\n    }\n\n    final public function build(): Inflector\n    {\n        return new Inflector(\n            new CachedWordInflector(new RulesetInflector(\n                ...$this->singularRulesets\n            )),\n            new CachedWordInflector(new RulesetInflector(\n                ...$this->pluralRulesets\n            ))\n        );\n    }\n\n    final public function withSingularRules(?Ruleset $singularRules, bool $reset = false): LanguageInflectorFactory\n    {\n        if ($reset) {\n            $this->singularRulesets = [];\n        }\n\n        if ($singularRules instanceof Ruleset) {\n            array_unshift($this->singularRulesets, $singularRules);\n        }\n\n        return $this;\n    }\n\n    final public function withPluralRules(?Ruleset $pluralRules, bool $reset = false): LanguageInflectorFactory\n    {\n        if ($reset) {\n            $this->pluralRulesets = [];\n        }\n\n        if ($pluralRules instanceof Ruleset) {\n            array_unshift($this->pluralRulesets, $pluralRules);\n        }\n\n        return $this;\n    }\n\n    abstract protected function getSingularRuleset(): Ruleset;\n\n    abstract protected function getPluralRuleset(): Ruleset;\n}\n"
  },
  {
    "path": "server/vendor/doctrine/inflector/lib/Doctrine/Inflector/Inflector.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Doctrine\\Inflector;\n\nuse RuntimeException;\n\nuse function chr;\nuse function function_exists;\nuse function lcfirst;\nuse function mb_strtolower;\nuse function ord;\nuse function preg_match;\nuse function preg_replace;\nuse function sprintf;\nuse function str_replace;\nuse function strlen;\nuse function strtolower;\nuse function strtr;\nuse function trim;\nuse function ucwords;\n\nclass Inflector\n{\n    private const ACCENTED_CHARACTERS = [\n        'À' => 'A',\n        'Á' => 'A',\n        'Â' => 'A',\n        'Ã' => 'A',\n        'Ä' => 'Ae',\n        'Æ' => 'Ae',\n        'Å' => 'Aa',\n        'æ' => 'a',\n        'Ç' => 'C',\n        'È' => 'E',\n        'É' => 'E',\n        'Ê' => 'E',\n        'Ë' => 'E',\n        'Ì' => 'I',\n        'Í' => 'I',\n        'Î' => 'I',\n        'Ï' => 'I',\n        'Ñ' => 'N',\n        'Ò' => 'O',\n        'Ó' => 'O',\n        'Ô' => 'O',\n        'Õ' => 'O',\n        'Ö' => 'Oe',\n        'Ù' => 'U',\n        'Ú' => 'U',\n        'Û' => 'U',\n        'Ü' => 'Ue',\n        'Ý' => 'Y',\n        'ß' => 'ss',\n        'à' => 'a',\n        'á' => 'a',\n        'â' => 'a',\n        'ã' => 'a',\n        'ä' => 'ae',\n        'å' => 'aa',\n        'ç' => 'c',\n        'è' => 'e',\n        'é' => 'e',\n        'ê' => 'e',\n        'ë' => 'e',\n        'ì' => 'i',\n        'í' => 'i',\n        'î' => 'i',\n        'ï' => 'i',\n        'ñ' => 'n',\n        'ò' => 'o',\n        'ó' => 'o',\n        'ô' => 'o',\n        'õ' => 'o',\n        'ö' => 'oe',\n        'ù' => 'u',\n        'ú' => 'u',\n        'û' => 'u',\n        'ü' => 'ue',\n        'ý' => 'y',\n        'ÿ' => 'y',\n        'Ā' => 'A',\n        'ā' => 'a',\n        'Ă' => 'A',\n        'ă' => 'a',\n        'Ą' => 'A',\n        'ą' => 'a',\n        'Ć' => 'C',\n        'ć' => 'c',\n        'Ĉ' => 'C',\n        'ĉ' => 'c',\n        'Ċ' => 'C',\n        'ċ' => 'c',\n        'Č' => 'C',\n        'č' => 'c',\n        'Ď' => 'D',\n        'ď' => 'd',\n        'Đ' => 'D',\n        'đ' => 'd',\n        'Ē' => 'E',\n        'ē' => 'e',\n        'Ĕ' => 'E',\n        'ĕ' => 'e',\n        'Ė' => 'E',\n        'ė' => 'e',\n        'Ę' => 'E',\n        'ę' => 'e',\n        'Ě' => 'E',\n        'ě' => 'e',\n        'Ĝ' => 'G',\n        'ĝ' => 'g',\n        'Ğ' => 'G',\n        'ğ' => 'g',\n        'Ġ' => 'G',\n        'ġ' => 'g',\n        'Ģ' => 'G',\n        'ģ' => 'g',\n        'Ĥ' => 'H',\n        'ĥ' => 'h',\n        'Ħ' => 'H',\n        'ħ' => 'h',\n        'Ĩ' => 'I',\n        'ĩ' => 'i',\n        'Ī' => 'I',\n        'ī' => 'i',\n        'Ĭ' => 'I',\n        'ĭ' => 'i',\n        'Į' => 'I',\n        'į' => 'i',\n        'İ' => 'I',\n        'ı' => 'i',\n        'Ĳ' => 'IJ',\n        'ĳ' => 'ij',\n        'Ĵ' => 'J',\n        'ĵ' => 'j',\n        'Ķ' => 'K',\n        'ķ' => 'k',\n        'ĸ' => 'k',\n        'Ĺ' => 'L',\n        'ĺ' => 'l',\n        'Ļ' => 'L',\n        'ļ' => 'l',\n        'Ľ' => 'L',\n        'ľ' => 'l',\n        'Ŀ' => 'L',\n        'ŀ' => 'l',\n        'Ł' => 'L',\n        'ł' => 'l',\n        'Ń' => 'N',\n        'ń' => 'n',\n        'Ņ' => 'N',\n        'ņ' => 'n',\n        'Ň' => 'N',\n        'ň' => 'n',\n        'ŉ' => 'N',\n        'Ŋ' => 'n',\n        'ŋ' => 'N',\n        'Ō' => 'O',\n        'ō' => 'o',\n        'Ŏ' => 'O',\n        'ŏ' => 'o',\n        'Ő' => 'O',\n        'ő' => 'o',\n        'Œ' => 'OE',\n        'œ' => 'oe',\n        'Ø' => 'O',\n        'ø' => 'o',\n        'Ŕ' => 'R',\n        'ŕ' => 'r',\n        'Ŗ' => 'R',\n        'ŗ' => 'r',\n        'Ř' => 'R',\n        'ř' => 'r',\n        'Ś' => 'S',\n        'ś' => 's',\n        'Ŝ' => 'S',\n        'ŝ' => 's',\n        'Ş' => 'S',\n        'ş' => 's',\n        'Š' => 'S',\n        'š' => 's',\n        'Ţ' => 'T',\n        'ţ' => 't',\n        'Ť' => 'T',\n        'ť' => 't',\n        'Ŧ' => 'T',\n        'ŧ' => 't',\n        'Ũ' => 'U',\n        'ũ' => 'u',\n        'Ū' => 'U',\n        'ū' => 'u',\n        'Ŭ' => 'U',\n        'ŭ' => 'u',\n        'Ů' => 'U',\n        'ů' => 'u',\n        'Ű' => 'U',\n        'ű' => 'u',\n        'Ų' => 'U',\n        'ų' => 'u',\n        'Ŵ' => 'W',\n        'ŵ' => 'w',\n        'Ŷ' => 'Y',\n        'ŷ' => 'y',\n        'Ÿ' => 'Y',\n        'Ź' => 'Z',\n        'ź' => 'z',\n        'Ż' => 'Z',\n        'ż' => 'z',\n        'Ž' => 'Z',\n        'ž' => 'z',\n        'ſ' => 's',\n        '€' => 'E',\n        '£' => '',\n    ];\n\n    /** @var WordInflector */\n    private $singularizer;\n\n    /** @var WordInflector */\n    private $pluralizer;\n\n    public function __construct(WordInflector $singularizer, WordInflector $pluralizer)\n    {\n        $this->singularizer = $singularizer;\n        $this->pluralizer   = $pluralizer;\n    }\n\n    /**\n     * Converts a word into the format for a Doctrine table name. Converts 'ModelName' to 'model_name'.\n     */\n    public function tableize(string $word): string\n    {\n        $tableized = preg_replace('~(?<=\\\\w)([A-Z])~u', '_$1', $word);\n\n        if ($tableized === null) {\n            throw new RuntimeException(sprintf(\n                'preg_replace returned null for value \"%s\"',\n                $word\n            ));\n        }\n\n        return mb_strtolower($tableized);\n    }\n\n    /**\n     * Converts a word into the format for a Doctrine class name. Converts 'table_name' to 'TableName'.\n     */\n    public function classify(string $word): string\n    {\n        return str_replace([' ', '_', '-'], '', ucwords($word, ' _-'));\n    }\n\n    /**\n     * Camelizes a word. This uses the classify() method and turns the first character to lowercase.\n     */\n    public function camelize(string $word): string\n    {\n        return lcfirst($this->classify($word));\n    }\n\n    /**\n     * Uppercases words with configurable delimiters between words.\n     *\n     * Takes a string and capitalizes all of the words, like PHP's built-in\n     * ucwords function. This extends that behavior, however, by allowing the\n     * word delimiters to be configured, rather than only separating on\n     * whitespace.\n     *\n     * Here is an example:\n     * <code>\n     * <?php\n     * $string = 'top-o-the-morning to all_of_you!';\n     * echo $inflector->capitalize($string);\n     * // Top-O-The-Morning To All_of_you!\n     *\n     * echo $inflector->capitalize($string, '-_ ');\n     * // Top-O-The-Morning To All_Of_You!\n     * ?>\n     * </code>\n     *\n     * @param string $string     The string to operate on.\n     * @param string $delimiters A list of word separators.\n     *\n     * @return string The string with all delimiter-separated words capitalized.\n     */\n    public function capitalize(string $string, string $delimiters = \" \\n\\t\\r\\0\\x0B-\"): string\n    {\n        return ucwords($string, $delimiters);\n    }\n\n    /**\n     * Checks if the given string seems like it has utf8 characters in it.\n     *\n     * @param string $string The string to check for utf8 characters in.\n     */\n    public function seemsUtf8(string $string): bool\n    {\n        for ($i = 0; $i < strlen($string); $i++) {\n            if (ord($string[$i]) < 0x80) {\n                continue; // 0bbbbbbb\n            }\n\n            if ((ord($string[$i]) & 0xE0) === 0xC0) {\n                $n = 1; // 110bbbbb\n            } elseif ((ord($string[$i]) & 0xF0) === 0xE0) {\n                $n = 2; // 1110bbbb\n            } elseif ((ord($string[$i]) & 0xF8) === 0xF0) {\n                $n = 3; // 11110bbb\n            } elseif ((ord($string[$i]) & 0xFC) === 0xF8) {\n                $n = 4; // 111110bb\n            } elseif ((ord($string[$i]) & 0xFE) === 0xFC) {\n                $n = 5; // 1111110b\n            } else {\n                return false; // Does not match any model\n            }\n\n            for ($j = 0; $j < $n; $j++) { // n bytes matching 10bbbbbb follow ?\n                if (++$i === strlen($string) || ((ord($string[$i]) & 0xC0) !== 0x80)) {\n                    return false;\n                }\n            }\n        }\n\n        return true;\n    }\n\n    /**\n     * Remove any illegal characters, accents, etc.\n     *\n     * @param  string $string String to unaccent\n     *\n     * @return string Unaccented string\n     */\n    public function unaccent(string $string): string\n    {\n        if (preg_match('/[\\x80-\\xff]/', $string) === false) {\n            return $string;\n        }\n\n        if ($this->seemsUtf8($string)) {\n            $string = strtr($string, self::ACCENTED_CHARACTERS);\n        } else {\n            $characters = [];\n\n            // Assume ISO-8859-1 if not UTF-8\n            $characters['in'] =\n                  chr(128)\n                . chr(131)\n                . chr(138)\n                . chr(142)\n                . chr(154)\n                . chr(158)\n                . chr(159)\n                . chr(162)\n                . chr(165)\n                . chr(181)\n                . chr(192)\n                . chr(193)\n                . chr(194)\n                . chr(195)\n                . chr(196)\n                . chr(197)\n                . chr(199)\n                . chr(200)\n                . chr(201)\n                . chr(202)\n                . chr(203)\n                . chr(204)\n                . chr(205)\n                . chr(206)\n                . chr(207)\n                . chr(209)\n                . chr(210)\n                . chr(211)\n                . chr(212)\n                . chr(213)\n                . chr(214)\n                . chr(216)\n                . chr(217)\n                . chr(218)\n                . chr(219)\n                . chr(220)\n                . chr(221)\n                . chr(224)\n                . chr(225)\n                . chr(226)\n                . chr(227)\n                . chr(228)\n                . chr(229)\n                . chr(231)\n                . chr(232)\n                . chr(233)\n                . chr(234)\n                . chr(235)\n                . chr(236)\n                . chr(237)\n                . chr(238)\n                . chr(239)\n                . chr(241)\n                . chr(242)\n                . chr(243)\n                . chr(244)\n                . chr(245)\n                . chr(246)\n                . chr(248)\n                . chr(249)\n                . chr(250)\n                . chr(251)\n                . chr(252)\n                . chr(253)\n                . chr(255);\n\n            $characters['out'] = 'EfSZszYcYuAAAAAACEEEEIIIINOOOOOOUUUUYaaaaaaceeeeiiiinoooooouuuuyy';\n\n            $string = strtr($string, $characters['in'], $characters['out']);\n\n            $doubleChars = [];\n\n            $doubleChars['in'] = [\n                chr(140),\n                chr(156),\n                chr(198),\n                chr(208),\n                chr(222),\n                chr(223),\n                chr(230),\n                chr(240),\n                chr(254),\n            ];\n\n            $doubleChars['out'] = ['OE', 'oe', 'AE', 'DH', 'TH', 'ss', 'ae', 'dh', 'th'];\n\n            $string = str_replace($doubleChars['in'], $doubleChars['out'], $string);\n        }\n\n        return $string;\n    }\n\n    /**\n     * Convert any passed string to a url friendly string.\n     * Converts 'My first blog post' to 'my-first-blog-post'\n     *\n     * @param  string $string String to urlize.\n     *\n     * @return string Urlized string.\n     */\n    public function urlize(string $string): string\n    {\n        // Remove all non url friendly characters with the unaccent function\n        $unaccented = $this->unaccent($string);\n\n        if (function_exists('mb_strtolower')) {\n            $lowered = mb_strtolower($unaccented);\n        } else {\n            $lowered = strtolower($unaccented);\n        }\n\n        $replacements = [\n            '/\\W/' => ' ',\n            '/([A-Z]+)([A-Z][a-z])/' => '\\1_\\2',\n            '/([a-z\\d])([A-Z])/' => '\\1_\\2',\n            '/[^A-Z^a-z^0-9^\\/]+/' => '-',\n        ];\n\n        $urlized = $lowered;\n\n        foreach ($replacements as $pattern => $replacement) {\n            $replaced = preg_replace($pattern, $replacement, $urlized);\n\n            if ($replaced === null) {\n                throw new RuntimeException(sprintf(\n                    'preg_replace returned null for value \"%s\"',\n                    $urlized\n                ));\n            }\n\n            $urlized = $replaced;\n        }\n\n        return trim($urlized, '-');\n    }\n\n    /**\n     * Returns a word in singular form.\n     *\n     * @param string $word The word in plural form.\n     *\n     * @return string The word in singular form.\n     */\n    public function singularize(string $word): string\n    {\n        return $this->singularizer->inflect($word);\n    }\n\n    /**\n     * Returns a word in plural form.\n     *\n     * @param string $word The word in singular form.\n     *\n     * @return string The word in plural form.\n     */\n    public function pluralize(string $word): string\n    {\n        return $this->pluralizer->inflect($word);\n    }\n}\n"
  },
  {
    "path": "server/vendor/doctrine/inflector/lib/Doctrine/Inflector/InflectorFactory.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Doctrine\\Inflector;\n\nuse Doctrine\\Inflector\\Rules\\English;\nuse Doctrine\\Inflector\\Rules\\French;\nuse Doctrine\\Inflector\\Rules\\NorwegianBokmal;\nuse Doctrine\\Inflector\\Rules\\Portuguese;\nuse Doctrine\\Inflector\\Rules\\Spanish;\nuse Doctrine\\Inflector\\Rules\\Turkish;\nuse InvalidArgumentException;\n\nuse function sprintf;\n\nfinal class InflectorFactory\n{\n    public static function create(): LanguageInflectorFactory\n    {\n        return self::createForLanguage(Language::ENGLISH);\n    }\n\n    public static function createForLanguage(string $language): LanguageInflectorFactory\n    {\n        switch ($language) {\n            case Language::ENGLISH:\n                return new English\\InflectorFactory();\n\n            case Language::FRENCH:\n                return new French\\InflectorFactory();\n\n            case Language::NORWEGIAN_BOKMAL:\n                return new NorwegianBokmal\\InflectorFactory();\n\n            case Language::PORTUGUESE:\n                return new Portuguese\\InflectorFactory();\n\n            case Language::SPANISH:\n                return new Spanish\\InflectorFactory();\n\n            case Language::TURKISH:\n                return new Turkish\\InflectorFactory();\n\n            default:\n                throw new InvalidArgumentException(sprintf(\n                    'Language \"%s\" is not supported.',\n                    $language\n                ));\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/doctrine/inflector/lib/Doctrine/Inflector/Language.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Doctrine\\Inflector;\n\nfinal class Language\n{\n    public const ENGLISH          = 'english';\n    public const FRENCH           = 'french';\n    public const NORWEGIAN_BOKMAL = 'norwegian-bokmal';\n    public const PORTUGUESE       = 'portuguese';\n    public const SPANISH          = 'spanish';\n    public const TURKISH          = 'turkish';\n\n    private function __construct()\n    {\n    }\n}\n"
  },
  {
    "path": "server/vendor/doctrine/inflector/lib/Doctrine/Inflector/LanguageInflectorFactory.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Doctrine\\Inflector;\n\nuse Doctrine\\Inflector\\Rules\\Ruleset;\n\ninterface LanguageInflectorFactory\n{\n    /**\n     * Applies custom rules for singularisation\n     *\n     * @param bool $reset If true, will unset default inflections for all new rules\n     *\n     * @return $this\n     */\n    public function withSingularRules(?Ruleset $singularRules, bool $reset = false): self;\n\n    /**\n     * Applies custom rules for pluralisation\n     *\n     * @param bool $reset If true, will unset default inflections for all new rules\n     *\n     * @return $this\n     */\n    public function withPluralRules(?Ruleset $pluralRules, bool $reset = false): self;\n\n    /**\n     * Builds the inflector instance with all applicable rules\n     */\n    public function build(): Inflector;\n}\n"
  },
  {
    "path": "server/vendor/doctrine/inflector/lib/Doctrine/Inflector/NoopWordInflector.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Doctrine\\Inflector;\n\nclass NoopWordInflector implements WordInflector\n{\n    public function inflect(string $word): string\n    {\n        return $word;\n    }\n}\n"
  },
  {
    "path": "server/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/English/Inflectible.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Doctrine\\Inflector\\Rules\\English;\n\nuse Doctrine\\Inflector\\Rules\\Pattern;\nuse Doctrine\\Inflector\\Rules\\Substitution;\nuse Doctrine\\Inflector\\Rules\\Transformation;\nuse Doctrine\\Inflector\\Rules\\Word;\n\nclass Inflectible\n{\n    /** @return Transformation[] */\n    public static function getSingular(): iterable\n    {\n        yield new Transformation(new Pattern('(s)tatuses$'), '\\1\\2tatus');\n        yield new Transformation(new Pattern('(s)tatus$'), '\\1\\2tatus');\n        yield new Transformation(new Pattern('(c)ampus$'), '\\1\\2ampus');\n        yield new Transformation(new Pattern('^(.*)(menu)s$'), '\\1\\2');\n        yield new Transformation(new Pattern('(quiz)zes$'), '\\\\1');\n        yield new Transformation(new Pattern('(matr)ices$'), '\\1ix');\n        yield new Transformation(new Pattern('(vert|ind)ices$'), '\\1ex');\n        yield new Transformation(new Pattern('^(ox)en'), '\\1');\n        yield new Transformation(new Pattern('(alias)(es)*$'), '\\1');\n        yield new Transformation(new Pattern('(buffal|her|potat|tomat|volcan)oes$'), '\\1o');\n        yield new Transformation(new Pattern('(alumn|bacill|cact|foc|fung|nucle|radi|stimul|syllab|termin|viri?)i$'), '\\1us');\n        yield new Transformation(new Pattern('([ftw]ax)es'), '\\1');\n        yield new Transformation(new Pattern('(analys|ax|cris|test|thes)es$'), '\\1is');\n        yield new Transformation(new Pattern('(shoe|slave)s$'), '\\1');\n        yield new Transformation(new Pattern('(o)es$'), '\\1');\n        yield new Transformation(new Pattern('ouses$'), 'ouse');\n        yield new Transformation(new Pattern('([^a])uses$'), '\\1us');\n        yield new Transformation(new Pattern('([m|l])ice$'), '\\1ouse');\n        yield new Transformation(new Pattern('(x|ch|ss|sh)es$'), '\\1');\n        yield new Transformation(new Pattern('(m)ovies$'), '\\1\\2ovie');\n        yield new Transformation(new Pattern('(s)eries$'), '\\1\\2eries');\n        yield new Transformation(new Pattern('([^aeiouy]|qu)ies$'), '\\1y');\n        yield new Transformation(new Pattern('([lr])ves$'), '\\1f');\n        yield new Transformation(new Pattern('(tive)s$'), '\\1');\n        yield new Transformation(new Pattern('(hive)s$'), '\\1');\n        yield new Transformation(new Pattern('(drive)s$'), '\\1');\n        yield new Transformation(new Pattern('(dive)s$'), '\\1');\n        yield new Transformation(new Pattern('(olive)s$'), '\\1');\n        yield new Transformation(new Pattern('([^fo])ves$'), '\\1fe');\n        yield new Transformation(new Pattern('(^analy)ses$'), '\\1sis');\n        yield new Transformation(new Pattern('(analy|diagno|^ba|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$'), '\\1\\2sis');\n        yield new Transformation(new Pattern('(tax)a$'), '\\1on');\n        yield new Transformation(new Pattern('(c)riteria$'), '\\1riterion');\n        yield new Transformation(new Pattern('([ti])a(?<!regatta)$'), '\\1um');\n        yield new Transformation(new Pattern('(p)eople$'), '\\1\\2erson');\n        yield new Transformation(new Pattern('(m)en$'), '\\1an');\n        yield new Transformation(new Pattern('(c)hildren$'), '\\1\\2hild');\n        yield new Transformation(new Pattern('(f)eet$'), '\\1oot');\n        yield new Transformation(new Pattern('(n)ews$'), '\\1\\2ews');\n        yield new Transformation(new Pattern('eaus$'), 'eau');\n        yield new Transformation(new Pattern('^tights$'), 'tights');\n        yield new Transformation(new Pattern('^shorts$'), 'shorts');\n        yield new Transformation(new Pattern('s$'), '');\n    }\n\n    /** @return Transformation[] */\n    public static function getPlural(): iterable\n    {\n        yield new Transformation(new Pattern('(s)tatus$'), '\\1\\2tatuses');\n        yield new Transformation(new Pattern('(quiz)$'), '\\1zes');\n        yield new Transformation(new Pattern('^(ox)$'), '\\1\\2en');\n        yield new Transformation(new Pattern('([m|l])ouse$'), '\\1ice');\n        yield new Transformation(new Pattern('(matr|vert|ind)(ix|ex)$'), '\\1ices');\n        yield new Transformation(new Pattern('(x|ch|ss|sh)$'), '\\1es');\n        yield new Transformation(new Pattern('([^aeiouy]|qu)y$'), '\\1ies');\n        yield new Transformation(new Pattern('(hive|gulf)$'), '\\1s');\n        yield new Transformation(new Pattern('(?:([^f])fe|([lr])f)$'), '\\1\\2ves');\n        yield new Transformation(new Pattern('sis$'), 'ses');\n        yield new Transformation(new Pattern('([ti])um$'), '\\1a');\n        yield new Transformation(new Pattern('(tax)on$'), '\\1a');\n        yield new Transformation(new Pattern('(c)riterion$'), '\\1riteria');\n        yield new Transformation(new Pattern('(p)erson$'), '\\1eople');\n        yield new Transformation(new Pattern('(m)an$'), '\\1en');\n        yield new Transformation(new Pattern('(c)hild$'), '\\1hildren');\n        yield new Transformation(new Pattern('(f)oot$'), '\\1eet');\n        yield new Transformation(new Pattern('(buffal|her|potat|tomat|volcan)o$'), '\\1\\2oes');\n        yield new Transformation(new Pattern('(alumn|bacill|cact|foc|fung|nucle|radi|stimul|syllab|termin|vir)us$'), '\\1i');\n        yield new Transformation(new Pattern('us$'), 'uses');\n        yield new Transformation(new Pattern('(alias)$'), '\\1es');\n        yield new Transformation(new Pattern('(analys|ax|cris|test|thes)is$'), '\\1es');\n        yield new Transformation(new Pattern('s$'), 's');\n        yield new Transformation(new Pattern('^$'), '');\n        yield new Transformation(new Pattern('$'), 's');\n    }\n\n    /** @return Substitution[] */\n    public static function getIrregular(): iterable\n    {\n        yield new Substitution(new Word('atlas'), new Word('atlases'));\n        yield new Substitution(new Word('axis'), new Word('axes'));\n        yield new Substitution(new Word('axe'), new Word('axes'));\n        yield new Substitution(new Word('beef'), new Word('beefs'));\n        yield new Substitution(new Word('blouse'), new Word('blouses'));\n        yield new Substitution(new Word('brother'), new Word('brothers'));\n        yield new Substitution(new Word('cafe'), new Word('cafes'));\n        yield new Substitution(new Word('cave'), new Word('caves'));\n        yield new Substitution(new Word('chateau'), new Word('chateaux'));\n        yield new Substitution(new Word('niveau'), new Word('niveaux'));\n        yield new Substitution(new Word('child'), new Word('children'));\n        yield new Substitution(new Word('canvas'), new Word('canvases'));\n        yield new Substitution(new Word('cookie'), new Word('cookies'));\n        yield new Substitution(new Word('brownie'), new Word('brownies'));\n        yield new Substitution(new Word('corpus'), new Word('corpuses'));\n        yield new Substitution(new Word('cow'), new Word('cows'));\n        yield new Substitution(new Word('criterion'), new Word('criteria'));\n        yield new Substitution(new Word('curriculum'), new Word('curricula'));\n        yield new Substitution(new Word('demo'), new Word('demos'));\n        yield new Substitution(new Word('domino'), new Word('dominoes'));\n        yield new Substitution(new Word('echo'), new Word('echoes'));\n        yield new Substitution(new Word('epoch'), new Word('epochs'));\n        yield new Substitution(new Word('foot'), new Word('feet'));\n        yield new Substitution(new Word('fungus'), new Word('fungi'));\n        yield new Substitution(new Word('ganglion'), new Word('ganglions'));\n        yield new Substitution(new Word('gas'), new Word('gases'));\n        yield new Substitution(new Word('genie'), new Word('genies'));\n        yield new Substitution(new Word('genus'), new Word('genera'));\n        yield new Substitution(new Word('goose'), new Word('geese'));\n        yield new Substitution(new Word('graffito'), new Word('graffiti'));\n        yield new Substitution(new Word('hippopotamus'), new Word('hippopotami'));\n        yield new Substitution(new Word('hoof'), new Word('hoofs'));\n        yield new Substitution(new Word('human'), new Word('humans'));\n        yield new Substitution(new Word('iris'), new Word('irises'));\n        yield new Substitution(new Word('larva'), new Word('larvae'));\n        yield new Substitution(new Word('leaf'), new Word('leaves'));\n        yield new Substitution(new Word('lens'), new Word('lenses'));\n        yield new Substitution(new Word('loaf'), new Word('loaves'));\n        yield new Substitution(new Word('man'), new Word('men'));\n        yield new Substitution(new Word('medium'), new Word('media'));\n        yield new Substitution(new Word('memorandum'), new Word('memoranda'));\n        yield new Substitution(new Word('money'), new Word('monies'));\n        yield new Substitution(new Word('mongoose'), new Word('mongooses'));\n        yield new Substitution(new Word('motto'), new Word('mottoes'));\n        yield new Substitution(new Word('move'), new Word('moves'));\n        yield new Substitution(new Word('mythos'), new Word('mythoi'));\n        yield new Substitution(new Word('niche'), new Word('niches'));\n        yield new Substitution(new Word('nucleus'), new Word('nuclei'));\n        yield new Substitution(new Word('numen'), new Word('numina'));\n        yield new Substitution(new Word('occiput'), new Word('occiputs'));\n        yield new Substitution(new Word('octopus'), new Word('octopuses'));\n        yield new Substitution(new Word('opus'), new Word('opuses'));\n        yield new Substitution(new Word('ox'), new Word('oxen'));\n        yield new Substitution(new Word('passerby'), new Word('passersby'));\n        yield new Substitution(new Word('penis'), new Word('penises'));\n        yield new Substitution(new Word('person'), new Word('people'));\n        yield new Substitution(new Word('plateau'), new Word('plateaux'));\n        yield new Substitution(new Word('runner-up'), new Word('runners-up'));\n        yield new Substitution(new Word('safe'), new Word('safes'));\n        yield new Substitution(new Word('sex'), new Word('sexes'));\n        yield new Substitution(new Word('sieve'), new Word('sieves'));\n        yield new Substitution(new Word('soliloquy'), new Word('soliloquies'));\n        yield new Substitution(new Word('son-in-law'), new Word('sons-in-law'));\n        yield new Substitution(new Word('syllabus'), new Word('syllabi'));\n        yield new Substitution(new Word('testis'), new Word('testes'));\n        yield new Substitution(new Word('thief'), new Word('thieves'));\n        yield new Substitution(new Word('tooth'), new Word('teeth'));\n        yield new Substitution(new Word('tornado'), new Word('tornadoes'));\n        yield new Substitution(new Word('trilby'), new Word('trilbys'));\n        yield new Substitution(new Word('turf'), new Word('turfs'));\n        yield new Substitution(new Word('valve'), new Word('valves'));\n        yield new Substitution(new Word('volcano'), new Word('volcanoes'));\n        yield new Substitution(new Word('abuse'), new Word('abuses'));\n        yield new Substitution(new Word('avalanche'), new Word('avalanches'));\n        yield new Substitution(new Word('cache'), new Word('caches'));\n        yield new Substitution(new Word('criterion'), new Word('criteria'));\n        yield new Substitution(new Word('curve'), new Word('curves'));\n        yield new Substitution(new Word('emphasis'), new Word('emphases'));\n        yield new Substitution(new Word('foe'), new Word('foes'));\n        yield new Substitution(new Word('grave'), new Word('graves'));\n        yield new Substitution(new Word('hoax'), new Word('hoaxes'));\n        yield new Substitution(new Word('medium'), new Word('media'));\n        yield new Substitution(new Word('neurosis'), new Word('neuroses'));\n        yield new Substitution(new Word('save'), new Word('saves'));\n        yield new Substitution(new Word('wave'), new Word('waves'));\n        yield new Substitution(new Word('oasis'), new Word('oases'));\n        yield new Substitution(new Word('valve'), new Word('valves'));\n        yield new Substitution(new Word('zombie'), new Word('zombies'));\n    }\n}\n"
  },
  {
    "path": "server/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/English/InflectorFactory.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Doctrine\\Inflector\\Rules\\English;\n\nuse Doctrine\\Inflector\\GenericLanguageInflectorFactory;\nuse Doctrine\\Inflector\\Rules\\Ruleset;\n\nfinal class InflectorFactory extends GenericLanguageInflectorFactory\n{\n    protected function getSingularRuleset(): Ruleset\n    {\n        return Rules::getSingularRuleset();\n    }\n\n    protected function getPluralRuleset(): Ruleset\n    {\n        return Rules::getPluralRuleset();\n    }\n}\n"
  },
  {
    "path": "server/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/English/Rules.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Doctrine\\Inflector\\Rules\\English;\n\nuse Doctrine\\Inflector\\Rules\\Patterns;\nuse Doctrine\\Inflector\\Rules\\Ruleset;\nuse Doctrine\\Inflector\\Rules\\Substitutions;\nuse Doctrine\\Inflector\\Rules\\Transformations;\n\nfinal class Rules\n{\n    public static function getSingularRuleset(): Ruleset\n    {\n        return new Ruleset(\n            new Transformations(...Inflectible::getSingular()),\n            new Patterns(...Uninflected::getSingular()),\n            (new Substitutions(...Inflectible::getIrregular()))->getFlippedSubstitutions()\n        );\n    }\n\n    public static function getPluralRuleset(): Ruleset\n    {\n        return new Ruleset(\n            new Transformations(...Inflectible::getPlural()),\n            new Patterns(...Uninflected::getPlural()),\n            new Substitutions(...Inflectible::getIrregular())\n        );\n    }\n}\n"
  },
  {
    "path": "server/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/English/Uninflected.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Doctrine\\Inflector\\Rules\\English;\n\nuse Doctrine\\Inflector\\Rules\\Pattern;\n\nfinal class Uninflected\n{\n    /** @return Pattern[] */\n    public static function getSingular(): iterable\n    {\n        yield from self::getDefault();\n\n        yield new Pattern('.*ss');\n        yield new Pattern('clothes');\n        yield new Pattern('data');\n        yield new Pattern('fascia');\n        yield new Pattern('fuchsia');\n        yield new Pattern('galleria');\n        yield new Pattern('mafia');\n        yield new Pattern('militia');\n        yield new Pattern('pants');\n        yield new Pattern('petunia');\n        yield new Pattern('sepia');\n        yield new Pattern('trivia');\n        yield new Pattern('utopia');\n    }\n\n    /** @return Pattern[] */\n    public static function getPlural(): iterable\n    {\n        yield from self::getDefault();\n\n        yield new Pattern('people');\n        yield new Pattern('trivia');\n        yield new Pattern('\\w+ware$');\n        yield new Pattern('media');\n    }\n\n    /** @return Pattern[] */\n    private static function getDefault(): iterable\n    {\n        yield new Pattern('\\w+media');\n        yield new Pattern('advice');\n        yield new Pattern('aircraft');\n        yield new Pattern('amoyese');\n        yield new Pattern('art');\n        yield new Pattern('audio');\n        yield new Pattern('baggage');\n        yield new Pattern('bison');\n        yield new Pattern('borghese');\n        yield new Pattern('bream');\n        yield new Pattern('breeches');\n        yield new Pattern('britches');\n        yield new Pattern('buffalo');\n        yield new Pattern('butter');\n        yield new Pattern('cantus');\n        yield new Pattern('carp');\n        yield new Pattern('cattle');\n        yield new Pattern('chassis');\n        yield new Pattern('clippers');\n        yield new Pattern('clothing');\n        yield new Pattern('coal');\n        yield new Pattern('cod');\n        yield new Pattern('coitus');\n        yield new Pattern('compensation');\n        yield new Pattern('congoese');\n        yield new Pattern('contretemps');\n        yield new Pattern('coreopsis');\n        yield new Pattern('corps');\n        yield new Pattern('cotton');\n        yield new Pattern('data');\n        yield new Pattern('debris');\n        yield new Pattern('deer');\n        yield new Pattern('diabetes');\n        yield new Pattern('djinn');\n        yield new Pattern('education');\n        yield new Pattern('eland');\n        yield new Pattern('elk');\n        yield new Pattern('emoji');\n        yield new Pattern('equipment');\n        yield new Pattern('evidence');\n        yield new Pattern('faroese');\n        yield new Pattern('feedback');\n        yield new Pattern('fish');\n        yield new Pattern('flounder');\n        yield new Pattern('flour');\n        yield new Pattern('foochowese');\n        yield new Pattern('food');\n        yield new Pattern('furniture');\n        yield new Pattern('gallows');\n        yield new Pattern('genevese');\n        yield new Pattern('genoese');\n        yield new Pattern('gilbertese');\n        yield new Pattern('gold');\n        yield new Pattern('headquarters');\n        yield new Pattern('herpes');\n        yield new Pattern('hijinks');\n        yield new Pattern('homework');\n        yield new Pattern('hottentotese');\n        yield new Pattern('impatience');\n        yield new Pattern('information');\n        yield new Pattern('innings');\n        yield new Pattern('jackanapes');\n        yield new Pattern('jeans');\n        yield new Pattern('jedi');\n        yield new Pattern('kin');\n        yield new Pattern('kiplingese');\n        yield new Pattern('knowledge');\n        yield new Pattern('kongoese');\n        yield new Pattern('leather');\n        yield new Pattern('love');\n        yield new Pattern('lucchese');\n        yield new Pattern('luggage');\n        yield new Pattern('mackerel');\n        yield new Pattern('Maltese');\n        yield new Pattern('management');\n        yield new Pattern('metadata');\n        yield new Pattern('mews');\n        yield new Pattern('money');\n        yield new Pattern('moose');\n        yield new Pattern('mumps');\n        yield new Pattern('music');\n        yield new Pattern('nankingese');\n        yield new Pattern('news');\n        yield new Pattern('nexus');\n        yield new Pattern('niasese');\n        yield new Pattern('nutrition');\n        yield new Pattern('offspring');\n        yield new Pattern('oil');\n        yield new Pattern('patience');\n        yield new Pattern('pekingese');\n        yield new Pattern('piedmontese');\n        yield new Pattern('pincers');\n        yield new Pattern('pistoiese');\n        yield new Pattern('plankton');\n        yield new Pattern('pliers');\n        yield new Pattern('pokemon');\n        yield new Pattern('police');\n        yield new Pattern('polish');\n        yield new Pattern('portuguese');\n        yield new Pattern('proceedings');\n        yield new Pattern('progress');\n        yield new Pattern('rabies');\n        yield new Pattern('rain');\n        yield new Pattern('research');\n        yield new Pattern('rhinoceros');\n        yield new Pattern('rice');\n        yield new Pattern('salmon');\n        yield new Pattern('sand');\n        yield new Pattern('sarawakese');\n        yield new Pattern('scissors');\n        yield new Pattern('sea[- ]bass');\n        yield new Pattern('series');\n        yield new Pattern('shavese');\n        yield new Pattern('shears');\n        yield new Pattern('sheep');\n        yield new Pattern('siemens');\n        yield new Pattern('silk');\n        yield new Pattern('sms');\n        yield new Pattern('soap');\n        yield new Pattern('social media');\n        yield new Pattern('spam');\n        yield new Pattern('species');\n        yield new Pattern('staff');\n        yield new Pattern('sugar');\n        yield new Pattern('swine');\n        yield new Pattern('talent');\n        yield new Pattern('toothpaste');\n        yield new Pattern('traffic');\n        yield new Pattern('travel');\n        yield new Pattern('trousers');\n        yield new Pattern('trout');\n        yield new Pattern('tuna');\n        yield new Pattern('us');\n        yield new Pattern('vermontese');\n        yield new Pattern('vinegar');\n        yield new Pattern('weather');\n        yield new Pattern('wenchowese');\n        yield new Pattern('wheat');\n        yield new Pattern('whiting');\n        yield new Pattern('wildebeest');\n        yield new Pattern('wood');\n        yield new Pattern('wool');\n        yield new Pattern('yengeese');\n    }\n}\n"
  },
  {
    "path": "server/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/French/Inflectible.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Doctrine\\Inflector\\Rules\\French;\n\nuse Doctrine\\Inflector\\Rules\\Pattern;\nuse Doctrine\\Inflector\\Rules\\Substitution;\nuse Doctrine\\Inflector\\Rules\\Transformation;\nuse Doctrine\\Inflector\\Rules\\Word;\n\nclass Inflectible\n{\n    /** @return Transformation[] */\n    public static function getSingular(): iterable\n    {\n        yield new Transformation(new Pattern('/(b|cor|ém|gemm|soupir|trav|vant|vitr)aux$/'), '\\1ail');\n        yield new Transformation(new Pattern('/ails$/'), 'ail');\n        yield new Transformation(new Pattern('/(journ|chev)aux$/'), '\\1al');\n        yield new Transformation(new Pattern('/(bijou|caillou|chou|genou|hibou|joujou|pou|au|eu|eau)x$/'), '\\1');\n        yield new Transformation(new Pattern('/s$/'), '');\n    }\n\n    /** @return Transformation[] */\n    public static function getPlural(): iterable\n    {\n        yield new Transformation(new Pattern('/(s|x|z)$/'), '\\1');\n        yield new Transformation(new Pattern('/(b|cor|ém|gemm|soupir|trav|vant|vitr)ail$/'), '\\1aux');\n        yield new Transformation(new Pattern('/ail$/'), 'ails');\n        yield new Transformation(new Pattern('/(chacal|carnaval|festival|récital)$/'), '\\1s');\n        yield new Transformation(new Pattern('/al$/'), 'aux');\n        yield new Transformation(new Pattern('/(bleu|émeu|landau|pneu|sarrau)$/'), '\\1s');\n        yield new Transformation(new Pattern('/(bijou|caillou|chou|genou|hibou|joujou|lieu|pou|au|eu|eau)$/'), '\\1x');\n        yield new Transformation(new Pattern('/$/'), 's');\n    }\n\n    /** @return Substitution[] */\n    public static function getIrregular(): iterable\n    {\n        yield new Substitution(new Word('monsieur'), new Word('messieurs'));\n        yield new Substitution(new Word('madame'), new Word('mesdames'));\n        yield new Substitution(new Word('mademoiselle'), new Word('mesdemoiselles'));\n    }\n}\n"
  },
  {
    "path": "server/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/French/InflectorFactory.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Doctrine\\Inflector\\Rules\\French;\n\nuse Doctrine\\Inflector\\GenericLanguageInflectorFactory;\nuse Doctrine\\Inflector\\Rules\\Ruleset;\n\nfinal class InflectorFactory extends GenericLanguageInflectorFactory\n{\n    protected function getSingularRuleset(): Ruleset\n    {\n        return Rules::getSingularRuleset();\n    }\n\n    protected function getPluralRuleset(): Ruleset\n    {\n        return Rules::getPluralRuleset();\n    }\n}\n"
  },
  {
    "path": "server/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/French/Rules.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Doctrine\\Inflector\\Rules\\French;\n\nuse Doctrine\\Inflector\\Rules\\Patterns;\nuse Doctrine\\Inflector\\Rules\\Ruleset;\nuse Doctrine\\Inflector\\Rules\\Substitutions;\nuse Doctrine\\Inflector\\Rules\\Transformations;\n\nfinal class Rules\n{\n    public static function getSingularRuleset(): Ruleset\n    {\n        return new Ruleset(\n            new Transformations(...Inflectible::getSingular()),\n            new Patterns(...Uninflected::getSingular()),\n            (new Substitutions(...Inflectible::getIrregular()))->getFlippedSubstitutions()\n        );\n    }\n\n    public static function getPluralRuleset(): Ruleset\n    {\n        return new Ruleset(\n            new Transformations(...Inflectible::getPlural()),\n            new Patterns(...Uninflected::getPlural()),\n            new Substitutions(...Inflectible::getIrregular())\n        );\n    }\n}\n"
  },
  {
    "path": "server/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/French/Uninflected.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Doctrine\\Inflector\\Rules\\French;\n\nuse Doctrine\\Inflector\\Rules\\Pattern;\n\nfinal class Uninflected\n{\n    /** @return Pattern[] */\n    public static function getSingular(): iterable\n    {\n        yield from self::getDefault();\n    }\n\n    /** @return Pattern[] */\n    public static function getPlural(): iterable\n    {\n        yield from self::getDefault();\n    }\n\n    /** @return Pattern[] */\n    private static function getDefault(): iterable\n    {\n        yield new Pattern('');\n    }\n}\n"
  },
  {
    "path": "server/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/NorwegianBokmal/Inflectible.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Doctrine\\Inflector\\Rules\\NorwegianBokmal;\n\nuse Doctrine\\Inflector\\Rules\\Pattern;\nuse Doctrine\\Inflector\\Rules\\Substitution;\nuse Doctrine\\Inflector\\Rules\\Transformation;\nuse Doctrine\\Inflector\\Rules\\Word;\n\nclass Inflectible\n{\n    /** @return Transformation[] */\n    public static function getSingular(): iterable\n    {\n        yield new Transformation(new Pattern('/re$/i'), 'r');\n        yield new Transformation(new Pattern('/er$/i'), '');\n    }\n\n    /** @return Transformation[] */\n    public static function getPlural(): iterable\n    {\n        yield new Transformation(new Pattern('/e$/i'), 'er');\n        yield new Transformation(new Pattern('/r$/i'), 're');\n        yield new Transformation(new Pattern('/$/'), 'er');\n    }\n\n    /** @return Substitution[] */\n    public static function getIrregular(): iterable\n    {\n        yield new Substitution(new Word('konto'), new Word('konti'));\n    }\n}\n"
  },
  {
    "path": "server/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/NorwegianBokmal/InflectorFactory.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Doctrine\\Inflector\\Rules\\NorwegianBokmal;\n\nuse Doctrine\\Inflector\\GenericLanguageInflectorFactory;\nuse Doctrine\\Inflector\\Rules\\Ruleset;\n\nfinal class InflectorFactory extends GenericLanguageInflectorFactory\n{\n    protected function getSingularRuleset(): Ruleset\n    {\n        return Rules::getSingularRuleset();\n    }\n\n    protected function getPluralRuleset(): Ruleset\n    {\n        return Rules::getPluralRuleset();\n    }\n}\n"
  },
  {
    "path": "server/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/NorwegianBokmal/Rules.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Doctrine\\Inflector\\Rules\\NorwegianBokmal;\n\nuse Doctrine\\Inflector\\Rules\\Patterns;\nuse Doctrine\\Inflector\\Rules\\Ruleset;\nuse Doctrine\\Inflector\\Rules\\Substitutions;\nuse Doctrine\\Inflector\\Rules\\Transformations;\n\nfinal class Rules\n{\n    public static function getSingularRuleset(): Ruleset\n    {\n        return new Ruleset(\n            new Transformations(...Inflectible::getSingular()),\n            new Patterns(...Uninflected::getSingular()),\n            (new Substitutions(...Inflectible::getIrregular()))->getFlippedSubstitutions()\n        );\n    }\n\n    public static function getPluralRuleset(): Ruleset\n    {\n        return new Ruleset(\n            new Transformations(...Inflectible::getPlural()),\n            new Patterns(...Uninflected::getPlural()),\n            new Substitutions(...Inflectible::getIrregular())\n        );\n    }\n}\n"
  },
  {
    "path": "server/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/NorwegianBokmal/Uninflected.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Doctrine\\Inflector\\Rules\\NorwegianBokmal;\n\nuse Doctrine\\Inflector\\Rules\\Pattern;\n\nfinal class Uninflected\n{\n    /** @return Pattern[] */\n    public static function getSingular(): iterable\n    {\n        yield from self::getDefault();\n    }\n\n    /** @return Pattern[] */\n    public static function getPlural(): iterable\n    {\n        yield from self::getDefault();\n    }\n\n    /** @return Pattern[] */\n    private static function getDefault(): iterable\n    {\n        yield new Pattern('barn');\n        yield new Pattern('fjell');\n        yield new Pattern('hus');\n    }\n}\n"
  },
  {
    "path": "server/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Pattern.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Doctrine\\Inflector\\Rules;\n\nuse function preg_match;\n\nfinal class Pattern\n{\n    /** @var string */\n    private $pattern;\n\n    /** @var string */\n    private $regex;\n\n    public function __construct(string $pattern)\n    {\n        $this->pattern = $pattern;\n\n        if (isset($this->pattern[0]) && $this->pattern[0] === '/') {\n            $this->regex = $this->pattern;\n        } else {\n            $this->regex = '/' . $this->pattern . '/i';\n        }\n    }\n\n    public function getPattern(): string\n    {\n        return $this->pattern;\n    }\n\n    public function getRegex(): string\n    {\n        return $this->regex;\n    }\n\n    public function matches(string $word): bool\n    {\n        return preg_match($this->getRegex(), $word) === 1;\n    }\n}\n"
  },
  {
    "path": "server/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Patterns.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Doctrine\\Inflector\\Rules;\n\nuse function array_map;\nuse function implode;\nuse function preg_match;\n\nclass Patterns\n{\n    /** @var Pattern[] */\n    private $patterns;\n\n    /** @var string */\n    private $regex;\n\n    public function __construct(Pattern ...$patterns)\n    {\n        $this->patterns = $patterns;\n\n        $patterns = array_map(static function (Pattern $pattern): string {\n            return $pattern->getPattern();\n        }, $this->patterns);\n\n        $this->regex = '/^(?:' . implode('|', $patterns) . ')$/i';\n    }\n\n    public function matches(string $word): bool\n    {\n        return preg_match($this->regex, $word, $regs) === 1;\n    }\n}\n"
  },
  {
    "path": "server/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Portuguese/Inflectible.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Doctrine\\Inflector\\Rules\\Portuguese;\n\nuse Doctrine\\Inflector\\Rules\\Pattern;\nuse Doctrine\\Inflector\\Rules\\Substitution;\nuse Doctrine\\Inflector\\Rules\\Transformation;\nuse Doctrine\\Inflector\\Rules\\Word;\n\nclass Inflectible\n{\n    /** @return Transformation[] */\n    public static function getSingular(): iterable\n    {\n        yield new Transformation(new Pattern('/^(g|)ases$/i'), '\\1ás');\n        yield new Transformation(new Pattern('/(japon|escoc|ingl|dinamarqu|fregu|portugu)eses$/i'), '\\1ês');\n        yield new Transformation(new Pattern('/(ae|ao|oe)s$/'), 'ao');\n        yield new Transformation(new Pattern('/(ãe|ão|õe)s$/'), 'ão');\n        yield new Transformation(new Pattern('/^(.*[^s]s)es$/i'), '\\1');\n        yield new Transformation(new Pattern('/sses$/i'), 'sse');\n        yield new Transformation(new Pattern('/ns$/i'), 'm');\n        yield new Transformation(new Pattern('/(r|t|f|v)is$/i'), '\\1il');\n        yield new Transformation(new Pattern('/uis$/i'), 'ul');\n        yield new Transformation(new Pattern('/ois$/i'), 'ol');\n        yield new Transformation(new Pattern('/eis$/i'), 'ei');\n        yield new Transformation(new Pattern('/éis$/i'), 'el');\n        yield new Transformation(new Pattern('/([^p])ais$/i'), '\\1al');\n        yield new Transformation(new Pattern('/(r|z)es$/i'), '\\1');\n        yield new Transformation(new Pattern('/^(á|gá)s$/i'), '\\1s');\n        yield new Transformation(new Pattern('/([^ê])s$/i'), '\\1');\n    }\n\n    /** @return Transformation[] */\n    public static function getPlural(): iterable\n    {\n        yield new Transformation(new Pattern('/^(alem|c|p)ao$/i'), '\\1aes');\n        yield new Transformation(new Pattern('/^(irm|m)ao$/i'), '\\1aos');\n        yield new Transformation(new Pattern('/ao$/i'), 'oes');\n        yield new Transformation(new Pattern('/^(alem|c|p)ão$/i'), '\\1ães');\n        yield new Transformation(new Pattern('/^(irm|m)ão$/i'), '\\1ãos');\n        yield new Transformation(new Pattern('/ão$/i'), 'ões');\n        yield new Transformation(new Pattern('/^(|g)ás$/i'), '\\1ases');\n        yield new Transformation(new Pattern('/^(japon|escoc|ingl|dinamarqu|fregu|portugu)ês$/i'), '\\1eses');\n        yield new Transformation(new Pattern('/m$/i'), 'ns');\n        yield new Transformation(new Pattern('/([^aeou])il$/i'), '\\1is');\n        yield new Transformation(new Pattern('/ul$/i'), 'uis');\n        yield new Transformation(new Pattern('/ol$/i'), 'ois');\n        yield new Transformation(new Pattern('/el$/i'), 'eis');\n        yield new Transformation(new Pattern('/al$/i'), 'ais');\n        yield new Transformation(new Pattern('/(z|r)$/i'), '\\1es');\n        yield new Transformation(new Pattern('/(s)$/i'), '\\1');\n        yield new Transformation(new Pattern('/$/'), 's');\n    }\n\n    /** @return Substitution[] */\n    public static function getIrregular(): iterable\n    {\n        yield new Substitution(new Word('abdomen'), new Word('abdomens'));\n        yield new Substitution(new Word('alemão'), new Word('alemães'));\n        yield new Substitution(new Word('artesã'), new Word('artesãos'));\n        yield new Substitution(new Word('álcool'), new Word('álcoois'));\n        yield new Substitution(new Word('árvore'), new Word('árvores'));\n        yield new Substitution(new Word('bencão'), new Word('bencãos'));\n        yield new Substitution(new Word('cão'), new Word('cães'));\n        yield new Substitution(new Word('campus'), new Word('campi'));\n        yield new Substitution(new Word('cadáver'), new Word('cadáveres'));\n        yield new Substitution(new Word('capelão'), new Word('capelães'));\n        yield new Substitution(new Word('capitão'), new Word('capitães'));\n        yield new Substitution(new Word('chão'), new Word('chãos'));\n        yield new Substitution(new Word('charlatão'), new Word('charlatães'));\n        yield new Substitution(new Word('cidadão'), new Word('cidadãos'));\n        yield new Substitution(new Word('consul'), new Word('consules'));\n        yield new Substitution(new Word('cristão'), new Word('cristãos'));\n        yield new Substitution(new Word('difícil'), new Word('difíceis'));\n        yield new Substitution(new Word('email'), new Word('emails'));\n        yield new Substitution(new Word('escrivão'), new Word('escrivães'));\n        yield new Substitution(new Word('fóssil'), new Word('fósseis'));\n        yield new Substitution(new Word('gás'), new Word('gases'));\n        yield new Substitution(new Word('germens'), new Word('germen'));\n        yield new Substitution(new Word('grão'), new Word('grãos'));\n        yield new Substitution(new Word('hífen'), new Word('hífens'));\n        yield new Substitution(new Word('irmão'), new Word('irmãos'));\n        yield new Substitution(new Word('liquens'), new Word('liquen'));\n        yield new Substitution(new Word('mal'), new Word('males'));\n        yield new Substitution(new Word('mão'), new Word('mãos'));\n        yield new Substitution(new Word('orfão'), new Word('orfãos'));\n        yield new Substitution(new Word('país'), new Word('países'));\n        yield new Substitution(new Word('pai'), new Word('pais'));\n        yield new Substitution(new Word('pão'), new Word('pães'));\n        yield new Substitution(new Word('projétil'), new Word('projéteis'));\n        yield new Substitution(new Word('réptil'), new Word('répteis'));\n        yield new Substitution(new Word('sacristão'), new Word('sacristães'));\n        yield new Substitution(new Word('sotão'), new Word('sotãos'));\n        yield new Substitution(new Word('tabelião'), new Word('tabeliães'));\n    }\n}\n"
  },
  {
    "path": "server/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Portuguese/InflectorFactory.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Doctrine\\Inflector\\Rules\\Portuguese;\n\nuse Doctrine\\Inflector\\GenericLanguageInflectorFactory;\nuse Doctrine\\Inflector\\Rules\\Ruleset;\n\nfinal class InflectorFactory extends GenericLanguageInflectorFactory\n{\n    protected function getSingularRuleset(): Ruleset\n    {\n        return Rules::getSingularRuleset();\n    }\n\n    protected function getPluralRuleset(): Ruleset\n    {\n        return Rules::getPluralRuleset();\n    }\n}\n"
  },
  {
    "path": "server/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Portuguese/Rules.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Doctrine\\Inflector\\Rules\\Portuguese;\n\nuse Doctrine\\Inflector\\Rules\\Patterns;\nuse Doctrine\\Inflector\\Rules\\Ruleset;\nuse Doctrine\\Inflector\\Rules\\Substitutions;\nuse Doctrine\\Inflector\\Rules\\Transformations;\n\nfinal class Rules\n{\n    public static function getSingularRuleset(): Ruleset\n    {\n        return new Ruleset(\n            new Transformations(...Inflectible::getSingular()),\n            new Patterns(...Uninflected::getSingular()),\n            (new Substitutions(...Inflectible::getIrregular()))->getFlippedSubstitutions()\n        );\n    }\n\n    public static function getPluralRuleset(): Ruleset\n    {\n        return new Ruleset(\n            new Transformations(...Inflectible::getPlural()),\n            new Patterns(...Uninflected::getPlural()),\n            new Substitutions(...Inflectible::getIrregular())\n        );\n    }\n}\n"
  },
  {
    "path": "server/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Portuguese/Uninflected.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Doctrine\\Inflector\\Rules\\Portuguese;\n\nuse Doctrine\\Inflector\\Rules\\Pattern;\n\nfinal class Uninflected\n{\n    /** @return Pattern[] */\n    public static function getSingular(): iterable\n    {\n        yield from self::getDefault();\n    }\n\n    /** @return Pattern[] */\n    public static function getPlural(): iterable\n    {\n        yield from self::getDefault();\n    }\n\n    /** @return Pattern[] */\n    private static function getDefault(): iterable\n    {\n        yield new Pattern('tórax');\n        yield new Pattern('tênis');\n        yield new Pattern('ônibus');\n        yield new Pattern('lápis');\n        yield new Pattern('fênix');\n    }\n}\n"
  },
  {
    "path": "server/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Ruleset.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Doctrine\\Inflector\\Rules;\n\nclass Ruleset\n{\n    /** @var Transformations */\n    private $regular;\n\n    /** @var Patterns */\n    private $uninflected;\n\n    /** @var Substitutions */\n    private $irregular;\n\n    public function __construct(Transformations $regular, Patterns $uninflected, Substitutions $irregular)\n    {\n        $this->regular     = $regular;\n        $this->uninflected = $uninflected;\n        $this->irregular   = $irregular;\n    }\n\n    public function getRegular(): Transformations\n    {\n        return $this->regular;\n    }\n\n    public function getUninflected(): Patterns\n    {\n        return $this->uninflected;\n    }\n\n    public function getIrregular(): Substitutions\n    {\n        return $this->irregular;\n    }\n}\n"
  },
  {
    "path": "server/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Spanish/Inflectible.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Doctrine\\Inflector\\Rules\\Spanish;\n\nuse Doctrine\\Inflector\\Rules\\Pattern;\nuse Doctrine\\Inflector\\Rules\\Substitution;\nuse Doctrine\\Inflector\\Rules\\Transformation;\nuse Doctrine\\Inflector\\Rules\\Word;\n\nclass Inflectible\n{\n    /** @return Transformation[] */\n    public static function getSingular(): iterable\n    {\n        yield new Transformation(new Pattern('/ereses$/'), 'erés');\n        yield new Transformation(new Pattern('/iones$/'), 'ión');\n        yield new Transformation(new Pattern('/ces$/'), 'z');\n        yield new Transformation(new Pattern('/es$/'), '');\n        yield new Transformation(new Pattern('/s$/'), '');\n    }\n\n    /** @return Transformation[] */\n    public static function getPlural(): iterable\n    {\n        yield new Transformation(new Pattern('/ú([sn])$/i'), 'u\\1es');\n        yield new Transformation(new Pattern('/ó([sn])$/i'), 'o\\1es');\n        yield new Transformation(new Pattern('/í([sn])$/i'), 'i\\1es');\n        yield new Transformation(new Pattern('/é([sn])$/i'), 'e\\1es');\n        yield new Transformation(new Pattern('/á([sn])$/i'), 'a\\1es');\n        yield new Transformation(new Pattern('/z$/i'), 'ces');\n        yield new Transformation(new Pattern('/([aeiou]s)$/i'), '\\1');\n        yield new Transformation(new Pattern('/([^aeéiou])$/i'), '\\1es');\n        yield new Transformation(new Pattern('/$/'), 's');\n    }\n\n    /** @return Substitution[] */\n    public static function getIrregular(): iterable\n    {\n        yield new Substitution(new Word('el'), new Word('los'));\n        yield new Substitution(new Word('papá'), new Word('papás'));\n        yield new Substitution(new Word('mamá'), new Word('mamás'));\n        yield new Substitution(new Word('sofá'), new Word('sofás'));\n        yield new Substitution(new Word('mes'), new Word('meses'));\n    }\n}\n"
  },
  {
    "path": "server/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Spanish/InflectorFactory.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Doctrine\\Inflector\\Rules\\Spanish;\n\nuse Doctrine\\Inflector\\GenericLanguageInflectorFactory;\nuse Doctrine\\Inflector\\Rules\\Ruleset;\n\nfinal class InflectorFactory extends GenericLanguageInflectorFactory\n{\n    protected function getSingularRuleset(): Ruleset\n    {\n        return Rules::getSingularRuleset();\n    }\n\n    protected function getPluralRuleset(): Ruleset\n    {\n        return Rules::getPluralRuleset();\n    }\n}\n"
  },
  {
    "path": "server/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Spanish/Rules.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Doctrine\\Inflector\\Rules\\Spanish;\n\nuse Doctrine\\Inflector\\Rules\\Patterns;\nuse Doctrine\\Inflector\\Rules\\Ruleset;\nuse Doctrine\\Inflector\\Rules\\Substitutions;\nuse Doctrine\\Inflector\\Rules\\Transformations;\n\nfinal class Rules\n{\n    public static function getSingularRuleset(): Ruleset\n    {\n        return new Ruleset(\n            new Transformations(...Inflectible::getSingular()),\n            new Patterns(...Uninflected::getSingular()),\n            (new Substitutions(...Inflectible::getIrregular()))->getFlippedSubstitutions()\n        );\n    }\n\n    public static function getPluralRuleset(): Ruleset\n    {\n        return new Ruleset(\n            new Transformations(...Inflectible::getPlural()),\n            new Patterns(...Uninflected::getPlural()),\n            new Substitutions(...Inflectible::getIrregular())\n        );\n    }\n}\n"
  },
  {
    "path": "server/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Spanish/Uninflected.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Doctrine\\Inflector\\Rules\\Spanish;\n\nuse Doctrine\\Inflector\\Rules\\Pattern;\n\nfinal class Uninflected\n{\n    /** @return Pattern[] */\n    public static function getSingular(): iterable\n    {\n        yield from self::getDefault();\n    }\n\n    /** @return Pattern[] */\n    public static function getPlural(): iterable\n    {\n        yield from self::getDefault();\n    }\n\n    /** @return Pattern[] */\n    private static function getDefault(): iterable\n    {\n        yield new Pattern('lunes');\n        yield new Pattern('rompecabezas');\n        yield new Pattern('crisis');\n    }\n}\n"
  },
  {
    "path": "server/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Substitution.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Doctrine\\Inflector\\Rules;\n\nfinal class Substitution\n{\n    /** @var Word */\n    private $from;\n\n    /** @var Word */\n    private $to;\n\n    public function __construct(Word $from, Word $to)\n    {\n        $this->from = $from;\n        $this->to   = $to;\n    }\n\n    public function getFrom(): Word\n    {\n        return $this->from;\n    }\n\n    public function getTo(): Word\n    {\n        return $this->to;\n    }\n}\n"
  },
  {
    "path": "server/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Substitutions.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Doctrine\\Inflector\\Rules;\n\nuse Doctrine\\Inflector\\WordInflector;\n\nuse function strtolower;\nuse function strtoupper;\nuse function substr;\n\nclass Substitutions implements WordInflector\n{\n    /** @var Substitution[] */\n    private $substitutions;\n\n    public function __construct(Substitution ...$substitutions)\n    {\n        foreach ($substitutions as $substitution) {\n            $this->substitutions[$substitution->getFrom()->getWord()] = $substitution;\n        }\n    }\n\n    public function getFlippedSubstitutions(): Substitutions\n    {\n        $substitutions = [];\n\n        foreach ($this->substitutions as $substitution) {\n            $substitutions[] = new Substitution(\n                $substitution->getTo(),\n                $substitution->getFrom()\n            );\n        }\n\n        return new Substitutions(...$substitutions);\n    }\n\n    public function inflect(string $word): string\n    {\n        $lowerWord = strtolower($word);\n\n        if (isset($this->substitutions[$lowerWord])) {\n            $firstLetterUppercase = $lowerWord[0] !== $word[0];\n\n            $toWord = $this->substitutions[$lowerWord]->getTo()->getWord();\n\n            if ($firstLetterUppercase) {\n                return strtoupper($toWord[0]) . substr($toWord, 1);\n            }\n\n            return $toWord;\n        }\n\n        return $word;\n    }\n}\n"
  },
  {
    "path": "server/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Transformation.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Doctrine\\Inflector\\Rules;\n\nuse Doctrine\\Inflector\\WordInflector;\n\nuse function preg_replace;\n\nfinal class Transformation implements WordInflector\n{\n    /** @var Pattern */\n    private $pattern;\n\n    /** @var string */\n    private $replacement;\n\n    public function __construct(Pattern $pattern, string $replacement)\n    {\n        $this->pattern     = $pattern;\n        $this->replacement = $replacement;\n    }\n\n    public function getPattern(): Pattern\n    {\n        return $this->pattern;\n    }\n\n    public function getReplacement(): string\n    {\n        return $this->replacement;\n    }\n\n    public function inflect(string $word): string\n    {\n        return (string) preg_replace($this->pattern->getRegex(), $this->replacement, $word);\n    }\n}\n"
  },
  {
    "path": "server/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Transformations.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Doctrine\\Inflector\\Rules;\n\nuse Doctrine\\Inflector\\WordInflector;\n\nclass Transformations implements WordInflector\n{\n    /** @var Transformation[] */\n    private $transformations;\n\n    public function __construct(Transformation ...$transformations)\n    {\n        $this->transformations = $transformations;\n    }\n\n    public function inflect(string $word): string\n    {\n        foreach ($this->transformations as $transformation) {\n            if ($transformation->getPattern()->matches($word)) {\n                return $transformation->inflect($word);\n            }\n        }\n\n        return $word;\n    }\n}\n"
  },
  {
    "path": "server/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Turkish/Inflectible.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Doctrine\\Inflector\\Rules\\Turkish;\n\nuse Doctrine\\Inflector\\Rules\\Pattern;\nuse Doctrine\\Inflector\\Rules\\Substitution;\nuse Doctrine\\Inflector\\Rules\\Transformation;\nuse Doctrine\\Inflector\\Rules\\Word;\n\nclass Inflectible\n{\n    /** @return Transformation[] */\n    public static function getSingular(): iterable\n    {\n        yield new Transformation(new Pattern('/l[ae]r$/i'), '');\n    }\n\n    /** @return Transformation[] */\n    public static function getPlural(): iterable\n    {\n        yield new Transformation(new Pattern('/([eöiü][^aoıueöiü]{0,6})$/u'), '\\1ler');\n        yield new Transformation(new Pattern('/([aoıu][^aoıueöiü]{0,6})$/u'), '\\1lar');\n    }\n\n    /** @return Substitution[] */\n    public static function getIrregular(): iterable\n    {\n        yield new Substitution(new Word('ben'), new Word('biz'));\n        yield new Substitution(new Word('sen'), new Word('siz'));\n        yield new Substitution(new Word('o'), new Word('onlar'));\n    }\n}\n"
  },
  {
    "path": "server/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Turkish/InflectorFactory.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Doctrine\\Inflector\\Rules\\Turkish;\n\nuse Doctrine\\Inflector\\GenericLanguageInflectorFactory;\nuse Doctrine\\Inflector\\Rules\\Ruleset;\n\nfinal class InflectorFactory extends GenericLanguageInflectorFactory\n{\n    protected function getSingularRuleset(): Ruleset\n    {\n        return Rules::getSingularRuleset();\n    }\n\n    protected function getPluralRuleset(): Ruleset\n    {\n        return Rules::getPluralRuleset();\n    }\n}\n"
  },
  {
    "path": "server/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Turkish/Rules.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Doctrine\\Inflector\\Rules\\Turkish;\n\nuse Doctrine\\Inflector\\Rules\\Patterns;\nuse Doctrine\\Inflector\\Rules\\Ruleset;\nuse Doctrine\\Inflector\\Rules\\Substitutions;\nuse Doctrine\\Inflector\\Rules\\Transformations;\n\nfinal class Rules\n{\n    public static function getSingularRuleset(): Ruleset\n    {\n        return new Ruleset(\n            new Transformations(...Inflectible::getSingular()),\n            new Patterns(...Uninflected::getSingular()),\n            (new Substitutions(...Inflectible::getIrregular()))->getFlippedSubstitutions()\n        );\n    }\n\n    public static function getPluralRuleset(): Ruleset\n    {\n        return new Ruleset(\n            new Transformations(...Inflectible::getPlural()),\n            new Patterns(...Uninflected::getPlural()),\n            new Substitutions(...Inflectible::getIrregular())\n        );\n    }\n}\n"
  },
  {
    "path": "server/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Turkish/Uninflected.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Doctrine\\Inflector\\Rules\\Turkish;\n\nuse Doctrine\\Inflector\\Rules\\Pattern;\n\nfinal class Uninflected\n{\n    /** @return Pattern[] */\n    public static function getSingular(): iterable\n    {\n        yield from self::getDefault();\n    }\n\n    /** @return Pattern[] */\n    public static function getPlural(): iterable\n    {\n        yield from self::getDefault();\n    }\n\n    /** @return Pattern[] */\n    private static function getDefault(): iterable\n    {\n        yield new Pattern('lunes');\n        yield new Pattern('rompecabezas');\n        yield new Pattern('crisis');\n    }\n}\n"
  },
  {
    "path": "server/vendor/doctrine/inflector/lib/Doctrine/Inflector/Rules/Word.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Doctrine\\Inflector\\Rules;\n\nclass Word\n{\n    /** @var string */\n    private $word;\n\n    public function __construct(string $word)\n    {\n        $this->word = $word;\n    }\n\n    public function getWord(): string\n    {\n        return $this->word;\n    }\n}\n"
  },
  {
    "path": "server/vendor/doctrine/inflector/lib/Doctrine/Inflector/RulesetInflector.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Doctrine\\Inflector;\n\nuse Doctrine\\Inflector\\Rules\\Ruleset;\n\nuse function array_merge;\n\n/**\n * Inflects based on multiple rulesets.\n *\n * Rules:\n * - If the word matches any uninflected word pattern, it is not inflected\n * - The first ruleset that returns a different value for an irregular word wins\n * - The first ruleset that returns a different value for a regular word wins\n * - If none of the above match, the word is left as-is\n */\nclass RulesetInflector implements WordInflector\n{\n    /** @var Ruleset[] */\n    private $rulesets;\n\n    public function __construct(Ruleset $ruleset, Ruleset ...$rulesets)\n    {\n        $this->rulesets = array_merge([$ruleset], $rulesets);\n    }\n\n    public function inflect(string $word): string\n    {\n        if ($word === '') {\n            return '';\n        }\n\n        foreach ($this->rulesets as $ruleset) {\n            if ($ruleset->getUninflected()->matches($word)) {\n                return $word;\n            }\n\n            $inflected = $ruleset->getIrregular()->inflect($word);\n\n            if ($inflected !== $word) {\n                return $inflected;\n            }\n\n            $inflected = $ruleset->getRegular()->inflect($word);\n\n            if ($inflected !== $word) {\n                return $inflected;\n            }\n        }\n\n        return $word;\n    }\n}\n"
  },
  {
    "path": "server/vendor/doctrine/inflector/lib/Doctrine/Inflector/WordInflector.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Doctrine\\Inflector;\n\ninterface WordInflector\n{\n    public function inflect(string $word): string;\n}\n"
  },
  {
    "path": "server/vendor/graham-campbell/result-type/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2020-2023 Graham Campbell <hello@gjcampbell.co.uk>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "server/vendor/graham-campbell/result-type/composer.json",
    "content": "{\n    \"name\": \"graham-campbell/result-type\",\n    \"description\": \"An Implementation Of The Result Type\",\n    \"keywords\": [\"result\", \"result-type\", \"Result\", \"Result Type\", \"Result-Type\", \"Graham Campbell\", \"GrahamCampbell\"],\n    \"license\": \"MIT\",\n    \"authors\": [\n        {\n            \"name\": \"Graham Campbell\",\n            \"email\": \"hello@gjcampbell.co.uk\",\n            \"homepage\": \"https://github.com/GrahamCampbell\"\n        }\n    ],\n    \"require\": {\n        \"php\": \"^7.2.5 || ^8.0\",\n        \"phpoption/phpoption\": \"^1.9.2\"\n    },\n    \"require-dev\": {\n        \"phpunit/phpunit\": \"^8.5.34 || ^9.6.13 || ^10.4.2\"\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"GrahamCampbell\\\\ResultType\\\\\": \"src/\"\n        }\n    },\n    \"autoload-dev\": {\n        \"psr-4\": {\n            \"GrahamCampbell\\\\Tests\\\\ResultType\\\\\": \"tests/\"\n        }\n    },\n    \"config\": {\n        \"preferred-install\": \"dist\"\n    }\n}\n"
  },
  {
    "path": "server/vendor/graham-campbell/result-type/src/Error.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\n/*\n * This file is part of Result Type.\n *\n * (c) Graham Campbell <hello@gjcampbell.co.uk>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace GrahamCampbell\\ResultType;\n\nuse PhpOption\\None;\nuse PhpOption\\Some;\n\n/**\n * @template T\n * @template E\n *\n * @extends \\GrahamCampbell\\ResultType\\Result<T,E>\n */\nfinal class Error extends Result\n{\n    /**\n     * @var E\n     */\n    private $value;\n\n    /**\n     * Internal constructor for an error value.\n     *\n     * @param E $value\n     *\n     * @return void\n     */\n    private function __construct($value)\n    {\n        $this->value = $value;\n    }\n\n    /**\n     * Create a new error value.\n     *\n     * @template F\n     *\n     * @param F $value\n     *\n     * @return \\GrahamCampbell\\ResultType\\Result<T,F>\n     */\n    public static function create($value)\n    {\n        return new self($value);\n    }\n\n    /**\n     * Get the success option value.\n     *\n     * @return \\PhpOption\\Option<T>\n     */\n    public function success()\n    {\n        return None::create();\n    }\n\n    /**\n     * Map over the success value.\n     *\n     * @template S\n     *\n     * @param callable(T):S $f\n     *\n     * @return \\GrahamCampbell\\ResultType\\Result<S,E>\n     */\n    public function map(callable $f)\n    {\n        return self::create($this->value);\n    }\n\n    /**\n     * Flat map over the success value.\n     *\n     * @template S\n     * @template F\n     *\n     * @param callable(T):\\GrahamCampbell\\ResultType\\Result<S,F> $f\n     *\n     * @return \\GrahamCampbell\\ResultType\\Result<S,F>\n     */\n    public function flatMap(callable $f)\n    {\n        /** @var \\GrahamCampbell\\ResultType\\Result<S,F> */\n        return self::create($this->value);\n    }\n\n    /**\n     * Get the error option value.\n     *\n     * @return \\PhpOption\\Option<E>\n     */\n    public function error()\n    {\n        return Some::create($this->value);\n    }\n\n    /**\n     * Map over the error value.\n     *\n     * @template F\n     *\n     * @param callable(E):F $f\n     *\n     * @return \\GrahamCampbell\\ResultType\\Result<T,F>\n     */\n    public function mapError(callable $f)\n    {\n        return self::create($f($this->value));\n    }\n}\n"
  },
  {
    "path": "server/vendor/graham-campbell/result-type/src/Result.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\n/*\n * This file is part of Result Type.\n *\n * (c) Graham Campbell <hello@gjcampbell.co.uk>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace GrahamCampbell\\ResultType;\n\n/**\n * @template T\n * @template E\n */\nabstract class Result\n{\n    /**\n     * Get the success option value.\n     *\n     * @return \\PhpOption\\Option<T>\n     */\n    abstract public function success();\n\n    /**\n     * Map over the success value.\n     *\n     * @template S\n     *\n     * @param callable(T):S $f\n     *\n     * @return \\GrahamCampbell\\ResultType\\Result<S,E>\n     */\n    abstract public function map(callable $f);\n\n    /**\n     * Flat map over the success value.\n     *\n     * @template S\n     * @template F\n     *\n     * @param callable(T):\\GrahamCampbell\\ResultType\\Result<S,F> $f\n     *\n     * @return \\GrahamCampbell\\ResultType\\Result<S,F>\n     */\n    abstract public function flatMap(callable $f);\n\n    /**\n     * Get the error option value.\n     *\n     * @return \\PhpOption\\Option<E>\n     */\n    abstract public function error();\n\n    /**\n     * Map over the error value.\n     *\n     * @template F\n     *\n     * @param callable(E):F $f\n     *\n     * @return \\GrahamCampbell\\ResultType\\Result<T,F>\n     */\n    abstract public function mapError(callable $f);\n}\n"
  },
  {
    "path": "server/vendor/graham-campbell/result-type/src/Success.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\n/*\n * This file is part of Result Type.\n *\n * (c) Graham Campbell <hello@gjcampbell.co.uk>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace GrahamCampbell\\ResultType;\n\nuse PhpOption\\None;\nuse PhpOption\\Some;\n\n/**\n * @template T\n * @template E\n *\n * @extends \\GrahamCampbell\\ResultType\\Result<T,E>\n */\nfinal class Success extends Result\n{\n    /**\n     * @var T\n     */\n    private $value;\n\n    /**\n     * Internal constructor for a success value.\n     *\n     * @param T $value\n     *\n     * @return void\n     */\n    private function __construct($value)\n    {\n        $this->value = $value;\n    }\n\n    /**\n     * Create a new error value.\n     *\n     * @template S\n     *\n     * @param S $value\n     *\n     * @return \\GrahamCampbell\\ResultType\\Result<S,E>\n     */\n    public static function create($value)\n    {\n        return new self($value);\n    }\n\n    /**\n     * Get the success option value.\n     *\n     * @return \\PhpOption\\Option<T>\n     */\n    public function success()\n    {\n        return Some::create($this->value);\n    }\n\n    /**\n     * Map over the success value.\n     *\n     * @template S\n     *\n     * @param callable(T):S $f\n     *\n     * @return \\GrahamCampbell\\ResultType\\Result<S,E>\n     */\n    public function map(callable $f)\n    {\n        return self::create($f($this->value));\n    }\n\n    /**\n     * Flat map over the success value.\n     *\n     * @template S\n     * @template F\n     *\n     * @param callable(T):\\GrahamCampbell\\ResultType\\Result<S,F> $f\n     *\n     * @return \\GrahamCampbell\\ResultType\\Result<S,F>\n     */\n    public function flatMap(callable $f)\n    {\n        return $f($this->value);\n    }\n\n    /**\n     * Get the error option value.\n     *\n     * @return \\PhpOption\\Option<E>\n     */\n    public function error()\n    {\n        return None::create();\n    }\n\n    /**\n     * Map over the error value.\n     *\n     * @template F\n     *\n     * @param callable(E):F $f\n     *\n     * @return \\GrahamCampbell\\ResultType\\Result<T,F>\n     */\n    public function mapError(callable $f)\n    {\n        return self::create($this->value);\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/command/LICENSE",
    "content": "Copyright (c) 2015 Michael Dowling, https://github.com/mtdowling <mtdowling@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "server/vendor/guzzlehttp/command/README.md",
    "content": "# Guzzle Commands\n\n[![License](https://poser.pugx.org/guzzlehttp/command/license)](https://packagist.org/packages/guzzlehttp/command)\n[![Build Status](https://travis-ci.org/guzzle/command.svg?branch=master)](https://travis-ci.org/guzzle/command) \n[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/guzzle/command/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/guzzle/command/?branch=master) \n[![Code Coverage](https://scrutinizer-ci.com/g/guzzle/command/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/guzzle/command/?branch=master) \n[![SensioLabsInsight](https://insight.sensiolabs.com/projects/7a93338e-50cd-42f7-9299-17c44d92148f/mini.png)](https://insight.sensiolabs.com/projects/7a93338e-50cd-42f7-9299-17c44d92148f)\n[![Latest Stable Version](https://poser.pugx.org/guzzlehttp/command/v/stable)](https://packagist.org/packages/guzzlehttp/command)\n[![Latest Unstable Version](https://poser.pugx.org/guzzlehttp/command/v/unstable)](https://packagist.org/packages/guzzlehttp/command)\n[![Total Downloads](https://poser.pugx.org/guzzlehttp/command/downloads)](https://packagist.org/packages/guzzlehttp/command)\n\nThis library uses Guzzle (``guzzlehttp/guzzle``, version 6.x) and provides the\nfoundations to create fully-featured web service clients by abstracting Guzzle\nHTTP **requests** and **responses** into higher-level **commands** and\n**results**. A **middleware** system, analogous to — but separate from — the one\nin the HTTP layer may be used to customize client behavior when preparing\ncommands into requests and processing responses into results.\n\n### Commands\n    \nKey-value pair objects representing an operation of a web service. Commands have a name and a set of parameters.\n\n### Results\n\nKey-value pair objects representing the processed result of executing an operation of a web service.\n\n## Installing\n\nThis project can be installed using Composer:\n\n``composer require guzzlehttp/command``\n\nFor **Guzzle 5**, use ``composer require guzzlehttp/command:0.8.*``. The source\ncode for the Guzzle 5 version is available on the\n`0.8 branch <https://github.com/guzzle/command/tree/0.8>`_.\n\n**Note:** If Composer is not\n`installed globally <https://getcomposer.org/doc/00-intro.md#globally>`_,\nthen you may need to run the preceding Composer commands using\n``php composer.phar`` (where ``composer.phar`` is the path to your copy of\nComposer), instead of just ``composer``.\n\n## Service Clients\n\nService Clients are web service clients that implement the\n``GuzzleHttp\\Command\\ServiceClientInterface`` and use an underlying Guzzle HTTP\nclient (``GuzzleHttp\\Client``) to communicate with the service. Service clients\ncreate and execute **commands** (``GuzzleHttp\\Command\\CommandInterface``),\nwhich encapsulate operations within the web service, including the operation\nname and parameters. This library provides a generic implementation of a service\nclient: the ``GuzzleHttp\\Command\\ServiceClient`` class.\n\n## Instantiating a Service Client\n\n@TODO Add documentation\n\n* ``ServiceClient``'s constructor\n* Transformer functions (``$commandToRequestTransformer`` and ``$responseToResultTransformer``)\n* The ``HandlerStack``\n\n## Executing Commands\n\nService clients create command objects using the ``getCommand()`` method.\n\n```php\n$commandName = 'foo';\n$arguments = ['baz' => 'bar'];\n$command = $client->getCommand($commandName, $arguments);\n\n```\n\nAfter creating a command, you may execute the command using the ``execute()``\nmethod of the client.\n\n```php\n$result = $client->execute($command);\n```\n\nThe result of executing a command will be a ``GuzzleHttp\\Command\\ResultInterface``\nobject. Result objects are ``ArrayAccess``-ible and contain the data parsed from\nHTTP response.\n\nService clients have magic methods that act as shortcuts to executing commands\nby name without having to create the ``Command`` object in a separate step\nbefore executing it.\n\n```php\n$result = $client->foo(['baz' => 'bar']);\n```\n\n## Asynchronous Commands\n\n@TODO Add documentation\n\n* ``-Async`` suffix for client methods\n* Promises\n\n```php\n// Create and execute an asynchronous command.\n$command = $command = $client->getCommand('foo', ['baz' => 'bar']);\n$promise = $client->executeAsync($command);\n\n// Use asynchronous commands with magic methods.\n$promise = $client->fooAsync(['baz' => 'bar']);\n```\n\n@TODO Add documentation\n\n* ``wait()``-ing on promises.\n\n```php\n$result = $promise->wait();\n\necho $result['fizz']; //> 'buzz' \n```\n\n## Concurrent Requests\n\n@TODO Add documentation\n\n* ``executeAll()``\n* ``executeAllAsync()``.\n* Options (``fulfilled``, ``rejected``, ``concurrency``)\n\n## Middleware: Extending the Client\n\nMiddleware can be added to the service client or underlying HTTP client to\nimplement additional behavior and customize the ``Command``-to-``Result`` and\n``Request``-to-``Response`` lifecycles, respectively.\n\n## Todo\n\n* Middleware system and command vs request layers\n* The ``HandlerStack``\n"
  },
  {
    "path": "server/vendor/guzzlehttp/command/composer.json",
    "content": "{\n    \"name\": \"guzzlehttp/command\",\n    \"description\": \"Provides the foundation for building command-based web service clients\",\n    \"license\": \"MIT\",\n    \"authors\": [\n        {\n            \"name\": \"Michael Dowling\",\n            \"email\": \"mtdowling@gmail.com\",\n            \"homepage\": \"https://github.com/mtdowling\"\n        },\n        {\n            \"name\": \"Jeremy Lindblom\",\n            \"email\": \"jeremeamia@gmail.com\",\n            \"homepage\": \"https://github.com/jeremeamia\"\n        }\n    ],\n    \"require\": {\n        \"php\": \">=5.5.0\",\n        \"guzzlehttp/guzzle\": \"^6.2\",\n        \"guzzlehttp/promises\": \"~1.3\",\n        \"guzzlehttp/psr7\": \"~1.0\"\n    },\n    \"require-dev\": {\n        \"phpunit/phpunit\": \"~4.0|~5.0\"\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"GuzzleHttp\\\\Command\\\\\": \"src/\"\n        }\n    },\n    \"extra\": {\n        \"branch-alias\": {\n            \"dev-master\": \"0.9-dev\"\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/command/src/Command.php",
    "content": "<?php\nnamespace GuzzleHttp\\Command;\n\nuse GuzzleHttp\\HandlerStack;\n\n/**\n * Default command implementation.\n */\nclass Command implements CommandInterface\n{\n    use HasDataTrait;\n\n    /** @var string */\n    private $name;\n\n    /** @var HandlerStack */\n    private $handlerStack;\n\n    /**\n     * @param string       $name         Name of the command\n     * @param array        $args         Arguments to pass to the command\n     * @param HandlerStack $handlerStack Stack of middleware for the command\n     */\n    public function __construct(\n        $name,\n        array $args = [],\n        HandlerStack $handlerStack = null\n    ) {\n        $this->name = $name;\n        $this->data = $args;\n        $this->handlerStack = $handlerStack;\n    }\n\n    public function getHandlerStack()\n    {\n        return $this->handlerStack;\n    }\n\n    public function getName()\n    {\n        return $this->name;\n    }\n\n    public function hasParam($name)\n    {\n        return array_key_exists($name, $this->data);\n    }\n\n    public function __clone()\n    {\n        if ($this->handlerStack) {\n            $this->handlerStack = clone $this->handlerStack;\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/command/src/CommandInterface.php",
    "content": "<?php\nnamespace GuzzleHttp\\Command;\n\nuse GuzzleHttp\\HandlerStack;\n\n/**\n * A command object encapsulates the input parameters used to control the\n * creation of a HTTP request and processing of a HTTP response.\n *\n * Using the getParams() method will return the input parameters of the command\n * as an associative array.\n */\ninterface CommandInterface extends \\ArrayAccess, \\IteratorAggregate, \\Countable, ToArrayInterface\n{\n    /**\n     * Retrieves the handler stack specific to this command's execution.\n     *\n     * This can be used to add middleware that is specific to the command instance.\n     *\n     * @return HandlerStack\n     */\n    public function getHandlerStack();\n\n    /**\n     * Get the name of the command.\n     *\n     * @return string\n     */\n    public function getName();\n\n    /**\n     * Check if the command has a parameter by name.\n     *\n     * @param string $name Name of the parameter to check.\n     *\n     * @return bool\n     */\n    public function hasParam($name);\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/command/src/Exception/CommandClientException.php",
    "content": "<?php\nnamespace GuzzleHttp\\Command\\Exception;\n\n/**\n * Exception encountered when a 4xx level response is received for a request\n */\nclass CommandClientException extends CommandException {}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/command/src/Exception/CommandException.php",
    "content": "<?php\nnamespace GuzzleHttp\\Command\\Exception;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse GuzzleHttp\\Exception\\RequestException;\nuse GuzzleHttp\\Command\\CommandInterface;\nuse Psr\\Http\\Message\\RequestInterface;\nuse Psr\\Http\\Message\\ResponseInterface;\n\n/**\n * Exception encountered while executing a command.\n */\nclass CommandException extends \\RuntimeException implements GuzzleException\n{\n    /** @var CommandInterface */\n    private $command;\n\n    /** @var RequestInterface */\n    private $request;\n\n    /** @var ResponseInterface */\n    private $response;\n\n    /**\n     * @param CommandInterface $command\n     * @param \\Exception $prev\n     * @return CommandException\n     */\n    public static function fromPrevious(CommandInterface $command, \\Exception $prev)\n    {\n        // If the exception is already a command exception, return it.\n        if ($prev instanceof self && $command === $prev->getCommand()) {\n            return $prev;\n        }\n\n        // If the exception is a RequestException, get the Request and Response.\n        $request = $response = null;\n        if ($prev instanceof RequestException) {\n            $request = $prev->getRequest();\n            $response = $prev->getResponse();\n        }\n\n        // Throw a more specific exception for 4XX or 5XX responses.\n        $class = self::class;\n        $statusCode = $response ? $response->getStatusCode() : 0;\n        if ($statusCode >= 400 && $statusCode < 500) {\n            $class = CommandClientException::class;\n        } elseif ($statusCode >= 500 && $statusCode < 600) {\n            $class = CommandServerException::class;\n        }\n\n        // Prepare the message.\n        $message = 'There was an error executing the ' . $command->getName()\n            . ' command: ' . $prev->getMessage();\n\n        // Create the exception.\n        return new $class($message, $command, $prev, $request, $response);\n    }\n\n    /**\n     * @param string $message Exception message\n     * @param CommandInterface $command\n     * @param \\Exception $previous Previous exception (if any)\n     * @param RequestInterface $request\n     * @param ResponseInterface $response\n     */\n    public function __construct(\n        $message,\n        CommandInterface $command,\n        \\Exception $previous = null,\n        RequestInterface $request = null,\n        ResponseInterface $response = null\n    ) {\n        $this->command = $command;\n        $this->request = $request;\n        $this->response = $response;\n        parent::__construct($message, 0, $previous);\n    }\n\n    /**\n     * Gets the command that failed.\n     *\n     * @return CommandInterface\n     */\n    public function getCommand()\n    {\n        return $this->command;\n    }\n\n    /**\n     * Gets the request that caused the exception\n     *\n     * @return RequestInterface|null\n     */\n    public function getRequest()\n    {\n        return $this->request;\n    }\n\n    /**\n     * Gets the associated response\n     *\n     * @return ResponseInterface|null\n     */\n    public function getResponse()\n    {\n        return $this->response;\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/command/src/Exception/CommandServerException.php",
    "content": "<?php\nnamespace GuzzleHttp\\Command\\Exception;\n\n/**\n * Exception encountered when a 5xx level response is received for a request\n */\nclass CommandServerException extends CommandException {}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/command/src/HasDataTrait.php",
    "content": "<?php\n\nnamespace GuzzleHttp\\Command;\n\n/**\n * Basic collection behavior for Command and Result objects.\n *\n * The methods in the class are primarily for implementing the ArrayAccess,\n * Countable, and IteratorAggregate interfaces.\n */\ntrait HasDataTrait\n{\n    /** @var array Data stored in the collection. */\n    protected $data;\n\n    public function __toString()\n    {\n        return print_r($this, true);\n    }\n\n    public function __debugInfo()\n    {\n        return $this->data;\n    }\n\n    public function offsetExists($offset)\n    {\n        return array_key_exists($offset, $this->data);\n    }\n\n    public function offsetGet($offset)\n    {\n        return isset($this->data[$offset]) ? $this->data[$offset] : null;\n    }\n\n    public function offsetSet($offset, $value)\n    {\n        $this->data[$offset] = $value;\n    }\n\n    public function offsetUnset($offset)\n    {\n        unset($this->data[$offset]);\n    }\n\n    public function count()\n    {\n        return count($this->data);\n    }\n\n    public function getIterator()\n    {\n        return new \\ArrayIterator($this->data);\n    }\n\n    public function toArray()\n    {\n        return $this->data;\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/command/src/Result.php",
    "content": "<?php\nnamespace GuzzleHttp\\Command;\n\n/**\n * Default command implementation.\n */\nclass Result implements ResultInterface\n{\n    use HasDataTrait;\n\n    /**\n     * @param array $data\n     */\n    public function __construct(array $data = [])\n    {\n        $this->data = $data;\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/command/src/ResultInterface.php",
    "content": "<?php\nnamespace GuzzleHttp\\Command;\n\n/**\n * An array-like object that represents the result of executing a command.\n */\ninterface ResultInterface extends \\ArrayAccess, \\IteratorAggregate, \\Countable, ToArrayInterface\n{\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/command/src/ServiceClient.php",
    "content": "<?php\nnamespace GuzzleHttp\\Command;\n\nuse GuzzleHttp\\ClientInterface as HttpClient;\nuse GuzzleHttp\\Command\\Exception\\CommandException;\nuse GuzzleHttp\\HandlerStack;\nuse GuzzleHttp\\Promise;\nuse GuzzleHttp\\Promise\\PromiseInterface;\nuse Psr\\Http\\Message\\RequestInterface;\nuse Psr\\Http\\Message\\ResponseInterface;\n\n/**\n * The Guzzle ServiceClient serves as the foundation for creating web service\n * clients that interact with RPC-style APIs.\n */\nclass ServiceClient implements ServiceClientInterface\n{\n    /** @var HttpClient HTTP client used to send requests */\n    private $httpClient;\n\n    /** @var HandlerStack */\n    private $handlerStack;\n    \n    /** @var callable */\n    private $commandToRequestTransformer;\n\n    /** @var callable */\n    private $responseToResultTransformer;\n\n    /**\n     * Instantiates a Guzzle ServiceClient for making requests to a web service.\n     *\n     * @param HttpClient $httpClient A fully-configured Guzzle HTTP client that\n     *     will be used to perform the underlying HTTP requests.\n     * @param callable $commandToRequestTransformer A callable that transforms\n     *     a Command into a Request. The function should accept a\n     *     `GuzzleHttp\\Command\\CommandInterface` object and return a\n     *     `Psr\\Http\\Message\\RequestInterface` object.\n     * @param callable $responseToResultTransformer A callable that transforms a\n     *     Response into a Result. The function should accept a\n     *     `Psr\\Http\\Message\\ResponseInterface` object (and optionally a\n     *     `Psr\\Http\\Message\\RequestInterface` object) and return a\n     *     `GuzzleHttp\\Command\\ResultInterface` object.\n     * @param HandlerStack $commandHandlerStack A Guzzle HandlerStack, which can\n     *     be used to add command-level middleware to the service client.\n     */\n    public function __construct(\n        HttpClient $httpClient,\n        callable $commandToRequestTransformer,\n        callable $responseToResultTransformer,\n        HandlerStack $commandHandlerStack = null\n    ) {\n        $this->httpClient = $httpClient;\n        $this->commandToRequestTransformer = $commandToRequestTransformer;\n        $this->responseToResultTransformer = $responseToResultTransformer;\n        $this->handlerStack = $commandHandlerStack ?: new HandlerStack();\n        $this->handlerStack->setHandler($this->createCommandHandler());\n    }\n\n    public function getHttpClient()\n    {\n        return $this->httpClient;\n    }\n\n    public function getHandlerStack()\n    {\n        return $this->handlerStack;\n    }\n\n    public function getCommand($name, array $params = [])\n    {\n        return new Command($name, $params, clone $this->handlerStack);\n    }\n\n    public function execute(CommandInterface $command)\n    {\n        return $this->executeAsync($command)->wait();\n    }\n\n    public function executeAsync(CommandInterface $command)\n    {\n        $stack = $command->getHandlerStack() ?: $this->handlerStack;\n        $handler = $stack->resolve();\n\n        return $handler($command);\n    }\n\n    public function executeAll($commands, array $options = [])\n    {\n        // Modify provided callbacks to track results.\n        $results = [];\n        $options['fulfilled'] = function ($v, $k) use (&$results, $options) {\n            if (isset($options['fulfilled'])) {\n                $options['fulfilled']($v, $k);\n            }\n            $results[$k] = $v;\n        };\n        $options['rejected'] = function ($v, $k) use (&$results, $options) {\n            if (isset($options['rejected'])) {\n                $options['rejected']($v, $k);\n            }\n            $results[$k] = $v;\n        };\n\n        // Execute multiple commands synchronously, then sort and return the results.\n        return $this->executeAllAsync($commands, $options)\n            ->then(function () use (&$results) {\n                ksort($results);\n                return $results;\n            })\n            ->wait();\n    }\n\n    public function executeAllAsync($commands, array $options = [])\n    {\n        // Apply default concurrency.\n        if (!isset($options['concurrency'])) {\n            $options['concurrency'] = 25;\n        }\n\n        // Convert the iterator of commands to a generator of promises.\n        $commands = Promise\\iter_for($commands);\n        $promises = function () use ($commands) {\n            foreach ($commands as $key => $command) {\n                if (!$command instanceof CommandInterface) {\n                    throw new \\InvalidArgumentException('The iterator must '\n                        . 'yield instances of ' . CommandInterface::class);\n                }\n                yield $key => $this->executeAsync($command);\n            }\n        };\n\n        // Execute the commands using a pool.\n        return (new Promise\\EachPromise($promises(), $options))->promise();\n    }\n\n    /**\n     * Creates and executes a command for an operation by name.\n     *\n     * @param string $name Name of the command to execute.\n     * @param array $args Arguments to pass to the getCommand method.\n     *\n     * @return ResultInterface|PromiseInterface\n     * @see \\GuzzleHttp\\Command\\ServiceClientInterface::getCommand\n     */\n    public function __call($name, array $args)\n    {\n        $args = isset($args[0]) ? $args[0] : [];\n        if (substr($name, -5) === 'Async') {\n            $command = $this->getCommand(substr($name, 0, -5), $args);\n            return $this->executeAsync($command);\n        } else {\n            return $this->execute($this->getCommand($name, $args));\n        }\n    }\n\n    /**\n     * Defines the main handler for commands that uses the HTTP client.\n     *\n     * @return callable\n     */\n    private function createCommandHandler()\n    {\n        return function (CommandInterface $command) {\n            return Promise\\coroutine(function () use ($command) {\n                // Prepare the HTTP options.\n                $opts = $command['@http'] ?: [];\n                unset($command['@http']);\n\n                try {\n                    // Prepare the request from the command and send it.\n                    $request = $this->transformCommandToRequest($command);\n                    $promise = $this->httpClient->sendAsync($request, $opts);\n\n                    // Create a result from the response.\n                    $response = (yield $promise);\n                    yield $this->transformResponseToResult($response, $request, $command);\n                } catch (\\Exception $e) {\n                    throw CommandException::fromPrevious($command, $e);\n                }\n            });\n        };\n    }\n\n    /**\n     * Transforms a Command object into a Request object.\n     *\n     * @param CommandInterface $command\n     * @return RequestInterface\n     */\n    private function transformCommandToRequest(CommandInterface $command)\n    {\n        $transform = $this->commandToRequestTransformer;\n\n        return $transform($command);\n    }\n\n\n    /**\n     * Transforms a Response object, also using data from the Request object,\n     * into a Result object.\n     *\n     * @param ResponseInterface $response\n     * @param RequestInterface $request\n     * @param CommandInterface $command\n     * @return ResultInterface\n     */\n    private function transformResponseToResult(\n        ResponseInterface $response,\n        RequestInterface $request,\n        CommandInterface $command\n    ) {\n        $transform = $this->responseToResultTransformer;\n\n        return $transform($response, $request, $command);\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/command/src/ServiceClientInterface.php",
    "content": "<?php\nnamespace GuzzleHttp\\Command;\n\nuse GuzzleHttp\\ClientInterface;\nuse GuzzleHttp\\Command\\Exception\\CommandException;\nuse GuzzleHttp\\HandlerStack;\nuse GuzzleHttp\\Promise\\PromiseInterface;\n\n/**\n * Web service client interface.\n */\ninterface ServiceClientInterface\n{\n    /**\n     * Create a command for an operation name.\n     *\n     * Special keys may be set on the command to control how it behaves.\n     * Implementations SHOULD be able to utilize the following keys or throw\n     * an exception if unable.\n     *\n     * @param string $name Name of the operation to use in the command\n     * @param array  $args Arguments to pass to the command\n     *\n     * @return CommandInterface\n     * @throws \\InvalidArgumentException if no command can be found by name\n     */\n    public function getCommand($name, array $args = []);\n\n    /**\n     * Execute a single command.\n     *\n     * @param CommandInterface $command Command to execute\n     *\n     * @return ResultInterface The result of the executed command\n     * @throws CommandException\n     */\n    public function execute(CommandInterface $command);\n\n    /**\n     * Execute a single command asynchronously\n     *\n     * @param CommandInterface $command Command to execute\n     *\n     * @return PromiseInterface A Promise that resolves to a Result.\n     */\n    public function executeAsync(CommandInterface $command);\n\n    /**\n     * Executes multiple commands concurrently using a fixed pool size.\n     *\n     * @param array|\\Iterator $commands Array or iterator that contains\n     *     CommandInterface objects to execute with the client.\n     * @param array $options Associative array of options to apply.\n     *     - concurrency: (int) Max number of commands to execute concurrently.\n     *     - fulfilled: (callable) Function to invoke when a command completes.\n     *     - rejected: (callable) Function to invoke when a command fails.\n     *\n     * @return array\n     * @see GuzzleHttp\\Command\\ServiceClientInterface::createPool for options.\n     */\n    public function executeAll($commands, array $options = []);\n\n    /**\n     * Executes multiple commands concurrently and asynchronously using a\n     * fixed pool size.\n     *\n     * @param array|\\Iterator $commands Array or iterator that contains\n     *     CommandInterface objects to execute with the client.\n     * @param array $options Associative array of options to apply.\n     *     - concurrency: (int) Max number of commands to execute concurrently.\n     *     - fulfilled: (callable) Function to invoke when a command completes.\n     *     - rejected: (callable) Function to invoke when a command fails.\n     *\n     * @return PromiseInterface\n     * @see GuzzleHttp\\Command\\ServiceClientInterface::createPool for options.\n     */\n    public function executeAllAsync($commands, array $options = []);\n\n    /**\n     * Get the HTTP client used to send requests for the web service client\n     *\n     * @return ClientInterface\n     */\n    public function getHttpClient();\n\n    /**\n     * Get the HandlerStack which can be used to add middleware to the client.\n     *\n     * @return HandlerStack\n     */\n    public function getHandlerStack();\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/command/src/ToArrayInterface.php",
    "content": "<?php\n\nnamespace GuzzleHttp\\Command;\n\n/**\n * An object that can be represented as an array\n */\ninterface ToArrayInterface\n{\n    /**\n     * Get the array representation of an object\n     *\n     * @return array\n     */\n    public function toArray();\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/guzzle/.php_cs",
    "content": "<?php\n\n$config = PhpCsFixer\\Config::create()\n    ->setRiskyAllowed(true)\n    ->setRules([\n        '@PSR2' => true,\n        'array_syntax' => ['syntax' => 'short'],\n        'declare_strict_types' => false,\n        'concat_space' => ['spacing'=>'one'],\n        'php_unit_test_case_static_method_calls' => ['call_type' => 'self'],\n        'ordered_imports' => true,\n        // 'phpdoc_align' => ['align'=>'vertical'],\n        // 'native_function_invocation' => true,\n    ])\n    ->setFinder(\n        PhpCsFixer\\Finder::create()\n            ->in(__DIR__.'/src')\n            ->in(__DIR__.'/tests')\n            ->name('*.php')\n    )\n;\n\nreturn $config;\n"
  },
  {
    "path": "server/vendor/guzzlehttp/guzzle/CHANGELOG.md",
    "content": "# Change Log\n\n## 6.5.8 - 2022-06-20\n\n* Fix change in port should be considered a change in origin\n* Fix `CURLOPT_HTTPAUTH` option not cleared on change of origin\n\n## 6.5.7 - 2022-06-09\n\n* Fix failure to strip Authorization header on HTTP downgrade\n* Fix failure to strip the Cookie header on change in host or HTTP downgrade\n\n## 6.5.6 - 2022-05-25\n\n* Fix cross-domain cookie leakage\n\n## 6.5.5 - 2020-06-16\n\n* Unpin version constraint for `symfony/polyfill-intl-idn` [#2678](https://github.com/guzzle/guzzle/pull/2678)\n\n## 6.5.4 - 2020-05-25\n\n* Fix various intl icu issues [#2626](https://github.com/guzzle/guzzle/pull/2626)\n\n## 6.5.3 - 2020-04-18\n\n* Use Symfony intl-idn polyfill [#2550](https://github.com/guzzle/guzzle/pull/2550)\n* Remove use of internal functions [#2548](https://github.com/guzzle/guzzle/pull/2548)\n\n## 6.5.2 - 2019-12-23\n\n* idn_to_ascii() fix for old PHP versions [#2489](https://github.com/guzzle/guzzle/pull/2489)\n\n## 6.5.1 - 2019-12-21\n\n* Better defaults for PHP installations with old ICU lib [#2454](https://github.com/guzzle/guzzle/pull/2454)\n* IDN support for redirects [#2424](https://github.com/guzzle/guzzle/pull/2424)\n\n## 6.5.0 - 2019-12-07\n\n* Improvement: Added support for reset internal queue in MockHandler. [#2143](https://github.com/guzzle/guzzle/pull/2143)\n* Improvement: Added support to pass arbitrary options to `curl_multi_init`. [#2287](https://github.com/guzzle/guzzle/pull/2287)\n* Fix: Gracefully handle passing `null` to the `header` option. [#2132](https://github.com/guzzle/guzzle/pull/2132)\n* Fix: `RetryMiddleware` did not do exponential delay between retries due unit mismatch. [#2132](https://github.com/guzzle/guzzle/pull/2132)\n  Previously, `RetryMiddleware` would sleep for 1 millisecond, then 2 milliseconds, then 4 milliseconds.\n  **After this change, `RetryMiddleware` will sleep for 1 second, then 2 seconds, then 4 seconds.**\n  `Middleware::retry()` accepts a second callback parameter to override the default timeouts if needed.\n* Fix: Prevent undefined offset when using array for ssl_key options. [#2348](https://github.com/guzzle/guzzle/pull/2348)\n* Deprecated `ClientInterface::VERSION`\n\n## 6.4.1 - 2019-10-23\n\n* No `guzzle.phar` was created in 6.4.0 due expired API token. This release will fix that \n* Added `parent::__construct()` to `FileCookieJar` and `SessionCookieJar`\n\n## 6.4.0 - 2019-10-23\n\n* Improvement: Improved error messages when using curl < 7.21.2 [#2108](https://github.com/guzzle/guzzle/pull/2108)\n* Fix: Test if response is readable before returning a summary in `RequestException::getResponseBodySummary()` [#2081](https://github.com/guzzle/guzzle/pull/2081)\n* Fix: Add support for GUZZLE_CURL_SELECT_TIMEOUT environment variable [#2161](https://github.com/guzzle/guzzle/pull/2161)\n* Improvement: Added `GuzzleHttp\\Exception\\InvalidArgumentException` [#2163](https://github.com/guzzle/guzzle/pull/2163)\n* Improvement: Added `GuzzleHttp\\_current_time()` to use `hrtime()` if that function exists. [#2242](https://github.com/guzzle/guzzle/pull/2242)\n* Improvement: Added curl's `appconnect_time` in `TransferStats` [#2284](https://github.com/guzzle/guzzle/pull/2284)\n* Improvement: Make GuzzleException extend Throwable wherever it's available [#2273](https://github.com/guzzle/guzzle/pull/2273)\n* Fix: Prevent concurrent writes to file when saving `CookieJar` [#2335](https://github.com/guzzle/guzzle/pull/2335)\n* Improvement: Update `MockHandler` so we can test transfer time [#2362](https://github.com/guzzle/guzzle/pull/2362)\n\n## 6.3.3 - 2018-04-22\n\n* Fix: Default headers when decode_content is specified\n\n\n## 6.3.2 - 2018-03-26\n\n* Fix: Release process\n\n\n## 6.3.1 - 2018-03-26\n\n* Bug fix: Parsing 0 epoch expiry times in cookies [#2014](https://github.com/guzzle/guzzle/pull/2014)\n* Improvement: Better ConnectException detection [#2012](https://github.com/guzzle/guzzle/pull/2012)\n* Bug fix: Malformed domain that contains a \"/\" [#1999](https://github.com/guzzle/guzzle/pull/1999)\n* Bug fix: Undefined offset when a cookie has no first key-value pair [#1998](https://github.com/guzzle/guzzle/pull/1998)\n* Improvement: Support PHPUnit 6 [#1953](https://github.com/guzzle/guzzle/pull/1953)\n* Bug fix: Support empty headers [#1915](https://github.com/guzzle/guzzle/pull/1915)\n* Bug fix: Ignore case during header modifications [#1916](https://github.com/guzzle/guzzle/pull/1916)\n\n+ Minor code cleanups, documentation fixes and clarifications.\n\n\n## 6.3.0 - 2017-06-22\n\n* Feature: force IP resolution (ipv4 or ipv6) [#1608](https://github.com/guzzle/guzzle/pull/1608), [#1659](https://github.com/guzzle/guzzle/pull/1659)\n* Improvement: Don't include summary in exception message when body is empty [#1621](https://github.com/guzzle/guzzle/pull/1621)\n* Improvement: Handle `on_headers` option in MockHandler [#1580](https://github.com/guzzle/guzzle/pull/1580)\n* Improvement: Added SUSE Linux CA path [#1609](https://github.com/guzzle/guzzle/issues/1609)\n* Improvement: Use class reference for getting the name of the class instead of using hardcoded strings [#1641](https://github.com/guzzle/guzzle/pull/1641)\n* Feature: Added `read_timeout` option [#1611](https://github.com/guzzle/guzzle/pull/1611)\n* Bug fix: PHP 7.x fixes [#1685](https://github.com/guzzle/guzzle/pull/1685), [#1686](https://github.com/guzzle/guzzle/pull/1686), [#1811](https://github.com/guzzle/guzzle/pull/1811)\n* Deprecation: BadResponseException instantiation without a response [#1642](https://github.com/guzzle/guzzle/pull/1642)\n* Feature: Added NTLM auth [#1569](https://github.com/guzzle/guzzle/pull/1569)\n* Feature: Track redirect HTTP status codes [#1711](https://github.com/guzzle/guzzle/pull/1711)\n* Improvement: Check handler type during construction [#1745](https://github.com/guzzle/guzzle/pull/1745)\n* Improvement: Always include the Content-Length if there's a body [#1721](https://github.com/guzzle/guzzle/pull/1721)\n* Feature: Added convenience method to access a cookie by name [#1318](https://github.com/guzzle/guzzle/pull/1318)\n* Bug fix: Fill `CURLOPT_CAPATH` and `CURLOPT_CAINFO` properly [#1684](https://github.com/guzzle/guzzle/pull/1684)\n* Improvement:  \tUse `\\GuzzleHttp\\Promise\\rejection_for` function instead of object init [#1827](https://github.com/guzzle/guzzle/pull/1827)\n\n\n+ Minor code cleanups, documentation fixes and clarifications.\n\n## 6.2.3 - 2017-02-28\n\n* Fix deprecations with guzzle/psr7 version 1.4\n\n## 6.2.2 - 2016-10-08\n\n* Allow to pass nullable Response to delay callable\n* Only add scheme when host is present\n* Fix drain case where content-length is the literal string zero\n* Obfuscate in-URL credentials in exceptions\n\n## 6.2.1 - 2016-07-18\n\n* Address HTTP_PROXY security vulnerability, CVE-2016-5385:\n  https://httpoxy.org/\n* Fixing timeout bug with StreamHandler:\n  https://github.com/guzzle/guzzle/pull/1488\n* Only read up to `Content-Length` in PHP StreamHandler to avoid timeouts when\n  a server does not honor `Connection: close`.\n* Ignore URI fragment when sending requests.\n\n## 6.2.0 - 2016-03-21\n\n* Feature: added `GuzzleHttp\\json_encode` and `GuzzleHttp\\json_decode`.\n  https://github.com/guzzle/guzzle/pull/1389\n* Bug fix: Fix sleep calculation when waiting for delayed requests.\n  https://github.com/guzzle/guzzle/pull/1324\n* Feature: More flexible history containers.\n  https://github.com/guzzle/guzzle/pull/1373\n* Bug fix: defer sink stream opening in StreamHandler.\n  https://github.com/guzzle/guzzle/pull/1377\n* Bug fix: do not attempt to escape cookie values.\n  https://github.com/guzzle/guzzle/pull/1406\n* Feature: report original content encoding and length on decoded responses.\n  https://github.com/guzzle/guzzle/pull/1409\n* Bug fix: rewind seekable request bodies before dispatching to cURL.\n  https://github.com/guzzle/guzzle/pull/1422\n* Bug fix: provide an empty string to `http_build_query` for HHVM workaround.\n  https://github.com/guzzle/guzzle/pull/1367\n\n## 6.1.1 - 2015-11-22\n\n* Bug fix: Proxy::wrapSync() now correctly proxies to the appropriate handler\n  https://github.com/guzzle/guzzle/commit/911bcbc8b434adce64e223a6d1d14e9a8f63e4e4\n* Feature: HandlerStack is now more generic.\n  https://github.com/guzzle/guzzle/commit/f2102941331cda544745eedd97fc8fd46e1ee33e\n* Bug fix: setting verify to false in the StreamHandler now disables peer\n  verification. https://github.com/guzzle/guzzle/issues/1256\n* Feature: Middleware now uses an exception factory, including more error\n  context. https://github.com/guzzle/guzzle/pull/1282\n* Feature: better support for disabled functions.\n  https://github.com/guzzle/guzzle/pull/1287\n* Bug fix: fixed regression where MockHandler was not using `sink`.\n  https://github.com/guzzle/guzzle/pull/1292\n\n## 6.1.0 - 2015-09-08\n\n* Feature: Added the `on_stats` request option to provide access to transfer\n  statistics for requests. https://github.com/guzzle/guzzle/pull/1202\n* Feature: Added the ability to persist session cookies in CookieJars.\n  https://github.com/guzzle/guzzle/pull/1195\n* Feature: Some compatibility updates for Google APP Engine\n  https://github.com/guzzle/guzzle/pull/1216\n* Feature: Added support for NO_PROXY to prevent the use of a proxy based on\n  a simple set of rules. https://github.com/guzzle/guzzle/pull/1197\n* Feature: Cookies can now contain square brackets.\n  https://github.com/guzzle/guzzle/pull/1237\n* Bug fix: Now correctly parsing `=` inside of quotes in Cookies.\n  https://github.com/guzzle/guzzle/pull/1232\n* Bug fix: Cusotm cURL options now correctly override curl options of the\n  same name. https://github.com/guzzle/guzzle/pull/1221\n* Bug fix: Content-Type header is now added when using an explicitly provided\n  multipart body. https://github.com/guzzle/guzzle/pull/1218\n* Bug fix: Now ignoring Set-Cookie headers that have no name.\n* Bug fix: Reason phrase is no longer cast to an int in some cases in the\n  cURL handler. https://github.com/guzzle/guzzle/pull/1187\n* Bug fix: Remove the Authorization header when redirecting if the Host\n  header changes. https://github.com/guzzle/guzzle/pull/1207\n* Bug fix: Cookie path matching fixes\n  https://github.com/guzzle/guzzle/issues/1129\n* Bug fix: Fixing the cURL `body_as_string` setting\n  https://github.com/guzzle/guzzle/pull/1201\n* Bug fix: quotes are no longer stripped when parsing cookies.\n  https://github.com/guzzle/guzzle/issues/1172\n* Bug fix: `form_params` and `query` now always uses the `&` separator.\n  https://github.com/guzzle/guzzle/pull/1163\n* Bug fix: Adding a Content-Length to PHP stream wrapper requests if not set.\n  https://github.com/guzzle/guzzle/pull/1189\n\n## 6.0.2 - 2015-07-04\n\n* Fixed a memory leak in the curl handlers in which references to callbacks\n  were not being removed by `curl_reset`.\n* Cookies are now extracted properly before redirects.\n* Cookies now allow more character ranges.\n* Decoded Content-Encoding responses are now modified to correctly reflect\n  their state if the encoding was automatically removed by a handler. This\n  means that the `Content-Encoding` header may be removed an the\n  `Content-Length` modified to reflect the message size after removing the\n  encoding.\n* Added a more explicit error message when trying to use `form_params` and\n  `multipart` in the same request.\n* Several fixes for HHVM support.\n* Functions are now conditionally required using an additional level of\n  indirection to help with global Composer installations.\n\n## 6.0.1 - 2015-05-27\n\n* Fixed a bug with serializing the `query` request option where the `&`\n  separator was missing.\n* Added a better error message for when `body` is provided as an array. Please\n  use `form_params` or `multipart` instead.\n* Various doc fixes.\n\n## 6.0.0 - 2015-05-26\n\n* See the UPGRADING.md document for more information.\n* Added `multipart` and `form_params` request options.\n* Added `synchronous` request option.\n* Added the `on_headers` request option.\n* Fixed `expect` handling.\n* No longer adding default middlewares in the client ctor. These need to be\n  present on the provided handler in order to work.\n* Requests are no longer initiated when sending async requests with the\n  CurlMultiHandler. This prevents unexpected recursion from requests completing\n  while ticking the cURL loop.\n* Removed the semantics of setting `default` to `true`. This is no longer\n  required now that the cURL loop is not ticked for async requests.\n* Added request and response logging middleware.\n* No longer allowing self signed certificates when using the StreamHandler.\n* Ensuring that `sink` is valid if saving to a file.\n* Request exceptions now include a \"handler context\" which provides handler\n  specific contextual information.\n* Added `GuzzleHttp\\RequestOptions` to allow request options to be applied\n  using constants.\n* `$maxHandles` has been removed from CurlMultiHandler.\n* `MultipartPostBody` is now part of the `guzzlehttp/psr7` package.\n\n## 5.3.0 - 2015-05-19\n\n* Mock now supports `save_to`\n* Marked `AbstractRequestEvent::getTransaction()` as public.\n* Fixed a bug in which multiple headers using different casing would overwrite\n  previous headers in the associative array.\n* Added `Utils::getDefaultHandler()`\n* Marked `GuzzleHttp\\Client::getDefaultUserAgent` as deprecated.\n* URL scheme is now always lowercased.\n\n## 6.0.0-beta.1\n\n* Requires PHP >= 5.5\n* Updated to use PSR-7\n  * Requires immutable messages, which basically means an event based system\n    owned by a request instance is no longer possible.\n  * Utilizing the [Guzzle PSR-7 package](https://github.com/guzzle/psr7).\n  * Removed the dependency on `guzzlehttp/streams`. These stream abstractions\n    are available in the `guzzlehttp/psr7` package under the `GuzzleHttp\\Psr7`\n    namespace.\n* Added middleware and handler system\n  * Replaced the Guzzle event and subscriber system with a middleware system.\n  * No longer depends on RingPHP, but rather places the HTTP handlers directly\n    in Guzzle, operating on PSR-7 messages.\n  * Retry logic is now encapsulated in `GuzzleHttp\\Middleware::retry`, which\n    means the `guzzlehttp/retry-subscriber` is now obsolete.\n  * Mocking responses is now handled using `GuzzleHttp\\Handler\\MockHandler`.\n* Asynchronous responses\n  * No longer supports the `future` request option to send an async request.\n    Instead, use one of the `*Async` methods of a client (e.g., `requestAsync`,\n    `getAsync`, etc.).\n  * Utilizing `GuzzleHttp\\Promise` instead of React's promise library to avoid\n    recursion required by chaining and forwarding react promises. See\n    https://github.com/guzzle/promises\n  * Added `requestAsync` and `sendAsync` to send request asynchronously.\n  * Added magic methods for `getAsync()`, `postAsync()`, etc. to send requests\n    asynchronously.\n* Request options\n  * POST and form updates\n    * Added the `form_fields` and `form_files` request options.\n    * Removed the `GuzzleHttp\\Post` namespace.\n    * The `body` request option no longer accepts an array for POST requests.\n  * The `exceptions` request option has been deprecated in favor of the\n    `http_errors` request options.\n  * The `save_to` request option has been deprecated in favor of `sink` request\n    option.\n* Clients no longer accept an array of URI template string and variables for\n  URI variables. You will need to expand URI templates before passing them\n  into a client constructor or request method.\n* Client methods `get()`, `post()`, `put()`, `patch()`, `options()`, etc. are\n  now magic methods that will send synchronous requests.\n* Replaced `Utils.php` with plain functions in `functions.php`.\n* Removed `GuzzleHttp\\Collection`.\n* Removed `GuzzleHttp\\BatchResults`. Batched pool results are now returned as\n  an array.\n* Removed `GuzzleHttp\\Query`. Query string handling is now handled using an\n  associative array passed into the `query` request option. The query string\n  is serialized using PHP's `http_build_query`. If you need more control, you\n  can pass the query string in as a string.\n* `GuzzleHttp\\QueryParser` has been replaced with the\n  `GuzzleHttp\\Psr7\\parse_query`.\n\n## 5.2.0 - 2015-01-27\n\n* Added `AppliesHeadersInterface` to make applying headers to a request based\n  on the body more generic and not specific to `PostBodyInterface`.\n* Reduced the number of stack frames needed to send requests.\n* Nested futures are now resolved in the client rather than the RequestFsm\n* Finishing state transitions is now handled in the RequestFsm rather than the\n  RingBridge.\n* Added a guard in the Pool class to not use recursion for request retries.\n\n## 5.1.0 - 2014-12-19\n\n* Pool class no longer uses recursion when a request is intercepted.\n* The size of a Pool can now be dynamically adjusted using a callback.\n  See https://github.com/guzzle/guzzle/pull/943.\n* Setting a request option to `null` when creating a request with a client will\n  ensure that the option is not set. This allows you to overwrite default\n  request options on a per-request basis.\n  See https://github.com/guzzle/guzzle/pull/937.\n* Added the ability to limit which protocols are allowed for redirects by\n  specifying a `protocols` array in the `allow_redirects` request option.\n* Nested futures due to retries are now resolved when waiting for synchronous\n  responses. See https://github.com/guzzle/guzzle/pull/947.\n* `\"0\"` is now an allowed URI path. See\n  https://github.com/guzzle/guzzle/pull/935.\n* `Query` no longer typehints on the `$query` argument in the constructor,\n  allowing for strings and arrays.\n* Exceptions thrown in the `end` event are now correctly wrapped with Guzzle\n  specific exceptions if necessary.\n\n## 5.0.3 - 2014-11-03\n\nThis change updates query strings so that they are treated as un-encoded values\nby default where the value represents an un-encoded value to send over the\nwire. A Query object then encodes the value before sending over the wire. This\nmeans that even value query string values (e.g., \":\") are url encoded. This\nmakes the Query class match PHP's http_build_query function. However, if you\nwant to send requests over the wire using valid query string characters that do\nnot need to be encoded, then you can provide a string to Url::setQuery() and\npass true as the second argument to specify that the query string is a raw\nstring that should not be parsed or encoded (unless a call to getQuery() is\nsubsequently made, forcing the query-string to be converted into a Query\nobject).\n\n## 5.0.2 - 2014-10-30\n\n* Added a trailing `\\r\\n` to multipart/form-data payloads. See\n  https://github.com/guzzle/guzzle/pull/871\n* Added a `GuzzleHttp\\Pool::send()` convenience method to match the docs.\n* Status codes are now returned as integers. See\n  https://github.com/guzzle/guzzle/issues/881\n* No longer overwriting an existing `application/x-www-form-urlencoded` header\n  when sending POST requests, allowing for customized headers. See\n  https://github.com/guzzle/guzzle/issues/877\n* Improved path URL serialization.\n\n  * No longer double percent-encoding characters in the path or query string if\n    they are already encoded.\n  * Now properly encoding the supplied path to a URL object, instead of only\n    encoding ' ' and '?'.\n  * Note: This has been changed in 5.0.3 to now encode query string values by\n    default unless the `rawString` argument is provided when setting the query\n    string on a URL: Now allowing many more characters to be present in the\n    query string without being percent encoded. See http://tools.ietf.org/html/rfc3986#appendix-A\n\n## 5.0.1 - 2014-10-16\n\nBugfix release.\n\n* Fixed an issue where connection errors still returned response object in\n  error and end events event though the response is unusable. This has been\n  corrected so that a response is not returned in the `getResponse` method of\n  these events if the response did not complete. https://github.com/guzzle/guzzle/issues/867\n* Fixed an issue where transfer statistics were not being populated in the\n  RingBridge. https://github.com/guzzle/guzzle/issues/866\n\n## 5.0.0 - 2014-10-12\n\nAdding support for non-blocking responses and some minor API cleanup.\n\n### New Features\n\n* Added support for non-blocking responses based on `guzzlehttp/guzzle-ring`.\n* Added a public API for creating a default HTTP adapter.\n* Updated the redirect plugin to be non-blocking so that redirects are sent\n  concurrently. Other plugins like this can now be updated to be non-blocking.\n* Added a \"progress\" event so that you can get upload and download progress\n  events.\n* Added `GuzzleHttp\\Pool` which implements FutureInterface and transfers\n  requests concurrently using a capped pool size as efficiently as possible.\n* Added `hasListeners()` to EmitterInterface.\n* Removed `GuzzleHttp\\ClientInterface::sendAll` and marked\n  `GuzzleHttp\\Client::sendAll` as deprecated (it's still there, just not the\n  recommended way).\n\n### Breaking changes\n\nThe breaking changes in this release are relatively minor. The biggest thing to\nlook out for is that request and response objects no longer implement fluent\ninterfaces.\n\n* Removed the fluent interfaces (i.e., `return $this`) from requests,\n  responses, `GuzzleHttp\\Collection`, `GuzzleHttp\\Url`,\n  `GuzzleHttp\\Query`, `GuzzleHttp\\Post\\PostBody`, and\n  `GuzzleHttp\\Cookie\\SetCookie`. This blog post provides a good outline of\n  why I did this: http://ocramius.github.io/blog/fluent-interfaces-are-evil/.\n  This also makes the Guzzle message interfaces compatible with the current\n  PSR-7 message proposal.\n* Removed \"functions.php\", so that Guzzle is truly PSR-4 compliant. Except\n  for the HTTP request functions from function.php, these functions are now\n  implemented in `GuzzleHttp\\Utils` using camelCase. `GuzzleHttp\\json_decode`\n  moved to `GuzzleHttp\\Utils::jsonDecode`. `GuzzleHttp\\get_path` moved to\n  `GuzzleHttp\\Utils::getPath`. `GuzzleHttp\\set_path` moved to\n  `GuzzleHttp\\Utils::setPath`. `GuzzleHttp\\batch` should now be\n  `GuzzleHttp\\Pool::batch`, which returns an `objectStorage`. Using functions.php\n  caused problems for many users: they aren't PSR-4 compliant, require an\n  explicit include, and needed an if-guard to ensure that the functions are not\n  declared multiple times.\n* Rewrote adapter layer.\n    * Removing all classes from `GuzzleHttp\\Adapter`, these are now\n      implemented as callables that are stored in `GuzzleHttp\\Ring\\Client`.\n    * Removed the concept of \"parallel adapters\". Sending requests serially or\n      concurrently is now handled using a single adapter.\n    * Moved `GuzzleHttp\\Adapter\\Transaction` to `GuzzleHttp\\Transaction`. The\n      Transaction object now exposes the request, response, and client as public\n      properties. The getters and setters have been removed.\n* Removed the \"headers\" event. This event was only useful for changing the\n  body a response once the headers of the response were known. You can implement\n  a similar behavior in a number of ways. One example might be to use a\n  FnStream that has access to the transaction being sent. For example, when the\n  first byte is written, you could check if the response headers match your\n  expectations, and if so, change the actual stream body that is being\n  written to.\n* Removed the `asArray` parameter from\n  `GuzzleHttp\\Message\\MessageInterface::getHeader`. If you want to get a header\n  value as an array, then use the newly added `getHeaderAsArray()` method of\n  `MessageInterface`. This change makes the Guzzle interfaces compatible with\n  the PSR-7 interfaces.\n* `GuzzleHttp\\Message\\MessageFactory` no longer allows subclasses to add\n  custom request options using double-dispatch (this was an implementation\n  detail). Instead, you should now provide an associative array to the\n  constructor which is a mapping of the request option name mapping to a\n  function that applies the option value to a request.\n* Removed the concept of \"throwImmediately\" from exceptions and error events.\n  This control mechanism was used to stop a transfer of concurrent requests\n  from completing. This can now be handled by throwing the exception or by\n  cancelling a pool of requests or each outstanding future request individually.\n* Updated to \"GuzzleHttp\\Streams\" 3.0.\n    * `GuzzleHttp\\Stream\\StreamInterface::getContents()` no longer accepts a\n      `maxLen` parameter. This update makes the Guzzle streams project\n      compatible with the current PSR-7 proposal.\n    * `GuzzleHttp\\Stream\\Stream::__construct`,\n      `GuzzleHttp\\Stream\\Stream::factory`, and\n      `GuzzleHttp\\Stream\\Utils::create` no longer accept a size in the second\n      argument. They now accept an associative array of options, including the\n      \"size\" key and \"metadata\" key which can be used to provide custom metadata.\n\n## 4.2.2 - 2014-09-08\n\n* Fixed a memory leak in the CurlAdapter when reusing cURL handles.\n* No longer using `request_fulluri` in stream adapter proxies.\n* Relative redirects are now based on the last response, not the first response.\n\n## 4.2.1 - 2014-08-19\n\n* Ensuring that the StreamAdapter does not always add a Content-Type header\n* Adding automated github releases with a phar and zip\n\n## 4.2.0 - 2014-08-17\n\n* Now merging in default options using a case-insensitive comparison.\n  Closes https://github.com/guzzle/guzzle/issues/767\n* Added the ability to automatically decode `Content-Encoding` response bodies\n  using the `decode_content` request option. This is set to `true` by default\n  to decode the response body if it comes over the wire with a\n  `Content-Encoding`. Set this value to `false` to disable decoding the\n  response content, and pass a string to provide a request `Accept-Encoding`\n  header and turn on automatic response decoding. This feature now allows you\n  to pass an `Accept-Encoding` header in the headers of a request but still\n  disable automatic response decoding.\n  Closes https://github.com/guzzle/guzzle/issues/764\n* Added the ability to throw an exception immediately when transferring\n  requests in parallel. Closes https://github.com/guzzle/guzzle/issues/760\n* Updating guzzlehttp/streams dependency to ~2.1\n* No longer utilizing the now deprecated namespaced methods from the stream\n  package.\n\n## 4.1.8 - 2014-08-14\n\n* Fixed an issue in the CurlFactory that caused setting the `stream=false`\n  request option to throw an exception.\n  See: https://github.com/guzzle/guzzle/issues/769\n* TransactionIterator now calls rewind on the inner iterator.\n  See: https://github.com/guzzle/guzzle/pull/765\n* You can now set the `Content-Type` header to `multipart/form-data`\n  when creating POST requests to force multipart bodies.\n  See https://github.com/guzzle/guzzle/issues/768\n\n## 4.1.7 - 2014-08-07\n\n* Fixed an error in the HistoryPlugin that caused the same request and response\n  to be logged multiple times when an HTTP protocol error occurs.\n* Ensuring that cURL does not add a default Content-Type when no Content-Type\n  has been supplied by the user. This prevents the adapter layer from modifying\n  the request that is sent over the wire after any listeners may have already\n  put the request in a desired state (e.g., signed the request).\n* Throwing an exception when you attempt to send requests that have the\n  \"stream\" set to true in parallel using the MultiAdapter.\n* Only calling curl_multi_select when there are active cURL handles. This was\n  previously changed and caused performance problems on some systems due to PHP\n  always selecting until the maximum select timeout.\n* Fixed a bug where multipart/form-data POST fields were not correctly\n  aggregated (e.g., values with \"&\").\n\n## 4.1.6 - 2014-08-03\n\n* Added helper methods to make it easier to represent messages as strings,\n  including getting the start line and getting headers as a string.\n\n## 4.1.5 - 2014-08-02\n\n* Automatically retrying cURL \"Connection died, retrying a fresh connect\"\n  errors when possible.\n* cURL implementation cleanup\n* Allowing multiple event subscriber listeners to be registered per event by\n  passing an array of arrays of listener configuration.\n\n## 4.1.4 - 2014-07-22\n\n* Fixed a bug that caused multi-part POST requests with more than one field to\n  serialize incorrectly.\n* Paths can now be set to \"0\"\n* `ResponseInterface::xml` now accepts a `libxml_options` option and added a\n  missing default argument that was required when parsing XML response bodies.\n* A `save_to` stream is now created lazily, which means that files are not\n  created on disk unless a request succeeds.\n\n## 4.1.3 - 2014-07-15\n\n* Various fixes to multipart/form-data POST uploads\n* Wrapping function.php in an if-statement to ensure Guzzle can be used\n  globally and in a Composer install\n* Fixed an issue with generating and merging in events to an event array\n* POST headers are only applied before sending a request to allow you to change\n  the query aggregator used before uploading\n* Added much more robust query string parsing\n* Fixed various parsing and normalization issues with URLs\n* Fixing an issue where multi-valued headers were not being utilized correctly\n  in the StreamAdapter\n\n## 4.1.2 - 2014-06-18\n\n* Added support for sending payloads with GET requests\n\n## 4.1.1 - 2014-06-08\n\n* Fixed an issue related to using custom message factory options in subclasses\n* Fixed an issue with nested form fields in a multi-part POST\n* Fixed an issue with using the `json` request option for POST requests\n* Added `ToArrayInterface` to `GuzzleHttp\\Cookie\\CookieJar`\n\n## 4.1.0 - 2014-05-27\n\n* Added a `json` request option to easily serialize JSON payloads.\n* Added a `GuzzleHttp\\json_decode()` wrapper to safely parse JSON.\n* Added `setPort()` and `getPort()` to `GuzzleHttp\\Message\\RequestInterface`.\n* Added the ability to provide an emitter to a client in the client constructor.\n* Added the ability to persist a cookie session using $_SESSION.\n* Added a trait that can be used to add event listeners to an iterator.\n* Removed request method constants from RequestInterface.\n* Fixed warning when invalid request start-lines are received.\n* Updated MessageFactory to work with custom request option methods.\n* Updated cacert bundle to latest build.\n\n4.0.2 (2014-04-16)\n------------------\n\n* Proxy requests using the StreamAdapter now properly use request_fulluri (#632)\n* Added the ability to set scalars as POST fields (#628)\n\n## 4.0.1 - 2014-04-04\n\n* The HTTP status code of a response is now set as the exception code of\n  RequestException objects.\n* 303 redirects will now correctly switch from POST to GET requests.\n* The default parallel adapter of a client now correctly uses the MultiAdapter.\n* HasDataTrait now initializes the internal data array as an empty array so\n  that the toArray() method always returns an array.\n\n## 4.0.0 - 2014-03-29\n\n* For more information on the 4.0 transition, see:\n  http://mtdowling.com/blog/2014/03/15/guzzle-4-rc/\n* For information on changes and upgrading, see:\n  https://github.com/guzzle/guzzle/blob/master/UPGRADING.md#3x-to-40\n* Added `GuzzleHttp\\batch()` as a convenience function for sending requests in\n  parallel without needing to write asynchronous code.\n* Restructured how events are added to `GuzzleHttp\\ClientInterface::sendAll()`.\n  You can now pass a callable or an array of associative arrays where each\n  associative array contains the \"fn\", \"priority\", and \"once\" keys.\n\n## 4.0.0.rc-2 - 2014-03-25\n\n* Removed `getConfig()` and `setConfig()` from clients to avoid confusion\n  around whether things like base_url, message_factory, etc. should be able to\n  be retrieved or modified.\n* Added `getDefaultOption()` and `setDefaultOption()` to ClientInterface\n* functions.php functions were renamed using snake_case to match PHP idioms\n* Added support for `HTTP_PROXY`, `HTTPS_PROXY`, and\n  `GUZZLE_CURL_SELECT_TIMEOUT` environment variables\n* Added the ability to specify custom `sendAll()` event priorities\n* Added the ability to specify custom stream context options to the stream\n  adapter.\n* Added a functions.php function for `get_path()` and `set_path()`\n* CurlAdapter and MultiAdapter now use a callable to generate curl resources\n* MockAdapter now properly reads a body and emits a `headers` event\n* Updated Url class to check if a scheme and host are set before adding \":\"\n  and \"//\". This allows empty Url (e.g., \"\") to be serialized as \"\".\n* Parsing invalid XML no longer emits warnings\n* Curl classes now properly throw AdapterExceptions\n* Various performance optimizations\n* Streams are created with the faster `Stream\\create()` function\n* Marked deprecation_proxy() as internal\n* Test server is now a collection of static methods on a class\n\n## 4.0.0-rc.1 - 2014-03-15\n\n* See https://github.com/guzzle/guzzle/blob/master/UPGRADING.md#3x-to-40\n\n## 3.8.1 - 2014-01-28\n\n* Bug: Always using GET requests when redirecting from a 303 response\n* Bug: CURLOPT_SSL_VERIFYHOST is now correctly set to false when setting `$certificateAuthority` to false in\n  `Guzzle\\Http\\ClientInterface::setSslVerification()`\n* Bug: RedirectPlugin now uses strict RFC 3986 compliance when combining a base URL with a relative URL\n* Bug: The body of a request can now be set to `\"0\"`\n* Sending PHP stream requests no longer forces `HTTP/1.0`\n* Adding more information to ExceptionCollection exceptions so that users have more context, including a stack trace of\n  each sub-exception\n* Updated the `$ref` attribute in service descriptions to merge over any existing parameters of a schema (rather than\n  clobbering everything).\n* Merging URLs will now use the query string object from the relative URL (thus allowing custom query aggregators)\n* Query strings are now parsed in a way that they do no convert empty keys with no value to have a dangling `=`.\n  For example `foo&bar=baz` is now correctly parsed and recognized as `foo&bar=baz` rather than `foo=&bar=baz`.\n* Now properly escaping the regular expression delimiter when matching Cookie domains.\n* Network access is now disabled when loading XML documents\n\n## 3.8.0 - 2013-12-05\n\n* Added the ability to define a POST name for a file\n* JSON response parsing now properly walks additionalProperties\n* cURL error code 18 is now retried automatically in the BackoffPlugin\n* Fixed a cURL error when URLs contain fragments\n* Fixed an issue in the BackoffPlugin retry event where it was trying to access all exceptions as if they were\n  CurlExceptions\n* CURLOPT_PROGRESS function fix for PHP 5.5 (69fcc1e)\n* Added the ability for Guzzle to work with older versions of cURL that do not support `CURLOPT_TIMEOUT_MS`\n* Fixed a bug that was encountered when parsing empty header parameters\n* UriTemplate now has a `setRegex()` method to match the docs\n* The `debug` request parameter now checks if it is truthy rather than if it exists\n* Setting the `debug` request parameter to true shows verbose cURL output instead of using the LogPlugin\n* Added the ability to combine URLs using strict RFC 3986 compliance\n* Command objects can now return the validation errors encountered by the command\n* Various fixes to cache revalidation (#437 and 29797e5)\n* Various fixes to the AsyncPlugin\n* Cleaned up build scripts\n\n## 3.7.4 - 2013-10-02\n\n* Bug fix: 0 is now an allowed value in a description parameter that has a default value (#430)\n* Bug fix: SchemaFormatter now returns an integer when formatting to a Unix timestamp\n  (see https://github.com/aws/aws-sdk-php/issues/147)\n* Bug fix: Cleaned up and fixed URL dot segment removal to properly resolve internal dots\n* Minimum PHP version is now properly specified as 5.3.3 (up from 5.3.2) (#420)\n* Updated the bundled cacert.pem (#419)\n* OauthPlugin now supports adding authentication to headers or query string (#425)\n\n## 3.7.3 - 2013-09-08\n\n* Added the ability to get the exception associated with a request/command when using `MultiTransferException` and\n  `CommandTransferException`.\n* Setting `additionalParameters` of a response to false is now honored when parsing responses with a service description\n* Schemas are only injected into response models when explicitly configured.\n* No longer guessing Content-Type based on the path of a request. Content-Type is now only guessed based on the path of\n  an EntityBody.\n* Bug fix: ChunkedIterator can now properly chunk a \\Traversable as well as an \\Iterator.\n* Bug fix: FilterIterator now relies on `\\Iterator` instead of `\\Traversable`.\n* Bug fix: Gracefully handling malformed responses in RequestMediator::writeResponseBody()\n* Bug fix: Replaced call to canCache with canCacheRequest in the CallbackCanCacheStrategy of the CachePlugin\n* Bug fix: Visiting XML attributes first before visiting XML children when serializing requests\n* Bug fix: Properly parsing headers that contain commas contained in quotes\n* Bug fix: mimetype guessing based on a filename is now case-insensitive\n\n## 3.7.2 - 2013-08-02\n\n* Bug fix: Properly URL encoding paths when using the PHP-only version of the UriTemplate expander\n  See https://github.com/guzzle/guzzle/issues/371\n* Bug fix: Cookie domains are now matched correctly according to RFC 6265\n  See https://github.com/guzzle/guzzle/issues/377\n* Bug fix: GET parameters are now used when calculating an OAuth signature\n* Bug fix: Fixed an issue with cache revalidation where the If-None-Match header was being double quoted\n* `Guzzle\\Common\\AbstractHasDispatcher::dispatch()` now returns the event that was dispatched\n* `Guzzle\\Http\\QueryString::factory()` now guesses the most appropriate query aggregator to used based on the input.\n  See https://github.com/guzzle/guzzle/issues/379\n* Added a way to add custom domain objects to service description parsing using the `operation.parse_class` event. See\n  https://github.com/guzzle/guzzle/pull/380\n* cURL multi cleanup and optimizations\n\n## 3.7.1 - 2013-07-05\n\n* Bug fix: Setting default options on a client now works\n* Bug fix: Setting options on HEAD requests now works. See #352\n* Bug fix: Moving stream factory before send event to before building the stream. See #353\n* Bug fix: Cookies no longer match on IP addresses per RFC 6265\n* Bug fix: Correctly parsing header parameters that are in `<>` and quotes\n* Added `cert` and `ssl_key` as request options\n* `Host` header can now diverge from the host part of a URL if the header is set manually\n* `Guzzle\\Service\\Command\\LocationVisitor\\Request\\XmlVisitor` was rewritten to change from using SimpleXML to XMLWriter\n* OAuth parameters are only added via the plugin if they aren't already set\n* Exceptions are now thrown when a URL cannot be parsed\n* Returning `false` if `Guzzle\\Http\\EntityBody::getContentMd5()` fails\n* Not setting a `Content-MD5` on a command if calculating the Content-MD5 fails via the CommandContentMd5Plugin\n\n## 3.7.0 - 2013-06-10\n\n* See UPGRADING.md for more information on how to upgrade.\n* Requests now support the ability to specify an array of $options when creating a request to more easily modify a\n  request. You can pass a 'request.options' configuration setting to a client to apply default request options to\n  every request created by a client (e.g. default query string variables, headers, curl options, etc.).\n* Added a static facade class that allows you to use Guzzle with static methods and mount the class to `\\Guzzle`.\n  See `Guzzle\\Http\\StaticClient::mount`.\n* Added `command.request_options` to `Guzzle\\Service\\Command\\AbstractCommand` to pass request options to requests\n      created by a command (e.g. custom headers, query string variables, timeout settings, etc.).\n* Stream size in `Guzzle\\Stream\\PhpStreamRequestFactory` will now be set if Content-Length is returned in the\n  headers of a response\n* Added `Guzzle\\Common\\Collection::setPath($path, $value)` to set a value into an array using a nested key\n  (e.g. `$collection->setPath('foo/baz/bar', 'test'); echo $collection['foo']['bar']['bar'];`)\n* ServiceBuilders now support storing and retrieving arbitrary data\n* CachePlugin can now purge all resources for a given URI\n* CachePlugin can automatically purge matching cached items when a non-idempotent request is sent to a resource\n* CachePlugin now uses the Vary header to determine if a resource is a cache hit\n* `Guzzle\\Http\\Message\\Response` now implements `\\Serializable`\n* Added `Guzzle\\Cache\\CacheAdapterFactory::fromCache()` to more easily create cache adapters\n* `Guzzle\\Service\\ClientInterface::execute()` now accepts an array, single command, or Traversable\n* Fixed a bug in `Guzzle\\Http\\Message\\Header\\Link::addLink()`\n* Better handling of calculating the size of a stream in `Guzzle\\Stream\\Stream` using fstat() and caching the size\n* `Guzzle\\Common\\Exception\\ExceptionCollection` now creates a more readable exception message\n* Fixing BC break: Added back the MonologLogAdapter implementation rather than extending from PsrLog so that older\n  Symfony users can still use the old version of Monolog.\n* Fixing BC break: Added the implementation back in for `Guzzle\\Http\\Message\\AbstractMessage::getTokenizedHeader()`.\n  Now triggering an E_USER_DEPRECATED warning when used. Use `$message->getHeader()->parseParams()`.\n* Several performance improvements to `Guzzle\\Common\\Collection`\n* Added an `$options` argument to the end of the following methods of `Guzzle\\Http\\ClientInterface`:\n  createRequest, head, delete, put, patch, post, options, prepareRequest\n* Added an `$options` argument to the end of `Guzzle\\Http\\Message\\Request\\RequestFactoryInterface::createRequest()`\n* Added an `applyOptions()` method to `Guzzle\\Http\\Message\\Request\\RequestFactoryInterface`\n* Changed `Guzzle\\Http\\ClientInterface::get($uri = null, $headers = null, $body = null)` to\n  `Guzzle\\Http\\ClientInterface::get($uri = null, $headers = null, $options = array())`. You can still pass in a\n  resource, string, or EntityBody into the $options parameter to specify the download location of the response.\n* Changed `Guzzle\\Common\\Collection::__construct($data)` to no longer accepts a null value for `$data` but a\n  default `array()`\n* Added `Guzzle\\Stream\\StreamInterface::isRepeatable`\n* Removed `Guzzle\\Http\\ClientInterface::setDefaultHeaders(). Use\n  $client->getConfig()->setPath('request.options/headers/{header_name}', 'value')`. or\n  $client->getConfig()->setPath('request.options/headers', array('header_name' => 'value'))`.\n* Removed `Guzzle\\Http\\ClientInterface::getDefaultHeaders(). Use $client->getConfig()->getPath('request.options/headers')`.\n* Removed `Guzzle\\Http\\ClientInterface::expandTemplate()`\n* Removed `Guzzle\\Http\\ClientInterface::setRequestFactory()`\n* Removed `Guzzle\\Http\\ClientInterface::getCurlMulti()`\n* Removed `Guzzle\\Http\\Message\\RequestInterface::canCache`\n* Removed `Guzzle\\Http\\Message\\RequestInterface::setIsRedirect`\n* Removed `Guzzle\\Http\\Message\\RequestInterface::isRedirect`\n* Made `Guzzle\\Http\\Client::expandTemplate` and `getUriTemplate` protected methods.\n* You can now enable E_USER_DEPRECATED warnings to see if you are using a deprecated method by setting\n  `Guzzle\\Common\\Version::$emitWarnings` to true.\n* Marked `Guzzle\\Http\\Message\\Request::isResponseBodyRepeatable()` as deprecated. Use\n      `$request->getResponseBody()->isRepeatable()` instead.\n* Marked `Guzzle\\Http\\Message\\Request::canCache()` as deprecated. Use\n  `Guzzle\\Plugin\\Cache\\DefaultCanCacheStrategy->canCacheRequest()` instead.\n* Marked `Guzzle\\Http\\Message\\Request::canCache()` as deprecated. Use\n  `Guzzle\\Plugin\\Cache\\DefaultCanCacheStrategy->canCacheRequest()` instead.\n* Marked `Guzzle\\Http\\Message\\Request::setIsRedirect()` as deprecated. Use the HistoryPlugin instead.\n* Marked `Guzzle\\Http\\Message\\Request::isRedirect()` as deprecated. Use the HistoryPlugin instead.\n* Marked `Guzzle\\Cache\\CacheAdapterFactory::factory()` as deprecated\n* Marked 'command.headers', 'command.response_body' and 'command.on_complete' as deprecated for AbstractCommand.\n  These will work through Guzzle 4.0\n* Marked 'request.params' for `Guzzle\\Http\\Client` as deprecated. Use [request.options][params].\n* Marked `Guzzle\\Service\\Client::enableMagicMethods()` as deprecated. Magic methods can no longer be disabled on a Guzzle\\Service\\Client.\n* Marked `Guzzle\\Service\\Client::getDefaultHeaders()` as deprecated. Use $client->getConfig()->getPath('request.options/headers')`.\n* Marked `Guzzle\\Service\\Client::setDefaultHeaders()` as deprecated. Use $client->getConfig()->setPath('request.options/headers/{header_name}', 'value')`.\n* Marked `Guzzle\\Parser\\Url\\UrlParser` as deprecated. Just use PHP's `parse_url()` and percent encode your UTF-8.\n* Marked `Guzzle\\Common\\Collection::inject()` as deprecated.\n* Marked `Guzzle\\Plugin\\CurlAuth\\CurlAuthPlugin` as deprecated. Use `$client->getConfig()->setPath('request.options/auth', array('user', 'pass', 'Basic|Digest');`\n* CacheKeyProviderInterface and DefaultCacheKeyProvider are no longer used. All of this logic is handled in a\n  CacheStorageInterface. These two objects and interface will be removed in a future version.\n* Always setting X-cache headers on cached responses\n* Default cache TTLs are now handled by the CacheStorageInterface of a CachePlugin\n* `CacheStorageInterface::cache($key, Response $response, $ttl = null)` has changed to `cache(RequestInterface\n  $request, Response $response);`\n* `CacheStorageInterface::fetch($key)` has changed to `fetch(RequestInterface $request);`\n* `CacheStorageInterface::delete($key)` has changed to `delete(RequestInterface $request);`\n* Added `CacheStorageInterface::purge($url)`\n* `DefaultRevalidation::__construct(CacheKeyProviderInterface $cacheKey, CacheStorageInterface $cache, CachePlugin\n  $plugin)` has changed to `DefaultRevalidation::__construct(CacheStorageInterface $cache,\n  CanCacheStrategyInterface $canCache = null)`\n* Added `RevalidationInterface::shouldRevalidate(RequestInterface $request, Response $response)`\n\n## 3.6.0 - 2013-05-29\n\n* ServiceDescription now implements ToArrayInterface\n* Added command.hidden_params to blacklist certain headers from being treated as additionalParameters\n* Guzzle can now correctly parse incomplete URLs\n* Mixed casing of headers are now forced to be a single consistent casing across all values for that header.\n* Messages internally use a HeaderCollection object to delegate handling case-insensitive header resolution\n* Removed the whole changedHeader() function system of messages because all header changes now go through addHeader().\n* Specific header implementations can be created for complex headers. When a message creates a header, it uses a\n  HeaderFactory which can map specific headers to specific header classes. There is now a Link header and\n  CacheControl header implementation.\n* Removed from interface: Guzzle\\Http\\ClientInterface::setUriTemplate\n* Removed from interface: Guzzle\\Http\\ClientInterface::setCurlMulti()\n* Removed Guzzle\\Http\\Message\\Request::receivedRequestHeader() and implemented this functionality in\n  Guzzle\\Http\\Curl\\RequestMediator\n* Removed the optional $asString parameter from MessageInterface::getHeader(). Just cast the header to a string.\n* Removed the optional $tryChunkedTransfer option from Guzzle\\Http\\Message\\EntityEnclosingRequestInterface\n* Removed the $asObjects argument from Guzzle\\Http\\Message\\MessageInterface::getHeaders()\n* Removed Guzzle\\Parser\\ParserRegister::get(). Use getParser()\n* Removed Guzzle\\Parser\\ParserRegister::set(). Use registerParser().\n* All response header helper functions return a string rather than mixing Header objects and strings inconsistently\n* Removed cURL blacklist support. This is no longer necessary now that Expect, Accept, etc. are managed by Guzzle\n  directly via interfaces\n* Removed the injecting of a request object onto a response object. The methods to get and set a request still exist\n  but are a no-op until removed.\n* Most classes that used to require a `Guzzle\\Service\\Command\\CommandInterface` typehint now request a\n  `Guzzle\\Service\\Command\\ArrayCommandInterface`.\n* Added `Guzzle\\Http\\Message\\RequestInterface::startResponse()` to the RequestInterface to handle injecting a response\n  on a request while the request is still being transferred\n* The ability to case-insensitively search for header values\n* Guzzle\\Http\\Message\\Header::hasExactHeader\n* Guzzle\\Http\\Message\\Header::raw. Use getAll()\n* Deprecated cache control specific methods on Guzzle\\Http\\Message\\AbstractMessage. Use the CacheControl header object\n  instead.\n* `Guzzle\\Service\\Command\\CommandInterface` now extends from ToArrayInterface and ArrayAccess\n* Added the ability to cast Model objects to a string to view debug information.\n\n## 3.5.0 - 2013-05-13\n\n* Bug: Fixed a regression so that request responses are parsed only once per oncomplete event rather than multiple times\n* Bug: Better cleanup of one-time events across the board (when an event is meant to fire once, it will now remove\n  itself from the EventDispatcher)\n* Bug: `Guzzle\\Log\\MessageFormatter` now properly writes \"total_time\" and \"connect_time\" values\n* Bug: Cloning an EntityEnclosingRequest now clones the EntityBody too\n* Bug: Fixed an undefined index error when parsing nested JSON responses with a sentAs parameter that reference a\n  non-existent key\n* Bug: All __call() method arguments are now required (helps with mocking frameworks)\n* Deprecating Response::getRequest() and now using a shallow clone of a request object to remove a circular reference\n  to help with refcount based garbage collection of resources created by sending a request\n* Deprecating ZF1 cache and log adapters. These will be removed in the next major version.\n* Deprecating `Response::getPreviousResponse()` (method signature still exists, but it's deprecated). Use the\n  HistoryPlugin for a history.\n* Added a `responseBody` alias for the `response_body` location\n* Refactored internals to no longer rely on Response::getRequest()\n* HistoryPlugin can now be cast to a string\n* HistoryPlugin now logs transactions rather than requests and responses to more accurately keep track of the requests\n  and responses that are sent over the wire\n* Added `getEffectiveUrl()` and `getRedirectCount()` to Response objects\n\n## 3.4.3 - 2013-04-30\n\n* Bug fix: Fixing bug introduced in 3.4.2 where redirect responses are duplicated on the final redirected response\n* Added a check to re-extract the temp cacert bundle from the phar before sending each request\n\n## 3.4.2 - 2013-04-29\n\n* Bug fix: Stream objects now work correctly with \"a\" and \"a+\" modes\n* Bug fix: Removing `Transfer-Encoding: chunked` header when a Content-Length is present\n* Bug fix: AsyncPlugin no longer forces HEAD requests\n* Bug fix: DateTime timezones are now properly handled when using the service description schema formatter\n* Bug fix: CachePlugin now properly handles stale-if-error directives when a request to the origin server fails\n* Setting a response on a request will write to the custom request body from the response body if one is specified\n* LogPlugin now writes to php://output when STDERR is undefined\n* Added the ability to set multiple POST files for the same key in a single call\n* application/x-www-form-urlencoded POSTs now use the utf-8 charset by default\n* Added the ability to queue CurlExceptions to the MockPlugin\n* Cleaned up how manual responses are queued on requests (removed \"queued_response\" and now using request.before_send)\n* Configuration loading now allows remote files\n\n## 3.4.1 - 2013-04-16\n\n* Large refactoring to how CurlMulti handles work. There is now a proxy that sits in front of a pool of CurlMulti\n  handles. This greatly simplifies the implementation, fixes a couple bugs, and provides a small performance boost.\n* Exceptions are now properly grouped when sending requests in parallel\n* Redirects are now properly aggregated when a multi transaction fails\n* Redirects now set the response on the original object even in the event of a failure\n* Bug fix: Model names are now properly set even when using $refs\n* Added support for PHP 5.5's CurlFile to prevent warnings with the deprecated @ syntax\n* Added support for oauth_callback in OAuth signatures\n* Added support for oauth_verifier in OAuth signatures\n* Added support to attempt to retrieve a command first literally, then ucfirst, the with inflection\n\n## 3.4.0 - 2013-04-11\n\n* Bug fix: URLs are now resolved correctly based on http://tools.ietf.org/html/rfc3986#section-5.2. #289\n* Bug fix: Absolute URLs with a path in a service description will now properly override the base URL. #289\n* Bug fix: Parsing a query string with a single PHP array value will now result in an array. #263\n* Bug fix: Better normalization of the User-Agent header to prevent duplicate headers. #264.\n* Bug fix: Added `number` type to service descriptions.\n* Bug fix: empty parameters are removed from an OAuth signature\n* Bug fix: Revalidating a cache entry prefers the Last-Modified over the Date header\n* Bug fix: Fixed \"array to string\" error when validating a union of types in a service description\n* Bug fix: Removed code that attempted to determine the size of a stream when data is written to the stream\n* Bug fix: Not including an `oauth_token` if the value is null in the OauthPlugin.\n* Bug fix: Now correctly aggregating successful requests and failed requests in CurlMulti when a redirect occurs.\n* The new default CURLOPT_TIMEOUT setting has been increased to 150 seconds so that Guzzle works on poor connections.\n* Added a feature to EntityEnclosingRequest::setBody() that will automatically set the Content-Type of the request if\n  the Content-Type can be determined based on the entity body or the path of the request.\n* Added the ability to overwrite configuration settings in a client when grabbing a throwaway client from a builder.\n* Added support for a PSR-3 LogAdapter.\n* Added a `command.after_prepare` event\n* Added `oauth_callback` parameter to the OauthPlugin\n* Added the ability to create a custom stream class when using a stream factory\n* Added a CachingEntityBody decorator\n* Added support for `additionalParameters` in service descriptions to define how custom parameters are serialized.\n* The bundled SSL certificate is now provided in the phar file and extracted when running Guzzle from a phar.\n* You can now send any EntityEnclosingRequest with POST fields or POST files and cURL will handle creating bodies\n* POST requests using a custom entity body are now treated exactly like PUT requests but with a custom cURL method. This\n  means that the redirect behavior of POST requests with custom bodies will not be the same as POST requests that use\n  POST fields or files (the latter is only used when emulating a form POST in the browser).\n* Lots of cleanup to CurlHandle::factory and RequestFactory::createRequest\n\n## 3.3.1 - 2013-03-10\n\n* Added the ability to create PHP streaming responses from HTTP requests\n* Bug fix: Running any filters when parsing response headers with service descriptions\n* Bug fix: OauthPlugin fixes to allow for multi-dimensional array signing, and sorting parameters before signing\n* Bug fix: Removed the adding of default empty arrays and false Booleans to responses in order to be consistent across\n  response location visitors.\n* Bug fix: Removed the possibility of creating configuration files with circular dependencies\n* RequestFactory::create() now uses the key of a POST file when setting the POST file name\n* Added xmlAllowEmpty to serialize an XML body even if no XML specific parameters are set\n\n## 3.3.0 - 2013-03-03\n\n* A large number of performance optimizations have been made\n* Bug fix: Added 'wb' as a valid write mode for streams\n* Bug fix: `Guzzle\\Http\\Message\\Response::json()` now allows scalar values to be returned\n* Bug fix: Fixed bug in `Guzzle\\Http\\Message\\Response` where wrapping quotes were stripped from `getEtag()`\n* BC: Removed `Guzzle\\Http\\Utils` class\n* BC: Setting a service description on a client will no longer modify the client's command factories.\n* BC: Emitting IO events from a RequestMediator is now a parameter that must be set in a request's curl options using\n  the 'emit_io' key. This was previously set under a request's parameters using 'curl.emit_io'\n* BC: `Guzzle\\Stream\\Stream::getWrapper()` and `Guzzle\\Stream\\Stream::getSteamType()` are no longer converted to\n  lowercase\n* Operation parameter objects are now lazy loaded internally\n* Added ErrorResponsePlugin that can throw errors for responses defined in service description operations' errorResponses\n* Added support for instantiating responseType=class responseClass classes. Classes must implement\n  `Guzzle\\Service\\Command\\ResponseClassInterface`\n* Added support for additionalProperties for top-level parameters in responseType=model responseClasses. These\n  additional properties also support locations and can be used to parse JSON responses where the outermost part of the\n  JSON is an array\n* Added support for nested renaming of JSON models (rename sentAs to name)\n* CachePlugin\n    * Added support for stale-if-error so that the CachePlugin can now serve stale content from the cache on error\n    * Debug headers can now added to cached response in the CachePlugin\n\n## 3.2.0 - 2013-02-14\n\n* CurlMulti is no longer reused globally. A new multi object is created per-client. This helps to isolate clients.\n* URLs with no path no longer contain a \"/\" by default\n* Guzzle\\Http\\QueryString does no longer manages the leading \"?\". This is now handled in Guzzle\\Http\\Url.\n* BadResponseException no longer includes the full request and response message\n* Adding setData() to Guzzle\\Service\\Description\\ServiceDescriptionInterface\n* Adding getResponseBody() to Guzzle\\Http\\Message\\RequestInterface\n* Various updates to classes to use ServiceDescriptionInterface type hints rather than ServiceDescription\n* Header values can now be normalized into distinct values when multiple headers are combined with a comma separated list\n* xmlEncoding can now be customized for the XML declaration of a XML service description operation\n* Guzzle\\Http\\QueryString now uses Guzzle\\Http\\QueryAggregator\\QueryAggregatorInterface objects to add custom value\n  aggregation and no longer uses callbacks\n* The URL encoding implementation of Guzzle\\Http\\QueryString can now be customized\n* Bug fix: Filters were not always invoked for array service description parameters\n* Bug fix: Redirects now use a target response body rather than a temporary response body\n* Bug fix: The default exponential backoff BackoffPlugin was not giving when the request threshold was exceeded\n* Bug fix: Guzzle now takes the first found value when grabbing Cache-Control directives\n\n## 3.1.2 - 2013-01-27\n\n* Refactored how operation responses are parsed. Visitors now include a before() method responsible for parsing the\n  response body. For example, the XmlVisitor now parses the XML response into an array in the before() method.\n* Fixed an issue where cURL would not automatically decompress responses when the Accept-Encoding header was sent\n* CURLOPT_SSL_VERIFYHOST is never set to 1 because it is deprecated (see 5e0ff2ef20f839e19d1eeb298f90ba3598784444)\n* Fixed a bug where redirect responses were not chained correctly using getPreviousResponse()\n* Setting default headers on a client after setting the user-agent will not erase the user-agent setting\n\n## 3.1.1 - 2013-01-20\n\n* Adding wildcard support to Guzzle\\Common\\Collection::getPath()\n* Adding alias support to ServiceBuilder configs\n* Adding Guzzle\\Service\\Resource\\CompositeResourceIteratorFactory and cleaning up factory interface\n\n## 3.1.0 - 2013-01-12\n\n* BC: CurlException now extends from RequestException rather than BadResponseException\n* BC: Renamed Guzzle\\Plugin\\Cache\\CanCacheStrategyInterface::canCache() to canCacheRequest() and added CanCacheResponse()\n* Added getData to ServiceDescriptionInterface\n* Added context array to RequestInterface::setState()\n* Bug: Removing hard dependency on the BackoffPlugin from Guzzle\\Http\n* Bug: Adding required content-type when JSON request visitor adds JSON to a command\n* Bug: Fixing the serialization of a service description with custom data\n* Made it easier to deal with exceptions thrown when transferring commands or requests in parallel by providing\n  an array of successful and failed responses\n* Moved getPath from Guzzle\\Service\\Resource\\Model to Guzzle\\Common\\Collection\n* Added Guzzle\\Http\\IoEmittingEntityBody\n* Moved command filtration from validators to location visitors\n* Added `extends` attributes to service description parameters\n* Added getModels to ServiceDescriptionInterface\n\n## 3.0.7 - 2012-12-19\n\n* Fixing phar detection when forcing a cacert to system if null or true\n* Allowing filename to be passed to `Guzzle\\Http\\Message\\Request::setResponseBody()`\n* Cleaning up `Guzzle\\Common\\Collection::inject` method\n* Adding a response_body location to service descriptions\n\n## 3.0.6 - 2012-12-09\n\n* CurlMulti performance improvements\n* Adding setErrorResponses() to Operation\n* composer.json tweaks\n\n## 3.0.5 - 2012-11-18\n\n* Bug: Fixing an infinite recursion bug caused from revalidating with the CachePlugin\n* Bug: Response body can now be a string containing \"0\"\n* Bug: Using Guzzle inside of a phar uses system by default but now allows for a custom cacert\n* Bug: QueryString::fromString now properly parses query string parameters that contain equal signs\n* Added support for XML attributes in service description responses\n* DefaultRequestSerializer now supports array URI parameter values for URI template expansion\n* Added better mimetype guessing to requests and post files\n\n## 3.0.4 - 2012-11-11\n\n* Bug: Fixed a bug when adding multiple cookies to a request to use the correct glue value\n* Bug: Cookies can now be added that have a name, domain, or value set to \"0\"\n* Bug: Using the system cacert bundle when using the Phar\n* Added json and xml methods to Response to make it easier to parse JSON and XML response data into data structures\n* Enhanced cookie jar de-duplication\n* Added the ability to enable strict cookie jars that throw exceptions when invalid cookies are added\n* Added setStream to StreamInterface to actually make it possible to implement custom rewind behavior for entity bodies\n* Added the ability to create any sort of hash for a stream rather than just an MD5 hash\n\n## 3.0.3 - 2012-11-04\n\n* Implementing redirects in PHP rather than cURL\n* Added PECL URI template extension and using as default parser if available\n* Bug: Fixed Content-Length parsing of Response factory\n* Adding rewind() method to entity bodies and streams. Allows for custom rewinding of non-repeatable streams.\n* Adding ToArrayInterface throughout library\n* Fixing OauthPlugin to create unique nonce values per request\n\n## 3.0.2 - 2012-10-25\n\n* Magic methods are enabled by default on clients\n* Magic methods return the result of a command\n* Service clients no longer require a base_url option in the factory\n* Bug: Fixed an issue with URI templates where null template variables were being expanded\n\n## 3.0.1 - 2012-10-22\n\n* Models can now be used like regular collection objects by calling filter, map, etc.\n* Models no longer require a Parameter structure or initial data in the constructor\n* Added a custom AppendIterator to get around a PHP bug with the `\\AppendIterator`\n\n## 3.0.0 - 2012-10-15\n\n* Rewrote service description format to be based on Swagger\n    * Now based on JSON schema\n    * Added nested input structures and nested response models\n    * Support for JSON and XML input and output models\n    * Renamed `commands` to `operations`\n    * Removed dot class notation\n    * Removed custom types\n* Broke the project into smaller top-level namespaces to be more component friendly\n* Removed support for XML configs and descriptions. Use arrays or JSON files.\n* Removed the Validation component and Inspector\n* Moved all cookie code to Guzzle\\Plugin\\Cookie\n* Magic methods on a Guzzle\\Service\\Client now return the command un-executed.\n* Calling getResult() or getResponse() on a command will lazily execute the command if needed.\n* Now shipping with cURL's CA certs and using it by default\n* Added previousResponse() method to response objects\n* No longer sending Accept and Accept-Encoding headers on every request\n* Only sending an Expect header by default when a payload is greater than 1MB\n* Added/moved client options:\n    * curl.blacklist to curl.option.blacklist\n    * Added ssl.certificate_authority\n* Added a Guzzle\\Iterator component\n* Moved plugins from Guzzle\\Http\\Plugin to Guzzle\\Plugin\n* Added a more robust backoff retry strategy (replaced the ExponentialBackoffPlugin)\n* Added a more robust caching plugin\n* Added setBody to response objects\n* Updating LogPlugin to use a more flexible MessageFormatter\n* Added a completely revamped build process\n* Cleaning up Collection class and removing default values from the get method\n* Fixed ZF2 cache adapters\n\n## 2.8.8 - 2012-10-15\n\n* Bug: Fixed a cookie issue that caused dot prefixed domains to not match where popular browsers did\n\n## 2.8.7 - 2012-09-30\n\n* Bug: Fixed config file aliases for JSON includes\n* Bug: Fixed cookie bug on a request object by using CookieParser to parse cookies on requests\n* Bug: Removing the path to a file when sending a Content-Disposition header on a POST upload\n* Bug: Hardening request and response parsing to account for missing parts\n* Bug: Fixed PEAR packaging\n* Bug: Fixed Request::getInfo\n* Bug: Fixed cases where CURLM_CALL_MULTI_PERFORM return codes were causing curl transactions to fail\n* Adding the ability for the namespace Iterator factory to look in multiple directories\n* Added more getters/setters/removers from service descriptions\n* Added the ability to remove POST fields from OAuth signatures\n* OAuth plugin now supports 2-legged OAuth\n\n## 2.8.6 - 2012-09-05\n\n* Added the ability to modify and build service descriptions\n* Added the use of visitors to apply parameters to locations in service descriptions using the dynamic command\n* Added a `json` parameter location\n* Now allowing dot notation for classes in the CacheAdapterFactory\n* Using the union of two arrays rather than an array_merge when extending service builder services and service params\n* Ensuring that a service is a string before doing strpos() checks on it when substituting services for references\n  in service builder config files.\n* Services defined in two different config files that include one another will by default replace the previously\n  defined service, but you can now create services that extend themselves and merge their settings over the previous\n* The JsonLoader now supports aliasing filenames with different filenames. This allows you to alias something like\n  '_default' with a default JSON configuration file.\n\n## 2.8.5 - 2012-08-29\n\n* Bug: Suppressed empty arrays from URI templates\n* Bug: Added the missing $options argument from ServiceDescription::factory to enable caching\n* Added support for HTTP responses that do not contain a reason phrase in the start-line\n* AbstractCommand commands are now invokable\n* Added a way to get the data used when signing an Oauth request before a request is sent\n\n## 2.8.4 - 2012-08-15\n\n* Bug: Custom delay time calculations are no longer ignored in the ExponentialBackoffPlugin\n* Added the ability to transfer entity bodies as a string rather than streamed. This gets around curl error 65. Set `body_as_string` in a request's curl options to enable.\n* Added a StreamInterface, EntityBodyInterface, and added ftell() to Guzzle\\Common\\Stream\n* Added an AbstractEntityBodyDecorator and a ReadLimitEntityBody decorator to transfer only a subset of a decorated stream\n* Stream and EntityBody objects will now return the file position to the previous position after a read required operation (e.g. getContentMd5())\n* Added additional response status codes\n* Removed SSL information from the default User-Agent header\n* DELETE requests can now send an entity body\n* Added an EventDispatcher to the ExponentialBackoffPlugin and added an ExponentialBackoffLogger to log backoff retries\n* Added the ability of the MockPlugin to consume mocked request bodies\n* LogPlugin now exposes request and response objects in the extras array\n\n## 2.8.3 - 2012-07-30\n\n* Bug: Fixed a case where empty POST requests were sent as GET requests\n* Bug: Fixed a bug in ExponentialBackoffPlugin that caused fatal errors when retrying an EntityEnclosingRequest that does not have a body\n* Bug: Setting the response body of a request to null after completing a request, not when setting the state of a request to new\n* Added multiple inheritance to service description commands\n* Added an ApiCommandInterface and added `getParamNames()` and `hasParam()`\n* Removed the default 2mb size cutoff from the Md5ValidatorPlugin so that it now defaults to validating everything\n* Changed CurlMulti::perform to pass a smaller timeout to CurlMulti::executeHandles\n\n## 2.8.2 - 2012-07-24\n\n* Bug: Query string values set to 0 are no longer dropped from the query string\n* Bug: A Collection object is no longer created each time a call is made to `Guzzle\\Service\\Command\\AbstractCommand::getRequestHeaders()`\n* Bug: `+` is now treated as an encoded space when parsing query strings\n* QueryString and Collection performance improvements\n* Allowing dot notation for class paths in filters attribute of a service descriptions\n\n## 2.8.1 - 2012-07-16\n\n* Loosening Event Dispatcher dependency\n* POST redirects can now be customized using CURLOPT_POSTREDIR\n\n## 2.8.0 - 2012-07-15\n\n* BC: Guzzle\\Http\\Query\n    * Query strings with empty variables will always show an equal sign unless the variable is set to QueryString::BLANK (e.g. ?acl= vs ?acl)\n    * Changed isEncodingValues() and isEncodingFields() to isUrlEncoding()\n    * Changed setEncodeValues(bool) and setEncodeFields(bool) to useUrlEncoding(bool)\n    * Changed the aggregation functions of QueryString to be static methods\n    * Can now use fromString() with querystrings that have a leading ?\n* cURL configuration values can be specified in service descriptions using `curl.` prefixed parameters\n* Content-Length is set to 0 before emitting the request.before_send event when sending an empty request body\n* Cookies are no longer URL decoded by default\n* Bug: URI template variables set to null are no longer expanded\n\n## 2.7.2 - 2012-07-02\n\n* BC: Moving things to get ready for subtree splits. Moving Inflection into Common. Moving Guzzle\\Http\\Parser to Guzzle\\Parser.\n* BC: Removing Guzzle\\Common\\Batch\\Batch::count() and replacing it with isEmpty()\n* CachePlugin now allows for a custom request parameter function to check if a request can be cached\n* Bug fix: CachePlugin now only caches GET and HEAD requests by default\n* Bug fix: Using header glue when transferring headers over the wire\n* Allowing deeply nested arrays for composite variables in URI templates\n* Batch divisors can now return iterators or arrays\n\n## 2.7.1 - 2012-06-26\n\n* Minor patch to update version number in UA string\n* Updating build process\n\n## 2.7.0 - 2012-06-25\n\n* BC: Inflection classes moved to Guzzle\\Inflection. No longer static methods. Can now inject custom inflectors into classes.\n* BC: Removed magic setX methods from commands\n* BC: Magic methods mapped to service description commands are now inflected in the command factory rather than the client __call() method\n* Verbose cURL options are no longer enabled by default. Set curl.debug to true on a client to enable.\n* Bug: Now allowing colons in a response start-line (e.g. HTTP/1.1 503 Service Unavailable: Back-end server is at capacity)\n* Guzzle\\Service\\Resource\\ResourceIteratorApplyBatched now internally uses the Guzzle\\Common\\Batch namespace\n* Added Guzzle\\Service\\Plugin namespace and a PluginCollectionPlugin\n* Added the ability to set POST fields and files in a service description\n* Guzzle\\Http\\EntityBody::factory() now accepts objects with a __toString() method\n* Adding a command.before_prepare event to clients\n* Added BatchClosureTransfer and BatchClosureDivisor\n* BatchTransferException now includes references to the batch divisor and transfer strategies\n* Fixed some tests so that they pass more reliably\n* Added Guzzle\\Common\\Log\\ArrayLogAdapter\n\n## 2.6.6 - 2012-06-10\n\n* BC: Removing Guzzle\\Http\\Plugin\\BatchQueuePlugin\n* BC: Removing Guzzle\\Service\\Command\\CommandSet\n* Adding generic batching system (replaces the batch queue plugin and command set)\n* Updating ZF cache and log adapters and now using ZF's composer repository\n* Bug: Setting the name of each ApiParam when creating through an ApiCommand\n* Adding result_type, result_doc, deprecated, and doc_url to service descriptions\n* Bug: Changed the default cookie header casing back to 'Cookie'\n\n## 2.6.5 - 2012-06-03\n\n* BC: Renaming Guzzle\\Http\\Message\\RequestInterface::getResourceUri() to getResource()\n* BC: Removing unused AUTH_BASIC and AUTH_DIGEST constants from\n* BC: Guzzle\\Http\\Cookie is now used to manage Set-Cookie data, not Cookie data\n* BC: Renaming methods in the CookieJarInterface\n* Moving almost all cookie logic out of the CookiePlugin and into the Cookie or CookieJar implementations\n* Making the default glue for HTTP headers ';' instead of ','\n* Adding a removeValue to Guzzle\\Http\\Message\\Header\n* Adding getCookies() to request interface.\n* Making it easier to add event subscribers to HasDispatcherInterface classes. Can now directly call addSubscriber()\n\n## 2.6.4 - 2012-05-30\n\n* BC: Cleaning up how POST files are stored in EntityEnclosingRequest objects. Adding PostFile class.\n* BC: Moving ApiCommand specific functionality from the Inspector and on to the ApiCommand\n* Bug: Fixing magic method command calls on clients\n* Bug: Email constraint only validates strings\n* Bug: Aggregate POST fields when POST files are present in curl handle\n* Bug: Fixing default User-Agent header\n* Bug: Only appending or prepending parameters in commands if they are specified\n* Bug: Not requiring response reason phrases or status codes to match a predefined list of codes\n* Allowing the use of dot notation for class namespaces when using instance_of constraint\n* Added any_match validation constraint\n* Added an AsyncPlugin\n* Passing request object to the calculateWait method of the ExponentialBackoffPlugin\n* Allowing the result of a command object to be changed\n* Parsing location and type sub values when instantiating a service description rather than over and over at runtime\n\n## 2.6.3 - 2012-05-23\n\n* [BC] Guzzle\\Common\\FromConfigInterface no longer requires any config options.\n* [BC] Refactoring how POST files are stored on an EntityEnclosingRequest. They are now separate from POST fields.\n* You can now use an array of data when creating PUT request bodies in the request factory.\n* Removing the requirement that HTTPS requests needed a Cache-Control: public directive to be cacheable.\n* [Http] Adding support for Content-Type in multipart POST uploads per upload\n* [Http] Added support for uploading multiple files using the same name (foo[0], foo[1])\n* Adding more POST data operations for easier manipulation of POST data.\n* You can now set empty POST fields.\n* The body of a request is only shown on EntityEnclosingRequest objects that do not use POST files.\n* Split the Guzzle\\Service\\Inspector::validateConfig method into two methods. One to initialize when a command is created, and one to validate.\n* CS updates\n\n## 2.6.2 - 2012-05-19\n\n* [Http] Better handling of nested scope requests in CurlMulti.  Requests are now always prepares in the send() method rather than the addRequest() method.\n\n## 2.6.1 - 2012-05-19\n\n* [BC] Removing 'path' support in service descriptions.  Use 'uri'.\n* [BC] Guzzle\\Service\\Inspector::parseDocBlock is now protected. Adding getApiParamsForClass() with cache.\n* [BC] Removing Guzzle\\Common\\NullObject.  Use https://github.com/mtdowling/NullObject if you need it.\n* [BC] Removing Guzzle\\Common\\XmlElement.\n* All commands, both dynamic and concrete, have ApiCommand objects.\n* Adding a fix for CurlMulti so that if all of the connections encounter some sort of curl error, then the loop exits.\n* Adding checks to EntityEnclosingRequest so that empty POST files and fields are ignored.\n* Making the method signature of Guzzle\\Service\\Builder\\ServiceBuilder::factory more flexible.\n\n## 2.6.0 - 2012-05-15\n\n* [BC] Moving Guzzle\\Service\\Builder to Guzzle\\Service\\Builder\\ServiceBuilder\n* [BC] Executing a Command returns the result of the command rather than the command\n* [BC] Moving all HTTP parsing logic to Guzzle\\Http\\Parsers. Allows for faster C implementations if needed.\n* [BC] Changing the Guzzle\\Http\\Message\\Response::setProtocol() method to accept a protocol and version in separate args.\n* [BC] Moving ResourceIterator* to Guzzle\\Service\\Resource\n* [BC] Completely refactored ResourceIterators to iterate over a cloned command object\n* [BC] Moved Guzzle\\Http\\UriTemplate to Guzzle\\Http\\Parser\\UriTemplate\\UriTemplate\n* [BC] Guzzle\\Guzzle is now deprecated\n* Moving Guzzle\\Common\\Guzzle::inject to Guzzle\\Common\\Collection::inject\n* Adding Guzzle\\Version class to give version information about Guzzle\n* Adding Guzzle\\Http\\Utils class to provide getDefaultUserAgent() and getHttpDate()\n* Adding Guzzle\\Curl\\CurlVersion to manage caching curl_version() data\n* ServiceDescription and ServiceBuilder are now cacheable using similar configs\n* Changing the format of XML and JSON service builder configs.  Backwards compatible.\n* Cleaned up Cookie parsing\n* Trimming the default Guzzle User-Agent header\n* Adding a setOnComplete() method to Commands that is called when a command completes\n* Keeping track of requests that were mocked in the MockPlugin\n* Fixed a caching bug in the CacheAdapterFactory\n* Inspector objects can be injected into a Command object\n* Refactoring a lot of code and tests to be case insensitive when dealing with headers\n* Adding Guzzle\\Http\\Message\\HeaderComparison for easy comparison of HTTP headers using a DSL\n* Adding the ability to set global option overrides to service builder configs\n* Adding the ability to include other service builder config files from within XML and JSON files\n* Moving the parseQuery method out of Url and on to QueryString::fromString() as a static factory method.\n\n## 2.5.0 - 2012-05-08\n\n* Major performance improvements\n* [BC] Simplifying Guzzle\\Common\\Collection.  Please check to see if you are using features that are now deprecated.\n* [BC] Using a custom validation system that allows a flyweight implementation for much faster validation. No longer using Symfony2 Validation component.\n* [BC] No longer supporting \"{{ }}\" for injecting into command or UriTemplates.  Use \"{}\"\n* Added the ability to passed parameters to all requests created by a client\n* Added callback functionality to the ExponentialBackoffPlugin\n* Using microtime in ExponentialBackoffPlugin to allow more granular backoff strategies.\n* Rewinding request stream bodies when retrying requests\n* Exception is thrown when JSON response body cannot be decoded\n* Added configurable magic method calls to clients and commands.  This is off by default.\n* Fixed a defect that added a hash to every parsed URL part\n* Fixed duplicate none generation for OauthPlugin.\n* Emitting an event each time a client is generated by a ServiceBuilder\n* Using an ApiParams object instead of a Collection for parameters of an ApiCommand\n* cache.* request parameters should be renamed to params.cache.*\n* Added the ability to set arbitrary curl options on requests (disable_wire, progress, etc.). See CurlHandle.\n* Added the ability to disable type validation of service descriptions\n* ServiceDescriptions and ServiceBuilders are now Serializable\n"
  },
  {
    "path": "server/vendor/guzzlehttp/guzzle/Dockerfile",
    "content": "FROM composer:latest as setup\n\nRUN mkdir /guzzle\n\nWORKDIR /guzzle\n\nRUN set -xe \\\n    && composer init --name=guzzlehttp/test --description=\"Simple project for testing Guzzle scripts\" --author=\"Márk Sági-Kazár <mark.sagikazar@gmail.com>\" --no-interaction \\\n    && composer require guzzlehttp/guzzle\n\n\nFROM php:7.3\n\nRUN mkdir /guzzle\n\nWORKDIR /guzzle\n\nCOPY --from=setup /guzzle /guzzle\n"
  },
  {
    "path": "server/vendor/guzzlehttp/guzzle/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2011 Michael Dowling <mtdowling@gmail.com>\nCopyright (c) 2012 Jeremy Lindblom <jeremeamia@gmail.com>\nCopyright (c) 2014 Graham Campbell <hello@gjcampbell.co.uk>\nCopyright (c) 2015 Márk Sági-Kazár <mark.sagikazar@gmail.com>\nCopyright (c) 2015 Tobias Schultze <webmaster@tubo-world.de>\nCopyright (c) 2016 Tobias Nyholm <tobias.nyholm@gmail.com>\nCopyright (c) 2016 George Mponos <gmponos@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "server/vendor/guzzlehttp/guzzle/README.md",
    "content": "![Guzzle](.github/logo.png?raw=true)\n\n# Guzzle, PHP HTTP client\n\n[![Latest Version](https://img.shields.io/github/release/guzzle/guzzle.svg?style=flat-square)](https://github.com/guzzle/guzzle/releases)\n[![Build Status](https://img.shields.io/github/workflow/status/guzzle/guzzle/CI?label=ci%20build&style=flat-square)](https://github.com/guzzle/guzzle/actions?query=workflow%3ACI)\n[![Total Downloads](https://img.shields.io/packagist/dt/guzzlehttp/guzzle.svg?style=flat-square)](https://packagist.org/packages/guzzlehttp/guzzle)\n\nGuzzle is a PHP HTTP client that makes it easy to send HTTP requests and\ntrivial to integrate with web services.\n\n- Simple interface for building query strings, POST requests, streaming large\n  uploads, streaming large downloads, using HTTP cookies, uploading JSON data,\n  etc...\n- Can send both synchronous and asynchronous requests using the same interface.\n- Uses PSR-7 interfaces for requests, responses, and streams. This allows you\n  to utilize other PSR-7 compatible libraries with Guzzle.\n- Abstracts away the underlying HTTP transport, allowing you to write\n  environment and transport agnostic code; i.e., no hard dependency on cURL,\n  PHP streams, sockets, or non-blocking event loops.\n- Middleware system allows you to augment and compose client behavior.\n\n```php\n$client = new \\GuzzleHttp\\Client();\n$response = $client->request('GET', 'https://api.github.com/repos/guzzle/guzzle');\n\necho $response->getStatusCode(); # 200\necho $response->getHeaderLine('content-type'); # 'application/json; charset=utf8'\necho $response->getBody(); # '{\"id\": 1420053, \"name\": \"guzzle\", ...}'\n\n# Send an asynchronous request.\n$request = new \\GuzzleHttp\\Psr7\\Request('GET', 'http://httpbin.org');\n$promise = $client->sendAsync($request)->then(function ($response) {\n    echo 'I completed! ' . $response->getBody();\n});\n\n$promise->wait();\n```\n\n## Help and docs\n\nWe use GitHub issues only to discuss bugs and new features. For support please refer to:\n\n- [Documentation](https://docs.guzzlephp.org)\n- [Stack Overflow](https://stackoverflow.com/questions/tagged/guzzle)\n- [#guzzle](https://app.slack.com/client/T0D2S9JCT/CE6UAAKL4) channel on [PHP-HTTP Slack](https://slack.httplug.io/)\n- [Gitter](https://gitter.im/guzzle/guzzle)\n\n\n## Installing Guzzle\n\nThe recommended way to install Guzzle is through\n[Composer](https://getcomposer.org/).\n\n```bash\n# Install Composer\ncurl -sS https://getcomposer.org/installer | php\n```\n\nNext, run the Composer command to install the latest stable version of Guzzle:\n\n```bash\ncomposer require guzzlehttp/guzzle\n```\n\nAfter installing, you need to require Composer's autoloader:\n\n```php\nrequire 'vendor/autoload.php';\n```\n\nYou can then later update Guzzle using composer:\n\n ```bash\ncomposer update\n ```\n\n\n## Version Guidance\n\n| Version | Status         | Packagist           | Namespace    | Repo                | Docs                | PSR-7 | PHP Version  |\n|---------|----------------|---------------------|--------------|---------------------|---------------------|-------|--------------|\n| 3.x     | EOL            | `guzzle/guzzle`     | `Guzzle`     | [v3][guzzle-3-repo] | [v3][guzzle-3-docs] | No    | >=5.3.3,<7.0 |\n| 4.x     | EOL            | `guzzlehttp/guzzle` | `GuzzleHttp` | [v4][guzzle-4-repo] | N/A                 | No    | >=5.4,<7.0   |\n| 5.x     | EOL            | `guzzlehttp/guzzle` | `GuzzleHttp` | [v5][guzzle-5-repo] | [v5][guzzle-5-docs] | No    | >=5.4,<7.4   |\n| 6.x     | Security fixes | `guzzlehttp/guzzle` | `GuzzleHttp` | [v6][guzzle-6-repo] | [v6][guzzle-6-docs] | Yes   | >=5.5,<8.0   |\n| 7.x     | Latest         | `guzzlehttp/guzzle` | `GuzzleHttp` | [v7][guzzle-7-repo] | [v7][guzzle-7-docs] | Yes   | >=7.2.5,<8.2 |\n\n[guzzle-3-repo]: https://github.com/guzzle/guzzle3\n[guzzle-4-repo]: https://github.com/guzzle/guzzle/tree/4.x\n[guzzle-5-repo]: https://github.com/guzzle/guzzle/tree/5.3\n[guzzle-6-repo]: https://github.com/guzzle/guzzle/tree/6.5\n[guzzle-7-repo]: https://github.com/guzzle/guzzle\n[guzzle-3-docs]: https://guzzle3.readthedocs.io/\n[guzzle-5-docs]: https://docs.guzzlephp.org/en/5.3/\n[guzzle-6-docs]: https://docs.guzzlephp.org/en/6.5/\n[guzzle-7-docs]: https://docs.guzzlephp.org/en/latest/\n"
  },
  {
    "path": "server/vendor/guzzlehttp/guzzle/UPGRADING.md",
    "content": "Guzzle Upgrade Guide\n====================\n\n5.0 to 6.0\n----------\n\nGuzzle now uses [PSR-7](http://www.php-fig.org/psr/psr-7/) for HTTP messages.\nDue to the fact that these messages are immutable, this prompted a refactoring\nof Guzzle to use a middleware based system rather than an event system. Any\nHTTP message interaction (e.g., `GuzzleHttp\\Message\\Request`) need to be\nupdated to work with the new immutable PSR-7 request and response objects. Any\nevent listeners or subscribers need to be updated to become middleware\nfunctions that wrap handlers (or are injected into a\n`GuzzleHttp\\HandlerStack`).\n\n- Removed `GuzzleHttp\\BatchResults`\n- Removed `GuzzleHttp\\Collection`\n- Removed `GuzzleHttp\\HasDataTrait`\n- Removed `GuzzleHttp\\ToArrayInterface`\n- The `guzzlehttp/streams` dependency has been removed. Stream functionality\n  is now present in the `GuzzleHttp\\Psr7` namespace provided by the\n  `guzzlehttp/psr7` package.\n- Guzzle no longer uses ReactPHP promises and now uses the\n  `guzzlehttp/promises` library. We use a custom promise library for three\n  significant reasons:\n  1. React promises (at the time of writing this) are recursive. Promise\n     chaining and promise resolution will eventually blow the stack. Guzzle\n     promises are not recursive as they use a sort of trampolining technique.\n     Note: there has been movement in the React project to modify promises to\n     no longer utilize recursion.\n  2. Guzzle needs to have the ability to synchronously block on a promise to\n     wait for a result. Guzzle promises allows this functionality (and does\n     not require the use of recursion).\n  3. Because we need to be able to wait on a result, doing so using React\n     promises requires wrapping react promises with RingPHP futures. This\n     overhead is no longer needed, reducing stack sizes, reducing complexity,\n     and improving performance.\n- `GuzzleHttp\\Mimetypes` has been moved to a function in\n  `GuzzleHttp\\Psr7\\mimetype_from_extension` and\n  `GuzzleHttp\\Psr7\\mimetype_from_filename`.\n- `GuzzleHttp\\Query` and `GuzzleHttp\\QueryParser` have been removed. Query\n  strings must now be passed into request objects as strings, or provided to\n  the `query` request option when creating requests with clients. The `query`\n  option uses PHP's `http_build_query` to convert an array to a string. If you\n  need a different serialization technique, you will need to pass the query\n  string in as a string. There are a couple helper functions that will make\n  working with query strings easier: `GuzzleHttp\\Psr7\\parse_query` and\n  `GuzzleHttp\\Psr7\\build_query`.\n- Guzzle no longer has a dependency on RingPHP. Due to the use of a middleware\n  system based on PSR-7, using RingPHP and it's middleware system as well adds\n  more complexity than the benefits it provides. All HTTP handlers that were\n  present in RingPHP have been modified to work directly with PSR-7 messages\n  and placed in the `GuzzleHttp\\Handler` namespace. This significantly reduces\n  complexity in Guzzle, removes a dependency, and improves performance. RingPHP\n  will be maintained for Guzzle 5 support, but will no longer be a part of\n  Guzzle 6.\n- As Guzzle now uses a middleware based systems the event system and RingPHP\n  integration has been removed. Note: while the event system has been removed,\n  it is possible to add your own type of event system that is powered by the\n  middleware system.\n  - Removed the `Event` namespace.\n  - Removed the `Subscriber` namespace.\n  - Removed `Transaction` class\n  - Removed `RequestFsm`\n  - Removed `RingBridge`\n  - `GuzzleHttp\\Subscriber\\Cookie` is now provided by\n    `GuzzleHttp\\Middleware::cookies`\n  - `GuzzleHttp\\Subscriber\\HttpError` is now provided by\n    `GuzzleHttp\\Middleware::httpError`\n  - `GuzzleHttp\\Subscriber\\History` is now provided by\n    `GuzzleHttp\\Middleware::history`\n  - `GuzzleHttp\\Subscriber\\Mock` is now provided by\n    `GuzzleHttp\\Handler\\MockHandler`\n  - `GuzzleHttp\\Subscriber\\Prepare` is now provided by\n    `GuzzleHttp\\PrepareBodyMiddleware`\n  - `GuzzleHttp\\Subscriber\\Redirect` is now provided by\n    `GuzzleHttp\\RedirectMiddleware`\n- Guzzle now uses `Psr\\Http\\Message\\UriInterface` (implements in\n  `GuzzleHttp\\Psr7\\Uri`) for URI support. `GuzzleHttp\\Url` is now gone.\n- Static functions in `GuzzleHttp\\Utils` have been moved to namespaced\n  functions under the `GuzzleHttp` namespace. This requires either a Composer\n  based autoloader or you to include functions.php.\n- `GuzzleHttp\\ClientInterface::getDefaultOption` has been renamed to\n  `GuzzleHttp\\ClientInterface::getConfig`.\n- `GuzzleHttp\\ClientInterface::setDefaultOption` has been removed.\n- The `json` and `xml` methods of response objects has been removed. With the\n  migration to strictly adhering to PSR-7 as the interface for Guzzle messages,\n  adding methods to message interfaces would actually require Guzzle messages\n  to extend from PSR-7 messages rather then work with them directly.\n\n## Migrating to middleware\n\nThe change to PSR-7 unfortunately required significant refactoring to Guzzle\ndue to the fact that PSR-7 messages are immutable. Guzzle 5 relied on an event\nsystem from plugins. The event system relied on mutability of HTTP messages and\nside effects in order to work. With immutable messages, you have to change your\nworkflow to become more about either returning a value (e.g., functional\nmiddlewares) or setting a value on an object. Guzzle v6 has chosen the\nfunctional middleware approach.\n\nInstead of using the event system to listen for things like the `before` event,\nyou now create a stack based middleware function that intercepts a request on\nthe way in and the promise of the response on the way out. This is a much\nsimpler and more predictable approach than the event system and works nicely\nwith PSR-7 middleware. Due to the use of promises, the middleware system is\nalso asynchronous.\n\nv5:\n\n```php\nuse GuzzleHttp\\Event\\BeforeEvent;\n$client = new GuzzleHttp\\Client();\n// Get the emitter and listen to the before event.\n$client->getEmitter()->on('before', function (BeforeEvent $e) {\n    // Guzzle v5 events relied on mutation\n    $e->getRequest()->setHeader('X-Foo', 'Bar');\n});\n```\n\nv6:\n\nIn v6, you can modify the request before it is sent using the `mapRequest`\nmiddleware. The idiomatic way in v6 to modify the request/response lifecycle is\nto setup a handler middleware stack up front and inject the handler into a\nclient.\n\n```php\nuse GuzzleHttp\\Middleware;\n// Create a handler stack that has all of the default middlewares attached\n$handler = GuzzleHttp\\HandlerStack::create();\n// Push the handler onto the handler stack\n$handler->push(Middleware::mapRequest(function (RequestInterface $request) {\n    // Notice that we have to return a request object\n    return $request->withHeader('X-Foo', 'Bar');\n}));\n// Inject the handler into the client\n$client = new GuzzleHttp\\Client(['handler' => $handler]);\n```\n\n## POST Requests\n\nThis version added the [`form_params`](http://guzzle.readthedocs.org/en/latest/request-options.html#form_params)\nand `multipart` request options. `form_params` is an associative array of\nstrings or array of strings and is used to serialize an\n`application/x-www-form-urlencoded` POST request. The\n[`multipart`](http://guzzle.readthedocs.org/en/latest/request-options.html#multipart)\noption is now used to send a multipart/form-data POST request.\n\n`GuzzleHttp\\Post\\PostFile` has been removed. Use the `multipart` option to add\nPOST files to a multipart/form-data request.\n\nThe `body` option no longer accepts an array to send POST requests. Please use\n`multipart` or `form_params` instead.\n\nThe `base_url` option has been renamed to `base_uri`.\n\n4.x to 5.0\n----------\n\n## Rewritten Adapter Layer\n\nGuzzle now uses [RingPHP](http://ringphp.readthedocs.org/en/latest) to send\nHTTP requests. The `adapter` option in a `GuzzleHttp\\Client` constructor\nis still supported, but it has now been renamed to `handler`. Instead of\npassing a `GuzzleHttp\\Adapter\\AdapterInterface`, you must now pass a PHP\n`callable` that follows the RingPHP specification.\n\n## Removed Fluent Interfaces\n\n[Fluent interfaces were removed](http://ocramius.github.io/blog/fluent-interfaces-are-evil)\nfrom the following classes:\n\n- `GuzzleHttp\\Collection`\n- `GuzzleHttp\\Url`\n- `GuzzleHttp\\Query`\n- `GuzzleHttp\\Post\\PostBody`\n- `GuzzleHttp\\Cookie\\SetCookie`\n\n## Removed functions.php\n\nRemoved \"functions.php\", so that Guzzle is truly PSR-4 compliant. The following\nfunctions can be used as replacements.\n\n- `GuzzleHttp\\json_decode` -> `GuzzleHttp\\Utils::jsonDecode`\n- `GuzzleHttp\\get_path` -> `GuzzleHttp\\Utils::getPath`\n- `GuzzleHttp\\Utils::setPath` -> `GuzzleHttp\\set_path`\n- `GuzzleHttp\\Pool::batch` -> `GuzzleHttp\\batch`. This function is, however,\n  deprecated in favor of using `GuzzleHttp\\Pool::batch()`.\n\nThe \"procedural\" global client has been removed with no replacement (e.g.,\n`GuzzleHttp\\get()`, `GuzzleHttp\\post()`, etc.). Use a `GuzzleHttp\\Client`\nobject as a replacement.\n\n## `throwImmediately` has been removed\n\nThe concept of \"throwImmediately\" has been removed from exceptions and error\nevents. This control mechanism was used to stop a transfer of concurrent\nrequests from completing. This can now be handled by throwing the exception or\nby cancelling a pool of requests or each outstanding future request\nindividually.\n\n## headers event has been removed\n\nRemoved the \"headers\" event. This event was only useful for changing the\nbody a response once the headers of the response were known. You can implement\na similar behavior in a number of ways. One example might be to use a\nFnStream that has access to the transaction being sent. For example, when the\nfirst byte is written, you could check if the response headers match your\nexpectations, and if so, change the actual stream body that is being\nwritten to.\n\n## Updates to HTTP Messages\n\nRemoved the `asArray` parameter from\n`GuzzleHttp\\Message\\MessageInterface::getHeader`. If you want to get a header\nvalue as an array, then use the newly added `getHeaderAsArray()` method of\n`MessageInterface`. This change makes the Guzzle interfaces compatible with\nthe PSR-7 interfaces.\n\n3.x to 4.0\n----------\n\n## Overarching changes:\n\n- Now requires PHP 5.4 or greater.\n- No longer requires cURL to send requests.\n- Guzzle no longer wraps every exception it throws. Only exceptions that are\n  recoverable are now wrapped by Guzzle.\n- Various namespaces have been removed or renamed.\n- No longer requiring the Symfony EventDispatcher. A custom event dispatcher\n  based on the Symfony EventDispatcher is\n  now utilized in `GuzzleHttp\\Event\\EmitterInterface` (resulting in significant\n  speed and functionality improvements).\n\nChanges per Guzzle 3.x namespace are described below.\n\n## Batch\n\nThe `Guzzle\\Batch` namespace has been removed. This is best left to\nthird-parties to implement on top of Guzzle's core HTTP library.\n\n## Cache\n\nThe `Guzzle\\Cache` namespace has been removed. (Todo: No suitable replacement\nhas been implemented yet, but hoping to utilize a PSR cache interface).\n\n## Common\n\n- Removed all of the wrapped exceptions. It's better to use the standard PHP\n  library for unrecoverable exceptions.\n- `FromConfigInterface` has been removed.\n- `Guzzle\\Common\\Version` has been removed. The VERSION constant can be found\n  at `GuzzleHttp\\ClientInterface::VERSION`.\n\n### Collection\n\n- `getAll` has been removed. Use `toArray` to convert a collection to an array.\n- `inject` has been removed.\n- `keySearch` has been removed.\n- `getPath` no longer supports wildcard expressions. Use something better like\n  JMESPath for this.\n- `setPath` now supports appending to an existing array via the `[]` notation.\n\n### Events\n\nGuzzle no longer requires Symfony's EventDispatcher component. Guzzle now uses\n`GuzzleHttp\\Event\\Emitter`.\n\n- `Symfony\\Component\\EventDispatcher\\EventDispatcherInterface` is replaced by\n  `GuzzleHttp\\Event\\EmitterInterface`.\n- `Symfony\\Component\\EventDispatcher\\EventDispatcher` is replaced by\n  `GuzzleHttp\\Event\\Emitter`.\n- `Symfony\\Component\\EventDispatcher\\Event` is replaced by\n  `GuzzleHttp\\Event\\Event`, and Guzzle now has an EventInterface in\n  `GuzzleHttp\\Event\\EventInterface`.\n- `AbstractHasDispatcher` has moved to a trait, `HasEmitterTrait`, and\n  `HasDispatcherInterface` has moved to `HasEmitterInterface`. Retrieving the\n  event emitter of a request, client, etc. now uses the `getEmitter` method\n  rather than the `getDispatcher` method.\n\n#### Emitter\n\n- Use the `once()` method to add a listener that automatically removes itself\n  the first time it is invoked.\n- Use the `listeners()` method to retrieve a list of event listeners rather than\n  the `getListeners()` method.\n- Use `emit()` instead of `dispatch()` to emit an event from an emitter.\n- Use `attach()` instead of `addSubscriber()` and `detach()` instead of\n  `removeSubscriber()`.\n\n```php\n$mock = new Mock();\n// 3.x\n$request->getEventDispatcher()->addSubscriber($mock);\n$request->getEventDispatcher()->removeSubscriber($mock);\n// 4.x\n$request->getEmitter()->attach($mock);\n$request->getEmitter()->detach($mock);\n```\n\nUse the `on()` method to add a listener rather than the `addListener()` method.\n\n```php\n// 3.x\n$request->getEventDispatcher()->addListener('foo', function (Event $event) { /* ... */ } );\n// 4.x\n$request->getEmitter()->on('foo', function (Event $event, $name) { /* ... */ } );\n```\n\n## Http\n\n### General changes\n\n- The cacert.pem certificate has been moved to `src/cacert.pem`.\n- Added the concept of adapters that are used to transfer requests over the\n  wire.\n- Simplified the event system.\n- Sending requests in parallel is still possible, but batching is no longer a\n  concept of the HTTP layer. Instead, you must use the `complete` and `error`\n  events to asynchronously manage parallel request transfers.\n- `Guzzle\\Http\\Url` has moved to `GuzzleHttp\\Url`.\n- `Guzzle\\Http\\QueryString` has moved to `GuzzleHttp\\Query`.\n- QueryAggregators have been rewritten so that they are simply callable\n  functions.\n- `GuzzleHttp\\StaticClient` has been removed. Use the functions provided in\n  `functions.php` for an easy to use static client instance.\n- Exceptions in `GuzzleHttp\\Exception` have been updated to all extend from\n  `GuzzleHttp\\Exception\\TransferException`.\n\n### Client\n\nCalling methods like `get()`, `post()`, `head()`, etc. no longer create and\nreturn a request, but rather creates a request, sends the request, and returns\nthe response.\n\n```php\n// 3.0\n$request = $client->get('/');\n$response = $request->send();\n\n// 4.0\n$response = $client->get('/');\n\n// or, to mirror the previous behavior\n$request = $client->createRequest('GET', '/');\n$response = $client->send($request);\n```\n\n`GuzzleHttp\\ClientInterface` has changed.\n\n- The `send` method no longer accepts more than one request. Use `sendAll` to\n  send multiple requests in parallel.\n- `setUserAgent()` has been removed. Use a default request option instead. You\n  could, for example, do something like:\n  `$client->setConfig('defaults/headers/User-Agent', 'Foo/Bar ' . $client::getDefaultUserAgent())`.\n- `setSslVerification()` has been removed. Use default request options instead,\n  like `$client->setConfig('defaults/verify', true)`.\n\n`GuzzleHttp\\Client` has changed.\n\n- The constructor now accepts only an associative array. You can include a\n  `base_url` string or array to use a URI template as the base URL of a client.\n  You can also specify a `defaults` key that is an associative array of default\n  request options. You can pass an `adapter` to use a custom adapter,\n  `batch_adapter` to use a custom adapter for sending requests in parallel, or\n  a `message_factory` to change the factory used to create HTTP requests and\n  responses.\n- The client no longer emits a `client.create_request` event.\n- Creating requests with a client no longer automatically utilize a URI\n  template. You must pass an array into a creational method (e.g.,\n  `createRequest`, `get`, `put`, etc.) in order to expand a URI template.\n\n### Messages\n\nMessages no longer have references to their counterparts (i.e., a request no\nlonger has a reference to it's response, and a response no loger has a\nreference to its request). This association is now managed through a\n`GuzzleHttp\\Adapter\\TransactionInterface` object. You can get references to\nthese transaction objects using request events that are emitted over the\nlifecycle of a request.\n\n#### Requests with a body\n\n- `GuzzleHttp\\Message\\EntityEnclosingRequest` and\n  `GuzzleHttp\\Message\\EntityEnclosingRequestInterface` have been removed. The\n  separation between requests that contain a body and requests that do not\n  contain a body has been removed, and now `GuzzleHttp\\Message\\RequestInterface`\n  handles both use cases.\n- Any method that previously accepts a `GuzzleHttp\\Response` object now accept a\n  `GuzzleHttp\\Message\\ResponseInterface`.\n- `GuzzleHttp\\Message\\RequestFactoryInterface` has been renamed to\n  `GuzzleHttp\\Message\\MessageFactoryInterface`. This interface is used to create\n  both requests and responses and is implemented in\n  `GuzzleHttp\\Message\\MessageFactory`.\n- POST field and file methods have been removed from the request object. You\n  must now use the methods made available to `GuzzleHttp\\Post\\PostBodyInterface`\n  to control the format of a POST body. Requests that are created using a\n  standard `GuzzleHttp\\Message\\MessageFactoryInterface` will automatically use\n  a `GuzzleHttp\\Post\\PostBody` body if the body was passed as an array or if\n  the method is POST and no body is provided.\n\n```php\n$request = $client->createRequest('POST', '/');\n$request->getBody()->setField('foo', 'bar');\n$request->getBody()->addFile(new PostFile('file_key', fopen('/path/to/content', 'r')));\n```\n\n#### Headers\n\n- `GuzzleHttp\\Message\\Header` has been removed. Header values are now simply\n  represented by an array of values or as a string. Header values are returned\n  as a string by default when retrieving a header value from a message. You can\n  pass an optional argument of `true` to retrieve a header value as an array\n  of strings instead of a single concatenated string.\n- `GuzzleHttp\\PostFile` and `GuzzleHttp\\PostFileInterface` have been moved to\n  `GuzzleHttp\\Post`. This interface has been simplified and now allows the\n  addition of arbitrary headers.\n- Custom headers like `GuzzleHttp\\Message\\Header\\Link` have been removed. Most\n  of the custom headers are now handled separately in specific\n  subscribers/plugins, and `GuzzleHttp\\Message\\HeaderValues::parseParams()` has\n  been updated to properly handle headers that contain parameters (like the\n  `Link` header).\n\n#### Responses\n\n- `GuzzleHttp\\Message\\Response::getInfo()` and\n  `GuzzleHttp\\Message\\Response::setInfo()` have been removed. Use the event\n  system to retrieve this type of information.\n- `GuzzleHttp\\Message\\Response::getRawHeaders()` has been removed.\n- `GuzzleHttp\\Message\\Response::getMessage()` has been removed.\n- `GuzzleHttp\\Message\\Response::calculateAge()` and other cache specific\n  methods have moved to the CacheSubscriber.\n- Header specific helper functions like `getContentMd5()` have been removed.\n  Just use `getHeader('Content-MD5')` instead.\n- `GuzzleHttp\\Message\\Response::setRequest()` and\n  `GuzzleHttp\\Message\\Response::getRequest()` have been removed. Use the event\n  system to work with request and response objects as a transaction.\n- `GuzzleHttp\\Message\\Response::getRedirectCount()` has been removed. Use the\n  Redirect subscriber instead.\n- `GuzzleHttp\\Message\\Response::isSuccessful()` and other related methods have\n  been removed. Use `getStatusCode()` instead.\n\n#### Streaming responses\n\nStreaming requests can now be created by a client directly, returning a\n`GuzzleHttp\\Message\\ResponseInterface` object that contains a body stream\nreferencing an open PHP HTTP stream.\n\n```php\n// 3.0\nuse Guzzle\\Stream\\PhpStreamRequestFactory;\n$request = $client->get('/');\n$factory = new PhpStreamRequestFactory();\n$stream = $factory->fromRequest($request);\n$data = $stream->read(1024);\n\n// 4.0\n$response = $client->get('/', ['stream' => true]);\n// Read some data off of the stream in the response body\n$data = $response->getBody()->read(1024);\n```\n\n#### Redirects\n\nThe `configureRedirects()` method has been removed in favor of a\n`allow_redirects` request option.\n\n```php\n// Standard redirects with a default of a max of 5 redirects\n$request = $client->createRequest('GET', '/', ['allow_redirects' => true]);\n\n// Strict redirects with a custom number of redirects\n$request = $client->createRequest('GET', '/', [\n    'allow_redirects' => ['max' => 5, 'strict' => true]\n]);\n```\n\n#### EntityBody\n\nEntityBody interfaces and classes have been removed or moved to\n`GuzzleHttp\\Stream`. All classes and interfaces that once required\n`GuzzleHttp\\EntityBodyInterface` now require\n`GuzzleHttp\\Stream\\StreamInterface`. Creating a new body for a request no\nlonger uses `GuzzleHttp\\EntityBody::factory` but now uses\n`GuzzleHttp\\Stream\\Stream::factory` or even better:\n`GuzzleHttp\\Stream\\create()`.\n\n- `Guzzle\\Http\\EntityBodyInterface` is now `GuzzleHttp\\Stream\\StreamInterface`\n- `Guzzle\\Http\\EntityBody` is now `GuzzleHttp\\Stream\\Stream`\n- `Guzzle\\Http\\CachingEntityBody` is now `GuzzleHttp\\Stream\\CachingStream`\n- `Guzzle\\Http\\ReadLimitEntityBody` is now `GuzzleHttp\\Stream\\LimitStream`\n- `Guzzle\\Http\\IoEmittyinEntityBody` has been removed.\n\n#### Request lifecycle events\n\nRequests previously submitted a large number of requests. The number of events\nemitted over the lifecycle of a request has been significantly reduced to make\nit easier to understand how to extend the behavior of a request. All events\nemitted during the lifecycle of a request now emit a custom\n`GuzzleHttp\\Event\\EventInterface` object that contains context providing\nmethods and a way in which to modify the transaction at that specific point in\ntime (e.g., intercept the request and set a response on the transaction).\n\n- `request.before_send` has been renamed to `before` and now emits a\n  `GuzzleHttp\\Event\\BeforeEvent`\n- `request.complete` has been renamed to `complete` and now emits a\n  `GuzzleHttp\\Event\\CompleteEvent`.\n- `request.sent` has been removed. Use `complete`.\n- `request.success` has been removed. Use `complete`.\n- `error` is now an event that emits a `GuzzleHttp\\Event\\ErrorEvent`.\n- `request.exception` has been removed. Use `error`.\n- `request.receive.status_line` has been removed.\n- `curl.callback.progress` has been removed. Use a custom `StreamInterface` to\n  maintain a status update.\n- `curl.callback.write` has been removed. Use a custom `StreamInterface` to\n  intercept writes.\n- `curl.callback.read` has been removed. Use a custom `StreamInterface` to\n  intercept reads.\n\n`headers` is a new event that is emitted after the response headers of a\nrequest have been received before the body of the response is downloaded. This\nevent emits a `GuzzleHttp\\Event\\HeadersEvent`.\n\nYou can intercept a request and inject a response using the `intercept()` event\nof a `GuzzleHttp\\Event\\BeforeEvent`, `GuzzleHttp\\Event\\CompleteEvent`, and\n`GuzzleHttp\\Event\\ErrorEvent` event.\n\nSee: http://docs.guzzlephp.org/en/latest/events.html\n\n## Inflection\n\nThe `Guzzle\\Inflection` namespace has been removed. This is not a core concern\nof Guzzle.\n\n## Iterator\n\nThe `Guzzle\\Iterator` namespace has been removed.\n\n- `Guzzle\\Iterator\\AppendIterator`, `Guzzle\\Iterator\\ChunkedIterator`, and\n  `Guzzle\\Iterator\\MethodProxyIterator` are nice, but not a core requirement of\n  Guzzle itself.\n- `Guzzle\\Iterator\\FilterIterator` is no longer needed because an equivalent\n  class is shipped with PHP 5.4.\n- `Guzzle\\Iterator\\MapIterator` is not really needed when using PHP 5.5 because\n  it's easier to just wrap an iterator in a generator that maps values.\n\nFor a replacement of these iterators, see https://github.com/nikic/iter\n\n## Log\n\nThe LogPlugin has moved to https://github.com/guzzle/log-subscriber. The\n`Guzzle\\Log` namespace has been removed. Guzzle now relies on\n`Psr\\Log\\LoggerInterface` for all logging. The MessageFormatter class has been\nmoved to `GuzzleHttp\\Subscriber\\Log\\Formatter`.\n\n## Parser\n\nThe `Guzzle\\Parser` namespace has been removed. This was previously used to\nmake it possible to plug in custom parsers for cookies, messages, URI\ntemplates, and URLs; however, this level of complexity is not needed in Guzzle\nso it has been removed.\n\n- Cookie: Cookie parsing logic has been moved to\n  `GuzzleHttp\\Cookie\\SetCookie::fromString`.\n- Message: Message parsing logic for both requests and responses has been moved\n  to `GuzzleHttp\\Message\\MessageFactory::fromMessage`. Message parsing is only\n  used in debugging or deserializing messages, so it doesn't make sense for\n  Guzzle as a library to add this level of complexity to parsing messages.\n- UriTemplate: URI template parsing has been moved to\n  `GuzzleHttp\\UriTemplate`. The Guzzle library will automatically use the PECL\n  URI template library if it is installed.\n- Url: URL parsing is now performed in `GuzzleHttp\\Url::fromString` (previously\n  it was `Guzzle\\Http\\Url::factory()`). If custom URL parsing is necessary,\n  then developers are free to subclass `GuzzleHttp\\Url`.\n\n## Plugin\n\nThe `Guzzle\\Plugin` namespace has been renamed to `GuzzleHttp\\Subscriber`.\nSeveral plugins are shipping with the core Guzzle library under this namespace.\n\n- `GuzzleHttp\\Subscriber\\Cookie`: Replaces the old CookiePlugin. Cookie jar\n  code has moved to `GuzzleHttp\\Cookie`.\n- `GuzzleHttp\\Subscriber\\History`: Replaces the old HistoryPlugin.\n- `GuzzleHttp\\Subscriber\\HttpError`: Throws errors when a bad HTTP response is\n  received.\n- `GuzzleHttp\\Subscriber\\Mock`: Replaces the old MockPlugin.\n- `GuzzleHttp\\Subscriber\\Prepare`: Prepares the body of a request just before\n  sending. This subscriber is attached to all requests by default.\n- `GuzzleHttp\\Subscriber\\Redirect`: Replaces the RedirectPlugin.\n\nThe following plugins have been removed (third-parties are free to re-implement\nthese if needed):\n\n- `GuzzleHttp\\Plugin\\Async` has been removed.\n- `GuzzleHttp\\Plugin\\CurlAuth` has been removed.\n- `GuzzleHttp\\Plugin\\ErrorResponse\\ErrorResponsePlugin` has been removed. This\n  functionality should instead be implemented with event listeners that occur\n  after normal response parsing occurs in the guzzle/command package.\n\nThe following plugins are not part of the core Guzzle package, but are provided\nin separate repositories:\n\n- `Guzzle\\Http\\Plugin\\BackoffPlugin` has been rewritten to be much simpler\n  to build custom retry policies using simple functions rather than various\n  chained classes. See: https://github.com/guzzle/retry-subscriber\n- `Guzzle\\Http\\Plugin\\Cache\\CachePlugin` has moved to\n  https://github.com/guzzle/cache-subscriber\n- `Guzzle\\Http\\Plugin\\Log\\LogPlugin` has moved to\n  https://github.com/guzzle/log-subscriber\n- `Guzzle\\Http\\Plugin\\Md5\\Md5Plugin` has moved to\n  https://github.com/guzzle/message-integrity-subscriber\n- `Guzzle\\Http\\Plugin\\Mock\\MockPlugin` has moved to\n  `GuzzleHttp\\Subscriber\\MockSubscriber`.\n- `Guzzle\\Http\\Plugin\\Oauth\\OauthPlugin` has moved to\n  https://github.com/guzzle/oauth-subscriber\n\n## Service\n\nThe service description layer of Guzzle has moved into two separate packages:\n\n- http://github.com/guzzle/command Provides a high level abstraction over web\n  services by representing web service operations using commands.\n- http://github.com/guzzle/guzzle-services Provides an implementation of\n  guzzle/command that provides request serialization and response parsing using\n  Guzzle service descriptions.\n\n## Stream\n\nStream have moved to a separate package available at\nhttps://github.com/guzzle/streams.\n\n`Guzzle\\Stream\\StreamInterface` has been given a large update to cleanly take\non the responsibilities of `Guzzle\\Http\\EntityBody` and\n`Guzzle\\Http\\EntityBodyInterface` now that they have been removed. The number\nof methods implemented by the `StreamInterface` has been drastically reduced to\nallow developers to more easily extend and decorate stream behavior.\n\n## Removed methods from StreamInterface\n\n- `getStream` and `setStream` have been removed to better encapsulate streams.\n- `getMetadata` and `setMetadata` have been removed in favor of\n  `GuzzleHttp\\Stream\\MetadataStreamInterface`.\n- `getWrapper`, `getWrapperData`, `getStreamType`, and `getUri` have all been\n  removed. This data is accessible when\n  using streams that implement `GuzzleHttp\\Stream\\MetadataStreamInterface`.\n- `rewind` has been removed. Use `seek(0)` for a similar behavior.\n\n## Renamed methods\n\n- `detachStream` has been renamed to `detach`.\n- `feof` has been renamed to `eof`.\n- `ftell` has been renamed to `tell`.\n- `readLine` has moved from an instance method to a static class method of\n  `GuzzleHttp\\Stream\\Stream`.\n\n## Metadata streams\n\n`GuzzleHttp\\Stream\\MetadataStreamInterface` has been added to denote streams\nthat contain additional metadata accessible via `getMetadata()`.\n`GuzzleHttp\\Stream\\StreamInterface::getMetadata` and\n`GuzzleHttp\\Stream\\StreamInterface::setMetadata` have been removed.\n\n## StreamRequestFactory\n\nThe entire concept of the StreamRequestFactory has been removed. The way this\nwas used in Guzzle 3 broke the actual interface of sending streaming requests\n(instead of getting back a Response, you got a StreamInterface). Streaming\nPHP requests are now implemented through the `GuzzleHttp\\Adapter\\StreamAdapter`.\n\n3.6 to 3.7\n----------\n\n### Deprecations\n\n- You can now enable E_USER_DEPRECATED warnings to see if you are using any deprecated methods.:\n\n```php\n\\Guzzle\\Common\\Version::$emitWarnings = true;\n```\n\nThe following APIs and options have been marked as deprecated:\n\n- Marked `Guzzle\\Http\\Message\\Request::isResponseBodyRepeatable()` as deprecated. Use `$request->getResponseBody()->isRepeatable()` instead.\n- Marked `Guzzle\\Http\\Message\\Request::canCache()` as deprecated. Use `Guzzle\\Plugin\\Cache\\DefaultCanCacheStrategy->canCacheRequest()` instead.\n- Marked `Guzzle\\Http\\Message\\Request::canCache()` as deprecated. Use `Guzzle\\Plugin\\Cache\\DefaultCanCacheStrategy->canCacheRequest()` instead.\n- Marked `Guzzle\\Http\\Message\\Request::setIsRedirect()` as deprecated. Use the HistoryPlugin instead.\n- Marked `Guzzle\\Http\\Message\\Request::isRedirect()` as deprecated. Use the HistoryPlugin instead.\n- Marked `Guzzle\\Cache\\CacheAdapterFactory::factory()` as deprecated\n- Marked `Guzzle\\Service\\Client::enableMagicMethods()` as deprecated. Magic methods can no longer be disabled on a Guzzle\\Service\\Client.\n- Marked `Guzzle\\Parser\\Url\\UrlParser` as deprecated. Just use PHP's `parse_url()` and percent encode your UTF-8.\n- Marked `Guzzle\\Common\\Collection::inject()` as deprecated.\n- Marked `Guzzle\\Plugin\\CurlAuth\\CurlAuthPlugin` as deprecated. Use\n  `$client->getConfig()->setPath('request.options/auth', array('user', 'pass', 'Basic|Digest|NTLM|Any'));` or\n  `$client->setDefaultOption('auth', array('user', 'pass', 'Basic|Digest|NTLM|Any'));`\n\n3.7 introduces `request.options` as a parameter for a client configuration and as an optional argument to all creational\nrequest methods. When paired with a client's configuration settings, these options allow you to specify default settings\nfor various aspects of a request. Because these options make other previous configuration options redundant, several\nconfiguration options and methods of a client and AbstractCommand have been deprecated.\n\n- Marked `Guzzle\\Service\\Client::getDefaultHeaders()` as deprecated. Use `$client->getDefaultOption('headers')`.\n- Marked `Guzzle\\Service\\Client::setDefaultHeaders()` as deprecated. Use `$client->setDefaultOption('headers/{header_name}', 'value')`.\n- Marked 'request.params' for `Guzzle\\Http\\Client` as deprecated. Use `$client->setDefaultOption('params/{param_name}', 'value')`\n- Marked 'command.headers', 'command.response_body' and 'command.on_complete' as deprecated for AbstractCommand. These will work through Guzzle 4.0\n\n        $command = $client->getCommand('foo', array(\n            'command.headers' => array('Test' => '123'),\n            'command.response_body' => '/path/to/file'\n        ));\n\n        // Should be changed to:\n\n        $command = $client->getCommand('foo', array(\n            'command.request_options' => array(\n                'headers' => array('Test' => '123'),\n                'save_as' => '/path/to/file'\n            )\n        ));\n\n### Interface changes\n\nAdditions and changes (you will need to update any implementations or subclasses you may have created):\n\n- Added an `$options` argument to the end of the following methods of `Guzzle\\Http\\ClientInterface`:\n  createRequest, head, delete, put, patch, post, options, prepareRequest\n- Added an `$options` argument to the end of `Guzzle\\Http\\Message\\Request\\RequestFactoryInterface::createRequest()`\n- Added an `applyOptions()` method to `Guzzle\\Http\\Message\\Request\\RequestFactoryInterface`\n- Changed `Guzzle\\Http\\ClientInterface::get($uri = null, $headers = null, $body = null)` to\n  `Guzzle\\Http\\ClientInterface::get($uri = null, $headers = null, $options = array())`. You can still pass in a\n  resource, string, or EntityBody into the $options parameter to specify the download location of the response.\n- Changed `Guzzle\\Common\\Collection::__construct($data)` to no longer accepts a null value for `$data` but a\n  default `array()`\n- Added `Guzzle\\Stream\\StreamInterface::isRepeatable`\n- Made `Guzzle\\Http\\Client::expandTemplate` and `getUriTemplate` protected methods.\n\nThe following methods were removed from interfaces. All of these methods are still available in the concrete classes\nthat implement them, but you should update your code to use alternative methods:\n\n- Removed `Guzzle\\Http\\ClientInterface::setDefaultHeaders(). Use\n  `$client->getConfig()->setPath('request.options/headers/{header_name}', 'value')`. or\n  `$client->getConfig()->setPath('request.options/headers', array('header_name' => 'value'))` or\n  `$client->setDefaultOption('headers/{header_name}', 'value')`. or\n  `$client->setDefaultOption('headers', array('header_name' => 'value'))`.\n- Removed `Guzzle\\Http\\ClientInterface::getDefaultHeaders(). Use `$client->getConfig()->getPath('request.options/headers')`.\n- Removed `Guzzle\\Http\\ClientInterface::expandTemplate()`. This is an implementation detail.\n- Removed `Guzzle\\Http\\ClientInterface::setRequestFactory()`. This is an implementation detail.\n- Removed `Guzzle\\Http\\ClientInterface::getCurlMulti()`. This is a very specific implementation detail.\n- Removed `Guzzle\\Http\\Message\\RequestInterface::canCache`. Use the CachePlugin.\n- Removed `Guzzle\\Http\\Message\\RequestInterface::setIsRedirect`. Use the HistoryPlugin.\n- Removed `Guzzle\\Http\\Message\\RequestInterface::isRedirect`. Use the HistoryPlugin.\n\n### Cache plugin breaking changes\n\n- CacheKeyProviderInterface and DefaultCacheKeyProvider are no longer used. All of this logic is handled in a\n  CacheStorageInterface. These two objects and interface will be removed in a future version.\n- Always setting X-cache headers on cached responses\n- Default cache TTLs are now handled by the CacheStorageInterface of a CachePlugin\n- `CacheStorageInterface::cache($key, Response $response, $ttl = null)` has changed to `cache(RequestInterface\n  $request, Response $response);`\n- `CacheStorageInterface::fetch($key)` has changed to `fetch(RequestInterface $request);`\n- `CacheStorageInterface::delete($key)` has changed to `delete(RequestInterface $request);`\n- Added `CacheStorageInterface::purge($url)`\n- `DefaultRevalidation::__construct(CacheKeyProviderInterface $cacheKey, CacheStorageInterface $cache, CachePlugin\n  $plugin)` has changed to `DefaultRevalidation::__construct(CacheStorageInterface $cache,\n  CanCacheStrategyInterface $canCache = null)`\n- Added `RevalidationInterface::shouldRevalidate(RequestInterface $request, Response $response)`\n\n3.5 to 3.6\n----------\n\n* Mixed casing of headers are now forced to be a single consistent casing across all values for that header.\n* Messages internally use a HeaderCollection object to delegate handling case-insensitive header resolution\n* Removed the whole changedHeader() function system of messages because all header changes now go through addHeader().\n  For example, setHeader() first removes the header using unset on a HeaderCollection and then calls addHeader().\n  Keeping the Host header and URL host in sync is now handled by overriding the addHeader method in Request.\n* Specific header implementations can be created for complex headers. When a message creates a header, it uses a\n  HeaderFactory which can map specific headers to specific header classes. There is now a Link header and\n  CacheControl header implementation.\n* Moved getLinks() from Response to just be used on a Link header object.\n\nIf you previously relied on Guzzle\\Http\\Message\\Header::raw(), then you will need to update your code to use the\nHeaderInterface (e.g. toArray(), getAll(), etc.).\n\n### Interface changes\n\n* Removed from interface: Guzzle\\Http\\ClientInterface::setUriTemplate\n* Removed from interface: Guzzle\\Http\\ClientInterface::setCurlMulti()\n* Removed Guzzle\\Http\\Message\\Request::receivedRequestHeader() and implemented this functionality in\n  Guzzle\\Http\\Curl\\RequestMediator\n* Removed the optional $asString parameter from MessageInterface::getHeader(). Just cast the header to a string.\n* Removed the optional $tryChunkedTransfer option from Guzzle\\Http\\Message\\EntityEnclosingRequestInterface\n* Removed the $asObjects argument from Guzzle\\Http\\Message\\MessageInterface::getHeaders()\n\n### Removed deprecated functions\n\n* Removed Guzzle\\Parser\\ParserRegister::get(). Use getParser()\n* Removed Guzzle\\Parser\\ParserRegister::set(). Use registerParser().\n\n### Deprecations\n\n* The ability to case-insensitively search for header values\n* Guzzle\\Http\\Message\\Header::hasExactHeader\n* Guzzle\\Http\\Message\\Header::raw. Use getAll()\n* Deprecated cache control specific methods on Guzzle\\Http\\Message\\AbstractMessage. Use the CacheControl header object\n  instead.\n\n### Other changes\n\n* All response header helper functions return a string rather than mixing Header objects and strings inconsistently\n* Removed cURL blacklist support. This is no longer necessary now that Expect, Accept, etc. are managed by Guzzle\n  directly via interfaces\n* Removed the injecting of a request object onto a response object. The methods to get and set a request still exist\n  but are a no-op until removed.\n* Most classes that used to require a `Guzzle\\Service\\Command\\CommandInterface` typehint now request a\n  `Guzzle\\Service\\Command\\ArrayCommandInterface`.\n* Added `Guzzle\\Http\\Message\\RequestInterface::startResponse()` to the RequestInterface to handle injecting a response\n  on a request while the request is still being transferred\n* `Guzzle\\Service\\Command\\CommandInterface` now extends from ToArrayInterface and ArrayAccess\n\n3.3 to 3.4\n----------\n\nBase URLs of a client now follow the rules of http://tools.ietf.org/html/rfc3986#section-5.2.2 when merging URLs.\n\n3.2 to 3.3\n----------\n\n### Response::getEtag() quote stripping removed\n\n`Guzzle\\Http\\Message\\Response::getEtag()` no longer strips quotes around the ETag response header\n\n### Removed `Guzzle\\Http\\Utils`\n\nThe `Guzzle\\Http\\Utils` class was removed. This class was only used for testing.\n\n### Stream wrapper and type\n\n`Guzzle\\Stream\\Stream::getWrapper()` and `Guzzle\\Stream\\Stream::getStreamType()` are no longer converted to lowercase.\n\n### curl.emit_io became emit_io\n\nEmitting IO events from a RequestMediator is now a parameter that must be set in a request's curl options using the\n'emit_io' key. This was previously set under a request's parameters using 'curl.emit_io'\n\n3.1 to 3.2\n----------\n\n### CurlMulti is no longer reused globally\n\nBefore 3.2, the same CurlMulti object was reused globally for each client. This can cause issue where plugins added\nto a single client can pollute requests dispatched from other clients.\n\nIf you still wish to reuse the same CurlMulti object with each client, then you can add a listener to the\nServiceBuilder's `service_builder.create_client` event to inject a custom CurlMulti object into each client as it is\ncreated.\n\n```php\n$multi = new Guzzle\\Http\\Curl\\CurlMulti();\n$builder = Guzzle\\Service\\Builder\\ServiceBuilder::factory('/path/to/config.json');\n$builder->addListener('service_builder.create_client', function ($event) use ($multi) {\n    $event['client']->setCurlMulti($multi);\n}\n});\n```\n\n### No default path\n\nURLs no longer have a default path value of '/' if no path was specified.\n\nBefore:\n\n```php\n$request = $client->get('http://www.foo.com');\necho $request->getUrl();\n// >> http://www.foo.com/\n```\n\nAfter:\n\n```php\n$request = $client->get('http://www.foo.com');\necho $request->getUrl();\n// >> http://www.foo.com\n```\n\n### Less verbose BadResponseException\n\nThe exception message for `Guzzle\\Http\\Exception\\BadResponseException` no longer contains the full HTTP request and\nresponse information. You can, however, get access to the request and response object by calling `getRequest()` or\n`getResponse()` on the exception object.\n\n### Query parameter aggregation\n\nMulti-valued query parameters are no longer aggregated using a callback function. `Guzzle\\Http\\Query` now has a\nsetAggregator() method that accepts a `Guzzle\\Http\\QueryAggregator\\QueryAggregatorInterface` object. This object is\nresponsible for handling the aggregation of multi-valued query string variables into a flattened hash.\n\n2.8 to 3.x\n----------\n\n### Guzzle\\Service\\Inspector\n\nChange `\\Guzzle\\Service\\Inspector::fromConfig` to `\\Guzzle\\Common\\Collection::fromConfig`\n\n**Before**\n\n```php\nuse Guzzle\\Service\\Inspector;\n\nclass YourClient extends \\Guzzle\\Service\\Client\n{\n    public static function factory($config = array())\n    {\n        $default = array();\n        $required = array('base_url', 'username', 'api_key');\n        $config = Inspector::fromConfig($config, $default, $required);\n\n        $client = new self(\n            $config->get('base_url'),\n            $config->get('username'),\n            $config->get('api_key')\n        );\n        $client->setConfig($config);\n\n        $client->setDescription(ServiceDescription::factory(__DIR__ . DIRECTORY_SEPARATOR . 'client.json'));\n\n        return $client;\n    }\n```\n\n**After**\n\n```php\nuse Guzzle\\Common\\Collection;\n\nclass YourClient extends \\Guzzle\\Service\\Client\n{\n    public static function factory($config = array())\n    {\n        $default = array();\n        $required = array('base_url', 'username', 'api_key');\n        $config = Collection::fromConfig($config, $default, $required);\n\n        $client = new self(\n            $config->get('base_url'),\n            $config->get('username'),\n            $config->get('api_key')\n        );\n        $client->setConfig($config);\n\n        $client->setDescription(ServiceDescription::factory(__DIR__ . DIRECTORY_SEPARATOR . 'client.json'));\n\n        return $client;\n    }\n```\n\n### Convert XML Service Descriptions to JSON\n\n**Before**\n\n```xml\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<client>\n    <commands>\n        <!-- Groups -->\n        <command name=\"list_groups\" method=\"GET\" uri=\"groups.json\">\n            <doc>Get a list of groups</doc>\n        </command>\n        <command name=\"search_groups\" method=\"GET\" uri='search.json?query=\"{{query}} type:group\"'>\n            <doc>Uses a search query to get a list of groups</doc>\n            <param name=\"query\" type=\"string\" required=\"true\" />\n        </command>\n        <command name=\"create_group\" method=\"POST\" uri=\"groups.json\">\n            <doc>Create a group</doc>\n            <param name=\"data\" type=\"array\" location=\"body\" filters=\"json_encode\" doc=\"Group JSON\"/>\n            <param name=\"Content-Type\" location=\"header\" static=\"application/json\"/>\n        </command>\n        <command name=\"delete_group\" method=\"DELETE\" uri=\"groups/{{id}}.json\">\n            <doc>Delete a group by ID</doc>\n            <param name=\"id\" type=\"integer\" required=\"true\"/>\n        </command>\n        <command name=\"get_group\" method=\"GET\" uri=\"groups/{{id}}.json\">\n            <param name=\"id\" type=\"integer\" required=\"true\"/>\n        </command>\n        <command name=\"update_group\" method=\"PUT\" uri=\"groups/{{id}}.json\">\n            <doc>Update a group</doc>\n            <param name=\"id\" type=\"integer\" required=\"true\"/>\n            <param name=\"data\" type=\"array\" location=\"body\" filters=\"json_encode\" doc=\"Group JSON\"/>\n            <param name=\"Content-Type\" location=\"header\" static=\"application/json\"/>\n        </command>\n    </commands>\n</client>\n```\n\n**After**\n\n```json\n{\n    \"name\":       \"Zendesk REST API v2\",\n    \"apiVersion\": \"2012-12-31\",\n    \"description\":\"Provides access to Zendesk views, groups, tickets, ticket fields, and users\",\n    \"operations\": {\n        \"list_groups\":  {\n            \"httpMethod\":\"GET\",\n            \"uri\":       \"groups.json\",\n            \"summary\":   \"Get a list of groups\"\n        },\n        \"search_groups\":{\n            \"httpMethod\":\"GET\",\n            \"uri\":       \"search.json?query=\\\"{query} type:group\\\"\",\n            \"summary\":   \"Uses a search query to get a list of groups\",\n            \"parameters\":{\n                \"query\":{\n                    \"location\":   \"uri\",\n                    \"description\":\"Zendesk Search Query\",\n                    \"type\":       \"string\",\n                    \"required\":   true\n                }\n            }\n        },\n        \"create_group\": {\n            \"httpMethod\":\"POST\",\n            \"uri\":       \"groups.json\",\n            \"summary\":   \"Create a group\",\n            \"parameters\":{\n                \"data\":        {\n                    \"type\":       \"array\",\n                    \"location\":   \"body\",\n                    \"description\":\"Group JSON\",\n                    \"filters\":    \"json_encode\",\n                    \"required\":   true\n                },\n                \"Content-Type\":{\n                    \"type\":    \"string\",\n                    \"location\":\"header\",\n                    \"static\":  \"application/json\"\n                }\n            }\n        },\n        \"delete_group\": {\n            \"httpMethod\":\"DELETE\",\n            \"uri\":       \"groups/{id}.json\",\n            \"summary\":   \"Delete a group\",\n            \"parameters\":{\n                \"id\":{\n                    \"location\":   \"uri\",\n                    \"description\":\"Group to delete by ID\",\n                    \"type\":       \"integer\",\n                    \"required\":   true\n                }\n            }\n        },\n        \"get_group\":    {\n            \"httpMethod\":\"GET\",\n            \"uri\":       \"groups/{id}.json\",\n            \"summary\":   \"Get a ticket\",\n            \"parameters\":{\n                \"id\":{\n                    \"location\":   \"uri\",\n                    \"description\":\"Group to get by ID\",\n                    \"type\":       \"integer\",\n                    \"required\":   true\n                }\n            }\n        },\n        \"update_group\": {\n            \"httpMethod\":\"PUT\",\n            \"uri\":       \"groups/{id}.json\",\n            \"summary\":   \"Update a group\",\n            \"parameters\":{\n                \"id\":          {\n                    \"location\":   \"uri\",\n                    \"description\":\"Group to update by ID\",\n                    \"type\":       \"integer\",\n                    \"required\":   true\n                },\n                \"data\":        {\n                    \"type\":       \"array\",\n                    \"location\":   \"body\",\n                    \"description\":\"Group JSON\",\n                    \"filters\":    \"json_encode\",\n                    \"required\":   true\n                },\n                \"Content-Type\":{\n                    \"type\":    \"string\",\n                    \"location\":\"header\",\n                    \"static\":  \"application/json\"\n                }\n            }\n        }\n}\n```\n\n### Guzzle\\Service\\Description\\ServiceDescription\n\nCommands are now called Operations\n\n**Before**\n\n```php\nuse Guzzle\\Service\\Description\\ServiceDescription;\n\n$sd = new ServiceDescription();\n$sd->getCommands();     // @returns ApiCommandInterface[]\n$sd->hasCommand($name);\n$sd->getCommand($name); // @returns ApiCommandInterface|null\n$sd->addCommand($command); // @param ApiCommandInterface $command\n```\n\n**After**\n\n```php\nuse Guzzle\\Service\\Description\\ServiceDescription;\n\n$sd = new ServiceDescription();\n$sd->getOperations();           // @returns OperationInterface[]\n$sd->hasOperation($name);\n$sd->getOperation($name);       // @returns OperationInterface|null\n$sd->addOperation($operation);  // @param OperationInterface $operation\n```\n\n### Guzzle\\Common\\Inflection\\Inflector\n\nNamespace is now `Guzzle\\Inflection\\Inflector`\n\n### Guzzle\\Http\\Plugin\n\nNamespace is now `Guzzle\\Plugin`. Many other changes occur within this namespace and are detailed in their own sections below.\n\n### Guzzle\\Http\\Plugin\\LogPlugin and Guzzle\\Common\\Log\n\nNow `Guzzle\\Plugin\\Log\\LogPlugin` and `Guzzle\\Log` respectively.\n\n**Before**\n\n```php\nuse Guzzle\\Common\\Log\\ClosureLogAdapter;\nuse Guzzle\\Http\\Plugin\\LogPlugin;\n\n/** @var \\Guzzle\\Http\\Client */\n$client;\n\n// $verbosity is an integer indicating desired message verbosity level\n$client->addSubscriber(new LogPlugin(new ClosureLogAdapter(function($m) { echo $m; }, $verbosity = LogPlugin::LOG_VERBOSE);\n```\n\n**After**\n\n```php\nuse Guzzle\\Log\\ClosureLogAdapter;\nuse Guzzle\\Log\\MessageFormatter;\nuse Guzzle\\Plugin\\Log\\LogPlugin;\n\n/** @var \\Guzzle\\Http\\Client */\n$client;\n\n// $format is a string indicating desired message format -- @see MessageFormatter\n$client->addSubscriber(new LogPlugin(new ClosureLogAdapter(function($m) { echo $m; }, $format = MessageFormatter::DEBUG_FORMAT);\n```\n\n### Guzzle\\Http\\Plugin\\CurlAuthPlugin\n\nNow `Guzzle\\Plugin\\CurlAuth\\CurlAuthPlugin`.\n\n### Guzzle\\Http\\Plugin\\ExponentialBackoffPlugin\n\nNow `Guzzle\\Plugin\\Backoff\\BackoffPlugin`, and other changes.\n\n**Before**\n\n```php\nuse Guzzle\\Http\\Plugin\\ExponentialBackoffPlugin;\n\n$backoffPlugin = new ExponentialBackoffPlugin($maxRetries, array_merge(\n        ExponentialBackoffPlugin::getDefaultFailureCodes(), array(429)\n    ));\n\n$client->addSubscriber($backoffPlugin);\n```\n\n**After**\n\n```php\nuse Guzzle\\Plugin\\Backoff\\BackoffPlugin;\nuse Guzzle\\Plugin\\Backoff\\HttpBackoffStrategy;\n\n// Use convenient factory method instead -- see implementation for ideas of what\n// you can do with chaining backoff strategies\n$backoffPlugin = BackoffPlugin::getExponentialBackoff($maxRetries, array_merge(\n        HttpBackoffStrategy::getDefaultFailureCodes(), array(429)\n    ));\n$client->addSubscriber($backoffPlugin);\n```\n\n### Known Issues\n\n#### [BUG] Accept-Encoding header behavior changed unintentionally.\n\n(See #217) (Fixed in 09daeb8c666fb44499a0646d655a8ae36456575e)\n\nIn version 2.8 setting the `Accept-Encoding` header would set the CURLOPT_ENCODING option, which permitted cURL to\nproperly handle gzip/deflate compressed responses from the server. In versions affected by this bug this does not happen.\nSee issue #217 for a workaround, or use a version containing the fix.\n"
  },
  {
    "path": "server/vendor/guzzlehttp/guzzle/composer.json",
    "content": "{\n    \"name\": \"guzzlehttp/guzzle\",\n    \"type\": \"library\",\n    \"description\": \"Guzzle is a PHP HTTP client library\",\n    \"keywords\": [\n        \"framework\",\n        \"http\",\n        \"rest\",\n        \"web service\",\n        \"curl\",\n        \"client\",\n        \"HTTP client\"\n    ],\n    \"homepage\": \"http://guzzlephp.org/\",\n    \"license\": \"MIT\",\n    \"authors\": [\n        {\n            \"name\": \"Graham Campbell\",\n            \"email\": \"hello@gjcampbell.co.uk\",\n            \"homepage\": \"https://github.com/GrahamCampbell\"\n        },\n        {\n            \"name\": \"Michael Dowling\",\n            \"email\": \"mtdowling@gmail.com\",\n            \"homepage\": \"https://github.com/mtdowling\"\n        },\n        {\n            \"name\": \"Jeremy Lindblom\",\n            \"email\": \"jeremeamia@gmail.com\",\n            \"homepage\": \"https://github.com/jeremeamia\"\n        },\n        {\n            \"name\": \"George Mponos\",\n            \"email\": \"gmponos@gmail.com\",\n            \"homepage\": \"https://github.com/gmponos\"\n        },\n        {\n            \"name\": \"Tobias Nyholm\",\n            \"email\": \"tobias.nyholm@gmail.com\",\n            \"homepage\": \"https://github.com/Nyholm\"\n        },\n        {\n            \"name\": \"Márk Sági-Kazár\",\n            \"email\": \"mark.sagikazar@gmail.com\",\n            \"homepage\": \"https://github.com/sagikazarmark\"\n        },\n        {\n            \"name\": \"Tobias Schultze\",\n            \"email\": \"webmaster@tubo-world.de\",\n            \"homepage\": \"https://github.com/Tobion\"\n        }\n    ],\n    \"require\": {\n        \"php\": \">=5.5\",\n        \"ext-json\": \"*\",\n        \"symfony/polyfill-intl-idn\": \"^1.17\",\n        \"guzzlehttp/promises\": \"^1.0\",\n        \"guzzlehttp/psr7\": \"^1.9\"\n    },\n    \"require-dev\": {\n        \"ext-curl\": \"*\",\n        \"phpunit/phpunit\": \"^4.8.35 || ^5.7 || ^6.4 || ^7.0\",\n        \"psr/log\": \"^1.1\"\n    },\n    \"suggest\": {\n        \"psr/log\": \"Required for using the Log middleware\"\n    },\n    \"config\": {\n        \"sort-packages\": true,\n        \"allow-plugins\": {\n            \"bamarni/composer-bin-plugin\": true\n        }\n    },\n    \"extra\": {\n        \"branch-alias\": {\n            \"dev-master\": \"6.5-dev\"\n        }\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"GuzzleHttp\\\\\": \"src/\"\n        },\n        \"files\": [\n            \"src/functions_include.php\"\n        ]\n    },\n    \"autoload-dev\": {\n        \"psr-4\": {\n            \"GuzzleHttp\\\\Tests\\\\\": \"tests/\"\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/guzzle/src/Client.php",
    "content": "<?php\nnamespace GuzzleHttp;\n\nuse GuzzleHttp\\Cookie\\CookieJar;\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse GuzzleHttp\\Promise;\nuse GuzzleHttp\\Psr7;\nuse Psr\\Http\\Message\\RequestInterface;\nuse Psr\\Http\\Message\\ResponseInterface;\nuse Psr\\Http\\Message\\UriInterface;\n\n/**\n * @method ResponseInterface get(string|UriInterface $uri, array $options = [])\n * @method ResponseInterface head(string|UriInterface $uri, array $options = [])\n * @method ResponseInterface put(string|UriInterface $uri, array $options = [])\n * @method ResponseInterface post(string|UriInterface $uri, array $options = [])\n * @method ResponseInterface patch(string|UriInterface $uri, array $options = [])\n * @method ResponseInterface delete(string|UriInterface $uri, array $options = [])\n * @method Promise\\PromiseInterface getAsync(string|UriInterface $uri, array $options = [])\n * @method Promise\\PromiseInterface headAsync(string|UriInterface $uri, array $options = [])\n * @method Promise\\PromiseInterface putAsync(string|UriInterface $uri, array $options = [])\n * @method Promise\\PromiseInterface postAsync(string|UriInterface $uri, array $options = [])\n * @method Promise\\PromiseInterface patchAsync(string|UriInterface $uri, array $options = [])\n * @method Promise\\PromiseInterface deleteAsync(string|UriInterface $uri, array $options = [])\n */\nclass Client implements ClientInterface\n{\n    /** @var array Default request options */\n    private $config;\n\n    /**\n     * Clients accept an array of constructor parameters.\n     *\n     * Here's an example of creating a client using a base_uri and an array of\n     * default request options to apply to each request:\n     *\n     *     $client = new Client([\n     *         'base_uri'        => 'http://www.foo.com/1.0/',\n     *         'timeout'         => 0,\n     *         'allow_redirects' => false,\n     *         'proxy'           => '192.168.16.1:10'\n     *     ]);\n     *\n     * Client configuration settings include the following options:\n     *\n     * - handler: (callable) Function that transfers HTTP requests over the\n     *   wire. The function is called with a Psr7\\Http\\Message\\RequestInterface\n     *   and array of transfer options, and must return a\n     *   GuzzleHttp\\Promise\\PromiseInterface that is fulfilled with a\n     *   Psr7\\Http\\Message\\ResponseInterface on success.\n     *   If no handler is provided, a default handler will be created\n     *   that enables all of the request options below by attaching all of the\n     *   default middleware to the handler.\n     * - base_uri: (string|UriInterface) Base URI of the client that is merged\n     *   into relative URIs. Can be a string or instance of UriInterface.\n     * - **: any request option\n     *\n     * @param array $config Client configuration settings.\n     *\n     * @see \\GuzzleHttp\\RequestOptions for a list of available request options.\n     */\n    public function __construct(array $config = [])\n    {\n        if (!isset($config['handler'])) {\n            $config['handler'] = HandlerStack::create();\n        } elseif (!is_callable($config['handler'])) {\n            throw new \\InvalidArgumentException('handler must be a callable');\n        }\n\n        // Convert the base_uri to a UriInterface\n        if (isset($config['base_uri'])) {\n            $config['base_uri'] = Psr7\\uri_for($config['base_uri']);\n        }\n\n        $this->configureDefaults($config);\n    }\n\n    /**\n     * @param string $method\n     * @param array  $args\n     *\n     * @return Promise\\PromiseInterface\n     */\n    public function __call($method, $args)\n    {\n        if (count($args) < 1) {\n            throw new \\InvalidArgumentException('Magic request methods require a URI and optional options array');\n        }\n\n        $uri = $args[0];\n        $opts = isset($args[1]) ? $args[1] : [];\n\n        return substr($method, -5) === 'Async'\n            ? $this->requestAsync(substr($method, 0, -5), $uri, $opts)\n            : $this->request($method, $uri, $opts);\n    }\n\n    /**\n     * Asynchronously send an HTTP request.\n     *\n     * @param array $options Request options to apply to the given\n     *                       request and to the transfer. See \\GuzzleHttp\\RequestOptions.\n     *\n     * @return Promise\\PromiseInterface\n     */\n    public function sendAsync(RequestInterface $request, array $options = [])\n    {\n        // Merge the base URI into the request URI if needed.\n        $options = $this->prepareDefaults($options);\n\n        return $this->transfer(\n            $request->withUri($this->buildUri($request->getUri(), $options), $request->hasHeader('Host')),\n            $options\n        );\n    }\n\n    /**\n     * Send an HTTP request.\n     *\n     * @param array $options Request options to apply to the given\n     *                       request and to the transfer. See \\GuzzleHttp\\RequestOptions.\n     *\n     * @return ResponseInterface\n     * @throws GuzzleException\n     */\n    public function send(RequestInterface $request, array $options = [])\n    {\n        $options[RequestOptions::SYNCHRONOUS] = true;\n        return $this->sendAsync($request, $options)->wait();\n    }\n\n    /**\n     * Create and send an asynchronous HTTP request.\n     *\n     * Use an absolute path to override the base path of the client, or a\n     * relative path to append to the base path of the client. The URL can\n     * contain the query string as well. Use an array to provide a URL\n     * template and additional variables to use in the URL template expansion.\n     *\n     * @param string              $method  HTTP method\n     * @param string|UriInterface $uri     URI object or string.\n     * @param array               $options Request options to apply. See \\GuzzleHttp\\RequestOptions.\n     *\n     * @return Promise\\PromiseInterface\n     */\n    public function requestAsync($method, $uri = '', array $options = [])\n    {\n        $options = $this->prepareDefaults($options);\n        // Remove request modifying parameter because it can be done up-front.\n        $headers = isset($options['headers']) ? $options['headers'] : [];\n        $body = isset($options['body']) ? $options['body'] : null;\n        $version = isset($options['version']) ? $options['version'] : '1.1';\n        // Merge the URI into the base URI.\n        $uri = $this->buildUri($uri, $options);\n        if (is_array($body)) {\n            $this->invalidBody();\n        }\n        $request = new Psr7\\Request($method, $uri, $headers, $body, $version);\n        // Remove the option so that they are not doubly-applied.\n        unset($options['headers'], $options['body'], $options['version']);\n\n        return $this->transfer($request, $options);\n    }\n\n    /**\n     * Create and send an HTTP request.\n     *\n     * Use an absolute path to override the base path of the client, or a\n     * relative path to append to the base path of the client. The URL can\n     * contain the query string as well.\n     *\n     * @param string              $method  HTTP method.\n     * @param string|UriInterface $uri     URI object or string.\n     * @param array               $options Request options to apply. See \\GuzzleHttp\\RequestOptions.\n     *\n     * @return ResponseInterface\n     * @throws GuzzleException\n     */\n    public function request($method, $uri = '', array $options = [])\n    {\n        $options[RequestOptions::SYNCHRONOUS] = true;\n        return $this->requestAsync($method, $uri, $options)->wait();\n    }\n\n    /**\n     * Get a client configuration option.\n     *\n     * These options include default request options of the client, a \"handler\"\n     * (if utilized by the concrete client), and a \"base_uri\" if utilized by\n     * the concrete client.\n     *\n     * @param string|null $option The config option to retrieve.\n     *\n     * @return mixed\n     */\n    public function getConfig($option = null)\n    {\n        return $option === null\n            ? $this->config\n            : (isset($this->config[$option]) ? $this->config[$option] : null);\n    }\n\n    /**\n     * @param  string|null $uri\n     *\n     * @return UriInterface\n     */\n    private function buildUri($uri, array $config)\n    {\n        // for BC we accept null which would otherwise fail in uri_for\n        $uri = Psr7\\uri_for($uri === null ? '' : $uri);\n\n        if (isset($config['base_uri'])) {\n            $uri = Psr7\\UriResolver::resolve(Psr7\\uri_for($config['base_uri']), $uri);\n        }\n\n        if (isset($config['idn_conversion']) && ($config['idn_conversion'] !== false)) {\n            $idnOptions = ($config['idn_conversion'] === true) ? IDNA_DEFAULT : $config['idn_conversion'];\n            $uri = Utils::idnUriConvert($uri, $idnOptions);\n        }\n\n        return $uri->getScheme() === '' && $uri->getHost() !== '' ? $uri->withScheme('http') : $uri;\n    }\n\n    /**\n     * Configures the default options for a client.\n     *\n     * @param array $config\n     * @return void\n     */\n    private function configureDefaults(array $config)\n    {\n        $defaults = [\n            'allow_redirects' => RedirectMiddleware::$defaultSettings,\n            'http_errors'     => true,\n            'decode_content'  => true,\n            'verify'          => true,\n            'cookies'         => false,\n            'idn_conversion'  => true,\n        ];\n\n        // Use the standard Linux HTTP_PROXY and HTTPS_PROXY if set.\n\n        // We can only trust the HTTP_PROXY environment variable in a CLI\n        // process due to the fact that PHP has no reliable mechanism to\n        // get environment variables that start with \"HTTP_\".\n        if (php_sapi_name() === 'cli' && getenv('HTTP_PROXY')) {\n            $defaults['proxy']['http'] = getenv('HTTP_PROXY');\n        }\n\n        if ($proxy = getenv('HTTPS_PROXY')) {\n            $defaults['proxy']['https'] = $proxy;\n        }\n\n        if ($noProxy = getenv('NO_PROXY')) {\n            $cleanedNoProxy = str_replace(' ', '', $noProxy);\n            $defaults['proxy']['no'] = explode(',', $cleanedNoProxy);\n        }\n\n        $this->config = $config + $defaults;\n\n        if (!empty($config['cookies']) && $config['cookies'] === true) {\n            $this->config['cookies'] = new CookieJar();\n        }\n\n        // Add the default user-agent header.\n        if (!isset($this->config['headers'])) {\n            $this->config['headers'] = ['User-Agent' => default_user_agent()];\n        } else {\n            // Add the User-Agent header if one was not already set.\n            foreach (array_keys($this->config['headers']) as $name) {\n                if (strtolower($name) === 'user-agent') {\n                    return;\n                }\n            }\n            $this->config['headers']['User-Agent'] = default_user_agent();\n        }\n    }\n\n    /**\n     * Merges default options into the array.\n     *\n     * @param array $options Options to modify by reference\n     *\n     * @return array\n     */\n    private function prepareDefaults(array $options)\n    {\n        $defaults = $this->config;\n\n        if (!empty($defaults['headers'])) {\n            // Default headers are only added if they are not present.\n            $defaults['_conditional'] = $defaults['headers'];\n            unset($defaults['headers']);\n        }\n\n        // Special handling for headers is required as they are added as\n        // conditional headers and as headers passed to a request ctor.\n        if (array_key_exists('headers', $options)) {\n            // Allows default headers to be unset.\n            if ($options['headers'] === null) {\n                $defaults['_conditional'] = [];\n                unset($options['headers']);\n            } elseif (!is_array($options['headers'])) {\n                throw new \\InvalidArgumentException('headers must be an array');\n            }\n        }\n\n        // Shallow merge defaults underneath options.\n        $result = $options + $defaults;\n\n        // Remove null values.\n        foreach ($result as $k => $v) {\n            if ($v === null) {\n                unset($result[$k]);\n            }\n        }\n\n        return $result;\n    }\n\n    /**\n     * Transfers the given request and applies request options.\n     *\n     * The URI of the request is not modified and the request options are used\n     * as-is without merging in default options.\n     *\n     * @param array $options See \\GuzzleHttp\\RequestOptions.\n     *\n     * @return Promise\\PromiseInterface\n     */\n    private function transfer(RequestInterface $request, array $options)\n    {\n        // save_to -> sink\n        if (isset($options['save_to'])) {\n            $options['sink'] = $options['save_to'];\n            unset($options['save_to']);\n        }\n\n        // exceptions -> http_errors\n        if (isset($options['exceptions'])) {\n            $options['http_errors'] = $options['exceptions'];\n            unset($options['exceptions']);\n        }\n\n        $request = $this->applyOptions($request, $options);\n        /** @var HandlerStack $handler */\n        $handler = $options['handler'];\n\n        try {\n            return Promise\\promise_for($handler($request, $options));\n        } catch (\\Exception $e) {\n            return Promise\\rejection_for($e);\n        }\n    }\n\n    /**\n     * Applies the array of request options to a request.\n     *\n     * @param RequestInterface $request\n     * @param array            $options\n     *\n     * @return RequestInterface\n     */\n    private function applyOptions(RequestInterface $request, array &$options)\n    {\n        $modify = [\n            'set_headers' => [],\n        ];\n\n        if (isset($options['headers'])) {\n            $modify['set_headers'] = $options['headers'];\n            unset($options['headers']);\n        }\n\n        if (isset($options['form_params'])) {\n            if (isset($options['multipart'])) {\n                throw new \\InvalidArgumentException('You cannot use '\n                    . 'form_params and multipart at the same time. Use the '\n                    . 'form_params option if you want to send application/'\n                    . 'x-www-form-urlencoded requests, and the multipart '\n                    . 'option to send multipart/form-data requests.');\n            }\n            $options['body'] = http_build_query($options['form_params'], '', '&');\n            unset($options['form_params']);\n            // Ensure that we don't have the header in different case and set the new value.\n            $options['_conditional'] = Psr7\\_caseless_remove(['Content-Type'], $options['_conditional']);\n            $options['_conditional']['Content-Type'] = 'application/x-www-form-urlencoded';\n        }\n\n        if (isset($options['multipart'])) {\n            $options['body'] = new Psr7\\MultipartStream($options['multipart']);\n            unset($options['multipart']);\n        }\n\n        if (isset($options['json'])) {\n            $options['body'] = \\GuzzleHttp\\json_encode($options['json']);\n            unset($options['json']);\n            // Ensure that we don't have the header in different case and set the new value.\n            $options['_conditional'] = Psr7\\_caseless_remove(['Content-Type'], $options['_conditional']);\n            $options['_conditional']['Content-Type'] = 'application/json';\n        }\n\n        if (!empty($options['decode_content'])\n            && $options['decode_content'] !== true\n        ) {\n            // Ensure that we don't have the header in different case and set the new value.\n            $options['_conditional'] = Psr7\\_caseless_remove(['Accept-Encoding'], $options['_conditional']);\n            $modify['set_headers']['Accept-Encoding'] = $options['decode_content'];\n        }\n\n        if (isset($options['body'])) {\n            if (is_array($options['body'])) {\n                $this->invalidBody();\n            }\n            $modify['body'] = Psr7\\stream_for($options['body']);\n            unset($options['body']);\n        }\n\n        if (!empty($options['auth']) && is_array($options['auth'])) {\n            $value = $options['auth'];\n            $type = isset($value[2]) ? strtolower($value[2]) : 'basic';\n            switch ($type) {\n                case 'basic':\n                    // Ensure that we don't have the header in different case and set the new value.\n                    $modify['set_headers'] = Psr7\\_caseless_remove(['Authorization'], $modify['set_headers']);\n                    $modify['set_headers']['Authorization'] = 'Basic '\n                        . base64_encode(\"$value[0]:$value[1]\");\n                    break;\n                case 'digest':\n                    // @todo: Do not rely on curl\n                    $options['curl'][CURLOPT_HTTPAUTH] = CURLAUTH_DIGEST;\n                    $options['curl'][CURLOPT_USERPWD] = \"$value[0]:$value[1]\";\n                    break;\n                case 'ntlm':\n                    $options['curl'][CURLOPT_HTTPAUTH] = CURLAUTH_NTLM;\n                    $options['curl'][CURLOPT_USERPWD] = \"$value[0]:$value[1]\";\n                    break;\n            }\n        }\n\n        if (isset($options['query'])) {\n            $value = $options['query'];\n            if (is_array($value)) {\n                $value = http_build_query($value, null, '&', PHP_QUERY_RFC3986);\n            }\n            if (!is_string($value)) {\n                throw new \\InvalidArgumentException('query must be a string or array');\n            }\n            $modify['query'] = $value;\n            unset($options['query']);\n        }\n\n        // Ensure that sink is not an invalid value.\n        if (isset($options['sink'])) {\n            // TODO: Add more sink validation?\n            if (is_bool($options['sink'])) {\n                throw new \\InvalidArgumentException('sink must not be a boolean');\n            }\n        }\n\n        $request = Psr7\\modify_request($request, $modify);\n        if ($request->getBody() instanceof Psr7\\MultipartStream) {\n            // Use a multipart/form-data POST if a Content-Type is not set.\n            // Ensure that we don't have the header in different case and set the new value.\n            $options['_conditional'] = Psr7\\_caseless_remove(['Content-Type'], $options['_conditional']);\n            $options['_conditional']['Content-Type'] = 'multipart/form-data; boundary='\n                . $request->getBody()->getBoundary();\n        }\n\n        // Merge in conditional headers if they are not present.\n        if (isset($options['_conditional'])) {\n            // Build up the changes so it's in a single clone of the message.\n            $modify = [];\n            foreach ($options['_conditional'] as $k => $v) {\n                if (!$request->hasHeader($k)) {\n                    $modify['set_headers'][$k] = $v;\n                }\n            }\n            $request = Psr7\\modify_request($request, $modify);\n            // Don't pass this internal value along to middleware/handlers.\n            unset($options['_conditional']);\n        }\n\n        return $request;\n    }\n\n    /**\n     * Throw Exception with pre-set message.\n     * @return void\n     * @throws \\InvalidArgumentException Invalid body.\n     */\n    private function invalidBody()\n    {\n        throw new \\InvalidArgumentException('Passing in the \"body\" request '\n            . 'option as an array to send a POST request has been deprecated. '\n            . 'Please use the \"form_params\" request option to send a '\n            . 'application/x-www-form-urlencoded request, or the \"multipart\" '\n            . 'request option to send a multipart/form-data request.');\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/guzzle/src/ClientInterface.php",
    "content": "<?php\nnamespace GuzzleHttp;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse GuzzleHttp\\Promise\\PromiseInterface;\nuse Psr\\Http\\Message\\RequestInterface;\nuse Psr\\Http\\Message\\ResponseInterface;\nuse Psr\\Http\\Message\\UriInterface;\n\n/**\n * Client interface for sending HTTP requests.\n */\ninterface ClientInterface\n{\n    /**\n     * @deprecated Will be removed in Guzzle 7.0.0\n     */\n    const VERSION = '6.5.5';\n\n    /**\n     * Send an HTTP request.\n     *\n     * @param RequestInterface $request Request to send\n     * @param array            $options Request options to apply to the given\n     *                                  request and to the transfer.\n     *\n     * @return ResponseInterface\n     * @throws GuzzleException\n     */\n    public function send(RequestInterface $request, array $options = []);\n\n    /**\n     * Asynchronously send an HTTP request.\n     *\n     * @param RequestInterface $request Request to send\n     * @param array            $options Request options to apply to the given\n     *                                  request and to the transfer.\n     *\n     * @return PromiseInterface\n     */\n    public function sendAsync(RequestInterface $request, array $options = []);\n\n    /**\n     * Create and send an HTTP request.\n     *\n     * Use an absolute path to override the base path of the client, or a\n     * relative path to append to the base path of the client. The URL can\n     * contain the query string as well.\n     *\n     * @param string              $method  HTTP method.\n     * @param string|UriInterface $uri     URI object or string.\n     * @param array               $options Request options to apply.\n     *\n     * @return ResponseInterface\n     * @throws GuzzleException\n     */\n    public function request($method, $uri, array $options = []);\n\n    /**\n     * Create and send an asynchronous HTTP request.\n     *\n     * Use an absolute path to override the base path of the client, or a\n     * relative path to append to the base path of the client. The URL can\n     * contain the query string as well. Use an array to provide a URL\n     * template and additional variables to use in the URL template expansion.\n     *\n     * @param string              $method  HTTP method\n     * @param string|UriInterface $uri     URI object or string.\n     * @param array               $options Request options to apply.\n     *\n     * @return PromiseInterface\n     */\n    public function requestAsync($method, $uri, array $options = []);\n\n    /**\n     * Get a client configuration option.\n     *\n     * These options include default request options of the client, a \"handler\"\n     * (if utilized by the concrete client), and a \"base_uri\" if utilized by\n     * the concrete client.\n     *\n     * @param string|null $option The config option to retrieve.\n     *\n     * @return mixed\n     */\n    public function getConfig($option = null);\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/guzzle/src/Cookie/CookieJar.php",
    "content": "<?php\nnamespace GuzzleHttp\\Cookie;\n\nuse Psr\\Http\\Message\\RequestInterface;\nuse Psr\\Http\\Message\\ResponseInterface;\n\n/**\n * Cookie jar that stores cookies as an array\n */\nclass CookieJar implements CookieJarInterface\n{\n    /** @var SetCookie[] Loaded cookie data */\n    private $cookies = [];\n\n    /** @var bool */\n    private $strictMode;\n\n    /**\n     * @param bool $strictMode   Set to true to throw exceptions when invalid\n     *                           cookies are added to the cookie jar.\n     * @param array $cookieArray Array of SetCookie objects or a hash of\n     *                           arrays that can be used with the SetCookie\n     *                           constructor\n     */\n    public function __construct($strictMode = false, $cookieArray = [])\n    {\n        $this->strictMode = $strictMode;\n\n        foreach ($cookieArray as $cookie) {\n            if (!($cookie instanceof SetCookie)) {\n                $cookie = new SetCookie($cookie);\n            }\n            $this->setCookie($cookie);\n        }\n    }\n\n    /**\n     * Create a new Cookie jar from an associative array and domain.\n     *\n     * @param array  $cookies Cookies to create the jar from\n     * @param string $domain  Domain to set the cookies to\n     *\n     * @return self\n     */\n    public static function fromArray(array $cookies, $domain)\n    {\n        $cookieJar = new self();\n        foreach ($cookies as $name => $value) {\n            $cookieJar->setCookie(new SetCookie([\n                'Domain'  => $domain,\n                'Name'    => $name,\n                'Value'   => $value,\n                'Discard' => true\n            ]));\n        }\n\n        return $cookieJar;\n    }\n\n    /**\n     * @deprecated\n     */\n    public static function getCookieValue($value)\n    {\n        return $value;\n    }\n\n    /**\n     * Evaluate if this cookie should be persisted to storage\n     * that survives between requests.\n     *\n     * @param SetCookie $cookie Being evaluated.\n     * @param bool $allowSessionCookies If we should persist session cookies\n     * @return bool\n     */\n    public static function shouldPersist(\n        SetCookie $cookie,\n        $allowSessionCookies = false\n    ) {\n        if ($cookie->getExpires() || $allowSessionCookies) {\n            if (!$cookie->getDiscard()) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * Finds and returns the cookie based on the name\n     *\n     * @param string $name cookie name to search for\n     * @return SetCookie|null cookie that was found or null if not found\n     */\n    public function getCookieByName($name)\n    {\n        // don't allow a non string name\n        if ($name === null || !is_scalar($name)) {\n            return null;\n        }\n        foreach ($this->cookies as $cookie) {\n            if ($cookie->getName() !== null && strcasecmp($cookie->getName(), $name) === 0) {\n                return $cookie;\n            }\n        }\n\n        return null;\n    }\n\n    public function toArray()\n    {\n        return array_map(function (SetCookie $cookie) {\n            return $cookie->toArray();\n        }, $this->getIterator()->getArrayCopy());\n    }\n\n    public function clear($domain = null, $path = null, $name = null)\n    {\n        if (!$domain) {\n            $this->cookies = [];\n            return;\n        } elseif (!$path) {\n            $this->cookies = array_filter(\n                $this->cookies,\n                function (SetCookie $cookie) use ($domain) {\n                    return !$cookie->matchesDomain($domain);\n                }\n            );\n        } elseif (!$name) {\n            $this->cookies = array_filter(\n                $this->cookies,\n                function (SetCookie $cookie) use ($path, $domain) {\n                    return !($cookie->matchesPath($path) &&\n                        $cookie->matchesDomain($domain));\n                }\n            );\n        } else {\n            $this->cookies = array_filter(\n                $this->cookies,\n                function (SetCookie $cookie) use ($path, $domain, $name) {\n                    return !($cookie->getName() == $name &&\n                        $cookie->matchesPath($path) &&\n                        $cookie->matchesDomain($domain));\n                }\n            );\n        }\n    }\n\n    public function clearSessionCookies()\n    {\n        $this->cookies = array_filter(\n            $this->cookies,\n            function (SetCookie $cookie) {\n                return !$cookie->getDiscard() && $cookie->getExpires();\n            }\n        );\n    }\n\n    public function setCookie(SetCookie $cookie)\n    {\n        // If the name string is empty (but not 0), ignore the set-cookie\n        // string entirely.\n        $name = $cookie->getName();\n        if (!$name && $name !== '0') {\n            return false;\n        }\n\n        // Only allow cookies with set and valid domain, name, value\n        $result = $cookie->validate();\n        if ($result !== true) {\n            if ($this->strictMode) {\n                throw new \\RuntimeException('Invalid cookie: ' . $result);\n            } else {\n                $this->removeCookieIfEmpty($cookie);\n                return false;\n            }\n        }\n\n        // Resolve conflicts with previously set cookies\n        foreach ($this->cookies as $i => $c) {\n\n            // Two cookies are identical, when their path, and domain are\n            // identical.\n            if ($c->getPath() != $cookie->getPath() ||\n                $c->getDomain() != $cookie->getDomain() ||\n                $c->getName() != $cookie->getName()\n            ) {\n                continue;\n            }\n\n            // The previously set cookie is a discard cookie and this one is\n            // not so allow the new cookie to be set\n            if (!$cookie->getDiscard() && $c->getDiscard()) {\n                unset($this->cookies[$i]);\n                continue;\n            }\n\n            // If the new cookie's expiration is further into the future, then\n            // replace the old cookie\n            if ($cookie->getExpires() > $c->getExpires()) {\n                unset($this->cookies[$i]);\n                continue;\n            }\n\n            // If the value has changed, we better change it\n            if ($cookie->getValue() !== $c->getValue()) {\n                unset($this->cookies[$i]);\n                continue;\n            }\n\n            // The cookie exists, so no need to continue\n            return false;\n        }\n\n        $this->cookies[] = $cookie;\n\n        return true;\n    }\n\n    public function count()\n    {\n        return count($this->cookies);\n    }\n\n    public function getIterator()\n    {\n        return new \\ArrayIterator(array_values($this->cookies));\n    }\n\n    public function extractCookies(\n        RequestInterface $request,\n        ResponseInterface $response\n    ) {\n        if ($cookieHeader = $response->getHeader('Set-Cookie')) {\n            foreach ($cookieHeader as $cookie) {\n                $sc = SetCookie::fromString($cookie);\n                if (!$sc->getDomain()) {\n                    $sc->setDomain($request->getUri()->getHost());\n                }\n                if (0 !== strpos($sc->getPath(), '/')) {\n                    $sc->setPath($this->getCookiePathFromRequest($request));\n                }\n                if (!$sc->matchesDomain($request->getUri()->getHost())) {\n                    continue;\n                }\n                // Note: At this point `$sc->getDomain()` being a public suffix should\n                // be rejected, but we don't want to pull in the full PSL dependency.\n                $this->setCookie($sc);\n            }\n        }\n    }\n\n    /**\n     * Computes cookie path following RFC 6265 section 5.1.4\n     *\n     * @link https://tools.ietf.org/html/rfc6265#section-5.1.4\n     *\n     * @param RequestInterface $request\n     * @return string\n     */\n    private function getCookiePathFromRequest(RequestInterface $request)\n    {\n        $uriPath = $request->getUri()->getPath();\n        if (''  === $uriPath) {\n            return '/';\n        }\n        if (0 !== strpos($uriPath, '/')) {\n            return '/';\n        }\n        if ('/' === $uriPath) {\n            return '/';\n        }\n        if (0 === $lastSlashPos = strrpos($uriPath, '/')) {\n            return '/';\n        }\n\n        return substr($uriPath, 0, $lastSlashPos);\n    }\n\n    public function withCookieHeader(RequestInterface $request)\n    {\n        $values = [];\n        $uri = $request->getUri();\n        $scheme = $uri->getScheme();\n        $host = $uri->getHost();\n        $path = $uri->getPath() ?: '/';\n\n        foreach ($this->cookies as $cookie) {\n            if ($cookie->matchesPath($path) &&\n                $cookie->matchesDomain($host) &&\n                !$cookie->isExpired() &&\n                (!$cookie->getSecure() || $scheme === 'https')\n            ) {\n                $values[] = $cookie->getName() . '='\n                    . $cookie->getValue();\n            }\n        }\n\n        return $values\n            ? $request->withHeader('Cookie', implode('; ', $values))\n            : $request;\n    }\n\n    /**\n     * If a cookie already exists and the server asks to set it again with a\n     * null value, the cookie must be deleted.\n     *\n     * @param SetCookie $cookie\n     */\n    private function removeCookieIfEmpty(SetCookie $cookie)\n    {\n        $cookieValue = $cookie->getValue();\n        if ($cookieValue === null || $cookieValue === '') {\n            $this->clear(\n                $cookie->getDomain(),\n                $cookie->getPath(),\n                $cookie->getName()\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php",
    "content": "<?php\nnamespace GuzzleHttp\\Cookie;\n\nuse Psr\\Http\\Message\\RequestInterface;\nuse Psr\\Http\\Message\\ResponseInterface;\n\n/**\n * Stores HTTP cookies.\n *\n * It extracts cookies from HTTP requests, and returns them in HTTP responses.\n * CookieJarInterface instances automatically expire contained cookies when\n * necessary. Subclasses are also responsible for storing and retrieving\n * cookies from a file, database, etc.\n *\n * @link http://docs.python.org/2/library/cookielib.html Inspiration\n */\ninterface CookieJarInterface extends \\Countable, \\IteratorAggregate\n{\n    /**\n     * Create a request with added cookie headers.\n     *\n     * If no matching cookies are found in the cookie jar, then no Cookie\n     * header is added to the request and the same request is returned.\n     *\n     * @param RequestInterface $request Request object to modify.\n     *\n     * @return RequestInterface returns the modified request.\n     */\n    public function withCookieHeader(RequestInterface $request);\n\n    /**\n     * Extract cookies from an HTTP response and store them in the CookieJar.\n     *\n     * @param RequestInterface  $request  Request that was sent\n     * @param ResponseInterface $response Response that was received\n     */\n    public function extractCookies(\n        RequestInterface $request,\n        ResponseInterface $response\n    );\n\n    /**\n     * Sets a cookie in the cookie jar.\n     *\n     * @param SetCookie $cookie Cookie to set.\n     *\n     * @return bool Returns true on success or false on failure\n     */\n    public function setCookie(SetCookie $cookie);\n\n    /**\n     * Remove cookies currently held in the cookie jar.\n     *\n     * Invoking this method without arguments will empty the whole cookie jar.\n     * If given a $domain argument only cookies belonging to that domain will\n     * be removed. If given a $domain and $path argument, cookies belonging to\n     * the specified path within that domain are removed. If given all three\n     * arguments, then the cookie with the specified name, path and domain is\n     * removed.\n     *\n     * @param string|null $domain Clears cookies matching a domain\n     * @param string|null $path   Clears cookies matching a domain and path\n     * @param string|null $name   Clears cookies matching a domain, path, and name\n     *\n     * @return CookieJarInterface\n     */\n    public function clear($domain = null, $path = null, $name = null);\n\n    /**\n     * Discard all sessions cookies.\n     *\n     * Removes cookies that don't have an expire field or a have a discard\n     * field set to true. To be called when the user agent shuts down according\n     * to RFC 2965.\n     */\n    public function clearSessionCookies();\n\n    /**\n     * Converts the cookie jar to an array.\n     *\n     * @return array\n     */\n    public function toArray();\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php",
    "content": "<?php\nnamespace GuzzleHttp\\Cookie;\n\n/**\n * Persists non-session cookies using a JSON formatted file\n */\nclass FileCookieJar extends CookieJar\n{\n    /** @var string filename */\n    private $filename;\n\n    /** @var bool Control whether to persist session cookies or not. */\n    private $storeSessionCookies;\n\n    /**\n     * Create a new FileCookieJar object\n     *\n     * @param string $cookieFile        File to store the cookie data\n     * @param bool $storeSessionCookies Set to true to store session cookies\n     *                                  in the cookie jar.\n     *\n     * @throws \\RuntimeException if the file cannot be found or created\n     */\n    public function __construct($cookieFile, $storeSessionCookies = false)\n    {\n        parent::__construct();\n        $this->filename = $cookieFile;\n        $this->storeSessionCookies = $storeSessionCookies;\n\n        if (file_exists($cookieFile)) {\n            $this->load($cookieFile);\n        }\n    }\n\n    /**\n     * Saves the file when shutting down\n     */\n    public function __destruct()\n    {\n        $this->save($this->filename);\n    }\n\n    /**\n     * Saves the cookies to a file.\n     *\n     * @param string $filename File to save\n     * @throws \\RuntimeException if the file cannot be found or created\n     */\n    public function save($filename)\n    {\n        $json = [];\n        foreach ($this as $cookie) {\n            /** @var SetCookie $cookie */\n            if (CookieJar::shouldPersist($cookie, $this->storeSessionCookies)) {\n                $json[] = $cookie->toArray();\n            }\n        }\n\n        $jsonStr = \\GuzzleHttp\\json_encode($json);\n        if (false === file_put_contents($filename, $jsonStr, LOCK_EX)) {\n            throw new \\RuntimeException(\"Unable to save file {$filename}\");\n        }\n    }\n\n    /**\n     * Load cookies from a JSON formatted file.\n     *\n     * Old cookies are kept unless overwritten by newly loaded ones.\n     *\n     * @param string $filename Cookie file to load.\n     * @throws \\RuntimeException if the file cannot be loaded.\n     */\n    public function load($filename)\n    {\n        $json = file_get_contents($filename);\n        if (false === $json) {\n            throw new \\RuntimeException(\"Unable to load file {$filename}\");\n        } elseif ($json === '') {\n            return;\n        }\n\n        $data = \\GuzzleHttp\\json_decode($json, true);\n        if (is_array($data)) {\n            foreach (json_decode($json, true) as $cookie) {\n                $this->setCookie(new SetCookie($cookie));\n            }\n        } elseif (strlen($data)) {\n            throw new \\RuntimeException(\"Invalid cookie file: {$filename}\");\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php",
    "content": "<?php\nnamespace GuzzleHttp\\Cookie;\n\n/**\n * Persists cookies in the client session\n */\nclass SessionCookieJar extends CookieJar\n{\n    /** @var string session key */\n    private $sessionKey;\n    \n    /** @var bool Control whether to persist session cookies or not. */\n    private $storeSessionCookies;\n\n    /**\n     * Create a new SessionCookieJar object\n     *\n     * @param string $sessionKey        Session key name to store the cookie\n     *                                  data in session\n     * @param bool $storeSessionCookies Set to true to store session cookies\n     *                                  in the cookie jar.\n     */\n    public function __construct($sessionKey, $storeSessionCookies = false)\n    {\n        parent::__construct();\n        $this->sessionKey = $sessionKey;\n        $this->storeSessionCookies = $storeSessionCookies;\n        $this->load();\n    }\n\n    /**\n     * Saves cookies to session when shutting down\n     */\n    public function __destruct()\n    {\n        $this->save();\n    }\n\n    /**\n     * Save cookies to the client session\n     */\n    public function save()\n    {\n        $json = [];\n        foreach ($this as $cookie) {\n            /** @var SetCookie $cookie */\n            if (CookieJar::shouldPersist($cookie, $this->storeSessionCookies)) {\n                $json[] = $cookie->toArray();\n            }\n        }\n\n        $_SESSION[$this->sessionKey] = json_encode($json);\n    }\n\n    /**\n     * Load the contents of the client session into the data array\n     */\n    protected function load()\n    {\n        if (!isset($_SESSION[$this->sessionKey])) {\n            return;\n        }\n        $data = json_decode($_SESSION[$this->sessionKey], true);\n        if (is_array($data)) {\n            foreach ($data as $cookie) {\n                $this->setCookie(new SetCookie($cookie));\n            }\n        } elseif (strlen($data)) {\n            throw new \\RuntimeException(\"Invalid cookie data\");\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/guzzle/src/Cookie/SetCookie.php",
    "content": "<?php\nnamespace GuzzleHttp\\Cookie;\n\n/**\n * Set-Cookie object\n */\nclass SetCookie\n{\n    /** @var array */\n    private static $defaults = [\n        'Name'     => null,\n        'Value'    => null,\n        'Domain'   => null,\n        'Path'     => '/',\n        'Max-Age'  => null,\n        'Expires'  => null,\n        'Secure'   => false,\n        'Discard'  => false,\n        'HttpOnly' => false\n    ];\n\n    /** @var array Cookie data */\n    private $data;\n\n    /**\n     * Create a new SetCookie object from a string\n     *\n     * @param string $cookie Set-Cookie header string\n     *\n     * @return self\n     */\n    public static function fromString($cookie)\n    {\n        // Create the default return array\n        $data = self::$defaults;\n        // Explode the cookie string using a series of semicolons\n        $pieces = array_filter(array_map('trim', explode(';', $cookie)));\n        // The name of the cookie (first kvp) must exist and include an equal sign.\n        if (empty($pieces[0]) || !strpos($pieces[0], '=')) {\n            return new self($data);\n        }\n\n        // Add the cookie pieces into the parsed data array\n        foreach ($pieces as $part) {\n            $cookieParts = explode('=', $part, 2);\n            $key = trim($cookieParts[0]);\n            $value = isset($cookieParts[1])\n                ? trim($cookieParts[1], \" \\n\\r\\t\\0\\x0B\")\n                : true;\n\n            // Only check for non-cookies when cookies have been found\n            if (empty($data['Name'])) {\n                $data['Name'] = $key;\n                $data['Value'] = $value;\n            } else {\n                foreach (array_keys(self::$defaults) as $search) {\n                    if (!strcasecmp($search, $key)) {\n                        $data[$search] = $value;\n                        continue 2;\n                    }\n                }\n                $data[$key] = $value;\n            }\n        }\n\n        return new self($data);\n    }\n\n    /**\n     * @param array $data Array of cookie data provided by a Cookie parser\n     */\n    public function __construct(array $data = [])\n    {\n        $this->data = array_replace(self::$defaults, $data);\n        // Extract the Expires value and turn it into a UNIX timestamp if needed\n        if (!$this->getExpires() && $this->getMaxAge()) {\n            // Calculate the Expires date\n            $this->setExpires(time() + $this->getMaxAge());\n        } elseif ($this->getExpires() && !is_numeric($this->getExpires())) {\n            $this->setExpires($this->getExpires());\n        }\n    }\n\n    public function __toString()\n    {\n        $str = $this->data['Name'] . '=' . $this->data['Value'] . '; ';\n        foreach ($this->data as $k => $v) {\n            if ($k !== 'Name' && $k !== 'Value' && $v !== null && $v !== false) {\n                if ($k === 'Expires') {\n                    $str .= 'Expires=' . gmdate('D, d M Y H:i:s \\G\\M\\T', $v) . '; ';\n                } else {\n                    $str .= ($v === true ? $k : \"{$k}={$v}\") . '; ';\n                }\n            }\n        }\n\n        return rtrim($str, '; ');\n    }\n\n    public function toArray()\n    {\n        return $this->data;\n    }\n\n    /**\n     * Get the cookie name\n     *\n     * @return string\n     */\n    public function getName()\n    {\n        return $this->data['Name'];\n    }\n\n    /**\n     * Set the cookie name\n     *\n     * @param string $name Cookie name\n     */\n    public function setName($name)\n    {\n        $this->data['Name'] = $name;\n    }\n\n    /**\n     * Get the cookie value\n     *\n     * @return string\n     */\n    public function getValue()\n    {\n        return $this->data['Value'];\n    }\n\n    /**\n     * Set the cookie value\n     *\n     * @param string $value Cookie value\n     */\n    public function setValue($value)\n    {\n        $this->data['Value'] = $value;\n    }\n\n    /**\n     * Get the domain\n     *\n     * @return string|null\n     */\n    public function getDomain()\n    {\n        return $this->data['Domain'];\n    }\n\n    /**\n     * Set the domain of the cookie\n     *\n     * @param string $domain\n     */\n    public function setDomain($domain)\n    {\n        $this->data['Domain'] = $domain;\n    }\n\n    /**\n     * Get the path\n     *\n     * @return string\n     */\n    public function getPath()\n    {\n        return $this->data['Path'];\n    }\n\n    /**\n     * Set the path of the cookie\n     *\n     * @param string $path Path of the cookie\n     */\n    public function setPath($path)\n    {\n        $this->data['Path'] = $path;\n    }\n\n    /**\n     * Maximum lifetime of the cookie in seconds\n     *\n     * @return int|null\n     */\n    public function getMaxAge()\n    {\n        return $this->data['Max-Age'];\n    }\n\n    /**\n     * Set the max-age of the cookie\n     *\n     * @param int $maxAge Max age of the cookie in seconds\n     */\n    public function setMaxAge($maxAge)\n    {\n        $this->data['Max-Age'] = $maxAge;\n    }\n\n    /**\n     * The UNIX timestamp when the cookie Expires\n     *\n     * @return mixed\n     */\n    public function getExpires()\n    {\n        return $this->data['Expires'];\n    }\n\n    /**\n     * Set the unix timestamp for which the cookie will expire\n     *\n     * @param int $timestamp Unix timestamp\n     */\n    public function setExpires($timestamp)\n    {\n        $this->data['Expires'] = is_numeric($timestamp)\n            ? (int) $timestamp\n            : strtotime($timestamp);\n    }\n\n    /**\n     * Get whether or not this is a secure cookie\n     *\n     * @return bool|null\n     */\n    public function getSecure()\n    {\n        return $this->data['Secure'];\n    }\n\n    /**\n     * Set whether or not the cookie is secure\n     *\n     * @param bool $secure Set to true or false if secure\n     */\n    public function setSecure($secure)\n    {\n        $this->data['Secure'] = $secure;\n    }\n\n    /**\n     * Get whether or not this is a session cookie\n     *\n     * @return bool|null\n     */\n    public function getDiscard()\n    {\n        return $this->data['Discard'];\n    }\n\n    /**\n     * Set whether or not this is a session cookie\n     *\n     * @param bool $discard Set to true or false if this is a session cookie\n     */\n    public function setDiscard($discard)\n    {\n        $this->data['Discard'] = $discard;\n    }\n\n    /**\n     * Get whether or not this is an HTTP only cookie\n     *\n     * @return bool\n     */\n    public function getHttpOnly()\n    {\n        return $this->data['HttpOnly'];\n    }\n\n    /**\n     * Set whether or not this is an HTTP only cookie\n     *\n     * @param bool $httpOnly Set to true or false if this is HTTP only\n     */\n    public function setHttpOnly($httpOnly)\n    {\n        $this->data['HttpOnly'] = $httpOnly;\n    }\n\n    /**\n     * Check if the cookie matches a path value.\n     *\n     * A request-path path-matches a given cookie-path if at least one of\n     * the following conditions holds:\n     *\n     * - The cookie-path and the request-path are identical.\n     * - The cookie-path is a prefix of the request-path, and the last\n     *   character of the cookie-path is %x2F (\"/\").\n     * - The cookie-path is a prefix of the request-path, and the first\n     *   character of the request-path that is not included in the cookie-\n     *   path is a %x2F (\"/\") character.\n     *\n     * @param string $requestPath Path to check against\n     *\n     * @return bool\n     */\n    public function matchesPath($requestPath)\n    {\n        $cookiePath = $this->getPath();\n\n        // Match on exact matches or when path is the default empty \"/\"\n        if ($cookiePath === '/' || $cookiePath == $requestPath) {\n            return true;\n        }\n\n        // Ensure that the cookie-path is a prefix of the request path.\n        if (0 !== strpos($requestPath, $cookiePath)) {\n            return false;\n        }\n\n        // Match if the last character of the cookie-path is \"/\"\n        if (substr($cookiePath, -1, 1) === '/') {\n            return true;\n        }\n\n        // Match if the first character not included in cookie path is \"/\"\n        return substr($requestPath, strlen($cookiePath), 1) === '/';\n    }\n\n    /**\n     * Check if the cookie matches a domain value\n     *\n     * @param string $domain Domain to check against\n     *\n     * @return bool\n     */\n    public function matchesDomain($domain)\n    {\n        $cookieDomain = $this->getDomain();\n        if (null === $cookieDomain) {\n            return true;\n        }\n\n        // Remove the leading '.' as per spec in RFC 6265.\n        // http://tools.ietf.org/html/rfc6265#section-5.2.3\n        $cookieDomain = ltrim(strtolower($cookieDomain), '.');\n\n        $domain = strtolower($domain);\n\n        // Domain not set or exact match.\n        if ('' === $cookieDomain || $domain === $cookieDomain) {\n            return true;\n        }\n\n        // Matching the subdomain according to RFC 6265.\n        // http://tools.ietf.org/html/rfc6265#section-5.1.3\n        if (filter_var($domain, FILTER_VALIDATE_IP)) {\n            return false;\n        }\n\n        return (bool) preg_match('/\\.' . preg_quote($cookieDomain, '/') . '$/', $domain);\n    }\n\n    /**\n     * Check if the cookie is expired\n     *\n     * @return bool\n     */\n    public function isExpired()\n    {\n        return $this->getExpires() !== null && time() > $this->getExpires();\n    }\n\n    /**\n     * Check if the cookie is valid according to RFC 6265\n     *\n     * @return bool|string Returns true if valid or an error message if invalid\n     */\n    public function validate()\n    {\n        // Names must not be empty, but can be 0\n        $name = $this->getName();\n        if (empty($name) && !is_numeric($name)) {\n            return 'The cookie name must not be empty';\n        }\n\n        // Check if any of the invalid characters are present in the cookie name\n        if (preg_match(\n            '/[\\x00-\\x20\\x22\\x28-\\x29\\x2c\\x2f\\x3a-\\x40\\x5c\\x7b\\x7d\\x7f]/',\n            $name\n        )) {\n            return 'Cookie name must not contain invalid characters: ASCII '\n                . 'Control characters (0-31;127), space, tab and the '\n                . 'following characters: ()<>@,;:\\\"/?={}';\n        }\n\n        // Value must not be empty, but can be 0\n        $value = $this->getValue();\n        if (empty($value) && !is_numeric($value)) {\n            return 'The cookie value must not be empty';\n        }\n\n        // Domains must not be empty, but can be 0\n        // A \"0\" is not a valid internet domain, but may be used as server name\n        // in a private network.\n        $domain = $this->getDomain();\n        if (empty($domain) && !is_numeric($domain)) {\n            return 'The cookie domain must not be empty';\n        }\n\n        return true;\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/guzzle/src/Exception/BadResponseException.php",
    "content": "<?php\nnamespace GuzzleHttp\\Exception;\n\nuse Psr\\Http\\Message\\RequestInterface;\nuse Psr\\Http\\Message\\ResponseInterface;\n\n/**\n * Exception when an HTTP error occurs (4xx or 5xx error)\n */\nclass BadResponseException extends RequestException\n{\n    public function __construct(\n        $message,\n        RequestInterface $request,\n        ResponseInterface $response = null,\n        \\Exception $previous = null,\n        array $handlerContext = []\n    ) {\n        if (null === $response) {\n            @trigger_error(\n                'Instantiating the ' . __CLASS__ . ' class without a Response is deprecated since version 6.3 and will be removed in 7.0.',\n                E_USER_DEPRECATED\n            );\n        }\n        parent::__construct($message, $request, $response, $previous, $handlerContext);\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/guzzle/src/Exception/ClientException.php",
    "content": "<?php\nnamespace GuzzleHttp\\Exception;\n\n/**\n * Exception when a client error is encountered (4xx codes)\n */\nclass ClientException extends BadResponseException\n{\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/guzzle/src/Exception/ConnectException.php",
    "content": "<?php\nnamespace GuzzleHttp\\Exception;\n\nuse Psr\\Http\\Message\\RequestInterface;\n\n/**\n * Exception thrown when a connection cannot be established.\n *\n * Note that no response is present for a ConnectException\n */\nclass ConnectException extends RequestException\n{\n    public function __construct(\n        $message,\n        RequestInterface $request,\n        \\Exception $previous = null,\n        array $handlerContext = []\n    ) {\n        parent::__construct($message, $request, null, $previous, $handlerContext);\n    }\n\n    /**\n     * @return null\n     */\n    public function getResponse()\n    {\n        return null;\n    }\n\n    /**\n     * @return bool\n     */\n    public function hasResponse()\n    {\n        return false;\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/guzzle/src/Exception/GuzzleException.php",
    "content": "<?php\nnamespace GuzzleHttp\\Exception;\n\nuse Throwable;\n\nif (interface_exists(Throwable::class)) {\n    interface GuzzleException extends Throwable\n    {\n    }\n} else {\n    /**\n     * @method string getMessage()\n     * @method \\Throwable|null getPrevious()\n     * @method mixed getCode()\n     * @method string getFile()\n     * @method int getLine()\n     * @method array getTrace()\n     * @method string getTraceAsString()\n     */\n    interface GuzzleException\n    {\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/guzzle/src/Exception/InvalidArgumentException.php",
    "content": "<?php\n\nnamespace GuzzleHttp\\Exception;\n\nfinal class InvalidArgumentException extends \\InvalidArgumentException implements GuzzleException\n{\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php",
    "content": "<?php\nnamespace GuzzleHttp\\Exception;\n\nuse GuzzleHttp\\Promise\\PromiseInterface;\nuse Psr\\Http\\Message\\RequestInterface;\nuse Psr\\Http\\Message\\ResponseInterface;\nuse Psr\\Http\\Message\\UriInterface;\n\n/**\n * HTTP Request exception\n */\nclass RequestException extends TransferException\n{\n    /** @var RequestInterface */\n    private $request;\n\n    /** @var ResponseInterface|null */\n    private $response;\n\n    /** @var array */\n    private $handlerContext;\n\n    public function __construct(\n        $message,\n        RequestInterface $request,\n        ResponseInterface $response = null,\n        \\Exception $previous = null,\n        array $handlerContext = []\n    ) {\n        // Set the code of the exception if the response is set and not future.\n        $code = $response && !($response instanceof PromiseInterface)\n            ? $response->getStatusCode()\n            : 0;\n        parent::__construct($message, $code, $previous);\n        $this->request = $request;\n        $this->response = $response;\n        $this->handlerContext = $handlerContext;\n    }\n\n    /**\n     * Wrap non-RequestExceptions with a RequestException\n     *\n     * @param RequestInterface $request\n     * @param \\Exception       $e\n     *\n     * @return RequestException\n     */\n    public static function wrapException(RequestInterface $request, \\Exception $e)\n    {\n        return $e instanceof RequestException\n            ? $e\n            : new RequestException($e->getMessage(), $request, null, $e);\n    }\n\n    /**\n     * Factory method to create a new exception with a normalized error message\n     *\n     * @param RequestInterface  $request  Request\n     * @param ResponseInterface $response Response received\n     * @param \\Exception        $previous Previous exception\n     * @param array             $ctx      Optional handler context.\n     *\n     * @return self\n     */\n    public static function create(\n        RequestInterface $request,\n        ResponseInterface $response = null,\n        \\Exception $previous = null,\n        array $ctx = []\n    ) {\n        if (!$response) {\n            return new self(\n                'Error completing request',\n                $request,\n                null,\n                $previous,\n                $ctx\n            );\n        }\n\n        $level = (int) floor($response->getStatusCode() / 100);\n        if ($level === 4) {\n            $label = 'Client error';\n            $className = ClientException::class;\n        } elseif ($level === 5) {\n            $label = 'Server error';\n            $className = ServerException::class;\n        } else {\n            $label = 'Unsuccessful request';\n            $className = __CLASS__;\n        }\n\n        $uri = $request->getUri();\n        $uri = static::obfuscateUri($uri);\n\n        // Client Error: `GET /` resulted in a `404 Not Found` response:\n        // <html> ... (truncated)\n        $message = sprintf(\n            '%s: `%s %s` resulted in a `%s %s` response',\n            $label,\n            $request->getMethod(),\n            $uri,\n            $response->getStatusCode(),\n            $response->getReasonPhrase()\n        );\n\n        $summary = static::getResponseBodySummary($response);\n\n        if ($summary !== null) {\n            $message .= \":\\n{$summary}\\n\";\n        }\n\n        return new $className($message, $request, $response, $previous, $ctx);\n    }\n\n    /**\n     * Get a short summary of the response\n     *\n     * Will return `null` if the response is not printable.\n     *\n     * @param ResponseInterface $response\n     *\n     * @return string|null\n     */\n    public static function getResponseBodySummary(ResponseInterface $response)\n    {\n        return \\GuzzleHttp\\Psr7\\get_message_body_summary($response);\n    }\n\n    /**\n     * Obfuscates URI if there is a username and a password present\n     *\n     * @param UriInterface $uri\n     *\n     * @return UriInterface\n     */\n    private static function obfuscateUri(UriInterface $uri)\n    {\n        $userInfo = $uri->getUserInfo();\n\n        if (false !== ($pos = strpos($userInfo, ':'))) {\n            return $uri->withUserInfo(substr($userInfo, 0, $pos), '***');\n        }\n\n        return $uri;\n    }\n\n    /**\n     * Get the request that caused the exception\n     *\n     * @return RequestInterface\n     */\n    public function getRequest()\n    {\n        return $this->request;\n    }\n\n    /**\n     * Get the associated response\n     *\n     * @return ResponseInterface|null\n     */\n    public function getResponse()\n    {\n        return $this->response;\n    }\n\n    /**\n     * Check if a response was received\n     *\n     * @return bool\n     */\n    public function hasResponse()\n    {\n        return $this->response !== null;\n    }\n\n    /**\n     * Get contextual information about the error from the underlying handler.\n     *\n     * The contents of this array will vary depending on which handler you are\n     * using. It may also be just an empty array. Relying on this data will\n     * couple you to a specific handler, but can give more debug information\n     * when needed.\n     *\n     * @return array\n     */\n    public function getHandlerContext()\n    {\n        return $this->handlerContext;\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/guzzle/src/Exception/SeekException.php",
    "content": "<?php\nnamespace GuzzleHttp\\Exception;\n\nuse Psr\\Http\\Message\\StreamInterface;\n\n/**\n * Exception thrown when a seek fails on a stream.\n */\nclass SeekException extends \\RuntimeException implements GuzzleException\n{\n    private $stream;\n\n    public function __construct(StreamInterface $stream, $pos = 0, $msg = '')\n    {\n        $this->stream = $stream;\n        $msg = $msg ?: 'Could not seek the stream to position ' . $pos;\n        parent::__construct($msg);\n    }\n\n    /**\n     * @return StreamInterface\n     */\n    public function getStream()\n    {\n        return $this->stream;\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/guzzle/src/Exception/ServerException.php",
    "content": "<?php\nnamespace GuzzleHttp\\Exception;\n\n/**\n * Exception when a server error is encountered (5xx codes)\n */\nclass ServerException extends BadResponseException\n{\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/guzzle/src/Exception/TooManyRedirectsException.php",
    "content": "<?php\nnamespace GuzzleHttp\\Exception;\n\nclass TooManyRedirectsException extends RequestException\n{\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/guzzle/src/Exception/TransferException.php",
    "content": "<?php\nnamespace GuzzleHttp\\Exception;\n\nclass TransferException extends \\RuntimeException implements GuzzleException\n{\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php",
    "content": "<?php\nnamespace GuzzleHttp\\Handler;\n\nuse GuzzleHttp\\Exception\\ConnectException;\nuse GuzzleHttp\\Exception\\RequestException;\nuse GuzzleHttp\\Promise\\FulfilledPromise;\nuse GuzzleHttp\\Psr7;\nuse GuzzleHttp\\Psr7\\LazyOpenStream;\nuse GuzzleHttp\\TransferStats;\nuse Psr\\Http\\Message\\RequestInterface;\n\n/**\n * Creates curl resources from a request\n */\nclass CurlFactory implements CurlFactoryInterface\n{\n    const CURL_VERSION_STR = 'curl_version';\n    const LOW_CURL_VERSION_NUMBER = '7.21.2';\n\n    /** @var array */\n    private $handles = [];\n\n    /** @var int Total number of idle handles to keep in cache */\n    private $maxHandles;\n\n    /**\n     * @param int $maxHandles Maximum number of idle handles.\n     */\n    public function __construct($maxHandles)\n    {\n        $this->maxHandles = $maxHandles;\n    }\n\n    public function create(RequestInterface $request, array $options)\n    {\n        if (isset($options['curl']['body_as_string'])) {\n            $options['_body_as_string'] = $options['curl']['body_as_string'];\n            unset($options['curl']['body_as_string']);\n        }\n\n        $easy = new EasyHandle;\n        $easy->request = $request;\n        $easy->options = $options;\n        $conf = $this->getDefaultConf($easy);\n        $this->applyMethod($easy, $conf);\n        $this->applyHandlerOptions($easy, $conf);\n        $this->applyHeaders($easy, $conf);\n        unset($conf['_headers']);\n\n        // Add handler options from the request configuration options\n        if (isset($options['curl'])) {\n            $conf = array_replace($conf, $options['curl']);\n        }\n\n        $conf[CURLOPT_HEADERFUNCTION] = $this->createHeaderFn($easy);\n        $easy->handle = $this->handles\n            ? array_pop($this->handles)\n            : curl_init();\n        curl_setopt_array($easy->handle, $conf);\n\n        return $easy;\n    }\n\n    public function release(EasyHandle $easy)\n    {\n        $resource = $easy->handle;\n        unset($easy->handle);\n\n        if (count($this->handles) >= $this->maxHandles) {\n            curl_close($resource);\n        } else {\n            // Remove all callback functions as they can hold onto references\n            // and are not cleaned up by curl_reset. Using curl_setopt_array\n            // does not work for some reason, so removing each one\n            // individually.\n            curl_setopt($resource, CURLOPT_HEADERFUNCTION, null);\n            curl_setopt($resource, CURLOPT_READFUNCTION, null);\n            curl_setopt($resource, CURLOPT_WRITEFUNCTION, null);\n            curl_setopt($resource, CURLOPT_PROGRESSFUNCTION, null);\n            curl_reset($resource);\n            $this->handles[] = $resource;\n        }\n    }\n\n    /**\n     * Completes a cURL transaction, either returning a response promise or a\n     * rejected promise.\n     *\n     * @param callable             $handler\n     * @param EasyHandle           $easy\n     * @param CurlFactoryInterface $factory Dictates how the handle is released\n     *\n     * @return \\GuzzleHttp\\Promise\\PromiseInterface\n     */\n    public static function finish(\n        callable $handler,\n        EasyHandle $easy,\n        CurlFactoryInterface $factory\n    ) {\n        if (isset($easy->options['on_stats'])) {\n            self::invokeStats($easy);\n        }\n\n        if (!$easy->response || $easy->errno) {\n            return self::finishError($handler, $easy, $factory);\n        }\n\n        // Return the response if it is present and there is no error.\n        $factory->release($easy);\n\n        // Rewind the body of the response if possible.\n        $body = $easy->response->getBody();\n        if ($body->isSeekable()) {\n            $body->rewind();\n        }\n\n        return new FulfilledPromise($easy->response);\n    }\n\n    private static function invokeStats(EasyHandle $easy)\n    {\n        $curlStats = curl_getinfo($easy->handle);\n        $curlStats['appconnect_time'] = curl_getinfo($easy->handle, CURLINFO_APPCONNECT_TIME);\n        $stats = new TransferStats(\n            $easy->request,\n            $easy->response,\n            $curlStats['total_time'],\n            $easy->errno,\n            $curlStats\n        );\n        call_user_func($easy->options['on_stats'], $stats);\n    }\n\n    private static function finishError(\n        callable $handler,\n        EasyHandle $easy,\n        CurlFactoryInterface $factory\n    ) {\n        // Get error information and release the handle to the factory.\n        $ctx = [\n            'errno' => $easy->errno,\n            'error' => curl_error($easy->handle),\n            'appconnect_time' => curl_getinfo($easy->handle, CURLINFO_APPCONNECT_TIME),\n        ] + curl_getinfo($easy->handle);\n        $ctx[self::CURL_VERSION_STR] = curl_version()['version'];\n        $factory->release($easy);\n\n        // Retry when nothing is present or when curl failed to rewind.\n        if (empty($easy->options['_err_message'])\n            && (!$easy->errno || $easy->errno == 65)\n        ) {\n            return self::retryFailedRewind($handler, $easy, $ctx);\n        }\n\n        return self::createRejection($easy, $ctx);\n    }\n\n    private static function createRejection(EasyHandle $easy, array $ctx)\n    {\n        static $connectionErrors = [\n            CURLE_OPERATION_TIMEOUTED  => true,\n            CURLE_COULDNT_RESOLVE_HOST => true,\n            CURLE_COULDNT_CONNECT      => true,\n            CURLE_SSL_CONNECT_ERROR    => true,\n            CURLE_GOT_NOTHING          => true,\n        ];\n\n        // If an exception was encountered during the onHeaders event, then\n        // return a rejected promise that wraps that exception.\n        if ($easy->onHeadersException) {\n            return \\GuzzleHttp\\Promise\\rejection_for(\n                new RequestException(\n                    'An error was encountered during the on_headers event',\n                    $easy->request,\n                    $easy->response,\n                    $easy->onHeadersException,\n                    $ctx\n                )\n            );\n        }\n        if (version_compare($ctx[self::CURL_VERSION_STR], self::LOW_CURL_VERSION_NUMBER)) {\n            $message = sprintf(\n                'cURL error %s: %s (%s)',\n                $ctx['errno'],\n                $ctx['error'],\n                'see https://curl.haxx.se/libcurl/c/libcurl-errors.html'\n            );\n        } else {\n            $message = sprintf(\n                'cURL error %s: %s (%s) for %s',\n                $ctx['errno'],\n                $ctx['error'],\n                'see https://curl.haxx.se/libcurl/c/libcurl-errors.html',\n                $easy->request->getUri()\n            );\n        }\n\n        // Create a connection exception if it was a specific error code.\n        $error = isset($connectionErrors[$easy->errno])\n            ? new ConnectException($message, $easy->request, null, $ctx)\n            : new RequestException($message, $easy->request, $easy->response, null, $ctx);\n\n        return \\GuzzleHttp\\Promise\\rejection_for($error);\n    }\n\n    private function getDefaultConf(EasyHandle $easy)\n    {\n        $conf = [\n            '_headers'             => $easy->request->getHeaders(),\n            CURLOPT_CUSTOMREQUEST  => $easy->request->getMethod(),\n            CURLOPT_URL            => (string) $easy->request->getUri()->withFragment(''),\n            CURLOPT_RETURNTRANSFER => false,\n            CURLOPT_HEADER         => false,\n            CURLOPT_CONNECTTIMEOUT => 150,\n        ];\n\n        if (defined('CURLOPT_PROTOCOLS')) {\n            $conf[CURLOPT_PROTOCOLS] = CURLPROTO_HTTP | CURLPROTO_HTTPS;\n        }\n\n        $version = $easy->request->getProtocolVersion();\n        if ($version == 1.1) {\n            $conf[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_1;\n        } elseif ($version == 2.0) {\n            $conf[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_2_0;\n        } else {\n            $conf[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_0;\n        }\n\n        return $conf;\n    }\n\n    private function applyMethod(EasyHandle $easy, array &$conf)\n    {\n        $body = $easy->request->getBody();\n        $size = $body->getSize();\n\n        if ($size === null || $size > 0) {\n            $this->applyBody($easy->request, $easy->options, $conf);\n            return;\n        }\n\n        $method = $easy->request->getMethod();\n        if ($method === 'PUT' || $method === 'POST') {\n            // See http://tools.ietf.org/html/rfc7230#section-3.3.2\n            if (!$easy->request->hasHeader('Content-Length')) {\n                $conf[CURLOPT_HTTPHEADER][] = 'Content-Length: 0';\n            }\n        } elseif ($method === 'HEAD') {\n            $conf[CURLOPT_NOBODY] = true;\n            unset(\n                $conf[CURLOPT_WRITEFUNCTION],\n                $conf[CURLOPT_READFUNCTION],\n                $conf[CURLOPT_FILE],\n                $conf[CURLOPT_INFILE]\n            );\n        }\n    }\n\n    private function applyBody(RequestInterface $request, array $options, array &$conf)\n    {\n        $size = $request->hasHeader('Content-Length')\n            ? (int) $request->getHeaderLine('Content-Length')\n            : null;\n\n        // Send the body as a string if the size is less than 1MB OR if the\n        // [curl][body_as_string] request value is set.\n        if (($size !== null && $size < 1000000) ||\n            !empty($options['_body_as_string'])\n        ) {\n            $conf[CURLOPT_POSTFIELDS] = (string) $request->getBody();\n            // Don't duplicate the Content-Length header\n            $this->removeHeader('Content-Length', $conf);\n            $this->removeHeader('Transfer-Encoding', $conf);\n        } else {\n            $conf[CURLOPT_UPLOAD] = true;\n            if ($size !== null) {\n                $conf[CURLOPT_INFILESIZE] = $size;\n                $this->removeHeader('Content-Length', $conf);\n            }\n            $body = $request->getBody();\n            if ($body->isSeekable()) {\n                $body->rewind();\n            }\n            $conf[CURLOPT_READFUNCTION] = function ($ch, $fd, $length) use ($body) {\n                return $body->read($length);\n            };\n        }\n\n        // If the Expect header is not present, prevent curl from adding it\n        if (!$request->hasHeader('Expect')) {\n            $conf[CURLOPT_HTTPHEADER][] = 'Expect:';\n        }\n\n        // cURL sometimes adds a content-type by default. Prevent this.\n        if (!$request->hasHeader('Content-Type')) {\n            $conf[CURLOPT_HTTPHEADER][] = 'Content-Type:';\n        }\n    }\n\n    private function applyHeaders(EasyHandle $easy, array &$conf)\n    {\n        foreach ($conf['_headers'] as $name => $values) {\n            foreach ($values as $value) {\n                $value = (string) $value;\n                if ($value === '') {\n                    // cURL requires a special format for empty headers.\n                    // See https://github.com/guzzle/guzzle/issues/1882 for more details.\n                    $conf[CURLOPT_HTTPHEADER][] = \"$name;\";\n                } else {\n                    $conf[CURLOPT_HTTPHEADER][] = \"$name: $value\";\n                }\n            }\n        }\n\n        // Remove the Accept header if one was not set\n        if (!$easy->request->hasHeader('Accept')) {\n            $conf[CURLOPT_HTTPHEADER][] = 'Accept:';\n        }\n    }\n\n    /**\n     * Remove a header from the options array.\n     *\n     * @param string $name    Case-insensitive header to remove\n     * @param array  $options Array of options to modify\n     */\n    private function removeHeader($name, array &$options)\n    {\n        foreach (array_keys($options['_headers']) as $key) {\n            if (!strcasecmp($key, $name)) {\n                unset($options['_headers'][$key]);\n                return;\n            }\n        }\n    }\n\n    private function applyHandlerOptions(EasyHandle $easy, array &$conf)\n    {\n        $options = $easy->options;\n        if (isset($options['verify'])) {\n            if ($options['verify'] === false) {\n                unset($conf[CURLOPT_CAINFO]);\n                $conf[CURLOPT_SSL_VERIFYHOST] = 0;\n                $conf[CURLOPT_SSL_VERIFYPEER] = false;\n            } else {\n                $conf[CURLOPT_SSL_VERIFYHOST] = 2;\n                $conf[CURLOPT_SSL_VERIFYPEER] = true;\n                if (is_string($options['verify'])) {\n                    // Throw an error if the file/folder/link path is not valid or doesn't exist.\n                    if (!file_exists($options['verify'])) {\n                        throw new \\InvalidArgumentException(\n                            \"SSL CA bundle not found: {$options['verify']}\"\n                        );\n                    }\n                    // If it's a directory or a link to a directory use CURLOPT_CAPATH.\n                    // If not, it's probably a file, or a link to a file, so use CURLOPT_CAINFO.\n                    if (is_dir($options['verify']) ||\n                        (is_link($options['verify']) && is_dir(readlink($options['verify'])))) {\n                        $conf[CURLOPT_CAPATH] = $options['verify'];\n                    } else {\n                        $conf[CURLOPT_CAINFO] = $options['verify'];\n                    }\n                }\n            }\n        }\n\n        if (!empty($options['decode_content'])) {\n            $accept = $easy->request->getHeaderLine('Accept-Encoding');\n            if ($accept) {\n                $conf[CURLOPT_ENCODING] = $accept;\n            } else {\n                $conf[CURLOPT_ENCODING] = '';\n                // Don't let curl send the header over the wire\n                $conf[CURLOPT_HTTPHEADER][] = 'Accept-Encoding:';\n            }\n        }\n\n        if (isset($options['sink'])) {\n            $sink = $options['sink'];\n            if (!is_string($sink)) {\n                $sink = \\GuzzleHttp\\Psr7\\stream_for($sink);\n            } elseif (!is_dir(dirname($sink))) {\n                // Ensure that the directory exists before failing in curl.\n                throw new \\RuntimeException(sprintf(\n                    'Directory %s does not exist for sink value of %s',\n                    dirname($sink),\n                    $sink\n                ));\n            } else {\n                $sink = new LazyOpenStream($sink, 'w+');\n            }\n            $easy->sink = $sink;\n            $conf[CURLOPT_WRITEFUNCTION] = function ($ch, $write) use ($sink) {\n                return $sink->write($write);\n            };\n        } else {\n            // Use a default temp stream if no sink was set.\n            $conf[CURLOPT_FILE] = fopen('php://temp', 'w+');\n            $easy->sink = Psr7\\stream_for($conf[CURLOPT_FILE]);\n        }\n        $timeoutRequiresNoSignal = false;\n        if (isset($options['timeout'])) {\n            $timeoutRequiresNoSignal |= $options['timeout'] < 1;\n            $conf[CURLOPT_TIMEOUT_MS] = $options['timeout'] * 1000;\n        }\n\n        // CURL default value is CURL_IPRESOLVE_WHATEVER\n        if (isset($options['force_ip_resolve'])) {\n            if ('v4' === $options['force_ip_resolve']) {\n                $conf[CURLOPT_IPRESOLVE] = CURL_IPRESOLVE_V4;\n            } elseif ('v6' === $options['force_ip_resolve']) {\n                $conf[CURLOPT_IPRESOLVE] = CURL_IPRESOLVE_V6;\n            }\n        }\n\n        if (isset($options['connect_timeout'])) {\n            $timeoutRequiresNoSignal |= $options['connect_timeout'] < 1;\n            $conf[CURLOPT_CONNECTTIMEOUT_MS] = $options['connect_timeout'] * 1000;\n        }\n\n        if ($timeoutRequiresNoSignal && strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {\n            $conf[CURLOPT_NOSIGNAL] = true;\n        }\n\n        if (isset($options['proxy'])) {\n            if (!is_array($options['proxy'])) {\n                $conf[CURLOPT_PROXY] = $options['proxy'];\n            } else {\n                $scheme = $easy->request->getUri()->getScheme();\n                if (isset($options['proxy'][$scheme])) {\n                    $host = $easy->request->getUri()->getHost();\n                    if (!isset($options['proxy']['no']) ||\n                        !\\GuzzleHttp\\is_host_in_noproxy($host, $options['proxy']['no'])\n                    ) {\n                        $conf[CURLOPT_PROXY] = $options['proxy'][$scheme];\n                    }\n                }\n            }\n        }\n\n        if (isset($options['cert'])) {\n            $cert = $options['cert'];\n            if (is_array($cert)) {\n                $conf[CURLOPT_SSLCERTPASSWD] = $cert[1];\n                $cert = $cert[0];\n            }\n            if (!file_exists($cert)) {\n                throw new \\InvalidArgumentException(\n                    \"SSL certificate not found: {$cert}\"\n                );\n            }\n            $conf[CURLOPT_SSLCERT] = $cert;\n        }\n\n        if (isset($options['ssl_key'])) {\n            if (is_array($options['ssl_key'])) {\n                if (count($options['ssl_key']) === 2) {\n                    list($sslKey, $conf[CURLOPT_SSLKEYPASSWD]) = $options['ssl_key'];\n                } else {\n                    list($sslKey) = $options['ssl_key'];\n                }\n            }\n\n            $sslKey = isset($sslKey) ? $sslKey: $options['ssl_key'];\n\n            if (!file_exists($sslKey)) {\n                throw new \\InvalidArgumentException(\n                    \"SSL private key not found: {$sslKey}\"\n                );\n            }\n            $conf[CURLOPT_SSLKEY] = $sslKey;\n        }\n\n        if (isset($options['progress'])) {\n            $progress = $options['progress'];\n            if (!is_callable($progress)) {\n                throw new \\InvalidArgumentException(\n                    'progress client option must be callable'\n                );\n            }\n            $conf[CURLOPT_NOPROGRESS] = false;\n            $conf[CURLOPT_PROGRESSFUNCTION] = function () use ($progress) {\n                $args = func_get_args();\n                // PHP 5.5 pushed the handle onto the start of the args\n                if (is_resource($args[0])) {\n                    array_shift($args);\n                }\n                call_user_func_array($progress, $args);\n            };\n        }\n\n        if (!empty($options['debug'])) {\n            $conf[CURLOPT_STDERR] = \\GuzzleHttp\\debug_resource($options['debug']);\n            $conf[CURLOPT_VERBOSE] = true;\n        }\n    }\n\n    /**\n     * This function ensures that a response was set on a transaction. If one\n     * was not set, then the request is retried if possible. This error\n     * typically means you are sending a payload, curl encountered a\n     * \"Connection died, retrying a fresh connect\" error, tried to rewind the\n     * stream, and then encountered a \"necessary data rewind wasn't possible\"\n     * error, causing the request to be sent through curl_multi_info_read()\n     * without an error status.\n     */\n    private static function retryFailedRewind(\n        callable $handler,\n        EasyHandle $easy,\n        array $ctx\n    ) {\n        try {\n            // Only rewind if the body has been read from.\n            $body = $easy->request->getBody();\n            if ($body->tell() > 0) {\n                $body->rewind();\n            }\n        } catch (\\RuntimeException $e) {\n            $ctx['error'] = 'The connection unexpectedly failed without '\n                . 'providing an error. The request would have been retried, '\n                . 'but attempting to rewind the request body failed. '\n                . 'Exception: ' . $e;\n            return self::createRejection($easy, $ctx);\n        }\n\n        // Retry no more than 3 times before giving up.\n        if (!isset($easy->options['_curl_retries'])) {\n            $easy->options['_curl_retries'] = 1;\n        } elseif ($easy->options['_curl_retries'] == 2) {\n            $ctx['error'] = 'The cURL request was retried 3 times '\n                . 'and did not succeed. The most likely reason for the failure '\n                . 'is that cURL was unable to rewind the body of the request '\n                . 'and subsequent retries resulted in the same error. Turn on '\n                . 'the debug option to see what went wrong. See '\n                . 'https://bugs.php.net/bug.php?id=47204 for more information.';\n            return self::createRejection($easy, $ctx);\n        } else {\n            $easy->options['_curl_retries']++;\n        }\n\n        return $handler($easy->request, $easy->options);\n    }\n\n    private function createHeaderFn(EasyHandle $easy)\n    {\n        if (isset($easy->options['on_headers'])) {\n            $onHeaders = $easy->options['on_headers'];\n\n            if (!is_callable($onHeaders)) {\n                throw new \\InvalidArgumentException('on_headers must be callable');\n            }\n        } else {\n            $onHeaders = null;\n        }\n\n        return function ($ch, $h) use (\n            $onHeaders,\n            $easy,\n            &$startingResponse\n        ) {\n            $value = trim($h);\n            if ($value === '') {\n                $startingResponse = true;\n                $easy->createResponse();\n                if ($onHeaders !== null) {\n                    try {\n                        $onHeaders($easy->response);\n                    } catch (\\Exception $e) {\n                        // Associate the exception with the handle and trigger\n                        // a curl header write error by returning 0.\n                        $easy->onHeadersException = $e;\n                        return -1;\n                    }\n                }\n            } elseif ($startingResponse) {\n                $startingResponse = false;\n                $easy->headers = [$value];\n            } else {\n                $easy->headers[] = $value;\n            }\n            return strlen($h);\n        };\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/guzzle/src/Handler/CurlFactoryInterface.php",
    "content": "<?php\nnamespace GuzzleHttp\\Handler;\n\nuse Psr\\Http\\Message\\RequestInterface;\n\ninterface CurlFactoryInterface\n{\n    /**\n     * Creates a cURL handle resource.\n     *\n     * @param RequestInterface $request Request\n     * @param array            $options Transfer options\n     *\n     * @return EasyHandle\n     * @throws \\RuntimeException when an option cannot be applied\n     */\n    public function create(RequestInterface $request, array $options);\n\n    /**\n     * Release an easy handle, allowing it to be reused or closed.\n     *\n     * This function must call unset on the easy handle's \"handle\" property.\n     *\n     * @param EasyHandle $easy\n     */\n    public function release(EasyHandle $easy);\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/guzzle/src/Handler/CurlHandler.php",
    "content": "<?php\nnamespace GuzzleHttp\\Handler;\n\nuse GuzzleHttp\\Psr7;\nuse Psr\\Http\\Message\\RequestInterface;\n\n/**\n * HTTP handler that uses cURL easy handles as a transport layer.\n *\n * When using the CurlHandler, custom curl options can be specified as an\n * associative array of curl option constants mapping to values in the\n * **curl** key of the \"client\" key of the request.\n */\nclass CurlHandler\n{\n    /** @var CurlFactoryInterface */\n    private $factory;\n\n    /**\n     * Accepts an associative array of options:\n     *\n     * - factory: Optional curl factory used to create cURL handles.\n     *\n     * @param array $options Array of options to use with the handler\n     */\n    public function __construct(array $options = [])\n    {\n        $this->factory = isset($options['handle_factory'])\n            ? $options['handle_factory']\n            : new CurlFactory(3);\n    }\n\n    public function __invoke(RequestInterface $request, array $options)\n    {\n        if (isset($options['delay'])) {\n            usleep($options['delay'] * 1000);\n        }\n\n        $easy = $this->factory->create($request, $options);\n        curl_exec($easy->handle);\n        $easy->errno = curl_errno($easy->handle);\n\n        return CurlFactory::finish($this, $easy, $this->factory);\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php",
    "content": "<?php\nnamespace GuzzleHttp\\Handler;\n\nuse GuzzleHttp\\Promise as P;\nuse GuzzleHttp\\Promise\\Promise;\nuse GuzzleHttp\\Utils;\nuse Psr\\Http\\Message\\RequestInterface;\n\n/**\n * Returns an asynchronous response using curl_multi_* functions.\n *\n * When using the CurlMultiHandler, custom curl options can be specified as an\n * associative array of curl option constants mapping to values in the\n * **curl** key of the provided request options.\n *\n * @property resource $_mh Internal use only. Lazy loaded multi-handle.\n */\nclass CurlMultiHandler\n{\n    /** @var CurlFactoryInterface */\n    private $factory;\n    private $selectTimeout;\n    private $active;\n    private $handles = [];\n    private $delays = [];\n    private $options = [];\n\n    /**\n     * This handler accepts the following options:\n     *\n     * - handle_factory: An optional factory  used to create curl handles\n     * - select_timeout: Optional timeout (in seconds) to block before timing\n     *   out while selecting curl handles. Defaults to 1 second.\n     * - options: An associative array of CURLMOPT_* options and\n     *   corresponding values for curl_multi_setopt()\n     *\n     * @param array $options\n     */\n    public function __construct(array $options = [])\n    {\n        $this->factory = isset($options['handle_factory'])\n            ? $options['handle_factory'] : new CurlFactory(50);\n\n        if (isset($options['select_timeout'])) {\n            $this->selectTimeout = $options['select_timeout'];\n        } elseif ($selectTimeout = getenv('GUZZLE_CURL_SELECT_TIMEOUT')) {\n            $this->selectTimeout = $selectTimeout;\n        } else {\n            $this->selectTimeout = 1;\n        }\n\n        $this->options = isset($options['options']) ? $options['options'] : [];\n    }\n\n    public function __get($name)\n    {\n        if ($name === '_mh') {\n            $this->_mh = curl_multi_init();\n\n            foreach ($this->options as $option => $value) {\n                // A warning is raised in case of a wrong option.\n                curl_multi_setopt($this->_mh, $option, $value);\n            }\n\n            // Further calls to _mh will return the value directly, without entering the\n            // __get() method at all.\n            return $this->_mh;\n        }\n\n        throw new \\BadMethodCallException();\n    }\n\n    public function __destruct()\n    {\n        if (isset($this->_mh)) {\n            curl_multi_close($this->_mh);\n            unset($this->_mh);\n        }\n    }\n\n    public function __invoke(RequestInterface $request, array $options)\n    {\n        $easy = $this->factory->create($request, $options);\n        $id = (int) $easy->handle;\n\n        $promise = new Promise(\n            [$this, 'execute'],\n            function () use ($id) {\n                return $this->cancel($id);\n            }\n        );\n\n        $this->addRequest(['easy' => $easy, 'deferred' => $promise]);\n\n        return $promise;\n    }\n\n    /**\n     * Ticks the curl event loop.\n     */\n    public function tick()\n    {\n        // Add any delayed handles if needed.\n        if ($this->delays) {\n            $currentTime = Utils::currentTime();\n            foreach ($this->delays as $id => $delay) {\n                if ($currentTime >= $delay) {\n                    unset($this->delays[$id]);\n                    curl_multi_add_handle(\n                        $this->_mh,\n                        $this->handles[$id]['easy']->handle\n                    );\n                }\n            }\n        }\n\n        // Step through the task queue which may add additional requests.\n        P\\queue()->run();\n\n        if ($this->active &&\n            curl_multi_select($this->_mh, $this->selectTimeout) === -1\n        ) {\n            // Perform a usleep if a select returns -1.\n            // See: https://bugs.php.net/bug.php?id=61141\n            usleep(250);\n        }\n\n        while (curl_multi_exec($this->_mh, $this->active) === CURLM_CALL_MULTI_PERFORM);\n\n        $this->processMessages();\n    }\n\n    /**\n     * Runs until all outstanding connections have completed.\n     */\n    public function execute()\n    {\n        $queue = P\\queue();\n\n        while ($this->handles || !$queue->isEmpty()) {\n            // If there are no transfers, then sleep for the next delay\n            if (!$this->active && $this->delays) {\n                usleep($this->timeToNext());\n            }\n            $this->tick();\n        }\n    }\n\n    private function addRequest(array $entry)\n    {\n        $easy = $entry['easy'];\n        $id = (int) $easy->handle;\n        $this->handles[$id] = $entry;\n        if (empty($easy->options['delay'])) {\n            curl_multi_add_handle($this->_mh, $easy->handle);\n        } else {\n            $this->delays[$id] = Utils::currentTime() + ($easy->options['delay'] / 1000);\n        }\n    }\n\n    /**\n     * Cancels a handle from sending and removes references to it.\n     *\n     * @param int $id Handle ID to cancel and remove.\n     *\n     * @return bool True on success, false on failure.\n     */\n    private function cancel($id)\n    {\n        // Cannot cancel if it has been processed.\n        if (!isset($this->handles[$id])) {\n            return false;\n        }\n\n        $handle = $this->handles[$id]['easy']->handle;\n        unset($this->delays[$id], $this->handles[$id]);\n        curl_multi_remove_handle($this->_mh, $handle);\n        curl_close($handle);\n\n        return true;\n    }\n\n    private function processMessages()\n    {\n        while ($done = curl_multi_info_read($this->_mh)) {\n            $id = (int) $done['handle'];\n            curl_multi_remove_handle($this->_mh, $done['handle']);\n\n            if (!isset($this->handles[$id])) {\n                // Probably was cancelled.\n                continue;\n            }\n\n            $entry = $this->handles[$id];\n            unset($this->handles[$id], $this->delays[$id]);\n            $entry['easy']->errno = $done['result'];\n            $entry['deferred']->resolve(\n                CurlFactory::finish(\n                    $this,\n                    $entry['easy'],\n                    $this->factory\n                )\n            );\n        }\n    }\n\n    private function timeToNext()\n    {\n        $currentTime = Utils::currentTime();\n        $nextTime = PHP_INT_MAX;\n        foreach ($this->delays as $time) {\n            if ($time < $nextTime) {\n                $nextTime = $time;\n            }\n        }\n\n        return max(0, $nextTime - $currentTime) * 1000000;\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/guzzle/src/Handler/EasyHandle.php",
    "content": "<?php\nnamespace GuzzleHttp\\Handler;\n\nuse GuzzleHttp\\Psr7\\Response;\nuse Psr\\Http\\Message\\RequestInterface;\nuse Psr\\Http\\Message\\ResponseInterface;\nuse Psr\\Http\\Message\\StreamInterface;\n\n/**\n * Represents a cURL easy handle and the data it populates.\n *\n * @internal\n */\nfinal class EasyHandle\n{\n    /** @var resource cURL resource */\n    public $handle;\n\n    /** @var StreamInterface Where data is being written */\n    public $sink;\n\n    /** @var array Received HTTP headers so far */\n    public $headers = [];\n\n    /** @var ResponseInterface Received response (if any) */\n    public $response;\n\n    /** @var RequestInterface Request being sent */\n    public $request;\n\n    /** @var array Request options */\n    public $options = [];\n\n    /** @var int cURL error number (if any) */\n    public $errno = 0;\n\n    /** @var \\Exception Exception during on_headers (if any) */\n    public $onHeadersException;\n\n    /**\n     * Attach a response to the easy handle based on the received headers.\n     *\n     * @throws \\RuntimeException if no headers have been received.\n     */\n    public function createResponse()\n    {\n        if (empty($this->headers)) {\n            throw new \\RuntimeException('No headers have been received');\n        }\n\n        // HTTP-version SP status-code SP reason-phrase\n        $startLine = explode(' ', array_shift($this->headers), 3);\n        $headers = \\GuzzleHttp\\headers_from_lines($this->headers);\n        $normalizedKeys = \\GuzzleHttp\\normalize_header_keys($headers);\n\n        if (!empty($this->options['decode_content'])\n            && isset($normalizedKeys['content-encoding'])\n        ) {\n            $headers['x-encoded-content-encoding']\n                = $headers[$normalizedKeys['content-encoding']];\n            unset($headers[$normalizedKeys['content-encoding']]);\n            if (isset($normalizedKeys['content-length'])) {\n                $headers['x-encoded-content-length']\n                    = $headers[$normalizedKeys['content-length']];\n\n                $bodyLength = (int) $this->sink->getSize();\n                if ($bodyLength) {\n                    $headers[$normalizedKeys['content-length']] = $bodyLength;\n                } else {\n                    unset($headers[$normalizedKeys['content-length']]);\n                }\n            }\n        }\n\n        // Attach a response to the easy handle with the parsed headers.\n        $this->response = new Response(\n            $startLine[1],\n            $headers,\n            $this->sink,\n            substr($startLine[0], 5),\n            isset($startLine[2]) ? (string) $startLine[2] : null\n        );\n    }\n\n    public function __get($name)\n    {\n        $msg = $name === 'handle'\n            ? 'The EasyHandle has been released'\n            : 'Invalid property: ' . $name;\n        throw new \\BadMethodCallException($msg);\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/guzzle/src/Handler/MockHandler.php",
    "content": "<?php\nnamespace GuzzleHttp\\Handler;\n\nuse GuzzleHttp\\Exception\\RequestException;\nuse GuzzleHttp\\HandlerStack;\nuse GuzzleHttp\\Promise\\PromiseInterface;\nuse GuzzleHttp\\Promise\\RejectedPromise;\nuse GuzzleHttp\\TransferStats;\nuse Psr\\Http\\Message\\RequestInterface;\nuse Psr\\Http\\Message\\ResponseInterface;\n\n/**\n * Handler that returns responses or throw exceptions from a queue.\n */\nclass MockHandler implements \\Countable\n{\n    private $queue = [];\n    private $lastRequest;\n    private $lastOptions;\n    private $onFulfilled;\n    private $onRejected;\n\n    /**\n     * Creates a new MockHandler that uses the default handler stack list of\n     * middlewares.\n     *\n     * @param array $queue Array of responses, callables, or exceptions.\n     * @param callable $onFulfilled Callback to invoke when the return value is fulfilled.\n     * @param callable $onRejected  Callback to invoke when the return value is rejected.\n     *\n     * @return HandlerStack\n     */\n    public static function createWithMiddleware(\n        array $queue = null,\n        callable $onFulfilled = null,\n        callable $onRejected = null\n    ) {\n        return HandlerStack::create(new self($queue, $onFulfilled, $onRejected));\n    }\n\n    /**\n     * The passed in value must be an array of\n     * {@see Psr7\\Http\\Message\\ResponseInterface} objects, Exceptions,\n     * callables, or Promises.\n     *\n     * @param array $queue\n     * @param callable $onFulfilled Callback to invoke when the return value is fulfilled.\n     * @param callable $onRejected  Callback to invoke when the return value is rejected.\n     */\n    public function __construct(\n        array $queue = null,\n        callable $onFulfilled = null,\n        callable $onRejected = null\n    ) {\n        $this->onFulfilled = $onFulfilled;\n        $this->onRejected = $onRejected;\n\n        if ($queue) {\n            call_user_func_array([$this, 'append'], $queue);\n        }\n    }\n\n    public function __invoke(RequestInterface $request, array $options)\n    {\n        if (!$this->queue) {\n            throw new \\OutOfBoundsException('Mock queue is empty');\n        }\n\n        if (isset($options['delay']) && is_numeric($options['delay'])) {\n            usleep($options['delay'] * 1000);\n        }\n\n        $this->lastRequest = $request;\n        $this->lastOptions = $options;\n        $response = array_shift($this->queue);\n\n        if (isset($options['on_headers'])) {\n            if (!is_callable($options['on_headers'])) {\n                throw new \\InvalidArgumentException('on_headers must be callable');\n            }\n            try {\n                $options['on_headers']($response);\n            } catch (\\Exception $e) {\n                $msg = 'An error was encountered during the on_headers event';\n                $response = new RequestException($msg, $request, $response, $e);\n            }\n        }\n\n        if (is_callable($response)) {\n            $response = call_user_func($response, $request, $options);\n        }\n\n        $response = $response instanceof \\Exception\n            ? \\GuzzleHttp\\Promise\\rejection_for($response)\n            : \\GuzzleHttp\\Promise\\promise_for($response);\n\n        return $response->then(\n            function ($value) use ($request, $options) {\n                $this->invokeStats($request, $options, $value);\n                if ($this->onFulfilled) {\n                    call_user_func($this->onFulfilled, $value);\n                }\n                if (isset($options['sink'])) {\n                    $contents = (string) $value->getBody();\n                    $sink = $options['sink'];\n\n                    if (is_resource($sink)) {\n                        fwrite($sink, $contents);\n                    } elseif (is_string($sink)) {\n                        file_put_contents($sink, $contents);\n                    } elseif ($sink instanceof \\Psr\\Http\\Message\\StreamInterface) {\n                        $sink->write($contents);\n                    }\n                }\n\n                return $value;\n            },\n            function ($reason) use ($request, $options) {\n                $this->invokeStats($request, $options, null, $reason);\n                if ($this->onRejected) {\n                    call_user_func($this->onRejected, $reason);\n                }\n                return \\GuzzleHttp\\Promise\\rejection_for($reason);\n            }\n        );\n    }\n\n    /**\n     * Adds one or more variadic requests, exceptions, callables, or promises\n     * to the queue.\n     */\n    public function append()\n    {\n        foreach (func_get_args() as $value) {\n            if ($value instanceof ResponseInterface\n                || $value instanceof \\Exception\n                || $value instanceof PromiseInterface\n                || is_callable($value)\n            ) {\n                $this->queue[] = $value;\n            } else {\n                throw new \\InvalidArgumentException('Expected a response or '\n                    . 'exception. Found ' . \\GuzzleHttp\\describe_type($value));\n            }\n        }\n    }\n\n    /**\n     * Get the last received request.\n     *\n     * @return RequestInterface\n     */\n    public function getLastRequest()\n    {\n        return $this->lastRequest;\n    }\n\n    /**\n     * Get the last received request options.\n     *\n     * @return array\n     */\n    public function getLastOptions()\n    {\n        return $this->lastOptions;\n    }\n\n    /**\n     * Returns the number of remaining items in the queue.\n     *\n     * @return int\n     */\n    public function count()\n    {\n        return count($this->queue);\n    }\n\n    public function reset()\n    {\n        $this->queue = [];\n    }\n\n    private function invokeStats(\n        RequestInterface $request,\n        array $options,\n        ResponseInterface $response = null,\n        $reason = null\n    ) {\n        if (isset($options['on_stats'])) {\n            $transferTime = isset($options['transfer_time']) ? $options['transfer_time'] : 0;\n            $stats = new TransferStats($request, $response, $transferTime, $reason);\n            call_user_func($options['on_stats'], $stats);\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/guzzle/src/Handler/Proxy.php",
    "content": "<?php\nnamespace GuzzleHttp\\Handler;\n\nuse GuzzleHttp\\RequestOptions;\nuse Psr\\Http\\Message\\RequestInterface;\n\n/**\n * Provides basic proxies for handlers.\n */\nclass Proxy\n{\n    /**\n     * Sends synchronous requests to a specific handler while sending all other\n     * requests to another handler.\n     *\n     * @param callable $default Handler used for normal responses\n     * @param callable $sync    Handler used for synchronous responses.\n     *\n     * @return callable Returns the composed handler.\n     */\n    public static function wrapSync(\n        callable $default,\n        callable $sync\n    ) {\n        return function (RequestInterface $request, array $options) use ($default, $sync) {\n            return empty($options[RequestOptions::SYNCHRONOUS])\n                ? $default($request, $options)\n                : $sync($request, $options);\n        };\n    }\n\n    /**\n     * Sends streaming requests to a streaming compatible handler while sending\n     * all other requests to a default handler.\n     *\n     * This, for example, could be useful for taking advantage of the\n     * performance benefits of curl while still supporting true streaming\n     * through the StreamHandler.\n     *\n     * @param callable $default   Handler used for non-streaming responses\n     * @param callable $streaming Handler used for streaming responses\n     *\n     * @return callable Returns the composed handler.\n     */\n    public static function wrapStreaming(\n        callable $default,\n        callable $streaming\n    ) {\n        return function (RequestInterface $request, array $options) use ($default, $streaming) {\n            return empty($options['stream'])\n                ? $default($request, $options)\n                : $streaming($request, $options);\n        };\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/guzzle/src/Handler/StreamHandler.php",
    "content": "<?php\nnamespace GuzzleHttp\\Handler;\n\nuse GuzzleHttp\\Exception\\ConnectException;\nuse GuzzleHttp\\Exception\\RequestException;\nuse GuzzleHttp\\Promise\\FulfilledPromise;\nuse GuzzleHttp\\Promise\\PromiseInterface;\nuse GuzzleHttp\\Psr7;\nuse GuzzleHttp\\TransferStats;\nuse GuzzleHttp\\Utils;\nuse Psr\\Http\\Message\\RequestInterface;\nuse Psr\\Http\\Message\\ResponseInterface;\nuse Psr\\Http\\Message\\StreamInterface;\n\n/**\n * HTTP handler that uses PHP's HTTP stream wrapper.\n */\nclass StreamHandler\n{\n    private $lastHeaders = [];\n\n    /**\n     * Sends an HTTP request.\n     *\n     * @param RequestInterface $request Request to send.\n     * @param array            $options Request transfer options.\n     *\n     * @return PromiseInterface\n     */\n    public function __invoke(RequestInterface $request, array $options)\n    {\n        // Sleep if there is a delay specified.\n        if (isset($options['delay'])) {\n            usleep($options['delay'] * 1000);\n        }\n\n        $startTime = isset($options['on_stats']) ? Utils::currentTime() : null;\n\n        try {\n            // Does not support the expect header.\n            $request = $request->withoutHeader('Expect');\n\n            // Append a content-length header if body size is zero to match\n            // cURL's behavior.\n            if (0 === $request->getBody()->getSize()) {\n                $request = $request->withHeader('Content-Length', '0');\n            }\n\n            return $this->createResponse(\n                $request,\n                $options,\n                $this->createStream($request, $options),\n                $startTime\n            );\n        } catch (\\InvalidArgumentException $e) {\n            throw $e;\n        } catch (\\Exception $e) {\n            // Determine if the error was a networking error.\n            $message = $e->getMessage();\n            // This list can probably get more comprehensive.\n            if (strpos($message, 'getaddrinfo') // DNS lookup failed\n                || strpos($message, 'Connection refused')\n                || strpos($message, \"couldn't connect to host\") // error on HHVM\n                || strpos($message, \"connection attempt failed\")\n            ) {\n                $e = new ConnectException($e->getMessage(), $request, $e);\n            }\n            $e = RequestException::wrapException($request, $e);\n            $this->invokeStats($options, $request, $startTime, null, $e);\n\n            return \\GuzzleHttp\\Promise\\rejection_for($e);\n        }\n    }\n\n    private function invokeStats(\n        array $options,\n        RequestInterface $request,\n        $startTime,\n        ResponseInterface $response = null,\n        $error = null\n    ) {\n        if (isset($options['on_stats'])) {\n            $stats = new TransferStats(\n                $request,\n                $response,\n                Utils::currentTime() - $startTime,\n                $error,\n                []\n            );\n            call_user_func($options['on_stats'], $stats);\n        }\n    }\n\n    private function createResponse(\n        RequestInterface $request,\n        array $options,\n        $stream,\n        $startTime\n    ) {\n        $hdrs = $this->lastHeaders;\n        $this->lastHeaders = [];\n        $parts = explode(' ', array_shift($hdrs), 3);\n        $ver = explode('/', $parts[0])[1];\n        $status = $parts[1];\n        $reason = isset($parts[2]) ? $parts[2] : null;\n        $headers = \\GuzzleHttp\\headers_from_lines($hdrs);\n        list($stream, $headers) = $this->checkDecode($options, $headers, $stream);\n        $stream = Psr7\\stream_for($stream);\n        $sink = $stream;\n\n        if (strcasecmp('HEAD', $request->getMethod())) {\n            $sink = $this->createSink($stream, $options);\n        }\n\n        $response = new Psr7\\Response($status, $headers, $sink, $ver, $reason);\n\n        if (isset($options['on_headers'])) {\n            try {\n                $options['on_headers']($response);\n            } catch (\\Exception $e) {\n                $msg = 'An error was encountered during the on_headers event';\n                $ex = new RequestException($msg, $request, $response, $e);\n                return \\GuzzleHttp\\Promise\\rejection_for($ex);\n            }\n        }\n\n        // Do not drain when the request is a HEAD request because they have\n        // no body.\n        if ($sink !== $stream) {\n            $this->drain(\n                $stream,\n                $sink,\n                $response->getHeaderLine('Content-Length')\n            );\n        }\n\n        $this->invokeStats($options, $request, $startTime, $response, null);\n\n        return new FulfilledPromise($response);\n    }\n\n    private function createSink(StreamInterface $stream, array $options)\n    {\n        if (!empty($options['stream'])) {\n            return $stream;\n        }\n\n        $sink = isset($options['sink'])\n            ? $options['sink']\n            : fopen('php://temp', 'r+');\n\n        return is_string($sink)\n            ? new Psr7\\LazyOpenStream($sink, 'w+')\n            : Psr7\\stream_for($sink);\n    }\n\n    private function checkDecode(array $options, array $headers, $stream)\n    {\n        // Automatically decode responses when instructed.\n        if (!empty($options['decode_content'])) {\n            $normalizedKeys = \\GuzzleHttp\\normalize_header_keys($headers);\n            if (isset($normalizedKeys['content-encoding'])) {\n                $encoding = $headers[$normalizedKeys['content-encoding']];\n                if ($encoding[0] === 'gzip' || $encoding[0] === 'deflate') {\n                    $stream = new Psr7\\InflateStream(\n                        Psr7\\stream_for($stream)\n                    );\n                    $headers['x-encoded-content-encoding']\n                        = $headers[$normalizedKeys['content-encoding']];\n                    // Remove content-encoding header\n                    unset($headers[$normalizedKeys['content-encoding']]);\n                    // Fix content-length header\n                    if (isset($normalizedKeys['content-length'])) {\n                        $headers['x-encoded-content-length']\n                            = $headers[$normalizedKeys['content-length']];\n\n                        $length = (int) $stream->getSize();\n                        if ($length === 0) {\n                            unset($headers[$normalizedKeys['content-length']]);\n                        } else {\n                            $headers[$normalizedKeys['content-length']] = [$length];\n                        }\n                    }\n                }\n            }\n        }\n\n        return [$stream, $headers];\n    }\n\n    /**\n     * Drains the source stream into the \"sink\" client option.\n     *\n     * @param StreamInterface $source\n     * @param StreamInterface $sink\n     * @param string          $contentLength Header specifying the amount of\n     *                                       data to read.\n     *\n     * @return StreamInterface\n     * @throws \\RuntimeException when the sink option is invalid.\n     */\n    private function drain(\n        StreamInterface $source,\n        StreamInterface $sink,\n        $contentLength\n    ) {\n        // If a content-length header is provided, then stop reading once\n        // that number of bytes has been read. This can prevent infinitely\n        // reading from a stream when dealing with servers that do not honor\n        // Connection: Close headers.\n        Psr7\\copy_to_stream(\n            $source,\n            $sink,\n            (strlen($contentLength) > 0 && (int) $contentLength > 0) ? (int) $contentLength : -1\n        );\n\n        $sink->seek(0);\n        $source->close();\n\n        return $sink;\n    }\n\n    /**\n     * Create a resource and check to ensure it was created successfully\n     *\n     * @param callable $callback Callable that returns stream resource\n     *\n     * @return resource\n     * @throws \\RuntimeException on error\n     */\n    private function createResource(callable $callback)\n    {\n        $errors = null;\n        set_error_handler(function ($_, $msg, $file, $line) use (&$errors) {\n            $errors[] = [\n                'message' => $msg,\n                'file'    => $file,\n                'line'    => $line\n            ];\n            return true;\n        });\n\n        $resource = $callback();\n        restore_error_handler();\n\n        if (!$resource) {\n            $message = 'Error creating resource: ';\n            foreach ($errors as $err) {\n                foreach ($err as $key => $value) {\n                    $message .= \"[$key] $value\" . PHP_EOL;\n                }\n            }\n            throw new \\RuntimeException(trim($message));\n        }\n\n        return $resource;\n    }\n\n    private function createStream(RequestInterface $request, array $options)\n    {\n        static $methods;\n        if (!$methods) {\n            $methods = array_flip(get_class_methods(__CLASS__));\n        }\n\n        // HTTP/1.1 streams using the PHP stream wrapper require a\n        // Connection: close header\n        if ($request->getProtocolVersion() == '1.1'\n            && !$request->hasHeader('Connection')\n        ) {\n            $request = $request->withHeader('Connection', 'close');\n        }\n\n        // Ensure SSL is verified by default\n        if (!isset($options['verify'])) {\n            $options['verify'] = true;\n        }\n\n        $params = [];\n        $context = $this->getDefaultContext($request);\n\n        if (isset($options['on_headers']) && !is_callable($options['on_headers'])) {\n            throw new \\InvalidArgumentException('on_headers must be callable');\n        }\n\n        if (!empty($options)) {\n            foreach ($options as $key => $value) {\n                $method = \"add_{$key}\";\n                if (isset($methods[$method])) {\n                    $this->{$method}($request, $context, $value, $params);\n                }\n            }\n        }\n\n        if (isset($options['stream_context'])) {\n            if (!is_array($options['stream_context'])) {\n                throw new \\InvalidArgumentException('stream_context must be an array');\n            }\n            $context = array_replace_recursive(\n                $context,\n                $options['stream_context']\n            );\n        }\n\n        // Microsoft NTLM authentication only supported with curl handler\n        if (isset($options['auth'])\n            && is_array($options['auth'])\n            && isset($options['auth'][2])\n            && 'ntlm' == $options['auth'][2]\n        ) {\n            throw new \\InvalidArgumentException('Microsoft NTLM authentication only supported with curl handler');\n        }\n\n        $uri = $this->resolveHost($request, $options);\n\n        $context = $this->createResource(\n            function () use ($context, $params) {\n                return stream_context_create($context, $params);\n            }\n        );\n\n        return $this->createResource(\n            function () use ($uri, &$http_response_header, $context, $options) {\n                $resource = fopen((string) $uri, 'r', null, $context);\n                $this->lastHeaders = $http_response_header;\n\n                if (isset($options['read_timeout'])) {\n                    $readTimeout = $options['read_timeout'];\n                    $sec = (int) $readTimeout;\n                    $usec = ($readTimeout - $sec) * 100000;\n                    stream_set_timeout($resource, $sec, $usec);\n                }\n\n                return $resource;\n            }\n        );\n    }\n\n    private function resolveHost(RequestInterface $request, array $options)\n    {\n        $uri = $request->getUri();\n\n        if (isset($options['force_ip_resolve']) && !filter_var($uri->getHost(), FILTER_VALIDATE_IP)) {\n            if ('v4' === $options['force_ip_resolve']) {\n                $records = dns_get_record($uri->getHost(), DNS_A);\n                if (!isset($records[0]['ip'])) {\n                    throw new ConnectException(\n                        sprintf(\n                            \"Could not resolve IPv4 address for host '%s'\",\n                            $uri->getHost()\n                        ),\n                        $request\n                    );\n                }\n                $uri = $uri->withHost($records[0]['ip']);\n            } elseif ('v6' === $options['force_ip_resolve']) {\n                $records = dns_get_record($uri->getHost(), DNS_AAAA);\n                if (!isset($records[0]['ipv6'])) {\n                    throw new ConnectException(\n                        sprintf(\n                            \"Could not resolve IPv6 address for host '%s'\",\n                            $uri->getHost()\n                        ),\n                        $request\n                    );\n                }\n                $uri = $uri->withHost('[' . $records[0]['ipv6'] . ']');\n            }\n        }\n\n        return $uri;\n    }\n\n    private function getDefaultContext(RequestInterface $request)\n    {\n        $headers = '';\n        foreach ($request->getHeaders() as $name => $value) {\n            foreach ($value as $val) {\n                $headers .= \"$name: $val\\r\\n\";\n            }\n        }\n\n        $context = [\n            'http' => [\n                'method'           => $request->getMethod(),\n                'header'           => $headers,\n                'protocol_version' => $request->getProtocolVersion(),\n                'ignore_errors'    => true,\n                'follow_location'  => 0,\n            ],\n        ];\n\n        $body = (string) $request->getBody();\n\n        if (!empty($body)) {\n            $context['http']['content'] = $body;\n            // Prevent the HTTP handler from adding a Content-Type header.\n            if (!$request->hasHeader('Content-Type')) {\n                $context['http']['header'] .= \"Content-Type:\\r\\n\";\n            }\n        }\n\n        $context['http']['header'] = rtrim($context['http']['header']);\n\n        return $context;\n    }\n\n    private function add_proxy(RequestInterface $request, &$options, $value, &$params)\n    {\n        if (!is_array($value)) {\n            $options['http']['proxy'] = $value;\n        } else {\n            $scheme = $request->getUri()->getScheme();\n            if (isset($value[$scheme])) {\n                if (!isset($value['no'])\n                    || !\\GuzzleHttp\\is_host_in_noproxy(\n                        $request->getUri()->getHost(),\n                        $value['no']\n                    )\n                ) {\n                    $options['http']['proxy'] = $value[$scheme];\n                }\n            }\n        }\n    }\n\n    private function add_timeout(RequestInterface $request, &$options, $value, &$params)\n    {\n        if ($value > 0) {\n            $options['http']['timeout'] = $value;\n        }\n    }\n\n    private function add_verify(RequestInterface $request, &$options, $value, &$params)\n    {\n        if ($value === true) {\n            // PHP 5.6 or greater will find the system cert by default. When\n            // < 5.6, use the Guzzle bundled cacert.\n            if (PHP_VERSION_ID < 50600) {\n                $options['ssl']['cafile'] = \\GuzzleHttp\\default_ca_bundle();\n            }\n        } elseif (is_string($value)) {\n            $options['ssl']['cafile'] = $value;\n            if (!file_exists($value)) {\n                throw new \\RuntimeException(\"SSL CA bundle not found: $value\");\n            }\n        } elseif ($value === false) {\n            $options['ssl']['verify_peer'] = false;\n            $options['ssl']['verify_peer_name'] = false;\n            return;\n        } else {\n            throw new \\InvalidArgumentException('Invalid verify request option');\n        }\n\n        $options['ssl']['verify_peer'] = true;\n        $options['ssl']['verify_peer_name'] = true;\n        $options['ssl']['allow_self_signed'] = false;\n    }\n\n    private function add_cert(RequestInterface $request, &$options, $value, &$params)\n    {\n        if (is_array($value)) {\n            $options['ssl']['passphrase'] = $value[1];\n            $value = $value[0];\n        }\n\n        if (!file_exists($value)) {\n            throw new \\RuntimeException(\"SSL certificate not found: {$value}\");\n        }\n\n        $options['ssl']['local_cert'] = $value;\n    }\n\n    private function add_progress(RequestInterface $request, &$options, $value, &$params)\n    {\n        $this->addNotification(\n            $params,\n            function ($code, $a, $b, $c, $transferred, $total) use ($value) {\n                if ($code == STREAM_NOTIFY_PROGRESS) {\n                    $value($total, $transferred, null, null);\n                }\n            }\n        );\n    }\n\n    private function add_debug(RequestInterface $request, &$options, $value, &$params)\n    {\n        if ($value === false) {\n            return;\n        }\n\n        static $map = [\n            STREAM_NOTIFY_CONNECT       => 'CONNECT',\n            STREAM_NOTIFY_AUTH_REQUIRED => 'AUTH_REQUIRED',\n            STREAM_NOTIFY_AUTH_RESULT   => 'AUTH_RESULT',\n            STREAM_NOTIFY_MIME_TYPE_IS  => 'MIME_TYPE_IS',\n            STREAM_NOTIFY_FILE_SIZE_IS  => 'FILE_SIZE_IS',\n            STREAM_NOTIFY_REDIRECTED    => 'REDIRECTED',\n            STREAM_NOTIFY_PROGRESS      => 'PROGRESS',\n            STREAM_NOTIFY_FAILURE       => 'FAILURE',\n            STREAM_NOTIFY_COMPLETED     => 'COMPLETED',\n            STREAM_NOTIFY_RESOLVE       => 'RESOLVE',\n        ];\n        static $args = ['severity', 'message', 'message_code',\n            'bytes_transferred', 'bytes_max'];\n\n        $value = \\GuzzleHttp\\debug_resource($value);\n        $ident = $request->getMethod() . ' ' . $request->getUri()->withFragment('');\n        $this->addNotification(\n            $params,\n            function () use ($ident, $value, $map, $args) {\n                $passed = func_get_args();\n                $code = array_shift($passed);\n                fprintf($value, '<%s> [%s] ', $ident, $map[$code]);\n                foreach (array_filter($passed) as $i => $v) {\n                    fwrite($value, $args[$i] . ': \"' . $v . '\" ');\n                }\n                fwrite($value, \"\\n\");\n            }\n        );\n    }\n\n    private function addNotification(array &$params, callable $notify)\n    {\n        // Wrap the existing function if needed.\n        if (!isset($params['notification'])) {\n            $params['notification'] = $notify;\n        } else {\n            $params['notification'] = $this->callArray([\n                $params['notification'],\n                $notify\n            ]);\n        }\n    }\n\n    private function callArray(array $functions)\n    {\n        return function () use ($functions) {\n            $args = func_get_args();\n            foreach ($functions as $fn) {\n                call_user_func_array($fn, $args);\n            }\n        };\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/guzzle/src/HandlerStack.php",
    "content": "<?php\nnamespace GuzzleHttp;\n\nuse GuzzleHttp\\Promise\\PromiseInterface;\nuse Psr\\Http\\Message\\RequestInterface;\nuse Psr\\Http\\Message\\ResponseInterface;\n\n/**\n * Creates a composed Guzzle handler function by stacking middlewares on top of\n * an HTTP handler function.\n */\nclass HandlerStack\n{\n    /** @var callable|null */\n    private $handler;\n\n    /** @var array */\n    private $stack = [];\n\n    /** @var callable|null */\n    private $cached;\n\n    /**\n     * Creates a default handler stack that can be used by clients.\n     *\n     * The returned handler will wrap the provided handler or use the most\n     * appropriate default handler for your system. The returned HandlerStack has\n     * support for cookies, redirects, HTTP error exceptions, and preparing a body\n     * before sending.\n     *\n     * The returned handler stack can be passed to a client in the \"handler\"\n     * option.\n     *\n     * @param callable $handler HTTP handler function to use with the stack. If no\n     *                          handler is provided, the best handler for your\n     *                          system will be utilized.\n     *\n     * @return HandlerStack\n     */\n    public static function create(callable $handler = null)\n    {\n        $stack = new self($handler ?: choose_handler());\n        $stack->push(Middleware::httpErrors(), 'http_errors');\n        $stack->push(Middleware::redirect(), 'allow_redirects');\n        $stack->push(Middleware::cookies(), 'cookies');\n        $stack->push(Middleware::prepareBody(), 'prepare_body');\n\n        return $stack;\n    }\n\n    /**\n     * @param callable $handler Underlying HTTP handler.\n     */\n    public function __construct(callable $handler = null)\n    {\n        $this->handler = $handler;\n    }\n\n    /**\n     * Invokes the handler stack as a composed handler\n     *\n     * @param RequestInterface $request\n     * @param array            $options\n     *\n     * @return ResponseInterface|PromiseInterface\n     */\n    public function __invoke(RequestInterface $request, array $options)\n    {\n        $handler = $this->resolve();\n\n        return $handler($request, $options);\n    }\n\n    /**\n     * Dumps a string representation of the stack.\n     *\n     * @return string\n     */\n    public function __toString()\n    {\n        $depth = 0;\n        $stack = [];\n        if ($this->handler) {\n            $stack[] = \"0) Handler: \" . $this->debugCallable($this->handler);\n        }\n\n        $result = '';\n        foreach (array_reverse($this->stack) as $tuple) {\n            $depth++;\n            $str = \"{$depth}) Name: '{$tuple[1]}', \";\n            $str .= \"Function: \" . $this->debugCallable($tuple[0]);\n            $result = \"> {$str}\\n{$result}\";\n            $stack[] = $str;\n        }\n\n        foreach (array_keys($stack) as $k) {\n            $result .= \"< {$stack[$k]}\\n\";\n        }\n\n        return $result;\n    }\n\n    /**\n     * Set the HTTP handler that actually returns a promise.\n     *\n     * @param callable $handler Accepts a request and array of options and\n     *                          returns a Promise.\n     */\n    public function setHandler(callable $handler)\n    {\n        $this->handler = $handler;\n        $this->cached = null;\n    }\n\n    /**\n     * Returns true if the builder has a handler.\n     *\n     * @return bool\n     */\n    public function hasHandler()\n    {\n        return (bool) $this->handler;\n    }\n\n    /**\n     * Unshift a middleware to the bottom of the stack.\n     *\n     * @param callable $middleware Middleware function\n     * @param string   $name       Name to register for this middleware.\n     */\n    public function unshift(callable $middleware, $name = null)\n    {\n        array_unshift($this->stack, [$middleware, $name]);\n        $this->cached = null;\n    }\n\n    /**\n     * Push a middleware to the top of the stack.\n     *\n     * @param callable $middleware Middleware function\n     * @param string   $name       Name to register for this middleware.\n     */\n    public function push(callable $middleware, $name = '')\n    {\n        $this->stack[] = [$middleware, $name];\n        $this->cached = null;\n    }\n\n    /**\n     * Add a middleware before another middleware by name.\n     *\n     * @param string   $findName   Middleware to find\n     * @param callable $middleware Middleware function\n     * @param string   $withName   Name to register for this middleware.\n     */\n    public function before($findName, callable $middleware, $withName = '')\n    {\n        $this->splice($findName, $withName, $middleware, true);\n    }\n\n    /**\n     * Add a middleware after another middleware by name.\n     *\n     * @param string   $findName   Middleware to find\n     * @param callable $middleware Middleware function\n     * @param string   $withName   Name to register for this middleware.\n     */\n    public function after($findName, callable $middleware, $withName = '')\n    {\n        $this->splice($findName, $withName, $middleware, false);\n    }\n\n    /**\n     * Remove a middleware by instance or name from the stack.\n     *\n     * @param callable|string $remove Middleware to remove by instance or name.\n     */\n    public function remove($remove)\n    {\n        $this->cached = null;\n        $idx = is_callable($remove) ? 0 : 1;\n        $this->stack = array_values(array_filter(\n            $this->stack,\n            function ($tuple) use ($idx, $remove) {\n                return $tuple[$idx] !== $remove;\n            }\n        ));\n    }\n\n    /**\n     * Compose the middleware and handler into a single callable function.\n     *\n     * @return callable\n     */\n    public function resolve()\n    {\n        if (!$this->cached) {\n            if (!($prev = $this->handler)) {\n                throw new \\LogicException('No handler has been specified');\n            }\n\n            foreach (array_reverse($this->stack) as $fn) {\n                $prev = $fn[0]($prev);\n            }\n\n            $this->cached = $prev;\n        }\n\n        return $this->cached;\n    }\n\n    /**\n     * @param string $name\n     * @return int\n     */\n    private function findByName($name)\n    {\n        foreach ($this->stack as $k => $v) {\n            if ($v[1] === $name) {\n                return $k;\n            }\n        }\n\n        throw new \\InvalidArgumentException(\"Middleware not found: $name\");\n    }\n\n    /**\n     * Splices a function into the middleware list at a specific position.\n     *\n     * @param string   $findName\n     * @param string   $withName\n     * @param callable $middleware\n     * @param bool     $before\n     */\n    private function splice($findName, $withName, callable $middleware, $before)\n    {\n        $this->cached = null;\n        $idx = $this->findByName($findName);\n        $tuple = [$middleware, $withName];\n\n        if ($before) {\n            if ($idx === 0) {\n                array_unshift($this->stack, $tuple);\n            } else {\n                $replacement = [$tuple, $this->stack[$idx]];\n                array_splice($this->stack, $idx, 1, $replacement);\n            }\n        } elseif ($idx === count($this->stack) - 1) {\n            $this->stack[] = $tuple;\n        } else {\n            $replacement = [$this->stack[$idx], $tuple];\n            array_splice($this->stack, $idx, 1, $replacement);\n        }\n    }\n\n    /**\n     * Provides a debug string for a given callable.\n     *\n     * @param array|callable $fn Function to write as a string.\n     *\n     * @return string\n     */\n    private function debugCallable($fn)\n    {\n        if (is_string($fn)) {\n            return \"callable({$fn})\";\n        }\n\n        if (is_array($fn)) {\n            return is_string($fn[0])\n                ? \"callable({$fn[0]}::{$fn[1]})\"\n                : \"callable(['\" . get_class($fn[0]) . \"', '{$fn[1]}'])\";\n        }\n\n        return 'callable(' . spl_object_hash($fn) . ')';\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/guzzle/src/MessageFormatter.php",
    "content": "<?php\nnamespace GuzzleHttp;\n\nuse Psr\\Http\\Message\\MessageInterface;\nuse Psr\\Http\\Message\\RequestInterface;\nuse Psr\\Http\\Message\\ResponseInterface;\n\n/**\n * Formats log messages using variable substitutions for requests, responses,\n * and other transactional data.\n *\n * The following variable substitutions are supported:\n *\n * - {request}:        Full HTTP request message\n * - {response}:       Full HTTP response message\n * - {ts}:             ISO 8601 date in GMT\n * - {date_iso_8601}   ISO 8601 date in GMT\n * - {date_common_log} Apache common log date using the configured timezone.\n * - {host}:           Host of the request\n * - {method}:         Method of the request\n * - {uri}:            URI of the request\n * - {version}:        Protocol version\n * - {target}:         Request target of the request (path + query + fragment)\n * - {hostname}:       Hostname of the machine that sent the request\n * - {code}:           Status code of the response (if available)\n * - {phrase}:         Reason phrase of the response  (if available)\n * - {error}:          Any error messages (if available)\n * - {req_header_*}:   Replace `*` with the lowercased name of a request header to add to the message\n * - {res_header_*}:   Replace `*` with the lowercased name of a response header to add to the message\n * - {req_headers}:    Request headers\n * - {res_headers}:    Response headers\n * - {req_body}:       Request body\n * - {res_body}:       Response body\n */\nclass MessageFormatter\n{\n    /**\n     * Apache Common Log Format.\n     * @link http://httpd.apache.org/docs/2.4/logs.html#common\n     * @var string\n     */\n    const CLF = \"{hostname} {req_header_User-Agent} - [{date_common_log}] \\\"{method} {target} HTTP/{version}\\\" {code} {res_header_Content-Length}\";\n    const DEBUG = \">>>>>>>>\\n{request}\\n<<<<<<<<\\n{response}\\n--------\\n{error}\";\n    const SHORT = '[{ts}] \"{method} {target} HTTP/{version}\" {code}';\n\n    /** @var string Template used to format log messages */\n    private $template;\n\n    /**\n     * @param string $template Log message template\n     */\n    public function __construct($template = self::CLF)\n    {\n        $this->template = $template ?: self::CLF;\n    }\n\n    /**\n     * Returns a formatted message string.\n     *\n     * @param RequestInterface  $request  Request that was sent\n     * @param ResponseInterface $response Response that was received\n     * @param \\Exception        $error    Exception that was received\n     *\n     * @return string\n     */\n    public function format(\n        RequestInterface $request,\n        ResponseInterface $response = null,\n        \\Exception $error = null\n    ) {\n        $cache = [];\n\n        return preg_replace_callback(\n            '/{\\s*([A-Za-z_\\-\\.0-9]+)\\s*}/',\n            function (array $matches) use ($request, $response, $error, &$cache) {\n                if (isset($cache[$matches[1]])) {\n                    return $cache[$matches[1]];\n                }\n\n                $result = '';\n                switch ($matches[1]) {\n                    case 'request':\n                        $result = Psr7\\str($request);\n                        break;\n                    case 'response':\n                        $result = $response ? Psr7\\str($response) : '';\n                        break;\n                    case 'req_headers':\n                        $result = trim($request->getMethod()\n                                . ' ' . $request->getRequestTarget())\n                            . ' HTTP/' . $request->getProtocolVersion() . \"\\r\\n\"\n                            . $this->headers($request);\n                        break;\n                    case 'res_headers':\n                        $result = $response ?\n                            sprintf(\n                                'HTTP/%s %d %s',\n                                $response->getProtocolVersion(),\n                                $response->getStatusCode(),\n                                $response->getReasonPhrase()\n                            ) . \"\\r\\n\" . $this->headers($response)\n                            : 'NULL';\n                        break;\n                    case 'req_body':\n                        $result = $request->getBody();\n                        break;\n                    case 'res_body':\n                        $result = $response ? $response->getBody() : 'NULL';\n                        break;\n                    case 'ts':\n                    case 'date_iso_8601':\n                        $result = gmdate('c');\n                        break;\n                    case 'date_common_log':\n                        $result = date('d/M/Y:H:i:s O');\n                        break;\n                    case 'method':\n                        $result = $request->getMethod();\n                        break;\n                    case 'version':\n                        $result = $request->getProtocolVersion();\n                        break;\n                    case 'uri':\n                    case 'url':\n                        $result = $request->getUri();\n                        break;\n                    case 'target':\n                        $result = $request->getRequestTarget();\n                        break;\n                    case 'req_version':\n                        $result = $request->getProtocolVersion();\n                        break;\n                    case 'res_version':\n                        $result = $response\n                            ? $response->getProtocolVersion()\n                            : 'NULL';\n                        break;\n                    case 'host':\n                        $result = $request->getHeaderLine('Host');\n                        break;\n                    case 'hostname':\n                        $result = gethostname();\n                        break;\n                    case 'code':\n                        $result = $response ? $response->getStatusCode() : 'NULL';\n                        break;\n                    case 'phrase':\n                        $result = $response ? $response->getReasonPhrase() : 'NULL';\n                        break;\n                    case 'error':\n                        $result = $error ? $error->getMessage() : 'NULL';\n                        break;\n                    default:\n                        // handle prefixed dynamic headers\n                        if (strpos($matches[1], 'req_header_') === 0) {\n                            $result = $request->getHeaderLine(substr($matches[1], 11));\n                        } elseif (strpos($matches[1], 'res_header_') === 0) {\n                            $result = $response\n                                ? $response->getHeaderLine(substr($matches[1], 11))\n                                : 'NULL';\n                        }\n                }\n\n                $cache[$matches[1]] = $result;\n                return $result;\n            },\n            $this->template\n        );\n    }\n\n    /**\n     * Get headers from message as string\n     *\n     * @return string\n     */\n    private function headers(MessageInterface $message)\n    {\n        $result = '';\n        foreach ($message->getHeaders() as $name => $values) {\n            $result .= $name . ': ' . implode(', ', $values) . \"\\r\\n\";\n        }\n\n        return trim($result);\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/guzzle/src/Middleware.php",
    "content": "<?php\nnamespace GuzzleHttp;\n\nuse GuzzleHttp\\Cookie\\CookieJarInterface;\nuse GuzzleHttp\\Exception\\RequestException;\nuse GuzzleHttp\\Promise\\RejectedPromise;\nuse GuzzleHttp\\Psr7;\nuse Psr\\Http\\Message\\ResponseInterface;\nuse Psr\\Log\\LoggerInterface;\n\n/**\n * Functions used to create and wrap handlers with handler middleware.\n */\nfinal class Middleware\n{\n    /**\n     * Middleware that adds cookies to requests.\n     *\n     * The options array must be set to a CookieJarInterface in order to use\n     * cookies. This is typically handled for you by a client.\n     *\n     * @return callable Returns a function that accepts the next handler.\n     */\n    public static function cookies()\n    {\n        return function (callable $handler) {\n            return function ($request, array $options) use ($handler) {\n                if (empty($options['cookies'])) {\n                    return $handler($request, $options);\n                } elseif (!($options['cookies'] instanceof CookieJarInterface)) {\n                    throw new \\InvalidArgumentException('cookies must be an instance of GuzzleHttp\\Cookie\\CookieJarInterface');\n                }\n                $cookieJar = $options['cookies'];\n                $request = $cookieJar->withCookieHeader($request);\n                return $handler($request, $options)\n                    ->then(\n                        function ($response) use ($cookieJar, $request) {\n                            $cookieJar->extractCookies($request, $response);\n                            return $response;\n                        }\n                    );\n            };\n        };\n    }\n\n    /**\n     * Middleware that throws exceptions for 4xx or 5xx responses when the\n     * \"http_error\" request option is set to true.\n     *\n     * @return callable Returns a function that accepts the next handler.\n     */\n    public static function httpErrors()\n    {\n        return function (callable $handler) {\n            return function ($request, array $options) use ($handler) {\n                if (empty($options['http_errors'])) {\n                    return $handler($request, $options);\n                }\n                return $handler($request, $options)->then(\n                    function (ResponseInterface $response) use ($request) {\n                        $code = $response->getStatusCode();\n                        if ($code < 400) {\n                            return $response;\n                        }\n                        throw RequestException::create($request, $response);\n                    }\n                );\n            };\n        };\n    }\n\n    /**\n     * Middleware that pushes history data to an ArrayAccess container.\n     *\n     * @param array|\\ArrayAccess $container Container to hold the history (by reference).\n     *\n     * @return callable Returns a function that accepts the next handler.\n     * @throws \\InvalidArgumentException if container is not an array or ArrayAccess.\n     */\n    public static function history(&$container)\n    {\n        if (!is_array($container) && !$container instanceof \\ArrayAccess) {\n            throw new \\InvalidArgumentException('history container must be an array or object implementing ArrayAccess');\n        }\n\n        return function (callable $handler) use (&$container) {\n            return function ($request, array $options) use ($handler, &$container) {\n                return $handler($request, $options)->then(\n                    function ($value) use ($request, &$container, $options) {\n                        $container[] = [\n                            'request'  => $request,\n                            'response' => $value,\n                            'error'    => null,\n                            'options'  => $options\n                        ];\n                        return $value;\n                    },\n                    function ($reason) use ($request, &$container, $options) {\n                        $container[] = [\n                            'request'  => $request,\n                            'response' => null,\n                            'error'    => $reason,\n                            'options'  => $options\n                        ];\n                        return \\GuzzleHttp\\Promise\\rejection_for($reason);\n                    }\n                );\n            };\n        };\n    }\n\n    /**\n     * Middleware that invokes a callback before and after sending a request.\n     *\n     * The provided listener cannot modify or alter the response. It simply\n     * \"taps\" into the chain to be notified before returning the promise. The\n     * before listener accepts a request and options array, and the after\n     * listener accepts a request, options array, and response promise.\n     *\n     * @param callable $before Function to invoke before forwarding the request.\n     * @param callable $after  Function invoked after forwarding.\n     *\n     * @return callable Returns a function that accepts the next handler.\n     */\n    public static function tap(callable $before = null, callable $after = null)\n    {\n        return function (callable $handler) use ($before, $after) {\n            return function ($request, array $options) use ($handler, $before, $after) {\n                if ($before) {\n                    $before($request, $options);\n                }\n                $response = $handler($request, $options);\n                if ($after) {\n                    $after($request, $options, $response);\n                }\n                return $response;\n            };\n        };\n    }\n\n    /**\n     * Middleware that handles request redirects.\n     *\n     * @return callable Returns a function that accepts the next handler.\n     */\n    public static function redirect()\n    {\n        return function (callable $handler) {\n            return new RedirectMiddleware($handler);\n        };\n    }\n\n    /**\n     * Middleware that retries requests based on the boolean result of\n     * invoking the provided \"decider\" function.\n     *\n     * If no delay function is provided, a simple implementation of exponential\n     * backoff will be utilized.\n     *\n     * @param callable $decider Function that accepts the number of retries,\n     *                          a request, [response], and [exception] and\n     *                          returns true if the request is to be retried.\n     * @param callable $delay   Function that accepts the number of retries and\n     *                          returns the number of milliseconds to delay.\n     *\n     * @return callable Returns a function that accepts the next handler.\n     */\n    public static function retry(callable $decider, callable $delay = null)\n    {\n        return function (callable $handler) use ($decider, $delay) {\n            return new RetryMiddleware($decider, $handler, $delay);\n        };\n    }\n\n    /**\n     * Middleware that logs requests, responses, and errors using a message\n     * formatter.\n     *\n     * @param LoggerInterface  $logger Logs messages.\n     * @param MessageFormatter $formatter Formatter used to create message strings.\n     * @param string           $logLevel Level at which to log requests.\n     *\n     * @return callable Returns a function that accepts the next handler.\n     */\n    public static function log(LoggerInterface $logger, MessageFormatter $formatter, $logLevel = 'info' /* \\Psr\\Log\\LogLevel::INFO */)\n    {\n        return function (callable $handler) use ($logger, $formatter, $logLevel) {\n            return function ($request, array $options) use ($handler, $logger, $formatter, $logLevel) {\n                return $handler($request, $options)->then(\n                    function ($response) use ($logger, $request, $formatter, $logLevel) {\n                        $message = $formatter->format($request, $response);\n                        $logger->log($logLevel, $message);\n                        return $response;\n                    },\n                    function ($reason) use ($logger, $request, $formatter) {\n                        $response = $reason instanceof RequestException\n                            ? $reason->getResponse()\n                            : null;\n                        $message = $formatter->format($request, $response, $reason);\n                        $logger->notice($message);\n                        return \\GuzzleHttp\\Promise\\rejection_for($reason);\n                    }\n                );\n            };\n        };\n    }\n\n    /**\n     * This middleware adds a default content-type if possible, a default\n     * content-length or transfer-encoding header, and the expect header.\n     *\n     * @return callable\n     */\n    public static function prepareBody()\n    {\n        return function (callable $handler) {\n            return new PrepareBodyMiddleware($handler);\n        };\n    }\n\n    /**\n     * Middleware that applies a map function to the request before passing to\n     * the next handler.\n     *\n     * @param callable $fn Function that accepts a RequestInterface and returns\n     *                     a RequestInterface.\n     * @return callable\n     */\n    public static function mapRequest(callable $fn)\n    {\n        return function (callable $handler) use ($fn) {\n            return function ($request, array $options) use ($handler, $fn) {\n                return $handler($fn($request), $options);\n            };\n        };\n    }\n\n    /**\n     * Middleware that applies a map function to the resolved promise's\n     * response.\n     *\n     * @param callable $fn Function that accepts a ResponseInterface and\n     *                     returns a ResponseInterface.\n     * @return callable\n     */\n    public static function mapResponse(callable $fn)\n    {\n        return function (callable $handler) use ($fn) {\n            return function ($request, array $options) use ($handler, $fn) {\n                return $handler($request, $options)->then($fn);\n            };\n        };\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/guzzle/src/Pool.php",
    "content": "<?php\nnamespace GuzzleHttp;\n\nuse GuzzleHttp\\Promise\\EachPromise;\nuse GuzzleHttp\\Promise\\PromiseInterface;\nuse GuzzleHttp\\Promise\\PromisorInterface;\nuse Psr\\Http\\Message\\RequestInterface;\n\n/**\n * Sends an iterator of requests concurrently using a capped pool size.\n *\n * The pool will read from an iterator until it is cancelled or until the\n * iterator is consumed. When a request is yielded, the request is sent after\n * applying the \"request_options\" request options (if provided in the ctor).\n *\n * When a function is yielded by the iterator, the function is provided the\n * \"request_options\" array that should be merged on top of any existing\n * options, and the function MUST then return a wait-able promise.\n */\nclass Pool implements PromisorInterface\n{\n    /** @var EachPromise */\n    private $each;\n\n    /**\n     * @param ClientInterface $client   Client used to send the requests.\n     * @param array|\\Iterator $requests Requests or functions that return\n     *                                  requests to send concurrently.\n     * @param array           $config   Associative array of options\n     *     - concurrency: (int) Maximum number of requests to send concurrently\n     *     - options: Array of request options to apply to each request.\n     *     - fulfilled: (callable) Function to invoke when a request completes.\n     *     - rejected: (callable) Function to invoke when a request is rejected.\n     */\n    public function __construct(\n        ClientInterface $client,\n        $requests,\n        array $config = []\n    ) {\n        // Backwards compatibility.\n        if (isset($config['pool_size'])) {\n            $config['concurrency'] = $config['pool_size'];\n        } elseif (!isset($config['concurrency'])) {\n            $config['concurrency'] = 25;\n        }\n\n        if (isset($config['options'])) {\n            $opts = $config['options'];\n            unset($config['options']);\n        } else {\n            $opts = [];\n        }\n\n        $iterable = \\GuzzleHttp\\Promise\\iter_for($requests);\n        $requests = function () use ($iterable, $client, $opts) {\n            foreach ($iterable as $key => $rfn) {\n                if ($rfn instanceof RequestInterface) {\n                    yield $key => $client->sendAsync($rfn, $opts);\n                } elseif (is_callable($rfn)) {\n                    yield $key => $rfn($opts);\n                } else {\n                    throw new \\InvalidArgumentException('Each value yielded by '\n                        . 'the iterator must be a Psr7\\Http\\Message\\RequestInterface '\n                        . 'or a callable that returns a promise that fulfills '\n                        . 'with a Psr7\\Message\\Http\\ResponseInterface object.');\n                }\n            }\n        };\n\n        $this->each = new EachPromise($requests(), $config);\n    }\n\n    /**\n     * Get promise\n     *\n     * @return PromiseInterface\n     */\n    public function promise()\n    {\n        return $this->each->promise();\n    }\n\n    /**\n     * Sends multiple requests concurrently and returns an array of responses\n     * and exceptions that uses the same ordering as the provided requests.\n     *\n     * IMPORTANT: This method keeps every request and response in memory, and\n     * as such, is NOT recommended when sending a large number or an\n     * indeterminate number of requests concurrently.\n     *\n     * @param ClientInterface $client   Client used to send the requests\n     * @param array|\\Iterator $requests Requests to send concurrently.\n     * @param array           $options  Passes through the options available in\n     *                                  {@see GuzzleHttp\\Pool::__construct}\n     *\n     * @return array Returns an array containing the response or an exception\n     *               in the same order that the requests were sent.\n     * @throws \\InvalidArgumentException if the event format is incorrect.\n     */\n    public static function batch(\n        ClientInterface $client,\n        $requests,\n        array $options = []\n    ) {\n        $res = [];\n        self::cmpCallback($options, 'fulfilled', $res);\n        self::cmpCallback($options, 'rejected', $res);\n        $pool = new static($client, $requests, $options);\n        $pool->promise()->wait();\n        ksort($res);\n\n        return $res;\n    }\n\n    /**\n     * Execute callback(s)\n     *\n     * @return void\n     */\n    private static function cmpCallback(array &$options, $name, array &$results)\n    {\n        if (!isset($options[$name])) {\n            $options[$name] = function ($v, $k) use (&$results) {\n                $results[$k] = $v;\n            };\n        } else {\n            $currentFn = $options[$name];\n            $options[$name] = function ($v, $k) use (&$results, $currentFn) {\n                $currentFn($v, $k);\n                $results[$k] = $v;\n            };\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php",
    "content": "<?php\nnamespace GuzzleHttp;\n\nuse GuzzleHttp\\Promise\\PromiseInterface;\nuse GuzzleHttp\\Psr7;\nuse Psr\\Http\\Message\\RequestInterface;\n\n/**\n * Prepares requests that contain a body, adding the Content-Length,\n * Content-Type, and Expect headers.\n */\nclass PrepareBodyMiddleware\n{\n    /** @var callable  */\n    private $nextHandler;\n\n    /**\n     * @param callable $nextHandler Next handler to invoke.\n     */\n    public function __construct(callable $nextHandler)\n    {\n        $this->nextHandler = $nextHandler;\n    }\n\n    /**\n     * @param RequestInterface $request\n     * @param array            $options\n     *\n     * @return PromiseInterface\n     */\n    public function __invoke(RequestInterface $request, array $options)\n    {\n        $fn = $this->nextHandler;\n\n        // Don't do anything if the request has no body.\n        if ($request->getBody()->getSize() === 0) {\n            return $fn($request, $options);\n        }\n\n        $modify = [];\n\n        // Add a default content-type if possible.\n        if (!$request->hasHeader('Content-Type')) {\n            if ($uri = $request->getBody()->getMetadata('uri')) {\n                if ($type = Psr7\\mimetype_from_filename($uri)) {\n                    $modify['set_headers']['Content-Type'] = $type;\n                }\n            }\n        }\n\n        // Add a default content-length or transfer-encoding header.\n        if (!$request->hasHeader('Content-Length')\n            && !$request->hasHeader('Transfer-Encoding')\n        ) {\n            $size = $request->getBody()->getSize();\n            if ($size !== null) {\n                $modify['set_headers']['Content-Length'] = $size;\n            } else {\n                $modify['set_headers']['Transfer-Encoding'] = 'chunked';\n            }\n        }\n\n        // Add the expect header if needed.\n        $this->addExpectHeader($request, $options, $modify);\n\n        return $fn(Psr7\\modify_request($request, $modify), $options);\n    }\n\n    /**\n     * Add expect header\n     *\n     * @return void\n     */\n    private function addExpectHeader(\n        RequestInterface $request,\n        array $options,\n        array &$modify\n    ) {\n        // Determine if the Expect header should be used\n        if ($request->hasHeader('Expect')) {\n            return;\n        }\n\n        $expect = isset($options['expect']) ? $options['expect'] : null;\n\n        // Return if disabled or if you're not using HTTP/1.1 or HTTP/2.0\n        if ($expect === false || $request->getProtocolVersion() < 1.1) {\n            return;\n        }\n\n        // The expect header is unconditionally enabled\n        if ($expect === true) {\n            $modify['set_headers']['Expect'] = '100-Continue';\n            return;\n        }\n\n        // By default, send the expect header when the payload is > 1mb\n        if ($expect === null) {\n            $expect = 1048576;\n        }\n\n        // Always add if the body cannot be rewound, the size cannot be\n        // determined, or the size is greater than the cutoff threshold\n        $body = $request->getBody();\n        $size = $body->getSize();\n\n        if ($size === null || $size >= (int) $expect || !$body->isSeekable()) {\n            $modify['set_headers']['Expect'] = '100-Continue';\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/guzzle/src/RedirectMiddleware.php",
    "content": "<?php\nnamespace GuzzleHttp;\n\nuse GuzzleHttp\\Exception\\BadResponseException;\nuse GuzzleHttp\\Exception\\TooManyRedirectsException;\nuse GuzzleHttp\\Promise\\PromiseInterface;\nuse GuzzleHttp\\Psr7;\nuse Psr\\Http\\Message\\RequestInterface;\nuse Psr\\Http\\Message\\ResponseInterface;\nuse Psr\\Http\\Message\\UriInterface;\n\n/**\n * Request redirect middleware.\n *\n * Apply this middleware like other middleware using\n * {@see \\GuzzleHttp\\Middleware::redirect()}.\n */\nclass RedirectMiddleware\n{\n    const HISTORY_HEADER = 'X-Guzzle-Redirect-History';\n\n    const STATUS_HISTORY_HEADER = 'X-Guzzle-Redirect-Status-History';\n\n    public static $defaultSettings = [\n        'max'             => 5,\n        'protocols'       => ['http', 'https'],\n        'strict'          => false,\n        'referer'         => false,\n        'track_redirects' => false,\n    ];\n\n    /** @var callable  */\n    private $nextHandler;\n\n    /**\n     * @param callable $nextHandler Next handler to invoke.\n     */\n    public function __construct(callable $nextHandler)\n    {\n        $this->nextHandler = $nextHandler;\n    }\n\n    /**\n     * @param RequestInterface $request\n     * @param array            $options\n     *\n     * @return PromiseInterface\n     */\n    public function __invoke(RequestInterface $request, array $options)\n    {\n        $fn = $this->nextHandler;\n\n        if (empty($options['allow_redirects'])) {\n            return $fn($request, $options);\n        }\n\n        if ($options['allow_redirects'] === true) {\n            $options['allow_redirects'] = self::$defaultSettings;\n        } elseif (!is_array($options['allow_redirects'])) {\n            throw new \\InvalidArgumentException('allow_redirects must be true, false, or array');\n        } else {\n            // Merge the default settings with the provided settings\n            $options['allow_redirects'] += self::$defaultSettings;\n        }\n\n        if (empty($options['allow_redirects']['max'])) {\n            return $fn($request, $options);\n        }\n\n        return $fn($request, $options)\n            ->then(function (ResponseInterface $response) use ($request, $options) {\n                return $this->checkRedirect($request, $options, $response);\n            });\n    }\n\n    /**\n     * @param RequestInterface  $request\n     * @param array             $options\n     * @param ResponseInterface $response\n     *\n     * @return ResponseInterface|PromiseInterface\n     */\n    public function checkRedirect(\n        RequestInterface $request,\n        array $options,\n        ResponseInterface $response\n    ) {\n        if (substr($response->getStatusCode(), 0, 1) != '3'\n            || !$response->hasHeader('Location')\n        ) {\n            return $response;\n        }\n\n        $this->guardMax($request, $options);\n        $nextRequest = $this->modifyRequest($request, $options, $response);\n\n        // If authorization is handled by curl, unset it if URI is cross-origin.\n        if (Psr7\\UriComparator::isCrossOrigin($request->getUri(), $nextRequest->getUri()) && defined('\\CURLOPT_HTTPAUTH')) {\n            unset(\n                $options['curl'][\\CURLOPT_HTTPAUTH],\n                $options['curl'][\\CURLOPT_USERPWD]\n            );\n        }\n\n        if (isset($options['allow_redirects']['on_redirect'])) {\n            call_user_func(\n                $options['allow_redirects']['on_redirect'],\n                $request,\n                $response,\n                $nextRequest->getUri()\n            );\n        }\n\n        /** @var PromiseInterface|ResponseInterface $promise */\n        $promise = $this($nextRequest, $options);\n\n        // Add headers to be able to track history of redirects.\n        if (!empty($options['allow_redirects']['track_redirects'])) {\n            return $this->withTracking(\n                $promise,\n                (string) $nextRequest->getUri(),\n                $response->getStatusCode()\n            );\n        }\n\n        return $promise;\n    }\n\n    /**\n     * Enable tracking on promise.\n     *\n     * @return PromiseInterface\n     */\n    private function withTracking(PromiseInterface $promise, $uri, $statusCode)\n    {\n        return $promise->then(\n            function (ResponseInterface $response) use ($uri, $statusCode) {\n                // Note that we are pushing to the front of the list as this\n                // would be an earlier response than what is currently present\n                // in the history header.\n                $historyHeader = $response->getHeader(self::HISTORY_HEADER);\n                $statusHeader = $response->getHeader(self::STATUS_HISTORY_HEADER);\n                array_unshift($historyHeader, $uri);\n                array_unshift($statusHeader, $statusCode);\n                return $response->withHeader(self::HISTORY_HEADER, $historyHeader)\n                                ->withHeader(self::STATUS_HISTORY_HEADER, $statusHeader);\n            }\n        );\n    }\n\n    /**\n     * Check for too many redirects.\n     *\n     * @return void\n     *\n     * @throws TooManyRedirectsException Too many redirects.\n     */\n    private function guardMax(RequestInterface $request, array &$options)\n    {\n        $current = isset($options['__redirect_count'])\n            ? $options['__redirect_count']\n            : 0;\n        $options['__redirect_count'] = $current + 1;\n        $max = $options['allow_redirects']['max'];\n\n        if ($options['__redirect_count'] > $max) {\n            throw new TooManyRedirectsException(\n                \"Will not follow more than {$max} redirects\",\n                $request\n            );\n        }\n    }\n\n    /**\n     * @param RequestInterface  $request\n     * @param array             $options\n     * @param ResponseInterface $response\n     *\n     * @return RequestInterface\n     */\n    public function modifyRequest(\n        RequestInterface $request,\n        array $options,\n        ResponseInterface $response\n    ) {\n        // Request modifications to apply.\n        $modify = [];\n        $protocols = $options['allow_redirects']['protocols'];\n\n        // Use a GET request if this is an entity enclosing request and we are\n        // not forcing RFC compliance, but rather emulating what all browsers\n        // would do.\n        $statusCode = $response->getStatusCode();\n        if ($statusCode == 303 ||\n            ($statusCode <= 302 && !$options['allow_redirects']['strict'])\n        ) {\n            $modify['method'] = 'GET';\n            $modify['body'] = '';\n        }\n\n        $uri = self::redirectUri($request, $response, $protocols);\n        if (isset($options['idn_conversion']) && ($options['idn_conversion'] !== false)) {\n            $idnOptions = ($options['idn_conversion'] === true) ? IDNA_DEFAULT : $options['idn_conversion'];\n            $uri = Utils::idnUriConvert($uri, $idnOptions);\n        }\n\n        $modify['uri'] = $uri;\n        Psr7\\rewind_body($request);\n\n        // Add the Referer header if it is told to do so and only\n        // add the header if we are not redirecting from https to http.\n        if ($options['allow_redirects']['referer']\n            && $modify['uri']->getScheme() === $request->getUri()->getScheme()\n        ) {\n            $uri = $request->getUri()->withUserInfo('');\n            $modify['set_headers']['Referer'] = (string) $uri;\n        } else {\n            $modify['remove_headers'][] = 'Referer';\n        }\n\n        // Remove Authorization and Cookie headers if URI is cross-origin.\n        if (Psr7\\UriComparator::isCrossOrigin($request->getUri(), $modify['uri'])) {\n            $modify['remove_headers'][] = 'Authorization';\n            $modify['remove_headers'][] = 'Cookie';\n        }\n\n        return Psr7\\modify_request($request, $modify);\n    }\n\n    /**\n     * Set the appropriate URL on the request based on the location header.\n     *\n     * @param RequestInterface  $request\n     * @param ResponseInterface $response\n     * @param array             $protocols\n     *\n     * @return UriInterface\n     */\n    private static function redirectUri(\n        RequestInterface $request,\n        ResponseInterface $response,\n        array $protocols\n    ) {\n        $location = Psr7\\UriResolver::resolve(\n            $request->getUri(),\n            new Psr7\\Uri($response->getHeaderLine('Location'))\n        );\n\n        // Ensure that the redirect URI is allowed based on the protocols.\n        if (!in_array($location->getScheme(), $protocols)) {\n            throw new BadResponseException(\n                sprintf(\n                    'Redirect URI, %s, does not use one of the allowed redirect protocols: %s',\n                    $location,\n                    implode(', ', $protocols)\n                ),\n                $request,\n                $response\n            );\n        }\n\n        return $location;\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/guzzle/src/RequestOptions.php",
    "content": "<?php\nnamespace GuzzleHttp;\n\n/**\n * This class contains a list of built-in Guzzle request options.\n *\n * More documentation for each option can be found at http://guzzlephp.org/.\n *\n * @link http://docs.guzzlephp.org/en/v6/request-options.html\n */\nfinal class RequestOptions\n{\n    /**\n     * allow_redirects: (bool|array) Controls redirect behavior. Pass false\n     * to disable redirects, pass true to enable redirects, pass an\n     * associative to provide custom redirect settings. Defaults to \"false\".\n     * This option only works if your handler has the RedirectMiddleware. When\n     * passing an associative array, you can provide the following key value\n     * pairs:\n     *\n     * - max: (int, default=5) maximum number of allowed redirects.\n     * - strict: (bool, default=false) Set to true to use strict redirects\n     *   meaning redirect POST requests with POST requests vs. doing what most\n     *   browsers do which is redirect POST requests with GET requests\n     * - referer: (bool, default=false) Set to true to enable the Referer\n     *   header.\n     * - protocols: (array, default=['http', 'https']) Allowed redirect\n     *   protocols.\n     * - on_redirect: (callable) PHP callable that is invoked when a redirect\n     *   is encountered. The callable is invoked with the request, the redirect\n     *   response that was received, and the effective URI. Any return value\n     *   from the on_redirect function is ignored.\n     */\n    const ALLOW_REDIRECTS = 'allow_redirects';\n\n    /**\n     * auth: (array) Pass an array of HTTP authentication parameters to use\n     * with the request. The array must contain the username in index [0],\n     * the password in index [1], and you can optionally provide a built-in\n     * authentication type in index [2]. Pass null to disable authentication\n     * for a request.\n     */\n    const AUTH = 'auth';\n\n    /**\n     * body: (resource|string|null|int|float|StreamInterface|callable|\\Iterator)\n     * Body to send in the request.\n     */\n    const BODY = 'body';\n\n    /**\n     * cert: (string|array) Set to a string to specify the path to a file\n     * containing a PEM formatted SSL client side certificate. If a password\n     * is required, then set cert to an array containing the path to the PEM\n     * file in the first array element followed by the certificate password\n     * in the second array element.\n     */\n    const CERT = 'cert';\n\n    /**\n     * cookies: (bool|GuzzleHttp\\Cookie\\CookieJarInterface, default=false)\n     * Specifies whether or not cookies are used in a request or what cookie\n     * jar to use or what cookies to send. This option only works if your\n     * handler has the `cookie` middleware. Valid values are `false` and\n     * an instance of {@see GuzzleHttp\\Cookie\\CookieJarInterface}.\n     */\n    const COOKIES = 'cookies';\n\n    /**\n     * connect_timeout: (float, default=0) Float describing the number of\n     * seconds to wait while trying to connect to a server. Use 0 to wait\n     * indefinitely (the default behavior).\n     */\n    const CONNECT_TIMEOUT = 'connect_timeout';\n\n    /**\n     * debug: (bool|resource) Set to true or set to a PHP stream returned by\n     * fopen()  enable debug output with the HTTP handler used to send a\n     * request.\n     */\n    const DEBUG = 'debug';\n\n    /**\n     * decode_content: (bool, default=true) Specify whether or not\n     * Content-Encoding responses (gzip, deflate, etc.) are automatically\n     * decoded.\n     */\n    const DECODE_CONTENT = 'decode_content';\n\n    /**\n     * delay: (int) The amount of time to delay before sending in milliseconds.\n     */\n    const DELAY = 'delay';\n\n    /**\n     * expect: (bool|integer) Controls the behavior of the\n     * \"Expect: 100-Continue\" header.\n     *\n     * Set to `true` to enable the \"Expect: 100-Continue\" header for all\n     * requests that sends a body. Set to `false` to disable the\n     * \"Expect: 100-Continue\" header for all requests. Set to a number so that\n     * the size of the payload must be greater than the number in order to send\n     * the Expect header. Setting to a number will send the Expect header for\n     * all requests in which the size of the payload cannot be determined or\n     * where the body is not rewindable.\n     *\n     * By default, Guzzle will add the \"Expect: 100-Continue\" header when the\n     * size of the body of a request is greater than 1 MB and a request is\n     * using HTTP/1.1.\n     */\n    const EXPECT = 'expect';\n\n    /**\n     * form_params: (array) Associative array of form field names to values\n     * where each value is a string or array of strings. Sets the Content-Type\n     * header to application/x-www-form-urlencoded when no Content-Type header\n     * is already present.\n     */\n    const FORM_PARAMS = 'form_params';\n\n    /**\n     * headers: (array) Associative array of HTTP headers. Each value MUST be\n     * a string or array of strings.\n     */\n    const HEADERS = 'headers';\n\n    /**\n     * http_errors: (bool, default=true) Set to false to disable exceptions\n     * when a non- successful HTTP response is received. By default,\n     * exceptions will be thrown for 4xx and 5xx responses. This option only\n     * works if your handler has the `httpErrors` middleware.\n     */\n    const HTTP_ERRORS = 'http_errors';\n\n    /**\n     * idn: (bool|int, default=true) A combination of IDNA_* constants for\n     * idn_to_ascii() PHP's function (see \"options\" parameter). Set to false to\n     * disable IDN support completely, or to true to use the default\n     * configuration (IDNA_DEFAULT constant).\n     */\n    const IDN_CONVERSION = 'idn_conversion';\n\n    /**\n     * json: (mixed) Adds JSON data to a request. The provided value is JSON\n     * encoded and a Content-Type header of application/json will be added to\n     * the request if no Content-Type header is already present.\n     */\n    const JSON = 'json';\n\n    /**\n     * multipart: (array) Array of associative arrays, each containing a\n     * required \"name\" key mapping to the form field, name, a required\n     * \"contents\" key mapping to a StreamInterface|resource|string, an\n     * optional \"headers\" associative array of custom headers, and an\n     * optional \"filename\" key mapping to a string to send as the filename in\n     * the part. If no \"filename\" key is present, then no \"filename\" attribute\n     * will be added to the part.\n     */\n    const MULTIPART = 'multipart';\n\n    /**\n     * on_headers: (callable) A callable that is invoked when the HTTP headers\n     * of the response have been received but the body has not yet begun to\n     * download.\n     */\n    const ON_HEADERS = 'on_headers';\n\n    /**\n     * on_stats: (callable) allows you to get access to transfer statistics of\n     * a request and access the lower level transfer details of the handler\n     * associated with your client. ``on_stats`` is a callable that is invoked\n     * when a handler has finished sending a request. The callback is invoked\n     * with transfer statistics about the request, the response received, or\n     * the error encountered. Included in the data is the total amount of time\n     * taken to send the request.\n     */\n    const ON_STATS = 'on_stats';\n\n    /**\n     * progress: (callable) Defines a function to invoke when transfer\n     * progress is made. The function accepts the following positional\n     * arguments: the total number of bytes expected to be downloaded, the\n     * number of bytes downloaded so far, the number of bytes expected to be\n     * uploaded, the number of bytes uploaded so far.\n     */\n    const PROGRESS = 'progress';\n\n    /**\n     * proxy: (string|array) Pass a string to specify an HTTP proxy, or an\n     * array to specify different proxies for different protocols (where the\n     * key is the protocol and the value is a proxy string).\n     */\n    const PROXY = 'proxy';\n\n    /**\n     * query: (array|string) Associative array of query string values to add\n     * to the request. This option uses PHP's http_build_query() to create\n     * the string representation. Pass a string value if you need more\n     * control than what this method provides\n     */\n    const QUERY = 'query';\n\n    /**\n     * sink: (resource|string|StreamInterface) Where the data of the\n     * response is written to. Defaults to a PHP temp stream. Providing a\n     * string will write data to a file by the given name.\n     */\n    const SINK = 'sink';\n\n    /**\n     * synchronous: (bool) Set to true to inform HTTP handlers that you intend\n     * on waiting on the response. This can be useful for optimizations. Note\n     * that a promise is still returned if you are using one of the async\n     * client methods.\n     */\n    const SYNCHRONOUS = 'synchronous';\n\n    /**\n     * ssl_key: (array|string) Specify the path to a file containing a private\n     * SSL key in PEM format. If a password is required, then set to an array\n     * containing the path to the SSL key in the first array element followed\n     * by the password required for the certificate in the second element.\n     */\n    const SSL_KEY = 'ssl_key';\n\n    /**\n     * stream: Set to true to attempt to stream a response rather than\n     * download it all up-front.\n     */\n    const STREAM = 'stream';\n\n    /**\n     * verify: (bool|string, default=true) Describes the SSL certificate\n     * verification behavior of a request. Set to true to enable SSL\n     * certificate verification using the system CA bundle when available\n     * (the default). Set to false to disable certificate verification (this\n     * is insecure!). Set to a string to provide the path to a CA bundle on\n     * disk to enable verification using a custom certificate.\n     */\n    const VERIFY = 'verify';\n\n    /**\n     * timeout: (float, default=0) Float describing the timeout of the\n     * request in seconds. Use 0 to wait indefinitely (the default behavior).\n     */\n    const TIMEOUT = 'timeout';\n\n    /**\n     * read_timeout: (float, default=default_socket_timeout ini setting) Float describing\n     * the body read timeout, for stream requests.\n     */\n    const READ_TIMEOUT = 'read_timeout';\n\n    /**\n     * version: (float) Specifies the HTTP protocol version to attempt to use.\n     */\n    const VERSION = 'version';\n\n    /**\n     * force_ip_resolve: (bool) Force client to use only ipv4 or ipv6 protocol\n     */\n    const FORCE_IP_RESOLVE = 'force_ip_resolve';\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/guzzle/src/RetryMiddleware.php",
    "content": "<?php\nnamespace GuzzleHttp;\n\nuse GuzzleHttp\\Promise\\PromiseInterface;\nuse GuzzleHttp\\Promise\\RejectedPromise;\nuse GuzzleHttp\\Psr7;\nuse Psr\\Http\\Message\\RequestInterface;\nuse Psr\\Http\\Message\\ResponseInterface;\n\n/**\n * Middleware that retries requests based on the boolean result of\n * invoking the provided \"decider\" function.\n */\nclass RetryMiddleware\n{\n    /** @var callable  */\n    private $nextHandler;\n\n    /** @var callable */\n    private $decider;\n\n    /** @var callable */\n    private $delay;\n\n    /**\n     * @param callable $decider     Function that accepts the number of retries,\n     *                              a request, [response], and [exception] and\n     *                              returns true if the request is to be\n     *                              retried.\n     * @param callable $nextHandler Next handler to invoke.\n     * @param callable $delay       Function that accepts the number of retries\n     *                              and [response] and returns the number of\n     *                              milliseconds to delay.\n     */\n    public function __construct(\n        callable $decider,\n        callable $nextHandler,\n        callable $delay = null\n    ) {\n        $this->decider = $decider;\n        $this->nextHandler = $nextHandler;\n        $this->delay = $delay ?: __CLASS__ . '::exponentialDelay';\n    }\n\n    /**\n     * Default exponential backoff delay function.\n     *\n     * @param int $retries\n     *\n     * @return int milliseconds.\n     */\n    public static function exponentialDelay($retries)\n    {\n        return (int) pow(2, $retries - 1) * 1000;\n    }\n\n    /**\n     * @param RequestInterface $request\n     * @param array            $options\n     *\n     * @return PromiseInterface\n     */\n    public function __invoke(RequestInterface $request, array $options)\n    {\n        if (!isset($options['retries'])) {\n            $options['retries'] = 0;\n        }\n\n        $fn = $this->nextHandler;\n        return $fn($request, $options)\n            ->then(\n                $this->onFulfilled($request, $options),\n                $this->onRejected($request, $options)\n            );\n    }\n\n    /**\n     * Execute fulfilled closure\n     *\n     * @return mixed\n     */\n    private function onFulfilled(RequestInterface $req, array $options)\n    {\n        return function ($value) use ($req, $options) {\n            if (!call_user_func(\n                $this->decider,\n                $options['retries'],\n                $req,\n                $value,\n                null\n            )) {\n                return $value;\n            }\n            return $this->doRetry($req, $options, $value);\n        };\n    }\n\n    /**\n     * Execute rejected closure\n     *\n     * @return callable\n     */\n    private function onRejected(RequestInterface $req, array $options)\n    {\n        return function ($reason) use ($req, $options) {\n            if (!call_user_func(\n                $this->decider,\n                $options['retries'],\n                $req,\n                null,\n                $reason\n            )) {\n                return \\GuzzleHttp\\Promise\\rejection_for($reason);\n            }\n            return $this->doRetry($req, $options);\n        };\n    }\n\n    /**\n     * @return self\n     */\n    private function doRetry(RequestInterface $request, array $options, ResponseInterface $response = null)\n    {\n        $options['delay'] = call_user_func($this->delay, ++$options['retries'], $response);\n\n        return $this($request, $options);\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/guzzle/src/TransferStats.php",
    "content": "<?php\nnamespace GuzzleHttp;\n\nuse Psr\\Http\\Message\\RequestInterface;\nuse Psr\\Http\\Message\\ResponseInterface;\nuse Psr\\Http\\Message\\UriInterface;\n\n/**\n * Represents data at the point after it was transferred either successfully\n * or after a network error.\n */\nfinal class TransferStats\n{\n    private $request;\n    private $response;\n    private $transferTime;\n    private $handlerStats;\n    private $handlerErrorData;\n\n    /**\n     * @param RequestInterface       $request          Request that was sent.\n     * @param ResponseInterface|null $response         Response received (if any)\n     * @param float|null             $transferTime     Total handler transfer time.\n     * @param mixed                  $handlerErrorData Handler error data.\n     * @param array                  $handlerStats     Handler specific stats.\n     */\n    public function __construct(\n        RequestInterface $request,\n        ResponseInterface $response = null,\n        $transferTime = null,\n        $handlerErrorData = null,\n        $handlerStats = []\n    ) {\n        $this->request = $request;\n        $this->response = $response;\n        $this->transferTime = $transferTime;\n        $this->handlerErrorData = $handlerErrorData;\n        $this->handlerStats = $handlerStats;\n    }\n\n    /**\n     * @return RequestInterface\n     */\n    public function getRequest()\n    {\n        return $this->request;\n    }\n\n    /**\n     * Returns the response that was received (if any).\n     *\n     * @return ResponseInterface|null\n     */\n    public function getResponse()\n    {\n        return $this->response;\n    }\n\n    /**\n     * Returns true if a response was received.\n     *\n     * @return bool\n     */\n    public function hasResponse()\n    {\n        return $this->response !== null;\n    }\n\n    /**\n     * Gets handler specific error data.\n     *\n     * This might be an exception, a integer representing an error code, or\n     * anything else. Relying on this value assumes that you know what handler\n     * you are using.\n     *\n     * @return mixed\n     */\n    public function getHandlerErrorData()\n    {\n        return $this->handlerErrorData;\n    }\n\n    /**\n     * Get the effective URI the request was sent to.\n     *\n     * @return UriInterface\n     */\n    public function getEffectiveUri()\n    {\n        return $this->request->getUri();\n    }\n\n    /**\n     * Get the estimated time the request was being transferred by the handler.\n     *\n     * @return float|null Time in seconds.\n     */\n    public function getTransferTime()\n    {\n        return $this->transferTime;\n    }\n\n    /**\n     * Gets an array of all of the handler specific transfer data.\n     *\n     * @return array\n     */\n    public function getHandlerStats()\n    {\n        return $this->handlerStats;\n    }\n\n    /**\n     * Get a specific handler statistic from the handler by name.\n     *\n     * @param string $stat Handler specific transfer stat to retrieve.\n     *\n     * @return mixed|null\n     */\n    public function getHandlerStat($stat)\n    {\n        return isset($this->handlerStats[$stat])\n            ? $this->handlerStats[$stat]\n            : null;\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/guzzle/src/UriTemplate.php",
    "content": "<?php\nnamespace GuzzleHttp;\n\n/**\n * Expands URI templates. Userland implementation of PECL uri_template.\n *\n * @link http://tools.ietf.org/html/rfc6570\n */\nclass UriTemplate\n{\n    /** @var string URI template */\n    private $template;\n\n    /** @var array Variables to use in the template expansion */\n    private $variables;\n\n    /** @var array Hash for quick operator lookups */\n    private static $operatorHash = [\n        ''  => ['prefix' => '',  'joiner' => ',', 'query' => false],\n        '+' => ['prefix' => '',  'joiner' => ',', 'query' => false],\n        '#' => ['prefix' => '#', 'joiner' => ',', 'query' => false],\n        '.' => ['prefix' => '.', 'joiner' => '.', 'query' => false],\n        '/' => ['prefix' => '/', 'joiner' => '/', 'query' => false],\n        ';' => ['prefix' => ';', 'joiner' => ';', 'query' => true],\n        '?' => ['prefix' => '?', 'joiner' => '&', 'query' => true],\n        '&' => ['prefix' => '&', 'joiner' => '&', 'query' => true]\n    ];\n\n    /** @var array Delimiters */\n    private static $delims = [':', '/', '?', '#', '[', ']', '@', '!', '$',\n        '&', '\\'', '(', ')', '*', '+', ',', ';', '='];\n\n    /** @var array Percent encoded delimiters */\n    private static $delimsPct = ['%3A', '%2F', '%3F', '%23', '%5B', '%5D',\n        '%40', '%21', '%24', '%26', '%27', '%28', '%29', '%2A', '%2B', '%2C',\n        '%3B', '%3D'];\n\n    public function expand($template, array $variables)\n    {\n        if (false === strpos($template, '{')) {\n            return $template;\n        }\n\n        $this->template = $template;\n        $this->variables = $variables;\n\n        return preg_replace_callback(\n            '/\\{([^\\}]+)\\}/',\n            [$this, 'expandMatch'],\n            $this->template\n        );\n    }\n\n    /**\n     * Parse an expression into parts\n     *\n     * @param string $expression Expression to parse\n     *\n     * @return array Returns an associative array of parts\n     */\n    private function parseExpression($expression)\n    {\n        $result = [];\n\n        if (isset(self::$operatorHash[$expression[0]])) {\n            $result['operator'] = $expression[0];\n            $expression = substr($expression, 1);\n        } else {\n            $result['operator'] = '';\n        }\n\n        foreach (explode(',', $expression) as $value) {\n            $value = trim($value);\n            $varspec = [];\n            if ($colonPos = strpos($value, ':')) {\n                $varspec['value'] = substr($value, 0, $colonPos);\n                $varspec['modifier'] = ':';\n                $varspec['position'] = (int) substr($value, $colonPos + 1);\n            } elseif (substr($value, -1) === '*') {\n                $varspec['modifier'] = '*';\n                $varspec['value'] = substr($value, 0, -1);\n            } else {\n                $varspec['value'] = (string) $value;\n                $varspec['modifier'] = '';\n            }\n            $result['values'][] = $varspec;\n        }\n\n        return $result;\n    }\n\n    /**\n     * Process an expansion\n     *\n     * @param array $matches Matches met in the preg_replace_callback\n     *\n     * @return string Returns the replacement string\n     */\n    private function expandMatch(array $matches)\n    {\n        static $rfc1738to3986 = ['+' => '%20', '%7e' => '~'];\n\n        $replacements = [];\n        $parsed = self::parseExpression($matches[1]);\n        $prefix = self::$operatorHash[$parsed['operator']]['prefix'];\n        $joiner = self::$operatorHash[$parsed['operator']]['joiner'];\n        $useQuery = self::$operatorHash[$parsed['operator']]['query'];\n\n        foreach ($parsed['values'] as $value) {\n            if (!isset($this->variables[$value['value']])) {\n                continue;\n            }\n\n            $variable = $this->variables[$value['value']];\n            $actuallyUseQuery = $useQuery;\n            $expanded = '';\n\n            if (is_array($variable)) {\n                $isAssoc = $this->isAssoc($variable);\n                $kvp = [];\n                foreach ($variable as $key => $var) {\n                    if ($isAssoc) {\n                        $key = rawurlencode($key);\n                        $isNestedArray = is_array($var);\n                    } else {\n                        $isNestedArray = false;\n                    }\n\n                    if (!$isNestedArray) {\n                        $var = rawurlencode($var);\n                        if ($parsed['operator'] === '+' ||\n                            $parsed['operator'] === '#'\n                        ) {\n                            $var = $this->decodeReserved($var);\n                        }\n                    }\n\n                    if ($value['modifier'] === '*') {\n                        if ($isAssoc) {\n                            if ($isNestedArray) {\n                                // Nested arrays must allow for deeply nested\n                                // structures.\n                                $var = strtr(\n                                    http_build_query([$key => $var]),\n                                    $rfc1738to3986\n                                );\n                            } else {\n                                $var = $key . '=' . $var;\n                            }\n                        } elseif ($key > 0 && $actuallyUseQuery) {\n                            $var = $value['value'] . '=' . $var;\n                        }\n                    }\n\n                    $kvp[$key] = $var;\n                }\n\n                if (empty($variable)) {\n                    $actuallyUseQuery = false;\n                } elseif ($value['modifier'] === '*') {\n                    $expanded = implode($joiner, $kvp);\n                    if ($isAssoc) {\n                        // Don't prepend the value name when using the explode\n                        // modifier with an associative array.\n                        $actuallyUseQuery = false;\n                    }\n                } else {\n                    if ($isAssoc) {\n                        // When an associative array is encountered and the\n                        // explode modifier is not set, then the result must be\n                        // a comma separated list of keys followed by their\n                        // respective values.\n                        foreach ($kvp as $k => &$v) {\n                            $v = $k . ',' . $v;\n                        }\n                    }\n                    $expanded = implode(',', $kvp);\n                }\n            } else {\n                if ($value['modifier'] === ':') {\n                    $variable = substr($variable, 0, $value['position']);\n                }\n                $expanded = rawurlencode($variable);\n                if ($parsed['operator'] === '+' || $parsed['operator'] === '#') {\n                    $expanded = $this->decodeReserved($expanded);\n                }\n            }\n\n            if ($actuallyUseQuery) {\n                if (!$expanded && $joiner !== '&') {\n                    $expanded = $value['value'];\n                } else {\n                    $expanded = $value['value'] . '=' . $expanded;\n                }\n            }\n\n            $replacements[] = $expanded;\n        }\n\n        $ret = implode($joiner, $replacements);\n        if ($ret && $prefix) {\n            return $prefix . $ret;\n        }\n\n        return $ret;\n    }\n\n    /**\n     * Determines if an array is associative.\n     *\n     * This makes the assumption that input arrays are sequences or hashes.\n     * This assumption is a tradeoff for accuracy in favor of speed, but it\n     * should work in almost every case where input is supplied for a URI\n     * template.\n     *\n     * @param array $array Array to check\n     *\n     * @return bool\n     */\n    private function isAssoc(array $array)\n    {\n        return $array && array_keys($array)[0] !== 0;\n    }\n\n    /**\n     * Removes percent encoding on reserved characters (used with + and #\n     * modifiers).\n     *\n     * @param string $string String to fix\n     *\n     * @return string\n     */\n    private function decodeReserved($string)\n    {\n        return str_replace(self::$delimsPct, self::$delims, $string);\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/guzzle/src/Utils.php",
    "content": "<?php\nnamespace GuzzleHttp;\n\nuse GuzzleHttp\\Exception\\InvalidArgumentException;\nuse Psr\\Http\\Message\\UriInterface;\nuse Symfony\\Polyfill\\Intl\\Idn\\Idn;\n\nfinal class Utils\n{\n    /**\n     * Wrapper for the hrtime() or microtime() functions\n     * (depending on the PHP version, one of the two is used)\n     *\n     * @return float|mixed UNIX timestamp\n     *\n     * @internal\n     */\n    public static function currentTime()\n    {\n        return function_exists('hrtime') ? hrtime(true) / 1e9 : microtime(true);\n    }\n\n    /**\n     * @param int $options\n     *\n     * @return UriInterface\n     * @throws InvalidArgumentException\n     *\n     * @internal\n     */\n    public static function idnUriConvert(UriInterface $uri, $options = 0)\n    {\n        if ($uri->getHost()) {\n            $asciiHost = self::idnToAsci($uri->getHost(), $options, $info);\n            if ($asciiHost === false) {\n                $errorBitSet = isset($info['errors']) ? $info['errors'] : 0;\n\n                $errorConstants = array_filter(array_keys(get_defined_constants()), function ($name) {\n                    return substr($name, 0, 11) === 'IDNA_ERROR_';\n                });\n\n                $errors = [];\n                foreach ($errorConstants as $errorConstant) {\n                    if ($errorBitSet & constant($errorConstant)) {\n                        $errors[] = $errorConstant;\n                    }\n                }\n\n                $errorMessage = 'IDN conversion failed';\n                if ($errors) {\n                    $errorMessage .= ' (errors: ' . implode(', ', $errors) . ')';\n                }\n\n                throw new InvalidArgumentException($errorMessage);\n            } else {\n                if ($uri->getHost() !== $asciiHost) {\n                    // Replace URI only if the ASCII version is different\n                    $uri = $uri->withHost($asciiHost);\n                }\n            }\n        }\n\n        return $uri;\n    }\n\n    /**\n     * @param string $domain\n     * @param int    $options\n     * @param array  $info\n     *\n     * @return string|false\n     */\n    private static function idnToAsci($domain, $options, &$info = [])\n    {\n        if (\\preg_match('%^[ -~]+$%', $domain) === 1) {\n            return $domain;\n        }\n\n        if (\\extension_loaded('intl') && defined('INTL_IDNA_VARIANT_UTS46')) {\n            return \\idn_to_ascii($domain, $options, INTL_IDNA_VARIANT_UTS46, $info);\n        }\n\n        /*\n         * The Idn class is marked as @internal. Verify that class and method exists.\n         */\n        if (method_exists(Idn::class, 'idn_to_ascii')) {\n            return Idn::idn_to_ascii($domain, $options, Idn::INTL_IDNA_VARIANT_UTS46, $info);\n        }\n\n        throw new \\RuntimeException('ext-intl or symfony/polyfill-intl-idn not loaded or too old');\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/guzzle/src/functions.php",
    "content": "<?php\nnamespace GuzzleHttp;\n\nuse GuzzleHttp\\Handler\\CurlHandler;\nuse GuzzleHttp\\Handler\\CurlMultiHandler;\nuse GuzzleHttp\\Handler\\Proxy;\nuse GuzzleHttp\\Handler\\StreamHandler;\n\n/**\n * Expands a URI template\n *\n * @param string $template  URI template\n * @param array  $variables Template variables\n *\n * @return string\n */\nfunction uri_template($template, array $variables)\n{\n    if (extension_loaded('uri_template')) {\n        // @codeCoverageIgnoreStart\n        return \\uri_template($template, $variables);\n        // @codeCoverageIgnoreEnd\n    }\n\n    static $uriTemplate;\n    if (!$uriTemplate) {\n        $uriTemplate = new UriTemplate();\n    }\n\n    return $uriTemplate->expand($template, $variables);\n}\n\n/**\n * Debug function used to describe the provided value type and class.\n *\n * @param mixed $input\n *\n * @return string Returns a string containing the type of the variable and\n *                if a class is provided, the class name.\n */\nfunction describe_type($input)\n{\n    switch (gettype($input)) {\n        case 'object':\n            return 'object(' . get_class($input) . ')';\n        case 'array':\n            return 'array(' . count($input) . ')';\n        default:\n            ob_start();\n            var_dump($input);\n            // normalize float vs double\n            return str_replace('double(', 'float(', rtrim(ob_get_clean()));\n    }\n}\n\n/**\n * Parses an array of header lines into an associative array of headers.\n *\n * @param iterable $lines Header lines array of strings in the following\n *                     format: \"Name: Value\"\n * @return array\n */\nfunction headers_from_lines($lines)\n{\n    $headers = [];\n\n    foreach ($lines as $line) {\n        $parts = explode(':', $line, 2);\n        $headers[trim($parts[0])][] = isset($parts[1])\n            ? trim($parts[1])\n            : null;\n    }\n\n    return $headers;\n}\n\n/**\n * Returns a debug stream based on the provided variable.\n *\n * @param mixed $value Optional value\n *\n * @return resource\n */\nfunction debug_resource($value = null)\n{\n    if (is_resource($value)) {\n        return $value;\n    } elseif (defined('STDOUT')) {\n        return STDOUT;\n    }\n\n    return fopen('php://output', 'w');\n}\n\n/**\n * Chooses and creates a default handler to use based on the environment.\n *\n * The returned handler is not wrapped by any default middlewares.\n *\n * @return callable Returns the best handler for the given system.\n * @throws \\RuntimeException if no viable Handler is available.\n */\nfunction choose_handler()\n{\n    $handler = null;\n    if (function_exists('curl_multi_exec') && function_exists('curl_exec')) {\n        $handler = Proxy::wrapSync(new CurlMultiHandler(), new CurlHandler());\n    } elseif (function_exists('curl_exec')) {\n        $handler = new CurlHandler();\n    } elseif (function_exists('curl_multi_exec')) {\n        $handler = new CurlMultiHandler();\n    }\n\n    if (ini_get('allow_url_fopen')) {\n        $handler = $handler\n            ? Proxy::wrapStreaming($handler, new StreamHandler())\n            : new StreamHandler();\n    } elseif (!$handler) {\n        throw new \\RuntimeException('GuzzleHttp requires cURL, the '\n            . 'allow_url_fopen ini setting, or a custom HTTP handler.');\n    }\n\n    return $handler;\n}\n\n/**\n * Get the default User-Agent string to use with Guzzle\n *\n * @return string\n */\nfunction default_user_agent()\n{\n    static $defaultAgent = '';\n\n    if (!$defaultAgent) {\n        $defaultAgent = 'GuzzleHttp/' . Client::VERSION;\n        if (extension_loaded('curl') && function_exists('curl_version')) {\n            $defaultAgent .= ' curl/' . \\curl_version()['version'];\n        }\n        $defaultAgent .= ' PHP/' . PHP_VERSION;\n    }\n\n    return $defaultAgent;\n}\n\n/**\n * Returns the default cacert bundle for the current system.\n *\n * First, the openssl.cafile and curl.cainfo php.ini settings are checked.\n * If those settings are not configured, then the common locations for\n * bundles found on Red Hat, CentOS, Fedora, Ubuntu, Debian, FreeBSD, OS X\n * and Windows are checked. If any of these file locations are found on\n * disk, they will be utilized.\n *\n * Note: the result of this function is cached for subsequent calls.\n *\n * @return string\n * @throws \\RuntimeException if no bundle can be found.\n */\nfunction default_ca_bundle()\n{\n    static $cached = null;\n    static $cafiles = [\n        // Red Hat, CentOS, Fedora (provided by the ca-certificates package)\n        '/etc/pki/tls/certs/ca-bundle.crt',\n        // Ubuntu, Debian (provided by the ca-certificates package)\n        '/etc/ssl/certs/ca-certificates.crt',\n        // FreeBSD (provided by the ca_root_nss package)\n        '/usr/local/share/certs/ca-root-nss.crt',\n        // SLES 12 (provided by the ca-certificates package)\n        '/var/lib/ca-certificates/ca-bundle.pem',\n        // OS X provided by homebrew (using the default path)\n        '/usr/local/etc/openssl/cert.pem',\n        // Google app engine\n        '/etc/ca-certificates.crt',\n        // Windows?\n        'C:\\\\windows\\\\system32\\\\curl-ca-bundle.crt',\n        'C:\\\\windows\\\\curl-ca-bundle.crt',\n    ];\n\n    if ($cached) {\n        return $cached;\n    }\n\n    if ($ca = ini_get('openssl.cafile')) {\n        return $cached = $ca;\n    }\n\n    if ($ca = ini_get('curl.cainfo')) {\n        return $cached = $ca;\n    }\n\n    foreach ($cafiles as $filename) {\n        if (file_exists($filename)) {\n            return $cached = $filename;\n        }\n    }\n\n    throw new \\RuntimeException(\n        <<< EOT\nNo system CA bundle could be found in any of the the common system locations.\nPHP versions earlier than 5.6 are not properly configured to use the system's\nCA bundle by default. In order to verify peer certificates, you will need to\nsupply the path on disk to a certificate bundle to the 'verify' request\noption: http://docs.guzzlephp.org/en/latest/clients.html#verify. If you do not\nneed a specific certificate bundle, then Mozilla provides a commonly used CA\nbundle which can be downloaded here (provided by the maintainer of cURL):\nhttps://raw.githubusercontent.com/bagder/ca-bundle/master/ca-bundle.crt. Once\nyou have a CA bundle available on disk, you can set the 'openssl.cafile' PHP\nini setting to point to the path to the file, allowing you to omit the 'verify'\nrequest option. See http://curl.haxx.se/docs/sslcerts.html for more\ninformation.\nEOT\n    );\n}\n\n/**\n * Creates an associative array of lowercase header names to the actual\n * header casing.\n *\n * @param array $headers\n *\n * @return array\n */\nfunction normalize_header_keys(array $headers)\n{\n    $result = [];\n    foreach (array_keys($headers) as $key) {\n        $result[strtolower($key)] = $key;\n    }\n\n    return $result;\n}\n\n/**\n * Returns true if the provided host matches any of the no proxy areas.\n *\n * This method will strip a port from the host if it is present. Each pattern\n * can be matched with an exact match (e.g., \"foo.com\" == \"foo.com\") or a\n * partial match: (e.g., \"foo.com\" == \"baz.foo.com\" and \".foo.com\" ==\n * \"baz.foo.com\", but \".foo.com\" != \"foo.com\").\n *\n * Areas are matched in the following cases:\n * 1. \"*\" (without quotes) always matches any hosts.\n * 2. An exact match.\n * 3. The area starts with \".\" and the area is the last part of the host. e.g.\n *    '.mit.edu' will match any host that ends with '.mit.edu'.\n *\n * @param string $host         Host to check against the patterns.\n * @param array  $noProxyArray An array of host patterns.\n *\n * @return bool\n */\nfunction is_host_in_noproxy($host, array $noProxyArray)\n{\n    if (strlen($host) === 0) {\n        throw new \\InvalidArgumentException('Empty host provided');\n    }\n\n    // Strip port if present.\n    if (strpos($host, ':')) {\n        $host = explode($host, ':', 2)[0];\n    }\n\n    foreach ($noProxyArray as $area) {\n        // Always match on wildcards.\n        if ($area === '*') {\n            return true;\n        } elseif (empty($area)) {\n            // Don't match on empty values.\n            continue;\n        } elseif ($area === $host) {\n            // Exact matches.\n            return true;\n        } else {\n            // Special match if the area when prefixed with \".\". Remove any\n            // existing leading \".\" and add a new leading \".\".\n            $area = '.' . ltrim($area, '.');\n            if (substr($host, -(strlen($area))) === $area) {\n                return true;\n            }\n        }\n    }\n\n    return false;\n}\n\n/**\n * Wrapper for json_decode that throws when an error occurs.\n *\n * @param string $json    JSON data to parse\n * @param bool $assoc     When true, returned objects will be converted\n *                        into associative arrays.\n * @param int    $depth   User specified recursion depth.\n * @param int    $options Bitmask of JSON decode options.\n *\n * @return mixed\n * @throws Exception\\InvalidArgumentException if the JSON cannot be decoded.\n * @link http://www.php.net/manual/en/function.json-decode.php\n */\nfunction json_decode($json, $assoc = false, $depth = 512, $options = 0)\n{\n    $data = \\json_decode($json, $assoc, $depth, $options);\n    if (JSON_ERROR_NONE !== json_last_error()) {\n        throw new Exception\\InvalidArgumentException(\n            'json_decode error: ' . json_last_error_msg()\n        );\n    }\n\n    return $data;\n}\n\n/**\n * Wrapper for JSON encoding that throws when an error occurs.\n *\n * @param mixed $value   The value being encoded\n * @param int    $options JSON encode option bitmask\n * @param int    $depth   Set the maximum depth. Must be greater than zero.\n *\n * @return string\n * @throws Exception\\InvalidArgumentException if the JSON cannot be encoded.\n * @link http://www.php.net/manual/en/function.json-encode.php\n */\nfunction json_encode($value, $options = 0, $depth = 512)\n{\n    $json = \\json_encode($value, $options, $depth);\n    if (JSON_ERROR_NONE !== json_last_error()) {\n        throw new Exception\\InvalidArgumentException(\n            'json_encode error: ' . json_last_error_msg()\n        );\n    }\n\n    return $json;\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/guzzle/src/functions_include.php",
    "content": "<?php\n\n// Don't redefine the functions if included multiple times.\nif (!function_exists('GuzzleHttp\\uri_template')) {\n    require __DIR__ . '/functions.php';\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/promises/CHANGELOG.md",
    "content": "# CHANGELOG\n\n## 1.5.3 - 2023-05-21\n\n### Changed\n\n- Removed remaining usage of deprecated functions\n\n## 1.5.2 - 2022-08-07\n\n### Changed\n\n- Officially support PHP 8.2\n\n## 1.5.1 - 2021-10-22\n\n### Fixed\n\n- Revert \"Call handler when waiting on fulfilled/rejected Promise\"\n- Fix pool memory leak when empty array of promises provided\n\n## 1.5.0 - 2021-10-07\n\n### Changed\n\n- Call handler when waiting on fulfilled/rejected Promise\n- Officially support PHP 8.1\n\n### Fixed\n\n- Fix manually settle promises generated with `Utils::task`\n\n## 1.4.1 - 2021-02-18\n\n### Fixed\n\n- Fixed `each_limit` skipping promises and failing\n\n## 1.4.0 - 2020-09-30\n\n### Added\n\n- Support for PHP 8\n- Optional `$recursive` flag to `all`\n- Replaced functions by static methods\n\n### Fixed\n\n- Fix empty `each` processing\n- Fix promise handling for Iterators of non-unique keys\n- Fixed `method_exists` crashes on PHP 8\n- Memory leak on exceptions\n\n\n## 1.3.1 - 2016-12-20\n\n### Fixed\n\n- `wait()` foreign promise compatibility\n\n\n## 1.3.0 - 2016-11-18\n\n### Added\n\n- Adds support for custom task queues.\n\n### Fixed\n\n- Fixed coroutine promise memory leak.\n\n\n## 1.2.0 - 2016-05-18\n\n### Changed\n\n- Update to now catch `\\Throwable` on PHP 7+\n\n\n## 1.1.0 - 2016-03-07\n\n### Changed\n\n- Update EachPromise to prevent recurring on a iterator when advancing, as this\n  could trigger fatal generator errors.\n- Update Promise to allow recursive waiting without unwrapping exceptions.\n\n\n## 1.0.3 - 2015-10-15\n\n### Changed\n\n- Update EachPromise to immediately resolve when the underlying promise iterator\n  is empty. Previously, such a promise would throw an exception when its `wait`\n  function was called.\n\n\n## 1.0.2 - 2015-05-15\n\n### Changed\n\n- Conditionally require functions.php.\n\n\n## 1.0.1 - 2015-06-24\n\n### Changed\n\n- Updating EachPromise to call next on the underlying promise iterator as late\n  as possible to ensure that generators that generate new requests based on\n  callbacks are not iterated until after callbacks are invoked.\n\n\n## 1.0.0 - 2015-05-12\n\n- Initial release\n"
  },
  {
    "path": "server/vendor/guzzlehttp/promises/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2015 Michael Dowling <mtdowling@gmail.com>\nCopyright (c) 2015 Graham Campbell <hello@gjcampbell.co.uk>\nCopyright (c) 2017 Tobias Schultze <webmaster@tubo-world.de>\nCopyright (c) 2020 Tobias Nyholm <tobias.nyholm@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "server/vendor/guzzlehttp/promises/README.md",
    "content": "# Guzzle Promises\n\n[Promises/A+](https://promisesaplus.com/) implementation that handles promise\nchaining and resolution iteratively, allowing for \"infinite\" promise chaining\nwhile keeping the stack size constant. Read [this blog post](https://blog.domenic.me/youre-missing-the-point-of-promises/)\nfor a general introduction to promises.\n\n- [Features](#features)\n- [Quick start](#quick-start)\n- [Synchronous wait](#synchronous-wait)\n- [Cancellation](#cancellation)\n- [API](#api)\n  - [Promise](#promise)\n  - [FulfilledPromise](#fulfilledpromise)\n  - [RejectedPromise](#rejectedpromise)\n- [Promise interop](#promise-interop)\n- [Implementation notes](#implementation-notes)\n\n\n## Features\n\n- [Promises/A+](https://promisesaplus.com/) implementation.\n- Promise resolution and chaining is handled iteratively, allowing for\n  \"infinite\" promise chaining.\n- Promises have a synchronous `wait` method.\n- Promises can be cancelled.\n- Works with any object that has a `then` function.\n- C# style async/await coroutine promises using\n  `GuzzleHttp\\Promise\\Coroutine::of()`.\n\n\n## Quick Start\n\nA *promise* represents the eventual result of an asynchronous operation. The\nprimary way of interacting with a promise is through its `then` method, which\nregisters callbacks to receive either a promise's eventual value or the reason\nwhy the promise cannot be fulfilled.\n\n### Callbacks\n\nCallbacks are registered with the `then` method by providing an optional \n`$onFulfilled` followed by an optional `$onRejected` function.\n\n\n```php\nuse GuzzleHttp\\Promise\\Promise;\n\n$promise = new Promise();\n$promise->then(\n    // $onFulfilled\n    function ($value) {\n        echo 'The promise was fulfilled.';\n    },\n    // $onRejected\n    function ($reason) {\n        echo 'The promise was rejected.';\n    }\n);\n```\n\n*Resolving* a promise means that you either fulfill a promise with a *value* or\nreject a promise with a *reason*. Resolving a promise triggers callbacks\nregistered with the promise's `then` method. These callbacks are triggered\nonly once and in the order in which they were added.\n\n### Resolving a Promise\n\nPromises are fulfilled using the `resolve($value)` method. Resolving a promise\nwith any value other than a `GuzzleHttp\\Promise\\RejectedPromise` will trigger\nall of the onFulfilled callbacks (resolving a promise with a rejected promise\nwill reject the promise and trigger the `$onRejected` callbacks).\n\n```php\nuse GuzzleHttp\\Promise\\Promise;\n\n$promise = new Promise();\n$promise\n    ->then(function ($value) {\n        // Return a value and don't break the chain\n        return \"Hello, \" . $value;\n    })\n    // This then is executed after the first then and receives the value\n    // returned from the first then.\n    ->then(function ($value) {\n        echo $value;\n    });\n\n// Resolving the promise triggers the $onFulfilled callbacks and outputs\n// \"Hello, reader.\"\n$promise->resolve('reader.');\n```\n\n### Promise Forwarding\n\nPromises can be chained one after the other. Each then in the chain is a new\npromise. The return value of a promise is what's forwarded to the next\npromise in the chain. Returning a promise in a `then` callback will cause the\nsubsequent promises in the chain to only be fulfilled when the returned promise\nhas been fulfilled. The next promise in the chain will be invoked with the\nresolved value of the promise.\n\n```php\nuse GuzzleHttp\\Promise\\Promise;\n\n$promise = new Promise();\n$nextPromise = new Promise();\n\n$promise\n    ->then(function ($value) use ($nextPromise) {\n        echo $value;\n        return $nextPromise;\n    })\n    ->then(function ($value) {\n        echo $value;\n    });\n\n// Triggers the first callback and outputs \"A\"\n$promise->resolve('A');\n// Triggers the second callback and outputs \"B\"\n$nextPromise->resolve('B');\n```\n\n### Promise Rejection\n\nWhen a promise is rejected, the `$onRejected` callbacks are invoked with the\nrejection reason.\n\n```php\nuse GuzzleHttp\\Promise\\Promise;\n\n$promise = new Promise();\n$promise->then(null, function ($reason) {\n    echo $reason;\n});\n\n$promise->reject('Error!');\n// Outputs \"Error!\"\n```\n\n### Rejection Forwarding\n\nIf an exception is thrown in an `$onRejected` callback, subsequent\n`$onRejected` callbacks are invoked with the thrown exception as the reason.\n\n```php\nuse GuzzleHttp\\Promise\\Promise;\n\n$promise = new Promise();\n$promise->then(null, function ($reason) {\n    throw new Exception($reason);\n})->then(null, function ($reason) {\n    assert($reason->getMessage() === 'Error!');\n});\n\n$promise->reject('Error!');\n```\n\nYou can also forward a rejection down the promise chain by returning a\n`GuzzleHttp\\Promise\\RejectedPromise` in either an `$onFulfilled` or\n`$onRejected` callback.\n\n```php\nuse GuzzleHttp\\Promise\\Promise;\nuse GuzzleHttp\\Promise\\RejectedPromise;\n\n$promise = new Promise();\n$promise->then(null, function ($reason) {\n    return new RejectedPromise($reason);\n})->then(null, function ($reason) {\n    assert($reason === 'Error!');\n});\n\n$promise->reject('Error!');\n```\n\nIf an exception is not thrown in a `$onRejected` callback and the callback\ndoes not return a rejected promise, downstream `$onFulfilled` callbacks are\ninvoked using the value returned from the `$onRejected` callback.\n\n```php\nuse GuzzleHttp\\Promise\\Promise;\n\n$promise = new Promise();\n$promise\n    ->then(null, function ($reason) {\n        return \"It's ok\";\n    })\n    ->then(function ($value) {\n        assert($value === \"It's ok\");\n    });\n\n$promise->reject('Error!');\n```\n\n\n## Synchronous Wait\n\nYou can synchronously force promises to complete using a promise's `wait`\nmethod. When creating a promise, you can provide a wait function that is used\nto synchronously force a promise to complete. When a wait function is invoked\nit is expected to deliver a value to the promise or reject the promise. If the\nwait function does not deliver a value, then an exception is thrown. The wait\nfunction provided to a promise constructor is invoked when the `wait` function\nof the promise is called.\n\n```php\n$promise = new Promise(function () use (&$promise) {\n    $promise->resolve('foo');\n});\n\n// Calling wait will return the value of the promise.\necho $promise->wait(); // outputs \"foo\"\n```\n\nIf an exception is encountered while invoking the wait function of a promise,\nthe promise is rejected with the exception and the exception is thrown.\n\n```php\n$promise = new Promise(function () use (&$promise) {\n    throw new Exception('foo');\n});\n\n$promise->wait(); // throws the exception.\n```\n\nCalling `wait` on a promise that has been fulfilled will not trigger the wait\nfunction. It will simply return the previously resolved value.\n\n```php\n$promise = new Promise(function () { die('this is not called!'); });\n$promise->resolve('foo');\necho $promise->wait(); // outputs \"foo\"\n```\n\nCalling `wait` on a promise that has been rejected will throw an exception. If\nthe rejection reason is an instance of `\\Exception` the reason is thrown.\nOtherwise, a `GuzzleHttp\\Promise\\RejectionException` is thrown and the reason\ncan be obtained by calling the `getReason` method of the exception.\n\n```php\n$promise = new Promise();\n$promise->reject('foo');\n$promise->wait();\n```\n\n> PHP Fatal error:  Uncaught exception 'GuzzleHttp\\Promise\\RejectionException' with message 'The promise was rejected with value: foo'\n\n### Unwrapping a Promise\n\nWhen synchronously waiting on a promise, you are joining the state of the\npromise into the current state of execution (i.e., return the value of the\npromise if it was fulfilled or throw an exception if it was rejected). This is\ncalled \"unwrapping\" the promise. Waiting on a promise will by default unwrap\nthe promise state.\n\nYou can force a promise to resolve and *not* unwrap the state of the promise\nby passing `false` to the first argument of the `wait` function:\n\n```php\n$promise = new Promise();\n$promise->reject('foo');\n// This will not throw an exception. It simply ensures the promise has\n// been resolved.\n$promise->wait(false);\n```\n\nWhen unwrapping a promise, the resolved value of the promise will be waited\nupon until the unwrapped value is not a promise. This means that if you resolve\npromise A with a promise B and unwrap promise A, the value returned by the\nwait function will be the value delivered to promise B.\n\n**Note**: when you do not unwrap the promise, no value is returned.\n\n\n## Cancellation\n\nYou can cancel a promise that has not yet been fulfilled using the `cancel()`\nmethod of a promise. When creating a promise you can provide an optional\ncancel function that when invoked cancels the action of computing a resolution\nof the promise.\n\n\n## API\n\n### Promise\n\nWhen creating a promise object, you can provide an optional `$waitFn` and\n`$cancelFn`. `$waitFn` is a function that is invoked with no arguments and is\nexpected to resolve the promise. `$cancelFn` is a function with no arguments\nthat is expected to cancel the computation of a promise. It is invoked when the\n`cancel()` method of a promise is called.\n\n```php\nuse GuzzleHttp\\Promise\\Promise;\n\n$promise = new Promise(\n    function () use (&$promise) {\n        $promise->resolve('waited');\n    },\n    function () {\n        // do something that will cancel the promise computation (e.g., close\n        // a socket, cancel a database query, etc...)\n    }\n);\n\nassert('waited' === $promise->wait());\n```\n\nA promise has the following methods:\n\n- `then(callable $onFulfilled, callable $onRejected) : PromiseInterface`\n  \n  Appends fulfillment and rejection handlers to the promise, and returns a new promise resolving to the return value of the called handler.\n\n- `otherwise(callable $onRejected) : PromiseInterface`\n  \n  Appends a rejection handler callback to the promise, and returns a new promise resolving to the return value of the callback if it is called, or to its original fulfillment value if the promise is instead fulfilled.\n\n- `wait($unwrap = true) : mixed`\n\n  Synchronously waits on the promise to complete.\n  \n  `$unwrap` controls whether or not the value of the promise is returned for a\n  fulfilled promise or if an exception is thrown if the promise is rejected.\n  This is set to `true` by default.\n\n- `cancel()`\n\n  Attempts to cancel the promise if possible. The promise being cancelled and\n  the parent most ancestor that has not yet been resolved will also be\n  cancelled. Any promises waiting on the cancelled promise to resolve will also\n  be cancelled.\n\n- `getState() : string`\n\n  Returns the state of the promise. One of `pending`, `fulfilled`, or\n  `rejected`.\n\n- `resolve($value)`\n\n  Fulfills the promise with the given `$value`.\n\n- `reject($reason)`\n\n  Rejects the promise with the given `$reason`.\n\n\n### FulfilledPromise\n\nA fulfilled promise can be created to represent a promise that has been\nfulfilled.\n\n```php\nuse GuzzleHttp\\Promise\\FulfilledPromise;\n\n$promise = new FulfilledPromise('value');\n\n// Fulfilled callbacks are immediately invoked.\n$promise->then(function ($value) {\n    echo $value;\n});\n```\n\n\n### RejectedPromise\n\nA rejected promise can be created to represent a promise that has been\nrejected.\n\n```php\nuse GuzzleHttp\\Promise\\RejectedPromise;\n\n$promise = new RejectedPromise('Error');\n\n// Rejected callbacks are immediately invoked.\n$promise->then(null, function ($reason) {\n    echo $reason;\n});\n```\n\n\n## Promise Interoperability\n\nThis library works with foreign promises that have a `then` method. This means\nyou can use Guzzle promises with [React promises](https://github.com/reactphp/promise)\nfor example. When a foreign promise is returned inside of a then method\ncallback, promise resolution will occur recursively.\n\n```php\n// Create a React promise\n$deferred = new React\\Promise\\Deferred();\n$reactPromise = $deferred->promise();\n\n// Create a Guzzle promise that is fulfilled with a React promise.\n$guzzlePromise = new GuzzleHttp\\Promise\\Promise();\n$guzzlePromise->then(function ($value) use ($reactPromise) {\n    // Do something something with the value...\n    // Return the React promise\n    return $reactPromise;\n});\n```\n\nPlease note that wait and cancel chaining is no longer possible when forwarding\na foreign promise. You will need to wrap a third-party promise with a Guzzle\npromise in order to utilize wait and cancel functions with foreign promises.\n\n\n### Event Loop Integration\n\nIn order to keep the stack size constant, Guzzle promises are resolved\nasynchronously using a task queue. When waiting on promises synchronously, the\ntask queue will be automatically run to ensure that the blocking promise and\nany forwarded promises are resolved. When using promises asynchronously in an\nevent loop, you will need to run the task queue on each tick of the loop. If\nyou do not run the task queue, then promises will not be resolved.\n\nYou can run the task queue using the `run()` method of the global task queue\ninstance.\n\n```php\n// Get the global task queue\n$queue = GuzzleHttp\\Promise\\Utils::queue();\n$queue->run();\n```\n\nFor example, you could use Guzzle promises with React using a periodic timer:\n\n```php\n$loop = React\\EventLoop\\Factory::create();\n$loop->addPeriodicTimer(0, [$queue, 'run']);\n```\n\n*TODO*: Perhaps adding a `futureTick()` on each tick would be faster?\n\n\n## Implementation Notes\n\n### Promise Resolution and Chaining is Handled Iteratively\n\nBy shuffling pending handlers from one owner to another, promises are\nresolved iteratively, allowing for \"infinite\" then chaining.\n\n```php\n<?php\nrequire 'vendor/autoload.php';\n\nuse GuzzleHttp\\Promise\\Promise;\n\n$parent = new Promise();\n$p = $parent;\n\nfor ($i = 0; $i < 1000; $i++) {\n    $p = $p->then(function ($v) {\n        // The stack size remains constant (a good thing)\n        echo xdebug_get_stack_depth() . ', ';\n        return $v + 1;\n    });\n}\n\n$parent->resolve(0);\nvar_dump($p->wait()); // int(1000)\n\n```\n\nWhen a promise is fulfilled or rejected with a non-promise value, the promise\nthen takes ownership of the handlers of each child promise and delivers values\ndown the chain without using recursion.\n\nWhen a promise is resolved with another promise, the original promise transfers\nall of its pending handlers to the new promise. When the new promise is\neventually resolved, all of the pending handlers are delivered the forwarded\nvalue.\n\n### A Promise is the Deferred\n\nSome promise libraries implement promises using a deferred object to represent\na computation and a promise object to represent the delivery of the result of\nthe computation. This is a nice separation of computation and delivery because\nconsumers of the promise cannot modify the value that will be eventually\ndelivered.\n\nOne side effect of being able to implement promise resolution and chaining\niteratively is that you need to be able for one promise to reach into the state\nof another promise to shuffle around ownership of handlers. In order to achieve\nthis without making the handlers of a promise publicly mutable, a promise is\nalso the deferred value, allowing promises of the same parent class to reach\ninto and modify the private properties of promises of the same type. While this\ndoes allow consumers of the value to modify the resolution or rejection of the\ndeferred, it is a small price to pay for keeping the stack size constant.\n\n```php\n$promise = new Promise();\n$promise->then(function ($value) { echo $value; });\n// The promise is the deferred value, so you can deliver a value to it.\n$promise->resolve('foo');\n// prints \"foo\"\n```\n\n\n## Upgrading from Function API\n\nA static API was first introduced in 1.4.0, in order to mitigate problems with\nfunctions conflicting between global and local copies of the package. The\nfunction API will be removed in 2.0.0. A migration table has been provided here\nfor your convenience:\n\n| Original Function | Replacement Method |\n|----------------|----------------|\n| `queue` | `Utils::queue` |\n| `task` | `Utils::task` |\n| `promise_for` | `Create::promiseFor` |\n| `rejection_for` | `Create::rejectionFor` |\n| `exception_for` | `Create::exceptionFor` |\n| `iter_for` | `Create::iterFor` |\n| `inspect` | `Utils::inspect` |\n| `inspect_all` | `Utils::inspectAll` |\n| `unwrap` | `Utils::unwrap` |\n| `all` | `Utils::all` |\n| `some` | `Utils::some` |\n| `any` | `Utils::any` |\n| `settle` | `Utils::settle` |\n| `each` | `Each::of` |\n| `each_limit` | `Each::ofLimit` |\n| `each_limit_all` | `Each::ofLimitAll` |\n| `!is_fulfilled` | `Is::pending` |\n| `is_fulfilled` | `Is::fulfilled` |\n| `is_rejected` | `Is::rejected` |\n| `is_settled` | `Is::settled` |\n| `coroutine` | `Coroutine::of` |\n\n\n## Security\n\nIf you discover a security vulnerability within this package, please send an email to security@tidelift.com. All security vulnerabilities will be promptly addressed. Please do not disclose security-related issues publicly until a fix has been announced. Please see [Security Policy](https://github.com/guzzle/promises/security/policy) for more information.\n\n\n## License\n\nGuzzle is made available under the MIT License (MIT). Please see [License File](LICENSE) for more information.\n\n\n## For Enterprise\n\nAvailable as part of the Tidelift Subscription\n\nThe maintainers of Guzzle and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/packagist-guzzlehttp-promises?utm_source=packagist-guzzlehttp-promises&utm_medium=referral&utm_campaign=enterprise&utm_term=repo)\n"
  },
  {
    "path": "server/vendor/guzzlehttp/promises/composer.json",
    "content": "{\n    \"name\": \"guzzlehttp/promises\",\n    \"description\": \"Guzzle promises library\",\n    \"keywords\": [\"promise\"],\n    \"license\": \"MIT\",\n    \"authors\": [\n        {\n            \"name\": \"Graham Campbell\",\n            \"email\": \"hello@gjcampbell.co.uk\",\n            \"homepage\": \"https://github.com/GrahamCampbell\"\n        },\n        {\n            \"name\": \"Michael Dowling\",\n            \"email\": \"mtdowling@gmail.com\",\n            \"homepage\": \"https://github.com/mtdowling\"\n        },\n        {\n            \"name\": \"Tobias Nyholm\",\n            \"email\": \"tobias.nyholm@gmail.com\",\n            \"homepage\": \"https://github.com/Nyholm\"\n        },\n        {\n            \"name\": \"Tobias Schultze\",\n            \"email\": \"webmaster@tubo-world.de\",\n            \"homepage\": \"https://github.com/Tobion\"\n        }\n    ],\n    \"require\": {\n        \"php\": \">=5.5\"\n    },\n    \"require-dev\": {\n        \"symfony/phpunit-bridge\": \"^4.4 || ^5.1\"\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"GuzzleHttp\\\\Promise\\\\\": \"src/\"\n        },\n        \"files\": [\"src/functions_include.php\"]\n    },\n    \"autoload-dev\": {\n        \"psr-4\": {\n            \"GuzzleHttp\\\\Promise\\\\Tests\\\\\": \"tests/\"\n        }\n    },\n    \"scripts\": {\n        \"test\": \"vendor/bin/simple-phpunit\",\n        \"test-ci\": \"vendor/bin/simple-phpunit --coverage-text\"\n    },\n    \"config\": {\n        \"preferred-install\": \"dist\",\n        \"sort-packages\": true\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/promises/src/AggregateException.php",
    "content": "<?php\n\nnamespace GuzzleHttp\\Promise;\n\n/**\n * Exception thrown when too many errors occur in the some() or any() methods.\n */\nclass AggregateException extends RejectionException\n{\n    public function __construct($msg, array $reasons)\n    {\n        parent::__construct(\n            $reasons,\n            sprintf('%s; %d rejected promises', $msg, count($reasons))\n        );\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/promises/src/CancellationException.php",
    "content": "<?php\n\nnamespace GuzzleHttp\\Promise;\n\n/**\n * Exception that is set as the reason for a promise that has been cancelled.\n */\nclass CancellationException extends RejectionException\n{\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/promises/src/Coroutine.php",
    "content": "<?php\n\nnamespace GuzzleHttp\\Promise;\n\nuse Exception;\nuse Generator;\nuse Throwable;\n\n/**\n * Creates a promise that is resolved using a generator that yields values or\n * promises (somewhat similar to C#'s async keyword).\n *\n * When called, the Coroutine::of method will start an instance of the generator\n * and returns a promise that is fulfilled with its final yielded value.\n *\n * Control is returned back to the generator when the yielded promise settles.\n * This can lead to less verbose code when doing lots of sequential async calls\n * with minimal processing in between.\n *\n *     use GuzzleHttp\\Promise;\n *\n *     function createPromise($value) {\n *         return new Promise\\FulfilledPromise($value);\n *     }\n *\n *     $promise = Promise\\Coroutine::of(function () {\n *         $value = (yield createPromise('a'));\n *         try {\n *             $value = (yield createPromise($value . 'b'));\n *         } catch (\\Exception $e) {\n *             // The promise was rejected.\n *         }\n *         yield $value . 'c';\n *     });\n *\n *     // Outputs \"abc\"\n *     $promise->then(function ($v) { echo $v; });\n *\n * @param callable $generatorFn Generator function to wrap into a promise.\n *\n * @return Promise\n *\n * @link https://github.com/petkaantonov/bluebird/blob/master/API.md#generators inspiration\n */\nfinal class Coroutine implements PromiseInterface\n{\n    /**\n     * @var PromiseInterface|null\n     */\n    private $currentPromise;\n\n    /**\n     * @var Generator\n     */\n    private $generator;\n\n    /**\n     * @var Promise\n     */\n    private $result;\n\n    public function __construct(callable $generatorFn)\n    {\n        $this->generator = $generatorFn();\n        $this->result = new Promise(function () {\n            while (isset($this->currentPromise)) {\n                $this->currentPromise->wait();\n            }\n        });\n        try {\n            $this->nextCoroutine($this->generator->current());\n        } catch (\\Exception $exception) {\n            $this->result->reject($exception);\n        } catch (Throwable $throwable) {\n            $this->result->reject($throwable);\n        }\n    }\n\n    /**\n     * Create a new coroutine.\n     *\n     * @return self\n     */\n    public static function of(callable $generatorFn)\n    {\n        return new self($generatorFn);\n    }\n\n    public function then(\n        callable $onFulfilled = null,\n        callable $onRejected = null\n    ) {\n        return $this->result->then($onFulfilled, $onRejected);\n    }\n\n    public function otherwise(callable $onRejected)\n    {\n        return $this->result->otherwise($onRejected);\n    }\n\n    public function wait($unwrap = true)\n    {\n        return $this->result->wait($unwrap);\n    }\n\n    public function getState()\n    {\n        return $this->result->getState();\n    }\n\n    public function resolve($value)\n    {\n        $this->result->resolve($value);\n    }\n\n    public function reject($reason)\n    {\n        $this->result->reject($reason);\n    }\n\n    public function cancel()\n    {\n        $this->currentPromise->cancel();\n        $this->result->cancel();\n    }\n\n    private function nextCoroutine($yielded)\n    {\n        $this->currentPromise = Create::promiseFor($yielded)\n            ->then([$this, '_handleSuccess'], [$this, '_handleFailure']);\n    }\n\n    /**\n     * @internal\n     */\n    public function _handleSuccess($value)\n    {\n        unset($this->currentPromise);\n        try {\n            $next = $this->generator->send($value);\n            if ($this->generator->valid()) {\n                $this->nextCoroutine($next);\n            } else {\n                $this->result->resolve($value);\n            }\n        } catch (Exception $exception) {\n            $this->result->reject($exception);\n        } catch (Throwable $throwable) {\n            $this->result->reject($throwable);\n        }\n    }\n\n    /**\n     * @internal\n     */\n    public function _handleFailure($reason)\n    {\n        unset($this->currentPromise);\n        try {\n            $nextYield = $this->generator->throw(Create::exceptionFor($reason));\n            // The throw was caught, so keep iterating on the coroutine\n            $this->nextCoroutine($nextYield);\n        } catch (Exception $exception) {\n            $this->result->reject($exception);\n        } catch (Throwable $throwable) {\n            $this->result->reject($throwable);\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/promises/src/Create.php",
    "content": "<?php\n\nnamespace GuzzleHttp\\Promise;\n\nfinal class Create\n{\n    /**\n     * Creates a promise for a value if the value is not a promise.\n     *\n     * @param mixed $value Promise or value.\n     *\n     * @return PromiseInterface\n     */\n    public static function promiseFor($value)\n    {\n        if ($value instanceof PromiseInterface) {\n            return $value;\n        }\n\n        // Return a Guzzle promise that shadows the given promise.\n        if (is_object($value) && method_exists($value, 'then')) {\n            $wfn = method_exists($value, 'wait') ? [$value, 'wait'] : null;\n            $cfn = method_exists($value, 'cancel') ? [$value, 'cancel'] : null;\n            $promise = new Promise($wfn, $cfn);\n            $value->then([$promise, 'resolve'], [$promise, 'reject']);\n            return $promise;\n        }\n\n        return new FulfilledPromise($value);\n    }\n\n    /**\n     * Creates a rejected promise for a reason if the reason is not a promise.\n     * If the provided reason is a promise, then it is returned as-is.\n     *\n     * @param mixed $reason Promise or reason.\n     *\n     * @return PromiseInterface\n     */\n    public static function rejectionFor($reason)\n    {\n        if ($reason instanceof PromiseInterface) {\n            return $reason;\n        }\n\n        return new RejectedPromise($reason);\n    }\n\n    /**\n     * Create an exception for a rejected promise value.\n     *\n     * @param mixed $reason\n     *\n     * @return \\Exception|\\Throwable\n     */\n    public static function exceptionFor($reason)\n    {\n        if ($reason instanceof \\Exception || $reason instanceof \\Throwable) {\n            return $reason;\n        }\n\n        return new RejectionException($reason);\n    }\n\n    /**\n     * Returns an iterator for the given value.\n     *\n     * @param mixed $value\n     *\n     * @return \\Iterator\n     */\n    public static function iterFor($value)\n    {\n        if ($value instanceof \\Iterator) {\n            return $value;\n        }\n\n        if (is_array($value)) {\n            return new \\ArrayIterator($value);\n        }\n\n        return new \\ArrayIterator([$value]);\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/promises/src/Each.php",
    "content": "<?php\n\nnamespace GuzzleHttp\\Promise;\n\nfinal class Each\n{\n    /**\n     * Given an iterator that yields promises or values, returns a promise that\n     * is fulfilled with a null value when the iterator has been consumed or\n     * the aggregate promise has been fulfilled or rejected.\n     *\n     * $onFulfilled is a function that accepts the fulfilled value, iterator\n     * index, and the aggregate promise. The callback can invoke any necessary\n     * side effects and choose to resolve or reject the aggregate if needed.\n     *\n     * $onRejected is a function that accepts the rejection reason, iterator\n     * index, and the aggregate promise. The callback can invoke any necessary\n     * side effects and choose to resolve or reject the aggregate if needed.\n     *\n     * @param mixed    $iterable    Iterator or array to iterate over.\n     * @param callable $onFulfilled\n     * @param callable $onRejected\n     *\n     * @return PromiseInterface\n     */\n    public static function of(\n        $iterable,\n        callable $onFulfilled = null,\n        callable $onRejected = null\n    ) {\n        return (new EachPromise($iterable, [\n            'fulfilled' => $onFulfilled,\n            'rejected'  => $onRejected\n        ]))->promise();\n    }\n\n    /**\n     * Like of, but only allows a certain number of outstanding promises at any\n     * given time.\n     *\n     * $concurrency may be an integer or a function that accepts the number of\n     * pending promises and returns a numeric concurrency limit value to allow\n     * for dynamic a concurrency size.\n     *\n     * @param mixed        $iterable\n     * @param int|callable $concurrency\n     * @param callable     $onFulfilled\n     * @param callable     $onRejected\n     *\n     * @return PromiseInterface\n     */\n    public static function ofLimit(\n        $iterable,\n        $concurrency,\n        callable $onFulfilled = null,\n        callable $onRejected = null\n    ) {\n        return (new EachPromise($iterable, [\n            'fulfilled'   => $onFulfilled,\n            'rejected'    => $onRejected,\n            'concurrency' => $concurrency\n        ]))->promise();\n    }\n\n    /**\n     * Like limit, but ensures that no promise in the given $iterable argument\n     * is rejected. If any promise is rejected, then the aggregate promise is\n     * rejected with the encountered rejection.\n     *\n     * @param mixed        $iterable\n     * @param int|callable $concurrency\n     * @param callable     $onFulfilled\n     *\n     * @return PromiseInterface\n     */\n    public static function ofLimitAll(\n        $iterable,\n        $concurrency,\n        callable $onFulfilled = null\n    ) {\n        return self::ofLimit(\n            $iterable,\n            $concurrency,\n            $onFulfilled,\n            function ($reason, $idx, PromiseInterface $aggregate) {\n                $aggregate->reject($reason);\n            }\n        );\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/promises/src/EachPromise.php",
    "content": "<?php\n\nnamespace GuzzleHttp\\Promise;\n\n/**\n * Represents a promise that iterates over many promises and invokes\n * side-effect functions in the process.\n */\nclass EachPromise implements PromisorInterface\n{\n    private $pending = [];\n\n    private $nextPendingIndex = 0;\n\n    /** @var \\Iterator|null */\n    private $iterable;\n\n    /** @var callable|int|null */\n    private $concurrency;\n\n    /** @var callable|null */\n    private $onFulfilled;\n\n    /** @var callable|null */\n    private $onRejected;\n\n    /** @var Promise|null */\n    private $aggregate;\n\n    /** @var bool|null */\n    private $mutex;\n\n    /**\n     * Configuration hash can include the following key value pairs:\n     *\n     * - fulfilled: (callable) Invoked when a promise fulfills. The function\n     *   is invoked with three arguments: the fulfillment value, the index\n     *   position from the iterable list of the promise, and the aggregate\n     *   promise that manages all of the promises. The aggregate promise may\n     *   be resolved from within the callback to short-circuit the promise.\n     * - rejected: (callable) Invoked when a promise is rejected. The\n     *   function is invoked with three arguments: the rejection reason, the\n     *   index position from the iterable list of the promise, and the\n     *   aggregate promise that manages all of the promises. The aggregate\n     *   promise may be resolved from within the callback to short-circuit\n     *   the promise.\n     * - concurrency: (integer) Pass this configuration option to limit the\n     *   allowed number of outstanding concurrently executing promises,\n     *   creating a capped pool of promises. There is no limit by default.\n     *\n     * @param mixed $iterable Promises or values to iterate.\n     * @param array $config   Configuration options\n     */\n    public function __construct($iterable, array $config = [])\n    {\n        $this->iterable = Create::iterFor($iterable);\n\n        if (isset($config['concurrency'])) {\n            $this->concurrency = $config['concurrency'];\n        }\n\n        if (isset($config['fulfilled'])) {\n            $this->onFulfilled = $config['fulfilled'];\n        }\n\n        if (isset($config['rejected'])) {\n            $this->onRejected = $config['rejected'];\n        }\n    }\n\n    /** @psalm-suppress InvalidNullableReturnType */\n    public function promise()\n    {\n        if ($this->aggregate) {\n            return $this->aggregate;\n        }\n\n        try {\n            $this->createPromise();\n            /** @psalm-assert Promise $this->aggregate */\n            $this->iterable->rewind();\n            $this->refillPending();\n        } catch (\\Throwable $e) {\n            $this->aggregate->reject($e);\n        } catch (\\Exception $e) {\n            $this->aggregate->reject($e);\n        }\n\n        /**\n         * @psalm-suppress NullableReturnStatement\n         * @phpstan-ignore-next-line\n         */\n        return $this->aggregate;\n    }\n\n    private function createPromise()\n    {\n        $this->mutex = false;\n        $this->aggregate = new Promise(function () {\n            if ($this->checkIfFinished()) {\n                return;\n            }\n            reset($this->pending);\n            // Consume a potentially fluctuating list of promises while\n            // ensuring that indexes are maintained (precluding array_shift).\n            while ($promise = current($this->pending)) {\n                next($this->pending);\n                $promise->wait();\n                if (Is::settled($this->aggregate)) {\n                    return;\n                }\n            }\n        });\n\n        // Clear the references when the promise is resolved.\n        $clearFn = function () {\n            $this->iterable = $this->concurrency = $this->pending = null;\n            $this->onFulfilled = $this->onRejected = null;\n            $this->nextPendingIndex = 0;\n        };\n\n        $this->aggregate->then($clearFn, $clearFn);\n    }\n\n    private function refillPending()\n    {\n        if (!$this->concurrency) {\n            // Add all pending promises.\n            while ($this->addPending() && $this->advanceIterator());\n            return;\n        }\n\n        // Add only up to N pending promises.\n        $concurrency = is_callable($this->concurrency)\n            ? call_user_func($this->concurrency, count($this->pending))\n            : $this->concurrency;\n        $concurrency = max($concurrency - count($this->pending), 0);\n        // Concurrency may be set to 0 to disallow new promises.\n        if (!$concurrency) {\n            return;\n        }\n        // Add the first pending promise.\n        $this->addPending();\n        // Note this is special handling for concurrency=1 so that we do\n        // not advance the iterator after adding the first promise. This\n        // helps work around issues with generators that might not have the\n        // next value to yield until promise callbacks are called.\n        while (--$concurrency\n            && $this->advanceIterator()\n            && $this->addPending());\n    }\n\n    private function addPending()\n    {\n        if (!$this->iterable || !$this->iterable->valid()) {\n            return false;\n        }\n\n        $promise = Create::promiseFor($this->iterable->current());\n        $key = $this->iterable->key();\n\n        // Iterable keys may not be unique, so we use a counter to\n        // guarantee uniqueness\n        $idx = $this->nextPendingIndex++;\n\n        $this->pending[$idx] = $promise->then(\n            function ($value) use ($idx, $key) {\n                if ($this->onFulfilled) {\n                    call_user_func(\n                        $this->onFulfilled,\n                        $value,\n                        $key,\n                        $this->aggregate\n                    );\n                }\n                $this->step($idx);\n            },\n            function ($reason) use ($idx, $key) {\n                if ($this->onRejected) {\n                    call_user_func(\n                        $this->onRejected,\n                        $reason,\n                        $key,\n                        $this->aggregate\n                    );\n                }\n                $this->step($idx);\n            }\n        );\n\n        return true;\n    }\n\n    private function advanceIterator()\n    {\n        // Place a lock on the iterator so that we ensure to not recurse,\n        // preventing fatal generator errors.\n        if ($this->mutex) {\n            return false;\n        }\n\n        $this->mutex = true;\n\n        try {\n            $this->iterable->next();\n            $this->mutex = false;\n            return true;\n        } catch (\\Throwable $e) {\n            $this->aggregate->reject($e);\n            $this->mutex = false;\n            return false;\n        } catch (\\Exception $e) {\n            $this->aggregate->reject($e);\n            $this->mutex = false;\n            return false;\n        }\n    }\n\n    private function step($idx)\n    {\n        // If the promise was already resolved, then ignore this step.\n        if (Is::settled($this->aggregate)) {\n            return;\n        }\n\n        unset($this->pending[$idx]);\n\n        // Only refill pending promises if we are not locked, preventing the\n        // EachPromise to recursively invoke the provided iterator, which\n        // cause a fatal error: \"Cannot resume an already running generator\"\n        if ($this->advanceIterator() && !$this->checkIfFinished()) {\n            // Add more pending promises if possible.\n            $this->refillPending();\n        }\n    }\n\n    private function checkIfFinished()\n    {\n        if (!$this->pending && !$this->iterable->valid()) {\n            // Resolve the promise if there's nothing left to do.\n            $this->aggregate->resolve(null);\n            return true;\n        }\n\n        return false;\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/promises/src/FulfilledPromise.php",
    "content": "<?php\n\nnamespace GuzzleHttp\\Promise;\n\n/**\n * A promise that has been fulfilled.\n *\n * Thenning off of this promise will invoke the onFulfilled callback\n * immediately and ignore other callbacks.\n */\nclass FulfilledPromise implements PromiseInterface\n{\n    private $value;\n\n    public function __construct($value)\n    {\n        if (is_object($value) && method_exists($value, 'then')) {\n            throw new \\InvalidArgumentException(\n                'You cannot create a FulfilledPromise with a promise.'\n            );\n        }\n\n        $this->value = $value;\n    }\n\n    public function then(\n        callable $onFulfilled = null,\n        callable $onRejected = null\n    ) {\n        // Return itself if there is no onFulfilled function.\n        if (!$onFulfilled) {\n            return $this;\n        }\n\n        $queue = Utils::queue();\n        $p = new Promise([$queue, 'run']);\n        $value = $this->value;\n        $queue->add(static function () use ($p, $value, $onFulfilled) {\n            if (Is::pending($p)) {\n                try {\n                    $p->resolve($onFulfilled($value));\n                } catch (\\Throwable $e) {\n                    $p->reject($e);\n                } catch (\\Exception $e) {\n                    $p->reject($e);\n                }\n            }\n        });\n\n        return $p;\n    }\n\n    public function otherwise(callable $onRejected)\n    {\n        return $this->then(null, $onRejected);\n    }\n\n    public function wait($unwrap = true, $defaultDelivery = null)\n    {\n        return $unwrap ? $this->value : null;\n    }\n\n    public function getState()\n    {\n        return self::FULFILLED;\n    }\n\n    public function resolve($value)\n    {\n        if ($value !== $this->value) {\n            throw new \\LogicException(\"Cannot resolve a fulfilled promise\");\n        }\n    }\n\n    public function reject($reason)\n    {\n        throw new \\LogicException(\"Cannot reject a fulfilled promise\");\n    }\n\n    public function cancel()\n    {\n        // pass\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/promises/src/Is.php",
    "content": "<?php\n\nnamespace GuzzleHttp\\Promise;\n\nfinal class Is\n{\n    /**\n     * Returns true if a promise is pending.\n     *\n     * @return bool\n     */\n    public static function pending(PromiseInterface $promise)\n    {\n        return $promise->getState() === PromiseInterface::PENDING;\n    }\n\n    /**\n     * Returns true if a promise is fulfilled or rejected.\n     *\n     * @return bool\n     */\n    public static function settled(PromiseInterface $promise)\n    {\n        return $promise->getState() !== PromiseInterface::PENDING;\n    }\n\n    /**\n     * Returns true if a promise is fulfilled.\n     *\n     * @return bool\n     */\n    public static function fulfilled(PromiseInterface $promise)\n    {\n        return $promise->getState() === PromiseInterface::FULFILLED;\n    }\n\n    /**\n     * Returns true if a promise is rejected.\n     *\n     * @return bool\n     */\n    public static function rejected(PromiseInterface $promise)\n    {\n        return $promise->getState() === PromiseInterface::REJECTED;\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/promises/src/Promise.php",
    "content": "<?php\n\nnamespace GuzzleHttp\\Promise;\n\n/**\n * Promises/A+ implementation that avoids recursion when possible.\n *\n * @link https://promisesaplus.com/\n */\nclass Promise implements PromiseInterface\n{\n    private $state = self::PENDING;\n    private $result;\n    private $cancelFn;\n    private $waitFn;\n    private $waitList;\n    private $handlers = [];\n\n    /**\n     * @param callable $waitFn   Fn that when invoked resolves the promise.\n     * @param callable $cancelFn Fn that when invoked cancels the promise.\n     */\n    public function __construct(\n        callable $waitFn = null,\n        callable $cancelFn = null\n    ) {\n        $this->waitFn = $waitFn;\n        $this->cancelFn = $cancelFn;\n    }\n\n    public function then(\n        callable $onFulfilled = null,\n        callable $onRejected = null\n    ) {\n        if ($this->state === self::PENDING) {\n            $p = new Promise(null, [$this, 'cancel']);\n            $this->handlers[] = [$p, $onFulfilled, $onRejected];\n            $p->waitList = $this->waitList;\n            $p->waitList[] = $this;\n            return $p;\n        }\n\n        // Return a fulfilled promise and immediately invoke any callbacks.\n        if ($this->state === self::FULFILLED) {\n            $promise = Create::promiseFor($this->result);\n            return $onFulfilled ? $promise->then($onFulfilled) : $promise;\n        }\n\n        // It's either cancelled or rejected, so return a rejected promise\n        // and immediately invoke any callbacks.\n        $rejection = Create::rejectionFor($this->result);\n        return $onRejected ? $rejection->then(null, $onRejected) : $rejection;\n    }\n\n    public function otherwise(callable $onRejected)\n    {\n        return $this->then(null, $onRejected);\n    }\n\n    public function wait($unwrap = true)\n    {\n        $this->waitIfPending();\n\n        if ($this->result instanceof PromiseInterface) {\n            return $this->result->wait($unwrap);\n        }\n        if ($unwrap) {\n            if ($this->state === self::FULFILLED) {\n                return $this->result;\n            }\n            // It's rejected so \"unwrap\" and throw an exception.\n            throw Create::exceptionFor($this->result);\n        }\n    }\n\n    public function getState()\n    {\n        return $this->state;\n    }\n\n    public function cancel()\n    {\n        if ($this->state !== self::PENDING) {\n            return;\n        }\n\n        $this->waitFn = $this->waitList = null;\n\n        if ($this->cancelFn) {\n            $fn = $this->cancelFn;\n            $this->cancelFn = null;\n            try {\n                $fn();\n            } catch (\\Throwable $e) {\n                $this->reject($e);\n            } catch (\\Exception $e) {\n                $this->reject($e);\n            }\n        }\n\n        // Reject the promise only if it wasn't rejected in a then callback.\n        /** @psalm-suppress RedundantCondition */\n        if ($this->state === self::PENDING) {\n            $this->reject(new CancellationException('Promise has been cancelled'));\n        }\n    }\n\n    public function resolve($value)\n    {\n        $this->settle(self::FULFILLED, $value);\n    }\n\n    public function reject($reason)\n    {\n        $this->settle(self::REJECTED, $reason);\n    }\n\n    private function settle($state, $value)\n    {\n        if ($this->state !== self::PENDING) {\n            // Ignore calls with the same resolution.\n            if ($state === $this->state && $value === $this->result) {\n                return;\n            }\n            throw $this->state === $state\n                ? new \\LogicException(\"The promise is already {$state}.\")\n                : new \\LogicException(\"Cannot change a {$this->state} promise to {$state}\");\n        }\n\n        if ($value === $this) {\n            throw new \\LogicException('Cannot fulfill or reject a promise with itself');\n        }\n\n        // Clear out the state of the promise but stash the handlers.\n        $this->state = $state;\n        $this->result = $value;\n        $handlers = $this->handlers;\n        $this->handlers = null;\n        $this->waitList = $this->waitFn = null;\n        $this->cancelFn = null;\n\n        if (!$handlers) {\n            return;\n        }\n\n        // If the value was not a settled promise or a thenable, then resolve\n        // it in the task queue using the correct ID.\n        if (!is_object($value) || !method_exists($value, 'then')) {\n            $id = $state === self::FULFILLED ? 1 : 2;\n            // It's a success, so resolve the handlers in the queue.\n            Utils::queue()->add(static function () use ($id, $value, $handlers) {\n                foreach ($handlers as $handler) {\n                    self::callHandler($id, $value, $handler);\n                }\n            });\n        } elseif ($value instanceof Promise && Is::pending($value)) {\n            // We can just merge our handlers onto the next promise.\n            $value->handlers = array_merge($value->handlers, $handlers);\n        } else {\n            // Resolve the handlers when the forwarded promise is resolved.\n            $value->then(\n                static function ($value) use ($handlers) {\n                    foreach ($handlers as $handler) {\n                        self::callHandler(1, $value, $handler);\n                    }\n                },\n                static function ($reason) use ($handlers) {\n                    foreach ($handlers as $handler) {\n                        self::callHandler(2, $reason, $handler);\n                    }\n                }\n            );\n        }\n    }\n\n    /**\n     * Call a stack of handlers using a specific callback index and value.\n     *\n     * @param int   $index   1 (resolve) or 2 (reject).\n     * @param mixed $value   Value to pass to the callback.\n     * @param array $handler Array of handler data (promise and callbacks).\n     */\n    private static function callHandler($index, $value, array $handler)\n    {\n        /** @var PromiseInterface $promise */\n        $promise = $handler[0];\n\n        // The promise may have been cancelled or resolved before placing\n        // this thunk in the queue.\n        if (Is::settled($promise)) {\n            return;\n        }\n\n        try {\n            if (isset($handler[$index])) {\n                /*\n                 * If $f throws an exception, then $handler will be in the exception\n                 * stack trace. Since $handler contains a reference to the callable\n                 * itself we get a circular reference. We clear the $handler\n                 * here to avoid that memory leak.\n                 */\n                $f = $handler[$index];\n                unset($handler);\n                $promise->resolve($f($value));\n            } elseif ($index === 1) {\n                // Forward resolution values as-is.\n                $promise->resolve($value);\n            } else {\n                // Forward rejections down the chain.\n                $promise->reject($value);\n            }\n        } catch (\\Throwable $reason) {\n            $promise->reject($reason);\n        } catch (\\Exception $reason) {\n            $promise->reject($reason);\n        }\n    }\n\n    private function waitIfPending()\n    {\n        if ($this->state !== self::PENDING) {\n            return;\n        } elseif ($this->waitFn) {\n            $this->invokeWaitFn();\n        } elseif ($this->waitList) {\n            $this->invokeWaitList();\n        } else {\n            // If there's no wait function, then reject the promise.\n            $this->reject('Cannot wait on a promise that has '\n                . 'no internal wait function. You must provide a wait '\n                . 'function when constructing the promise to be able to '\n                . 'wait on a promise.');\n        }\n\n        Utils::queue()->run();\n\n        /** @psalm-suppress RedundantCondition */\n        if ($this->state === self::PENDING) {\n            $this->reject('Invoking the wait callback did not resolve the promise');\n        }\n    }\n\n    private function invokeWaitFn()\n    {\n        try {\n            $wfn = $this->waitFn;\n            $this->waitFn = null;\n            $wfn(true);\n        } catch (\\Exception $reason) {\n            if ($this->state === self::PENDING) {\n                // The promise has not been resolved yet, so reject the promise\n                // with the exception.\n                $this->reject($reason);\n            } else {\n                // The promise was already resolved, so there's a problem in\n                // the application.\n                throw $reason;\n            }\n        }\n    }\n\n    private function invokeWaitList()\n    {\n        $waitList = $this->waitList;\n        $this->waitList = null;\n\n        foreach ($waitList as $result) {\n            do {\n                $result->waitIfPending();\n                $result = $result->result;\n            } while ($result instanceof Promise);\n\n            if ($result instanceof PromiseInterface) {\n                $result->wait(false);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/promises/src/PromiseInterface.php",
    "content": "<?php\n\nnamespace GuzzleHttp\\Promise;\n\n/**\n * A promise represents the eventual result of an asynchronous operation.\n *\n * The primary way of interacting with a promise is through its then method,\n * which registers callbacks to receive either a promise’s eventual value or\n * the reason why the promise cannot be fulfilled.\n *\n * @link https://promisesaplus.com/\n */\ninterface PromiseInterface\n{\n    const PENDING = 'pending';\n    const FULFILLED = 'fulfilled';\n    const REJECTED = 'rejected';\n\n    /**\n     * Appends fulfillment and rejection handlers to the promise, and returns\n     * a new promise resolving to the return value of the called handler.\n     *\n     * @param callable $onFulfilled Invoked when the promise fulfills.\n     * @param callable $onRejected  Invoked when the promise is rejected.\n     *\n     * @return PromiseInterface\n     */\n    public function then(\n        callable $onFulfilled = null,\n        callable $onRejected = null\n    );\n\n    /**\n     * Appends a rejection handler callback to the promise, and returns a new\n     * promise resolving to the return value of the callback if it is called,\n     * or to its original fulfillment value if the promise is instead\n     * fulfilled.\n     *\n     * @param callable $onRejected Invoked when the promise is rejected.\n     *\n     * @return PromiseInterface\n     */\n    public function otherwise(callable $onRejected);\n\n    /**\n     * Get the state of the promise (\"pending\", \"rejected\", or \"fulfilled\").\n     *\n     * The three states can be checked against the constants defined on\n     * PromiseInterface: PENDING, FULFILLED, and REJECTED.\n     *\n     * @return string\n     */\n    public function getState();\n\n    /**\n     * Resolve the promise with the given value.\n     *\n     * @param mixed $value\n     *\n     * @throws \\RuntimeException if the promise is already resolved.\n     */\n    public function resolve($value);\n\n    /**\n     * Reject the promise with the given reason.\n     *\n     * @param mixed $reason\n     *\n     * @throws \\RuntimeException if the promise is already resolved.\n     */\n    public function reject($reason);\n\n    /**\n     * Cancels the promise if possible.\n     *\n     * @link https://github.com/promises-aplus/cancellation-spec/issues/7\n     */\n    public function cancel();\n\n    /**\n     * Waits until the promise completes if possible.\n     *\n     * Pass $unwrap as true to unwrap the result of the promise, either\n     * returning the resolved value or throwing the rejected exception.\n     *\n     * If the promise cannot be waited on, then the promise will be rejected.\n     *\n     * @param bool $unwrap\n     *\n     * @return mixed\n     *\n     * @throws \\LogicException if the promise has no wait function or if the\n     *                         promise does not settle after waiting.\n     */\n    public function wait($unwrap = true);\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/promises/src/PromisorInterface.php",
    "content": "<?php\n\nnamespace GuzzleHttp\\Promise;\n\n/**\n * Interface used with classes that return a promise.\n */\ninterface PromisorInterface\n{\n    /**\n     * Returns a promise.\n     *\n     * @return PromiseInterface\n     */\n    public function promise();\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/promises/src/RejectedPromise.php",
    "content": "<?php\n\nnamespace GuzzleHttp\\Promise;\n\n/**\n * A promise that has been rejected.\n *\n * Thenning off of this promise will invoke the onRejected callback\n * immediately and ignore other callbacks.\n */\nclass RejectedPromise implements PromiseInterface\n{\n    private $reason;\n\n    public function __construct($reason)\n    {\n        if (is_object($reason) && method_exists($reason, 'then')) {\n            throw new \\InvalidArgumentException(\n                'You cannot create a RejectedPromise with a promise.'\n            );\n        }\n\n        $this->reason = $reason;\n    }\n\n    public function then(\n        callable $onFulfilled = null,\n        callable $onRejected = null\n    ) {\n        // If there's no onRejected callback then just return self.\n        if (!$onRejected) {\n            return $this;\n        }\n\n        $queue = Utils::queue();\n        $reason = $this->reason;\n        $p = new Promise([$queue, 'run']);\n        $queue->add(static function () use ($p, $reason, $onRejected) {\n            if (Is::pending($p)) {\n                try {\n                    // Return a resolved promise if onRejected does not throw.\n                    $p->resolve($onRejected($reason));\n                } catch (\\Throwable $e) {\n                    // onRejected threw, so return a rejected promise.\n                    $p->reject($e);\n                } catch (\\Exception $e) {\n                    // onRejected threw, so return a rejected promise.\n                    $p->reject($e);\n                }\n            }\n        });\n\n        return $p;\n    }\n\n    public function otherwise(callable $onRejected)\n    {\n        return $this->then(null, $onRejected);\n    }\n\n    public function wait($unwrap = true, $defaultDelivery = null)\n    {\n        if ($unwrap) {\n            throw Create::exceptionFor($this->reason);\n        }\n\n        return null;\n    }\n\n    public function getState()\n    {\n        return self::REJECTED;\n    }\n\n    public function resolve($value)\n    {\n        throw new \\LogicException(\"Cannot resolve a rejected promise\");\n    }\n\n    public function reject($reason)\n    {\n        if ($reason !== $this->reason) {\n            throw new \\LogicException(\"Cannot reject a rejected promise\");\n        }\n    }\n\n    public function cancel()\n    {\n        // pass\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/promises/src/RejectionException.php",
    "content": "<?php\n\nnamespace GuzzleHttp\\Promise;\n\n/**\n * A special exception that is thrown when waiting on a rejected promise.\n *\n * The reason value is available via the getReason() method.\n */\nclass RejectionException extends \\RuntimeException\n{\n    /** @var mixed Rejection reason. */\n    private $reason;\n\n    /**\n     * @param mixed  $reason      Rejection reason.\n     * @param string $description Optional description\n     */\n    public function __construct($reason, $description = null)\n    {\n        $this->reason = $reason;\n\n        $message = 'The promise was rejected';\n\n        if ($description) {\n            $message .= ' with reason: ' . $description;\n        } elseif (is_string($reason)\n            || (is_object($reason) && method_exists($reason, '__toString'))\n        ) {\n            $message .= ' with reason: ' . $this->reason;\n        } elseif ($reason instanceof \\JsonSerializable) {\n            $message .= ' with reason: '\n                . json_encode($this->reason, JSON_PRETTY_PRINT);\n        }\n\n        parent::__construct($message);\n    }\n\n    /**\n     * Returns the rejection reason.\n     *\n     * @return mixed\n     */\n    public function getReason()\n    {\n        return $this->reason;\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/promises/src/TaskQueue.php",
    "content": "<?php\n\nnamespace GuzzleHttp\\Promise;\n\n/**\n * A task queue that executes tasks in a FIFO order.\n *\n * This task queue class is used to settle promises asynchronously and\n * maintains a constant stack size. You can use the task queue asynchronously\n * by calling the `run()` function of the global task queue in an event loop.\n *\n *     GuzzleHttp\\Promise\\Utils::queue()->run();\n */\nclass TaskQueue implements TaskQueueInterface\n{\n    private $enableShutdown = true;\n    private $queue = [];\n\n    public function __construct($withShutdown = true)\n    {\n        if ($withShutdown) {\n            register_shutdown_function(function () {\n                if ($this->enableShutdown) {\n                    // Only run the tasks if an E_ERROR didn't occur.\n                    $err = error_get_last();\n                    if (!$err || ($err['type'] ^ E_ERROR)) {\n                        $this->run();\n                    }\n                }\n            });\n        }\n    }\n\n    public function isEmpty()\n    {\n        return !$this->queue;\n    }\n\n    public function add(callable $task)\n    {\n        $this->queue[] = $task;\n    }\n\n    public function run()\n    {\n        while ($task = array_shift($this->queue)) {\n            /** @var callable $task */\n            $task();\n        }\n    }\n\n    /**\n     * The task queue will be run and exhausted by default when the process\n     * exits IFF the exit is not the result of a PHP E_ERROR error.\n     *\n     * You can disable running the automatic shutdown of the queue by calling\n     * this function. If you disable the task queue shutdown process, then you\n     * MUST either run the task queue (as a result of running your event loop\n     * or manually using the run() method) or wait on each outstanding promise.\n     *\n     * Note: This shutdown will occur before any destructors are triggered.\n     */\n    public function disableShutdown()\n    {\n        $this->enableShutdown = false;\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/promises/src/TaskQueueInterface.php",
    "content": "<?php\n\nnamespace GuzzleHttp\\Promise;\n\ninterface TaskQueueInterface\n{\n    /**\n     * Returns true if the queue is empty.\n     *\n     * @return bool\n     */\n    public function isEmpty();\n\n    /**\n     * Adds a task to the queue that will be executed the next time run is\n     * called.\n     */\n    public function add(callable $task);\n\n    /**\n     * Execute all of the pending task in the queue.\n     */\n    public function run();\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/promises/src/Utils.php",
    "content": "<?php\n\nnamespace GuzzleHttp\\Promise;\n\nfinal class Utils\n{\n    /**\n     * Get the global task queue used for promise resolution.\n     *\n     * This task queue MUST be run in an event loop in order for promises to be\n     * settled asynchronously. It will be automatically run when synchronously\n     * waiting on a promise.\n     *\n     * <code>\n     * while ($eventLoop->isRunning()) {\n     *     GuzzleHttp\\Promise\\Utils::queue()->run();\n     * }\n     * </code>\n     *\n     * @param TaskQueueInterface $assign Optionally specify a new queue instance.\n     *\n     * @return TaskQueueInterface\n     */\n    public static function queue(TaskQueueInterface $assign = null)\n    {\n        static $queue;\n\n        if ($assign) {\n            $queue = $assign;\n        } elseif (!$queue) {\n            $queue = new TaskQueue();\n        }\n\n        return $queue;\n    }\n\n    /**\n     * Adds a function to run in the task queue when it is next `run()` and\n     * returns a promise that is fulfilled or rejected with the result.\n     *\n     * @param callable $task Task function to run.\n     *\n     * @return PromiseInterface\n     */\n    public static function task(callable $task)\n    {\n        $queue = self::queue();\n        $promise = new Promise([$queue, 'run']);\n        $queue->add(function () use ($task, $promise) {\n            try {\n                if (Is::pending($promise)) {\n                    $promise->resolve($task());\n                }\n            } catch (\\Throwable $e) {\n                $promise->reject($e);\n            } catch (\\Exception $e) {\n                $promise->reject($e);\n            }\n        });\n\n        return $promise;\n    }\n\n    /**\n     * Synchronously waits on a promise to resolve and returns an inspection\n     * state array.\n     *\n     * Returns a state associative array containing a \"state\" key mapping to a\n     * valid promise state. If the state of the promise is \"fulfilled\", the\n     * array will contain a \"value\" key mapping to the fulfilled value of the\n     * promise. If the promise is rejected, the array will contain a \"reason\"\n     * key mapping to the rejection reason of the promise.\n     *\n     * @param PromiseInterface $promise Promise or value.\n     *\n     * @return array\n     */\n    public static function inspect(PromiseInterface $promise)\n    {\n        try {\n            return [\n                'state' => PromiseInterface::FULFILLED,\n                'value' => $promise->wait()\n            ];\n        } catch (RejectionException $e) {\n            return ['state' => PromiseInterface::REJECTED, 'reason' => $e->getReason()];\n        } catch (\\Throwable $e) {\n            return ['state' => PromiseInterface::REJECTED, 'reason' => $e];\n        } catch (\\Exception $e) {\n            return ['state' => PromiseInterface::REJECTED, 'reason' => $e];\n        }\n    }\n\n    /**\n     * Waits on all of the provided promises, but does not unwrap rejected\n     * promises as thrown exception.\n     *\n     * Returns an array of inspection state arrays.\n     *\n     * @see inspect for the inspection state array format.\n     *\n     * @param PromiseInterface[] $promises Traversable of promises to wait upon.\n     *\n     * @return array\n     */\n    public static function inspectAll($promises)\n    {\n        $results = [];\n        foreach ($promises as $key => $promise) {\n            $results[$key] = self::inspect($promise);\n        }\n\n        return $results;\n    }\n\n    /**\n     * Waits on all of the provided promises and returns the fulfilled values.\n     *\n     * Returns an array that contains the value of each promise (in the same\n     * order the promises were provided). An exception is thrown if any of the\n     * promises are rejected.\n     *\n     * @param iterable<PromiseInterface> $promises Iterable of PromiseInterface objects to wait on.\n     *\n     * @return array\n     *\n     * @throws \\Exception on error\n     * @throws \\Throwable on error in PHP >=7\n     */\n    public static function unwrap($promises)\n    {\n        $results = [];\n        foreach ($promises as $key => $promise) {\n            $results[$key] = $promise->wait();\n        }\n\n        return $results;\n    }\n\n    /**\n     * Given an array of promises, return a promise that is fulfilled when all\n     * the items in the array are fulfilled.\n     *\n     * The promise's fulfillment value is an array with fulfillment values at\n     * respective positions to the original array. If any promise in the array\n     * rejects, the returned promise is rejected with the rejection reason.\n     *\n     * @param mixed $promises  Promises or values.\n     * @param bool  $recursive If true, resolves new promises that might have been added to the stack during its own resolution.\n     *\n     * @return PromiseInterface\n     */\n    public static function all($promises, $recursive = false)\n    {\n        $results = [];\n        $promise = Each::of(\n            $promises,\n            function ($value, $idx) use (&$results) {\n                $results[$idx] = $value;\n            },\n            function ($reason, $idx, Promise $aggregate) {\n                $aggregate->reject($reason);\n            }\n        )->then(function () use (&$results) {\n            ksort($results);\n            return $results;\n        });\n\n        if (true === $recursive) {\n            $promise = $promise->then(function ($results) use ($recursive, &$promises) {\n                foreach ($promises as $promise) {\n                    if (Is::pending($promise)) {\n                        return self::all($promises, $recursive);\n                    }\n                }\n                return $results;\n            });\n        }\n\n        return $promise;\n    }\n\n    /**\n     * Initiate a competitive race between multiple promises or values (values\n     * will become immediately fulfilled promises).\n     *\n     * When count amount of promises have been fulfilled, the returned promise\n     * is fulfilled with an array that contains the fulfillment values of the\n     * winners in order of resolution.\n     *\n     * This promise is rejected with a {@see AggregateException} if the number\n     * of fulfilled promises is less than the desired $count.\n     *\n     * @param int   $count    Total number of promises.\n     * @param mixed $promises Promises or values.\n     *\n     * @return PromiseInterface\n     */\n    public static function some($count, $promises)\n    {\n        $results = [];\n        $rejections = [];\n\n        return Each::of(\n            $promises,\n            function ($value, $idx, PromiseInterface $p) use (&$results, $count) {\n                if (Is::settled($p)) {\n                    return;\n                }\n                $results[$idx] = $value;\n                if (count($results) >= $count) {\n                    $p->resolve(null);\n                }\n            },\n            function ($reason) use (&$rejections) {\n                $rejections[] = $reason;\n            }\n        )->then(\n            function () use (&$results, &$rejections, $count) {\n                if (count($results) !== $count) {\n                    throw new AggregateException(\n                        'Not enough promises to fulfill count',\n                        $rejections\n                    );\n                }\n                ksort($results);\n                return array_values($results);\n            }\n        );\n    }\n\n    /**\n     * Like some(), with 1 as count. However, if the promise fulfills, the\n     * fulfillment value is not an array of 1 but the value directly.\n     *\n     * @param mixed $promises Promises or values.\n     *\n     * @return PromiseInterface\n     */\n    public static function any($promises)\n    {\n        return self::some(1, $promises)->then(function ($values) {\n            return $values[0];\n        });\n    }\n\n    /**\n     * Returns a promise that is fulfilled when all of the provided promises have\n     * been fulfilled or rejected.\n     *\n     * The returned promise is fulfilled with an array of inspection state arrays.\n     *\n     * @see inspect for the inspection state array format.\n     *\n     * @param mixed $promises Promises or values.\n     *\n     * @return PromiseInterface\n     */\n    public static function settle($promises)\n    {\n        $results = [];\n\n        return Each::of(\n            $promises,\n            function ($value, $idx) use (&$results) {\n                $results[$idx] = ['state' => PromiseInterface::FULFILLED, 'value' => $value];\n            },\n            function ($reason, $idx) use (&$results) {\n                $results[$idx] = ['state' => PromiseInterface::REJECTED, 'reason' => $reason];\n            }\n        )->then(function () use (&$results) {\n            ksort($results);\n            return $results;\n        });\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/promises/src/functions.php",
    "content": "<?php\n\nnamespace GuzzleHttp\\Promise;\n\n/**\n * Get the global task queue used for promise resolution.\n *\n * This task queue MUST be run in an event loop in order for promises to be\n * settled asynchronously. It will be automatically run when synchronously\n * waiting on a promise.\n *\n * <code>\n * while ($eventLoop->isRunning()) {\n *     GuzzleHttp\\Promise\\queue()->run();\n * }\n * </code>\n *\n * @param TaskQueueInterface $assign Optionally specify a new queue instance.\n *\n * @return TaskQueueInterface\n *\n * @deprecated queue will be removed in guzzlehttp/promises:2.0. Use Utils::queue instead.\n */\nfunction queue(TaskQueueInterface $assign = null)\n{\n    return Utils::queue($assign);\n}\n\n/**\n * Adds a function to run in the task queue when it is next `run()` and returns\n * a promise that is fulfilled or rejected with the result.\n *\n * @param callable $task Task function to run.\n *\n * @return PromiseInterface\n *\n * @deprecated task will be removed in guzzlehttp/promises:2.0. Use Utils::task instead.\n */\nfunction task(callable $task)\n{\n    return Utils::task($task);\n}\n\n/**\n * Creates a promise for a value if the value is not a promise.\n *\n * @param mixed $value Promise or value.\n *\n * @return PromiseInterface\n *\n * @deprecated promise_for will be removed in guzzlehttp/promises:2.0. Use Create::promiseFor instead.\n */\nfunction promise_for($value)\n{\n    return Create::promiseFor($value);\n}\n\n/**\n * Creates a rejected promise for a reason if the reason is not a promise. If\n * the provided reason is a promise, then it is returned as-is.\n *\n * @param mixed $reason Promise or reason.\n *\n * @return PromiseInterface\n *\n * @deprecated rejection_for will be removed in guzzlehttp/promises:2.0. Use Create::rejectionFor instead.\n */\nfunction rejection_for($reason)\n{\n    return Create::rejectionFor($reason);\n}\n\n/**\n * Create an exception for a rejected promise value.\n *\n * @param mixed $reason\n *\n * @return \\Exception|\\Throwable\n *\n * @deprecated exception_for will be removed in guzzlehttp/promises:2.0. Use Create::exceptionFor instead.\n */\nfunction exception_for($reason)\n{\n    return Create::exceptionFor($reason);\n}\n\n/**\n * Returns an iterator for the given value.\n *\n * @param mixed $value\n *\n * @return \\Iterator\n *\n * @deprecated iter_for will be removed in guzzlehttp/promises:2.0. Use Create::iterFor instead.\n */\nfunction iter_for($value)\n{\n    return Create::iterFor($value);\n}\n\n/**\n * Synchronously waits on a promise to resolve and returns an inspection state\n * array.\n *\n * Returns a state associative array containing a \"state\" key mapping to a\n * valid promise state. If the state of the promise is \"fulfilled\", the array\n * will contain a \"value\" key mapping to the fulfilled value of the promise. If\n * the promise is rejected, the array will contain a \"reason\" key mapping to\n * the rejection reason of the promise.\n *\n * @param PromiseInterface $promise Promise or value.\n *\n * @return array\n *\n * @deprecated inspect will be removed in guzzlehttp/promises:2.0. Use Utils::inspect instead.\n */\nfunction inspect(PromiseInterface $promise)\n{\n    return Utils::inspect($promise);\n}\n\n/**\n * Waits on all of the provided promises, but does not unwrap rejected promises\n * as thrown exception.\n *\n * Returns an array of inspection state arrays.\n *\n * @see inspect for the inspection state array format.\n *\n * @param PromiseInterface[] $promises Traversable of promises to wait upon.\n *\n * @return array\n *\n * @deprecated inspect will be removed in guzzlehttp/promises:2.0. Use Utils::inspectAll instead.\n */\nfunction inspect_all($promises)\n{\n    return Utils::inspectAll($promises);\n}\n\n/**\n * Waits on all of the provided promises and returns the fulfilled values.\n *\n * Returns an array that contains the value of each promise (in the same order\n * the promises were provided). An exception is thrown if any of the promises\n * are rejected.\n *\n * @param iterable<PromiseInterface> $promises Iterable of PromiseInterface objects to wait on.\n *\n * @return array\n *\n * @throws \\Exception on error\n * @throws \\Throwable on error in PHP >=7\n *\n * @deprecated unwrap will be removed in guzzlehttp/promises:2.0. Use Utils::unwrap instead.\n */\nfunction unwrap($promises)\n{\n    return Utils::unwrap($promises);\n}\n\n/**\n * Given an array of promises, return a promise that is fulfilled when all the\n * items in the array are fulfilled.\n *\n * The promise's fulfillment value is an array with fulfillment values at\n * respective positions to the original array. If any promise in the array\n * rejects, the returned promise is rejected with the rejection reason.\n *\n * @param mixed $promises  Promises or values.\n * @param bool  $recursive If true, resolves new promises that might have been added to the stack during its own resolution.\n *\n * @return PromiseInterface\n *\n * @deprecated all will be removed in guzzlehttp/promises:2.0. Use Utils::all instead.\n */\nfunction all($promises, $recursive = false)\n{\n    return Utils::all($promises, $recursive);\n}\n\n/**\n * Initiate a competitive race between multiple promises or values (values will\n * become immediately fulfilled promises).\n *\n * When count amount of promises have been fulfilled, the returned promise is\n * fulfilled with an array that contains the fulfillment values of the winners\n * in order of resolution.\n *\n * This promise is rejected with a {@see AggregateException} if the number of\n * fulfilled promises is less than the desired $count.\n *\n * @param int   $count    Total number of promises.\n * @param mixed $promises Promises or values.\n *\n * @return PromiseInterface\n *\n * @deprecated some will be removed in guzzlehttp/promises:2.0. Use Utils::some instead.\n */\nfunction some($count, $promises)\n{\n    return Utils::some($count, $promises);\n}\n\n/**\n * Like some(), with 1 as count. However, if the promise fulfills, the\n * fulfillment value is not an array of 1 but the value directly.\n *\n * @param mixed $promises Promises or values.\n *\n * @return PromiseInterface\n *\n * @deprecated any will be removed in guzzlehttp/promises:2.0. Use Utils::any instead.\n */\nfunction any($promises)\n{\n    return Utils::any($promises);\n}\n\n/**\n * Returns a promise that is fulfilled when all of the provided promises have\n * been fulfilled or rejected.\n *\n * The returned promise is fulfilled with an array of inspection state arrays.\n *\n * @see inspect for the inspection state array format.\n *\n * @param mixed $promises Promises or values.\n *\n * @return PromiseInterface\n *\n * @deprecated settle will be removed in guzzlehttp/promises:2.0. Use Utils::settle instead.\n */\nfunction settle($promises)\n{\n    return Utils::settle($promises);\n}\n\n/**\n * Given an iterator that yields promises or values, returns a promise that is\n * fulfilled with a null value when the iterator has been consumed or the\n * aggregate promise has been fulfilled or rejected.\n *\n * $onFulfilled is a function that accepts the fulfilled value, iterator index,\n * and the aggregate promise. The callback can invoke any necessary side\n * effects and choose to resolve or reject the aggregate if needed.\n *\n * $onRejected is a function that accepts the rejection reason, iterator index,\n * and the aggregate promise. The callback can invoke any necessary side\n * effects and choose to resolve or reject the aggregate if needed.\n *\n * @param mixed    $iterable    Iterator or array to iterate over.\n * @param callable $onFulfilled\n * @param callable $onRejected\n *\n * @return PromiseInterface\n *\n * @deprecated each will be removed in guzzlehttp/promises:2.0. Use Each::of instead.\n */\nfunction each(\n    $iterable,\n    callable $onFulfilled = null,\n    callable $onRejected = null\n) {\n    return Each::of($iterable, $onFulfilled, $onRejected);\n}\n\n/**\n * Like each, but only allows a certain number of outstanding promises at any\n * given time.\n *\n * $concurrency may be an integer or a function that accepts the number of\n * pending promises and returns a numeric concurrency limit value to allow for\n * dynamic a concurrency size.\n *\n * @param mixed        $iterable\n * @param int|callable $concurrency\n * @param callable     $onFulfilled\n * @param callable     $onRejected\n *\n * @return PromiseInterface\n *\n * @deprecated each_limit will be removed in guzzlehttp/promises:2.0. Use Each::ofLimit instead.\n */\nfunction each_limit(\n    $iterable,\n    $concurrency,\n    callable $onFulfilled = null,\n    callable $onRejected = null\n) {\n    return Each::ofLimit($iterable, $concurrency, $onFulfilled, $onRejected);\n}\n\n/**\n * Like each_limit, but ensures that no promise in the given $iterable argument\n * is rejected. If any promise is rejected, then the aggregate promise is\n * rejected with the encountered rejection.\n *\n * @param mixed        $iterable\n * @param int|callable $concurrency\n * @param callable     $onFulfilled\n *\n * @return PromiseInterface\n *\n * @deprecated each_limit_all will be removed in guzzlehttp/promises:2.0. Use Each::ofLimitAll instead.\n */\nfunction each_limit_all(\n    $iterable,\n    $concurrency,\n    callable $onFulfilled = null\n) {\n    return Each::ofLimitAll($iterable, $concurrency, $onFulfilled);\n}\n\n/**\n * Returns true if a promise is fulfilled.\n *\n * @return bool\n *\n * @deprecated is_fulfilled will be removed in guzzlehttp/promises:2.0. Use Is::fulfilled instead.\n */\nfunction is_fulfilled(PromiseInterface $promise)\n{\n    return Is::fulfilled($promise);\n}\n\n/**\n * Returns true if a promise is rejected.\n *\n * @return bool\n *\n * @deprecated is_rejected will be removed in guzzlehttp/promises:2.0. Use Is::rejected instead.\n */\nfunction is_rejected(PromiseInterface $promise)\n{\n    return Is::rejected($promise);\n}\n\n/**\n * Returns true if a promise is fulfilled or rejected.\n *\n * @return bool\n *\n * @deprecated is_settled will be removed in guzzlehttp/promises:2.0. Use Is::settled instead.\n */\nfunction is_settled(PromiseInterface $promise)\n{\n    return Is::settled($promise);\n}\n\n/**\n * Create a new coroutine.\n *\n * @see Coroutine\n *\n * @return PromiseInterface\n *\n * @deprecated coroutine will be removed in guzzlehttp/promises:2.0. Use Coroutine::of instead.\n */\nfunction coroutine(callable $generatorFn)\n{\n    return Coroutine::of($generatorFn);\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/promises/src/functions_include.php",
    "content": "<?php\n\n// Don't redefine the functions if included multiple times.\nif (!function_exists('GuzzleHttp\\Promise\\promise_for')) {\n    require __DIR__ . '/functions.php';\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/psr7/.github/FUNDING.yml",
    "content": "github: [Nyholm, GrahamCampbell]\ntidelift: \"packagist/guzzlehttp/psr7\"\n"
  },
  {
    "path": "server/vendor/guzzlehttp/psr7/.github/stale.yml",
    "content": "daysUntilStale: 120\ndaysUntilClose: 14\nexemptLabels:\n  - lifecycle/keep-open\n  - lifecycle/ready-for-merge\n# Label to use when marking an issue as stale\nstaleLabel: lifecycle/stale\n# Comment to post when marking an issue as stale. Set to `false` to disable\nmarkComment: >\n  This issue has been automatically marked as stale because it has not had\n  recent activity. It will be closed after 2 weeks if no further activity occurs. Thank you\n  for your contributions.\n# Comment to post when closing a stale issue. Set to `false` to disable\ncloseComment: false\n"
  },
  {
    "path": "server/vendor/guzzlehttp/psr7/.github/workflows/ci.yml",
    "content": "name: CI\n\non:\n  pull_request:\n\njobs:\n  build:\n    name: Build\n    runs-on: ubuntu-22.04\n    strategy:\n      max-parallel: 10\n      matrix:\n        php: ['5.5', '5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1']\n\n    steps:\n      - name: Set up PHP\n        uses: shivammathur/setup-php@v2\n        with:\n          php-version: ${{ matrix.php }}\n          coverage: 'none'\n          extensions: mbstring\n\n      - name: Checkout code\n        uses: actions/checkout@v3\n\n      - name: Install dependencies\n        run: composer update --no-interaction --no-progress\n\n      - name: Run tests\n        run: make test\n"
  },
  {
    "path": "server/vendor/guzzlehttp/psr7/.github/workflows/integration.yml",
    "content": "name: Integration\n\non:\n  pull_request:\n\njobs:\n  build:\n    name: Test\n    runs-on: ubuntu-22.04\n    strategy:\n      max-parallel: 10\n      matrix:\n        php: ['7.2', '7.3', '7.4', '8.0', '8.1']\n\n    steps:\n      - name: Set up PHP\n        uses: shivammathur/setup-php@v2\n        with:\n          php-version: ${{ matrix.php }}\n          coverage: none\n\n      - name: Checkout code\n        uses: actions/checkout@v3\n\n      - name: Download dependencies\n        uses: ramsey/composer-install@v1\n        with:\n          composer-options: --no-interaction --optimize-autoloader\n\n      - name: Start server\n        run: php -S 127.0.0.1:10002 tests/Integration/server.php &\n\n      - name: Run tests\n        env:\n          TEST_SERVER: 127.0.0.1:10002\n        run: ./vendor/bin/phpunit --testsuite Integration\n"
  },
  {
    "path": "server/vendor/guzzlehttp/psr7/.github/workflows/static.yml",
    "content": "name: Static analysis\n\non:\n  pull_request:\n\njobs:\n  php-cs-fixer:\n    name: PHP-CS-Fixer\n    runs-on: ubuntu-22.04\n\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v3\n\n      - name: Setup PHP\n        uses: shivammathur/setup-php@v2\n        with:\n          php-version: '7.4'\n          coverage: none\n          extensions: mbstring\n\n      - name: Download dependencies\n        run: composer update --no-interaction --no-progress\n\n      - name: Download PHP CS Fixer\n        run: composer require \"friendsofphp/php-cs-fixer:2.18.4\"\n\n      - name: Execute PHP CS Fixer\n        run: vendor/bin/php-cs-fixer fix --diff-format udiff --dry-run\n"
  },
  {
    "path": "server/vendor/guzzlehttp/psr7/.php_cs.dist",
    "content": "<?php\n\n$config = PhpCsFixer\\Config::create()\n    ->setRiskyAllowed(true)\n    ->setRules([\n        '@PSR2' => true,\n        'array_syntax' => ['syntax' => 'short'],\n        'concat_space' => ['spacing' => 'one'],\n        'declare_strict_types' => false,\n        'final_static_access' => true,\n        'fully_qualified_strict_types' => true,\n        'header_comment' => false,\n        'is_null' => ['use_yoda_style' => true],\n        'list_syntax' => ['syntax' => 'long'],\n        'lowercase_cast' => true,\n        'magic_method_casing' => true,\n        'modernize_types_casting' => true,\n        'multiline_comment_opening_closing' => true,\n        'no_alias_functions' => true,\n        'no_alternative_syntax' => true,\n        'no_blank_lines_after_phpdoc' => true,\n        'no_empty_comment' => true,\n        'no_empty_phpdoc' => true,\n        'no_empty_statement' => true,\n        'no_extra_blank_lines' => true,\n        'no_leading_import_slash' => true,\n        'no_trailing_comma_in_singleline_array' => true,\n        'no_unset_cast' => true,\n        'no_unused_imports' => true,\n        'no_whitespace_in_blank_line' => true,\n        'ordered_imports' => true,\n        'php_unit_ordered_covers' => true,\n        'php_unit_test_annotation' => ['style' => 'prefix'],\n        'php_unit_test_case_static_method_calls' => ['call_type' => 'self'],\n        'phpdoc_align' => ['align' => 'vertical'],\n        'phpdoc_no_useless_inheritdoc' => true,\n        'phpdoc_scalar' => true,\n        'phpdoc_separation' => true,\n        'phpdoc_single_line_var_spacing' => true,\n        'phpdoc_trim' => true,\n        'phpdoc_trim_consecutive_blank_line_separation' => true,\n        'phpdoc_types' => true,\n        'phpdoc_types_order' => ['null_adjustment' => 'always_last', 'sort_algorithm' => 'none'],\n        'phpdoc_var_without_name' => true,\n        'single_trait_insert_per_statement' => true,\n        'standardize_not_equals' => true,\n    ])\n    ->setFinder(\n        PhpCsFixer\\Finder::create()\n            ->in(__DIR__.'/src')\n            ->in(__DIR__.'/tests')\n            ->name('*.php')\n    )\n;\n\nreturn $config;\n"
  },
  {
    "path": "server/vendor/guzzlehttp/psr7/CHANGELOG.md",
    "content": "# Change Log\n\n\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)\nand this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n\n\n## Unreleased\n\n## 1.9.1 - 2023-04-17\n\n### Fixed\n\n- Fixed header validation issue\n\n## 1.9.0 - 2022-06-20\n\n### Added\n\n- Added `UriComparator::isCrossOrigin` method\n\n## 1.8.5 - 2022-03-20\n\n### Fixed\n\n- Correct header value validation\n\n## 1.8.4 - 2022-03-20\n\n### Fixed\n\n- Validate header values properly\n\n## 1.8.3 - 2021-10-05\n\n### Fixed\n\n- Return `null` in caching stream size if remote size is `null`\n\n## 1.8.2 - 2021-04-26\n\n### Fixed\n\n- Handle possibly unset `url` in `stream_get_meta_data`\n\n## 1.8.1 - 2021-03-21\n\n### Fixed\n\n- Issue parsing IPv6 URLs\n- Issue modifying ServerRequest lost all its attributes\n\n## 1.8.0 - 2021-03-21\n\n### Added\n\n- Locale independent URL parsing\n- Most classes got a `@final` annotation to prepare for 2.0\n\n### Fixed\n\n- Issue when creating stream from `php://input` and curl-ext is not installed\n- Broken `Utils::tryFopen()` on PHP 8\n\n## 1.7.0 - 2020-09-30\n\n### Added\n\n- Replaced functions by static methods\n\n### Fixed\n\n- Converting a non-seekable stream to a string\n- Handle multiple Set-Cookie correctly\n- Ignore array keys in header values when merging\n- Allow multibyte characters to be parsed in `Message:bodySummary()`\n\n### Changed\n\n- Restored partial HHVM 3 support\n\n\n## [1.6.1] - 2019-07-02\n\n### Fixed\n\n- Accept null and bool header values again\n\n\n## [1.6.0] - 2019-06-30\n\n### Added\n\n- Allowed version `^3.0` of `ralouphie/getallheaders` dependency (#244)\n- Added MIME type for WEBP image format (#246)\n- Added more validation of values according to PSR-7 and RFC standards, e.g. status code range (#250, #272)\n\n### Changed\n\n- Tests don't pass with HHVM 4.0, so HHVM support got dropped. Other libraries like composer have done the same. (#262)\n- Accept port number 0 to be valid (#270)\n\n### Fixed\n\n- Fixed subsequent reads from `php://input` in ServerRequest (#247)\n- Fixed readable/writable detection for certain stream modes (#248)\n- Fixed encoding of special characters in the `userInfo` component of an URI (#253)\n\n\n## [1.5.2] - 2018-12-04\n\n### Fixed\n\n- Check body size when getting the message summary\n\n\n## [1.5.1] - 2018-12-04\n\n### Fixed\n\n- Get the summary of a body only if it is readable\n\n\n## [1.5.0] - 2018-12-03\n\n### Added\n\n- Response first-line to response string exception (fixes #145)\n- A test for #129 behavior\n- `get_message_body_summary` function in order to get the message summary\n- `3gp` and `mkv` mime types\n\n### Changed\n\n- Clarify exception message when stream is detached\n\n### Deprecated\n\n- Deprecated parsing folded header lines as per RFC 7230\n\n### Fixed\n\n- Fix `AppendStream::detach` to not close streams\n- `InflateStream` preserves `isSeekable` attribute of the underlying stream\n- `ServerRequest::getUriFromGlobals` to support URLs in query parameters\n\n\nSeveral other fixes and improvements.\n\n\n## [1.4.2] - 2017-03-20\n\n### Fixed\n\n- Reverted BC break to `Uri::resolve` and `Uri::removeDotSegments` by removing\n  calls to `trigger_error` when deprecated methods are invoked.\n\n\n## [1.4.1] - 2017-02-27\n\n### Added\n\n- Rriggering of silenced deprecation warnings.\n\n### Fixed\n\n- Reverted BC break by reintroducing behavior to automagically fix a URI with a\n  relative path and an authority by adding a leading slash to the path. It's only\n  deprecated now.\n\n\n## [1.4.0] - 2017-02-21\n\n### Added\n\n- Added common URI utility methods based on RFC 3986 (see documentation in the readme):\n  - `Uri::isDefaultPort`\n  - `Uri::isAbsolute`\n  - `Uri::isNetworkPathReference`\n  - `Uri::isAbsolutePathReference`\n  - `Uri::isRelativePathReference`\n  - `Uri::isSameDocumentReference`\n  - `Uri::composeComponents`\n  - `UriNormalizer::normalize`\n  - `UriNormalizer::isEquivalent`\n  - `UriResolver::relativize`\n\n### Changed\n\n- Ensure `ServerRequest::getUriFromGlobals` returns a URI in absolute form.\n- Allow `parse_response` to parse a response without delimiting space and reason.\n- Ensure each URI modification results in a valid URI according to PSR-7 discussions.\n  Invalid modifications will throw an exception instead of returning a wrong URI or\n  doing some magic.\n  - `(new Uri)->withPath('foo')->withHost('example.com')` will throw an exception\n    because the path of a URI with an authority must start with a slash \"/\" or be empty\n  - `(new Uri())->withScheme('http')` will return `'http://localhost'`\n\n### Deprecated\n\n- `Uri::resolve` in favor of `UriResolver::resolve`\n- `Uri::removeDotSegments` in favor of `UriResolver::removeDotSegments`\n\n### Fixed\n\n- `Stream::read` when length parameter <= 0.\n- `copy_to_stream` reads bytes in chunks instead of `maxLen` into memory.\n- `ServerRequest::getUriFromGlobals` when `Host` header contains port.\n- Compatibility of URIs with `file` scheme and empty host.\n\n\n## [1.3.1] - 2016-06-25\n\n### Fixed\n\n- `Uri::__toString` for network path references, e.g. `//example.org`.\n- Missing lowercase normalization for host.\n- Handling of URI components in case they are `'0'` in a lot of places,\n  e.g. as a user info password.\n- `Uri::withAddedHeader` to correctly merge headers with different case.\n- Trimming of header values in `Uri::withAddedHeader`. Header values may\n  be surrounded by whitespace which should be ignored according to RFC 7230\n  Section 3.2.4. This does not apply to header names.\n- `Uri::withAddedHeader` with an array of header values.\n- `Uri::resolve` when base path has no slash and handling of fragment.\n- Handling of encoding in `Uri::with(out)QueryValue` so one can pass the\n  key/value both in encoded as well as decoded form to those methods. This is\n  consistent with withPath, withQuery etc.\n- `ServerRequest::withoutAttribute` when attribute value is null.\n\n\n## [1.3.0] - 2016-04-13\n\n### Added\n\n- Remaining interfaces needed for full PSR7 compatibility\n  (ServerRequestInterface, UploadedFileInterface, etc.).\n- Support for stream_for from scalars.\n\n### Changed\n\n- Can now extend Uri.\n\n### Fixed\n- A bug in validating request methods by making it more permissive.\n\n\n## [1.2.3] - 2016-02-18\n\n### Fixed\n\n- Support in `GuzzleHttp\\Psr7\\CachingStream` for seeking forward on remote\n  streams, which can sometimes return fewer bytes than requested with `fread`.\n- Handling of gzipped responses with FNAME headers.\n\n\n## [1.2.2] - 2016-01-22\n\n### Added\n\n- Support for URIs without any authority.\n- Support for HTTP 451 'Unavailable For Legal Reasons.'\n- Support for using '0' as a filename.\n- Support for including non-standard ports in Host headers.\n\n\n## [1.2.1] - 2015-11-02\n\n### Changes\n\n- Now supporting negative offsets when seeking to SEEK_END.\n\n\n## [1.2.0] - 2015-08-15\n\n### Changed\n\n- Body as `\"0\"` is now properly added to a response.\n- Now allowing forward seeking in CachingStream.\n- Now properly parsing HTTP requests that contain proxy targets in\n  `parse_request`.\n- functions.php is now conditionally required.\n- user-info is no longer dropped when resolving URIs.\n\n\n## [1.1.0] - 2015-06-24\n\n### Changed\n\n- URIs can now be relative.\n- `multipart/form-data` headers are now overridden case-insensitively.\n- URI paths no longer encode the following characters because they are allowed\n  in URIs: \"(\", \")\", \"*\", \"!\", \"'\"\n- A port is no longer added to a URI when the scheme is missing and no port is\n  present.\n\n\n## 1.0.0 - 2015-05-19\n\nInitial release.\n\nCurrently unsupported:\n\n- `Psr\\Http\\Message\\ServerRequestInterface`\n- `Psr\\Http\\Message\\UploadedFileInterface`\n\n\n\n[1.6.0]: https://github.com/guzzle/psr7/compare/1.5.2...1.6.0\n[1.5.2]: https://github.com/guzzle/psr7/compare/1.5.1...1.5.2\n[1.5.1]: https://github.com/guzzle/psr7/compare/1.5.0...1.5.1\n[1.5.0]: https://github.com/guzzle/psr7/compare/1.4.2...1.5.0\n[1.4.2]: https://github.com/guzzle/psr7/compare/1.4.1...1.4.2\n[1.4.1]: https://github.com/guzzle/psr7/compare/1.4.0...1.4.1\n[1.4.0]: https://github.com/guzzle/psr7/compare/1.3.1...1.4.0\n[1.3.1]: https://github.com/guzzle/psr7/compare/1.3.0...1.3.1\n[1.3.0]: https://github.com/guzzle/psr7/compare/1.2.3...1.3.0\n[1.2.3]: https://github.com/guzzle/psr7/compare/1.2.2...1.2.3\n[1.2.2]: https://github.com/guzzle/psr7/compare/1.2.1...1.2.2\n[1.2.1]: https://github.com/guzzle/psr7/compare/1.2.0...1.2.1\n[1.2.0]: https://github.com/guzzle/psr7/compare/1.1.0...1.2.0\n[1.1.0]: https://github.com/guzzle/psr7/compare/1.0.0...1.1.0\n"
  },
  {
    "path": "server/vendor/guzzlehttp/psr7/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2015 Michael Dowling <mtdowling@gmail.com>\nCopyright (c) 2015 Márk Sági-Kazár <mark.sagikazar@gmail.com>\nCopyright (c) 2015 Graham Campbell <hello@gjcampbell.co.uk>\nCopyright (c) 2016 Tobias Schultze <webmaster@tubo-world.de>\nCopyright (c) 2016 George Mponos <gmponos@gmail.com>\nCopyright (c) 2018 Tobias Nyholm <tobias.nyholm@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "server/vendor/guzzlehttp/psr7/README.md",
    "content": "# PSR-7 Message Implementation\n\nThis repository contains a full [PSR-7](https://www.php-fig.org/psr/psr-7/)\nmessage implementation, several stream decorators, and some helpful\nfunctionality like query string parsing.\n\n\n[![Build Status](https://travis-ci.org/guzzle/psr7.svg?branch=master)](https://travis-ci.org/guzzle/psr7)\n\n\n# Stream implementation\n\nThis package comes with a number of stream implementations and stream\ndecorators.\n\n\n## AppendStream\n\n`GuzzleHttp\\Psr7\\AppendStream`\n\nReads from multiple streams, one after the other.\n\n```php\nuse GuzzleHttp\\Psr7;\n\n$a = Psr7\\Utils::streamFor('abc, ');\n$b = Psr7\\Utils::streamFor('123.');\n$composed = new Psr7\\AppendStream([$a, $b]);\n\n$composed->addStream(Psr7\\Utils::streamFor(' Above all listen to me'));\n\necho $composed; // abc, 123. Above all listen to me.\n```\n\n\n## BufferStream\n\n`GuzzleHttp\\Psr7\\BufferStream`\n\nProvides a buffer stream that can be written to fill a buffer, and read\nfrom to remove bytes from the buffer.\n\nThis stream returns a \"hwm\" metadata value that tells upstream consumers\nwhat the configured high water mark of the stream is, or the maximum\npreferred size of the buffer.\n\n```php\nuse GuzzleHttp\\Psr7;\n\n// When more than 1024 bytes are in the buffer, it will begin returning\n// false to writes. This is an indication that writers should slow down.\n$buffer = new Psr7\\BufferStream(1024);\n```\n\n\n## CachingStream\n\nThe CachingStream is used to allow seeking over previously read bytes on\nnon-seekable streams. This can be useful when transferring a non-seekable\nentity body fails due to needing to rewind the stream (for example, resulting\nfrom a redirect). Data that is read from the remote stream will be buffered in\na PHP temp stream so that previously read bytes are cached first in memory,\nthen on disk.\n\n```php\nuse GuzzleHttp\\Psr7;\n\n$original = Psr7\\Utils::streamFor(fopen('http://www.google.com', 'r'));\n$stream = new Psr7\\CachingStream($original);\n\n$stream->read(1024);\necho $stream->tell();\n// 1024\n\n$stream->seek(0);\necho $stream->tell();\n// 0\n```\n\n\n## DroppingStream\n\n`GuzzleHttp\\Psr7\\DroppingStream`\n\nStream decorator that begins dropping data once the size of the underlying\nstream becomes too full.\n\n```php\nuse GuzzleHttp\\Psr7;\n\n// Create an empty stream\n$stream = Psr7\\Utils::streamFor();\n\n// Start dropping data when the stream has more than 10 bytes\n$dropping = new Psr7\\DroppingStream($stream, 10);\n\n$dropping->write('01234567890123456789');\necho $stream; // 0123456789\n```\n\n\n## FnStream\n\n`GuzzleHttp\\Psr7\\FnStream`\n\nCompose stream implementations based on a hash of functions.\n\nAllows for easy testing and extension of a provided stream without needing\nto create a concrete class for a simple extension point.\n\n```php\n\nuse GuzzleHttp\\Psr7;\n\n$stream = Psr7\\Utils::streamFor('hi');\n$fnStream = Psr7\\FnStream::decorate($stream, [\n    'rewind' => function () use ($stream) {\n        echo 'About to rewind - ';\n        $stream->rewind();\n        echo 'rewound!';\n    }\n]);\n\n$fnStream->rewind();\n// Outputs: About to rewind - rewound!\n```\n\n\n## InflateStream\n\n`GuzzleHttp\\Psr7\\InflateStream`\n\nUses PHP's zlib.inflate filter to inflate deflate or gzipped content.\n\nThis stream decorator skips the first 10 bytes of the given stream to remove\nthe gzip header, converts the provided stream to a PHP stream resource,\nthen appends the zlib.inflate filter. The stream is then converted back\nto a Guzzle stream resource to be used as a Guzzle stream.\n\n\n## LazyOpenStream\n\n`GuzzleHttp\\Psr7\\LazyOpenStream`\n\nLazily reads or writes to a file that is opened only after an IO operation\ntake place on the stream.\n\n```php\nuse GuzzleHttp\\Psr7;\n\n$stream = new Psr7\\LazyOpenStream('/path/to/file', 'r');\n// The file has not yet been opened...\n\necho $stream->read(10);\n// The file is opened and read from only when needed.\n```\n\n\n## LimitStream\n\n`GuzzleHttp\\Psr7\\LimitStream`\n\nLimitStream can be used to read a subset or slice of an existing stream object.\nThis can be useful for breaking a large file into smaller pieces to be sent in\nchunks (e.g. Amazon S3's multipart upload API).\n\n```php\nuse GuzzleHttp\\Psr7;\n\n$original = Psr7\\Utils::streamFor(fopen('/tmp/test.txt', 'r+'));\necho $original->getSize();\n// >>> 1048576\n\n// Limit the size of the body to 1024 bytes and start reading from byte 2048\n$stream = new Psr7\\LimitStream($original, 1024, 2048);\necho $stream->getSize();\n// >>> 1024\necho $stream->tell();\n// >>> 0\n```\n\n\n## MultipartStream\n\n`GuzzleHttp\\Psr7\\MultipartStream`\n\nStream that when read returns bytes for a streaming multipart or\nmultipart/form-data stream.\n\n\n## NoSeekStream\n\n`GuzzleHttp\\Psr7\\NoSeekStream`\n\nNoSeekStream wraps a stream and does not allow seeking.\n\n```php\nuse GuzzleHttp\\Psr7;\n\n$original = Psr7\\Utils::streamFor('foo');\n$noSeek = new Psr7\\NoSeekStream($original);\n\necho $noSeek->read(3);\n// foo\nvar_export($noSeek->isSeekable());\n// false\n$noSeek->seek(0);\nvar_export($noSeek->read(3));\n// NULL\n```\n\n\n## PumpStream\n\n`GuzzleHttp\\Psr7\\PumpStream`\n\nProvides a read only stream that pumps data from a PHP callable.\n\nWhen invoking the provided callable, the PumpStream will pass the amount of\ndata requested to read to the callable. The callable can choose to ignore\nthis value and return fewer or more bytes than requested. Any extra data\nreturned by the provided callable is buffered internally until drained using\nthe read() function of the PumpStream. The provided callable MUST return\nfalse when there is no more data to read.\n\n\n## Implementing stream decorators\n\nCreating a stream decorator is very easy thanks to the\n`GuzzleHttp\\Psr7\\StreamDecoratorTrait`. This trait provides methods that\nimplement `Psr\\Http\\Message\\StreamInterface` by proxying to an underlying\nstream. Just `use` the `StreamDecoratorTrait` and implement your custom\nmethods.\n\nFor example, let's say we wanted to call a specific function each time the last\nbyte is read from a stream. This could be implemented by overriding the\n`read()` method.\n\n```php\nuse Psr\\Http\\Message\\StreamInterface;\nuse GuzzleHttp\\Psr7\\StreamDecoratorTrait;\n\nclass EofCallbackStream implements StreamInterface\n{\n    use StreamDecoratorTrait;\n\n    private $callback;\n\n    public function __construct(StreamInterface $stream, callable $cb)\n    {\n        $this->stream = $stream;\n        $this->callback = $cb;\n    }\n\n    public function read($length)\n    {\n        $result = $this->stream->read($length);\n\n        // Invoke the callback when EOF is hit.\n        if ($this->eof()) {\n            call_user_func($this->callback);\n        }\n\n        return $result;\n    }\n}\n```\n\nThis decorator could be added to any existing stream and used like so:\n\n```php\nuse GuzzleHttp\\Psr7;\n\n$original = Psr7\\Utils::streamFor('foo');\n\n$eofStream = new EofCallbackStream($original, function () {\n    echo 'EOF!';\n});\n\n$eofStream->read(2);\n$eofStream->read(1);\n// echoes \"EOF!\"\n$eofStream->seek(0);\n$eofStream->read(3);\n// echoes \"EOF!\"\n```\n\n\n## PHP StreamWrapper\n\nYou can use the `GuzzleHttp\\Psr7\\StreamWrapper` class if you need to use a\nPSR-7 stream as a PHP stream resource.\n\nUse the `GuzzleHttp\\Psr7\\StreamWrapper::getResource()` method to create a PHP\nstream from a PSR-7 stream.\n\n```php\nuse GuzzleHttp\\Psr7\\StreamWrapper;\n\n$stream = GuzzleHttp\\Psr7\\Utils::streamFor('hello!');\n$resource = StreamWrapper::getResource($stream);\necho fread($resource, 6); // outputs hello!\n```\n\n\n# Static API\n\nThere are various static methods available under the `GuzzleHttp\\Psr7` namespace.\n\n\n## `GuzzleHttp\\Psr7\\Message::toString`\n\n`public static function toString(MessageInterface $message): string`\n\nReturns the string representation of an HTTP message.\n\n```php\n$request = new GuzzleHttp\\Psr7\\Request('GET', 'http://example.com');\necho GuzzleHttp\\Psr7\\Message::toString($request);\n```\n\n\n## `GuzzleHttp\\Psr7\\Message::bodySummary`\n\n`public static function bodySummary(MessageInterface $message, int $truncateAt = 120): string|null`\n\nGet a short summary of the message body.\n\nWill return `null` if the response is not printable.\n\n\n## `GuzzleHttp\\Psr7\\Message::rewindBody`\n\n`public static function rewindBody(MessageInterface $message): void`\n\nAttempts to rewind a message body and throws an exception on failure.\n\nThe body of the message will only be rewound if a call to `tell()`\nreturns a value other than `0`.\n\n\n## `GuzzleHttp\\Psr7\\Message::parseMessage`\n\n`public static function parseMessage(string $message): array`\n\nParses an HTTP message into an associative array.\n\nThe array contains the \"start-line\" key containing the start line of\nthe message, \"headers\" key containing an associative array of header\narray values, and a \"body\" key containing the body of the message.\n\n\n## `GuzzleHttp\\Psr7\\Message::parseRequestUri`\n\n`public static function parseRequestUri(string $path, array $headers): string`\n\nConstructs a URI for an HTTP request message.\n\n\n## `GuzzleHttp\\Psr7\\Message::parseRequest`\n\n`public static function parseRequest(string $message): Request`\n\nParses a request message string into a request object.\n\n\n## `GuzzleHttp\\Psr7\\Message::parseResponse`\n\n`public static function parseResponse(string $message): Response`\n\nParses a response message string into a response object.\n\n\n## `GuzzleHttp\\Psr7\\Header::parse`\n\n`public static function parse(string|array $header): array`\n\nParse an array of header values containing \";\" separated data into an\narray of associative arrays representing the header key value pair data\nof the header. When a parameter does not contain a value, but just\ncontains a key, this function will inject a key with a '' string value.\n\n\n## `GuzzleHttp\\Psr7\\Header::normalize`\n\n`public static function normalize(string|array $header): array`\n\nConverts an array of header values that may contain comma separated\nheaders into an array of headers with no comma separated values.\n\n\n## `GuzzleHttp\\Psr7\\Query::parse`\n\n`public static function parse(string $str, int|bool $urlEncoding = true): array`\n\nParse a query string into an associative array.\n\nIf multiple values are found for the same key, the value of that key\nvalue pair will become an array. This function does not parse nested\nPHP style arrays into an associative array (e.g., `foo[a]=1&foo[b]=2`\nwill be parsed into `['foo[a]' => '1', 'foo[b]' => '2'])`.\n\n\n## `GuzzleHttp\\Psr7\\Query::build`\n\n`public static function build(array $params, int|false $encoding = PHP_QUERY_RFC3986): string`\n\nBuild a query string from an array of key value pairs.\n\nThis function can use the return value of `parse()` to build a query\nstring. This function does not modify the provided keys when an array is\nencountered (like `http_build_query()` would).\n\n\n## `GuzzleHttp\\Psr7\\Utils::caselessRemove`\n\n`public static function caselessRemove(iterable<string> $keys, $keys, array $data): array`\n\nRemove the items given by the keys, case insensitively from the data.\n\n\n## `GuzzleHttp\\Psr7\\Utils::copyToStream`\n\n`public static function copyToStream(StreamInterface $source, StreamInterface $dest, int $maxLen = -1): void`\n\nCopy the contents of a stream into another stream until the given number\nof bytes have been read.\n\n\n## `GuzzleHttp\\Psr7\\Utils::copyToString`\n\n`public static function copyToString(StreamInterface $stream, int $maxLen = -1): string`\n\nCopy the contents of a stream into a string until the given number of\nbytes have been read.\n\n\n## `GuzzleHttp\\Psr7\\Utils::hash`\n\n`public static function hash(StreamInterface $stream, string $algo, bool $rawOutput = false): string`\n\nCalculate a hash of a stream.\n\nThis method reads the entire stream to calculate a rolling hash, based on\nPHP's `hash_init` functions.\n\n\n## `GuzzleHttp\\Psr7\\Utils::modifyRequest`\n\n`public static function modifyRequest(RequestInterface $request, array $changes): RequestInterface`\n\nClone and modify a request with the given changes.\n\nThis method is useful for reducing the number of clones needed to mutate\na message.\n\n- method: (string) Changes the HTTP method.\n- set_headers: (array) Sets the given headers.\n- remove_headers: (array) Remove the given headers.\n- body: (mixed) Sets the given body.\n- uri: (UriInterface) Set the URI.\n- query: (string) Set the query string value of the URI.\n- version: (string) Set the protocol version.\n\n\n## `GuzzleHttp\\Psr7\\Utils::readLine`\n\n`public static function readLine(StreamInterface $stream, int $maxLength = null): string`\n\nRead a line from the stream up to the maximum allowed buffer length.\n\n\n## `GuzzleHttp\\Psr7\\Utils::streamFor`\n\n`public static function streamFor(resource|string|null|int|float|bool|StreamInterface|callable|\\Iterator $resource = '', array $options = []): StreamInterface`\n\nCreate a new stream based on the input type.\n\nOptions is an associative array that can contain the following keys:\n\n- metadata: Array of custom metadata.\n- size: Size of the stream.\n\nThis method accepts the following `$resource` types:\n\n- `Psr\\Http\\Message\\StreamInterface`: Returns the value as-is.\n- `string`: Creates a stream object that uses the given string as the contents.\n- `resource`: Creates a stream object that wraps the given PHP stream resource.\n- `Iterator`: If the provided value implements `Iterator`, then a read-only\n  stream object will be created that wraps the given iterable. Each time the\n  stream is read from, data from the iterator will fill a buffer and will be\n  continuously called until the buffer is equal to the requested read size.\n  Subsequent read calls will first read from the buffer and then call `next`\n  on the underlying iterator until it is exhausted.\n- `object` with `__toString()`: If the object has the `__toString()` method,\n  the object will be cast to a string and then a stream will be returned that\n  uses the string value.\n- `NULL`: When `null` is passed, an empty stream object is returned.\n- `callable` When a callable is passed, a read-only stream object will be\n  created that invokes the given callable. The callable is invoked with the\n  number of suggested bytes to read. The callable can return any number of\n  bytes, but MUST return `false` when there is no more data to return. The\n  stream object that wraps the callable will invoke the callable until the\n  number of requested bytes are available. Any additional bytes will be\n  buffered and used in subsequent reads.\n\n```php\n$stream = GuzzleHttp\\Psr7\\Utils::streamFor('foo');\n$stream = GuzzleHttp\\Psr7\\Utils::streamFor(fopen('/path/to/file', 'r'));\n\n$generator = function ($bytes) {\n    for ($i = 0; $i < $bytes; $i++) {\n        yield ' ';\n    }\n}\n\n$stream = GuzzleHttp\\Psr7\\Utils::streamFor($generator(100));\n```\n\n\n## `GuzzleHttp\\Psr7\\Utils::tryFopen`\n\n`public static function tryFopen(string $filename, string $mode): resource`\n\nSafely opens a PHP stream resource using a filename.\n\nWhen fopen fails, PHP normally raises a warning. This function adds an\nerror handler that checks for errors and throws an exception instead.\n\n\n## `GuzzleHttp\\Psr7\\Utils::uriFor`\n\n`public static function uriFor(string|UriInterface $uri): UriInterface`\n\nReturns a UriInterface for the given value.\n\nThis function accepts a string or UriInterface and returns a\nUriInterface for the given value. If the value is already a\nUriInterface, it is returned as-is.\n\n\n## `GuzzleHttp\\Psr7\\MimeType::fromFilename`\n\n`public static function fromFilename(string $filename): string|null`\n\nDetermines the mimetype of a file by looking at its extension.\n\n\n## `GuzzleHttp\\Psr7\\MimeType::fromExtension`\n\n`public static function fromExtension(string $extension): string|null`\n\nMaps a file extensions to a mimetype.\n\n\n## Upgrading from Function API\n\nThe static API was first introduced in 1.7.0, in order to mitigate problems with functions conflicting between global and local copies of the package. The function API will be removed in 2.0.0. A migration table has been provided here for your convenience:\n\n| Original Function | Replacement Method |\n|----------------|----------------|\n| `str` | `Message::toString` |\n| `uri_for` | `Utils::uriFor` |\n| `stream_for` | `Utils::streamFor` |\n| `parse_header` | `Header::parse` |\n| `normalize_header` | `Header::normalize` |\n| `modify_request` | `Utils::modifyRequest` |\n| `rewind_body` | `Message::rewindBody` |\n| `try_fopen` | `Utils::tryFopen` |\n| `copy_to_string` | `Utils::copyToString` |\n| `copy_to_stream` | `Utils::copyToStream` |\n| `hash` | `Utils::hash` |\n| `readline` | `Utils::readLine` |\n| `parse_request` | `Message::parseRequest` |\n| `parse_response` | `Message::parseResponse` |\n| `parse_query` | `Query::parse` |\n| `build_query` | `Query::build` |\n| `mimetype_from_filename` | `MimeType::fromFilename` |\n| `mimetype_from_extension` | `MimeType::fromExtension` |\n| `_parse_message` | `Message::parseMessage` |\n| `_parse_request_uri` | `Message::parseRequestUri` |\n| `get_message_body_summary` | `Message::bodySummary` |\n| `_caseless_remove` | `Utils::caselessRemove` |\n\n\n# Additional URI Methods\n\nAside from the standard `Psr\\Http\\Message\\UriInterface` implementation in form of the `GuzzleHttp\\Psr7\\Uri` class,\nthis library also provides additional functionality when working with URIs as static methods.\n\n## URI Types\n\nAn instance of `Psr\\Http\\Message\\UriInterface` can either be an absolute URI or a relative reference.\nAn absolute URI has a scheme. A relative reference is used to express a URI relative to another URI,\nthe base URI. Relative references can be divided into several forms according to\n[RFC 3986 Section 4.2](https://tools.ietf.org/html/rfc3986#section-4.2):\n\n- network-path references, e.g. `//example.com/path`\n- absolute-path references, e.g. `/path`\n- relative-path references, e.g. `subpath`\n\nThe following methods can be used to identify the type of the URI.\n\n### `GuzzleHttp\\Psr7\\Uri::isAbsolute`\n\n`public static function isAbsolute(UriInterface $uri): bool`\n\nWhether the URI is absolute, i.e. it has a scheme.\n\n### `GuzzleHttp\\Psr7\\Uri::isNetworkPathReference`\n\n`public static function isNetworkPathReference(UriInterface $uri): bool`\n\nWhether the URI is a network-path reference. A relative reference that begins with two slash characters is\ntermed an network-path reference.\n\n### `GuzzleHttp\\Psr7\\Uri::isAbsolutePathReference`\n\n`public static function isAbsolutePathReference(UriInterface $uri): bool`\n\nWhether the URI is a absolute-path reference. A relative reference that begins with a single slash character is\ntermed an absolute-path reference.\n\n### `GuzzleHttp\\Psr7\\Uri::isRelativePathReference`\n\n`public static function isRelativePathReference(UriInterface $uri): bool`\n\nWhether the URI is a relative-path reference. A relative reference that does not begin with a slash character is\ntermed a relative-path reference.\n\n### `GuzzleHttp\\Psr7\\Uri::isSameDocumentReference`\n\n`public static function isSameDocumentReference(UriInterface $uri, UriInterface $base = null): bool`\n\nWhether the URI is a same-document reference. A same-document reference refers to a URI that is, aside from its\nfragment component, identical to the base URI. When no base URI is given, only an empty URI reference\n(apart from its fragment) is considered a same-document reference.\n\n## URI Components\n\nAdditional methods to work with URI components.\n\n### `GuzzleHttp\\Psr7\\Uri::isDefaultPort`\n\n`public static function isDefaultPort(UriInterface $uri): bool`\n\nWhether the URI has the default port of the current scheme. `Psr\\Http\\Message\\UriInterface::getPort` may return null\nor the standard port. This method can be used independently of the implementation.\n\n### `GuzzleHttp\\Psr7\\Uri::composeComponents`\n\n`public static function composeComponents($scheme, $authority, $path, $query, $fragment): string`\n\nComposes a URI reference string from its various components according to\n[RFC 3986 Section 5.3](https://tools.ietf.org/html/rfc3986#section-5.3). Usually this method does not need to be called\nmanually but instead is used indirectly via `Psr\\Http\\Message\\UriInterface::__toString`.\n\n### `GuzzleHttp\\Psr7\\Uri::fromParts`\n\n`public static function fromParts(array $parts): UriInterface`\n\nCreates a URI from a hash of [`parse_url`](https://www.php.net/manual/en/function.parse-url.php) components.\n\n\n### `GuzzleHttp\\Psr7\\Uri::withQueryValue`\n\n`public static function withQueryValue(UriInterface $uri, $key, $value): UriInterface`\n\nCreates a new URI with a specific query string value. Any existing query string values that exactly match the\nprovided key are removed and replaced with the given key value pair. A value of null will set the query string\nkey without a value, e.g. \"key\" instead of \"key=value\".\n\n### `GuzzleHttp\\Psr7\\Uri::withQueryValues`\n\n`public static function withQueryValues(UriInterface $uri, array $keyValueArray): UriInterface`\n\nCreates a new URI with multiple query string values. It has the same behavior as `withQueryValue()` but for an\nassociative array of key => value.\n\n### `GuzzleHttp\\Psr7\\Uri::withoutQueryValue`\n\n`public static function withoutQueryValue(UriInterface $uri, $key): UriInterface`\n\nCreates a new URI with a specific query string value removed. Any existing query string values that exactly match the\nprovided key are removed.\n\n## Cross-Origin Detection\n\n`GuzzleHttp\\Psr7\\UriComparator` provides methods to determine if a modified URL should be considered cross-origin.\n\n### `GuzzleHttp\\Psr7\\UriComparator::isCrossOrigin`\n\n`public static function isCrossOrigin(UriInterface $original, UriInterface $modified): bool`\n\nDetermines if a modified URL should be considered cross-origin with respect to an original URL.\n\n## Reference Resolution\n\n`GuzzleHttp\\Psr7\\UriResolver` provides methods to resolve a URI reference in the context of a base URI according\nto [RFC 3986 Section 5](https://tools.ietf.org/html/rfc3986#section-5). This is for example also what web browsers\ndo when resolving a link in a website based on the current request URI.\n\n### `GuzzleHttp\\Psr7\\UriResolver::resolve`\n\n`public static function resolve(UriInterface $base, UriInterface $rel): UriInterface`\n\nConverts the relative URI into a new URI that is resolved against the base URI.\n\n### `GuzzleHttp\\Psr7\\UriResolver::removeDotSegments`\n\n`public static function removeDotSegments(string $path): string`\n\nRemoves dot segments from a path and returns the new path according to\n[RFC 3986 Section 5.2.4](https://tools.ietf.org/html/rfc3986#section-5.2.4).\n\n### `GuzzleHttp\\Psr7\\UriResolver::relativize`\n\n`public static function relativize(UriInterface $base, UriInterface $target): UriInterface`\n\nReturns the target URI as a relative reference from the base URI. This method is the counterpart to resolve():\n\n```php\n(string) $target === (string) UriResolver::resolve($base, UriResolver::relativize($base, $target))\n```\n\nOne use-case is to use the current request URI as base URI and then generate relative links in your documents\nto reduce the document size or offer self-contained downloadable document archives.\n\n```php\n$base = new Uri('http://example.com/a/b/');\necho UriResolver::relativize($base, new Uri('http://example.com/a/b/c'));  // prints 'c'.\necho UriResolver::relativize($base, new Uri('http://example.com/a/x/y'));  // prints '../x/y'.\necho UriResolver::relativize($base, new Uri('http://example.com/a/b/?q')); // prints '?q'.\necho UriResolver::relativize($base, new Uri('http://example.org/a/b/'));   // prints '//example.org/a/b/'.\n```\n\n## Normalization and Comparison\n\n`GuzzleHttp\\Psr7\\UriNormalizer` provides methods to normalize and compare URIs according to\n[RFC 3986 Section 6](https://tools.ietf.org/html/rfc3986#section-6).\n\n### `GuzzleHttp\\Psr7\\UriNormalizer::normalize`\n\n`public static function normalize(UriInterface $uri, $flags = self::PRESERVING_NORMALIZATIONS): UriInterface`\n\nReturns a normalized URI. The scheme and host component are already normalized to lowercase per PSR-7 UriInterface.\nThis methods adds additional normalizations that can be configured with the `$flags` parameter which is a bitmask\nof normalizations to apply. The following normalizations are available:\n\n- `UriNormalizer::PRESERVING_NORMALIZATIONS`\n\n    Default normalizations which only include the ones that preserve semantics.\n\n- `UriNormalizer::CAPITALIZE_PERCENT_ENCODING`\n\n    All letters within a percent-encoding triplet (e.g., \"%3A\") are case-insensitive, and should be capitalized.\n\n    Example: `http://example.org/a%c2%b1b` → `http://example.org/a%C2%B1b`\n\n- `UriNormalizer::DECODE_UNRESERVED_CHARACTERS`\n\n    Decodes percent-encoded octets of unreserved characters. For consistency, percent-encoded octets in the ranges of\n    ALPHA (%41–%5A and %61–%7A), DIGIT (%30–%39), hyphen (%2D), period (%2E), underscore (%5F), or tilde (%7E) should\n    not be created by URI producers and, when found in a URI, should be decoded to their corresponding unreserved\n    characters by URI normalizers.\n\n    Example: `http://example.org/%7Eusern%61me/` → `http://example.org/~username/`\n\n- `UriNormalizer::CONVERT_EMPTY_PATH`\n\n    Converts the empty path to \"/\" for http and https URIs.\n\n    Example: `http://example.org` → `http://example.org/`\n\n- `UriNormalizer::REMOVE_DEFAULT_HOST`\n\n    Removes the default host of the given URI scheme from the URI. Only the \"file\" scheme defines the default host\n    \"localhost\". All of `file:/myfile`, `file:///myfile`, and `file://localhost/myfile` are equivalent according to\n    RFC 3986.\n\n    Example: `file://localhost/myfile` → `file:///myfile`\n\n- `UriNormalizer::REMOVE_DEFAULT_PORT`\n\n    Removes the default port of the given URI scheme from the URI.\n\n    Example: `http://example.org:80/` → `http://example.org/`\n\n- `UriNormalizer::REMOVE_DOT_SEGMENTS`\n\n    Removes unnecessary dot-segments. Dot-segments in relative-path references are not removed as it would\n    change the semantics of the URI reference.\n\n    Example: `http://example.org/../a/b/../c/./d.html` → `http://example.org/a/c/d.html`\n\n- `UriNormalizer::REMOVE_DUPLICATE_SLASHES`\n\n    Paths which include two or more adjacent slashes are converted to one. Webservers usually ignore duplicate slashes\n    and treat those URIs equivalent. But in theory those URIs do not need to be equivalent. So this normalization\n    may change the semantics. Encoded slashes (%2F) are not removed.\n\n    Example: `http://example.org//foo///bar.html` → `http://example.org/foo/bar.html`\n\n- `UriNormalizer::SORT_QUERY_PARAMETERS`\n\n    Sort query parameters with their values in alphabetical order. However, the order of parameters in a URI may be\n    significant (this is not defined by the standard). So this normalization is not safe and may change the semantics\n    of the URI.\n\n    Example: `?lang=en&article=fred` → `?article=fred&lang=en`\n\n### `GuzzleHttp\\Psr7\\UriNormalizer::isEquivalent`\n\n`public static function isEquivalent(UriInterface $uri1, UriInterface $uri2, $normalizations = self::PRESERVING_NORMALIZATIONS): bool`\n\nWhether two URIs can be considered equivalent. Both URIs are normalized automatically before comparison with the given\n`$normalizations` bitmask. The method also accepts relative URI references and returns true when they are equivalent.\nThis of course assumes they will be resolved against the same base URI. If this is not the case, determination of\nequivalence or difference of relative references does not mean anything.\n\n\n## Version Guidance\n\n| Version | Status         | PHP Version      |\n|---------|----------------|------------------|\n| 1.x     | Security fixes | >=5.4,<8.1       |\n| 2.x     | Latest         | ^7.2.5 \\|\\| ^8.0 |\n\n\n## Security\n\nIf you discover a security vulnerability within this package, please send an email to security@tidelift.com. All security vulnerabilities will be promptly addressed. Please do not disclose security-related issues publicly until a fix has been announced. Please see [Security Policy](https://github.com/guzzle/psr7/security/policy) for more information.\n\n\n## License\n\nGuzzle is made available under the MIT License (MIT). Please see [License File](LICENSE) for more information.\n\n\n## For Enterprise\n\nAvailable as part of the Tidelift Subscription\n\nThe maintainers of Guzzle and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/packagist-guzzlehttp-psr7?utm_source=packagist-guzzlehttp-psr7&utm_medium=referral&utm_campaign=enterprise&utm_term=repo)\n"
  },
  {
    "path": "server/vendor/guzzlehttp/psr7/composer.json",
    "content": "{\n    \"name\": \"guzzlehttp/psr7\",\n    \"description\": \"PSR-7 message implementation that also provides common utility methods\",\n    \"keywords\": [\"request\", \"response\", \"message\", \"stream\", \"http\", \"uri\", \"url\", \"psr-7\"],\n    \"license\": \"MIT\",\n    \"authors\": [\n        {\n            \"name\": \"Graham Campbell\",\n            \"email\": \"hello@gjcampbell.co.uk\",\n            \"homepage\": \"https://github.com/GrahamCampbell\"\n        },\n        {\n            \"name\": \"Michael Dowling\",\n            \"email\": \"mtdowling@gmail.com\",\n            \"homepage\": \"https://github.com/mtdowling\"\n        },\n        {\n            \"name\": \"George Mponos\",\n            \"email\": \"gmponos@gmail.com\",\n            \"homepage\": \"https://github.com/gmponos\"\n        },\n        {\n            \"name\": \"Tobias Nyholm\",\n            \"email\": \"tobias.nyholm@gmail.com\",\n            \"homepage\": \"https://github.com/Nyholm\"\n        },\n        {\n            \"name\": \"Márk Sági-Kazár\",\n            \"email\": \"mark.sagikazar@gmail.com\",\n            \"homepage\": \"https://github.com/sagikazarmark\"\n        },\n        {\n            \"name\": \"Tobias Schultze\",\n            \"email\": \"webmaster@tubo-world.de\",\n            \"homepage\": \"https://github.com/Tobion\"\n        }\n    ],\n    \"require\": {\n        \"php\": \">=5.4.0\",\n        \"psr/http-message\": \"~1.0\",\n        \"ralouphie/getallheaders\": \"^2.0.5 || ^3.0.0\"\n    },\n    \"require-dev\": {\n        \"phpunit/phpunit\": \"~4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.10\",\n        \"ext-zlib\": \"*\"\n    },\n    \"provide\": {\n        \"psr/http-message-implementation\": \"1.0\"\n    },\n    \"suggest\": {\n        \"laminas/laminas-httphandlerrunner\": \"Emit PSR-7 responses\"\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"GuzzleHttp\\\\Psr7\\\\\": \"src/\"\n        },\n        \"files\": [\"src/functions_include.php\"]\n    },\n    \"autoload-dev\": {\n        \"psr-4\": {\n            \"GuzzleHttp\\\\Tests\\\\Psr7\\\\\": \"tests/\"\n        }\n    },\n    \"config\": {\n        \"preferred-install\": \"dist\",\n        \"sort-packages\": true,\n        \"allow-plugins\": {\n            \"bamarni/composer-bin-plugin\": true\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/psr7/src/AppendStream.php",
    "content": "<?php\n\nnamespace GuzzleHttp\\Psr7;\n\nuse Psr\\Http\\Message\\StreamInterface;\n\n/**\n * Reads from multiple streams, one after the other.\n *\n * This is a read-only stream decorator.\n *\n * @final\n */\nclass AppendStream implements StreamInterface\n{\n    /** @var StreamInterface[] Streams being decorated */\n    private $streams = [];\n\n    private $seekable = true;\n    private $current = 0;\n    private $pos = 0;\n\n    /**\n     * @param StreamInterface[] $streams Streams to decorate. Each stream must\n     *                                   be readable.\n     */\n    public function __construct(array $streams = [])\n    {\n        foreach ($streams as $stream) {\n            $this->addStream($stream);\n        }\n    }\n\n    public function __toString()\n    {\n        try {\n            $this->rewind();\n            return $this->getContents();\n        } catch (\\Exception $e) {\n            return '';\n        }\n    }\n\n    /**\n     * Add a stream to the AppendStream\n     *\n     * @param StreamInterface $stream Stream to append. Must be readable.\n     *\n     * @throws \\InvalidArgumentException if the stream is not readable\n     */\n    public function addStream(StreamInterface $stream)\n    {\n        if (!$stream->isReadable()) {\n            throw new \\InvalidArgumentException('Each stream must be readable');\n        }\n\n        // The stream is only seekable if all streams are seekable\n        if (!$stream->isSeekable()) {\n            $this->seekable = false;\n        }\n\n        $this->streams[] = $stream;\n    }\n\n    public function getContents()\n    {\n        return Utils::copyToString($this);\n    }\n\n    /**\n     * Closes each attached stream.\n     *\n     * {@inheritdoc}\n     */\n    public function close()\n    {\n        $this->pos = $this->current = 0;\n        $this->seekable = true;\n\n        foreach ($this->streams as $stream) {\n            $stream->close();\n        }\n\n        $this->streams = [];\n    }\n\n    /**\n     * Detaches each attached stream.\n     *\n     * Returns null as it's not clear which underlying stream resource to return.\n     *\n     * {@inheritdoc}\n     */\n    public function detach()\n    {\n        $this->pos = $this->current = 0;\n        $this->seekable = true;\n\n        foreach ($this->streams as $stream) {\n            $stream->detach();\n        }\n\n        $this->streams = [];\n\n        return null;\n    }\n\n    public function tell()\n    {\n        return $this->pos;\n    }\n\n    /**\n     * Tries to calculate the size by adding the size of each stream.\n     *\n     * If any of the streams do not return a valid number, then the size of the\n     * append stream cannot be determined and null is returned.\n     *\n     * {@inheritdoc}\n     */\n    public function getSize()\n    {\n        $size = 0;\n\n        foreach ($this->streams as $stream) {\n            $s = $stream->getSize();\n            if ($s === null) {\n                return null;\n            }\n            $size += $s;\n        }\n\n        return $size;\n    }\n\n    public function eof()\n    {\n        return !$this->streams ||\n            ($this->current >= count($this->streams) - 1 &&\n             $this->streams[$this->current]->eof());\n    }\n\n    public function rewind()\n    {\n        $this->seek(0);\n    }\n\n    /**\n     * Attempts to seek to the given position. Only supports SEEK_SET.\n     *\n     * {@inheritdoc}\n     */\n    public function seek($offset, $whence = SEEK_SET)\n    {\n        if (!$this->seekable) {\n            throw new \\RuntimeException('This AppendStream is not seekable');\n        } elseif ($whence !== SEEK_SET) {\n            throw new \\RuntimeException('The AppendStream can only seek with SEEK_SET');\n        }\n\n        $this->pos = $this->current = 0;\n\n        // Rewind each stream\n        foreach ($this->streams as $i => $stream) {\n            try {\n                $stream->rewind();\n            } catch (\\Exception $e) {\n                throw new \\RuntimeException('Unable to seek stream '\n                    . $i . ' of the AppendStream', 0, $e);\n            }\n        }\n\n        // Seek to the actual position by reading from each stream\n        while ($this->pos < $offset && !$this->eof()) {\n            $result = $this->read(min(8096, $offset - $this->pos));\n            if ($result === '') {\n                break;\n            }\n        }\n    }\n\n    /**\n     * Reads from all of the appended streams until the length is met or EOF.\n     *\n     * {@inheritdoc}\n     */\n    public function read($length)\n    {\n        $buffer = '';\n        $total = count($this->streams) - 1;\n        $remaining = $length;\n        $progressToNext = false;\n\n        while ($remaining > 0) {\n\n            // Progress to the next stream if needed.\n            if ($progressToNext || $this->streams[$this->current]->eof()) {\n                $progressToNext = false;\n                if ($this->current === $total) {\n                    break;\n                }\n                $this->current++;\n            }\n\n            $result = $this->streams[$this->current]->read($remaining);\n\n            // Using a loose comparison here to match on '', false, and null\n            if ($result == null) {\n                $progressToNext = true;\n                continue;\n            }\n\n            $buffer .= $result;\n            $remaining = $length - strlen($buffer);\n        }\n\n        $this->pos += strlen($buffer);\n\n        return $buffer;\n    }\n\n    public function isReadable()\n    {\n        return true;\n    }\n\n    public function isWritable()\n    {\n        return false;\n    }\n\n    public function isSeekable()\n    {\n        return $this->seekable;\n    }\n\n    public function write($string)\n    {\n        throw new \\RuntimeException('Cannot write to an AppendStream');\n    }\n\n    public function getMetadata($key = null)\n    {\n        return $key ? null : [];\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/psr7/src/BufferStream.php",
    "content": "<?php\n\nnamespace GuzzleHttp\\Psr7;\n\nuse Psr\\Http\\Message\\StreamInterface;\n\n/**\n * Provides a buffer stream that can be written to to fill a buffer, and read\n * from to remove bytes from the buffer.\n *\n * This stream returns a \"hwm\" metadata value that tells upstream consumers\n * what the configured high water mark of the stream is, or the maximum\n * preferred size of the buffer.\n *\n * @final\n */\nclass BufferStream implements StreamInterface\n{\n    private $hwm;\n    private $buffer = '';\n\n    /**\n     * @param int $hwm High water mark, representing the preferred maximum\n     *                 buffer size. If the size of the buffer exceeds the high\n     *                 water mark, then calls to write will continue to succeed\n     *                 but will return false to inform writers to slow down\n     *                 until the buffer has been drained by reading from it.\n     */\n    public function __construct($hwm = 16384)\n    {\n        $this->hwm = $hwm;\n    }\n\n    public function __toString()\n    {\n        return $this->getContents();\n    }\n\n    public function getContents()\n    {\n        $buffer = $this->buffer;\n        $this->buffer = '';\n\n        return $buffer;\n    }\n\n    public function close()\n    {\n        $this->buffer = '';\n    }\n\n    public function detach()\n    {\n        $this->close();\n\n        return null;\n    }\n\n    public function getSize()\n    {\n        return strlen($this->buffer);\n    }\n\n    public function isReadable()\n    {\n        return true;\n    }\n\n    public function isWritable()\n    {\n        return true;\n    }\n\n    public function isSeekable()\n    {\n        return false;\n    }\n\n    public function rewind()\n    {\n        $this->seek(0);\n    }\n\n    public function seek($offset, $whence = SEEK_SET)\n    {\n        throw new \\RuntimeException('Cannot seek a BufferStream');\n    }\n\n    public function eof()\n    {\n        return strlen($this->buffer) === 0;\n    }\n\n    public function tell()\n    {\n        throw new \\RuntimeException('Cannot determine the position of a BufferStream');\n    }\n\n    /**\n     * Reads data from the buffer.\n     */\n    public function read($length)\n    {\n        $currentLength = strlen($this->buffer);\n\n        if ($length >= $currentLength) {\n            // No need to slice the buffer because we don't have enough data.\n            $result = $this->buffer;\n            $this->buffer = '';\n        } else {\n            // Slice up the result to provide a subset of the buffer.\n            $result = substr($this->buffer, 0, $length);\n            $this->buffer = substr($this->buffer, $length);\n        }\n\n        return $result;\n    }\n\n    /**\n     * Writes data to the buffer.\n     */\n    public function write($string)\n    {\n        $this->buffer .= $string;\n\n        // TODO: What should happen here?\n        if (strlen($this->buffer) >= $this->hwm) {\n            return false;\n        }\n\n        return strlen($string);\n    }\n\n    public function getMetadata($key = null)\n    {\n        if ($key == 'hwm') {\n            return $this->hwm;\n        }\n\n        return $key ? null : [];\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/psr7/src/CachingStream.php",
    "content": "<?php\n\nnamespace GuzzleHttp\\Psr7;\n\nuse Psr\\Http\\Message\\StreamInterface;\n\n/**\n * Stream decorator that can cache previously read bytes from a sequentially\n * read stream.\n *\n * @final\n */\nclass CachingStream implements StreamInterface\n{\n    use StreamDecoratorTrait;\n\n    /** @var StreamInterface Stream being wrapped */\n    private $remoteStream;\n\n    /** @var int Number of bytes to skip reading due to a write on the buffer */\n    private $skipReadBytes = 0;\n\n    /**\n     * We will treat the buffer object as the body of the stream\n     *\n     * @param StreamInterface $stream Stream to cache. The cursor is assumed to be at the beginning of the stream.\n     * @param StreamInterface $target Optionally specify where data is cached\n     */\n    public function __construct(\n        StreamInterface $stream,\n        StreamInterface $target = null\n    ) {\n        $this->remoteStream = $stream;\n        $this->stream = $target ?: new Stream(Utils::tryFopen('php://temp', 'r+'));\n    }\n\n    public function getSize()\n    {\n        $remoteSize = $this->remoteStream->getSize();\n\n        if (null === $remoteSize) {\n            return null;\n        }\n\n        return max($this->stream->getSize(), $remoteSize);\n    }\n\n    public function rewind()\n    {\n        $this->seek(0);\n    }\n\n    public function seek($offset, $whence = SEEK_SET)\n    {\n        if ($whence == SEEK_SET) {\n            $byte = $offset;\n        } elseif ($whence == SEEK_CUR) {\n            $byte = $offset + $this->tell();\n        } elseif ($whence == SEEK_END) {\n            $size = $this->remoteStream->getSize();\n            if ($size === null) {\n                $size = $this->cacheEntireStream();\n            }\n            $byte = $size + $offset;\n        } else {\n            throw new \\InvalidArgumentException('Invalid whence');\n        }\n\n        $diff = $byte - $this->stream->getSize();\n\n        if ($diff > 0) {\n            // Read the remoteStream until we have read in at least the amount\n            // of bytes requested, or we reach the end of the file.\n            while ($diff > 0 && !$this->remoteStream->eof()) {\n                $this->read($diff);\n                $diff = $byte - $this->stream->getSize();\n            }\n        } else {\n            // We can just do a normal seek since we've already seen this byte.\n            $this->stream->seek($byte);\n        }\n    }\n\n    public function read($length)\n    {\n        // Perform a regular read on any previously read data from the buffer\n        $data = $this->stream->read($length);\n        $remaining = $length - strlen($data);\n\n        // More data was requested so read from the remote stream\n        if ($remaining) {\n            // If data was written to the buffer in a position that would have\n            // been filled from the remote stream, then we must skip bytes on\n            // the remote stream to emulate overwriting bytes from that\n            // position. This mimics the behavior of other PHP stream wrappers.\n            $remoteData = $this->remoteStream->read(\n                $remaining + $this->skipReadBytes\n            );\n\n            if ($this->skipReadBytes) {\n                $len = strlen($remoteData);\n                $remoteData = substr($remoteData, $this->skipReadBytes);\n                $this->skipReadBytes = max(0, $this->skipReadBytes - $len);\n            }\n\n            $data .= $remoteData;\n            $this->stream->write($remoteData);\n        }\n\n        return $data;\n    }\n\n    public function write($string)\n    {\n        // When appending to the end of the currently read stream, you'll want\n        // to skip bytes from being read from the remote stream to emulate\n        // other stream wrappers. Basically replacing bytes of data of a fixed\n        // length.\n        $overflow = (strlen($string) + $this->tell()) - $this->remoteStream->tell();\n        if ($overflow > 0) {\n            $this->skipReadBytes += $overflow;\n        }\n\n        return $this->stream->write($string);\n    }\n\n    public function eof()\n    {\n        return $this->stream->eof() && $this->remoteStream->eof();\n    }\n\n    /**\n     * Close both the remote stream and buffer stream\n     */\n    public function close()\n    {\n        $this->remoteStream->close() && $this->stream->close();\n    }\n\n    private function cacheEntireStream()\n    {\n        $target = new FnStream(['write' => 'strlen']);\n        Utils::copyToStream($this, $target);\n\n        return $this->tell();\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/psr7/src/DroppingStream.php",
    "content": "<?php\n\nnamespace GuzzleHttp\\Psr7;\n\nuse Psr\\Http\\Message\\StreamInterface;\n\n/**\n * Stream decorator that begins dropping data once the size of the underlying\n * stream becomes too full.\n *\n * @final\n */\nclass DroppingStream implements StreamInterface\n{\n    use StreamDecoratorTrait;\n\n    private $maxLength;\n\n    /**\n     * @param StreamInterface $stream    Underlying stream to decorate.\n     * @param int             $maxLength Maximum size before dropping data.\n     */\n    public function __construct(StreamInterface $stream, $maxLength)\n    {\n        $this->stream = $stream;\n        $this->maxLength = $maxLength;\n    }\n\n    public function write($string)\n    {\n        $diff = $this->maxLength - $this->stream->getSize();\n\n        // Begin returning 0 when the underlying stream is too large.\n        if ($diff <= 0) {\n            return 0;\n        }\n\n        // Write the stream or a subset of the stream if needed.\n        if (strlen($string) < $diff) {\n            return $this->stream->write($string);\n        }\n\n        return $this->stream->write(substr($string, 0, $diff));\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/psr7/src/FnStream.php",
    "content": "<?php\n\nnamespace GuzzleHttp\\Psr7;\n\nuse Psr\\Http\\Message\\StreamInterface;\n\n/**\n * Compose stream implementations based on a hash of functions.\n *\n * Allows for easy testing and extension of a provided stream without needing\n * to create a concrete class for a simple extension point.\n *\n * @final\n */\nclass FnStream implements StreamInterface\n{\n    /** @var array */\n    private $methods;\n\n    /** @var array Methods that must be implemented in the given array */\n    private static $slots = ['__toString', 'close', 'detach', 'rewind',\n        'getSize', 'tell', 'eof', 'isSeekable', 'seek', 'isWritable', 'write',\n        'isReadable', 'read', 'getContents', 'getMetadata'];\n\n    /**\n     * @param array $methods Hash of method name to a callable.\n     */\n    public function __construct(array $methods)\n    {\n        $this->methods = $methods;\n\n        // Create the functions on the class\n        foreach ($methods as $name => $fn) {\n            $this->{'_fn_' . $name} = $fn;\n        }\n    }\n\n    /**\n     * Lazily determine which methods are not implemented.\n     *\n     * @throws \\BadMethodCallException\n     */\n    public function __get($name)\n    {\n        throw new \\BadMethodCallException(str_replace('_fn_', '', $name)\n            . '() is not implemented in the FnStream');\n    }\n\n    /**\n     * The close method is called on the underlying stream only if possible.\n     */\n    public function __destruct()\n    {\n        if (isset($this->_fn_close)) {\n            call_user_func($this->_fn_close);\n        }\n    }\n\n    /**\n     * An unserialize would allow the __destruct to run when the unserialized value goes out of scope.\n     *\n     * @throws \\LogicException\n     */\n    public function __wakeup()\n    {\n        throw new \\LogicException('FnStream should never be unserialized');\n    }\n\n    /**\n     * Adds custom functionality to an underlying stream by intercepting\n     * specific method calls.\n     *\n     * @param StreamInterface $stream  Stream to decorate\n     * @param array           $methods Hash of method name to a closure\n     *\n     * @return FnStream\n     */\n    public static function decorate(StreamInterface $stream, array $methods)\n    {\n        // If any of the required methods were not provided, then simply\n        // proxy to the decorated stream.\n        foreach (array_diff(self::$slots, array_keys($methods)) as $diff) {\n            $methods[$diff] = [$stream, $diff];\n        }\n\n        return new self($methods);\n    }\n\n    public function __toString()\n    {\n        return call_user_func($this->_fn___toString);\n    }\n\n    public function close()\n    {\n        return call_user_func($this->_fn_close);\n    }\n\n    public function detach()\n    {\n        return call_user_func($this->_fn_detach);\n    }\n\n    public function getSize()\n    {\n        return call_user_func($this->_fn_getSize);\n    }\n\n    public function tell()\n    {\n        return call_user_func($this->_fn_tell);\n    }\n\n    public function eof()\n    {\n        return call_user_func($this->_fn_eof);\n    }\n\n    public function isSeekable()\n    {\n        return call_user_func($this->_fn_isSeekable);\n    }\n\n    public function rewind()\n    {\n        call_user_func($this->_fn_rewind);\n    }\n\n    public function seek($offset, $whence = SEEK_SET)\n    {\n        call_user_func($this->_fn_seek, $offset, $whence);\n    }\n\n    public function isWritable()\n    {\n        return call_user_func($this->_fn_isWritable);\n    }\n\n    public function write($string)\n    {\n        return call_user_func($this->_fn_write, $string);\n    }\n\n    public function isReadable()\n    {\n        return call_user_func($this->_fn_isReadable);\n    }\n\n    public function read($length)\n    {\n        return call_user_func($this->_fn_read, $length);\n    }\n\n    public function getContents()\n    {\n        return call_user_func($this->_fn_getContents);\n    }\n\n    public function getMetadata($key = null)\n    {\n        return call_user_func($this->_fn_getMetadata, $key);\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/psr7/src/Header.php",
    "content": "<?php\n\nnamespace GuzzleHttp\\Psr7;\n\nfinal class Header\n{\n    /**\n     * Parse an array of header values containing \";\" separated data into an\n     * array of associative arrays representing the header key value pair data\n     * of the header. When a parameter does not contain a value, but just\n     * contains a key, this function will inject a key with a '' string value.\n     *\n     * @param string|array $header Header to parse into components.\n     *\n     * @return array Returns the parsed header values.\n     */\n    public static function parse($header)\n    {\n        static $trimmed = \"\\\"'  \\n\\t\\r\";\n        $params = $matches = [];\n\n        foreach (self::normalize($header) as $val) {\n            $part = [];\n            foreach (preg_split('/;(?=([^\"]*\"[^\"]*\")*[^\"]*$)/', $val) as $kvp) {\n                if (preg_match_all('/<[^>]+>|[^=]+/', $kvp, $matches)) {\n                    $m = $matches[0];\n                    if (isset($m[1])) {\n                        $part[trim($m[0], $trimmed)] = trim($m[1], $trimmed);\n                    } else {\n                        $part[] = trim($m[0], $trimmed);\n                    }\n                }\n            }\n            if ($part) {\n                $params[] = $part;\n            }\n        }\n\n        return $params;\n    }\n\n    /**\n     * Converts an array of header values that may contain comma separated\n     * headers into an array of headers with no comma separated values.\n     *\n     * @param string|array $header Header to normalize.\n     *\n     * @return array Returns the normalized header field values.\n     */\n    public static function normalize($header)\n    {\n        if (!is_array($header)) {\n            return array_map('trim', explode(',', $header));\n        }\n\n        $result = [];\n        foreach ($header as $value) {\n            foreach ((array) $value as $v) {\n                if (strpos($v, ',') === false) {\n                    $result[] = $v;\n                    continue;\n                }\n                foreach (preg_split('/,(?=([^\"]*\"[^\"]*\")*[^\"]*$)/', $v) as $vv) {\n                    $result[] = trim($vv);\n                }\n            }\n        }\n\n        return $result;\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/psr7/src/InflateStream.php",
    "content": "<?php\n\nnamespace GuzzleHttp\\Psr7;\n\nuse Psr\\Http\\Message\\StreamInterface;\n\n/**\n * Uses PHP's zlib.inflate filter to inflate deflate or gzipped content.\n *\n * This stream decorator skips the first 10 bytes of the given stream to remove\n * the gzip header, converts the provided stream to a PHP stream resource,\n * then appends the zlib.inflate filter. The stream is then converted back\n * to a Guzzle stream resource to be used as a Guzzle stream.\n *\n * @link http://tools.ietf.org/html/rfc1952\n * @link http://php.net/manual/en/filters.compression.php\n *\n * @final\n */\nclass InflateStream implements StreamInterface\n{\n    use StreamDecoratorTrait;\n\n    public function __construct(StreamInterface $stream)\n    {\n        // read the first 10 bytes, ie. gzip header\n        $header = $stream->read(10);\n        $filenameHeaderLength = $this->getLengthOfPossibleFilenameHeader($stream, $header);\n        // Skip the header, that is 10 + length of filename + 1 (nil) bytes\n        $stream = new LimitStream($stream, -1, 10 + $filenameHeaderLength);\n        $resource = StreamWrapper::getResource($stream);\n        stream_filter_append($resource, 'zlib.inflate', STREAM_FILTER_READ);\n        $this->stream = $stream->isSeekable() ? new Stream($resource) : new NoSeekStream(new Stream($resource));\n    }\n\n    /**\n     * @param StreamInterface $stream\n     * @param $header\n     *\n     * @return int\n     */\n    private function getLengthOfPossibleFilenameHeader(StreamInterface $stream, $header)\n    {\n        $filename_header_length = 0;\n\n        if (substr(bin2hex($header), 6, 2) === '08') {\n            // we have a filename, read until nil\n            $filename_header_length = 1;\n            while ($stream->read(1) !== chr(0)) {\n                $filename_header_length++;\n            }\n        }\n\n        return $filename_header_length;\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/psr7/src/LazyOpenStream.php",
    "content": "<?php\n\nnamespace GuzzleHttp\\Psr7;\n\nuse Psr\\Http\\Message\\StreamInterface;\n\n/**\n * Lazily reads or writes to a file that is opened only after an IO operation\n * take place on the stream.\n *\n * @final\n */\nclass LazyOpenStream implements StreamInterface\n{\n    use StreamDecoratorTrait;\n\n    /** @var string File to open */\n    private $filename;\n\n    /** @var string */\n    private $mode;\n\n    /**\n     * @param string $filename File to lazily open\n     * @param string $mode     fopen mode to use when opening the stream\n     */\n    public function __construct($filename, $mode)\n    {\n        $this->filename = $filename;\n        $this->mode = $mode;\n    }\n\n    /**\n     * Creates the underlying stream lazily when required.\n     *\n     * @return StreamInterface\n     */\n    protected function createStream()\n    {\n        return Utils::streamFor(Utils::tryFopen($this->filename, $this->mode));\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/psr7/src/LimitStream.php",
    "content": "<?php\n\nnamespace GuzzleHttp\\Psr7;\n\nuse Psr\\Http\\Message\\StreamInterface;\n\n/**\n * Decorator used to return only a subset of a stream.\n *\n * @final\n */\nclass LimitStream implements StreamInterface\n{\n    use StreamDecoratorTrait;\n\n    /** @var int Offset to start reading from */\n    private $offset;\n\n    /** @var int Limit the number of bytes that can be read */\n    private $limit;\n\n    /**\n     * @param StreamInterface $stream Stream to wrap\n     * @param int             $limit  Total number of bytes to allow to be read\n     *                                from the stream. Pass -1 for no limit.\n     * @param int             $offset Position to seek to before reading (only\n     *                                works on seekable streams).\n     */\n    public function __construct(\n        StreamInterface $stream,\n        $limit = -1,\n        $offset = 0\n    ) {\n        $this->stream = $stream;\n        $this->setLimit($limit);\n        $this->setOffset($offset);\n    }\n\n    public function eof()\n    {\n        // Always return true if the underlying stream is EOF\n        if ($this->stream->eof()) {\n            return true;\n        }\n\n        // No limit and the underlying stream is not at EOF\n        if ($this->limit == -1) {\n            return false;\n        }\n\n        return $this->stream->tell() >= $this->offset + $this->limit;\n    }\n\n    /**\n     * Returns the size of the limited subset of data\n     * {@inheritdoc}\n     */\n    public function getSize()\n    {\n        if (null === ($length = $this->stream->getSize())) {\n            return null;\n        } elseif ($this->limit == -1) {\n            return $length - $this->offset;\n        } else {\n            return min($this->limit, $length - $this->offset);\n        }\n    }\n\n    /**\n     * Allow for a bounded seek on the read limited stream\n     * {@inheritdoc}\n     */\n    public function seek($offset, $whence = SEEK_SET)\n    {\n        if ($whence !== SEEK_SET || $offset < 0) {\n            throw new \\RuntimeException(sprintf(\n                'Cannot seek to offset %s with whence %s',\n                $offset,\n                $whence\n            ));\n        }\n\n        $offset += $this->offset;\n\n        if ($this->limit !== -1) {\n            if ($offset > $this->offset + $this->limit) {\n                $offset = $this->offset + $this->limit;\n            }\n        }\n\n        $this->stream->seek($offset);\n    }\n\n    /**\n     * Give a relative tell()\n     * {@inheritdoc}\n     */\n    public function tell()\n    {\n        return $this->stream->tell() - $this->offset;\n    }\n\n    /**\n     * Set the offset to start limiting from\n     *\n     * @param int $offset Offset to seek to and begin byte limiting from\n     *\n     * @throws \\RuntimeException if the stream cannot be seeked.\n     */\n    public function setOffset($offset)\n    {\n        $current = $this->stream->tell();\n\n        if ($current !== $offset) {\n            // If the stream cannot seek to the offset position, then read to it\n            if ($this->stream->isSeekable()) {\n                $this->stream->seek($offset);\n            } elseif ($current > $offset) {\n                throw new \\RuntimeException(\"Could not seek to stream offset $offset\");\n            } else {\n                $this->stream->read($offset - $current);\n            }\n        }\n\n        $this->offset = $offset;\n    }\n\n    /**\n     * Set the limit of bytes that the decorator allows to be read from the\n     * stream.\n     *\n     * @param int $limit Number of bytes to allow to be read from the stream.\n     *                   Use -1 for no limit.\n     */\n    public function setLimit($limit)\n    {\n        $this->limit = $limit;\n    }\n\n    public function read($length)\n    {\n        if ($this->limit == -1) {\n            return $this->stream->read($length);\n        }\n\n        // Check if the current position is less than the total allowed\n        // bytes + original offset\n        $remaining = ($this->offset + $this->limit) - $this->stream->tell();\n        if ($remaining > 0) {\n            // Only return the amount of requested data, ensuring that the byte\n            // limit is not exceeded\n            return $this->stream->read(min($remaining, $length));\n        }\n\n        return '';\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/psr7/src/Message.php",
    "content": "<?php\n\nnamespace GuzzleHttp\\Psr7;\n\nuse Psr\\Http\\Message\\MessageInterface;\nuse Psr\\Http\\Message\\RequestInterface;\nuse Psr\\Http\\Message\\ResponseInterface;\n\nfinal class Message\n{\n    /**\n     * Returns the string representation of an HTTP message.\n     *\n     * @param MessageInterface $message Message to convert to a string.\n     *\n     * @return string\n     */\n    public static function toString(MessageInterface $message)\n    {\n        if ($message instanceof RequestInterface) {\n            $msg = trim($message->getMethod() . ' '\n                    . $message->getRequestTarget())\n                . ' HTTP/' . $message->getProtocolVersion();\n            if (!$message->hasHeader('host')) {\n                $msg .= \"\\r\\nHost: \" . $message->getUri()->getHost();\n            }\n        } elseif ($message instanceof ResponseInterface) {\n            $msg = 'HTTP/' . $message->getProtocolVersion() . ' '\n                . $message->getStatusCode() . ' '\n                . $message->getReasonPhrase();\n        } else {\n            throw new \\InvalidArgumentException('Unknown message type');\n        }\n\n        foreach ($message->getHeaders() as $name => $values) {\n            if (strtolower($name) === 'set-cookie') {\n                foreach ($values as $value) {\n                    $msg .= \"\\r\\n{$name}: \" . $value;\n                }\n            } else {\n                $msg .= \"\\r\\n{$name}: \" . implode(', ', $values);\n            }\n        }\n\n        return \"{$msg}\\r\\n\\r\\n\" . $message->getBody();\n    }\n\n    /**\n     * Get a short summary of the message body.\n     *\n     * Will return `null` if the response is not printable.\n     *\n     * @param MessageInterface $message    The message to get the body summary\n     * @param int              $truncateAt The maximum allowed size of the summary\n     *\n     * @return string|null\n     */\n    public static function bodySummary(MessageInterface $message, $truncateAt = 120)\n    {\n        $body = $message->getBody();\n\n        if (!$body->isSeekable() || !$body->isReadable()) {\n            return null;\n        }\n\n        $size = $body->getSize();\n\n        if ($size === 0) {\n            return null;\n        }\n\n        $summary = $body->read($truncateAt);\n        $body->rewind();\n\n        if ($size > $truncateAt) {\n            $summary .= ' (truncated...)';\n        }\n\n        // Matches any printable character, including unicode characters:\n        // letters, marks, numbers, punctuation, spacing, and separators.\n        if (preg_match('/[^\\pL\\pM\\pN\\pP\\pS\\pZ\\n\\r\\t]/u', $summary)) {\n            return null;\n        }\n\n        return $summary;\n    }\n\n    /**\n     * Attempts to rewind a message body and throws an exception on failure.\n     *\n     * The body of the message will only be rewound if a call to `tell()`\n     * returns a value other than `0`.\n     *\n     * @param MessageInterface $message Message to rewind\n     *\n     * @throws \\RuntimeException\n     */\n    public static function rewindBody(MessageInterface $message)\n    {\n        $body = $message->getBody();\n\n        if ($body->tell()) {\n            $body->rewind();\n        }\n    }\n\n    /**\n     * Parses an HTTP message into an associative array.\n     *\n     * The array contains the \"start-line\" key containing the start line of\n     * the message, \"headers\" key containing an associative array of header\n     * array values, and a \"body\" key containing the body of the message.\n     *\n     * @param string $message HTTP request or response to parse.\n     *\n     * @return array\n     */\n    public static function parseMessage($message)\n    {\n        if (!$message) {\n            throw new \\InvalidArgumentException('Invalid message');\n        }\n\n        $message = ltrim($message, \"\\r\\n\");\n\n        $messageParts = preg_split(\"/\\r?\\n\\r?\\n/\", $message, 2);\n\n        if ($messageParts === false || count($messageParts) !== 2) {\n            throw new \\InvalidArgumentException('Invalid message: Missing header delimiter');\n        }\n\n        list($rawHeaders, $body) = $messageParts;\n        $rawHeaders .= \"\\r\\n\"; // Put back the delimiter we split previously\n        $headerParts = preg_split(\"/\\r?\\n/\", $rawHeaders, 2);\n\n        if ($headerParts === false || count($headerParts) !== 2) {\n            throw new \\InvalidArgumentException('Invalid message: Missing status line');\n        }\n\n        list($startLine, $rawHeaders) = $headerParts;\n\n        if (preg_match(\"/(?:^HTTP\\/|^[A-Z]+ \\S+ HTTP\\/)(\\d+(?:\\.\\d+)?)/i\", $startLine, $matches) && $matches[1] === '1.0') {\n            // Header folding is deprecated for HTTP/1.1, but allowed in HTTP/1.0\n            $rawHeaders = preg_replace(Rfc7230::HEADER_FOLD_REGEX, ' ', $rawHeaders);\n        }\n\n        /** @var array[] $headerLines */\n        $count = preg_match_all(Rfc7230::HEADER_REGEX, $rawHeaders, $headerLines, PREG_SET_ORDER);\n\n        // If these aren't the same, then one line didn't match and there's an invalid header.\n        if ($count !== substr_count($rawHeaders, \"\\n\")) {\n            // Folding is deprecated, see https://tools.ietf.org/html/rfc7230#section-3.2.4\n            if (preg_match(Rfc7230::HEADER_FOLD_REGEX, $rawHeaders)) {\n                throw new \\InvalidArgumentException('Invalid header syntax: Obsolete line folding');\n            }\n\n            throw new \\InvalidArgumentException('Invalid header syntax');\n        }\n\n        $headers = [];\n\n        foreach ($headerLines as $headerLine) {\n            $headers[$headerLine[1]][] = $headerLine[2];\n        }\n\n        return [\n            'start-line' => $startLine,\n            'headers' => $headers,\n            'body' => $body,\n        ];\n    }\n\n    /**\n     * Constructs a URI for an HTTP request message.\n     *\n     * @param string $path    Path from the start-line\n     * @param array  $headers Array of headers (each value an array).\n     *\n     * @return string\n     */\n    public static function parseRequestUri($path, array $headers)\n    {\n        $hostKey = array_filter(array_keys($headers), function ($k) {\n            return strtolower($k) === 'host';\n        });\n\n        // If no host is found, then a full URI cannot be constructed.\n        if (!$hostKey) {\n            return $path;\n        }\n\n        $host = $headers[reset($hostKey)][0];\n        $scheme = substr($host, -4) === ':443' ? 'https' : 'http';\n\n        return $scheme . '://' . $host . '/' . ltrim($path, '/');\n    }\n\n    /**\n     * Parses a request message string into a request object.\n     *\n     * @param string $message Request message string.\n     *\n     * @return Request\n     */\n    public static function parseRequest($message)\n    {\n        $data = self::parseMessage($message);\n        $matches = [];\n        if (!preg_match('/^[\\S]+\\s+([a-zA-Z]+:\\/\\/|\\/).*/', $data['start-line'], $matches)) {\n            throw new \\InvalidArgumentException('Invalid request string');\n        }\n        $parts = explode(' ', $data['start-line'], 3);\n        $version = isset($parts[2]) ? explode('/', $parts[2])[1] : '1.1';\n\n        $request = new Request(\n            $parts[0],\n            $matches[1] === '/' ? self::parseRequestUri($parts[1], $data['headers']) : $parts[1],\n            $data['headers'],\n            $data['body'],\n            $version\n        );\n\n        return $matches[1] === '/' ? $request : $request->withRequestTarget($parts[1]);\n    }\n\n    /**\n     * Parses a response message string into a response object.\n     *\n     * @param string $message Response message string.\n     *\n     * @return Response\n     */\n    public static function parseResponse($message)\n    {\n        $data = self::parseMessage($message);\n        // According to https://tools.ietf.org/html/rfc7230#section-3.1.2 the space\n        // between status-code and reason-phrase is required. But browsers accept\n        // responses without space and reason as well.\n        if (!preg_match('/^HTTP\\/.* [0-9]{3}( .*|$)/', $data['start-line'])) {\n            throw new \\InvalidArgumentException('Invalid response string: ' . $data['start-line']);\n        }\n        $parts = explode(' ', $data['start-line'], 3);\n\n        return new Response(\n            (int) $parts[1],\n            $data['headers'],\n            $data['body'],\n            explode('/', $parts[0])[1],\n            isset($parts[2]) ? $parts[2] : null\n        );\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/psr7/src/MessageTrait.php",
    "content": "<?php\n\nnamespace GuzzleHttp\\Psr7;\n\nuse Psr\\Http\\Message\\StreamInterface;\n\n/**\n * Trait implementing functionality common to requests and responses.\n */\ntrait MessageTrait\n{\n    /** @var array Map of all registered headers, as original name => array of values */\n    private $headers = [];\n\n    /** @var array Map of lowercase header name => original name at registration */\n    private $headerNames  = [];\n\n    /** @var string */\n    private $protocol = '1.1';\n\n    /** @var StreamInterface|null */\n    private $stream;\n\n    public function getProtocolVersion()\n    {\n        return $this->protocol;\n    }\n\n    public function withProtocolVersion($version)\n    {\n        if ($this->protocol === $version) {\n            return $this;\n        }\n\n        $new = clone $this;\n        $new->protocol = $version;\n        return $new;\n    }\n\n    public function getHeaders()\n    {\n        return $this->headers;\n    }\n\n    public function hasHeader($header)\n    {\n        return isset($this->headerNames[strtolower($header)]);\n    }\n\n    public function getHeader($header)\n    {\n        $header = strtolower($header);\n\n        if (!isset($this->headerNames[$header])) {\n            return [];\n        }\n\n        $header = $this->headerNames[$header];\n\n        return $this->headers[$header];\n    }\n\n    public function getHeaderLine($header)\n    {\n        return implode(', ', $this->getHeader($header));\n    }\n\n    public function withHeader($header, $value)\n    {\n        $this->assertHeader($header);\n        $value = $this->normalizeHeaderValue($value);\n        $normalized = strtolower($header);\n\n        $new = clone $this;\n        if (isset($new->headerNames[$normalized])) {\n            unset($new->headers[$new->headerNames[$normalized]]);\n        }\n        $new->headerNames[$normalized] = $header;\n        $new->headers[$header] = $value;\n\n        return $new;\n    }\n\n    public function withAddedHeader($header, $value)\n    {\n        $this->assertHeader($header);\n        $value = $this->normalizeHeaderValue($value);\n        $normalized = strtolower($header);\n\n        $new = clone $this;\n        if (isset($new->headerNames[$normalized])) {\n            $header = $this->headerNames[$normalized];\n            $new->headers[$header] = array_merge($this->headers[$header], $value);\n        } else {\n            $new->headerNames[$normalized] = $header;\n            $new->headers[$header] = $value;\n        }\n\n        return $new;\n    }\n\n    public function withoutHeader($header)\n    {\n        $normalized = strtolower($header);\n\n        if (!isset($this->headerNames[$normalized])) {\n            return $this;\n        }\n\n        $header = $this->headerNames[$normalized];\n\n        $new = clone $this;\n        unset($new->headers[$header], $new->headerNames[$normalized]);\n\n        return $new;\n    }\n\n    public function getBody()\n    {\n        if (!$this->stream) {\n            $this->stream = Utils::streamFor('');\n        }\n\n        return $this->stream;\n    }\n\n    public function withBody(StreamInterface $body)\n    {\n        if ($body === $this->stream) {\n            return $this;\n        }\n\n        $new = clone $this;\n        $new->stream = $body;\n        return $new;\n    }\n\n    private function setHeaders(array $headers)\n    {\n        $this->headerNames = $this->headers = [];\n        foreach ($headers as $header => $value) {\n            if (is_int($header)) {\n                // Numeric array keys are converted to int by PHP but having a header name '123' is not forbidden by the spec\n                // and also allowed in withHeader(). So we need to cast it to string again for the following assertion to pass.\n                $header = (string) $header;\n            }\n            $this->assertHeader($header);\n            $value = $this->normalizeHeaderValue($value);\n            $normalized = strtolower($header);\n            if (isset($this->headerNames[$normalized])) {\n                $header = $this->headerNames[$normalized];\n                $this->headers[$header] = array_merge($this->headers[$header], $value);\n            } else {\n                $this->headerNames[$normalized] = $header;\n                $this->headers[$header] = $value;\n            }\n        }\n    }\n\n    /**\n     * @param mixed $value\n     *\n     * @return string[]\n     */\n    private function normalizeHeaderValue($value)\n    {\n        if (!is_array($value)) {\n            return $this->trimAndValidateHeaderValues([$value]);\n        }\n\n        if (count($value) === 0) {\n            throw new \\InvalidArgumentException('Header value can not be an empty array.');\n        }\n\n        return $this->trimAndValidateHeaderValues($value);\n    }\n\n    /**\n     * Trims whitespace from the header values.\n     *\n     * Spaces and tabs ought to be excluded by parsers when extracting the field value from a header field.\n     *\n     * header-field = field-name \":\" OWS field-value OWS\n     * OWS          = *( SP / HTAB )\n     *\n     * @param mixed[] $values Header values\n     *\n     * @return string[] Trimmed header values\n     *\n     * @see https://tools.ietf.org/html/rfc7230#section-3.2.4\n     */\n    private function trimAndValidateHeaderValues(array $values)\n    {\n        return array_map(function ($value) {\n            if (!is_scalar($value) && null !== $value) {\n                throw new \\InvalidArgumentException(sprintf(\n                    'Header value must be scalar or null but %s provided.',\n                    is_object($value) ? get_class($value) : gettype($value)\n                ));\n            }\n\n            $trimmed = trim((string) $value, \" \\t\");\n            $this->assertValue($trimmed);\n\n            return $trimmed;\n        }, array_values($values));\n    }\n\n    /**\n     * @see https://tools.ietf.org/html/rfc7230#section-3.2\n     *\n     * @param mixed $header\n     *\n     * @return void\n     */\n    private function assertHeader($header)\n    {\n        if (!is_string($header)) {\n            throw new \\InvalidArgumentException(sprintf(\n                'Header name must be a string but %s provided.',\n                is_object($header) ? get_class($header) : gettype($header)\n            ));\n        }\n\n        if ($header === '') {\n            throw new \\InvalidArgumentException('Header name can not be empty.');\n        }\n\n        if (! preg_match('/^[a-zA-Z0-9\\'`#$%&*+.^_|~!-]+$/D', $header)) {\n            throw new \\InvalidArgumentException(\n                sprintf('\"%s\" is not valid header name.', $header)\n            );\n        }\n    }\n\n    /**\n     * @param string $value\n     *\n     * @return void\n     *\n     * @see https://tools.ietf.org/html/rfc7230#section-3.2\n     *\n     * field-value    = *( field-content / obs-fold )\n     * field-content  = field-vchar [ 1*( SP / HTAB ) field-vchar ]\n     * field-vchar    = VCHAR / obs-text\n     * VCHAR          = %x21-7E\n     * obs-text       = %x80-FF\n     * obs-fold       = CRLF 1*( SP / HTAB )\n     */\n    private function assertValue($value)\n    {\n        // The regular expression intentionally does not support the obs-fold production, because as\n        // per RFC 7230#3.2.4:\n        //\n        // A sender MUST NOT generate a message that includes\n        // line folding (i.e., that has any field-value that contains a match to\n        // the obs-fold rule) unless the message is intended for packaging\n        // within the message/http media type.\n        //\n        // Clients must not send a request with line folding and a server sending folded headers is\n        // likely very rare. Line folding is a fairly obscure feature of HTTP/1.1 and thus not accepting\n        // folding is not likely to break any legitimate use case.\n        if (! preg_match('/^[\\x20\\x09\\x21-\\x7E\\x80-\\xFF]*$/D', $value)) {\n            throw new \\InvalidArgumentException(\n                sprintf('\"%s\" is not valid header value.', $value)\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/psr7/src/MimeType.php",
    "content": "<?php\n\nnamespace GuzzleHttp\\Psr7;\n\nfinal class MimeType\n{\n    /**\n     * Determines the mimetype of a file by looking at its extension.\n     *\n     * @param string $filename\n     *\n     * @return string|null\n     */\n    public static function fromFilename($filename)\n    {\n        return self::fromExtension(pathinfo($filename, PATHINFO_EXTENSION));\n    }\n\n    /**\n     * Maps a file extensions to a mimetype.\n     *\n     * @param string $extension string The file extension.\n     *\n     * @return string|null\n     *\n     * @link http://svn.apache.org/repos/asf/httpd/httpd/branches/1.3.x/conf/mime.types\n     */\n    public static function fromExtension($extension)\n    {\n        static $mimetypes = [\n            '3gp' => 'video/3gpp',\n            '7z' => 'application/x-7z-compressed',\n            'aac' => 'audio/x-aac',\n            'ai' => 'application/postscript',\n            'aif' => 'audio/x-aiff',\n            'asc' => 'text/plain',\n            'asf' => 'video/x-ms-asf',\n            'atom' => 'application/atom+xml',\n            'avi' => 'video/x-msvideo',\n            'bmp' => 'image/bmp',\n            'bz2' => 'application/x-bzip2',\n            'cer' => 'application/pkix-cert',\n            'crl' => 'application/pkix-crl',\n            'crt' => 'application/x-x509-ca-cert',\n            'css' => 'text/css',\n            'csv' => 'text/csv',\n            'cu' => 'application/cu-seeme',\n            'deb' => 'application/x-debian-package',\n            'doc' => 'application/msword',\n            'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n            'dvi' => 'application/x-dvi',\n            'eot' => 'application/vnd.ms-fontobject',\n            'eps' => 'application/postscript',\n            'epub' => 'application/epub+zip',\n            'etx' => 'text/x-setext',\n            'flac' => 'audio/flac',\n            'flv' => 'video/x-flv',\n            'gif' => 'image/gif',\n            'gz' => 'application/gzip',\n            'htm' => 'text/html',\n            'html' => 'text/html',\n            'ico' => 'image/x-icon',\n            'ics' => 'text/calendar',\n            'ini' => 'text/plain',\n            'iso' => 'application/x-iso9660-image',\n            'jar' => 'application/java-archive',\n            'jpe' => 'image/jpeg',\n            'jpeg' => 'image/jpeg',\n            'jpg' => 'image/jpeg',\n            'js' => 'text/javascript',\n            'json' => 'application/json',\n            'latex' => 'application/x-latex',\n            'log' => 'text/plain',\n            'm4a' => 'audio/mp4',\n            'm4v' => 'video/mp4',\n            'mid' => 'audio/midi',\n            'midi' => 'audio/midi',\n            'mov' => 'video/quicktime',\n            'mkv' => 'video/x-matroska',\n            'mp3' => 'audio/mpeg',\n            'mp4' => 'video/mp4',\n            'mp4a' => 'audio/mp4',\n            'mp4v' => 'video/mp4',\n            'mpe' => 'video/mpeg',\n            'mpeg' => 'video/mpeg',\n            'mpg' => 'video/mpeg',\n            'mpg4' => 'video/mp4',\n            'oga' => 'audio/ogg',\n            'ogg' => 'audio/ogg',\n            'ogv' => 'video/ogg',\n            'ogx' => 'application/ogg',\n            'pbm' => 'image/x-portable-bitmap',\n            'pdf' => 'application/pdf',\n            'pgm' => 'image/x-portable-graymap',\n            'png' => 'image/png',\n            'pnm' => 'image/x-portable-anymap',\n            'ppm' => 'image/x-portable-pixmap',\n            'ppt' => 'application/vnd.ms-powerpoint',\n            'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',\n            'ps' => 'application/postscript',\n            'qt' => 'video/quicktime',\n            'rar' => 'application/x-rar-compressed',\n            'ras' => 'image/x-cmu-raster',\n            'rss' => 'application/rss+xml',\n            'rtf' => 'application/rtf',\n            'sgm' => 'text/sgml',\n            'sgml' => 'text/sgml',\n            'svg' => 'image/svg+xml',\n            'swf' => 'application/x-shockwave-flash',\n            'tar' => 'application/x-tar',\n            'tif' => 'image/tiff',\n            'tiff' => 'image/tiff',\n            'torrent' => 'application/x-bittorrent',\n            'ttf' => 'application/x-font-ttf',\n            'txt' => 'text/plain',\n            'wav' => 'audio/x-wav',\n            'webm' => 'video/webm',\n            'webp' => 'image/webp',\n            'wma' => 'audio/x-ms-wma',\n            'wmv' => 'video/x-ms-wmv',\n            'woff' => 'application/x-font-woff',\n            'wsdl' => 'application/wsdl+xml',\n            'xbm' => 'image/x-xbitmap',\n            'xls' => 'application/vnd.ms-excel',\n            'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n            'xml' => 'application/xml',\n            'xpm' => 'image/x-xpixmap',\n            'xwd' => 'image/x-xwindowdump',\n            'yaml' => 'text/yaml',\n            'yml' => 'text/yaml',\n            'zip' => 'application/zip',\n        ];\n\n        $extension = strtolower($extension);\n\n        return isset($mimetypes[$extension])\n            ? $mimetypes[$extension]\n            : null;\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/psr7/src/MultipartStream.php",
    "content": "<?php\n\nnamespace GuzzleHttp\\Psr7;\n\nuse Psr\\Http\\Message\\StreamInterface;\n\n/**\n * Stream that when read returns bytes for a streaming multipart or\n * multipart/form-data stream.\n *\n * @final\n */\nclass MultipartStream implements StreamInterface\n{\n    use StreamDecoratorTrait;\n\n    private $boundary;\n\n    /**\n     * @param array  $elements Array of associative arrays, each containing a\n     *                         required \"name\" key mapping to the form field,\n     *                         name, a required \"contents\" key mapping to a\n     *                         StreamInterface/resource/string, an optional\n     *                         \"headers\" associative array of custom headers,\n     *                         and an optional \"filename\" key mapping to a\n     *                         string to send as the filename in the part.\n     * @param string $boundary You can optionally provide a specific boundary\n     *\n     * @throws \\InvalidArgumentException\n     */\n    public function __construct(array $elements = [], $boundary = null)\n    {\n        $this->boundary = $boundary ?: sha1(uniqid('', true));\n        $this->stream = $this->createStream($elements);\n    }\n\n    /**\n     * Get the boundary\n     *\n     * @return string\n     */\n    public function getBoundary()\n    {\n        return $this->boundary;\n    }\n\n    public function isWritable()\n    {\n        return false;\n    }\n\n    /**\n     * Get the headers needed before transferring the content of a POST file\n     */\n    private function getHeaders(array $headers)\n    {\n        $str = '';\n        foreach ($headers as $key => $value) {\n            $str .= \"{$key}: {$value}\\r\\n\";\n        }\n\n        return \"--{$this->boundary}\\r\\n\" . trim($str) . \"\\r\\n\\r\\n\";\n    }\n\n    /**\n     * Create the aggregate stream that will be used to upload the POST data\n     */\n    protected function createStream(array $elements)\n    {\n        $stream = new AppendStream();\n\n        foreach ($elements as $element) {\n            $this->addElement($stream, $element);\n        }\n\n        // Add the trailing boundary with CRLF\n        $stream->addStream(Utils::streamFor(\"--{$this->boundary}--\\r\\n\"));\n\n        return $stream;\n    }\n\n    private function addElement(AppendStream $stream, array $element)\n    {\n        foreach (['contents', 'name'] as $key) {\n            if (!array_key_exists($key, $element)) {\n                throw new \\InvalidArgumentException(\"A '{$key}' key is required\");\n            }\n        }\n\n        $element['contents'] = Utils::streamFor($element['contents']);\n\n        if (empty($element['filename'])) {\n            $uri = $element['contents']->getMetadata('uri');\n            if (substr($uri, 0, 6) !== 'php://') {\n                $element['filename'] = $uri;\n            }\n        }\n\n        list($body, $headers) = $this->createElement(\n            $element['name'],\n            $element['contents'],\n            isset($element['filename']) ? $element['filename'] : null,\n            isset($element['headers']) ? $element['headers'] : []\n        );\n\n        $stream->addStream(Utils::streamFor($this->getHeaders($headers)));\n        $stream->addStream($body);\n        $stream->addStream(Utils::streamFor(\"\\r\\n\"));\n    }\n\n    /**\n     * @return array\n     */\n    private function createElement($name, StreamInterface $stream, $filename, array $headers)\n    {\n        // Set a default content-disposition header if one was no provided\n        $disposition = $this->getHeader($headers, 'content-disposition');\n        if (!$disposition) {\n            $headers['Content-Disposition'] = ($filename === '0' || $filename)\n                ? sprintf(\n                    'form-data; name=\"%s\"; filename=\"%s\"',\n                    $name,\n                    basename($filename)\n                )\n                : \"form-data; name=\\\"{$name}\\\"\";\n        }\n\n        // Set a default content-length header if one was no provided\n        $length = $this->getHeader($headers, 'content-length');\n        if (!$length) {\n            if ($length = $stream->getSize()) {\n                $headers['Content-Length'] = (string) $length;\n            }\n        }\n\n        // Set a default Content-Type if one was not supplied\n        $type = $this->getHeader($headers, 'content-type');\n        if (!$type && ($filename === '0' || $filename)) {\n            if ($type = MimeType::fromFilename($filename)) {\n                $headers['Content-Type'] = $type;\n            }\n        }\n\n        return [$stream, $headers];\n    }\n\n    private function getHeader(array $headers, $key)\n    {\n        $lowercaseHeader = strtolower($key);\n        foreach ($headers as $k => $v) {\n            if (strtolower($k) === $lowercaseHeader) {\n                return $v;\n            }\n        }\n\n        return null;\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/psr7/src/NoSeekStream.php",
    "content": "<?php\n\nnamespace GuzzleHttp\\Psr7;\n\nuse Psr\\Http\\Message\\StreamInterface;\n\n/**\n * Stream decorator that prevents a stream from being seeked.\n *\n * @final\n */\nclass NoSeekStream implements StreamInterface\n{\n    use StreamDecoratorTrait;\n\n    public function seek($offset, $whence = SEEK_SET)\n    {\n        throw new \\RuntimeException('Cannot seek a NoSeekStream');\n    }\n\n    public function isSeekable()\n    {\n        return false;\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/psr7/src/PumpStream.php",
    "content": "<?php\n\nnamespace GuzzleHttp\\Psr7;\n\nuse Psr\\Http\\Message\\StreamInterface;\n\n/**\n * Provides a read only stream that pumps data from a PHP callable.\n *\n * When invoking the provided callable, the PumpStream will pass the amount of\n * data requested to read to the callable. The callable can choose to ignore\n * this value and return fewer or more bytes than requested. Any extra data\n * returned by the provided callable is buffered internally until drained using\n * the read() function of the PumpStream. The provided callable MUST return\n * false when there is no more data to read.\n *\n * @final\n */\nclass PumpStream implements StreamInterface\n{\n    /** @var callable */\n    private $source;\n\n    /** @var int */\n    private $size;\n\n    /** @var int */\n    private $tellPos = 0;\n\n    /** @var array */\n    private $metadata;\n\n    /** @var BufferStream */\n    private $buffer;\n\n    /**\n     * @param callable $source  Source of the stream data. The callable MAY\n     *                          accept an integer argument used to control the\n     *                          amount of data to return. The callable MUST\n     *                          return a string when called, or false on error\n     *                          or EOF.\n     * @param array    $options Stream options:\n     *                          - metadata: Hash of metadata to use with stream.\n     *                          - size: Size of the stream, if known.\n     */\n    public function __construct(callable $source, array $options = [])\n    {\n        $this->source = $source;\n        $this->size = isset($options['size']) ? $options['size'] : null;\n        $this->metadata = isset($options['metadata']) ? $options['metadata'] : [];\n        $this->buffer = new BufferStream();\n    }\n\n    public function __toString()\n    {\n        try {\n            return Utils::copyToString($this);\n        } catch (\\Exception $e) {\n            return '';\n        }\n    }\n\n    public function close()\n    {\n        $this->detach();\n    }\n\n    public function detach()\n    {\n        $this->tellPos = false;\n        $this->source = null;\n\n        return null;\n    }\n\n    public function getSize()\n    {\n        return $this->size;\n    }\n\n    public function tell()\n    {\n        return $this->tellPos;\n    }\n\n    public function eof()\n    {\n        return !$this->source;\n    }\n\n    public function isSeekable()\n    {\n        return false;\n    }\n\n    public function rewind()\n    {\n        $this->seek(0);\n    }\n\n    public function seek($offset, $whence = SEEK_SET)\n    {\n        throw new \\RuntimeException('Cannot seek a PumpStream');\n    }\n\n    public function isWritable()\n    {\n        return false;\n    }\n\n    public function write($string)\n    {\n        throw new \\RuntimeException('Cannot write to a PumpStream');\n    }\n\n    public function isReadable()\n    {\n        return true;\n    }\n\n    public function read($length)\n    {\n        $data = $this->buffer->read($length);\n        $readLen = strlen($data);\n        $this->tellPos += $readLen;\n        $remaining = $length - $readLen;\n\n        if ($remaining) {\n            $this->pump($remaining);\n            $data .= $this->buffer->read($remaining);\n            $this->tellPos += strlen($data) - $readLen;\n        }\n\n        return $data;\n    }\n\n    public function getContents()\n    {\n        $result = '';\n        while (!$this->eof()) {\n            $result .= $this->read(1000000);\n        }\n\n        return $result;\n    }\n\n    public function getMetadata($key = null)\n    {\n        if (!$key) {\n            return $this->metadata;\n        }\n\n        return isset($this->metadata[$key]) ? $this->metadata[$key] : null;\n    }\n\n    private function pump($length)\n    {\n        if ($this->source) {\n            do {\n                $data = call_user_func($this->source, $length);\n                if ($data === false || $data === null) {\n                    $this->source = null;\n                    return;\n                }\n                $this->buffer->write($data);\n                $length -= strlen($data);\n            } while ($length > 0);\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/psr7/src/Query.php",
    "content": "<?php\n\nnamespace GuzzleHttp\\Psr7;\n\nfinal class Query\n{\n    /**\n     * Parse a query string into an associative array.\n     *\n     * If multiple values are found for the same key, the value of that key\n     * value pair will become an array. This function does not parse nested\n     * PHP style arrays into an associative array (e.g., `foo[a]=1&foo[b]=2`\n     * will be parsed into `['foo[a]' => '1', 'foo[b]' => '2'])`.\n     *\n     * @param string   $str         Query string to parse\n     * @param int|bool $urlEncoding How the query string is encoded\n     *\n     * @return array\n     */\n    public static function parse($str, $urlEncoding = true)\n    {\n        $result = [];\n\n        if ($str === '') {\n            return $result;\n        }\n\n        if ($urlEncoding === true) {\n            $decoder = function ($value) {\n                return rawurldecode(str_replace('+', ' ', $value));\n            };\n        } elseif ($urlEncoding === PHP_QUERY_RFC3986) {\n            $decoder = 'rawurldecode';\n        } elseif ($urlEncoding === PHP_QUERY_RFC1738) {\n            $decoder = 'urldecode';\n        } else {\n            $decoder = function ($str) {\n                return $str;\n            };\n        }\n\n        foreach (explode('&', $str) as $kvp) {\n            $parts = explode('=', $kvp, 2);\n            $key = $decoder($parts[0]);\n            $value = isset($parts[1]) ? $decoder($parts[1]) : null;\n            if (!isset($result[$key])) {\n                $result[$key] = $value;\n            } else {\n                if (!is_array($result[$key])) {\n                    $result[$key] = [$result[$key]];\n                }\n                $result[$key][] = $value;\n            }\n        }\n\n        return $result;\n    }\n\n    /**\n     * Build a query string from an array of key value pairs.\n     *\n     * This function can use the return value of `parse()` to build a query\n     * string. This function does not modify the provided keys when an array is\n     * encountered (like `http_build_query()` would).\n     *\n     * @param array     $params   Query string parameters.\n     * @param int|false $encoding Set to false to not encode, PHP_QUERY_RFC3986\n     *                            to encode using RFC3986, or PHP_QUERY_RFC1738\n     *                            to encode using RFC1738.\n     *\n     * @return string\n     */\n    public static function build(array $params, $encoding = PHP_QUERY_RFC3986)\n    {\n        if (!$params) {\n            return '';\n        }\n\n        if ($encoding === false) {\n            $encoder = function ($str) {\n                return $str;\n            };\n        } elseif ($encoding === PHP_QUERY_RFC3986) {\n            $encoder = 'rawurlencode';\n        } elseif ($encoding === PHP_QUERY_RFC1738) {\n            $encoder = 'urlencode';\n        } else {\n            throw new \\InvalidArgumentException('Invalid type');\n        }\n\n        $qs = '';\n        foreach ($params as $k => $v) {\n            $k = $encoder($k);\n            if (!is_array($v)) {\n                $qs .= $k;\n                if ($v !== null) {\n                    $qs .= '=' . $encoder($v);\n                }\n                $qs .= '&';\n            } else {\n                foreach ($v as $vv) {\n                    $qs .= $k;\n                    if ($vv !== null) {\n                        $qs .= '=' . $encoder($vv);\n                    }\n                    $qs .= '&';\n                }\n            }\n        }\n\n        return $qs ? (string) substr($qs, 0, -1) : '';\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/psr7/src/Request.php",
    "content": "<?php\n\nnamespace GuzzleHttp\\Psr7;\n\nuse InvalidArgumentException;\nuse Psr\\Http\\Message\\RequestInterface;\nuse Psr\\Http\\Message\\StreamInterface;\nuse Psr\\Http\\Message\\UriInterface;\n\n/**\n * PSR-7 request implementation.\n */\nclass Request implements RequestInterface\n{\n    use MessageTrait;\n\n    /** @var string */\n    private $method;\n\n    /** @var string|null */\n    private $requestTarget;\n\n    /** @var UriInterface */\n    private $uri;\n\n    /**\n     * @param string                               $method  HTTP method\n     * @param string|UriInterface                  $uri     URI\n     * @param array                                $headers Request headers\n     * @param string|resource|StreamInterface|null $body    Request body\n     * @param string                               $version Protocol version\n     */\n    public function __construct(\n        $method,\n        $uri,\n        array $headers = [],\n        $body = null,\n        $version = '1.1'\n    ) {\n        $this->assertMethod($method);\n        if (!($uri instanceof UriInterface)) {\n            $uri = new Uri($uri);\n        }\n\n        $this->method = strtoupper($method);\n        $this->uri = $uri;\n        $this->setHeaders($headers);\n        $this->protocol = $version;\n\n        if (!isset($this->headerNames['host'])) {\n            $this->updateHostFromUri();\n        }\n\n        if ($body !== '' && $body !== null) {\n            $this->stream = Utils::streamFor($body);\n        }\n    }\n\n    public function getRequestTarget()\n    {\n        if ($this->requestTarget !== null) {\n            return $this->requestTarget;\n        }\n\n        $target = $this->uri->getPath();\n        if ($target == '') {\n            $target = '/';\n        }\n        if ($this->uri->getQuery() != '') {\n            $target .= '?' . $this->uri->getQuery();\n        }\n\n        return $target;\n    }\n\n    public function withRequestTarget($requestTarget)\n    {\n        if (preg_match('#\\s#', $requestTarget)) {\n            throw new InvalidArgumentException(\n                'Invalid request target provided; cannot contain whitespace'\n            );\n        }\n\n        $new = clone $this;\n        $new->requestTarget = $requestTarget;\n        return $new;\n    }\n\n    public function getMethod()\n    {\n        return $this->method;\n    }\n\n    public function withMethod($method)\n    {\n        $this->assertMethod($method);\n        $new = clone $this;\n        $new->method = strtoupper($method);\n        return $new;\n    }\n\n    public function getUri()\n    {\n        return $this->uri;\n    }\n\n    public function withUri(UriInterface $uri, $preserveHost = false)\n    {\n        if ($uri === $this->uri) {\n            return $this;\n        }\n\n        $new = clone $this;\n        $new->uri = $uri;\n\n        if (!$preserveHost || !isset($this->headerNames['host'])) {\n            $new->updateHostFromUri();\n        }\n\n        return $new;\n    }\n\n    private function updateHostFromUri()\n    {\n        $host = $this->uri->getHost();\n\n        if ($host == '') {\n            return;\n        }\n\n        if (($port = $this->uri->getPort()) !== null) {\n            $host .= ':' . $port;\n        }\n\n        if (isset($this->headerNames['host'])) {\n            $header = $this->headerNames['host'];\n        } else {\n            $header = 'Host';\n            $this->headerNames['host'] = 'Host';\n        }\n        // Ensure Host is the first header.\n        // See: http://tools.ietf.org/html/rfc7230#section-5.4\n        $this->headers = [$header => [$host]] + $this->headers;\n    }\n\n    private function assertMethod($method)\n    {\n        if (!is_string($method) || $method === '') {\n            throw new \\InvalidArgumentException('Method must be a non-empty string.');\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/psr7/src/Response.php",
    "content": "<?php\n\nnamespace GuzzleHttp\\Psr7;\n\nuse Psr\\Http\\Message\\ResponseInterface;\nuse Psr\\Http\\Message\\StreamInterface;\n\n/**\n * PSR-7 response implementation.\n */\nclass Response implements ResponseInterface\n{\n    use MessageTrait;\n\n    /** @var array Map of standard HTTP status code/reason phrases */\n    private static $phrases = [\n        100 => 'Continue',\n        101 => 'Switching Protocols',\n        102 => 'Processing',\n        200 => 'OK',\n        201 => 'Created',\n        202 => 'Accepted',\n        203 => 'Non-Authoritative Information',\n        204 => 'No Content',\n        205 => 'Reset Content',\n        206 => 'Partial Content',\n        207 => 'Multi-status',\n        208 => 'Already Reported',\n        300 => 'Multiple Choices',\n        301 => 'Moved Permanently',\n        302 => 'Found',\n        303 => 'See Other',\n        304 => 'Not Modified',\n        305 => 'Use Proxy',\n        306 => 'Switch Proxy',\n        307 => 'Temporary Redirect',\n        400 => 'Bad Request',\n        401 => 'Unauthorized',\n        402 => 'Payment Required',\n        403 => 'Forbidden',\n        404 => 'Not Found',\n        405 => 'Method Not Allowed',\n        406 => 'Not Acceptable',\n        407 => 'Proxy Authentication Required',\n        408 => 'Request Time-out',\n        409 => 'Conflict',\n        410 => 'Gone',\n        411 => 'Length Required',\n        412 => 'Precondition Failed',\n        413 => 'Request Entity Too Large',\n        414 => 'Request-URI Too Large',\n        415 => 'Unsupported Media Type',\n        416 => 'Requested range not satisfiable',\n        417 => 'Expectation Failed',\n        418 => 'I\\'m a teapot',\n        422 => 'Unprocessable Entity',\n        423 => 'Locked',\n        424 => 'Failed Dependency',\n        425 => 'Unordered Collection',\n        426 => 'Upgrade Required',\n        428 => 'Precondition Required',\n        429 => 'Too Many Requests',\n        431 => 'Request Header Fields Too Large',\n        451 => 'Unavailable For Legal Reasons',\n        500 => 'Internal Server Error',\n        501 => 'Not Implemented',\n        502 => 'Bad Gateway',\n        503 => 'Service Unavailable',\n        504 => 'Gateway Time-out',\n        505 => 'HTTP Version not supported',\n        506 => 'Variant Also Negotiates',\n        507 => 'Insufficient Storage',\n        508 => 'Loop Detected',\n        511 => 'Network Authentication Required',\n    ];\n\n    /** @var string */\n    private $reasonPhrase = '';\n\n    /** @var int */\n    private $statusCode = 200;\n\n    /**\n     * @param int                                  $status  Status code\n     * @param array                                $headers Response headers\n     * @param string|resource|StreamInterface|null $body    Response body\n     * @param string                               $version Protocol version\n     * @param string|null                          $reason  Reason phrase (when empty a default will be used based on the status code)\n     */\n    public function __construct(\n        $status = 200,\n        array $headers = [],\n        $body = null,\n        $version = '1.1',\n        $reason = null\n    ) {\n        $this->assertStatusCodeIsInteger($status);\n        $status = (int) $status;\n        $this->assertStatusCodeRange($status);\n\n        $this->statusCode = $status;\n\n        if ($body !== '' && $body !== null) {\n            $this->stream = Utils::streamFor($body);\n        }\n\n        $this->setHeaders($headers);\n        if ($reason == '' && isset(self::$phrases[$this->statusCode])) {\n            $this->reasonPhrase = self::$phrases[$this->statusCode];\n        } else {\n            $this->reasonPhrase = (string) $reason;\n        }\n\n        $this->protocol = $version;\n    }\n\n    public function getStatusCode()\n    {\n        return $this->statusCode;\n    }\n\n    public function getReasonPhrase()\n    {\n        return $this->reasonPhrase;\n    }\n\n    public function withStatus($code, $reasonPhrase = '')\n    {\n        $this->assertStatusCodeIsInteger($code);\n        $code = (int) $code;\n        $this->assertStatusCodeRange($code);\n\n        $new = clone $this;\n        $new->statusCode = $code;\n        if ($reasonPhrase == '' && isset(self::$phrases[$new->statusCode])) {\n            $reasonPhrase = self::$phrases[$new->statusCode];\n        }\n        $new->reasonPhrase = (string) $reasonPhrase;\n        return $new;\n    }\n\n    private function assertStatusCodeIsInteger($statusCode)\n    {\n        if (filter_var($statusCode, FILTER_VALIDATE_INT) === false) {\n            throw new \\InvalidArgumentException('Status code must be an integer value.');\n        }\n    }\n\n    private function assertStatusCodeRange($statusCode)\n    {\n        if ($statusCode < 100 || $statusCode >= 600) {\n            throw new \\InvalidArgumentException('Status code must be an integer value between 1xx and 5xx.');\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/psr7/src/Rfc7230.php",
    "content": "<?php\n\nnamespace GuzzleHttp\\Psr7;\n\nfinal class Rfc7230\n{\n    /**\n     * Header related regular expressions (copied from amphp/http package)\n     * (Note: once we require PHP 7.x we could just depend on the upstream package)\n     *\n     * Note: header delimiter (\\r\\n) is modified to \\r?\\n to accept line feed only delimiters for BC reasons.\n     *\n     * @link    https://github.com/amphp/http/blob/v1.0.1/src/Rfc7230.php#L12-L15\n     *\n     * @license https://github.com/amphp/http/blob/v1.0.1/LICENSE\n     */\n    const HEADER_REGEX = \"(^([^()<>@,;:\\\\\\\"/[\\]?={}\\x01-\\x20\\x7F]++):[ \\t]*+((?:[ \\t]*+[\\x21-\\x7E\\x80-\\xFF]++)*+)[ \\t]*+\\r?\\n)m\";\n    const HEADER_FOLD_REGEX = \"(\\r?\\n[ \\t]++)\";\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/psr7/src/ServerRequest.php",
    "content": "<?php\n\nnamespace GuzzleHttp\\Psr7;\n\nuse InvalidArgumentException;\nuse Psr\\Http\\Message\\ServerRequestInterface;\nuse Psr\\Http\\Message\\StreamInterface;\nuse Psr\\Http\\Message\\UploadedFileInterface;\nuse Psr\\Http\\Message\\UriInterface;\n\n/**\n * Server-side HTTP request\n *\n * Extends the Request definition to add methods for accessing incoming data,\n * specifically server parameters, cookies, matched path parameters, query\n * string arguments, body parameters, and upload file information.\n *\n * \"Attributes\" are discovered via decomposing the request (and usually\n * specifically the URI path), and typically will be injected by the application.\n *\n * Requests are considered immutable; all methods that might change state are\n * implemented such that they retain the internal state of the current\n * message and return a new instance that contains the changed state.\n */\nclass ServerRequest extends Request implements ServerRequestInterface\n{\n    /**\n     * @var array\n     */\n    private $attributes = [];\n\n    /**\n     * @var array\n     */\n    private $cookieParams = [];\n\n    /**\n     * @var array|object|null\n     */\n    private $parsedBody;\n\n    /**\n     * @var array\n     */\n    private $queryParams = [];\n\n    /**\n     * @var array\n     */\n    private $serverParams;\n\n    /**\n     * @var array\n     */\n    private $uploadedFiles = [];\n\n    /**\n     * @param string                               $method       HTTP method\n     * @param string|UriInterface                  $uri          URI\n     * @param array                                $headers      Request headers\n     * @param string|resource|StreamInterface|null $body         Request body\n     * @param string                               $version      Protocol version\n     * @param array                                $serverParams Typically the $_SERVER superglobal\n     */\n    public function __construct(\n        $method,\n        $uri,\n        array $headers = [],\n        $body = null,\n        $version = '1.1',\n        array $serverParams = []\n    ) {\n        $this->serverParams = $serverParams;\n\n        parent::__construct($method, $uri, $headers, $body, $version);\n    }\n\n    /**\n     * Return an UploadedFile instance array.\n     *\n     * @param array $files A array which respect $_FILES structure\n     *\n     * @return array\n     *\n     * @throws InvalidArgumentException for unrecognized values\n     */\n    public static function normalizeFiles(array $files)\n    {\n        $normalized = [];\n\n        foreach ($files as $key => $value) {\n            if ($value instanceof UploadedFileInterface) {\n                $normalized[$key] = $value;\n            } elseif (is_array($value) && isset($value['tmp_name'])) {\n                $normalized[$key] = self::createUploadedFileFromSpec($value);\n            } elseif (is_array($value)) {\n                $normalized[$key] = self::normalizeFiles($value);\n                continue;\n            } else {\n                throw new InvalidArgumentException('Invalid value in files specification');\n            }\n        }\n\n        return $normalized;\n    }\n\n    /**\n     * Create and return an UploadedFile instance from a $_FILES specification.\n     *\n     * If the specification represents an array of values, this method will\n     * delegate to normalizeNestedFileSpec() and return that return value.\n     *\n     * @param array $value $_FILES struct\n     *\n     * @return array|UploadedFileInterface\n     */\n    private static function createUploadedFileFromSpec(array $value)\n    {\n        if (is_array($value['tmp_name'])) {\n            return self::normalizeNestedFileSpec($value);\n        }\n\n        return new UploadedFile(\n            $value['tmp_name'],\n            (int) $value['size'],\n            (int) $value['error'],\n            $value['name'],\n            $value['type']\n        );\n    }\n\n    /**\n     * Normalize an array of file specifications.\n     *\n     * Loops through all nested files and returns a normalized array of\n     * UploadedFileInterface instances.\n     *\n     * @param array $files\n     *\n     * @return UploadedFileInterface[]\n     */\n    private static function normalizeNestedFileSpec(array $files = [])\n    {\n        $normalizedFiles = [];\n\n        foreach (array_keys($files['tmp_name']) as $key) {\n            $spec = [\n                'tmp_name' => $files['tmp_name'][$key],\n                'size'     => $files['size'][$key],\n                'error'    => $files['error'][$key],\n                'name'     => $files['name'][$key],\n                'type'     => $files['type'][$key],\n            ];\n            $normalizedFiles[$key] = self::createUploadedFileFromSpec($spec);\n        }\n\n        return $normalizedFiles;\n    }\n\n    /**\n     * Return a ServerRequest populated with superglobals:\n     * $_GET\n     * $_POST\n     * $_COOKIE\n     * $_FILES\n     * $_SERVER\n     *\n     * @return ServerRequestInterface\n     */\n    public static function fromGlobals()\n    {\n        $method = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : 'GET';\n        $headers = getallheaders();\n        $uri = self::getUriFromGlobals();\n        $body = new CachingStream(new LazyOpenStream('php://input', 'r+'));\n        $protocol = isset($_SERVER['SERVER_PROTOCOL']) ? str_replace('HTTP/', '', $_SERVER['SERVER_PROTOCOL']) : '1.1';\n\n        $serverRequest = new ServerRequest($method, $uri, $headers, $body, $protocol, $_SERVER);\n\n        return $serverRequest\n            ->withCookieParams($_COOKIE)\n            ->withQueryParams($_GET)\n            ->withParsedBody($_POST)\n            ->withUploadedFiles(self::normalizeFiles($_FILES));\n    }\n\n    private static function extractHostAndPortFromAuthority($authority)\n    {\n        $uri = 'http://' . $authority;\n        $parts = parse_url($uri);\n        if (false === $parts) {\n            return [null, null];\n        }\n\n        $host = isset($parts['host']) ? $parts['host'] : null;\n        $port = isset($parts['port']) ? $parts['port'] : null;\n\n        return [$host, $port];\n    }\n\n    /**\n     * Get a Uri populated with values from $_SERVER.\n     *\n     * @return UriInterface\n     */\n    public static function getUriFromGlobals()\n    {\n        $uri = new Uri('');\n\n        $uri = $uri->withScheme(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' ? 'https' : 'http');\n\n        $hasPort = false;\n        if (isset($_SERVER['HTTP_HOST'])) {\n            list($host, $port) = self::extractHostAndPortFromAuthority($_SERVER['HTTP_HOST']);\n            if ($host !== null) {\n                $uri = $uri->withHost($host);\n            }\n\n            if ($port !== null) {\n                $hasPort = true;\n                $uri = $uri->withPort($port);\n            }\n        } elseif (isset($_SERVER['SERVER_NAME'])) {\n            $uri = $uri->withHost($_SERVER['SERVER_NAME']);\n        } elseif (isset($_SERVER['SERVER_ADDR'])) {\n            $uri = $uri->withHost($_SERVER['SERVER_ADDR']);\n        }\n\n        if (!$hasPort && isset($_SERVER['SERVER_PORT'])) {\n            $uri = $uri->withPort($_SERVER['SERVER_PORT']);\n        }\n\n        $hasQuery = false;\n        if (isset($_SERVER['REQUEST_URI'])) {\n            $requestUriParts = explode('?', $_SERVER['REQUEST_URI'], 2);\n            $uri = $uri->withPath($requestUriParts[0]);\n            if (isset($requestUriParts[1])) {\n                $hasQuery = true;\n                $uri = $uri->withQuery($requestUriParts[1]);\n            }\n        }\n\n        if (!$hasQuery && isset($_SERVER['QUERY_STRING'])) {\n            $uri = $uri->withQuery($_SERVER['QUERY_STRING']);\n        }\n\n        return $uri;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getServerParams()\n    {\n        return $this->serverParams;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getUploadedFiles()\n    {\n        return $this->uploadedFiles;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function withUploadedFiles(array $uploadedFiles)\n    {\n        $new = clone $this;\n        $new->uploadedFiles = $uploadedFiles;\n\n        return $new;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getCookieParams()\n    {\n        return $this->cookieParams;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function withCookieParams(array $cookies)\n    {\n        $new = clone $this;\n        $new->cookieParams = $cookies;\n\n        return $new;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getQueryParams()\n    {\n        return $this->queryParams;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function withQueryParams(array $query)\n    {\n        $new = clone $this;\n        $new->queryParams = $query;\n\n        return $new;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getParsedBody()\n    {\n        return $this->parsedBody;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function withParsedBody($data)\n    {\n        $new = clone $this;\n        $new->parsedBody = $data;\n\n        return $new;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getAttributes()\n    {\n        return $this->attributes;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getAttribute($attribute, $default = null)\n    {\n        if (false === array_key_exists($attribute, $this->attributes)) {\n            return $default;\n        }\n\n        return $this->attributes[$attribute];\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function withAttribute($attribute, $value)\n    {\n        $new = clone $this;\n        $new->attributes[$attribute] = $value;\n\n        return $new;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function withoutAttribute($attribute)\n    {\n        if (false === array_key_exists($attribute, $this->attributes)) {\n            return $this;\n        }\n\n        $new = clone $this;\n        unset($new->attributes[$attribute]);\n\n        return $new;\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/psr7/src/Stream.php",
    "content": "<?php\n\nnamespace GuzzleHttp\\Psr7;\n\nuse Psr\\Http\\Message\\StreamInterface;\n\n/**\n * PHP stream implementation.\n *\n * @var $stream\n */\nclass Stream implements StreamInterface\n{\n    /**\n     * Resource modes.\n     *\n     * @var string\n     *\n     * @see http://php.net/manual/function.fopen.php\n     * @see http://php.net/manual/en/function.gzopen.php\n     */\n    const READABLE_MODES = '/r|a\\+|ab\\+|w\\+|wb\\+|x\\+|xb\\+|c\\+|cb\\+/';\n    const WRITABLE_MODES = '/a|w|r\\+|rb\\+|rw|x|c/';\n\n    private $stream;\n    private $size;\n    private $seekable;\n    private $readable;\n    private $writable;\n    private $uri;\n    private $customMetadata;\n\n    /**\n     * This constructor accepts an associative array of options.\n     *\n     * - size: (int) If a read stream would otherwise have an indeterminate\n     *   size, but the size is known due to foreknowledge, then you can\n     *   provide that size, in bytes.\n     * - metadata: (array) Any additional metadata to return when the metadata\n     *   of the stream is accessed.\n     *\n     * @param resource $stream  Stream resource to wrap.\n     * @param array    $options Associative array of options.\n     *\n     * @throws \\InvalidArgumentException if the stream is not a stream resource\n     */\n    public function __construct($stream, $options = [])\n    {\n        if (!is_resource($stream)) {\n            throw new \\InvalidArgumentException('Stream must be a resource');\n        }\n\n        if (isset($options['size'])) {\n            $this->size = $options['size'];\n        }\n\n        $this->customMetadata = isset($options['metadata'])\n            ? $options['metadata']\n            : [];\n\n        $this->stream = $stream;\n        $meta = stream_get_meta_data($this->stream);\n        $this->seekable = $meta['seekable'];\n        $this->readable = (bool)preg_match(self::READABLE_MODES, $meta['mode']);\n        $this->writable = (bool)preg_match(self::WRITABLE_MODES, $meta['mode']);\n        $this->uri = $this->getMetadata('uri');\n    }\n\n    /**\n     * Closes the stream when the destructed\n     */\n    public function __destruct()\n    {\n        $this->close();\n    }\n\n    public function __toString()\n    {\n        try {\n            if ($this->isSeekable()) {\n                $this->seek(0);\n            }\n            return $this->getContents();\n        } catch (\\Exception $e) {\n            return '';\n        }\n    }\n\n    public function getContents()\n    {\n        if (!isset($this->stream)) {\n            throw new \\RuntimeException('Stream is detached');\n        }\n\n        $contents = stream_get_contents($this->stream);\n\n        if ($contents === false) {\n            throw new \\RuntimeException('Unable to read stream contents');\n        }\n\n        return $contents;\n    }\n\n    public function close()\n    {\n        if (isset($this->stream)) {\n            if (is_resource($this->stream)) {\n                fclose($this->stream);\n            }\n            $this->detach();\n        }\n    }\n\n    public function detach()\n    {\n        if (!isset($this->stream)) {\n            return null;\n        }\n\n        $result = $this->stream;\n        unset($this->stream);\n        $this->size = $this->uri = null;\n        $this->readable = $this->writable = $this->seekable = false;\n\n        return $result;\n    }\n\n    public function getSize()\n    {\n        if ($this->size !== null) {\n            return $this->size;\n        }\n\n        if (!isset($this->stream)) {\n            return null;\n        }\n\n        // Clear the stat cache if the stream has a URI\n        if ($this->uri) {\n            clearstatcache(true, $this->uri);\n        }\n\n        $stats = fstat($this->stream);\n        if (isset($stats['size'])) {\n            $this->size = $stats['size'];\n            return $this->size;\n        }\n\n        return null;\n    }\n\n    public function isReadable()\n    {\n        return $this->readable;\n    }\n\n    public function isWritable()\n    {\n        return $this->writable;\n    }\n\n    public function isSeekable()\n    {\n        return $this->seekable;\n    }\n\n    public function eof()\n    {\n        if (!isset($this->stream)) {\n            throw new \\RuntimeException('Stream is detached');\n        }\n\n        return feof($this->stream);\n    }\n\n    public function tell()\n    {\n        if (!isset($this->stream)) {\n            throw new \\RuntimeException('Stream is detached');\n        }\n\n        $result = ftell($this->stream);\n\n        if ($result === false) {\n            throw new \\RuntimeException('Unable to determine stream position');\n        }\n\n        return $result;\n    }\n\n    public function rewind()\n    {\n        $this->seek(0);\n    }\n\n    public function seek($offset, $whence = SEEK_SET)\n    {\n        $whence = (int) $whence;\n\n        if (!isset($this->stream)) {\n            throw new \\RuntimeException('Stream is detached');\n        }\n        if (!$this->seekable) {\n            throw new \\RuntimeException('Stream is not seekable');\n        }\n        if (fseek($this->stream, $offset, $whence) === -1) {\n            throw new \\RuntimeException('Unable to seek to stream position '\n                . $offset . ' with whence ' . var_export($whence, true));\n        }\n    }\n\n    public function read($length)\n    {\n        if (!isset($this->stream)) {\n            throw new \\RuntimeException('Stream is detached');\n        }\n        if (!$this->readable) {\n            throw new \\RuntimeException('Cannot read from non-readable stream');\n        }\n        if ($length < 0) {\n            throw new \\RuntimeException('Length parameter cannot be negative');\n        }\n\n        if (0 === $length) {\n            return '';\n        }\n\n        $string = fread($this->stream, $length);\n        if (false === $string) {\n            throw new \\RuntimeException('Unable to read from stream');\n        }\n\n        return $string;\n    }\n\n    public function write($string)\n    {\n        if (!isset($this->stream)) {\n            throw new \\RuntimeException('Stream is detached');\n        }\n        if (!$this->writable) {\n            throw new \\RuntimeException('Cannot write to a non-writable stream');\n        }\n\n        // We can't know the size after writing anything\n        $this->size = null;\n        $result = fwrite($this->stream, $string);\n\n        if ($result === false) {\n            throw new \\RuntimeException('Unable to write to stream');\n        }\n\n        return $result;\n    }\n\n    public function getMetadata($key = null)\n    {\n        if (!isset($this->stream)) {\n            return $key ? null : [];\n        } elseif (!$key) {\n            return $this->customMetadata + stream_get_meta_data($this->stream);\n        } elseif (isset($this->customMetadata[$key])) {\n            return $this->customMetadata[$key];\n        }\n\n        $meta = stream_get_meta_data($this->stream);\n\n        return isset($meta[$key]) ? $meta[$key] : null;\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/psr7/src/StreamDecoratorTrait.php",
    "content": "<?php\n\nnamespace GuzzleHttp\\Psr7;\n\nuse Psr\\Http\\Message\\StreamInterface;\n\n/**\n * Stream decorator trait\n *\n * @property StreamInterface stream\n */\ntrait StreamDecoratorTrait\n{\n    /**\n     * @param StreamInterface $stream Stream to decorate\n     */\n    public function __construct(StreamInterface $stream)\n    {\n        $this->stream = $stream;\n    }\n\n    /**\n     * Magic method used to create a new stream if streams are not added in\n     * the constructor of a decorator (e.g., LazyOpenStream).\n     *\n     * @param string $name Name of the property (allows \"stream\" only).\n     *\n     * @return StreamInterface\n     */\n    public function __get($name)\n    {\n        if ($name == 'stream') {\n            $this->stream = $this->createStream();\n            return $this->stream;\n        }\n\n        throw new \\UnexpectedValueException(\"$name not found on class\");\n    }\n\n    public function __toString()\n    {\n        try {\n            if ($this->isSeekable()) {\n                $this->seek(0);\n            }\n            return $this->getContents();\n        } catch (\\Exception $e) {\n            // Really, PHP? https://bugs.php.net/bug.php?id=53648\n            trigger_error('StreamDecorator::__toString exception: '\n                . (string) $e, E_USER_ERROR);\n            return '';\n        }\n    }\n\n    public function getContents()\n    {\n        return Utils::copyToString($this);\n    }\n\n    /**\n     * Allow decorators to implement custom methods\n     *\n     * @param string $method Missing method name\n     * @param array  $args   Method arguments\n     *\n     * @return mixed\n     */\n    public function __call($method, array $args)\n    {\n        $result = call_user_func_array([$this->stream, $method], $args);\n\n        // Always return the wrapped object if the result is a return $this\n        return $result === $this->stream ? $this : $result;\n    }\n\n    public function close()\n    {\n        $this->stream->close();\n    }\n\n    public function getMetadata($key = null)\n    {\n        return $this->stream->getMetadata($key);\n    }\n\n    public function detach()\n    {\n        return $this->stream->detach();\n    }\n\n    public function getSize()\n    {\n        return $this->stream->getSize();\n    }\n\n    public function eof()\n    {\n        return $this->stream->eof();\n    }\n\n    public function tell()\n    {\n        return $this->stream->tell();\n    }\n\n    public function isReadable()\n    {\n        return $this->stream->isReadable();\n    }\n\n    public function isWritable()\n    {\n        return $this->stream->isWritable();\n    }\n\n    public function isSeekable()\n    {\n        return $this->stream->isSeekable();\n    }\n\n    public function rewind()\n    {\n        $this->seek(0);\n    }\n\n    public function seek($offset, $whence = SEEK_SET)\n    {\n        $this->stream->seek($offset, $whence);\n    }\n\n    public function read($length)\n    {\n        return $this->stream->read($length);\n    }\n\n    public function write($string)\n    {\n        return $this->stream->write($string);\n    }\n\n    /**\n     * Implement in subclasses to dynamically create streams when requested.\n     *\n     * @return StreamInterface\n     *\n     * @throws \\BadMethodCallException\n     */\n    protected function createStream()\n    {\n        throw new \\BadMethodCallException('Not implemented');\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/psr7/src/StreamWrapper.php",
    "content": "<?php\n\nnamespace GuzzleHttp\\Psr7;\n\nuse Psr\\Http\\Message\\StreamInterface;\n\n/**\n * Converts Guzzle streams into PHP stream resources.\n *\n * @final\n */\nclass StreamWrapper\n{\n    /** @var resource */\n    public $context;\n\n    /** @var StreamInterface */\n    private $stream;\n\n    /** @var string r, r+, or w */\n    private $mode;\n\n    /**\n     * Returns a resource representing the stream.\n     *\n     * @param StreamInterface $stream The stream to get a resource for\n     *\n     * @return resource\n     *\n     * @throws \\InvalidArgumentException if stream is not readable or writable\n     */\n    public static function getResource(StreamInterface $stream)\n    {\n        self::register();\n\n        if ($stream->isReadable()) {\n            $mode = $stream->isWritable() ? 'r+' : 'r';\n        } elseif ($stream->isWritable()) {\n            $mode = 'w';\n        } else {\n            throw new \\InvalidArgumentException('The stream must be readable, '\n                . 'writable, or both.');\n        }\n\n        return fopen('guzzle://stream', $mode, null, self::createStreamContext($stream));\n    }\n\n    /**\n     * Creates a stream context that can be used to open a stream as a php stream resource.\n     *\n     * @param StreamInterface $stream\n     *\n     * @return resource\n     */\n    public static function createStreamContext(StreamInterface $stream)\n    {\n        return stream_context_create([\n            'guzzle' => ['stream' => $stream]\n        ]);\n    }\n\n    /**\n     * Registers the stream wrapper if needed\n     */\n    public static function register()\n    {\n        if (!in_array('guzzle', stream_get_wrappers())) {\n            stream_wrapper_register('guzzle', __CLASS__);\n        }\n    }\n\n    public function stream_open($path, $mode, $options, &$opened_path)\n    {\n        $options = stream_context_get_options($this->context);\n\n        if (!isset($options['guzzle']['stream'])) {\n            return false;\n        }\n\n        $this->mode = $mode;\n        $this->stream = $options['guzzle']['stream'];\n\n        return true;\n    }\n\n    public function stream_read($count)\n    {\n        return $this->stream->read($count);\n    }\n\n    public function stream_write($data)\n    {\n        return (int) $this->stream->write($data);\n    }\n\n    public function stream_tell()\n    {\n        return $this->stream->tell();\n    }\n\n    public function stream_eof()\n    {\n        return $this->stream->eof();\n    }\n\n    public function stream_seek($offset, $whence)\n    {\n        $this->stream->seek($offset, $whence);\n\n        return true;\n    }\n\n    public function stream_cast($cast_as)\n    {\n        $stream = clone($this->stream);\n\n        return $stream->detach();\n    }\n\n    public function stream_stat()\n    {\n        static $modeMap = [\n            'r'  => 33060,\n            'rb' => 33060,\n            'r+' => 33206,\n            'w'  => 33188,\n            'wb' => 33188\n        ];\n\n        return [\n            'dev'     => 0,\n            'ino'     => 0,\n            'mode'    => $modeMap[$this->mode],\n            'nlink'   => 0,\n            'uid'     => 0,\n            'gid'     => 0,\n            'rdev'    => 0,\n            'size'    => $this->stream->getSize() ?: 0,\n            'atime'   => 0,\n            'mtime'   => 0,\n            'ctime'   => 0,\n            'blksize' => 0,\n            'blocks'  => 0\n        ];\n    }\n\n    public function url_stat($path, $flags)\n    {\n        return [\n            'dev'     => 0,\n            'ino'     => 0,\n            'mode'    => 0,\n            'nlink'   => 0,\n            'uid'     => 0,\n            'gid'     => 0,\n            'rdev'    => 0,\n            'size'    => 0,\n            'atime'   => 0,\n            'mtime'   => 0,\n            'ctime'   => 0,\n            'blksize' => 0,\n            'blocks'  => 0\n        ];\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/psr7/src/UploadedFile.php",
    "content": "<?php\n\nnamespace GuzzleHttp\\Psr7;\n\nuse InvalidArgumentException;\nuse Psr\\Http\\Message\\StreamInterface;\nuse Psr\\Http\\Message\\UploadedFileInterface;\nuse RuntimeException;\n\nclass UploadedFile implements UploadedFileInterface\n{\n    /**\n     * @var int[]\n     */\n    private static $errors = [\n        UPLOAD_ERR_OK,\n        UPLOAD_ERR_INI_SIZE,\n        UPLOAD_ERR_FORM_SIZE,\n        UPLOAD_ERR_PARTIAL,\n        UPLOAD_ERR_NO_FILE,\n        UPLOAD_ERR_NO_TMP_DIR,\n        UPLOAD_ERR_CANT_WRITE,\n        UPLOAD_ERR_EXTENSION,\n    ];\n\n    /**\n     * @var string\n     */\n    private $clientFilename;\n\n    /**\n     * @var string\n     */\n    private $clientMediaType;\n\n    /**\n     * @var int\n     */\n    private $error;\n\n    /**\n     * @var string|null\n     */\n    private $file;\n\n    /**\n     * @var bool\n     */\n    private $moved = false;\n\n    /**\n     * @var int\n     */\n    private $size;\n\n    /**\n     * @var StreamInterface|null\n     */\n    private $stream;\n\n    /**\n     * @param StreamInterface|string|resource $streamOrFile\n     * @param int                             $size\n     * @param int                             $errorStatus\n     * @param string|null                     $clientFilename\n     * @param string|null                     $clientMediaType\n     */\n    public function __construct(\n        $streamOrFile,\n        $size,\n        $errorStatus,\n        $clientFilename = null,\n        $clientMediaType = null\n    ) {\n        $this->setError($errorStatus);\n        $this->setSize($size);\n        $this->setClientFilename($clientFilename);\n        $this->setClientMediaType($clientMediaType);\n\n        if ($this->isOk()) {\n            $this->setStreamOrFile($streamOrFile);\n        }\n    }\n\n    /**\n     * Depending on the value set file or stream variable\n     *\n     * @param mixed $streamOrFile\n     *\n     * @throws InvalidArgumentException\n     */\n    private function setStreamOrFile($streamOrFile)\n    {\n        if (is_string($streamOrFile)) {\n            $this->file = $streamOrFile;\n        } elseif (is_resource($streamOrFile)) {\n            $this->stream = new Stream($streamOrFile);\n        } elseif ($streamOrFile instanceof StreamInterface) {\n            $this->stream = $streamOrFile;\n        } else {\n            throw new InvalidArgumentException(\n                'Invalid stream or file provided for UploadedFile'\n            );\n        }\n    }\n\n    /**\n     * @param int $error\n     *\n     * @throws InvalidArgumentException\n     */\n    private function setError($error)\n    {\n        if (false === is_int($error)) {\n            throw new InvalidArgumentException(\n                'Upload file error status must be an integer'\n            );\n        }\n\n        if (false === in_array($error, UploadedFile::$errors)) {\n            throw new InvalidArgumentException(\n                'Invalid error status for UploadedFile'\n            );\n        }\n\n        $this->error = $error;\n    }\n\n    /**\n     * @param int $size\n     *\n     * @throws InvalidArgumentException\n     */\n    private function setSize($size)\n    {\n        if (false === is_int($size)) {\n            throw new InvalidArgumentException(\n                'Upload file size must be an integer'\n            );\n        }\n\n        $this->size = $size;\n    }\n\n    /**\n     * @param mixed $param\n     *\n     * @return bool\n     */\n    private function isStringOrNull($param)\n    {\n        return in_array(gettype($param), ['string', 'NULL']);\n    }\n\n    /**\n     * @param mixed $param\n     *\n     * @return bool\n     */\n    private function isStringNotEmpty($param)\n    {\n        return is_string($param) && false === empty($param);\n    }\n\n    /**\n     * @param string|null $clientFilename\n     *\n     * @throws InvalidArgumentException\n     */\n    private function setClientFilename($clientFilename)\n    {\n        if (false === $this->isStringOrNull($clientFilename)) {\n            throw new InvalidArgumentException(\n                'Upload file client filename must be a string or null'\n            );\n        }\n\n        $this->clientFilename = $clientFilename;\n    }\n\n    /**\n     * @param string|null $clientMediaType\n     *\n     * @throws InvalidArgumentException\n     */\n    private function setClientMediaType($clientMediaType)\n    {\n        if (false === $this->isStringOrNull($clientMediaType)) {\n            throw new InvalidArgumentException(\n                'Upload file client media type must be a string or null'\n            );\n        }\n\n        $this->clientMediaType = $clientMediaType;\n    }\n\n    /**\n     * Return true if there is no upload error\n     *\n     * @return bool\n     */\n    private function isOk()\n    {\n        return $this->error === UPLOAD_ERR_OK;\n    }\n\n    /**\n     * @return bool\n     */\n    public function isMoved()\n    {\n        return $this->moved;\n    }\n\n    /**\n     * @throws RuntimeException if is moved or not ok\n     */\n    private function validateActive()\n    {\n        if (false === $this->isOk()) {\n            throw new RuntimeException('Cannot retrieve stream due to upload error');\n        }\n\n        if ($this->isMoved()) {\n            throw new RuntimeException('Cannot retrieve stream after it has already been moved');\n        }\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @throws RuntimeException if the upload was not successful.\n     */\n    public function getStream()\n    {\n        $this->validateActive();\n\n        if ($this->stream instanceof StreamInterface) {\n            return $this->stream;\n        }\n\n        return new LazyOpenStream($this->file, 'r+');\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see http://php.net/is_uploaded_file\n     * @see http://php.net/move_uploaded_file\n     *\n     * @param string $targetPath Path to which to move the uploaded file.\n     *\n     * @throws RuntimeException         if the upload was not successful.\n     * @throws InvalidArgumentException if the $path specified is invalid.\n     * @throws RuntimeException         on any error during the move operation, or on\n     *                                  the second or subsequent call to the method.\n     */\n    public function moveTo($targetPath)\n    {\n        $this->validateActive();\n\n        if (false === $this->isStringNotEmpty($targetPath)) {\n            throw new InvalidArgumentException(\n                'Invalid path provided for move operation; must be a non-empty string'\n            );\n        }\n\n        if ($this->file) {\n            $this->moved = php_sapi_name() == 'cli'\n                ? rename($this->file, $targetPath)\n                : move_uploaded_file($this->file, $targetPath);\n        } else {\n            Utils::copyToStream(\n                $this->getStream(),\n                new LazyOpenStream($targetPath, 'w')\n            );\n\n            $this->moved = true;\n        }\n\n        if (false === $this->moved) {\n            throw new RuntimeException(\n                sprintf('Uploaded file could not be moved to %s', $targetPath)\n            );\n        }\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @return int|null The file size in bytes or null if unknown.\n     */\n    public function getSize()\n    {\n        return $this->size;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see http://php.net/manual/en/features.file-upload.errors.php\n     *\n     * @return int One of PHP's UPLOAD_ERR_XXX constants.\n     */\n    public function getError()\n    {\n        return $this->error;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @return string|null The filename sent by the client or null if none\n     *                     was provided.\n     */\n    public function getClientFilename()\n    {\n        return $this->clientFilename;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getClientMediaType()\n    {\n        return $this->clientMediaType;\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/psr7/src/Uri.php",
    "content": "<?php\n\nnamespace GuzzleHttp\\Psr7;\n\nuse Psr\\Http\\Message\\UriInterface;\n\n/**\n * PSR-7 URI implementation.\n *\n * @author Michael Dowling\n * @author Tobias Schultze\n * @author Matthew Weier O'Phinney\n */\nclass Uri implements UriInterface\n{\n    /**\n     * Absolute http and https URIs require a host per RFC 7230 Section 2.7\n     * but in generic URIs the host can be empty. So for http(s) URIs\n     * we apply this default host when no host is given yet to form a\n     * valid URI.\n     */\n    const HTTP_DEFAULT_HOST = 'localhost';\n\n    private static $defaultPorts = [\n        'http'  => 80,\n        'https' => 443,\n        'ftp' => 21,\n        'gopher' => 70,\n        'nntp' => 119,\n        'news' => 119,\n        'telnet' => 23,\n        'tn3270' => 23,\n        'imap' => 143,\n        'pop' => 110,\n        'ldap' => 389,\n    ];\n\n    private static $charUnreserved = 'a-zA-Z0-9_\\-\\.~';\n    private static $charSubDelims = '!\\$&\\'\\(\\)\\*\\+,;=';\n    private static $replaceQuery = ['=' => '%3D', '&' => '%26'];\n\n    /** @var string Uri scheme. */\n    private $scheme = '';\n\n    /** @var string Uri user info. */\n    private $userInfo = '';\n\n    /** @var string Uri host. */\n    private $host = '';\n\n    /** @var int|null Uri port. */\n    private $port;\n\n    /** @var string Uri path. */\n    private $path = '';\n\n    /** @var string Uri query string. */\n    private $query = '';\n\n    /** @var string Uri fragment. */\n    private $fragment = '';\n\n    /**\n     * @param string $uri URI to parse\n     */\n    public function __construct($uri = '')\n    {\n        // weak type check to also accept null until we can add scalar type hints\n        if ($uri != '') {\n            $parts = self::parse($uri);\n            if ($parts === false) {\n                throw new \\InvalidArgumentException(\"Unable to parse URI: $uri\");\n            }\n            $this->applyParts($parts);\n        }\n    }\n\n    /**\n     * UTF-8 aware \\parse_url() replacement.\n     *\n     * The internal function produces broken output for non ASCII domain names\n     * (IDN) when used with locales other than \"C\".\n     *\n     * On the other hand, cURL understands IDN correctly only when UTF-8 locale\n     * is configured (\"C.UTF-8\", \"en_US.UTF-8\", etc.).\n     *\n     * @see https://bugs.php.net/bug.php?id=52923\n     * @see https://www.php.net/manual/en/function.parse-url.php#114817\n     * @see https://curl.haxx.se/libcurl/c/CURLOPT_URL.html#ENCODING\n     *\n     * @param string $url\n     *\n     * @return array|false\n     */\n    private static function parse($url)\n    {\n        // If IPv6\n        $prefix = '';\n        if (preg_match('%^(.*://\\[[0-9:a-f]+\\])(.*?)$%', $url, $matches)) {\n            $prefix = $matches[1];\n            $url = $matches[2];\n        }\n\n        $encodedUrl = preg_replace_callback(\n            '%[^:/@?&=#]+%usD',\n            static function ($matches) {\n                return urlencode($matches[0]);\n            },\n            $url\n        );\n\n        $result = parse_url($prefix . $encodedUrl);\n\n        if ($result === false) {\n            return false;\n        }\n\n        return array_map('urldecode', $result);\n    }\n\n    public function __toString()\n    {\n        return self::composeComponents(\n            $this->scheme,\n            $this->getAuthority(),\n            $this->path,\n            $this->query,\n            $this->fragment\n        );\n    }\n\n    /**\n     * Composes a URI reference string from its various components.\n     *\n     * Usually this method does not need to be called manually but instead is used indirectly via\n     * `Psr\\Http\\Message\\UriInterface::__toString`.\n     *\n     * PSR-7 UriInterface treats an empty component the same as a missing component as\n     * getQuery(), getFragment() etc. always return a string. This explains the slight\n     * difference to RFC 3986 Section 5.3.\n     *\n     * Another adjustment is that the authority separator is added even when the authority is missing/empty\n     * for the \"file\" scheme. This is because PHP stream functions like `file_get_contents` only work with\n     * `file:///myfile` but not with `file:/myfile` although they are equivalent according to RFC 3986. But\n     * `file:///` is the more common syntax for the file scheme anyway (Chrome for example redirects to\n     * that format).\n     *\n     * @param string $scheme\n     * @param string $authority\n     * @param string $path\n     * @param string $query\n     * @param string $fragment\n     *\n     * @return string\n     *\n     * @link https://tools.ietf.org/html/rfc3986#section-5.3\n     */\n    public static function composeComponents($scheme, $authority, $path, $query, $fragment)\n    {\n        $uri = '';\n\n        // weak type checks to also accept null until we can add scalar type hints\n        if ($scheme != '') {\n            $uri .= $scheme . ':';\n        }\n\n        if ($authority != ''|| $scheme === 'file') {\n            $uri .= '//' . $authority;\n        }\n\n        $uri .= $path;\n\n        if ($query != '') {\n            $uri .= '?' . $query;\n        }\n\n        if ($fragment != '') {\n            $uri .= '#' . $fragment;\n        }\n\n        return $uri;\n    }\n\n    /**\n     * Whether the URI has the default port of the current scheme.\n     *\n     * `Psr\\Http\\Message\\UriInterface::getPort` may return null or the standard port. This method can be used\n     * independently of the implementation.\n     *\n     * @param UriInterface $uri\n     *\n     * @return bool\n     */\n    public static function isDefaultPort(UriInterface $uri)\n    {\n        return $uri->getPort() === null\n            || (isset(self::$defaultPorts[$uri->getScheme()]) && $uri->getPort() === self::$defaultPorts[$uri->getScheme()]);\n    }\n\n    /**\n     * Whether the URI is absolute, i.e. it has a scheme.\n     *\n     * An instance of UriInterface can either be an absolute URI or a relative reference. This method returns true\n     * if it is the former. An absolute URI has a scheme. A relative reference is used to express a URI relative\n     * to another URI, the base URI. Relative references can be divided into several forms:\n     * - network-path references, e.g. '//example.com/path'\n     * - absolute-path references, e.g. '/path'\n     * - relative-path references, e.g. 'subpath'\n     *\n     * @param UriInterface $uri\n     *\n     * @return bool\n     *\n     * @see Uri::isNetworkPathReference\n     * @see Uri::isAbsolutePathReference\n     * @see Uri::isRelativePathReference\n     * @link https://tools.ietf.org/html/rfc3986#section-4\n     */\n    public static function isAbsolute(UriInterface $uri)\n    {\n        return $uri->getScheme() !== '';\n    }\n\n    /**\n     * Whether the URI is a network-path reference.\n     *\n     * A relative reference that begins with two slash characters is termed an network-path reference.\n     *\n     * @param UriInterface $uri\n     *\n     * @return bool\n     *\n     * @link https://tools.ietf.org/html/rfc3986#section-4.2\n     */\n    public static function isNetworkPathReference(UriInterface $uri)\n    {\n        return $uri->getScheme() === '' && $uri->getAuthority() !== '';\n    }\n\n    /**\n     * Whether the URI is a absolute-path reference.\n     *\n     * A relative reference that begins with a single slash character is termed an absolute-path reference.\n     *\n     * @param UriInterface $uri\n     *\n     * @return bool\n     *\n     * @link https://tools.ietf.org/html/rfc3986#section-4.2\n     */\n    public static function isAbsolutePathReference(UriInterface $uri)\n    {\n        return $uri->getScheme() === ''\n            && $uri->getAuthority() === ''\n            && isset($uri->getPath()[0])\n            && $uri->getPath()[0] === '/';\n    }\n\n    /**\n     * Whether the URI is a relative-path reference.\n     *\n     * A relative reference that does not begin with a slash character is termed a relative-path reference.\n     *\n     * @param UriInterface $uri\n     *\n     * @return bool\n     *\n     * @link https://tools.ietf.org/html/rfc3986#section-4.2\n     */\n    public static function isRelativePathReference(UriInterface $uri)\n    {\n        return $uri->getScheme() === ''\n            && $uri->getAuthority() === ''\n            && (!isset($uri->getPath()[0]) || $uri->getPath()[0] !== '/');\n    }\n\n    /**\n     * Whether the URI is a same-document reference.\n     *\n     * A same-document reference refers to a URI that is, aside from its fragment\n     * component, identical to the base URI. When no base URI is given, only an empty\n     * URI reference (apart from its fragment) is considered a same-document reference.\n     *\n     * @param UriInterface      $uri  The URI to check\n     * @param UriInterface|null $base An optional base URI to compare against\n     *\n     * @return bool\n     *\n     * @link https://tools.ietf.org/html/rfc3986#section-4.4\n     */\n    public static function isSameDocumentReference(UriInterface $uri, UriInterface $base = null)\n    {\n        if ($base !== null) {\n            $uri = UriResolver::resolve($base, $uri);\n\n            return ($uri->getScheme() === $base->getScheme())\n                && ($uri->getAuthority() === $base->getAuthority())\n                && ($uri->getPath() === $base->getPath())\n                && ($uri->getQuery() === $base->getQuery());\n        }\n\n        return $uri->getScheme() === '' && $uri->getAuthority() === '' && $uri->getPath() === '' && $uri->getQuery() === '';\n    }\n\n    /**\n     * Removes dot segments from a path and returns the new path.\n     *\n     * @param string $path\n     *\n     * @return string\n     *\n     * @deprecated since version 1.4. Use UriResolver::removeDotSegments instead.\n     * @see UriResolver::removeDotSegments\n     */\n    public static function removeDotSegments($path)\n    {\n        return UriResolver::removeDotSegments($path);\n    }\n\n    /**\n     * Converts the relative URI into a new URI that is resolved against the base URI.\n     *\n     * @param UriInterface        $base Base URI\n     * @param string|UriInterface $rel  Relative URI\n     *\n     * @return UriInterface\n     *\n     * @deprecated since version 1.4. Use UriResolver::resolve instead.\n     * @see UriResolver::resolve\n     */\n    public static function resolve(UriInterface $base, $rel)\n    {\n        if (!($rel instanceof UriInterface)) {\n            $rel = new self($rel);\n        }\n\n        return UriResolver::resolve($base, $rel);\n    }\n\n    /**\n     * Creates a new URI with a specific query string value removed.\n     *\n     * Any existing query string values that exactly match the provided key are\n     * removed.\n     *\n     * @param UriInterface $uri URI to use as a base.\n     * @param string       $key Query string key to remove.\n     *\n     * @return UriInterface\n     */\n    public static function withoutQueryValue(UriInterface $uri, $key)\n    {\n        $result = self::getFilteredQueryString($uri, [$key]);\n\n        return $uri->withQuery(implode('&', $result));\n    }\n\n    /**\n     * Creates a new URI with a specific query string value.\n     *\n     * Any existing query string values that exactly match the provided key are\n     * removed and replaced with the given key value pair.\n     *\n     * A value of null will set the query string key without a value, e.g. \"key\"\n     * instead of \"key=value\".\n     *\n     * @param UriInterface $uri   URI to use as a base.\n     * @param string       $key   Key to set.\n     * @param string|null  $value Value to set\n     *\n     * @return UriInterface\n     */\n    public static function withQueryValue(UriInterface $uri, $key, $value)\n    {\n        $result = self::getFilteredQueryString($uri, [$key]);\n\n        $result[] = self::generateQueryString($key, $value);\n\n        return $uri->withQuery(implode('&', $result));\n    }\n\n    /**\n     * Creates a new URI with multiple specific query string values.\n     *\n     * It has the same behavior as withQueryValue() but for an associative array of key => value.\n     *\n     * @param UriInterface $uri           URI to use as a base.\n     * @param array        $keyValueArray Associative array of key and values\n     *\n     * @return UriInterface\n     */\n    public static function withQueryValues(UriInterface $uri, array $keyValueArray)\n    {\n        $result = self::getFilteredQueryString($uri, array_keys($keyValueArray));\n\n        foreach ($keyValueArray as $key => $value) {\n            $result[] = self::generateQueryString($key, $value);\n        }\n\n        return $uri->withQuery(implode('&', $result));\n    }\n\n    /**\n     * Creates a URI from a hash of `parse_url` components.\n     *\n     * @param array $parts\n     *\n     * @return UriInterface\n     *\n     * @link http://php.net/manual/en/function.parse-url.php\n     *\n     * @throws \\InvalidArgumentException If the components do not form a valid URI.\n     */\n    public static function fromParts(array $parts)\n    {\n        $uri = new self();\n        $uri->applyParts($parts);\n        $uri->validateState();\n\n        return $uri;\n    }\n\n    public function getScheme()\n    {\n        return $this->scheme;\n    }\n\n    public function getAuthority()\n    {\n        $authority = $this->host;\n        if ($this->userInfo !== '') {\n            $authority = $this->userInfo . '@' . $authority;\n        }\n\n        if ($this->port !== null) {\n            $authority .= ':' . $this->port;\n        }\n\n        return $authority;\n    }\n\n    public function getUserInfo()\n    {\n        return $this->userInfo;\n    }\n\n    public function getHost()\n    {\n        return $this->host;\n    }\n\n    public function getPort()\n    {\n        return $this->port;\n    }\n\n    public function getPath()\n    {\n        return $this->path;\n    }\n\n    public function getQuery()\n    {\n        return $this->query;\n    }\n\n    public function getFragment()\n    {\n        return $this->fragment;\n    }\n\n    public function withScheme($scheme)\n    {\n        $scheme = $this->filterScheme($scheme);\n\n        if ($this->scheme === $scheme) {\n            return $this;\n        }\n\n        $new = clone $this;\n        $new->scheme = $scheme;\n        $new->removeDefaultPort();\n        $new->validateState();\n\n        return $new;\n    }\n\n    public function withUserInfo($user, $password = null)\n    {\n        $info = $this->filterUserInfoComponent($user);\n        if ($password !== null) {\n            $info .= ':' . $this->filterUserInfoComponent($password);\n        }\n\n        if ($this->userInfo === $info) {\n            return $this;\n        }\n\n        $new = clone $this;\n        $new->userInfo = $info;\n        $new->validateState();\n\n        return $new;\n    }\n\n    public function withHost($host)\n    {\n        $host = $this->filterHost($host);\n\n        if ($this->host === $host) {\n            return $this;\n        }\n\n        $new = clone $this;\n        $new->host = $host;\n        $new->validateState();\n\n        return $new;\n    }\n\n    public function withPort($port)\n    {\n        $port = $this->filterPort($port);\n\n        if ($this->port === $port) {\n            return $this;\n        }\n\n        $new = clone $this;\n        $new->port = $port;\n        $new->removeDefaultPort();\n        $new->validateState();\n\n        return $new;\n    }\n\n    public function withPath($path)\n    {\n        $path = $this->filterPath($path);\n\n        if ($this->path === $path) {\n            return $this;\n        }\n\n        $new = clone $this;\n        $new->path = $path;\n        $new->validateState();\n\n        return $new;\n    }\n\n    public function withQuery($query)\n    {\n        $query = $this->filterQueryAndFragment($query);\n\n        if ($this->query === $query) {\n            return $this;\n        }\n\n        $new = clone $this;\n        $new->query = $query;\n\n        return $new;\n    }\n\n    public function withFragment($fragment)\n    {\n        $fragment = $this->filterQueryAndFragment($fragment);\n\n        if ($this->fragment === $fragment) {\n            return $this;\n        }\n\n        $new = clone $this;\n        $new->fragment = $fragment;\n\n        return $new;\n    }\n\n    /**\n     * Apply parse_url parts to a URI.\n     *\n     * @param array $parts Array of parse_url parts to apply.\n     */\n    private function applyParts(array $parts)\n    {\n        $this->scheme = isset($parts['scheme'])\n            ? $this->filterScheme($parts['scheme'])\n            : '';\n        $this->userInfo = isset($parts['user'])\n            ? $this->filterUserInfoComponent($parts['user'])\n            : '';\n        $this->host = isset($parts['host'])\n            ? $this->filterHost($parts['host'])\n            : '';\n        $this->port = isset($parts['port'])\n            ? $this->filterPort($parts['port'])\n            : null;\n        $this->path = isset($parts['path'])\n            ? $this->filterPath($parts['path'])\n            : '';\n        $this->query = isset($parts['query'])\n            ? $this->filterQueryAndFragment($parts['query'])\n            : '';\n        $this->fragment = isset($parts['fragment'])\n            ? $this->filterQueryAndFragment($parts['fragment'])\n            : '';\n        if (isset($parts['pass'])) {\n            $this->userInfo .= ':' . $this->filterUserInfoComponent($parts['pass']);\n        }\n\n        $this->removeDefaultPort();\n    }\n\n    /**\n     * @param string $scheme\n     *\n     * @return string\n     *\n     * @throws \\InvalidArgumentException If the scheme is invalid.\n     */\n    private function filterScheme($scheme)\n    {\n        if (!is_string($scheme)) {\n            throw new \\InvalidArgumentException('Scheme must be a string');\n        }\n\n        return \\strtr($scheme, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz');\n    }\n\n    /**\n     * @param string $component\n     *\n     * @return string\n     *\n     * @throws \\InvalidArgumentException If the user info is invalid.\n     */\n    private function filterUserInfoComponent($component)\n    {\n        if (!is_string($component)) {\n            throw new \\InvalidArgumentException('User info must be a string');\n        }\n\n        return preg_replace_callback(\n            '/(?:[^%' . self::$charUnreserved . self::$charSubDelims . ']+|%(?![A-Fa-f0-9]{2}))/',\n            [$this, 'rawurlencodeMatchZero'],\n            $component\n        );\n    }\n\n    /**\n     * @param string $host\n     *\n     * @return string\n     *\n     * @throws \\InvalidArgumentException If the host is invalid.\n     */\n    private function filterHost($host)\n    {\n        if (!is_string($host)) {\n            throw new \\InvalidArgumentException('Host must be a string');\n        }\n\n        return \\strtr($host, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz');\n    }\n\n    /**\n     * @param int|null $port\n     *\n     * @return int|null\n     *\n     * @throws \\InvalidArgumentException If the port is invalid.\n     */\n    private function filterPort($port)\n    {\n        if ($port === null) {\n            return null;\n        }\n\n        $port = (int) $port;\n        if (0 > $port || 0xffff < $port) {\n            throw new \\InvalidArgumentException(\n                sprintf('Invalid port: %d. Must be between 0 and 65535', $port)\n            );\n        }\n\n        return $port;\n    }\n\n    /**\n     * @param UriInterface $uri\n     * @param array        $keys\n     *\n     * @return array\n     */\n    private static function getFilteredQueryString(UriInterface $uri, array $keys)\n    {\n        $current = $uri->getQuery();\n\n        if ($current === '') {\n            return [];\n        }\n\n        $decodedKeys = array_map('rawurldecode', $keys);\n\n        return array_filter(explode('&', $current), function ($part) use ($decodedKeys) {\n            return !in_array(rawurldecode(explode('=', $part)[0]), $decodedKeys, true);\n        });\n    }\n\n    /**\n     * @param string      $key\n     * @param string|null $value\n     *\n     * @return string\n     */\n    private static function generateQueryString($key, $value)\n    {\n        // Query string separators (\"=\", \"&\") within the key or value need to be encoded\n        // (while preventing double-encoding) before setting the query string. All other\n        // chars that need percent-encoding will be encoded by withQuery().\n        $queryString = strtr($key, self::$replaceQuery);\n\n        if ($value !== null) {\n            $queryString .= '=' . strtr($value, self::$replaceQuery);\n        }\n\n        return $queryString;\n    }\n\n    private function removeDefaultPort()\n    {\n        if ($this->port !== null && self::isDefaultPort($this)) {\n            $this->port = null;\n        }\n    }\n\n    /**\n     * Filters the path of a URI\n     *\n     * @param string $path\n     *\n     * @return string\n     *\n     * @throws \\InvalidArgumentException If the path is invalid.\n     */\n    private function filterPath($path)\n    {\n        if (!is_string($path)) {\n            throw new \\InvalidArgumentException('Path must be a string');\n        }\n\n        return preg_replace_callback(\n            '/(?:[^' . self::$charUnreserved . self::$charSubDelims . '%:@\\/]++|%(?![A-Fa-f0-9]{2}))/',\n            [$this, 'rawurlencodeMatchZero'],\n            $path\n        );\n    }\n\n    /**\n     * Filters the query string or fragment of a URI.\n     *\n     * @param string $str\n     *\n     * @return string\n     *\n     * @throws \\InvalidArgumentException If the query or fragment is invalid.\n     */\n    private function filterQueryAndFragment($str)\n    {\n        if (!is_string($str)) {\n            throw new \\InvalidArgumentException('Query and fragment must be a string');\n        }\n\n        return preg_replace_callback(\n            '/(?:[^' . self::$charUnreserved . self::$charSubDelims . '%:@\\/\\?]++|%(?![A-Fa-f0-9]{2}))/',\n            [$this, 'rawurlencodeMatchZero'],\n            $str\n        );\n    }\n\n    private function rawurlencodeMatchZero(array $match)\n    {\n        return rawurlencode($match[0]);\n    }\n\n    private function validateState()\n    {\n        if ($this->host === '' && ($this->scheme === 'http' || $this->scheme === 'https')) {\n            $this->host = self::HTTP_DEFAULT_HOST;\n        }\n\n        if ($this->getAuthority() === '') {\n            if (0 === strpos($this->path, '//')) {\n                throw new \\InvalidArgumentException('The path of a URI without an authority must not start with two slashes \"//\"');\n            }\n            if ($this->scheme === '' && false !== strpos(explode('/', $this->path, 2)[0], ':')) {\n                throw new \\InvalidArgumentException('A relative URI must not have a path beginning with a segment containing a colon');\n            }\n        } elseif (isset($this->path[0]) && $this->path[0] !== '/') {\n            @trigger_error(\n                'The path of a URI with an authority must start with a slash \"/\" or be empty. Automagically fixing the URI ' .\n                'by adding a leading slash to the path is deprecated since version 1.4 and will throw an exception instead.',\n                E_USER_DEPRECATED\n            );\n            $this->path = '/' . $this->path;\n            //throw new \\InvalidArgumentException('The path of a URI with an authority must start with a slash \"/\" or be empty');\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/psr7/src/UriComparator.php",
    "content": "<?php\n\nnamespace GuzzleHttp\\Psr7;\n\nuse Psr\\Http\\Message\\UriInterface;\n\n/**\n * Provides methods to determine if a modified URL should be considered cross-origin.\n *\n * @author Graham Campbell\n */\nfinal class UriComparator\n{\n    /**\n     * Determines if a modified URL should be considered cross-origin with\n     * respect to an original URL.\n     *\n     * @return bool\n     */\n    public static function isCrossOrigin(UriInterface $original, UriInterface $modified)\n    {\n        if (\\strcasecmp($original->getHost(), $modified->getHost()) !== 0) {\n            return true;\n        }\n\n        if ($original->getScheme() !== $modified->getScheme()) {\n            return true;\n        }\n\n        if (self::computePort($original) !== self::computePort($modified)) {\n            return true;\n        }\n\n        return false;\n    }\n\n    /**\n     * @return int\n     */\n    private static function computePort(UriInterface $uri)\n    {\n        $port = $uri->getPort();\n\n        if (null !== $port) {\n            return $port;\n        }\n\n        return 'https' === $uri->getScheme() ? 443 : 80;\n    }\n\n    private function __construct()\n    {\n        // cannot be instantiated\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/psr7/src/UriNormalizer.php",
    "content": "<?php\n\nnamespace GuzzleHttp\\Psr7;\n\nuse Psr\\Http\\Message\\UriInterface;\n\n/**\n * Provides methods to normalize and compare URIs.\n *\n * @author Tobias Schultze\n *\n * @link https://tools.ietf.org/html/rfc3986#section-6\n */\nfinal class UriNormalizer\n{\n    /**\n     * Default normalizations which only include the ones that preserve semantics.\n     *\n     * self::CAPITALIZE_PERCENT_ENCODING | self::DECODE_UNRESERVED_CHARACTERS | self::CONVERT_EMPTY_PATH |\n     * self::REMOVE_DEFAULT_HOST | self::REMOVE_DEFAULT_PORT | self::REMOVE_DOT_SEGMENTS\n     */\n    const PRESERVING_NORMALIZATIONS = 63;\n\n    /**\n     * All letters within a percent-encoding triplet (e.g., \"%3A\") are case-insensitive, and should be capitalized.\n     *\n     * Example: http://example.org/a%c2%b1b → http://example.org/a%C2%B1b\n     */\n    const CAPITALIZE_PERCENT_ENCODING = 1;\n\n    /**\n     * Decodes percent-encoded octets of unreserved characters.\n     *\n     * For consistency, percent-encoded octets in the ranges of ALPHA (%41–%5A and %61–%7A), DIGIT (%30–%39),\n     * hyphen (%2D), period (%2E), underscore (%5F), or tilde (%7E) should not be created by URI producers and,\n     * when found in a URI, should be decoded to their corresponding unreserved characters by URI normalizers.\n     *\n     * Example: http://example.org/%7Eusern%61me/ → http://example.org/~username/\n     */\n    const DECODE_UNRESERVED_CHARACTERS = 2;\n\n    /**\n     * Converts the empty path to \"/\" for http and https URIs.\n     *\n     * Example: http://example.org → http://example.org/\n     */\n    const CONVERT_EMPTY_PATH = 4;\n\n    /**\n     * Removes the default host of the given URI scheme from the URI.\n     *\n     * Only the \"file\" scheme defines the default host \"localhost\".\n     * All of `file:/myfile`, `file:///myfile`, and `file://localhost/myfile`\n     * are equivalent according to RFC 3986. The first format is not accepted\n     * by PHPs stream functions and thus already normalized implicitly to the\n     * second format in the Uri class. See `GuzzleHttp\\Psr7\\Uri::composeComponents`.\n     *\n     * Example: file://localhost/myfile → file:///myfile\n     */\n    const REMOVE_DEFAULT_HOST = 8;\n\n    /**\n     * Removes the default port of the given URI scheme from the URI.\n     *\n     * Example: http://example.org:80/ → http://example.org/\n     */\n    const REMOVE_DEFAULT_PORT = 16;\n\n    /**\n     * Removes unnecessary dot-segments.\n     *\n     * Dot-segments in relative-path references are not removed as it would\n     * change the semantics of the URI reference.\n     *\n     * Example: http://example.org/../a/b/../c/./d.html → http://example.org/a/c/d.html\n     */\n    const REMOVE_DOT_SEGMENTS = 32;\n\n    /**\n     * Paths which include two or more adjacent slashes are converted to one.\n     *\n     * Webservers usually ignore duplicate slashes and treat those URIs equivalent.\n     * But in theory those URIs do not need to be equivalent. So this normalization\n     * may change the semantics. Encoded slashes (%2F) are not removed.\n     *\n     * Example: http://example.org//foo///bar.html → http://example.org/foo/bar.html\n     */\n    const REMOVE_DUPLICATE_SLASHES = 64;\n\n    /**\n     * Sort query parameters with their values in alphabetical order.\n     *\n     * However, the order of parameters in a URI may be significant (this is not defined by the standard).\n     * So this normalization is not safe and may change the semantics of the URI.\n     *\n     * Example: ?lang=en&article=fred → ?article=fred&lang=en\n     *\n     * Note: The sorting is neither locale nor Unicode aware (the URI query does not get decoded at all) as the\n     * purpose is to be able to compare URIs in a reproducible way, not to have the params sorted perfectly.\n     */\n    const SORT_QUERY_PARAMETERS = 128;\n\n    /**\n     * Returns a normalized URI.\n     *\n     * The scheme and host component are already normalized to lowercase per PSR-7 UriInterface.\n     * This methods adds additional normalizations that can be configured with the $flags parameter.\n     *\n     * PSR-7 UriInterface cannot distinguish between an empty component and a missing component as\n     * getQuery(), getFragment() etc. always return a string. This means the URIs \"/?#\" and \"/\" are\n     * treated equivalent which is not necessarily true according to RFC 3986. But that difference\n     * is highly uncommon in reality. So this potential normalization is implied in PSR-7 as well.\n     *\n     * @param UriInterface $uri   The URI to normalize\n     * @param int          $flags A bitmask of normalizations to apply, see constants\n     *\n     * @return UriInterface The normalized URI\n     *\n     * @link https://tools.ietf.org/html/rfc3986#section-6.2\n     */\n    public static function normalize(UriInterface $uri, $flags = self::PRESERVING_NORMALIZATIONS)\n    {\n        if ($flags & self::CAPITALIZE_PERCENT_ENCODING) {\n            $uri = self::capitalizePercentEncoding($uri);\n        }\n\n        if ($flags & self::DECODE_UNRESERVED_CHARACTERS) {\n            $uri = self::decodeUnreservedCharacters($uri);\n        }\n\n        if ($flags & self::CONVERT_EMPTY_PATH && $uri->getPath() === '' &&\n            ($uri->getScheme() === 'http' || $uri->getScheme() === 'https')\n        ) {\n            $uri = $uri->withPath('/');\n        }\n\n        if ($flags & self::REMOVE_DEFAULT_HOST && $uri->getScheme() === 'file' && $uri->getHost() === 'localhost') {\n            $uri = $uri->withHost('');\n        }\n\n        if ($flags & self::REMOVE_DEFAULT_PORT && $uri->getPort() !== null && Uri::isDefaultPort($uri)) {\n            $uri = $uri->withPort(null);\n        }\n\n        if ($flags & self::REMOVE_DOT_SEGMENTS && !Uri::isRelativePathReference($uri)) {\n            $uri = $uri->withPath(UriResolver::removeDotSegments($uri->getPath()));\n        }\n\n        if ($flags & self::REMOVE_DUPLICATE_SLASHES) {\n            $uri = $uri->withPath(preg_replace('#//++#', '/', $uri->getPath()));\n        }\n\n        if ($flags & self::SORT_QUERY_PARAMETERS && $uri->getQuery() !== '') {\n            $queryKeyValues = explode('&', $uri->getQuery());\n            sort($queryKeyValues);\n            $uri = $uri->withQuery(implode('&', $queryKeyValues));\n        }\n\n        return $uri;\n    }\n\n    /**\n     * Whether two URIs can be considered equivalent.\n     *\n     * Both URIs are normalized automatically before comparison with the given $normalizations bitmask. The method also\n     * accepts relative URI references and returns true when they are equivalent. This of course assumes they will be\n     * resolved against the same base URI. If this is not the case, determination of equivalence or difference of\n     * relative references does not mean anything.\n     *\n     * @param UriInterface $uri1           An URI to compare\n     * @param UriInterface $uri2           An URI to compare\n     * @param int          $normalizations A bitmask of normalizations to apply, see constants\n     *\n     * @return bool\n     *\n     * @link https://tools.ietf.org/html/rfc3986#section-6.1\n     */\n    public static function isEquivalent(UriInterface $uri1, UriInterface $uri2, $normalizations = self::PRESERVING_NORMALIZATIONS)\n    {\n        return (string) self::normalize($uri1, $normalizations) === (string) self::normalize($uri2, $normalizations);\n    }\n\n    private static function capitalizePercentEncoding(UriInterface $uri)\n    {\n        $regex = '/(?:%[A-Fa-f0-9]{2})++/';\n\n        $callback = function (array $match) {\n            return strtoupper($match[0]);\n        };\n\n        return\n            $uri->withPath(\n                preg_replace_callback($regex, $callback, $uri->getPath())\n            )->withQuery(\n                preg_replace_callback($regex, $callback, $uri->getQuery())\n            );\n    }\n\n    private static function decodeUnreservedCharacters(UriInterface $uri)\n    {\n        $regex = '/%(?:2D|2E|5F|7E|3[0-9]|[46][1-9A-F]|[57][0-9A])/i';\n\n        $callback = function (array $match) {\n            return rawurldecode($match[0]);\n        };\n\n        return\n            $uri->withPath(\n                preg_replace_callback($regex, $callback, $uri->getPath())\n            )->withQuery(\n                preg_replace_callback($regex, $callback, $uri->getQuery())\n            );\n    }\n\n    private function __construct()\n    {\n        // cannot be instantiated\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/psr7/src/UriResolver.php",
    "content": "<?php\n\nnamespace GuzzleHttp\\Psr7;\n\nuse Psr\\Http\\Message\\UriInterface;\n\n/**\n * Resolves a URI reference in the context of a base URI and the opposite way.\n *\n * @author Tobias Schultze\n *\n * @link https://tools.ietf.org/html/rfc3986#section-5\n */\nfinal class UriResolver\n{\n    /**\n     * Removes dot segments from a path and returns the new path.\n     *\n     * @param string $path\n     *\n     * @return string\n     *\n     * @link http://tools.ietf.org/html/rfc3986#section-5.2.4\n     */\n    public static function removeDotSegments($path)\n    {\n        if ($path === '' || $path === '/') {\n            return $path;\n        }\n\n        $results = [];\n        $segments = explode('/', $path);\n        foreach ($segments as $segment) {\n            if ($segment === '..') {\n                array_pop($results);\n            } elseif ($segment !== '.') {\n                $results[] = $segment;\n            }\n        }\n\n        $newPath = implode('/', $results);\n\n        if ($path[0] === '/' && (!isset($newPath[0]) || $newPath[0] !== '/')) {\n            // Re-add the leading slash if necessary for cases like \"/..\"\n            $newPath = '/' . $newPath;\n        } elseif ($newPath !== '' && ($segment === '.' || $segment === '..')) {\n            // Add the trailing slash if necessary\n            // If newPath is not empty, then $segment must be set and is the last segment from the foreach\n            $newPath .= '/';\n        }\n\n        return $newPath;\n    }\n\n    /**\n     * Converts the relative URI into a new URI that is resolved against the base URI.\n     *\n     * @param UriInterface $base Base URI\n     * @param UriInterface $rel  Relative URI\n     *\n     * @return UriInterface\n     *\n     * @link http://tools.ietf.org/html/rfc3986#section-5.2\n     */\n    public static function resolve(UriInterface $base, UriInterface $rel)\n    {\n        if ((string) $rel === '') {\n            // we can simply return the same base URI instance for this same-document reference\n            return $base;\n        }\n\n        if ($rel->getScheme() != '') {\n            return $rel->withPath(self::removeDotSegments($rel->getPath()));\n        }\n\n        if ($rel->getAuthority() != '') {\n            $targetAuthority = $rel->getAuthority();\n            $targetPath = self::removeDotSegments($rel->getPath());\n            $targetQuery = $rel->getQuery();\n        } else {\n            $targetAuthority = $base->getAuthority();\n            if ($rel->getPath() === '') {\n                $targetPath = $base->getPath();\n                $targetQuery = $rel->getQuery() != '' ? $rel->getQuery() : $base->getQuery();\n            } else {\n                if ($rel->getPath()[0] === '/') {\n                    $targetPath = $rel->getPath();\n                } else {\n                    if ($targetAuthority != '' && $base->getPath() === '') {\n                        $targetPath = '/' . $rel->getPath();\n                    } else {\n                        $lastSlashPos = strrpos($base->getPath(), '/');\n                        if ($lastSlashPos === false) {\n                            $targetPath = $rel->getPath();\n                        } else {\n                            $targetPath = substr($base->getPath(), 0, $lastSlashPos + 1) . $rel->getPath();\n                        }\n                    }\n                }\n                $targetPath = self::removeDotSegments($targetPath);\n                $targetQuery = $rel->getQuery();\n            }\n        }\n\n        return new Uri(Uri::composeComponents(\n            $base->getScheme(),\n            $targetAuthority,\n            $targetPath,\n            $targetQuery,\n            $rel->getFragment()\n        ));\n    }\n\n    /**\n     * Returns the target URI as a relative reference from the base URI.\n     *\n     * This method is the counterpart to resolve():\n     *\n     *    (string) $target === (string) UriResolver::resolve($base, UriResolver::relativize($base, $target))\n     *\n     * One use-case is to use the current request URI as base URI and then generate relative links in your documents\n     * to reduce the document size or offer self-contained downloadable document archives.\n     *\n     *    $base = new Uri('http://example.com/a/b/');\n     *    echo UriResolver::relativize($base, new Uri('http://example.com/a/b/c'));  // prints 'c'.\n     *    echo UriResolver::relativize($base, new Uri('http://example.com/a/x/y'));  // prints '../x/y'.\n     *    echo UriResolver::relativize($base, new Uri('http://example.com/a/b/?q')); // prints '?q'.\n     *    echo UriResolver::relativize($base, new Uri('http://example.org/a/b/'));   // prints '//example.org/a/b/'.\n     *\n     * This method also accepts a target that is already relative and will try to relativize it further. Only a\n     * relative-path reference will be returned as-is.\n     *\n     *    echo UriResolver::relativize($base, new Uri('/a/b/c'));  // prints 'c' as well\n     *\n     * @param UriInterface $base   Base URI\n     * @param UriInterface $target Target URI\n     *\n     * @return UriInterface The relative URI reference\n     */\n    public static function relativize(UriInterface $base, UriInterface $target)\n    {\n        if ($target->getScheme() !== '' &&\n            ($base->getScheme() !== $target->getScheme() || $target->getAuthority() === '' && $base->getAuthority() !== '')\n        ) {\n            return $target;\n        }\n\n        if (Uri::isRelativePathReference($target)) {\n            // As the target is already highly relative we return it as-is. It would be possible to resolve\n            // the target with `$target = self::resolve($base, $target);` and then try make it more relative\n            // by removing a duplicate query. But let's not do that automatically.\n            return $target;\n        }\n\n        if ($target->getAuthority() !== '' && $base->getAuthority() !== $target->getAuthority()) {\n            return $target->withScheme('');\n        }\n\n        // We must remove the path before removing the authority because if the path starts with two slashes, the URI\n        // would turn invalid. And we also cannot set a relative path before removing the authority, as that is also\n        // invalid.\n        $emptyPathUri = $target->withScheme('')->withPath('')->withUserInfo('')->withPort(null)->withHost('');\n\n        if ($base->getPath() !== $target->getPath()) {\n            return $emptyPathUri->withPath(self::getRelativePath($base, $target));\n        }\n\n        if ($base->getQuery() === $target->getQuery()) {\n            // Only the target fragment is left. And it must be returned even if base and target fragment are the same.\n            return $emptyPathUri->withQuery('');\n        }\n\n        // If the base URI has a query but the target has none, we cannot return an empty path reference as it would\n        // inherit the base query component when resolving.\n        if ($target->getQuery() === '') {\n            $segments = explode('/', $target->getPath());\n            $lastSegment = end($segments);\n\n            return $emptyPathUri->withPath($lastSegment === '' ? './' : $lastSegment);\n        }\n\n        return $emptyPathUri;\n    }\n\n    private static function getRelativePath(UriInterface $base, UriInterface $target)\n    {\n        $sourceSegments = explode('/', $base->getPath());\n        $targetSegments = explode('/', $target->getPath());\n        array_pop($sourceSegments);\n        $targetLastSegment = array_pop($targetSegments);\n        foreach ($sourceSegments as $i => $segment) {\n            if (isset($targetSegments[$i]) && $segment === $targetSegments[$i]) {\n                unset($sourceSegments[$i], $targetSegments[$i]);\n            } else {\n                break;\n            }\n        }\n        $targetSegments[] = $targetLastSegment;\n        $relativePath = str_repeat('../', count($sourceSegments)) . implode('/', $targetSegments);\n\n        // A reference to am empty last segment or an empty first sub-segment must be prefixed with \"./\".\n        // This also applies to a segment with a colon character (e.g., \"file:colon\") that cannot be used\n        // as the first segment of a relative-path reference, as it would be mistaken for a scheme name.\n        if ('' === $relativePath || false !== strpos(explode('/', $relativePath, 2)[0], ':')) {\n            $relativePath = \"./$relativePath\";\n        } elseif ('/' === $relativePath[0]) {\n            if ($base->getAuthority() != '' && $base->getPath() === '') {\n                // In this case an extra slash is added by resolve() automatically. So we must not add one here.\n                $relativePath = \".$relativePath\";\n            } else {\n                $relativePath = \"./$relativePath\";\n            }\n        }\n\n        return $relativePath;\n    }\n\n    private function __construct()\n    {\n        // cannot be instantiated\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/psr7/src/Utils.php",
    "content": "<?php\n\nnamespace GuzzleHttp\\Psr7;\n\nuse Psr\\Http\\Message\\RequestInterface;\nuse Psr\\Http\\Message\\ServerRequestInterface;\nuse Psr\\Http\\Message\\StreamInterface;\nuse Psr\\Http\\Message\\UriInterface;\n\nfinal class Utils\n{\n    /**\n     * Remove the items given by the keys, case insensitively from the data.\n     *\n     * @param iterable<string> $keys\n     *\n     * @return array\n     */\n    public static function caselessRemove($keys, array $data)\n    {\n        $result = [];\n\n        foreach ($keys as &$key) {\n            $key = strtolower($key);\n        }\n\n        foreach ($data as $k => $v) {\n            if (!in_array(strtolower($k), $keys)) {\n                $result[$k] = $v;\n            }\n        }\n\n        return $result;\n    }\n\n    /**\n     * Copy the contents of a stream into another stream until the given number\n     * of bytes have been read.\n     *\n     * @param StreamInterface $source Stream to read from\n     * @param StreamInterface $dest   Stream to write to\n     * @param int             $maxLen Maximum number of bytes to read. Pass -1\n     *                                to read the entire stream.\n     *\n     * @throws \\RuntimeException on error.\n     */\n    public static function copyToStream(StreamInterface $source, StreamInterface $dest, $maxLen = -1)\n    {\n        $bufferSize = 8192;\n\n        if ($maxLen === -1) {\n            while (!$source->eof()) {\n                if (!$dest->write($source->read($bufferSize))) {\n                    break;\n                }\n            }\n        } else {\n            $remaining = $maxLen;\n            while ($remaining > 0 && !$source->eof()) {\n                $buf = $source->read(min($bufferSize, $remaining));\n                $len = strlen($buf);\n                if (!$len) {\n                    break;\n                }\n                $remaining -= $len;\n                $dest->write($buf);\n            }\n        }\n    }\n\n    /**\n     * Copy the contents of a stream into a string until the given number of\n     * bytes have been read.\n     *\n     * @param StreamInterface $stream Stream to read\n     * @param int             $maxLen Maximum number of bytes to read. Pass -1\n     *                                to read the entire stream.\n     *\n     * @return string\n     *\n     * @throws \\RuntimeException on error.\n     */\n    public static function copyToString(StreamInterface $stream, $maxLen = -1)\n    {\n        $buffer = '';\n\n        if ($maxLen === -1) {\n            while (!$stream->eof()) {\n                $buf = $stream->read(1048576);\n                // Using a loose equality here to match on '' and false.\n                if ($buf == null) {\n                    break;\n                }\n                $buffer .= $buf;\n            }\n            return $buffer;\n        }\n\n        $len = 0;\n        while (!$stream->eof() && $len < $maxLen) {\n            $buf = $stream->read($maxLen - $len);\n            // Using a loose equality here to match on '' and false.\n            if ($buf == null) {\n                break;\n            }\n            $buffer .= $buf;\n            $len = strlen($buffer);\n        }\n\n        return $buffer;\n    }\n\n    /**\n     * Calculate a hash of a stream.\n     *\n     * This method reads the entire stream to calculate a rolling hash, based\n     * on PHP's `hash_init` functions.\n     *\n     * @param StreamInterface $stream    Stream to calculate the hash for\n     * @param string          $algo      Hash algorithm (e.g. md5, crc32, etc)\n     * @param bool            $rawOutput Whether or not to use raw output\n     *\n     * @return string Returns the hash of the stream\n     *\n     * @throws \\RuntimeException on error.\n     */\n    public static function hash(StreamInterface $stream, $algo, $rawOutput = false)\n    {\n        $pos = $stream->tell();\n\n        if ($pos > 0) {\n            $stream->rewind();\n        }\n\n        $ctx = hash_init($algo);\n        while (!$stream->eof()) {\n            hash_update($ctx, $stream->read(1048576));\n        }\n\n        $out = hash_final($ctx, (bool) $rawOutput);\n        $stream->seek($pos);\n\n        return $out;\n    }\n\n    /**\n     * Clone and modify a request with the given changes.\n     *\n     * This method is useful for reducing the number of clones needed to mutate\n     * a message.\n     *\n     * The changes can be one of:\n     * - method: (string) Changes the HTTP method.\n     * - set_headers: (array) Sets the given headers.\n     * - remove_headers: (array) Remove the given headers.\n     * - body: (mixed) Sets the given body.\n     * - uri: (UriInterface) Set the URI.\n     * - query: (string) Set the query string value of the URI.\n     * - version: (string) Set the protocol version.\n     *\n     * @param RequestInterface $request Request to clone and modify.\n     * @param array            $changes Changes to apply.\n     *\n     * @return RequestInterface\n     */\n    public static function modifyRequest(RequestInterface $request, array $changes)\n    {\n        if (!$changes) {\n            return $request;\n        }\n\n        $headers = $request->getHeaders();\n\n        if (!isset($changes['uri'])) {\n            $uri = $request->getUri();\n        } else {\n            // Remove the host header if one is on the URI\n            if ($host = $changes['uri']->getHost()) {\n                $changes['set_headers']['Host'] = $host;\n\n                if ($port = $changes['uri']->getPort()) {\n                    $standardPorts = ['http' => 80, 'https' => 443];\n                    $scheme = $changes['uri']->getScheme();\n                    if (isset($standardPorts[$scheme]) && $port != $standardPorts[$scheme]) {\n                        $changes['set_headers']['Host'] .= ':' . $port;\n                    }\n                }\n            }\n            $uri = $changes['uri'];\n        }\n\n        if (!empty($changes['remove_headers'])) {\n            $headers = self::caselessRemove($changes['remove_headers'], $headers);\n        }\n\n        if (!empty($changes['set_headers'])) {\n            $headers = self::caselessRemove(array_keys($changes['set_headers']), $headers);\n            $headers = $changes['set_headers'] + $headers;\n        }\n\n        if (isset($changes['query'])) {\n            $uri = $uri->withQuery($changes['query']);\n        }\n\n        if ($request instanceof ServerRequestInterface) {\n            $new = (new ServerRequest(\n                isset($changes['method']) ? $changes['method'] : $request->getMethod(),\n                $uri,\n                $headers,\n                isset($changes['body']) ? $changes['body'] : $request->getBody(),\n                isset($changes['version'])\n                    ? $changes['version']\n                    : $request->getProtocolVersion(),\n                $request->getServerParams()\n            ))\n            ->withParsedBody($request->getParsedBody())\n            ->withQueryParams($request->getQueryParams())\n            ->withCookieParams($request->getCookieParams())\n            ->withUploadedFiles($request->getUploadedFiles());\n\n            foreach ($request->getAttributes() as $key => $value) {\n                $new = $new->withAttribute($key, $value);\n            }\n\n            return $new;\n        }\n\n        return new Request(\n            isset($changes['method']) ? $changes['method'] : $request->getMethod(),\n            $uri,\n            $headers,\n            isset($changes['body']) ? $changes['body'] : $request->getBody(),\n            isset($changes['version'])\n                ? $changes['version']\n                : $request->getProtocolVersion()\n        );\n    }\n\n    /**\n     * Read a line from the stream up to the maximum allowed buffer length.\n     *\n     * @param StreamInterface $stream    Stream to read from\n     * @param int|null        $maxLength Maximum buffer length\n     *\n     * @return string\n     */\n    public static function readLine(StreamInterface $stream, $maxLength = null)\n    {\n        $buffer = '';\n        $size = 0;\n\n        while (!$stream->eof()) {\n            // Using a loose equality here to match on '' and false.\n            if (null == ($byte = $stream->read(1))) {\n                return $buffer;\n            }\n            $buffer .= $byte;\n            // Break when a new line is found or the max length - 1 is reached\n            if ($byte === \"\\n\" || ++$size === $maxLength - 1) {\n                break;\n            }\n        }\n\n        return $buffer;\n    }\n\n    /**\n     * Create a new stream based on the input type.\n     *\n     * Options is an associative array that can contain the following keys:\n     * - metadata: Array of custom metadata.\n     * - size: Size of the stream.\n     *\n     * This method accepts the following `$resource` types:\n     * - `Psr\\Http\\Message\\StreamInterface`: Returns the value as-is.\n     * - `string`: Creates a stream object that uses the given string as the contents.\n     * - `resource`: Creates a stream object that wraps the given PHP stream resource.\n     * - `Iterator`: If the provided value implements `Iterator`, then a read-only\n     *   stream object will be created that wraps the given iterable. Each time the\n     *   stream is read from, data from the iterator will fill a buffer and will be\n     *   continuously called until the buffer is equal to the requested read size.\n     *   Subsequent read calls will first read from the buffer and then call `next`\n     *   on the underlying iterator until it is exhausted.\n     * - `object` with `__toString()`: If the object has the `__toString()` method,\n     *   the object will be cast to a string and then a stream will be returned that\n     *   uses the string value.\n     * - `NULL`: When `null` is passed, an empty stream object is returned.\n     * - `callable` When a callable is passed, a read-only stream object will be\n     *   created that invokes the given callable. The callable is invoked with the\n     *   number of suggested bytes to read. The callable can return any number of\n     *   bytes, but MUST return `false` when there is no more data to return. The\n     *   stream object that wraps the callable will invoke the callable until the\n     *   number of requested bytes are available. Any additional bytes will be\n     *   buffered and used in subsequent reads.\n     *\n     * @param resource|string|int|float|bool|StreamInterface|callable|\\Iterator|null $resource Entity body data\n     * @param array                                                                  $options  Additional options\n     *\n     * @return StreamInterface\n     *\n     * @throws \\InvalidArgumentException if the $resource arg is not valid.\n     */\n    public static function streamFor($resource = '', array $options = [])\n    {\n        if (is_scalar($resource)) {\n            $stream = self::tryFopen('php://temp', 'r+');\n            if ($resource !== '') {\n                fwrite($stream, $resource);\n                fseek($stream, 0);\n            }\n            return new Stream($stream, $options);\n        }\n\n        switch (gettype($resource)) {\n            case 'resource':\n                /*\n                 * The 'php://input' is a special stream with quirks and inconsistencies.\n                 * We avoid using that stream by reading it into php://temp\n                 */\n                $metaData = \\stream_get_meta_data($resource);\n                if (isset($metaData['uri']) && $metaData['uri'] === 'php://input') {\n                    $stream = self::tryFopen('php://temp', 'w+');\n                    fwrite($stream, stream_get_contents($resource));\n                    fseek($stream, 0);\n                    $resource = $stream;\n                }\n                return new Stream($resource, $options);\n            case 'object':\n                if ($resource instanceof StreamInterface) {\n                    return $resource;\n                } elseif ($resource instanceof \\Iterator) {\n                    return new PumpStream(function () use ($resource) {\n                        if (!$resource->valid()) {\n                            return false;\n                        }\n                        $result = $resource->current();\n                        $resource->next();\n                        return $result;\n                    }, $options);\n                } elseif (method_exists($resource, '__toString')) {\n                    return Utils::streamFor((string) $resource, $options);\n                }\n                break;\n            case 'NULL':\n                return new Stream(self::tryFopen('php://temp', 'r+'), $options);\n        }\n\n        if (is_callable($resource)) {\n            return new PumpStream($resource, $options);\n        }\n\n        throw new \\InvalidArgumentException('Invalid resource type: ' . gettype($resource));\n    }\n\n    /**\n     * Safely opens a PHP stream resource using a filename.\n     *\n     * When fopen fails, PHP normally raises a warning. This function adds an\n     * error handler that checks for errors and throws an exception instead.\n     *\n     * @param string $filename File to open\n     * @param string $mode     Mode used to open the file\n     *\n     * @return resource\n     *\n     * @throws \\RuntimeException if the file cannot be opened\n     */\n    public static function tryFopen($filename, $mode)\n    {\n        $ex = null;\n        set_error_handler(function () use ($filename, $mode, &$ex) {\n            $ex = new \\RuntimeException(sprintf(\n                'Unable to open \"%s\" using mode \"%s\": %s',\n                $filename,\n                $mode,\n                func_get_args()[1]\n            ));\n\n            return true;\n        });\n\n        try {\n            $handle = fopen($filename, $mode);\n        } catch (\\Throwable $e) {\n            $ex = new \\RuntimeException(sprintf(\n                'Unable to open \"%s\" using mode \"%s\": %s',\n                $filename,\n                $mode,\n                $e->getMessage()\n            ), 0, $e);\n        }\n\n        restore_error_handler();\n\n        if ($ex) {\n            /** @var $ex \\RuntimeException */\n            throw $ex;\n        }\n\n        return $handle;\n    }\n\n    /**\n     * Returns a UriInterface for the given value.\n     *\n     * This function accepts a string or UriInterface and returns a\n     * UriInterface for the given value. If the value is already a\n     * UriInterface, it is returned as-is.\n     *\n     * @param string|UriInterface $uri\n     *\n     * @return UriInterface\n     *\n     * @throws \\InvalidArgumentException\n     */\n    public static function uriFor($uri)\n    {\n        if ($uri instanceof UriInterface) {\n            return $uri;\n        }\n\n        if (is_string($uri)) {\n            return new Uri($uri);\n        }\n\n        throw new \\InvalidArgumentException('URI must be a string or UriInterface');\n    }\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/psr7/src/functions.php",
    "content": "<?php\n\nnamespace GuzzleHttp\\Psr7;\n\nuse Psr\\Http\\Message\\MessageInterface;\nuse Psr\\Http\\Message\\RequestInterface;\nuse Psr\\Http\\Message\\StreamInterface;\nuse Psr\\Http\\Message\\UriInterface;\n\n/**\n * Returns the string representation of an HTTP message.\n *\n * @param MessageInterface $message Message to convert to a string.\n *\n * @return string\n *\n * @deprecated str will be removed in guzzlehttp/psr7:2.0. Use Message::toString instead.\n */\nfunction str(MessageInterface $message)\n{\n    return Message::toString($message);\n}\n\n/**\n * Returns a UriInterface for the given value.\n *\n * This function accepts a string or UriInterface and returns a\n * UriInterface for the given value. If the value is already a\n * UriInterface, it is returned as-is.\n *\n * @param string|UriInterface $uri\n *\n * @return UriInterface\n *\n * @throws \\InvalidArgumentException\n *\n * @deprecated uri_for will be removed in guzzlehttp/psr7:2.0. Use Utils::uriFor instead.\n */\nfunction uri_for($uri)\n{\n    return Utils::uriFor($uri);\n}\n\n/**\n * Create a new stream based on the input type.\n *\n * Options is an associative array that can contain the following keys:\n * - metadata: Array of custom metadata.\n * - size: Size of the stream.\n *\n * This method accepts the following `$resource` types:\n * - `Psr\\Http\\Message\\StreamInterface`: Returns the value as-is.\n * - `string`: Creates a stream object that uses the given string as the contents.\n * - `resource`: Creates a stream object that wraps the given PHP stream resource.\n * - `Iterator`: If the provided value implements `Iterator`, then a read-only\n *   stream object will be created that wraps the given iterable. Each time the\n *   stream is read from, data from the iterator will fill a buffer and will be\n *   continuously called until the buffer is equal to the requested read size.\n *   Subsequent read calls will first read from the buffer and then call `next`\n *   on the underlying iterator until it is exhausted.\n * - `object` with `__toString()`: If the object has the `__toString()` method,\n *   the object will be cast to a string and then a stream will be returned that\n *   uses the string value.\n * - `NULL`: When `null` is passed, an empty stream object is returned.\n * - `callable` When a callable is passed, a read-only stream object will be\n *   created that invokes the given callable. The callable is invoked with the\n *   number of suggested bytes to read. The callable can return any number of\n *   bytes, but MUST return `false` when there is no more data to return. The\n *   stream object that wraps the callable will invoke the callable until the\n *   number of requested bytes are available. Any additional bytes will be\n *   buffered and used in subsequent reads.\n *\n * @param resource|string|int|float|bool|StreamInterface|callable|\\Iterator|null $resource Entity body data\n * @param array                                                                  $options  Additional options\n *\n * @return StreamInterface\n *\n * @throws \\InvalidArgumentException if the $resource arg is not valid.\n *\n * @deprecated stream_for will be removed in guzzlehttp/psr7:2.0. Use Utils::streamFor instead.\n */\nfunction stream_for($resource = '', array $options = [])\n{\n    return Utils::streamFor($resource, $options);\n}\n\n/**\n * Parse an array of header values containing \";\" separated data into an\n * array of associative arrays representing the header key value pair data\n * of the header. When a parameter does not contain a value, but just\n * contains a key, this function will inject a key with a '' string value.\n *\n * @param string|array $header Header to parse into components.\n *\n * @return array Returns the parsed header values.\n *\n * @deprecated parse_header will be removed in guzzlehttp/psr7:2.0. Use Header::parse instead.\n */\nfunction parse_header($header)\n{\n    return Header::parse($header);\n}\n\n/**\n * Converts an array of header values that may contain comma separated\n * headers into an array of headers with no comma separated values.\n *\n * @param string|array $header Header to normalize.\n *\n * @return array Returns the normalized header field values.\n *\n * @deprecated normalize_header will be removed in guzzlehttp/psr7:2.0. Use Header::normalize instead.\n */\nfunction normalize_header($header)\n{\n    return Header::normalize($header);\n}\n\n/**\n * Clone and modify a request with the given changes.\n *\n * This method is useful for reducing the number of clones needed to mutate a\n * message.\n *\n * The changes can be one of:\n * - method: (string) Changes the HTTP method.\n * - set_headers: (array) Sets the given headers.\n * - remove_headers: (array) Remove the given headers.\n * - body: (mixed) Sets the given body.\n * - uri: (UriInterface) Set the URI.\n * - query: (string) Set the query string value of the URI.\n * - version: (string) Set the protocol version.\n *\n * @param RequestInterface $request Request to clone and modify.\n * @param array            $changes Changes to apply.\n *\n * @return RequestInterface\n *\n * @deprecated modify_request will be removed in guzzlehttp/psr7:2.0. Use Utils::modifyRequest instead.\n */\nfunction modify_request(RequestInterface $request, array $changes)\n{\n    return Utils::modifyRequest($request, $changes);\n}\n\n/**\n * Attempts to rewind a message body and throws an exception on failure.\n *\n * The body of the message will only be rewound if a call to `tell()` returns a\n * value other than `0`.\n *\n * @param MessageInterface $message Message to rewind\n *\n * @throws \\RuntimeException\n *\n * @deprecated rewind_body will be removed in guzzlehttp/psr7:2.0. Use Message::rewindBody instead.\n */\nfunction rewind_body(MessageInterface $message)\n{\n    Message::rewindBody($message);\n}\n\n/**\n * Safely opens a PHP stream resource using a filename.\n *\n * When fopen fails, PHP normally raises a warning. This function adds an\n * error handler that checks for errors and throws an exception instead.\n *\n * @param string $filename File to open\n * @param string $mode     Mode used to open the file\n *\n * @return resource\n *\n * @throws \\RuntimeException if the file cannot be opened\n *\n * @deprecated try_fopen will be removed in guzzlehttp/psr7:2.0. Use Utils::tryFopen instead.\n */\nfunction try_fopen($filename, $mode)\n{\n    return Utils::tryFopen($filename, $mode);\n}\n\n/**\n * Copy the contents of a stream into a string until the given number of\n * bytes have been read.\n *\n * @param StreamInterface $stream Stream to read\n * @param int             $maxLen Maximum number of bytes to read. Pass -1\n *                                to read the entire stream.\n *\n * @return string\n *\n * @throws \\RuntimeException on error.\n *\n * @deprecated copy_to_string will be removed in guzzlehttp/psr7:2.0. Use Utils::copyToString instead.\n */\nfunction copy_to_string(StreamInterface $stream, $maxLen = -1)\n{\n    return Utils::copyToString($stream, $maxLen);\n}\n\n/**\n * Copy the contents of a stream into another stream until the given number\n * of bytes have been read.\n *\n * @param StreamInterface $source Stream to read from\n * @param StreamInterface $dest   Stream to write to\n * @param int             $maxLen Maximum number of bytes to read. Pass -1\n *                                to read the entire stream.\n *\n * @throws \\RuntimeException on error.\n *\n * @deprecated copy_to_stream will be removed in guzzlehttp/psr7:2.0. Use Utils::copyToStream instead.\n */\nfunction copy_to_stream(StreamInterface $source, StreamInterface $dest, $maxLen = -1)\n{\n    return Utils::copyToStream($source, $dest, $maxLen);\n}\n\n/**\n * Calculate a hash of a stream.\n *\n * This method reads the entire stream to calculate a rolling hash, based on\n * PHP's `hash_init` functions.\n *\n * @param StreamInterface $stream    Stream to calculate the hash for\n * @param string          $algo      Hash algorithm (e.g. md5, crc32, etc)\n * @param bool            $rawOutput Whether or not to use raw output\n *\n * @return string Returns the hash of the stream\n *\n * @throws \\RuntimeException on error.\n *\n * @deprecated hash will be removed in guzzlehttp/psr7:2.0. Use Utils::hash instead.\n */\nfunction hash(StreamInterface $stream, $algo, $rawOutput = false)\n{\n    return Utils::hash($stream, $algo, $rawOutput);\n}\n\n/**\n * Read a line from the stream up to the maximum allowed buffer length.\n *\n * @param StreamInterface $stream    Stream to read from\n * @param int|null        $maxLength Maximum buffer length\n *\n * @return string\n *\n * @deprecated readline will be removed in guzzlehttp/psr7:2.0. Use Utils::readLine instead.\n */\nfunction readline(StreamInterface $stream, $maxLength = null)\n{\n    return Utils::readLine($stream, $maxLength);\n}\n\n/**\n * Parses a request message string into a request object.\n *\n * @param string $message Request message string.\n *\n * @return Request\n *\n * @deprecated parse_request will be removed in guzzlehttp/psr7:2.0. Use Message::parseRequest instead.\n */\nfunction parse_request($message)\n{\n    return Message::parseRequest($message);\n}\n\n/**\n * Parses a response message string into a response object.\n *\n * @param string $message Response message string.\n *\n * @return Response\n *\n * @deprecated parse_response will be removed in guzzlehttp/psr7:2.0. Use Message::parseResponse instead.\n */\nfunction parse_response($message)\n{\n    return Message::parseResponse($message);\n}\n\n/**\n * Parse a query string into an associative array.\n *\n * If multiple values are found for the same key, the value of that key value\n * pair will become an array. This function does not parse nested PHP style\n * arrays into an associative array (e.g., `foo[a]=1&foo[b]=2` will be parsed\n * into `['foo[a]' => '1', 'foo[b]' => '2'])`.\n *\n * @param string   $str         Query string to parse\n * @param int|bool $urlEncoding How the query string is encoded\n *\n * @return array\n *\n * @deprecated parse_query will be removed in guzzlehttp/psr7:2.0. Use Query::parse instead.\n */\nfunction parse_query($str, $urlEncoding = true)\n{\n    return Query::parse($str, $urlEncoding);\n}\n\n/**\n * Build a query string from an array of key value pairs.\n *\n * This function can use the return value of `parse_query()` to build a query\n * string. This function does not modify the provided keys when an array is\n * encountered (like `http_build_query()` would).\n *\n * @param array     $params   Query string parameters.\n * @param int|false $encoding Set to false to not encode, PHP_QUERY_RFC3986\n *                            to encode using RFC3986, or PHP_QUERY_RFC1738\n *                            to encode using RFC1738.\n *\n * @return string\n *\n * @deprecated build_query will be removed in guzzlehttp/psr7:2.0. Use Query::build instead.\n */\nfunction build_query(array $params, $encoding = PHP_QUERY_RFC3986)\n{\n    return Query::build($params, $encoding);\n}\n\n/**\n * Determines the mimetype of a file by looking at its extension.\n *\n * @param string $filename\n *\n * @return string|null\n *\n * @deprecated mimetype_from_filename will be removed in guzzlehttp/psr7:2.0. Use MimeType::fromFilename instead.\n */\nfunction mimetype_from_filename($filename)\n{\n    return MimeType::fromFilename($filename);\n}\n\n/**\n * Maps a file extensions to a mimetype.\n *\n * @param $extension string The file extension.\n *\n * @return string|null\n *\n * @link http://svn.apache.org/repos/asf/httpd/httpd/branches/1.3.x/conf/mime.types\n * @deprecated mimetype_from_extension will be removed in guzzlehttp/psr7:2.0. Use MimeType::fromExtension instead.\n */\nfunction mimetype_from_extension($extension)\n{\n    return MimeType::fromExtension($extension);\n}\n\n/**\n * Parses an HTTP message into an associative array.\n *\n * The array contains the \"start-line\" key containing the start line of\n * the message, \"headers\" key containing an associative array of header\n * array values, and a \"body\" key containing the body of the message.\n *\n * @param string $message HTTP request or response to parse.\n *\n * @return array\n *\n * @internal\n *\n * @deprecated _parse_message will be removed in guzzlehttp/psr7:2.0. Use Message::parseMessage instead.\n */\nfunction _parse_message($message)\n{\n    return Message::parseMessage($message);\n}\n\n/**\n * Constructs a URI for an HTTP request message.\n *\n * @param string $path    Path from the start-line\n * @param array  $headers Array of headers (each value an array).\n *\n * @return string\n *\n * @internal\n *\n * @deprecated _parse_request_uri will be removed in guzzlehttp/psr7:2.0. Use Message::parseRequestUri instead.\n */\nfunction _parse_request_uri($path, array $headers)\n{\n    return Message::parseRequestUri($path, $headers);\n}\n\n/**\n * Get a short summary of the message body.\n *\n * Will return `null` if the response is not printable.\n *\n * @param MessageInterface $message    The message to get the body summary\n * @param int              $truncateAt The maximum allowed size of the summary\n *\n * @return string|null\n *\n * @deprecated get_message_body_summary will be removed in guzzlehttp/psr7:2.0. Use Message::bodySummary instead.\n */\nfunction get_message_body_summary(MessageInterface $message, $truncateAt = 120)\n{\n    return Message::bodySummary($message, $truncateAt);\n}\n\n/**\n * Remove the items given by the keys, case insensitively from the data.\n *\n * @param iterable<string> $keys\n *\n * @return array\n *\n * @internal\n *\n * @deprecated _caseless_remove will be removed in guzzlehttp/psr7:2.0. Use Utils::caselessRemove instead.\n */\nfunction _caseless_remove($keys, array $data)\n{\n    return Utils::caselessRemove($keys, $data);\n}\n"
  },
  {
    "path": "server/vendor/guzzlehttp/psr7/src/functions_include.php",
    "content": "<?php\n\n// Don't redefine the functions if included multiple times.\nif (!function_exists('GuzzleHttp\\Psr7\\str')) {\n    require __DIR__ . '/functions.php';\n}\n"
  },
  {
    "path": "server/vendor/illuminate/bus/Batch.php",
    "content": "<?php\n\nnamespace Illuminate\\Bus;\n\nuse Carbon\\CarbonImmutable;\nuse Closure;\nuse Illuminate\\Contracts\\Queue\\Factory as QueueFactory;\nuse Illuminate\\Contracts\\Support\\Arrayable;\nuse Illuminate\\Queue\\CallQueuedClosure;\nuse Illuminate\\Support\\Arr;\nuse Illuminate\\Support\\Collection;\nuse JsonSerializable;\nuse Throwable;\n\nclass Batch implements Arrayable, JsonSerializable\n{\n    /**\n     * The queue factory implementation.\n     *\n     * @var \\Illuminate\\Contracts\\Queue\\Factory\n     */\n    protected $queue;\n\n    /**\n     * The repository implementation.\n     *\n     * @var \\Illuminate\\Bus\\BatchRepository\n     */\n    protected $repository;\n\n    /**\n     * The batch ID.\n     *\n     * @var string\n     */\n    public $id;\n\n    /**\n     * The batch name.\n     *\n     * @var string\n     */\n    public $name;\n\n    /**\n     * The total number of jobs that belong to the batch.\n     *\n     * @var int\n     */\n    public $totalJobs;\n\n    /**\n     * The total number of jobs that are still pending.\n     *\n     * @var int\n     */\n    public $pendingJobs;\n\n    /**\n     * The total number of jobs that have failed.\n     *\n     * @var int\n     */\n    public $failedJobs;\n\n    /**\n     * The IDs of the jobs that have failed.\n     *\n     * @var array\n     */\n    public $failedJobIds;\n\n    /**\n     * The batch options.\n     *\n     * @var array\n     */\n    public $options;\n\n    /**\n     * The date indicating when the batch was created.\n     *\n     * @var \\Carbon\\CarbonImmutable\n     */\n    public $createdAt;\n\n    /**\n     * The date indicating when the batch was cancelled.\n     *\n     * @var \\Carbon\\CarbonImmutable|null\n     */\n    public $cancelledAt;\n\n    /**\n     * The date indicating when the batch was finished.\n     *\n     * @var \\Carbon\\CarbonImmutable|null\n     */\n    public $finishedAt;\n\n    /**\n     * Create a new batch instance.\n     *\n     * @param  \\Illuminate\\Contracts\\Queue\\Factory  $queue\n     * @param  \\Illuminate\\Bus\\BatchRepository  $repository\n     * @param  string  $id\n     * @param  string  $name\n     * @param  int  $totalJobs\n     * @param  int  $pendingJobs\n     * @param  int  $failedJobs\n     * @param  array  $failedJobIds\n     * @param  array  $options\n     * @param  \\Carbon\\CarbonImmutable  $createdAt\n     * @param  \\Carbon\\CarbonImmutable|null  $cancelledAt\n     * @param  \\Carbon\\CarbonImmutable|null  $finishedAt\n     * @return void\n     */\n    public function __construct(QueueFactory $queue,\n                                BatchRepository $repository,\n                                string $id,\n                                string $name,\n                                int $totalJobs,\n                                int $pendingJobs,\n                                int $failedJobs,\n                                array $failedJobIds,\n                                array $options,\n                                CarbonImmutable $createdAt,\n                                ?CarbonImmutable $cancelledAt = null,\n                                ?CarbonImmutable $finishedAt = null)\n    {\n        $this->queue = $queue;\n        $this->repository = $repository;\n        $this->id = $id;\n        $this->name = $name;\n        $this->totalJobs = $totalJobs;\n        $this->pendingJobs = $pendingJobs;\n        $this->failedJobs = $failedJobs;\n        $this->failedJobIds = $failedJobIds;\n        $this->options = $options;\n        $this->createdAt = $createdAt;\n        $this->cancelledAt = $cancelledAt;\n        $this->finishedAt = $finishedAt;\n    }\n\n    /**\n     * Get a fresh instance of the batch represented by this ID.\n     *\n     * @return self\n     */\n    public function fresh()\n    {\n        return $this->repository->find($this->id);\n    }\n\n    /**\n     * Add additional jobs to the batch.\n     *\n     * @param  \\Illuminate\\Support\\Enumerable|array  $jobs\n     * @return self\n     */\n    public function add($jobs)\n    {\n        $count = 0;\n\n        $jobs = Collection::wrap($jobs)->map(function ($job) use (&$count) {\n            $job = $job instanceof Closure ? CallQueuedClosure::create($job) : $job;\n\n            if (is_array($job)) {\n                $count += count($job);\n\n                return with($this->prepareBatchedChain($job), function ($chain) {\n                    return $chain->first()\n                            ->allOnQueue($this->options['queue'] ?? null)\n                            ->allOnConnection($this->options['connection'] ?? null)\n                            ->chain($chain->slice(1)->values()->all());\n                });\n            } else {\n                $job->withBatchId($this->id);\n\n                $count++;\n            }\n\n            return $job;\n        });\n\n        $this->repository->transaction(function () use ($jobs, $count) {\n            $this->repository->incrementTotalJobs($this->id, $count);\n\n            $this->queue->connection($this->options['connection'] ?? null)->bulk(\n                $jobs->all(),\n                $data = '',\n                $this->options['queue'] ?? null\n            );\n        });\n\n        return $this->fresh();\n    }\n\n    /**\n     * Prepare a chain that exists within the jobs being added.\n     *\n     * @param  array  $chain\n     * @return \\Illuminate\\Support\\Collection\n     */\n    protected function prepareBatchedChain(array $chain)\n    {\n        return collect($chain)->map(function ($job) {\n            $job = $job instanceof Closure ? CallQueuedClosure::create($job) : $job;\n\n            return $job->withBatchId($this->id);\n        });\n    }\n\n    /**\n     * Get the total number of jobs that have been processed by the batch thus far.\n     *\n     * @return int\n     */\n    public function processedJobs()\n    {\n        return $this->totalJobs - $this->pendingJobs;\n    }\n\n    /**\n     * Get the percentage of jobs that have been processed (between 0-100).\n     *\n     * @return int\n     */\n    public function progress()\n    {\n        return $this->totalJobs > 0 ? round(($this->processedJobs() / $this->totalJobs) * 100) : 0;\n    }\n\n    /**\n     * Record that a job within the batch finished successfully, executing any callbacks if necessary.\n     *\n     * @param  string  $jobId\n     * @return void\n     */\n    public function recordSuccessfulJob(string $jobId)\n    {\n        $counts = $this->decrementPendingJobs($jobId);\n\n        if ($counts->pendingJobs === 0) {\n            $this->repository->markAsFinished($this->id);\n        }\n\n        if ($counts->pendingJobs === 0 && $this->hasThenCallbacks()) {\n            $batch = $this->fresh();\n\n            collect($this->options['then'])->each(function ($handler) use ($batch) {\n                $this->invokeHandlerCallback($handler, $batch);\n            });\n        }\n\n        if ($counts->allJobsHaveRanExactlyOnce() && $this->hasFinallyCallbacks()) {\n            $batch = $this->fresh();\n\n            collect($this->options['finally'])->each(function ($handler) use ($batch) {\n                $this->invokeHandlerCallback($handler, $batch);\n            });\n        }\n    }\n\n    /**\n     * Decrement the pending jobs for the batch.\n     *\n     * @param  string  $jobId\n     * @return \\Illuminate\\Bus\\UpdatedBatchJobCounts\n     */\n    public function decrementPendingJobs(string $jobId)\n    {\n        return $this->repository->decrementPendingJobs($this->id, $jobId);\n    }\n\n    /**\n     * Determine if the batch has finished executing.\n     *\n     * @return bool\n     */\n    public function finished()\n    {\n        return ! is_null($this->finishedAt);\n    }\n\n    /**\n     * Determine if the batch has \"success\" callbacks.\n     *\n     * @return bool\n     */\n    public function hasThenCallbacks()\n    {\n        return isset($this->options['then']) && ! empty($this->options['then']);\n    }\n\n    /**\n     * Determine if the batch allows jobs to fail without cancelling the batch.\n     *\n     * @return bool\n     */\n    public function allowsFailures()\n    {\n        return Arr::get($this->options, 'allowFailures', false) === true;\n    }\n\n    /**\n     * Determine if the batch has job failures.\n     *\n     * @return bool\n     */\n    public function hasFailures()\n    {\n        return $this->failedJobs > 0;\n    }\n\n    /**\n     * Record that a job within the batch failed to finish successfully, executing any callbacks if necessary.\n     *\n     * @param  string  $jobId\n     * @param  \\Throwable  $e\n     * @return void\n     */\n    public function recordFailedJob(string $jobId, $e)\n    {\n        $counts = $this->incrementFailedJobs($jobId);\n\n        if ($counts->failedJobs === 1 && ! $this->allowsFailures()) {\n            $this->cancel();\n        }\n\n        if ($counts->failedJobs === 1 && $this->hasCatchCallbacks()) {\n            $batch = $this->fresh();\n\n            collect($this->options['catch'])->each(function ($handler) use ($batch, $e) {\n                $this->invokeHandlerCallback($handler, $batch, $e);\n            });\n        }\n\n        if ($counts->allJobsHaveRanExactlyOnce() && $this->hasFinallyCallbacks()) {\n            $batch = $this->fresh();\n\n            collect($this->options['finally'])->each(function ($handler) use ($batch, $e) {\n                $this->invokeHandlerCallback($handler, $batch, $e);\n            });\n        }\n    }\n\n    /**\n     * Increment the failed jobs for the batch.\n     *\n     * @param  string  $jobId\n     * @return \\Illuminate\\Bus\\UpdatedBatchJobCounts\n     */\n    public function incrementFailedJobs(string $jobId)\n    {\n        return $this->repository->incrementFailedJobs($this->id, $jobId);\n    }\n\n    /**\n     * Determine if the batch has \"catch\" callbacks.\n     *\n     * @return bool\n     */\n    public function hasCatchCallbacks()\n    {\n        return isset($this->options['catch']) && ! empty($this->options['catch']);\n    }\n\n    /**\n     * Determine if the batch has \"finally\" callbacks.\n     *\n     * @return bool\n     */\n    public function hasFinallyCallbacks()\n    {\n        return isset($this->options['finally']) && ! empty($this->options['finally']);\n    }\n\n    /**\n     * Cancel the batch.\n     *\n     * @return void\n     */\n    public function cancel()\n    {\n        $this->repository->cancel($this->id);\n    }\n\n    /**\n     * Determine if the batch has been cancelled.\n     *\n     * @return bool\n     */\n    public function canceled()\n    {\n        return $this->cancelled();\n    }\n\n    /**\n     * Determine if the batch has been cancelled.\n     *\n     * @return bool\n     */\n    public function cancelled()\n    {\n        return ! is_null($this->cancelledAt);\n    }\n\n    /**\n     * Delete the batch from storage.\n     *\n     * @return void\n     */\n    public function delete()\n    {\n        $this->repository->delete($this->id);\n    }\n\n    /**\n     * Invoke a batch callback handler.\n     *\n     * @param  callable  $handler\n     * @param  \\Illuminate\\Bus\\Batch  $batch\n     * @param  \\Throwable|null  $e\n     * @return void\n     */\n    protected function invokeHandlerCallback($handler, Batch $batch, Throwable $e = null)\n    {\n        try {\n            return $handler($batch, $e);\n        } catch (Throwable $e) {\n            if (function_exists('report')) {\n                report($e);\n            }\n        }\n    }\n\n    /**\n     * Convert the batch to an array.\n     *\n     * @return array\n     */\n    public function toArray()\n    {\n        return [\n            'id' => $this->id,\n            'name' => $this->name,\n            'totalJobs' => $this->totalJobs,\n            'pendingJobs' => $this->pendingJobs,\n            'processedJobs' => $this->processedJobs(),\n            'progress' => $this->progress(),\n            'failedJobs' => $this->failedJobs,\n            'options' => $this->options,\n            'createdAt' => $this->createdAt,\n            'cancelledAt' => $this->cancelledAt,\n            'finishedAt' => $this->finishedAt,\n        ];\n    }\n\n    /**\n     * Get the JSON serializable representation of the object.\n     *\n     * @return array\n     */\n    #[\\ReturnTypeWillChange]\n    public function jsonSerialize()\n    {\n        return $this->toArray();\n    }\n\n    /**\n     * Dynamically access the batch's \"options\" via properties.\n     *\n     * @param  string  $key\n     * @return mixed\n     */\n    public function __get($key)\n    {\n        return $this->options[$key] ?? null;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/bus/BatchFactory.php",
    "content": "<?php\n\nnamespace Illuminate\\Bus;\n\nuse Carbon\\CarbonImmutable;\nuse Illuminate\\Contracts\\Queue\\Factory as QueueFactory;\n\nclass BatchFactory\n{\n    /**\n     * The queue factory implementation.\n     *\n     * @var \\Illuminate\\Contracts\\Queue\\Factory\n     */\n    protected $queue;\n\n    /**\n     * Create a new batch factory instance.\n     *\n     * @param  \\Illuminate\\Contracts\\Queue\\Factory  $queue\n     * @return void\n     */\n    public function __construct(QueueFactory $queue)\n    {\n        $this->queue = $queue;\n    }\n\n    /**\n     * Create a new batch instance.\n     *\n     * @param  \\Illuminate\\Bus\\BatchRepository  $repository\n     * @param  string  $id\n     * @param  string  $name\n     * @param  int  $totalJobs\n     * @param  int  $pendingJobs\n     * @param  int  $failedJobs\n     * @param  array  $failedJobIds\n     * @param  array  $options\n     * @param  \\Carbon\\CarbonImmutable  $createdAt\n     * @param  \\Carbon\\CarbonImmutable|null  $cancelledAt\n     * @param  \\Carbon\\CarbonImmutable|null  $finishedAt\n     * @return \\Illuminate\\Bus\\Batch\n     */\n    public function make(BatchRepository $repository,\n                         string $id,\n                         string $name,\n                         int $totalJobs,\n                         int $pendingJobs,\n                         int $failedJobs,\n                         array $failedJobIds,\n                         array $options,\n                         CarbonImmutable $createdAt,\n                         ?CarbonImmutable $cancelledAt,\n                         ?CarbonImmutable $finishedAt)\n    {\n        return new Batch($this->queue, $repository, $id, $name, $totalJobs, $pendingJobs, $failedJobs, $failedJobIds, $options, $createdAt, $cancelledAt, $finishedAt);\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/bus/BatchRepository.php",
    "content": "<?php\n\nnamespace Illuminate\\Bus;\n\nuse Closure;\n\ninterface BatchRepository\n{\n    /**\n     * Retrieve a list of batches.\n     *\n     * @param  int  $limit\n     * @param  mixed  $before\n     * @return \\Illuminate\\Bus\\Batch[]\n     */\n    public function get($limit, $before);\n\n    /**\n     * Retrieve information about an existing batch.\n     *\n     * @param  string  $batchId\n     * @return \\Illuminate\\Bus\\Batch|null\n     */\n    public function find(string $batchId);\n\n    /**\n     * Store a new pending batch.\n     *\n     * @param  \\Illuminate\\Bus\\PendingBatch  $batch\n     * @return \\Illuminate\\Bus\\Batch\n     */\n    public function store(PendingBatch $batch);\n\n    /**\n     * Increment the total number of jobs within the batch.\n     *\n     * @param  string  $batchId\n     * @param  int  $amount\n     * @return void\n     */\n    public function incrementTotalJobs(string $batchId, int $amount);\n\n    /**\n     * Decrement the total number of pending jobs for the batch.\n     *\n     * @param  string  $batchId\n     * @param  string  $jobId\n     * @return \\Illuminate\\Bus\\UpdatedBatchJobCounts\n     */\n    public function decrementPendingJobs(string $batchId, string $jobId);\n\n    /**\n     * Increment the total number of failed jobs for the batch.\n     *\n     * @param  string  $batchId\n     * @param  string  $jobId\n     * @return \\Illuminate\\Bus\\UpdatedBatchJobCounts\n     */\n    public function incrementFailedJobs(string $batchId, string $jobId);\n\n    /**\n     * Mark the batch that has the given ID as finished.\n     *\n     * @param  string  $batchId\n     * @return void\n     */\n    public function markAsFinished(string $batchId);\n\n    /**\n     * Cancel the batch that has the given ID.\n     *\n     * @param  string  $batchId\n     * @return void\n     */\n    public function cancel(string $batchId);\n\n    /**\n     * Delete the batch that has the given ID.\n     *\n     * @param  string  $batchId\n     * @return void\n     */\n    public function delete(string $batchId);\n\n    /**\n     * Execute the given Closure within a storage specific transaction.\n     *\n     * @param  \\Closure  $callback\n     * @return mixed\n     */\n    public function transaction(Closure $callback);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/bus/Batchable.php",
    "content": "<?php\n\nnamespace Illuminate\\Bus;\n\nuse Illuminate\\Container\\Container;\n\ntrait Batchable\n{\n    /**\n     * The batch ID (if applicable).\n     *\n     * @var string\n     */\n    public $batchId;\n\n    /**\n     * Get the batch instance for the job, if applicable.\n     *\n     * @return \\Illuminate\\Bus\\Batch|null\n     */\n    public function batch()\n    {\n        if ($this->batchId) {\n            return Container::getInstance()->make(BatchRepository::class)->find($this->batchId);\n        }\n    }\n\n    /**\n     * Determine if the batch is still active and processing.\n     *\n     * @return bool\n     */\n    public function batching()\n    {\n        $batch = $this->batch();\n\n        return $batch && ! $batch->cancelled();\n    }\n\n    /**\n     * Set the batch ID on the job.\n     *\n     * @param  string  $batchId\n     * @return $this\n     */\n    public function withBatchId(string $batchId)\n    {\n        $this->batchId = $batchId;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/bus/BusServiceProvider.php",
    "content": "<?php\n\nnamespace Illuminate\\Bus;\n\nuse Illuminate\\Contracts\\Bus\\Dispatcher as DispatcherContract;\nuse Illuminate\\Contracts\\Bus\\QueueingDispatcher as QueueingDispatcherContract;\nuse Illuminate\\Contracts\\Queue\\Factory as QueueFactoryContract;\nuse Illuminate\\Contracts\\Support\\DeferrableProvider;\nuse Illuminate\\Support\\ServiceProvider;\n\nclass BusServiceProvider extends ServiceProvider implements DeferrableProvider\n{\n    /**\n     * Register the service provider.\n     *\n     * @return void\n     */\n    public function register()\n    {\n        $this->app->singleton(Dispatcher::class, function ($app) {\n            return new Dispatcher($app, function ($connection = null) use ($app) {\n                return $app[QueueFactoryContract::class]->connection($connection);\n            });\n        });\n\n        $this->registerBatchServices();\n\n        $this->app->alias(\n            Dispatcher::class, DispatcherContract::class\n        );\n\n        $this->app->alias(\n            Dispatcher::class, QueueingDispatcherContract::class\n        );\n    }\n\n    /**\n     * Register the batch handling services.\n     *\n     * @return void\n     */\n    protected function registerBatchServices()\n    {\n        $this->app->singleton(BatchRepository::class, DatabaseBatchRepository::class);\n\n        $this->app->singleton(DatabaseBatchRepository::class, function ($app) {\n            return new DatabaseBatchRepository(\n                $app->make(BatchFactory::class),\n                $app->make('db')->connection($app->config->get('queue.batching.database')),\n                $app->config->get('queue.batching.table', 'job_batches')\n            );\n        });\n    }\n\n    /**\n     * Get the services provided by the provider.\n     *\n     * @return array\n     */\n    public function provides()\n    {\n        return [\n            Dispatcher::class,\n            DispatcherContract::class,\n            QueueingDispatcherContract::class,\n            BatchRepository::class,\n        ];\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/bus/DatabaseBatchRepository.php",
    "content": "<?php\n\nnamespace Illuminate\\Bus;\n\nuse Carbon\\CarbonImmutable;\nuse Closure;\nuse DateTimeInterface;\nuse Illuminate\\Database\\Connection;\nuse Illuminate\\Database\\PostgresConnection;\nuse Illuminate\\Database\\Query\\Expression;\nuse Illuminate\\Support\\Str;\n\nclass DatabaseBatchRepository implements PrunableBatchRepository\n{\n    /**\n     * The batch factory instance.\n     *\n     * @var \\Illuminate\\Bus\\BatchFactory\n     */\n    protected $factory;\n\n    /**\n     * The database connection instance.\n     *\n     * @var \\Illuminate\\Database\\Connection\n     */\n    protected $connection;\n\n    /**\n     * The database table to use to store batch information.\n     *\n     * @var string\n     */\n    protected $table;\n\n    /**\n     * Create a new batch repository instance.\n     *\n     * @param  \\Illuminate\\Bus\\BatchFactory  $factory\n     * @param  \\Illuminate\\Database\\Connection  $connection\n     * @param  string  $table\n     */\n    public function __construct(BatchFactory $factory, Connection $connection, string $table)\n    {\n        $this->factory = $factory;\n        $this->connection = $connection;\n        $this->table = $table;\n    }\n\n    /**\n     * Retrieve a list of batches.\n     *\n     * @param  int  $limit\n     * @param  mixed  $before\n     * @return \\Illuminate\\Bus\\Batch[]\n     */\n    public function get($limit = 50, $before = null)\n    {\n        return $this->connection->table($this->table)\n                            ->orderByDesc('id')\n                            ->take($limit)\n                            ->when($before, function ($q) use ($before) {\n                                return $q->where('id', '<', $before);\n                            })\n                            ->get()\n                            ->map(function ($batch) {\n                                return $this->toBatch($batch);\n                            })\n                            ->all();\n    }\n\n    /**\n     * Retrieve information about an existing batch.\n     *\n     * @param  string  $batchId\n     * @return \\Illuminate\\Bus\\Batch|null\n     */\n    public function find(string $batchId)\n    {\n        $batch = $this->connection->table($this->table)\n                            ->where('id', $batchId)\n                            ->first();\n\n        if ($batch) {\n            return $this->toBatch($batch);\n        }\n    }\n\n    /**\n     * Store a new pending batch.\n     *\n     * @param  \\Illuminate\\Bus\\PendingBatch  $batch\n     * @return \\Illuminate\\Bus\\Batch\n     */\n    public function store(PendingBatch $batch)\n    {\n        $id = (string) Str::orderedUuid();\n\n        $this->connection->table($this->table)->insert([\n            'id' => $id,\n            'name' => $batch->name,\n            'total_jobs' => 0,\n            'pending_jobs' => 0,\n            'failed_jobs' => 0,\n            'failed_job_ids' => '[]',\n            'options' => $this->serialize($batch->options),\n            'created_at' => time(),\n            'cancelled_at' => null,\n            'finished_at' => null,\n        ]);\n\n        return $this->find($id);\n    }\n\n    /**\n     * Increment the total number of jobs within the batch.\n     *\n     * @param  string  $batchId\n     * @param  int  $amount\n     * @return void\n     */\n    public function incrementTotalJobs(string $batchId, int $amount)\n    {\n        $this->connection->table($this->table)->where('id', $batchId)->update([\n            'total_jobs' => new Expression('total_jobs + '.$amount),\n            'pending_jobs' => new Expression('pending_jobs + '.$amount),\n            'finished_at' => null,\n        ]);\n    }\n\n    /**\n     * Decrement the total number of pending jobs for the batch.\n     *\n     * @param  string  $batchId\n     * @param  string  $jobId\n     * @return \\Illuminate\\Bus\\UpdatedBatchJobCounts\n     */\n    public function decrementPendingJobs(string $batchId, string $jobId)\n    {\n        $values = $this->updateAtomicValues($batchId, function ($batch) use ($jobId) {\n            return [\n                'pending_jobs' => $batch->pending_jobs - 1,\n                'failed_jobs' => $batch->failed_jobs,\n                'failed_job_ids' => json_encode(array_values(array_diff(json_decode($batch->failed_job_ids, true), [$jobId]))),\n            ];\n        });\n\n        return new UpdatedBatchJobCounts(\n            $values['pending_jobs'],\n            $values['failed_jobs']\n        );\n    }\n\n    /**\n     * Increment the total number of failed jobs for the batch.\n     *\n     * @param  string  $batchId\n     * @param  string  $jobId\n     * @return \\Illuminate\\Bus\\UpdatedBatchJobCounts\n     */\n    public function incrementFailedJobs(string $batchId, string $jobId)\n    {\n        $values = $this->updateAtomicValues($batchId, function ($batch) use ($jobId) {\n            return [\n                'pending_jobs' => $batch->pending_jobs,\n                'failed_jobs' => $batch->failed_jobs + 1,\n                'failed_job_ids' => json_encode(array_values(array_unique(array_merge(json_decode($batch->failed_job_ids, true), [$jobId])))),\n            ];\n        });\n\n        return new UpdatedBatchJobCounts(\n            $values['pending_jobs'],\n            $values['failed_jobs']\n        );\n    }\n\n    /**\n     * Update an atomic value within the batch.\n     *\n     * @param  string  $batchId\n     * @param  \\Closure  $callback\n     * @return int|null\n     */\n    protected function updateAtomicValues(string $batchId, Closure $callback)\n    {\n        return $this->connection->transaction(function () use ($batchId, $callback) {\n            $batch = $this->connection->table($this->table)->where('id', $batchId)\n                        ->lockForUpdate()\n                        ->first();\n\n            return is_null($batch) ? [] : tap($callback($batch), function ($values) use ($batchId) {\n                $this->connection->table($this->table)->where('id', $batchId)->update($values);\n            });\n        });\n    }\n\n    /**\n     * Mark the batch that has the given ID as finished.\n     *\n     * @param  string  $batchId\n     * @return void\n     */\n    public function markAsFinished(string $batchId)\n    {\n        $this->connection->table($this->table)->where('id', $batchId)->update([\n            'finished_at' => time(),\n        ]);\n    }\n\n    /**\n     * Cancel the batch that has the given ID.\n     *\n     * @param  string  $batchId\n     * @return void\n     */\n    public function cancel(string $batchId)\n    {\n        $this->connection->table($this->table)->where('id', $batchId)->update([\n            'cancelled_at' => time(),\n            'finished_at' => time(),\n        ]);\n    }\n\n    /**\n     * Delete the batch that has the given ID.\n     *\n     * @param  string  $batchId\n     * @return void\n     */\n    public function delete(string $batchId)\n    {\n        $this->connection->table($this->table)->where('id', $batchId)->delete();\n    }\n\n    /**\n     * Prune all of the entries older than the given date.\n     *\n     * @param  \\DateTimeInterface  $before\n     * @return int\n     */\n    public function prune(DateTimeInterface $before)\n    {\n        $query = $this->connection->table($this->table)\n            ->whereNotNull('finished_at')\n            ->where('finished_at', '<', $before->getTimestamp());\n\n        $totalDeleted = 0;\n\n        do {\n            $deleted = $query->take(1000)->delete();\n\n            $totalDeleted += $deleted;\n        } while ($deleted !== 0);\n\n        return $totalDeleted;\n    }\n\n    /**\n     * Prune all of the unfinished entries older than the given date.\n     *\n     * @param  \\DateTimeInterface  $before\n     * @return int\n     */\n    public function pruneUnfinished(DateTimeInterface $before)\n    {\n        $query = $this->connection->table($this->table)\n            ->whereNull('finished_at')\n            ->where('created_at', '<', $before->getTimestamp());\n\n        $totalDeleted = 0;\n\n        do {\n            $deleted = $query->take(1000)->delete();\n\n            $totalDeleted += $deleted;\n        } while ($deleted !== 0);\n\n        return $totalDeleted;\n    }\n\n    /**\n     * Execute the given Closure within a storage specific transaction.\n     *\n     * @param  \\Closure  $callback\n     * @return mixed\n     */\n    public function transaction(Closure $callback)\n    {\n        return $this->connection->transaction(function () use ($callback) {\n            return $callback();\n        });\n    }\n\n    /**\n     * Serialize the given value.\n     *\n     * @param  mixed  $value\n     * @return string\n     */\n    protected function serialize($value)\n    {\n        $serialized = serialize($value);\n\n        return $this->connection instanceof PostgresConnection\n            ? base64_encode($serialized)\n            : $serialized;\n    }\n\n    /**\n     * Unserialize the given value.\n     *\n     * @param  string  $serialized\n     * @return mixed\n     */\n    protected function unserialize($serialized)\n    {\n        if ($this->connection instanceof PostgresConnection &&\n            ! Str::contains($serialized, [':', ';'])) {\n            $serialized = base64_decode($serialized);\n        }\n\n        return unserialize($serialized);\n    }\n\n    /**\n     * Convert the given raw batch to a Batch object.\n     *\n     * @param  object  $batch\n     * @return \\Illuminate\\Bus\\Batch\n     */\n    protected function toBatch($batch)\n    {\n        return $this->factory->make(\n            $this,\n            $batch->id,\n            $batch->name,\n            (int) $batch->total_jobs,\n            (int) $batch->pending_jobs,\n            (int) $batch->failed_jobs,\n            json_decode($batch->failed_job_ids, true),\n            $this->unserialize($batch->options),\n            CarbonImmutable::createFromTimestamp($batch->created_at),\n            $batch->cancelled_at ? CarbonImmutable::createFromTimestamp($batch->cancelled_at) : $batch->cancelled_at,\n            $batch->finished_at ? CarbonImmutable::createFromTimestamp($batch->finished_at) : $batch->finished_at\n        );\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/bus/Dispatcher.php",
    "content": "<?php\n\nnamespace Illuminate\\Bus;\n\nuse Closure;\nuse Illuminate\\Contracts\\Bus\\QueueingDispatcher;\nuse Illuminate\\Contracts\\Container\\Container;\nuse Illuminate\\Contracts\\Queue\\Queue;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Foundation\\Bus\\PendingChain;\nuse Illuminate\\Pipeline\\Pipeline;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Illuminate\\Queue\\Jobs\\SyncJob;\nuse Illuminate\\Support\\Collection;\nuse RuntimeException;\n\nclass Dispatcher implements QueueingDispatcher\n{\n    /**\n     * The container implementation.\n     *\n     * @var \\Illuminate\\Contracts\\Container\\Container\n     */\n    protected $container;\n\n    /**\n     * The pipeline instance for the bus.\n     *\n     * @var \\Illuminate\\Pipeline\\Pipeline\n     */\n    protected $pipeline;\n\n    /**\n     * The pipes to send commands through before dispatching.\n     *\n     * @var array\n     */\n    protected $pipes = [];\n\n    /**\n     * The command to handler mapping for non-self-handling events.\n     *\n     * @var array\n     */\n    protected $handlers = [];\n\n    /**\n     * The queue resolver callback.\n     *\n     * @var \\Closure|null\n     */\n    protected $queueResolver;\n\n    /**\n     * Create a new command dispatcher instance.\n     *\n     * @param  \\Illuminate\\Contracts\\Container\\Container  $container\n     * @param  \\Closure|null  $queueResolver\n     * @return void\n     */\n    public function __construct(Container $container, Closure $queueResolver = null)\n    {\n        $this->container = $container;\n        $this->queueResolver = $queueResolver;\n        $this->pipeline = new Pipeline($container);\n    }\n\n    /**\n     * Dispatch a command to its appropriate handler.\n     *\n     * @param  mixed  $command\n     * @return mixed\n     */\n    public function dispatch($command)\n    {\n        return $this->queueResolver && $this->commandShouldBeQueued($command)\n                        ? $this->dispatchToQueue($command)\n                        : $this->dispatchNow($command);\n    }\n\n    /**\n     * Dispatch a command to its appropriate handler in the current process.\n     *\n     * Queueable jobs will be dispatched to the \"sync\" queue.\n     *\n     * @param  mixed  $command\n     * @param  mixed  $handler\n     * @return mixed\n     */\n    public function dispatchSync($command, $handler = null)\n    {\n        if ($this->queueResolver &&\n            $this->commandShouldBeQueued($command) &&\n            method_exists($command, 'onConnection')) {\n            return $this->dispatchToQueue($command->onConnection('sync'));\n        }\n\n        return $this->dispatchNow($command, $handler);\n    }\n\n    /**\n     * Dispatch a command to its appropriate handler in the current process without using the synchronous queue.\n     *\n     * @param  mixed  $command\n     * @param  mixed  $handler\n     * @return mixed\n     */\n    public function dispatchNow($command, $handler = null)\n    {\n        $uses = class_uses_recursive($command);\n\n        if (in_array(InteractsWithQueue::class, $uses) &&\n            in_array(Queueable::class, $uses) &&\n            ! $command->job) {\n            $command->setJob(new SyncJob($this->container, json_encode([]), 'sync', 'sync'));\n        }\n\n        if ($handler || $handler = $this->getCommandHandler($command)) {\n            $callback = function ($command) use ($handler) {\n                $method = method_exists($handler, 'handle') ? 'handle' : '__invoke';\n\n                return $handler->{$method}($command);\n            };\n        } else {\n            $callback = function ($command) {\n                $method = method_exists($command, 'handle') ? 'handle' : '__invoke';\n\n                return $this->container->call([$command, $method]);\n            };\n        }\n\n        return $this->pipeline->send($command)->through($this->pipes)->then($callback);\n    }\n\n    /**\n     * Attempt to find the batch with the given ID.\n     *\n     * @param  string  $batchId\n     * @return \\Illuminate\\Bus\\Batch|null\n     */\n    public function findBatch(string $batchId)\n    {\n        return $this->container->make(BatchRepository::class)->find($batchId);\n    }\n\n    /**\n     * Create a new batch of queueable jobs.\n     *\n     * @param  \\Illuminate\\Support\\Collection|array|mixed  $jobs\n     * @return \\Illuminate\\Bus\\PendingBatch\n     */\n    public function batch($jobs)\n    {\n        return new PendingBatch($this->container, Collection::wrap($jobs));\n    }\n\n    /**\n     * Create a new chain of queueable jobs.\n     *\n     * @param  \\Illuminate\\Support\\Collection|array  $jobs\n     * @return \\Illuminate\\Foundation\\Bus\\PendingChain\n     */\n    public function chain($jobs)\n    {\n        $jobs = Collection::wrap($jobs);\n\n        return new PendingChain($jobs->shift(), $jobs->toArray());\n    }\n\n    /**\n     * Determine if the given command has a handler.\n     *\n     * @param  mixed  $command\n     * @return bool\n     */\n    public function hasCommandHandler($command)\n    {\n        return array_key_exists(get_class($command), $this->handlers);\n    }\n\n    /**\n     * Retrieve the handler for a command.\n     *\n     * @param  mixed  $command\n     * @return bool|mixed\n     */\n    public function getCommandHandler($command)\n    {\n        if ($this->hasCommandHandler($command)) {\n            return $this->container->make($this->handlers[get_class($command)]);\n        }\n\n        return false;\n    }\n\n    /**\n     * Determine if the given command should be queued.\n     *\n     * @param  mixed  $command\n     * @return bool\n     */\n    protected function commandShouldBeQueued($command)\n    {\n        return $command instanceof ShouldQueue;\n    }\n\n    /**\n     * Dispatch a command to its appropriate handler behind a queue.\n     *\n     * @param  mixed  $command\n     * @return mixed\n     *\n     * @throws \\RuntimeException\n     */\n    public function dispatchToQueue($command)\n    {\n        $connection = $command->connection ?? null;\n\n        $queue = call_user_func($this->queueResolver, $connection);\n\n        if (! $queue instanceof Queue) {\n            throw new RuntimeException('Queue resolver did not return a Queue implementation.');\n        }\n\n        if (method_exists($command, 'queue')) {\n            return $command->queue($queue, $command);\n        }\n\n        return $this->pushCommandToQueue($queue, $command);\n    }\n\n    /**\n     * Push the command onto the given queue instance.\n     *\n     * @param  \\Illuminate\\Contracts\\Queue\\Queue  $queue\n     * @param  mixed  $command\n     * @return mixed\n     */\n    protected function pushCommandToQueue($queue, $command)\n    {\n        if (isset($command->queue, $command->delay)) {\n            return $queue->laterOn($command->queue, $command->delay, $command);\n        }\n\n        if (isset($command->queue)) {\n            return $queue->pushOn($command->queue, $command);\n        }\n\n        if (isset($command->delay)) {\n            return $queue->later($command->delay, $command);\n        }\n\n        return $queue->push($command);\n    }\n\n    /**\n     * Dispatch a command to its appropriate handler after the current process.\n     *\n     * @param  mixed  $command\n     * @param  mixed  $handler\n     * @return void\n     */\n    public function dispatchAfterResponse($command, $handler = null)\n    {\n        $this->container->terminating(function () use ($command, $handler) {\n            $this->dispatchNow($command, $handler);\n        });\n    }\n\n    /**\n     * Set the pipes through which commands should be piped before dispatching.\n     *\n     * @param  array  $pipes\n     * @return $this\n     */\n    public function pipeThrough(array $pipes)\n    {\n        $this->pipes = $pipes;\n\n        return $this;\n    }\n\n    /**\n     * Map a command to a handler.\n     *\n     * @param  array  $map\n     * @return $this\n     */\n    public function map(array $map)\n    {\n        $this->handlers = array_merge($this->handlers, $map);\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/bus/Events/BatchDispatched.php",
    "content": "<?php\n\nnamespace Illuminate\\Bus\\Events;\n\nuse Illuminate\\Bus\\Batch;\n\nclass BatchDispatched\n{\n    /**\n     * The batch instance.\n     *\n     * @var \\Illuminate\\Bus\\Batch\n     */\n    public $batch;\n\n    /**\n     * Create a new event instance.\n     *\n     * @param  \\Illuminate\\Bus\\Batch  $batch\n     * @return void\n     */\n    public function __construct(Batch $batch)\n    {\n        $this->batch = $batch;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/bus/LICENSE.md",
    "content": "The MIT License (MIT)\n\nCopyright (c) Taylor Otwell\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "server/vendor/illuminate/bus/PendingBatch.php",
    "content": "<?php\n\nnamespace Illuminate\\Bus;\n\nuse Closure;\nuse Illuminate\\Bus\\Events\\BatchDispatched;\nuse Illuminate\\Contracts\\Container\\Container;\nuse Illuminate\\Contracts\\Events\\Dispatcher as EventDispatcher;\nuse Illuminate\\Queue\\SerializableClosureFactory;\nuse Illuminate\\Support\\Arr;\nuse Illuminate\\Support\\Collection;\nuse Throwable;\n\nclass PendingBatch\n{\n    /**\n     * The IoC container instance.\n     *\n     * @var \\Illuminate\\Contracts\\Container\\Container\n     */\n    protected $container;\n\n    /**\n     * The batch name.\n     *\n     * @var string\n     */\n    public $name = '';\n\n    /**\n     * The jobs that belong to the batch.\n     *\n     * @var \\Illuminate\\Support\\Collection\n     */\n    public $jobs;\n\n    /**\n     * The batch options.\n     *\n     * @var array\n     */\n    public $options = [];\n\n    /**\n     * Create a new pending batch instance.\n     *\n     * @param  \\Illuminate\\Contracts\\Container\\Container  $container\n     * @param  \\Illuminate\\Support\\Collection  $jobs\n     * @return void\n     */\n    public function __construct(Container $container, Collection $jobs)\n    {\n        $this->container = $container;\n        $this->jobs = $jobs;\n    }\n\n    /**\n     * Add jobs to the batch.\n     *\n     * @param  iterable  $jobs\n     * @return $this\n     */\n    public function add($jobs)\n    {\n        foreach ($jobs as $job) {\n            $this->jobs->push($job);\n        }\n\n        return $this;\n    }\n\n    /**\n     * Add a callback to be executed after all jobs in the batch have executed successfully.\n     *\n     * @param  callable  $callback\n     * @return $this\n     */\n    public function then($callback)\n    {\n        $this->options['then'][] = $callback instanceof Closure\n                        ? SerializableClosureFactory::make($callback)\n                        : $callback;\n\n        return $this;\n    }\n\n    /**\n     * Get the \"then\" callbacks that have been registered with the pending batch.\n     *\n     * @return array\n     */\n    public function thenCallbacks()\n    {\n        return $this->options['then'] ?? [];\n    }\n\n    /**\n     * Add a callback to be executed after the first failing job in the batch.\n     *\n     * @param  callable  $callback\n     * @return $this\n     */\n    public function catch($callback)\n    {\n        $this->options['catch'][] = $callback instanceof Closure\n                    ? SerializableClosureFactory::make($callback)\n                    : $callback;\n\n        return $this;\n    }\n\n    /**\n     * Get the \"catch\" callbacks that have been registered with the pending batch.\n     *\n     * @return array\n     */\n    public function catchCallbacks()\n    {\n        return $this->options['catch'] ?? [];\n    }\n\n    /**\n     * Add a callback to be executed after the batch has finished executing.\n     *\n     * @param  callable  $callback\n     * @return $this\n     */\n    public function finally($callback)\n    {\n        $this->options['finally'][] = $callback instanceof Closure\n                    ? SerializableClosureFactory::make($callback)\n                    : $callback;\n\n        return $this;\n    }\n\n    /**\n     * Get the \"finally\" callbacks that have been registered with the pending batch.\n     *\n     * @return array\n     */\n    public function finallyCallbacks()\n    {\n        return $this->options['finally'] ?? [];\n    }\n\n    /**\n     * Indicate that the batch should not be cancelled when a job within the batch fails.\n     *\n     * @param  bool  $allowFailures\n     * @return $this\n     */\n    public function allowFailures($allowFailures = true)\n    {\n        $this->options['allowFailures'] = $allowFailures;\n\n        return $this;\n    }\n\n    /**\n     * Determine if the pending batch allows jobs to fail without cancelling the batch.\n     *\n     * @return bool\n     */\n    public function allowsFailures()\n    {\n        return Arr::get($this->options, 'allowFailures', false) === true;\n    }\n\n    /**\n     * Set the name for the batch.\n     *\n     * @param  string  $name\n     * @return $this\n     */\n    public function name(string $name)\n    {\n        $this->name = $name;\n\n        return $this;\n    }\n\n    /**\n     * Specify the queue connection that the batched jobs should run on.\n     *\n     * @param  string  $connection\n     * @return $this\n     */\n    public function onConnection(string $connection)\n    {\n        $this->options['connection'] = $connection;\n\n        return $this;\n    }\n\n    /**\n     * Get the connection used by the pending batch.\n     *\n     * @return string|null\n     */\n    public function connection()\n    {\n        return $this->options['connection'] ?? null;\n    }\n\n    /**\n     * Specify the queue that the batched jobs should run on.\n     *\n     * @param  string  $queue\n     * @return $this\n     */\n    public function onQueue(string $queue)\n    {\n        $this->options['queue'] = $queue;\n\n        return $this;\n    }\n\n    /**\n     * Get the queue used by the pending batch.\n     *\n     * @return string|null\n     */\n    public function queue()\n    {\n        return $this->options['queue'] ?? null;\n    }\n\n    /**\n     * Add additional data into the batch's options array.\n     *\n     * @param  string  $key\n     * @param  mixed  $value\n     * @return $this\n     */\n    public function withOption(string $key, $value)\n    {\n        $this->options[$key] = $value;\n\n        return $this;\n    }\n\n    /**\n     * Dispatch the batch.\n     *\n     * @return \\Illuminate\\Bus\\Batch\n     *\n     * @throws \\Throwable\n     */\n    public function dispatch()\n    {\n        $repository = $this->container->make(BatchRepository::class);\n\n        try {\n            $batch = $repository->store($this);\n\n            $batch = $batch->add($this->jobs);\n        } catch (Throwable $e) {\n            if (isset($batch)) {\n                $repository->delete($batch->id);\n            }\n\n            throw $e;\n        }\n\n        $this->container->make(EventDispatcher::class)->dispatch(\n            new BatchDispatched($batch)\n        );\n\n        return $batch;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/bus/PrunableBatchRepository.php",
    "content": "<?php\n\nnamespace Illuminate\\Bus;\n\nuse DateTimeInterface;\n\ninterface PrunableBatchRepository extends BatchRepository\n{\n    /**\n     * Prune all of the entries older than the given date.\n     *\n     * @param  \\DateTimeInterface  $before\n     * @return int\n     */\n    public function prune(DateTimeInterface $before);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/bus/Queueable.php",
    "content": "<?php\n\nnamespace Illuminate\\Bus;\n\nuse Closure;\nuse Illuminate\\Queue\\CallQueuedClosure;\nuse Illuminate\\Support\\Arr;\nuse RuntimeException;\n\ntrait Queueable\n{\n    /**\n     * The name of the connection the job should be sent to.\n     *\n     * @var string|null\n     */\n    public $connection;\n\n    /**\n     * The name of the queue the job should be sent to.\n     *\n     * @var string|null\n     */\n    public $queue;\n\n    /**\n     * The name of the connection the chain should be sent to.\n     *\n     * @var string|null\n     */\n    public $chainConnection;\n\n    /**\n     * The name of the queue the chain should be sent to.\n     *\n     * @var string|null\n     */\n    public $chainQueue;\n\n    /**\n     * The callbacks to be executed on chain failure.\n     *\n     * @var array|null\n     */\n    public $chainCatchCallbacks;\n\n    /**\n     * The number of seconds before the job should be made available.\n     *\n     * @var \\DateTimeInterface|\\DateInterval|int|null\n     */\n    public $delay;\n\n    /**\n     * Indicates whether the job should be dispatched after all database transactions have committed.\n     *\n     * @var bool|null\n     */\n    public $afterCommit;\n\n    /**\n     * The middleware the job should be dispatched through.\n     *\n     * @var array\n     */\n    public $middleware = [];\n\n    /**\n     * The jobs that should run if this job is successful.\n     *\n     * @var array\n     */\n    public $chained = [];\n\n    /**\n     * Set the desired connection for the job.\n     *\n     * @param  string|null  $connection\n     * @return $this\n     */\n    public function onConnection($connection)\n    {\n        $this->connection = $connection;\n\n        return $this;\n    }\n\n    /**\n     * Set the desired queue for the job.\n     *\n     * @param  string|null  $queue\n     * @return $this\n     */\n    public function onQueue($queue)\n    {\n        $this->queue = $queue;\n\n        return $this;\n    }\n\n    /**\n     * Set the desired connection for the chain.\n     *\n     * @param  string|null  $connection\n     * @return $this\n     */\n    public function allOnConnection($connection)\n    {\n        $this->chainConnection = $connection;\n        $this->connection = $connection;\n\n        return $this;\n    }\n\n    /**\n     * Set the desired queue for the chain.\n     *\n     * @param  string|null  $queue\n     * @return $this\n     */\n    public function allOnQueue($queue)\n    {\n        $this->chainQueue = $queue;\n        $this->queue = $queue;\n\n        return $this;\n    }\n\n    /**\n     * Set the desired delay for the job.\n     *\n     * @param  \\DateTimeInterface|\\DateInterval|int|null  $delay\n     * @return $this\n     */\n    public function delay($delay)\n    {\n        $this->delay = $delay;\n\n        return $this;\n    }\n\n    /**\n     * Indicate that the job should be dispatched after all database transactions have committed.\n     *\n     * @return $this\n     */\n    public function afterCommit()\n    {\n        $this->afterCommit = true;\n\n        return $this;\n    }\n\n    /**\n     * Indicate that the job should not wait until database transactions have been committed before dispatching.\n     *\n     * @return $this\n     */\n    public function beforeCommit()\n    {\n        $this->afterCommit = false;\n\n        return $this;\n    }\n\n    /**\n     * Specify the middleware the job should be dispatched through.\n     *\n     * @param  array|object  $middleware\n     * @return $this\n     */\n    public function through($middleware)\n    {\n        $this->middleware = Arr::wrap($middleware);\n\n        return $this;\n    }\n\n    /**\n     * Set the jobs that should run if this job is successful.\n     *\n     * @param  array  $chain\n     * @return $this\n     */\n    public function chain($chain)\n    {\n        $this->chained = collect($chain)->map(function ($job) {\n            return $this->serializeJob($job);\n        })->all();\n\n        return $this;\n    }\n\n    /**\n     * Serialize a job for queuing.\n     *\n     * @param  mixed  $job\n     * @return string\n     *\n     * @throws \\RuntimeException\n     */\n    protected function serializeJob($job)\n    {\n        if ($job instanceof Closure) {\n            if (! class_exists(CallQueuedClosure::class)) {\n                throw new RuntimeException(\n                    'To enable support for closure jobs, please install the illuminate/queue package.'\n                );\n            }\n\n            $job = CallQueuedClosure::create($job);\n        }\n\n        return serialize($job);\n    }\n\n    /**\n     * Dispatch the next job on the chain.\n     *\n     * @return void\n     */\n    public function dispatchNextJobInChain()\n    {\n        if (! empty($this->chained)) {\n            dispatch(tap(unserialize(array_shift($this->chained)), function ($next) {\n                $next->chained = $this->chained;\n\n                $next->onConnection($next->connection ?: $this->chainConnection);\n                $next->onQueue($next->queue ?: $this->chainQueue);\n\n                $next->chainConnection = $this->chainConnection;\n                $next->chainQueue = $this->chainQueue;\n                $next->chainCatchCallbacks = $this->chainCatchCallbacks;\n            }));\n        }\n    }\n\n    /**\n     * Invoke all of the chain's failed job callbacks.\n     *\n     * @param  \\Throwable  $e\n     * @return void\n     */\n    public function invokeChainCatchCallbacks($e)\n    {\n        collect($this->chainCatchCallbacks)->each(function ($callback) use ($e) {\n            $callback($e);\n        });\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/bus/UniqueLock.php",
    "content": "<?php\n\nnamespace Illuminate\\Bus;\n\nuse Illuminate\\Contracts\\Cache\\Repository as Cache;\n\nclass UniqueLock\n{\n    /**\n     * The cache repository implementation.\n     *\n     * @var \\Illuminate\\Contracts\\Cache\\Repository\n     */\n    protected $cache;\n\n    /**\n     * Create a new unique lock manager instance.\n     *\n     * @param  \\Illuminate\\Contracts\\Cache\\Repository  $cache\n     * @return void\n     */\n    public function __construct(Cache $cache)\n    {\n        $this->cache = $cache;\n    }\n\n    /**\n     * Attempt to acquire a lock for the given job.\n     *\n     * @param  mixed  $job\n     * @return bool\n     */\n    public function acquire($job)\n    {\n        $uniqueId = method_exists($job, 'uniqueId')\n                    ? $job->uniqueId()\n                    : ($job->uniqueId ?? '');\n\n        $cache = method_exists($job, 'uniqueVia')\n                    ? $job->uniqueVia()\n                    : $this->cache;\n\n        return (bool) $cache->lock(\n            $key = 'laravel_unique_job:'.get_class($job).$uniqueId,\n            $job->uniqueFor ?? 0\n        )->get();\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/bus/UpdatedBatchJobCounts.php",
    "content": "<?php\n\nnamespace Illuminate\\Bus;\n\nclass UpdatedBatchJobCounts\n{\n    /**\n     * The number of pending jobs remaining for the batch.\n     *\n     * @var int\n     */\n    public $pendingJobs;\n\n    /**\n     * The number of failed jobs that belong to the batch.\n     *\n     * @var int\n     */\n    public $failedJobs;\n\n    /**\n     * Create a new batch job counts object.\n     *\n     * @param  int  $pendingJobs\n     * @param  int  $failedJobs\n     * @return void\n     */\n    public function __construct(int $pendingJobs = 0, int $failedJobs = 0)\n    {\n        $this->pendingJobs = $pendingJobs;\n        $this->failedJobs = $failedJobs;\n    }\n\n    /**\n     * Determine if all jobs have run exactly once.\n     *\n     * @return bool\n     */\n    public function allJobsHaveRanExactlyOnce()\n    {\n        return ($this->pendingJobs - $this->failedJobs) === 0;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/bus/composer.json",
    "content": "{\n    \"name\": \"illuminate/bus\",\n    \"description\": \"The Illuminate Bus package.\",\n    \"license\": \"MIT\",\n    \"homepage\": \"https://laravel.com\",\n    \"support\": {\n        \"issues\": \"https://github.com/laravel/framework/issues\",\n        \"source\": \"https://github.com/laravel/framework\"\n    },\n    \"authors\": [\n        {\n            \"name\": \"Taylor Otwell\",\n            \"email\": \"taylor@laravel.com\"\n        }\n    ],\n    \"require\": {\n        \"php\": \"^7.3|^8.0\",\n        \"illuminate/collections\": \"^8.0\",\n        \"illuminate/contracts\": \"^8.0\",\n        \"illuminate/pipeline\": \"^8.0\",\n        \"illuminate/support\": \"^8.0\"\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"Illuminate\\\\Bus\\\\\": \"\"\n        }\n    },\n    \"extra\": {\n        \"branch-alias\": {\n            \"dev-master\": \"8.x-dev\"\n        }\n    },\n    \"suggest\": {\n        \"illuminate/queue\": \"Required to use closures when chaining jobs (^7.0).\"\n    },\n    \"config\": {\n        \"sort-packages\": true\n    },\n    \"minimum-stability\": \"dev\"\n}\n"
  },
  {
    "path": "server/vendor/illuminate/collections/Arr.php",
    "content": "<?php\n\nnamespace Illuminate\\Support;\n\nuse ArrayAccess;\nuse Illuminate\\Support\\Traits\\Macroable;\nuse InvalidArgumentException;\n\nclass Arr\n{\n    use Macroable;\n\n    /**\n     * Determine whether the given value is array accessible.\n     *\n     * @param  mixed  $value\n     * @return bool\n     */\n    public static function accessible($value)\n    {\n        return is_array($value) || $value instanceof ArrayAccess;\n    }\n\n    /**\n     * Add an element to an array using \"dot\" notation if it doesn't exist.\n     *\n     * @param  array  $array\n     * @param  string  $key\n     * @param  mixed  $value\n     * @return array\n     */\n    public static function add($array, $key, $value)\n    {\n        if (is_null(static::get($array, $key))) {\n            static::set($array, $key, $value);\n        }\n\n        return $array;\n    }\n\n    /**\n     * Collapse an array of arrays into a single array.\n     *\n     * @param  iterable  $array\n     * @return array\n     */\n    public static function collapse($array)\n    {\n        $results = [];\n\n        foreach ($array as $values) {\n            if ($values instanceof Collection) {\n                $values = $values->all();\n            } elseif (! is_array($values)) {\n                continue;\n            }\n\n            $results[] = $values;\n        }\n\n        return array_merge([], ...$results);\n    }\n\n    /**\n     * Cross join the given arrays, returning all possible permutations.\n     *\n     * @param  iterable  ...$arrays\n     * @return array\n     */\n    public static function crossJoin(...$arrays)\n    {\n        $results = [[]];\n\n        foreach ($arrays as $index => $array) {\n            $append = [];\n\n            foreach ($results as $product) {\n                foreach ($array as $item) {\n                    $product[$index] = $item;\n\n                    $append[] = $product;\n                }\n            }\n\n            $results = $append;\n        }\n\n        return $results;\n    }\n\n    /**\n     * Divide an array into two arrays. One with keys and the other with values.\n     *\n     * @param  array  $array\n     * @return array\n     */\n    public static function divide($array)\n    {\n        return [array_keys($array), array_values($array)];\n    }\n\n    /**\n     * Flatten a multi-dimensional associative array with dots.\n     *\n     * @param  iterable  $array\n     * @param  string  $prepend\n     * @return array\n     */\n    public static function dot($array, $prepend = '')\n    {\n        $results = [];\n\n        foreach ($array as $key => $value) {\n            if (is_array($value) && ! empty($value)) {\n                $results = array_merge($results, static::dot($value, $prepend.$key.'.'));\n            } else {\n                $results[$prepend.$key] = $value;\n            }\n        }\n\n        return $results;\n    }\n\n    /**\n     * Convert a flatten \"dot\" notation array into an expanded array.\n     *\n     * @param  iterable  $array\n     * @return array\n     */\n    public static function undot($array)\n    {\n        $results = [];\n\n        foreach ($array as $key => $value) {\n            static::set($results, $key, $value);\n        }\n\n        return $results;\n    }\n\n    /**\n     * Get all of the given array except for a specified array of keys.\n     *\n     * @param  array  $array\n     * @param  array|string  $keys\n     * @return array\n     */\n    public static function except($array, $keys)\n    {\n        static::forget($array, $keys);\n\n        return $array;\n    }\n\n    /**\n     * Determine if the given key exists in the provided array.\n     *\n     * @param  \\ArrayAccess|array  $array\n     * @param  string|int  $key\n     * @return bool\n     */\n    public static function exists($array, $key)\n    {\n        if ($array instanceof Enumerable) {\n            return $array->has($key);\n        }\n\n        if ($array instanceof ArrayAccess) {\n            return $array->offsetExists($key);\n        }\n\n        return array_key_exists($key, $array);\n    }\n\n    /**\n     * Return the first element in an array passing a given truth test.\n     *\n     * @param  iterable  $array\n     * @param  callable|null  $callback\n     * @param  mixed  $default\n     * @return mixed\n     */\n    public static function first($array, callable $callback = null, $default = null)\n    {\n        if (is_null($callback)) {\n            if (empty($array)) {\n                return value($default);\n            }\n\n            foreach ($array as $item) {\n                return $item;\n            }\n        }\n\n        foreach ($array as $key => $value) {\n            if ($callback($value, $key)) {\n                return $value;\n            }\n        }\n\n        return value($default);\n    }\n\n    /**\n     * Return the last element in an array passing a given truth test.\n     *\n     * @param  array  $array\n     * @param  callable|null  $callback\n     * @param  mixed  $default\n     * @return mixed\n     */\n    public static function last($array, callable $callback = null, $default = null)\n    {\n        if (is_null($callback)) {\n            return empty($array) ? value($default) : end($array);\n        }\n\n        return static::first(array_reverse($array, true), $callback, $default);\n    }\n\n    /**\n     * Flatten a multi-dimensional array into a single level.\n     *\n     * @param  iterable  $array\n     * @param  int  $depth\n     * @return array\n     */\n    public static function flatten($array, $depth = INF)\n    {\n        $result = [];\n\n        foreach ($array as $item) {\n            $item = $item instanceof Collection ? $item->all() : $item;\n\n            if (! is_array($item)) {\n                $result[] = $item;\n            } else {\n                $values = $depth === 1\n                    ? array_values($item)\n                    : static::flatten($item, $depth - 1);\n\n                foreach ($values as $value) {\n                    $result[] = $value;\n                }\n            }\n        }\n\n        return $result;\n    }\n\n    /**\n     * Remove one or many array items from a given array using \"dot\" notation.\n     *\n     * @param  array  $array\n     * @param  array|string  $keys\n     * @return void\n     */\n    public static function forget(&$array, $keys)\n    {\n        $original = &$array;\n\n        $keys = (array) $keys;\n\n        if (count($keys) === 0) {\n            return;\n        }\n\n        foreach ($keys as $key) {\n            // if the exact key exists in the top-level, remove it\n            if (static::exists($array, $key)) {\n                unset($array[$key]);\n\n                continue;\n            }\n\n            $parts = explode('.', $key);\n\n            // clean up before each pass\n            $array = &$original;\n\n            while (count($parts) > 1) {\n                $part = array_shift($parts);\n\n                if (isset($array[$part]) && is_array($array[$part])) {\n                    $array = &$array[$part];\n                } else {\n                    continue 2;\n                }\n            }\n\n            unset($array[array_shift($parts)]);\n        }\n    }\n\n    /**\n     * Get an item from an array using \"dot\" notation.\n     *\n     * @param  \\ArrayAccess|array  $array\n     * @param  string|int|null  $key\n     * @param  mixed  $default\n     * @return mixed\n     */\n    public static function get($array, $key, $default = null)\n    {\n        if (! static::accessible($array)) {\n            return value($default);\n        }\n\n        if (is_null($key)) {\n            return $array;\n        }\n\n        if (static::exists($array, $key)) {\n            return $array[$key];\n        }\n\n        if (strpos($key, '.') === false) {\n            return $array[$key] ?? value($default);\n        }\n\n        foreach (explode('.', $key) as $segment) {\n            if (static::accessible($array) && static::exists($array, $segment)) {\n                $array = $array[$segment];\n            } else {\n                return value($default);\n            }\n        }\n\n        return $array;\n    }\n\n    /**\n     * Check if an item or items exist in an array using \"dot\" notation.\n     *\n     * @param  \\ArrayAccess|array  $array\n     * @param  string|array  $keys\n     * @return bool\n     */\n    public static function has($array, $keys)\n    {\n        $keys = (array) $keys;\n\n        if (! $array || $keys === []) {\n            return false;\n        }\n\n        foreach ($keys as $key) {\n            $subKeyArray = $array;\n\n            if (static::exists($array, $key)) {\n                continue;\n            }\n\n            foreach (explode('.', $key) as $segment) {\n                if (static::accessible($subKeyArray) && static::exists($subKeyArray, $segment)) {\n                    $subKeyArray = $subKeyArray[$segment];\n                } else {\n                    return false;\n                }\n            }\n        }\n\n        return true;\n    }\n\n    /**\n     * Determine if any of the keys exist in an array using \"dot\" notation.\n     *\n     * @param  \\ArrayAccess|array  $array\n     * @param  string|array  $keys\n     * @return bool\n     */\n    public static function hasAny($array, $keys)\n    {\n        if (is_null($keys)) {\n            return false;\n        }\n\n        $keys = (array) $keys;\n\n        if (! $array) {\n            return false;\n        }\n\n        if ($keys === []) {\n            return false;\n        }\n\n        foreach ($keys as $key) {\n            if (static::has($array, $key)) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * Determines if an array is associative.\n     *\n     * An array is \"associative\" if it doesn't have sequential numerical keys beginning with zero.\n     *\n     * @param  array  $array\n     * @return bool\n     */\n    public static function isAssoc(array $array)\n    {\n        $keys = array_keys($array);\n\n        return array_keys($keys) !== $keys;\n    }\n\n    /**\n     * Determines if an array is a list.\n     *\n     * An array is a \"list\" if all array keys are sequential integers starting from 0 with no gaps in between.\n     *\n     * @param  array  $array\n     * @return bool\n     */\n    public static function isList($array)\n    {\n        return ! self::isAssoc($array);\n    }\n\n    /**\n     * Get a subset of the items from the given array.\n     *\n     * @param  array  $array\n     * @param  array|string  $keys\n     * @return array\n     */\n    public static function only($array, $keys)\n    {\n        return array_intersect_key($array, array_flip((array) $keys));\n    }\n\n    /**\n     * Pluck an array of values from an array.\n     *\n     * @param  iterable  $array\n     * @param  string|array|int|null  $value\n     * @param  string|array|null  $key\n     * @return array\n     */\n    public static function pluck($array, $value, $key = null)\n    {\n        $results = [];\n\n        [$value, $key] = static::explodePluckParameters($value, $key);\n\n        foreach ($array as $item) {\n            $itemValue = data_get($item, $value);\n\n            // If the key is \"null\", we will just append the value to the array and keep\n            // looping. Otherwise we will key the array using the value of the key we\n            // received from the developer. Then we'll return the final array form.\n            if (is_null($key)) {\n                $results[] = $itemValue;\n            } else {\n                $itemKey = data_get($item, $key);\n\n                if (is_object($itemKey) && method_exists($itemKey, '__toString')) {\n                    $itemKey = (string) $itemKey;\n                }\n\n                $results[$itemKey] = $itemValue;\n            }\n        }\n\n        return $results;\n    }\n\n    /**\n     * Explode the \"value\" and \"key\" arguments passed to \"pluck\".\n     *\n     * @param  string|array  $value\n     * @param  string|array|null  $key\n     * @return array\n     */\n    protected static function explodePluckParameters($value, $key)\n    {\n        $value = is_string($value) ? explode('.', $value) : $value;\n\n        $key = is_null($key) || is_array($key) ? $key : explode('.', $key);\n\n        return [$value, $key];\n    }\n\n    /**\n     * Push an item onto the beginning of an array.\n     *\n     * @param  array  $array\n     * @param  mixed  $value\n     * @param  mixed  $key\n     * @return array\n     */\n    public static function prepend($array, $value, $key = null)\n    {\n        if (func_num_args() == 2) {\n            array_unshift($array, $value);\n        } else {\n            $array = [$key => $value] + $array;\n        }\n\n        return $array;\n    }\n\n    /**\n     * Get a value from the array, and remove it.\n     *\n     * @param  array  $array\n     * @param  string|int  $key\n     * @param  mixed  $default\n     * @return mixed\n     */\n    public static function pull(&$array, $key, $default = null)\n    {\n        $value = static::get($array, $key, $default);\n\n        static::forget($array, $key);\n\n        return $value;\n    }\n\n    /**\n     * Convert the array into a query string.\n     *\n     * @param  array  $array\n     * @return string\n     */\n    public static function query($array)\n    {\n        return http_build_query($array, '', '&', PHP_QUERY_RFC3986);\n    }\n\n    /**\n     * Get one or a specified number of random values from an array.\n     *\n     * @param  array  $array\n     * @param  int|null  $number\n     * @param  bool|false  $preserveKeys\n     * @return mixed\n     *\n     * @throws \\InvalidArgumentException\n     */\n    public static function random($array, $number = null, $preserveKeys = false)\n    {\n        $requested = is_null($number) ? 1 : $number;\n\n        $count = count($array);\n\n        if ($requested > $count) {\n            throw new InvalidArgumentException(\n                \"You requested {$requested} items, but there are only {$count} items available.\"\n            );\n        }\n\n        if (is_null($number)) {\n            return $array[array_rand($array)];\n        }\n\n        if ((int) $number === 0) {\n            return [];\n        }\n\n        $keys = array_rand($array, $number);\n\n        $results = [];\n\n        if ($preserveKeys) {\n            foreach ((array) $keys as $key) {\n                $results[$key] = $array[$key];\n            }\n        } else {\n            foreach ((array) $keys as $key) {\n                $results[] = $array[$key];\n            }\n        }\n\n        return $results;\n    }\n\n    /**\n     * Set an array item to a given value using \"dot\" notation.\n     *\n     * If no key is given to the method, the entire array will be replaced.\n     *\n     * @param  array  $array\n     * @param  string|null  $key\n     * @param  mixed  $value\n     * @return array\n     */\n    public static function set(&$array, $key, $value)\n    {\n        if (is_null($key)) {\n            return $array = $value;\n        }\n\n        $keys = explode('.', $key);\n\n        foreach ($keys as $i => $key) {\n            if (count($keys) === 1) {\n                break;\n            }\n\n            unset($keys[$i]);\n\n            // If the key doesn't exist at this depth, we will just create an empty array\n            // to hold the next value, allowing us to create the arrays to hold final\n            // values at the correct depth. Then we'll keep digging into the array.\n            if (! isset($array[$key]) || ! is_array($array[$key])) {\n                $array[$key] = [];\n            }\n\n            $array = &$array[$key];\n        }\n\n        $array[array_shift($keys)] = $value;\n\n        return $array;\n    }\n\n    /**\n     * Shuffle the given array and return the result.\n     *\n     * @param  array  $array\n     * @param  int|null  $seed\n     * @return array\n     */\n    public static function shuffle($array, $seed = null)\n    {\n        if (is_null($seed)) {\n            shuffle($array);\n        } else {\n            mt_srand($seed);\n            shuffle($array);\n            mt_srand();\n        }\n\n        return $array;\n    }\n\n    /**\n     * Sort the array using the given callback or \"dot\" notation.\n     *\n     * @param  array  $array\n     * @param  callable|array|string|null  $callback\n     * @return array\n     */\n    public static function sort($array, $callback = null)\n    {\n        return Collection::make($array)->sortBy($callback)->all();\n    }\n\n    /**\n     * Recursively sort an array by keys and values.\n     *\n     * @param  array  $array\n     * @param  int  $options\n     * @param  bool  $descending\n     * @return array\n     */\n    public static function sortRecursive($array, $options = SORT_REGULAR, $descending = false)\n    {\n        foreach ($array as &$value) {\n            if (is_array($value)) {\n                $value = static::sortRecursive($value, $options, $descending);\n            }\n        }\n\n        if (static::isAssoc($array)) {\n            $descending\n                    ? krsort($array, $options)\n                    : ksort($array, $options);\n        } else {\n            $descending\n                    ? rsort($array, $options)\n                    : sort($array, $options);\n        }\n\n        return $array;\n    }\n\n    /**\n     * Conditionally compile classes from an array into a CSS class list.\n     *\n     * @param  array  $array\n     * @return string\n     */\n    public static function toCssClasses($array)\n    {\n        $classList = static::wrap($array);\n\n        $classes = [];\n\n        foreach ($classList as $class => $constraint) {\n            if (is_numeric($class)) {\n                $classes[] = $constraint;\n            } elseif ($constraint) {\n                $classes[] = $class;\n            }\n        }\n\n        return implode(' ', $classes);\n    }\n\n    /**\n     * Filter the array using the given callback.\n     *\n     * @param  array  $array\n     * @param  callable  $callback\n     * @return array\n     */\n    public static function where($array, callable $callback)\n    {\n        return array_filter($array, $callback, ARRAY_FILTER_USE_BOTH);\n    }\n\n    /**\n     * Filter items where the value is not null.\n     *\n     * @param  array  $array\n     * @return array\n     */\n    public static function whereNotNull($array)\n    {\n        return static::where($array, function ($value) {\n            return ! is_null($value);\n        });\n    }\n\n    /**\n     * If the given value is not an array and not null, wrap it in one.\n     *\n     * @param  mixed  $value\n     * @return array\n     */\n    public static function wrap($value)\n    {\n        if (is_null($value)) {\n            return [];\n        }\n\n        return is_array($value) ? $value : [$value];\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/collections/Collection.php",
    "content": "<?php\n\nnamespace Illuminate\\Support;\n\nuse ArrayAccess;\nuse ArrayIterator;\nuse Illuminate\\Contracts\\Support\\CanBeEscapedWhenCastToString;\nuse Illuminate\\Support\\Traits\\EnumeratesValues;\nuse Illuminate\\Support\\Traits\\Macroable;\nuse stdClass;\n\nclass Collection implements ArrayAccess, CanBeEscapedWhenCastToString, Enumerable\n{\n    use EnumeratesValues, Macroable;\n\n    /**\n     * The items contained in the collection.\n     *\n     * @var array\n     */\n    protected $items = [];\n\n    /**\n     * Create a new collection.\n     *\n     * @param  mixed  $items\n     * @return void\n     */\n    public function __construct($items = [])\n    {\n        $this->items = $this->getArrayableItems($items);\n    }\n\n    /**\n     * Create a collection with the given range.\n     *\n     * @param  int  $from\n     * @param  int  $to\n     * @return static\n     */\n    public static function range($from, $to)\n    {\n        return new static(range($from, $to));\n    }\n\n    /**\n     * Get all of the items in the collection.\n     *\n     * @return array\n     */\n    public function all()\n    {\n        return $this->items;\n    }\n\n    /**\n     * Get a lazy collection for the items in this collection.\n     *\n     * @return \\Illuminate\\Support\\LazyCollection\n     */\n    public function lazy()\n    {\n        return new LazyCollection($this->items);\n    }\n\n    /**\n     * Get the average value of a given key.\n     *\n     * @param  callable|string|null  $callback\n     * @return mixed\n     */\n    public function avg($callback = null)\n    {\n        $callback = $this->valueRetriever($callback);\n\n        $items = $this->map(function ($value) use ($callback) {\n            return $callback($value);\n        })->filter(function ($value) {\n            return ! is_null($value);\n        });\n\n        if ($count = $items->count()) {\n            return $items->sum() / $count;\n        }\n    }\n\n    /**\n     * Get the median of a given key.\n     *\n     * @param  string|array|null  $key\n     * @return mixed\n     */\n    public function median($key = null)\n    {\n        $values = (isset($key) ? $this->pluck($key) : $this)\n            ->filter(function ($item) {\n                return ! is_null($item);\n            })->sort()->values();\n\n        $count = $values->count();\n\n        if ($count === 0) {\n            return;\n        }\n\n        $middle = (int) ($count / 2);\n\n        if ($count % 2) {\n            return $values->get($middle);\n        }\n\n        return (new static([\n            $values->get($middle - 1), $values->get($middle),\n        ]))->average();\n    }\n\n    /**\n     * Get the mode of a given key.\n     *\n     * @param  string|array|null  $key\n     * @return array|null\n     */\n    public function mode($key = null)\n    {\n        if ($this->count() === 0) {\n            return;\n        }\n\n        $collection = isset($key) ? $this->pluck($key) : $this;\n\n        $counts = new static;\n\n        $collection->each(function ($value) use ($counts) {\n            $counts[$value] = isset($counts[$value]) ? $counts[$value] + 1 : 1;\n        });\n\n        $sorted = $counts->sort();\n\n        $highestValue = $sorted->last();\n\n        return $sorted->filter(function ($value) use ($highestValue) {\n            return $value == $highestValue;\n        })->sort()->keys()->all();\n    }\n\n    /**\n     * Collapse the collection of items into a single array.\n     *\n     * @return static\n     */\n    public function collapse()\n    {\n        return new static(Arr::collapse($this->items));\n    }\n\n    /**\n     * Determine if an item exists in the collection.\n     *\n     * @param  mixed  $key\n     * @param  mixed  $operator\n     * @param  mixed  $value\n     * @return bool\n     */\n    public function contains($key, $operator = null, $value = null)\n    {\n        if (func_num_args() === 1) {\n            if ($this->useAsCallable($key)) {\n                $placeholder = new stdClass;\n\n                return $this->first($key, $placeholder) !== $placeholder;\n            }\n\n            return in_array($key, $this->items);\n        }\n\n        return $this->contains($this->operatorForWhere(...func_get_args()));\n    }\n\n    /**\n     * Determine if an item is not contained in the collection.\n     *\n     * @param  mixed  $key\n     * @param  mixed  $operator\n     * @param  mixed  $value\n     * @return bool\n     */\n    public function doesntContain($key, $operator = null, $value = null)\n    {\n        return ! $this->contains(...func_get_args());\n    }\n\n    /**\n     * Cross join with the given lists, returning all possible permutations.\n     *\n     * @param  mixed  ...$lists\n     * @return static\n     */\n    public function crossJoin(...$lists)\n    {\n        return new static(Arr::crossJoin(\n            $this->items, ...array_map([$this, 'getArrayableItems'], $lists)\n        ));\n    }\n\n    /**\n     * Get the items in the collection that are not present in the given items.\n     *\n     * @param  mixed  $items\n     * @return static\n     */\n    public function diff($items)\n    {\n        return new static(array_diff($this->items, $this->getArrayableItems($items)));\n    }\n\n    /**\n     * Get the items in the collection that are not present in the given items, using the callback.\n     *\n     * @param  mixed  $items\n     * @param  callable  $callback\n     * @return static\n     */\n    public function diffUsing($items, callable $callback)\n    {\n        return new static(array_udiff($this->items, $this->getArrayableItems($items), $callback));\n    }\n\n    /**\n     * Get the items in the collection whose keys and values are not present in the given items.\n     *\n     * @param  mixed  $items\n     * @return static\n     */\n    public function diffAssoc($items)\n    {\n        return new static(array_diff_assoc($this->items, $this->getArrayableItems($items)));\n    }\n\n    /**\n     * Get the items in the collection whose keys and values are not present in the given items, using the callback.\n     *\n     * @param  mixed  $items\n     * @param  callable  $callback\n     * @return static\n     */\n    public function diffAssocUsing($items, callable $callback)\n    {\n        return new static(array_diff_uassoc($this->items, $this->getArrayableItems($items), $callback));\n    }\n\n    /**\n     * Get the items in the collection whose keys are not present in the given items.\n     *\n     * @param  mixed  $items\n     * @return static\n     */\n    public function diffKeys($items)\n    {\n        return new static(array_diff_key($this->items, $this->getArrayableItems($items)));\n    }\n\n    /**\n     * Get the items in the collection whose keys are not present in the given items, using the callback.\n     *\n     * @param  mixed  $items\n     * @param  callable  $callback\n     * @return static\n     */\n    public function diffKeysUsing($items, callable $callback)\n    {\n        return new static(array_diff_ukey($this->items, $this->getArrayableItems($items), $callback));\n    }\n\n    /**\n     * Retrieve duplicate items from the collection.\n     *\n     * @param  callable|string|null  $callback\n     * @param  bool  $strict\n     * @return static\n     */\n    public function duplicates($callback = null, $strict = false)\n    {\n        $items = $this->map($this->valueRetriever($callback));\n\n        $uniqueItems = $items->unique(null, $strict);\n\n        $compare = $this->duplicateComparator($strict);\n\n        $duplicates = new static;\n\n        foreach ($items as $key => $value) {\n            if ($uniqueItems->isNotEmpty() && $compare($value, $uniqueItems->first())) {\n                $uniqueItems->shift();\n            } else {\n                $duplicates[$key] = $value;\n            }\n        }\n\n        return $duplicates;\n    }\n\n    /**\n     * Retrieve duplicate items from the collection using strict comparison.\n     *\n     * @param  callable|string|null  $callback\n     * @return static\n     */\n    public function duplicatesStrict($callback = null)\n    {\n        return $this->duplicates($callback, true);\n    }\n\n    /**\n     * Get the comparison function to detect duplicates.\n     *\n     * @param  bool  $strict\n     * @return \\Closure\n     */\n    protected function duplicateComparator($strict)\n    {\n        if ($strict) {\n            return function ($a, $b) {\n                return $a === $b;\n            };\n        }\n\n        return function ($a, $b) {\n            return $a == $b;\n        };\n    }\n\n    /**\n     * Get all items except for those with the specified keys.\n     *\n     * @param  \\Illuminate\\Support\\Collection|mixed  $keys\n     * @return static\n     */\n    public function except($keys)\n    {\n        if ($keys instanceof Enumerable) {\n            $keys = $keys->all();\n        } elseif (! is_array($keys)) {\n            $keys = func_get_args();\n        }\n\n        return new static(Arr::except($this->items, $keys));\n    }\n\n    /**\n     * Run a filter over each of the items.\n     *\n     * @param  callable|null  $callback\n     * @return static\n     */\n    public function filter(callable $callback = null)\n    {\n        if ($callback) {\n            return new static(Arr::where($this->items, $callback));\n        }\n\n        return new static(array_filter($this->items));\n    }\n\n    /**\n     * Get the first item from the collection passing the given truth test.\n     *\n     * @param  callable|null  $callback\n     * @param  mixed  $default\n     * @return mixed\n     */\n    public function first(callable $callback = null, $default = null)\n    {\n        return Arr::first($this->items, $callback, $default);\n    }\n\n    /**\n     * Get a flattened array of the items in the collection.\n     *\n     * @param  int  $depth\n     * @return static\n     */\n    public function flatten($depth = INF)\n    {\n        return new static(Arr::flatten($this->items, $depth));\n    }\n\n    /**\n     * Flip the items in the collection.\n     *\n     * @return static\n     */\n    public function flip()\n    {\n        return new static(array_flip($this->items));\n    }\n\n    /**\n     * Remove an item from the collection by key.\n     *\n     * @param  string|int|array  $keys\n     * @return $this\n     */\n    public function forget($keys)\n    {\n        foreach ((array) $keys as $key) {\n            $this->offsetUnset($key);\n        }\n\n        return $this;\n    }\n\n    /**\n     * Get an item from the collection by key.\n     *\n     * @param  mixed  $key\n     * @param  mixed  $default\n     * @return mixed\n     */\n    public function get($key, $default = null)\n    {\n        if (array_key_exists($key, $this->items)) {\n            return $this->items[$key];\n        }\n\n        return value($default);\n    }\n\n    /**\n     * Get an item from the collection by key or add it to collection if it does not exist.\n     *\n     * @param  mixed  $key\n     * @param  mixed  $value\n     * @return mixed\n     */\n    public function getOrPut($key, $value)\n    {\n        if (array_key_exists($key, $this->items)) {\n            return $this->items[$key];\n        }\n\n        $this->offsetSet($key, $value = value($value));\n\n        return $value;\n    }\n\n    /**\n     * Group an associative array by a field or using a callback.\n     *\n     * @param  array|callable|string  $groupBy\n     * @param  bool  $preserveKeys\n     * @return static\n     */\n    public function groupBy($groupBy, $preserveKeys = false)\n    {\n        if (! $this->useAsCallable($groupBy) && is_array($groupBy)) {\n            $nextGroups = $groupBy;\n\n            $groupBy = array_shift($nextGroups);\n        }\n\n        $groupBy = $this->valueRetriever($groupBy);\n\n        $results = [];\n\n        foreach ($this->items as $key => $value) {\n            $groupKeys = $groupBy($value, $key);\n\n            if (! is_array($groupKeys)) {\n                $groupKeys = [$groupKeys];\n            }\n\n            foreach ($groupKeys as $groupKey) {\n                $groupKey = is_bool($groupKey) ? (int) $groupKey : $groupKey;\n\n                if (! array_key_exists($groupKey, $results)) {\n                    $results[$groupKey] = new static;\n                }\n\n                $results[$groupKey]->offsetSet($preserveKeys ? $key : null, $value);\n            }\n        }\n\n        $result = new static($results);\n\n        if (! empty($nextGroups)) {\n            return $result->map->groupBy($nextGroups, $preserveKeys);\n        }\n\n        return $result;\n    }\n\n    /**\n     * Key an associative array by a field or using a callback.\n     *\n     * @param  callable|string  $keyBy\n     * @return static\n     */\n    public function keyBy($keyBy)\n    {\n        $keyBy = $this->valueRetriever($keyBy);\n\n        $results = [];\n\n        foreach ($this->items as $key => $item) {\n            $resolvedKey = $keyBy($item, $key);\n\n            if (is_object($resolvedKey)) {\n                $resolvedKey = (string) $resolvedKey;\n            }\n\n            $results[$resolvedKey] = $item;\n        }\n\n        return new static($results);\n    }\n\n    /**\n     * Determine if an item exists in the collection by key.\n     *\n     * @param  mixed  $key\n     * @return bool\n     */\n    public function has($key)\n    {\n        $keys = is_array($key) ? $key : func_get_args();\n\n        foreach ($keys as $value) {\n            if (! array_key_exists($value, $this->items)) {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    /**\n     * Determine if any of the keys exist in the collection.\n     *\n     * @param  mixed  $key\n     * @return bool\n     */\n    public function hasAny($key)\n    {\n        if ($this->isEmpty()) {\n            return false;\n        }\n\n        $keys = is_array($key) ? $key : func_get_args();\n\n        foreach ($keys as $value) {\n            if ($this->has($value)) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * Concatenate values of a given key as a string.\n     *\n     * @param  string  $value\n     * @param  string|null  $glue\n     * @return string\n     */\n    public function implode($value, $glue = null)\n    {\n        $first = $this->first();\n\n        if (is_array($first) || (is_object($first) && ! $first instanceof Stringable)) {\n            return implode($glue ?? '', $this->pluck($value)->all());\n        }\n\n        return implode($value ?? '', $this->items);\n    }\n\n    /**\n     * Intersect the collection with the given items.\n     *\n     * @param  mixed  $items\n     * @return static\n     */\n    public function intersect($items)\n    {\n        return new static(array_intersect($this->items, $this->getArrayableItems($items)));\n    }\n\n    /**\n     * Intersect the collection with the given items by key.\n     *\n     * @param  mixed  $items\n     * @return static\n     */\n    public function intersectByKeys($items)\n    {\n        return new static(array_intersect_key(\n            $this->items, $this->getArrayableItems($items)\n        ));\n    }\n\n    /**\n     * Determine if the collection is empty or not.\n     *\n     * @return bool\n     */\n    public function isEmpty()\n    {\n        return empty($this->items);\n    }\n\n    /**\n     * Determine if the collection contains a single item.\n     *\n     * @return bool\n     */\n    public function containsOneItem()\n    {\n        return $this->count() === 1;\n    }\n\n    /**\n     * Join all items from the collection using a string. The final items can use a separate glue string.\n     *\n     * @param  string  $glue\n     * @param  string  $finalGlue\n     * @return string\n     */\n    public function join($glue, $finalGlue = '')\n    {\n        if ($finalGlue === '') {\n            return $this->implode($glue);\n        }\n\n        $count = $this->count();\n\n        if ($count === 0) {\n            return '';\n        }\n\n        if ($count === 1) {\n            return $this->last();\n        }\n\n        $collection = new static($this->items);\n\n        $finalItem = $collection->pop();\n\n        return $collection->implode($glue).$finalGlue.$finalItem;\n    }\n\n    /**\n     * Get the keys of the collection items.\n     *\n     * @return static\n     */\n    public function keys()\n    {\n        return new static(array_keys($this->items));\n    }\n\n    /**\n     * Get the last item from the collection.\n     *\n     * @param  callable|null  $callback\n     * @param  mixed  $default\n     * @return mixed\n     */\n    public function last(callable $callback = null, $default = null)\n    {\n        return Arr::last($this->items, $callback, $default);\n    }\n\n    /**\n     * Get the values of a given key.\n     *\n     * @param  string|array|int|null  $value\n     * @param  string|null  $key\n     * @return static\n     */\n    public function pluck($value, $key = null)\n    {\n        return new static(Arr::pluck($this->items, $value, $key));\n    }\n\n    /**\n     * Run a map over each of the items.\n     *\n     * @param  callable  $callback\n     * @return static\n     */\n    public function map(callable $callback)\n    {\n        $keys = array_keys($this->items);\n\n        $items = array_map($callback, $this->items, $keys);\n\n        return new static(array_combine($keys, $items));\n    }\n\n    /**\n     * Run a dictionary map over the items.\n     *\n     * The callback should return an associative array with a single key/value pair.\n     *\n     * @param  callable  $callback\n     * @return static\n     */\n    public function mapToDictionary(callable $callback)\n    {\n        $dictionary = [];\n\n        foreach ($this->items as $key => $item) {\n            $pair = $callback($item, $key);\n\n            $key = key($pair);\n\n            $value = reset($pair);\n\n            if (! isset($dictionary[$key])) {\n                $dictionary[$key] = [];\n            }\n\n            $dictionary[$key][] = $value;\n        }\n\n        return new static($dictionary);\n    }\n\n    /**\n     * Run an associative map over each of the items.\n     *\n     * The callback should return an associative array with a single key/value pair.\n     *\n     * @param  callable  $callback\n     * @return static\n     */\n    public function mapWithKeys(callable $callback)\n    {\n        $result = [];\n\n        foreach ($this->items as $key => $value) {\n            $assoc = $callback($value, $key);\n\n            foreach ($assoc as $mapKey => $mapValue) {\n                $result[$mapKey] = $mapValue;\n            }\n        }\n\n        return new static($result);\n    }\n\n    /**\n     * Merge the collection with the given items.\n     *\n     * @param  mixed  $items\n     * @return static\n     */\n    public function merge($items)\n    {\n        return new static(array_merge($this->items, $this->getArrayableItems($items)));\n    }\n\n    /**\n     * Recursively merge the collection with the given items.\n     *\n     * @param  mixed  $items\n     * @return static\n     */\n    public function mergeRecursive($items)\n    {\n        return new static(array_merge_recursive($this->items, $this->getArrayableItems($items)));\n    }\n\n    /**\n     * Create a collection by using this collection for keys and another for its values.\n     *\n     * @param  mixed  $values\n     * @return static\n     */\n    public function combine($values)\n    {\n        return new static(array_combine($this->all(), $this->getArrayableItems($values)));\n    }\n\n    /**\n     * Union the collection with the given items.\n     *\n     * @param  mixed  $items\n     * @return static\n     */\n    public function union($items)\n    {\n        return new static($this->items + $this->getArrayableItems($items));\n    }\n\n    /**\n     * Create a new collection consisting of every n-th element.\n     *\n     * @param  int  $step\n     * @param  int  $offset\n     * @return static\n     */\n    public function nth($step, $offset = 0)\n    {\n        $new = [];\n\n        $position = 0;\n\n        foreach ($this->slice($offset)->items as $item) {\n            if ($position % $step === 0) {\n                $new[] = $item;\n            }\n\n            $position++;\n        }\n\n        return new static($new);\n    }\n\n    /**\n     * Get the items with the specified keys.\n     *\n     * @param  mixed  $keys\n     * @return static\n     */\n    public function only($keys)\n    {\n        if (is_null($keys)) {\n            return new static($this->items);\n        }\n\n        if ($keys instanceof Enumerable) {\n            $keys = $keys->all();\n        }\n\n        $keys = is_array($keys) ? $keys : func_get_args();\n\n        return new static(Arr::only($this->items, $keys));\n    }\n\n    /**\n     * Get and remove the last N items from the collection.\n     *\n     * @param  int  $count\n     * @return mixed\n     */\n    public function pop($count = 1)\n    {\n        if ($count === 1) {\n            return array_pop($this->items);\n        }\n\n        if ($this->isEmpty()) {\n            return new static;\n        }\n\n        $results = [];\n\n        $collectionCount = $this->count();\n\n        foreach (range(1, min($count, $collectionCount)) as $item) {\n            array_push($results, array_pop($this->items));\n        }\n\n        return new static($results);\n    }\n\n    /**\n     * Push an item onto the beginning of the collection.\n     *\n     * @param  mixed  $value\n     * @param  mixed  $key\n     * @return $this\n     */\n    public function prepend($value, $key = null)\n    {\n        $this->items = Arr::prepend($this->items, ...func_get_args());\n\n        return $this;\n    }\n\n    /**\n     * Push one or more items onto the end of the collection.\n     *\n     * @param  mixed  $values\n     * @return $this\n     */\n    public function push(...$values)\n    {\n        foreach ($values as $value) {\n            $this->items[] = $value;\n        }\n\n        return $this;\n    }\n\n    /**\n     * Push all of the given items onto the collection.\n     *\n     * @param  iterable  $source\n     * @return static\n     */\n    public function concat($source)\n    {\n        $result = new static($this);\n\n        foreach ($source as $item) {\n            $result->push($item);\n        }\n\n        return $result;\n    }\n\n    /**\n     * Get and remove an item from the collection.\n     *\n     * @param  mixed  $key\n     * @param  mixed  $default\n     * @return mixed\n     */\n    public function pull($key, $default = null)\n    {\n        return Arr::pull($this->items, $key, $default);\n    }\n\n    /**\n     * Put an item in the collection by key.\n     *\n     * @param  mixed  $key\n     * @param  mixed  $value\n     * @return $this\n     */\n    public function put($key, $value)\n    {\n        $this->offsetSet($key, $value);\n\n        return $this;\n    }\n\n    /**\n     * Get one or a specified number of items randomly from the collection.\n     *\n     * @param  int|null  $number\n     * @return static|mixed\n     *\n     * @throws \\InvalidArgumentException\n     */\n    public function random($number = null)\n    {\n        if (is_null($number)) {\n            return Arr::random($this->items);\n        }\n\n        return new static(Arr::random($this->items, $number));\n    }\n\n    /**\n     * Replace the collection items with the given items.\n     *\n     * @param  mixed  $items\n     * @return static\n     */\n    public function replace($items)\n    {\n        return new static(array_replace($this->items, $this->getArrayableItems($items)));\n    }\n\n    /**\n     * Recursively replace the collection items with the given items.\n     *\n     * @param  mixed  $items\n     * @return static\n     */\n    public function replaceRecursive($items)\n    {\n        return new static(array_replace_recursive($this->items, $this->getArrayableItems($items)));\n    }\n\n    /**\n     * Reverse items order.\n     *\n     * @return static\n     */\n    public function reverse()\n    {\n        return new static(array_reverse($this->items, true));\n    }\n\n    /**\n     * Search the collection for a given value and return the corresponding key if successful.\n     *\n     * @param  mixed  $value\n     * @param  bool  $strict\n     * @return mixed\n     */\n    public function search($value, $strict = false)\n    {\n        if (! $this->useAsCallable($value)) {\n            return array_search($value, $this->items, $strict);\n        }\n\n        foreach ($this->items as $key => $item) {\n            if ($value($item, $key)) {\n                return $key;\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * Get and remove the first N items from the collection.\n     *\n     * @param  int  $count\n     * @return mixed\n     */\n    public function shift($count = 1)\n    {\n        if ($count === 1) {\n            return array_shift($this->items);\n        }\n\n        if ($this->isEmpty()) {\n            return new static;\n        }\n\n        $results = [];\n\n        $collectionCount = $this->count();\n\n        foreach (range(1, min($count, $collectionCount)) as $item) {\n            array_push($results, array_shift($this->items));\n        }\n\n        return new static($results);\n    }\n\n    /**\n     * Shuffle the items in the collection.\n     *\n     * @param  int|null  $seed\n     * @return static\n     */\n    public function shuffle($seed = null)\n    {\n        return new static(Arr::shuffle($this->items, $seed));\n    }\n\n    /**\n     * Create chunks representing a \"sliding window\" view of the items in the collection.\n     *\n     * @param  int  $size\n     * @param  int  $step\n     * @return static\n     */\n    public function sliding($size = 2, $step = 1)\n    {\n        $chunks = floor(($this->count() - $size) / $step) + 1;\n\n        return static::times($chunks, function ($number) use ($size, $step) {\n            return $this->slice(($number - 1) * $step, $size);\n        });\n    }\n\n    /**\n     * Skip the first {$count} items.\n     *\n     * @param  int  $count\n     * @return static\n     */\n    public function skip($count)\n    {\n        return $this->slice($count);\n    }\n\n    /**\n     * Skip items in the collection until the given condition is met.\n     *\n     * @param  mixed  $value\n     * @return static\n     */\n    public function skipUntil($value)\n    {\n        return new static($this->lazy()->skipUntil($value)->all());\n    }\n\n    /**\n     * Skip items in the collection while the given condition is met.\n     *\n     * @param  mixed  $value\n     * @return static\n     */\n    public function skipWhile($value)\n    {\n        return new static($this->lazy()->skipWhile($value)->all());\n    }\n\n    /**\n     * Slice the underlying collection array.\n     *\n     * @param  int  $offset\n     * @param  int|null  $length\n     * @return static\n     */\n    public function slice($offset, $length = null)\n    {\n        return new static(array_slice($this->items, $offset, $length, true));\n    }\n\n    /**\n     * Split a collection into a certain number of groups.\n     *\n     * @param  int  $numberOfGroups\n     * @return static\n     */\n    public function split($numberOfGroups)\n    {\n        if ($this->isEmpty()) {\n            return new static;\n        }\n\n        $groups = new static;\n\n        $groupSize = floor($this->count() / $numberOfGroups);\n\n        $remain = $this->count() % $numberOfGroups;\n\n        $start = 0;\n\n        for ($i = 0; $i < $numberOfGroups; $i++) {\n            $size = $groupSize;\n\n            if ($i < $remain) {\n                $size++;\n            }\n\n            if ($size) {\n                $groups->push(new static(array_slice($this->items, $start, $size)));\n\n                $start += $size;\n            }\n        }\n\n        return $groups;\n    }\n\n    /**\n     * Split a collection into a certain number of groups, and fill the first groups completely.\n     *\n     * @param  int  $numberOfGroups\n     * @return static\n     */\n    public function splitIn($numberOfGroups)\n    {\n        return $this->chunk(ceil($this->count() / $numberOfGroups));\n    }\n\n    /**\n     * Get the first item in the collection, but only if exactly one item exists. Otherwise, throw an exception.\n     *\n     * @param  mixed  $key\n     * @param  mixed  $operator\n     * @param  mixed  $value\n     * @return mixed\n     *\n     * @throws \\Illuminate\\Support\\ItemNotFoundException\n     * @throws \\Illuminate\\Support\\MultipleItemsFoundException\n     */\n    public function sole($key = null, $operator = null, $value = null)\n    {\n        $filter = func_num_args() > 1\n            ? $this->operatorForWhere(...func_get_args())\n            : $key;\n\n        $items = $this->when($filter)->filter($filter);\n\n        if ($items->isEmpty()) {\n            throw new ItemNotFoundException;\n        }\n\n        if ($items->count() > 1) {\n            throw new MultipleItemsFoundException;\n        }\n\n        return $items->first();\n    }\n\n    /**\n     * Get the first item in the collection but throw an exception if no matching items exist.\n     *\n     * @param  mixed  $key\n     * @param  mixed  $operator\n     * @param  mixed  $value\n     * @return mixed\n     *\n     * @throws \\Illuminate\\Support\\ItemNotFoundException\n     */\n    public function firstOrFail($key = null, $operator = null, $value = null)\n    {\n        $filter = func_num_args() > 1\n            ? $this->operatorForWhere(...func_get_args())\n            : $key;\n\n        $placeholder = new stdClass();\n\n        $item = $this->first($filter, $placeholder);\n\n        if ($item === $placeholder) {\n            throw new ItemNotFoundException;\n        }\n\n        return $item;\n    }\n\n    /**\n     * Chunk the collection into chunks of the given size.\n     *\n     * @param  int  $size\n     * @return static\n     */\n    public function chunk($size)\n    {\n        if ($size <= 0) {\n            return new static;\n        }\n\n        $chunks = [];\n\n        foreach (array_chunk($this->items, $size, true) as $chunk) {\n            $chunks[] = new static($chunk);\n        }\n\n        return new static($chunks);\n    }\n\n    /**\n     * Chunk the collection into chunks with a callback.\n     *\n     * @param  callable  $callback\n     * @return static\n     */\n    public function chunkWhile(callable $callback)\n    {\n        return new static(\n            $this->lazy()->chunkWhile($callback)->mapInto(static::class)\n        );\n    }\n\n    /**\n     * Sort through each item with a callback.\n     *\n     * @param  callable|int|null  $callback\n     * @return static\n     */\n    public function sort($callback = null)\n    {\n        $items = $this->items;\n\n        $callback && is_callable($callback)\n            ? uasort($items, $callback)\n            : asort($items, $callback ?? SORT_REGULAR);\n\n        return new static($items);\n    }\n\n    /**\n     * Sort items in descending order.\n     *\n     * @param  int  $options\n     * @return static\n     */\n    public function sortDesc($options = SORT_REGULAR)\n    {\n        $items = $this->items;\n\n        arsort($items, $options);\n\n        return new static($items);\n    }\n\n    /**\n     * Sort the collection using the given callback.\n     *\n     * @param  callable|array|string  $callback\n     * @param  int  $options\n     * @param  bool  $descending\n     * @return static\n     */\n    public function sortBy($callback, $options = SORT_REGULAR, $descending = false)\n    {\n        if (is_array($callback) && ! is_callable($callback)) {\n            return $this->sortByMany($callback);\n        }\n\n        $results = [];\n\n        $callback = $this->valueRetriever($callback);\n\n        // First we will loop through the items and get the comparator from a callback\n        // function which we were given. Then, we will sort the returned values and\n        // grab all the corresponding values for the sorted keys from this array.\n        foreach ($this->items as $key => $value) {\n            $results[$key] = $callback($value, $key);\n        }\n\n        $descending ? arsort($results, $options)\n            : asort($results, $options);\n\n        // Once we have sorted all of the keys in the array, we will loop through them\n        // and grab the corresponding model so we can set the underlying items list\n        // to the sorted version. Then we'll just return the collection instance.\n        foreach (array_keys($results) as $key) {\n            $results[$key] = $this->items[$key];\n        }\n\n        return new static($results);\n    }\n\n    /**\n     * Sort the collection using multiple comparisons.\n     *\n     * @param  array  $comparisons\n     * @return static\n     */\n    protected function sortByMany(array $comparisons = [])\n    {\n        $items = $this->items;\n\n        usort($items, function ($a, $b) use ($comparisons) {\n            foreach ($comparisons as $comparison) {\n                $comparison = Arr::wrap($comparison);\n\n                $prop = $comparison[0];\n\n                $ascending = Arr::get($comparison, 1, true) === true ||\n                             Arr::get($comparison, 1, true) === 'asc';\n\n                $result = 0;\n\n                if (! is_string($prop) && is_callable($prop)) {\n                    $result = $prop($a, $b);\n                } else {\n                    $values = [data_get($a, $prop), data_get($b, $prop)];\n\n                    if (! $ascending) {\n                        $values = array_reverse($values);\n                    }\n\n                    $result = $values[0] <=> $values[1];\n                }\n\n                if ($result === 0) {\n                    continue;\n                }\n\n                return $result;\n            }\n        });\n\n        return new static($items);\n    }\n\n    /**\n     * Sort the collection in descending order using the given callback.\n     *\n     * @param  callable|string  $callback\n     * @param  int  $options\n     * @return static\n     */\n    public function sortByDesc($callback, $options = SORT_REGULAR)\n    {\n        return $this->sortBy($callback, $options, true);\n    }\n\n    /**\n     * Sort the collection keys.\n     *\n     * @param  int  $options\n     * @param  bool  $descending\n     * @return static\n     */\n    public function sortKeys($options = SORT_REGULAR, $descending = false)\n    {\n        $items = $this->items;\n\n        $descending ? krsort($items, $options) : ksort($items, $options);\n\n        return new static($items);\n    }\n\n    /**\n     * Sort the collection keys in descending order.\n     *\n     * @param  int  $options\n     * @return static\n     */\n    public function sortKeysDesc($options = SORT_REGULAR)\n    {\n        return $this->sortKeys($options, true);\n    }\n\n    /**\n     * Sort the collection keys using a callback.\n     *\n     * @param  callable  $callback\n     * @return static\n     */\n    public function sortKeysUsing(callable $callback)\n    {\n        $items = $this->items;\n\n        uksort($items, $callback);\n\n        return new static($items);\n    }\n\n    /**\n     * Splice a portion of the underlying collection array.\n     *\n     * @param  int  $offset\n     * @param  int|null  $length\n     * @param  mixed  $replacement\n     * @return static\n     */\n    public function splice($offset, $length = null, $replacement = [])\n    {\n        if (func_num_args() === 1) {\n            return new static(array_splice($this->items, $offset));\n        }\n\n        return new static(array_splice($this->items, $offset, $length, $this->getArrayableItems($replacement)));\n    }\n\n    /**\n     * Take the first or last {$limit} items.\n     *\n     * @param  int  $limit\n     * @return static\n     */\n    public function take($limit)\n    {\n        if ($limit < 0) {\n            return $this->slice($limit, abs($limit));\n        }\n\n        return $this->slice(0, $limit);\n    }\n\n    /**\n     * Take items in the collection until the given condition is met.\n     *\n     * @param  mixed  $value\n     * @return static\n     */\n    public function takeUntil($value)\n    {\n        return new static($this->lazy()->takeUntil($value)->all());\n    }\n\n    /**\n     * Take items in the collection while the given condition is met.\n     *\n     * @param  mixed  $value\n     * @return static\n     */\n    public function takeWhile($value)\n    {\n        return new static($this->lazy()->takeWhile($value)->all());\n    }\n\n    /**\n     * Transform each item in the collection using a callback.\n     *\n     * @param  callable  $callback\n     * @return $this\n     */\n    public function transform(callable $callback)\n    {\n        $this->items = $this->map($callback)->all();\n\n        return $this;\n    }\n\n    /**\n     * Convert a flatten \"dot\" notation array into an expanded array.\n     *\n     * @return static\n     */\n    public function undot()\n    {\n        return new static(Arr::undot($this->all()));\n    }\n\n    /**\n     * Return only unique items from the collection array.\n     *\n     * @param  string|callable|null  $key\n     * @param  bool  $strict\n     * @return static\n     */\n    public function unique($key = null, $strict = false)\n    {\n        if (is_null($key) && $strict === false) {\n            return new static(array_unique($this->items, SORT_REGULAR));\n        }\n\n        $callback = $this->valueRetriever($key);\n\n        $exists = [];\n\n        return $this->reject(function ($item, $key) use ($callback, $strict, &$exists) {\n            if (in_array($id = $callback($item, $key), $exists, $strict)) {\n                return true;\n            }\n\n            $exists[] = $id;\n        });\n    }\n\n    /**\n     * Reset the keys on the underlying array.\n     *\n     * @return static\n     */\n    public function values()\n    {\n        return new static(array_values($this->items));\n    }\n\n    /**\n     * Zip the collection together with one or more arrays.\n     *\n     * e.g. new Collection([1, 2, 3])->zip([4, 5, 6]);\n     *      => [[1, 4], [2, 5], [3, 6]]\n     *\n     * @param  mixed  ...$items\n     * @return static\n     */\n    public function zip($items)\n    {\n        $arrayableItems = array_map(function ($items) {\n            return $this->getArrayableItems($items);\n        }, func_get_args());\n\n        $params = array_merge([function () {\n            return new static(func_get_args());\n        }, $this->items], $arrayableItems);\n\n        return new static(array_map(...$params));\n    }\n\n    /**\n     * Pad collection to the specified length with a value.\n     *\n     * @param  int  $size\n     * @param  mixed  $value\n     * @return static\n     */\n    public function pad($size, $value)\n    {\n        return new static(array_pad($this->items, $size, $value));\n    }\n\n    /**\n     * Get an iterator for the items.\n     *\n     * @return \\ArrayIterator\n     */\n    #[\\ReturnTypeWillChange]\n    public function getIterator()\n    {\n        return new ArrayIterator($this->items);\n    }\n\n    /**\n     * Count the number of items in the collection.\n     *\n     * @return int\n     */\n    #[\\ReturnTypeWillChange]\n    public function count()\n    {\n        return count($this->items);\n    }\n\n    /**\n     * Count the number of items in the collection by a field or using a callback.\n     *\n     * @param  callable|string  $countBy\n     * @return static\n     */\n    public function countBy($countBy = null)\n    {\n        return new static($this->lazy()->countBy($countBy)->all());\n    }\n\n    /**\n     * Add an item to the collection.\n     *\n     * @param  mixed  $item\n     * @return $this\n     */\n    public function add($item)\n    {\n        $this->items[] = $item;\n\n        return $this;\n    }\n\n    /**\n     * Get a base Support collection instance from this collection.\n     *\n     * @return \\Illuminate\\Support\\Collection\n     */\n    public function toBase()\n    {\n        return new self($this);\n    }\n\n    /**\n     * Determine if an item exists at an offset.\n     *\n     * @param  mixed  $key\n     * @return bool\n     */\n    #[\\ReturnTypeWillChange]\n    public function offsetExists($key)\n    {\n        return isset($this->items[$key]);\n    }\n\n    /**\n     * Get an item at a given offset.\n     *\n     * @param  mixed  $key\n     * @return mixed\n     */\n    #[\\ReturnTypeWillChange]\n    public function offsetGet($key)\n    {\n        return $this->items[$key];\n    }\n\n    /**\n     * Set the item at a given offset.\n     *\n     * @param  mixed  $key\n     * @param  mixed  $value\n     * @return void\n     */\n    #[\\ReturnTypeWillChange]\n    public function offsetSet($key, $value)\n    {\n        if (is_null($key)) {\n            $this->items[] = $value;\n        } else {\n            $this->items[$key] = $value;\n        }\n    }\n\n    /**\n     * Unset the item at a given offset.\n     *\n     * @param  mixed  $key\n     * @return void\n     */\n    #[\\ReturnTypeWillChange]\n    public function offsetUnset($key)\n    {\n        unset($this->items[$key]);\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/collections/Enumerable.php",
    "content": "<?php\n\nnamespace Illuminate\\Support;\n\nuse Countable;\nuse Illuminate\\Contracts\\Support\\Arrayable;\nuse Illuminate\\Contracts\\Support\\Jsonable;\nuse IteratorAggregate;\nuse JsonSerializable;\n\ninterface Enumerable extends Arrayable, Countable, IteratorAggregate, Jsonable, JsonSerializable\n{\n    /**\n     * Create a new collection instance if the value isn't one already.\n     *\n     * @param  mixed  $items\n     * @return static\n     */\n    public static function make($items = []);\n\n    /**\n     * Create a new instance by invoking the callback a given amount of times.\n     *\n     * @param  int  $number\n     * @param  callable|null  $callback\n     * @return static\n     */\n    public static function times($number, callable $callback = null);\n\n    /**\n     * Create a collection with the given range.\n     *\n     * @param  int  $from\n     * @param  int  $to\n     * @return static\n     */\n    public static function range($from, $to);\n\n    /**\n     * Wrap the given value in a collection if applicable.\n     *\n     * @param  mixed  $value\n     * @return static\n     */\n    public static function wrap($value);\n\n    /**\n     * Get the underlying items from the given collection if applicable.\n     *\n     * @param  array|static  $value\n     * @return array\n     */\n    public static function unwrap($value);\n\n    /**\n     * Create a new instance with no items.\n     *\n     * @return static\n     */\n    public static function empty();\n\n    /**\n     * Get all items in the enumerable.\n     *\n     * @return array\n     */\n    public function all();\n\n    /**\n     * Alias for the \"avg\" method.\n     *\n     * @param  callable|string|null  $callback\n     * @return mixed\n     */\n    public function average($callback = null);\n\n    /**\n     * Get the median of a given key.\n     *\n     * @param  string|array|null  $key\n     * @return mixed\n     */\n    public function median($key = null);\n\n    /**\n     * Get the mode of a given key.\n     *\n     * @param  string|array|null  $key\n     * @return array|null\n     */\n    public function mode($key = null);\n\n    /**\n     * Collapse the items into a single enumerable.\n     *\n     * @return static\n     */\n    public function collapse();\n\n    /**\n     * Alias for the \"contains\" method.\n     *\n     * @param  mixed  $key\n     * @param  mixed  $operator\n     * @param  mixed  $value\n     * @return bool\n     */\n    public function some($key, $operator = null, $value = null);\n\n    /**\n     * Determine if an item exists, using strict comparison.\n     *\n     * @param  mixed  $key\n     * @param  mixed  $value\n     * @return bool\n     */\n    public function containsStrict($key, $value = null);\n\n    /**\n     * Get the average value of a given key.\n     *\n     * @param  callable|string|null  $callback\n     * @return mixed\n     */\n    public function avg($callback = null);\n\n    /**\n     * Determine if an item exists in the enumerable.\n     *\n     * @param  mixed  $key\n     * @param  mixed  $operator\n     * @param  mixed  $value\n     * @return bool\n     */\n    public function contains($key, $operator = null, $value = null);\n\n    /**\n     * Cross join with the given lists, returning all possible permutations.\n     *\n     * @param  mixed  ...$lists\n     * @return static\n     */\n    public function crossJoin(...$lists);\n\n    /**\n     * Dump the collection and end the script.\n     *\n     * @param  mixed  ...$args\n     * @return void\n     */\n    public function dd(...$args);\n\n    /**\n     * Dump the collection.\n     *\n     * @return $this\n     */\n    public function dump();\n\n    /**\n     * Get the items that are not present in the given items.\n     *\n     * @param  mixed  $items\n     * @return static\n     */\n    public function diff($items);\n\n    /**\n     * Get the items that are not present in the given items, using the callback.\n     *\n     * @param  mixed  $items\n     * @param  callable  $callback\n     * @return static\n     */\n    public function diffUsing($items, callable $callback);\n\n    /**\n     * Get the items whose keys and values are not present in the given items.\n     *\n     * @param  mixed  $items\n     * @return static\n     */\n    public function diffAssoc($items);\n\n    /**\n     * Get the items whose keys and values are not present in the given items, using the callback.\n     *\n     * @param  mixed  $items\n     * @param  callable  $callback\n     * @return static\n     */\n    public function diffAssocUsing($items, callable $callback);\n\n    /**\n     * Get the items whose keys are not present in the given items.\n     *\n     * @param  mixed  $items\n     * @return static\n     */\n    public function diffKeys($items);\n\n    /**\n     * Get the items whose keys are not present in the given items, using the callback.\n     *\n     * @param  mixed  $items\n     * @param  callable  $callback\n     * @return static\n     */\n    public function diffKeysUsing($items, callable $callback);\n\n    /**\n     * Retrieve duplicate items.\n     *\n     * @param  callable|string|null  $callback\n     * @param  bool  $strict\n     * @return static\n     */\n    public function duplicates($callback = null, $strict = false);\n\n    /**\n     * Retrieve duplicate items using strict comparison.\n     *\n     * @param  callable|string|null  $callback\n     * @return static\n     */\n    public function duplicatesStrict($callback = null);\n\n    /**\n     * Execute a callback over each item.\n     *\n     * @param  callable  $callback\n     * @return $this\n     */\n    public function each(callable $callback);\n\n    /**\n     * Execute a callback over each nested chunk of items.\n     *\n     * @param  callable  $callback\n     * @return static\n     */\n    public function eachSpread(callable $callback);\n\n    /**\n     * Determine if all items pass the given truth test.\n     *\n     * @param  string|callable  $key\n     * @param  mixed  $operator\n     * @param  mixed  $value\n     * @return bool\n     */\n    public function every($key, $operator = null, $value = null);\n\n    /**\n     * Get all items except for those with the specified keys.\n     *\n     * @param  mixed  $keys\n     * @return static\n     */\n    public function except($keys);\n\n    /**\n     * Run a filter over each of the items.\n     *\n     * @param  callable|null  $callback\n     * @return static\n     */\n    public function filter(callable $callback = null);\n\n    /**\n     * Apply the callback if the value is truthy.\n     *\n     * @param  bool  $value\n     * @param  callable  $callback\n     * @param  callable|null  $default\n     * @return static|mixed\n     */\n    public function when($value, callable $callback, callable $default = null);\n\n    /**\n     * Apply the callback if the collection is empty.\n     *\n     * @param  callable  $callback\n     * @param  callable|null  $default\n     * @return static|mixed\n     */\n    public function whenEmpty(callable $callback, callable $default = null);\n\n    /**\n     * Apply the callback if the collection is not empty.\n     *\n     * @param  callable  $callback\n     * @param  callable|null  $default\n     * @return static|mixed\n     */\n    public function whenNotEmpty(callable $callback, callable $default = null);\n\n    /**\n     * Apply the callback if the value is falsy.\n     *\n     * @param  bool  $value\n     * @param  callable  $callback\n     * @param  callable|null  $default\n     * @return static|mixed\n     */\n    public function unless($value, callable $callback, callable $default = null);\n\n    /**\n     * Apply the callback unless the collection is empty.\n     *\n     * @param  callable  $callback\n     * @param  callable|null  $default\n     * @return static|mixed\n     */\n    public function unlessEmpty(callable $callback, callable $default = null);\n\n    /**\n     * Apply the callback unless the collection is not empty.\n     *\n     * @param  callable  $callback\n     * @param  callable|null  $default\n     * @return static|mixed\n     */\n    public function unlessNotEmpty(callable $callback, callable $default = null);\n\n    /**\n     * Filter items by the given key value pair.\n     *\n     * @param  string  $key\n     * @param  mixed  $operator\n     * @param  mixed  $value\n     * @return static\n     */\n    public function where($key, $operator = null, $value = null);\n\n    /**\n     * Filter items where the value for the given key is null.\n     *\n     * @param  string|null  $key\n     * @return static\n     */\n    public function whereNull($key = null);\n\n    /**\n     * Filter items where the value for the given key is not null.\n     *\n     * @param  string|null  $key\n     * @return static\n     */\n    public function whereNotNull($key = null);\n\n    /**\n     * Filter items by the given key value pair using strict comparison.\n     *\n     * @param  string  $key\n     * @param  mixed  $value\n     * @return static\n     */\n    public function whereStrict($key, $value);\n\n    /**\n     * Filter items by the given key value pair.\n     *\n     * @param  string  $key\n     * @param  mixed  $values\n     * @param  bool  $strict\n     * @return static\n     */\n    public function whereIn($key, $values, $strict = false);\n\n    /**\n     * Filter items by the given key value pair using strict comparison.\n     *\n     * @param  string  $key\n     * @param  mixed  $values\n     * @return static\n     */\n    public function whereInStrict($key, $values);\n\n    /**\n     * Filter items such that the value of the given key is between the given values.\n     *\n     * @param  string  $key\n     * @param  array  $values\n     * @return static\n     */\n    public function whereBetween($key, $values);\n\n    /**\n     * Filter items such that the value of the given key is not between the given values.\n     *\n     * @param  string  $key\n     * @param  array  $values\n     * @return static\n     */\n    public function whereNotBetween($key, $values);\n\n    /**\n     * Filter items by the given key value pair.\n     *\n     * @param  string  $key\n     * @param  mixed  $values\n     * @param  bool  $strict\n     * @return static\n     */\n    public function whereNotIn($key, $values, $strict = false);\n\n    /**\n     * Filter items by the given key value pair using strict comparison.\n     *\n     * @param  string  $key\n     * @param  mixed  $values\n     * @return static\n     */\n    public function whereNotInStrict($key, $values);\n\n    /**\n     * Filter the items, removing any items that don't match the given type(s).\n     *\n     * @param  string|string[]  $type\n     * @return static\n     */\n    public function whereInstanceOf($type);\n\n    /**\n     * Get the first item from the enumerable passing the given truth test.\n     *\n     * @param  callable|null  $callback\n     * @param  mixed  $default\n     * @return mixed\n     */\n    public function first(callable $callback = null, $default = null);\n\n    /**\n     * Get the first item by the given key value pair.\n     *\n     * @param  string  $key\n     * @param  mixed  $operator\n     * @param  mixed  $value\n     * @return mixed\n     */\n    public function firstWhere($key, $operator = null, $value = null);\n\n    /**\n     * Get a flattened array of the items in the collection.\n     *\n     * @param  int  $depth\n     * @return static\n     */\n    public function flatten($depth = INF);\n\n    /**\n     * Flip the values with their keys.\n     *\n     * @return static\n     */\n    public function flip();\n\n    /**\n     * Get an item from the collection by key.\n     *\n     * @param  mixed  $key\n     * @param  mixed  $default\n     * @return mixed\n     */\n    public function get($key, $default = null);\n\n    /**\n     * Group an associative array by a field or using a callback.\n     *\n     * @param  array|callable|string  $groupBy\n     * @param  bool  $preserveKeys\n     * @return static\n     */\n    public function groupBy($groupBy, $preserveKeys = false);\n\n    /**\n     * Key an associative array by a field or using a callback.\n     *\n     * @param  callable|string  $keyBy\n     * @return static\n     */\n    public function keyBy($keyBy);\n\n    /**\n     * Determine if an item exists in the collection by key.\n     *\n     * @param  mixed  $key\n     * @return bool\n     */\n    public function has($key);\n\n    /**\n     * Concatenate values of a given key as a string.\n     *\n     * @param  string  $value\n     * @param  string|null  $glue\n     * @return string\n     */\n    public function implode($value, $glue = null);\n\n    /**\n     * Intersect the collection with the given items.\n     *\n     * @param  mixed  $items\n     * @return static\n     */\n    public function intersect($items);\n\n    /**\n     * Intersect the collection with the given items by key.\n     *\n     * @param  mixed  $items\n     * @return static\n     */\n    public function intersectByKeys($items);\n\n    /**\n     * Determine if the collection is empty or not.\n     *\n     * @return bool\n     */\n    public function isEmpty();\n\n    /**\n     * Determine if the collection is not empty.\n     *\n     * @return bool\n     */\n    public function isNotEmpty();\n\n    /**\n     * Join all items from the collection using a string. The final items can use a separate glue string.\n     *\n     * @param  string  $glue\n     * @param  string  $finalGlue\n     * @return string\n     */\n    public function join($glue, $finalGlue = '');\n\n    /**\n     * Get the keys of the collection items.\n     *\n     * @return static\n     */\n    public function keys();\n\n    /**\n     * Get the last item from the collection.\n     *\n     * @param  callable|null  $callback\n     * @param  mixed  $default\n     * @return mixed\n     */\n    public function last(callable $callback = null, $default = null);\n\n    /**\n     * Run a map over each of the items.\n     *\n     * @param  callable  $callback\n     * @return static\n     */\n    public function map(callable $callback);\n\n    /**\n     * Run a map over each nested chunk of items.\n     *\n     * @param  callable  $callback\n     * @return static\n     */\n    public function mapSpread(callable $callback);\n\n    /**\n     * Run a dictionary map over the items.\n     *\n     * The callback should return an associative array with a single key/value pair.\n     *\n     * @param  callable  $callback\n     * @return static\n     */\n    public function mapToDictionary(callable $callback);\n\n    /**\n     * Run a grouping map over the items.\n     *\n     * The callback should return an associative array with a single key/value pair.\n     *\n     * @param  callable  $callback\n     * @return static\n     */\n    public function mapToGroups(callable $callback);\n\n    /**\n     * Run an associative map over each of the items.\n     *\n     * The callback should return an associative array with a single key/value pair.\n     *\n     * @param  callable  $callback\n     * @return static\n     */\n    public function mapWithKeys(callable $callback);\n\n    /**\n     * Map a collection and flatten the result by a single level.\n     *\n     * @param  callable  $callback\n     * @return static\n     */\n    public function flatMap(callable $callback);\n\n    /**\n     * Map the values into a new class.\n     *\n     * @param  string  $class\n     * @return static\n     */\n    public function mapInto($class);\n\n    /**\n     * Merge the collection with the given items.\n     *\n     * @param  mixed  $items\n     * @return static\n     */\n    public function merge($items);\n\n    /**\n     * Recursively merge the collection with the given items.\n     *\n     * @param  mixed  $items\n     * @return static\n     */\n    public function mergeRecursive($items);\n\n    /**\n     * Create a collection by using this collection for keys and another for its values.\n     *\n     * @param  mixed  $values\n     * @return static\n     */\n    public function combine($values);\n\n    /**\n     * Union the collection with the given items.\n     *\n     * @param  mixed  $items\n     * @return static\n     */\n    public function union($items);\n\n    /**\n     * Get the min value of a given key.\n     *\n     * @param  callable|string|null  $callback\n     * @return mixed\n     */\n    public function min($callback = null);\n\n    /**\n     * Get the max value of a given key.\n     *\n     * @param  callable|string|null  $callback\n     * @return mixed\n     */\n    public function max($callback = null);\n\n    /**\n     * Create a new collection consisting of every n-th element.\n     *\n     * @param  int  $step\n     * @param  int  $offset\n     * @return static\n     */\n    public function nth($step, $offset = 0);\n\n    /**\n     * Get the items with the specified keys.\n     *\n     * @param  mixed  $keys\n     * @return static\n     */\n    public function only($keys);\n\n    /**\n     * \"Paginate\" the collection by slicing it into a smaller collection.\n     *\n     * @param  int  $page\n     * @param  int  $perPage\n     * @return static\n     */\n    public function forPage($page, $perPage);\n\n    /**\n     * Partition the collection into two arrays using the given callback or key.\n     *\n     * @param  callable|string  $key\n     * @param  mixed  $operator\n     * @param  mixed  $value\n     * @return static\n     */\n    public function partition($key, $operator = null, $value = null);\n\n    /**\n     * Push all of the given items onto the collection.\n     *\n     * @param  iterable  $source\n     * @return static\n     */\n    public function concat($source);\n\n    /**\n     * Get one or a specified number of items randomly from the collection.\n     *\n     * @param  int|null  $number\n     * @return static|mixed\n     *\n     * @throws \\InvalidArgumentException\n     */\n    public function random($number = null);\n\n    /**\n     * Reduce the collection to a single value.\n     *\n     * @param  callable  $callback\n     * @param  mixed  $initial\n     * @return mixed\n     */\n    public function reduce(callable $callback, $initial = null);\n\n    /**\n     * Replace the collection items with the given items.\n     *\n     * @param  mixed  $items\n     * @return static\n     */\n    public function replace($items);\n\n    /**\n     * Recursively replace the collection items with the given items.\n     *\n     * @param  mixed  $items\n     * @return static\n     */\n    public function replaceRecursive($items);\n\n    /**\n     * Reverse items order.\n     *\n     * @return static\n     */\n    public function reverse();\n\n    /**\n     * Search the collection for a given value and return the corresponding key if successful.\n     *\n     * @param  mixed  $value\n     * @param  bool  $strict\n     * @return mixed\n     */\n    public function search($value, $strict = false);\n\n    /**\n     * Shuffle the items in the collection.\n     *\n     * @param  int|null  $seed\n     * @return static\n     */\n    public function shuffle($seed = null);\n\n    /**\n     * Skip the first {$count} items.\n     *\n     * @param  int  $count\n     * @return static\n     */\n    public function skip($count);\n\n    /**\n     * Skip items in the collection until the given condition is met.\n     *\n     * @param  mixed  $value\n     * @return static\n     */\n    public function skipUntil($value);\n\n    /**\n     * Skip items in the collection while the given condition is met.\n     *\n     * @param  mixed  $value\n     * @return static\n     */\n    public function skipWhile($value);\n\n    /**\n     * Get a slice of items from the enumerable.\n     *\n     * @param  int  $offset\n     * @param  int|null  $length\n     * @return static\n     */\n    public function slice($offset, $length = null);\n\n    /**\n     * Split a collection into a certain number of groups.\n     *\n     * @param  int  $numberOfGroups\n     * @return static\n     */\n    public function split($numberOfGroups);\n\n    /**\n     * Chunk the collection into chunks of the given size.\n     *\n     * @param  int  $size\n     * @return static\n     */\n    public function chunk($size);\n\n    /**\n     * Chunk the collection into chunks with a callback.\n     *\n     * @param  callable  $callback\n     * @return static\n     */\n    public function chunkWhile(callable $callback);\n\n    /**\n     * Sort through each item with a callback.\n     *\n     * @param  callable|null|int  $callback\n     * @return static\n     */\n    public function sort($callback = null);\n\n    /**\n     * Sort items in descending order.\n     *\n     * @param  int  $options\n     * @return static\n     */\n    public function sortDesc($options = SORT_REGULAR);\n\n    /**\n     * Sort the collection using the given callback.\n     *\n     * @param  callable|string  $callback\n     * @param  int  $options\n     * @param  bool  $descending\n     * @return static\n     */\n    public function sortBy($callback, $options = SORT_REGULAR, $descending = false);\n\n    /**\n     * Sort the collection in descending order using the given callback.\n     *\n     * @param  callable|string  $callback\n     * @param  int  $options\n     * @return static\n     */\n    public function sortByDesc($callback, $options = SORT_REGULAR);\n\n    /**\n     * Sort the collection keys.\n     *\n     * @param  int  $options\n     * @param  bool  $descending\n     * @return static\n     */\n    public function sortKeys($options = SORT_REGULAR, $descending = false);\n\n    /**\n     * Sort the collection keys in descending order.\n     *\n     * @param  int  $options\n     * @return static\n     */\n    public function sortKeysDesc($options = SORT_REGULAR);\n\n    /**\n     * Get the sum of the given values.\n     *\n     * @param  callable|string|null  $callback\n     * @return mixed\n     */\n    public function sum($callback = null);\n\n    /**\n     * Take the first or last {$limit} items.\n     *\n     * @param  int  $limit\n     * @return static\n     */\n    public function take($limit);\n\n    /**\n     * Take items in the collection until the given condition is met.\n     *\n     * @param  mixed  $value\n     * @return static\n     */\n    public function takeUntil($value);\n\n    /**\n     * Take items in the collection while the given condition is met.\n     *\n     * @param  mixed  $value\n     * @return static\n     */\n    public function takeWhile($value);\n\n    /**\n     * Pass the collection to the given callback and then return it.\n     *\n     * @param  callable  $callback\n     * @return $this\n     */\n    public function tap(callable $callback);\n\n    /**\n     * Pass the enumerable to the given callback and return the result.\n     *\n     * @param  callable  $callback\n     * @return mixed\n     */\n    public function pipe(callable $callback);\n\n    /**\n     * Get the values of a given key.\n     *\n     * @param  string|array  $value\n     * @param  string|null  $key\n     * @return static\n     */\n    public function pluck($value, $key = null);\n\n    /**\n     * Create a collection of all elements that do not pass a given truth test.\n     *\n     * @param  callable|mixed  $callback\n     * @return static\n     */\n    public function reject($callback = true);\n\n    /**\n     * Return only unique items from the collection array.\n     *\n     * @param  string|callable|null  $key\n     * @param  bool  $strict\n     * @return static\n     */\n    public function unique($key = null, $strict = false);\n\n    /**\n     * Return only unique items from the collection array using strict comparison.\n     *\n     * @param  string|callable|null  $key\n     * @return static\n     */\n    public function uniqueStrict($key = null);\n\n    /**\n     * Reset the keys on the underlying array.\n     *\n     * @return static\n     */\n    public function values();\n\n    /**\n     * Pad collection to the specified length with a value.\n     *\n     * @param  int  $size\n     * @param  mixed  $value\n     * @return static\n     */\n    public function pad($size, $value);\n\n    /**\n     * Count the number of items in the collection using a given truth test.\n     *\n     * @param  callable|null  $callback\n     * @return static\n     */\n    public function countBy($callback = null);\n\n    /**\n     * Zip the collection together with one or more arrays.\n     *\n     * e.g. new Collection([1, 2, 3])->zip([4, 5, 6]);\n     *      => [[1, 4], [2, 5], [3, 6]]\n     *\n     * @param  mixed  ...$items\n     * @return static\n     */\n    public function zip($items);\n\n    /**\n     * Collect the values into a collection.\n     *\n     * @return \\Illuminate\\Support\\Collection\n     */\n    public function collect();\n\n    /**\n     * Convert the collection to its string representation.\n     *\n     * @return string\n     */\n    public function __toString();\n\n    /**\n     * Add a method to the list of proxied methods.\n     *\n     * @param  string  $method\n     * @return void\n     */\n    public static function proxy($method);\n\n    /**\n     * Dynamically access collection proxies.\n     *\n     * @param  string  $key\n     * @return mixed\n     *\n     * @throws \\Exception\n     */\n    public function __get($key);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/collections/HigherOrderCollectionProxy.php",
    "content": "<?php\n\nnamespace Illuminate\\Support;\n\n/**\n * @mixin \\Illuminate\\Support\\Enumerable\n */\nclass HigherOrderCollectionProxy\n{\n    /**\n     * The collection being operated on.\n     *\n     * @var \\Illuminate\\Support\\Enumerable\n     */\n    protected $collection;\n\n    /**\n     * The method being proxied.\n     *\n     * @var string\n     */\n    protected $method;\n\n    /**\n     * Create a new proxy instance.\n     *\n     * @param  \\Illuminate\\Support\\Enumerable  $collection\n     * @param  string  $method\n     * @return void\n     */\n    public function __construct(Enumerable $collection, $method)\n    {\n        $this->method = $method;\n        $this->collection = $collection;\n    }\n\n    /**\n     * Proxy accessing an attribute onto the collection items.\n     *\n     * @param  string  $key\n     * @return mixed\n     */\n    public function __get($key)\n    {\n        return $this->collection->{$this->method}(function ($value) use ($key) {\n            return is_array($value) ? $value[$key] : $value->{$key};\n        });\n    }\n\n    /**\n     * Proxy a method call onto the collection items.\n     *\n     * @param  string  $method\n     * @param  array  $parameters\n     * @return mixed\n     */\n    public function __call($method, $parameters)\n    {\n        return $this->collection->{$this->method}(function ($value) use ($method, $parameters) {\n            return $value->{$method}(...$parameters);\n        });\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/collections/HigherOrderWhenProxy.php",
    "content": "<?php\n\nnamespace Illuminate\\Support;\n\n/**\n * @mixin \\Illuminate\\Support\\Enumerable\n */\nclass HigherOrderWhenProxy\n{\n    /**\n     * The collection being operated on.\n     *\n     * @var \\Illuminate\\Support\\Enumerable\n     */\n    protected $collection;\n\n    /**\n     * The condition for proxying.\n     *\n     * @var bool\n     */\n    protected $condition;\n\n    /**\n     * Create a new proxy instance.\n     *\n     * @param  \\Illuminate\\Support\\Enumerable  $collection\n     * @param  bool  $condition\n     * @return void\n     */\n    public function __construct(Enumerable $collection, $condition)\n    {\n        $this->condition = $condition;\n        $this->collection = $collection;\n    }\n\n    /**\n     * Proxy accessing an attribute onto the collection.\n     *\n     * @param  string  $key\n     * @return mixed\n     */\n    public function __get($key)\n    {\n        return $this->condition\n            ? $this->collection->{$key}\n            : $this->collection;\n    }\n\n    /**\n     * Proxy a method call onto the collection.\n     *\n     * @param  string  $method\n     * @param  array  $parameters\n     * @return mixed\n     */\n    public function __call($method, $parameters)\n    {\n        return $this->condition\n            ? $this->collection->{$method}(...$parameters)\n            : $this->collection;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/collections/ItemNotFoundException.php",
    "content": "<?php\n\nnamespace Illuminate\\Support;\n\nuse RuntimeException;\n\nclass ItemNotFoundException extends RuntimeException\n{\n}\n"
  },
  {
    "path": "server/vendor/illuminate/collections/LICENSE.md",
    "content": "The MIT License (MIT)\n\nCopyright (c) Taylor Otwell\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "server/vendor/illuminate/collections/LazyCollection.php",
    "content": "<?php\n\nnamespace Illuminate\\Support;\n\nuse ArrayIterator;\nuse Closure;\nuse DateTimeInterface;\nuse Illuminate\\Contracts\\Support\\CanBeEscapedWhenCastToString;\nuse Illuminate\\Support\\Traits\\EnumeratesValues;\nuse Illuminate\\Support\\Traits\\Macroable;\nuse IteratorAggregate;\nuse stdClass;\n\nclass LazyCollection implements CanBeEscapedWhenCastToString, Enumerable\n{\n    use EnumeratesValues, Macroable;\n\n    /**\n     * The source from which to generate items.\n     *\n     * @var callable|static\n     */\n    public $source;\n\n    /**\n     * Create a new lazy collection instance.\n     *\n     * @param  mixed  $source\n     * @return void\n     */\n    public function __construct($source = null)\n    {\n        if ($source instanceof Closure || $source instanceof self) {\n            $this->source = $source;\n        } elseif (is_null($source)) {\n            $this->source = static::empty();\n        } else {\n            $this->source = $this->getArrayableItems($source);\n        }\n    }\n\n    /**\n     * Create a collection with the given range.\n     *\n     * @param  int  $from\n     * @param  int  $to\n     * @return static\n     */\n    public static function range($from, $to)\n    {\n        return new static(function () use ($from, $to) {\n            if ($from <= $to) {\n                for (; $from <= $to; $from++) {\n                    yield $from;\n                }\n            } else {\n                for (; $from >= $to; $from--) {\n                    yield $from;\n                }\n            }\n        });\n    }\n\n    /**\n     * Get all items in the enumerable.\n     *\n     * @return array\n     */\n    public function all()\n    {\n        if (is_array($this->source)) {\n            return $this->source;\n        }\n\n        return iterator_to_array($this->getIterator());\n    }\n\n    /**\n     * Eager load all items into a new lazy collection backed by an array.\n     *\n     * @return static\n     */\n    public function eager()\n    {\n        return new static($this->all());\n    }\n\n    /**\n     * Cache values as they're enumerated.\n     *\n     * @return static\n     */\n    public function remember()\n    {\n        $iterator = $this->getIterator();\n\n        $iteratorIndex = 0;\n\n        $cache = [];\n\n        return new static(function () use ($iterator, &$iteratorIndex, &$cache) {\n            for ($index = 0; true; $index++) {\n                if (array_key_exists($index, $cache)) {\n                    yield $cache[$index][0] => $cache[$index][1];\n\n                    continue;\n                }\n\n                if ($iteratorIndex < $index) {\n                    $iterator->next();\n\n                    $iteratorIndex++;\n                }\n\n                if (! $iterator->valid()) {\n                    break;\n                }\n\n                $cache[$index] = [$iterator->key(), $iterator->current()];\n\n                yield $cache[$index][0] => $cache[$index][1];\n            }\n        });\n    }\n\n    /**\n     * Get the average value of a given key.\n     *\n     * @param  callable|string|null  $callback\n     * @return mixed\n     */\n    public function avg($callback = null)\n    {\n        return $this->collect()->avg($callback);\n    }\n\n    /**\n     * Get the median of a given key.\n     *\n     * @param  string|array|null  $key\n     * @return mixed\n     */\n    public function median($key = null)\n    {\n        return $this->collect()->median($key);\n    }\n\n    /**\n     * Get the mode of a given key.\n     *\n     * @param  string|array|null  $key\n     * @return array|null\n     */\n    public function mode($key = null)\n    {\n        return $this->collect()->mode($key);\n    }\n\n    /**\n     * Collapse the collection of items into a single array.\n     *\n     * @return static\n     */\n    public function collapse()\n    {\n        return new static(function () {\n            foreach ($this as $values) {\n                if (is_array($values) || $values instanceof Enumerable) {\n                    foreach ($values as $value) {\n                        yield $value;\n                    }\n                }\n            }\n        });\n    }\n\n    /**\n     * Determine if an item exists in the enumerable.\n     *\n     * @param  mixed  $key\n     * @param  mixed  $operator\n     * @param  mixed  $value\n     * @return bool\n     */\n    public function contains($key, $operator = null, $value = null)\n    {\n        if (func_num_args() === 1 && $this->useAsCallable($key)) {\n            $placeholder = new stdClass;\n\n            return $this->first($key, $placeholder) !== $placeholder;\n        }\n\n        if (func_num_args() === 1) {\n            $needle = $key;\n\n            foreach ($this as $value) {\n                if ($value == $needle) {\n                    return true;\n                }\n            }\n\n            return false;\n        }\n\n        return $this->contains($this->operatorForWhere(...func_get_args()));\n    }\n\n    /**\n     * Determine if an item is not contained in the enumerable.\n     *\n     * @param  mixed  $key\n     * @param  mixed  $operator\n     * @param  mixed  $value\n     * @return bool\n     */\n    public function doesntContain($key, $operator = null, $value = null)\n    {\n        return ! $this->contains(...func_get_args());\n    }\n\n    /**\n     * Cross join the given iterables, returning all possible permutations.\n     *\n     * @param  array  ...$arrays\n     * @return static\n     */\n    public function crossJoin(...$arrays)\n    {\n        return $this->passthru('crossJoin', func_get_args());\n    }\n\n    /**\n     * Count the number of items in the collection by a field or using a callback.\n     *\n     * @param  callable|string  $countBy\n     * @return static\n     */\n    public function countBy($countBy = null)\n    {\n        $countBy = is_null($countBy)\n            ? $this->identity()\n            : $this->valueRetriever($countBy);\n\n        return new static(function () use ($countBy) {\n            $counts = [];\n\n            foreach ($this as $key => $value) {\n                $group = $countBy($value, $key);\n\n                if (empty($counts[$group])) {\n                    $counts[$group] = 0;\n                }\n\n                $counts[$group]++;\n            }\n\n            yield from $counts;\n        });\n    }\n\n    /**\n     * Get the items that are not present in the given items.\n     *\n     * @param  mixed  $items\n     * @return static\n     */\n    public function diff($items)\n    {\n        return $this->passthru('diff', func_get_args());\n    }\n\n    /**\n     * Get the items that are not present in the given items, using the callback.\n     *\n     * @param  mixed  $items\n     * @param  callable  $callback\n     * @return static\n     */\n    public function diffUsing($items, callable $callback)\n    {\n        return $this->passthru('diffUsing', func_get_args());\n    }\n\n    /**\n     * Get the items whose keys and values are not present in the given items.\n     *\n     * @param  mixed  $items\n     * @return static\n     */\n    public function diffAssoc($items)\n    {\n        return $this->passthru('diffAssoc', func_get_args());\n    }\n\n    /**\n     * Get the items whose keys and values are not present in the given items, using the callback.\n     *\n     * @param  mixed  $items\n     * @param  callable  $callback\n     * @return static\n     */\n    public function diffAssocUsing($items, callable $callback)\n    {\n        return $this->passthru('diffAssocUsing', func_get_args());\n    }\n\n    /**\n     * Get the items whose keys are not present in the given items.\n     *\n     * @param  mixed  $items\n     * @return static\n     */\n    public function diffKeys($items)\n    {\n        return $this->passthru('diffKeys', func_get_args());\n    }\n\n    /**\n     * Get the items whose keys are not present in the given items, using the callback.\n     *\n     * @param  mixed  $items\n     * @param  callable  $callback\n     * @return static\n     */\n    public function diffKeysUsing($items, callable $callback)\n    {\n        return $this->passthru('diffKeysUsing', func_get_args());\n    }\n\n    /**\n     * Retrieve duplicate items.\n     *\n     * @param  callable|string|null  $callback\n     * @param  bool  $strict\n     * @return static\n     */\n    public function duplicates($callback = null, $strict = false)\n    {\n        return $this->passthru('duplicates', func_get_args());\n    }\n\n    /**\n     * Retrieve duplicate items using strict comparison.\n     *\n     * @param  callable|string|null  $callback\n     * @return static\n     */\n    public function duplicatesStrict($callback = null)\n    {\n        return $this->passthru('duplicatesStrict', func_get_args());\n    }\n\n    /**\n     * Get all items except for those with the specified keys.\n     *\n     * @param  mixed  $keys\n     * @return static\n     */\n    public function except($keys)\n    {\n        return $this->passthru('except', func_get_args());\n    }\n\n    /**\n     * Run a filter over each of the items.\n     *\n     * @param  callable|null  $callback\n     * @return static\n     */\n    public function filter(callable $callback = null)\n    {\n        if (is_null($callback)) {\n            $callback = function ($value) {\n                return (bool) $value;\n            };\n        }\n\n        return new static(function () use ($callback) {\n            foreach ($this as $key => $value) {\n                if ($callback($value, $key)) {\n                    yield $key => $value;\n                }\n            }\n        });\n    }\n\n    /**\n     * Get the first item from the enumerable passing the given truth test.\n     *\n     * @param  callable|null  $callback\n     * @param  mixed  $default\n     * @return mixed\n     */\n    public function first(callable $callback = null, $default = null)\n    {\n        $iterator = $this->getIterator();\n\n        if (is_null($callback)) {\n            if (! $iterator->valid()) {\n                return value($default);\n            }\n\n            return $iterator->current();\n        }\n\n        foreach ($iterator as $key => $value) {\n            if ($callback($value, $key)) {\n                return $value;\n            }\n        }\n\n        return value($default);\n    }\n\n    /**\n     * Get a flattened list of the items in the collection.\n     *\n     * @param  int  $depth\n     * @return static\n     */\n    public function flatten($depth = INF)\n    {\n        $instance = new static(function () use ($depth) {\n            foreach ($this as $item) {\n                if (! is_array($item) && ! $item instanceof Enumerable) {\n                    yield $item;\n                } elseif ($depth === 1) {\n                    yield from $item;\n                } else {\n                    yield from (new static($item))->flatten($depth - 1);\n                }\n            }\n        });\n\n        return $instance->values();\n    }\n\n    /**\n     * Flip the items in the collection.\n     *\n     * @return static\n     */\n    public function flip()\n    {\n        return new static(function () {\n            foreach ($this as $key => $value) {\n                yield $value => $key;\n            }\n        });\n    }\n\n    /**\n     * Get an item by key.\n     *\n     * @param  mixed  $key\n     * @param  mixed  $default\n     * @return mixed\n     */\n    public function get($key, $default = null)\n    {\n        if (is_null($key)) {\n            return;\n        }\n\n        foreach ($this as $outerKey => $outerValue) {\n            if ($outerKey == $key) {\n                return $outerValue;\n            }\n        }\n\n        return value($default);\n    }\n\n    /**\n     * Group an associative array by a field or using a callback.\n     *\n     * @param  array|callable|string  $groupBy\n     * @param  bool  $preserveKeys\n     * @return static\n     */\n    public function groupBy($groupBy, $preserveKeys = false)\n    {\n        return $this->passthru('groupBy', func_get_args());\n    }\n\n    /**\n     * Key an associative array by a field or using a callback.\n     *\n     * @param  callable|string  $keyBy\n     * @return static\n     */\n    public function keyBy($keyBy)\n    {\n        return new static(function () use ($keyBy) {\n            $keyBy = $this->valueRetriever($keyBy);\n\n            foreach ($this as $key => $item) {\n                $resolvedKey = $keyBy($item, $key);\n\n                if (is_object($resolvedKey)) {\n                    $resolvedKey = (string) $resolvedKey;\n                }\n\n                yield $resolvedKey => $item;\n            }\n        });\n    }\n\n    /**\n     * Determine if an item exists in the collection by key.\n     *\n     * @param  mixed  $key\n     * @return bool\n     */\n    public function has($key)\n    {\n        $keys = array_flip(is_array($key) ? $key : func_get_args());\n        $count = count($keys);\n\n        foreach ($this as $key => $value) {\n            if (array_key_exists($key, $keys) && --$count == 0) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * Determine if any of the keys exist in the collection.\n     *\n     * @param  mixed  $key\n     * @return bool\n     */\n    public function hasAny($key)\n    {\n        $keys = array_flip(is_array($key) ? $key : func_get_args());\n\n        foreach ($this as $key => $value) {\n            if (array_key_exists($key, $keys)) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * Concatenate values of a given key as a string.\n     *\n     * @param  string  $value\n     * @param  string|null  $glue\n     * @return string\n     */\n    public function implode($value, $glue = null)\n    {\n        return $this->collect()->implode(...func_get_args());\n    }\n\n    /**\n     * Intersect the collection with the given items.\n     *\n     * @param  mixed  $items\n     * @return static\n     */\n    public function intersect($items)\n    {\n        return $this->passthru('intersect', func_get_args());\n    }\n\n    /**\n     * Intersect the collection with the given items by key.\n     *\n     * @param  mixed  $items\n     * @return static\n     */\n    public function intersectByKeys($items)\n    {\n        return $this->passthru('intersectByKeys', func_get_args());\n    }\n\n    /**\n     * Determine if the items are empty or not.\n     *\n     * @return bool\n     */\n    public function isEmpty()\n    {\n        return ! $this->getIterator()->valid();\n    }\n\n    /**\n     * Determine if the collection contains a single item.\n     *\n     * @return bool\n     */\n    public function containsOneItem()\n    {\n        return $this->take(2)->count() === 1;\n    }\n\n    /**\n     * Join all items from the collection using a string. The final items can use a separate glue string.\n     *\n     * @param  string  $glue\n     * @param  string  $finalGlue\n     * @return string\n     */\n    public function join($glue, $finalGlue = '')\n    {\n        return $this->collect()->join(...func_get_args());\n    }\n\n    /**\n     * Get the keys of the collection items.\n     *\n     * @return static\n     */\n    public function keys()\n    {\n        return new static(function () {\n            foreach ($this as $key => $value) {\n                yield $key;\n            }\n        });\n    }\n\n    /**\n     * Get the last item from the collection.\n     *\n     * @param  callable|null  $callback\n     * @param  mixed  $default\n     * @return mixed\n     */\n    public function last(callable $callback = null, $default = null)\n    {\n        $needle = $placeholder = new stdClass;\n\n        foreach ($this as $key => $value) {\n            if (is_null($callback) || $callback($value, $key)) {\n                $needle = $value;\n            }\n        }\n\n        return $needle === $placeholder ? value($default) : $needle;\n    }\n\n    /**\n     * Get the values of a given key.\n     *\n     * @param  string|array  $value\n     * @param  string|null  $key\n     * @return static\n     */\n    public function pluck($value, $key = null)\n    {\n        return new static(function () use ($value, $key) {\n            [$value, $key] = $this->explodePluckParameters($value, $key);\n\n            foreach ($this as $item) {\n                $itemValue = data_get($item, $value);\n\n                if (is_null($key)) {\n                    yield $itemValue;\n                } else {\n                    $itemKey = data_get($item, $key);\n\n                    if (is_object($itemKey) && method_exists($itemKey, '__toString')) {\n                        $itemKey = (string) $itemKey;\n                    }\n\n                    yield $itemKey => $itemValue;\n                }\n            }\n        });\n    }\n\n    /**\n     * Run a map over each of the items.\n     *\n     * @param  callable  $callback\n     * @return static\n     */\n    public function map(callable $callback)\n    {\n        return new static(function () use ($callback) {\n            foreach ($this as $key => $value) {\n                yield $key => $callback($value, $key);\n            }\n        });\n    }\n\n    /**\n     * Run a dictionary map over the items.\n     *\n     * The callback should return an associative array with a single key/value pair.\n     *\n     * @param  callable  $callback\n     * @return static\n     */\n    public function mapToDictionary(callable $callback)\n    {\n        return $this->passthru('mapToDictionary', func_get_args());\n    }\n\n    /**\n     * Run an associative map over each of the items.\n     *\n     * The callback should return an associative array with a single key/value pair.\n     *\n     * @param  callable  $callback\n     * @return static\n     */\n    public function mapWithKeys(callable $callback)\n    {\n        return new static(function () use ($callback) {\n            foreach ($this as $key => $value) {\n                yield from $callback($value, $key);\n            }\n        });\n    }\n\n    /**\n     * Merge the collection with the given items.\n     *\n     * @param  mixed  $items\n     * @return static\n     */\n    public function merge($items)\n    {\n        return $this->passthru('merge', func_get_args());\n    }\n\n    /**\n     * Recursively merge the collection with the given items.\n     *\n     * @param  mixed  $items\n     * @return static\n     */\n    public function mergeRecursive($items)\n    {\n        return $this->passthru('mergeRecursive', func_get_args());\n    }\n\n    /**\n     * Create a collection by using this collection for keys and another for its values.\n     *\n     * @param  mixed  $values\n     * @return static\n     */\n    public function combine($values)\n    {\n        return new static(function () use ($values) {\n            $values = $this->makeIterator($values);\n\n            $errorMessage = 'Both parameters should have an equal number of elements';\n\n            foreach ($this as $key) {\n                if (! $values->valid()) {\n                    trigger_error($errorMessage, E_USER_WARNING);\n\n                    break;\n                }\n\n                yield $key => $values->current();\n\n                $values->next();\n            }\n\n            if ($values->valid()) {\n                trigger_error($errorMessage, E_USER_WARNING);\n            }\n        });\n    }\n\n    /**\n     * Union the collection with the given items.\n     *\n     * @param  mixed  $items\n     * @return static\n     */\n    public function union($items)\n    {\n        return $this->passthru('union', func_get_args());\n    }\n\n    /**\n     * Create a new collection consisting of every n-th element.\n     *\n     * @param  int  $step\n     * @param  int  $offset\n     * @return static\n     */\n    public function nth($step, $offset = 0)\n    {\n        return new static(function () use ($step, $offset) {\n            $position = 0;\n\n            foreach ($this->slice($offset) as $item) {\n                if ($position % $step === 0) {\n                    yield $item;\n                }\n\n                $position++;\n            }\n        });\n    }\n\n    /**\n     * Get the items with the specified keys.\n     *\n     * @param  mixed  $keys\n     * @return static\n     */\n    public function only($keys)\n    {\n        if ($keys instanceof Enumerable) {\n            $keys = $keys->all();\n        } elseif (! is_null($keys)) {\n            $keys = is_array($keys) ? $keys : func_get_args();\n        }\n\n        return new static(function () use ($keys) {\n            if (is_null($keys)) {\n                yield from $this;\n            } else {\n                $keys = array_flip($keys);\n\n                foreach ($this as $key => $value) {\n                    if (array_key_exists($key, $keys)) {\n                        yield $key => $value;\n\n                        unset($keys[$key]);\n\n                        if (empty($keys)) {\n                            break;\n                        }\n                    }\n                }\n            }\n        });\n    }\n\n    /**\n     * Push all of the given items onto the collection.\n     *\n     * @param  iterable  $source\n     * @return static\n     */\n    public function concat($source)\n    {\n        return (new static(function () use ($source) {\n            yield from $this;\n            yield from $source;\n        }))->values();\n    }\n\n    /**\n     * Get one or a specified number of items randomly from the collection.\n     *\n     * @param  int|null  $number\n     * @return static|mixed\n     *\n     * @throws \\InvalidArgumentException\n     */\n    public function random($number = null)\n    {\n        $result = $this->collect()->random(...func_get_args());\n\n        return is_null($number) ? $result : new static($result);\n    }\n\n    /**\n     * Replace the collection items with the given items.\n     *\n     * @param  mixed  $items\n     * @return static\n     */\n    public function replace($items)\n    {\n        return new static(function () use ($items) {\n            $items = $this->getArrayableItems($items);\n\n            foreach ($this as $key => $value) {\n                if (array_key_exists($key, $items)) {\n                    yield $key => $items[$key];\n\n                    unset($items[$key]);\n                } else {\n                    yield $key => $value;\n                }\n            }\n\n            foreach ($items as $key => $value) {\n                yield $key => $value;\n            }\n        });\n    }\n\n    /**\n     * Recursively replace the collection items with the given items.\n     *\n     * @param  mixed  $items\n     * @return static\n     */\n    public function replaceRecursive($items)\n    {\n        return $this->passthru('replaceRecursive', func_get_args());\n    }\n\n    /**\n     * Reverse items order.\n     *\n     * @return static\n     */\n    public function reverse()\n    {\n        return $this->passthru('reverse', func_get_args());\n    }\n\n    /**\n     * Search the collection for a given value and return the corresponding key if successful.\n     *\n     * @param  mixed  $value\n     * @param  bool  $strict\n     * @return mixed\n     */\n    public function search($value, $strict = false)\n    {\n        $predicate = $this->useAsCallable($value)\n            ? $value\n            : function ($item) use ($value, $strict) {\n                return $strict ? $item === $value : $item == $value;\n            };\n\n        foreach ($this as $key => $item) {\n            if ($predicate($item, $key)) {\n                return $key;\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * Shuffle the items in the collection.\n     *\n     * @param  int|null  $seed\n     * @return static\n     */\n    public function shuffle($seed = null)\n    {\n        return $this->passthru('shuffle', func_get_args());\n    }\n\n    /**\n     * Create chunks representing a \"sliding window\" view of the items in the collection.\n     *\n     * @param  int  $size\n     * @param  int  $step\n     * @return static\n     */\n    public function sliding($size = 2, $step = 1)\n    {\n        return new static(function () use ($size, $step) {\n            $iterator = $this->getIterator();\n\n            $chunk = [];\n\n            while ($iterator->valid()) {\n                $chunk[$iterator->key()] = $iterator->current();\n\n                if (count($chunk) == $size) {\n                    yield tap(new static($chunk), function () use (&$chunk, $step) {\n                        $chunk = array_slice($chunk, $step, null, true);\n                    });\n\n                    // If the $step between chunks is bigger than each chunk's $size\n                    // we will skip the extra items (which should never be in any\n                    // chunk) before we continue to the next chunk in the loop.\n                    if ($step > $size) {\n                        $skip = $step - $size;\n\n                        for ($i = 0; $i < $skip && $iterator->valid(); $i++) {\n                            $iterator->next();\n                        }\n                    }\n                }\n\n                $iterator->next();\n            }\n        });\n    }\n\n    /**\n     * Skip the first {$count} items.\n     *\n     * @param  int  $count\n     * @return static\n     */\n    public function skip($count)\n    {\n        return new static(function () use ($count) {\n            $iterator = $this->getIterator();\n\n            while ($iterator->valid() && $count--) {\n                $iterator->next();\n            }\n\n            while ($iterator->valid()) {\n                yield $iterator->key() => $iterator->current();\n\n                $iterator->next();\n            }\n        });\n    }\n\n    /**\n     * Skip items in the collection until the given condition is met.\n     *\n     * @param  mixed  $value\n     * @return static\n     */\n    public function skipUntil($value)\n    {\n        $callback = $this->useAsCallable($value) ? $value : $this->equality($value);\n\n        return $this->skipWhile($this->negate($callback));\n    }\n\n    /**\n     * Skip items in the collection while the given condition is met.\n     *\n     * @param  mixed  $value\n     * @return static\n     */\n    public function skipWhile($value)\n    {\n        $callback = $this->useAsCallable($value) ? $value : $this->equality($value);\n\n        return new static(function () use ($callback) {\n            $iterator = $this->getIterator();\n\n            while ($iterator->valid() && $callback($iterator->current(), $iterator->key())) {\n                $iterator->next();\n            }\n\n            while ($iterator->valid()) {\n                yield $iterator->key() => $iterator->current();\n\n                $iterator->next();\n            }\n        });\n    }\n\n    /**\n     * Get a slice of items from the enumerable.\n     *\n     * @param  int  $offset\n     * @param  int|null  $length\n     * @return static\n     */\n    public function slice($offset, $length = null)\n    {\n        if ($offset < 0 || $length < 0) {\n            return $this->passthru('slice', func_get_args());\n        }\n\n        $instance = $this->skip($offset);\n\n        return is_null($length) ? $instance : $instance->take($length);\n    }\n\n    /**\n     * Split a collection into a certain number of groups.\n     *\n     * @param  int  $numberOfGroups\n     * @return static\n     */\n    public function split($numberOfGroups)\n    {\n        return $this->passthru('split', func_get_args());\n    }\n\n    /**\n     * Get the first item in the collection, but only if exactly one item exists. Otherwise, throw an exception.\n     *\n     * @param  mixed  $key\n     * @param  mixed  $operator\n     * @param  mixed  $value\n     * @return mixed\n     *\n     * @throws \\Illuminate\\Support\\ItemNotFoundException\n     * @throws \\Illuminate\\Support\\MultipleItemsFoundException\n     */\n    public function sole($key = null, $operator = null, $value = null)\n    {\n        $filter = func_num_args() > 1\n            ? $this->operatorForWhere(...func_get_args())\n            : $key;\n\n        return $this\n            ->when($filter)\n            ->filter($filter)\n            ->take(2)\n            ->collect()\n            ->sole();\n    }\n\n    /**\n     * Get the first item in the collection but throw an exception if no matching items exist.\n     *\n     * @param  mixed  $key\n     * @param  mixed  $operator\n     * @param  mixed  $value\n     * @return mixed\n     *\n     * @throws \\Illuminate\\Support\\ItemNotFoundException\n     */\n    public function firstOrFail($key = null, $operator = null, $value = null)\n    {\n        $filter = func_num_args() > 1\n            ? $this->operatorForWhere(...func_get_args())\n            : $key;\n\n        return $this\n            ->when($filter)\n            ->filter($filter)\n            ->take(1)\n            ->collect()\n            ->firstOrFail();\n    }\n\n    /**\n     * Chunk the collection into chunks of the given size.\n     *\n     * @param  int  $size\n     * @return static\n     */\n    public function chunk($size)\n    {\n        if ($size <= 0) {\n            return static::empty();\n        }\n\n        return new static(function () use ($size) {\n            $iterator = $this->getIterator();\n\n            while ($iterator->valid()) {\n                $chunk = [];\n\n                while (true) {\n                    $chunk[$iterator->key()] = $iterator->current();\n\n                    if (count($chunk) < $size) {\n                        $iterator->next();\n\n                        if (! $iterator->valid()) {\n                            break;\n                        }\n                    } else {\n                        break;\n                    }\n                }\n\n                yield new static($chunk);\n\n                $iterator->next();\n            }\n        });\n    }\n\n    /**\n     * Split a collection into a certain number of groups, and fill the first groups completely.\n     *\n     * @param  int  $numberOfGroups\n     * @return static\n     */\n    public function splitIn($numberOfGroups)\n    {\n        return $this->chunk(ceil($this->count() / $numberOfGroups));\n    }\n\n    /**\n     * Chunk the collection into chunks with a callback.\n     *\n     * @param  callable  $callback\n     * @return static\n     */\n    public function chunkWhile(callable $callback)\n    {\n        return new static(function () use ($callback) {\n            $iterator = $this->getIterator();\n\n            $chunk = new Collection;\n\n            if ($iterator->valid()) {\n                $chunk[$iterator->key()] = $iterator->current();\n\n                $iterator->next();\n            }\n\n            while ($iterator->valid()) {\n                if (! $callback($iterator->current(), $iterator->key(), $chunk)) {\n                    yield new static($chunk);\n\n                    $chunk = new Collection;\n                }\n\n                $chunk[$iterator->key()] = $iterator->current();\n\n                $iterator->next();\n            }\n\n            if ($chunk->isNotEmpty()) {\n                yield new static($chunk);\n            }\n        });\n    }\n\n    /**\n     * Sort through each item with a callback.\n     *\n     * @param  callable|null|int  $callback\n     * @return static\n     */\n    public function sort($callback = null)\n    {\n        return $this->passthru('sort', func_get_args());\n    }\n\n    /**\n     * Sort items in descending order.\n     *\n     * @param  int  $options\n     * @return static\n     */\n    public function sortDesc($options = SORT_REGULAR)\n    {\n        return $this->passthru('sortDesc', func_get_args());\n    }\n\n    /**\n     * Sort the collection using the given callback.\n     *\n     * @param  callable|string  $callback\n     * @param  int  $options\n     * @param  bool  $descending\n     * @return static\n     */\n    public function sortBy($callback, $options = SORT_REGULAR, $descending = false)\n    {\n        return $this->passthru('sortBy', func_get_args());\n    }\n\n    /**\n     * Sort the collection in descending order using the given callback.\n     *\n     * @param  callable|string  $callback\n     * @param  int  $options\n     * @return static\n     */\n    public function sortByDesc($callback, $options = SORT_REGULAR)\n    {\n        return $this->passthru('sortByDesc', func_get_args());\n    }\n\n    /**\n     * Sort the collection keys.\n     *\n     * @param  int  $options\n     * @param  bool  $descending\n     * @return static\n     */\n    public function sortKeys($options = SORT_REGULAR, $descending = false)\n    {\n        return $this->passthru('sortKeys', func_get_args());\n    }\n\n    /**\n     * Sort the collection keys in descending order.\n     *\n     * @param  int  $options\n     * @return static\n     */\n    public function sortKeysDesc($options = SORT_REGULAR)\n    {\n        return $this->passthru('sortKeysDesc', func_get_args());\n    }\n\n    /**\n     * Sort the collection keys using a callback.\n     *\n     * @param  callable  $callback\n     * @return static\n     */\n    public function sortKeysUsing(callable $callback)\n    {\n        return $this->passthru('sortKeysUsing', func_get_args());\n    }\n\n    /**\n     * Take the first or last {$limit} items.\n     *\n     * @param  int  $limit\n     * @return static\n     */\n    public function take($limit)\n    {\n        if ($limit < 0) {\n            return $this->passthru('take', func_get_args());\n        }\n\n        return new static(function () use ($limit) {\n            $iterator = $this->getIterator();\n\n            while ($limit--) {\n                if (! $iterator->valid()) {\n                    break;\n                }\n\n                yield $iterator->key() => $iterator->current();\n\n                if ($limit) {\n                    $iterator->next();\n                }\n            }\n        });\n    }\n\n    /**\n     * Take items in the collection until the given condition is met.\n     *\n     * @param  mixed  $value\n     * @return static\n     */\n    public function takeUntil($value)\n    {\n        $callback = $this->useAsCallable($value) ? $value : $this->equality($value);\n\n        return new static(function () use ($callback) {\n            foreach ($this as $key => $item) {\n                if ($callback($item, $key)) {\n                    break;\n                }\n\n                yield $key => $item;\n            }\n        });\n    }\n\n    /**\n     * Take items in the collection until a given point in time.\n     *\n     * @param  \\DateTimeInterface  $timeout\n     * @return static\n     */\n    public function takeUntilTimeout(DateTimeInterface $timeout)\n    {\n        $timeout = $timeout->getTimestamp();\n\n        return $this->takeWhile(function () use ($timeout) {\n            return $this->now() < $timeout;\n        });\n    }\n\n    /**\n     * Take items in the collection while the given condition is met.\n     *\n     * @param  mixed  $value\n     * @return static\n     */\n    public function takeWhile($value)\n    {\n        $callback = $this->useAsCallable($value) ? $value : $this->equality($value);\n\n        return $this->takeUntil(function ($item, $key) use ($callback) {\n            return ! $callback($item, $key);\n        });\n    }\n\n    /**\n     * Pass each item in the collection to the given callback, lazily.\n     *\n     * @param  callable  $callback\n     * @return static\n     */\n    public function tapEach(callable $callback)\n    {\n        return new static(function () use ($callback) {\n            foreach ($this as $key => $value) {\n                $callback($value, $key);\n\n                yield $key => $value;\n            }\n        });\n    }\n\n    /**\n     * Convert a flatten \"dot\" notation array into an expanded array.\n     *\n     * @return static\n     */\n    public function undot()\n    {\n        return $this->passthru('undot', []);\n    }\n\n    /**\n     * Return only unique items from the collection array.\n     *\n     * @param  string|callable|null  $key\n     * @param  bool  $strict\n     * @return static\n     */\n    public function unique($key = null, $strict = false)\n    {\n        $callback = $this->valueRetriever($key);\n\n        return new static(function () use ($callback, $strict) {\n            $exists = [];\n\n            foreach ($this as $key => $item) {\n                if (! in_array($id = $callback($item, $key), $exists, $strict)) {\n                    yield $key => $item;\n\n                    $exists[] = $id;\n                }\n            }\n        });\n    }\n\n    /**\n     * Reset the keys on the underlying array.\n     *\n     * @return static\n     */\n    public function values()\n    {\n        return new static(function () {\n            foreach ($this as $item) {\n                yield $item;\n            }\n        });\n    }\n\n    /**\n     * Zip the collection together with one or more arrays.\n     *\n     * e.g. new LazyCollection([1, 2, 3])->zip([4, 5, 6]);\n     *      => [[1, 4], [2, 5], [3, 6]]\n     *\n     * @param  mixed  ...$items\n     * @return static\n     */\n    public function zip($items)\n    {\n        $iterables = func_get_args();\n\n        return new static(function () use ($iterables) {\n            $iterators = Collection::make($iterables)->map(function ($iterable) {\n                return $this->makeIterator($iterable);\n            })->prepend($this->getIterator());\n\n            while ($iterators->contains->valid()) {\n                yield new static($iterators->map->current());\n\n                $iterators->each->next();\n            }\n        });\n    }\n\n    /**\n     * Pad collection to the specified length with a value.\n     *\n     * @param  int  $size\n     * @param  mixed  $value\n     * @return static\n     */\n    public function pad($size, $value)\n    {\n        if ($size < 0) {\n            return $this->passthru('pad', func_get_args());\n        }\n\n        return new static(function () use ($size, $value) {\n            $yielded = 0;\n\n            foreach ($this as $index => $item) {\n                yield $index => $item;\n\n                $yielded++;\n            }\n\n            while ($yielded++ < $size) {\n                yield $value;\n            }\n        });\n    }\n\n    /**\n     * Get the values iterator.\n     *\n     * @return \\Traversable\n     */\n    #[\\ReturnTypeWillChange]\n    public function getIterator()\n    {\n        return $this->makeIterator($this->source);\n    }\n\n    /**\n     * Count the number of items in the collection.\n     *\n     * @return int\n     */\n    #[\\ReturnTypeWillChange]\n    public function count()\n    {\n        if (is_array($this->source)) {\n            return count($this->source);\n        }\n\n        return iterator_count($this->getIterator());\n    }\n\n    /**\n     * Make an iterator from the given source.\n     *\n     * @param  mixed  $source\n     * @return \\Traversable\n     */\n    protected function makeIterator($source)\n    {\n        if ($source instanceof IteratorAggregate) {\n            return $source->getIterator();\n        }\n\n        if (is_array($source)) {\n            return new ArrayIterator($source);\n        }\n\n        return $source();\n    }\n\n    /**\n     * Explode the \"value\" and \"key\" arguments passed to \"pluck\".\n     *\n     * @param  string|array  $value\n     * @param  string|array|null  $key\n     * @return array\n     */\n    protected function explodePluckParameters($value, $key)\n    {\n        $value = is_string($value) ? explode('.', $value) : $value;\n\n        $key = is_null($key) || is_array($key) ? $key : explode('.', $key);\n\n        return [$value, $key];\n    }\n\n    /**\n     * Pass this lazy collection through a method on the collection class.\n     *\n     * @param  string  $method\n     * @param  array  $params\n     * @return static\n     */\n    protected function passthru($method, array $params)\n    {\n        return new static(function () use ($method, $params) {\n            yield from $this->collect()->$method(...$params);\n        });\n    }\n\n    /**\n     * Get the current time.\n     *\n     * @return int\n     */\n    protected function now()\n    {\n        return time();\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/collections/MultipleItemsFoundException.php",
    "content": "<?php\n\nnamespace Illuminate\\Support;\n\nuse RuntimeException;\n\nclass MultipleItemsFoundException extends RuntimeException\n{\n}\n"
  },
  {
    "path": "server/vendor/illuminate/collections/Traits/EnumeratesValues.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Traits;\n\nuse CachingIterator;\nuse Closure;\nuse Exception;\nuse Illuminate\\Contracts\\Support\\Arrayable;\nuse Illuminate\\Contracts\\Support\\Jsonable;\nuse Illuminate\\Support\\Arr;\nuse Illuminate\\Support\\Collection;\nuse Illuminate\\Support\\Enumerable;\nuse Illuminate\\Support\\HigherOrderCollectionProxy;\nuse Illuminate\\Support\\HigherOrderWhenProxy;\nuse JsonSerializable;\nuse Symfony\\Component\\VarDumper\\VarDumper;\nuse Traversable;\nuse UnexpectedValueException;\nuse UnitEnum;\n\n/**\n * @property-read HigherOrderCollectionProxy $average\n * @property-read HigherOrderCollectionProxy $avg\n * @property-read HigherOrderCollectionProxy $contains\n * @property-read HigherOrderCollectionProxy $doesntContain\n * @property-read HigherOrderCollectionProxy $each\n * @property-read HigherOrderCollectionProxy $every\n * @property-read HigherOrderCollectionProxy $filter\n * @property-read HigherOrderCollectionProxy $first\n * @property-read HigherOrderCollectionProxy $flatMap\n * @property-read HigherOrderCollectionProxy $groupBy\n * @property-read HigherOrderCollectionProxy $keyBy\n * @property-read HigherOrderCollectionProxy $map\n * @property-read HigherOrderCollectionProxy $max\n * @property-read HigherOrderCollectionProxy $min\n * @property-read HigherOrderCollectionProxy $partition\n * @property-read HigherOrderCollectionProxy $reject\n * @property-read HigherOrderCollectionProxy $some\n * @property-read HigherOrderCollectionProxy $sortBy\n * @property-read HigherOrderCollectionProxy $sortByDesc\n * @property-read HigherOrderCollectionProxy $skipUntil\n * @property-read HigherOrderCollectionProxy $skipWhile\n * @property-read HigherOrderCollectionProxy $sum\n * @property-read HigherOrderCollectionProxy $takeUntil\n * @property-read HigherOrderCollectionProxy $takeWhile\n * @property-read HigherOrderCollectionProxy $unique\n * @property-read HigherOrderCollectionProxy $until\n */\ntrait EnumeratesValues\n{\n    /**\n     * Indicates that the object's string representation should be escaped when __toString is invoked.\n     *\n     * @var bool\n     */\n    protected $escapeWhenCastingToString = false;\n\n    /**\n     * The methods that can be proxied.\n     *\n     * @var string[]\n     */\n    protected static $proxies = [\n        'average',\n        'avg',\n        'contains',\n        'doesntContain',\n        'each',\n        'every',\n        'filter',\n        'first',\n        'flatMap',\n        'groupBy',\n        'keyBy',\n        'map',\n        'max',\n        'min',\n        'partition',\n        'reject',\n        'skipUntil',\n        'skipWhile',\n        'some',\n        'sortBy',\n        'sortByDesc',\n        'sum',\n        'takeUntil',\n        'takeWhile',\n        'unique',\n        'until',\n    ];\n\n    /**\n     * Create a new collection instance if the value isn't one already.\n     *\n     * @param  mixed  $items\n     * @return static\n     */\n    public static function make($items = [])\n    {\n        return new static($items);\n    }\n\n    /**\n     * Wrap the given value in a collection if applicable.\n     *\n     * @param  mixed  $value\n     * @return static\n     */\n    public static function wrap($value)\n    {\n        return $value instanceof Enumerable\n            ? new static($value)\n            : new static(Arr::wrap($value));\n    }\n\n    /**\n     * Get the underlying items from the given collection if applicable.\n     *\n     * @param  array|static  $value\n     * @return array\n     */\n    public static function unwrap($value)\n    {\n        return $value instanceof Enumerable ? $value->all() : $value;\n    }\n\n    /**\n     * Create a new instance with no items.\n     *\n     * @return static\n     */\n    public static function empty()\n    {\n        return new static([]);\n    }\n\n    /**\n     * Create a new collection by invoking the callback a given amount of times.\n     *\n     * @param  int  $number\n     * @param  callable|null  $callback\n     * @return static\n     */\n    public static function times($number, callable $callback = null)\n    {\n        if ($number < 1) {\n            return new static;\n        }\n\n        return static::range(1, $number)\n            ->when($callback)\n            ->map($callback);\n    }\n\n    /**\n     * Alias for the \"avg\" method.\n     *\n     * @param  callable|string|null  $callback\n     * @return mixed\n     */\n    public function average($callback = null)\n    {\n        return $this->avg($callback);\n    }\n\n    /**\n     * Alias for the \"contains\" method.\n     *\n     * @param  mixed  $key\n     * @param  mixed  $operator\n     * @param  mixed  $value\n     * @return bool\n     */\n    public function some($key, $operator = null, $value = null)\n    {\n        return $this->contains(...func_get_args());\n    }\n\n    /**\n     * Determine if an item exists, using strict comparison.\n     *\n     * @param  mixed  $key\n     * @param  mixed  $value\n     * @return bool\n     */\n    public function containsStrict($key, $value = null)\n    {\n        if (func_num_args() === 2) {\n            return $this->contains(function ($item) use ($key, $value) {\n                return data_get($item, $key) === $value;\n            });\n        }\n\n        if ($this->useAsCallable($key)) {\n            return ! is_null($this->first($key));\n        }\n\n        foreach ($this as $item) {\n            if ($item === $key) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * Dump the items and end the script.\n     *\n     * @param  mixed  ...$args\n     * @return void\n     */\n    public function dd(...$args)\n    {\n        $this->dump(...$args);\n\n        exit(1);\n    }\n\n    /**\n     * Dump the items.\n     *\n     * @return $this\n     */\n    public function dump()\n    {\n        (new Collection(func_get_args()))\n            ->push($this->all())\n            ->each(function ($item) {\n                VarDumper::dump($item);\n            });\n\n        return $this;\n    }\n\n    /**\n     * Execute a callback over each item.\n     *\n     * @param  callable  $callback\n     * @return $this\n     */\n    public function each(callable $callback)\n    {\n        foreach ($this as $key => $item) {\n            if ($callback($item, $key) === false) {\n                break;\n            }\n        }\n\n        return $this;\n    }\n\n    /**\n     * Execute a callback over each nested chunk of items.\n     *\n     * @param  callable  $callback\n     * @return static\n     */\n    public function eachSpread(callable $callback)\n    {\n        return $this->each(function ($chunk, $key) use ($callback) {\n            $chunk[] = $key;\n\n            return $callback(...$chunk);\n        });\n    }\n\n    /**\n     * Determine if all items pass the given truth test.\n     *\n     * @param  string|callable  $key\n     * @param  mixed  $operator\n     * @param  mixed  $value\n     * @return bool\n     */\n    public function every($key, $operator = null, $value = null)\n    {\n        if (func_num_args() === 1) {\n            $callback = $this->valueRetriever($key);\n\n            foreach ($this as $k => $v) {\n                if (! $callback($v, $k)) {\n                    return false;\n                }\n            }\n\n            return true;\n        }\n\n        return $this->every($this->operatorForWhere(...func_get_args()));\n    }\n\n    /**\n     * Get the first item by the given key value pair.\n     *\n     * @param  string  $key\n     * @param  mixed  $operator\n     * @param  mixed  $value\n     * @return mixed\n     */\n    public function firstWhere($key, $operator = null, $value = null)\n    {\n        return $this->first($this->operatorForWhere(...func_get_args()));\n    }\n\n    /**\n     * Determine if the collection is not empty.\n     *\n     * @return bool\n     */\n    public function isNotEmpty()\n    {\n        return ! $this->isEmpty();\n    }\n\n    /**\n     * Run a map over each nested chunk of items.\n     *\n     * @param  callable  $callback\n     * @return static\n     */\n    public function mapSpread(callable $callback)\n    {\n        return $this->map(function ($chunk, $key) use ($callback) {\n            $chunk[] = $key;\n\n            return $callback(...$chunk);\n        });\n    }\n\n    /**\n     * Run a grouping map over the items.\n     *\n     * The callback should return an associative array with a single key/value pair.\n     *\n     * @param  callable  $callback\n     * @return static\n     */\n    public function mapToGroups(callable $callback)\n    {\n        $groups = $this->mapToDictionary($callback);\n\n        return $groups->map([$this, 'make']);\n    }\n\n    /**\n     * Map a collection and flatten the result by a single level.\n     *\n     * @param  callable  $callback\n     * @return static\n     */\n    public function flatMap(callable $callback)\n    {\n        return $this->map($callback)->collapse();\n    }\n\n    /**\n     * Map the values into a new class.\n     *\n     * @param  string  $class\n     * @return static\n     */\n    public function mapInto($class)\n    {\n        return $this->map(function ($value, $key) use ($class) {\n            return new $class($value, $key);\n        });\n    }\n\n    /**\n     * Get the min value of a given key.\n     *\n     * @param  callable|string|null  $callback\n     * @return mixed\n     */\n    public function min($callback = null)\n    {\n        $callback = $this->valueRetriever($callback);\n\n        return $this->map(function ($value) use ($callback) {\n            return $callback($value);\n        })->filter(function ($value) {\n            return ! is_null($value);\n        })->reduce(function ($result, $value) {\n            return is_null($result) || $value < $result ? $value : $result;\n        });\n    }\n\n    /**\n     * Get the max value of a given key.\n     *\n     * @param  callable|string|null  $callback\n     * @return mixed\n     */\n    public function max($callback = null)\n    {\n        $callback = $this->valueRetriever($callback);\n\n        return $this->filter(function ($value) {\n            return ! is_null($value);\n        })->reduce(function ($result, $item) use ($callback) {\n            $value = $callback($item);\n\n            return is_null($result) || $value > $result ? $value : $result;\n        });\n    }\n\n    /**\n     * \"Paginate\" the collection by slicing it into a smaller collection.\n     *\n     * @param  int  $page\n     * @param  int  $perPage\n     * @return static\n     */\n    public function forPage($page, $perPage)\n    {\n        $offset = max(0, ($page - 1) * $perPage);\n\n        return $this->slice($offset, $perPage);\n    }\n\n    /**\n     * Partition the collection into two arrays using the given callback or key.\n     *\n     * @param  callable|string  $key\n     * @param  mixed  $operator\n     * @param  mixed  $value\n     * @return static\n     */\n    public function partition($key, $operator = null, $value = null)\n    {\n        $passed = [];\n        $failed = [];\n\n        $callback = func_num_args() === 1\n                ? $this->valueRetriever($key)\n                : $this->operatorForWhere(...func_get_args());\n\n        foreach ($this as $key => $item) {\n            if ($callback($item, $key)) {\n                $passed[$key] = $item;\n            } else {\n                $failed[$key] = $item;\n            }\n        }\n\n        return new static([new static($passed), new static($failed)]);\n    }\n\n    /**\n     * Get the sum of the given values.\n     *\n     * @param  callable|string|null  $callback\n     * @return mixed\n     */\n    public function sum($callback = null)\n    {\n        $callback = is_null($callback)\n            ? $this->identity()\n            : $this->valueRetriever($callback);\n\n        return $this->reduce(function ($result, $item) use ($callback) {\n            return $result + $callback($item);\n        }, 0);\n    }\n\n    /**\n     * Apply the callback if the value is truthy.\n     *\n     * @param  bool|mixed  $value\n     * @param  callable|null  $callback\n     * @param  callable|null  $default\n     * @return static|mixed\n     */\n    public function when($value, callable $callback = null, callable $default = null)\n    {\n        if (! $callback) {\n            return new HigherOrderWhenProxy($this, $value);\n        }\n\n        if ($value) {\n            return $callback($this, $value);\n        } elseif ($default) {\n            return $default($this, $value);\n        }\n\n        return $this;\n    }\n\n    /**\n     * Apply the callback if the collection is empty.\n     *\n     * @param  callable  $callback\n     * @param  callable|null  $default\n     * @return static|mixed\n     */\n    public function whenEmpty(callable $callback, callable $default = null)\n    {\n        return $this->when($this->isEmpty(), $callback, $default);\n    }\n\n    /**\n     * Apply the callback if the collection is not empty.\n     *\n     * @param  callable  $callback\n     * @param  callable|null  $default\n     * @return static|mixed\n     */\n    public function whenNotEmpty(callable $callback, callable $default = null)\n    {\n        return $this->when($this->isNotEmpty(), $callback, $default);\n    }\n\n    /**\n     * Apply the callback if the value is falsy.\n     *\n     * @param  bool  $value\n     * @param  callable  $callback\n     * @param  callable|null  $default\n     * @return static|mixed\n     */\n    public function unless($value, callable $callback, callable $default = null)\n    {\n        return $this->when(! $value, $callback, $default);\n    }\n\n    /**\n     * Apply the callback unless the collection is empty.\n     *\n     * @param  callable  $callback\n     * @param  callable|null  $default\n     * @return static|mixed\n     */\n    public function unlessEmpty(callable $callback, callable $default = null)\n    {\n        return $this->whenNotEmpty($callback, $default);\n    }\n\n    /**\n     * Apply the callback unless the collection is not empty.\n     *\n     * @param  callable  $callback\n     * @param  callable|null  $default\n     * @return static|mixed\n     */\n    public function unlessNotEmpty(callable $callback, callable $default = null)\n    {\n        return $this->whenEmpty($callback, $default);\n    }\n\n    /**\n     * Filter items by the given key value pair.\n     *\n     * @param  string  $key\n     * @param  mixed  $operator\n     * @param  mixed  $value\n     * @return static\n     */\n    public function where($key, $operator = null, $value = null)\n    {\n        return $this->filter($this->operatorForWhere(...func_get_args()));\n    }\n\n    /**\n     * Filter items where the value for the given key is null.\n     *\n     * @param  string|null  $key\n     * @return static\n     */\n    public function whereNull($key = null)\n    {\n        return $this->whereStrict($key, null);\n    }\n\n    /**\n     * Filter items where the value for the given key is not null.\n     *\n     * @param  string|null  $key\n     * @return static\n     */\n    public function whereNotNull($key = null)\n    {\n        return $this->where($key, '!==', null);\n    }\n\n    /**\n     * Filter items by the given key value pair using strict comparison.\n     *\n     * @param  string  $key\n     * @param  mixed  $value\n     * @return static\n     */\n    public function whereStrict($key, $value)\n    {\n        return $this->where($key, '===', $value);\n    }\n\n    /**\n     * Filter items by the given key value pair.\n     *\n     * @param  string  $key\n     * @param  mixed  $values\n     * @param  bool  $strict\n     * @return static\n     */\n    public function whereIn($key, $values, $strict = false)\n    {\n        $values = $this->getArrayableItems($values);\n\n        return $this->filter(function ($item) use ($key, $values, $strict) {\n            return in_array(data_get($item, $key), $values, $strict);\n        });\n    }\n\n    /**\n     * Filter items by the given key value pair using strict comparison.\n     *\n     * @param  string  $key\n     * @param  mixed  $values\n     * @return static\n     */\n    public function whereInStrict($key, $values)\n    {\n        return $this->whereIn($key, $values, true);\n    }\n\n    /**\n     * Filter items such that the value of the given key is between the given values.\n     *\n     * @param  string  $key\n     * @param  array  $values\n     * @return static\n     */\n    public function whereBetween($key, $values)\n    {\n        return $this->where($key, '>=', reset($values))->where($key, '<=', end($values));\n    }\n\n    /**\n     * Filter items such that the value of the given key is not between the given values.\n     *\n     * @param  string  $key\n     * @param  array  $values\n     * @return static\n     */\n    public function whereNotBetween($key, $values)\n    {\n        return $this->filter(function ($item) use ($key, $values) {\n            return data_get($item, $key) < reset($values) || data_get($item, $key) > end($values);\n        });\n    }\n\n    /**\n     * Filter items by the given key value pair.\n     *\n     * @param  string  $key\n     * @param  mixed  $values\n     * @param  bool  $strict\n     * @return static\n     */\n    public function whereNotIn($key, $values, $strict = false)\n    {\n        $values = $this->getArrayableItems($values);\n\n        return $this->reject(function ($item) use ($key, $values, $strict) {\n            return in_array(data_get($item, $key), $values, $strict);\n        });\n    }\n\n    /**\n     * Filter items by the given key value pair using strict comparison.\n     *\n     * @param  string  $key\n     * @param  mixed  $values\n     * @return static\n     */\n    public function whereNotInStrict($key, $values)\n    {\n        return $this->whereNotIn($key, $values, true);\n    }\n\n    /**\n     * Filter the items, removing any items that don't match the given type(s).\n     *\n     * @param  string|string[]  $type\n     * @return static\n     */\n    public function whereInstanceOf($type)\n    {\n        return $this->filter(function ($value) use ($type) {\n            if (is_array($type)) {\n                foreach ($type as $classType) {\n                    if ($value instanceof $classType) {\n                        return true;\n                    }\n                }\n\n                return false;\n            }\n\n            return $value instanceof $type;\n        });\n    }\n\n    /**\n     * Pass the collection to the given callback and return the result.\n     *\n     * @param  callable  $callback\n     * @return mixed\n     */\n    public function pipe(callable $callback)\n    {\n        return $callback($this);\n    }\n\n    /**\n     * Pass the collection into a new class.\n     *\n     * @param  string  $class\n     * @return mixed\n     */\n    public function pipeInto($class)\n    {\n        return new $class($this);\n    }\n\n    /**\n     * Pass the collection through a series of callable pipes and return the result.\n     *\n     * @param  array<callable>  $pipes\n     * @return mixed\n     */\n    public function pipeThrough($pipes)\n    {\n        return static::make($pipes)->reduce(\n            function ($carry, $pipe) {\n                return $pipe($carry);\n            },\n            $this,\n        );\n    }\n\n    /**\n     * Pass the collection to the given callback and then return it.\n     *\n     * @param  callable  $callback\n     * @return $this\n     */\n    public function tap(callable $callback)\n    {\n        $callback(clone $this);\n\n        return $this;\n    }\n\n    /**\n     * Reduce the collection to a single value.\n     *\n     * @param  callable  $callback\n     * @param  mixed  $initial\n     * @return mixed\n     */\n    public function reduce(callable $callback, $initial = null)\n    {\n        $result = $initial;\n\n        foreach ($this as $key => $value) {\n            $result = $callback($result, $value, $key);\n        }\n\n        return $result;\n    }\n\n    /**\n     * Reduce the collection to multiple aggregate values.\n     *\n     * @param  callable  $callback\n     * @param  mixed  ...$initial\n     * @return array\n     *\n     * @deprecated Use \"reduceSpread\" instead\n     *\n     * @throws \\UnexpectedValueException\n     */\n    public function reduceMany(callable $callback, ...$initial)\n    {\n        return $this->reduceSpread($callback, ...$initial);\n    }\n\n    /**\n     * Reduce the collection to multiple aggregate values.\n     *\n     * @param  callable  $callback\n     * @param  mixed  ...$initial\n     * @return array\n     *\n     * @throws \\UnexpectedValueException\n     */\n    public function reduceSpread(callable $callback, ...$initial)\n    {\n        $result = $initial;\n\n        foreach ($this as $key => $value) {\n            $result = call_user_func_array($callback, array_merge($result, [$value, $key]));\n\n            if (! is_array($result)) {\n                throw new UnexpectedValueException(sprintf(\n                    \"%s::reduceMany expects reducer to return an array, but got a '%s' instead.\",\n                    class_basename(static::class), gettype($result)\n                ));\n            }\n        }\n\n        return $result;\n    }\n\n    /**\n     * Reduce an associative collection to a single value.\n     *\n     * @param  callable  $callback\n     * @param  mixed  $initial\n     * @return mixed\n     */\n    public function reduceWithKeys(callable $callback, $initial = null)\n    {\n        return $this->reduce($callback, $initial);\n    }\n\n    /**\n     * Create a collection of all elements that do not pass a given truth test.\n     *\n     * @param  callable|mixed  $callback\n     * @return static\n     */\n    public function reject($callback = true)\n    {\n        $useAsCallable = $this->useAsCallable($callback);\n\n        return $this->filter(function ($value, $key) use ($callback, $useAsCallable) {\n            return $useAsCallable\n                ? ! $callback($value, $key)\n                : $value != $callback;\n        });\n    }\n\n    /**\n     * Return only unique items from the collection array using strict comparison.\n     *\n     * @param  string|callable|null  $key\n     * @return static\n     */\n    public function uniqueStrict($key = null)\n    {\n        return $this->unique($key, true);\n    }\n\n    /**\n     * Collect the values into a collection.\n     *\n     * @return \\Illuminate\\Support\\Collection\n     */\n    public function collect()\n    {\n        return new Collection($this->all());\n    }\n\n    /**\n     * Get the collection of items as a plain array.\n     *\n     * @return array\n     */\n    public function toArray()\n    {\n        return $this->map(function ($value) {\n            return $value instanceof Arrayable ? $value->toArray() : $value;\n        })->all();\n    }\n\n    /**\n     * Convert the object into something JSON serializable.\n     *\n     * @return array\n     */\n    #[\\ReturnTypeWillChange]\n    public function jsonSerialize()\n    {\n        return array_map(function ($value) {\n            if ($value instanceof JsonSerializable) {\n                return $value->jsonSerialize();\n            } elseif ($value instanceof Jsonable) {\n                return json_decode($value->toJson(), true);\n            } elseif ($value instanceof Arrayable) {\n                return $value->toArray();\n            }\n\n            return $value;\n        }, $this->all());\n    }\n\n    /**\n     * Get the collection of items as JSON.\n     *\n     * @param  int  $options\n     * @return string\n     */\n    public function toJson($options = 0)\n    {\n        return json_encode($this->jsonSerialize(), $options);\n    }\n\n    /**\n     * Get a CachingIterator instance.\n     *\n     * @param  int  $flags\n     * @return \\CachingIterator\n     */\n    public function getCachingIterator($flags = CachingIterator::CALL_TOSTRING)\n    {\n        return new CachingIterator($this->getIterator(), $flags);\n    }\n\n    /**\n     * Convert the collection to its string representation.\n     *\n     * @return string\n     */\n    public function __toString()\n    {\n        return $this->escapeWhenCastingToString\n                    ? e($this->toJson())\n                    : $this->toJson();\n    }\n\n    /**\n     * Indicate that the model's string representation should be escaped when __toString is invoked.\n     *\n     * @param  bool  $escape\n     * @return $this\n     */\n    public function escapeWhenCastingToString($escape = true)\n    {\n        $this->escapeWhenCastingToString = $escape;\n\n        return $this;\n    }\n\n    /**\n     * Add a method to the list of proxied methods.\n     *\n     * @param  string  $method\n     * @return void\n     */\n    public static function proxy($method)\n    {\n        static::$proxies[] = $method;\n    }\n\n    /**\n     * Dynamically access collection proxies.\n     *\n     * @param  string  $key\n     * @return mixed\n     *\n     * @throws \\Exception\n     */\n    public function __get($key)\n    {\n        if (! in_array($key, static::$proxies)) {\n            throw new Exception(\"Property [{$key}] does not exist on this collection instance.\");\n        }\n\n        return new HigherOrderCollectionProxy($this, $key);\n    }\n\n    /**\n     * Results array of items from Collection or Arrayable.\n     *\n     * @param  mixed  $items\n     * @return array\n     */\n    protected function getArrayableItems($items)\n    {\n        if (is_array($items)) {\n            return $items;\n        } elseif ($items instanceof Enumerable) {\n            return $items->all();\n        } elseif ($items instanceof Arrayable) {\n            return $items->toArray();\n        } elseif ($items instanceof Jsonable) {\n            return json_decode($items->toJson(), true);\n        } elseif ($items instanceof JsonSerializable) {\n            return (array) $items->jsonSerialize();\n        } elseif ($items instanceof Traversable) {\n            return iterator_to_array($items);\n        } elseif ($items instanceof UnitEnum) {\n            return [$items];\n        }\n\n        return (array) $items;\n    }\n\n    /**\n     * Get an operator checker callback.\n     *\n     * @param  string  $key\n     * @param  string|null  $operator\n     * @param  mixed  $value\n     * @return \\Closure\n     */\n    protected function operatorForWhere($key, $operator = null, $value = null)\n    {\n        if (func_num_args() === 1) {\n            $value = true;\n\n            $operator = '=';\n        }\n\n        if (func_num_args() === 2) {\n            $value = $operator;\n\n            $operator = '=';\n        }\n\n        return function ($item) use ($key, $operator, $value) {\n            $retrieved = data_get($item, $key);\n\n            $strings = array_filter([$retrieved, $value], function ($value) {\n                return is_string($value) || (is_object($value) && method_exists($value, '__toString'));\n            });\n\n            if (count($strings) < 2 && count(array_filter([$retrieved, $value], 'is_object')) == 1) {\n                return in_array($operator, ['!=', '<>', '!==']);\n            }\n\n            switch ($operator) {\n                default:\n                case '=':\n                case '==':  return $retrieved == $value;\n                case '!=':\n                case '<>':  return $retrieved != $value;\n                case '<':   return $retrieved < $value;\n                case '>':   return $retrieved > $value;\n                case '<=':  return $retrieved <= $value;\n                case '>=':  return $retrieved >= $value;\n                case '===': return $retrieved === $value;\n                case '!==': return $retrieved !== $value;\n            }\n        };\n    }\n\n    /**\n     * Determine if the given value is callable, but not a string.\n     *\n     * @param  mixed  $value\n     * @return bool\n     */\n    protected function useAsCallable($value)\n    {\n        return ! is_string($value) && is_callable($value);\n    }\n\n    /**\n     * Get a value retrieving callback.\n     *\n     * @param  callable|string|null  $value\n     * @return callable\n     */\n    protected function valueRetriever($value)\n    {\n        if ($this->useAsCallable($value)) {\n            return $value;\n        }\n\n        return function ($item) use ($value) {\n            return data_get($item, $value);\n        };\n    }\n\n    /**\n     * Make a function to check an item's equality.\n     *\n     * @param  mixed  $value\n     * @return \\Closure\n     */\n    protected function equality($value)\n    {\n        return function ($item) use ($value) {\n            return $item === $value;\n        };\n    }\n\n    /**\n     * Make a function using another function, by negating its result.\n     *\n     * @param  \\Closure  $callback\n     * @return \\Closure\n     */\n    protected function negate(Closure $callback)\n    {\n        return function (...$params) use ($callback) {\n            return ! $callback(...$params);\n        };\n    }\n\n    /**\n     * Make a function that returns what's passed to it.\n     *\n     * @return \\Closure\n     */\n    protected function identity()\n    {\n        return function ($value) {\n            return $value;\n        };\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/collections/composer.json",
    "content": "{\n    \"name\": \"illuminate/collections\",\n    \"description\": \"The Illuminate Collections package.\",\n    \"license\": \"MIT\",\n    \"homepage\": \"https://laravel.com\",\n    \"support\": {\n        \"issues\": \"https://github.com/laravel/framework/issues\",\n        \"source\": \"https://github.com/laravel/framework\"\n    },\n    \"authors\": [\n        {\n            \"name\": \"Taylor Otwell\",\n            \"email\": \"taylor@laravel.com\"\n        }\n    ],\n    \"require\": {\n        \"php\": \"^7.3|^8.0\",\n        \"illuminate/contracts\": \"^8.0\",\n        \"illuminate/macroable\": \"^8.0\"\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"Illuminate\\\\Support\\\\\": \"\"\n        },\n        \"files\": [\n            \"helpers.php\"\n        ]\n    },\n    \"extra\": {\n        \"branch-alias\": {\n            \"dev-master\": \"8.x-dev\"\n        }\n    },\n    \"suggest\": {\n        \"symfony/var-dumper\": \"Required to use the dump method (^5.4).\"\n    },\n    \"config\": {\n        \"sort-packages\": true\n    },\n    \"minimum-stability\": \"dev\"\n}\n"
  },
  {
    "path": "server/vendor/illuminate/collections/helpers.php",
    "content": "<?php\n\nuse Illuminate\\Support\\Arr;\nuse Illuminate\\Support\\Collection;\n\nif (! function_exists('collect')) {\n    /**\n     * Create a collection from the given value.\n     *\n     * @param  mixed  $value\n     * @return \\Illuminate\\Support\\Collection\n     */\n    function collect($value = null)\n    {\n        return new Collection($value);\n    }\n}\n\nif (! function_exists('data_fill')) {\n    /**\n     * Fill in data where it's missing.\n     *\n     * @param  mixed  $target\n     * @param  string|array  $key\n     * @param  mixed  $value\n     * @return mixed\n     */\n    function data_fill(&$target, $key, $value)\n    {\n        return data_set($target, $key, $value, false);\n    }\n}\n\nif (! function_exists('data_get')) {\n    /**\n     * Get an item from an array or object using \"dot\" notation.\n     *\n     * @param  mixed  $target\n     * @param  string|array|int|null  $key\n     * @param  mixed  $default\n     * @return mixed\n     */\n    function data_get($target, $key, $default = null)\n    {\n        if (is_null($key)) {\n            return $target;\n        }\n\n        $key = is_array($key) ? $key : explode('.', $key);\n\n        foreach ($key as $i => $segment) {\n            unset($key[$i]);\n\n            if (is_null($segment)) {\n                return $target;\n            }\n\n            if ($segment === '*') {\n                if ($target instanceof Collection) {\n                    $target = $target->all();\n                } elseif (! is_array($target)) {\n                    return value($default);\n                }\n\n                $result = [];\n\n                foreach ($target as $item) {\n                    $result[] = data_get($item, $key);\n                }\n\n                return in_array('*', $key) ? Arr::collapse($result) : $result;\n            }\n\n            if (Arr::accessible($target) && Arr::exists($target, $segment)) {\n                $target = $target[$segment];\n            } elseif (is_object($target) && isset($target->{$segment})) {\n                $target = $target->{$segment};\n            } else {\n                return value($default);\n            }\n        }\n\n        return $target;\n    }\n}\n\nif (! function_exists('data_set')) {\n    /**\n     * Set an item on an array or object using dot notation.\n     *\n     * @param  mixed  $target\n     * @param  string|array  $key\n     * @param  mixed  $value\n     * @param  bool  $overwrite\n     * @return mixed\n     */\n    function data_set(&$target, $key, $value, $overwrite = true)\n    {\n        $segments = is_array($key) ? $key : explode('.', $key);\n\n        if (($segment = array_shift($segments)) === '*') {\n            if (! Arr::accessible($target)) {\n                $target = [];\n            }\n\n            if ($segments) {\n                foreach ($target as &$inner) {\n                    data_set($inner, $segments, $value, $overwrite);\n                }\n            } elseif ($overwrite) {\n                foreach ($target as &$inner) {\n                    $inner = $value;\n                }\n            }\n        } elseif (Arr::accessible($target)) {\n            if ($segments) {\n                if (! Arr::exists($target, $segment)) {\n                    $target[$segment] = [];\n                }\n\n                data_set($target[$segment], $segments, $value, $overwrite);\n            } elseif ($overwrite || ! Arr::exists($target, $segment)) {\n                $target[$segment] = $value;\n            }\n        } elseif (is_object($target)) {\n            if ($segments) {\n                if (! isset($target->{$segment})) {\n                    $target->{$segment} = [];\n                }\n\n                data_set($target->{$segment}, $segments, $value, $overwrite);\n            } elseif ($overwrite || ! isset($target->{$segment})) {\n                $target->{$segment} = $value;\n            }\n        } else {\n            $target = [];\n\n            if ($segments) {\n                data_set($target[$segment], $segments, $value, $overwrite);\n            } elseif ($overwrite) {\n                $target[$segment] = $value;\n            }\n        }\n\n        return $target;\n    }\n}\n\nif (! function_exists('head')) {\n    /**\n     * Get the first element of an array. Useful for method chaining.\n     *\n     * @param  array  $array\n     * @return mixed\n     */\n    function head($array)\n    {\n        return reset($array);\n    }\n}\n\nif (! function_exists('last')) {\n    /**\n     * Get the last element from an array.\n     *\n     * @param  array  $array\n     * @return mixed\n     */\n    function last($array)\n    {\n        return end($array);\n    }\n}\n\nif (! function_exists('value')) {\n    /**\n     * Return the default value of the given value.\n     *\n     * @param  mixed  $value\n     * @return mixed\n     */\n    function value($value, ...$args)\n    {\n        return $value instanceof Closure ? $value(...$args) : $value;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/container/BoundMethod.php",
    "content": "<?php\n\nnamespace Illuminate\\Container;\n\nuse Closure;\nuse Illuminate\\Contracts\\Container\\BindingResolutionException;\nuse InvalidArgumentException;\nuse ReflectionFunction;\nuse ReflectionMethod;\n\nclass BoundMethod\n{\n    /**\n     * Call the given Closure / class@method and inject its dependencies.\n     *\n     * @param  \\Illuminate\\Container\\Container  $container\n     * @param  callable|string  $callback\n     * @param  array  $parameters\n     * @param  string|null  $defaultMethod\n     * @return mixed\n     *\n     * @throws \\ReflectionException\n     * @throws \\InvalidArgumentException\n     */\n    public static function call($container, $callback, array $parameters = [], $defaultMethod = null)\n    {\n        if (is_string($callback) && ! $defaultMethod && method_exists($callback, '__invoke')) {\n            $defaultMethod = '__invoke';\n        }\n\n        if (static::isCallableWithAtSign($callback) || $defaultMethod) {\n            return static::callClass($container, $callback, $parameters, $defaultMethod);\n        }\n\n        return static::callBoundMethod($container, $callback, function () use ($container, $callback, $parameters) {\n            return $callback(...array_values(static::getMethodDependencies($container, $callback, $parameters)));\n        });\n    }\n\n    /**\n     * Call a string reference to a class using Class@method syntax.\n     *\n     * @param  \\Illuminate\\Container\\Container  $container\n     * @param  string  $target\n     * @param  array  $parameters\n     * @param  string|null  $defaultMethod\n     * @return mixed\n     *\n     * @throws \\InvalidArgumentException\n     */\n    protected static function callClass($container, $target, array $parameters = [], $defaultMethod = null)\n    {\n        $segments = explode('@', $target);\n\n        // We will assume an @ sign is used to delimit the class name from the method\n        // name. We will split on this @ sign and then build a callable array that\n        // we can pass right back into the \"call\" method for dependency binding.\n        $method = count($segments) === 2\n                        ? $segments[1] : $defaultMethod;\n\n        if (is_null($method)) {\n            throw new InvalidArgumentException('Method not provided.');\n        }\n\n        return static::call(\n            $container, [$container->make($segments[0]), $method], $parameters\n        );\n    }\n\n    /**\n     * Call a method that has been bound to the container.\n     *\n     * @param  \\Illuminate\\Container\\Container  $container\n     * @param  callable  $callback\n     * @param  mixed  $default\n     * @return mixed\n     */\n    protected static function callBoundMethod($container, $callback, $default)\n    {\n        if (! is_array($callback)) {\n            return Util::unwrapIfClosure($default);\n        }\n\n        // Here we need to turn the array callable into a Class@method string we can use to\n        // examine the container and see if there are any method bindings for this given\n        // method. If there are, we can call this method binding callback immediately.\n        $method = static::normalizeMethod($callback);\n\n        if ($container->hasMethodBinding($method)) {\n            return $container->callMethodBinding($method, $callback[0]);\n        }\n\n        return Util::unwrapIfClosure($default);\n    }\n\n    /**\n     * Normalize the given callback into a Class@method string.\n     *\n     * @param  callable  $callback\n     * @return string\n     */\n    protected static function normalizeMethod($callback)\n    {\n        $class = is_string($callback[0]) ? $callback[0] : get_class($callback[0]);\n\n        return \"{$class}@{$callback[1]}\";\n    }\n\n    /**\n     * Get all dependencies for a given method.\n     *\n     * @param  \\Illuminate\\Container\\Container  $container\n     * @param  callable|string  $callback\n     * @param  array  $parameters\n     * @return array\n     *\n     * @throws \\ReflectionException\n     */\n    protected static function getMethodDependencies($container, $callback, array $parameters = [])\n    {\n        $dependencies = [];\n\n        foreach (static::getCallReflector($callback)->getParameters() as $parameter) {\n            static::addDependencyForCallParameter($container, $parameter, $parameters, $dependencies);\n        }\n\n        return array_merge($dependencies, array_values($parameters));\n    }\n\n    /**\n     * Get the proper reflection instance for the given callback.\n     *\n     * @param  callable|string  $callback\n     * @return \\ReflectionFunctionAbstract\n     *\n     * @throws \\ReflectionException\n     */\n    protected static function getCallReflector($callback)\n    {\n        if (is_string($callback) && strpos($callback, '::') !== false) {\n            $callback = explode('::', $callback);\n        } elseif (is_object($callback) && ! $callback instanceof Closure) {\n            $callback = [$callback, '__invoke'];\n        }\n\n        return is_array($callback)\n                        ? new ReflectionMethod($callback[0], $callback[1])\n                        : new ReflectionFunction($callback);\n    }\n\n    /**\n     * Get the dependency for the given call parameter.\n     *\n     * @param  \\Illuminate\\Container\\Container  $container\n     * @param  \\ReflectionParameter  $parameter\n     * @param  array  $parameters\n     * @param  array  $dependencies\n     * @return void\n     *\n     * @throws \\Illuminate\\Contracts\\Container\\BindingResolutionException\n     */\n    protected static function addDependencyForCallParameter($container, $parameter,\n                                                            array &$parameters, &$dependencies)\n    {\n        if (array_key_exists($paramName = $parameter->getName(), $parameters)) {\n            $dependencies[] = $parameters[$paramName];\n\n            unset($parameters[$paramName]);\n        } elseif (! is_null($className = Util::getParameterClassName($parameter))) {\n            if (array_key_exists($className, $parameters)) {\n                $dependencies[] = $parameters[$className];\n\n                unset($parameters[$className]);\n            } else {\n                if ($parameter->isVariadic()) {\n                    $variadicDependencies = $container->make($className);\n\n                    $dependencies = array_merge($dependencies, is_array($variadicDependencies)\n                                ? $variadicDependencies\n                                : [$variadicDependencies]);\n                } else {\n                    $dependencies[] = $container->make($className);\n                }\n            }\n        } elseif ($parameter->isDefaultValueAvailable()) {\n            $dependencies[] = $parameter->getDefaultValue();\n        } elseif (! $parameter->isOptional() && ! array_key_exists($paramName, $parameters)) {\n            $message = \"Unable to resolve dependency [{$parameter}] in class {$parameter->getDeclaringClass()->getName()}\";\n\n            throw new BindingResolutionException($message);\n        }\n    }\n\n    /**\n     * Determine if the given string is in Class@method syntax.\n     *\n     * @param  mixed  $callback\n     * @return bool\n     */\n    protected static function isCallableWithAtSign($callback)\n    {\n        return is_string($callback) && strpos($callback, '@') !== false;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/container/Container.php",
    "content": "<?php\n\nnamespace Illuminate\\Container;\n\nuse ArrayAccess;\nuse Closure;\nuse Exception;\nuse Illuminate\\Contracts\\Container\\BindingResolutionException;\nuse Illuminate\\Contracts\\Container\\CircularDependencyException;\nuse Illuminate\\Contracts\\Container\\Container as ContainerContract;\nuse LogicException;\nuse ReflectionClass;\nuse ReflectionException;\nuse ReflectionParameter;\nuse TypeError;\n\nclass Container implements ArrayAccess, ContainerContract\n{\n    /**\n     * The current globally available container (if any).\n     *\n     * @var static\n     */\n    protected static $instance;\n\n    /**\n     * An array of the types that have been resolved.\n     *\n     * @var bool[]\n     */\n    protected $resolved = [];\n\n    /**\n     * The container's bindings.\n     *\n     * @var array[]\n     */\n    protected $bindings = [];\n\n    /**\n     * The container's method bindings.\n     *\n     * @var \\Closure[]\n     */\n    protected $methodBindings = [];\n\n    /**\n     * The container's shared instances.\n     *\n     * @var object[]\n     */\n    protected $instances = [];\n\n    /**\n     * The container's scoped instances.\n     *\n     * @var array\n     */\n    protected $scopedInstances = [];\n\n    /**\n     * The registered type aliases.\n     *\n     * @var string[]\n     */\n    protected $aliases = [];\n\n    /**\n     * The registered aliases keyed by the abstract name.\n     *\n     * @var array[]\n     */\n    protected $abstractAliases = [];\n\n    /**\n     * The extension closures for services.\n     *\n     * @var array[]\n     */\n    protected $extenders = [];\n\n    /**\n     * All of the registered tags.\n     *\n     * @var array[]\n     */\n    protected $tags = [];\n\n    /**\n     * The stack of concretions currently being built.\n     *\n     * @var array[]\n     */\n    protected $buildStack = [];\n\n    /**\n     * The parameter override stack.\n     *\n     * @var array[]\n     */\n    protected $with = [];\n\n    /**\n     * The contextual binding map.\n     *\n     * @var array[]\n     */\n    public $contextual = [];\n\n    /**\n     * All of the registered rebound callbacks.\n     *\n     * @var array[]\n     */\n    protected $reboundCallbacks = [];\n\n    /**\n     * All of the global before resolving callbacks.\n     *\n     * @var \\Closure[]\n     */\n    protected $globalBeforeResolvingCallbacks = [];\n\n    /**\n     * All of the global resolving callbacks.\n     *\n     * @var \\Closure[]\n     */\n    protected $globalResolvingCallbacks = [];\n\n    /**\n     * All of the global after resolving callbacks.\n     *\n     * @var \\Closure[]\n     */\n    protected $globalAfterResolvingCallbacks = [];\n\n    /**\n     * All of the before resolving callbacks by class type.\n     *\n     * @var array[]\n     */\n    protected $beforeResolvingCallbacks = [];\n\n    /**\n     * All of the resolving callbacks by class type.\n     *\n     * @var array[]\n     */\n    protected $resolvingCallbacks = [];\n\n    /**\n     * All of the after resolving callbacks by class type.\n     *\n     * @var array[]\n     */\n    protected $afterResolvingCallbacks = [];\n\n    /**\n     * Define a contextual binding.\n     *\n     * @param  array|string  $concrete\n     * @return \\Illuminate\\Contracts\\Container\\ContextualBindingBuilder\n     */\n    public function when($concrete)\n    {\n        $aliases = [];\n\n        foreach (Util::arrayWrap($concrete) as $c) {\n            $aliases[] = $this->getAlias($c);\n        }\n\n        return new ContextualBindingBuilder($this, $aliases);\n    }\n\n    /**\n     * Determine if the given abstract type has been bound.\n     *\n     * @param  string  $abstract\n     * @return bool\n     */\n    public function bound($abstract)\n    {\n        return isset($this->bindings[$abstract]) ||\n               isset($this->instances[$abstract]) ||\n               $this->isAlias($abstract);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @return bool\n     */\n    public function has($id)\n    {\n        return $this->bound($id);\n    }\n\n    /**\n     * Determine if the given abstract type has been resolved.\n     *\n     * @param  string  $abstract\n     * @return bool\n     */\n    public function resolved($abstract)\n    {\n        if ($this->isAlias($abstract)) {\n            $abstract = $this->getAlias($abstract);\n        }\n\n        return isset($this->resolved[$abstract]) ||\n               isset($this->instances[$abstract]);\n    }\n\n    /**\n     * Determine if a given type is shared.\n     *\n     * @param  string  $abstract\n     * @return bool\n     */\n    public function isShared($abstract)\n    {\n        return isset($this->instances[$abstract]) ||\n               (isset($this->bindings[$abstract]['shared']) &&\n               $this->bindings[$abstract]['shared'] === true);\n    }\n\n    /**\n     * Determine if a given string is an alias.\n     *\n     * @param  string  $name\n     * @return bool\n     */\n    public function isAlias($name)\n    {\n        return isset($this->aliases[$name]);\n    }\n\n    /**\n     * Register a binding with the container.\n     *\n     * @param  string  $abstract\n     * @param  \\Closure|string|null  $concrete\n     * @param  bool  $shared\n     * @return void\n     *\n     * @throws \\TypeError\n     */\n    public function bind($abstract, $concrete = null, $shared = false)\n    {\n        $this->dropStaleInstances($abstract);\n\n        // If no concrete type was given, we will simply set the concrete type to the\n        // abstract type. After that, the concrete type to be registered as shared\n        // without being forced to state their classes in both of the parameters.\n        if (is_null($concrete)) {\n            $concrete = $abstract;\n        }\n\n        // If the factory is not a Closure, it means it is just a class name which is\n        // bound into this container to the abstract type and we will just wrap it\n        // up inside its own Closure to give us more convenience when extending.\n        if (! $concrete instanceof Closure) {\n            if (! is_string($concrete)) {\n                throw new TypeError(self::class.'::bind(): Argument #2 ($concrete) must be of type Closure|string|null');\n            }\n\n            $concrete = $this->getClosure($abstract, $concrete);\n        }\n\n        $this->bindings[$abstract] = compact('concrete', 'shared');\n\n        // If the abstract type was already resolved in this container we'll fire the\n        // rebound listener so that any objects which have already gotten resolved\n        // can have their copy of the object updated via the listener callbacks.\n        if ($this->resolved($abstract)) {\n            $this->rebound($abstract);\n        }\n    }\n\n    /**\n     * Get the Closure to be used when building a type.\n     *\n     * @param  string  $abstract\n     * @param  string  $concrete\n     * @return \\Closure\n     */\n    protected function getClosure($abstract, $concrete)\n    {\n        return function ($container, $parameters = []) use ($abstract, $concrete) {\n            if ($abstract == $concrete) {\n                return $container->build($concrete);\n            }\n\n            return $container->resolve(\n                $concrete, $parameters, $raiseEvents = false\n            );\n        };\n    }\n\n    /**\n     * Determine if the container has a method binding.\n     *\n     * @param  string  $method\n     * @return bool\n     */\n    public function hasMethodBinding($method)\n    {\n        return isset($this->methodBindings[$method]);\n    }\n\n    /**\n     * Bind a callback to resolve with Container::call.\n     *\n     * @param  array|string  $method\n     * @param  \\Closure  $callback\n     * @return void\n     */\n    public function bindMethod($method, $callback)\n    {\n        $this->methodBindings[$this->parseBindMethod($method)] = $callback;\n    }\n\n    /**\n     * Get the method to be bound in class@method format.\n     *\n     * @param  array|string  $method\n     * @return string\n     */\n    protected function parseBindMethod($method)\n    {\n        if (is_array($method)) {\n            return $method[0].'@'.$method[1];\n        }\n\n        return $method;\n    }\n\n    /**\n     * Get the method binding for the given method.\n     *\n     * @param  string  $method\n     * @param  mixed  $instance\n     * @return mixed\n     */\n    public function callMethodBinding($method, $instance)\n    {\n        return call_user_func($this->methodBindings[$method], $instance, $this);\n    }\n\n    /**\n     * Add a contextual binding to the container.\n     *\n     * @param  string  $concrete\n     * @param  string  $abstract\n     * @param  \\Closure|string  $implementation\n     * @return void\n     */\n    public function addContextualBinding($concrete, $abstract, $implementation)\n    {\n        $this->contextual[$concrete][$this->getAlias($abstract)] = $implementation;\n    }\n\n    /**\n     * Register a binding if it hasn't already been registered.\n     *\n     * @param  string  $abstract\n     * @param  \\Closure|string|null  $concrete\n     * @param  bool  $shared\n     * @return void\n     */\n    public function bindIf($abstract, $concrete = null, $shared = false)\n    {\n        if (! $this->bound($abstract)) {\n            $this->bind($abstract, $concrete, $shared);\n        }\n    }\n\n    /**\n     * Register a shared binding in the container.\n     *\n     * @param  string  $abstract\n     * @param  \\Closure|string|null  $concrete\n     * @return void\n     */\n    public function singleton($abstract, $concrete = null)\n    {\n        $this->bind($abstract, $concrete, true);\n    }\n\n    /**\n     * Register a shared binding if it hasn't already been registered.\n     *\n     * @param  string  $abstract\n     * @param  \\Closure|string|null  $concrete\n     * @return void\n     */\n    public function singletonIf($abstract, $concrete = null)\n    {\n        if (! $this->bound($abstract)) {\n            $this->singleton($abstract, $concrete);\n        }\n    }\n\n    /**\n     * Register a scoped binding in the container.\n     *\n     * @param  string  $abstract\n     * @param  \\Closure|string|null  $concrete\n     * @return void\n     */\n    public function scoped($abstract, $concrete = null)\n    {\n        $this->scopedInstances[] = $abstract;\n\n        $this->singleton($abstract, $concrete);\n    }\n\n    /**\n     * Register a scoped binding if it hasn't already been registered.\n     *\n     * @param  string  $abstract\n     * @param  \\Closure|string|null  $concrete\n     * @return void\n     */\n    public function scopedIf($abstract, $concrete = null)\n    {\n        if (! $this->bound($abstract)) {\n            $this->scopedInstances[] = $abstract;\n\n            $this->singleton($abstract, $concrete);\n        }\n    }\n\n    /**\n     * \"Extend\" an abstract type in the container.\n     *\n     * @param  string  $abstract\n     * @param  \\Closure  $closure\n     * @return void\n     *\n     * @throws \\InvalidArgumentException\n     */\n    public function extend($abstract, Closure $closure)\n    {\n        $abstract = $this->getAlias($abstract);\n\n        if (isset($this->instances[$abstract])) {\n            $this->instances[$abstract] = $closure($this->instances[$abstract], $this);\n\n            $this->rebound($abstract);\n        } else {\n            $this->extenders[$abstract][] = $closure;\n\n            if ($this->resolved($abstract)) {\n                $this->rebound($abstract);\n            }\n        }\n    }\n\n    /**\n     * Register an existing instance as shared in the container.\n     *\n     * @param  string  $abstract\n     * @param  mixed  $instance\n     * @return mixed\n     */\n    public function instance($abstract, $instance)\n    {\n        $this->removeAbstractAlias($abstract);\n\n        $isBound = $this->bound($abstract);\n\n        unset($this->aliases[$abstract]);\n\n        // We'll check to determine if this type has been bound before, and if it has\n        // we will fire the rebound callbacks registered with the container and it\n        // can be updated with consuming classes that have gotten resolved here.\n        $this->instances[$abstract] = $instance;\n\n        if ($isBound) {\n            $this->rebound($abstract);\n        }\n\n        return $instance;\n    }\n\n    /**\n     * Remove an alias from the contextual binding alias cache.\n     *\n     * @param  string  $searched\n     * @return void\n     */\n    protected function removeAbstractAlias($searched)\n    {\n        if (! isset($this->aliases[$searched])) {\n            return;\n        }\n\n        foreach ($this->abstractAliases as $abstract => $aliases) {\n            foreach ($aliases as $index => $alias) {\n                if ($alias == $searched) {\n                    unset($this->abstractAliases[$abstract][$index]);\n                }\n            }\n        }\n    }\n\n    /**\n     * Assign a set of tags to a given binding.\n     *\n     * @param  array|string  $abstracts\n     * @param  array|mixed  ...$tags\n     * @return void\n     */\n    public function tag($abstracts, $tags)\n    {\n        $tags = is_array($tags) ? $tags : array_slice(func_get_args(), 1);\n\n        foreach ($tags as $tag) {\n            if (! isset($this->tags[$tag])) {\n                $this->tags[$tag] = [];\n            }\n\n            foreach ((array) $abstracts as $abstract) {\n                $this->tags[$tag][] = $abstract;\n            }\n        }\n    }\n\n    /**\n     * Resolve all of the bindings for a given tag.\n     *\n     * @param  string  $tag\n     * @return iterable\n     */\n    public function tagged($tag)\n    {\n        if (! isset($this->tags[$tag])) {\n            return [];\n        }\n\n        return new RewindableGenerator(function () use ($tag) {\n            foreach ($this->tags[$tag] as $abstract) {\n                yield $this->make($abstract);\n            }\n        }, count($this->tags[$tag]));\n    }\n\n    /**\n     * Alias a type to a different name.\n     *\n     * @param  string  $abstract\n     * @param  string  $alias\n     * @return void\n     *\n     * @throws \\LogicException\n     */\n    public function alias($abstract, $alias)\n    {\n        if ($alias === $abstract) {\n            throw new LogicException(\"[{$abstract}] is aliased to itself.\");\n        }\n\n        $this->aliases[$alias] = $abstract;\n\n        $this->abstractAliases[$abstract][] = $alias;\n    }\n\n    /**\n     * Bind a new callback to an abstract's rebind event.\n     *\n     * @param  string  $abstract\n     * @param  \\Closure  $callback\n     * @return mixed\n     */\n    public function rebinding($abstract, Closure $callback)\n    {\n        $this->reboundCallbacks[$abstract = $this->getAlias($abstract)][] = $callback;\n\n        if ($this->bound($abstract)) {\n            return $this->make($abstract);\n        }\n    }\n\n    /**\n     * Refresh an instance on the given target and method.\n     *\n     * @param  string  $abstract\n     * @param  mixed  $target\n     * @param  string  $method\n     * @return mixed\n     */\n    public function refresh($abstract, $target, $method)\n    {\n        return $this->rebinding($abstract, function ($app, $instance) use ($target, $method) {\n            $target->{$method}($instance);\n        });\n    }\n\n    /**\n     * Fire the \"rebound\" callbacks for the given abstract type.\n     *\n     * @param  string  $abstract\n     * @return void\n     */\n    protected function rebound($abstract)\n    {\n        $instance = $this->make($abstract);\n\n        foreach ($this->getReboundCallbacks($abstract) as $callback) {\n            call_user_func($callback, $this, $instance);\n        }\n    }\n\n    /**\n     * Get the rebound callbacks for a given type.\n     *\n     * @param  string  $abstract\n     * @return array\n     */\n    protected function getReboundCallbacks($abstract)\n    {\n        return $this->reboundCallbacks[$abstract] ?? [];\n    }\n\n    /**\n     * Wrap the given closure such that its dependencies will be injected when executed.\n     *\n     * @param  \\Closure  $callback\n     * @param  array  $parameters\n     * @return \\Closure\n     */\n    public function wrap(Closure $callback, array $parameters = [])\n    {\n        return function () use ($callback, $parameters) {\n            return $this->call($callback, $parameters);\n        };\n    }\n\n    /**\n     * Call the given Closure / class@method and inject its dependencies.\n     *\n     * @param  callable|string  $callback\n     * @param  array<string, mixed>  $parameters\n     * @param  string|null  $defaultMethod\n     * @return mixed\n     *\n     * @throws \\InvalidArgumentException\n     */\n    public function call($callback, array $parameters = [], $defaultMethod = null)\n    {\n        return BoundMethod::call($this, $callback, $parameters, $defaultMethod);\n    }\n\n    /**\n     * Get a closure to resolve the given type from the container.\n     *\n     * @param  string  $abstract\n     * @return \\Closure\n     */\n    public function factory($abstract)\n    {\n        return function () use ($abstract) {\n            return $this->make($abstract);\n        };\n    }\n\n    /**\n     * An alias function name for make().\n     *\n     * @param  string|callable  $abstract\n     * @param  array  $parameters\n     * @return mixed\n     *\n     * @throws \\Illuminate\\Contracts\\Container\\BindingResolutionException\n     */\n    public function makeWith($abstract, array $parameters = [])\n    {\n        return $this->make($abstract, $parameters);\n    }\n\n    /**\n     * Resolve the given type from the container.\n     *\n     * @param  string|callable  $abstract\n     * @param  array  $parameters\n     * @return mixed\n     *\n     * @throws \\Illuminate\\Contracts\\Container\\BindingResolutionException\n     */\n    public function make($abstract, array $parameters = [])\n    {\n        return $this->resolve($abstract, $parameters);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @return mixed\n     */\n    public function get($id)\n    {\n        try {\n            return $this->resolve($id);\n        } catch (Exception $e) {\n            if ($this->has($id) || $e instanceof CircularDependencyException) {\n                throw $e;\n            }\n\n            throw new EntryNotFoundException($id, $e->getCode(), $e);\n        }\n    }\n\n    /**\n     * Resolve the given type from the container.\n     *\n     * @param  string|callable  $abstract\n     * @param  array  $parameters\n     * @param  bool  $raiseEvents\n     * @return mixed\n     *\n     * @throws \\Illuminate\\Contracts\\Container\\BindingResolutionException\n     * @throws \\Illuminate\\Contracts\\Container\\CircularDependencyException\n     */\n    protected function resolve($abstract, $parameters = [], $raiseEvents = true)\n    {\n        $abstract = $this->getAlias($abstract);\n\n        // First we'll fire any event handlers which handle the \"before\" resolving of\n        // specific types. This gives some hooks the chance to add various extends\n        // calls to change the resolution of objects that they're interested in.\n        if ($raiseEvents) {\n            $this->fireBeforeResolvingCallbacks($abstract, $parameters);\n        }\n\n        $concrete = $this->getContextualConcrete($abstract);\n\n        $needsContextualBuild = ! empty($parameters) || ! is_null($concrete);\n\n        // If an instance of the type is currently being managed as a singleton we'll\n        // just return an existing instance instead of instantiating new instances\n        // so the developer can keep using the same objects instance every time.\n        if (isset($this->instances[$abstract]) && ! $needsContextualBuild) {\n            return $this->instances[$abstract];\n        }\n\n        $this->with[] = $parameters;\n\n        if (is_null($concrete)) {\n            $concrete = $this->getConcrete($abstract);\n        }\n\n        // We're ready to instantiate an instance of the concrete type registered for\n        // the binding. This will instantiate the types, as well as resolve any of\n        // its \"nested\" dependencies recursively until all have gotten resolved.\n        if ($this->isBuildable($concrete, $abstract)) {\n            $object = $this->build($concrete);\n        } else {\n            $object = $this->make($concrete);\n        }\n\n        // If we defined any extenders for this type, we'll need to spin through them\n        // and apply them to the object being built. This allows for the extension\n        // of services, such as changing configuration or decorating the object.\n        foreach ($this->getExtenders($abstract) as $extender) {\n            $object = $extender($object, $this);\n        }\n\n        // If the requested type is registered as a singleton we'll want to cache off\n        // the instances in \"memory\" so we can return it later without creating an\n        // entirely new instance of an object on each subsequent request for it.\n        if ($this->isShared($abstract) && ! $needsContextualBuild) {\n            $this->instances[$abstract] = $object;\n        }\n\n        if ($raiseEvents) {\n            $this->fireResolvingCallbacks($abstract, $object);\n        }\n\n        // Before returning, we will also set the resolved flag to \"true\" and pop off\n        // the parameter overrides for this build. After those two things are done\n        // we will be ready to return back the fully constructed class instance.\n        $this->resolved[$abstract] = true;\n\n        array_pop($this->with);\n\n        return $object;\n    }\n\n    /**\n     * Get the concrete type for a given abstract.\n     *\n     * @param  string|callable  $abstract\n     * @return mixed\n     */\n    protected function getConcrete($abstract)\n    {\n        // If we don't have a registered resolver or concrete for the type, we'll just\n        // assume each type is a concrete name and will attempt to resolve it as is\n        // since the container should be able to resolve concretes automatically.\n        if (isset($this->bindings[$abstract])) {\n            return $this->bindings[$abstract]['concrete'];\n        }\n\n        return $abstract;\n    }\n\n    /**\n     * Get the contextual concrete binding for the given abstract.\n     *\n     * @param  string|callable  $abstract\n     * @return \\Closure|string|array|null\n     */\n    protected function getContextualConcrete($abstract)\n    {\n        if (! is_null($binding = $this->findInContextualBindings($abstract))) {\n            return $binding;\n        }\n\n        // Next we need to see if a contextual binding might be bound under an alias of the\n        // given abstract type. So, we will need to check if any aliases exist with this\n        // type and then spin through them and check for contextual bindings on these.\n        if (empty($this->abstractAliases[$abstract])) {\n            return;\n        }\n\n        foreach ($this->abstractAliases[$abstract] as $alias) {\n            if (! is_null($binding = $this->findInContextualBindings($alias))) {\n                return $binding;\n            }\n        }\n    }\n\n    /**\n     * Find the concrete binding for the given abstract in the contextual binding array.\n     *\n     * @param  string|callable  $abstract\n     * @return \\Closure|string|null\n     */\n    protected function findInContextualBindings($abstract)\n    {\n        return $this->contextual[end($this->buildStack)][$abstract] ?? null;\n    }\n\n    /**\n     * Determine if the given concrete is buildable.\n     *\n     * @param  mixed  $concrete\n     * @param  string  $abstract\n     * @return bool\n     */\n    protected function isBuildable($concrete, $abstract)\n    {\n        return $concrete === $abstract || $concrete instanceof Closure;\n    }\n\n    /**\n     * Instantiate a concrete instance of the given type.\n     *\n     * @param  \\Closure|string  $concrete\n     * @return mixed\n     *\n     * @throws \\Illuminate\\Contracts\\Container\\BindingResolutionException\n     * @throws \\Illuminate\\Contracts\\Container\\CircularDependencyException\n     */\n    public function build($concrete)\n    {\n        // If the concrete type is actually a Closure, we will just execute it and\n        // hand back the results of the functions, which allows functions to be\n        // used as resolvers for more fine-tuned resolution of these objects.\n        if ($concrete instanceof Closure) {\n            return $concrete($this, $this->getLastParameterOverride());\n        }\n\n        try {\n            $reflector = new ReflectionClass($concrete);\n        } catch (ReflectionException $e) {\n            throw new BindingResolutionException(\"Target class [$concrete] does not exist.\", 0, $e);\n        }\n\n        // If the type is not instantiable, the developer is attempting to resolve\n        // an abstract type such as an Interface or Abstract Class and there is\n        // no binding registered for the abstractions so we need to bail out.\n        if (! $reflector->isInstantiable()) {\n            return $this->notInstantiable($concrete);\n        }\n\n        $this->buildStack[] = $concrete;\n\n        $constructor = $reflector->getConstructor();\n\n        // If there are no constructors, that means there are no dependencies then\n        // we can just resolve the instances of the objects right away, without\n        // resolving any other types or dependencies out of these containers.\n        if (is_null($constructor)) {\n            array_pop($this->buildStack);\n\n            return new $concrete;\n        }\n\n        $dependencies = $constructor->getParameters();\n\n        // Once we have all the constructor's parameters we can create each of the\n        // dependency instances and then use the reflection instances to make a\n        // new instance of this class, injecting the created dependencies in.\n        try {\n            $instances = $this->resolveDependencies($dependencies);\n        } catch (BindingResolutionException $e) {\n            array_pop($this->buildStack);\n\n            throw $e;\n        }\n\n        array_pop($this->buildStack);\n\n        return $reflector->newInstanceArgs($instances);\n    }\n\n    /**\n     * Resolve all of the dependencies from the ReflectionParameters.\n     *\n     * @param  \\ReflectionParameter[]  $dependencies\n     * @return array\n     *\n     * @throws \\Illuminate\\Contracts\\Container\\BindingResolutionException\n     */\n    protected function resolveDependencies(array $dependencies)\n    {\n        $results = [];\n\n        foreach ($dependencies as $dependency) {\n            // If the dependency has an override for this particular build we will use\n            // that instead as the value. Otherwise, we will continue with this run\n            // of resolutions and let reflection attempt to determine the result.\n            if ($this->hasParameterOverride($dependency)) {\n                $results[] = $this->getParameterOverride($dependency);\n\n                continue;\n            }\n\n            // If the class is null, it means the dependency is a string or some other\n            // primitive type which we can not resolve since it is not a class and\n            // we will just bomb out with an error since we have no-where to go.\n            $result = is_null(Util::getParameterClassName($dependency))\n                            ? $this->resolvePrimitive($dependency)\n                            : $this->resolveClass($dependency);\n\n            if ($dependency->isVariadic()) {\n                $results = array_merge($results, $result);\n            } else {\n                $results[] = $result;\n            }\n        }\n\n        return $results;\n    }\n\n    /**\n     * Determine if the given dependency has a parameter override.\n     *\n     * @param  \\ReflectionParameter  $dependency\n     * @return bool\n     */\n    protected function hasParameterOverride($dependency)\n    {\n        return array_key_exists(\n            $dependency->name, $this->getLastParameterOverride()\n        );\n    }\n\n    /**\n     * Get a parameter override for a dependency.\n     *\n     * @param  \\ReflectionParameter  $dependency\n     * @return mixed\n     */\n    protected function getParameterOverride($dependency)\n    {\n        return $this->getLastParameterOverride()[$dependency->name];\n    }\n\n    /**\n     * Get the last parameter override.\n     *\n     * @return array\n     */\n    protected function getLastParameterOverride()\n    {\n        return count($this->with) ? end($this->with) : [];\n    }\n\n    /**\n     * Resolve a non-class hinted primitive dependency.\n     *\n     * @param  \\ReflectionParameter  $parameter\n     * @return mixed\n     *\n     * @throws \\Illuminate\\Contracts\\Container\\BindingResolutionException\n     */\n    protected function resolvePrimitive(ReflectionParameter $parameter)\n    {\n        if (! is_null($concrete = $this->getContextualConcrete('$'.$parameter->getName()))) {\n            return $concrete instanceof Closure ? $concrete($this) : $concrete;\n        }\n\n        if ($parameter->isDefaultValueAvailable()) {\n            return $parameter->getDefaultValue();\n        }\n\n        $this->unresolvablePrimitive($parameter);\n    }\n\n    /**\n     * Resolve a class based dependency from the container.\n     *\n     * @param  \\ReflectionParameter  $parameter\n     * @return mixed\n     *\n     * @throws \\Illuminate\\Contracts\\Container\\BindingResolutionException\n     */\n    protected function resolveClass(ReflectionParameter $parameter)\n    {\n        try {\n            return $parameter->isVariadic()\n                        ? $this->resolveVariadicClass($parameter)\n                        : $this->make(Util::getParameterClassName($parameter));\n        }\n\n        // If we can not resolve the class instance, we will check to see if the value\n        // is optional, and if it is we will return the optional parameter value as\n        // the value of the dependency, similarly to how we do this with scalars.\n        catch (BindingResolutionException $e) {\n            if ($parameter->isDefaultValueAvailable()) {\n                array_pop($this->with);\n\n                return $parameter->getDefaultValue();\n            }\n\n            if ($parameter->isVariadic()) {\n                array_pop($this->with);\n\n                return [];\n            }\n\n            throw $e;\n        }\n    }\n\n    /**\n     * Resolve a class based variadic dependency from the container.\n     *\n     * @param  \\ReflectionParameter  $parameter\n     * @return mixed\n     */\n    protected function resolveVariadicClass(ReflectionParameter $parameter)\n    {\n        $className = Util::getParameterClassName($parameter);\n\n        $abstract = $this->getAlias($className);\n\n        if (! is_array($concrete = $this->getContextualConcrete($abstract))) {\n            return $this->make($className);\n        }\n\n        return array_map(function ($abstract) {\n            return $this->resolve($abstract);\n        }, $concrete);\n    }\n\n    /**\n     * Throw an exception that the concrete is not instantiable.\n     *\n     * @param  string  $concrete\n     * @return void\n     *\n     * @throws \\Illuminate\\Contracts\\Container\\BindingResolutionException\n     */\n    protected function notInstantiable($concrete)\n    {\n        if (! empty($this->buildStack)) {\n            $previous = implode(', ', $this->buildStack);\n\n            $message = \"Target [$concrete] is not instantiable while building [$previous].\";\n        } else {\n            $message = \"Target [$concrete] is not instantiable.\";\n        }\n\n        throw new BindingResolutionException($message);\n    }\n\n    /**\n     * Throw an exception for an unresolvable primitive.\n     *\n     * @param  \\ReflectionParameter  $parameter\n     * @return void\n     *\n     * @throws \\Illuminate\\Contracts\\Container\\BindingResolutionException\n     */\n    protected function unresolvablePrimitive(ReflectionParameter $parameter)\n    {\n        $message = \"Unresolvable dependency resolving [$parameter] in class {$parameter->getDeclaringClass()->getName()}\";\n\n        throw new BindingResolutionException($message);\n    }\n\n    /**\n     * Register a new before resolving callback for all types.\n     *\n     * @param  \\Closure|string  $abstract\n     * @param  \\Closure|null  $callback\n     * @return void\n     */\n    public function beforeResolving($abstract, Closure $callback = null)\n    {\n        if (is_string($abstract)) {\n            $abstract = $this->getAlias($abstract);\n        }\n\n        if ($abstract instanceof Closure && is_null($callback)) {\n            $this->globalBeforeResolvingCallbacks[] = $abstract;\n        } else {\n            $this->beforeResolvingCallbacks[$abstract][] = $callback;\n        }\n    }\n\n    /**\n     * Register a new resolving callback.\n     *\n     * @param  \\Closure|string  $abstract\n     * @param  \\Closure|null  $callback\n     * @return void\n     */\n    public function resolving($abstract, Closure $callback = null)\n    {\n        if (is_string($abstract)) {\n            $abstract = $this->getAlias($abstract);\n        }\n\n        if (is_null($callback) && $abstract instanceof Closure) {\n            $this->globalResolvingCallbacks[] = $abstract;\n        } else {\n            $this->resolvingCallbacks[$abstract][] = $callback;\n        }\n    }\n\n    /**\n     * Register a new after resolving callback for all types.\n     *\n     * @param  \\Closure|string  $abstract\n     * @param  \\Closure|null  $callback\n     * @return void\n     */\n    public function afterResolving($abstract, Closure $callback = null)\n    {\n        if (is_string($abstract)) {\n            $abstract = $this->getAlias($abstract);\n        }\n\n        if ($abstract instanceof Closure && is_null($callback)) {\n            $this->globalAfterResolvingCallbacks[] = $abstract;\n        } else {\n            $this->afterResolvingCallbacks[$abstract][] = $callback;\n        }\n    }\n\n    /**\n     * Fire all of the before resolving callbacks.\n     *\n     * @param  string  $abstract\n     * @param  array  $parameters\n     * @return void\n     */\n    protected function fireBeforeResolvingCallbacks($abstract, $parameters = [])\n    {\n        $this->fireBeforeCallbackArray($abstract, $parameters, $this->globalBeforeResolvingCallbacks);\n\n        foreach ($this->beforeResolvingCallbacks as $type => $callbacks) {\n            if ($type === $abstract || is_subclass_of($abstract, $type)) {\n                $this->fireBeforeCallbackArray($abstract, $parameters, $callbacks);\n            }\n        }\n    }\n\n    /**\n     * Fire an array of callbacks with an object.\n     *\n     * @param  string  $abstract\n     * @param  array  $parameters\n     * @param  array  $callbacks\n     * @return void\n     */\n    protected function fireBeforeCallbackArray($abstract, $parameters, array $callbacks)\n    {\n        foreach ($callbacks as $callback) {\n            $callback($abstract, $parameters, $this);\n        }\n    }\n\n    /**\n     * Fire all of the resolving callbacks.\n     *\n     * @param  string  $abstract\n     * @param  mixed  $object\n     * @return void\n     */\n    protected function fireResolvingCallbacks($abstract, $object)\n    {\n        $this->fireCallbackArray($object, $this->globalResolvingCallbacks);\n\n        $this->fireCallbackArray(\n            $object, $this->getCallbacksForType($abstract, $object, $this->resolvingCallbacks)\n        );\n\n        $this->fireAfterResolvingCallbacks($abstract, $object);\n    }\n\n    /**\n     * Fire all of the after resolving callbacks.\n     *\n     * @param  string  $abstract\n     * @param  mixed  $object\n     * @return void\n     */\n    protected function fireAfterResolvingCallbacks($abstract, $object)\n    {\n        $this->fireCallbackArray($object, $this->globalAfterResolvingCallbacks);\n\n        $this->fireCallbackArray(\n            $object, $this->getCallbacksForType($abstract, $object, $this->afterResolvingCallbacks)\n        );\n    }\n\n    /**\n     * Get all callbacks for a given type.\n     *\n     * @param  string  $abstract\n     * @param  object  $object\n     * @param  array  $callbacksPerType\n     * @return array\n     */\n    protected function getCallbacksForType($abstract, $object, array $callbacksPerType)\n    {\n        $results = [];\n\n        foreach ($callbacksPerType as $type => $callbacks) {\n            if ($type === $abstract || $object instanceof $type) {\n                $results = array_merge($results, $callbacks);\n            }\n        }\n\n        return $results;\n    }\n\n    /**\n     * Fire an array of callbacks with an object.\n     *\n     * @param  mixed  $object\n     * @param  array  $callbacks\n     * @return void\n     */\n    protected function fireCallbackArray($object, array $callbacks)\n    {\n        foreach ($callbacks as $callback) {\n            $callback($object, $this);\n        }\n    }\n\n    /**\n     * Get the container's bindings.\n     *\n     * @return array\n     */\n    public function getBindings()\n    {\n        return $this->bindings;\n    }\n\n    /**\n     * Get the alias for an abstract if available.\n     *\n     * @param  string  $abstract\n     * @return string\n     */\n    public function getAlias($abstract)\n    {\n        return isset($this->aliases[$abstract])\n                    ? $this->getAlias($this->aliases[$abstract])\n                    : $abstract;\n    }\n\n    /**\n     * Get the extender callbacks for a given type.\n     *\n     * @param  string  $abstract\n     * @return array\n     */\n    protected function getExtenders($abstract)\n    {\n        return $this->extenders[$this->getAlias($abstract)] ?? [];\n    }\n\n    /**\n     * Remove all of the extender callbacks for a given type.\n     *\n     * @param  string  $abstract\n     * @return void\n     */\n    public function forgetExtenders($abstract)\n    {\n        unset($this->extenders[$this->getAlias($abstract)]);\n    }\n\n    /**\n     * Drop all of the stale instances and aliases.\n     *\n     * @param  string  $abstract\n     * @return void\n     */\n    protected function dropStaleInstances($abstract)\n    {\n        unset($this->instances[$abstract], $this->aliases[$abstract]);\n    }\n\n    /**\n     * Remove a resolved instance from the instance cache.\n     *\n     * @param  string  $abstract\n     * @return void\n     */\n    public function forgetInstance($abstract)\n    {\n        unset($this->instances[$abstract]);\n    }\n\n    /**\n     * Clear all of the instances from the container.\n     *\n     * @return void\n     */\n    public function forgetInstances()\n    {\n        $this->instances = [];\n    }\n\n    /**\n     * Clear all of the scoped instances from the container.\n     *\n     * @return void\n     */\n    public function forgetScopedInstances()\n    {\n        foreach ($this->scopedInstances as $scoped) {\n            unset($this->instances[$scoped]);\n        }\n    }\n\n    /**\n     * Flush the container of all bindings and resolved instances.\n     *\n     * @return void\n     */\n    public function flush()\n    {\n        $this->aliases = [];\n        $this->resolved = [];\n        $this->bindings = [];\n        $this->instances = [];\n        $this->abstractAliases = [];\n        $this->scopedInstances = [];\n    }\n\n    /**\n     * Get the globally available instance of the container.\n     *\n     * @return static\n     */\n    public static function getInstance()\n    {\n        if (is_null(static::$instance)) {\n            static::$instance = new static;\n        }\n\n        return static::$instance;\n    }\n\n    /**\n     * Set the shared instance of the container.\n     *\n     * @param  \\Illuminate\\Contracts\\Container\\Container|null  $container\n     * @return \\Illuminate\\Contracts\\Container\\Container|static\n     */\n    public static function setInstance(ContainerContract $container = null)\n    {\n        return static::$instance = $container;\n    }\n\n    /**\n     * Determine if a given offset exists.\n     *\n     * @param  string  $key\n     * @return bool\n     */\n    #[\\ReturnTypeWillChange]\n    public function offsetExists($key)\n    {\n        return $this->bound($key);\n    }\n\n    /**\n     * Get the value at a given offset.\n     *\n     * @param  string  $key\n     * @return mixed\n     */\n    #[\\ReturnTypeWillChange]\n    public function offsetGet($key)\n    {\n        return $this->make($key);\n    }\n\n    /**\n     * Set the value at a given offset.\n     *\n     * @param  string  $key\n     * @param  mixed  $value\n     * @return void\n     */\n    #[\\ReturnTypeWillChange]\n    public function offsetSet($key, $value)\n    {\n        $this->bind($key, $value instanceof Closure ? $value : function () use ($value) {\n            return $value;\n        });\n    }\n\n    /**\n     * Unset the value at a given offset.\n     *\n     * @param  string  $key\n     * @return void\n     */\n    #[\\ReturnTypeWillChange]\n    public function offsetUnset($key)\n    {\n        unset($this->bindings[$key], $this->instances[$key], $this->resolved[$key]);\n    }\n\n    /**\n     * Dynamically access container services.\n     *\n     * @param  string  $key\n     * @return mixed\n     */\n    public function __get($key)\n    {\n        return $this[$key];\n    }\n\n    /**\n     * Dynamically set container services.\n     *\n     * @param  string  $key\n     * @param  mixed  $value\n     * @return void\n     */\n    public function __set($key, $value)\n    {\n        $this[$key] = $value;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/container/ContextualBindingBuilder.php",
    "content": "<?php\n\nnamespace Illuminate\\Container;\n\nuse Illuminate\\Contracts\\Container\\Container;\nuse Illuminate\\Contracts\\Container\\ContextualBindingBuilder as ContextualBindingBuilderContract;\n\nclass ContextualBindingBuilder implements ContextualBindingBuilderContract\n{\n    /**\n     * The underlying container instance.\n     *\n     * @var \\Illuminate\\Contracts\\Container\\Container\n     */\n    protected $container;\n\n    /**\n     * The concrete instance.\n     *\n     * @var string|array\n     */\n    protected $concrete;\n\n    /**\n     * The abstract target.\n     *\n     * @var string\n     */\n    protected $needs;\n\n    /**\n     * Create a new contextual binding builder.\n     *\n     * @param  \\Illuminate\\Contracts\\Container\\Container  $container\n     * @param  string|array  $concrete\n     * @return void\n     */\n    public function __construct(Container $container, $concrete)\n    {\n        $this->concrete = $concrete;\n        $this->container = $container;\n    }\n\n    /**\n     * Define the abstract target that depends on the context.\n     *\n     * @param  string  $abstract\n     * @return $this\n     */\n    public function needs($abstract)\n    {\n        $this->needs = $abstract;\n\n        return $this;\n    }\n\n    /**\n     * Define the implementation for the contextual binding.\n     *\n     * @param  \\Closure|string|array  $implementation\n     * @return void\n     */\n    public function give($implementation)\n    {\n        foreach (Util::arrayWrap($this->concrete) as $concrete) {\n            $this->container->addContextualBinding($concrete, $this->needs, $implementation);\n        }\n    }\n\n    /**\n     * Define tagged services to be used as the implementation for the contextual binding.\n     *\n     * @param  string  $tag\n     * @return void\n     */\n    public function giveTagged($tag)\n    {\n        $this->give(function ($container) use ($tag) {\n            $taggedServices = $container->tagged($tag);\n\n            return is_array($taggedServices) ? $taggedServices : iterator_to_array($taggedServices);\n        });\n    }\n\n    /**\n     * Specify the configuration item to bind as a primitive.\n     *\n     * @param  string  $key\n     * @param  ?string  $default\n     * @return void\n     */\n    public function giveConfig($key, $default = null)\n    {\n        $this->give(function ($container) use ($key, $default) {\n            return $container->get('config')->get($key, $default);\n        });\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/container/EntryNotFoundException.php",
    "content": "<?php\n\nnamespace Illuminate\\Container;\n\nuse Exception;\nuse Psr\\Container\\NotFoundExceptionInterface;\n\nclass EntryNotFoundException extends Exception implements NotFoundExceptionInterface\n{\n    //\n}\n"
  },
  {
    "path": "server/vendor/illuminate/container/LICENSE.md",
    "content": "The MIT License (MIT)\n\nCopyright (c) Taylor Otwell\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "server/vendor/illuminate/container/RewindableGenerator.php",
    "content": "<?php\n\nnamespace Illuminate\\Container;\n\nuse Countable;\nuse IteratorAggregate;\n\nclass RewindableGenerator implements Countable, IteratorAggregate\n{\n    /**\n     * The generator callback.\n     *\n     * @var callable\n     */\n    protected $generator;\n\n    /**\n     * The number of tagged services.\n     *\n     * @var callable|int\n     */\n    protected $count;\n\n    /**\n     * Create a new generator instance.\n     *\n     * @param  callable  $generator\n     * @param  callable|int  $count\n     * @return void\n     */\n    public function __construct(callable $generator, $count)\n    {\n        $this->count = $count;\n        $this->generator = $generator;\n    }\n\n    /**\n     * Get an iterator from the generator.\n     *\n     * @return mixed\n     */\n    #[\\ReturnTypeWillChange]\n    public function getIterator()\n    {\n        return ($this->generator)();\n    }\n\n    /**\n     * Get the total number of tagged services.\n     *\n     * @return int\n     */\n    #[\\ReturnTypeWillChange]\n    public function count()\n    {\n        if (is_callable($count = $this->count)) {\n            $this->count = $count();\n        }\n\n        return $this->count;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/container/Util.php",
    "content": "<?php\n\nnamespace Illuminate\\Container;\n\nuse Closure;\nuse ReflectionNamedType;\n\n/**\n * @internal\n */\nclass Util\n{\n    /**\n     * If the given value is not an array and not null, wrap it in one.\n     *\n     * From Arr::wrap() in Illuminate\\Support.\n     *\n     * @param  mixed  $value\n     * @return array\n     */\n    public static function arrayWrap($value)\n    {\n        if (is_null($value)) {\n            return [];\n        }\n\n        return is_array($value) ? $value : [$value];\n    }\n\n    /**\n     * Return the default value of the given value.\n     *\n     * From global value() helper in Illuminate\\Support.\n     *\n     * @param  mixed  $value\n     * @return mixed\n     */\n    public static function unwrapIfClosure($value)\n    {\n        return $value instanceof Closure ? $value() : $value;\n    }\n\n    /**\n     * Get the class name of the given parameter's type, if possible.\n     *\n     * From Reflector::getParameterClassName() in Illuminate\\Support.\n     *\n     * @param  \\ReflectionParameter  $parameter\n     * @return string|null\n     */\n    public static function getParameterClassName($parameter)\n    {\n        $type = $parameter->getType();\n\n        if (! $type instanceof ReflectionNamedType || $type->isBuiltin()) {\n            return null;\n        }\n\n        $name = $type->getName();\n\n        if (! is_null($class = $parameter->getDeclaringClass())) {\n            if ($name === 'self') {\n                return $class->getName();\n            }\n\n            if ($name === 'parent' && $parent = $class->getParentClass()) {\n                return $parent->getName();\n            }\n        }\n\n        return $name;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/container/composer.json",
    "content": "{\n    \"name\": \"illuminate/container\",\n    \"description\": \"The Illuminate Container package.\",\n    \"license\": \"MIT\",\n    \"homepage\": \"https://laravel.com\",\n    \"support\": {\n        \"issues\": \"https://github.com/laravel/framework/issues\",\n        \"source\": \"https://github.com/laravel/framework\"\n    },\n    \"authors\": [\n        {\n            \"name\": \"Taylor Otwell\",\n            \"email\": \"taylor@laravel.com\"\n        }\n    ],\n    \"require\": {\n        \"php\": \"^7.3|^8.0\",\n        \"illuminate/contracts\": \"^8.0\",\n        \"psr/container\": \"^1.0\"\n    },\n    \"provide\": {\n        \"psr/container-implementation\": \"1.0\"\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"Illuminate\\\\Container\\\\\": \"\"\n        }\n    },\n    \"extra\": {\n        \"branch-alias\": {\n            \"dev-master\": \"8.x-dev\"\n        }\n    },\n    \"config\": {\n        \"sort-packages\": true\n    },\n    \"minimum-stability\": \"dev\"\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Auth/Access/Authorizable.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Auth\\Access;\n\ninterface Authorizable\n{\n    /**\n     * Determine if the entity has a given ability.\n     *\n     * @param  iterable|string  $abilities\n     * @param  array|mixed  $arguments\n     * @return bool\n     */\n    public function can($abilities, $arguments = []);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Auth/Access/Gate.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Auth\\Access;\n\ninterface Gate\n{\n    /**\n     * Determine if a given ability has been defined.\n     *\n     * @param  string  $ability\n     * @return bool\n     */\n    public function has($ability);\n\n    /**\n     * Define a new ability.\n     *\n     * @param  string  $ability\n     * @param  callable|string  $callback\n     * @return $this\n     */\n    public function define($ability, $callback);\n\n    /**\n     * Define abilities for a resource.\n     *\n     * @param  string  $name\n     * @param  string  $class\n     * @param  array|null  $abilities\n     * @return $this\n     */\n    public function resource($name, $class, array $abilities = null);\n\n    /**\n     * Define a policy class for a given class type.\n     *\n     * @param  string  $class\n     * @param  string  $policy\n     * @return $this\n     */\n    public function policy($class, $policy);\n\n    /**\n     * Register a callback to run before all Gate checks.\n     *\n     * @param  callable  $callback\n     * @return $this\n     */\n    public function before(callable $callback);\n\n    /**\n     * Register a callback to run after all Gate checks.\n     *\n     * @param  callable  $callback\n     * @return $this\n     */\n    public function after(callable $callback);\n\n    /**\n     * Determine if the given ability should be granted for the current user.\n     *\n     * @param  string  $ability\n     * @param  array|mixed  $arguments\n     * @return bool\n     */\n    public function allows($ability, $arguments = []);\n\n    /**\n     * Determine if the given ability should be denied for the current user.\n     *\n     * @param  string  $ability\n     * @param  array|mixed  $arguments\n     * @return bool\n     */\n    public function denies($ability, $arguments = []);\n\n    /**\n     * Determine if all of the given abilities should be granted for the current user.\n     *\n     * @param  iterable|string  $abilities\n     * @param  array|mixed  $arguments\n     * @return bool\n     */\n    public function check($abilities, $arguments = []);\n\n    /**\n     * Determine if any one of the given abilities should be granted for the current user.\n     *\n     * @param  iterable|string  $abilities\n     * @param  array|mixed  $arguments\n     * @return bool\n     */\n    public function any($abilities, $arguments = []);\n\n    /**\n     * Determine if the given ability should be granted for the current user.\n     *\n     * @param  string  $ability\n     * @param  array|mixed  $arguments\n     * @return \\Illuminate\\Auth\\Access\\Response\n     *\n     * @throws \\Illuminate\\Auth\\Access\\AuthorizationException\n     */\n    public function authorize($ability, $arguments = []);\n\n    /**\n     * Inspect the user for the given ability.\n     *\n     * @param  string  $ability\n     * @param  array|mixed  $arguments\n     * @return \\Illuminate\\Auth\\Access\\Response\n     */\n    public function inspect($ability, $arguments = []);\n\n    /**\n     * Get the raw result from the authorization callback.\n     *\n     * @param  string  $ability\n     * @param  array|mixed  $arguments\n     * @return mixed\n     *\n     * @throws \\Illuminate\\Auth\\Access\\AuthorizationException\n     */\n    public function raw($ability, $arguments = []);\n\n    /**\n     * Get a policy instance for a given class.\n     *\n     * @param  object|string  $class\n     * @return mixed\n     *\n     * @throws \\InvalidArgumentException\n     */\n    public function getPolicyFor($class);\n\n    /**\n     * Get a guard instance for the given user.\n     *\n     * @param  \\Illuminate\\Contracts\\Auth\\Authenticatable|mixed  $user\n     * @return static\n     */\n    public function forUser($user);\n\n    /**\n     * Get all of the defined abilities.\n     *\n     * @return array\n     */\n    public function abilities();\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Auth/Authenticatable.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Auth;\n\ninterface Authenticatable\n{\n    /**\n     * Get the name of the unique identifier for the user.\n     *\n     * @return string\n     */\n    public function getAuthIdentifierName();\n\n    /**\n     * Get the unique identifier for the user.\n     *\n     * @return mixed\n     */\n    public function getAuthIdentifier();\n\n    /**\n     * Get the password for the user.\n     *\n     * @return string\n     */\n    public function getAuthPassword();\n\n    /**\n     * Get the token value for the \"remember me\" session.\n     *\n     * @return string\n     */\n    public function getRememberToken();\n\n    /**\n     * Set the token value for the \"remember me\" session.\n     *\n     * @param  string  $value\n     * @return void\n     */\n    public function setRememberToken($value);\n\n    /**\n     * Get the column name for the \"remember me\" token.\n     *\n     * @return string\n     */\n    public function getRememberTokenName();\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Auth/CanResetPassword.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Auth;\n\ninterface CanResetPassword\n{\n    /**\n     * Get the e-mail address where password reset links are sent.\n     *\n     * @return string\n     */\n    public function getEmailForPasswordReset();\n\n    /**\n     * Send the password reset notification.\n     *\n     * @param  string  $token\n     * @return void\n     */\n    public function sendPasswordResetNotification($token);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Auth/Factory.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Auth;\n\ninterface Factory\n{\n    /**\n     * Get a guard instance by name.\n     *\n     * @param  string|null  $name\n     * @return \\Illuminate\\Contracts\\Auth\\Guard|\\Illuminate\\Contracts\\Auth\\StatefulGuard\n     */\n    public function guard($name = null);\n\n    /**\n     * Set the default guard the factory should serve.\n     *\n     * @param  string  $name\n     * @return void\n     */\n    public function shouldUse($name);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Auth/Guard.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Auth;\n\ninterface Guard\n{\n    /**\n     * Determine if the current user is authenticated.\n     *\n     * @return bool\n     */\n    public function check();\n\n    /**\n     * Determine if the current user is a guest.\n     *\n     * @return bool\n     */\n    public function guest();\n\n    /**\n     * Get the currently authenticated user.\n     *\n     * @return \\Illuminate\\Contracts\\Auth\\Authenticatable|null\n     */\n    public function user();\n\n    /**\n     * Get the ID for the currently authenticated user.\n     *\n     * @return int|string|null\n     */\n    public function id();\n\n    /**\n     * Validate a user's credentials.\n     *\n     * @param  array  $credentials\n     * @return bool\n     */\n    public function validate(array $credentials = []);\n\n    /**\n     * Set the current user.\n     *\n     * @param  \\Illuminate\\Contracts\\Auth\\Authenticatable  $user\n     * @return void\n     */\n    public function setUser(Authenticatable $user);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Auth/Middleware/AuthenticatesRequests.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Auth\\Middleware;\n\ninterface AuthenticatesRequests\n{\n    //\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Auth/MustVerifyEmail.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Auth;\n\ninterface MustVerifyEmail\n{\n    /**\n     * Determine if the user has verified their email address.\n     *\n     * @return bool\n     */\n    public function hasVerifiedEmail();\n\n    /**\n     * Mark the given user's email as verified.\n     *\n     * @return bool\n     */\n    public function markEmailAsVerified();\n\n    /**\n     * Send the email verification notification.\n     *\n     * @return void\n     */\n    public function sendEmailVerificationNotification();\n\n    /**\n     * Get the email address that should be used for verification.\n     *\n     * @return string\n     */\n    public function getEmailForVerification();\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Auth/PasswordBroker.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Auth;\n\nuse Closure;\n\ninterface PasswordBroker\n{\n    /**\n     * Constant representing a successfully sent reminder.\n     *\n     * @var string\n     */\n    const RESET_LINK_SENT = 'passwords.sent';\n\n    /**\n     * Constant representing a successfully reset password.\n     *\n     * @var string\n     */\n    const PASSWORD_RESET = 'passwords.reset';\n\n    /**\n     * Constant representing the user not found response.\n     *\n     * @var string\n     */\n    const INVALID_USER = 'passwords.user';\n\n    /**\n     * Constant representing an invalid token.\n     *\n     * @var string\n     */\n    const INVALID_TOKEN = 'passwords.token';\n\n    /**\n     * Constant representing a throttled reset attempt.\n     *\n     * @var string\n     */\n    const RESET_THROTTLED = 'passwords.throttled';\n\n    /**\n     * Send a password reset link to a user.\n     *\n     * @param  array  $credentials\n     * @param  \\Closure|null  $callback\n     * @return string\n     */\n    public function sendResetLink(array $credentials, Closure $callback = null);\n\n    /**\n     * Reset the password for the given token.\n     *\n     * @param  array  $credentials\n     * @param  \\Closure  $callback\n     * @return mixed\n     */\n    public function reset(array $credentials, Closure $callback);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Auth/PasswordBrokerFactory.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Auth;\n\ninterface PasswordBrokerFactory\n{\n    /**\n     * Get a password broker instance by name.\n     *\n     * @param  string|null  $name\n     * @return mixed\n     */\n    public function broker($name = null);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Auth/StatefulGuard.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Auth;\n\ninterface StatefulGuard extends Guard\n{\n    /**\n     * Attempt to authenticate a user using the given credentials.\n     *\n     * @param  array  $credentials\n     * @param  bool  $remember\n     * @return bool\n     */\n    public function attempt(array $credentials = [], $remember = false);\n\n    /**\n     * Log a user into the application without sessions or cookies.\n     *\n     * @param  array  $credentials\n     * @return bool\n     */\n    public function once(array $credentials = []);\n\n    /**\n     * Log a user into the application.\n     *\n     * @param  \\Illuminate\\Contracts\\Auth\\Authenticatable  $user\n     * @param  bool  $remember\n     * @return void\n     */\n    public function login(Authenticatable $user, $remember = false);\n\n    /**\n     * Log the given user ID into the application.\n     *\n     * @param  mixed  $id\n     * @param  bool  $remember\n     * @return \\Illuminate\\Contracts\\Auth\\Authenticatable|bool\n     */\n    public function loginUsingId($id, $remember = false);\n\n    /**\n     * Log the given user ID into the application without sessions or cookies.\n     *\n     * @param  mixed  $id\n     * @return \\Illuminate\\Contracts\\Auth\\Authenticatable|bool\n     */\n    public function onceUsingId($id);\n\n    /**\n     * Determine if the user was authenticated via \"remember me\" cookie.\n     *\n     * @return bool\n     */\n    public function viaRemember();\n\n    /**\n     * Log the user out of the application.\n     *\n     * @return void\n     */\n    public function logout();\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Auth/SupportsBasicAuth.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Auth;\n\ninterface SupportsBasicAuth\n{\n    /**\n     * Attempt to authenticate using HTTP Basic Auth.\n     *\n     * @param  string  $field\n     * @param  array  $extraConditions\n     * @return \\Symfony\\Component\\HttpFoundation\\Response|null\n     */\n    public function basic($field = 'email', $extraConditions = []);\n\n    /**\n     * Perform a stateless HTTP Basic login attempt.\n     *\n     * @param  string  $field\n     * @param  array  $extraConditions\n     * @return \\Symfony\\Component\\HttpFoundation\\Response|null\n     */\n    public function onceBasic($field = 'email', $extraConditions = []);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Auth/UserProvider.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Auth;\n\ninterface UserProvider\n{\n    /**\n     * Retrieve a user by their unique identifier.\n     *\n     * @param  mixed  $identifier\n     * @return \\Illuminate\\Contracts\\Auth\\Authenticatable|null\n     */\n    public function retrieveById($identifier);\n\n    /**\n     * Retrieve a user by their unique identifier and \"remember me\" token.\n     *\n     * @param  mixed  $identifier\n     * @param  string  $token\n     * @return \\Illuminate\\Contracts\\Auth\\Authenticatable|null\n     */\n    public function retrieveByToken($identifier, $token);\n\n    /**\n     * Update the \"remember me\" token for the given user in storage.\n     *\n     * @param  \\Illuminate\\Contracts\\Auth\\Authenticatable  $user\n     * @param  string  $token\n     * @return void\n     */\n    public function updateRememberToken(Authenticatable $user, $token);\n\n    /**\n     * Retrieve a user by the given credentials.\n     *\n     * @param  array  $credentials\n     * @return \\Illuminate\\Contracts\\Auth\\Authenticatable|null\n     */\n    public function retrieveByCredentials(array $credentials);\n\n    /**\n     * Validate a user against the given credentials.\n     *\n     * @param  \\Illuminate\\Contracts\\Auth\\Authenticatable  $user\n     * @param  array  $credentials\n     * @return bool\n     */\n    public function validateCredentials(Authenticatable $user, array $credentials);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Broadcasting/Broadcaster.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Broadcasting;\n\ninterface Broadcaster\n{\n    /**\n     * Authenticate the incoming request for a given channel.\n     *\n     * @param  \\Illuminate\\Http\\Request  $request\n     * @return mixed\n     */\n    public function auth($request);\n\n    /**\n     * Return the valid authentication response.\n     *\n     * @param  \\Illuminate\\Http\\Request  $request\n     * @param  mixed  $result\n     * @return mixed\n     */\n    public function validAuthenticationResponse($request, $result);\n\n    /**\n     * Broadcast the given event.\n     *\n     * @param  array  $channels\n     * @param  string  $event\n     * @param  array  $payload\n     * @return void\n     */\n    public function broadcast(array $channels, $event, array $payload = []);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Broadcasting/Factory.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Broadcasting;\n\ninterface Factory\n{\n    /**\n     * Get a broadcaster implementation by name.\n     *\n     * @param  string|null  $name\n     * @return \\Illuminate\\Contracts\\Broadcasting\\Broadcaster\n     */\n    public function connection($name = null);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Broadcasting/HasBroadcastChannel.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Broadcasting;\n\ninterface HasBroadcastChannel\n{\n    /**\n     * Get the broadcast channel route definition that is associated with the given entity.\n     *\n     * @return string\n     */\n    public function broadcastChannelRoute();\n\n    /**\n     * Get the broadcast channel name that is associated with the given entity.\n     *\n     * @return string\n     */\n    public function broadcastChannel();\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Broadcasting/ShouldBroadcast.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Broadcasting;\n\ninterface ShouldBroadcast\n{\n    /**\n     * Get the channels the event should broadcast on.\n     *\n     * @return \\Illuminate\\Broadcasting\\Channel|\\Illuminate\\Broadcasting\\Channel[]|string[]|string\n     */\n    public function broadcastOn();\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Broadcasting/ShouldBroadcastNow.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Broadcasting;\n\ninterface ShouldBroadcastNow extends ShouldBroadcast\n{\n    //\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Bus/Dispatcher.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Bus;\n\ninterface Dispatcher\n{\n    /**\n     * Dispatch a command to its appropriate handler.\n     *\n     * @param  mixed  $command\n     * @return mixed\n     */\n    public function dispatch($command);\n\n    /**\n     * Dispatch a command to its appropriate handler in the current process.\n     *\n     * Queueable jobs will be dispatched to the \"sync\" queue.\n     *\n     * @param  mixed  $command\n     * @param  mixed  $handler\n     * @return mixed\n     */\n    public function dispatchSync($command, $handler = null);\n\n    /**\n     * Dispatch a command to its appropriate handler in the current process.\n     *\n     * @param  mixed  $command\n     * @param  mixed  $handler\n     * @return mixed\n     */\n    public function dispatchNow($command, $handler = null);\n\n    /**\n     * Determine if the given command has a handler.\n     *\n     * @param  mixed  $command\n     * @return bool\n     */\n    public function hasCommandHandler($command);\n\n    /**\n     * Retrieve the handler for a command.\n     *\n     * @param  mixed  $command\n     * @return bool|mixed\n     */\n    public function getCommandHandler($command);\n\n    /**\n     * Set the pipes commands should be piped through before dispatching.\n     *\n     * @param  array  $pipes\n     * @return $this\n     */\n    public function pipeThrough(array $pipes);\n\n    /**\n     * Map a command to a handler.\n     *\n     * @param  array  $map\n     * @return $this\n     */\n    public function map(array $map);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Bus/QueueingDispatcher.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Bus;\n\ninterface QueueingDispatcher extends Dispatcher\n{\n    /**\n     * Attempt to find the batch with the given ID.\n     *\n     * @param  string  $batchId\n     * @return \\Illuminate\\Bus\\Batch|null\n     */\n    public function findBatch(string $batchId);\n\n    /**\n     * Create a new batch of queueable jobs.\n     *\n     * @param  \\Illuminate\\Support\\Collection|array  $jobs\n     * @return \\Illuminate\\Bus\\PendingBatch\n     */\n    public function batch($jobs);\n\n    /**\n     * Dispatch a command to its appropriate handler behind a queue.\n     *\n     * @param  mixed  $command\n     * @return mixed\n     */\n    public function dispatchToQueue($command);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Cache/Factory.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Cache;\n\ninterface Factory\n{\n    /**\n     * Get a cache store instance by name.\n     *\n     * @param  string|null  $name\n     * @return \\Illuminate\\Contracts\\Cache\\Repository\n     */\n    public function store($name = null);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Cache/Lock.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Cache;\n\ninterface Lock\n{\n    /**\n     * Attempt to acquire the lock.\n     *\n     * @param  callable|null  $callback\n     * @return mixed\n     */\n    public function get($callback = null);\n\n    /**\n     * Attempt to acquire the lock for the given number of seconds.\n     *\n     * @param  int  $seconds\n     * @param  callable|null  $callback\n     * @return mixed\n     */\n    public function block($seconds, $callback = null);\n\n    /**\n     * Release the lock.\n     *\n     * @return bool\n     */\n    public function release();\n\n    /**\n     * Returns the current owner of the lock.\n     *\n     * @return string\n     */\n    public function owner();\n\n    /**\n     * Releases this lock in disregard of ownership.\n     *\n     * @return void\n     */\n    public function forceRelease();\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Cache/LockProvider.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Cache;\n\ninterface LockProvider\n{\n    /**\n     * Get a lock instance.\n     *\n     * @param  string  $name\n     * @param  int  $seconds\n     * @param  string|null  $owner\n     * @return \\Illuminate\\Contracts\\Cache\\Lock\n     */\n    public function lock($name, $seconds = 0, $owner = null);\n\n    /**\n     * Restore a lock instance using the owner identifier.\n     *\n     * @param  string  $name\n     * @param  string  $owner\n     * @return \\Illuminate\\Contracts\\Cache\\Lock\n     */\n    public function restoreLock($name, $owner);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Cache/LockTimeoutException.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Cache;\n\nuse Exception;\n\nclass LockTimeoutException extends Exception\n{\n    //\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Cache/Repository.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Cache;\n\nuse Closure;\nuse Psr\\SimpleCache\\CacheInterface;\n\ninterface Repository extends CacheInterface\n{\n    /**\n     * Retrieve an item from the cache and delete it.\n     *\n     * @param  string  $key\n     * @param  mixed  $default\n     * @return mixed\n     */\n    public function pull($key, $default = null);\n\n    /**\n     * Store an item in the cache.\n     *\n     * @param  string  $key\n     * @param  mixed  $value\n     * @param  \\DateTimeInterface|\\DateInterval|int|null  $ttl\n     * @return bool\n     */\n    public function put($key, $value, $ttl = null);\n\n    /**\n     * Store an item in the cache if the key does not exist.\n     *\n     * @param  string  $key\n     * @param  mixed  $value\n     * @param  \\DateTimeInterface|\\DateInterval|int|null  $ttl\n     * @return bool\n     */\n    public function add($key, $value, $ttl = null);\n\n    /**\n     * Increment the value of an item in the cache.\n     *\n     * @param  string  $key\n     * @param  mixed  $value\n     * @return int|bool\n     */\n    public function increment($key, $value = 1);\n\n    /**\n     * Decrement the value of an item in the cache.\n     *\n     * @param  string  $key\n     * @param  mixed  $value\n     * @return int|bool\n     */\n    public function decrement($key, $value = 1);\n\n    /**\n     * Store an item in the cache indefinitely.\n     *\n     * @param  string  $key\n     * @param  mixed  $value\n     * @return bool\n     */\n    public function forever($key, $value);\n\n    /**\n     * Get an item from the cache, or execute the given Closure and store the result.\n     *\n     * @param  string  $key\n     * @param  \\DateTimeInterface|\\DateInterval|int|null  $ttl\n     * @param  \\Closure  $callback\n     * @return mixed\n     */\n    public function remember($key, $ttl, Closure $callback);\n\n    /**\n     * Get an item from the cache, or execute the given Closure and store the result forever.\n     *\n     * @param  string  $key\n     * @param  \\Closure  $callback\n     * @return mixed\n     */\n    public function sear($key, Closure $callback);\n\n    /**\n     * Get an item from the cache, or execute the given Closure and store the result forever.\n     *\n     * @param  string  $key\n     * @param  \\Closure  $callback\n     * @return mixed\n     */\n    public function rememberForever($key, Closure $callback);\n\n    /**\n     * Remove an item from the cache.\n     *\n     * @param  string  $key\n     * @return bool\n     */\n    public function forget($key);\n\n    /**\n     * Get the cache store implementation.\n     *\n     * @return \\Illuminate\\Contracts\\Cache\\Store\n     */\n    public function getStore();\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Cache/Store.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Cache;\n\ninterface Store\n{\n    /**\n     * Retrieve an item from the cache by key.\n     *\n     * @param  string|array  $key\n     * @return mixed\n     */\n    public function get($key);\n\n    /**\n     * Retrieve multiple items from the cache by key.\n     *\n     * Items not found in the cache will have a null value.\n     *\n     * @param  array  $keys\n     * @return array\n     */\n    public function many(array $keys);\n\n    /**\n     * Store an item in the cache for a given number of seconds.\n     *\n     * @param  string  $key\n     * @param  mixed  $value\n     * @param  int  $seconds\n     * @return bool\n     */\n    public function put($key, $value, $seconds);\n\n    /**\n     * Store multiple items in the cache for a given number of seconds.\n     *\n     * @param  array  $values\n     * @param  int  $seconds\n     * @return bool\n     */\n    public function putMany(array $values, $seconds);\n\n    /**\n     * Increment the value of an item in the cache.\n     *\n     * @param  string  $key\n     * @param  mixed  $value\n     * @return int|bool\n     */\n    public function increment($key, $value = 1);\n\n    /**\n     * Decrement the value of an item in the cache.\n     *\n     * @param  string  $key\n     * @param  mixed  $value\n     * @return int|bool\n     */\n    public function decrement($key, $value = 1);\n\n    /**\n     * Store an item in the cache indefinitely.\n     *\n     * @param  string  $key\n     * @param  mixed  $value\n     * @return bool\n     */\n    public function forever($key, $value);\n\n    /**\n     * Remove an item from the cache.\n     *\n     * @param  string  $key\n     * @return bool\n     */\n    public function forget($key);\n\n    /**\n     * Remove all items from the cache.\n     *\n     * @return bool\n     */\n    public function flush();\n\n    /**\n     * Get the cache key prefix.\n     *\n     * @return string\n     */\n    public function getPrefix();\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Config/Repository.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Config;\n\ninterface Repository\n{\n    /**\n     * Determine if the given configuration value exists.\n     *\n     * @param  string  $key\n     * @return bool\n     */\n    public function has($key);\n\n    /**\n     * Get the specified configuration value.\n     *\n     * @param  array|string  $key\n     * @param  mixed  $default\n     * @return mixed\n     */\n    public function get($key, $default = null);\n\n    /**\n     * Get all of the configuration items for the application.\n     *\n     * @return array\n     */\n    public function all();\n\n    /**\n     * Set a given configuration value.\n     *\n     * @param  array|string  $key\n     * @param  mixed  $value\n     * @return void\n     */\n    public function set($key, $value = null);\n\n    /**\n     * Prepend a value onto an array configuration value.\n     *\n     * @param  string  $key\n     * @param  mixed  $value\n     * @return void\n     */\n    public function prepend($key, $value);\n\n    /**\n     * Push a value onto an array configuration value.\n     *\n     * @param  string  $key\n     * @param  mixed  $value\n     * @return void\n     */\n    public function push($key, $value);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Console/Application.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Console;\n\ninterface Application\n{\n    /**\n     * Run an Artisan console command by name.\n     *\n     * @param  string  $command\n     * @param  array  $parameters\n     * @param  \\Symfony\\Component\\Console\\Output\\OutputInterface|null  $outputBuffer\n     * @return int\n     */\n    public function call($command, array $parameters = [], $outputBuffer = null);\n\n    /**\n     * Get the output from the last command.\n     *\n     * @return string\n     */\n    public function output();\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Console/Kernel.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Console;\n\ninterface Kernel\n{\n    /**\n     * Bootstrap the application for artisan commands.\n     *\n     * @return void\n     */\n    public function bootstrap();\n\n    /**\n     * Handle an incoming console command.\n     *\n     * @param  \\Symfony\\Component\\Console\\Input\\InputInterface  $input\n     * @param  \\Symfony\\Component\\Console\\Output\\OutputInterface|null  $output\n     * @return int\n     */\n    public function handle($input, $output = null);\n\n    /**\n     * Run an Artisan console command by name.\n     *\n     * @param  string  $command\n     * @param  array  $parameters\n     * @param  \\Symfony\\Component\\Console\\Output\\OutputInterface|null  $outputBuffer\n     * @return int\n     */\n    public function call($command, array $parameters = [], $outputBuffer = null);\n\n    /**\n     * Queue an Artisan console command by name.\n     *\n     * @param  string  $command\n     * @param  array  $parameters\n     * @return \\Illuminate\\Foundation\\Bus\\PendingDispatch\n     */\n    public function queue($command, array $parameters = []);\n\n    /**\n     * Get all of the commands registered with the console.\n     *\n     * @return array\n     */\n    public function all();\n\n    /**\n     * Get the output for the last run command.\n     *\n     * @return string\n     */\n    public function output();\n\n    /**\n     * Terminate the application.\n     *\n     * @param  \\Symfony\\Component\\Console\\Input\\InputInterface  $input\n     * @param  int  $status\n     * @return void\n     */\n    public function terminate($input, $status);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Container/BindingResolutionException.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Container;\n\nuse Exception;\nuse Psr\\Container\\ContainerExceptionInterface;\n\nclass BindingResolutionException extends Exception implements ContainerExceptionInterface\n{\n    //\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Container/CircularDependencyException.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Container;\n\nuse Exception;\nuse Psr\\Container\\ContainerExceptionInterface;\n\nclass CircularDependencyException extends Exception implements ContainerExceptionInterface\n{\n    //\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Container/Container.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Container;\n\nuse Closure;\nuse Psr\\Container\\ContainerInterface;\n\ninterface Container extends ContainerInterface\n{\n    /**\n     * Determine if the given abstract type has been bound.\n     *\n     * @param  string  $abstract\n     * @return bool\n     */\n    public function bound($abstract);\n\n    /**\n     * Alias a type to a different name.\n     *\n     * @param  string  $abstract\n     * @param  string  $alias\n     * @return void\n     *\n     * @throws \\LogicException\n     */\n    public function alias($abstract, $alias);\n\n    /**\n     * Assign a set of tags to a given binding.\n     *\n     * @param  array|string  $abstracts\n     * @param  array|mixed  ...$tags\n     * @return void\n     */\n    public function tag($abstracts, $tags);\n\n    /**\n     * Resolve all of the bindings for a given tag.\n     *\n     * @param  string  $tag\n     * @return iterable\n     */\n    public function tagged($tag);\n\n    /**\n     * Register a binding with the container.\n     *\n     * @param  string  $abstract\n     * @param  \\Closure|string|null  $concrete\n     * @param  bool  $shared\n     * @return void\n     */\n    public function bind($abstract, $concrete = null, $shared = false);\n\n    /**\n     * Register a binding if it hasn't already been registered.\n     *\n     * @param  string  $abstract\n     * @param  \\Closure|string|null  $concrete\n     * @param  bool  $shared\n     * @return void\n     */\n    public function bindIf($abstract, $concrete = null, $shared = false);\n\n    /**\n     * Register a shared binding in the container.\n     *\n     * @param  string  $abstract\n     * @param  \\Closure|string|null  $concrete\n     * @return void\n     */\n    public function singleton($abstract, $concrete = null);\n\n    /**\n     * Register a shared binding if it hasn't already been registered.\n     *\n     * @param  string  $abstract\n     * @param  \\Closure|string|null  $concrete\n     * @return void\n     */\n    public function singletonIf($abstract, $concrete = null);\n\n    /**\n     * \"Extend\" an abstract type in the container.\n     *\n     * @param  string  $abstract\n     * @param  \\Closure  $closure\n     * @return void\n     *\n     * @throws \\InvalidArgumentException\n     */\n    public function extend($abstract, Closure $closure);\n\n    /**\n     * Register an existing instance as shared in the container.\n     *\n     * @param  string  $abstract\n     * @param  mixed  $instance\n     * @return mixed\n     */\n    public function instance($abstract, $instance);\n\n    /**\n     * Add a contextual binding to the container.\n     *\n     * @param  string  $concrete\n     * @param  string  $abstract\n     * @param  \\Closure|string  $implementation\n     * @return void\n     */\n    public function addContextualBinding($concrete, $abstract, $implementation);\n\n    /**\n     * Define a contextual binding.\n     *\n     * @param  string|array  $concrete\n     * @return \\Illuminate\\Contracts\\Container\\ContextualBindingBuilder\n     */\n    public function when($concrete);\n\n    /**\n     * Get a closure to resolve the given type from the container.\n     *\n     * @param  string  $abstract\n     * @return \\Closure\n     */\n    public function factory($abstract);\n\n    /**\n     * Flush the container of all bindings and resolved instances.\n     *\n     * @return void\n     */\n    public function flush();\n\n    /**\n     * Resolve the given type from the container.\n     *\n     * @param  string  $abstract\n     * @param  array  $parameters\n     * @return mixed\n     *\n     * @throws \\Illuminate\\Contracts\\Container\\BindingResolutionException\n     */\n    public function make($abstract, array $parameters = []);\n\n    /**\n     * Call the given Closure / class@method and inject its dependencies.\n     *\n     * @param  callable|string  $callback\n     * @param  array  $parameters\n     * @param  string|null  $defaultMethod\n     * @return mixed\n     */\n    public function call($callback, array $parameters = [], $defaultMethod = null);\n\n    /**\n     * Determine if the given abstract type has been resolved.\n     *\n     * @param  string  $abstract\n     * @return bool\n     */\n    public function resolved($abstract);\n\n    /**\n     * Register a new resolving callback.\n     *\n     * @param  \\Closure|string  $abstract\n     * @param  \\Closure|null  $callback\n     * @return void\n     */\n    public function resolving($abstract, Closure $callback = null);\n\n    /**\n     * Register a new after resolving callback.\n     *\n     * @param  \\Closure|string  $abstract\n     * @param  \\Closure|null  $callback\n     * @return void\n     */\n    public function afterResolving($abstract, Closure $callback = null);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Container/ContextualBindingBuilder.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Container;\n\ninterface ContextualBindingBuilder\n{\n    /**\n     * Define the abstract target that depends on the context.\n     *\n     * @param  string  $abstract\n     * @return $this\n     */\n    public function needs($abstract);\n\n    /**\n     * Define the implementation for the contextual binding.\n     *\n     * @param  \\Closure|string|array  $implementation\n     * @return void\n     */\n    public function give($implementation);\n\n    /**\n     * Define tagged services to be used as the implementation for the contextual binding.\n     *\n     * @param  string  $tag\n     * @return void\n     */\n    public function giveTagged($tag);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Cookie/Factory.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Cookie;\n\ninterface Factory\n{\n    /**\n     * Create a new cookie instance.\n     *\n     * @param  string  $name\n     * @param  string  $value\n     * @param  int  $minutes\n     * @param  string|null  $path\n     * @param  string|null  $domain\n     * @param  bool|null  $secure\n     * @param  bool  $httpOnly\n     * @param  bool  $raw\n     * @param  string|null  $sameSite\n     * @return \\Symfony\\Component\\HttpFoundation\\Cookie\n     */\n    public function make($name, $value, $minutes = 0, $path = null, $domain = null, $secure = null, $httpOnly = true, $raw = false, $sameSite = null);\n\n    /**\n     * Create a cookie that lasts \"forever\" (five years).\n     *\n     * @param  string  $name\n     * @param  string  $value\n     * @param  string|null  $path\n     * @param  string|null  $domain\n     * @param  bool|null  $secure\n     * @param  bool  $httpOnly\n     * @param  bool  $raw\n     * @param  string|null  $sameSite\n     * @return \\Symfony\\Component\\HttpFoundation\\Cookie\n     */\n    public function forever($name, $value, $path = null, $domain = null, $secure = null, $httpOnly = true, $raw = false, $sameSite = null);\n\n    /**\n     * Expire the given cookie.\n     *\n     * @param  string  $name\n     * @param  string|null  $path\n     * @param  string|null  $domain\n     * @return \\Symfony\\Component\\HttpFoundation\\Cookie\n     */\n    public function forget($name, $path = null, $domain = null);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Cookie/QueueingFactory.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Cookie;\n\ninterface QueueingFactory extends Factory\n{\n    /**\n     * Queue a cookie to send with the next response.\n     *\n     * @param  array  $parameters\n     * @return void\n     */\n    public function queue(...$parameters);\n\n    /**\n     * Remove a cookie from the queue.\n     *\n     * @param  string  $name\n     * @param  string|null  $path\n     * @return void\n     */\n    public function unqueue($name, $path = null);\n\n    /**\n     * Get the cookies which have been queued for the next request.\n     *\n     * @return array\n     */\n    public function getQueuedCookies();\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Database/Eloquent/Castable.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Database\\Eloquent;\n\ninterface Castable\n{\n    /**\n     * Get the name of the caster class to use when casting from / to this cast target.\n     *\n     * @param  array  $arguments\n     * @return string\n     * @return string|\\Illuminate\\Contracts\\Database\\Eloquent\\CastsAttributes|\\Illuminate\\Contracts\\Database\\Eloquent\\CastsInboundAttributes\n     */\n    public static function castUsing(array $arguments);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Database/Eloquent/CastsAttributes.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Database\\Eloquent;\n\ninterface CastsAttributes\n{\n    /**\n     * Transform the attribute from the underlying model values.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $model\n     * @param  string  $key\n     * @param  mixed  $value\n     * @param  array  $attributes\n     * @return mixed\n     */\n    public function get($model, string $key, $value, array $attributes);\n\n    /**\n     * Transform the attribute to its underlying model values.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $model\n     * @param  string  $key\n     * @param  mixed  $value\n     * @param  array  $attributes\n     * @return mixed\n     */\n    public function set($model, string $key, $value, array $attributes);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Database/Eloquent/CastsInboundAttributes.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Database\\Eloquent;\n\ninterface CastsInboundAttributes\n{\n    /**\n     * Transform the attribute to its underlying model values.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $model\n     * @param  string  $key\n     * @param  mixed  $value\n     * @param  array  $attributes\n     * @return mixed\n     */\n    public function set($model, string $key, $value, array $attributes);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Database/Eloquent/DeviatesCastableAttributes.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Database\\Eloquent;\n\ninterface DeviatesCastableAttributes\n{\n    /**\n     * Increment the attribute.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $model\n     * @param  string  $key\n     * @param  mixed  $value\n     * @param  array  $attributes\n     * @return mixed\n     */\n    public function increment($model, string $key, $value, array $attributes);\n\n    /**\n     * Decrement the attribute.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $model\n     * @param  string  $key\n     * @param  mixed  $value\n     * @param  array  $attributes\n     * @return mixed\n     */\n    public function decrement($model, string $key, $value, array $attributes);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Database/Eloquent/SerializesCastableAttributes.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Database\\Eloquent;\n\ninterface SerializesCastableAttributes\n{\n    /**\n     * Serialize the attribute when converting the model to an array.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $model\n     * @param  string  $key\n     * @param  mixed  $value\n     * @param  array  $attributes\n     * @return mixed\n     */\n    public function serialize($model, string $key, $value, array $attributes);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Database/Eloquent/SupportsPartialRelations.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Database\\Eloquent;\n\ninterface SupportsPartialRelations\n{\n    /**\n     * Indicate that the relation is a single result of a larger one-to-many relationship.\n     *\n     * @param  string|null  $column\n     * @param  string|\\Closure|null  $aggregate\n     * @param  string  $relation\n     * @return $this\n     */\n    public function ofMany($column = 'id', $aggregate = 'MAX', $relation = null);\n\n    /**\n     * Determine whether the relationship is a one-of-many relationship.\n     *\n     * @return bool\n     */\n    public function isOneOfMany();\n\n    /**\n     * Get the one of many inner join subselect query builder instance.\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Builder|void\n     */\n    public function getOneOfManySubQuery();\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Database/Events/MigrationEvent.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Database\\Events;\n\ninterface MigrationEvent\n{\n    //\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Database/ModelIdentifier.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Database;\n\nclass ModelIdentifier\n{\n    /**\n     * The class name of the model.\n     *\n     * @var string\n     */\n    public $class;\n\n    /**\n     * The unique identifier of the model.\n     *\n     * This may be either a single ID or an array of IDs.\n     *\n     * @var mixed\n     */\n    public $id;\n\n    /**\n     * The relationships loaded on the model.\n     *\n     * @var array\n     */\n    public $relations;\n\n    /**\n     * The connection name of the model.\n     *\n     * @var string|null\n     */\n    public $connection;\n\n    /**\n     * Create a new model identifier.\n     *\n     * @param  string  $class\n     * @param  mixed  $id\n     * @param  array  $relations\n     * @param  mixed  $connection\n     * @return void\n     */\n    public function __construct($class, $id, array $relations, $connection)\n    {\n        $this->id = $id;\n        $this->class = $class;\n        $this->relations = $relations;\n        $this->connection = $connection;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Debug/ExceptionHandler.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Debug;\n\nuse Throwable;\n\ninterface ExceptionHandler\n{\n    /**\n     * Report or log an exception.\n     *\n     * @param  \\Throwable  $e\n     * @return void\n     *\n     * @throws \\Throwable\n     */\n    public function report(Throwable $e);\n\n    /**\n     * Determine if the exception should be reported.\n     *\n     * @param  \\Throwable  $e\n     * @return bool\n     */\n    public function shouldReport(Throwable $e);\n\n    /**\n     * Render an exception into an HTTP response.\n     *\n     * @param  \\Illuminate\\Http\\Request  $request\n     * @param  \\Throwable  $e\n     * @return \\Symfony\\Component\\HttpFoundation\\Response\n     *\n     * @throws \\Throwable\n     */\n    public function render($request, Throwable $e);\n\n    /**\n     * Render an exception to the console.\n     *\n     * @param  \\Symfony\\Component\\Console\\Output\\OutputInterface  $output\n     * @param  \\Throwable  $e\n     * @return void\n     */\n    public function renderForConsole($output, Throwable $e);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Encryption/DecryptException.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Encryption;\n\nuse RuntimeException;\n\nclass DecryptException extends RuntimeException\n{\n    //\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Encryption/EncryptException.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Encryption;\n\nuse RuntimeException;\n\nclass EncryptException extends RuntimeException\n{\n    //\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Encryption/Encrypter.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Encryption;\n\ninterface Encrypter\n{\n    /**\n     * Encrypt the given value.\n     *\n     * @param  mixed  $value\n     * @param  bool  $serialize\n     * @return string\n     *\n     * @throws \\Illuminate\\Contracts\\Encryption\\EncryptException\n     */\n    public function encrypt($value, $serialize = true);\n\n    /**\n     * Decrypt the given value.\n     *\n     * @param  string  $payload\n     * @param  bool  $unserialize\n     * @return mixed\n     *\n     * @throws \\Illuminate\\Contracts\\Encryption\\DecryptException\n     */\n    public function decrypt($payload, $unserialize = true);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Encryption/StringEncrypter.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Encryption;\n\ninterface StringEncrypter\n{\n    /**\n     * Encrypt a string without serialization.\n     *\n     * @param  string  $value\n     * @return string\n     *\n     * @throws \\Illuminate\\Contracts\\Encryption\\EncryptException\n     */\n    public function encryptString($value);\n\n    /**\n     * Decrypt the given string without unserialization.\n     *\n     * @param  string  $payload\n     * @return string\n     *\n     * @throws \\Illuminate\\Contracts\\Encryption\\DecryptException\n     */\n    public function decryptString($payload);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Events/Dispatcher.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Events;\n\ninterface Dispatcher\n{\n    /**\n     * Register an event listener with the dispatcher.\n     *\n     * @param  \\Closure|string|array  $events\n     * @param  \\Closure|string|array|null  $listener\n     * @return void\n     */\n    public function listen($events, $listener = null);\n\n    /**\n     * Determine if a given event has listeners.\n     *\n     * @param  string  $eventName\n     * @return bool\n     */\n    public function hasListeners($eventName);\n\n    /**\n     * Register an event subscriber with the dispatcher.\n     *\n     * @param  object|string  $subscriber\n     * @return void\n     */\n    public function subscribe($subscriber);\n\n    /**\n     * Dispatch an event until the first non-null response is returned.\n     *\n     * @param  string|object  $event\n     * @param  mixed  $payload\n     * @return array|null\n     */\n    public function until($event, $payload = []);\n\n    /**\n     * Dispatch an event and call the listeners.\n     *\n     * @param  string|object  $event\n     * @param  mixed  $payload\n     * @param  bool  $halt\n     * @return array|null\n     */\n    public function dispatch($event, $payload = [], $halt = false);\n\n    /**\n     * Register an event and payload to be fired later.\n     *\n     * @param  string  $event\n     * @param  array  $payload\n     * @return void\n     */\n    public function push($event, $payload = []);\n\n    /**\n     * Flush a set of pushed events.\n     *\n     * @param  string  $event\n     * @return void\n     */\n    public function flush($event);\n\n    /**\n     * Remove a set of listeners from the dispatcher.\n     *\n     * @param  string  $event\n     * @return void\n     */\n    public function forget($event);\n\n    /**\n     * Forget all of the queued listeners.\n     *\n     * @return void\n     */\n    public function forgetPushed();\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Filesystem/Cloud.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Filesystem;\n\ninterface Cloud extends Filesystem\n{\n    /**\n     * Get the URL for the file at the given path.\n     *\n     * @param  string  $path\n     * @return string\n     */\n    public function url($path);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Filesystem/Factory.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Filesystem;\n\ninterface Factory\n{\n    /**\n     * Get a filesystem implementation.\n     *\n     * @param  string|null  $name\n     * @return \\Illuminate\\Contracts\\Filesystem\\Filesystem\n     */\n    public function disk($name = null);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Filesystem/FileExistsException.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Filesystem;\n\nuse Exception;\n\nclass FileExistsException extends Exception\n{\n    //\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Filesystem/FileNotFoundException.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Filesystem;\n\nuse Exception;\n\nclass FileNotFoundException extends Exception\n{\n    //\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Filesystem/Filesystem.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Filesystem;\n\ninterface Filesystem\n{\n    /**\n     * The public visibility setting.\n     *\n     * @var string\n     */\n    const VISIBILITY_PUBLIC = 'public';\n\n    /**\n     * The private visibility setting.\n     *\n     * @var string\n     */\n    const VISIBILITY_PRIVATE = 'private';\n\n    /**\n     * Determine if a file exists.\n     *\n     * @param  string  $path\n     * @return bool\n     */\n    public function exists($path);\n\n    /**\n     * Get the contents of a file.\n     *\n     * @param  string  $path\n     * @return string\n     *\n     * @throws \\Illuminate\\Contracts\\Filesystem\\FileNotFoundException\n     */\n    public function get($path);\n\n    /**\n     * Get a resource to read the file.\n     *\n     * @param  string  $path\n     * @return resource|null The path resource or null on failure.\n     *\n     * @throws \\Illuminate\\Contracts\\Filesystem\\FileNotFoundException\n     */\n    public function readStream($path);\n\n    /**\n     * Write the contents of a file.\n     *\n     * @param  string  $path\n     * @param  string|resource  $contents\n     * @param  mixed  $options\n     * @return bool\n     */\n    public function put($path, $contents, $options = []);\n\n    /**\n     * Write a new file using a stream.\n     *\n     * @param  string  $path\n     * @param  resource  $resource\n     * @param  array  $options\n     * @return bool\n     *\n     * @throws \\InvalidArgumentException If $resource is not a file handle.\n     * @throws \\Illuminate\\Contracts\\Filesystem\\FileExistsException\n     */\n    public function writeStream($path, $resource, array $options = []);\n\n    /**\n     * Get the visibility for the given path.\n     *\n     * @param  string  $path\n     * @return string\n     */\n    public function getVisibility($path);\n\n    /**\n     * Set the visibility for the given path.\n     *\n     * @param  string  $path\n     * @param  string  $visibility\n     * @return bool\n     */\n    public function setVisibility($path, $visibility);\n\n    /**\n     * Prepend to a file.\n     *\n     * @param  string  $path\n     * @param  string  $data\n     * @return bool\n     */\n    public function prepend($path, $data);\n\n    /**\n     * Append to a file.\n     *\n     * @param  string  $path\n     * @param  string  $data\n     * @return bool\n     */\n    public function append($path, $data);\n\n    /**\n     * Delete the file at a given path.\n     *\n     * @param  string|array  $paths\n     * @return bool\n     */\n    public function delete($paths);\n\n    /**\n     * Copy a file to a new location.\n     *\n     * @param  string  $from\n     * @param  string  $to\n     * @return bool\n     */\n    public function copy($from, $to);\n\n    /**\n     * Move a file to a new location.\n     *\n     * @param  string  $from\n     * @param  string  $to\n     * @return bool\n     */\n    public function move($from, $to);\n\n    /**\n     * Get the file size of a given file.\n     *\n     * @param  string  $path\n     * @return int\n     */\n    public function size($path);\n\n    /**\n     * Get the file's last modification time.\n     *\n     * @param  string  $path\n     * @return int\n     */\n    public function lastModified($path);\n\n    /**\n     * Get an array of all files in a directory.\n     *\n     * @param  string|null  $directory\n     * @param  bool  $recursive\n     * @return array\n     */\n    public function files($directory = null, $recursive = false);\n\n    /**\n     * Get all of the files from the given directory (recursive).\n     *\n     * @param  string|null  $directory\n     * @return array\n     */\n    public function allFiles($directory = null);\n\n    /**\n     * Get all of the directories within a given directory.\n     *\n     * @param  string|null  $directory\n     * @param  bool  $recursive\n     * @return array\n     */\n    public function directories($directory = null, $recursive = false);\n\n    /**\n     * Get all (recursive) of the directories within a given directory.\n     *\n     * @param  string|null  $directory\n     * @return array\n     */\n    public function allDirectories($directory = null);\n\n    /**\n     * Create a directory.\n     *\n     * @param  string  $path\n     * @return bool\n     */\n    public function makeDirectory($path);\n\n    /**\n     * Recursively delete a directory.\n     *\n     * @param  string  $directory\n     * @return bool\n     */\n    public function deleteDirectory($directory);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Filesystem/LockTimeoutException.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Filesystem;\n\nuse Exception;\n\nclass LockTimeoutException extends Exception\n{\n    //\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Foundation/Application.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Foundation;\n\nuse Illuminate\\Contracts\\Container\\Container;\n\ninterface Application extends Container\n{\n    /**\n     * Get the version number of the application.\n     *\n     * @return string\n     */\n    public function version();\n\n    /**\n     * Get the base path of the Laravel installation.\n     *\n     * @param  string  $path\n     * @return string\n     */\n    public function basePath($path = '');\n\n    /**\n     * Get the path to the bootstrap directory.\n     *\n     * @param  string  $path\n     * @return string\n     */\n    public function bootstrapPath($path = '');\n\n    /**\n     * Get the path to the application configuration files.\n     *\n     * @param  string  $path\n     * @return string\n     */\n    public function configPath($path = '');\n\n    /**\n     * Get the path to the database directory.\n     *\n     * @param  string  $path\n     * @return string\n     */\n    public function databasePath($path = '');\n\n    /**\n     * Get the path to the resources directory.\n     *\n     * @param  string  $path\n     * @return string\n     */\n    public function resourcePath($path = '');\n\n    /**\n     * Get the path to the storage directory.\n     *\n     * @return string\n     */\n    public function storagePath();\n\n    /**\n     * Get or check the current application environment.\n     *\n     * @param  string|array  $environments\n     * @return string|bool\n     */\n    public function environment(...$environments);\n\n    /**\n     * Determine if the application is running in the console.\n     *\n     * @return bool\n     */\n    public function runningInConsole();\n\n    /**\n     * Determine if the application is running unit tests.\n     *\n     * @return bool\n     */\n    public function runningUnitTests();\n\n    /**\n     * Determine if the application is currently down for maintenance.\n     *\n     * @return bool\n     */\n    public function isDownForMaintenance();\n\n    /**\n     * Register all of the configured providers.\n     *\n     * @return void\n     */\n    public function registerConfiguredProviders();\n\n    /**\n     * Register a service provider with the application.\n     *\n     * @param  \\Illuminate\\Support\\ServiceProvider|string  $provider\n     * @param  bool  $force\n     * @return \\Illuminate\\Support\\ServiceProvider\n     */\n    public function register($provider, $force = false);\n\n    /**\n     * Register a deferred provider and service.\n     *\n     * @param  string  $provider\n     * @param  string|null  $service\n     * @return void\n     */\n    public function registerDeferredProvider($provider, $service = null);\n\n    /**\n     * Resolve a service provider instance from the class name.\n     *\n     * @param  string  $provider\n     * @return \\Illuminate\\Support\\ServiceProvider\n     */\n    public function resolveProvider($provider);\n\n    /**\n     * Boot the application's service providers.\n     *\n     * @return void\n     */\n    public function boot();\n\n    /**\n     * Register a new boot listener.\n     *\n     * @param  callable  $callback\n     * @return void\n     */\n    public function booting($callback);\n\n    /**\n     * Register a new \"booted\" listener.\n     *\n     * @param  callable  $callback\n     * @return void\n     */\n    public function booted($callback);\n\n    /**\n     * Run the given array of bootstrap classes.\n     *\n     * @param  array  $bootstrappers\n     * @return void\n     */\n    public function bootstrapWith(array $bootstrappers);\n\n    /**\n     * Get the current application locale.\n     *\n     * @return string\n     */\n    public function getLocale();\n\n    /**\n     * Get the application namespace.\n     *\n     * @return string\n     *\n     * @throws \\RuntimeException\n     */\n    public function getNamespace();\n\n    /**\n     * Get the registered service provider instances if any exist.\n     *\n     * @param  \\Illuminate\\Support\\ServiceProvider|string  $provider\n     * @return array\n     */\n    public function getProviders($provider);\n\n    /**\n     * Determine if the application has been bootstrapped before.\n     *\n     * @return bool\n     */\n    public function hasBeenBootstrapped();\n\n    /**\n     * Load and boot all of the remaining deferred providers.\n     *\n     * @return void\n     */\n    public function loadDeferredProviders();\n\n    /**\n     * Set the current application locale.\n     *\n     * @param  string  $locale\n     * @return void\n     */\n    public function setLocale($locale);\n\n    /**\n     * Determine if middleware has been disabled for the application.\n     *\n     * @return bool\n     */\n    public function shouldSkipMiddleware();\n\n    /**\n     * Terminate the application.\n     *\n     * @return void\n     */\n    public function terminate();\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Foundation/CachesConfiguration.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Foundation;\n\ninterface CachesConfiguration\n{\n    /**\n     * Determine if the application configuration is cached.\n     *\n     * @return bool\n     */\n    public function configurationIsCached();\n\n    /**\n     * Get the path to the configuration cache file.\n     *\n     * @return string\n     */\n    public function getCachedConfigPath();\n\n    /**\n     * Get the path to the cached services.php file.\n     *\n     * @return string\n     */\n    public function getCachedServicesPath();\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Foundation/CachesRoutes.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Foundation;\n\ninterface CachesRoutes\n{\n    /**\n     * Determine if the application routes are cached.\n     *\n     * @return bool\n     */\n    public function routesAreCached();\n\n    /**\n     * Get the path to the routes cache file.\n     *\n     * @return string\n     */\n    public function getCachedRoutesPath();\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Hashing/Hasher.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Hashing;\n\ninterface Hasher\n{\n    /**\n     * Get information about the given hashed value.\n     *\n     * @param  string  $hashedValue\n     * @return array\n     */\n    public function info($hashedValue);\n\n    /**\n     * Hash the given value.\n     *\n     * @param  string  $value\n     * @param  array  $options\n     * @return string\n     */\n    public function make($value, array $options = []);\n\n    /**\n     * Check the given plain value against a hash.\n     *\n     * @param  string  $value\n     * @param  string  $hashedValue\n     * @param  array  $options\n     * @return bool\n     */\n    public function check($value, $hashedValue, array $options = []);\n\n    /**\n     * Check if the given hash has been hashed using the given options.\n     *\n     * @param  string  $hashedValue\n     * @param  array  $options\n     * @return bool\n     */\n    public function needsRehash($hashedValue, array $options = []);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Http/Kernel.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Http;\n\ninterface Kernel\n{\n    /**\n     * Bootstrap the application for HTTP requests.\n     *\n     * @return void\n     */\n    public function bootstrap();\n\n    /**\n     * Handle an incoming HTTP request.\n     *\n     * @param  \\Symfony\\Component\\HttpFoundation\\Request  $request\n     * @return \\Symfony\\Component\\HttpFoundation\\Response\n     */\n    public function handle($request);\n\n    /**\n     * Perform any final actions for the request lifecycle.\n     *\n     * @param  \\Symfony\\Component\\HttpFoundation\\Request  $request\n     * @param  \\Symfony\\Component\\HttpFoundation\\Response  $response\n     * @return void\n     */\n    public function terminate($request, $response);\n\n    /**\n     * Get the Laravel application instance.\n     *\n     * @return \\Illuminate\\Contracts\\Foundation\\Application\n     */\n    public function getApplication();\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/LICENSE.md",
    "content": "The MIT License (MIT)\n\nCopyright (c) Taylor Otwell\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Mail/Factory.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Mail;\n\ninterface Factory\n{\n    /**\n     * Get a mailer instance by name.\n     *\n     * @param  string|null  $name\n     * @return \\Illuminate\\Contracts\\Mail\\Mailer\n     */\n    public function mailer($name = null);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Mail/MailQueue.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Mail;\n\ninterface MailQueue\n{\n    /**\n     * Queue a new e-mail message for sending.\n     *\n     * @param  \\Illuminate\\Contracts\\Mail\\Mailable|string|array  $view\n     * @param  string|null  $queue\n     * @return mixed\n     */\n    public function queue($view, $queue = null);\n\n    /**\n     * Queue a new e-mail message for sending after (n) seconds.\n     *\n     * @param  \\DateTimeInterface|\\DateInterval|int  $delay\n     * @param  \\Illuminate\\Contracts\\Mail\\Mailable|string|array  $view\n     * @param  string|null  $queue\n     * @return mixed\n     */\n    public function later($delay, $view, $queue = null);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Mail/Mailable.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Mail;\n\nuse Illuminate\\Contracts\\Queue\\Factory as Queue;\n\ninterface Mailable\n{\n    /**\n     * Send the message using the given mailer.\n     *\n     * @param  \\Illuminate\\Contracts\\Mail\\Factory|\\Illuminate\\Contracts\\Mail\\Mailer  $mailer\n     * @return void\n     */\n    public function send($mailer);\n\n    /**\n     * Queue the given message.\n     *\n     * @param  \\Illuminate\\Contracts\\Queue\\Factory  $queue\n     * @return mixed\n     */\n    public function queue(Queue $queue);\n\n    /**\n     * Deliver the queued message after the given delay.\n     *\n     * @param  \\DateTimeInterface|\\DateInterval|int  $delay\n     * @param  \\Illuminate\\Contracts\\Queue\\Factory  $queue\n     * @return mixed\n     */\n    public function later($delay, Queue $queue);\n\n    /**\n     * Set the recipients of the message.\n     *\n     * @param  object|array|string  $address\n     * @param  string|null  $name\n     * @return self\n     */\n    public function cc($address, $name = null);\n\n    /**\n     * Set the recipients of the message.\n     *\n     * @param  object|array|string  $address\n     * @param  string|null  $name\n     * @return $this\n     */\n    public function bcc($address, $name = null);\n\n    /**\n     * Set the recipients of the message.\n     *\n     * @param  object|array|string  $address\n     * @param  string|null  $name\n     * @return $this\n     */\n    public function to($address, $name = null);\n\n    /**\n     * Set the locale of the message.\n     *\n     * @param  string  $locale\n     * @return $this\n     */\n    public function locale($locale);\n\n    /**\n     * Set the name of the mailer that should be used to send the message.\n     *\n     * @param  string  $mailer\n     * @return $this\n     */\n    public function mailer($mailer);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Mail/Mailer.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Mail;\n\ninterface Mailer\n{\n    /**\n     * Begin the process of mailing a mailable class instance.\n     *\n     * @param  mixed  $users\n     * @return \\Illuminate\\Mail\\PendingMail\n     */\n    public function to($users);\n\n    /**\n     * Begin the process of mailing a mailable class instance.\n     *\n     * @param  mixed  $users\n     * @return \\Illuminate\\Mail\\PendingMail\n     */\n    public function bcc($users);\n\n    /**\n     * Send a new message with only a raw text part.\n     *\n     * @param  string  $text\n     * @param  mixed  $callback\n     * @return void\n     */\n    public function raw($text, $callback);\n\n    /**\n     * Send a new message using a view.\n     *\n     * @param  \\Illuminate\\Contracts\\Mail\\Mailable|string|array  $view\n     * @param  array  $data\n     * @param  \\Closure|string|null  $callback\n     * @return void\n     */\n    public function send($view, array $data = [], $callback = null);\n\n    /**\n     * Get the array of failed recipients.\n     *\n     * @return array\n     */\n    public function failures();\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Notifications/Dispatcher.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Notifications;\n\ninterface Dispatcher\n{\n    /**\n     * Send the given notification to the given notifiable entities.\n     *\n     * @param  \\Illuminate\\Support\\Collection|array|mixed  $notifiables\n     * @param  mixed  $notification\n     * @return void\n     */\n    public function send($notifiables, $notification);\n\n    /**\n     * Send the given notification immediately.\n     *\n     * @param  \\Illuminate\\Support\\Collection|array|mixed  $notifiables\n     * @param  mixed  $notification\n     * @return void\n     */\n    public function sendNow($notifiables, $notification);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Notifications/Factory.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Notifications;\n\ninterface Factory\n{\n    /**\n     * Get a channel instance by name.\n     *\n     * @param  string|null  $name\n     * @return mixed\n     */\n    public function channel($name = null);\n\n    /**\n     * Send the given notification to the given notifiable entities.\n     *\n     * @param  \\Illuminate\\Support\\Collection|array|mixed  $notifiables\n     * @param  mixed  $notification\n     * @return void\n     */\n    public function send($notifiables, $notification);\n\n    /**\n     * Send the given notification immediately.\n     *\n     * @param  \\Illuminate\\Support\\Collection|array|mixed  $notifiables\n     * @param  mixed  $notification\n     * @return void\n     */\n    public function sendNow($notifiables, $notification);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Pagination/CursorPaginator.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Pagination;\n\ninterface CursorPaginator\n{\n    /**\n     * Get the URL for a given cursor.\n     *\n     * @param  \\Illuminate\\Pagination\\Cursor|null  $cursor\n     * @return string\n     */\n    public function url($cursor);\n\n    /**\n     * Add a set of query string values to the paginator.\n     *\n     * @param  array|string|null  $key\n     * @param  string|null  $value\n     * @return $this\n     */\n    public function appends($key, $value = null);\n\n    /**\n     * Get / set the URL fragment to be appended to URLs.\n     *\n     * @param  string|null  $fragment\n     * @return $this|string|null\n     */\n    public function fragment($fragment = null);\n\n    /**\n     * Get the URL for the previous page, or null.\n     *\n     * @return string|null\n     */\n    public function previousPageUrl();\n\n    /**\n     * The URL for the next page, or null.\n     *\n     * @return string|null\n     */\n    public function nextPageUrl();\n\n    /**\n     * Get all of the items being paginated.\n     *\n     * @return array\n     */\n    public function items();\n\n    /**\n     * Get the \"cursor\" of the previous set of items.\n     *\n     * @return \\Illuminate\\Pagination\\Cursor|null\n     */\n    public function previousCursor();\n\n    /**\n     * Get the \"cursor\" of the next set of items.\n     *\n     * @return \\Illuminate\\Pagination\\Cursor|null\n     */\n    public function nextCursor();\n\n    /**\n     * Determine how many items are being shown per page.\n     *\n     * @return int\n     */\n    public function perPage();\n\n    /**\n     * Get the current cursor being paginated.\n     *\n     * @return \\Illuminate\\Pagination\\Cursor|null\n     */\n    public function cursor();\n\n    /**\n     * Determine if there are enough items to split into multiple pages.\n     *\n     * @return bool\n     */\n    public function hasPages();\n\n    /**\n     * Get the base path for paginator generated URLs.\n     *\n     * @return string|null\n     */\n    public function path();\n\n    /**\n     * Determine if the list of items is empty or not.\n     *\n     * @return bool\n     */\n    public function isEmpty();\n\n    /**\n     * Determine if the list of items is not empty.\n     *\n     * @return bool\n     */\n    public function isNotEmpty();\n\n    /**\n     * Render the paginator using a given view.\n     *\n     * @param  string|null  $view\n     * @param  array  $data\n     * @return string\n     */\n    public function render($view = null, $data = []);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Pagination/LengthAwarePaginator.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Pagination;\n\ninterface LengthAwarePaginator extends Paginator\n{\n    /**\n     * Create a range of pagination URLs.\n     *\n     * @param  int  $start\n     * @param  int  $end\n     * @return array\n     */\n    public function getUrlRange($start, $end);\n\n    /**\n     * Determine the total number of items in the data store.\n     *\n     * @return int\n     */\n    public function total();\n\n    /**\n     * Get the page number of the last available page.\n     *\n     * @return int\n     */\n    public function lastPage();\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Pagination/Paginator.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Pagination;\n\ninterface Paginator\n{\n    /**\n     * Get the URL for a given page.\n     *\n     * @param  int  $page\n     * @return string\n     */\n    public function url($page);\n\n    /**\n     * Add a set of query string values to the paginator.\n     *\n     * @param  array|string  $key\n     * @param  string|null  $value\n     * @return $this\n     */\n    public function appends($key, $value = null);\n\n    /**\n     * Get / set the URL fragment to be appended to URLs.\n     *\n     * @param  string|null  $fragment\n     * @return $this|string\n     */\n    public function fragment($fragment = null);\n\n    /**\n     * The URL for the next page, or null.\n     *\n     * @return string|null\n     */\n    public function nextPageUrl();\n\n    /**\n     * Get the URL for the previous page, or null.\n     *\n     * @return string|null\n     */\n    public function previousPageUrl();\n\n    /**\n     * Get all of the items being paginated.\n     *\n     * @return array\n     */\n    public function items();\n\n    /**\n     * Get the \"index\" of the first item being paginated.\n     *\n     * @return int\n     */\n    public function firstItem();\n\n    /**\n     * Get the \"index\" of the last item being paginated.\n     *\n     * @return int\n     */\n    public function lastItem();\n\n    /**\n     * Determine how many items are being shown per page.\n     *\n     * @return int\n     */\n    public function perPage();\n\n    /**\n     * Determine the current page being paginated.\n     *\n     * @return int\n     */\n    public function currentPage();\n\n    /**\n     * Determine if there are enough items to split into multiple pages.\n     *\n     * @return bool\n     */\n    public function hasPages();\n\n    /**\n     * Determine if there are more items in the data store.\n     *\n     * @return bool\n     */\n    public function hasMorePages();\n\n    /**\n     * Get the base path for paginator generated URLs.\n     *\n     * @return string|null\n     */\n    public function path();\n\n    /**\n     * Determine if the list of items is empty or not.\n     *\n     * @return bool\n     */\n    public function isEmpty();\n\n    /**\n     * Determine if the list of items is not empty.\n     *\n     * @return bool\n     */\n    public function isNotEmpty();\n\n    /**\n     * Render the paginator using a given view.\n     *\n     * @param  string|null  $view\n     * @param  array  $data\n     * @return string\n     */\n    public function render($view = null, $data = []);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Pipeline/Hub.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Pipeline;\n\ninterface Hub\n{\n    /**\n     * Send an object through one of the available pipelines.\n     *\n     * @param  mixed  $object\n     * @param  string|null  $pipeline\n     * @return mixed\n     */\n    public function pipe($object, $pipeline = null);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Pipeline/Pipeline.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Pipeline;\n\nuse Closure;\n\ninterface Pipeline\n{\n    /**\n     * Set the traveler object being sent on the pipeline.\n     *\n     * @param  mixed  $traveler\n     * @return $this\n     */\n    public function send($traveler);\n\n    /**\n     * Set the stops of the pipeline.\n     *\n     * @param  dynamic|array  $stops\n     * @return $this\n     */\n    public function through($stops);\n\n    /**\n     * Set the method to call on the stops.\n     *\n     * @param  string  $method\n     * @return $this\n     */\n    public function via($method);\n\n    /**\n     * Run the pipeline with a final destination callback.\n     *\n     * @param  \\Closure  $destination\n     * @return mixed\n     */\n    public function then(Closure $destination);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Queue/ClearableQueue.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Queue;\n\ninterface ClearableQueue\n{\n    /**\n     * Delete all of the jobs from the queue.\n     *\n     * @param  string  $queue\n     * @return int\n     */\n    public function clear($queue);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Queue/EntityNotFoundException.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Queue;\n\nuse InvalidArgumentException;\n\nclass EntityNotFoundException extends InvalidArgumentException\n{\n    /**\n     * Create a new exception instance.\n     *\n     * @param  string  $type\n     * @param  mixed  $id\n     * @return void\n     */\n    public function __construct($type, $id)\n    {\n        $id = (string) $id;\n\n        parent::__construct(\"Queueable entity [{$type}] not found for ID [{$id}].\");\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Queue/EntityResolver.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Queue;\n\ninterface EntityResolver\n{\n    /**\n     * Resolve the entity for the given ID.\n     *\n     * @param  string  $type\n     * @param  mixed  $id\n     * @return mixed\n     */\n    public function resolve($type, $id);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Queue/Factory.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Queue;\n\ninterface Factory\n{\n    /**\n     * Resolve a queue connection instance.\n     *\n     * @param  string|null  $name\n     * @return \\Illuminate\\Contracts\\Queue\\Queue\n     */\n    public function connection($name = null);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Queue/Job.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Queue;\n\ninterface Job\n{\n    /**\n     * Get the UUID of the job.\n     *\n     * @return string|null\n     */\n    public function uuid();\n\n    /**\n     * Get the job identifier.\n     *\n     * @return string\n     */\n    public function getJobId();\n\n    /**\n     * Get the decoded body of the job.\n     *\n     * @return array\n     */\n    public function payload();\n\n    /**\n     * Fire the job.\n     *\n     * @return void\n     */\n    public function fire();\n\n    /**\n     * Release the job back into the queue.\n     *\n     * Accepts a delay specified in seconds.\n     *\n     * @param  int  $delay\n     * @return void\n     */\n    public function release($delay = 0);\n\n    /**\n     * Determine if the job was released back into the queue.\n     *\n     * @return bool\n     */\n    public function isReleased();\n\n    /**\n     * Delete the job from the queue.\n     *\n     * @return void\n     */\n    public function delete();\n\n    /**\n     * Determine if the job has been deleted.\n     *\n     * @return bool\n     */\n    public function isDeleted();\n\n    /**\n     * Determine if the job has been deleted or released.\n     *\n     * @return bool\n     */\n    public function isDeletedOrReleased();\n\n    /**\n     * Get the number of times the job has been attempted.\n     *\n     * @return int\n     */\n    public function attempts();\n\n    /**\n     * Determine if the job has been marked as a failure.\n     *\n     * @return bool\n     */\n    public function hasFailed();\n\n    /**\n     * Mark the job as \"failed\".\n     *\n     * @return void\n     */\n    public function markAsFailed();\n\n    /**\n     * Delete the job, call the \"failed\" method, and raise the failed job event.\n     *\n     * @param  \\Throwable|null  $e\n     * @return void\n     */\n    public function fail($e = null);\n\n    /**\n     * Get the number of times to attempt a job.\n     *\n     * @return int|null\n     */\n    public function maxTries();\n\n    /**\n     * Get the maximum number of exceptions allowed, regardless of attempts.\n     *\n     * @return int|null\n     */\n    public function maxExceptions();\n\n    /**\n     * Get the number of seconds the job can run.\n     *\n     * @return int|null\n     */\n    public function timeout();\n\n    /**\n     * Get the timestamp indicating when the job should timeout.\n     *\n     * @return int|null\n     */\n    public function retryUntil();\n\n    /**\n     * Get the name of the queued job class.\n     *\n     * @return string\n     */\n    public function getName();\n\n    /**\n     * Get the resolved name of the queued job class.\n     *\n     * Resolves the name of \"wrapped\" jobs such as class-based handlers.\n     *\n     * @return string\n     */\n    public function resolveName();\n\n    /**\n     * Get the name of the connection the job belongs to.\n     *\n     * @return string\n     */\n    public function getConnectionName();\n\n    /**\n     * Get the name of the queue the job belongs to.\n     *\n     * @return string\n     */\n    public function getQueue();\n\n    /**\n     * Get the raw body string for the job.\n     *\n     * @return string\n     */\n    public function getRawBody();\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Queue/Monitor.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Queue;\n\ninterface Monitor\n{\n    /**\n     * Register a callback to be executed on every iteration through the queue loop.\n     *\n     * @param  mixed  $callback\n     * @return void\n     */\n    public function looping($callback);\n\n    /**\n     * Register a callback to be executed when a job fails after the maximum amount of retries.\n     *\n     * @param  mixed  $callback\n     * @return void\n     */\n    public function failing($callback);\n\n    /**\n     * Register a callback to be executed when a daemon queue is stopping.\n     *\n     * @param  mixed  $callback\n     * @return void\n     */\n    public function stopping($callback);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Queue/Queue.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Queue;\n\ninterface Queue\n{\n    /**\n     * Get the size of the queue.\n     *\n     * @param  string|null  $queue\n     * @return int\n     */\n    public function size($queue = null);\n\n    /**\n     * Push a new job onto the queue.\n     *\n     * @param  string|object  $job\n     * @param  mixed  $data\n     * @param  string|null  $queue\n     * @return mixed\n     */\n    public function push($job, $data = '', $queue = null);\n\n    /**\n     * Push a new job onto the queue.\n     *\n     * @param  string  $queue\n     * @param  string|object  $job\n     * @param  mixed  $data\n     * @return mixed\n     */\n    public function pushOn($queue, $job, $data = '');\n\n    /**\n     * Push a raw payload onto the queue.\n     *\n     * @param  string  $payload\n     * @param  string|null  $queue\n     * @param  array  $options\n     * @return mixed\n     */\n    public function pushRaw($payload, $queue = null, array $options = []);\n\n    /**\n     * Push a new job onto the queue after a delay.\n     *\n     * @param  \\DateTimeInterface|\\DateInterval|int  $delay\n     * @param  string|object  $job\n     * @param  mixed  $data\n     * @param  string|null  $queue\n     * @return mixed\n     */\n    public function later($delay, $job, $data = '', $queue = null);\n\n    /**\n     * Push a new job onto the queue after a delay.\n     *\n     * @param  string  $queue\n     * @param  \\DateTimeInterface|\\DateInterval|int  $delay\n     * @param  string|object  $job\n     * @param  mixed  $data\n     * @return mixed\n     */\n    public function laterOn($queue, $delay, $job, $data = '');\n\n    /**\n     * Push an array of jobs onto the queue.\n     *\n     * @param  array  $jobs\n     * @param  mixed  $data\n     * @param  string|null  $queue\n     * @return mixed\n     */\n    public function bulk($jobs, $data = '', $queue = null);\n\n    /**\n     * Pop the next job off of the queue.\n     *\n     * @param  string|null  $queue\n     * @return \\Illuminate\\Contracts\\Queue\\Job|null\n     */\n    public function pop($queue = null);\n\n    /**\n     * Get the connection name for the queue.\n     *\n     * @return string\n     */\n    public function getConnectionName();\n\n    /**\n     * Set the connection name for the queue.\n     *\n     * @param  string  $name\n     * @return $this\n     */\n    public function setConnectionName($name);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Queue/QueueableCollection.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Queue;\n\ninterface QueueableCollection\n{\n    /**\n     * Get the type of the entities being queued.\n     *\n     * @return string|null\n     */\n    public function getQueueableClass();\n\n    /**\n     * Get the identifiers for all of the entities.\n     *\n     * @return array\n     */\n    public function getQueueableIds();\n\n    /**\n     * Get the relationships of the entities being queued.\n     *\n     * @return array\n     */\n    public function getQueueableRelations();\n\n    /**\n     * Get the connection of the entities being queued.\n     *\n     * @return string|null\n     */\n    public function getQueueableConnection();\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Queue/QueueableEntity.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Queue;\n\ninterface QueueableEntity\n{\n    /**\n     * Get the queueable identity for the entity.\n     *\n     * @return mixed\n     */\n    public function getQueueableId();\n\n    /**\n     * Get the relationships for the entity.\n     *\n     * @return array\n     */\n    public function getQueueableRelations();\n\n    /**\n     * Get the connection of the entity.\n     *\n     * @return string|null\n     */\n    public function getQueueableConnection();\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Queue/ShouldBeEncrypted.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Queue;\n\ninterface ShouldBeEncrypted\n{\n    //\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Queue/ShouldBeUnique.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Queue;\n\ninterface ShouldBeUnique\n{\n    //\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Queue/ShouldBeUniqueUntilProcessing.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Queue;\n\ninterface ShouldBeUniqueUntilProcessing extends ShouldBeUnique\n{\n    //\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Queue/ShouldQueue.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Queue;\n\ninterface ShouldQueue\n{\n    //\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Redis/Connection.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Redis;\n\nuse Closure;\n\ninterface Connection\n{\n    /**\n     * Subscribe to a set of given channels for messages.\n     *\n     * @param  array|string  $channels\n     * @param  \\Closure  $callback\n     * @return void\n     */\n    public function subscribe($channels, Closure $callback);\n\n    /**\n     * Subscribe to a set of given channels with wildcards.\n     *\n     * @param  array|string  $channels\n     * @param  \\Closure  $callback\n     * @return void\n     */\n    public function psubscribe($channels, Closure $callback);\n\n    /**\n     * Run a command against the Redis database.\n     *\n     * @param  string  $method\n     * @param  array  $parameters\n     * @return mixed\n     */\n    public function command($method, array $parameters = []);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Redis/Connector.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Redis;\n\ninterface Connector\n{\n    /**\n     * Create a connection to a Redis cluster.\n     *\n     * @param  array  $config\n     * @param  array  $options\n     * @return \\Illuminate\\Redis\\Connections\\Connection\n     */\n    public function connect(array $config, array $options);\n\n    /**\n     * Create a connection to a Redis instance.\n     *\n     * @param  array  $config\n     * @param  array  $clusterOptions\n     * @param  array  $options\n     * @return \\Illuminate\\Redis\\Connections\\Connection\n     */\n    public function connectToCluster(array $config, array $clusterOptions, array $options);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Redis/Factory.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Redis;\n\ninterface Factory\n{\n    /**\n     * Get a Redis connection by name.\n     *\n     * @param  string|null  $name\n     * @return \\Illuminate\\Redis\\Connections\\Connection\n     */\n    public function connection($name = null);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Redis/LimiterTimeoutException.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Redis;\n\nuse Exception;\n\nclass LimiterTimeoutException extends Exception\n{\n    //\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Routing/BindingRegistrar.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Routing;\n\ninterface BindingRegistrar\n{\n    /**\n     * Add a new route parameter binder.\n     *\n     * @param  string  $key\n     * @param  string|callable  $binder\n     * @return void\n     */\n    public function bind($key, $binder);\n\n    /**\n     * Get the binding callback for a given binding.\n     *\n     * @param  string  $key\n     * @return \\Closure\n     */\n    public function getBindingCallback($key);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Routing/Registrar.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Routing;\n\ninterface Registrar\n{\n    /**\n     * Register a new GET route with the router.\n     *\n     * @param  string  $uri\n     * @param  array|string|callable  $action\n     * @return \\Illuminate\\Routing\\Route\n     */\n    public function get($uri, $action);\n\n    /**\n     * Register a new POST route with the router.\n     *\n     * @param  string  $uri\n     * @param  array|string|callable  $action\n     * @return \\Illuminate\\Routing\\Route\n     */\n    public function post($uri, $action);\n\n    /**\n     * Register a new PUT route with the router.\n     *\n     * @param  string  $uri\n     * @param  array|string|callable  $action\n     * @return \\Illuminate\\Routing\\Route\n     */\n    public function put($uri, $action);\n\n    /**\n     * Register a new DELETE route with the router.\n     *\n     * @param  string  $uri\n     * @param  array|string|callable  $action\n     * @return \\Illuminate\\Routing\\Route\n     */\n    public function delete($uri, $action);\n\n    /**\n     * Register a new PATCH route with the router.\n     *\n     * @param  string  $uri\n     * @param  array|string|callable  $action\n     * @return \\Illuminate\\Routing\\Route\n     */\n    public function patch($uri, $action);\n\n    /**\n     * Register a new OPTIONS route with the router.\n     *\n     * @param  string  $uri\n     * @param  array|string|callable  $action\n     * @return \\Illuminate\\Routing\\Route\n     */\n    public function options($uri, $action);\n\n    /**\n     * Register a new route with the given verbs.\n     *\n     * @param  array|string  $methods\n     * @param  string  $uri\n     * @param  array|string|callable  $action\n     * @return \\Illuminate\\Routing\\Route\n     */\n    public function match($methods, $uri, $action);\n\n    /**\n     * Route a resource to a controller.\n     *\n     * @param  string  $name\n     * @param  string  $controller\n     * @param  array  $options\n     * @return \\Illuminate\\Routing\\PendingResourceRegistration\n     */\n    public function resource($name, $controller, array $options = []);\n\n    /**\n     * Create a route group with shared attributes.\n     *\n     * @param  array  $attributes\n     * @param  \\Closure|string  $routes\n     * @return void\n     */\n    public function group(array $attributes, $routes);\n\n    /**\n     * Substitute the route bindings onto the route.\n     *\n     * @param  \\Illuminate\\Routing\\Route  $route\n     * @return \\Illuminate\\Routing\\Route\n     */\n    public function substituteBindings($route);\n\n    /**\n     * Substitute the implicit Eloquent model bindings for the route.\n     *\n     * @param  \\Illuminate\\Routing\\Route  $route\n     * @return void\n     */\n    public function substituteImplicitBindings($route);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Routing/ResponseFactory.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Routing;\n\ninterface ResponseFactory\n{\n    /**\n     * Create a new response instance.\n     *\n     * @param  array|string  $content\n     * @param  int  $status\n     * @param  array  $headers\n     * @return \\Illuminate\\Http\\Response\n     */\n    public function make($content = '', $status = 200, array $headers = []);\n\n    /**\n     * Create a new \"no content\" response.\n     *\n     * @param  int  $status\n     * @param  array  $headers\n     * @return \\Illuminate\\Http\\Response\n     */\n    public function noContent($status = 204, array $headers = []);\n\n    /**\n     * Create a new response for a given view.\n     *\n     * @param  string|array  $view\n     * @param  array  $data\n     * @param  int  $status\n     * @param  array  $headers\n     * @return \\Illuminate\\Http\\Response\n     */\n    public function view($view, $data = [], $status = 200, array $headers = []);\n\n    /**\n     * Create a new JSON response instance.\n     *\n     * @param  mixed  $data\n     * @param  int  $status\n     * @param  array  $headers\n     * @param  int  $options\n     * @return \\Illuminate\\Http\\JsonResponse\n     */\n    public function json($data = [], $status = 200, array $headers = [], $options = 0);\n\n    /**\n     * Create a new JSONP response instance.\n     *\n     * @param  string  $callback\n     * @param  mixed  $data\n     * @param  int  $status\n     * @param  array  $headers\n     * @param  int  $options\n     * @return \\Illuminate\\Http\\JsonResponse\n     */\n    public function jsonp($callback, $data = [], $status = 200, array $headers = [], $options = 0);\n\n    /**\n     * Create a new streamed response instance.\n     *\n     * @param  \\Closure  $callback\n     * @param  int  $status\n     * @param  array  $headers\n     * @return \\Symfony\\Component\\HttpFoundation\\StreamedResponse\n     */\n    public function stream($callback, $status = 200, array $headers = []);\n\n    /**\n     * Create a new streamed response instance as a file download.\n     *\n     * @param  \\Closure  $callback\n     * @param  string|null  $name\n     * @param  array  $headers\n     * @param  string|null  $disposition\n     * @return \\Symfony\\Component\\HttpFoundation\\StreamedResponse\n     */\n    public function streamDownload($callback, $name = null, array $headers = [], $disposition = 'attachment');\n\n    /**\n     * Create a new file download response.\n     *\n     * @param  \\SplFileInfo|string  $file\n     * @param  string|null  $name\n     * @param  array  $headers\n     * @param  string|null  $disposition\n     * @return \\Symfony\\Component\\HttpFoundation\\BinaryFileResponse\n     */\n    public function download($file, $name = null, array $headers = [], $disposition = 'attachment');\n\n    /**\n     * Return the raw contents of a binary file.\n     *\n     * @param  \\SplFileInfo|string  $file\n     * @param  array  $headers\n     * @return \\Symfony\\Component\\HttpFoundation\\BinaryFileResponse\n     */\n    public function file($file, array $headers = []);\n\n    /**\n     * Create a new redirect response to the given path.\n     *\n     * @param  string  $path\n     * @param  int  $status\n     * @param  array  $headers\n     * @param  bool|null  $secure\n     * @return \\Illuminate\\Http\\RedirectResponse\n     */\n    public function redirectTo($path, $status = 302, $headers = [], $secure = null);\n\n    /**\n     * Create a new redirect response to a named route.\n     *\n     * @param  string  $route\n     * @param  mixed  $parameters\n     * @param  int  $status\n     * @param  array  $headers\n     * @return \\Illuminate\\Http\\RedirectResponse\n     */\n    public function redirectToRoute($route, $parameters = [], $status = 302, $headers = []);\n\n    /**\n     * Create a new redirect response to a controller action.\n     *\n     * @param  string  $action\n     * @param  mixed  $parameters\n     * @param  int  $status\n     * @param  array  $headers\n     * @return \\Illuminate\\Http\\RedirectResponse\n     */\n    public function redirectToAction($action, $parameters = [], $status = 302, $headers = []);\n\n    /**\n     * Create a new redirect response, while putting the current URL in the session.\n     *\n     * @param  string  $path\n     * @param  int  $status\n     * @param  array  $headers\n     * @param  bool|null  $secure\n     * @return \\Illuminate\\Http\\RedirectResponse\n     */\n    public function redirectGuest($path, $status = 302, $headers = [], $secure = null);\n\n    /**\n     * Create a new redirect response to the previously intended location.\n     *\n     * @param  string  $default\n     * @param  int  $status\n     * @param  array  $headers\n     * @param  bool|null  $secure\n     * @return \\Illuminate\\Http\\RedirectResponse\n     */\n    public function redirectToIntended($default = '/', $status = 302, $headers = [], $secure = null);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Routing/UrlGenerator.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Routing;\n\ninterface UrlGenerator\n{\n    /**\n     * Get the current URL for the request.\n     *\n     * @return string\n     */\n    public function current();\n\n    /**\n     * Get the URL for the previous request.\n     *\n     * @param  mixed  $fallback\n     * @return string\n     */\n    public function previous($fallback = false);\n\n    /**\n     * Generate an absolute URL to the given path.\n     *\n     * @param  string  $path\n     * @param  mixed  $extra\n     * @param  bool|null  $secure\n     * @return string\n     */\n    public function to($path, $extra = [], $secure = null);\n\n    /**\n     * Generate a secure, absolute URL to the given path.\n     *\n     * @param  string  $path\n     * @param  array  $parameters\n     * @return string\n     */\n    public function secure($path, $parameters = []);\n\n    /**\n     * Generate the URL to an application asset.\n     *\n     * @param  string  $path\n     * @param  bool|null  $secure\n     * @return string\n     */\n    public function asset($path, $secure = null);\n\n    /**\n     * Get the URL to a named route.\n     *\n     * @param  string  $name\n     * @param  mixed  $parameters\n     * @param  bool  $absolute\n     * @return string\n     *\n     * @throws \\InvalidArgumentException\n     */\n    public function route($name, $parameters = [], $absolute = true);\n\n    /**\n     * Get the URL to a controller action.\n     *\n     * @param  string|array  $action\n     * @param  mixed  $parameters\n     * @param  bool  $absolute\n     * @return string\n     */\n    public function action($action, $parameters = [], $absolute = true);\n\n    /**\n     * Set the root controller namespace.\n     *\n     * @param  string  $rootNamespace\n     * @return $this\n     */\n    public function setRootControllerNamespace($rootNamespace);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Routing/UrlRoutable.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Routing;\n\ninterface UrlRoutable\n{\n    /**\n     * Get the value of the model's route key.\n     *\n     * @return mixed\n     */\n    public function getRouteKey();\n\n    /**\n     * Get the route key for the model.\n     *\n     * @return string\n     */\n    public function getRouteKeyName();\n\n    /**\n     * Retrieve the model for a bound value.\n     *\n     * @param  mixed  $value\n     * @param  string|null  $field\n     * @return \\Illuminate\\Database\\Eloquent\\Model|null\n     */\n    public function resolveRouteBinding($value, $field = null);\n\n    /**\n     * Retrieve the child model for a bound value.\n     *\n     * @param  string  $childType\n     * @param  mixed  $value\n     * @param  string|null  $field\n     * @return \\Illuminate\\Database\\Eloquent\\Model|null\n     */\n    public function resolveChildRouteBinding($childType, $value, $field);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Session/Session.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Session;\n\ninterface Session\n{\n    /**\n     * Get the name of the session.\n     *\n     * @return string\n     */\n    public function getName();\n\n    /**\n     * Set the name of the session.\n     *\n     * @param  string  $name\n     * @return void\n     */\n    public function setName($name);\n\n    /**\n     * Get the current session ID.\n     *\n     * @return string\n     */\n    public function getId();\n\n    /**\n     * Set the session ID.\n     *\n     * @param  string  $id\n     * @return void\n     */\n    public function setId($id);\n\n    /**\n     * Start the session, reading the data from a handler.\n     *\n     * @return bool\n     */\n    public function start();\n\n    /**\n     * Save the session data to storage.\n     *\n     * @return void\n     */\n    public function save();\n\n    /**\n     * Get all of the session data.\n     *\n     * @return array\n     */\n    public function all();\n\n    /**\n     * Checks if a key exists.\n     *\n     * @param  string|array  $key\n     * @return bool\n     */\n    public function exists($key);\n\n    /**\n     * Checks if a key is present and not null.\n     *\n     * @param  string|array  $key\n     * @return bool\n     */\n    public function has($key);\n\n    /**\n     * Get an item from the session.\n     *\n     * @param  string  $key\n     * @param  mixed  $default\n     * @return mixed\n     */\n    public function get($key, $default = null);\n\n    /**\n     * Get the value of a given key and then forget it.\n     *\n     * @param  string  $key\n     * @param  mixed  $default\n     * @return mixed\n     */\n    public function pull($key, $default = null);\n\n    /**\n     * Put a key / value pair or array of key / value pairs in the session.\n     *\n     * @param  string|array  $key\n     * @param  mixed  $value\n     * @return void\n     */\n    public function put($key, $value = null);\n\n    /**\n     * Get the CSRF token value.\n     *\n     * @return string\n     */\n    public function token();\n\n    /**\n     * Regenerate the CSRF token value.\n     *\n     * @return void\n     */\n    public function regenerateToken();\n\n    /**\n     * Remove an item from the session, returning its value.\n     *\n     * @param  string  $key\n     * @return mixed\n     */\n    public function remove($key);\n\n    /**\n     * Remove one or many items from the session.\n     *\n     * @param  string|array  $keys\n     * @return void\n     */\n    public function forget($keys);\n\n    /**\n     * Remove all of the items from the session.\n     *\n     * @return void\n     */\n    public function flush();\n\n    /**\n     * Flush the session data and regenerate the ID.\n     *\n     * @return bool\n     */\n    public function invalidate();\n\n    /**\n     * Generate a new session identifier.\n     *\n     * @param  bool  $destroy\n     * @return bool\n     */\n    public function regenerate($destroy = false);\n\n    /**\n     * Generate a new session ID for the session.\n     *\n     * @param  bool  $destroy\n     * @return bool\n     */\n    public function migrate($destroy = false);\n\n    /**\n     * Determine if the session has been started.\n     *\n     * @return bool\n     */\n    public function isStarted();\n\n    /**\n     * Get the previous URL from the session.\n     *\n     * @return string|null\n     */\n    public function previousUrl();\n\n    /**\n     * Set the \"previous\" URL in the session.\n     *\n     * @param  string  $url\n     * @return void\n     */\n    public function setPreviousUrl($url);\n\n    /**\n     * Get the session handler instance.\n     *\n     * @return \\SessionHandlerInterface\n     */\n    public function getHandler();\n\n    /**\n     * Determine if the session handler needs a request.\n     *\n     * @return bool\n     */\n    public function handlerNeedsRequest();\n\n    /**\n     * Set the request on the handler instance.\n     *\n     * @param  \\Illuminate\\Http\\Request  $request\n     * @return void\n     */\n    public function setRequestOnHandler($request);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Support/Arrayable.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Support;\n\ninterface Arrayable\n{\n    /**\n     * Get the instance as an array.\n     *\n     * @return array\n     */\n    public function toArray();\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Support/CanBeEscapedWhenCastToString.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Support;\n\ninterface CanBeEscapedWhenCastToString\n{\n    /**\n     * Indicate that the object's string representation should be escaped when __toString is invoked.\n     *\n     * @param  bool  $escape\n     * @return $this\n     */\n    public function escapeWhenCastingToString($escape = true);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Support/DeferrableProvider.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Support;\n\ninterface DeferrableProvider\n{\n    /**\n     * Get the services provided by the provider.\n     *\n     * @return array\n     */\n    public function provides();\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Support/DeferringDisplayableValue.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Support;\n\ninterface DeferringDisplayableValue\n{\n    /**\n     * Resolve the displayable value that the class is deferring.\n     *\n     * @return \\Illuminate\\Contracts\\Support\\Htmlable|string\n     */\n    public function resolveDisplayableValue();\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Support/Htmlable.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Support;\n\ninterface Htmlable\n{\n    /**\n     * Get content as a string of HTML.\n     *\n     * @return string\n     */\n    public function toHtml();\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Support/Jsonable.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Support;\n\ninterface Jsonable\n{\n    /**\n     * Convert the object to its JSON representation.\n     *\n     * @param  int  $options\n     * @return string\n     */\n    public function toJson($options = 0);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Support/MessageBag.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Support;\n\nuse Countable;\n\ninterface MessageBag extends Arrayable, Countable\n{\n    /**\n     * Get the keys present in the message bag.\n     *\n     * @return array\n     */\n    public function keys();\n\n    /**\n     * Add a message to the bag.\n     *\n     * @param  string  $key\n     * @param  string  $message\n     * @return $this\n     */\n    public function add($key, $message);\n\n    /**\n     * Merge a new array of messages into the bag.\n     *\n     * @param  \\Illuminate\\Contracts\\Support\\MessageProvider|array  $messages\n     * @return $this\n     */\n    public function merge($messages);\n\n    /**\n     * Determine if messages exist for a given key.\n     *\n     * @param  string|array  $key\n     * @return bool\n     */\n    public function has($key);\n\n    /**\n     * Get the first message from the bag for a given key.\n     *\n     * @param  string|null  $key\n     * @param  string|null  $format\n     * @return string\n     */\n    public function first($key = null, $format = null);\n\n    /**\n     * Get all of the messages from the bag for a given key.\n     *\n     * @param  string  $key\n     * @param  string|null  $format\n     * @return array\n     */\n    public function get($key, $format = null);\n\n    /**\n     * Get all of the messages for every key in the bag.\n     *\n     * @param  string|null  $format\n     * @return array\n     */\n    public function all($format = null);\n\n    /**\n     * Get the raw messages in the container.\n     *\n     * @return array\n     */\n    public function getMessages();\n\n    /**\n     * Get the default message format.\n     *\n     * @return string\n     */\n    public function getFormat();\n\n    /**\n     * Set the default message format.\n     *\n     * @param  string  $format\n     * @return $this\n     */\n    public function setFormat($format = ':message');\n\n    /**\n     * Determine if the message bag has any messages.\n     *\n     * @return bool\n     */\n    public function isEmpty();\n\n    /**\n     * Determine if the message bag has any messages.\n     *\n     * @return bool\n     */\n    public function isNotEmpty();\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Support/MessageProvider.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Support;\n\ninterface MessageProvider\n{\n    /**\n     * Get the messages for the instance.\n     *\n     * @return \\Illuminate\\Contracts\\Support\\MessageBag\n     */\n    public function getMessageBag();\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Support/Renderable.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Support;\n\ninterface Renderable\n{\n    /**\n     * Get the evaluated contents of the object.\n     *\n     * @return string\n     */\n    public function render();\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Support/Responsable.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Support;\n\ninterface Responsable\n{\n    /**\n     * Create an HTTP response that represents the object.\n     *\n     * @param  \\Illuminate\\Http\\Request  $request\n     * @return \\Symfony\\Component\\HttpFoundation\\Response\n     */\n    public function toResponse($request);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Support/ValidatedData.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Support;\n\nuse ArrayAccess;\nuse IteratorAggregate;\n\ninterface ValidatedData extends Arrayable, ArrayAccess, IteratorAggregate\n{\n    //\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Translation/HasLocalePreference.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Translation;\n\ninterface HasLocalePreference\n{\n    /**\n     * Get the preferred locale of the entity.\n     *\n     * @return string|null\n     */\n    public function preferredLocale();\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Translation/Loader.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Translation;\n\ninterface Loader\n{\n    /**\n     * Load the messages for the given locale.\n     *\n     * @param  string  $locale\n     * @param  string  $group\n     * @param  string|null  $namespace\n     * @return array\n     */\n    public function load($locale, $group, $namespace = null);\n\n    /**\n     * Add a new namespace to the loader.\n     *\n     * @param  string  $namespace\n     * @param  string  $hint\n     * @return void\n     */\n    public function addNamespace($namespace, $hint);\n\n    /**\n     * Add a new JSON path to the loader.\n     *\n     * @param  string  $path\n     * @return void\n     */\n    public function addJsonPath($path);\n\n    /**\n     * Get an array of all the registered namespaces.\n     *\n     * @return array\n     */\n    public function namespaces();\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Translation/Translator.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Translation;\n\ninterface Translator\n{\n    /**\n     * Get the translation for a given key.\n     *\n     * @param  string  $key\n     * @param  array  $replace\n     * @param  string|null  $locale\n     * @return mixed\n     */\n    public function get($key, array $replace = [], $locale = null);\n\n    /**\n     * Get a translation according to an integer value.\n     *\n     * @param  string  $key\n     * @param  \\Countable|int|array  $number\n     * @param  array  $replace\n     * @param  string|null  $locale\n     * @return string\n     */\n    public function choice($key, $number, array $replace = [], $locale = null);\n\n    /**\n     * Get the default locale being used.\n     *\n     * @return string\n     */\n    public function getLocale();\n\n    /**\n     * Set the default locale.\n     *\n     * @param  string  $locale\n     * @return void\n     */\n    public function setLocale($locale);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Validation/DataAwareRule.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Validation;\n\ninterface DataAwareRule\n{\n    /**\n     * Set the data under validation.\n     *\n     * @param  array  $data\n     * @return $this\n     */\n    public function setData($data);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Validation/Factory.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Validation;\n\ninterface Factory\n{\n    /**\n     * Create a new Validator instance.\n     *\n     * @param  array  $data\n     * @param  array  $rules\n     * @param  array  $messages\n     * @param  array  $customAttributes\n     * @return \\Illuminate\\Contracts\\Validation\\Validator\n     */\n    public function make(array $data, array $rules, array $messages = [], array $customAttributes = []);\n\n    /**\n     * Register a custom validator extension.\n     *\n     * @param  string  $rule\n     * @param  \\Closure|string  $extension\n     * @param  string|null  $message\n     * @return void\n     */\n    public function extend($rule, $extension, $message = null);\n\n    /**\n     * Register a custom implicit validator extension.\n     *\n     * @param  string  $rule\n     * @param  \\Closure|string  $extension\n     * @param  string|null  $message\n     * @return void\n     */\n    public function extendImplicit($rule, $extension, $message = null);\n\n    /**\n     * Register a custom implicit validator message replacer.\n     *\n     * @param  string  $rule\n     * @param  \\Closure|string  $replacer\n     * @return void\n     */\n    public function replacer($rule, $replacer);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Validation/ImplicitRule.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Validation;\n\ninterface ImplicitRule extends Rule\n{\n    //\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Validation/Rule.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Validation;\n\ninterface Rule\n{\n    /**\n     * Determine if the validation rule passes.\n     *\n     * @param  string  $attribute\n     * @param  mixed  $value\n     * @return bool\n     */\n    public function passes($attribute, $value);\n\n    /**\n     * Get the validation error message.\n     *\n     * @return string|array\n     */\n    public function message();\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Validation/UncompromisedVerifier.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Validation;\n\ninterface UncompromisedVerifier\n{\n    /**\n     * Verify that the given data has not been compromised in data leaks.\n     *\n     * @param  array  $data\n     * @return bool\n     */\n    public function verify($data);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Validation/ValidatesWhenResolved.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Validation;\n\ninterface ValidatesWhenResolved\n{\n    /**\n     * Validate the given class instance.\n     *\n     * @return void\n     */\n    public function validateResolved();\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Validation/Validator.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Validation;\n\nuse Illuminate\\Contracts\\Support\\MessageProvider;\n\ninterface Validator extends MessageProvider\n{\n    /**\n     * Run the validator's rules against its data.\n     *\n     * @return array\n     *\n     * @throws \\Illuminate\\Validation\\ValidationException\n     */\n    public function validate();\n\n    /**\n     * Get the attributes and values that were validated.\n     *\n     * @return array\n     *\n     * @throws \\Illuminate\\Validation\\ValidationException\n     */\n    public function validated();\n\n    /**\n     * Determine if the data fails the validation rules.\n     *\n     * @return bool\n     */\n    public function fails();\n\n    /**\n     * Get the failed validation rules.\n     *\n     * @return array\n     */\n    public function failed();\n\n    /**\n     * Add conditions to a given field based on a Closure.\n     *\n     * @param  string|array  $attribute\n     * @param  string|array  $rules\n     * @param  callable  $callback\n     * @return $this\n     */\n    public function sometimes($attribute, $rules, callable $callback);\n\n    /**\n     * Add an after validation callback.\n     *\n     * @param  callable|string  $callback\n     * @return $this\n     */\n    public function after($callback);\n\n    /**\n     * Get all of the validation error messages.\n     *\n     * @return \\Illuminate\\Support\\MessageBag\n     */\n    public function errors();\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/Validation/ValidatorAwareRule.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\Validation;\n\ninterface ValidatorAwareRule\n{\n    /**\n     * Set the current validator.\n     *\n     * @param  \\Illuminate\\Validation\\Validator  $validator\n     * @return $this\n     */\n    public function setValidator($validator);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/View/Engine.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\View;\n\ninterface Engine\n{\n    /**\n     * Get the evaluated contents of the view.\n     *\n     * @param  string  $path\n     * @param  array  $data\n     * @return string\n     */\n    public function get($path, array $data = []);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/View/Factory.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\View;\n\ninterface Factory\n{\n    /**\n     * Determine if a given view exists.\n     *\n     * @param  string  $view\n     * @return bool\n     */\n    public function exists($view);\n\n    /**\n     * Get the evaluated view contents for the given path.\n     *\n     * @param  string  $path\n     * @param  \\Illuminate\\Contracts\\Support\\Arrayable|array  $data\n     * @param  array  $mergeData\n     * @return \\Illuminate\\Contracts\\View\\View\n     */\n    public function file($path, $data = [], $mergeData = []);\n\n    /**\n     * Get the evaluated view contents for the given view.\n     *\n     * @param  string  $view\n     * @param  \\Illuminate\\Contracts\\Support\\Arrayable|array  $data\n     * @param  array  $mergeData\n     * @return \\Illuminate\\Contracts\\View\\View\n     */\n    public function make($view, $data = [], $mergeData = []);\n\n    /**\n     * Add a piece of shared data to the environment.\n     *\n     * @param  array|string  $key\n     * @param  mixed  $value\n     * @return mixed\n     */\n    public function share($key, $value = null);\n\n    /**\n     * Register a view composer event.\n     *\n     * @param  array|string  $views\n     * @param  \\Closure|string  $callback\n     * @return array\n     */\n    public function composer($views, $callback);\n\n    /**\n     * Register a view creator event.\n     *\n     * @param  array|string  $views\n     * @param  \\Closure|string  $callback\n     * @return array\n     */\n    public function creator($views, $callback);\n\n    /**\n     * Add a new namespace to the loader.\n     *\n     * @param  string  $namespace\n     * @param  string|array  $hints\n     * @return $this\n     */\n    public function addNamespace($namespace, $hints);\n\n    /**\n     * Replace the namespace hints for the given namespace.\n     *\n     * @param  string  $namespace\n     * @param  string|array  $hints\n     * @return $this\n     */\n    public function replaceNamespace($namespace, $hints);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/View/View.php",
    "content": "<?php\n\nnamespace Illuminate\\Contracts\\View;\n\nuse Illuminate\\Contracts\\Support\\Renderable;\n\ninterface View extends Renderable\n{\n    /**\n     * Get the name of the view.\n     *\n     * @return string\n     */\n    public function name();\n\n    /**\n     * Add a piece of data to the view.\n     *\n     * @param  string|array  $key\n     * @param  mixed  $value\n     * @return $this\n     */\n    public function with($key, $value = null);\n\n    /**\n     * Get the array of view data.\n     *\n     * @return array\n     */\n    public function getData();\n}\n"
  },
  {
    "path": "server/vendor/illuminate/contracts/composer.json",
    "content": "{\n    \"name\": \"illuminate/contracts\",\n    \"description\": \"The Illuminate Contracts package.\",\n    \"license\": \"MIT\",\n    \"homepage\": \"https://laravel.com\",\n    \"support\": {\n        \"issues\": \"https://github.com/laravel/framework/issues\",\n        \"source\": \"https://github.com/laravel/framework\"\n    },\n    \"authors\": [\n        {\n            \"name\": \"Taylor Otwell\",\n            \"email\": \"taylor@laravel.com\"\n        }\n    ],\n    \"require\": {\n        \"php\": \"^7.3|^8.0\",\n        \"psr/container\": \"^1.0\",\n        \"psr/simple-cache\": \"^1.0\"\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"Illuminate\\\\Contracts\\\\\": \"\"\n        }\n    },\n    \"extra\": {\n        \"branch-alias\": {\n            \"dev-master\": \"8.x-dev\"\n        }\n    },\n    \"config\": {\n        \"sort-packages\": true\n    },\n    \"minimum-stability\": \"dev\"\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Capsule/Manager.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Capsule;\n\nuse Illuminate\\Container\\Container;\nuse Illuminate\\Contracts\\Events\\Dispatcher;\nuse Illuminate\\Database\\Connectors\\ConnectionFactory;\nuse Illuminate\\Database\\DatabaseManager;\nuse Illuminate\\Database\\Eloquent\\Model as Eloquent;\nuse Illuminate\\Support\\Traits\\CapsuleManagerTrait;\nuse PDO;\n\nclass Manager\n{\n    use CapsuleManagerTrait;\n\n    /**\n     * The database manager instance.\n     *\n     * @var \\Illuminate\\Database\\DatabaseManager\n     */\n    protected $manager;\n\n    /**\n     * Create a new database capsule manager.\n     *\n     * @param  \\Illuminate\\Container\\Container|null  $container\n     * @return void\n     */\n    public function __construct(Container $container = null)\n    {\n        $this->setupContainer($container ?: new Container);\n\n        // Once we have the container setup, we will setup the default configuration\n        // options in the container \"config\" binding. This will make the database\n        // manager work correctly out of the box without extreme configuration.\n        $this->setupDefaultConfiguration();\n\n        $this->setupManager();\n    }\n\n    /**\n     * Setup the default database configuration options.\n     *\n     * @return void\n     */\n    protected function setupDefaultConfiguration()\n    {\n        $this->container['config']['database.fetch'] = PDO::FETCH_OBJ;\n\n        $this->container['config']['database.default'] = 'default';\n    }\n\n    /**\n     * Build the database manager instance.\n     *\n     * @return void\n     */\n    protected function setupManager()\n    {\n        $factory = new ConnectionFactory($this->container);\n\n        $this->manager = new DatabaseManager($this->container, $factory);\n    }\n\n    /**\n     * Get a connection instance from the global manager.\n     *\n     * @param  string|null  $connection\n     * @return \\Illuminate\\Database\\Connection\n     */\n    public static function connection($connection = null)\n    {\n        return static::$instance->getConnection($connection);\n    }\n\n    /**\n     * Get a fluent query builder instance.\n     *\n     * @param  \\Closure|\\Illuminate\\Database\\Query\\Builder|string  $table\n     * @param  string|null  $as\n     * @param  string|null  $connection\n     * @return \\Illuminate\\Database\\Query\\Builder\n     */\n    public static function table($table, $as = null, $connection = null)\n    {\n        return static::$instance->connection($connection)->table($table, $as);\n    }\n\n    /**\n     * Get a schema builder instance.\n     *\n     * @param  string|null  $connection\n     * @return \\Illuminate\\Database\\Schema\\Builder\n     */\n    public static function schema($connection = null)\n    {\n        return static::$instance->connection($connection)->getSchemaBuilder();\n    }\n\n    /**\n     * Get a registered connection instance.\n     *\n     * @param  string|null  $name\n     * @return \\Illuminate\\Database\\Connection\n     */\n    public function getConnection($name = null)\n    {\n        return $this->manager->connection($name);\n    }\n\n    /**\n     * Register a connection with the manager.\n     *\n     * @param  array  $config\n     * @param  string  $name\n     * @return void\n     */\n    public function addConnection(array $config, $name = 'default')\n    {\n        $connections = $this->container['config']['database.connections'];\n\n        $connections[$name] = $config;\n\n        $this->container['config']['database.connections'] = $connections;\n    }\n\n    /**\n     * Bootstrap Eloquent so it is ready for usage.\n     *\n     * @return void\n     */\n    public function bootEloquent()\n    {\n        Eloquent::setConnectionResolver($this->manager);\n\n        // If we have an event dispatcher instance, we will go ahead and register it\n        // with the Eloquent ORM, allowing for model callbacks while creating and\n        // updating \"model\" instances; however, it is not necessary to operate.\n        if ($dispatcher = $this->getEventDispatcher()) {\n            Eloquent::setEventDispatcher($dispatcher);\n        }\n    }\n\n    /**\n     * Set the fetch mode for the database connections.\n     *\n     * @param  int  $fetchMode\n     * @return $this\n     */\n    public function setFetchMode($fetchMode)\n    {\n        $this->container['config']['database.fetch'] = $fetchMode;\n\n        return $this;\n    }\n\n    /**\n     * Get the database manager instance.\n     *\n     * @return \\Illuminate\\Database\\DatabaseManager\n     */\n    public function getDatabaseManager()\n    {\n        return $this->manager;\n    }\n\n    /**\n     * Get the current event dispatcher instance.\n     *\n     * @return \\Illuminate\\Contracts\\Events\\Dispatcher|null\n     */\n    public function getEventDispatcher()\n    {\n        if ($this->container->bound('events')) {\n            return $this->container['events'];\n        }\n    }\n\n    /**\n     * Set the event dispatcher instance to be used by connections.\n     *\n     * @param  \\Illuminate\\Contracts\\Events\\Dispatcher  $dispatcher\n     * @return void\n     */\n    public function setEventDispatcher(Dispatcher $dispatcher)\n    {\n        $this->container->instance('events', $dispatcher);\n    }\n\n    /**\n     * Dynamically pass methods to the default connection.\n     *\n     * @param  string  $method\n     * @param  array  $parameters\n     * @return mixed\n     */\n    public static function __callStatic($method, $parameters)\n    {\n        return static::connection()->$method(...$parameters);\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/ClassMorphViolationException.php",
    "content": "<?php\n\nnamespace Illuminate\\Database;\n\nuse RuntimeException;\n\nclass ClassMorphViolationException extends RuntimeException\n{\n    /**\n     * The name of the affected Eloquent model.\n     *\n     * @var string\n     */\n    public $model;\n\n    /**\n     * Create a new exception instance.\n     *\n     * @param  object  $model\n     */\n    public function __construct($model)\n    {\n        $class = get_class($model);\n\n        parent::__construct(\"No morph map defined for model [{$class}].\");\n\n        $this->model = $class;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Concerns/BuildsQueries.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Concerns;\n\nuse Illuminate\\Container\\Container;\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Illuminate\\Database\\MultipleRecordsFoundException;\nuse Illuminate\\Database\\RecordsNotFoundException;\nuse Illuminate\\Pagination\\Cursor;\nuse Illuminate\\Pagination\\CursorPaginator;\nuse Illuminate\\Pagination\\LengthAwarePaginator;\nuse Illuminate\\Pagination\\Paginator;\nuse Illuminate\\Support\\Collection;\nuse Illuminate\\Support\\LazyCollection;\nuse Illuminate\\Support\\Traits\\Conditionable;\nuse InvalidArgumentException;\nuse RuntimeException;\n\ntrait BuildsQueries\n{\n    use Conditionable;\n\n    /**\n     * Chunk the results of the query.\n     *\n     * @param  int  $count\n     * @param  callable  $callback\n     * @return bool\n     */\n    public function chunk($count, callable $callback)\n    {\n        $this->enforceOrderBy();\n\n        $page = 1;\n\n        do {\n            // We'll execute the query for the given page and get the results. If there are\n            // no results we can just break and return from here. When there are results\n            // we will call the callback with the current chunk of these results here.\n            $results = $this->forPage($page, $count)->get();\n\n            $countResults = $results->count();\n\n            if ($countResults == 0) {\n                break;\n            }\n\n            // On each chunk result set, we will pass them to the callback and then let the\n            // developer take care of everything within the callback, which allows us to\n            // keep the memory low for spinning through large result sets for working.\n            if ($callback($results, $page) === false) {\n                return false;\n            }\n\n            unset($results);\n\n            $page++;\n        } while ($countResults == $count);\n\n        return true;\n    }\n\n    /**\n     * Run a map over each item while chunking.\n     *\n     * @param  callable  $callback\n     * @param  int  $count\n     * @return \\Illuminate\\Support\\Collection\n     */\n    public function chunkMap(callable $callback, $count = 1000)\n    {\n        $collection = Collection::make();\n\n        $this->chunk($count, function ($items) use ($collection, $callback) {\n            $items->each(function ($item) use ($collection, $callback) {\n                $collection->push($callback($item));\n            });\n        });\n\n        return $collection;\n    }\n\n    /**\n     * Execute a callback over each item while chunking.\n     *\n     * @param  callable  $callback\n     * @param  int  $count\n     * @return bool\n     *\n     * @throws \\RuntimeException\n     */\n    public function each(callable $callback, $count = 1000)\n    {\n        return $this->chunk($count, function ($results) use ($callback) {\n            foreach ($results as $key => $value) {\n                if ($callback($value, $key) === false) {\n                    return false;\n                }\n            }\n        });\n    }\n\n    /**\n     * Chunk the results of a query by comparing IDs.\n     *\n     * @param  int  $count\n     * @param  callable  $callback\n     * @param  string|null  $column\n     * @param  string|null  $alias\n     * @return bool\n     */\n    public function chunkById($count, callable $callback, $column = null, $alias = null)\n    {\n        $column = $column ?? $this->defaultKeyName();\n\n        $alias = $alias ?? $column;\n\n        $lastId = null;\n\n        $page = 1;\n\n        do {\n            $clone = clone $this;\n\n            // We'll execute the query for the given page and get the results. If there are\n            // no results we can just break and return from here. When there are results\n            // we will call the callback with the current chunk of these results here.\n            $results = $clone->forPageAfterId($count, $lastId, $column)->get();\n\n            $countResults = $results->count();\n\n            if ($countResults == 0) {\n                break;\n            }\n\n            // On each chunk result set, we will pass them to the callback and then let the\n            // developer take care of everything within the callback, which allows us to\n            // keep the memory low for spinning through large result sets for working.\n            if ($callback($results, $page) === false) {\n                return false;\n            }\n\n            $lastId = $results->last()->{$alias};\n\n            if ($lastId === null) {\n                throw new RuntimeException(\"The chunkById operation was aborted because the [{$alias}] column is not present in the query result.\");\n            }\n\n            unset($results);\n\n            $page++;\n        } while ($countResults == $count);\n\n        return true;\n    }\n\n    /**\n     * Execute a callback over each item while chunking by ID.\n     *\n     * @param  callable  $callback\n     * @param  int  $count\n     * @param  string|null  $column\n     * @param  string|null  $alias\n     * @return bool\n     */\n    public function eachById(callable $callback, $count = 1000, $column = null, $alias = null)\n    {\n        return $this->chunkById($count, function ($results, $page) use ($callback, $count) {\n            foreach ($results as $key => $value) {\n                if ($callback($value, (($page - 1) * $count) + $key) === false) {\n                    return false;\n                }\n            }\n        }, $column, $alias);\n    }\n\n    /**\n     * Query lazily, by chunks of the given size.\n     *\n     * @param  int  $chunkSize\n     * @return \\Illuminate\\Support\\LazyCollection\n     *\n     * @throws \\InvalidArgumentException\n     */\n    public function lazy($chunkSize = 1000)\n    {\n        if ($chunkSize < 1) {\n            throw new InvalidArgumentException('The chunk size should be at least 1');\n        }\n\n        $this->enforceOrderBy();\n\n        return LazyCollection::make(function () use ($chunkSize) {\n            $page = 1;\n\n            while (true) {\n                $results = $this->forPage($page++, $chunkSize)->get();\n\n                foreach ($results as $result) {\n                    yield $result;\n                }\n\n                if ($results->count() < $chunkSize) {\n                    return;\n                }\n            }\n        });\n    }\n\n    /**\n     * Query lazily, by chunking the results of a query by comparing IDs.\n     *\n     * @param  int  $chunkSize\n     * @param  string|null  $column\n     * @param  string|null  $alias\n     * @return \\Illuminate\\Support\\LazyCollection\n     *\n     * @throws \\InvalidArgumentException\n     */\n    public function lazyById($chunkSize = 1000, $column = null, $alias = null)\n    {\n        return $this->orderedLazyById($chunkSize, $column, $alias);\n    }\n\n    /**\n     * Query lazily, by chunking the results of a query by comparing IDs in descending order.\n     *\n     * @param  int  $chunkSize\n     * @param  string|null  $column\n     * @param  string|null  $alias\n     * @return \\Illuminate\\Support\\LazyCollection\n     *\n     * @throws \\InvalidArgumentException\n     */\n    public function lazyByIdDesc($chunkSize = 1000, $column = null, $alias = null)\n    {\n        return $this->orderedLazyById($chunkSize, $column, $alias, true);\n    }\n\n    /**\n     * Query lazily, by chunking the results of a query by comparing IDs in a given order.\n     *\n     * @param  int  $chunkSize\n     * @param  string|null  $column\n     * @param  string|null  $alias\n     * @param  bool  $descending\n     * @return \\Illuminate\\Support\\LazyCollection\n     *\n     * @throws \\InvalidArgumentException\n     */\n    protected function orderedLazyById($chunkSize = 1000, $column = null, $alias = null, $descending = false)\n    {\n        if ($chunkSize < 1) {\n            throw new InvalidArgumentException('The chunk size should be at least 1');\n        }\n\n        $column = $column ?? $this->defaultKeyName();\n\n        $alias = $alias ?? $column;\n\n        return LazyCollection::make(function () use ($chunkSize, $column, $alias, $descending) {\n            $lastId = null;\n\n            while (true) {\n                $clone = clone $this;\n\n                if ($descending) {\n                    $results = $clone->forPageBeforeId($chunkSize, $lastId, $column)->get();\n                } else {\n                    $results = $clone->forPageAfterId($chunkSize, $lastId, $column)->get();\n                }\n\n                foreach ($results as $result) {\n                    yield $result;\n                }\n\n                if ($results->count() < $chunkSize) {\n                    return;\n                }\n\n                $lastId = $results->last()->{$alias};\n            }\n        });\n    }\n\n    /**\n     * Execute the query and get the first result.\n     *\n     * @param  array|string  $columns\n     * @return \\Illuminate\\Database\\Eloquent\\Model|object|static|null\n     */\n    public function first($columns = ['*'])\n    {\n        return $this->take(1)->get($columns)->first();\n    }\n\n    /**\n     * Execute the query and get the first result if it's the sole matching record.\n     *\n     * @param  array|string  $columns\n     * @return \\Illuminate\\Database\\Eloquent\\Model|object|static|null\n     *\n     * @throws \\Illuminate\\Database\\RecordsNotFoundException\n     * @throws \\Illuminate\\Database\\MultipleRecordsFoundException\n     */\n    public function sole($columns = ['*'])\n    {\n        $result = $this->take(2)->get($columns);\n\n        if ($result->isEmpty()) {\n            throw new RecordsNotFoundException;\n        }\n\n        if ($result->count() > 1) {\n            throw new MultipleRecordsFoundException;\n        }\n\n        return $result->first();\n    }\n\n    /**\n     * Paginate the given query using a cursor paginator.\n     *\n     * @param  int  $perPage\n     * @param  array  $columns\n     * @param  string  $cursorName\n     * @param  \\Illuminate\\Pagination\\Cursor|string|null  $cursor\n     * @return \\Illuminate\\Contracts\\Pagination\\CursorPaginator\n     */\n    protected function paginateUsingCursor($perPage, $columns = ['*'], $cursorName = 'cursor', $cursor = null)\n    {\n        if (! $cursor instanceof Cursor) {\n            $cursor = is_string($cursor)\n                ? Cursor::fromEncoded($cursor)\n                : CursorPaginator::resolveCurrentCursor($cursorName, $cursor);\n        }\n\n        $orders = $this->ensureOrderForCursorPagination(! is_null($cursor) && $cursor->pointsToPreviousItems());\n\n        if (! is_null($cursor)) {\n            $addCursorConditions = function (self $builder, $previousColumn, $i) use (&$addCursorConditions, $cursor, $orders) {\n                $unionBuilders = isset($builder->unions) ? collect($builder->unions)->pluck('query') : collect();\n\n                if (! is_null($previousColumn)) {\n                    $builder->where(\n                        $this->getOriginalColumnNameForCursorPagination($this, $previousColumn),\n                        '=',\n                        $cursor->parameter($previousColumn)\n                    );\n\n                    $unionBuilders->each(function ($unionBuilder) use ($previousColumn, $cursor) {\n                        $unionBuilder->where(\n                            $this->getOriginalColumnNameForCursorPagination($this, $previousColumn),\n                            '=',\n                            $cursor->parameter($previousColumn)\n                        );\n\n                        $this->addBinding($unionBuilder->getRawBindings()['where'], 'union');\n                    });\n                }\n\n                $builder->where(function (self $builder) use ($addCursorConditions, $cursor, $orders, $i, $unionBuilders) {\n                    ['column' => $column, 'direction' => $direction] = $orders[$i];\n\n                    $builder->where(\n                        $this->getOriginalColumnNameForCursorPagination($this, $column),\n                        $direction === 'asc' ? '>' : '<',\n                        $cursor->parameter($column)\n                    );\n\n                    if ($i < $orders->count() - 1) {\n                        $builder->orWhere(function (self $builder) use ($addCursorConditions, $column, $i) {\n                            $addCursorConditions($builder, $column, $i + 1);\n                        });\n                    }\n\n                    $unionBuilders->each(function ($unionBuilder) use ($column, $direction, $cursor, $i, $orders, $addCursorConditions) {\n                        $unionBuilder->where(function ($unionBuilder) use ($column, $direction, $cursor, $i, $orders, $addCursorConditions) {\n                            $unionBuilder->where(\n                                $this->getOriginalColumnNameForCursorPagination($this, $column),\n                                $direction === 'asc' ? '>' : '<',\n                                $cursor->parameter($column)\n                            );\n\n                            if ($i < $orders->count() - 1) {\n                                $unionBuilder->orWhere(function (self $builder) use ($addCursorConditions, $column, $i) {\n                                    $addCursorConditions($builder, $column, $i + 1);\n                                });\n                            }\n\n                            $this->addBinding($unionBuilder->getRawBindings()['where'], 'union');\n                        });\n                    });\n                });\n            };\n\n            $addCursorConditions($this, null, 0);\n        }\n\n        $this->limit($perPage + 1);\n\n        return $this->cursorPaginator($this->get($columns), $perPage, $cursor, [\n            'path' => Paginator::resolveCurrentPath(),\n            'cursorName' => $cursorName,\n            'parameters' => $orders->pluck('column')->toArray(),\n        ]);\n    }\n\n    /**\n     * Get the original column name of the given column, without any aliasing.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder|\\Illuminate\\Database\\Eloquent\\Builder  $builder\n     * @param  string  $parameter\n     * @return string\n     */\n    protected function getOriginalColumnNameForCursorPagination($builder, string $parameter)\n    {\n        $columns = $builder instanceof Builder ? $builder->getQuery()->columns : $builder->columns;\n\n        if (! is_null($columns)) {\n            foreach ($columns as $column) {\n                if (($position = stripos($column, ' as ')) !== false) {\n                    $as = substr($column, $position, 4);\n\n                    [$original, $alias] = explode($as, $column);\n\n                    if ($parameter === $alias) {\n                        return $original;\n                    }\n                }\n            }\n        }\n\n        return $parameter;\n    }\n\n    /**\n     * Create a new length-aware paginator instance.\n     *\n     * @param  \\Illuminate\\Support\\Collection  $items\n     * @param  int  $total\n     * @param  int  $perPage\n     * @param  int  $currentPage\n     * @param  array  $options\n     * @return \\Illuminate\\Pagination\\LengthAwarePaginator\n     */\n    protected function paginator($items, $total, $perPage, $currentPage, $options)\n    {\n        return Container::getInstance()->makeWith(LengthAwarePaginator::class, compact(\n            'items', 'total', 'perPage', 'currentPage', 'options'\n        ));\n    }\n\n    /**\n     * Create a new simple paginator instance.\n     *\n     * @param  \\Illuminate\\Support\\Collection  $items\n     * @param  int  $perPage\n     * @param  int  $currentPage\n     * @param  array  $options\n     * @return \\Illuminate\\Pagination\\Paginator\n     */\n    protected function simplePaginator($items, $perPage, $currentPage, $options)\n    {\n        return Container::getInstance()->makeWith(Paginator::class, compact(\n            'items', 'perPage', 'currentPage', 'options'\n        ));\n    }\n\n    /**\n     * Create a new cursor paginator instance.\n     *\n     * @param  \\Illuminate\\Support\\Collection  $items\n     * @param  int  $perPage\n     * @param  \\Illuminate\\Pagination\\Cursor  $cursor\n     * @param  array  $options\n     * @return \\Illuminate\\Pagination\\CursorPaginator\n     */\n    protected function cursorPaginator($items, $perPage, $cursor, $options)\n    {\n        return Container::getInstance()->makeWith(CursorPaginator::class, compact(\n            'items', 'perPage', 'cursor', 'options'\n        ));\n    }\n\n    /**\n     * Pass the query to a given callback.\n     *\n     * @param  callable  $callback\n     * @return $this|mixed\n     */\n    public function tap($callback)\n    {\n        return $this->when(true, $callback);\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Concerns/ExplainsQueries.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Concerns;\n\nuse Illuminate\\Support\\Collection;\n\ntrait ExplainsQueries\n{\n    /**\n     * Explains the query.\n     *\n     * @return \\Illuminate\\Support\\Collection\n     */\n    public function explain()\n    {\n        $sql = $this->toSql();\n\n        $bindings = $this->getBindings();\n\n        $explanation = $this->getConnection()->select('EXPLAIN '.$sql, $bindings);\n\n        return new Collection($explanation);\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Concerns/ManagesTransactions.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Concerns;\n\nuse Closure;\nuse RuntimeException;\nuse Throwable;\n\ntrait ManagesTransactions\n{\n    /**\n     * Execute a Closure within a transaction.\n     *\n     * @param  \\Closure  $callback\n     * @param  int  $attempts\n     * @return mixed\n     *\n     * @throws \\Throwable\n     */\n    public function transaction(Closure $callback, $attempts = 1)\n    {\n        for ($currentAttempt = 1; $currentAttempt <= $attempts; $currentAttempt++) {\n            $this->beginTransaction();\n\n            // We'll simply execute the given callback within a try / catch block and if we\n            // catch any exception we can rollback this transaction so that none of this\n            // gets actually persisted to a database or stored in a permanent fashion.\n            try {\n                $callbackResult = $callback($this);\n            }\n\n            // If we catch an exception we'll rollback this transaction and try again if we\n            // are not out of attempts. If we are out of attempts we will just throw the\n            // exception back out and let the developer handle an uncaught exceptions.\n            catch (Throwable $e) {\n                $this->handleTransactionException(\n                    $e, $currentAttempt, $attempts\n                );\n\n                continue;\n            }\n\n            try {\n                if ($this->transactions == 1) {\n                    $this->getPdo()->commit();\n                }\n\n                $this->transactions = max(0, $this->transactions - 1);\n\n                if ($this->transactions == 0) {\n                    optional($this->transactionsManager)->commit($this->getName());\n                }\n            } catch (Throwable $e) {\n                $this->handleCommitTransactionException(\n                    $e, $currentAttempt, $attempts\n                );\n\n                continue;\n            }\n\n            $this->fireConnectionEvent('committed');\n\n            return $callbackResult;\n        }\n    }\n\n    /**\n     * Handle an exception encountered when running a transacted statement.\n     *\n     * @param  \\Throwable  $e\n     * @param  int  $currentAttempt\n     * @param  int  $maxAttempts\n     * @return void\n     *\n     * @throws \\Throwable\n     */\n    protected function handleTransactionException(Throwable $e, $currentAttempt, $maxAttempts)\n    {\n        // On a deadlock, MySQL rolls back the entire transaction so we can't just\n        // retry the query. We have to throw this exception all the way out and\n        // let the developer handle it in another way. We will decrement too.\n        if ($this->causedByConcurrencyError($e) &&\n            $this->transactions > 1) {\n            $this->transactions--;\n\n            optional($this->transactionsManager)->rollback(\n                $this->getName(), $this->transactions\n            );\n\n            throw $e;\n        }\n\n        // If there was an exception we will rollback this transaction and then we\n        // can check if we have exceeded the maximum attempt count for this and\n        // if we haven't we will return and try this query again in our loop.\n        $this->rollBack();\n\n        if ($this->causedByConcurrencyError($e) &&\n            $currentAttempt < $maxAttempts) {\n            return;\n        }\n\n        throw $e;\n    }\n\n    /**\n     * Start a new database transaction.\n     *\n     * @return void\n     *\n     * @throws \\Throwable\n     */\n    public function beginTransaction()\n    {\n        $this->createTransaction();\n\n        $this->transactions++;\n\n        optional($this->transactionsManager)->begin(\n            $this->getName(), $this->transactions\n        );\n\n        $this->fireConnectionEvent('beganTransaction');\n    }\n\n    /**\n     * Create a transaction within the database.\n     *\n     * @return void\n     *\n     * @throws \\Throwable\n     */\n    protected function createTransaction()\n    {\n        if ($this->transactions == 0) {\n            $this->reconnectIfMissingConnection();\n\n            try {\n                $this->getPdo()->beginTransaction();\n            } catch (Throwable $e) {\n                $this->handleBeginTransactionException($e);\n            }\n        } elseif ($this->transactions >= 1 && $this->queryGrammar->supportsSavepoints()) {\n            $this->createSavepoint();\n        }\n    }\n\n    /**\n     * Create a save point within the database.\n     *\n     * @return void\n     *\n     * @throws \\Throwable\n     */\n    protected function createSavepoint()\n    {\n        $this->getPdo()->exec(\n            $this->queryGrammar->compileSavepoint('trans'.($this->transactions + 1))\n        );\n    }\n\n    /**\n     * Handle an exception from a transaction beginning.\n     *\n     * @param  \\Throwable  $e\n     * @return void\n     *\n     * @throws \\Throwable\n     */\n    protected function handleBeginTransactionException(Throwable $e)\n    {\n        if ($this->causedByLostConnection($e)) {\n            $this->reconnect();\n\n            $this->getPdo()->beginTransaction();\n        } else {\n            throw $e;\n        }\n    }\n\n    /**\n     * Commit the active database transaction.\n     *\n     * @return void\n     *\n     * @throws \\Throwable\n     */\n    public function commit()\n    {\n        if ($this->transactions == 1) {\n            $this->getPdo()->commit();\n        }\n\n        $this->transactions = max(0, $this->transactions - 1);\n\n        if ($this->transactions == 0) {\n            optional($this->transactionsManager)->commit($this->getName());\n        }\n\n        $this->fireConnectionEvent('committed');\n    }\n\n    /**\n     * Handle an exception encountered when committing a transaction.\n     *\n     * @param  \\Throwable  $e\n     * @param  int  $currentAttempt\n     * @param  int  $maxAttempts\n     * @return void\n     *\n     * @throws \\Throwable\n     */\n    protected function handleCommitTransactionException(Throwable $e, $currentAttempt, $maxAttempts)\n    {\n        $this->transactions = max(0, $this->transactions - 1);\n\n        if ($this->causedByConcurrencyError($e) &&\n            $currentAttempt < $maxAttempts) {\n            return;\n        }\n\n        if ($this->causedByLostConnection($e)) {\n            $this->transactions = 0;\n        }\n\n        throw $e;\n    }\n\n    /**\n     * Rollback the active database transaction.\n     *\n     * @param  int|null  $toLevel\n     * @return void\n     *\n     * @throws \\Throwable\n     */\n    public function rollBack($toLevel = null)\n    {\n        // We allow developers to rollback to a certain transaction level. We will verify\n        // that this given transaction level is valid before attempting to rollback to\n        // that level. If it's not we will just return out and not attempt anything.\n        $toLevel = is_null($toLevel)\n                    ? $this->transactions - 1\n                    : $toLevel;\n\n        if ($toLevel < 0 || $toLevel >= $this->transactions) {\n            return;\n        }\n\n        // Next, we will actually perform this rollback within this database and fire the\n        // rollback event. We will also set the current transaction level to the given\n        // level that was passed into this method so it will be right from here out.\n        try {\n            $this->performRollBack($toLevel);\n        } catch (Throwable $e) {\n            $this->handleRollBackException($e);\n        }\n\n        $this->transactions = $toLevel;\n\n        optional($this->transactionsManager)->rollback(\n            $this->getName(), $this->transactions\n        );\n\n        $this->fireConnectionEvent('rollingBack');\n    }\n\n    /**\n     * Perform a rollback within the database.\n     *\n     * @param  int  $toLevel\n     * @return void\n     *\n     * @throws \\Throwable\n     */\n    protected function performRollBack($toLevel)\n    {\n        if ($toLevel == 0) {\n            $this->getPdo()->rollBack();\n        } elseif ($this->queryGrammar->supportsSavepoints()) {\n            $this->getPdo()->exec(\n                $this->queryGrammar->compileSavepointRollBack('trans'.($toLevel + 1))\n            );\n        }\n    }\n\n    /**\n     * Handle an exception from a rollback.\n     *\n     * @param  \\Throwable  $e\n     * @return void\n     *\n     * @throws \\Throwable\n     */\n    protected function handleRollBackException(Throwable $e)\n    {\n        if ($this->causedByLostConnection($e)) {\n            $this->transactions = 0;\n\n            optional($this->transactionsManager)->rollback(\n                $this->getName(), $this->transactions\n            );\n        }\n\n        throw $e;\n    }\n\n    /**\n     * Get the number of active transactions.\n     *\n     * @return int\n     */\n    public function transactionLevel()\n    {\n        return $this->transactions;\n    }\n\n    /**\n     * Execute the callback after a transaction commits.\n     *\n     * @param  callable  $callback\n     * @return void\n     *\n     * @throws \\RuntimeException\n     */\n    public function afterCommit($callback)\n    {\n        if ($this->transactionsManager) {\n            return $this->transactionsManager->addCallback($callback);\n        }\n\n        throw new RuntimeException('Transactions Manager has not been set.');\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/ConfigurationUrlParser.php",
    "content": "<?php\n\nnamespace Illuminate\\Database;\n\nuse Illuminate\\Support\\ConfigurationUrlParser as BaseConfigurationUrlParser;\n\nclass ConfigurationUrlParser extends BaseConfigurationUrlParser\n{\n    //\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Connection.php",
    "content": "<?php\n\nnamespace Illuminate\\Database;\n\nuse Closure;\nuse DateTimeInterface;\nuse Doctrine\\DBAL\\Connection as DoctrineConnection;\nuse Doctrine\\DBAL\\Types\\Type;\nuse Exception;\nuse Illuminate\\Contracts\\Events\\Dispatcher;\nuse Illuminate\\Database\\Events\\QueryExecuted;\nuse Illuminate\\Database\\Events\\StatementPrepared;\nuse Illuminate\\Database\\Events\\TransactionBeginning;\nuse Illuminate\\Database\\Events\\TransactionCommitted;\nuse Illuminate\\Database\\Events\\TransactionRolledBack;\nuse Illuminate\\Database\\Query\\Builder as QueryBuilder;\nuse Illuminate\\Database\\Query\\Expression;\nuse Illuminate\\Database\\Query\\Grammars\\Grammar as QueryGrammar;\nuse Illuminate\\Database\\Query\\Processors\\Processor;\nuse Illuminate\\Database\\Schema\\Builder as SchemaBuilder;\nuse Illuminate\\Support\\Arr;\nuse LogicException;\nuse PDO;\nuse PDOStatement;\nuse RuntimeException;\n\nclass Connection implements ConnectionInterface\n{\n    use DetectsConcurrencyErrors,\n        DetectsLostConnections,\n        Concerns\\ManagesTransactions;\n\n    /**\n     * The active PDO connection.\n     *\n     * @var \\PDO|\\Closure\n     */\n    protected $pdo;\n\n    /**\n     * The active PDO connection used for reads.\n     *\n     * @var \\PDO|\\Closure\n     */\n    protected $readPdo;\n\n    /**\n     * The name of the connected database.\n     *\n     * @var string\n     */\n    protected $database;\n\n    /**\n     * The type of the connection.\n     *\n     * @var string|null\n     */\n    protected $readWriteType;\n\n    /**\n     * The table prefix for the connection.\n     *\n     * @var string\n     */\n    protected $tablePrefix = '';\n\n    /**\n     * The database connection configuration options.\n     *\n     * @var array\n     */\n    protected $config = [];\n\n    /**\n     * The reconnector instance for the connection.\n     *\n     * @var callable\n     */\n    protected $reconnector;\n\n    /**\n     * The query grammar implementation.\n     *\n     * @var \\Illuminate\\Database\\Query\\Grammars\\Grammar\n     */\n    protected $queryGrammar;\n\n    /**\n     * The schema grammar implementation.\n     *\n     * @var \\Illuminate\\Database\\Schema\\Grammars\\Grammar\n     */\n    protected $schemaGrammar;\n\n    /**\n     * The query post processor implementation.\n     *\n     * @var \\Illuminate\\Database\\Query\\Processors\\Processor\n     */\n    protected $postProcessor;\n\n    /**\n     * The event dispatcher instance.\n     *\n     * @var \\Illuminate\\Contracts\\Events\\Dispatcher\n     */\n    protected $events;\n\n    /**\n     * The default fetch mode of the connection.\n     *\n     * @var int\n     */\n    protected $fetchMode = PDO::FETCH_OBJ;\n\n    /**\n     * The number of active transactions.\n     *\n     * @var int\n     */\n    protected $transactions = 0;\n\n    /**\n     * The transaction manager instance.\n     *\n     * @var \\Illuminate\\Database\\DatabaseTransactionsManager\n     */\n    protected $transactionsManager;\n\n    /**\n     * Indicates if changes have been made to the database.\n     *\n     * @var bool\n     */\n    protected $recordsModified = false;\n\n    /**\n     * Indicates if the connection should use the \"write\" PDO connection.\n     *\n     * @var bool\n     */\n    protected $readOnWriteConnection = false;\n\n    /**\n     * All of the queries run against the connection.\n     *\n     * @var array\n     */\n    protected $queryLog = [];\n\n    /**\n     * Indicates whether queries are being logged.\n     *\n     * @var bool\n     */\n    protected $loggingQueries = false;\n\n    /**\n     * Indicates if the connection is in a \"dry run\".\n     *\n     * @var bool\n     */\n    protected $pretending = false;\n\n    /**\n     * All of the callbacks that should be invoked before a query is executed.\n     *\n     * @var array\n     */\n    protected $beforeExecutingCallbacks = [];\n\n    /**\n     * The instance of Doctrine connection.\n     *\n     * @var \\Doctrine\\DBAL\\Connection\n     */\n    protected $doctrineConnection;\n\n    /**\n     * Type mappings that should be registered with new Doctrine connections.\n     *\n     * @var array\n     */\n    protected $doctrineTypeMappings = [];\n\n    /**\n     * The connection resolvers.\n     *\n     * @var array\n     */\n    protected static $resolvers = [];\n\n    /**\n     * Create a new database connection instance.\n     *\n     * @param  \\PDO|\\Closure  $pdo\n     * @param  string  $database\n     * @param  string  $tablePrefix\n     * @param  array  $config\n     * @return void\n     */\n    public function __construct($pdo, $database = '', $tablePrefix = '', array $config = [])\n    {\n        $this->pdo = $pdo;\n\n        // First we will setup the default properties. We keep track of the DB\n        // name we are connected to since it is needed when some reflective\n        // type commands are run such as checking whether a table exists.\n        $this->database = $database;\n\n        $this->tablePrefix = $tablePrefix;\n\n        $this->config = $config;\n\n        // We need to initialize a query grammar and the query post processors\n        // which are both very important parts of the database abstractions\n        // so we initialize these to their default values while starting.\n        $this->useDefaultQueryGrammar();\n\n        $this->useDefaultPostProcessor();\n    }\n\n    /**\n     * Set the query grammar to the default implementation.\n     *\n     * @return void\n     */\n    public function useDefaultQueryGrammar()\n    {\n        $this->queryGrammar = $this->getDefaultQueryGrammar();\n    }\n\n    /**\n     * Get the default query grammar instance.\n     *\n     * @return \\Illuminate\\Database\\Query\\Grammars\\Grammar\n     */\n    protected function getDefaultQueryGrammar()\n    {\n        return new QueryGrammar;\n    }\n\n    /**\n     * Set the schema grammar to the default implementation.\n     *\n     * @return void\n     */\n    public function useDefaultSchemaGrammar()\n    {\n        $this->schemaGrammar = $this->getDefaultSchemaGrammar();\n    }\n\n    /**\n     * Get the default schema grammar instance.\n     *\n     * @return \\Illuminate\\Database\\Schema\\Grammars\\Grammar\n     */\n    protected function getDefaultSchemaGrammar()\n    {\n        //\n    }\n\n    /**\n     * Set the query post processor to the default implementation.\n     *\n     * @return void\n     */\n    public function useDefaultPostProcessor()\n    {\n        $this->postProcessor = $this->getDefaultPostProcessor();\n    }\n\n    /**\n     * Get the default post processor instance.\n     *\n     * @return \\Illuminate\\Database\\Query\\Processors\\Processor\n     */\n    protected function getDefaultPostProcessor()\n    {\n        return new Processor;\n    }\n\n    /**\n     * Get a schema builder instance for the connection.\n     *\n     * @return \\Illuminate\\Database\\Schema\\Builder\n     */\n    public function getSchemaBuilder()\n    {\n        if (is_null($this->schemaGrammar)) {\n            $this->useDefaultSchemaGrammar();\n        }\n\n        return new SchemaBuilder($this);\n    }\n\n    /**\n     * Begin a fluent query against a database table.\n     *\n     * @param  \\Closure|\\Illuminate\\Database\\Query\\Builder|string  $table\n     * @param  string|null  $as\n     * @return \\Illuminate\\Database\\Query\\Builder\n     */\n    public function table($table, $as = null)\n    {\n        return $this->query()->from($table, $as);\n    }\n\n    /**\n     * Get a new query builder instance.\n     *\n     * @return \\Illuminate\\Database\\Query\\Builder\n     */\n    public function query()\n    {\n        return new QueryBuilder(\n            $this, $this->getQueryGrammar(), $this->getPostProcessor()\n        );\n    }\n\n    /**\n     * Run a select statement and return a single result.\n     *\n     * @param  string  $query\n     * @param  array  $bindings\n     * @param  bool  $useReadPdo\n     * @return mixed\n     */\n    public function selectOne($query, $bindings = [], $useReadPdo = true)\n    {\n        $records = $this->select($query, $bindings, $useReadPdo);\n\n        return array_shift($records);\n    }\n\n    /**\n     * Run a select statement against the database.\n     *\n     * @param  string  $query\n     * @param  array  $bindings\n     * @return array\n     */\n    public function selectFromWriteConnection($query, $bindings = [])\n    {\n        return $this->select($query, $bindings, false);\n    }\n\n    /**\n     * Run a select statement against the database.\n     *\n     * @param  string  $query\n     * @param  array  $bindings\n     * @param  bool  $useReadPdo\n     * @return array\n     */\n    public function select($query, $bindings = [], $useReadPdo = true)\n    {\n        return $this->run($query, $bindings, function ($query, $bindings) use ($useReadPdo) {\n            if ($this->pretending()) {\n                return [];\n            }\n\n            // For select statements, we'll simply execute the query and return an array\n            // of the database result set. Each element in the array will be a single\n            // row from the database table, and will either be an array or objects.\n            $statement = $this->prepared(\n                $this->getPdoForSelect($useReadPdo)->prepare($query)\n            );\n\n            $this->bindValues($statement, $this->prepareBindings($bindings));\n\n            $statement->execute();\n\n            return $statement->fetchAll();\n        });\n    }\n\n    /**\n     * Run a select statement against the database and returns a generator.\n     *\n     * @param  string  $query\n     * @param  array  $bindings\n     * @param  bool  $useReadPdo\n     * @return \\Generator\n     */\n    public function cursor($query, $bindings = [], $useReadPdo = true)\n    {\n        $statement = $this->run($query, $bindings, function ($query, $bindings) use ($useReadPdo) {\n            if ($this->pretending()) {\n                return [];\n            }\n\n            // First we will create a statement for the query. Then, we will set the fetch\n            // mode and prepare the bindings for the query. Once that's done we will be\n            // ready to execute the query against the database and return the cursor.\n            $statement = $this->prepared($this->getPdoForSelect($useReadPdo)\n                              ->prepare($query));\n\n            $this->bindValues(\n                $statement, $this->prepareBindings($bindings)\n            );\n\n            // Next, we'll execute the query against the database and return the statement\n            // so we can return the cursor. The cursor will use a PHP generator to give\n            // back one row at a time without using a bunch of memory to render them.\n            $statement->execute();\n\n            return $statement;\n        });\n\n        while ($record = $statement->fetch()) {\n            yield $record;\n        }\n    }\n\n    /**\n     * Configure the PDO prepared statement.\n     *\n     * @param  \\PDOStatement  $statement\n     * @return \\PDOStatement\n     */\n    protected function prepared(PDOStatement $statement)\n    {\n        $statement->setFetchMode($this->fetchMode);\n\n        $this->event(new StatementPrepared(\n            $this, $statement\n        ));\n\n        return $statement;\n    }\n\n    /**\n     * Get the PDO connection to use for a select query.\n     *\n     * @param  bool  $useReadPdo\n     * @return \\PDO\n     */\n    protected function getPdoForSelect($useReadPdo = true)\n    {\n        return $useReadPdo ? $this->getReadPdo() : $this->getPdo();\n    }\n\n    /**\n     * Run an insert statement against the database.\n     *\n     * @param  string  $query\n     * @param  array  $bindings\n     * @return bool\n     */\n    public function insert($query, $bindings = [])\n    {\n        return $this->statement($query, $bindings);\n    }\n\n    /**\n     * Run an update statement against the database.\n     *\n     * @param  string  $query\n     * @param  array  $bindings\n     * @return int\n     */\n    public function update($query, $bindings = [])\n    {\n        return $this->affectingStatement($query, $bindings);\n    }\n\n    /**\n     * Run a delete statement against the database.\n     *\n     * @param  string  $query\n     * @param  array  $bindings\n     * @return int\n     */\n    public function delete($query, $bindings = [])\n    {\n        return $this->affectingStatement($query, $bindings);\n    }\n\n    /**\n     * Execute an SQL statement and return the boolean result.\n     *\n     * @param  string  $query\n     * @param  array  $bindings\n     * @return bool\n     */\n    public function statement($query, $bindings = [])\n    {\n        return $this->run($query, $bindings, function ($query, $bindings) {\n            if ($this->pretending()) {\n                return true;\n            }\n\n            $statement = $this->getPdo()->prepare($query);\n\n            $this->bindValues($statement, $this->prepareBindings($bindings));\n\n            $this->recordsHaveBeenModified();\n\n            return $statement->execute();\n        });\n    }\n\n    /**\n     * Run an SQL statement and get the number of rows affected.\n     *\n     * @param  string  $query\n     * @param  array  $bindings\n     * @return int\n     */\n    public function affectingStatement($query, $bindings = [])\n    {\n        return $this->run($query, $bindings, function ($query, $bindings) {\n            if ($this->pretending()) {\n                return 0;\n            }\n\n            // For update or delete statements, we want to get the number of rows affected\n            // by the statement and return that back to the developer. We'll first need\n            // to execute the statement and then we'll use PDO to fetch the affected.\n            $statement = $this->getPdo()->prepare($query);\n\n            $this->bindValues($statement, $this->prepareBindings($bindings));\n\n            $statement->execute();\n\n            $this->recordsHaveBeenModified(\n                ($count = $statement->rowCount()) > 0\n            );\n\n            return $count;\n        });\n    }\n\n    /**\n     * Run a raw, unprepared query against the PDO connection.\n     *\n     * @param  string  $query\n     * @return bool\n     */\n    public function unprepared($query)\n    {\n        return $this->run($query, [], function ($query) {\n            if ($this->pretending()) {\n                return true;\n            }\n\n            $this->recordsHaveBeenModified(\n                $change = $this->getPdo()->exec($query) !== false\n            );\n\n            return $change;\n        });\n    }\n\n    /**\n     * Execute the given callback in \"dry run\" mode.\n     *\n     * @param  \\Closure  $callback\n     * @return array\n     */\n    public function pretend(Closure $callback)\n    {\n        return $this->withFreshQueryLog(function () use ($callback) {\n            $this->pretending = true;\n\n            // Basically to make the database connection \"pretend\", we will just return\n            // the default values for all the query methods, then we will return an\n            // array of queries that were \"executed\" within the Closure callback.\n            $callback($this);\n\n            $this->pretending = false;\n\n            return $this->queryLog;\n        });\n    }\n\n    /**\n     * Execute the given callback in \"dry run\" mode.\n     *\n     * @param  \\Closure  $callback\n     * @return array\n     */\n    protected function withFreshQueryLog($callback)\n    {\n        $loggingQueries = $this->loggingQueries;\n\n        // First we will back up the value of the logging queries property and then\n        // we'll be ready to run callbacks. This query log will also get cleared\n        // so we will have a new log of all the queries that are executed now.\n        $this->enableQueryLog();\n\n        $this->queryLog = [];\n\n        // Now we'll execute this callback and capture the result. Once it has been\n        // executed we will restore the value of query logging and give back the\n        // value of the callback so the original callers can have the results.\n        $result = $callback();\n\n        $this->loggingQueries = $loggingQueries;\n\n        return $result;\n    }\n\n    /**\n     * Bind values to their parameters in the given statement.\n     *\n     * @param  \\PDOStatement  $statement\n     * @param  array  $bindings\n     * @return void\n     */\n    public function bindValues($statement, $bindings)\n    {\n        foreach ($bindings as $key => $value) {\n            $statement->bindValue(\n                is_string($key) ? $key : $key + 1,\n                $value,\n                is_int($value) ? PDO::PARAM_INT : PDO::PARAM_STR\n            );\n        }\n    }\n\n    /**\n     * Prepare the query bindings for execution.\n     *\n     * @param  array  $bindings\n     * @return array\n     */\n    public function prepareBindings(array $bindings)\n    {\n        $grammar = $this->getQueryGrammar();\n\n        foreach ($bindings as $key => $value) {\n            // We need to transform all instances of DateTimeInterface into the actual\n            // date string. Each query grammar maintains its own date string format\n            // so we'll just ask the grammar for the format to get from the date.\n            if ($value instanceof DateTimeInterface) {\n                $bindings[$key] = $value->format($grammar->getDateFormat());\n            } elseif (is_bool($value)) {\n                $bindings[$key] = (int) $value;\n            }\n        }\n\n        return $bindings;\n    }\n\n    /**\n     * Run a SQL statement and log its execution context.\n     *\n     * @param  string  $query\n     * @param  array  $bindings\n     * @param  \\Closure  $callback\n     * @return mixed\n     *\n     * @throws \\Illuminate\\Database\\QueryException\n     */\n    protected function run($query, $bindings, Closure $callback)\n    {\n        foreach ($this->beforeExecutingCallbacks as $beforeExecutingCallback) {\n            $beforeExecutingCallback($query, $bindings, $this);\n        }\n\n        $this->reconnectIfMissingConnection();\n\n        $start = microtime(true);\n\n        // Here we will run this query. If an exception occurs we'll determine if it was\n        // caused by a connection that has been lost. If that is the cause, we'll try\n        // to re-establish connection and re-run the query with a fresh connection.\n        try {\n            $result = $this->runQueryCallback($query, $bindings, $callback);\n        } catch (QueryException $e) {\n            $result = $this->handleQueryException(\n                $e, $query, $bindings, $callback\n            );\n        }\n\n        // Once we have run the query we will calculate the time that it took to run and\n        // then log the query, bindings, and execution time so we will report them on\n        // the event that the developer needs them. We'll log time in milliseconds.\n        $this->logQuery(\n            $query, $bindings, $this->getElapsedTime($start)\n        );\n\n        return $result;\n    }\n\n    /**\n     * Run a SQL statement.\n     *\n     * @param  string  $query\n     * @param  array  $bindings\n     * @param  \\Closure  $callback\n     * @return mixed\n     *\n     * @throws \\Illuminate\\Database\\QueryException\n     */\n    protected function runQueryCallback($query, $bindings, Closure $callback)\n    {\n        // To execute the statement, we'll simply call the callback, which will actually\n        // run the SQL against the PDO connection. Then we can calculate the time it\n        // took to execute and log the query SQL, bindings and time in our memory.\n        try {\n            return $callback($query, $bindings);\n        }\n\n        // If an exception occurs when attempting to run a query, we'll format the error\n        // message to include the bindings with SQL, which will make this exception a\n        // lot more helpful to the developer instead of just the database's errors.\n        catch (Exception $e) {\n            throw new QueryException(\n                $query, $this->prepareBindings($bindings), $e\n            );\n        }\n    }\n\n    /**\n     * Log a query in the connection's query log.\n     *\n     * @param  string  $query\n     * @param  array  $bindings\n     * @param  float|null  $time\n     * @return void\n     */\n    public function logQuery($query, $bindings, $time = null)\n    {\n        $this->event(new QueryExecuted($query, $bindings, $time, $this));\n\n        if ($this->loggingQueries) {\n            $this->queryLog[] = compact('query', 'bindings', 'time');\n        }\n    }\n\n    /**\n     * Get the elapsed time since a given starting point.\n     *\n     * @param  int  $start\n     * @return float\n     */\n    protected function getElapsedTime($start)\n    {\n        return round((microtime(true) - $start) * 1000, 2);\n    }\n\n    /**\n     * Handle a query exception.\n     *\n     * @param  \\Illuminate\\Database\\QueryException  $e\n     * @param  string  $query\n     * @param  array  $bindings\n     * @param  \\Closure  $callback\n     * @return mixed\n     *\n     * @throws \\Illuminate\\Database\\QueryException\n     */\n    protected function handleQueryException(QueryException $e, $query, $bindings, Closure $callback)\n    {\n        if ($this->transactions >= 1) {\n            throw $e;\n        }\n\n        return $this->tryAgainIfCausedByLostConnection(\n            $e, $query, $bindings, $callback\n        );\n    }\n\n    /**\n     * Handle a query exception that occurred during query execution.\n     *\n     * @param  \\Illuminate\\Database\\QueryException  $e\n     * @param  string  $query\n     * @param  array  $bindings\n     * @param  \\Closure  $callback\n     * @return mixed\n     *\n     * @throws \\Illuminate\\Database\\QueryException\n     */\n    protected function tryAgainIfCausedByLostConnection(QueryException $e, $query, $bindings, Closure $callback)\n    {\n        if ($this->causedByLostConnection($e->getPrevious())) {\n            $this->reconnect();\n\n            return $this->runQueryCallback($query, $bindings, $callback);\n        }\n\n        throw $e;\n    }\n\n    /**\n     * Reconnect to the database.\n     *\n     * @return void\n     *\n     * @throws \\LogicException\n     */\n    public function reconnect()\n    {\n        if (is_callable($this->reconnector)) {\n            $this->doctrineConnection = null;\n\n            return call_user_func($this->reconnector, $this);\n        }\n\n        throw new LogicException('Lost connection and no reconnector available.');\n    }\n\n    /**\n     * Reconnect to the database if a PDO connection is missing.\n     *\n     * @return void\n     */\n    protected function reconnectIfMissingConnection()\n    {\n        if (is_null($this->pdo)) {\n            $this->reconnect();\n        }\n    }\n\n    /**\n     * Disconnect from the underlying PDO connection.\n     *\n     * @return void\n     */\n    public function disconnect()\n    {\n        $this->setPdo(null)->setReadPdo(null);\n\n        $this->doctrineConnection = null;\n    }\n\n    /**\n     * Register a hook to be run just before a database query is executed.\n     *\n     * @param  \\Closure  $callback\n     * @return $this\n     */\n    public function beforeExecuting(Closure $callback)\n    {\n        $this->beforeExecutingCallbacks[] = $callback;\n\n        return $this;\n    }\n\n    /**\n     * Register a database query listener with the connection.\n     *\n     * @param  \\Closure  $callback\n     * @return void\n     */\n    public function listen(Closure $callback)\n    {\n        if (isset($this->events)) {\n            $this->events->listen(Events\\QueryExecuted::class, $callback);\n        }\n    }\n\n    /**\n     * Fire an event for this connection.\n     *\n     * @param  string  $event\n     * @return array|null\n     */\n    protected function fireConnectionEvent($event)\n    {\n        if (! isset($this->events)) {\n            return;\n        }\n\n        switch ($event) {\n            case 'beganTransaction':\n                return $this->events->dispatch(new TransactionBeginning($this));\n            case 'committed':\n                return $this->events->dispatch(new TransactionCommitted($this));\n            case 'rollingBack':\n                return $this->events->dispatch(new TransactionRolledBack($this));\n        }\n    }\n\n    /**\n     * Fire the given event if possible.\n     *\n     * @param  mixed  $event\n     * @return void\n     */\n    protected function event($event)\n    {\n        if (isset($this->events)) {\n            $this->events->dispatch($event);\n        }\n    }\n\n    /**\n     * Get a new raw query expression.\n     *\n     * @param  mixed  $value\n     * @return \\Illuminate\\Database\\Query\\Expression\n     */\n    public function raw($value)\n    {\n        return new Expression($value);\n    }\n\n    /**\n     * Determine if the database connection has modified any database records.\n     *\n     * @return bool\n     */\n    public function hasModifiedRecords()\n    {\n        return $this->recordsModified;\n    }\n\n    /**\n     * Indicate if any records have been modified.\n     *\n     * @param  bool  $value\n     * @return void\n     */\n    public function recordsHaveBeenModified($value = true)\n    {\n        if (! $this->recordsModified) {\n            $this->recordsModified = $value;\n        }\n    }\n\n    /**\n     * Set the record modification state.\n     *\n     * @param  bool  $value\n     * @return $this\n     */\n    public function setRecordModificationState(bool $value)\n    {\n        $this->recordsModified = $value;\n\n        return $this;\n    }\n\n    /**\n     * Reset the record modification state.\n     *\n     * @return void\n     */\n    public function forgetRecordModificationState()\n    {\n        $this->recordsModified = false;\n    }\n\n    /**\n     * Indicate that the connection should use the write PDO connection for reads.\n     *\n     * @param  bool  $value\n     * @return $this\n     */\n    public function useWriteConnectionWhenReading($value = true)\n    {\n        $this->readOnWriteConnection = $value;\n\n        return $this;\n    }\n\n    /**\n     * Is Doctrine available?\n     *\n     * @return bool\n     */\n    public function isDoctrineAvailable()\n    {\n        return class_exists('Doctrine\\DBAL\\Connection');\n    }\n\n    /**\n     * Get a Doctrine Schema Column instance.\n     *\n     * @param  string  $table\n     * @param  string  $column\n     * @return \\Doctrine\\DBAL\\Schema\\Column\n     */\n    public function getDoctrineColumn($table, $column)\n    {\n        $schema = $this->getDoctrineSchemaManager();\n\n        return $schema->listTableDetails($table)->getColumn($column);\n    }\n\n    /**\n     * Get the Doctrine DBAL schema manager for the connection.\n     *\n     * @return \\Doctrine\\DBAL\\Schema\\AbstractSchemaManager\n     */\n    public function getDoctrineSchemaManager()\n    {\n        $connection = $this->getDoctrineConnection();\n\n        // Doctrine v2 expects one parameter while v3 expects two. 2nd will be ignored on v2...\n        return $this->getDoctrineDriver()->getSchemaManager(\n            $connection,\n            $connection->getDatabasePlatform()\n        );\n    }\n\n    /**\n     * Get the Doctrine DBAL database connection instance.\n     *\n     * @return \\Doctrine\\DBAL\\Connection\n     */\n    public function getDoctrineConnection()\n    {\n        if (is_null($this->doctrineConnection)) {\n            $driver = $this->getDoctrineDriver();\n\n            $this->doctrineConnection = new DoctrineConnection(array_filter([\n                'pdo' => $this->getPdo(),\n                'dbname' => $this->getDatabaseName(),\n                'driver' => method_exists($driver, 'getName') ? $driver->getName() : null,\n                'serverVersion' => $this->getConfig('server_version'),\n            ]), $driver);\n\n            foreach ($this->doctrineTypeMappings as $name => $type) {\n                $this->doctrineConnection\n                    ->getDatabasePlatform()\n                    ->registerDoctrineTypeMapping($type, $name);\n            }\n        }\n\n        return $this->doctrineConnection;\n    }\n\n    /**\n     * Register a custom Doctrine mapping type.\n     *\n     * @param  string  $class\n     * @param  string  $name\n     * @param  string  $type\n     * @return void\n     *\n     * @throws \\Doctrine\\DBAL\\DBALException\n     * @throws \\RuntimeException\n     */\n    public function registerDoctrineType(string $class, string $name, string $type): void\n    {\n        if (! $this->isDoctrineAvailable()) {\n            throw new RuntimeException(\n                'Registering a custom Doctrine type requires Doctrine DBAL (doctrine/dbal).'\n            );\n        }\n\n        if (! Type::hasType($name)) {\n            Type::addType($name, $class);\n        }\n\n        $this->doctrineTypeMappings[$name] = $type;\n    }\n\n    /**\n     * Get the current PDO connection.\n     *\n     * @return \\PDO\n     */\n    public function getPdo()\n    {\n        if ($this->pdo instanceof Closure) {\n            return $this->pdo = call_user_func($this->pdo);\n        }\n\n        return $this->pdo;\n    }\n\n    /**\n     * Get the current PDO connection parameter without executing any reconnect logic.\n     *\n     * @return \\PDO|\\Closure|null\n     */\n    public function getRawPdo()\n    {\n        return $this->pdo;\n    }\n\n    /**\n     * Get the current PDO connection used for reading.\n     *\n     * @return \\PDO\n     */\n    public function getReadPdo()\n    {\n        if ($this->transactions > 0) {\n            return $this->getPdo();\n        }\n\n        if ($this->readOnWriteConnection ||\n            ($this->recordsModified && $this->getConfig('sticky'))) {\n            return $this->getPdo();\n        }\n\n        if ($this->readPdo instanceof Closure) {\n            return $this->readPdo = call_user_func($this->readPdo);\n        }\n\n        return $this->readPdo ?: $this->getPdo();\n    }\n\n    /**\n     * Get the current read PDO connection parameter without executing any reconnect logic.\n     *\n     * @return \\PDO|\\Closure|null\n     */\n    public function getRawReadPdo()\n    {\n        return $this->readPdo;\n    }\n\n    /**\n     * Set the PDO connection.\n     *\n     * @param  \\PDO|\\Closure|null  $pdo\n     * @return $this\n     */\n    public function setPdo($pdo)\n    {\n        $this->transactions = 0;\n\n        $this->pdo = $pdo;\n\n        return $this;\n    }\n\n    /**\n     * Set the PDO connection used for reading.\n     *\n     * @param  \\PDO|\\Closure|null  $pdo\n     * @return $this\n     */\n    public function setReadPdo($pdo)\n    {\n        $this->readPdo = $pdo;\n\n        return $this;\n    }\n\n    /**\n     * Set the reconnect instance on the connection.\n     *\n     * @param  callable  $reconnector\n     * @return $this\n     */\n    public function setReconnector(callable $reconnector)\n    {\n        $this->reconnector = $reconnector;\n\n        return $this;\n    }\n\n    /**\n     * Get the database connection name.\n     *\n     * @return string|null\n     */\n    public function getName()\n    {\n        return $this->getConfig('name');\n    }\n\n    /**\n     * Get the database connection full name.\n     *\n     * @return string|null\n     */\n    public function getNameWithReadWriteType()\n    {\n        return $this->getName().($this->readWriteType ? '::'.$this->readWriteType : '');\n    }\n\n    /**\n     * Get an option from the configuration options.\n     *\n     * @param  string|null  $option\n     * @return mixed\n     */\n    public function getConfig($option = null)\n    {\n        return Arr::get($this->config, $option);\n    }\n\n    /**\n     * Get the PDO driver name.\n     *\n     * @return string\n     */\n    public function getDriverName()\n    {\n        return $this->getConfig('driver');\n    }\n\n    /**\n     * Get the query grammar used by the connection.\n     *\n     * @return \\Illuminate\\Database\\Query\\Grammars\\Grammar\n     */\n    public function getQueryGrammar()\n    {\n        return $this->queryGrammar;\n    }\n\n    /**\n     * Set the query grammar used by the connection.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Grammars\\Grammar  $grammar\n     * @return $this\n     */\n    public function setQueryGrammar(Query\\Grammars\\Grammar $grammar)\n    {\n        $this->queryGrammar = $grammar;\n\n        return $this;\n    }\n\n    /**\n     * Get the schema grammar used by the connection.\n     *\n     * @return \\Illuminate\\Database\\Schema\\Grammars\\Grammar\n     */\n    public function getSchemaGrammar()\n    {\n        return $this->schemaGrammar;\n    }\n\n    /**\n     * Set the schema grammar used by the connection.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Grammars\\Grammar  $grammar\n     * @return $this\n     */\n    public function setSchemaGrammar(Schema\\Grammars\\Grammar $grammar)\n    {\n        $this->schemaGrammar = $grammar;\n\n        return $this;\n    }\n\n    /**\n     * Get the query post processor used by the connection.\n     *\n     * @return \\Illuminate\\Database\\Query\\Processors\\Processor\n     */\n    public function getPostProcessor()\n    {\n        return $this->postProcessor;\n    }\n\n    /**\n     * Set the query post processor used by the connection.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Processors\\Processor  $processor\n     * @return $this\n     */\n    public function setPostProcessor(Processor $processor)\n    {\n        $this->postProcessor = $processor;\n\n        return $this;\n    }\n\n    /**\n     * Get the event dispatcher used by the connection.\n     *\n     * @return \\Illuminate\\Contracts\\Events\\Dispatcher\n     */\n    public function getEventDispatcher()\n    {\n        return $this->events;\n    }\n\n    /**\n     * Set the event dispatcher instance on the connection.\n     *\n     * @param  \\Illuminate\\Contracts\\Events\\Dispatcher  $events\n     * @return $this\n     */\n    public function setEventDispatcher(Dispatcher $events)\n    {\n        $this->events = $events;\n\n        return $this;\n    }\n\n    /**\n     * Unset the event dispatcher for this connection.\n     *\n     * @return void\n     */\n    public function unsetEventDispatcher()\n    {\n        $this->events = null;\n    }\n\n    /**\n     * Set the transaction manager instance on the connection.\n     *\n     * @param  \\Illuminate\\Database\\DatabaseTransactionsManager  $manager\n     * @return $this\n     */\n    public function setTransactionManager($manager)\n    {\n        $this->transactionsManager = $manager;\n\n        return $this;\n    }\n\n    /**\n     * Unset the transaction manager for this connection.\n     *\n     * @return void\n     */\n    public function unsetTransactionManager()\n    {\n        $this->transactionsManager = null;\n    }\n\n    /**\n     * Determine if the connection is in a \"dry run\".\n     *\n     * @return bool\n     */\n    public function pretending()\n    {\n        return $this->pretending === true;\n    }\n\n    /**\n     * Get the connection query log.\n     *\n     * @return array\n     */\n    public function getQueryLog()\n    {\n        return $this->queryLog;\n    }\n\n    /**\n     * Clear the query log.\n     *\n     * @return void\n     */\n    public function flushQueryLog()\n    {\n        $this->queryLog = [];\n    }\n\n    /**\n     * Enable the query log on the connection.\n     *\n     * @return void\n     */\n    public function enableQueryLog()\n    {\n        $this->loggingQueries = true;\n    }\n\n    /**\n     * Disable the query log on the connection.\n     *\n     * @return void\n     */\n    public function disableQueryLog()\n    {\n        $this->loggingQueries = false;\n    }\n\n    /**\n     * Determine whether we're logging queries.\n     *\n     * @return bool\n     */\n    public function logging()\n    {\n        return $this->loggingQueries;\n    }\n\n    /**\n     * Get the name of the connected database.\n     *\n     * @return string\n     */\n    public function getDatabaseName()\n    {\n        return $this->database;\n    }\n\n    /**\n     * Set the name of the connected database.\n     *\n     * @param  string  $database\n     * @return $this\n     */\n    public function setDatabaseName($database)\n    {\n        $this->database = $database;\n\n        return $this;\n    }\n\n    /**\n     * Set the read / write type of the connection.\n     *\n     * @param  string|null  $readWriteType\n     * @return $this\n     */\n    public function setReadWriteType($readWriteType)\n    {\n        $this->readWriteType = $readWriteType;\n\n        return $this;\n    }\n\n    /**\n     * Get the table prefix for the connection.\n     *\n     * @return string\n     */\n    public function getTablePrefix()\n    {\n        return $this->tablePrefix;\n    }\n\n    /**\n     * Set the table prefix in use by the connection.\n     *\n     * @param  string  $prefix\n     * @return $this\n     */\n    public function setTablePrefix($prefix)\n    {\n        $this->tablePrefix = $prefix;\n\n        $this->getQueryGrammar()->setTablePrefix($prefix);\n\n        return $this;\n    }\n\n    /**\n     * Set the table prefix and return the grammar.\n     *\n     * @param  \\Illuminate\\Database\\Grammar  $grammar\n     * @return \\Illuminate\\Database\\Grammar\n     */\n    public function withTablePrefix(Grammar $grammar)\n    {\n        $grammar->setTablePrefix($this->tablePrefix);\n\n        return $grammar;\n    }\n\n    /**\n     * Register a connection resolver.\n     *\n     * @param  string  $driver\n     * @param  \\Closure  $callback\n     * @return void\n     */\n    public static function resolverFor($driver, Closure $callback)\n    {\n        static::$resolvers[$driver] = $callback;\n    }\n\n    /**\n     * Get the connection resolver for the given driver.\n     *\n     * @param  string  $driver\n     * @return mixed\n     */\n    public static function getResolver($driver)\n    {\n        return static::$resolvers[$driver] ?? null;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/ConnectionInterface.php",
    "content": "<?php\n\nnamespace Illuminate\\Database;\n\nuse Closure;\n\ninterface ConnectionInterface\n{\n    /**\n     * Begin a fluent query against a database table.\n     *\n     * @param  \\Closure|\\Illuminate\\Database\\Query\\Builder|string  $table\n     * @param  string|null  $as\n     * @return \\Illuminate\\Database\\Query\\Builder\n     */\n    public function table($table, $as = null);\n\n    /**\n     * Get a new raw query expression.\n     *\n     * @param  mixed  $value\n     * @return \\Illuminate\\Database\\Query\\Expression\n     */\n    public function raw($value);\n\n    /**\n     * Run a select statement and return a single result.\n     *\n     * @param  string  $query\n     * @param  array  $bindings\n     * @param  bool  $useReadPdo\n     * @return mixed\n     */\n    public function selectOne($query, $bindings = [], $useReadPdo = true);\n\n    /**\n     * Run a select statement against the database.\n     *\n     * @param  string  $query\n     * @param  array  $bindings\n     * @param  bool  $useReadPdo\n     * @return array\n     */\n    public function select($query, $bindings = [], $useReadPdo = true);\n\n    /**\n     * Run a select statement against the database and returns a generator.\n     *\n     * @param  string  $query\n     * @param  array  $bindings\n     * @param  bool  $useReadPdo\n     * @return \\Generator\n     */\n    public function cursor($query, $bindings = [], $useReadPdo = true);\n\n    /**\n     * Run an insert statement against the database.\n     *\n     * @param  string  $query\n     * @param  array  $bindings\n     * @return bool\n     */\n    public function insert($query, $bindings = []);\n\n    /**\n     * Run an update statement against the database.\n     *\n     * @param  string  $query\n     * @param  array  $bindings\n     * @return int\n     */\n    public function update($query, $bindings = []);\n\n    /**\n     * Run a delete statement against the database.\n     *\n     * @param  string  $query\n     * @param  array  $bindings\n     * @return int\n     */\n    public function delete($query, $bindings = []);\n\n    /**\n     * Execute an SQL statement and return the boolean result.\n     *\n     * @param  string  $query\n     * @param  array  $bindings\n     * @return bool\n     */\n    public function statement($query, $bindings = []);\n\n    /**\n     * Run an SQL statement and get the number of rows affected.\n     *\n     * @param  string  $query\n     * @param  array  $bindings\n     * @return int\n     */\n    public function affectingStatement($query, $bindings = []);\n\n    /**\n     * Run a raw, unprepared query against the PDO connection.\n     *\n     * @param  string  $query\n     * @return bool\n     */\n    public function unprepared($query);\n\n    /**\n     * Prepare the query bindings for execution.\n     *\n     * @param  array  $bindings\n     * @return array\n     */\n    public function prepareBindings(array $bindings);\n\n    /**\n     * Execute a Closure within a transaction.\n     *\n     * @param  \\Closure  $callback\n     * @param  int  $attempts\n     * @return mixed\n     *\n     * @throws \\Throwable\n     */\n    public function transaction(Closure $callback, $attempts = 1);\n\n    /**\n     * Start a new database transaction.\n     *\n     * @return void\n     */\n    public function beginTransaction();\n\n    /**\n     * Commit the active database transaction.\n     *\n     * @return void\n     */\n    public function commit();\n\n    /**\n     * Rollback the active database transaction.\n     *\n     * @return void\n     */\n    public function rollBack();\n\n    /**\n     * Get the number of active transactions.\n     *\n     * @return int\n     */\n    public function transactionLevel();\n\n    /**\n     * Execute the given callback in \"dry run\" mode.\n     *\n     * @param  \\Closure  $callback\n     * @return array\n     */\n    public function pretend(Closure $callback);\n\n    /**\n     * Get the name of the connected database.\n     *\n     * @return string\n     */\n    public function getDatabaseName();\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/ConnectionResolver.php",
    "content": "<?php\n\nnamespace Illuminate\\Database;\n\nclass ConnectionResolver implements ConnectionResolverInterface\n{\n    /**\n     * All of the registered connections.\n     *\n     * @var array\n     */\n    protected $connections = [];\n\n    /**\n     * The default connection name.\n     *\n     * @var string\n     */\n    protected $default;\n\n    /**\n     * Create a new connection resolver instance.\n     *\n     * @param  array  $connections\n     * @return void\n     */\n    public function __construct(array $connections = [])\n    {\n        foreach ($connections as $name => $connection) {\n            $this->addConnection($name, $connection);\n        }\n    }\n\n    /**\n     * Get a database connection instance.\n     *\n     * @param  string|null  $name\n     * @return \\Illuminate\\Database\\ConnectionInterface\n     */\n    public function connection($name = null)\n    {\n        if (is_null($name)) {\n            $name = $this->getDefaultConnection();\n        }\n\n        return $this->connections[$name];\n    }\n\n    /**\n     * Add a connection to the resolver.\n     *\n     * @param  string  $name\n     * @param  \\Illuminate\\Database\\ConnectionInterface  $connection\n     * @return void\n     */\n    public function addConnection($name, ConnectionInterface $connection)\n    {\n        $this->connections[$name] = $connection;\n    }\n\n    /**\n     * Check if a connection has been registered.\n     *\n     * @param  string  $name\n     * @return bool\n     */\n    public function hasConnection($name)\n    {\n        return isset($this->connections[$name]);\n    }\n\n    /**\n     * Get the default connection name.\n     *\n     * @return string\n     */\n    public function getDefaultConnection()\n    {\n        return $this->default;\n    }\n\n    /**\n     * Set the default connection name.\n     *\n     * @param  string  $name\n     * @return void\n     */\n    public function setDefaultConnection($name)\n    {\n        $this->default = $name;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/ConnectionResolverInterface.php",
    "content": "<?php\n\nnamespace Illuminate\\Database;\n\ninterface ConnectionResolverInterface\n{\n    /**\n     * Get a database connection instance.\n     *\n     * @param  string|null  $name\n     * @return \\Illuminate\\Database\\ConnectionInterface\n     */\n    public function connection($name = null);\n\n    /**\n     * Get the default connection name.\n     *\n     * @return string\n     */\n    public function getDefaultConnection();\n\n    /**\n     * Set the default connection name.\n     *\n     * @param  string  $name\n     * @return void\n     */\n    public function setDefaultConnection($name);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Connectors/ConnectionFactory.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Connectors;\n\nuse Illuminate\\Contracts\\Container\\Container;\nuse Illuminate\\Database\\Connection;\nuse Illuminate\\Database\\MySqlConnection;\nuse Illuminate\\Database\\PostgresConnection;\nuse Illuminate\\Database\\SQLiteConnection;\nuse Illuminate\\Database\\SqlServerConnection;\nuse Illuminate\\Support\\Arr;\nuse InvalidArgumentException;\nuse PDOException;\n\nclass ConnectionFactory\n{\n    /**\n     * The IoC container instance.\n     *\n     * @var \\Illuminate\\Contracts\\Container\\Container\n     */\n    protected $container;\n\n    /**\n     * Create a new connection factory instance.\n     *\n     * @param  \\Illuminate\\Contracts\\Container\\Container  $container\n     * @return void\n     */\n    public function __construct(Container $container)\n    {\n        $this->container = $container;\n    }\n\n    /**\n     * Establish a PDO connection based on the configuration.\n     *\n     * @param  array  $config\n     * @param  string|null  $name\n     * @return \\Illuminate\\Database\\Connection\n     */\n    public function make(array $config, $name = null)\n    {\n        $config = $this->parseConfig($config, $name);\n\n        if (isset($config['read'])) {\n            return $this->createReadWriteConnection($config);\n        }\n\n        return $this->createSingleConnection($config);\n    }\n\n    /**\n     * Parse and prepare the database configuration.\n     *\n     * @param  array  $config\n     * @param  string  $name\n     * @return array\n     */\n    protected function parseConfig(array $config, $name)\n    {\n        return Arr::add(Arr::add($config, 'prefix', ''), 'name', $name);\n    }\n\n    /**\n     * Create a single database connection instance.\n     *\n     * @param  array  $config\n     * @return \\Illuminate\\Database\\Connection\n     */\n    protected function createSingleConnection(array $config)\n    {\n        $pdo = $this->createPdoResolver($config);\n\n        return $this->createConnection(\n            $config['driver'], $pdo, $config['database'], $config['prefix'], $config\n        );\n    }\n\n    /**\n     * Create a read / write database connection instance.\n     *\n     * @param  array  $config\n     * @return \\Illuminate\\Database\\Connection\n     */\n    protected function createReadWriteConnection(array $config)\n    {\n        $connection = $this->createSingleConnection($this->getWriteConfig($config));\n\n        return $connection->setReadPdo($this->createReadPdo($config));\n    }\n\n    /**\n     * Create a new PDO instance for reading.\n     *\n     * @param  array  $config\n     * @return \\Closure\n     */\n    protected function createReadPdo(array $config)\n    {\n        return $this->createPdoResolver($this->getReadConfig($config));\n    }\n\n    /**\n     * Get the read configuration for a read / write connection.\n     *\n     * @param  array  $config\n     * @return array\n     */\n    protected function getReadConfig(array $config)\n    {\n        return $this->mergeReadWriteConfig(\n            $config, $this->getReadWriteConfig($config, 'read')\n        );\n    }\n\n    /**\n     * Get the write configuration for a read / write connection.\n     *\n     * @param  array  $config\n     * @return array\n     */\n    protected function getWriteConfig(array $config)\n    {\n        return $this->mergeReadWriteConfig(\n            $config, $this->getReadWriteConfig($config, 'write')\n        );\n    }\n\n    /**\n     * Get a read / write level configuration.\n     *\n     * @param  array  $config\n     * @param  string  $type\n     * @return array\n     */\n    protected function getReadWriteConfig(array $config, $type)\n    {\n        return isset($config[$type][0])\n                        ? Arr::random($config[$type])\n                        : $config[$type];\n    }\n\n    /**\n     * Merge a configuration for a read / write connection.\n     *\n     * @param  array  $config\n     * @param  array  $merge\n     * @return array\n     */\n    protected function mergeReadWriteConfig(array $config, array $merge)\n    {\n        return Arr::except(array_merge($config, $merge), ['read', 'write']);\n    }\n\n    /**\n     * Create a new Closure that resolves to a PDO instance.\n     *\n     * @param  array  $config\n     * @return \\Closure\n     */\n    protected function createPdoResolver(array $config)\n    {\n        return array_key_exists('host', $config)\n                            ? $this->createPdoResolverWithHosts($config)\n                            : $this->createPdoResolverWithoutHosts($config);\n    }\n\n    /**\n     * Create a new Closure that resolves to a PDO instance with a specific host or an array of hosts.\n     *\n     * @param  array  $config\n     * @return \\Closure\n     *\n     * @throws \\PDOException\n     */\n    protected function createPdoResolverWithHosts(array $config)\n    {\n        return function () use ($config) {\n            foreach (Arr::shuffle($hosts = $this->parseHosts($config)) as $key => $host) {\n                $config['host'] = $host;\n\n                try {\n                    return $this->createConnector($config)->connect($config);\n                } catch (PDOException $e) {\n                    continue;\n                }\n            }\n\n            throw $e;\n        };\n    }\n\n    /**\n     * Parse the hosts configuration item into an array.\n     *\n     * @param  array  $config\n     * @return array\n     *\n     * @throws \\InvalidArgumentException\n     */\n    protected function parseHosts(array $config)\n    {\n        $hosts = Arr::wrap($config['host']);\n\n        if (empty($hosts)) {\n            throw new InvalidArgumentException('Database hosts array is empty.');\n        }\n\n        return $hosts;\n    }\n\n    /**\n     * Create a new Closure that resolves to a PDO instance where there is no configured host.\n     *\n     * @param  array  $config\n     * @return \\Closure\n     */\n    protected function createPdoResolverWithoutHosts(array $config)\n    {\n        return function () use ($config) {\n            return $this->createConnector($config)->connect($config);\n        };\n    }\n\n    /**\n     * Create a connector instance based on the configuration.\n     *\n     * @param  array  $config\n     * @return \\Illuminate\\Database\\Connectors\\ConnectorInterface\n     *\n     * @throws \\InvalidArgumentException\n     */\n    public function createConnector(array $config)\n    {\n        if (! isset($config['driver'])) {\n            throw new InvalidArgumentException('A driver must be specified.');\n        }\n\n        if ($this->container->bound($key = \"db.connector.{$config['driver']}\")) {\n            return $this->container->make($key);\n        }\n\n        switch ($config['driver']) {\n            case 'mysql':\n                return new MySqlConnector;\n            case 'pgsql':\n                return new PostgresConnector;\n            case 'sqlite':\n                return new SQLiteConnector;\n            case 'sqlsrv':\n                return new SqlServerConnector;\n        }\n\n        throw new InvalidArgumentException(\"Unsupported driver [{$config['driver']}].\");\n    }\n\n    /**\n     * Create a new connection instance.\n     *\n     * @param  string  $driver\n     * @param  \\PDO|\\Closure  $connection\n     * @param  string  $database\n     * @param  string  $prefix\n     * @param  array  $config\n     * @return \\Illuminate\\Database\\Connection\n     *\n     * @throws \\InvalidArgumentException\n     */\n    protected function createConnection($driver, $connection, $database, $prefix = '', array $config = [])\n    {\n        if ($resolver = Connection::getResolver($driver)) {\n            return $resolver($connection, $database, $prefix, $config);\n        }\n\n        switch ($driver) {\n            case 'mysql':\n                return new MySqlConnection($connection, $database, $prefix, $config);\n            case 'pgsql':\n                return new PostgresConnection($connection, $database, $prefix, $config);\n            case 'sqlite':\n                return new SQLiteConnection($connection, $database, $prefix, $config);\n            case 'sqlsrv':\n                return new SqlServerConnection($connection, $database, $prefix, $config);\n        }\n\n        throw new InvalidArgumentException(\"Unsupported driver [{$driver}].\");\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Connectors/Connector.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Connectors;\n\nuse Doctrine\\DBAL\\Driver\\PDOConnection;\nuse Exception;\nuse Illuminate\\Database\\DetectsLostConnections;\nuse PDO;\nuse Throwable;\n\nclass Connector\n{\n    use DetectsLostConnections;\n\n    /**\n     * The default PDO connection options.\n     *\n     * @var array\n     */\n    protected $options = [\n        PDO::ATTR_CASE => PDO::CASE_NATURAL,\n        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,\n        PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL,\n        PDO::ATTR_STRINGIFY_FETCHES => false,\n        PDO::ATTR_EMULATE_PREPARES => false,\n    ];\n\n    /**\n     * Create a new PDO connection.\n     *\n     * @param  string  $dsn\n     * @param  array  $config\n     * @param  array  $options\n     * @return \\PDO\n     *\n     * @throws \\Exception\n     */\n    public function createConnection($dsn, array $config, array $options)\n    {\n        [$username, $password] = [\n            $config['username'] ?? null, $config['password'] ?? null,\n        ];\n\n        try {\n            return $this->createPdoConnection(\n                $dsn, $username, $password, $options\n            );\n        } catch (Exception $e) {\n            return $this->tryAgainIfCausedByLostConnection(\n                $e, $dsn, $username, $password, $options\n            );\n        }\n    }\n\n    /**\n     * Create a new PDO connection instance.\n     *\n     * @param  string  $dsn\n     * @param  string  $username\n     * @param  string  $password\n     * @param  array  $options\n     * @return \\PDO\n     */\n    protected function createPdoConnection($dsn, $username, $password, $options)\n    {\n        if (class_exists(PDOConnection::class) && ! $this->isPersistentConnection($options)) {\n            return new PDOConnection($dsn, $username, $password, $options);\n        }\n\n        return new PDO($dsn, $username, $password, $options);\n    }\n\n    /**\n     * Determine if the connection is persistent.\n     *\n     * @param  array  $options\n     * @return bool\n     */\n    protected function isPersistentConnection($options)\n    {\n        return isset($options[PDO::ATTR_PERSISTENT]) &&\n               $options[PDO::ATTR_PERSISTENT];\n    }\n\n    /**\n     * Handle an exception that occurred during connect execution.\n     *\n     * @param  \\Throwable  $e\n     * @param  string  $dsn\n     * @param  string  $username\n     * @param  string  $password\n     * @param  array  $options\n     * @return \\PDO\n     *\n     * @throws \\Exception\n     */\n    protected function tryAgainIfCausedByLostConnection(Throwable $e, $dsn, $username, $password, $options)\n    {\n        if ($this->causedByLostConnection($e)) {\n            return $this->createPdoConnection($dsn, $username, $password, $options);\n        }\n\n        throw $e;\n    }\n\n    /**\n     * Get the PDO options based on the configuration.\n     *\n     * @param  array  $config\n     * @return array\n     */\n    public function getOptions(array $config)\n    {\n        $options = $config['options'] ?? [];\n\n        return array_diff_key($this->options, $options) + $options;\n    }\n\n    /**\n     * Get the default PDO connection options.\n     *\n     * @return array\n     */\n    public function getDefaultOptions()\n    {\n        return $this->options;\n    }\n\n    /**\n     * Set the default PDO connection options.\n     *\n     * @param  array  $options\n     * @return void\n     */\n    public function setDefaultOptions(array $options)\n    {\n        $this->options = $options;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Connectors/ConnectorInterface.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Connectors;\n\ninterface ConnectorInterface\n{\n    /**\n     * Establish a database connection.\n     *\n     * @param  array  $config\n     * @return \\PDO\n     */\n    public function connect(array $config);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Connectors/MySqlConnector.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Connectors;\n\nuse PDO;\n\nclass MySqlConnector extends Connector implements ConnectorInterface\n{\n    /**\n     * Establish a database connection.\n     *\n     * @param  array  $config\n     * @return \\PDO\n     */\n    public function connect(array $config)\n    {\n        $dsn = $this->getDsn($config);\n\n        $options = $this->getOptions($config);\n\n        // We need to grab the PDO options that should be used while making the brand\n        // new connection instance. The PDO options control various aspects of the\n        // connection's behavior, and some might be specified by the developers.\n        $connection = $this->createConnection($dsn, $config, $options);\n\n        if (! empty($config['database'])) {\n            $connection->exec(\"use `{$config['database']}`;\");\n        }\n\n        $this->configureIsolationLevel($connection, $config);\n\n        $this->configureEncoding($connection, $config);\n\n        // Next, we will check to see if a timezone has been specified in this config\n        // and if it has we will issue a statement to modify the timezone with the\n        // database. Setting this DB timezone is an optional configuration item.\n        $this->configureTimezone($connection, $config);\n\n        $this->setModes($connection, $config);\n\n        return $connection;\n    }\n\n    /**\n     * Set the connection transaction isolation level.\n     *\n     * @param  \\PDO  $connection\n     * @param  array  $config\n     * @return void\n     */\n    protected function configureIsolationLevel($connection, array $config)\n    {\n        if (! isset($config['isolation_level'])) {\n            return;\n        }\n\n        $connection->prepare(\n            \"SET SESSION TRANSACTION ISOLATION LEVEL {$config['isolation_level']}\"\n        )->execute();\n    }\n\n    /**\n     * Set the connection character set and collation.\n     *\n     * @param  \\PDO  $connection\n     * @param  array  $config\n     * @return void|\\PDO\n     */\n    protected function configureEncoding($connection, array $config)\n    {\n        if (! isset($config['charset'])) {\n            return $connection;\n        }\n\n        $connection->prepare(\n            \"set names '{$config['charset']}'\".$this->getCollation($config)\n        )->execute();\n    }\n\n    /**\n     * Get the collation for the configuration.\n     *\n     * @param  array  $config\n     * @return string\n     */\n    protected function getCollation(array $config)\n    {\n        return isset($config['collation']) ? \" collate '{$config['collation']}'\" : '';\n    }\n\n    /**\n     * Set the timezone on the connection.\n     *\n     * @param  \\PDO  $connection\n     * @param  array  $config\n     * @return void\n     */\n    protected function configureTimezone($connection, array $config)\n    {\n        if (isset($config['timezone'])) {\n            $connection->prepare('set time_zone=\"'.$config['timezone'].'\"')->execute();\n        }\n    }\n\n    /**\n     * Create a DSN string from a configuration.\n     *\n     * Chooses socket or host/port based on the 'unix_socket' config value.\n     *\n     * @param  array  $config\n     * @return string\n     */\n    protected function getDsn(array $config)\n    {\n        return $this->hasSocket($config)\n                            ? $this->getSocketDsn($config)\n                            : $this->getHostDsn($config);\n    }\n\n    /**\n     * Determine if the given configuration array has a UNIX socket value.\n     *\n     * @param  array  $config\n     * @return bool\n     */\n    protected function hasSocket(array $config)\n    {\n        return isset($config['unix_socket']) && ! empty($config['unix_socket']);\n    }\n\n    /**\n     * Get the DSN string for a socket configuration.\n     *\n     * @param  array  $config\n     * @return string\n     */\n    protected function getSocketDsn(array $config)\n    {\n        return \"mysql:unix_socket={$config['unix_socket']};dbname={$config['database']}\";\n    }\n\n    /**\n     * Get the DSN string for a host / port configuration.\n     *\n     * @param  array  $config\n     * @return string\n     */\n    protected function getHostDsn(array $config)\n    {\n        extract($config, EXTR_SKIP);\n\n        return isset($port)\n                    ? \"mysql:host={$host};port={$port};dbname={$database}\"\n                    : \"mysql:host={$host};dbname={$database}\";\n    }\n\n    /**\n     * Set the modes for the connection.\n     *\n     * @param  \\PDO  $connection\n     * @param  array  $config\n     * @return void\n     */\n    protected function setModes(PDO $connection, array $config)\n    {\n        if (isset($config['modes'])) {\n            $this->setCustomModes($connection, $config);\n        } elseif (isset($config['strict'])) {\n            if ($config['strict']) {\n                $connection->prepare($this->strictMode($connection, $config))->execute();\n            } else {\n                $connection->prepare(\"set session sql_mode='NO_ENGINE_SUBSTITUTION'\")->execute();\n            }\n        }\n    }\n\n    /**\n     * Set the custom modes on the connection.\n     *\n     * @param  \\PDO  $connection\n     * @param  array  $config\n     * @return void\n     */\n    protected function setCustomModes(PDO $connection, array $config)\n    {\n        $modes = implode(',', $config['modes']);\n\n        $connection->prepare(\"set session sql_mode='{$modes}'\")->execute();\n    }\n\n    /**\n     * Get the query to enable strict mode.\n     *\n     * @param  \\PDO  $connection\n     * @param  array  $config\n     * @return string\n     */\n    protected function strictMode(PDO $connection, $config)\n    {\n        $version = $config['version'] ?? $connection->getAttribute(PDO::ATTR_SERVER_VERSION);\n\n        if (version_compare($version, '8.0.11') >= 0) {\n            return \"set session sql_mode='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'\";\n        }\n\n        return \"set session sql_mode='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION'\";\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Connectors/PostgresConnector.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Connectors;\n\nuse PDO;\n\nclass PostgresConnector extends Connector implements ConnectorInterface\n{\n    /**\n     * The default PDO connection options.\n     *\n     * @var array\n     */\n    protected $options = [\n        PDO::ATTR_CASE => PDO::CASE_NATURAL,\n        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,\n        PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL,\n        PDO::ATTR_STRINGIFY_FETCHES => false,\n    ];\n\n    /**\n     * Establish a database connection.\n     *\n     * @param  array  $config\n     * @return \\PDO\n     */\n    public function connect(array $config)\n    {\n        // First we'll create the basic DSN and connection instance connecting to the\n        // using the configuration option specified by the developer. We will also\n        // set the default character set on the connections to UTF-8 by default.\n        $connection = $this->createConnection(\n            $this->getDsn($config), $config, $this->getOptions($config)\n        );\n\n        $this->configureIsolationLevel($connection, $config);\n\n        $this->configureEncoding($connection, $config);\n\n        // Next, we will check to see if a timezone has been specified in this config\n        // and if it has we will issue a statement to modify the timezone with the\n        // database. Setting this DB timezone is an optional configuration item.\n        $this->configureTimezone($connection, $config);\n\n        $this->configureSchema($connection, $config);\n\n        // Postgres allows an application_name to be set by the user and this name is\n        // used to when monitoring the application with pg_stat_activity. So we'll\n        // determine if the option has been specified and run a statement if so.\n        $this->configureApplicationName($connection, $config);\n\n        $this->configureSynchronousCommit($connection, $config);\n\n        return $connection;\n    }\n\n    /**\n     * Set the connection transaction isolation level.\n     *\n     * @param  \\PDO  $connection\n     * @param  array  $config\n     * @return void\n     */\n    protected function configureIsolationLevel($connection, array $config)\n    {\n        if (isset($config['isolation_level'])) {\n            $connection->prepare(\"set session characteristics as transaction isolation level {$config['isolation_level']}\")->execute();\n        }\n    }\n\n    /**\n     * Set the connection character set and collation.\n     *\n     * @param  \\PDO  $connection\n     * @param  array  $config\n     * @return void\n     */\n    protected function configureEncoding($connection, $config)\n    {\n        if (! isset($config['charset'])) {\n            return;\n        }\n\n        $connection->prepare(\"set names '{$config['charset']}'\")->execute();\n    }\n\n    /**\n     * Set the timezone on the connection.\n     *\n     * @param  \\PDO  $connection\n     * @param  array  $config\n     * @return void\n     */\n    protected function configureTimezone($connection, array $config)\n    {\n        if (isset($config['timezone'])) {\n            $timezone = $config['timezone'];\n\n            $connection->prepare(\"set time zone '{$timezone}'\")->execute();\n        }\n    }\n\n    /**\n     * Set the schema on the connection.\n     *\n     * @param  \\PDO  $connection\n     * @param  array  $config\n     * @return void\n     */\n    protected function configureSchema($connection, $config)\n    {\n        if (isset($config['schema'])) {\n            $schema = $this->formatSchema($config['schema']);\n\n            $connection->prepare(\"set search_path to {$schema}\")->execute();\n        }\n    }\n\n    /**\n     * Format the schema for the DSN.\n     *\n     * @param  array|string  $schema\n     * @return string\n     */\n    protected function formatSchema($schema)\n    {\n        if (is_array($schema)) {\n            return '\"'.implode('\", \"', $schema).'\"';\n        }\n\n        return '\"'.$schema.'\"';\n    }\n\n    /**\n     * Set the schema on the connection.\n     *\n     * @param  \\PDO  $connection\n     * @param  array  $config\n     * @return void\n     */\n    protected function configureApplicationName($connection, $config)\n    {\n        if (isset($config['application_name'])) {\n            $applicationName = $config['application_name'];\n\n            $connection->prepare(\"set application_name to '$applicationName'\")->execute();\n        }\n    }\n\n    /**\n     * Create a DSN string from a configuration.\n     *\n     * @param  array  $config\n     * @return string\n     */\n    protected function getDsn(array $config)\n    {\n        // First we will create the basic DSN setup as well as the port if it is in\n        // in the configuration options. This will give us the basic DSN we will\n        // need to establish the PDO connections and return them back for use.\n        extract($config, EXTR_SKIP);\n\n        $host = isset($host) ? \"host={$host};\" : '';\n\n        $dsn = \"pgsql:{$host}dbname='{$database}'\";\n\n        // If a port was specified, we will add it to this Postgres DSN connections\n        // format. Once we have done that we are ready to return this connection\n        // string back out for usage, as this has been fully constructed here.\n        if (isset($config['port'])) {\n            $dsn .= \";port={$port}\";\n        }\n\n        return $this->addSslOptions($dsn, $config);\n    }\n\n    /**\n     * Add the SSL options to the DSN.\n     *\n     * @param  string  $dsn\n     * @param  array  $config\n     * @return string\n     */\n    protected function addSslOptions($dsn, array $config)\n    {\n        foreach (['sslmode', 'sslcert', 'sslkey', 'sslrootcert'] as $option) {\n            if (isset($config[$option])) {\n                $dsn .= \";{$option}={$config[$option]}\";\n            }\n        }\n\n        return $dsn;\n    }\n\n    /**\n     * Configure the synchronous_commit setting.\n     *\n     * @param  \\PDO  $connection\n     * @param  array  $config\n     * @return void\n     */\n    protected function configureSynchronousCommit($connection, array $config)\n    {\n        if (! isset($config['synchronous_commit'])) {\n            return;\n        }\n\n        $connection->prepare(\"set synchronous_commit to '{$config['synchronous_commit']}'\")->execute();\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Connectors/SQLiteConnector.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Connectors;\n\nuse InvalidArgumentException;\n\nclass SQLiteConnector extends Connector implements ConnectorInterface\n{\n    /**\n     * Establish a database connection.\n     *\n     * @param  array  $config\n     * @return \\PDO\n     *\n     * @throws \\InvalidArgumentException\n     */\n    public function connect(array $config)\n    {\n        $options = $this->getOptions($config);\n\n        // SQLite supports \"in-memory\" databases that only last as long as the owning\n        // connection does. These are useful for tests or for short lifetime store\n        // querying. In-memory databases may only have a single open connection.\n        if ($config['database'] === ':memory:') {\n            return $this->createConnection('sqlite::memory:', $config, $options);\n        }\n\n        $path = realpath($config['database']);\n\n        // Here we'll verify that the SQLite database exists before going any further\n        // as the developer probably wants to know if the database exists and this\n        // SQLite driver will not throw any exception if it does not by default.\n        if ($path === false) {\n            throw new InvalidArgumentException(\"Database ({$config['database']}) does not exist.\");\n        }\n\n        return $this->createConnection(\"sqlite:{$path}\", $config, $options);\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Connectors/SqlServerConnector.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Connectors;\n\nuse Illuminate\\Support\\Arr;\nuse PDO;\n\nclass SqlServerConnector extends Connector implements ConnectorInterface\n{\n    /**\n     * The PDO connection options.\n     *\n     * @var array\n     */\n    protected $options = [\n        PDO::ATTR_CASE => PDO::CASE_NATURAL,\n        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,\n        PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL,\n        PDO::ATTR_STRINGIFY_FETCHES => false,\n    ];\n\n    /**\n     * Establish a database connection.\n     *\n     * @param  array  $config\n     * @return \\PDO\n     */\n    public function connect(array $config)\n    {\n        $options = $this->getOptions($config);\n\n        return $this->createConnection($this->getDsn($config), $config, $options);\n    }\n\n    /**\n     * Create a DSN string from a configuration.\n     *\n     * @param  array  $config\n     * @return string\n     */\n    protected function getDsn(array $config)\n    {\n        // First we will create the basic DSN setup as well as the port if it is in\n        // in the configuration options. This will give us the basic DSN we will\n        // need to establish the PDO connections and return them back for use.\n        if ($this->prefersOdbc($config)) {\n            return $this->getOdbcDsn($config);\n        }\n\n        if (in_array('sqlsrv', $this->getAvailableDrivers())) {\n            return $this->getSqlSrvDsn($config);\n        } else {\n            return $this->getDblibDsn($config);\n        }\n    }\n\n    /**\n     * Determine if the database configuration prefers ODBC.\n     *\n     * @param  array  $config\n     * @return bool\n     */\n    protected function prefersOdbc(array $config)\n    {\n        return in_array('odbc', $this->getAvailableDrivers()) &&\n               ($config['odbc'] ?? null) === true;\n    }\n\n    /**\n     * Get the DSN string for a DbLib connection.\n     *\n     * @param  array  $config\n     * @return string\n     */\n    protected function getDblibDsn(array $config)\n    {\n        return $this->buildConnectString('dblib', array_merge([\n            'host' => $this->buildHostString($config, ':'),\n            'dbname' => $config['database'],\n        ], Arr::only($config, ['appname', 'charset', 'version'])));\n    }\n\n    /**\n     * Get the DSN string for an ODBC connection.\n     *\n     * @param  array  $config\n     * @return string\n     */\n    protected function getOdbcDsn(array $config)\n    {\n        return isset($config['odbc_datasource_name'])\n                    ? 'odbc:'.$config['odbc_datasource_name'] : '';\n    }\n\n    /**\n     * Get the DSN string for a SqlSrv connection.\n     *\n     * @param  array  $config\n     * @return string\n     */\n    protected function getSqlSrvDsn(array $config)\n    {\n        $arguments = [\n            'Server' => $this->buildHostString($config, ','),\n        ];\n\n        if (isset($config['database'])) {\n            $arguments['Database'] = $config['database'];\n        }\n\n        if (isset($config['readonly'])) {\n            $arguments['ApplicationIntent'] = 'ReadOnly';\n        }\n\n        if (isset($config['pooling']) && $config['pooling'] === false) {\n            $arguments['ConnectionPooling'] = '0';\n        }\n\n        if (isset($config['appname'])) {\n            $arguments['APP'] = $config['appname'];\n        }\n\n        if (isset($config['encrypt'])) {\n            $arguments['Encrypt'] = $config['encrypt'];\n        }\n\n        if (isset($config['trust_server_certificate'])) {\n            $arguments['TrustServerCertificate'] = $config['trust_server_certificate'];\n        }\n\n        if (isset($config['multiple_active_result_sets']) && $config['multiple_active_result_sets'] === false) {\n            $arguments['MultipleActiveResultSets'] = 'false';\n        }\n\n        if (isset($config['transaction_isolation'])) {\n            $arguments['TransactionIsolation'] = $config['transaction_isolation'];\n        }\n\n        if (isset($config['multi_subnet_failover'])) {\n            $arguments['MultiSubnetFailover'] = $config['multi_subnet_failover'];\n        }\n\n        if (isset($config['column_encryption'])) {\n            $arguments['ColumnEncryption'] = $config['column_encryption'];\n        }\n\n        if (isset($config['key_store_authentication'])) {\n            $arguments['KeyStoreAuthentication'] = $config['key_store_authentication'];\n        }\n\n        if (isset($config['key_store_principal_id'])) {\n            $arguments['KeyStorePrincipalId'] = $config['key_store_principal_id'];\n        }\n\n        if (isset($config['key_store_secret'])) {\n            $arguments['KeyStoreSecret'] = $config['key_store_secret'];\n        }\n\n        if (isset($config['login_timeout'])) {\n            $arguments['LoginTimeout'] = $config['login_timeout'];\n        }\n\n        return $this->buildConnectString('sqlsrv', $arguments);\n    }\n\n    /**\n     * Build a connection string from the given arguments.\n     *\n     * @param  string  $driver\n     * @param  array  $arguments\n     * @return string\n     */\n    protected function buildConnectString($driver, array $arguments)\n    {\n        return $driver.':'.implode(';', array_map(function ($key) use ($arguments) {\n            return sprintf('%s=%s', $key, $arguments[$key]);\n        }, array_keys($arguments)));\n    }\n\n    /**\n     * Build a host string from the given configuration.\n     *\n     * @param  array  $config\n     * @param  string  $separator\n     * @return string\n     */\n    protected function buildHostString(array $config, $separator)\n    {\n        if (empty($config['port'])) {\n            return $config['host'];\n        }\n\n        return $config['host'].$separator.$config['port'];\n    }\n\n    /**\n     * Get the available PDO drivers.\n     *\n     * @return array\n     */\n    protected function getAvailableDrivers()\n    {\n        return PDO::getAvailableDrivers();\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Console/DbCommand.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Console;\n\nuse Illuminate\\Console\\Command;\nuse Illuminate\\Support\\ConfigurationUrlParser;\nuse Symfony\\Component\\Process\\Process;\nuse UnexpectedValueException;\n\nclass DbCommand extends Command\n{\n    /**\n     * The name and signature of the console command.\n     *\n     * @var string\n     */\n    protected $signature = 'db {connection? : The database connection that should be used}\n               {--read : Connect to the read connection}\n               {--write : Connect to the write connection}';\n\n    /**\n     * The console command description.\n     *\n     * @var string\n     */\n    protected $description = 'Start a new database CLI session';\n\n    /**\n     * Execute the console command.\n     *\n     * @return int\n     */\n    public function handle()\n    {\n        $connection = $this->getConnection();\n\n        (new Process(\n            array_merge([$this->getCommand($connection)], $this->commandArguments($connection)),\n            null,\n            $this->commandEnvironment($connection)\n        ))->setTimeout(null)->setTty(true)->mustRun(function ($type, $buffer) {\n            $this->output->write($buffer);\n        });\n\n        return 0;\n    }\n\n    /**\n     * Get the database connection configuration.\n     *\n     * @return array\n     *\n     * @throws \\UnexpectedValueException\n     */\n    public function getConnection()\n    {\n        $connection = $this->laravel['config']['database.connections.'.\n            (($db = $this->argument('connection')) ?? $this->laravel['config']['database.default'])\n        ];\n\n        if (empty($connection)) {\n            throw new UnexpectedValueException(\"Invalid database connection [{$db}].\");\n        }\n\n        if (! empty($connection['url'])) {\n            $connection = (new ConfigurationUrlParser)->parseConfiguration($connection);\n        }\n\n        if ($this->option('read')) {\n            if (is_array($connection['read']['host'])) {\n                $connection['read']['host'] = $connection['read']['host'][0];\n            }\n\n            $connection = array_merge($connection, $connection['read']);\n        } elseif ($this->option('write')) {\n            if (is_array($connection['write']['host'])) {\n                $connection['write']['host'] = $connection['write']['host'][0];\n            }\n\n            $connection = array_merge($connection, $connection['write']);\n        }\n\n        return $connection;\n    }\n\n    /**\n     * Get the arguments for the database client command.\n     *\n     * @param  array  $connection\n     * @return array\n     */\n    public function commandArguments(array $connection)\n    {\n        $driver = ucfirst($connection['driver']);\n\n        return $this->{\"get{$driver}Arguments\"}($connection);\n    }\n\n    /**\n     * Get the environment variables for the database client command.\n     *\n     * @param  array  $connection\n     * @return array|null\n     */\n    public function commandEnvironment(array $connection)\n    {\n        $driver = ucfirst($connection['driver']);\n\n        if (method_exists($this, \"get{$driver}Environment\")) {\n            return $this->{\"get{$driver}Environment\"}($connection);\n        }\n\n        return null;\n    }\n\n    /**\n     * Get the database client command to run.\n     *\n     * @param  array  $connection\n     * @return string\n     */\n    public function getCommand(array $connection)\n    {\n        return [\n            'mysql' => 'mysql',\n            'pgsql' => 'psql',\n            'sqlite' => 'sqlite3',\n            'sqlsrv' => 'sqlcmd',\n        ][$connection['driver']];\n    }\n\n    /**\n     * Get the arguments for the MySQL CLI.\n     *\n     * @param  array  $connection\n     * @return array\n     */\n    protected function getMysqlArguments(array $connection)\n    {\n        return array_merge([\n            '--host='.$connection['host'],\n            '--port='.$connection['port'],\n            '--user='.$connection['username'],\n        ], $this->getOptionalArguments([\n            'password' => '--password='.$connection['password'],\n            'unix_socket' => '--socket='.($connection['unix_socket'] ?? ''),\n            'charset' => '--default-character-set='.($connection['charset'] ?? ''),\n        ], $connection), [$connection['database']]);\n    }\n\n    /**\n     * Get the arguments for the Postgres CLI.\n     *\n     * @param  array  $connection\n     * @return array\n     */\n    protected function getPgsqlArguments(array $connection)\n    {\n        return [$connection['database']];\n    }\n\n    /**\n     * Get the arguments for the SQLite CLI.\n     *\n     * @param  array  $connection\n     * @return array\n     */\n    protected function getSqliteArguments(array $connection)\n    {\n        return [$connection['database']];\n    }\n\n    /**\n     * Get the arguments for the SQL Server CLI.\n     *\n     * @param  array  $connection\n     * @return array\n     */\n    protected function getSqlsrvArguments(array $connection)\n    {\n        return array_merge(...$this->getOptionalArguments([\n            'database' => ['-d', $connection['database']],\n            'username' => ['-U', $connection['username']],\n            'password' => ['-P', $connection['password']],\n            'host' => ['-S', 'tcp:'.$connection['host']\n                        .($connection['port'] ? ','.$connection['port'] : ''), ],\n        ], $connection));\n    }\n\n    /**\n     * Get the environment variables for the Postgres CLI.\n     *\n     * @param  array  $connection\n     * @return array|null\n     */\n    protected function getPgsqlEnvironment(array $connection)\n    {\n        return array_merge(...$this->getOptionalArguments([\n            'username' => ['PGUSER' => $connection['username']],\n            'host' => ['PGHOST' => $connection['host']],\n            'port' => ['PGPORT' => $connection['port']],\n            'password' => ['PGPASSWORD' => $connection['password']],\n        ], $connection));\n    }\n\n    /**\n     * Get the optional arguments based on the connection configuration.\n     *\n     * @param  array  $args\n     * @param  array  $connection\n     * @return array\n     */\n    protected function getOptionalArguments(array $args, array $connection)\n    {\n        return array_values(array_filter($args, function ($key) use ($connection) {\n            return ! empty($connection[$key]);\n        }, ARRAY_FILTER_USE_KEY));\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Console/DumpCommand.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Console;\n\nuse Illuminate\\Console\\Command;\nuse Illuminate\\Contracts\\Events\\Dispatcher;\nuse Illuminate\\Database\\Connection;\nuse Illuminate\\Database\\ConnectionResolverInterface;\nuse Illuminate\\Database\\Events\\SchemaDumped;\nuse Illuminate\\Filesystem\\Filesystem;\nuse Illuminate\\Support\\Facades\\Config;\n\nclass DumpCommand extends Command\n{\n    /**\n     * The console command name.\n     *\n     * @var string\n     */\n    protected $signature = 'schema:dump\n                {--database= : The database connection to use}\n                {--path= : The path where the schema dump file should be stored}\n                {--prune : Delete all existing migration files}';\n\n    /**\n     * The console command description.\n     *\n     * @var string\n     */\n    protected $description = 'Dump the given database schema';\n\n    /**\n     * Execute the console command.\n     *\n     * @param  \\Illuminate\\Database\\ConnectionResolverInterface  $connections\n     * @param  \\Illuminate\\Contracts\\Events\\Dispatcher  $dispatcher\n     * @return int\n     */\n    public function handle(ConnectionResolverInterface $connections, Dispatcher $dispatcher)\n    {\n        $connection = $connections->connection($database = $this->input->getOption('database'));\n\n        $this->schemaState($connection)->dump(\n            $connection, $path = $this->path($connection)\n        );\n\n        $dispatcher->dispatch(new SchemaDumped($connection, $path));\n\n        $this->info('Database schema dumped successfully.');\n\n        if ($this->option('prune')) {\n            (new Filesystem)->deleteDirectory(\n                database_path('migrations'), $preserve = false\n            );\n\n            $this->info('Migrations pruned successfully.');\n        }\n    }\n\n    /**\n     * Create a schema state instance for the given connection.\n     *\n     * @param  \\Illuminate\\Database\\Connection  $connection\n     * @return mixed\n     */\n    protected function schemaState(Connection $connection)\n    {\n        return $connection->getSchemaState()\n                ->withMigrationTable($connection->getTablePrefix().Config::get('database.migrations', 'migrations'))\n                ->handleOutputUsing(function ($type, $buffer) {\n                    $this->output->write($buffer);\n                });\n    }\n\n    /**\n     * Get the path that the dump should be written to.\n     *\n     * @param  \\Illuminate\\Database\\Connection  $connection\n     */\n    protected function path(Connection $connection)\n    {\n        return tap($this->option('path') ?: database_path('schema/'.$connection->getName().'-schema.dump'), function ($path) {\n            (new Filesystem)->ensureDirectoryExists(dirname($path));\n        });\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Console/Factories/FactoryMakeCommand.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Console\\Factories;\n\nuse Illuminate\\Console\\GeneratorCommand;\nuse Illuminate\\Support\\Str;\nuse Symfony\\Component\\Console\\Input\\InputOption;\n\nclass FactoryMakeCommand extends GeneratorCommand\n{\n    /**\n     * The console command name.\n     *\n     * @var string\n     */\n    protected $name = 'make:factory';\n\n    /**\n     * The console command description.\n     *\n     * @var string\n     */\n    protected $description = 'Create a new model factory';\n\n    /**\n     * The type of class being generated.\n     *\n     * @var string\n     */\n    protected $type = 'Factory';\n\n    /**\n     * Get the stub file for the generator.\n     *\n     * @return string\n     */\n    protected function getStub()\n    {\n        return $this->resolveStubPath('/stubs/factory.stub');\n    }\n\n    /**\n     * Resolve the fully-qualified path to the stub.\n     *\n     * @param  string  $stub\n     * @return string\n     */\n    protected function resolveStubPath($stub)\n    {\n        return file_exists($customPath = $this->laravel->basePath(trim($stub, '/')))\n            ? $customPath\n            : __DIR__.$stub;\n    }\n\n    /**\n     * Build the class with the given name.\n     *\n     * @param  string  $name\n     * @return string\n     */\n    protected function buildClass($name)\n    {\n        $factory = class_basename(Str::ucfirst(str_replace('Factory', '', $name)));\n\n        $namespaceModel = $this->option('model')\n                        ? $this->qualifyModel($this->option('model'))\n                        : $this->qualifyModel($this->guessModelName($name));\n\n        $model = class_basename($namespaceModel);\n\n        if (Str::startsWith($namespaceModel, $this->rootNamespace().'Models')) {\n            $namespace = Str::beforeLast('Database\\\\Factories\\\\'.Str::after($namespaceModel, $this->rootNamespace().'Models\\\\'), '\\\\');\n        } else {\n            $namespace = 'Database\\\\Factories';\n        }\n\n        $replace = [\n            '{{ factoryNamespace }}' => $namespace,\n            'NamespacedDummyModel' => $namespaceModel,\n            '{{ namespacedModel }}' => $namespaceModel,\n            '{{namespacedModel}}' => $namespaceModel,\n            'DummyModel' => $model,\n            '{{ model }}' => $model,\n            '{{model}}' => $model,\n            '{{ factory }}' => $factory,\n            '{{factory}}' => $factory,\n        ];\n\n        return str_replace(\n            array_keys($replace), array_values($replace), parent::buildClass($name)\n        );\n    }\n\n    /**\n     * Get the destination class path.\n     *\n     * @param  string  $name\n     * @return string\n     */\n    protected function getPath($name)\n    {\n        $name = (string) Str::of($name)->replaceFirst($this->rootNamespace(), '')->finish('Factory');\n\n        return $this->laravel->databasePath().'/factories/'.str_replace('\\\\', '/', $name).'.php';\n    }\n\n    /**\n     * Guess the model name from the Factory name or return a default model name.\n     *\n     * @param  string  $name\n     * @return string\n     */\n    protected function guessModelName($name)\n    {\n        if (Str::endsWith($name, 'Factory')) {\n            $name = substr($name, 0, -7);\n        }\n\n        $modelName = $this->qualifyModel(Str::after($name, $this->rootNamespace()));\n\n        if (class_exists($modelName)) {\n            return $modelName;\n        }\n\n        if (is_dir(app_path('Models/'))) {\n            return $this->rootNamespace().'Models\\Model';\n        }\n\n        return $this->rootNamespace().'Model';\n    }\n\n    /**\n     * Get the console command options.\n     *\n     * @return array\n     */\n    protected function getOptions()\n    {\n        return [\n            ['model', 'm', InputOption::VALUE_OPTIONAL, 'The name of the model'],\n        ];\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Console/Factories/stubs/factory.stub",
    "content": "<?php\n\nnamespace {{ factoryNamespace }};\n\nuse Illuminate\\Database\\Eloquent\\Factories\\Factory;\n\nclass {{ factory }}Factory extends Factory\n{\n    /**\n     * Define the model's default state.\n     *\n     * @return array\n     */\n    public function definition()\n    {\n        return [\n            //\n        ];\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Console/Migrations/BaseCommand.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Console\\Migrations;\n\nuse Illuminate\\Console\\Command;\n\nclass BaseCommand extends Command\n{\n    /**\n     * Get all of the migration paths.\n     *\n     * @return array\n     */\n    protected function getMigrationPaths()\n    {\n        // Here, we will check to see if a path option has been defined. If it has we will\n        // use the path relative to the root of the installation folder so our database\n        // migrations may be run for any customized path from within the application.\n        if ($this->input->hasOption('path') && $this->option('path')) {\n            return collect($this->option('path'))->map(function ($path) {\n                return ! $this->usingRealPath()\n                                ? $this->laravel->basePath().'/'.$path\n                                : $path;\n            })->all();\n        }\n\n        return array_merge(\n            $this->migrator->paths(), [$this->getMigrationPath()]\n        );\n    }\n\n    /**\n     * Determine if the given path(s) are pre-resolved \"real\" paths.\n     *\n     * @return bool\n     */\n    protected function usingRealPath()\n    {\n        return $this->input->hasOption('realpath') && $this->option('realpath');\n    }\n\n    /**\n     * Get the path to the migration directory.\n     *\n     * @return string\n     */\n    protected function getMigrationPath()\n    {\n        return $this->laravel->databasePath().DIRECTORY_SEPARATOR.'migrations';\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Console/Migrations/FreshCommand.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Console\\Migrations;\n\nuse Illuminate\\Console\\Command;\nuse Illuminate\\Console\\ConfirmableTrait;\nuse Illuminate\\Contracts\\Events\\Dispatcher;\nuse Illuminate\\Database\\Events\\DatabaseRefreshed;\nuse Symfony\\Component\\Console\\Input\\InputOption;\n\nclass FreshCommand extends Command\n{\n    use ConfirmableTrait;\n\n    /**\n     * The console command name.\n     *\n     * @var string\n     */\n    protected $name = 'migrate:fresh';\n\n    /**\n     * The console command description.\n     *\n     * @var string\n     */\n    protected $description = 'Drop all tables and re-run all migrations';\n\n    /**\n     * Execute the console command.\n     *\n     * @return int\n     */\n    public function handle()\n    {\n        if (! $this->confirmToProceed()) {\n            return 1;\n        }\n\n        $database = $this->input->getOption('database');\n\n        $this->call('db:wipe', array_filter([\n            '--database' => $database,\n            '--drop-views' => $this->option('drop-views'),\n            '--drop-types' => $this->option('drop-types'),\n            '--force' => true,\n        ]));\n\n        $this->call('migrate', array_filter([\n            '--database' => $database,\n            '--path' => $this->input->getOption('path'),\n            '--realpath' => $this->input->getOption('realpath'),\n            '--schema-path' => $this->input->getOption('schema-path'),\n            '--force' => true,\n            '--step' => $this->option('step'),\n        ]));\n\n        if ($this->laravel->bound(Dispatcher::class)) {\n            $this->laravel[Dispatcher::class]->dispatch(\n                new DatabaseRefreshed\n            );\n        }\n\n        if ($this->needsSeeding()) {\n            $this->runSeeder($database);\n        }\n\n        return 0;\n    }\n\n    /**\n     * Determine if the developer has requested database seeding.\n     *\n     * @return bool\n     */\n    protected function needsSeeding()\n    {\n        return $this->option('seed') || $this->option('seeder');\n    }\n\n    /**\n     * Run the database seeder command.\n     *\n     * @param  string  $database\n     * @return void\n     */\n    protected function runSeeder($database)\n    {\n        $this->call('db:seed', array_filter([\n            '--database' => $database,\n            '--class' => $this->option('seeder') ?: 'Database\\\\Seeders\\\\DatabaseSeeder',\n            '--force' => true,\n        ]));\n    }\n\n    /**\n     * Get the console command options.\n     *\n     * @return array\n     */\n    protected function getOptions()\n    {\n        return [\n            ['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to use'],\n            ['drop-views', null, InputOption::VALUE_NONE, 'Drop all tables and views'],\n            ['drop-types', null, InputOption::VALUE_NONE, 'Drop all tables and types (Postgres only)'],\n            ['force', null, InputOption::VALUE_NONE, 'Force the operation to run when in production'],\n            ['path', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'The path(s) to the migrations files to be executed'],\n            ['realpath', null, InputOption::VALUE_NONE, 'Indicate any provided migration file paths are pre-resolved absolute paths'],\n            ['schema-path', null, InputOption::VALUE_OPTIONAL, 'The path to a schema dump file'],\n            ['seed', null, InputOption::VALUE_NONE, 'Indicates if the seed task should be re-run'],\n            ['seeder', null, InputOption::VALUE_OPTIONAL, 'The class name of the root seeder'],\n            ['step', null, InputOption::VALUE_NONE, 'Force the migrations to be run so they can be rolled back individually'],\n        ];\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Console/Migrations/InstallCommand.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Console\\Migrations;\n\nuse Illuminate\\Console\\Command;\nuse Illuminate\\Database\\Migrations\\MigrationRepositoryInterface;\nuse Symfony\\Component\\Console\\Input\\InputOption;\n\nclass InstallCommand extends Command\n{\n    /**\n     * The console command name.\n     *\n     * @var string\n     */\n    protected $name = 'migrate:install';\n\n    /**\n     * The console command description.\n     *\n     * @var string\n     */\n    protected $description = 'Create the migration repository';\n\n    /**\n     * The repository instance.\n     *\n     * @var \\Illuminate\\Database\\Migrations\\MigrationRepositoryInterface\n     */\n    protected $repository;\n\n    /**\n     * Create a new migration install command instance.\n     *\n     * @param  \\Illuminate\\Database\\Migrations\\MigrationRepositoryInterface  $repository\n     * @return void\n     */\n    public function __construct(MigrationRepositoryInterface $repository)\n    {\n        parent::__construct();\n\n        $this->repository = $repository;\n    }\n\n    /**\n     * Execute the console command.\n     *\n     * @return void\n     */\n    public function handle()\n    {\n        $this->repository->setSource($this->input->getOption('database'));\n\n        $this->repository->createRepository();\n\n        $this->info('Migration table created successfully.');\n    }\n\n    /**\n     * Get the console command options.\n     *\n     * @return array\n     */\n    protected function getOptions()\n    {\n        return [\n            ['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to use'],\n        ];\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Console/Migrations/MigrateCommand.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Console\\Migrations;\n\nuse Illuminate\\Console\\ConfirmableTrait;\nuse Illuminate\\Contracts\\Events\\Dispatcher;\nuse Illuminate\\Database\\Events\\SchemaLoaded;\nuse Illuminate\\Database\\Migrations\\Migrator;\nuse Illuminate\\Database\\SqlServerConnection;\n\nclass MigrateCommand extends BaseCommand\n{\n    use ConfirmableTrait;\n\n    /**\n     * The name and signature of the console command.\n     *\n     * @var string\n     */\n    protected $signature = 'migrate {--database= : The database connection to use}\n                {--force : Force the operation to run when in production}\n                {--path=* : The path(s) to the migrations files to be executed}\n                {--realpath : Indicate any provided migration file paths are pre-resolved absolute paths}\n                {--schema-path= : The path to a schema dump file}\n                {--pretend : Dump the SQL queries that would be run}\n                {--seed : Indicates if the seed task should be re-run}\n                {--seeder= : The class name of the root seeder}\n                {--step : Force the migrations to be run so they can be rolled back individually}';\n\n    /**\n     * The console command description.\n     *\n     * @var string\n     */\n    protected $description = 'Run the database migrations';\n\n    /**\n     * The migrator instance.\n     *\n     * @var \\Illuminate\\Database\\Migrations\\Migrator\n     */\n    protected $migrator;\n\n    /**\n     * The event dispatcher instance.\n     *\n     * @var \\Illuminate\\Contracts\\Events\\Dispatcher\n     */\n    protected $dispatcher;\n\n    /**\n     * Create a new migration command instance.\n     *\n     * @param  \\Illuminate\\Database\\Migrations\\Migrator  $migrator\n     * @param  \\Illuminate\\Contracts\\Events\\Dispatcher  $dispatcher\n     * @return void\n     */\n    public function __construct(Migrator $migrator, Dispatcher $dispatcher)\n    {\n        parent::__construct();\n\n        $this->migrator = $migrator;\n        $this->dispatcher = $dispatcher;\n    }\n\n    /**\n     * Execute the console command.\n     *\n     * @return int\n     */\n    public function handle()\n    {\n        if (! $this->confirmToProceed()) {\n            return 1;\n        }\n\n        $this->migrator->usingConnection($this->option('database'), function () {\n            $this->prepareDatabase();\n\n            // Next, we will check to see if a path option has been defined. If it has\n            // we will use the path relative to the root of this installation folder\n            // so that migrations may be run for any path within the applications.\n            $this->migrator->setOutput($this->output)\n                    ->run($this->getMigrationPaths(), [\n                        'pretend' => $this->option('pretend'),\n                        'step' => $this->option('step'),\n                    ]);\n\n            // Finally, if the \"seed\" option has been given, we will re-run the database\n            // seed task to re-populate the database, which is convenient when adding\n            // a migration and a seed at the same time, as it is only this command.\n            if ($this->option('seed') && ! $this->option('pretend')) {\n                $this->call('db:seed', [\n                    '--class' => $this->option('seeder') ?: 'Database\\\\Seeders\\\\DatabaseSeeder',\n                    '--force' => true,\n                ]);\n            }\n        });\n\n        return 0;\n    }\n\n    /**\n     * Prepare the migration database for running.\n     *\n     * @return void\n     */\n    protected function prepareDatabase()\n    {\n        if (! $this->migrator->repositoryExists()) {\n            $this->call('migrate:install', array_filter([\n                '--database' => $this->option('database'),\n            ]));\n        }\n\n        if (! $this->migrator->hasRunAnyMigrations() && ! $this->option('pretend')) {\n            $this->loadSchemaState();\n        }\n    }\n\n    /**\n     * Load the schema state to seed the initial database schema structure.\n     *\n     * @return void\n     */\n    protected function loadSchemaState()\n    {\n        $connection = $this->migrator->resolveConnection($this->option('database'));\n\n        // First, we will make sure that the connection supports schema loading and that\n        // the schema file exists before we proceed any further. If not, we will just\n        // continue with the standard migration operation as normal without errors.\n        if ($connection instanceof SqlServerConnection ||\n            ! is_file($path = $this->schemaPath($connection))) {\n            return;\n        }\n\n        $this->line('<info>Loading stored database schema:</info> '.$path);\n\n        $startTime = microtime(true);\n\n        // Since the schema file will create the \"migrations\" table and reload it to its\n        // proper state, we need to delete it here so we don't get an error that this\n        // table already exists when the stored database schema file gets executed.\n        $this->migrator->deleteRepository();\n\n        $connection->getSchemaState()->handleOutputUsing(function ($type, $buffer) {\n            $this->output->write($buffer);\n        })->load($path);\n\n        $runTime = number_format((microtime(true) - $startTime) * 1000, 2);\n\n        // Finally, we will fire an event that this schema has been loaded so developers\n        // can perform any post schema load tasks that are necessary in listeners for\n        // this event, which may seed the database tables with some necessary data.\n        $this->dispatcher->dispatch(\n            new SchemaLoaded($connection, $path)\n        );\n\n        $this->line('<info>Loaded stored database schema.</info> ('.$runTime.'ms)');\n    }\n\n    /**\n     * Get the path to the stored schema for the given connection.\n     *\n     * @param  \\Illuminate\\Database\\Connection  $connection\n     * @return string\n     */\n    protected function schemaPath($connection)\n    {\n        if ($this->option('schema-path')) {\n            return $this->option('schema-path');\n        }\n\n        if (file_exists($path = database_path('schema/'.$connection->getName().'-schema.dump'))) {\n            return $path;\n        }\n\n        return database_path('schema/'.$connection->getName().'-schema.sql');\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Console/Migrations/MigrateMakeCommand.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Console\\Migrations;\n\nuse Illuminate\\Database\\Migrations\\MigrationCreator;\nuse Illuminate\\Support\\Composer;\nuse Illuminate\\Support\\Str;\n\nclass MigrateMakeCommand extends BaseCommand\n{\n    /**\n     * The console command signature.\n     *\n     * @var string\n     */\n    protected $signature = 'make:migration {name : The name of the migration}\n        {--create= : The table to be created}\n        {--table= : The table to migrate}\n        {--path= : The location where the migration file should be created}\n        {--realpath : Indicate any provided migration file paths are pre-resolved absolute paths}\n        {--fullpath : Output the full path of the migration}';\n\n    /**\n     * The console command description.\n     *\n     * @var string\n     */\n    protected $description = 'Create a new migration file';\n\n    /**\n     * The migration creator instance.\n     *\n     * @var \\Illuminate\\Database\\Migrations\\MigrationCreator\n     */\n    protected $creator;\n\n    /**\n     * The Composer instance.\n     *\n     * @var \\Illuminate\\Support\\Composer\n     */\n    protected $composer;\n\n    /**\n     * Create a new migration install command instance.\n     *\n     * @param  \\Illuminate\\Database\\Migrations\\MigrationCreator  $creator\n     * @param  \\Illuminate\\Support\\Composer  $composer\n     * @return void\n     */\n    public function __construct(MigrationCreator $creator, Composer $composer)\n    {\n        parent::__construct();\n\n        $this->creator = $creator;\n        $this->composer = $composer;\n    }\n\n    /**\n     * Execute the console command.\n     *\n     * @return void\n     */\n    public function handle()\n    {\n        // It's possible for the developer to specify the tables to modify in this\n        // schema operation. The developer may also specify if this table needs\n        // to be freshly created so we can create the appropriate migrations.\n        $name = Str::snake(trim($this->input->getArgument('name')));\n\n        $table = $this->input->getOption('table');\n\n        $create = $this->input->getOption('create') ?: false;\n\n        // If no table was given as an option but a create option is given then we\n        // will use the \"create\" option as the table name. This allows the devs\n        // to pass a table name into this option as a short-cut for creating.\n        if (! $table && is_string($create)) {\n            $table = $create;\n\n            $create = true;\n        }\n\n        // Next, we will attempt to guess the table name if this the migration has\n        // \"create\" in the name. This will allow us to provide a convenient way\n        // of creating migrations that create new tables for the application.\n        if (! $table) {\n            [$table, $create] = TableGuesser::guess($name);\n        }\n\n        // Now we are ready to write the migration out to disk. Once we've written\n        // the migration out, we will dump-autoload for the entire framework to\n        // make sure that the migrations are registered by the class loaders.\n        $this->writeMigration($name, $table, $create);\n\n        $this->composer->dumpAutoloads();\n    }\n\n    /**\n     * Write the migration file to disk.\n     *\n     * @param  string  $name\n     * @param  string  $table\n     * @param  bool  $create\n     * @return string\n     */\n    protected function writeMigration($name, $table, $create)\n    {\n        $file = $this->creator->create(\n            $name, $this->getMigrationPath(), $table, $create\n        );\n\n        if (! $this->option('fullpath')) {\n            $file = pathinfo($file, PATHINFO_FILENAME);\n        }\n\n        $this->line(\"<info>Created Migration:</info> {$file}\");\n    }\n\n    /**\n     * Get migration path (either specified by '--path' option or default location).\n     *\n     * @return string\n     */\n    protected function getMigrationPath()\n    {\n        if (! is_null($targetPath = $this->input->getOption('path'))) {\n            return ! $this->usingRealPath()\n                            ? $this->laravel->basePath().'/'.$targetPath\n                            : $targetPath;\n        }\n\n        return parent::getMigrationPath();\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Console/Migrations/RefreshCommand.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Console\\Migrations;\n\nuse Illuminate\\Console\\Command;\nuse Illuminate\\Console\\ConfirmableTrait;\nuse Illuminate\\Contracts\\Events\\Dispatcher;\nuse Illuminate\\Database\\Events\\DatabaseRefreshed;\nuse Symfony\\Component\\Console\\Input\\InputOption;\n\nclass RefreshCommand extends Command\n{\n    use ConfirmableTrait;\n\n    /**\n     * The console command name.\n     *\n     * @var string\n     */\n    protected $name = 'migrate:refresh';\n\n    /**\n     * The console command description.\n     *\n     * @var string\n     */\n    protected $description = 'Reset and re-run all migrations';\n\n    /**\n     * Execute the console command.\n     *\n     * @return int\n     */\n    public function handle()\n    {\n        if (! $this->confirmToProceed()) {\n            return 1;\n        }\n\n        // Next we'll gather some of the options so that we can have the right options\n        // to pass to the commands. This includes options such as which database to\n        // use and the path to use for the migration. Then we'll run the command.\n        $database = $this->input->getOption('database');\n\n        $path = $this->input->getOption('path');\n\n        // If the \"step\" option is specified it means we only want to rollback a small\n        // number of migrations before migrating again. For example, the user might\n        // only rollback and remigrate the latest four migrations instead of all.\n        $step = $this->input->getOption('step') ?: 0;\n\n        if ($step > 0) {\n            $this->runRollback($database, $path, $step);\n        } else {\n            $this->runReset($database, $path);\n        }\n\n        // The refresh command is essentially just a brief aggregate of a few other of\n        // the migration commands and just provides a convenient wrapper to execute\n        // them in succession. We'll also see if we need to re-seed the database.\n        $this->call('migrate', array_filter([\n            '--database' => $database,\n            '--path' => $path,\n            '--realpath' => $this->input->getOption('realpath'),\n            '--force' => true,\n        ]));\n\n        if ($this->laravel->bound(Dispatcher::class)) {\n            $this->laravel[Dispatcher::class]->dispatch(\n                new DatabaseRefreshed\n            );\n        }\n\n        if ($this->needsSeeding()) {\n            $this->runSeeder($database);\n        }\n\n        return 0;\n    }\n\n    /**\n     * Run the rollback command.\n     *\n     * @param  string  $database\n     * @param  string  $path\n     * @param  int  $step\n     * @return void\n     */\n    protected function runRollback($database, $path, $step)\n    {\n        $this->call('migrate:rollback', array_filter([\n            '--database' => $database,\n            '--path' => $path,\n            '--realpath' => $this->input->getOption('realpath'),\n            '--step' => $step,\n            '--force' => true,\n        ]));\n    }\n\n    /**\n     * Run the reset command.\n     *\n     * @param  string  $database\n     * @param  string  $path\n     * @return void\n     */\n    protected function runReset($database, $path)\n    {\n        $this->call('migrate:reset', array_filter([\n            '--database' => $database,\n            '--path' => $path,\n            '--realpath' => $this->input->getOption('realpath'),\n            '--force' => true,\n        ]));\n    }\n\n    /**\n     * Determine if the developer has requested database seeding.\n     *\n     * @return bool\n     */\n    protected function needsSeeding()\n    {\n        return $this->option('seed') || $this->option('seeder');\n    }\n\n    /**\n     * Run the database seeder command.\n     *\n     * @param  string  $database\n     * @return void\n     */\n    protected function runSeeder($database)\n    {\n        $this->call('db:seed', array_filter([\n            '--database' => $database,\n            '--class' => $this->option('seeder') ?: 'Database\\\\Seeders\\\\DatabaseSeeder',\n            '--force' => true,\n        ]));\n    }\n\n    /**\n     * Get the console command options.\n     *\n     * @return array\n     */\n    protected function getOptions()\n    {\n        return [\n            ['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to use'],\n            ['force', null, InputOption::VALUE_NONE, 'Force the operation to run when in production'],\n            ['path', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'The path(s) to the migrations files to be executed'],\n            ['realpath', null, InputOption::VALUE_NONE, 'Indicate any provided migration file paths are pre-resolved absolute paths'],\n            ['seed', null, InputOption::VALUE_NONE, 'Indicates if the seed task should be re-run'],\n            ['seeder', null, InputOption::VALUE_OPTIONAL, 'The class name of the root seeder'],\n            ['step', null, InputOption::VALUE_OPTIONAL, 'The number of migrations to be reverted & re-run'],\n        ];\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Console/Migrations/ResetCommand.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Console\\Migrations;\n\nuse Illuminate\\Console\\ConfirmableTrait;\nuse Illuminate\\Database\\Migrations\\Migrator;\nuse Symfony\\Component\\Console\\Input\\InputOption;\n\nclass ResetCommand extends BaseCommand\n{\n    use ConfirmableTrait;\n\n    /**\n     * The console command name.\n     *\n     * @var string\n     */\n    protected $name = 'migrate:reset';\n\n    /**\n     * The console command description.\n     *\n     * @var string\n     */\n    protected $description = 'Rollback all database migrations';\n\n    /**\n     * The migrator instance.\n     *\n     * @var \\Illuminate\\Database\\Migrations\\Migrator\n     */\n    protected $migrator;\n\n    /**\n     * Create a new migration rollback command instance.\n     *\n     * @param  \\Illuminate\\Database\\Migrations\\Migrator  $migrator\n     * @return void\n     */\n    public function __construct(Migrator $migrator)\n    {\n        parent::__construct();\n\n        $this->migrator = $migrator;\n    }\n\n    /**\n     * Execute the console command.\n     *\n     * @return int\n     */\n    public function handle()\n    {\n        if (! $this->confirmToProceed()) {\n            return 1;\n        }\n\n        return $this->migrator->usingConnection($this->option('database'), function () {\n            // First, we'll make sure that the migration table actually exists before we\n            // start trying to rollback and re-run all of the migrations. If it's not\n            // present we'll just bail out with an info message for the developers.\n            if (! $this->migrator->repositoryExists()) {\n                return $this->comment('Migration table not found.');\n            }\n\n            $this->migrator->setOutput($this->output)->reset(\n                $this->getMigrationPaths(), $this->option('pretend')\n            );\n        });\n    }\n\n    /**\n     * Get the console command options.\n     *\n     * @return array\n     */\n    protected function getOptions()\n    {\n        return [\n            ['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to use'],\n\n            ['force', null, InputOption::VALUE_NONE, 'Force the operation to run when in production'],\n\n            ['path', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'The path(s) to the migrations files to be executed'],\n\n            ['realpath', null, InputOption::VALUE_NONE, 'Indicate any provided migration file paths are pre-resolved absolute paths'],\n\n            ['pretend', null, InputOption::VALUE_NONE, 'Dump the SQL queries that would be run'],\n        ];\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Console/Migrations/RollbackCommand.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Console\\Migrations;\n\nuse Illuminate\\Console\\ConfirmableTrait;\nuse Illuminate\\Database\\Migrations\\Migrator;\nuse Symfony\\Component\\Console\\Input\\InputOption;\n\nclass RollbackCommand extends BaseCommand\n{\n    use ConfirmableTrait;\n\n    /**\n     * The console command name.\n     *\n     * @var string\n     */\n    protected $name = 'migrate:rollback';\n\n    /**\n     * The console command description.\n     *\n     * @var string\n     */\n    protected $description = 'Rollback the last database migration';\n\n    /**\n     * The migrator instance.\n     *\n     * @var \\Illuminate\\Database\\Migrations\\Migrator\n     */\n    protected $migrator;\n\n    /**\n     * Create a new migration rollback command instance.\n     *\n     * @param  \\Illuminate\\Database\\Migrations\\Migrator  $migrator\n     * @return void\n     */\n    public function __construct(Migrator $migrator)\n    {\n        parent::__construct();\n\n        $this->migrator = $migrator;\n    }\n\n    /**\n     * Execute the console command.\n     *\n     * @return int\n     */\n    public function handle()\n    {\n        if (! $this->confirmToProceed()) {\n            return 1;\n        }\n\n        $this->migrator->usingConnection($this->option('database'), function () {\n            $this->migrator->setOutput($this->output)->rollback(\n                $this->getMigrationPaths(), [\n                    'pretend' => $this->option('pretend'),\n                    'step' => (int) $this->option('step'),\n                ]\n            );\n        });\n\n        return 0;\n    }\n\n    /**\n     * Get the console command options.\n     *\n     * @return array\n     */\n    protected function getOptions()\n    {\n        return [\n            ['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to use'],\n\n            ['force', null, InputOption::VALUE_NONE, 'Force the operation to run when in production'],\n\n            ['path', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'The path(s) to the migrations files to be executed'],\n\n            ['realpath', null, InputOption::VALUE_NONE, 'Indicate any provided migration file paths are pre-resolved absolute paths'],\n\n            ['pretend', null, InputOption::VALUE_NONE, 'Dump the SQL queries that would be run'],\n\n            ['step', null, InputOption::VALUE_OPTIONAL, 'The number of migrations to be reverted'],\n        ];\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Console/Migrations/StatusCommand.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Console\\Migrations;\n\nuse Illuminate\\Database\\Migrations\\Migrator;\nuse Illuminate\\Support\\Collection;\nuse Symfony\\Component\\Console\\Input\\InputOption;\n\nclass StatusCommand extends BaseCommand\n{\n    /**\n     * The console command name.\n     *\n     * @var string\n     */\n    protected $name = 'migrate:status';\n\n    /**\n     * The console command description.\n     *\n     * @var string\n     */\n    protected $description = 'Show the status of each migration';\n\n    /**\n     * The migrator instance.\n     *\n     * @var \\Illuminate\\Database\\Migrations\\Migrator\n     */\n    protected $migrator;\n\n    /**\n     * Create a new migration rollback command instance.\n     *\n     * @param  \\Illuminate\\Database\\Migrations\\Migrator  $migrator\n     * @return void\n     */\n    public function __construct(Migrator $migrator)\n    {\n        parent::__construct();\n\n        $this->migrator = $migrator;\n    }\n\n    /**\n     * Execute the console command.\n     *\n     * @return int|null\n     */\n    public function handle()\n    {\n        return $this->migrator->usingConnection($this->option('database'), function () {\n            if (! $this->migrator->repositoryExists()) {\n                $this->error('Migration table not found.');\n\n                return 1;\n            }\n\n            $ran = $this->migrator->getRepository()->getRan();\n\n            $batches = $this->migrator->getRepository()->getMigrationBatches();\n\n            if (count($migrations = $this->getStatusFor($ran, $batches)) > 0) {\n                $this->table(['Ran?', 'Migration', 'Batch'], $migrations);\n            } else {\n                $this->error('No migrations found');\n            }\n        });\n    }\n\n    /**\n     * Get the status for the given ran migrations.\n     *\n     * @param  array  $ran\n     * @param  array  $batches\n     * @return \\Illuminate\\Support\\Collection\n     */\n    protected function getStatusFor(array $ran, array $batches)\n    {\n        return Collection::make($this->getAllMigrationFiles())\n                    ->map(function ($migration) use ($ran, $batches) {\n                        $migrationName = $this->migrator->getMigrationName($migration);\n\n                        return in_array($migrationName, $ran)\n                                ? ['<info>Yes</info>', $migrationName, $batches[$migrationName]]\n                                : ['<fg=red>No</fg=red>', $migrationName];\n                    });\n    }\n\n    /**\n     * Get an array of all of the migration files.\n     *\n     * @return array\n     */\n    protected function getAllMigrationFiles()\n    {\n        return $this->migrator->getMigrationFiles($this->getMigrationPaths());\n    }\n\n    /**\n     * Get the console command options.\n     *\n     * @return array\n     */\n    protected function getOptions()\n    {\n        return [\n            ['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to use'],\n\n            ['path', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'The path(s) to the migrations files to use'],\n\n            ['realpath', null, InputOption::VALUE_NONE, 'Indicate any provided migration file paths are pre-resolved absolute paths'],\n        ];\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Console/Migrations/TableGuesser.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Console\\Migrations;\n\nclass TableGuesser\n{\n    const CREATE_PATTERNS = [\n        '/^create_(\\w+)_table$/',\n        '/^create_(\\w+)$/',\n    ];\n\n    const CHANGE_PATTERNS = [\n        '/_(to|from|in)_(\\w+)_table$/',\n        '/_(to|from|in)_(\\w+)$/',\n    ];\n\n    /**\n     * Attempt to guess the table name and \"creation\" status of the given migration.\n     *\n     * @param  string  $migration\n     * @return array\n     */\n    public static function guess($migration)\n    {\n        foreach (self::CREATE_PATTERNS as $pattern) {\n            if (preg_match($pattern, $migration, $matches)) {\n                return [$matches[1], $create = true];\n            }\n        }\n\n        foreach (self::CHANGE_PATTERNS as $pattern) {\n            if (preg_match($pattern, $migration, $matches)) {\n                return [$matches[2], $create = false];\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Console/PruneCommand.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Console;\n\nuse Illuminate\\Console\\Command;\nuse Illuminate\\Contracts\\Events\\Dispatcher;\nuse Illuminate\\Database\\Eloquent\\MassPrunable;\nuse Illuminate\\Database\\Eloquent\\Prunable;\nuse Illuminate\\Database\\Eloquent\\SoftDeletes;\nuse Illuminate\\Database\\Events\\ModelsPruned;\nuse Illuminate\\Support\\Str;\nuse InvalidArgumentException;\nuse Symfony\\Component\\Finder\\Finder;\n\nclass PruneCommand extends Command\n{\n    /**\n     * The console command name.\n     *\n     * @var string\n     */\n    protected $signature = 'model:prune\n                                {--model=* : Class names of the models to be pruned}\n                                {--except=* : Class names of the models to be excluded from pruning}\n                                {--chunk=1000 : The number of models to retrieve per chunk of models to be deleted}\n                                {--pretend : Display the number of prunable records found instead of deleting them}';\n\n    /**\n     * The console command description.\n     *\n     * @var string\n     */\n    protected $description = 'Prune models that are no longer needed';\n\n    /**\n     * Execute the console command.\n     *\n     * @param  \\Illuminate\\Contracts\\Events\\Dispatcher  $events\n     * @return void\n     */\n    public function handle(Dispatcher $events)\n    {\n        $models = $this->models();\n\n        if ($models->isEmpty()) {\n            $this->info('No prunable models found.');\n\n            return;\n        }\n\n        if ($this->option('pretend')) {\n            $models->each(function ($model) {\n                $this->pretendToPrune($model);\n            });\n\n            return;\n        }\n\n        $events->listen(ModelsPruned::class, function ($event) {\n            $this->info(\"{$event->count} [{$event->model}] records have been pruned.\");\n        });\n\n        $models->each(function ($model) {\n            $instance = new $model;\n\n            $chunkSize = property_exists($instance, 'prunableChunkSize')\n                            ? $instance->prunableChunkSize\n                            : $this->option('chunk');\n\n            $total = $this->isPrunable($model)\n                        ? $instance->pruneAll($chunkSize)\n                        : 0;\n\n            if ($total == 0) {\n                $this->info(\"No prunable [$model] records found.\");\n            }\n        });\n\n        $events->forget(ModelsPruned::class);\n    }\n\n    /**\n     * Determine the models that should be pruned.\n     *\n     * @return \\Illuminate\\Support\\Collection\n     */\n    protected function models()\n    {\n        if (! empty($models = $this->option('model'))) {\n            return collect($models)->filter(function ($model) {\n                return class_exists($model);\n            })->values();\n        }\n\n        $except = $this->option('except');\n\n        if (! empty($models) && ! empty($except)) {\n            throw new InvalidArgumentException('The --models and --except options cannot be combined.');\n        }\n\n        return collect((new Finder)->in($this->getDefaultPath())->files()->name('*.php'))\n            ->map(function ($model) {\n                $namespace = $this->laravel->getNamespace();\n\n                return $namespace.str_replace(\n                    ['/', '.php'],\n                    ['\\\\', ''],\n                    Str::after($model->getRealPath(), realpath(app_path()).DIRECTORY_SEPARATOR)\n                );\n            })->when(! empty($except), function ($models) use ($except) {\n                return $models->reject(function ($model) use ($except) {\n                    return in_array($model, $except);\n                });\n            })->filter(function ($model) {\n                return $this->isPrunable($model);\n            })->filter(function ($model) {\n                return class_exists($model);\n            })->values();\n    }\n\n    /**\n     * Get the default path where models are located.\n     *\n     * @return string\n     */\n    protected function getDefaultPath()\n    {\n        return app_path('Models');\n    }\n\n    /**\n     * Determine if the given model class is prunable.\n     *\n     * @param  string  $model\n     * @return bool\n     */\n    protected function isPrunable($model)\n    {\n        $uses = class_uses_recursive($model);\n\n        return in_array(Prunable::class, $uses) || in_array(MassPrunable::class, $uses);\n    }\n\n    /**\n     * Display how many models will be pruned.\n     *\n     * @param  string  $model\n     * @return void\n     */\n    protected function pretendToPrune($model)\n    {\n        $instance = new $model;\n\n        $count = $instance->prunable()\n            ->when(in_array(SoftDeletes::class, class_uses_recursive(get_class($instance))), function ($query) {\n                $query->withTrashed();\n            })->count();\n\n        if ($count === 0) {\n            $this->info(\"No prunable [$model] records found.\");\n        } else {\n            $this->info(\"{$count} [{$model}] records will be pruned.\");\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Console/Seeds/SeedCommand.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Console\\Seeds;\n\nuse Illuminate\\Console\\Command;\nuse Illuminate\\Console\\ConfirmableTrait;\nuse Illuminate\\Database\\ConnectionResolverInterface as Resolver;\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Symfony\\Component\\Console\\Input\\InputArgument;\nuse Symfony\\Component\\Console\\Input\\InputOption;\n\nclass SeedCommand extends Command\n{\n    use ConfirmableTrait;\n\n    /**\n     * The console command name.\n     *\n     * @var string\n     */\n    protected $name = 'db:seed';\n\n    /**\n     * The console command description.\n     *\n     * @var string\n     */\n    protected $description = 'Seed the database with records';\n\n    /**\n     * The connection resolver instance.\n     *\n     * @var \\Illuminate\\Database\\ConnectionResolverInterface\n     */\n    protected $resolver;\n\n    /**\n     * Create a new database seed command instance.\n     *\n     * @param  \\Illuminate\\Database\\ConnectionResolverInterface  $resolver\n     * @return void\n     */\n    public function __construct(Resolver $resolver)\n    {\n        parent::__construct();\n\n        $this->resolver = $resolver;\n    }\n\n    /**\n     * Execute the console command.\n     *\n     * @return int\n     */\n    public function handle()\n    {\n        if (! $this->confirmToProceed()) {\n            return 1;\n        }\n\n        $previousConnection = $this->resolver->getDefaultConnection();\n\n        $this->resolver->setDefaultConnection($this->getDatabase());\n\n        Model::unguarded(function () {\n            $this->getSeeder()->__invoke();\n        });\n\n        if ($previousConnection) {\n            $this->resolver->setDefaultConnection($previousConnection);\n        }\n\n        $this->info('Database seeding completed successfully.');\n\n        return 0;\n    }\n\n    /**\n     * Get a seeder instance from the container.\n     *\n     * @return \\Illuminate\\Database\\Seeder\n     */\n    protected function getSeeder()\n    {\n        $class = $this->input->getArgument('class') ?? $this->input->getOption('class');\n\n        if (strpos($class, '\\\\') === false) {\n            $class = 'Database\\\\Seeders\\\\'.$class;\n        }\n\n        if ($class === 'Database\\\\Seeders\\\\DatabaseSeeder' &&\n            ! class_exists($class)) {\n            $class = 'DatabaseSeeder';\n        }\n\n        return $this->laravel->make($class)\n                        ->setContainer($this->laravel)\n                        ->setCommand($this);\n    }\n\n    /**\n     * Get the name of the database connection to use.\n     *\n     * @return string\n     */\n    protected function getDatabase()\n    {\n        $database = $this->input->getOption('database');\n\n        return $database ?: $this->laravel['config']['database.default'];\n    }\n\n    /**\n     * Get the console command arguments.\n     *\n     * @return array\n     */\n    protected function getArguments()\n    {\n        return [\n            ['class', InputArgument::OPTIONAL, 'The class name of the root seeder', null],\n        ];\n    }\n\n    /**\n     * Get the console command options.\n     *\n     * @return array\n     */\n    protected function getOptions()\n    {\n        return [\n            ['class', null, InputOption::VALUE_OPTIONAL, 'The class name of the root seeder', 'Database\\\\Seeders\\\\DatabaseSeeder'],\n            ['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to seed'],\n            ['force', null, InputOption::VALUE_NONE, 'Force the operation to run when in production'],\n        ];\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Console/Seeds/SeederMakeCommand.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Console\\Seeds;\n\nuse Illuminate\\Console\\GeneratorCommand;\n\nclass SeederMakeCommand extends GeneratorCommand\n{\n    /**\n     * The console command name.\n     *\n     * @var string\n     */\n    protected $name = 'make:seeder';\n\n    /**\n     * The console command description.\n     *\n     * @var string\n     */\n    protected $description = 'Create a new seeder class';\n\n    /**\n     * The type of class being generated.\n     *\n     * @var string\n     */\n    protected $type = 'Seeder';\n\n    /**\n     * Execute the console command.\n     *\n     * @return void\n     */\n    public function handle()\n    {\n        parent::handle();\n    }\n\n    /**\n     * Get the stub file for the generator.\n     *\n     * @return string\n     */\n    protected function getStub()\n    {\n        return $this->resolveStubPath('/stubs/seeder.stub');\n    }\n\n    /**\n     * Resolve the fully-qualified path to the stub.\n     *\n     * @param  string  $stub\n     * @return string\n     */\n    protected function resolveStubPath($stub)\n    {\n        return is_file($customPath = $this->laravel->basePath(trim($stub, '/')))\n            ? $customPath\n            : __DIR__.$stub;\n    }\n\n    /**\n     * Get the destination class path.\n     *\n     * @param  string  $name\n     * @return string\n     */\n    protected function getPath($name)\n    {\n        if (is_dir($this->laravel->databasePath().'/seeds')) {\n            return $this->laravel->databasePath().'/seeds/'.$name.'.php';\n        } else {\n            return $this->laravel->databasePath().'/seeders/'.$name.'.php';\n        }\n    }\n\n    /**\n     * Parse the class name and format according to the root namespace.\n     *\n     * @param  string  $name\n     * @return string\n     */\n    protected function qualifyClass($name)\n    {\n        return $name;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Console/Seeds/stubs/seeder.stub",
    "content": "<?php\n\nnamespace Database\\Seeders;\n\nuse Illuminate\\Database\\Seeder;\n\nclass {{ class }} extends Seeder\n{\n    /**\n     * Run the database seeds.\n     *\n     * @return void\n     */\n    public function run()\n    {\n        //\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Console/WipeCommand.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Console;\n\nuse Illuminate\\Console\\Command;\nuse Illuminate\\Console\\ConfirmableTrait;\nuse Symfony\\Component\\Console\\Input\\InputOption;\n\nclass WipeCommand extends Command\n{\n    use ConfirmableTrait;\n\n    /**\n     * The console command name.\n     *\n     * @var string\n     */\n    protected $name = 'db:wipe';\n\n    /**\n     * The console command description.\n     *\n     * @var string\n     */\n    protected $description = 'Drop all tables, views, and types';\n\n    /**\n     * Execute the console command.\n     *\n     * @return int\n     */\n    public function handle()\n    {\n        if (! $this->confirmToProceed()) {\n            return 1;\n        }\n\n        $database = $this->input->getOption('database');\n\n        if ($this->option('drop-views')) {\n            $this->dropAllViews($database);\n\n            $this->info('Dropped all views successfully.');\n        }\n\n        $this->dropAllTables($database);\n\n        $this->info('Dropped all tables successfully.');\n\n        if ($this->option('drop-types')) {\n            $this->dropAllTypes($database);\n\n            $this->info('Dropped all types successfully.');\n        }\n\n        return 0;\n    }\n\n    /**\n     * Drop all of the database tables.\n     *\n     * @param  string  $database\n     * @return void\n     */\n    protected function dropAllTables($database)\n    {\n        $this->laravel['db']->connection($database)\n                    ->getSchemaBuilder()\n                    ->dropAllTables();\n    }\n\n    /**\n     * Drop all of the database views.\n     *\n     * @param  string  $database\n     * @return void\n     */\n    protected function dropAllViews($database)\n    {\n        $this->laravel['db']->connection($database)\n                    ->getSchemaBuilder()\n                    ->dropAllViews();\n    }\n\n    /**\n     * Drop all of the database types.\n     *\n     * @param  string  $database\n     * @return void\n     */\n    protected function dropAllTypes($database)\n    {\n        $this->laravel['db']->connection($database)\n                    ->getSchemaBuilder()\n                    ->dropAllTypes();\n    }\n\n    /**\n     * Get the console command options.\n     *\n     * @return array\n     */\n    protected function getOptions()\n    {\n        return [\n            ['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to use'],\n            ['drop-views', null, InputOption::VALUE_NONE, 'Drop all tables and views'],\n            ['drop-types', null, InputOption::VALUE_NONE, 'Drop all tables and types (Postgres only)'],\n            ['force', null, InputOption::VALUE_NONE, 'Force the operation to run when in production'],\n        ];\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/DBAL/TimestampType.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\DBAL;\n\nuse Doctrine\\DBAL\\Platforms\\AbstractPlatform;\nuse Doctrine\\DBAL\\Types\\PhpDateTimeMappingType;\nuse Doctrine\\DBAL\\Types\\Type;\nuse RuntimeException;\n\nclass TimestampType extends Type implements PhpDateTimeMappingType\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @return string\n     */\n    public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)\n    {\n        $name = $platform->getName();\n\n        switch ($name) {\n            case 'mysql':\n            case 'mysql2':\n                return $this->getMySqlPlatformSQLDeclaration($fieldDeclaration);\n\n            case 'postgresql':\n            case 'pgsql':\n            case 'postgres':\n                return $this->getPostgresPlatformSQLDeclaration($fieldDeclaration);\n\n            case 'mssql':\n                return $this->getSqlServerPlatformSQLDeclaration($fieldDeclaration);\n\n            case 'sqlite':\n            case 'sqlite3':\n                return $this->getSQLitePlatformSQLDeclaration($fieldDeclaration);\n\n            default:\n                throw new RuntimeException('Invalid platform: '.$name);\n        }\n    }\n\n    /**\n     * Get the SQL declaration for MySQL.\n     *\n     * @param  array  $fieldDeclaration\n     * @return string\n     */\n    protected function getMySqlPlatformSQLDeclaration(array $fieldDeclaration)\n    {\n        $columnType = 'TIMESTAMP';\n\n        if ($fieldDeclaration['precision']) {\n            $columnType = 'TIMESTAMP('.$fieldDeclaration['precision'].')';\n        }\n\n        $notNull = $fieldDeclaration['notnull'] ?? false;\n\n        if (! $notNull) {\n            return $columnType.' NULL';\n        }\n\n        return $columnType;\n    }\n\n    /**\n     * Get the SQL declaration for PostgreSQL.\n     *\n     * @param  array  $fieldDeclaration\n     * @return string\n     */\n    protected function getPostgresPlatformSQLDeclaration(array $fieldDeclaration)\n    {\n        return 'TIMESTAMP('.(int) $fieldDeclaration['precision'].')';\n    }\n\n    /**\n     * Get the SQL declaration for SQL Server.\n     *\n     * @param  array  $fieldDeclaration\n     * @return string\n     */\n    protected function getSqlServerPlatformSQLDeclaration(array $fieldDeclaration)\n    {\n        return $fieldDeclaration['precision'] ?? false\n                    ? 'DATETIME2('.$fieldDeclaration['precision'].')'\n                    : 'DATETIME';\n    }\n\n    /**\n     * Get the SQL declaration for SQLite.\n     *\n     * @param  array  $fieldDeclaration\n     * @return string\n     */\n    protected function getSQLitePlatformSQLDeclaration(array $fieldDeclaration)\n    {\n        return 'DATETIME';\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @return string\n     */\n    public function getName()\n    {\n        return 'timestamp';\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/DatabaseManager.php",
    "content": "<?php\n\nnamespace Illuminate\\Database;\n\nuse Doctrine\\DBAL\\Types\\Type;\nuse Illuminate\\Database\\Connectors\\ConnectionFactory;\nuse Illuminate\\Support\\Arr;\nuse Illuminate\\Support\\ConfigurationUrlParser;\nuse Illuminate\\Support\\Str;\nuse InvalidArgumentException;\nuse PDO;\nuse RuntimeException;\n\n/**\n * @mixin \\Illuminate\\Database\\Connection\n */\nclass DatabaseManager implements ConnectionResolverInterface\n{\n    /**\n     * The application instance.\n     *\n     * @var \\Illuminate\\Contracts\\Foundation\\Application\n     */\n    protected $app;\n\n    /**\n     * The database connection factory instance.\n     *\n     * @var \\Illuminate\\Database\\Connectors\\ConnectionFactory\n     */\n    protected $factory;\n\n    /**\n     * The active connection instances.\n     *\n     * @var array\n     */\n    protected $connections = [];\n\n    /**\n     * The custom connection resolvers.\n     *\n     * @var array\n     */\n    protected $extensions = [];\n\n    /**\n     * The callback to be executed to reconnect to a database.\n     *\n     * @var callable\n     */\n    protected $reconnector;\n\n    /**\n     * The custom Doctrine column types.\n     *\n     * @var array\n     */\n    protected $doctrineTypes = [];\n\n    /**\n     * Create a new database manager instance.\n     *\n     * @param  \\Illuminate\\Contracts\\Foundation\\Application  $app\n     * @param  \\Illuminate\\Database\\Connectors\\ConnectionFactory  $factory\n     * @return void\n     */\n    public function __construct($app, ConnectionFactory $factory)\n    {\n        $this->app = $app;\n        $this->factory = $factory;\n\n        $this->reconnector = function ($connection) {\n            $this->reconnect($connection->getNameWithReadWriteType());\n        };\n    }\n\n    /**\n     * Get a database connection instance.\n     *\n     * @param  string|null  $name\n     * @return \\Illuminate\\Database\\Connection\n     */\n    public function connection($name = null)\n    {\n        [$database, $type] = $this->parseConnectionName($name);\n\n        $name = $name ?: $database;\n\n        // If we haven't created this connection, we'll create it based on the config\n        // provided in the application. Once we've created the connections we will\n        // set the \"fetch mode\" for PDO which determines the query return types.\n        if (! isset($this->connections[$name])) {\n            $this->connections[$name] = $this->configure(\n                $this->makeConnection($database), $type\n            );\n        }\n\n        return $this->connections[$name];\n    }\n\n    /**\n     * Parse the connection into an array of the name and read / write type.\n     *\n     * @param  string  $name\n     * @return array\n     */\n    protected function parseConnectionName($name)\n    {\n        $name = $name ?: $this->getDefaultConnection();\n\n        return Str::endsWith($name, ['::read', '::write'])\n                            ? explode('::', $name, 2) : [$name, null];\n    }\n\n    /**\n     * Make the database connection instance.\n     *\n     * @param  string  $name\n     * @return \\Illuminate\\Database\\Connection\n     */\n    protected function makeConnection($name)\n    {\n        $config = $this->configuration($name);\n\n        // First we will check by the connection name to see if an extension has been\n        // registered specifically for that connection. If it has we will call the\n        // Closure and pass it the config allowing it to resolve the connection.\n        if (isset($this->extensions[$name])) {\n            return call_user_func($this->extensions[$name], $config, $name);\n        }\n\n        // Next we will check to see if an extension has been registered for a driver\n        // and will call the Closure if so, which allows us to have a more generic\n        // resolver for the drivers themselves which applies to all connections.\n        if (isset($this->extensions[$driver = $config['driver']])) {\n            return call_user_func($this->extensions[$driver], $config, $name);\n        }\n\n        return $this->factory->make($config, $name);\n    }\n\n    /**\n     * Get the configuration for a connection.\n     *\n     * @param  string  $name\n     * @return array\n     *\n     * @throws \\InvalidArgumentException\n     */\n    protected function configuration($name)\n    {\n        $name = $name ?: $this->getDefaultConnection();\n\n        // To get the database connection configuration, we will just pull each of the\n        // connection configurations and get the configurations for the given name.\n        // If the configuration doesn't exist, we'll throw an exception and bail.\n        $connections = $this->app['config']['database.connections'];\n\n        if (is_null($config = Arr::get($connections, $name))) {\n            throw new InvalidArgumentException(\"Database connection [{$name}] not configured.\");\n        }\n\n        return (new ConfigurationUrlParser)\n                    ->parseConfiguration($config);\n    }\n\n    /**\n     * Prepare the database connection instance.\n     *\n     * @param  \\Illuminate\\Database\\Connection  $connection\n     * @param  string  $type\n     * @return \\Illuminate\\Database\\Connection\n     */\n    protected function configure(Connection $connection, $type)\n    {\n        $connection = $this->setPdoForType($connection, $type)->setReadWriteType($type);\n\n        // First we'll set the fetch mode and a few other dependencies of the database\n        // connection. This method basically just configures and prepares it to get\n        // used by the application. Once we're finished we'll return it back out.\n        if ($this->app->bound('events')) {\n            $connection->setEventDispatcher($this->app['events']);\n        }\n\n        if ($this->app->bound('db.transactions')) {\n            $connection->setTransactionManager($this->app['db.transactions']);\n        }\n\n        // Here we'll set a reconnector callback. This reconnector can be any callable\n        // so we will set a Closure to reconnect from this manager with the name of\n        // the connection, which will allow us to reconnect from the connections.\n        $connection->setReconnector($this->reconnector);\n\n        $this->registerConfiguredDoctrineTypes($connection);\n\n        return $connection;\n    }\n\n    /**\n     * Prepare the read / write mode for database connection instance.\n     *\n     * @param  \\Illuminate\\Database\\Connection  $connection\n     * @param  string|null  $type\n     * @return \\Illuminate\\Database\\Connection\n     */\n    protected function setPdoForType(Connection $connection, $type = null)\n    {\n        if ($type === 'read') {\n            $connection->setPdo($connection->getReadPdo());\n        } elseif ($type === 'write') {\n            $connection->setReadPdo($connection->getPdo());\n        }\n\n        return $connection;\n    }\n\n    /**\n     * Register custom Doctrine types with the connection.\n     *\n     * @param  \\Illuminate\\Database\\Connection  $connection\n     * @return void\n     */\n    protected function registerConfiguredDoctrineTypes(Connection $connection): void\n    {\n        foreach ($this->app['config']->get('database.dbal.types', []) as $name => $class) {\n            $this->registerDoctrineType($class, $name, $name);\n        }\n\n        foreach ($this->doctrineTypes as $name => [$type, $class]) {\n            $connection->registerDoctrineType($class, $name, $type);\n        }\n    }\n\n    /**\n     * Register a custom Doctrine type.\n     *\n     * @param  string  $class\n     * @param  string  $name\n     * @param  string  $type\n     * @return void\n     *\n     * @throws \\Doctrine\\DBAL\\DBALException\n     * @throws \\RuntimeException\n     */\n    public function registerDoctrineType(string $class, string $name, string $type): void\n    {\n        if (! class_exists('Doctrine\\DBAL\\Connection')) {\n            throw new RuntimeException(\n                'Registering a custom Doctrine type requires Doctrine DBAL (doctrine/dbal).'\n            );\n        }\n\n        if (! Type::hasType($name)) {\n            Type::addType($name, $class);\n        }\n\n        $this->doctrineTypes[$name] = [$type, $class];\n    }\n\n    /**\n     * Disconnect from the given database and remove from local cache.\n     *\n     * @param  string|null  $name\n     * @return void\n     */\n    public function purge($name = null)\n    {\n        $name = $name ?: $this->getDefaultConnection();\n\n        $this->disconnect($name);\n\n        unset($this->connections[$name]);\n    }\n\n    /**\n     * Disconnect from the given database.\n     *\n     * @param  string|null  $name\n     * @return void\n     */\n    public function disconnect($name = null)\n    {\n        if (isset($this->connections[$name = $name ?: $this->getDefaultConnection()])) {\n            $this->connections[$name]->disconnect();\n        }\n    }\n\n    /**\n     * Reconnect to the given database.\n     *\n     * @param  string|null  $name\n     * @return \\Illuminate\\Database\\Connection\n     */\n    public function reconnect($name = null)\n    {\n        $this->disconnect($name = $name ?: $this->getDefaultConnection());\n\n        if (! isset($this->connections[$name])) {\n            return $this->connection($name);\n        }\n\n        return $this->refreshPdoConnections($name);\n    }\n\n    /**\n     * Set the default database connection for the callback execution.\n     *\n     * @param  string  $name\n     * @param  callable  $callback\n     * @return mixed\n     */\n    public function usingConnection($name, callable $callback)\n    {\n        $previousName = $this->getDefaultConnection();\n\n        $this->setDefaultConnection($name);\n\n        return tap($callback(), function () use ($previousName) {\n            $this->setDefaultConnection($previousName);\n        });\n    }\n\n    /**\n     * Refresh the PDO connections on a given connection.\n     *\n     * @param  string  $name\n     * @return \\Illuminate\\Database\\Connection\n     */\n    protected function refreshPdoConnections($name)\n    {\n        [$database, $type] = $this->parseConnectionName($name);\n\n        $fresh = $this->configure(\n            $this->makeConnection($database), $type\n        );\n\n        return $this->connections[$name]\n                    ->setPdo($fresh->getRawPdo())\n                    ->setReadPdo($fresh->getRawReadPdo());\n    }\n\n    /**\n     * Get the default connection name.\n     *\n     * @return string\n     */\n    public function getDefaultConnection()\n    {\n        return $this->app['config']['database.default'];\n    }\n\n    /**\n     * Set the default connection name.\n     *\n     * @param  string  $name\n     * @return void\n     */\n    public function setDefaultConnection($name)\n    {\n        $this->app['config']['database.default'] = $name;\n    }\n\n    /**\n     * Get all of the support drivers.\n     *\n     * @return array\n     */\n    public function supportedDrivers()\n    {\n        return ['mysql', 'pgsql', 'sqlite', 'sqlsrv'];\n    }\n\n    /**\n     * Get all of the drivers that are actually available.\n     *\n     * @return array\n     */\n    public function availableDrivers()\n    {\n        return array_intersect(\n            $this->supportedDrivers(),\n            str_replace('dblib', 'sqlsrv', PDO::getAvailableDrivers())\n        );\n    }\n\n    /**\n     * Register an extension connection resolver.\n     *\n     * @param  string  $name\n     * @param  callable  $resolver\n     * @return void\n     */\n    public function extend($name, callable $resolver)\n    {\n        $this->extensions[$name] = $resolver;\n    }\n\n    /**\n     * Return all of the created connections.\n     *\n     * @return array\n     */\n    public function getConnections()\n    {\n        return $this->connections;\n    }\n\n    /**\n     * Set the database reconnector callback.\n     *\n     * @param  callable  $reconnector\n     * @return void\n     */\n    public function setReconnector(callable $reconnector)\n    {\n        $this->reconnector = $reconnector;\n    }\n\n    /**\n     * Set the application instance used by the manager.\n     *\n     * @param  \\Illuminate\\Contracts\\Foundation\\Application  $app\n     * @return $this\n     */\n    public function setApplication($app)\n    {\n        $this->app = $app;\n\n        return $this;\n    }\n\n    /**\n     * Dynamically pass methods to the default connection.\n     *\n     * @param  string  $method\n     * @param  array  $parameters\n     * @return mixed\n     */\n    public function __call($method, $parameters)\n    {\n        return $this->connection()->$method(...$parameters);\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/DatabaseServiceProvider.php",
    "content": "<?php\n\nnamespace Illuminate\\Database;\n\nuse Faker\\Factory as FakerFactory;\nuse Faker\\Generator as FakerGenerator;\nuse Illuminate\\Contracts\\Queue\\EntityResolver;\nuse Illuminate\\Database\\Connectors\\ConnectionFactory;\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Database\\Eloquent\\QueueEntityResolver;\nuse Illuminate\\Support\\ServiceProvider;\n\nclass DatabaseServiceProvider extends ServiceProvider\n{\n    /**\n     * The array of resolved Faker instances.\n     *\n     * @var array\n     */\n    protected static $fakers = [];\n\n    /**\n     * Bootstrap the application events.\n     *\n     * @return void\n     */\n    public function boot()\n    {\n        Model::setConnectionResolver($this->app['db']);\n\n        Model::setEventDispatcher($this->app['events']);\n    }\n\n    /**\n     * Register the service provider.\n     *\n     * @return void\n     */\n    public function register()\n    {\n        Model::clearBootedModels();\n\n        $this->registerConnectionServices();\n        $this->registerEloquentFactory();\n        $this->registerQueueableEntityResolver();\n    }\n\n    /**\n     * Register the primary database bindings.\n     *\n     * @return void\n     */\n    protected function registerConnectionServices()\n    {\n        // The connection factory is used to create the actual connection instances on\n        // the database. We will inject the factory into the manager so that it may\n        // make the connections while they are actually needed and not of before.\n        $this->app->singleton('db.factory', function ($app) {\n            return new ConnectionFactory($app);\n        });\n\n        // The database manager is used to resolve various connections, since multiple\n        // connections might be managed. It also implements the connection resolver\n        // interface which may be used by other components requiring connections.\n        $this->app->singleton('db', function ($app) {\n            return new DatabaseManager($app, $app['db.factory']);\n        });\n\n        $this->app->bind('db.connection', function ($app) {\n            return $app['db']->connection();\n        });\n\n        $this->app->singleton('db.transactions', function ($app) {\n            return new DatabaseTransactionsManager;\n        });\n    }\n\n    /**\n     * Register the Eloquent factory instance in the container.\n     *\n     * @return void\n     */\n    protected function registerEloquentFactory()\n    {\n        $this->app->singleton(FakerGenerator::class, function ($app, $parameters) {\n            $locale = $parameters['locale'] ?? $app['config']->get('app.faker_locale', 'en_US');\n\n            if (! isset(static::$fakers[$locale])) {\n                static::$fakers[$locale] = FakerFactory::create($locale);\n            }\n\n            static::$fakers[$locale]->unique(true);\n\n            return static::$fakers[$locale];\n        });\n    }\n\n    /**\n     * Register the queueable entity resolver implementation.\n     *\n     * @return void\n     */\n    protected function registerQueueableEntityResolver()\n    {\n        $this->app->singleton(EntityResolver::class, function () {\n            return new QueueEntityResolver;\n        });\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/DatabaseTransactionRecord.php",
    "content": "<?php\n\nnamespace Illuminate\\Database;\n\nclass DatabaseTransactionRecord\n{\n    /**\n     * The name of the database connection.\n     *\n     * @var string\n     */\n    public $connection;\n\n    /**\n     * The transaction level.\n     *\n     * @var int\n     */\n    public $level;\n\n    /**\n     * The callbacks that should be executed after committing.\n     *\n     * @var array\n     */\n    protected $callbacks = [];\n\n    /**\n     * Create a new database transaction record instance.\n     *\n     * @param  string  $connection\n     * @param  int  $level\n     * @return void\n     */\n    public function __construct($connection, $level)\n    {\n        $this->connection = $connection;\n        $this->level = $level;\n    }\n\n    /**\n     * Register a callback to be executed after committing.\n     *\n     * @param  callable  $callback\n     * @return void\n     */\n    public function addCallback($callback)\n    {\n        $this->callbacks[] = $callback;\n    }\n\n    /**\n     * Execute all of the callbacks.\n     *\n     * @return void\n     */\n    public function executeCallbacks()\n    {\n        foreach ($this->callbacks as $callback) {\n            call_user_func($callback);\n        }\n    }\n\n    /**\n     * Get all of the callbacks.\n     *\n     * @return array\n     */\n    public function getCallbacks()\n    {\n        return $this->callbacks;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/DatabaseTransactionsManager.php",
    "content": "<?php\n\nnamespace Illuminate\\Database;\n\nclass DatabaseTransactionsManager\n{\n    /**\n     * All of the recorded transactions.\n     *\n     * @var \\Illuminate\\Support\\Collection\n     */\n    protected $transactions;\n\n    /**\n     * Create a new database transactions manager instance.\n     *\n     * @return void\n     */\n    public function __construct()\n    {\n        $this->transactions = collect();\n    }\n\n    /**\n     * Start a new database transaction.\n     *\n     * @param  string  $connection\n     * @param  int  $level\n     * @return void\n     */\n    public function begin($connection, $level)\n    {\n        $this->transactions->push(\n            new DatabaseTransactionRecord($connection, $level)\n        );\n    }\n\n    /**\n     * Rollback the active database transaction.\n     *\n     * @param  string  $connection\n     * @param  int  $level\n     * @return void\n     */\n    public function rollback($connection, $level)\n    {\n        $this->transactions = $this->transactions->reject(function ($transaction) use ($connection, $level) {\n            return $transaction->connection == $connection &&\n                   $transaction->level > $level;\n        })->values();\n    }\n\n    /**\n     * Commit the active database transaction.\n     *\n     * @param  string  $connection\n     * @return void\n     */\n    public function commit($connection)\n    {\n        [$forThisConnection, $forOtherConnections] = $this->transactions->partition(\n            function ($transaction) use ($connection) {\n                return $transaction->connection == $connection;\n            }\n        );\n\n        $this->transactions = $forOtherConnections->values();\n\n        $forThisConnection->map->executeCallbacks();\n    }\n\n    /**\n     * Register a transaction callback.\n     *\n     * @param  callable  $callback\n     * @return void\n     */\n    public function addCallback($callback)\n    {\n        if ($current = $this->transactions->last()) {\n            return $current->addCallback($callback);\n        }\n\n        call_user_func($callback);\n    }\n\n    /**\n     * Get all the transactions.\n     *\n     * @return \\Illuminate\\Support\\Collection\n     */\n    public function getTransactions()\n    {\n        return $this->transactions;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/DetectsConcurrencyErrors.php",
    "content": "<?php\n\nnamespace Illuminate\\Database;\n\nuse Illuminate\\Support\\Str;\nuse PDOException;\nuse Throwable;\n\ntrait DetectsConcurrencyErrors\n{\n    /**\n     * Determine if the given exception was caused by a concurrency error such as a deadlock or serialization failure.\n     *\n     * @param  \\Throwable  $e\n     * @return bool\n     */\n    protected function causedByConcurrencyError(Throwable $e)\n    {\n        if ($e instanceof PDOException && ($e->getCode() === 40001 || $e->getCode() === '40001')) {\n            return true;\n        }\n\n        $message = $e->getMessage();\n\n        return Str::contains($message, [\n            'Deadlock found when trying to get lock',\n            'deadlock detected',\n            'The database file is locked',\n            'database is locked',\n            'database table is locked',\n            'A table in the database is locked',\n            'has been chosen as the deadlock victim',\n            'Lock wait timeout exceeded; try restarting transaction',\n            'WSREP detected deadlock/conflict and aborted the transaction. Try restarting the transaction',\n        ]);\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/DetectsLostConnections.php",
    "content": "<?php\n\nnamespace Illuminate\\Database;\n\nuse Illuminate\\Support\\Str;\nuse Throwable;\n\ntrait DetectsLostConnections\n{\n    /**\n     * Determine if the given exception was caused by a lost connection.\n     *\n     * @param  \\Throwable  $e\n     * @return bool\n     */\n    protected function causedByLostConnection(Throwable $e)\n    {\n        $message = $e->getMessage();\n\n        return Str::contains($message, [\n            'server has gone away',\n            'no connection to the server',\n            'Lost connection',\n            'is dead or not enabled',\n            'Error while sending',\n            'decryption failed or bad record mac',\n            'server closed the connection unexpectedly',\n            'SSL connection has been closed unexpectedly',\n            'Error writing data to the connection',\n            'Resource deadlock avoided',\n            'Transaction() on null',\n            'child connection forced to terminate due to client_idle_limit',\n            'query_wait_timeout',\n            'reset by peer',\n            'Physical connection is not usable',\n            'TCP Provider: Error code 0x68',\n            'ORA-03114',\n            'Packets out of order. Expected',\n            'Adaptive Server connection failed',\n            'Communication link failure',\n            'connection is no longer usable',\n            'Login timeout expired',\n            'SQLSTATE[HY000] [2002] Connection refused',\n            'running with the --read-only option so it cannot execute this statement',\n            'The connection is broken and recovery is not possible. The connection is marked by the client driver as unrecoverable. No attempt was made to restore the connection.',\n            'SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed: Try again',\n            'SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed: Name or service not known',\n            'SQLSTATE[HY000]: General error: 7 SSL SYSCALL error: EOF detected',\n            'SQLSTATE[HY000] [2002] Connection timed out',\n            'SSL: Connection timed out',\n            'SQLSTATE[HY000]: General error: 1105 The last transaction was aborted due to Seamless Scaling. Please retry.',\n            'Temporary failure in name resolution',\n            'SSL: Broken pipe',\n            'SQLSTATE[08S01]: Communication link failure',\n            'SQLSTATE[08006] [7] could not connect to server: Connection refused Is the server running on host',\n            'SQLSTATE[HY000]: General error: 7 SSL SYSCALL error: No route to host',\n            'The client was disconnected by the server because of inactivity. See wait_timeout and interactive_timeout for configuring this behavior.',\n            'SQLSTATE[08006] [7] could not translate host name',\n            'TCP Provider: Error code 0x274C',\n        ]);\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/BroadcastableModelEventOccurred.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent;\n\nuse Illuminate\\Broadcasting\\InteractsWithSockets;\nuse Illuminate\\Broadcasting\\PrivateChannel;\nuse Illuminate\\Contracts\\Broadcasting\\ShouldBroadcast;\nuse Illuminate\\Queue\\SerializesModels;\n\nclass BroadcastableModelEventOccurred implements ShouldBroadcast\n{\n    use InteractsWithSockets, SerializesModels;\n\n    /**\n     * The model instance corresponding to the event.\n     *\n     * @var \\Illuminate\\Database\\Eloquent\\Model\n     */\n    public $model;\n\n    /**\n     * The event name (created, updated, etc.).\n     *\n     * @var string\n     */\n    protected $event;\n\n    /**\n     * The channels that the event should be broadcast on.\n     *\n     * @var array\n     */\n    protected $channels = [];\n\n    /**\n     * The queue connection that should be used to queue the broadcast job.\n     *\n     * @var string\n     */\n    public $connection;\n\n    /**\n     * The queue that should be used to queue the broadcast job.\n     *\n     * @var string\n     */\n    public $queue;\n\n    /**\n     * Create a new event instance.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $model\n     * @param  string  $event\n     * @return void\n     */\n    public function __construct($model, $event)\n    {\n        $this->model = $model;\n        $this->event = $event;\n    }\n\n    /**\n     * The channels the event should broadcast on.\n     *\n     * @return array\n     */\n    public function broadcastOn()\n    {\n        $channels = empty($this->channels)\n                ? ($this->model->broadcastOn($this->event) ?: [])\n                : $this->channels;\n\n        return collect($channels)->map(function ($channel) {\n            return $channel instanceof Model ? new PrivateChannel($channel) : $channel;\n        })->all();\n    }\n\n    /**\n     * The name the event should broadcast as.\n     *\n     * @return string\n     */\n    public function broadcastAs()\n    {\n        $default = class_basename($this->model).ucfirst($this->event);\n\n        return method_exists($this->model, 'broadcastAs')\n                ? ($this->model->broadcastAs($this->event) ?: $default)\n                : $default;\n    }\n\n    /**\n     * Get the data that should be sent with the broadcasted event.\n     *\n     * @return array|null\n     */\n    public function broadcastWith()\n    {\n        return method_exists($this->model, 'broadcastWith')\n            ? $this->model->broadcastWith($this->event)\n            : null;\n    }\n\n    /**\n     * Manually specify the channels the event should broadcast on.\n     *\n     * @param  array  $channels\n     * @return $this\n     */\n    public function onChannels(array $channels)\n    {\n        $this->channels = $channels;\n\n        return $this;\n    }\n\n    /**\n     * Determine if the event should be broadcast synchronously.\n     *\n     * @return bool\n     */\n    public function shouldBroadcastNow()\n    {\n        return $this->event === 'deleted' &&\n               ! method_exists($this->model, 'bootSoftDeletes');\n    }\n\n    /**\n     * Get the event name.\n     *\n     * @return string\n     */\n    public function event()\n    {\n        return $this->event;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/BroadcastsEvents.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent;\n\nuse Illuminate\\Support\\Arr;\n\ntrait BroadcastsEvents\n{\n    /**\n     * Boot the event broadcasting trait.\n     *\n     * @return void\n     */\n    public static function bootBroadcastsEvents()\n    {\n        static::created(function ($model) {\n            $model->broadcastCreated();\n        });\n\n        static::updated(function ($model) {\n            $model->broadcastUpdated();\n        });\n\n        if (method_exists(static::class, 'bootSoftDeletes')) {\n            static::softDeleted(function ($model) {\n                $model->broadcastTrashed();\n            });\n\n            static::restored(function ($model) {\n                $model->broadcastRestored();\n            });\n        }\n\n        static::deleted(function ($model) {\n            $model->broadcastDeleted();\n        });\n    }\n\n    /**\n     * Broadcast that the model was created.\n     *\n     * @param  \\Illuminate\\Broadcasting\\Channel|\\Illuminate\\Contracts\\Broadcasting\\HasBroadcastChannel|array|null  $channels\n     * @return \\Illuminate\\Broadcasting\\PendingBroadcast\n     */\n    public function broadcastCreated($channels = null)\n    {\n        return $this->broadcastIfBroadcastChannelsExistForEvent(\n            $this->newBroadcastableModelEvent('created'), 'created', $channels\n        );\n    }\n\n    /**\n     * Broadcast that the model was updated.\n     *\n     * @param  \\Illuminate\\Broadcasting\\Channel|\\Illuminate\\Contracts\\Broadcasting\\HasBroadcastChannel|array|null  $channels\n     * @return \\Illuminate\\Broadcasting\\PendingBroadcast\n     */\n    public function broadcastUpdated($channels = null)\n    {\n        return $this->broadcastIfBroadcastChannelsExistForEvent(\n            $this->newBroadcastableModelEvent('updated'), 'updated', $channels\n        );\n    }\n\n    /**\n     * Broadcast that the model was trashed.\n     *\n     * @param  \\Illuminate\\Broadcasting\\Channel|\\Illuminate\\Contracts\\Broadcasting\\HasBroadcastChannel|array|null  $channels\n     * @return \\Illuminate\\Broadcasting\\PendingBroadcast\n     */\n    public function broadcastTrashed($channels = null)\n    {\n        return $this->broadcastIfBroadcastChannelsExistForEvent(\n            $this->newBroadcastableModelEvent('trashed'), 'trashed', $channels\n        );\n    }\n\n    /**\n     * Broadcast that the model was restored.\n     *\n     * @param  \\Illuminate\\Broadcasting\\Channel|\\Illuminate\\Contracts\\Broadcasting\\HasBroadcastChannel|array|null  $channels\n     * @return \\Illuminate\\Broadcasting\\PendingBroadcast\n     */\n    public function broadcastRestored($channels = null)\n    {\n        return $this->broadcastIfBroadcastChannelsExistForEvent(\n            $this->newBroadcastableModelEvent('restored'), 'restored', $channels\n        );\n    }\n\n    /**\n     * Broadcast that the model was deleted.\n     *\n     * @param  \\Illuminate\\Broadcasting\\Channel|\\Illuminate\\Contracts\\Broadcasting\\HasBroadcastChannel|array|null  $channels\n     * @return \\Illuminate\\Broadcasting\\PendingBroadcast\n     */\n    public function broadcastDeleted($channels = null)\n    {\n        return $this->broadcastIfBroadcastChannelsExistForEvent(\n            $this->newBroadcastableModelEvent('deleted'), 'deleted', $channels\n        );\n    }\n\n    /**\n     * Broadcast the given event instance if channels are configured for the model event.\n     *\n     * @param  mixed  $instance\n     * @param  string  $event\n     * @param  mixed  $channels\n     * @return \\Illuminate\\Broadcasting\\PendingBroadcast|null\n     */\n    protected function broadcastIfBroadcastChannelsExistForEvent($instance, $event, $channels = null)\n    {\n        if (! static::$isBroadcasting) {\n            return;\n        }\n\n        if (! empty($this->broadcastOn($event)) || ! empty($channels)) {\n            return broadcast($instance->onChannels(Arr::wrap($channels)));\n        }\n    }\n\n    /**\n     * Create a new broadcastable model event event.\n     *\n     * @param  string  $event\n     * @return mixed\n     */\n    public function newBroadcastableModelEvent($event)\n    {\n        return tap($this->newBroadcastableEvent($event), function ($event) {\n            $event->connection = property_exists($this, 'broadcastConnection')\n                            ? $this->broadcastConnection\n                            : $this->broadcastConnection();\n\n            $event->queue = property_exists($this, 'broadcastQueue')\n                            ? $this->broadcastQueue\n                            : $this->broadcastQueue();\n\n            $event->afterCommit = property_exists($this, 'broadcastAfterCommit')\n                            ? $this->broadcastAfterCommit\n                            : $this->broadcastAfterCommit();\n        });\n    }\n\n    /**\n     * Create a new broadcastable model event for the model.\n     *\n     * @param  string  $event\n     * @return \\Illuminate\\Database\\Eloquent\\BroadcastableModelEventOccurred\n     */\n    protected function newBroadcastableEvent($event)\n    {\n        return new BroadcastableModelEventOccurred($this, $event);\n    }\n\n    /**\n     * Get the channels that model events should broadcast on.\n     *\n     * @param  string  $event\n     * @return \\Illuminate\\Broadcasting\\Channel|array\n     */\n    public function broadcastOn($event)\n    {\n        return [$this];\n    }\n\n    /**\n     * Get the queue connection that should be used to broadcast model events.\n     *\n     * @return string|null\n     */\n    public function broadcastConnection()\n    {\n        //\n    }\n\n    /**\n     * Get the queue that should be used to broadcast model events.\n     *\n     * @return string|null\n     */\n    public function broadcastQueue()\n    {\n        //\n    }\n\n    /**\n     * Determine if the model event broadcast queued job should be dispatched after all transactions are committed.\n     *\n     * @return bool\n     */\n    public function broadcastAfterCommit()\n    {\n        return false;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/Builder.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent;\n\nuse BadMethodCallException;\nuse Closure;\nuse Exception;\nuse Illuminate\\Contracts\\Support\\Arrayable;\nuse Illuminate\\Database\\Concerns\\BuildsQueries;\nuse Illuminate\\Database\\Eloquent\\Relations\\BelongsToMany;\nuse Illuminate\\Database\\Eloquent\\Relations\\Relation;\nuse Illuminate\\Database\\Query\\Builder as QueryBuilder;\nuse Illuminate\\Database\\RecordsNotFoundException;\nuse Illuminate\\Pagination\\Paginator;\nuse Illuminate\\Support\\Arr;\nuse Illuminate\\Support\\Str;\nuse Illuminate\\Support\\Traits\\ForwardsCalls;\nuse ReflectionClass;\nuse ReflectionMethod;\n\n/**\n * @property-read HigherOrderBuilderProxy $orWhere\n *\n * @mixin \\Illuminate\\Database\\Query\\Builder\n */\nclass Builder\n{\n    use Concerns\\QueriesRelationships, ForwardsCalls;\n    use BuildsQueries {\n        sole as baseSole;\n    }\n\n    /**\n     * The base query builder instance.\n     *\n     * @var \\Illuminate\\Database\\Query\\Builder\n     */\n    protected $query;\n\n    /**\n     * The model being queried.\n     *\n     * @var \\Illuminate\\Database\\Eloquent\\Model\n     */\n    protected $model;\n\n    /**\n     * The relationships that should be eager loaded.\n     *\n     * @var array\n     */\n    protected $eagerLoad = [];\n\n    /**\n     * All of the globally registered builder macros.\n     *\n     * @var array\n     */\n    protected static $macros = [];\n\n    /**\n     * All of the locally registered builder macros.\n     *\n     * @var array\n     */\n    protected $localMacros = [];\n\n    /**\n     * A replacement for the typical delete function.\n     *\n     * @var \\Closure\n     */\n    protected $onDelete;\n\n    /**\n     * The properties that should be returned from query builder.\n     *\n     * @var string[]\n     */\n    protected $propertyPassthru = [\n        'from',\n    ];\n\n    /**\n     * The methods that should be returned from query builder.\n     *\n     * @var string[]\n     */\n    protected $passthru = [\n        'aggregate',\n        'average',\n        'avg',\n        'count',\n        'dd',\n        'doesntExist',\n        'dump',\n        'exists',\n        'explain',\n        'getBindings',\n        'getConnection',\n        'getGrammar',\n        'insert',\n        'insertGetId',\n        'insertOrIgnore',\n        'insertUsing',\n        'max',\n        'min',\n        'raw',\n        'sum',\n        'toSql',\n    ];\n\n    /**\n     * Applied global scopes.\n     *\n     * @var array\n     */\n    protected $scopes = [];\n\n    /**\n     * Removed global scopes.\n     *\n     * @var array\n     */\n    protected $removedScopes = [];\n\n    /**\n     * Create a new Eloquent query builder instance.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @return void\n     */\n    public function __construct(QueryBuilder $query)\n    {\n        $this->query = $query;\n    }\n\n    /**\n     * Create and return an un-saved model instance.\n     *\n     * @param  array  $attributes\n     * @return \\Illuminate\\Database\\Eloquent\\Model|static\n     */\n    public function make(array $attributes = [])\n    {\n        return $this->newModelInstance($attributes);\n    }\n\n    /**\n     * Register a new global scope.\n     *\n     * @param  string  $identifier\n     * @param  \\Illuminate\\Database\\Eloquent\\Scope|\\Closure  $scope\n     * @return $this\n     */\n    public function withGlobalScope($identifier, $scope)\n    {\n        $this->scopes[$identifier] = $scope;\n\n        if (method_exists($scope, 'extend')) {\n            $scope->extend($this);\n        }\n\n        return $this;\n    }\n\n    /**\n     * Remove a registered global scope.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Scope|string  $scope\n     * @return $this\n     */\n    public function withoutGlobalScope($scope)\n    {\n        if (! is_string($scope)) {\n            $scope = get_class($scope);\n        }\n\n        unset($this->scopes[$scope]);\n\n        $this->removedScopes[] = $scope;\n\n        return $this;\n    }\n\n    /**\n     * Remove all or passed registered global scopes.\n     *\n     * @param  array|null  $scopes\n     * @return $this\n     */\n    public function withoutGlobalScopes(array $scopes = null)\n    {\n        if (! is_array($scopes)) {\n            $scopes = array_keys($this->scopes);\n        }\n\n        foreach ($scopes as $scope) {\n            $this->withoutGlobalScope($scope);\n        }\n\n        return $this;\n    }\n\n    /**\n     * Get an array of global scopes that were removed from the query.\n     *\n     * @return array\n     */\n    public function removedScopes()\n    {\n        return $this->removedScopes;\n    }\n\n    /**\n     * Add a where clause on the primary key to the query.\n     *\n     * @param  mixed  $id\n     * @return $this\n     */\n    public function whereKey($id)\n    {\n        if ($id instanceof Model) {\n            $id = $id->getKey();\n        }\n\n        if (is_array($id) || $id instanceof Arrayable) {\n            $this->query->whereIn($this->model->getQualifiedKeyName(), $id);\n\n            return $this;\n        }\n\n        if ($id !== null && $this->model->getKeyType() === 'string') {\n            $id = (string) $id;\n        }\n\n        return $this->where($this->model->getQualifiedKeyName(), '=', $id);\n    }\n\n    /**\n     * Add a where clause on the primary key to the query.\n     *\n     * @param  mixed  $id\n     * @return $this\n     */\n    public function whereKeyNot($id)\n    {\n        if ($id instanceof Model) {\n            $id = $id->getKey();\n        }\n\n        if (is_array($id) || $id instanceof Arrayable) {\n            $this->query->whereNotIn($this->model->getQualifiedKeyName(), $id);\n\n            return $this;\n        }\n\n        if ($id !== null && $this->model->getKeyType() === 'string') {\n            $id = (string) $id;\n        }\n\n        return $this->where($this->model->getQualifiedKeyName(), '!=', $id);\n    }\n\n    /**\n     * Add a basic where clause to the query.\n     *\n     * @param  \\Closure|string|array|\\Illuminate\\Database\\Query\\Expression  $column\n     * @param  mixed  $operator\n     * @param  mixed  $value\n     * @param  string  $boolean\n     * @return $this\n     */\n    public function where($column, $operator = null, $value = null, $boolean = 'and')\n    {\n        if ($column instanceof Closure && is_null($operator)) {\n            $column($query = $this->model->newQueryWithoutRelationships());\n\n            $this->query->addNestedWhereQuery($query->getQuery(), $boolean);\n        } else {\n            $this->query->where(...func_get_args());\n        }\n\n        return $this;\n    }\n\n    /**\n     * Add a basic where clause to the query, and return the first result.\n     *\n     * @param  \\Closure|string|array|\\Illuminate\\Database\\Query\\Expression  $column\n     * @param  mixed  $operator\n     * @param  mixed  $value\n     * @param  string  $boolean\n     * @return \\Illuminate\\Database\\Eloquent\\Model|static|null\n     */\n    public function firstWhere($column, $operator = null, $value = null, $boolean = 'and')\n    {\n        return $this->where($column, $operator, $value, $boolean)->first();\n    }\n\n    /**\n     * Add an \"or where\" clause to the query.\n     *\n     * @param  \\Closure|array|string|\\Illuminate\\Database\\Query\\Expression  $column\n     * @param  mixed  $operator\n     * @param  mixed  $value\n     * @return $this\n     */\n    public function orWhere($column, $operator = null, $value = null)\n    {\n        [$value, $operator] = $this->query->prepareValueAndOperator(\n            $value, $operator, func_num_args() === 2\n        );\n\n        return $this->where($column, $operator, $value, 'or');\n    }\n\n    /**\n     * Add an \"order by\" clause for a timestamp to the query.\n     *\n     * @param  string|\\Illuminate\\Database\\Query\\Expression  $column\n     * @return $this\n     */\n    public function latest($column = null)\n    {\n        if (is_null($column)) {\n            $column = $this->model->getCreatedAtColumn() ?? 'created_at';\n        }\n\n        $this->query->latest($column);\n\n        return $this;\n    }\n\n    /**\n     * Add an \"order by\" clause for a timestamp to the query.\n     *\n     * @param  string|\\Illuminate\\Database\\Query\\Expression  $column\n     * @return $this\n     */\n    public function oldest($column = null)\n    {\n        if (is_null($column)) {\n            $column = $this->model->getCreatedAtColumn() ?? 'created_at';\n        }\n\n        $this->query->oldest($column);\n\n        return $this;\n    }\n\n    /**\n     * Create a collection of models from plain arrays.\n     *\n     * @param  array  $items\n     * @return \\Illuminate\\Database\\Eloquent\\Collection\n     */\n    public function hydrate(array $items)\n    {\n        $instance = $this->newModelInstance();\n\n        return $instance->newCollection(array_map(function ($item) use ($items, $instance) {\n            $model = $instance->newFromBuilder($item);\n\n            if (count($items) > 1) {\n                $model->preventsLazyLoading = Model::preventsLazyLoading();\n            }\n\n            return $model;\n        }, $items));\n    }\n\n    /**\n     * Create a collection of models from a raw query.\n     *\n     * @param  string  $query\n     * @param  array  $bindings\n     * @return \\Illuminate\\Database\\Eloquent\\Collection\n     */\n    public function fromQuery($query, $bindings = [])\n    {\n        return $this->hydrate(\n            $this->query->getConnection()->select($query, $bindings)\n        );\n    }\n\n    /**\n     * Find a model by its primary key.\n     *\n     * @param  mixed  $id\n     * @param  array  $columns\n     * @return \\Illuminate\\Database\\Eloquent\\Model|\\Illuminate\\Database\\Eloquent\\Collection|static[]|static|null\n     */\n    public function find($id, $columns = ['*'])\n    {\n        if (is_array($id) || $id instanceof Arrayable) {\n            return $this->findMany($id, $columns);\n        }\n\n        return $this->whereKey($id)->first($columns);\n    }\n\n    /**\n     * Find multiple models by their primary keys.\n     *\n     * @param  \\Illuminate\\Contracts\\Support\\Arrayable|array  $ids\n     * @param  array  $columns\n     * @return \\Illuminate\\Database\\Eloquent\\Collection\n     */\n    public function findMany($ids, $columns = ['*'])\n    {\n        $ids = $ids instanceof Arrayable ? $ids->toArray() : $ids;\n\n        if (empty($ids)) {\n            return $this->model->newCollection();\n        }\n\n        return $this->whereKey($ids)->get($columns);\n    }\n\n    /**\n     * Find a model by its primary key or throw an exception.\n     *\n     * @param  mixed  $id\n     * @param  array  $columns\n     * @return \\Illuminate\\Database\\Eloquent\\Model|\\Illuminate\\Database\\Eloquent\\Collection|static|static[]\n     *\n     * @throws \\Illuminate\\Database\\Eloquent\\ModelNotFoundException\n     */\n    public function findOrFail($id, $columns = ['*'])\n    {\n        $result = $this->find($id, $columns);\n\n        $id = $id instanceof Arrayable ? $id->toArray() : $id;\n\n        if (is_array($id)) {\n            if (count($result) === count(array_unique($id))) {\n                return $result;\n            }\n        } elseif (! is_null($result)) {\n            return $result;\n        }\n\n        throw (new ModelNotFoundException)->setModel(\n            get_class($this->model), $id\n        );\n    }\n\n    /**\n     * Find a model by its primary key or return fresh model instance.\n     *\n     * @param  mixed  $id\n     * @param  array  $columns\n     * @return \\Illuminate\\Database\\Eloquent\\Model|static\n     */\n    public function findOrNew($id, $columns = ['*'])\n    {\n        if (! is_null($model = $this->find($id, $columns))) {\n            return $model;\n        }\n\n        return $this->newModelInstance();\n    }\n\n    /**\n     * Get the first record matching the attributes or instantiate it.\n     *\n     * @param  array  $attributes\n     * @param  array  $values\n     * @return \\Illuminate\\Database\\Eloquent\\Model|static\n     */\n    public function firstOrNew(array $attributes = [], array $values = [])\n    {\n        if (! is_null($instance = $this->where($attributes)->first())) {\n            return $instance;\n        }\n\n        return $this->newModelInstance(array_merge($attributes, $values));\n    }\n\n    /**\n     * Get the first record matching the attributes or create it.\n     *\n     * @param  array  $attributes\n     * @param  array  $values\n     * @return \\Illuminate\\Database\\Eloquent\\Model|static\n     */\n    public function firstOrCreate(array $attributes = [], array $values = [])\n    {\n        if (! is_null($instance = $this->where($attributes)->first())) {\n            return $instance;\n        }\n\n        return tap($this->newModelInstance(array_merge($attributes, $values)), function ($instance) {\n            $instance->save();\n        });\n    }\n\n    /**\n     * Create or update a record matching the attributes, and fill it with values.\n     *\n     * @param  array  $attributes\n     * @param  array  $values\n     * @return \\Illuminate\\Database\\Eloquent\\Model|static\n     */\n    public function updateOrCreate(array $attributes, array $values = [])\n    {\n        return tap($this->firstOrNew($attributes), function ($instance) use ($values) {\n            $instance->fill($values)->save();\n        });\n    }\n\n    /**\n     * Execute the query and get the first result or throw an exception.\n     *\n     * @param  array  $columns\n     * @return \\Illuminate\\Database\\Eloquent\\Model|static\n     *\n     * @throws \\Illuminate\\Database\\Eloquent\\ModelNotFoundException\n     */\n    public function firstOrFail($columns = ['*'])\n    {\n        if (! is_null($model = $this->first($columns))) {\n            return $model;\n        }\n\n        throw (new ModelNotFoundException)->setModel(get_class($this->model));\n    }\n\n    /**\n     * Execute the query and get the first result or call a callback.\n     *\n     * @param  \\Closure|array  $columns\n     * @param  \\Closure|null  $callback\n     * @return \\Illuminate\\Database\\Eloquent\\Model|static|mixed\n     */\n    public function firstOr($columns = ['*'], Closure $callback = null)\n    {\n        if ($columns instanceof Closure) {\n            $callback = $columns;\n\n            $columns = ['*'];\n        }\n\n        if (! is_null($model = $this->first($columns))) {\n            return $model;\n        }\n\n        return $callback();\n    }\n\n    /**\n     * Execute the query and get the first result if it's the sole matching record.\n     *\n     * @param  array|string  $columns\n     * @return \\Illuminate\\Database\\Eloquent\\Model\n     *\n     * @throws \\Illuminate\\Database\\Eloquent\\ModelNotFoundException\n     * @throws \\Illuminate\\Database\\MultipleRecordsFoundException\n     */\n    public function sole($columns = ['*'])\n    {\n        try {\n            return $this->baseSole($columns);\n        } catch (RecordsNotFoundException $exception) {\n            throw (new ModelNotFoundException)->setModel(get_class($this->model));\n        }\n    }\n\n    /**\n     * Get a single column's value from the first result of a query.\n     *\n     * @param  string|\\Illuminate\\Database\\Query\\Expression  $column\n     * @return mixed\n     */\n    public function value($column)\n    {\n        if ($result = $this->first([$column])) {\n            return $result->{Str::afterLast($column, '.')};\n        }\n    }\n\n    /**\n     * Get a single column's value from the first result of the query or throw an exception.\n     *\n     * @param  string|\\Illuminate\\Database\\Query\\Expression  $column\n     * @return mixed\n     *\n     * @throws \\Illuminate\\Database\\Eloquent\\ModelNotFoundException\n     */\n    public function valueOrFail($column)\n    {\n        return $this->firstOrFail([$column])->{Str::afterLast($column, '.')};\n    }\n\n    /**\n     * Execute the query as a \"select\" statement.\n     *\n     * @param  array|string  $columns\n     * @return \\Illuminate\\Database\\Eloquent\\Collection|static[]\n     */\n    public function get($columns = ['*'])\n    {\n        $builder = $this->applyScopes();\n\n        // If we actually found models we will also eager load any relationships that\n        // have been specified as needing to be eager loaded, which will solve the\n        // n+1 query issue for the developers to avoid running a lot of queries.\n        if (count($models = $builder->getModels($columns)) > 0) {\n            $models = $builder->eagerLoadRelations($models);\n        }\n\n        return $builder->getModel()->newCollection($models);\n    }\n\n    /**\n     * Get the hydrated models without eager loading.\n     *\n     * @param  array|string  $columns\n     * @return \\Illuminate\\Database\\Eloquent\\Model[]|static[]\n     */\n    public function getModels($columns = ['*'])\n    {\n        return $this->model->hydrate(\n            $this->query->get($columns)->all()\n        )->all();\n    }\n\n    /**\n     * Eager load the relationships for the models.\n     *\n     * @param  array  $models\n     * @return array\n     */\n    public function eagerLoadRelations(array $models)\n    {\n        foreach ($this->eagerLoad as $name => $constraints) {\n            // For nested eager loads we'll skip loading them here and they will be set as an\n            // eager load on the query to retrieve the relation so that they will be eager\n            // loaded on that query, because that is where they get hydrated as models.\n            if (strpos($name, '.') === false) {\n                $models = $this->eagerLoadRelation($models, $name, $constraints);\n            }\n        }\n\n        return $models;\n    }\n\n    /**\n     * Eagerly load the relationship on a set of models.\n     *\n     * @param  array  $models\n     * @param  string  $name\n     * @param  \\Closure  $constraints\n     * @return array\n     */\n    protected function eagerLoadRelation(array $models, $name, Closure $constraints)\n    {\n        // First we will \"back up\" the existing where conditions on the query so we can\n        // add our eager constraints. Then we will merge the wheres that were on the\n        // query back to it in order that any where conditions might be specified.\n        $relation = $this->getRelation($name);\n\n        $relation->addEagerConstraints($models);\n\n        $constraints($relation);\n\n        // Once we have the results, we just match those back up to their parent models\n        // using the relationship instance. Then we just return the finished arrays\n        // of models which have been eagerly hydrated and are readied for return.\n        return $relation->match(\n            $relation->initRelation($models, $name),\n            $relation->getEager(), $name\n        );\n    }\n\n    /**\n     * Get the relation instance for the given relation name.\n     *\n     * @param  string  $name\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\Relation\n     */\n    public function getRelation($name)\n    {\n        // We want to run a relationship query without any constrains so that we will\n        // not have to remove these where clauses manually which gets really hacky\n        // and error prone. We don't want constraints because we add eager ones.\n        $relation = Relation::noConstraints(function () use ($name) {\n            try {\n                return $this->getModel()->newInstance()->$name();\n            } catch (BadMethodCallException $e) {\n                throw RelationNotFoundException::make($this->getModel(), $name);\n            }\n        });\n\n        $nested = $this->relationsNestedUnder($name);\n\n        // If there are nested relationships set on the query, we will put those onto\n        // the query instances so that they can be handled after this relationship\n        // is loaded. In this way they will all trickle down as they are loaded.\n        if (count($nested) > 0) {\n            $relation->getQuery()->with($nested);\n        }\n\n        return $relation;\n    }\n\n    /**\n     * Get the deeply nested relations for a given top-level relation.\n     *\n     * @param  string  $relation\n     * @return array\n     */\n    protected function relationsNestedUnder($relation)\n    {\n        $nested = [];\n\n        // We are basically looking for any relationships that are nested deeper than\n        // the given top-level relationship. We will just check for any relations\n        // that start with the given top relations and adds them to our arrays.\n        foreach ($this->eagerLoad as $name => $constraints) {\n            if ($this->isNestedUnder($relation, $name)) {\n                $nested[substr($name, strlen($relation.'.'))] = $constraints;\n            }\n        }\n\n        return $nested;\n    }\n\n    /**\n     * Determine if the relationship is nested.\n     *\n     * @param  string  $relation\n     * @param  string  $name\n     * @return bool\n     */\n    protected function isNestedUnder($relation, $name)\n    {\n        return Str::contains($name, '.') && Str::startsWith($name, $relation.'.');\n    }\n\n    /**\n     * Get a lazy collection for the given query.\n     *\n     * @return \\Illuminate\\Support\\LazyCollection\n     */\n    public function cursor()\n    {\n        return $this->applyScopes()->query->cursor()->map(function ($record) {\n            return $this->newModelInstance()->newFromBuilder($record);\n        });\n    }\n\n    /**\n     * Add a generic \"order by\" clause if the query doesn't already have one.\n     *\n     * @return void\n     */\n    protected function enforceOrderBy()\n    {\n        if (empty($this->query->orders) && empty($this->query->unionOrders)) {\n            $this->orderBy($this->model->getQualifiedKeyName(), 'asc');\n        }\n    }\n\n    /**\n     * Get an array with the values of a given column.\n     *\n     * @param  string|\\Illuminate\\Database\\Query\\Expression  $column\n     * @param  string|null  $key\n     * @return \\Illuminate\\Support\\Collection\n     */\n    public function pluck($column, $key = null)\n    {\n        $results = $this->toBase()->pluck($column, $key);\n\n        // If the model has a mutator for the requested column, we will spin through\n        // the results and mutate the values so that the mutated version of these\n        // columns are returned as you would expect from these Eloquent models.\n        if (! $this->model->hasGetMutator($column) &&\n            ! $this->model->hasCast($column) &&\n            ! in_array($column, $this->model->getDates())) {\n            return $results;\n        }\n\n        return $results->map(function ($value) use ($column) {\n            return $this->model->newFromBuilder([$column => $value])->{$column};\n        });\n    }\n\n    /**\n     * Paginate the given query.\n     *\n     * @param  int|null  $perPage\n     * @param  array  $columns\n     * @param  string  $pageName\n     * @param  int|null  $page\n     * @return \\Illuminate\\Contracts\\Pagination\\LengthAwarePaginator\n     *\n     * @throws \\InvalidArgumentException\n     */\n    public function paginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null)\n    {\n        $page = $page ?: Paginator::resolveCurrentPage($pageName);\n\n        $perPage = $perPage ?: $this->model->getPerPage();\n\n        $results = ($total = $this->toBase()->getCountForPagination())\n                                    ? $this->forPage($page, $perPage)->get($columns)\n                                    : $this->model->newCollection();\n\n        return $this->paginator($results, $total, $perPage, $page, [\n            'path' => Paginator::resolveCurrentPath(),\n            'pageName' => $pageName,\n        ]);\n    }\n\n    /**\n     * Paginate the given query into a simple paginator.\n     *\n     * @param  int|null  $perPage\n     * @param  array  $columns\n     * @param  string  $pageName\n     * @param  int|null  $page\n     * @return \\Illuminate\\Contracts\\Pagination\\Paginator\n     */\n    public function simplePaginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null)\n    {\n        $page = $page ?: Paginator::resolveCurrentPage($pageName);\n\n        $perPage = $perPage ?: $this->model->getPerPage();\n\n        // Next we will set the limit and offset for this query so that when we get the\n        // results we get the proper section of results. Then, we'll create the full\n        // paginator instances for these results with the given page and per page.\n        $this->skip(($page - 1) * $perPage)->take($perPage + 1);\n\n        return $this->simplePaginator($this->get($columns), $perPage, $page, [\n            'path' => Paginator::resolveCurrentPath(),\n            'pageName' => $pageName,\n        ]);\n    }\n\n    /**\n     * Paginate the given query into a cursor paginator.\n     *\n     * @param  int|null  $perPage\n     * @param  array  $columns\n     * @param  string  $cursorName\n     * @param  \\Illuminate\\Pagination\\Cursor|string|null  $cursor\n     * @return \\Illuminate\\Contracts\\Pagination\\CursorPaginator\n     */\n    public function cursorPaginate($perPage = null, $columns = ['*'], $cursorName = 'cursor', $cursor = null)\n    {\n        $perPage = $perPage ?: $this->model->getPerPage();\n\n        return $this->paginateUsingCursor($perPage, $columns, $cursorName, $cursor);\n    }\n\n    /**\n     * Ensure the proper order by required for cursor pagination.\n     *\n     * @param  bool  $shouldReverse\n     * @return \\Illuminate\\Support\\Collection\n     */\n    protected function ensureOrderForCursorPagination($shouldReverse = false)\n    {\n        if (empty($this->query->orders) && empty($this->query->unionOrders)) {\n            $this->enforceOrderBy();\n        }\n\n        if ($shouldReverse) {\n            $this->query->orders = collect($this->query->orders)->map(function ($order) {\n                $order['direction'] = $order['direction'] === 'asc' ? 'desc' : 'asc';\n\n                return $order;\n            })->toArray();\n        }\n\n        if ($this->query->unionOrders) {\n            return collect($this->query->unionOrders);\n        }\n\n        return collect($this->query->orders);\n    }\n\n    /**\n     * Save a new model and return the instance.\n     *\n     * @param  array  $attributes\n     * @return \\Illuminate\\Database\\Eloquent\\Model|$this\n     */\n    public function create(array $attributes = [])\n    {\n        return tap($this->newModelInstance($attributes), function ($instance) {\n            $instance->save();\n        });\n    }\n\n    /**\n     * Save a new model and return the instance. Allow mass-assignment.\n     *\n     * @param  array  $attributes\n     * @return \\Illuminate\\Database\\Eloquent\\Model|$this\n     */\n    public function forceCreate(array $attributes)\n    {\n        return $this->model->unguarded(function () use ($attributes) {\n            return $this->newModelInstance()->create($attributes);\n        });\n    }\n\n    /**\n     * Update records in the database.\n     *\n     * @param  array  $values\n     * @return int\n     */\n    public function update(array $values)\n    {\n        return $this->toBase()->update($this->addUpdatedAtColumn($values));\n    }\n\n    /**\n     * Insert new records or update the existing ones.\n     *\n     * @param  array  $values\n     * @param  array|string  $uniqueBy\n     * @param  array|null  $update\n     * @return int\n     */\n    public function upsert(array $values, $uniqueBy, $update = null)\n    {\n        if (empty($values)) {\n            return 0;\n        }\n\n        if (! is_array(reset($values))) {\n            $values = [$values];\n        }\n\n        if (is_null($update)) {\n            $update = array_keys(reset($values));\n        }\n\n        return $this->toBase()->upsert(\n            $this->addTimestampsToUpsertValues($values),\n            $uniqueBy,\n            $this->addUpdatedAtToUpsertColumns($update)\n        );\n    }\n\n    /**\n     * Increment a column's value by a given amount.\n     *\n     * @param  string|\\Illuminate\\Database\\Query\\Expression  $column\n     * @param  float|int  $amount\n     * @param  array  $extra\n     * @return int\n     */\n    public function increment($column, $amount = 1, array $extra = [])\n    {\n        return $this->toBase()->increment(\n            $column, $amount, $this->addUpdatedAtColumn($extra)\n        );\n    }\n\n    /**\n     * Decrement a column's value by a given amount.\n     *\n     * @param  string|\\Illuminate\\Database\\Query\\Expression  $column\n     * @param  float|int  $amount\n     * @param  array  $extra\n     * @return int\n     */\n    public function decrement($column, $amount = 1, array $extra = [])\n    {\n        return $this->toBase()->decrement(\n            $column, $amount, $this->addUpdatedAtColumn($extra)\n        );\n    }\n\n    /**\n     * Add the \"updated at\" column to an array of values.\n     *\n     * @param  array  $values\n     * @return array\n     */\n    protected function addUpdatedAtColumn(array $values)\n    {\n        if (! $this->model->usesTimestamps() ||\n            is_null($this->model->getUpdatedAtColumn())) {\n            return $values;\n        }\n\n        $column = $this->model->getUpdatedAtColumn();\n\n        $values = array_merge(\n            [$column => $this->model->freshTimestampString()],\n            $values\n        );\n\n        $segments = preg_split('/\\s+as\\s+/i', $this->query->from);\n\n        $qualifiedColumn = end($segments).'.'.$column;\n\n        $values[$qualifiedColumn] = Arr::get($values, $qualifiedColumn, $values[$column]);\n\n        unset($values[$column]);\n\n        return $values;\n    }\n\n    /**\n     * Add timestamps to the inserted values.\n     *\n     * @param  array  $values\n     * @return array\n     */\n    protected function addTimestampsToUpsertValues(array $values)\n    {\n        if (! $this->model->usesTimestamps()) {\n            return $values;\n        }\n\n        $timestamp = $this->model->freshTimestampString();\n\n        $columns = array_filter([\n            $this->model->getCreatedAtColumn(),\n            $this->model->getUpdatedAtColumn(),\n        ]);\n\n        foreach ($columns as $column) {\n            foreach ($values as &$row) {\n                $row = array_merge([$column => $timestamp], $row);\n            }\n        }\n\n        return $values;\n    }\n\n    /**\n     * Add the \"updated at\" column to the updated columns.\n     *\n     * @param  array  $update\n     * @return array\n     */\n    protected function addUpdatedAtToUpsertColumns(array $update)\n    {\n        if (! $this->model->usesTimestamps()) {\n            return $update;\n        }\n\n        $column = $this->model->getUpdatedAtColumn();\n\n        if (! is_null($column) &&\n            ! array_key_exists($column, $update) &&\n            ! in_array($column, $update)) {\n            $update[] = $column;\n        }\n\n        return $update;\n    }\n\n    /**\n     * Delete records from the database.\n     *\n     * @return mixed\n     */\n    public function delete()\n    {\n        if (isset($this->onDelete)) {\n            return call_user_func($this->onDelete, $this);\n        }\n\n        return $this->toBase()->delete();\n    }\n\n    /**\n     * Run the default delete function on the builder.\n     *\n     * Since we do not apply scopes here, the row will actually be deleted.\n     *\n     * @return mixed\n     */\n    public function forceDelete()\n    {\n        return $this->query->delete();\n    }\n\n    /**\n     * Register a replacement for the default delete function.\n     *\n     * @param  \\Closure  $callback\n     * @return void\n     */\n    public function onDelete(Closure $callback)\n    {\n        $this->onDelete = $callback;\n    }\n\n    /**\n     * Determine if the given model has a scope.\n     *\n     * @param  string  $scope\n     * @return bool\n     */\n    public function hasNamedScope($scope)\n    {\n        return $this->model && $this->model->hasNamedScope($scope);\n    }\n\n    /**\n     * Call the given local model scopes.\n     *\n     * @param  array|string  $scopes\n     * @return static|mixed\n     */\n    public function scopes($scopes)\n    {\n        $builder = $this;\n\n        foreach (Arr::wrap($scopes) as $scope => $parameters) {\n            // If the scope key is an integer, then the scope was passed as the value and\n            // the parameter list is empty, so we will format the scope name and these\n            // parameters here. Then, we'll be ready to call the scope on the model.\n            if (is_int($scope)) {\n                [$scope, $parameters] = [$parameters, []];\n            }\n\n            // Next we'll pass the scope callback to the callScope method which will take\n            // care of grouping the \"wheres\" properly so the logical order doesn't get\n            // messed up when adding scopes. Then we'll return back out the builder.\n            $builder = $builder->callNamedScope(\n                $scope, Arr::wrap($parameters)\n            );\n        }\n\n        return $builder;\n    }\n\n    /**\n     * Apply the scopes to the Eloquent builder instance and return it.\n     *\n     * @return static\n     */\n    public function applyScopes()\n    {\n        if (! $this->scopes) {\n            return $this;\n        }\n\n        $builder = clone $this;\n\n        foreach ($this->scopes as $identifier => $scope) {\n            if (! isset($builder->scopes[$identifier])) {\n                continue;\n            }\n\n            $builder->callScope(function (self $builder) use ($scope) {\n                // If the scope is a Closure we will just go ahead and call the scope with the\n                // builder instance. The \"callScope\" method will properly group the clauses\n                // that are added to this query so \"where\" clauses maintain proper logic.\n                if ($scope instanceof Closure) {\n                    $scope($builder);\n                }\n\n                // If the scope is a scope object, we will call the apply method on this scope\n                // passing in the builder and the model instance. After we run all of these\n                // scopes we will return back the builder instance to the outside caller.\n                if ($scope instanceof Scope) {\n                    $scope->apply($builder, $this->getModel());\n                }\n            });\n        }\n\n        return $builder;\n    }\n\n    /**\n     * Apply the given scope on the current builder instance.\n     *\n     * @param  callable  $scope\n     * @param  array  $parameters\n     * @return mixed\n     */\n    protected function callScope(callable $scope, array $parameters = [])\n    {\n        array_unshift($parameters, $this);\n\n        $query = $this->getQuery();\n\n        // We will keep track of how many wheres are on the query before running the\n        // scope so that we can properly group the added scope constraints in the\n        // query as their own isolated nested where statement and avoid issues.\n        $originalWhereCount = is_null($query->wheres)\n                    ? 0 : count($query->wheres);\n\n        $result = $scope(...array_values($parameters)) ?? $this;\n\n        if (count((array) $query->wheres) > $originalWhereCount) {\n            $this->addNewWheresWithinGroup($query, $originalWhereCount);\n        }\n\n        return $result;\n    }\n\n    /**\n     * Apply the given named scope on the current builder instance.\n     *\n     * @param  string  $scope\n     * @param  array  $parameters\n     * @return mixed\n     */\n    protected function callNamedScope($scope, array $parameters = [])\n    {\n        return $this->callScope(function (...$parameters) use ($scope) {\n            return $this->model->callNamedScope($scope, $parameters);\n        }, $parameters);\n    }\n\n    /**\n     * Nest where conditions by slicing them at the given where count.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  int  $originalWhereCount\n     * @return void\n     */\n    protected function addNewWheresWithinGroup(QueryBuilder $query, $originalWhereCount)\n    {\n        // Here, we totally remove all of the where clauses since we are going to\n        // rebuild them as nested queries by slicing the groups of wheres into\n        // their own sections. This is to prevent any confusing logic order.\n        $allWheres = $query->wheres;\n\n        $query->wheres = [];\n\n        $this->groupWhereSliceForScope(\n            $query, array_slice($allWheres, 0, $originalWhereCount)\n        );\n\n        $this->groupWhereSliceForScope(\n            $query, array_slice($allWheres, $originalWhereCount)\n        );\n    }\n\n    /**\n     * Slice where conditions at the given offset and add them to the query as a nested condition.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $whereSlice\n     * @return void\n     */\n    protected function groupWhereSliceForScope(QueryBuilder $query, $whereSlice)\n    {\n        $whereBooleans = collect($whereSlice)->pluck('boolean');\n\n        // Here we'll check if the given subset of where clauses contains any \"or\"\n        // booleans and in this case create a nested where expression. That way\n        // we don't add any unnecessary nesting thus keeping the query clean.\n        if ($whereBooleans->contains('or')) {\n            $query->wheres[] = $this->createNestedWhere(\n                $whereSlice, $whereBooleans->first()\n            );\n        } else {\n            $query->wheres = array_merge($query->wheres, $whereSlice);\n        }\n    }\n\n    /**\n     * Create a where array with nested where conditions.\n     *\n     * @param  array  $whereSlice\n     * @param  string  $boolean\n     * @return array\n     */\n    protected function createNestedWhere($whereSlice, $boolean = 'and')\n    {\n        $whereGroup = $this->getQuery()->forNestedWhere();\n\n        $whereGroup->wheres = $whereSlice;\n\n        return ['type' => 'Nested', 'query' => $whereGroup, 'boolean' => $boolean];\n    }\n\n    /**\n     * Set the relationships that should be eager loaded.\n     *\n     * @param  string|array  $relations\n     * @param  string|\\Closure|null  $callback\n     * @return $this\n     */\n    public function with($relations, $callback = null)\n    {\n        if ($callback instanceof Closure) {\n            $eagerLoad = $this->parseWithRelations([$relations => $callback]);\n        } else {\n            $eagerLoad = $this->parseWithRelations(is_string($relations) ? func_get_args() : $relations);\n        }\n\n        $this->eagerLoad = array_merge($this->eagerLoad, $eagerLoad);\n\n        return $this;\n    }\n\n    /**\n     * Prevent the specified relations from being eager loaded.\n     *\n     * @param  mixed  $relations\n     * @return $this\n     */\n    public function without($relations)\n    {\n        $this->eagerLoad = array_diff_key($this->eagerLoad, array_flip(\n            is_string($relations) ? func_get_args() : $relations\n        ));\n\n        return $this;\n    }\n\n    /**\n     * Set the relationships that should be eager loaded while removing any previously added eager loading specifications.\n     *\n     * @param  mixed  $relations\n     * @return $this\n     */\n    public function withOnly($relations)\n    {\n        $this->eagerLoad = [];\n\n        return $this->with($relations);\n    }\n\n    /**\n     * Create a new instance of the model being queried.\n     *\n     * @param  array  $attributes\n     * @return \\Illuminate\\Database\\Eloquent\\Model|static\n     */\n    public function newModelInstance($attributes = [])\n    {\n        return $this->model->newInstance($attributes)->setConnection(\n            $this->query->getConnection()->getName()\n        );\n    }\n\n    /**\n     * Parse a list of relations into individuals.\n     *\n     * @param  array  $relations\n     * @return array\n     */\n    protected function parseWithRelations(array $relations)\n    {\n        $results = [];\n\n        foreach ($relations as $name => $constraints) {\n            // If the \"name\" value is a numeric key, we can assume that no constraints\n            // have been specified. We will just put an empty Closure there so that\n            // we can treat these all the same while we are looping through them.\n            if (is_numeric($name)) {\n                $name = $constraints;\n\n                [$name, $constraints] = Str::contains($name, ':')\n                            ? $this->createSelectWithConstraint($name)\n                            : [$name, static function () {\n                                //\n                            }];\n            }\n\n            // We need to separate out any nested includes, which allows the developers\n            // to load deep relationships using \"dots\" without stating each level of\n            // the relationship with its own key in the array of eager-load names.\n            $results = $this->addNestedWiths($name, $results);\n\n            $results[$name] = $constraints;\n        }\n\n        return $results;\n    }\n\n    /**\n     * Create a constraint to select the given columns for the relation.\n     *\n     * @param  string  $name\n     * @return array\n     */\n    protected function createSelectWithConstraint($name)\n    {\n        return [explode(':', $name)[0], static function ($query) use ($name) {\n            $query->select(array_map(static function ($column) use ($query) {\n                if (Str::contains($column, '.')) {\n                    return $column;\n                }\n\n                return $query instanceof BelongsToMany\n                        ? $query->getRelated()->getTable().'.'.$column\n                        : $column;\n            }, explode(',', explode(':', $name)[1])));\n        }];\n    }\n\n    /**\n     * Parse the nested relationships in a relation.\n     *\n     * @param  string  $name\n     * @param  array  $results\n     * @return array\n     */\n    protected function addNestedWiths($name, $results)\n    {\n        $progress = [];\n\n        // If the relation has already been set on the result array, we will not set it\n        // again, since that would override any constraints that were already placed\n        // on the relationships. We will only set the ones that are not specified.\n        foreach (explode('.', $name) as $segment) {\n            $progress[] = $segment;\n\n            if (! isset($results[$last = implode('.', $progress)])) {\n                $results[$last] = static function () {\n                    //\n                };\n            }\n        }\n\n        return $results;\n    }\n\n    /**\n     * Apply query-time casts to the model instance.\n     *\n     * @param  array  $casts\n     * @return $this\n     */\n    public function withCasts($casts)\n    {\n        $this->model->mergeCasts($casts);\n\n        return $this;\n    }\n\n    /**\n     * Get the underlying query builder instance.\n     *\n     * @return \\Illuminate\\Database\\Query\\Builder\n     */\n    public function getQuery()\n    {\n        return $this->query;\n    }\n\n    /**\n     * Set the underlying query builder instance.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @return $this\n     */\n    public function setQuery($query)\n    {\n        $this->query = $query;\n\n        return $this;\n    }\n\n    /**\n     * Get a base query builder instance.\n     *\n     * @return \\Illuminate\\Database\\Query\\Builder\n     */\n    public function toBase()\n    {\n        return $this->applyScopes()->getQuery();\n    }\n\n    /**\n     * Get the relationships being eagerly loaded.\n     *\n     * @return array\n     */\n    public function getEagerLoads()\n    {\n        return $this->eagerLoad;\n    }\n\n    /**\n     * Set the relationships being eagerly loaded.\n     *\n     * @param  array  $eagerLoad\n     * @return $this\n     */\n    public function setEagerLoads(array $eagerLoad)\n    {\n        $this->eagerLoad = $eagerLoad;\n\n        return $this;\n    }\n\n    /**\n     * Get the default key name of the table.\n     *\n     * @return string\n     */\n    protected function defaultKeyName()\n    {\n        return $this->getModel()->getKeyName();\n    }\n\n    /**\n     * Get the model instance being queried.\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Model|static\n     */\n    public function getModel()\n    {\n        return $this->model;\n    }\n\n    /**\n     * Set a model instance for the model being queried.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $model\n     * @return $this\n     */\n    public function setModel(Model $model)\n    {\n        $this->model = $model;\n\n        $this->query->from($model->getTable());\n\n        return $this;\n    }\n\n    /**\n     * Qualify the given column name by the model's table.\n     *\n     * @param  string|\\Illuminate\\Database\\Query\\Expression  $column\n     * @return string\n     */\n    public function qualifyColumn($column)\n    {\n        return $this->model->qualifyColumn($column);\n    }\n\n    /**\n     * Qualify the given columns with the model's table.\n     *\n     * @param  array|\\Illuminate\\Database\\Query\\Expression  $columns\n     * @return array\n     */\n    public function qualifyColumns($columns)\n    {\n        return $this->model->qualifyColumns($columns);\n    }\n\n    /**\n     * Get the given macro by name.\n     *\n     * @param  string  $name\n     * @return \\Closure\n     */\n    public function getMacro($name)\n    {\n        return Arr::get($this->localMacros, $name);\n    }\n\n    /**\n     * Checks if a macro is registered.\n     *\n     * @param  string  $name\n     * @return bool\n     */\n    public function hasMacro($name)\n    {\n        return isset($this->localMacros[$name]);\n    }\n\n    /**\n     * Get the given global macro by name.\n     *\n     * @param  string  $name\n     * @return \\Closure\n     */\n    public static function getGlobalMacro($name)\n    {\n        return Arr::get(static::$macros, $name);\n    }\n\n    /**\n     * Checks if a global macro is registered.\n     *\n     * @param  string  $name\n     * @return bool\n     */\n    public static function hasGlobalMacro($name)\n    {\n        return isset(static::$macros[$name]);\n    }\n\n    /**\n     * Dynamically access builder proxies.\n     *\n     * @param  string  $key\n     * @return mixed\n     *\n     * @throws \\Exception\n     */\n    public function __get($key)\n    {\n        if ($key === 'orWhere') {\n            return new HigherOrderBuilderProxy($this, $key);\n        }\n\n        if (in_array($key, $this->propertyPassthru)) {\n            return $this->toBase()->{$key};\n        }\n\n        throw new Exception(\"Property [{$key}] does not exist on the Eloquent builder instance.\");\n    }\n\n    /**\n     * Dynamically handle calls into the query instance.\n     *\n     * @param  string  $method\n     * @param  array  $parameters\n     * @return mixed\n     */\n    public function __call($method, $parameters)\n    {\n        if ($method === 'macro') {\n            $this->localMacros[$parameters[0]] = $parameters[1];\n\n            return;\n        }\n\n        if ($this->hasMacro($method)) {\n            array_unshift($parameters, $this);\n\n            return $this->localMacros[$method](...$parameters);\n        }\n\n        if (static::hasGlobalMacro($method)) {\n            $callable = static::$macros[$method];\n\n            if ($callable instanceof Closure) {\n                $callable = $callable->bindTo($this, static::class);\n            }\n\n            return $callable(...$parameters);\n        }\n\n        if ($this->hasNamedScope($method)) {\n            return $this->callNamedScope($method, $parameters);\n        }\n\n        if (in_array($method, $this->passthru)) {\n            return $this->toBase()->{$method}(...$parameters);\n        }\n\n        $this->forwardCallTo($this->query, $method, $parameters);\n\n        return $this;\n    }\n\n    /**\n     * Dynamically handle calls into the query instance.\n     *\n     * @param  string  $method\n     * @param  array  $parameters\n     * @return mixed\n     *\n     * @throws \\BadMethodCallException\n     */\n    public static function __callStatic($method, $parameters)\n    {\n        if ($method === 'macro') {\n            static::$macros[$parameters[0]] = $parameters[1];\n\n            return;\n        }\n\n        if ($method === 'mixin') {\n            return static::registerMixin($parameters[0], $parameters[1] ?? true);\n        }\n\n        if (! static::hasGlobalMacro($method)) {\n            static::throwBadMethodCallException($method);\n        }\n\n        $callable = static::$macros[$method];\n\n        if ($callable instanceof Closure) {\n            $callable = $callable->bindTo(null, static::class);\n        }\n\n        return $callable(...$parameters);\n    }\n\n    /**\n     * Register the given mixin with the builder.\n     *\n     * @param  string  $mixin\n     * @param  bool  $replace\n     * @return void\n     */\n    protected static function registerMixin($mixin, $replace)\n    {\n        $methods = (new ReflectionClass($mixin))->getMethods(\n                ReflectionMethod::IS_PUBLIC | ReflectionMethod::IS_PROTECTED\n            );\n\n        foreach ($methods as $method) {\n            if ($replace || ! static::hasGlobalMacro($method->name)) {\n                $method->setAccessible(true);\n\n                static::macro($method->name, $method->invoke($mixin));\n            }\n        }\n    }\n\n    /**\n     * Clone the Eloquent query builder.\n     *\n     * @return static\n     */\n    public function clone()\n    {\n        return clone $this;\n    }\n\n    /**\n     * Force a clone of the underlying query builder when cloning.\n     *\n     * @return void\n     */\n    public function __clone()\n    {\n        $this->query = clone $this->query;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/Casts/ArrayObject.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent\\Casts;\n\nuse ArrayObject as BaseArrayObject;\nuse Illuminate\\Contracts\\Support\\Arrayable;\nuse JsonSerializable;\n\nclass ArrayObject extends BaseArrayObject implements Arrayable, JsonSerializable\n{\n    /**\n     * Get a collection containing the underlying array.\n     *\n     * @return \\Illuminate\\Support\\Collection\n     */\n    public function collect()\n    {\n        return collect($this->getArrayCopy());\n    }\n\n    /**\n     * Get the instance as an array.\n     *\n     * @return array\n     */\n    public function toArray()\n    {\n        return $this->getArrayCopy();\n    }\n\n    /**\n     * Get the array that should be JSON serialized.\n     *\n     * @return array\n     */\n    #[\\ReturnTypeWillChange]\n    public function jsonSerialize()\n    {\n        return $this->getArrayCopy();\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/Casts/AsArrayObject.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent\\Casts;\n\nuse Illuminate\\Contracts\\Database\\Eloquent\\Castable;\nuse Illuminate\\Contracts\\Database\\Eloquent\\CastsAttributes;\n\nclass AsArrayObject implements Castable\n{\n    /**\n     * Get the caster class to use when casting from / to this cast target.\n     *\n     * @param  array  $arguments\n     * @return object|string\n     */\n    public static function castUsing(array $arguments)\n    {\n        return new class implements CastsAttributes\n        {\n            public function get($model, $key, $value, $attributes)\n            {\n                return isset($attributes[$key]) ? new ArrayObject(json_decode($attributes[$key], true)) : null;\n            }\n\n            public function set($model, $key, $value, $attributes)\n            {\n                return [$key => json_encode($value)];\n            }\n\n            public function serialize($model, string $key, $value, array $attributes)\n            {\n                return $value->getArrayCopy();\n            }\n        };\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/Casts/AsCollection.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent\\Casts;\n\nuse Illuminate\\Contracts\\Database\\Eloquent\\Castable;\nuse Illuminate\\Contracts\\Database\\Eloquent\\CastsAttributes;\nuse Illuminate\\Support\\Collection;\n\nclass AsCollection implements Castable\n{\n    /**\n     * Get the caster class to use when casting from / to this cast target.\n     *\n     * @param  array  $arguments\n     * @return object|string\n     */\n    public static function castUsing(array $arguments)\n    {\n        return new class implements CastsAttributes\n        {\n            public function get($model, $key, $value, $attributes)\n            {\n                return isset($attributes[$key]) ? new Collection(json_decode($attributes[$key], true)) : null;\n            }\n\n            public function set($model, $key, $value, $attributes)\n            {\n                return [$key => json_encode($value)];\n            }\n        };\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/Casts/AsEncryptedArrayObject.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent\\Casts;\n\nuse Illuminate\\Contracts\\Database\\Eloquent\\Castable;\nuse Illuminate\\Contracts\\Database\\Eloquent\\CastsAttributes;\nuse Illuminate\\Support\\Facades\\Crypt;\n\nclass AsEncryptedArrayObject implements Castable\n{\n    /**\n     * Get the caster class to use when casting from / to this cast target.\n     *\n     * @param  array  $arguments\n     * @return object|string\n     */\n    public static function castUsing(array $arguments)\n    {\n        return new class implements CastsAttributes\n        {\n            public function get($model, $key, $value, $attributes)\n            {\n                if (isset($attributes[$key])) {\n                    return new ArrayObject(json_decode(Crypt::decryptString($attributes[$key]), true));\n                }\n\n                return null;\n            }\n\n            public function set($model, $key, $value, $attributes)\n            {\n                if (! is_null($value)) {\n                    return [$key => Crypt::encryptString(json_encode($value))];\n                }\n\n                return null;\n            }\n\n            public function serialize($model, string $key, $value, array $attributes)\n            {\n                return ! is_null($value) ? $value->getArrayCopy() : null;\n            }\n        };\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/Casts/AsEncryptedCollection.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent\\Casts;\n\nuse Illuminate\\Contracts\\Database\\Eloquent\\Castable;\nuse Illuminate\\Contracts\\Database\\Eloquent\\CastsAttributes;\nuse Illuminate\\Support\\Collection;\nuse Illuminate\\Support\\Facades\\Crypt;\n\nclass AsEncryptedCollection implements Castable\n{\n    /**\n     * Get the caster class to use when casting from / to this cast target.\n     *\n     * @param  array  $arguments\n     * @return object|string\n     */\n    public static function castUsing(array $arguments)\n    {\n        return new class implements CastsAttributes\n        {\n            public function get($model, $key, $value, $attributes)\n            {\n                if (isset($attributes[$key])) {\n                    return new Collection(json_decode(Crypt::decryptString($attributes[$key]), true));\n                }\n\n                return null;\n            }\n\n            public function set($model, $key, $value, $attributes)\n            {\n                if (! is_null($value)) {\n                    return [$key => Crypt::encryptString(json_encode($value))];\n                }\n\n                return null;\n            }\n        };\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/Casts/AsStringable.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent\\Casts;\n\nuse Illuminate\\Contracts\\Database\\Eloquent\\Castable;\nuse Illuminate\\Contracts\\Database\\Eloquent\\CastsAttributes;\nuse Illuminate\\Support\\Str;\n\nclass AsStringable implements Castable\n{\n    /**\n     * Get the caster class to use when casting from / to this cast target.\n     *\n     * @param  array  $arguments\n     * @return object|string\n     */\n    public static function castUsing(array $arguments)\n    {\n        return new class implements CastsAttributes\n        {\n            public function get($model, $key, $value, $attributes)\n            {\n                return isset($value) ? Str::of($value) : null;\n            }\n\n            public function set($model, $key, $value, $attributes)\n            {\n                return isset($value) ? (string) $value : null;\n            }\n        };\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/Casts/Attribute.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent\\Casts;\n\nclass Attribute\n{\n    /**\n     * The attribute accessor.\n     *\n     * @var callable\n     */\n    public $get;\n\n    /**\n     * The attribute mutator.\n     *\n     * @var callable\n     */\n    public $set;\n\n    /**\n     * Indicates if caching of objects is enabled for this attribute.\n     *\n     * @var bool\n     */\n    public $withObjectCaching = true;\n\n    /**\n     * Create a new attribute accessor / mutator.\n     *\n     * @param  callable|null  $get\n     * @param  callable|null  $set\n     * @return void\n     */\n    public function __construct(callable $get = null, callable $set = null)\n    {\n        $this->get = $get;\n        $this->set = $set;\n    }\n\n    /**\n     * Create a new attribute accessor.\n     *\n     * @param  callable  $get\n     * @return static\n     */\n    public static function get(callable $get)\n    {\n        return new static($get);\n    }\n\n    /**\n     * Create a new attribute mutator.\n     *\n     * @param  callable  $set\n     * @return static\n     */\n    public static function set(callable $set)\n    {\n        return new static(null, $set);\n    }\n\n    /**\n     * Disable object caching for the attribute.\n     *\n     * @return static\n     */\n    public function withoutObjectCaching()\n    {\n        $this->withObjectCaching = false;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/Collection.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent;\n\nuse Illuminate\\Contracts\\Queue\\QueueableCollection;\nuse Illuminate\\Contracts\\Queue\\QueueableEntity;\nuse Illuminate\\Contracts\\Support\\Arrayable;\nuse Illuminate\\Support\\Arr;\nuse Illuminate\\Support\\Collection as BaseCollection;\nuse Illuminate\\Support\\Str;\nuse LogicException;\n\nclass Collection extends BaseCollection implements QueueableCollection\n{\n    /**\n     * Find a model in the collection by key.\n     *\n     * @param  mixed  $key\n     * @param  mixed  $default\n     * @return \\Illuminate\\Database\\Eloquent\\Model|static|null\n     */\n    public function find($key, $default = null)\n    {\n        if ($key instanceof Model) {\n            $key = $key->getKey();\n        }\n\n        if ($key instanceof Arrayable) {\n            $key = $key->toArray();\n        }\n\n        if (is_array($key)) {\n            if ($this->isEmpty()) {\n                return new static;\n            }\n\n            return $this->whereIn($this->first()->getKeyName(), $key);\n        }\n\n        return Arr::first($this->items, function ($model) use ($key) {\n            return $model->getKey() == $key;\n        }, $default);\n    }\n\n    /**\n     * Load a set of relationships onto the collection.\n     *\n     * @param  array|string  $relations\n     * @return $this\n     */\n    public function load($relations)\n    {\n        if ($this->isNotEmpty()) {\n            if (is_string($relations)) {\n                $relations = func_get_args();\n            }\n\n            $query = $this->first()->newQueryWithoutRelationships()->with($relations);\n\n            $this->items = $query->eagerLoadRelations($this->items);\n        }\n\n        return $this;\n    }\n\n    /**\n     * Load a set of aggregations over relationship's column onto the collection.\n     *\n     * @param  array|string  $relations\n     * @param  string  $column\n     * @param  string  $function\n     * @return $this\n     */\n    public function loadAggregate($relations, $column, $function = null)\n    {\n        if ($this->isEmpty()) {\n            return $this;\n        }\n\n        $models = $this->first()->newModelQuery()\n            ->whereKey($this->modelKeys())\n            ->select($this->first()->getKeyName())\n            ->withAggregate($relations, $column, $function)\n            ->get()\n            ->keyBy($this->first()->getKeyName());\n\n        $attributes = Arr::except(\n            array_keys($models->first()->getAttributes()),\n            $models->first()->getKeyName()\n        );\n\n        $this->each(function ($model) use ($models, $attributes) {\n            $extraAttributes = Arr::only($models->get($model->getKey())->getAttributes(), $attributes);\n\n            $model->forceFill($extraAttributes)\n                ->syncOriginalAttributes($attributes)\n                ->mergeCasts($models->get($model->getKey())->getCasts());\n        });\n\n        return $this;\n    }\n\n    /**\n     * Load a set of relationship counts onto the collection.\n     *\n     * @param  array|string  $relations\n     * @return $this\n     */\n    public function loadCount($relations)\n    {\n        return $this->loadAggregate($relations, '*', 'count');\n    }\n\n    /**\n     * Load a set of relationship's max column values onto the collection.\n     *\n     * @param  array|string  $relations\n     * @param  string  $column\n     * @return $this\n     */\n    public function loadMax($relations, $column)\n    {\n        return $this->loadAggregate($relations, $column, 'max');\n    }\n\n    /**\n     * Load a set of relationship's min column values onto the collection.\n     *\n     * @param  array|string  $relations\n     * @param  string  $column\n     * @return $this\n     */\n    public function loadMin($relations, $column)\n    {\n        return $this->loadAggregate($relations, $column, 'min');\n    }\n\n    /**\n     * Load a set of relationship's column summations onto the collection.\n     *\n     * @param  array|string  $relations\n     * @param  string  $column\n     * @return $this\n     */\n    public function loadSum($relations, $column)\n    {\n        return $this->loadAggregate($relations, $column, 'sum');\n    }\n\n    /**\n     * Load a set of relationship's average column values onto the collection.\n     *\n     * @param  array|string  $relations\n     * @param  string  $column\n     * @return $this\n     */\n    public function loadAvg($relations, $column)\n    {\n        return $this->loadAggregate($relations, $column, 'avg');\n    }\n\n    /**\n     * Load a set of related existences onto the collection.\n     *\n     * @param  array|string  $relations\n     * @return $this\n     */\n    public function loadExists($relations)\n    {\n        return $this->loadAggregate($relations, '*', 'exists');\n    }\n\n    /**\n     * Load a set of relationships onto the collection if they are not already eager loaded.\n     *\n     * @param  array|string  $relations\n     * @return $this\n     */\n    public function loadMissing($relations)\n    {\n        if (is_string($relations)) {\n            $relations = func_get_args();\n        }\n\n        foreach ($relations as $key => $value) {\n            if (is_numeric($key)) {\n                $key = $value;\n            }\n\n            $segments = explode('.', explode(':', $key)[0]);\n\n            if (Str::contains($key, ':')) {\n                $segments[count($segments) - 1] .= ':'.explode(':', $key)[1];\n            }\n\n            $path = [];\n\n            foreach ($segments as $segment) {\n                $path[] = [$segment => $segment];\n            }\n\n            if (is_callable($value)) {\n                $path[count($segments) - 1][end($segments)] = $value;\n            }\n\n            $this->loadMissingRelation($this, $path);\n        }\n\n        return $this;\n    }\n\n    /**\n     * Load a relationship path if it is not already eager loaded.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Collection  $models\n     * @param  array  $path\n     * @return void\n     */\n    protected function loadMissingRelation(self $models, array $path)\n    {\n        $relation = array_shift($path);\n\n        $name = explode(':', key($relation))[0];\n\n        if (is_string(reset($relation))) {\n            $relation = reset($relation);\n        }\n\n        $models->filter(function ($model) use ($name) {\n            return ! is_null($model) && ! $model->relationLoaded($name);\n        })->load($relation);\n\n        if (empty($path)) {\n            return;\n        }\n\n        $models = $models->pluck($name)->whereNotNull();\n\n        if ($models->first() instanceof BaseCollection) {\n            $models = $models->collapse();\n        }\n\n        $this->loadMissingRelation(new static($models), $path);\n    }\n\n    /**\n     * Load a set of relationships onto the mixed relationship collection.\n     *\n     * @param  string  $relation\n     * @param  array  $relations\n     * @return $this\n     */\n    public function loadMorph($relation, $relations)\n    {\n        $this->pluck($relation)\n            ->filter()\n            ->groupBy(function ($model) {\n                return get_class($model);\n            })\n            ->each(function ($models, $className) use ($relations) {\n                static::make($models)->load($relations[$className] ?? []);\n            });\n\n        return $this;\n    }\n\n    /**\n     * Load a set of relationship counts onto the mixed relationship collection.\n     *\n     * @param  string  $relation\n     * @param  array  $relations\n     * @return $this\n     */\n    public function loadMorphCount($relation, $relations)\n    {\n        $this->pluck($relation)\n            ->filter()\n            ->groupBy(function ($model) {\n                return get_class($model);\n            })\n            ->each(function ($models, $className) use ($relations) {\n                static::make($models)->loadCount($relations[$className] ?? []);\n            });\n\n        return $this;\n    }\n\n    /**\n     * Determine if a key exists in the collection.\n     *\n     * @param  mixed  $key\n     * @param  mixed  $operator\n     * @param  mixed  $value\n     * @return bool\n     */\n    public function contains($key, $operator = null, $value = null)\n    {\n        if (func_num_args() > 1 || $this->useAsCallable($key)) {\n            return parent::contains(...func_get_args());\n        }\n\n        if ($key instanceof Model) {\n            return parent::contains(function ($model) use ($key) {\n                return $model->is($key);\n            });\n        }\n\n        return parent::contains(function ($model) use ($key) {\n            return $model->getKey() == $key;\n        });\n    }\n\n    /**\n     * Get the array of primary keys.\n     *\n     * @return array\n     */\n    public function modelKeys()\n    {\n        return array_map(function ($model) {\n            return $model->getKey();\n        }, $this->items);\n    }\n\n    /**\n     * Merge the collection with the given items.\n     *\n     * @param  \\ArrayAccess|array  $items\n     * @return static\n     */\n    public function merge($items)\n    {\n        $dictionary = $this->getDictionary();\n\n        foreach ($items as $item) {\n            $dictionary[$item->getKey()] = $item;\n        }\n\n        return new static(array_values($dictionary));\n    }\n\n    /**\n     * Run a map over each of the items.\n     *\n     * @param  callable  $callback\n     * @return \\Illuminate\\Support\\Collection|static\n     */\n    public function map(callable $callback)\n    {\n        $result = parent::map($callback);\n\n        return $result->contains(function ($item) {\n            return ! $item instanceof Model;\n        }) ? $result->toBase() : $result;\n    }\n\n    /**\n     * Run an associative map over each of the items.\n     *\n     * The callback should return an associative array with a single key / value pair.\n     *\n     * @param  callable  $callback\n     * @return \\Illuminate\\Support\\Collection|static\n     */\n    public function mapWithKeys(callable $callback)\n    {\n        $result = parent::mapWithKeys($callback);\n\n        return $result->contains(function ($item) {\n            return ! $item instanceof Model;\n        }) ? $result->toBase() : $result;\n    }\n\n    /**\n     * Reload a fresh model instance from the database for all the entities.\n     *\n     * @param  array|string  $with\n     * @return static\n     */\n    public function fresh($with = [])\n    {\n        if ($this->isEmpty()) {\n            return new static;\n        }\n\n        $model = $this->first();\n\n        $freshModels = $model->newQueryWithoutScopes()\n            ->with(is_string($with) ? func_get_args() : $with)\n            ->whereIn($model->getKeyName(), $this->modelKeys())\n            ->get()\n            ->getDictionary();\n\n        return $this->filter(function ($model) use ($freshModels) {\n            return $model->exists && isset($freshModels[$model->getKey()]);\n        })\n        ->map(function ($model) use ($freshModels) {\n            return $freshModels[$model->getKey()];\n        });\n    }\n\n    /**\n     * Diff the collection with the given items.\n     *\n     * @param  \\ArrayAccess|array  $items\n     * @return static\n     */\n    public function diff($items)\n    {\n        $diff = new static;\n\n        $dictionary = $this->getDictionary($items);\n\n        foreach ($this->items as $item) {\n            if (! isset($dictionary[$item->getKey()])) {\n                $diff->add($item);\n            }\n        }\n\n        return $diff;\n    }\n\n    /**\n     * Intersect the collection with the given items.\n     *\n     * @param  \\ArrayAccess|array  $items\n     * @return static\n     */\n    public function intersect($items)\n    {\n        $intersect = new static;\n\n        if (empty($items)) {\n            return $intersect;\n        }\n\n        $dictionary = $this->getDictionary($items);\n\n        foreach ($this->items as $item) {\n            if (isset($dictionary[$item->getKey()])) {\n                $intersect->add($item);\n            }\n        }\n\n        return $intersect;\n    }\n\n    /**\n     * Return only unique items from the collection.\n     *\n     * @param  string|callable|null  $key\n     * @param  bool  $strict\n     * @return static\n     */\n    public function unique($key = null, $strict = false)\n    {\n        if (! is_null($key)) {\n            return parent::unique($key, $strict);\n        }\n\n        return new static(array_values($this->getDictionary()));\n    }\n\n    /**\n     * Returns only the models from the collection with the specified keys.\n     *\n     * @param  mixed  $keys\n     * @return static\n     */\n    public function only($keys)\n    {\n        if (is_null($keys)) {\n            return new static($this->items);\n        }\n\n        $dictionary = Arr::only($this->getDictionary(), $keys);\n\n        return new static(array_values($dictionary));\n    }\n\n    /**\n     * Returns all models in the collection except the models with specified keys.\n     *\n     * @param  mixed  $keys\n     * @return static\n     */\n    public function except($keys)\n    {\n        $dictionary = Arr::except($this->getDictionary(), $keys);\n\n        return new static(array_values($dictionary));\n    }\n\n    /**\n     * Make the given, typically visible, attributes hidden across the entire collection.\n     *\n     * @param  array|string  $attributes\n     * @return $this\n     */\n    public function makeHidden($attributes)\n    {\n        return $this->each->makeHidden($attributes);\n    }\n\n    /**\n     * Make the given, typically hidden, attributes visible across the entire collection.\n     *\n     * @param  array|string  $attributes\n     * @return $this\n     */\n    public function makeVisible($attributes)\n    {\n        return $this->each->makeVisible($attributes);\n    }\n\n    /**\n     * Append an attribute across the entire collection.\n     *\n     * @param  array|string  $attributes\n     * @return $this\n     */\n    public function append($attributes)\n    {\n        return $this->each->append($attributes);\n    }\n\n    /**\n     * Get a dictionary keyed by primary keys.\n     *\n     * @param  \\ArrayAccess|array|null  $items\n     * @return array\n     */\n    public function getDictionary($items = null)\n    {\n        $items = is_null($items) ? $this->items : $items;\n\n        $dictionary = [];\n\n        foreach ($items as $value) {\n            $dictionary[$value->getKey()] = $value;\n        }\n\n        return $dictionary;\n    }\n\n    /**\n     * The following methods are intercepted to always return base collections.\n     */\n\n    /**\n     * Get an array with the values of a given key.\n     *\n     * @param  string|array  $value\n     * @param  string|null  $key\n     * @return \\Illuminate\\Support\\Collection\n     */\n    public function pluck($value, $key = null)\n    {\n        return $this->toBase()->pluck($value, $key);\n    }\n\n    /**\n     * Get the keys of the collection items.\n     *\n     * @return \\Illuminate\\Support\\Collection\n     */\n    public function keys()\n    {\n        return $this->toBase()->keys();\n    }\n\n    /**\n     * Zip the collection together with one or more arrays.\n     *\n     * @param  mixed  ...$items\n     * @return \\Illuminate\\Support\\Collection\n     */\n    public function zip($items)\n    {\n        return $this->toBase()->zip(...func_get_args());\n    }\n\n    /**\n     * Collapse the collection of items into a single array.\n     *\n     * @return \\Illuminate\\Support\\Collection\n     */\n    public function collapse()\n    {\n        return $this->toBase()->collapse();\n    }\n\n    /**\n     * Get a flattened array of the items in the collection.\n     *\n     * @param  int  $depth\n     * @return \\Illuminate\\Support\\Collection\n     */\n    public function flatten($depth = INF)\n    {\n        return $this->toBase()->flatten($depth);\n    }\n\n    /**\n     * Flip the items in the collection.\n     *\n     * @return \\Illuminate\\Support\\Collection\n     */\n    public function flip()\n    {\n        return $this->toBase()->flip();\n    }\n\n    /**\n     * Pad collection to the specified length with a value.\n     *\n     * @param  int  $size\n     * @param  mixed  $value\n     * @return \\Illuminate\\Support\\Collection\n     */\n    public function pad($size, $value)\n    {\n        return $this->toBase()->pad($size, $value);\n    }\n\n    /**\n     * Get the comparison function to detect duplicates.\n     *\n     * @param  bool  $strict\n     * @return \\Closure\n     */\n    protected function duplicateComparator($strict)\n    {\n        return function ($a, $b) {\n            return $a->is($b);\n        };\n    }\n\n    /**\n     * Get the type of the entities being queued.\n     *\n     * @return string|null\n     *\n     * @throws \\LogicException\n     */\n    public function getQueueableClass()\n    {\n        if ($this->isEmpty()) {\n            return;\n        }\n\n        $class = get_class($this->first());\n\n        $this->each(function ($model) use ($class) {\n            if (get_class($model) !== $class) {\n                throw new LogicException('Queueing collections with multiple model types is not supported.');\n            }\n        });\n\n        return $class;\n    }\n\n    /**\n     * Get the identifiers for all of the entities.\n     *\n     * @return array\n     */\n    public function getQueueableIds()\n    {\n        if ($this->isEmpty()) {\n            return [];\n        }\n\n        return $this->first() instanceof QueueableEntity\n                    ? $this->map->getQueueableId()->all()\n                    : $this->modelKeys();\n    }\n\n    /**\n     * Get the relationships of the entities being queued.\n     *\n     * @return array\n     */\n    public function getQueueableRelations()\n    {\n        if ($this->isEmpty()) {\n            return [];\n        }\n\n        $relations = $this->map->getQueueableRelations()->all();\n\n        if (count($relations) === 0 || $relations === [[]]) {\n            return [];\n        } elseif (count($relations) === 1) {\n            return reset($relations);\n        } else {\n            return array_intersect(...array_values($relations));\n        }\n    }\n\n    /**\n     * Get the connection of the entities being queued.\n     *\n     * @return string|null\n     *\n     * @throws \\LogicException\n     */\n    public function getQueueableConnection()\n    {\n        if ($this->isEmpty()) {\n            return;\n        }\n\n        $connection = $this->first()->getConnectionName();\n\n        $this->each(function ($model) use ($connection) {\n            if ($model->getConnectionName() !== $connection) {\n                throw new LogicException('Queueing collections with multiple model connections is not supported.');\n            }\n        });\n\n        return $connection;\n    }\n\n    /**\n     * Get the Eloquent query builder from the collection.\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Builder\n     *\n     * @throws \\LogicException\n     */\n    public function toQuery()\n    {\n        $model = $this->first();\n\n        if (! $model) {\n            throw new LogicException('Unable to create query for empty collection.');\n        }\n\n        $class = get_class($model);\n\n        if ($this->filter(function ($model) use ($class) {\n            return ! $model instanceof $class;\n        })->isNotEmpty()) {\n            throw new LogicException('Unable to create query for collection with mixed types.');\n        }\n\n        return $model->newModelQuery()->whereKey($this->modelKeys());\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/Concerns/GuardsAttributes.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent\\Concerns;\n\nuse Illuminate\\Support\\Str;\n\ntrait GuardsAttributes\n{\n    /**\n     * The attributes that are mass assignable.\n     *\n     * @var string[]\n     */\n    protected $fillable = [];\n\n    /**\n     * The attributes that aren't mass assignable.\n     *\n     * @var string[]|bool\n     */\n    protected $guarded = ['*'];\n\n    /**\n     * Indicates if all mass assignment is enabled.\n     *\n     * @var bool\n     */\n    protected static $unguarded = false;\n\n    /**\n     * The actual columns that exist on the database and can be guarded.\n     *\n     * @var array\n     */\n    protected static $guardableColumns = [];\n\n    /**\n     * Get the fillable attributes for the model.\n     *\n     * @return array\n     */\n    public function getFillable()\n    {\n        return $this->fillable;\n    }\n\n    /**\n     * Set the fillable attributes for the model.\n     *\n     * @param  array  $fillable\n     * @return $this\n     */\n    public function fillable(array $fillable)\n    {\n        $this->fillable = $fillable;\n\n        return $this;\n    }\n\n    /**\n     * Merge new fillable attributes with existing fillable attributes on the model.\n     *\n     * @param  array  $fillable\n     * @return $this\n     */\n    public function mergeFillable(array $fillable)\n    {\n        $this->fillable = array_merge($this->fillable, $fillable);\n\n        return $this;\n    }\n\n    /**\n     * Get the guarded attributes for the model.\n     *\n     * @return array\n     */\n    public function getGuarded()\n    {\n        return $this->guarded === false\n                    ? []\n                    : $this->guarded;\n    }\n\n    /**\n     * Set the guarded attributes for the model.\n     *\n     * @param  array  $guarded\n     * @return $this\n     */\n    public function guard(array $guarded)\n    {\n        $this->guarded = $guarded;\n\n        return $this;\n    }\n\n    /**\n     * Merge new guarded attributes with existing guarded attributes on the model.\n     *\n     * @param  array  $guarded\n     * @return $this\n     */\n    public function mergeGuarded(array $guarded)\n    {\n        $this->guarded = array_merge($this->guarded, $guarded);\n\n        return $this;\n    }\n\n    /**\n     * Disable all mass assignable restrictions.\n     *\n     * @param  bool  $state\n     * @return void\n     */\n    public static function unguard($state = true)\n    {\n        static::$unguarded = $state;\n    }\n\n    /**\n     * Enable the mass assignment restrictions.\n     *\n     * @return void\n     */\n    public static function reguard()\n    {\n        static::$unguarded = false;\n    }\n\n    /**\n     * Determine if the current state is \"unguarded\".\n     *\n     * @return bool\n     */\n    public static function isUnguarded()\n    {\n        return static::$unguarded;\n    }\n\n    /**\n     * Run the given callable while being unguarded.\n     *\n     * @param  callable  $callback\n     * @return mixed\n     */\n    public static function unguarded(callable $callback)\n    {\n        if (static::$unguarded) {\n            return $callback();\n        }\n\n        static::unguard();\n\n        try {\n            return $callback();\n        } finally {\n            static::reguard();\n        }\n    }\n\n    /**\n     * Determine if the given attribute may be mass assigned.\n     *\n     * @param  string  $key\n     * @return bool\n     */\n    public function isFillable($key)\n    {\n        if (static::$unguarded) {\n            return true;\n        }\n\n        // If the key is in the \"fillable\" array, we can of course assume that it's\n        // a fillable attribute. Otherwise, we will check the guarded array when\n        // we need to determine if the attribute is black-listed on the model.\n        if (in_array($key, $this->getFillable())) {\n            return true;\n        }\n\n        // If the attribute is explicitly listed in the \"guarded\" array then we can\n        // return false immediately. This means this attribute is definitely not\n        // fillable and there is no point in going any further in this method.\n        if ($this->isGuarded($key)) {\n            return false;\n        }\n\n        return empty($this->getFillable()) &&\n            strpos($key, '.') === false &&\n            ! Str::startsWith($key, '_');\n    }\n\n    /**\n     * Determine if the given key is guarded.\n     *\n     * @param  string  $key\n     * @return bool\n     */\n    public function isGuarded($key)\n    {\n        if (empty($this->getGuarded())) {\n            return false;\n        }\n\n        return $this->getGuarded() == ['*'] ||\n               ! empty(preg_grep('/^'.preg_quote($key).'$/i', $this->getGuarded())) ||\n               ! $this->isGuardableColumn($key);\n    }\n\n    /**\n     * Determine if the given column is a valid, guardable column.\n     *\n     * @param  string  $key\n     * @return bool\n     */\n    protected function isGuardableColumn($key)\n    {\n        if (! isset(static::$guardableColumns[get_class($this)])) {\n            $columns = $this->getConnection()\n                        ->getSchemaBuilder()\n                        ->getColumnListing($this->getTable());\n\n            if (empty($columns)) {\n                return true;\n            }\n            static::$guardableColumns[get_class($this)] = $columns;\n        }\n\n        return in_array($key, static::$guardableColumns[get_class($this)]);\n    }\n\n    /**\n     * Determine if the model is totally guarded.\n     *\n     * @return bool\n     */\n    public function totallyGuarded()\n    {\n        return count($this->getFillable()) === 0 && $this->getGuarded() == ['*'];\n    }\n\n    /**\n     * Get the fillable attributes of a given array.\n     *\n     * @param  array  $attributes\n     * @return array\n     */\n    protected function fillableFromArray(array $attributes)\n    {\n        if (count($this->getFillable()) > 0 && ! static::$unguarded) {\n            return array_intersect_key($attributes, array_flip($this->getFillable()));\n        }\n\n        return $attributes;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/Concerns/HasAttributes.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent\\Concerns;\n\nuse Carbon\\CarbonImmutable;\nuse Carbon\\CarbonInterface;\nuse DateTimeInterface;\nuse Illuminate\\Contracts\\Database\\Eloquent\\Castable;\nuse Illuminate\\Contracts\\Database\\Eloquent\\CastsInboundAttributes;\nuse Illuminate\\Contracts\\Support\\Arrayable;\nuse Illuminate\\Database\\Eloquent\\Casts\\AsArrayObject;\nuse Illuminate\\Database\\Eloquent\\Casts\\AsCollection;\nuse Illuminate\\Database\\Eloquent\\Casts\\Attribute;\nuse Illuminate\\Database\\Eloquent\\InvalidCastException;\nuse Illuminate\\Database\\Eloquent\\JsonEncodingException;\nuse Illuminate\\Database\\Eloquent\\Relations\\Relation;\nuse Illuminate\\Database\\LazyLoadingViolationException;\nuse Illuminate\\Support\\Arr;\nuse Illuminate\\Support\\Carbon;\nuse Illuminate\\Support\\Collection as BaseCollection;\nuse Illuminate\\Support\\Facades\\Crypt;\nuse Illuminate\\Support\\Facades\\Date;\nuse Illuminate\\Support\\Str;\nuse InvalidArgumentException;\nuse LogicException;\nuse ReflectionClass;\nuse ReflectionMethod;\nuse ReflectionNamedType;\n\ntrait HasAttributes\n{\n    /**\n     * The model's attributes.\n     *\n     * @var array\n     */\n    protected $attributes = [];\n\n    /**\n     * The model attribute's original state.\n     *\n     * @var array\n     */\n    protected $original = [];\n\n    /**\n     * The changed model attributes.\n     *\n     * @var array\n     */\n    protected $changes = [];\n\n    /**\n     * The attributes that should be cast.\n     *\n     * @var array\n     */\n    protected $casts = [];\n\n    /**\n     * The attributes that have been cast using custom classes.\n     *\n     * @var array\n     */\n    protected $classCastCache = [];\n\n    /**\n     * The attributes that have been cast using \"Attribute\" return type mutators.\n     *\n     * @var array\n     */\n    protected $attributeCastCache = [];\n\n    /**\n     * The built-in, primitive cast types supported by Eloquent.\n     *\n     * @var string[]\n     */\n    protected static $primitiveCastTypes = [\n        'array',\n        'bool',\n        'boolean',\n        'collection',\n        'custom_datetime',\n        'date',\n        'datetime',\n        'decimal',\n        'double',\n        'encrypted',\n        'encrypted:array',\n        'encrypted:collection',\n        'encrypted:json',\n        'encrypted:object',\n        'float',\n        'immutable_date',\n        'immutable_datetime',\n        'immutable_custom_datetime',\n        'int',\n        'integer',\n        'json',\n        'object',\n        'real',\n        'string',\n        'timestamp',\n    ];\n\n    /**\n     * The attributes that should be mutated to dates.\n     *\n     * @deprecated Use the \"casts\" property\n     *\n     * @var array\n     */\n    protected $dates = [];\n\n    /**\n     * The storage format of the model's date columns.\n     *\n     * @var string\n     */\n    protected $dateFormat;\n\n    /**\n     * The accessors to append to the model's array form.\n     *\n     * @var array\n     */\n    protected $appends = [];\n\n    /**\n     * Indicates whether attributes are snake cased on arrays.\n     *\n     * @var bool\n     */\n    public static $snakeAttributes = true;\n\n    /**\n     * The cache of the mutated attributes for each class.\n     *\n     * @var array\n     */\n    protected static $mutatorCache = [];\n\n    /**\n     * The cache of the \"Attribute\" return type marked mutated attributes for each class.\n     *\n     * @var array\n     */\n    protected static $attributeMutatorCache = [];\n\n    /**\n     * The cache of the \"Attribute\" return type marked mutated, gettable attributes for each class.\n     *\n     * @var array\n     */\n    protected static $getAttributeMutatorCache = [];\n\n    /**\n     * The cache of the \"Attribute\" return type marked mutated, settable attributes for each class.\n     *\n     * @var array\n     */\n    protected static $setAttributeMutatorCache = [];\n\n    /**\n     * The encrypter instance that is used to encrypt attributes.\n     *\n     * @var \\Illuminate\\Contracts\\Encryption\\Encrypter\n     */\n    public static $encrypter;\n\n    /**\n     * Convert the model's attributes to an array.\n     *\n     * @return array\n     */\n    public function attributesToArray()\n    {\n        // If an attribute is a date, we will cast it to a string after converting it\n        // to a DateTime / Carbon instance. This is so we will get some consistent\n        // formatting while accessing attributes vs. arraying / JSONing a model.\n        $attributes = $this->addDateAttributesToArray(\n            $attributes = $this->getArrayableAttributes()\n        );\n\n        $attributes = $this->addMutatedAttributesToArray(\n            $attributes, $mutatedAttributes = $this->getMutatedAttributes()\n        );\n\n        // Next we will handle any casts that have been setup for this model and cast\n        // the values to their appropriate type. If the attribute has a mutator we\n        // will not perform the cast on those attributes to avoid any confusion.\n        $attributes = $this->addCastAttributesToArray(\n            $attributes, $mutatedAttributes\n        );\n\n        // Here we will grab all of the appended, calculated attributes to this model\n        // as these attributes are not really in the attributes array, but are run\n        // when we need to array or JSON the model for convenience to the coder.\n        foreach ($this->getArrayableAppends() as $key) {\n            $attributes[$key] = $this->mutateAttributeForArray($key, null);\n        }\n\n        return $attributes;\n    }\n\n    /**\n     * Add the date attributes to the attributes array.\n     *\n     * @param  array  $attributes\n     * @return array\n     */\n    protected function addDateAttributesToArray(array $attributes)\n    {\n        foreach ($this->getDates() as $key) {\n            if (! isset($attributes[$key])) {\n                continue;\n            }\n\n            $attributes[$key] = $this->serializeDate(\n                $this->asDateTime($attributes[$key])\n            );\n        }\n\n        return $attributes;\n    }\n\n    /**\n     * Add the mutated attributes to the attributes array.\n     *\n     * @param  array  $attributes\n     * @param  array  $mutatedAttributes\n     * @return array\n     */\n    protected function addMutatedAttributesToArray(array $attributes, array $mutatedAttributes)\n    {\n        foreach ($mutatedAttributes as $key) {\n            // We want to spin through all the mutated attributes for this model and call\n            // the mutator for the attribute. We cache off every mutated attributes so\n            // we don't have to constantly check on attributes that actually change.\n            if (! array_key_exists($key, $attributes)) {\n                continue;\n            }\n\n            // Next, we will call the mutator for this attribute so that we can get these\n            // mutated attribute's actual values. After we finish mutating each of the\n            // attributes we will return this final array of the mutated attributes.\n            $attributes[$key] = $this->mutateAttributeForArray(\n                $key, $attributes[$key]\n            );\n        }\n\n        return $attributes;\n    }\n\n    /**\n     * Add the casted attributes to the attributes array.\n     *\n     * @param  array  $attributes\n     * @param  array  $mutatedAttributes\n     * @return array\n     */\n    protected function addCastAttributesToArray(array $attributes, array $mutatedAttributes)\n    {\n        foreach ($this->getCasts() as $key => $value) {\n            if (! array_key_exists($key, $attributes) ||\n                in_array($key, $mutatedAttributes)) {\n                continue;\n            }\n\n            // Here we will cast the attribute. Then, if the cast is a date or datetime cast\n            // then we will serialize the date for the array. This will convert the dates\n            // to strings based on the date format specified for these Eloquent models.\n            $attributes[$key] = $this->castAttribute(\n                $key, $attributes[$key]\n            );\n\n            // If the attribute cast was a date or a datetime, we will serialize the date as\n            // a string. This allows the developers to customize how dates are serialized\n            // into an array without affecting how they are persisted into the storage.\n            if ($attributes[$key] && in_array($value, ['date', 'datetime', 'immutable_date', 'immutable_datetime'])) {\n                $attributes[$key] = $this->serializeDate($attributes[$key]);\n            }\n\n            if ($attributes[$key] && ($this->isCustomDateTimeCast($value) ||\n                $this->isImmutableCustomDateTimeCast($value))) {\n                $attributes[$key] = $attributes[$key]->format(explode(':', $value, 2)[1]);\n            }\n\n            if ($attributes[$key] && $attributes[$key] instanceof DateTimeInterface &&\n                $this->isClassCastable($key)) {\n                $attributes[$key] = $this->serializeDate($attributes[$key]);\n            }\n\n            if ($attributes[$key] && $this->isClassSerializable($key)) {\n                $attributes[$key] = $this->serializeClassCastableAttribute($key, $attributes[$key]);\n            }\n\n            if ($this->isEnumCastable($key) && (! ($attributes[$key] ?? null) instanceof Arrayable)) {\n                $attributes[$key] = isset($attributes[$key]) ? $attributes[$key]->value : null;\n            }\n\n            if ($attributes[$key] instanceof Arrayable) {\n                $attributes[$key] = $attributes[$key]->toArray();\n            }\n        }\n\n        return $attributes;\n    }\n\n    /**\n     * Get an attribute array of all arrayable attributes.\n     *\n     * @return array\n     */\n    protected function getArrayableAttributes()\n    {\n        return $this->getArrayableItems($this->getAttributes());\n    }\n\n    /**\n     * Get all of the appendable values that are arrayable.\n     *\n     * @return array\n     */\n    protected function getArrayableAppends()\n    {\n        if (! count($this->appends)) {\n            return [];\n        }\n\n        return $this->getArrayableItems(\n            array_combine($this->appends, $this->appends)\n        );\n    }\n\n    /**\n     * Get the model's relationships in array form.\n     *\n     * @return array\n     */\n    public function relationsToArray()\n    {\n        $attributes = [];\n\n        foreach ($this->getArrayableRelations() as $key => $value) {\n            // If the values implements the Arrayable interface we can just call this\n            // toArray method on the instances which will convert both models and\n            // collections to their proper array form and we'll set the values.\n            if ($value instanceof Arrayable) {\n                $relation = $value->toArray();\n            }\n\n            // If the value is null, we'll still go ahead and set it in this list of\n            // attributes since null is used to represent empty relationships if\n            // if it a has one or belongs to type relationships on the models.\n            elseif (is_null($value)) {\n                $relation = $value;\n            }\n\n            // If the relationships snake-casing is enabled, we will snake case this\n            // key so that the relation attribute is snake cased in this returned\n            // array to the developers, making this consistent with attributes.\n            if (static::$snakeAttributes) {\n                $key = Str::snake($key);\n            }\n\n            // If the relation value has been set, we will set it on this attributes\n            // list for returning. If it was not arrayable or null, we'll not set\n            // the value on the array because it is some type of invalid value.\n            if (isset($relation) || is_null($value)) {\n                $attributes[$key] = $relation;\n            }\n\n            unset($relation);\n        }\n\n        return $attributes;\n    }\n\n    /**\n     * Get an attribute array of all arrayable relations.\n     *\n     * @return array\n     */\n    protected function getArrayableRelations()\n    {\n        return $this->getArrayableItems($this->relations);\n    }\n\n    /**\n     * Get an attribute array of all arrayable values.\n     *\n     * @param  array  $values\n     * @return array\n     */\n    protected function getArrayableItems(array $values)\n    {\n        if (count($this->getVisible()) > 0) {\n            $values = array_intersect_key($values, array_flip($this->getVisible()));\n        }\n\n        if (count($this->getHidden()) > 0) {\n            $values = array_diff_key($values, array_flip($this->getHidden()));\n        }\n\n        return $values;\n    }\n\n    /**\n     * Get an attribute from the model.\n     *\n     * @param  string  $key\n     * @return mixed\n     */\n    public function getAttribute($key)\n    {\n        if (! $key) {\n            return;\n        }\n\n        // If the attribute exists in the attribute array or has a \"get\" mutator we will\n        // get the attribute's value. Otherwise, we will proceed as if the developers\n        // are asking for a relationship's value. This covers both types of values.\n        if (array_key_exists($key, $this->attributes) ||\n            array_key_exists($key, $this->casts) ||\n            $this->hasGetMutator($key) ||\n            $this->hasAttributeMutator($key) ||\n            $this->isClassCastable($key)) {\n            return $this->getAttributeValue($key);\n        }\n\n        // Here we will determine if the model base class itself contains this given key\n        // since we don't want to treat any of those methods as relationships because\n        // they are all intended as helper methods and none of these are relations.\n        if (method_exists(self::class, $key)) {\n            return;\n        }\n\n        return $this->getRelationValue($key);\n    }\n\n    /**\n     * Get a plain attribute (not a relationship).\n     *\n     * @param  string  $key\n     * @return mixed\n     */\n    public function getAttributeValue($key)\n    {\n        return $this->transformModelValue($key, $this->getAttributeFromArray($key));\n    }\n\n    /**\n     * Get an attribute from the $attributes array.\n     *\n     * @param  string  $key\n     * @return mixed\n     */\n    protected function getAttributeFromArray($key)\n    {\n        return $this->getAttributes()[$key] ?? null;\n    }\n\n    /**\n     * Get a relationship.\n     *\n     * @param  string  $key\n     * @return mixed\n     */\n    public function getRelationValue($key)\n    {\n        // If the key already exists in the relationships array, it just means the\n        // relationship has already been loaded, so we'll just return it out of\n        // here because there is no need to query within the relations twice.\n        if ($this->relationLoaded($key)) {\n            return $this->relations[$key];\n        }\n\n        if (! $this->isRelation($key)) {\n            return;\n        }\n\n        if ($this->preventsLazyLoading) {\n            $this->handleLazyLoadingViolation($key);\n        }\n\n        // If the \"attribute\" exists as a method on the model, we will just assume\n        // it is a relationship and will load and return results from the query\n        // and hydrate the relationship's value on the \"relationships\" array.\n        return $this->getRelationshipFromMethod($key);\n    }\n\n    /**\n     * Determine if the given key is a relationship method on the model.\n     *\n     * @param  string  $key\n     * @return bool\n     */\n    public function isRelation($key)\n    {\n        if ($this->hasAttributeMutator($key)) {\n            return false;\n        }\n\n        return method_exists($this, $key) ||\n            (static::$relationResolvers[get_class($this)][$key] ?? null);\n    }\n\n    /**\n     * Handle a lazy loading violation.\n     *\n     * @param  string  $key\n     * @return mixed\n     */\n    protected function handleLazyLoadingViolation($key)\n    {\n        if (isset(static::$lazyLoadingViolationCallback)) {\n            return call_user_func(static::$lazyLoadingViolationCallback, $this, $key);\n        }\n\n        if (! $this->exists || $this->wasRecentlyCreated) {\n            return;\n        }\n\n        throw new LazyLoadingViolationException($this, $key);\n    }\n\n    /**\n     * Get a relationship value from a method.\n     *\n     * @param  string  $method\n     * @return mixed\n     *\n     * @throws \\LogicException\n     */\n    protected function getRelationshipFromMethod($method)\n    {\n        $relation = $this->$method();\n\n        if (! $relation instanceof Relation) {\n            if (is_null($relation)) {\n                throw new LogicException(sprintf(\n                    '%s::%s must return a relationship instance, but \"null\" was returned. Was the \"return\" keyword used?', static::class, $method\n                ));\n            }\n\n            throw new LogicException(sprintf(\n                '%s::%s must return a relationship instance.', static::class, $method\n            ));\n        }\n\n        return tap($relation->getResults(), function ($results) use ($method) {\n            $this->setRelation($method, $results);\n        });\n    }\n\n    /**\n     * Determine if a get mutator exists for an attribute.\n     *\n     * @param  string  $key\n     * @return bool\n     */\n    public function hasGetMutator($key)\n    {\n        return method_exists($this, 'get'.Str::studly($key).'Attribute');\n    }\n\n    /**\n     * Determine if a \"Attribute\" return type marked mutator exists for an attribute.\n     *\n     * @param  string  $key\n     * @return bool\n     */\n    public function hasAttributeMutator($key)\n    {\n        if (isset(static::$attributeMutatorCache[get_class($this)][$key])) {\n            return static::$attributeMutatorCache[get_class($this)][$key];\n        }\n\n        if (! method_exists($this, $method = Str::camel($key))) {\n            return static::$attributeMutatorCache[get_class($this)][$key] = false;\n        }\n\n        $returnType = (new ReflectionMethod($this, $method))->getReturnType();\n\n        return static::$attributeMutatorCache[get_class($this)][$key] = $returnType &&\n                    $returnType instanceof ReflectionNamedType &&\n                    $returnType->getName() === Attribute::class;\n    }\n\n    /**\n     * Determine if a \"Attribute\" return type marked get mutator exists for an attribute.\n     *\n     * @param  string  $key\n     * @return bool\n     */\n    public function hasAttributeGetMutator($key)\n    {\n        if (isset(static::$getAttributeMutatorCache[get_class($this)][$key])) {\n            return static::$getAttributeMutatorCache[get_class($this)][$key];\n        }\n\n        if (! $this->hasAttributeMutator($key)) {\n            return static::$getAttributeMutatorCache[get_class($this)][$key] = false;\n        }\n\n        return static::$getAttributeMutatorCache[get_class($this)][$key] = is_callable($this->{Str::camel($key)}()->get);\n    }\n\n    /**\n     * Get the value of an attribute using its mutator.\n     *\n     * @param  string  $key\n     * @param  mixed  $value\n     * @return mixed\n     */\n    protected function mutateAttribute($key, $value)\n    {\n        return $this->{'get'.Str::studly($key).'Attribute'}($value);\n    }\n\n    /**\n     * Get the value of an \"Attribute\" return type marked attribute using its mutator.\n     *\n     * @param  string  $key\n     * @param  mixed  $value\n     * @return mixed\n     */\n    protected function mutateAttributeMarkedAttribute($key, $value)\n    {\n        if (isset($this->attributeCastCache[$key])) {\n            return $this->attributeCastCache[$key];\n        }\n\n        $attribute = $this->{Str::camel($key)}();\n\n        $value = call_user_func($attribute->get ?: function ($value) {\n            return $value;\n        }, $value, $this->attributes);\n\n        if (! is_object($value) || ! $attribute->withObjectCaching) {\n            unset($this->attributeCastCache[$key]);\n        } else {\n            $this->attributeCastCache[$key] = $value;\n        }\n\n        return $value;\n    }\n\n    /**\n     * Get the value of an attribute using its mutator for array conversion.\n     *\n     * @param  string  $key\n     * @param  mixed  $value\n     * @return mixed\n     */\n    protected function mutateAttributeForArray($key, $value)\n    {\n        if ($this->isClassCastable($key)) {\n            $value = $this->getClassCastableAttributeValue($key, $value);\n        } elseif (isset(static::$getAttributeMutatorCache[get_class($this)][$key]) &&\n                  static::$getAttributeMutatorCache[get_class($this)][$key] === true) {\n            $value = $this->mutateAttributeMarkedAttribute($key, $value);\n\n            $value = $value instanceof DateTimeInterface\n                        ? $this->serializeDate($value)\n                        : $value;\n        } else {\n            $value = $this->mutateAttribute($key, $value);\n        }\n\n        return $value instanceof Arrayable ? $value->toArray() : $value;\n    }\n\n    /**\n     * Merge new casts with existing casts on the model.\n     *\n     * @param  array  $casts\n     * @return $this\n     */\n    public function mergeCasts($casts)\n    {\n        $this->casts = array_merge($this->casts, $casts);\n\n        return $this;\n    }\n\n    /**\n     * Cast an attribute to a native PHP type.\n     *\n     * @param  string  $key\n     * @param  mixed  $value\n     * @return mixed\n     */\n    protected function castAttribute($key, $value)\n    {\n        $castType = $this->getCastType($key);\n\n        if (is_null($value) && in_array($castType, static::$primitiveCastTypes)) {\n            return $value;\n        }\n\n        // If the key is one of the encrypted castable types, we'll first decrypt\n        // the value and update the cast type so we may leverage the following\n        // logic for casting this value to any additionally specified types.\n        if ($this->isEncryptedCastable($key)) {\n            $value = $this->fromEncryptedString($value);\n\n            $castType = Str::after($castType, 'encrypted:');\n        }\n\n        switch ($castType) {\n            case 'int':\n            case 'integer':\n                return (int) $value;\n            case 'real':\n            case 'float':\n            case 'double':\n                return $this->fromFloat($value);\n            case 'decimal':\n                return $this->asDecimal($value, explode(':', $this->getCasts()[$key], 2)[1]);\n            case 'string':\n                return (string) $value;\n            case 'bool':\n            case 'boolean':\n                return (bool) $value;\n            case 'object':\n                return $this->fromJson($value, true);\n            case 'array':\n            case 'json':\n                return $this->fromJson($value);\n            case 'collection':\n                return new BaseCollection($this->fromJson($value));\n            case 'date':\n                return $this->asDate($value);\n            case 'datetime':\n            case 'custom_datetime':\n                return $this->asDateTime($value);\n            case 'immutable_date':\n                return $this->asDate($value)->toImmutable();\n            case 'immutable_custom_datetime':\n            case 'immutable_datetime':\n                return $this->asDateTime($value)->toImmutable();\n            case 'timestamp':\n                return $this->asTimestamp($value);\n        }\n\n        if ($this->isEnumCastable($key)) {\n            return $this->getEnumCastableAttributeValue($key, $value);\n        }\n\n        if ($this->isClassCastable($key)) {\n            return $this->getClassCastableAttributeValue($key, $value);\n        }\n\n        return $value;\n    }\n\n    /**\n     * Cast the given attribute using a custom cast class.\n     *\n     * @param  string  $key\n     * @param  mixed  $value\n     * @return mixed\n     */\n    protected function getClassCastableAttributeValue($key, $value)\n    {\n        if (isset($this->classCastCache[$key])) {\n            return $this->classCastCache[$key];\n        } else {\n            $caster = $this->resolveCasterClass($key);\n\n            $value = $caster instanceof CastsInboundAttributes\n                ? $value\n                : $caster->get($this, $key, $value, $this->attributes);\n\n            if ($caster instanceof CastsInboundAttributes || ! is_object($value)) {\n                unset($this->classCastCache[$key]);\n            } else {\n                $this->classCastCache[$key] = $value;\n            }\n\n            return $value;\n        }\n    }\n\n    /**\n     * Cast the given attribute to an enum.\n     *\n     * @param  string  $key\n     * @param  mixed  $value\n     * @return mixed\n     */\n    protected function getEnumCastableAttributeValue($key, $value)\n    {\n        if (is_null($value)) {\n            return;\n        }\n\n        $castType = $this->getCasts()[$key];\n\n        if ($value instanceof $castType) {\n            return $value;\n        }\n\n        return $castType::from($value);\n    }\n\n    /**\n     * Get the type of cast for a model attribute.\n     *\n     * @param  string  $key\n     * @return string\n     */\n    protected function getCastType($key)\n    {\n        if ($this->isCustomDateTimeCast($this->getCasts()[$key])) {\n            return 'custom_datetime';\n        }\n\n        if ($this->isImmutableCustomDateTimeCast($this->getCasts()[$key])) {\n            return 'immutable_custom_datetime';\n        }\n\n        if ($this->isDecimalCast($this->getCasts()[$key])) {\n            return 'decimal';\n        }\n\n        return trim(strtolower($this->getCasts()[$key]));\n    }\n\n    /**\n     * Increment or decrement the given attribute using the custom cast class.\n     *\n     * @param  string  $method\n     * @param  string  $key\n     * @param  mixed  $value\n     * @return mixed\n     */\n    protected function deviateClassCastableAttribute($method, $key, $value)\n    {\n        return $this->resolveCasterClass($key)->{$method}(\n            $this, $key, $value, $this->attributes\n        );\n    }\n\n    /**\n     * Serialize the given attribute using the custom cast class.\n     *\n     * @param  string  $key\n     * @param  mixed  $value\n     * @return mixed\n     */\n    protected function serializeClassCastableAttribute($key, $value)\n    {\n        return $this->resolveCasterClass($key)->serialize(\n            $this, $key, $value, $this->attributes\n        );\n    }\n\n    /**\n     * Determine if the cast type is a custom date time cast.\n     *\n     * @param  string  $cast\n     * @return bool\n     */\n    protected function isCustomDateTimeCast($cast)\n    {\n        return strncmp($cast, 'date:', 5) === 0 ||\n               strncmp($cast, 'datetime:', 9) === 0;\n    }\n\n    /**\n     * Determine if the cast type is an immutable custom date time cast.\n     *\n     * @param  string  $cast\n     * @return bool\n     */\n    protected function isImmutableCustomDateTimeCast($cast)\n    {\n        return strncmp($cast, 'immutable_date:', 15) === 0 ||\n               strncmp($cast, 'immutable_datetime:', 19) === 0;\n    }\n\n    /**\n     * Determine if the cast type is a decimal cast.\n     *\n     * @param  string  $cast\n     * @return bool\n     */\n    protected function isDecimalCast($cast)\n    {\n        return strncmp($cast, 'decimal:', 8) === 0;\n    }\n\n    /**\n     * Set a given attribute on the model.\n     *\n     * @param  string  $key\n     * @param  mixed  $value\n     * @return mixed\n     */\n    public function setAttribute($key, $value)\n    {\n        // First we will check for the presence of a mutator for the set operation\n        // which simply lets the developers tweak the attribute as it is set on\n        // this model, such as \"json_encoding\" a listing of data for storage.\n        if ($this->hasSetMutator($key)) {\n            return $this->setMutatedAttributeValue($key, $value);\n        } elseif ($this->hasAttributeSetMutator($key)) {\n            return $this->setAttributeMarkedMutatedAttributeValue($key, $value);\n        }\n\n        // If an attribute is listed as a \"date\", we'll convert it from a DateTime\n        // instance into a form proper for storage on the database tables using\n        // the connection grammar's date format. We will auto set the values.\n        elseif ($value && $this->isDateAttribute($key)) {\n            $value = $this->fromDateTime($value);\n        }\n\n        if ($this->isEnumCastable($key)) {\n            $this->setEnumCastableAttribute($key, $value);\n\n            return $this;\n        }\n\n        if ($this->isClassCastable($key)) {\n            $this->setClassCastableAttribute($key, $value);\n\n            return $this;\n        }\n\n        if (! is_null($value) && $this->isJsonCastable($key)) {\n            $value = $this->castAttributeAsJson($key, $value);\n        }\n\n        // If this attribute contains a JSON ->, we'll set the proper value in the\n        // attribute's underlying array. This takes care of properly nesting an\n        // attribute in the array's value in the case of deeply nested items.\n        if (Str::contains($key, '->')) {\n            return $this->fillJsonAttribute($key, $value);\n        }\n\n        if (! is_null($value) && $this->isEncryptedCastable($key)) {\n            $value = $this->castAttributeAsEncryptedString($key, $value);\n        }\n\n        $this->attributes[$key] = $value;\n\n        return $this;\n    }\n\n    /**\n     * Determine if a set mutator exists for an attribute.\n     *\n     * @param  string  $key\n     * @return bool\n     */\n    public function hasSetMutator($key)\n    {\n        return method_exists($this, 'set'.Str::studly($key).'Attribute');\n    }\n\n    /**\n     * Determine if an \"Attribute\" return type marked set mutator exists for an attribute.\n     *\n     * @param  string  $key\n     * @return bool\n     */\n    public function hasAttributeSetMutator($key)\n    {\n        $class = get_class($this);\n\n        if (isset(static::$setAttributeMutatorCache[$class][$key])) {\n            return static::$setAttributeMutatorCache[$class][$key];\n        }\n\n        if (! method_exists($this, $method = Str::camel($key))) {\n            return static::$setAttributeMutatorCache[$class][$key] = false;\n        }\n\n        $returnType = (new ReflectionMethod($this, $method))->getReturnType();\n\n        return static::$setAttributeMutatorCache[$class][$key] = $returnType &&\n                    $returnType instanceof ReflectionNamedType &&\n                    $returnType->getName() === Attribute::class &&\n                    is_callable($this->{$method}()->set);\n    }\n\n    /**\n     * Set the value of an attribute using its mutator.\n     *\n     * @param  string  $key\n     * @param  mixed  $value\n     * @return mixed\n     */\n    protected function setMutatedAttributeValue($key, $value)\n    {\n        return $this->{'set'.Str::studly($key).'Attribute'}($value);\n    }\n\n    /**\n     * Set the value of a \"Attribute\" return type marked attribute using its mutator.\n     *\n     * @param  string  $key\n     * @param  mixed  $value\n     * @return mixed\n     */\n    protected function setAttributeMarkedMutatedAttributeValue($key, $value)\n    {\n        $attribute = $this->{Str::camel($key)}();\n\n        $callback = $attribute->set ?: function ($value) use ($key) {\n            $this->attributes[$key] = $value;\n        };\n\n        $this->attributes = array_merge(\n            $this->attributes,\n            $this->normalizeCastClassResponse(\n                $key, call_user_func($callback, $value, $this->attributes)\n            )\n        );\n\n        if (! is_object($value) || ! $attribute->withObjectCaching) {\n            unset($this->attributeCastCache[$key]);\n        } else {\n            $this->attributeCastCache[$key] = $value;\n        }\n    }\n\n    /**\n     * Determine if the given attribute is a date or date castable.\n     *\n     * @param  string  $key\n     * @return bool\n     */\n    protected function isDateAttribute($key)\n    {\n        return in_array($key, $this->getDates(), true) ||\n            $this->isDateCastable($key);\n    }\n\n    /**\n     * Set a given JSON attribute on the model.\n     *\n     * @param  string  $key\n     * @param  mixed  $value\n     * @return $this\n     */\n    public function fillJsonAttribute($key, $value)\n    {\n        [$key, $path] = explode('->', $key, 2);\n\n        $value = $this->asJson($this->getArrayAttributeWithValue(\n            $path, $key, $value\n        ));\n\n        $this->attributes[$key] = $this->isEncryptedCastable($key)\n            ? $this->castAttributeAsEncryptedString($key, $value)\n            : $value;\n\n        return $this;\n    }\n\n    /**\n     * Set the value of a class castable attribute.\n     *\n     * @param  string  $key\n     * @param  mixed  $value\n     * @return void\n     */\n    protected function setClassCastableAttribute($key, $value)\n    {\n        $caster = $this->resolveCasterClass($key);\n\n        if (is_null($value)) {\n            $this->attributes = array_merge($this->attributes, array_map(\n                function () {\n                },\n                $this->normalizeCastClassResponse($key, $caster->set(\n                    $this, $key, $this->{$key}, $this->attributes\n                ))\n            ));\n        } else {\n            $this->attributes = array_merge(\n                $this->attributes,\n                $this->normalizeCastClassResponse($key, $caster->set(\n                    $this, $key, $value, $this->attributes\n                ))\n            );\n        }\n\n        if ($caster instanceof CastsInboundAttributes || ! is_object($value)) {\n            unset($this->classCastCache[$key]);\n        } else {\n            $this->classCastCache[$key] = $value;\n        }\n    }\n\n    /**\n     * Set the value of an enum castable attribute.\n     *\n     * @param  string  $key\n     * @param  \\BackedEnum  $value\n     * @return void\n     */\n    protected function setEnumCastableAttribute($key, $value)\n    {\n        $enumClass = $this->getCasts()[$key];\n\n        if (! isset($value)) {\n            $this->attributes[$key] = null;\n        } elseif ($value instanceof $enumClass) {\n            $this->attributes[$key] = $value->value;\n        } else {\n            $this->attributes[$key] = $enumClass::from($value)->value;\n        }\n    }\n\n    /**\n     * Get an array attribute with the given key and value set.\n     *\n     * @param  string  $path\n     * @param  string  $key\n     * @param  mixed  $value\n     * @return $this\n     */\n    protected function getArrayAttributeWithValue($path, $key, $value)\n    {\n        return tap($this->getArrayAttributeByKey($key), function (&$array) use ($path, $value) {\n            Arr::set($array, str_replace('->', '.', $path), $value);\n        });\n    }\n\n    /**\n     * Get an array attribute or return an empty array if it is not set.\n     *\n     * @param  string  $key\n     * @return array\n     */\n    protected function getArrayAttributeByKey($key)\n    {\n        if (! isset($this->attributes[$key])) {\n            return [];\n        }\n\n        return $this->fromJson(\n            $this->isEncryptedCastable($key)\n                ? $this->fromEncryptedString($this->attributes[$key])\n                : $this->attributes[$key]\n        );\n    }\n\n    /**\n     * Cast the given attribute to JSON.\n     *\n     * @param  string  $key\n     * @param  mixed  $value\n     * @return string\n     */\n    protected function castAttributeAsJson($key, $value)\n    {\n        $value = $this->asJson($value);\n\n        if ($value === false) {\n            throw JsonEncodingException::forAttribute(\n                $this, $key, json_last_error_msg()\n            );\n        }\n\n        return $value;\n    }\n\n    /**\n     * Encode the given value as JSON.\n     *\n     * @param  mixed  $value\n     * @return string\n     */\n    protected function asJson($value)\n    {\n        return json_encode($value);\n    }\n\n    /**\n     * Decode the given JSON back into an array or object.\n     *\n     * @param  string  $value\n     * @param  bool  $asObject\n     * @return mixed\n     */\n    public function fromJson($value, $asObject = false)\n    {\n        return json_decode($value, ! $asObject);\n    }\n\n    /**\n     * Decrypt the given encrypted string.\n     *\n     * @param  string  $value\n     * @return mixed\n     */\n    public function fromEncryptedString($value)\n    {\n        return (static::$encrypter ?? Crypt::getFacadeRoot())->decrypt($value, false);\n    }\n\n    /**\n     * Cast the given attribute to an encrypted string.\n     *\n     * @param  string  $key\n     * @param  mixed  $value\n     * @return string\n     */\n    protected function castAttributeAsEncryptedString($key, $value)\n    {\n        return (static::$encrypter ?? Crypt::getFacadeRoot())->encrypt($value, false);\n    }\n\n    /**\n     * Set the encrypter instance that will be used to encrypt attributes.\n     *\n     * @param  \\Illuminate\\Contracts\\Encryption\\Encrypter  $encrypter\n     * @return void\n     */\n    public static function encryptUsing($encrypter)\n    {\n        static::$encrypter = $encrypter;\n    }\n\n    /**\n     * Decode the given float.\n     *\n     * @param  mixed  $value\n     * @return mixed\n     */\n    public function fromFloat($value)\n    {\n        switch ((string) $value) {\n            case 'Infinity':\n                return INF;\n            case '-Infinity':\n                return -INF;\n            case 'NaN':\n                return NAN;\n            default:\n                return (float) $value;\n        }\n    }\n\n    /**\n     * Return a decimal as string.\n     *\n     * @param  float  $value\n     * @param  int  $decimals\n     * @return string\n     */\n    protected function asDecimal($value, $decimals)\n    {\n        return number_format($value, $decimals, '.', '');\n    }\n\n    /**\n     * Return a timestamp as DateTime object with time set to 00:00:00.\n     *\n     * @param  mixed  $value\n     * @return \\Illuminate\\Support\\Carbon\n     */\n    protected function asDate($value)\n    {\n        return $this->asDateTime($value)->startOfDay();\n    }\n\n    /**\n     * Return a timestamp as DateTime object.\n     *\n     * @param  mixed  $value\n     * @return \\Illuminate\\Support\\Carbon\n     */\n    protected function asDateTime($value)\n    {\n        // If this value is already a Carbon instance, we shall just return it as is.\n        // This prevents us having to re-instantiate a Carbon instance when we know\n        // it already is one, which wouldn't be fulfilled by the DateTime check.\n        if ($value instanceof CarbonInterface) {\n            return Date::instance($value);\n        }\n\n        // If the value is already a DateTime instance, we will just skip the rest of\n        // these checks since they will be a waste of time, and hinder performance\n        // when checking the field. We will just return the DateTime right away.\n        if ($value instanceof DateTimeInterface) {\n            return Date::parse(\n                $value->format('Y-m-d H:i:s.u'), $value->getTimezone()\n            );\n        }\n\n        // If this value is an integer, we will assume it is a UNIX timestamp's value\n        // and format a Carbon object from this timestamp. This allows flexibility\n        // when defining your date fields as they might be UNIX timestamps here.\n        if (is_numeric($value)) {\n            return Date::createFromTimestamp($value);\n        }\n\n        // If the value is in simply year, month, day format, we will instantiate the\n        // Carbon instances from that format. Again, this provides for simple date\n        // fields on the database, while still supporting Carbonized conversion.\n        if ($this->isStandardDateFormat($value)) {\n            return Date::instance(Carbon::createFromFormat('Y-m-d', $value)->startOfDay());\n        }\n\n        $format = $this->getDateFormat();\n\n        // Finally, we will just assume this date is in the format used by default on\n        // the database connection and use that format to create the Carbon object\n        // that is returned back out to the developers after we convert it here.\n        try {\n            $date = Date::createFromFormat($format, $value);\n        } catch (InvalidArgumentException $e) {\n            $date = false;\n        }\n\n        return $date ?: Date::parse($value);\n    }\n\n    /**\n     * Determine if the given value is a standard date format.\n     *\n     * @param  string  $value\n     * @return bool\n     */\n    protected function isStandardDateFormat($value)\n    {\n        return preg_match('/^(\\d{4})-(\\d{1,2})-(\\d{1,2})$/', $value);\n    }\n\n    /**\n     * Convert a DateTime to a storable string.\n     *\n     * @param  mixed  $value\n     * @return string|null\n     */\n    public function fromDateTime($value)\n    {\n        return empty($value) ? $value : $this->asDateTime($value)->format(\n            $this->getDateFormat()\n        );\n    }\n\n    /**\n     * Return a timestamp as unix timestamp.\n     *\n     * @param  mixed  $value\n     * @return int\n     */\n    protected function asTimestamp($value)\n    {\n        return $this->asDateTime($value)->getTimestamp();\n    }\n\n    /**\n     * Prepare a date for array / JSON serialization.\n     *\n     * @param  \\DateTimeInterface  $date\n     * @return string\n     */\n    protected function serializeDate(DateTimeInterface $date)\n    {\n        return $date instanceof \\DateTimeImmutable ?\n            CarbonImmutable::instance($date)->toJSON() :\n            Carbon::instance($date)->toJSON();\n    }\n\n    /**\n     * Get the attributes that should be converted to dates.\n     *\n     * @return array\n     */\n    public function getDates()\n    {\n        if (! $this->usesTimestamps()) {\n            return $this->dates;\n        }\n\n        $defaults = [\n            $this->getCreatedAtColumn(),\n            $this->getUpdatedAtColumn(),\n        ];\n\n        return array_unique(array_merge($this->dates, $defaults));\n    }\n\n    /**\n     * Get the format for database stored dates.\n     *\n     * @return string\n     */\n    public function getDateFormat()\n    {\n        return $this->dateFormat ?: $this->getConnection()->getQueryGrammar()->getDateFormat();\n    }\n\n    /**\n     * Set the date format used by the model.\n     *\n     * @param  string  $format\n     * @return $this\n     */\n    public function setDateFormat($format)\n    {\n        $this->dateFormat = $format;\n\n        return $this;\n    }\n\n    /**\n     * Determine whether an attribute should be cast to a native type.\n     *\n     * @param  string  $key\n     * @param  array|string|null  $types\n     * @return bool\n     */\n    public function hasCast($key, $types = null)\n    {\n        if (array_key_exists($key, $this->getCasts())) {\n            return $types ? in_array($this->getCastType($key), (array) $types, true) : true;\n        }\n\n        return false;\n    }\n\n    /**\n     * Get the casts array.\n     *\n     * @return array\n     */\n    public function getCasts()\n    {\n        if ($this->getIncrementing()) {\n            return array_merge([$this->getKeyName() => $this->getKeyType()], $this->casts);\n        }\n\n        return $this->casts;\n    }\n\n    /**\n     * Determine whether a value is Date / DateTime castable for inbound manipulation.\n     *\n     * @param  string  $key\n     * @return bool\n     */\n    protected function isDateCastable($key)\n    {\n        return $this->hasCast($key, ['date', 'datetime', 'immutable_date', 'immutable_datetime']);\n    }\n\n    /**\n     * Determine whether a value is Date / DateTime custom-castable for inbound manipulation.\n     *\n     * @param  string  $key\n     * @return bool\n     */\n    protected function isDateCastableWithCustomFormat($key)\n    {\n        return $this->hasCast($key, ['custom_datetime', 'immutable_custom_datetime']);\n    }\n\n    /**\n     * Determine whether a value is JSON castable for inbound manipulation.\n     *\n     * @param  string  $key\n     * @return bool\n     */\n    protected function isJsonCastable($key)\n    {\n        return $this->hasCast($key, ['array', 'json', 'object', 'collection', 'encrypted:array', 'encrypted:collection', 'encrypted:json', 'encrypted:object']);\n    }\n\n    /**\n     * Determine whether a value is an encrypted castable for inbound manipulation.\n     *\n     * @param  string  $key\n     * @return bool\n     */\n    protected function isEncryptedCastable($key)\n    {\n        return $this->hasCast($key, ['encrypted', 'encrypted:array', 'encrypted:collection', 'encrypted:json', 'encrypted:object']);\n    }\n\n    /**\n     * Determine if the given key is cast using a custom class.\n     *\n     * @param  string  $key\n     * @return bool\n     *\n     * @throws \\Illuminate\\Database\\Eloquent\\InvalidCastException\n     */\n    protected function isClassCastable($key)\n    {\n        if (! array_key_exists($key, $this->getCasts())) {\n            return false;\n        }\n\n        $castType = $this->parseCasterClass($this->getCasts()[$key]);\n\n        if (in_array($castType, static::$primitiveCastTypes)) {\n            return false;\n        }\n\n        if (class_exists($castType)) {\n            return true;\n        }\n\n        throw new InvalidCastException($this->getModel(), $key, $castType);\n    }\n\n    /**\n     * Determine if the given key is cast using an enum.\n     *\n     * @param  string  $key\n     * @return bool\n     */\n    protected function isEnumCastable($key)\n    {\n        if (! array_key_exists($key, $this->getCasts())) {\n            return false;\n        }\n\n        $castType = $this->getCasts()[$key];\n\n        if (in_array($castType, static::$primitiveCastTypes)) {\n            return false;\n        }\n\n        if (function_exists('enum_exists') && enum_exists($castType)) {\n            return true;\n        }\n    }\n\n    /**\n     * Determine if the key is deviable using a custom class.\n     *\n     * @param  string  $key\n     * @return bool\n     *\n     * @throws \\Illuminate\\Database\\Eloquent\\InvalidCastException\n     */\n    protected function isClassDeviable($key)\n    {\n        return $this->isClassCastable($key) &&\n            method_exists($castType = $this->parseCasterClass($this->getCasts()[$key]), 'increment') &&\n            method_exists($castType, 'decrement');\n    }\n\n    /**\n     * Determine if the key is serializable using a custom class.\n     *\n     * @param  string  $key\n     * @return bool\n     *\n     * @throws \\Illuminate\\Database\\Eloquent\\InvalidCastException\n     */\n    protected function isClassSerializable($key)\n    {\n        return ! $this->isEnumCastable($key) &&\n            $this->isClassCastable($key) &&\n            method_exists($this->resolveCasterClass($key), 'serialize');\n    }\n\n    /**\n     * Resolve the custom caster class for a given key.\n     *\n     * @param  string  $key\n     * @return mixed\n     */\n    protected function resolveCasterClass($key)\n    {\n        $castType = $this->getCasts()[$key];\n\n        $arguments = [];\n\n        if (is_string($castType) && strpos($castType, ':') !== false) {\n            $segments = explode(':', $castType, 2);\n\n            $castType = $segments[0];\n            $arguments = explode(',', $segments[1]);\n        }\n\n        if (is_subclass_of($castType, Castable::class)) {\n            $castType = $castType::castUsing($arguments);\n        }\n\n        if (is_object($castType)) {\n            return $castType;\n        }\n\n        return new $castType(...$arguments);\n    }\n\n    /**\n     * Parse the given caster class, removing any arguments.\n     *\n     * @param  string  $class\n     * @return string\n     */\n    protected function parseCasterClass($class)\n    {\n        return strpos($class, ':') === false\n            ? $class\n            : explode(':', $class, 2)[0];\n    }\n\n    /**\n     * Merge the cast class and attribute cast attributes back into the model.\n     *\n     * @return void\n     */\n    protected function mergeAttributesFromCachedCasts()\n    {\n        $this->mergeAttributesFromClassCasts();\n        $this->mergeAttributesFromAttributeCasts();\n    }\n\n    /**\n     * Merge the cast class attributes back into the model.\n     *\n     * @return void\n     */\n    protected function mergeAttributesFromClassCasts()\n    {\n        foreach ($this->classCastCache as $key => $value) {\n            $caster = $this->resolveCasterClass($key);\n\n            $this->attributes = array_merge(\n                $this->attributes,\n                $caster instanceof CastsInboundAttributes\n                    ? [$key => $value]\n                    : $this->normalizeCastClassResponse($key, $caster->set($this, $key, $value, $this->attributes))\n            );\n        }\n    }\n\n    /**\n     * Merge the cast class attributes back into the model.\n     *\n     * @return void\n     */\n    protected function mergeAttributesFromAttributeCasts()\n    {\n        foreach ($this->attributeCastCache as $key => $value) {\n            $attribute = $this->{Str::camel($key)}();\n\n            if ($attribute->get && ! $attribute->set) {\n                continue;\n            }\n\n            $callback = $attribute->set ?: function ($value) use ($key) {\n                $this->attributes[$key] = $value;\n            };\n\n            $this->attributes = array_merge(\n                $this->attributes,\n                $this->normalizeCastClassResponse(\n                    $key, call_user_func($callback, $value, $this->attributes)\n                )\n            );\n        }\n    }\n\n    /**\n     * Normalize the response from a custom class caster.\n     *\n     * @param  string  $key\n     * @param  mixed  $value\n     * @return array\n     */\n    protected function normalizeCastClassResponse($key, $value)\n    {\n        return is_array($value) ? $value : [$key => $value];\n    }\n\n    /**\n     * Get all of the current attributes on the model.\n     *\n     * @return array\n     */\n    public function getAttributes()\n    {\n        $this->mergeAttributesFromCachedCasts();\n\n        return $this->attributes;\n    }\n\n    /**\n     * Get all of the current attributes on the model for an insert operation.\n     *\n     * @return array\n     */\n    protected function getAttributesForInsert()\n    {\n        return $this->getAttributes();\n    }\n\n    /**\n     * Set the array of model attributes. No checking is done.\n     *\n     * @param  array  $attributes\n     * @param  bool  $sync\n     * @return $this\n     */\n    public function setRawAttributes(array $attributes, $sync = false)\n    {\n        $this->attributes = $attributes;\n\n        if ($sync) {\n            $this->syncOriginal();\n        }\n\n        $this->classCastCache = [];\n        $this->attributeCastCache = [];\n\n        return $this;\n    }\n\n    /**\n     * Get the model's original attribute values.\n     *\n     * @param  string|null  $key\n     * @param  mixed  $default\n     * @return mixed|array\n     */\n    public function getOriginal($key = null, $default = null)\n    {\n        return (new static)->setRawAttributes(\n            $this->original, $sync = true\n        )->getOriginalWithoutRewindingModel($key, $default);\n    }\n\n    /**\n     * Get the model's original attribute values.\n     *\n     * @param  string|null  $key\n     * @param  mixed  $default\n     * @return mixed|array\n     */\n    protected function getOriginalWithoutRewindingModel($key = null, $default = null)\n    {\n        if ($key) {\n            return $this->transformModelValue(\n                $key, Arr::get($this->original, $key, $default)\n            );\n        }\n\n        return collect($this->original)->mapWithKeys(function ($value, $key) {\n            return [$key => $this->transformModelValue($key, $value)];\n        })->all();\n    }\n\n    /**\n     * Get the model's raw original attribute values.\n     *\n     * @param  string|null  $key\n     * @param  mixed  $default\n     * @return mixed|array\n     */\n    public function getRawOriginal($key = null, $default = null)\n    {\n        return Arr::get($this->original, $key, $default);\n    }\n\n    /**\n     * Get a subset of the model's attributes.\n     *\n     * @param  array|mixed  $attributes\n     * @return array\n     */\n    public function only($attributes)\n    {\n        $results = [];\n\n        foreach (is_array($attributes) ? $attributes : func_get_args() as $attribute) {\n            $results[$attribute] = $this->getAttribute($attribute);\n        }\n\n        return $results;\n    }\n\n    /**\n     * Sync the original attributes with the current.\n     *\n     * @return $this\n     */\n    public function syncOriginal()\n    {\n        $this->original = $this->getAttributes();\n\n        return $this;\n    }\n\n    /**\n     * Sync a single original attribute with its current value.\n     *\n     * @param  string  $attribute\n     * @return $this\n     */\n    public function syncOriginalAttribute($attribute)\n    {\n        return $this->syncOriginalAttributes($attribute);\n    }\n\n    /**\n     * Sync multiple original attribute with their current values.\n     *\n     * @param  array|string  $attributes\n     * @return $this\n     */\n    public function syncOriginalAttributes($attributes)\n    {\n        $attributes = is_array($attributes) ? $attributes : func_get_args();\n\n        $modelAttributes = $this->getAttributes();\n\n        foreach ($attributes as $attribute) {\n            $this->original[$attribute] = $modelAttributes[$attribute];\n        }\n\n        return $this;\n    }\n\n    /**\n     * Sync the changed attributes.\n     *\n     * @return $this\n     */\n    public function syncChanges()\n    {\n        $this->changes = $this->getDirty();\n\n        return $this;\n    }\n\n    /**\n     * Determine if the model or any of the given attribute(s) have been modified.\n     *\n     * @param  array|string|null  $attributes\n     * @return bool\n     */\n    public function isDirty($attributes = null)\n    {\n        return $this->hasChanges(\n            $this->getDirty(), is_array($attributes) ? $attributes : func_get_args()\n        );\n    }\n\n    /**\n     * Determine if the model or all the given attribute(s) have remained the same.\n     *\n     * @param  array|string|null  $attributes\n     * @return bool\n     */\n    public function isClean($attributes = null)\n    {\n        return ! $this->isDirty(...func_get_args());\n    }\n\n    /**\n     * Determine if the model or any of the given attribute(s) have been modified.\n     *\n     * @param  array|string|null  $attributes\n     * @return bool\n     */\n    public function wasChanged($attributes = null)\n    {\n        return $this->hasChanges(\n            $this->getChanges(), is_array($attributes) ? $attributes : func_get_args()\n        );\n    }\n\n    /**\n     * Determine if any of the given attributes were changed.\n     *\n     * @param  array  $changes\n     * @param  array|string|null  $attributes\n     * @return bool\n     */\n    protected function hasChanges($changes, $attributes = null)\n    {\n        // If no specific attributes were provided, we will just see if the dirty array\n        // already contains any attributes. If it does we will just return that this\n        // count is greater than zero. Else, we need to check specific attributes.\n        if (empty($attributes)) {\n            return count($changes) > 0;\n        }\n\n        // Here we will spin through every attribute and see if this is in the array of\n        // dirty attributes. If it is, we will return true and if we make it through\n        // all of the attributes for the entire array we will return false at end.\n        foreach (Arr::wrap($attributes) as $attribute) {\n            if (array_key_exists($attribute, $changes)) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * Get the attributes that have been changed since the last sync.\n     *\n     * @return array\n     */\n    public function getDirty()\n    {\n        $dirty = [];\n\n        foreach ($this->getAttributes() as $key => $value) {\n            if (! $this->originalIsEquivalent($key)) {\n                $dirty[$key] = $value;\n            }\n        }\n\n        return $dirty;\n    }\n\n    /**\n     * Get the attributes that were changed.\n     *\n     * @return array\n     */\n    public function getChanges()\n    {\n        return $this->changes;\n    }\n\n    /**\n     * Determine if the new and old values for a given key are equivalent.\n     *\n     * @param  string  $key\n     * @return bool\n     */\n    public function originalIsEquivalent($key)\n    {\n        if (! array_key_exists($key, $this->original)) {\n            return false;\n        }\n\n        $attribute = Arr::get($this->attributes, $key);\n        $original = Arr::get($this->original, $key);\n\n        if ($attribute === $original) {\n            return true;\n        } elseif (is_null($attribute)) {\n            return false;\n        } elseif ($this->isDateAttribute($key) || $this->isDateCastableWithCustomFormat($key)) {\n            return $this->fromDateTime($attribute) ===\n                $this->fromDateTime($original);\n        } elseif ($this->hasCast($key, ['object', 'collection'])) {\n            return $this->fromJson($attribute) ===\n                $this->fromJson($original);\n        } elseif ($this->hasCast($key, ['real', 'float', 'double'])) {\n            if (($attribute === null && $original !== null) || ($attribute !== null && $original === null)) {\n                return false;\n            }\n\n            return abs($this->castAttribute($key, $attribute) - $this->castAttribute($key, $original)) < PHP_FLOAT_EPSILON * 4;\n        } elseif ($this->hasCast($key, static::$primitiveCastTypes)) {\n            return $this->castAttribute($key, $attribute) ===\n                $this->castAttribute($key, $original);\n        } elseif ($this->isClassCastable($key) && in_array($this->getCasts()[$key], [AsArrayObject::class, AsCollection::class])) {\n            return $this->fromJson($attribute) === $this->fromJson($original);\n        }\n\n        return is_numeric($attribute) && is_numeric($original)\n            && strcmp((string) $attribute, (string) $original) === 0;\n    }\n\n    /**\n     * Transform a raw model value using mutators, casts, etc.\n     *\n     * @param  string  $key\n     * @param  mixed  $value\n     * @return mixed\n     */\n    protected function transformModelValue($key, $value)\n    {\n        // If the attribute has a get mutator, we will call that then return what\n        // it returns as the value, which is useful for transforming values on\n        // retrieval from the model to a form that is more useful for usage.\n        if ($this->hasGetMutator($key)) {\n            return $this->mutateAttribute($key, $value);\n        } elseif ($this->hasAttributeGetMutator($key)) {\n            return $this->mutateAttributeMarkedAttribute($key, $value);\n        }\n\n        // If the attribute exists within the cast array, we will convert it to\n        // an appropriate native PHP type dependent upon the associated value\n        // given with the key in the pair. Dayle made this comment line up.\n        if ($this->hasCast($key)) {\n            return $this->castAttribute($key, $value);\n        }\n\n        // If the attribute is listed as a date, we will convert it to a DateTime\n        // instance on retrieval, which makes it quite convenient to work with\n        // date fields without having to create a mutator for each property.\n        if ($value !== null\n            && \\in_array($key, $this->getDates(), false)) {\n            return $this->asDateTime($value);\n        }\n\n        return $value;\n    }\n\n    /**\n     * Append attributes to query when building a query.\n     *\n     * @param  array|string  $attributes\n     * @return $this\n     */\n    public function append($attributes)\n    {\n        $this->appends = array_unique(\n            array_merge($this->appends, is_string($attributes) ? func_get_args() : $attributes)\n        );\n\n        return $this;\n    }\n\n    /**\n     * Set the accessors to append to model arrays.\n     *\n     * @param  array  $appends\n     * @return $this\n     */\n    public function setAppends(array $appends)\n    {\n        $this->appends = $appends;\n\n        return $this;\n    }\n\n    /**\n     * Return whether the accessor attribute has been appended.\n     *\n     * @param  string  $attribute\n     * @return bool\n     */\n    public function hasAppended($attribute)\n    {\n        return in_array($attribute, $this->appends);\n    }\n\n    /**\n     * Get the mutated attributes for a given instance.\n     *\n     * @return array\n     */\n    public function getMutatedAttributes()\n    {\n        $class = static::class;\n\n        if (! isset(static::$mutatorCache[$class])) {\n            static::cacheMutatedAttributes($class);\n        }\n\n        return static::$mutatorCache[$class];\n    }\n\n    /**\n     * Extract and cache all the mutated attributes of a class.\n     *\n     * @param  string  $class\n     * @return void\n     */\n    public static function cacheMutatedAttributes($class)\n    {\n        static::$getAttributeMutatorCache[$class] =\n            collect($attributeMutatorMethods = static::getAttributeMarkedMutatorMethods($class))\n                    ->mapWithKeys(function ($match) {\n                        return [lcfirst(static::$snakeAttributes ? Str::snake($match) : $match) => true];\n                    })->all();\n\n        static::$mutatorCache[$class] = collect(static::getMutatorMethods($class))\n                ->merge($attributeMutatorMethods)\n                ->map(function ($match) {\n                    return lcfirst(static::$snakeAttributes ? Str::snake($match) : $match);\n                })->all();\n    }\n\n    /**\n     * Get all of the attribute mutator methods.\n     *\n     * @param  mixed  $class\n     * @return array\n     */\n    protected static function getMutatorMethods($class)\n    {\n        preg_match_all('/(?<=^|;)get([^;]+?)Attribute(;|$)/', implode(';', get_class_methods($class)), $matches);\n\n        return $matches[1];\n    }\n\n    /**\n     * Get all of the \"Attribute\" return typed attribute mutator methods.\n     *\n     * @param  mixed  $class\n     * @return array\n     */\n    protected static function getAttributeMarkedMutatorMethods($class)\n    {\n        $instance = is_object($class) ? $class : new $class;\n\n        return collect((new ReflectionClass($instance))->getMethods())->filter(function ($method) use ($instance) {\n            $returnType = $method->getReturnType();\n\n            if ($returnType &&\n                $returnType instanceof ReflectionNamedType &&\n                $returnType->getName() === Attribute::class) {\n                $method->setAccessible(true);\n\n                if (is_callable($method->invoke($instance)->get)) {\n                    return true;\n                }\n            }\n\n            return false;\n        })->map->name->values()->all();\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/Concerns/HasEvents.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent\\Concerns;\n\nuse Illuminate\\Contracts\\Events\\Dispatcher;\nuse Illuminate\\Events\\NullDispatcher;\nuse Illuminate\\Support\\Arr;\nuse InvalidArgumentException;\n\ntrait HasEvents\n{\n    /**\n     * The event map for the model.\n     *\n     * Allows for object-based events for native Eloquent events.\n     *\n     * @var array\n     */\n    protected $dispatchesEvents = [];\n\n    /**\n     * User exposed observable events.\n     *\n     * These are extra user-defined events observers may subscribe to.\n     *\n     * @var array\n     */\n    protected $observables = [];\n\n    /**\n     * Register observers with the model.\n     *\n     * @param  object|array|string  $classes\n     * @return void\n     *\n     * @throws \\RuntimeException\n     */\n    public static function observe($classes)\n    {\n        $instance = new static;\n\n        foreach (Arr::wrap($classes) as $class) {\n            $instance->registerObserver($class);\n        }\n    }\n\n    /**\n     * Register a single observer with the model.\n     *\n     * @param  object|string  $class\n     * @return void\n     *\n     * @throws \\RuntimeException\n     */\n    protected function registerObserver($class)\n    {\n        $className = $this->resolveObserverClassName($class);\n\n        // When registering a model observer, we will spin through the possible events\n        // and determine if this observer has that method. If it does, we will hook\n        // it into the model's event system, making it convenient to watch these.\n        foreach ($this->getObservableEvents() as $event) {\n            if (method_exists($class, $event)) {\n                static::registerModelEvent($event, $className.'@'.$event);\n            }\n        }\n    }\n\n    /**\n     * Resolve the observer's class name from an object or string.\n     *\n     * @param  object|string  $class\n     * @return string\n     *\n     * @throws \\InvalidArgumentException\n     */\n    private function resolveObserverClassName($class)\n    {\n        if (is_object($class)) {\n            return get_class($class);\n        }\n\n        if (class_exists($class)) {\n            return $class;\n        }\n\n        throw new InvalidArgumentException('Unable to find observer: '.$class);\n    }\n\n    /**\n     * Get the observable event names.\n     *\n     * @return array\n     */\n    public function getObservableEvents()\n    {\n        return array_merge(\n            [\n                'retrieved', 'creating', 'created', 'updating', 'updated',\n                'saving', 'saved', 'restoring', 'restored', 'replicating',\n                'deleting', 'deleted', 'forceDeleted',\n            ],\n            $this->observables\n        );\n    }\n\n    /**\n     * Set the observable event names.\n     *\n     * @param  array  $observables\n     * @return $this\n     */\n    public function setObservableEvents(array $observables)\n    {\n        $this->observables = $observables;\n\n        return $this;\n    }\n\n    /**\n     * Add an observable event name.\n     *\n     * @param  array|mixed  $observables\n     * @return void\n     */\n    public function addObservableEvents($observables)\n    {\n        $this->observables = array_unique(array_merge(\n            $this->observables, is_array($observables) ? $observables : func_get_args()\n        ));\n    }\n\n    /**\n     * Remove an observable event name.\n     *\n     * @param  array|mixed  $observables\n     * @return void\n     */\n    public function removeObservableEvents($observables)\n    {\n        $this->observables = array_diff(\n            $this->observables, is_array($observables) ? $observables : func_get_args()\n        );\n    }\n\n    /**\n     * Register a model event with the dispatcher.\n     *\n     * @param  string  $event\n     * @param  \\Illuminate\\Events\\QueuedClosure|\\Closure|string  $callback\n     * @return void\n     */\n    protected static function registerModelEvent($event, $callback)\n    {\n        if (isset(static::$dispatcher)) {\n            $name = static::class;\n\n            static::$dispatcher->listen(\"eloquent.{$event}: {$name}\", $callback);\n        }\n    }\n\n    /**\n     * Fire the given event for the model.\n     *\n     * @param  string  $event\n     * @param  bool  $halt\n     * @return mixed\n     */\n    protected function fireModelEvent($event, $halt = true)\n    {\n        if (! isset(static::$dispatcher)) {\n            return true;\n        }\n\n        // First, we will get the proper method to call on the event dispatcher, and then we\n        // will attempt to fire a custom, object based event for the given event. If that\n        // returns a result we can return that result, or we'll call the string events.\n        $method = $halt ? 'until' : 'dispatch';\n\n        $result = $this->filterModelEventResults(\n            $this->fireCustomModelEvent($event, $method)\n        );\n\n        if ($result === false) {\n            return false;\n        }\n\n        return ! empty($result) ? $result : static::$dispatcher->{$method}(\n            \"eloquent.{$event}: \".static::class, $this\n        );\n    }\n\n    /**\n     * Fire a custom model event for the given event.\n     *\n     * @param  string  $event\n     * @param  string  $method\n     * @return mixed|null\n     */\n    protected function fireCustomModelEvent($event, $method)\n    {\n        if (! isset($this->dispatchesEvents[$event])) {\n            return;\n        }\n\n        $result = static::$dispatcher->$method(new $this->dispatchesEvents[$event]($this));\n\n        if (! is_null($result)) {\n            return $result;\n        }\n    }\n\n    /**\n     * Filter the model event results.\n     *\n     * @param  mixed  $result\n     * @return mixed\n     */\n    protected function filterModelEventResults($result)\n    {\n        if (is_array($result)) {\n            $result = array_filter($result, function ($response) {\n                return ! is_null($response);\n            });\n        }\n\n        return $result;\n    }\n\n    /**\n     * Register a retrieved model event with the dispatcher.\n     *\n     * @param  \\Illuminate\\Events\\QueuedClosure|\\Closure|string  $callback\n     * @return void\n     */\n    public static function retrieved($callback)\n    {\n        static::registerModelEvent('retrieved', $callback);\n    }\n\n    /**\n     * Register a saving model event with the dispatcher.\n     *\n     * @param  \\Illuminate\\Events\\QueuedClosure|\\Closure|string  $callback\n     * @return void\n     */\n    public static function saving($callback)\n    {\n        static::registerModelEvent('saving', $callback);\n    }\n\n    /**\n     * Register a saved model event with the dispatcher.\n     *\n     * @param  \\Illuminate\\Events\\QueuedClosure|\\Closure|string  $callback\n     * @return void\n     */\n    public static function saved($callback)\n    {\n        static::registerModelEvent('saved', $callback);\n    }\n\n    /**\n     * Register an updating model event with the dispatcher.\n     *\n     * @param  \\Illuminate\\Events\\QueuedClosure|\\Closure|string  $callback\n     * @return void\n     */\n    public static function updating($callback)\n    {\n        static::registerModelEvent('updating', $callback);\n    }\n\n    /**\n     * Register an updated model event with the dispatcher.\n     *\n     * @param  \\Illuminate\\Events\\QueuedClosure|\\Closure|string  $callback\n     * @return void\n     */\n    public static function updated($callback)\n    {\n        static::registerModelEvent('updated', $callback);\n    }\n\n    /**\n     * Register a creating model event with the dispatcher.\n     *\n     * @param  \\Illuminate\\Events\\QueuedClosure|\\Closure|string  $callback\n     * @return void\n     */\n    public static function creating($callback)\n    {\n        static::registerModelEvent('creating', $callback);\n    }\n\n    /**\n     * Register a created model event with the dispatcher.\n     *\n     * @param  \\Illuminate\\Events\\QueuedClosure|\\Closure|string  $callback\n     * @return void\n     */\n    public static function created($callback)\n    {\n        static::registerModelEvent('created', $callback);\n    }\n\n    /**\n     * Register a replicating model event with the dispatcher.\n     *\n     * @param  \\Illuminate\\Events\\QueuedClosure|\\Closure|string  $callback\n     * @return void\n     */\n    public static function replicating($callback)\n    {\n        static::registerModelEvent('replicating', $callback);\n    }\n\n    /**\n     * Register a deleting model event with the dispatcher.\n     *\n     * @param  \\Illuminate\\Events\\QueuedClosure|\\Closure|string  $callback\n     * @return void\n     */\n    public static function deleting($callback)\n    {\n        static::registerModelEvent('deleting', $callback);\n    }\n\n    /**\n     * Register a deleted model event with the dispatcher.\n     *\n     * @param  \\Illuminate\\Events\\QueuedClosure|\\Closure|string  $callback\n     * @return void\n     */\n    public static function deleted($callback)\n    {\n        static::registerModelEvent('deleted', $callback);\n    }\n\n    /**\n     * Remove all of the event listeners for the model.\n     *\n     * @return void\n     */\n    public static function flushEventListeners()\n    {\n        if (! isset(static::$dispatcher)) {\n            return;\n        }\n\n        $instance = new static;\n\n        foreach ($instance->getObservableEvents() as $event) {\n            static::$dispatcher->forget(\"eloquent.{$event}: \".static::class);\n        }\n\n        foreach (array_values($instance->dispatchesEvents) as $event) {\n            static::$dispatcher->forget($event);\n        }\n    }\n\n    /**\n     * Get the event dispatcher instance.\n     *\n     * @return \\Illuminate\\Contracts\\Events\\Dispatcher\n     */\n    public static function getEventDispatcher()\n    {\n        return static::$dispatcher;\n    }\n\n    /**\n     * Set the event dispatcher instance.\n     *\n     * @param  \\Illuminate\\Contracts\\Events\\Dispatcher  $dispatcher\n     * @return void\n     */\n    public static function setEventDispatcher(Dispatcher $dispatcher)\n    {\n        static::$dispatcher = $dispatcher;\n    }\n\n    /**\n     * Unset the event dispatcher for models.\n     *\n     * @return void\n     */\n    public static function unsetEventDispatcher()\n    {\n        static::$dispatcher = null;\n    }\n\n    /**\n     * Execute a callback without firing any model events for any model type.\n     *\n     * @param  callable  $callback\n     * @return mixed\n     */\n    public static function withoutEvents(callable $callback)\n    {\n        $dispatcher = static::getEventDispatcher();\n\n        if ($dispatcher) {\n            static::setEventDispatcher(new NullDispatcher($dispatcher));\n        }\n\n        try {\n            return $callback();\n        } finally {\n            if ($dispatcher) {\n                static::setEventDispatcher($dispatcher);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/Concerns/HasGlobalScopes.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent\\Concerns;\n\nuse Closure;\nuse Illuminate\\Database\\Eloquent\\Scope;\nuse Illuminate\\Support\\Arr;\nuse InvalidArgumentException;\n\ntrait HasGlobalScopes\n{\n    /**\n     * Register a new global scope on the model.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Scope|\\Closure|string  $scope\n     * @param  \\Closure|null  $implementation\n     * @return mixed\n     *\n     * @throws \\InvalidArgumentException\n     */\n    public static function addGlobalScope($scope, Closure $implementation = null)\n    {\n        if (is_string($scope) && ! is_null($implementation)) {\n            return static::$globalScopes[static::class][$scope] = $implementation;\n        } elseif ($scope instanceof Closure) {\n            return static::$globalScopes[static::class][spl_object_hash($scope)] = $scope;\n        } elseif ($scope instanceof Scope) {\n            return static::$globalScopes[static::class][get_class($scope)] = $scope;\n        }\n\n        throw new InvalidArgumentException('Global scope must be an instance of Closure or Scope.');\n    }\n\n    /**\n     * Determine if a model has a global scope.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Scope|string  $scope\n     * @return bool\n     */\n    public static function hasGlobalScope($scope)\n    {\n        return ! is_null(static::getGlobalScope($scope));\n    }\n\n    /**\n     * Get a global scope registered with the model.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Scope|string  $scope\n     * @return \\Illuminate\\Database\\Eloquent\\Scope|\\Closure|null\n     */\n    public static function getGlobalScope($scope)\n    {\n        if (is_string($scope)) {\n            return Arr::get(static::$globalScopes, static::class.'.'.$scope);\n        }\n\n        return Arr::get(\n            static::$globalScopes, static::class.'.'.get_class($scope)\n        );\n    }\n\n    /**\n     * Get the global scopes for this class instance.\n     *\n     * @return array\n     */\n    public function getGlobalScopes()\n    {\n        return Arr::get(static::$globalScopes, static::class, []);\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/Concerns/HasRelationships.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent\\Concerns;\n\nuse Closure;\nuse Illuminate\\Database\\ClassMorphViolationException;\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Illuminate\\Database\\Eloquent\\Collection;\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Database\\Eloquent\\Relations\\BelongsTo;\nuse Illuminate\\Database\\Eloquent\\Relations\\BelongsToMany;\nuse Illuminate\\Database\\Eloquent\\Relations\\HasMany;\nuse Illuminate\\Database\\Eloquent\\Relations\\HasManyThrough;\nuse Illuminate\\Database\\Eloquent\\Relations\\HasOne;\nuse Illuminate\\Database\\Eloquent\\Relations\\HasOneThrough;\nuse Illuminate\\Database\\Eloquent\\Relations\\MorphMany;\nuse Illuminate\\Database\\Eloquent\\Relations\\MorphOne;\nuse Illuminate\\Database\\Eloquent\\Relations\\MorphTo;\nuse Illuminate\\Database\\Eloquent\\Relations\\MorphToMany;\nuse Illuminate\\Database\\Eloquent\\Relations\\Relation;\nuse Illuminate\\Support\\Arr;\nuse Illuminate\\Support\\Str;\n\ntrait HasRelationships\n{\n    /**\n     * The loaded relationships for the model.\n     *\n     * @var array\n     */\n    protected $relations = [];\n\n    /**\n     * The relationships that should be touched on save.\n     *\n     * @var array\n     */\n    protected $touches = [];\n\n    /**\n     * The many to many relationship methods.\n     *\n     * @var string[]\n     */\n    public static $manyMethods = [\n        'belongsToMany', 'morphToMany', 'morphedByMany',\n    ];\n\n    /**\n     * The relation resolver callbacks.\n     *\n     * @var array\n     */\n    protected static $relationResolvers = [];\n\n    /**\n     * Define a dynamic relation resolver.\n     *\n     * @param  string  $name\n     * @param  \\Closure  $callback\n     * @return void\n     */\n    public static function resolveRelationUsing($name, Closure $callback)\n    {\n        static::$relationResolvers = array_replace_recursive(\n            static::$relationResolvers,\n            [static::class => [$name => $callback]]\n        );\n    }\n\n    /**\n     * Define a one-to-one relationship.\n     *\n     * @param  string  $related\n     * @param  string|null  $foreignKey\n     * @param  string|null  $localKey\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\HasOne\n     */\n    public function hasOne($related, $foreignKey = null, $localKey = null)\n    {\n        $instance = $this->newRelatedInstance($related);\n\n        $foreignKey = $foreignKey ?: $this->getForeignKey();\n\n        $localKey = $localKey ?: $this->getKeyName();\n\n        return $this->newHasOne($instance->newQuery(), $this, $instance->getTable().'.'.$foreignKey, $localKey);\n    }\n\n    /**\n     * Instantiate a new HasOne relationship.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $query\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $parent\n     * @param  string  $foreignKey\n     * @param  string  $localKey\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\HasOne\n     */\n    protected function newHasOne(Builder $query, Model $parent, $foreignKey, $localKey)\n    {\n        return new HasOne($query, $parent, $foreignKey, $localKey);\n    }\n\n    /**\n     * Define a has-one-through relationship.\n     *\n     * @param  string  $related\n     * @param  string  $through\n     * @param  string|null  $firstKey\n     * @param  string|null  $secondKey\n     * @param  string|null  $localKey\n     * @param  string|null  $secondLocalKey\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\HasOneThrough\n     */\n    public function hasOneThrough($related, $through, $firstKey = null, $secondKey = null, $localKey = null, $secondLocalKey = null)\n    {\n        $through = new $through;\n\n        $firstKey = $firstKey ?: $this->getForeignKey();\n\n        $secondKey = $secondKey ?: $through->getForeignKey();\n\n        return $this->newHasOneThrough(\n            $this->newRelatedInstance($related)->newQuery(), $this, $through,\n            $firstKey, $secondKey, $localKey ?: $this->getKeyName(),\n            $secondLocalKey ?: $through->getKeyName()\n        );\n    }\n\n    /**\n     * Instantiate a new HasOneThrough relationship.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $query\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $farParent\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $throughParent\n     * @param  string  $firstKey\n     * @param  string  $secondKey\n     * @param  string  $localKey\n     * @param  string  $secondLocalKey\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\HasOneThrough\n     */\n    protected function newHasOneThrough(Builder $query, Model $farParent, Model $throughParent, $firstKey, $secondKey, $localKey, $secondLocalKey)\n    {\n        return new HasOneThrough($query, $farParent, $throughParent, $firstKey, $secondKey, $localKey, $secondLocalKey);\n    }\n\n    /**\n     * Define a polymorphic one-to-one relationship.\n     *\n     * @param  string  $related\n     * @param  string  $name\n     * @param  string|null  $type\n     * @param  string|null  $id\n     * @param  string|null  $localKey\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\MorphOne\n     */\n    public function morphOne($related, $name, $type = null, $id = null, $localKey = null)\n    {\n        $instance = $this->newRelatedInstance($related);\n\n        [$type, $id] = $this->getMorphs($name, $type, $id);\n\n        $table = $instance->getTable();\n\n        $localKey = $localKey ?: $this->getKeyName();\n\n        return $this->newMorphOne($instance->newQuery(), $this, $table.'.'.$type, $table.'.'.$id, $localKey);\n    }\n\n    /**\n     * Instantiate a new MorphOne relationship.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $query\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $parent\n     * @param  string  $type\n     * @param  string  $id\n     * @param  string  $localKey\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\MorphOne\n     */\n    protected function newMorphOne(Builder $query, Model $parent, $type, $id, $localKey)\n    {\n        return new MorphOne($query, $parent, $type, $id, $localKey);\n    }\n\n    /**\n     * Define an inverse one-to-one or many relationship.\n     *\n     * @param  string  $related\n     * @param  string|null  $foreignKey\n     * @param  string|null  $ownerKey\n     * @param  string|null  $relation\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\BelongsTo\n     */\n    public function belongsTo($related, $foreignKey = null, $ownerKey = null, $relation = null)\n    {\n        // If no relation name was given, we will use this debug backtrace to extract\n        // the calling method's name and use that as the relationship name as most\n        // of the time this will be what we desire to use for the relationships.\n        if (is_null($relation)) {\n            $relation = $this->guessBelongsToRelation();\n        }\n\n        $instance = $this->newRelatedInstance($related);\n\n        // If no foreign key was supplied, we can use a backtrace to guess the proper\n        // foreign key name by using the name of the relationship function, which\n        // when combined with an \"_id\" should conventionally match the columns.\n        if (is_null($foreignKey)) {\n            $foreignKey = Str::snake($relation).'_'.$instance->getKeyName();\n        }\n\n        // Once we have the foreign key names, we'll just create a new Eloquent query\n        // for the related models and returns the relationship instance which will\n        // actually be responsible for retrieving and hydrating every relations.\n        $ownerKey = $ownerKey ?: $instance->getKeyName();\n\n        return $this->newBelongsTo(\n            $instance->newQuery(), $this, $foreignKey, $ownerKey, $relation\n        );\n    }\n\n    /**\n     * Instantiate a new BelongsTo relationship.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $query\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $child\n     * @param  string  $foreignKey\n     * @param  string  $ownerKey\n     * @param  string  $relation\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\BelongsTo\n     */\n    protected function newBelongsTo(Builder $query, Model $child, $foreignKey, $ownerKey, $relation)\n    {\n        return new BelongsTo($query, $child, $foreignKey, $ownerKey, $relation);\n    }\n\n    /**\n     * Define a polymorphic, inverse one-to-one or many relationship.\n     *\n     * @param  string|null  $name\n     * @param  string|null  $type\n     * @param  string|null  $id\n     * @param  string|null  $ownerKey\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\MorphTo\n     */\n    public function morphTo($name = null, $type = null, $id = null, $ownerKey = null)\n    {\n        // If no name is provided, we will use the backtrace to get the function name\n        // since that is most likely the name of the polymorphic interface. We can\n        // use that to get both the class and foreign key that will be utilized.\n        $name = $name ?: $this->guessBelongsToRelation();\n\n        [$type, $id] = $this->getMorphs(\n            Str::snake($name), $type, $id\n        );\n\n        // If the type value is null it is probably safe to assume we're eager loading\n        // the relationship. In this case we'll just pass in a dummy query where we\n        // need to remove any eager loads that may already be defined on a model.\n        return is_null($class = $this->getAttributeFromArray($type)) || $class === ''\n                    ? $this->morphEagerTo($name, $type, $id, $ownerKey)\n                    : $this->morphInstanceTo($class, $name, $type, $id, $ownerKey);\n    }\n\n    /**\n     * Define a polymorphic, inverse one-to-one or many relationship.\n     *\n     * @param  string  $name\n     * @param  string  $type\n     * @param  string  $id\n     * @param  string  $ownerKey\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\MorphTo\n     */\n    protected function morphEagerTo($name, $type, $id, $ownerKey)\n    {\n        return $this->newMorphTo(\n            $this->newQuery()->setEagerLoads([]), $this, $id, $ownerKey, $type, $name\n        );\n    }\n\n    /**\n     * Define a polymorphic, inverse one-to-one or many relationship.\n     *\n     * @param  string  $target\n     * @param  string  $name\n     * @param  string  $type\n     * @param  string  $id\n     * @param  string  $ownerKey\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\MorphTo\n     */\n    protected function morphInstanceTo($target, $name, $type, $id, $ownerKey)\n    {\n        $instance = $this->newRelatedInstance(\n            static::getActualClassNameForMorph($target)\n        );\n\n        return $this->newMorphTo(\n            $instance->newQuery(), $this, $id, $ownerKey ?? $instance->getKeyName(), $type, $name\n        );\n    }\n\n    /**\n     * Instantiate a new MorphTo relationship.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $query\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $parent\n     * @param  string  $foreignKey\n     * @param  string  $ownerKey\n     * @param  string  $type\n     * @param  string  $relation\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\MorphTo\n     */\n    protected function newMorphTo(Builder $query, Model $parent, $foreignKey, $ownerKey, $type, $relation)\n    {\n        return new MorphTo($query, $parent, $foreignKey, $ownerKey, $type, $relation);\n    }\n\n    /**\n     * Retrieve the actual class name for a given morph class.\n     *\n     * @param  string  $class\n     * @return string\n     */\n    public static function getActualClassNameForMorph($class)\n    {\n        return Arr::get(Relation::morphMap() ?: [], $class, $class);\n    }\n\n    /**\n     * Guess the \"belongs to\" relationship name.\n     *\n     * @return string\n     */\n    protected function guessBelongsToRelation()\n    {\n        [$one, $two, $caller] = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3);\n\n        return $caller['function'];\n    }\n\n    /**\n     * Define a one-to-many relationship.\n     *\n     * @param  string  $related\n     * @param  string|null  $foreignKey\n     * @param  string|null  $localKey\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\HasMany\n     */\n    public function hasMany($related, $foreignKey = null, $localKey = null)\n    {\n        $instance = $this->newRelatedInstance($related);\n\n        $foreignKey = $foreignKey ?: $this->getForeignKey();\n\n        $localKey = $localKey ?: $this->getKeyName();\n\n        return $this->newHasMany(\n            $instance->newQuery(), $this, $instance->getTable().'.'.$foreignKey, $localKey\n        );\n    }\n\n    /**\n     * Instantiate a new HasMany relationship.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $query\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $parent\n     * @param  string  $foreignKey\n     * @param  string  $localKey\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\HasMany\n     */\n    protected function newHasMany(Builder $query, Model $parent, $foreignKey, $localKey)\n    {\n        return new HasMany($query, $parent, $foreignKey, $localKey);\n    }\n\n    /**\n     * Define a has-many-through relationship.\n     *\n     * @param  string  $related\n     * @param  string  $through\n     * @param  string|null  $firstKey\n     * @param  string|null  $secondKey\n     * @param  string|null  $localKey\n     * @param  string|null  $secondLocalKey\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\HasManyThrough\n     */\n    public function hasManyThrough($related, $through, $firstKey = null, $secondKey = null, $localKey = null, $secondLocalKey = null)\n    {\n        $through = new $through;\n\n        $firstKey = $firstKey ?: $this->getForeignKey();\n\n        $secondKey = $secondKey ?: $through->getForeignKey();\n\n        return $this->newHasManyThrough(\n            $this->newRelatedInstance($related)->newQuery(),\n            $this,\n            $through,\n            $firstKey,\n            $secondKey,\n            $localKey ?: $this->getKeyName(),\n            $secondLocalKey ?: $through->getKeyName()\n        );\n    }\n\n    /**\n     * Instantiate a new HasManyThrough relationship.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $query\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $farParent\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $throughParent\n     * @param  string  $firstKey\n     * @param  string  $secondKey\n     * @param  string  $localKey\n     * @param  string  $secondLocalKey\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\HasManyThrough\n     */\n    protected function newHasManyThrough(Builder $query, Model $farParent, Model $throughParent, $firstKey, $secondKey, $localKey, $secondLocalKey)\n    {\n        return new HasManyThrough($query, $farParent, $throughParent, $firstKey, $secondKey, $localKey, $secondLocalKey);\n    }\n\n    /**\n     * Define a polymorphic one-to-many relationship.\n     *\n     * @param  string  $related\n     * @param  string  $name\n     * @param  string|null  $type\n     * @param  string|null  $id\n     * @param  string|null  $localKey\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\MorphMany\n     */\n    public function morphMany($related, $name, $type = null, $id = null, $localKey = null)\n    {\n        $instance = $this->newRelatedInstance($related);\n\n        // Here we will gather up the morph type and ID for the relationship so that we\n        // can properly query the intermediate table of a relation. Finally, we will\n        // get the table and create the relationship instances for the developers.\n        [$type, $id] = $this->getMorphs($name, $type, $id);\n\n        $table = $instance->getTable();\n\n        $localKey = $localKey ?: $this->getKeyName();\n\n        return $this->newMorphMany($instance->newQuery(), $this, $table.'.'.$type, $table.'.'.$id, $localKey);\n    }\n\n    /**\n     * Instantiate a new MorphMany relationship.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $query\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $parent\n     * @param  string  $type\n     * @param  string  $id\n     * @param  string  $localKey\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\MorphMany\n     */\n    protected function newMorphMany(Builder $query, Model $parent, $type, $id, $localKey)\n    {\n        return new MorphMany($query, $parent, $type, $id, $localKey);\n    }\n\n    /**\n     * Define a many-to-many relationship.\n     *\n     * @param  string  $related\n     * @param  string|null  $table\n     * @param  string|null  $foreignPivotKey\n     * @param  string|null  $relatedPivotKey\n     * @param  string|null  $parentKey\n     * @param  string|null  $relatedKey\n     * @param  string|null  $relation\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\BelongsToMany\n     */\n    public function belongsToMany($related, $table = null, $foreignPivotKey = null, $relatedPivotKey = null,\n                                  $parentKey = null, $relatedKey = null, $relation = null)\n    {\n        // If no relationship name was passed, we will pull backtraces to get the\n        // name of the calling function. We will use that function name as the\n        // title of this relation since that is a great convention to apply.\n        if (is_null($relation)) {\n            $relation = $this->guessBelongsToManyRelation();\n        }\n\n        // First, we'll need to determine the foreign key and \"other key\" for the\n        // relationship. Once we have determined the keys we'll make the query\n        // instances as well as the relationship instances we need for this.\n        $instance = $this->newRelatedInstance($related);\n\n        $foreignPivotKey = $foreignPivotKey ?: $this->getForeignKey();\n\n        $relatedPivotKey = $relatedPivotKey ?: $instance->getForeignKey();\n\n        // If no table name was provided, we can guess it by concatenating the two\n        // models using underscores in alphabetical order. The two model names\n        // are transformed to snake case from their default CamelCase also.\n        if (is_null($table)) {\n            $table = $this->joiningTable($related, $instance);\n        }\n\n        return $this->newBelongsToMany(\n            $instance->newQuery(), $this, $table, $foreignPivotKey,\n            $relatedPivotKey, $parentKey ?: $this->getKeyName(),\n            $relatedKey ?: $instance->getKeyName(), $relation\n        );\n    }\n\n    /**\n     * Instantiate a new BelongsToMany relationship.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $query\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $parent\n     * @param  string  $table\n     * @param  string  $foreignPivotKey\n     * @param  string  $relatedPivotKey\n     * @param  string  $parentKey\n     * @param  string  $relatedKey\n     * @param  string|null  $relationName\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\BelongsToMany\n     */\n    protected function newBelongsToMany(Builder $query, Model $parent, $table, $foreignPivotKey, $relatedPivotKey,\n                                        $parentKey, $relatedKey, $relationName = null)\n    {\n        return new BelongsToMany($query, $parent, $table, $foreignPivotKey, $relatedPivotKey, $parentKey, $relatedKey, $relationName);\n    }\n\n    /**\n     * Define a polymorphic many-to-many relationship.\n     *\n     * @param  string  $related\n     * @param  string  $name\n     * @param  string|null  $table\n     * @param  string|null  $foreignPivotKey\n     * @param  string|null  $relatedPivotKey\n     * @param  string|null  $parentKey\n     * @param  string|null  $relatedKey\n     * @param  bool  $inverse\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\MorphToMany\n     */\n    public function morphToMany($related, $name, $table = null, $foreignPivotKey = null,\n                                $relatedPivotKey = null, $parentKey = null,\n                                $relatedKey = null, $inverse = false)\n    {\n        $caller = $this->guessBelongsToManyRelation();\n\n        // First, we will need to determine the foreign key and \"other key\" for the\n        // relationship. Once we have determined the keys we will make the query\n        // instances, as well as the relationship instances we need for these.\n        $instance = $this->newRelatedInstance($related);\n\n        $foreignPivotKey = $foreignPivotKey ?: $name.'_id';\n\n        $relatedPivotKey = $relatedPivotKey ?: $instance->getForeignKey();\n\n        // Now we're ready to create a new query builder for this related model and\n        // the relationship instances for this relation. This relations will set\n        // appropriate query constraints then entirely manages the hydrations.\n        if (! $table) {\n            $words = preg_split('/(_)/u', $name, -1, PREG_SPLIT_DELIM_CAPTURE);\n\n            $lastWord = array_pop($words);\n\n            $table = implode('', $words).Str::plural($lastWord);\n        }\n\n        return $this->newMorphToMany(\n            $instance->newQuery(), $this, $name, $table,\n            $foreignPivotKey, $relatedPivotKey, $parentKey ?: $this->getKeyName(),\n            $relatedKey ?: $instance->getKeyName(), $caller, $inverse\n        );\n    }\n\n    /**\n     * Instantiate a new MorphToMany relationship.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $query\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $parent\n     * @param  string  $name\n     * @param  string  $table\n     * @param  string  $foreignPivotKey\n     * @param  string  $relatedPivotKey\n     * @param  string  $parentKey\n     * @param  string  $relatedKey\n     * @param  string|null  $relationName\n     * @param  bool  $inverse\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\MorphToMany\n     */\n    protected function newMorphToMany(Builder $query, Model $parent, $name, $table, $foreignPivotKey,\n                                      $relatedPivotKey, $parentKey, $relatedKey,\n                                      $relationName = null, $inverse = false)\n    {\n        return new MorphToMany($query, $parent, $name, $table, $foreignPivotKey, $relatedPivotKey, $parentKey, $relatedKey,\n            $relationName, $inverse);\n    }\n\n    /**\n     * Define a polymorphic, inverse many-to-many relationship.\n     *\n     * @param  string  $related\n     * @param  string  $name\n     * @param  string|null  $table\n     * @param  string|null  $foreignPivotKey\n     * @param  string|null  $relatedPivotKey\n     * @param  string|null  $parentKey\n     * @param  string|null  $relatedKey\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\MorphToMany\n     */\n    public function morphedByMany($related, $name, $table = null, $foreignPivotKey = null,\n                                  $relatedPivotKey = null, $parentKey = null, $relatedKey = null)\n    {\n        $foreignPivotKey = $foreignPivotKey ?: $this->getForeignKey();\n\n        // For the inverse of the polymorphic many-to-many relations, we will change\n        // the way we determine the foreign and other keys, as it is the opposite\n        // of the morph-to-many method since we're figuring out these inverses.\n        $relatedPivotKey = $relatedPivotKey ?: $name.'_id';\n\n        return $this->morphToMany(\n            $related, $name, $table, $foreignPivotKey,\n            $relatedPivotKey, $parentKey, $relatedKey, true\n        );\n    }\n\n    /**\n     * Get the relationship name of the belongsToMany relationship.\n     *\n     * @return string|null\n     */\n    protected function guessBelongsToManyRelation()\n    {\n        $caller = Arr::first(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS), function ($trace) {\n            return ! in_array(\n                $trace['function'],\n                array_merge(static::$manyMethods, ['guessBelongsToManyRelation'])\n            );\n        });\n\n        return ! is_null($caller) ? $caller['function'] : null;\n    }\n\n    /**\n     * Get the joining table name for a many-to-many relation.\n     *\n     * @param  string  $related\n     * @param  \\Illuminate\\Database\\Eloquent\\Model|null  $instance\n     * @return string\n     */\n    public function joiningTable($related, $instance = null)\n    {\n        // The joining table name, by convention, is simply the snake cased models\n        // sorted alphabetically and concatenated with an underscore, so we can\n        // just sort the models and join them together to get the table name.\n        $segments = [\n            $instance ? $instance->joiningTableSegment()\n                      : Str::snake(class_basename($related)),\n            $this->joiningTableSegment(),\n        ];\n\n        // Now that we have the model names in an array we can just sort them and\n        // use the implode function to join them together with an underscores,\n        // which is typically used by convention within the database system.\n        sort($segments);\n\n        return strtolower(implode('_', $segments));\n    }\n\n    /**\n     * Get this model's half of the intermediate table name for belongsToMany relationships.\n     *\n     * @return string\n     */\n    public function joiningTableSegment()\n    {\n        return Str::snake(class_basename($this));\n    }\n\n    /**\n     * Determine if the model touches a given relation.\n     *\n     * @param  string  $relation\n     * @return bool\n     */\n    public function touches($relation)\n    {\n        return in_array($relation, $this->getTouchedRelations());\n    }\n\n    /**\n     * Touch the owning relations of the model.\n     *\n     * @return void\n     */\n    public function touchOwners()\n    {\n        foreach ($this->getTouchedRelations() as $relation) {\n            $this->$relation()->touch();\n\n            if ($this->$relation instanceof self) {\n                $this->$relation->fireModelEvent('saved', false);\n\n                $this->$relation->touchOwners();\n            } elseif ($this->$relation instanceof Collection) {\n                $this->$relation->each->touchOwners();\n            }\n        }\n    }\n\n    /**\n     * Get the polymorphic relationship columns.\n     *\n     * @param  string  $name\n     * @param  string  $type\n     * @param  string  $id\n     * @return array\n     */\n    protected function getMorphs($name, $type, $id)\n    {\n        return [$type ?: $name.'_type', $id ?: $name.'_id'];\n    }\n\n    /**\n     * Get the class name for polymorphic relations.\n     *\n     * @return string\n     */\n    public function getMorphClass()\n    {\n        $morphMap = Relation::morphMap();\n\n        if (! empty($morphMap) && in_array(static::class, $morphMap)) {\n            return array_search(static::class, $morphMap, true);\n        }\n\n        if (Relation::requiresMorphMap()) {\n            throw new ClassMorphViolationException($this);\n        }\n\n        return static::class;\n    }\n\n    /**\n     * Create a new model instance for a related model.\n     *\n     * @param  string  $class\n     * @return mixed\n     */\n    protected function newRelatedInstance($class)\n    {\n        return tap(new $class, function ($instance) {\n            if (! $instance->getConnectionName()) {\n                $instance->setConnection($this->connection);\n            }\n        });\n    }\n\n    /**\n     * Get all the loaded relations for the instance.\n     *\n     * @return array\n     */\n    public function getRelations()\n    {\n        return $this->relations;\n    }\n\n    /**\n     * Get a specified relationship.\n     *\n     * @param  string  $relation\n     * @return mixed\n     */\n    public function getRelation($relation)\n    {\n        return $this->relations[$relation];\n    }\n\n    /**\n     * Determine if the given relation is loaded.\n     *\n     * @param  string  $key\n     * @return bool\n     */\n    public function relationLoaded($key)\n    {\n        return array_key_exists($key, $this->relations);\n    }\n\n    /**\n     * Set the given relationship on the model.\n     *\n     * @param  string  $relation\n     * @param  mixed  $value\n     * @return $this\n     */\n    public function setRelation($relation, $value)\n    {\n        $this->relations[$relation] = $value;\n\n        return $this;\n    }\n\n    /**\n     * Unset a loaded relationship.\n     *\n     * @param  string  $relation\n     * @return $this\n     */\n    public function unsetRelation($relation)\n    {\n        unset($this->relations[$relation]);\n\n        return $this;\n    }\n\n    /**\n     * Set the entire relations array on the model.\n     *\n     * @param  array  $relations\n     * @return $this\n     */\n    public function setRelations(array $relations)\n    {\n        $this->relations = $relations;\n\n        return $this;\n    }\n\n    /**\n     * Duplicate the instance and unset all the loaded relations.\n     *\n     * @return $this\n     */\n    public function withoutRelations()\n    {\n        $model = clone $this;\n\n        return $model->unsetRelations();\n    }\n\n    /**\n     * Unset all the loaded relations for the instance.\n     *\n     * @return $this\n     */\n    public function unsetRelations()\n    {\n        $this->relations = [];\n\n        return $this;\n    }\n\n    /**\n     * Get the relationships that are touched on save.\n     *\n     * @return array\n     */\n    public function getTouchedRelations()\n    {\n        return $this->touches;\n    }\n\n    /**\n     * Set the relationships that are touched on save.\n     *\n     * @param  array  $touches\n     * @return $this\n     */\n    public function setTouchedRelations(array $touches)\n    {\n        $this->touches = $touches;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/Concerns/HasTimestamps.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent\\Concerns;\n\nuse Illuminate\\Support\\Facades\\Date;\n\ntrait HasTimestamps\n{\n    /**\n     * Indicates if the model should be timestamped.\n     *\n     * @var bool\n     */\n    public $timestamps = true;\n\n    /**\n     * Update the model's update timestamp.\n     *\n     * @return bool\n     */\n    public function touch()\n    {\n        if (! $this->usesTimestamps()) {\n            return false;\n        }\n\n        $this->updateTimestamps();\n\n        return $this->save();\n    }\n\n    /**\n     * Update the creation and update timestamps.\n     *\n     * @return void\n     */\n    public function updateTimestamps()\n    {\n        $time = $this->freshTimestamp();\n\n        $updatedAtColumn = $this->getUpdatedAtColumn();\n\n        if (! is_null($updatedAtColumn) && ! $this->isDirty($updatedAtColumn)) {\n            $this->setUpdatedAt($time);\n        }\n\n        $createdAtColumn = $this->getCreatedAtColumn();\n\n        if (! $this->exists && ! is_null($createdAtColumn) && ! $this->isDirty($createdAtColumn)) {\n            $this->setCreatedAt($time);\n        }\n    }\n\n    /**\n     * Set the value of the \"created at\" attribute.\n     *\n     * @param  mixed  $value\n     * @return $this\n     */\n    public function setCreatedAt($value)\n    {\n        $this->{$this->getCreatedAtColumn()} = $value;\n\n        return $this;\n    }\n\n    /**\n     * Set the value of the \"updated at\" attribute.\n     *\n     * @param  mixed  $value\n     * @return $this\n     */\n    public function setUpdatedAt($value)\n    {\n        $this->{$this->getUpdatedAtColumn()} = $value;\n\n        return $this;\n    }\n\n    /**\n     * Get a fresh timestamp for the model.\n     *\n     * @return \\Illuminate\\Support\\Carbon\n     */\n    public function freshTimestamp()\n    {\n        return Date::now();\n    }\n\n    /**\n     * Get a fresh timestamp for the model.\n     *\n     * @return string\n     */\n    public function freshTimestampString()\n    {\n        return $this->fromDateTime($this->freshTimestamp());\n    }\n\n    /**\n     * Determine if the model uses timestamps.\n     *\n     * @return bool\n     */\n    public function usesTimestamps()\n    {\n        return $this->timestamps;\n    }\n\n    /**\n     * Get the name of the \"created at\" column.\n     *\n     * @return string|null\n     */\n    public function getCreatedAtColumn()\n    {\n        return static::CREATED_AT;\n    }\n\n    /**\n     * Get the name of the \"updated at\" column.\n     *\n     * @return string|null\n     */\n    public function getUpdatedAtColumn()\n    {\n        return static::UPDATED_AT;\n    }\n\n    /**\n     * Get the fully qualified \"created at\" column.\n     *\n     * @return string|null\n     */\n    public function getQualifiedCreatedAtColumn()\n    {\n        return $this->qualifyColumn($this->getCreatedAtColumn());\n    }\n\n    /**\n     * Get the fully qualified \"updated at\" column.\n     *\n     * @return string|null\n     */\n    public function getQualifiedUpdatedAtColumn()\n    {\n        return $this->qualifyColumn($this->getUpdatedAtColumn());\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/Concerns/HidesAttributes.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent\\Concerns;\n\nuse Closure;\n\ntrait HidesAttributes\n{\n    /**\n     * The attributes that should be hidden for serialization.\n     *\n     * @var array\n     */\n    protected $hidden = [];\n\n    /**\n     * The attributes that should be visible in serialization.\n     *\n     * @var array\n     */\n    protected $visible = [];\n\n    /**\n     * Get the hidden attributes for the model.\n     *\n     * @return array\n     */\n    public function getHidden()\n    {\n        return $this->hidden;\n    }\n\n    /**\n     * Set the hidden attributes for the model.\n     *\n     * @param  array  $hidden\n     * @return $this\n     */\n    public function setHidden(array $hidden)\n    {\n        $this->hidden = $hidden;\n\n        return $this;\n    }\n\n    /**\n     * Get the visible attributes for the model.\n     *\n     * @return array\n     */\n    public function getVisible()\n    {\n        return $this->visible;\n    }\n\n    /**\n     * Set the visible attributes for the model.\n     *\n     * @param  array  $visible\n     * @return $this\n     */\n    public function setVisible(array $visible)\n    {\n        $this->visible = $visible;\n\n        return $this;\n    }\n\n    /**\n     * Make the given, typically hidden, attributes visible.\n     *\n     * @param  array|string|null  $attributes\n     * @return $this\n     */\n    public function makeVisible($attributes)\n    {\n        $attributes = is_array($attributes) ? $attributes : func_get_args();\n\n        $this->hidden = array_diff($this->hidden, $attributes);\n\n        if (! empty($this->visible)) {\n            $this->visible = array_merge($this->visible, $attributes);\n        }\n\n        return $this;\n    }\n\n    /**\n     * Make the given, typically hidden, attributes visible if the given truth test passes.\n     *\n     * @param  bool|Closure  $condition\n     * @param  array|string|null  $attributes\n     * @return $this\n     */\n    public function makeVisibleIf($condition, $attributes)\n    {\n        return value($condition, $this) ? $this->makeVisible($attributes) : $this;\n    }\n\n    /**\n     * Make the given, typically visible, attributes hidden.\n     *\n     * @param  array|string|null  $attributes\n     * @return $this\n     */\n    public function makeHidden($attributes)\n    {\n        $this->hidden = array_merge(\n            $this->hidden, is_array($attributes) ? $attributes : func_get_args()\n        );\n\n        return $this;\n    }\n\n    /**\n     * Make the given, typically visible, attributes hidden if the given truth test passes.\n     *\n     * @param  bool|Closure  $condition\n     * @param  array|string|null  $attributes\n     * @return $this\n     */\n    public function makeHiddenIf($condition, $attributes)\n    {\n        return value($condition, $this) ? $this->makeHidden($attributes) : $this;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/Concerns/QueriesRelationships.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent\\Concerns;\n\nuse BadMethodCallException;\nuse Closure;\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Illuminate\\Database\\Eloquent\\RelationNotFoundException;\nuse Illuminate\\Database\\Eloquent\\Relations\\BelongsTo;\nuse Illuminate\\Database\\Eloquent\\Relations\\MorphTo;\nuse Illuminate\\Database\\Eloquent\\Relations\\Relation;\nuse Illuminate\\Database\\Query\\Builder as QueryBuilder;\nuse Illuminate\\Database\\Query\\Expression;\nuse Illuminate\\Support\\Str;\n\ntrait QueriesRelationships\n{\n    /**\n     * Add a relationship count / exists condition to the query.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Relations\\Relation|string  $relation\n     * @param  string  $operator\n     * @param  int  $count\n     * @param  string  $boolean\n     * @param  \\Closure|null  $callback\n     * @return \\Illuminate\\Database\\Eloquent\\Builder|static\n     *\n     * @throws \\RuntimeException\n     */\n    public function has($relation, $operator = '>=', $count = 1, $boolean = 'and', Closure $callback = null)\n    {\n        if (is_string($relation)) {\n            if (strpos($relation, '.') !== false) {\n                return $this->hasNested($relation, $operator, $count, $boolean, $callback);\n            }\n\n            $relation = $this->getRelationWithoutConstraints($relation);\n        }\n\n        if ($relation instanceof MorphTo) {\n            return $this->hasMorph($relation, ['*'], $operator, $count, $boolean, $callback);\n        }\n\n        // If we only need to check for the existence of the relation, then we can optimize\n        // the subquery to only run a \"where exists\" clause instead of this full \"count\"\n        // clause. This will make these queries run much faster compared with a count.\n        $method = $this->canUseExistsForExistenceCheck($operator, $count)\n                        ? 'getRelationExistenceQuery'\n                        : 'getRelationExistenceCountQuery';\n\n        $hasQuery = $relation->{$method}(\n            $relation->getRelated()->newQueryWithoutRelationships(), $this\n        );\n\n        // Next we will call any given callback as an \"anonymous\" scope so they can get the\n        // proper logical grouping of the where clauses if needed by this Eloquent query\n        // builder. Then, we will be ready to finalize and return this query instance.\n        if ($callback) {\n            $hasQuery->callScope($callback);\n        }\n\n        return $this->addHasWhere(\n            $hasQuery, $relation, $operator, $count, $boolean\n        );\n    }\n\n    /**\n     * Add nested relationship count / exists conditions to the query.\n     *\n     * Sets up recursive call to whereHas until we finish the nested relation.\n     *\n     * @param  string  $relations\n     * @param  string  $operator\n     * @param  int  $count\n     * @param  string  $boolean\n     * @param  \\Closure|null  $callback\n     * @return \\Illuminate\\Database\\Eloquent\\Builder|static\n     */\n    protected function hasNested($relations, $operator = '>=', $count = 1, $boolean = 'and', $callback = null)\n    {\n        $relations = explode('.', $relations);\n\n        $doesntHave = $operator === '<' && $count === 1;\n\n        if ($doesntHave) {\n            $operator = '>=';\n            $count = 1;\n        }\n\n        $closure = function ($q) use (&$closure, &$relations, $operator, $count, $callback) {\n            // In order to nest \"has\", we need to add count relation constraints on the\n            // callback Closure. We'll do this by simply passing the Closure its own\n            // reference to itself so it calls itself recursively on each segment.\n            count($relations) > 1\n                ? $q->whereHas(array_shift($relations), $closure)\n                : $q->has(array_shift($relations), $operator, $count, 'and', $callback);\n        };\n\n        return $this->has(array_shift($relations), $doesntHave ? '<' : '>=', 1, $boolean, $closure);\n    }\n\n    /**\n     * Add a relationship count / exists condition to the query with an \"or\".\n     *\n     * @param  string  $relation\n     * @param  string  $operator\n     * @param  int  $count\n     * @return \\Illuminate\\Database\\Eloquent\\Builder|static\n     */\n    public function orHas($relation, $operator = '>=', $count = 1)\n    {\n        return $this->has($relation, $operator, $count, 'or');\n    }\n\n    /**\n     * Add a relationship count / exists condition to the query.\n     *\n     * @param  string  $relation\n     * @param  string  $boolean\n     * @param  \\Closure|null  $callback\n     * @return \\Illuminate\\Database\\Eloquent\\Builder|static\n     */\n    public function doesntHave($relation, $boolean = 'and', Closure $callback = null)\n    {\n        return $this->has($relation, '<', 1, $boolean, $callback);\n    }\n\n    /**\n     * Add a relationship count / exists condition to the query with an \"or\".\n     *\n     * @param  string  $relation\n     * @return \\Illuminate\\Database\\Eloquent\\Builder|static\n     */\n    public function orDoesntHave($relation)\n    {\n        return $this->doesntHave($relation, 'or');\n    }\n\n    /**\n     * Add a relationship count / exists condition to the query with where clauses.\n     *\n     * @param  string  $relation\n     * @param  \\Closure|null  $callback\n     * @param  string  $operator\n     * @param  int  $count\n     * @return \\Illuminate\\Database\\Eloquent\\Builder|static\n     */\n    public function whereHas($relation, Closure $callback = null, $operator = '>=', $count = 1)\n    {\n        return $this->has($relation, $operator, $count, 'and', $callback);\n    }\n\n    /**\n     * Add a relationship count / exists condition to the query with where clauses and an \"or\".\n     *\n     * @param  string  $relation\n     * @param  \\Closure|null  $callback\n     * @param  string  $operator\n     * @param  int  $count\n     * @return \\Illuminate\\Database\\Eloquent\\Builder|static\n     */\n    public function orWhereHas($relation, Closure $callback = null, $operator = '>=', $count = 1)\n    {\n        return $this->has($relation, $operator, $count, 'or', $callback);\n    }\n\n    /**\n     * Add a relationship count / exists condition to the query with where clauses.\n     *\n     * @param  string  $relation\n     * @param  \\Closure|null  $callback\n     * @return \\Illuminate\\Database\\Eloquent\\Builder|static\n     */\n    public function whereDoesntHave($relation, Closure $callback = null)\n    {\n        return $this->doesntHave($relation, 'and', $callback);\n    }\n\n    /**\n     * Add a relationship count / exists condition to the query with where clauses and an \"or\".\n     *\n     * @param  string  $relation\n     * @param  \\Closure|null  $callback\n     * @return \\Illuminate\\Database\\Eloquent\\Builder|static\n     */\n    public function orWhereDoesntHave($relation, Closure $callback = null)\n    {\n        return $this->doesntHave($relation, 'or', $callback);\n    }\n\n    /**\n     * Add a polymorphic relationship count / exists condition to the query.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Relations\\MorphTo|string  $relation\n     * @param  string|array  $types\n     * @param  string  $operator\n     * @param  int  $count\n     * @param  string  $boolean\n     * @param  \\Closure|null  $callback\n     * @return \\Illuminate\\Database\\Eloquent\\Builder|static\n     */\n    public function hasMorph($relation, $types, $operator = '>=', $count = 1, $boolean = 'and', Closure $callback = null)\n    {\n        if (is_string($relation)) {\n            $relation = $this->getRelationWithoutConstraints($relation);\n        }\n\n        $types = (array) $types;\n\n        if ($types === ['*']) {\n            $types = $this->model->newModelQuery()->distinct()->pluck($relation->getMorphType())->filter()->all();\n        }\n\n        foreach ($types as &$type) {\n            $type = Relation::getMorphedModel($type) ?? $type;\n        }\n\n        return $this->where(function ($query) use ($relation, $callback, $operator, $count, $types) {\n            foreach ($types as $type) {\n                $query->orWhere(function ($query) use ($relation, $callback, $operator, $count, $type) {\n                    $belongsTo = $this->getBelongsToRelation($relation, $type);\n\n                    if ($callback) {\n                        $callback = function ($query) use ($callback, $type) {\n                            return $callback($query, $type);\n                        };\n                    }\n\n                    $query->where($this->qualifyColumn($relation->getMorphType()), '=', (new $type)->getMorphClass())\n                                ->whereHas($belongsTo, $callback, $operator, $count);\n                });\n            }\n        }, null, null, $boolean);\n    }\n\n    /**\n     * Get the BelongsTo relationship for a single polymorphic type.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Relations\\MorphTo  $relation\n     * @param  string  $type\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\BelongsTo\n     */\n    protected function getBelongsToRelation(MorphTo $relation, $type)\n    {\n        $belongsTo = Relation::noConstraints(function () use ($relation, $type) {\n            return $this->model->belongsTo(\n                $type,\n                $relation->getForeignKeyName(),\n                $relation->getOwnerKeyName()\n            );\n        });\n\n        $belongsTo->getQuery()->mergeConstraintsFrom($relation->getQuery());\n\n        return $belongsTo;\n    }\n\n    /**\n     * Add a polymorphic relationship count / exists condition to the query with an \"or\".\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Relations\\MorphTo|string  $relation\n     * @param  string|array  $types\n     * @param  string  $operator\n     * @param  int  $count\n     * @return \\Illuminate\\Database\\Eloquent\\Builder|static\n     */\n    public function orHasMorph($relation, $types, $operator = '>=', $count = 1)\n    {\n        return $this->hasMorph($relation, $types, $operator, $count, 'or');\n    }\n\n    /**\n     * Add a polymorphic relationship count / exists condition to the query.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Relations\\MorphTo|string  $relation\n     * @param  string|array  $types\n     * @param  string  $boolean\n     * @param  \\Closure|null  $callback\n     * @return \\Illuminate\\Database\\Eloquent\\Builder|static\n     */\n    public function doesntHaveMorph($relation, $types, $boolean = 'and', Closure $callback = null)\n    {\n        return $this->hasMorph($relation, $types, '<', 1, $boolean, $callback);\n    }\n\n    /**\n     * Add a polymorphic relationship count / exists condition to the query with an \"or\".\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Relations\\MorphTo|string  $relation\n     * @param  string|array  $types\n     * @return \\Illuminate\\Database\\Eloquent\\Builder|static\n     */\n    public function orDoesntHaveMorph($relation, $types)\n    {\n        return $this->doesntHaveMorph($relation, $types, 'or');\n    }\n\n    /**\n     * Add a polymorphic relationship count / exists condition to the query with where clauses.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Relations\\MorphTo|string  $relation\n     * @param  string|array  $types\n     * @param  \\Closure|null  $callback\n     * @param  string  $operator\n     * @param  int  $count\n     * @return \\Illuminate\\Database\\Eloquent\\Builder|static\n     */\n    public function whereHasMorph($relation, $types, Closure $callback = null, $operator = '>=', $count = 1)\n    {\n        return $this->hasMorph($relation, $types, $operator, $count, 'and', $callback);\n    }\n\n    /**\n     * Add a polymorphic relationship count / exists condition to the query with where clauses and an \"or\".\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Relations\\MorphTo|string  $relation\n     * @param  string|array  $types\n     * @param  \\Closure|null  $callback\n     * @param  string  $operator\n     * @param  int  $count\n     * @return \\Illuminate\\Database\\Eloquent\\Builder|static\n     */\n    public function orWhereHasMorph($relation, $types, Closure $callback = null, $operator = '>=', $count = 1)\n    {\n        return $this->hasMorph($relation, $types, $operator, $count, 'or', $callback);\n    }\n\n    /**\n     * Add a polymorphic relationship count / exists condition to the query with where clauses.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Relations\\MorphTo|string  $relation\n     * @param  string|array  $types\n     * @param  \\Closure|null  $callback\n     * @return \\Illuminate\\Database\\Eloquent\\Builder|static\n     */\n    public function whereDoesntHaveMorph($relation, $types, Closure $callback = null)\n    {\n        return $this->doesntHaveMorph($relation, $types, 'and', $callback);\n    }\n\n    /**\n     * Add a polymorphic relationship count / exists condition to the query with where clauses and an \"or\".\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Relations\\MorphTo|string  $relation\n     * @param  string|array  $types\n     * @param  \\Closure|null  $callback\n     * @return \\Illuminate\\Database\\Eloquent\\Builder|static\n     */\n    public function orWhereDoesntHaveMorph($relation, $types, Closure $callback = null)\n    {\n        return $this->doesntHaveMorph($relation, $types, 'or', $callback);\n    }\n\n    /**\n     * Add a basic where clause to a relationship query.\n     *\n     * @param  string  $relation\n     * @param  \\Closure|string|array|\\Illuminate\\Database\\Query\\Expression  $column\n     * @param  mixed  $operator\n     * @param  mixed  $value\n     * @return \\Illuminate\\Database\\Eloquent\\Builder|static\n     */\n    public function whereRelation($relation, $column, $operator = null, $value = null)\n    {\n        return $this->whereHas($relation, function ($query) use ($column, $operator, $value) {\n            $query->where($column, $operator, $value);\n        });\n    }\n\n    /**\n     * Add an \"or where\" clause to a relationship query.\n     *\n     * @param  string  $relation\n     * @param  \\Closure|string|array|\\Illuminate\\Database\\Query\\Expression  $column\n     * @param  mixed  $operator\n     * @param  mixed  $value\n     * @return \\Illuminate\\Database\\Eloquent\\Builder|static\n     */\n    public function orWhereRelation($relation, $column, $operator = null, $value = null)\n    {\n        return $this->orWhereHas($relation, function ($query) use ($column, $operator, $value) {\n            $query->where($column, $operator, $value);\n        });\n    }\n\n    /**\n     * Add a polymorphic relationship condition to the query with a where clause.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Relations\\MorphTo|string  $relation\n     * @param  string|array  $types\n     * @param  \\Closure|string|array|\\Illuminate\\Database\\Query\\Expression  $column\n     * @param  mixed  $operator\n     * @param  mixed  $value\n     * @return \\Illuminate\\Database\\Eloquent\\Builder|static\n     */\n    public function whereMorphRelation($relation, $types, $column, $operator = null, $value = null)\n    {\n        return $this->whereHasMorph($relation, $types, function ($query) use ($column, $operator, $value) {\n            $query->where($column, $operator, $value);\n        });\n    }\n\n    /**\n     * Add a polymorphic relationship condition to the query with an \"or where\" clause.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Relations\\MorphTo|string  $relation\n     * @param  string|array  $types\n     * @param  \\Closure|string|array|\\Illuminate\\Database\\Query\\Expression  $column\n     * @param  mixed  $operator\n     * @param  mixed  $value\n     * @return \\Illuminate\\Database\\Eloquent\\Builder|static\n     */\n    public function orWhereMorphRelation($relation, $types, $column, $operator = null, $value = null)\n    {\n        return $this->orWhereHasMorph($relation, $types, function ($query) use ($column, $operator, $value) {\n            $query->where($column, $operator, $value);\n        });\n    }\n\n    /**\n     * Add a morph-to relationship condition to the query.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Relations\\MorphTo|string  $relation\n     * @param  \\Illuminate\\Database\\Eloquent\\Model|string  $model\n     * @return \\Illuminate\\Database\\Eloquent\\Builder|static\n     */\n    public function whereMorphedTo($relation, $model, $boolean = 'and')\n    {\n        if (is_string($relation)) {\n            $relation = $this->getRelationWithoutConstraints($relation);\n        }\n\n        if (is_string($model)) {\n            $morphMap = Relation::morphMap();\n\n            if (! empty($morphMap) && in_array($model, $morphMap)) {\n                $model = array_search($model, $morphMap, true);\n            }\n\n            return $this->where($relation->getMorphType(), $model, null, $boolean);\n        }\n\n        return $this->where(function ($query) use ($relation, $model) {\n            $query->where($relation->getMorphType(), $model->getMorphClass())\n                ->where($relation->getForeignKeyName(), $model->getKey());\n        }, null, null, $boolean);\n    }\n\n    /**\n     * Add a morph-to relationship condition to the query with an \"or where\" clause.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Relations\\MorphTo|string  $relation\n     * @param  \\Illuminate\\Database\\Eloquent\\Model|string  $model\n     * @return \\Illuminate\\Database\\Eloquent\\Builder|static\n     */\n    public function orWhereMorphedTo($relation, $model)\n    {\n        return $this->whereMorphedTo($relation, $model, 'or');\n    }\n\n    /**\n     * Add a \"belongs to\" relationship where clause to the query.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $related\n     * @param  string  $relationship\n     * @param  string  $boolean\n     * @return $this\n     *\n     * @throws \\RuntimeException\n     */\n    public function whereBelongsTo($related, $relationshipName = null, $boolean = 'and')\n    {\n        if ($relationshipName === null) {\n            $relationshipName = Str::camel(class_basename($related));\n        }\n\n        try {\n            $relationship = $this->model->{$relationshipName}();\n        } catch (BadMethodCallException $exception) {\n            throw RelationNotFoundException::make($this->model, $relationshipName);\n        }\n\n        if (! $relationship instanceof BelongsTo) {\n            throw RelationNotFoundException::make($this->model, $relationshipName, BelongsTo::class);\n        }\n\n        $this->where(\n            $relationship->getQualifiedForeignKeyName(),\n            '=',\n            $related->getAttributeValue($relationship->getOwnerKeyName()),\n            $boolean,\n        );\n\n        return $this;\n    }\n\n    /**\n     * Add an \"BelongsTo\" relationship with an \"or where\" clause to the query.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $related\n     * @param  string  $relationship\n     * @return $this\n     *\n     * @throws \\RuntimeException\n     */\n    public function orWhereBelongsTo($related, $relationshipName = null)\n    {\n        return $this->whereBelongsTo($related, $relationshipName, 'or');\n    }\n\n    /**\n     * Add subselect queries to include an aggregate value for a relationship.\n     *\n     * @param  mixed  $relations\n     * @param  string  $column\n     * @param  string  $function\n     * @return $this\n     */\n    public function withAggregate($relations, $column, $function = null)\n    {\n        if (empty($relations)) {\n            return $this;\n        }\n\n        if (is_null($this->query->columns)) {\n            $this->query->select([$this->query->from.'.*']);\n        }\n\n        $relations = is_array($relations) ? $relations : [$relations];\n\n        foreach ($this->parseWithRelations($relations) as $name => $constraints) {\n            // First we will determine if the name has been aliased using an \"as\" clause on the name\n            // and if it has we will extract the actual relationship name and the desired name of\n            // the resulting column. This allows multiple aggregates on the same relationships.\n            $segments = explode(' ', $name);\n\n            unset($alias);\n\n            if (count($segments) === 3 && Str::lower($segments[1]) === 'as') {\n                [$name, $alias] = [$segments[0], $segments[2]];\n            }\n\n            $relation = $this->getRelationWithoutConstraints($name);\n\n            if ($function) {\n                $hashedColumn = $this->getQuery()->from === $relation->getQuery()->getQuery()->from\n                                            ? \"{$relation->getRelationCountHash(false)}.$column\"\n                                            : $column;\n\n                $wrappedColumn = $this->getQuery()->getGrammar()->wrap(\n                    $column === '*' ? $column : $relation->getRelated()->qualifyColumn($hashedColumn)\n                );\n\n                $expression = $function === 'exists' ? $wrappedColumn : sprintf('%s(%s)', $function, $wrappedColumn);\n            } else {\n                $expression = $column;\n            }\n\n            // Here, we will grab the relationship sub-query and prepare to add it to the main query\n            // as a sub-select. First, we'll get the \"has\" query and use that to get the relation\n            // sub-query. We'll format this relationship name and append this column if needed.\n            $query = $relation->getRelationExistenceQuery(\n                $relation->getRelated()->newQuery(), $this, new Expression($expression)\n            )->setBindings([], 'select');\n\n            $query->callScope($constraints);\n\n            $query = $query->mergeConstraintsFrom($relation->getQuery())->toBase();\n\n            // If the query contains certain elements like orderings / more than one column selected\n            // then we will remove those elements from the query so that it will execute properly\n            // when given to the database. Otherwise, we may receive SQL errors or poor syntax.\n            $query->orders = null;\n            $query->setBindings([], 'order');\n\n            if (count($query->columns) > 1) {\n                $query->columns = [$query->columns[0]];\n                $query->bindings['select'] = [];\n            }\n\n            // Finally, we will make the proper column alias to the query and run this sub-select on\n            // the query builder. Then, we will return the builder instance back to the developer\n            // for further constraint chaining that needs to take place on the query as needed.\n            $alias = $alias ?? Str::snake(\n                preg_replace('/[^[:alnum:][:space:]_]/u', '', \"$name $function $column\")\n            );\n\n            if ($function === 'exists') {\n                $this->selectRaw(\n                    sprintf('exists(%s) as %s', $query->toSql(), $this->getQuery()->grammar->wrap($alias)),\n                    $query->getBindings()\n                )->withCasts([$alias => 'bool']);\n            } else {\n                $this->selectSub(\n                    $function ? $query : $query->limit(1),\n                    $alias\n                );\n            }\n        }\n\n        return $this;\n    }\n\n    /**\n     * Add subselect queries to count the relations.\n     *\n     * @param  mixed  $relations\n     * @return $this\n     */\n    public function withCount($relations)\n    {\n        return $this->withAggregate(is_array($relations) ? $relations : func_get_args(), '*', 'count');\n    }\n\n    /**\n     * Add subselect queries to include the max of the relation's column.\n     *\n     * @param  string|array  $relation\n     * @param  string  $column\n     * @return $this\n     */\n    public function withMax($relation, $column)\n    {\n        return $this->withAggregate($relation, $column, 'max');\n    }\n\n    /**\n     * Add subselect queries to include the min of the relation's column.\n     *\n     * @param  string|array  $relation\n     * @param  string  $column\n     * @return $this\n     */\n    public function withMin($relation, $column)\n    {\n        return $this->withAggregate($relation, $column, 'min');\n    }\n\n    /**\n     * Add subselect queries to include the sum of the relation's column.\n     *\n     * @param  string|array  $relation\n     * @param  string  $column\n     * @return $this\n     */\n    public function withSum($relation, $column)\n    {\n        return $this->withAggregate($relation, $column, 'sum');\n    }\n\n    /**\n     * Add subselect queries to include the average of the relation's column.\n     *\n     * @param  string|array  $relation\n     * @param  string  $column\n     * @return $this\n     */\n    public function withAvg($relation, $column)\n    {\n        return $this->withAggregate($relation, $column, 'avg');\n    }\n\n    /**\n     * Add subselect queries to include the existence of related models.\n     *\n     * @param  string|array  $relation\n     * @return $this\n     */\n    public function withExists($relation)\n    {\n        return $this->withAggregate($relation, '*', 'exists');\n    }\n\n    /**\n     * Add the \"has\" condition where clause to the query.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $hasQuery\n     * @param  \\Illuminate\\Database\\Eloquent\\Relations\\Relation  $relation\n     * @param  string  $operator\n     * @param  int  $count\n     * @param  string  $boolean\n     * @return \\Illuminate\\Database\\Eloquent\\Builder|static\n     */\n    protected function addHasWhere(Builder $hasQuery, Relation $relation, $operator, $count, $boolean)\n    {\n        $hasQuery->mergeConstraintsFrom($relation->getQuery());\n\n        return $this->canUseExistsForExistenceCheck($operator, $count)\n                ? $this->addWhereExistsQuery($hasQuery->toBase(), $boolean, $operator === '<' && $count === 1)\n                : $this->addWhereCountQuery($hasQuery->toBase(), $operator, $count, $boolean);\n    }\n\n    /**\n     * Merge the where constraints from another query to the current query.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $from\n     * @return \\Illuminate\\Database\\Eloquent\\Builder|static\n     */\n    public function mergeConstraintsFrom(Builder $from)\n    {\n        $whereBindings = $from->getQuery()->getRawBindings()['where'] ?? [];\n\n        // Here we have some other query that we want to merge the where constraints from. We will\n        // copy over any where constraints on the query as well as remove any global scopes the\n        // query might have removed. Then we will return ourselves with the finished merging.\n        return $this->withoutGlobalScopes(\n            $from->removedScopes()\n        )->mergeWheres(\n            $from->getQuery()->wheres, $whereBindings\n        );\n    }\n\n    /**\n     * Add a sub-query count clause to this query.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  string  $operator\n     * @param  int  $count\n     * @param  string  $boolean\n     * @return $this\n     */\n    protected function addWhereCountQuery(QueryBuilder $query, $operator = '>=', $count = 1, $boolean = 'and')\n    {\n        $this->query->addBinding($query->getBindings(), 'where');\n\n        return $this->where(\n            new Expression('('.$query->toSql().')'),\n            $operator,\n            is_numeric($count) ? new Expression($count) : $count,\n            $boolean\n        );\n    }\n\n    /**\n     * Get the \"has relation\" base query instance.\n     *\n     * @param  string  $relation\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\Relation\n     */\n    protected function getRelationWithoutConstraints($relation)\n    {\n        return Relation::noConstraints(function () use ($relation) {\n            return $this->getModel()->{$relation}();\n        });\n    }\n\n    /**\n     * Check if we can run an \"exists\" query to optimize performance.\n     *\n     * @param  string  $operator\n     * @param  int  $count\n     * @return bool\n     */\n    protected function canUseExistsForExistenceCheck($operator, $count)\n    {\n        return ($operator === '>=' || $operator === '<') && $count === 1;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/Factories/BelongsToManyRelationship.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent\\Factories;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Support\\Collection;\n\nclass BelongsToManyRelationship\n{\n    /**\n     * The related factory instance.\n     *\n     * @var \\Illuminate\\Database\\Eloquent\\Factories\\Factory|\\Illuminate\\Support\\Collection|\\Illuminate\\Database\\Eloquent\\Model\n     */\n    protected $factory;\n\n    /**\n     * The pivot attributes / attribute resolver.\n     *\n     * @var callable|array\n     */\n    protected $pivot;\n\n    /**\n     * The relationship name.\n     *\n     * @var string\n     */\n    protected $relationship;\n\n    /**\n     * Create a new attached relationship definition.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Factories\\Factory|\\Illuminate\\Support\\Collection|\\Illuminate\\Database\\Eloquent\\Model  $factory\n     * @param  callable|array  $pivot\n     * @param  string  $relationship\n     * @return void\n     */\n    public function __construct($factory, $pivot, $relationship)\n    {\n        $this->factory = $factory;\n        $this->pivot = $pivot;\n        $this->relationship = $relationship;\n    }\n\n    /**\n     * Create the attached relationship for the given model.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $model\n     * @return void\n     */\n    public function createFor(Model $model)\n    {\n        Collection::wrap($this->factory instanceof Factory ? $this->factory->create([], $model) : $this->factory)->each(function ($attachable) use ($model) {\n            $model->{$this->relationship}()->attach(\n                $attachable,\n                is_callable($this->pivot) ? call_user_func($this->pivot, $model) : $this->pivot\n            );\n        });\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/Factories/BelongsToRelationship.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent\\Factories;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Database\\Eloquent\\Relations\\MorphTo;\n\nclass BelongsToRelationship\n{\n    /**\n     * The related factory instance.\n     *\n     * @var \\Illuminate\\Database\\Eloquent\\Factories\\Factory|\\Illuminate\\Database\\Eloquent\\Model\n     */\n    protected $factory;\n\n    /**\n     * The relationship name.\n     *\n     * @var string\n     */\n    protected $relationship;\n\n    /**\n     * The cached, resolved parent instance ID.\n     *\n     * @var mixed\n     */\n    protected $resolved;\n\n    /**\n     * Create a new \"belongs to\" relationship definition.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Factories\\Factory|\\Illuminate\\Database\\Eloquent\\Model  $factory\n     * @param  string  $relationship\n     * @return void\n     */\n    public function __construct($factory, $relationship)\n    {\n        $this->factory = $factory;\n        $this->relationship = $relationship;\n    }\n\n    /**\n     * Get the parent model attributes and resolvers for the given child model.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $model\n     * @return array\n     */\n    public function attributesFor(Model $model)\n    {\n        $relationship = $model->{$this->relationship}();\n\n        return $relationship instanceof MorphTo ? [\n            $relationship->getMorphType() => $this->factory instanceof Factory ? $this->factory->newModel()->getMorphClass() : $this->factory->getMorphClass(),\n            $relationship->getForeignKeyName() => $this->resolver($relationship->getOwnerKeyName()),\n        ] : [\n            $relationship->getForeignKeyName() => $this->resolver($relationship->getOwnerKeyName()),\n        ];\n    }\n\n    /**\n     * Get the deferred resolver for this relationship's parent ID.\n     *\n     * @param  string|null  $key\n     * @return \\Closure\n     */\n    protected function resolver($key)\n    {\n        return function () use ($key) {\n            if (! $this->resolved) {\n                $instance = $this->factory instanceof Factory ? $this->factory->create() : $this->factory;\n\n                return $this->resolved = $key ? $instance->{$key} : $instance->getKey();\n            }\n\n            return $this->resolved;\n        };\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/Factories/CrossJoinSequence.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent\\Factories;\n\nuse Illuminate\\Support\\Arr;\n\nclass CrossJoinSequence extends Sequence\n{\n    /**\n     * Create a new cross join sequence instance.\n     *\n     * @param  array  $sequences\n     * @return void\n     */\n    public function __construct(...$sequences)\n    {\n        $crossJoined = array_map(\n            function ($a) {\n                return array_merge(...$a);\n            },\n            Arr::crossJoin(...$sequences),\n        );\n\n        parent::__construct(...$crossJoined);\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/Factories/Factory.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent\\Factories;\n\nuse Closure;\nuse Faker\\Generator;\nuse Illuminate\\Container\\Container;\nuse Illuminate\\Contracts\\Foundation\\Application;\nuse Illuminate\\Database\\Eloquent\\Collection as EloquentCollection;\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Support\\Collection;\nuse Illuminate\\Support\\Str;\nuse Illuminate\\Support\\Traits\\Conditionable;\nuse Illuminate\\Support\\Traits\\ForwardsCalls;\nuse Illuminate\\Support\\Traits\\Macroable;\nuse Throwable;\n\nabstract class Factory\n{\n    use Conditionable, ForwardsCalls, Macroable {\n        __call as macroCall;\n    }\n\n    /**\n     * The name of the factory's corresponding model.\n     *\n     * @var string|null\n     */\n    protected $model;\n\n    /**\n     * The number of models that should be generated.\n     *\n     * @var int|null\n     */\n    protected $count;\n\n    /**\n     * The state transformations that will be applied to the model.\n     *\n     * @var \\Illuminate\\Support\\Collection\n     */\n    protected $states;\n\n    /**\n     * The parent relationships that will be applied to the model.\n     *\n     * @var \\Illuminate\\Support\\Collection\n     */\n    protected $has;\n\n    /**\n     * The child relationships that will be applied to the model.\n     *\n     * @var \\Illuminate\\Support\\Collection\n     */\n    protected $for;\n\n    /**\n     * The \"after making\" callbacks that will be applied to the model.\n     *\n     * @var \\Illuminate\\Support\\Collection\n     */\n    protected $afterMaking;\n\n    /**\n     * The \"after creating\" callbacks that will be applied to the model.\n     *\n     * @var \\Illuminate\\Support\\Collection\n     */\n    protected $afterCreating;\n\n    /**\n     * The name of the database connection that will be used to create the models.\n     *\n     * @var string\n     */\n    protected $connection;\n\n    /**\n     * The current Faker instance.\n     *\n     * @var \\Faker\\Generator\n     */\n    protected $faker;\n\n    /**\n     * The default namespace where factories reside.\n     *\n     * @var string\n     */\n    protected static $namespace = 'Database\\\\Factories\\\\';\n\n    /**\n     * The default model name resolver.\n     *\n     * @var callable\n     */\n    protected static $modelNameResolver;\n\n    /**\n     * The factory name resolver.\n     *\n     * @var callable\n     */\n    protected static $factoryNameResolver;\n\n    /**\n     * Create a new factory instance.\n     *\n     * @param  int|null  $count\n     * @param  \\Illuminate\\Support\\Collection|null  $states\n     * @param  \\Illuminate\\Support\\Collection|null  $has\n     * @param  \\Illuminate\\Support\\Collection|null  $for\n     * @param  \\Illuminate\\Support\\Collection|null  $afterMaking\n     * @param  \\Illuminate\\Support\\Collection|null  $afterCreating\n     * @param  string|null  $connection\n     * @return void\n     */\n    public function __construct($count = null,\n                                ?Collection $states = null,\n                                ?Collection $has = null,\n                                ?Collection $for = null,\n                                ?Collection $afterMaking = null,\n                                ?Collection $afterCreating = null,\n                                $connection = null)\n    {\n        $this->count = $count;\n        $this->states = $states ?: new Collection;\n        $this->has = $has ?: new Collection;\n        $this->for = $for ?: new Collection;\n        $this->afterMaking = $afterMaking ?: new Collection;\n        $this->afterCreating = $afterCreating ?: new Collection;\n        $this->connection = $connection;\n        $this->faker = $this->withFaker();\n    }\n\n    /**\n     * Define the model's default state.\n     *\n     * @return array\n     */\n    abstract public function definition();\n\n    /**\n     * Get a new factory instance for the given attributes.\n     *\n     * @param  callable|array  $attributes\n     * @return static\n     */\n    public static function new($attributes = [])\n    {\n        return (new static)->state($attributes)->configure();\n    }\n\n    /**\n     * Get a new factory instance for the given number of models.\n     *\n     * @param  int  $count\n     * @return static\n     */\n    public static function times(int $count)\n    {\n        return static::new()->count($count);\n    }\n\n    /**\n     * Configure the factory.\n     *\n     * @return $this\n     */\n    public function configure()\n    {\n        return $this;\n    }\n\n    /**\n     * Get the raw attributes generated by the factory.\n     *\n     * @param  array  $attributes\n     * @param  \\Illuminate\\Database\\Eloquent\\Model|null  $parent\n     * @return array\n     */\n    public function raw($attributes = [], ?Model $parent = null)\n    {\n        if ($this->count === null) {\n            return $this->state($attributes)->getExpandedAttributes($parent);\n        }\n\n        return array_map(function () use ($attributes, $parent) {\n            return $this->state($attributes)->getExpandedAttributes($parent);\n        }, range(1, $this->count));\n    }\n\n    /**\n     * Create a single model and persist it to the database.\n     *\n     * @param  array  $attributes\n     * @return \\Illuminate\\Database\\Eloquent\\Model\n     */\n    public function createOne($attributes = [])\n    {\n        return $this->count(null)->create($attributes);\n    }\n\n    /**\n     * Create a single model and persist it to the database.\n     *\n     * @param  array  $attributes\n     * @return \\Illuminate\\Database\\Eloquent\\Model\n     */\n    public function createOneQuietly($attributes = [])\n    {\n        return $this->count(null)->createQuietly($attributes);\n    }\n\n    /**\n     * Create a collection of models and persist them to the database.\n     *\n     * @param  iterable  $records\n     * @return \\Illuminate\\Database\\Eloquent\\Collection\n     */\n    public function createMany(iterable $records)\n    {\n        return new EloquentCollection(\n            collect($records)->map(function ($record) {\n                return $this->state($record)->create();\n            })\n        );\n    }\n\n    /**\n     * Create a collection of models and persist them to the database.\n     *\n     * @param  iterable  $records\n     * @return \\Illuminate\\Database\\Eloquent\\Collection\n     */\n    public function createManyQuietly(iterable $records)\n    {\n        return Model::withoutEvents(function () use ($records) {\n            return $this->createMany($records);\n        });\n    }\n\n    /**\n     * Create a collection of models and persist them to the database.\n     *\n     * @param  array  $attributes\n     * @param  \\Illuminate\\Database\\Eloquent\\Model|null  $parent\n     * @return \\Illuminate\\Database\\Eloquent\\Collection|\\Illuminate\\Database\\Eloquent\\Model\n     */\n    public function create($attributes = [], ?Model $parent = null)\n    {\n        if (! empty($attributes)) {\n            return $this->state($attributes)->create([], $parent);\n        }\n\n        $results = $this->make($attributes, $parent);\n\n        if ($results instanceof Model) {\n            $this->store(collect([$results]));\n\n            $this->callAfterCreating(collect([$results]), $parent);\n        } else {\n            $this->store($results);\n\n            $this->callAfterCreating($results, $parent);\n        }\n\n        return $results;\n    }\n\n    /**\n     * Create a collection of models and persist them to the database.\n     *\n     * @param  array  $attributes\n     * @param  \\Illuminate\\Database\\Eloquent\\Model|null  $parent\n     * @return \\Illuminate\\Database\\Eloquent\\Collection|\\Illuminate\\Database\\Eloquent\\Model\n     */\n    public function createQuietly($attributes = [], ?Model $parent = null)\n    {\n        return Model::withoutEvents(function () use ($attributes, $parent) {\n            return $this->create($attributes, $parent);\n        });\n    }\n\n    /**\n     * Create a callback that persists a model in the database when invoked.\n     *\n     * @param  array  $attributes\n     * @param  \\Illuminate\\Database\\Eloquent\\Model|null  $parent\n     * @return \\Closure\n     */\n    public function lazy(array $attributes = [], ?Model $parent = null)\n    {\n        return function () use ($attributes, $parent) {\n            return $this->create($attributes, $parent);\n        };\n    }\n\n    /**\n     * Set the connection name on the results and store them.\n     *\n     * @param  \\Illuminate\\Support\\Collection  $results\n     * @return void\n     */\n    protected function store(Collection $results)\n    {\n        $results->each(function ($model) {\n            if (! isset($this->connection)) {\n                $model->setConnection($model->newQueryWithoutScopes()->getConnection()->getName());\n            }\n\n            $model->save();\n\n            $this->createChildren($model);\n        });\n    }\n\n    /**\n     * Create the children for the given model.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $model\n     * @return void\n     */\n    protected function createChildren(Model $model)\n    {\n        Model::unguarded(function () use ($model) {\n            $this->has->each(function ($has) use ($model) {\n                $has->createFor($model);\n            });\n        });\n    }\n\n    /**\n     * Make a single instance of the model.\n     *\n     * @param  callable|array  $attributes\n     * @return \\Illuminate\\Database\\Eloquent\\Model\n     */\n    public function makeOne($attributes = [])\n    {\n        return $this->count(null)->make($attributes);\n    }\n\n    /**\n     * Create a collection of models.\n     *\n     * @param  array  $attributes\n     * @param  \\Illuminate\\Database\\Eloquent\\Model|null  $parent\n     * @return \\Illuminate\\Database\\Eloquent\\Collection|\\Illuminate\\Database\\Eloquent\\Model\n     */\n    public function make($attributes = [], ?Model $parent = null)\n    {\n        if (! empty($attributes)) {\n            return $this->state($attributes)->make([], $parent);\n        }\n\n        if ($this->count === null) {\n            return tap($this->makeInstance($parent), function ($instance) {\n                $this->callAfterMaking(collect([$instance]));\n            });\n        }\n\n        if ($this->count < 1) {\n            return $this->newModel()->newCollection();\n        }\n\n        $instances = $this->newModel()->newCollection(array_map(function () use ($parent) {\n            return $this->makeInstance($parent);\n        }, range(1, $this->count)));\n\n        $this->callAfterMaking($instances);\n\n        return $instances;\n    }\n\n    /**\n     * Make an instance of the model with the given attributes.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Model|null  $parent\n     * @return \\Illuminate\\Database\\Eloquent\\Model\n     */\n    protected function makeInstance(?Model $parent)\n    {\n        return Model::unguarded(function () use ($parent) {\n            return tap($this->newModel($this->getExpandedAttributes($parent)), function ($instance) {\n                if (isset($this->connection)) {\n                    $instance->setConnection($this->connection);\n                }\n            });\n        });\n    }\n\n    /**\n     * Get a raw attributes array for the model.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Model|null  $parent\n     * @return mixed\n     */\n    protected function getExpandedAttributes(?Model $parent)\n    {\n        return $this->expandAttributes($this->getRawAttributes($parent));\n    }\n\n    /**\n     * Get the raw attributes for the model as an array.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Model|null  $parent\n     * @return array\n     */\n    protected function getRawAttributes(?Model $parent)\n    {\n        return $this->states->pipe(function ($states) {\n            return $this->for->isEmpty() ? $states : new Collection(array_merge([function () {\n                return $this->parentResolvers();\n            }], $states->all()));\n        })->reduce(function ($carry, $state) use ($parent) {\n            if ($state instanceof Closure) {\n                $state = $state->bindTo($this);\n            }\n\n            return array_merge($carry, $state($carry, $parent));\n        }, $this->definition());\n    }\n\n    /**\n     * Create the parent relationship resolvers (as deferred Closures).\n     *\n     * @return array\n     */\n    protected function parentResolvers()\n    {\n        $model = $this->newModel();\n\n        return $this->for->map(function (BelongsToRelationship $for) use ($model) {\n            return $for->attributesFor($model);\n        })->collapse()->all();\n    }\n\n    /**\n     * Expand all attributes to their underlying values.\n     *\n     * @param  array  $definition\n     * @return array\n     */\n    protected function expandAttributes(array $definition)\n    {\n        return collect($definition)->map(function ($attribute, $key) use (&$definition) {\n            if (is_callable($attribute) && ! is_string($attribute) && ! is_array($attribute)) {\n                $attribute = $attribute($definition);\n            }\n\n            if ($attribute instanceof self) {\n                $attribute = $attribute->create()->getKey();\n            } elseif ($attribute instanceof Model) {\n                $attribute = $attribute->getKey();\n            }\n\n            $definition[$key] = $attribute;\n\n            return $attribute;\n        })->all();\n    }\n\n    /**\n     * Add a new state transformation to the model definition.\n     *\n     * @param  callable|array  $state\n     * @return static\n     */\n    public function state($state)\n    {\n        return $this->newInstance([\n            'states' => $this->states->concat([\n                is_callable($state) ? $state : function () use ($state) {\n                    return $state;\n                },\n            ]),\n        ]);\n    }\n\n    /**\n     * Add a new sequenced state transformation to the model definition.\n     *\n     * @param  array  $sequence\n     * @return static\n     */\n    public function sequence(...$sequence)\n    {\n        return $this->state(new Sequence(...$sequence));\n    }\n\n    /**\n     * Add a new cross joined sequenced state transformation to the model definition.\n     *\n     * @param  array  $sequence\n     * @return static\n     */\n    public function crossJoinSequence(...$sequence)\n    {\n        return $this->state(new CrossJoinSequence(...$sequence));\n    }\n\n    /**\n     * Define a child relationship for the model.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Factories\\Factory  $factory\n     * @param  string|null  $relationship\n     * @return static\n     */\n    public function has(self $factory, $relationship = null)\n    {\n        return $this->newInstance([\n            'has' => $this->has->concat([new Relationship(\n                $factory, $relationship ?: $this->guessRelationship($factory->modelName())\n            )]),\n        ]);\n    }\n\n    /**\n     * Attempt to guess the relationship name for a \"has\" relationship.\n     *\n     * @param  string  $related\n     * @return string\n     */\n    protected function guessRelationship(string $related)\n    {\n        $guess = Str::camel(Str::plural(class_basename($related)));\n\n        return method_exists($this->modelName(), $guess) ? $guess : Str::singular($guess);\n    }\n\n    /**\n     * Define an attached relationship for the model.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Factories\\Factory|\\Illuminate\\Support\\Collection|\\Illuminate\\Database\\Eloquent\\Model  $factory\n     * @param  callable|array  $pivot\n     * @param  string|null  $relationship\n     * @return static\n     */\n    public function hasAttached($factory, $pivot = [], $relationship = null)\n    {\n        return $this->newInstance([\n            'has' => $this->has->concat([new BelongsToManyRelationship(\n                $factory,\n                $pivot,\n                $relationship ?: Str::camel(Str::plural(class_basename(\n                    $factory instanceof Factory\n                        ? $factory->modelName()\n                        : Collection::wrap($factory)->first()\n                )))\n            )]),\n        ]);\n    }\n\n    /**\n     * Define a parent relationship for the model.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Factories\\Factory|\\Illuminate\\Database\\Eloquent\\Model  $factory\n     * @param  string|null  $relationship\n     * @return static\n     */\n    public function for($factory, $relationship = null)\n    {\n        return $this->newInstance(['for' => $this->for->concat([new BelongsToRelationship(\n            $factory,\n            $relationship ?: Str::camel(class_basename(\n                $factory instanceof Factory ? $factory->modelName() : $factory\n            ))\n        )])]);\n    }\n\n    /**\n     * Add a new \"after making\" callback to the model definition.\n     *\n     * @param  \\Closure  $callback\n     * @return static\n     */\n    public function afterMaking(Closure $callback)\n    {\n        return $this->newInstance(['afterMaking' => $this->afterMaking->concat([$callback])]);\n    }\n\n    /**\n     * Add a new \"after creating\" callback to the model definition.\n     *\n     * @param  \\Closure  $callback\n     * @return static\n     */\n    public function afterCreating(Closure $callback)\n    {\n        return $this->newInstance(['afterCreating' => $this->afterCreating->concat([$callback])]);\n    }\n\n    /**\n     * Call the \"after making\" callbacks for the given model instances.\n     *\n     * @param  \\Illuminate\\Support\\Collection  $instances\n     * @return void\n     */\n    protected function callAfterMaking(Collection $instances)\n    {\n        $instances->each(function ($model) {\n            $this->afterMaking->each(function ($callback) use ($model) {\n                $callback($model);\n            });\n        });\n    }\n\n    /**\n     * Call the \"after creating\" callbacks for the given model instances.\n     *\n     * @param  \\Illuminate\\Support\\Collection  $instances\n     * @param  \\Illuminate\\Database\\Eloquent\\Model|null  $parent\n     * @return void\n     */\n    protected function callAfterCreating(Collection $instances, ?Model $parent = null)\n    {\n        $instances->each(function ($model) use ($parent) {\n            $this->afterCreating->each(function ($callback) use ($model, $parent) {\n                $callback($model, $parent);\n            });\n        });\n    }\n\n    /**\n     * Specify how many models should be generated.\n     *\n     * @param  int|null  $count\n     * @return static\n     */\n    public function count(?int $count)\n    {\n        return $this->newInstance(['count' => $count]);\n    }\n\n    /**\n     * Specify the database connection that should be used to generate models.\n     *\n     * @param  string  $connection\n     * @return static\n     */\n    public function connection(string $connection)\n    {\n        return $this->newInstance(['connection' => $connection]);\n    }\n\n    /**\n     * Create a new instance of the factory builder with the given mutated properties.\n     *\n     * @param  array  $arguments\n     * @return static\n     */\n    protected function newInstance(array $arguments = [])\n    {\n        return new static(...array_values(array_merge([\n            'count' => $this->count,\n            'states' => $this->states,\n            'has' => $this->has,\n            'for' => $this->for,\n            'afterMaking' => $this->afterMaking,\n            'afterCreating' => $this->afterCreating,\n            'connection' => $this->connection,\n        ], $arguments)));\n    }\n\n    /**\n     * Get a new model instance.\n     *\n     * @param  array  $attributes\n     * @return \\Illuminate\\Database\\Eloquent\\Model\n     */\n    public function newModel(array $attributes = [])\n    {\n        $model = $this->modelName();\n\n        return new $model($attributes);\n    }\n\n    /**\n     * Get the name of the model that is generated by the factory.\n     *\n     * @return string\n     */\n    public function modelName()\n    {\n        $resolver = static::$modelNameResolver ?: function (self $factory) {\n            $namespacedFactoryBasename = Str::replaceLast(\n                'Factory', '', Str::replaceFirst(static::$namespace, '', get_class($factory))\n            );\n\n            $factoryBasename = Str::replaceLast('Factory', '', class_basename($factory));\n\n            $appNamespace = static::appNamespace();\n\n            return class_exists($appNamespace.'Models\\\\'.$namespacedFactoryBasename)\n                        ? $appNamespace.'Models\\\\'.$namespacedFactoryBasename\n                        : $appNamespace.$factoryBasename;\n        };\n\n        return $this->model ?: $resolver($this);\n    }\n\n    /**\n     * Specify the callback that should be invoked to guess model names based on factory names.\n     *\n     * @param  callable  $callback\n     * @return void\n     */\n    public static function guessModelNamesUsing(callable $callback)\n    {\n        static::$modelNameResolver = $callback;\n    }\n\n    /**\n     * Specify the default namespace that contains the application's model factories.\n     *\n     * @param  string  $namespace\n     * @return void\n     */\n    public static function useNamespace(string $namespace)\n    {\n        static::$namespace = $namespace;\n    }\n\n    /**\n     * Get a new factory instance for the given model name.\n     *\n     * @param  string  $modelName\n     * @return static\n     */\n    public static function factoryForModel(string $modelName)\n    {\n        $factory = static::resolveFactoryName($modelName);\n\n        return $factory::new();\n    }\n\n    /**\n     * Specify the callback that should be invoked to guess factory names based on dynamic relationship names.\n     *\n     * @param  callable  $callback\n     * @return void\n     */\n    public static function guessFactoryNamesUsing(callable $callback)\n    {\n        static::$factoryNameResolver = $callback;\n    }\n\n    /**\n     * Get a new Faker instance.\n     *\n     * @return \\Faker\\Generator\n     */\n    protected function withFaker()\n    {\n        return Container::getInstance()->make(Generator::class);\n    }\n\n    /**\n     * Get the factory name for the given model name.\n     *\n     * @param  string  $modelName\n     * @return string\n     */\n    public static function resolveFactoryName(string $modelName)\n    {\n        $resolver = static::$factoryNameResolver ?: function (string $modelName) {\n            $appNamespace = static::appNamespace();\n\n            $modelName = Str::startsWith($modelName, $appNamespace.'Models\\\\')\n                ? Str::after($modelName, $appNamespace.'Models\\\\')\n                : Str::after($modelName, $appNamespace);\n\n            return static::$namespace.$modelName.'Factory';\n        };\n\n        return $resolver($modelName);\n    }\n\n    /**\n     * Get the application namespace for the application.\n     *\n     * @return string\n     */\n    protected static function appNamespace()\n    {\n        try {\n            return Container::getInstance()\n                            ->make(Application::class)\n                            ->getNamespace();\n        } catch (Throwable $e) {\n            return 'App\\\\';\n        }\n    }\n\n    /**\n     * Proxy dynamic factory methods onto their proper methods.\n     *\n     * @param  string  $method\n     * @param  array  $parameters\n     * @return mixed\n     */\n    public function __call($method, $parameters)\n    {\n        if (static::hasMacro($method)) {\n            return $this->macroCall($method, $parameters);\n        }\n\n        if (! Str::startsWith($method, ['for', 'has'])) {\n            static::throwBadMethodCallException($method);\n        }\n\n        $relationship = Str::camel(Str::substr($method, 3));\n\n        $relatedModel = get_class($this->newModel()->{$relationship}()->getRelated());\n\n        if (method_exists($relatedModel, 'newFactory')) {\n            $factory = $relatedModel::newFactory() ?: static::factoryForModel($relatedModel);\n        } else {\n            $factory = static::factoryForModel($relatedModel);\n        }\n\n        if (Str::startsWith($method, 'for')) {\n            return $this->for($factory->state($parameters[0] ?? []), $relationship);\n        } elseif (Str::startsWith($method, 'has')) {\n            return $this->has(\n                $factory\n                    ->count(is_numeric($parameters[0] ?? null) ? $parameters[0] : 1)\n                    ->state((is_callable($parameters[0] ?? null) || is_array($parameters[0] ?? null)) ? $parameters[0] : ($parameters[1] ?? [])),\n                $relationship\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/Factories/HasFactory.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent\\Factories;\n\ntrait HasFactory\n{\n    /**\n     * Get a new factory instance for the model.\n     *\n     * @param  mixed  $parameters\n     * @return \\Illuminate\\Database\\Eloquent\\Factories\\Factory\n     */\n    public static function factory(...$parameters)\n    {\n        $factory = static::newFactory() ?: Factory::factoryForModel(get_called_class());\n\n        return $factory\n                    ->count(is_numeric($parameters[0] ?? null) ? $parameters[0] : null)\n                    ->state(is_array($parameters[0] ?? null) ? $parameters[0] : ($parameters[1] ?? []));\n    }\n\n    /**\n     * Create a new factory instance for the model.\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Factories\\Factory\n     */\n    protected static function newFactory()\n    {\n        //\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/Factories/Relationship.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent\\Factories;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Database\\Eloquent\\Relations\\BelongsToMany;\nuse Illuminate\\Database\\Eloquent\\Relations\\HasOneOrMany;\nuse Illuminate\\Database\\Eloquent\\Relations\\MorphOneOrMany;\n\nclass Relationship\n{\n    /**\n     * The related factory instance.\n     *\n     * @var \\Illuminate\\Database\\Eloquent\\Factories\\Factory\n     */\n    protected $factory;\n\n    /**\n     * The relationship name.\n     *\n     * @var string\n     */\n    protected $relationship;\n\n    /**\n     * Create a new child relationship instance.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Factories\\Factory  $factory\n     * @param  string  $relationship\n     * @return void\n     */\n    public function __construct(Factory $factory, $relationship)\n    {\n        $this->factory = $factory;\n        $this->relationship = $relationship;\n    }\n\n    /**\n     * Create the child relationship for the given parent model.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $parent\n     * @return void\n     */\n    public function createFor(Model $parent)\n    {\n        $relationship = $parent->{$this->relationship}();\n\n        if ($relationship instanceof MorphOneOrMany) {\n            $this->factory->state([\n                $relationship->getMorphType() => $relationship->getMorphClass(),\n                $relationship->getForeignKeyName() => $relationship->getParentKey(),\n            ])->create([], $parent);\n        } elseif ($relationship instanceof HasOneOrMany) {\n            $this->factory->state([\n                $relationship->getForeignKeyName() => $relationship->getParentKey(),\n            ])->create([], $parent);\n        } elseif ($relationship instanceof BelongsToMany) {\n            $relationship->attach($this->factory->create([], $parent));\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/Factories/Sequence.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent\\Factories;\n\nuse Countable;\n\nclass Sequence implements Countable\n{\n    /**\n     * The sequence of return values.\n     *\n     * @var array\n     */\n    protected $sequence;\n\n    /**\n     * The count of the sequence items.\n     *\n     * @var int\n     */\n    public $count;\n\n    /**\n     * The current index of the sequence iteration.\n     *\n     * @var int\n     */\n    public $index = 0;\n\n    /**\n     * Create a new sequence instance.\n     *\n     * @param  array  $sequence\n     * @return void\n     */\n    public function __construct(...$sequence)\n    {\n        $this->sequence = $sequence;\n        $this->count = count($sequence);\n    }\n\n    /**\n     * Get the current count of the sequence items.\n     *\n     * @return int\n     */\n    public function count(): int\n    {\n        return $this->count;\n    }\n\n    /**\n     * Get the next value in the sequence.\n     *\n     * @return mixed\n     */\n    public function __invoke()\n    {\n        return tap(value($this->sequence[$this->index % $this->count], $this), function () {\n            $this->index = $this->index + 1;\n        });\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/HigherOrderBuilderProxy.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent;\n\n/**\n * @mixin \\Illuminate\\Database\\Eloquent\\Builder\n */\nclass HigherOrderBuilderProxy\n{\n    /**\n     * The collection being operated on.\n     *\n     * @var \\Illuminate\\Database\\Eloquent\\Builder\n     */\n    protected $builder;\n\n    /**\n     * The method being proxied.\n     *\n     * @var string\n     */\n    protected $method;\n\n    /**\n     * Create a new proxy instance.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $builder\n     * @param  string  $method\n     * @return void\n     */\n    public function __construct(Builder $builder, $method)\n    {\n        $this->method = $method;\n        $this->builder = $builder;\n    }\n\n    /**\n     * Proxy a scope call onto the query builder.\n     *\n     * @param  string  $method\n     * @param  array  $parameters\n     * @return mixed\n     */\n    public function __call($method, $parameters)\n    {\n        return $this->builder->{$this->method}(function ($value) use ($method, $parameters) {\n            return $value->{$method}(...$parameters);\n        });\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/InvalidCastException.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent;\n\nuse RuntimeException;\n\nclass InvalidCastException extends RuntimeException\n{\n    /**\n     * The name of the affected Eloquent model.\n     *\n     * @var string\n     */\n    public $model;\n\n    /**\n     * The name of the column.\n     *\n     * @var string\n     */\n    public $column;\n\n    /**\n     * The name of the cast type.\n     *\n     * @var string\n     */\n    public $castType;\n\n    /**\n     * Create a new exception instance.\n     *\n     * @param  object  $model\n     * @param  string  $column\n     * @param  string  $castType\n     * @return static\n     */\n    public function __construct($model, $column, $castType)\n    {\n        $class = get_class($model);\n\n        parent::__construct(\"Call to undefined cast [{$castType}] on column [{$column}] in model [{$class}].\");\n\n        $this->model = $class;\n        $this->column = $column;\n        $this->castType = $castType;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/JsonEncodingException.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent;\n\nuse RuntimeException;\n\nclass JsonEncodingException extends RuntimeException\n{\n    /**\n     * Create a new JSON encoding exception for the model.\n     *\n     * @param  mixed  $model\n     * @param  string  $message\n     * @return static\n     */\n    public static function forModel($model, $message)\n    {\n        return new static('Error encoding model ['.get_class($model).'] with ID ['.$model->getKey().'] to JSON: '.$message);\n    }\n\n    /**\n     * Create a new JSON encoding exception for the resource.\n     *\n     * @param  \\Illuminate\\Http\\Resources\\Json\\JsonResource  $resource\n     * @param  string  $message\n     * @return static\n     */\n    public static function forResource($resource, $message)\n    {\n        $model = $resource->resource;\n\n        return new static('Error encoding resource ['.get_class($resource).'] with model ['.get_class($model).'] with ID ['.$model->getKey().'] to JSON: '.$message);\n    }\n\n    /**\n     * Create a new JSON encoding exception for an attribute.\n     *\n     * @param  mixed  $model\n     * @param  mixed  $key\n     * @param  string  $message\n     * @return static\n     */\n    public static function forAttribute($model, $key, $message)\n    {\n        $class = get_class($model);\n\n        return new static(\"Unable to encode attribute [{$key}] for model [{$class}] to JSON: {$message}.\");\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/MassAssignmentException.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent;\n\nuse RuntimeException;\n\nclass MassAssignmentException extends RuntimeException\n{\n    //\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/MassPrunable.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent;\n\nuse Illuminate\\Database\\Events\\ModelsPruned;\nuse LogicException;\n\ntrait MassPrunable\n{\n    /**\n     * Prune all prunable models in the database.\n     *\n     * @param  int  $chunkSize\n     * @return int\n     */\n    public function pruneAll(int $chunkSize = 1000)\n    {\n        $query = tap($this->prunable(), function ($query) use ($chunkSize) {\n            $query->when(! $query->getQuery()->limit, function ($query) use ($chunkSize) {\n                $query->limit($chunkSize);\n            });\n        });\n\n        $total = 0;\n\n        do {\n            $total += $count = in_array(SoftDeletes::class, class_uses_recursive(get_class($this)))\n                        ? $query->forceDelete()\n                        : $query->delete();\n\n            if ($count > 0) {\n                event(new ModelsPruned(static::class, $total));\n            }\n        } while ($count > 0);\n\n        return $total;\n    }\n\n    /**\n     * Get the prunable model query.\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Builder\n     */\n    public function prunable()\n    {\n        throw new LogicException('Please implement the prunable method on your model.');\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/Model.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent;\n\nuse ArrayAccess;\nuse Illuminate\\Contracts\\Broadcasting\\HasBroadcastChannel;\nuse Illuminate\\Contracts\\Queue\\QueueableCollection;\nuse Illuminate\\Contracts\\Queue\\QueueableEntity;\nuse Illuminate\\Contracts\\Routing\\UrlRoutable;\nuse Illuminate\\Contracts\\Support\\Arrayable;\nuse Illuminate\\Contracts\\Support\\CanBeEscapedWhenCastToString;\nuse Illuminate\\Contracts\\Support\\Jsonable;\nuse Illuminate\\Database\\ConnectionResolverInterface as Resolver;\nuse Illuminate\\Database\\Eloquent\\Collection as EloquentCollection;\nuse Illuminate\\Database\\Eloquent\\Relations\\BelongsToMany;\nuse Illuminate\\Database\\Eloquent\\Relations\\Concerns\\AsPivot;\nuse Illuminate\\Database\\Eloquent\\Relations\\HasManyThrough;\nuse Illuminate\\Database\\Eloquent\\Relations\\Pivot;\nuse Illuminate\\Support\\Arr;\nuse Illuminate\\Support\\Collection as BaseCollection;\nuse Illuminate\\Support\\Str;\nuse Illuminate\\Support\\Traits\\ForwardsCalls;\nuse JsonSerializable;\nuse LogicException;\n\nabstract class Model implements Arrayable, ArrayAccess, CanBeEscapedWhenCastToString, HasBroadcastChannel, Jsonable, JsonSerializable, QueueableEntity, UrlRoutable\n{\n    use Concerns\\HasAttributes,\n        Concerns\\HasEvents,\n        Concerns\\HasGlobalScopes,\n        Concerns\\HasRelationships,\n        Concerns\\HasTimestamps,\n        Concerns\\HidesAttributes,\n        Concerns\\GuardsAttributes,\n        ForwardsCalls;\n\n    /**\n     * The connection name for the model.\n     *\n     * @var string|null\n     */\n    protected $connection;\n\n    /**\n     * The table associated with the model.\n     *\n     * @var string\n     */\n    protected $table;\n\n    /**\n     * The primary key for the model.\n     *\n     * @var string\n     */\n    protected $primaryKey = 'id';\n\n    /**\n     * The \"type\" of the primary key ID.\n     *\n     * @var string\n     */\n    protected $keyType = 'int';\n\n    /**\n     * Indicates if the IDs are auto-incrementing.\n     *\n     * @var bool\n     */\n    public $incrementing = true;\n\n    /**\n     * The relations to eager load on every query.\n     *\n     * @var array\n     */\n    protected $with = [];\n\n    /**\n     * The relationship counts that should be eager loaded on every query.\n     *\n     * @var array\n     */\n    protected $withCount = [];\n\n    /**\n     * Indicates whether lazy loading will be prevented on this model.\n     *\n     * @var bool\n     */\n    public $preventsLazyLoading = false;\n\n    /**\n     * The number of models to return for pagination.\n     *\n     * @var int\n     */\n    protected $perPage = 15;\n\n    /**\n     * Indicates if the model exists.\n     *\n     * @var bool\n     */\n    public $exists = false;\n\n    /**\n     * Indicates if the model was inserted during the current request lifecycle.\n     *\n     * @var bool\n     */\n    public $wasRecentlyCreated = false;\n\n    /**\n     * Indicates that the object's string representation should be escaped when __toString is invoked.\n     *\n     * @var bool\n     */\n    protected $escapeWhenCastingToString = false;\n\n    /**\n     * The connection resolver instance.\n     *\n     * @var \\Illuminate\\Database\\ConnectionResolverInterface\n     */\n    protected static $resolver;\n\n    /**\n     * The event dispatcher instance.\n     *\n     * @var \\Illuminate\\Contracts\\Events\\Dispatcher\n     */\n    protected static $dispatcher;\n\n    /**\n     * The array of booted models.\n     *\n     * @var array\n     */\n    protected static $booted = [];\n\n    /**\n     * The array of trait initializers that will be called on each new instance.\n     *\n     * @var array\n     */\n    protected static $traitInitializers = [];\n\n    /**\n     * The array of global scopes on the model.\n     *\n     * @var array\n     */\n    protected static $globalScopes = [];\n\n    /**\n     * The list of models classes that should not be affected with touch.\n     *\n     * @var array\n     */\n    protected static $ignoreOnTouch = [];\n\n    /**\n     * Indicates whether lazy loading should be restricted on all models.\n     *\n     * @var bool\n     */\n    protected static $modelsShouldPreventLazyLoading = false;\n\n    /**\n     * The callback that is responsible for handling lazy loading violations.\n     *\n     * @var callable|null\n     */\n    protected static $lazyLoadingViolationCallback;\n\n    /**\n     * Indicates if broadcasting is currently enabled.\n     *\n     * @var bool\n     */\n    protected static $isBroadcasting = true;\n\n    /**\n     * The name of the \"created at\" column.\n     *\n     * @var string|null\n     */\n    const CREATED_AT = 'created_at';\n\n    /**\n     * The name of the \"updated at\" column.\n     *\n     * @var string|null\n     */\n    const UPDATED_AT = 'updated_at';\n\n    /**\n     * Create a new Eloquent model instance.\n     *\n     * @param  array  $attributes\n     * @return void\n     */\n    public function __construct(array $attributes = [])\n    {\n        $this->bootIfNotBooted();\n\n        $this->initializeTraits();\n\n        $this->syncOriginal();\n\n        $this->fill($attributes);\n    }\n\n    /**\n     * Check if the model needs to be booted and if so, do it.\n     *\n     * @return void\n     */\n    protected function bootIfNotBooted()\n    {\n        if (! isset(static::$booted[static::class])) {\n            static::$booted[static::class] = true;\n\n            $this->fireModelEvent('booting', false);\n\n            static::booting();\n            static::boot();\n            static::booted();\n\n            $this->fireModelEvent('booted', false);\n        }\n    }\n\n    /**\n     * Perform any actions required before the model boots.\n     *\n     * @return void\n     */\n    protected static function booting()\n    {\n        //\n    }\n\n    /**\n     * Bootstrap the model and its traits.\n     *\n     * @return void\n     */\n    protected static function boot()\n    {\n        static::bootTraits();\n    }\n\n    /**\n     * Boot all of the bootable traits on the model.\n     *\n     * @return void\n     */\n    protected static function bootTraits()\n    {\n        $class = static::class;\n\n        $booted = [];\n\n        static::$traitInitializers[$class] = [];\n\n        foreach (class_uses_recursive($class) as $trait) {\n            $method = 'boot'.class_basename($trait);\n\n            if (method_exists($class, $method) && ! in_array($method, $booted)) {\n                forward_static_call([$class, $method]);\n\n                $booted[] = $method;\n            }\n\n            if (method_exists($class, $method = 'initialize'.class_basename($trait))) {\n                static::$traitInitializers[$class][] = $method;\n\n                static::$traitInitializers[$class] = array_unique(\n                    static::$traitInitializers[$class]\n                );\n            }\n        }\n    }\n\n    /**\n     * Initialize any initializable traits on the model.\n     *\n     * @return void\n     */\n    protected function initializeTraits()\n    {\n        foreach (static::$traitInitializers[static::class] as $method) {\n            $this->{$method}();\n        }\n    }\n\n    /**\n     * Perform any actions required after the model boots.\n     *\n     * @return void\n     */\n    protected static function booted()\n    {\n        //\n    }\n\n    /**\n     * Clear the list of booted models so they will be re-booted.\n     *\n     * @return void\n     */\n    public static function clearBootedModels()\n    {\n        static::$booted = [];\n\n        static::$globalScopes = [];\n    }\n\n    /**\n     * Disables relationship model touching for the current class during given callback scope.\n     *\n     * @param  callable  $callback\n     * @return void\n     */\n    public static function withoutTouching(callable $callback)\n    {\n        static::withoutTouchingOn([static::class], $callback);\n    }\n\n    /**\n     * Disables relationship model touching for the given model classes during given callback scope.\n     *\n     * @param  array  $models\n     * @param  callable  $callback\n     * @return void\n     */\n    public static function withoutTouchingOn(array $models, callable $callback)\n    {\n        static::$ignoreOnTouch = array_values(array_merge(static::$ignoreOnTouch, $models));\n\n        try {\n            $callback();\n        } finally {\n            static::$ignoreOnTouch = array_values(array_diff(static::$ignoreOnTouch, $models));\n        }\n    }\n\n    /**\n     * Determine if the given model is ignoring touches.\n     *\n     * @param  string|null  $class\n     * @return bool\n     */\n    public static function isIgnoringTouch($class = null)\n    {\n        $class = $class ?: static::class;\n\n        if (! get_class_vars($class)['timestamps'] || ! $class::UPDATED_AT) {\n            return true;\n        }\n\n        foreach (static::$ignoreOnTouch as $ignoredClass) {\n            if ($class === $ignoredClass || is_subclass_of($class, $ignoredClass)) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * Prevent model relationships from being lazy loaded.\n     *\n     * @param  bool  $value\n     * @return void\n     */\n    public static function preventLazyLoading($value = true)\n    {\n        static::$modelsShouldPreventLazyLoading = $value;\n    }\n\n    /**\n     * Register a callback that is responsible for handling lazy loading violations.\n     *\n     * @param  callable|null  $callback\n     * @return void\n     */\n    public static function handleLazyLoadingViolationUsing(?callable $callback)\n    {\n        static::$lazyLoadingViolationCallback = $callback;\n    }\n\n    /**\n     * Execute a callback without broadcasting any model events for all model types.\n     *\n     * @param  callable  $callback\n     * @return mixed\n     */\n    public static function withoutBroadcasting(callable $callback)\n    {\n        $isBroadcasting = static::$isBroadcasting;\n\n        static::$isBroadcasting = false;\n\n        try {\n            return $callback();\n        } finally {\n            static::$isBroadcasting = $isBroadcasting;\n        }\n    }\n\n    /**\n     * Fill the model with an array of attributes.\n     *\n     * @param  array  $attributes\n     * @return $this\n     *\n     * @throws \\Illuminate\\Database\\Eloquent\\MassAssignmentException\n     */\n    public function fill(array $attributes)\n    {\n        $totallyGuarded = $this->totallyGuarded();\n\n        foreach ($this->fillableFromArray($attributes) as $key => $value) {\n            // The developers may choose to place some attributes in the \"fillable\" array\n            // which means only those attributes may be set through mass assignment to\n            // the model, and all others will just get ignored for security reasons.\n            if ($this->isFillable($key)) {\n                $this->setAttribute($key, $value);\n            } elseif ($totallyGuarded) {\n                throw new MassAssignmentException(sprintf(\n                    'Add [%s] to fillable property to allow mass assignment on [%s].',\n                    $key, get_class($this)\n                ));\n            }\n        }\n\n        return $this;\n    }\n\n    /**\n     * Fill the model with an array of attributes. Force mass assignment.\n     *\n     * @param  array  $attributes\n     * @return $this\n     */\n    public function forceFill(array $attributes)\n    {\n        return static::unguarded(function () use ($attributes) {\n            return $this->fill($attributes);\n        });\n    }\n\n    /**\n     * Qualify the given column name by the model's table.\n     *\n     * @param  string  $column\n     * @return string\n     */\n    public function qualifyColumn($column)\n    {\n        if (Str::contains($column, '.')) {\n            return $column;\n        }\n\n        return $this->getTable().'.'.$column;\n    }\n\n    /**\n     * Qualify the given columns with the model's table.\n     *\n     * @param  array  $columns\n     * @return array\n     */\n    public function qualifyColumns($columns)\n    {\n        return collect($columns)->map(function ($column) {\n            return $this->qualifyColumn($column);\n        })->all();\n    }\n\n    /**\n     * Create a new instance of the given model.\n     *\n     * @param  array  $attributes\n     * @param  bool  $exists\n     * @return static\n     */\n    public function newInstance($attributes = [], $exists = false)\n    {\n        // This method just provides a convenient way for us to generate fresh model\n        // instances of this current model. It is particularly useful during the\n        // hydration of new objects via the Eloquent query builder instances.\n        $model = new static((array) $attributes);\n\n        $model->exists = $exists;\n\n        $model->setConnection(\n            $this->getConnectionName()\n        );\n\n        $model->setTable($this->getTable());\n\n        $model->mergeCasts($this->casts);\n\n        return $model;\n    }\n\n    /**\n     * Create a new model instance that is existing.\n     *\n     * @param  array  $attributes\n     * @param  string|null  $connection\n     * @return static\n     */\n    public function newFromBuilder($attributes = [], $connection = null)\n    {\n        $model = $this->newInstance([], true);\n\n        $model->setRawAttributes((array) $attributes, true);\n\n        $model->setConnection($connection ?: $this->getConnectionName());\n\n        $model->fireModelEvent('retrieved', false);\n\n        return $model;\n    }\n\n    /**\n     * Begin querying the model on a given connection.\n     *\n     * @param  string|null  $connection\n     * @return \\Illuminate\\Database\\Eloquent\\Builder\n     */\n    public static function on($connection = null)\n    {\n        // First we will just create a fresh instance of this model, and then we can set the\n        // connection on the model so that it is used for the queries we execute, as well\n        // as being set on every relation we retrieve without a custom connection name.\n        $instance = new static;\n\n        $instance->setConnection($connection);\n\n        return $instance->newQuery();\n    }\n\n    /**\n     * Begin querying the model on the write connection.\n     *\n     * @return \\Illuminate\\Database\\Query\\Builder\n     */\n    public static function onWriteConnection()\n    {\n        return static::query()->useWritePdo();\n    }\n\n    /**\n     * Get all of the models from the database.\n     *\n     * @param  array|mixed  $columns\n     * @return \\Illuminate\\Database\\Eloquent\\Collection|static[]\n     */\n    public static function all($columns = ['*'])\n    {\n        return static::query()->get(\n            is_array($columns) ? $columns : func_get_args()\n        );\n    }\n\n    /**\n     * Begin querying a model with eager loading.\n     *\n     * @param  array|string  $relations\n     * @return \\Illuminate\\Database\\Eloquent\\Builder\n     */\n    public static function with($relations)\n    {\n        return static::query()->with(\n            is_string($relations) ? func_get_args() : $relations\n        );\n    }\n\n    /**\n     * Eager load relations on the model.\n     *\n     * @param  array|string  $relations\n     * @return $this\n     */\n    public function load($relations)\n    {\n        $query = $this->newQueryWithoutRelationships()->with(\n            is_string($relations) ? func_get_args() : $relations\n        );\n\n        $query->eagerLoadRelations([$this]);\n\n        return $this;\n    }\n\n    /**\n     * Eager load relationships on the polymorphic relation of a model.\n     *\n     * @param  string  $relation\n     * @param  array  $relations\n     * @return $this\n     */\n    public function loadMorph($relation, $relations)\n    {\n        if (! $this->{$relation}) {\n            return $this;\n        }\n\n        $className = get_class($this->{$relation});\n\n        $this->{$relation}->load($relations[$className] ?? []);\n\n        return $this;\n    }\n\n    /**\n     * Eager load relations on the model if they are not already eager loaded.\n     *\n     * @param  array|string  $relations\n     * @return $this\n     */\n    public function loadMissing($relations)\n    {\n        $relations = is_string($relations) ? func_get_args() : $relations;\n\n        $this->newCollection([$this])->loadMissing($relations);\n\n        return $this;\n    }\n\n    /**\n     * Eager load relation's column aggregations on the model.\n     *\n     * @param  array|string  $relations\n     * @param  string  $column\n     * @param  string  $function\n     * @return $this\n     */\n    public function loadAggregate($relations, $column, $function = null)\n    {\n        $this->newCollection([$this])->loadAggregate($relations, $column, $function);\n\n        return $this;\n    }\n\n    /**\n     * Eager load relation counts on the model.\n     *\n     * @param  array|string  $relations\n     * @return $this\n     */\n    public function loadCount($relations)\n    {\n        $relations = is_string($relations) ? func_get_args() : $relations;\n\n        return $this->loadAggregate($relations, '*', 'count');\n    }\n\n    /**\n     * Eager load relation max column values on the model.\n     *\n     * @param  array|string  $relations\n     * @param  string  $column\n     * @return $this\n     */\n    public function loadMax($relations, $column)\n    {\n        return $this->loadAggregate($relations, $column, 'max');\n    }\n\n    /**\n     * Eager load relation min column values on the model.\n     *\n     * @param  array|string  $relations\n     * @param  string  $column\n     * @return $this\n     */\n    public function loadMin($relations, $column)\n    {\n        return $this->loadAggregate($relations, $column, 'min');\n    }\n\n    /**\n     * Eager load relation's column summations on the model.\n     *\n     * @param  array|string  $relations\n     * @param  string  $column\n     * @return $this\n     */\n    public function loadSum($relations, $column)\n    {\n        return $this->loadAggregate($relations, $column, 'sum');\n    }\n\n    /**\n     * Eager load relation average column values on the model.\n     *\n     * @param  array|string  $relations\n     * @param  string  $column\n     * @return $this\n     */\n    public function loadAvg($relations, $column)\n    {\n        return $this->loadAggregate($relations, $column, 'avg');\n    }\n\n    /**\n     * Eager load related model existence values on the model.\n     *\n     * @param  array|string  $relations\n     * @return $this\n     */\n    public function loadExists($relations)\n    {\n        return $this->loadAggregate($relations, '*', 'exists');\n    }\n\n    /**\n     * Eager load relationship column aggregation on the polymorphic relation of a model.\n     *\n     * @param  string  $relation\n     * @param  array  $relations\n     * @param  string  $column\n     * @param  string  $function\n     * @return $this\n     */\n    public function loadMorphAggregate($relation, $relations, $column, $function = null)\n    {\n        if (! $this->{$relation}) {\n            return $this;\n        }\n\n        $className = get_class($this->{$relation});\n\n        $this->{$relation}->loadAggregate($relations[$className] ?? [], $column, $function);\n\n        return $this;\n    }\n\n    /**\n     * Eager load relationship counts on the polymorphic relation of a model.\n     *\n     * @param  string  $relation\n     * @param  array  $relations\n     * @return $this\n     */\n    public function loadMorphCount($relation, $relations)\n    {\n        return $this->loadMorphAggregate($relation, $relations, '*', 'count');\n    }\n\n    /**\n     * Eager load relationship max column values on the polymorphic relation of a model.\n     *\n     * @param  string  $relation\n     * @param  array  $relations\n     * @param  string  $column\n     * @return $this\n     */\n    public function loadMorphMax($relation, $relations, $column)\n    {\n        return $this->loadMorphAggregate($relation, $relations, $column, 'max');\n    }\n\n    /**\n     * Eager load relationship min column values on the polymorphic relation of a model.\n     *\n     * @param  string  $relation\n     * @param  array  $relations\n     * @param  string  $column\n     * @return $this\n     */\n    public function loadMorphMin($relation, $relations, $column)\n    {\n        return $this->loadMorphAggregate($relation, $relations, $column, 'min');\n    }\n\n    /**\n     * Eager load relationship column summations on the polymorphic relation of a model.\n     *\n     * @param  string  $relation\n     * @param  array  $relations\n     * @param  string  $column\n     * @return $this\n     */\n    public function loadMorphSum($relation, $relations, $column)\n    {\n        return $this->loadMorphAggregate($relation, $relations, $column, 'sum');\n    }\n\n    /**\n     * Eager load relationship average column values on the polymorphic relation of a model.\n     *\n     * @param  string  $relation\n     * @param  array  $relations\n     * @param  string  $column\n     * @return $this\n     */\n    public function loadMorphAvg($relation, $relations, $column)\n    {\n        return $this->loadMorphAggregate($relation, $relations, $column, 'avg');\n    }\n\n    /**\n     * Increment a column's value by a given amount.\n     *\n     * @param  string  $column\n     * @param  float|int  $amount\n     * @param  array  $extra\n     * @return int\n     */\n    protected function increment($column, $amount = 1, array $extra = [])\n    {\n        return $this->incrementOrDecrement($column, $amount, $extra, 'increment');\n    }\n\n    /**\n     * Decrement a column's value by a given amount.\n     *\n     * @param  string  $column\n     * @param  float|int  $amount\n     * @param  array  $extra\n     * @return int\n     */\n    protected function decrement($column, $amount = 1, array $extra = [])\n    {\n        return $this->incrementOrDecrement($column, $amount, $extra, 'decrement');\n    }\n\n    /**\n     * Run the increment or decrement method on the model.\n     *\n     * @param  string  $column\n     * @param  float|int  $amount\n     * @param  array  $extra\n     * @param  string  $method\n     * @return int\n     */\n    protected function incrementOrDecrement($column, $amount, $extra, $method)\n    {\n        $query = $this->newQueryWithoutRelationships();\n\n        if (! $this->exists) {\n            return $query->{$method}($column, $amount, $extra);\n        }\n\n        $this->{$column} = $this->isClassDeviable($column)\n            ? $this->deviateClassCastableAttribute($method, $column, $amount)\n            : $this->{$column} + ($method === 'increment' ? $amount : $amount * -1);\n\n        $this->forceFill($extra);\n\n        if ($this->fireModelEvent('updating') === false) {\n            return false;\n        }\n\n        return tap($this->setKeysForSaveQuery($query)->{$method}($column, $amount, $extra), function () use ($column) {\n            $this->syncChanges();\n\n            $this->fireModelEvent('updated', false);\n\n            $this->syncOriginalAttribute($column);\n        });\n    }\n\n    /**\n     * Update the model in the database.\n     *\n     * @param  array  $attributes\n     * @param  array  $options\n     * @return bool\n     */\n    public function update(array $attributes = [], array $options = [])\n    {\n        if (! $this->exists) {\n            return false;\n        }\n\n        return $this->fill($attributes)->save($options);\n    }\n\n    /**\n     * Update the model in the database within a transaction.\n     *\n     * @param  array  $attributes\n     * @param  array  $options\n     * @return bool\n     *\n     * @throws \\Throwable\n     */\n    public function updateOrFail(array $attributes = [], array $options = [])\n    {\n        if (! $this->exists) {\n            return false;\n        }\n\n        return $this->fill($attributes)->saveOrFail($options);\n    }\n\n    /**\n     * Update the model in the database without raising any events.\n     *\n     * @param  array  $attributes\n     * @param  array  $options\n     * @return bool\n     */\n    public function updateQuietly(array $attributes = [], array $options = [])\n    {\n        if (! $this->exists) {\n            return false;\n        }\n\n        return $this->fill($attributes)->saveQuietly($options);\n    }\n\n    /**\n     * Save the model and all of its relationships.\n     *\n     * @return bool\n     */\n    public function push()\n    {\n        if (! $this->save()) {\n            return false;\n        }\n\n        // To sync all of the relationships to the database, we will simply spin through\n        // the relationships and save each model via this \"push\" method, which allows\n        // us to recurse into all of these nested relations for the model instance.\n        foreach ($this->relations as $models) {\n            $models = $models instanceof Collection\n                        ? $models->all() : [$models];\n\n            foreach (array_filter($models) as $model) {\n                if (! $model->push()) {\n                    return false;\n                }\n            }\n        }\n\n        return true;\n    }\n\n    /**\n     * Save the model to the database without raising any events.\n     *\n     * @param  array  $options\n     * @return bool\n     */\n    public function saveQuietly(array $options = [])\n    {\n        return static::withoutEvents(function () use ($options) {\n            return $this->save($options);\n        });\n    }\n\n    /**\n     * Save the model to the database.\n     *\n     * @param  array  $options\n     * @return bool\n     */\n    public function save(array $options = [])\n    {\n        $this->mergeAttributesFromCachedCasts();\n\n        $query = $this->newModelQuery();\n\n        // If the \"saving\" event returns false we'll bail out of the save and return\n        // false, indicating that the save failed. This provides a chance for any\n        // listeners to cancel save operations if validations fail or whatever.\n        if ($this->fireModelEvent('saving') === false) {\n            return false;\n        }\n\n        // If the model already exists in the database we can just update our record\n        // that is already in this database using the current IDs in this \"where\"\n        // clause to only update this model. Otherwise, we'll just insert them.\n        if ($this->exists) {\n            $saved = $this->isDirty() ?\n                        $this->performUpdate($query) : true;\n        }\n\n        // If the model is brand new, we'll insert it into our database and set the\n        // ID attribute on the model to the value of the newly inserted row's ID\n        // which is typically an auto-increment value managed by the database.\n        else {\n            $saved = $this->performInsert($query);\n\n            if (! $this->getConnectionName() &&\n                $connection = $query->getConnection()) {\n                $this->setConnection($connection->getName());\n            }\n        }\n\n        // If the model is successfully saved, we need to do a few more things once\n        // that is done. We will call the \"saved\" method here to run any actions\n        // we need to happen after a model gets successfully saved right here.\n        if ($saved) {\n            $this->finishSave($options);\n        }\n\n        return $saved;\n    }\n\n    /**\n     * Save the model to the database within a transaction.\n     *\n     * @param  array  $options\n     * @return bool\n     *\n     * @throws \\Throwable\n     */\n    public function saveOrFail(array $options = [])\n    {\n        return $this->getConnection()->transaction(function () use ($options) {\n            return $this->save($options);\n        });\n    }\n\n    /**\n     * Perform any actions that are necessary after the model is saved.\n     *\n     * @param  array  $options\n     * @return void\n     */\n    protected function finishSave(array $options)\n    {\n        $this->fireModelEvent('saved', false);\n\n        if ($this->isDirty() && ($options['touch'] ?? true)) {\n            $this->touchOwners();\n        }\n\n        $this->syncOriginal();\n    }\n\n    /**\n     * Perform a model update operation.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $query\n     * @return bool\n     */\n    protected function performUpdate(Builder $query)\n    {\n        // If the updating event returns false, we will cancel the update operation so\n        // developers can hook Validation systems into their models and cancel this\n        // operation if the model does not pass validation. Otherwise, we update.\n        if ($this->fireModelEvent('updating') === false) {\n            return false;\n        }\n\n        // First we need to create a fresh query instance and touch the creation and\n        // update timestamp on the model which are maintained by us for developer\n        // convenience. Then we will just continue saving the model instances.\n        if ($this->usesTimestamps()) {\n            $this->updateTimestamps();\n        }\n\n        // Once we have run the update operation, we will fire the \"updated\" event for\n        // this model instance. This will allow developers to hook into these after\n        // models are updated, giving them a chance to do any special processing.\n        $dirty = $this->getDirty();\n\n        if (count($dirty) > 0) {\n            $this->setKeysForSaveQuery($query)->update($dirty);\n\n            $this->syncChanges();\n\n            $this->fireModelEvent('updated', false);\n        }\n\n        return true;\n    }\n\n    /**\n     * Set the keys for a select query.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $query\n     * @return \\Illuminate\\Database\\Eloquent\\Builder\n     */\n    protected function setKeysForSelectQuery($query)\n    {\n        $query->where($this->getKeyName(), '=', $this->getKeyForSelectQuery());\n\n        return $query;\n    }\n\n    /**\n     * Get the primary key value for a select query.\n     *\n     * @return mixed\n     */\n    protected function getKeyForSelectQuery()\n    {\n        return $this->original[$this->getKeyName()] ?? $this->getKey();\n    }\n\n    /**\n     * Set the keys for a save update query.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $query\n     * @return \\Illuminate\\Database\\Eloquent\\Builder\n     */\n    protected function setKeysForSaveQuery($query)\n    {\n        $query->where($this->getKeyName(), '=', $this->getKeyForSaveQuery());\n\n        return $query;\n    }\n\n    /**\n     * Get the primary key value for a save query.\n     *\n     * @return mixed\n     */\n    protected function getKeyForSaveQuery()\n    {\n        return $this->original[$this->getKeyName()] ?? $this->getKey();\n    }\n\n    /**\n     * Perform a model insert operation.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $query\n     * @return bool\n     */\n    protected function performInsert(Builder $query)\n    {\n        if ($this->fireModelEvent('creating') === false) {\n            return false;\n        }\n\n        // First we'll need to create a fresh query instance and touch the creation and\n        // update timestamps on this model, which are maintained by us for developer\n        // convenience. After, we will just continue saving these model instances.\n        if ($this->usesTimestamps()) {\n            $this->updateTimestamps();\n        }\n\n        // If the model has an incrementing key, we can use the \"insertGetId\" method on\n        // the query builder, which will give us back the final inserted ID for this\n        // table from the database. Not all tables have to be incrementing though.\n        $attributes = $this->getAttributesForInsert();\n\n        if ($this->getIncrementing()) {\n            $this->insertAndSetId($query, $attributes);\n        }\n\n        // If the table isn't incrementing we'll simply insert these attributes as they\n        // are. These attribute arrays must contain an \"id\" column previously placed\n        // there by the developer as the manually determined key for these models.\n        else {\n            if (empty($attributes)) {\n                return true;\n            }\n\n            $query->insert($attributes);\n        }\n\n        // We will go ahead and set the exists property to true, so that it is set when\n        // the created event is fired, just in case the developer tries to update it\n        // during the event. This will allow them to do so and run an update here.\n        $this->exists = true;\n\n        $this->wasRecentlyCreated = true;\n\n        $this->fireModelEvent('created', false);\n\n        return true;\n    }\n\n    /**\n     * Insert the given attributes and set the ID on the model.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $query\n     * @param  array  $attributes\n     * @return void\n     */\n    protected function insertAndSetId(Builder $query, $attributes)\n    {\n        $id = $query->insertGetId($attributes, $keyName = $this->getKeyName());\n\n        $this->setAttribute($keyName, $id);\n    }\n\n    /**\n     * Destroy the models for the given IDs.\n     *\n     * @param  \\Illuminate\\Support\\Collection|array|int|string  $ids\n     * @return int\n     */\n    public static function destroy($ids)\n    {\n        if ($ids instanceof EloquentCollection) {\n            $ids = $ids->modelKeys();\n        }\n\n        if ($ids instanceof BaseCollection) {\n            $ids = $ids->all();\n        }\n\n        $ids = is_array($ids) ? $ids : func_get_args();\n\n        if (count($ids) === 0) {\n            return 0;\n        }\n\n        // We will actually pull the models from the database table and call delete on\n        // each of them individually so that their events get fired properly with a\n        // correct set of attributes in case the developers wants to check these.\n        $key = ($instance = new static)->getKeyName();\n\n        $count = 0;\n\n        foreach ($instance->whereIn($key, $ids)->get() as $model) {\n            if ($model->delete()) {\n                $count++;\n            }\n        }\n\n        return $count;\n    }\n\n    /**\n     * Delete the model from the database.\n     *\n     * @return bool|null\n     *\n     * @throws \\LogicException\n     */\n    public function delete()\n    {\n        $this->mergeAttributesFromCachedCasts();\n\n        if (is_null($this->getKeyName())) {\n            throw new LogicException('No primary key defined on model.');\n        }\n\n        // If the model doesn't exist, there is nothing to delete so we'll just return\n        // immediately and not do anything else. Otherwise, we will continue with a\n        // deletion process on the model, firing the proper events, and so forth.\n        if (! $this->exists) {\n            return;\n        }\n\n        if ($this->fireModelEvent('deleting') === false) {\n            return false;\n        }\n\n        // Here, we'll touch the owning models, verifying these timestamps get updated\n        // for the models. This will allow any caching to get broken on the parents\n        // by the timestamp. Then we will go ahead and delete the model instance.\n        $this->touchOwners();\n\n        $this->performDeleteOnModel();\n\n        // Once the model has been deleted, we will fire off the deleted event so that\n        // the developers may hook into post-delete operations. We will then return\n        // a boolean true as the delete is presumably successful on the database.\n        $this->fireModelEvent('deleted', false);\n\n        return true;\n    }\n\n    /**\n     * Delete the model from the database within a transaction.\n     *\n     * @return bool|null\n     *\n     * @throws \\Throwable\n     */\n    public function deleteOrFail()\n    {\n        if (! $this->exists) {\n            return false;\n        }\n\n        return $this->getConnection()->transaction(function () {\n            return $this->delete();\n        });\n    }\n\n    /**\n     * Force a hard delete on a soft deleted model.\n     *\n     * This method protects developers from running forceDelete when the trait is missing.\n     *\n     * @return bool|null\n     */\n    public function forceDelete()\n    {\n        return $this->delete();\n    }\n\n    /**\n     * Perform the actual delete query on this model instance.\n     *\n     * @return void\n     */\n    protected function performDeleteOnModel()\n    {\n        $this->setKeysForSaveQuery($this->newModelQuery())->delete();\n\n        $this->exists = false;\n    }\n\n    /**\n     * Begin querying the model.\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Builder\n     */\n    public static function query()\n    {\n        return (new static)->newQuery();\n    }\n\n    /**\n     * Get a new query builder for the model's table.\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Builder\n     */\n    public function newQuery()\n    {\n        return $this->registerGlobalScopes($this->newQueryWithoutScopes());\n    }\n\n    /**\n     * Get a new query builder that doesn't have any global scopes or eager loading.\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Builder|static\n     */\n    public function newModelQuery()\n    {\n        return $this->newEloquentBuilder(\n            $this->newBaseQueryBuilder()\n        )->setModel($this);\n    }\n\n    /**\n     * Get a new query builder with no relationships loaded.\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Builder\n     */\n    public function newQueryWithoutRelationships()\n    {\n        return $this->registerGlobalScopes($this->newModelQuery());\n    }\n\n    /**\n     * Register the global scopes for this builder instance.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $builder\n     * @return \\Illuminate\\Database\\Eloquent\\Builder\n     */\n    public function registerGlobalScopes($builder)\n    {\n        foreach ($this->getGlobalScopes() as $identifier => $scope) {\n            $builder->withGlobalScope($identifier, $scope);\n        }\n\n        return $builder;\n    }\n\n    /**\n     * Get a new query builder that doesn't have any global scopes.\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Builder|static\n     */\n    public function newQueryWithoutScopes()\n    {\n        return $this->newModelQuery()\n                    ->with($this->with)\n                    ->withCount($this->withCount);\n    }\n\n    /**\n     * Get a new query instance without a given scope.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Scope|string  $scope\n     * @return \\Illuminate\\Database\\Eloquent\\Builder\n     */\n    public function newQueryWithoutScope($scope)\n    {\n        return $this->newQuery()->withoutGlobalScope($scope);\n    }\n\n    /**\n     * Get a new query to restore one or more models by their queueable IDs.\n     *\n     * @param  array|int  $ids\n     * @return \\Illuminate\\Database\\Eloquent\\Builder\n     */\n    public function newQueryForRestoration($ids)\n    {\n        return is_array($ids)\n                ? $this->newQueryWithoutScopes()->whereIn($this->getQualifiedKeyName(), $ids)\n                : $this->newQueryWithoutScopes()->whereKey($ids);\n    }\n\n    /**\n     * Create a new Eloquent query builder for the model.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @return \\Illuminate\\Database\\Eloquent\\Builder|static\n     */\n    public function newEloquentBuilder($query)\n    {\n        return new Builder($query);\n    }\n\n    /**\n     * Get a new query builder instance for the connection.\n     *\n     * @return \\Illuminate\\Database\\Query\\Builder\n     */\n    protected function newBaseQueryBuilder()\n    {\n        return $this->getConnection()->query();\n    }\n\n    /**\n     * Create a new Eloquent Collection instance.\n     *\n     * @param  array  $models\n     * @return \\Illuminate\\Database\\Eloquent\\Collection\n     */\n    public function newCollection(array $models = [])\n    {\n        return new Collection($models);\n    }\n\n    /**\n     * Create a new pivot model instance.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $parent\n     * @param  array  $attributes\n     * @param  string  $table\n     * @param  bool  $exists\n     * @param  string|null  $using\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\Pivot\n     */\n    public function newPivot(self $parent, array $attributes, $table, $exists, $using = null)\n    {\n        return $using ? $using::fromRawAttributes($parent, $attributes, $table, $exists)\n                      : Pivot::fromAttributes($parent, $attributes, $table, $exists);\n    }\n\n    /**\n     * Determine if the model has a given scope.\n     *\n     * @param  string  $scope\n     * @return bool\n     */\n    public function hasNamedScope($scope)\n    {\n        return method_exists($this, 'scope'.ucfirst($scope));\n    }\n\n    /**\n     * Apply the given named scope if possible.\n     *\n     * @param  string  $scope\n     * @param  array  $parameters\n     * @return mixed\n     */\n    public function callNamedScope($scope, array $parameters = [])\n    {\n        return $this->{'scope'.ucfirst($scope)}(...$parameters);\n    }\n\n    /**\n     * Convert the model instance to an array.\n     *\n     * @return array\n     */\n    public function toArray()\n    {\n        return array_merge($this->attributesToArray(), $this->relationsToArray());\n    }\n\n    /**\n     * Convert the model instance to JSON.\n     *\n     * @param  int  $options\n     * @return string\n     *\n     * @throws \\Illuminate\\Database\\Eloquent\\JsonEncodingException\n     */\n    public function toJson($options = 0)\n    {\n        $json = json_encode($this->jsonSerialize(), $options);\n\n        if (JSON_ERROR_NONE !== json_last_error()) {\n            throw JsonEncodingException::forModel($this, json_last_error_msg());\n        }\n\n        return $json;\n    }\n\n    /**\n     * Convert the object into something JSON serializable.\n     *\n     * @return array\n     */\n    #[\\ReturnTypeWillChange]\n    public function jsonSerialize()\n    {\n        return $this->toArray();\n    }\n\n    /**\n     * Reload a fresh model instance from the database.\n     *\n     * @param  array|string  $with\n     * @return static|null\n     */\n    public function fresh($with = [])\n    {\n        if (! $this->exists) {\n            return;\n        }\n\n        return $this->setKeysForSelectQuery($this->newQueryWithoutScopes())\n                        ->with(is_string($with) ? func_get_args() : $with)\n                        ->first();\n    }\n\n    /**\n     * Reload the current model instance with fresh attributes from the database.\n     *\n     * @return $this\n     */\n    public function refresh()\n    {\n        if (! $this->exists) {\n            return $this;\n        }\n\n        $this->setRawAttributes(\n            $this->setKeysForSelectQuery($this->newQueryWithoutScopes())->firstOrFail()->attributes\n        );\n\n        $this->load(collect($this->relations)->reject(function ($relation) {\n            return $relation instanceof Pivot\n                || (is_object($relation) && in_array(AsPivot::class, class_uses_recursive($relation), true));\n        })->keys()->all());\n\n        $this->syncOriginal();\n\n        return $this;\n    }\n\n    /**\n     * Clone the model into a new, non-existing instance.\n     *\n     * @param  array|null  $except\n     * @return static\n     */\n    public function replicate(array $except = null)\n    {\n        $defaults = [\n            $this->getKeyName(),\n            $this->getCreatedAtColumn(),\n            $this->getUpdatedAtColumn(),\n        ];\n\n        $attributes = Arr::except(\n            $this->getAttributes(), $except ? array_unique(array_merge($except, $defaults)) : $defaults\n        );\n\n        return tap(new static, function ($instance) use ($attributes) {\n            $instance->setRawAttributes($attributes);\n\n            $instance->setRelations($this->relations);\n\n            $instance->fireModelEvent('replicating', false);\n        });\n    }\n\n    /**\n     * Determine if two models have the same ID and belong to the same table.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Model|null  $model\n     * @return bool\n     */\n    public function is($model)\n    {\n        return ! is_null($model) &&\n               $this->getKey() === $model->getKey() &&\n               $this->getTable() === $model->getTable() &&\n               $this->getConnectionName() === $model->getConnectionName();\n    }\n\n    /**\n     * Determine if two models are not the same.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Model|null  $model\n     * @return bool\n     */\n    public function isNot($model)\n    {\n        return ! $this->is($model);\n    }\n\n    /**\n     * Get the database connection for the model.\n     *\n     * @return \\Illuminate\\Database\\Connection\n     */\n    public function getConnection()\n    {\n        return static::resolveConnection($this->getConnectionName());\n    }\n\n    /**\n     * Get the current connection name for the model.\n     *\n     * @return string|null\n     */\n    public function getConnectionName()\n    {\n        return $this->connection;\n    }\n\n    /**\n     * Set the connection associated with the model.\n     *\n     * @param  string|null  $name\n     * @return $this\n     */\n    public function setConnection($name)\n    {\n        $this->connection = $name;\n\n        return $this;\n    }\n\n    /**\n     * Resolve a connection instance.\n     *\n     * @param  string|null  $connection\n     * @return \\Illuminate\\Database\\Connection\n     */\n    public static function resolveConnection($connection = null)\n    {\n        return static::$resolver->connection($connection);\n    }\n\n    /**\n     * Get the connection resolver instance.\n     *\n     * @return \\Illuminate\\Database\\ConnectionResolverInterface\n     */\n    public static function getConnectionResolver()\n    {\n        return static::$resolver;\n    }\n\n    /**\n     * Set the connection resolver instance.\n     *\n     * @param  \\Illuminate\\Database\\ConnectionResolverInterface  $resolver\n     * @return void\n     */\n    public static function setConnectionResolver(Resolver $resolver)\n    {\n        static::$resolver = $resolver;\n    }\n\n    /**\n     * Unset the connection resolver for models.\n     *\n     * @return void\n     */\n    public static function unsetConnectionResolver()\n    {\n        static::$resolver = null;\n    }\n\n    /**\n     * Get the table associated with the model.\n     *\n     * @return string\n     */\n    public function getTable()\n    {\n        return $this->table ?? Str::snake(Str::pluralStudly(class_basename($this)));\n    }\n\n    /**\n     * Set the table associated with the model.\n     *\n     * @param  string  $table\n     * @return $this\n     */\n    public function setTable($table)\n    {\n        $this->table = $table;\n\n        return $this;\n    }\n\n    /**\n     * Get the primary key for the model.\n     *\n     * @return string\n     */\n    public function getKeyName()\n    {\n        return $this->primaryKey;\n    }\n\n    /**\n     * Set the primary key for the model.\n     *\n     * @param  string  $key\n     * @return $this\n     */\n    public function setKeyName($key)\n    {\n        $this->primaryKey = $key;\n\n        return $this;\n    }\n\n    /**\n     * Get the table qualified key name.\n     *\n     * @return string\n     */\n    public function getQualifiedKeyName()\n    {\n        return $this->qualifyColumn($this->getKeyName());\n    }\n\n    /**\n     * Get the auto-incrementing key type.\n     *\n     * @return string\n     */\n    public function getKeyType()\n    {\n        return $this->keyType;\n    }\n\n    /**\n     * Set the data type for the primary key.\n     *\n     * @param  string  $type\n     * @return $this\n     */\n    public function setKeyType($type)\n    {\n        $this->keyType = $type;\n\n        return $this;\n    }\n\n    /**\n     * Get the value indicating whether the IDs are incrementing.\n     *\n     * @return bool\n     */\n    public function getIncrementing()\n    {\n        return $this->incrementing;\n    }\n\n    /**\n     * Set whether IDs are incrementing.\n     *\n     * @param  bool  $value\n     * @return $this\n     */\n    public function setIncrementing($value)\n    {\n        $this->incrementing = $value;\n\n        return $this;\n    }\n\n    /**\n     * Get the value of the model's primary key.\n     *\n     * @return mixed\n     */\n    public function getKey()\n    {\n        return $this->getAttribute($this->getKeyName());\n    }\n\n    /**\n     * Get the queueable identity for the entity.\n     *\n     * @return mixed\n     */\n    public function getQueueableId()\n    {\n        return $this->getKey();\n    }\n\n    /**\n     * Get the queueable relationships for the entity.\n     *\n     * @return array\n     */\n    public function getQueueableRelations()\n    {\n        $relations = [];\n\n        foreach ($this->getRelations() as $key => $relation) {\n            if (! method_exists($this, $key)) {\n                continue;\n            }\n\n            $relations[] = $key;\n\n            if ($relation instanceof QueueableCollection) {\n                foreach ($relation->getQueueableRelations() as $collectionValue) {\n                    $relations[] = $key.'.'.$collectionValue;\n                }\n            }\n\n            if ($relation instanceof QueueableEntity) {\n                foreach ($relation->getQueueableRelations() as $entityKey => $entityValue) {\n                    $relations[] = $key.'.'.$entityValue;\n                }\n            }\n        }\n\n        return array_unique($relations);\n    }\n\n    /**\n     * Get the queueable connection for the entity.\n     *\n     * @return string|null\n     */\n    public function getQueueableConnection()\n    {\n        return $this->getConnectionName();\n    }\n\n    /**\n     * Get the value of the model's route key.\n     *\n     * @return mixed\n     */\n    public function getRouteKey()\n    {\n        return $this->getAttribute($this->getRouteKeyName());\n    }\n\n    /**\n     * Get the route key for the model.\n     *\n     * @return string\n     */\n    public function getRouteKeyName()\n    {\n        return $this->getKeyName();\n    }\n\n    /**\n     * Retrieve the model for a bound value.\n     *\n     * @param  mixed  $value\n     * @param  string|null  $field\n     * @return \\Illuminate\\Database\\Eloquent\\Model|null\n     */\n    public function resolveRouteBinding($value, $field = null)\n    {\n        return $this->resolveRouteBindingQuery($this, $value, $field)->first();\n    }\n\n    /**\n     * Retrieve the model for a bound value.\n     *\n     * @param  mixed  $value\n     * @param  string|null  $field\n     * @return \\Illuminate\\Database\\Eloquent\\Model|null\n     */\n    public function resolveSoftDeletableRouteBinding($value, $field = null)\n    {\n        return $this->resolveRouteBindingQuery($this, $value, $field)->withTrashed()->first();\n    }\n\n    /**\n     * Retrieve the child model for a bound value.\n     *\n     * @param  string  $childType\n     * @param  mixed  $value\n     * @param  string|null  $field\n     * @return \\Illuminate\\Database\\Eloquent\\Model|null\n     */\n    public function resolveChildRouteBinding($childType, $value, $field)\n    {\n        return $this->resolveChildRouteBindingQuery($childType, $value, $field)->first();\n    }\n\n    /**\n     * Retrieve the child model for a bound value.\n     *\n     * @param  string  $childType\n     * @param  mixed  $value\n     * @param  string|null  $field\n     * @return \\Illuminate\\Database\\Eloquent\\Model|null\n     */\n    public function resolveSoftDeletableChildRouteBinding($childType, $value, $field)\n    {\n        return $this->resolveChildRouteBindingQuery($childType, $value, $field)->withTrashed()->first();\n    }\n\n    /**\n     * Retrieve the child model query for a bound value.\n     *\n     * @param  string  $childType\n     * @param  mixed  $value\n     * @param  string|null  $field\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\Relation\n     */\n    protected function resolveChildRouteBindingQuery($childType, $value, $field)\n    {\n        $relationship = $this->{Str::plural(Str::camel($childType))}();\n\n        $field = $field ?: $relationship->getRelated()->getRouteKeyName();\n\n        if ($relationship instanceof HasManyThrough ||\n            $relationship instanceof BelongsToMany) {\n            $field = $relationship->getRelated()->getTable().'.'.$field;\n        }\n\n        return $relationship instanceof Model\n                ? $relationship->resolveRouteBindingQuery($relationship, $value, $field)\n                : $relationship->getRelated()->resolveRouteBindingQuery($relationship, $value, $field);\n    }\n\n    /**\n     * Retrieve the model for a bound value.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Model|Illuminate\\Database\\Eloquent\\Relations\\Relation  $query\n     * @param  mixed  $value\n     * @param  string|null  $field\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\Relation\n     */\n    public function resolveRouteBindingQuery($query, $value, $field = null)\n    {\n        return $query->where($field ?? $this->getRouteKeyName(), $value);\n    }\n\n    /**\n     * Get the default foreign key name for the model.\n     *\n     * @return string\n     */\n    public function getForeignKey()\n    {\n        return Str::snake(class_basename($this)).'_'.$this->getKeyName();\n    }\n\n    /**\n     * Get the number of models to return per page.\n     *\n     * @return int\n     */\n    public function getPerPage()\n    {\n        return $this->perPage;\n    }\n\n    /**\n     * Set the number of models to return per page.\n     *\n     * @param  int  $perPage\n     * @return $this\n     */\n    public function setPerPage($perPage)\n    {\n        $this->perPage = $perPage;\n\n        return $this;\n    }\n\n    /**\n     * Determine if lazy loading is disabled.\n     *\n     * @return bool\n     */\n    public static function preventsLazyLoading()\n    {\n        return static::$modelsShouldPreventLazyLoading;\n    }\n\n    /**\n     * Get the broadcast channel route definition that is associated with the given entity.\n     *\n     * @return string\n     */\n    public function broadcastChannelRoute()\n    {\n        return str_replace('\\\\', '.', get_class($this)).'.{'.Str::camel(class_basename($this)).'}';\n    }\n\n    /**\n     * Get the broadcast channel name that is associated with the given entity.\n     *\n     * @return string\n     */\n    public function broadcastChannel()\n    {\n        return str_replace('\\\\', '.', get_class($this)).'.'.$this->getKey();\n    }\n\n    /**\n     * Dynamically retrieve attributes on the model.\n     *\n     * @param  string  $key\n     * @return mixed\n     */\n    public function __get($key)\n    {\n        return $this->getAttribute($key);\n    }\n\n    /**\n     * Dynamically set attributes on the model.\n     *\n     * @param  string  $key\n     * @param  mixed  $value\n     * @return void\n     */\n    public function __set($key, $value)\n    {\n        $this->setAttribute($key, $value);\n    }\n\n    /**\n     * Determine if the given attribute exists.\n     *\n     * @param  mixed  $offset\n     * @return bool\n     */\n    #[\\ReturnTypeWillChange]\n    public function offsetExists($offset)\n    {\n        return ! is_null($this->getAttribute($offset));\n    }\n\n    /**\n     * Get the value for a given offset.\n     *\n     * @param  mixed  $offset\n     * @return mixed\n     */\n    #[\\ReturnTypeWillChange]\n    public function offsetGet($offset)\n    {\n        return $this->getAttribute($offset);\n    }\n\n    /**\n     * Set the value for a given offset.\n     *\n     * @param  mixed  $offset\n     * @param  mixed  $value\n     * @return void\n     */\n    #[\\ReturnTypeWillChange]\n    public function offsetSet($offset, $value)\n    {\n        $this->setAttribute($offset, $value);\n    }\n\n    /**\n     * Unset the value for a given offset.\n     *\n     * @param  mixed  $offset\n     * @return void\n     */\n    #[\\ReturnTypeWillChange]\n    public function offsetUnset($offset)\n    {\n        unset($this->attributes[$offset], $this->relations[$offset]);\n    }\n\n    /**\n     * Determine if an attribute or relation exists on the model.\n     *\n     * @param  string  $key\n     * @return bool\n     */\n    public function __isset($key)\n    {\n        return $this->offsetExists($key);\n    }\n\n    /**\n     * Unset an attribute on the model.\n     *\n     * @param  string  $key\n     * @return void\n     */\n    public function __unset($key)\n    {\n        $this->offsetUnset($key);\n    }\n\n    /**\n     * Handle dynamic method calls into the model.\n     *\n     * @param  string  $method\n     * @param  array  $parameters\n     * @return mixed\n     */\n    public function __call($method, $parameters)\n    {\n        if (in_array($method, ['increment', 'decrement'])) {\n            return $this->$method(...$parameters);\n        }\n\n        if ($resolver = (static::$relationResolvers[get_class($this)][$method] ?? null)) {\n            return $resolver($this);\n        }\n\n        return $this->forwardCallTo($this->newQuery(), $method, $parameters);\n    }\n\n    /**\n     * Handle dynamic static method calls into the model.\n     *\n     * @param  string  $method\n     * @param  array  $parameters\n     * @return mixed\n     */\n    public static function __callStatic($method, $parameters)\n    {\n        return (new static)->$method(...$parameters);\n    }\n\n    /**\n     * Convert the model to its string representation.\n     *\n     * @return string\n     */\n    public function __toString()\n    {\n        return $this->escapeWhenCastingToString\n                    ? e($this->toJson())\n                    : $this->toJson();\n    }\n\n    /**\n     * Indicate that the object's string representation should be escaped when __toString is invoked.\n     *\n     * @param  bool  $escape\n     * @return $this\n     */\n    public function escapeWhenCastingToString($escape = true)\n    {\n        $this->escapeWhenCastingToString = $escape;\n\n        return $this;\n    }\n\n    /**\n     * Prepare the object for serialization.\n     *\n     * @return array\n     */\n    public function __sleep()\n    {\n        $this->mergeAttributesFromCachedCasts();\n\n        $this->classCastCache = [];\n        $this->attributeCastCache = [];\n\n        return array_keys(get_object_vars($this));\n    }\n\n    /**\n     * When a model is being unserialized, check if it needs to be booted.\n     *\n     * @return void\n     */\n    public function __wakeup()\n    {\n        $this->bootIfNotBooted();\n\n        $this->initializeTraits();\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/ModelNotFoundException.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent;\n\nuse Illuminate\\Database\\RecordsNotFoundException;\nuse Illuminate\\Support\\Arr;\n\nclass ModelNotFoundException extends RecordsNotFoundException\n{\n    /**\n     * Name of the affected Eloquent model.\n     *\n     * @var string\n     */\n    protected $model;\n\n    /**\n     * The affected model IDs.\n     *\n     * @var int|array\n     */\n    protected $ids;\n\n    /**\n     * Set the affected Eloquent model and instance ids.\n     *\n     * @param  string  $model\n     * @param  int|array  $ids\n     * @return $this\n     */\n    public function setModel($model, $ids = [])\n    {\n        $this->model = $model;\n        $this->ids = Arr::wrap($ids);\n\n        $this->message = \"No query results for model [{$model}]\";\n\n        if (count($this->ids) > 0) {\n            $this->message .= ' '.implode(', ', $this->ids);\n        } else {\n            $this->message .= '.';\n        }\n\n        return $this;\n    }\n\n    /**\n     * Get the affected Eloquent model.\n     *\n     * @return string\n     */\n    public function getModel()\n    {\n        return $this->model;\n    }\n\n    /**\n     * Get the affected Eloquent model IDs.\n     *\n     * @return int|array\n     */\n    public function getIds()\n    {\n        return $this->ids;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/Prunable.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent;\n\nuse Illuminate\\Database\\Events\\ModelsPruned;\nuse LogicException;\n\ntrait Prunable\n{\n    /**\n     * Prune all prunable models in the database.\n     *\n     * @param  int  $chunkSize\n     * @return int\n     */\n    public function pruneAll(int $chunkSize = 1000)\n    {\n        $total = 0;\n\n        $this->prunable()\n            ->when(in_array(SoftDeletes::class, class_uses_recursive(get_class($this))), function ($query) {\n                $query->withTrashed();\n            })->chunkById($chunkSize, function ($models) use (&$total) {\n                $models->each->prune();\n\n                $total += $models->count();\n\n                event(new ModelsPruned(static::class, $total));\n            });\n\n        return $total;\n    }\n\n    /**\n     * Get the prunable model query.\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Builder\n     */\n    public function prunable()\n    {\n        throw new LogicException('Please implement the prunable method on your model.');\n    }\n\n    /**\n     * Prune the model in the database.\n     *\n     * @return bool|null\n     */\n    public function prune()\n    {\n        $this->pruning();\n\n        return in_array(SoftDeletes::class, class_uses_recursive(get_class($this)))\n                ? $this->forceDelete()\n                : $this->delete();\n    }\n\n    /**\n     * Prepare the model for pruning.\n     *\n     * @return void\n     */\n    protected function pruning()\n    {\n        //\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/QueueEntityResolver.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent;\n\nuse Illuminate\\Contracts\\Queue\\EntityNotFoundException;\nuse Illuminate\\Contracts\\Queue\\EntityResolver as EntityResolverContract;\n\nclass QueueEntityResolver implements EntityResolverContract\n{\n    /**\n     * Resolve the entity for the given ID.\n     *\n     * @param  string  $type\n     * @param  mixed  $id\n     * @return mixed\n     *\n     * @throws \\Illuminate\\Contracts\\Queue\\EntityNotFoundException\n     */\n    public function resolve($type, $id)\n    {\n        $instance = (new $type)->find($id);\n\n        if ($instance) {\n            return $instance;\n        }\n\n        throw new EntityNotFoundException($type, $id);\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/RelationNotFoundException.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent;\n\nuse RuntimeException;\n\nclass RelationNotFoundException extends RuntimeException\n{\n    /**\n     * The name of the affected Eloquent model.\n     *\n     * @var string\n     */\n    public $model;\n\n    /**\n     * The name of the relation.\n     *\n     * @var string\n     */\n    public $relation;\n\n    /**\n     * Create a new exception instance.\n     *\n     * @param  object  $model\n     * @param  string  $relation\n     * @param  string|null  $type\n     * @return static\n     */\n    public static function make($model, $relation, $type = null)\n    {\n        $class = get_class($model);\n\n        $instance = new static(\n            is_null($type)\n                ? \"Call to undefined relationship [{$relation}] on model [{$class}].\"\n                : \"Call to undefined relationship [{$relation}] on model [{$class}] of type [{$type}].\",\n        );\n\n        $instance->model = $class;\n        $instance->relation = $relation;\n\n        return $instance;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/Relations/BelongsTo.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent\\Relations;\n\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Illuminate\\Database\\Eloquent\\Collection;\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Database\\Eloquent\\Relations\\Concerns\\ComparesRelatedModels;\nuse Illuminate\\Database\\Eloquent\\Relations\\Concerns\\InteractsWithDictionary;\nuse Illuminate\\Database\\Eloquent\\Relations\\Concerns\\SupportsDefaultModels;\n\nclass BelongsTo extends Relation\n{\n    use ComparesRelatedModels,\n        InteractsWithDictionary,\n        SupportsDefaultModels;\n\n    /**\n     * The child model instance of the relation.\n     *\n     * @var \\Illuminate\\Database\\Eloquent\\Model\n     */\n    protected $child;\n\n    /**\n     * The foreign key of the parent model.\n     *\n     * @var string\n     */\n    protected $foreignKey;\n\n    /**\n     * The associated key on the parent model.\n     *\n     * @var string\n     */\n    protected $ownerKey;\n\n    /**\n     * The name of the relationship.\n     *\n     * @var string\n     */\n    protected $relationName;\n\n    /**\n     * Create a new belongs to relationship instance.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $query\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $child\n     * @param  string  $foreignKey\n     * @param  string  $ownerKey\n     * @param  string  $relationName\n     * @return void\n     */\n    public function __construct(Builder $query, Model $child, $foreignKey, $ownerKey, $relationName)\n    {\n        $this->ownerKey = $ownerKey;\n        $this->relationName = $relationName;\n        $this->foreignKey = $foreignKey;\n\n        // In the underlying base relationship class, this variable is referred to as\n        // the \"parent\" since most relationships are not inversed. But, since this\n        // one is we will create a \"child\" variable for much better readability.\n        $this->child = $child;\n\n        parent::__construct($query, $child);\n    }\n\n    /**\n     * Get the results of the relationship.\n     *\n     * @return mixed\n     */\n    public function getResults()\n    {\n        if (is_null($this->child->{$this->foreignKey})) {\n            return $this->getDefaultFor($this->parent);\n        }\n\n        return $this->query->first() ?: $this->getDefaultFor($this->parent);\n    }\n\n    /**\n     * Set the base constraints on the relation query.\n     *\n     * @return void\n     */\n    public function addConstraints()\n    {\n        if (static::$constraints) {\n            // For belongs to relationships, which are essentially the inverse of has one\n            // or has many relationships, we need to actually query on the primary key\n            // of the related models matching on the foreign key that's on a parent.\n            $table = $this->related->getTable();\n\n            $this->query->where($table.'.'.$this->ownerKey, '=', $this->child->{$this->foreignKey});\n        }\n    }\n\n    /**\n     * Set the constraints for an eager load of the relation.\n     *\n     * @param  array  $models\n     * @return void\n     */\n    public function addEagerConstraints(array $models)\n    {\n        // We'll grab the primary key name of the related models since it could be set to\n        // a non-standard name and not \"id\". We will then construct the constraint for\n        // our eagerly loading query so it returns the proper models from execution.\n        $key = $this->related->getTable().'.'.$this->ownerKey;\n\n        $whereIn = $this->whereInMethod($this->related, $this->ownerKey);\n\n        $this->query->{$whereIn}($key, $this->getEagerModelKeys($models));\n    }\n\n    /**\n     * Gather the keys from an array of related models.\n     *\n     * @param  array  $models\n     * @return array\n     */\n    protected function getEagerModelKeys(array $models)\n    {\n        $keys = [];\n\n        // First we need to gather all of the keys from the parent models so we know what\n        // to query for via the eager loading query. We will add them to an array then\n        // execute a \"where in\" statement to gather up all of those related records.\n        foreach ($models as $model) {\n            if (! is_null($value = $model->{$this->foreignKey})) {\n                $keys[] = $value;\n            }\n        }\n\n        sort($keys);\n\n        return array_values(array_unique($keys));\n    }\n\n    /**\n     * Initialize the relation on a set of models.\n     *\n     * @param  array  $models\n     * @param  string  $relation\n     * @return array\n     */\n    public function initRelation(array $models, $relation)\n    {\n        foreach ($models as $model) {\n            $model->setRelation($relation, $this->getDefaultFor($model));\n        }\n\n        return $models;\n    }\n\n    /**\n     * Match the eagerly loaded results to their parents.\n     *\n     * @param  array  $models\n     * @param  \\Illuminate\\Database\\Eloquent\\Collection  $results\n     * @param  string  $relation\n     * @return array\n     */\n    public function match(array $models, Collection $results, $relation)\n    {\n        $foreign = $this->foreignKey;\n\n        $owner = $this->ownerKey;\n\n        // First we will get to build a dictionary of the child models by their primary\n        // key of the relationship, then we can easily match the children back onto\n        // the parents using that dictionary and the primary key of the children.\n        $dictionary = [];\n\n        foreach ($results as $result) {\n            $attribute = $this->getDictionaryKey($result->getAttribute($owner));\n\n            $dictionary[$attribute] = $result;\n        }\n\n        // Once we have the dictionary constructed, we can loop through all the parents\n        // and match back onto their children using these keys of the dictionary and\n        // the primary key of the children to map them onto the correct instances.\n        foreach ($models as $model) {\n            $attribute = $this->getDictionaryKey($model->{$foreign});\n\n            if (isset($dictionary[$attribute])) {\n                $model->setRelation($relation, $dictionary[$attribute]);\n            }\n        }\n\n        return $models;\n    }\n\n    /**\n     * Associate the model instance to the given parent.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Model|int|string|null  $model\n     * @return \\Illuminate\\Database\\Eloquent\\Model\n     */\n    public function associate($model)\n    {\n        $ownerKey = $model instanceof Model ? $model->getAttribute($this->ownerKey) : $model;\n\n        $this->child->setAttribute($this->foreignKey, $ownerKey);\n\n        if ($model instanceof Model) {\n            $this->child->setRelation($this->relationName, $model);\n        } else {\n            $this->child->unsetRelation($this->relationName);\n        }\n\n        return $this->child;\n    }\n\n    /**\n     * Dissociate previously associated model from the given parent.\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Model\n     */\n    public function dissociate()\n    {\n        $this->child->setAttribute($this->foreignKey, null);\n\n        return $this->child->setRelation($this->relationName, null);\n    }\n\n    /**\n     * Alias of \"dissociate\" method.\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Model\n     */\n    public function disassociate()\n    {\n        return $this->dissociate();\n    }\n\n    /**\n     * Add the constraints for a relationship query.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $query\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $parentQuery\n     * @param  array|mixed  $columns\n     * @return \\Illuminate\\Database\\Eloquent\\Builder\n     */\n    public function getRelationExistenceQuery(Builder $query, Builder $parentQuery, $columns = ['*'])\n    {\n        if ($parentQuery->getQuery()->from == $query->getQuery()->from) {\n            return $this->getRelationExistenceQueryForSelfRelation($query, $parentQuery, $columns);\n        }\n\n        return $query->select($columns)->whereColumn(\n            $this->getQualifiedForeignKeyName(), '=', $query->qualifyColumn($this->ownerKey)\n        );\n    }\n\n    /**\n     * Add the constraints for a relationship query on the same table.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $query\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $parentQuery\n     * @param  array|mixed  $columns\n     * @return \\Illuminate\\Database\\Eloquent\\Builder\n     */\n    public function getRelationExistenceQueryForSelfRelation(Builder $query, Builder $parentQuery, $columns = ['*'])\n    {\n        $query->select($columns)->from(\n            $query->getModel()->getTable().' as '.$hash = $this->getRelationCountHash()\n        );\n\n        $query->getModel()->setTable($hash);\n\n        return $query->whereColumn(\n            $hash.'.'.$this->ownerKey, '=', $this->getQualifiedForeignKeyName()\n        );\n    }\n\n    /**\n     * Determine if the related model has an auto-incrementing ID.\n     *\n     * @return bool\n     */\n    protected function relationHasIncrementingId()\n    {\n        return $this->related->getIncrementing() &&\n            in_array($this->related->getKeyType(), ['int', 'integer']);\n    }\n\n    /**\n     * Make a new related instance for the given model.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $parent\n     * @return \\Illuminate\\Database\\Eloquent\\Model\n     */\n    protected function newRelatedInstanceFor(Model $parent)\n    {\n        return $this->related->newInstance();\n    }\n\n    /**\n     * Get the child of the relationship.\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Model\n     */\n    public function getChild()\n    {\n        return $this->child;\n    }\n\n    /**\n     * Get the foreign key of the relationship.\n     *\n     * @return string\n     */\n    public function getForeignKeyName()\n    {\n        return $this->foreignKey;\n    }\n\n    /**\n     * Get the fully qualified foreign key of the relationship.\n     *\n     * @return string\n     */\n    public function getQualifiedForeignKeyName()\n    {\n        return $this->child->qualifyColumn($this->foreignKey);\n    }\n\n    /**\n     * Get the key value of the child's foreign key.\n     *\n     * @return mixed\n     */\n    public function getParentKey()\n    {\n        return $this->child->{$this->foreignKey};\n    }\n\n    /**\n     * Get the associated key of the relationship.\n     *\n     * @return string\n     */\n    public function getOwnerKeyName()\n    {\n        return $this->ownerKey;\n    }\n\n    /**\n     * Get the fully qualified associated key of the relationship.\n     *\n     * @return string\n     */\n    public function getQualifiedOwnerKeyName()\n    {\n        return $this->related->qualifyColumn($this->ownerKey);\n    }\n\n    /**\n     * Get the value of the model's associated key.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $model\n     * @return mixed\n     */\n    protected function getRelatedKeyFrom(Model $model)\n    {\n        return $model->{$this->ownerKey};\n    }\n\n    /**\n     * Get the name of the relationship.\n     *\n     * @return string\n     */\n    public function getRelationName()\n    {\n        return $this->relationName;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/Relations/BelongsToMany.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent\\Relations;\n\nuse Closure;\nuse Illuminate\\Contracts\\Support\\Arrayable;\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Illuminate\\Database\\Eloquent\\Collection;\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Database\\Eloquent\\ModelNotFoundException;\nuse Illuminate\\Database\\Eloquent\\Relations\\Concerns\\AsPivot;\nuse Illuminate\\Database\\Eloquent\\Relations\\Concerns\\InteractsWithDictionary;\nuse Illuminate\\Database\\Eloquent\\Relations\\Concerns\\InteractsWithPivotTable;\nuse Illuminate\\Support\\Str;\nuse InvalidArgumentException;\n\nclass BelongsToMany extends Relation\n{\n    use InteractsWithDictionary, InteractsWithPivotTable;\n\n    /**\n     * The intermediate table for the relation.\n     *\n     * @var string\n     */\n    protected $table;\n\n    /**\n     * The foreign key of the parent model.\n     *\n     * @var string\n     */\n    protected $foreignPivotKey;\n\n    /**\n     * The associated key of the relation.\n     *\n     * @var string\n     */\n    protected $relatedPivotKey;\n\n    /**\n     * The key name of the parent model.\n     *\n     * @var string\n     */\n    protected $parentKey;\n\n    /**\n     * The key name of the related model.\n     *\n     * @var string\n     */\n    protected $relatedKey;\n\n    /**\n     * The \"name\" of the relationship.\n     *\n     * @var string\n     */\n    protected $relationName;\n\n    /**\n     * The pivot table columns to retrieve.\n     *\n     * @var array\n     */\n    protected $pivotColumns = [];\n\n    /**\n     * Any pivot table restrictions for where clauses.\n     *\n     * @var array\n     */\n    protected $pivotWheres = [];\n\n    /**\n     * Any pivot table restrictions for whereIn clauses.\n     *\n     * @var array\n     */\n    protected $pivotWhereIns = [];\n\n    /**\n     * Any pivot table restrictions for whereNull clauses.\n     *\n     * @var array\n     */\n    protected $pivotWhereNulls = [];\n\n    /**\n     * The default values for the pivot columns.\n     *\n     * @var array\n     */\n    protected $pivotValues = [];\n\n    /**\n     * Indicates if timestamps are available on the pivot table.\n     *\n     * @var bool\n     */\n    public $withTimestamps = false;\n\n    /**\n     * The custom pivot table column for the created_at timestamp.\n     *\n     * @var string\n     */\n    protected $pivotCreatedAt;\n\n    /**\n     * The custom pivot table column for the updated_at timestamp.\n     *\n     * @var string\n     */\n    protected $pivotUpdatedAt;\n\n    /**\n     * The class name of the custom pivot model to use for the relationship.\n     *\n     * @var string\n     */\n    protected $using;\n\n    /**\n     * The name of the accessor to use for the \"pivot\" relationship.\n     *\n     * @var string\n     */\n    protected $accessor = 'pivot';\n\n    /**\n     * Create a new belongs to many relationship instance.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $query\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $parent\n     * @param  string  $table\n     * @param  string  $foreignPivotKey\n     * @param  string  $relatedPivotKey\n     * @param  string  $parentKey\n     * @param  string  $relatedKey\n     * @param  string|null  $relationName\n     * @return void\n     */\n    public function __construct(Builder $query, Model $parent, $table, $foreignPivotKey,\n                                $relatedPivotKey, $parentKey, $relatedKey, $relationName = null)\n    {\n        $this->parentKey = $parentKey;\n        $this->relatedKey = $relatedKey;\n        $this->relationName = $relationName;\n        $this->relatedPivotKey = $relatedPivotKey;\n        $this->foreignPivotKey = $foreignPivotKey;\n        $this->table = $this->resolveTableName($table);\n\n        parent::__construct($query, $parent);\n    }\n\n    /**\n     * Attempt to resolve the intermediate table name from the given string.\n     *\n     * @param  string  $table\n     * @return string\n     */\n    protected function resolveTableName($table)\n    {\n        if (! Str::contains($table, '\\\\') || ! class_exists($table)) {\n            return $table;\n        }\n\n        $model = new $table;\n\n        if (! $model instanceof Model) {\n            return $table;\n        }\n\n        if (in_array(AsPivot::class, class_uses_recursive($model))) {\n            $this->using($table);\n        }\n\n        return $model->getTable();\n    }\n\n    /**\n     * Set the base constraints on the relation query.\n     *\n     * @return void\n     */\n    public function addConstraints()\n    {\n        $this->performJoin();\n\n        if (static::$constraints) {\n            $this->addWhereConstraints();\n        }\n    }\n\n    /**\n     * Set the join clause for the relation query.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder|null  $query\n     * @return $this\n     */\n    protected function performJoin($query = null)\n    {\n        $query = $query ?: $this->query;\n\n        // We need to join to the intermediate table on the related model's primary\n        // key column with the intermediate table's foreign key for the related\n        // model instance. Then we can set the \"where\" for the parent models.\n        $query->join(\n            $this->table,\n            $this->getQualifiedRelatedKeyName(),\n            '=',\n            $this->getQualifiedRelatedPivotKeyName()\n        );\n\n        return $this;\n    }\n\n    /**\n     * Set the where clause for the relation query.\n     *\n     * @return $this\n     */\n    protected function addWhereConstraints()\n    {\n        $this->query->where(\n            $this->getQualifiedForeignPivotKeyName(), '=', $this->parent->{$this->parentKey}\n        );\n\n        return $this;\n    }\n\n    /**\n     * Set the constraints for an eager load of the relation.\n     *\n     * @param  array  $models\n     * @return void\n     */\n    public function addEagerConstraints(array $models)\n    {\n        $whereIn = $this->whereInMethod($this->parent, $this->parentKey);\n\n        $this->query->{$whereIn}(\n            $this->getQualifiedForeignPivotKeyName(),\n            $this->getKeys($models, $this->parentKey)\n        );\n    }\n\n    /**\n     * Initialize the relation on a set of models.\n     *\n     * @param  array  $models\n     * @param  string  $relation\n     * @return array\n     */\n    public function initRelation(array $models, $relation)\n    {\n        foreach ($models as $model) {\n            $model->setRelation($relation, $this->related->newCollection());\n        }\n\n        return $models;\n    }\n\n    /**\n     * Match the eagerly loaded results to their parents.\n     *\n     * @param  array  $models\n     * @param  \\Illuminate\\Database\\Eloquent\\Collection  $results\n     * @param  string  $relation\n     * @return array\n     */\n    public function match(array $models, Collection $results, $relation)\n    {\n        $dictionary = $this->buildDictionary($results);\n\n        // Once we have an array dictionary of child objects we can easily match the\n        // children back to their parent using the dictionary and the keys on the\n        // parent models. Then we should return these hydrated models back out.\n        foreach ($models as $model) {\n            $key = $this->getDictionaryKey($model->{$this->parentKey});\n\n            if (isset($dictionary[$key])) {\n                $model->setRelation(\n                    $relation, $this->related->newCollection($dictionary[$key])\n                );\n            }\n        }\n\n        return $models;\n    }\n\n    /**\n     * Build model dictionary keyed by the relation's foreign key.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Collection  $results\n     * @return array\n     */\n    protected function buildDictionary(Collection $results)\n    {\n        // First we will build a dictionary of child models keyed by the foreign key\n        // of the relation so that we will easily and quickly match them to their\n        // parents without having a possibly slow inner loops for every models.\n        $dictionary = [];\n\n        foreach ($results as $result) {\n            $value = $this->getDictionaryKey($result->{$this->accessor}->{$this->foreignPivotKey});\n\n            $dictionary[$value][] = $result;\n        }\n\n        return $dictionary;\n    }\n\n    /**\n     * Get the class being used for pivot models.\n     *\n     * @return string\n     */\n    public function getPivotClass()\n    {\n        return $this->using ?? Pivot::class;\n    }\n\n    /**\n     * Specify the custom pivot model to use for the relationship.\n     *\n     * @param  string  $class\n     * @return $this\n     */\n    public function using($class)\n    {\n        $this->using = $class;\n\n        return $this;\n    }\n\n    /**\n     * Specify the custom pivot accessor to use for the relationship.\n     *\n     * @param  string  $accessor\n     * @return $this\n     */\n    public function as($accessor)\n    {\n        $this->accessor = $accessor;\n\n        return $this;\n    }\n\n    /**\n     * Set a where clause for a pivot table column.\n     *\n     * @param  string  $column\n     * @param  mixed  $operator\n     * @param  mixed  $value\n     * @param  string  $boolean\n     * @return $this\n     */\n    public function wherePivot($column, $operator = null, $value = null, $boolean = 'and')\n    {\n        $this->pivotWheres[] = func_get_args();\n\n        return $this->where($this->qualifyPivotColumn($column), $operator, $value, $boolean);\n    }\n\n    /**\n     * Set a \"where between\" clause for a pivot table column.\n     *\n     * @param  string  $column\n     * @param  array  $values\n     * @param  string  $boolean\n     * @param  bool  $not\n     * @return $this\n     */\n    public function wherePivotBetween($column, array $values, $boolean = 'and', $not = false)\n    {\n        return $this->whereBetween($this->qualifyPivotColumn($column), $values, $boolean, $not);\n    }\n\n    /**\n     * Set a \"or where between\" clause for a pivot table column.\n     *\n     * @param  string  $column\n     * @param  array  $values\n     * @return $this\n     */\n    public function orWherePivotBetween($column, array $values)\n    {\n        return $this->wherePivotBetween($column, $values, 'or');\n    }\n\n    /**\n     * Set a \"where pivot not between\" clause for a pivot table column.\n     *\n     * @param  string  $column\n     * @param  array  $values\n     * @param  string  $boolean\n     * @return $this\n     */\n    public function wherePivotNotBetween($column, array $values, $boolean = 'and')\n    {\n        return $this->wherePivotBetween($column, $values, $boolean, true);\n    }\n\n    /**\n     * Set a \"or where not between\" clause for a pivot table column.\n     *\n     * @param  string  $column\n     * @param  array  $values\n     * @return $this\n     */\n    public function orWherePivotNotBetween($column, array $values)\n    {\n        return $this->wherePivotBetween($column, $values, 'or', true);\n    }\n\n    /**\n     * Set a \"where in\" clause for a pivot table column.\n     *\n     * @param  string  $column\n     * @param  mixed  $values\n     * @param  string  $boolean\n     * @param  bool  $not\n     * @return $this\n     */\n    public function wherePivotIn($column, $values, $boolean = 'and', $not = false)\n    {\n        $this->pivotWhereIns[] = func_get_args();\n\n        return $this->whereIn($this->qualifyPivotColumn($column), $values, $boolean, $not);\n    }\n\n    /**\n     * Set an \"or where\" clause for a pivot table column.\n     *\n     * @param  string  $column\n     * @param  mixed  $operator\n     * @param  mixed  $value\n     * @return $this\n     */\n    public function orWherePivot($column, $operator = null, $value = null)\n    {\n        return $this->wherePivot($column, $operator, $value, 'or');\n    }\n\n    /**\n     * Set a where clause for a pivot table column.\n     *\n     * In addition, new pivot records will receive this value.\n     *\n     * @param  string|array  $column\n     * @param  mixed  $value\n     * @return $this\n     *\n     * @throws \\InvalidArgumentException\n     */\n    public function withPivotValue($column, $value = null)\n    {\n        if (is_array($column)) {\n            foreach ($column as $name => $value) {\n                $this->withPivotValue($name, $value);\n            }\n\n            return $this;\n        }\n\n        if (is_null($value)) {\n            throw new InvalidArgumentException('The provided value may not be null.');\n        }\n\n        $this->pivotValues[] = compact('column', 'value');\n\n        return $this->wherePivot($column, '=', $value);\n    }\n\n    /**\n     * Set an \"or where in\" clause for a pivot table column.\n     *\n     * @param  string  $column\n     * @param  mixed  $values\n     * @return $this\n     */\n    public function orWherePivotIn($column, $values)\n    {\n        return $this->wherePivotIn($column, $values, 'or');\n    }\n\n    /**\n     * Set a \"where not in\" clause for a pivot table column.\n     *\n     * @param  string  $column\n     * @param  mixed  $values\n     * @param  string  $boolean\n     * @return $this\n     */\n    public function wherePivotNotIn($column, $values, $boolean = 'and')\n    {\n        return $this->wherePivotIn($column, $values, $boolean, true);\n    }\n\n    /**\n     * Set an \"or where not in\" clause for a pivot table column.\n     *\n     * @param  string  $column\n     * @param  mixed  $values\n     * @return $this\n     */\n    public function orWherePivotNotIn($column, $values)\n    {\n        return $this->wherePivotNotIn($column, $values, 'or');\n    }\n\n    /**\n     * Set a \"where null\" clause for a pivot table column.\n     *\n     * @param  string  $column\n     * @param  string  $boolean\n     * @param  bool  $not\n     * @return $this\n     */\n    public function wherePivotNull($column, $boolean = 'and', $not = false)\n    {\n        $this->pivotWhereNulls[] = func_get_args();\n\n        return $this->whereNull($this->qualifyPivotColumn($column), $boolean, $not);\n    }\n\n    /**\n     * Set a \"where not null\" clause for a pivot table column.\n     *\n     * @param  string  $column\n     * @param  string  $boolean\n     * @return $this\n     */\n    public function wherePivotNotNull($column, $boolean = 'and')\n    {\n        return $this->wherePivotNull($column, $boolean, true);\n    }\n\n    /**\n     * Set a \"or where null\" clause for a pivot table column.\n     *\n     * @param  string  $column\n     * @param  bool  $not\n     * @return $this\n     */\n    public function orWherePivotNull($column, $not = false)\n    {\n        return $this->wherePivotNull($column, 'or', $not);\n    }\n\n    /**\n     * Set a \"or where not null\" clause for a pivot table column.\n     *\n     * @param  string  $column\n     * @return $this\n     */\n    public function orWherePivotNotNull($column)\n    {\n        return $this->orWherePivotNull($column, true);\n    }\n\n    /**\n     * Add an \"order by\" clause for a pivot table column.\n     *\n     * @param  string  $column\n     * @param  string  $direction\n     * @return $this\n     */\n    public function orderByPivot($column, $direction = 'asc')\n    {\n        return $this->orderBy($this->qualifyPivotColumn($column), $direction);\n    }\n\n    /**\n     * Find a related model by its primary key or return a new instance of the related model.\n     *\n     * @param  mixed  $id\n     * @param  array  $columns\n     * @return \\Illuminate\\Support\\Collection|\\Illuminate\\Database\\Eloquent\\Model\n     */\n    public function findOrNew($id, $columns = ['*'])\n    {\n        if (is_null($instance = $this->find($id, $columns))) {\n            $instance = $this->related->newInstance();\n        }\n\n        return $instance;\n    }\n\n    /**\n     * Get the first related model record matching the attributes or instantiate it.\n     *\n     * @param  array  $attributes\n     * @return \\Illuminate\\Database\\Eloquent\\Model\n     */\n    public function firstOrNew(array $attributes)\n    {\n        if (is_null($instance = $this->where($attributes)->first())) {\n            $instance = $this->related->newInstance($attributes);\n        }\n\n        return $instance;\n    }\n\n    /**\n     * Get the first related record matching the attributes or create it.\n     *\n     * @param  array  $attributes\n     * @param  array  $joining\n     * @param  bool  $touch\n     * @return \\Illuminate\\Database\\Eloquent\\Model\n     */\n    public function firstOrCreate(array $attributes, array $joining = [], $touch = true)\n    {\n        if (is_null($instance = $this->where($attributes)->first())) {\n            $instance = $this->create($attributes, $joining, $touch);\n        }\n\n        return $instance;\n    }\n\n    /**\n     * Create or update a related record matching the attributes, and fill it with values.\n     *\n     * @param  array  $attributes\n     * @param  array  $values\n     * @param  array  $joining\n     * @param  bool  $touch\n     * @return \\Illuminate\\Database\\Eloquent\\Model\n     */\n    public function updateOrCreate(array $attributes, array $values = [], array $joining = [], $touch = true)\n    {\n        if (is_null($instance = $this->where($attributes)->first())) {\n            return $this->create($values, $joining, $touch);\n        }\n\n        $instance->fill($values);\n\n        $instance->save(['touch' => false]);\n\n        return $instance;\n    }\n\n    /**\n     * Find a related model by its primary key.\n     *\n     * @param  mixed  $id\n     * @param  array  $columns\n     * @return \\Illuminate\\Database\\Eloquent\\Model|\\Illuminate\\Database\\Eloquent\\Collection|null\n     */\n    public function find($id, $columns = ['*'])\n    {\n        if (! $id instanceof Model && (is_array($id) || $id instanceof Arrayable)) {\n            return $this->findMany($id, $columns);\n        }\n\n        return $this->where(\n            $this->getRelated()->getQualifiedKeyName(), '=', $this->parseId($id)\n        )->first($columns);\n    }\n\n    /**\n     * Find multiple related models by their primary keys.\n     *\n     * @param  \\Illuminate\\Contracts\\Support\\Arrayable|array  $ids\n     * @param  array  $columns\n     * @return \\Illuminate\\Database\\Eloquent\\Collection\n     */\n    public function findMany($ids, $columns = ['*'])\n    {\n        $ids = $ids instanceof Arrayable ? $ids->toArray() : $ids;\n\n        if (empty($ids)) {\n            return $this->getRelated()->newCollection();\n        }\n\n        return $this->whereIn(\n            $this->getRelated()->getQualifiedKeyName(), $this->parseIds($ids)\n        )->get($columns);\n    }\n\n    /**\n     * Find a related model by its primary key or throw an exception.\n     *\n     * @param  mixed  $id\n     * @param  array  $columns\n     * @return \\Illuminate\\Database\\Eloquent\\Model|\\Illuminate\\Database\\Eloquent\\Collection\n     *\n     * @throws \\Illuminate\\Database\\Eloquent\\ModelNotFoundException\n     */\n    public function findOrFail($id, $columns = ['*'])\n    {\n        $result = $this->find($id, $columns);\n\n        $id = $id instanceof Arrayable ? $id->toArray() : $id;\n\n        if (is_array($id)) {\n            if (count($result) === count(array_unique($id))) {\n                return $result;\n            }\n        } elseif (! is_null($result)) {\n            return $result;\n        }\n\n        throw (new ModelNotFoundException)->setModel(get_class($this->related), $id);\n    }\n\n    /**\n     * Add a basic where clause to the query, and return the first result.\n     *\n     * @param  \\Closure|string|array  $column\n     * @param  mixed  $operator\n     * @param  mixed  $value\n     * @param  string  $boolean\n     * @return \\Illuminate\\Database\\Eloquent\\Model|static\n     */\n    public function firstWhere($column, $operator = null, $value = null, $boolean = 'and')\n    {\n        return $this->where($column, $operator, $value, $boolean)->first();\n    }\n\n    /**\n     * Execute the query and get the first result.\n     *\n     * @param  array  $columns\n     * @return mixed\n     */\n    public function first($columns = ['*'])\n    {\n        $results = $this->take(1)->get($columns);\n\n        return count($results) > 0 ? $results->first() : null;\n    }\n\n    /**\n     * Execute the query and get the first result or throw an exception.\n     *\n     * @param  array  $columns\n     * @return \\Illuminate\\Database\\Eloquent\\Model|static\n     *\n     * @throws \\Illuminate\\Database\\Eloquent\\ModelNotFoundException\n     */\n    public function firstOrFail($columns = ['*'])\n    {\n        if (! is_null($model = $this->first($columns))) {\n            return $model;\n        }\n\n        throw (new ModelNotFoundException)->setModel(get_class($this->related));\n    }\n\n    /**\n     * Execute the query and get the first result or call a callback.\n     *\n     * @param  \\Closure|array  $columns\n     * @param  \\Closure|null  $callback\n     * @return \\Illuminate\\Database\\Eloquent\\Model|static|mixed\n     */\n    public function firstOr($columns = ['*'], Closure $callback = null)\n    {\n        if ($columns instanceof Closure) {\n            $callback = $columns;\n\n            $columns = ['*'];\n        }\n\n        if (! is_null($model = $this->first($columns))) {\n            return $model;\n        }\n\n        return $callback();\n    }\n\n    /**\n     * Get the results of the relationship.\n     *\n     * @return mixed\n     */\n    public function getResults()\n    {\n        return ! is_null($this->parent->{$this->parentKey})\n                ? $this->get()\n                : $this->related->newCollection();\n    }\n\n    /**\n     * Execute the query as a \"select\" statement.\n     *\n     * @param  array  $columns\n     * @return \\Illuminate\\Database\\Eloquent\\Collection\n     */\n    public function get($columns = ['*'])\n    {\n        // First we'll add the proper select columns onto the query so it is run with\n        // the proper columns. Then, we will get the results and hydrate our pivot\n        // models with the result of those columns as a separate model relation.\n        $builder = $this->query->applyScopes();\n\n        $columns = $builder->getQuery()->columns ? [] : $columns;\n\n        $models = $builder->addSelect(\n            $this->shouldSelect($columns)\n        )->getModels();\n\n        $this->hydratePivotRelation($models);\n\n        // If we actually found models we will also eager load any relationships that\n        // have been specified as needing to be eager loaded. This will solve the\n        // n + 1 query problem for the developer and also increase performance.\n        if (count($models) > 0) {\n            $models = $builder->eagerLoadRelations($models);\n        }\n\n        return $this->related->newCollection($models);\n    }\n\n    /**\n     * Get the select columns for the relation query.\n     *\n     * @param  array  $columns\n     * @return array\n     */\n    protected function shouldSelect(array $columns = ['*'])\n    {\n        if ($columns == ['*']) {\n            $columns = [$this->related->getTable().'.*'];\n        }\n\n        return array_merge($columns, $this->aliasedPivotColumns());\n    }\n\n    /**\n     * Get the pivot columns for the relation.\n     *\n     * \"pivot_\" is prefixed ot each column for easy removal later.\n     *\n     * @return array\n     */\n    protected function aliasedPivotColumns()\n    {\n        $defaults = [$this->foreignPivotKey, $this->relatedPivotKey];\n\n        return collect(array_merge($defaults, $this->pivotColumns))->map(function ($column) {\n            return $this->qualifyPivotColumn($column).' as pivot_'.$column;\n        })->unique()->all();\n    }\n\n    /**\n     * Get a paginator for the \"select\" statement.\n     *\n     * @param  int|null  $perPage\n     * @param  array  $columns\n     * @param  string  $pageName\n     * @param  int|null  $page\n     * @return \\Illuminate\\Contracts\\Pagination\\LengthAwarePaginator\n     */\n    public function paginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null)\n    {\n        $this->query->addSelect($this->shouldSelect($columns));\n\n        return tap($this->query->paginate($perPage, $columns, $pageName, $page), function ($paginator) {\n            $this->hydratePivotRelation($paginator->items());\n        });\n    }\n\n    /**\n     * Paginate the given query into a simple paginator.\n     *\n     * @param  int|null  $perPage\n     * @param  array  $columns\n     * @param  string  $pageName\n     * @param  int|null  $page\n     * @return \\Illuminate\\Contracts\\Pagination\\Paginator\n     */\n    public function simplePaginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null)\n    {\n        $this->query->addSelect($this->shouldSelect($columns));\n\n        return tap($this->query->simplePaginate($perPage, $columns, $pageName, $page), function ($paginator) {\n            $this->hydratePivotRelation($paginator->items());\n        });\n    }\n\n    /**\n     * Paginate the given query into a cursor paginator.\n     *\n     * @param  int|null  $perPage\n     * @param  array  $columns\n     * @param  string  $cursorName\n     * @param  string|null  $cursor\n     * @return \\Illuminate\\Contracts\\Pagination\\CursorPaginator\n     */\n    public function cursorPaginate($perPage = null, $columns = ['*'], $cursorName = 'cursor', $cursor = null)\n    {\n        $this->query->addSelect($this->shouldSelect($columns));\n\n        return tap($this->query->cursorPaginate($perPage, $columns, $cursorName, $cursor), function ($paginator) {\n            $this->hydratePivotRelation($paginator->items());\n        });\n    }\n\n    /**\n     * Chunk the results of the query.\n     *\n     * @param  int  $count\n     * @param  callable  $callback\n     * @return bool\n     */\n    public function chunk($count, callable $callback)\n    {\n        return $this->prepareQueryBuilder()->chunk($count, function ($results, $page) use ($callback) {\n            $this->hydratePivotRelation($results->all());\n\n            return $callback($results, $page);\n        });\n    }\n\n    /**\n     * Chunk the results of a query by comparing numeric IDs.\n     *\n     * @param  int  $count\n     * @param  callable  $callback\n     * @param  string|null  $column\n     * @param  string|null  $alias\n     * @return bool\n     */\n    public function chunkById($count, callable $callback, $column = null, $alias = null)\n    {\n        $this->prepareQueryBuilder();\n\n        $column = $column ?? $this->getRelated()->qualifyColumn(\n            $this->getRelatedKeyName()\n        );\n\n        $alias = $alias ?? $this->getRelatedKeyName();\n\n        return $this->query->chunkById($count, function ($results) use ($callback) {\n            $this->hydratePivotRelation($results->all());\n\n            return $callback($results);\n        }, $column, $alias);\n    }\n\n    /**\n     * Execute a callback over each item while chunking.\n     *\n     * @param  callable  $callback\n     * @param  int  $count\n     * @return bool\n     */\n    public function each(callable $callback, $count = 1000)\n    {\n        return $this->chunk($count, function ($results) use ($callback) {\n            foreach ($results as $key => $value) {\n                if ($callback($value, $key) === false) {\n                    return false;\n                }\n            }\n        });\n    }\n\n    /**\n     * Query lazily, by chunks of the given size.\n     *\n     * @param  int  $chunkSize\n     * @return \\Illuminate\\Support\\LazyCollection\n     */\n    public function lazy($chunkSize = 1000)\n    {\n        return $this->prepareQueryBuilder()->lazy($chunkSize)->map(function ($model) {\n            $this->hydratePivotRelation([$model]);\n\n            return $model;\n        });\n    }\n\n    /**\n     * Query lazily, by chunking the results of a query by comparing IDs.\n     *\n     * @param  int  $chunkSize\n     * @param  string|null  $column\n     * @param  string|null  $alias\n     * @return \\Illuminate\\Support\\LazyCollection\n     */\n    public function lazyById($chunkSize = 1000, $column = null, $alias = null)\n    {\n        $column = $column ?? $this->getRelated()->qualifyColumn(\n            $this->getRelatedKeyName()\n        );\n\n        $alias = $alias ?? $this->getRelatedKeyName();\n\n        return $this->prepareQueryBuilder()->lazyById($chunkSize, $column, $alias)->map(function ($model) {\n            $this->hydratePivotRelation([$model]);\n\n            return $model;\n        });\n    }\n\n    /**\n     * Get a lazy collection for the given query.\n     *\n     * @return \\Illuminate\\Support\\LazyCollection\n     */\n    public function cursor()\n    {\n        return $this->prepareQueryBuilder()->cursor()->map(function ($model) {\n            $this->hydratePivotRelation([$model]);\n\n            return $model;\n        });\n    }\n\n    /**\n     * Prepare the query builder for query execution.\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Builder\n     */\n    protected function prepareQueryBuilder()\n    {\n        return $this->query->addSelect($this->shouldSelect());\n    }\n\n    /**\n     * Hydrate the pivot table relationship on the models.\n     *\n     * @param  array  $models\n     * @return void\n     */\n    protected function hydratePivotRelation(array $models)\n    {\n        // To hydrate the pivot relationship, we will just gather the pivot attributes\n        // and create a new Pivot model, which is basically a dynamic model that we\n        // will set the attributes, table, and connections on it so it will work.\n        foreach ($models as $model) {\n            $model->setRelation($this->accessor, $this->newExistingPivot(\n                $this->migratePivotAttributes($model)\n            ));\n        }\n    }\n\n    /**\n     * Get the pivot attributes from a model.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $model\n     * @return array\n     */\n    protected function migratePivotAttributes(Model $model)\n    {\n        $values = [];\n\n        foreach ($model->getAttributes() as $key => $value) {\n            // To get the pivots attributes we will just take any of the attributes which\n            // begin with \"pivot_\" and add those to this arrays, as well as unsetting\n            // them from the parent's models since they exist in a different table.\n            if (strpos($key, 'pivot_') === 0) {\n                $values[substr($key, 6)] = $value;\n\n                unset($model->$key);\n            }\n        }\n\n        return $values;\n    }\n\n    /**\n     * If we're touching the parent model, touch.\n     *\n     * @return void\n     */\n    public function touchIfTouching()\n    {\n        if ($this->touchingParent()) {\n            $this->getParent()->touch();\n        }\n\n        if ($this->getParent()->touches($this->relationName)) {\n            $this->touch();\n        }\n    }\n\n    /**\n     * Determine if we should touch the parent on sync.\n     *\n     * @return bool\n     */\n    protected function touchingParent()\n    {\n        return $this->getRelated()->touches($this->guessInverseRelation());\n    }\n\n    /**\n     * Attempt to guess the name of the inverse of the relation.\n     *\n     * @return string\n     */\n    protected function guessInverseRelation()\n    {\n        return Str::camel(Str::pluralStudly(class_basename($this->getParent())));\n    }\n\n    /**\n     * Touch all of the related models for the relationship.\n     *\n     * E.g.: Touch all roles associated with this user.\n     *\n     * @return void\n     */\n    public function touch()\n    {\n        $key = $this->getRelated()->getKeyName();\n\n        $columns = [\n            $this->related->getUpdatedAtColumn() => $this->related->freshTimestampString(),\n        ];\n\n        // If we actually have IDs for the relation, we will run the query to update all\n        // the related model's timestamps, to make sure these all reflect the changes\n        // to the parent models. This will help us keep any caching synced up here.\n        if (count($ids = $this->allRelatedIds()) > 0) {\n            $this->getRelated()->newQueryWithoutRelationships()->whereIn($key, $ids)->update($columns);\n        }\n    }\n\n    /**\n     * Get all of the IDs for the related models.\n     *\n     * @return \\Illuminate\\Support\\Collection\n     */\n    public function allRelatedIds()\n    {\n        return $this->newPivotQuery()->pluck($this->relatedPivotKey);\n    }\n\n    /**\n     * Save a new model and attach it to the parent model.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $model\n     * @param  array  $pivotAttributes\n     * @param  bool  $touch\n     * @return \\Illuminate\\Database\\Eloquent\\Model\n     */\n    public function save(Model $model, array $pivotAttributes = [], $touch = true)\n    {\n        $model->save(['touch' => false]);\n\n        $this->attach($model, $pivotAttributes, $touch);\n\n        return $model;\n    }\n\n    /**\n     * Save an array of new models and attach them to the parent model.\n     *\n     * @param  \\Illuminate\\Support\\Collection|array  $models\n     * @param  array  $pivotAttributes\n     * @return array\n     */\n    public function saveMany($models, array $pivotAttributes = [])\n    {\n        foreach ($models as $key => $model) {\n            $this->save($model, (array) ($pivotAttributes[$key] ?? []), false);\n        }\n\n        $this->touchIfTouching();\n\n        return $models;\n    }\n\n    /**\n     * Create a new instance of the related model.\n     *\n     * @param  array  $attributes\n     * @param  array  $joining\n     * @param  bool  $touch\n     * @return \\Illuminate\\Database\\Eloquent\\Model\n     */\n    public function create(array $attributes = [], array $joining = [], $touch = true)\n    {\n        $instance = $this->related->newInstance($attributes);\n\n        // Once we save the related model, we need to attach it to the base model via\n        // through intermediate table so we'll use the existing \"attach\" method to\n        // accomplish this which will insert the record and any more attributes.\n        $instance->save(['touch' => false]);\n\n        $this->attach($instance, $joining, $touch);\n\n        return $instance;\n    }\n\n    /**\n     * Create an array of new instances of the related models.\n     *\n     * @param  iterable  $records\n     * @param  array  $joinings\n     * @return array\n     */\n    public function createMany(iterable $records, array $joinings = [])\n    {\n        $instances = [];\n\n        foreach ($records as $key => $record) {\n            $instances[] = $this->create($record, (array) ($joinings[$key] ?? []), false);\n        }\n\n        $this->touchIfTouching();\n\n        return $instances;\n    }\n\n    /**\n     * Add the constraints for a relationship query.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $query\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $parentQuery\n     * @param  array|mixed  $columns\n     * @return \\Illuminate\\Database\\Eloquent\\Builder\n     */\n    public function getRelationExistenceQuery(Builder $query, Builder $parentQuery, $columns = ['*'])\n    {\n        if ($parentQuery->getQuery()->from == $query->getQuery()->from) {\n            return $this->getRelationExistenceQueryForSelfJoin($query, $parentQuery, $columns);\n        }\n\n        $this->performJoin($query);\n\n        return parent::getRelationExistenceQuery($query, $parentQuery, $columns);\n    }\n\n    /**\n     * Add the constraints for a relationship query on the same table.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $query\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $parentQuery\n     * @param  array|mixed  $columns\n     * @return \\Illuminate\\Database\\Eloquent\\Builder\n     */\n    public function getRelationExistenceQueryForSelfJoin(Builder $query, Builder $parentQuery, $columns = ['*'])\n    {\n        $query->select($columns);\n\n        $query->from($this->related->getTable().' as '.$hash = $this->getRelationCountHash());\n\n        $this->related->setTable($hash);\n\n        $this->performJoin($query);\n\n        return parent::getRelationExistenceQuery($query, $parentQuery, $columns);\n    }\n\n    /**\n     * Get the key for comparing against the parent key in \"has\" query.\n     *\n     * @return string\n     */\n    public function getExistenceCompareKey()\n    {\n        return $this->getQualifiedForeignPivotKeyName();\n    }\n\n    /**\n     * Specify that the pivot table has creation and update timestamps.\n     *\n     * @param  mixed  $createdAt\n     * @param  mixed  $updatedAt\n     * @return $this\n     */\n    public function withTimestamps($createdAt = null, $updatedAt = null)\n    {\n        $this->withTimestamps = true;\n\n        $this->pivotCreatedAt = $createdAt;\n        $this->pivotUpdatedAt = $updatedAt;\n\n        return $this->withPivot($this->createdAt(), $this->updatedAt());\n    }\n\n    /**\n     * Get the name of the \"created at\" column.\n     *\n     * @return string\n     */\n    public function createdAt()\n    {\n        return $this->pivotCreatedAt ?: $this->parent->getCreatedAtColumn();\n    }\n\n    /**\n     * Get the name of the \"updated at\" column.\n     *\n     * @return string\n     */\n    public function updatedAt()\n    {\n        return $this->pivotUpdatedAt ?: $this->parent->getUpdatedAtColumn();\n    }\n\n    /**\n     * Get the foreign key for the relation.\n     *\n     * @return string\n     */\n    public function getForeignPivotKeyName()\n    {\n        return $this->foreignPivotKey;\n    }\n\n    /**\n     * Get the fully qualified foreign key for the relation.\n     *\n     * @return string\n     */\n    public function getQualifiedForeignPivotKeyName()\n    {\n        return $this->qualifyPivotColumn($this->foreignPivotKey);\n    }\n\n    /**\n     * Get the \"related key\" for the relation.\n     *\n     * @return string\n     */\n    public function getRelatedPivotKeyName()\n    {\n        return $this->relatedPivotKey;\n    }\n\n    /**\n     * Get the fully qualified \"related key\" for the relation.\n     *\n     * @return string\n     */\n    public function getQualifiedRelatedPivotKeyName()\n    {\n        return $this->qualifyPivotColumn($this->relatedPivotKey);\n    }\n\n    /**\n     * Get the parent key for the relationship.\n     *\n     * @return string\n     */\n    public function getParentKeyName()\n    {\n        return $this->parentKey;\n    }\n\n    /**\n     * Get the fully qualified parent key name for the relation.\n     *\n     * @return string\n     */\n    public function getQualifiedParentKeyName()\n    {\n        return $this->parent->qualifyColumn($this->parentKey);\n    }\n\n    /**\n     * Get the related key for the relationship.\n     *\n     * @return string\n     */\n    public function getRelatedKeyName()\n    {\n        return $this->relatedKey;\n    }\n\n    /**\n     * Get the fully qualified related key name for the relation.\n     *\n     * @return string\n     */\n    public function getQualifiedRelatedKeyName()\n    {\n        return $this->related->qualifyColumn($this->relatedKey);\n    }\n\n    /**\n     * Get the intermediate table for the relationship.\n     *\n     * @return string\n     */\n    public function getTable()\n    {\n        return $this->table;\n    }\n\n    /**\n     * Get the relationship name for the relationship.\n     *\n     * @return string\n     */\n    public function getRelationName()\n    {\n        return $this->relationName;\n    }\n\n    /**\n     * Get the name of the pivot accessor for this relationship.\n     *\n     * @return string\n     */\n    public function getPivotAccessor()\n    {\n        return $this->accessor;\n    }\n\n    /**\n     * Get the pivot columns for this relationship.\n     *\n     * @return array\n     */\n    public function getPivotColumns()\n    {\n        return $this->pivotColumns;\n    }\n\n    /**\n     * Qualify the given column name by the pivot table.\n     *\n     * @param  string  $column\n     * @return string\n     */\n    public function qualifyPivotColumn($column)\n    {\n        return Str::contains($column, '.')\n                    ? $column\n                    : $this->table.'.'.$column;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/Relations/Concerns/AsPivot.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent\\Relations\\Concerns;\n\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Support\\Str;\n\ntrait AsPivot\n{\n    /**\n     * The parent model of the relationship.\n     *\n     * @var \\Illuminate\\Database\\Eloquent\\Model\n     */\n    public $pivotParent;\n\n    /**\n     * The name of the foreign key column.\n     *\n     * @var string\n     */\n    protected $foreignKey;\n\n    /**\n     * The name of the \"other key\" column.\n     *\n     * @var string\n     */\n    protected $relatedKey;\n\n    /**\n     * Create a new pivot model instance.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $parent\n     * @param  array  $attributes\n     * @param  string  $table\n     * @param  bool  $exists\n     * @return static\n     */\n    public static function fromAttributes(Model $parent, $attributes, $table, $exists = false)\n    {\n        $instance = new static;\n\n        $instance->timestamps = $instance->hasTimestampAttributes($attributes);\n\n        // The pivot model is a \"dynamic\" model since we will set the tables dynamically\n        // for the instance. This allows it work for any intermediate tables for the\n        // many to many relationship that are defined by this developer's classes.\n        $instance->setConnection($parent->getConnectionName())\n            ->setTable($table)\n            ->forceFill($attributes)\n            ->syncOriginal();\n\n        // We store off the parent instance so we will access the timestamp column names\n        // for the model, since the pivot model timestamps aren't easily configurable\n        // from the developer's point of view. We can use the parents to get these.\n        $instance->pivotParent = $parent;\n\n        $instance->exists = $exists;\n\n        return $instance;\n    }\n\n    /**\n     * Create a new pivot model from raw values returned from a query.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $parent\n     * @param  array  $attributes\n     * @param  string  $table\n     * @param  bool  $exists\n     * @return static\n     */\n    public static function fromRawAttributes(Model $parent, $attributes, $table, $exists = false)\n    {\n        $instance = static::fromAttributes($parent, [], $table, $exists);\n\n        $instance->timestamps = $instance->hasTimestampAttributes($attributes);\n\n        $instance->setRawAttributes($attributes, $exists);\n\n        return $instance;\n    }\n\n    /**\n     * Set the keys for a select query.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $query\n     * @return \\Illuminate\\Database\\Eloquent\\Builder\n     */\n    protected function setKeysForSelectQuery($query)\n    {\n        if (isset($this->attributes[$this->getKeyName()])) {\n            return parent::setKeysForSelectQuery($query);\n        }\n\n        $query->where($this->foreignKey, $this->getOriginal(\n            $this->foreignKey, $this->getAttribute($this->foreignKey)\n        ));\n\n        return $query->where($this->relatedKey, $this->getOriginal(\n            $this->relatedKey, $this->getAttribute($this->relatedKey)\n        ));\n    }\n\n    /**\n     * Set the keys for a save update query.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $query\n     * @return \\Illuminate\\Database\\Eloquent\\Builder\n     */\n    protected function setKeysForSaveQuery($query)\n    {\n        return $this->setKeysForSelectQuery($query);\n    }\n\n    /**\n     * Delete the pivot model record from the database.\n     *\n     * @return int\n     */\n    public function delete()\n    {\n        if (isset($this->attributes[$this->getKeyName()])) {\n            return (int) parent::delete();\n        }\n\n        if ($this->fireModelEvent('deleting') === false) {\n            return 0;\n        }\n\n        $this->touchOwners();\n\n        return tap($this->getDeleteQuery()->delete(), function () {\n            $this->exists = false;\n\n            $this->fireModelEvent('deleted', false);\n        });\n    }\n\n    /**\n     * Get the query builder for a delete operation on the pivot.\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Builder\n     */\n    protected function getDeleteQuery()\n    {\n        return $this->newQueryWithoutRelationships()->where([\n            $this->foreignKey => $this->getOriginal($this->foreignKey, $this->getAttribute($this->foreignKey)),\n            $this->relatedKey => $this->getOriginal($this->relatedKey, $this->getAttribute($this->relatedKey)),\n        ]);\n    }\n\n    /**\n     * Get the table associated with the model.\n     *\n     * @return string\n     */\n    public function getTable()\n    {\n        if (! isset($this->table)) {\n            $this->setTable(str_replace(\n                '\\\\', '', Str::snake(Str::singular(class_basename($this)))\n            ));\n        }\n\n        return $this->table;\n    }\n\n    /**\n     * Get the foreign key column name.\n     *\n     * @return string\n     */\n    public function getForeignKey()\n    {\n        return $this->foreignKey;\n    }\n\n    /**\n     * Get the \"related key\" column name.\n     *\n     * @return string\n     */\n    public function getRelatedKey()\n    {\n        return $this->relatedKey;\n    }\n\n    /**\n     * Get the \"related key\" column name.\n     *\n     * @return string\n     */\n    public function getOtherKey()\n    {\n        return $this->getRelatedKey();\n    }\n\n    /**\n     * Set the key names for the pivot model instance.\n     *\n     * @param  string  $foreignKey\n     * @param  string  $relatedKey\n     * @return $this\n     */\n    public function setPivotKeys($foreignKey, $relatedKey)\n    {\n        $this->foreignKey = $foreignKey;\n\n        $this->relatedKey = $relatedKey;\n\n        return $this;\n    }\n\n    /**\n     * Determine if the pivot model or given attributes has timestamp attributes.\n     *\n     * @param  array|null  $attributes\n     * @return bool\n     */\n    public function hasTimestampAttributes($attributes = null)\n    {\n        return array_key_exists($this->getCreatedAtColumn(), $attributes ?? $this->attributes);\n    }\n\n    /**\n     * Get the name of the \"created at\" column.\n     *\n     * @return string\n     */\n    public function getCreatedAtColumn()\n    {\n        return $this->pivotParent\n            ? $this->pivotParent->getCreatedAtColumn()\n            : parent::getCreatedAtColumn();\n    }\n\n    /**\n     * Get the name of the \"updated at\" column.\n     *\n     * @return string\n     */\n    public function getUpdatedAtColumn()\n    {\n        return $this->pivotParent\n            ? $this->pivotParent->getUpdatedAtColumn()\n            : parent::getUpdatedAtColumn();\n    }\n\n    /**\n     * Get the queueable identity for the entity.\n     *\n     * @return mixed\n     */\n    public function getQueueableId()\n    {\n        if (isset($this->attributes[$this->getKeyName()])) {\n            return $this->getKey();\n        }\n\n        return sprintf(\n            '%s:%s:%s:%s',\n            $this->foreignKey, $this->getAttribute($this->foreignKey),\n            $this->relatedKey, $this->getAttribute($this->relatedKey)\n        );\n    }\n\n    /**\n     * Get a new query to restore one or more models by their queueable IDs.\n     *\n     * @param  int[]|string[]|string  $ids\n     * @return \\Illuminate\\Database\\Eloquent\\Builder\n     */\n    public function newQueryForRestoration($ids)\n    {\n        if (is_array($ids)) {\n            return $this->newQueryForCollectionRestoration($ids);\n        }\n\n        if (! Str::contains($ids, ':')) {\n            return parent::newQueryForRestoration($ids);\n        }\n\n        $segments = explode(':', $ids);\n\n        return $this->newQueryWithoutScopes()\n            ->where($segments[0], $segments[1])\n            ->where($segments[2], $segments[3]);\n    }\n\n    /**\n     * Get a new query to restore multiple models by their queueable IDs.\n     *\n     * @param  int[]|string[]  $ids\n     * @return \\Illuminate\\Database\\Eloquent\\Builder\n     */\n    protected function newQueryForCollectionRestoration(array $ids)\n    {\n        $ids = array_values($ids);\n\n        if (! Str::contains($ids[0], ':')) {\n            return parent::newQueryForRestoration($ids);\n        }\n\n        $query = $this->newQueryWithoutScopes();\n\n        foreach ($ids as $id) {\n            $segments = explode(':', $id);\n\n            $query->orWhere(function ($query) use ($segments) {\n                return $query->where($segments[0], $segments[1])\n                    ->where($segments[2], $segments[3]);\n            });\n        }\n\n        return $query;\n    }\n\n    /**\n     * Unset all the loaded relations for the instance.\n     *\n     * @return $this\n     */\n    public function unsetRelations()\n    {\n        $this->pivotParent = null;\n        $this->relations = [];\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/Relations/Concerns/CanBeOneOfMany.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent\\Relations\\Concerns;\n\nuse Closure;\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Illuminate\\Database\\Query\\JoinClause;\nuse Illuminate\\Support\\Arr;\nuse Illuminate\\Support\\Str;\nuse InvalidArgumentException;\n\ntrait CanBeOneOfMany\n{\n    /**\n     * Determines whether the relationship is one-of-many.\n     *\n     * @var bool\n     */\n    protected $isOneOfMany = false;\n\n    /**\n     * The name of the relationship.\n     *\n     * @var string\n     */\n    protected $relationName;\n\n    /**\n     * The one of many inner join subselect query builder instance.\n     *\n     * @var \\Illuminate\\Database\\Eloquent\\Builder|null\n     */\n    protected $oneOfManySubQuery;\n\n    /**\n     * Add constraints for inner join subselect for one of many relationships.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $query\n     * @param  string|null  $column\n     * @param  string|null  $aggregate\n     * @return void\n     */\n    abstract public function addOneOfManySubQueryConstraints(Builder $query, $column = null, $aggregate = null);\n\n    /**\n     * Get the columns the determine the relationship groups.\n     *\n     * @return array|string\n     */\n    abstract public function getOneOfManySubQuerySelectColumns();\n\n    /**\n     * Add join query constraints for one of many relationships.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\JoinClause  $join\n     * @return void\n     */\n    abstract public function addOneOfManyJoinSubQueryConstraints(JoinClause $join);\n\n    /**\n     * Indicate that the relation is a single result of a larger one-to-many relationship.\n     *\n     * @param  string|array|null  $column\n     * @param  string|Closure|null  $aggregate\n     * @param  string|null  $relation\n     * @return $this\n     *\n     * @throws \\InvalidArgumentException\n     */\n    public function ofMany($column = 'id', $aggregate = 'MAX', $relation = null)\n    {\n        $this->isOneOfMany = true;\n\n        $this->relationName = $relation ?: $this->getDefaultOneOfManyJoinAlias(\n            $this->guessRelationship()\n        );\n\n        $keyName = $this->query->getModel()->getKeyName();\n\n        $columns = is_string($columns = $column) ? [\n            $column => $aggregate,\n            $keyName => $aggregate,\n        ] : $column;\n\n        if (! array_key_exists($keyName, $columns)) {\n            $columns[$keyName] = 'MAX';\n        }\n\n        if ($aggregate instanceof Closure) {\n            $closure = $aggregate;\n        }\n\n        foreach ($columns as $column => $aggregate) {\n            if (! in_array(strtolower($aggregate), ['min', 'max'])) {\n                throw new InvalidArgumentException(\"Invalid aggregate [{$aggregate}] used within ofMany relation. Available aggregates: MIN, MAX\");\n            }\n\n            $subQuery = $this->newOneOfManySubQuery(\n                $this->getOneOfManySubQuerySelectColumns(),\n                $column, $aggregate\n            );\n\n            if (isset($previous)) {\n                $this->addOneOfManyJoinSubQuery($subQuery, $previous['subQuery'], $previous['column']);\n            }\n\n            if (isset($closure)) {\n                $closure($subQuery);\n            }\n\n            if (! isset($previous)) {\n                $this->oneOfManySubQuery = $subQuery;\n            }\n\n            if (array_key_last($columns) == $column) {\n                $this->addOneOfManyJoinSubQuery($this->query, $subQuery, $column);\n            }\n\n            $previous = [\n                'subQuery' => $subQuery,\n                'column' => $column,\n            ];\n        }\n\n        $this->addConstraints();\n\n        $columns = $this->query->getQuery()->columns;\n\n        if (is_null($columns) || $columns === ['*']) {\n            $this->select([$this->qualifyColumn('*')]);\n        }\n\n        return $this;\n    }\n\n    /**\n     * Indicate that the relation is the latest single result of a larger one-to-many relationship.\n     *\n     * @param  string|array|null  $column\n     * @param  string|Closure|null  $aggregate\n     * @param  string|null  $relation\n     * @return $this\n     */\n    public function latestOfMany($column = 'id', $relation = null)\n    {\n        return $this->ofMany(collect(Arr::wrap($column))->mapWithKeys(function ($column) {\n            return [$column => 'MAX'];\n        })->all(), 'MAX', $relation);\n    }\n\n    /**\n     * Indicate that the relation is the oldest single result of a larger one-to-many relationship.\n     *\n     * @param  string|array|null  $column\n     * @param  string|Closure|null  $aggregate\n     * @param  string|null  $relation\n     * @return $this\n     */\n    public function oldestOfMany($column = 'id', $relation = null)\n    {\n        return $this->ofMany(collect(Arr::wrap($column))->mapWithKeys(function ($column) {\n            return [$column => 'MIN'];\n        })->all(), 'MIN', $relation);\n    }\n\n    /**\n     * Get the default alias for the one of many inner join clause.\n     *\n     * @param  string  $relation\n     * @return string\n     */\n    protected function getDefaultOneOfManyJoinAlias($relation)\n    {\n        return $relation == $this->query->getModel()->getTable()\n            ? $relation.'_of_many'\n            : $relation;\n    }\n\n    /**\n     * Get a new query for the related model, grouping the query by the given column, often the foreign key of the relationship.\n     *\n     * @param  string|array  $groupBy\n     * @param  string|null  $column\n     * @param  string|null  $aggregate\n     * @return \\Illuminate\\Database\\Eloquent\\Builder\n     */\n    protected function newOneOfManySubQuery($groupBy, $column = null, $aggregate = null)\n    {\n        $subQuery = $this->query->getModel()\n            ->newQuery()\n            ->withoutGlobalScopes($this->removedScopes());\n\n        foreach (Arr::wrap($groupBy) as $group) {\n            $subQuery->groupBy($this->qualifyRelatedColumn($group));\n        }\n\n        if (! is_null($column)) {\n            $subQuery->selectRaw($aggregate.'('.$subQuery->getQuery()->grammar->wrap($subQuery->qualifyColumn($column)).') as '.$subQuery->getQuery()->grammar->wrap($column.'_aggregate'));\n        }\n\n        $this->addOneOfManySubQueryConstraints($subQuery, $groupBy, $column, $aggregate);\n\n        return $subQuery;\n    }\n\n    /**\n     * Add the join subquery to the given query on the given column and the relationship's foreign key.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $parent\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $subQuery\n     * @param  string  $on\n     * @return void\n     */\n    protected function addOneOfManyJoinSubQuery(Builder $parent, Builder $subQuery, $on)\n    {\n        $parent->beforeQuery(function ($parent) use ($subQuery, $on) {\n            $subQuery->applyBeforeQueryCallbacks();\n\n            $parent->joinSub($subQuery, $this->relationName, function ($join) use ($on) {\n                $join->on($this->qualifySubSelectColumn($on.'_aggregate'), '=', $this->qualifyRelatedColumn($on));\n\n                $this->addOneOfManyJoinSubQueryConstraints($join, $on);\n            });\n        });\n    }\n\n    /**\n     * Merge the relationship query joins to the given query builder.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $builder\n     * @return void\n     */\n    protected function mergeOneOfManyJoinsTo(Builder $query)\n    {\n        $query->getQuery()->beforeQueryCallbacks = $this->query->getQuery()->beforeQueryCallbacks;\n\n        $query->applyBeforeQueryCallbacks();\n    }\n\n    /**\n     * Get the query builder that will contain the relationship constraints.\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Builder\n     */\n    protected function getRelationQuery()\n    {\n        return $this->isOneOfMany()\n            ? $this->oneOfManySubQuery\n            : $this->query;\n    }\n\n    /**\n     * Get the one of many inner join subselect builder instance.\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Builder|void\n     */\n    public function getOneOfManySubQuery()\n    {\n        return $this->oneOfManySubQuery;\n    }\n\n    /**\n     * Get the qualified column name for the one-of-many relationship using the subselect join query's alias.\n     *\n     * @param  string  $column\n     * @return string\n     */\n    public function qualifySubSelectColumn($column)\n    {\n        return $this->getRelationName().'.'.last(explode('.', $column));\n    }\n\n    /**\n     * Qualify related column using the related table name if it is not already qualified.\n     *\n     * @param  string  $column\n     * @return string\n     */\n    protected function qualifyRelatedColumn($column)\n    {\n        return Str::contains($column, '.') ? $column : $this->query->getModel()->getTable().'.'.$column;\n    }\n\n    /**\n     * Guess the \"hasOne\" relationship's name via backtrace.\n     *\n     * @return string\n     */\n    protected function guessRelationship()\n    {\n        return debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3)[2]['function'];\n    }\n\n    /**\n     * Determine whether the relationship is a one-of-many relationship.\n     *\n     * @return bool\n     */\n    public function isOneOfMany()\n    {\n        return $this->isOneOfMany;\n    }\n\n    /**\n     * Get the name of the relationship.\n     *\n     * @return string\n     */\n    public function getRelationName()\n    {\n        return $this->relationName;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/Relations/Concerns/ComparesRelatedModels.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent\\Relations\\Concerns;\n\nuse Illuminate\\Contracts\\Database\\Eloquent\\SupportsPartialRelations;\nuse Illuminate\\Database\\Eloquent\\Model;\n\ntrait ComparesRelatedModels\n{\n    /**\n     * Determine if the model is the related instance of the relationship.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Model|null  $model\n     * @return bool\n     */\n    public function is($model)\n    {\n        $match = ! is_null($model) &&\n               $this->compareKeys($this->getParentKey(), $this->getRelatedKeyFrom($model)) &&\n               $this->related->getTable() === $model->getTable() &&\n               $this->related->getConnectionName() === $model->getConnectionName();\n\n        if ($match && $this instanceof SupportsPartialRelations && $this->isOneOfMany()) {\n            return $this->query\n                        ->whereKey($model->getKey())\n                        ->exists();\n        }\n\n        return $match;\n    }\n\n    /**\n     * Determine if the model is not the related instance of the relationship.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Model|null  $model\n     * @return bool\n     */\n    public function isNot($model)\n    {\n        return ! $this->is($model);\n    }\n\n    /**\n     * Get the value of the parent model's key.\n     *\n     * @return mixed\n     */\n    abstract public function getParentKey();\n\n    /**\n     * Get the value of the model's related key.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $model\n     * @return mixed\n     */\n    abstract protected function getRelatedKeyFrom(Model $model);\n\n    /**\n     * Compare the parent key with the related key.\n     *\n     * @param  mixed  $parentKey\n     * @param  mixed  $relatedKey\n     * @return bool\n     */\n    protected function compareKeys($parentKey, $relatedKey)\n    {\n        if (empty($parentKey) || empty($relatedKey)) {\n            return false;\n        }\n\n        if (is_int($parentKey) || is_int($relatedKey)) {\n            return (int) $parentKey === (int) $relatedKey;\n        }\n\n        return $parentKey === $relatedKey;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/Relations/Concerns/InteractsWithDictionary.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent\\Relations\\Concerns;\n\nuse BackedEnum;\nuse Doctrine\\Instantiator\\Exception\\InvalidArgumentException;\n\ntrait InteractsWithDictionary\n{\n    /**\n     * Get a dictionary key attribute - casting it to a string if necessary.\n     *\n     * @param  mixed  $attribute\n     * @return mixed\n     *\n     * @throws \\Doctrine\\Instantiator\\Exception\\InvalidArgumentException\n     */\n    protected function getDictionaryKey($attribute)\n    {\n        if (is_object($attribute)) {\n            if (method_exists($attribute, '__toString')) {\n                return $attribute->__toString();\n            }\n\n            if (function_exists('enum_exists') &&\n                $attribute instanceof BackedEnum) {\n                return $attribute->value;\n            }\n\n            throw new InvalidArgumentException('Model attribute value is an object but does not have a __toString method.');\n        }\n\n        return $attribute;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent\\Relations\\Concerns;\n\nuse Illuminate\\Database\\Eloquent\\Collection;\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Database\\Eloquent\\Relations\\Pivot;\nuse Illuminate\\Support\\Collection as BaseCollection;\n\ntrait InteractsWithPivotTable\n{\n    /**\n     * Toggles a model (or models) from the parent.\n     *\n     * Each existing model is detached, and non existing ones are attached.\n     *\n     * @param  mixed  $ids\n     * @param  bool  $touch\n     * @return array\n     */\n    public function toggle($ids, $touch = true)\n    {\n        $changes = [\n            'attached' => [], 'detached' => [],\n        ];\n\n        $records = $this->formatRecordsList($this->parseIds($ids));\n\n        // Next, we will determine which IDs should get removed from the join table by\n        // checking which of the given ID/records is in the list of current records\n        // and removing all of those rows from this \"intermediate\" joining table.\n        $detach = array_values(array_intersect(\n            $this->newPivotQuery()->pluck($this->relatedPivotKey)->all(),\n            array_keys($records)\n        ));\n\n        if (count($detach) > 0) {\n            $this->detach($detach, false);\n\n            $changes['detached'] = $this->castKeys($detach);\n        }\n\n        // Finally, for all of the records which were not \"detached\", we'll attach the\n        // records into the intermediate table. Then, we will add those attaches to\n        // this change list and get ready to return these results to the callers.\n        $attach = array_diff_key($records, array_flip($detach));\n\n        if (count($attach) > 0) {\n            $this->attach($attach, [], false);\n\n            $changes['attached'] = array_keys($attach);\n        }\n\n        // Once we have finished attaching or detaching the records, we will see if we\n        // have done any attaching or detaching, and if we have we will touch these\n        // relationships if they are configured to touch on any database updates.\n        if ($touch && (count($changes['attached']) ||\n                       count($changes['detached']))) {\n            $this->touchIfTouching();\n        }\n\n        return $changes;\n    }\n\n    /**\n     * Sync the intermediate tables with a list of IDs without detaching.\n     *\n     * @param  \\Illuminate\\Support\\Collection|\\Illuminate\\Database\\Eloquent\\Model|array  $ids\n     * @return array\n     */\n    public function syncWithoutDetaching($ids)\n    {\n        return $this->sync($ids, false);\n    }\n\n    /**\n     * Sync the intermediate tables with a list of IDs or collection of models.\n     *\n     * @param  \\Illuminate\\Support\\Collection|\\Illuminate\\Database\\Eloquent\\Model|array  $ids\n     * @param  bool  $detaching\n     * @return array\n     */\n    public function sync($ids, $detaching = true)\n    {\n        $changes = [\n            'attached' => [], 'detached' => [], 'updated' => [],\n        ];\n\n        // First we need to attach any of the associated models that are not currently\n        // in this joining table. We'll spin through the given IDs, checking to see\n        // if they exist in the array of current ones, and if not we will insert.\n        $current = $this->getCurrentlyAttachedPivots()\n                        ->pluck($this->relatedPivotKey)->all();\n\n        $detach = array_diff($current, array_keys(\n            $records = $this->formatRecordsList($this->parseIds($ids))\n        ));\n\n        // Next, we will take the differences of the currents and given IDs and detach\n        // all of the entities that exist in the \"current\" array but are not in the\n        // array of the new IDs given to the method which will complete the sync.\n        if ($detaching && count($detach) > 0) {\n            $this->detach($detach);\n\n            $changes['detached'] = $this->castKeys($detach);\n        }\n\n        // Now we are finally ready to attach the new records. Note that we'll disable\n        // touching until after the entire operation is complete so we don't fire a\n        // ton of touch operations until we are totally done syncing the records.\n        $changes = array_merge(\n            $changes, $this->attachNew($records, $current, false)\n        );\n\n        // Once we have finished attaching or detaching the records, we will see if we\n        // have done any attaching or detaching, and if we have we will touch these\n        // relationships if they are configured to touch on any database updates.\n        if (count($changes['attached']) ||\n            count($changes['updated']) ||\n            count($changes['detached'])) {\n            $this->touchIfTouching();\n        }\n\n        return $changes;\n    }\n\n    /**\n     * Sync the intermediate tables with a list of IDs or collection of models with the given pivot values.\n     *\n     * @param  \\Illuminate\\Support\\Collection|\\Illuminate\\Database\\Eloquent\\Model|array  $ids\n     * @param  array  $values\n     * @param  bool  $detaching\n     * @return array\n     */\n    public function syncWithPivotValues($ids, array $values, bool $detaching = true)\n    {\n        return $this->sync(collect($this->parseIds($ids))->mapWithKeys(function ($id) use ($values) {\n            return [$id => $values];\n        }), $detaching);\n    }\n\n    /**\n     * Format the sync / toggle record list so that it is keyed by ID.\n     *\n     * @param  array  $records\n     * @return array\n     */\n    protected function formatRecordsList(array $records)\n    {\n        return collect($records)->mapWithKeys(function ($attributes, $id) {\n            if (! is_array($attributes)) {\n                [$id, $attributes] = [$attributes, []];\n            }\n\n            return [$id => $attributes];\n        })->all();\n    }\n\n    /**\n     * Attach all of the records that aren't in the given current records.\n     *\n     * @param  array  $records\n     * @param  array  $current\n     * @param  bool  $touch\n     * @return array\n     */\n    protected function attachNew(array $records, array $current, $touch = true)\n    {\n        $changes = ['attached' => [], 'updated' => []];\n\n        foreach ($records as $id => $attributes) {\n            // If the ID is not in the list of existing pivot IDs, we will insert a new pivot\n            // record, otherwise, we will just update this existing record on this joining\n            // table, so that the developers will easily update these records pain free.\n            if (! in_array($id, $current)) {\n                $this->attach($id, $attributes, $touch);\n\n                $changes['attached'][] = $this->castKey($id);\n            }\n\n            // Now we'll try to update an existing pivot record with the attributes that were\n            // given to the method. If the model is actually updated we will add it to the\n            // list of updated pivot records so we return them back out to the consumer.\n            elseif (count($attributes) > 0 &&\n                $this->updateExistingPivot($id, $attributes, $touch)) {\n                $changes['updated'][] = $this->castKey($id);\n            }\n        }\n\n        return $changes;\n    }\n\n    /**\n     * Update an existing pivot record on the table.\n     *\n     * @param  mixed  $id\n     * @param  array  $attributes\n     * @param  bool  $touch\n     * @return int\n     */\n    public function updateExistingPivot($id, array $attributes, $touch = true)\n    {\n        if ($this->using &&\n            empty($this->pivotWheres) &&\n            empty($this->pivotWhereIns) &&\n            empty($this->pivotWhereNulls)) {\n            return $this->updateExistingPivotUsingCustomClass($id, $attributes, $touch);\n        }\n\n        if (in_array($this->updatedAt(), $this->pivotColumns)) {\n            $attributes = $this->addTimestampsToAttachment($attributes, true);\n        }\n\n        $updated = $this->newPivotStatementForId($this->parseId($id))->update(\n            $this->castAttributes($attributes)\n        );\n\n        if ($touch) {\n            $this->touchIfTouching();\n        }\n\n        return $updated;\n    }\n\n    /**\n     * Update an existing pivot record on the table via a custom class.\n     *\n     * @param  mixed  $id\n     * @param  array  $attributes\n     * @param  bool  $touch\n     * @return int\n     */\n    protected function updateExistingPivotUsingCustomClass($id, array $attributes, $touch)\n    {\n        $pivot = $this->getCurrentlyAttachedPivots()\n                    ->where($this->foreignPivotKey, $this->parent->{$this->parentKey})\n                    ->where($this->relatedPivotKey, $this->parseId($id))\n                    ->first();\n\n        $updated = $pivot ? $pivot->fill($attributes)->isDirty() : false;\n\n        if ($updated) {\n            $pivot->save();\n        }\n\n        if ($touch) {\n            $this->touchIfTouching();\n        }\n\n        return (int) $updated;\n    }\n\n    /**\n     * Attach a model to the parent.\n     *\n     * @param  mixed  $id\n     * @param  array  $attributes\n     * @param  bool  $touch\n     * @return void\n     */\n    public function attach($id, array $attributes = [], $touch = true)\n    {\n        if ($this->using) {\n            $this->attachUsingCustomClass($id, $attributes);\n        } else {\n            // Here we will insert the attachment records into the pivot table. Once we have\n            // inserted the records, we will touch the relationships if necessary and the\n            // function will return. We can parse the IDs before inserting the records.\n            $this->newPivotStatement()->insert($this->formatAttachRecords(\n                $this->parseIds($id), $attributes\n            ));\n        }\n\n        if ($touch) {\n            $this->touchIfTouching();\n        }\n    }\n\n    /**\n     * Attach a model to the parent using a custom class.\n     *\n     * @param  mixed  $id\n     * @param  array  $attributes\n     * @return void\n     */\n    protected function attachUsingCustomClass($id, array $attributes)\n    {\n        $records = $this->formatAttachRecords(\n            $this->parseIds($id), $attributes\n        );\n\n        foreach ($records as $record) {\n            $this->newPivot($record, false)->save();\n        }\n    }\n\n    /**\n     * Create an array of records to insert into the pivot table.\n     *\n     * @param  array  $ids\n     * @param  array  $attributes\n     * @return array\n     */\n    protected function formatAttachRecords($ids, array $attributes)\n    {\n        $records = [];\n\n        $hasTimestamps = ($this->hasPivotColumn($this->createdAt()) ||\n                  $this->hasPivotColumn($this->updatedAt()));\n\n        // To create the attachment records, we will simply spin through the IDs given\n        // and create a new record to insert for each ID. Each ID may actually be a\n        // key in the array, with extra attributes to be placed in other columns.\n        foreach ($ids as $key => $value) {\n            $records[] = $this->formatAttachRecord(\n                $key, $value, $attributes, $hasTimestamps\n            );\n        }\n\n        return $records;\n    }\n\n    /**\n     * Create a full attachment record payload.\n     *\n     * @param  int  $key\n     * @param  mixed  $value\n     * @param  array  $attributes\n     * @param  bool  $hasTimestamps\n     * @return array\n     */\n    protected function formatAttachRecord($key, $value, $attributes, $hasTimestamps)\n    {\n        [$id, $attributes] = $this->extractAttachIdAndAttributes($key, $value, $attributes);\n\n        return array_merge(\n            $this->baseAttachRecord($id, $hasTimestamps), $this->castAttributes($attributes)\n        );\n    }\n\n    /**\n     * Get the attach record ID and extra attributes.\n     *\n     * @param  mixed  $key\n     * @param  mixed  $value\n     * @param  array  $attributes\n     * @return array\n     */\n    protected function extractAttachIdAndAttributes($key, $value, array $attributes)\n    {\n        return is_array($value)\n                    ? [$key, array_merge($value, $attributes)]\n                    : [$value, $attributes];\n    }\n\n    /**\n     * Create a new pivot attachment record.\n     *\n     * @param  int  $id\n     * @param  bool  $timed\n     * @return array\n     */\n    protected function baseAttachRecord($id, $timed)\n    {\n        $record[$this->relatedPivotKey] = $id;\n\n        $record[$this->foreignPivotKey] = $this->parent->{$this->parentKey};\n\n        // If the record needs to have creation and update timestamps, we will make\n        // them by calling the parent model's \"freshTimestamp\" method which will\n        // provide us with a fresh timestamp in this model's preferred format.\n        if ($timed) {\n            $record = $this->addTimestampsToAttachment($record);\n        }\n\n        foreach ($this->pivotValues as $value) {\n            $record[$value['column']] = $value['value'];\n        }\n\n        return $record;\n    }\n\n    /**\n     * Set the creation and update timestamps on an attach record.\n     *\n     * @param  array  $record\n     * @param  bool  $exists\n     * @return array\n     */\n    protected function addTimestampsToAttachment(array $record, $exists = false)\n    {\n        $fresh = $this->parent->freshTimestamp();\n\n        if ($this->using) {\n            $pivotModel = new $this->using;\n\n            $fresh = $fresh->format($pivotModel->getDateFormat());\n        }\n\n        if (! $exists && $this->hasPivotColumn($this->createdAt())) {\n            $record[$this->createdAt()] = $fresh;\n        }\n\n        if ($this->hasPivotColumn($this->updatedAt())) {\n            $record[$this->updatedAt()] = $fresh;\n        }\n\n        return $record;\n    }\n\n    /**\n     * Determine whether the given column is defined as a pivot column.\n     *\n     * @param  string  $column\n     * @return bool\n     */\n    public function hasPivotColumn($column)\n    {\n        return in_array($column, $this->pivotColumns);\n    }\n\n    /**\n     * Detach models from the relationship.\n     *\n     * @param  mixed  $ids\n     * @param  bool  $touch\n     * @return int\n     */\n    public function detach($ids = null, $touch = true)\n    {\n        if ($this->using &&\n            ! empty($ids) &&\n            empty($this->pivotWheres) &&\n            empty($this->pivotWhereIns) &&\n            empty($this->pivotWhereNulls)) {\n            $results = $this->detachUsingCustomClass($ids);\n        } else {\n            $query = $this->newPivotQuery();\n\n            // If associated IDs were passed to the method we will only delete those\n            // associations, otherwise all of the association ties will be broken.\n            // We'll return the numbers of affected rows when we do the deletes.\n            if (! is_null($ids)) {\n                $ids = $this->parseIds($ids);\n\n                if (empty($ids)) {\n                    return 0;\n                }\n\n                $query->whereIn($this->getQualifiedRelatedPivotKeyName(), (array) $ids);\n            }\n\n            // Once we have all of the conditions set on the statement, we are ready\n            // to run the delete on the pivot table. Then, if the touch parameter\n            // is true, we will go ahead and touch all related models to sync.\n            $results = $query->delete();\n        }\n\n        if ($touch) {\n            $this->touchIfTouching();\n        }\n\n        return $results;\n    }\n\n    /**\n     * Detach models from the relationship using a custom class.\n     *\n     * @param  mixed  $ids\n     * @return int\n     */\n    protected function detachUsingCustomClass($ids)\n    {\n        $results = 0;\n\n        foreach ($this->parseIds($ids) as $id) {\n            $results += $this->newPivot([\n                $this->foreignPivotKey => $this->parent->{$this->parentKey},\n                $this->relatedPivotKey => $id,\n            ], true)->delete();\n        }\n\n        return $results;\n    }\n\n    /**\n     * Get the pivot models that are currently attached.\n     *\n     * @return \\Illuminate\\Support\\Collection\n     */\n    protected function getCurrentlyAttachedPivots()\n    {\n        return $this->newPivotQuery()->get()->map(function ($record) {\n            $class = $this->using ?: Pivot::class;\n\n            $pivot = $class::fromRawAttributes($this->parent, (array) $record, $this->getTable(), true);\n\n            return $pivot->setPivotKeys($this->foreignPivotKey, $this->relatedPivotKey);\n        });\n    }\n\n    /**\n     * Create a new pivot model instance.\n     *\n     * @param  array  $attributes\n     * @param  bool  $exists\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\Pivot\n     */\n    public function newPivot(array $attributes = [], $exists = false)\n    {\n        $pivot = $this->related->newPivot(\n            $this->parent, $attributes, $this->table, $exists, $this->using\n        );\n\n        return $pivot->setPivotKeys($this->foreignPivotKey, $this->relatedPivotKey);\n    }\n\n    /**\n     * Create a new existing pivot model instance.\n     *\n     * @param  array  $attributes\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\Pivot\n     */\n    public function newExistingPivot(array $attributes = [])\n    {\n        return $this->newPivot($attributes, true);\n    }\n\n    /**\n     * Get a new plain query builder for the pivot table.\n     *\n     * @return \\Illuminate\\Database\\Query\\Builder\n     */\n    public function newPivotStatement()\n    {\n        return $this->query->getQuery()->newQuery()->from($this->table);\n    }\n\n    /**\n     * Get a new pivot statement for a given \"other\" ID.\n     *\n     * @param  mixed  $id\n     * @return \\Illuminate\\Database\\Query\\Builder\n     */\n    public function newPivotStatementForId($id)\n    {\n        return $this->newPivotQuery()->whereIn($this->relatedPivotKey, $this->parseIds($id));\n    }\n\n    /**\n     * Create a new query builder for the pivot table.\n     *\n     * @return \\Illuminate\\Database\\Query\\Builder\n     */\n    public function newPivotQuery()\n    {\n        $query = $this->newPivotStatement();\n\n        foreach ($this->pivotWheres as $arguments) {\n            $query->where(...$arguments);\n        }\n\n        foreach ($this->pivotWhereIns as $arguments) {\n            $query->whereIn(...$arguments);\n        }\n\n        foreach ($this->pivotWhereNulls as $arguments) {\n            $query->whereNull(...$arguments);\n        }\n\n        return $query->where($this->getQualifiedForeignPivotKeyName(), $this->parent->{$this->parentKey});\n    }\n\n    /**\n     * Set the columns on the pivot table to retrieve.\n     *\n     * @param  array|mixed  $columns\n     * @return $this\n     */\n    public function withPivot($columns)\n    {\n        $this->pivotColumns = array_merge(\n            $this->pivotColumns, is_array($columns) ? $columns : func_get_args()\n        );\n\n        return $this;\n    }\n\n    /**\n     * Get all of the IDs from the given mixed value.\n     *\n     * @param  mixed  $value\n     * @return array\n     */\n    protected function parseIds($value)\n    {\n        if ($value instanceof Model) {\n            return [$value->{$this->relatedKey}];\n        }\n\n        if ($value instanceof Collection) {\n            return $value->pluck($this->relatedKey)->all();\n        }\n\n        if ($value instanceof BaseCollection) {\n            return $value->toArray();\n        }\n\n        return (array) $value;\n    }\n\n    /**\n     * Get the ID from the given mixed value.\n     *\n     * @param  mixed  $value\n     * @return mixed\n     */\n    protected function parseId($value)\n    {\n        return $value instanceof Model ? $value->{$this->relatedKey} : $value;\n    }\n\n    /**\n     * Cast the given keys to integers if they are numeric and string otherwise.\n     *\n     * @param  array  $keys\n     * @return array\n     */\n    protected function castKeys(array $keys)\n    {\n        return array_map(function ($v) {\n            return $this->castKey($v);\n        }, $keys);\n    }\n\n    /**\n     * Cast the given key to convert to primary key type.\n     *\n     * @param  mixed  $key\n     * @return mixed\n     */\n    protected function castKey($key)\n    {\n        return $this->getTypeSwapValue(\n            $this->related->getKeyType(),\n            $key\n        );\n    }\n\n    /**\n     * Cast the given pivot attributes.\n     *\n     * @param  array  $attributes\n     * @return array\n     */\n    protected function castAttributes($attributes)\n    {\n        return $this->using\n                    ? $this->newPivot()->fill($attributes)->getAttributes()\n                    : $attributes;\n    }\n\n    /**\n     * Converts a given value to a given type value.\n     *\n     * @param  string  $type\n     * @param  mixed  $value\n     * @return mixed\n     */\n    protected function getTypeSwapValue($type, $value)\n    {\n        switch (strtolower($type)) {\n            case 'int':\n            case 'integer':\n                return (int) $value;\n            case 'real':\n            case 'float':\n            case 'double':\n                return (float) $value;\n            case 'string':\n                return (string) $value;\n            default:\n                return $value;\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/Relations/Concerns/SupportsDefaultModels.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent\\Relations\\Concerns;\n\nuse Illuminate\\Database\\Eloquent\\Model;\n\ntrait SupportsDefaultModels\n{\n    /**\n     * Indicates if a default model instance should be used.\n     *\n     * Alternatively, may be a Closure or array.\n     *\n     * @var \\Closure|array|bool\n     */\n    protected $withDefault;\n\n    /**\n     * Make a new related instance for the given model.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $parent\n     * @return \\Illuminate\\Database\\Eloquent\\Model\n     */\n    abstract protected function newRelatedInstanceFor(Model $parent);\n\n    /**\n     * Return a new model instance in case the relationship does not exist.\n     *\n     * @param  \\Closure|array|bool  $callback\n     * @return $this\n     */\n    public function withDefault($callback = true)\n    {\n        $this->withDefault = $callback;\n\n        return $this;\n    }\n\n    /**\n     * Get the default value for this relation.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $parent\n     * @return \\Illuminate\\Database\\Eloquent\\Model|null\n     */\n    protected function getDefaultFor(Model $parent)\n    {\n        if (! $this->withDefault) {\n            return;\n        }\n\n        $instance = $this->newRelatedInstanceFor($parent);\n\n        if (is_callable($this->withDefault)) {\n            return call_user_func($this->withDefault, $instance, $parent) ?: $instance;\n        }\n\n        if (is_array($this->withDefault)) {\n            $instance->forceFill($this->withDefault);\n        }\n\n        return $instance;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/Relations/HasMany.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent\\Relations;\n\nuse Illuminate\\Database\\Eloquent\\Collection;\n\nclass HasMany extends HasOneOrMany\n{\n    /**\n     * Get the results of the relationship.\n     *\n     * @return mixed\n     */\n    public function getResults()\n    {\n        return ! is_null($this->getParentKey())\n                ? $this->query->get()\n                : $this->related->newCollection();\n    }\n\n    /**\n     * Initialize the relation on a set of models.\n     *\n     * @param  array  $models\n     * @param  string  $relation\n     * @return array\n     */\n    public function initRelation(array $models, $relation)\n    {\n        foreach ($models as $model) {\n            $model->setRelation($relation, $this->related->newCollection());\n        }\n\n        return $models;\n    }\n\n    /**\n     * Match the eagerly loaded results to their parents.\n     *\n     * @param  array  $models\n     * @param  \\Illuminate\\Database\\Eloquent\\Collection  $results\n     * @param  string  $relation\n     * @return array\n     */\n    public function match(array $models, Collection $results, $relation)\n    {\n        return $this->matchMany($models, $results, $relation);\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/Relations/HasManyThrough.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent\\Relations;\n\nuse Illuminate\\Contracts\\Support\\Arrayable;\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Illuminate\\Database\\Eloquent\\Collection;\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Database\\Eloquent\\ModelNotFoundException;\nuse Illuminate\\Database\\Eloquent\\Relations\\Concerns\\InteractsWithDictionary;\nuse Illuminate\\Database\\Eloquent\\SoftDeletes;\n\nclass HasManyThrough extends Relation\n{\n    use InteractsWithDictionary;\n\n    /**\n     * The \"through\" parent model instance.\n     *\n     * @var \\Illuminate\\Database\\Eloquent\\Model\n     */\n    protected $throughParent;\n\n    /**\n     * The far parent model instance.\n     *\n     * @var \\Illuminate\\Database\\Eloquent\\Model\n     */\n    protected $farParent;\n\n    /**\n     * The near key on the relationship.\n     *\n     * @var string\n     */\n    protected $firstKey;\n\n    /**\n     * The far key on the relationship.\n     *\n     * @var string\n     */\n    protected $secondKey;\n\n    /**\n     * The local key on the relationship.\n     *\n     * @var string\n     */\n    protected $localKey;\n\n    /**\n     * The local key on the intermediary model.\n     *\n     * @var string\n     */\n    protected $secondLocalKey;\n\n    /**\n     * Create a new has many through relationship instance.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $query\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $farParent\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $throughParent\n     * @param  string  $firstKey\n     * @param  string  $secondKey\n     * @param  string  $localKey\n     * @param  string  $secondLocalKey\n     * @return void\n     */\n    public function __construct(Builder $query, Model $farParent, Model $throughParent, $firstKey, $secondKey, $localKey, $secondLocalKey)\n    {\n        $this->localKey = $localKey;\n        $this->firstKey = $firstKey;\n        $this->secondKey = $secondKey;\n        $this->farParent = $farParent;\n        $this->throughParent = $throughParent;\n        $this->secondLocalKey = $secondLocalKey;\n\n        parent::__construct($query, $throughParent);\n    }\n\n    /**\n     * Set the base constraints on the relation query.\n     *\n     * @return void\n     */\n    public function addConstraints()\n    {\n        $localValue = $this->farParent[$this->localKey];\n\n        $this->performJoin();\n\n        if (static::$constraints) {\n            $this->query->where($this->getQualifiedFirstKeyName(), '=', $localValue);\n        }\n    }\n\n    /**\n     * Set the join clause on the query.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder|null  $query\n     * @return void\n     */\n    protected function performJoin(Builder $query = null)\n    {\n        $query = $query ?: $this->query;\n\n        $farKey = $this->getQualifiedFarKeyName();\n\n        $query->join($this->throughParent->getTable(), $this->getQualifiedParentKeyName(), '=', $farKey);\n\n        if ($this->throughParentSoftDeletes()) {\n            $query->withGlobalScope('SoftDeletableHasManyThrough', function ($query) {\n                $query->whereNull($this->throughParent->getQualifiedDeletedAtColumn());\n            });\n        }\n    }\n\n    /**\n     * Get the fully qualified parent key name.\n     *\n     * @return string\n     */\n    public function getQualifiedParentKeyName()\n    {\n        return $this->parent->qualifyColumn($this->secondLocalKey);\n    }\n\n    /**\n     * Determine whether \"through\" parent of the relation uses Soft Deletes.\n     *\n     * @return bool\n     */\n    public function throughParentSoftDeletes()\n    {\n        return in_array(SoftDeletes::class, class_uses_recursive($this->throughParent));\n    }\n\n    /**\n     * Indicate that trashed \"through\" parents should be included in the query.\n     *\n     * @return $this\n     */\n    public function withTrashedParents()\n    {\n        $this->query->withoutGlobalScope('SoftDeletableHasManyThrough');\n\n        return $this;\n    }\n\n    /**\n     * Set the constraints for an eager load of the relation.\n     *\n     * @param  array  $models\n     * @return void\n     */\n    public function addEagerConstraints(array $models)\n    {\n        $whereIn = $this->whereInMethod($this->farParent, $this->localKey);\n\n        $this->query->{$whereIn}(\n            $this->getQualifiedFirstKeyName(), $this->getKeys($models, $this->localKey)\n        );\n    }\n\n    /**\n     * Initialize the relation on a set of models.\n     *\n     * @param  array  $models\n     * @param  string  $relation\n     * @return array\n     */\n    public function initRelation(array $models, $relation)\n    {\n        foreach ($models as $model) {\n            $model->setRelation($relation, $this->related->newCollection());\n        }\n\n        return $models;\n    }\n\n    /**\n     * Match the eagerly loaded results to their parents.\n     *\n     * @param  array  $models\n     * @param  \\Illuminate\\Database\\Eloquent\\Collection  $results\n     * @param  string  $relation\n     * @return array\n     */\n    public function match(array $models, Collection $results, $relation)\n    {\n        $dictionary = $this->buildDictionary($results);\n\n        // Once we have the dictionary we can simply spin through the parent models to\n        // link them up with their children using the keyed dictionary to make the\n        // matching very convenient and easy work. Then we'll just return them.\n        foreach ($models as $model) {\n            if (isset($dictionary[$key = $this->getDictionaryKey($model->getAttribute($this->localKey))])) {\n                $model->setRelation(\n                    $relation, $this->related->newCollection($dictionary[$key])\n                );\n            }\n        }\n\n        return $models;\n    }\n\n    /**\n     * Build model dictionary keyed by the relation's foreign key.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Collection  $results\n     * @return array\n     */\n    protected function buildDictionary(Collection $results)\n    {\n        $dictionary = [];\n\n        // First we will create a dictionary of models keyed by the foreign key of the\n        // relationship as this will allow us to quickly access all of the related\n        // models without having to do nested looping which will be quite slow.\n        foreach ($results as $result) {\n            $dictionary[$result->laravel_through_key][] = $result;\n        }\n\n        return $dictionary;\n    }\n\n    /**\n     * Get the first related model record matching the attributes or instantiate it.\n     *\n     * @param  array  $attributes\n     * @return \\Illuminate\\Database\\Eloquent\\Model\n     */\n    public function firstOrNew(array $attributes)\n    {\n        if (is_null($instance = $this->where($attributes)->first())) {\n            $instance = $this->related->newInstance($attributes);\n        }\n\n        return $instance;\n    }\n\n    /**\n     * Create or update a related record matching the attributes, and fill it with values.\n     *\n     * @param  array  $attributes\n     * @param  array  $values\n     * @return \\Illuminate\\Database\\Eloquent\\Model\n     */\n    public function updateOrCreate(array $attributes, array $values = [])\n    {\n        $instance = $this->firstOrNew($attributes);\n\n        $instance->fill($values)->save();\n\n        return $instance;\n    }\n\n    /**\n     * Add a basic where clause to the query, and return the first result.\n     *\n     * @param  \\Closure|string|array  $column\n     * @param  mixed  $operator\n     * @param  mixed  $value\n     * @param  string  $boolean\n     * @return \\Illuminate\\Database\\Eloquent\\Model|static\n     */\n    public function firstWhere($column, $operator = null, $value = null, $boolean = 'and')\n    {\n        return $this->where($column, $operator, $value, $boolean)->first();\n    }\n\n    /**\n     * Execute the query and get the first related model.\n     *\n     * @param  array  $columns\n     * @return mixed\n     */\n    public function first($columns = ['*'])\n    {\n        $results = $this->take(1)->get($columns);\n\n        return count($results) > 0 ? $results->first() : null;\n    }\n\n    /**\n     * Execute the query and get the first result or throw an exception.\n     *\n     * @param  array  $columns\n     * @return \\Illuminate\\Database\\Eloquent\\Model|static\n     *\n     * @throws \\Illuminate\\Database\\Eloquent\\ModelNotFoundException\n     */\n    public function firstOrFail($columns = ['*'])\n    {\n        if (! is_null($model = $this->first($columns))) {\n            return $model;\n        }\n\n        throw (new ModelNotFoundException)->setModel(get_class($this->related));\n    }\n\n    /**\n     * Find a related model by its primary key.\n     *\n     * @param  mixed  $id\n     * @param  array  $columns\n     * @return \\Illuminate\\Database\\Eloquent\\Model|\\Illuminate\\Database\\Eloquent\\Collection|null\n     */\n    public function find($id, $columns = ['*'])\n    {\n        if (is_array($id) || $id instanceof Arrayable) {\n            return $this->findMany($id, $columns);\n        }\n\n        return $this->where(\n            $this->getRelated()->getQualifiedKeyName(), '=', $id\n        )->first($columns);\n    }\n\n    /**\n     * Find multiple related models by their primary keys.\n     *\n     * @param  \\Illuminate\\Contracts\\Support\\Arrayable|array  $ids\n     * @param  array  $columns\n     * @return \\Illuminate\\Database\\Eloquent\\Collection\n     */\n    public function findMany($ids, $columns = ['*'])\n    {\n        $ids = $ids instanceof Arrayable ? $ids->toArray() : $ids;\n\n        if (empty($ids)) {\n            return $this->getRelated()->newCollection();\n        }\n\n        return $this->whereIn(\n            $this->getRelated()->getQualifiedKeyName(), $ids\n        )->get($columns);\n    }\n\n    /**\n     * Find a related model by its primary key or throw an exception.\n     *\n     * @param  mixed  $id\n     * @param  array  $columns\n     * @return \\Illuminate\\Database\\Eloquent\\Model|\\Illuminate\\Database\\Eloquent\\Collection\n     *\n     * @throws \\Illuminate\\Database\\Eloquent\\ModelNotFoundException\n     */\n    public function findOrFail($id, $columns = ['*'])\n    {\n        $result = $this->find($id, $columns);\n\n        $id = $id instanceof Arrayable ? $id->toArray() : $id;\n\n        if (is_array($id)) {\n            if (count($result) === count(array_unique($id))) {\n                return $result;\n            }\n        } elseif (! is_null($result)) {\n            return $result;\n        }\n\n        throw (new ModelNotFoundException)->setModel(get_class($this->related), $id);\n    }\n\n    /**\n     * Get the results of the relationship.\n     *\n     * @return mixed\n     */\n    public function getResults()\n    {\n        return ! is_null($this->farParent->{$this->localKey})\n                ? $this->get()\n                : $this->related->newCollection();\n    }\n\n    /**\n     * Execute the query as a \"select\" statement.\n     *\n     * @param  array  $columns\n     * @return \\Illuminate\\Database\\Eloquent\\Collection\n     */\n    public function get($columns = ['*'])\n    {\n        $builder = $this->prepareQueryBuilder($columns);\n\n        $models = $builder->getModels();\n\n        // If we actually found models we will also eager load any relationships that\n        // have been specified as needing to be eager loaded. This will solve the\n        // n + 1 query problem for the developer and also increase performance.\n        if (count($models) > 0) {\n            $models = $builder->eagerLoadRelations($models);\n        }\n\n        return $this->related->newCollection($models);\n    }\n\n    /**\n     * Get a paginator for the \"select\" statement.\n     *\n     * @param  int|null  $perPage\n     * @param  array  $columns\n     * @param  string  $pageName\n     * @param  int  $page\n     * @return \\Illuminate\\Contracts\\Pagination\\LengthAwarePaginator\n     */\n    public function paginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null)\n    {\n        $this->query->addSelect($this->shouldSelect($columns));\n\n        return $this->query->paginate($perPage, $columns, $pageName, $page);\n    }\n\n    /**\n     * Paginate the given query into a simple paginator.\n     *\n     * @param  int|null  $perPage\n     * @param  array  $columns\n     * @param  string  $pageName\n     * @param  int|null  $page\n     * @return \\Illuminate\\Contracts\\Pagination\\Paginator\n     */\n    public function simplePaginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null)\n    {\n        $this->query->addSelect($this->shouldSelect($columns));\n\n        return $this->query->simplePaginate($perPage, $columns, $pageName, $page);\n    }\n\n    /**\n     * Paginate the given query into a cursor paginator.\n     *\n     * @param  int|null  $perPage\n     * @param  array  $columns\n     * @param  string  $cursorName\n     * @param  string|null  $cursor\n     * @return \\Illuminate\\Contracts\\Pagination\\CursorPaginator\n     */\n    public function cursorPaginate($perPage = null, $columns = ['*'], $cursorName = 'cursor', $cursor = null)\n    {\n        $this->query->addSelect($this->shouldSelect($columns));\n\n        return $this->query->cursorPaginate($perPage, $columns, $cursorName, $cursor);\n    }\n\n    /**\n     * Set the select clause for the relation query.\n     *\n     * @param  array  $columns\n     * @return array\n     */\n    protected function shouldSelect(array $columns = ['*'])\n    {\n        if ($columns == ['*']) {\n            $columns = [$this->related->getTable().'.*'];\n        }\n\n        return array_merge($columns, [$this->getQualifiedFirstKeyName().' as laravel_through_key']);\n    }\n\n    /**\n     * Chunk the results of the query.\n     *\n     * @param  int  $count\n     * @param  callable  $callback\n     * @return bool\n     */\n    public function chunk($count, callable $callback)\n    {\n        return $this->prepareQueryBuilder()->chunk($count, $callback);\n    }\n\n    /**\n     * Chunk the results of a query by comparing numeric IDs.\n     *\n     * @param  int  $count\n     * @param  callable  $callback\n     * @param  string|null  $column\n     * @param  string|null  $alias\n     * @return bool\n     */\n    public function chunkById($count, callable $callback, $column = null, $alias = null)\n    {\n        $column = $column ?? $this->getRelated()->getQualifiedKeyName();\n\n        $alias = $alias ?? $this->getRelated()->getKeyName();\n\n        return $this->prepareQueryBuilder()->chunkById($count, $callback, $column, $alias);\n    }\n\n    /**\n     * Get a generator for the given query.\n     *\n     * @return \\Generator\n     */\n    public function cursor()\n    {\n        return $this->prepareQueryBuilder()->cursor();\n    }\n\n    /**\n     * Execute a callback over each item while chunking.\n     *\n     * @param  callable  $callback\n     * @param  int  $count\n     * @return bool\n     */\n    public function each(callable $callback, $count = 1000)\n    {\n        return $this->chunk($count, function ($results) use ($callback) {\n            foreach ($results as $key => $value) {\n                if ($callback($value, $key) === false) {\n                    return false;\n                }\n            }\n        });\n    }\n\n    /**\n     * Query lazily, by chunks of the given size.\n     *\n     * @param  int  $chunkSize\n     * @return \\Illuminate\\Support\\LazyCollection\n     */\n    public function lazy($chunkSize = 1000)\n    {\n        return $this->prepareQueryBuilder()->lazy($chunkSize);\n    }\n\n    /**\n     * Query lazily, by chunking the results of a query by comparing IDs.\n     *\n     * @param  int  $chunkSize\n     * @param  string|null  $column\n     * @param  string|null  $alias\n     * @return \\Illuminate\\Support\\LazyCollection\n     */\n    public function lazyById($chunkSize = 1000, $column = null, $alias = null)\n    {\n        $column = $column ?? $this->getRelated()->getQualifiedKeyName();\n\n        $alias = $alias ?? $this->getRelated()->getKeyName();\n\n        return $this->prepareQueryBuilder()->lazyById($chunkSize, $column, $alias);\n    }\n\n    /**\n     * Prepare the query builder for query execution.\n     *\n     * @param  array  $columns\n     * @return \\Illuminate\\Database\\Eloquent\\Builder\n     */\n    protected function prepareQueryBuilder($columns = ['*'])\n    {\n        $builder = $this->query->applyScopes();\n\n        return $builder->addSelect(\n            $this->shouldSelect($builder->getQuery()->columns ? [] : $columns)\n        );\n    }\n\n    /**\n     * Add the constraints for a relationship query.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $query\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $parentQuery\n     * @param  array|mixed  $columns\n     * @return \\Illuminate\\Database\\Eloquent\\Builder\n     */\n    public function getRelationExistenceQuery(Builder $query, Builder $parentQuery, $columns = ['*'])\n    {\n        if ($parentQuery->getQuery()->from === $query->getQuery()->from) {\n            return $this->getRelationExistenceQueryForSelfRelation($query, $parentQuery, $columns);\n        }\n\n        if ($parentQuery->getQuery()->from === $this->throughParent->getTable()) {\n            return $this->getRelationExistenceQueryForThroughSelfRelation($query, $parentQuery, $columns);\n        }\n\n        $this->performJoin($query);\n\n        return $query->select($columns)->whereColumn(\n            $this->getQualifiedLocalKeyName(), '=', $this->getQualifiedFirstKeyName()\n        );\n    }\n\n    /**\n     * Add the constraints for a relationship query on the same table.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $query\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $parentQuery\n     * @param  array|mixed  $columns\n     * @return \\Illuminate\\Database\\Eloquent\\Builder\n     */\n    public function getRelationExistenceQueryForSelfRelation(Builder $query, Builder $parentQuery, $columns = ['*'])\n    {\n        $query->from($query->getModel()->getTable().' as '.$hash = $this->getRelationCountHash());\n\n        $query->join($this->throughParent->getTable(), $this->getQualifiedParentKeyName(), '=', $hash.'.'.$this->secondKey);\n\n        if ($this->throughParentSoftDeletes()) {\n            $query->whereNull($this->throughParent->getQualifiedDeletedAtColumn());\n        }\n\n        $query->getModel()->setTable($hash);\n\n        return $query->select($columns)->whereColumn(\n            $parentQuery->getQuery()->from.'.'.$this->localKey, '=', $this->getQualifiedFirstKeyName()\n        );\n    }\n\n    /**\n     * Add the constraints for a relationship query on the same table as the through parent.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $query\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $parentQuery\n     * @param  array|mixed  $columns\n     * @return \\Illuminate\\Database\\Eloquent\\Builder\n     */\n    public function getRelationExistenceQueryForThroughSelfRelation(Builder $query, Builder $parentQuery, $columns = ['*'])\n    {\n        $table = $this->throughParent->getTable().' as '.$hash = $this->getRelationCountHash();\n\n        $query->join($table, $hash.'.'.$this->secondLocalKey, '=', $this->getQualifiedFarKeyName());\n\n        if ($this->throughParentSoftDeletes()) {\n            $query->whereNull($hash.'.'.$this->throughParent->getDeletedAtColumn());\n        }\n\n        return $query->select($columns)->whereColumn(\n            $parentQuery->getQuery()->from.'.'.$this->localKey, '=', $hash.'.'.$this->firstKey\n        );\n    }\n\n    /**\n     * Get the qualified foreign key on the related model.\n     *\n     * @return string\n     */\n    public function getQualifiedFarKeyName()\n    {\n        return $this->getQualifiedForeignKeyName();\n    }\n\n    /**\n     * Get the foreign key on the \"through\" model.\n     *\n     * @return string\n     */\n    public function getFirstKeyName()\n    {\n        return $this->firstKey;\n    }\n\n    /**\n     * Get the qualified foreign key on the \"through\" model.\n     *\n     * @return string\n     */\n    public function getQualifiedFirstKeyName()\n    {\n        return $this->throughParent->qualifyColumn($this->firstKey);\n    }\n\n    /**\n     * Get the foreign key on the related model.\n     *\n     * @return string\n     */\n    public function getForeignKeyName()\n    {\n        return $this->secondKey;\n    }\n\n    /**\n     * Get the qualified foreign key on the related model.\n     *\n     * @return string\n     */\n    public function getQualifiedForeignKeyName()\n    {\n        return $this->related->qualifyColumn($this->secondKey);\n    }\n\n    /**\n     * Get the local key on the far parent model.\n     *\n     * @return string\n     */\n    public function getLocalKeyName()\n    {\n        return $this->localKey;\n    }\n\n    /**\n     * Get the qualified local key on the far parent model.\n     *\n     * @return string\n     */\n    public function getQualifiedLocalKeyName()\n    {\n        return $this->farParent->qualifyColumn($this->localKey);\n    }\n\n    /**\n     * Get the local key on the intermediary model.\n     *\n     * @return string\n     */\n    public function getSecondLocalKeyName()\n    {\n        return $this->secondLocalKey;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/Relations/HasOne.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent\\Relations;\n\nuse Illuminate\\Contracts\\Database\\Eloquent\\SupportsPartialRelations;\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Illuminate\\Database\\Eloquent\\Collection;\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Database\\Eloquent\\Relations\\Concerns\\CanBeOneOfMany;\nuse Illuminate\\Database\\Eloquent\\Relations\\Concerns\\ComparesRelatedModels;\nuse Illuminate\\Database\\Eloquent\\Relations\\Concerns\\SupportsDefaultModels;\nuse Illuminate\\Database\\Query\\JoinClause;\n\nclass HasOne extends HasOneOrMany implements SupportsPartialRelations\n{\n    use ComparesRelatedModels, CanBeOneOfMany, SupportsDefaultModels;\n\n    /**\n     * Get the results of the relationship.\n     *\n     * @return mixed\n     */\n    public function getResults()\n    {\n        if (is_null($this->getParentKey())) {\n            return $this->getDefaultFor($this->parent);\n        }\n\n        return $this->query->first() ?: $this->getDefaultFor($this->parent);\n    }\n\n    /**\n     * Initialize the relation on a set of models.\n     *\n     * @param  array  $models\n     * @param  string  $relation\n     * @return array\n     */\n    public function initRelation(array $models, $relation)\n    {\n        foreach ($models as $model) {\n            $model->setRelation($relation, $this->getDefaultFor($model));\n        }\n\n        return $models;\n    }\n\n    /**\n     * Match the eagerly loaded results to their parents.\n     *\n     * @param  array  $models\n     * @param  \\Illuminate\\Database\\Eloquent\\Collection  $results\n     * @param  string  $relation\n     * @return array\n     */\n    public function match(array $models, Collection $results, $relation)\n    {\n        return $this->matchOne($models, $results, $relation);\n    }\n\n    /**\n     * Add the constraints for an internal relationship existence query.\n     *\n     * Essentially, these queries compare on column names like \"whereColumn\".\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $query\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $parentQuery\n     * @param  array|mixed  $columns\n     * @return \\Illuminate\\Database\\Eloquent\\Builder\n     */\n    public function getRelationExistenceQuery(Builder $query, Builder $parentQuery, $columns = ['*'])\n    {\n        if ($this->isOneOfMany()) {\n            $this->mergeOneOfManyJoinsTo($query);\n        }\n\n        return parent::getRelationExistenceQuery($query, $parentQuery, $columns);\n    }\n\n    /**\n     * Add constraints for inner join subselect for one of many relationships.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $query\n     * @param  string|null  $column\n     * @param  string|null  $aggregate\n     * @return void\n     */\n    public function addOneOfManySubQueryConstraints(Builder $query, $column = null, $aggregate = null)\n    {\n        $query->addSelect($this->foreignKey);\n    }\n\n    /**\n     * Get the columns that should be selected by the one of many subquery.\n     *\n     * @return array|string\n     */\n    public function getOneOfManySubQuerySelectColumns()\n    {\n        return $this->foreignKey;\n    }\n\n    /**\n     * Add join query constraints for one of many relationships.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\JoinClause  $join\n     * @return void\n     */\n    public function addOneOfManyJoinSubQueryConstraints(JoinClause $join)\n    {\n        $join->on($this->qualifySubSelectColumn($this->foreignKey), '=', $this->qualifyRelatedColumn($this->foreignKey));\n    }\n\n    /**\n     * Make a new related instance for the given model.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $parent\n     * @return \\Illuminate\\Database\\Eloquent\\Model\n     */\n    public function newRelatedInstanceFor(Model $parent)\n    {\n        return $this->related->newInstance()->setAttribute(\n            $this->getForeignKeyName(), $parent->{$this->localKey}\n        );\n    }\n\n    /**\n     * Get the value of the model's foreign key.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $model\n     * @return mixed\n     */\n    protected function getRelatedKeyFrom(Model $model)\n    {\n        return $model->getAttribute($this->getForeignKeyName());\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/Relations/HasOneOrMany.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent\\Relations;\n\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Illuminate\\Database\\Eloquent\\Collection;\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Database\\Eloquent\\Relations\\Concerns\\InteractsWithDictionary;\n\nabstract class HasOneOrMany extends Relation\n{\n    use InteractsWithDictionary;\n\n    /**\n     * The foreign key of the parent model.\n     *\n     * @var string\n     */\n    protected $foreignKey;\n\n    /**\n     * The local key of the parent model.\n     *\n     * @var string\n     */\n    protected $localKey;\n\n    /**\n     * Create a new has one or many relationship instance.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $query\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $parent\n     * @param  string  $foreignKey\n     * @param  string  $localKey\n     * @return void\n     */\n    public function __construct(Builder $query, Model $parent, $foreignKey, $localKey)\n    {\n        $this->localKey = $localKey;\n        $this->foreignKey = $foreignKey;\n\n        parent::__construct($query, $parent);\n    }\n\n    /**\n     * Create and return an un-saved instance of the related model.\n     *\n     * @param  array  $attributes\n     * @return \\Illuminate\\Database\\Eloquent\\Model\n     */\n    public function make(array $attributes = [])\n    {\n        return tap($this->related->newInstance($attributes), function ($instance) {\n            $this->setForeignAttributesForCreate($instance);\n        });\n    }\n\n    /**\n     * Create and return an un-saved instance of the related models.\n     *\n     * @param  iterable  $records\n     * @return \\Illuminate\\Database\\Eloquent\\Collection\n     */\n    public function makeMany($records)\n    {\n        $instances = $this->related->newCollection();\n\n        foreach ($records as $record) {\n            $instances->push($this->make($record));\n        }\n\n        return $instances;\n    }\n\n    /**\n     * Set the base constraints on the relation query.\n     *\n     * @return void\n     */\n    public function addConstraints()\n    {\n        if (static::$constraints) {\n            $query = $this->getRelationQuery();\n\n            $query->where($this->foreignKey, '=', $this->getParentKey());\n\n            $query->whereNotNull($this->foreignKey);\n        }\n    }\n\n    /**\n     * Set the constraints for an eager load of the relation.\n     *\n     * @param  array  $models\n     * @return void\n     */\n    public function addEagerConstraints(array $models)\n    {\n        $whereIn = $this->whereInMethod($this->parent, $this->localKey);\n\n        $this->getRelationQuery()->{$whereIn}(\n            $this->foreignKey, $this->getKeys($models, $this->localKey)\n        );\n    }\n\n    /**\n     * Match the eagerly loaded results to their single parents.\n     *\n     * @param  array  $models\n     * @param  \\Illuminate\\Database\\Eloquent\\Collection  $results\n     * @param  string  $relation\n     * @return array\n     */\n    public function matchOne(array $models, Collection $results, $relation)\n    {\n        return $this->matchOneOrMany($models, $results, $relation, 'one');\n    }\n\n    /**\n     * Match the eagerly loaded results to their many parents.\n     *\n     * @param  array  $models\n     * @param  \\Illuminate\\Database\\Eloquent\\Collection  $results\n     * @param  string  $relation\n     * @return array\n     */\n    public function matchMany(array $models, Collection $results, $relation)\n    {\n        return $this->matchOneOrMany($models, $results, $relation, 'many');\n    }\n\n    /**\n     * Match the eagerly loaded results to their many parents.\n     *\n     * @param  array  $models\n     * @param  \\Illuminate\\Database\\Eloquent\\Collection  $results\n     * @param  string  $relation\n     * @param  string  $type\n     * @return array\n     */\n    protected function matchOneOrMany(array $models, Collection $results, $relation, $type)\n    {\n        $dictionary = $this->buildDictionary($results);\n\n        // Once we have the dictionary we can simply spin through the parent models to\n        // link them up with their children using the keyed dictionary to make the\n        // matching very convenient and easy work. Then we'll just return them.\n        foreach ($models as $model) {\n            if (isset($dictionary[$key = $this->getDictionaryKey($model->getAttribute($this->localKey))])) {\n                $model->setRelation(\n                    $relation, $this->getRelationValue($dictionary, $key, $type)\n                );\n            }\n        }\n\n        return $models;\n    }\n\n    /**\n     * Get the value of a relationship by one or many type.\n     *\n     * @param  array  $dictionary\n     * @param  string  $key\n     * @param  string  $type\n     * @return mixed\n     */\n    protected function getRelationValue(array $dictionary, $key, $type)\n    {\n        $value = $dictionary[$key];\n\n        return $type === 'one' ? reset($value) : $this->related->newCollection($value);\n    }\n\n    /**\n     * Build model dictionary keyed by the relation's foreign key.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Collection  $results\n     * @return array\n     */\n    protected function buildDictionary(Collection $results)\n    {\n        $foreign = $this->getForeignKeyName();\n\n        return $results->mapToDictionary(function ($result) use ($foreign) {\n            return [$this->getDictionaryKey($result->{$foreign}) => $result];\n        })->all();\n    }\n\n    /**\n     * Find a model by its primary key or return a new instance of the related model.\n     *\n     * @param  mixed  $id\n     * @param  array  $columns\n     * @return \\Illuminate\\Support\\Collection|\\Illuminate\\Database\\Eloquent\\Model\n     */\n    public function findOrNew($id, $columns = ['*'])\n    {\n        if (is_null($instance = $this->find($id, $columns))) {\n            $instance = $this->related->newInstance();\n\n            $this->setForeignAttributesForCreate($instance);\n        }\n\n        return $instance;\n    }\n\n    /**\n     * Get the first related model record matching the attributes or instantiate it.\n     *\n     * @param  array  $attributes\n     * @param  array  $values\n     * @return \\Illuminate\\Database\\Eloquent\\Model\n     */\n    public function firstOrNew(array $attributes = [], array $values = [])\n    {\n        if (is_null($instance = $this->where($attributes)->first())) {\n            $instance = $this->related->newInstance(array_merge($attributes, $values));\n\n            $this->setForeignAttributesForCreate($instance);\n        }\n\n        return $instance;\n    }\n\n    /**\n     * Get the first related record matching the attributes or create it.\n     *\n     * @param  array  $attributes\n     * @param  array  $values\n     * @return \\Illuminate\\Database\\Eloquent\\Model\n     */\n    public function firstOrCreate(array $attributes = [], array $values = [])\n    {\n        if (is_null($instance = $this->where($attributes)->first())) {\n            $instance = $this->create(array_merge($attributes, $values));\n        }\n\n        return $instance;\n    }\n\n    /**\n     * Create or update a related record matching the attributes, and fill it with values.\n     *\n     * @param  array  $attributes\n     * @param  array  $values\n     * @return \\Illuminate\\Database\\Eloquent\\Model\n     */\n    public function updateOrCreate(array $attributes, array $values = [])\n    {\n        return tap($this->firstOrNew($attributes), function ($instance) use ($values) {\n            $instance->fill($values);\n\n            $instance->save();\n        });\n    }\n\n    /**\n     * Attach a model instance to the parent model.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $model\n     * @return \\Illuminate\\Database\\Eloquent\\Model|false\n     */\n    public function save(Model $model)\n    {\n        $this->setForeignAttributesForCreate($model);\n\n        return $model->save() ? $model : false;\n    }\n\n    /**\n     * Attach a collection of models to the parent instance.\n     *\n     * @param  iterable  $models\n     * @return iterable\n     */\n    public function saveMany($models)\n    {\n        foreach ($models as $model) {\n            $this->save($model);\n        }\n\n        return $models;\n    }\n\n    /**\n     * Create a new instance of the related model.\n     *\n     * @param  array  $attributes\n     * @return \\Illuminate\\Database\\Eloquent\\Model\n     */\n    public function create(array $attributes = [])\n    {\n        return tap($this->related->newInstance($attributes), function ($instance) {\n            $this->setForeignAttributesForCreate($instance);\n\n            $instance->save();\n        });\n    }\n\n    /**\n     * Create a new instance of the related model. Allow mass-assignment.\n     *\n     * @param  array  $attributes\n     * @return \\Illuminate\\Database\\Eloquent\\Model\n     */\n    public function forceCreate(array $attributes = [])\n    {\n        $attributes[$this->getForeignKeyName()] = $this->getParentKey();\n\n        return $this->related->forceCreate($attributes);\n    }\n\n    /**\n     * Create a Collection of new instances of the related model.\n     *\n     * @param  iterable  $records\n     * @return \\Illuminate\\Database\\Eloquent\\Collection\n     */\n    public function createMany(iterable $records)\n    {\n        $instances = $this->related->newCollection();\n\n        foreach ($records as $record) {\n            $instances->push($this->create($record));\n        }\n\n        return $instances;\n    }\n\n    /**\n     * Set the foreign ID for creating a related model.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $model\n     * @return void\n     */\n    protected function setForeignAttributesForCreate(Model $model)\n    {\n        $model->setAttribute($this->getForeignKeyName(), $this->getParentKey());\n    }\n\n    /**\n     * Add the constraints for a relationship query.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $query\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $parentQuery\n     * @param  array|mixed  $columns\n     * @return \\Illuminate\\Database\\Eloquent\\Builder\n     */\n    public function getRelationExistenceQuery(Builder $query, Builder $parentQuery, $columns = ['*'])\n    {\n        if ($query->getQuery()->from == $parentQuery->getQuery()->from) {\n            return $this->getRelationExistenceQueryForSelfRelation($query, $parentQuery, $columns);\n        }\n\n        return parent::getRelationExistenceQuery($query, $parentQuery, $columns);\n    }\n\n    /**\n     * Add the constraints for a relationship query on the same table.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $query\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $parentQuery\n     * @param  array|mixed  $columns\n     * @return \\Illuminate\\Database\\Eloquent\\Builder\n     */\n    public function getRelationExistenceQueryForSelfRelation(Builder $query, Builder $parentQuery, $columns = ['*'])\n    {\n        $query->from($query->getModel()->getTable().' as '.$hash = $this->getRelationCountHash());\n\n        $query->getModel()->setTable($hash);\n\n        return $query->select($columns)->whereColumn(\n            $this->getQualifiedParentKeyName(), '=', $hash.'.'.$this->getForeignKeyName()\n        );\n    }\n\n    /**\n     * Get the key for comparing against the parent key in \"has\" query.\n     *\n     * @return string\n     */\n    public function getExistenceCompareKey()\n    {\n        return $this->getQualifiedForeignKeyName();\n    }\n\n    /**\n     * Get the key value of the parent's local key.\n     *\n     * @return mixed\n     */\n    public function getParentKey()\n    {\n        return $this->parent->getAttribute($this->localKey);\n    }\n\n    /**\n     * Get the fully qualified parent key name.\n     *\n     * @return string\n     */\n    public function getQualifiedParentKeyName()\n    {\n        return $this->parent->qualifyColumn($this->localKey);\n    }\n\n    /**\n     * Get the plain foreign key.\n     *\n     * @return string\n     */\n    public function getForeignKeyName()\n    {\n        $segments = explode('.', $this->getQualifiedForeignKeyName());\n\n        return end($segments);\n    }\n\n    /**\n     * Get the foreign key for the relationship.\n     *\n     * @return string\n     */\n    public function getQualifiedForeignKeyName()\n    {\n        return $this->foreignKey;\n    }\n\n    /**\n     * Get the local key for the relationship.\n     *\n     * @return string\n     */\n    public function getLocalKeyName()\n    {\n        return $this->localKey;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/Relations/HasOneThrough.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent\\Relations;\n\nuse Illuminate\\Database\\Eloquent\\Collection;\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Database\\Eloquent\\Relations\\Concerns\\InteractsWithDictionary;\nuse Illuminate\\Database\\Eloquent\\Relations\\Concerns\\SupportsDefaultModels;\n\nclass HasOneThrough extends HasManyThrough\n{\n    use InteractsWithDictionary, SupportsDefaultModels;\n\n    /**\n     * Get the results of the relationship.\n     *\n     * @return mixed\n     */\n    public function getResults()\n    {\n        return $this->first() ?: $this->getDefaultFor($this->farParent);\n    }\n\n    /**\n     * Initialize the relation on a set of models.\n     *\n     * @param  array  $models\n     * @param  string  $relation\n     * @return array\n     */\n    public function initRelation(array $models, $relation)\n    {\n        foreach ($models as $model) {\n            $model->setRelation($relation, $this->getDefaultFor($model));\n        }\n\n        return $models;\n    }\n\n    /**\n     * Match the eagerly loaded results to their parents.\n     *\n     * @param  array  $models\n     * @param  \\Illuminate\\Database\\Eloquent\\Collection  $results\n     * @param  string  $relation\n     * @return array\n     */\n    public function match(array $models, Collection $results, $relation)\n    {\n        $dictionary = $this->buildDictionary($results);\n\n        // Once we have the dictionary we can simply spin through the parent models to\n        // link them up with their children using the keyed dictionary to make the\n        // matching very convenient and easy work. Then we'll just return them.\n        foreach ($models as $model) {\n            if (isset($dictionary[$key = $this->getDictionaryKey($model->getAttribute($this->localKey))])) {\n                $value = $dictionary[$key];\n                $model->setRelation(\n                    $relation, reset($value)\n                );\n            }\n        }\n\n        return $models;\n    }\n\n    /**\n     * Make a new related instance for the given model.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $parent\n     * @return \\Illuminate\\Database\\Eloquent\\Model\n     */\n    public function newRelatedInstanceFor(Model $parent)\n    {\n        return $this->related->newInstance();\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/Relations/MorphMany.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent\\Relations;\n\nuse Illuminate\\Database\\Eloquent\\Collection;\n\nclass MorphMany extends MorphOneOrMany\n{\n    /**\n     * Get the results of the relationship.\n     *\n     * @return mixed\n     */\n    public function getResults()\n    {\n        return ! is_null($this->getParentKey())\n                ? $this->query->get()\n                : $this->related->newCollection();\n    }\n\n    /**\n     * Initialize the relation on a set of models.\n     *\n     * @param  array  $models\n     * @param  string  $relation\n     * @return array\n     */\n    public function initRelation(array $models, $relation)\n    {\n        foreach ($models as $model) {\n            $model->setRelation($relation, $this->related->newCollection());\n        }\n\n        return $models;\n    }\n\n    /**\n     * Match the eagerly loaded results to their parents.\n     *\n     * @param  array  $models\n     * @param  \\Illuminate\\Database\\Eloquent\\Collection  $results\n     * @param  string  $relation\n     * @return array\n     */\n    public function match(array $models, Collection $results, $relation)\n    {\n        return $this->matchMany($models, $results, $relation);\n    }\n\n    /**\n     * Create a new instance of the related model. Allow mass-assignment.\n     *\n     * @param  array  $attributes\n     * @return \\Illuminate\\Database\\Eloquent\\Model\n     */\n    public function forceCreate(array $attributes = [])\n    {\n        $attributes[$this->getMorphType()] = $this->morphClass;\n\n        return parent::forceCreate($attributes);\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/Relations/MorphOne.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent\\Relations;\n\nuse Illuminate\\Contracts\\Database\\Eloquent\\SupportsPartialRelations;\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Illuminate\\Database\\Eloquent\\Collection;\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Database\\Eloquent\\Relations\\Concerns\\CanBeOneOfMany;\nuse Illuminate\\Database\\Eloquent\\Relations\\Concerns\\ComparesRelatedModels;\nuse Illuminate\\Database\\Eloquent\\Relations\\Concerns\\SupportsDefaultModels;\nuse Illuminate\\Database\\Query\\JoinClause;\n\nclass MorphOne extends MorphOneOrMany implements SupportsPartialRelations\n{\n    use CanBeOneOfMany, ComparesRelatedModels, SupportsDefaultModels;\n\n    /**\n     * Get the results of the relationship.\n     *\n     * @return mixed\n     */\n    public function getResults()\n    {\n        if (is_null($this->getParentKey())) {\n            return $this->getDefaultFor($this->parent);\n        }\n\n        return $this->query->first() ?: $this->getDefaultFor($this->parent);\n    }\n\n    /**\n     * Initialize the relation on a set of models.\n     *\n     * @param  array  $models\n     * @param  string  $relation\n     * @return array\n     */\n    public function initRelation(array $models, $relation)\n    {\n        foreach ($models as $model) {\n            $model->setRelation($relation, $this->getDefaultFor($model));\n        }\n\n        return $models;\n    }\n\n    /**\n     * Match the eagerly loaded results to their parents.\n     *\n     * @param  array  $models\n     * @param  \\Illuminate\\Database\\Eloquent\\Collection  $results\n     * @param  string  $relation\n     * @return array\n     */\n    public function match(array $models, Collection $results, $relation)\n    {\n        return $this->matchOne($models, $results, $relation);\n    }\n\n    /**\n     * Get the relationship query.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $query\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $parentQuery\n     * @param  array|mixed  $columns\n     * @return \\Illuminate\\Database\\Eloquent\\Builder\n     */\n    public function getRelationExistenceQuery(Builder $query, Builder $parentQuery, $columns = ['*'])\n    {\n        if ($this->isOneOfMany()) {\n            $this->mergeOneOfManyJoinsTo($query);\n        }\n\n        return parent::getRelationExistenceQuery($query, $parentQuery, $columns);\n    }\n\n    /**\n     * Add constraints for inner join subselect for one of many relationships.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $query\n     * @param  string|null  $column\n     * @param  string|null  $aggregate\n     * @return void\n     */\n    public function addOneOfManySubQueryConstraints(Builder $query, $column = null, $aggregate = null)\n    {\n        $query->addSelect($this->foreignKey, $this->morphType);\n    }\n\n    /**\n     * Get the columns that should be selected by the one of many subquery.\n     *\n     * @return array|string\n     */\n    public function getOneOfManySubQuerySelectColumns()\n    {\n        return [$this->foreignKey, $this->morphType];\n    }\n\n    /**\n     * Add join query constraints for one of many relationships.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\JoinClause  $join\n     * @return void\n     */\n    public function addOneOfManyJoinSubQueryConstraints(JoinClause $join)\n    {\n        $join\n            ->on($this->qualifySubSelectColumn($this->morphType), '=', $this->qualifyRelatedColumn($this->morphType))\n            ->on($this->qualifySubSelectColumn($this->foreignKey), '=', $this->qualifyRelatedColumn($this->foreignKey));\n    }\n\n    /**\n     * Make a new related instance for the given model.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $parent\n     * @return \\Illuminate\\Database\\Eloquent\\Model\n     */\n    public function newRelatedInstanceFor(Model $parent)\n    {\n        return $this->related->newInstance()\n                    ->setAttribute($this->getForeignKeyName(), $parent->{$this->localKey})\n                    ->setAttribute($this->getMorphType(), $this->morphClass);\n    }\n\n    /**\n     * Get the value of the model's foreign key.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $model\n     * @return mixed\n     */\n    protected function getRelatedKeyFrom(Model $model)\n    {\n        return $model->getAttribute($this->getForeignKeyName());\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/Relations/MorphOneOrMany.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent\\Relations;\n\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Illuminate\\Database\\Eloquent\\Model;\n\nabstract class MorphOneOrMany extends HasOneOrMany\n{\n    /**\n     * The foreign key type for the relationship.\n     *\n     * @var string\n     */\n    protected $morphType;\n\n    /**\n     * The class name of the parent model.\n     *\n     * @var string\n     */\n    protected $morphClass;\n\n    /**\n     * Create a new morph one or many relationship instance.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $query\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $parent\n     * @param  string  $type\n     * @param  string  $id\n     * @param  string  $localKey\n     * @return void\n     */\n    public function __construct(Builder $query, Model $parent, $type, $id, $localKey)\n    {\n        $this->morphType = $type;\n\n        $this->morphClass = $parent->getMorphClass();\n\n        parent::__construct($query, $parent, $id, $localKey);\n    }\n\n    /**\n     * Set the base constraints on the relation query.\n     *\n     * @return void\n     */\n    public function addConstraints()\n    {\n        if (static::$constraints) {\n            $this->getRelationQuery()->where($this->morphType, $this->morphClass);\n\n            parent::addConstraints();\n        }\n    }\n\n    /**\n     * Set the constraints for an eager load of the relation.\n     *\n     * @param  array  $models\n     * @return void\n     */\n    public function addEagerConstraints(array $models)\n    {\n        parent::addEagerConstraints($models);\n\n        $this->getRelationQuery()->where($this->morphType, $this->morphClass);\n    }\n\n    /**\n     * Set the foreign ID and type for creating a related model.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $model\n     * @return void\n     */\n    protected function setForeignAttributesForCreate(Model $model)\n    {\n        $model->{$this->getForeignKeyName()} = $this->getParentKey();\n\n        $model->{$this->getMorphType()} = $this->morphClass;\n    }\n\n    /**\n     * Get the relationship query.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $query\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $parentQuery\n     * @param  array|mixed  $columns\n     * @return \\Illuminate\\Database\\Eloquent\\Builder\n     */\n    public function getRelationExistenceQuery(Builder $query, Builder $parentQuery, $columns = ['*'])\n    {\n        return parent::getRelationExistenceQuery($query, $parentQuery, $columns)->where(\n            $query->qualifyColumn($this->getMorphType()), $this->morphClass\n        );\n    }\n\n    /**\n     * Get the foreign key \"type\" name.\n     *\n     * @return string\n     */\n    public function getQualifiedMorphType()\n    {\n        return $this->morphType;\n    }\n\n    /**\n     * Get the plain morph type name without the table.\n     *\n     * @return string\n     */\n    public function getMorphType()\n    {\n        return last(explode('.', $this->morphType));\n    }\n\n    /**\n     * Get the class name of the parent model.\n     *\n     * @return string\n     */\n    public function getMorphClass()\n    {\n        return $this->morphClass;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/Relations/MorphPivot.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent\\Relations;\n\nuse Illuminate\\Support\\Str;\n\nclass MorphPivot extends Pivot\n{\n    /**\n     * The type of the polymorphic relation.\n     *\n     * Explicitly define this so it's not included in saved attributes.\n     *\n     * @var string\n     */\n    protected $morphType;\n\n    /**\n     * The value of the polymorphic relation.\n     *\n     * Explicitly define this so it's not included in saved attributes.\n     *\n     * @var string\n     */\n    protected $morphClass;\n\n    /**\n     * Set the keys for a save update query.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $query\n     * @return \\Illuminate\\Database\\Eloquent\\Builder\n     */\n    protected function setKeysForSaveQuery($query)\n    {\n        $query->where($this->morphType, $this->morphClass);\n\n        return parent::setKeysForSaveQuery($query);\n    }\n\n    /**\n     * Set the keys for a select query.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $query\n     * @return \\Illuminate\\Database\\Eloquent\\Builder\n     */\n    protected function setKeysForSelectQuery($query)\n    {\n        $query->where($this->morphType, $this->morphClass);\n\n        return parent::setKeysForSelectQuery($query);\n    }\n\n    /**\n     * Delete the pivot model record from the database.\n     *\n     * @return int\n     */\n    public function delete()\n    {\n        if (isset($this->attributes[$this->getKeyName()])) {\n            return (int) parent::delete();\n        }\n\n        if ($this->fireModelEvent('deleting') === false) {\n            return 0;\n        }\n\n        $query = $this->getDeleteQuery();\n\n        $query->where($this->morphType, $this->morphClass);\n\n        return tap($query->delete(), function () {\n            $this->fireModelEvent('deleted', false);\n        });\n    }\n\n    /**\n     * Get the morph type for the pivot.\n     *\n     * @return string\n     */\n    public function getMorphType()\n    {\n        return $this->morphType;\n    }\n\n    /**\n     * Set the morph type for the pivot.\n     *\n     * @param  string  $morphType\n     * @return $this\n     */\n    public function setMorphType($morphType)\n    {\n        $this->morphType = $morphType;\n\n        return $this;\n    }\n\n    /**\n     * Set the morph class for the pivot.\n     *\n     * @param  string  $morphClass\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\MorphPivot\n     */\n    public function setMorphClass($morphClass)\n    {\n        $this->morphClass = $morphClass;\n\n        return $this;\n    }\n\n    /**\n     * Get the queueable identity for the entity.\n     *\n     * @return mixed\n     */\n    public function getQueueableId()\n    {\n        if (isset($this->attributes[$this->getKeyName()])) {\n            return $this->getKey();\n        }\n\n        return sprintf(\n            '%s:%s:%s:%s:%s:%s',\n            $this->foreignKey, $this->getAttribute($this->foreignKey),\n            $this->relatedKey, $this->getAttribute($this->relatedKey),\n            $this->morphType, $this->morphClass\n        );\n    }\n\n    /**\n     * Get a new query to restore one or more models by their queueable IDs.\n     *\n     * @param  array|int  $ids\n     * @return \\Illuminate\\Database\\Eloquent\\Builder\n     */\n    public function newQueryForRestoration($ids)\n    {\n        if (is_array($ids)) {\n            return $this->newQueryForCollectionRestoration($ids);\n        }\n\n        if (! Str::contains($ids, ':')) {\n            return parent::newQueryForRestoration($ids);\n        }\n\n        $segments = explode(':', $ids);\n\n        return $this->newQueryWithoutScopes()\n                        ->where($segments[0], $segments[1])\n                        ->where($segments[2], $segments[3])\n                        ->where($segments[4], $segments[5]);\n    }\n\n    /**\n     * Get a new query to restore multiple models by their queueable IDs.\n     *\n     * @param  array  $ids\n     * @return \\Illuminate\\Database\\Eloquent\\Builder\n     */\n    protected function newQueryForCollectionRestoration(array $ids)\n    {\n        $ids = array_values($ids);\n\n        if (! Str::contains($ids[0], ':')) {\n            return parent::newQueryForRestoration($ids);\n        }\n\n        $query = $this->newQueryWithoutScopes();\n\n        foreach ($ids as $id) {\n            $segments = explode(':', $id);\n\n            $query->orWhere(function ($query) use ($segments) {\n                return $query->where($segments[0], $segments[1])\n                             ->where($segments[2], $segments[3])\n                             ->where($segments[4], $segments[5]);\n            });\n        }\n\n        return $query;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/Relations/MorphTo.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent\\Relations;\n\nuse BadMethodCallException;\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Illuminate\\Database\\Eloquent\\Collection;\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Database\\Eloquent\\Relations\\Concerns\\InteractsWithDictionary;\n\nclass MorphTo extends BelongsTo\n{\n    use InteractsWithDictionary;\n\n    /**\n     * The type of the polymorphic relation.\n     *\n     * @var string\n     */\n    protected $morphType;\n\n    /**\n     * The models whose relations are being eager loaded.\n     *\n     * @var \\Illuminate\\Database\\Eloquent\\Collection\n     */\n    protected $models;\n\n    /**\n     * All of the models keyed by ID.\n     *\n     * @var array\n     */\n    protected $dictionary = [];\n\n    /**\n     * A buffer of dynamic calls to query macros.\n     *\n     * @var array\n     */\n    protected $macroBuffer = [];\n\n    /**\n     * A map of relations to load for each individual morph type.\n     *\n     * @var array\n     */\n    protected $morphableEagerLoads = [];\n\n    /**\n     * A map of relationship counts to load for each individual morph type.\n     *\n     * @var array\n     */\n    protected $morphableEagerLoadCounts = [];\n\n    /**\n     * A map of constraints to apply for each individual morph type.\n     *\n     * @var array\n     */\n    protected $morphableConstraints = [];\n\n    /**\n     * Create a new morph to relationship instance.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $query\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $parent\n     * @param  string  $foreignKey\n     * @param  string  $ownerKey\n     * @param  string  $type\n     * @param  string  $relation\n     * @return void\n     */\n    public function __construct(Builder $query, Model $parent, $foreignKey, $ownerKey, $type, $relation)\n    {\n        $this->morphType = $type;\n\n        parent::__construct($query, $parent, $foreignKey, $ownerKey, $relation);\n    }\n\n    /**\n     * Set the constraints for an eager load of the relation.\n     *\n     * @param  array  $models\n     * @return void\n     */\n    public function addEagerConstraints(array $models)\n    {\n        $this->buildDictionary($this->models = Collection::make($models));\n    }\n\n    /**\n     * Build a dictionary with the models.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Collection  $models\n     * @return void\n     */\n    protected function buildDictionary(Collection $models)\n    {\n        foreach ($models as $model) {\n            if ($model->{$this->morphType}) {\n                $morphTypeKey = $this->getDictionaryKey($model->{$this->morphType});\n                $foreignKeyKey = $this->getDictionaryKey($model->{$this->foreignKey});\n\n                $this->dictionary[$morphTypeKey][$foreignKeyKey][] = $model;\n            }\n        }\n    }\n\n    /**\n     * Get the results of the relationship.\n     *\n     * Called via eager load method of Eloquent query builder.\n     *\n     * @return mixed\n     */\n    public function getEager()\n    {\n        foreach (array_keys($this->dictionary) as $type) {\n            $this->matchToMorphParents($type, $this->getResultsByType($type));\n        }\n\n        return $this->models;\n    }\n\n    /**\n     * Get all of the relation results for a type.\n     *\n     * @param  string  $type\n     * @return \\Illuminate\\Database\\Eloquent\\Collection\n     */\n    protected function getResultsByType($type)\n    {\n        $instance = $this->createModelByType($type);\n\n        $ownerKey = $this->ownerKey ?? $instance->getKeyName();\n\n        $query = $this->replayMacros($instance->newQuery())\n                            ->mergeConstraintsFrom($this->getQuery())\n                            ->with(array_merge(\n                                $this->getQuery()->getEagerLoads(),\n                                (array) ($this->morphableEagerLoads[get_class($instance)] ?? [])\n                            ))\n                            ->withCount(\n                                (array) ($this->morphableEagerLoadCounts[get_class($instance)] ?? [])\n                            );\n\n        if ($callback = ($this->morphableConstraints[get_class($instance)] ?? null)) {\n            $callback($query);\n        }\n\n        $whereIn = $this->whereInMethod($instance, $ownerKey);\n\n        return $query->{$whereIn}(\n            $instance->getTable().'.'.$ownerKey, $this->gatherKeysByType($type, $instance->getKeyType())\n        )->get();\n    }\n\n    /**\n     * Gather all of the foreign keys for a given type.\n     *\n     * @param  string  $type\n     * @param  string  $keyType\n     * @return array\n     */\n    protected function gatherKeysByType($type, $keyType)\n    {\n        return $keyType !== 'string'\n                    ? array_keys($this->dictionary[$type])\n                    : array_map(function ($modelId) {\n                        return (string) $modelId;\n                    }, array_filter(array_keys($this->dictionary[$type])));\n    }\n\n    /**\n     * Create a new model instance by type.\n     *\n     * @param  string  $type\n     * @return \\Illuminate\\Database\\Eloquent\\Model\n     */\n    public function createModelByType($type)\n    {\n        $class = Model::getActualClassNameForMorph($type);\n\n        return tap(new $class, function ($instance) {\n            if (! $instance->getConnectionName()) {\n                $instance->setConnection($this->getConnection()->getName());\n            }\n        });\n    }\n\n    /**\n     * Match the eagerly loaded results to their parents.\n     *\n     * @param  array  $models\n     * @param  \\Illuminate\\Database\\Eloquent\\Collection  $results\n     * @param  string  $relation\n     * @return array\n     */\n    public function match(array $models, Collection $results, $relation)\n    {\n        return $models;\n    }\n\n    /**\n     * Match the results for a given type to their parents.\n     *\n     * @param  string  $type\n     * @param  \\Illuminate\\Database\\Eloquent\\Collection  $results\n     * @return void\n     */\n    protected function matchToMorphParents($type, Collection $results)\n    {\n        foreach ($results as $result) {\n            $ownerKey = ! is_null($this->ownerKey) ? $this->getDictionaryKey($result->{$this->ownerKey}) : $result->getKey();\n\n            if (isset($this->dictionary[$type][$ownerKey])) {\n                foreach ($this->dictionary[$type][$ownerKey] as $model) {\n                    $model->setRelation($this->relationName, $result);\n                }\n            }\n        }\n    }\n\n    /**\n     * Associate the model instance to the given parent.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $model\n     * @return \\Illuminate\\Database\\Eloquent\\Model\n     */\n    public function associate($model)\n    {\n        if ($model instanceof Model) {\n            $foreignKey = $this->ownerKey && $model->{$this->ownerKey}\n                            ? $this->ownerKey\n                            : $model->getKeyName();\n        }\n\n        $this->parent->setAttribute(\n            $this->foreignKey, $model instanceof Model ? $model->{$foreignKey} : null\n        );\n\n        $this->parent->setAttribute(\n            $this->morphType, $model instanceof Model ? $model->getMorphClass() : null\n        );\n\n        return $this->parent->setRelation($this->relationName, $model);\n    }\n\n    /**\n     * Dissociate previously associated model from the given parent.\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Model\n     */\n    public function dissociate()\n    {\n        $this->parent->setAttribute($this->foreignKey, null);\n\n        $this->parent->setAttribute($this->morphType, null);\n\n        return $this->parent->setRelation($this->relationName, null);\n    }\n\n    /**\n     * Touch all of the related models for the relationship.\n     *\n     * @return void\n     */\n    public function touch()\n    {\n        if (! is_null($this->child->{$this->foreignKey})) {\n            parent::touch();\n        }\n    }\n\n    /**\n     * Make a new related instance for the given model.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $parent\n     * @return \\Illuminate\\Database\\Eloquent\\Model\n     */\n    protected function newRelatedInstanceFor(Model $parent)\n    {\n        return $parent->{$this->getRelationName()}()->getRelated()->newInstance();\n    }\n\n    /**\n     * Get the foreign key \"type\" name.\n     *\n     * @return string\n     */\n    public function getMorphType()\n    {\n        return $this->morphType;\n    }\n\n    /**\n     * Get the dictionary used by the relationship.\n     *\n     * @return array\n     */\n    public function getDictionary()\n    {\n        return $this->dictionary;\n    }\n\n    /**\n     * Specify which relations to load for a given morph type.\n     *\n     * @param  array  $with\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\MorphTo\n     */\n    public function morphWith(array $with)\n    {\n        $this->morphableEagerLoads = array_merge(\n            $this->morphableEagerLoads, $with\n        );\n\n        return $this;\n    }\n\n    /**\n     * Specify which relationship counts to load for a given morph type.\n     *\n     * @param  array  $withCount\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\MorphTo\n     */\n    public function morphWithCount(array $withCount)\n    {\n        $this->morphableEagerLoadCounts = array_merge(\n            $this->morphableEagerLoadCounts, $withCount\n        );\n\n        return $this;\n    }\n\n    /**\n     * Specify constraints on the query for a given morph type.\n     *\n     * @param  array  $callbacks\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\MorphTo\n     */\n    public function constrain(array $callbacks)\n    {\n        $this->morphableConstraints = array_merge(\n            $this->morphableConstraints, $callbacks\n        );\n\n        return $this;\n    }\n\n    /**\n     * Replay stored macro calls on the actual related instance.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $query\n     * @return \\Illuminate\\Database\\Eloquent\\Builder\n     */\n    protected function replayMacros(Builder $query)\n    {\n        foreach ($this->macroBuffer as $macro) {\n            $query->{$macro['method']}(...$macro['parameters']);\n        }\n\n        return $query;\n    }\n\n    /**\n     * Handle dynamic method calls to the relationship.\n     *\n     * @param  string  $method\n     * @param  array  $parameters\n     * @return mixed\n     */\n    public function __call($method, $parameters)\n    {\n        try {\n            $result = parent::__call($method, $parameters);\n\n            if (in_array($method, ['select', 'selectRaw', 'selectSub', 'addSelect', 'withoutGlobalScopes'])) {\n                $this->macroBuffer[] = compact('method', 'parameters');\n            }\n\n            return $result;\n        }\n\n        // If we tried to call a method that does not exist on the parent Builder instance,\n        // we'll assume that we want to call a query macro (e.g. withTrashed) that only\n        // exists on related models. We will just store the call and replay it later.\n        catch (BadMethodCallException $e) {\n            $this->macroBuffer[] = compact('method', 'parameters');\n\n            return $this;\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/Relations/MorphToMany.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent\\Relations;\n\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Support\\Arr;\n\nclass MorphToMany extends BelongsToMany\n{\n    /**\n     * The type of the polymorphic relation.\n     *\n     * @var string\n     */\n    protected $morphType;\n\n    /**\n     * The class name of the morph type constraint.\n     *\n     * @var string\n     */\n    protected $morphClass;\n\n    /**\n     * Indicates if we are connecting the inverse of the relation.\n     *\n     * This primarily affects the morphClass constraint.\n     *\n     * @var bool\n     */\n    protected $inverse;\n\n    /**\n     * Create a new morph to many relationship instance.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $query\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $parent\n     * @param  string  $name\n     * @param  string  $table\n     * @param  string  $foreignPivotKey\n     * @param  string  $relatedPivotKey\n     * @param  string  $parentKey\n     * @param  string  $relatedKey\n     * @param  string|null  $relationName\n     * @param  bool  $inverse\n     * @return void\n     */\n    public function __construct(Builder $query, Model $parent, $name, $table, $foreignPivotKey,\n                                $relatedPivotKey, $parentKey, $relatedKey, $relationName = null, $inverse = false)\n    {\n        $this->inverse = $inverse;\n        $this->morphType = $name.'_type';\n        $this->morphClass = $inverse ? $query->getModel()->getMorphClass() : $parent->getMorphClass();\n\n        parent::__construct(\n            $query, $parent, $table, $foreignPivotKey,\n            $relatedPivotKey, $parentKey, $relatedKey, $relationName\n        );\n    }\n\n    /**\n     * Set the where clause for the relation query.\n     *\n     * @return $this\n     */\n    protected function addWhereConstraints()\n    {\n        parent::addWhereConstraints();\n\n        $this->query->where($this->qualifyPivotColumn($this->morphType), $this->morphClass);\n\n        return $this;\n    }\n\n    /**\n     * Set the constraints for an eager load of the relation.\n     *\n     * @param  array  $models\n     * @return void\n     */\n    public function addEagerConstraints(array $models)\n    {\n        parent::addEagerConstraints($models);\n\n        $this->query->where($this->qualifyPivotColumn($this->morphType), $this->morphClass);\n    }\n\n    /**\n     * Create a new pivot attachment record.\n     *\n     * @param  int  $id\n     * @param  bool  $timed\n     * @return array\n     */\n    protected function baseAttachRecord($id, $timed)\n    {\n        return Arr::add(\n            parent::baseAttachRecord($id, $timed), $this->morphType, $this->morphClass\n        );\n    }\n\n    /**\n     * Add the constraints for a relationship count query.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $query\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $parentQuery\n     * @param  array|mixed  $columns\n     * @return \\Illuminate\\Database\\Eloquent\\Builder\n     */\n    public function getRelationExistenceQuery(Builder $query, Builder $parentQuery, $columns = ['*'])\n    {\n        return parent::getRelationExistenceQuery($query, $parentQuery, $columns)->where(\n            $this->qualifyPivotColumn($this->morphType), $this->morphClass\n        );\n    }\n\n    /**\n     * Get the pivot models that are currently attached.\n     *\n     * @return \\Illuminate\\Support\\Collection\n     */\n    protected function getCurrentlyAttachedPivots()\n    {\n        return parent::getCurrentlyAttachedPivots()->map(function ($record) {\n            return $record instanceof MorphPivot\n                            ? $record->setMorphType($this->morphType)\n                                     ->setMorphClass($this->morphClass)\n                            : $record;\n        });\n    }\n\n    /**\n     * Create a new query builder for the pivot table.\n     *\n     * @return \\Illuminate\\Database\\Query\\Builder\n     */\n    public function newPivotQuery()\n    {\n        return parent::newPivotQuery()->where($this->morphType, $this->morphClass);\n    }\n\n    /**\n     * Create a new pivot model instance.\n     *\n     * @param  array  $attributes\n     * @param  bool  $exists\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\Pivot\n     */\n    public function newPivot(array $attributes = [], $exists = false)\n    {\n        $using = $this->using;\n\n        $pivot = $using ? $using::fromRawAttributes($this->parent, $attributes, $this->table, $exists)\n                        : MorphPivot::fromAttributes($this->parent, $attributes, $this->table, $exists);\n\n        $pivot->setPivotKeys($this->foreignPivotKey, $this->relatedPivotKey)\n              ->setMorphType($this->morphType)\n              ->setMorphClass($this->morphClass);\n\n        return $pivot;\n    }\n\n    /**\n     * Get the pivot columns for the relation.\n     *\n     * \"pivot_\" is prefixed at each column for easy removal later.\n     *\n     * @return array\n     */\n    protected function aliasedPivotColumns()\n    {\n        $defaults = [$this->foreignPivotKey, $this->relatedPivotKey, $this->morphType];\n\n        return collect(array_merge($defaults, $this->pivotColumns))->map(function ($column) {\n            return $this->qualifyPivotColumn($column).' as pivot_'.$column;\n        })->unique()->all();\n    }\n\n    /**\n     * Get the foreign key \"type\" name.\n     *\n     * @return string\n     */\n    public function getMorphType()\n    {\n        return $this->morphType;\n    }\n\n    /**\n     * Get the class name of the parent model.\n     *\n     * @return string\n     */\n    public function getMorphClass()\n    {\n        return $this->morphClass;\n    }\n\n    /**\n     * Get the indicator for a reverse relationship.\n     *\n     * @return bool\n     */\n    public function getInverse()\n    {\n        return $this->inverse;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/Relations/Pivot.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent\\Relations;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Database\\Eloquent\\Relations\\Concerns\\AsPivot;\n\nclass Pivot extends Model\n{\n    use AsPivot;\n\n    /**\n     * Indicates if the IDs are auto-incrementing.\n     *\n     * @var bool\n     */\n    public $incrementing = false;\n\n    /**\n     * The attributes that aren't mass assignable.\n     *\n     * @var array\n     */\n    protected $guarded = [];\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/Relations/Relation.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent\\Relations;\n\nuse Closure;\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Illuminate\\Database\\Eloquent\\Collection;\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Database\\Eloquent\\ModelNotFoundException;\nuse Illuminate\\Database\\MultipleRecordsFoundException;\nuse Illuminate\\Database\\Query\\Expression;\nuse Illuminate\\Support\\Arr;\nuse Illuminate\\Support\\Traits\\ForwardsCalls;\nuse Illuminate\\Support\\Traits\\Macroable;\n\n/**\n * @mixin \\Illuminate\\Database\\Eloquent\\Builder\n */\nabstract class Relation\n{\n    use ForwardsCalls, Macroable {\n        __call as macroCall;\n    }\n\n    /**\n     * The Eloquent query builder instance.\n     *\n     * @var \\Illuminate\\Database\\Eloquent\\Builder\n     */\n    protected $query;\n\n    /**\n     * The parent model instance.\n     *\n     * @var \\Illuminate\\Database\\Eloquent\\Model\n     */\n    protected $parent;\n\n    /**\n     * The related model instance.\n     *\n     * @var \\Illuminate\\Database\\Eloquent\\Model\n     */\n    protected $related;\n\n    /**\n     * Indicates if the relation is adding constraints.\n     *\n     * @var bool\n     */\n    protected static $constraints = true;\n\n    /**\n     * An array to map class names to their morph names in the database.\n     *\n     * @var array\n     */\n    public static $morphMap = [];\n\n    /**\n     * Prevents morph relationships without a morph map.\n     *\n     * @var bool\n     */\n    protected static $requireMorphMap = false;\n\n    /**\n     * The count of self joins.\n     *\n     * @var int\n     */\n    protected static $selfJoinCount = 0;\n\n    /**\n     * Create a new relation instance.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $query\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $parent\n     * @return void\n     */\n    public function __construct(Builder $query, Model $parent)\n    {\n        $this->query = $query;\n        $this->parent = $parent;\n        $this->related = $query->getModel();\n\n        $this->addConstraints();\n    }\n\n    /**\n     * Run a callback with constraints disabled on the relation.\n     *\n     * @param  \\Closure  $callback\n     * @return mixed\n     */\n    public static function noConstraints(Closure $callback)\n    {\n        $previous = static::$constraints;\n\n        static::$constraints = false;\n\n        // When resetting the relation where clause, we want to shift the first element\n        // off of the bindings, leaving only the constraints that the developers put\n        // as \"extra\" on the relationships, and not original relation constraints.\n        try {\n            return $callback();\n        } finally {\n            static::$constraints = $previous;\n        }\n    }\n\n    /**\n     * Set the base constraints on the relation query.\n     *\n     * @return void\n     */\n    abstract public function addConstraints();\n\n    /**\n     * Set the constraints for an eager load of the relation.\n     *\n     * @param  array  $models\n     * @return void\n     */\n    abstract public function addEagerConstraints(array $models);\n\n    /**\n     * Initialize the relation on a set of models.\n     *\n     * @param  array  $models\n     * @param  string  $relation\n     * @return array\n     */\n    abstract public function initRelation(array $models, $relation);\n\n    /**\n     * Match the eagerly loaded results to their parents.\n     *\n     * @param  array  $models\n     * @param  \\Illuminate\\Database\\Eloquent\\Collection  $results\n     * @param  string  $relation\n     * @return array\n     */\n    abstract public function match(array $models, Collection $results, $relation);\n\n    /**\n     * Get the results of the relationship.\n     *\n     * @return mixed\n     */\n    abstract public function getResults();\n\n    /**\n     * Get the relationship for eager loading.\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Collection\n     */\n    public function getEager()\n    {\n        return $this->get();\n    }\n\n    /**\n     * Execute the query and get the first result if it's the sole matching record.\n     *\n     * @param  array|string  $columns\n     * @return \\Illuminate\\Database\\Eloquent\\Model\n     *\n     * @throws \\Illuminate\\Database\\Eloquent\\ModelNotFoundException\n     * @throws \\Illuminate\\Database\\MultipleRecordsFoundException\n     */\n    public function sole($columns = ['*'])\n    {\n        $result = $this->take(2)->get($columns);\n\n        if ($result->isEmpty()) {\n            throw (new ModelNotFoundException)->setModel(get_class($this->related));\n        }\n\n        if ($result->count() > 1) {\n            throw new MultipleRecordsFoundException;\n        }\n\n        return $result->first();\n    }\n\n    /**\n     * Execute the query as a \"select\" statement.\n     *\n     * @param  array  $columns\n     * @return \\Illuminate\\Database\\Eloquent\\Collection\n     */\n    public function get($columns = ['*'])\n    {\n        return $this->query->get($columns);\n    }\n\n    /**\n     * Touch all of the related models for the relationship.\n     *\n     * @return void\n     */\n    public function touch()\n    {\n        $model = $this->getRelated();\n\n        if (! $model::isIgnoringTouch()) {\n            $this->rawUpdate([\n                $model->getUpdatedAtColumn() => $model->freshTimestampString(),\n            ]);\n        }\n    }\n\n    /**\n     * Run a raw update against the base query.\n     *\n     * @param  array  $attributes\n     * @return int\n     */\n    public function rawUpdate(array $attributes = [])\n    {\n        return $this->query->withoutGlobalScopes()->update($attributes);\n    }\n\n    /**\n     * Add the constraints for a relationship count query.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $query\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $parentQuery\n     * @return \\Illuminate\\Database\\Eloquent\\Builder\n     */\n    public function getRelationExistenceCountQuery(Builder $query, Builder $parentQuery)\n    {\n        return $this->getRelationExistenceQuery(\n            $query, $parentQuery, new Expression('count(*)')\n        )->setBindings([], 'select');\n    }\n\n    /**\n     * Add the constraints for an internal relationship existence query.\n     *\n     * Essentially, these queries compare on column names like whereColumn.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $query\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $parentQuery\n     * @param  array|mixed  $columns\n     * @return \\Illuminate\\Database\\Eloquent\\Builder\n     */\n    public function getRelationExistenceQuery(Builder $query, Builder $parentQuery, $columns = ['*'])\n    {\n        return $query->select($columns)->whereColumn(\n            $this->getQualifiedParentKeyName(), '=', $this->getExistenceCompareKey()\n        );\n    }\n\n    /**\n     * Get a relationship join table hash.\n     *\n     * @param  bool  $incrementJoinCount\n     * @return string\n     */\n    public function getRelationCountHash($incrementJoinCount = true)\n    {\n        return 'laravel_reserved_'.($incrementJoinCount ? static::$selfJoinCount++ : static::$selfJoinCount);\n    }\n\n    /**\n     * Get all of the primary keys for an array of models.\n     *\n     * @param  array  $models\n     * @param  string|null  $key\n     * @return array\n     */\n    protected function getKeys(array $models, $key = null)\n    {\n        return collect($models)->map(function ($value) use ($key) {\n            return $key ? $value->getAttribute($key) : $value->getKey();\n        })->values()->unique(null, true)->sort()->all();\n    }\n\n    /**\n     * Get the query builder that will contain the relationship constraints.\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Builder\n     */\n    protected function getRelationQuery()\n    {\n        return $this->query;\n    }\n\n    /**\n     * Get the underlying query for the relation.\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Builder\n     */\n    public function getQuery()\n    {\n        return $this->query;\n    }\n\n    /**\n     * Get the base query builder driving the Eloquent builder.\n     *\n     * @return \\Illuminate\\Database\\Query\\Builder\n     */\n    public function getBaseQuery()\n    {\n        return $this->query->getQuery();\n    }\n\n    /**\n     * Get the parent model of the relation.\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Model\n     */\n    public function getParent()\n    {\n        return $this->parent;\n    }\n\n    /**\n     * Get the fully qualified parent key name.\n     *\n     * @return string\n     */\n    public function getQualifiedParentKeyName()\n    {\n        return $this->parent->getQualifiedKeyName();\n    }\n\n    /**\n     * Get the related model of the relation.\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Model\n     */\n    public function getRelated()\n    {\n        return $this->related;\n    }\n\n    /**\n     * Get the name of the \"created at\" column.\n     *\n     * @return string\n     */\n    public function createdAt()\n    {\n        return $this->parent->getCreatedAtColumn();\n    }\n\n    /**\n     * Get the name of the \"updated at\" column.\n     *\n     * @return string\n     */\n    public function updatedAt()\n    {\n        return $this->parent->getUpdatedAtColumn();\n    }\n\n    /**\n     * Get the name of the related model's \"updated at\" column.\n     *\n     * @return string\n     */\n    public function relatedUpdatedAt()\n    {\n        return $this->related->getUpdatedAtColumn();\n    }\n\n    /**\n     * Get the name of the \"where in\" method for eager loading.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $model\n     * @param  string  $key\n     * @return string\n     */\n    protected function whereInMethod(Model $model, $key)\n    {\n        return $model->getKeyName() === last(explode('.', $key))\n                    && in_array($model->getKeyType(), ['int', 'integer'])\n                        ? 'whereIntegerInRaw'\n                        : 'whereIn';\n    }\n\n    /**\n     * Prevent polymorphic relationships from being used without model mappings.\n     *\n     * @param  bool  $requireMorphMap\n     * @return void\n     */\n    public static function requireMorphMap($requireMorphMap = true)\n    {\n        static::$requireMorphMap = $requireMorphMap;\n    }\n\n    /**\n     * Determine if polymorphic relationships require explicit model mapping.\n     *\n     * @return bool\n     */\n    public static function requiresMorphMap()\n    {\n        return static::$requireMorphMap;\n    }\n\n    /**\n     * Define the morph map for polymorphic relations and require all morphed models to be explicitly mapped.\n     *\n     * @param  array  $map\n     * @param  bool  $merge\n     * @return array\n     */\n    public static function enforceMorphMap(array $map, $merge = true)\n    {\n        static::requireMorphMap();\n\n        return static::morphMap($map, $merge);\n    }\n\n    /**\n     * Set or get the morph map for polymorphic relations.\n     *\n     * @param  array|null  $map\n     * @param  bool  $merge\n     * @return array\n     */\n    public static function morphMap(array $map = null, $merge = true)\n    {\n        $map = static::buildMorphMapFromModels($map);\n\n        if (is_array($map)) {\n            static::$morphMap = $merge && static::$morphMap\n                            ? $map + static::$morphMap : $map;\n        }\n\n        return static::$morphMap;\n    }\n\n    /**\n     * Builds a table-keyed array from model class names.\n     *\n     * @param  string[]|null  $models\n     * @return array|null\n     */\n    protected static function buildMorphMapFromModels(array $models = null)\n    {\n        if (is_null($models) || Arr::isAssoc($models)) {\n            return $models;\n        }\n\n        return array_combine(array_map(function ($model) {\n            return (new $model)->getTable();\n        }, $models), $models);\n    }\n\n    /**\n     * Get the model associated with a custom polymorphic type.\n     *\n     * @param  string  $alias\n     * @return string|null\n     */\n    public static function getMorphedModel($alias)\n    {\n        return static::$morphMap[$alias] ?? null;\n    }\n\n    /**\n     * Handle dynamic method calls to the relationship.\n     *\n     * @param  string  $method\n     * @param  array  $parameters\n     * @return mixed\n     */\n    public function __call($method, $parameters)\n    {\n        if (static::hasMacro($method)) {\n            return $this->macroCall($method, $parameters);\n        }\n\n        return $this->forwardDecoratedCallTo($this->query, $method, $parameters);\n    }\n\n    /**\n     * Force a clone of the underlying query builder when cloning.\n     *\n     * @return void\n     */\n    public function __clone()\n    {\n        $this->query = clone $this->query;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/Scope.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent;\n\ninterface Scope\n{\n    /**\n     * Apply the scope to a given Eloquent query builder.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $builder\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $model\n     * @return void\n     */\n    public function apply(Builder $builder, Model $model);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/SoftDeletes.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent;\n\n/**\n * @method static static|\\Illuminate\\Database\\Eloquent\\Builder|\\Illuminate\\Database\\Query\\Builder withTrashed(bool $withTrashed = true)\n * @method static static|\\Illuminate\\Database\\Eloquent\\Builder|\\Illuminate\\Database\\Query\\Builder onlyTrashed()\n * @method static static|\\Illuminate\\Database\\Eloquent\\Builder|\\Illuminate\\Database\\Query\\Builder withoutTrashed()\n */\ntrait SoftDeletes\n{\n    /**\n     * Indicates if the model is currently force deleting.\n     *\n     * @var bool\n     */\n    protected $forceDeleting = false;\n\n    /**\n     * Boot the soft deleting trait for a model.\n     *\n     * @return void\n     */\n    public static function bootSoftDeletes()\n    {\n        static::addGlobalScope(new SoftDeletingScope);\n    }\n\n    /**\n     * Initialize the soft deleting trait for an instance.\n     *\n     * @return void\n     */\n    public function initializeSoftDeletes()\n    {\n        if (! isset($this->casts[$this->getDeletedAtColumn()])) {\n            $this->casts[$this->getDeletedAtColumn()] = 'datetime';\n        }\n    }\n\n    /**\n     * Force a hard delete on a soft deleted model.\n     *\n     * @return bool|null\n     */\n    public function forceDelete()\n    {\n        $this->forceDeleting = true;\n\n        return tap($this->delete(), function ($deleted) {\n            $this->forceDeleting = false;\n\n            if ($deleted) {\n                $this->fireModelEvent('forceDeleted', false);\n            }\n        });\n    }\n\n    /**\n     * Perform the actual delete query on this model instance.\n     *\n     * @return mixed\n     */\n    protected function performDeleteOnModel()\n    {\n        if ($this->forceDeleting) {\n            return tap($this->setKeysForSaveQuery($this->newModelQuery())->forceDelete(), function () {\n                $this->exists = false;\n            });\n        }\n\n        return $this->runSoftDelete();\n    }\n\n    /**\n     * Perform the actual delete query on this model instance.\n     *\n     * @return void\n     */\n    protected function runSoftDelete()\n    {\n        $query = $this->setKeysForSaveQuery($this->newModelQuery());\n\n        $time = $this->freshTimestamp();\n\n        $columns = [$this->getDeletedAtColumn() => $this->fromDateTime($time)];\n\n        $this->{$this->getDeletedAtColumn()} = $time;\n\n        if ($this->timestamps && ! is_null($this->getUpdatedAtColumn())) {\n            $this->{$this->getUpdatedAtColumn()} = $time;\n\n            $columns[$this->getUpdatedAtColumn()] = $this->fromDateTime($time);\n        }\n\n        $query->update($columns);\n\n        $this->syncOriginalAttributes(array_keys($columns));\n\n        $this->fireModelEvent('trashed', false);\n    }\n\n    /**\n     * Restore a soft-deleted model instance.\n     *\n     * @return bool|null\n     */\n    public function restore()\n    {\n        // If the restoring event does not return false, we will proceed with this\n        // restore operation. Otherwise, we bail out so the developer will stop\n        // the restore totally. We will clear the deleted timestamp and save.\n        if ($this->fireModelEvent('restoring') === false) {\n            return false;\n        }\n\n        $this->{$this->getDeletedAtColumn()} = null;\n\n        // Once we have saved the model, we will fire the \"restored\" event so this\n        // developer will do anything they need to after a restore operation is\n        // totally finished. Then we will return the result of the save call.\n        $this->exists = true;\n\n        $result = $this->save();\n\n        $this->fireModelEvent('restored', false);\n\n        return $result;\n    }\n\n    /**\n     * Determine if the model instance has been soft-deleted.\n     *\n     * @return bool\n     */\n    public function trashed()\n    {\n        return ! is_null($this->{$this->getDeletedAtColumn()});\n    }\n\n    /**\n     * Register a \"softDeleted\" model event callback with the dispatcher.\n     *\n     * @param  \\Closure|string  $callback\n     * @return void\n     */\n    public static function softDeleted($callback)\n    {\n        static::registerModelEvent('trashed', $callback);\n    }\n\n    /**\n     * Register a \"restoring\" model event callback with the dispatcher.\n     *\n     * @param  \\Closure|string  $callback\n     * @return void\n     */\n    public static function restoring($callback)\n    {\n        static::registerModelEvent('restoring', $callback);\n    }\n\n    /**\n     * Register a \"restored\" model event callback with the dispatcher.\n     *\n     * @param  \\Closure|string  $callback\n     * @return void\n     */\n    public static function restored($callback)\n    {\n        static::registerModelEvent('restored', $callback);\n    }\n\n    /**\n     * Register a \"forceDeleted\" model event callback with the dispatcher.\n     *\n     * @param  \\Closure|string  $callback\n     * @return void\n     */\n    public static function forceDeleted($callback)\n    {\n        static::registerModelEvent('forceDeleted', $callback);\n    }\n\n    /**\n     * Determine if the model is currently force deleting.\n     *\n     * @return bool\n     */\n    public function isForceDeleting()\n    {\n        return $this->forceDeleting;\n    }\n\n    /**\n     * Get the name of the \"deleted at\" column.\n     *\n     * @return string\n     */\n    public function getDeletedAtColumn()\n    {\n        return defined('static::DELETED_AT') ? static::DELETED_AT : 'deleted_at';\n    }\n\n    /**\n     * Get the fully qualified \"deleted at\" column.\n     *\n     * @return string\n     */\n    public function getQualifiedDeletedAtColumn()\n    {\n        return $this->qualifyColumn($this->getDeletedAtColumn());\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Eloquent/SoftDeletingScope.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Eloquent;\n\nclass SoftDeletingScope implements Scope\n{\n    /**\n     * All of the extensions to be added to the builder.\n     *\n     * @var string[]\n     */\n    protected $extensions = ['Restore', 'WithTrashed', 'WithoutTrashed', 'OnlyTrashed'];\n\n    /**\n     * Apply the scope to a given Eloquent query builder.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $builder\n     * @param  \\Illuminate\\Database\\Eloquent\\Model  $model\n     * @return void\n     */\n    public function apply(Builder $builder, Model $model)\n    {\n        $builder->whereNull($model->getQualifiedDeletedAtColumn());\n    }\n\n    /**\n     * Extend the query builder with the needed functions.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $builder\n     * @return void\n     */\n    public function extend(Builder $builder)\n    {\n        foreach ($this->extensions as $extension) {\n            $this->{\"add{$extension}\"}($builder);\n        }\n\n        $builder->onDelete(function (Builder $builder) {\n            $column = $this->getDeletedAtColumn($builder);\n\n            return $builder->update([\n                $column => $builder->getModel()->freshTimestampString(),\n            ]);\n        });\n    }\n\n    /**\n     * Get the \"deleted at\" column for the builder.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $builder\n     * @return string\n     */\n    protected function getDeletedAtColumn(Builder $builder)\n    {\n        if (count((array) $builder->getQuery()->joins) > 0) {\n            return $builder->getModel()->getQualifiedDeletedAtColumn();\n        }\n\n        return $builder->getModel()->getDeletedAtColumn();\n    }\n\n    /**\n     * Add the restore extension to the builder.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $builder\n     * @return void\n     */\n    protected function addRestore(Builder $builder)\n    {\n        $builder->macro('restore', function (Builder $builder) {\n            $builder->withTrashed();\n\n            return $builder->update([$builder->getModel()->getDeletedAtColumn() => null]);\n        });\n    }\n\n    /**\n     * Add the with-trashed extension to the builder.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $builder\n     * @return void\n     */\n    protected function addWithTrashed(Builder $builder)\n    {\n        $builder->macro('withTrashed', function (Builder $builder, $withTrashed = true) {\n            if (! $withTrashed) {\n                return $builder->withoutTrashed();\n            }\n\n            return $builder->withoutGlobalScope($this);\n        });\n    }\n\n    /**\n     * Add the without-trashed extension to the builder.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $builder\n     * @return void\n     */\n    protected function addWithoutTrashed(Builder $builder)\n    {\n        $builder->macro('withoutTrashed', function (Builder $builder) {\n            $model = $builder->getModel();\n\n            $builder->withoutGlobalScope($this)->whereNull(\n                $model->getQualifiedDeletedAtColumn()\n            );\n\n            return $builder;\n        });\n    }\n\n    /**\n     * Add the only-trashed extension to the builder.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Builder  $builder\n     * @return void\n     */\n    protected function addOnlyTrashed(Builder $builder)\n    {\n        $builder->macro('onlyTrashed', function (Builder $builder) {\n            $model = $builder->getModel();\n\n            $builder->withoutGlobalScope($this)->whereNotNull(\n                $model->getQualifiedDeletedAtColumn()\n            );\n\n            return $builder;\n        });\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Events/ConnectionEvent.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Events;\n\nabstract class ConnectionEvent\n{\n    /**\n     * The name of the connection.\n     *\n     * @var string\n     */\n    public $connectionName;\n\n    /**\n     * The database connection instance.\n     *\n     * @var \\Illuminate\\Database\\Connection\n     */\n    public $connection;\n\n    /**\n     * Create a new event instance.\n     *\n     * @param  \\Illuminate\\Database\\Connection  $connection\n     * @return void\n     */\n    public function __construct($connection)\n    {\n        $this->connection = $connection;\n        $this->connectionName = $connection->getName();\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Events/DatabaseRefreshed.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Events;\n\nuse Illuminate\\Contracts\\Database\\Events\\MigrationEvent as MigrationEventContract;\n\nclass DatabaseRefreshed implements MigrationEventContract\n{\n    //\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Events/MigrationEnded.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Events;\n\nclass MigrationEnded extends MigrationEvent\n{\n    //\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Events/MigrationEvent.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Events;\n\nuse Illuminate\\Contracts\\Database\\Events\\MigrationEvent as MigrationEventContract;\nuse Illuminate\\Database\\Migrations\\Migration;\n\nabstract class MigrationEvent implements MigrationEventContract\n{\n    /**\n     * A migration instance.\n     *\n     * @var \\Illuminate\\Database\\Migrations\\Migration\n     */\n    public $migration;\n\n    /**\n     * The migration method that was called.\n     *\n     * @var string\n     */\n    public $method;\n\n    /**\n     * Create a new event instance.\n     *\n     * @param  \\Illuminate\\Database\\Migrations\\Migration  $migration\n     * @param  string  $method\n     * @return void\n     */\n    public function __construct(Migration $migration, $method)\n    {\n        $this->method = $method;\n        $this->migration = $migration;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Events/MigrationStarted.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Events;\n\nclass MigrationStarted extends MigrationEvent\n{\n    //\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Events/MigrationsEnded.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Events;\n\nclass MigrationsEnded extends MigrationsEvent\n{\n    //\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Events/MigrationsEvent.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Events;\n\nuse Illuminate\\Contracts\\Database\\Events\\MigrationEvent as MigrationEventContract;\n\nabstract class MigrationsEvent implements MigrationEventContract\n{\n    /**\n     * The migration method that was invoked.\n     *\n     * @var string\n     */\n    public $method;\n\n    /**\n     * Create a new event instance.\n     *\n     * @param  string  $method\n     * @return void\n     */\n    public function __construct($method)\n    {\n        $this->method = $method;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Events/MigrationsStarted.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Events;\n\nclass MigrationsStarted extends MigrationsEvent\n{\n    //\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Events/ModelsPruned.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Events;\n\nclass ModelsPruned\n{\n    /**\n     * The class name of the model that was pruned.\n     *\n     * @var string\n     */\n    public $model;\n\n    /**\n     * The number of pruned records.\n     *\n     * @var int\n     */\n    public $count;\n\n    /**\n     * Create a new event instance.\n     *\n     * @param  string  $model\n     * @param  int  $count\n     * @return void\n     */\n    public function __construct($model, $count)\n    {\n        $this->model = $model;\n        $this->count = $count;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Events/NoPendingMigrations.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Events;\n\nclass NoPendingMigrations\n{\n    /**\n     * The migration method that was called.\n     *\n     * @var string\n     */\n    public $method;\n\n    /**\n     * Create a new event instance.\n     *\n     * @param  string  $method\n     * @return void\n     */\n    public function __construct($method)\n    {\n        $this->method = $method;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Events/QueryExecuted.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Events;\n\nclass QueryExecuted\n{\n    /**\n     * The SQL query that was executed.\n     *\n     * @var string\n     */\n    public $sql;\n\n    /**\n     * The array of query bindings.\n     *\n     * @var array\n     */\n    public $bindings;\n\n    /**\n     * The number of milliseconds it took to execute the query.\n     *\n     * @var float\n     */\n    public $time;\n\n    /**\n     * The database connection instance.\n     *\n     * @var \\Illuminate\\Database\\Connection\n     */\n    public $connection;\n\n    /**\n     * The database connection name.\n     *\n     * @var string\n     */\n    public $connectionName;\n\n    /**\n     * Create a new event instance.\n     *\n     * @param  string  $sql\n     * @param  array  $bindings\n     * @param  float|null  $time\n     * @param  \\Illuminate\\Database\\Connection  $connection\n     * @return void\n     */\n    public function __construct($sql, $bindings, $time, $connection)\n    {\n        $this->sql = $sql;\n        $this->time = $time;\n        $this->bindings = $bindings;\n        $this->connection = $connection;\n        $this->connectionName = $connection->getName();\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Events/SchemaDumped.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Events;\n\nclass SchemaDumped\n{\n    /**\n     * The database connection instance.\n     *\n     * @var \\Illuminate\\Database\\Connection\n     */\n    public $connection;\n\n    /**\n     * The database connection name.\n     *\n     * @var string\n     */\n    public $connectionName;\n\n    /**\n     * The path to the schema dump.\n     *\n     * @var string\n     */\n    public $path;\n\n    /**\n     * Create a new event instance.\n     *\n     * @param  \\Illuminate\\Database\\Connection  $connection\n     * @param  string  $path\n     * @return void\n     */\n    public function __construct($connection, $path)\n    {\n        $this->connection = $connection;\n        $this->connectionName = $connection->getName();\n        $this->path = $path;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Events/SchemaLoaded.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Events;\n\nclass SchemaLoaded\n{\n    /**\n     * The database connection instance.\n     *\n     * @var \\Illuminate\\Database\\Connection\n     */\n    public $connection;\n\n    /**\n     * The database connection name.\n     *\n     * @var string\n     */\n    public $connectionName;\n\n    /**\n     * The path to the schema dump.\n     *\n     * @var string\n     */\n    public $path;\n\n    /**\n     * Create a new event instance.\n     *\n     * @param  \\Illuminate\\Database\\Connection  $connection\n     * @param  string  $path\n     * @return void\n     */\n    public function __construct($connection, $path)\n    {\n        $this->connection = $connection;\n        $this->connectionName = $connection->getName();\n        $this->path = $path;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Events/StatementPrepared.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Events;\n\nclass StatementPrepared\n{\n    /**\n     * The database connection instance.\n     *\n     * @var \\Illuminate\\Database\\Connection\n     */\n    public $connection;\n\n    /**\n     * The PDO statement.\n     *\n     * @var \\PDOStatement\n     */\n    public $statement;\n\n    /**\n     * Create a new event instance.\n     *\n     * @param  \\Illuminate\\Database\\Connection  $connection\n     * @param  \\PDOStatement  $statement\n     * @return void\n     */\n    public function __construct($connection, $statement)\n    {\n        $this->statement = $statement;\n        $this->connection = $connection;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Events/TransactionBeginning.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Events;\n\nclass TransactionBeginning extends ConnectionEvent\n{\n    //\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Events/TransactionCommitted.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Events;\n\nclass TransactionCommitted extends ConnectionEvent\n{\n    //\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Events/TransactionRolledBack.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Events;\n\nclass TransactionRolledBack extends ConnectionEvent\n{\n    //\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Grammar.php",
    "content": "<?php\n\nnamespace Illuminate\\Database;\n\nuse Illuminate\\Database\\Query\\Expression;\nuse Illuminate\\Support\\Traits\\Macroable;\n\nabstract class Grammar\n{\n    use Macroable;\n\n    /**\n     * The grammar table prefix.\n     *\n     * @var string\n     */\n    protected $tablePrefix = '';\n\n    /**\n     * Wrap an array of values.\n     *\n     * @param  array  $values\n     * @return array\n     */\n    public function wrapArray(array $values)\n    {\n        return array_map([$this, 'wrap'], $values);\n    }\n\n    /**\n     * Wrap a table in keyword identifiers.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Expression|string  $table\n     * @return string\n     */\n    public function wrapTable($table)\n    {\n        if (! $this->isExpression($table)) {\n            return $this->wrap($this->tablePrefix.$table, true);\n        }\n\n        return $this->getValue($table);\n    }\n\n    /**\n     * Wrap a value in keyword identifiers.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Expression|string  $value\n     * @param  bool  $prefixAlias\n     * @return string\n     */\n    public function wrap($value, $prefixAlias = false)\n    {\n        if ($this->isExpression($value)) {\n            return $this->getValue($value);\n        }\n\n        // If the value being wrapped has a column alias we will need to separate out\n        // the pieces so we can wrap each of the segments of the expression on its\n        // own, and then join these both back together using the \"as\" connector.\n        if (stripos($value, ' as ') !== false) {\n            return $this->wrapAliasedValue($value, $prefixAlias);\n        }\n\n        return $this->wrapSegments(explode('.', $value));\n    }\n\n    /**\n     * Wrap a value that has an alias.\n     *\n     * @param  string  $value\n     * @param  bool  $prefixAlias\n     * @return string\n     */\n    protected function wrapAliasedValue($value, $prefixAlias = false)\n    {\n        $segments = preg_split('/\\s+as\\s+/i', $value);\n\n        // If we are wrapping a table we need to prefix the alias with the table prefix\n        // as well in order to generate proper syntax. If this is a column of course\n        // no prefix is necessary. The condition will be true when from wrapTable.\n        if ($prefixAlias) {\n            $segments[1] = $this->tablePrefix.$segments[1];\n        }\n\n        return $this->wrap($segments[0]).' as '.$this->wrapValue($segments[1]);\n    }\n\n    /**\n     * Wrap the given value segments.\n     *\n     * @param  array  $segments\n     * @return string\n     */\n    protected function wrapSegments($segments)\n    {\n        return collect($segments)->map(function ($segment, $key) use ($segments) {\n            return $key == 0 && count($segments) > 1\n                            ? $this->wrapTable($segment)\n                            : $this->wrapValue($segment);\n        })->implode('.');\n    }\n\n    /**\n     * Wrap a single string in keyword identifiers.\n     *\n     * @param  string  $value\n     * @return string\n     */\n    protected function wrapValue($value)\n    {\n        if ($value !== '*') {\n            return '\"'.str_replace('\"', '\"\"', $value).'\"';\n        }\n\n        return $value;\n    }\n\n    /**\n     * Convert an array of column names into a delimited string.\n     *\n     * @param  array  $columns\n     * @return string\n     */\n    public function columnize(array $columns)\n    {\n        return implode(', ', array_map([$this, 'wrap'], $columns));\n    }\n\n    /**\n     * Create query parameter place-holders for an array.\n     *\n     * @param  array  $values\n     * @return string\n     */\n    public function parameterize(array $values)\n    {\n        return implode(', ', array_map([$this, 'parameter'], $values));\n    }\n\n    /**\n     * Get the appropriate query parameter place-holder for a value.\n     *\n     * @param  mixed  $value\n     * @return string\n     */\n    public function parameter($value)\n    {\n        return $this->isExpression($value) ? $this->getValue($value) : '?';\n    }\n\n    /**\n     * Quote the given string literal.\n     *\n     * @param  string|array  $value\n     * @return string\n     */\n    public function quoteString($value)\n    {\n        if (is_array($value)) {\n            return implode(', ', array_map([$this, __FUNCTION__], $value));\n        }\n\n        return \"'$value'\";\n    }\n\n    /**\n     * Determine if the given value is a raw expression.\n     *\n     * @param  mixed  $value\n     * @return bool\n     */\n    public function isExpression($value)\n    {\n        return $value instanceof Expression;\n    }\n\n    /**\n     * Get the value of a raw expression.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Expression  $expression\n     * @return mixed\n     */\n    public function getValue($expression)\n    {\n        return $expression->getValue();\n    }\n\n    /**\n     * Get the format for database stored dates.\n     *\n     * @return string\n     */\n    public function getDateFormat()\n    {\n        return 'Y-m-d H:i:s';\n    }\n\n    /**\n     * Get the grammar's table prefix.\n     *\n     * @return string\n     */\n    public function getTablePrefix()\n    {\n        return $this->tablePrefix;\n    }\n\n    /**\n     * Set the grammar's table prefix.\n     *\n     * @param  string  $prefix\n     * @return $this\n     */\n    public function setTablePrefix($prefix)\n    {\n        $this->tablePrefix = $prefix;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/LICENSE.md",
    "content": "The MIT License (MIT)\n\nCopyright (c) Taylor Otwell\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "server/vendor/illuminate/database/LazyLoadingViolationException.php",
    "content": "<?php\n\nnamespace Illuminate\\Database;\n\nuse RuntimeException;\n\nclass LazyLoadingViolationException extends RuntimeException\n{\n    /**\n     * The name of the affected Eloquent model.\n     *\n     * @var string\n     */\n    public $model;\n\n    /**\n     * The name of the relation.\n     *\n     * @var string\n     */\n    public $relation;\n\n    /**\n     * Create a new exception instance.\n     *\n     * @param  object  $model\n     * @param  string  $relation\n     * @return static\n     */\n    public function __construct($model, $relation)\n    {\n        $class = get_class($model);\n\n        parent::__construct(\"Attempted to lazy load [{$relation}] on model [{$class}] but lazy loading is disabled.\");\n\n        $this->model = $class;\n        $this->relation = $relation;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/MigrationServiceProvider.php",
    "content": "<?php\n\nnamespace Illuminate\\Database;\n\nuse Illuminate\\Contracts\\Events\\Dispatcher;\nuse Illuminate\\Contracts\\Support\\DeferrableProvider;\nuse Illuminate\\Database\\Console\\Migrations\\FreshCommand;\nuse Illuminate\\Database\\Console\\Migrations\\InstallCommand;\nuse Illuminate\\Database\\Console\\Migrations\\MigrateCommand;\nuse Illuminate\\Database\\Console\\Migrations\\MigrateMakeCommand;\nuse Illuminate\\Database\\Console\\Migrations\\RefreshCommand;\nuse Illuminate\\Database\\Console\\Migrations\\ResetCommand;\nuse Illuminate\\Database\\Console\\Migrations\\RollbackCommand;\nuse Illuminate\\Database\\Console\\Migrations\\StatusCommand;\nuse Illuminate\\Database\\Migrations\\DatabaseMigrationRepository;\nuse Illuminate\\Database\\Migrations\\MigrationCreator;\nuse Illuminate\\Database\\Migrations\\Migrator;\nuse Illuminate\\Support\\ServiceProvider;\n\nclass MigrationServiceProvider extends ServiceProvider implements DeferrableProvider\n{\n    /**\n     * The commands to be registered.\n     *\n     * @var array\n     */\n    protected $commands = [\n        'Migrate' => 'command.migrate',\n        'MigrateFresh' => 'command.migrate.fresh',\n        'MigrateInstall' => 'command.migrate.install',\n        'MigrateRefresh' => 'command.migrate.refresh',\n        'MigrateReset' => 'command.migrate.reset',\n        'MigrateRollback' => 'command.migrate.rollback',\n        'MigrateStatus' => 'command.migrate.status',\n        'MigrateMake' => 'command.migrate.make',\n    ];\n\n    /**\n     * Register the service provider.\n     *\n     * @return void\n     */\n    public function register()\n    {\n        $this->registerRepository();\n\n        $this->registerMigrator();\n\n        $this->registerCreator();\n\n        $this->registerCommands($this->commands);\n    }\n\n    /**\n     * Register the migration repository service.\n     *\n     * @return void\n     */\n    protected function registerRepository()\n    {\n        $this->app->singleton('migration.repository', function ($app) {\n            $table = $app['config']['database.migrations'];\n\n            return new DatabaseMigrationRepository($app['db'], $table);\n        });\n    }\n\n    /**\n     * Register the migrator service.\n     *\n     * @return void\n     */\n    protected function registerMigrator()\n    {\n        // The migrator is responsible for actually running and rollback the migration\n        // files in the application. We'll pass in our database connection resolver\n        // so the migrator can resolve any of these connections when it needs to.\n        $this->app->singleton('migrator', function ($app) {\n            $repository = $app['migration.repository'];\n\n            return new Migrator($repository, $app['db'], $app['files'], $app['events']);\n        });\n    }\n\n    /**\n     * Register the migration creator.\n     *\n     * @return void\n     */\n    protected function registerCreator()\n    {\n        $this->app->singleton('migration.creator', function ($app) {\n            return new MigrationCreator($app['files'], $app->basePath('stubs'));\n        });\n    }\n\n    /**\n     * Register the given commands.\n     *\n     * @param  array  $commands\n     * @return void\n     */\n    protected function registerCommands(array $commands)\n    {\n        foreach (array_keys($commands) as $command) {\n            $this->{\"register{$command}Command\"}();\n        }\n\n        $this->commands(array_values($commands));\n    }\n\n    /**\n     * Register the command.\n     *\n     * @return void\n     */\n    protected function registerMigrateCommand()\n    {\n        $this->app->singleton('command.migrate', function ($app) {\n            return new MigrateCommand($app['migrator'], $app[Dispatcher::class]);\n        });\n    }\n\n    /**\n     * Register the command.\n     *\n     * @return void\n     */\n    protected function registerMigrateFreshCommand()\n    {\n        $this->app->singleton('command.migrate.fresh', function () {\n            return new FreshCommand;\n        });\n    }\n\n    /**\n     * Register the command.\n     *\n     * @return void\n     */\n    protected function registerMigrateInstallCommand()\n    {\n        $this->app->singleton('command.migrate.install', function ($app) {\n            return new InstallCommand($app['migration.repository']);\n        });\n    }\n\n    /**\n     * Register the command.\n     *\n     * @return void\n     */\n    protected function registerMigrateMakeCommand()\n    {\n        $this->app->singleton('command.migrate.make', function ($app) {\n            // Once we have the migration creator registered, we will create the command\n            // and inject the creator. The creator is responsible for the actual file\n            // creation of the migrations, and may be extended by these developers.\n            $creator = $app['migration.creator'];\n\n            $composer = $app['composer'];\n\n            return new MigrateMakeCommand($creator, $composer);\n        });\n    }\n\n    /**\n     * Register the command.\n     *\n     * @return void\n     */\n    protected function registerMigrateRefreshCommand()\n    {\n        $this->app->singleton('command.migrate.refresh', function () {\n            return new RefreshCommand;\n        });\n    }\n\n    /**\n     * Register the command.\n     *\n     * @return void\n     */\n    protected function registerMigrateResetCommand()\n    {\n        $this->app->singleton('command.migrate.reset', function ($app) {\n            return new ResetCommand($app['migrator']);\n        });\n    }\n\n    /**\n     * Register the command.\n     *\n     * @return void\n     */\n    protected function registerMigrateRollbackCommand()\n    {\n        $this->app->singleton('command.migrate.rollback', function ($app) {\n            return new RollbackCommand($app['migrator']);\n        });\n    }\n\n    /**\n     * Register the command.\n     *\n     * @return void\n     */\n    protected function registerMigrateStatusCommand()\n    {\n        $this->app->singleton('command.migrate.status', function ($app) {\n            return new StatusCommand($app['migrator']);\n        });\n    }\n\n    /**\n     * Get the services provided by the provider.\n     *\n     * @return array\n     */\n    public function provides()\n    {\n        return array_merge([\n            'migrator', 'migration.repository', 'migration.creator',\n        ], array_values($this->commands));\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Migrations/DatabaseMigrationRepository.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Migrations;\n\nuse Illuminate\\Database\\ConnectionResolverInterface as Resolver;\n\nclass DatabaseMigrationRepository implements MigrationRepositoryInterface\n{\n    /**\n     * The database connection resolver instance.\n     *\n     * @var \\Illuminate\\Database\\ConnectionResolverInterface\n     */\n    protected $resolver;\n\n    /**\n     * The name of the migration table.\n     *\n     * @var string\n     */\n    protected $table;\n\n    /**\n     * The name of the database connection to use.\n     *\n     * @var string\n     */\n    protected $connection;\n\n    /**\n     * Create a new database migration repository instance.\n     *\n     * @param  \\Illuminate\\Database\\ConnectionResolverInterface  $resolver\n     * @param  string  $table\n     * @return void\n     */\n    public function __construct(Resolver $resolver, $table)\n    {\n        $this->table = $table;\n        $this->resolver = $resolver;\n    }\n\n    /**\n     * Get the completed migrations.\n     *\n     * @return array\n     */\n    public function getRan()\n    {\n        return $this->table()\n                ->orderBy('batch', 'asc')\n                ->orderBy('migration', 'asc')\n                ->pluck('migration')->all();\n    }\n\n    /**\n     * Get list of migrations.\n     *\n     * @param  int  $steps\n     * @return array\n     */\n    public function getMigrations($steps)\n    {\n        $query = $this->table()->where('batch', '>=', '1');\n\n        return $query->orderBy('batch', 'desc')\n                     ->orderBy('migration', 'desc')\n                     ->take($steps)->get()->all();\n    }\n\n    /**\n     * Get the last migration batch.\n     *\n     * @return array\n     */\n    public function getLast()\n    {\n        $query = $this->table()->where('batch', $this->getLastBatchNumber());\n\n        return $query->orderBy('migration', 'desc')->get()->all();\n    }\n\n    /**\n     * Get the completed migrations with their batch numbers.\n     *\n     * @return array\n     */\n    public function getMigrationBatches()\n    {\n        return $this->table()\n                ->orderBy('batch', 'asc')\n                ->orderBy('migration', 'asc')\n                ->pluck('batch', 'migration')->all();\n    }\n\n    /**\n     * Log that a migration was run.\n     *\n     * @param  string  $file\n     * @param  int  $batch\n     * @return void\n     */\n    public function log($file, $batch)\n    {\n        $record = ['migration' => $file, 'batch' => $batch];\n\n        $this->table()->insert($record);\n    }\n\n    /**\n     * Remove a migration from the log.\n     *\n     * @param  object  $migration\n     * @return void\n     */\n    public function delete($migration)\n    {\n        $this->table()->where('migration', $migration->migration)->delete();\n    }\n\n    /**\n     * Get the next migration batch number.\n     *\n     * @return int\n     */\n    public function getNextBatchNumber()\n    {\n        return $this->getLastBatchNumber() + 1;\n    }\n\n    /**\n     * Get the last migration batch number.\n     *\n     * @return int\n     */\n    public function getLastBatchNumber()\n    {\n        return $this->table()->max('batch');\n    }\n\n    /**\n     * Create the migration repository data store.\n     *\n     * @return void\n     */\n    public function createRepository()\n    {\n        $schema = $this->getConnection()->getSchemaBuilder();\n\n        $schema->create($this->table, function ($table) {\n            // The migrations table is responsible for keeping track of which of the\n            // migrations have actually run for the application. We'll create the\n            // table to hold the migration file's path as well as the batch ID.\n            $table->increments('id');\n            $table->string('migration');\n            $table->integer('batch');\n        });\n    }\n\n    /**\n     * Determine if the migration repository exists.\n     *\n     * @return bool\n     */\n    public function repositoryExists()\n    {\n        $schema = $this->getConnection()->getSchemaBuilder();\n\n        return $schema->hasTable($this->table);\n    }\n\n    /**\n     * Delete the migration repository data store.\n     *\n     * @return void\n     */\n    public function deleteRepository()\n    {\n        $schema = $this->getConnection()->getSchemaBuilder();\n\n        $schema->drop($this->table);\n    }\n\n    /**\n     * Get a query builder for the migration table.\n     *\n     * @return \\Illuminate\\Database\\Query\\Builder\n     */\n    protected function table()\n    {\n        return $this->getConnection()->table($this->table)->useWritePdo();\n    }\n\n    /**\n     * Get the connection resolver instance.\n     *\n     * @return \\Illuminate\\Database\\ConnectionResolverInterface\n     */\n    public function getConnectionResolver()\n    {\n        return $this->resolver;\n    }\n\n    /**\n     * Resolve the database connection instance.\n     *\n     * @return \\Illuminate\\Database\\Connection\n     */\n    public function getConnection()\n    {\n        return $this->resolver->connection($this->connection);\n    }\n\n    /**\n     * Set the information source to gather data.\n     *\n     * @param  string  $name\n     * @return void\n     */\n    public function setSource($name)\n    {\n        $this->connection = $name;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Migrations/Migration.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Migrations;\n\nabstract class Migration\n{\n    /**\n     * The name of the database connection to use.\n     *\n     * @var string|null\n     */\n    protected $connection;\n\n    /**\n     * Enables, if supported, wrapping the migration within a transaction.\n     *\n     * @var bool\n     */\n    public $withinTransaction = true;\n\n    /**\n     * Get the migration connection name.\n     *\n     * @return string|null\n     */\n    public function getConnection()\n    {\n        return $this->connection;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Migrations/MigrationCreator.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Migrations;\n\nuse Closure;\nuse Illuminate\\Filesystem\\Filesystem;\nuse Illuminate\\Support\\Str;\nuse InvalidArgumentException;\n\nclass MigrationCreator\n{\n    /**\n     * The filesystem instance.\n     *\n     * @var \\Illuminate\\Filesystem\\Filesystem\n     */\n    protected $files;\n\n    /**\n     * The custom app stubs directory.\n     *\n     * @var string\n     */\n    protected $customStubPath;\n\n    /**\n     * The registered post create hooks.\n     *\n     * @var array\n     */\n    protected $postCreate = [];\n\n    /**\n     * Create a new migration creator instance.\n     *\n     * @param  \\Illuminate\\Filesystem\\Filesystem  $files\n     * @param  string  $customStubPath\n     * @return void\n     */\n    public function __construct(Filesystem $files, $customStubPath)\n    {\n        $this->files = $files;\n        $this->customStubPath = $customStubPath;\n    }\n\n    /**\n     * Create a new migration at the given path.\n     *\n     * @param  string  $name\n     * @param  string  $path\n     * @param  string|null  $table\n     * @param  bool  $create\n     * @return string\n     *\n     * @throws \\Exception\n     */\n    public function create($name, $path, $table = null, $create = false)\n    {\n        $this->ensureMigrationDoesntAlreadyExist($name, $path);\n\n        // First we will get the stub file for the migration, which serves as a type\n        // of template for the migration. Once we have those we will populate the\n        // various place-holders, save the file, and run the post create event.\n        $stub = $this->getStub($table, $create);\n\n        $path = $this->getPath($name, $path);\n\n        $this->files->ensureDirectoryExists(dirname($path));\n\n        $this->files->put(\n            $path, $this->populateStub($name, $stub, $table)\n        );\n\n        // Next, we will fire any hooks that are supposed to fire after a migration is\n        // created. Once that is done we'll be ready to return the full path to the\n        // migration file so it can be used however it's needed by the developer.\n        $this->firePostCreateHooks($table);\n\n        return $path;\n    }\n\n    /**\n     * Ensure that a migration with the given name doesn't already exist.\n     *\n     * @param  string  $name\n     * @param  string  $migrationPath\n     * @return void\n     *\n     * @throws \\InvalidArgumentException\n     */\n    protected function ensureMigrationDoesntAlreadyExist($name, $migrationPath = null)\n    {\n        if (! empty($migrationPath)) {\n            $migrationFiles = $this->files->glob($migrationPath.'/*.php');\n\n            foreach ($migrationFiles as $migrationFile) {\n                $this->files->requireOnce($migrationFile);\n            }\n        }\n\n        if (class_exists($className = $this->getClassName($name))) {\n            throw new InvalidArgumentException(\"A {$className} class already exists.\");\n        }\n    }\n\n    /**\n     * Get the migration stub file.\n     *\n     * @param  string|null  $table\n     * @param  bool  $create\n     * @return string\n     */\n    protected function getStub($table, $create)\n    {\n        if (is_null($table)) {\n            $stub = $this->files->exists($customPath = $this->customStubPath.'/migration.stub')\n                            ? $customPath\n                            : $this->stubPath().'/migration.stub';\n        } elseif ($create) {\n            $stub = $this->files->exists($customPath = $this->customStubPath.'/migration.create.stub')\n                            ? $customPath\n                            : $this->stubPath().'/migration.create.stub';\n        } else {\n            $stub = $this->files->exists($customPath = $this->customStubPath.'/migration.update.stub')\n                            ? $customPath\n                            : $this->stubPath().'/migration.update.stub';\n        }\n\n        return $this->files->get($stub);\n    }\n\n    /**\n     * Populate the place-holders in the migration stub.\n     *\n     * @param  string  $name\n     * @param  string  $stub\n     * @param  string|null  $table\n     * @return string\n     */\n    protected function populateStub($name, $stub, $table)\n    {\n        $stub = str_replace(\n            ['DummyClass', '{{ class }}', '{{class}}'],\n            $this->getClassName($name), $stub\n        );\n\n        // Here we will replace the table place-holders with the table specified by\n        // the developer, which is useful for quickly creating a tables creation\n        // or update migration from the console instead of typing it manually.\n        if (! is_null($table)) {\n            $stub = str_replace(\n                ['DummyTable', '{{ table }}', '{{table}}'],\n                $table, $stub\n            );\n        }\n\n        return $stub;\n    }\n\n    /**\n     * Get the class name of a migration name.\n     *\n     * @param  string  $name\n     * @return string\n     */\n    protected function getClassName($name)\n    {\n        return Str::studly($name);\n    }\n\n    /**\n     * Get the full path to the migration.\n     *\n     * @param  string  $name\n     * @param  string  $path\n     * @return string\n     */\n    protected function getPath($name, $path)\n    {\n        return $path.'/'.$this->getDatePrefix().'_'.$name.'.php';\n    }\n\n    /**\n     * Fire the registered post create hooks.\n     *\n     * @param  string|null  $table\n     * @return void\n     */\n    protected function firePostCreateHooks($table)\n    {\n        foreach ($this->postCreate as $callback) {\n            $callback($table);\n        }\n    }\n\n    /**\n     * Register a post migration create hook.\n     *\n     * @param  \\Closure  $callback\n     * @return void\n     */\n    public function afterCreate(Closure $callback)\n    {\n        $this->postCreate[] = $callback;\n    }\n\n    /**\n     * Get the date prefix for the migration.\n     *\n     * @return string\n     */\n    protected function getDatePrefix()\n    {\n        return date('Y_m_d_His');\n    }\n\n    /**\n     * Get the path to the stubs.\n     *\n     * @return string\n     */\n    public function stubPath()\n    {\n        return __DIR__.'/stubs';\n    }\n\n    /**\n     * Get the filesystem instance.\n     *\n     * @return \\Illuminate\\Filesystem\\Filesystem\n     */\n    public function getFilesystem()\n    {\n        return $this->files;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Migrations/MigrationRepositoryInterface.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Migrations;\n\ninterface MigrationRepositoryInterface\n{\n    /**\n     * Get the completed migrations.\n     *\n     * @return array\n     */\n    public function getRan();\n\n    /**\n     * Get the list of migrations.\n     *\n     * @param  int  $steps\n     * @return array\n     */\n    public function getMigrations($steps);\n\n    /**\n     * Get the last migration batch.\n     *\n     * @return array\n     */\n    public function getLast();\n\n    /**\n     * Get the completed migrations with their batch numbers.\n     *\n     * @return array\n     */\n    public function getMigrationBatches();\n\n    /**\n     * Log that a migration was run.\n     *\n     * @param  string  $file\n     * @param  int  $batch\n     * @return void\n     */\n    public function log($file, $batch);\n\n    /**\n     * Remove a migration from the log.\n     *\n     * @param  object  $migration\n     * @return void\n     */\n    public function delete($migration);\n\n    /**\n     * Get the next migration batch number.\n     *\n     * @return int\n     */\n    public function getNextBatchNumber();\n\n    /**\n     * Create the migration repository data store.\n     *\n     * @return void\n     */\n    public function createRepository();\n\n    /**\n     * Determine if the migration repository exists.\n     *\n     * @return bool\n     */\n    public function repositoryExists();\n\n    /**\n     * Delete the migration repository data store.\n     *\n     * @return void\n     */\n    public function deleteRepository();\n\n    /**\n     * Set the information source to gather data.\n     *\n     * @param  string  $name\n     * @return void\n     */\n    public function setSource($name);\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Migrations/Migrator.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Migrations;\n\nuse Doctrine\\DBAL\\Schema\\SchemaException;\nuse Illuminate\\Contracts\\Events\\Dispatcher;\nuse Illuminate\\Database\\ConnectionResolverInterface as Resolver;\nuse Illuminate\\Database\\Events\\MigrationEnded;\nuse Illuminate\\Database\\Events\\MigrationsEnded;\nuse Illuminate\\Database\\Events\\MigrationsStarted;\nuse Illuminate\\Database\\Events\\MigrationStarted;\nuse Illuminate\\Database\\Events\\NoPendingMigrations;\nuse Illuminate\\Filesystem\\Filesystem;\nuse Illuminate\\Support\\Arr;\nuse Illuminate\\Support\\Collection;\nuse Illuminate\\Support\\Str;\nuse ReflectionClass;\nuse Symfony\\Component\\Console\\Output\\OutputInterface;\n\nclass Migrator\n{\n    /**\n     * The event dispatcher instance.\n     *\n     * @var \\Illuminate\\Contracts\\Events\\Dispatcher\n     */\n    protected $events;\n\n    /**\n     * The migration repository implementation.\n     *\n     * @var \\Illuminate\\Database\\Migrations\\MigrationRepositoryInterface\n     */\n    protected $repository;\n\n    /**\n     * The filesystem instance.\n     *\n     * @var \\Illuminate\\Filesystem\\Filesystem\n     */\n    protected $files;\n\n    /**\n     * The connection resolver instance.\n     *\n     * @var \\Illuminate\\Database\\ConnectionResolverInterface\n     */\n    protected $resolver;\n\n    /**\n     * The name of the default connection.\n     *\n     * @var string\n     */\n    protected $connection;\n\n    /**\n     * The paths to all of the migration files.\n     *\n     * @var array\n     */\n    protected $paths = [];\n\n    /**\n     * The output interface implementation.\n     *\n     * @var \\Symfony\\Component\\Console\\Output\\OutputInterface\n     */\n    protected $output;\n\n    /**\n     * Create a new migrator instance.\n     *\n     * @param  \\Illuminate\\Database\\Migrations\\MigrationRepositoryInterface  $repository\n     * @param  \\Illuminate\\Database\\ConnectionResolverInterface  $resolver\n     * @param  \\Illuminate\\Filesystem\\Filesystem  $files\n     * @param  \\Illuminate\\Contracts\\Events\\Dispatcher|null  $dispatcher\n     * @return void\n     */\n    public function __construct(MigrationRepositoryInterface $repository,\n                                Resolver $resolver,\n                                Filesystem $files,\n                                Dispatcher $dispatcher = null)\n    {\n        $this->files = $files;\n        $this->events = $dispatcher;\n        $this->resolver = $resolver;\n        $this->repository = $repository;\n    }\n\n    /**\n     * Run the pending migrations at a given path.\n     *\n     * @param  array|string  $paths\n     * @param  array  $options\n     * @return array\n     */\n    public function run($paths = [], array $options = [])\n    {\n        // Once we grab all of the migration files for the path, we will compare them\n        // against the migrations that have already been run for this package then\n        // run each of the outstanding migrations against a database connection.\n        $files = $this->getMigrationFiles($paths);\n\n        $this->requireFiles($migrations = $this->pendingMigrations(\n            $files, $this->repository->getRan()\n        ));\n\n        // Once we have all these migrations that are outstanding we are ready to run\n        // we will go ahead and run them \"up\". This will execute each migration as\n        // an operation against a database. Then we'll return this list of them.\n        $this->runPending($migrations, $options);\n\n        return $migrations;\n    }\n\n    /**\n     * Get the migration files that have not yet run.\n     *\n     * @param  array  $files\n     * @param  array  $ran\n     * @return array\n     */\n    protected function pendingMigrations($files, $ran)\n    {\n        return Collection::make($files)\n                ->reject(function ($file) use ($ran) {\n                    return in_array($this->getMigrationName($file), $ran);\n                })->values()->all();\n    }\n\n    /**\n     * Run an array of migrations.\n     *\n     * @param  array  $migrations\n     * @param  array  $options\n     * @return void\n     */\n    public function runPending(array $migrations, array $options = [])\n    {\n        // First we will just make sure that there are any migrations to run. If there\n        // aren't, we will just make a note of it to the developer so they're aware\n        // that all of the migrations have been run against this database system.\n        if (count($migrations) === 0) {\n            $this->fireMigrationEvent(new NoPendingMigrations('up'));\n\n            $this->note('<info>Nothing to migrate.</info>');\n\n            return;\n        }\n\n        // Next, we will get the next batch number for the migrations so we can insert\n        // correct batch number in the database migrations repository when we store\n        // each migration's execution. We will also extract a few of the options.\n        $batch = $this->repository->getNextBatchNumber();\n\n        $pretend = $options['pretend'] ?? false;\n\n        $step = $options['step'] ?? false;\n\n        $this->fireMigrationEvent(new MigrationsStarted('up'));\n\n        // Once we have the array of migrations, we will spin through them and run the\n        // migrations \"up\" so the changes are made to the databases. We'll then log\n        // that the migration was run so we don't repeat it next time we execute.\n        foreach ($migrations as $file) {\n            $this->runUp($file, $batch, $pretend);\n\n            if ($step) {\n                $batch++;\n            }\n        }\n\n        $this->fireMigrationEvent(new MigrationsEnded('up'));\n    }\n\n    /**\n     * Run \"up\" a migration instance.\n     *\n     * @param  string  $file\n     * @param  int  $batch\n     * @param  bool  $pretend\n     * @return void\n     */\n    protected function runUp($file, $batch, $pretend)\n    {\n        // First we will resolve a \"real\" instance of the migration class from this\n        // migration file name. Once we have the instances we can run the actual\n        // command such as \"up\" or \"down\", or we can just simulate the action.\n        $migration = $this->resolvePath($file);\n\n        $name = $this->getMigrationName($file);\n\n        if ($pretend) {\n            return $this->pretendToRun($migration, 'up');\n        }\n\n        $this->note(\"<comment>Migrating:</comment> {$name}\");\n\n        $startTime = microtime(true);\n\n        $this->runMigration($migration, 'up');\n\n        $runTime = number_format((microtime(true) - $startTime) * 1000, 2);\n\n        // Once we have run a migrations class, we will log that it was run in this\n        // repository so that we don't try to run it next time we do a migration\n        // in the application. A migration repository keeps the migrate order.\n        $this->repository->log($name, $batch);\n\n        $this->note(\"<info>Migrated:</info>  {$name} ({$runTime}ms)\");\n    }\n\n    /**\n     * Rollback the last migration operation.\n     *\n     * @param  array|string  $paths\n     * @param  array  $options\n     * @return array\n     */\n    public function rollback($paths = [], array $options = [])\n    {\n        // We want to pull in the last batch of migrations that ran on the previous\n        // migration operation. We'll then reverse those migrations and run each\n        // of them \"down\" to reverse the last migration \"operation\" which ran.\n        $migrations = $this->getMigrationsForRollback($options);\n\n        if (count($migrations) === 0) {\n            $this->fireMigrationEvent(new NoPendingMigrations('down'));\n\n            $this->note('<info>Nothing to rollback.</info>');\n\n            return [];\n        }\n\n        return $this->rollbackMigrations($migrations, $paths, $options);\n    }\n\n    /**\n     * Get the migrations for a rollback operation.\n     *\n     * @param  array  $options\n     * @return array\n     */\n    protected function getMigrationsForRollback(array $options)\n    {\n        if (($steps = $options['step'] ?? 0) > 0) {\n            return $this->repository->getMigrations($steps);\n        }\n\n        return $this->repository->getLast();\n    }\n\n    /**\n     * Rollback the given migrations.\n     *\n     * @param  array  $migrations\n     * @param  array|string  $paths\n     * @param  array  $options\n     * @return array\n     */\n    protected function rollbackMigrations(array $migrations, $paths, array $options)\n    {\n        $rolledBack = [];\n\n        $this->requireFiles($files = $this->getMigrationFiles($paths));\n\n        $this->fireMigrationEvent(new MigrationsStarted('down'));\n\n        // Next we will run through all of the migrations and call the \"down\" method\n        // which will reverse each migration in order. This getLast method on the\n        // repository already returns these migration's names in reverse order.\n        foreach ($migrations as $migration) {\n            $migration = (object) $migration;\n\n            if (! $file = Arr::get($files, $migration->migration)) {\n                $this->note(\"<fg=red>Migration not found:</> {$migration->migration}\");\n\n                continue;\n            }\n\n            $rolledBack[] = $file;\n\n            $this->runDown(\n                $file, $migration,\n                $options['pretend'] ?? false\n            );\n        }\n\n        $this->fireMigrationEvent(new MigrationsEnded('down'));\n\n        return $rolledBack;\n    }\n\n    /**\n     * Rolls all of the currently applied migrations back.\n     *\n     * @param  array|string  $paths\n     * @param  bool  $pretend\n     * @return array\n     */\n    public function reset($paths = [], $pretend = false)\n    {\n        // Next, we will reverse the migration list so we can run them back in the\n        // correct order for resetting this database. This will allow us to get\n        // the database back into its \"empty\" state ready for the migrations.\n        $migrations = array_reverse($this->repository->getRan());\n\n        if (count($migrations) === 0) {\n            $this->note('<info>Nothing to rollback.</info>');\n\n            return [];\n        }\n\n        return $this->resetMigrations($migrations, $paths, $pretend);\n    }\n\n    /**\n     * Reset the given migrations.\n     *\n     * @param  array  $migrations\n     * @param  array  $paths\n     * @param  bool  $pretend\n     * @return array\n     */\n    protected function resetMigrations(array $migrations, array $paths, $pretend = false)\n    {\n        // Since the getRan method that retrieves the migration name just gives us the\n        // migration name, we will format the names into objects with the name as a\n        // property on the objects so that we can pass it to the rollback method.\n        $migrations = collect($migrations)->map(function ($m) {\n            return (object) ['migration' => $m];\n        })->all();\n\n        return $this->rollbackMigrations(\n            $migrations, $paths, compact('pretend')\n        );\n    }\n\n    /**\n     * Run \"down\" a migration instance.\n     *\n     * @param  string  $file\n     * @param  object  $migration\n     * @param  bool  $pretend\n     * @return void\n     */\n    protected function runDown($file, $migration, $pretend)\n    {\n        // First we will get the file name of the migration so we can resolve out an\n        // instance of the migration. Once we get an instance we can either run a\n        // pretend execution of the migration or we can run the real migration.\n        $instance = $this->resolvePath($file);\n\n        $name = $this->getMigrationName($file);\n\n        $this->note(\"<comment>Rolling back:</comment> {$name}\");\n\n        if ($pretend) {\n            return $this->pretendToRun($instance, 'down');\n        }\n\n        $startTime = microtime(true);\n\n        $this->runMigration($instance, 'down');\n\n        $runTime = number_format((microtime(true) - $startTime) * 1000, 2);\n\n        // Once we have successfully run the migration \"down\" we will remove it from\n        // the migration repository so it will be considered to have not been run\n        // by the application then will be able to fire by any later operation.\n        $this->repository->delete($migration);\n\n        $this->note(\"<info>Rolled back:</info>  {$name} ({$runTime}ms)\");\n    }\n\n    /**\n     * Run a migration inside a transaction if the database supports it.\n     *\n     * @param  object  $migration\n     * @param  string  $method\n     * @return void\n     */\n    protected function runMigration($migration, $method)\n    {\n        $connection = $this->resolveConnection(\n            $migration->getConnection()\n        );\n\n        $callback = function () use ($connection, $migration, $method) {\n            if (method_exists($migration, $method)) {\n                $this->fireMigrationEvent(new MigrationStarted($migration, $method));\n\n                $this->runMethod($connection, $migration, $method);\n\n                $this->fireMigrationEvent(new MigrationEnded($migration, $method));\n            }\n        };\n\n        $this->getSchemaGrammar($connection)->supportsSchemaTransactions()\n            && $migration->withinTransaction\n                    ? $connection->transaction($callback)\n                    : $callback();\n    }\n\n    /**\n     * Pretend to run the migrations.\n     *\n     * @param  object  $migration\n     * @param  string  $method\n     * @return void\n     */\n    protected function pretendToRun($migration, $method)\n    {\n        try {\n            foreach ($this->getQueries($migration, $method) as $query) {\n                $name = get_class($migration);\n\n                $reflectionClass = new ReflectionClass($migration);\n\n                if ($reflectionClass->isAnonymous()) {\n                    $name = $this->getMigrationName($reflectionClass->getFileName());\n                }\n\n                $this->note(\"<info>{$name}:</info> {$query['query']}\");\n            }\n        } catch (SchemaException $e) {\n            $name = get_class($migration);\n\n            $this->note(\"<info>{$name}:</info> failed to dump queries. This may be due to changing database columns using Doctrine, which is not supported while pretending to run migrations.\");\n        }\n    }\n\n    /**\n     * Get all of the queries that would be run for a migration.\n     *\n     * @param  object  $migration\n     * @param  string  $method\n     * @return array\n     */\n    protected function getQueries($migration, $method)\n    {\n        // Now that we have the connections we can resolve it and pretend to run the\n        // queries against the database returning the array of raw SQL statements\n        // that would get fired against the database system for this migration.\n        $db = $this->resolveConnection(\n            $migration->getConnection()\n        );\n\n        return $db->pretend(function () use ($db, $migration, $method) {\n            if (method_exists($migration, $method)) {\n                $this->runMethod($db, $migration, $method);\n            }\n        });\n    }\n\n    /**\n     * Run a migration method on the given connection.\n     *\n     * @param  \\Illuminate\\Database\\Connection  $connection\n     * @param  object  $migration\n     * @param  string  $method\n     * @return void\n     */\n    protected function runMethod($connection, $migration, $method)\n    {\n        $previousConnection = $this->resolver->getDefaultConnection();\n\n        try {\n            $this->resolver->setDefaultConnection($connection->getName());\n\n            $migration->{$method}();\n        } finally {\n            $this->resolver->setDefaultConnection($previousConnection);\n        }\n    }\n\n    /**\n     * Resolve a migration instance from a file.\n     *\n     * @param  string  $file\n     * @return object\n     */\n    public function resolve($file)\n    {\n        $class = $this->getMigrationClass($file);\n\n        return new $class;\n    }\n\n    /**\n     * Resolve a migration instance from a migration path.\n     *\n     * @param  string  $path\n     * @return object\n     */\n    protected function resolvePath(string $path)\n    {\n        $class = $this->getMigrationClass($this->getMigrationName($path));\n\n        if (class_exists($class) && realpath($path) == (new ReflectionClass($class))->getFileName()) {\n            return new $class;\n        }\n\n        $migration = $this->files->getRequire($path);\n\n        return is_object($migration) ? $migration : new $class;\n    }\n\n    /**\n     * Generate a migration class name based on the migration file name.\n     *\n     * @param  string  $migrationName\n     * @return string\n     */\n    protected function getMigrationClass(string $migrationName): string\n    {\n        return Str::studly(implode('_', array_slice(explode('_', $migrationName), 4)));\n    }\n\n    /**\n     * Get all of the migration files in a given path.\n     *\n     * @param  string|array  $paths\n     * @return array\n     */\n    public function getMigrationFiles($paths)\n    {\n        return Collection::make($paths)->flatMap(function ($path) {\n            return Str::endsWith($path, '.php') ? [$path] : $this->files->glob($path.'/*_*.php');\n        })->filter()->values()->keyBy(function ($file) {\n            return $this->getMigrationName($file);\n        })->sortBy(function ($file, $key) {\n            return $key;\n        })->all();\n    }\n\n    /**\n     * Require in all the migration files in a given path.\n     *\n     * @param  array  $files\n     * @return void\n     */\n    public function requireFiles(array $files)\n    {\n        foreach ($files as $file) {\n            $this->files->requireOnce($file);\n        }\n    }\n\n    /**\n     * Get the name of the migration.\n     *\n     * @param  string  $path\n     * @return string\n     */\n    public function getMigrationName($path)\n    {\n        return str_replace('.php', '', basename($path));\n    }\n\n    /**\n     * Register a custom migration path.\n     *\n     * @param  string  $path\n     * @return void\n     */\n    public function path($path)\n    {\n        $this->paths = array_unique(array_merge($this->paths, [$path]));\n    }\n\n    /**\n     * Get all of the custom migration paths.\n     *\n     * @return array\n     */\n    public function paths()\n    {\n        return $this->paths;\n    }\n\n    /**\n     * Get the default connection name.\n     *\n     * @return string\n     */\n    public function getConnection()\n    {\n        return $this->connection;\n    }\n\n    /**\n     * Execute the given callback using the given connection as the default connection.\n     *\n     * @param  string  $name\n     * @param  callable  $callback\n     * @return mixed\n     */\n    public function usingConnection($name, callable $callback)\n    {\n        $previousConnection = $this->resolver->getDefaultConnection();\n\n        $this->setConnection($name);\n\n        return tap($callback(), function () use ($previousConnection) {\n            $this->setConnection($previousConnection);\n        });\n    }\n\n    /**\n     * Set the default connection name.\n     *\n     * @param  string  $name\n     * @return void\n     */\n    public function setConnection($name)\n    {\n        if (! is_null($name)) {\n            $this->resolver->setDefaultConnection($name);\n        }\n\n        $this->repository->setSource($name);\n\n        $this->connection = $name;\n    }\n\n    /**\n     * Resolve the database connection instance.\n     *\n     * @param  string  $connection\n     * @return \\Illuminate\\Database\\Connection\n     */\n    public function resolveConnection($connection)\n    {\n        return $this->resolver->connection($connection ?: $this->connection);\n    }\n\n    /**\n     * Get the schema grammar out of a migration connection.\n     *\n     * @param  \\Illuminate\\Database\\Connection  $connection\n     * @return \\Illuminate\\Database\\Schema\\Grammars\\Grammar\n     */\n    protected function getSchemaGrammar($connection)\n    {\n        if (is_null($grammar = $connection->getSchemaGrammar())) {\n            $connection->useDefaultSchemaGrammar();\n\n            $grammar = $connection->getSchemaGrammar();\n        }\n\n        return $grammar;\n    }\n\n    /**\n     * Get the migration repository instance.\n     *\n     * @return \\Illuminate\\Database\\Migrations\\MigrationRepositoryInterface\n     */\n    public function getRepository()\n    {\n        return $this->repository;\n    }\n\n    /**\n     * Determine if the migration repository exists.\n     *\n     * @return bool\n     */\n    public function repositoryExists()\n    {\n        return $this->repository->repositoryExists();\n    }\n\n    /**\n     * Determine if any migrations have been run.\n     *\n     * @return bool\n     */\n    public function hasRunAnyMigrations()\n    {\n        return $this->repositoryExists() && count($this->repository->getRan()) > 0;\n    }\n\n    /**\n     * Delete the migration repository data store.\n     *\n     * @return void\n     */\n    public function deleteRepository()\n    {\n        return $this->repository->deleteRepository();\n    }\n\n    /**\n     * Get the file system instance.\n     *\n     * @return \\Illuminate\\Filesystem\\Filesystem\n     */\n    public function getFilesystem()\n    {\n        return $this->files;\n    }\n\n    /**\n     * Set the output implementation that should be used by the console.\n     *\n     * @param  \\Symfony\\Component\\Console\\Output\\OutputInterface  $output\n     * @return $this\n     */\n    public function setOutput(OutputInterface $output)\n    {\n        $this->output = $output;\n\n        return $this;\n    }\n\n    /**\n     * Write a note to the console's output.\n     *\n     * @param  string  $message\n     * @return void\n     */\n    protected function note($message)\n    {\n        if ($this->output) {\n            $this->output->writeln($message);\n        }\n    }\n\n    /**\n     * Fire the given event for the migration.\n     *\n     * @param  \\Illuminate\\Contracts\\Database\\Events\\MigrationEvent  $event\n     * @return void\n     */\n    public function fireMigrationEvent($event)\n    {\n        if ($this->events) {\n            $this->events->dispatch($event);\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Migrations/stubs/migration.create.stub",
    "content": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nclass {{ class }} extends Migration\n{\n    /**\n     * Run the migrations.\n     *\n     * @return void\n     */\n    public function up()\n    {\n        Schema::create('{{ table }}', function (Blueprint $table) {\n            $table->id();\n            $table->timestamps();\n        });\n    }\n\n    /**\n     * Reverse the migrations.\n     *\n     * @return void\n     */\n    public function down()\n    {\n        Schema::dropIfExists('{{ table }}');\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Migrations/stubs/migration.stub",
    "content": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nclass {{ class }} extends Migration\n{\n    /**\n     * Run the migrations.\n     *\n     * @return void\n     */\n    public function up()\n    {\n        //\n    }\n\n    /**\n     * Reverse the migrations.\n     *\n     * @return void\n     */\n    public function down()\n    {\n        //\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Migrations/stubs/migration.update.stub",
    "content": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nclass {{ class }} extends Migration\n{\n    /**\n     * Run the migrations.\n     *\n     * @return void\n     */\n    public function up()\n    {\n        Schema::table('{{ table }}', function (Blueprint $table) {\n            //\n        });\n    }\n\n    /**\n     * Reverse the migrations.\n     *\n     * @return void\n     */\n    public function down()\n    {\n        Schema::table('{{ table }}', function (Blueprint $table) {\n            //\n        });\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/MultipleRecordsFoundException.php",
    "content": "<?php\n\nnamespace Illuminate\\Database;\n\nuse RuntimeException;\n\nclass MultipleRecordsFoundException extends RuntimeException\n{\n    //\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/MySqlConnection.php",
    "content": "<?php\n\nnamespace Illuminate\\Database;\n\nuse Doctrine\\DBAL\\Driver\\PDOMySql\\Driver as DoctrineDriver;\nuse Doctrine\\DBAL\\Version;\nuse Illuminate\\Database\\PDO\\MySqlDriver;\nuse Illuminate\\Database\\Query\\Grammars\\MySqlGrammar as QueryGrammar;\nuse Illuminate\\Database\\Query\\Processors\\MySqlProcessor;\nuse Illuminate\\Database\\Schema\\Grammars\\MySqlGrammar as SchemaGrammar;\nuse Illuminate\\Database\\Schema\\MySqlBuilder;\nuse Illuminate\\Database\\Schema\\MySqlSchemaState;\nuse Illuminate\\Filesystem\\Filesystem;\nuse PDO;\n\nclass MySqlConnection extends Connection\n{\n    /**\n     * Determine if the connected database is a MariaDB database.\n     *\n     * @return bool\n     */\n    public function isMaria()\n    {\n        return strpos($this->getPdo()->getAttribute(PDO::ATTR_SERVER_VERSION), 'MariaDB') !== false;\n    }\n\n    /**\n     * Get the default query grammar instance.\n     *\n     * @return \\Illuminate\\Database\\Query\\Grammars\\MySqlGrammar\n     */\n    protected function getDefaultQueryGrammar()\n    {\n        return $this->withTablePrefix(new QueryGrammar);\n    }\n\n    /**\n     * Get a schema builder instance for the connection.\n     *\n     * @return \\Illuminate\\Database\\Schema\\MySqlBuilder\n     */\n    public function getSchemaBuilder()\n    {\n        if (is_null($this->schemaGrammar)) {\n            $this->useDefaultSchemaGrammar();\n        }\n\n        return new MySqlBuilder($this);\n    }\n\n    /**\n     * Get the default schema grammar instance.\n     *\n     * @return \\Illuminate\\Database\\Schema\\Grammars\\MySqlGrammar\n     */\n    protected function getDefaultSchemaGrammar()\n    {\n        return $this->withTablePrefix(new SchemaGrammar);\n    }\n\n    /**\n     * Get the schema state for the connection.\n     *\n     * @param  \\Illuminate\\Filesystem\\Filesystem|null  $files\n     * @param  callable|null  $processFactory\n     * @return \\Illuminate\\Database\\Schema\\MySqlSchemaState\n     */\n    public function getSchemaState(Filesystem $files = null, callable $processFactory = null)\n    {\n        return new MySqlSchemaState($this, $files, $processFactory);\n    }\n\n    /**\n     * Get the default post processor instance.\n     *\n     * @return \\Illuminate\\Database\\Query\\Processors\\MySqlProcessor\n     */\n    protected function getDefaultPostProcessor()\n    {\n        return new MySqlProcessor;\n    }\n\n    /**\n     * Get the Doctrine DBAL driver.\n     *\n     * @return \\Doctrine\\DBAL\\Driver\\PDOMySql\\Driver|\\Illuminate\\Database\\PDO\\MySqlDriver\n     */\n    protected function getDoctrineDriver()\n    {\n        return class_exists(Version::class) ? new DoctrineDriver : new MySqlDriver;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/PDO/Concerns/ConnectsToDatabase.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\PDO\\Concerns;\n\nuse Illuminate\\Database\\PDO\\Connection;\nuse InvalidArgumentException;\nuse PDO;\n\ntrait ConnectsToDatabase\n{\n    /**\n     * Create a new database connection.\n     *\n     * @param  array  $params\n     * @return \\Illuminate\\Database\\PDO\\Connection\n     *\n     * @throws \\InvalidArgumentException\n     */\n    public function connect(array $params)\n    {\n        if (! isset($params['pdo']) || ! $params['pdo'] instanceof PDO) {\n            throw new InvalidArgumentException('Laravel requires the \"pdo\" property to be set and be a PDO instance.');\n        }\n\n        return new Connection($params['pdo']);\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/PDO/Connection.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\PDO;\n\nuse Doctrine\\DBAL\\Driver\\PDO\\Exception;\nuse Doctrine\\DBAL\\Driver\\PDO\\Result;\nuse Doctrine\\DBAL\\Driver\\PDO\\Statement;\nuse Doctrine\\DBAL\\Driver\\Result as ResultInterface;\nuse Doctrine\\DBAL\\Driver\\ServerInfoAwareConnection;\nuse Doctrine\\DBAL\\Driver\\Statement as StatementInterface;\nuse Doctrine\\DBAL\\ParameterType;\nuse PDO;\nuse PDOException;\nuse PDOStatement;\n\nclass Connection implements ServerInfoAwareConnection\n{\n    /**\n     * The underlying PDO connection.\n     *\n     * @var \\PDO\n     */\n    protected $connection;\n\n    /**\n     * Create a new PDO connection instance.\n     *\n     * @param  \\PDO  $connection\n     * @return void\n     */\n    public function __construct(PDO $connection)\n    {\n        $this->connection = $connection;\n    }\n\n    /**\n     * Execute an SQL statement.\n     *\n     * @param  string  $statement\n     * @return int\n     */\n    public function exec(string $statement): int\n    {\n        try {\n            $result = $this->connection->exec($statement);\n\n            \\assert($result !== false);\n\n            return $result;\n        } catch (PDOException $exception) {\n            throw Exception::new($exception);\n        }\n    }\n\n    /**\n     * Prepare a new SQL statement.\n     *\n     * @param  string  $sql\n     * @return \\Doctrine\\DBAL\\Driver\\Statement\n     */\n    public function prepare(string $sql): StatementInterface\n    {\n        try {\n            return $this->createStatement(\n                $this->connection->prepare($sql)\n            );\n        } catch (PDOException $exception) {\n            throw Exception::new($exception);\n        }\n    }\n\n    /**\n     * Execute a new query against the connection.\n     *\n     * @param  string  $sql\n     * @return \\Doctrine\\DBAL\\Driver\\Result\n     */\n    public function query(string $sql): ResultInterface\n    {\n        try {\n            $stmt = $this->connection->query($sql);\n\n            \\assert($stmt instanceof PDOStatement);\n\n            return new Result($stmt);\n        } catch (PDOException $exception) {\n            throw Exception::new($exception);\n        }\n    }\n\n    /**\n     * Get the last insert ID.\n     *\n     * @param  string|null  $name\n     * @return mixed\n     */\n    public function lastInsertId($name = null)\n    {\n        try {\n            if ($name === null) {\n                return $this->connection->lastInsertId();\n            }\n\n            return $this->connection->lastInsertId($name);\n        } catch (PDOException $exception) {\n            throw Exception::new($exception);\n        }\n    }\n\n    /**\n     * Create a new statement instance.\n     *\n     * @param  \\PDOStatement  $stmt\n     * @return \\Doctrine\\DBAL\\Driver\\PDO\\Statement\n     */\n    protected function createStatement(PDOStatement $stmt): Statement\n    {\n        return new Statement($stmt);\n    }\n\n    /**\n     * Begin a new database transaction.\n     *\n     * @return void\n     */\n    public function beginTransaction()\n    {\n        return $this->connection->beginTransaction();\n    }\n\n    /**\n     * Commit a database transaction.\n     *\n     * @return void\n     */\n    public function commit()\n    {\n        return $this->connection->commit();\n    }\n\n    /**\n     * Rollback a database transaction.\n     *\n     * @return void\n     */\n    public function rollBack()\n    {\n        return $this->connection->rollBack();\n    }\n\n    /**\n     * Wrap quotes around the given input.\n     *\n     * @param  string  $input\n     * @param  string  $type\n     * @return string\n     */\n    public function quote($input, $type = ParameterType::STRING)\n    {\n        return $this->connection->quote($input, $type);\n    }\n\n    /**\n     * Get the server version for the connection.\n     *\n     * @return string\n     */\n    public function getServerVersion()\n    {\n        return $this->connection->getAttribute(PDO::ATTR_SERVER_VERSION);\n    }\n\n    /**\n     * Get the wrapped PDO connection.\n     *\n     * @return \\PDO\n     */\n    public function getWrappedConnection(): PDO\n    {\n        return $this->connection;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/PDO/MySqlDriver.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\PDO;\n\nuse Doctrine\\DBAL\\Driver\\AbstractMySQLDriver;\nuse Illuminate\\Database\\PDO\\Concerns\\ConnectsToDatabase;\n\nclass MySqlDriver extends AbstractMySQLDriver\n{\n    use ConnectsToDatabase;\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/PDO/PostgresDriver.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\PDO;\n\nuse Doctrine\\DBAL\\Driver\\AbstractPostgreSQLDriver;\nuse Illuminate\\Database\\PDO\\Concerns\\ConnectsToDatabase;\n\nclass PostgresDriver extends AbstractPostgreSQLDriver\n{\n    use ConnectsToDatabase;\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/PDO/SQLiteDriver.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\PDO;\n\nuse Doctrine\\DBAL\\Driver\\AbstractSQLiteDriver;\nuse Illuminate\\Database\\PDO\\Concerns\\ConnectsToDatabase;\n\nclass SQLiteDriver extends AbstractSQLiteDriver\n{\n    use ConnectsToDatabase;\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/PDO/SqlServerConnection.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\PDO;\n\nuse Doctrine\\DBAL\\Driver\\PDO\\SQLSrv\\Statement;\nuse Doctrine\\DBAL\\Driver\\Result;\nuse Doctrine\\DBAL\\Driver\\ServerInfoAwareConnection;\nuse Doctrine\\DBAL\\Driver\\Statement as StatementInterface;\nuse Doctrine\\DBAL\\ParameterType;\nuse PDO;\n\nclass SqlServerConnection implements ServerInfoAwareConnection\n{\n    /**\n     * The underlying connection instance.\n     *\n     * @var \\Illuminate\\Database\\PDO\\Connection\n     */\n    protected $connection;\n\n    /**\n     * Create a new SQL Server connection instance.\n     *\n     * @param  \\Illuminate\\Database\\PDO\\Connection  $connection\n     * @return void\n     */\n    public function __construct(Connection $connection)\n    {\n        $this->connection = $connection;\n    }\n\n    /**\n     * Prepare a new SQL statement.\n     *\n     * @param  string  $sql\n     * @return \\Doctrine\\DBAL\\Driver\\Statement\n     */\n    public function prepare(string $sql): StatementInterface\n    {\n        return new Statement(\n            $this->connection->prepare($sql)\n        );\n    }\n\n    /**\n     * Execute a new query against the connection.\n     *\n     * @param  string  $sql\n     * @return \\Doctrine\\DBAL\\Driver\\Result\n     */\n    public function query(string $sql): Result\n    {\n        return $this->connection->query($sql);\n    }\n\n    /**\n     * Execute an SQL statement.\n     *\n     * @param  string  $statement\n     * @return int\n     */\n    public function exec(string $statement): int\n    {\n        return $this->connection->exec($statement);\n    }\n\n    /**\n     * Get the last insert ID.\n     *\n     * @param  string|null  $name\n     * @return mixed\n     */\n    public function lastInsertId($name = null)\n    {\n        if ($name === null) {\n            return $this->connection->lastInsertId($name);\n        }\n\n        return $this->prepare('SELECT CONVERT(VARCHAR(MAX), current_value) FROM sys.sequences WHERE name = ?')\n            ->execute([$name])\n            ->fetchOne();\n    }\n\n    /**\n     * Begin a new database transaction.\n     *\n     * @return void\n     */\n    public function beginTransaction()\n    {\n        return $this->connection->beginTransaction();\n    }\n\n    /**\n     * Commit a database transaction.\n     *\n     * @return void\n     */\n    public function commit()\n    {\n        return $this->connection->commit();\n    }\n\n    /**\n     * Rollback a database transaction.\n     *\n     * @return void\n     */\n    public function rollBack()\n    {\n        return $this->connection->rollBack();\n    }\n\n    /**\n     * Wrap quotes around the given input.\n     *\n     * @param  string  $value\n     * @param  int  $type\n     * @return string\n     */\n    public function quote($value, $type = ParameterType::STRING)\n    {\n        $val = $this->connection->quote($value, $type);\n\n        // Fix for a driver version terminating all values with null byte...\n        if (\\is_string($val) && \\strpos($val, \"\\0\") !== false) {\n            $val = \\substr($val, 0, -1);\n        }\n\n        return $val;\n    }\n\n    /**\n     * Get the server version for the connection.\n     *\n     * @return string\n     */\n    public function getServerVersion()\n    {\n        return $this->connection->getServerVersion();\n    }\n\n    /**\n     * Get the wrapped PDO connection.\n     *\n     * @return \\PDO\n     */\n    public function getWrappedConnection(): PDO\n    {\n        return $this->connection->getWrappedConnection();\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/PDO/SqlServerDriver.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\PDO;\n\nuse Doctrine\\DBAL\\Driver\\AbstractSQLServerDriver;\n\nclass SqlServerDriver extends AbstractSQLServerDriver\n{\n    /**\n     * @return \\Doctrine\\DBAL\\Driver\\Connection\n     */\n    public function connect(array $params)\n    {\n        return new SqlServerConnection(\n            new Connection($params['pdo'])\n        );\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/PostgresConnection.php",
    "content": "<?php\n\nnamespace Illuminate\\Database;\n\nuse Doctrine\\DBAL\\Driver\\PDOPgSql\\Driver as DoctrineDriver;\nuse Doctrine\\DBAL\\Version;\nuse Illuminate\\Database\\PDO\\PostgresDriver;\nuse Illuminate\\Database\\Query\\Grammars\\PostgresGrammar as QueryGrammar;\nuse Illuminate\\Database\\Query\\Processors\\PostgresProcessor;\nuse Illuminate\\Database\\Schema\\Grammars\\PostgresGrammar as SchemaGrammar;\nuse Illuminate\\Database\\Schema\\PostgresBuilder;\nuse Illuminate\\Database\\Schema\\PostgresSchemaState;\nuse Illuminate\\Filesystem\\Filesystem;\nuse PDO;\n\nclass PostgresConnection extends Connection\n{\n    /**\n     * Bind values to their parameters in the given statement.\n     *\n     * @param  \\PDOStatement  $statement\n     * @param  array  $bindings\n     * @return void\n     */\n    public function bindValues($statement, $bindings)\n    {\n        foreach ($bindings as $key => $value) {\n            if (is_int($value)) {\n                $pdoParam = PDO::PARAM_INT;\n            } elseif (is_resource($value)) {\n                $pdoParam = PDO::PARAM_LOB;\n            } else {\n                $pdoParam = PDO::PARAM_STR;\n            }\n\n            $statement->bindValue(\n                is_string($key) ? $key : $key + 1,\n                $value,\n                $pdoParam\n            );\n        }\n    }\n\n    /**\n     * Get the default query grammar instance.\n     *\n     * @return \\Illuminate\\Database\\Query\\Grammars\\PostgresGrammar\n     */\n    protected function getDefaultQueryGrammar()\n    {\n        return $this->withTablePrefix(new QueryGrammar);\n    }\n\n    /**\n     * Get a schema builder instance for the connection.\n     *\n     * @return \\Illuminate\\Database\\Schema\\PostgresBuilder\n     */\n    public function getSchemaBuilder()\n    {\n        if (is_null($this->schemaGrammar)) {\n            $this->useDefaultSchemaGrammar();\n        }\n\n        return new PostgresBuilder($this);\n    }\n\n    /**\n     * Get the default schema grammar instance.\n     *\n     * @return \\Illuminate\\Database\\Schema\\Grammars\\PostgresGrammar\n     */\n    protected function getDefaultSchemaGrammar()\n    {\n        return $this->withTablePrefix(new SchemaGrammar);\n    }\n\n    /**\n     * Get the schema state for the connection.\n     *\n     * @param  \\Illuminate\\Filesystem\\Filesystem|null  $files\n     * @param  callable|null  $processFactory\n     * @return \\Illuminate\\Database\\Schema\\PostgresSchemaState\n     */\n    public function getSchemaState(Filesystem $files = null, callable $processFactory = null)\n    {\n        return new PostgresSchemaState($this, $files, $processFactory);\n    }\n\n    /**\n     * Get the default post processor instance.\n     *\n     * @return \\Illuminate\\Database\\Query\\Processors\\PostgresProcessor\n     */\n    protected function getDefaultPostProcessor()\n    {\n        return new PostgresProcessor;\n    }\n\n    /**\n     * Get the Doctrine DBAL driver.\n     *\n     * @return \\Doctrine\\DBAL\\Driver\\PDOPgSql\\Driver|\\Illuminate\\Database\\PDO\\PostgresDriver\n     */\n    protected function getDoctrineDriver()\n    {\n        return class_exists(Version::class) ? new DoctrineDriver : new PostgresDriver;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Query/Builder.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Query;\n\nuse BackedEnum;\nuse Closure;\nuse DateTimeInterface;\nuse Illuminate\\Contracts\\Support\\Arrayable;\nuse Illuminate\\Database\\Concerns\\BuildsQueries;\nuse Illuminate\\Database\\Concerns\\ExplainsQueries;\nuse Illuminate\\Database\\ConnectionInterface;\nuse Illuminate\\Database\\Eloquent\\Builder as EloquentBuilder;\nuse Illuminate\\Database\\Eloquent\\Relations\\Relation;\nuse Illuminate\\Database\\Query\\Grammars\\Grammar;\nuse Illuminate\\Database\\Query\\Processors\\Processor;\nuse Illuminate\\Pagination\\Paginator;\nuse Illuminate\\Support\\Arr;\nuse Illuminate\\Support\\Collection;\nuse Illuminate\\Support\\LazyCollection;\nuse Illuminate\\Support\\Str;\nuse Illuminate\\Support\\Traits\\ForwardsCalls;\nuse Illuminate\\Support\\Traits\\Macroable;\nuse InvalidArgumentException;\nuse LogicException;\nuse RuntimeException;\n\nclass Builder\n{\n    use BuildsQueries, ExplainsQueries, ForwardsCalls, Macroable {\n        __call as macroCall;\n    }\n\n    /**\n     * The database connection instance.\n     *\n     * @var \\Illuminate\\Database\\ConnectionInterface\n     */\n    public $connection;\n\n    /**\n     * The database query grammar instance.\n     *\n     * @var \\Illuminate\\Database\\Query\\Grammars\\Grammar\n     */\n    public $grammar;\n\n    /**\n     * The database query post processor instance.\n     *\n     * @var \\Illuminate\\Database\\Query\\Processors\\Processor\n     */\n    public $processor;\n\n    /**\n     * The current query value bindings.\n     *\n     * @var array\n     */\n    public $bindings = [\n        'select' => [],\n        'from' => [],\n        'join' => [],\n        'where' => [],\n        'groupBy' => [],\n        'having' => [],\n        'order' => [],\n        'union' => [],\n        'unionOrder' => [],\n    ];\n\n    /**\n     * An aggregate function and column to be run.\n     *\n     * @var array\n     */\n    public $aggregate;\n\n    /**\n     * The columns that should be returned.\n     *\n     * @var array\n     */\n    public $columns;\n\n    /**\n     * Indicates if the query returns distinct results.\n     *\n     * Occasionally contains the columns that should be distinct.\n     *\n     * @var bool|array\n     */\n    public $distinct = false;\n\n    /**\n     * The table which the query is targeting.\n     *\n     * @var string\n     */\n    public $from;\n\n    /**\n     * The table joins for the query.\n     *\n     * @var array\n     */\n    public $joins;\n\n    /**\n     * The where constraints for the query.\n     *\n     * @var array\n     */\n    public $wheres = [];\n\n    /**\n     * The groupings for the query.\n     *\n     * @var array\n     */\n    public $groups;\n\n    /**\n     * The having constraints for the query.\n     *\n     * @var array\n     */\n    public $havings;\n\n    /**\n     * The orderings for the query.\n     *\n     * @var array\n     */\n    public $orders;\n\n    /**\n     * The maximum number of records to return.\n     *\n     * @var int\n     */\n    public $limit;\n\n    /**\n     * The number of records to skip.\n     *\n     * @var int\n     */\n    public $offset;\n\n    /**\n     * The query union statements.\n     *\n     * @var array\n     */\n    public $unions;\n\n    /**\n     * The maximum number of union records to return.\n     *\n     * @var int\n     */\n    public $unionLimit;\n\n    /**\n     * The number of union records to skip.\n     *\n     * @var int\n     */\n    public $unionOffset;\n\n    /**\n     * The orderings for the union query.\n     *\n     * @var array\n     */\n    public $unionOrders;\n\n    /**\n     * Indicates whether row locking is being used.\n     *\n     * @var string|bool\n     */\n    public $lock;\n\n    /**\n     * The callbacks that should be invoked before the query is executed.\n     *\n     * @var array\n     */\n    public $beforeQueryCallbacks = [];\n\n    /**\n     * All of the available clause operators.\n     *\n     * @var string[]\n     */\n    public $operators = [\n        '=', '<', '>', '<=', '>=', '<>', '!=', '<=>',\n        'like', 'like binary', 'not like', 'ilike',\n        '&', '|', '^', '<<', '>>', '&~',\n        'rlike', 'not rlike', 'regexp', 'not regexp',\n        '~', '~*', '!~', '!~*', 'similar to',\n        'not similar to', 'not ilike', '~~*', '!~~*',\n    ];\n\n    /**\n     * All of the available bitwise operators.\n     *\n     * @var string[]\n     */\n    public $bitwiseOperators = [\n        '&', '|', '^', '<<', '>>', '&~',\n    ];\n\n    /**\n     * Whether to use write pdo for the select.\n     *\n     * @var bool\n     */\n    public $useWritePdo = false;\n\n    /**\n     * Create a new query builder instance.\n     *\n     * @param  \\Illuminate\\Database\\ConnectionInterface  $connection\n     * @param  \\Illuminate\\Database\\Query\\Grammars\\Grammar|null  $grammar\n     * @param  \\Illuminate\\Database\\Query\\Processors\\Processor|null  $processor\n     * @return void\n     */\n    public function __construct(ConnectionInterface $connection,\n                                Grammar $grammar = null,\n                                Processor $processor = null)\n    {\n        $this->connection = $connection;\n        $this->grammar = $grammar ?: $connection->getQueryGrammar();\n        $this->processor = $processor ?: $connection->getPostProcessor();\n    }\n\n    /**\n     * Set the columns to be selected.\n     *\n     * @param  array|mixed  $columns\n     * @return $this\n     */\n    public function select($columns = ['*'])\n    {\n        $this->columns = [];\n        $this->bindings['select'] = [];\n        $columns = is_array($columns) ? $columns : func_get_args();\n\n        foreach ($columns as $as => $column) {\n            if (is_string($as) && $this->isQueryable($column)) {\n                $this->selectSub($column, $as);\n            } else {\n                $this->columns[] = $column;\n            }\n        }\n\n        return $this;\n    }\n\n    /**\n     * Add a subselect expression to the query.\n     *\n     * @param  \\Closure|\\Illuminate\\Database\\Query\\Builder|\\Illuminate\\Database\\Eloquent\\Builder|string  $query\n     * @param  string  $as\n     * @return $this\n     *\n     * @throws \\InvalidArgumentException\n     */\n    public function selectSub($query, $as)\n    {\n        [$query, $bindings] = $this->createSub($query);\n\n        return $this->selectRaw(\n            '('.$query.') as '.$this->grammar->wrap($as), $bindings\n        );\n    }\n\n    /**\n     * Add a new \"raw\" select expression to the query.\n     *\n     * @param  string  $expression\n     * @param  array  $bindings\n     * @return $this\n     */\n    public function selectRaw($expression, array $bindings = [])\n    {\n        $this->addSelect(new Expression($expression));\n\n        if ($bindings) {\n            $this->addBinding($bindings, 'select');\n        }\n\n        return $this;\n    }\n\n    /**\n     * Makes \"from\" fetch from a subquery.\n     *\n     * @param  \\Closure|\\Illuminate\\Database\\Query\\Builder|string  $query\n     * @param  string  $as\n     * @return $this\n     *\n     * @throws \\InvalidArgumentException\n     */\n    public function fromSub($query, $as)\n    {\n        [$query, $bindings] = $this->createSub($query);\n\n        return $this->fromRaw('('.$query.') as '.$this->grammar->wrapTable($as), $bindings);\n    }\n\n    /**\n     * Add a raw from clause to the query.\n     *\n     * @param  string  $expression\n     * @param  mixed  $bindings\n     * @return $this\n     */\n    public function fromRaw($expression, $bindings = [])\n    {\n        $this->from = new Expression($expression);\n\n        $this->addBinding($bindings, 'from');\n\n        return $this;\n    }\n\n    /**\n     * Creates a subquery and parse it.\n     *\n     * @param  \\Closure|\\Illuminate\\Database\\Query\\Builder|string  $query\n     * @return array\n     */\n    protected function createSub($query)\n    {\n        // If the given query is a Closure, we will execute it while passing in a new\n        // query instance to the Closure. This will give the developer a chance to\n        // format and work with the query before we cast it to a raw SQL string.\n        if ($query instanceof Closure) {\n            $callback = $query;\n\n            $callback($query = $this->forSubQuery());\n        }\n\n        return $this->parseSub($query);\n    }\n\n    /**\n     * Parse the subquery into SQL and bindings.\n     *\n     * @param  mixed  $query\n     * @return array\n     *\n     * @throws \\InvalidArgumentException\n     */\n    protected function parseSub($query)\n    {\n        if ($query instanceof self || $query instanceof EloquentBuilder || $query instanceof Relation) {\n            $query = $this->prependDatabaseNameIfCrossDatabaseQuery($query);\n\n            return [$query->toSql(), $query->getBindings()];\n        } elseif (is_string($query)) {\n            return [$query, []];\n        } else {\n            throw new InvalidArgumentException(\n                'A subquery must be a query builder instance, a Closure, or a string.'\n            );\n        }\n    }\n\n    /**\n     * Prepend the database name if the given query is on another database.\n     *\n     * @param  mixed  $query\n     * @return mixed\n     */\n    protected function prependDatabaseNameIfCrossDatabaseQuery($query)\n    {\n        if ($query->getConnection()->getDatabaseName() !==\n            $this->getConnection()->getDatabaseName()) {\n            $databaseName = $query->getConnection()->getDatabaseName();\n\n            if (strpos($query->from, $databaseName) !== 0 && strpos($query->from, '.') === false) {\n                $query->from($databaseName.'.'.$query->from);\n            }\n        }\n\n        return $query;\n    }\n\n    /**\n     * Add a new select column to the query.\n     *\n     * @param  array|mixed  $column\n     * @return $this\n     */\n    public function addSelect($column)\n    {\n        $columns = is_array($column) ? $column : func_get_args();\n\n        foreach ($columns as $as => $column) {\n            if (is_string($as) && $this->isQueryable($column)) {\n                if (is_null($this->columns)) {\n                    $this->select($this->from.'.*');\n                }\n\n                $this->selectSub($column, $as);\n            } else {\n                $this->columns[] = $column;\n            }\n        }\n\n        return $this;\n    }\n\n    /**\n     * Force the query to only return distinct results.\n     *\n     * @param  mixed  ...$distinct\n     * @return $this\n     */\n    public function distinct()\n    {\n        $columns = func_get_args();\n\n        if (count($columns) > 0) {\n            $this->distinct = is_array($columns[0]) || is_bool($columns[0]) ? $columns[0] : $columns;\n        } else {\n            $this->distinct = true;\n        }\n\n        return $this;\n    }\n\n    /**\n     * Set the table which the query is targeting.\n     *\n     * @param  \\Closure|\\Illuminate\\Database\\Query\\Builder|string  $table\n     * @param  string|null  $as\n     * @return $this\n     */\n    public function from($table, $as = null)\n    {\n        if ($this->isQueryable($table)) {\n            return $this->fromSub($table, $as);\n        }\n\n        $this->from = $as ? \"{$table} as {$as}\" : $table;\n\n        return $this;\n    }\n\n    /**\n     * Add a join clause to the query.\n     *\n     * @param  string  $table\n     * @param  \\Closure|string  $first\n     * @param  string|null  $operator\n     * @param  string|null  $second\n     * @param  string  $type\n     * @param  bool  $where\n     * @return $this\n     */\n    public function join($table, $first, $operator = null, $second = null, $type = 'inner', $where = false)\n    {\n        $join = $this->newJoinClause($this, $type, $table);\n\n        // If the first \"column\" of the join is really a Closure instance the developer\n        // is trying to build a join with a complex \"on\" clause containing more than\n        // one condition, so we'll add the join and call a Closure with the query.\n        if ($first instanceof Closure) {\n            $first($join);\n\n            $this->joins[] = $join;\n\n            $this->addBinding($join->getBindings(), 'join');\n        }\n\n        // If the column is simply a string, we can assume the join simply has a basic\n        // \"on\" clause with a single condition. So we will just build the join with\n        // this simple join clauses attached to it. There is not a join callback.\n        else {\n            $method = $where ? 'where' : 'on';\n\n            $this->joins[] = $join->$method($first, $operator, $second);\n\n            $this->addBinding($join->getBindings(), 'join');\n        }\n\n        return $this;\n    }\n\n    /**\n     * Add a \"join where\" clause to the query.\n     *\n     * @param  string  $table\n     * @param  \\Closure|string  $first\n     * @param  string  $operator\n     * @param  string  $second\n     * @param  string  $type\n     * @return $this\n     */\n    public function joinWhere($table, $first, $operator, $second, $type = 'inner')\n    {\n        return $this->join($table, $first, $operator, $second, $type, true);\n    }\n\n    /**\n     * Add a subquery join clause to the query.\n     *\n     * @param  \\Closure|\\Illuminate\\Database\\Query\\Builder|\\Illuminate\\Database\\Eloquent\\Builder|string  $query\n     * @param  string  $as\n     * @param  \\Closure|string  $first\n     * @param  string|null  $operator\n     * @param  string|null  $second\n     * @param  string  $type\n     * @param  bool  $where\n     * @return $this\n     *\n     * @throws \\InvalidArgumentException\n     */\n    public function joinSub($query, $as, $first, $operator = null, $second = null, $type = 'inner', $where = false)\n    {\n        [$query, $bindings] = $this->createSub($query);\n\n        $expression = '('.$query.') as '.$this->grammar->wrapTable($as);\n\n        $this->addBinding($bindings, 'join');\n\n        return $this->join(new Expression($expression), $first, $operator, $second, $type, $where);\n    }\n\n    /**\n     * Add a left join to the query.\n     *\n     * @param  string  $table\n     * @param  \\Closure|string  $first\n     * @param  string|null  $operator\n     * @param  string|null  $second\n     * @return $this\n     */\n    public function leftJoin($table, $first, $operator = null, $second = null)\n    {\n        return $this->join($table, $first, $operator, $second, 'left');\n    }\n\n    /**\n     * Add a \"join where\" clause to the query.\n     *\n     * @param  string  $table\n     * @param  \\Closure|string  $first\n     * @param  string  $operator\n     * @param  string  $second\n     * @return $this\n     */\n    public function leftJoinWhere($table, $first, $operator, $second)\n    {\n        return $this->joinWhere($table, $first, $operator, $second, 'left');\n    }\n\n    /**\n     * Add a subquery left join to the query.\n     *\n     * @param  \\Closure|\\Illuminate\\Database\\Query\\Builder|\\Illuminate\\Database\\Eloquent\\Builder|string  $query\n     * @param  string  $as\n     * @param  \\Closure|string  $first\n     * @param  string|null  $operator\n     * @param  string|null  $second\n     * @return $this\n     */\n    public function leftJoinSub($query, $as, $first, $operator = null, $second = null)\n    {\n        return $this->joinSub($query, $as, $first, $operator, $second, 'left');\n    }\n\n    /**\n     * Add a right join to the query.\n     *\n     * @param  string  $table\n     * @param  \\Closure|string  $first\n     * @param  string|null  $operator\n     * @param  string|null  $second\n     * @return $this\n     */\n    public function rightJoin($table, $first, $operator = null, $second = null)\n    {\n        return $this->join($table, $first, $operator, $second, 'right');\n    }\n\n    /**\n     * Add a \"right join where\" clause to the query.\n     *\n     * @param  string  $table\n     * @param  \\Closure|string  $first\n     * @param  string  $operator\n     * @param  string  $second\n     * @return $this\n     */\n    public function rightJoinWhere($table, $first, $operator, $second)\n    {\n        return $this->joinWhere($table, $first, $operator, $second, 'right');\n    }\n\n    /**\n     * Add a subquery right join to the query.\n     *\n     * @param  \\Closure|\\Illuminate\\Database\\Query\\Builder|\\Illuminate\\Database\\Eloquent\\Builder|string  $query\n     * @param  string  $as\n     * @param  \\Closure|string  $first\n     * @param  string|null  $operator\n     * @param  string|null  $second\n     * @return $this\n     */\n    public function rightJoinSub($query, $as, $first, $operator = null, $second = null)\n    {\n        return $this->joinSub($query, $as, $first, $operator, $second, 'right');\n    }\n\n    /**\n     * Add a \"cross join\" clause to the query.\n     *\n     * @param  string  $table\n     * @param  \\Closure|string|null  $first\n     * @param  string|null  $operator\n     * @param  string|null  $second\n     * @return $this\n     */\n    public function crossJoin($table, $first = null, $operator = null, $second = null)\n    {\n        if ($first) {\n            return $this->join($table, $first, $operator, $second, 'cross');\n        }\n\n        $this->joins[] = $this->newJoinClause($this, 'cross', $table);\n\n        return $this;\n    }\n\n    /**\n     * Add a subquery cross join to the query.\n     *\n     * @param  \\Closure|\\Illuminate\\Database\\Query\\Builder|string  $query\n     * @param  string  $as\n     * @return $this\n     */\n    public function crossJoinSub($query, $as)\n    {\n        [$query, $bindings] = $this->createSub($query);\n\n        $expression = '('.$query.') as '.$this->grammar->wrapTable($as);\n\n        $this->addBinding($bindings, 'join');\n\n        $this->joins[] = $this->newJoinClause($this, 'cross', new Expression($expression));\n\n        return $this;\n    }\n\n    /**\n     * Get a new join clause.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $parentQuery\n     * @param  string  $type\n     * @param  string  $table\n     * @return \\Illuminate\\Database\\Query\\JoinClause\n     */\n    protected function newJoinClause(self $parentQuery, $type, $table)\n    {\n        return new JoinClause($parentQuery, $type, $table);\n    }\n\n    /**\n     * Merge an array of where clauses and bindings.\n     *\n     * @param  array  $wheres\n     * @param  array  $bindings\n     * @return void\n     */\n    public function mergeWheres($wheres, $bindings)\n    {\n        $this->wheres = array_merge($this->wheres, (array) $wheres);\n\n        $this->bindings['where'] = array_values(\n            array_merge($this->bindings['where'], (array) $bindings)\n        );\n    }\n\n    /**\n     * Add a basic where clause to the query.\n     *\n     * @param  \\Closure|string|array  $column\n     * @param  mixed  $operator\n     * @param  mixed  $value\n     * @param  string  $boolean\n     * @return $this\n     */\n    public function where($column, $operator = null, $value = null, $boolean = 'and')\n    {\n        // If the column is an array, we will assume it is an array of key-value pairs\n        // and can add them each as a where clause. We will maintain the boolean we\n        // received when the method was called and pass it into the nested where.\n        if (is_array($column)) {\n            return $this->addArrayOfWheres($column, $boolean);\n        }\n\n        // Here we will make some assumptions about the operator. If only 2 values are\n        // passed to the method, we will assume that the operator is an equals sign\n        // and keep going. Otherwise, we'll require the operator to be passed in.\n        [$value, $operator] = $this->prepareValueAndOperator(\n            $value, $operator, func_num_args() === 2\n        );\n\n        // If the columns is actually a Closure instance, we will assume the developer\n        // wants to begin a nested where statement which is wrapped in parenthesis.\n        // We'll add that Closure to the query then return back out immediately.\n        if ($column instanceof Closure && is_null($operator)) {\n            return $this->whereNested($column, $boolean);\n        }\n\n        // If the column is a Closure instance and there is an operator value, we will\n        // assume the developer wants to run a subquery and then compare the result\n        // of that subquery with the given value that was provided to the method.\n        if ($this->isQueryable($column) && ! is_null($operator)) {\n            [$sub, $bindings] = $this->createSub($column);\n\n            return $this->addBinding($bindings, 'where')\n                ->where(new Expression('('.$sub.')'), $operator, $value, $boolean);\n        }\n\n        // If the given operator is not found in the list of valid operators we will\n        // assume that the developer is just short-cutting the '=' operators and\n        // we will set the operators to '=' and set the values appropriately.\n        if ($this->invalidOperator($operator)) {\n            [$value, $operator] = [$operator, '='];\n        }\n\n        // If the value is a Closure, it means the developer is performing an entire\n        // sub-select within the query and we will need to compile the sub-select\n        // within the where clause to get the appropriate query record results.\n        if ($value instanceof Closure) {\n            return $this->whereSub($column, $operator, $value, $boolean);\n        }\n\n        // If the value is \"null\", we will just assume the developer wants to add a\n        // where null clause to the query. So, we will allow a short-cut here to\n        // that method for convenience so the developer doesn't have to check.\n        if (is_null($value)) {\n            return $this->whereNull($column, $boolean, $operator !== '=');\n        }\n\n        $type = 'Basic';\n\n        // If the column is making a JSON reference we'll check to see if the value\n        // is a boolean. If it is, we'll add the raw boolean string as an actual\n        // value to the query to ensure this is properly handled by the query.\n        if (Str::contains($column, '->') && is_bool($value)) {\n            $value = new Expression($value ? 'true' : 'false');\n\n            if (is_string($column)) {\n                $type = 'JsonBoolean';\n            }\n        }\n\n        if ($this->isBitwiseOperator($operator)) {\n            $type = 'Bitwise';\n        }\n\n        // Now that we are working with just a simple query we can put the elements\n        // in our array and add the query binding to our array of bindings that\n        // will be bound to each SQL statements when it is finally executed.\n        $this->wheres[] = compact(\n            'type', 'column', 'operator', 'value', 'boolean'\n        );\n\n        if (! $value instanceof Expression) {\n            $this->addBinding($this->flattenValue($value), 'where');\n        }\n\n        return $this;\n    }\n\n    /**\n     * Add an array of where clauses to the query.\n     *\n     * @param  array  $column\n     * @param  string  $boolean\n     * @param  string  $method\n     * @return $this\n     */\n    protected function addArrayOfWheres($column, $boolean, $method = 'where')\n    {\n        return $this->whereNested(function ($query) use ($column, $method, $boolean) {\n            foreach ($column as $key => $value) {\n                if (is_numeric($key) && is_array($value)) {\n                    $query->{$method}(...array_values($value));\n                } else {\n                    $query->$method($key, '=', $value, $boolean);\n                }\n            }\n        }, $boolean);\n    }\n\n    /**\n     * Prepare the value and operator for a where clause.\n     *\n     * @param  string  $value\n     * @param  string  $operator\n     * @param  bool  $useDefault\n     * @return array\n     *\n     * @throws \\InvalidArgumentException\n     */\n    public function prepareValueAndOperator($value, $operator, $useDefault = false)\n    {\n        if ($useDefault) {\n            return [$operator, '='];\n        } elseif ($this->invalidOperatorAndValue($operator, $value)) {\n            throw new InvalidArgumentException('Illegal operator and value combination.');\n        }\n\n        return [$value, $operator];\n    }\n\n    /**\n     * Determine if the given operator and value combination is legal.\n     *\n     * Prevents using Null values with invalid operators.\n     *\n     * @param  string  $operator\n     * @param  mixed  $value\n     * @return bool\n     */\n    protected function invalidOperatorAndValue($operator, $value)\n    {\n        return is_null($value) && in_array($operator, $this->operators) &&\n             ! in_array($operator, ['=', '<>', '!=']);\n    }\n\n    /**\n     * Determine if the given operator is supported.\n     *\n     * @param  string  $operator\n     * @return bool\n     */\n    protected function invalidOperator($operator)\n    {\n        return ! is_string($operator) || (! in_array(strtolower($operator), $this->operators, true) &&\n               ! in_array(strtolower($operator), $this->grammar->getOperators(), true));\n    }\n\n    /**\n     * Determine if the operator is a bitwise operator.\n     *\n     * @param  string  $operator\n     * @return bool\n     */\n    protected function isBitwiseOperator($operator)\n    {\n        return in_array(strtolower($operator), $this->bitwiseOperators, true) ||\n               in_array(strtolower($operator), $this->grammar->getBitwiseOperators(), true);\n    }\n\n    /**\n     * Add an \"or where\" clause to the query.\n     *\n     * @param  \\Closure|string|array  $column\n     * @param  mixed  $operator\n     * @param  mixed  $value\n     * @return $this\n     */\n    public function orWhere($column, $operator = null, $value = null)\n    {\n        [$value, $operator] = $this->prepareValueAndOperator(\n            $value, $operator, func_num_args() === 2\n        );\n\n        return $this->where($column, $operator, $value, 'or');\n    }\n\n    /**\n     * Add a \"where\" clause comparing two columns to the query.\n     *\n     * @param  string|array  $first\n     * @param  string|null  $operator\n     * @param  string|null  $second\n     * @param  string|null  $boolean\n     * @return $this\n     */\n    public function whereColumn($first, $operator = null, $second = null, $boolean = 'and')\n    {\n        // If the column is an array, we will assume it is an array of key-value pairs\n        // and can add them each as a where clause. We will maintain the boolean we\n        // received when the method was called and pass it into the nested where.\n        if (is_array($first)) {\n            return $this->addArrayOfWheres($first, $boolean, 'whereColumn');\n        }\n\n        // If the given operator is not found in the list of valid operators we will\n        // assume that the developer is just short-cutting the '=' operators and\n        // we will set the operators to '=' and set the values appropriately.\n        if ($this->invalidOperator($operator)) {\n            [$second, $operator] = [$operator, '='];\n        }\n\n        // Finally, we will add this where clause into this array of clauses that we\n        // are building for the query. All of them will be compiled via a grammar\n        // once the query is about to be executed and run against the database.\n        $type = 'Column';\n\n        $this->wheres[] = compact(\n            'type', 'first', 'operator', 'second', 'boolean'\n        );\n\n        return $this;\n    }\n\n    /**\n     * Add an \"or where\" clause comparing two columns to the query.\n     *\n     * @param  string|array  $first\n     * @param  string|null  $operator\n     * @param  string|null  $second\n     * @return $this\n     */\n    public function orWhereColumn($first, $operator = null, $second = null)\n    {\n        return $this->whereColumn($first, $operator, $second, 'or');\n    }\n\n    /**\n     * Add a raw where clause to the query.\n     *\n     * @param  string  $sql\n     * @param  mixed  $bindings\n     * @param  string  $boolean\n     * @return $this\n     */\n    public function whereRaw($sql, $bindings = [], $boolean = 'and')\n    {\n        $this->wheres[] = ['type' => 'raw', 'sql' => $sql, 'boolean' => $boolean];\n\n        $this->addBinding((array) $bindings, 'where');\n\n        return $this;\n    }\n\n    /**\n     * Add a raw or where clause to the query.\n     *\n     * @param  string  $sql\n     * @param  mixed  $bindings\n     * @return $this\n     */\n    public function orWhereRaw($sql, $bindings = [])\n    {\n        return $this->whereRaw($sql, $bindings, 'or');\n    }\n\n    /**\n     * Add a \"where in\" clause to the query.\n     *\n     * @param  string  $column\n     * @param  mixed  $values\n     * @param  string  $boolean\n     * @param  bool  $not\n     * @return $this\n     */\n    public function whereIn($column, $values, $boolean = 'and', $not = false)\n    {\n        $type = $not ? 'NotIn' : 'In';\n\n        // If the value is a query builder instance we will assume the developer wants to\n        // look for any values that exists within this given query. So we will add the\n        // query accordingly so that this query is properly executed when it is run.\n        if ($this->isQueryable($values)) {\n            [$query, $bindings] = $this->createSub($values);\n\n            $values = [new Expression($query)];\n\n            $this->addBinding($bindings, 'where');\n        }\n\n        // Next, if the value is Arrayable we need to cast it to its raw array form so we\n        // have the underlying array value instead of an Arrayable object which is not\n        // able to be added as a binding, etc. We will then add to the wheres array.\n        if ($values instanceof Arrayable) {\n            $values = $values->toArray();\n        }\n\n        $this->wheres[] = compact('type', 'column', 'values', 'boolean');\n\n        // Finally we'll add a binding for each values unless that value is an expression\n        // in which case we will just skip over it since it will be the query as a raw\n        // string and not as a parameterized place-holder to be replaced by the PDO.\n        $this->addBinding($this->cleanBindings($values), 'where');\n\n        return $this;\n    }\n\n    /**\n     * Add an \"or where in\" clause to the query.\n     *\n     * @param  string  $column\n     * @param  mixed  $values\n     * @return $this\n     */\n    public function orWhereIn($column, $values)\n    {\n        return $this->whereIn($column, $values, 'or');\n    }\n\n    /**\n     * Add a \"where not in\" clause to the query.\n     *\n     * @param  string  $column\n     * @param  mixed  $values\n     * @param  string  $boolean\n     * @return $this\n     */\n    public function whereNotIn($column, $values, $boolean = 'and')\n    {\n        return $this->whereIn($column, $values, $boolean, true);\n    }\n\n    /**\n     * Add an \"or where not in\" clause to the query.\n     *\n     * @param  string  $column\n     * @param  mixed  $values\n     * @return $this\n     */\n    public function orWhereNotIn($column, $values)\n    {\n        return $this->whereNotIn($column, $values, 'or');\n    }\n\n    /**\n     * Add a \"where in raw\" clause for integer values to the query.\n     *\n     * @param  string  $column\n     * @param  \\Illuminate\\Contracts\\Support\\Arrayable|array  $values\n     * @param  string  $boolean\n     * @param  bool  $not\n     * @return $this\n     */\n    public function whereIntegerInRaw($column, $values, $boolean = 'and', $not = false)\n    {\n        $type = $not ? 'NotInRaw' : 'InRaw';\n\n        if ($values instanceof Arrayable) {\n            $values = $values->toArray();\n        }\n\n        foreach ($values as &$value) {\n            $value = (int) $value;\n        }\n\n        $this->wheres[] = compact('type', 'column', 'values', 'boolean');\n\n        return $this;\n    }\n\n    /**\n     * Add an \"or where in raw\" clause for integer values to the query.\n     *\n     * @param  string  $column\n     * @param  \\Illuminate\\Contracts\\Support\\Arrayable|array  $values\n     * @return $this\n     */\n    public function orWhereIntegerInRaw($column, $values)\n    {\n        return $this->whereIntegerInRaw($column, $values, 'or');\n    }\n\n    /**\n     * Add a \"where not in raw\" clause for integer values to the query.\n     *\n     * @param  string  $column\n     * @param  \\Illuminate\\Contracts\\Support\\Arrayable|array  $values\n     * @param  string  $boolean\n     * @return $this\n     */\n    public function whereIntegerNotInRaw($column, $values, $boolean = 'and')\n    {\n        return $this->whereIntegerInRaw($column, $values, $boolean, true);\n    }\n\n    /**\n     * Add an \"or where not in raw\" clause for integer values to the query.\n     *\n     * @param  string  $column\n     * @param  \\Illuminate\\Contracts\\Support\\Arrayable|array  $values\n     * @return $this\n     */\n    public function orWhereIntegerNotInRaw($column, $values)\n    {\n        return $this->whereIntegerNotInRaw($column, $values, 'or');\n    }\n\n    /**\n     * Add a \"where null\" clause to the query.\n     *\n     * @param  string|array  $columns\n     * @param  string  $boolean\n     * @param  bool  $not\n     * @return $this\n     */\n    public function whereNull($columns, $boolean = 'and', $not = false)\n    {\n        $type = $not ? 'NotNull' : 'Null';\n\n        foreach (Arr::wrap($columns) as $column) {\n            $this->wheres[] = compact('type', 'column', 'boolean');\n        }\n\n        return $this;\n    }\n\n    /**\n     * Add an \"or where null\" clause to the query.\n     *\n     * @param  string|array  $column\n     * @return $this\n     */\n    public function orWhereNull($column)\n    {\n        return $this->whereNull($column, 'or');\n    }\n\n    /**\n     * Add a \"where not null\" clause to the query.\n     *\n     * @param  string|array  $columns\n     * @param  string  $boolean\n     * @return $this\n     */\n    public function whereNotNull($columns, $boolean = 'and')\n    {\n        return $this->whereNull($columns, $boolean, true);\n    }\n\n    /**\n     * Add a where between statement to the query.\n     *\n     * @param  string|\\Illuminate\\Database\\Query\\Expression  $column\n     * @param  array  $values\n     * @param  string  $boolean\n     * @param  bool  $not\n     * @return $this\n     */\n    public function whereBetween($column, array $values, $boolean = 'and', $not = false)\n    {\n        $type = 'between';\n\n        $this->wheres[] = compact('type', 'column', 'values', 'boolean', 'not');\n\n        $this->addBinding(array_slice($this->cleanBindings(Arr::flatten($values)), 0, 2), 'where');\n\n        return $this;\n    }\n\n    /**\n     * Add a where between statement using columns to the query.\n     *\n     * @param  string  $column\n     * @param  array  $values\n     * @param  string  $boolean\n     * @param  bool  $not\n     * @return $this\n     */\n    public function whereBetweenColumns($column, array $values, $boolean = 'and', $not = false)\n    {\n        $type = 'betweenColumns';\n\n        $this->wheres[] = compact('type', 'column', 'values', 'boolean', 'not');\n\n        return $this;\n    }\n\n    /**\n     * Add an or where between statement to the query.\n     *\n     * @param  string  $column\n     * @param  array  $values\n     * @return $this\n     */\n    public function orWhereBetween($column, array $values)\n    {\n        return $this->whereBetween($column, $values, 'or');\n    }\n\n    /**\n     * Add an or where between statement using columns to the query.\n     *\n     * @param  string  $column\n     * @param  array  $values\n     * @return $this\n     */\n    public function orWhereBetweenColumns($column, array $values)\n    {\n        return $this->whereBetweenColumns($column, $values, 'or');\n    }\n\n    /**\n     * Add a where not between statement to the query.\n     *\n     * @param  string  $column\n     * @param  array  $values\n     * @param  string  $boolean\n     * @return $this\n     */\n    public function whereNotBetween($column, array $values, $boolean = 'and')\n    {\n        return $this->whereBetween($column, $values, $boolean, true);\n    }\n\n    /**\n     * Add a where not between statement using columns to the query.\n     *\n     * @param  string  $column\n     * @param  array  $values\n     * @param  string  $boolean\n     * @return $this\n     */\n    public function whereNotBetweenColumns($column, array $values, $boolean = 'and')\n    {\n        return $this->whereBetweenColumns($column, $values, $boolean, true);\n    }\n\n    /**\n     * Add an or where not between statement to the query.\n     *\n     * @param  string  $column\n     * @param  array  $values\n     * @return $this\n     */\n    public function orWhereNotBetween($column, array $values)\n    {\n        return $this->whereNotBetween($column, $values, 'or');\n    }\n\n    /**\n     * Add an or where not between statement using columns to the query.\n     *\n     * @param  string  $column\n     * @param  array  $values\n     * @return $this\n     */\n    public function orWhereNotBetweenColumns($column, array $values)\n    {\n        return $this->whereNotBetweenColumns($column, $values, 'or');\n    }\n\n    /**\n     * Add an \"or where not null\" clause to the query.\n     *\n     * @param  string  $column\n     * @return $this\n     */\n    public function orWhereNotNull($column)\n    {\n        return $this->whereNotNull($column, 'or');\n    }\n\n    /**\n     * Add a \"where date\" statement to the query.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Expression|string  $column\n     * @param  string  $operator\n     * @param  \\DateTimeInterface|string|null  $value\n     * @param  string  $boolean\n     * @return $this\n     */\n    public function whereDate($column, $operator, $value = null, $boolean = 'and')\n    {\n        [$value, $operator] = $this->prepareValueAndOperator(\n            $value, $operator, func_num_args() === 2\n        );\n\n        $value = $this->flattenValue($value);\n\n        if ($value instanceof DateTimeInterface) {\n            $value = $value->format('Y-m-d');\n        }\n\n        return $this->addDateBasedWhere('Date', $column, $operator, $value, $boolean);\n    }\n\n    /**\n     * Add an \"or where date\" statement to the query.\n     *\n     * @param  string  $column\n     * @param  string  $operator\n     * @param  \\DateTimeInterface|string|null  $value\n     * @return $this\n     */\n    public function orWhereDate($column, $operator, $value = null)\n    {\n        [$value, $operator] = $this->prepareValueAndOperator(\n            $value, $operator, func_num_args() === 2\n        );\n\n        return $this->whereDate($column, $operator, $value, 'or');\n    }\n\n    /**\n     * Add a \"where time\" statement to the query.\n     *\n     * @param  string  $column\n     * @param  string  $operator\n     * @param  \\DateTimeInterface|string|null  $value\n     * @param  string  $boolean\n     * @return $this\n     */\n    public function whereTime($column, $operator, $value = null, $boolean = 'and')\n    {\n        [$value, $operator] = $this->prepareValueAndOperator(\n            $value, $operator, func_num_args() === 2\n        );\n\n        $value = $this->flattenValue($value);\n\n        if ($value instanceof DateTimeInterface) {\n            $value = $value->format('H:i:s');\n        }\n\n        return $this->addDateBasedWhere('Time', $column, $operator, $value, $boolean);\n    }\n\n    /**\n     * Add an \"or where time\" statement to the query.\n     *\n     * @param  string  $column\n     * @param  string  $operator\n     * @param  \\DateTimeInterface|string|null  $value\n     * @return $this\n     */\n    public function orWhereTime($column, $operator, $value = null)\n    {\n        [$value, $operator] = $this->prepareValueAndOperator(\n            $value, $operator, func_num_args() === 2\n        );\n\n        return $this->whereTime($column, $operator, $value, 'or');\n    }\n\n    /**\n     * Add a \"where day\" statement to the query.\n     *\n     * @param  string  $column\n     * @param  string  $operator\n     * @param  \\DateTimeInterface|string|null  $value\n     * @param  string  $boolean\n     * @return $this\n     */\n    public function whereDay($column, $operator, $value = null, $boolean = 'and')\n    {\n        [$value, $operator] = $this->prepareValueAndOperator(\n            $value, $operator, func_num_args() === 2\n        );\n\n        $value = $this->flattenValue($value);\n\n        if ($value instanceof DateTimeInterface) {\n            $value = $value->format('d');\n        }\n\n        if (! $value instanceof Expression) {\n            $value = str_pad($value, 2, '0', STR_PAD_LEFT);\n        }\n\n        return $this->addDateBasedWhere('Day', $column, $operator, $value, $boolean);\n    }\n\n    /**\n     * Add an \"or where day\" statement to the query.\n     *\n     * @param  string  $column\n     * @param  string  $operator\n     * @param  \\DateTimeInterface|string|null  $value\n     * @return $this\n     */\n    public function orWhereDay($column, $operator, $value = null)\n    {\n        [$value, $operator] = $this->prepareValueAndOperator(\n            $value, $operator, func_num_args() === 2\n        );\n\n        return $this->whereDay($column, $operator, $value, 'or');\n    }\n\n    /**\n     * Add a \"where month\" statement to the query.\n     *\n     * @param  string  $column\n     * @param  string  $operator\n     * @param  \\DateTimeInterface|string|null  $value\n     * @param  string  $boolean\n     * @return $this\n     */\n    public function whereMonth($column, $operator, $value = null, $boolean = 'and')\n    {\n        [$value, $operator] = $this->prepareValueAndOperator(\n            $value, $operator, func_num_args() === 2\n        );\n\n        $value = $this->flattenValue($value);\n\n        if ($value instanceof DateTimeInterface) {\n            $value = $value->format('m');\n        }\n\n        if (! $value instanceof Expression) {\n            $value = str_pad($value, 2, '0', STR_PAD_LEFT);\n        }\n\n        return $this->addDateBasedWhere('Month', $column, $operator, $value, $boolean);\n    }\n\n    /**\n     * Add an \"or where month\" statement to the query.\n     *\n     * @param  string  $column\n     * @param  string  $operator\n     * @param  \\DateTimeInterface|string|null  $value\n     * @return $this\n     */\n    public function orWhereMonth($column, $operator, $value = null)\n    {\n        [$value, $operator] = $this->prepareValueAndOperator(\n            $value, $operator, func_num_args() === 2\n        );\n\n        return $this->whereMonth($column, $operator, $value, 'or');\n    }\n\n    /**\n     * Add a \"where year\" statement to the query.\n     *\n     * @param  string  $column\n     * @param  string  $operator\n     * @param  \\DateTimeInterface|string|int|null  $value\n     * @param  string  $boolean\n     * @return $this\n     */\n    public function whereYear($column, $operator, $value = null, $boolean = 'and')\n    {\n        [$value, $operator] = $this->prepareValueAndOperator(\n            $value, $operator, func_num_args() === 2\n        );\n\n        $value = $this->flattenValue($value);\n\n        if ($value instanceof DateTimeInterface) {\n            $value = $value->format('Y');\n        }\n\n        return $this->addDateBasedWhere('Year', $column, $operator, $value, $boolean);\n    }\n\n    /**\n     * Add an \"or where year\" statement to the query.\n     *\n     * @param  string  $column\n     * @param  string  $operator\n     * @param  \\DateTimeInterface|string|int|null  $value\n     * @return $this\n     */\n    public function orWhereYear($column, $operator, $value = null)\n    {\n        [$value, $operator] = $this->prepareValueAndOperator(\n            $value, $operator, func_num_args() === 2\n        );\n\n        return $this->whereYear($column, $operator, $value, 'or');\n    }\n\n    /**\n     * Add a date based (year, month, day, time) statement to the query.\n     *\n     * @param  string  $type\n     * @param  string  $column\n     * @param  string  $operator\n     * @param  mixed  $value\n     * @param  string  $boolean\n     * @return $this\n     */\n    protected function addDateBasedWhere($type, $column, $operator, $value, $boolean = 'and')\n    {\n        $this->wheres[] = compact('column', 'type', 'boolean', 'operator', 'value');\n\n        if (! $value instanceof Expression) {\n            $this->addBinding($value, 'where');\n        }\n\n        return $this;\n    }\n\n    /**\n     * Add a nested where statement to the query.\n     *\n     * @param  \\Closure  $callback\n     * @param  string  $boolean\n     * @return $this\n     */\n    public function whereNested(Closure $callback, $boolean = 'and')\n    {\n        call_user_func($callback, $query = $this->forNestedWhere());\n\n        return $this->addNestedWhereQuery($query, $boolean);\n    }\n\n    /**\n     * Create a new query instance for nested where condition.\n     *\n     * @return \\Illuminate\\Database\\Query\\Builder\n     */\n    public function forNestedWhere()\n    {\n        return $this->newQuery()->from($this->from);\n    }\n\n    /**\n     * Add another query builder as a nested where to the query builder.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  string  $boolean\n     * @return $this\n     */\n    public function addNestedWhereQuery($query, $boolean = 'and')\n    {\n        if (count($query->wheres)) {\n            $type = 'Nested';\n\n            $this->wheres[] = compact('type', 'query', 'boolean');\n\n            $this->addBinding($query->getRawBindings()['where'], 'where');\n        }\n\n        return $this;\n    }\n\n    /**\n     * Add a full sub-select to the query.\n     *\n     * @param  string  $column\n     * @param  string  $operator\n     * @param  \\Closure  $callback\n     * @param  string  $boolean\n     * @return $this\n     */\n    protected function whereSub($column, $operator, Closure $callback, $boolean)\n    {\n        $type = 'Sub';\n\n        // Once we have the query instance we can simply execute it so it can add all\n        // of the sub-select's conditions to itself, and then we can cache it off\n        // in the array of where clauses for the \"main\" parent query instance.\n        call_user_func($callback, $query = $this->forSubQuery());\n\n        $this->wheres[] = compact(\n            'type', 'column', 'operator', 'query', 'boolean'\n        );\n\n        $this->addBinding($query->getBindings(), 'where');\n\n        return $this;\n    }\n\n    /**\n     * Add an exists clause to the query.\n     *\n     * @param  \\Closure  $callback\n     * @param  string  $boolean\n     * @param  bool  $not\n     * @return $this\n     */\n    public function whereExists(Closure $callback, $boolean = 'and', $not = false)\n    {\n        $query = $this->forSubQuery();\n\n        // Similar to the sub-select clause, we will create a new query instance so\n        // the developer may cleanly specify the entire exists query and we will\n        // compile the whole thing in the grammar and insert it into the SQL.\n        call_user_func($callback, $query);\n\n        return $this->addWhereExistsQuery($query, $boolean, $not);\n    }\n\n    /**\n     * Add an or exists clause to the query.\n     *\n     * @param  \\Closure  $callback\n     * @param  bool  $not\n     * @return $this\n     */\n    public function orWhereExists(Closure $callback, $not = false)\n    {\n        return $this->whereExists($callback, 'or', $not);\n    }\n\n    /**\n     * Add a where not exists clause to the query.\n     *\n     * @param  \\Closure  $callback\n     * @param  string  $boolean\n     * @return $this\n     */\n    public function whereNotExists(Closure $callback, $boolean = 'and')\n    {\n        return $this->whereExists($callback, $boolean, true);\n    }\n\n    /**\n     * Add a where not exists clause to the query.\n     *\n     * @param  \\Closure  $callback\n     * @return $this\n     */\n    public function orWhereNotExists(Closure $callback)\n    {\n        return $this->orWhereExists($callback, true);\n    }\n\n    /**\n     * Add an exists clause to the query.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  string  $boolean\n     * @param  bool  $not\n     * @return $this\n     */\n    public function addWhereExistsQuery(self $query, $boolean = 'and', $not = false)\n    {\n        $type = $not ? 'NotExists' : 'Exists';\n\n        $this->wheres[] = compact('type', 'query', 'boolean');\n\n        $this->addBinding($query->getBindings(), 'where');\n\n        return $this;\n    }\n\n    /**\n     * Adds a where condition using row values.\n     *\n     * @param  array  $columns\n     * @param  string  $operator\n     * @param  array  $values\n     * @param  string  $boolean\n     * @return $this\n     *\n     * @throws \\InvalidArgumentException\n     */\n    public function whereRowValues($columns, $operator, $values, $boolean = 'and')\n    {\n        if (count($columns) !== count($values)) {\n            throw new InvalidArgumentException('The number of columns must match the number of values');\n        }\n\n        $type = 'RowValues';\n\n        $this->wheres[] = compact('type', 'columns', 'operator', 'values', 'boolean');\n\n        $this->addBinding($this->cleanBindings($values));\n\n        return $this;\n    }\n\n    /**\n     * Adds an or where condition using row values.\n     *\n     * @param  array  $columns\n     * @param  string  $operator\n     * @param  array  $values\n     * @return $this\n     */\n    public function orWhereRowValues($columns, $operator, $values)\n    {\n        return $this->whereRowValues($columns, $operator, $values, 'or');\n    }\n\n    /**\n     * Add a \"where JSON contains\" clause to the query.\n     *\n     * @param  string  $column\n     * @param  mixed  $value\n     * @param  string  $boolean\n     * @param  bool  $not\n     * @return $this\n     */\n    public function whereJsonContains($column, $value, $boolean = 'and', $not = false)\n    {\n        $type = 'JsonContains';\n\n        $this->wheres[] = compact('type', 'column', 'value', 'boolean', 'not');\n\n        if (! $value instanceof Expression) {\n            $this->addBinding($this->grammar->prepareBindingForJsonContains($value));\n        }\n\n        return $this;\n    }\n\n    /**\n     * Add an \"or where JSON contains\" clause to the query.\n     *\n     * @param  string  $column\n     * @param  mixed  $value\n     * @return $this\n     */\n    public function orWhereJsonContains($column, $value)\n    {\n        return $this->whereJsonContains($column, $value, 'or');\n    }\n\n    /**\n     * Add a \"where JSON not contains\" clause to the query.\n     *\n     * @param  string  $column\n     * @param  mixed  $value\n     * @param  string  $boolean\n     * @return $this\n     */\n    public function whereJsonDoesntContain($column, $value, $boolean = 'and')\n    {\n        return $this->whereJsonContains($column, $value, $boolean, true);\n    }\n\n    /**\n     * Add an \"or where JSON not contains\" clause to the query.\n     *\n     * @param  string  $column\n     * @param  mixed  $value\n     * @return $this\n     */\n    public function orWhereJsonDoesntContain($column, $value)\n    {\n        return $this->whereJsonDoesntContain($column, $value, 'or');\n    }\n\n    /**\n     * Add a \"where JSON length\" clause to the query.\n     *\n     * @param  string  $column\n     * @param  mixed  $operator\n     * @param  mixed  $value\n     * @param  string  $boolean\n     * @return $this\n     */\n    public function whereJsonLength($column, $operator, $value = null, $boolean = 'and')\n    {\n        $type = 'JsonLength';\n\n        [$value, $operator] = $this->prepareValueAndOperator(\n            $value, $operator, func_num_args() === 2\n        );\n\n        $this->wheres[] = compact('type', 'column', 'operator', 'value', 'boolean');\n\n        if (! $value instanceof Expression) {\n            $this->addBinding((int) $this->flattenValue($value));\n        }\n\n        return $this;\n    }\n\n    /**\n     * Add an \"or where JSON length\" clause to the query.\n     *\n     * @param  string  $column\n     * @param  mixed  $operator\n     * @param  mixed  $value\n     * @return $this\n     */\n    public function orWhereJsonLength($column, $operator, $value = null)\n    {\n        [$value, $operator] = $this->prepareValueAndOperator(\n            $value, $operator, func_num_args() === 2\n        );\n\n        return $this->whereJsonLength($column, $operator, $value, 'or');\n    }\n\n    /**\n     * Handles dynamic \"where\" clauses to the query.\n     *\n     * @param  string  $method\n     * @param  array  $parameters\n     * @return $this\n     */\n    public function dynamicWhere($method, $parameters)\n    {\n        $finder = substr($method, 5);\n\n        $segments = preg_split(\n            '/(And|Or)(?=[A-Z])/', $finder, -1, PREG_SPLIT_DELIM_CAPTURE\n        );\n\n        // The connector variable will determine which connector will be used for the\n        // query condition. We will change it as we come across new boolean values\n        // in the dynamic method strings, which could contain a number of these.\n        $connector = 'and';\n\n        $index = 0;\n\n        foreach ($segments as $segment) {\n            // If the segment is not a boolean connector, we can assume it is a column's name\n            // and we will add it to the query as a new constraint as a where clause, then\n            // we can keep iterating through the dynamic method string's segments again.\n            if ($segment !== 'And' && $segment !== 'Or') {\n                $this->addDynamic($segment, $connector, $parameters, $index);\n\n                $index++;\n            }\n\n            // Otherwise, we will store the connector so we know how the next where clause we\n            // find in the query should be connected to the previous ones, meaning we will\n            // have the proper boolean connector to connect the next where clause found.\n            else {\n                $connector = $segment;\n            }\n        }\n\n        return $this;\n    }\n\n    /**\n     * Add a single dynamic where clause statement to the query.\n     *\n     * @param  string  $segment\n     * @param  string  $connector\n     * @param  array  $parameters\n     * @param  int  $index\n     * @return void\n     */\n    protected function addDynamic($segment, $connector, $parameters, $index)\n    {\n        // Once we have parsed out the columns and formatted the boolean operators we\n        // are ready to add it to this query as a where clause just like any other\n        // clause on the query. Then we'll increment the parameter index values.\n        $bool = strtolower($connector);\n\n        $this->where(Str::snake($segment), '=', $parameters[$index], $bool);\n    }\n\n    /**\n     * Add a \"where fulltext\" clause to the query.\n     *\n     * @param  string|string[]  $columns\n     * @param  string  $value\n     * @param  string  $boolean\n     * @return $this\n     */\n    public function whereFullText($columns, $value, array $options = [], $boolean = 'and')\n    {\n        $type = 'Fulltext';\n\n        $columns = (array) $columns;\n\n        $this->wheres[] = compact('type', 'columns', 'value', 'options', 'boolean');\n\n        $this->addBinding($value);\n\n        return $this;\n    }\n\n    /**\n     * Add a \"or where fulltext\" clause to the query.\n     *\n     * @param  string|string[]  $columns\n     * @param  string  $value\n     * @return $this\n     */\n    public function orWhereFullText($columns, $value, array $options = [])\n    {\n        return $this->whereFulltext($columns, $value, $options, 'or');\n    }\n\n    /**\n     * Add a \"group by\" clause to the query.\n     *\n     * @param  array|string  ...$groups\n     * @return $this\n     */\n    public function groupBy(...$groups)\n    {\n        foreach ($groups as $group) {\n            $this->groups = array_merge(\n                (array) $this->groups,\n                Arr::wrap($group)\n            );\n        }\n\n        return $this;\n    }\n\n    /**\n     * Add a raw groupBy clause to the query.\n     *\n     * @param  string  $sql\n     * @param  array  $bindings\n     * @return $this\n     */\n    public function groupByRaw($sql, array $bindings = [])\n    {\n        $this->groups[] = new Expression($sql);\n\n        $this->addBinding($bindings, 'groupBy');\n\n        return $this;\n    }\n\n    /**\n     * Add a \"having\" clause to the query.\n     *\n     * @param  string  $column\n     * @param  string|null  $operator\n     * @param  string|null  $value\n     * @param  string  $boolean\n     * @return $this\n     */\n    public function having($column, $operator = null, $value = null, $boolean = 'and')\n    {\n        $type = 'Basic';\n\n        // Here we will make some assumptions about the operator. If only 2 values are\n        // passed to the method, we will assume that the operator is an equals sign\n        // and keep going. Otherwise, we'll require the operator to be passed in.\n        [$value, $operator] = $this->prepareValueAndOperator(\n            $value, $operator, func_num_args() === 2\n        );\n\n        // If the given operator is not found in the list of valid operators we will\n        // assume that the developer is just short-cutting the '=' operators and\n        // we will set the operators to '=' and set the values appropriately.\n        if ($this->invalidOperator($operator)) {\n            [$value, $operator] = [$operator, '='];\n        }\n\n        if ($this->isBitwiseOperator($operator)) {\n            $type = 'Bitwise';\n        }\n\n        $this->havings[] = compact('type', 'column', 'operator', 'value', 'boolean');\n\n        if (! $value instanceof Expression) {\n            $this->addBinding($this->flattenValue($value), 'having');\n        }\n\n        return $this;\n    }\n\n    /**\n     * Add an \"or having\" clause to the query.\n     *\n     * @param  string  $column\n     * @param  string|null  $operator\n     * @param  string|null  $value\n     * @return $this\n     */\n    public function orHaving($column, $operator = null, $value = null)\n    {\n        [$value, $operator] = $this->prepareValueAndOperator(\n            $value, $operator, func_num_args() === 2\n        );\n\n        return $this->having($column, $operator, $value, 'or');\n    }\n\n    /**\n     * Add a \"having between \" clause to the query.\n     *\n     * @param  string  $column\n     * @param  array  $values\n     * @param  string  $boolean\n     * @param  bool  $not\n     * @return $this\n     */\n    public function havingBetween($column, array $values, $boolean = 'and', $not = false)\n    {\n        $type = 'between';\n\n        $this->havings[] = compact('type', 'column', 'values', 'boolean', 'not');\n\n        $this->addBinding(array_slice($this->cleanBindings(Arr::flatten($values)), 0, 2), 'having');\n\n        return $this;\n    }\n\n    /**\n     * Add a raw having clause to the query.\n     *\n     * @param  string  $sql\n     * @param  array  $bindings\n     * @param  string  $boolean\n     * @return $this\n     */\n    public function havingRaw($sql, array $bindings = [], $boolean = 'and')\n    {\n        $type = 'Raw';\n\n        $this->havings[] = compact('type', 'sql', 'boolean');\n\n        $this->addBinding($bindings, 'having');\n\n        return $this;\n    }\n\n    /**\n     * Add a raw or having clause to the query.\n     *\n     * @param  string  $sql\n     * @param  array  $bindings\n     * @return $this\n     */\n    public function orHavingRaw($sql, array $bindings = [])\n    {\n        return $this->havingRaw($sql, $bindings, 'or');\n    }\n\n    /**\n     * Add an \"order by\" clause to the query.\n     *\n     * @param  \\Closure|\\Illuminate\\Database\\Eloquent\\Builder|\\Illuminate\\Database\\Query\\Builder|\\Illuminate\\Database\\Query\\Expression|string  $column\n     * @param  string  $direction\n     * @return $this\n     *\n     * @throws \\InvalidArgumentException\n     */\n    public function orderBy($column, $direction = 'asc')\n    {\n        if ($this->isQueryable($column)) {\n            [$query, $bindings] = $this->createSub($column);\n\n            $column = new Expression('('.$query.')');\n\n            $this->addBinding($bindings, $this->unions ? 'unionOrder' : 'order');\n        }\n\n        $direction = strtolower($direction);\n\n        if (! in_array($direction, ['asc', 'desc'], true)) {\n            throw new InvalidArgumentException('Order direction must be \"asc\" or \"desc\".');\n        }\n\n        $this->{$this->unions ? 'unionOrders' : 'orders'}[] = [\n            'column' => $column,\n            'direction' => $direction,\n        ];\n\n        return $this;\n    }\n\n    /**\n     * Add a descending \"order by\" clause to the query.\n     *\n     * @param  \\Closure|\\Illuminate\\Database\\Eloquent\\Builder|\\Illuminate\\Database\\Query\\Builder|\\Illuminate\\Database\\Query\\Expression|string  $column\n     * @return $this\n     */\n    public function orderByDesc($column)\n    {\n        return $this->orderBy($column, 'desc');\n    }\n\n    /**\n     * Add an \"order by\" clause for a timestamp to the query.\n     *\n     * @param  \\Closure|\\Illuminate\\Database\\Eloquent\\Builder|\\Illuminate\\Database\\Query\\Builder|\\Illuminate\\Database\\Query\\Expression|string  $column\n     * @return $this\n     */\n    public function latest($column = 'created_at')\n    {\n        return $this->orderBy($column, 'desc');\n    }\n\n    /**\n     * Add an \"order by\" clause for a timestamp to the query.\n     *\n     * @param  \\Closure|\\Illuminate\\Database\\Eloquent\\Builder|\\Illuminate\\Database\\Query\\Builder|\\Illuminate\\Database\\Query\\Expression|string  $column\n     * @return $this\n     */\n    public function oldest($column = 'created_at')\n    {\n        return $this->orderBy($column, 'asc');\n    }\n\n    /**\n     * Put the query's results in random order.\n     *\n     * @param  string  $seed\n     * @return $this\n     */\n    public function inRandomOrder($seed = '')\n    {\n        return $this->orderByRaw($this->grammar->compileRandom($seed));\n    }\n\n    /**\n     * Add a raw \"order by\" clause to the query.\n     *\n     * @param  string  $sql\n     * @param  array  $bindings\n     * @return $this\n     */\n    public function orderByRaw($sql, $bindings = [])\n    {\n        $type = 'Raw';\n\n        $this->{$this->unions ? 'unionOrders' : 'orders'}[] = compact('type', 'sql');\n\n        $this->addBinding($bindings, $this->unions ? 'unionOrder' : 'order');\n\n        return $this;\n    }\n\n    /**\n     * Alias to set the \"offset\" value of the query.\n     *\n     * @param  int  $value\n     * @return $this\n     */\n    public function skip($value)\n    {\n        return $this->offset($value);\n    }\n\n    /**\n     * Set the \"offset\" value of the query.\n     *\n     * @param  int  $value\n     * @return $this\n     */\n    public function offset($value)\n    {\n        $property = $this->unions ? 'unionOffset' : 'offset';\n\n        $this->$property = max(0, (int) $value);\n\n        return $this;\n    }\n\n    /**\n     * Alias to set the \"limit\" value of the query.\n     *\n     * @param  int  $value\n     * @return $this\n     */\n    public function take($value)\n    {\n        return $this->limit($value);\n    }\n\n    /**\n     * Set the \"limit\" value of the query.\n     *\n     * @param  int  $value\n     * @return $this\n     */\n    public function limit($value)\n    {\n        $property = $this->unions ? 'unionLimit' : 'limit';\n\n        if ($value >= 0) {\n            $this->$property = ! is_null($value) ? (int) $value : null;\n        }\n\n        return $this;\n    }\n\n    /**\n     * Set the limit and offset for a given page.\n     *\n     * @param  int  $page\n     * @param  int  $perPage\n     * @return $this\n     */\n    public function forPage($page, $perPage = 15)\n    {\n        return $this->offset(($page - 1) * $perPage)->limit($perPage);\n    }\n\n    /**\n     * Constrain the query to the previous \"page\" of results before a given ID.\n     *\n     * @param  int  $perPage\n     * @param  int|null  $lastId\n     * @param  string  $column\n     * @return $this\n     */\n    public function forPageBeforeId($perPage = 15, $lastId = 0, $column = 'id')\n    {\n        $this->orders = $this->removeExistingOrdersFor($column);\n\n        if (! is_null($lastId)) {\n            $this->where($column, '<', $lastId);\n        }\n\n        return $this->orderBy($column, 'desc')\n                    ->limit($perPage);\n    }\n\n    /**\n     * Constrain the query to the next \"page\" of results after a given ID.\n     *\n     * @param  int  $perPage\n     * @param  int|null  $lastId\n     * @param  string  $column\n     * @return $this\n     */\n    public function forPageAfterId($perPage = 15, $lastId = 0, $column = 'id')\n    {\n        $this->orders = $this->removeExistingOrdersFor($column);\n\n        if (! is_null($lastId)) {\n            $this->where($column, '>', $lastId);\n        }\n\n        return $this->orderBy($column, 'asc')\n                    ->limit($perPage);\n    }\n\n    /**\n     * Remove all existing orders and optionally add a new order.\n     *\n     * @param  \\Closure|\\Illuminate\\Database\\Query\\Builder|\\Illuminate\\Database\\Query\\Expression|string|null  $column\n     * @param  string  $direction\n     * @return $this\n     */\n    public function reorder($column = null, $direction = 'asc')\n    {\n        $this->orders = null;\n        $this->unionOrders = null;\n        $this->bindings['order'] = [];\n        $this->bindings['unionOrder'] = [];\n\n        if ($column) {\n            return $this->orderBy($column, $direction);\n        }\n\n        return $this;\n    }\n\n    /**\n     * Get an array with all orders with a given column removed.\n     *\n     * @param  string  $column\n     * @return array\n     */\n    protected function removeExistingOrdersFor($column)\n    {\n        return Collection::make($this->orders)\n                    ->reject(function ($order) use ($column) {\n                        return isset($order['column'])\n                               ? $order['column'] === $column : false;\n                    })->values()->all();\n    }\n\n    /**\n     * Add a union statement to the query.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder|\\Closure  $query\n     * @param  bool  $all\n     * @return $this\n     */\n    public function union($query, $all = false)\n    {\n        if ($query instanceof Closure) {\n            call_user_func($query, $query = $this->newQuery());\n        }\n\n        $this->unions[] = compact('query', 'all');\n\n        $this->addBinding($query->getBindings(), 'union');\n\n        return $this;\n    }\n\n    /**\n     * Add a union all statement to the query.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder|\\Closure  $query\n     * @return $this\n     */\n    public function unionAll($query)\n    {\n        return $this->union($query, true);\n    }\n\n    /**\n     * Lock the selected rows in the table.\n     *\n     * @param  string|bool  $value\n     * @return $this\n     */\n    public function lock($value = true)\n    {\n        $this->lock = $value;\n\n        if (! is_null($this->lock)) {\n            $this->useWritePdo();\n        }\n\n        return $this;\n    }\n\n    /**\n     * Lock the selected rows in the table for updating.\n     *\n     * @return \\Illuminate\\Database\\Query\\Builder\n     */\n    public function lockForUpdate()\n    {\n        return $this->lock(true);\n    }\n\n    /**\n     * Share lock the selected rows in the table.\n     *\n     * @return \\Illuminate\\Database\\Query\\Builder\n     */\n    public function sharedLock()\n    {\n        return $this->lock(false);\n    }\n\n    /**\n     * Register a closure to be invoked before the query is executed.\n     *\n     * @param  callable  $callback\n     * @return $this\n     */\n    public function beforeQuery(callable $callback)\n    {\n        $this->beforeQueryCallbacks[] = $callback;\n\n        return $this;\n    }\n\n    /**\n     * Invoke the \"before query\" modification callbacks.\n     *\n     * @return void\n     */\n    public function applyBeforeQueryCallbacks()\n    {\n        foreach ($this->beforeQueryCallbacks as $callback) {\n            $callback($this);\n        }\n\n        $this->beforeQueryCallbacks = [];\n    }\n\n    /**\n     * Get the SQL representation of the query.\n     *\n     * @return string\n     */\n    public function toSql()\n    {\n        $this->applyBeforeQueryCallbacks();\n\n        return $this->grammar->compileSelect($this);\n    }\n\n    /**\n     * Execute a query for a single record by ID.\n     *\n     * @param  int|string  $id\n     * @param  array  $columns\n     * @return mixed|static\n     */\n    public function find($id, $columns = ['*'])\n    {\n        return $this->where('id', '=', $id)->first($columns);\n    }\n\n    /**\n     * Get a single column's value from the first result of a query.\n     *\n     * @param  string  $column\n     * @return mixed\n     */\n    public function value($column)\n    {\n        $result = (array) $this->first([$column]);\n\n        return count($result) > 0 ? reset($result) : null;\n    }\n\n    /**\n     * Execute the query as a \"select\" statement.\n     *\n     * @param  array|string  $columns\n     * @return \\Illuminate\\Support\\Collection\n     */\n    public function get($columns = ['*'])\n    {\n        return collect($this->onceWithColumns(Arr::wrap($columns), function () {\n            return $this->processor->processSelect($this, $this->runSelect());\n        }));\n    }\n\n    /**\n     * Run the query as a \"select\" statement against the connection.\n     *\n     * @return array\n     */\n    protected function runSelect()\n    {\n        return $this->connection->select(\n            $this->toSql(), $this->getBindings(), ! $this->useWritePdo\n        );\n    }\n\n    /**\n     * Paginate the given query into a simple paginator.\n     *\n     * @param  int  $perPage\n     * @param  array  $columns\n     * @param  string  $pageName\n     * @param  int|null  $page\n     * @return \\Illuminate\\Contracts\\Pagination\\LengthAwarePaginator\n     */\n    public function paginate($perPage = 15, $columns = ['*'], $pageName = 'page', $page = null)\n    {\n        $page = $page ?: Paginator::resolveCurrentPage($pageName);\n\n        $total = $this->getCountForPagination();\n\n        $results = $total ? $this->forPage($page, $perPage)->get($columns) : collect();\n\n        return $this->paginator($results, $total, $perPage, $page, [\n            'path' => Paginator::resolveCurrentPath(),\n            'pageName' => $pageName,\n        ]);\n    }\n\n    /**\n     * Get a paginator only supporting simple next and previous links.\n     *\n     * This is more efficient on larger data-sets, etc.\n     *\n     * @param  int  $perPage\n     * @param  array  $columns\n     * @param  string  $pageName\n     * @param  int|null  $page\n     * @return \\Illuminate\\Contracts\\Pagination\\Paginator\n     */\n    public function simplePaginate($perPage = 15, $columns = ['*'], $pageName = 'page', $page = null)\n    {\n        $page = $page ?: Paginator::resolveCurrentPage($pageName);\n\n        $this->offset(($page - 1) * $perPage)->limit($perPage + 1);\n\n        return $this->simplePaginator($this->get($columns), $perPage, $page, [\n            'path' => Paginator::resolveCurrentPath(),\n            'pageName' => $pageName,\n        ]);\n    }\n\n    /**\n     * Get a paginator only supporting simple next and previous links.\n     *\n     * This is more efficient on larger data-sets, etc.\n     *\n     * @param  int|null  $perPage\n     * @param  array  $columns\n     * @param  string  $cursorName\n     * @param  \\Illuminate\\Pagination\\Cursor|string|null  $cursor\n     * @return \\Illuminate\\Contracts\\Pagination\\CursorPaginator\n     */\n    public function cursorPaginate($perPage = 15, $columns = ['*'], $cursorName = 'cursor', $cursor = null)\n    {\n        return $this->paginateUsingCursor($perPage, $columns, $cursorName, $cursor);\n    }\n\n    /**\n     * Ensure the proper order by required for cursor pagination.\n     *\n     * @param  bool  $shouldReverse\n     * @return \\Illuminate\\Support\\Collection\n     */\n    protected function ensureOrderForCursorPagination($shouldReverse = false)\n    {\n        $this->enforceOrderBy();\n\n        return collect($this->orders ?? $this->unionOrders ?? [])->filter(function ($order) {\n            return Arr::has($order, 'direction');\n        })->when($shouldReverse, function (Collection $orders) {\n            return $orders->map(function ($order) {\n                $order['direction'] = $order['direction'] === 'asc' ? 'desc' : 'asc';\n\n                return $order;\n            });\n        })->values();\n    }\n\n    /**\n     * Get the count of the total records for the paginator.\n     *\n     * @param  array  $columns\n     * @return int\n     */\n    public function getCountForPagination($columns = ['*'])\n    {\n        $results = $this->runPaginationCountQuery($columns);\n\n        // Once we have run the pagination count query, we will get the resulting count and\n        // take into account what type of query it was. When there is a group by we will\n        // just return the count of the entire results set since that will be correct.\n        if (! isset($results[0])) {\n            return 0;\n        } elseif (is_object($results[0])) {\n            return (int) $results[0]->aggregate;\n        }\n\n        return (int) array_change_key_case((array) $results[0])['aggregate'];\n    }\n\n    /**\n     * Run a pagination count query.\n     *\n     * @param  array  $columns\n     * @return array\n     */\n    protected function runPaginationCountQuery($columns = ['*'])\n    {\n        if ($this->groups || $this->havings) {\n            $clone = $this->cloneForPaginationCount();\n\n            if (is_null($clone->columns) && ! empty($this->joins)) {\n                $clone->select($this->from.'.*');\n            }\n\n            return $this->newQuery()\n                ->from(new Expression('('.$clone->toSql().') as '.$this->grammar->wrap('aggregate_table')))\n                ->mergeBindings($clone)\n                ->setAggregate('count', $this->withoutSelectAliases($columns))\n                ->get()->all();\n        }\n\n        $without = $this->unions ? ['orders', 'limit', 'offset'] : ['columns', 'orders', 'limit', 'offset'];\n\n        return $this->cloneWithout($without)\n                    ->cloneWithoutBindings($this->unions ? ['order'] : ['select', 'order'])\n                    ->setAggregate('count', $this->withoutSelectAliases($columns))\n                    ->get()->all();\n    }\n\n    /**\n     * Clone the existing query instance for usage in a pagination subquery.\n     *\n     * @return self\n     */\n    protected function cloneForPaginationCount()\n    {\n        return $this->cloneWithout(['orders', 'limit', 'offset'])\n                    ->cloneWithoutBindings(['order']);\n    }\n\n    /**\n     * Remove the column aliases since they will break count queries.\n     *\n     * @param  array  $columns\n     * @return array\n     */\n    protected function withoutSelectAliases(array $columns)\n    {\n        return array_map(function ($column) {\n            return is_string($column) && ($aliasPosition = stripos($column, ' as ')) !== false\n                    ? substr($column, 0, $aliasPosition) : $column;\n        }, $columns);\n    }\n\n    /**\n     * Get a lazy collection for the given query.\n     *\n     * @return \\Illuminate\\Support\\LazyCollection\n     */\n    public function cursor()\n    {\n        if (is_null($this->columns)) {\n            $this->columns = ['*'];\n        }\n\n        return new LazyCollection(function () {\n            yield from $this->connection->cursor(\n                $this->toSql(), $this->getBindings(), ! $this->useWritePdo\n            );\n        });\n    }\n\n    /**\n     * Throw an exception if the query doesn't have an orderBy clause.\n     *\n     * @return void\n     *\n     * @throws \\RuntimeException\n     */\n    protected function enforceOrderBy()\n    {\n        if (empty($this->orders) && empty($this->unionOrders)) {\n            throw new RuntimeException('You must specify an orderBy clause when using this function.');\n        }\n    }\n\n    /**\n     * Get a collection instance containing the values of a given column.\n     *\n     * @param  string  $column\n     * @param  string|null  $key\n     * @return \\Illuminate\\Support\\Collection\n     */\n    public function pluck($column, $key = null)\n    {\n        // First, we will need to select the results of the query accounting for the\n        // given columns / key. Once we have the results, we will be able to take\n        // the results and get the exact data that was requested for the query.\n        $queryResult = $this->onceWithColumns(\n            is_null($key) ? [$column] : [$column, $key],\n            function () {\n                return $this->processor->processSelect(\n                    $this, $this->runSelect()\n                );\n            }\n        );\n\n        if (empty($queryResult)) {\n            return collect();\n        }\n\n        // If the columns are qualified with a table or have an alias, we cannot use\n        // those directly in the \"pluck\" operations since the results from the DB\n        // are only keyed by the column itself. We'll strip the table out here.\n        $column = $this->stripTableForPluck($column);\n\n        $key = $this->stripTableForPluck($key);\n\n        return is_array($queryResult[0])\n                    ? $this->pluckFromArrayColumn($queryResult, $column, $key)\n                    : $this->pluckFromObjectColumn($queryResult, $column, $key);\n    }\n\n    /**\n     * Strip off the table name or alias from a column identifier.\n     *\n     * @param  string  $column\n     * @return string|null\n     */\n    protected function stripTableForPluck($column)\n    {\n        if (is_null($column)) {\n            return $column;\n        }\n\n        $separator = strpos(strtolower($column), ' as ') !== false ? ' as ' : '\\.';\n\n        return last(preg_split('~'.$separator.'~i', $column));\n    }\n\n    /**\n     * Retrieve column values from rows represented as objects.\n     *\n     * @param  array  $queryResult\n     * @param  string  $column\n     * @param  string  $key\n     * @return \\Illuminate\\Support\\Collection\n     */\n    protected function pluckFromObjectColumn($queryResult, $column, $key)\n    {\n        $results = [];\n\n        if (is_null($key)) {\n            foreach ($queryResult as $row) {\n                $results[] = $row->$column;\n            }\n        } else {\n            foreach ($queryResult as $row) {\n                $results[$row->$key] = $row->$column;\n            }\n        }\n\n        return collect($results);\n    }\n\n    /**\n     * Retrieve column values from rows represented as arrays.\n     *\n     * @param  array  $queryResult\n     * @param  string  $column\n     * @param  string  $key\n     * @return \\Illuminate\\Support\\Collection\n     */\n    protected function pluckFromArrayColumn($queryResult, $column, $key)\n    {\n        $results = [];\n\n        if (is_null($key)) {\n            foreach ($queryResult as $row) {\n                $results[] = $row[$column];\n            }\n        } else {\n            foreach ($queryResult as $row) {\n                $results[$row[$key]] = $row[$column];\n            }\n        }\n\n        return collect($results);\n    }\n\n    /**\n     * Concatenate values of a given column as a string.\n     *\n     * @param  string  $column\n     * @param  string  $glue\n     * @return string\n     */\n    public function implode($column, $glue = '')\n    {\n        return $this->pluck($column)->implode($glue);\n    }\n\n    /**\n     * Determine if any rows exist for the current query.\n     *\n     * @return bool\n     */\n    public function exists()\n    {\n        $this->applyBeforeQueryCallbacks();\n\n        $results = $this->connection->select(\n            $this->grammar->compileExists($this), $this->getBindings(), ! $this->useWritePdo\n        );\n\n        // If the results has rows, we will get the row and see if the exists column is a\n        // boolean true. If there is no results for this query we will return false as\n        // there are no rows for this query at all and we can return that info here.\n        if (isset($results[0])) {\n            $results = (array) $results[0];\n\n            return (bool) $results['exists'];\n        }\n\n        return false;\n    }\n\n    /**\n     * Determine if no rows exist for the current query.\n     *\n     * @return bool\n     */\n    public function doesntExist()\n    {\n        return ! $this->exists();\n    }\n\n    /**\n     * Execute the given callback if no rows exist for the current query.\n     *\n     * @param  \\Closure  $callback\n     * @return mixed\n     */\n    public function existsOr(Closure $callback)\n    {\n        return $this->exists() ? true : $callback();\n    }\n\n    /**\n     * Execute the given callback if rows exist for the current query.\n     *\n     * @param  \\Closure  $callback\n     * @return mixed\n     */\n    public function doesntExistOr(Closure $callback)\n    {\n        return $this->doesntExist() ? true : $callback();\n    }\n\n    /**\n     * Retrieve the \"count\" result of the query.\n     *\n     * @param  string  $columns\n     * @return int\n     */\n    public function count($columns = '*')\n    {\n        return (int) $this->aggregate(__FUNCTION__, Arr::wrap($columns));\n    }\n\n    /**\n     * Retrieve the minimum value of a given column.\n     *\n     * @param  string  $column\n     * @return mixed\n     */\n    public function min($column)\n    {\n        return $this->aggregate(__FUNCTION__, [$column]);\n    }\n\n    /**\n     * Retrieve the maximum value of a given column.\n     *\n     * @param  string  $column\n     * @return mixed\n     */\n    public function max($column)\n    {\n        return $this->aggregate(__FUNCTION__, [$column]);\n    }\n\n    /**\n     * Retrieve the sum of the values of a given column.\n     *\n     * @param  string  $column\n     * @return mixed\n     */\n    public function sum($column)\n    {\n        $result = $this->aggregate(__FUNCTION__, [$column]);\n\n        return $result ?: 0;\n    }\n\n    /**\n     * Retrieve the average of the values of a given column.\n     *\n     * @param  string  $column\n     * @return mixed\n     */\n    public function avg($column)\n    {\n        return $this->aggregate(__FUNCTION__, [$column]);\n    }\n\n    /**\n     * Alias for the \"avg\" method.\n     *\n     * @param  string  $column\n     * @return mixed\n     */\n    public function average($column)\n    {\n        return $this->avg($column);\n    }\n\n    /**\n     * Execute an aggregate function on the database.\n     *\n     * @param  string  $function\n     * @param  array  $columns\n     * @return mixed\n     */\n    public function aggregate($function, $columns = ['*'])\n    {\n        $results = $this->cloneWithout($this->unions || $this->havings ? [] : ['columns'])\n                        ->cloneWithoutBindings($this->unions || $this->havings ? [] : ['select'])\n                        ->setAggregate($function, $columns)\n                        ->get($columns);\n\n        if (! $results->isEmpty()) {\n            return array_change_key_case((array) $results[0])['aggregate'];\n        }\n    }\n\n    /**\n     * Execute a numeric aggregate function on the database.\n     *\n     * @param  string  $function\n     * @param  array  $columns\n     * @return float|int\n     */\n    public function numericAggregate($function, $columns = ['*'])\n    {\n        $result = $this->aggregate($function, $columns);\n\n        // If there is no result, we can obviously just return 0 here. Next, we will check\n        // if the result is an integer or float. If it is already one of these two data\n        // types we can just return the result as-is, otherwise we will convert this.\n        if (! $result) {\n            return 0;\n        }\n\n        if (is_int($result) || is_float($result)) {\n            return $result;\n        }\n\n        // If the result doesn't contain a decimal place, we will assume it is an int then\n        // cast it to one. When it does we will cast it to a float since it needs to be\n        // cast to the expected data type for the developers out of pure convenience.\n        return strpos((string) $result, '.') === false\n                ? (int) $result : (float) $result;\n    }\n\n    /**\n     * Set the aggregate property without running the query.\n     *\n     * @param  string  $function\n     * @param  array  $columns\n     * @return $this\n     */\n    protected function setAggregate($function, $columns)\n    {\n        $this->aggregate = compact('function', 'columns');\n\n        if (empty($this->groups)) {\n            $this->orders = null;\n\n            $this->bindings['order'] = [];\n        }\n\n        return $this;\n    }\n\n    /**\n     * Execute the given callback while selecting the given columns.\n     *\n     * After running the callback, the columns are reset to the original value.\n     *\n     * @param  array  $columns\n     * @param  callable  $callback\n     * @return mixed\n     */\n    protected function onceWithColumns($columns, $callback)\n    {\n        $original = $this->columns;\n\n        if (is_null($original)) {\n            $this->columns = $columns;\n        }\n\n        $result = $callback();\n\n        $this->columns = $original;\n\n        return $result;\n    }\n\n    /**\n     * Insert new records into the database.\n     *\n     * @param  array  $values\n     * @return bool\n     */\n    public function insert(array $values)\n    {\n        // Since every insert gets treated like a batch insert, we will make sure the\n        // bindings are structured in a way that is convenient when building these\n        // inserts statements by verifying these elements are actually an array.\n        if (empty($values)) {\n            return true;\n        }\n\n        if (! is_array(reset($values))) {\n            $values = [$values];\n        }\n\n        // Here, we will sort the insert keys for every record so that each insert is\n        // in the same order for the record. We need to make sure this is the case\n        // so there are not any errors or problems when inserting these records.\n        else {\n            foreach ($values as $key => $value) {\n                ksort($value);\n\n                $values[$key] = $value;\n            }\n        }\n\n        $this->applyBeforeQueryCallbacks();\n\n        // Finally, we will run this query against the database connection and return\n        // the results. We will need to also flatten these bindings before running\n        // the query so they are all in one huge, flattened array for execution.\n        return $this->connection->insert(\n            $this->grammar->compileInsert($this, $values),\n            $this->cleanBindings(Arr::flatten($values, 1))\n        );\n    }\n\n    /**\n     * Insert new records into the database while ignoring errors.\n     *\n     * @param  array  $values\n     * @return int\n     */\n    public function insertOrIgnore(array $values)\n    {\n        if (empty($values)) {\n            return 0;\n        }\n\n        if (! is_array(reset($values))) {\n            $values = [$values];\n        } else {\n            foreach ($values as $key => $value) {\n                ksort($value);\n                $values[$key] = $value;\n            }\n        }\n\n        $this->applyBeforeQueryCallbacks();\n\n        return $this->connection->affectingStatement(\n            $this->grammar->compileInsertOrIgnore($this, $values),\n            $this->cleanBindings(Arr::flatten($values, 1))\n        );\n    }\n\n    /**\n     * Insert a new record and get the value of the primary key.\n     *\n     * @param  array  $values\n     * @param  string|null  $sequence\n     * @return int\n     */\n    public function insertGetId(array $values, $sequence = null)\n    {\n        $this->applyBeforeQueryCallbacks();\n\n        $sql = $this->grammar->compileInsertGetId($this, $values, $sequence);\n\n        $values = $this->cleanBindings($values);\n\n        return $this->processor->processInsertGetId($this, $sql, $values, $sequence);\n    }\n\n    /**\n     * Insert new records into the table using a subquery.\n     *\n     * @param  array  $columns\n     * @param  \\Closure|\\Illuminate\\Database\\Query\\Builder|string  $query\n     * @return int\n     */\n    public function insertUsing(array $columns, $query)\n    {\n        $this->applyBeforeQueryCallbacks();\n\n        [$sql, $bindings] = $this->createSub($query);\n\n        return $this->connection->affectingStatement(\n            $this->grammar->compileInsertUsing($this, $columns, $sql),\n            $this->cleanBindings($bindings)\n        );\n    }\n\n    /**\n     * Update records in the database.\n     *\n     * @param  array  $values\n     * @return int\n     */\n    public function update(array $values)\n    {\n        $this->applyBeforeQueryCallbacks();\n\n        $sql = $this->grammar->compileUpdate($this, $values);\n\n        return $this->connection->update($sql, $this->cleanBindings(\n            $this->grammar->prepareBindingsForUpdate($this->bindings, $values)\n        ));\n    }\n\n    /**\n     * Update records in a PostgreSQL database using the update from syntax.\n     *\n     * @param  array  $values\n     * @return int\n     */\n    public function updateFrom(array $values)\n    {\n        if (! method_exists($this->grammar, 'compileUpdateFrom')) {\n            throw new LogicException('This database engine does not support the updateFrom method.');\n        }\n\n        $this->applyBeforeQueryCallbacks();\n\n        $sql = $this->grammar->compileUpdateFrom($this, $values);\n\n        return $this->connection->update($sql, $this->cleanBindings(\n            $this->grammar->prepareBindingsForUpdateFrom($this->bindings, $values)\n        ));\n    }\n\n    /**\n     * Insert or update a record matching the attributes, and fill it with values.\n     *\n     * @param  array  $attributes\n     * @param  array  $values\n     * @return bool\n     */\n    public function updateOrInsert(array $attributes, array $values = [])\n    {\n        if (! $this->where($attributes)->exists()) {\n            return $this->insert(array_merge($attributes, $values));\n        }\n\n        if (empty($values)) {\n            return true;\n        }\n\n        return (bool) $this->limit(1)->update($values);\n    }\n\n    /**\n     * Insert new records or update the existing ones.\n     *\n     * @param  array  $values\n     * @param  array|string  $uniqueBy\n     * @param  array|null  $update\n     * @return int\n     */\n    public function upsert(array $values, $uniqueBy, $update = null)\n    {\n        if (empty($values)) {\n            return 0;\n        } elseif ($update === []) {\n            return (int) $this->insert($values);\n        }\n\n        if (! is_array(reset($values))) {\n            $values = [$values];\n        } else {\n            foreach ($values as $key => $value) {\n                ksort($value);\n\n                $values[$key] = $value;\n            }\n        }\n\n        if (is_null($update)) {\n            $update = array_keys(reset($values));\n        }\n\n        $this->applyBeforeQueryCallbacks();\n\n        $bindings = $this->cleanBindings(array_merge(\n            Arr::flatten($values, 1),\n            collect($update)->reject(function ($value, $key) {\n                return is_int($key);\n            })->all()\n        ));\n\n        return $this->connection->affectingStatement(\n            $this->grammar->compileUpsert($this, $values, (array) $uniqueBy, $update),\n            $bindings\n        );\n    }\n\n    /**\n     * Increment a column's value by a given amount.\n     *\n     * @param  string  $column\n     * @param  float|int  $amount\n     * @param  array  $extra\n     * @return int\n     *\n     * @throws \\InvalidArgumentException\n     */\n    public function increment($column, $amount = 1, array $extra = [])\n    {\n        if (! is_numeric($amount)) {\n            throw new InvalidArgumentException('Non-numeric value passed to increment method.');\n        }\n\n        $wrapped = $this->grammar->wrap($column);\n\n        $columns = array_merge([$column => $this->raw(\"$wrapped + $amount\")], $extra);\n\n        return $this->update($columns);\n    }\n\n    /**\n     * Decrement a column's value by a given amount.\n     *\n     * @param  string  $column\n     * @param  float|int  $amount\n     * @param  array  $extra\n     * @return int\n     *\n     * @throws \\InvalidArgumentException\n     */\n    public function decrement($column, $amount = 1, array $extra = [])\n    {\n        if (! is_numeric($amount)) {\n            throw new InvalidArgumentException('Non-numeric value passed to decrement method.');\n        }\n\n        $wrapped = $this->grammar->wrap($column);\n\n        $columns = array_merge([$column => $this->raw(\"$wrapped - $amount\")], $extra);\n\n        return $this->update($columns);\n    }\n\n    /**\n     * Delete records from the database.\n     *\n     * @param  mixed  $id\n     * @return int\n     */\n    public function delete($id = null)\n    {\n        // If an ID is passed to the method, we will set the where clause to check the\n        // ID to let developers to simply and quickly remove a single row from this\n        // database without manually specifying the \"where\" clauses on the query.\n        if (! is_null($id)) {\n            $this->where($this->from.'.id', '=', $id);\n        }\n\n        $this->applyBeforeQueryCallbacks();\n\n        return $this->connection->delete(\n            $this->grammar->compileDelete($this), $this->cleanBindings(\n                $this->grammar->prepareBindingsForDelete($this->bindings)\n            )\n        );\n    }\n\n    /**\n     * Run a truncate statement on the table.\n     *\n     * @return void\n     */\n    public function truncate()\n    {\n        $this->applyBeforeQueryCallbacks();\n\n        foreach ($this->grammar->compileTruncate($this) as $sql => $bindings) {\n            $this->connection->statement($sql, $bindings);\n        }\n    }\n\n    /**\n     * Get a new instance of the query builder.\n     *\n     * @return \\Illuminate\\Database\\Query\\Builder\n     */\n    public function newQuery()\n    {\n        return new static($this->connection, $this->grammar, $this->processor);\n    }\n\n    /**\n     * Create a new query instance for a sub-query.\n     *\n     * @return \\Illuminate\\Database\\Query\\Builder\n     */\n    protected function forSubQuery()\n    {\n        return $this->newQuery();\n    }\n\n    /**\n     * Create a raw database expression.\n     *\n     * @param  mixed  $value\n     * @return \\Illuminate\\Database\\Query\\Expression\n     */\n    public function raw($value)\n    {\n        return $this->connection->raw($value);\n    }\n\n    /**\n     * Get the current query value bindings in a flattened array.\n     *\n     * @return array\n     */\n    public function getBindings()\n    {\n        return Arr::flatten($this->bindings);\n    }\n\n    /**\n     * Get the raw array of bindings.\n     *\n     * @return array\n     */\n    public function getRawBindings()\n    {\n        return $this->bindings;\n    }\n\n    /**\n     * Set the bindings on the query builder.\n     *\n     * @param  array  $bindings\n     * @param  string  $type\n     * @return $this\n     *\n     * @throws \\InvalidArgumentException\n     */\n    public function setBindings(array $bindings, $type = 'where')\n    {\n        if (! array_key_exists($type, $this->bindings)) {\n            throw new InvalidArgumentException(\"Invalid binding type: {$type}.\");\n        }\n\n        $this->bindings[$type] = $bindings;\n\n        return $this;\n    }\n\n    /**\n     * Add a binding to the query.\n     *\n     * @param  mixed  $value\n     * @param  string  $type\n     * @return $this\n     *\n     * @throws \\InvalidArgumentException\n     */\n    public function addBinding($value, $type = 'where')\n    {\n        if (! array_key_exists($type, $this->bindings)) {\n            throw new InvalidArgumentException(\"Invalid binding type: {$type}.\");\n        }\n\n        if (is_array($value)) {\n            $this->bindings[$type] = array_values(array_map(\n                [$this, 'castBinding'],\n                array_merge($this->bindings[$type], $value),\n            ));\n        } else {\n            $this->bindings[$type][] = $this->castBinding($value);\n        }\n\n        return $this;\n    }\n\n    /**\n     * Cast the given binding value.\n     *\n     * @param  mixed  $value\n     * @return mixed\n     */\n    public function castBinding($value)\n    {\n        if (function_exists('enum_exists') && $value instanceof BackedEnum) {\n            return $value->value;\n        }\n\n        return $value;\n    }\n\n    /**\n     * Merge an array of bindings into our bindings.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @return $this\n     */\n    public function mergeBindings(self $query)\n    {\n        $this->bindings = array_merge_recursive($this->bindings, $query->bindings);\n\n        return $this;\n    }\n\n    /**\n     * Remove all of the expressions from a list of bindings.\n     *\n     * @param  array  $bindings\n     * @return array\n     */\n    public function cleanBindings(array $bindings)\n    {\n        return collect($bindings)\n                    ->reject(function ($binding) {\n                        return $binding instanceof Expression;\n                    })\n                    ->map([$this, 'castBinding'])\n                    ->values()\n                    ->all();\n    }\n\n    /**\n     * Get a scalar type value from an unknown type of input.\n     *\n     * @param  mixed  $value\n     * @return mixed\n     */\n    protected function flattenValue($value)\n    {\n        return is_array($value) ? head(Arr::flatten($value)) : $value;\n    }\n\n    /**\n     * Get the default key name of the table.\n     *\n     * @return string\n     */\n    protected function defaultKeyName()\n    {\n        return 'id';\n    }\n\n    /**\n     * Get the database connection instance.\n     *\n     * @return \\Illuminate\\Database\\ConnectionInterface\n     */\n    public function getConnection()\n    {\n        return $this->connection;\n    }\n\n    /**\n     * Get the database query processor instance.\n     *\n     * @return \\Illuminate\\Database\\Query\\Processors\\Processor\n     */\n    public function getProcessor()\n    {\n        return $this->processor;\n    }\n\n    /**\n     * Get the query grammar instance.\n     *\n     * @return \\Illuminate\\Database\\Query\\Grammars\\Grammar\n     */\n    public function getGrammar()\n    {\n        return $this->grammar;\n    }\n\n    /**\n     * Use the write pdo for query.\n     *\n     * @return $this\n     */\n    public function useWritePdo()\n    {\n        $this->useWritePdo = true;\n\n        return $this;\n    }\n\n    /**\n     * Determine if the value is a query builder instance or a Closure.\n     *\n     * @param  mixed  $value\n     * @return bool\n     */\n    protected function isQueryable($value)\n    {\n        return $value instanceof self ||\n               $value instanceof EloquentBuilder ||\n               $value instanceof Relation ||\n               $value instanceof Closure;\n    }\n\n    /**\n     * Clone the query.\n     *\n     * @return static\n     */\n    public function clone()\n    {\n        return clone $this;\n    }\n\n    /**\n     * Clone the query without the given properties.\n     *\n     * @param  array  $properties\n     * @return static\n     */\n    public function cloneWithout(array $properties)\n    {\n        return tap($this->clone(), function ($clone) use ($properties) {\n            foreach ($properties as $property) {\n                $clone->{$property} = null;\n            }\n        });\n    }\n\n    /**\n     * Clone the query without the given bindings.\n     *\n     * @param  array  $except\n     * @return static\n     */\n    public function cloneWithoutBindings(array $except)\n    {\n        return tap($this->clone(), function ($clone) use ($except) {\n            foreach ($except as $type) {\n                $clone->bindings[$type] = [];\n            }\n        });\n    }\n\n    /**\n     * Dump the current SQL and bindings.\n     *\n     * @return $this\n     */\n    public function dump()\n    {\n        dump($this->toSql(), $this->getBindings());\n\n        return $this;\n    }\n\n    /**\n     * Die and dump the current SQL and bindings.\n     *\n     * @return never\n     */\n    public function dd()\n    {\n        dd($this->toSql(), $this->getBindings());\n    }\n\n    /**\n     * Handle dynamic method calls into the method.\n     *\n     * @param  string  $method\n     * @param  array  $parameters\n     * @return mixed\n     *\n     * @throws \\BadMethodCallException\n     */\n    public function __call($method, $parameters)\n    {\n        if (static::hasMacro($method)) {\n            return $this->macroCall($method, $parameters);\n        }\n\n        if (Str::startsWith($method, 'where')) {\n            return $this->dynamicWhere($method, $parameters);\n        }\n\n        static::throwBadMethodCallException($method);\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Query/Expression.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Query;\n\nclass Expression\n{\n    /**\n     * The value of the expression.\n     *\n     * @var mixed\n     */\n    protected $value;\n\n    /**\n     * Create a new raw query expression.\n     *\n     * @param  mixed  $value\n     * @return void\n     */\n    public function __construct($value)\n    {\n        $this->value = $value;\n    }\n\n    /**\n     * Get the value of the expression.\n     *\n     * @return mixed\n     */\n    public function getValue()\n    {\n        return $this->value;\n    }\n\n    /**\n     * Get the value of the expression.\n     *\n     * @return string\n     */\n    public function __toString()\n    {\n        return (string) $this->getValue();\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Query/Grammars/Grammar.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Query\\Grammars;\n\nuse Illuminate\\Database\\Grammar as BaseGrammar;\nuse Illuminate\\Database\\Query\\Builder;\nuse Illuminate\\Database\\Query\\JoinClause;\nuse Illuminate\\Support\\Arr;\nuse Illuminate\\Support\\Str;\nuse RuntimeException;\n\nclass Grammar extends BaseGrammar\n{\n    /**\n     * The grammar specific operators.\n     *\n     * @var array\n     */\n    protected $operators = [];\n\n    /**\n     * The grammar specific bitwise operators.\n     *\n     * @var array\n     */\n    protected $bitwiseOperators = [];\n\n    /**\n     * The components that make up a select clause.\n     *\n     * @var string[]\n     */\n    protected $selectComponents = [\n        'aggregate',\n        'columns',\n        'from',\n        'joins',\n        'wheres',\n        'groups',\n        'havings',\n        'orders',\n        'limit',\n        'offset',\n        'lock',\n    ];\n\n    /**\n     * Compile a select query into SQL.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @return string\n     */\n    public function compileSelect(Builder $query)\n    {\n        if (($query->unions || $query->havings) && $query->aggregate) {\n            return $this->compileUnionAggregate($query);\n        }\n\n        // If the query does not have any columns set, we'll set the columns to the\n        // * character to just get all of the columns from the database. Then we\n        // can build the query and concatenate all the pieces together as one.\n        $original = $query->columns;\n\n        if (is_null($query->columns)) {\n            $query->columns = ['*'];\n        }\n\n        // To compile the query, we'll spin through each component of the query and\n        // see if that component exists. If it does we'll just call the compiler\n        // function for the component which is responsible for making the SQL.\n        $sql = trim($this->concatenate(\n            $this->compileComponents($query))\n        );\n\n        if ($query->unions) {\n            $sql = $this->wrapUnion($sql).' '.$this->compileUnions($query);\n        }\n\n        $query->columns = $original;\n\n        return $sql;\n    }\n\n    /**\n     * Compile the components necessary for a select clause.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @return array\n     */\n    protected function compileComponents(Builder $query)\n    {\n        $sql = [];\n\n        foreach ($this->selectComponents as $component) {\n            if (isset($query->$component)) {\n                $method = 'compile'.ucfirst($component);\n\n                $sql[$component] = $this->$method($query, $query->$component);\n            }\n        }\n\n        return $sql;\n    }\n\n    /**\n     * Compile an aggregated select clause.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $aggregate\n     * @return string\n     */\n    protected function compileAggregate(Builder $query, $aggregate)\n    {\n        $column = $this->columnize($aggregate['columns']);\n\n        // If the query has a \"distinct\" constraint and we're not asking for all columns\n        // we need to prepend \"distinct\" onto the column name so that the query takes\n        // it into account when it performs the aggregating operations on the data.\n        if (is_array($query->distinct)) {\n            $column = 'distinct '.$this->columnize($query->distinct);\n        } elseif ($query->distinct && $column !== '*') {\n            $column = 'distinct '.$column;\n        }\n\n        return 'select '.$aggregate['function'].'('.$column.') as aggregate';\n    }\n\n    /**\n     * Compile the \"select *\" portion of the query.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $columns\n     * @return string|null\n     */\n    protected function compileColumns(Builder $query, $columns)\n    {\n        // If the query is actually performing an aggregating select, we will let that\n        // compiler handle the building of the select clauses, as it will need some\n        // more syntax that is best handled by that function to keep things neat.\n        if (! is_null($query->aggregate)) {\n            return;\n        }\n\n        if ($query->distinct) {\n            $select = 'select distinct ';\n        } else {\n            $select = 'select ';\n        }\n\n        return $select.$this->columnize($columns);\n    }\n\n    /**\n     * Compile the \"from\" portion of the query.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  string  $table\n     * @return string\n     */\n    protected function compileFrom(Builder $query, $table)\n    {\n        return 'from '.$this->wrapTable($table);\n    }\n\n    /**\n     * Compile the \"join\" portions of the query.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $joins\n     * @return string\n     */\n    protected function compileJoins(Builder $query, $joins)\n    {\n        return collect($joins)->map(function ($join) use ($query) {\n            $table = $this->wrapTable($join->table);\n\n            $nestedJoins = is_null($join->joins) ? '' : ' '.$this->compileJoins($query, $join->joins);\n\n            $tableAndNestedJoins = is_null($join->joins) ? $table : '('.$table.$nestedJoins.')';\n\n            return trim(\"{$join->type} join {$tableAndNestedJoins} {$this->compileWheres($join)}\");\n        })->implode(' ');\n    }\n\n    /**\n     * Compile the \"where\" portions of the query.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @return string\n     */\n    public function compileWheres(Builder $query)\n    {\n        // Each type of where clauses has its own compiler function which is responsible\n        // for actually creating the where clauses SQL. This helps keep the code nice\n        // and maintainable since each clause has a very small method that it uses.\n        if (is_null($query->wheres)) {\n            return '';\n        }\n\n        // If we actually have some where clauses, we will strip off the first boolean\n        // operator, which is added by the query builders for convenience so we can\n        // avoid checking for the first clauses in each of the compilers methods.\n        if (count($sql = $this->compileWheresToArray($query)) > 0) {\n            return $this->concatenateWhereClauses($query, $sql);\n        }\n\n        return '';\n    }\n\n    /**\n     * Get an array of all the where clauses for the query.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @return array\n     */\n    protected function compileWheresToArray($query)\n    {\n        return collect($query->wheres)->map(function ($where) use ($query) {\n            return $where['boolean'].' '.$this->{\"where{$where['type']}\"}($query, $where);\n        })->all();\n    }\n\n    /**\n     * Format the where clause statements into one string.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $sql\n     * @return string\n     */\n    protected function concatenateWhereClauses($query, $sql)\n    {\n        $conjunction = $query instanceof JoinClause ? 'on' : 'where';\n\n        return $conjunction.' '.$this->removeLeadingBoolean(implode(' ', $sql));\n    }\n\n    /**\n     * Compile a raw where clause.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $where\n     * @return string\n     */\n    protected function whereRaw(Builder $query, $where)\n    {\n        return $where['sql'];\n    }\n\n    /**\n     * Compile a basic where clause.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $where\n     * @return string\n     */\n    protected function whereBasic(Builder $query, $where)\n    {\n        $value = $this->parameter($where['value']);\n\n        $operator = str_replace('?', '??', $where['operator']);\n\n        return $this->wrap($where['column']).' '.$operator.' '.$value;\n    }\n\n    /**\n     * Compile a bitwise operator where clause.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $where\n     * @return string\n     */\n    protected function whereBitwise(Builder $query, $where)\n    {\n        return $this->whereBasic($query, $where);\n    }\n\n    /**\n     * Compile a \"where in\" clause.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $where\n     * @return string\n     */\n    protected function whereIn(Builder $query, $where)\n    {\n        if (! empty($where['values'])) {\n            return $this->wrap($where['column']).' in ('.$this->parameterize($where['values']).')';\n        }\n\n        return '0 = 1';\n    }\n\n    /**\n     * Compile a \"where not in\" clause.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $where\n     * @return string\n     */\n    protected function whereNotIn(Builder $query, $where)\n    {\n        if (! empty($where['values'])) {\n            return $this->wrap($where['column']).' not in ('.$this->parameterize($where['values']).')';\n        }\n\n        return '1 = 1';\n    }\n\n    /**\n     * Compile a \"where not in raw\" clause.\n     *\n     * For safety, whereIntegerInRaw ensures this method is only used with integer values.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $where\n     * @return string\n     */\n    protected function whereNotInRaw(Builder $query, $where)\n    {\n        if (! empty($where['values'])) {\n            return $this->wrap($where['column']).' not in ('.implode(', ', $where['values']).')';\n        }\n\n        return '1 = 1';\n    }\n\n    /**\n     * Compile a \"where in raw\" clause.\n     *\n     * For safety, whereIntegerInRaw ensures this method is only used with integer values.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $where\n     * @return string\n     */\n    protected function whereInRaw(Builder $query, $where)\n    {\n        if (! empty($where['values'])) {\n            return $this->wrap($where['column']).' in ('.implode(', ', $where['values']).')';\n        }\n\n        return '0 = 1';\n    }\n\n    /**\n     * Compile a \"where null\" clause.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $where\n     * @return string\n     */\n    protected function whereNull(Builder $query, $where)\n    {\n        return $this->wrap($where['column']).' is null';\n    }\n\n    /**\n     * Compile a \"where not null\" clause.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $where\n     * @return string\n     */\n    protected function whereNotNull(Builder $query, $where)\n    {\n        return $this->wrap($where['column']).' is not null';\n    }\n\n    /**\n     * Compile a \"between\" where clause.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $where\n     * @return string\n     */\n    protected function whereBetween(Builder $query, $where)\n    {\n        $between = $where['not'] ? 'not between' : 'between';\n\n        $min = $this->parameter(reset($where['values']));\n\n        $max = $this->parameter(end($where['values']));\n\n        return $this->wrap($where['column']).' '.$between.' '.$min.' and '.$max;\n    }\n\n    /**\n     * Compile a \"between\" where clause.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $where\n     * @return string\n     */\n    protected function whereBetweenColumns(Builder $query, $where)\n    {\n        $between = $where['not'] ? 'not between' : 'between';\n\n        $min = $this->wrap(reset($where['values']));\n\n        $max = $this->wrap(end($where['values']));\n\n        return $this->wrap($where['column']).' '.$between.' '.$min.' and '.$max;\n    }\n\n    /**\n     * Compile a \"where date\" clause.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $where\n     * @return string\n     */\n    protected function whereDate(Builder $query, $where)\n    {\n        return $this->dateBasedWhere('date', $query, $where);\n    }\n\n    /**\n     * Compile a \"where time\" clause.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $where\n     * @return string\n     */\n    protected function whereTime(Builder $query, $where)\n    {\n        return $this->dateBasedWhere('time', $query, $where);\n    }\n\n    /**\n     * Compile a \"where day\" clause.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $where\n     * @return string\n     */\n    protected function whereDay(Builder $query, $where)\n    {\n        return $this->dateBasedWhere('day', $query, $where);\n    }\n\n    /**\n     * Compile a \"where month\" clause.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $where\n     * @return string\n     */\n    protected function whereMonth(Builder $query, $where)\n    {\n        return $this->dateBasedWhere('month', $query, $where);\n    }\n\n    /**\n     * Compile a \"where year\" clause.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $where\n     * @return string\n     */\n    protected function whereYear(Builder $query, $where)\n    {\n        return $this->dateBasedWhere('year', $query, $where);\n    }\n\n    /**\n     * Compile a date based where clause.\n     *\n     * @param  string  $type\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $where\n     * @return string\n     */\n    protected function dateBasedWhere($type, Builder $query, $where)\n    {\n        $value = $this->parameter($where['value']);\n\n        return $type.'('.$this->wrap($where['column']).') '.$where['operator'].' '.$value;\n    }\n\n    /**\n     * Compile a where clause comparing two columns.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $where\n     * @return string\n     */\n    protected function whereColumn(Builder $query, $where)\n    {\n        return $this->wrap($where['first']).' '.$where['operator'].' '.$this->wrap($where['second']);\n    }\n\n    /**\n     * Compile a nested where clause.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $where\n     * @return string\n     */\n    protected function whereNested(Builder $query, $where)\n    {\n        // Here we will calculate what portion of the string we need to remove. If this\n        // is a join clause query, we need to remove the \"on\" portion of the SQL and\n        // if it is a normal query we need to take the leading \"where\" of queries.\n        $offset = $query instanceof JoinClause ? 3 : 6;\n\n        return '('.substr($this->compileWheres($where['query']), $offset).')';\n    }\n\n    /**\n     * Compile a where condition with a sub-select.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $where\n     * @return string\n     */\n    protected function whereSub(Builder $query, $where)\n    {\n        $select = $this->compileSelect($where['query']);\n\n        return $this->wrap($where['column']).' '.$where['operator'].\" ($select)\";\n    }\n\n    /**\n     * Compile a where exists clause.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $where\n     * @return string\n     */\n    protected function whereExists(Builder $query, $where)\n    {\n        return 'exists ('.$this->compileSelect($where['query']).')';\n    }\n\n    /**\n     * Compile a where exists clause.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $where\n     * @return string\n     */\n    protected function whereNotExists(Builder $query, $where)\n    {\n        return 'not exists ('.$this->compileSelect($where['query']).')';\n    }\n\n    /**\n     * Compile a where row values condition.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $where\n     * @return string\n     */\n    protected function whereRowValues(Builder $query, $where)\n    {\n        $columns = $this->columnize($where['columns']);\n\n        $values = $this->parameterize($where['values']);\n\n        return '('.$columns.') '.$where['operator'].' ('.$values.')';\n    }\n\n    /**\n     * Compile a \"where JSON boolean\" clause.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $where\n     * @return string\n     */\n    protected function whereJsonBoolean(Builder $query, $where)\n    {\n        $column = $this->wrapJsonBooleanSelector($where['column']);\n\n        $value = $this->wrapJsonBooleanValue(\n            $this->parameter($where['value'])\n        );\n\n        return $column.' '.$where['operator'].' '.$value;\n    }\n\n    /**\n     * Compile a \"where JSON contains\" clause.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $where\n     * @return string\n     */\n    protected function whereJsonContains(Builder $query, $where)\n    {\n        $not = $where['not'] ? 'not ' : '';\n\n        return $not.$this->compileJsonContains(\n            $where['column'],\n            $this->parameter($where['value'])\n        );\n    }\n\n    /**\n     * Compile a \"JSON contains\" statement into SQL.\n     *\n     * @param  string  $column\n     * @param  string  $value\n     * @return string\n     *\n     * @throws \\RuntimeException\n     */\n    protected function compileJsonContains($column, $value)\n    {\n        throw new RuntimeException('This database engine does not support JSON contains operations.');\n    }\n\n    /**\n     * Prepare the binding for a \"JSON contains\" statement.\n     *\n     * @param  mixed  $binding\n     * @return string\n     */\n    public function prepareBindingForJsonContains($binding)\n    {\n        return json_encode($binding);\n    }\n\n    /**\n     * Compile a \"where JSON length\" clause.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $where\n     * @return string\n     */\n    protected function whereJsonLength(Builder $query, $where)\n    {\n        return $this->compileJsonLength(\n            $where['column'],\n            $where['operator'],\n            $this->parameter($where['value'])\n        );\n    }\n\n    /**\n     * Compile a \"JSON length\" statement into SQL.\n     *\n     * @param  string  $column\n     * @param  string  $operator\n     * @param  string  $value\n     * @return string\n     *\n     * @throws \\RuntimeException\n     */\n    protected function compileJsonLength($column, $operator, $value)\n    {\n        throw new RuntimeException('This database engine does not support JSON length operations.');\n    }\n\n    /**\n     * Compile a \"where fulltext\" clause.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $where\n     * @return string\n     */\n    public function whereFullText(Builder $query, $where)\n    {\n        throw new RuntimeException('This database engine does not support fulltext search operations.');\n    }\n\n    /**\n     * Compile the \"group by\" portions of the query.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $groups\n     * @return string\n     */\n    protected function compileGroups(Builder $query, $groups)\n    {\n        return 'group by '.$this->columnize($groups);\n    }\n\n    /**\n     * Compile the \"having\" portions of the query.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $havings\n     * @return string\n     */\n    protected function compileHavings(Builder $query, $havings)\n    {\n        $sql = implode(' ', array_map([$this, 'compileHaving'], $havings));\n\n        return 'having '.$this->removeLeadingBoolean($sql);\n    }\n\n    /**\n     * Compile a single having clause.\n     *\n     * @param  array  $having\n     * @return string\n     */\n    protected function compileHaving(array $having)\n    {\n        // If the having clause is \"raw\", we can just return the clause straight away\n        // without doing any more processing on it. Otherwise, we will compile the\n        // clause into SQL based on the components that make it up from builder.\n        if ($having['type'] === 'Raw') {\n            return $having['boolean'].' '.$having['sql'];\n        } elseif ($having['type'] === 'between') {\n            return $this->compileHavingBetween($having);\n        }\n\n        return $this->compileBasicHaving($having);\n    }\n\n    /**\n     * Compile a basic having clause.\n     *\n     * @param  array  $having\n     * @return string\n     */\n    protected function compileBasicHaving($having)\n    {\n        $column = $this->wrap($having['column']);\n\n        $parameter = $this->parameter($having['value']);\n\n        return $having['boolean'].' '.$column.' '.$having['operator'].' '.$parameter;\n    }\n\n    /**\n     * Compile a \"between\" having clause.\n     *\n     * @param  array  $having\n     * @return string\n     */\n    protected function compileHavingBetween($having)\n    {\n        $between = $having['not'] ? 'not between' : 'between';\n\n        $column = $this->wrap($having['column']);\n\n        $min = $this->parameter(head($having['values']));\n\n        $max = $this->parameter(last($having['values']));\n\n        return $having['boolean'].' '.$column.' '.$between.' '.$min.' and '.$max;\n    }\n\n    /**\n     * Compile the \"order by\" portions of the query.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $orders\n     * @return string\n     */\n    protected function compileOrders(Builder $query, $orders)\n    {\n        if (! empty($orders)) {\n            return 'order by '.implode(', ', $this->compileOrdersToArray($query, $orders));\n        }\n\n        return '';\n    }\n\n    /**\n     * Compile the query orders to an array.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $orders\n     * @return array\n     */\n    protected function compileOrdersToArray(Builder $query, $orders)\n    {\n        return array_map(function ($order) {\n            return $order['sql'] ?? $this->wrap($order['column']).' '.$order['direction'];\n        }, $orders);\n    }\n\n    /**\n     * Compile the random statement into SQL.\n     *\n     * @param  string  $seed\n     * @return string\n     */\n    public function compileRandom($seed)\n    {\n        return 'RANDOM()';\n    }\n\n    /**\n     * Compile the \"limit\" portions of the query.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  int  $limit\n     * @return string\n     */\n    protected function compileLimit(Builder $query, $limit)\n    {\n        return 'limit '.(int) $limit;\n    }\n\n    /**\n     * Compile the \"offset\" portions of the query.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  int  $offset\n     * @return string\n     */\n    protected function compileOffset(Builder $query, $offset)\n    {\n        return 'offset '.(int) $offset;\n    }\n\n    /**\n     * Compile the \"union\" queries attached to the main query.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @return string\n     */\n    protected function compileUnions(Builder $query)\n    {\n        $sql = '';\n\n        foreach ($query->unions as $union) {\n            $sql .= $this->compileUnion($union);\n        }\n\n        if (! empty($query->unionOrders)) {\n            $sql .= ' '.$this->compileOrders($query, $query->unionOrders);\n        }\n\n        if (isset($query->unionLimit)) {\n            $sql .= ' '.$this->compileLimit($query, $query->unionLimit);\n        }\n\n        if (isset($query->unionOffset)) {\n            $sql .= ' '.$this->compileOffset($query, $query->unionOffset);\n        }\n\n        return ltrim($sql);\n    }\n\n    /**\n     * Compile a single union statement.\n     *\n     * @param  array  $union\n     * @return string\n     */\n    protected function compileUnion(array $union)\n    {\n        $conjunction = $union['all'] ? ' union all ' : ' union ';\n\n        return $conjunction.$this->wrapUnion($union['query']->toSql());\n    }\n\n    /**\n     * Wrap a union subquery in parentheses.\n     *\n     * @param  string  $sql\n     * @return string\n     */\n    protected function wrapUnion($sql)\n    {\n        return '('.$sql.')';\n    }\n\n    /**\n     * Compile a union aggregate query into SQL.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @return string\n     */\n    protected function compileUnionAggregate(Builder $query)\n    {\n        $sql = $this->compileAggregate($query, $query->aggregate);\n\n        $query->aggregate = null;\n\n        return $sql.' from ('.$this->compileSelect($query).') as '.$this->wrapTable('temp_table');\n    }\n\n    /**\n     * Compile an exists statement into SQL.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @return string\n     */\n    public function compileExists(Builder $query)\n    {\n        $select = $this->compileSelect($query);\n\n        return \"select exists({$select}) as {$this->wrap('exists')}\";\n    }\n\n    /**\n     * Compile an insert statement into SQL.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $values\n     * @return string\n     */\n    public function compileInsert(Builder $query, array $values)\n    {\n        // Essentially we will force every insert to be treated as a batch insert which\n        // simply makes creating the SQL easier for us since we can utilize the same\n        // basic routine regardless of an amount of records given to us to insert.\n        $table = $this->wrapTable($query->from);\n\n        if (empty($values)) {\n            return \"insert into {$table} default values\";\n        }\n\n        if (! is_array(reset($values))) {\n            $values = [$values];\n        }\n\n        $columns = $this->columnize(array_keys(reset($values)));\n\n        // We need to build a list of parameter place-holders of values that are bound\n        // to the query. Each insert should have the exact same amount of parameter\n        // bindings so we will loop through the record and parameterize them all.\n        $parameters = collect($values)->map(function ($record) {\n            return '('.$this->parameterize($record).')';\n        })->implode(', ');\n\n        return \"insert into $table ($columns) values $parameters\";\n    }\n\n    /**\n     * Compile an insert ignore statement into SQL.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $values\n     * @return string\n     *\n     * @throws \\RuntimeException\n     */\n    public function compileInsertOrIgnore(Builder $query, array $values)\n    {\n        throw new RuntimeException('This database engine does not support inserting while ignoring errors.');\n    }\n\n    /**\n     * Compile an insert and get ID statement into SQL.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $values\n     * @param  string  $sequence\n     * @return string\n     */\n    public function compileInsertGetId(Builder $query, $values, $sequence)\n    {\n        return $this->compileInsert($query, $values);\n    }\n\n    /**\n     * Compile an insert statement using a subquery into SQL.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $columns\n     * @param  string  $sql\n     * @return string\n     */\n    public function compileInsertUsing(Builder $query, array $columns, string $sql)\n    {\n        return \"insert into {$this->wrapTable($query->from)} ({$this->columnize($columns)}) $sql\";\n    }\n\n    /**\n     * Compile an update statement into SQL.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $values\n     * @return string\n     */\n    public function compileUpdate(Builder $query, array $values)\n    {\n        $table = $this->wrapTable($query->from);\n\n        $columns = $this->compileUpdateColumns($query, $values);\n\n        $where = $this->compileWheres($query);\n\n        return trim(\n            isset($query->joins)\n                ? $this->compileUpdateWithJoins($query, $table, $columns, $where)\n                : $this->compileUpdateWithoutJoins($query, $table, $columns, $where)\n        );\n    }\n\n    /**\n     * Compile the columns for an update statement.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $values\n     * @return string\n     */\n    protected function compileUpdateColumns(Builder $query, array $values)\n    {\n        return collect($values)->map(function ($value, $key) {\n            return $this->wrap($key).' = '.$this->parameter($value);\n        })->implode(', ');\n    }\n\n    /**\n     * Compile an update statement without joins into SQL.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  string  $table\n     * @param  string  $columns\n     * @param  string  $where\n     * @return string\n     */\n    protected function compileUpdateWithoutJoins(Builder $query, $table, $columns, $where)\n    {\n        return \"update {$table} set {$columns} {$where}\";\n    }\n\n    /**\n     * Compile an update statement with joins into SQL.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  string  $table\n     * @param  string  $columns\n     * @param  string  $where\n     * @return string\n     */\n    protected function compileUpdateWithJoins(Builder $query, $table, $columns, $where)\n    {\n        $joins = $this->compileJoins($query, $query->joins);\n\n        return \"update {$table} {$joins} set {$columns} {$where}\";\n    }\n\n    /**\n     * Compile an \"upsert\" statement into SQL.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $values\n     * @param  array  $uniqueBy\n     * @param  array  $update\n     * @return string\n     *\n     * @throws \\RuntimeException\n     */\n    public function compileUpsert(Builder $query, array $values, array $uniqueBy, array $update)\n    {\n        throw new RuntimeException('This database engine does not support upserts.');\n    }\n\n    /**\n     * Prepare the bindings for an update statement.\n     *\n     * @param  array  $bindings\n     * @param  array  $values\n     * @return array\n     */\n    public function prepareBindingsForUpdate(array $bindings, array $values)\n    {\n        $cleanBindings = Arr::except($bindings, ['select', 'join']);\n\n        return array_values(\n            array_merge($bindings['join'], $values, Arr::flatten($cleanBindings))\n        );\n    }\n\n    /**\n     * Compile a delete statement into SQL.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @return string\n     */\n    public function compileDelete(Builder $query)\n    {\n        $table = $this->wrapTable($query->from);\n\n        $where = $this->compileWheres($query);\n\n        return trim(\n            isset($query->joins)\n                ? $this->compileDeleteWithJoins($query, $table, $where)\n                : $this->compileDeleteWithoutJoins($query, $table, $where)\n        );\n    }\n\n    /**\n     * Compile a delete statement without joins into SQL.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  string  $table\n     * @param  string  $where\n     * @return string\n     */\n    protected function compileDeleteWithoutJoins(Builder $query, $table, $where)\n    {\n        return \"delete from {$table} {$where}\";\n    }\n\n    /**\n     * Compile a delete statement with joins into SQL.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  string  $table\n     * @param  string  $where\n     * @return string\n     */\n    protected function compileDeleteWithJoins(Builder $query, $table, $where)\n    {\n        $alias = last(explode(' as ', $table));\n\n        $joins = $this->compileJoins($query, $query->joins);\n\n        return \"delete {$alias} from {$table} {$joins} {$where}\";\n    }\n\n    /**\n     * Prepare the bindings for a delete statement.\n     *\n     * @param  array  $bindings\n     * @return array\n     */\n    public function prepareBindingsForDelete(array $bindings)\n    {\n        return Arr::flatten(\n            Arr::except($bindings, 'select')\n        );\n    }\n\n    /**\n     * Compile a truncate table statement into SQL.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @return array\n     */\n    public function compileTruncate(Builder $query)\n    {\n        return ['truncate table '.$this->wrapTable($query->from) => []];\n    }\n\n    /**\n     * Compile the lock into SQL.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  bool|string  $value\n     * @return string\n     */\n    protected function compileLock(Builder $query, $value)\n    {\n        return is_string($value) ? $value : '';\n    }\n\n    /**\n     * Determine if the grammar supports savepoints.\n     *\n     * @return bool\n     */\n    public function supportsSavepoints()\n    {\n        return true;\n    }\n\n    /**\n     * Compile the SQL statement to define a savepoint.\n     *\n     * @param  string  $name\n     * @return string\n     */\n    public function compileSavepoint($name)\n    {\n        return 'SAVEPOINT '.$name;\n    }\n\n    /**\n     * Compile the SQL statement to execute a savepoint rollback.\n     *\n     * @param  string  $name\n     * @return string\n     */\n    public function compileSavepointRollBack($name)\n    {\n        return 'ROLLBACK TO SAVEPOINT '.$name;\n    }\n\n    /**\n     * Wrap a value in keyword identifiers.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Expression|string  $value\n     * @param  bool  $prefixAlias\n     * @return string\n     */\n    public function wrap($value, $prefixAlias = false)\n    {\n        if ($this->isExpression($value)) {\n            return $this->getValue($value);\n        }\n\n        // If the value being wrapped has a column alias we will need to separate out\n        // the pieces so we can wrap each of the segments of the expression on its\n        // own, and then join these both back together using the \"as\" connector.\n        if (stripos($value, ' as ') !== false) {\n            return $this->wrapAliasedValue($value, $prefixAlias);\n        }\n\n        // If the given value is a JSON selector we will wrap it differently than a\n        // traditional value. We will need to split this path and wrap each part\n        // wrapped, etc. Otherwise, we will simply wrap the value as a string.\n        if ($this->isJsonSelector($value)) {\n            return $this->wrapJsonSelector($value);\n        }\n\n        return $this->wrapSegments(explode('.', $value));\n    }\n\n    /**\n     * Wrap the given JSON selector.\n     *\n     * @param  string  $value\n     * @return string\n     *\n     * @throws \\RuntimeException\n     */\n    protected function wrapJsonSelector($value)\n    {\n        throw new RuntimeException('This database engine does not support JSON operations.');\n    }\n\n    /**\n     * Wrap the given JSON selector for boolean values.\n     *\n     * @param  string  $value\n     * @return string\n     */\n    protected function wrapJsonBooleanSelector($value)\n    {\n        return $this->wrapJsonSelector($value);\n    }\n\n    /**\n     * Wrap the given JSON boolean value.\n     *\n     * @param  string  $value\n     * @return string\n     */\n    protected function wrapJsonBooleanValue($value)\n    {\n        return $value;\n    }\n\n    /**\n     * Split the given JSON selector into the field and the optional path and wrap them separately.\n     *\n     * @param  string  $column\n     * @return array\n     */\n    protected function wrapJsonFieldAndPath($column)\n    {\n        $parts = explode('->', $column, 2);\n\n        $field = $this->wrap($parts[0]);\n\n        $path = count($parts) > 1 ? ', '.$this->wrapJsonPath($parts[1], '->') : '';\n\n        return [$field, $path];\n    }\n\n    /**\n     * Wrap the given JSON path.\n     *\n     * @param  string  $value\n     * @param  string  $delimiter\n     * @return string\n     */\n    protected function wrapJsonPath($value, $delimiter = '->')\n    {\n        $value = preg_replace(\"/([\\\\\\\\]+)?\\\\'/\", \"''\", $value);\n\n        return '\\'$.\"'.str_replace($delimiter, '\".\"', $value).'\"\\'';\n    }\n\n    /**\n     * Determine if the given string is a JSON selector.\n     *\n     * @param  string  $value\n     * @return bool\n     */\n    protected function isJsonSelector($value)\n    {\n        return Str::contains($value, '->');\n    }\n\n    /**\n     * Concatenate an array of segments, removing empties.\n     *\n     * @param  array  $segments\n     * @return string\n     */\n    protected function concatenate($segments)\n    {\n        return implode(' ', array_filter($segments, function ($value) {\n            return (string) $value !== '';\n        }));\n    }\n\n    /**\n     * Remove the leading boolean from a statement.\n     *\n     * @param  string  $value\n     * @return string\n     */\n    protected function removeLeadingBoolean($value)\n    {\n        return preg_replace('/and |or /i', '', $value, 1);\n    }\n\n    /**\n     * Get the grammar specific operators.\n     *\n     * @return array\n     */\n    public function getOperators()\n    {\n        return $this->operators;\n    }\n\n    /**\n     * Get the grammar specific bitwise operators.\n     *\n     * @return array\n     */\n    public function getBitwiseOperators()\n    {\n        return $this->bitwiseOperators;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Query/Grammars/MySqlGrammar.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Query\\Grammars;\n\nuse Illuminate\\Database\\Query\\Builder;\nuse Illuminate\\Support\\Str;\n\nclass MySqlGrammar extends Grammar\n{\n    /**\n     * The grammar specific operators.\n     *\n     * @var string[]\n     */\n    protected $operators = ['sounds like'];\n\n    /**\n     * Add a \"where null\" clause to the query.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $where\n     * @return string\n     */\n    protected function whereNull(Builder $query, $where)\n    {\n        if ($this->isJsonSelector($where['column'])) {\n            [$field, $path] = $this->wrapJsonFieldAndPath($where['column']);\n\n            return '(json_extract('.$field.$path.') is null OR json_type(json_extract('.$field.$path.')) = \\'NULL\\')';\n        }\n\n        return parent::whereNull($query, $where);\n    }\n\n    /**\n     * Add a \"where not null\" clause to the query.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $where\n     * @return string\n     */\n    protected function whereNotNull(Builder $query, $where)\n    {\n        if ($this->isJsonSelector($where['column'])) {\n            [$field, $path] = $this->wrapJsonFieldAndPath($where['column']);\n\n            return '(json_extract('.$field.$path.') is not null AND json_type(json_extract('.$field.$path.')) != \\'NULL\\')';\n        }\n\n        return parent::whereNotNull($query, $where);\n    }\n\n    /**\n     * Compile a \"where fulltext\" clause.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $where\n     * @return string\n     */\n    public function whereFullText(Builder $query, $where)\n    {\n        $columns = $this->columnize($where['columns']);\n\n        $value = $this->parameter($where['value']);\n\n        $mode = ($where['options']['mode'] ?? []) === 'boolean'\n            ? ' in boolean mode'\n            : ' in natural language mode';\n\n        $expanded = ($where['options']['expanded'] ?? []) && ($where['options']['mode'] ?? []) !== 'boolean'\n            ? ' with query expansion'\n            : '';\n\n        return \"match ({$columns}) against (\".$value.\"{$mode}{$expanded})\";\n    }\n\n    /**\n     * Compile an insert ignore statement into SQL.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $values\n     * @return string\n     */\n    public function compileInsertOrIgnore(Builder $query, array $values)\n    {\n        return Str::replaceFirst('insert', 'insert ignore', $this->compileInsert($query, $values));\n    }\n\n    /**\n     * Compile a \"JSON contains\" statement into SQL.\n     *\n     * @param  string  $column\n     * @param  string  $value\n     * @return string\n     */\n    protected function compileJsonContains($column, $value)\n    {\n        [$field, $path] = $this->wrapJsonFieldAndPath($column);\n\n        return 'json_contains('.$field.', '.$value.$path.')';\n    }\n\n    /**\n     * Compile a \"JSON length\" statement into SQL.\n     *\n     * @param  string  $column\n     * @param  string  $operator\n     * @param  string  $value\n     * @return string\n     */\n    protected function compileJsonLength($column, $operator, $value)\n    {\n        [$field, $path] = $this->wrapJsonFieldAndPath($column);\n\n        return 'json_length('.$field.$path.') '.$operator.' '.$value;\n    }\n\n    /**\n     * Compile the random statement into SQL.\n     *\n     * @param  string  $seed\n     * @return string\n     */\n    public function compileRandom($seed)\n    {\n        return 'RAND('.$seed.')';\n    }\n\n    /**\n     * Compile the lock into SQL.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  bool|string  $value\n     * @return string\n     */\n    protected function compileLock(Builder $query, $value)\n    {\n        if (! is_string($value)) {\n            return $value ? 'for update' : 'lock in share mode';\n        }\n\n        return $value;\n    }\n\n    /**\n     * Compile an insert statement into SQL.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $values\n     * @return string\n     */\n    public function compileInsert(Builder $query, array $values)\n    {\n        if (empty($values)) {\n            $values = [[]];\n        }\n\n        return parent::compileInsert($query, $values);\n    }\n\n    /**\n     * Compile the columns for an update statement.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $values\n     * @return string\n     */\n    protected function compileUpdateColumns(Builder $query, array $values)\n    {\n        return collect($values)->map(function ($value, $key) {\n            if ($this->isJsonSelector($key)) {\n                return $this->compileJsonUpdateColumn($key, $value);\n            }\n\n            return $this->wrap($key).' = '.$this->parameter($value);\n        })->implode(', ');\n    }\n\n    /**\n     * Compile an \"upsert\" statement into SQL.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $values\n     * @param  array  $uniqueBy\n     * @param  array  $update\n     * @return string\n     */\n    public function compileUpsert(Builder $query, array $values, array $uniqueBy, array $update)\n    {\n        $sql = $this->compileInsert($query, $values).' on duplicate key update ';\n\n        $columns = collect($update)->map(function ($value, $key) {\n            return is_numeric($key)\n                ? $this->wrap($value).' = values('.$this->wrap($value).')'\n                : $this->wrap($key).' = '.$this->parameter($value);\n        })->implode(', ');\n\n        return $sql.$columns;\n    }\n\n    /**\n     * Prepare a JSON column being updated using the JSON_SET function.\n     *\n     * @param  string  $key\n     * @param  mixed  $value\n     * @return string\n     */\n    protected function compileJsonUpdateColumn($key, $value)\n    {\n        if (is_bool($value)) {\n            $value = $value ? 'true' : 'false';\n        } elseif (is_array($value)) {\n            $value = 'cast(? as json)';\n        } else {\n            $value = $this->parameter($value);\n        }\n\n        [$field, $path] = $this->wrapJsonFieldAndPath($key);\n\n        return \"{$field} = json_set({$field}{$path}, {$value})\";\n    }\n\n    /**\n     * Compile an update statement without joins into SQL.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  string  $table\n     * @param  string  $columns\n     * @param  string  $where\n     * @return string\n     */\n    protected function compileUpdateWithoutJoins(Builder $query, $table, $columns, $where)\n    {\n        $sql = parent::compileUpdateWithoutJoins($query, $table, $columns, $where);\n\n        if (! empty($query->orders)) {\n            $sql .= ' '.$this->compileOrders($query, $query->orders);\n        }\n\n        if (isset($query->limit)) {\n            $sql .= ' '.$this->compileLimit($query, $query->limit);\n        }\n\n        return $sql;\n    }\n\n    /**\n     * Prepare the bindings for an update statement.\n     *\n     * Booleans, integers, and doubles are inserted into JSON updates as raw values.\n     *\n     * @param  array  $bindings\n     * @param  array  $values\n     * @return array\n     */\n    public function prepareBindingsForUpdate(array $bindings, array $values)\n    {\n        $values = collect($values)->reject(function ($value, $column) {\n            return $this->isJsonSelector($column) && is_bool($value);\n        })->map(function ($value) {\n            return is_array($value) ? json_encode($value) : $value;\n        })->all();\n\n        return parent::prepareBindingsForUpdate($bindings, $values);\n    }\n\n    /**\n     * Compile a delete query that does not use joins.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  string  $table\n     * @param  string  $where\n     * @return string\n     */\n    protected function compileDeleteWithoutJoins(Builder $query, $table, $where)\n    {\n        $sql = parent::compileDeleteWithoutJoins($query, $table, $where);\n\n        // When using MySQL, delete statements may contain order by statements and limits\n        // so we will compile both of those here. Once we have finished compiling this\n        // we will return the completed SQL statement so it will be executed for us.\n        if (! empty($query->orders)) {\n            $sql .= ' '.$this->compileOrders($query, $query->orders);\n        }\n\n        if (isset($query->limit)) {\n            $sql .= ' '.$this->compileLimit($query, $query->limit);\n        }\n\n        return $sql;\n    }\n\n    /**\n     * Wrap a single string in keyword identifiers.\n     *\n     * @param  string  $value\n     * @return string\n     */\n    protected function wrapValue($value)\n    {\n        return $value === '*' ? $value : '`'.str_replace('`', '``', $value).'`';\n    }\n\n    /**\n     * Wrap the given JSON selector.\n     *\n     * @param  string  $value\n     * @return string\n     */\n    protected function wrapJsonSelector($value)\n    {\n        [$field, $path] = $this->wrapJsonFieldAndPath($value);\n\n        return 'json_unquote(json_extract('.$field.$path.'))';\n    }\n\n    /**\n     * Wrap the given JSON selector for boolean values.\n     *\n     * @param  string  $value\n     * @return string\n     */\n    protected function wrapJsonBooleanSelector($value)\n    {\n        [$field, $path] = $this->wrapJsonFieldAndPath($value);\n\n        return 'json_extract('.$field.$path.')';\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Query/Grammars/PostgresGrammar.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Query\\Grammars;\n\nuse Illuminate\\Database\\Query\\Builder;\nuse Illuminate\\Support\\Arr;\nuse Illuminate\\Support\\Str;\n\nclass PostgresGrammar extends Grammar\n{\n    /**\n     * All of the available clause operators.\n     *\n     * @var string[]\n     */\n    protected $operators = [\n        '=', '<', '>', '<=', '>=', '<>', '!=',\n        'like', 'not like', 'between', 'ilike', 'not ilike',\n        '~', '&', '|', '#', '<<', '>>', '<<=', '>>=',\n        '&&', '@>', '<@', '?', '?|', '?&', '||', '-', '@?', '@@', '#-',\n        'is distinct from', 'is not distinct from',\n    ];\n\n    /**\n     * The grammar specific bitwise operators.\n     *\n     * @var array\n     */\n    protected $bitwiseOperators = [\n        '~', '&', '|', '#', '<<', '>>', '<<=', '>>=',\n    ];\n\n    /**\n     * {@inheritdoc}\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $where\n     * @return string\n     */\n    protected function whereBasic(Builder $query, $where)\n    {\n        if (Str::contains(strtolower($where['operator']), 'like')) {\n            return sprintf(\n                '%s::text %s %s',\n                $this->wrap($where['column']),\n                $where['operator'],\n                $this->parameter($where['value'])\n            );\n        }\n\n        return parent::whereBasic($query, $where);\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $where\n     * @return string\n     */\n    protected function whereBitwise(Builder $query, $where)\n    {\n        $value = $this->parameter($where['value']);\n\n        $operator = str_replace('?', '??', $where['operator']);\n\n        return '('.$this->wrap($where['column']).' '.$operator.' '.$value.')::bool';\n    }\n\n    /**\n     * Compile a \"where date\" clause.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $where\n     * @return string\n     */\n    protected function whereDate(Builder $query, $where)\n    {\n        $value = $this->parameter($where['value']);\n\n        return $this->wrap($where['column']).'::date '.$where['operator'].' '.$value;\n    }\n\n    /**\n     * Compile a \"where time\" clause.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $where\n     * @return string\n     */\n    protected function whereTime(Builder $query, $where)\n    {\n        $value = $this->parameter($where['value']);\n\n        return $this->wrap($where['column']).'::time '.$where['operator'].' '.$value;\n    }\n\n    /**\n     * Compile a date based where clause.\n     *\n     * @param  string  $type\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $where\n     * @return string\n     */\n    protected function dateBasedWhere($type, Builder $query, $where)\n    {\n        $value = $this->parameter($where['value']);\n\n        return 'extract('.$type.' from '.$this->wrap($where['column']).') '.$where['operator'].' '.$value;\n    }\n\n    /**\n     * Compile a \"where fulltext\" clause.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $where\n     * @return string\n     */\n    public function whereFullText(Builder $query, $where)\n    {\n        $language = $where['options']['language'] ?? 'english';\n\n        if (! in_array($language, $this->validFullTextLanguages())) {\n            $language = 'english';\n        }\n\n        $columns = collect($where['columns'])->map(function ($column) use ($language) {\n            return \"to_tsvector('{$language}', {$this->wrap($column)})\";\n        })->implode(' || ');\n\n        $mode = 'plainto_tsquery';\n\n        if (($where['options']['mode'] ?? []) === 'phrase') {\n            $mode = 'phraseto_tsquery';\n        }\n\n        if (($where['options']['mode'] ?? []) === 'websearch') {\n            $mode = 'websearch_to_tsquery';\n        }\n\n        return \"({$columns}) @@ {$mode}('{$language}', {$this->parameter($where['value'])})\";\n    }\n\n    /**\n     * Get an array of valid full text languages.\n     *\n     * @return array\n     */\n    protected function validFullTextLanguages()\n    {\n        return [\n            'simple',\n            'arabic',\n            'danish',\n            'dutch',\n            'english',\n            'finnish',\n            'french',\n            'german',\n            'hungarian',\n            'indonesian',\n            'irish',\n            'italian',\n            'lithuanian',\n            'nepali',\n            'norwegian',\n            'portuguese',\n            'romanian',\n            'russian',\n            'spanish',\n            'swedish',\n            'tamil',\n            'turkish',\n        ];\n    }\n\n    /**\n     * Compile the \"select *\" portion of the query.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $columns\n     * @return string|null\n     */\n    protected function compileColumns(Builder $query, $columns)\n    {\n        // If the query is actually performing an aggregating select, we will let that\n        // compiler handle the building of the select clauses, as it will need some\n        // more syntax that is best handled by that function to keep things neat.\n        if (! is_null($query->aggregate)) {\n            return;\n        }\n\n        if (is_array($query->distinct)) {\n            $select = 'select distinct on ('.$this->columnize($query->distinct).') ';\n        } elseif ($query->distinct) {\n            $select = 'select distinct ';\n        } else {\n            $select = 'select ';\n        }\n\n        return $select.$this->columnize($columns);\n    }\n\n    /**\n     * Compile a \"JSON contains\" statement into SQL.\n     *\n     * @param  string  $column\n     * @param  string  $value\n     * @return string\n     */\n    protected function compileJsonContains($column, $value)\n    {\n        $column = str_replace('->>', '->', $this->wrap($column));\n\n        return '('.$column.')::jsonb @> '.$value;\n    }\n\n    /**\n     * Compile a \"JSON length\" statement into SQL.\n     *\n     * @param  string  $column\n     * @param  string  $operator\n     * @param  string  $value\n     * @return string\n     */\n    protected function compileJsonLength($column, $operator, $value)\n    {\n        $column = str_replace('->>', '->', $this->wrap($column));\n\n        return 'json_array_length(('.$column.')::json) '.$operator.' '.$value;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @param  array  $having\n     * @return string\n     */\n    protected function compileHaving(array $having)\n    {\n        if ($having['type'] === 'Bitwise') {\n            return $this->compileHavingBitwise($having);\n        }\n\n        return parent::compileHaving($having);\n    }\n\n    /**\n     * Compile a having clause involving a bitwise operator.\n     *\n     * @param  array  $having\n     * @return string\n     */\n    protected function compileHavingBitwise($having)\n    {\n        $column = $this->wrap($having['column']);\n\n        $parameter = $this->parameter($having['value']);\n\n        return $having['boolean'].' ('.$column.' '.$having['operator'].' '.$parameter.')::bool';\n    }\n\n    /**\n     * Compile the lock into SQL.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  bool|string  $value\n     * @return string\n     */\n    protected function compileLock(Builder $query, $value)\n    {\n        if (! is_string($value)) {\n            return $value ? 'for update' : 'for share';\n        }\n\n        return $value;\n    }\n\n    /**\n     * Compile an insert ignore statement into SQL.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $values\n     * @return string\n     */\n    public function compileInsertOrIgnore(Builder $query, array $values)\n    {\n        return $this->compileInsert($query, $values).' on conflict do nothing';\n    }\n\n    /**\n     * Compile an insert and get ID statement into SQL.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $values\n     * @param  string  $sequence\n     * @return string\n     */\n    public function compileInsertGetId(Builder $query, $values, $sequence)\n    {\n        return $this->compileInsert($query, $values).' returning '.$this->wrap($sequence ?: 'id');\n    }\n\n    /**\n     * Compile an update statement into SQL.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $values\n     * @return string\n     */\n    public function compileUpdate(Builder $query, array $values)\n    {\n        if (isset($query->joins) || isset($query->limit)) {\n            return $this->compileUpdateWithJoinsOrLimit($query, $values);\n        }\n\n        return parent::compileUpdate($query, $values);\n    }\n\n    /**\n     * Compile the columns for an update statement.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $values\n     * @return string\n     */\n    protected function compileUpdateColumns(Builder $query, array $values)\n    {\n        return collect($values)->map(function ($value, $key) {\n            $column = last(explode('.', $key));\n\n            if ($this->isJsonSelector($key)) {\n                return $this->compileJsonUpdateColumn($column, $value);\n            }\n\n            return $this->wrap($column).' = '.$this->parameter($value);\n        })->implode(', ');\n    }\n\n    /**\n     * Compile an \"upsert\" statement into SQL.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $values\n     * @param  array  $uniqueBy\n     * @param  array  $update\n     * @return string\n     */\n    public function compileUpsert(Builder $query, array $values, array $uniqueBy, array $update)\n    {\n        $sql = $this->compileInsert($query, $values);\n\n        $sql .= ' on conflict ('.$this->columnize($uniqueBy).') do update set ';\n\n        $columns = collect($update)->map(function ($value, $key) {\n            return is_numeric($key)\n                ? $this->wrap($value).' = '.$this->wrapValue('excluded').'.'.$this->wrap($value)\n                : $this->wrap($key).' = '.$this->parameter($value);\n        })->implode(', ');\n\n        return $sql.$columns;\n    }\n\n    /**\n     * Prepares a JSON column being updated using the JSONB_SET function.\n     *\n     * @param  string  $key\n     * @param  mixed  $value\n     * @return string\n     */\n    protected function compileJsonUpdateColumn($key, $value)\n    {\n        $segments = explode('->', $key);\n\n        $field = $this->wrap(array_shift($segments));\n\n        $path = '\\'{\"'.implode('\",\"', $segments).'\"}\\'';\n\n        return \"{$field} = jsonb_set({$field}::jsonb, {$path}, {$this->parameter($value)})\";\n    }\n\n    /**\n     * Compile an update from statement into SQL.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $values\n     * @return string\n     */\n    public function compileUpdateFrom(Builder $query, $values)\n    {\n        $table = $this->wrapTable($query->from);\n\n        // Each one of the columns in the update statements needs to be wrapped in the\n        // keyword identifiers, also a place-holder needs to be created for each of\n        // the values in the list of bindings so we can make the sets statements.\n        $columns = $this->compileUpdateColumns($query, $values);\n\n        $from = '';\n\n        if (isset($query->joins)) {\n            // When using Postgres, updates with joins list the joined tables in the from\n            // clause, which is different than other systems like MySQL. Here, we will\n            // compile out the tables that are joined and add them to a from clause.\n            $froms = collect($query->joins)->map(function ($join) {\n                return $this->wrapTable($join->table);\n            })->all();\n\n            if (count($froms) > 0) {\n                $from = ' from '.implode(', ', $froms);\n            }\n        }\n\n        $where = $this->compileUpdateWheres($query);\n\n        return trim(\"update {$table} set {$columns}{$from} {$where}\");\n    }\n\n    /**\n     * Compile the additional where clauses for updates with joins.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @return string\n     */\n    protected function compileUpdateWheres(Builder $query)\n    {\n        $baseWheres = $this->compileWheres($query);\n\n        if (! isset($query->joins)) {\n            return $baseWheres;\n        }\n\n        // Once we compile the join constraints, we will either use them as the where\n        // clause or append them to the existing base where clauses. If we need to\n        // strip the leading boolean we will do so when using as the only where.\n        $joinWheres = $this->compileUpdateJoinWheres($query);\n\n        if (trim($baseWheres) == '') {\n            return 'where '.$this->removeLeadingBoolean($joinWheres);\n        }\n\n        return $baseWheres.' '.$joinWheres;\n    }\n\n    /**\n     * Compile the \"join\" clause where clauses for an update.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @return string\n     */\n    protected function compileUpdateJoinWheres(Builder $query)\n    {\n        $joinWheres = [];\n\n        // Here we will just loop through all of the join constraints and compile them\n        // all out then implode them. This should give us \"where\" like syntax after\n        // everything has been built and then we will join it to the real wheres.\n        foreach ($query->joins as $join) {\n            foreach ($join->wheres as $where) {\n                $method = \"where{$where['type']}\";\n\n                $joinWheres[] = $where['boolean'].' '.$this->$method($query, $where);\n            }\n        }\n\n        return implode(' ', $joinWheres);\n    }\n\n    /**\n     * Prepare the bindings for an update statement.\n     *\n     * @param  array  $bindings\n     * @param  array  $values\n     * @return array\n     */\n    public function prepareBindingsForUpdateFrom(array $bindings, array $values)\n    {\n        $values = collect($values)->map(function ($value, $column) {\n            return is_array($value) || ($this->isJsonSelector($column) && ! $this->isExpression($value))\n                ? json_encode($value)\n                : $value;\n        })->all();\n\n        $bindingsWithoutWhere = Arr::except($bindings, ['select', 'where']);\n\n        return array_values(\n            array_merge($values, $bindings['where'], Arr::flatten($bindingsWithoutWhere))\n        );\n    }\n\n    /**\n     * Compile an update statement with joins or limit into SQL.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $values\n     * @return string\n     */\n    protected function compileUpdateWithJoinsOrLimit(Builder $query, array $values)\n    {\n        $table = $this->wrapTable($query->from);\n\n        $columns = $this->compileUpdateColumns($query, $values);\n\n        $alias = last(preg_split('/\\s+as\\s+/i', $query->from));\n\n        $selectSql = $this->compileSelect($query->select($alias.'.ctid'));\n\n        return \"update {$table} set {$columns} where {$this->wrap('ctid')} in ({$selectSql})\";\n    }\n\n    /**\n     * Prepare the bindings for an update statement.\n     *\n     * @param  array  $bindings\n     * @param  array  $values\n     * @return array\n     */\n    public function prepareBindingsForUpdate(array $bindings, array $values)\n    {\n        $values = collect($values)->map(function ($value, $column) {\n            return is_array($value) || ($this->isJsonSelector($column) && ! $this->isExpression($value))\n                ? json_encode($value)\n                : $value;\n        })->all();\n\n        $cleanBindings = Arr::except($bindings, 'select');\n\n        return array_values(\n            array_merge($values, Arr::flatten($cleanBindings))\n        );\n    }\n\n    /**\n     * Compile a delete statement into SQL.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @return string\n     */\n    public function compileDelete(Builder $query)\n    {\n        if (isset($query->joins) || isset($query->limit)) {\n            return $this->compileDeleteWithJoinsOrLimit($query);\n        }\n\n        return parent::compileDelete($query);\n    }\n\n    /**\n     * Compile a delete statement with joins or limit into SQL.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @return string\n     */\n    protected function compileDeleteWithJoinsOrLimit(Builder $query)\n    {\n        $table = $this->wrapTable($query->from);\n\n        $alias = last(preg_split('/\\s+as\\s+/i', $query->from));\n\n        $selectSql = $this->compileSelect($query->select($alias.'.ctid'));\n\n        return \"delete from {$table} where {$this->wrap('ctid')} in ({$selectSql})\";\n    }\n\n    /**\n     * Compile a truncate table statement into SQL.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @return array\n     */\n    public function compileTruncate(Builder $query)\n    {\n        return ['truncate '.$this->wrapTable($query->from).' restart identity cascade' => []];\n    }\n\n    /**\n     * Wrap the given JSON selector.\n     *\n     * @param  string  $value\n     * @return string\n     */\n    protected function wrapJsonSelector($value)\n    {\n        $path = explode('->', $value);\n\n        $field = $this->wrapSegments(explode('.', array_shift($path)));\n\n        $wrappedPath = $this->wrapJsonPathAttributes($path);\n\n        $attribute = array_pop($wrappedPath);\n\n        if (! empty($wrappedPath)) {\n            return $field.'->'.implode('->', $wrappedPath).'->>'.$attribute;\n        }\n\n        return $field.'->>'.$attribute;\n    }\n\n    /**\n     * Wrap the given JSON selector for boolean values.\n     *\n     * @param  string  $value\n     * @return string\n     */\n    protected function wrapJsonBooleanSelector($value)\n    {\n        $selector = str_replace(\n            '->>', '->',\n            $this->wrapJsonSelector($value)\n        );\n\n        return '('.$selector.')::jsonb';\n    }\n\n    /**\n     * Wrap the given JSON boolean value.\n     *\n     * @param  string  $value\n     * @return string\n     */\n    protected function wrapJsonBooleanValue($value)\n    {\n        return \"'\".$value.\"'::jsonb\";\n    }\n\n    /**\n     * Wrap the attributes of the give JSON path.\n     *\n     * @param  array  $path\n     * @return array\n     */\n    protected function wrapJsonPathAttributes($path)\n    {\n        return array_map(function ($attribute) {\n            return filter_var($attribute, FILTER_VALIDATE_INT) !== false\n                        ? $attribute\n                        : \"'$attribute'\";\n        }, $path);\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Query/Grammars/SQLiteGrammar.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Query\\Grammars;\n\nuse Illuminate\\Database\\Query\\Builder;\nuse Illuminate\\Support\\Arr;\nuse Illuminate\\Support\\Str;\n\nclass SQLiteGrammar extends Grammar\n{\n    /**\n     * All of the available clause operators.\n     *\n     * @var string[]\n     */\n    protected $operators = [\n        '=', '<', '>', '<=', '>=', '<>', '!=',\n        'like', 'not like', 'ilike',\n        '&', '|', '<<', '>>',\n    ];\n\n    /**\n     * Compile the lock into SQL.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  bool|string  $value\n     * @return string\n     */\n    protected function compileLock(Builder $query, $value)\n    {\n        return '';\n    }\n\n    /**\n     * Wrap a union subquery in parentheses.\n     *\n     * @param  string  $sql\n     * @return string\n     */\n    protected function wrapUnion($sql)\n    {\n        return 'select * from ('.$sql.')';\n    }\n\n    /**\n     * Compile a \"where date\" clause.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $where\n     * @return string\n     */\n    protected function whereDate(Builder $query, $where)\n    {\n        return $this->dateBasedWhere('%Y-%m-%d', $query, $where);\n    }\n\n    /**\n     * Compile a \"where day\" clause.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $where\n     * @return string\n     */\n    protected function whereDay(Builder $query, $where)\n    {\n        return $this->dateBasedWhere('%d', $query, $where);\n    }\n\n    /**\n     * Compile a \"where month\" clause.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $where\n     * @return string\n     */\n    protected function whereMonth(Builder $query, $where)\n    {\n        return $this->dateBasedWhere('%m', $query, $where);\n    }\n\n    /**\n     * Compile a \"where year\" clause.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $where\n     * @return string\n     */\n    protected function whereYear(Builder $query, $where)\n    {\n        return $this->dateBasedWhere('%Y', $query, $where);\n    }\n\n    /**\n     * Compile a \"where time\" clause.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $where\n     * @return string\n     */\n    protected function whereTime(Builder $query, $where)\n    {\n        return $this->dateBasedWhere('%H:%M:%S', $query, $where);\n    }\n\n    /**\n     * Compile a date based where clause.\n     *\n     * @param  string  $type\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $where\n     * @return string\n     */\n    protected function dateBasedWhere($type, Builder $query, $where)\n    {\n        $value = $this->parameter($where['value']);\n\n        return \"strftime('{$type}', {$this->wrap($where['column'])}) {$where['operator']} cast({$value} as text)\";\n    }\n\n    /**\n     * Compile a \"JSON length\" statement into SQL.\n     *\n     * @param  string  $column\n     * @param  string  $operator\n     * @param  string  $value\n     * @return string\n     */\n    protected function compileJsonLength($column, $operator, $value)\n    {\n        [$field, $path] = $this->wrapJsonFieldAndPath($column);\n\n        return 'json_array_length('.$field.$path.') '.$operator.' '.$value;\n    }\n\n    /**\n     * Compile an update statement into SQL.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $values\n     * @return string\n     */\n    public function compileUpdate(Builder $query, array $values)\n    {\n        if (isset($query->joins) || isset($query->limit)) {\n            return $this->compileUpdateWithJoinsOrLimit($query, $values);\n        }\n\n        return parent::compileUpdate($query, $values);\n    }\n\n    /**\n     * Compile an insert ignore statement into SQL.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $values\n     * @return string\n     */\n    public function compileInsertOrIgnore(Builder $query, array $values)\n    {\n        return Str::replaceFirst('insert', 'insert or ignore', $this->compileInsert($query, $values));\n    }\n\n    /**\n     * Compile the columns for an update statement.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $values\n     * @return string\n     */\n    protected function compileUpdateColumns(Builder $query, array $values)\n    {\n        $jsonGroups = $this->groupJsonColumnsForUpdate($values);\n\n        return collect($values)->reject(function ($value, $key) {\n            return $this->isJsonSelector($key);\n        })->merge($jsonGroups)->map(function ($value, $key) use ($jsonGroups) {\n            $column = last(explode('.', $key));\n\n            $value = isset($jsonGroups[$key]) ? $this->compileJsonPatch($column, $value) : $this->parameter($value);\n\n            return $this->wrap($column).' = '.$value;\n        })->implode(', ');\n    }\n\n    /**\n     * Compile an \"upsert\" statement into SQL.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $values\n     * @param  array  $uniqueBy\n     * @param  array  $update\n     * @return string\n     */\n    public function compileUpsert(Builder $query, array $values, array $uniqueBy, array $update)\n    {\n        $sql = $this->compileInsert($query, $values);\n\n        $sql .= ' on conflict ('.$this->columnize($uniqueBy).') do update set ';\n\n        $columns = collect($update)->map(function ($value, $key) {\n            return is_numeric($key)\n                ? $this->wrap($value).' = '.$this->wrapValue('excluded').'.'.$this->wrap($value)\n                : $this->wrap($key).' = '.$this->parameter($value);\n        })->implode(', ');\n\n        return $sql.$columns;\n    }\n\n    /**\n     * Group the nested JSON columns.\n     *\n     * @param  array  $values\n     * @return array\n     */\n    protected function groupJsonColumnsForUpdate(array $values)\n    {\n        $groups = [];\n\n        foreach ($values as $key => $value) {\n            if ($this->isJsonSelector($key)) {\n                Arr::set($groups, str_replace('->', '.', Str::after($key, '.')), $value);\n            }\n        }\n\n        return $groups;\n    }\n\n    /**\n     * Compile a \"JSON\" patch statement into SQL.\n     *\n     * @param  string  $column\n     * @param  mixed  $value\n     * @return string\n     */\n    protected function compileJsonPatch($column, $value)\n    {\n        return \"json_patch(ifnull({$this->wrap($column)}, json('{}')), json({$this->parameter($value)}))\";\n    }\n\n    /**\n     * Compile an update statement with joins or limit into SQL.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $values\n     * @return string\n     */\n    protected function compileUpdateWithJoinsOrLimit(Builder $query, array $values)\n    {\n        $table = $this->wrapTable($query->from);\n\n        $columns = $this->compileUpdateColumns($query, $values);\n\n        $alias = last(preg_split('/\\s+as\\s+/i', $query->from));\n\n        $selectSql = $this->compileSelect($query->select($alias.'.rowid'));\n\n        return \"update {$table} set {$columns} where {$this->wrap('rowid')} in ({$selectSql})\";\n    }\n\n    /**\n     * Prepare the bindings for an update statement.\n     *\n     * @param  array  $bindings\n     * @param  array  $values\n     * @return array\n     */\n    public function prepareBindingsForUpdate(array $bindings, array $values)\n    {\n        $groups = $this->groupJsonColumnsForUpdate($values);\n\n        $values = collect($values)->reject(function ($value, $key) {\n            return $this->isJsonSelector($key);\n        })->merge($groups)->map(function ($value) {\n            return is_array($value) ? json_encode($value) : $value;\n        })->all();\n\n        $cleanBindings = Arr::except($bindings, 'select');\n\n        return array_values(\n            array_merge($values, Arr::flatten($cleanBindings))\n        );\n    }\n\n    /**\n     * Compile a delete statement into SQL.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @return string\n     */\n    public function compileDelete(Builder $query)\n    {\n        if (isset($query->joins) || isset($query->limit)) {\n            return $this->compileDeleteWithJoinsOrLimit($query);\n        }\n\n        return parent::compileDelete($query);\n    }\n\n    /**\n     * Compile a delete statement with joins or limit into SQL.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @return string\n     */\n    protected function compileDeleteWithJoinsOrLimit(Builder $query)\n    {\n        $table = $this->wrapTable($query->from);\n\n        $alias = last(preg_split('/\\s+as\\s+/i', $query->from));\n\n        $selectSql = $this->compileSelect($query->select($alias.'.rowid'));\n\n        return \"delete from {$table} where {$this->wrap('rowid')} in ({$selectSql})\";\n    }\n\n    /**\n     * Compile a truncate table statement into SQL.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @return array\n     */\n    public function compileTruncate(Builder $query)\n    {\n        return [\n            'delete from sqlite_sequence where name = ?' => [$query->from],\n            'delete from '.$this->wrapTable($query->from) => [],\n        ];\n    }\n\n    /**\n     * Wrap the given JSON selector.\n     *\n     * @param  string  $value\n     * @return string\n     */\n    protected function wrapJsonSelector($value)\n    {\n        [$field, $path] = $this->wrapJsonFieldAndPath($value);\n\n        return 'json_extract('.$field.$path.')';\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Query/Grammars/SqlServerGrammar.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Query\\Grammars;\n\nuse Illuminate\\Database\\Query\\Builder;\nuse Illuminate\\Support\\Arr;\nuse Illuminate\\Support\\Str;\n\nclass SqlServerGrammar extends Grammar\n{\n    /**\n     * All of the available clause operators.\n     *\n     * @var string[]\n     */\n    protected $operators = [\n        '=', '<', '>', '<=', '>=', '!<', '!>', '<>', '!=',\n        'like', 'not like', 'ilike',\n        '&', '&=', '|', '|=', '^', '^=',\n    ];\n\n    /**\n     * Compile a select query into SQL.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @return string\n     */\n    public function compileSelect(Builder $query)\n    {\n        if (! $query->offset) {\n            return parent::compileSelect($query);\n        }\n\n        if (is_null($query->columns)) {\n            $query->columns = ['*'];\n        }\n\n        $components = $this->compileComponents($query);\n\n        if (! empty($components['orders'])) {\n            return parent::compileSelect($query).\" offset {$query->offset} rows fetch next {$query->limit} rows only\";\n        }\n\n        // If an offset is present on the query, we will need to wrap the query in\n        // a big \"ANSI\" offset syntax block. This is very nasty compared to the\n        // other database systems but is necessary for implementing features.\n        return $this->compileAnsiOffset(\n            $query, $components\n        );\n    }\n\n    /**\n     * Compile the \"select *\" portion of the query.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $columns\n     * @return string|null\n     */\n    protected function compileColumns(Builder $query, $columns)\n    {\n        if (! is_null($query->aggregate)) {\n            return;\n        }\n\n        $select = $query->distinct ? 'select distinct ' : 'select ';\n\n        // If there is a limit on the query, but not an offset, we will add the top\n        // clause to the query, which serves as a \"limit\" type clause within the\n        // SQL Server system similar to the limit keywords available in MySQL.\n        if (is_numeric($query->limit) && $query->limit > 0 && $query->offset <= 0) {\n            $select .= 'top '.((int) $query->limit).' ';\n        }\n\n        return $select.$this->columnize($columns);\n    }\n\n    /**\n     * Compile the \"from\" portion of the query.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  string  $table\n     * @return string\n     */\n    protected function compileFrom(Builder $query, $table)\n    {\n        $from = parent::compileFrom($query, $table);\n\n        if (is_string($query->lock)) {\n            return $from.' '.$query->lock;\n        }\n\n        if (! is_null($query->lock)) {\n            return $from.' with(rowlock,'.($query->lock ? 'updlock,' : '').'holdlock)';\n        }\n\n        return $from;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $where\n     * @return string\n     */\n    protected function whereBitwise(Builder $query, $where)\n    {\n        $value = $this->parameter($where['value']);\n\n        $operator = str_replace('?', '??', $where['operator']);\n\n        return '('.$this->wrap($where['column']).' '.$operator.' '.$value.') != 0';\n    }\n\n    /**\n     * Compile a \"where date\" clause.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $where\n     * @return string\n     */\n    protected function whereDate(Builder $query, $where)\n    {\n        $value = $this->parameter($where['value']);\n\n        return 'cast('.$this->wrap($where['column']).' as date) '.$where['operator'].' '.$value;\n    }\n\n    /**\n     * Compile a \"where time\" clause.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $where\n     * @return string\n     */\n    protected function whereTime(Builder $query, $where)\n    {\n        $value = $this->parameter($where['value']);\n\n        return 'cast('.$this->wrap($where['column']).' as time) '.$where['operator'].' '.$value;\n    }\n\n    /**\n     * Compile a \"JSON contains\" statement into SQL.\n     *\n     * @param  string  $column\n     * @param  string  $value\n     * @return string\n     */\n    protected function compileJsonContains($column, $value)\n    {\n        [$field, $path] = $this->wrapJsonFieldAndPath($column);\n\n        return $value.' in (select [value] from openjson('.$field.$path.'))';\n    }\n\n    /**\n     * Prepare the binding for a \"JSON contains\" statement.\n     *\n     * @param  mixed  $binding\n     * @return string\n     */\n    public function prepareBindingForJsonContains($binding)\n    {\n        return is_bool($binding) ? json_encode($binding) : $binding;\n    }\n\n    /**\n     * Compile a \"JSON length\" statement into SQL.\n     *\n     * @param  string  $column\n     * @param  string  $operator\n     * @param  string  $value\n     * @return string\n     */\n    protected function compileJsonLength($column, $operator, $value)\n    {\n        [$field, $path] = $this->wrapJsonFieldAndPath($column);\n\n        return '(select count(*) from openjson('.$field.$path.')) '.$operator.' '.$value;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @param  array  $having\n     * @return string\n     */\n    protected function compileHaving(array $having)\n    {\n        if ($having['type'] === 'Bitwise') {\n            return $this->compileHavingBitwise($having);\n        }\n\n        return parent::compileHaving($having);\n    }\n\n    /**\n     * Compile a having clause involving a bitwise operator.\n     *\n     * @param  array  $having\n     * @return string\n     */\n    protected function compileHavingBitwise($having)\n    {\n        $column = $this->wrap($having['column']);\n\n        $parameter = $this->parameter($having['value']);\n\n        return $having['boolean'].' ('.$column.' '.$having['operator'].' '.$parameter.') != 0';\n    }\n\n    /**\n     * Create a full ANSI offset clause for the query.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $components\n     * @return string\n     */\n    protected function compileAnsiOffset(Builder $query, $components)\n    {\n        // An ORDER BY clause is required to make this offset query work, so if one does\n        // not exist we'll just create a dummy clause to trick the database and so it\n        // does not complain about the queries for not having an \"order by\" clause.\n        if (empty($components['orders'])) {\n            $components['orders'] = 'order by (select 0)';\n        }\n\n        // We need to add the row number to the query so we can compare it to the offset\n        // and limit values given for the statements. So we will add an expression to\n        // the \"select\" that will give back the row numbers on each of the records.\n        $components['columns'] .= $this->compileOver($components['orders']);\n\n        unset($components['orders']);\n\n        if ($this->queryOrderContainsSubquery($query)) {\n            $query->bindings = $this->sortBindingsForSubqueryOrderBy($query);\n        }\n\n        // Next we need to calculate the constraints that should be placed on the query\n        // to get the right offset and limit from our query but if there is no limit\n        // set we will just handle the offset only since that is all that matters.\n        $sql = $this->concatenate($components);\n\n        return $this->compileTableExpression($sql, $query);\n    }\n\n    /**\n     * Compile the over statement for a table expression.\n     *\n     * @param  string  $orderings\n     * @return string\n     */\n    protected function compileOver($orderings)\n    {\n        return \", row_number() over ({$orderings}) as row_num\";\n    }\n\n    /**\n     * Determine if the query's order by clauses contain a subquery.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @return bool\n     */\n    protected function queryOrderContainsSubquery($query)\n    {\n        if (! is_array($query->orders)) {\n            return false;\n        }\n\n        return Arr::first($query->orders, function ($value) {\n            return $this->isExpression($value['column'] ?? null);\n        }, false) !== false;\n    }\n\n    /**\n     * Move the order bindings to be after the \"select\" statement to account for an order by subquery.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @return array\n     */\n    protected function sortBindingsForSubqueryOrderBy($query)\n    {\n        return Arr::sort($query->bindings, function ($bindings, $key) {\n            return array_search($key, ['select', 'order', 'from', 'join', 'where', 'groupBy', 'having', 'union', 'unionOrder']);\n        });\n    }\n\n    /**\n     * Compile a common table expression for a query.\n     *\n     * @param  string  $sql\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @return string\n     */\n    protected function compileTableExpression($sql, $query)\n    {\n        $constraint = $this->compileRowConstraint($query);\n\n        return \"select * from ({$sql}) as temp_table where row_num {$constraint} order by row_num\";\n    }\n\n    /**\n     * Compile the limit / offset row constraint for a query.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @return string\n     */\n    protected function compileRowConstraint($query)\n    {\n        $start = (int) $query->offset + 1;\n\n        if ($query->limit > 0) {\n            $finish = (int) $query->offset + (int) $query->limit;\n\n            return \"between {$start} and {$finish}\";\n        }\n\n        return \">= {$start}\";\n    }\n\n    /**\n     * Compile a delete statement without joins into SQL.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  string  $table\n     * @param  string  $where\n     * @return string\n     */\n    protected function compileDeleteWithoutJoins(Builder $query, $table, $where)\n    {\n        $sql = parent::compileDeleteWithoutJoins($query, $table, $where);\n\n        return ! is_null($query->limit) && $query->limit > 0 && $query->offset <= 0\n                        ? Str::replaceFirst('delete', 'delete top ('.$query->limit.')', $sql)\n                        : $sql;\n    }\n\n    /**\n     * Compile the random statement into SQL.\n     *\n     * @param  string  $seed\n     * @return string\n     */\n    public function compileRandom($seed)\n    {\n        return 'NEWID()';\n    }\n\n    /**\n     * Compile the \"limit\" portions of the query.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  int  $limit\n     * @return string\n     */\n    protected function compileLimit(Builder $query, $limit)\n    {\n        return '';\n    }\n\n    /**\n     * Compile the \"offset\" portions of the query.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  int  $offset\n     * @return string\n     */\n    protected function compileOffset(Builder $query, $offset)\n    {\n        return '';\n    }\n\n    /**\n     * Compile the lock into SQL.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  bool|string  $value\n     * @return string\n     */\n    protected function compileLock(Builder $query, $value)\n    {\n        return '';\n    }\n\n    /**\n     * Wrap a union subquery in parentheses.\n     *\n     * @param  string  $sql\n     * @return string\n     */\n    protected function wrapUnion($sql)\n    {\n        return 'select * from ('.$sql.') as '.$this->wrapTable('temp_table');\n    }\n\n    /**\n     * Compile an exists statement into SQL.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @return string\n     */\n    public function compileExists(Builder $query)\n    {\n        $existsQuery = clone $query;\n\n        $existsQuery->columns = [];\n\n        return $this->compileSelect($existsQuery->selectRaw('1 [exists]')->limit(1));\n    }\n\n    /**\n     * Compile an update statement with joins into SQL.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  string  $table\n     * @param  string  $columns\n     * @param  string  $where\n     * @return string\n     */\n    protected function compileUpdateWithJoins(Builder $query, $table, $columns, $where)\n    {\n        $alias = last(explode(' as ', $table));\n\n        $joins = $this->compileJoins($query, $query->joins);\n\n        return \"update {$alias} set {$columns} from {$table} {$joins} {$where}\";\n    }\n\n    /**\n     * Compile an \"upsert\" statement into SQL.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $values\n     * @param  array  $uniqueBy\n     * @param  array  $update\n     * @return string\n     */\n    public function compileUpsert(Builder $query, array $values, array $uniqueBy, array $update)\n    {\n        $columns = $this->columnize(array_keys(reset($values)));\n\n        $sql = 'merge '.$this->wrapTable($query->from).' ';\n\n        $parameters = collect($values)->map(function ($record) {\n            return '('.$this->parameterize($record).')';\n        })->implode(', ');\n\n        $sql .= 'using (values '.$parameters.') '.$this->wrapTable('laravel_source').' ('.$columns.') ';\n\n        $on = collect($uniqueBy)->map(function ($column) use ($query) {\n            return $this->wrap('laravel_source.'.$column).' = '.$this->wrap($query->from.'.'.$column);\n        })->implode(' and ');\n\n        $sql .= 'on '.$on.' ';\n\n        if ($update) {\n            $update = collect($update)->map(function ($value, $key) {\n                return is_numeric($key)\n                    ? $this->wrap($value).' = '.$this->wrap('laravel_source.'.$value)\n                    : $this->wrap($key).' = '.$this->parameter($value);\n            })->implode(', ');\n\n            $sql .= 'when matched then update set '.$update.' ';\n        }\n\n        $sql .= 'when not matched then insert ('.$columns.') values ('.$columns.');';\n\n        return $sql;\n    }\n\n    /**\n     * Prepare the bindings for an update statement.\n     *\n     * @param  array  $bindings\n     * @param  array  $values\n     * @return array\n     */\n    public function prepareBindingsForUpdate(array $bindings, array $values)\n    {\n        $cleanBindings = Arr::except($bindings, 'select');\n\n        return array_values(\n            array_merge($values, Arr::flatten($cleanBindings))\n        );\n    }\n\n    /**\n     * Compile the SQL statement to define a savepoint.\n     *\n     * @param  string  $name\n     * @return string\n     */\n    public function compileSavepoint($name)\n    {\n        return 'SAVE TRANSACTION '.$name;\n    }\n\n    /**\n     * Compile the SQL statement to execute a savepoint rollback.\n     *\n     * @param  string  $name\n     * @return string\n     */\n    public function compileSavepointRollBack($name)\n    {\n        return 'ROLLBACK TRANSACTION '.$name;\n    }\n\n    /**\n     * Get the format for database stored dates.\n     *\n     * @return string\n     */\n    public function getDateFormat()\n    {\n        return 'Y-m-d H:i:s.v';\n    }\n\n    /**\n     * Wrap a single string in keyword identifiers.\n     *\n     * @param  string  $value\n     * @return string\n     */\n    protected function wrapValue($value)\n    {\n        return $value === '*' ? $value : '['.str_replace(']', ']]', $value).']';\n    }\n\n    /**\n     * Wrap the given JSON selector.\n     *\n     * @param  string  $value\n     * @return string\n     */\n    protected function wrapJsonSelector($value)\n    {\n        [$field, $path] = $this->wrapJsonFieldAndPath($value);\n\n        return 'json_value('.$field.$path.')';\n    }\n\n    /**\n     * Wrap the given JSON boolean value.\n     *\n     * @param  string  $value\n     * @return string\n     */\n    protected function wrapJsonBooleanValue($value)\n    {\n        return \"'\".$value.\"'\";\n    }\n\n    /**\n     * Wrap a table in keyword identifiers.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Expression|string  $table\n     * @return string\n     */\n    public function wrapTable($table)\n    {\n        if (! $this->isExpression($table)) {\n            return $this->wrapTableValuedFunction(parent::wrapTable($table));\n        }\n\n        return $this->getValue($table);\n    }\n\n    /**\n     * Wrap a table in keyword identifiers.\n     *\n     * @param  string  $table\n     * @return string\n     */\n    protected function wrapTableValuedFunction($table)\n    {\n        if (preg_match('/^(.+?)(\\(.*?\\))]$/', $table, $matches) === 1) {\n            $table = $matches[1].']'.$matches[2];\n        }\n\n        return $table;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Query/JoinClause.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Query;\n\nuse Closure;\n\nclass JoinClause extends Builder\n{\n    /**\n     * The type of join being performed.\n     *\n     * @var string\n     */\n    public $type;\n\n    /**\n     * The table the join clause is joining to.\n     *\n     * @var string\n     */\n    public $table;\n\n    /**\n     * The connection of the parent query builder.\n     *\n     * @var \\Illuminate\\Database\\ConnectionInterface\n     */\n    protected $parentConnection;\n\n    /**\n     * The grammar of the parent query builder.\n     *\n     * @var \\Illuminate\\Database\\Query\\Grammars\\Grammar\n     */\n    protected $parentGrammar;\n\n    /**\n     * The processor of the parent query builder.\n     *\n     * @var \\Illuminate\\Database\\Query\\Processors\\Processor\n     */\n    protected $parentProcessor;\n\n    /**\n     * The class name of the parent query builder.\n     *\n     * @var string\n     */\n    protected $parentClass;\n\n    /**\n     * Create a new join clause instance.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $parentQuery\n     * @param  string  $type\n     * @param  string  $table\n     * @return void\n     */\n    public function __construct(Builder $parentQuery, $type, $table)\n    {\n        $this->type = $type;\n        $this->table = $table;\n        $this->parentClass = get_class($parentQuery);\n        $this->parentGrammar = $parentQuery->getGrammar();\n        $this->parentProcessor = $parentQuery->getProcessor();\n        $this->parentConnection = $parentQuery->getConnection();\n\n        parent::__construct(\n            $this->parentConnection, $this->parentGrammar, $this->parentProcessor\n        );\n    }\n\n    /**\n     * Add an \"on\" clause to the join.\n     *\n     * On clauses can be chained, e.g.\n     *\n     *  $join->on('contacts.user_id', '=', 'users.id')\n     *       ->on('contacts.info_id', '=', 'info.id')\n     *\n     * will produce the following SQL:\n     *\n     * on `contacts`.`user_id` = `users`.`id` and `contacts`.`info_id` = `info`.`id`\n     *\n     * @param  \\Closure|string  $first\n     * @param  string|null  $operator\n     * @param  \\Illuminate\\Database\\Query\\Expression|string|null  $second\n     * @param  string  $boolean\n     * @return $this\n     *\n     * @throws \\InvalidArgumentException\n     */\n    public function on($first, $operator = null, $second = null, $boolean = 'and')\n    {\n        if ($first instanceof Closure) {\n            return $this->whereNested($first, $boolean);\n        }\n\n        return $this->whereColumn($first, $operator, $second, $boolean);\n    }\n\n    /**\n     * Add an \"or on\" clause to the join.\n     *\n     * @param  \\Closure|string  $first\n     * @param  string|null  $operator\n     * @param  \\Illuminate\\Database\\Query\\Expression|string|null  $second\n     * @return \\Illuminate\\Database\\Query\\JoinClause\n     */\n    public function orOn($first, $operator = null, $second = null)\n    {\n        return $this->on($first, $operator, $second, 'or');\n    }\n\n    /**\n     * Get a new instance of the join clause builder.\n     *\n     * @return \\Illuminate\\Database\\Query\\JoinClause\n     */\n    public function newQuery()\n    {\n        return new static($this->newParentQuery(), $this->type, $this->table);\n    }\n\n    /**\n     * Create a new query instance for sub-query.\n     *\n     * @return \\Illuminate\\Database\\Query\\Builder\n     */\n    protected function forSubQuery()\n    {\n        return $this->newParentQuery()->newQuery();\n    }\n\n    /**\n     * Create a new parent query instance.\n     *\n     * @return \\Illuminate\\Database\\Query\\Builder\n     */\n    protected function newParentQuery()\n    {\n        $class = $this->parentClass;\n\n        return new $class($this->parentConnection, $this->parentGrammar, $this->parentProcessor);\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Query/Processors/MySqlProcessor.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Query\\Processors;\n\nclass MySqlProcessor extends Processor\n{\n    /**\n     * Process the results of a column listing query.\n     *\n     * @param  array  $results\n     * @return array\n     */\n    public function processColumnListing($results)\n    {\n        return array_map(function ($result) {\n            return ((object) $result)->column_name;\n        }, $results);\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Query/Processors/PostgresProcessor.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Query\\Processors;\n\nuse Illuminate\\Database\\Query\\Builder;\n\nclass PostgresProcessor extends Processor\n{\n    /**\n     * Process an \"insert get ID\" query.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  string  $sql\n     * @param  array  $values\n     * @param  string|null  $sequence\n     * @return int\n     */\n    public function processInsertGetId(Builder $query, $sql, $values, $sequence = null)\n    {\n        $connection = $query->getConnection();\n\n        $connection->recordsHaveBeenModified();\n\n        $result = $connection->selectFromWriteConnection($sql, $values)[0];\n\n        $sequence = $sequence ?: 'id';\n\n        $id = is_object($result) ? $result->{$sequence} : $result[$sequence];\n\n        return is_numeric($id) ? (int) $id : $id;\n    }\n\n    /**\n     * Process the results of a column listing query.\n     *\n     * @param  array  $results\n     * @return array\n     */\n    public function processColumnListing($results)\n    {\n        return array_map(function ($result) {\n            return ((object) $result)->column_name;\n        }, $results);\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Query/Processors/Processor.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Query\\Processors;\n\nuse Illuminate\\Database\\Query\\Builder;\n\nclass Processor\n{\n    /**\n     * Process the results of a \"select\" query.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  array  $results\n     * @return array\n     */\n    public function processSelect(Builder $query, $results)\n    {\n        return $results;\n    }\n\n    /**\n     * Process an  \"insert get ID\" query.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  string  $sql\n     * @param  array  $values\n     * @param  string|null  $sequence\n     * @return int\n     */\n    public function processInsertGetId(Builder $query, $sql, $values, $sequence = null)\n    {\n        $query->getConnection()->insert($sql, $values);\n\n        $id = $query->getConnection()->getPdo()->lastInsertId($sequence);\n\n        return is_numeric($id) ? (int) $id : $id;\n    }\n\n    /**\n     * Process the results of a column listing query.\n     *\n     * @param  array  $results\n     * @return array\n     */\n    public function processColumnListing($results)\n    {\n        return $results;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Query/Processors/SQLiteProcessor.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Query\\Processors;\n\nclass SQLiteProcessor extends Processor\n{\n    /**\n     * Process the results of a column listing query.\n     *\n     * @param  array  $results\n     * @return array\n     */\n    public function processColumnListing($results)\n    {\n        return array_map(function ($result) {\n            return ((object) $result)->name;\n        }, $results);\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Query/Processors/SqlServerProcessor.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Query\\Processors;\n\nuse Exception;\nuse Illuminate\\Database\\Connection;\nuse Illuminate\\Database\\Query\\Builder;\n\nclass SqlServerProcessor extends Processor\n{\n    /**\n     * Process an \"insert get ID\" query.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Builder  $query\n     * @param  string  $sql\n     * @param  array  $values\n     * @param  string|null  $sequence\n     * @return int\n     */\n    public function processInsertGetId(Builder $query, $sql, $values, $sequence = null)\n    {\n        $connection = $query->getConnection();\n\n        $connection->insert($sql, $values);\n\n        if ($connection->getConfig('odbc') === true) {\n            $id = $this->processInsertGetIdForOdbc($connection);\n        } else {\n            $id = $connection->getPdo()->lastInsertId();\n        }\n\n        return is_numeric($id) ? (int) $id : $id;\n    }\n\n    /**\n     * Process an \"insert get ID\" query for ODBC.\n     *\n     * @param  \\Illuminate\\Database\\Connection  $connection\n     * @return int\n     *\n     * @throws \\Exception\n     */\n    protected function processInsertGetIdForOdbc(Connection $connection)\n    {\n        $result = $connection->selectFromWriteConnection(\n            'SELECT CAST(COALESCE(SCOPE_IDENTITY(), @@IDENTITY) AS int) AS insertid'\n        );\n\n        if (! $result) {\n            throw new Exception('Unable to retrieve lastInsertID for ODBC.');\n        }\n\n        $row = $result[0];\n\n        return is_object($row) ? $row->insertid : $row['insertid'];\n    }\n\n    /**\n     * Process the results of a column listing query.\n     *\n     * @param  array  $results\n     * @return array\n     */\n    public function processColumnListing($results)\n    {\n        return array_map(function ($result) {\n            return ((object) $result)->name;\n        }, $results);\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/QueryException.php",
    "content": "<?php\n\nnamespace Illuminate\\Database;\n\nuse Illuminate\\Support\\Str;\nuse PDOException;\nuse Throwable;\n\nclass QueryException extends PDOException\n{\n    /**\n     * The SQL for the query.\n     *\n     * @var string\n     */\n    protected $sql;\n\n    /**\n     * The bindings for the query.\n     *\n     * @var array\n     */\n    protected $bindings;\n\n    /**\n     * Create a new query exception instance.\n     *\n     * @param  string  $sql\n     * @param  array  $bindings\n     * @param  \\Throwable  $previous\n     * @return void\n     */\n    public function __construct($sql, array $bindings, Throwable $previous)\n    {\n        parent::__construct('', 0, $previous);\n\n        $this->sql = $sql;\n        $this->bindings = $bindings;\n        $this->code = $previous->getCode();\n        $this->message = $this->formatMessage($sql, $bindings, $previous);\n\n        if ($previous instanceof PDOException) {\n            $this->errorInfo = $previous->errorInfo;\n        }\n    }\n\n    /**\n     * Format the SQL error message.\n     *\n     * @param  string  $sql\n     * @param  array  $bindings\n     * @param  \\Throwable  $previous\n     * @return string\n     */\n    protected function formatMessage($sql, $bindings, Throwable $previous)\n    {\n        return $previous->getMessage().' (SQL: '.Str::replaceArray('?', $bindings, $sql).')';\n    }\n\n    /**\n     * Get the SQL for the query.\n     *\n     * @return string\n     */\n    public function getSql()\n    {\n        return $this->sql;\n    }\n\n    /**\n     * Get the bindings for the query.\n     *\n     * @return array\n     */\n    public function getBindings()\n    {\n        return $this->bindings;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/README.md",
    "content": "## Illuminate Database\n\nThe Illuminate Database component is a full database toolkit for PHP, providing an expressive query builder, ActiveRecord style ORM, and schema builder. It currently supports MySQL, Postgres, SQL Server, and SQLite. It also serves as the database layer of the Laravel PHP framework.\n\n### Usage Instructions\n\nFirst, create a new \"Capsule\" manager instance. Capsule aims to make configuring the library for usage outside of the Laravel framework as easy as possible.\n\n```PHP\nuse Illuminate\\Database\\Capsule\\Manager as Capsule;\n\n$capsule = new Capsule;\n\n$capsule->addConnection([\n    'driver' => 'mysql',\n    'host' => 'localhost',\n    'database' => 'database',\n    'username' => 'root',\n    'password' => 'password',\n    'charset' => 'utf8',\n    'collation' => 'utf8_unicode_ci',\n    'prefix' => '',\n]);\n\n// Set the event dispatcher used by Eloquent models... (optional)\nuse Illuminate\\Events\\Dispatcher;\nuse Illuminate\\Container\\Container;\n$capsule->setEventDispatcher(new Dispatcher(new Container));\n\n// Make this Capsule instance available globally via static methods... (optional)\n$capsule->setAsGlobal();\n\n// Setup the Eloquent ORM... (optional; unless you've used setEventDispatcher())\n$capsule->bootEloquent();\n```\n\n> `composer require \"illuminate/events\"` required when you need to use observers with Eloquent.\n\nOnce the Capsule instance has been registered. You may use it like so:\n\n**Using The Query Builder**\n\n```PHP\n$users = Capsule::table('users')->where('votes', '>', 100)->get();\n```\nOther core methods may be accessed directly from the Capsule in the same manner as from the DB facade:\n```PHP\n$results = Capsule::select('select * from users where id = ?', [1]);\n```\n\n**Using The Schema Builder**\n\n```PHP\nCapsule::schema()->create('users', function ($table) {\n    $table->increments('id');\n    $table->string('email')->unique();\n    $table->timestamps();\n});\n```\n\n**Using The Eloquent ORM**\n\n```PHP\nclass User extends Illuminate\\Database\\Eloquent\\Model {}\n\n$users = User::where('votes', '>', 1)->get();\n```\n\nFor further documentation on using the various database facilities this library provides, consult the [Laravel framework documentation](https://laravel.com/docs).\n"
  },
  {
    "path": "server/vendor/illuminate/database/RecordsNotFoundException.php",
    "content": "<?php\n\nnamespace Illuminate\\Database;\n\nuse RuntimeException;\n\nclass RecordsNotFoundException extends RuntimeException\n{\n    //\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/SQLiteConnection.php",
    "content": "<?php\n\nnamespace Illuminate\\Database;\n\nuse Doctrine\\DBAL\\Driver\\PDOSqlite\\Driver as DoctrineDriver;\nuse Doctrine\\DBAL\\Version;\nuse Illuminate\\Database\\PDO\\SQLiteDriver;\nuse Illuminate\\Database\\Query\\Grammars\\SQLiteGrammar as QueryGrammar;\nuse Illuminate\\Database\\Query\\Processors\\SQLiteProcessor;\nuse Illuminate\\Database\\Schema\\Grammars\\SQLiteGrammar as SchemaGrammar;\nuse Illuminate\\Database\\Schema\\SQLiteBuilder;\nuse Illuminate\\Database\\Schema\\SqliteSchemaState;\nuse Illuminate\\Filesystem\\Filesystem;\n\nclass SQLiteConnection extends Connection\n{\n    /**\n     * Create a new database connection instance.\n     *\n     * @param  \\PDO|\\Closure  $pdo\n     * @param  string  $database\n     * @param  string  $tablePrefix\n     * @param  array  $config\n     * @return void\n     */\n    public function __construct($pdo, $database = '', $tablePrefix = '', array $config = [])\n    {\n        parent::__construct($pdo, $database, $tablePrefix, $config);\n\n        $enableForeignKeyConstraints = $this->getForeignKeyConstraintsConfigurationValue();\n\n        if ($enableForeignKeyConstraints === null) {\n            return;\n        }\n\n        $enableForeignKeyConstraints\n            ? $this->getSchemaBuilder()->enableForeignKeyConstraints()\n            : $this->getSchemaBuilder()->disableForeignKeyConstraints();\n    }\n\n    /**\n     * Get the default query grammar instance.\n     *\n     * @return \\Illuminate\\Database\\Query\\Grammars\\SQLiteGrammar\n     */\n    protected function getDefaultQueryGrammar()\n    {\n        return $this->withTablePrefix(new QueryGrammar);\n    }\n\n    /**\n     * Get a schema builder instance for the connection.\n     *\n     * @return \\Illuminate\\Database\\Schema\\SQLiteBuilder\n     */\n    public function getSchemaBuilder()\n    {\n        if (is_null($this->schemaGrammar)) {\n            $this->useDefaultSchemaGrammar();\n        }\n\n        return new SQLiteBuilder($this);\n    }\n\n    /**\n     * Get the default schema grammar instance.\n     *\n     * @return \\Illuminate\\Database\\Schema\\Grammars\\SQLiteGrammar\n     */\n    protected function getDefaultSchemaGrammar()\n    {\n        return $this->withTablePrefix(new SchemaGrammar);\n    }\n\n    /**\n     * Get the schema state for the connection.\n     *\n     * @param  \\Illuminate\\Filesystem\\Filesystem|null  $files\n     * @param  callable|null  $processFactory\n     *\n     * @throws \\RuntimeException\n     */\n    public function getSchemaState(Filesystem $files = null, callable $processFactory = null)\n    {\n        return new SqliteSchemaState($this, $files, $processFactory);\n    }\n\n    /**\n     * Get the default post processor instance.\n     *\n     * @return \\Illuminate\\Database\\Query\\Processors\\SQLiteProcessor\n     */\n    protected function getDefaultPostProcessor()\n    {\n        return new SQLiteProcessor;\n    }\n\n    /**\n     * Get the Doctrine DBAL driver.\n     *\n     * @return \\Doctrine\\DBAL\\Driver\\PDOSqlite\\Driver|\\Illuminate\\Database\\PDO\\SQLiteDriver\n     */\n    protected function getDoctrineDriver()\n    {\n        return class_exists(Version::class) ? new DoctrineDriver : new SQLiteDriver;\n    }\n\n    /**\n     * Get the database connection foreign key constraints configuration option.\n     *\n     * @return bool|null\n     */\n    protected function getForeignKeyConstraintsConfigurationValue()\n    {\n        return $this->getConfig('foreign_key_constraints');\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Schema/Blueprint.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Schema;\n\nuse BadMethodCallException;\nuse Closure;\nuse Illuminate\\Database\\Connection;\nuse Illuminate\\Database\\Query\\Expression;\nuse Illuminate\\Database\\Schema\\Grammars\\Grammar;\nuse Illuminate\\Database\\SQLiteConnection;\nuse Illuminate\\Support\\Fluent;\nuse Illuminate\\Support\\Traits\\Macroable;\n\nclass Blueprint\n{\n    use Macroable;\n\n    /**\n     * The table the blueprint describes.\n     *\n     * @var string\n     */\n    protected $table;\n\n    /**\n     * The prefix of the table.\n     *\n     * @var string\n     */\n    protected $prefix;\n\n    /**\n     * The columns that should be added to the table.\n     *\n     * @var \\Illuminate\\Database\\Schema\\ColumnDefinition[]\n     */\n    protected $columns = [];\n\n    /**\n     * The commands that should be run for the table.\n     *\n     * @var \\Illuminate\\Support\\Fluent[]\n     */\n    protected $commands = [];\n\n    /**\n     * The storage engine that should be used for the table.\n     *\n     * @var string\n     */\n    public $engine;\n\n    /**\n     * The default character set that should be used for the table.\n     *\n     * @var string\n     */\n    public $charset;\n\n    /**\n     * The collation that should be used for the table.\n     *\n     * @var string\n     */\n    public $collation;\n\n    /**\n     * Whether to make the table temporary.\n     *\n     * @var bool\n     */\n    public $temporary = false;\n\n    /**\n     * The column to add new columns after.\n     *\n     * @var string\n     */\n    public $after;\n\n    /**\n     * Create a new schema blueprint.\n     *\n     * @param  string  $table\n     * @param  \\Closure|null  $callback\n     * @param  string  $prefix\n     * @return void\n     */\n    public function __construct($table, Closure $callback = null, $prefix = '')\n    {\n        $this->table = $table;\n        $this->prefix = $prefix;\n\n        if (! is_null($callback)) {\n            $callback($this);\n        }\n    }\n\n    /**\n     * Execute the blueprint against the database.\n     *\n     * @param  \\Illuminate\\Database\\Connection  $connection\n     * @param  \\Illuminate\\Database\\Schema\\Grammars\\Grammar  $grammar\n     * @return void\n     */\n    public function build(Connection $connection, Grammar $grammar)\n    {\n        foreach ($this->toSql($connection, $grammar) as $statement) {\n            $connection->statement($statement);\n        }\n    }\n\n    /**\n     * Get the raw SQL statements for the blueprint.\n     *\n     * @param  \\Illuminate\\Database\\Connection  $connection\n     * @param  \\Illuminate\\Database\\Schema\\Grammars\\Grammar  $grammar\n     * @return array\n     */\n    public function toSql(Connection $connection, Grammar $grammar)\n    {\n        $this->addImpliedCommands($grammar);\n\n        $statements = [];\n\n        // Each type of command has a corresponding compiler function on the schema\n        // grammar which is used to build the necessary SQL statements to build\n        // the blueprint element, so we'll just call that compilers function.\n        $this->ensureCommandsAreValid($connection);\n\n        foreach ($this->commands as $command) {\n            $method = 'compile'.ucfirst($command->name);\n\n            if (method_exists($grammar, $method) || $grammar::hasMacro($method)) {\n                if (! is_null($sql = $grammar->$method($this, $command, $connection))) {\n                    $statements = array_merge($statements, (array) $sql);\n                }\n            }\n        }\n\n        return $statements;\n    }\n\n    /**\n     * Ensure the commands on the blueprint are valid for the connection type.\n     *\n     * @param  \\Illuminate\\Database\\Connection  $connection\n     * @return void\n     *\n     * @throws \\BadMethodCallException\n     */\n    protected function ensureCommandsAreValid(Connection $connection)\n    {\n        if ($connection instanceof SQLiteConnection) {\n            if ($this->commandsNamed(['dropColumn', 'renameColumn'])->count() > 1) {\n                throw new BadMethodCallException(\n                    \"SQLite doesn't support multiple calls to dropColumn / renameColumn in a single modification.\"\n                );\n            }\n\n            if ($this->commandsNamed(['dropForeign'])->count() > 0) {\n                throw new BadMethodCallException(\n                    \"SQLite doesn't support dropping foreign keys (you would need to re-create the table).\"\n                );\n            }\n        }\n    }\n\n    /**\n     * Get all of the commands matching the given names.\n     *\n     * @param  array  $names\n     * @return \\Illuminate\\Support\\Collection\n     */\n    protected function commandsNamed(array $names)\n    {\n        return collect($this->commands)->filter(function ($command) use ($names) {\n            return in_array($command->name, $names);\n        });\n    }\n\n    /**\n     * Add the commands that are implied by the blueprint's state.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Grammars\\Grammar  $grammar\n     * @return void\n     */\n    protected function addImpliedCommands(Grammar $grammar)\n    {\n        if (count($this->getAddedColumns()) > 0 && ! $this->creating()) {\n            array_unshift($this->commands, $this->createCommand('add'));\n        }\n\n        if (count($this->getChangedColumns()) > 0 && ! $this->creating()) {\n            array_unshift($this->commands, $this->createCommand('change'));\n        }\n\n        $this->addFluentIndexes();\n\n        $this->addFluentCommands($grammar);\n    }\n\n    /**\n     * Add the index commands fluently specified on columns.\n     *\n     * @return void\n     */\n    protected function addFluentIndexes()\n    {\n        foreach ($this->columns as $column) {\n            foreach (['primary', 'unique', 'index', 'fulltext', 'fullText', 'spatialIndex'] as $index) {\n                // If the index has been specified on the given column, but is simply equal\n                // to \"true\" (boolean), no name has been specified for this index so the\n                // index method can be called without a name and it will generate one.\n                if ($column->{$index} === true) {\n                    $this->{$index}($column->name);\n                    $column->{$index} = false;\n\n                    continue 2;\n                }\n\n                // If the index has been specified on the given column, and it has a string\n                // value, we'll go ahead and call the index method and pass the name for\n                // the index since the developer specified the explicit name for this.\n                elseif (isset($column->{$index})) {\n                    $this->{$index}($column->name, $column->{$index});\n                    $column->{$index} = false;\n\n                    continue 2;\n                }\n            }\n        }\n    }\n\n    /**\n     * Add the fluent commands specified on any columns.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Grammars\\Grammar  $grammar\n     * @return void\n     */\n    public function addFluentCommands(Grammar $grammar)\n    {\n        foreach ($this->columns as $column) {\n            foreach ($grammar->getFluentCommands() as $commandName) {\n                $attributeName = lcfirst($commandName);\n\n                if (! isset($column->{$attributeName})) {\n                    continue;\n                }\n\n                $value = $column->{$attributeName};\n\n                $this->addCommand(\n                    $commandName, compact('value', 'column')\n                );\n            }\n        }\n    }\n\n    /**\n     * Determine if the blueprint has a create command.\n     *\n     * @return bool\n     */\n    public function creating()\n    {\n        return collect($this->commands)->contains(function ($command) {\n            return $command->name === 'create';\n        });\n    }\n\n    /**\n     * Indicate that the table needs to be created.\n     *\n     * @return \\Illuminate\\Support\\Fluent\n     */\n    public function create()\n    {\n        return $this->addCommand('create');\n    }\n\n    /**\n     * Indicate that the table needs to be temporary.\n     *\n     * @return void\n     */\n    public function temporary()\n    {\n        $this->temporary = true;\n    }\n\n    /**\n     * Indicate that the table should be dropped.\n     *\n     * @return \\Illuminate\\Support\\Fluent\n     */\n    public function drop()\n    {\n        return $this->addCommand('drop');\n    }\n\n    /**\n     * Indicate that the table should be dropped if it exists.\n     *\n     * @return \\Illuminate\\Support\\Fluent\n     */\n    public function dropIfExists()\n    {\n        return $this->addCommand('dropIfExists');\n    }\n\n    /**\n     * Indicate that the given columns should be dropped.\n     *\n     * @param  array|mixed  $columns\n     * @return \\Illuminate\\Support\\Fluent\n     */\n    public function dropColumn($columns)\n    {\n        $columns = is_array($columns) ? $columns : func_get_args();\n\n        return $this->addCommand('dropColumn', compact('columns'));\n    }\n\n    /**\n     * Indicate that the given columns should be renamed.\n     *\n     * @param  string  $from\n     * @param  string  $to\n     * @return \\Illuminate\\Support\\Fluent\n     */\n    public function renameColumn($from, $to)\n    {\n        return $this->addCommand('renameColumn', compact('from', 'to'));\n    }\n\n    /**\n     * Indicate that the given primary key should be dropped.\n     *\n     * @param  string|array|null  $index\n     * @return \\Illuminate\\Support\\Fluent\n     */\n    public function dropPrimary($index = null)\n    {\n        return $this->dropIndexCommand('dropPrimary', 'primary', $index);\n    }\n\n    /**\n     * Indicate that the given unique key should be dropped.\n     *\n     * @param  string|array  $index\n     * @return \\Illuminate\\Support\\Fluent\n     */\n    public function dropUnique($index)\n    {\n        return $this->dropIndexCommand('dropUnique', 'unique', $index);\n    }\n\n    /**\n     * Indicate that the given index should be dropped.\n     *\n     * @param  string|array  $index\n     * @return \\Illuminate\\Support\\Fluent\n     */\n    public function dropIndex($index)\n    {\n        return $this->dropIndexCommand('dropIndex', 'index', $index);\n    }\n\n    /**\n     * Indicate that the given fulltext index should be dropped.\n     *\n     * @param  string|array  $index\n     * @return \\Illuminate\\Support\\Fluent\n     */\n    public function dropFullText($index)\n    {\n        return $this->dropIndexCommand('dropFullText', 'fulltext', $index);\n    }\n\n    /**\n     * Indicate that the given spatial index should be dropped.\n     *\n     * @param  string|array  $index\n     * @return \\Illuminate\\Support\\Fluent\n     */\n    public function dropSpatialIndex($index)\n    {\n        return $this->dropIndexCommand('dropSpatialIndex', 'spatialIndex', $index);\n    }\n\n    /**\n     * Indicate that the given foreign key should be dropped.\n     *\n     * @param  string|array  $index\n     * @return \\Illuminate\\Support\\Fluent\n     */\n    public function dropForeign($index)\n    {\n        return $this->dropIndexCommand('dropForeign', 'foreign', $index);\n    }\n\n    /**\n     * Indicate that the given column and foreign key should be dropped.\n     *\n     * @param  string  $column\n     * @return \\Illuminate\\Support\\Fluent\n     */\n    public function dropConstrainedForeignId($column)\n    {\n        $this->dropForeign([$column]);\n\n        return $this->dropColumn($column);\n    }\n\n    /**\n     * Indicate that the given indexes should be renamed.\n     *\n     * @param  string  $from\n     * @param  string  $to\n     * @return \\Illuminate\\Support\\Fluent\n     */\n    public function renameIndex($from, $to)\n    {\n        return $this->addCommand('renameIndex', compact('from', 'to'));\n    }\n\n    /**\n     * Indicate that the timestamp columns should be dropped.\n     *\n     * @return void\n     */\n    public function dropTimestamps()\n    {\n        $this->dropColumn('created_at', 'updated_at');\n    }\n\n    /**\n     * Indicate that the timestamp columns should be dropped.\n     *\n     * @return void\n     */\n    public function dropTimestampsTz()\n    {\n        $this->dropTimestamps();\n    }\n\n    /**\n     * Indicate that the soft delete column should be dropped.\n     *\n     * @param  string  $column\n     * @return void\n     */\n    public function dropSoftDeletes($column = 'deleted_at')\n    {\n        $this->dropColumn($column);\n    }\n\n    /**\n     * Indicate that the soft delete column should be dropped.\n     *\n     * @param  string  $column\n     * @return void\n     */\n    public function dropSoftDeletesTz($column = 'deleted_at')\n    {\n        $this->dropSoftDeletes($column);\n    }\n\n    /**\n     * Indicate that the remember token column should be dropped.\n     *\n     * @return void\n     */\n    public function dropRememberToken()\n    {\n        $this->dropColumn('remember_token');\n    }\n\n    /**\n     * Indicate that the polymorphic columns should be dropped.\n     *\n     * @param  string  $name\n     * @param  string|null  $indexName\n     * @return void\n     */\n    public function dropMorphs($name, $indexName = null)\n    {\n        $this->dropIndex($indexName ?: $this->createIndexName('index', [\"{$name}_type\", \"{$name}_id\"]));\n\n        $this->dropColumn(\"{$name}_type\", \"{$name}_id\");\n    }\n\n    /**\n     * Rename the table to a given name.\n     *\n     * @param  string  $to\n     * @return \\Illuminate\\Support\\Fluent\n     */\n    public function rename($to)\n    {\n        return $this->addCommand('rename', compact('to'));\n    }\n\n    /**\n     * Specify the primary key(s) for the table.\n     *\n     * @param  string|array  $columns\n     * @param  string|null  $name\n     * @param  string|null  $algorithm\n     * @return \\Illuminate\\Support\\Fluent\n     */\n    public function primary($columns, $name = null, $algorithm = null)\n    {\n        return $this->indexCommand('primary', $columns, $name, $algorithm);\n    }\n\n    /**\n     * Specify a unique index for the table.\n     *\n     * @param  string|array  $columns\n     * @param  string|null  $name\n     * @param  string|null  $algorithm\n     * @return \\Illuminate\\Support\\Fluent\n     */\n    public function unique($columns, $name = null, $algorithm = null)\n    {\n        return $this->indexCommand('unique', $columns, $name, $algorithm);\n    }\n\n    /**\n     * Specify an index for the table.\n     *\n     * @param  string|array  $columns\n     * @param  string|null  $name\n     * @param  string|null  $algorithm\n     * @return \\Illuminate\\Support\\Fluent\n     */\n    public function index($columns, $name = null, $algorithm = null)\n    {\n        return $this->indexCommand('index', $columns, $name, $algorithm);\n    }\n\n    /**\n     * Specify an fulltext for the table.\n     *\n     * @param  string|array  $columns\n     * @param  string|null  $name\n     * @param  string|null  $algorithm\n     * @return \\Illuminate\\Support\\Fluent\n     */\n    public function fullText($columns, $name = null, $algorithm = null)\n    {\n        return $this->indexCommand('fulltext', $columns, $name, $algorithm);\n    }\n\n    /**\n     * Specify a spatial index for the table.\n     *\n     * @param  string|array  $columns\n     * @param  string|null  $name\n     * @return \\Illuminate\\Support\\Fluent\n     */\n    public function spatialIndex($columns, $name = null)\n    {\n        return $this->indexCommand('spatialIndex', $columns, $name);\n    }\n\n    /**\n     * Specify a raw index for the table.\n     *\n     * @param  string  $expression\n     * @param  string  $name\n     * @return \\Illuminate\\Support\\Fluent\n     */\n    public function rawIndex($expression, $name)\n    {\n        return $this->index([new Expression($expression)], $name);\n    }\n\n    /**\n     * Specify a foreign key for the table.\n     *\n     * @param  string|array  $columns\n     * @param  string|null  $name\n     * @return \\Illuminate\\Database\\Schema\\ForeignKeyDefinition\n     */\n    public function foreign($columns, $name = null)\n    {\n        $command = new ForeignKeyDefinition(\n            $this->indexCommand('foreign', $columns, $name)->getAttributes()\n        );\n\n        $this->commands[count($this->commands) - 1] = $command;\n\n        return $command;\n    }\n\n    /**\n     * Create a new auto-incrementing big integer (8-byte) column on the table.\n     *\n     * @param  string  $column\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function id($column = 'id')\n    {\n        return $this->bigIncrements($column);\n    }\n\n    /**\n     * Create a new auto-incrementing integer (4-byte) column on the table.\n     *\n     * @param  string  $column\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function increments($column)\n    {\n        return $this->unsignedInteger($column, true);\n    }\n\n    /**\n     * Create a new auto-incrementing integer (4-byte) column on the table.\n     *\n     * @param  string  $column\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function integerIncrements($column)\n    {\n        return $this->unsignedInteger($column, true);\n    }\n\n    /**\n     * Create a new auto-incrementing tiny integer (1-byte) column on the table.\n     *\n     * @param  string  $column\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function tinyIncrements($column)\n    {\n        return $this->unsignedTinyInteger($column, true);\n    }\n\n    /**\n     * Create a new auto-incrementing small integer (2-byte) column on the table.\n     *\n     * @param  string  $column\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function smallIncrements($column)\n    {\n        return $this->unsignedSmallInteger($column, true);\n    }\n\n    /**\n     * Create a new auto-incrementing medium integer (3-byte) column on the table.\n     *\n     * @param  string  $column\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function mediumIncrements($column)\n    {\n        return $this->unsignedMediumInteger($column, true);\n    }\n\n    /**\n     * Create a new auto-incrementing big integer (8-byte) column on the table.\n     *\n     * @param  string  $column\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function bigIncrements($column)\n    {\n        return $this->unsignedBigInteger($column, true);\n    }\n\n    /**\n     * Create a new char column on the table.\n     *\n     * @param  string  $column\n     * @param  int|null  $length\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function char($column, $length = null)\n    {\n        $length = $length ?: Builder::$defaultStringLength;\n\n        return $this->addColumn('char', $column, compact('length'));\n    }\n\n    /**\n     * Create a new string column on the table.\n     *\n     * @param  string  $column\n     * @param  int|null  $length\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function string($column, $length = null)\n    {\n        $length = $length ?: Builder::$defaultStringLength;\n\n        return $this->addColumn('string', $column, compact('length'));\n    }\n\n    /**\n     * Create a new tiny text column on the table.\n     *\n     * @param  string  $column\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function tinyText($column)\n    {\n        return $this->addColumn('tinyText', $column);\n    }\n\n    /**\n     * Create a new text column on the table.\n     *\n     * @param  string  $column\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function text($column)\n    {\n        return $this->addColumn('text', $column);\n    }\n\n    /**\n     * Create a new medium text column on the table.\n     *\n     * @param  string  $column\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function mediumText($column)\n    {\n        return $this->addColumn('mediumText', $column);\n    }\n\n    /**\n     * Create a new long text column on the table.\n     *\n     * @param  string  $column\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function longText($column)\n    {\n        return $this->addColumn('longText', $column);\n    }\n\n    /**\n     * Create a new integer (4-byte) column on the table.\n     *\n     * @param  string  $column\n     * @param  bool  $autoIncrement\n     * @param  bool  $unsigned\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function integer($column, $autoIncrement = false, $unsigned = false)\n    {\n        return $this->addColumn('integer', $column, compact('autoIncrement', 'unsigned'));\n    }\n\n    /**\n     * Create a new tiny integer (1-byte) column on the table.\n     *\n     * @param  string  $column\n     * @param  bool  $autoIncrement\n     * @param  bool  $unsigned\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function tinyInteger($column, $autoIncrement = false, $unsigned = false)\n    {\n        return $this->addColumn('tinyInteger', $column, compact('autoIncrement', 'unsigned'));\n    }\n\n    /**\n     * Create a new small integer (2-byte) column on the table.\n     *\n     * @param  string  $column\n     * @param  bool  $autoIncrement\n     * @param  bool  $unsigned\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function smallInteger($column, $autoIncrement = false, $unsigned = false)\n    {\n        return $this->addColumn('smallInteger', $column, compact('autoIncrement', 'unsigned'));\n    }\n\n    /**\n     * Create a new medium integer (3-byte) column on the table.\n     *\n     * @param  string  $column\n     * @param  bool  $autoIncrement\n     * @param  bool  $unsigned\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function mediumInteger($column, $autoIncrement = false, $unsigned = false)\n    {\n        return $this->addColumn('mediumInteger', $column, compact('autoIncrement', 'unsigned'));\n    }\n\n    /**\n     * Create a new big integer (8-byte) column on the table.\n     *\n     * @param  string  $column\n     * @param  bool  $autoIncrement\n     * @param  bool  $unsigned\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function bigInteger($column, $autoIncrement = false, $unsigned = false)\n    {\n        return $this->addColumn('bigInteger', $column, compact('autoIncrement', 'unsigned'));\n    }\n\n    /**\n     * Create a new unsigned integer (4-byte) column on the table.\n     *\n     * @param  string  $column\n     * @param  bool  $autoIncrement\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function unsignedInteger($column, $autoIncrement = false)\n    {\n        return $this->integer($column, $autoIncrement, true);\n    }\n\n    /**\n     * Create a new unsigned tiny integer (1-byte) column on the table.\n     *\n     * @param  string  $column\n     * @param  bool  $autoIncrement\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function unsignedTinyInteger($column, $autoIncrement = false)\n    {\n        return $this->tinyInteger($column, $autoIncrement, true);\n    }\n\n    /**\n     * Create a new unsigned small integer (2-byte) column on the table.\n     *\n     * @param  string  $column\n     * @param  bool  $autoIncrement\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function unsignedSmallInteger($column, $autoIncrement = false)\n    {\n        return $this->smallInteger($column, $autoIncrement, true);\n    }\n\n    /**\n     * Create a new unsigned medium integer (3-byte) column on the table.\n     *\n     * @param  string  $column\n     * @param  bool  $autoIncrement\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function unsignedMediumInteger($column, $autoIncrement = false)\n    {\n        return $this->mediumInteger($column, $autoIncrement, true);\n    }\n\n    /**\n     * Create a new unsigned big integer (8-byte) column on the table.\n     *\n     * @param  string  $column\n     * @param  bool  $autoIncrement\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function unsignedBigInteger($column, $autoIncrement = false)\n    {\n        return $this->bigInteger($column, $autoIncrement, true);\n    }\n\n    /**\n     * Create a new unsigned big integer (8-byte) column on the table.\n     *\n     * @param  string  $column\n     * @return \\Illuminate\\Database\\Schema\\ForeignIdColumnDefinition\n     */\n    public function foreignId($column)\n    {\n        return $this->addColumnDefinition(new ForeignIdColumnDefinition($this, [\n            'type' => 'bigInteger',\n            'name' => $column,\n            'autoIncrement' => false,\n            'unsigned' => true,\n        ]));\n    }\n\n    /**\n     * Create a foreign ID column for the given model.\n     *\n     * @param  \\Illuminate\\Database\\Eloquent\\Model|string  $model\n     * @param  string|null  $column\n     * @return \\Illuminate\\Database\\Schema\\ForeignIdColumnDefinition\n     */\n    public function foreignIdFor($model, $column = null)\n    {\n        if (is_string($model)) {\n            $model = new $model;\n        }\n\n        return $model->getKeyType() === 'int' && $model->getIncrementing()\n                    ? $this->foreignId($column ?: $model->getForeignKey())\n                    : $this->foreignUuid($column ?: $model->getForeignKey());\n    }\n\n    /**\n     * Create a new float column on the table.\n     *\n     * @param  string  $column\n     * @param  int  $total\n     * @param  int  $places\n     * @param  bool  $unsigned\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function float($column, $total = 8, $places = 2, $unsigned = false)\n    {\n        return $this->addColumn('float', $column, compact('total', 'places', 'unsigned'));\n    }\n\n    /**\n     * Create a new double column on the table.\n     *\n     * @param  string  $column\n     * @param  int|null  $total\n     * @param  int|null  $places\n     * @param  bool  $unsigned\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function double($column, $total = null, $places = null, $unsigned = false)\n    {\n        return $this->addColumn('double', $column, compact('total', 'places', 'unsigned'));\n    }\n\n    /**\n     * Create a new decimal column on the table.\n     *\n     * @param  string  $column\n     * @param  int  $total\n     * @param  int  $places\n     * @param  bool  $unsigned\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function decimal($column, $total = 8, $places = 2, $unsigned = false)\n    {\n        return $this->addColumn('decimal', $column, compact('total', 'places', 'unsigned'));\n    }\n\n    /**\n     * Create a new unsigned float column on the table.\n     *\n     * @param  string  $column\n     * @param  int  $total\n     * @param  int  $places\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function unsignedFloat($column, $total = 8, $places = 2)\n    {\n        return $this->float($column, $total, $places, true);\n    }\n\n    /**\n     * Create a new unsigned double column on the table.\n     *\n     * @param  string  $column\n     * @param  int  $total\n     * @param  int  $places\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function unsignedDouble($column, $total = null, $places = null)\n    {\n        return $this->double($column, $total, $places, true);\n    }\n\n    /**\n     * Create a new unsigned decimal column on the table.\n     *\n     * @param  string  $column\n     * @param  int  $total\n     * @param  int  $places\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function unsignedDecimal($column, $total = 8, $places = 2)\n    {\n        return $this->decimal($column, $total, $places, true);\n    }\n\n    /**\n     * Create a new boolean column on the table.\n     *\n     * @param  string  $column\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function boolean($column)\n    {\n        return $this->addColumn('boolean', $column);\n    }\n\n    /**\n     * Create a new enum column on the table.\n     *\n     * @param  string  $column\n     * @param  array  $allowed\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function enum($column, array $allowed)\n    {\n        return $this->addColumn('enum', $column, compact('allowed'));\n    }\n\n    /**\n     * Create a new set column on the table.\n     *\n     * @param  string  $column\n     * @param  array  $allowed\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function set($column, array $allowed)\n    {\n        return $this->addColumn('set', $column, compact('allowed'));\n    }\n\n    /**\n     * Create a new json column on the table.\n     *\n     * @param  string  $column\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function json($column)\n    {\n        return $this->addColumn('json', $column);\n    }\n\n    /**\n     * Create a new jsonb column on the table.\n     *\n     * @param  string  $column\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function jsonb($column)\n    {\n        return $this->addColumn('jsonb', $column);\n    }\n\n    /**\n     * Create a new date column on the table.\n     *\n     * @param  string  $column\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function date($column)\n    {\n        return $this->addColumn('date', $column);\n    }\n\n    /**\n     * Create a new date-time column on the table.\n     *\n     * @param  string  $column\n     * @param  int  $precision\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function dateTime($column, $precision = 0)\n    {\n        return $this->addColumn('dateTime', $column, compact('precision'));\n    }\n\n    /**\n     * Create a new date-time column (with time zone) on the table.\n     *\n     * @param  string  $column\n     * @param  int  $precision\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function dateTimeTz($column, $precision = 0)\n    {\n        return $this->addColumn('dateTimeTz', $column, compact('precision'));\n    }\n\n    /**\n     * Create a new time column on the table.\n     *\n     * @param  string  $column\n     * @param  int  $precision\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function time($column, $precision = 0)\n    {\n        return $this->addColumn('time', $column, compact('precision'));\n    }\n\n    /**\n     * Create a new time column (with time zone) on the table.\n     *\n     * @param  string  $column\n     * @param  int  $precision\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function timeTz($column, $precision = 0)\n    {\n        return $this->addColumn('timeTz', $column, compact('precision'));\n    }\n\n    /**\n     * Create a new timestamp column on the table.\n     *\n     * @param  string  $column\n     * @param  int  $precision\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function timestamp($column, $precision = 0)\n    {\n        return $this->addColumn('timestamp', $column, compact('precision'));\n    }\n\n    /**\n     * Create a new timestamp (with time zone) column on the table.\n     *\n     * @param  string  $column\n     * @param  int  $precision\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function timestampTz($column, $precision = 0)\n    {\n        return $this->addColumn('timestampTz', $column, compact('precision'));\n    }\n\n    /**\n     * Add nullable creation and update timestamps to the table.\n     *\n     * @param  int  $precision\n     * @return void\n     */\n    public function timestamps($precision = 0)\n    {\n        $this->timestamp('created_at', $precision)->nullable();\n\n        $this->timestamp('updated_at', $precision)->nullable();\n    }\n\n    /**\n     * Add nullable creation and update timestamps to the table.\n     *\n     * Alias for self::timestamps().\n     *\n     * @param  int  $precision\n     * @return void\n     */\n    public function nullableTimestamps($precision = 0)\n    {\n        $this->timestamps($precision);\n    }\n\n    /**\n     * Add creation and update timestampTz columns to the table.\n     *\n     * @param  int  $precision\n     * @return void\n     */\n    public function timestampsTz($precision = 0)\n    {\n        $this->timestampTz('created_at', $precision)->nullable();\n\n        $this->timestampTz('updated_at', $precision)->nullable();\n    }\n\n    /**\n     * Add a \"deleted at\" timestamp for the table.\n     *\n     * @param  string  $column\n     * @param  int  $precision\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function softDeletes($column = 'deleted_at', $precision = 0)\n    {\n        return $this->timestamp($column, $precision)->nullable();\n    }\n\n    /**\n     * Add a \"deleted at\" timestampTz for the table.\n     *\n     * @param  string  $column\n     * @param  int  $precision\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function softDeletesTz($column = 'deleted_at', $precision = 0)\n    {\n        return $this->timestampTz($column, $precision)->nullable();\n    }\n\n    /**\n     * Create a new year column on the table.\n     *\n     * @param  string  $column\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function year($column)\n    {\n        return $this->addColumn('year', $column);\n    }\n\n    /**\n     * Create a new binary column on the table.\n     *\n     * @param  string  $column\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function binary($column)\n    {\n        return $this->addColumn('binary', $column);\n    }\n\n    /**\n     * Create a new uuid column on the table.\n     *\n     * @param  string  $column\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function uuid($column)\n    {\n        return $this->addColumn('uuid', $column);\n    }\n\n    /**\n     * Create a new UUID column on the table with a foreign key constraint.\n     *\n     * @param  string  $column\n     * @return \\Illuminate\\Database\\Schema\\ForeignIdColumnDefinition\n     */\n    public function foreignUuid($column)\n    {\n        return $this->addColumnDefinition(new ForeignIdColumnDefinition($this, [\n            'type' => 'uuid',\n            'name' => $column,\n        ]));\n    }\n\n    /**\n     * Create a new IP address column on the table.\n     *\n     * @param  string  $column\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function ipAddress($column)\n    {\n        return $this->addColumn('ipAddress', $column);\n    }\n\n    /**\n     * Create a new MAC address column on the table.\n     *\n     * @param  string  $column\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function macAddress($column)\n    {\n        return $this->addColumn('macAddress', $column);\n    }\n\n    /**\n     * Create a new geometry column on the table.\n     *\n     * @param  string  $column\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function geometry($column)\n    {\n        return $this->addColumn('geometry', $column);\n    }\n\n    /**\n     * Create a new point column on the table.\n     *\n     * @param  string  $column\n     * @param  int|null  $srid\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function point($column, $srid = null)\n    {\n        return $this->addColumn('point', $column, compact('srid'));\n    }\n\n    /**\n     * Create a new linestring column on the table.\n     *\n     * @param  string  $column\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function lineString($column)\n    {\n        return $this->addColumn('linestring', $column);\n    }\n\n    /**\n     * Create a new polygon column on the table.\n     *\n     * @param  string  $column\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function polygon($column)\n    {\n        return $this->addColumn('polygon', $column);\n    }\n\n    /**\n     * Create a new geometrycollection column on the table.\n     *\n     * @param  string  $column\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function geometryCollection($column)\n    {\n        return $this->addColumn('geometrycollection', $column);\n    }\n\n    /**\n     * Create a new multipoint column on the table.\n     *\n     * @param  string  $column\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function multiPoint($column)\n    {\n        return $this->addColumn('multipoint', $column);\n    }\n\n    /**\n     * Create a new multilinestring column on the table.\n     *\n     * @param  string  $column\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function multiLineString($column)\n    {\n        return $this->addColumn('multilinestring', $column);\n    }\n\n    /**\n     * Create a new multipolygon column on the table.\n     *\n     * @param  string  $column\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function multiPolygon($column)\n    {\n        return $this->addColumn('multipolygon', $column);\n    }\n\n    /**\n     * Create a new multipolygon column on the table.\n     *\n     * @param  string  $column\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function multiPolygonZ($column)\n    {\n        return $this->addColumn('multipolygonz', $column);\n    }\n\n    /**\n     * Create a new generated, computed column on the table.\n     *\n     * @param  string  $column\n     * @param  string  $expression\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function computed($column, $expression)\n    {\n        return $this->addColumn('computed', $column, compact('expression'));\n    }\n\n    /**\n     * Add the proper columns for a polymorphic table.\n     *\n     * @param  string  $name\n     * @param  string|null  $indexName\n     * @return void\n     */\n    public function morphs($name, $indexName = null)\n    {\n        if (Builder::$defaultMorphKeyType === 'uuid') {\n            $this->uuidMorphs($name, $indexName);\n        } else {\n            $this->numericMorphs($name, $indexName);\n        }\n    }\n\n    /**\n     * Add nullable columns for a polymorphic table.\n     *\n     * @param  string  $name\n     * @param  string|null  $indexName\n     * @return void\n     */\n    public function nullableMorphs($name, $indexName = null)\n    {\n        if (Builder::$defaultMorphKeyType === 'uuid') {\n            $this->nullableUuidMorphs($name, $indexName);\n        } else {\n            $this->nullableNumericMorphs($name, $indexName);\n        }\n    }\n\n    /**\n     * Add the proper columns for a polymorphic table using numeric IDs (incremental).\n     *\n     * @param  string  $name\n     * @param  string|null  $indexName\n     * @return void\n     */\n    public function numericMorphs($name, $indexName = null)\n    {\n        $this->string(\"{$name}_type\");\n\n        $this->unsignedBigInteger(\"{$name}_id\");\n\n        $this->index([\"{$name}_type\", \"{$name}_id\"], $indexName);\n    }\n\n    /**\n     * Add nullable columns for a polymorphic table using numeric IDs (incremental).\n     *\n     * @param  string  $name\n     * @param  string|null  $indexName\n     * @return void\n     */\n    public function nullableNumericMorphs($name, $indexName = null)\n    {\n        $this->string(\"{$name}_type\")->nullable();\n\n        $this->unsignedBigInteger(\"{$name}_id\")->nullable();\n\n        $this->index([\"{$name}_type\", \"{$name}_id\"], $indexName);\n    }\n\n    /**\n     * Add the proper columns for a polymorphic table using UUIDs.\n     *\n     * @param  string  $name\n     * @param  string|null  $indexName\n     * @return void\n     */\n    public function uuidMorphs($name, $indexName = null)\n    {\n        $this->string(\"{$name}_type\");\n\n        $this->uuid(\"{$name}_id\");\n\n        $this->index([\"{$name}_type\", \"{$name}_id\"], $indexName);\n    }\n\n    /**\n     * Add nullable columns for a polymorphic table using UUIDs.\n     *\n     * @param  string  $name\n     * @param  string|null  $indexName\n     * @return void\n     */\n    public function nullableUuidMorphs($name, $indexName = null)\n    {\n        $this->string(\"{$name}_type\")->nullable();\n\n        $this->uuid(\"{$name}_id\")->nullable();\n\n        $this->index([\"{$name}_type\", \"{$name}_id\"], $indexName);\n    }\n\n    /**\n     * Adds the `remember_token` column to the table.\n     *\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function rememberToken()\n    {\n        return $this->string('remember_token', 100)->nullable();\n    }\n\n    /**\n     * Add a new index command to the blueprint.\n     *\n     * @param  string  $type\n     * @param  string|array  $columns\n     * @param  string  $index\n     * @param  string|null  $algorithm\n     * @return \\Illuminate\\Support\\Fluent\n     */\n    protected function indexCommand($type, $columns, $index, $algorithm = null)\n    {\n        $columns = (array) $columns;\n\n        // If no name was specified for this index, we will create one using a basic\n        // convention of the table name, followed by the columns, followed by an\n        // index type, such as primary or index, which makes the index unique.\n        $index = $index ?: $this->createIndexName($type, $columns);\n\n        return $this->addCommand(\n            $type, compact('index', 'columns', 'algorithm')\n        );\n    }\n\n    /**\n     * Create a new drop index command on the blueprint.\n     *\n     * @param  string  $command\n     * @param  string  $type\n     * @param  string|array  $index\n     * @return \\Illuminate\\Support\\Fluent\n     */\n    protected function dropIndexCommand($command, $type, $index)\n    {\n        $columns = [];\n\n        // If the given \"index\" is actually an array of columns, the developer means\n        // to drop an index merely by specifying the columns involved without the\n        // conventional name, so we will build the index name from the columns.\n        if (is_array($index)) {\n            $index = $this->createIndexName($type, $columns = $index);\n        }\n\n        return $this->indexCommand($command, $columns, $index);\n    }\n\n    /**\n     * Create a default index name for the table.\n     *\n     * @param  string  $type\n     * @param  array  $columns\n     * @return string\n     */\n    protected function createIndexName($type, array $columns)\n    {\n        $index = strtolower($this->prefix.$this->table.'_'.implode('_', $columns).'_'.$type);\n\n        return str_replace(['-', '.'], '_', $index);\n    }\n\n    /**\n     * Add a new column to the blueprint.\n     *\n     * @param  string  $type\n     * @param  string  $name\n     * @param  array  $parameters\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    public function addColumn($type, $name, array $parameters = [])\n    {\n        return $this->addColumnDefinition(new ColumnDefinition(\n            array_merge(compact('type', 'name'), $parameters)\n        ));\n    }\n\n    /**\n     * Add a new column definition to the blueprint.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\ColumnDefinition  $definition\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition\n     */\n    protected function addColumnDefinition($definition)\n    {\n        $this->columns[] = $definition;\n\n        if ($this->after) {\n            $definition->after($this->after);\n\n            $this->after = $definition->name;\n        }\n\n        return $definition;\n    }\n\n    /**\n     * Add the columns from the callback after the given column.\n     *\n     * @param  string  $column\n     * @param  \\Closure  $callback\n     * @return void\n     */\n    public function after($column, Closure $callback)\n    {\n        $this->after = $column;\n\n        $callback($this);\n\n        $this->after = null;\n    }\n\n    /**\n     * Remove a column from the schema blueprint.\n     *\n     * @param  string  $name\n     * @return $this\n     */\n    public function removeColumn($name)\n    {\n        $this->columns = array_values(array_filter($this->columns, function ($c) use ($name) {\n            return $c['name'] != $name;\n        }));\n\n        return $this;\n    }\n\n    /**\n     * Add a new command to the blueprint.\n     *\n     * @param  string  $name\n     * @param  array  $parameters\n     * @return \\Illuminate\\Support\\Fluent\n     */\n    protected function addCommand($name, array $parameters = [])\n    {\n        $this->commands[] = $command = $this->createCommand($name, $parameters);\n\n        return $command;\n    }\n\n    /**\n     * Create a new Fluent command.\n     *\n     * @param  string  $name\n     * @param  array  $parameters\n     * @return \\Illuminate\\Support\\Fluent\n     */\n    protected function createCommand($name, array $parameters = [])\n    {\n        return new Fluent(array_merge(compact('name'), $parameters));\n    }\n\n    /**\n     * Get the table the blueprint describes.\n     *\n     * @return string\n     */\n    public function getTable()\n    {\n        return $this->table;\n    }\n\n    /**\n     * Get the columns on the blueprint.\n     *\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition[]\n     */\n    public function getColumns()\n    {\n        return $this->columns;\n    }\n\n    /**\n     * Get the commands on the blueprint.\n     *\n     * @return \\Illuminate\\Support\\Fluent[]\n     */\n    public function getCommands()\n    {\n        return $this->commands;\n    }\n\n    /**\n     * Get the columns on the blueprint that should be added.\n     *\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition[]\n     */\n    public function getAddedColumns()\n    {\n        return array_filter($this->columns, function ($column) {\n            return ! $column->change;\n        });\n    }\n\n    /**\n     * Get the columns on the blueprint that should be changed.\n     *\n     * @return \\Illuminate\\Database\\Schema\\ColumnDefinition[]\n     */\n    public function getChangedColumns()\n    {\n        return array_filter($this->columns, function ($column) {\n            return (bool) $column->change;\n        });\n    }\n\n    /**\n     * Determine if the blueprint has auto-increment columns.\n     *\n     * @return bool\n     */\n    public function hasAutoIncrementColumn()\n    {\n        return ! is_null(collect($this->getAddedColumns())->first(function ($column) {\n            return $column->autoIncrement === true;\n        }));\n    }\n\n    /**\n     * Get the auto-increment column starting values.\n     *\n     * @return array\n     */\n    public function autoIncrementingStartingValues()\n    {\n        if (! $this->hasAutoIncrementColumn()) {\n            return [];\n        }\n\n        return collect($this->getAddedColumns())->mapWithKeys(function ($column) {\n            return $column->autoIncrement === true\n                        ? [$column->name => $column->get('startingValue', $column->get('from'))]\n                        : [$column->name => null];\n        })->filter()->all();\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Schema/Builder.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Schema;\n\nuse Closure;\nuse Illuminate\\Container\\Container;\nuse Illuminate\\Database\\Connection;\nuse InvalidArgumentException;\nuse LogicException;\n\nclass Builder\n{\n    /**\n     * The database connection instance.\n     *\n     * @var \\Illuminate\\Database\\Connection\n     */\n    protected $connection;\n\n    /**\n     * The schema grammar instance.\n     *\n     * @var \\Illuminate\\Database\\Schema\\Grammars\\Grammar\n     */\n    protected $grammar;\n\n    /**\n     * The Blueprint resolver callback.\n     *\n     * @var \\Closure\n     */\n    protected $resolver;\n\n    /**\n     * The default string length for migrations.\n     *\n     * @var int\n     */\n    public static $defaultStringLength = 255;\n\n    /**\n     * The default relationship morph key type.\n     *\n     * @var string\n     */\n    public static $defaultMorphKeyType = 'int';\n\n    /**\n     * Create a new database Schema manager.\n     *\n     * @param  \\Illuminate\\Database\\Connection  $connection\n     * @return void\n     */\n    public function __construct(Connection $connection)\n    {\n        $this->connection = $connection;\n        $this->grammar = $connection->getSchemaGrammar();\n    }\n\n    /**\n     * Set the default string length for migrations.\n     *\n     * @param  int  $length\n     * @return void\n     */\n    public static function defaultStringLength($length)\n    {\n        static::$defaultStringLength = $length;\n    }\n\n    /**\n     * Set the default morph key type for migrations.\n     *\n     * @param  string  $type\n     * @return void\n     *\n     * @throws \\InvalidArgumentException\n     */\n    public static function defaultMorphKeyType(string $type)\n    {\n        if (! in_array($type, ['int', 'uuid'])) {\n            throw new InvalidArgumentException(\"Morph key type must be 'int' or 'uuid'.\");\n        }\n\n        static::$defaultMorphKeyType = $type;\n    }\n\n    /**\n     * Set the default morph key type for migrations to UUIDs.\n     *\n     * @return void\n     */\n    public static function morphUsingUuids()\n    {\n        return static::defaultMorphKeyType('uuid');\n    }\n\n    /**\n     * Create a database in the schema.\n     *\n     * @param  string  $name\n     * @return bool\n     *\n     * @throws \\LogicException\n     */\n    public function createDatabase($name)\n    {\n        throw new LogicException('This database driver does not support creating databases.');\n    }\n\n    /**\n     * Drop a database from the schema if the database exists.\n     *\n     * @param  string  $name\n     * @return bool\n     *\n     * @throws \\LogicException\n     */\n    public function dropDatabaseIfExists($name)\n    {\n        throw new LogicException('This database driver does not support dropping databases.');\n    }\n\n    /**\n     * Determine if the given table exists.\n     *\n     * @param  string  $table\n     * @return bool\n     */\n    public function hasTable($table)\n    {\n        $table = $this->connection->getTablePrefix().$table;\n\n        return count($this->connection->selectFromWriteConnection(\n            $this->grammar->compileTableExists(), [$table]\n        )) > 0;\n    }\n\n    /**\n     * Determine if the given table has a given column.\n     *\n     * @param  string  $table\n     * @param  string  $column\n     * @return bool\n     */\n    public function hasColumn($table, $column)\n    {\n        return in_array(\n            strtolower($column), array_map('strtolower', $this->getColumnListing($table))\n        );\n    }\n\n    /**\n     * Determine if the given table has given columns.\n     *\n     * @param  string  $table\n     * @param  array  $columns\n     * @return bool\n     */\n    public function hasColumns($table, array $columns)\n    {\n        $tableColumns = array_map('strtolower', $this->getColumnListing($table));\n\n        foreach ($columns as $column) {\n            if (! in_array(strtolower($column), $tableColumns)) {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    /**\n     * Get the data type for the given column name.\n     *\n     * @param  string  $table\n     * @param  string  $column\n     * @return string\n     */\n    public function getColumnType($table, $column)\n    {\n        $table = $this->connection->getTablePrefix().$table;\n\n        return $this->connection->getDoctrineColumn($table, $column)->getType()->getName();\n    }\n\n    /**\n     * Get the column listing for a given table.\n     *\n     * @param  string  $table\n     * @return array\n     */\n    public function getColumnListing($table)\n    {\n        $results = $this->connection->selectFromWriteConnection($this->grammar->compileColumnListing(\n            $this->connection->getTablePrefix().$table\n        ));\n\n        return $this->connection->getPostProcessor()->processColumnListing($results);\n    }\n\n    /**\n     * Modify a table on the schema.\n     *\n     * @param  string  $table\n     * @param  \\Closure  $callback\n     * @return void\n     */\n    public function table($table, Closure $callback)\n    {\n        $this->build($this->createBlueprint($table, $callback));\n    }\n\n    /**\n     * Create a new table on the schema.\n     *\n     * @param  string  $table\n     * @param  \\Closure  $callback\n     * @return void\n     */\n    public function create($table, Closure $callback)\n    {\n        $this->build(tap($this->createBlueprint($table), function ($blueprint) use ($callback) {\n            $blueprint->create();\n\n            $callback($blueprint);\n        }));\n    }\n\n    /**\n     * Drop a table from the schema.\n     *\n     * @param  string  $table\n     * @return void\n     */\n    public function drop($table)\n    {\n        $this->build(tap($this->createBlueprint($table), function ($blueprint) {\n            $blueprint->drop();\n        }));\n    }\n\n    /**\n     * Drop a table from the schema if it exists.\n     *\n     * @param  string  $table\n     * @return void\n     */\n    public function dropIfExists($table)\n    {\n        $this->build(tap($this->createBlueprint($table), function ($blueprint) {\n            $blueprint->dropIfExists();\n        }));\n    }\n\n    /**\n     * Drop columns from a table schema.\n     *\n     * @param  string  $table\n     * @param  string|array  $columns\n     * @return void\n     */\n    public function dropColumns($table, $columns)\n    {\n        $this->table($table, function (Blueprint $blueprint) use ($columns) {\n            $blueprint->dropColumn($columns);\n        });\n    }\n\n    /**\n     * Drop all tables from the database.\n     *\n     * @return void\n     *\n     * @throws \\LogicException\n     */\n    public function dropAllTables()\n    {\n        throw new LogicException('This database driver does not support dropping all tables.');\n    }\n\n    /**\n     * Drop all views from the database.\n     *\n     * @return void\n     *\n     * @throws \\LogicException\n     */\n    public function dropAllViews()\n    {\n        throw new LogicException('This database driver does not support dropping all views.');\n    }\n\n    /**\n     * Drop all types from the database.\n     *\n     * @return void\n     *\n     * @throws \\LogicException\n     */\n    public function dropAllTypes()\n    {\n        throw new LogicException('This database driver does not support dropping all types.');\n    }\n\n    /**\n     * Get all of the table names for the database.\n     *\n     * @return void\n     *\n     * @throws \\LogicException\n     */\n    public function getAllTables()\n    {\n        throw new LogicException('This database driver does not support getting all tables.');\n    }\n\n    /**\n     * Rename a table on the schema.\n     *\n     * @param  string  $from\n     * @param  string  $to\n     * @return void\n     */\n    public function rename($from, $to)\n    {\n        $this->build(tap($this->createBlueprint($from), function ($blueprint) use ($to) {\n            $blueprint->rename($to);\n        }));\n    }\n\n    /**\n     * Enable foreign key constraints.\n     *\n     * @return bool\n     */\n    public function enableForeignKeyConstraints()\n    {\n        return $this->connection->statement(\n            $this->grammar->compileEnableForeignKeyConstraints()\n        );\n    }\n\n    /**\n     * Disable foreign key constraints.\n     *\n     * @return bool\n     */\n    public function disableForeignKeyConstraints()\n    {\n        return $this->connection->statement(\n            $this->grammar->compileDisableForeignKeyConstraints()\n        );\n    }\n\n    /**\n     * Execute the blueprint to build / modify the table.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @return void\n     */\n    protected function build(Blueprint $blueprint)\n    {\n        $blueprint->build($this->connection, $this->grammar);\n    }\n\n    /**\n     * Create a new command set with a Closure.\n     *\n     * @param  string  $table\n     * @param  \\Closure|null  $callback\n     * @return \\Illuminate\\Database\\Schema\\Blueprint\n     */\n    protected function createBlueprint($table, Closure $callback = null)\n    {\n        $prefix = $this->connection->getConfig('prefix_indexes')\n                    ? $this->connection->getConfig('prefix')\n                    : '';\n\n        if (isset($this->resolver)) {\n            return call_user_func($this->resolver, $table, $callback, $prefix);\n        }\n\n        return Container::getInstance()->make(Blueprint::class, compact('table', 'callback', 'prefix'));\n    }\n\n    /**\n     * Register a custom Doctrine mapping type.\n     *\n     * @param  string  $class\n     * @param  string  $name\n     * @param  string  $type\n     * @return void\n     */\n    public function registerCustomDoctrineType($class, $name, $type)\n    {\n        $this->connection->registerDoctrineType($class, $name, $type);\n    }\n\n    /**\n     * Get the database connection instance.\n     *\n     * @return \\Illuminate\\Database\\Connection\n     */\n    public function getConnection()\n    {\n        return $this->connection;\n    }\n\n    /**\n     * Set the database connection instance.\n     *\n     * @param  \\Illuminate\\Database\\Connection  $connection\n     * @return $this\n     */\n    public function setConnection(Connection $connection)\n    {\n        $this->connection = $connection;\n\n        return $this;\n    }\n\n    /**\n     * Set the Schema Blueprint resolver callback.\n     *\n     * @param  \\Closure  $resolver\n     * @return void\n     */\n    public function blueprintResolver(Closure $resolver)\n    {\n        $this->resolver = $resolver;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Schema/ColumnDefinition.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Schema;\n\nuse Illuminate\\Support\\Fluent;\n\n/**\n * @method $this after(string $column) Place the column \"after\" another column (MySQL)\n * @method $this always() Used as a modifier for generatedAs() (PostgreSQL)\n * @method $this autoIncrement() Set INTEGER columns as auto-increment (primary key)\n * @method $this change() Change the column\n * @method $this charset(string $charset) Specify a character set for the column (MySQL)\n * @method $this collation(string $collation) Specify a collation for the column (MySQL/PostgreSQL/SQL Server)\n * @method $this comment(string $comment) Add a comment to the column (MySQL/PostgreSQL)\n * @method $this default(mixed $value) Specify a \"default\" value for the column\n * @method $this first() Place the column \"first\" in the table (MySQL)\n * @method $this from(int $startingValue) Set the starting value of an auto-incrementing field (MySQL / PostgreSQL)\n * @method $this generatedAs(string|Expression $expression = null) Create a SQL compliant identity column (PostgreSQL)\n * @method $this index(string $indexName = null) Add an index\n * @method $this invisible() Specify that the column should be invisible to \"SELECT *\" (MySQL)\n * @method $this nullable(bool $value = true) Allow NULL values to be inserted into the column\n * @method $this persisted() Mark the computed generated column as persistent (SQL Server)\n * @method $this primary() Add a primary index\n * @method $this fulltext(string $indexName = null) Add a fulltext index\n * @method $this spatialIndex(string $indexName = null) Add a spatial index\n * @method $this startingValue(int $startingValue) Set the starting value of an auto-incrementing field (MySQL/PostgreSQL)\n * @method $this storedAs(string $expression) Create a stored generated column (MySQL/PostgreSQL/SQLite)\n * @method $this type(string $type) Specify a type for the column\n * @method $this unique(string $indexName = null) Add a unique index\n * @method $this unsigned() Set the INTEGER column as UNSIGNED (MySQL)\n * @method $this useCurrent() Set the TIMESTAMP column to use CURRENT_TIMESTAMP as default value\n * @method $this useCurrentOnUpdate() Set the TIMESTAMP column to use CURRENT_TIMESTAMP when updating (MySQL)\n * @method $this virtualAs(string $expression) Create a virtual generated column (MySQL/PostgreSQL/SQLite)\n */\nclass ColumnDefinition extends Fluent\n{\n    //\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Schema/ForeignIdColumnDefinition.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Schema;\n\nuse Illuminate\\Support\\Str;\n\nclass ForeignIdColumnDefinition extends ColumnDefinition\n{\n    /**\n     * The schema builder blueprint instance.\n     *\n     * @var \\Illuminate\\Database\\Schema\\Blueprint\n     */\n    protected $blueprint;\n\n    /**\n     * Create a new foreign ID column definition.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  array  $attributes\n     * @return void\n     */\n    public function __construct(Blueprint $blueprint, $attributes = [])\n    {\n        parent::__construct($attributes);\n\n        $this->blueprint = $blueprint;\n    }\n\n    /**\n     * Create a foreign key constraint on this column referencing the \"id\" column of the conventionally related table.\n     *\n     * @param  string|null  $table\n     * @param  string  $column\n     * @return \\Illuminate\\Database\\Schema\\ForeignKeyDefinition\n     */\n    public function constrained($table = null, $column = 'id')\n    {\n        return $this->references($column)->on($table ?? Str::plural(Str::beforeLast($this->name, '_'.$column)));\n    }\n\n    /**\n     * Specify which column this foreign ID references on another table.\n     *\n     * @param  string  $column\n     * @return \\Illuminate\\Database\\Schema\\ForeignKeyDefinition\n     */\n    public function references($column)\n    {\n        return $this->blueprint->foreign($this->name)->references($column);\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Schema/ForeignKeyDefinition.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Schema;\n\nuse Illuminate\\Support\\Fluent;\n\n/**\n * @method ForeignKeyDefinition deferrable(bool $value = true) Set the foreign key as deferrable (PostgreSQL)\n * @method ForeignKeyDefinition initiallyImmediate(bool $value = true) Set the default time to check the constraint (PostgreSQL)\n * @method ForeignKeyDefinition on(string $table) Specify the referenced table\n * @method ForeignKeyDefinition onDelete(string $action) Add an ON DELETE action\n * @method ForeignKeyDefinition onUpdate(string $action) Add an ON UPDATE action\n * @method ForeignKeyDefinition references(string|array $columns) Specify the referenced column(s)\n */\nclass ForeignKeyDefinition extends Fluent\n{\n    /**\n     * Indicate that updates should cascade.\n     *\n     * @return $this\n     */\n    public function cascadeOnUpdate()\n    {\n        return $this->onUpdate('cascade');\n    }\n\n    /**\n     * Indicate that updates should be restricted.\n     *\n     * @return $this\n     */\n    public function restrictOnUpdate()\n    {\n        return $this->onUpdate('restrict');\n    }\n\n    /**\n     * Indicate that deletes should cascade.\n     *\n     * @return $this\n     */\n    public function cascadeOnDelete()\n    {\n        return $this->onDelete('cascade');\n    }\n\n    /**\n     * Indicate that deletes should be restricted.\n     *\n     * @return $this\n     */\n    public function restrictOnDelete()\n    {\n        return $this->onDelete('restrict');\n    }\n\n    /**\n     * Indicate that deletes should set the foreign key value to null.\n     *\n     * @return $this\n     */\n    public function nullOnDelete()\n    {\n        return $this->onDelete('set null');\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Schema/Grammars/ChangeColumn.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Schema\\Grammars;\n\nuse Doctrine\\DBAL\\Schema\\AbstractSchemaManager as SchemaManager;\nuse Doctrine\\DBAL\\Schema\\Comparator;\nuse Doctrine\\DBAL\\Schema\\Table;\nuse Doctrine\\DBAL\\Types\\Type;\nuse Illuminate\\Database\\Connection;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Fluent;\nuse RuntimeException;\n\nclass ChangeColumn\n{\n    /**\n     * Compile a change column command into a series of SQL statements.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Grammars\\Grammar  $grammar\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @param  \\Illuminate\\Database\\Connection  $connection\n     * @return array\n     *\n     * @throws \\RuntimeException\n     */\n    public static function compile($grammar, Blueprint $blueprint, Fluent $command, Connection $connection)\n    {\n        if (! $connection->isDoctrineAvailable()) {\n            throw new RuntimeException(sprintf(\n                'Changing columns for table \"%s\" requires Doctrine DBAL. Please install the doctrine/dbal package.',\n                $blueprint->getTable()\n            ));\n        }\n\n        $schema = $connection->getDoctrineSchemaManager();\n        $databasePlatform = $schema->getDatabasePlatform();\n        $databasePlatform->registerDoctrineTypeMapping('enum', 'string');\n\n        $tableDiff = static::getChangedDiff(\n            $grammar, $blueprint, $schema\n        );\n\n        if ($tableDiff !== false) {\n            return (array) $databasePlatform->getAlterTableSQL($tableDiff);\n        }\n\n        return [];\n    }\n\n    /**\n     * Get the Doctrine table difference for the given changes.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Grammars\\Grammar  $grammar\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Doctrine\\DBAL\\Schema\\AbstractSchemaManager  $schema\n     * @return \\Doctrine\\DBAL\\Schema\\TableDiff|bool\n     */\n    protected static function getChangedDiff($grammar, Blueprint $blueprint, SchemaManager $schema)\n    {\n        $current = $schema->listTableDetails($grammar->getTablePrefix().$blueprint->getTable());\n\n        return (new Comparator)->diffTable(\n            $current, static::getTableWithColumnChanges($blueprint, $current)\n        );\n    }\n\n    /**\n     * Get a copy of the given Doctrine table after making the column changes.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Doctrine\\DBAL\\Schema\\Table  $table\n     * @return \\Doctrine\\DBAL\\Schema\\Table\n     */\n    protected static function getTableWithColumnChanges(Blueprint $blueprint, Table $table)\n    {\n        $table = clone $table;\n\n        foreach ($blueprint->getChangedColumns() as $fluent) {\n            $column = static::getDoctrineColumn($table, $fluent);\n\n            // Here we will spin through each fluent column definition and map it to the proper\n            // Doctrine column definitions - which is necessary because Laravel and Doctrine\n            // use some different terminology for various column attributes on the tables.\n            foreach ($fluent->getAttributes() as $key => $value) {\n                if (! is_null($option = static::mapFluentOptionToDoctrine($key))) {\n                    if (method_exists($column, $method = 'set'.ucfirst($option))) {\n                        $column->{$method}(static::mapFluentValueToDoctrine($option, $value));\n                        continue;\n                    }\n\n                    $column->setCustomSchemaOption($option, static::mapFluentValueToDoctrine($option, $value));\n                }\n            }\n        }\n\n        return $table;\n    }\n\n    /**\n     * Get the Doctrine column instance for a column change.\n     *\n     * @param  \\Doctrine\\DBAL\\Schema\\Table  $table\n     * @param  \\Illuminate\\Support\\Fluent  $fluent\n     * @return \\Doctrine\\DBAL\\Schema\\Column\n     */\n    protected static function getDoctrineColumn(Table $table, Fluent $fluent)\n    {\n        return $table->changeColumn(\n            $fluent['name'], static::getDoctrineColumnChangeOptions($fluent)\n        )->getColumn($fluent['name']);\n    }\n\n    /**\n     * Get the Doctrine column change options.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $fluent\n     * @return array\n     */\n    protected static function getDoctrineColumnChangeOptions(Fluent $fluent)\n    {\n        $options = ['type' => static::getDoctrineColumnType($fluent['type'])];\n\n        if (in_array($fluent['type'], ['text', 'mediumText', 'longText'])) {\n            $options['length'] = static::calculateDoctrineTextLength($fluent['type']);\n        }\n\n        if (static::doesntNeedCharacterOptions($fluent['type'])) {\n            $options['customSchemaOptions'] = [\n                'collation' => '',\n                'charset' => '',\n            ];\n        }\n\n        return $options;\n    }\n\n    /**\n     * Get the doctrine column type.\n     *\n     * @param  string  $type\n     * @return \\Doctrine\\DBAL\\Types\\Type\n     */\n    protected static function getDoctrineColumnType($type)\n    {\n        $type = strtolower($type);\n\n        switch ($type) {\n            case 'biginteger':\n                $type = 'bigint';\n                break;\n            case 'smallinteger':\n                $type = 'smallint';\n                break;\n            case 'mediumtext':\n            case 'longtext':\n                $type = 'text';\n                break;\n            case 'binary':\n                $type = 'blob';\n                break;\n            case 'uuid':\n                $type = 'guid';\n                break;\n        }\n\n        return Type::getType($type);\n    }\n\n    /**\n     * Calculate the proper column length to force the Doctrine text type.\n     *\n     * @param  string  $type\n     * @return int\n     */\n    protected static function calculateDoctrineTextLength($type)\n    {\n        switch ($type) {\n            case 'mediumText':\n                return 65535 + 1;\n            case 'longText':\n                return 16777215 + 1;\n            default:\n                return 255 + 1;\n        }\n    }\n\n    /**\n     * Determine if the given type does not need character / collation options.\n     *\n     * @param  string  $type\n     * @return bool\n     */\n    protected static function doesntNeedCharacterOptions($type)\n    {\n        return in_array($type, [\n            'bigInteger',\n            'binary',\n            'boolean',\n            'date',\n            'dateTime',\n            'decimal',\n            'double',\n            'float',\n            'integer',\n            'json',\n            'mediumInteger',\n            'smallInteger',\n            'time',\n            'tinyInteger',\n        ]);\n    }\n\n    /**\n     * Get the matching Doctrine option for a given Fluent attribute name.\n     *\n     * @param  string  $attribute\n     * @return string|null\n     */\n    protected static function mapFluentOptionToDoctrine($attribute)\n    {\n        switch ($attribute) {\n            case 'type':\n            case 'name':\n                return;\n            case 'nullable':\n                return 'notnull';\n            case 'total':\n                return 'precision';\n            case 'places':\n                return 'scale';\n            default:\n                return $attribute;\n        }\n    }\n\n    /**\n     * Get the matching Doctrine value for a given Fluent attribute.\n     *\n     * @param  string  $option\n     * @param  mixed  $value\n     * @return mixed\n     */\n    protected static function mapFluentValueToDoctrine($option, $value)\n    {\n        return $option === 'notnull' ? ! $value : $value;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Schema/Grammars/Grammar.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Schema\\Grammars;\n\nuse Doctrine\\DBAL\\Schema\\AbstractSchemaManager as SchemaManager;\nuse Doctrine\\DBAL\\Schema\\TableDiff;\nuse Illuminate\\Database\\Connection;\nuse Illuminate\\Database\\Grammar as BaseGrammar;\nuse Illuminate\\Database\\Query\\Expression;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Fluent;\nuse LogicException;\nuse RuntimeException;\n\nabstract class Grammar extends BaseGrammar\n{\n    /**\n     * If this Grammar supports schema changes wrapped in a transaction.\n     *\n     * @var bool\n     */\n    protected $transactions = false;\n\n    /**\n     * The commands to be executed outside of create or alter command.\n     *\n     * @var array\n     */\n    protected $fluentCommands = [];\n\n    /**\n     * Compile a create database command.\n     *\n     * @param  string  $name\n     * @param  \\Illuminate\\Database\\Connection  $connection\n     * @return void\n     *\n     * @throws \\LogicException\n     */\n    public function compileCreateDatabase($name, $connection)\n    {\n        throw new LogicException('This database driver does not support creating databases.');\n    }\n\n    /**\n     * Compile a drop database if exists command.\n     *\n     * @param  string  $name\n     * @return void\n     *\n     * @throws \\LogicException\n     */\n    public function compileDropDatabaseIfExists($name)\n    {\n        throw new LogicException('This database driver does not support dropping databases.');\n    }\n\n    /**\n     * Compile a rename column command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @param  \\Illuminate\\Database\\Connection  $connection\n     * @return array\n     */\n    public function compileRenameColumn(Blueprint $blueprint, Fluent $command, Connection $connection)\n    {\n        return RenameColumn::compile($this, $blueprint, $command, $connection);\n    }\n\n    /**\n     * Compile a change column command into a series of SQL statements.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @param  \\Illuminate\\Database\\Connection  $connection\n     * @return array\n     *\n     * @throws \\RuntimeException\n     */\n    public function compileChange(Blueprint $blueprint, Fluent $command, Connection $connection)\n    {\n        return ChangeColumn::compile($this, $blueprint, $command, $connection);\n    }\n\n    /**\n     * Compile a fulltext index key command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     *\n     * @throws \\RuntimeException\n     */\n    public function compileFulltext(Blueprint $blueprint, Fluent $command)\n    {\n        throw new RuntimeException('This database driver does not support fulltext index creation.');\n    }\n\n    /**\n     * Compile a drop fulltext index command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileDropFullText(Blueprint $blueprint, Fluent $command)\n    {\n        throw new RuntimeException('This database driver does not support fulltext index creation.');\n    }\n\n    /**\n     * Compile a foreign key command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileForeign(Blueprint $blueprint, Fluent $command)\n    {\n        // We need to prepare several of the elements of the foreign key definition\n        // before we can create the SQL, such as wrapping the tables and convert\n        // an array of columns to comma-delimited strings for the SQL queries.\n        $sql = sprintf('alter table %s add constraint %s ',\n            $this->wrapTable($blueprint),\n            $this->wrap($command->index)\n        );\n\n        // Once we have the initial portion of the SQL statement we will add on the\n        // key name, table name, and referenced columns. These will complete the\n        // main portion of the SQL statement and this SQL will almost be done.\n        $sql .= sprintf('foreign key (%s) references %s (%s)',\n            $this->columnize($command->columns),\n            $this->wrapTable($command->on),\n            $this->columnize((array) $command->references)\n        );\n\n        // Once we have the basic foreign key creation statement constructed we can\n        // build out the syntax for what should happen on an update or delete of\n        // the affected columns, which will get something like \"cascade\", etc.\n        if (! is_null($command->onDelete)) {\n            $sql .= \" on delete {$command->onDelete}\";\n        }\n\n        if (! is_null($command->onUpdate)) {\n            $sql .= \" on update {$command->onUpdate}\";\n        }\n\n        return $sql;\n    }\n\n    /**\n     * Compile the blueprint's column definitions.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @return array\n     */\n    protected function getColumns(Blueprint $blueprint)\n    {\n        $columns = [];\n\n        foreach ($blueprint->getAddedColumns() as $column) {\n            // Each of the column types have their own compiler functions which are tasked\n            // with turning the column definition into its SQL format for this platform\n            // used by the connection. The column's modifiers are compiled and added.\n            $sql = $this->wrap($column).' '.$this->getType($column);\n\n            $columns[] = $this->addModifiers($sql, $blueprint, $column);\n        }\n\n        return $columns;\n    }\n\n    /**\n     * Get the SQL for the column data type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function getType(Fluent $column)\n    {\n        return $this->{'type'.ucfirst($column->type)}($column);\n    }\n\n    /**\n     * Create the column definition for a generated, computed column type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return void\n     *\n     * @throws \\RuntimeException\n     */\n    protected function typeComputed(Fluent $column)\n    {\n        throw new RuntimeException('This database driver does not support the computed type.');\n    }\n\n    /**\n     * Add the column modifiers to the definition.\n     *\n     * @param  string  $sql\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function addModifiers($sql, Blueprint $blueprint, Fluent $column)\n    {\n        foreach ($this->modifiers as $modifier) {\n            if (method_exists($this, $method = \"modify{$modifier}\")) {\n                $sql .= $this->{$method}($blueprint, $column);\n            }\n        }\n\n        return $sql;\n    }\n\n    /**\n     * Get the primary key command if it exists on the blueprint.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  string  $name\n     * @return \\Illuminate\\Support\\Fluent|null\n     */\n    protected function getCommandByName(Blueprint $blueprint, $name)\n    {\n        $commands = $this->getCommandsByName($blueprint, $name);\n\n        if (count($commands) > 0) {\n            return reset($commands);\n        }\n    }\n\n    /**\n     * Get all of the commands with a given name.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  string  $name\n     * @return array\n     */\n    protected function getCommandsByName(Blueprint $blueprint, $name)\n    {\n        return array_filter($blueprint->getCommands(), function ($value) use ($name) {\n            return $value->name == $name;\n        });\n    }\n\n    /**\n     * Add a prefix to an array of values.\n     *\n     * @param  string  $prefix\n     * @param  array  $values\n     * @return array\n     */\n    public function prefixArray($prefix, array $values)\n    {\n        return array_map(function ($value) use ($prefix) {\n            return $prefix.' '.$value;\n        }, $values);\n    }\n\n    /**\n     * Wrap a table in keyword identifiers.\n     *\n     * @param  mixed  $table\n     * @return string\n     */\n    public function wrapTable($table)\n    {\n        return parent::wrapTable(\n            $table instanceof Blueprint ? $table->getTable() : $table\n        );\n    }\n\n    /**\n     * Wrap a value in keyword identifiers.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Expression|string  $value\n     * @param  bool  $prefixAlias\n     * @return string\n     */\n    public function wrap($value, $prefixAlias = false)\n    {\n        return parent::wrap(\n            $value instanceof Fluent ? $value->name : $value, $prefixAlias\n        );\n    }\n\n    /**\n     * Format a value so that it can be used in \"default\" clauses.\n     *\n     * @param  mixed  $value\n     * @return string\n     */\n    protected function getDefaultValue($value)\n    {\n        if ($value instanceof Expression) {\n            return $value;\n        }\n\n        return is_bool($value)\n                    ? \"'\".(int) $value.\"'\"\n                    : \"'\".(string) $value.\"'\";\n    }\n\n    /**\n     * Create an empty Doctrine DBAL TableDiff from the Blueprint.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Doctrine\\DBAL\\Schema\\AbstractSchemaManager  $schema\n     * @return \\Doctrine\\DBAL\\Schema\\TableDiff\n     */\n    public function getDoctrineTableDiff(Blueprint $blueprint, SchemaManager $schema)\n    {\n        $table = $this->getTablePrefix().$blueprint->getTable();\n\n        return tap(new TableDiff($table), function ($tableDiff) use ($schema, $table) {\n            $tableDiff->fromTable = $schema->listTableDetails($table);\n        });\n    }\n\n    /**\n     * Get the fluent commands for the grammar.\n     *\n     * @return array\n     */\n    public function getFluentCommands()\n    {\n        return $this->fluentCommands;\n    }\n\n    /**\n     * Check if this Grammar supports schema changes wrapped in a transaction.\n     *\n     * @return bool\n     */\n    public function supportsSchemaTransactions()\n    {\n        return $this->transactions;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Schema/Grammars/MySqlGrammar.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Schema\\Grammars;\n\nuse Illuminate\\Database\\Connection;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Fluent;\nuse RuntimeException;\n\nclass MySqlGrammar extends Grammar\n{\n    /**\n     * The possible column modifiers.\n     *\n     * @var string[]\n     */\n    protected $modifiers = [\n        'Unsigned', 'Charset', 'Collate', 'VirtualAs', 'StoredAs', 'Nullable', 'Invisible',\n        'Srid', 'Default', 'Increment', 'Comment', 'After', 'First',\n    ];\n\n    /**\n     * The possible column serials.\n     *\n     * @var string[]\n     */\n    protected $serials = ['bigInteger', 'integer', 'mediumInteger', 'smallInteger', 'tinyInteger'];\n\n    /**\n     * Compile a create database command.\n     *\n     * @param  string  $name\n     * @param  \\Illuminate\\Database\\Connection  $connection\n     * @return string\n     */\n    public function compileCreateDatabase($name, $connection)\n    {\n        return sprintf(\n            'create database %s default character set %s default collate %s',\n            $this->wrapValue($name),\n            $this->wrapValue($connection->getConfig('charset')),\n            $this->wrapValue($connection->getConfig('collation')),\n        );\n    }\n\n    /**\n     * Compile a drop database if exists command.\n     *\n     * @param  string  $name\n     * @return string\n     */\n    public function compileDropDatabaseIfExists($name)\n    {\n        return sprintf(\n            'drop database if exists %s',\n            $this->wrapValue($name)\n        );\n    }\n\n    /**\n     * Compile the query to determine the list of tables.\n     *\n     * @return string\n     */\n    public function compileTableExists()\n    {\n        return \"select * from information_schema.tables where table_schema = ? and table_name = ? and table_type = 'BASE TABLE'\";\n    }\n\n    /**\n     * Compile the query to determine the list of columns.\n     *\n     * @return string\n     */\n    public function compileColumnListing()\n    {\n        return 'select column_name as `column_name` from information_schema.columns where table_schema = ? and table_name = ?';\n    }\n\n    /**\n     * Compile a create table command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @param  \\Illuminate\\Database\\Connection  $connection\n     * @return array\n     */\n    public function compileCreate(Blueprint $blueprint, Fluent $command, Connection $connection)\n    {\n        $sql = $this->compileCreateTable(\n            $blueprint, $command, $connection\n        );\n\n        // Once we have the primary SQL, we can add the encoding option to the SQL for\n        // the table.  Then, we can check if a storage engine has been supplied for\n        // the table. If so, we will add the engine declaration to the SQL query.\n        $sql = $this->compileCreateEncoding(\n            $sql, $connection, $blueprint\n        );\n\n        // Finally, we will append the engine configuration onto this SQL statement as\n        // the final thing we do before returning this finished SQL. Once this gets\n        // added the query will be ready to execute against the real connections.\n        return array_values(array_filter(array_merge([$this->compileCreateEngine(\n            $sql, $connection, $blueprint\n        )], $this->compileAutoIncrementStartingValues($blueprint))));\n    }\n\n    /**\n     * Create the main create table clause.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @param  \\Illuminate\\Database\\Connection  $connection\n     * @return array\n     */\n    protected function compileCreateTable($blueprint, $command, $connection)\n    {\n        return trim(sprintf('%s table %s (%s)',\n            $blueprint->temporary ? 'create temporary' : 'create',\n            $this->wrapTable($blueprint),\n            implode(', ', $this->getColumns($blueprint))\n        ));\n    }\n\n    /**\n     * Append the character set specifications to a command.\n     *\n     * @param  string  $sql\n     * @param  \\Illuminate\\Database\\Connection  $connection\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @return string\n     */\n    protected function compileCreateEncoding($sql, Connection $connection, Blueprint $blueprint)\n    {\n        // First we will set the character set if one has been set on either the create\n        // blueprint itself or on the root configuration for the connection that the\n        // table is being created on. We will add these to the create table query.\n        if (isset($blueprint->charset)) {\n            $sql .= ' default character set '.$blueprint->charset;\n        } elseif (! is_null($charset = $connection->getConfig('charset'))) {\n            $sql .= ' default character set '.$charset;\n        }\n\n        // Next we will add the collation to the create table statement if one has been\n        // added to either this create table blueprint or the configuration for this\n        // connection that the query is targeting. We'll add it to this SQL query.\n        if (isset($blueprint->collation)) {\n            $sql .= \" collate '{$blueprint->collation}'\";\n        } elseif (! is_null($collation = $connection->getConfig('collation'))) {\n            $sql .= \" collate '{$collation}'\";\n        }\n\n        return $sql;\n    }\n\n    /**\n     * Append the engine specifications to a command.\n     *\n     * @param  string  $sql\n     * @param  \\Illuminate\\Database\\Connection  $connection\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @return string\n     */\n    protected function compileCreateEngine($sql, Connection $connection, Blueprint $blueprint)\n    {\n        if (isset($blueprint->engine)) {\n            return $sql.' engine = '.$blueprint->engine;\n        } elseif (! is_null($engine = $connection->getConfig('engine'))) {\n            return $sql.' engine = '.$engine;\n        }\n\n        return $sql;\n    }\n\n    /**\n     * Compile an add column command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return array\n     */\n    public function compileAdd(Blueprint $blueprint, Fluent $command)\n    {\n        $columns = $this->prefixArray('add', $this->getColumns($blueprint));\n\n        return array_values(array_merge(\n            ['alter table '.$this->wrapTable($blueprint).' '.implode(', ', $columns)],\n            $this->compileAutoIncrementStartingValues($blueprint)\n        ));\n    }\n\n    /**\n     * Compile the auto-incrementing column starting values.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @return array\n     */\n    public function compileAutoIncrementStartingValues(Blueprint $blueprint)\n    {\n        return collect($blueprint->autoIncrementingStartingValues())->map(function ($value, $column) use ($blueprint) {\n            return 'alter table '.$this->wrapTable($blueprint->getTable()).' auto_increment = '.$value;\n        })->all();\n    }\n\n    /**\n     * Compile a primary key command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compilePrimary(Blueprint $blueprint, Fluent $command)\n    {\n        $command->name(null);\n\n        return $this->compileKey($blueprint, $command, 'primary key');\n    }\n\n    /**\n     * Compile a unique key command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileUnique(Blueprint $blueprint, Fluent $command)\n    {\n        return $this->compileKey($blueprint, $command, 'unique');\n    }\n\n    /**\n     * Compile a plain index key command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileIndex(Blueprint $blueprint, Fluent $command)\n    {\n        return $this->compileKey($blueprint, $command, 'index');\n    }\n\n    /**\n     * Compile a fulltext index key command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileFullText(Blueprint $blueprint, Fluent $command)\n    {\n        return $this->compileKey($blueprint, $command, 'fulltext');\n    }\n\n    /**\n     * Compile a spatial index key command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileSpatialIndex(Blueprint $blueprint, Fluent $command)\n    {\n        return $this->compileKey($blueprint, $command, 'spatial index');\n    }\n\n    /**\n     * Compile an index creation command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @param  string  $type\n     * @return string\n     */\n    protected function compileKey(Blueprint $blueprint, Fluent $command, $type)\n    {\n        return sprintf('alter table %s add %s %s%s(%s)',\n            $this->wrapTable($blueprint),\n            $type,\n            $this->wrap($command->index),\n            $command->algorithm ? ' using '.$command->algorithm : '',\n            $this->columnize($command->columns)\n        );\n    }\n\n    /**\n     * Compile a drop table command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileDrop(Blueprint $blueprint, Fluent $command)\n    {\n        return 'drop table '.$this->wrapTable($blueprint);\n    }\n\n    /**\n     * Compile a drop table (if exists) command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileDropIfExists(Blueprint $blueprint, Fluent $command)\n    {\n        return 'drop table if exists '.$this->wrapTable($blueprint);\n    }\n\n    /**\n     * Compile a drop column command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileDropColumn(Blueprint $blueprint, Fluent $command)\n    {\n        $columns = $this->prefixArray('drop', $this->wrapArray($command->columns));\n\n        return 'alter table '.$this->wrapTable($blueprint).' '.implode(', ', $columns);\n    }\n\n    /**\n     * Compile a drop primary key command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileDropPrimary(Blueprint $blueprint, Fluent $command)\n    {\n        return 'alter table '.$this->wrapTable($blueprint).' drop primary key';\n    }\n\n    /**\n     * Compile a drop unique key command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileDropUnique(Blueprint $blueprint, Fluent $command)\n    {\n        $index = $this->wrap($command->index);\n\n        return \"alter table {$this->wrapTable($blueprint)} drop index {$index}\";\n    }\n\n    /**\n     * Compile a drop index command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileDropIndex(Blueprint $blueprint, Fluent $command)\n    {\n        $index = $this->wrap($command->index);\n\n        return \"alter table {$this->wrapTable($blueprint)} drop index {$index}\";\n    }\n\n    /**\n     * Compile a drop fulltext index command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileDropFullText(Blueprint $blueprint, Fluent $command)\n    {\n        return $this->compileDropIndex($blueprint, $command);\n    }\n\n    /**\n     * Compile a drop spatial index command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileDropSpatialIndex(Blueprint $blueprint, Fluent $command)\n    {\n        return $this->compileDropIndex($blueprint, $command);\n    }\n\n    /**\n     * Compile a drop foreign key command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileDropForeign(Blueprint $blueprint, Fluent $command)\n    {\n        $index = $this->wrap($command->index);\n\n        return \"alter table {$this->wrapTable($blueprint)} drop foreign key {$index}\";\n    }\n\n    /**\n     * Compile a rename table command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileRename(Blueprint $blueprint, Fluent $command)\n    {\n        $from = $this->wrapTable($blueprint);\n\n        return \"rename table {$from} to \".$this->wrapTable($command->to);\n    }\n\n    /**\n     * Compile a rename index command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileRenameIndex(Blueprint $blueprint, Fluent $command)\n    {\n        return sprintf('alter table %s rename index %s to %s',\n            $this->wrapTable($blueprint),\n            $this->wrap($command->from),\n            $this->wrap($command->to)\n        );\n    }\n\n    /**\n     * Compile the SQL needed to drop all tables.\n     *\n     * @param  array  $tables\n     * @return string\n     */\n    public function compileDropAllTables($tables)\n    {\n        return 'drop table '.implode(',', $this->wrapArray($tables));\n    }\n\n    /**\n     * Compile the SQL needed to drop all views.\n     *\n     * @param  array  $views\n     * @return string\n     */\n    public function compileDropAllViews($views)\n    {\n        return 'drop view '.implode(',', $this->wrapArray($views));\n    }\n\n    /**\n     * Compile the SQL needed to retrieve all table names.\n     *\n     * @return string\n     */\n    public function compileGetAllTables()\n    {\n        return 'SHOW FULL TABLES WHERE table_type = \\'BASE TABLE\\'';\n    }\n\n    /**\n     * Compile the SQL needed to retrieve all view names.\n     *\n     * @return string\n     */\n    public function compileGetAllViews()\n    {\n        return 'SHOW FULL TABLES WHERE table_type = \\'VIEW\\'';\n    }\n\n    /**\n     * Compile the command to enable foreign key constraints.\n     *\n     * @return string\n     */\n    public function compileEnableForeignKeyConstraints()\n    {\n        return 'SET FOREIGN_KEY_CHECKS=1;';\n    }\n\n    /**\n     * Compile the command to disable foreign key constraints.\n     *\n     * @return string\n     */\n    public function compileDisableForeignKeyConstraints()\n    {\n        return 'SET FOREIGN_KEY_CHECKS=0;';\n    }\n\n    /**\n     * Create the column definition for a char type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeChar(Fluent $column)\n    {\n        return \"char({$column->length})\";\n    }\n\n    /**\n     * Create the column definition for a string type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeString(Fluent $column)\n    {\n        return \"varchar({$column->length})\";\n    }\n\n    /**\n     * Create the column definition for a tiny text type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeTinyText(Fluent $column)\n    {\n        return 'tinytext';\n    }\n\n    /**\n     * Create the column definition for a text type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeText(Fluent $column)\n    {\n        return 'text';\n    }\n\n    /**\n     * Create the column definition for a medium text type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeMediumText(Fluent $column)\n    {\n        return 'mediumtext';\n    }\n\n    /**\n     * Create the column definition for a long text type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeLongText(Fluent $column)\n    {\n        return 'longtext';\n    }\n\n    /**\n     * Create the column definition for a big integer type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeBigInteger(Fluent $column)\n    {\n        return 'bigint';\n    }\n\n    /**\n     * Create the column definition for an integer type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeInteger(Fluent $column)\n    {\n        return 'int';\n    }\n\n    /**\n     * Create the column definition for a medium integer type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeMediumInteger(Fluent $column)\n    {\n        return 'mediumint';\n    }\n\n    /**\n     * Create the column definition for a tiny integer type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeTinyInteger(Fluent $column)\n    {\n        return 'tinyint';\n    }\n\n    /**\n     * Create the column definition for a small integer type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeSmallInteger(Fluent $column)\n    {\n        return 'smallint';\n    }\n\n    /**\n     * Create the column definition for a float type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeFloat(Fluent $column)\n    {\n        return $this->typeDouble($column);\n    }\n\n    /**\n     * Create the column definition for a double type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeDouble(Fluent $column)\n    {\n        if ($column->total && $column->places) {\n            return \"double({$column->total}, {$column->places})\";\n        }\n\n        return 'double';\n    }\n\n    /**\n     * Create the column definition for a decimal type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeDecimal(Fluent $column)\n    {\n        return \"decimal({$column->total}, {$column->places})\";\n    }\n\n    /**\n     * Create the column definition for a boolean type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeBoolean(Fluent $column)\n    {\n        return 'tinyint(1)';\n    }\n\n    /**\n     * Create the column definition for an enumeration type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeEnum(Fluent $column)\n    {\n        return sprintf('enum(%s)', $this->quoteString($column->allowed));\n    }\n\n    /**\n     * Create the column definition for a set enumeration type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeSet(Fluent $column)\n    {\n        return sprintf('set(%s)', $this->quoteString($column->allowed));\n    }\n\n    /**\n     * Create the column definition for a json type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeJson(Fluent $column)\n    {\n        return 'json';\n    }\n\n    /**\n     * Create the column definition for a jsonb type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeJsonb(Fluent $column)\n    {\n        return 'json';\n    }\n\n    /**\n     * Create the column definition for a date type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeDate(Fluent $column)\n    {\n        return 'date';\n    }\n\n    /**\n     * Create the column definition for a date-time type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeDateTime(Fluent $column)\n    {\n        $columnType = $column->precision ? \"datetime($column->precision)\" : 'datetime';\n\n        $current = $column->precision ? \"CURRENT_TIMESTAMP($column->precision)\" : 'CURRENT_TIMESTAMP';\n\n        $columnType = $column->useCurrent ? \"$columnType default $current\" : $columnType;\n\n        return $column->useCurrentOnUpdate ? \"$columnType on update $current\" : $columnType;\n    }\n\n    /**\n     * Create the column definition for a date-time (with time zone) type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeDateTimeTz(Fluent $column)\n    {\n        return $this->typeDateTime($column);\n    }\n\n    /**\n     * Create the column definition for a time type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeTime(Fluent $column)\n    {\n        return $column->precision ? \"time($column->precision)\" : 'time';\n    }\n\n    /**\n     * Create the column definition for a time (with time zone) type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeTimeTz(Fluent $column)\n    {\n        return $this->typeTime($column);\n    }\n\n    /**\n     * Create the column definition for a timestamp type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeTimestamp(Fluent $column)\n    {\n        $columnType = $column->precision ? \"timestamp($column->precision)\" : 'timestamp';\n\n        $current = $column->precision ? \"CURRENT_TIMESTAMP($column->precision)\" : 'CURRENT_TIMESTAMP';\n\n        $columnType = $column->useCurrent ? \"$columnType default $current\" : $columnType;\n\n        return $column->useCurrentOnUpdate ? \"$columnType on update $current\" : $columnType;\n    }\n\n    /**\n     * Create the column definition for a timestamp (with time zone) type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeTimestampTz(Fluent $column)\n    {\n        return $this->typeTimestamp($column);\n    }\n\n    /**\n     * Create the column definition for a year type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeYear(Fluent $column)\n    {\n        return 'year';\n    }\n\n    /**\n     * Create the column definition for a binary type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeBinary(Fluent $column)\n    {\n        return 'blob';\n    }\n\n    /**\n     * Create the column definition for a uuid type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeUuid(Fluent $column)\n    {\n        return 'char(36)';\n    }\n\n    /**\n     * Create the column definition for an IP address type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeIpAddress(Fluent $column)\n    {\n        return 'varchar(45)';\n    }\n\n    /**\n     * Create the column definition for a MAC address type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeMacAddress(Fluent $column)\n    {\n        return 'varchar(17)';\n    }\n\n    /**\n     * Create the column definition for a spatial Geometry type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    public function typeGeometry(Fluent $column)\n    {\n        return 'geometry';\n    }\n\n    /**\n     * Create the column definition for a spatial Point type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    public function typePoint(Fluent $column)\n    {\n        return 'point';\n    }\n\n    /**\n     * Create the column definition for a spatial LineString type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    public function typeLineString(Fluent $column)\n    {\n        return 'linestring';\n    }\n\n    /**\n     * Create the column definition for a spatial Polygon type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    public function typePolygon(Fluent $column)\n    {\n        return 'polygon';\n    }\n\n    /**\n     * Create the column definition for a spatial GeometryCollection type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    public function typeGeometryCollection(Fluent $column)\n    {\n        return 'geometrycollection';\n    }\n\n    /**\n     * Create the column definition for a spatial MultiPoint type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    public function typeMultiPoint(Fluent $column)\n    {\n        return 'multipoint';\n    }\n\n    /**\n     * Create the column definition for a spatial MultiLineString type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    public function typeMultiLineString(Fluent $column)\n    {\n        return 'multilinestring';\n    }\n\n    /**\n     * Create the column definition for a spatial MultiPolygon type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    public function typeMultiPolygon(Fluent $column)\n    {\n        return 'multipolygon';\n    }\n\n    /**\n     * Create the column definition for a generated, computed column type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return void\n     *\n     * @throws \\RuntimeException\n     */\n    protected function typeComputed(Fluent $column)\n    {\n        throw new RuntimeException('This database driver requires a type, see the virtualAs / storedAs modifiers.');\n    }\n\n    /**\n     * Get the SQL for a generated virtual column modifier.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string|null\n     */\n    protected function modifyVirtualAs(Blueprint $blueprint, Fluent $column)\n    {\n        if (! is_null($column->virtualAs)) {\n            return \" as ({$column->virtualAs})\";\n        }\n    }\n\n    /**\n     * Get the SQL for a generated stored column modifier.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string|null\n     */\n    protected function modifyStoredAs(Blueprint $blueprint, Fluent $column)\n    {\n        if (! is_null($column->storedAs)) {\n            return \" as ({$column->storedAs}) stored\";\n        }\n    }\n\n    /**\n     * Get the SQL for an unsigned column modifier.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string|null\n     */\n    protected function modifyUnsigned(Blueprint $blueprint, Fluent $column)\n    {\n        if ($column->unsigned) {\n            return ' unsigned';\n        }\n    }\n\n    /**\n     * Get the SQL for a character set column modifier.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string|null\n     */\n    protected function modifyCharset(Blueprint $blueprint, Fluent $column)\n    {\n        if (! is_null($column->charset)) {\n            return ' character set '.$column->charset;\n        }\n    }\n\n    /**\n     * Get the SQL for a collation column modifier.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string|null\n     */\n    protected function modifyCollate(Blueprint $blueprint, Fluent $column)\n    {\n        if (! is_null($column->collation)) {\n            return \" collate '{$column->collation}'\";\n        }\n    }\n\n    /**\n     * Get the SQL for a nullable column modifier.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string|null\n     */\n    protected function modifyNullable(Blueprint $blueprint, Fluent $column)\n    {\n        if (is_null($column->virtualAs) && is_null($column->storedAs)) {\n            return $column->nullable ? ' null' : ' not null';\n        }\n\n        if ($column->nullable === false) {\n            return ' not null';\n        }\n    }\n\n    /**\n     * Get the SQL for an invisible column modifier.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string|null\n     */\n    protected function modifyInvisible(Blueprint $blueprint, Fluent $column)\n    {\n        if (! is_null($column->invisible)) {\n            return ' invisible';\n        }\n    }\n\n    /**\n     * Get the SQL for a default column modifier.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string|null\n     */\n    protected function modifyDefault(Blueprint $blueprint, Fluent $column)\n    {\n        if (! is_null($column->default)) {\n            return ' default '.$this->getDefaultValue($column->default);\n        }\n    }\n\n    /**\n     * Get the SQL for an auto-increment column modifier.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string|null\n     */\n    protected function modifyIncrement(Blueprint $blueprint, Fluent $column)\n    {\n        if (in_array($column->type, $this->serials) && $column->autoIncrement) {\n            return ' auto_increment primary key';\n        }\n    }\n\n    /**\n     * Get the SQL for a \"first\" column modifier.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string|null\n     */\n    protected function modifyFirst(Blueprint $blueprint, Fluent $column)\n    {\n        if (! is_null($column->first)) {\n            return ' first';\n        }\n    }\n\n    /**\n     * Get the SQL for an \"after\" column modifier.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string|null\n     */\n    protected function modifyAfter(Blueprint $blueprint, Fluent $column)\n    {\n        if (! is_null($column->after)) {\n            return ' after '.$this->wrap($column->after);\n        }\n    }\n\n    /**\n     * Get the SQL for a \"comment\" column modifier.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string|null\n     */\n    protected function modifyComment(Blueprint $blueprint, Fluent $column)\n    {\n        if (! is_null($column->comment)) {\n            return \" comment '\".addslashes($column->comment).\"'\";\n        }\n    }\n\n    /**\n     * Get the SQL for a SRID column modifier.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string|null\n     */\n    protected function modifySrid(Blueprint $blueprint, Fluent $column)\n    {\n        if (! is_null($column->srid) && is_int($column->srid) && $column->srid > 0) {\n            return ' srid '.$column->srid;\n        }\n    }\n\n    /**\n     * Wrap a single string in keyword identifiers.\n     *\n     * @param  string  $value\n     * @return string\n     */\n    protected function wrapValue($value)\n    {\n        if ($value !== '*') {\n            return '`'.str_replace('`', '``', $value).'`';\n        }\n\n        return $value;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Schema/Grammars/PostgresGrammar.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Schema\\Grammars;\n\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Fluent;\n\nclass PostgresGrammar extends Grammar\n{\n    /**\n     * If this Grammar supports schema changes wrapped in a transaction.\n     *\n     * @var bool\n     */\n    protected $transactions = true;\n\n    /**\n     * The possible column modifiers.\n     *\n     * @var string[]\n     */\n    protected $modifiers = ['Collate', 'Increment', 'Nullable', 'Default', 'VirtualAs', 'StoredAs'];\n\n    /**\n     * The columns available as serials.\n     *\n     * @var string[]\n     */\n    protected $serials = ['bigInteger', 'integer', 'mediumInteger', 'smallInteger', 'tinyInteger'];\n\n    /**\n     * The commands to be executed outside of create or alter command.\n     *\n     * @var string[]\n     */\n    protected $fluentCommands = ['Comment'];\n\n    /**\n     * Compile a create database command.\n     *\n     * @param  string  $name\n     * @param  \\Illuminate\\Database\\Connection  $connection\n     * @return string\n     */\n    public function compileCreateDatabase($name, $connection)\n    {\n        return sprintf(\n            'create database %s encoding %s',\n            $this->wrapValue($name),\n            $this->wrapValue($connection->getConfig('charset')),\n        );\n    }\n\n    /**\n     * Compile a drop database if exists command.\n     *\n     * @param  string  $name\n     * @return string\n     */\n    public function compileDropDatabaseIfExists($name)\n    {\n        return sprintf(\n            'drop database if exists %s',\n            $this->wrapValue($name)\n        );\n    }\n\n    /**\n     * Compile the query to determine if a table exists.\n     *\n     * @return string\n     */\n    public function compileTableExists()\n    {\n        return \"select * from information_schema.tables where table_schema = ? and table_name = ? and table_type = 'BASE TABLE'\";\n    }\n\n    /**\n     * Compile the query to determine the list of columns.\n     *\n     * @return string\n     */\n    public function compileColumnListing()\n    {\n        return 'select column_name from information_schema.columns where table_schema = ? and table_name = ?';\n    }\n\n    /**\n     * Compile a create table command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return array\n     */\n    public function compileCreate(Blueprint $blueprint, Fluent $command)\n    {\n        return array_values(array_filter(array_merge([sprintf('%s table %s (%s)',\n            $blueprint->temporary ? 'create temporary' : 'create',\n            $this->wrapTable($blueprint),\n            implode(', ', $this->getColumns($blueprint))\n        )], $this->compileAutoIncrementStartingValues($blueprint))));\n    }\n\n    /**\n     * Compile a column addition command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileAdd(Blueprint $blueprint, Fluent $command)\n    {\n        return array_values(array_filter(array_merge([sprintf('alter table %s %s',\n            $this->wrapTable($blueprint),\n            implode(', ', $this->prefixArray('add column', $this->getColumns($blueprint)))\n        )], $this->compileAutoIncrementStartingValues($blueprint))));\n    }\n\n    /**\n     * Compile the auto-incrementing column starting values.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @return array\n     */\n    public function compileAutoIncrementStartingValues(Blueprint $blueprint)\n    {\n        return collect($blueprint->autoIncrementingStartingValues())->map(function ($value, $column) use ($blueprint) {\n            return 'alter sequence '.$blueprint->getTable().'_'.$column.'_seq restart with '.$value;\n        })->all();\n    }\n\n    /**\n     * Compile a primary key command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compilePrimary(Blueprint $blueprint, Fluent $command)\n    {\n        $columns = $this->columnize($command->columns);\n\n        return 'alter table '.$this->wrapTable($blueprint).\" add primary key ({$columns})\";\n    }\n\n    /**\n     * Compile a unique key command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileUnique(Blueprint $blueprint, Fluent $command)\n    {\n        return sprintf('alter table %s add constraint %s unique (%s)',\n            $this->wrapTable($blueprint),\n            $this->wrap($command->index),\n            $this->columnize($command->columns)\n        );\n    }\n\n    /**\n     * Compile a plain index key command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileIndex(Blueprint $blueprint, Fluent $command)\n    {\n        return sprintf('create index %s on %s%s (%s)',\n            $this->wrap($command->index),\n            $this->wrapTable($blueprint),\n            $command->algorithm ? ' using '.$command->algorithm : '',\n            $this->columnize($command->columns)\n        );\n    }\n\n    /**\n     * Compile a fulltext index key command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     *\n     * @throws \\RuntimeException\n     */\n    public function compileFulltext(Blueprint $blueprint, Fluent $command)\n    {\n        $language = $command->language ?: 'english';\n\n        $columns = array_map(function ($column) use ($language) {\n            return \"to_tsvector({$this->quoteString($language)}, {$this->wrap($column)})\";\n        }, $command->columns);\n\n        return sprintf('create index %s on %s using gin ((%s))',\n            $this->wrap($command->index),\n            $this->wrapTable($blueprint),\n            implode(' || ', $columns)\n        );\n    }\n\n    /**\n     * Compile a spatial index key command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileSpatialIndex(Blueprint $blueprint, Fluent $command)\n    {\n        $command->algorithm = 'gist';\n\n        return $this->compileIndex($blueprint, $command);\n    }\n\n    /**\n     * Compile a foreign key command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileForeign(Blueprint $blueprint, Fluent $command)\n    {\n        $sql = parent::compileForeign($blueprint, $command);\n\n        if (! is_null($command->deferrable)) {\n            $sql .= $command->deferrable ? ' deferrable' : ' not deferrable';\n        }\n\n        if ($command->deferrable && ! is_null($command->initiallyImmediate)) {\n            $sql .= $command->initiallyImmediate ? ' initially immediate' : ' initially deferred';\n        }\n\n        if (! is_null($command->notValid)) {\n            $sql .= ' not valid';\n        }\n\n        return $sql;\n    }\n\n    /**\n     * Compile a drop table command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileDrop(Blueprint $blueprint, Fluent $command)\n    {\n        return 'drop table '.$this->wrapTable($blueprint);\n    }\n\n    /**\n     * Compile a drop table (if exists) command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileDropIfExists(Blueprint $blueprint, Fluent $command)\n    {\n        return 'drop table if exists '.$this->wrapTable($blueprint);\n    }\n\n    /**\n     * Compile the SQL needed to drop all tables.\n     *\n     * @param  array  $tables\n     * @return string\n     */\n    public function compileDropAllTables($tables)\n    {\n        return 'drop table \"'.implode('\",\"', $tables).'\" cascade';\n    }\n\n    /**\n     * Compile the SQL needed to drop all views.\n     *\n     * @param  array  $views\n     * @return string\n     */\n    public function compileDropAllViews($views)\n    {\n        return 'drop view \"'.implode('\",\"', $views).'\" cascade';\n    }\n\n    /**\n     * Compile the SQL needed to drop all types.\n     *\n     * @param  array  $types\n     * @return string\n     */\n    public function compileDropAllTypes($types)\n    {\n        return 'drop type \"'.implode('\",\"', $types).'\" cascade';\n    }\n\n    /**\n     * Compile the SQL needed to retrieve all table names.\n     *\n     * @param  string|array  $schema\n     * @return string\n     */\n    public function compileGetAllTables($schema)\n    {\n        return \"select tablename from pg_catalog.pg_tables where schemaname in ('\".implode(\"','\", (array) $schema).\"')\";\n    }\n\n    /**\n     * Compile the SQL needed to retrieve all view names.\n     *\n     * @param  string|array  $schema\n     * @return string\n     */\n    public function compileGetAllViews($schema)\n    {\n        return \"select viewname from pg_catalog.pg_views where schemaname in ('\".implode(\"','\", (array) $schema).\"')\";\n    }\n\n    /**\n     * Compile the SQL needed to retrieve all type names.\n     *\n     * @return string\n     */\n    public function compileGetAllTypes()\n    {\n        return 'select distinct pg_type.typname from pg_type inner join pg_enum on pg_enum.enumtypid = pg_type.oid';\n    }\n\n    /**\n     * Compile a drop column command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileDropColumn(Blueprint $blueprint, Fluent $command)\n    {\n        $columns = $this->prefixArray('drop column', $this->wrapArray($command->columns));\n\n        return 'alter table '.$this->wrapTable($blueprint).' '.implode(', ', $columns);\n    }\n\n    /**\n     * Compile a drop primary key command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileDropPrimary(Blueprint $blueprint, Fluent $command)\n    {\n        $index = $this->wrap(\"{$blueprint->getTable()}_pkey\");\n\n        return 'alter table '.$this->wrapTable($blueprint).\" drop constraint {$index}\";\n    }\n\n    /**\n     * Compile a drop unique key command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileDropUnique(Blueprint $blueprint, Fluent $command)\n    {\n        $index = $this->wrap($command->index);\n\n        return \"alter table {$this->wrapTable($blueprint)} drop constraint {$index}\";\n    }\n\n    /**\n     * Compile a drop index command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileDropIndex(Blueprint $blueprint, Fluent $command)\n    {\n        return \"drop index {$this->wrap($command->index)}\";\n    }\n\n    /**\n     * Compile a drop fulltext index command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileDropFullText(Blueprint $blueprint, Fluent $command)\n    {\n        return $this->compileDropIndex($blueprint, $command);\n    }\n\n    /**\n     * Compile a drop spatial index command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileDropSpatialIndex(Blueprint $blueprint, Fluent $command)\n    {\n        return $this->compileDropIndex($blueprint, $command);\n    }\n\n    /**\n     * Compile a drop foreign key command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileDropForeign(Blueprint $blueprint, Fluent $command)\n    {\n        $index = $this->wrap($command->index);\n\n        return \"alter table {$this->wrapTable($blueprint)} drop constraint {$index}\";\n    }\n\n    /**\n     * Compile a rename table command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileRename(Blueprint $blueprint, Fluent $command)\n    {\n        $from = $this->wrapTable($blueprint);\n\n        return \"alter table {$from} rename to \".$this->wrapTable($command->to);\n    }\n\n    /**\n     * Compile a rename index command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileRenameIndex(Blueprint $blueprint, Fluent $command)\n    {\n        return sprintf('alter index %s rename to %s',\n            $this->wrap($command->from),\n            $this->wrap($command->to)\n        );\n    }\n\n    /**\n     * Compile the command to enable foreign key constraints.\n     *\n     * @return string\n     */\n    public function compileEnableForeignKeyConstraints()\n    {\n        return 'SET CONSTRAINTS ALL IMMEDIATE;';\n    }\n\n    /**\n     * Compile the command to disable foreign key constraints.\n     *\n     * @return string\n     */\n    public function compileDisableForeignKeyConstraints()\n    {\n        return 'SET CONSTRAINTS ALL DEFERRED;';\n    }\n\n    /**\n     * Compile a comment command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileComment(Blueprint $blueprint, Fluent $command)\n    {\n        return sprintf('comment on column %s.%s is %s',\n            $this->wrapTable($blueprint),\n            $this->wrap($command->column->name),\n            \"'\".str_replace(\"'\", \"''\", $command->value).\"'\"\n        );\n    }\n\n    /**\n     * Create the column definition for a char type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeChar(Fluent $column)\n    {\n        return \"char({$column->length})\";\n    }\n\n    /**\n     * Create the column definition for a string type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeString(Fluent $column)\n    {\n        return \"varchar({$column->length})\";\n    }\n\n    /**\n     * Create the column definition for a tiny text type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeTinyText(Fluent $column)\n    {\n        return 'varchar(255)';\n    }\n\n    /**\n     * Create the column definition for a text type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeText(Fluent $column)\n    {\n        return 'text';\n    }\n\n    /**\n     * Create the column definition for a medium text type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeMediumText(Fluent $column)\n    {\n        return 'text';\n    }\n\n    /**\n     * Create the column definition for a long text type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeLongText(Fluent $column)\n    {\n        return 'text';\n    }\n\n    /**\n     * Create the column definition for an integer type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeInteger(Fluent $column)\n    {\n        return $this->generatableColumn('integer', $column);\n    }\n\n    /**\n     * Create the column definition for a big integer type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeBigInteger(Fluent $column)\n    {\n        return $this->generatableColumn('bigint', $column);\n    }\n\n    /**\n     * Create the column definition for a medium integer type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeMediumInteger(Fluent $column)\n    {\n        return $this->generatableColumn('integer', $column);\n    }\n\n    /**\n     * Create the column definition for a tiny integer type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeTinyInteger(Fluent $column)\n    {\n        return $this->generatableColumn('smallint', $column);\n    }\n\n    /**\n     * Create the column definition for a small integer type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeSmallInteger(Fluent $column)\n    {\n        return $this->generatableColumn('smallint', $column);\n    }\n\n    /**\n     * Create the column definition for a generatable column.\n     *\n     * @param  string  $type\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function generatableColumn($type, Fluent $column)\n    {\n        if (! $column->autoIncrement && is_null($column->generatedAs)) {\n            return $type;\n        }\n\n        if ($column->autoIncrement && is_null($column->generatedAs)) {\n            return with([\n                'integer' => 'serial',\n                'bigint' => 'bigserial',\n                'smallint' => 'smallserial',\n            ])[$type];\n        }\n\n        $options = '';\n\n        if (! is_bool($column->generatedAs) && ! empty($column->generatedAs)) {\n            $options = sprintf(' (%s)', $column->generatedAs);\n        }\n\n        return sprintf(\n            '%s generated %s as identity%s',\n            $type,\n            $column->always ? 'always' : 'by default',\n            $options\n        );\n    }\n\n    /**\n     * Create the column definition for a float type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeFloat(Fluent $column)\n    {\n        return $this->typeDouble($column);\n    }\n\n    /**\n     * Create the column definition for a double type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeDouble(Fluent $column)\n    {\n        return 'double precision';\n    }\n\n    /**\n     * Create the column definition for a real type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeReal(Fluent $column)\n    {\n        return 'real';\n    }\n\n    /**\n     * Create the column definition for a decimal type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeDecimal(Fluent $column)\n    {\n        return \"decimal({$column->total}, {$column->places})\";\n    }\n\n    /**\n     * Create the column definition for a boolean type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeBoolean(Fluent $column)\n    {\n        return 'boolean';\n    }\n\n    /**\n     * Create the column definition for an enumeration type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeEnum(Fluent $column)\n    {\n        return sprintf(\n            'varchar(255) check (\"%s\" in (%s))',\n            $column->name,\n            $this->quoteString($column->allowed)\n        );\n    }\n\n    /**\n     * Create the column definition for a json type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeJson(Fluent $column)\n    {\n        return 'json';\n    }\n\n    /**\n     * Create the column definition for a jsonb type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeJsonb(Fluent $column)\n    {\n        return 'jsonb';\n    }\n\n    /**\n     * Create the column definition for a date type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeDate(Fluent $column)\n    {\n        return 'date';\n    }\n\n    /**\n     * Create the column definition for a date-time type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeDateTime(Fluent $column)\n    {\n        return $this->typeTimestamp($column);\n    }\n\n    /**\n     * Create the column definition for a date-time (with time zone) type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeDateTimeTz(Fluent $column)\n    {\n        return $this->typeTimestampTz($column);\n    }\n\n    /**\n     * Create the column definition for a time type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeTime(Fluent $column)\n    {\n        return 'time'.(is_null($column->precision) ? '' : \"($column->precision)\").' without time zone';\n    }\n\n    /**\n     * Create the column definition for a time (with time zone) type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeTimeTz(Fluent $column)\n    {\n        return 'time'.(is_null($column->precision) ? '' : \"($column->precision)\").' with time zone';\n    }\n\n    /**\n     * Create the column definition for a timestamp type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeTimestamp(Fluent $column)\n    {\n        $columnType = 'timestamp'.(is_null($column->precision) ? '' : \"($column->precision)\").' without time zone';\n\n        return $column->useCurrent ? \"$columnType default CURRENT_TIMESTAMP\" : $columnType;\n    }\n\n    /**\n     * Create the column definition for a timestamp (with time zone) type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeTimestampTz(Fluent $column)\n    {\n        $columnType = 'timestamp'.(is_null($column->precision) ? '' : \"($column->precision)\").' with time zone';\n\n        return $column->useCurrent ? \"$columnType default CURRENT_TIMESTAMP\" : $columnType;\n    }\n\n    /**\n     * Create the column definition for a year type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeYear(Fluent $column)\n    {\n        return $this->typeInteger($column);\n    }\n\n    /**\n     * Create the column definition for a binary type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeBinary(Fluent $column)\n    {\n        return 'bytea';\n    }\n\n    /**\n     * Create the column definition for a uuid type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeUuid(Fluent $column)\n    {\n        return 'uuid';\n    }\n\n    /**\n     * Create the column definition for an IP address type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeIpAddress(Fluent $column)\n    {\n        return 'inet';\n    }\n\n    /**\n     * Create the column definition for a MAC address type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeMacAddress(Fluent $column)\n    {\n        return 'macaddr';\n    }\n\n    /**\n     * Create the column definition for a spatial Geometry type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeGeometry(Fluent $column)\n    {\n        return $this->formatPostGisType('geometry', $column);\n    }\n\n    /**\n     * Create the column definition for a spatial Point type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typePoint(Fluent $column)\n    {\n        return $this->formatPostGisType('point', $column);\n    }\n\n    /**\n     * Create the column definition for a spatial LineString type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeLineString(Fluent $column)\n    {\n        return $this->formatPostGisType('linestring', $column);\n    }\n\n    /**\n     * Create the column definition for a spatial Polygon type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typePolygon(Fluent $column)\n    {\n        return $this->formatPostGisType('polygon', $column);\n    }\n\n    /**\n     * Create the column definition for a spatial GeometryCollection type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeGeometryCollection(Fluent $column)\n    {\n        return $this->formatPostGisType('geometrycollection', $column);\n    }\n\n    /**\n     * Create the column definition for a spatial MultiPoint type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeMultiPoint(Fluent $column)\n    {\n        return $this->formatPostGisType('multipoint', $column);\n    }\n\n    /**\n     * Create the column definition for a spatial MultiLineString type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    public function typeMultiLineString(Fluent $column)\n    {\n        return $this->formatPostGisType('multilinestring', $column);\n    }\n\n    /**\n     * Create the column definition for a spatial MultiPolygon type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeMultiPolygon(Fluent $column)\n    {\n        return $this->formatPostGisType('multipolygon', $column);\n    }\n\n    /**\n     * Create the column definition for a spatial MultiPolygonZ type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeMultiPolygonZ(Fluent $column)\n    {\n        return $this->formatPostGisType('multipolygonz', $column);\n    }\n\n    /**\n     * Format the column definition for a PostGIS spatial type.\n     *\n     * @param  string  $type\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    private function formatPostGisType($type, Fluent $column)\n    {\n        if ($column->isGeometry === null) {\n            return sprintf('geography(%s, %s)', $type, $column->projection ?? '4326');\n        }\n\n        if ($column->projection !== null) {\n            return sprintf('geometry(%s, %s)', $type, $column->projection);\n        }\n\n        return \"geometry({$type})\";\n    }\n\n    /**\n     * Get the SQL for a collation column modifier.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string|null\n     */\n    protected function modifyCollate(Blueprint $blueprint, Fluent $column)\n    {\n        if (! is_null($column->collation)) {\n            return ' collate '.$this->wrapValue($column->collation);\n        }\n    }\n\n    /**\n     * Get the SQL for a nullable column modifier.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string|null\n     */\n    protected function modifyNullable(Blueprint $blueprint, Fluent $column)\n    {\n        return $column->nullable ? ' null' : ' not null';\n    }\n\n    /**\n     * Get the SQL for a default column modifier.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string|null\n     */\n    protected function modifyDefault(Blueprint $blueprint, Fluent $column)\n    {\n        if (! is_null($column->default)) {\n            return ' default '.$this->getDefaultValue($column->default);\n        }\n    }\n\n    /**\n     * Get the SQL for an auto-increment column modifier.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string|null\n     */\n    protected function modifyIncrement(Blueprint $blueprint, Fluent $column)\n    {\n        if ((in_array($column->type, $this->serials) || ($column->generatedAs !== null)) && $column->autoIncrement) {\n            return ' primary key';\n        }\n    }\n\n    /**\n     * Get the SQL for a generated virtual column modifier.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string|null\n     */\n    protected function modifyVirtualAs(Blueprint $blueprint, Fluent $column)\n    {\n        if ($column->virtualAs !== null) {\n            return \" generated always as ({$column->virtualAs})\";\n        }\n    }\n\n    /**\n     * Get the SQL for a generated stored column modifier.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string|null\n     */\n    protected function modifyStoredAs(Blueprint $blueprint, Fluent $column)\n    {\n        if ($column->storedAs !== null) {\n            return \" generated always as ({$column->storedAs}) stored\";\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Schema/Grammars/RenameColumn.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Schema\\Grammars;\n\nuse Doctrine\\DBAL\\Schema\\AbstractSchemaManager as SchemaManager;\nuse Doctrine\\DBAL\\Schema\\Column;\nuse Doctrine\\DBAL\\Schema\\TableDiff;\nuse Illuminate\\Database\\Connection;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Fluent;\n\nclass RenameColumn\n{\n    /**\n     * Compile a rename column command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Grammars\\Grammar  $grammar\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @param  \\Illuminate\\Database\\Connection  $connection\n     * @return array\n     */\n    public static function compile(Grammar $grammar, Blueprint $blueprint, Fluent $command, Connection $connection)\n    {\n        $schema = $connection->getDoctrineSchemaManager();\n        $databasePlatform = $schema->getDatabasePlatform();\n        $databasePlatform->registerDoctrineTypeMapping('enum', 'string');\n\n        $column = $connection->getDoctrineColumn(\n            $grammar->getTablePrefix().$blueprint->getTable(), $command->from\n        );\n\n        return (array) $databasePlatform->getAlterTableSQL(static::getRenamedDiff(\n            $grammar, $blueprint, $command, $column, $schema\n        ));\n    }\n\n    /**\n     * Get a new column instance with the new column name.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Grammars\\Grammar  $grammar\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @param  \\Doctrine\\DBAL\\Schema\\Column  $column\n     * @param  \\Doctrine\\DBAL\\Schema\\AbstractSchemaManager  $schema\n     * @return \\Doctrine\\DBAL\\Schema\\TableDiff\n     */\n    protected static function getRenamedDiff(Grammar $grammar, Blueprint $blueprint, Fluent $command, Column $column, SchemaManager $schema)\n    {\n        return static::setRenamedColumns(\n            $grammar->getDoctrineTableDiff($blueprint, $schema), $command, $column\n        );\n    }\n\n    /**\n     * Set the renamed columns on the table diff.\n     *\n     * @param  \\Doctrine\\DBAL\\Schema\\TableDiff  $tableDiff\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @param  \\Doctrine\\DBAL\\Schema\\Column  $column\n     * @return \\Doctrine\\DBAL\\Schema\\TableDiff\n     */\n    protected static function setRenamedColumns(TableDiff $tableDiff, Fluent $command, Column $column)\n    {\n        $tableDiff->renamedColumns = [\n            $command->from => new Column($command->to, $column->getType(), self::getWritableColumnOptions($column)),\n        ];\n\n        return $tableDiff;\n    }\n\n    /**\n     * Get the writable column options.\n     *\n     * @param  \\Doctrine\\DBAL\\Schema\\Column  $column\n     * @return array\n     */\n    private static function getWritableColumnOptions(Column $column)\n    {\n        return array_filter($column->toArray(), function (string $name) use ($column) {\n            return method_exists($column, 'set'.$name);\n        }, ARRAY_FILTER_USE_KEY);\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Schema/Grammars/SQLiteGrammar.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Schema\\Grammars;\n\nuse Doctrine\\DBAL\\Schema\\Index;\nuse Illuminate\\Database\\Connection;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Arr;\nuse Illuminate\\Support\\Fluent;\nuse RuntimeException;\n\nclass SQLiteGrammar extends Grammar\n{\n    /**\n     * The possible column modifiers.\n     *\n     * @var string[]\n     */\n    protected $modifiers = ['VirtualAs', 'StoredAs', 'Nullable', 'Default', 'Increment'];\n\n    /**\n     * The columns available as serials.\n     *\n     * @var string[]\n     */\n    protected $serials = ['bigInteger', 'integer', 'mediumInteger', 'smallInteger', 'tinyInteger'];\n\n    /**\n     * Compile the query to determine if a table exists.\n     *\n     * @return string\n     */\n    public function compileTableExists()\n    {\n        return \"select * from sqlite_master where type = 'table' and name = ?\";\n    }\n\n    /**\n     * Compile the query to determine the list of columns.\n     *\n     * @param  string  $table\n     * @return string\n     */\n    public function compileColumnListing($table)\n    {\n        return 'pragma table_info('.$this->wrap(str_replace('.', '__', $table)).')';\n    }\n\n    /**\n     * Compile a create table command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileCreate(Blueprint $blueprint, Fluent $command)\n    {\n        return sprintf('%s table %s (%s%s%s)',\n            $blueprint->temporary ? 'create temporary' : 'create',\n            $this->wrapTable($blueprint),\n            implode(', ', $this->getColumns($blueprint)),\n            (string) $this->addForeignKeys($blueprint),\n            (string) $this->addPrimaryKeys($blueprint)\n        );\n    }\n\n    /**\n     * Get the foreign key syntax for a table creation statement.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @return string|null\n     */\n    protected function addForeignKeys(Blueprint $blueprint)\n    {\n        $foreigns = $this->getCommandsByName($blueprint, 'foreign');\n\n        return collect($foreigns)->reduce(function ($sql, $foreign) {\n            // Once we have all the foreign key commands for the table creation statement\n            // we'll loop through each of them and add them to the create table SQL we\n            // are building, since SQLite needs foreign keys on the tables creation.\n            $sql .= $this->getForeignKey($foreign);\n\n            if (! is_null($foreign->onDelete)) {\n                $sql .= \" on delete {$foreign->onDelete}\";\n            }\n\n            // If this foreign key specifies the action to be taken on update we will add\n            // that to the statement here. We'll append it to this SQL and then return\n            // the SQL so we can keep adding any other foreign constraints onto this.\n            if (! is_null($foreign->onUpdate)) {\n                $sql .= \" on update {$foreign->onUpdate}\";\n            }\n\n            return $sql;\n        }, '');\n    }\n\n    /**\n     * Get the SQL for the foreign key.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $foreign\n     * @return string\n     */\n    protected function getForeignKey($foreign)\n    {\n        // We need to columnize the columns that the foreign key is being defined for\n        // so that it is a properly formatted list. Once we have done this, we can\n        // return the foreign key SQL declaration to the calling method for use.\n        return sprintf(', foreign key(%s) references %s(%s)',\n            $this->columnize($foreign->columns),\n            $this->wrapTable($foreign->on),\n            $this->columnize((array) $foreign->references)\n        );\n    }\n\n    /**\n     * Get the primary key syntax for a table creation statement.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @return string|null\n     */\n    protected function addPrimaryKeys(Blueprint $blueprint)\n    {\n        if (! is_null($primary = $this->getCommandByName($blueprint, 'primary'))) {\n            return \", primary key ({$this->columnize($primary->columns)})\";\n        }\n    }\n\n    /**\n     * Compile alter table commands for adding columns.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return array\n     */\n    public function compileAdd(Blueprint $blueprint, Fluent $command)\n    {\n        $columns = $this->prefixArray('add column', $this->getColumns($blueprint));\n\n        return collect($columns)->reject(function ($column) {\n            return preg_match('/as \\(.*\\) stored/', $column) > 0;\n        })->map(function ($column) use ($blueprint) {\n            return 'alter table '.$this->wrapTable($blueprint).' '.$column;\n        })->all();\n    }\n\n    /**\n     * Compile a unique key command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileUnique(Blueprint $blueprint, Fluent $command)\n    {\n        return sprintf('create unique index %s on %s (%s)',\n            $this->wrap($command->index),\n            $this->wrapTable($blueprint),\n            $this->columnize($command->columns)\n        );\n    }\n\n    /**\n     * Compile a plain index key command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileIndex(Blueprint $blueprint, Fluent $command)\n    {\n        return sprintf('create index %s on %s (%s)',\n            $this->wrap($command->index),\n            $this->wrapTable($blueprint),\n            $this->columnize($command->columns)\n        );\n    }\n\n    /**\n     * Compile a spatial index key command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return void\n     *\n     * @throws \\RuntimeException\n     */\n    public function compileSpatialIndex(Blueprint $blueprint, Fluent $command)\n    {\n        throw new RuntimeException('The database driver in use does not support spatial indexes.');\n    }\n\n    /**\n     * Compile a foreign key command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileForeign(Blueprint $blueprint, Fluent $command)\n    {\n        // Handled on table creation...\n    }\n\n    /**\n     * Compile a drop table command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileDrop(Blueprint $blueprint, Fluent $command)\n    {\n        return 'drop table '.$this->wrapTable($blueprint);\n    }\n\n    /**\n     * Compile a drop table (if exists) command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileDropIfExists(Blueprint $blueprint, Fluent $command)\n    {\n        return 'drop table if exists '.$this->wrapTable($blueprint);\n    }\n\n    /**\n     * Compile the SQL needed to drop all tables.\n     *\n     * @return string\n     */\n    public function compileDropAllTables()\n    {\n        return \"delete from sqlite_master where type in ('table', 'index', 'trigger')\";\n    }\n\n    /**\n     * Compile the SQL needed to drop all views.\n     *\n     * @return string\n     */\n    public function compileDropAllViews()\n    {\n        return \"delete from sqlite_master where type in ('view')\";\n    }\n\n    /**\n     * Compile the SQL needed to rebuild the database.\n     *\n     * @return string\n     */\n    public function compileRebuild()\n    {\n        return 'vacuum';\n    }\n\n    /**\n     * Compile a drop column command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @param  \\Illuminate\\Database\\Connection  $connection\n     * @return array\n     */\n    public function compileDropColumn(Blueprint $blueprint, Fluent $command, Connection $connection)\n    {\n        $tableDiff = $this->getDoctrineTableDiff(\n            $blueprint, $schema = $connection->getDoctrineSchemaManager()\n        );\n\n        foreach ($command->columns as $name) {\n            $tableDiff->removedColumns[$name] = $connection->getDoctrineColumn(\n                $this->getTablePrefix().$blueprint->getTable(), $name\n            );\n        }\n\n        return (array) $schema->getDatabasePlatform()->getAlterTableSQL($tableDiff);\n    }\n\n    /**\n     * Compile a drop unique key command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileDropUnique(Blueprint $blueprint, Fluent $command)\n    {\n        $index = $this->wrap($command->index);\n\n        return \"drop index {$index}\";\n    }\n\n    /**\n     * Compile a drop index command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileDropIndex(Blueprint $blueprint, Fluent $command)\n    {\n        $index = $this->wrap($command->index);\n\n        return \"drop index {$index}\";\n    }\n\n    /**\n     * Compile a drop spatial index command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return void\n     *\n     * @throws \\RuntimeException\n     */\n    public function compileDropSpatialIndex(Blueprint $blueprint, Fluent $command)\n    {\n        throw new RuntimeException('The database driver in use does not support spatial indexes.');\n    }\n\n    /**\n     * Compile a rename table command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileRename(Blueprint $blueprint, Fluent $command)\n    {\n        $from = $this->wrapTable($blueprint);\n\n        return \"alter table {$from} rename to \".$this->wrapTable($command->to);\n    }\n\n    /**\n     * Compile a rename index command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @param  \\Illuminate\\Database\\Connection  $connection\n     * @return array\n     *\n     * @throws \\RuntimeException\n     */\n    public function compileRenameIndex(Blueprint $blueprint, Fluent $command, Connection $connection)\n    {\n        $schemaManager = $connection->getDoctrineSchemaManager();\n\n        $indexes = $schemaManager->listTableIndexes($this->getTablePrefix().$blueprint->getTable());\n\n        $index = Arr::get($indexes, $command->from);\n\n        if (! $index) {\n            throw new RuntimeException(\"Index [{$command->from}] does not exist.\");\n        }\n\n        $newIndex = new Index(\n            $command->to, $index->getColumns(), $index->isUnique(),\n            $index->isPrimary(), $index->getFlags(), $index->getOptions()\n        );\n\n        $platform = $schemaManager->getDatabasePlatform();\n\n        return [\n            $platform->getDropIndexSQL($command->from, $this->getTablePrefix().$blueprint->getTable()),\n            $platform->getCreateIndexSQL($newIndex, $this->getTablePrefix().$blueprint->getTable()),\n        ];\n    }\n\n    /**\n     * Compile the command to enable foreign key constraints.\n     *\n     * @return string\n     */\n    public function compileEnableForeignKeyConstraints()\n    {\n        return 'PRAGMA foreign_keys = ON;';\n    }\n\n    /**\n     * Compile the command to disable foreign key constraints.\n     *\n     * @return string\n     */\n    public function compileDisableForeignKeyConstraints()\n    {\n        return 'PRAGMA foreign_keys = OFF;';\n    }\n\n    /**\n     * Compile the SQL needed to enable a writable schema.\n     *\n     * @return string\n     */\n    public function compileEnableWriteableSchema()\n    {\n        return 'PRAGMA writable_schema = 1;';\n    }\n\n    /**\n     * Compile the SQL needed to disable a writable schema.\n     *\n     * @return string\n     */\n    public function compileDisableWriteableSchema()\n    {\n        return 'PRAGMA writable_schema = 0;';\n    }\n\n    /**\n     * Create the column definition for a char type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeChar(Fluent $column)\n    {\n        return 'varchar';\n    }\n\n    /**\n     * Create the column definition for a string type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeString(Fluent $column)\n    {\n        return 'varchar';\n    }\n\n    /**\n     * Create the column definition for a tiny text type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeTinyText(Fluent $column)\n    {\n        return 'text';\n    }\n\n    /**\n     * Create the column definition for a text type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeText(Fluent $column)\n    {\n        return 'text';\n    }\n\n    /**\n     * Create the column definition for a medium text type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeMediumText(Fluent $column)\n    {\n        return 'text';\n    }\n\n    /**\n     * Create the column definition for a long text type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeLongText(Fluent $column)\n    {\n        return 'text';\n    }\n\n    /**\n     * Create the column definition for an integer type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeInteger(Fluent $column)\n    {\n        return 'integer';\n    }\n\n    /**\n     * Create the column definition for a big integer type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeBigInteger(Fluent $column)\n    {\n        return 'integer';\n    }\n\n    /**\n     * Create the column definition for a medium integer type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeMediumInteger(Fluent $column)\n    {\n        return 'integer';\n    }\n\n    /**\n     * Create the column definition for a tiny integer type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeTinyInteger(Fluent $column)\n    {\n        return 'integer';\n    }\n\n    /**\n     * Create the column definition for a small integer type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeSmallInteger(Fluent $column)\n    {\n        return 'integer';\n    }\n\n    /**\n     * Create the column definition for a float type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeFloat(Fluent $column)\n    {\n        return 'float';\n    }\n\n    /**\n     * Create the column definition for a double type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeDouble(Fluent $column)\n    {\n        return 'float';\n    }\n\n    /**\n     * Create the column definition for a decimal type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeDecimal(Fluent $column)\n    {\n        return 'numeric';\n    }\n\n    /**\n     * Create the column definition for a boolean type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeBoolean(Fluent $column)\n    {\n        return 'tinyint(1)';\n    }\n\n    /**\n     * Create the column definition for an enumeration type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeEnum(Fluent $column)\n    {\n        return sprintf(\n            'varchar check (\"%s\" in (%s))',\n            $column->name,\n            $this->quoteString($column->allowed)\n        );\n    }\n\n    /**\n     * Create the column definition for a json type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeJson(Fluent $column)\n    {\n        return 'text';\n    }\n\n    /**\n     * Create the column definition for a jsonb type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeJsonb(Fluent $column)\n    {\n        return 'text';\n    }\n\n    /**\n     * Create the column definition for a date type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeDate(Fluent $column)\n    {\n        return 'date';\n    }\n\n    /**\n     * Create the column definition for a date-time type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeDateTime(Fluent $column)\n    {\n        return $this->typeTimestamp($column);\n    }\n\n    /**\n     * Create the column definition for a date-time (with time zone) type.\n     *\n     * Note: \"SQLite does not have a storage class set aside for storing dates and/or times.\"\n     *\n     * @link https://www.sqlite.org/datatype3.html\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeDateTimeTz(Fluent $column)\n    {\n        return $this->typeDateTime($column);\n    }\n\n    /**\n     * Create the column definition for a time type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeTime(Fluent $column)\n    {\n        return 'time';\n    }\n\n    /**\n     * Create the column definition for a time (with time zone) type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeTimeTz(Fluent $column)\n    {\n        return $this->typeTime($column);\n    }\n\n    /**\n     * Create the column definition for a timestamp type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeTimestamp(Fluent $column)\n    {\n        return $column->useCurrent ? 'datetime default CURRENT_TIMESTAMP' : 'datetime';\n    }\n\n    /**\n     * Create the column definition for a timestamp (with time zone) type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeTimestampTz(Fluent $column)\n    {\n        return $this->typeTimestamp($column);\n    }\n\n    /**\n     * Create the column definition for a year type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeYear(Fluent $column)\n    {\n        return $this->typeInteger($column);\n    }\n\n    /**\n     * Create the column definition for a binary type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeBinary(Fluent $column)\n    {\n        return 'blob';\n    }\n\n    /**\n     * Create the column definition for a uuid type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeUuid(Fluent $column)\n    {\n        return 'varchar';\n    }\n\n    /**\n     * Create the column definition for an IP address type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeIpAddress(Fluent $column)\n    {\n        return 'varchar';\n    }\n\n    /**\n     * Create the column definition for a MAC address type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeMacAddress(Fluent $column)\n    {\n        return 'varchar';\n    }\n\n    /**\n     * Create the column definition for a spatial Geometry type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    public function typeGeometry(Fluent $column)\n    {\n        return 'geometry';\n    }\n\n    /**\n     * Create the column definition for a spatial Point type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    public function typePoint(Fluent $column)\n    {\n        return 'point';\n    }\n\n    /**\n     * Create the column definition for a spatial LineString type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    public function typeLineString(Fluent $column)\n    {\n        return 'linestring';\n    }\n\n    /**\n     * Create the column definition for a spatial Polygon type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    public function typePolygon(Fluent $column)\n    {\n        return 'polygon';\n    }\n\n    /**\n     * Create the column definition for a spatial GeometryCollection type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    public function typeGeometryCollection(Fluent $column)\n    {\n        return 'geometrycollection';\n    }\n\n    /**\n     * Create the column definition for a spatial MultiPoint type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    public function typeMultiPoint(Fluent $column)\n    {\n        return 'multipoint';\n    }\n\n    /**\n     * Create the column definition for a spatial MultiLineString type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    public function typeMultiLineString(Fluent $column)\n    {\n        return 'multilinestring';\n    }\n\n    /**\n     * Create the column definition for a spatial MultiPolygon type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    public function typeMultiPolygon(Fluent $column)\n    {\n        return 'multipolygon';\n    }\n\n    /**\n     * Create the column definition for a generated, computed column type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return void\n     *\n     * @throws \\RuntimeException\n     */\n    protected function typeComputed(Fluent $column)\n    {\n        throw new RuntimeException('This database driver requires a type, see the virtualAs / storedAs modifiers.');\n    }\n\n    /**\n     * Get the SQL for a generated virtual column modifier.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string|null\n     */\n    protected function modifyVirtualAs(Blueprint $blueprint, Fluent $column)\n    {\n        if (! is_null($column->virtualAs)) {\n            return \" as ({$column->virtualAs})\";\n        }\n    }\n\n    /**\n     * Get the SQL for a generated stored column modifier.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string|null\n     */\n    protected function modifyStoredAs(Blueprint $blueprint, Fluent $column)\n    {\n        if (! is_null($column->storedAs)) {\n            return \" as ({$column->storedAs}) stored\";\n        }\n    }\n\n    /**\n     * Get the SQL for a nullable column modifier.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string|null\n     */\n    protected function modifyNullable(Blueprint $blueprint, Fluent $column)\n    {\n        if (is_null($column->virtualAs) && is_null($column->storedAs)) {\n            return $column->nullable ? '' : ' not null';\n        }\n\n        if ($column->nullable === false) {\n            return ' not null';\n        }\n    }\n\n    /**\n     * Get the SQL for a default column modifier.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string|null\n     */\n    protected function modifyDefault(Blueprint $blueprint, Fluent $column)\n    {\n        if (! is_null($column->default) && is_null($column->virtualAs) && is_null($column->storedAs)) {\n            return ' default '.$this->getDefaultValue($column->default);\n        }\n    }\n\n    /**\n     * Get the SQL for an auto-increment column modifier.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string|null\n     */\n    protected function modifyIncrement(Blueprint $blueprint, Fluent $column)\n    {\n        if (in_array($column->type, $this->serials) && $column->autoIncrement) {\n            return ' primary key autoincrement';\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Schema/Grammars/SqlServerGrammar.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Schema\\Grammars;\n\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Fluent;\n\nclass SqlServerGrammar extends Grammar\n{\n    /**\n     * If this Grammar supports schema changes wrapped in a transaction.\n     *\n     * @var bool\n     */\n    protected $transactions = true;\n\n    /**\n     * The possible column modifiers.\n     *\n     * @var string[]\n     */\n    protected $modifiers = ['Increment', 'Collate', 'Nullable', 'Default', 'Persisted'];\n\n    /**\n     * The columns available as serials.\n     *\n     * @var string[]\n     */\n    protected $serials = ['tinyInteger', 'smallInteger', 'mediumInteger', 'integer', 'bigInteger'];\n\n    /**\n     * Compile a create database command.\n     *\n     * @param  string  $name\n     * @param  \\Illuminate\\Database\\Connection  $connection\n     * @return string\n     */\n    public function compileCreateDatabase($name, $connection)\n    {\n        return sprintf(\n            'create database %s',\n            $this->wrapValue($name),\n        );\n    }\n\n    /**\n     * Compile a drop database if exists command.\n     *\n     * @param  string  $name\n     * @return string\n     */\n    public function compileDropDatabaseIfExists($name)\n    {\n        return sprintf(\n            'drop database if exists %s',\n            $this->wrapValue($name)\n        );\n    }\n\n    /**\n     * Compile the query to determine if a table exists.\n     *\n     * @return string\n     */\n    public function compileTableExists()\n    {\n        return \"select * from sys.sysobjects where id = object_id(?) and xtype in ('U', 'V')\";\n    }\n\n    /**\n     * Compile the query to determine the list of columns.\n     *\n     * @param  string  $table\n     * @return string\n     */\n    public function compileColumnListing($table)\n    {\n        return \"select name from sys.columns where object_id = object_id('$table')\";\n    }\n\n    /**\n     * Compile a create table command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileCreate(Blueprint $blueprint, Fluent $command)\n    {\n        $columns = implode(', ', $this->getColumns($blueprint));\n\n        return 'create table '.$this->wrapTable($blueprint).\" ($columns)\";\n    }\n\n    /**\n     * Compile a column addition table command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileAdd(Blueprint $blueprint, Fluent $command)\n    {\n        return sprintf('alter table %s add %s',\n            $this->wrapTable($blueprint),\n            implode(', ', $this->getColumns($blueprint))\n        );\n    }\n\n    /**\n     * Compile a primary key command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compilePrimary(Blueprint $blueprint, Fluent $command)\n    {\n        return sprintf('alter table %s add constraint %s primary key (%s)',\n            $this->wrapTable($blueprint),\n            $this->wrap($command->index),\n            $this->columnize($command->columns)\n        );\n    }\n\n    /**\n     * Compile a unique key command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileUnique(Blueprint $blueprint, Fluent $command)\n    {\n        return sprintf('create unique index %s on %s (%s)',\n            $this->wrap($command->index),\n            $this->wrapTable($blueprint),\n            $this->columnize($command->columns)\n        );\n    }\n\n    /**\n     * Compile a plain index key command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileIndex(Blueprint $blueprint, Fluent $command)\n    {\n        return sprintf('create index %s on %s (%s)',\n            $this->wrap($command->index),\n            $this->wrapTable($blueprint),\n            $this->columnize($command->columns)\n        );\n    }\n\n    /**\n     * Compile a spatial index key command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileSpatialIndex(Blueprint $blueprint, Fluent $command)\n    {\n        return sprintf('create spatial index %s on %s (%s)',\n            $this->wrap($command->index),\n            $this->wrapTable($blueprint),\n            $this->columnize($command->columns)\n        );\n    }\n\n    /**\n     * Compile a drop table command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileDrop(Blueprint $blueprint, Fluent $command)\n    {\n        return 'drop table '.$this->wrapTable($blueprint);\n    }\n\n    /**\n     * Compile a drop table (if exists) command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileDropIfExists(Blueprint $blueprint, Fluent $command)\n    {\n        return sprintf('if exists (select * from sys.sysobjects where id = object_id(%s, \\'U\\')) drop table %s',\n            \"'\".str_replace(\"'\", \"''\", $this->getTablePrefix().$blueprint->getTable()).\"'\",\n            $this->wrapTable($blueprint)\n        );\n    }\n\n    /**\n     * Compile the SQL needed to drop all tables.\n     *\n     * @return string\n     */\n    public function compileDropAllTables()\n    {\n        return \"EXEC sp_msforeachtable 'DROP TABLE ?'\";\n    }\n\n    /**\n     * Compile a drop column command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileDropColumn(Blueprint $blueprint, Fluent $command)\n    {\n        $columns = $this->wrapArray($command->columns);\n\n        $dropExistingConstraintsSql = $this->compileDropDefaultConstraint($blueprint, $command).';';\n\n        return $dropExistingConstraintsSql.'alter table '.$this->wrapTable($blueprint).' drop column '.implode(', ', $columns);\n    }\n\n    /**\n     * Compile a drop default constraint command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileDropDefaultConstraint(Blueprint $blueprint, Fluent $command)\n    {\n        $columns = \"'\".implode(\"','\", $command->columns).\"'\";\n\n        $tableName = $this->getTablePrefix().$blueprint->getTable();\n\n        $sql = \"DECLARE @sql NVARCHAR(MAX) = '';\";\n        $sql .= \"SELECT @sql += 'ALTER TABLE [dbo].[{$tableName}] DROP CONSTRAINT ' + OBJECT_NAME([default_object_id]) + ';' \";\n        $sql .= 'FROM sys.columns ';\n        $sql .= \"WHERE [object_id] = OBJECT_ID('[dbo].[{$tableName}]') AND [name] in ({$columns}) AND [default_object_id] <> 0;\";\n        $sql .= 'EXEC(@sql)';\n\n        return $sql;\n    }\n\n    /**\n     * Compile a drop primary key command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileDropPrimary(Blueprint $blueprint, Fluent $command)\n    {\n        $index = $this->wrap($command->index);\n\n        return \"alter table {$this->wrapTable($blueprint)} drop constraint {$index}\";\n    }\n\n    /**\n     * Compile a drop unique key command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileDropUnique(Blueprint $blueprint, Fluent $command)\n    {\n        $index = $this->wrap($command->index);\n\n        return \"drop index {$index} on {$this->wrapTable($blueprint)}\";\n    }\n\n    /**\n     * Compile a drop index command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileDropIndex(Blueprint $blueprint, Fluent $command)\n    {\n        $index = $this->wrap($command->index);\n\n        return \"drop index {$index} on {$this->wrapTable($blueprint)}\";\n    }\n\n    /**\n     * Compile a drop spatial index command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileDropSpatialIndex(Blueprint $blueprint, Fluent $command)\n    {\n        return $this->compileDropIndex($blueprint, $command);\n    }\n\n    /**\n     * Compile a drop foreign key command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileDropForeign(Blueprint $blueprint, Fluent $command)\n    {\n        $index = $this->wrap($command->index);\n\n        return \"alter table {$this->wrapTable($blueprint)} drop constraint {$index}\";\n    }\n\n    /**\n     * Compile a rename table command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileRename(Blueprint $blueprint, Fluent $command)\n    {\n        $from = $this->wrapTable($blueprint);\n\n        return \"sp_rename {$from}, \".$this->wrapTable($command->to);\n    }\n\n    /**\n     * Compile a rename index command.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $command\n     * @return string\n     */\n    public function compileRenameIndex(Blueprint $blueprint, Fluent $command)\n    {\n        return sprintf(\"sp_rename N'%s', %s, N'INDEX'\",\n            $this->wrap($blueprint->getTable().'.'.$command->from),\n            $this->wrap($command->to)\n        );\n    }\n\n    /**\n     * Compile the command to enable foreign key constraints.\n     *\n     * @return string\n     */\n    public function compileEnableForeignKeyConstraints()\n    {\n        return 'EXEC sp_msforeachtable @command1=\"print \\'?\\'\", @command2=\"ALTER TABLE ? WITH CHECK CHECK CONSTRAINT all\";';\n    }\n\n    /**\n     * Compile the command to disable foreign key constraints.\n     *\n     * @return string\n     */\n    public function compileDisableForeignKeyConstraints()\n    {\n        return 'EXEC sp_msforeachtable \"ALTER TABLE ? NOCHECK CONSTRAINT all\";';\n    }\n\n    /**\n     * Compile the command to drop all foreign keys.\n     *\n     * @return string\n     */\n    public function compileDropAllForeignKeys()\n    {\n        return \"DECLARE @sql NVARCHAR(MAX) = N'';\n            SELECT @sql += 'ALTER TABLE '\n                + QUOTENAME(OBJECT_SCHEMA_NAME(parent_object_id)) + '.' + + QUOTENAME(OBJECT_NAME(parent_object_id))\n                + ' DROP CONSTRAINT ' + QUOTENAME(name) + ';'\n            FROM sys.foreign_keys;\n\n            EXEC sp_executesql @sql;\";\n    }\n\n    /**\n     * Compile the command to drop all views.\n     *\n     * @return string\n     */\n    public function compileDropAllViews()\n    {\n        return \"DECLARE @sql NVARCHAR(MAX) = N'';\n            SELECT @sql += 'DROP VIEW ' + QUOTENAME(OBJECT_SCHEMA_NAME(object_id)) + '.' + QUOTENAME(name) + ';'\n            FROM sys.views;\n\n            EXEC sp_executesql @sql;\";\n    }\n\n    /**\n     * Create the column definition for a char type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeChar(Fluent $column)\n    {\n        return \"nchar({$column->length})\";\n    }\n\n    /**\n     * Create the column definition for a string type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeString(Fluent $column)\n    {\n        return \"nvarchar({$column->length})\";\n    }\n\n    /**\n     * Create the column definition for a tiny text type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeTinyText(Fluent $column)\n    {\n        return 'nvarchar(255)';\n    }\n\n    /**\n     * Create the column definition for a text type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeText(Fluent $column)\n    {\n        return 'nvarchar(max)';\n    }\n\n    /**\n     * Create the column definition for a medium text type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeMediumText(Fluent $column)\n    {\n        return 'nvarchar(max)';\n    }\n\n    /**\n     * Create the column definition for a long text type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeLongText(Fluent $column)\n    {\n        return 'nvarchar(max)';\n    }\n\n    /**\n     * Create the column definition for an integer type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeInteger(Fluent $column)\n    {\n        return 'int';\n    }\n\n    /**\n     * Create the column definition for a big integer type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeBigInteger(Fluent $column)\n    {\n        return 'bigint';\n    }\n\n    /**\n     * Create the column definition for a medium integer type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeMediumInteger(Fluent $column)\n    {\n        return 'int';\n    }\n\n    /**\n     * Create the column definition for a tiny integer type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeTinyInteger(Fluent $column)\n    {\n        return 'tinyint';\n    }\n\n    /**\n     * Create the column definition for a small integer type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeSmallInteger(Fluent $column)\n    {\n        return 'smallint';\n    }\n\n    /**\n     * Create the column definition for a float type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeFloat(Fluent $column)\n    {\n        return 'float';\n    }\n\n    /**\n     * Create the column definition for a double type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeDouble(Fluent $column)\n    {\n        return 'float';\n    }\n\n    /**\n     * Create the column definition for a decimal type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeDecimal(Fluent $column)\n    {\n        return \"decimal({$column->total}, {$column->places})\";\n    }\n\n    /**\n     * Create the column definition for a boolean type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeBoolean(Fluent $column)\n    {\n        return 'bit';\n    }\n\n    /**\n     * Create the column definition for an enumeration type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeEnum(Fluent $column)\n    {\n        return sprintf(\n            'nvarchar(255) check (\"%s\" in (%s))',\n            $column->name,\n            $this->quoteString($column->allowed)\n        );\n    }\n\n    /**\n     * Create the column definition for a json type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeJson(Fluent $column)\n    {\n        return 'nvarchar(max)';\n    }\n\n    /**\n     * Create the column definition for a jsonb type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeJsonb(Fluent $column)\n    {\n        return 'nvarchar(max)';\n    }\n\n    /**\n     * Create the column definition for a date type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeDate(Fluent $column)\n    {\n        return 'date';\n    }\n\n    /**\n     * Create the column definition for a date-time type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeDateTime(Fluent $column)\n    {\n        return $this->typeTimestamp($column);\n    }\n\n    /**\n     * Create the column definition for a date-time (with time zone) type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeDateTimeTz(Fluent $column)\n    {\n        return $this->typeTimestampTz($column);\n    }\n\n    /**\n     * Create the column definition for a time type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeTime(Fluent $column)\n    {\n        return $column->precision ? \"time($column->precision)\" : 'time';\n    }\n\n    /**\n     * Create the column definition for a time (with time zone) type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeTimeTz(Fluent $column)\n    {\n        return $this->typeTime($column);\n    }\n\n    /**\n     * Create the column definition for a timestamp type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeTimestamp(Fluent $column)\n    {\n        $columnType = $column->precision ? \"datetime2($column->precision)\" : 'datetime';\n\n        return $column->useCurrent ? \"$columnType default CURRENT_TIMESTAMP\" : $columnType;\n    }\n\n    /**\n     * Create the column definition for a timestamp (with time zone) type.\n     *\n     * @link https://docs.microsoft.com/en-us/sql/t-sql/data-types/datetimeoffset-transact-sql?view=sql-server-ver15\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeTimestampTz(Fluent $column)\n    {\n        $columnType = $column->precision ? \"datetimeoffset($column->precision)\" : 'datetimeoffset';\n\n        return $column->useCurrent ? \"$columnType default CURRENT_TIMESTAMP\" : $columnType;\n    }\n\n    /**\n     * Create the column definition for a year type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeYear(Fluent $column)\n    {\n        return $this->typeInteger($column);\n    }\n\n    /**\n     * Create the column definition for a binary type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeBinary(Fluent $column)\n    {\n        return 'varbinary(max)';\n    }\n\n    /**\n     * Create the column definition for a uuid type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeUuid(Fluent $column)\n    {\n        return 'uniqueidentifier';\n    }\n\n    /**\n     * Create the column definition for an IP address type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeIpAddress(Fluent $column)\n    {\n        return 'nvarchar(45)';\n    }\n\n    /**\n     * Create the column definition for a MAC address type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    protected function typeMacAddress(Fluent $column)\n    {\n        return 'nvarchar(17)';\n    }\n\n    /**\n     * Create the column definition for a spatial Geometry type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    public function typeGeometry(Fluent $column)\n    {\n        return 'geography';\n    }\n\n    /**\n     * Create the column definition for a spatial Point type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    public function typePoint(Fluent $column)\n    {\n        return 'geography';\n    }\n\n    /**\n     * Create the column definition for a spatial LineString type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    public function typeLineString(Fluent $column)\n    {\n        return 'geography';\n    }\n\n    /**\n     * Create the column definition for a spatial Polygon type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    public function typePolygon(Fluent $column)\n    {\n        return 'geography';\n    }\n\n    /**\n     * Create the column definition for a spatial GeometryCollection type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    public function typeGeometryCollection(Fluent $column)\n    {\n        return 'geography';\n    }\n\n    /**\n     * Create the column definition for a spatial MultiPoint type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    public function typeMultiPoint(Fluent $column)\n    {\n        return 'geography';\n    }\n\n    /**\n     * Create the column definition for a spatial MultiLineString type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    public function typeMultiLineString(Fluent $column)\n    {\n        return 'geography';\n    }\n\n    /**\n     * Create the column definition for a spatial MultiPolygon type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string\n     */\n    public function typeMultiPolygon(Fluent $column)\n    {\n        return 'geography';\n    }\n\n    /**\n     * Create the column definition for a generated, computed column type.\n     *\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string|null\n     */\n    protected function typeComputed(Fluent $column)\n    {\n        return \"as ({$column->expression})\";\n    }\n\n    /**\n     * Get the SQL for a collation column modifier.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string|null\n     */\n    protected function modifyCollate(Blueprint $blueprint, Fluent $column)\n    {\n        if (! is_null($column->collation)) {\n            return ' collate '.$column->collation;\n        }\n    }\n\n    /**\n     * Get the SQL for a nullable column modifier.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string|null\n     */\n    protected function modifyNullable(Blueprint $blueprint, Fluent $column)\n    {\n        if ($column->type !== 'computed') {\n            return $column->nullable ? ' null' : ' not null';\n        }\n    }\n\n    /**\n     * Get the SQL for a default column modifier.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string|null\n     */\n    protected function modifyDefault(Blueprint $blueprint, Fluent $column)\n    {\n        if (! is_null($column->default)) {\n            return ' default '.$this->getDefaultValue($column->default);\n        }\n    }\n\n    /**\n     * Get the SQL for an auto-increment column modifier.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string|null\n     */\n    protected function modifyIncrement(Blueprint $blueprint, Fluent $column)\n    {\n        if (in_array($column->type, $this->serials) && $column->autoIncrement) {\n            return ' identity primary key';\n        }\n    }\n\n    /**\n     * Get the SQL for a generated stored column modifier.\n     *\n     * @param  \\Illuminate\\Database\\Schema\\Blueprint  $blueprint\n     * @param  \\Illuminate\\Support\\Fluent  $column\n     * @return string|null\n     */\n    protected function modifyPersisted(Blueprint $blueprint, Fluent $column)\n    {\n        if ($column->persisted) {\n            return ' persisted';\n        }\n    }\n\n    /**\n     * Wrap a table in keyword identifiers.\n     *\n     * @param  \\Illuminate\\Database\\Query\\Expression|string  $table\n     * @return string\n     */\n    public function wrapTable($table)\n    {\n        if ($table instanceof Blueprint && $table->temporary) {\n            $this->setTablePrefix('#');\n        }\n\n        return parent::wrapTable($table);\n    }\n\n    /**\n     * Quote the given string literal.\n     *\n     * @param  string|array  $value\n     * @return string\n     */\n    public function quoteString($value)\n    {\n        if (is_array($value)) {\n            return implode(', ', array_map([$this, __FUNCTION__], $value));\n        }\n\n        return \"N'$value'\";\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Schema/MySqlBuilder.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Schema;\n\nclass MySqlBuilder extends Builder\n{\n    /**\n     * Create a database in the schema.\n     *\n     * @param  string  $name\n     * @return bool\n     */\n    public function createDatabase($name)\n    {\n        return $this->connection->statement(\n            $this->grammar->compileCreateDatabase($name, $this->connection)\n        );\n    }\n\n    /**\n     * Drop a database from the schema if the database exists.\n     *\n     * @param  string  $name\n     * @return bool\n     */\n    public function dropDatabaseIfExists($name)\n    {\n        return $this->connection->statement(\n            $this->grammar->compileDropDatabaseIfExists($name)\n        );\n    }\n\n    /**\n     * Determine if the given table exists.\n     *\n     * @param  string  $table\n     * @return bool\n     */\n    public function hasTable($table)\n    {\n        $table = $this->connection->getTablePrefix().$table;\n\n        return count($this->connection->select(\n            $this->grammar->compileTableExists(), [$this->connection->getDatabaseName(), $table]\n        )) > 0;\n    }\n\n    /**\n     * Get the column listing for a given table.\n     *\n     * @param  string  $table\n     * @return array\n     */\n    public function getColumnListing($table)\n    {\n        $table = $this->connection->getTablePrefix().$table;\n\n        $results = $this->connection->select(\n            $this->grammar->compileColumnListing(), [$this->connection->getDatabaseName(), $table]\n        );\n\n        return $this->connection->getPostProcessor()->processColumnListing($results);\n    }\n\n    /**\n     * Drop all tables from the database.\n     *\n     * @return void\n     */\n    public function dropAllTables()\n    {\n        $tables = [];\n\n        foreach ($this->getAllTables() as $row) {\n            $row = (array) $row;\n\n            $tables[] = reset($row);\n        }\n\n        if (empty($tables)) {\n            return;\n        }\n\n        $this->disableForeignKeyConstraints();\n\n        $this->connection->statement(\n            $this->grammar->compileDropAllTables($tables)\n        );\n\n        $this->enableForeignKeyConstraints();\n    }\n\n    /**\n     * Drop all views from the database.\n     *\n     * @return void\n     */\n    public function dropAllViews()\n    {\n        $views = [];\n\n        foreach ($this->getAllViews() as $row) {\n            $row = (array) $row;\n\n            $views[] = reset($row);\n        }\n\n        if (empty($views)) {\n            return;\n        }\n\n        $this->connection->statement(\n            $this->grammar->compileDropAllViews($views)\n        );\n    }\n\n    /**\n     * Get all of the table names for the database.\n     *\n     * @return array\n     */\n    public function getAllTables()\n    {\n        return $this->connection->select(\n            $this->grammar->compileGetAllTables()\n        );\n    }\n\n    /**\n     * Get all of the view names for the database.\n     *\n     * @return array\n     */\n    public function getAllViews()\n    {\n        return $this->connection->select(\n            $this->grammar->compileGetAllViews()\n        );\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Schema/MySqlSchemaState.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Schema;\n\nuse Exception;\nuse Illuminate\\Database\\Connection;\nuse Illuminate\\Support\\Str;\nuse Symfony\\Component\\Process\\Process;\n\nclass MySqlSchemaState extends SchemaState\n{\n    /**\n     * Dump the database's schema into a file.\n     *\n     * @param  \\Illuminate\\Database\\Connection  $connection\n     * @param  string  $path\n     * @return void\n     */\n    public function dump(Connection $connection, $path)\n    {\n        $this->executeDumpProcess($this->makeProcess(\n            $this->baseDumpCommand().' --routines --result-file=\"${:LARAVEL_LOAD_PATH}\" --no-data'\n        ), $this->output, array_merge($this->baseVariables($this->connection->getConfig()), [\n            'LARAVEL_LOAD_PATH' => $path,\n        ]));\n\n        $this->removeAutoIncrementingState($path);\n\n        $this->appendMigrationData($path);\n    }\n\n    /**\n     * Remove the auto-incrementing state from the given schema dump.\n     *\n     * @param  string  $path\n     * @return void\n     */\n    protected function removeAutoIncrementingState(string $path)\n    {\n        $this->files->put($path, preg_replace(\n            '/\\s+AUTO_INCREMENT=[0-9]+/iu',\n            '',\n            $this->files->get($path)\n        ));\n    }\n\n    /**\n     * Append the migration data to the schema dump.\n     *\n     * @param  string  $path\n     * @return void\n     */\n    protected function appendMigrationData(string $path)\n    {\n        $process = $this->executeDumpProcess($this->makeProcess(\n            $this->baseDumpCommand().' '.$this->migrationTable.' --no-create-info --skip-extended-insert --skip-routines --compact'\n        ), null, array_merge($this->baseVariables($this->connection->getConfig()), [\n            //\n        ]));\n\n        $this->files->append($path, $process->getOutput());\n    }\n\n    /**\n     * Load the given schema file into the database.\n     *\n     * @param  string  $path\n     * @return void\n     */\n    public function load($path)\n    {\n        $command = 'mysql '.$this->connectionString().' --database=\"${:LARAVEL_LOAD_DATABASE}\" < \"${:LARAVEL_LOAD_PATH}\"';\n\n        $process = $this->makeProcess($command)->setTimeout(null);\n\n        $process->mustRun(null, array_merge($this->baseVariables($this->connection->getConfig()), [\n            'LARAVEL_LOAD_PATH' => $path,\n        ]));\n    }\n\n    /**\n     * Get the base dump command arguments for MySQL as a string.\n     *\n     * @return string\n     */\n    protected function baseDumpCommand()\n    {\n        $command = 'mysqldump '.$this->connectionString().' --no-tablespaces --skip-add-locks --skip-comments --skip-set-charset --tz-utc --column-statistics=0';\n\n        if (! $this->connection->isMaria()) {\n            $command .= ' --set-gtid-purged=OFF';\n        }\n\n        return $command.' \"${:LARAVEL_LOAD_DATABASE}\"';\n    }\n\n    /**\n     * Generate a basic connection string (--socket, --host, --port, --user, --password) for the database.\n     *\n     * @return string\n     */\n    protected function connectionString()\n    {\n        $value = ' --user=\"${:LARAVEL_LOAD_USER}\" --password=\"${:LARAVEL_LOAD_PASSWORD}\"';\n\n        $value .= $this->connection->getConfig()['unix_socket'] ?? false\n                        ? ' --socket=\"${:LARAVEL_LOAD_SOCKET}\"'\n                        : ' --host=\"${:LARAVEL_LOAD_HOST}\" --port=\"${:LARAVEL_LOAD_PORT}\"';\n\n        return $value;\n    }\n\n    /**\n     * Get the base variables for a dump / load command.\n     *\n     * @param  array  $config\n     * @return array\n     */\n    protected function baseVariables(array $config)\n    {\n        $config['host'] = $config['host'] ?? '';\n\n        return [\n            'LARAVEL_LOAD_SOCKET' => $config['unix_socket'] ?? '',\n            'LARAVEL_LOAD_HOST' => is_array($config['host']) ? $config['host'][0] : $config['host'],\n            'LARAVEL_LOAD_PORT' => $config['port'] ?? '',\n            'LARAVEL_LOAD_USER' => $config['username'],\n            'LARAVEL_LOAD_PASSWORD' => $config['password'] ?? '',\n            'LARAVEL_LOAD_DATABASE' => $config['database'],\n        ];\n    }\n\n    /**\n     * Execute the given dump process.\n     *\n     * @param  \\Symfony\\Component\\Process\\Process  $process\n     * @param  callable  $output\n     * @param  array  $variables\n     * @return \\Symfony\\Component\\Process\\Process\n     */\n    protected function executeDumpProcess(Process $process, $output, array $variables)\n    {\n        try {\n            $process->setTimeout(null)->mustRun($output, $variables);\n        } catch (Exception $e) {\n            if (Str::contains($e->getMessage(), ['column-statistics', 'column_statistics'])) {\n                return $this->executeDumpProcess(Process::fromShellCommandLine(\n                    str_replace(' --column-statistics=0', '', $process->getCommandLine())\n                ), $output, $variables);\n            }\n\n            if (Str::contains($e->getMessage(), ['set-gtid-purged'])) {\n                return $this->executeDumpProcess(Process::fromShellCommandLine(\n                    str_replace(' --set-gtid-purged=OFF', '', $process->getCommandLine())\n                ), $output, $variables);\n            }\n\n            throw $e;\n        }\n\n        return $process;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Schema/PostgresBuilder.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Schema;\n\nclass PostgresBuilder extends Builder\n{\n    /**\n     * Create a database in the schema.\n     *\n     * @param  string  $name\n     * @return bool\n     */\n    public function createDatabase($name)\n    {\n        return $this->connection->statement(\n            $this->grammar->compileCreateDatabase($name, $this->connection)\n        );\n    }\n\n    /**\n     * Drop a database from the schema if the database exists.\n     *\n     * @param  string  $name\n     * @return bool\n     */\n    public function dropDatabaseIfExists($name)\n    {\n        return $this->connection->statement(\n            $this->grammar->compileDropDatabaseIfExists($name)\n        );\n    }\n\n    /**\n     * Determine if the given table exists.\n     *\n     * @param  string  $table\n     * @return bool\n     */\n    public function hasTable($table)\n    {\n        [$schema, $table] = $this->parseSchemaAndTable($table);\n\n        $table = $this->connection->getTablePrefix().$table;\n\n        return count($this->connection->select(\n            $this->grammar->compileTableExists(), [$schema, $table]\n        )) > 0;\n    }\n\n    /**\n     * Drop all tables from the database.\n     *\n     * @return void\n     */\n    public function dropAllTables()\n    {\n        $tables = [];\n\n        $excludedTables = $this->connection->getConfig('dont_drop') ?? ['spatial_ref_sys'];\n\n        foreach ($this->getAllTables() as $row) {\n            $row = (array) $row;\n\n            $table = reset($row);\n\n            if (! in_array($table, $excludedTables)) {\n                $tables[] = $table;\n            }\n        }\n\n        if (empty($tables)) {\n            return;\n        }\n\n        $this->connection->statement(\n            $this->grammar->compileDropAllTables($tables)\n        );\n    }\n\n    /**\n     * Drop all views from the database.\n     *\n     * @return void\n     */\n    public function dropAllViews()\n    {\n        $views = [];\n\n        foreach ($this->getAllViews() as $row) {\n            $row = (array) $row;\n\n            $views[] = reset($row);\n        }\n\n        if (empty($views)) {\n            return;\n        }\n\n        $this->connection->statement(\n            $this->grammar->compileDropAllViews($views)\n        );\n    }\n\n    /**\n     * Drop all types from the database.\n     *\n     * @return void\n     */\n    public function dropAllTypes()\n    {\n        $types = [];\n\n        foreach ($this->getAllTypes() as $row) {\n            $row = (array) $row;\n\n            $types[] = reset($row);\n        }\n\n        if (empty($types)) {\n            return;\n        }\n\n        $this->connection->statement(\n            $this->grammar->compileDropAllTypes($types)\n        );\n    }\n\n    /**\n     * Get all of the table names for the database.\n     *\n     * @return array\n     */\n    public function getAllTables()\n    {\n        return $this->connection->select(\n            $this->grammar->compileGetAllTables((array) $this->connection->getConfig('schema'))\n        );\n    }\n\n    /**\n     * Get all of the view names for the database.\n     *\n     * @return array\n     */\n    public function getAllViews()\n    {\n        return $this->connection->select(\n            $this->grammar->compileGetAllViews((array) $this->connection->getConfig('schema'))\n        );\n    }\n\n    /**\n     * Get all of the type names for the database.\n     *\n     * @return array\n     */\n    public function getAllTypes()\n    {\n        return $this->connection->select(\n            $this->grammar->compileGetAllTypes()\n        );\n    }\n\n    /**\n     * Get the column listing for a given table.\n     *\n     * @param  string  $table\n     * @return array\n     */\n    public function getColumnListing($table)\n    {\n        [$schema, $table] = $this->parseSchemaAndTable($table);\n\n        $table = $this->connection->getTablePrefix().$table;\n\n        $results = $this->connection->select(\n            $this->grammar->compileColumnListing(), [$schema, $table]\n        );\n\n        return $this->connection->getPostProcessor()->processColumnListing($results);\n    }\n\n    /**\n     * Parse the table name and extract the schema and table.\n     *\n     * @param  string  $table\n     * @return array\n     */\n    protected function parseSchemaAndTable($table)\n    {\n        $table = explode('.', $table);\n\n        if (is_array($schema = $this->connection->getConfig('schema'))) {\n            if (in_array($table[0], $schema)) {\n                return [array_shift($table), implode('.', $table)];\n            }\n\n            $schema = head($schema);\n        }\n\n        return [$schema ?: 'public', implode('.', $table)];\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Schema/PostgresSchemaState.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Schema;\n\nuse Illuminate\\Database\\Connection;\nuse Illuminate\\Support\\Str;\n\nclass PostgresSchemaState extends SchemaState\n{\n    /**\n     * Dump the database's schema into a file.\n     *\n     * @param  \\Illuminate\\Database\\Connection  $connection\n     * @param  string  $path\n     * @return void\n     */\n    public function dump(Connection $connection, $path)\n    {\n        $excludedTables = collect($connection->getSchemaBuilder()->getAllTables())\n                        ->map->tablename\n                        ->reject(function ($table) {\n                            return $table === $this->migrationTable;\n                        })->map(function ($table) {\n                            return '--exclude-table-data=\"*.'.$table.'\"';\n                        })->implode(' ');\n\n        $this->makeProcess(\n            $this->baseDumpCommand().' --file=\"${:LARAVEL_LOAD_PATH}\" '.$excludedTables\n        )->mustRun($this->output, array_merge($this->baseVariables($this->connection->getConfig()), [\n            'LARAVEL_LOAD_PATH' => $path,\n        ]));\n    }\n\n    /**\n     * Load the given schema file into the database.\n     *\n     * @param  string  $path\n     * @return void\n     */\n    public function load($path)\n    {\n        $command = 'pg_restore --no-owner --no-acl --clean --if-exists --host=\"${:LARAVEL_LOAD_HOST}\" --port=\"${:LARAVEL_LOAD_PORT}\" --username=\"${:LARAVEL_LOAD_USER}\" --dbname=\"${:LARAVEL_LOAD_DATABASE}\" \"${:LARAVEL_LOAD_PATH}\"';\n\n        if (Str::endsWith($path, '.sql')) {\n            $command = 'psql --file=\"${:LARAVEL_LOAD_PATH}\" --host=\"${:LARAVEL_LOAD_HOST}\" --port=\"${:LARAVEL_LOAD_PORT}\" --username=\"${:LARAVEL_LOAD_USER}\" --dbname=\"${:LARAVEL_LOAD_DATABASE}\"';\n        }\n\n        $process = $this->makeProcess($command);\n\n        $process->mustRun(null, array_merge($this->baseVariables($this->connection->getConfig()), [\n            'LARAVEL_LOAD_PATH' => $path,\n        ]));\n    }\n\n    /**\n     * Get the base dump command arguments for PostgreSQL as a string.\n     *\n     * @return string\n     */\n    protected function baseDumpCommand()\n    {\n        return 'pg_dump --no-owner --no-acl -Fc --host=\"${:LARAVEL_LOAD_HOST}\" --port=\"${:LARAVEL_LOAD_PORT}\" --username=\"${:LARAVEL_LOAD_USER}\" --dbname=\"${:LARAVEL_LOAD_DATABASE}\"';\n    }\n\n    /**\n     * Get the base variables for a dump / load command.\n     *\n     * @param  array  $config\n     * @return array\n     */\n    protected function baseVariables(array $config)\n    {\n        $config['host'] = $config['host'] ?? '';\n\n        return [\n            'LARAVEL_LOAD_HOST' => is_array($config['host']) ? $config['host'][0] : $config['host'],\n            'LARAVEL_LOAD_PORT' => $config['port'],\n            'LARAVEL_LOAD_USER' => $config['username'],\n            'PGPASSWORD' => $config['password'],\n            'LARAVEL_LOAD_DATABASE' => $config['database'],\n        ];\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Schema/SQLiteBuilder.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Schema;\n\nuse Illuminate\\Support\\Facades\\File;\n\nclass SQLiteBuilder extends Builder\n{\n    /**\n     * Create a database in the schema.\n     *\n     * @param  string  $name\n     * @return bool\n     */\n    public function createDatabase($name)\n    {\n        return File::put($name, '') !== false;\n    }\n\n    /**\n     * Drop a database from the schema if the database exists.\n     *\n     * @param  string  $name\n     * @return bool\n     */\n    public function dropDatabaseIfExists($name)\n    {\n        return File::exists($name)\n            ? File::delete($name)\n            : true;\n    }\n\n    /**\n     * Drop all tables from the database.\n     *\n     * @return void\n     */\n    public function dropAllTables()\n    {\n        if ($this->connection->getDatabaseName() !== ':memory:') {\n            return $this->refreshDatabaseFile();\n        }\n\n        $this->connection->select($this->grammar->compileEnableWriteableSchema());\n\n        $this->connection->select($this->grammar->compileDropAllTables());\n\n        $this->connection->select($this->grammar->compileDisableWriteableSchema());\n\n        $this->connection->select($this->grammar->compileRebuild());\n    }\n\n    /**\n     * Drop all views from the database.\n     *\n     * @return void\n     */\n    public function dropAllViews()\n    {\n        $this->connection->select($this->grammar->compileEnableWriteableSchema());\n\n        $this->connection->select($this->grammar->compileDropAllViews());\n\n        $this->connection->select($this->grammar->compileDisableWriteableSchema());\n\n        $this->connection->select($this->grammar->compileRebuild());\n    }\n\n    /**\n     * Empty the database file.\n     *\n     * @return void\n     */\n    public function refreshDatabaseFile()\n    {\n        file_put_contents($this->connection->getDatabaseName(), '');\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Schema/SchemaState.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Schema;\n\nuse Illuminate\\Database\\Connection;\nuse Illuminate\\Filesystem\\Filesystem;\nuse Symfony\\Component\\Process\\Process;\n\nabstract class SchemaState\n{\n    /**\n     * The connection instance.\n     *\n     * @var \\Illuminate\\Database\\Connection\n     */\n    protected $connection;\n\n    /**\n     * The filesystem instance.\n     *\n     * @var \\Illuminate\\Filesystem\\Filesystem\n     */\n    protected $files;\n\n    /**\n     * The name of the application's migration table.\n     *\n     * @var string\n     */\n    protected $migrationTable = 'migrations';\n\n    /**\n     * The process factory callback.\n     *\n     * @var callable\n     */\n    protected $processFactory;\n\n    /**\n     * The output callable instance.\n     *\n     * @var callable\n     */\n    protected $output;\n\n    /**\n     * Create a new dumper instance.\n     *\n     * @param  \\Illuminate\\Database\\Connection  $connection\n     * @param  \\Illuminate\\Filesystem\\Filesystem|null  $files\n     * @param  callable|null  $processFactory\n     * @return void\n     */\n    public function __construct(Connection $connection, Filesystem $files = null, callable $processFactory = null)\n    {\n        $this->connection = $connection;\n\n        $this->files = $files ?: new Filesystem;\n\n        $this->processFactory = $processFactory ?: function (...$arguments) {\n            return Process::fromShellCommandline(...$arguments)->setTimeout(null);\n        };\n\n        $this->handleOutputUsing(function () {\n            //\n        });\n    }\n\n    /**\n     * Dump the database's schema into a file.\n     *\n     * @param  \\Illuminate\\Database\\Connection  $connection\n     * @param  string  $path\n     * @return void\n     */\n    abstract public function dump(Connection $connection, $path);\n\n    /**\n     * Load the given schema file into the database.\n     *\n     * @param  string  $path\n     * @return void\n     */\n    abstract public function load($path);\n\n    /**\n     * Create a new process instance.\n     *\n     * @param  array  $arguments\n     * @return \\Symfony\\Component\\Process\\Process\n     */\n    public function makeProcess(...$arguments)\n    {\n        return call_user_func($this->processFactory, ...$arguments);\n    }\n\n    /**\n     * Specify the name of the application's migration table.\n     *\n     * @param  string  $table\n     * @return $this\n     */\n    public function withMigrationTable(string $table)\n    {\n        $this->migrationTable = $table;\n\n        return $this;\n    }\n\n    /**\n     * Specify the callback that should be used to handle process output.\n     *\n     * @param  callable  $output\n     * @return $this\n     */\n    public function handleOutputUsing(callable $output)\n    {\n        $this->output = $output;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Schema/SqlServerBuilder.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Schema;\n\nclass SqlServerBuilder extends Builder\n{\n    /**\n     * Create a database in the schema.\n     *\n     * @param  string  $name\n     * @return bool\n     */\n    public function createDatabase($name)\n    {\n        return $this->connection->statement(\n            $this->grammar->compileCreateDatabase($name, $this->connection)\n        );\n    }\n\n    /**\n     * Drop a database from the schema if the database exists.\n     *\n     * @param  string  $name\n     * @return bool\n     */\n    public function dropDatabaseIfExists($name)\n    {\n        return $this->connection->statement(\n            $this->grammar->compileDropDatabaseIfExists($name)\n        );\n    }\n\n    /**\n     * Drop all tables from the database.\n     *\n     * @return void\n     */\n    public function dropAllTables()\n    {\n        $this->connection->statement($this->grammar->compileDropAllForeignKeys());\n\n        $this->connection->statement($this->grammar->compileDropAllTables());\n    }\n\n    /**\n     * Drop all views from the database.\n     *\n     * @return void\n     */\n    public function dropAllViews()\n    {\n        $this->connection->statement($this->grammar->compileDropAllViews());\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Schema/SqliteSchemaState.php",
    "content": "<?php\n\nnamespace Illuminate\\Database\\Schema;\n\nuse Illuminate\\Database\\Connection;\n\nclass SqliteSchemaState extends SchemaState\n{\n    /**\n     * Dump the database's schema into a file.\n     *\n     * @param  \\Illuminate\\Database\\Connection  $connection\n     * @param  string  $path\n     * @return void\n     */\n    public function dump(Connection $connection, $path)\n    {\n        with($process = $this->makeProcess(\n            $this->baseCommand().' .schema'\n        ))->setTimeout(null)->mustRun(null, array_merge($this->baseVariables($this->connection->getConfig()), [\n            //\n        ]));\n\n        $migrations = collect(preg_split(\"/\\r\\n|\\n|\\r/\", $process->getOutput()))->filter(function ($line) {\n            return stripos($line, 'sqlite_sequence') === false &&\n                   strlen($line) > 0;\n        })->all();\n\n        $this->files->put($path, implode(PHP_EOL, $migrations).PHP_EOL);\n\n        $this->appendMigrationData($path);\n    }\n\n    /**\n     * Append the migration data to the schema dump.\n     *\n     * @param  string  $path\n     * @return void\n     */\n    protected function appendMigrationData(string $path)\n    {\n        with($process = $this->makeProcess(\n            $this->baseCommand().' \".dump \\''.$this->migrationTable.'\\'\"'\n        ))->mustRun(null, array_merge($this->baseVariables($this->connection->getConfig()), [\n            //\n        ]));\n\n        $migrations = collect(preg_split(\"/\\r\\n|\\n|\\r/\", $process->getOutput()))->filter(function ($line) {\n            return preg_match('/^\\s*(--|INSERT\\s)/iu', $line) === 1 &&\n                   strlen($line) > 0;\n        })->all();\n\n        $this->files->append($path, implode(PHP_EOL, $migrations).PHP_EOL);\n    }\n\n    /**\n     * Load the given schema file into the database.\n     *\n     * @param  string  $path\n     * @return void\n     */\n    public function load($path)\n    {\n        $process = $this->makeProcess($this->baseCommand().' < \"${:LARAVEL_LOAD_PATH}\"');\n\n        $process->mustRun(null, array_merge($this->baseVariables($this->connection->getConfig()), [\n            'LARAVEL_LOAD_PATH' => $path,\n        ]));\n    }\n\n    /**\n     * Get the base sqlite command arguments as a string.\n     *\n     * @return string\n     */\n    protected function baseCommand()\n    {\n        return 'sqlite3 \"${:LARAVEL_LOAD_DATABASE}\"';\n    }\n\n    /**\n     * Get the base variables for a dump / load command.\n     *\n     * @param  array  $config\n     * @return array\n     */\n    protected function baseVariables(array $config)\n    {\n        return [\n            'LARAVEL_LOAD_DATABASE' => $config['database'],\n        ];\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/Seeder.php",
    "content": "<?php\n\nnamespace Illuminate\\Database;\n\nuse Illuminate\\Console\\Command;\nuse Illuminate\\Container\\Container;\nuse Illuminate\\Support\\Arr;\nuse InvalidArgumentException;\n\nabstract class Seeder\n{\n    /**\n     * The container instance.\n     *\n     * @var \\Illuminate\\Container\\Container\n     */\n    protected $container;\n\n    /**\n     * The console command instance.\n     *\n     * @var \\Illuminate\\Console\\Command\n     */\n    protected $command;\n\n    /**\n     * Run the given seeder class.\n     *\n     * @param  array|string  $class\n     * @param  bool  $silent\n     * @param  array  $parameters\n     * @return $this\n     */\n    public function call($class, $silent = false, array $parameters = [])\n    {\n        $classes = Arr::wrap($class);\n\n        foreach ($classes as $class) {\n            $seeder = $this->resolve($class);\n\n            $name = get_class($seeder);\n\n            if ($silent === false && isset($this->command)) {\n                $this->command->getOutput()->writeln(\"<comment>Seeding:</comment> {$name}\");\n            }\n\n            $startTime = microtime(true);\n\n            $seeder->__invoke($parameters);\n\n            $runTime = number_format((microtime(true) - $startTime) * 1000, 2);\n\n            if ($silent === false && isset($this->command)) {\n                $this->command->getOutput()->writeln(\"<info>Seeded:</info>  {$name} ({$runTime}ms)\");\n            }\n        }\n\n        return $this;\n    }\n\n    /**\n     * Run the given seeder class.\n     *\n     * @param  array|string  $class\n     * @param  array  $parameters\n     * @return void\n     */\n    public function callWith($class, array $parameters = [])\n    {\n        $this->call($class, false, $parameters);\n    }\n\n    /**\n     * Silently run the given seeder class.\n     *\n     * @param  array|string  $class\n     * @param  array  $parameters\n     * @return void\n     */\n    public function callSilent($class, array $parameters = [])\n    {\n        $this->call($class, true, $parameters);\n    }\n\n    /**\n     * Resolve an instance of the given seeder class.\n     *\n     * @param  string  $class\n     * @return \\Illuminate\\Database\\Seeder\n     */\n    protected function resolve($class)\n    {\n        if (isset($this->container)) {\n            $instance = $this->container->make($class);\n\n            $instance->setContainer($this->container);\n        } else {\n            $instance = new $class;\n        }\n\n        if (isset($this->command)) {\n            $instance->setCommand($this->command);\n        }\n\n        return $instance;\n    }\n\n    /**\n     * Set the IoC container instance.\n     *\n     * @param  \\Illuminate\\Container\\Container  $container\n     * @return $this\n     */\n    public function setContainer(Container $container)\n    {\n        $this->container = $container;\n\n        return $this;\n    }\n\n    /**\n     * Set the console command instance.\n     *\n     * @param  \\Illuminate\\Console\\Command  $command\n     * @return $this\n     */\n    public function setCommand(Command $command)\n    {\n        $this->command = $command;\n\n        return $this;\n    }\n\n    /**\n     * Run the database seeds.\n     *\n     * @param  array  $parameters\n     * @return mixed\n     *\n     * @throws \\InvalidArgumentException\n     */\n    public function __invoke(array $parameters = [])\n    {\n        if (! method_exists($this, 'run')) {\n            throw new InvalidArgumentException('Method [run] missing from '.get_class($this));\n        }\n\n        return isset($this->container)\n                    ? $this->container->call([$this, 'run'], $parameters)\n                    : $this->run(...$parameters);\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/SqlServerConnection.php",
    "content": "<?php\n\nnamespace Illuminate\\Database;\n\nuse Closure;\nuse Doctrine\\DBAL\\Driver\\PDOSqlsrv\\Driver as DoctrineDriver;\nuse Doctrine\\DBAL\\Version;\nuse Illuminate\\Database\\PDO\\SqlServerDriver;\nuse Illuminate\\Database\\Query\\Grammars\\SqlServerGrammar as QueryGrammar;\nuse Illuminate\\Database\\Query\\Processors\\SqlServerProcessor;\nuse Illuminate\\Database\\Schema\\Grammars\\SqlServerGrammar as SchemaGrammar;\nuse Illuminate\\Database\\Schema\\SqlServerBuilder;\nuse Illuminate\\Filesystem\\Filesystem;\nuse RuntimeException;\nuse Throwable;\n\nclass SqlServerConnection extends Connection\n{\n    /**\n     * Execute a Closure within a transaction.\n     *\n     * @param  \\Closure  $callback\n     * @param  int  $attempts\n     * @return mixed\n     *\n     * @throws \\Throwable\n     */\n    public function transaction(Closure $callback, $attempts = 1)\n    {\n        for ($a = 1; $a <= $attempts; $a++) {\n            if ($this->getDriverName() === 'sqlsrv') {\n                return parent::transaction($callback, $attempts);\n            }\n\n            $this->getPdo()->exec('BEGIN TRAN');\n\n            // We'll simply execute the given callback within a try / catch block\n            // and if we catch any exception we can rollback the transaction\n            // so that none of the changes are persisted to the database.\n            try {\n                $result = $callback($this);\n\n                $this->getPdo()->exec('COMMIT TRAN');\n            }\n\n            // If we catch an exception, we will rollback so nothing gets messed\n            // up in the database. Then we'll re-throw the exception so it can\n            // be handled how the developer sees fit for their applications.\n            catch (Throwable $e) {\n                $this->getPdo()->exec('ROLLBACK TRAN');\n\n                throw $e;\n            }\n\n            return $result;\n        }\n    }\n\n    /**\n     * Get the default query grammar instance.\n     *\n     * @return \\Illuminate\\Database\\Query\\Grammars\\SqlServerGrammar\n     */\n    protected function getDefaultQueryGrammar()\n    {\n        return $this->withTablePrefix(new QueryGrammar);\n    }\n\n    /**\n     * Get a schema builder instance for the connection.\n     *\n     * @return \\Illuminate\\Database\\Schema\\SqlServerBuilder\n     */\n    public function getSchemaBuilder()\n    {\n        if (is_null($this->schemaGrammar)) {\n            $this->useDefaultSchemaGrammar();\n        }\n\n        return new SqlServerBuilder($this);\n    }\n\n    /**\n     * Get the default schema grammar instance.\n     *\n     * @return \\Illuminate\\Database\\Schema\\Grammars\\SqlServerGrammar\n     */\n    protected function getDefaultSchemaGrammar()\n    {\n        return $this->withTablePrefix(new SchemaGrammar);\n    }\n\n    /**\n     * Get the schema state for the connection.\n     *\n     * @param  \\Illuminate\\Filesystem\\Filesystem|null  $files\n     * @param  callable|null  $processFactory\n     *\n     * @throws \\RuntimeException\n     */\n    public function getSchemaState(Filesystem $files = null, callable $processFactory = null)\n    {\n        throw new RuntimeException('Schema dumping is not supported when using SQL Server.');\n    }\n\n    /**\n     * Get the default post processor instance.\n     *\n     * @return \\Illuminate\\Database\\Query\\Processors\\SqlServerProcessor\n     */\n    protected function getDefaultPostProcessor()\n    {\n        return new SqlServerProcessor;\n    }\n\n    /**\n     * Get the Doctrine DBAL driver.\n     *\n     * @return \\Doctrine\\DBAL\\Driver\\PDOSqlsrv\\Driver|\\Illuminate\\Database\\PDO\\SqlServerDriver\n     */\n    protected function getDoctrineDriver()\n    {\n        return class_exists(Version::class) ? new DoctrineDriver : new SqlServerDriver;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/database/composer.json",
    "content": "{\n    \"name\": \"illuminate/database\",\n    \"description\": \"The Illuminate Database package.\",\n    \"license\": \"MIT\",\n    \"homepage\": \"https://laravel.com\",\n    \"support\": {\n        \"issues\": \"https://github.com/laravel/framework/issues\",\n        \"source\": \"https://github.com/laravel/framework\"\n    },\n    \"keywords\": [\"laravel\", \"database\", \"sql\", \"orm\"],\n    \"authors\": [\n        {\n            \"name\": \"Taylor Otwell\",\n            \"email\": \"taylor@laravel.com\"\n        }\n    ],\n    \"require\": {\n        \"php\": \"^7.3|^8.0\",\n        \"ext-json\": \"*\",\n        \"illuminate/collections\": \"^8.0\",\n        \"illuminate/container\": \"^8.0\",\n        \"illuminate/contracts\": \"^8.0\",\n        \"illuminate/macroable\": \"^8.0\",\n        \"illuminate/support\": \"^8.0\",\n        \"symfony/console\": \"^5.4\"\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"Illuminate\\\\Database\\\\\": \"\"\n        }\n    },\n    \"extra\": {\n        \"branch-alias\": {\n            \"dev-master\": \"8.x-dev\"\n        }\n    },\n    \"suggest\": {\n        \"doctrine/dbal\": \"Required to rename columns and drop SQLite columns (^2.13.3|^3.1.4).\",\n        \"fakerphp/faker\": \"Required to use the eloquent factory builder (^1.9.1).\",\n        \"illuminate/console\": \"Required to use the database commands (^8.0).\",\n        \"illuminate/events\": \"Required to use the observers with Eloquent (^8.0).\",\n        \"illuminate/filesystem\": \"Required to use the migrations (^8.0).\",\n        \"illuminate/pagination\": \"Required to paginate the result set (^8.0).\",\n        \"symfony/finder\": \"Required to use Eloquent model factories (^5.4).\"\n    },\n    \"config\": {\n        \"sort-packages\": true\n    },\n    \"minimum-stability\": \"dev\"\n}\n"
  },
  {
    "path": "server/vendor/illuminate/events/CallQueuedListener.php",
    "content": "<?php\n\nnamespace Illuminate\\Events;\n\nuse Illuminate\\Bus\\Queueable;\nuse Illuminate\\Container\\Container;\nuse Illuminate\\Contracts\\Queue\\Job;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\n\nclass CallQueuedListener implements ShouldQueue\n{\n    use InteractsWithQueue, Queueable;\n\n    /**\n     * The listener class name.\n     *\n     * @var string\n     */\n    public $class;\n\n    /**\n     * The listener method.\n     *\n     * @var string\n     */\n    public $method;\n\n    /**\n     * The data to be passed to the listener.\n     *\n     * @var array\n     */\n    public $data;\n\n    /**\n     * The number of times the job may be attempted.\n     *\n     * @var int\n     */\n    public $tries;\n\n    /**\n     * The maximum number of exceptions allowed, regardless of attempts.\n     *\n     * @var int\n     */\n    public $maxExceptions;\n\n    /**\n     * The number of seconds to wait before retrying a job that encountered an uncaught exception.\n     *\n     * @var int\n     */\n    public $backoff;\n\n    /**\n     * The timestamp indicating when the job should timeout.\n     *\n     * @var int\n     */\n    public $retryUntil;\n\n    /**\n     * The number of seconds the job can run before timing out.\n     *\n     * @var int\n     */\n    public $timeout;\n\n    /**\n     * Indicates if the job should be encrypted.\n     *\n     * @var bool\n     */\n    public $shouldBeEncrypted = false;\n\n    /**\n     * Create a new job instance.\n     *\n     * @param  string  $class\n     * @param  string  $method\n     * @param  array  $data\n     * @return void\n     */\n    public function __construct($class, $method, $data)\n    {\n        $this->data = $data;\n        $this->class = $class;\n        $this->method = $method;\n    }\n\n    /**\n     * Handle the queued job.\n     *\n     * @param  \\Illuminate\\Container\\Container  $container\n     * @return void\n     */\n    public function handle(Container $container)\n    {\n        $this->prepareData();\n\n        $handler = $this->setJobInstanceIfNecessary(\n            $this->job, $container->make($this->class)\n        );\n\n        $handler->{$this->method}(...array_values($this->data));\n    }\n\n    /**\n     * Set the job instance of the given class if necessary.\n     *\n     * @param  \\Illuminate\\Contracts\\Queue\\Job  $job\n     * @param  object  $instance\n     * @return object\n     */\n    protected function setJobInstanceIfNecessary(Job $job, $instance)\n    {\n        if (in_array(InteractsWithQueue::class, class_uses_recursive($instance))) {\n            $instance->setJob($job);\n        }\n\n        return $instance;\n    }\n\n    /**\n     * Call the failed method on the job instance.\n     *\n     * The event instance and the exception will be passed.\n     *\n     * @param  \\Throwable  $e\n     * @return void\n     */\n    public function failed($e)\n    {\n        $this->prepareData();\n\n        $handler = Container::getInstance()->make($this->class);\n\n        $parameters = array_merge(array_values($this->data), [$e]);\n\n        if (method_exists($handler, 'failed')) {\n            $handler->failed(...$parameters);\n        }\n    }\n\n    /**\n     * Unserialize the data if needed.\n     *\n     * @return void\n     */\n    protected function prepareData()\n    {\n        if (is_string($this->data)) {\n            $this->data = unserialize($this->data);\n        }\n    }\n\n    /**\n     * Get the display name for the queued job.\n     *\n     * @return string\n     */\n    public function displayName()\n    {\n        return $this->class;\n    }\n\n    /**\n     * Prepare the instance for cloning.\n     *\n     * @return void\n     */\n    public function __clone()\n    {\n        $this->data = array_map(function ($data) {\n            return is_object($data) ? clone $data : $data;\n        }, $this->data);\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/events/Dispatcher.php",
    "content": "<?php\n\nnamespace Illuminate\\Events;\n\nuse Closure;\nuse Exception;\nuse Illuminate\\Container\\Container;\nuse Illuminate\\Contracts\\Broadcasting\\Factory as BroadcastFactory;\nuse Illuminate\\Contracts\\Broadcasting\\ShouldBroadcast;\nuse Illuminate\\Contracts\\Container\\Container as ContainerContract;\nuse Illuminate\\Contracts\\Events\\Dispatcher as DispatcherContract;\nuse Illuminate\\Contracts\\Queue\\ShouldBeEncrypted;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Support\\Arr;\nuse Illuminate\\Support\\Str;\nuse Illuminate\\Support\\Traits\\Macroable;\nuse Illuminate\\Support\\Traits\\ReflectsClosures;\nuse ReflectionClass;\n\nclass Dispatcher implements DispatcherContract\n{\n    use Macroable, ReflectsClosures;\n\n    /**\n     * The IoC container instance.\n     *\n     * @var \\Illuminate\\Contracts\\Container\\Container\n     */\n    protected $container;\n\n    /**\n     * The registered event listeners.\n     *\n     * @var array\n     */\n    protected $listeners = [];\n\n    /**\n     * The wildcard listeners.\n     *\n     * @var array\n     */\n    protected $wildcards = [];\n\n    /**\n     * The cached wildcard listeners.\n     *\n     * @var array\n     */\n    protected $wildcardsCache = [];\n\n    /**\n     * The queue resolver instance.\n     *\n     * @var callable\n     */\n    protected $queueResolver;\n\n    /**\n     * Create a new event dispatcher instance.\n     *\n     * @param  \\Illuminate\\Contracts\\Container\\Container|null  $container\n     * @return void\n     */\n    public function __construct(ContainerContract $container = null)\n    {\n        $this->container = $container ?: new Container;\n    }\n\n    /**\n     * Register an event listener with the dispatcher.\n     *\n     * @param  \\Closure|string|array  $events\n     * @param  \\Closure|string|array|null  $listener\n     * @return void\n     */\n    public function listen($events, $listener = null)\n    {\n        if ($events instanceof Closure) {\n            return collect($this->firstClosureParameterTypes($events))\n                ->each(function ($event) use ($events) {\n                    $this->listen($event, $events);\n                });\n        } elseif ($events instanceof QueuedClosure) {\n            return collect($this->firstClosureParameterTypes($events->closure))\n                ->each(function ($event) use ($events) {\n                    $this->listen($event, $events->resolve());\n                });\n        } elseif ($listener instanceof QueuedClosure) {\n            $listener = $listener->resolve();\n        }\n\n        foreach ((array) $events as $event) {\n            if (Str::contains($event, '*')) {\n                $this->setupWildcardListen($event, $listener);\n            } else {\n                $this->listeners[$event][] = $this->makeListener($listener);\n            }\n        }\n    }\n\n    /**\n     * Setup a wildcard listener callback.\n     *\n     * @param  string  $event\n     * @param  \\Closure|string  $listener\n     * @return void\n     */\n    protected function setupWildcardListen($event, $listener)\n    {\n        $this->wildcards[$event][] = $this->makeListener($listener, true);\n\n        $this->wildcardsCache = [];\n    }\n\n    /**\n     * Determine if a given event has listeners.\n     *\n     * @param  string  $eventName\n     * @return bool\n     */\n    public function hasListeners($eventName)\n    {\n        return isset($this->listeners[$eventName]) ||\n               isset($this->wildcards[$eventName]) ||\n               $this->hasWildcardListeners($eventName);\n    }\n\n    /**\n     * Determine if the given event has any wildcard listeners.\n     *\n     * @param  string  $eventName\n     * @return bool\n     */\n    public function hasWildcardListeners($eventName)\n    {\n        foreach ($this->wildcards as $key => $listeners) {\n            if (Str::is($key, $eventName)) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * Register an event and payload to be fired later.\n     *\n     * @param  string  $event\n     * @param  array  $payload\n     * @return void\n     */\n    public function push($event, $payload = [])\n    {\n        $this->listen($event.'_pushed', function () use ($event, $payload) {\n            $this->dispatch($event, $payload);\n        });\n    }\n\n    /**\n     * Flush a set of pushed events.\n     *\n     * @param  string  $event\n     * @return void\n     */\n    public function flush($event)\n    {\n        $this->dispatch($event.'_pushed');\n    }\n\n    /**\n     * Register an event subscriber with the dispatcher.\n     *\n     * @param  object|string  $subscriber\n     * @return void\n     */\n    public function subscribe($subscriber)\n    {\n        $subscriber = $this->resolveSubscriber($subscriber);\n\n        $events = $subscriber->subscribe($this);\n\n        if (is_array($events)) {\n            foreach ($events as $event => $listeners) {\n                foreach (Arr::wrap($listeners) as $listener) {\n                    if (is_string($listener) && method_exists($subscriber, $listener)) {\n                        $this->listen($event, [get_class($subscriber), $listener]);\n\n                        continue;\n                    }\n\n                    $this->listen($event, $listener);\n                }\n            }\n        }\n    }\n\n    /**\n     * Resolve the subscriber instance.\n     *\n     * @param  object|string  $subscriber\n     * @return mixed\n     */\n    protected function resolveSubscriber($subscriber)\n    {\n        if (is_string($subscriber)) {\n            return $this->container->make($subscriber);\n        }\n\n        return $subscriber;\n    }\n\n    /**\n     * Fire an event until the first non-null response is returned.\n     *\n     * @param  string|object  $event\n     * @param  mixed  $payload\n     * @return array|null\n     */\n    public function until($event, $payload = [])\n    {\n        return $this->dispatch($event, $payload, true);\n    }\n\n    /**\n     * Fire an event and call the listeners.\n     *\n     * @param  string|object  $event\n     * @param  mixed  $payload\n     * @param  bool  $halt\n     * @return array|null\n     */\n    public function dispatch($event, $payload = [], $halt = false)\n    {\n        // When the given \"event\" is actually an object we will assume it is an event\n        // object and use the class as the event name and this event itself as the\n        // payload to the handler, which makes object based events quite simple.\n        [$event, $payload] = $this->parseEventAndPayload(\n            $event, $payload\n        );\n\n        if ($this->shouldBroadcast($payload)) {\n            $this->broadcastEvent($payload[0]);\n        }\n\n        $responses = [];\n\n        foreach ($this->getListeners($event) as $listener) {\n            $response = $listener($event, $payload);\n\n            // If a response is returned from the listener and event halting is enabled\n            // we will just return this response, and not call the rest of the event\n            // listeners. Otherwise we will add the response on the response list.\n            if ($halt && ! is_null($response)) {\n                return $response;\n            }\n\n            // If a boolean false is returned from a listener, we will stop propagating\n            // the event to any further listeners down in the chain, else we keep on\n            // looping through the listeners and firing every one in our sequence.\n            if ($response === false) {\n                break;\n            }\n\n            $responses[] = $response;\n        }\n\n        return $halt ? null : $responses;\n    }\n\n    /**\n     * Parse the given event and payload and prepare them for dispatching.\n     *\n     * @param  mixed  $event\n     * @param  mixed  $payload\n     * @return array\n     */\n    protected function parseEventAndPayload($event, $payload)\n    {\n        if (is_object($event)) {\n            [$payload, $event] = [[$event], get_class($event)];\n        }\n\n        return [$event, Arr::wrap($payload)];\n    }\n\n    /**\n     * Determine if the payload has a broadcastable event.\n     *\n     * @param  array  $payload\n     * @return bool\n     */\n    protected function shouldBroadcast(array $payload)\n    {\n        return isset($payload[0]) &&\n               $payload[0] instanceof ShouldBroadcast &&\n               $this->broadcastWhen($payload[0]);\n    }\n\n    /**\n     * Check if the event should be broadcasted by the condition.\n     *\n     * @param  mixed  $event\n     * @return bool\n     */\n    protected function broadcastWhen($event)\n    {\n        return method_exists($event, 'broadcastWhen')\n                ? $event->broadcastWhen() : true;\n    }\n\n    /**\n     * Broadcast the given event class.\n     *\n     * @param  \\Illuminate\\Contracts\\Broadcasting\\ShouldBroadcast  $event\n     * @return void\n     */\n    protected function broadcastEvent($event)\n    {\n        $this->container->make(BroadcastFactory::class)->queue($event);\n    }\n\n    /**\n     * Get all of the listeners for a given event name.\n     *\n     * @param  string  $eventName\n     * @return array\n     */\n    public function getListeners($eventName)\n    {\n        $listeners = $this->listeners[$eventName] ?? [];\n\n        $listeners = array_merge(\n            $listeners,\n            $this->wildcardsCache[$eventName] ?? $this->getWildcardListeners($eventName)\n        );\n\n        return class_exists($eventName, false)\n                    ? $this->addInterfaceListeners($eventName, $listeners)\n                    : $listeners;\n    }\n\n    /**\n     * Get the wildcard listeners for the event.\n     *\n     * @param  string  $eventName\n     * @return array\n     */\n    protected function getWildcardListeners($eventName)\n    {\n        $wildcards = [];\n\n        foreach ($this->wildcards as $key => $listeners) {\n            if (Str::is($key, $eventName)) {\n                $wildcards = array_merge($wildcards, $listeners);\n            }\n        }\n\n        return $this->wildcardsCache[$eventName] = $wildcards;\n    }\n\n    /**\n     * Add the listeners for the event's interfaces to the given array.\n     *\n     * @param  string  $eventName\n     * @param  array  $listeners\n     * @return array\n     */\n    protected function addInterfaceListeners($eventName, array $listeners = [])\n    {\n        foreach (class_implements($eventName) as $interface) {\n            if (isset($this->listeners[$interface])) {\n                foreach ($this->listeners[$interface] as $names) {\n                    $listeners = array_merge($listeners, (array) $names);\n                }\n            }\n        }\n\n        return $listeners;\n    }\n\n    /**\n     * Register an event listener with the dispatcher.\n     *\n     * @param  \\Closure|string|array  $listener\n     * @param  bool  $wildcard\n     * @return \\Closure\n     */\n    public function makeListener($listener, $wildcard = false)\n    {\n        if (is_string($listener)) {\n            return $this->createClassListener($listener, $wildcard);\n        }\n\n        if (is_array($listener) && isset($listener[0]) && is_string($listener[0])) {\n            return $this->createClassListener($listener, $wildcard);\n        }\n\n        return function ($event, $payload) use ($listener, $wildcard) {\n            if ($wildcard) {\n                return $listener($event, $payload);\n            }\n\n            return $listener(...array_values($payload));\n        };\n    }\n\n    /**\n     * Create a class based listener using the IoC container.\n     *\n     * @param  string  $listener\n     * @param  bool  $wildcard\n     * @return \\Closure\n     */\n    public function createClassListener($listener, $wildcard = false)\n    {\n        return function ($event, $payload) use ($listener, $wildcard) {\n            if ($wildcard) {\n                return call_user_func($this->createClassCallable($listener), $event, $payload);\n            }\n\n            $callable = $this->createClassCallable($listener);\n\n            return $callable(...array_values($payload));\n        };\n    }\n\n    /**\n     * Create the class based event callable.\n     *\n     * @param  array|string  $listener\n     * @return callable\n     */\n    protected function createClassCallable($listener)\n    {\n        [$class, $method] = is_array($listener)\n                            ? $listener\n                            : $this->parseClassCallable($listener);\n\n        if (! method_exists($class, $method)) {\n            $method = '__invoke';\n        }\n\n        if ($this->handlerShouldBeQueued($class)) {\n            return $this->createQueuedHandlerCallable($class, $method);\n        }\n\n        $listener = $this->container->make($class);\n\n        return $this->handlerShouldBeDispatchedAfterDatabaseTransactions($listener)\n                    ? $this->createCallbackForListenerRunningAfterCommits($listener, $method)\n                    : [$listener, $method];\n    }\n\n    /**\n     * Parse the class listener into class and method.\n     *\n     * @param  string  $listener\n     * @return array\n     */\n    protected function parseClassCallable($listener)\n    {\n        return Str::parseCallback($listener, 'handle');\n    }\n\n    /**\n     * Determine if the event handler class should be queued.\n     *\n     * @param  string  $class\n     * @return bool\n     */\n    protected function handlerShouldBeQueued($class)\n    {\n        try {\n            return (new ReflectionClass($class))->implementsInterface(\n                ShouldQueue::class\n            );\n        } catch (Exception $e) {\n            return false;\n        }\n    }\n\n    /**\n     * Create a callable for putting an event handler on the queue.\n     *\n     * @param  string  $class\n     * @param  string  $method\n     * @return \\Closure\n     */\n    protected function createQueuedHandlerCallable($class, $method)\n    {\n        return function () use ($class, $method) {\n            $arguments = array_map(function ($a) {\n                return is_object($a) ? clone $a : $a;\n            }, func_get_args());\n\n            if ($this->handlerWantsToBeQueued($class, $arguments)) {\n                $this->queueHandler($class, $method, $arguments);\n            }\n        };\n    }\n\n    /**\n     * Determine if the given event handler should be dispatched after all database transactions have committed.\n     *\n     * @param  object|mixed  $listener\n     * @return bool\n     */\n    protected function handlerShouldBeDispatchedAfterDatabaseTransactions($listener)\n    {\n        return ($listener->afterCommit ?? null) && $this->container->bound('db.transactions');\n    }\n\n    /**\n     * Create a callable for dispatching a listener after database transactions.\n     *\n     * @param  mixed  $listener\n     * @param  string  $method\n     * @return \\Closure\n     */\n    protected function createCallbackForListenerRunningAfterCommits($listener, $method)\n    {\n        return function () use ($method, $listener) {\n            $payload = func_get_args();\n\n            $this->container->make('db.transactions')->addCallback(\n                function () use ($listener, $method, $payload) {\n                    $listener->$method(...$payload);\n                }\n            );\n        };\n    }\n\n    /**\n     * Determine if the event handler wants to be queued.\n     *\n     * @param  string  $class\n     * @param  array  $arguments\n     * @return bool\n     */\n    protected function handlerWantsToBeQueued($class, $arguments)\n    {\n        $instance = $this->container->make($class);\n\n        if (method_exists($instance, 'shouldQueue')) {\n            return $instance->shouldQueue($arguments[0]);\n        }\n\n        return true;\n    }\n\n    /**\n     * Queue the handler class.\n     *\n     * @param  string  $class\n     * @param  string  $method\n     * @param  array  $arguments\n     * @return void\n     */\n    protected function queueHandler($class, $method, $arguments)\n    {\n        [$listener, $job] = $this->createListenerAndJob($class, $method, $arguments);\n\n        $connection = $this->resolveQueue()->connection(method_exists($listener, 'viaConnection')\n                    ? $listener->viaConnection()\n                    : $listener->connection ?? null);\n\n        $queue = method_exists($listener, 'viaQueue')\n                    ? $listener->viaQueue()\n                    : $listener->queue ?? null;\n\n        isset($listener->delay)\n                    ? $connection->laterOn($queue, $listener->delay, $job)\n                    : $connection->pushOn($queue, $job);\n    }\n\n    /**\n     * Create the listener and job for a queued listener.\n     *\n     * @param  string  $class\n     * @param  string  $method\n     * @param  array  $arguments\n     * @return array\n     */\n    protected function createListenerAndJob($class, $method, $arguments)\n    {\n        $listener = (new ReflectionClass($class))->newInstanceWithoutConstructor();\n\n        return [$listener, $this->propagateListenerOptions(\n            $listener, new CallQueuedListener($class, $method, $arguments)\n        )];\n    }\n\n    /**\n     * Propagate listener options to the job.\n     *\n     * @param  mixed  $listener\n     * @param  mixed  $job\n     * @return mixed\n     */\n    protected function propagateListenerOptions($listener, $job)\n    {\n        return tap($job, function ($job) use ($listener) {\n            $job->afterCommit = property_exists($listener, 'afterCommit') ? $listener->afterCommit : null;\n            $job->backoff = method_exists($listener, 'backoff') ? $listener->backoff() : ($listener->backoff ?? null);\n            $job->maxExceptions = $listener->maxExceptions ?? null;\n            $job->retryUntil = method_exists($listener, 'retryUntil') ? $listener->retryUntil() : null;\n            $job->shouldBeEncrypted = $listener instanceof ShouldBeEncrypted;\n            $job->timeout = $listener->timeout ?? null;\n            $job->tries = $listener->tries ?? null;\n\n            $job->through(array_merge(\n                method_exists($listener, 'middleware') ? $listener->middleware() : [],\n                $listener->middleware ?? []\n            ));\n        });\n    }\n\n    /**\n     * Remove a set of listeners from the dispatcher.\n     *\n     * @param  string  $event\n     * @return void\n     */\n    public function forget($event)\n    {\n        if (Str::contains($event, '*')) {\n            unset($this->wildcards[$event]);\n        } else {\n            unset($this->listeners[$event]);\n        }\n\n        foreach ($this->wildcardsCache as $key => $listeners) {\n            if (Str::is($event, $key)) {\n                unset($this->wildcardsCache[$key]);\n            }\n        }\n    }\n\n    /**\n     * Forget all of the pushed listeners.\n     *\n     * @return void\n     */\n    public function forgetPushed()\n    {\n        foreach ($this->listeners as $key => $value) {\n            if (Str::endsWith($key, '_pushed')) {\n                $this->forget($key);\n            }\n        }\n    }\n\n    /**\n     * Get the queue implementation from the resolver.\n     *\n     * @return \\Illuminate\\Contracts\\Queue\\Queue\n     */\n    protected function resolveQueue()\n    {\n        return call_user_func($this->queueResolver);\n    }\n\n    /**\n     * Set the queue resolver implementation.\n     *\n     * @param  callable  $resolver\n     * @return $this\n     */\n    public function setQueueResolver(callable $resolver)\n    {\n        $this->queueResolver = $resolver;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/events/EventServiceProvider.php",
    "content": "<?php\n\nnamespace Illuminate\\Events;\n\nuse Illuminate\\Contracts\\Queue\\Factory as QueueFactoryContract;\nuse Illuminate\\Support\\ServiceProvider;\n\nclass EventServiceProvider extends ServiceProvider\n{\n    /**\n     * Register the service provider.\n     *\n     * @return void\n     */\n    public function register()\n    {\n        $this->app->singleton('events', function ($app) {\n            return (new Dispatcher($app))->setQueueResolver(function () use ($app) {\n                return $app->make(QueueFactoryContract::class);\n            });\n        });\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/events/InvokeQueuedClosure.php",
    "content": "<?php\n\nnamespace Illuminate\\Events;\n\nclass InvokeQueuedClosure\n{\n    /**\n     * Handle the event.\n     *\n     * @param  \\Laravel\\SerializableClosure\\SerializableClosure  $closure\n     * @param  array  $arguments\n     * @return void\n     */\n    public function handle($closure, array $arguments)\n    {\n        call_user_func($closure->getClosure(), ...$arguments);\n    }\n\n    /**\n     * Handle a job failure.\n     *\n     * @param  \\Laravel\\SerializableClosure\\SerializableClosure  $closure\n     * @param  array  $arguments\n     * @param  array  $catchCallbacks\n     * @param  \\Throwable  $exception\n     * @return void\n     */\n    public function failed($closure, array $arguments, array $catchCallbacks, $exception)\n    {\n        $arguments[] = $exception;\n\n        collect($catchCallbacks)->each->__invoke(...$arguments);\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/events/LICENSE.md",
    "content": "The MIT License (MIT)\n\nCopyright (c) Taylor Otwell\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "server/vendor/illuminate/events/NullDispatcher.php",
    "content": "<?php\n\nnamespace Illuminate\\Events;\n\nuse Illuminate\\Contracts\\Events\\Dispatcher as DispatcherContract;\nuse Illuminate\\Support\\Traits\\ForwardsCalls;\n\nclass NullDispatcher implements DispatcherContract\n{\n    use ForwardsCalls;\n\n    /**\n     * The underlying event dispatcher instance.\n     *\n     * @var \\Illuminate\\Contracts\\Events\\Dispatcher\n     */\n    protected $dispatcher;\n\n    /**\n     * Create a new event dispatcher instance that does not fire.\n     *\n     * @param  \\Illuminate\\Contracts\\Events\\Dispatcher  $dispatcher\n     * @return void\n     */\n    public function __construct(DispatcherContract $dispatcher)\n    {\n        $this->dispatcher = $dispatcher;\n    }\n\n    /**\n     * Don't fire an event.\n     *\n     * @param  string|object  $event\n     * @param  mixed  $payload\n     * @param  bool  $halt\n     * @return void\n     */\n    public function dispatch($event, $payload = [], $halt = false)\n    {\n        //\n    }\n\n    /**\n     * Don't register an event and payload to be fired later.\n     *\n     * @param  string  $event\n     * @param  array  $payload\n     * @return void\n     */\n    public function push($event, $payload = [])\n    {\n        //\n    }\n\n    /**\n     * Don't dispatch an event.\n     *\n     * @param  string|object  $event\n     * @param  mixed  $payload\n     * @return array|null\n     */\n    public function until($event, $payload = [])\n    {\n        //\n    }\n\n    /**\n     * Register an event listener with the dispatcher.\n     *\n     * @param  \\Closure|string|array  $events\n     * @param  \\Closure|string|array|null  $listener\n     * @return void\n     */\n    public function listen($events, $listener = null)\n    {\n        $this->dispatcher->listen($events, $listener);\n    }\n\n    /**\n     * Determine if a given event has listeners.\n     *\n     * @param  string  $eventName\n     * @return bool\n     */\n    public function hasListeners($eventName)\n    {\n        return $this->dispatcher->hasListeners($eventName);\n    }\n\n    /**\n     * Register an event subscriber with the dispatcher.\n     *\n     * @param  object|string  $subscriber\n     * @return void\n     */\n    public function subscribe($subscriber)\n    {\n        $this->dispatcher->subscribe($subscriber);\n    }\n\n    /**\n     * Flush a set of pushed events.\n     *\n     * @param  string  $event\n     * @return void\n     */\n    public function flush($event)\n    {\n        $this->dispatcher->flush($event);\n    }\n\n    /**\n     * Remove a set of listeners from the dispatcher.\n     *\n     * @param  string  $event\n     * @return void\n     */\n    public function forget($event)\n    {\n        $this->dispatcher->forget($event);\n    }\n\n    /**\n     * Forget all of the queued listeners.\n     *\n     * @return void\n     */\n    public function forgetPushed()\n    {\n        $this->dispatcher->forgetPushed();\n    }\n\n    /**\n     * Dynamically pass method calls to the underlying dispatcher.\n     *\n     * @param  string  $method\n     * @param  array  $parameters\n     * @return mixed\n     */\n    public function __call($method, $parameters)\n    {\n        return $this->forwardCallTo($this->dispatcher, $method, $parameters);\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/events/QueuedClosure.php",
    "content": "<?php\n\nnamespace Illuminate\\Events;\n\nuse Closure;\nuse Illuminate\\Queue\\SerializableClosureFactory;\n\nclass QueuedClosure\n{\n    /**\n     * The underlying Closure.\n     *\n     * @var \\Closure\n     */\n    public $closure;\n\n    /**\n     * The name of the connection the job should be sent to.\n     *\n     * @var string|null\n     */\n    public $connection;\n\n    /**\n     * The name of the queue the job should be sent to.\n     *\n     * @var string|null\n     */\n    public $queue;\n\n    /**\n     * The number of seconds before the job should be made available.\n     *\n     * @var \\DateTimeInterface|\\DateInterval|int|null\n     */\n    public $delay;\n\n    /**\n     * All of the \"catch\" callbacks for the queued closure.\n     *\n     * @var array\n     */\n    public $catchCallbacks = [];\n\n    /**\n     * Create a new queued closure event listener resolver.\n     *\n     * @param  \\Closure  $closure\n     * @return void\n     */\n    public function __construct(Closure $closure)\n    {\n        $this->closure = $closure;\n    }\n\n    /**\n     * Set the desired connection for the job.\n     *\n     * @param  string|null  $connection\n     * @return $this\n     */\n    public function onConnection($connection)\n    {\n        $this->connection = $connection;\n\n        return $this;\n    }\n\n    /**\n     * Set the desired queue for the job.\n     *\n     * @param  string|null  $queue\n     * @return $this\n     */\n    public function onQueue($queue)\n    {\n        $this->queue = $queue;\n\n        return $this;\n    }\n\n    /**\n     * Set the desired delay for the job.\n     *\n     * @param  \\DateTimeInterface|\\DateInterval|int|null  $delay\n     * @return $this\n     */\n    public function delay($delay)\n    {\n        $this->delay = $delay;\n\n        return $this;\n    }\n\n    /**\n     * Specify a callback that should be invoked if the queued listener job fails.\n     *\n     * @param  \\Closure  $closure\n     * @return $this\n     */\n    public function catch(Closure $closure)\n    {\n        $this->catchCallbacks[] = $closure;\n\n        return $this;\n    }\n\n    /**\n     * Resolve the actual event listener callback.\n     *\n     * @return \\Closure\n     */\n    public function resolve()\n    {\n        return function (...$arguments) {\n            dispatch(new CallQueuedListener(InvokeQueuedClosure::class, 'handle', [\n                'closure' => SerializableClosureFactory::make($this->closure),\n                'arguments' => $arguments,\n                'catch' => collect($this->catchCallbacks)->map(function ($callback) {\n                    return SerializableClosureFactory::make($callback);\n                })->all(),\n            ]))->onConnection($this->connection)->onQueue($this->queue)->delay($this->delay);\n        };\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/events/composer.json",
    "content": "{\n    \"name\": \"illuminate/events\",\n    \"description\": \"The Illuminate Events package.\",\n    \"license\": \"MIT\",\n    \"homepage\": \"https://laravel.com\",\n    \"support\": {\n        \"issues\": \"https://github.com/laravel/framework/issues\",\n        \"source\": \"https://github.com/laravel/framework\"\n    },\n    \"authors\": [\n        {\n            \"name\": \"Taylor Otwell\",\n            \"email\": \"taylor@laravel.com\"\n        }\n    ],\n    \"require\": {\n        \"php\": \"^7.3|^8.0\",\n        \"illuminate/bus\": \"^8.0\",\n        \"illuminate/collections\": \"^8.0\",\n        \"illuminate/container\": \"^8.0\",\n        \"illuminate/contracts\": \"^8.0\",\n        \"illuminate/macroable\": \"^8.0\",\n        \"illuminate/support\": \"^8.0\"\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"Illuminate\\\\Events\\\\\": \"\"\n        },\n        \"files\": [\n            \"functions.php\"\n        ]\n    },\n    \"extra\": {\n        \"branch-alias\": {\n            \"dev-master\": \"8.x-dev\"\n        }\n    },\n    \"config\": {\n        \"sort-packages\": true\n    },\n    \"minimum-stability\": \"dev\"\n}\n"
  },
  {
    "path": "server/vendor/illuminate/events/functions.php",
    "content": "<?php\n\nnamespace Illuminate\\Events;\n\nuse Closure;\n\nif (! function_exists('Illuminate\\Events\\queueable')) {\n    /**\n     * Create a new queued Closure event listener.\n     *\n     * @param  \\Closure  $closure\n     * @return \\Illuminate\\Events\\QueuedClosure\n     */\n    function queueable(Closure $closure)\n    {\n        return new QueuedClosure($closure);\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/macroable/LICENSE.md",
    "content": "The MIT License (MIT)\n\nCopyright (c) Taylor Otwell\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "server/vendor/illuminate/macroable/Traits/Macroable.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Traits;\n\nuse BadMethodCallException;\nuse Closure;\nuse ReflectionClass;\nuse ReflectionMethod;\n\ntrait Macroable\n{\n    /**\n     * The registered string macros.\n     *\n     * @var array\n     */\n    protected static $macros = [];\n\n    /**\n     * Register a custom macro.\n     *\n     * @param  string  $name\n     * @param  object|callable  $macro\n     * @return void\n     */\n    public static function macro($name, $macro)\n    {\n        static::$macros[$name] = $macro;\n    }\n\n    /**\n     * Mix another object into the class.\n     *\n     * @param  object  $mixin\n     * @param  bool  $replace\n     * @return void\n     *\n     * @throws \\ReflectionException\n     */\n    public static function mixin($mixin, $replace = true)\n    {\n        $methods = (new ReflectionClass($mixin))->getMethods(\n            ReflectionMethod::IS_PUBLIC | ReflectionMethod::IS_PROTECTED\n        );\n\n        foreach ($methods as $method) {\n            if ($replace || ! static::hasMacro($method->name)) {\n                $method->setAccessible(true);\n                static::macro($method->name, $method->invoke($mixin));\n            }\n        }\n    }\n\n    /**\n     * Checks if macro is registered.\n     *\n     * @param  string  $name\n     * @return bool\n     */\n    public static function hasMacro($name)\n    {\n        return isset(static::$macros[$name]);\n    }\n\n    /**\n     * Flush the existing macros.\n     *\n     * @return void\n     */\n    public static function flushMacros()\n    {\n        static::$macros = [];\n    }\n\n    /**\n     * Dynamically handle calls to the class.\n     *\n     * @param  string  $method\n     * @param  array  $parameters\n     * @return mixed\n     *\n     * @throws \\BadMethodCallException\n     */\n    public static function __callStatic($method, $parameters)\n    {\n        if (! static::hasMacro($method)) {\n            throw new BadMethodCallException(sprintf(\n                'Method %s::%s does not exist.', static::class, $method\n            ));\n        }\n\n        $macro = static::$macros[$method];\n\n        if ($macro instanceof Closure) {\n            $macro = $macro->bindTo(null, static::class);\n        }\n\n        return $macro(...$parameters);\n    }\n\n    /**\n     * Dynamically handle calls to the class.\n     *\n     * @param  string  $method\n     * @param  array  $parameters\n     * @return mixed\n     *\n     * @throws \\BadMethodCallException\n     */\n    public function __call($method, $parameters)\n    {\n        if (! static::hasMacro($method)) {\n            throw new BadMethodCallException(sprintf(\n                'Method %s::%s does not exist.', static::class, $method\n            ));\n        }\n\n        $macro = static::$macros[$method];\n\n        if ($macro instanceof Closure) {\n            $macro = $macro->bindTo($this, static::class);\n        }\n\n        return $macro(...$parameters);\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/macroable/composer.json",
    "content": "{\n    \"name\": \"illuminate/macroable\",\n    \"description\": \"The Illuminate Macroable package.\",\n    \"license\": \"MIT\",\n    \"homepage\": \"https://laravel.com\",\n    \"support\": {\n        \"issues\": \"https://github.com/laravel/framework/issues\",\n        \"source\": \"https://github.com/laravel/framework\"\n    },\n    \"authors\": [\n        {\n            \"name\": \"Taylor Otwell\",\n            \"email\": \"taylor@laravel.com\"\n        }\n    ],\n    \"require\": {\n        \"php\": \"^7.3|^8.0\"\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"Illuminate\\\\Support\\\\\": \"\"\n        }\n    },\n    \"extra\": {\n        \"branch-alias\": {\n            \"dev-master\": \"8.x-dev\"\n        }\n    },\n    \"config\": {\n        \"sort-packages\": true\n    },\n    \"minimum-stability\": \"dev\"\n}\n"
  },
  {
    "path": "server/vendor/illuminate/pipeline/Hub.php",
    "content": "<?php\n\nnamespace Illuminate\\Pipeline;\n\nuse Closure;\nuse Illuminate\\Contracts\\Container\\Container;\nuse Illuminate\\Contracts\\Pipeline\\Hub as HubContract;\n\nclass Hub implements HubContract\n{\n    /**\n     * The container implementation.\n     *\n     * @var \\Illuminate\\Contracts\\Container\\Container|null\n     */\n    protected $container;\n\n    /**\n     * All of the available pipelines.\n     *\n     * @var array\n     */\n    protected $pipelines = [];\n\n    /**\n     * Create a new Hub instance.\n     *\n     * @param  \\Illuminate\\Contracts\\Container\\Container|null  $container\n     * @return void\n     */\n    public function __construct(Container $container = null)\n    {\n        $this->container = $container;\n    }\n\n    /**\n     * Define the default named pipeline.\n     *\n     * @param  \\Closure  $callback\n     * @return void\n     */\n    public function defaults(Closure $callback)\n    {\n        return $this->pipeline('default', $callback);\n    }\n\n    /**\n     * Define a new named pipeline.\n     *\n     * @param  string  $name\n     * @param  \\Closure  $callback\n     * @return void\n     */\n    public function pipeline($name, Closure $callback)\n    {\n        $this->pipelines[$name] = $callback;\n    }\n\n    /**\n     * Send an object through one of the available pipelines.\n     *\n     * @param  mixed  $object\n     * @param  string|null  $pipeline\n     * @return mixed\n     */\n    public function pipe($object, $pipeline = null)\n    {\n        $pipeline = $pipeline ?: 'default';\n\n        return call_user_func(\n            $this->pipelines[$pipeline], new Pipeline($this->container), $object\n        );\n    }\n\n    /**\n     * Get the container instance used by the hub.\n     *\n     * @return \\Illuminate\\Contracts\\Container\\Container\n     */\n    public function getContainer()\n    {\n        return $this->container;\n    }\n\n    /**\n     * Set the container instance used by the hub.\n     *\n     * @param  \\Illuminate\\Contracts\\Container\\Container  $container\n     * @return $this\n     */\n    public function setContainer(Container $container)\n    {\n        $this->container = $container;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/pipeline/LICENSE.md",
    "content": "The MIT License (MIT)\n\nCopyright (c) Taylor Otwell\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "server/vendor/illuminate/pipeline/Pipeline.php",
    "content": "<?php\n\nnamespace Illuminate\\Pipeline;\n\nuse Closure;\nuse Illuminate\\Contracts\\Container\\Container;\nuse Illuminate\\Contracts\\Pipeline\\Pipeline as PipelineContract;\nuse RuntimeException;\nuse Throwable;\n\nclass Pipeline implements PipelineContract\n{\n    /**\n     * The container implementation.\n     *\n     * @var \\Illuminate\\Contracts\\Container\\Container\n     */\n    protected $container;\n\n    /**\n     * The object being passed through the pipeline.\n     *\n     * @var mixed\n     */\n    protected $passable;\n\n    /**\n     * The array of class pipes.\n     *\n     * @var array\n     */\n    protected $pipes = [];\n\n    /**\n     * The method to call on each pipe.\n     *\n     * @var string\n     */\n    protected $method = 'handle';\n\n    /**\n     * Create a new class instance.\n     *\n     * @param  \\Illuminate\\Contracts\\Container\\Container|null  $container\n     * @return void\n     */\n    public function __construct(Container $container = null)\n    {\n        $this->container = $container;\n    }\n\n    /**\n     * Set the object being sent through the pipeline.\n     *\n     * @param  mixed  $passable\n     * @return $this\n     */\n    public function send($passable)\n    {\n        $this->passable = $passable;\n\n        return $this;\n    }\n\n    /**\n     * Set the array of pipes.\n     *\n     * @param  array|mixed  $pipes\n     * @return $this\n     */\n    public function through($pipes)\n    {\n        $this->pipes = is_array($pipes) ? $pipes : func_get_args();\n\n        return $this;\n    }\n\n    /**\n     * Set the method to call on the pipes.\n     *\n     * @param  string  $method\n     * @return $this\n     */\n    public function via($method)\n    {\n        $this->method = $method;\n\n        return $this;\n    }\n\n    /**\n     * Run the pipeline with a final destination callback.\n     *\n     * @param  \\Closure  $destination\n     * @return mixed\n     */\n    public function then(Closure $destination)\n    {\n        $pipeline = array_reduce(\n            array_reverse($this->pipes()), $this->carry(), $this->prepareDestination($destination)\n        );\n\n        return $pipeline($this->passable);\n    }\n\n    /**\n     * Run the pipeline and return the result.\n     *\n     * @return mixed\n     */\n    public function thenReturn()\n    {\n        return $this->then(function ($passable) {\n            return $passable;\n        });\n    }\n\n    /**\n     * Get the final piece of the Closure onion.\n     *\n     * @param  \\Closure  $destination\n     * @return \\Closure\n     */\n    protected function prepareDestination(Closure $destination)\n    {\n        return function ($passable) use ($destination) {\n            try {\n                return $destination($passable);\n            } catch (Throwable $e) {\n                return $this->handleException($passable, $e);\n            }\n        };\n    }\n\n    /**\n     * Get a Closure that represents a slice of the application onion.\n     *\n     * @return \\Closure\n     */\n    protected function carry()\n    {\n        return function ($stack, $pipe) {\n            return function ($passable) use ($stack, $pipe) {\n                try {\n                    if (is_callable($pipe)) {\n                        // If the pipe is a callable, then we will call it directly, but otherwise we\n                        // will resolve the pipes out of the dependency container and call it with\n                        // the appropriate method and arguments, returning the results back out.\n                        return $pipe($passable, $stack);\n                    } elseif (! is_object($pipe)) {\n                        [$name, $parameters] = $this->parsePipeString($pipe);\n\n                        // If the pipe is a string we will parse the string and resolve the class out\n                        // of the dependency injection container. We can then build a callable and\n                        // execute the pipe function giving in the parameters that are required.\n                        $pipe = $this->getContainer()->make($name);\n\n                        $parameters = array_merge([$passable, $stack], $parameters);\n                    } else {\n                        // If the pipe is already an object we'll just make a callable and pass it to\n                        // the pipe as-is. There is no need to do any extra parsing and formatting\n                        // since the object we're given was already a fully instantiated object.\n                        $parameters = [$passable, $stack];\n                    }\n\n                    $carry = method_exists($pipe, $this->method)\n                                    ? $pipe->{$this->method}(...$parameters)\n                                    : $pipe(...$parameters);\n\n                    return $this->handleCarry($carry);\n                } catch (Throwable $e) {\n                    return $this->handleException($passable, $e);\n                }\n            };\n        };\n    }\n\n    /**\n     * Parse full pipe string to get name and parameters.\n     *\n     * @param  string  $pipe\n     * @return array\n     */\n    protected function parsePipeString($pipe)\n    {\n        [$name, $parameters] = array_pad(explode(':', $pipe, 2), 2, []);\n\n        if (is_string($parameters)) {\n            $parameters = explode(',', $parameters);\n        }\n\n        return [$name, $parameters];\n    }\n\n    /**\n     * Get the array of configured pipes.\n     *\n     * @return array\n     */\n    protected function pipes()\n    {\n        return $this->pipes;\n    }\n\n    /**\n     * Get the container instance.\n     *\n     * @return \\Illuminate\\Contracts\\Container\\Container\n     *\n     * @throws \\RuntimeException\n     */\n    protected function getContainer()\n    {\n        if (! $this->container) {\n            throw new RuntimeException('A container instance has not been passed to the Pipeline.');\n        }\n\n        return $this->container;\n    }\n\n    /**\n     * Set the container instance.\n     *\n     * @param  \\Illuminate\\Contracts\\Container\\Container  $container\n     * @return $this\n     */\n    public function setContainer(Container $container)\n    {\n        $this->container = $container;\n\n        return $this;\n    }\n\n    /**\n     * Handle the value returned from each pipe before passing it to the next.\n     *\n     * @param  mixed  $carry\n     * @return mixed\n     */\n    protected function handleCarry($carry)\n    {\n        return $carry;\n    }\n\n    /**\n     * Handle the given exception.\n     *\n     * @param  mixed  $passable\n     * @param  \\Throwable  $e\n     * @return mixed\n     *\n     * @throws \\Throwable\n     */\n    protected function handleException($passable, Throwable $e)\n    {\n        throw $e;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/pipeline/PipelineServiceProvider.php",
    "content": "<?php\n\nnamespace Illuminate\\Pipeline;\n\nuse Illuminate\\Contracts\\Pipeline\\Hub as PipelineHubContract;\nuse Illuminate\\Contracts\\Support\\DeferrableProvider;\nuse Illuminate\\Support\\ServiceProvider;\n\nclass PipelineServiceProvider extends ServiceProvider implements DeferrableProvider\n{\n    /**\n     * Register the service provider.\n     *\n     * @return void\n     */\n    public function register()\n    {\n        $this->app->singleton(\n            PipelineHubContract::class, Hub::class\n        );\n    }\n\n    /**\n     * Get the services provided by the provider.\n     *\n     * @return array\n     */\n    public function provides()\n    {\n        return [\n            PipelineHubContract::class,\n        ];\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/pipeline/composer.json",
    "content": "{\n    \"name\": \"illuminate/pipeline\",\n    \"description\": \"The Illuminate Pipeline package.\",\n    \"license\": \"MIT\",\n    \"homepage\": \"https://laravel.com\",\n    \"support\": {\n        \"issues\": \"https://github.com/laravel/framework/issues\",\n        \"source\": \"https://github.com/laravel/framework\"\n    },\n    \"authors\": [\n        {\n            \"name\": \"Taylor Otwell\",\n            \"email\": \"taylor@laravel.com\"\n        }\n    ],\n    \"require\": {\n        \"php\": \"^7.3|^8.0\",\n        \"illuminate/contracts\": \"^8.0\",\n        \"illuminate/support\": \"^8.0\"\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"Illuminate\\\\Pipeline\\\\\": \"\"\n        }\n    },\n    \"extra\": {\n        \"branch-alias\": {\n            \"dev-master\": \"8.x-dev\"\n        }\n    },\n    \"config\": {\n        \"sort-packages\": true\n    },\n    \"minimum-stability\": \"dev\"\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/AggregateServiceProvider.php",
    "content": "<?php\n\nnamespace Illuminate\\Support;\n\nclass AggregateServiceProvider extends ServiceProvider\n{\n    /**\n     * The provider class names.\n     *\n     * @var array\n     */\n    protected $providers = [];\n\n    /**\n     * An array of the service provider instances.\n     *\n     * @var array\n     */\n    protected $instances = [];\n\n    /**\n     * Register the service provider.\n     *\n     * @return void\n     */\n    public function register()\n    {\n        $this->instances = [];\n\n        foreach ($this->providers as $provider) {\n            $this->instances[] = $this->app->register($provider);\n        }\n    }\n\n    /**\n     * Get the services provided by the provider.\n     *\n     * @return array\n     */\n    public function provides()\n    {\n        $provides = [];\n\n        foreach ($this->providers as $provider) {\n            $instance = $this->app->resolveProvider($provider);\n\n            $provides = array_merge($provides, $instance->provides());\n        }\n\n        return $provides;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Carbon.php",
    "content": "<?php\n\nnamespace Illuminate\\Support;\n\nuse Carbon\\Carbon as BaseCarbon;\nuse Carbon\\CarbonImmutable as BaseCarbonImmutable;\n\nclass Carbon extends BaseCarbon\n{\n    /**\n     * {@inheritdoc}\n     */\n    public static function setTestNow($testNow = null)\n    {\n        BaseCarbon::setTestNow($testNow);\n        BaseCarbonImmutable::setTestNow($testNow);\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Composer.php",
    "content": "<?php\n\nnamespace Illuminate\\Support;\n\nuse Illuminate\\Filesystem\\Filesystem;\nuse Symfony\\Component\\Process\\PhpExecutableFinder;\nuse Symfony\\Component\\Process\\Process;\n\nclass Composer\n{\n    /**\n     * The filesystem instance.\n     *\n     * @var \\Illuminate\\Filesystem\\Filesystem\n     */\n    protected $files;\n\n    /**\n     * The working path to regenerate from.\n     *\n     * @var string|null\n     */\n    protected $workingPath;\n\n    /**\n     * Create a new Composer manager instance.\n     *\n     * @param  \\Illuminate\\Filesystem\\Filesystem  $files\n     * @param  string|null  $workingPath\n     * @return void\n     */\n    public function __construct(Filesystem $files, $workingPath = null)\n    {\n        $this->files = $files;\n        $this->workingPath = $workingPath;\n    }\n\n    /**\n     * Regenerate the Composer autoloader files.\n     *\n     * @param  string|array  $extra\n     * @return int\n     */\n    public function dumpAutoloads($extra = '')\n    {\n        $extra = $extra ? (array) $extra : [];\n\n        $command = array_merge($this->findComposer(), ['dump-autoload'], $extra);\n\n        return $this->getProcess($command)->run();\n    }\n\n    /**\n     * Regenerate the optimized Composer autoloader files.\n     *\n     * @return int\n     */\n    public function dumpOptimized()\n    {\n        return $this->dumpAutoloads('--optimize');\n    }\n\n    /**\n     * Get the composer command for the environment.\n     *\n     * @return array\n     */\n    protected function findComposer()\n    {\n        if ($this->files->exists($this->workingPath.'/composer.phar')) {\n            return [$this->phpBinary(), 'composer.phar'];\n        }\n\n        return ['composer'];\n    }\n\n    /**\n     * Get the PHP binary.\n     *\n     * @return string\n     */\n    protected function phpBinary()\n    {\n        return ProcessUtils::escapeArgument((new PhpExecutableFinder)->find(false));\n    }\n\n    /**\n     * Get a new Symfony process instance.\n     *\n     * @param  array  $command\n     * @return \\Symfony\\Component\\Process\\Process\n     */\n    protected function getProcess(array $command)\n    {\n        return (new Process($command, $this->workingPath))->setTimeout(null);\n    }\n\n    /**\n     * Set the working path used by the class.\n     *\n     * @param  string  $path\n     * @return $this\n     */\n    public function setWorkingPath($path)\n    {\n        $this->workingPath = realpath($path);\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/ConfigurationUrlParser.php",
    "content": "<?php\n\nnamespace Illuminate\\Support;\n\nuse InvalidArgumentException;\n\nclass ConfigurationUrlParser\n{\n    /**\n     * The drivers aliases map.\n     *\n     * @var array\n     */\n    protected static $driverAliases = [\n        'mssql' => 'sqlsrv',\n        'mysql2' => 'mysql', // RDS\n        'postgres' => 'pgsql',\n        'postgresql' => 'pgsql',\n        'sqlite3' => 'sqlite',\n        'redis' => 'tcp',\n        'rediss' => 'tls',\n    ];\n\n    /**\n     * Parse the database configuration, hydrating options using a database configuration URL if possible.\n     *\n     * @param  array|string  $config\n     * @return array\n     */\n    public function parseConfiguration($config)\n    {\n        if (is_string($config)) {\n            $config = ['url' => $config];\n        }\n\n        $url = Arr::pull($config, 'url');\n\n        if (! $url) {\n            return $config;\n        }\n\n        $rawComponents = $this->parseUrl($url);\n\n        $decodedComponents = $this->parseStringsToNativeTypes(\n            array_map('rawurldecode', $rawComponents)\n        );\n\n        return array_merge(\n            $config,\n            $this->getPrimaryOptions($decodedComponents),\n            $this->getQueryOptions($rawComponents)\n        );\n    }\n\n    /**\n     * Get the primary database connection options.\n     *\n     * @param  array  $url\n     * @return array\n     */\n    protected function getPrimaryOptions($url)\n    {\n        return array_filter([\n            'driver' => $this->getDriver($url),\n            'database' => $this->getDatabase($url),\n            'host' => $url['host'] ?? null,\n            'port' => $url['port'] ?? null,\n            'username' => $url['user'] ?? null,\n            'password' => $url['pass'] ?? null,\n        ], function ($value) {\n            return ! is_null($value);\n        });\n    }\n\n    /**\n     * Get the database driver from the URL.\n     *\n     * @param  array  $url\n     * @return string|null\n     */\n    protected function getDriver($url)\n    {\n        $alias = $url['scheme'] ?? null;\n\n        if (! $alias) {\n            return;\n        }\n\n        return static::$driverAliases[$alias] ?? $alias;\n    }\n\n    /**\n     * Get the database name from the URL.\n     *\n     * @param  array  $url\n     * @return string|null\n     */\n    protected function getDatabase($url)\n    {\n        $path = $url['path'] ?? null;\n\n        return $path && $path !== '/' ? substr($path, 1) : null;\n    }\n\n    /**\n     * Get all of the additional database options from the query string.\n     *\n     * @param  array  $url\n     * @return array\n     */\n    protected function getQueryOptions($url)\n    {\n        $queryString = $url['query'] ?? null;\n\n        if (! $queryString) {\n            return [];\n        }\n\n        $query = [];\n\n        parse_str($queryString, $query);\n\n        return $this->parseStringsToNativeTypes($query);\n    }\n\n    /**\n     * Parse the string URL to an array of components.\n     *\n     * @param  string  $url\n     * @return array\n     *\n     * @throws \\InvalidArgumentException\n     */\n    protected function parseUrl($url)\n    {\n        $url = preg_replace('#^(sqlite3?):///#', '$1://null/', $url);\n\n        $parsedUrl = parse_url($url);\n\n        if ($parsedUrl === false) {\n            throw new InvalidArgumentException('The database configuration URL is malformed.');\n        }\n\n        return $parsedUrl;\n    }\n\n    /**\n     * Convert string casted values to their native types.\n     *\n     * @param  mixed  $value\n     * @return mixed\n     */\n    protected function parseStringsToNativeTypes($value)\n    {\n        if (is_array($value)) {\n            return array_map([$this, 'parseStringsToNativeTypes'], $value);\n        }\n\n        if (! is_string($value)) {\n            return $value;\n        }\n\n        $parsedValue = json_decode($value, true);\n\n        if (json_last_error() === JSON_ERROR_NONE) {\n            return $parsedValue;\n        }\n\n        return $value;\n    }\n\n    /**\n     * Get all of the current drivers' aliases.\n     *\n     * @return array\n     */\n    public static function getDriverAliases()\n    {\n        return static::$driverAliases;\n    }\n\n    /**\n     * Add the given driver alias to the driver aliases array.\n     *\n     * @param  string  $alias\n     * @param  string  $driver\n     * @return void\n     */\n    public static function addDriverAlias($alias, $driver)\n    {\n        static::$driverAliases[$alias] = $driver;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/DateFactory.php",
    "content": "<?php\n\nnamespace Illuminate\\Support;\n\nuse Carbon\\Factory;\nuse InvalidArgumentException;\n\n/**\n * @see https://carbon.nesbot.com/docs/\n * @see https://github.com/briannesbitt/Carbon/blob/master/src/Carbon/Factory.php\n *\n * @method static Carbon create($year = 0, $month = 1, $day = 1, $hour = 0, $minute = 0, $second = 0, $tz = null)\n * @method static Carbon createFromDate($year = null, $month = null, $day = null, $tz = null)\n * @method static Carbon|false createFromFormat($format, $time, $tz = null)\n * @method static Carbon createFromTime($hour = 0, $minute = 0, $second = 0, $tz = null)\n * @method static Carbon createFromTimeString($time, $tz = null)\n * @method static Carbon createFromTimestamp($timestamp, $tz = null)\n * @method static Carbon createFromTimestampMs($timestamp, $tz = null)\n * @method static Carbon createFromTimestampUTC($timestamp)\n * @method static Carbon createMidnightDate($year = null, $month = null, $day = null, $tz = null)\n * @method static Carbon|false createSafe($year = null, $month = null, $day = null, $hour = null, $minute = null, $second = null, $tz = null)\n * @method static Carbon disableHumanDiffOption($humanDiffOption)\n * @method static Carbon enableHumanDiffOption($humanDiffOption)\n * @method static mixed executeWithLocale($locale, $func)\n * @method static Carbon fromSerialized($value)\n * @method static array getAvailableLocales()\n * @method static array getDays()\n * @method static int getHumanDiffOptions()\n * @method static array getIsoUnits()\n * @method static Carbon getLastErrors()\n * @method static string getLocale()\n * @method static int getMidDayAt()\n * @method static Carbon getTestNow()\n * @method static \\Symfony\\Component\\Translation\\TranslatorInterface getTranslator()\n * @method static int getWeekEndsAt()\n * @method static int getWeekStartsAt()\n * @method static array getWeekendDays()\n * @method static bool hasFormat($date, $format)\n * @method static bool hasMacro($name)\n * @method static bool hasRelativeKeywords($time)\n * @method static bool hasTestNow()\n * @method static Carbon instance($date)\n * @method static bool isImmutable()\n * @method static bool isModifiableUnit($unit)\n * @method static Carbon isMutable()\n * @method static bool isStrictModeEnabled()\n * @method static bool localeHasDiffOneDayWords($locale)\n * @method static bool localeHasDiffSyntax($locale)\n * @method static bool localeHasDiffTwoDayWords($locale)\n * @method static bool localeHasPeriodSyntax($locale)\n * @method static bool localeHasShortUnits($locale)\n * @method static void macro($name, $macro)\n * @method static Carbon|null make($var)\n * @method static Carbon maxValue()\n * @method static Carbon minValue()\n * @method static void mixin($mixin)\n * @method static Carbon now($tz = null)\n * @method static Carbon parse($time = null, $tz = null)\n * @method static string pluralUnit(string $unit)\n * @method static void resetMonthsOverflow()\n * @method static void resetToStringFormat()\n * @method static void resetYearsOverflow()\n * @method static void serializeUsing($callback)\n * @method static Carbon setHumanDiffOptions($humanDiffOptions)\n * @method static bool setLocale($locale)\n * @method static void setMidDayAt($hour)\n * @method static void setTestNow($testNow = null)\n * @method static void setToStringFormat($format)\n * @method static void setTranslator(\\Symfony\\Component\\Translation\\TranslatorInterface $translator)\n * @method static Carbon setUtf8($utf8)\n * @method static void setWeekEndsAt($day)\n * @method static void setWeekStartsAt($day)\n * @method static void setWeekendDays($days)\n * @method static bool shouldOverflowMonths()\n * @method static bool shouldOverflowYears()\n * @method static string singularUnit(string $unit)\n * @method static Carbon today($tz = null)\n * @method static Carbon tomorrow($tz = null)\n * @method static void useMonthsOverflow($monthsOverflow = true)\n * @method static Carbon useStrictMode($strictModeEnabled = true)\n * @method static void useYearsOverflow($yearsOverflow = true)\n * @method static Carbon yesterday($tz = null)\n */\nclass DateFactory\n{\n    /**\n     * The default class that will be used for all created dates.\n     *\n     * @var string\n     */\n    const DEFAULT_CLASS_NAME = Carbon::class;\n\n    /**\n     * The type (class) of dates that should be created.\n     *\n     * @var string\n     */\n    protected static $dateClass;\n\n    /**\n     * This callable may be used to intercept date creation.\n     *\n     * @var callable\n     */\n    protected static $callable;\n\n    /**\n     * The Carbon factory that should be used when creating dates.\n     *\n     * @var object\n     */\n    protected static $factory;\n\n    /**\n     * Use the given handler when generating dates (class name, callable, or factory).\n     *\n     * @param  mixed  $handler\n     * @return mixed\n     *\n     * @throws \\InvalidArgumentException\n     */\n    public static function use($handler)\n    {\n        if (is_callable($handler) && is_object($handler)) {\n            return static::useCallable($handler);\n        } elseif (is_string($handler)) {\n            return static::useClass($handler);\n        } elseif ($handler instanceof Factory) {\n            return static::useFactory($handler);\n        }\n\n        throw new InvalidArgumentException('Invalid date creation handler. Please provide a class name, callable, or Carbon factory.');\n    }\n\n    /**\n     * Use the default date class when generating dates.\n     *\n     * @return void\n     */\n    public static function useDefault()\n    {\n        static::$dateClass = null;\n        static::$callable = null;\n        static::$factory = null;\n    }\n\n    /**\n     * Execute the given callable on each date creation.\n     *\n     * @param  callable  $callable\n     * @return void\n     */\n    public static function useCallable(callable $callable)\n    {\n        static::$callable = $callable;\n\n        static::$dateClass = null;\n        static::$factory = null;\n    }\n\n    /**\n     * Use the given date type (class) when generating dates.\n     *\n     * @param  string  $dateClass\n     * @return void\n     */\n    public static function useClass($dateClass)\n    {\n        static::$dateClass = $dateClass;\n\n        static::$factory = null;\n        static::$callable = null;\n    }\n\n    /**\n     * Use the given Carbon factory when generating dates.\n     *\n     * @param  object  $factory\n     * @return void\n     */\n    public static function useFactory($factory)\n    {\n        static::$factory = $factory;\n\n        static::$dateClass = null;\n        static::$callable = null;\n    }\n\n    /**\n     * Handle dynamic calls to generate dates.\n     *\n     * @param  string  $method\n     * @param  array  $parameters\n     * @return mixed\n     *\n     * @throws \\RuntimeException\n     */\n    public function __call($method, $parameters)\n    {\n        $defaultClassName = static::DEFAULT_CLASS_NAME;\n\n        // Using callable to generate dates...\n        if (static::$callable) {\n            return call_user_func(static::$callable, $defaultClassName::$method(...$parameters));\n        }\n\n        // Using Carbon factory to generate dates...\n        if (static::$factory) {\n            return static::$factory->$method(...$parameters);\n        }\n\n        $dateClass = static::$dateClass ?: $defaultClassName;\n\n        // Check if date can be created using public class method...\n        if (method_exists($dateClass, $method) ||\n            method_exists($dateClass, 'hasMacro') && $dateClass::hasMacro($method)) {\n            return $dateClass::$method(...$parameters);\n        }\n\n        // If that fails, create the date with the default class...\n        $date = $defaultClassName::$method(...$parameters);\n\n        // If the configured class has an \"instance\" method, we'll try to pass our date into there...\n        if (method_exists($dateClass, 'instance')) {\n            return $dateClass::instance($date);\n        }\n\n        // Otherwise, assume the configured class has a DateTime compatible constructor...\n        return new $dateClass($date->format('Y-m-d H:i:s.u'), $date->getTimezone());\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Env.php",
    "content": "<?php\n\nnamespace Illuminate\\Support;\n\nuse Dotenv\\Repository\\Adapter\\PutenvAdapter;\nuse Dotenv\\Repository\\RepositoryBuilder;\nuse PhpOption\\Option;\n\nclass Env\n{\n    /**\n     * Indicates if the putenv adapter is enabled.\n     *\n     * @var bool\n     */\n    protected static $putenv = true;\n\n    /**\n     * The environment repository instance.\n     *\n     * @var \\Dotenv\\Repository\\RepositoryInterface|null\n     */\n    protected static $repository;\n\n    /**\n     * Enable the putenv adapter.\n     *\n     * @return void\n     */\n    public static function enablePutenv()\n    {\n        static::$putenv = true;\n        static::$repository = null;\n    }\n\n    /**\n     * Disable the putenv adapter.\n     *\n     * @return void\n     */\n    public static function disablePutenv()\n    {\n        static::$putenv = false;\n        static::$repository = null;\n    }\n\n    /**\n     * Get the environment repository instance.\n     *\n     * @return \\Dotenv\\Repository\\RepositoryInterface\n     */\n    public static function getRepository()\n    {\n        if (static::$repository === null) {\n            $builder = RepositoryBuilder::createWithDefaultAdapters();\n\n            if (static::$putenv) {\n                $builder = $builder->addAdapter(PutenvAdapter::class);\n            }\n\n            static::$repository = $builder->immutable()->make();\n        }\n\n        return static::$repository;\n    }\n\n    /**\n     * Gets the value of an environment variable.\n     *\n     * @param  string  $key\n     * @param  mixed  $default\n     * @return mixed\n     */\n    public static function get($key, $default = null)\n    {\n        return Option::fromValue(static::getRepository()->get($key))\n            ->map(function ($value) {\n                switch (strtolower($value)) {\n                    case 'true':\n                    case '(true)':\n                        return true;\n                    case 'false':\n                    case '(false)':\n                        return false;\n                    case 'empty':\n                    case '(empty)':\n                        return '';\n                    case 'null':\n                    case '(null)':\n                        return;\n                }\n\n                if (preg_match('/\\A([\\'\"])(.*)\\1\\z/', $value, $matches)) {\n                    return $matches[2];\n                }\n\n                return $value;\n            })\n            ->getOrCall(function () use ($default) {\n                return value($default);\n            });\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Facades/App.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Facades;\n\n/**\n * @method static \\Illuminate\\Contracts\\Foundation\\Application loadEnvironmentFrom(string $file)\n * @method static \\Illuminate\\Support\\ServiceProvider register(\\Illuminate\\Support\\ServiceProvider|string $provider, bool $force = false)\n * @method static \\Illuminate\\Support\\ServiceProvider resolveProvider(string $provider)\n * @method static array getProviders(\\Illuminate\\Support\\ServiceProvider|string $provider)\n * @method static mixed make($abstract, array $parameters = [])\n * @method static mixed makeWith($abstract, array $parameters = [])\n * @method static bool configurationIsCached()\n * @method static bool hasBeenBootstrapped()\n * @method static bool isDownForMaintenance()\n * @method static bool isLocal()\n * @method static bool isProduction()\n * @method static bool routesAreCached()\n * @method static bool runningInConsole()\n * @method static bool runningUnitTests()\n * @method static bool shouldSkipMiddleware()\n * @method static string basePath(string $path = '')\n * @method static string bootstrapPath(string $path = '')\n * @method static string configPath(string $path = '')\n * @method static string databasePath(string $path = '')\n * @method static string detectEnvironment(callable $callback)\n * @method static string environmentFile()\n * @method static string environmentFilePath()\n * @method static string environmentPath()\n * @method static string getCachedConfigPath()\n * @method static string getCachedPackagesPath()\n * @method static string getCachedRoutesPath()\n * @method static string getCachedServicesPath()\n * @method static string getLocale()\n * @method static string currentLocale()\n * @method static string getNamespace()\n * @method static string resourcePath(string $path = '')\n * @method static string storagePath(string $path = '')\n * @method static string version()\n * @method static string|bool environment(string|array ...$environments)\n * @method static never abort(int $code, string $message = '', array $headers = [])\n * @method static void boot()\n * @method static void booted(callable $callback)\n * @method static void booting(callable $callback)\n * @method static void bootstrapWith(array $bootstrappers)\n * @method static void loadDeferredProviders()\n * @method static void registerConfiguredProviders()\n * @method static void registerDeferredProvider(string $provider, string $service = null)\n * @method static void setLocale(string $locale)\n * @method static void terminate()\n *\n * @see \\Illuminate\\Contracts\\Foundation\\Application\n */\nclass App extends Facade\n{\n    /**\n     * Get the registered name of the component.\n     *\n     * @return string\n     */\n    protected static function getFacadeAccessor()\n    {\n        return 'app';\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Facades/Artisan.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Facades;\n\nuse Illuminate\\Contracts\\Console\\Kernel as ConsoleKernelContract;\n\n/**\n * @method static \\Illuminate\\Foundation\\Bus\\PendingDispatch queue(string $command, array $parameters = [])\n * @method static \\Illuminate\\Foundation\\Console\\ClosureCommand command(string $command, callable $callback)\n * @method static array all()\n * @method static int call(string $command, array $parameters = [], \\Symfony\\Component\\Console\\Output\\OutputInterface|null $outputBuffer = null)\n * @method static int handle(\\Symfony\\Component\\Console\\Input\\InputInterface $input, \\Symfony\\Component\\Console\\Output\\OutputInterface|null $output = null)\n * @method static string output()\n * @method static void terminate(\\Symfony\\Component\\Console\\Input\\InputInterface $input, int $status)\n *\n * @see \\Illuminate\\Contracts\\Console\\Kernel\n */\nclass Artisan extends Facade\n{\n    /**\n     * Get the registered name of the component.\n     *\n     * @return string\n     */\n    protected static function getFacadeAccessor()\n    {\n        return ConsoleKernelContract::class;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Facades/Auth.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Facades;\n\nuse Laravel\\Ui\\UiServiceProvider;\nuse RuntimeException;\n\n/**\n * @method static \\Illuminate\\Auth\\AuthManager extend(string $driver, \\Closure $callback)\n * @method static \\Illuminate\\Auth\\AuthManager provider(string $name, \\Closure $callback)\n * @method static \\Illuminate\\Contracts\\Auth\\Authenticatable loginUsingId(mixed $id, bool $remember = false)\n * @method static \\Illuminate\\Contracts\\Auth\\Authenticatable|null user()\n * @method static \\Illuminate\\Contracts\\Auth\\Guard|\\Illuminate\\Contracts\\Auth\\StatefulGuard guard(string|null $name = null)\n * @method static \\Illuminate\\Contracts\\Auth\\UserProvider|null createUserProvider(string $provider = null)\n * @method static \\Symfony\\Component\\HttpFoundation\\Response|null onceBasic(string $field = 'email',array $extraConditions = [])\n * @method static bool attempt(array $credentials = [], bool $remember = false)\n * @method static bool hasUser()\n * @method static bool check()\n * @method static bool guest()\n * @method static bool once(array $credentials = [])\n * @method static bool onceUsingId(mixed $id)\n * @method static bool validate(array $credentials = [])\n * @method static bool viaRemember()\n * @method static bool|null logoutOtherDevices(string $password, string $attribute = 'password')\n * @method static int|string|null id()\n * @method static void login(\\Illuminate\\Contracts\\Auth\\Authenticatable $user, bool $remember = false)\n * @method static void logout()\n * @method static void logoutCurrentDevice()\n * @method static void setUser(\\Illuminate\\Contracts\\Auth\\Authenticatable $user)\n * @method static void shouldUse(string $name);\n *\n * @see \\Illuminate\\Auth\\AuthManager\n * @see \\Illuminate\\Contracts\\Auth\\Factory\n * @see \\Illuminate\\Contracts\\Auth\\Guard\n * @see \\Illuminate\\Contracts\\Auth\\StatefulGuard\n */\nclass Auth extends Facade\n{\n    /**\n     * Get the registered name of the component.\n     *\n     * @return string\n     */\n    protected static function getFacadeAccessor()\n    {\n        return 'auth';\n    }\n\n    /**\n     * Register the typical authentication routes for an application.\n     *\n     * @param  array  $options\n     * @return void\n     *\n     * @throws \\RuntimeException\n     */\n    public static function routes(array $options = [])\n    {\n        if (! static::$app->providerIsLoaded(UiServiceProvider::class)) {\n            throw new RuntimeException('In order to use the Auth::routes() method, please install the laravel/ui package.');\n        }\n\n        static::$app->make('router')->auth($options);\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Facades/Blade.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Facades;\n\n/**\n * @method static array getClassComponentAliases()\n * @method static array getCustomDirectives()\n * @method static array getExtensions()\n * @method static bool check(string $name, array ...$parameters)\n * @method static string compileString(string $value)\n * @method static string render(string $string, array $data = [], bool $deleteCachedView = false)\n * @method static string renderComponent(\\Illuminate\\View\\Component $component)\n * @method static string getPath()\n * @method static string stripParentheses(string $expression)\n * @method static void aliasComponent(string $path, string|null $alias = null)\n * @method static void aliasInclude(string $path, string|null $alias = null)\n * @method static void compile(string|null $path = null)\n * @method static void component(string $class, string|null $alias = null, string $prefix = '')\n * @method static void components(array $components, string $prefix = '')\n * @method static void componentNamespace(string $namespace, string $prefix)\n * @method static void directive(string $name, callable $handler)\n * @method static void extend(callable $compiler)\n * @method static void if(string $name, callable $callback)\n * @method static void include(string $path, string|null $alias = null)\n * @method static void precompiler(callable $precompiler)\n * @method static void setEchoFormat(string $format)\n * @method static void setPath(string $path)\n * @method static void withDoubleEncoding()\n * @method static void withoutComponentTags()\n * @method static void withoutDoubleEncoding()\n * @method static void stringable(string|callable $class, callable|null $handler = null)\n *\n * @see \\Illuminate\\View\\Compilers\\BladeCompiler\n */\nclass Blade extends Facade\n{\n    /**\n     * Get the registered name of the component.\n     *\n     * @return string\n     */\n    protected static function getFacadeAccessor()\n    {\n        return 'blade.compiler';\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Facades/Broadcast.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Facades;\n\nuse Illuminate\\Contracts\\Broadcasting\\Factory as BroadcastingFactoryContract;\n\n/**\n * @method static \\Illuminate\\Broadcasting\\Broadcasters\\Broadcaster channel(string $channel, callable|string  $callback, array $options = [])\n * @method static mixed auth(\\Illuminate\\Http\\Request $request)\n * @method static \\Illuminate\\Contracts\\Broadcasting\\Broadcaster connection($name = null);\n * @method static void routes(array $attributes = null)\n * @method static \\Illuminate\\Broadcasting\\BroadcastManager socket($request = null)\n *\n * @see \\Illuminate\\Contracts\\Broadcasting\\Factory\n */\nclass Broadcast extends Facade\n{\n    /**\n     * Get the registered name of the component.\n     *\n     * @return string\n     */\n    protected static function getFacadeAccessor()\n    {\n        return BroadcastingFactoryContract::class;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Facades/Bus.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Facades;\n\nuse Illuminate\\Contracts\\Bus\\Dispatcher as BusDispatcherContract;\nuse Illuminate\\Foundation\\Bus\\PendingChain;\nuse Illuminate\\Support\\Testing\\Fakes\\BusFake;\n\n/**\n * @method static \\Illuminate\\Bus\\Batch|null findBatch(string $batchId)\n * @method static \\Illuminate\\Bus\\PendingBatch batch(array|mixed $jobs)\n * @method static \\Illuminate\\Contracts\\Bus\\Dispatcher map(array $map)\n * @method static \\Illuminate\\Contracts\\Bus\\Dispatcher pipeThrough(array $pipes)\n * @method static \\Illuminate\\Foundation\\Bus\\PendingChain chain(array $jobs)\n * @method static bool hasCommandHandler($command)\n * @method static bool|mixed getCommandHandler($command)\n * @method static mixed dispatch($command)\n * @method static mixed dispatchNow($command, $handler = null)\n * @method static mixed dispatchSync($command, $handler = null)\n * @method static void assertDispatched(string|\\Closure $command, callable|int $callback = null)\n * @method static void assertDispatchedTimes(string $command, int $times = 1)\n * @method static void assertNotDispatched(string|\\Closure $command, callable|int $callback = null)\n * @method static void assertDispatchedAfterResponse(string|\\Closure $command, callable|int $callback = null)\n * @method static void assertDispatchedAfterResponseTimes(string $command, int $times = 1)\n * @method static void assertNotDispatchedAfterResponse(string|\\Closure $command, callable $callback = null)\n * @method static void assertBatched(callable $callback)\n * @method static void assertBatchCount(int $count)\n * @method static void assertChained(array $expectedChain)\n * @method static void assertDispatchedSync(string|\\Closure $command, callable $callback = null)\n * @method static void assertDispatchedSyncTimes(string $command, int $times = 1)\n * @method static void assertNotDispatchedSync(string|\\Closure $command, callable $callback = null)\n * @method static void assertDispatchedWithoutChain(string|\\Closure $command, callable $callback = null)\n *\n * @see \\Illuminate\\Contracts\\Bus\\Dispatcher\n */\nclass Bus extends Facade\n{\n    /**\n     * Replace the bound instance with a fake.\n     *\n     * @param  array|string  $jobsToFake\n     * @return \\Illuminate\\Support\\Testing\\Fakes\\BusFake\n     */\n    public static function fake($jobsToFake = [])\n    {\n        static::swap($fake = new BusFake(static::getFacadeRoot(), $jobsToFake));\n\n        return $fake;\n    }\n\n    /**\n     * Dispatch the given chain of jobs.\n     *\n     * @param  array|mixed  $jobs\n     * @return \\Illuminate\\Foundation\\Bus\\PendingDispatch\n     */\n    public static function dispatchChain($jobs)\n    {\n        $jobs = is_array($jobs) ? $jobs : func_get_args();\n\n        return (new PendingChain(array_shift($jobs), $jobs))\n                    ->dispatch();\n    }\n\n    /**\n     * Get the registered name of the component.\n     *\n     * @return string\n     */\n    protected static function getFacadeAccessor()\n    {\n        return BusDispatcherContract::class;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Facades/Cache.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Facades;\n\n/**\n * @method static \\Illuminate\\Cache\\TaggedCache tags(array|mixed $names)\n * @method static \\Illuminate\\Contracts\\Cache\\Lock lock(string $name, int $seconds = 0, mixed $owner = null)\n * @method static \\Illuminate\\Contracts\\Cache\\Lock restoreLock(string $name, string $owner)\n * @method static \\Illuminate\\Contracts\\Cache\\Repository  store(string|null $name = null)\n * @method static \\Illuminate\\Contracts\\Cache\\Store getStore()\n * @method static bool add(string $key, $value, \\DateTimeInterface|\\DateInterval|int $ttl = null)\n * @method static bool flush()\n * @method static bool forever(string $key, $value)\n * @method static bool forget(string $key)\n * @method static bool has(string $key)\n * @method static bool missing(string $key)\n * @method static bool put(string $key, $value, \\DateTimeInterface|\\DateInterval|int $ttl = null)\n * @method static int|bool decrement(string $key, $value = 1)\n * @method static int|bool increment(string $key, $value = 1)\n * @method static mixed get(string $key, mixed $default = null)\n * @method static mixed pull(string $key, mixed $default = null)\n * @method static mixed remember(string $key, \\DateTimeInterface|\\DateInterval|int $ttl, \\Closure $callback)\n * @method static mixed rememberForever(string $key, \\Closure $callback)\n * @method static mixed sear(string $key, \\Closure $callback)\n *\n * @see \\Illuminate\\Cache\\CacheManager\n * @see \\Illuminate\\Cache\\Repository\n */\nclass Cache extends Facade\n{\n    /**\n     * Get the registered name of the component.\n     *\n     * @return string\n     */\n    protected static function getFacadeAccessor()\n    {\n        return 'cache';\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Facades/Config.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Facades;\n\n/**\n * @method static array all()\n * @method static bool has($key)\n * @method static mixed get($key, $default = null)\n * @method static void prepend($key, $value)\n * @method static void push($key, $value)\n * @method static void set($key, $value = null)\n *\n * @see \\Illuminate\\Config\\Repository\n */\nclass Config extends Facade\n{\n    /**\n     * Get the registered name of the component.\n     *\n     * @return string\n     */\n    protected static function getFacadeAccessor()\n    {\n        return 'config';\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Facades/Cookie.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Facades;\n\n/**\n * @method static array getQueuedCookies()\n * @method static unqueue($name)\n * @method static void queue(...$parameters)\n *\n * @see \\Illuminate\\Cookie\\CookieJar\n */\nclass Cookie extends Facade\n{\n    /**\n     * Determine if a cookie exists on the request.\n     *\n     * @param  string  $key\n     * @return bool\n     */\n    public static function has($key)\n    {\n        return ! is_null(static::$app['request']->cookie($key, null));\n    }\n\n    /**\n     * Retrieve a cookie from the request.\n     *\n     * @param  string|null  $key\n     * @param  mixed  $default\n     * @return string|array|null\n     */\n    public static function get($key = null, $default = null)\n    {\n        return static::$app['request']->cookie($key, $default);\n    }\n\n    /**\n     * Get the registered name of the component.\n     *\n     * @return string\n     */\n    protected static function getFacadeAccessor()\n    {\n        return 'cookie';\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Facades/Crypt.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Facades;\n\n/**\n * @method static bool supported(string $key, string $cipher)\n * @method static mixed decrypt(string $payload, bool $unserialize = true)\n * @method static string decryptString(string $payload)\n * @method static string encrypt(mixed $value, bool $serialize = true)\n * @method static string encryptString(string $value)\n * @method static string generateKey(string $cipher)\n * @method static string getKey()\n *\n * @see \\Illuminate\\Encryption\\Encrypter\n */\nclass Crypt extends Facade\n{\n    /**\n     * Get the registered name of the component.\n     *\n     * @return string\n     */\n    protected static function getFacadeAccessor()\n    {\n        return 'encrypter';\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Facades/DB.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Facades;\n\n/**\n * @method static \\Doctrine\\DBAL\\Driver\\PDOConnection getPdo()\n * @method static \\Illuminate\\Database\\ConnectionInterface connection(string $name = null)\n * @method static \\Illuminate\\Database\\Query\\Builder table(string $table, string $as = null)\n * @method static \\Illuminate\\Database\\Query\\Expression raw($value)\n * @method static array getQueryLog()\n * @method static array prepareBindings(array $bindings)\n * @method static array pretend(\\Closure $callback)\n * @method static array select(string $query, array $bindings = [], bool $useReadPdo = true)\n * @method static bool insert(string $query, array $bindings = [])\n * @method static bool logging()\n * @method static bool statement(string $query, array $bindings = [])\n * @method static bool unprepared(string $query)\n * @method static int affectingStatement(string $query, array $bindings = [])\n * @method static int delete(string $query, array $bindings = [])\n * @method static int transactionLevel()\n * @method static int update(string $query, array $bindings = [])\n * @method static mixed selectOne(string $query, array $bindings = [], bool $useReadPdo = true)\n * @method static mixed transaction(\\Closure $callback, int $attempts = 1)\n * @method static string getDefaultConnection()\n * @method static void afterCommit(\\Closure $callback)\n * @method static void beginTransaction()\n * @method static void commit()\n * @method static void enableQueryLog()\n * @method static void disableQueryLog()\n * @method static void flushQueryLog()\n * @method static \\Illuminate\\Database\\Connection beforeExecuting(\\Closure $callback)\n * @method static void listen(\\Closure $callback)\n * @method static void rollBack(int $toLevel = null)\n * @method static void setDefaultConnection(string $name)\n *\n * @see \\Illuminate\\Database\\DatabaseManager\n * @see \\Illuminate\\Database\\Connection\n */\nclass DB extends Facade\n{\n    /**\n     * Get the registered name of the component.\n     *\n     * @return string\n     */\n    protected static function getFacadeAccessor()\n    {\n        return 'db';\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Facades/Date.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Facades;\n\nuse Illuminate\\Support\\DateFactory;\n\n/**\n * @see https://carbon.nesbot.com/docs/\n * @see https://github.com/briannesbitt/Carbon/blob/master/src/Carbon/Factory.php\n *\n * @method static \\Illuminate\\Support\\Carbon create($year = 0, $month = 1, $day = 1, $hour = 0, $minute = 0, $second = 0, $tz = null)\n * @method static \\Illuminate\\Support\\Carbon createFromDate($year = null, $month = null, $day = null, $tz = null)\n * @method static \\Illuminate\\Support\\Carbon createFromTime($hour = 0, $minute = 0, $second = 0, $tz = null)\n * @method static \\Illuminate\\Support\\Carbon createFromTimeString($time, $tz = null)\n * @method static \\Illuminate\\Support\\Carbon createFromTimestamp($timestamp, $tz = null)\n * @method static \\Illuminate\\Support\\Carbon createFromTimestampMs($timestamp, $tz = null)\n * @method static \\Illuminate\\Support\\Carbon createFromTimestampUTC($timestamp)\n * @method static \\Illuminate\\Support\\Carbon createMidnightDate($year = null, $month = null, $day = null, $tz = null)\n * @method static \\Illuminate\\Support\\Carbon disableHumanDiffOption($humanDiffOption)\n * @method static \\Illuminate\\Support\\Carbon enableHumanDiffOption($humanDiffOption)\n * @method static \\Illuminate\\Support\\Carbon fromSerialized($value)\n * @method static \\Illuminate\\Support\\Carbon getLastErrors()\n * @method static \\Illuminate\\Support\\Carbon getTestNow()\n * @method static \\Illuminate\\Support\\Carbon instance($date)\n * @method static \\Illuminate\\Support\\Carbon isMutable()\n * @method static \\Illuminate\\Support\\Carbon maxValue()\n * @method static \\Illuminate\\Support\\Carbon minValue()\n * @method static \\Illuminate\\Support\\Carbon now($tz = null)\n * @method static \\Illuminate\\Support\\Carbon parse($time = null, $tz = null)\n * @method static \\Illuminate\\Support\\Carbon setHumanDiffOptions($humanDiffOptions)\n * @method static void setTestNow($testNow = null)\n * @method static \\Illuminate\\Support\\Carbon setUtf8($utf8)\n * @method static \\Illuminate\\Support\\Carbon today($tz = null)\n * @method static \\Illuminate\\Support\\Carbon tomorrow($tz = null)\n * @method static \\Illuminate\\Support\\Carbon useStrictMode($strictModeEnabled = true)\n * @method static \\Illuminate\\Support\\Carbon yesterday($tz = null)\n * @method static \\Illuminate\\Support\\Carbon|false createFromFormat($format, $time, $tz = null)\n * @method static \\Illuminate\\Support\\Carbon|false createSafe($year = null, $month = null, $day = null, $hour = null, $minute = null, $second = null, $tz = null)\n * @method static \\Illuminate\\Support\\Carbon|null make($var)\n * @method static \\Symfony\\Component\\Translation\\TranslatorInterface getTranslator()\n * @method static array getAvailableLocales()\n * @method static array getDays()\n * @method static array getIsoUnits()\n * @method static array getWeekendDays()\n * @method static bool hasFormat($date, $format)\n * @method static bool hasMacro($name)\n * @method static bool hasRelativeKeywords($time)\n * @method static bool hasTestNow()\n * @method static bool isImmutable()\n * @method static bool isModifiableUnit($unit)\n * @method static bool isStrictModeEnabled()\n * @method static bool localeHasDiffOneDayWords($locale)\n * @method static bool localeHasDiffSyntax($locale)\n * @method static bool localeHasDiffTwoDayWords($locale)\n * @method static bool localeHasPeriodSyntax($locale)\n * @method static bool localeHasShortUnits($locale)\n * @method static bool setLocale($locale)\n * @method static bool shouldOverflowMonths()\n * @method static bool shouldOverflowYears()\n * @method static int getHumanDiffOptions()\n * @method static int getMidDayAt()\n * @method static int getWeekEndsAt()\n * @method static int getWeekStartsAt()\n * @method static mixed executeWithLocale($locale, $func)\n * @method static mixed use(mixed $handler)\n * @method static string getLocale()\n * @method static string pluralUnit(string $unit)\n * @method static string singularUnit(string $unit)\n * @method static void macro($name, $macro)\n * @method static void mixin($mixin)\n * @method static void resetMonthsOverflow()\n * @method static void resetToStringFormat()\n * @method static void resetYearsOverflow()\n * @method static void serializeUsing($callback)\n * @method static void setMidDayAt($hour)\n * @method static void setToStringFormat($format)\n * @method static void setTranslator(\\Symfony\\Component\\Translation\\TranslatorInterface $translator)\n * @method static void setWeekEndsAt($day)\n * @method static void setWeekStartsAt($day)\n * @method static void setWeekendDays($days)\n * @method static void useCallable(callable $callable)\n * @method static void useClass(string $class)\n * @method static void useDefault()\n * @method static void useFactory(object $factory)\n * @method static void useMonthsOverflow($monthsOverflow = true)\n * @method static void useYearsOverflow($yearsOverflow = true)\n */\nclass Date extends Facade\n{\n    const DEFAULT_FACADE = DateFactory::class;\n\n    /**\n     * Get the registered name of the component.\n     *\n     * @return string\n     *\n     * @throws \\RuntimeException\n     */\n    protected static function getFacadeAccessor()\n    {\n        return 'date';\n    }\n\n    /**\n     * Resolve the facade root instance from the container.\n     *\n     * @param  string  $name\n     * @return mixed\n     */\n    protected static function resolveFacadeInstance($name)\n    {\n        if (! isset(static::$resolvedInstance[$name]) && ! isset(static::$app, static::$app[$name])) {\n            $class = static::DEFAULT_FACADE;\n\n            static::swap(new $class);\n        }\n\n        return parent::resolveFacadeInstance($name);\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Facades/Event.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Facades;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Support\\Testing\\Fakes\\EventFake;\n\n/**\n * @method static \\Closure createClassListener(string $listener, bool $wildcard = false)\n * @method static \\Closure makeListener(\\Closure|string $listener, bool $wildcard = false)\n * @method static \\Illuminate\\Events\\Dispatcher setQueueResolver(callable $resolver)\n * @method static array getListeners(string $eventName)\n * @method static array|null dispatch(string|object $event, mixed $payload = [], bool $halt = false)\n * @method static array|null until(string|object $event, mixed $payload = [])\n * @method static bool hasListeners(string $eventName)\n * @method static void assertDispatched(string|\\Closure $event, callable|int $callback = null)\n * @method static void assertDispatchedTimes(string $event, int $times = 1)\n * @method static void assertNotDispatched(string|\\Closure $event, callable|int $callback = null)\n * @method static void assertNothingDispatched()\n * @method static void assertListening(string $expectedEvent, string $expectedListener)\n * @method static void flush(string $event)\n * @method static void forget(string $event)\n * @method static void forgetPushed()\n * @method static void listen(\\Closure|string|array $events, \\Closure|string|array $listener = null)\n * @method static void push(string $event, array $payload = [])\n * @method static void subscribe(object|string $subscriber)\n *\n * @see \\Illuminate\\Events\\Dispatcher\n */\nclass Event extends Facade\n{\n    /**\n     * Replace the bound instance with a fake.\n     *\n     * @param  array|string  $eventsToFake\n     * @return \\Illuminate\\Support\\Testing\\Fakes\\EventFake\n     */\n    public static function fake($eventsToFake = [])\n    {\n        static::swap($fake = new EventFake(static::getFacadeRoot(), $eventsToFake));\n\n        Model::setEventDispatcher($fake);\n        Cache::refreshEventDispatcher();\n\n        return $fake;\n    }\n\n    /**\n     * Replace the bound instance with a fake that fakes all events except the given events.\n     *\n     * @param  string[]|string  $eventsToAllow\n     * @return \\Illuminate\\Support\\Testing\\Fakes\\EventFake\n     */\n    public static function fakeExcept($eventsToAllow)\n    {\n        return static::fake([\n            function ($eventName) use ($eventsToAllow) {\n                return ! in_array($eventName, (array) $eventsToAllow);\n            },\n        ]);\n    }\n\n    /**\n     * Replace the bound instance with a fake during the given callable's execution.\n     *\n     * @param  callable  $callable\n     * @param  array  $eventsToFake\n     * @return mixed\n     */\n    public static function fakeFor(callable $callable, array $eventsToFake = [])\n    {\n        $originalDispatcher = static::getFacadeRoot();\n\n        static::fake($eventsToFake);\n\n        return tap($callable(), function () use ($originalDispatcher) {\n            static::swap($originalDispatcher);\n\n            Model::setEventDispatcher($originalDispatcher);\n            Cache::refreshEventDispatcher();\n        });\n    }\n\n    /**\n     * Replace the bound instance with a fake during the given callable's execution.\n     *\n     * @param  callable  $callable\n     * @param  array  $eventsToAllow\n     * @return mixed\n     */\n    public static function fakeExceptFor(callable $callable, array $eventsToAllow = [])\n    {\n        $originalDispatcher = static::getFacadeRoot();\n\n        static::fakeExcept($eventsToAllow);\n\n        return tap($callable(), function () use ($originalDispatcher) {\n            static::swap($originalDispatcher);\n\n            Model::setEventDispatcher($originalDispatcher);\n            Cache::refreshEventDispatcher();\n        });\n    }\n\n    /**\n     * Get the registered name of the component.\n     *\n     * @return string\n     */\n    protected static function getFacadeAccessor()\n    {\n        return 'events';\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Facades/Facade.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Facades;\n\nuse Closure;\nuse Mockery;\nuse Mockery\\LegacyMockInterface;\nuse RuntimeException;\n\nabstract class Facade\n{\n    /**\n     * The application instance being facaded.\n     *\n     * @var \\Illuminate\\Contracts\\Foundation\\Application\n     */\n    protected static $app;\n\n    /**\n     * The resolved object instances.\n     *\n     * @var array\n     */\n    protected static $resolvedInstance;\n\n    /**\n     * Run a Closure when the facade has been resolved.\n     *\n     * @param  \\Closure  $callback\n     * @return void\n     */\n    public static function resolved(Closure $callback)\n    {\n        $accessor = static::getFacadeAccessor();\n\n        if (static::$app->resolved($accessor) === true) {\n            $callback(static::getFacadeRoot());\n        }\n\n        static::$app->afterResolving($accessor, function ($service) use ($callback) {\n            $callback($service);\n        });\n    }\n\n    /**\n     * Convert the facade into a Mockery spy.\n     *\n     * @return \\Mockery\\MockInterface\n     */\n    public static function spy()\n    {\n        if (! static::isMock()) {\n            $class = static::getMockableClass();\n\n            return tap($class ? Mockery::spy($class) : Mockery::spy(), function ($spy) {\n                static::swap($spy);\n            });\n        }\n    }\n\n    /**\n     * Initiate a partial mock on the facade.\n     *\n     * @return \\Mockery\\MockInterface\n     */\n    public static function partialMock()\n    {\n        $name = static::getFacadeAccessor();\n\n        $mock = static::isMock()\n            ? static::$resolvedInstance[$name]\n            : static::createFreshMockInstance();\n\n        return $mock->makePartial();\n    }\n\n    /**\n     * Initiate a mock expectation on the facade.\n     *\n     * @return \\Mockery\\Expectation\n     */\n    public static function shouldReceive()\n    {\n        $name = static::getFacadeAccessor();\n\n        $mock = static::isMock()\n                    ? static::$resolvedInstance[$name]\n                    : static::createFreshMockInstance();\n\n        return $mock->shouldReceive(...func_get_args());\n    }\n\n    /**\n     * Create a fresh mock instance for the given class.\n     *\n     * @return \\Mockery\\MockInterface\n     */\n    protected static function createFreshMockInstance()\n    {\n        return tap(static::createMock(), function ($mock) {\n            static::swap($mock);\n\n            $mock->shouldAllowMockingProtectedMethods();\n        });\n    }\n\n    /**\n     * Create a fresh mock instance for the given class.\n     *\n     * @return \\Mockery\\MockInterface\n     */\n    protected static function createMock()\n    {\n        $class = static::getMockableClass();\n\n        return $class ? Mockery::mock($class) : Mockery::mock();\n    }\n\n    /**\n     * Determines whether a mock is set as the instance of the facade.\n     *\n     * @return bool\n     */\n    protected static function isMock()\n    {\n        $name = static::getFacadeAccessor();\n\n        return isset(static::$resolvedInstance[$name]) &&\n               static::$resolvedInstance[$name] instanceof LegacyMockInterface;\n    }\n\n    /**\n     * Get the mockable class for the bound instance.\n     *\n     * @return string|null\n     */\n    protected static function getMockableClass()\n    {\n        if ($root = static::getFacadeRoot()) {\n            return get_class($root);\n        }\n    }\n\n    /**\n     * Hotswap the underlying instance behind the facade.\n     *\n     * @param  mixed  $instance\n     * @return void\n     */\n    public static function swap($instance)\n    {\n        static::$resolvedInstance[static::getFacadeAccessor()] = $instance;\n\n        if (isset(static::$app)) {\n            static::$app->instance(static::getFacadeAccessor(), $instance);\n        }\n    }\n\n    /**\n     * Get the root object behind the facade.\n     *\n     * @return mixed\n     */\n    public static function getFacadeRoot()\n    {\n        return static::resolveFacadeInstance(static::getFacadeAccessor());\n    }\n\n    /**\n     * Get the registered name of the component.\n     *\n     * @return string\n     *\n     * @throws \\RuntimeException\n     */\n    protected static function getFacadeAccessor()\n    {\n        throw new RuntimeException('Facade does not implement getFacadeAccessor method.');\n    }\n\n    /**\n     * Resolve the facade root instance from the container.\n     *\n     * @param  object|string  $name\n     * @return mixed\n     */\n    protected static function resolveFacadeInstance($name)\n    {\n        if (is_object($name)) {\n            return $name;\n        }\n\n        if (isset(static::$resolvedInstance[$name])) {\n            return static::$resolvedInstance[$name];\n        }\n\n        if (static::$app) {\n            return static::$resolvedInstance[$name] = static::$app[$name];\n        }\n    }\n\n    /**\n     * Clear a resolved facade instance.\n     *\n     * @param  string  $name\n     * @return void\n     */\n    public static function clearResolvedInstance($name)\n    {\n        unset(static::$resolvedInstance[$name]);\n    }\n\n    /**\n     * Clear all of the resolved instances.\n     *\n     * @return void\n     */\n    public static function clearResolvedInstances()\n    {\n        static::$resolvedInstance = [];\n    }\n\n    /**\n     * Get the application instance behind the facade.\n     *\n     * @return \\Illuminate\\Contracts\\Foundation\\Application\n     */\n    public static function getFacadeApplication()\n    {\n        return static::$app;\n    }\n\n    /**\n     * Set the application instance.\n     *\n     * @param  \\Illuminate\\Contracts\\Foundation\\Application  $app\n     * @return void\n     */\n    public static function setFacadeApplication($app)\n    {\n        static::$app = $app;\n    }\n\n    /**\n     * Handle dynamic, static calls to the object.\n     *\n     * @param  string  $method\n     * @param  array  $args\n     * @return mixed\n     *\n     * @throws \\RuntimeException\n     */\n    public static function __callStatic($method, $args)\n    {\n        $instance = static::getFacadeRoot();\n\n        if (! $instance) {\n            throw new RuntimeException('A facade root has not been set.');\n        }\n\n        return $instance->$method(...$args);\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Facades/File.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Facades;\n\n/**\n * @method static \\Symfony\\Component\\Finder\\SplFileInfo[] allFiles(string $directory, bool $hidden = false)\n * @method static \\Symfony\\Component\\Finder\\SplFileInfo[] files(string $directory, bool $hidden = false)\n * @method static array directories(string $directory)\n * @method static array glob(string $pattern, int $flags = 0)\n * @method static bool cleanDirectory(string $directory)\n * @method static bool copy(string $path, string $target)\n * @method static bool copyDirectory(string $directory, string $destination, int|null $options = null)\n * @method static bool delete(string|array $paths)\n * @method static bool deleteDirectories(string $directory)\n * @method static bool deleteDirectory(string $directory, bool $preserve = false)\n * @method static bool exists(string $path)\n * @method static bool isDirectory(string $directory)\n * @method static bool isFile(string $file)\n * @method static bool isReadable(string $path)\n * @method static bool isWritable(string $path)\n * @method static bool makeDirectory(string $path, int $mode = 0755, bool $recursive = false, bool $force = false)\n * @method static bool missing(string $path)\n * @method static bool move(string $path, string $target)\n * @method static bool moveDirectory(string $from, string $to, bool $overwrite = false)\n * @method static int append(string $path, string $data)\n * @method static int lastModified(string $path)\n * @method static int prepend(string $path, string $data)\n * @method static int size(string $path)\n * @method static int|bool put(string $path, string $contents, bool $lock = false)\n * @method static mixed chmod(string $path, int|null $mode = null)\n * @method static mixed getRequire(string $path, array $data = [])\n * @method static mixed requireOnce(string $file, array $data = [])\n * @method static string basename(string $path)\n * @method static string dirname(string $path)\n * @method static string extension(string $path)\n * @method static string get(string $path, bool $lock = false)\n * @method static string hash(string $path)\n * @method static string name(string $path)\n * @method static string sharedGet(string $path)\n * @method static string type(string $path)\n * @method static string|false mimeType(string $path)\n * @method static string|null guessExtension(string $path)\n * @method static void ensureDirectoryExists(string $path, int $mode = 0755, bool $recursive = true)\n * @method static void link(string $target, string $link)\n * @method static \\Illuminate\\Support\\LazyCollection lines(string $path)\n * @method static void relativeLink(string $target, string $link)\n * @method static void replace(string $path, string $content)\n *\n * @see \\Illuminate\\Filesystem\\Filesystem\n */\nclass File extends Facade\n{\n    /**\n     * Get the registered name of the component.\n     *\n     * @return string\n     */\n    protected static function getFacadeAccessor()\n    {\n        return 'files';\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Facades/Gate.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Facades;\n\nuse Illuminate\\Contracts\\Auth\\Access\\Gate as GateContract;\n\n/**\n * @method static \\Illuminate\\Auth\\Access\\Gate guessPolicyNamesUsing(callable $callback)\n * @method static \\Illuminate\\Auth\\Access\\Response authorize(string $ability, array|mixed $arguments = [])\n * @method static \\Illuminate\\Auth\\Access\\Response inspect(string $ability, array|mixed $arguments = [])\n * @method static \\Illuminate\\Auth\\Access\\Response allowIf(\\Closure|bool $condition, string|null $message = null, mixed $code = null)\n * @method static \\Illuminate\\Auth\\Access\\Response denyIf(\\Closure|bool $condition, string|null $message = null, mixed $code = null)\n * @method static \\Illuminate\\Contracts\\Auth\\Access\\Gate after(callable $callback)\n * @method static \\Illuminate\\Contracts\\Auth\\Access\\Gate before(callable $callback)\n * @method static \\Illuminate\\Contracts\\Auth\\Access\\Gate define(string $ability, callable|string $callback)\n * @method static \\Illuminate\\Contracts\\Auth\\Access\\Gate forUser(\\Illuminate\\Contracts\\Auth\\Authenticatable|mixed $user)\n * @method static \\Illuminate\\Contracts\\Auth\\Access\\Gate policy(string $class, string $policy)\n * @method static array abilities()\n * @method static bool allows(string $ability, array|mixed $arguments = [])\n * @method static bool any(iterable|string $abilities, array|mixed $arguments = [])\n * @method static bool check(iterable|string $abilities, array|mixed $arguments = [])\n * @method static bool denies(string $ability, array|mixed $arguments = [])\n * @method static bool has(string $ability)\n * @method static mixed getPolicyFor(object|string $class)\n * @method static mixed raw(string $ability, array|mixed $arguments = [])\n *\n * @see \\Illuminate\\Contracts\\Auth\\Access\\Gate\n */\nclass Gate extends Facade\n{\n    /**\n     * Get the registered name of the component.\n     *\n     * @return string\n     */\n    protected static function getFacadeAccessor()\n    {\n        return GateContract::class;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Facades/Hash.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Facades;\n\n/**\n * @method static array info(string $hashedValue)\n * @method static bool check(string $value, string $hashedValue, array $options = [])\n * @method static bool needsRehash(string $hashedValue, array $options = [])\n * @method static string make(string $value, array $options = [])\n * @method static \\Illuminate\\Hashing\\HashManager extend($driver, \\Closure $callback)\n *\n * @see \\Illuminate\\Hashing\\HashManager\n */\nclass Hash extends Facade\n{\n    /**\n     * Get the registered name of the component.\n     *\n     * @return string\n     */\n    protected static function getFacadeAccessor()\n    {\n        return 'hash';\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Facades/Http.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Facades;\n\nuse Illuminate\\Http\\Client\\Factory;\n\n/**\n * @method static \\GuzzleHttp\\Promise\\PromiseInterface response($body = null, $status = 200, $headers = [])\n * @method static \\Illuminate\\Http\\Client\\Factory fake($callback = null)\n * @method static \\Illuminate\\Http\\Client\\PendingRequest accept(string $contentType)\n * @method static \\Illuminate\\Http\\Client\\PendingRequest acceptJson()\n * @method static \\Illuminate\\Http\\Client\\PendingRequest asForm()\n * @method static \\Illuminate\\Http\\Client\\PendingRequest asJson()\n * @method static \\Illuminate\\Http\\Client\\PendingRequest asMultipart()\n * @method static \\Illuminate\\Http\\Client\\PendingRequest async()\n * @method static \\Illuminate\\Http\\Client\\PendingRequest attach(string|array $name, string $contents = '', string|null $filename = null, array $headers = [])\n * @method static \\Illuminate\\Http\\Client\\PendingRequest baseUrl(string $url)\n * @method static \\Illuminate\\Http\\Client\\PendingRequest beforeSending(callable $callback)\n * @method static \\Illuminate\\Http\\Client\\PendingRequest bodyFormat(string $format)\n * @method static \\Illuminate\\Http\\Client\\PendingRequest contentType(string $contentType)\n * @method static \\Illuminate\\Http\\Client\\PendingRequest dd()\n * @method static \\Illuminate\\Http\\Client\\PendingRequest dump()\n * @method static \\Illuminate\\Http\\Client\\PendingRequest retry(int $times, int $sleep = 0, ?callable $when = null)\n * @method static \\Illuminate\\Http\\Client\\PendingRequest sink(string|resource $to)\n * @method static \\Illuminate\\Http\\Client\\PendingRequest stub(callable $callback)\n * @method static \\Illuminate\\Http\\Client\\PendingRequest timeout(int $seconds)\n * @method static \\Illuminate\\Http\\Client\\PendingRequest withBasicAuth(string $username, string $password)\n * @method static \\Illuminate\\Http\\Client\\PendingRequest withBody(resource|string $content, string $contentType)\n * @method static \\Illuminate\\Http\\Client\\PendingRequest withCookies(array $cookies, string $domain)\n * @method static \\Illuminate\\Http\\Client\\PendingRequest withDigestAuth(string $username, string $password)\n * @method static \\Illuminate\\Http\\Client\\PendingRequest withHeaders(array $headers)\n * @method static \\Illuminate\\Http\\Client\\PendingRequest withMiddleware(callable $middleware)\n * @method static \\Illuminate\\Http\\Client\\PendingRequest withOptions(array $options)\n * @method static \\Illuminate\\Http\\Client\\PendingRequest withToken(string $token, string $type = 'Bearer')\n * @method static \\Illuminate\\Http\\Client\\PendingRequest withUserAgent(string $userAgent)\n * @method static \\Illuminate\\Http\\Client\\PendingRequest withoutRedirecting()\n * @method static \\Illuminate\\Http\\Client\\PendingRequest withoutVerifying()\n * @method static array pool(callable $callback)\n * @method static \\Illuminate\\Http\\Client\\Response delete(string $url, array $data = [])\n * @method static \\Illuminate\\Http\\Client\\Response get(string $url, array|string|null $query = null)\n * @method static \\Illuminate\\Http\\Client\\Response head(string $url, array|string|null $query = null)\n * @method static \\Illuminate\\Http\\Client\\Response patch(string $url, array $data = [])\n * @method static \\Illuminate\\Http\\Client\\Response post(string $url, array $data = [])\n * @method static \\Illuminate\\Http\\Client\\Response put(string $url, array $data = [])\n * @method static \\Illuminate\\Http\\Client\\Response send(string $method, string $url, array $options = [])\n * @method static \\Illuminate\\Http\\Client\\ResponseSequence fakeSequence(string $urlPattern = '*')\n * @method static void assertSent(callable $callback)\n * @method static void assertSentInOrder(array $callbacks)\n * @method static void assertNotSent(callable $callback)\n * @method static void assertNothingSent()\n * @method static void assertSentCount(int $count)\n * @method static void assertSequencesAreEmpty()\n *\n * @see \\Illuminate\\Http\\Client\\Factory\n */\nclass Http extends Facade\n{\n    /**\n     * Get the registered name of the component.\n     *\n     * @return string\n     */\n    protected static function getFacadeAccessor()\n    {\n        return Factory::class;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Facades/Lang.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Facades;\n\n/**\n * @method static bool hasForLocale(string $key, string $locale = null)\n * @method static bool has(string $key, string $locale = null, bool $fallback = true)\n * @method static mixed get(string $key, array $replace = [], string $locale = null, bool $fallback = true)\n * @method static string choice(string $key, \\Countable|int|array $number, array $replace = [], string $locale = null)\n * @method static string getLocale()\n * @method static void setLocale(string $locale)\n *\n * @see \\Illuminate\\Translation\\Translator\n */\nclass Lang extends Facade\n{\n    /**\n     * Get the registered name of the component.\n     *\n     * @return string\n     */\n    protected static function getFacadeAccessor()\n    {\n        return 'translator';\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Facades/Log.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Facades;\n\n/**\n * @method static \\Psr\\Log\\LoggerInterface channel(string $channel = null)\n * @method static \\Psr\\Log\\LoggerInterface stack(array $channels, string $channel = null)\n * @method static \\Psr\\Log\\LoggerInterface build(array $config)\n * @method static \\Illuminate\\Log\\Logger withContext(array $context = [])\n * @method static \\Illuminate\\Log\\Logger withoutContext()\n * @method static void alert(string $message, array $context = [])\n * @method static void critical(string $message, array $context = [])\n * @method static void debug(string $message, array $context = [])\n * @method static void emergency(string $message, array $context = [])\n * @method static void error(string $message, array $context = [])\n * @method static void info(string $message, array $context = [])\n * @method static void log($level, string $message, array $context = [])\n * @method static void notice(string $message, array $context = [])\n * @method static void warning(string $message, array $context = [])\n * @method static void write(string $level, string $message, array $context = [])\n * @method static void listen(\\Closure $callback)\n *\n * @see \\Illuminate\\Log\\Logger\n */\nclass Log extends Facade\n{\n    /**\n     * Get the registered name of the component.\n     *\n     * @return string\n     */\n    protected static function getFacadeAccessor()\n    {\n        return 'log';\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Facades/Mail.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Facades;\n\nuse Illuminate\\Support\\Testing\\Fakes\\MailFake;\n\n/**\n * @method static \\Illuminate\\Mail\\Mailer mailer(string|null $name = null)\n * @method static void alwaysFrom(string $address, string|null $name = null)\n * @method static void alwaysReplyTo(string $address, string|null $name = null)\n * @method static void alwaysReturnPath(string $address)\n * @method static void alwaysTo(string $address, string|null $name = null)\n * @method static \\Illuminate\\Mail\\PendingMail bcc($users)\n * @method static \\Illuminate\\Mail\\PendingMail to($users)\n * @method static \\Illuminate\\Support\\Collection queued(string $mailable, \\Closure|string $callback = null)\n * @method static \\Illuminate\\Support\\Collection sent(string $mailable, \\Closure|string $callback = null)\n * @method static array failures()\n * @method static bool hasQueued(string $mailable)\n * @method static bool hasSent(string $mailable)\n * @method static mixed later(\\DateTimeInterface|\\DateInterval|int $delay, \\Illuminate\\Contracts\\Mail\\Mailable|string|array $view, string $queue = null)\n * @method static mixed laterOn(string $queue, \\DateTimeInterface|\\DateInterval|int $delay, \\Illuminate\\Contracts\\Mail\\Mailable|string|array $view)\n * @method static mixed queue(\\Illuminate\\Contracts\\Mail\\Mailable|string|array $view, string $queue = null)\n * @method static mixed queueOn(string $queue, \\Illuminate\\Contracts\\Mail\\Mailable|string|array $view)\n * @method static void assertNotQueued(string $mailable, callable $callback = null)\n * @method static void assertNotSent(string $mailable, callable|int $callback = null)\n * @method static void assertNothingQueued()\n * @method static void assertNothingSent()\n * @method static void assertQueued(string|\\Closure $mailable, callable|int $callback = null)\n * @method static void assertSent(string|\\Closure $mailable, callable|int $callback = null)\n * @method static void raw(string $text, $callback)\n * @method static void plain(string $view, array $data, $callback)\n * @method static void html(string $html, $callback)\n * @method static void send(\\Illuminate\\Contracts\\Mail\\Mailable|string|array $view, array $data = [], \\Closure|string $callback = null)\n *\n * @see \\Illuminate\\Mail\\Mailer\n * @see \\Illuminate\\Support\\Testing\\Fakes\\MailFake\n */\nclass Mail extends Facade\n{\n    /**\n     * Replace the bound instance with a fake.\n     *\n     * @return \\Illuminate\\Support\\Testing\\Fakes\\MailFake\n     */\n    public static function fake()\n    {\n        static::swap($fake = new MailFake);\n\n        return $fake;\n    }\n\n    /**\n     * Get the registered name of the component.\n     *\n     * @return string\n     */\n    protected static function getFacadeAccessor()\n    {\n        return 'mail.manager';\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Facades/Notification.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Facades;\n\nuse Illuminate\\Notifications\\AnonymousNotifiable;\nuse Illuminate\\Notifications\\ChannelManager;\nuse Illuminate\\Support\\Testing\\Fakes\\NotificationFake;\n\n/**\n * @method static \\Illuminate\\Notifications\\ChannelManager locale(string|null $locale)\n * @method static \\Illuminate\\Support\\Collection sent(mixed $notifiable, string $notification, callable $callback = null)\n * @method static bool hasSent(mixed $notifiable, string $notification)\n * @method static mixed channel(string|null $name = null)\n * @method static void assertNotSentTo(mixed $notifiable, string|\\Closure $notification, callable $callback = null)\n * @method static void assertNothingSent()\n * @method static void assertSentOnDemand(string|\\Closure $notification, callable $callback = null)\n * @method static void assertSentTo(mixed $notifiable, string|\\Closure $notification, callable $callback = null)\n * @method static void assertSentOnDemandTimes(string $notification, int $times = 1)\n * @method static void assertSentToTimes(mixed $notifiable, string $notification, int $times = 1)\n * @method static void assertTimesSent(int $expectedCount, string $notification)\n * @method static void send(\\Illuminate\\Support\\Collection|array|mixed $notifiables, $notification)\n * @method static void sendNow(\\Illuminate\\Support\\Collection|array|mixed $notifiables, $notification)\n *\n * @see \\Illuminate\\Notifications\\ChannelManager\n */\nclass Notification extends Facade\n{\n    /**\n     * Replace the bound instance with a fake.\n     *\n     * @return \\Illuminate\\Support\\Testing\\Fakes\\NotificationFake\n     */\n    public static function fake()\n    {\n        static::swap($fake = new NotificationFake);\n\n        return $fake;\n    }\n\n    /**\n     * Begin sending a notification to an anonymous notifiable.\n     *\n     * @param  string  $channel\n     * @param  mixed  $route\n     * @return \\Illuminate\\Notifications\\AnonymousNotifiable\n     */\n    public static function route($channel, $route)\n    {\n        return (new AnonymousNotifiable)->route($channel, $route);\n    }\n\n    /**\n     * Get the registered name of the component.\n     *\n     * @return string\n     */\n    protected static function getFacadeAccessor()\n    {\n        return ChannelManager::class;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Facades/ParallelTesting.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Facades;\n\n/**\n * @method static void setUpProcess(callable $callback)\n * @method static void setUpTestCase(callable $callback)\n * @method static void setUpTestDatabase(callable $callback)\n * @method static void tearDownProcess(callable $callback)\n * @method static void tearDownTestCase(callable $callback)\n * @method static int|false token()\n *\n * @see \\Illuminate\\Testing\\ParallelTesting\n */\nclass ParallelTesting extends Facade\n{\n    /**\n     * Get the registered name of the component.\n     *\n     * @return string\n     */\n    protected static function getFacadeAccessor()\n    {\n        return \\Illuminate\\Testing\\ParallelTesting::class;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Facades/Password.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Facades;\n\nuse Illuminate\\Contracts\\Auth\\PasswordBroker;\n\n/**\n * @method static mixed reset(array $credentials, \\Closure $callback)\n * @method static string sendResetLink(array $credentials, \\Closure $callback = null)\n * @method static \\Illuminate\\Contracts\\Auth\\CanResetPassword getUser(array $credentials)\n * @method static string createToken(\\Illuminate\\Contracts\\Auth\\CanResetPassword $user)\n * @method static void deleteToken(\\Illuminate\\Contracts\\Auth\\CanResetPassword $user)\n * @method static bool tokenExists(\\Illuminate\\Contracts\\Auth\\CanResetPassword $user, string $token)\n * @method static \\Illuminate\\Auth\\Passwords\\TokenRepositoryInterface getRepository()\n * @method static \\Illuminate\\Contracts\\Auth\\PasswordBroker broker(string|null $name = null)\n *\n * @see \\Illuminate\\Auth\\Passwords\\PasswordBroker\n */\nclass Password extends Facade\n{\n    /**\n     * Constant representing a successfully sent reminder.\n     *\n     * @var string\n     */\n    const RESET_LINK_SENT = PasswordBroker::RESET_LINK_SENT;\n\n    /**\n     * Constant representing a successfully reset password.\n     *\n     * @var string\n     */\n    const PASSWORD_RESET = PasswordBroker::PASSWORD_RESET;\n\n    /**\n     * Constant representing the user not found response.\n     *\n     * @var string\n     */\n    const INVALID_USER = PasswordBroker::INVALID_USER;\n\n    /**\n     * Constant representing an invalid token.\n     *\n     * @var string\n     */\n    const INVALID_TOKEN = PasswordBroker::INVALID_TOKEN;\n\n    /**\n     * Constant representing a throttled reset attempt.\n     *\n     * @var string\n     */\n    const RESET_THROTTLED = PasswordBroker::RESET_THROTTLED;\n\n    /**\n     * Get the registered name of the component.\n     *\n     * @return string\n     */\n    protected static function getFacadeAccessor()\n    {\n        return 'auth.password';\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Facades/Queue.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Facades;\n\nuse Illuminate\\Queue\\Worker;\nuse Illuminate\\Support\\Testing\\Fakes\\QueueFake;\n\n/**\n * @method static \\Illuminate\\Contracts\\Queue\\Job|null pop(string $queue = null)\n * @method static \\Illuminate\\Contracts\\Queue\\Queue setConnectionName(string $name)\n * @method static int size(string $queue = null)\n * @method static mixed bulk(array $jobs, mixed $data = '', string $queue = null)\n * @method static mixed later(\\DateTimeInterface|\\DateInterval|int $delay, string|object $job, mixed $data = '', string $queue = null)\n * @method static mixed laterOn(string $queue, \\DateTimeInterface|\\DateInterval|int $delay, string|object $job, mixed $data = '')\n * @method static mixed push(string|object $job, mixed $data = '', $queue = null)\n * @method static mixed pushOn(string $queue, string|object $job, mixed $data = '')\n * @method static mixed pushRaw(string $payload, string $queue = null, array $options = [])\n * @method static string getConnectionName()\n * @method static void assertNotPushed(string|\\Closure $job, callable $callback = null)\n * @method static void assertNothingPushed()\n * @method static void assertPushed(string|\\Closure $job, callable|int $callback = null)\n * @method static void assertPushedOn(string $queue, string|\\Closure $job, callable $callback = null)\n * @method static void assertPushedWithChain(string $job, array $expectedChain = [], callable $callback = null)\n *\n * @see \\Illuminate\\Queue\\QueueManager\n * @see \\Illuminate\\Queue\\Queue\n */\nclass Queue extends Facade\n{\n    /**\n     * Register a callback to be executed to pick jobs.\n     *\n     * @param  string  $workerName\n     * @param  callable  $callback\n     * @return void\n     */\n    public static function popUsing($workerName, $callback)\n    {\n        return Worker::popUsing($workerName, $callback);\n    }\n\n    /**\n     * Replace the bound instance with a fake.\n     *\n     * @return \\Illuminate\\Support\\Testing\\Fakes\\QueueFake\n     */\n    public static function fake()\n    {\n        static::swap($fake = new QueueFake(static::getFacadeApplication()));\n\n        return $fake;\n    }\n\n    /**\n     * Get the registered name of the component.\n     *\n     * @return string\n     */\n    protected static function getFacadeAccessor()\n    {\n        return 'queue';\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Facades/RateLimiter.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Facades;\n\n/**\n * @method static \\Illuminate\\Cache\\RateLimiter for(string $name, \\Closure $callback)\n * @method static \\Closure limiter(string $name)\n * @method static bool tooManyAttempts($key, $maxAttempts)\n * @method static int hit($key, $decaySeconds = 60)\n * @method static mixed attempts($key)\n * @method static mixed resetAttempts($key)\n * @method static int retriesLeft($key, $maxAttempts)\n * @method static void clear($key)\n * @method static int availableIn($key)\n * @method static bool attempt($key, $maxAttempts, \\Closure $callback, $decaySeconds = 60)\n *\n * @see \\Illuminate\\Cache\\RateLimiter\n */\nclass RateLimiter extends Facade\n{\n    /**\n     * Get the registered name of the component.\n     *\n     * @return string\n     */\n    protected static function getFacadeAccessor()\n    {\n        return 'Illuminate\\Cache\\RateLimiter';\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Facades/Redirect.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Facades;\n\n/**\n * @method static \\Illuminate\\Http\\RedirectResponse action(string $action, mixed $parameters = [], int $status = 302, array $headers = [])\n * @method static \\Illuminate\\Http\\RedirectResponse away(string $path, int $status = 302, array $headers = [])\n * @method static \\Illuminate\\Http\\RedirectResponse back(int $status = 302, array $headers = [], $fallback = false)\n * @method static \\Illuminate\\Http\\RedirectResponse guest(string $path, int $status = 302, array $headers = [], bool $secure = null)\n * @method static \\Illuminate\\Http\\RedirectResponse home(int $status = 302)\n * @method static \\Illuminate\\Http\\RedirectResponse intended(string $default = '/', int $status = 302, array $headers = [], bool $secure = null)\n * @method static \\Illuminate\\Http\\RedirectResponse refresh(int $status = 302, array $headers = [])\n * @method static \\Illuminate\\Http\\RedirectResponse route(string $route, mixed $parameters = [], int $status = 302, array $headers = [])\n * @method static \\Illuminate\\Http\\RedirectResponse secure(string $path, int $status = 302, array $headers = [])\n * @method static \\Illuminate\\Http\\RedirectResponse signedRoute(string $name, mixed $parameters = [], \\DateTimeInterface|\\DateInterval|int $expiration = null, int $status = 302, array $headers = [])\n * @method static \\Illuminate\\Http\\RedirectResponse temporarySignedRoute(string $name, \\DateTimeInterface|\\DateInterval|int $expiration, mixed $parameters = [], int $status = 302, array $headers = [])\n * @method static \\Illuminate\\Http\\RedirectResponse to(string $path, int $status = 302, array $headers = [], bool $secure = null)\n * @method static \\Illuminate\\Routing\\UrlGenerator getUrlGenerator()\n * @method static void setSession(\\Illuminate\\Session\\Store $session)\n * @method static void setIntendedUrl(string $url)\n *\n * @see \\Illuminate\\Routing\\Redirector\n */\nclass Redirect extends Facade\n{\n    /**\n     * Get the registered name of the component.\n     *\n     * @return string\n     */\n    protected static function getFacadeAccessor()\n    {\n        return 'redirect';\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Facades/Redis.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Facades;\n\n/**\n * @method static \\Illuminate\\Redis\\Connections\\Connection connection(string $name = null)\n * @method static \\Illuminate\\Redis\\Limiters\\ConcurrencyLimiterBuilder funnel(string $name)\n * @method static \\Illuminate\\Redis\\Limiters\\DurationLimiterBuilder throttle(string $name)\n *\n * @see \\Illuminate\\Redis\\RedisManager\n * @see \\Illuminate\\Contracts\\Redis\\Factory\n */\nclass Redis extends Facade\n{\n    /**\n     * Get the registered name of the component.\n     *\n     * @return string\n     */\n    protected static function getFacadeAccessor()\n    {\n        return 'redis';\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Facades/Request.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Facades;\n\n/**\n * @method static \\Closure getRouteResolver()\n * @method static \\Closure getUserResolver()\n * @method static \\Illuminate\\Http\\Request capture()\n * @method static \\Illuminate\\Http\\Request createFrom(\\Illuminate\\Http\\Request $from, \\Illuminate\\Http\\Request|null $to = null)\n * @method static \\Illuminate\\Http\\Request createFromBase(\\Symfony\\Component\\HttpFoundation\\Request $request)\n * @method static \\Illuminate\\Http\\Request duplicate(array|null $query = null, array|null $request = null, array|null $attributes = null, array|null $cookies = null, array|null $files = null, array|null $server = null)\n * @method static \\Illuminate\\Http\\Request instance()\n * @method static \\Illuminate\\Http\\Request merge(array $input)\n * @method static \\Illuminate\\Http\\Request replace(array $input)\n * @method static \\Illuminate\\Http\\Request setJson(\\Symfony\\Component\\HttpFoundation\\ParameterBag $json)\n * @method static \\Illuminate\\Http\\Request setRouteResolver(\\Closure $callback)\n * @method static \\Illuminate\\Http\\Request setUserResolver(\\Closure $callback)\n * @method static \\Illuminate\\Http\\UploadedFile|\\Illuminate\\Http\\UploadedFile[]|array|null file(string|null $key = null, mixed $default = null)\n * @method static \\Illuminate\\Routing\\Route|object|string route(string|null $param = null, string|null $default = null)\n * @method static \\Illuminate\\Session\\Store session()\n * @method static \\Illuminate\\Session\\Store|null getSession()\n * @method static \\Symfony\\Component\\HttpFoundation\\ParameterBag|mixed json(string|null $key = null, mixed $default = null)\n * @method static array all(array|mixed|null $keys = null)\n * @method static array allFiles()\n * @method static array except(array|mixed $keys)\n * @method static array ips()\n * @method static array keys()\n * @method static array only(array|mixed $keys)\n * @method static array segments()\n * @method static array toArray()\n * @method static array validate(array $rules, ...$params)\n * @method static array validateWithBag(string $errorBag, array $rules, ...$params)\n * @method static bool accepts(string|array $contentTypes)\n * @method static bool acceptsAnyContentType()\n * @method static bool acceptsHtml()\n * @method static bool acceptsJson()\n * @method static bool ajax()\n * @method static bool anyFilled(string|array $key)\n * @method static bool exists(string|array $key)\n * @method static bool expectsJson()\n * @method static bool filled(string|array $key)\n * @method static bool fullUrlIs(mixed ...$patterns)\n * @method static bool has(string|array $key)\n * @method static bool hasAny(string|array $key)\n * @method static bool hasCookie(string $key)\n * @method static bool hasFile(string $key)\n * @method static bool hasHeader(string $key)\n * @method static bool hasValidSignature(bool $absolute = true)\n * @method static bool is(mixed ...$patterns)\n * @method static bool isJson()\n * @method static bool matchesType(string $actual, string $type)\n * @method static bool offsetExists(string $offset)\n * @method static bool pjax()\n * @method static bool prefers(string|array $contentTypes)\n * @method static bool prefetch()\n * @method static bool routeIs(mixed ...$patterns)\n * @method static bool secure()\n * @method static bool wantsJson()\n * @method static mixed filterFiles(mixed $files)\n * @method static mixed offsetGet(string $offset)\n * @method static mixed user(string|null $guard = null)\n * @method static string decodedPath()\n * @method static string fingerprint()\n * @method static string format($default = 'html')\n * @method static string fullUrl()\n * @method static string fullUrlWithQuery(array $query)\n * @method static string method()\n * @method static string path()\n * @method static string root()\n * @method static string url()\n * @method static string userAgent()\n * @method static string|array old(string|null $key = null, string|array|null $default = null)\n * @method static string|array|null cookie(string|null $key = null, string|array|null $default = null)\n * @method static string|array|null header(string|null $key = null, string|array|null $default = null)\n * @method static string|array|null input(string|null $key = null, string|array|null $default = null)\n * @method static string|array|null post(string|null $key = null, string|array|null $default = null)\n * @method static string|array|null query(string|null $key = null, string|array|null $default = null)\n * @method static string|array|null server(string|null $key = null, string|array|null $default = null)\n * @method static string|null bearerToken()\n * @method static string|null ip()\n * @method static string|null segment(int $index, string|null $default = null)\n * @method static void flash()\n * @method static void flashExcept(array|mixed $keys)\n * @method static void flashOnly(array|mixed $keys)\n * @method static void flush()\n * @method static void offsetSet(string $offset, mixed $value)\n * @method static void offsetUnset(string $offset)\n * @method static void setLaravelSession(\\Illuminate\\Contracts\\Session\\Session $session)\n *\n * @see \\Illuminate\\Http\\Request\n */\nclass Request extends Facade\n{\n    /**\n     * Get the registered name of the component.\n     *\n     * @return string\n     */\n    protected static function getFacadeAccessor()\n    {\n        return 'request';\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Facades/Response.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Facades;\n\nuse Illuminate\\Contracts\\Routing\\ResponseFactory as ResponseFactoryContract;\n\n/**\n * @method static \\Illuminate\\Http\\JsonResponse json(string|array $data = [], int $status = 200, array $headers = [], int $options = 0)\n * @method static \\Illuminate\\Http\\JsonResponse jsonp(string $callback, string|array $data = [], int $status = 200, array $headers = [], int $options = 0)\n * @method static \\Illuminate\\Http\\RedirectResponse redirectGuest(string $path, int $status = 302, array $headers = [], bool|null $secure = null)\n * @method static \\Illuminate\\Http\\RedirectResponse redirectTo(string $path, int $status = 302, array $headers = [], bool|null $secure = null)\n * @method static \\Illuminate\\Http\\RedirectResponse redirectToAction(string $action, mixed $parameters = [], int $status = 302, array $headers = [])\n * @method static \\Illuminate\\Http\\RedirectResponse redirectToIntended(string $default = '/', int $status = 302, array $headers = [], bool|null $secure = null)\n * @method static \\Illuminate\\Http\\RedirectResponse redirectToRoute(string $route, mixed $parameters = [], int $status = 302, array $headers = [])\n * @method static \\Illuminate\\Http\\Response make(array|string $content = '', int $status = 200, array $headers = [])\n * @method static \\Illuminate\\Http\\Response noContent($status = 204, array $headers = [])\n * @method static \\Illuminate\\Http\\Response view(string $view, array $data = [], int $status = 200, array $headers = [])\n * @method static \\Symfony\\Component\\HttpFoundation\\BinaryFileResponse download(\\SplFileInfo|string $file, string|null $name = null, array $headers = [], string|null $disposition = 'attachment')\n * @method static \\Symfony\\Component\\HttpFoundation\\BinaryFileResponse file($file, array $headers = [])\n * @method static \\Symfony\\Component\\HttpFoundation\\StreamedResponse stream(\\Closure $callback, int $status = 200, array $headers = [])\n * @method static \\Symfony\\Component\\HttpFoundation\\StreamedResponse streamDownload(\\Closure $callback, string|null $name = null, array $headers = [], string|null $disposition = 'attachment')\n *\n * @see \\Illuminate\\Contracts\\Routing\\ResponseFactory\n */\nclass Response extends Facade\n{\n    /**\n     * Get the registered name of the component.\n     *\n     * @return string\n     */\n    protected static function getFacadeAccessor()\n    {\n        return ResponseFactoryContract::class;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Facades/Route.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Facades;\n\n/**\n * @method static \\Illuminate\\Routing\\PendingResourceRegistration apiResource(string $name, string $controller, array $options = [])\n * @method static \\Illuminate\\Routing\\PendingResourceRegistration resource(string $name, string $controller, array $options = [])\n * @method static \\Illuminate\\Routing\\Route any(string $uri, array|string|callable|null $action = null)\n * @method static \\Illuminate\\Routing\\Route|null current()\n * @method static \\Illuminate\\Routing\\Route delete(string $uri, array|string|callable|null $action = null)\n * @method static \\Illuminate\\Routing\\Route fallback(array|string|callable|null $action = null)\n * @method static \\Illuminate\\Routing\\Route get(string $uri, array|string|callable|null $action = null)\n * @method static \\Illuminate\\Routing\\Route|null getCurrentRoute()\n * @method static \\Illuminate\\Routing\\RouteCollectionInterface getRoutes()\n * @method static \\Illuminate\\Routing\\Route match(array|string $methods, string $uri, array|string|callable|null $action = null)\n * @method static \\Illuminate\\Routing\\Route options(string $uri, array|string|callable|null $action = null)\n * @method static \\Illuminate\\Routing\\Route patch(string $uri, array|string|callable|null $action = null)\n * @method static \\Illuminate\\Routing\\Route permanentRedirect(string $uri, string $destination)\n * @method static \\Illuminate\\Routing\\Route post(string $uri, array|string|callable|null $action = null)\n * @method static \\Illuminate\\Routing\\Route put(string $uri, array|string|callable|null $action = null)\n * @method static \\Illuminate\\Routing\\Route redirect(string $uri, string $destination, int $status = 302)\n * @method static \\Illuminate\\Routing\\Route substituteBindings(\\Illuminate\\Support\\Facades\\Route $route)\n * @method static \\Illuminate\\Routing\\Route view(string $uri, string $view, array $data = [], int|array $status = 200, array $headers = [])\n * @method static \\Illuminate\\Routing\\RouteRegistrar as(string $value)\n * @method static \\Illuminate\\Routing\\RouteRegistrar controller(string $controller)\n * @method static \\Illuminate\\Routing\\RouteRegistrar domain(string $value)\n * @method static \\Illuminate\\Routing\\RouteRegistrar middleware(array|string|null $middleware)\n * @method static \\Illuminate\\Routing\\RouteRegistrar name(string $value)\n * @method static \\Illuminate\\Routing\\RouteRegistrar namespace(string|null $value)\n * @method static \\Illuminate\\Routing\\RouteRegistrar prefix(string $prefix)\n * @method static \\Illuminate\\Routing\\RouteRegistrar scopeBindings()\n * @method static \\Illuminate\\Routing\\RouteRegistrar where(array $where)\n * @method static \\Illuminate\\Routing\\RouteRegistrar withoutMiddleware(array|string $middleware)\n * @method static \\Illuminate\\Routing\\Router|\\Illuminate\\Routing\\RouteRegistrar group(\\Closure|string|array $attributes, \\Closure|string $routes)\n * @method static \\Illuminate\\Routing\\ResourceRegistrar resourceVerbs(array $verbs = [])\n * @method static string|null currentRouteAction()\n * @method static string|null currentRouteName()\n * @method static void apiResources(array $resources, array $options = [])\n * @method static void bind(string $key, string|callable $binder)\n * @method static void model(string $key, string $class, \\Closure|null $callback = null)\n * @method static void pattern(string $key, string $pattern)\n * @method static void resources(array $resources, array $options = [])\n * @method static void substituteImplicitBindings(\\Illuminate\\Support\\Facades\\Route $route)\n * @method static boolean uses(...$patterns)\n * @method static boolean is(...$patterns)\n * @method static boolean has(string $name)\n * @method static mixed input(string $key, string|null $default = null)\n *\n * @see \\Illuminate\\Routing\\Router\n */\nclass Route extends Facade\n{\n    /**\n     * Get the registered name of the component.\n     *\n     * @return string\n     */\n    protected static function getFacadeAccessor()\n    {\n        return 'router';\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Facades/Schema.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Facades;\n\n/**\n * @method static \\Illuminate\\Database\\Schema\\Builder create(string $table, \\Closure $callback)\n * @method static \\Illuminate\\Database\\Schema\\Builder createDatabase(string $name)\n * @method static \\Illuminate\\Database\\Schema\\Builder disableForeignKeyConstraints()\n * @method static \\Illuminate\\Database\\Schema\\Builder drop(string $table)\n * @method static \\Illuminate\\Database\\Schema\\Builder dropDatabaseIfExists(string $name)\n * @method static \\Illuminate\\Database\\Schema\\Builder dropIfExists(string $table)\n * @method static \\Illuminate\\Database\\Schema\\Builder enableForeignKeyConstraints()\n * @method static \\Illuminate\\Database\\Schema\\Builder rename(string $from, string $to)\n * @method static \\Illuminate\\Database\\Schema\\Builder table(string $table, \\Closure $callback)\n * @method static bool hasColumn(string $table, string $column)\n * @method static bool hasColumns(string $table, array $columns)\n * @method static bool dropColumns(string $table, array $columns)\n * @method static bool hasTable(string $table)\n * @method static void defaultStringLength(int $length)\n * @method static void registerCustomDoctrineType(string $class, string $name, string $type)\n * @method static array getColumnListing(string $table)\n * @method static string getColumnType(string $table, string $column)\n * @method static void morphUsingUuids()\n * @method static \\Illuminate\\Database\\Connection getConnection()\n * @method static \\Illuminate\\Database\\Schema\\Builder setConnection(\\Illuminate\\Database\\Connection $connection)\n *\n * @see \\Illuminate\\Database\\Schema\\Builder\n */\nclass Schema extends Facade\n{\n    /**\n     * Get a schema builder instance for a connection.\n     *\n     * @param  string|null  $name\n     * @return \\Illuminate\\Database\\Schema\\Builder\n     */\n    public static function connection($name)\n    {\n        return static::$app['db']->connection($name)->getSchemaBuilder();\n    }\n\n    /**\n     * Get a schema builder instance for the default connection.\n     *\n     * @return \\Illuminate\\Database\\Schema\\Builder\n     */\n    protected static function getFacadeAccessor()\n    {\n        return static::$app['db']->connection()->getSchemaBuilder();\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Facades/Session.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Facades;\n\n/**\n * @method static \\SessionHandlerInterface getHandler()\n * @method static array all()\n * @method static bool exists(string|array $key)\n * @method static bool handlerNeedsRequest()\n * @method static bool has(string|array $key)\n * @method static bool isStarted()\n * @method static bool migrate(bool $destroy = false)\n * @method static bool save()\n * @method static bool start()\n * @method static mixed get(string $key, $default = null)\n * @method static mixed flash(string $key, $value = true)\n * @method static mixed pull(string $key, $default = null)\n * @method static mixed remove(string $key)\n * @method static string getId()\n * @method static string getName()\n * @method static string token()\n * @method static string|null previousUrl()\n * @method static void flush()\n * @method static void forget(string|array $keys)\n * @method static void push(string $key, mixed $value)\n * @method static void put(string|array $key, $value = null)\n * @method static void setId(string $id)\n * @method static void setPreviousUrl(string $url)\n * @method static void setRequestOnHandler(\\Illuminate\\Http\\Request $request)\n *\n * @see \\Illuminate\\Session\\SessionManager\n * @see \\Illuminate\\Session\\Store\n */\nclass Session extends Facade\n{\n    /**\n     * Get the registered name of the component.\n     *\n     * @return string\n     */\n    protected static function getFacadeAccessor()\n    {\n        return 'session';\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Facades/Storage.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Facades;\n\nuse Illuminate\\Filesystem\\Filesystem;\n\n/**\n * @method static \\Illuminate\\Contracts\\Filesystem\\Filesystem assertExists(string|array $path)\n * @method static \\Illuminate\\Contracts\\Filesystem\\Filesystem assertMissing(string|array $path)\n * @method static \\Illuminate\\Contracts\\Filesystem\\Filesystem cloud()\n * @method static \\Illuminate\\Contracts\\Filesystem\\Filesystem build(string|array $root)\n * @method static \\Illuminate\\Contracts\\Filesystem\\Filesystem disk(string|null $name = null)\n * @method static \\Illuminate\\Filesystem\\FilesystemManager extend(string $driver, \\Closure $callback)\n * @method static \\Symfony\\Component\\HttpFoundation\\StreamedResponse download(string $path, string|null $name = null, array|null $headers = [])\n * @method static \\Symfony\\Component\\HttpFoundation\\StreamedResponse response(string $path, string|null $name = null, array|null $headers = [], string|null $disposition = 'inline')\n * @method static array allDirectories(string|null $directory = null)\n * @method static array allFiles(string|null $directory = null)\n * @method static array directories(string|null $directory = null, bool $recursive = false)\n * @method static array files(string|null $directory = null, bool $recursive = false)\n * @method static bool append(string $path, string $data)\n * @method static bool copy(string $from, string $to)\n * @method static bool delete(string|array $paths)\n * @method static bool deleteDirectory(string $directory)\n * @method static bool exists(string $path)\n * @method static bool makeDirectory(string $path)\n * @method static bool missing(string $path)\n * @method static bool move(string $from, string $to)\n * @method static bool prepend(string $path, string $data)\n * @method static bool put(string $path, \\Psr\\Http\\Message\\StreamInterface|\\Illuminate\\Http\\File|\\Illuminate\\Http\\UploadedFile|string|resource $contents, mixed $options = [])\n * @method static bool setVisibility(string $path, string $visibility)\n * @method static bool writeStream(string $path, resource $resource, array $options = [])\n * @method static int lastModified(string $path)\n * @method static int size(string $path)\n * @method static resource|null readStream(string $path)\n * @method static string get(string $path)\n * @method static string getVisibility(string $path)\n * @method static string path(string $path)\n * @method static string temporaryUrl(string $path, \\DateTimeInterface $expiration, array $options = [])\n * @method static string url(string $path)\n * @method static string|false mimeType(string $path)\n * @method static string|false putFile(string $path, \\Illuminate\\Http\\File|\\Illuminate\\Http\\UploadedFile|string $file, mixed $options = [])\n * @method static string|false putFileAs(string $path, \\Illuminate\\Http\\File|\\Illuminate\\Http\\UploadedFile|string $file, string $name, mixed $options = [])\n * @method static void macro(string $name, object|callable $macro)\n * @method static void buildTemporaryUrlsUsing(\\Closure $callback)\n *\n * @see \\Illuminate\\Filesystem\\FilesystemManager\n */\nclass Storage extends Facade\n{\n    /**\n     * Replace the given disk with a local testing disk.\n     *\n     * @param  string|null  $disk\n     * @param  array  $config\n     * @return \\Illuminate\\Contracts\\Filesystem\\Filesystem\n     */\n    public static function fake($disk = null, array $config = [])\n    {\n        $disk = $disk ?: static::$app['config']->get('filesystems.default');\n\n        $root = storage_path('framework/testing/disks/'.$disk);\n\n        if ($token = ParallelTesting::token()) {\n            $root = \"{$root}_test_{$token}\";\n        }\n\n        (new Filesystem)->cleanDirectory($root);\n\n        static::set($disk, $fake = static::createLocalDriver(array_merge($config, [\n            'root' => $root,\n        ])));\n\n        return $fake;\n    }\n\n    /**\n     * Replace the given disk with a persistent local testing disk.\n     *\n     * @param  string|null  $disk\n     * @param  array  $config\n     * @return \\Illuminate\\Contracts\\Filesystem\\Filesystem\n     */\n    public static function persistentFake($disk = null, array $config = [])\n    {\n        $disk = $disk ?: static::$app['config']->get('filesystems.default');\n\n        static::set($disk, $fake = static::createLocalDriver(array_merge($config, [\n            'root' => storage_path('framework/testing/disks/'.$disk),\n        ])));\n\n        return $fake;\n    }\n\n    /**\n     * Get the registered name of the component.\n     *\n     * @return string\n     */\n    protected static function getFacadeAccessor()\n    {\n        return 'filesystem';\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Facades/URL.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Facades;\n\n/**\n * @method static \\Illuminate\\Contracts\\Routing\\UrlGenerator setRootControllerNamespace(string $rootNamespace)\n * @method static bool hasValidSignature(\\Illuminate\\Http\\Request $request, bool $absolute = true)\n * @method static string action(string|array $action, $parameters = [], bool $absolute = true)\n * @method static string asset(string $path, bool $secure = null)\n * @method static string secureAsset(string $path)\n * @method static string current()\n * @method static string full()\n * @method static void macro(string $name, object|callable $macro)\n * @method static void mixin(object $mixin, bool $replace = true)\n * @method static string previous($fallback = false)\n * @method static string route(string $name, $parameters = [], bool $absolute = true)\n * @method static string secure(string $path, array $parameters = [])\n * @method static string signedRoute(string $name, array $parameters = [], \\DateTimeInterface|\\DateInterval|int $expiration = null, bool $absolute = true)\n * @method static string temporarySignedRoute(string $name, \\DateTimeInterface|\\DateInterval|int $expiration, array $parameters = [], bool $absolute = true)\n * @method static string to(string $path, $extra = [], bool $secure = null)\n * @method static void defaults(array $defaults)\n * @method static void forceScheme(string $scheme)\n * @method static bool isValidUrl(string $path)\n *\n * @see \\Illuminate\\Routing\\UrlGenerator\n */\nclass URL extends Facade\n{\n    /**\n     * Get the registered name of the component.\n     *\n     * @return string\n     */\n    protected static function getFacadeAccessor()\n    {\n        return 'url';\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Facades/Validator.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Facades;\n\n/**\n * @method static \\Illuminate\\Contracts\\Validation\\Validator make(array $data, array $rules, array $messages = [], array $customAttributes = [])\n * @method static void excludeUnvalidatedArrayKeys()\n * @method static void extend(string $rule, \\Closure|string $extension, string $message = null)\n * @method static void extendImplicit(string $rule, \\Closure|string $extension, string $message = null)\n * @method static void replacer(string $rule, \\Closure|string $replacer)\n * @method static array validate(array $data, array $rules, array $messages = [], array $customAttributes = [])\n *\n * @see \\Illuminate\\Validation\\Factory\n */\nclass Validator extends Facade\n{\n    /**\n     * Get the registered name of the component.\n     *\n     * @return string\n     */\n    protected static function getFacadeAccessor()\n    {\n        return 'validator';\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Facades/View.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Facades;\n\n/**\n * @method static \\Illuminate\\Contracts\\View\\Factory addNamespace(string $namespace, string|array $hints)\n * @method static \\Illuminate\\Contracts\\View\\View first(array $views, \\Illuminate\\Contracts\\Support\\Arrayable|array $data = [], array $mergeData = [])\n * @method static \\Illuminate\\Contracts\\View\\Factory replaceNamespace(string $namespace, string|array $hints)\n * @method static \\Illuminate\\Contracts\\View\\Factory addExtension(string $extension, string $engine, \\Closure|null $resolver = null)\n * @method static \\Illuminate\\Contracts\\View\\View file(string $path, array $data = [], array $mergeData = [])\n * @method static \\Illuminate\\Contracts\\View\\View make(string $view, array $data = [], array $mergeData = [])\n * @method static array composer(array|string $views, \\Closure|string $callback)\n * @method static array creator(array|string $views, \\Closure|string $callback)\n * @method static bool exists(string $view)\n * @method static mixed share(array|string $key, $value = null)\n *\n * @see \\Illuminate\\View\\Factory\n */\nclass View extends Facade\n{\n    /**\n     * Get the registered name of the component.\n     *\n     * @return string\n     */\n    protected static function getFacadeAccessor()\n    {\n        return 'view';\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Fluent.php",
    "content": "<?php\n\nnamespace Illuminate\\Support;\n\nuse ArrayAccess;\nuse Illuminate\\Contracts\\Support\\Arrayable;\nuse Illuminate\\Contracts\\Support\\Jsonable;\nuse JsonSerializable;\n\nclass Fluent implements Arrayable, ArrayAccess, Jsonable, JsonSerializable\n{\n    /**\n     * All of the attributes set on the fluent instance.\n     *\n     * @var array\n     */\n    protected $attributes = [];\n\n    /**\n     * Create a new fluent instance.\n     *\n     * @param  array|object  $attributes\n     * @return void\n     */\n    public function __construct($attributes = [])\n    {\n        foreach ($attributes as $key => $value) {\n            $this->attributes[$key] = $value;\n        }\n    }\n\n    /**\n     * Get an attribute from the fluent instance.\n     *\n     * @param  string  $key\n     * @param  mixed  $default\n     * @return mixed\n     */\n    public function get($key, $default = null)\n    {\n        if (array_key_exists($key, $this->attributes)) {\n            return $this->attributes[$key];\n        }\n\n        return value($default);\n    }\n\n    /**\n     * Get the attributes from the fluent instance.\n     *\n     * @return array\n     */\n    public function getAttributes()\n    {\n        return $this->attributes;\n    }\n\n    /**\n     * Convert the fluent instance to an array.\n     *\n     * @return array\n     */\n    public function toArray()\n    {\n        return $this->attributes;\n    }\n\n    /**\n     * Convert the object into something JSON serializable.\n     *\n     * @return array\n     */\n    #[\\ReturnTypeWillChange]\n    public function jsonSerialize()\n    {\n        return $this->toArray();\n    }\n\n    /**\n     * Convert the fluent instance to JSON.\n     *\n     * @param  int  $options\n     * @return string\n     */\n    public function toJson($options = 0)\n    {\n        return json_encode($this->jsonSerialize(), $options);\n    }\n\n    /**\n     * Determine if the given offset exists.\n     *\n     * @param  string  $offset\n     * @return bool\n     */\n    #[\\ReturnTypeWillChange]\n    public function offsetExists($offset)\n    {\n        return isset($this->attributes[$offset]);\n    }\n\n    /**\n     * Get the value for a given offset.\n     *\n     * @param  string  $offset\n     * @return mixed\n     */\n    #[\\ReturnTypeWillChange]\n    public function offsetGet($offset)\n    {\n        return $this->get($offset);\n    }\n\n    /**\n     * Set the value at the given offset.\n     *\n     * @param  string  $offset\n     * @param  mixed  $value\n     * @return void\n     */\n    #[\\ReturnTypeWillChange]\n    public function offsetSet($offset, $value)\n    {\n        $this->attributes[$offset] = $value;\n    }\n\n    /**\n     * Unset the value at the given offset.\n     *\n     * @param  string  $offset\n     * @return void\n     */\n    #[\\ReturnTypeWillChange]\n    public function offsetUnset($offset)\n    {\n        unset($this->attributes[$offset]);\n    }\n\n    /**\n     * Handle dynamic calls to the fluent instance to set attributes.\n     *\n     * @param  string  $method\n     * @param  array  $parameters\n     * @return $this\n     */\n    public function __call($method, $parameters)\n    {\n        $this->attributes[$method] = count($parameters) > 0 ? $parameters[0] : true;\n\n        return $this;\n    }\n\n    /**\n     * Dynamically retrieve the value of an attribute.\n     *\n     * @param  string  $key\n     * @return mixed\n     */\n    public function __get($key)\n    {\n        return $this->get($key);\n    }\n\n    /**\n     * Dynamically set the value of an attribute.\n     *\n     * @param  string  $key\n     * @param  mixed  $value\n     * @return void\n     */\n    public function __set($key, $value)\n    {\n        $this->offsetSet($key, $value);\n    }\n\n    /**\n     * Dynamically check if an attribute is set.\n     *\n     * @param  string  $key\n     * @return bool\n     */\n    public function __isset($key)\n    {\n        return $this->offsetExists($key);\n    }\n\n    /**\n     * Dynamically unset an attribute.\n     *\n     * @param  string  $key\n     * @return void\n     */\n    public function __unset($key)\n    {\n        $this->offsetUnset($key);\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/HigherOrderTapProxy.php",
    "content": "<?php\n\nnamespace Illuminate\\Support;\n\nclass HigherOrderTapProxy\n{\n    /**\n     * The target being tapped.\n     *\n     * @var mixed\n     */\n    public $target;\n\n    /**\n     * Create a new tap proxy instance.\n     *\n     * @param  mixed  $target\n     * @return void\n     */\n    public function __construct($target)\n    {\n        $this->target = $target;\n    }\n\n    /**\n     * Dynamically pass method calls to the target.\n     *\n     * @param  string  $method\n     * @param  array  $parameters\n     * @return mixed\n     */\n    public function __call($method, $parameters)\n    {\n        $this->target->{$method}(...$parameters);\n\n        return $this->target;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/HtmlString.php",
    "content": "<?php\n\nnamespace Illuminate\\Support;\n\nuse Illuminate\\Contracts\\Support\\Htmlable;\n\nclass HtmlString implements Htmlable\n{\n    /**\n     * The HTML string.\n     *\n     * @var string\n     */\n    protected $html;\n\n    /**\n     * Create a new HTML string instance.\n     *\n     * @param  string  $html\n     * @return void\n     */\n    public function __construct($html = '')\n    {\n        $this->html = $html;\n    }\n\n    /**\n     * Get the HTML string.\n     *\n     * @return string\n     */\n    public function toHtml()\n    {\n        return $this->html;\n    }\n\n    /**\n     * Determine if the given HTML string is empty.\n     *\n     * @return bool\n     */\n    public function isEmpty()\n    {\n        return $this->html === '';\n    }\n\n    /**\n     * Determine if the given HTML string is not empty.\n     *\n     * @return bool\n     */\n    public function isNotEmpty()\n    {\n        return ! $this->isEmpty();\n    }\n\n    /**\n     * Get the HTML string.\n     *\n     * @return string\n     */\n    public function __toString()\n    {\n        return $this->toHtml();\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/InteractsWithTime.php",
    "content": "<?php\n\nnamespace Illuminate\\Support;\n\nuse DateInterval;\nuse DateTimeInterface;\n\ntrait InteractsWithTime\n{\n    /**\n     * Get the number of seconds until the given DateTime.\n     *\n     * @param  \\DateTimeInterface|\\DateInterval|int  $delay\n     * @return int\n     */\n    protected function secondsUntil($delay)\n    {\n        $delay = $this->parseDateInterval($delay);\n\n        return $delay instanceof DateTimeInterface\n                            ? max(0, $delay->getTimestamp() - $this->currentTime())\n                            : (int) $delay;\n    }\n\n    /**\n     * Get the \"available at\" UNIX timestamp.\n     *\n     * @param  \\DateTimeInterface|\\DateInterval|int  $delay\n     * @return int\n     */\n    protected function availableAt($delay = 0)\n    {\n        $delay = $this->parseDateInterval($delay);\n\n        return $delay instanceof DateTimeInterface\n                            ? $delay->getTimestamp()\n                            : Carbon::now()->addRealSeconds($delay)->getTimestamp();\n    }\n\n    /**\n     * If the given value is an interval, convert it to a DateTime instance.\n     *\n     * @param  \\DateTimeInterface|\\DateInterval|int  $delay\n     * @return \\DateTimeInterface|int\n     */\n    protected function parseDateInterval($delay)\n    {\n        if ($delay instanceof DateInterval) {\n            $delay = Carbon::now()->add($delay);\n        }\n\n        return $delay;\n    }\n\n    /**\n     * Get the current system time as a UNIX timestamp.\n     *\n     * @return int\n     */\n    protected function currentTime()\n    {\n        return Carbon::now()->getTimestamp();\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Js.php",
    "content": "<?php\n\nnamespace Illuminate\\Support;\n\nuse Illuminate\\Contracts\\Support\\Arrayable;\nuse Illuminate\\Contracts\\Support\\Htmlable;\nuse Illuminate\\Contracts\\Support\\Jsonable;\nuse JsonSerializable;\n\nclass Js implements Htmlable\n{\n    /**\n     * The JavaScript string.\n     *\n     * @var string\n     */\n    protected $js;\n\n    /**\n     * Flags that should be used when encoding to JSON.\n     *\n     * @var int\n     */\n    protected const REQUIRED_FLAGS = JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT | JSON_THROW_ON_ERROR;\n\n    /**\n     * Create a new class instance.\n     *\n     * @param  mixed  $data\n     * @param  int|null  $flags\n     * @param  int  $depth\n     * @return void\n     *\n     * @throws \\JsonException\n     */\n    public function __construct($data, $flags = 0, $depth = 512)\n    {\n        $this->js = $this->convertDataToJavaScriptExpression($data, $flags, $depth);\n    }\n\n    /**\n     * Create a new JavaScript string from the given data.\n     *\n     * @param  mixed  $data\n     * @param  int  $flags\n     * @param  int  $depth\n     * @return static\n     *\n     * @throws \\JsonException\n     */\n    public static function from($data, $flags = 0, $depth = 512)\n    {\n        return new static($data, $flags, $depth);\n    }\n\n    /**\n     * Convert the given data to a JavaScript expression.\n     *\n     * @param  mixed  $data\n     * @param  int  $flags\n     * @param  int  $depth\n     * @return string\n     *\n     * @throws \\JsonException\n     */\n    protected function convertDataToJavaScriptExpression($data, $flags = 0, $depth = 512)\n    {\n        if ($data instanceof self) {\n            return $data->toHtml();\n        }\n\n        $json = $this->jsonEncode($data, $flags, $depth);\n\n        if (is_string($data)) {\n            return \"'\".substr($json, 1, -1).\"'\";\n        }\n\n        return $this->convertJsonToJavaScriptExpression($json, $flags);\n    }\n\n    /**\n     * Encode the given data as JSON.\n     *\n     * @param  mixed  $data\n     * @param  int  $flags\n     * @param  int  $depth\n     * @return string\n     *\n     * @throws \\JsonException\n     */\n    protected function jsonEncode($data, $flags = 0, $depth = 512)\n    {\n        if ($data instanceof Jsonable) {\n            return $data->toJson($flags | static::REQUIRED_FLAGS);\n        }\n\n        if ($data instanceof Arrayable && ! ($data instanceof JsonSerializable)) {\n            $data = $data->toArray();\n        }\n\n        return json_encode($data, $flags | static::REQUIRED_FLAGS, $depth);\n    }\n\n    /**\n     * Convert the given JSON to a JavaScript expression.\n     *\n     * @param  string  $json\n     * @param  int  $flags\n     * @return string\n     *\n     * @throws \\JsonException\n     */\n    protected function convertJsonToJavaScriptExpression($json, $flags = 0)\n    {\n        if ('[]' === $json || '{}' === $json) {\n            return $json;\n        }\n\n        if (Str::startsWith($json, ['\"', '{', '['])) {\n            return \"JSON.parse('\".substr(json_encode($json, $flags | static::REQUIRED_FLAGS), 1, -1).\"')\";\n        }\n\n        return $json;\n    }\n\n    /**\n     * Get the string representation of the data for use in HTML.\n     *\n     * @return string\n     */\n    public function toHtml()\n    {\n        return $this->js;\n    }\n\n    /**\n     * Get the string representation of the data for use in HTML.\n     *\n     * @return string\n     */\n    public function __toString()\n    {\n        return $this->toHtml();\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/LICENSE.md",
    "content": "The MIT License (MIT)\n\nCopyright (c) Taylor Otwell\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "server/vendor/illuminate/support/Manager.php",
    "content": "<?php\n\nnamespace Illuminate\\Support;\n\nuse Closure;\nuse Illuminate\\Contracts\\Container\\Container;\nuse InvalidArgumentException;\n\nabstract class Manager\n{\n    /**\n     * The container instance.\n     *\n     * @var \\Illuminate\\Contracts\\Container\\Container\n     */\n    protected $container;\n\n    /**\n     * The configuration repository instance.\n     *\n     * @var \\Illuminate\\Contracts\\Config\\Repository\n     */\n    protected $config;\n\n    /**\n     * The registered custom driver creators.\n     *\n     * @var array\n     */\n    protected $customCreators = [];\n\n    /**\n     * The array of created \"drivers\".\n     *\n     * @var array\n     */\n    protected $drivers = [];\n\n    /**\n     * Create a new manager instance.\n     *\n     * @param  \\Illuminate\\Contracts\\Container\\Container  $container\n     * @return void\n     */\n    public function __construct(Container $container)\n    {\n        $this->container = $container;\n        $this->config = $container->make('config');\n    }\n\n    /**\n     * Get the default driver name.\n     *\n     * @return string\n     */\n    abstract public function getDefaultDriver();\n\n    /**\n     * Get a driver instance.\n     *\n     * @param  string|null  $driver\n     * @return mixed\n     *\n     * @throws \\InvalidArgumentException\n     */\n    public function driver($driver = null)\n    {\n        $driver = $driver ?: $this->getDefaultDriver();\n\n        if (is_null($driver)) {\n            throw new InvalidArgumentException(sprintf(\n                'Unable to resolve NULL driver for [%s].', static::class\n            ));\n        }\n\n        // If the given driver has not been created before, we will create the instances\n        // here and cache it so we can return it next time very quickly. If there is\n        // already a driver created by this name, we'll just return that instance.\n        if (! isset($this->drivers[$driver])) {\n            $this->drivers[$driver] = $this->createDriver($driver);\n        }\n\n        return $this->drivers[$driver];\n    }\n\n    /**\n     * Create a new driver instance.\n     *\n     * @param  string  $driver\n     * @return mixed\n     *\n     * @throws \\InvalidArgumentException\n     */\n    protected function createDriver($driver)\n    {\n        // First, we will determine if a custom driver creator exists for the given driver and\n        // if it does not we will check for a creator method for the driver. Custom creator\n        // callbacks allow developers to build their own \"drivers\" easily using Closures.\n        if (isset($this->customCreators[$driver])) {\n            return $this->callCustomCreator($driver);\n        } else {\n            $method = 'create'.Str::studly($driver).'Driver';\n\n            if (method_exists($this, $method)) {\n                return $this->$method();\n            }\n        }\n\n        throw new InvalidArgumentException(\"Driver [$driver] not supported.\");\n    }\n\n    /**\n     * Call a custom driver creator.\n     *\n     * @param  string  $driver\n     * @return mixed\n     */\n    protected function callCustomCreator($driver)\n    {\n        return $this->customCreators[$driver]($this->container);\n    }\n\n    /**\n     * Register a custom driver creator Closure.\n     *\n     * @param  string  $driver\n     * @param  \\Closure  $callback\n     * @return $this\n     */\n    public function extend($driver, Closure $callback)\n    {\n        $this->customCreators[$driver] = $callback;\n\n        return $this;\n    }\n\n    /**\n     * Get all of the created \"drivers\".\n     *\n     * @return array\n     */\n    public function getDrivers()\n    {\n        return $this->drivers;\n    }\n\n    /**\n     * Get the container instance used by the manager.\n     *\n     * @return \\Illuminate\\Contracts\\Container\\Container\n     */\n    public function getContainer()\n    {\n        return $this->container;\n    }\n\n    /**\n     * Set the container instance used by the manager.\n     *\n     * @param  \\Illuminate\\Contracts\\Container\\Container  $container\n     * @return $this\n     */\n    public function setContainer(Container $container)\n    {\n        $this->container = $container;\n\n        return $this;\n    }\n\n    /**\n     * Forget all of the resolved driver instances.\n     *\n     * @return $this\n     */\n    public function forgetDrivers()\n    {\n        $this->drivers = [];\n\n        return $this;\n    }\n\n    /**\n     * Dynamically call the default driver instance.\n     *\n     * @param  string  $method\n     * @param  array  $parameters\n     * @return mixed\n     */\n    public function __call($method, $parameters)\n    {\n        return $this->driver()->$method(...$parameters);\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/MessageBag.php",
    "content": "<?php\n\nnamespace Illuminate\\Support;\n\nuse Illuminate\\Contracts\\Support\\Arrayable;\nuse Illuminate\\Contracts\\Support\\Jsonable;\nuse Illuminate\\Contracts\\Support\\MessageBag as MessageBagContract;\nuse Illuminate\\Contracts\\Support\\MessageProvider;\nuse JsonSerializable;\n\nclass MessageBag implements Jsonable, JsonSerializable, MessageBagContract, MessageProvider\n{\n    /**\n     * All of the registered messages.\n     *\n     * @var array\n     */\n    protected $messages = [];\n\n    /**\n     * Default format for message output.\n     *\n     * @var string\n     */\n    protected $format = ':message';\n\n    /**\n     * Create a new message bag instance.\n     *\n     * @param  array  $messages\n     * @return void\n     */\n    public function __construct(array $messages = [])\n    {\n        foreach ($messages as $key => $value) {\n            $value = $value instanceof Arrayable ? $value->toArray() : (array) $value;\n\n            $this->messages[$key] = array_unique($value);\n        }\n    }\n\n    /**\n     * Get the keys present in the message bag.\n     *\n     * @return array\n     */\n    public function keys()\n    {\n        return array_keys($this->messages);\n    }\n\n    /**\n     * Add a message to the message bag.\n     *\n     * @param  string  $key\n     * @param  string  $message\n     * @return $this\n     */\n    public function add($key, $message)\n    {\n        if ($this->isUnique($key, $message)) {\n            $this->messages[$key][] = $message;\n        }\n\n        return $this;\n    }\n\n    /**\n     * Add a message to the message bag if the given conditional is \"true\".\n     *\n     * @param  bool  $boolean\n     * @param  string  $key\n     * @param  string  $message\n     * @return $this\n     */\n    public function addIf($boolean, $key, $message)\n    {\n        return $boolean ? $this->add($key, $message) : $this;\n    }\n\n    /**\n     * Determine if a key and message combination already exists.\n     *\n     * @param  string  $key\n     * @param  string  $message\n     * @return bool\n     */\n    protected function isUnique($key, $message)\n    {\n        $messages = (array) $this->messages;\n\n        return ! isset($messages[$key]) || ! in_array($message, $messages[$key]);\n    }\n\n    /**\n     * Merge a new array of messages into the message bag.\n     *\n     * @param  \\Illuminate\\Contracts\\Support\\MessageProvider|array  $messages\n     * @return $this\n     */\n    public function merge($messages)\n    {\n        if ($messages instanceof MessageProvider) {\n            $messages = $messages->getMessageBag()->getMessages();\n        }\n\n        $this->messages = array_merge_recursive($this->messages, $messages);\n\n        return $this;\n    }\n\n    /**\n     * Determine if messages exist for all of the given keys.\n     *\n     * @param  array|string|null  $key\n     * @return bool\n     */\n    public function has($key)\n    {\n        if ($this->isEmpty()) {\n            return false;\n        }\n\n        if (is_null($key)) {\n            return $this->any();\n        }\n\n        $keys = is_array($key) ? $key : func_get_args();\n\n        foreach ($keys as $key) {\n            if ($this->first($key) === '') {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    /**\n     * Determine if messages exist for any of the given keys.\n     *\n     * @param  array|string  $keys\n     * @return bool\n     */\n    public function hasAny($keys = [])\n    {\n        if ($this->isEmpty()) {\n            return false;\n        }\n\n        $keys = is_array($keys) ? $keys : func_get_args();\n\n        foreach ($keys as $key) {\n            if ($this->has($key)) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * Get the first message from the message bag for a given key.\n     *\n     * @param  string|null  $key\n     * @param  string|null  $format\n     * @return string\n     */\n    public function first($key = null, $format = null)\n    {\n        $messages = is_null($key) ? $this->all($format) : $this->get($key, $format);\n\n        $firstMessage = Arr::first($messages, null, '');\n\n        return is_array($firstMessage) ? Arr::first($firstMessage) : $firstMessage;\n    }\n\n    /**\n     * Get all of the messages from the message bag for a given key.\n     *\n     * @param  string  $key\n     * @param  string|null  $format\n     * @return array\n     */\n    public function get($key, $format = null)\n    {\n        // If the message exists in the message bag, we will transform it and return\n        // the message. Otherwise, we will check if the key is implicit & collect\n        // all the messages that match the given key and output it as an array.\n        if (array_key_exists($key, $this->messages)) {\n            return $this->transform(\n                $this->messages[$key], $this->checkFormat($format), $key\n            );\n        }\n\n        if (Str::contains($key, '*')) {\n            return $this->getMessagesForWildcardKey($key, $format);\n        }\n\n        return [];\n    }\n\n    /**\n     * Get the messages for a wildcard key.\n     *\n     * @param  string  $key\n     * @param  string|null  $format\n     * @return array\n     */\n    protected function getMessagesForWildcardKey($key, $format)\n    {\n        return collect($this->messages)\n                ->filter(function ($messages, $messageKey) use ($key) {\n                    return Str::is($key, $messageKey);\n                })\n                ->map(function ($messages, $messageKey) use ($format) {\n                    return $this->transform(\n                        $messages, $this->checkFormat($format), $messageKey\n                    );\n                })->all();\n    }\n\n    /**\n     * Get all of the messages for every key in the message bag.\n     *\n     * @param  string|null  $format\n     * @return array\n     */\n    public function all($format = null)\n    {\n        $format = $this->checkFormat($format);\n\n        $all = [];\n\n        foreach ($this->messages as $key => $messages) {\n            $all = array_merge($all, $this->transform($messages, $format, $key));\n        }\n\n        return $all;\n    }\n\n    /**\n     * Get all of the unique messages for every key in the message bag.\n     *\n     * @param  string|null  $format\n     * @return array\n     */\n    public function unique($format = null)\n    {\n        return array_unique($this->all($format));\n    }\n\n    /**\n     * Format an array of messages.\n     *\n     * @param  array  $messages\n     * @param  string  $format\n     * @param  string  $messageKey\n     * @return array\n     */\n    protected function transform($messages, $format, $messageKey)\n    {\n        return collect((array) $messages)\n            ->map(function ($message) use ($format, $messageKey) {\n                // We will simply spin through the given messages and transform each one\n                // replacing the :message place holder with the real message allowing\n                // the messages to be easily formatted to each developer's desires.\n                return str_replace([':message', ':key'], [$message, $messageKey], $format);\n            })->all();\n    }\n\n    /**\n     * Get the appropriate format based on the given format.\n     *\n     * @param  string  $format\n     * @return string\n     */\n    protected function checkFormat($format)\n    {\n        return $format ?: $this->format;\n    }\n\n    /**\n     * Get the raw messages in the message bag.\n     *\n     * @return array\n     */\n    public function messages()\n    {\n        return $this->messages;\n    }\n\n    /**\n     * Get the raw messages in the message bag.\n     *\n     * @return array\n     */\n    public function getMessages()\n    {\n        return $this->messages();\n    }\n\n    /**\n     * Get the messages for the instance.\n     *\n     * @return \\Illuminate\\Support\\MessageBag\n     */\n    public function getMessageBag()\n    {\n        return $this;\n    }\n\n    /**\n     * Get the default message format.\n     *\n     * @return string\n     */\n    public function getFormat()\n    {\n        return $this->format;\n    }\n\n    /**\n     * Set the default message format.\n     *\n     * @param  string  $format\n     * @return \\Illuminate\\Support\\MessageBag\n     */\n    public function setFormat($format = ':message')\n    {\n        $this->format = $format;\n\n        return $this;\n    }\n\n    /**\n     * Determine if the message bag has any messages.\n     *\n     * @return bool\n     */\n    public function isEmpty()\n    {\n        return ! $this->any();\n    }\n\n    /**\n     * Determine if the message bag has any messages.\n     *\n     * @return bool\n     */\n    public function isNotEmpty()\n    {\n        return $this->any();\n    }\n\n    /**\n     * Determine if the message bag has any messages.\n     *\n     * @return bool\n     */\n    public function any()\n    {\n        return $this->count() > 0;\n    }\n\n    /**\n     * Get the number of messages in the message bag.\n     *\n     * @return int\n     */\n    #[\\ReturnTypeWillChange]\n    public function count()\n    {\n        return count($this->messages, COUNT_RECURSIVE) - count($this->messages);\n    }\n\n    /**\n     * Get the instance as an array.\n     *\n     * @return array\n     */\n    public function toArray()\n    {\n        return $this->getMessages();\n    }\n\n    /**\n     * Convert the object into something JSON serializable.\n     *\n     * @return array\n     */\n    #[\\ReturnTypeWillChange]\n    public function jsonSerialize()\n    {\n        return $this->toArray();\n    }\n\n    /**\n     * Convert the object to its JSON representation.\n     *\n     * @param  int  $options\n     * @return string\n     */\n    public function toJson($options = 0)\n    {\n        return json_encode($this->jsonSerialize(), $options);\n    }\n\n    /**\n     * Convert the message bag to its string representation.\n     *\n     * @return string\n     */\n    public function __toString()\n    {\n        return $this->toJson();\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/MultipleInstanceManager.php",
    "content": "<?php\n\nnamespace Illuminate\\Support;\n\nuse Closure;\nuse InvalidArgumentException;\nuse RuntimeException;\n\nabstract class MultipleInstanceManager\n{\n    /**\n     * The application instance.\n     *\n     * @var \\Illuminate\\Contracts\\Foundation\\Application\n     */\n    protected $app;\n\n    /**\n     * The array of resolved instances.\n     *\n     * @var array\n     */\n    protected $instances = [];\n\n    /**\n     * The registered custom instance creators.\n     *\n     * @var array\n     */\n    protected $customCreators = [];\n\n    /**\n     * Create a new manager instance.\n     *\n     * @param  \\Illuminate\\Contracts\\Foundation\\Application  $app\n     * @return void\n     */\n    public function __construct($app)\n    {\n        $this->app = $app;\n    }\n\n    /**\n     * Get the default instance name.\n     *\n     * @return string\n     */\n    abstract public function getDefaultInstance();\n\n    /**\n     * Set the default instance name.\n     *\n     * @param  string  $name\n     * @return void\n     */\n    abstract public function setDefaultInstance($name);\n\n    /**\n     * Get the instance specific configuration.\n     *\n     * @param  string  $name\n     * @return array\n     */\n    abstract public function getInstanceConfig($name);\n\n    /**\n     * Get an instance instance by name.\n     *\n     * @param  string|null  $name\n     * @return mixed\n     */\n    public function instance($name = null)\n    {\n        $name = $name ?: $this->getDefaultInstance();\n\n        return $this->instances[$name] = $this->get($name);\n    }\n\n    /**\n     * Attempt to get an instance from the local cache.\n     *\n     * @param  string  $name\n     * @return mixed\n     */\n    protected function get($name)\n    {\n        return $this->instances[$name] ?? $this->resolve($name);\n    }\n\n    /**\n     * Resolve the given instance.\n     *\n     * @param  string  $name\n     * @return mixed\n     *\n     * @throws \\InvalidArgumentException\n     */\n    protected function resolve($name)\n    {\n        $config = $this->getInstanceConfig($name);\n\n        if (is_null($config)) {\n            throw new InvalidArgumentException(\"Instance [{$name}] is not defined.\");\n        }\n\n        if (! array_key_exists('driver', $config)) {\n            throw new RuntimeException(\"Instance [{$name}] does not specify a driver.\");\n        }\n\n        if (isset($this->customCreators[$config['driver']])) {\n            return $this->callCustomCreator($config);\n        } else {\n            $driverMethod = 'create'.ucfirst($config['driver']).'Driver';\n\n            if (method_exists($this, $driverMethod)) {\n                return $this->{$driverMethod}($config);\n            } else {\n                throw new InvalidArgumentException(\"Instance driver [{$config['driver']}] is not supported.\");\n            }\n        }\n    }\n\n    /**\n     * Call a custom instance creator.\n     *\n     * @param  array  $config\n     * @return mixed\n     */\n    protected function callCustomCreator(array $config)\n    {\n        return $this->customCreators[$config['driver']]($this->app, $config);\n    }\n\n    /**\n     * Unset the given instances.\n     *\n     * @param  array|string|null  $name\n     * @return $this\n     */\n    public function forgetInstance($name = null)\n    {\n        $name = $name ?? $this->getDefaultInstance();\n\n        foreach ((array) $name as $instanceName) {\n            if (isset($this->instances[$instanceName])) {\n                unset($this->instances[$instanceName]);\n            }\n        }\n\n        return $this;\n    }\n\n    /**\n     * Disconnect the given instance and remove from local cache.\n     *\n     * @param  string|null  $name\n     * @return void\n     */\n    public function purge($name = null)\n    {\n        $name = $name ?? $this->getDefaultInstance();\n\n        unset($this->instances[$name]);\n    }\n\n    /**\n     * Register a custom instance creator Closure.\n     *\n     * @param  string  $name\n     * @param  \\Closure  $callback\n     * @return $this\n     */\n    public function extend($name, Closure $callback)\n    {\n        $this->customCreators[$name] = $callback->bindTo($this, $this);\n\n        return $this;\n    }\n\n    /**\n     * Dynamically call the default instance.\n     *\n     * @param  string  $method\n     * @param  array  $parameters\n     * @return mixed\n     */\n    public function __call($method, $parameters)\n    {\n        return $this->instance()->$method(...$parameters);\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/NamespacedItemResolver.php",
    "content": "<?php\n\nnamespace Illuminate\\Support;\n\nclass NamespacedItemResolver\n{\n    /**\n     * A cache of the parsed items.\n     *\n     * @var array\n     */\n    protected $parsed = [];\n\n    /**\n     * Parse a key into namespace, group, and item.\n     *\n     * @param  string  $key\n     * @return array\n     */\n    public function parseKey($key)\n    {\n        // If we've already parsed the given key, we'll return the cached version we\n        // already have, as this will save us some processing. We cache off every\n        // key we parse so we can quickly return it on all subsequent requests.\n        if (isset($this->parsed[$key])) {\n            return $this->parsed[$key];\n        }\n\n        // If the key does not contain a double colon, it means the key is not in a\n        // namespace, and is just a regular configuration item. Namespaces are a\n        // tool for organizing configuration items for things such as modules.\n        if (strpos($key, '::') === false) {\n            $segments = explode('.', $key);\n\n            $parsed = $this->parseBasicSegments($segments);\n        } else {\n            $parsed = $this->parseNamespacedSegments($key);\n        }\n\n        // Once we have the parsed array of this key's elements, such as its groups\n        // and namespace, we will cache each array inside a simple list that has\n        // the key and the parsed array for quick look-ups for later requests.\n        return $this->parsed[$key] = $parsed;\n    }\n\n    /**\n     * Parse an array of basic segments.\n     *\n     * @param  array  $segments\n     * @return array\n     */\n    protected function parseBasicSegments(array $segments)\n    {\n        // The first segment in a basic array will always be the group, so we can go\n        // ahead and grab that segment. If there is only one total segment we are\n        // just pulling an entire group out of the array and not a single item.\n        $group = $segments[0];\n\n        // If there is more than one segment in this group, it means we are pulling\n        // a specific item out of a group and will need to return this item name\n        // as well as the group so we know which item to pull from the arrays.\n        $item = count($segments) === 1\n                    ? null\n                    : implode('.', array_slice($segments, 1));\n\n        return [null, $group, $item];\n    }\n\n    /**\n     * Parse an array of namespaced segments.\n     *\n     * @param  string  $key\n     * @return array\n     */\n    protected function parseNamespacedSegments($key)\n    {\n        [$namespace, $item] = explode('::', $key);\n\n        // First we'll just explode the first segment to get the namespace and group\n        // since the item should be in the remaining segments. Once we have these\n        // two pieces of data we can proceed with parsing out the item's value.\n        $itemSegments = explode('.', $item);\n\n        $groupAndItem = array_slice(\n            $this->parseBasicSegments($itemSegments), 1\n        );\n\n        return array_merge([$namespace], $groupAndItem);\n    }\n\n    /**\n     * Set the parsed value of a key.\n     *\n     * @param  string  $key\n     * @param  array  $parsed\n     * @return void\n     */\n    public function setParsedKey($key, $parsed)\n    {\n        $this->parsed[$key] = $parsed;\n    }\n\n    /**\n     * Flush the cache of parsed keys.\n     *\n     * @return void\n     */\n    public function flushParsedKeys()\n    {\n        $this->parsed = [];\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Optional.php",
    "content": "<?php\n\nnamespace Illuminate\\Support;\n\nuse ArrayAccess;\nuse ArrayObject;\nuse Illuminate\\Support\\Traits\\Macroable;\n\nclass Optional implements ArrayAccess\n{\n    use Macroable {\n        __call as macroCall;\n    }\n\n    /**\n     * The underlying object.\n     *\n     * @var mixed\n     */\n    protected $value;\n\n    /**\n     * Create a new optional instance.\n     *\n     * @param  mixed  $value\n     * @return void\n     */\n    public function __construct($value)\n    {\n        $this->value = $value;\n    }\n\n    /**\n     * Dynamically access a property on the underlying object.\n     *\n     * @param  string  $key\n     * @return mixed\n     */\n    public function __get($key)\n    {\n        if (is_object($this->value)) {\n            return $this->value->{$key} ?? null;\n        }\n    }\n\n    /**\n     * Dynamically check a property exists on the underlying object.\n     *\n     * @param  mixed  $name\n     * @return bool\n     */\n    public function __isset($name)\n    {\n        if (is_object($this->value)) {\n            return isset($this->value->{$name});\n        }\n\n        if (is_array($this->value) || $this->value instanceof ArrayObject) {\n            return isset($this->value[$name]);\n        }\n\n        return false;\n    }\n\n    /**\n     * Determine if an item exists at an offset.\n     *\n     * @param  mixed  $key\n     * @return bool\n     */\n    #[\\ReturnTypeWillChange]\n    public function offsetExists($key)\n    {\n        return Arr::accessible($this->value) && Arr::exists($this->value, $key);\n    }\n\n    /**\n     * Get an item at a given offset.\n     *\n     * @param  mixed  $key\n     * @return mixed\n     */\n    #[\\ReturnTypeWillChange]\n    public function offsetGet($key)\n    {\n        return Arr::get($this->value, $key);\n    }\n\n    /**\n     * Set the item at a given offset.\n     *\n     * @param  mixed  $key\n     * @param  mixed  $value\n     * @return void\n     */\n    #[\\ReturnTypeWillChange]\n    public function offsetSet($key, $value)\n    {\n        if (Arr::accessible($this->value)) {\n            $this->value[$key] = $value;\n        }\n    }\n\n    /**\n     * Unset the item at a given offset.\n     *\n     * @param  string  $key\n     * @return void\n     */\n    #[\\ReturnTypeWillChange]\n    public function offsetUnset($key)\n    {\n        if (Arr::accessible($this->value)) {\n            unset($this->value[$key]);\n        }\n    }\n\n    /**\n     * Dynamically pass a method to the underlying object.\n     *\n     * @param  string  $method\n     * @param  array  $parameters\n     * @return mixed\n     */\n    public function __call($method, $parameters)\n    {\n        if (static::hasMacro($method)) {\n            return $this->macroCall($method, $parameters);\n        }\n\n        if (is_object($this->value)) {\n            return $this->value->{$method}(...$parameters);\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Pluralizer.php",
    "content": "<?php\n\nnamespace Illuminate\\Support;\n\nuse Doctrine\\Inflector\\Inflector;\nuse Doctrine\\Inflector\\InflectorFactory;\n\nclass Pluralizer\n{\n    /**\n     * Uncountable word forms.\n     *\n     * @var string[]\n     */\n    public static $uncountable = [\n        'audio',\n        'bison',\n        'cattle',\n        'chassis',\n        'compensation',\n        'coreopsis',\n        'data',\n        'deer',\n        'education',\n        'emoji',\n        'equipment',\n        'evidence',\n        'feedback',\n        'firmware',\n        'fish',\n        'furniture',\n        'gold',\n        'hardware',\n        'information',\n        'jedi',\n        'kin',\n        'knowledge',\n        'love',\n        'metadata',\n        'money',\n        'moose',\n        'news',\n        'nutrition',\n        'offspring',\n        'plankton',\n        'pokemon',\n        'police',\n        'rain',\n        'recommended',\n        'related',\n        'rice',\n        'series',\n        'sheep',\n        'software',\n        'species',\n        'swine',\n        'traffic',\n        'wheat',\n    ];\n\n    /**\n     * Get the plural form of an English word.\n     *\n     * @param  string  $value\n     * @param  int|array|\\Countable  $count\n     * @return string\n     */\n    public static function plural($value, $count = 2)\n    {\n        if (is_countable($count)) {\n            $count = count($count);\n        }\n\n        if ((int) abs($count) === 1 || static::uncountable($value) || preg_match('/^(.*)[A-Za-z0-9\\x{0080}-\\x{FFFF}]$/u', $value) == 0) {\n            return $value;\n        }\n\n        $plural = static::inflector()->pluralize($value);\n\n        return static::matchCase($plural, $value);\n    }\n\n    /**\n     * Get the singular form of an English word.\n     *\n     * @param  string  $value\n     * @return string\n     */\n    public static function singular($value)\n    {\n        $singular = static::inflector()->singularize($value);\n\n        return static::matchCase($singular, $value);\n    }\n\n    /**\n     * Determine if the given value is uncountable.\n     *\n     * @param  string  $value\n     * @return bool\n     */\n    protected static function uncountable($value)\n    {\n        return in_array(strtolower($value), static::$uncountable);\n    }\n\n    /**\n     * Attempt to match the case on two strings.\n     *\n     * @param  string  $value\n     * @param  string  $comparison\n     * @return string\n     */\n    protected static function matchCase($value, $comparison)\n    {\n        $functions = ['mb_strtolower', 'mb_strtoupper', 'ucfirst', 'ucwords'];\n\n        foreach ($functions as $function) {\n            if ($function($comparison) === $comparison) {\n                return $function($value);\n            }\n        }\n\n        return $value;\n    }\n\n    /**\n     * Get the inflector instance.\n     *\n     * @return \\Doctrine\\Inflector\\Inflector\n     */\n    public static function inflector()\n    {\n        static $inflector;\n\n        if (is_null($inflector)) {\n            $inflector = InflectorFactory::createForLanguage('english')->build();\n        }\n\n        return $inflector;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/ProcessUtils.php",
    "content": "<?php\n\nnamespace Illuminate\\Support;\n\n/**\n * ProcessUtils is a bunch of utility methods.\n *\n * This class was originally copied from Symfony 3.\n */\nclass ProcessUtils\n{\n    /**\n     * Escapes a string to be used as a shell argument.\n     *\n     * @param  string  $argument\n     * @return string\n     */\n    public static function escapeArgument($argument)\n    {\n        // Fix for PHP bug #43784 escapeshellarg removes % from given string\n        // Fix for PHP bug #49446 escapeshellarg doesn't work on Windows\n        // @see https://bugs.php.net/bug.php?id=43784\n        // @see https://bugs.php.net/bug.php?id=49446\n        if ('\\\\' === DIRECTORY_SEPARATOR) {\n            if ('' === $argument) {\n                return '\"\"';\n            }\n\n            $escapedArgument = '';\n            $quote = false;\n\n            foreach (preg_split('/(\")/', $argument, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE) as $part) {\n                if ('\"' === $part) {\n                    $escapedArgument .= '\\\\\"';\n                } elseif (self::isSurroundedBy($part, '%')) {\n                    // Avoid environment variable expansion\n                    $escapedArgument .= '^%\"'.substr($part, 1, -1).'\"^%';\n                } else {\n                    // escape trailing backslash\n                    if ('\\\\' === substr($part, -1)) {\n                        $part .= '\\\\';\n                    }\n                    $quote = true;\n                    $escapedArgument .= $part;\n                }\n            }\n\n            if ($quote) {\n                $escapedArgument = '\"'.$escapedArgument.'\"';\n            }\n\n            return $escapedArgument;\n        }\n\n        return \"'\".str_replace(\"'\", \"'\\\\''\", $argument).\"'\";\n    }\n\n    /**\n     * Is the given string surrounded by the given character?\n     *\n     * @param  string  $arg\n     * @param  string  $char\n     * @return bool\n     */\n    protected static function isSurroundedBy($arg, $char)\n    {\n        return 2 < strlen($arg) && $char === $arg[0] && $char === $arg[strlen($arg) - 1];\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Reflector.php",
    "content": "<?php\n\nnamespace Illuminate\\Support;\n\nuse ReflectionClass;\nuse ReflectionMethod;\nuse ReflectionNamedType;\nuse ReflectionUnionType;\n\nclass Reflector\n{\n    /**\n     * This is a PHP 7.4 compatible implementation of is_callable.\n     *\n     * @param  mixed  $var\n     * @param  bool  $syntaxOnly\n     * @return bool\n     */\n    public static function isCallable($var, $syntaxOnly = false)\n    {\n        if (! is_array($var)) {\n            return is_callable($var, $syntaxOnly);\n        }\n\n        if ((! isset($var[0]) || ! isset($var[1])) ||\n            ! is_string($var[1] ?? null)) {\n            return false;\n        }\n\n        if ($syntaxOnly &&\n            (is_string($var[0]) || is_object($var[0])) &&\n            is_string($var[1])) {\n            return true;\n        }\n\n        $class = is_object($var[0]) ? get_class($var[0]) : $var[0];\n\n        $method = $var[1];\n\n        if (! class_exists($class)) {\n            return false;\n        }\n\n        if (method_exists($class, $method)) {\n            return (new ReflectionMethod($class, $method))->isPublic();\n        }\n\n        if (is_object($var[0]) && method_exists($class, '__call')) {\n            return (new ReflectionMethod($class, '__call'))->isPublic();\n        }\n\n        if (! is_object($var[0]) && method_exists($class, '__callStatic')) {\n            return (new ReflectionMethod($class, '__callStatic'))->isPublic();\n        }\n\n        return false;\n    }\n\n    /**\n     * Get the class name of the given parameter's type, if possible.\n     *\n     * @param  \\ReflectionParameter  $parameter\n     * @return string|null\n     */\n    public static function getParameterClassName($parameter)\n    {\n        $type = $parameter->getType();\n\n        if (! $type instanceof ReflectionNamedType || $type->isBuiltin()) {\n            return;\n        }\n\n        return static::getTypeName($parameter, $type);\n    }\n\n    /**\n     * Get the class names of the given parameter's type, including union types.\n     *\n     * @param  \\ReflectionParameter  $parameter\n     * @return array\n     */\n    public static function getParameterClassNames($parameter)\n    {\n        $type = $parameter->getType();\n\n        if (! $type instanceof ReflectionUnionType) {\n            return array_filter([static::getParameterClassName($parameter)]);\n        }\n\n        $unionTypes = [];\n\n        foreach ($type->getTypes() as $listedType) {\n            if (! $listedType instanceof ReflectionNamedType || $listedType->isBuiltin()) {\n                continue;\n            }\n\n            $unionTypes[] = static::getTypeName($parameter, $listedType);\n        }\n\n        return array_filter($unionTypes);\n    }\n\n    /**\n     * Get the given type's class name.\n     *\n     * @param  \\ReflectionParameter  $parameter\n     * @param  \\ReflectionNamedType  $type\n     * @return string\n     */\n    protected static function getTypeName($parameter, $type)\n    {\n        $name = $type->getName();\n\n        if (! is_null($class = $parameter->getDeclaringClass())) {\n            if ($name === 'self') {\n                return $class->getName();\n            }\n\n            if ($name === 'parent' && $parent = $class->getParentClass()) {\n                return $parent->getName();\n            }\n        }\n\n        return $name;\n    }\n\n    /**\n     * Determine if the parameter's type is a subclass of the given type.\n     *\n     * @param  \\ReflectionParameter  $parameter\n     * @param  string  $className\n     * @return bool\n     */\n    public static function isParameterSubclassOf($parameter, $className)\n    {\n        $paramClassName = static::getParameterClassName($parameter);\n\n        return $paramClassName\n            && (class_exists($paramClassName) || interface_exists($paramClassName))\n            && (new ReflectionClass($paramClassName))->isSubclassOf($className);\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/ServiceProvider.php",
    "content": "<?php\n\nnamespace Illuminate\\Support;\n\nuse Closure;\nuse Illuminate\\Console\\Application as Artisan;\nuse Illuminate\\Contracts\\Foundation\\CachesConfiguration;\nuse Illuminate\\Contracts\\Foundation\\CachesRoutes;\nuse Illuminate\\Contracts\\Support\\DeferrableProvider;\nuse Illuminate\\Database\\Eloquent\\Factory as ModelFactory;\nuse Illuminate\\View\\Compilers\\BladeCompiler;\n\nabstract class ServiceProvider\n{\n    /**\n     * The application instance.\n     *\n     * @var \\Illuminate\\Contracts\\Foundation\\Application\n     */\n    protected $app;\n\n    /**\n     * All of the registered booting callbacks.\n     *\n     * @var array\n     */\n    protected $bootingCallbacks = [];\n\n    /**\n     * All of the registered booted callbacks.\n     *\n     * @var array\n     */\n    protected $bootedCallbacks = [];\n\n    /**\n     * The paths that should be published.\n     *\n     * @var array\n     */\n    public static $publishes = [];\n\n    /**\n     * The paths that should be published by group.\n     *\n     * @var array\n     */\n    public static $publishGroups = [];\n\n    /**\n     * Create a new service provider instance.\n     *\n     * @param  \\Illuminate\\Contracts\\Foundation\\Application  $app\n     * @return void\n     */\n    public function __construct($app)\n    {\n        $this->app = $app;\n    }\n\n    /**\n     * Register any application services.\n     *\n     * @return void\n     */\n    public function register()\n    {\n        //\n    }\n\n    /**\n     * Register a booting callback to be run before the \"boot\" method is called.\n     *\n     * @param  \\Closure  $callback\n     * @return void\n     */\n    public function booting(Closure $callback)\n    {\n        $this->bootingCallbacks[] = $callback;\n    }\n\n    /**\n     * Register a booted callback to be run after the \"boot\" method is called.\n     *\n     * @param  \\Closure  $callback\n     * @return void\n     */\n    public function booted(Closure $callback)\n    {\n        $this->bootedCallbacks[] = $callback;\n    }\n\n    /**\n     * Call the registered booting callbacks.\n     *\n     * @return void\n     */\n    public function callBootingCallbacks()\n    {\n        $index = 0;\n\n        while ($index < count($this->bootingCallbacks)) {\n            $this->app->call($this->bootingCallbacks[$index]);\n\n            $index++;\n        }\n    }\n\n    /**\n     * Call the registered booted callbacks.\n     *\n     * @return void\n     */\n    public function callBootedCallbacks()\n    {\n        $index = 0;\n\n        while ($index < count($this->bootedCallbacks)) {\n            $this->app->call($this->bootedCallbacks[$index]);\n\n            $index++;\n        }\n    }\n\n    /**\n     * Merge the given configuration with the existing configuration.\n     *\n     * @param  string  $path\n     * @param  string  $key\n     * @return void\n     */\n    protected function mergeConfigFrom($path, $key)\n    {\n        if (! ($this->app instanceof CachesConfiguration && $this->app->configurationIsCached())) {\n            $config = $this->app->make('config');\n\n            $config->set($key, array_merge(\n                require $path, $config->get($key, [])\n            ));\n        }\n    }\n\n    /**\n     * Load the given routes file if routes are not already cached.\n     *\n     * @param  string  $path\n     * @return void\n     */\n    protected function loadRoutesFrom($path)\n    {\n        if (! ($this->app instanceof CachesRoutes && $this->app->routesAreCached())) {\n            require $path;\n        }\n    }\n\n    /**\n     * Register a view file namespace.\n     *\n     * @param  string|array  $path\n     * @param  string  $namespace\n     * @return void\n     */\n    protected function loadViewsFrom($path, $namespace)\n    {\n        $this->callAfterResolving('view', function ($view) use ($path, $namespace) {\n            if (isset($this->app->config['view']['paths']) &&\n                is_array($this->app->config['view']['paths'])) {\n                foreach ($this->app->config['view']['paths'] as $viewPath) {\n                    if (is_dir($appPath = $viewPath.'/vendor/'.$namespace)) {\n                        $view->addNamespace($namespace, $appPath);\n                    }\n                }\n            }\n\n            $view->addNamespace($namespace, $path);\n        });\n    }\n\n    /**\n     * Register the given view components with a custom prefix.\n     *\n     * @param  string  $prefix\n     * @param  array  $components\n     * @return void\n     */\n    protected function loadViewComponentsAs($prefix, array $components)\n    {\n        $this->callAfterResolving(BladeCompiler::class, function ($blade) use ($prefix, $components) {\n            foreach ($components as $alias => $component) {\n                $blade->component($component, is_string($alias) ? $alias : null, $prefix);\n            }\n        });\n    }\n\n    /**\n     * Register a translation file namespace.\n     *\n     * @param  string  $path\n     * @param  string  $namespace\n     * @return void\n     */\n    protected function loadTranslationsFrom($path, $namespace)\n    {\n        $this->callAfterResolving('translator', function ($translator) use ($path, $namespace) {\n            $translator->addNamespace($namespace, $path);\n        });\n    }\n\n    /**\n     * Register a JSON translation file path.\n     *\n     * @param  string  $path\n     * @return void\n     */\n    protected function loadJsonTranslationsFrom($path)\n    {\n        $this->callAfterResolving('translator', function ($translator) use ($path) {\n            $translator->addJsonPath($path);\n        });\n    }\n\n    /**\n     * Register database migration paths.\n     *\n     * @param  array|string  $paths\n     * @return void\n     */\n    protected function loadMigrationsFrom($paths)\n    {\n        $this->callAfterResolving('migrator', function ($migrator) use ($paths) {\n            foreach ((array) $paths as $path) {\n                $migrator->path($path);\n            }\n        });\n    }\n\n    /**\n     * Register Eloquent model factory paths.\n     *\n     * @deprecated Will be removed in a future Laravel version.\n     *\n     * @param  array|string  $paths\n     * @return void\n     */\n    protected function loadFactoriesFrom($paths)\n    {\n        $this->callAfterResolving(ModelFactory::class, function ($factory) use ($paths) {\n            foreach ((array) $paths as $path) {\n                $factory->load($path);\n            }\n        });\n    }\n\n    /**\n     * Setup an after resolving listener, or fire immediately if already resolved.\n     *\n     * @param  string  $name\n     * @param  callable  $callback\n     * @return void\n     */\n    protected function callAfterResolving($name, $callback)\n    {\n        $this->app->afterResolving($name, $callback);\n\n        if ($this->app->resolved($name)) {\n            $callback($this->app->make($name), $this->app);\n        }\n    }\n\n    /**\n     * Register paths to be published by the publish command.\n     *\n     * @param  array  $paths\n     * @param  mixed  $groups\n     * @return void\n     */\n    protected function publishes(array $paths, $groups = null)\n    {\n        $this->ensurePublishArrayInitialized($class = static::class);\n\n        static::$publishes[$class] = array_merge(static::$publishes[$class], $paths);\n\n        foreach ((array) $groups as $group) {\n            $this->addPublishGroup($group, $paths);\n        }\n    }\n\n    /**\n     * Ensure the publish array for the service provider is initialized.\n     *\n     * @param  string  $class\n     * @return void\n     */\n    protected function ensurePublishArrayInitialized($class)\n    {\n        if (! array_key_exists($class, static::$publishes)) {\n            static::$publishes[$class] = [];\n        }\n    }\n\n    /**\n     * Add a publish group / tag to the service provider.\n     *\n     * @param  string  $group\n     * @param  array  $paths\n     * @return void\n     */\n    protected function addPublishGroup($group, $paths)\n    {\n        if (! array_key_exists($group, static::$publishGroups)) {\n            static::$publishGroups[$group] = [];\n        }\n\n        static::$publishGroups[$group] = array_merge(\n            static::$publishGroups[$group], $paths\n        );\n    }\n\n    /**\n     * Get the paths to publish.\n     *\n     * @param  string|null  $provider\n     * @param  string|null  $group\n     * @return array\n     */\n    public static function pathsToPublish($provider = null, $group = null)\n    {\n        if (! is_null($paths = static::pathsForProviderOrGroup($provider, $group))) {\n            return $paths;\n        }\n\n        return collect(static::$publishes)->reduce(function ($paths, $p) {\n            return array_merge($paths, $p);\n        }, []);\n    }\n\n    /**\n     * Get the paths for the provider or group (or both).\n     *\n     * @param  string|null  $provider\n     * @param  string|null  $group\n     * @return array\n     */\n    protected static function pathsForProviderOrGroup($provider, $group)\n    {\n        if ($provider && $group) {\n            return static::pathsForProviderAndGroup($provider, $group);\n        } elseif ($group && array_key_exists($group, static::$publishGroups)) {\n            return static::$publishGroups[$group];\n        } elseif ($provider && array_key_exists($provider, static::$publishes)) {\n            return static::$publishes[$provider];\n        } elseif ($group || $provider) {\n            return [];\n        }\n    }\n\n    /**\n     * Get the paths for the provider and group.\n     *\n     * @param  string  $provider\n     * @param  string  $group\n     * @return array\n     */\n    protected static function pathsForProviderAndGroup($provider, $group)\n    {\n        if (! empty(static::$publishes[$provider]) && ! empty(static::$publishGroups[$group])) {\n            return array_intersect_key(static::$publishes[$provider], static::$publishGroups[$group]);\n        }\n\n        return [];\n    }\n\n    /**\n     * Get the service providers available for publishing.\n     *\n     * @return array\n     */\n    public static function publishableProviders()\n    {\n        return array_keys(static::$publishes);\n    }\n\n    /**\n     * Get the groups available for publishing.\n     *\n     * @return array\n     */\n    public static function publishableGroups()\n    {\n        return array_keys(static::$publishGroups);\n    }\n\n    /**\n     * Register the package's custom Artisan commands.\n     *\n     * @param  array|mixed  $commands\n     * @return void\n     */\n    public function commands($commands)\n    {\n        $commands = is_array($commands) ? $commands : func_get_args();\n\n        Artisan::starting(function ($artisan) use ($commands) {\n            $artisan->resolveCommands($commands);\n        });\n    }\n\n    /**\n     * Get the services provided by the provider.\n     *\n     * @return array\n     */\n    public function provides()\n    {\n        return [];\n    }\n\n    /**\n     * Get the events that trigger this service provider to register.\n     *\n     * @return array\n     */\n    public function when()\n    {\n        return [];\n    }\n\n    /**\n     * Determine if the provider is deferred.\n     *\n     * @return bool\n     */\n    public function isDeferred()\n    {\n        return $this instanceof DeferrableProvider;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Str.php",
    "content": "<?php\n\nnamespace Illuminate\\Support;\n\nuse Illuminate\\Support\\Traits\\Macroable;\nuse League\\CommonMark\\GithubFlavoredMarkdownConverter;\nuse Ramsey\\Uuid\\Codec\\TimestampFirstCombCodec;\nuse Ramsey\\Uuid\\Generator\\CombGenerator;\nuse Ramsey\\Uuid\\Uuid;\nuse Ramsey\\Uuid\\UuidFactory;\nuse voku\\helper\\ASCII;\n\nclass Str\n{\n    use Macroable;\n\n    /**\n     * The cache of snake-cased words.\n     *\n     * @var array\n     */\n    protected static $snakeCache = [];\n\n    /**\n     * The cache of camel-cased words.\n     *\n     * @var array\n     */\n    protected static $camelCache = [];\n\n    /**\n     * The cache of studly-cased words.\n     *\n     * @var array\n     */\n    protected static $studlyCache = [];\n\n    /**\n     * The callback that should be used to generate UUIDs.\n     *\n     * @var callable\n     */\n    protected static $uuidFactory;\n\n    /**\n     * Get a new stringable object from the given string.\n     *\n     * @param  string  $string\n     * @return \\Illuminate\\Support\\Stringable\n     */\n    public static function of($string)\n    {\n        return new Stringable($string);\n    }\n\n    /**\n     * Return the remainder of a string after the first occurrence of a given value.\n     *\n     * @param  string  $subject\n     * @param  string  $search\n     * @return string\n     */\n    public static function after($subject, $search)\n    {\n        return $search === '' ? $subject : array_reverse(explode($search, $subject, 2))[0];\n    }\n\n    /**\n     * Return the remainder of a string after the last occurrence of a given value.\n     *\n     * @param  string  $subject\n     * @param  string  $search\n     * @return string\n     */\n    public static function afterLast($subject, $search)\n    {\n        if ($search === '') {\n            return $subject;\n        }\n\n        $position = strrpos($subject, (string) $search);\n\n        if ($position === false) {\n            return $subject;\n        }\n\n        return substr($subject, $position + strlen($search));\n    }\n\n    /**\n     * Transliterate a UTF-8 value to ASCII.\n     *\n     * @param  string  $value\n     * @param  string  $language\n     * @return string\n     */\n    public static function ascii($value, $language = 'en')\n    {\n        return ASCII::to_ascii((string) $value, $language);\n    }\n\n    /**\n     * Transliterate a string to its closest ASCII representation.\n     *\n     * @param  string  $string\n     * @param  string|null  $unknown\n     * @param  bool|null  $strict\n     * @return string\n     */\n    public static function transliterate($string, $unknown = '?', $strict = false)\n    {\n        return ASCII::to_transliterate($string, $unknown, $strict);\n    }\n\n    /**\n     * Get the portion of a string before the first occurrence of a given value.\n     *\n     * @param  string  $subject\n     * @param  string  $search\n     * @return string\n     */\n    public static function before($subject, $search)\n    {\n        if ($search === '') {\n            return $subject;\n        }\n\n        $result = strstr($subject, (string) $search, true);\n\n        return $result === false ? $subject : $result;\n    }\n\n    /**\n     * Get the portion of a string before the last occurrence of a given value.\n     *\n     * @param  string  $subject\n     * @param  string  $search\n     * @return string\n     */\n    public static function beforeLast($subject, $search)\n    {\n        if ($search === '') {\n            return $subject;\n        }\n\n        $pos = mb_strrpos($subject, $search);\n\n        if ($pos === false) {\n            return $subject;\n        }\n\n        return static::substr($subject, 0, $pos);\n    }\n\n    /**\n     * Get the portion of a string between two given values.\n     *\n     * @param  string  $subject\n     * @param  string  $from\n     * @param  string  $to\n     * @return string\n     */\n    public static function between($subject, $from, $to)\n    {\n        if ($from === '' || $to === '') {\n            return $subject;\n        }\n\n        return static::beforeLast(static::after($subject, $from), $to);\n    }\n\n    /**\n     * Convert a value to camel case.\n     *\n     * @param  string  $value\n     * @return string\n     */\n    public static function camel($value)\n    {\n        if (isset(static::$camelCache[$value])) {\n            return static::$camelCache[$value];\n        }\n\n        return static::$camelCache[$value] = lcfirst(static::studly($value));\n    }\n\n    /**\n     * Determine if a given string contains a given substring.\n     *\n     * @param  string  $haystack\n     * @param  string|string[]  $needles\n     * @return bool\n     */\n    public static function contains($haystack, $needles)\n    {\n        foreach ((array) $needles as $needle) {\n            if ($needle !== '' && mb_strpos($haystack, $needle) !== false) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * Determine if a given string contains all array values.\n     *\n     * @param  string  $haystack\n     * @param  string[]  $needles\n     * @return bool\n     */\n    public static function containsAll($haystack, array $needles)\n    {\n        foreach ($needles as $needle) {\n            if (! static::contains($haystack, $needle)) {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    /**\n     * Determine if a given string ends with a given substring.\n     *\n     * @param  string  $haystack\n     * @param  string|string[]  $needles\n     * @return bool\n     */\n    public static function endsWith($haystack, $needles)\n    {\n        foreach ((array) $needles as $needle) {\n            if (\n                $needle !== '' && $needle !== null\n                && substr($haystack, -strlen($needle)) === (string) $needle\n            ) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * Cap a string with a single instance of a given value.\n     *\n     * @param  string  $value\n     * @param  string  $cap\n     * @return string\n     */\n    public static function finish($value, $cap)\n    {\n        $quoted = preg_quote($cap, '/');\n\n        return preg_replace('/(?:'.$quoted.')+$/u', '', $value).$cap;\n    }\n\n    /**\n     * Determine if a given string matches a given pattern.\n     *\n     * @param  string|array  $pattern\n     * @param  string  $value\n     * @return bool\n     */\n    public static function is($pattern, $value)\n    {\n        $patterns = Arr::wrap($pattern);\n\n        $value = (string) $value;\n\n        if (empty($patterns)) {\n            return false;\n        }\n\n        foreach ($patterns as $pattern) {\n            $pattern = (string) $pattern;\n\n            // If the given value is an exact match we can of course return true right\n            // from the beginning. Otherwise, we will translate asterisks and do an\n            // actual pattern match against the two strings to see if they match.\n            if ($pattern == $value) {\n                return true;\n            }\n\n            $pattern = preg_quote($pattern, '#');\n\n            // Asterisks are translated into zero-or-more regular expression wildcards\n            // to make it convenient to check if the strings starts with the given\n            // pattern such as \"library/*\", making any string check convenient.\n            $pattern = str_replace('\\*', '.*', $pattern);\n\n            if (preg_match('#^'.$pattern.'\\z#u', $value) === 1) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * Determine if a given string is 7 bit ASCII.\n     *\n     * @param  string  $value\n     * @return bool\n     */\n    public static function isAscii($value)\n    {\n        return ASCII::is_ascii((string) $value);\n    }\n\n    /**\n     * Determine if a given string is a valid UUID.\n     *\n     * @param  string  $value\n     * @return bool\n     */\n    public static function isUuid($value)\n    {\n        if (! is_string($value)) {\n            return false;\n        }\n\n        return preg_match('/^[\\da-f]{8}-[\\da-f]{4}-[\\da-f]{4}-[\\da-f]{4}-[\\da-f]{12}$/iD', $value) > 0;\n    }\n\n    /**\n     * Convert a string to kebab case.\n     *\n     * @param  string  $value\n     * @return string\n     */\n    public static function kebab($value)\n    {\n        return static::snake($value, '-');\n    }\n\n    /**\n     * Return the length of the given string.\n     *\n     * @param  string  $value\n     * @param  string|null  $encoding\n     * @return int\n     */\n    public static function length($value, $encoding = null)\n    {\n        if ($encoding) {\n            return mb_strlen($value, $encoding);\n        }\n\n        return mb_strlen($value);\n    }\n\n    /**\n     * Limit the number of characters in a string.\n     *\n     * @param  string  $value\n     * @param  int  $limit\n     * @param  string  $end\n     * @return string\n     */\n    public static function limit($value, $limit = 100, $end = '...')\n    {\n        if (mb_strwidth($value, 'UTF-8') <= $limit) {\n            return $value;\n        }\n\n        return rtrim(mb_strimwidth($value, 0, $limit, '', 'UTF-8')).$end;\n    }\n\n    /**\n     * Convert the given string to lower-case.\n     *\n     * @param  string  $value\n     * @return string\n     */\n    public static function lower($value)\n    {\n        return mb_strtolower($value, 'UTF-8');\n    }\n\n    /**\n     * Limit the number of words in a string.\n     *\n     * @param  string  $value\n     * @param  int  $words\n     * @param  string  $end\n     * @return string\n     */\n    public static function words($value, $words = 100, $end = '...')\n    {\n        preg_match('/^\\s*+(?:\\S++\\s*+){1,'.$words.'}/u', $value, $matches);\n\n        if (! isset($matches[0]) || static::length($value) === static::length($matches[0])) {\n            return $value;\n        }\n\n        return rtrim($matches[0]).$end;\n    }\n\n    /**\n     * Converts GitHub flavored Markdown into HTML.\n     *\n     * @param  string  $string\n     * @param  array  $options\n     * @return string\n     */\n    public static function markdown($string, array $options = [])\n    {\n        $converter = new GithubFlavoredMarkdownConverter($options);\n\n        return (string) $converter->convertToHtml($string);\n    }\n\n    /**\n     * Masks a portion of a string with a repeated character.\n     *\n     * @param  string  $string\n     * @param  string  $character\n     * @param  int  $index\n     * @param  int|null  $length\n     * @param  string  $encoding\n     * @return string\n     */\n    public static function mask($string, $character, $index, $length = null, $encoding = 'UTF-8')\n    {\n        if ($character === '') {\n            return $string;\n        }\n\n        if (is_null($length) && PHP_MAJOR_VERSION < 8) {\n            $length = mb_strlen($string, $encoding);\n        }\n\n        $segment = mb_substr($string, $index, $length, $encoding);\n\n        if ($segment === '') {\n            return $string;\n        }\n\n        $strlen = mb_strlen($string, $encoding);\n        $startIndex = $index;\n\n        if ($index < 0) {\n            $startIndex = $index < -$strlen ? 0 : $strlen + $index;\n        }\n\n        $start = mb_substr($string, 0, $startIndex, $encoding);\n        $segmentLen = mb_strlen($segment, $encoding);\n        $end = mb_substr($string, $startIndex + $segmentLen);\n\n        return $start.str_repeat(mb_substr($character, 0, 1, $encoding), $segmentLen).$end;\n    }\n\n    /**\n     * Get the string matching the given pattern.\n     *\n     * @param  string  $pattern\n     * @param  string  $subject\n     * @return string\n     */\n    public static function match($pattern, $subject)\n    {\n        preg_match($pattern, $subject, $matches);\n\n        if (! $matches) {\n            return '';\n        }\n\n        return $matches[1] ?? $matches[0];\n    }\n\n    /**\n     * Get the string matching the given pattern.\n     *\n     * @param  string  $pattern\n     * @param  string  $subject\n     * @return \\Illuminate\\Support\\Collection\n     */\n    public static function matchAll($pattern, $subject)\n    {\n        preg_match_all($pattern, $subject, $matches);\n\n        if (empty($matches[0])) {\n            return collect();\n        }\n\n        return collect($matches[1] ?? $matches[0]);\n    }\n\n    /**\n     * Pad both sides of a string with another.\n     *\n     * @param  string  $value\n     * @param  int  $length\n     * @param  string  $pad\n     * @return string\n     */\n    public static function padBoth($value, $length, $pad = ' ')\n    {\n        return str_pad($value, strlen($value) - mb_strlen($value) + $length, $pad, STR_PAD_BOTH);\n    }\n\n    /**\n     * Pad the left side of a string with another.\n     *\n     * @param  string  $value\n     * @param  int  $length\n     * @param  string  $pad\n     * @return string\n     */\n    public static function padLeft($value, $length, $pad = ' ')\n    {\n        return str_pad($value, strlen($value) - mb_strlen($value) + $length, $pad, STR_PAD_LEFT);\n    }\n\n    /**\n     * Pad the right side of a string with another.\n     *\n     * @param  string  $value\n     * @param  int  $length\n     * @param  string  $pad\n     * @return string\n     */\n    public static function padRight($value, $length, $pad = ' ')\n    {\n        return str_pad($value, strlen($value) - mb_strlen($value) + $length, $pad, STR_PAD_RIGHT);\n    }\n\n    /**\n     * Parse a Class[@]method style callback into class and method.\n     *\n     * @param  string  $callback\n     * @param  string|null  $default\n     * @return array<int, string|null>\n     */\n    public static function parseCallback($callback, $default = null)\n    {\n        return static::contains($callback, '@') ? explode('@', $callback, 2) : [$callback, $default];\n    }\n\n    /**\n     * Get the plural form of an English word.\n     *\n     * @param  string  $value\n     * @param  int|array|\\Countable  $count\n     * @return string\n     */\n    public static function plural($value, $count = 2)\n    {\n        return Pluralizer::plural($value, $count);\n    }\n\n    /**\n     * Pluralize the last word of an English, studly caps case string.\n     *\n     * @param  string  $value\n     * @param  int|array|\\Countable  $count\n     * @return string\n     */\n    public static function pluralStudly($value, $count = 2)\n    {\n        $parts = preg_split('/(.)(?=[A-Z])/u', $value, -1, PREG_SPLIT_DELIM_CAPTURE);\n\n        $lastWord = array_pop($parts);\n\n        return implode('', $parts).self::plural($lastWord, $count);\n    }\n\n    /**\n     * Generate a more truly \"random\" alpha-numeric string.\n     *\n     * @param  int  $length\n     * @return string\n     */\n    public static function random($length = 16)\n    {\n        $string = '';\n\n        while (($len = strlen($string)) < $length) {\n            $size = $length - $len;\n\n            $bytes = random_bytes($size);\n\n            $string .= substr(str_replace(['/', '+', '='], '', base64_encode($bytes)), 0, $size);\n        }\n\n        return $string;\n    }\n\n    /**\n     * Repeat the given string.\n     *\n     * @param  string  $string\n     * @param  int  $times\n     * @return string\n     */\n    public static function repeat(string $string, int $times)\n    {\n        return str_repeat($string, $times);\n    }\n\n    /**\n     * Replace a given value in the string sequentially with an array.\n     *\n     * @param  string  $search\n     * @param  array<int|string, string>  $replace\n     * @param  string  $subject\n     * @return string\n     */\n    public static function replaceArray($search, array $replace, $subject)\n    {\n        $segments = explode($search, $subject);\n\n        $result = array_shift($segments);\n\n        foreach ($segments as $segment) {\n            $result .= (array_shift($replace) ?? $search).$segment;\n        }\n\n        return $result;\n    }\n\n    /**\n     * Replace the given value in the given string.\n     *\n     * @param  string|string[]  $search\n     * @param  string|string[]  $replace\n     * @param  string|string[]  $subject\n     * @return string\n     */\n    public static function replace($search, $replace, $subject)\n    {\n        return str_replace($search, $replace, $subject);\n    }\n\n    /**\n     * Replace the first occurrence of a given value in the string.\n     *\n     * @param  string  $search\n     * @param  string  $replace\n     * @param  string  $subject\n     * @return string\n     */\n    public static function replaceFirst($search, $replace, $subject)\n    {\n        if ($search === '') {\n            return $subject;\n        }\n\n        $position = strpos($subject, $search);\n\n        if ($position !== false) {\n            return substr_replace($subject, $replace, $position, strlen($search));\n        }\n\n        return $subject;\n    }\n\n    /**\n     * Replace the last occurrence of a given value in the string.\n     *\n     * @param  string  $search\n     * @param  string  $replace\n     * @param  string  $subject\n     * @return string\n     */\n    public static function replaceLast($search, $replace, $subject)\n    {\n        if ($search === '') {\n            return $subject;\n        }\n\n        $position = strrpos($subject, $search);\n\n        if ($position !== false) {\n            return substr_replace($subject, $replace, $position, strlen($search));\n        }\n\n        return $subject;\n    }\n\n    /**\n     * Remove any occurrence of the given string in the subject.\n     *\n     * @param  string|array<string>  $search\n     * @param  string  $subject\n     * @param  bool  $caseSensitive\n     * @return string\n     */\n    public static function remove($search, $subject, $caseSensitive = true)\n    {\n        $subject = $caseSensitive\n                    ? str_replace($search, '', $subject)\n                    : str_ireplace($search, '', $subject);\n\n        return $subject;\n    }\n\n    /**\n     * Reverse the given string.\n     *\n     * @param  string  $value\n     * @return string\n     */\n    public static function reverse(string $value)\n    {\n        return implode(array_reverse(mb_str_split($value)));\n    }\n\n    /**\n     * Begin a string with a single instance of a given value.\n     *\n     * @param  string  $value\n     * @param  string  $prefix\n     * @return string\n     */\n    public static function start($value, $prefix)\n    {\n        $quoted = preg_quote($prefix, '/');\n\n        return $prefix.preg_replace('/^(?:'.$quoted.')+/u', '', $value);\n    }\n\n    /**\n     * Convert the given string to upper-case.\n     *\n     * @param  string  $value\n     * @return string\n     */\n    public static function upper($value)\n    {\n        return mb_strtoupper($value, 'UTF-8');\n    }\n\n    /**\n     * Convert the given string to title case.\n     *\n     * @param  string  $value\n     * @return string\n     */\n    public static function title($value)\n    {\n        return mb_convert_case($value, MB_CASE_TITLE, 'UTF-8');\n    }\n\n    /**\n     * Convert the given string to title case for each word.\n     *\n     * @param  string  $value\n     * @return string\n     */\n    public static function headline($value)\n    {\n        $parts = explode(' ', $value);\n\n        $parts = count($parts) > 1\n            ? $parts = array_map([static::class, 'title'], $parts)\n            : $parts = array_map([static::class, 'title'], static::ucsplit(implode('_', $parts)));\n\n        $collapsed = static::replace(['-', '_', ' '], '_', implode('_', $parts));\n\n        return implode(' ', array_filter(explode('_', $collapsed)));\n    }\n\n    /**\n     * Get the singular form of an English word.\n     *\n     * @param  string  $value\n     * @return string\n     */\n    public static function singular($value)\n    {\n        return Pluralizer::singular($value);\n    }\n\n    /**\n     * Generate a URL friendly \"slug\" from a given string.\n     *\n     * @param  string  $title\n     * @param  string  $separator\n     * @param  string|null  $language\n     * @return string\n     */\n    public static function slug($title, $separator = '-', $language = 'en')\n    {\n        $title = $language ? static::ascii($title, $language) : $title;\n\n        // Convert all dashes/underscores into separator\n        $flip = $separator === '-' ? '_' : '-';\n\n        $title = preg_replace('!['.preg_quote($flip).']+!u', $separator, $title);\n\n        // Replace @ with the word 'at'\n        $title = str_replace('@', $separator.'at'.$separator, $title);\n\n        // Remove all characters that are not the separator, letters, numbers, or whitespace.\n        $title = preg_replace('![^'.preg_quote($separator).'\\pL\\pN\\s]+!u', '', static::lower($title));\n\n        // Replace all separator characters and whitespace by a single separator\n        $title = preg_replace('!['.preg_quote($separator).'\\s]+!u', $separator, $title);\n\n        return trim($title, $separator);\n    }\n\n    /**\n     * Convert a string to snake case.\n     *\n     * @param  string  $value\n     * @param  string  $delimiter\n     * @return string\n     */\n    public static function snake($value, $delimiter = '_')\n    {\n        $key = $value;\n\n        if (isset(static::$snakeCache[$key][$delimiter])) {\n            return static::$snakeCache[$key][$delimiter];\n        }\n\n        if (! ctype_lower($value)) {\n            $value = preg_replace('/\\s+/u', '', ucwords($value));\n\n            $value = static::lower(preg_replace('/(.)(?=[A-Z])/u', '$1'.$delimiter, $value));\n        }\n\n        return static::$snakeCache[$key][$delimiter] = $value;\n    }\n\n    /**\n     * Determine if a given string starts with a given substring.\n     *\n     * @param  string  $haystack\n     * @param  string|string[]  $needles\n     * @return bool\n     */\n    public static function startsWith($haystack, $needles)\n    {\n        foreach ((array) $needles as $needle) {\n            if ((string) $needle !== '' && strncmp($haystack, $needle, strlen($needle)) === 0) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * Convert a value to studly caps case.\n     *\n     * @param  string  $value\n     * @return string\n     */\n    public static function studly($value)\n    {\n        $key = $value;\n\n        if (isset(static::$studlyCache[$key])) {\n            return static::$studlyCache[$key];\n        }\n\n        $words = explode(' ', static::replace(['-', '_'], ' ', $value));\n\n        $studlyWords = array_map(function ($word) {\n            return static::ucfirst($word);\n        }, $words);\n\n        return static::$studlyCache[$key] = implode($studlyWords);\n    }\n\n    /**\n     * Returns the portion of the string specified by the start and length parameters.\n     *\n     * @param  string  $string\n     * @param  int  $start\n     * @param  int|null  $length\n     * @return string\n     */\n    public static function substr($string, $start, $length = null)\n    {\n        return mb_substr($string, $start, $length, 'UTF-8');\n    }\n\n    /**\n     * Returns the number of substring occurrences.\n     *\n     * @param  string  $haystack\n     * @param  string  $needle\n     * @param  int  $offset\n     * @param  int|null  $length\n     * @return int\n     */\n    public static function substrCount($haystack, $needle, $offset = 0, $length = null)\n    {\n        if (! is_null($length)) {\n            return substr_count($haystack, $needle, $offset, $length);\n        } else {\n            return substr_count($haystack, $needle, $offset);\n        }\n    }\n\n    /**\n     * Replace text within a portion of a string.\n     *\n     * @param  string|array  $string\n     * @param  string|array  $replace\n     * @param  array|int  $offset\n     * @param  array|int|null  $length\n     * @return string|array\n     */\n    public static function substrReplace($string, $replace, $offset = 0, $length = null)\n    {\n        if ($length === null) {\n            $length = strlen($string);\n        }\n\n        return substr_replace($string, $replace, $offset, $length);\n    }\n\n    /**\n     * Swap multiple keywords in a string with other keywords.\n     *\n     * @param  array  $map\n     * @param  string  $subject\n     * @return string\n     */\n    public static function swap(array $map, $subject)\n    {\n        return strtr($subject, $map);\n    }\n\n    /**\n     * Make a string's first character uppercase.\n     *\n     * @param  string  $string\n     * @return string\n     */\n    public static function ucfirst($string)\n    {\n        return static::upper(static::substr($string, 0, 1)).static::substr($string, 1);\n    }\n\n    /**\n     * Split a string into pieces by uppercase characters.\n     *\n     * @param  string  $string\n     * @return array\n     */\n    public static function ucsplit($string)\n    {\n        return preg_split('/(?=\\p{Lu})/u', $string, -1, PREG_SPLIT_NO_EMPTY);\n    }\n\n    /**\n     * Get the number of words a string contains.\n     *\n     * @param  string  $string\n     * @return int\n     */\n    public static function wordCount($string)\n    {\n        return str_word_count($string);\n    }\n\n    /**\n     * Generate a UUID (version 4).\n     *\n     * @return \\Ramsey\\Uuid\\UuidInterface\n     */\n    public static function uuid()\n    {\n        return static::$uuidFactory\n                    ? call_user_func(static::$uuidFactory)\n                    : Uuid::uuid4();\n    }\n\n    /**\n     * Generate a time-ordered UUID (version 4).\n     *\n     * @return \\Ramsey\\Uuid\\UuidInterface\n     */\n    public static function orderedUuid()\n    {\n        if (static::$uuidFactory) {\n            return call_user_func(static::$uuidFactory);\n        }\n\n        $factory = new UuidFactory;\n\n        $factory->setRandomGenerator(new CombGenerator(\n            $factory->getRandomGenerator(),\n            $factory->getNumberConverter()\n        ));\n\n        $factory->setCodec(new TimestampFirstCombCodec(\n            $factory->getUuidBuilder()\n        ));\n\n        return $factory->uuid4();\n    }\n\n    /**\n     * Set the callable that will be used to generate UUIDs.\n     *\n     * @param  callable|null  $factory\n     * @return void\n     */\n    public static function createUuidsUsing(callable $factory = null)\n    {\n        static::$uuidFactory = $factory;\n    }\n\n    /**\n     * Indicate that UUIDs should be created normally and not using a custom factory.\n     *\n     * @return void\n     */\n    public static function createUuidsNormally()\n    {\n        static::$uuidFactory = null;\n    }\n\n    /**\n     * Remove all strings from the casing caches.\n     *\n     * @return void\n     */\n    public static function flushCache()\n    {\n        static::$snakeCache = [];\n        static::$camelCache = [];\n        static::$studlyCache = [];\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Stringable.php",
    "content": "<?php\n\nnamespace Illuminate\\Support;\n\nuse Closure;\nuse Illuminate\\Support\\Traits\\Conditionable;\nuse Illuminate\\Support\\Traits\\Macroable;\nuse Illuminate\\Support\\Traits\\Tappable;\nuse JsonSerializable;\nuse Symfony\\Component\\VarDumper\\VarDumper;\n\nclass Stringable implements JsonSerializable\n{\n    use Conditionable, Macroable, Tappable;\n\n    /**\n     * The underlying string value.\n     *\n     * @var string\n     */\n    protected $value;\n\n    /**\n     * Create a new instance of the class.\n     *\n     * @param  string  $value\n     * @return void\n     */\n    public function __construct($value = '')\n    {\n        $this->value = (string) $value;\n    }\n\n    /**\n     * Return the remainder of a string after the first occurrence of a given value.\n     *\n     * @param  string  $search\n     * @return static\n     */\n    public function after($search)\n    {\n        return new static(Str::after($this->value, $search));\n    }\n\n    /**\n     * Return the remainder of a string after the last occurrence of a given value.\n     *\n     * @param  string  $search\n     * @return static\n     */\n    public function afterLast($search)\n    {\n        return new static(Str::afterLast($this->value, $search));\n    }\n\n    /**\n     * Append the given values to the string.\n     *\n     * @param  array  $values\n     * @return static\n     */\n    public function append(...$values)\n    {\n        return new static($this->value.implode('', $values));\n    }\n\n    /**\n     * Transliterate a UTF-8 value to ASCII.\n     *\n     * @param  string  $language\n     * @return static\n     */\n    public function ascii($language = 'en')\n    {\n        return new static(Str::ascii($this->value, $language));\n    }\n\n    /**\n     * Get the trailing name component of the path.\n     *\n     * @param  string  $suffix\n     * @return static\n     */\n    public function basename($suffix = '')\n    {\n        return new static(basename($this->value, $suffix));\n    }\n\n    /**\n     * Get the basename of the class path.\n     *\n     * @return static\n     */\n    public function classBasename()\n    {\n        return new static(class_basename($this->value));\n    }\n\n    /**\n     * Get the portion of a string before the first occurrence of a given value.\n     *\n     * @param  string  $search\n     * @return static\n     */\n    public function before($search)\n    {\n        return new static(Str::before($this->value, $search));\n    }\n\n    /**\n     * Get the portion of a string before the last occurrence of a given value.\n     *\n     * @param  string  $search\n     * @return static\n     */\n    public function beforeLast($search)\n    {\n        return new static(Str::beforeLast($this->value, $search));\n    }\n\n    /**\n     * Get the portion of a string between two given values.\n     *\n     * @param  string  $from\n     * @param  string  $to\n     * @return static\n     */\n    public function between($from, $to)\n    {\n        return new static(Str::between($this->value, $from, $to));\n    }\n\n    /**\n     * Convert a value to camel case.\n     *\n     * @return static\n     */\n    public function camel()\n    {\n        return new static(Str::camel($this->value));\n    }\n\n    /**\n     * Determine if a given string contains a given substring.\n     *\n     * @param  string|array  $needles\n     * @return bool\n     */\n    public function contains($needles)\n    {\n        return Str::contains($this->value, $needles);\n    }\n\n    /**\n     * Determine if a given string contains all array values.\n     *\n     * @param  array  $needles\n     * @return bool\n     */\n    public function containsAll(array $needles)\n    {\n        return Str::containsAll($this->value, $needles);\n    }\n\n    /**\n     * Get the parent directory's path.\n     *\n     * @param  int  $levels\n     * @return static\n     */\n    public function dirname($levels = 1)\n    {\n        return new static(dirname($this->value, $levels));\n    }\n\n    /**\n     * Determine if a given string ends with a given substring.\n     *\n     * @param  string|array  $needles\n     * @return bool\n     */\n    public function endsWith($needles)\n    {\n        return Str::endsWith($this->value, $needles);\n    }\n\n    /**\n     * Determine if the string is an exact match with the given value.\n     *\n     * @param  string  $value\n     * @return bool\n     */\n    public function exactly($value)\n    {\n        return $this->value === $value;\n    }\n\n    /**\n     * Explode the string into an array.\n     *\n     * @param  string  $delimiter\n     * @param  int  $limit\n     * @return \\Illuminate\\Support\\Collection\n     */\n    public function explode($delimiter, $limit = PHP_INT_MAX)\n    {\n        return collect(explode($delimiter, $this->value, $limit));\n    }\n\n    /**\n     * Split a string using a regular expression or by length.\n     *\n     * @param  string|int  $pattern\n     * @param  int  $limit\n     * @param  int  $flags\n     * @return \\Illuminate\\Support\\Collection\n     */\n    public function split($pattern, $limit = -1, $flags = 0)\n    {\n        if (filter_var($pattern, FILTER_VALIDATE_INT) !== false) {\n            return collect(mb_str_split($this->value, $pattern));\n        }\n\n        $segments = preg_split($pattern, $this->value, $limit, $flags);\n\n        return ! empty($segments) ? collect($segments) : collect();\n    }\n\n    /**\n     * Cap a string with a single instance of a given value.\n     *\n     * @param  string  $cap\n     * @return static\n     */\n    public function finish($cap)\n    {\n        return new static(Str::finish($this->value, $cap));\n    }\n\n    /**\n     * Determine if a given string matches a given pattern.\n     *\n     * @param  string|array  $pattern\n     * @return bool\n     */\n    public function is($pattern)\n    {\n        return Str::is($pattern, $this->value);\n    }\n\n    /**\n     * Determine if a given string is 7 bit ASCII.\n     *\n     * @return bool\n     */\n    public function isAscii()\n    {\n        return Str::isAscii($this->value);\n    }\n\n    /**\n     * Determine if a given string is a valid UUID.\n     *\n     * @return bool\n     */\n    public function isUuid()\n    {\n        return Str::isUuid($this->value);\n    }\n\n    /**\n     * Determine if the given string is empty.\n     *\n     * @return bool\n     */\n    public function isEmpty()\n    {\n        return $this->value === '';\n    }\n\n    /**\n     * Determine if the given string is not empty.\n     *\n     * @return bool\n     */\n    public function isNotEmpty()\n    {\n        return ! $this->isEmpty();\n    }\n\n    /**\n     * Convert a string to kebab case.\n     *\n     * @return static\n     */\n    public function kebab()\n    {\n        return new static(Str::kebab($this->value));\n    }\n\n    /**\n     * Return the length of the given string.\n     *\n     * @param  string  $encoding\n     * @return int\n     */\n    public function length($encoding = null)\n    {\n        return Str::length($this->value, $encoding);\n    }\n\n    /**\n     * Limit the number of characters in a string.\n     *\n     * @param  int  $limit\n     * @param  string  $end\n     * @return static\n     */\n    public function limit($limit = 100, $end = '...')\n    {\n        return new static(Str::limit($this->value, $limit, $end));\n    }\n\n    /**\n     * Convert the given string to lower-case.\n     *\n     * @return static\n     */\n    public function lower()\n    {\n        return new static(Str::lower($this->value));\n    }\n\n    /**\n     * Convert GitHub flavored Markdown into HTML.\n     *\n     * @param  array  $options\n     * @return static\n     */\n    public function markdown(array $options = [])\n    {\n        return new static(Str::markdown($this->value, $options));\n    }\n\n    /**\n     * Masks a portion of a string with a repeated character.\n     *\n     * @param  string  $character\n     * @param  int  $index\n     * @param  int|null  $length\n     * @param  string  $encoding\n     * @return static\n     */\n    public function mask($character, $index, $length = null, $encoding = 'UTF-8')\n    {\n        return new static(Str::mask($this->value, $character, $index, $length, $encoding));\n    }\n\n    /**\n     * Get the string matching the given pattern.\n     *\n     * @param  string  $pattern\n     * @return static\n     */\n    public function match($pattern)\n    {\n        return new static(Str::match($pattern, $this->value));\n    }\n\n    /**\n     * Get the string matching the given pattern.\n     *\n     * @param  string  $pattern\n     * @return \\Illuminate\\Support\\Collection\n     */\n    public function matchAll($pattern)\n    {\n        return Str::matchAll($pattern, $this->value);\n    }\n\n    /**\n     * Determine if the string matches the given pattern.\n     *\n     * @param  string  $pattern\n     * @return bool\n     */\n    public function test($pattern)\n    {\n        return $this->match($pattern)->isNotEmpty();\n    }\n\n    /**\n     * Pad both sides of the string with another.\n     *\n     * @param  int  $length\n     * @param  string  $pad\n     * @return static\n     */\n    public function padBoth($length, $pad = ' ')\n    {\n        return new static(Str::padBoth($this->value, $length, $pad));\n    }\n\n    /**\n     * Pad the left side of the string with another.\n     *\n     * @param  int  $length\n     * @param  string  $pad\n     * @return static\n     */\n    public function padLeft($length, $pad = ' ')\n    {\n        return new static(Str::padLeft($this->value, $length, $pad));\n    }\n\n    /**\n     * Pad the right side of the string with another.\n     *\n     * @param  int  $length\n     * @param  string  $pad\n     * @return static\n     */\n    public function padRight($length, $pad = ' ')\n    {\n        return new static(Str::padRight($this->value, $length, $pad));\n    }\n\n    /**\n     * Parse a Class@method style callback into class and method.\n     *\n     * @param  string|null  $default\n     * @return array\n     */\n    public function parseCallback($default = null)\n    {\n        return Str::parseCallback($this->value, $default);\n    }\n\n    /**\n     * Call the given callback and return a new string.\n     *\n     * @param  callable  $callback\n     * @return static\n     */\n    public function pipe(callable $callback)\n    {\n        return new static(call_user_func($callback, $this));\n    }\n\n    /**\n     * Get the plural form of an English word.\n     *\n     * @param  int  $count\n     * @return static\n     */\n    public function plural($count = 2)\n    {\n        return new static(Str::plural($this->value, $count));\n    }\n\n    /**\n     * Pluralize the last word of an English, studly caps case string.\n     *\n     * @param  int  $count\n     * @return static\n     */\n    public function pluralStudly($count = 2)\n    {\n        return new static(Str::pluralStudly($this->value, $count));\n    }\n\n    /**\n     * Prepend the given values to the string.\n     *\n     * @param  array  $values\n     * @return static\n     */\n    public function prepend(...$values)\n    {\n        return new static(implode('', $values).$this->value);\n    }\n\n    /**\n     * Remove any occurrence of the given string in the subject.\n     *\n     * @param  string|array<string>  $search\n     * @param  bool  $caseSensitive\n     * @return static\n     */\n    public function remove($search, $caseSensitive = true)\n    {\n        return new static(Str::remove($search, $this->value, $caseSensitive));\n    }\n\n    /**\n     * Reverse the string.\n     *\n     * @return static\n     */\n    public function reverse()\n    {\n        return new static(Str::reverse($this->value));\n    }\n\n    /**\n     * Repeat the string.\n     *\n     * @param  int  $times\n     * @return static\n     */\n    public function repeat(int $times)\n    {\n        return new static(Str::repeat($this->value, $times));\n    }\n\n    /**\n     * Replace the given value in the given string.\n     *\n     * @param  string|string[]  $search\n     * @param  string|string[]  $replace\n     * @return static\n     */\n    public function replace($search, $replace)\n    {\n        return new static(Str::replace($search, $replace, $this->value));\n    }\n\n    /**\n     * Replace a given value in the string sequentially with an array.\n     *\n     * @param  string  $search\n     * @param  array  $replace\n     * @return static\n     */\n    public function replaceArray($search, array $replace)\n    {\n        return new static(Str::replaceArray($search, $replace, $this->value));\n    }\n\n    /**\n     * Replace the first occurrence of a given value in the string.\n     *\n     * @param  string  $search\n     * @param  string  $replace\n     * @return static\n     */\n    public function replaceFirst($search, $replace)\n    {\n        return new static(Str::replaceFirst($search, $replace, $this->value));\n    }\n\n    /**\n     * Replace the last occurrence of a given value in the string.\n     *\n     * @param  string  $search\n     * @param  string  $replace\n     * @return static\n     */\n    public function replaceLast($search, $replace)\n    {\n        return new static(Str::replaceLast($search, $replace, $this->value));\n    }\n\n    /**\n     * Replace the patterns matching the given regular expression.\n     *\n     * @param  string  $pattern\n     * @param  \\Closure|string  $replace\n     * @param  int  $limit\n     * @return static\n     */\n    public function replaceMatches($pattern, $replace, $limit = -1)\n    {\n        if ($replace instanceof Closure) {\n            return new static(preg_replace_callback($pattern, $replace, $this->value, $limit));\n        }\n\n        return new static(preg_replace($pattern, $replace, $this->value, $limit));\n    }\n\n    /**\n     * Parse input from a string to a collection, according to a format.\n     *\n     * @param  string  $format\n     * @return \\Illuminate\\Support\\Collection\n     */\n    public function scan($format)\n    {\n        return collect(sscanf($this->value, $format));\n    }\n\n    /**\n     * Begin a string with a single instance of a given value.\n     *\n     * @param  string  $prefix\n     * @return static\n     */\n    public function start($prefix)\n    {\n        return new static(Str::start($this->value, $prefix));\n    }\n\n    /**\n     * Strip HTML and PHP tags from the given string.\n     *\n     * @param  string  $allowedTags\n     * @return static\n     */\n    public function stripTags($allowedTags = null)\n    {\n        return new static(strip_tags($this->value, $allowedTags));\n    }\n\n    /**\n     * Convert the given string to upper-case.\n     *\n     * @return static\n     */\n    public function upper()\n    {\n        return new static(Str::upper($this->value));\n    }\n\n    /**\n     * Convert the given string to title case.\n     *\n     * @return static\n     */\n    public function title()\n    {\n        return new static(Str::title($this->value));\n    }\n\n    /**\n     * Convert the given string to title case for each word.\n     *\n     * @return static\n     */\n    public function headline()\n    {\n        return new static(Str::headline($this->value));\n    }\n\n    /**\n     * Get the singular form of an English word.\n     *\n     * @return static\n     */\n    public function singular()\n    {\n        return new static(Str::singular($this->value));\n    }\n\n    /**\n     * Generate a URL friendly \"slug\" from a given string.\n     *\n     * @param  string  $separator\n     * @param  string|null  $language\n     * @return static\n     */\n    public function slug($separator = '-', $language = 'en')\n    {\n        return new static(Str::slug($this->value, $separator, $language));\n    }\n\n    /**\n     * Convert a string to snake case.\n     *\n     * @param  string  $delimiter\n     * @return static\n     */\n    public function snake($delimiter = '_')\n    {\n        return new static(Str::snake($this->value, $delimiter));\n    }\n\n    /**\n     * Determine if a given string starts with a given substring.\n     *\n     * @param  string|array  $needles\n     * @return bool\n     */\n    public function startsWith($needles)\n    {\n        return Str::startsWith($this->value, $needles);\n    }\n\n    /**\n     * Convert a value to studly caps case.\n     *\n     * @return static\n     */\n    public function studly()\n    {\n        return new static(Str::studly($this->value));\n    }\n\n    /**\n     * Returns the portion of the string specified by the start and length parameters.\n     *\n     * @param  int  $start\n     * @param  int|null  $length\n     * @return static\n     */\n    public function substr($start, $length = null)\n    {\n        return new static(Str::substr($this->value, $start, $length));\n    }\n\n    /**\n     * Returns the number of substring occurrences.\n     *\n     * @param  string  $needle\n     * @param  int|null  $offset\n     * @param  int|null  $length\n     * @return int\n     */\n    public function substrCount($needle, $offset = null, $length = null)\n    {\n        return Str::substrCount($this->value, $needle, $offset ?? 0, $length);\n    }\n\n    /**\n     * Replace text within a portion of a string.\n     *\n     * @param  string|array  $replace\n     * @param  array|int  $offset\n     * @param  array|int|null  $length\n     * @return static\n     */\n    public function substrReplace($replace, $offset = 0, $length = null)\n    {\n        return new static(Str::substrReplace($this->value, $replace, $offset, $length));\n    }\n\n    /**\n     * Swap multiple keywords in a string with other keywords.\n     *\n     * @param  array  $map\n     * @return static\n     */\n    public function swap(array $map)\n    {\n        return new static(strtr($this->value, $map));\n    }\n\n    /**\n     * Trim the string of the given characters.\n     *\n     * @param  string  $characters\n     * @return static\n     */\n    public function trim($characters = null)\n    {\n        return new static(trim(...array_merge([$this->value], func_get_args())));\n    }\n\n    /**\n     * Left trim the string of the given characters.\n     *\n     * @param  string  $characters\n     * @return static\n     */\n    public function ltrim($characters = null)\n    {\n        return new static(ltrim(...array_merge([$this->value], func_get_args())));\n    }\n\n    /**\n     * Right trim the string of the given characters.\n     *\n     * @param  string  $characters\n     * @return static\n     */\n    public function rtrim($characters = null)\n    {\n        return new static(rtrim(...array_merge([$this->value], func_get_args())));\n    }\n\n    /**\n     * Make a string's first character uppercase.\n     *\n     * @return static\n     */\n    public function ucfirst()\n    {\n        return new static(Str::ucfirst($this->value));\n    }\n\n    /**\n     * Split a string by uppercase characters.\n     *\n     * @return \\Illuminate\\Support\\Collection\n     */\n    public function ucsplit()\n    {\n        return collect(Str::ucsplit($this->value));\n    }\n\n    /**\n     * Execute the given callback if the string contains a given substring.\n     *\n     * @param  string|array  $needles\n     * @param  callable  $callback\n     * @param  callable|null  $default\n     * @return static\n     */\n    public function whenContains($needles, $callback, $default = null)\n    {\n        return $this->when($this->contains($needles), $callback, $default);\n    }\n\n    /**\n     * Execute the given callback if the string contains all array values.\n     *\n     * @param  array  $needles\n     * @param  callable  $callback\n     * @param  callable|null  $default\n     * @return static\n     */\n    public function whenContainsAll(array $needles, $callback, $default = null)\n    {\n        return $this->when($this->containsAll($needles), $callback, $default);\n    }\n\n    /**\n     * Execute the given callback if the string is empty.\n     *\n     * @param  callable  $callback\n     * @param  callable|null  $default\n     * @return static\n     */\n    public function whenEmpty($callback, $default = null)\n    {\n        return $this->when($this->isEmpty(), $callback, $default);\n    }\n\n    /**\n     * Execute the given callback if the string is not empty.\n     *\n     * @param  callable  $callback\n     * @param  callable|null  $default\n     * @return static\n     */\n    public function whenNotEmpty($callback, $default = null)\n    {\n        return $this->when($this->isNotEmpty(), $callback, $default);\n    }\n\n    /**\n     * Execute the given callback if the string ends with a given substring.\n     *\n     * @param  string|array  $needles\n     * @param  callable  $callback\n     * @param  callable|null  $default\n     * @return static\n     */\n    public function whenEndsWith($needles, $callback, $default = null)\n    {\n        return $this->when($this->endsWith($needles), $callback, $default);\n    }\n\n    /**\n     * Execute the given callback if the string is an exact match with the given value.\n     *\n     * @param  string  $value\n     * @param  callable  $callback\n     * @param  callable|null  $default\n     * @return static\n     */\n    public function whenExactly($value, $callback, $default = null)\n    {\n        return $this->when($this->exactly($value), $callback, $default);\n    }\n\n    /**\n     * Execute the given callback if the string matches a given pattern.\n     *\n     * @param  string|array  $pattern\n     * @param  callable  $callback\n     * @param  callable|null  $default\n     * @return static\n     */\n    public function whenIs($pattern, $callback, $default = null)\n    {\n        return $this->when($this->is($pattern), $callback, $default);\n    }\n\n    /**\n     * Execute the given callback if the string is 7 bit ASCII.\n     *\n     * @param  callable  $callback\n     * @param  callable|null  $default\n     * @return static\n     */\n    public function whenIsAscii($callback, $default = null)\n    {\n        return $this->when($this->isAscii(), $callback, $default);\n    }\n\n    /**\n     * Execute the given callback if the string is a valid UUID.\n     *\n     * @param  callable  $callback\n     * @param  callable|null  $default\n     * @return static\n     */\n    public function whenIsUuid($callback, $default = null)\n    {\n        return $this->when($this->isUuid(), $callback, $default);\n    }\n\n    /**\n     * Execute the given callback if the string starts with a given substring.\n     *\n     * @param  string|array  $needles\n     * @param  callable  $callback\n     * @param  callable|null  $default\n     * @return static\n     */\n    public function whenStartsWith($needles, $callback, $default = null)\n    {\n        return $this->when($this->startsWith($needles), $callback, $default);\n    }\n\n    /**\n     * Execute the given callback if the string matches the given pattern.\n     *\n     * @param  string  $pattern\n     * @param  callable  $callback\n     * @param  callable|null  $default\n     * @return static\n     */\n    public function whenTest($pattern, $callback, $default = null)\n    {\n        return $this->when($this->test($pattern), $callback, $default);\n    }\n\n    /**\n     * Limit the number of words in a string.\n     *\n     * @param  int  $words\n     * @param  string  $end\n     * @return static\n     */\n    public function words($words = 100, $end = '...')\n    {\n        return new static(Str::words($this->value, $words, $end));\n    }\n\n    /**\n     * Get the number of words a string contains.\n     *\n     * @return int\n     */\n    public function wordCount()\n    {\n        return str_word_count($this->value);\n    }\n\n    /**\n     * Convert the string into a `HtmlString` instance.\n     *\n     * @return \\Illuminate\\Support\\HtmlString\n     */\n    public function toHtmlString()\n    {\n        return new HtmlString($this->value);\n    }\n\n    /**\n     * Dump the string.\n     *\n     * @return $this\n     */\n    public function dump()\n    {\n        VarDumper::dump($this->value);\n\n        return $this;\n    }\n\n    /**\n     * Dump the string and end the script.\n     *\n     * @return never\n     */\n    public function dd()\n    {\n        $this->dump();\n\n        exit(1);\n    }\n\n    /**\n     * Convert the object to a string when JSON encoded.\n     *\n     * @return string\n     */\n    #[\\ReturnTypeWillChange]\n    public function jsonSerialize()\n    {\n        return $this->__toString();\n    }\n\n    /**\n     * Proxy dynamic properties onto methods.\n     *\n     * @param  string  $key\n     * @return mixed\n     */\n    public function __get($key)\n    {\n        return $this->{$key}();\n    }\n\n    /**\n     * Get the raw string value.\n     *\n     * @return string\n     */\n    public function __toString()\n    {\n        return (string) $this->value;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Testing/Fakes/BatchRepositoryFake.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Testing\\Fakes;\n\nuse Carbon\\CarbonImmutable;\nuse Closure;\nuse Illuminate\\Bus\\Batch;\nuse Illuminate\\Bus\\BatchRepository;\nuse Illuminate\\Bus\\PendingBatch;\nuse Illuminate\\Bus\\UpdatedBatchJobCounts;\nuse Illuminate\\Support\\Facades\\Facade;\nuse Illuminate\\Support\\Str;\n\nclass BatchRepositoryFake implements BatchRepository\n{\n    /**\n     * Retrieve a list of batches.\n     *\n     * @param  int  $limit\n     * @param  mixed  $before\n     * @return \\Illuminate\\Bus\\Batch[]\n     */\n    public function get($limit, $before)\n    {\n        return [];\n    }\n\n    /**\n     * Retrieve information about an existing batch.\n     *\n     * @param  string  $batchId\n     * @return \\Illuminate\\Bus\\Batch|null\n     */\n    public function find(string $batchId)\n    {\n        //\n    }\n\n    /**\n     * Store a new pending batch.\n     *\n     * @param  \\Illuminate\\Bus\\PendingBatch  $batch\n     * @return \\Illuminate\\Bus\\Batch\n     */\n    public function store(PendingBatch $batch)\n    {\n        return new Batch(\n            new QueueFake(Facade::getFacadeApplication()),\n            $this,\n            (string) Str::orderedUuid(),\n            $batch->name,\n            count($batch->jobs),\n            count($batch->jobs),\n            0,\n            [],\n            $batch->options,\n            CarbonImmutable::now(),\n            null,\n            null\n        );\n    }\n\n    /**\n     * Increment the total number of jobs within the batch.\n     *\n     * @param  string  $batchId\n     * @param  int  $amount\n     * @return void\n     */\n    public function incrementTotalJobs(string $batchId, int $amount)\n    {\n        //\n    }\n\n    /**\n     * Decrement the total number of pending jobs for the batch.\n     *\n     * @param  string  $batchId\n     * @param  string  $jobId\n     * @return \\Illuminate\\Bus\\UpdatedBatchJobCounts\n     */\n    public function decrementPendingJobs(string $batchId, string $jobId)\n    {\n        return new UpdatedBatchJobCounts;\n    }\n\n    /**\n     * Increment the total number of failed jobs for the batch.\n     *\n     * @param  string  $batchId\n     * @param  string  $jobId\n     * @return \\Illuminate\\Bus\\UpdatedBatchJobCounts\n     */\n    public function incrementFailedJobs(string $batchId, string $jobId)\n    {\n        return new UpdatedBatchJobCounts;\n    }\n\n    /**\n     * Mark the batch that has the given ID as finished.\n     *\n     * @param  string  $batchId\n     * @return void\n     */\n    public function markAsFinished(string $batchId)\n    {\n        //\n    }\n\n    /**\n     * Cancel the batch that has the given ID.\n     *\n     * @param  string  $batchId\n     * @return void\n     */\n    public function cancel(string $batchId)\n    {\n        //\n    }\n\n    /**\n     * Delete the batch that has the given ID.\n     *\n     * @param  string  $batchId\n     * @return void\n     */\n    public function delete(string $batchId)\n    {\n        //\n    }\n\n    /**\n     * Execute the given Closure within a storage specific transaction.\n     *\n     * @param  \\Closure  $callback\n     * @return mixed\n     */\n    public function transaction(Closure $callback)\n    {\n        return $callback();\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Testing/Fakes/BusFake.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Testing\\Fakes;\n\nuse Closure;\nuse Illuminate\\Bus\\PendingBatch;\nuse Illuminate\\Contracts\\Bus\\QueueingDispatcher;\nuse Illuminate\\Support\\Arr;\nuse Illuminate\\Support\\Collection;\nuse Illuminate\\Support\\Traits\\ReflectsClosures;\nuse PHPUnit\\Framework\\Assert as PHPUnit;\n\nclass BusFake implements QueueingDispatcher\n{\n    use ReflectsClosures;\n\n    /**\n     * The original Bus dispatcher implementation.\n     *\n     * @var \\Illuminate\\Contracts\\Bus\\QueueingDispatcher\n     */\n    protected $dispatcher;\n\n    /**\n     * The job types that should be intercepted instead of dispatched.\n     *\n     * @var array\n     */\n    protected $jobsToFake;\n\n    /**\n     * The commands that have been dispatched.\n     *\n     * @var array\n     */\n    protected $commands = [];\n\n    /**\n     * The commands that have been dispatched synchronously.\n     *\n     * @var array\n     */\n    protected $commandsSync = [];\n\n    /**\n     * The commands that have been dispatched after the response has been sent.\n     *\n     * @var array\n     */\n    protected $commandsAfterResponse = [];\n\n    /**\n     * The batches that have been dispatched.\n     *\n     * @var array\n     */\n    protected $batches = [];\n\n    /**\n     * Create a new bus fake instance.\n     *\n     * @param  \\Illuminate\\Contracts\\Bus\\QueueingDispatcher  $dispatcher\n     * @param  array|string  $jobsToFake\n     * @return void\n     */\n    public function __construct(QueueingDispatcher $dispatcher, $jobsToFake = [])\n    {\n        $this->dispatcher = $dispatcher;\n\n        $this->jobsToFake = Arr::wrap($jobsToFake);\n    }\n\n    /**\n     * Assert if a job was dispatched based on a truth-test callback.\n     *\n     * @param  string|\\Closure  $command\n     * @param  callable|int|null  $callback\n     * @return void\n     */\n    public function assertDispatched($command, $callback = null)\n    {\n        if ($command instanceof Closure) {\n            [$command, $callback] = [$this->firstClosureParameterType($command), $command];\n        }\n\n        if (is_numeric($callback)) {\n            return $this->assertDispatchedTimes($command, $callback);\n        }\n\n        PHPUnit::assertTrue(\n            $this->dispatched($command, $callback)->count() > 0 ||\n            $this->dispatchedAfterResponse($command, $callback)->count() > 0 ||\n            $this->dispatchedSync($command, $callback)->count() > 0,\n            \"The expected [{$command}] job was not dispatched.\"\n        );\n    }\n\n    /**\n     * Assert if a job was pushed a number of times.\n     *\n     * @param  string  $command\n     * @param  int  $times\n     * @return void\n     */\n    public function assertDispatchedTimes($command, $times = 1)\n    {\n        $count = $this->dispatched($command)->count() +\n                 $this->dispatchedAfterResponse($command)->count() +\n                 $this->dispatchedSync($command)->count();\n\n        PHPUnit::assertSame(\n            $times, $count,\n            \"The expected [{$command}] job was pushed {$count} times instead of {$times} times.\"\n        );\n    }\n\n    /**\n     * Determine if a job was dispatched based on a truth-test callback.\n     *\n     * @param  string|\\Closure  $command\n     * @param  callable|null  $callback\n     * @return void\n     */\n    public function assertNotDispatched($command, $callback = null)\n    {\n        if ($command instanceof Closure) {\n            [$command, $callback] = [$this->firstClosureParameterType($command), $command];\n        }\n\n        PHPUnit::assertTrue(\n            $this->dispatched($command, $callback)->count() === 0 &&\n            $this->dispatchedAfterResponse($command, $callback)->count() === 0 &&\n            $this->dispatchedSync($command, $callback)->count() === 0,\n            \"The unexpected [{$command}] job was dispatched.\"\n        );\n    }\n\n    /**\n     * Assert that no jobs were dispatched.\n     *\n     * @return void\n     */\n    public function assertNothingDispatched()\n    {\n        PHPUnit::assertEmpty($this->commands, 'Jobs were dispatched unexpectedly.');\n    }\n\n    /**\n     * Assert if a job was explicitly dispatched synchronously based on a truth-test callback.\n     *\n     * @param  string|\\Closure  $command\n     * @param  callable|int|null  $callback\n     * @return void\n     */\n    public function assertDispatchedSync($command, $callback = null)\n    {\n        if ($command instanceof Closure) {\n            [$command, $callback] = [$this->firstClosureParameterType($command), $command];\n        }\n\n        if (is_numeric($callback)) {\n            return $this->assertDispatchedSyncTimes($command, $callback);\n        }\n\n        PHPUnit::assertTrue(\n            $this->dispatchedSync($command, $callback)->count() > 0,\n            \"The expected [{$command}] job was not dispatched synchronously.\"\n        );\n    }\n\n    /**\n     * Assert if a job was pushed synchronously a number of times.\n     *\n     * @param  string  $command\n     * @param  int  $times\n     * @return void\n     */\n    public function assertDispatchedSyncTimes($command, $times = 1)\n    {\n        $count = $this->dispatchedSync($command)->count();\n\n        PHPUnit::assertSame(\n            $times, $count,\n            \"The expected [{$command}] job was synchronously pushed {$count} times instead of {$times} times.\"\n        );\n    }\n\n    /**\n     * Determine if a job was dispatched based on a truth-test callback.\n     *\n     * @param  string|\\Closure  $command\n     * @param  callable|null  $callback\n     * @return void\n     */\n    public function assertNotDispatchedSync($command, $callback = null)\n    {\n        if ($command instanceof Closure) {\n            [$command, $callback] = [$this->firstClosureParameterType($command), $command];\n        }\n\n        PHPUnit::assertCount(\n            0, $this->dispatchedSync($command, $callback),\n            \"The unexpected [{$command}] job was dispatched synchronously.\"\n        );\n    }\n\n    /**\n     * Assert if a job was dispatched after the response was sent based on a truth-test callback.\n     *\n     * @param  string|\\Closure  $command\n     * @param  callable|int|null  $callback\n     * @return void\n     */\n    public function assertDispatchedAfterResponse($command, $callback = null)\n    {\n        if ($command instanceof Closure) {\n            [$command, $callback] = [$this->firstClosureParameterType($command), $command];\n        }\n\n        if (is_numeric($callback)) {\n            return $this->assertDispatchedAfterResponseTimes($command, $callback);\n        }\n\n        PHPUnit::assertTrue(\n            $this->dispatchedAfterResponse($command, $callback)->count() > 0,\n            \"The expected [{$command}] job was not dispatched after sending the response.\"\n        );\n    }\n\n    /**\n     * Assert if a job was pushed after the response was sent a number of times.\n     *\n     * @param  string  $command\n     * @param  int  $times\n     * @return void\n     */\n    public function assertDispatchedAfterResponseTimes($command, $times = 1)\n    {\n        $count = $this->dispatchedAfterResponse($command)->count();\n\n        PHPUnit::assertSame(\n            $times, $count,\n            \"The expected [{$command}] job was pushed {$count} times instead of {$times} times.\"\n        );\n    }\n\n    /**\n     * Determine if a job was dispatched based on a truth-test callback.\n     *\n     * @param  string|\\Closure  $command\n     * @param  callable|null  $callback\n     * @return void\n     */\n    public function assertNotDispatchedAfterResponse($command, $callback = null)\n    {\n        if ($command instanceof Closure) {\n            [$command, $callback] = [$this->firstClosureParameterType($command), $command];\n        }\n\n        PHPUnit::assertCount(\n            0, $this->dispatchedAfterResponse($command, $callback),\n            \"The unexpected [{$command}] job was dispatched after sending the response.\"\n        );\n    }\n\n    /**\n     * Assert if a chain of jobs was dispatched.\n     *\n     * @param  array  $expectedChain\n     * @return void\n     */\n    public function assertChained(array $expectedChain)\n    {\n        $command = $expectedChain[0];\n\n        $expectedChain = array_slice($expectedChain, 1);\n\n        $callback = null;\n\n        if ($command instanceof Closure) {\n            [$command, $callback] = [$this->firstClosureParameterType($command), $command];\n        } elseif (! is_string($command)) {\n            $instance = $command;\n\n            $command = get_class($instance);\n\n            $callback = function ($job) use ($instance) {\n                return serialize($this->resetChainPropertiesToDefaults($job)) === serialize($instance);\n            };\n        }\n\n        PHPUnit::assertTrue(\n            $this->dispatched($command, $callback)->isNotEmpty(),\n            \"The expected [{$command}] job was not dispatched.\"\n        );\n\n        PHPUnit::assertTrue(\n            collect($expectedChain)->isNotEmpty(),\n            'The expected chain can not be empty.'\n        );\n\n        $this->isChainOfObjects($expectedChain)\n            ? $this->assertDispatchedWithChainOfObjects($command, $expectedChain, $callback)\n            : $this->assertDispatchedWithChainOfClasses($command, $expectedChain, $callback);\n    }\n\n    /**\n     * Reset the chain properties to their default values on the job.\n     *\n     * @param  mixed  $job\n     * @return mixed\n     */\n    protected function resetChainPropertiesToDefaults($job)\n    {\n        return tap(clone $job, function ($job) {\n            $job->chainConnection = null;\n            $job->chainQueue = null;\n            $job->chainCatchCallbacks = null;\n            $job->chained = [];\n        });\n    }\n\n    /**\n     * Assert if a job was dispatched with an empty chain based on a truth-test callback.\n     *\n     * @param  string|\\Closure  $command\n     * @param  callable|null  $callback\n     * @return void\n     */\n    public function assertDispatchedWithoutChain($command, $callback = null)\n    {\n        if ($command instanceof Closure) {\n            [$command, $callback] = [$this->firstClosureParameterType($command), $command];\n        }\n\n        PHPUnit::assertTrue(\n            $this->dispatched($command, $callback)->isNotEmpty(),\n            \"The expected [{$command}] job was not dispatched.\"\n        );\n\n        $this->assertDispatchedWithChainOfClasses($command, [], $callback);\n    }\n\n    /**\n     * Assert if a job was dispatched with chained jobs based on a truth-test callback.\n     *\n     * @param  string  $command\n     * @param  array  $expectedChain\n     * @param  callable|null  $callback\n     * @return void\n     */\n    protected function assertDispatchedWithChainOfObjects($command, $expectedChain, $callback)\n    {\n        $chain = collect($expectedChain)->map(function ($job) {\n            return serialize($job);\n        })->all();\n\n        PHPUnit::assertTrue(\n            $this->dispatched($command, $callback)->filter(function ($job) use ($chain) {\n                return $job->chained == $chain;\n            })->isNotEmpty(),\n            'The expected chain was not dispatched.'\n        );\n    }\n\n    /**\n     * Assert if a job was dispatched with chained jobs based on a truth-test callback.\n     *\n     * @param  string  $command\n     * @param  array  $expectedChain\n     * @param  callable|null  $callback\n     * @return void\n     */\n    protected function assertDispatchedWithChainOfClasses($command, $expectedChain, $callback)\n    {\n        $matching = $this->dispatched($command, $callback)->map->chained->map(function ($chain) {\n            return collect($chain)->map(function ($job) {\n                return get_class(unserialize($job));\n            });\n        })->filter(function ($chain) use ($expectedChain) {\n            return $chain->all() === $expectedChain;\n        });\n\n        PHPUnit::assertTrue(\n            $matching->isNotEmpty(), 'The expected chain was not dispatched.'\n        );\n    }\n\n    /**\n     * Determine if the given chain is entirely composed of objects.\n     *\n     * @param  array  $chain\n     * @return bool\n     */\n    protected function isChainOfObjects($chain)\n    {\n        return ! collect($chain)->contains(function ($job) {\n            return ! is_object($job);\n        });\n    }\n\n    /**\n     * Assert if a batch was dispatched based on a truth-test callback.\n     *\n     * @param  callable  $callback\n     * @return void\n     */\n    public function assertBatched(callable $callback)\n    {\n        PHPUnit::assertTrue(\n            $this->batched($callback)->count() > 0,\n            'The expected batch was not dispatched.'\n        );\n    }\n\n    /**\n     * Assert the number of batches that have been dispatched.\n     *\n     * @param  int  $count\n     * @return void\n     */\n    public function assertBatchCount($count)\n    {\n        PHPUnit::assertCount(\n            $count, $this->batches,\n        );\n    }\n\n    /**\n     * Get all of the jobs matching a truth-test callback.\n     *\n     * @param  string  $command\n     * @param  callable|null  $callback\n     * @return \\Illuminate\\Support\\Collection\n     */\n    public function dispatched($command, $callback = null)\n    {\n        if (! $this->hasDispatched($command)) {\n            return collect();\n        }\n\n        $callback = $callback ?: function () {\n            return true;\n        };\n\n        return collect($this->commands[$command])->filter(function ($command) use ($callback) {\n            return $callback($command);\n        });\n    }\n\n    /**\n     * Get all of the jobs dispatched synchronously matching a truth-test callback.\n     *\n     * @param  string  $command\n     * @param  callable|null  $callback\n     * @return \\Illuminate\\Support\\Collection\n     */\n    public function dispatchedSync(string $command, $callback = null)\n    {\n        if (! $this->hasDispatchedSync($command)) {\n            return collect();\n        }\n\n        $callback = $callback ?: function () {\n            return true;\n        };\n\n        return collect($this->commandsSync[$command])->filter(function ($command) use ($callback) {\n            return $callback($command);\n        });\n    }\n\n    /**\n     * Get all of the jobs dispatched after the response was sent matching a truth-test callback.\n     *\n     * @param  string  $command\n     * @param  callable|null  $callback\n     * @return \\Illuminate\\Support\\Collection\n     */\n    public function dispatchedAfterResponse(string $command, $callback = null)\n    {\n        if (! $this->hasDispatchedAfterResponse($command)) {\n            return collect();\n        }\n\n        $callback = $callback ?: function () {\n            return true;\n        };\n\n        return collect($this->commandsAfterResponse[$command])->filter(function ($command) use ($callback) {\n            return $callback($command);\n        });\n    }\n\n    /**\n     * Get all of the pending batches matching a truth-test callback.\n     *\n     * @param  callable  $callback\n     * @return \\Illuminate\\Support\\Collection\n     */\n    public function batched(callable $callback)\n    {\n        if (empty($this->batches)) {\n            return collect();\n        }\n\n        return collect($this->batches)->filter(function ($batch) use ($callback) {\n            return $callback($batch);\n        });\n    }\n\n    /**\n     * Determine if there are any stored commands for a given class.\n     *\n     * @param  string  $command\n     * @return bool\n     */\n    public function hasDispatched($command)\n    {\n        return isset($this->commands[$command]) && ! empty($this->commands[$command]);\n    }\n\n    /**\n     * Determine if there are any stored commands for a given class.\n     *\n     * @param  string  $command\n     * @return bool\n     */\n    public function hasDispatchedSync($command)\n    {\n        return isset($this->commandsSync[$command]) && ! empty($this->commandsSync[$command]);\n    }\n\n    /**\n     * Determine if there are any stored commands for a given class.\n     *\n     * @param  string  $command\n     * @return bool\n     */\n    public function hasDispatchedAfterResponse($command)\n    {\n        return isset($this->commandsAfterResponse[$command]) && ! empty($this->commandsAfterResponse[$command]);\n    }\n\n    /**\n     * Dispatch a command to its appropriate handler.\n     *\n     * @param  mixed  $command\n     * @return mixed\n     */\n    public function dispatch($command)\n    {\n        if ($this->shouldFakeJob($command)) {\n            $this->commands[get_class($command)][] = $command;\n        } else {\n            return $this->dispatcher->dispatch($command);\n        }\n    }\n\n    /**\n     * Dispatch a command to its appropriate handler in the current process.\n     *\n     * Queueable jobs will be dispatched to the \"sync\" queue.\n     *\n     * @param  mixed  $command\n     * @param  mixed  $handler\n     * @return mixed\n     */\n    public function dispatchSync($command, $handler = null)\n    {\n        if ($this->shouldFakeJob($command)) {\n            $this->commandsSync[get_class($command)][] = $command;\n        } else {\n            return $this->dispatcher->dispatchSync($command, $handler);\n        }\n    }\n\n    /**\n     * Dispatch a command to its appropriate handler in the current process.\n     *\n     * @param  mixed  $command\n     * @param  mixed  $handler\n     * @return mixed\n     */\n    public function dispatchNow($command, $handler = null)\n    {\n        if ($this->shouldFakeJob($command)) {\n            $this->commands[get_class($command)][] = $command;\n        } else {\n            return $this->dispatcher->dispatchNow($command, $handler);\n        }\n    }\n\n    /**\n     * Dispatch a command to its appropriate handler behind a queue.\n     *\n     * @param  mixed  $command\n     * @return mixed\n     */\n    public function dispatchToQueue($command)\n    {\n        if ($this->shouldFakeJob($command)) {\n            $this->commands[get_class($command)][] = $command;\n        } else {\n            return $this->dispatcher->dispatchToQueue($command);\n        }\n    }\n\n    /**\n     * Dispatch a command to its appropriate handler.\n     *\n     * @param  mixed  $command\n     * @return mixed\n     */\n    public function dispatchAfterResponse($command)\n    {\n        if ($this->shouldFakeJob($command)) {\n            $this->commandsAfterResponse[get_class($command)][] = $command;\n        } else {\n            return $this->dispatcher->dispatch($command);\n        }\n    }\n\n    /**\n     * Create a new chain of queueable jobs.\n     *\n     * @param  \\Illuminate\\Support\\Collection|array  $jobs\n     * @return \\Illuminate\\Foundation\\Bus\\PendingChain\n     */\n    public function chain($jobs)\n    {\n        $jobs = Collection::wrap($jobs);\n\n        return new PendingChainFake($this, $jobs->shift(), $jobs->toArray());\n    }\n\n    /**\n     * Attempt to find the batch with the given ID.\n     *\n     * @param  string  $batchId\n     * @return \\Illuminate\\Bus\\Batch|null\n     */\n    public function findBatch(string $batchId)\n    {\n        //\n    }\n\n    /**\n     * Create a new batch of queueable jobs.\n     *\n     * @param  \\Illuminate\\Support\\Collection|array  $jobs\n     * @return \\Illuminate\\Bus\\PendingBatch\n     */\n    public function batch($jobs)\n    {\n        return new PendingBatchFake($this, Collection::wrap($jobs));\n    }\n\n    /**\n     * Record the fake pending batch dispatch.\n     *\n     * @param  \\Illuminate\\Bus\\PendingBatch  $pendingBatch\n     * @return \\Illuminate\\Bus\\Batch\n     */\n    public function recordPendingBatch(PendingBatch $pendingBatch)\n    {\n        $this->batches[] = $pendingBatch;\n\n        return (new BatchRepositoryFake)->store($pendingBatch);\n    }\n\n    /**\n     * Determine if a command should be faked or actually dispatched.\n     *\n     * @param  mixed  $command\n     * @return bool\n     */\n    protected function shouldFakeJob($command)\n    {\n        if (empty($this->jobsToFake)) {\n            return true;\n        }\n\n        return collect($this->jobsToFake)\n            ->filter(function ($job) use ($command) {\n                return $job instanceof Closure\n                            ? $job($command)\n                            : $job === get_class($command);\n            })->isNotEmpty();\n    }\n\n    /**\n     * Set the pipes commands should be piped through before dispatching.\n     *\n     * @param  array  $pipes\n     * @return $this\n     */\n    public function pipeThrough(array $pipes)\n    {\n        $this->dispatcher->pipeThrough($pipes);\n\n        return $this;\n    }\n\n    /**\n     * Determine if the given command has a handler.\n     *\n     * @param  mixed  $command\n     * @return bool\n     */\n    public function hasCommandHandler($command)\n    {\n        return $this->dispatcher->hasCommandHandler($command);\n    }\n\n    /**\n     * Retrieve the handler for a command.\n     *\n     * @param  mixed  $command\n     * @return mixed\n     */\n    public function getCommandHandler($command)\n    {\n        return $this->dispatcher->getCommandHandler($command);\n    }\n\n    /**\n     * Map a command to a handler.\n     *\n     * @param  array  $map\n     * @return $this\n     */\n    public function map(array $map)\n    {\n        $this->dispatcher->map($map);\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Testing/Fakes/EventFake.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Testing\\Fakes;\n\nuse Closure;\nuse Illuminate\\Contracts\\Events\\Dispatcher;\nuse Illuminate\\Support\\Arr;\nuse Illuminate\\Support\\Str;\nuse Illuminate\\Support\\Traits\\ReflectsClosures;\nuse PHPUnit\\Framework\\Assert as PHPUnit;\nuse ReflectionFunction;\n\nclass EventFake implements Dispatcher\n{\n    use ReflectsClosures;\n\n    /**\n     * The original event dispatcher.\n     *\n     * @var \\Illuminate\\Contracts\\Events\\Dispatcher\n     */\n    protected $dispatcher;\n\n    /**\n     * The event types that should be intercepted instead of dispatched.\n     *\n     * @var array\n     */\n    protected $eventsToFake;\n\n    /**\n     * All of the events that have been intercepted keyed by type.\n     *\n     * @var array\n     */\n    protected $events = [];\n\n    /**\n     * Create a new event fake instance.\n     *\n     * @param  \\Illuminate\\Contracts\\Events\\Dispatcher  $dispatcher\n     * @param  array|string  $eventsToFake\n     * @return void\n     */\n    public function __construct(Dispatcher $dispatcher, $eventsToFake = [])\n    {\n        $this->dispatcher = $dispatcher;\n\n        $this->eventsToFake = Arr::wrap($eventsToFake);\n    }\n\n    /**\n     * Assert if an event has a listener attached to it.\n     *\n     * @param  string  $expectedEvent\n     * @param  string  $expectedListener\n     * @return void\n     */\n    public function assertListening($expectedEvent, $expectedListener)\n    {\n        foreach ($this->dispatcher->getListeners($expectedEvent) as $listenerClosure) {\n            $actualListener = (new ReflectionFunction($listenerClosure))\n                        ->getStaticVariables()['listener'];\n\n            if (is_string($actualListener) && Str::endsWith($actualListener, '@handle')) {\n                $actualListener = Str::parseCallback($actualListener)[0];\n            }\n\n            if ($actualListener === $expectedListener ||\n                ($actualListener instanceof Closure &&\n                $expectedListener === Closure::class)) {\n                PHPUnit::assertTrue(true);\n\n                return;\n            }\n        }\n\n        PHPUnit::assertTrue(\n            false,\n            sprintf(\n                'Event [%s] does not have the [%s] listener attached to it',\n                $expectedEvent,\n                print_r($expectedListener, true)\n            )\n        );\n    }\n\n    /**\n     * Assert if an event was dispatched based on a truth-test callback.\n     *\n     * @param  string|\\Closure  $event\n     * @param  callable|int|null  $callback\n     * @return void\n     */\n    public function assertDispatched($event, $callback = null)\n    {\n        if ($event instanceof Closure) {\n            [$event, $callback] = [$this->firstClosureParameterType($event), $event];\n        }\n\n        if (is_int($callback)) {\n            return $this->assertDispatchedTimes($event, $callback);\n        }\n\n        PHPUnit::assertTrue(\n            $this->dispatched($event, $callback)->count() > 0,\n            \"The expected [{$event}] event was not dispatched.\"\n        );\n    }\n\n    /**\n     * Assert if an event was dispatched a number of times.\n     *\n     * @param  string  $event\n     * @param  int  $times\n     * @return void\n     */\n    public function assertDispatchedTimes($event, $times = 1)\n    {\n        $count = $this->dispatched($event)->count();\n\n        PHPUnit::assertSame(\n            $times, $count,\n            \"The expected [{$event}] event was dispatched {$count} times instead of {$times} times.\"\n        );\n    }\n\n    /**\n     * Determine if an event was dispatched based on a truth-test callback.\n     *\n     * @param  string|\\Closure  $event\n     * @param  callable|null  $callback\n     * @return void\n     */\n    public function assertNotDispatched($event, $callback = null)\n    {\n        if ($event instanceof Closure) {\n            [$event, $callback] = [$this->firstClosureParameterType($event), $event];\n        }\n\n        PHPUnit::assertCount(\n            0, $this->dispatched($event, $callback),\n            \"The unexpected [{$event}] event was dispatched.\"\n        );\n    }\n\n    /**\n     * Assert that no events were dispatched.\n     *\n     * @return void\n     */\n    public function assertNothingDispatched()\n    {\n        $count = count(Arr::flatten($this->events));\n\n        PHPUnit::assertSame(\n            0, $count,\n            \"{$count} unexpected events were dispatched.\"\n        );\n    }\n\n    /**\n     * Get all of the events matching a truth-test callback.\n     *\n     * @param  string  $event\n     * @param  callable|null  $callback\n     * @return \\Illuminate\\Support\\Collection\n     */\n    public function dispatched($event, $callback = null)\n    {\n        if (! $this->hasDispatched($event)) {\n            return collect();\n        }\n\n        $callback = $callback ?: function () {\n            return true;\n        };\n\n        return collect($this->events[$event])->filter(function ($arguments) use ($callback) {\n            return $callback(...$arguments);\n        });\n    }\n\n    /**\n     * Determine if the given event has been dispatched.\n     *\n     * @param  string  $event\n     * @return bool\n     */\n    public function hasDispatched($event)\n    {\n        return isset($this->events[$event]) && ! empty($this->events[$event]);\n    }\n\n    /**\n     * Register an event listener with the dispatcher.\n     *\n     * @param  \\Closure|string|array  $events\n     * @param  mixed  $listener\n     * @return void\n     */\n    public function listen($events, $listener = null)\n    {\n        $this->dispatcher->listen($events, $listener);\n    }\n\n    /**\n     * Determine if a given event has listeners.\n     *\n     * @param  string  $eventName\n     * @return bool\n     */\n    public function hasListeners($eventName)\n    {\n        return $this->dispatcher->hasListeners($eventName);\n    }\n\n    /**\n     * Register an event and payload to be dispatched later.\n     *\n     * @param  string  $event\n     * @param  array  $payload\n     * @return void\n     */\n    public function push($event, $payload = [])\n    {\n        //\n    }\n\n    /**\n     * Register an event subscriber with the dispatcher.\n     *\n     * @param  object|string  $subscriber\n     * @return void\n     */\n    public function subscribe($subscriber)\n    {\n        $this->dispatcher->subscribe($subscriber);\n    }\n\n    /**\n     * Flush a set of pushed events.\n     *\n     * @param  string  $event\n     * @return void\n     */\n    public function flush($event)\n    {\n        //\n    }\n\n    /**\n     * Fire an event and call the listeners.\n     *\n     * @param  string|object  $event\n     * @param  mixed  $payload\n     * @param  bool  $halt\n     * @return array|null\n     */\n    public function dispatch($event, $payload = [], $halt = false)\n    {\n        $name = is_object($event) ? get_class($event) : (string) $event;\n\n        if ($this->shouldFakeEvent($name, $payload)) {\n            $this->events[$name][] = func_get_args();\n        } else {\n            return $this->dispatcher->dispatch($event, $payload, $halt);\n        }\n    }\n\n    /**\n     * Determine if an event should be faked or actually dispatched.\n     *\n     * @param  string  $eventName\n     * @param  mixed  $payload\n     * @return bool\n     */\n    protected function shouldFakeEvent($eventName, $payload)\n    {\n        if (empty($this->eventsToFake)) {\n            return true;\n        }\n\n        return collect($this->eventsToFake)\n            ->filter(function ($event) use ($eventName, $payload) {\n                return $event instanceof Closure\n                            ? $event($eventName, $payload)\n                            : $event === $eventName;\n            })\n            ->isNotEmpty();\n    }\n\n    /**\n     * Remove a set of listeners from the dispatcher.\n     *\n     * @param  string  $event\n     * @return void\n     */\n    public function forget($event)\n    {\n        //\n    }\n\n    /**\n     * Forget all of the queued listeners.\n     *\n     * @return void\n     */\n    public function forgetPushed()\n    {\n        //\n    }\n\n    /**\n     * Dispatch an event and call the listeners.\n     *\n     * @param  string|object  $event\n     * @param  mixed  $payload\n     * @return array|null\n     */\n    public function until($event, $payload = [])\n    {\n        return $this->dispatch($event, $payload, true);\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Testing/Fakes/MailFake.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Testing\\Fakes;\n\nuse Closure;\nuse Illuminate\\Contracts\\Mail\\Factory;\nuse Illuminate\\Contracts\\Mail\\Mailable;\nuse Illuminate\\Contracts\\Mail\\Mailer;\nuse Illuminate\\Contracts\\Mail\\MailQueue;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Support\\Traits\\ReflectsClosures;\nuse PHPUnit\\Framework\\Assert as PHPUnit;\n\nclass MailFake implements Factory, Mailer, MailQueue\n{\n    use ReflectsClosures;\n\n    /**\n     * The mailer currently being used to send a message.\n     *\n     * @var string\n     */\n    protected $currentMailer;\n\n    /**\n     * All of the mailables that have been sent.\n     *\n     * @var array\n     */\n    protected $mailables = [];\n\n    /**\n     * All of the mailables that have been queued.\n     *\n     * @var array\n     */\n    protected $queuedMailables = [];\n\n    /**\n     * Assert if a mailable was sent based on a truth-test callback.\n     *\n     * @param  string|\\Closure  $mailable\n     * @param  callable|int|null  $callback\n     * @return void\n     */\n    public function assertSent($mailable, $callback = null)\n    {\n        [$mailable, $callback] = $this->prepareMailableAndCallback($mailable, $callback);\n\n        if (is_numeric($callback)) {\n            return $this->assertSentTimes($mailable, $callback);\n        }\n\n        $message = \"The expected [{$mailable}] mailable was not sent.\";\n\n        if (count($this->queuedMailables) > 0) {\n            $message .= ' Did you mean to use assertQueued() instead?';\n        }\n\n        PHPUnit::assertTrue(\n            $this->sent($mailable, $callback)->count() > 0,\n            $message\n        );\n    }\n\n    /**\n     * Assert if a mailable was sent a number of times.\n     *\n     * @param  string  $mailable\n     * @param  int  $times\n     * @return void\n     */\n    protected function assertSentTimes($mailable, $times = 1)\n    {\n        $count = $this->sent($mailable)->count();\n\n        PHPUnit::assertSame(\n            $times, $count,\n            \"The expected [{$mailable}] mailable was sent {$count} times instead of {$times} times.\"\n        );\n    }\n\n    /**\n     * Determine if a mailable was not sent or queued to be sent based on a truth-test callback.\n     *\n     * @param  string|\\Closure  $mailable\n     * @param  callable|null  $callback\n     * @return void\n     */\n    public function assertNotOutgoing($mailable, $callback = null)\n    {\n        $this->assertNotSent($mailable, $callback);\n        $this->assertNotQueued($mailable, $callback);\n    }\n\n    /**\n     * Determine if a mailable was not sent based on a truth-test callback.\n     *\n     * @param  string|\\Closure  $mailable\n     * @param  callable|null  $callback\n     * @return void\n     */\n    public function assertNotSent($mailable, $callback = null)\n    {\n        [$mailable, $callback] = $this->prepareMailableAndCallback($mailable, $callback);\n\n        PHPUnit::assertCount(\n            0, $this->sent($mailable, $callback),\n            \"The unexpected [{$mailable}] mailable was sent.\"\n        );\n    }\n\n    /**\n     * Assert that no mailables were sent or queued to be sent.\n     *\n     * @return void\n     */\n    public function assertNothingOutgoing()\n    {\n        $this->assertNothingSent();\n        $this->assertNothingQueued();\n    }\n\n    /**\n     * Assert that no mailables were sent.\n     *\n     * @return void\n     */\n    public function assertNothingSent()\n    {\n        $mailableNames = collect($this->mailables)->map(function ($mailable) {\n            return get_class($mailable);\n        })->join(', ');\n\n        PHPUnit::assertEmpty($this->mailables, 'The following mailables were sent unexpectedly: '.$mailableNames);\n    }\n\n    /**\n     * Assert if a mailable was queued based on a truth-test callback.\n     *\n     * @param  string|\\Closure  $mailable\n     * @param  callable|int|null  $callback\n     * @return void\n     */\n    public function assertQueued($mailable, $callback = null)\n    {\n        [$mailable, $callback] = $this->prepareMailableAndCallback($mailable, $callback);\n\n        if (is_numeric($callback)) {\n            return $this->assertQueuedTimes($mailable, $callback);\n        }\n\n        PHPUnit::assertTrue(\n            $this->queued($mailable, $callback)->count() > 0,\n            \"The expected [{$mailable}] mailable was not queued.\"\n        );\n    }\n\n    /**\n     * Assert if a mailable was queued a number of times.\n     *\n     * @param  string  $mailable\n     * @param  int  $times\n     * @return void\n     */\n    protected function assertQueuedTimes($mailable, $times = 1)\n    {\n        $count = $this->queued($mailable)->count();\n\n        PHPUnit::assertSame(\n            $times, $count,\n            \"The expected [{$mailable}] mailable was queued {$count} times instead of {$times} times.\"\n        );\n    }\n\n    /**\n     * Determine if a mailable was not queued based on a truth-test callback.\n     *\n     * @param  string|\\Closure  $mailable\n     * @param  callable|null  $callback\n     * @return void\n     */\n    public function assertNotQueued($mailable, $callback = null)\n    {\n        [$mailable, $callback] = $this->prepareMailableAndCallback($mailable, $callback);\n\n        PHPUnit::assertCount(\n            0, $this->queued($mailable, $callback),\n            \"The unexpected [{$mailable}] mailable was queued.\"\n        );\n    }\n\n    /**\n     * Assert that no mailables were queued.\n     *\n     * @return void\n     */\n    public function assertNothingQueued()\n    {\n        $mailableNames = collect($this->queuedMailables)->map(function ($mailable) {\n            return get_class($mailable);\n        })->join(', ');\n\n        PHPUnit::assertEmpty($this->queuedMailables, 'The following mailables were queued unexpectedly: '.$mailableNames);\n    }\n\n    /**\n     * Get all of the mailables matching a truth-test callback.\n     *\n     * @param  string|\\Closure  $mailable\n     * @param  callable|null  $callback\n     * @return \\Illuminate\\Support\\Collection\n     */\n    public function sent($mailable, $callback = null)\n    {\n        [$mailable, $callback] = $this->prepareMailableAndCallback($mailable, $callback);\n\n        if (! $this->hasSent($mailable)) {\n            return collect();\n        }\n\n        $callback = $callback ?: function () {\n            return true;\n        };\n\n        return $this->mailablesOf($mailable)->filter(function ($mailable) use ($callback) {\n            return $callback($mailable);\n        });\n    }\n\n    /**\n     * Determine if the given mailable has been sent.\n     *\n     * @param  string  $mailable\n     * @return bool\n     */\n    public function hasSent($mailable)\n    {\n        return $this->mailablesOf($mailable)->count() > 0;\n    }\n\n    /**\n     * Get all of the queued mailables matching a truth-test callback.\n     *\n     * @param  string|\\Closure  $mailable\n     * @param  callable|null  $callback\n     * @return \\Illuminate\\Support\\Collection\n     */\n    public function queued($mailable, $callback = null)\n    {\n        [$mailable, $callback] = $this->prepareMailableAndCallback($mailable, $callback);\n\n        if (! $this->hasQueued($mailable)) {\n            return collect();\n        }\n\n        $callback = $callback ?: function () {\n            return true;\n        };\n\n        return $this->queuedMailablesOf($mailable)->filter(function ($mailable) use ($callback) {\n            return $callback($mailable);\n        });\n    }\n\n    /**\n     * Determine if the given mailable has been queued.\n     *\n     * @param  string  $mailable\n     * @return bool\n     */\n    public function hasQueued($mailable)\n    {\n        return $this->queuedMailablesOf($mailable)->count() > 0;\n    }\n\n    /**\n     * Get all of the mailed mailables for a given type.\n     *\n     * @param  string  $type\n     * @return \\Illuminate\\Support\\Collection\n     */\n    protected function mailablesOf($type)\n    {\n        return collect($this->mailables)->filter(function ($mailable) use ($type) {\n            return $mailable instanceof $type;\n        });\n    }\n\n    /**\n     * Get all of the mailed mailables for a given type.\n     *\n     * @param  string  $type\n     * @return \\Illuminate\\Support\\Collection\n     */\n    protected function queuedMailablesOf($type)\n    {\n        return collect($this->queuedMailables)->filter(function ($mailable) use ($type) {\n            return $mailable instanceof $type;\n        });\n    }\n\n    /**\n     * Get a mailer instance by name.\n     *\n     * @param  string|null  $name\n     * @return \\Illuminate\\Contracts\\Mail\\Mailer\n     */\n    public function mailer($name = null)\n    {\n        $this->currentMailer = $name;\n\n        return $this;\n    }\n\n    /**\n     * Begin the process of mailing a mailable class instance.\n     *\n     * @param  mixed  $users\n     * @return \\Illuminate\\Mail\\PendingMail\n     */\n    public function to($users)\n    {\n        return (new PendingMailFake($this))->to($users);\n    }\n\n    /**\n     * Begin the process of mailing a mailable class instance.\n     *\n     * @param  mixed  $users\n     * @return \\Illuminate\\Mail\\PendingMail\n     */\n    public function bcc($users)\n    {\n        return (new PendingMailFake($this))->bcc($users);\n    }\n\n    /**\n     * Send a new message with only a raw text part.\n     *\n     * @param  string  $text\n     * @param  \\Closure|string  $callback\n     * @return void\n     */\n    public function raw($text, $callback)\n    {\n        //\n    }\n\n    /**\n     * Send a new message using a view.\n     *\n     * @param  \\Illuminate\\Contracts\\Mail\\Mailable|string|array  $view\n     * @param  array  $data\n     * @param  \\Closure|string|null  $callback\n     * @return void\n     */\n    public function send($view, array $data = [], $callback = null)\n    {\n        if (! $view instanceof Mailable) {\n            return;\n        }\n\n        $view->mailer($this->currentMailer);\n\n        if ($view instanceof ShouldQueue) {\n            return $this->queue($view, $data);\n        }\n\n        $this->currentMailer = null;\n\n        $this->mailables[] = $view;\n    }\n\n    /**\n     * Queue a new e-mail message for sending.\n     *\n     * @param  \\Illuminate\\Contracts\\Mail\\Mailable|string|array  $view\n     * @param  string|null  $queue\n     * @return mixed\n     */\n    public function queue($view, $queue = null)\n    {\n        if (! $view instanceof Mailable) {\n            return;\n        }\n\n        $view->mailer($this->currentMailer);\n\n        $this->currentMailer = null;\n\n        $this->queuedMailables[] = $view;\n    }\n\n    /**\n     * Queue a new e-mail message for sending after (n) seconds.\n     *\n     * @param  \\DateTimeInterface|\\DateInterval|int  $delay\n     * @param  \\Illuminate\\Contracts\\Mail\\Mailable|string|array  $view\n     * @param  string|null  $queue\n     * @return mixed\n     */\n    public function later($delay, $view, $queue = null)\n    {\n        $this->queue($view, $queue);\n    }\n\n    /**\n     * Get the array of failed recipients.\n     *\n     * @return array\n     */\n    public function failures()\n    {\n        return [];\n    }\n\n    /**\n     * Infer mailable class using reflection if a typehinted closure is passed to assertion.\n     *\n     * @param  string|\\Closure  $mailable\n     * @param  callable|null  $callback\n     * @return array\n     */\n    protected function prepareMailableAndCallback($mailable, $callback)\n    {\n        if ($mailable instanceof Closure) {\n            return [$this->firstClosureParameterType($mailable), $mailable];\n        }\n\n        return [$mailable, $callback];\n    }\n\n    /**\n     * Forget all of the resolved mailer instances.\n     *\n     * @return $this\n     */\n    public function forgetMailers()\n    {\n        $this->currentMailer = null;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Testing/Fakes/NotificationFake.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Testing\\Fakes;\n\nuse Closure;\nuse Exception;\nuse Illuminate\\Contracts\\Notifications\\Dispatcher as NotificationDispatcher;\nuse Illuminate\\Contracts\\Notifications\\Factory as NotificationFactory;\nuse Illuminate\\Contracts\\Translation\\HasLocalePreference;\nuse Illuminate\\Notifications\\AnonymousNotifiable;\nuse Illuminate\\Support\\Collection;\nuse Illuminate\\Support\\Str;\nuse Illuminate\\Support\\Traits\\Macroable;\nuse Illuminate\\Support\\Traits\\ReflectsClosures;\nuse PHPUnit\\Framework\\Assert as PHPUnit;\n\nclass NotificationFake implements NotificationDispatcher, NotificationFactory\n{\n    use Macroable, ReflectsClosures;\n\n    /**\n     * All of the notifications that have been sent.\n     *\n     * @var array\n     */\n    protected $notifications = [];\n\n    /**\n     * Locale used when sending notifications.\n     *\n     * @var string|null\n     */\n    public $locale;\n\n    /**\n     * Assert if a notification was sent on-demand based on a truth-test callback.\n     *\n     * @param  string|\\Closure  $notification\n     * @param  callable|null  $callback\n     * @return void\n     *\n     * @throws \\Exception\n     */\n    public function assertSentOnDemand($notification, $callback = null)\n    {\n        $this->assertSentTo(new AnonymousNotifiable, $notification, $callback);\n    }\n\n    /**\n     * Assert if a notification was sent based on a truth-test callback.\n     *\n     * @param  mixed  $notifiable\n     * @param  string|\\Closure  $notification\n     * @param  callable|null  $callback\n     * @return void\n     *\n     * @throws \\Exception\n     */\n    public function assertSentTo($notifiable, $notification, $callback = null)\n    {\n        if (is_array($notifiable) || $notifiable instanceof Collection) {\n            if (count($notifiable) === 0) {\n                throw new Exception('No notifiable given.');\n            }\n\n            foreach ($notifiable as $singleNotifiable) {\n                $this->assertSentTo($singleNotifiable, $notification, $callback);\n            }\n\n            return;\n        }\n\n        if ($notification instanceof Closure) {\n            [$notification, $callback] = [$this->firstClosureParameterType($notification), $notification];\n        }\n\n        if (is_numeric($callback)) {\n            return $this->assertSentToTimes($notifiable, $notification, $callback);\n        }\n\n        PHPUnit::assertTrue(\n            $this->sent($notifiable, $notification, $callback)->count() > 0,\n            \"The expected [{$notification}] notification was not sent.\"\n        );\n    }\n\n    /**\n     * Assert if a notification was sent on-demand a number of times.\n     *\n     * @param  string  $notification\n     * @param  int  $times\n     * @return void\n     */\n    public function assertSentOnDemandTimes($notification, $times = 1)\n    {\n        return $this->assertSentToTimes(new AnonymousNotifiable, $notification, $times);\n    }\n\n    /**\n     * Assert if a notification was sent a number of times.\n     *\n     * @param  mixed  $notifiable\n     * @param  string  $notification\n     * @param  int  $times\n     * @return void\n     */\n    public function assertSentToTimes($notifiable, $notification, $times = 1)\n    {\n        $count = $this->sent($notifiable, $notification)->count();\n\n        PHPUnit::assertSame(\n            $times, $count,\n            \"Expected [{$notification}] to be sent {$times} times, but was sent {$count} times.\"\n        );\n    }\n\n    /**\n     * Determine if a notification was sent based on a truth-test callback.\n     *\n     * @param  mixed  $notifiable\n     * @param  string|\\Closure  $notification\n     * @param  callable|null  $callback\n     * @return void\n     *\n     * @throws \\Exception\n     */\n    public function assertNotSentTo($notifiable, $notification, $callback = null)\n    {\n        if (is_array($notifiable) || $notifiable instanceof Collection) {\n            if (count($notifiable) === 0) {\n                throw new Exception('No notifiable given.');\n            }\n\n            foreach ($notifiable as $singleNotifiable) {\n                $this->assertNotSentTo($singleNotifiable, $notification, $callback);\n            }\n\n            return;\n        }\n\n        if ($notification instanceof Closure) {\n            [$notification, $callback] = [$this->firstClosureParameterType($notification), $notification];\n        }\n\n        PHPUnit::assertCount(\n            0, $this->sent($notifiable, $notification, $callback),\n            \"The unexpected [{$notification}] notification was sent.\"\n        );\n    }\n\n    /**\n     * Assert that no notifications were sent.\n     *\n     * @return void\n     */\n    public function assertNothingSent()\n    {\n        PHPUnit::assertEmpty($this->notifications, 'Notifications were sent unexpectedly.');\n    }\n\n    /**\n     * Assert the total amount of times a notification was sent.\n     *\n     * @param  string  $notification\n     * @param  int  $expectedCount\n     * @return void\n     */\n    public function assertSentTimes($notification, $expectedCount)\n    {\n        $actualCount = collect($this->notifications)\n            ->flatten(1)\n            ->reduce(function ($count, $sent) use ($notification) {\n                return $count + count($sent[$notification] ?? []);\n            }, 0);\n\n        PHPUnit::assertSame(\n            $expectedCount, $actualCount,\n            \"Expected [{$notification}] to be sent {$expectedCount} times, but was sent {$actualCount} times.\"\n        );\n    }\n\n    /**\n     * Assert the total amount of times a notification was sent.\n     *\n     * @param  int  $expectedCount\n     * @param  string  $notification\n     * @return void\n     *\n     * @deprecated Use the assertSentTimes method instead\n     */\n    public function assertTimesSent($expectedCount, $notification)\n    {\n        $this->assertSentTimes($notification, $expectedCount);\n    }\n\n    /**\n     * Get all of the notifications matching a truth-test callback.\n     *\n     * @param  mixed  $notifiable\n     * @param  string  $notification\n     * @param  callable|null  $callback\n     * @return \\Illuminate\\Support\\Collection\n     */\n    public function sent($notifiable, $notification, $callback = null)\n    {\n        if (! $this->hasSent($notifiable, $notification)) {\n            return collect();\n        }\n\n        $callback = $callback ?: function () {\n            return true;\n        };\n\n        $notifications = collect($this->notificationsFor($notifiable, $notification));\n\n        return $notifications->filter(function ($arguments) use ($callback) {\n            return $callback(...array_values($arguments));\n        })->pluck('notification');\n    }\n\n    /**\n     * Determine if there are more notifications left to inspect.\n     *\n     * @param  mixed  $notifiable\n     * @param  string  $notification\n     * @return bool\n     */\n    public function hasSent($notifiable, $notification)\n    {\n        return ! empty($this->notificationsFor($notifiable, $notification));\n    }\n\n    /**\n     * Get all of the notifications for a notifiable entity by type.\n     *\n     * @param  mixed  $notifiable\n     * @param  string  $notification\n     * @return array\n     */\n    protected function notificationsFor($notifiable, $notification)\n    {\n        return $this->notifications[get_class($notifiable)][$notifiable->getKey()][$notification] ?? [];\n    }\n\n    /**\n     * Send the given notification to the given notifiable entities.\n     *\n     * @param  \\Illuminate\\Support\\Collection|array|mixed  $notifiables\n     * @param  mixed  $notification\n     * @return void\n     */\n    public function send($notifiables, $notification)\n    {\n        $this->sendNow($notifiables, $notification);\n    }\n\n    /**\n     * Send the given notification immediately.\n     *\n     * @param  \\Illuminate\\Support\\Collection|array|mixed  $notifiables\n     * @param  mixed  $notification\n     * @param  array|null  $channels\n     * @return void\n     */\n    public function sendNow($notifiables, $notification, array $channels = null)\n    {\n        if (! $notifiables instanceof Collection && ! is_array($notifiables)) {\n            $notifiables = [$notifiables];\n        }\n\n        foreach ($notifiables as $notifiable) {\n            if (! $notification->id) {\n                $notification->id = Str::uuid()->toString();\n            }\n\n            $notifiableChannels = $channels ?: $notification->via($notifiable);\n\n            if (method_exists($notification, 'shouldSend')) {\n                $notifiableChannels = array_filter(\n                    $notifiableChannels,\n                    function ($channel) use ($notification, $notifiable) {\n                        return $notification->shouldSend($notifiable, $channel) !== false;\n                    }\n                );\n\n                if (empty($notifiableChannels)) {\n                    continue;\n                }\n            }\n\n            $this->notifications[get_class($notifiable)][$notifiable->getKey()][get_class($notification)][] = [\n                'notification' => $notification,\n                'channels' => $notifiableChannels,\n                'notifiable' => $notifiable,\n                'locale' => $notification->locale ?? $this->locale ?? value(function () use ($notifiable) {\n                    if ($notifiable instanceof HasLocalePreference) {\n                        return $notifiable->preferredLocale();\n                    }\n                }),\n            ];\n        }\n    }\n\n    /**\n     * Get a channel instance by name.\n     *\n     * @param  string|null  $name\n     * @return mixed\n     */\n    public function channel($name = null)\n    {\n        //\n    }\n\n    /**\n     * Set the locale of notifications.\n     *\n     * @param  string  $locale\n     * @return $this\n     */\n    public function locale($locale)\n    {\n        $this->locale = $locale;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Testing/Fakes/PendingBatchFake.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Testing\\Fakes;\n\nuse Illuminate\\Bus\\PendingBatch;\nuse Illuminate\\Support\\Collection;\n\nclass PendingBatchFake extends PendingBatch\n{\n    /**\n     * The fake bus instance.\n     *\n     * @var \\Illuminate\\Support\\Testing\\Fakes\\BusFake\n     */\n    protected $bus;\n\n    /**\n     * Create a new pending batch instance.\n     *\n     * @param  \\Illuminate\\Support\\Testing\\Fakes\\BusFake  $bus\n     * @param  \\Illuminate\\Support\\Collection  $jobs\n     * @return void\n     */\n    public function __construct(BusFake $bus, Collection $jobs)\n    {\n        $this->bus = $bus;\n        $this->jobs = $jobs;\n    }\n\n    /**\n     * Dispatch the batch.\n     *\n     * @return \\Illuminate\\Bus\\Batch\n     */\n    public function dispatch()\n    {\n        return $this->bus->recordPendingBatch($this);\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Testing/Fakes/PendingChainFake.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Testing\\Fakes;\n\nuse Closure;\nuse Illuminate\\Foundation\\Bus\\PendingChain;\nuse Illuminate\\Queue\\CallQueuedClosure;\n\nclass PendingChainFake extends PendingChain\n{\n    /**\n     * The fake bus instance.\n     *\n     * @var \\Illuminate\\Support\\Testing\\Fakes\\BusFake\n     */\n    protected $bus;\n\n    /**\n     * Create a new pending chain instance.\n     *\n     * @param  \\Illuminate\\Support\\Testing\\Fakes\\BusFake  $bus\n     * @param  mixed  $job\n     * @param  array  $chain\n     * @return void\n     */\n    public function __construct(BusFake $bus, $job, $chain)\n    {\n        $this->bus = $bus;\n        $this->job = $job;\n        $this->chain = $chain;\n    }\n\n    /**\n     * Dispatch the job with the given arguments.\n     *\n     * @return \\Illuminate\\Foundation\\Bus\\PendingDispatch\n     */\n    public function dispatch()\n    {\n        if (is_string($this->job)) {\n            $firstJob = new $this->job(...func_get_args());\n        } elseif ($this->job instanceof Closure) {\n            $firstJob = CallQueuedClosure::create($this->job);\n        } else {\n            $firstJob = $this->job;\n        }\n\n        $firstJob->allOnConnection($this->connection);\n        $firstJob->allOnQueue($this->queue);\n        $firstJob->chain($this->chain);\n        $firstJob->delay($this->delay);\n        $firstJob->chainCatchCallbacks = $this->catchCallbacks();\n\n        return $this->bus->dispatch($firstJob);\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Testing/Fakes/PendingMailFake.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Testing\\Fakes;\n\nuse Illuminate\\Contracts\\Mail\\Mailable;\nuse Illuminate\\Mail\\PendingMail;\n\nclass PendingMailFake extends PendingMail\n{\n    /**\n     * Create a new instance.\n     *\n     * @param  \\Illuminate\\Support\\Testing\\Fakes\\MailFake  $mailer\n     * @return void\n     */\n    public function __construct($mailer)\n    {\n        $this->mailer = $mailer;\n    }\n\n    /**\n     * Send a new mailable message instance.\n     *\n     * @param  \\Illuminate\\Contracts\\Mail\\Mailable  $mailable\n     * @return void\n     */\n    public function send(Mailable $mailable)\n    {\n        $this->mailer->send($this->fill($mailable));\n    }\n\n    /**\n     * Push the given mailable onto the queue.\n     *\n     * @param  \\Illuminate\\Contracts\\Mail\\Mailable  $mailable\n     * @return mixed\n     */\n    public function queue(Mailable $mailable)\n    {\n        return $this->mailer->queue($this->fill($mailable));\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Testing/Fakes/QueueFake.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Testing\\Fakes;\n\nuse BadMethodCallException;\nuse Closure;\nuse Illuminate\\Contracts\\Queue\\Queue;\nuse Illuminate\\Queue\\QueueManager;\nuse Illuminate\\Support\\Traits\\ReflectsClosures;\nuse PHPUnit\\Framework\\Assert as PHPUnit;\n\nclass QueueFake extends QueueManager implements Queue\n{\n    use ReflectsClosures;\n\n    /**\n     * All of the jobs that have been pushed.\n     *\n     * @var array\n     */\n    protected $jobs = [];\n\n    /**\n     * Assert if a job was pushed based on a truth-test callback.\n     *\n     * @param  string|\\Closure  $job\n     * @param  callable|int|null  $callback\n     * @return void\n     */\n    public function assertPushed($job, $callback = null)\n    {\n        if ($job instanceof Closure) {\n            [$job, $callback] = [$this->firstClosureParameterType($job), $job];\n        }\n\n        if (is_numeric($callback)) {\n            return $this->assertPushedTimes($job, $callback);\n        }\n\n        PHPUnit::assertTrue(\n            $this->pushed($job, $callback)->count() > 0,\n            \"The expected [{$job}] job was not pushed.\"\n        );\n    }\n\n    /**\n     * Assert if a job was pushed a number of times.\n     *\n     * @param  string  $job\n     * @param  int  $times\n     * @return void\n     */\n    protected function assertPushedTimes($job, $times = 1)\n    {\n        $count = $this->pushed($job)->count();\n\n        PHPUnit::assertSame(\n            $times, $count,\n            \"The expected [{$job}] job was pushed {$count} times instead of {$times} times.\"\n        );\n    }\n\n    /**\n     * Assert if a job was pushed based on a truth-test callback.\n     *\n     * @param  string  $queue\n     * @param  string|\\Closure  $job\n     * @param  callable|null  $callback\n     * @return void\n     */\n    public function assertPushedOn($queue, $job, $callback = null)\n    {\n        if ($job instanceof Closure) {\n            [$job, $callback] = [$this->firstClosureParameterType($job), $job];\n        }\n\n        $this->assertPushed($job, function ($job, $pushedQueue) use ($callback, $queue) {\n            if ($pushedQueue !== $queue) {\n                return false;\n            }\n\n            return $callback ? $callback(...func_get_args()) : true;\n        });\n    }\n\n    /**\n     * Assert if a job was pushed with chained jobs based on a truth-test callback.\n     *\n     * @param  string  $job\n     * @param  array  $expectedChain\n     * @param  callable|null  $callback\n     * @return void\n     */\n    public function assertPushedWithChain($job, $expectedChain = [], $callback = null)\n    {\n        PHPUnit::assertTrue(\n            $this->pushed($job, $callback)->isNotEmpty(),\n            \"The expected [{$job}] job was not pushed.\"\n        );\n\n        PHPUnit::assertTrue(\n            collect($expectedChain)->isNotEmpty(),\n            'The expected chain can not be empty.'\n        );\n\n        $this->isChainOfObjects($expectedChain)\n                ? $this->assertPushedWithChainOfObjects($job, $expectedChain, $callback)\n                : $this->assertPushedWithChainOfClasses($job, $expectedChain, $callback);\n    }\n\n    /**\n     * Assert if a job was pushed with an empty chain based on a truth-test callback.\n     *\n     * @param  string  $job\n     * @param  callable|null  $callback\n     * @return void\n     */\n    public function assertPushedWithoutChain($job, $callback = null)\n    {\n        PHPUnit::assertTrue(\n            $this->pushed($job, $callback)->isNotEmpty(),\n            \"The expected [{$job}] job was not pushed.\"\n        );\n\n        $this->assertPushedWithChainOfClasses($job, [], $callback);\n    }\n\n    /**\n     * Assert if a job was pushed with chained jobs based on a truth-test callback.\n     *\n     * @param  string  $job\n     * @param  array  $expectedChain\n     * @param  callable|null  $callback\n     * @return void\n     */\n    protected function assertPushedWithChainOfObjects($job, $expectedChain, $callback)\n    {\n        $chain = collect($expectedChain)->map(function ($job) {\n            return serialize($job);\n        })->all();\n\n        PHPUnit::assertTrue(\n            $this->pushed($job, $callback)->filter(function ($job) use ($chain) {\n                return $job->chained == $chain;\n            })->isNotEmpty(),\n            'The expected chain was not pushed.'\n        );\n    }\n\n    /**\n     * Assert if a job was pushed with chained jobs based on a truth-test callback.\n     *\n     * @param  string  $job\n     * @param  array  $expectedChain\n     * @param  callable|null  $callback\n     * @return void\n     */\n    protected function assertPushedWithChainOfClasses($job, $expectedChain, $callback)\n    {\n        $matching = $this->pushed($job, $callback)->map->chained->map(function ($chain) {\n            return collect($chain)->map(function ($job) {\n                return get_class(unserialize($job));\n            });\n        })->filter(function ($chain) use ($expectedChain) {\n            return $chain->all() === $expectedChain;\n        });\n\n        PHPUnit::assertTrue(\n            $matching->isNotEmpty(), 'The expected chain was not pushed.'\n        );\n    }\n\n    /**\n     * Determine if the given chain is entirely composed of objects.\n     *\n     * @param  array  $chain\n     * @return bool\n     */\n    protected function isChainOfObjects($chain)\n    {\n        return ! collect($chain)->contains(function ($job) {\n            return ! is_object($job);\n        });\n    }\n\n    /**\n     * Determine if a job was pushed based on a truth-test callback.\n     *\n     * @param  string|\\Closure  $job\n     * @param  callable|null  $callback\n     * @return void\n     */\n    public function assertNotPushed($job, $callback = null)\n    {\n        if ($job instanceof Closure) {\n            [$job, $callback] = [$this->firstClosureParameterType($job), $job];\n        }\n\n        PHPUnit::assertCount(\n            0, $this->pushed($job, $callback),\n            \"The unexpected [{$job}] job was pushed.\"\n        );\n    }\n\n    /**\n     * Assert that no jobs were pushed.\n     *\n     * @return void\n     */\n    public function assertNothingPushed()\n    {\n        PHPUnit::assertEmpty($this->jobs, 'Jobs were pushed unexpectedly.');\n    }\n\n    /**\n     * Get all of the jobs matching a truth-test callback.\n     *\n     * @param  string  $job\n     * @param  callable|null  $callback\n     * @return \\Illuminate\\Support\\Collection\n     */\n    public function pushed($job, $callback = null)\n    {\n        if (! $this->hasPushed($job)) {\n            return collect();\n        }\n\n        $callback = $callback ?: function () {\n            return true;\n        };\n\n        return collect($this->jobs[$job])->filter(function ($data) use ($callback) {\n            return $callback($data['job'], $data['queue']);\n        })->pluck('job');\n    }\n\n    /**\n     * Determine if there are any stored jobs for a given class.\n     *\n     * @param  string  $job\n     * @return bool\n     */\n    public function hasPushed($job)\n    {\n        return isset($this->jobs[$job]) && ! empty($this->jobs[$job]);\n    }\n\n    /**\n     * Resolve a queue connection instance.\n     *\n     * @param  mixed  $value\n     * @return \\Illuminate\\Contracts\\Queue\\Queue\n     */\n    public function connection($value = null)\n    {\n        return $this;\n    }\n\n    /**\n     * Get the size of the queue.\n     *\n     * @param  string|null  $queue\n     * @return int\n     */\n    public function size($queue = null)\n    {\n        return collect($this->jobs)->flatten(1)->filter(function ($job) use ($queue) {\n            return $job['queue'] === $queue;\n        })->count();\n    }\n\n    /**\n     * Push a new job onto the queue.\n     *\n     * @param  string|object  $job\n     * @param  mixed  $data\n     * @param  string|null  $queue\n     * @return mixed\n     */\n    public function push($job, $data = '', $queue = null)\n    {\n        $this->jobs[is_object($job) ? get_class($job) : $job][] = [\n            'job' => $job,\n            'queue' => $queue,\n        ];\n    }\n\n    /**\n     * Push a raw payload onto the queue.\n     *\n     * @param  string  $payload\n     * @param  string|null  $queue\n     * @param  array  $options\n     * @return mixed\n     */\n    public function pushRaw($payload, $queue = null, array $options = [])\n    {\n        //\n    }\n\n    /**\n     * Push a new job onto the queue after a delay.\n     *\n     * @param  \\DateTimeInterface|\\DateInterval|int  $delay\n     * @param  string|object  $job\n     * @param  mixed  $data\n     * @param  string|null  $queue\n     * @return mixed\n     */\n    public function later($delay, $job, $data = '', $queue = null)\n    {\n        return $this->push($job, $data, $queue);\n    }\n\n    /**\n     * Push a new job onto the queue.\n     *\n     * @param  string  $queue\n     * @param  string|object  $job\n     * @param  mixed  $data\n     * @return mixed\n     */\n    public function pushOn($queue, $job, $data = '')\n    {\n        return $this->push($job, $data, $queue);\n    }\n\n    /**\n     * Push a new job onto the queue after a delay.\n     *\n     * @param  string  $queue\n     * @param  \\DateTimeInterface|\\DateInterval|int  $delay\n     * @param  string|object  $job\n     * @param  mixed  $data\n     * @return mixed\n     */\n    public function laterOn($queue, $delay, $job, $data = '')\n    {\n        return $this->push($job, $data, $queue);\n    }\n\n    /**\n     * Pop the next job off of the queue.\n     *\n     * @param  string|null  $queue\n     * @return \\Illuminate\\Contracts\\Queue\\Job|null\n     */\n    public function pop($queue = null)\n    {\n        //\n    }\n\n    /**\n     * Push an array of jobs onto the queue.\n     *\n     * @param  array  $jobs\n     * @param  mixed  $data\n     * @param  string|null  $queue\n     * @return mixed\n     */\n    public function bulk($jobs, $data = '', $queue = null)\n    {\n        foreach ($jobs as $job) {\n            $this->push($job, $data, $queue);\n        }\n    }\n\n    /**\n     * Get the jobs that have been pushed.\n     *\n     * @return array\n     */\n    public function pushedJobs()\n    {\n        return $this->jobs;\n    }\n\n    /**\n     * Get the connection name for the queue.\n     *\n     * @return string\n     */\n    public function getConnectionName()\n    {\n        //\n    }\n\n    /**\n     * Set the connection name for the queue.\n     *\n     * @param  string  $name\n     * @return $this\n     */\n    public function setConnectionName($name)\n    {\n        return $this;\n    }\n\n    /**\n     * Override the QueueManager to prevent circular dependency.\n     *\n     * @param  string  $method\n     * @param  array  $parameters\n     * @return mixed\n     *\n     * @throws \\BadMethodCallException\n     */\n    public function __call($method, $parameters)\n    {\n        throw new BadMethodCallException(sprintf(\n            'Call to undefined method %s::%s()', static::class, $method\n        ));\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Timebox.php",
    "content": "<?php\n\nnamespace Illuminate\\Support;\n\nclass Timebox\n{\n    /**\n     * Indicates if the timebox is allowed to return early.\n     *\n     * @var bool\n     */\n    public $earlyReturn = false;\n\n    /**\n     * Invoke the given callback within the specified timebox minimum.\n     *\n     * @param  callable  $callback\n     * @param  int  $microseconds\n     * @return mixed\n     */\n    public function call(callable $callback, int $microseconds)\n    {\n        $start = microtime(true);\n\n        $result = $callback($this);\n\n        $remainder = $microseconds - ((microtime(true) - $start) * 1000000);\n\n        if (! $this->earlyReturn && $remainder > 0) {\n            $this->usleep($remainder);\n        }\n\n        return $result;\n    }\n\n    /**\n     * Indicate that the timebox can return early.\n     *\n     * @return $this\n     */\n    public function returnEarly()\n    {\n        $this->earlyReturn = true;\n\n        return $this;\n    }\n\n    /**\n     * Indicate that the timebox cannot return early.\n     *\n     * @return $this\n     */\n    public function dontReturnEarly()\n    {\n        $this->earlyReturn = false;\n\n        return $this;\n    }\n\n    /**\n     * Sleep for the specified number of microseconds.\n     *\n     * @param  $microseconds\n     * @return void\n     */\n    protected function usleep($microseconds)\n    {\n        usleep($microseconds);\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Traits/CapsuleManagerTrait.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Traits;\n\nuse Illuminate\\Contracts\\Container\\Container;\nuse Illuminate\\Support\\Fluent;\n\ntrait CapsuleManagerTrait\n{\n    /**\n     * The current globally used instance.\n     *\n     * @var object\n     */\n    protected static $instance;\n\n    /**\n     * The container instance.\n     *\n     * @var \\Illuminate\\Contracts\\Container\\Container\n     */\n    protected $container;\n\n    /**\n     * Setup the IoC container instance.\n     *\n     * @param  \\Illuminate\\Contracts\\Container\\Container  $container\n     * @return void\n     */\n    protected function setupContainer(Container $container)\n    {\n        $this->container = $container;\n\n        if (! $this->container->bound('config')) {\n            $this->container->instance('config', new Fluent);\n        }\n    }\n\n    /**\n     * Make this capsule instance available globally.\n     *\n     * @return void\n     */\n    public function setAsGlobal()\n    {\n        static::$instance = $this;\n    }\n\n    /**\n     * Get the IoC container instance.\n     *\n     * @return \\Illuminate\\Contracts\\Container\\Container\n     */\n    public function getContainer()\n    {\n        return $this->container;\n    }\n\n    /**\n     * Set the IoC container instance.\n     *\n     * @param  \\Illuminate\\Contracts\\Container\\Container  $container\n     * @return void\n     */\n    public function setContainer(Container $container)\n    {\n        $this->container = $container;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Traits/Conditionable.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Traits;\n\ntrait Conditionable\n{\n    /**\n     * Apply the callback if the given \"value\" is truthy.\n     *\n     * @param  mixed  $value\n     * @param  callable  $callback\n     * @param  callable|null  $default\n     * @return $this|mixed\n     */\n    public function when($value, $callback, $default = null)\n    {\n        if ($value) {\n            return $callback($this, $value) ?: $this;\n        } elseif ($default) {\n            return $default($this, $value) ?: $this;\n        }\n\n        return $this;\n    }\n\n    /**\n     * Apply the callback if the given \"value\" is falsy.\n     *\n     * @param  mixed  $value\n     * @param  callable  $callback\n     * @param  callable|null  $default\n     * @return $this|mixed\n     */\n    public function unless($value, $callback, $default = null)\n    {\n        if (! $value) {\n            return $callback($this, $value) ?: $this;\n        } elseif ($default) {\n            return $default($this, $value) ?: $this;\n        }\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Traits/ForwardsCalls.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Traits;\n\nuse BadMethodCallException;\nuse Error;\n\ntrait ForwardsCalls\n{\n    /**\n     * Forward a method call to the given object.\n     *\n     * @param  mixed  $object\n     * @param  string  $method\n     * @param  array  $parameters\n     * @return mixed\n     *\n     * @throws \\BadMethodCallException\n     */\n    protected function forwardCallTo($object, $method, $parameters)\n    {\n        try {\n            return $object->{$method}(...$parameters);\n        } catch (Error|BadMethodCallException $e) {\n            $pattern = '~^Call to undefined method (?P<class>[^:]+)::(?P<method>[^\\(]+)\\(\\)$~';\n\n            if (! preg_match($pattern, $e->getMessage(), $matches)) {\n                throw $e;\n            }\n\n            if ($matches['class'] != get_class($object) ||\n                $matches['method'] != $method) {\n                throw $e;\n            }\n\n            static::throwBadMethodCallException($method);\n        }\n    }\n\n    /**\n     * Forward a method call to the given object, returning $this if the forwarded call returned itself.\n     *\n     * @param  mixed  $object\n     * @param  string  $method\n     * @param  array  $parameters\n     * @return mixed\n     *\n     * @throws \\BadMethodCallException\n     */\n    protected function forwardDecoratedCallTo($object, $method, $parameters)\n    {\n        $result = $this->forwardCallTo($object, $method, $parameters);\n\n        if ($result === $object) {\n            return $this;\n        }\n\n        return $result;\n    }\n\n    /**\n     * Throw a bad method call exception for the given method.\n     *\n     * @param  string  $method\n     * @return void\n     *\n     * @throws \\BadMethodCallException\n     */\n    protected static function throwBadMethodCallException($method)\n    {\n        throw new BadMethodCallException(sprintf(\n            'Call to undefined method %s::%s()', static::class, $method\n        ));\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Traits/Localizable.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Traits;\n\nuse Illuminate\\Container\\Container;\n\ntrait Localizable\n{\n    /**\n     * Run the callback with the given locale.\n     *\n     * @param  string  $locale\n     * @param  \\Closure  $callback\n     * @return mixed\n     */\n    public function withLocale($locale, $callback)\n    {\n        if (! $locale) {\n            return $callback();\n        }\n\n        $app = Container::getInstance();\n\n        $original = $app->getLocale();\n\n        try {\n            $app->setLocale($locale);\n\n            return $callback();\n        } finally {\n            $app->setLocale($original);\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Traits/ReflectsClosures.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Traits;\n\nuse Closure;\nuse Illuminate\\Support\\Reflector;\nuse ReflectionFunction;\nuse RuntimeException;\n\ntrait ReflectsClosures\n{\n    /**\n     * Get the class name of the first parameter of the given Closure.\n     *\n     * @param  \\Closure  $closure\n     * @return string\n     *\n     * @throws \\ReflectionException\n     * @throws \\RuntimeException\n     */\n    protected function firstClosureParameterType(Closure $closure)\n    {\n        $types = array_values($this->closureParameterTypes($closure));\n\n        if (! $types) {\n            throw new RuntimeException('The given Closure has no parameters.');\n        }\n\n        if ($types[0] === null) {\n            throw new RuntimeException('The first parameter of the given Closure is missing a type hint.');\n        }\n\n        return $types[0];\n    }\n\n    /**\n     * Get the class names of the first parameter of the given Closure, including union types.\n     *\n     * @param  \\Closure  $closure\n     * @return array\n     *\n     * @throws \\ReflectionException\n     * @throws \\RuntimeException\n     */\n    protected function firstClosureParameterTypes(Closure $closure)\n    {\n        $reflection = new ReflectionFunction($closure);\n\n        $types = collect($reflection->getParameters())->mapWithKeys(function ($parameter) {\n            if ($parameter->isVariadic()) {\n                return [$parameter->getName() => null];\n            }\n\n            return [$parameter->getName() => Reflector::getParameterClassNames($parameter)];\n        })->filter()->values()->all();\n\n        if (empty($types)) {\n            throw new RuntimeException('The given Closure has no parameters.');\n        }\n\n        if (isset($types[0]) && empty($types[0])) {\n            throw new RuntimeException('The first parameter of the given Closure is missing a type hint.');\n        }\n\n        return $types[0];\n    }\n\n    /**\n     * Get the class names / types of the parameters of the given Closure.\n     *\n     * @param  \\Closure  $closure\n     * @return array\n     *\n     * @throws \\ReflectionException\n     */\n    protected function closureParameterTypes(Closure $closure)\n    {\n        $reflection = new ReflectionFunction($closure);\n\n        return collect($reflection->getParameters())->mapWithKeys(function ($parameter) {\n            if ($parameter->isVariadic()) {\n                return [$parameter->getName() => null];\n            }\n\n            return [$parameter->getName() => Reflector::getParameterClassName($parameter)];\n        })->all();\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/Traits/Tappable.php",
    "content": "<?php\n\nnamespace Illuminate\\Support\\Traits;\n\ntrait Tappable\n{\n    /**\n     * Call the given Closure with this instance then return the instance.\n     *\n     * @param  callable|null  $callback\n     * @return $this|\\Illuminate\\Support\\HigherOrderTapProxy\n     */\n    public function tap($callback = null)\n    {\n        return tap($this, $callback);\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/ValidatedInput.php",
    "content": "<?php\n\nnamespace Illuminate\\Support;\n\nuse ArrayIterator;\nuse Illuminate\\Contracts\\Support\\ValidatedData;\nuse stdClass;\n\nclass ValidatedInput implements ValidatedData\n{\n    /**\n     * The underlying input.\n     *\n     * @var array\n     */\n    protected $input;\n\n    /**\n     * Create a new validated input container.\n     *\n     * @param  array  $input\n     * @return void\n     */\n    public function __construct(array $input)\n    {\n        $this->input = $input;\n    }\n\n    /**\n     * Get a subset containing the provided keys with values from the input data.\n     *\n     * @param  array|mixed  $keys\n     * @return array\n     */\n    public function only($keys)\n    {\n        $results = [];\n\n        $input = $this->input;\n\n        $placeholder = new stdClass;\n\n        foreach (is_array($keys) ? $keys : func_get_args() as $key) {\n            $value = data_get($input, $key, $placeholder);\n\n            if ($value !== $placeholder) {\n                Arr::set($results, $key, $value);\n            }\n        }\n\n        return $results;\n    }\n\n    /**\n     * Get all of the input except for a specified array of items.\n     *\n     * @param  array|mixed  $keys\n     * @return array\n     */\n    public function except($keys)\n    {\n        $keys = is_array($keys) ? $keys : func_get_args();\n\n        $results = $this->input;\n\n        Arr::forget($results, $keys);\n\n        return $results;\n    }\n\n    /**\n     * Merge the validated input with the given array of additional data.\n     *\n     * @param  array  $items\n     * @return static\n     */\n    public function merge(array $items)\n    {\n        return new static(array_merge($this->input, $items));\n    }\n\n    /**\n     * Get the input as a collection.\n     *\n     * @return \\Illuminate\\Support\\Collection\n     */\n    public function collect()\n    {\n        return new Collection($this->input);\n    }\n\n    /**\n     * Get the raw, underlying input array.\n     *\n     * @return array\n     */\n    public function all()\n    {\n        return $this->input;\n    }\n\n    /**\n     * Get the instance as an array.\n     *\n     * @return array\n     */\n    public function toArray()\n    {\n        return $this->all();\n    }\n\n    /**\n     * Dynamically access input data.\n     *\n     * @param  string  $name\n     * @return mixed\n     */\n    public function __get($name)\n    {\n        return $this->input[$name];\n    }\n\n    /**\n     * Dynamically set input data.\n     *\n     * @param  string  $name\n     * @param  mixed  $value\n     * @return mixed\n     */\n    public function __set($name, $value)\n    {\n        $this->input[$name] = $value;\n    }\n\n    /**\n     * Determine if an input key is set.\n     *\n     * @return bool\n     */\n    public function __isset($name)\n    {\n        return isset($this->input[$name]);\n    }\n\n    /**\n     * Remove an input key.\n     *\n     * @param  string  $name\n     * @return void\n     */\n    public function __unset($name)\n    {\n        unset($this->input[$name]);\n    }\n\n    /**\n     * Determine if an item exists at an offset.\n     *\n     * @param  mixed  $key\n     * @return bool\n     */\n    #[\\ReturnTypeWillChange]\n    public function offsetExists($key)\n    {\n        return isset($this->input[$key]);\n    }\n\n    /**\n     * Get an item at a given offset.\n     *\n     * @param  mixed  $key\n     * @return mixed\n     */\n    #[\\ReturnTypeWillChange]\n    public function offsetGet($key)\n    {\n        return $this->input[$key];\n    }\n\n    /**\n     * Set the item at a given offset.\n     *\n     * @param  mixed  $key\n     * @param  mixed  $value\n     * @return void\n     */\n    #[\\ReturnTypeWillChange]\n    public function offsetSet($key, $value)\n    {\n        if (is_null($key)) {\n            $this->input[] = $value;\n        } else {\n            $this->input[$key] = $value;\n        }\n    }\n\n    /**\n     * Unset the item at a given offset.\n     *\n     * @param  string  $key\n     * @return void\n     */\n    #[\\ReturnTypeWillChange]\n    public function offsetUnset($key)\n    {\n        unset($this->input[$key]);\n    }\n\n    /**\n     * Get an iterator for the input.\n     *\n     * @return \\ArrayIterator\n     */\n    #[\\ReturnTypeWillChange]\n    public function getIterator()\n    {\n        return new ArrayIterator($this->input);\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/ViewErrorBag.php",
    "content": "<?php\n\nnamespace Illuminate\\Support;\n\nuse Countable;\nuse Illuminate\\Contracts\\Support\\MessageBag as MessageBagContract;\n\n/**\n * @mixin \\Illuminate\\Contracts\\Support\\MessageBag\n */\nclass ViewErrorBag implements Countable\n{\n    /**\n     * The array of the view error bags.\n     *\n     * @var array\n     */\n    protected $bags = [];\n\n    /**\n     * Checks if a named MessageBag exists in the bags.\n     *\n     * @param  string  $key\n     * @return bool\n     */\n    public function hasBag($key = 'default')\n    {\n        return isset($this->bags[$key]);\n    }\n\n    /**\n     * Get a MessageBag instance from the bags.\n     *\n     * @param  string  $key\n     * @return \\Illuminate\\Contracts\\Support\\MessageBag\n     */\n    public function getBag($key)\n    {\n        return Arr::get($this->bags, $key) ?: new MessageBag;\n    }\n\n    /**\n     * Get all the bags.\n     *\n     * @return array\n     */\n    public function getBags()\n    {\n        return $this->bags;\n    }\n\n    /**\n     * Add a new MessageBag instance to the bags.\n     *\n     * @param  string  $key\n     * @param  \\Illuminate\\Contracts\\Support\\MessageBag  $bag\n     * @return $this\n     */\n    public function put($key, MessageBagContract $bag)\n    {\n        $this->bags[$key] = $bag;\n\n        return $this;\n    }\n\n    /**\n     * Determine if the default message bag has any messages.\n     *\n     * @return bool\n     */\n    public function any()\n    {\n        return $this->count() > 0;\n    }\n\n    /**\n     * Get the number of messages in the default bag.\n     *\n     * @return int\n     */\n    #[\\ReturnTypeWillChange]\n    public function count()\n    {\n        return $this->getBag('default')->count();\n    }\n\n    /**\n     * Dynamically call methods on the default bag.\n     *\n     * @param  string  $method\n     * @param  array  $parameters\n     * @return mixed\n     */\n    public function __call($method, $parameters)\n    {\n        return $this->getBag('default')->$method(...$parameters);\n    }\n\n    /**\n     * Dynamically access a view error bag.\n     *\n     * @param  string  $key\n     * @return \\Illuminate\\Contracts\\Support\\MessageBag\n     */\n    public function __get($key)\n    {\n        return $this->getBag($key);\n    }\n\n    /**\n     * Dynamically set a view error bag.\n     *\n     * @param  string  $key\n     * @param  \\Illuminate\\Contracts\\Support\\MessageBag  $value\n     * @return void\n     */\n    public function __set($key, $value)\n    {\n        $this->put($key, $value);\n    }\n\n    /**\n     * Convert the default bag to its string representation.\n     *\n     * @return string\n     */\n    public function __toString()\n    {\n        return (string) $this->getBag('default');\n    }\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/composer.json",
    "content": "{\n    \"name\": \"illuminate/support\",\n    \"description\": \"The Illuminate Support package.\",\n    \"license\": \"MIT\",\n    \"homepage\": \"https://laravel.com\",\n    \"support\": {\n        \"issues\": \"https://github.com/laravel/framework/issues\",\n        \"source\": \"https://github.com/laravel/framework\"\n    },\n    \"authors\": [\n        {\n            \"name\": \"Taylor Otwell\",\n            \"email\": \"taylor@laravel.com\"\n        }\n    ],\n    \"require\": {\n        \"php\": \"^7.3|^8.0\",\n        \"ext-json\": \"*\",\n        \"ext-mbstring\": \"*\",\n        \"doctrine/inflector\": \"^1.4|^2.0\",\n        \"illuminate/collections\": \"^8.0\",\n        \"illuminate/contracts\": \"^8.0\",\n        \"illuminate/macroable\": \"^8.0\",\n        \"nesbot/carbon\": \"^2.53.1\",\n        \"voku/portable-ascii\": \"^1.6.1\"\n    },\n    \"conflict\": {\n        \"tightenco/collect\": \"<5.5.33\"\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"Illuminate\\\\Support\\\\\": \"\"\n        },\n        \"files\": [\n            \"helpers.php\"\n        ]\n    },\n    \"extra\": {\n        \"branch-alias\": {\n            \"dev-master\": \"8.x-dev\"\n        }\n    },\n    \"suggest\": {\n        \"illuminate/filesystem\": \"Required to use the composer class (^8.0).\",\n        \"league/commonmark\": \"Required to use Str::markdown() and Stringable::markdown() (^1.3|^2.0.2).\",\n        \"ramsey/uuid\": \"Required to use Str::uuid() (^4.2.2).\",\n        \"symfony/process\": \"Required to use the composer class (^5.4).\",\n        \"symfony/var-dumper\": \"Required to use the dd function (^5.4).\",\n        \"vlucas/phpdotenv\": \"Required to use the Env class and env helper (^5.4.1).\"\n    },\n    \"config\": {\n        \"sort-packages\": true\n    },\n    \"minimum-stability\": \"dev\"\n}\n"
  },
  {
    "path": "server/vendor/illuminate/support/helpers.php",
    "content": "<?php\n\nuse Illuminate\\Contracts\\Support\\DeferringDisplayableValue;\nuse Illuminate\\Contracts\\Support\\Htmlable;\nuse Illuminate\\Support\\Arr;\nuse Illuminate\\Support\\Env;\nuse Illuminate\\Support\\HigherOrderTapProxy;\nuse Illuminate\\Support\\Optional;\n\nif (! function_exists('append_config')) {\n    /**\n     * Assign high numeric IDs to a config item to force appending.\n     *\n     * @param  array  $array\n     * @return array\n     */\n    function append_config(array $array)\n    {\n        $start = 9999;\n\n        foreach ($array as $key => $value) {\n            if (is_numeric($key)) {\n                $start++;\n\n                $array[$start] = Arr::pull($array, $key);\n            }\n        }\n\n        return $array;\n    }\n}\n\nif (! function_exists('blank')) {\n    /**\n     * Determine if the given value is \"blank\".\n     *\n     * @param  mixed  $value\n     * @return bool\n     */\n    function blank($value)\n    {\n        if (is_null($value)) {\n            return true;\n        }\n\n        if (is_string($value)) {\n            return trim($value) === '';\n        }\n\n        if (is_numeric($value) || is_bool($value)) {\n            return false;\n        }\n\n        if ($value instanceof Countable) {\n            return count($value) === 0;\n        }\n\n        return empty($value);\n    }\n}\n\nif (! function_exists('class_basename')) {\n    /**\n     * Get the class \"basename\" of the given object / class.\n     *\n     * @param  string|object  $class\n     * @return string\n     */\n    function class_basename($class)\n    {\n        $class = is_object($class) ? get_class($class) : $class;\n\n        return basename(str_replace('\\\\', '/', $class));\n    }\n}\n\nif (! function_exists('class_uses_recursive')) {\n    /**\n     * Returns all traits used by a class, its parent classes and trait of their traits.\n     *\n     * @param  object|string  $class\n     * @return array\n     */\n    function class_uses_recursive($class)\n    {\n        if (is_object($class)) {\n            $class = get_class($class);\n        }\n\n        $results = [];\n\n        foreach (array_reverse(class_parents($class)) + [$class => $class] as $class) {\n            $results += trait_uses_recursive($class);\n        }\n\n        return array_unique($results);\n    }\n}\n\nif (! function_exists('e')) {\n    /**\n     * Encode HTML special characters in a string.\n     *\n     * @param  \\Illuminate\\Contracts\\Support\\DeferringDisplayableValue|\\Illuminate\\Contracts\\Support\\Htmlable|string|null  $value\n     * @param  bool  $doubleEncode\n     * @return string\n     */\n    function e($value, $doubleEncode = true)\n    {\n        if ($value instanceof DeferringDisplayableValue) {\n            $value = $value->resolveDisplayableValue();\n        }\n\n        if ($value instanceof Htmlable) {\n            return $value->toHtml();\n        }\n\n        return htmlspecialchars($value ?? '', ENT_QUOTES, 'UTF-8', $doubleEncode);\n    }\n}\n\nif (! function_exists('env')) {\n    /**\n     * Gets the value of an environment variable.\n     *\n     * @param  string  $key\n     * @param  mixed  $default\n     * @return mixed\n     */\n    function env($key, $default = null)\n    {\n        return Env::get($key, $default);\n    }\n}\n\nif (! function_exists('filled')) {\n    /**\n     * Determine if a value is \"filled\".\n     *\n     * @param  mixed  $value\n     * @return bool\n     */\n    function filled($value)\n    {\n        return ! blank($value);\n    }\n}\n\nif (! function_exists('object_get')) {\n    /**\n     * Get an item from an object using \"dot\" notation.\n     *\n     * @param  object  $object\n     * @param  string|null  $key\n     * @param  mixed  $default\n     * @return mixed\n     */\n    function object_get($object, $key, $default = null)\n    {\n        if (is_null($key) || trim($key) === '') {\n            return $object;\n        }\n\n        foreach (explode('.', $key) as $segment) {\n            if (! is_object($object) || ! isset($object->{$segment})) {\n                return value($default);\n            }\n\n            $object = $object->{$segment};\n        }\n\n        return $object;\n    }\n}\n\nif (! function_exists('optional')) {\n    /**\n     * Provide access to optional objects.\n     *\n     * @param  mixed  $value\n     * @param  callable|null  $callback\n     * @return mixed\n     */\n    function optional($value = null, callable $callback = null)\n    {\n        if (is_null($callback)) {\n            return new Optional($value);\n        } elseif (! is_null($value)) {\n            return $callback($value);\n        }\n    }\n}\n\nif (! function_exists('preg_replace_array')) {\n    /**\n     * Replace a given pattern with each value in the array in sequentially.\n     *\n     * @param  string  $pattern\n     * @param  array  $replacements\n     * @param  string  $subject\n     * @return string\n     */\n    function preg_replace_array($pattern, array $replacements, $subject)\n    {\n        return preg_replace_callback($pattern, function () use (&$replacements) {\n            foreach ($replacements as $key => $value) {\n                return array_shift($replacements);\n            }\n        }, $subject);\n    }\n}\n\nif (! function_exists('retry')) {\n    /**\n     * Retry an operation a given number of times.\n     *\n     * @param  int  $times\n     * @param  callable  $callback\n     * @param  int|\\Closure  $sleepMilliseconds\n     * @param  callable|null  $when\n     * @return mixed\n     *\n     * @throws \\Exception\n     */\n    function retry($times, callable $callback, $sleepMilliseconds = 0, $when = null)\n    {\n        $attempts = 0;\n\n        beginning:\n        $attempts++;\n        $times--;\n\n        try {\n            return $callback($attempts);\n        } catch (Exception $e) {\n            if ($times < 1 || ($when && ! $when($e))) {\n                throw $e;\n            }\n\n            if ($sleepMilliseconds) {\n                usleep(value($sleepMilliseconds, $attempts) * 1000);\n            }\n\n            goto beginning;\n        }\n    }\n}\n\nif (! function_exists('tap')) {\n    /**\n     * Call the given Closure with the given value then return the value.\n     *\n     * @param  mixed  $value\n     * @param  callable|null  $callback\n     * @return mixed\n     */\n    function tap($value, $callback = null)\n    {\n        if (is_null($callback)) {\n            return new HigherOrderTapProxy($value);\n        }\n\n        $callback($value);\n\n        return $value;\n    }\n}\n\nif (! function_exists('throw_if')) {\n    /**\n     * Throw the given exception if the given condition is true.\n     *\n     * @param  mixed  $condition\n     * @param  \\Throwable|string  $exception\n     * @param  mixed  ...$parameters\n     * @return mixed\n     *\n     * @throws \\Throwable\n     */\n    function throw_if($condition, $exception = 'RuntimeException', ...$parameters)\n    {\n        if ($condition) {\n            if (is_string($exception) && class_exists($exception)) {\n                $exception = new $exception(...$parameters);\n            }\n\n            throw is_string($exception) ? new RuntimeException($exception) : $exception;\n        }\n\n        return $condition;\n    }\n}\n\nif (! function_exists('throw_unless')) {\n    /**\n     * Throw the given exception unless the given condition is true.\n     *\n     * @param  mixed  $condition\n     * @param  \\Throwable|string  $exception\n     * @param  mixed  ...$parameters\n     * @return mixed\n     *\n     * @throws \\Throwable\n     */\n    function throw_unless($condition, $exception = 'RuntimeException', ...$parameters)\n    {\n        throw_if(! $condition, $exception, ...$parameters);\n\n        return $condition;\n    }\n}\n\nif (! function_exists('trait_uses_recursive')) {\n    /**\n     * Returns all traits used by a trait and its traits.\n     *\n     * @param  string  $trait\n     * @return array\n     */\n    function trait_uses_recursive($trait)\n    {\n        $traits = class_uses($trait) ?: [];\n\n        foreach ($traits as $trait) {\n            $traits += trait_uses_recursive($trait);\n        }\n\n        return $traits;\n    }\n}\n\nif (! function_exists('transform')) {\n    /**\n     * Transform the given value if it is present.\n     *\n     * @param  mixed  $value\n     * @param  callable  $callback\n     * @param  mixed  $default\n     * @return mixed|null\n     */\n    function transform($value, callable $callback, $default = null)\n    {\n        if (filled($value)) {\n            return $callback($value);\n        }\n\n        if (is_callable($default)) {\n            return $default($value);\n        }\n\n        return $default;\n    }\n}\n\nif (! function_exists('windows_os')) {\n    /**\n     * Determine whether the current environment is Windows based.\n     *\n     * @return bool\n     */\n    function windows_os()\n    {\n        return PHP_OS_FAMILY === 'Windows';\n    }\n}\n\nif (! function_exists('with')) {\n    /**\n     * Return the given value, optionally passed through the given callback.\n     *\n     * @param  mixed  $value\n     * @param  callable|null  $callback\n     * @return mixed\n     */\n    function with($value, callable $callback = null)\n    {\n        return is_null($callback) ? $value : $callback($value);\n    }\n}\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/CAS.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * PHP Version 7\n *\n * @file     CAS.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\nrequire_once __DIR__.'/source/CAS.php';\n\ntrigger_error('Including CAS.php is deprecated. Install phpCAS using composer instead.', E_USER_DEPRECATED);\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/LICENSE",
    "content": "                                 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.\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/NOTICE",
    "content": "Copyright 2007-2011, JA-SIG, Inc.\nThis project includes software developed by Jasig.\nhttp://www.jasig.org/\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this software except in compliance with the License.\nYou may obtain a copy of the License at:\n\nhttp://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n\n===========================================================================\n\nCopyright © 2003-2007, The ESUP-Portail consortium\n\nRequirements for sources originally licensed under the New BSD License:\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions\nare met:\n\n- Redistributions of source code must retain the above copyright notice,\nthis list of conditions and the following disclaimer.\n\n- Redistributions in binary form must reproduce the above copyright notice,\nthis list of conditions and the following disclaimer in the documentation\nand/or other materials provided with the distribution.\n\n- Neither the name of JA-SIG, Inc. nor the names of its contributors may be\nused to endorse or promote products derived from this software without\nspecific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\nLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\nCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\nSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\nINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\nCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\nARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE.\n\n===========================================================================\n\nCopyright (c) 2009, Regents of the University of Nebraska\nAll rights reserved.\n\nRequirements for CAS_Autloader originally licensed under the New BSD License:\n\nRedistribution and use in source and binary forms, with or without modification,\nare permitted provided that the following conditions are met:\n\nRedistributions of source code must retain the above copyright notice, this list\nof conditions and the following disclaimer.\n\nRedistributions in binary form must reproduce the above copyright notice, this\nlist of conditions and the following disclaimer in the documentation and/or\nother materials provided with the distribution.\n\nNeither the name of the University of Nebraska nor the names of its contributors\nmay be used to endorse or promote products derived from this software without\nspecific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\nLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\nCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\nSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\nINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\nCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\nARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/README.md",
    "content": "phpCAS\n=======\n\nphpCAS is an authentication library that allows PHP applications to easily authenticate\nusers via a Central Authentication Service (CAS) server.\n\nPlease see the wiki website for more information:\n\nhttps://apereo.github.io/phpCAS/\n\nApi documentation can be found here:\n\nhttps://apereo.github.io/phpCAS/api/\n\n\n[![Test](https://github.com/apereo/phpCAS/actions/workflows/test.yml/badge.svg)](https://github.com/apereo/phpCAS/actions/workflows/test.yml)\n\nLICENSE\n-------\n\nCopyright 2007-2020, Apereo Foundation.\nThis project includes software developed by Apereo Foundation.\nhttp://www.apereo.org/\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this software except in compliance with the License.\nYou may obtain a copy of the License at:\n\nhttp://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/composer.json",
    "content": "{\n\t\"name\" : \"apereo/phpcas\",\n\t\"description\" : \"Provides a simple API for authenticating users against a CAS server\",\n\t\"keywords\" : [\n\t\t\"cas\",\n\t\t\"jasig\",\n\t\t\"apereo\"\n\t],\n\t\"homepage\" : \"https://wiki.jasig.org/display/CASC/phpCAS\",\n\t\"type\" : \"library\",\n\t\"license\" : \"Apache-2.0\",\n\t\"authors\" : [{\n\t\t\t\"name\" : \"Joachim Fritschi\",\n\t\t\t\"homepage\" : \"https://github.com/jfritschi\",\n\t\t\t\"email\" : \"jfritschi@freenet.de\"\n\t\t}, {\n\t\t\t\"name\" : \"Adam Franco\",\n\t\t\t\"homepage\" : \"https://github.com/adamfranco\"\n\t\t}, {\n\t\t\t\"name\" : \"Henry Pan\",\n\t\t\t\"homepage\" : \"https://github.com/phy25\"\n\t\t}\n\t],\n\t\"require\" : {\n\t\t\"php\" : \">=7.1.0\",\n\t\t\"ext-curl\" : \"*\",\n\t\t\"ext-dom\"  : \"*\",\n\t\t\"psr/log\" : \"^1.0 || ^2.0 || ^3.0\"\n    },\n\t\"require-dev\" : {\n\t\t\"monolog/monolog\" : \"^1.0.0 || ^2.0.0\",\n\t\t\"phpunit/phpunit\" : \">=7.5\", \n\t\t\"phpstan/phpstan\" : \"^1.5\"\n\t},\n\t\"autoload\" : {\n\t\t\"files\": [\"source/CAS.php\"],\n\t\t\"classmap\" : [\n\t\t\t\"source/\"\n\t\t]\n\t},\n\t\"autoload-dev\" : {\n\t\t\"psr-4\" : {\n\t\t\t\"PhpCas\\\\\" : \"test/CAS/\"\n\t\t}\n\t},\n\t\"scripts\" : {\n\t\t\"test\" : \"phpunit\", \n\t\t\"phpstan\" : \"phpstan\"\n\t},\n\t\"extra\" : {\n\t\t\"branch-alias\" : {\n\t\t\t\"dev-master\" : \"1.3.x-dev\"\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/AuthenticationException.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * PHP Version 7\n *\n * @file     CAS/AuthenticationException.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Joachim Fritschi <jfritschi@freenet.de>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\n/**\n * This interface defines methods that allow proxy-authenticated service handlers\n * to interact with phpCAS.\n *\n * Proxy service handlers must implement this interface as well as call\n * phpCAS::initializeProxiedService($this) at some point in their implementation.\n *\n * While not required, proxy-authenticated service handlers are encouraged to\n * implement the CAS_ProxiedService_Testable interface to facilitate unit testing.\n *\n * @class    CAS_AuthenticationException\n * @category Authentication\n * @package  PhpCAS\n * @author   Joachim Fritschi <jfritschi@freenet.de>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\nclass CAS_AuthenticationException\nextends RuntimeException\nimplements CAS_Exception\n{\n\n    /**\n     * This method is used to print the HTML output when the user was not\n     * authenticated.\n     *\n     * @param CAS_Client $client       phpcas client\n     * @param string     $failure      the failure that occured\n     * @param string     $cas_url      the URL the CAS server was asked for\n     * @param bool       $no_response  the response from the CAS server (other\n     * parameters are ignored if TRUE)\n     * @param bool       $bad_response bad response from the CAS server ($err_code\n     * and $err_msg ignored if TRUE)\n     * @param string     $cas_response the response of the CAS server\n     * @param int        $err_code     the error code given by the CAS server\n     * @param string     $err_msg      the error message given by the CAS server\n     */\n    public function __construct($client,$failure,$cas_url,$no_response,\n        $bad_response=false,$cas_response='',$err_code=-1,$err_msg=''\n    ) {\n        $messages = array();\n        phpCAS::traceBegin();\n        $lang = $client->getLangObj();\n        $client->printHTMLHeader($lang->getAuthenticationFailed());\n\n        if (phpCAS::getVerbose()) {\n            printf(\n                $lang->getYouWereNotAuthenticated(),\n                htmlentities($client->getURL()),\n                $_SERVER['SERVER_ADMIN'] ?? ''\n            );\n        }\n\n        phpCAS::trace($messages[] = 'CAS URL: '.$cas_url);\n        phpCAS::trace($messages[] = 'Authentication failure: '.$failure);\n        if ( $no_response ) {\n            phpCAS::trace($messages[] = 'Reason: no response from the CAS server');\n        } else {\n            if ( $bad_response ) {\n                phpCAS::trace($messages[] = 'Reason: bad response from the CAS server');\n            } else {\n                switch ($client->getServerVersion()) {\n                case CAS_VERSION_1_0:\n                    phpCAS::trace($messages[] = 'Reason: CAS error');\n                    break;\n                case CAS_VERSION_2_0:\n                case CAS_VERSION_3_0:\n                    if ( $err_code === -1 ) {\n                        phpCAS::trace($messages[] = 'Reason: no CAS error');\n                    } else {\n                        phpCAS::trace($messages[] = 'Reason: ['.$err_code.'] CAS error: '.$err_msg);\n                    }\n                    break;\n                }\n            }\n            phpCAS::trace($messages[] = 'CAS response: '.$cas_response);\n        }\n        $client->printHTMLFooter();\n        phpCAS::traceExit();\n\n        parent::__construct(implode(\"\\n\", $messages));\n    }\n\n}\n?>\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/Autoload.php",
    "content": "<?php\n\n/**\n * Autoloader Class\n *\n *  PHP Version 7\n *\n * @file      CAS/Autoload.php\n * @category  Authentication\n * @package   SimpleCAS\n * @author    Brett Bieber <brett.bieber@gmail.com>\n * @copyright 2008 Regents of the University of Nebraska\n * @license   http://www1.unl.edu/wdn/wiki/Software_License BSD License\n * @link      http://code.google.com/p/simplecas/\n **/\n\n/**\n * Autoload a class\n *\n * @param string $class Classname to load\n *\n * @return bool\n */\nfunction CAS_autoload($class)\n{\n    // Static to hold the Include Path to CAS\n    static $include_path;\n    // Check only for CAS classes\n    if (substr($class, 0, 4) !== 'CAS_' && substr($class, 0, 7) !== 'PhpCas\\\\') {\n        return false;\n    }\n\n    // Setup the include path if it's not already set from a previous call\n    if (empty($include_path)) {\n        $include_path = array(dirname(__DIR__));\n    }\n\n    // Declare local variable to store the expected full path to the file\n    foreach ($include_path as $path) {\n        $class_path = str_replace('_', DIRECTORY_SEPARATOR, $class);\n        // PhpCas namespace mapping\n        if (substr($class_path, 0, 7) === 'PhpCas\\\\') {\n            $class_path = 'CAS' . DIRECTORY_SEPARATOR . substr($class_path, 7);\n        }\n\n        $file_path = $path . DIRECTORY_SEPARATOR . $class_path . '.php';\n        $fp = @fopen($file_path, 'r', true);\n        if ($fp) {\n            fclose($fp);\n            include $file_path;\n            if (!class_exists($class, false) && !interface_exists($class, false)) {\n                die(\n                    new Exception(\n                        'Class ' . $class . ' was not present in ' .\n                        $file_path .\n                        ' [CAS_autoload]'\n                    )\n                );\n            }\n            return true;\n        }\n    }\n\n    $e = new Exception(\n        'Class ' . $class . ' could not be loaded from ' .\n        $file_path . ', file does not exist (Path=\"'\n        . implode(':', $include_path) .'\") [CAS_autoload]'\n    );\n    $trace = $e->getTrace();\n    if (isset($trace[2]) && isset($trace[2]['function'])\n        && in_array($trace[2]['function'], array('class_exists', 'interface_exists', 'trait_exists'))\n    ) {\n        return false;\n    }\n    if (isset($trace[1]) && isset($trace[1]['function'])\n        && in_array($trace[1]['function'], array('class_exists', 'interface_exists', 'trait_exists'))\n    ) {\n        return false;\n    }\n    die ((string) $e);\n}\n\n// Set up autoload if not already configured by composer.\nif (!class_exists('CAS_Client'))\n{\n    trigger_error('phpCAS autoloader is deprecated. Install phpCAS using composer instead.', E_USER_DEPRECATED);\n    spl_autoload_register('CAS_autoload');\n    if (function_exists('__autoload')\n        && !in_array('__autoload', spl_autoload_functions())\n    ) {\n        // __autoload() was being used, but now would be ignored, add\n        // it to the autoload stack\n        spl_autoload_register('__autoload');\n    }\n}\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/Client.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * PHP Version 7\n *\n * @file     CAS/Client.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Pascal Aubry <pascal.aubry@univ-rennes1.fr>\n * @author   Olivier Berger <olivier.berger@it-sudparis.eu>\n * @author   Brett Bieber <brett.bieber@gmail.com>\n * @author   Joachim Fritschi <jfritschi@freenet.de>\n * @author   Adam Franco <afranco@middlebury.edu>\n * @author   Tobias Schiebeck <tobias.schiebeck@manchester.ac.uk>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\n/**\n * The CAS_Client class is a client interface that provides CAS authentication\n * to PHP applications.\n *\n * @class    CAS_Client\n * @category Authentication\n * @package  PhpCAS\n * @author   Pascal Aubry <pascal.aubry@univ-rennes1.fr>\n * @author   Olivier Berger <olivier.berger@it-sudparis.eu>\n * @author   Brett Bieber <brett.bieber@gmail.com>\n * @author   Joachim Fritschi <jfritschi@freenet.de>\n * @author   Adam Franco <afranco@middlebury.edu>\n * @author   Tobias Schiebeck <tobias.schiebeck@manchester.ac.uk>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n *\n */\n\nclass CAS_Client\n{\n\n    // ########################################################################\n    //  HTML OUTPUT\n    // ########################################################################\n    /**\n    * @addtogroup internalOutput\n    * @{\n    */\n\n    /**\n     * This method filters a string by replacing special tokens by appropriate values\n     * and prints it. The corresponding tokens are taken into account:\n     * - __CAS_VERSION__\n     * - __PHPCAS_VERSION__\n     * - __SERVER_BASE_URL__\n     *\n     * Used by CAS_Client::PrintHTMLHeader() and CAS_Client::printHTMLFooter().\n     *\n     * @param string $str the string to filter and output\n     *\n     * @return void\n     */\n    private function _htmlFilterOutput($str)\n    {\n        $str = str_replace('__CAS_VERSION__', $this->getServerVersion(), $str);\n        $str = str_replace('__PHPCAS_VERSION__', phpCAS::getVersion(), $str);\n        $str = str_replace('__SERVER_BASE_URL__', $this->_getServerBaseURL(), $str);\n        echo $str;\n    }\n\n    /**\n     * A string used to print the header of HTML pages. Written by\n     * CAS_Client::setHTMLHeader(), read by CAS_Client::printHTMLHeader().\n     *\n     * @hideinitializer\n     * @see CAS_Client::setHTMLHeader, CAS_Client::printHTMLHeader()\n     */\n    private $_output_header = '';\n\n    /**\n     * This method prints the header of the HTML output (after filtering). If\n     * CAS_Client::setHTMLHeader() was not used, a default header is output.\n     *\n     * @param string $title the title of the page\n     *\n     * @return void\n     * @see _htmlFilterOutput()\n     */\n    public function printHTMLHeader($title)\n    {\n        if (!phpCAS::getVerbose()) {\n            return;\n        }\n\n        $this->_htmlFilterOutput(\n            str_replace(\n                '__TITLE__', $title,\n                (empty($this->_output_header)\n                ? '<html><head><title>__TITLE__</title></head><body><h1>__TITLE__</h1>'\n                : $this->_output_header)\n            )\n        );\n    }\n\n    /**\n     * A string used to print the footer of HTML pages. Written by\n     * CAS_Client::setHTMLFooter(), read by printHTMLFooter().\n     *\n     * @hideinitializer\n     * @see CAS_Client::setHTMLFooter, CAS_Client::printHTMLFooter()\n     */\n    private $_output_footer = '';\n\n    /**\n     * This method prints the footer of the HTML output (after filtering). If\n     * CAS_Client::setHTMLFooter() was not used, a default footer is output.\n     *\n     * @return void\n     * @see _htmlFilterOutput()\n     */\n    public function printHTMLFooter()\n    {\n        if (!phpCAS::getVerbose()) {\n            return;\n        }\n\n        $lang = $this->getLangObj();\n        $message = empty($this->_output_footer)\n            ? '<hr><address>phpCAS __PHPCAS_VERSION__ ' . $lang->getUsingServer() .\n              ' <a href=\"__SERVER_BASE_URL__\">__SERVER_BASE_URL__</a> (CAS __CAS_VERSION__)</a></address></body></html>'\n            : $this->_output_footer;\n\n        $this->_htmlFilterOutput($message);\n    }\n\n    /**\n     * This method set the HTML header used for all outputs.\n     *\n     * @param string $header the HTML header.\n     *\n     * @return void\n     */\n    public function setHTMLHeader($header)\n    {\n        // Argument Validation\n        if (gettype($header) != 'string')\n            throw new CAS_TypeMismatchException($header, '$header', 'string');\n\n        $this->_output_header = $header;\n    }\n\n    /**\n     * This method set the HTML footer used for all outputs.\n     *\n     * @param string $footer the HTML footer.\n     *\n     * @return void\n     */\n    public function setHTMLFooter($footer)\n    {\n        // Argument Validation\n        if (gettype($footer) != 'string')\n            throw new CAS_TypeMismatchException($footer, '$footer', 'string');\n\n        $this->_output_footer = $footer;\n    }\n\n    /**\n     * Simple wrapper for printf function, that respects\n     * phpCAS verbosity setting.\n     *\n     * @param string $format\n     * @param string|int|float ...$values\n     *\n     * @see printf()\n     */\n    private function printf(string $format, ...$values): void\n    {\n        if (phpCAS::getVerbose()) {\n            printf($format, ...$values);\n        }\n    }\n\n    /** @} */\n\n\n    // ########################################################################\n    //  INTERNATIONALIZATION\n    // ########################################################################\n    /**\n    * @addtogroup internalLang\n    * @{\n    */\n    /**\n     * A string corresponding to the language used by phpCAS. Written by\n     * CAS_Client::setLang(), read by CAS_Client::getLang().\n\n     * @note debugging information is always in english (debug purposes only).\n     */\n    private $_lang = PHPCAS_LANG_DEFAULT;\n\n    /**\n     * This method is used to set the language used by phpCAS.\n     *\n     * @param string $lang representing the language.\n     *\n     * @return void\n     */\n    public function setLang($lang)\n    {\n        // Argument Validation\n        if (gettype($lang) != 'string')\n            throw new CAS_TypeMismatchException($lang, '$lang', 'string');\n\n        phpCAS::traceBegin();\n        $obj = new $lang();\n        if (!($obj instanceof CAS_Languages_LanguageInterface)) {\n            throw new CAS_InvalidArgumentException(\n                '$className must implement the CAS_Languages_LanguageInterface'\n            );\n        }\n        $this->_lang = $lang;\n        phpCAS::traceEnd();\n    }\n    /**\n     * Create the language\n     *\n     * @return CAS_Languages_LanguageInterface object implementing the class\n     */\n    public function getLangObj()\n    {\n        $classname = $this->_lang;\n        return new $classname();\n    }\n\n    /** @} */\n    // ########################################################################\n    //  CAS SERVER CONFIG\n    // ########################################################################\n    /**\n    * @addtogroup internalConfig\n    * @{\n    */\n\n    /**\n     * a record to store information about the CAS server.\n     * - $_server['version']: the version of the CAS server\n     * - $_server['hostname']: the hostname of the CAS server\n     * - $_server['port']: the port the CAS server is running on\n     * - $_server['uri']: the base URI the CAS server is responding on\n     * - $_server['base_url']: the base URL of the CAS server\n     * - $_server['login_url']: the login URL of the CAS server\n     * - $_server['service_validate_url']: the service validating URL of the\n     *   CAS server\n     * - $_server['proxy_url']: the proxy URL of the CAS server\n     * - $_server['proxy_validate_url']: the proxy validating URL of the CAS server\n     * - $_server['logout_url']: the logout URL of the CAS server\n     *\n     * $_server['version'], $_server['hostname'], $_server['port'] and\n     * $_server['uri'] are written by CAS_Client::CAS_Client(), read by\n     * CAS_Client::getServerVersion(), CAS_Client::_getServerHostname(),\n     * CAS_Client::_getServerPort() and CAS_Client::_getServerURI().\n     *\n     * The other fields are written and read by CAS_Client::_getServerBaseURL(),\n     * CAS_Client::getServerLoginURL(), CAS_Client::getServerServiceValidateURL(),\n     * CAS_Client::getServerProxyValidateURL() and CAS_Client::getServerLogoutURL().\n     *\n     * @hideinitializer\n     */\n    private $_server = array(\n        'version' => '',\n        'hostname' => 'none',\n        'port' => -1,\n        'uri' => 'none');\n\n    /**\n     * This method is used to retrieve the version of the CAS server.\n     *\n     * @return string the version of the CAS server.\n     */\n    public function getServerVersion()\n    {\n        return $this->_server['version'];\n    }\n\n    /**\n     * This method is used to retrieve the hostname of the CAS server.\n     *\n     * @return string the hostname of the CAS server.\n     */\n    private function _getServerHostname()\n    {\n        return $this->_server['hostname'];\n    }\n\n    /**\n     * This method is used to retrieve the port of the CAS server.\n     *\n     * @return int the port of the CAS server.\n     */\n    private function _getServerPort()\n    {\n        return $this->_server['port'];\n    }\n\n    /**\n     * This method is used to retrieve the URI of the CAS server.\n     *\n     * @return string a URI.\n     */\n    private function _getServerURI()\n    {\n        return $this->_server['uri'];\n    }\n\n    /**\n     * This method is used to retrieve the base URL of the CAS server.\n     *\n     * @return string a URL.\n     */\n    private function _getServerBaseURL()\n    {\n        // the URL is build only when needed\n        if ( empty($this->_server['base_url']) ) {\n            $this->_server['base_url'] = 'https://' . $this->_getServerHostname();\n            if ($this->_getServerPort()!=443) {\n                $this->_server['base_url'] .= ':'\n                .$this->_getServerPort();\n            }\n            $this->_server['base_url'] .= $this->_getServerURI();\n        }\n        return $this->_server['base_url'];\n    }\n\n    /**\n     * This method is used to retrieve the login URL of the CAS server.\n     *\n     * @param bool $gateway true to check authentication, false to force it\n     * @param bool $renew   true to force the authentication with the CAS server\n     *\n     * @return string a URL.\n     * @note It is recommended that CAS implementations ignore the \"gateway\"\n     * parameter if \"renew\" is set\n     */\n    public function getServerLoginURL($gateway=false,$renew=false)\n    {\n        phpCAS::traceBegin();\n        // the URL is build only when needed\n        if ( empty($this->_server['login_url']) ) {\n            $this->_server['login_url'] = $this->_buildQueryUrl($this->_getServerBaseURL().'login','service='.urlencode($this->getURL()));\n        }\n        $url = $this->_server['login_url'];\n        if ($renew) {\n            // It is recommended that when the \"renew\" parameter is set, its\n            // value be \"true\"\n            $url = $this->_buildQueryUrl($url, 'renew=true');\n        } elseif ($gateway) {\n            // It is recommended that when the \"gateway\" parameter is set, its\n            // value be \"true\"\n            $url = $this->_buildQueryUrl($url, 'gateway=true');\n        }\n        phpCAS::traceEnd($url);\n        return $url;\n    }\n\n    /**\n     * This method sets the login URL of the CAS server.\n     *\n     * @param string $url the login URL\n     *\n     * @return string login url\n     */\n    public function setServerLoginURL($url)\n    {\n        // Argument Validation\n        if (gettype($url) != 'string')\n            throw new CAS_TypeMismatchException($url, '$url', 'string');\n\n        return $this->_server['login_url'] = $url;\n    }\n\n\n    /**\n     * This method sets the serviceValidate URL of the CAS server.\n     *\n     * @param string $url the serviceValidate URL\n     *\n     * @return string serviceValidate URL\n     */\n    public function setServerServiceValidateURL($url)\n    {\n        // Argument Validation\n        if (gettype($url) != 'string')\n            throw new CAS_TypeMismatchException($url, '$url', 'string');\n\n        return $this->_server['service_validate_url'] = $url;\n    }\n\n\n    /**\n     * This method sets the proxyValidate URL of the CAS server.\n     *\n     * @param string $url the proxyValidate URL\n     *\n     * @return string proxyValidate URL\n     */\n    public function setServerProxyValidateURL($url)\n    {\n        // Argument Validation\n        if (gettype($url) != 'string')\n            throw new CAS_TypeMismatchException($url, '$url', 'string');\n\n        return $this->_server['proxy_validate_url'] = $url;\n    }\n\n\n    /**\n     * This method sets the samlValidate URL of the CAS server.\n     *\n     * @param string $url the samlValidate URL\n     *\n     * @return string samlValidate URL\n     */\n    public function setServerSamlValidateURL($url)\n    {\n        // Argument Validation\n        if (gettype($url) != 'string')\n            throw new CAS_TypeMismatchException($url, '$url', 'string');\n\n        return $this->_server['saml_validate_url'] = $url;\n    }\n\n\n    /**\n     * This method is used to retrieve the service validating URL of the CAS server.\n     *\n     * @return string serviceValidate URL.\n     */\n    public function getServerServiceValidateURL()\n    {\n        phpCAS::traceBegin();\n        // the URL is build only when needed\n        if ( empty($this->_server['service_validate_url']) ) {\n            switch ($this->getServerVersion()) {\n            case CAS_VERSION_1_0:\n                $this->_server['service_validate_url'] = $this->_getServerBaseURL()\n                .'validate';\n                break;\n            case CAS_VERSION_2_0:\n                $this->_server['service_validate_url'] = $this->_getServerBaseURL()\n                .'serviceValidate';\n                break;\n            case CAS_VERSION_3_0:\n                $this->_server['service_validate_url'] = $this->_getServerBaseURL()\n                .'p3/serviceValidate';\n                break;\n            }\n        }\n        $url = $this->_buildQueryUrl(\n            $this->_server['service_validate_url'],\n            'service='.urlencode($this->getURL())\n        );\n        phpCAS::traceEnd($url);\n        return $url;\n    }\n    /**\n     * This method is used to retrieve the SAML validating URL of the CAS server.\n     *\n     * @return string samlValidate URL.\n     */\n    public function getServerSamlValidateURL()\n    {\n        phpCAS::traceBegin();\n        // the URL is build only when needed\n        if ( empty($this->_server['saml_validate_url']) ) {\n            switch ($this->getServerVersion()) {\n            case SAML_VERSION_1_1:\n                $this->_server['saml_validate_url'] = $this->_getServerBaseURL().'samlValidate';\n                break;\n            }\n        }\n\n        $url = $this->_buildQueryUrl(\n            $this->_server['saml_validate_url'],\n            'TARGET='.urlencode($this->getURL())\n        );\n        phpCAS::traceEnd($url);\n        return $url;\n    }\n\n    /**\n     * This method is used to retrieve the proxy validating URL of the CAS server.\n     *\n     * @return string proxyValidate URL.\n     */\n    public function getServerProxyValidateURL()\n    {\n        phpCAS::traceBegin();\n        // the URL is build only when needed\n        if ( empty($this->_server['proxy_validate_url']) ) {\n            switch ($this->getServerVersion()) {\n            case CAS_VERSION_1_0:\n                $this->_server['proxy_validate_url'] = '';\n                break;\n            case CAS_VERSION_2_0:\n                $this->_server['proxy_validate_url'] = $this->_getServerBaseURL().'proxyValidate';\n                break;\n            case CAS_VERSION_3_0:\n                $this->_server['proxy_validate_url'] = $this->_getServerBaseURL().'p3/proxyValidate';\n                break;\n            }\n        }\n        $url = $this->_buildQueryUrl(\n            $this->_server['proxy_validate_url'],\n            'service='.urlencode($this->getURL())\n        );\n        phpCAS::traceEnd($url);\n        return $url;\n    }\n\n\n    /**\n     * This method is used to retrieve the proxy URL of the CAS server.\n     *\n     * @return  string proxy URL.\n     */\n    public function getServerProxyURL()\n    {\n        // the URL is build only when needed\n        if ( empty($this->_server['proxy_url']) ) {\n            switch ($this->getServerVersion()) {\n            case CAS_VERSION_1_0:\n                $this->_server['proxy_url'] = '';\n                break;\n            case CAS_VERSION_2_0:\n            case CAS_VERSION_3_0:\n                $this->_server['proxy_url'] = $this->_getServerBaseURL().'proxy';\n                break;\n            }\n        }\n        return $this->_server['proxy_url'];\n    }\n\n    /**\n     * This method is used to retrieve the logout URL of the CAS server.\n     *\n     * @return string logout URL.\n     */\n    public function getServerLogoutURL()\n    {\n        // the URL is build only when needed\n        if ( empty($this->_server['logout_url']) ) {\n            $this->_server['logout_url'] = $this->_getServerBaseURL().'logout';\n        }\n        return $this->_server['logout_url'];\n    }\n\n    /**\n     * This method sets the logout URL of the CAS server.\n     *\n     * @param string $url the logout URL\n     *\n     * @return string logout url\n     */\n    public function setServerLogoutURL($url)\n    {\n        // Argument Validation\n        if (gettype($url) != 'string')\n            throw new CAS_TypeMismatchException($url, '$url', 'string');\n\n        return $this->_server['logout_url'] = $url;\n    }\n\n    /**\n     * An array to store extra curl options.\n     */\n    private $_curl_options = array();\n\n    /**\n     * This method is used to set additional user curl options.\n     *\n     * @param string $key   name of the curl option\n     * @param string $value value of the curl option\n     *\n     * @return void\n     */\n    public function setExtraCurlOption($key, $value)\n    {\n        $this->_curl_options[$key] = $value;\n    }\n\n    /** @} */\n\n    // ########################################################################\n    //  Change the internal behaviour of phpcas\n    // ########################################################################\n\n    /**\n     * @addtogroup internalBehave\n     * @{\n     */\n\n    /**\n     * The class to instantiate for making web requests in readUrl().\n     * The class specified must implement the CAS_Request_RequestInterface.\n     * By default CAS_Request_CurlRequest is used, but this may be overridden to\n     * supply alternate request mechanisms for testing.\n     */\n    private $_requestImplementation = 'CAS_Request_CurlRequest';\n\n    /**\n     * Override the default implementation used to make web requests in readUrl().\n     * This class must implement the CAS_Request_RequestInterface.\n     *\n     * @param string $className name of the RequestImplementation class\n     *\n     * @return void\n     */\n    public function setRequestImplementation ($className)\n    {\n        $obj = new $className;\n        if (!($obj instanceof CAS_Request_RequestInterface)) {\n            throw new CAS_InvalidArgumentException(\n                '$className must implement the CAS_Request_RequestInterface'\n            );\n        }\n        $this->_requestImplementation = $className;\n    }\n\n    /**\n     * @var boolean $_clearTicketsFromUrl; If true, phpCAS will clear session\n     * tickets from the URL after a successful authentication.\n     */\n    private $_clearTicketsFromUrl = true;\n\n    /**\n     * Configure the client to not send redirect headers and call exit() on\n     * authentication success. The normal redirect is used to remove the service\n     * ticket from the client's URL, but for running unit tests we need to\n     * continue without exiting.\n     *\n     * Needed for testing authentication\n     *\n     * @return void\n     */\n    public function setNoClearTicketsFromUrl ()\n    {\n        $this->_clearTicketsFromUrl = false;\n    }\n\n    /**\n     * @var callback $_attributeParserCallbackFunction;\n     */\n    private $_casAttributeParserCallbackFunction = null;\n\n    /**\n     * @var array $_attributeParserCallbackArgs;\n     */\n    private $_casAttributeParserCallbackArgs = array();\n\n    /**\n     * Set a callback function to be run when parsing CAS attributes\n     *\n     * The callback function will be passed a XMLNode as its first parameter,\n     * followed by any $additionalArgs you pass.\n     *\n     * @param string $function       callback function to call\n     * @param array  $additionalArgs optional array of arguments\n     *\n     * @return void\n     */\n    public function setCasAttributeParserCallback($function, array $additionalArgs = array())\n    {\n        $this->_casAttributeParserCallbackFunction = $function;\n        $this->_casAttributeParserCallbackArgs = $additionalArgs;\n    }\n\n    /** @var callable $_postAuthenticateCallbackFunction;\n     */\n    private $_postAuthenticateCallbackFunction = null;\n\n    /**\n     * @var array $_postAuthenticateCallbackArgs;\n     */\n    private $_postAuthenticateCallbackArgs = array();\n\n    /**\n     * Set a callback function to be run when a user authenticates.\n     *\n     * The callback function will be passed a $logoutTicket as its first parameter,\n     * followed by any $additionalArgs you pass. The $logoutTicket parameter is an\n     * opaque string that can be used to map a session-id to the logout request\n     * in order to support single-signout in applications that manage their own\n     * sessions (rather than letting phpCAS start the session).\n     *\n     * phpCAS::forceAuthentication() will always exit and forward client unless\n     * they are already authenticated. To perform an action at the moment the user\n     * logs in (such as registering an account, performing logging, etc), register\n     * a callback function here.\n     *\n     * @param callable $function       callback function to call\n     * @param array  $additionalArgs optional array of arguments\n     *\n     * @return void\n     */\n    public function setPostAuthenticateCallback ($function, array $additionalArgs = array())\n    {\n        $this->_postAuthenticateCallbackFunction = $function;\n        $this->_postAuthenticateCallbackArgs = $additionalArgs;\n    }\n\n    /**\n     * @var callable $_signoutCallbackFunction;\n     */\n    private $_signoutCallbackFunction = null;\n\n    /**\n     * @var array $_signoutCallbackArgs;\n     */\n    private $_signoutCallbackArgs = array();\n\n    /**\n     * Set a callback function to be run when a single-signout request is received.\n     *\n     * The callback function will be passed a $logoutTicket as its first parameter,\n     * followed by any $additionalArgs you pass. The $logoutTicket parameter is an\n     * opaque string that can be used to map a session-id to the logout request in\n     * order to support single-signout in applications that manage their own sessions\n     * (rather than letting phpCAS start and destroy the session).\n     *\n     * @param callable $function       callback function to call\n     * @param array  $additionalArgs optional array of arguments\n     *\n     * @return void\n     */\n    public function setSingleSignoutCallback ($function, array $additionalArgs = array())\n    {\n        $this->_signoutCallbackFunction = $function;\n        $this->_signoutCallbackArgs = $additionalArgs;\n    }\n\n    // ########################################################################\n    //  Methods for supplying code-flow feedback to integrators.\n    // ########################################################################\n\n    /**\n     * Ensure that this is actually a proxy object or fail with an exception\n     *\n     * @throws CAS_OutOfSequenceBeforeProxyException\n     *\n     * @return void\n     */\n    public function ensureIsProxy()\n    {\n        if (!$this->isProxy()) {\n            throw new CAS_OutOfSequenceBeforeProxyException();\n        }\n    }\n\n    /**\n     * Mark the caller of authentication. This will help client integraters determine\n     * problems with their code flow if they call a function such as getUser() before\n     * authentication has occurred.\n     *\n     * @param bool $auth True if authentication was successful, false otherwise.\n     *\n     * @return null\n     */\n    public function markAuthenticationCall ($auth)\n    {\n        // store where the authentication has been checked and the result\n        $dbg = debug_backtrace();\n        $this->_authentication_caller = array (\n            'file' => $dbg[1]['file'],\n            'line' => $dbg[1]['line'],\n            'method' => $dbg[1]['class'] . '::' . $dbg[1]['function'],\n            'result' => (boolean)$auth\n        );\n    }\n    private $_authentication_caller;\n\n    /**\n     * Answer true if authentication has been checked.\n     *\n     * @return bool\n     */\n    public function wasAuthenticationCalled ()\n    {\n        return !empty($this->_authentication_caller);\n    }\n\n    /**\n     * Ensure that authentication was checked. Terminate with exception if no\n     * authentication was performed\n     *\n     * @throws CAS_OutOfSequenceBeforeAuthenticationCallException\n     *\n     * @return void\n     */\n    private function _ensureAuthenticationCalled()\n    {\n        if (!$this->wasAuthenticationCalled()) {\n            throw new CAS_OutOfSequenceBeforeAuthenticationCallException();\n        }\n    }\n\n    /**\n     * Answer the result of the authentication call.\n     *\n     * Throws a CAS_OutOfSequenceException if wasAuthenticationCalled() is false\n     * and markAuthenticationCall() didn't happen.\n     *\n     * @return bool\n     */\n    public function wasAuthenticationCallSuccessful ()\n    {\n        $this->_ensureAuthenticationCalled();\n        return $this->_authentication_caller['result'];\n    }\n\n\n    /**\n     * Ensure that authentication was checked. Terminate with exception if no\n     * authentication was performed\n     *\n     * @throws CAS_OutOfSequenceException\n     *\n     * @return void\n     */\n    public function ensureAuthenticationCallSuccessful()\n    {\n        $this->_ensureAuthenticationCalled();\n        if (!$this->_authentication_caller['result']) {\n            throw new CAS_OutOfSequenceException(\n                'authentication was checked (by '\n                . $this->getAuthenticationCallerMethod()\n                . '() at ' . $this->getAuthenticationCallerFile()\n                . ':' . $this->getAuthenticationCallerLine()\n                . ') but the method returned false'\n            );\n        }\n    }\n\n    /**\n     * Answer information about the authentication caller.\n     *\n     * Throws a CAS_OutOfSequenceException if wasAuthenticationCalled() is false\n     * and markAuthenticationCall() didn't happen.\n     *\n     * @return string the file that called authentication\n     */\n    public function getAuthenticationCallerFile ()\n    {\n        $this->_ensureAuthenticationCalled();\n        return $this->_authentication_caller['file'];\n    }\n\n    /**\n     * Answer information about the authentication caller.\n     *\n     * Throws a CAS_OutOfSequenceException if wasAuthenticationCalled() is false\n     * and markAuthenticationCall() didn't happen.\n     *\n     * @return int the line that called authentication\n     */\n    public function getAuthenticationCallerLine ()\n    {\n        $this->_ensureAuthenticationCalled();\n        return $this->_authentication_caller['line'];\n    }\n\n    /**\n     * Answer information about the authentication caller.\n     *\n     * Throws a CAS_OutOfSequenceException if wasAuthenticationCalled() is false\n     * and markAuthenticationCall() didn't happen.\n     *\n     * @return string the method that called authentication\n     */\n    public function getAuthenticationCallerMethod ()\n    {\n        $this->_ensureAuthenticationCalled();\n        return $this->_authentication_caller['method'];\n    }\n\n    /** @} */\n\n    // ########################################################################\n    //  CONSTRUCTOR\n    // ########################################################################\n    /**\n    * @addtogroup internalConfig\n    * @{\n    */\n\n    /**\n     * CAS_Client constructor.\n     *\n     * @param string                   $server_version  the version of the CAS server\n     * @param bool                     $proxy           true if the CAS client is a CAS proxy\n     * @param string                   $server_hostname the hostname of the CAS server\n     * @param int                      $server_port     the port the CAS server is running on\n     * @param string                   $server_uri      the URI the CAS server is responding on\n     * @param bool                     $changeSessionID Allow phpCAS to change the session_id\n     *                                                  (Single Sign Out/handleLogoutRequests\n     *                                                  is based on that change)\n     * @param string|string[]|CAS_ServiceBaseUrl_Interface\n     *                                 $service_base_url the base URL (protocol, host and the\n     *                                                  optional port) of the CAS client; pass\n     *                                                  in an array to use auto discovery with\n     *                                                  an allowlist; pass in\n     *                                                  CAS_ServiceBaseUrl_Interface for custom\n     *                                                  behavior. Added in 1.6.0. Similar to\n     *                                                  serverName config in other CAS clients.\n     * @param \\SessionHandlerInterface $sessionHandler  the session handler\n     *\n     * @return self a newly created CAS_Client object\n     */\n    public function __construct(\n        $server_version,\n        $proxy,\n        $server_hostname,\n        $server_port,\n        $server_uri,\n        $service_base_url,\n        $changeSessionID = true,\n        \\SessionHandlerInterface $sessionHandler = null\n    ) {\n        // Argument validation\n        if (gettype($server_version) != 'string')\n            throw new CAS_TypeMismatchException($server_version, '$server_version', 'string');\n        if (gettype($proxy) != 'boolean')\n            throw new CAS_TypeMismatchException($proxy, '$proxy', 'boolean');\n        if (gettype($server_hostname) != 'string')\n            throw new CAS_TypeMismatchException($server_hostname, '$server_hostname', 'string');\n        if (gettype($server_port) != 'integer')\n            throw new CAS_TypeMismatchException($server_port, '$server_port', 'integer');\n        if (gettype($server_uri) != 'string')\n            throw new CAS_TypeMismatchException($server_uri, '$server_uri', 'string');\n        if (gettype($changeSessionID) != 'boolean')\n            throw new CAS_TypeMismatchException($changeSessionID, '$changeSessionID', 'boolean');\n\n        $this->_setServiceBaseUrl($service_base_url);\n\n        if (empty($sessionHandler)) {\n            $sessionHandler = new CAS_Session_PhpSession;\n        }\n\n        phpCAS::traceBegin();\n        // true : allow to change the session_id(), false session_id won't be\n        // changed and logout won't be handled because of that\n        $this->_setChangeSessionID($changeSessionID);\n\n        $this->setSessionHandler($sessionHandler);\n\n        if (!$this->_isLogoutRequest()) {\n            if (session_id() === \"\") {\n                // skip Session Handling for logout requests and if don't want it\n                session_start();\n                phpCAS :: trace(\"Starting a new session \" . session_id());\n            }\n        }\n\n        // Only for debug purposes\n        if ($this->isSessionAuthenticated()){\n            phpCAS :: trace(\"Session is authenticated as: \" . $this->getSessionValue('user'));\n        } else {\n            phpCAS :: trace(\"Session is not authenticated\");\n        }\n        // are we in proxy mode ?\n        $this->_proxy = $proxy;\n\n        // Make cookie handling available.\n        if ($this->isProxy()) {\n            if (!$this->hasSessionValue('service_cookies')) {\n                $this->setSessionValue('service_cookies', array());\n            }\n            // TODO remove explicit call to $_SESSION\n            $this->_serviceCookieJar = new CAS_CookieJar(\n                $_SESSION[static::PHPCAS_SESSION_PREFIX]['service_cookies']\n            );\n        }\n\n        // check version\n        $supportedProtocols = phpCAS::getSupportedProtocols();\n        if (isset($supportedProtocols[$server_version]) === false) {\n            phpCAS::error(\n                'this version of CAS (`'.$server_version\n                .'\\') is not supported by phpCAS '.phpCAS::getVersion()\n            );\n        }\n\n        if ($server_version === CAS_VERSION_1_0 && $this->isProxy()) {\n            phpCAS::error(\n                'CAS proxies are not supported in CAS '.$server_version\n            );\n        }\n\n        $this->_server['version'] = $server_version;\n\n        // check hostname\n        if ( empty($server_hostname)\n            || !preg_match('/[\\.\\d\\-a-z]*/', $server_hostname)\n        ) {\n            phpCAS::error('bad CAS server hostname (`'.$server_hostname.'\\')');\n        }\n        $this->_server['hostname'] = $server_hostname;\n\n        // check port\n        if ( $server_port == 0\n            || !is_int($server_port)\n        ) {\n            phpCAS::error('bad CAS server port (`'.$server_hostname.'\\')');\n        }\n        $this->_server['port'] = $server_port;\n\n        // check URI\n        if ( !preg_match('/[\\.\\d\\-_a-z\\/]*/', $server_uri) ) {\n            phpCAS::error('bad CAS server URI (`'.$server_uri.'\\')');\n        }\n        // add leading and trailing `/' and remove doubles\n        if(strstr($server_uri, '?') === false) $server_uri .= '/';\n        $server_uri = preg_replace('/\\/\\//', '/', '/'.$server_uri);\n        $this->_server['uri'] = $server_uri;\n\n        // set to callback mode if PgtIou and PgtId CGI GET parameters are provided\n        if ( $this->isProxy() ) {\n            if(!empty($_GET['pgtIou'])&&!empty($_GET['pgtId'])) {\n                $this->_setCallbackMode(true);\n                $this->_setCallbackModeUsingPost(false);\n            } elseif (!empty($_POST['pgtIou'])&&!empty($_POST['pgtId'])) {\n                $this->_setCallbackMode(true);\n                $this->_setCallbackModeUsingPost(true);\n            } else {\n                $this->_setCallbackMode(false);\n                $this->_setCallbackModeUsingPost(false);\n            }\n\n\n        }\n\n        if ( $this->_isCallbackMode() ) {\n            //callback mode: check that phpCAS is secured\n            if ( !$this->getServiceBaseUrl()->isHttps() ) {\n                phpCAS::error(\n                    'CAS proxies must be secured to use phpCAS; PGT\\'s will not be received from the CAS server'\n                );\n            }\n        } else {\n            //normal mode: get ticket and remove it from CGI parameters for\n            // developers\n            $ticket = (isset($_GET['ticket']) ? $_GET['ticket'] : '');\n            if (preg_match('/^[SP]T-/', $ticket) ) {\n                phpCAS::trace('Ticket \\''.$ticket.'\\' found');\n                $this->setTicket($ticket);\n                unset($_GET['ticket']);\n            } else if ( !empty($ticket) ) {\n                //ill-formed ticket, halt\n                phpCAS::error(\n                    'ill-formed ticket found in the URL (ticket=`'\n                    .htmlentities($ticket).'\\')'\n                );\n            }\n\n        }\n        phpCAS::traceEnd();\n    }\n\n    /** @} */\n\n    // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n    // XX                                                                    XX\n    // XX                           Session Handling                         XX\n    // XX                                                                    XX\n    // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n\n    /**\n     * @addtogroup internalConfig\n     * @{\n     */\n\n    /** The session prefix for phpCAS values */\n    const PHPCAS_SESSION_PREFIX = 'phpCAS';\n\n    /**\n     * @var bool A variable to whether phpcas will use its own session handling. Default = true\n     * @hideinitializer\n     */\n    private $_change_session_id = true;\n\n    /**\n     * @var SessionHandlerInterface\n     */\n    private $_sessionHandler;\n\n    /**\n     * Set a parameter whether to allow phpCAS to change session_id\n     *\n     * @param bool $allowed allow phpCAS to change session_id\n     *\n     * @return void\n     */\n    private function _setChangeSessionID($allowed)\n    {\n        $this->_change_session_id = $allowed;\n    }\n\n    /**\n     * Get whether phpCAS is allowed to change session_id\n     *\n     * @return bool\n     */\n    public function getChangeSessionID()\n    {\n        return $this->_change_session_id;\n    }\n\n    /**\n     * Set the session handler.\n     *\n     * @param \\SessionHandlerInterface $sessionHandler\n     *\n     * @return bool\n     */\n    public function setSessionHandler(\\SessionHandlerInterface $sessionHandler)\n    {\n        $this->_sessionHandler = $sessionHandler;\n        if (session_status() !== PHP_SESSION_ACTIVE) {\n            return session_set_save_handler($this->_sessionHandler, true);\n        }\n        return true;\n    }\n\n    /**\n     * Get a session value using the given key.\n     *\n     * @param string $key\n     * @param mixed  $default default value if the key is not set\n     *\n     * @return mixed\n     */\n    protected function getSessionValue($key, $default = null)\n    {\n        $this->validateSession($key);\n\n        if (isset($_SESSION[static::PHPCAS_SESSION_PREFIX][$key])) {\n            return $_SESSION[static::PHPCAS_SESSION_PREFIX][$key];\n        }\n\n        return $default;\n    }\n\n    /**\n     * Determine whether a session value is set or not.\n     *\n     * To check if a session value is empty or not please use\n     * !!(getSessionValue($key)).\n     *\n     * @param string $key\n     *\n     * @return bool\n     */\n    protected function hasSessionValue($key)\n    {\n        $this->validateSession($key);\n\n        return isset($_SESSION[static::PHPCAS_SESSION_PREFIX][$key]);\n    }\n\n    /**\n     * Set a session value using the given key and value.\n     *\n     * @param string $key\n     * @param mixed $value\n     *\n     * @return string\n     */\n    protected function setSessionValue($key, $value)\n    {\n        $this->validateSession($key);\n\n        $this->ensureSessionArray();\n        $_SESSION[static::PHPCAS_SESSION_PREFIX][$key] = $value;\n    }\n\n    /**\n     * Ensure that the session array is initialized before writing to it.\n     */\n    protected function ensureSessionArray() {\n      // init phpCAS session array\n      if (!isset($_SESSION[static::PHPCAS_SESSION_PREFIX])\n          || !is_array($_SESSION[static::PHPCAS_SESSION_PREFIX])) {\n          $_SESSION[static::PHPCAS_SESSION_PREFIX] = array();\n      }\n    }\n\n    /**\n     * Remove a session value with the given key.\n     *\n     * @param string $key\n     */\n    protected function removeSessionValue($key)\n    {\n        $this->validateSession($key);\n\n        if (isset($_SESSION[static::PHPCAS_SESSION_PREFIX][$key])) {\n            unset($_SESSION[static::PHPCAS_SESSION_PREFIX][$key]);\n            return true;\n        }\n\n        return false;\n    }\n\n    /**\n     * Remove all phpCAS session values.\n     */\n    protected function clearSessionValues()\n    {\n        unset($_SESSION[static::PHPCAS_SESSION_PREFIX]);\n    }\n\n    /**\n     * Ensure $key is a string for session utils input\n     *\n     * @param string $key\n     *\n     * @return bool\n     */\n    protected function validateSession($key)\n    {\n        if (!is_string($key)) {\n            throw new InvalidArgumentException('Session key must be a string.');\n        }\n\n        return true;\n    }\n\n    /**\n     * Renaming the session\n     *\n     * @param string $ticket name of the ticket\n     *\n     * @return void\n     */\n    protected function _renameSession($ticket)\n    {\n        phpCAS::traceBegin();\n        if ($this->getChangeSessionID()) {\n            if (!empty($this->_user)) {\n                $old_session = $_SESSION;\n                phpCAS :: trace(\"Killing session: \". session_id());\n                session_destroy();\n                // set up a new session, of name based on the ticket\n                $session_id = $this->_sessionIdForTicket($ticket);\n                phpCAS :: trace(\"Starting session: \". $session_id);\n                session_id($session_id);\n                session_start();\n                phpCAS :: trace(\"Restoring old session vars\");\n                $_SESSION = $old_session;\n            } else {\n                phpCAS :: trace (\n                    'Session should only be renamed after successfull authentication'\n                );\n            }\n        } else {\n            phpCAS :: trace(\n                \"Skipping session rename since phpCAS is not handling the session.\"\n            );\n        }\n        phpCAS::traceEnd();\n    }\n\n    /** @} */\n\n    // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n    // XX                                                                    XX\n    // XX                           AUTHENTICATION                           XX\n    // XX                                                                    XX\n    // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n\n    /**\n     * @addtogroup internalAuthentication\n     * @{\n     */\n\n    /**\n     * The Authenticated user. Written by CAS_Client::_setUser(), read by\n     * CAS_Client::getUser().\n     *\n     * @hideinitializer\n     */\n    private $_user = '';\n\n    /**\n     * This method sets the CAS user's login name.\n     *\n     * @param string $user the login name of the authenticated user.\n     *\n     * @return void\n     */\n    private function _setUser($user)\n    {\n        $this->_user = $user;\n    }\n\n    /**\n     * This method returns the CAS user's login name.\n     *\n     * @return string the login name of the authenticated user\n     *\n     * @warning should be called only after CAS_Client::forceAuthentication() or\n     * CAS_Client::isAuthenticated(), otherwise halt with an error.\n     */\n    public function getUser()\n    {\n        // Sequence validation\n        $this->ensureAuthenticationCallSuccessful();\n\n        return $this->_getUser();\n    }\n\n    /**\n     * This method returns the CAS user's login name.\n     *\n     * @return string the login name of the authenticated user\n     *\n     * @warning should be called only after CAS_Client::forceAuthentication() or\n     * CAS_Client::isAuthenticated(), otherwise halt with an error.\n     */\n    private function _getUser()\n    {\n        // This is likely a duplicate check that could be removed....\n        if ( empty($this->_user) ) {\n            phpCAS::error(\n                'this method should be used only after '.__CLASS__\n                .'::forceAuthentication() or '.__CLASS__.'::isAuthenticated()'\n            );\n        }\n        return $this->_user;\n    }\n\n    /**\n     * The Authenticated users attributes. Written by\n     * CAS_Client::setAttributes(), read by CAS_Client::getAttributes().\n     * @attention client applications should use phpCAS::getAttributes().\n     *\n     * @hideinitializer\n     */\n    private $_attributes = array();\n\n    /**\n     * Set an array of attributes\n     *\n     * @param array $attributes a key value array of attributes\n     *\n     * @return void\n     */\n    public function setAttributes($attributes)\n    {\n        $this->_attributes = $attributes;\n    }\n\n    /**\n     * Get an key values arry of attributes\n     *\n     * @return array of attributes\n     */\n    public function getAttributes()\n    {\n        // Sequence validation\n        $this->ensureAuthenticationCallSuccessful();\n        // This is likely a duplicate check that could be removed....\n        if ( empty($this->_user) ) {\n            // if no user is set, there shouldn't be any attributes also...\n            phpCAS::error(\n                'this method should be used only after '.__CLASS__\n                .'::forceAuthentication() or '.__CLASS__.'::isAuthenticated()'\n            );\n        }\n        return $this->_attributes;\n    }\n\n    /**\n     * Check whether attributes are available\n     *\n     * @return bool attributes available\n     */\n    public function hasAttributes()\n    {\n        // Sequence validation\n        $this->ensureAuthenticationCallSuccessful();\n\n        return !empty($this->_attributes);\n    }\n    /**\n     * Check whether a specific attribute with a name is available\n     *\n     * @param string $key name of attribute\n     *\n     * @return bool is attribute available\n     */\n    public function hasAttribute($key)\n    {\n        // Sequence validation\n        $this->ensureAuthenticationCallSuccessful();\n\n        return $this->_hasAttribute($key);\n    }\n\n    /**\n     * Check whether a specific attribute with a name is available\n     *\n     * @param string $key name of attribute\n     *\n     * @return bool is attribute available\n     */\n    private function _hasAttribute($key)\n    {\n        return (is_array($this->_attributes)\n            && array_key_exists($key, $this->_attributes));\n    }\n\n    /**\n     * Get a specific attribute by name\n     *\n     * @param string $key name of attribute\n     *\n     * @return string attribute values\n     */\n    public function getAttribute($key)\n    {\n        // Sequence validation\n        $this->ensureAuthenticationCallSuccessful();\n\n        if ($this->_hasAttribute($key)) {\n            return $this->_attributes[$key];\n        }\n    }\n\n    /**\n     * This method is called to renew the authentication of the user\n     * If the user is authenticated, renew the connection\n     * If not, redirect to CAS\n     *\n     * @return bool true when the user is authenticated; otherwise halt.\n     */\n    public function renewAuthentication()\n    {\n        phpCAS::traceBegin();\n        // Either way, the user is authenticated by CAS\n        $this->removeSessionValue('auth_checked');\n        if ( $this->isAuthenticated(true) ) {\n            phpCAS::trace('user already authenticated');\n            $res = true;\n        } else {\n            $this->redirectToCas(false, true);\n            // never reached\n            $res = false;\n        }\n        phpCAS::traceEnd();\n        return $res;\n    }\n\n    /**\n     * This method is called to be sure that the user is authenticated. When not\n     * authenticated, halt by redirecting to the CAS server; otherwise return true.\n     *\n     * @return bool true when the user is authenticated; otherwise halt.\n     */\n    public function forceAuthentication()\n    {\n        phpCAS::traceBegin();\n\n        if ( $this->isAuthenticated() ) {\n            // the user is authenticated, nothing to be done.\n            phpCAS::trace('no need to authenticate');\n            $res = true;\n        } else {\n            // the user is not authenticated, redirect to the CAS server\n            $this->removeSessionValue('auth_checked');\n            $this->redirectToCas(false/* no gateway */);\n            // never reached\n            $res = false;\n        }\n        phpCAS::traceEnd($res);\n        return $res;\n    }\n\n    /**\n     * An integer that gives the number of times authentication will be cached\n     * before rechecked.\n     *\n     * @hideinitializer\n     */\n    private $_cache_times_for_auth_recheck = 0;\n\n    /**\n     * Set the number of times authentication will be cached before rechecked.\n     *\n     * @param int $n number of times to wait for a recheck\n     *\n     * @return void\n     */\n    public function setCacheTimesForAuthRecheck($n)\n    {\n        if (gettype($n) != 'integer')\n            throw new CAS_TypeMismatchException($n, '$n', 'string');\n\n        $this->_cache_times_for_auth_recheck = $n;\n    }\n\n    /**\n     * This method is called to check whether the user is authenticated or not.\n     *\n     * @return bool true when the user is authenticated, false when a previous\n     * gateway login failed or  the function will not return if the user is\n     * redirected to the cas server for a gateway login attempt\n     */\n    public function checkAuthentication()\n    {\n        phpCAS::traceBegin();\n        $res = false; // default\n        if ( $this->isAuthenticated() ) {\n            phpCAS::trace('user is authenticated');\n            /* The 'auth_checked' variable is removed just in case it's set. */\n            $this->removeSessionValue('auth_checked');\n            $res = true;\n        } else if ($this->getSessionValue('auth_checked')) {\n            // the previous request has redirected the client to the CAS server\n            // with gateway=true\n            $this->removeSessionValue('auth_checked');\n        } else {\n            // avoid a check against CAS on every request\n            // we need to write this back to session later\n            $unauth_count = $this->getSessionValue('unauth_count', -2);\n\n            if (($unauth_count != -2\n                && $this->_cache_times_for_auth_recheck == -1)\n                || ($unauth_count >= 0\n                && $unauth_count < $this->_cache_times_for_auth_recheck)\n            ) {\n                if ($this->_cache_times_for_auth_recheck != -1) {\n                    $unauth_count++;\n                    phpCAS::trace(\n                        'user is not authenticated (cached for '\n                        .$unauth_count.' times of '\n                        .$this->_cache_times_for_auth_recheck.')'\n                    );\n                } else {\n                    phpCAS::trace(\n                        'user is not authenticated (cached for until login pressed)'\n                    );\n                }\n                $this->setSessionValue('unauth_count', $unauth_count);\n            } else {\n                $this->setSessionValue('unauth_count', 0);\n                $this->setSessionValue('auth_checked', true);\n                phpCAS::trace('user is not authenticated (cache reset)');\n                $this->redirectToCas(true/* gateway */);\n                // never reached\n            }\n        }\n        phpCAS::traceEnd($res);\n        return $res;\n    }\n\n    /**\n     * This method is called to check if the user is authenticated (previously or by\n     * tickets given in the URL).\n     *\n     * @param bool $renew true to force the authentication with the CAS server\n     *\n     * @return bool true when the user is authenticated. Also may redirect to the\n     * same URL without the ticket.\n     */\n    public function isAuthenticated($renew=false)\n    {\n        phpCAS::traceBegin();\n        $res = false;\n\n        if ( $this->_wasPreviouslyAuthenticated() ) {\n            if ($this->hasTicket()) {\n                // User has a additional ticket but was already authenticated\n                phpCAS::trace(\n                    'ticket was present and will be discarded, use renewAuthenticate()'\n                );\n                if ($this->_clearTicketsFromUrl) {\n                    phpCAS::trace(\"Prepare redirect to : \".$this->getURL());\n                    session_write_close();\n                    header('Location: '.$this->getURL());\n                    flush();\n                    phpCAS::traceExit();\n                    throw new CAS_GracefullTerminationException();\n                } else {\n                    phpCAS::trace(\n                        'Already authenticated, but skipping ticket clearing since setNoClearTicketsFromUrl() was used.'\n                    );\n                    $res = true;\n                }\n            } else {\n                // the user has already (previously during the session) been\n                // authenticated, nothing to be done.\n                phpCAS::trace(\n                    'user was already authenticated, no need to look for tickets'\n                );\n                $res = true;\n            }\n\n            // Mark the auth-check as complete to allow post-authentication\n            // callbacks to make use of phpCAS::getUser() and similar methods\n            $this->markAuthenticationCall($res);\n        } else {\n            if ($this->hasTicket()) {\n                $validate_url = '';\n                $text_response = '';\n                $tree_response = '';\n\n                switch ($this->getServerVersion()) {\n                case CAS_VERSION_1_0:\n                    // if a Service Ticket was given, validate it\n                    phpCAS::trace(\n                        'CAS 1.0 ticket `'.$this->getTicket().'\\' is present'\n                    );\n                    $this->validateCAS10(\n                        $validate_url, $text_response, $tree_response, $renew\n                    ); // if it fails, it halts\n                    phpCAS::trace(\n                        'CAS 1.0 ticket `'.$this->getTicket().'\\' was validated'\n                    );\n                    $this->setSessionValue('user', $this->_getUser());\n                    $res = true;\n                    $logoutTicket = $this->getTicket();\n                    break;\n                case CAS_VERSION_2_0:\n                case CAS_VERSION_3_0:\n                    // if a Proxy Ticket was given, validate it\n                    phpCAS::trace(\n                        'CAS '.$this->getServerVersion().' ticket `'.$this->getTicket().'\\' is present'\n                    );\n                    $this->validateCAS20(\n                        $validate_url, $text_response, $tree_response, $renew\n                    ); // note: if it fails, it halts\n                    phpCAS::trace(\n                        'CAS '.$this->getServerVersion().' ticket `'.$this->getTicket().'\\' was validated'\n                    );\n                    if ( $this->isProxy() ) {\n                        $this->_validatePGT(\n                            $validate_url, $text_response, $tree_response\n                        ); // idem\n                        phpCAS::trace('PGT `'.$this->_getPGT().'\\' was validated');\n                        $this->setSessionValue('pgt', $this->_getPGT());\n                    }\n                    $this->setSessionValue('user', $this->_getUser());\n                    if (!empty($this->_attributes)) {\n                        $this->setSessionValue('attributes', $this->_attributes);\n                    }\n                    $proxies = $this->getProxies();\n                    if (!empty($proxies)) {\n                        $this->setSessionValue('proxies', $this->getProxies());\n                    }\n                    $res = true;\n                    $logoutTicket = $this->getTicket();\n                    break;\n                case SAML_VERSION_1_1:\n                    // if we have a SAML ticket, validate it.\n                    phpCAS::trace(\n                        'SAML 1.1 ticket `'.$this->getTicket().'\\' is present'\n                    );\n                    $this->validateSA(\n                        $validate_url, $text_response, $tree_response, $renew\n                    ); // if it fails, it halts\n                    phpCAS::trace(\n                        'SAML 1.1 ticket `'.$this->getTicket().'\\' was validated'\n                    );\n                    $this->setSessionValue('user', $this->_getUser());\n                    $this->setSessionValue('attributes', $this->_attributes);\n                    $res = true;\n                    $logoutTicket = $this->getTicket();\n                    break;\n                default:\n                    phpCAS::trace('Protocol error');\n                    break;\n                }\n            } else {\n                // no ticket given, not authenticated\n                phpCAS::trace('no ticket found');\n            }\n\n            // Mark the auth-check as complete to allow post-authentication\n            // callbacks to make use of phpCAS::getUser() and similar methods\n            $this->markAuthenticationCall($res);\n\n            if ($res) {\n                // call the post-authenticate callback if registered.\n                if ($this->_postAuthenticateCallbackFunction) {\n                    $args = $this->_postAuthenticateCallbackArgs;\n                    array_unshift($args, $logoutTicket);\n                    call_user_func_array(\n                        $this->_postAuthenticateCallbackFunction, $args\n                    );\n                }\n\n                // if called with a ticket parameter, we need to redirect to the\n                // app without the ticket so that CAS-ification is transparent\n                // to the browser (for later POSTS) most of the checks and\n                // errors should have been made now, so we're safe for redirect\n                // without masking error messages. remove the ticket as a\n                // security precaution to prevent a ticket in the HTTP_REFERRER\n                if ($this->_clearTicketsFromUrl) {\n                    phpCAS::trace(\"Prepare redirect to : \".$this->getURL());\n                    session_write_close();\n                    header('Location: '.$this->getURL());\n                    flush();\n                    phpCAS::traceExit();\n                    throw new CAS_GracefullTerminationException();\n                }\n            }\n        }\n        phpCAS::traceEnd($res);\n        return $res;\n    }\n\n    /**\n     * This method tells if the current session is authenticated.\n     *\n     * @return bool true if authenticated based soley on $_SESSION variable\n     */\n    public function isSessionAuthenticated ()\n    {\n        return !!$this->getSessionValue('user');\n    }\n\n    /**\n     * This method tells if the user has already been (previously) authenticated\n     * by looking into the session variables.\n     *\n     * @note This function switches to callback mode when needed.\n     *\n     * @return bool true when the user has already been authenticated; false otherwise.\n     */\n    private function _wasPreviouslyAuthenticated()\n    {\n        phpCAS::traceBegin();\n\n        if ( $this->_isCallbackMode() ) {\n            // Rebroadcast the pgtIou and pgtId to all nodes\n            if ($this->_rebroadcast&&!isset($_POST['rebroadcast'])) {\n                $this->_rebroadcast(self::PGTIOU);\n            }\n            $this->_callback();\n        }\n\n        $auth = false;\n\n        if ( $this->isProxy() ) {\n            // CAS proxy: username and PGT must be present\n            if ( $this->isSessionAuthenticated()\n                && $this->getSessionValue('pgt')\n            ) {\n                // authentication already done\n                $this->_setUser($this->getSessionValue('user'));\n                if ($this->hasSessionValue('attributes')) {\n                    $this->setAttributes($this->getSessionValue('attributes'));\n                }\n                $this->_setPGT($this->getSessionValue('pgt'));\n                phpCAS::trace(\n                    'user = `'.$this->getSessionValue('user').'\\', PGT = `'\n                    .$this->getSessionValue('pgt').'\\''\n                );\n\n                // Include the list of proxies\n                if ($this->hasSessionValue('proxies')) {\n                    $this->_setProxies($this->getSessionValue('proxies'));\n                    phpCAS::trace(\n                        'proxies = \"'\n                        .implode('\", \"', $this->getSessionValue('proxies')).'\"'\n                    );\n                }\n\n                $auth = true;\n            } elseif ( $this->isSessionAuthenticated()\n                && !$this->getSessionValue('pgt')\n            ) {\n                // these two variables should be empty or not empty at the same time\n                phpCAS::trace(\n                    'username found (`'.$this->getSessionValue('user')\n                    .'\\') but PGT is empty'\n                );\n                // unset all tickets to enforce authentication\n                $this->clearSessionValues();\n                $this->setTicket('');\n            } elseif ( !$this->isSessionAuthenticated()\n                && $this->getSessionValue('pgt')\n            ) {\n                // these two variables should be empty or not empty at the same time\n                phpCAS::trace(\n                    'PGT found (`'.$this->getSessionValue('pgt')\n                    .'\\') but username is empty'\n                );\n                // unset all tickets to enforce authentication\n                $this->clearSessionValues();\n                $this->setTicket('');\n            } else {\n                phpCAS::trace('neither user nor PGT found');\n            }\n        } else {\n            // `simple' CAS client (not a proxy): username must be present\n            if ( $this->isSessionAuthenticated() ) {\n                // authentication already done\n                $this->_setUser($this->getSessionValue('user'));\n                if ($this->hasSessionValue('attributes')) {\n                    $this->setAttributes($this->getSessionValue('attributes'));\n                }\n                phpCAS::trace('user = `'.$this->getSessionValue('user').'\\'');\n\n                // Include the list of proxies\n                if ($this->hasSessionValue('proxies')) {\n                    $this->_setProxies($this->getSessionValue('proxies'));\n                    phpCAS::trace(\n                        'proxies = \"'\n                        .implode('\", \"', $this->getSessionValue('proxies')).'\"'\n                    );\n                }\n\n                $auth = true;\n            } else {\n                phpCAS::trace('no user found');\n            }\n        }\n\n        phpCAS::traceEnd($auth);\n        return $auth;\n    }\n\n    /**\n     * This method is used to redirect the client to the CAS server.\n     * It is used by CAS_Client::forceAuthentication() and\n     * CAS_Client::checkAuthentication().\n     *\n     * @param bool $gateway true to check authentication, false to force it\n     * @param bool $renew   true to force the authentication with the CAS server\n     *\n     * @return void\n     */\n    public function redirectToCas($gateway=false,$renew=false)\n    {\n        phpCAS::traceBegin();\n        $cas_url = $this->getServerLoginURL($gateway, $renew);\n        session_write_close();\n        if (php_sapi_name() === 'cli') {\n            @header('Location: '.$cas_url);\n        } else {\n            header('Location: '.$cas_url);\n        }\n        phpCAS::trace(\"Redirect to : \".$cas_url);\n        $lang = $this->getLangObj();\n        $this->printHTMLHeader($lang->getAuthenticationWanted());\n        $this->printf('<p>'. $lang->getShouldHaveBeenRedirected(). '</p>', $cas_url);\n        $this->printHTMLFooter();\n        phpCAS::traceExit();\n        throw new CAS_GracefullTerminationException();\n    }\n\n\n    /**\n     * This method is used to logout from CAS.\n     *\n     * @param array $params an array that contains the optional url and service\n     * parameters that will be passed to the CAS server\n     *\n     * @return void\n     */\n    public function logout($params)\n    {\n        phpCAS::traceBegin();\n        $cas_url = $this->getServerLogoutURL();\n        $paramSeparator = '?';\n        if (isset($params['url'])) {\n            $cas_url = $cas_url . $paramSeparator . \"url=\"\n                . urlencode($params['url']);\n            $paramSeparator = '&';\n        }\n        if (isset($params['service'])) {\n            $cas_url = $cas_url . $paramSeparator . \"service=\"\n                . urlencode($params['service']);\n        }\n        header('Location: '.$cas_url);\n        phpCAS::trace(\"Prepare redirect to : \".$cas_url);\n\n        phpCAS::trace(\"Destroying session : \".session_id());\n        session_unset();\n        session_destroy();\n        if (session_status() === PHP_SESSION_NONE) {\n            phpCAS::trace(\"Session terminated\");\n        } else {\n            phpCAS::error(\"Session was not terminated\");\n            phpCAS::trace(\"Session was not terminated\");\n        }\n        $lang = $this->getLangObj();\n        $this->printHTMLHeader($lang->getLogout());\n        $this->printf('<p>'.$lang->getShouldHaveBeenRedirected(). '</p>', $cas_url);\n        $this->printHTMLFooter();\n        phpCAS::traceExit();\n        throw new CAS_GracefullTerminationException();\n    }\n\n    /**\n     * Check of the current request is a logout request\n     *\n     * @return bool is logout request.\n     */\n    private function _isLogoutRequest()\n    {\n        return !empty($_POST['logoutRequest']);\n    }\n\n    /**\n     * This method handles logout requests.\n     *\n     * @param bool $check_client    true to check the client bofore handling\n     * the request, false not to perform any access control. True by default.\n     * @param array $allowed_clients an array of host names allowed to send\n     * logout requests.\n     *\n     * @return void\n     */\n    public function handleLogoutRequests($check_client=true, $allowed_clients=array())\n    {\n        phpCAS::traceBegin();\n        if (!$this->_isLogoutRequest()) {\n            phpCAS::trace(\"Not a logout request\");\n            phpCAS::traceEnd();\n            return;\n        }\n        if (!$this->getChangeSessionID()\n            && is_null($this->_signoutCallbackFunction)\n        ) {\n            phpCAS::trace(\n                \"phpCAS can't handle logout requests if it is not allowed to change session_id.\"\n            );\n        }\n        phpCAS::trace(\"Logout requested\");\n        $decoded_logout_rq = urldecode($_POST['logoutRequest']);\n        phpCAS::trace(\"SAML REQUEST: \".$decoded_logout_rq);\n        $allowed = false;\n        if ($check_client) {\n            if ($allowed_clients === array()) {\n                $allowed_clients = array( $this->_getServerHostname() );\n            }\n            $client_ip = $_SERVER['REMOTE_ADDR'];\n            $client = gethostbyaddr($client_ip);\n            phpCAS::trace(\"Client: \".$client.\"/\".$client_ip);\n            foreach ($allowed_clients as $allowed_client) {\n                if (($client == $allowed_client)\n                    || ($client_ip == $allowed_client)\n                ) {\n                    phpCAS::trace(\n                        \"Allowed client '\".$allowed_client\n                        .\"' matches, logout request is allowed\"\n                    );\n                    $allowed = true;\n                    break;\n                } else {\n                    phpCAS::trace(\n                        \"Allowed client '\".$allowed_client.\"' does not match\"\n                    );\n                }\n            }\n        } else {\n            phpCAS::trace(\"No access control set\");\n            $allowed = true;\n        }\n        // If Logout command is permitted proceed with the logout\n        if ($allowed) {\n            phpCAS::trace(\"Logout command allowed\");\n            // Rebroadcast the logout request\n            if ($this->_rebroadcast && !isset($_POST['rebroadcast'])) {\n                $this->_rebroadcast(self::LOGOUT);\n            }\n            // Extract the ticket from the SAML Request\n            preg_match(\n                \"|<samlp:SessionIndex>(.*)</samlp:SessionIndex>|\",\n                $decoded_logout_rq, $tick, PREG_OFFSET_CAPTURE, 3\n            );\n            $wrappedSamlSessionIndex = preg_replace(\n                '|<samlp:SessionIndex>|', '', $tick[0][0]\n            );\n            $ticket2logout = preg_replace(\n                '|</samlp:SessionIndex>|', '', $wrappedSamlSessionIndex\n            );\n            phpCAS::trace(\"Ticket to logout: \".$ticket2logout);\n\n            // call the post-authenticate callback if registered.\n            if ($this->_signoutCallbackFunction) {\n                $args = $this->_signoutCallbackArgs;\n                array_unshift($args, $ticket2logout);\n                call_user_func_array($this->_signoutCallbackFunction, $args);\n            }\n\n            // If phpCAS is managing the session_id, destroy session thanks to\n            // session_id.\n            if ($this->getChangeSessionID()) {\n                $session_id = $this->_sessionIdForTicket($ticket2logout);\n                phpCAS::trace(\"Session id: \".$session_id);\n\n                // destroy a possible application session created before phpcas\n                if (session_id() !== \"\") {\n                    session_unset();\n                    session_destroy();\n                }\n                // fix session ID\n                session_id($session_id);\n                $_COOKIE[session_name()]=$session_id;\n                $_GET[session_name()]=$session_id;\n\n                // Overwrite session\n                session_start();\n                session_unset();\n                session_destroy();\n                phpCAS::trace(\"Session \". $session_id . \" destroyed\");\n            }\n        } else {\n            phpCAS::error(\"Unauthorized logout request from client '\".$client.\"'\");\n            phpCAS::trace(\"Unauthorized logout request from client '\".$client.\"'\");\n        }\n        flush();\n        phpCAS::traceExit();\n        throw new CAS_GracefullTerminationException();\n\n    }\n\n    /** @} */\n\n    // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n    // XX                                                                    XX\n    // XX                  BASIC CLIENT FEATURES (CAS 1.0)                   XX\n    // XX                                                                    XX\n    // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n\n    // ########################################################################\n    //  ST\n    // ########################################################################\n    /**\n    * @addtogroup internalBasic\n    * @{\n    */\n\n    /**\n     * The Ticket provided in the URL of the request if present\n     * (empty otherwise). Written by CAS_Client::CAS_Client(), read by\n     * CAS_Client::getTicket() and CAS_Client::_hasPGT().\n     *\n     * @hideinitializer\n     */\n    private $_ticket = '';\n\n    /**\n     * This method returns the Service Ticket provided in the URL of the request.\n     *\n     * @return string service ticket.\n     */\n    public  function getTicket()\n    {\n        return $this->_ticket;\n    }\n\n    /**\n     * This method stores the Service Ticket.\n     *\n     * @param string $st The Service Ticket.\n     *\n     * @return void\n     */\n    public function setTicket($st)\n    {\n        $this->_ticket = $st;\n    }\n\n    /**\n     * This method tells if a Service Ticket was stored.\n     *\n     * @return bool if a Service Ticket has been stored.\n     */\n    public function hasTicket()\n    {\n        return !empty($this->_ticket);\n    }\n\n    /** @} */\n\n    // ########################################################################\n    //  ST VALIDATION\n    // ########################################################################\n    /**\n    * @addtogroup internalBasic\n    * @{\n    */\n\n    /**\n     * @var  string the certificate of the CAS server CA.\n     *\n     * @hideinitializer\n     */\n    private $_cas_server_ca_cert = null;\n\n\n    /**\n\n     * validate CN of the CAS server certificate\n\n     *\n\n     * @hideinitializer\n\n     */\n\n    private $_cas_server_cn_validate = true;\n\n    /**\n     * Set to true not to validate the CAS server.\n     *\n     * @hideinitializer\n     */\n    private $_no_cas_server_validation = false;\n\n\n    /**\n     * Set the CA certificate of the CAS server.\n     *\n     * @param string $cert        the PEM certificate file name of the CA that emited\n     * the cert of the server\n     * @param bool   $validate_cn valiate CN of the CAS server certificate\n     *\n     * @return void\n     */\n    public function setCasServerCACert($cert, $validate_cn)\n    {\n    // Argument validation\n        if (gettype($cert) != 'string') {\n            throw new CAS_TypeMismatchException($cert, '$cert', 'string');\n        }\n        if (gettype($validate_cn) != 'boolean') {\n            throw new CAS_TypeMismatchException($validate_cn, '$validate_cn', 'boolean');\n        }\n        if (!file_exists($cert)) {\n            throw new CAS_InvalidArgumentException(\"Certificate file does not exist \" . $this->_requestImplementation);\n        }\n        $this->_cas_server_ca_cert = $cert;\n        $this->_cas_server_cn_validate = $validate_cn;\n    }\n\n    /**\n     * Set no SSL validation for the CAS server.\n     *\n     * @return void\n     */\n    public function setNoCasServerValidation()\n    {\n        $this->_no_cas_server_validation = true;\n    }\n\n    /**\n     * This method is used to validate a CAS 1,0 ticket; halt on failure, and\n     * sets $validate_url, $text_reponse and $tree_response on success.\n     *\n     * @param string &$validate_url  reference to the the URL of the request to\n     * the CAS server.\n     * @param string &$text_response reference to the response of the CAS\n     * server, as is (XML text).\n     * @param string &$tree_response reference to the response of the CAS\n     * server, as a DOM XML tree.\n     * @param bool   $renew          true to force the authentication with the CAS server\n     *\n     * @return bool true when successfull and issue a CAS_AuthenticationException\n     * and false on an error\n     * @throws  CAS_AuthenticationException\n     */\n    public function validateCAS10(&$validate_url,&$text_response,&$tree_response,$renew=false)\n    {\n        phpCAS::traceBegin();\n        // build the URL to validate the ticket\n        $validate_url = $this->getServerServiceValidateURL()\n            .'&ticket='.urlencode($this->getTicket());\n\n        if ( $renew ) {\n            // pass the renew\n            $validate_url .= '&renew=true';\n        }\n\n        $headers = '';\n        $err_msg = '';\n        // open and read the URL\n        if ( !$this->_readURL($validate_url, $headers, $text_response, $err_msg) ) {\n            phpCAS::trace(\n                'could not open URL \\''.$validate_url.'\\' to validate ('.$err_msg.')'\n            );\n            throw new CAS_AuthenticationException(\n                $this, 'CAS 1.0 ticket not validated', $validate_url,\n                true/*$no_response*/\n            );\n        }\n\n        if (preg_match('/^no\\n/', $text_response)) {\n            phpCAS::trace('Ticket has not been validated');\n            throw new CAS_AuthenticationException(\n                $this, 'ST not validated', $validate_url, false/*$no_response*/,\n                false/*$bad_response*/, $text_response\n            );\n        } else if (!preg_match('/^yes\\n/', $text_response)) {\n            phpCAS::trace('ill-formed response');\n            throw new CAS_AuthenticationException(\n                $this, 'Ticket not validated', $validate_url,\n                false/*$no_response*/, true/*$bad_response*/, $text_response\n            );\n        }\n        // ticket has been validated, extract the user name\n        $arr = preg_split('/\\n/', $text_response);\n        $this->_setUser(trim($arr[1]));\n\n        $this->_renameSession($this->getTicket());\n\n        // at this step, ticket has been validated and $this->_user has been set,\n        phpCAS::traceEnd(true);\n        return true;\n    }\n\n    /** @} */\n\n\n    // ########################################################################\n    //  SAML VALIDATION\n    // ########################################################################\n    /**\n    * @addtogroup internalSAML\n    * @{\n    */\n\n    /**\n     * This method is used to validate a SAML TICKET; halt on failure, and sets\n     * $validate_url, $text_reponse and $tree_response on success. These\n     * parameters are used later by CAS_Client::_validatePGT() for CAS proxies.\n     *\n     * @param string &$validate_url  reference to the the URL of the request to\n     * the CAS server.\n     * @param string &$text_response reference to the response of the CAS\n     * server, as is (XML text).\n     * @param string &$tree_response reference to the response of the CAS\n     * server, as a DOM XML tree.\n     * @param bool   $renew          true to force the authentication with the CAS server\n     *\n     * @return bool true when successfull and issue a CAS_AuthenticationException\n     * and false on an error\n     *\n     * @throws  CAS_AuthenticationException\n     */\n    public function validateSA(&$validate_url,&$text_response,&$tree_response,$renew=false)\n    {\n        phpCAS::traceBegin();\n        $result = false;\n        // build the URL to validate the ticket\n        $validate_url = $this->getServerSamlValidateURL();\n\n        if ( $renew ) {\n            // pass the renew\n            $validate_url .= '&renew=true';\n        }\n\n        $headers = '';\n        $err_msg = '';\n        // open and read the URL\n        if ( !$this->_readURL($validate_url, $headers, $text_response, $err_msg) ) {\n            phpCAS::trace(\n                'could not open URL \\''.$validate_url.'\\' to validate ('.$err_msg.')'\n            );\n            throw new CAS_AuthenticationException(\n                $this, 'SA not validated', $validate_url, true/*$no_response*/\n            );\n        }\n\n        phpCAS::trace('server version: '.$this->getServerVersion());\n\n        // analyze the result depending on the version\n        switch ($this->getServerVersion()) {\n        case SAML_VERSION_1_1:\n            // create new DOMDocument Object\n            $dom = new DOMDocument();\n            // Fix possible whitspace problems\n            $dom->preserveWhiteSpace = false;\n            // read the response of the CAS server into a DOM object\n            if (!($dom->loadXML($text_response))) {\n                phpCAS::trace('dom->loadXML() failed');\n                throw new CAS_AuthenticationException(\n                    $this, 'SA not validated', $validate_url,\n                    false/*$no_response*/, true/*$bad_response*/,\n                    $text_response\n                );\n            }\n            // read the root node of the XML tree\n            if (!($tree_response = $dom->documentElement)) {\n                phpCAS::trace('documentElement() failed');\n                throw new CAS_AuthenticationException(\n                    $this, 'SA not validated', $validate_url,\n                    false/*$no_response*/, true/*$bad_response*/,\n                    $text_response\n                );\n            } else if ( $tree_response->localName != 'Envelope' ) {\n                // insure that tag name is 'Envelope'\n                phpCAS::trace(\n                    'bad XML root node (should be `Envelope\\' instead of `'\n                    .$tree_response->localName.'\\''\n                );\n                throw new CAS_AuthenticationException(\n                    $this, 'SA not validated', $validate_url,\n                    false/*$no_response*/, true/*$bad_response*/,\n                    $text_response\n                );\n            } else if ($tree_response->getElementsByTagName(\"NameIdentifier\")->length != 0) {\n                // check for the NameIdentifier tag in the SAML response\n                $success_elements = $tree_response->getElementsByTagName(\"NameIdentifier\");\n                phpCAS::trace('NameIdentifier found');\n                $user = trim($success_elements->item(0)->nodeValue);\n                phpCAS::trace('user = `'.$user.'`');\n                $this->_setUser($user);\n                $this->_setSessionAttributes($text_response);\n                $result = true;\n            } else {\n                phpCAS::trace('no <NameIdentifier> tag found in SAML payload');\n                throw new CAS_AuthenticationException(\n                    $this, 'SA not validated', $validate_url,\n                    false/*$no_response*/, true/*$bad_response*/,\n                    $text_response\n                );\n            }\n        }\n        if ($result) {\n            $this->_renameSession($this->getTicket());\n        }\n        // at this step, ST has been validated and $this->_user has been set,\n        phpCAS::traceEnd($result);\n        return $result;\n    }\n\n    /**\n     * This method will parse the DOM and pull out the attributes from the SAML\n     * payload and put them into an array, then put the array into the session.\n     *\n     * @param string $text_response the SAML payload.\n     *\n     * @return bool true when successfull and false if no attributes a found\n     */\n    private function _setSessionAttributes($text_response)\n    {\n        phpCAS::traceBegin();\n\n        $result = false;\n\n        $attr_array = array();\n\n        // create new DOMDocument Object\n        $dom = new DOMDocument();\n        // Fix possible whitspace problems\n        $dom->preserveWhiteSpace = false;\n        if (($dom->loadXML($text_response))) {\n            $xPath = new DOMXPath($dom);\n            $xPath->registerNamespace('samlp', 'urn:oasis:names:tc:SAML:1.0:protocol');\n            $xPath->registerNamespace('saml', 'urn:oasis:names:tc:SAML:1.0:assertion');\n            $nodelist = $xPath->query(\"//saml:Attribute\");\n\n            if ($nodelist) {\n                foreach ($nodelist as $node) {\n                    $xres = $xPath->query(\"saml:AttributeValue\", $node);\n                    $name = $node->getAttribute(\"AttributeName\");\n                    $value_array = array();\n                    foreach ($xres as $node2) {\n                        $value_array[] = $node2->nodeValue;\n                    }\n                    $attr_array[$name] = $value_array;\n                }\n                // UGent addition...\n                foreach ($attr_array as $attr_key => $attr_value) {\n                    if (count($attr_value) > 1) {\n                        $this->_attributes[$attr_key] = $attr_value;\n                        phpCAS::trace(\"* \" . $attr_key . \"=\" . print_r($attr_value, true));\n                    } else {\n                        $this->_attributes[$attr_key] = $attr_value[0];\n                        phpCAS::trace(\"* \" . $attr_key . \"=\" . $attr_value[0]);\n                    }\n                }\n                $result = true;\n            } else {\n                phpCAS::trace(\"SAML Attributes are empty\");\n                $result = false;\n            }\n        }\n        phpCAS::traceEnd($result);\n        return $result;\n    }\n\n    /** @} */\n\n    // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n    // XX                                                                    XX\n    // XX                     PROXY FEATURES (CAS 2.0)                       XX\n    // XX                                                                    XX\n    // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n\n    // ########################################################################\n    //  PROXYING\n    // ########################################################################\n    /**\n    * @addtogroup internalProxy\n    * @{\n    */\n\n    /**\n     * @var  bool is the client a proxy\n     * A boolean telling if the client is a CAS proxy or not. Written by\n     * CAS_Client::CAS_Client(), read by CAS_Client::isProxy().\n     */\n    private $_proxy;\n\n    /**\n     * @var  CAS_CookieJar Handler for managing service cookies.\n     */\n    private $_serviceCookieJar;\n\n    /**\n     * Tells if a CAS client is a CAS proxy or not\n     *\n     * @return bool true when the CAS client is a CAS proxy, false otherwise\n     */\n    public function isProxy()\n    {\n        return $this->_proxy;\n    }\n\n\n    /** @} */\n    // ########################################################################\n    //  PGT\n    // ########################################################################\n    /**\n    * @addtogroup internalProxy\n    * @{\n    */\n\n    /**\n     * the Proxy Grnting Ticket given by the CAS server (empty otherwise).\n     * Written by CAS_Client::_setPGT(), read by CAS_Client::_getPGT() and\n     * CAS_Client::_hasPGT().\n     *\n     * @hideinitializer\n     */\n    private $_pgt = '';\n\n    /**\n     * This method returns the Proxy Granting Ticket given by the CAS server.\n     *\n     * @return string the Proxy Granting Ticket.\n     */\n    private function _getPGT()\n    {\n        return $this->_pgt;\n    }\n\n    /**\n     * This method stores the Proxy Granting Ticket.\n     *\n     * @param string $pgt The Proxy Granting Ticket.\n     *\n     * @return void\n     */\n    private function _setPGT($pgt)\n    {\n        $this->_pgt = $pgt;\n    }\n\n    /**\n     * This method tells if a Proxy Granting Ticket was stored.\n     *\n     * @return bool true if a Proxy Granting Ticket has been stored.\n     */\n    private function _hasPGT()\n    {\n        return !empty($this->_pgt);\n    }\n\n    /** @} */\n\n    // ########################################################################\n    //  CALLBACK MODE\n    // ########################################################################\n    /**\n    * @addtogroup internalCallback\n    * @{\n    */\n    /**\n     * each PHP script using phpCAS in proxy mode is its own callback to get the\n     * PGT back from the CAS server. callback_mode is detected by the constructor\n     * thanks to the GET parameters.\n     */\n\n    /**\n     * @var bool a boolean to know if the CAS client is running in callback mode. Written by\n     * CAS_Client::setCallBackMode(), read by CAS_Client::_isCallbackMode().\n     *\n     * @hideinitializer\n     */\n    private $_callback_mode = false;\n\n    /**\n     * This method sets/unsets callback mode.\n     *\n     * @param bool $callback_mode true to set callback mode, false otherwise.\n     *\n     * @return void\n     */\n    private function _setCallbackMode($callback_mode)\n    {\n        $this->_callback_mode = $callback_mode;\n    }\n\n    /**\n     * This method returns true when the CAS client is running in callback mode,\n     * false otherwise.\n     *\n     * @return bool A boolean.\n     */\n    private function _isCallbackMode()\n    {\n        return $this->_callback_mode;\n    }\n\n    /**\n     * @var bool a boolean to know if the CAS client is using POST parameters when in callback mode.\n     * Written by CAS_Client::_setCallbackModeUsingPost(), read by CAS_Client::_isCallbackModeUsingPost().\n     *\n     * @hideinitializer\n     */\n    private $_callback_mode_using_post = false;\n\n    /**\n     * This method sets/unsets usage of POST parameters in callback mode (default/false is GET parameters)\n     *\n     * @param bool $callback_mode_using_post true to use POST, false to use GET (default).\n     *\n     * @return void\n     */\n    private function _setCallbackModeUsingPost($callback_mode_using_post)\n    {\n        $this->_callback_mode_using_post = $callback_mode_using_post;\n    }\n\n    /**\n     * This method returns true when the callback mode is using POST, false otherwise.\n     *\n     * @return bool A boolean.\n     */\n    private function _isCallbackModeUsingPost()\n    {\n        return $this->_callback_mode_using_post;\n    }\n\n    /**\n     * the URL that should be used for the PGT callback (in fact the URL of the\n     * current request without any CGI parameter). Written and read by\n     * CAS_Client::_getCallbackURL().\n     *\n     * @hideinitializer\n     */\n    private $_callback_url = '';\n\n    /**\n     * This method returns the URL that should be used for the PGT callback (in\n     * fact the URL of the current request without any CGI parameter, except if\n     * phpCAS::setFixedCallbackURL() was used).\n     *\n     * @return string The callback URL\n     */\n    private function _getCallbackURL()\n    {\n        // the URL is built when needed only\n        if ( empty($this->_callback_url) ) {\n            // remove the ticket if present in the URL\n            $final_uri = $this->getServiceBaseUrl()->get();\n            $request_uri = $_SERVER['REQUEST_URI'];\n            $request_uri = preg_replace('/\\?.*$/', '', $request_uri);\n            $final_uri .= $request_uri;\n            $this->_callback_url = $final_uri;\n        }\n        return $this->_callback_url;\n    }\n\n    /**\n     * This method sets the callback url.\n     *\n     * @param string $url url to set callback\n     *\n     * @return string the callback url\n     */\n    public function setCallbackURL($url)\n    {\n        // Sequence validation\n        $this->ensureIsProxy();\n        // Argument Validation\n        if (gettype($url) != 'string')\n            throw new CAS_TypeMismatchException($url, '$url', 'string');\n\n        return $this->_callback_url = $url;\n    }\n\n    /**\n     * This method is called by CAS_Client::CAS_Client() when running in callback\n     * mode. It stores the PGT and its PGT Iou, prints its output and halts.\n     *\n     * @return void\n     */\n    private function _callback()\n    {\n        phpCAS::traceBegin();\n        if ($this->_isCallbackModeUsingPost()) {\n            $pgtId = $_POST['pgtId'];\n            $pgtIou = $_POST['pgtIou'];\n        } else {\n            $pgtId = $_GET['pgtId'];\n            $pgtIou = $_GET['pgtIou'];\n        }\n        if (preg_match('/^PGTIOU-[\\.\\-\\w]+$/', $pgtIou)) {\n            if (preg_match('/^[PT]GT-[\\.\\-\\w]+$/', $pgtId)) {\n                phpCAS::trace('Storing PGT `'.$pgtId.'\\' (id=`'.$pgtIou.'\\')');\n                $this->_storePGT($pgtId, $pgtIou);\n                if ($this->isXmlResponse()) {\n                    echo '<?xml version=\"1.0\" encoding=\"UTF-8\"?>' . \"\\r\\n\";\n                    echo '<proxySuccess xmlns=\"http://www.yale.edu/tp/cas\" />';\n                    phpCAS::traceExit(\"XML response sent\");\n                } else {\n                    $this->printHTMLHeader('phpCAS callback');\n                    echo '<p>Storing PGT `'.$pgtId.'\\' (id=`'.$pgtIou.'\\').</p>';\n                    $this->printHTMLFooter();\n                    phpCAS::traceExit(\"HTML response sent\");\n                }\n                phpCAS::traceExit(\"Successfull Callback\");\n            } else {\n                phpCAS::error('PGT format invalid' . $pgtId);\n                phpCAS::traceExit('PGT format invalid' . $pgtId);\n            }\n        } else {\n            phpCAS::error('PGTiou format invalid' . $pgtIou);\n            phpCAS::traceExit('PGTiou format invalid' . $pgtIou);\n        }\n\n        // Flush the buffer to prevent from sending anything other then a 200\n        // Success Status back to the CAS Server. The Exception would normally\n        // report as a 500 error.\n        flush();\n        throw new CAS_GracefullTerminationException();\n    }\n\n    /**\n     * Check if application/xml or text/xml is pressent in HTTP_ACCEPT header values\n     * when return value is complex and contains attached q parameters.\n     * Example:  HTTP_ACCEPT = text/html,application/xhtml+xml,application/xml;q=0.9\n     * @return bool\n     */\n    private function isXmlResponse()\n    {\n        if (!array_key_exists('HTTP_ACCEPT', $_SERVER)) {\n            return false;\n        }\n        if (strpos($_SERVER['HTTP_ACCEPT'], 'application/xml') === false && strpos($_SERVER['HTTP_ACCEPT'], 'text/xml') === false) {\n            return false;\n        }\n\n        return true;\n    }\n\n    /** @} */\n\n    // ########################################################################\n    //  PGT STORAGE\n    // ########################################################################\n    /**\n    * @addtogroup internalPGTStorage\n    * @{\n    */\n\n    /**\n     * @var  CAS_PGTStorage_AbstractStorage\n     * an instance of a class inheriting of PGTStorage, used to deal with PGT\n     * storage. Created by CAS_Client::setPGTStorageFile(), used\n     * by CAS_Client::setPGTStorageFile() and CAS_Client::_initPGTStorage().\n     *\n     * @hideinitializer\n     */\n    private $_pgt_storage = null;\n\n    /**\n     * This method is used to initialize the storage of PGT's.\n     * Halts on error.\n     *\n     * @return void\n     */\n    private function _initPGTStorage()\n    {\n        // if no SetPGTStorageXxx() has been used, default to file\n        if ( !is_object($this->_pgt_storage) ) {\n            $this->setPGTStorageFile();\n        }\n\n        // initializes the storage\n        $this->_pgt_storage->init();\n    }\n\n    /**\n     * This method stores a PGT. Halts on error.\n     *\n     * @param string $pgt     the PGT to store\n     * @param string $pgt_iou its corresponding Iou\n     *\n     * @return void\n     */\n    private function _storePGT($pgt,$pgt_iou)\n    {\n        // ensure that storage is initialized\n        $this->_initPGTStorage();\n        // writes the PGT\n        $this->_pgt_storage->write($pgt, $pgt_iou);\n    }\n\n    /**\n     * This method reads a PGT from its Iou and deletes the corresponding\n     * storage entry.\n     *\n     * @param string $pgt_iou the PGT Iou\n     *\n     * @return string mul The PGT corresponding to the Iou, false when not found.\n     */\n    private function _loadPGT($pgt_iou)\n    {\n        // ensure that storage is initialized\n        $this->_initPGTStorage();\n        // read the PGT\n        return $this->_pgt_storage->read($pgt_iou);\n    }\n\n    /**\n     * This method can be used to set a custom PGT storage object.\n     *\n     * @param CAS_PGTStorage_AbstractStorage $storage a PGT storage object that\n     * inherits from the CAS_PGTStorage_AbstractStorage class\n     *\n     * @return void\n     */\n    public function setPGTStorage($storage)\n    {\n        // Sequence validation\n        $this->ensureIsProxy();\n\n        // check that the storage has not already been set\n        if ( is_object($this->_pgt_storage) ) {\n            phpCAS::error('PGT storage already defined');\n        }\n\n        // check to make sure a valid storage object was specified\n        if ( !($storage instanceof CAS_PGTStorage_AbstractStorage) )\n            throw new CAS_TypeMismatchException($storage, '$storage', 'CAS_PGTStorage_AbstractStorage object');\n\n        // store the PGTStorage object\n        $this->_pgt_storage = $storage;\n    }\n\n    /**\n     * This method is used to tell phpCAS to store the response of the\n     * CAS server to PGT requests in a database.\n     *\n     * @param string|PDO $dsn_or_pdo     a dsn string to use for creating a PDO\n     * object or a PDO object\n     * @param string $username       the username to use when connecting to the\n     * database\n     * @param string $password       the password to use when connecting to the\n     * database\n     * @param string $table          the table to use for storing and retrieving\n     * PGTs\n     * @param string $driver_options any driver options to use when connecting\n     * to the database\n     *\n     * @return void\n     */\n    public function setPGTStorageDb(\n        $dsn_or_pdo, $username='', $password='', $table='', $driver_options=null\n    ) {\n        // Sequence validation\n        $this->ensureIsProxy();\n\n        // Argument validation\n        if (!(is_object($dsn_or_pdo) && $dsn_or_pdo instanceof PDO) && !is_string($dsn_or_pdo))\n            throw new CAS_TypeMismatchException($dsn_or_pdo, '$dsn_or_pdo', 'string or PDO object');\n        if (gettype($username) != 'string')\n            throw new CAS_TypeMismatchException($username, '$username', 'string');\n        if (gettype($password) != 'string')\n            throw new CAS_TypeMismatchException($password, '$password', 'string');\n        if (gettype($table) != 'string')\n            throw new CAS_TypeMismatchException($table, '$password', 'string');\n\n        // create the storage object\n        $this->setPGTStorage(\n            new CAS_PGTStorage_Db(\n                $this, $dsn_or_pdo, $username, $password, $table, $driver_options\n            )\n        );\n    }\n\n    /**\n     * This method is used to tell phpCAS to store the response of the\n     * CAS server to PGT requests onto the filesystem.\n     *\n     * @param string $path the path where the PGT's should be stored\n     *\n     * @return void\n     */\n    public function setPGTStorageFile($path='')\n    {\n        // Sequence validation\n        $this->ensureIsProxy();\n\n        // Argument validation\n        if (gettype($path) != 'string')\n            throw new CAS_TypeMismatchException($path, '$path', 'string');\n\n        // create the storage object\n        $this->setPGTStorage(new CAS_PGTStorage_File($this, $path));\n    }\n\n\n    // ########################################################################\n    //  PGT VALIDATION\n    // ########################################################################\n    /**\n    * This method is used to validate a PGT; halt on failure.\n    *\n    * @param string &$validate_url the URL of the request to the CAS server.\n    * @param string $text_response the response of the CAS server, as is\n    *                              (XML text); result of\n    *                              CAS_Client::validateCAS10() or\n    *                              CAS_Client::validateCAS20().\n    * @param DOMElement $tree_response the response of the CAS server, as a DOM XML\n    * tree; result of CAS_Client::validateCAS10() or CAS_Client::validateCAS20().\n    *\n    * @return bool true when successfull and issue a CAS_AuthenticationException\n    * and false on an error\n    *\n    * @throws CAS_AuthenticationException\n    */\n    private function _validatePGT(&$validate_url,$text_response,$tree_response)\n    {\n        phpCAS::traceBegin();\n        if ( $tree_response->getElementsByTagName(\"proxyGrantingTicket\")->length == 0) {\n            phpCAS::trace('<proxyGrantingTicket> not found');\n            // authentication succeded, but no PGT Iou was transmitted\n            throw new CAS_AuthenticationException(\n                $this, 'Ticket validated but no PGT Iou transmitted',\n                $validate_url, false/*$no_response*/, false/*$bad_response*/,\n                $text_response\n            );\n        } else {\n            // PGT Iou transmitted, extract it\n            $pgt_iou = trim(\n                $tree_response->getElementsByTagName(\"proxyGrantingTicket\")->item(0)->nodeValue\n            );\n            if (preg_match('/^PGTIOU-[\\.\\-\\w]+$/', $pgt_iou)) {\n                $pgt = $this->_loadPGT($pgt_iou);\n                if ( $pgt == false ) {\n                    phpCAS::trace('could not load PGT');\n                    throw new CAS_AuthenticationException(\n                        $this,\n                        'PGT Iou was transmitted but PGT could not be retrieved',\n                        $validate_url, false/*$no_response*/,\n                        false/*$bad_response*/, $text_response\n                    );\n                }\n                $this->_setPGT($pgt);\n            } else {\n                phpCAS::trace('PGTiou format error');\n                throw new CAS_AuthenticationException(\n                    $this, 'PGT Iou was transmitted but has wrong format',\n                    $validate_url, false/*$no_response*/, false/*$bad_response*/,\n                    $text_response\n                );\n            }\n        }\n        phpCAS::traceEnd(true);\n        return true;\n    }\n\n    // ########################################################################\n    //  PGT VALIDATION\n    // ########################################################################\n\n    /**\n     * This method is used to retrieve PT's from the CAS server thanks to a PGT.\n     *\n     * @param string $target_service the service to ask for with the PT.\n     * @param int &$err_code      an error code (PHPCAS_SERVICE_OK on success).\n     * @param string &$err_msg       an error message (empty on success).\n     *\n     * @return string|false a Proxy Ticket, or false on error.\n     */\n    public function retrievePT($target_service,&$err_code,&$err_msg)\n    {\n        // Argument validation\n        if (gettype($target_service) != 'string')\n            throw new CAS_TypeMismatchException($target_service, '$target_service', 'string');\n\n        phpCAS::traceBegin();\n\n        // by default, $err_msg is set empty and $pt to true. On error, $pt is\n        // set to false and $err_msg to an error message. At the end, if $pt is false\n        // and $error_msg is still empty, it is set to 'invalid response' (the most\n        // commonly encountered error).\n        $err_msg = '';\n\n        // build the URL to retrieve the PT\n        $cas_url = $this->getServerProxyURL().'?targetService='\n            .urlencode($target_service).'&pgt='.$this->_getPGT();\n\n        $headers = '';\n        $cas_response = '';\n        // open and read the URL\n        if ( !$this->_readURL($cas_url, $headers, $cas_response, $err_msg) ) {\n            phpCAS::trace(\n                'could not open URL \\''.$cas_url.'\\' to validate ('.$err_msg.')'\n            );\n            $err_code = PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE;\n            $err_msg = 'could not retrieve PT (no response from the CAS server)';\n            phpCAS::traceEnd(false);\n            return false;\n        }\n\n        $bad_response = false;\n\n        // create new DOMDocument object\n        $dom = new DOMDocument();\n        // Fix possible whitspace problems\n        $dom->preserveWhiteSpace = false;\n        // read the response of the CAS server into a DOM object\n        if ( !($dom->loadXML($cas_response))) {\n            phpCAS::trace('dom->loadXML() failed');\n            // read failed\n            $bad_response = true;\n        }\n\n        if ( !$bad_response ) {\n            // read the root node of the XML tree\n            if ( !($root = $dom->documentElement) ) {\n                phpCAS::trace('documentElement failed');\n                // read failed\n                $bad_response = true;\n            }\n        }\n\n        if ( !$bad_response ) {\n            // insure that tag name is 'serviceResponse'\n            if ( $root->localName != 'serviceResponse' ) {\n                phpCAS::trace('localName failed');\n                // bad root node\n                $bad_response = true;\n            }\n        }\n\n        if ( !$bad_response ) {\n            // look for a proxySuccess tag\n            if ( $root->getElementsByTagName(\"proxySuccess\")->length != 0) {\n                $proxy_success_list = $root->getElementsByTagName(\"proxySuccess\");\n\n                // authentication succeded, look for a proxyTicket tag\n                if ( $proxy_success_list->item(0)->getElementsByTagName(\"proxyTicket\")->length != 0) {\n                    $err_code = PHPCAS_SERVICE_OK;\n                    $err_msg = '';\n                    $pt = trim(\n                        $proxy_success_list->item(0)->getElementsByTagName(\"proxyTicket\")->item(0)->nodeValue\n                    );\n                    phpCAS::trace('original PT: '.trim($pt));\n                    phpCAS::traceEnd($pt);\n                    return $pt;\n                } else {\n                    phpCAS::trace('<proxySuccess> was found, but not <proxyTicket>');\n                }\n            } else if ($root->getElementsByTagName(\"proxyFailure\")->length != 0) {\n                // look for a proxyFailure tag\n                $proxy_failure_list = $root->getElementsByTagName(\"proxyFailure\");\n\n                // authentication failed, extract the error\n                $err_code = PHPCAS_SERVICE_PT_FAILURE;\n                $err_msg = 'PT retrieving failed (code=`'\n                .$proxy_failure_list->item(0)->getAttribute('code')\n                .'\\', message=`'\n                .trim($proxy_failure_list->item(0)->nodeValue)\n                .'\\')';\n                phpCAS::traceEnd(false);\n                return false;\n            } else {\n                phpCAS::trace('neither <proxySuccess> nor <proxyFailure> found');\n            }\n        }\n\n        // at this step, we are sure that the response of the CAS server was\n        // illformed\n        $err_code = PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE;\n        $err_msg = 'Invalid response from the CAS server (response=`'\n            .$cas_response.'\\')';\n\n        phpCAS::traceEnd(false);\n        return false;\n    }\n\n    /** @} */\n\n    // ########################################################################\n    // READ CAS SERVER ANSWERS\n    // ########################################################################\n\n    /**\n     * @addtogroup internalMisc\n     * @{\n     */\n\n    /**\n     * This method is used to acces a remote URL.\n     *\n     * @param string $url      the URL to access.\n     * @param string &$headers an array containing the HTTP header lines of the\n     * response (an empty array on failure).\n     * @param string &$body    the body of the response, as a string (empty on\n     * failure).\n     * @param string &$err_msg an error message, filled on failure.\n     *\n     * @return bool true on success, false otherwise (in this later case, $err_msg\n     * contains an error message).\n     */\n    private function _readURL($url, &$headers, &$body, &$err_msg)\n    {\n        phpCAS::traceBegin();\n        $className = $this->_requestImplementation;\n        $request = new $className();\n\n        if (count($this->_curl_options)) {\n            $request->setCurlOptions($this->_curl_options);\n        }\n\n        $request->setUrl($url);\n\n        if (empty($this->_cas_server_ca_cert) && !$this->_no_cas_server_validation) {\n            phpCAS::error(\n                'one of the methods phpCAS::setCasServerCACert() or phpCAS::setNoCasServerValidation() must be called.'\n            );\n        }\n        if ($this->_cas_server_ca_cert != '') {\n            $request->setSslCaCert(\n                $this->_cas_server_ca_cert, $this->_cas_server_cn_validate\n            );\n        }\n\n        // add extra stuff if SAML\n        if ($this->getServerVersion() == SAML_VERSION_1_1) {\n            $request->addHeader(\"soapaction: http://www.oasis-open.org/committees/security\");\n            $request->addHeader(\"cache-control: no-cache\");\n            $request->addHeader(\"pragma: no-cache\");\n            $request->addHeader(\"accept: text/xml\");\n            $request->addHeader(\"connection: keep-alive\");\n            $request->addHeader(\"content-type: text/xml\");\n            $request->makePost();\n            $request->setPostBody($this->_buildSAMLPayload());\n        }\n\n        if ($request->send()) {\n            $headers = $request->getResponseHeaders();\n            $body = $request->getResponseBody();\n            $err_msg = '';\n            phpCAS::traceEnd(true);\n            return true;\n        } else {\n            $headers = '';\n            $body = '';\n            $err_msg = $request->getErrorMessage();\n            phpCAS::traceEnd(false);\n            return false;\n        }\n    }\n\n    /**\n     * This method is used to build the SAML POST body sent to /samlValidate URL.\n     *\n     * @return string the SOAP-encased SAMLP artifact (the ticket).\n     */\n    private function _buildSAMLPayload()\n    {\n        phpCAS::traceBegin();\n\n        //get the ticket\n        $sa = urlencode($this->getTicket());\n\n        $body = SAML_SOAP_ENV.SAML_SOAP_BODY.SAMLP_REQUEST\n            .SAML_ASSERTION_ARTIFACT.$sa.SAML_ASSERTION_ARTIFACT_CLOSE\n            .SAMLP_REQUEST_CLOSE.SAML_SOAP_BODY_CLOSE.SAML_SOAP_ENV_CLOSE;\n\n        phpCAS::traceEnd($body);\n        return ($body);\n    }\n\n    /** @} **/\n\n    // ########################################################################\n    // ACCESS TO EXTERNAL SERVICES\n    // ########################################################################\n\n    /**\n     * @addtogroup internalProxyServices\n     * @{\n     */\n\n\n    /**\n     * Answer a proxy-authenticated service handler.\n     *\n     * @param string $type The service type. One of:\n     * PHPCAS_PROXIED_SERVICE_HTTP_GET, PHPCAS_PROXIED_SERVICE_HTTP_POST,\n     * PHPCAS_PROXIED_SERVICE_IMAP\n     *\n     * @return CAS_ProxiedService\n     * @throws InvalidArgumentException If the service type is unknown.\n     */\n    public function getProxiedService ($type)\n    {\n        // Sequence validation\n        $this->ensureIsProxy();\n        $this->ensureAuthenticationCallSuccessful();\n\n        // Argument validation\n        if (gettype($type) != 'string')\n            throw new CAS_TypeMismatchException($type, '$type', 'string');\n\n        switch ($type) {\n        case PHPCAS_PROXIED_SERVICE_HTTP_GET:\n        case PHPCAS_PROXIED_SERVICE_HTTP_POST:\n            $requestClass = $this->_requestImplementation;\n            $request = new $requestClass();\n            if (count($this->_curl_options)) {\n                $request->setCurlOptions($this->_curl_options);\n            }\n            $proxiedService = new $type($request, $this->_serviceCookieJar);\n            if ($proxiedService instanceof CAS_ProxiedService_Testable) {\n                $proxiedService->setCasClient($this);\n            }\n            return $proxiedService;\n        case PHPCAS_PROXIED_SERVICE_IMAP;\n            $proxiedService = new CAS_ProxiedService_Imap($this->_getUser());\n            if ($proxiedService instanceof CAS_ProxiedService_Testable) {\n                $proxiedService->setCasClient($this);\n            }\n            return $proxiedService;\n        default:\n            throw new CAS_InvalidArgumentException(\n                \"Unknown proxied-service type, $type.\"\n            );\n        }\n    }\n\n    /**\n     * Initialize a proxied-service handler with the proxy-ticket it should use.\n     *\n     * @param CAS_ProxiedService $proxiedService service handler\n     *\n     * @return void\n     *\n     * @throws CAS_ProxyTicketException If there is a proxy-ticket failure.\n     *\t\tThe code of the Exception will be one of:\n     *\t\t\tPHPCAS_SERVICE_PT_NO_SERVER_RESPONSE\n     *\t\t\tPHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE\n     *\t\t\tPHPCAS_SERVICE_PT_FAILURE\n     * @throws CAS_ProxiedService_Exception If there is a failure getting the\n     * url from the proxied service.\n     */\n    public function initializeProxiedService (CAS_ProxiedService $proxiedService)\n    {\n        // Sequence validation\n        $this->ensureIsProxy();\n        $this->ensureAuthenticationCallSuccessful();\n\n        $url = $proxiedService->getServiceUrl();\n        if (!is_string($url)) {\n            throw new CAS_ProxiedService_Exception(\n                \"Proxied Service \".get_class($proxiedService)\n                .\"->getServiceUrl() should have returned a string, returned a \"\n                .gettype($url).\" instead.\"\n            );\n        }\n        $pt = $this->retrievePT($url, $err_code, $err_msg);\n        if (!$pt) {\n            throw new CAS_ProxyTicketException($err_msg, $err_code);\n        }\n        $proxiedService->setProxyTicket($pt);\n    }\n\n    /**\n     * This method is used to access an HTTP[S] service.\n     *\n     * @param string $url       the service to access.\n     * @param int    &$err_code an error code Possible values are\n     * PHPCAS_SERVICE_OK (on success), PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE,\n     * PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE, PHPCAS_SERVICE_PT_FAILURE,\n     * PHPCAS_SERVICE_NOT_AVAILABLE.\n     * @param string &$output   the output of the service (also used to give an error\n     * message on failure).\n     *\n     * @return bool true on success, false otherwise (in this later case, $err_code\n     * gives the reason why it failed and $output contains an error message).\n     */\n    public function serviceWeb($url,&$err_code,&$output)\n    {\n        // Sequence validation\n        $this->ensureIsProxy();\n        $this->ensureAuthenticationCallSuccessful();\n\n        // Argument validation\n        if (gettype($url) != 'string')\n            throw new CAS_TypeMismatchException($url, '$url', 'string');\n\n        try {\n            $service = $this->getProxiedService(PHPCAS_PROXIED_SERVICE_HTTP_GET);\n            $service->setUrl($url);\n            $service->send();\n            $output = $service->getResponseBody();\n            $err_code = PHPCAS_SERVICE_OK;\n            return true;\n        } catch (CAS_ProxyTicketException $e) {\n            $err_code = $e->getCode();\n            $output = $e->getMessage();\n            return false;\n        } catch (CAS_ProxiedService_Exception $e) {\n            $lang = $this->getLangObj();\n            $output = sprintf(\n                $lang->getServiceUnavailable(), $url, $e->getMessage()\n            );\n            $err_code = PHPCAS_SERVICE_NOT_AVAILABLE;\n            return false;\n        }\n    }\n\n    /**\n     * This method is used to access an IMAP/POP3/NNTP service.\n     *\n     * @param string $url        a string giving the URL of the service, including\n     * the mailing box for IMAP URLs, as accepted by imap_open().\n     * @param string $serviceUrl a string giving for CAS retrieve Proxy ticket\n     * @param string $flags      options given to imap_open().\n     * @param int    &$err_code  an error code Possible values are\n     * PHPCAS_SERVICE_OK (on success), PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE,\n     * PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE, PHPCAS_SERVICE_PT_FAILURE,\n     *  PHPCAS_SERVICE_NOT_AVAILABLE.\n     * @param string &$err_msg   an error message on failure\n     * @param string &$pt        the Proxy Ticket (PT) retrieved from the CAS\n     * server to access the URL on success, false on error).\n     *\n     * @return object|false an IMAP stream on success, false otherwise (in this later\n     *  case, $err_code gives the reason why it failed and $err_msg contains an\n     *  error message).\n     */\n    public function serviceMail($url,$serviceUrl,$flags,&$err_code,&$err_msg,&$pt)\n    {\n        // Sequence validation\n        $this->ensureIsProxy();\n        $this->ensureAuthenticationCallSuccessful();\n\n        // Argument validation\n        if (gettype($url) != 'string')\n            throw new CAS_TypeMismatchException($url, '$url', 'string');\n        if (gettype($serviceUrl) != 'string')\n            throw new CAS_TypeMismatchException($serviceUrl, '$serviceUrl', 'string');\n        if (gettype($flags) != 'integer')\n            throw new CAS_TypeMismatchException($flags, '$flags', 'string');\n\n        try {\n            $service = $this->getProxiedService(PHPCAS_PROXIED_SERVICE_IMAP);\n            $service->setServiceUrl($serviceUrl);\n            $service->setMailbox($url);\n            $service->setOptions($flags);\n\n            $stream = $service->open();\n            $err_code = PHPCAS_SERVICE_OK;\n            $pt = $service->getImapProxyTicket();\n            return $stream;\n        } catch (CAS_ProxyTicketException $e) {\n            $err_msg = $e->getMessage();\n            $err_code = $e->getCode();\n            $pt = false;\n            return false;\n        } catch (CAS_ProxiedService_Exception $e) {\n            $lang = $this->getLangObj();\n            $err_msg = sprintf(\n                $lang->getServiceUnavailable(),\n                $url,\n                $e->getMessage()\n            );\n            $err_code = PHPCAS_SERVICE_NOT_AVAILABLE;\n            $pt = false;\n            return false;\n        }\n    }\n\n    /** @} **/\n\n    // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n    // XX                                                                    XX\n    // XX                  PROXIED CLIENT FEATURES (CAS 2.0)                 XX\n    // XX                                                                    XX\n    // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n\n    // ########################################################################\n    //  PT\n    // ########################################################################\n    /**\n    * @addtogroup internalService\n    * @{\n    */\n\n    /**\n     * This array will store a list of proxies in front of this application. This\n     * property will only be populated if this script is being proxied rather than\n     * accessed directly.\n     *\n     * It is set in CAS_Client::validateCAS20() and can be read by\n     * CAS_Client::getProxies()\n     *\n     * @access private\n     */\n    private $_proxies = array();\n\n    /**\n     * Answer an array of proxies that are sitting in front of this application.\n     *\n     * This method will only return a non-empty array if we have received and\n     * validated a Proxy Ticket.\n     *\n     * @return array\n     * @access public\n     */\n    public function getProxies()\n    {\n        return $this->_proxies;\n    }\n\n    /**\n     * Set the Proxy array, probably from persistant storage.\n     *\n     * @param array $proxies An array of proxies\n     *\n     * @return void\n     * @access private\n     */\n    private function _setProxies($proxies)\n    {\n        $this->_proxies = $proxies;\n        if (!empty($proxies)) {\n            // For proxy-authenticated requests people are not viewing the URL\n            // directly since the client is another application making a\n            // web-service call.\n            // Because of this, stripping the ticket from the URL is unnecessary\n            // and causes another web-service request to be performed. Additionally,\n            // if session handling on either the client or the server malfunctions\n            // then the subsequent request will not complete successfully.\n            $this->setNoClearTicketsFromUrl();\n        }\n    }\n\n    /**\n     * A container of patterns to be allowed as proxies in front of the cas client.\n     *\n     * @var CAS_ProxyChain_AllowedList\n     */\n    private $_allowed_proxy_chains;\n\n    /**\n     * Answer the CAS_ProxyChain_AllowedList object for this client.\n     *\n     * @return CAS_ProxyChain_AllowedList\n     */\n    public function getAllowedProxyChains ()\n    {\n        if (empty($this->_allowed_proxy_chains)) {\n            $this->_allowed_proxy_chains = new CAS_ProxyChain_AllowedList();\n        }\n        return $this->_allowed_proxy_chains;\n    }\n\n    /** @} */\n    // ########################################################################\n    //  PT VALIDATION\n    // ########################################################################\n    /**\n    * @addtogroup internalProxied\n    * @{\n    */\n\n    /**\n     * This method is used to validate a cas 2.0 ST or PT; halt on failure\n     * Used for all CAS 2.0 validations\n     *\n     * @param string &$validate_url  the url of the reponse\n     * @param string &$text_response the text of the repsones\n     * @param DOMElement &$tree_response the domxml tree of the respones\n     * @param bool   $renew          true to force the authentication with the CAS server\n     *\n     * @return bool true when successfull and issue a CAS_AuthenticationException\n     * and false on an error\n     *\n     * @throws  CAS_AuthenticationException\n     */\n    public function validateCAS20(&$validate_url,&$text_response,&$tree_response, $renew=false)\n    {\n        phpCAS::traceBegin();\n        phpCAS::trace($text_response);\n        // build the URL to validate the ticket\n        if ($this->getAllowedProxyChains()->isProxyingAllowed()) {\n            $validate_url = $this->getServerProxyValidateURL().'&ticket='\n                .urlencode($this->getTicket());\n        } else {\n            $validate_url = $this->getServerServiceValidateURL().'&ticket='\n                .urlencode($this->getTicket());\n        }\n\n        if ( $this->isProxy() ) {\n            // pass the callback url for CAS proxies\n            $validate_url .= '&pgtUrl='.urlencode($this->_getCallbackURL());\n        }\n\n        if ( $renew ) {\n            // pass the renew\n            $validate_url .= '&renew=true';\n        }\n\n        // open and read the URL\n        if ( !$this->_readURL($validate_url, $headers, $text_response, $err_msg) ) {\n            phpCAS::trace(\n                'could not open URL \\''.$validate_url.'\\' to validate ('.$err_msg.')'\n            );\n            throw new CAS_AuthenticationException(\n                $this, 'Ticket not validated', $validate_url,\n                true/*$no_response*/\n            );\n        }\n\n        // create new DOMDocument object\n        $dom = new DOMDocument();\n        // Fix possible whitspace problems\n        $dom->preserveWhiteSpace = false;\n        // CAS servers should only return data in utf-8\n        $dom->encoding = \"utf-8\";\n        // read the response of the CAS server into a DOMDocument object\n        if ( !($dom->loadXML($text_response))) {\n            // read failed\n            throw new CAS_AuthenticationException(\n                $this, 'Ticket not validated', $validate_url,\n                false/*$no_response*/, true/*$bad_response*/, $text_response\n            );\n        } else if ( !($tree_response = $dom->documentElement) ) {\n            // read the root node of the XML tree\n            // read failed\n            throw new CAS_AuthenticationException(\n                $this, 'Ticket not validated', $validate_url,\n                false/*$no_response*/, true/*$bad_response*/, $text_response\n            );\n        } else if ($tree_response->localName != 'serviceResponse') {\n            // insure that tag name is 'serviceResponse'\n            // bad root node\n            throw new CAS_AuthenticationException(\n                $this, 'Ticket not validated', $validate_url,\n                false/*$no_response*/, true/*$bad_response*/, $text_response\n            );\n        } else if ( $tree_response->getElementsByTagName(\"authenticationFailure\")->length != 0) {\n            // authentication failed, extract the error code and message and throw exception\n            $auth_fail_list = $tree_response\n                ->getElementsByTagName(\"authenticationFailure\");\n            throw new CAS_AuthenticationException(\n                $this, 'Ticket not validated', $validate_url,\n                false/*$no_response*/, false/*$bad_response*/,\n                $text_response,\n                $auth_fail_list->item(0)->getAttribute('code')/*$err_code*/,\n                trim($auth_fail_list->item(0)->nodeValue)/*$err_msg*/\n            );\n        } else if ($tree_response->getElementsByTagName(\"authenticationSuccess\")->length != 0) {\n            // authentication succeded, extract the user name\n            $success_elements = $tree_response\n                ->getElementsByTagName(\"authenticationSuccess\");\n            if ( $success_elements->item(0)->getElementsByTagName(\"user\")->length == 0) {\n                // no user specified => error\n                throw new CAS_AuthenticationException(\n                    $this, 'Ticket not validated', $validate_url,\n                    false/*$no_response*/, true/*$bad_response*/, $text_response\n                );\n            } else {\n                $this->_setUser(\n                    trim(\n                        $success_elements->item(0)->getElementsByTagName(\"user\")->item(0)->nodeValue\n                    )\n                );\n                $this->_readExtraAttributesCas20($success_elements);\n                // Store the proxies we are sitting behind for authorization checking\n                $proxyList = array();\n                if ( sizeof($arr = $success_elements->item(0)->getElementsByTagName(\"proxy\")) > 0) {\n                    foreach ($arr as $proxyElem) {\n                        phpCAS::trace(\"Found Proxy: \".$proxyElem->nodeValue);\n                        $proxyList[] = trim($proxyElem->nodeValue);\n                    }\n                    $this->_setProxies($proxyList);\n                    phpCAS::trace(\"Storing Proxy List\");\n                }\n                // Check if the proxies in front of us are allowed\n                if (!$this->getAllowedProxyChains()->isProxyListAllowed($proxyList)) {\n                    throw new CAS_AuthenticationException(\n                        $this, 'Proxy not allowed', $validate_url,\n                        false/*$no_response*/, true/*$bad_response*/,\n                        $text_response\n                    );\n                } else {\n                    $result = true;\n                }\n            }\n        } else {\n            throw new CAS_AuthenticationException(\n                $this, 'Ticket not validated', $validate_url,\n                false/*$no_response*/, true/*$bad_response*/,\n                $text_response\n            );\n        }\n\n        $this->_renameSession($this->getTicket());\n\n        // at this step, Ticket has been validated and $this->_user has been set,\n\n        phpCAS::traceEnd($result);\n        return $result;\n    }\n\n    /**\n     * This method recursively parses the attribute XML.\n     * It also collapses name-value pairs into a single\n     * array entry. It parses all common formats of\n     * attributes and well formed XML files.\n     *\n     * @param string $root       the DOM root element to be parsed\n     * @param string $namespace  namespace of the elements\n     *\n     * @return an array of the parsed XML elements\n     *\n     * Formats tested:\n     *\n     *  \"Jasig Style\" Attributes:\n     *\n     *      <cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>\n     *          <cas:authenticationSuccess>\n     *              <cas:user>jsmith</cas:user>\n     *              <cas:attributes>\n     *                  <cas:attraStyle>RubyCAS</cas:attraStyle>\n     *                  <cas:surname>Smith</cas:surname>\n     *                  <cas:givenName>John</cas:givenName>\n     *                  <cas:memberOf>CN=Staff,OU=Groups,DC=example,DC=edu</cas:memberOf>\n     *                  <cas:memberOf>CN=Spanish Department,OU=Departments,OU=Groups,DC=example,DC=edu</cas:memberOf>\n     *              </cas:attributes>\n     *              <cas:proxyGrantingTicket>PGTIOU-84678-8a9d2sfa23casd</cas:proxyGrantingTicket>\n     *          </cas:authenticationSuccess>\n     *      </cas:serviceResponse>\n     *\n     *  \"Jasig Style\" Attributes (longer version):\n     *\n     *      <cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>\n     *          <cas:authenticationSuccess>\n     *              <cas:user>jsmith</cas:user>\n     *              <cas:attributes>\n     *                  <cas:attribute>\n     *                      <cas:name>surname</cas:name>\n     *                      <cas:value>Smith</cas:value>\n     *                  </cas:attribute>\n     *                  <cas:attribute>\n     *                      <cas:name>givenName</cas:name>\n     *                      <cas:value>John</cas:value>\n     *                  </cas:attribute>\n     *                  <cas:attribute>\n     *                      <cas:name>memberOf</cas:name>\n     *                      <cas:value>['CN=Staff,OU=Groups,DC=example,DC=edu', 'CN=Spanish Department,OU=Departments,OU=Groups,DC=example,DC=edu']</cas:value>\n     *                  </cas:attribute>\n     *              </cas:attributes>\n     *              <cas:proxyGrantingTicket>PGTIOU-84678-8a9d2sfa23casd</cas:proxyGrantingTicket>\n     *          </cas:authenticationSuccess>\n     *      </cas:serviceResponse>\n     *\n     *  \"RubyCAS Style\" attributes\n     *\n     *      <cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>\n     *          <cas:authenticationSuccess>\n     *              <cas:user>jsmith</cas:user>\n     *\n     *              <cas:attraStyle>RubyCAS</cas:attraStyle>\n     *              <cas:surname>Smith</cas:surname>\n     *              <cas:givenName>John</cas:givenName>\n     *              <cas:memberOf>CN=Staff,OU=Groups,DC=example,DC=edu</cas:memberOf>\n     *              <cas:memberOf>CN=Spanish Department,OU=Departments,OU=Groups,DC=example,DC=edu</cas:memberOf>\n     *\n     *              <cas:proxyGrantingTicket>PGTIOU-84678-8a9d2sfa23casd</cas:proxyGrantingTicket>\n     *          </cas:authenticationSuccess>\n     *      </cas:serviceResponse>\n     *\n     *  \"Name-Value\" attributes.\n     *\n     *  Attribute format from these mailing list thread:\n     *  http://jasig.275507.n4.nabble.com/CAS-attributes-and-how-they-appear-in-the-CAS-response-td264272.html\n     *  Note: This is a less widely used format, but in use by at least two institutions.\n     *\n     *      <cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>\n     *          <cas:authenticationSuccess>\n     *              <cas:user>jsmith</cas:user>\n     *\n     *              <cas:attribute name='attraStyle' value='Name-Value' />\n     *              <cas:attribute name='surname' value='Smith' />\n     *              <cas:attribute name='givenName' value='John' />\n     *              <cas:attribute name='memberOf' value='CN=Staff,OU=Groups,DC=example,DC=edu' />\n     *              <cas:attribute name='memberOf' value='CN=Spanish Department,OU=Departments,OU=Groups,DC=example,DC=edu' />\n     *\n     *              <cas:proxyGrantingTicket>PGTIOU-84678-8a9d2sfa23casd</cas:proxyGrantingTicket>\n     *          </cas:authenticationSuccess>\n     *      </cas:serviceResponse>\n     *\n     * result:\n     *\n     *      Array (\n     *          [surname] => Smith\n     *          [givenName] => John\n     *          [memberOf] => Array (\n     *              [0] => CN=Staff, OU=Groups, DC=example, DC=edu\n     *              [1] => CN=Spanish Department, OU=Departments, OU=Groups, DC=example, DC=edu\n     *          )\n     *      )\n     */\n    private function _xml_to_array($root, $namespace = \"cas\")\n    {\n        $result = array();\n        if ($root->hasAttributes()) {\n            $attrs = $root->attributes;\n            $pair = array();\n            foreach ($attrs as $attr) {\n                if ($attr->name === \"name\") {\n                    $pair['name'] = $attr->value;\n                } elseif ($attr->name === \"value\") {\n                    $pair['value'] = $attr->value;\n                } else {\n                    $result[$attr->name] = $attr->value;\n                }\n                if (array_key_exists('name', $pair) && array_key_exists('value', $pair)) {\n                    $result[$pair['name']] = $pair['value'];\n                }\n            }\n        }\n        if ($root->hasChildNodes()) {\n            $children = $root->childNodes;\n            if ($children->length == 1) {\n                $child = $children->item(0);\n                if ($child->nodeType == XML_TEXT_NODE) {\n                    $result['_value'] = $child->nodeValue;\n                    return (count($result) == 1) ? $result['_value'] : $result;\n                }\n            }\n            $groups = array();\n            foreach ($children as $child) {\n                $child_nodeName = str_ireplace($namespace . \":\", \"\", $child->nodeName);\n                if (in_array($child_nodeName, array(\"user\", \"proxies\", \"proxyGrantingTicket\"))) {\n                    continue;\n                }\n                if (!isset($result[$child_nodeName])) {\n                    $res = $this->_xml_to_array($child, $namespace);\n                    if (!empty($res)) {\n                        $result[$child_nodeName] = $this->_xml_to_array($child, $namespace);\n                    }\n                } else {\n                    if (!isset($groups[$child_nodeName])) {\n                        $result[$child_nodeName] = array($result[$child_nodeName]);\n                        $groups[$child_nodeName] = 1;\n                    }\n                    $result[$child_nodeName][] = $this->_xml_to_array($child, $namespace);\n                }\n            }\n        }\n        return $result;\n    }\n\n    /**\n     * This method parses a \"JSON-like array\" of strings\n     * into an array of strings\n     *\n     * @param string $json_value  the json-like string:\n     *      e.g.:\n     *          ['CN=Staff,OU=Groups,DC=example,DC=edu', 'CN=Spanish Department,OU=Departments,OU=Groups,DC=example,DC=edu']\n     *\n     * @return array of strings Description\n     *      e.g.:\n     *          Array (\n     *              [0] => CN=Staff,OU=Groups,DC=example,DC=edu\n     *              [1] => CN=Spanish Department,OU=Departments,OU=Groups,DC=example,DC=edu\n     *          )\n     */\n    private function _parse_json_like_array_value($json_value)\n    {\n        $parts = explode(\",\", trim($json_value, \"[]\"));\n        $out = array();\n        $quote = '';\n        foreach ($parts as $part) {\n            $part = trim($part);\n            if ($quote === '') {\n                $value = \"\";\n                if ($this->_startsWith($part, '\\'')) {\n                    $quote = '\\'';\n                } elseif ($this->_startsWith($part, '\"')) {\n                    $quote = '\"';\n                } else {\n                    $out[] = $part;\n                }\n                $part = ltrim($part, $quote);\n            }\n            if ($quote !== '') {\n                $value .= $part;\n                if ($this->_endsWith($part, $quote)) {\n                    $out[] = rtrim($value, $quote);\n                    $quote = '';\n                } else {\n                    $value .= \", \";\n                };\n            }\n        }\n        return $out;\n    }\n\n    /**\n     * This method recursively removes unneccessary hirarchy levels in array-trees.\n     * into an array of strings\n     *\n     * @param array $arr the array to flatten\n     *      e.g.:\n     *          Array (\n     *              [attributes] => Array (\n     *                  [attribute] => Array (\n     *                      [0] => Array (\n     *                          [name] => surname\n     *                          [value] => Smith\n     *                      )\n     *                      [1] => Array (\n     *                          [name] => givenName\n     *                          [value] => John\n     *                      )\n     *                      [2] => Array (\n     *                          [name] => memberOf\n     *                          [value] => ['CN=Staff,OU=Groups,DC=example,DC=edu', 'CN=Spanish Department,OU=Departments,OU=Groups,DC=example,DC=edu']\n     *                      )\n     *                  )\n     *              )\n     *          )\n     *\n     * @return array the flattened array\n     *      e.g.:\n     *          Array (\n     *              [attribute] => Array (\n     *                  [surname] => Smith\n     *                  [givenName] => John\n     *                  [memberOf] => Array (\n     *                      [0] => CN=Staff, OU=Groups, DC=example, DC=edu\n     *                      [1] => CN=Spanish Department, OU=Departments, OU=Groups, DC=example, DC=edu\n     *                  )\n     *              )\n     *          )\n     */\n    private function _flatten_array($arr)\n    {\n        if (!is_array($arr)) {\n            if ($this->_startsWith($arr, '[') && $this->_endsWith($arr, ']')) {\n                return $this->_parse_json_like_array_value($arr);\n            } else {\n                return $arr;\n            }\n        }\n        $out = array();\n        foreach ($arr as $key => $val) {\n            if (!is_array($val)) {\n                $out[$key] = $val;\n            } else {\n                switch (count($val)) {\n                case 1 : {\n                        $key = key($val);\n                        if (array_key_exists($key, $out)) {\n                            $value = $out[$key];\n                            if (!is_array($value)) {\n                                $out[$key] = array();\n                                $out[$key][] = $value;\n                            }\n                            $out[$key][] = $this->_flatten_array($val[$key]);\n                        } else {\n                            $out[$key] = $this->_flatten_array($val[$key]);\n                        };\n                        break;\n                    };\n                case 2 : {\n                        if (array_key_exists(\"name\", $val) && array_key_exists(\"value\", $val)) {\n                            $key = $val['name'];\n                            if (array_key_exists($key, $out)) {\n                                $value = $out[$key];\n                                if (!is_array($value)) {\n                                    $out[$key] = array();\n                                    $out[$key][] = $value;\n                                }\n                                $out[$key][] = $this->_flatten_array($val['value']);\n                            } else {\n                                $out[$key] = $this->_flatten_array($val['value']);\n                            };\n                        } else {\n                            $out[$key] = $this->_flatten_array($val);\n                        }\n                        break;\n                    };\n                default: {\n                        $out[$key] = $this->_flatten_array($val);\n                    }\n                }\n            }\n        }\n        return $out;\n    }\n\n    /**\n     * This method will parse the DOM and pull out the attributes from the XML\n     * payload and put them into an array, then put the array into the session.\n     *\n     * @param DOMNodeList $success_elements payload of the response\n     *\n     * @return bool true when successfull, halt otherwise by calling\n     * CAS_Client::_authError().\n     */\n    private function _readExtraAttributesCas20($success_elements)\n    {\n        phpCAS::traceBegin();\n\n        $extra_attributes = array();\n        if ($this->_casAttributeParserCallbackFunction !== null\n            && is_callable($this->_casAttributeParserCallbackFunction)\n        ) {\n            array_unshift($this->_casAttributeParserCallbackArgs, $success_elements->item(0));\n            phpCAS :: trace(\"Calling attritubeParser callback\");\n            $extra_attributes =  call_user_func_array(\n                $this->_casAttributeParserCallbackFunction,\n                $this->_casAttributeParserCallbackArgs\n            );\n        } else {\n            phpCAS :: trace(\"Parse extra attributes:    \");\n            $attributes = $this->_xml_to_array($success_elements->item(0));\n            phpCAS :: trace(print_r($attributes,true). \"\\nFLATTEN Array:    \");\n            $extra_attributes = $this->_flatten_array($attributes);\n            phpCAS :: trace(print_r($extra_attributes, true).\"\\nFILTER :    \");\n            if (array_key_exists(\"attribute\", $extra_attributes)) {\n                $extra_attributes = $extra_attributes[\"attribute\"];\n            } elseif (array_key_exists(\"attributes\", $extra_attributes)) {\n                $extra_attributes = $extra_attributes[\"attributes\"];\n            };\n            phpCAS :: trace(print_r($extra_attributes, true).\"return\");\n        }\n        $this->setAttributes($extra_attributes);\n        phpCAS::traceEnd();\n        return true;\n    }\n\n    /**\n     * Add an attribute value to an array of attributes.\n     *\n     * @param array  &$attributeArray reference to array\n     * @param string $name            name of attribute\n     * @param string $value           value of attribute\n     *\n     * @return void\n     */\n    private function _addAttributeToArray(array &$attributeArray, $name, $value)\n    {\n        // If multiple attributes exist, add as an array value\n        if (isset($attributeArray[$name])) {\n            // Initialize the array with the existing value\n            if (!is_array($attributeArray[$name])) {\n                $existingValue = $attributeArray[$name];\n                $attributeArray[$name] = array($existingValue);\n            }\n\n            $attributeArray[$name][] = trim($value);\n        } else {\n            $attributeArray[$name] = trim($value);\n        }\n    }\n\n    /** @} */\n\n    // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n    // XX                                                                    XX\n    // XX                               MISC                                 XX\n    // XX                                                                    XX\n    // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n\n    /**\n     * @addtogroup internalMisc\n     * @{\n     */\n\n    // ########################################################################\n    //  URL\n    // ########################################################################\n    /**\n    * the URL of the current request (without any ticket CGI parameter). Written\n    * and read by CAS_Client::getURL().\n    *\n    * @hideinitializer\n    */\n    private $_url = '';\n\n\n    /**\n     * This method sets the URL of the current request\n     *\n     * @param string $url url to set for service\n     *\n     * @return void\n     */\n    public function setURL($url)\n    {\n        // Argument Validation\n        if (gettype($url) != 'string')\n            throw new CAS_TypeMismatchException($url, '$url', 'string');\n\n        $this->_url = $url;\n    }\n\n    /**\n     * This method returns the URL of the current request (without any ticket\n     * CGI parameter).\n     *\n     * @return string The URL\n     */\n    public function getURL()\n    {\n        phpCAS::traceBegin();\n        // the URL is built when needed only\n        if ( empty($this->_url) ) {\n            // remove the ticket if present in the URL\n            $final_uri = $this->getServiceBaseUrl()->get();\n            $request_uri = explode('?', $_SERVER['REQUEST_URI'], 2);\n            $final_uri .= $request_uri[0];\n\n            if (isset($request_uri[1]) && $request_uri[1]) {\n                $query_string= $this->_removeParameterFromQueryString('ticket', $request_uri[1]);\n\n                // If the query string still has anything left,\n                // append it to the final URI\n                if ($query_string !== '') {\n                    $final_uri .= \"?$query_string\";\n                }\n            }\n\n            phpCAS::trace(\"Final URI: $final_uri\");\n            $this->setURL($final_uri);\n        }\n        phpCAS::traceEnd($this->_url);\n        return $this->_url;\n    }\n\n    /**\n     * This method sets the base URL of the CAS server.\n     *\n     * @param string $url the base URL\n     *\n     * @return string base url\n     */\n    public function setBaseURL($url)\n    {\n        // Argument Validation\n        if (gettype($url) != 'string')\n            throw new CAS_TypeMismatchException($url, '$url', 'string');\n\n        return $this->_server['base_url'] = $url;\n    }\n\n    /**\n     * The ServiceBaseUrl object that provides base URL during service URL\n     * discovery process.\n     *\n     * @var CAS_ServiceBaseUrl_Interface\n     *\n     * @hideinitializer\n     */\n    private $_serviceBaseUrl = null;\n\n    /**\n     * Answer the CAS_ServiceBaseUrl_Interface object for this client.\n     *\n     * @return CAS_ServiceBaseUrl_Interface\n     */\n    public function getServiceBaseUrl()\n    {\n        if (empty($this->_serviceBaseUrl)) {\n            phpCAS::error(\"ServiceBaseUrl object is not initialized\");\n        }\n        return $this->_serviceBaseUrl;\n    }\n\n    /**\n     * This method sets the service base URL used during service URL discovery process.\n     *\n     * This is required since phpCAS 1.6.0 to protect the integrity of the authentication.\n     *\n     * @since phpCAS 1.6.0\n     *\n     * @param $name can be any of the following:\n     *   - A base URL string. The service URL discovery will always use this (protocol,\n     *     hostname and optional port number) without using any external host names.\n     *   - An array of base URL strings. The service URL discovery will check against\n     *     this list before using the auto discovered base URL. If there is no match,\n     *     the first base URL in the array will be used as the default. This option is\n     *     helpful if your PHP website is accessible through multiple domains without a\n     *     canonical name, or through both HTTP and HTTPS.\n     *   - A class that implements CAS_ServiceBaseUrl_Interface. If you need to customize\n     *     the base URL discovery behavior, you can pass in a class that implements the\n     *     interface.\n     *\n     * @return void\n     */\n    private function _setServiceBaseUrl($name)\n    {\n        if (is_array($name)) {\n            $this->_serviceBaseUrl = new CAS_ServiceBaseUrl_AllowedListDiscovery($name);\n        } else if (is_string($name)) {\n            $this->_serviceBaseUrl = new CAS_ServiceBaseUrl_Static($name);\n        } else if ($name instanceof CAS_ServiceBaseUrl_Interface) {\n            $this->_serviceBaseUrl = $name;\n        } else {\n            throw new CAS_TypeMismatchException($name, '$name', 'array, string, or CAS_ServiceBaseUrl_Interface object');\n        }\n    }\n\n    /**\n     * Removes a parameter from a query string\n     *\n     * @param string $parameterName name of parameter\n     * @param string $queryString   query string\n     *\n     * @return string new query string\n     *\n     * @link http://stackoverflow.com/questions/1842681/regular-expression-to-remove-one-parameter-from-query-string\n     */\n    private function _removeParameterFromQueryString($parameterName, $queryString)\n    {\n        $parameterName\t= preg_quote($parameterName);\n        return preg_replace(\n            \"/&$parameterName(=[^&]*)?|^$parameterName(=[^&]*)?&?/\",\n            '', $queryString\n        );\n    }\n\n    /**\n     * This method is used to append query parameters to an url. Since the url\n     * might already contain parameter it has to be detected and to build a proper\n     * URL\n     *\n     * @param string $url   base url to add the query params to\n     * @param string $query params in query form with & separated\n     *\n     * @return string url with query params\n     */\n    private function _buildQueryUrl($url, $query)\n    {\n        $url .= (strstr($url, '?') === false) ? '?' : '&';\n        $url .= $query;\n        return $url;\n    }\n\n    /**\n     * This method tests if a string starts with a given character.\n     *\n     * @param string $text  text to test\n     * @param string $char  character to test for\n     *\n     * @return bool          true if the $text starts with $char\n     */\n    private function _startsWith($text, $char)\n    {\n        return (strpos($text, $char) === 0);\n    }\n\n    /**\n     * This method tests if a string ends with a given character\n     *\n     * @param string $text  text to test\n     * @param string $char  character to test for\n     *\n     * @return bool         true if the $text ends with $char\n     */\n    private function _endsWith($text, $char)\n    {\n        return (strpos(strrev($text), $char) === 0);\n    }\n\n    /**\n     * Answer a valid session-id given a CAS ticket.\n     *\n     * The output must be deterministic to allow single-log-out when presented with\n     * the ticket to log-out.\n     *\n     *\n     * @param string $ticket name of the ticket\n     *\n     * @return string\n     */\n    private function _sessionIdForTicket($ticket)\n    {\n      // Hash the ticket to ensure that the value meets the PHP 7.1 requirement\n      // that session-ids have a length between 22 and 256 characters.\n      return hash('sha256', $this->_sessionIdSalt . $ticket);\n    }\n\n    /**\n     * Set a salt/seed for the session-id hash to make it harder to guess.\n     *\n     * @var string $_sessionIdSalt\n     */\n    private $_sessionIdSalt = '';\n\n    /**\n     * Set a salt/seed for the session-id hash to make it harder to guess.\n     *\n     * @param string $salt\n     *\n     * @return void\n     */\n    public function setSessionIdSalt($salt) {\n      $this->_sessionIdSalt = (string)$salt;\n    }\n\n    // ########################################################################\n    //  AUTHENTICATION ERROR HANDLING\n    // ########################################################################\n    /**\n    * This method is used to print the HTML output when the user was not\n    * authenticated.\n    *\n    * @param string $failure      the failure that occured\n    * @param string $cas_url      the URL the CAS server was asked for\n    * @param bool   $no_response  the response from the CAS server (other\n    * parameters are ignored if true)\n    * @param bool   $bad_response bad response from the CAS server ($err_code\n    * and $err_msg ignored if true)\n    * @param string $cas_response the response of the CAS server\n    * @param int    $err_code     the error code given by the CAS server\n    * @param string $err_msg      the error message given by the CAS server\n    *\n    * @return void\n    */\n    private function _authError(\n        $failure,\n        $cas_url,\n        $no_response=false,\n        $bad_response=false,\n        $cas_response='',\n        $err_code=-1,\n        $err_msg=''\n    ) {\n        phpCAS::traceBegin();\n        $lang = $this->getLangObj();\n        $this->printHTMLHeader($lang->getAuthenticationFailed());\n        $this->printf(\n            $lang->getYouWereNotAuthenticated(), htmlentities($this->getURL()),\n            isset($_SERVER['SERVER_ADMIN']) ? $_SERVER['SERVER_ADMIN']:''\n        );\n        phpCAS::trace('CAS URL: '.$cas_url);\n        phpCAS::trace('Authentication failure: '.$failure);\n        if ( $no_response ) {\n            phpCAS::trace('Reason: no response from the CAS server');\n        } else {\n            if ( $bad_response ) {\n                phpCAS::trace('Reason: bad response from the CAS server');\n            } else {\n                switch ($this->getServerVersion()) {\n                case CAS_VERSION_1_0:\n                    phpCAS::trace('Reason: CAS error');\n                    break;\n                case CAS_VERSION_2_0:\n                case CAS_VERSION_3_0:\n                    if ( $err_code === -1 ) {\n                        phpCAS::trace('Reason: no CAS error');\n                    } else {\n                        phpCAS::trace(\n                            'Reason: ['.$err_code.'] CAS error: '.$err_msg\n                        );\n                    }\n                    break;\n                }\n            }\n            phpCAS::trace('CAS response: '.$cas_response);\n        }\n        $this->printHTMLFooter();\n        phpCAS::traceExit();\n        throw new CAS_GracefullTerminationException();\n    }\n\n    // ########################################################################\n    //  PGTIOU/PGTID and logoutRequest rebroadcasting\n    // ########################################################################\n\n    /**\n     * Boolean of whether to rebroadcast pgtIou/pgtId and logoutRequest, and\n     * array of the nodes.\n     */\n    private $_rebroadcast = false;\n    private $_rebroadcast_nodes = array();\n\n    /**\n     * Constants used for determining rebroadcast node type.\n     */\n    const HOSTNAME = 0;\n    const IP = 1;\n\n    /**\n     * Determine the node type from the URL.\n     *\n     * @param String $nodeURL The node URL.\n     *\n     * @return int hostname\n     *\n     */\n    private function _getNodeType($nodeURL)\n    {\n        phpCAS::traceBegin();\n        if (preg_match(\"/^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$/\", $nodeURL)) {\n            phpCAS::traceEnd(self::IP);\n            return self::IP;\n        } else {\n            phpCAS::traceEnd(self::HOSTNAME);\n            return self::HOSTNAME;\n        }\n    }\n\n    /**\n     * Store the rebroadcast node for pgtIou/pgtId and logout requests.\n     *\n     * @param string $rebroadcastNodeUrl The rebroadcast node URL.\n     *\n     * @return void\n     */\n    public function addRebroadcastNode($rebroadcastNodeUrl)\n    {\n        // Argument validation\n        if ( !(bool)preg_match(\"/^(http|https):\\/\\/([A-Z0-9][A-Z0-9_-]*(?:\\.[A-Z0-9][A-Z0-9_-]*)+):?(\\d+)?\\/?/i\", $rebroadcastNodeUrl))\n            throw new CAS_TypeMismatchException($rebroadcastNodeUrl, '$rebroadcastNodeUrl', 'url');\n\n        // Store the rebroadcast node and set flag\n        $this->_rebroadcast = true;\n        $this->_rebroadcast_nodes[] = $rebroadcastNodeUrl;\n    }\n\n    /**\n     * An array to store extra rebroadcast curl options.\n     */\n    private $_rebroadcast_headers = array();\n\n    /**\n     * This method is used to add header parameters when rebroadcasting\n     * pgtIou/pgtId or logoutRequest.\n     *\n     * @param string $header Header to send when rebroadcasting.\n     *\n     * @return void\n     */\n    public function addRebroadcastHeader($header)\n    {\n        if (gettype($header) != 'string')\n            throw new CAS_TypeMismatchException($header, '$header', 'string');\n\n        $this->_rebroadcast_headers[] = $header;\n    }\n\n    /**\n     * Constants used for determining rebroadcast type (logout or pgtIou/pgtId).\n     */\n    const LOGOUT = 0;\n    const PGTIOU = 1;\n\n    /**\n     * This method rebroadcasts logout/pgtIou requests. Can be LOGOUT,PGTIOU\n     *\n     * @param int $type type of rebroadcasting.\n     *\n     * @return void\n     */\n    private function _rebroadcast($type)\n    {\n        phpCAS::traceBegin();\n\n        $rebroadcast_curl_options = array(\n        CURLOPT_FAILONERROR => 1,\n        CURLOPT_FOLLOWLOCATION => 1,\n        CURLOPT_RETURNTRANSFER => 1,\n        CURLOPT_CONNECTTIMEOUT => 1,\n        CURLOPT_TIMEOUT => 4);\n\n        // Try to determine the IP address of the server\n        if (!empty($_SERVER['SERVER_ADDR'])) {\n            $ip = $_SERVER['SERVER_ADDR'];\n        } else if (!empty($_SERVER['LOCAL_ADDR'])) {\n            // IIS 7\n            $ip = $_SERVER['LOCAL_ADDR'];\n        }\n        // Try to determine the DNS name of the server\n        if (!empty($ip)) {\n            $dns = gethostbyaddr($ip);\n        }\n        $multiClassName = 'CAS_Request_CurlMultiRequest';\n        $multiRequest = new $multiClassName();\n\n        for ($i = 0; $i < sizeof($this->_rebroadcast_nodes); $i++) {\n            if ((($this->_getNodeType($this->_rebroadcast_nodes[$i]) == self::HOSTNAME) && !empty($dns) && (stripos($this->_rebroadcast_nodes[$i], $dns) === false))\n                || (($this->_getNodeType($this->_rebroadcast_nodes[$i]) == self::IP) && !empty($ip) && (stripos($this->_rebroadcast_nodes[$i], $ip) === false))\n            ) {\n                phpCAS::trace(\n                    'Rebroadcast target URL: '.$this->_rebroadcast_nodes[$i]\n                    .$_SERVER['REQUEST_URI']\n                );\n                $className = $this->_requestImplementation;\n                $request = new $className();\n\n                $url = $this->_rebroadcast_nodes[$i].$_SERVER['REQUEST_URI'];\n                $request->setUrl($url);\n\n                if (count($this->_rebroadcast_headers)) {\n                    $request->addHeaders($this->_rebroadcast_headers);\n                }\n\n                $request->makePost();\n                if ($type == self::LOGOUT) {\n                    // Logout request\n                    $request->setPostBody(\n                        'rebroadcast=false&logoutRequest='.$_POST['logoutRequest']\n                    );\n                } else if ($type == self::PGTIOU) {\n                    // pgtIou/pgtId rebroadcast\n                    $request->setPostBody('rebroadcast=false');\n                }\n\n                $request->setCurlOptions($rebroadcast_curl_options);\n\n                $multiRequest->addRequest($request);\n            } else {\n                phpCAS::trace(\n                    'Rebroadcast not sent to self: '\n                    .$this->_rebroadcast_nodes[$i].' == '.(!empty($ip)?$ip:'')\n                    .'/'.(!empty($dns)?$dns:'')\n                );\n            }\n        }\n        // We need at least 1 request\n        if ($multiRequest->getNumRequests() > 0) {\n            $multiRequest->send();\n        }\n        phpCAS::traceEnd();\n    }\n\n    /** @} */\n}\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/CookieJar.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * PHP Version 7\n *\n * @file     CAS/CookieJar.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\n/**\n * This class provides access to service cookies and handles parsing of response\n * headers to pull out cookie values.\n *\n * @class    CAS_CookieJar\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\nclass CAS_CookieJar\n{\n\n    private $_cookies;\n\n    /**\n     * Create a new cookie jar by passing it a reference to an array in which it\n     * should store cookies.\n     *\n     * @param array &$storageArray Array to store cookies\n     *\n     * @return void\n     */\n    public function __construct (array &$storageArray)\n    {\n        $this->_cookies =& $storageArray;\n    }\n\n    /**\n     * Store cookies for a web service request.\n     * Cookie storage is based on RFC 2965: http://www.ietf.org/rfc/rfc2965.txt\n     *\n     * @param string $request_url      The URL that generated the response headers.\n     * @param array  $response_headers An array of the HTTP response header strings.\n     *\n     * @return void\n     *\n     * @access private\n     */\n    public function storeCookies ($request_url, $response_headers)\n    {\n        $urlParts = parse_url($request_url);\n        $defaultDomain = $urlParts['host'];\n\n        $cookies = $this->parseCookieHeaders($response_headers, $defaultDomain);\n\n        foreach ($cookies as $cookie) {\n            // Enforce the same-origin policy by verifying that the cookie\n            // would match the url that is setting it\n            if (!$this->cookieMatchesTarget($cookie, $urlParts)) {\n                continue;\n            }\n\n            // store the cookie\n            $this->storeCookie($cookie);\n\n            phpCAS::trace($cookie['name'].' -> '.$cookie['value']);\n        }\n    }\n\n    /**\n     * Retrieve cookies applicable for a web service request.\n     * Cookie applicability is based on RFC 2965: http://www.ietf.org/rfc/rfc2965.txt\n     *\n     * @param string $request_url The url that the cookies will be for.\n     *\n     * @return array An array containing cookies. E.g. array('name' => 'val');\n     *\n     * @access private\n     */\n    public function getCookies ($request_url)\n    {\n        if (!count($this->_cookies)) {\n            return array();\n        }\n\n        // If our request URL can't be parsed, no cookies apply.\n        $target = parse_url($request_url);\n        if ($target === false) {\n            return array();\n        }\n\n        $this->expireCookies();\n\n        $matching_cookies = array();\n        foreach ($this->_cookies as $key => $cookie) {\n            if ($this->cookieMatchesTarget($cookie, $target)) {\n                $matching_cookies[$cookie['name']] = $cookie['value'];\n            }\n        }\n        return $matching_cookies;\n    }\n\n\n    /**\n     * Parse Cookies without PECL\n     * From the comments in http://php.net/manual/en/function.http-parse-cookie.php\n     *\n     * @param array  $header        array of header lines.\n     * @param string $defaultDomain The domain to use if none is specified in\n     * the cookie.\n     *\n     * @return array of cookies\n     */\n    protected function parseCookieHeaders( $header, $defaultDomain )\n    {\n        phpCAS::traceBegin();\n        $cookies = array();\n        foreach ( $header as $line ) {\n            if ( preg_match('/^Set-Cookie2?: /i', $line)) {\n                $cookies[] = $this->parseCookieHeader($line, $defaultDomain);\n            }\n        }\n\n        phpCAS::traceEnd($cookies);\n        return $cookies;\n    }\n\n    /**\n     * Parse a single cookie header line.\n     *\n     * Based on RFC2965 http://www.ietf.org/rfc/rfc2965.txt\n     *\n     * @param string $line          The header line.\n     * @param string $defaultDomain The domain to use if none is specified in\n     * the cookie.\n     *\n     * @return array\n     */\n    protected function parseCookieHeader ($line, $defaultDomain)\n    {\n        if (!$defaultDomain) {\n            throw new CAS_InvalidArgumentException(\n                '$defaultDomain was not provided.'\n            );\n        }\n\n        // Set our default values\n        $cookie = array(\n            'domain' => $defaultDomain,\n            'path' => '/',\n            'secure' => false,\n        );\n\n        $line = preg_replace('/^Set-Cookie2?: /i', '', trim($line));\n\n        // trim any trailing semicolons.\n        $line = trim($line, ';');\n\n        phpCAS::trace(\"Cookie Line: $line\");\n\n        // This implementation makes the assumption that semicolons will not\n        // be present in quoted attribute values. While attribute values that\n        // contain semicolons are allowed by RFC2965, they are hopefully rare\n        // enough to ignore for our purposes. Most browsers make the same\n        // assumption.\n        $attributeStrings = explode(';', $line);\n\n        foreach ( $attributeStrings as $attributeString ) {\n            // split on the first equals sign and use the rest as value\n            $attributeParts = explode('=', $attributeString, 2);\n\n            $attributeName = trim($attributeParts[0]);\n            $attributeNameLC = strtolower($attributeName);\n\n            if (isset($attributeParts[1])) {\n                $attributeValue = trim($attributeParts[1]);\n                // Values may be quoted strings.\n                if (strpos($attributeValue, '\"') === 0) {\n                    $attributeValue = trim($attributeValue, '\"');\n                    // unescape any escaped quotes:\n                    $attributeValue = str_replace('\\\"', '\"', $attributeValue);\n                }\n            } else {\n                $attributeValue = null;\n            }\n\n            switch ($attributeNameLC) {\n            case 'expires':\n                $cookie['expires'] = strtotime($attributeValue);\n                break;\n            case 'max-age':\n                $cookie['max-age'] = (int)$attributeValue;\n                // Set an expiry time based on the max-age\n                if ($cookie['max-age']) {\n                    $cookie['expires'] = time() + $cookie['max-age'];\n                } else {\n                    // If max-age is zero, then the cookie should be removed\n                    // imediately so set an expiry before now.\n                    $cookie['expires'] = time() - 1;\n                }\n                break;\n            case 'secure':\n                $cookie['secure'] = true;\n                break;\n            case 'domain':\n            case 'path':\n            case 'port':\n            case 'version':\n            case 'comment':\n            case 'commenturl':\n            case 'discard':\n            case 'httponly':\n            case 'samesite':\n                $cookie[$attributeNameLC] = $attributeValue;\n                break;\n            default:\n                $cookie['name'] = $attributeName;\n                $cookie['value'] = $attributeValue;\n            }\n        }\n\n        return $cookie;\n    }\n\n    /**\n     * Add, update, or remove a cookie.\n     *\n     * @param array $cookie A cookie array as created by parseCookieHeaders()\n     *\n     * @return void\n     *\n     * @access protected\n     */\n    protected function storeCookie ($cookie)\n    {\n        // Discard any old versions of this cookie.\n        $this->discardCookie($cookie);\n        $this->_cookies[] = $cookie;\n\n    }\n\n    /**\n     * Discard an existing cookie\n     *\n     * @param array $cookie An cookie\n     *\n     * @return void\n     *\n     * @access protected\n     */\n    protected function discardCookie ($cookie)\n    {\n        if (!isset($cookie['domain'])\n            || !isset($cookie['path'])\n            || !isset($cookie['path'])\n        ) {\n            throw new CAS_InvalidArgumentException('Invalid Cookie array passed.');\n        }\n\n        foreach ($this->_cookies as $key => $old_cookie) {\n            if ( $cookie['domain'] == $old_cookie['domain']\n                && $cookie['path'] == $old_cookie['path']\n                && $cookie['name'] == $old_cookie['name']\n            ) {\n                unset($this->_cookies[$key]);\n            }\n        }\n    }\n\n    /**\n     * Go through our stored cookies and remove any that are expired.\n     *\n     * @return void\n     *\n     * @access protected\n     */\n    protected function expireCookies ()\n    {\n        foreach ($this->_cookies as $key => $cookie) {\n            if (isset($cookie['expires']) && $cookie['expires'] < time()) {\n                unset($this->_cookies[$key]);\n            }\n        }\n    }\n\n    /**\n     * Answer true if cookie is applicable to a target.\n     *\n     * @param array $cookie An array of cookie attributes.\n     * @param array|false $target An array of URL attributes as generated by parse_url().\n     *\n     * @return bool\n     *\n     * @access private\n     */\n    protected function cookieMatchesTarget ($cookie, $target)\n    {\n        if (!is_array($target)) {\n            throw new CAS_InvalidArgumentException(\n                '$target must be an array of URL attributes as generated by parse_url().'\n            );\n        }\n        if (!isset($target['host'])) {\n            throw new CAS_InvalidArgumentException(\n                '$target must be an array of URL attributes as generated by parse_url().'\n            );\n        }\n\n        // Verify that the scheme matches\n        if ($cookie['secure'] && $target['scheme'] != 'https') {\n            return false;\n        }\n\n        // Verify that the host matches\n        // Match domain and mulit-host cookies\n        if (strpos($cookie['domain'], '.') === 0) {\n            // .host.domain.edu cookies are valid for host.domain.edu\n            if (substr($cookie['domain'], 1) == $target['host']) {\n                // continue with other checks\n            } else {\n                // non-exact host-name matches.\n                // check that the target host a.b.c.edu is within .b.c.edu\n                $pos = strripos($target['host'], $cookie['domain']);\n                if (!$pos) {\n                    return false;\n                }\n                // verify that the cookie domain is the last part of the host.\n                if ($pos + strlen($cookie['domain']) != strlen($target['host'])) {\n                    return false;\n                }\n                // verify that the host name does not contain interior dots as per\n                // RFC 2965 section 3.3.2  Rejecting Cookies\n                // http://www.ietf.org/rfc/rfc2965.txt\n                $hostname = substr($target['host'], 0, $pos);\n                if (strpos($hostname, '.') !== false) {\n                    return false;\n                }\n            }\n        } else {\n            // If the cookie host doesn't begin with '.',\n            // the host must case-insensitive match exactly\n            if (strcasecmp($target['host'], $cookie['domain']) !== 0) {\n                return false;\n            }\n        }\n\n        // Verify that the port matches\n        if (isset($cookie['ports'])\n            && !in_array($target['port'], $cookie['ports'])\n        ) {\n            return false;\n        }\n\n        // Verify that the path matches\n        if (strpos($target['path'], $cookie['path']) !== 0) {\n            return false;\n        }\n\n        return true;\n    }\n\n}\n\n?>\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/Exception.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * PHP Version 7\n *\n * @file     CAS/Exception.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\n/**\n * A root exception interface for all exceptions in phpCAS.\n *\n * All exceptions thrown in phpCAS should implement this interface to allow them\n * to be caught as a category by clients. Each phpCAS exception should extend\n * an appropriate SPL exception class that best fits its type.\n *\n * For example, an InvalidArgumentException in phpCAS should be defined as\n *\n *\t\tclass CAS_InvalidArgumentException\n *\t\t\textends InvalidArgumentException\n *\t\t\timplements CAS_Exception\n *\t\t{ }\n *\n * This definition allows the CAS_InvalidArgumentException to be caught as either\n * an InvalidArgumentException or as a CAS_Exception.\n *\n * @class    CAS_Exception\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n *\n */\ninterface CAS_Exception\n{\n\n}\n?>\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/GracefullTerminationException.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * PHP Version 7\n *\n * @file     CAS/GracefullTerminationException.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Joachim Fritschi <jfritschi@freenet.de>\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\n/**\n * An exception for terminatinating execution or to throw for unit testing\n *\n * @class     CAS_GracefullTerminationException.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Joachim Fritschi <jfritschi@freenet.de>\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\nclass CAS_GracefullTerminationException\nextends RuntimeException\nimplements CAS_Exception\n{\n\n    /**\n     * Test if exceptions should be thrown or if we should just exit.\n     * In production usage we want to just exit cleanly when prompting the user\n     * for a redirect without filling the error logs with uncaught exceptions.\n     * In unit testing scenarios we cannot exit or we won't be able to continue\n     * with our tests.\n     *\n     * @param string $message Message Text\n     * @param int $code    Error code\n     *\n     * @return self\n     */\n    public function __construct ($message = 'Terminate Gracefully', $code = 0)\n    {\n        // Exit cleanly to avoid filling up the logs with uncaught exceptions.\n        if (self::$_exitWhenThrown) {\n            exit;\n        } else {\n            // Throw exceptions to allow unit testing to continue;\n            parent::__construct($message, $code);\n        }\n    }\n\n    private static $_exitWhenThrown = true;\n    /**\n    * Force phpcas to thow Exceptions instead of calling exit()\n    * Needed for unit testing. Generally shouldn't be used in production due to\n    * an increase in Apache error logging if CAS_GracefulTerminiationExceptions\n    * are not caught and handled.\n    *\n    * @return void\n    */\n    public static function throwInsteadOfExiting()\n    {\n        self::$_exitWhenThrown = false;\n    }\n\n}\n?>\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/InvalidArgumentException.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * PHP Version 7\n *\n * @file     CAS/InvalidArgumentException.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\n/**\n * Exception that denotes invalid arguments were passed.\n *\n * @class    CAS_InvalidArgumentException\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\nclass CAS_InvalidArgumentException\nextends InvalidArgumentException\nimplements CAS_Exception\n{\n\n}\n?>\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/Languages/Catalan.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * PHP Version 7\n *\n * @file     CAS/Language/Catalan.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Iván-Benjamín García Torà <ivaniclixx@gmail.com>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\n/**\n * Catalan language class\n *\n * @class    CAS_Languages_Catalan\n * @category Authentication\n * @package  PhpCAS\n * @author   Iván-Benjamín García Torà <ivaniclixx@gmail.com>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n *\n * @sa @link internalLang Internationalization @endlink\n * @ingroup internalLang\n */\nclass CAS_Languages_Catalan implements CAS_Languages_LanguageInterface\n{\n    /**\n    * Get the using server string\n    *\n    * @return string using server\n    */\n    public function getUsingServer()\n    {\n        return 'usant servidor';\n    }\n\n    /**\n    * Get authentication wanted string\n    *\n    * @return string authentication wanted\n    */\n    public function getAuthenticationWanted()\n    {\n        return 'Autentificació CAS necessària!';\n    }\n\n    /**\n    * Get logout string\n    *\n    * @return string logout\n    */\n    public function getLogout()\n    {\n        return 'Sortida de CAS necessària!';\n    }\n\n    /**\n    * Get the should have been redirected string\n    *\n    * @return string should habe been redirected\n    */\n    public function getShouldHaveBeenRedirected()\n    {\n        return 'Ja hauria d\\ haver estat redireccionat al servidor CAS. Feu click <a href=\"%s\">aquí</a> per a continuar.';\n    }\n\n    /**\n    * Get authentication failed string\n    *\n    * @return string authentication failed\n    */\n    public function getAuthenticationFailed()\n    {\n        return 'Autentificació CAS fallida!';\n    }\n\n    /**\n    * Get the your were not authenticated string\n    *\n    * @return string not authenticated\n    */\n    public function getYouWereNotAuthenticated()\n    {\n        return '<p>No estàs autentificat.</p><p>Pots tornar a intentar-ho fent click <a href=\"%s\">aquí</a>.</p><p>Si el problema persisteix hauría de contactar amb l\\'<a href=\"mailto:%s\">administrador d\\'aquest llocc</a>.</p>';\n    }\n\n    /**\n    * Get the service unavailable string\n    *\n    * @return string service unavailable\n    */\n    public function getServiceUnavailable()\n    {\n        return 'El servei `<b>%s</b>\\' no està disponible (<b>%s</b>).';\n    }\n}\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/Languages/ChineseSimplified.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * PHP Version 7\n *\n * @file     CAS/Language/ChineseSimplified.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Pascal Aubry <pascal.aubry@univ-rennes1.fr>, Phy25 <caslang@phy25.com>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\n/**\n * Chinese Simplified language class\n *\n * @class    CAS_Languages_ChineseSimplified\n * @category Authentication\n * @package  PhpCAS\n * @author   Pascal Aubry <pascal.aubry@univ-rennes1.fr>, Phy25 <caslang@phy25.com>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n *\n * @sa @link internalLang Internationalization @endlink\n * @ingroup internalLang\n */\nclass CAS_Languages_ChineseSimplified implements CAS_Languages_LanguageInterface\n{\n    /**\n     * Get the using server string\n     *\n     * @return string using server\n     */\n    public function getUsingServer()\n    {\n        return '连接的服务器';\n    }\n\n    /**\n     * Get authentication wanted string\n     *\n     * @return string authentication wanted\n     */\n    public function getAuthenticationWanted()\n    {\n        return '请进行 CAS 认证！';\n    }\n\n    /**\n     * Get logout string\n     *\n     * @return string logout\n     */\n    public function getLogout()\n    {\n        return '请进行 CAS 登出！';\n    }\n\n    /**\n     * Get the should have been redirected string\n     *\n     * @return string should habe been redirected\n     */\n    public function getShouldHaveBeenRedirected()\n    {\n        return '你正被重定向到 CAS 服务器。<a href=\"%s\">点击这里</a>继续。';\n    }\n\n    /**\n    * Get authentication failed string\n    *\n    * @return string authentication failed\n    */\n    public function getAuthenticationFailed()\n    {\n        return 'CAS 认证失败！';\n    }\n\n    /**\n    * Get the your were not authenticated string\n    *\n    * @return string not authenticated\n    */\n    public function getYouWereNotAuthenticated()\n    {\n        return '<p>你没有成功登录。</p><p>你可以<a href=\"%s\">点击这里重新登录</a>。</p><p>如果问题依然存在，请<a href=\"mailto:%s\">联系本站管理员</a>。</p>';\n    }\n\n    /**\n    * Get the service unavailable string\n    *\n    * @return string service unavailable\n    */\n    public function getServiceUnavailable()\n    {\n        return '服务器 <b>%s</b> 不可用（<b>%s</b>）。';\n    }\n}\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/Languages/English.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * PHP Version 7\n *\n * @file     CAS/Language/English.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Pascal Aubry <pascal.aubry@univ-rennes1.fr>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\n/**\n * English language class\n *\n * @class    CAS_Languages_English\n * @category Authentication\n * @package  PhpCAS\n * @author   Pascal Aubry <pascal.aubry@univ-rennes1.fr>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n *\n * @sa @link internalLang Internationalization @endlink\n * @ingroup internalLang\n */\nclass CAS_Languages_English implements CAS_Languages_LanguageInterface\n{\n    /**\n     * Get the using server string\n     *\n     * @return string using server\n     */\n    public function getUsingServer()\n    {\n        return 'using server';\n    }\n\n    /**\n     * Get authentication wanted string\n     *\n     * @return string authentication wanted\n     */\n    public function getAuthenticationWanted()\n    {\n        return 'CAS Authentication wanted!';\n    }\n\n    /**\n     * Get logout string\n     *\n     * @return string logout\n     */\n    public function getLogout()\n    {\n        return 'CAS logout wanted!';\n    }\n\n    /**\n     * Get the should have been redirected string\n     *\n     * @return string should habe been redirected\n     */\n    public function getShouldHaveBeenRedirected()\n    {\n        return 'You should already have been redirected to the CAS server. Click <a href=\"%s\">here</a> to continue.';\n    }\n\n    /**\n    * Get authentication failed string\n    *\n    * @return string authentication failed\n    */\n    public function getAuthenticationFailed()\n    {\n        return 'CAS Authentication failed!';\n    }\n\n    /**\n    * Get the your were not authenticated string\n    *\n    * @return string not authenticated\n    */\n    public function getYouWereNotAuthenticated()\n    {\n        return '<p>You were not authenticated.</p><p>You may submit your request again by clicking <a href=\"%s\">here</a>.</p><p>If the problem persists, you may contact <a href=\"mailto:%s\">the administrator of this site</a>.</p>';\n    }\n\n    /**\n    * Get the service unavailable string\n    *\n    * @return string service unavailable\n    */\n    public function getServiceUnavailable()\n    {\n        return 'The service `<b>%s</b>\\' is not available (<b>%s</b>).';\n    }\n}\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/Languages/French.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * PHP Version 7\n *\n * @file     CAS/Language/French.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Pascal Aubry <pascal.aubry@univ-rennes1.fr>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\n/**\n * French language class\n *\n * @class    CAS_Languages_French\n * @category Authentication\n * @package  PhpCAS\n * @author   Pascal Aubry <pascal.aubry@univ-rennes1.fr>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n *\n * @sa @link internalLang Internationalization @endlink\n * @ingroup internalLang\n */\nclass CAS_Languages_French implements CAS_Languages_LanguageInterface\n{\n    /**\n     * Get the using server string\n     *\n     * @return string using server\n     */\n    public function getUsingServer()\n    {\n        return 'utilisant le serveur';\n    }\n\n    /**\n     * Get authentication wanted string\n     *\n     * @return string authentication wanted\n     */\n    public function getAuthenticationWanted()\n    {\n        return 'Authentication CAS nécessaire&nbsp;!';\n    }\n\n    /**\n     * Get logout string\n     *\n     * @return string logout\n     */\n    public function getLogout()\n    {\n        return 'Déconnexion demandée&nbsp;!';\n    }\n\n    /**\n     * Get the should have been redirected string\n     *\n     * @return string should habe been redirected\n     */\n    public function getShouldHaveBeenRedirected()\n    {\n        return 'Vous auriez du etre redirigé(e) vers le serveur CAS. Cliquez <a href=\"%s\">ici</a> pour continuer.';\n    }\n\n    /**\n     * Get authentication failed string\n     *\n     * @return string authentication failed\n     */\n    public function getAuthenticationFailed()\n    {\n        return 'Authentification CAS infructueuse&nbsp;!';\n    }\n\n    /**\n     * Get the your were not authenticated string\n     *\n     * @return string not authenticated\n     */\n    public function getYouWereNotAuthenticated()\n    {\n        return '<p>Vous n\\'avez pas été authentifié(e).</p><p>Vous pouvez soumettre votre requete à nouveau en cliquant <a href=\"%s\">ici</a>.</p><p>Si le problème persiste, vous pouvez contacter <a href=\"mailto:%s\">l\\'administrateur de ce site</a>.</p>';\n    }\n\n    /**\n     * Get the service unavailable string\n     *\n     * @return string service unavailable\n     */\n    public function getServiceUnavailable()\n    {\n        return 'Le service `<b>%s</b>\\' est indisponible (<b>%s</b>)';\n    }\n}\n\n?>\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/Languages/Galego.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * PHP Version 7\n *\n * @file     CAS/Language/Galego.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Enrique Huelva Rivero enrique.huelvarivero@plexus.es\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\n/**\n * Galego language class\n *\n * @class    CAS_Languages_Galego\n * @category Authentication\n * @package  PhpCAS\n * @author   Enrique Huelva Rivero enrique.huelvarivero@plexus.es\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n *\n\n * @sa @link internalLang Internationalization @endlink\n * @ingroup internalLang\n */\nclass CAS_Languages_Galego implements CAS_Languages_LanguageInterface\n{\n    /**\n     * Get the using server string\n     *\n     * @return string using server\n     */\n    public function getUsingServer()\n    {\n        return 'usando servidor';\n    }\n\n    /**\n     * Get authentication wanted string\n     *\n     * @return string authentication wanted\n     */\n    public function getAuthenticationWanted()\n    {\n        return 'Autenticación CAS necesaria!';\n    }\n\n    /**\n     * Get logout string\n     *\n     * @return string logout\n     */\n    public function getLogout()\n    {\n        return 'Saída CAS necesaria!';\n    }\n\n    /**\n     * Get the should have been redirected string\n     *\n     * @return string should habe been redirected\n     */\n    public function getShouldHaveBeenRedirected()\n    {\n        return 'Xa debería ser redireccionado ao servidor CAS. Faga click <a href=\"%s\">aquí</a> para continuar';\n    }\n\n    /**\n     * Get authentication failed string\n     *\n     * @return string authentication failed\n     */\n    public function getAuthenticationFailed()\n    {\n        return 'Autenticación CAS errada!';\n    }\n\n    /**\n     * Get the your were not authenticated string\n     *\n     * @return string not authenticated\n     */\n    public function getYouWereNotAuthenticated()\n    {\n        return '\n        <p>Non estás autenticado</p><p>Podes volver tentalo facendo click <a href=\"%s\">aquí</a>.</p><p>Se o problema persiste debería contactar con el <a href=\"mailto:%s\">administrador deste sitio</a>.</p>';\n    }\n\n    /**\n     * Get the service unavailable string\n     *\n     * @return string service unavailable\n     */\n    public function getServiceUnavailable()\n    {\n        return 'O servizo `<b>%s</b>\\' non está dispoñible (<b>%s</b>).';\n    }\n}\n?>\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/Languages/German.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * PHP Version 7\n *\n * @file     CAS/Language/German.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Henrik Genssen <hg@mediafactory.de>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\n/**\n * German language class\n *\n * @class    CAS_Languages_German\n * @category Authentication\n * @package  PhpCAS\n * @author   Henrik Genssen <hg@mediafactory.de>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n *\n * @sa @link internalLang Internationalization @endlink\n * @ingroup internalLang\n */\nclass CAS_Languages_German implements CAS_Languages_LanguageInterface\n{\n    /**\n     * Get the using server string\n     *\n     * @return string using server\n     */\n    public function getUsingServer()\n    {\n        return 'via Server';\n    }\n\n    /**\n     * Get authentication wanted string\n     *\n     * @return string authentication wanted\n     */\n    public function getAuthenticationWanted()\n    {\n        return 'CAS Authentifizierung erforderlich!';\n    }\n\n    /**\n     * Get logout string\n     *\n     * @return string logout\n     */\n    public function getLogout()\n    {\n        return 'CAS Abmeldung!';\n    }\n\n    /**\n     * Get the should have been redirected string\n     *\n     * @return string should habe been redirected\n     */\n    public function getShouldHaveBeenRedirected()\n    {\n        return 'eigentlich h&auml;ten Sie zum CAS Server weitergeleitet werden sollen. Dr&uuml;cken Sie <a href=\"%s\">hier</a> um fortzufahren.';\n    }\n\n    /**\n     * Get authentication failed string\n     *\n     * @return string authentication failed\n     */\n    public function getAuthenticationFailed()\n    {\n        return 'CAS Anmeldung fehlgeschlagen!';\n    }\n\n    /**\n     * Get the your were not authenticated string\n     *\n     * @return string not authenticated\n     */\n    public function getYouWereNotAuthenticated()\n    {\n        return '<p>Sie wurden nicht angemeldet.</p><p>Um es erneut zu versuchen klicken Sie <a href=\"%s\">hier</a>.</p><p>Wenn das Problem bestehen bleibt, kontaktieren Sie den <a href=\"mailto:%s\">Administrator</a> dieser Seite.</p>';\n    }\n\n    /**\n     * Get the service unavailable string\n     *\n     * @return string service unavailable\n     */\n    public function getServiceUnavailable()\n    {\n        return 'Der Dienst `<b>%s</b>\\' ist nicht verf&uuml;gbar (<b>%s</b>).';\n    }\n}\n\n?>\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/Languages/Greek.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * PHP Version 7\n *\n * @file     CAS/Language/Greek.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Vangelis Haniotakis <haniotak@ucnet.uoc.gr>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\n/**\n * Greek language class\n *\n * @class    CAS_Languages_Greek\n * @category Authentication\n * @package  PhpCAS\n * @author   Vangelis Haniotakis <haniotak@ucnet.uoc.gr>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n *\n * @sa @link internalLang Internationalization @endlink\n * @ingroup internalLang\n */\nclass CAS_Languages_Greek implements CAS_Languages_LanguageInterface\n{\n    /**\n     * Get the using server string\n     *\n     * @return string using server\n     */\n    public function getUsingServer()\n    {\n        return 'χρησιμοποιείται ο εξυπηρετητής';\n    }\n\n    /**\n     * Get authentication wanted string\n     *\n     * @return string authentication wanted\n     */\n    public function getAuthenticationWanted()\n    {\n        return 'Απαιτείται η ταυτοποίηση CAS!';\n    }\n\n    /**\n     * Get logout string\n     *\n     * @return string logout\n     */\n    public function getLogout()\n    {\n        return 'Απαιτείται η αποσύνδεση από CAS!';\n    }\n\n    /**\n     * Get the should have been redirected string\n     *\n     * @return string should habe been redirected\n     */\n    public function getShouldHaveBeenRedirected()\n    {\n        return 'Θα έπρεπε να είχατε ανακατευθυνθεί στον εξυπηρετητή CAS. Κάντε κλίκ <a href=\"%s\">εδώ</a> για να συνεχίσετε.';\n    }\n\n    /**\n     * Get authentication failed string\n     *\n     * @return string authentication failed\n     */\n    public function getAuthenticationFailed()\n    {\n        return 'Η ταυτοποίηση CAS απέτυχε!';\n    }\n\n    /**\n     * Get the your were not authenticated string\n     *\n     * @return string not authenticated\n     */\n    public function getYouWereNotAuthenticated()\n    {\n        return '<p>Δεν ταυτοποιηθήκατε.</p><p>Μπορείτε να ξαναπροσπαθήσετε, κάνοντας κλίκ <a href=\"%s\">εδώ</a>.</p><p>Εαν το πρόβλημα επιμείνει, ελάτε σε επαφή με τον <a href=\"mailto:%s\">διαχειριστή</a>.</p>';\n    }\n\n    /**\n     * Get the service unavailable string\n     *\n     * @return string service unavailable\n     */\n    public function getServiceUnavailable()\n    {\n        return 'Η υπηρεσία `<b>%s</b>\\' δεν είναι διαθέσιμη (<b>%s</b>).';\n    }\n}\n?>\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/Languages/Japanese.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * PHP Version 7\n *\n * @file     CAS/Language/Japanese.php\n * @category Authentication\n * @package  PhpCAS\n * @author   fnorif <fnorif@yahoo.co.jp>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\n/**\n * Japanese language class. Now Encoding is UTF-8.\n *\n * @class    CAS_Languages_Japanese\n * @category Authentication\n * @package  PhpCAS\n * @author   fnorif <fnorif@yahoo.co.jp>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n *\n **/\nclass CAS_Languages_Japanese implements CAS_Languages_LanguageInterface\n{\n    /**\n     * Get the using server string\n     *\n     * @return string using server\n     */\n    public function getUsingServer()\n    {\n        return 'サーバーを使っています。';\n    }\n\n    /**\n     * Get authentication wanted string\n     *\n     * @return string authentication wanted\n     */\n    public function getAuthenticationWanted()\n    {\n        return 'CASによる認証を行います。';\n    }\n\n    /**\n     * Get logout string\n     *\n     * @return string logout\n     */\n    public function getLogout()\n    {\n        return 'CASからログアウトします!';\n    }\n\n    /**\n     * Get the should have been redirected string\n     *\n     * @return string should habe been redirected\n     */\n    public function getShouldHaveBeenRedirected()\n    {\n        return 'CASサーバに行く必要があります。自動的に転送されない場合は <a href=\"%s\">こちら</a> をクリックして続行します。';\n    }\n\n    /**\n     * Get authentication failed string\n     *\n     * @return string authentication failed\n     */\n    public function getAuthenticationFailed()\n    {\n        return 'CASによる認証に失敗しました。';\n    }\n\n    /**\n     * Get the your were not authenticated string\n     *\n     * @return string not authenticated\n     */\n    public function getYouWereNotAuthenticated()\n    {\n        return '<p>認証できませんでした。</p><p>もう一度リクエストを送信する場合は<a href=\"%s\">こちら</a>をクリック。</p><p>問題が解決しない場合は <a href=\"mailto:%s\">このサイトの管理者</a>に問い合わせてください。</p>';\n    }\n\n    /**\n     * Get the service unavailable string\n     *\n     * @return string service unavailable\n     */\n    public function getServiceUnavailable()\n    {\n        return 'サービス `<b>%s</b>\\' は利用できません (<b>%s</b>)。';\n    }\n}\n?>\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/Languages/LanguageInterface.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * PHP Version 7\n *\n * @file     CAS/Language/LanguageInterface.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Joachim Fritschi <jfritschi@freenet.de>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\n/**\n * Language Interface class for all internationalization files\n *\n * @class    CAS_Languages_LanguageInterface\n * @category Authentication\n * @package  PhpCAS\n * @author   Joachim Fritschi <jfritschi@freenet.de>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n *\n * @sa @link internalLang Internationalization @endlink\n * @ingroup internalLang\n */\n\ninterface CAS_Languages_LanguageInterface\n{\n    /**\n     * Get the using server string\n     *\n     * @return string using server\n     */\n    public function getUsingServer();\n\n    /**\n     * Get authentication wanted string\n     *\n     * @return string authentication wanted\n     */\n    public function getAuthenticationWanted();\n\n    /**\n     * Get logout string\n     *\n     * @return string logout\n     */\n    public function getLogout();\n\n    /**\n     * Get the should have been redirected string\n     *\n     * @return string should habe been redirected\n     */\n    public function getShouldHaveBeenRedirected();\n\n    /**\n     * Get authentication failed string\n     *\n     * @return string authentication failed\n     */\n    public function getAuthenticationFailed();\n\n    /**\n     * Get the your were not authenticated string\n     *\n     * @return string not authenticated\n     */\n    public function getYouWereNotAuthenticated();\n\n    /**\n     * Get the service unavailable string\n     *\n     * @return string service unavailable\n     */\n    public function getServiceUnavailable();\n\n}\n?>\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/Languages/Portuguese.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * PHP Version 7\n *\n * @file     CAS/Language/Portuguese.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Sherwin Harris <sherwin.harris@gmail.com>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://apereo.atlassian.net/wiki/spaces/CASC/pages/103252517/phpCAS\n */\n\n/**\n * Portuguese language class\n *\n * @class    CAS_Languages_Portuguese\n * @category Authentication\n * @package  PhpCAS\n * @author   Sherwin Harris <sherwin.harris@gmail.com>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://apereo.atlassian.net/wiki/spaces/CASC/pages/103252517/phpCAS\n *\n * @sa @link internalLang Internationalization @endlink\n * @ingroup internalLang\n */\nclass CAS_Languages_Portuguese implements CAS_Languages_LanguageInterface\n{\n    /**\n     * Get the using server string\n     *\n     * @return string using server\n     */\n    public function getUsingServer()\n    {\n        return 'Usando o servidor';\n    }\n\n    /**\n     * Get authentication wanted string\n     *\n     * @return string authentication wanted\n     */\n    public function getAuthenticationWanted()\n    {\n        return 'A autenticação do servidor CAS desejado!';\n    }\n\n    /**\n     * Get logout string\n     *\n     * @return string logout\n     */\n    public function getLogout()\n    {\n        return 'Saida do servidor CAS desejado!';\n    }\n\n    /**\n     * Get the should have been redirected string\n     *\n     * @return string should have been redirected\n     */\n    public function getShouldHaveBeenRedirected()\n    {\n        return 'Você já deve ter sido redirecionado para o servidor CAS. Clique <a href=\"%s\">aqui</a> para continuar';\n    }\n\n    /**\n    * Get authentication failed string\n    *\n    * @return string authentication failed\n    */\n    public function getAuthenticationFailed()\n    {\n        return 'A autenticação do servidor CAS falheu!';\n    }\n\n    /**\n    * Get the your were not authenticated string\n    *\n    * @return string not authenticated\n    */\n    public function getYouWereNotAuthenticated()\n    {\n        return '<p>Você não foi autenticado.</p><p>Você pode enviar sua solicitação novamente clicando <a href=\"%s\">aqui</a>. </p><p>Se o problema persistir, você pode entrar em contato com <a href=\"mailto:%s\">o administrador deste site</a>.</p>';\n    }\n\n    /**\n    * Get the service unavailable string\n    *\n    * @return string service unavailable\n    */\n    public function getServiceUnavailable()\n    {\n        return 'O serviço `<b>%s</b>\\' não está disponível (<b>%s</b>).';\n    }\n}\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/Languages/Spanish.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * PHP Version 7\n *\n * @file     CAS/Language/Spanish.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Iván-Benjamín García Torà <ivaniclixx@gmail.com>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\n/**\n * Spanish language class\n *\n * @class    CAS_Languages_Spanish\n * @category Authentication\n * @package  PhpCAS\n * @author   Iván-Benjamín García Torà <ivaniclixx@gmail.com>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n *\n\n * @sa @link internalLang Internationalization @endlink\n * @ingroup internalLang\n */\nclass CAS_Languages_Spanish implements CAS_Languages_LanguageInterface\n{\n\n    /**\n     * Get the using server string\n     *\n     * @return string using server\n     */\n    public function getUsingServer()\n    {\n        return 'usando servidor';\n    }\n\n    /**\n     * Get authentication wanted string\n     *\n     * @return string authentication wanted\n     */\n    public function getAuthenticationWanted()\n    {\n        return '¡Autentificación CAS necesaria!';\n    }\n\n    /**\n     * Get logout string\n     *\n     * @return string logout\n     */\n    public function getLogout()\n    {\n        return '¡Salida CAS necesaria!';\n    }\n\n    /**\n     * Get the should have been redirected string\n     *\n     * @return string should habe been redirected\n     */\n    public function getShouldHaveBeenRedirected()\n    {\n        return 'Ya debería haber sido redireccionado al servidor CAS. Haga click <a href=\"%s\">aquí</a> para continuar.';\n    }\n\n    /**\n     * Get authentication failed string\n     *\n     * @return string authentication failed\n     */\n    public function getAuthenticationFailed()\n    {\n        return '¡Autentificación CAS fallida!';\n    }\n\n    /**\n     * Get the your were not authenticated string\n     *\n     * @return string not authenticated\n     */\n    public function getYouWereNotAuthenticated()\n    {\n        return '<p>No estás autentificado.</p><p>Puedes volver a intentarlo haciendo click <a href=\"%s\">aquí</a>.</p><p>Si el problema persiste debería contactar con el <a href=\"mailto:%s\">administrador de este sitio</a>.</p>';\n    }\n\n    /**\n     * Get the service unavailable string\n     *\n     * @return string service unavailable\n     */\n    public function getServiceUnavailable()\n    {\n        return 'El servicio `<b>%s</b>\\' no está disponible (<b>%s</b>).';\n    }\n}\n?>\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/OutOfSequenceBeforeAuthenticationCallException.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *\n * PHP Version 7\n *\n * @file     CAS/OutOfSequenceBeforeAuthenticationCallException.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Joachim Fritschi <jfritschi@freenet.de>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\n/**\n * This class defines Exceptions that should be thrown when the sequence of\n * operations is invalid. In this case it should be thrown when an\n * authentication call has not yet happened.\n *\n * @class    CAS_OutOfSequenceBeforeAuthenticationCallException\n * @category Authentication\n * @package  PhpCAS\n * @author   Joachim Fritschi <jfritschi@freenet.de>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\nclass CAS_OutOfSequenceBeforeAuthenticationCallException\nextends CAS_OutOfSequenceException\nimplements CAS_Exception\n{\n    /**\n     * Return standard error meessage\n     *\n     * @return void\n     */\n    public function __construct ()\n    {\n        parent::__construct('An authentication call hasn\\'t happened yet.');\n    }\n}\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/OutOfSequenceBeforeClientException.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *\n * PHP Version 7\n *\n * @file     CAS/OutOfSequenceBeforeClientException.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Joachim Fritschi <jfritschi@freenet.de>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\n/**\n * This class defines Exceptions that should be thrown when the sequence of\n * operations is invalid. In this case it should be thrown when the client() or\n *  proxy() call has not yet happened and no client or proxy object exists.\n *\n * @class    CAS_OutOfSequenceBeforeClientException\n * @category Authentication\n * @package  PhpCAS\n * @author   Joachim Fritschi <jfritschi@freenet.de>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\nclass CAS_OutOfSequenceBeforeClientException\nextends CAS_OutOfSequenceException\nimplements CAS_Exception\n{\n    /**\n     * Return standard error message\n     *\n     * @return void\n     */\n    public function __construct ()\n    {\n        parent::__construct(\n            'this method cannot be called before phpCAS::client() or phpCAS::proxy()'\n        );\n    }\n}\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/OutOfSequenceBeforeProxyException.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *\n * PHP Version 7\n *\n * @file     CAS/OutOfSequenceBeforeProxyException.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Joachim Fritschi <jfritschi@freenet.de>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\n/**\n * This class defines Exceptions that should be thrown when the sequence of\n * operations is invalid. In this case it should be thrown when the proxy() call\n * has not yet happened and no proxy object exists.\n *\n * @class    CAS_OutOfSequenceBeforeProxyException\n * @category Authentication\n * @package  PhpCAS\n * @author   Joachim Fritschi <jfritschi@freenet.de>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\nclass CAS_OutOfSequenceBeforeProxyException\nextends CAS_OutOfSequenceException\nimplements CAS_Exception\n{\n\n    /**\n     * Return standard error message\n     *\n     * @return void\n     */\n    public function __construct ()\n    {\n        parent::__construct(\n            'this method cannot be called before phpCAS::proxy()'\n        );\n    }\n}\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/OutOfSequenceException.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *\n * PHP Version 7\n *\n * @file     CAS/OutOfSequenceException.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\n/**\n * This class defines Exceptions that should be thrown when the sequence of\n * operations is invalid. Examples are:\n *\t\t- Requesting the response before executing a request.\n *\t\t- Changing the URL of a request after executing the request.\n *\n * @class    CAS_OutOfSequenceException\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\nclass CAS_OutOfSequenceException\nextends BadMethodCallException\nimplements CAS_Exception\n{\n\n}\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/PGTStorage/AbstractStorage.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * PHP Version 7\n *\n * @file     CAS/PGTStorage/AbstractStorage.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Pascal Aubry <pascal.aubry@univ-rennes1.fr>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\n/**\n * Basic class for PGT storage\n * The CAS_PGTStorage_AbstractStorage class is a generic class for PGT storage.\n * This class should not be instanciated itself but inherited by specific PGT\n * storage classes.\n *\n * @class CAS_PGTStorage_AbstractStorage\n * @category Authentication\n * @package  PhpCAS\n * @author   Pascal Aubry <pascal.aubry@univ-rennes1.fr>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n *\n * @ingroup internalPGTStorage\n */\n\nabstract class CAS_PGTStorage_AbstractStorage\n{\n    /**\n     * @addtogroup internalPGTStorage\n     * @{\n     */\n\n    // ########################################################################\n    //  CONSTRUCTOR\n    // ########################################################################\n\n    /**\n     * The constructor of the class, should be called only by inherited classes.\n     *\n     * @param CAS_Client $cas_parent the CAS _client instance that creates the\n     * current object.\n     *\n     * @return void\n     *\n     * @protected\n     */\n    function __construct($cas_parent)\n    {\n        phpCAS::traceBegin();\n        if ( !$cas_parent->isProxy() ) {\n            phpCAS::error(\n                'defining PGT storage makes no sense when not using a CAS proxy'\n            );\n        }\n        phpCAS::traceEnd();\n    }\n\n    // ########################################################################\n    //  DEBUGGING\n    // ########################################################################\n\n    /**\n     * This virtual method returns an informational string giving the type of storage\n     * used by the object (used for debugging purposes).\n     *\n     * @return string\n     *\n     * @public\n     */\n    function getStorageType()\n    {\n        phpCAS::error(__CLASS__.'::'.__FUNCTION__.'() should never be called');\n    }\n\n    /**\n     * This virtual method returns an informational string giving informations on the\n     * parameters of the storage.(used for debugging purposes).\n     *\n     * @return string\n     *\n     * @public\n     */\n    function getStorageInfo()\n    {\n        phpCAS::error(__CLASS__.'::'.__FUNCTION__.'() should never be called');\n    }\n\n    // ########################################################################\n    //  ERROR HANDLING\n    // ########################################################################\n\n    /**\n     * string used to store an error message. Written by\n     * PGTStorage::setErrorMessage(), read by PGTStorage::getErrorMessage().\n     *\n     * @hideinitializer\n     * @deprecated not used.\n     */\n    var $_error_message=false;\n\n    /**\n     * This method sets en error message, which can be read later by\n     * PGTStorage::getErrorMessage().\n     *\n     * @param string $error_message an error message\n     *\n     * @return void\n     *\n     * @deprecated not used.\n     */\n    function setErrorMessage($error_message)\n    {\n        $this->_error_message = $error_message;\n    }\n\n    /**\n     * This method returns an error message set by PGTStorage::setErrorMessage().\n     *\n     * @return string an error message when set by PGTStorage::setErrorMessage(), FALSE\n     * otherwise.\n     *\n     * @deprecated not used.\n     */\n    function getErrorMessage()\n    {\n        return $this->_error_message;\n    }\n\n    // ########################################################################\n    //  INITIALIZATION\n    // ########################################################################\n\n    /**\n     * a boolean telling if the storage has already been initialized. Written by\n     * PGTStorage::init(), read by PGTStorage::isInitialized().\n     *\n     * @hideinitializer\n     */\n    var $_initialized = false;\n\n    /**\n     * This method tells if the storage has already been intialized.\n     *\n     * @return bool\n     *\n     * @protected\n     */\n    function isInitialized()\n    {\n        return $this->_initialized;\n    }\n\n    /**\n     * This virtual method initializes the object.\n     *\n     * @return void\n     */\n    function init()\n    {\n        $this->_initialized = true;\n    }\n\n    // ########################################################################\n    //  PGT I/O\n    // ########################################################################\n\n    /**\n     * This virtual method stores a PGT and its corresponding PGT Iuo.\n     *\n     * @param string $pgt     the PGT\n     * @param string $pgt_iou the PGT iou\n     *\n     * @return void\n     *\n     * @note Should never be called.\n     *\n     */\n    function write($pgt,$pgt_iou)\n    {\n        phpCAS::error(__CLASS__.'::'.__FUNCTION__.'() should never be called');\n    }\n\n    /**\n     * This virtual method reads a PGT corresponding to a PGT Iou and deletes\n     * the corresponding storage entry.\n     *\n     * @param string $pgt_iou the PGT iou\n     *\n     * @return string\n     *\n     * @note Should never be called.\n     */\n    function read($pgt_iou)\n    {\n        phpCAS::error(__CLASS__.'::'.__FUNCTION__.'() should never be called');\n    }\n\n    /** @} */\n\n}\n\n?>\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/PGTStorage/Db.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * PHP Version 7\n *\n * @file     CAS/PGTStorage/Db.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Daniel Frett <daniel.frett@gmail.com>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\ndefine('CAS_PGT_STORAGE_DB_DEFAULT_TABLE', 'cas_pgts');\n\n/**\n * Basic class for PGT database storage\n * The CAS_PGTStorage_Db class is a class for PGT database storage.\n *\n * @class    CAS_PGTStorage_Db\n * @category Authentication\n * @package  PhpCAS\n * @author   Daniel Frett <daniel.frett@gmail.com>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n *\n * @ingroup internalPGTStorageDb\n */\n\nclass CAS_PGTStorage_Db extends CAS_PGTStorage_AbstractStorage\n{\n    /**\n     * @addtogroup internalCAS_PGTStorageDb\n     * @{\n     */\n\n    /**\n     * the PDO object to use for database interactions\n     */\n    private $_pdo;\n\n    /**\n     * This method returns the PDO object to use for database interactions.\n     *\n     * @return PDO object\n     */\n    private function _getPdo()\n    {\n        return $this->_pdo;\n    }\n\n    /**\n     * database connection options to use when creating a new PDO object\n     */\n    private $_dsn;\n    private $_username;\n    private $_password;\n    private $_driver_options;\n\n    /**\n     * @var string the table to use for storing/retrieving pgt's\n     */\n    private $_table;\n\n    /**\n     * This method returns the table to use when storing/retrieving PGT's\n     *\n     * @return string the name of the pgt storage table.\n     */\n    private function _getTable()\n    {\n        return $this->_table;\n    }\n\n    // ########################################################################\n    //  DEBUGGING\n    // ########################################################################\n\n    /**\n     * This method returns an informational string giving the type of storage\n     * used by the object (used for debugging purposes).\n     *\n     * @return string an informational string.\n     */\n    public function getStorageType()\n    {\n        return \"db\";\n    }\n\n    /**\n     * This method returns an informational string giving informations on the\n     * parameters of the storage.(used for debugging purposes).\n     *\n     * @return string an informational string.\n     * @public\n     */\n    public function getStorageInfo()\n    {\n        return 'table=`'.$this->_getTable().'\\'';\n    }\n\n    // ########################################################################\n    //  CONSTRUCTOR\n    // ########################################################################\n\n    /**\n     * The class constructor.\n     *\n     * @param CAS_Client $cas_parent     the CAS_Client instance that creates\n     * the object.\n     * @param string     $dsn_or_pdo     a dsn string to use for creating a PDO\n     * object or a PDO object\n     * @param string     $username       the username to use when connecting to\n     * the database\n     * @param string     $password       the password to use when connecting to\n     * the database\n     * @param string     $table          the table to use for storing and\n     * retrieving PGT's\n     * @param string     $driver_options any driver options to use when\n     * connecting to the database\n     */\n    public function __construct(\n        $cas_parent, $dsn_or_pdo, $username='', $password='', $table='',\n        $driver_options=null\n    ) {\n        phpCAS::traceBegin();\n        // call the ancestor's constructor\n        parent::__construct($cas_parent);\n\n        // set default values\n        if ( empty($table) ) {\n            $table = CAS_PGT_STORAGE_DB_DEFAULT_TABLE;\n        }\n        if ( !is_array($driver_options) ) {\n            $driver_options = array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION);\n        }\n\n        // store the specified parameters\n        if ($dsn_or_pdo instanceof PDO) {\n            $this->_pdo = $dsn_or_pdo;\n        } else {\n            $this->_dsn = $dsn_or_pdo;\n            $this->_username = $username;\n            $this->_password = $password;\n            $this->_driver_options = $driver_options;\n        }\n\n        // store the table name\n        $this->_table = $table;\n\n        phpCAS::traceEnd();\n    }\n\n    // ########################################################################\n    //  INITIALIZATION\n    // ########################################################################\n\n    /**\n     * This method is used to initialize the storage. Halts on error.\n     *\n     * @return void\n     */\n    public function init()\n    {\n        phpCAS::traceBegin();\n        // if the storage has already been initialized, return immediatly\n        if ($this->isInitialized()) {\n            return;\n        }\n\n        // initialize the base object\n        parent::init();\n\n        // create the PDO object if it doesn't exist already\n        if (!($this->_pdo instanceof PDO)) {\n            try {\n                $this->_pdo = new PDO(\n                    $this->_dsn, $this->_username, $this->_password,\n                    $this->_driver_options\n                );\n            }\n            catch(PDOException $e) {\n                phpCAS::error('Database connection error: ' . $e->getMessage());\n            }\n        }\n\n        phpCAS::traceEnd();\n    }\n\n    // ########################################################################\n    //  PDO database interaction\n    // ########################################################################\n\n    /**\n     * attribute that stores the previous error mode for the PDO handle while\n     * processing a transaction\n     */\n    private $_errMode;\n\n    /**\n     * This method will enable the Exception error mode on the PDO object\n     *\n     * @return void\n     */\n    private function _setErrorMode()\n    {\n        // get PDO object and enable exception error mode\n        $pdo = $this->_getPdo();\n        $this->_errMode = $pdo->getAttribute(PDO::ATTR_ERRMODE);\n        $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);\n    }\n\n    /**\n     * this method will reset the error mode on the PDO object\n     *\n     * @return void\n     */\n    private function _resetErrorMode()\n    {\n        // get PDO object and reset the error mode to what it was originally\n        $pdo = $this->_getPdo();\n        $pdo->setAttribute(PDO::ATTR_ERRMODE, $this->_errMode);\n    }\n\n    // ########################################################################\n    //  database queries\n    // ########################################################################\n    // these queries are potentially unsafe because the person using this library\n    // can set the table to use, but there is no reliable way to escape SQL\n    // fieldnames in PDO yet\n\n    /**\n     * This method returns the query used to create a pgt storage table\n     *\n     * @return string the create table SQL, no bind params in query\n     */\n    protected function createTableSql()\n    {\n        return 'CREATE TABLE ' . $this->_getTable()\n            . ' (pgt_iou VARCHAR(255) NOT NULL PRIMARY KEY, pgt VARCHAR(255) NOT NULL)';\n    }\n\n    /**\n     * This method returns the query used to store a pgt\n     *\n     * @return string the store PGT SQL, :pgt and :pgt_iou are the bind params contained\n     *         in the query\n     */\n    protected function storePgtSql()\n    {\n        return 'INSERT INTO ' . $this->_getTable()\n            . ' (pgt_iou, pgt) VALUES (:pgt_iou, :pgt)';\n    }\n\n    /**\n     * This method returns the query used to retrieve a pgt. the first column\n     * of the first row should contain the pgt\n     *\n     * @return string the retrieve PGT SQL, :pgt_iou is the only bind param contained\n     *         in the query\n     */\n    protected function retrievePgtSql()\n    {\n        return 'SELECT pgt FROM ' . $this->_getTable() . ' WHERE pgt_iou = :pgt_iou';\n    }\n\n    /**\n     * This method returns the query used to delete a pgt.\n     *\n     * @return string the delete PGT SQL, :pgt_iou is the only bind param contained in\n     *         the query\n     */\n    protected function deletePgtSql()\n    {\n        return 'DELETE FROM ' . $this->_getTable() . ' WHERE pgt_iou = :pgt_iou';\n    }\n\n    // ########################################################################\n    //  PGT I/O\n    // ########################################################################\n\n    /**\n     * This method creates the database table used to store pgt's and pgtiou's\n     *\n     * @return void\n     */\n    public function createTable()\n    {\n        phpCAS::traceBegin();\n\n        // initialize this PGTStorage object if it hasn't been initialized yet\n        if ( !$this->isInitialized() ) {\n            $this->init();\n        }\n\n        // initialize the PDO object for this method\n        $pdo = $this->_getPdo();\n        $this->_setErrorMode();\n\n        try {\n            $pdo->beginTransaction();\n\n            $query = $pdo->query($this->createTableSQL());\n            $query->closeCursor();\n\n            $pdo->commit();\n        }\n        catch(PDOException $e) {\n            // attempt rolling back the transaction before throwing a phpCAS error\n            try {\n                $pdo->rollBack();\n            }\n            catch(PDOException $e) {\n            }\n            phpCAS::error('error creating PGT storage table: ' . $e->getMessage());\n        }\n\n        // reset the PDO object\n        $this->_resetErrorMode();\n\n        phpCAS::traceEnd();\n    }\n\n    /**\n     * This method stores a PGT and its corresponding PGT Iou in the database.\n     * Echoes a warning on error.\n     *\n     * @param string $pgt     the PGT\n     * @param string $pgt_iou the PGT iou\n     *\n     * @return void\n     */\n    public function write($pgt, $pgt_iou)\n    {\n        phpCAS::traceBegin();\n\n        // initialize the PDO object for this method\n        $pdo = $this->_getPdo();\n        $this->_setErrorMode();\n\n        try {\n            $pdo->beginTransaction();\n\n            $query = $pdo->prepare($this->storePgtSql());\n            $query->bindValue(':pgt', $pgt, PDO::PARAM_STR);\n            $query->bindValue(':pgt_iou', $pgt_iou, PDO::PARAM_STR);\n            $query->execute();\n            $query->closeCursor();\n\n            $pdo->commit();\n        }\n        catch(PDOException $e) {\n            // attempt rolling back the transaction before throwing a phpCAS error\n            try {\n                $pdo->rollBack();\n            }\n            catch(PDOException $e) {\n            }\n            phpCAS::error('error writing PGT to database: ' . $e->getMessage());\n        }\n\n        // reset the PDO object\n        $this->_resetErrorMode();\n\n        phpCAS::traceEnd();\n    }\n\n    /**\n     * This method reads a PGT corresponding to a PGT Iou and deletes the\n     * corresponding db entry.\n     *\n     * @param string $pgt_iou the PGT iou\n     *\n     * @return string|false the corresponding PGT, or FALSE on error\n     */\n    public function read($pgt_iou)\n    {\n        phpCAS::traceBegin();\n        $pgt = false;\n\n        // initialize the PDO object for this method\n        $pdo = $this->_getPdo();\n        $this->_setErrorMode();\n\n        try {\n            $pdo->beginTransaction();\n\n            // fetch the pgt for the specified pgt_iou\n            $query = $pdo->prepare($this->retrievePgtSql());\n            $query->bindValue(':pgt_iou', $pgt_iou, PDO::PARAM_STR);\n            $query->execute();\n            $pgt = $query->fetchColumn(0);\n            $query->closeCursor();\n\n            // delete the specified pgt_iou from the database\n            $query = $pdo->prepare($this->deletePgtSql());\n            $query->bindValue(':pgt_iou', $pgt_iou, PDO::PARAM_STR);\n            $query->execute();\n            $query->closeCursor();\n\n            $pdo->commit();\n        }\n        catch(PDOException $e) {\n            // attempt rolling back the transaction before throwing a phpCAS error\n            try {\n                $pdo->rollBack();\n            }\n            catch(PDOException $e) {\n            }\n            phpCAS::trace('error reading PGT from database: ' . $e->getMessage());\n        }\n\n        // reset the PDO object\n        $this->_resetErrorMode();\n\n        phpCAS::traceEnd();\n        return $pgt;\n    }\n\n    /** @} */\n\n}\n\n?>\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/PGTStorage/File.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * PHP Version 7\n *\n * @file     CAS/PGTStorage/AbstractStorage.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Pascal Aubry <pascal.aubry@univ-rennes1.fr>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\n/**\n * The CAS_PGTStorage_File class is a class for PGT file storage. An instance of\n * this class is returned by CAS_Client::SetPGTStorageFile().\n *\n * @class    CAS_PGTStorage_File\n * @category Authentication\n * @package  PhpCAS\n * @author   Pascal Aubry <pascal.aubry@univ-rennes1.fr>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n *\n *\n * @ingroup internalPGTStorageFile\n */\n\nclass CAS_PGTStorage_File extends CAS_PGTStorage_AbstractStorage\n{\n    /**\n     * @addtogroup internalPGTStorageFile\n     * @{\n     */\n\n    /**\n     * a string telling where PGT's should be stored on the filesystem. Written by\n     * PGTStorageFile::PGTStorageFile(), read by getPath().\n     *\n     * @private\n     */\n    var $_path;\n\n    /**\n     * This method returns the name of the directory where PGT's should be stored\n     * on the filesystem.\n     *\n     * @return string the name of a directory (with leading and trailing '/')\n     *\n     * @private\n     */\n    function getPath()\n    {\n        return $this->_path;\n    }\n\n    // ########################################################################\n    //  DEBUGGING\n    // ########################################################################\n\n    /**\n     * This method returns an informational string giving the type of storage\n     * used by the object (used for debugging purposes).\n     *\n     * @return string an informational string.\n     * @public\n     */\n    function getStorageType()\n    {\n        return \"file\";\n    }\n\n    /**\n     * This method returns an informational string giving informations on the\n     * parameters of the storage.(used for debugging purposes).\n     *\n     * @return string an informational string.\n     * @public\n     */\n    function getStorageInfo()\n    {\n        return 'path=`'.$this->getPath().'\\'';\n    }\n\n    // ########################################################################\n    //  CONSTRUCTOR\n    // ########################################################################\n\n    /**\n     * The class constructor, called by CAS_Client::SetPGTStorageFile().\n     *\n     * @param CAS_Client $cas_parent the CAS_Client instance that creates the object.\n     * @param string     $path       the path where the PGT's should be stored\n     *\n     * @return void\n     *\n     * @public\n     */\n    function __construct($cas_parent,$path)\n    {\n        phpCAS::traceBegin();\n        // call the ancestor's constructor\n        parent::__construct($cas_parent);\n\n        if (empty($path)) {\n            $path = CAS_PGT_STORAGE_FILE_DEFAULT_PATH;\n        }\n        // check that the path is an absolute path\n        if (getenv(\"OS\")==\"Windows_NT\" || strtoupper(substr(PHP_OS,0,3)) == 'WIN') {\n\n            if (!preg_match('`^[a-zA-Z]:`', $path)) {\n                phpCAS::error('an absolute path is needed for PGT storage to file');\n            }\n\n        } else {\n\n            if ( $path[0] != '/' ) {\n                phpCAS::error('an absolute path is needed for PGT storage to file');\n            }\n\n            // store the path (with a leading and trailing '/')\n            $path = preg_replace('|[/]*$|', '/', $path);\n            $path = preg_replace('|^[/]*|', '/', $path);\n        }\n\n        $this->_path = $path;\n        phpCAS::traceEnd();\n    }\n\n    // ########################################################################\n    //  INITIALIZATION\n    // ########################################################################\n\n    /**\n     * This method is used to initialize the storage. Halts on error.\n     *\n     * @return void\n     * @public\n     */\n    function init()\n    {\n        phpCAS::traceBegin();\n        // if the storage has already been initialized, return immediatly\n        if ($this->isInitialized()) {\n            return;\n        }\n        // call the ancestor's method (mark as initialized)\n        parent::init();\n        phpCAS::traceEnd();\n    }\n\n    // ########################################################################\n    //  PGT I/O\n    // ########################################################################\n\n    /**\n     * This method returns the filename corresponding to a PGT Iou.\n     *\n     * @param string $pgt_iou the PGT iou.\n     *\n     * @return string a filename\n     * @private\n     */\n    function getPGTIouFilename($pgt_iou)\n    {\n        phpCAS::traceBegin();\n        $filename = $this->getPath().\"phpcas-\".hash(\"sha256\", $pgt_iou);\n//        $filename = $this->getPath().$pgt_iou.'.plain';\n        phpCAS::trace(\"Sha256 filename:\" . $filename);\n        phpCAS::traceEnd();\n        return $filename;\n    }\n\n    /**\n     * This method stores a PGT and its corresponding PGT Iou into a file. Echoes a\n     * warning on error.\n     *\n     * @param string $pgt     the PGT\n     * @param string $pgt_iou the PGT iou\n     *\n     * @return void\n     *\n     * @public\n     */\n    function write($pgt,$pgt_iou)\n    {\n        phpCAS::traceBegin();\n        $fname = $this->getPGTIouFilename($pgt_iou);\n        if (!file_exists($fname)) {\n            touch($fname);\n            // Chmod will fail on windows\n            @chmod($fname, 0600);\n            if ($f=fopen($fname, \"w\")) {\n                if (fputs($f, $pgt) === false) {\n                    phpCAS::error('could not write PGT to `'.$fname.'\\'');\n                }\n                phpCAS::trace('Successful write of PGT to `'.$fname.'\\'');\n                fclose($f);\n            } else {\n                phpCAS::error('could not open `'.$fname.'\\'');\n            }\n        } else {\n            phpCAS::error('File exists: `'.$fname.'\\'');\n        }\n        phpCAS::traceEnd();\n    }\n\n    /**\n     * This method reads a PGT corresponding to a PGT Iou and deletes the\n     * corresponding file.\n     *\n     * @param string $pgt_iou the PGT iou\n     *\n     * @return string|false the corresponding PGT, or FALSE on error\n     *\n     * @public\n     */\n    function read($pgt_iou)\n    {\n        phpCAS::traceBegin();\n        $pgt = false;\n        $fname = $this->getPGTIouFilename($pgt_iou);\n        if (file_exists($fname)) {\n            if (!($f=fopen($fname, \"r\"))) {\n                phpCAS::error('could not open `'.$fname.'\\'');\n            } else {\n                if (($pgt=fgets($f)) === false) {\n                    phpCAS::error('could not read PGT from `'.$fname.'\\'');\n                }\n                phpCAS::trace('Successful read of PGT to `'.$fname.'\\'');\n                fclose($f);\n            }\n            // delete the PGT file\n            @unlink($fname);\n        } else {\n            phpCAS::error('No such file `'.$fname.'\\'');\n        }\n        phpCAS::traceEnd($pgt);\n        return $pgt;\n    }\n\n    /** @} */\n\n}\n?>\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/ProxiedService/Abstract.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * PHP Version 7\n *\n * @file     CAS/ProxiedService/Abstract.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\n/**\n * This class implements common methods for ProxiedService implementations included\n * with phpCAS.\n *\n * @class    CAS_ProxiedService_Abstract\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\nabstract class CAS_ProxiedService_Abstract\nimplements CAS_ProxiedService, CAS_ProxiedService_Testable\n{\n\n    /**\n     * The proxy ticket that can be used when making service requests.\n     * @var string $_proxyTicket;\n     */\n    private $_proxyTicket;\n\n    /**\n     * Register a proxy ticket with the Proxy that it can use when making requests.\n     *\n     * @param string $proxyTicket proxy ticket\n     *\n     * @return void\n     * @throws InvalidArgumentException If the $proxyTicket is invalid.\n     * @throws CAS_OutOfSequenceException If called after a proxy ticket has\n     *         already been initialized/set.\n     */\n    public function setProxyTicket ($proxyTicket)\n    {\n        if (empty($proxyTicket)) {\n            throw new CAS_InvalidArgumentException(\n                'Trying to initialize with an empty proxy ticket.'\n            );\n        }\n        if (!empty($this->_proxyTicket)) {\n            throw new CAS_OutOfSequenceException(\n                'Already initialized, cannot change the proxy ticket.'\n            );\n        }\n        $this->_proxyTicket = $proxyTicket;\n    }\n\n    /**\n     * Answer the proxy ticket to be used when making requests.\n     *\n     * @return string\n     * @throws CAS_OutOfSequenceException If called before a proxy ticket has\n     * already been initialized/set.\n     */\n    protected function getProxyTicket ()\n    {\n        if (empty($this->_proxyTicket)) {\n            throw new CAS_OutOfSequenceException(\n                'No proxy ticket yet. Call $this->initializeProxyTicket() to aquire the proxy ticket.'\n            );\n        }\n\n        return $this->_proxyTicket;\n    }\n\n    /**\n     * @var CAS_Client $_casClient;\n     */\n    private $_casClient;\n\n    /**\n     * Use a particular CAS_Client->initializeProxiedService() rather than the\n     * static phpCAS::initializeProxiedService().\n     *\n     * This method should not be called in standard operation, but is needed for unit\n     * testing.\n     *\n     * @param CAS_Client $casClient cas client\n     *\n     * @return void\n     * @throws CAS_OutOfSequenceException If called after a proxy ticket has\n     * already been initialized/set.\n     */\n    public function setCasClient (CAS_Client $casClient)\n    {\n        if (!empty($this->_proxyTicket)) {\n            throw new CAS_OutOfSequenceException(\n                'Already initialized, cannot change the CAS_Client.'\n            );\n        }\n\n        $this->_casClient = $casClient;\n    }\n\n    /**\n     * Fetch our proxy ticket.\n     *\n     * Descendent classes should call this method once their service URL is available\n     * to initialize their proxy ticket.\n     *\n     * @return void\n     * @throws CAS_OutOfSequenceException If called after a proxy ticket has\n     * already been initialized.\n     */\n    protected function initializeProxyTicket()\n    {\n        if (!empty($this->_proxyTicket)) {\n            throw new CAS_OutOfSequenceException(\n                'Already initialized, cannot initialize again.'\n            );\n        }\n        // Allow usage of a particular CAS_Client for unit testing.\n        if (empty($this->_casClient)) {\n            phpCAS::initializeProxiedService($this);\n        } else {\n            $this->_casClient->initializeProxiedService($this);\n        }\n    }\n\n}\n?>\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/ProxiedService/Exception.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * PHP Version 7\n *\n * @file     CAS/ProxiedService/Exception.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\n/**\n * An Exception for problems communicating with a proxied service.\n *\n * @class    CAS_ProxiedService_Exception\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\nclass CAS_ProxiedService_Exception\nextends Exception\nimplements CAS_Exception\n{\n\n}\n?>\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/ProxiedService/Http/Abstract.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * PHP Version 7\n *\n * @file     CAS/ProxiedService/Http/Abstract.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\n/**\n * This class implements common methods for ProxiedService implementations included\n * with phpCAS.\n *\n * @class    CAS_ProxiedService_Http_Abstract\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\nabstract class CAS_ProxiedService_Http_Abstract extends\nCAS_ProxiedService_Abstract implements CAS_ProxiedService_Http\n{\n    /**\n     * The HTTP request mechanism talking to the target service.\n     *\n     * @var CAS_Request_RequestInterface $requestHandler\n     */\n    protected $requestHandler;\n\n    /**\n     * The storage mechanism for cookies set by the target service.\n     *\n     * @var CAS_CookieJar $_cookieJar\n     */\n    private $_cookieJar;\n\n    /**\n     * Constructor.\n     *\n     * @param CAS_Request_RequestInterface $requestHandler request handler object\n     * @param CAS_CookieJar                $cookieJar      cookieJar object\n     *\n     * @return void\n     */\n    public function __construct(CAS_Request_RequestInterface $requestHandler,\n        CAS_CookieJar $cookieJar\n    ) {\n        $this->requestHandler = $requestHandler;\n        $this->_cookieJar = $cookieJar;\n    }\n\n    /**\n     * The target service url.\n     * @var string $_url;\n     */\n    private $_url;\n\n    /**\n     * Answer a service identifier (URL) for whom we should fetch a proxy ticket.\n     *\n     * @return string\n     * @throws Exception If no service url is available.\n     */\n    public function getServiceUrl()\n    {\n        if (empty($this->_url)) {\n            throw new CAS_ProxiedService_Exception(\n                'No URL set via ' . get_class($this) . '->setUrl($url).'\n            );\n        }\n\n        return $this->_url;\n    }\n\n    /*********************************************************\n     * Configure the Request\n     *********************************************************/\n\n    /**\n     * Set the URL of the Request\n     *\n     * @param string $url url to set\n     *\n     * @return void\n     * @throws CAS_OutOfSequenceException If called after the Request has been sent.\n     */\n    public function setUrl($url)\n    {\n        if ($this->hasBeenSent()) {\n            throw new CAS_OutOfSequenceException(\n                'Cannot set the URL, request already sent.'\n            );\n        }\n        if (!is_string($url)) {\n            throw new CAS_InvalidArgumentException('$url must be a string.');\n        }\n\n        $this->_url = $url;\n    }\n\n    /*********************************************************\n     * 2. Send the Request\n     *********************************************************/\n\n    /**\n     * Perform the request.\n     *\n     * @return void\n     * @throws CAS_OutOfSequenceException If called multiple times.\n     * @throws CAS_ProxyTicketException If there is a proxy-ticket failure.\n     *\t\tThe code of the Exception will be one of:\n     *\t\t\tPHPCAS_SERVICE_PT_NO_SERVER_RESPONSE\n     *\t\t\tPHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE\n     *\t\t\tPHPCAS_SERVICE_PT_FAILURE\n     * @throws CAS_ProxiedService_Exception If there is a failure sending the\n     * request to the target service.\n     */\n    public function send()\n    {\n        if ($this->hasBeenSent()) {\n            throw new CAS_OutOfSequenceException(\n                'Cannot send, request already sent.'\n            );\n        }\n\n        phpCAS::traceBegin();\n\n        // Get our proxy ticket and append it to our URL.\n        $this->initializeProxyTicket();\n        $url = $this->getServiceUrl();\n        if (strstr($url, '?') === false) {\n            $url = $url . '?ticket=' . $this->getProxyTicket();\n        } else {\n            $url = $url . '&ticket=' . $this->getProxyTicket();\n        }\n\n        try {\n            $this->makeRequest($url);\n        } catch (Exception $e) {\n            phpCAS::traceEnd();\n            throw $e;\n        }\n    }\n\n    /**\n     * Indicator of the number of requests (including redirects performed.\n     *\n     * @var int $_numRequests;\n     */\n    private $_numRequests = 0;\n\n    /**\n     * The response headers.\n     *\n     * @var array $_responseHeaders;\n     */\n    private $_responseHeaders = array();\n\n    /**\n     * The response status code.\n     *\n     * @var int $_responseStatusCode;\n     */\n    private $_responseStatusCode = '';\n\n    /**\n     * The response headers.\n     *\n     * @var string $_responseBody;\n     */\n    private $_responseBody = '';\n\n    /**\n     * Build and perform a request, following redirects\n     *\n     * @param string $url url for the request\n     *\n     * @return void\n     * @throws CAS_ProxyTicketException If there is a proxy-ticket failure.\n     *\t\tThe code of the Exception will be one of:\n     *\t\t\tPHPCAS_SERVICE_PT_NO_SERVER_RESPONSE\n     *\t\t\tPHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE\n     *\t\t\tPHPCAS_SERVICE_PT_FAILURE\n     * @throws CAS_ProxiedService_Exception If there is a failure sending the\n     * request to the target service.\n     */\n    protected function makeRequest($url)\n    {\n        // Verify that we are not in a redirect loop\n        $this->_numRequests++;\n        if ($this->_numRequests > 4) {\n            $message = 'Exceeded the maximum number of redirects (3) in proxied service request.';\n            phpCAS::trace($message);\n            throw new CAS_ProxiedService_Exception($message);\n        }\n\n        // Create a new request.\n        $request = clone $this->requestHandler;\n        $request->setUrl($url);\n\n        // Add any cookies to the request.\n        $request->addCookies($this->_cookieJar->getCookies($url));\n\n        // Add any other parts of the request needed by concrete classes\n        $this->populateRequest($request);\n\n        // Perform the request.\n        phpCAS::trace('Performing proxied service request to \\'' . $url . '\\'');\n        if (!$request->send()) {\n            $message = 'Could not perform proxied service request to URL`'\n            . $url . '\\'. ' . $request->getErrorMessage();\n            phpCAS::trace($message);\n            throw new CAS_ProxiedService_Exception($message);\n        }\n\n        // Store any cookies from the response;\n        $this->_cookieJar->storeCookies($url, $request->getResponseHeaders());\n\n        // Follow any redirects\n        if ($redirectUrl = $this->getRedirectUrl($request->getResponseHeaders())\n        ) {\n            phpCAS::trace('Found redirect:' . $redirectUrl);\n            $this->makeRequest($redirectUrl);\n        } else {\n\n            $this->_responseHeaders = $request->getResponseHeaders();\n            $this->_responseBody = $request->getResponseBody();\n            $this->_responseStatusCode = $request->getResponseStatusCode();\n        }\n    }\n\n    /**\n     * Add any other parts of the request needed by concrete classes\n     *\n     * @param CAS_Request_RequestInterface $request request interface object\n     *\n     * @return void\n     */\n    abstract protected function populateRequest(\n        CAS_Request_RequestInterface $request\n    );\n\n    /**\n     * Answer a redirect URL if a redirect header is found, otherwise null.\n     *\n     * @param array $responseHeaders response header to extract a redirect from\n     *\n     * @return string|null\n     */\n    protected function getRedirectUrl(array $responseHeaders)\n    {\n        // Check for the redirect after authentication\n        foreach ($responseHeaders as $header) {\n            if ( preg_match('/^(Location:|URI:)\\s*([^\\s]+.*)$/', $header, $matches)\n            ) {\n                return trim(array_pop($matches));\n            }\n        }\n        return null;\n    }\n\n    /*********************************************************\n     * 3. Access the response\n     *********************************************************/\n\n    /**\n     * Answer true if our request has been sent yet.\n     *\n     * @return bool\n     */\n    protected function hasBeenSent()\n    {\n        return ($this->_numRequests > 0);\n    }\n\n    /**\n     * Answer the headers of the response.\n     *\n     * @return array An array of header strings.\n     * @throws CAS_OutOfSequenceException If called before the Request has been sent.\n     */\n    public function getResponseHeaders()\n    {\n        if (!$this->hasBeenSent()) {\n            throw new CAS_OutOfSequenceException(\n                'Cannot access response, request not sent yet.'\n            );\n        }\n\n        return $this->_responseHeaders;\n    }\n\n    /**\n     * Answer HTTP status code of the response\n     *\n     * @return int\n     * @throws CAS_OutOfSequenceException If called before the Request has been sent.\n     */\n    public function getResponseStatusCode()\n    {\n        if (!$this->hasBeenSent()) {\n            throw new CAS_OutOfSequenceException(\n                'Cannot access response, request not sent yet.'\n            );\n        }\n\n        return $this->_responseStatusCode;\n    }\n\n    /**\n     * Answer the body of response.\n     *\n     * @return string\n     * @throws CAS_OutOfSequenceException If called before the Request has been sent.\n     */\n    public function getResponseBody()\n    {\n        if (!$this->hasBeenSent()) {\n            throw new CAS_OutOfSequenceException(\n                'Cannot access response, request not sent yet.'\n            );\n        }\n\n        return $this->_responseBody;\n    }\n\n    /**\n     * Answer the cookies from the response. This may include cookies set during\n     * redirect responses.\n     *\n     * @return array An array containing cookies. E.g. array('name' => 'val');\n     */\n    public function getCookies()\n    {\n        return $this->_cookieJar->getCookies($this->getServiceUrl());\n    }\n\n}\n?>\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/ProxiedService/Http/Get.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * PHP Version 7\n *\n * @file     CAS/ProxiedService/Http/Get.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\n/**\n * This class is used to make proxied service requests via the HTTP GET method.\n *\n * Usage Example:\n *\n *\ttry {\n *\t\t$service = phpCAS::getProxiedService(PHPCAS_PROXIED_SERVICE_HTTP_GET);\n *\t\t$service->setUrl('http://www.example.com/path/');\n *\t\t$service->send();\n *\t\tif ($service->getResponseStatusCode() == 200)\n *\t\t\treturn $service->getResponseBody();\n *\t\telse\n *\t\t\t// The service responded with an error code 404, 500, etc.\n *\t\t\tthrow new Exception('The service responded with an error.');\n *\n * \t} catch (CAS_ProxyTicketException $e) {\n *\t    if ($e->getCode() == PHPCAS_SERVICE_PT_FAILURE)\n *\t\t\treturn \"Your login has timed out. You need to log in again.\";\n *\t\telse\n *\t\t\t// Other proxy ticket errors are from bad request format\n *          // (shouldn't happen) or CAS server failure (unlikely)\n *          // so lets just stop if we hit those.\n *\t\t\tthrow $e;\n *\t} catch (CAS_ProxiedService_Exception $e) {\n *\t\t// Something prevented the service request from being sent or received.\n *\t\t// We didn't even get a valid error response (404, 500, etc), so this\n *\t\t// might be caused by a network error or a DNS resolution failure.\n *\t\t// We could handle it in some way, but for now we will just stop.\n *\t\tthrow $e;\n *\t}\n *\n * @class    CAS_ProxiedService_Http_Get\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\nclass CAS_ProxiedService_Http_Get\nextends CAS_ProxiedService_Http_Abstract\n{\n\n    /**\n     * Add any other parts of the request needed by concrete classes\n     *\n     * @param CAS_Request_RequestInterface $request request interface\n     *\n     * @return void\n     */\n    protected function populateRequest (CAS_Request_RequestInterface $request)\n    {\n        // do nothing, since the URL has already been sent and that is our\n        // only data.\n    }\n}\n?>\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/ProxiedService/Http/Post.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * PHP Version 7\n *\n * @file     CAS/ProxiedService/Http/Post.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\n/**\n * This class is used to make proxied service requests via the HTTP POST method.\n *\n * Usage Example:\n *\n *\ttry {\n * \t\t$service = phpCAS::getProxiedService(PHPCAS_PROXIED_SERVICE_HTTP_POST);\n * \t\t$service->setUrl('http://www.example.com/path/');\n *\t\t$service->setContentType('text/xml');\n *\t\t$service->setBody('<?xml version=\"1.0\"?'.'><methodCall><methodName>example.search</methodName></methodCall>');\n * \t\t$service->send();\n *\t\tif ($service->getResponseStatusCode() == 200)\n *\t\t\treturn $service->getResponseBody();\n *\t\telse\n *\t\t\t// The service responded with an error code 404, 500, etc.\n *\t\t\tthrow new Exception('The service responded with an error.');\n *\n *\t} catch (CAS_ProxyTicketException $e) {\n *\t\tif ($e->getCode() == PHPCAS_SERVICE_PT_FAILURE)\n *\t\t\treturn \"Your login has timed out. You need to log in again.\";\n *\t\telse\n *\t\t\t// Other proxy ticket errors are from bad request format\n *          // (shouldn't happen) or CAS server failure (unlikely) so lets just\n *          // stop if we hit those.\n *\t\t\tthrow $e;\n *\t} catch (CAS_ProxiedService_Exception $e) {\n *\t\t// Something prevented the service request from being sent or received.\n *\t\t// We didn't even get a valid error response (404, 500, etc), so this\n *\t\t// might be caused by a network error or a DNS resolution failure.\n *\t\t// We could handle it in some way, but for now we will just stop.\n *\t\tthrow $e;\n *\t}\n *\n * @class    CAS_ProxiedService_Http_Post\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\nclass CAS_ProxiedService_Http_Post\nextends CAS_ProxiedService_Http_Abstract\n{\n\n    /**\n     * The content-type of this request\n     *\n     * @var string $_contentType\n     */\n    private $_contentType;\n\n    /**\n     * The body of the this request\n     *\n     * @var string $_body\n     */\n    private $_body;\n\n    /**\n     * Set the content type of this POST request.\n     *\n     * @param string $contentType content type\n     *\n     * @return void\n     * @throws CAS_OutOfSequenceException If called after the Request has been sent.\n     */\n    public function setContentType ($contentType)\n    {\n        if ($this->hasBeenSent()) {\n            throw new CAS_OutOfSequenceException(\n                'Cannot set the content type, request already sent.'\n            );\n        }\n\n        $this->_contentType = $contentType;\n    }\n\n    /**\n     * Set the body of this POST request.\n     *\n     * @param string $body body to set\n     *\n     * @return void\n     * @throws CAS_OutOfSequenceException If called after the Request has been sent.\n     */\n    public function setBody ($body)\n    {\n        if ($this->hasBeenSent()) {\n            throw new CAS_OutOfSequenceException(\n                'Cannot set the body, request already sent.'\n            );\n        }\n\n        $this->_body = $body;\n    }\n\n    /**\n     * Add any other parts of the request needed by concrete classes\n     *\n     * @param CAS_Request_RequestInterface $request request interface class\n     *\n     * @return void\n     */\n    protected function populateRequest (CAS_Request_RequestInterface $request)\n    {\n        if (empty($this->_contentType) && !empty($this->_body)) {\n            throw new CAS_ProxiedService_Exception(\n                \"If you pass a POST body, you must specify a content type via \"\n                .get_class($this).'->setContentType($contentType).'\n            );\n        }\n\n        $request->makePost();\n        if (!empty($this->_body)) {\n            $request->addHeader('Content-Type: '.$this->_contentType);\n            $request->addHeader('Content-Length: '.strlen($this->_body));\n            $request->setPostBody($this->_body);\n        }\n    }\n\n\n}\n?>\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/ProxiedService/Http.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * PHP Version 7\n *\n * @file     CAS/ProxiedService/Http.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\n/**\n * This interface defines methods that clients should use for configuring, sending,\n * and receiving proxied HTTP requests.\n *\n * @class    CAS_ProxiedService_Http\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\ninterface CAS_ProxiedService_Http\n{\n\n    /*********************************************************\n     * Configure the Request\n    *********************************************************/\n\n    /**\n     * Set the URL of the Request\n     *\n     * @param string $url Url to set\n     *\n     * @return void\n     * @throws CAS_OutOfSequenceException If called after the Request has been sent.\n     */\n    public function setUrl ($url);\n\n    /*********************************************************\n     * 2. Send the Request\n    *********************************************************/\n\n    /**\n     * Perform the request.\n     *\n     * @return bool TRUE on success, FALSE on failure.\n     * @throws CAS_OutOfSequenceException If called multiple times.\n     */\n    public function send ();\n\n    /*********************************************************\n     * 3. Access the response\n    *********************************************************/\n\n    /**\n     * Answer the headers of the response.\n     *\n     * @return array An array of header strings.\n     * @throws CAS_OutOfSequenceException If called before the Request has been sent.\n     */\n    public function getResponseHeaders ();\n\n    /**\n     * Answer the body of response.\n     *\n     * @return string\n     * @throws CAS_OutOfSequenceException If called before the Request has been sent.\n     */\n    public function getResponseBody ();\n\n}\n?>\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/ProxiedService/Imap.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * PHP Version 7\n *\n * @file     CAS/ProxiedService/Imap.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\n/**\n * Provides access to a proxy-authenticated IMAP stream\n *\n * @class    CAS_ProxiedService_Imap\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\nclass CAS_ProxiedService_Imap\nextends CAS_ProxiedService_Abstract\n{\n\n    /**\n     * The username to send via imap_open.\n     *\n     * @var string $_username;\n     */\n    private $_username;\n\n    /**\n     * Constructor.\n     *\n     * @param string $username Username\n     *\n     * @return void\n     */\n    public function __construct ($username)\n    {\n        if (!is_string($username) || !strlen($username)) {\n            throw new CAS_InvalidArgumentException('Invalid username.');\n        }\n\n        $this->_username = $username;\n    }\n\n    /**\n     * The target service url.\n     * @var string $_url;\n     */\n    private $_url;\n\n    /**\n     * Answer a service identifier (URL) for whom we should fetch a proxy ticket.\n     *\n     * @return string\n     * @throws Exception If no service url is available.\n     */\n    public function getServiceUrl ()\n    {\n        if (empty($this->_url)) {\n            throw new CAS_ProxiedService_Exception(\n                'No URL set via '.get_class($this).'->getServiceUrl($url).'\n            );\n        }\n\n        return $this->_url;\n    }\n\n    /*********************************************************\n     * Configure the Stream\n    *********************************************************/\n\n    /**\n     * Set the URL of the service to pass to CAS for proxy-ticket retrieval.\n     *\n     * @param string $url Url to set\n     *\n     * @return void\n     * @throws CAS_OutOfSequenceException If called after the stream has been opened.\n     */\n    public function setServiceUrl ($url)\n    {\n        if ($this->hasBeenOpened()) {\n            throw new CAS_OutOfSequenceException(\n                'Cannot set the URL, stream already opened.'\n            );\n        }\n        if (!is_string($url) || !strlen($url)) {\n            throw new CAS_InvalidArgumentException('Invalid url.');\n        }\n\n        $this->_url = $url;\n    }\n\n    /**\n     * The mailbox to open. See the $mailbox parameter of imap_open().\n     *\n     * @var string $_mailbox\n     */\n    private $_mailbox;\n\n    /**\n     * Set the mailbox to open. See the $mailbox parameter of imap_open().\n     *\n     * @param string $mailbox Mailbox to set\n     *\n     * @return void\n     * @throws CAS_OutOfSequenceException If called after the stream has been opened.\n     */\n    public function setMailbox ($mailbox)\n    {\n        if ($this->hasBeenOpened()) {\n            throw new CAS_OutOfSequenceException(\n                'Cannot set the mailbox, stream already opened.'\n            );\n        }\n        if (!is_string($mailbox) || !strlen($mailbox)) {\n            throw new CAS_InvalidArgumentException('Invalid mailbox.');\n        }\n\n        $this->_mailbox = $mailbox;\n    }\n\n    /**\n     * A bit mask of options to pass to imap_open() as the $options parameter.\n     *\n     * @var int $_options\n     */\n    private $_options = null;\n\n    /**\n     * Set the options for opening the stream. See the $options parameter of\n     * imap_open().\n     *\n     * @param int $options Options for the stream\n     *\n     * @return void\n     * @throws CAS_OutOfSequenceException If called after the stream has been opened.\n     */\n    public function setOptions ($options)\n    {\n        if ($this->hasBeenOpened()) {\n            throw new CAS_OutOfSequenceException(\n                'Cannot set options, stream already opened.'\n            );\n        }\n        if (!is_int($options)) {\n            throw new CAS_InvalidArgumentException('Invalid options.');\n        }\n\n        $this->_options = $options;\n    }\n\n    /*********************************************************\n     * 2. Open the stream\n    *********************************************************/\n\n    /**\n     * Open the IMAP stream (similar to imap_open()).\n     *\n     * @return resource Returns an IMAP stream on success\n     * @throws CAS_OutOfSequenceException If called multiple times.\n     * @throws CAS_ProxyTicketException If there is a proxy-ticket failure.\n     *\t\tThe code of the Exception will be one of:\n     *\t\t\tPHPCAS_SERVICE_PT_NO_SERVER_RESPONSE\n     *\t\t\tPHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE\n     *\t\t\tPHPCAS_SERVICE_PT_FAILURE\n     * @throws CAS_ProxiedService_Exception If there is a failure sending the\n     *         request to the target service.\n     */\n    public function open ()\n    {\n        if ($this->hasBeenOpened()) {\n            throw new CAS_OutOfSequenceException('Stream already opened.');\n        }\n        if (empty($this->_mailbox)) {\n            throw new CAS_ProxiedService_Exception(\n                'You must specify a mailbox via '.get_class($this)\n                .'->setMailbox($mailbox)'\n            );\n        }\n\n        phpCAS::traceBegin();\n\n        // Get our proxy ticket and append it to our URL.\n        $this->initializeProxyTicket();\n        phpCAS::trace('opening IMAP mailbox `'.$this->_mailbox.'\\'...');\n        $this->_stream = @imap_open(\n            $this->_mailbox, $this->_username, $this->getProxyTicket(),\n            $this->_options\n        );\n        if ($this->_stream) {\n            phpCAS::trace('ok');\n        } else {\n            phpCAS::trace('could not open mailbox');\n            // @todo add localization integration.\n            $message = 'IMAP Error: '.$this->_url.' '. var_export(imap_errors(), true);\n            phpCAS::trace($message);\n            throw new CAS_ProxiedService_Exception($message);\n        }\n\n        phpCAS::traceEnd();\n        return $this->_stream;\n    }\n\n    /**\n     * Answer true if our request has been sent yet.\n     *\n     * @return bool\n     */\n    protected function hasBeenOpened ()\n    {\n        return !empty($this->_stream);\n    }\n\n    /*********************************************************\n     * 3. Access the result\n    *********************************************************/\n    /**\n     * The IMAP stream\n     *\n     * @var resource $_stream\n     */\n    private $_stream;\n\n    /**\n     * Answer the IMAP stream\n     *\n     * @return resource\n     * @throws CAS_OutOfSequenceException if stream is not opened yet\n     */\n    public function getStream ()\n    {\n        if (!$this->hasBeenOpened()) {\n            throw new CAS_OutOfSequenceException(\n                'Cannot access stream, not opened yet.'\n            );\n        }\n        return $this->_stream;\n    }\n\n    /**\n     * CAS_Client::serviceMail() needs to return the proxy ticket for some reason,\n     * so this method provides access to it.\n     *\n     * @return string\n     * @throws CAS_OutOfSequenceException If called before the stream has been\n     * opened.\n     */\n    public function getImapProxyTicket ()\n    {\n        if (!$this->hasBeenOpened()) {\n            throw new CAS_OutOfSequenceException(\n                'Cannot access errors, stream not opened yet.'\n            );\n        }\n        return $this->getProxyTicket();\n    }\n}\n?>\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/ProxiedService/Testable.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * PHP Version 7\n *\n * @file     CAS/ProxiedService/Testabel.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\n/**\n * This interface defines methods that allow proxy-authenticated service handlers\n * to be tested in unit tests.\n *\n * Classes implementing this interface SHOULD store the CAS_Client passed and\n * initialize themselves with that client rather than via the static phpCAS\n * method. For example:\n *\n *\t\t/ **\n *\t\t * Fetch our proxy ticket.\n *\t\t * /\n *\t\tprotected function initializeProxyTicket() {\n *\t\t\t// Allow usage of a particular CAS_Client for unit testing.\n *\t\t\tif (is_null($this->casClient))\n *\t\t\t\tphpCAS::initializeProxiedService($this);\n *\t\t\telse\n *\t\t\t\t$this->casClient->initializeProxiedService($this);\n *\t\t}\n *\n * @class    CAS_ProxiedService_Testabel\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\ninterface CAS_ProxiedService_Testable\n{\n\n    /**\n     * Use a particular CAS_Client->initializeProxiedService() rather than the\n     * static phpCAS::initializeProxiedService().\n     *\n     * This method should not be called in standard operation, but is needed for unit\n     * testing.\n     *\n     * @param CAS_Client $casClient Cas client object\n     *\n     * @return void\n     * @throws CAS_OutOfSequenceException If called after a proxy ticket has\n     *         already been initialized/set.\n     */\n    public function setCasClient (CAS_Client $casClient);\n\n}\n?>\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/ProxiedService.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * PHP Version 7\n *\n * @file     CAS/ProxiedService.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\n/**\n * This interface defines methods that allow proxy-authenticated service handlers\n * to interact with phpCAS.\n *\n * Proxy service handlers must implement this interface as well as call\n * phpCAS::initializeProxiedService($this) at some point in their implementation.\n *\n * While not required, proxy-authenticated service handlers are encouraged to\n * implement the CAS_ProxiedService_Testable interface to facilitate unit testing.\n *\n * @class    CAS_ProxiedService\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\ninterface CAS_ProxiedService\n{\n\n    /**\n     * Answer a service identifier (URL) for whom we should fetch a proxy ticket.\n     *\n     * @return string\n     * @throws Exception If no service url is available.\n     */\n    public function getServiceUrl ();\n\n    /**\n     * Register a proxy ticket with the ProxiedService that it can use when\n     * making requests.\n     *\n     * @param string $proxyTicket Proxy ticket string\n     *\n     * @return void\n     * @throws InvalidArgumentException If the $proxyTicket is invalid.\n     * @throws CAS_OutOfSequenceException If called after a proxy ticket has\n     * already been initialized/set.\n     */\n    public function setProxyTicket ($proxyTicket);\n\n}\n?>\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/ProxyChain/AllowedList.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * PHP Version 7\n *\n * @file     CAS/ProxyChain/AllowedList.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\n\n/**\n * ProxyChain is a container for storing chains of valid proxies that can\n * be used to validate proxied requests to a service\n *\n * @class    CAS_ProxyChain_AllowedList\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\nclass CAS_ProxyChain_AllowedList\n{\n\n    private $_chains = array();\n\n    /**\n     * Check whether proxies are allowed by configuration\n     *\n     * @return bool\n     */\n    public function isProxyingAllowed()\n    {\n        return (count($this->_chains) > 0);\n    }\n\n    /**\n     * Add a chain of proxies to the list of possible chains\n     *\n     * @param CAS_ProxyChain_Interface $chain A chain of proxies\n     *\n     * @return void\n     */\n    public function allowProxyChain(CAS_ProxyChain_Interface $chain)\n    {\n        $this->_chains[] = $chain;\n    }\n\n    /**\n     * Check if the proxies found in the response match the allowed proxies\n     *\n     * @param array $proxies list of proxies to check\n     *\n     * @return bool whether the proxies match the allowed proxies\n     */\n    public function isProxyListAllowed(array $proxies)\n    {\n        phpCAS::traceBegin();\n        if (empty($proxies)) {\n            phpCAS::trace(\"No proxies were found in the response\");\n            phpCAS::traceEnd(true);\n            return true;\n        } elseif (!$this->isProxyingAllowed()) {\n            phpCAS::trace(\"Proxies are not allowed\");\n            phpCAS::traceEnd(false);\n            return false;\n        } else {\n            $res = $this->contains($proxies);\n            phpCAS::traceEnd($res);\n            return $res;\n        }\n    }\n\n    /**\n     * Validate the proxies from the proxy ticket validation against the\n     * chains that were definded.\n     *\n     * @param array $list List of proxies from the proxy ticket validation.\n     *\n     * @return bool if any chain fully matches the supplied list\n     */\n    public function contains(array $list)\n    {\n        phpCAS::traceBegin();\n        $count = 0;\n        foreach ($this->_chains as $chain) {\n            phpCAS::trace(\"Checking chain \". $count++);\n            if ($chain->matches($list)) {\n                phpCAS::traceEnd(true);\n                return true;\n            }\n        }\n        phpCAS::trace(\"No proxy chain matches.\");\n        phpCAS::traceEnd(false);\n        return false;\n    }\n}\n?>\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/ProxyChain/Any.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * PHP Version 7\n *\n * @file     CAS/ProxyChain/Any.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\n/**\n * A proxy-chain definition that will match any list of proxies.\n *\n * Use this class for quick testing or in certain production screnarios you\n * might want to allow allow any other valid service to proxy your service.\n *\n * THIS CLASS IS HOWEVER NOT RECOMMENDED FOR PRODUCTION AND HAS SECURITY\n * IMPLICATIONS: YOU ARE ALLOWING ANY SERVICE TO ACT ON BEHALF OF A USER\n * ON THIS SERVICE.\n *\n * @class    CAS_ProxyChain_Any\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\nclass CAS_ProxyChain_Any\nimplements CAS_ProxyChain_Interface\n{\n\n    /**\n     * Match a list of proxies.\n     *\n     * @param array $list The list of proxies in front of this service.\n     *\n     * @return bool\n     */\n    public function matches(array $list)\n    {\n        phpCAS::trace(\"Using CAS_ProxyChain_Any. No proxy validation is performed.\");\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/ProxyChain/Interface.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * PHP Version 7\n *\n * @file     CAS/ProxyChain/Interface.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\n/**\n * An interface for classes that define a list of allowed proxies in front of\n * the current application.\n *\n * @class    CAS_ProxyChain_Interface\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\ninterface CAS_ProxyChain_Interface\n{\n\n    /**\n     * Match a list of proxies.\n     *\n     * @param array $list The list of proxies in front of this service.\n     *\n     * @return bool\n     */\n    public function matches(array $list);\n\n}\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/ProxyChain/Trusted.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * PHP Version 7\n *\n * @file     CAS/ProxyChain/Trusted.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\n/**\n * A proxy-chain definition that defines a chain up to a trusted proxy and\n * delegates the resposibility of validating the rest of the chain to that\n * trusted proxy.\n *\n * @class    CAS_ProxyChain_Trusted\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\nclass CAS_ProxyChain_Trusted\nextends CAS_ProxyChain\nimplements CAS_ProxyChain_Interface\n{\n\n    /**\n     * Validate the size of the the list as compared to our chain.\n     *\n     * @param array $list list of proxies\n     *\n     * @return bool\n     */\n    protected function isSizeValid (array $list)\n    {\n        return (sizeof($this->chain) <= sizeof($list));\n    }\n\n}\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/ProxyChain.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * PHP Version 7\n *\n * @file     CAS/ProxyChain.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\n/**\n * A normal proxy-chain definition that lists each level of the chain as either\n * a string or regular expression.\n *\n * @class    CAS_ProxyChain\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\nclass CAS_ProxyChain\nimplements CAS_ProxyChain_Interface\n{\n\n    protected $chain = array();\n\n    /**\n     * A chain is an array of strings or regexp strings that will be matched\n     * against. Regexp will be matched with preg_match and strings will be\n     * matched from the beginning. A string must fully match the beginning of\n     * an proxy url. So you can define a full domain as acceptable or go further\n     * down.\n     * Proxies have to be defined in reverse from the service to the user. If a\n     * user hits service A get proxied via B to service C the list of acceptable\n     * proxies on C would be array(B,A);\n     *\n     * @param array $chain A chain of proxies\n     */\n    public function __construct(array $chain)\n    {\n        // Ensure that we have an indexed array\n        $this->chain = array_values($chain);\n    }\n\n    /**\n     * Match a list of proxies.\n     *\n     * @param array $list The list of proxies in front of this service.\n     *\n     * @return bool\n     */\n    public function matches(array $list)\n    {\n        $list = array_values($list);  // Ensure that we have an indexed array\n        if ($this->isSizeValid($list)) {\n            $mismatch = false;\n            foreach ($this->chain as $i => $search) {\n                $proxy_url = $list[$i];\n                if (preg_match('/^\\/.*\\/[ixASUXu]*$/s', $search)) {\n                    if (preg_match($search, $proxy_url)) {\n                        phpCAS::trace(\n                            \"Found regexp \" .  $search . \" matching \" . $proxy_url\n                        );\n                    } else {\n                        phpCAS::trace(\n                            \"No regexp match \" .  $search . \" != \" . $proxy_url\n                        );\n                        $mismatch = true;\n                        break;\n                    }\n                } else {\n                    if (strncasecmp($search, $proxy_url, strlen($search)) == 0) {\n                        phpCAS::trace(\n                            \"Found string \" .  $search . \" matching \" . $proxy_url\n                        );\n                    } else {\n                        phpCAS::trace(\n                            \"No match \" .  $search . \" != \" . $proxy_url\n                        );\n                        $mismatch = true;\n                        break;\n                    }\n                }\n            }\n            if (!$mismatch) {\n                phpCAS::trace(\"Proxy chain matches\");\n                return true;\n            }\n        } else {\n            phpCAS::trace(\"Proxy chain skipped: size mismatch\");\n        }\n        return false;\n    }\n\n    /**\n     * Validate the size of the the list as compared to our chain.\n     *\n     * @param array $list List of proxies\n     *\n     * @return bool\n     */\n    protected function isSizeValid (array $list)\n    {\n        return (sizeof($this->chain) == sizeof($list));\n    }\n}\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/ProxyTicketException.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * PHP Version 7\n *\n * @class    CAS/ProxyTicketException.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n *\n */\n\n/**\n * An Exception for errors related to fetching or validating proxy tickets.\n *\n * @class    CAS_ProxyTicketException\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\nclass CAS_ProxyTicketException\nextends BadMethodCallException\nimplements CAS_Exception\n{\n\n    /**\n     * Constructor\n     *\n     * @param string $message Message text\n     * @param int    $code    Error code\n     *\n     * @return void\n     */\n    public function __construct ($message, $code = PHPCAS_SERVICE_PT_FAILURE)\n    {\n        // Warn if the code is not in our allowed list\n        $ptCodes = array(\n        PHPCAS_SERVICE_PT_FAILURE,\n        PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE,\n        PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE,\n        );\n        if (!in_array($code, $ptCodes)) {\n            trigger_error(\n                'Invalid code '.$code\n                .' passed. Must be one of PHPCAS_SERVICE_PT_FAILURE, PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE, or PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE.'\n            );\n        }\n\n        parent::__construct($message, $code);\n    }\n}\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/Request/AbstractRequest.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * PHP Version 7\n *\n * @file     CAS/Request/AbstractRequest.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\n/**\n * Provides support for performing web-requests via curl\n *\n * @class    CAS_Request_AbstractRequest\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\nabstract class CAS_Request_AbstractRequest\nimplements CAS_Request_RequestInterface\n{\n\n    protected $url = null;\n    protected $cookies = array();\n    protected $headers = array();\n    protected $isPost = false;\n    protected $postBody = null;\n    protected $caCertPath = null;\n    protected $validateCN = true;\n    private $_sent = false;\n    private $_responseHeaders = array();\n    private $_responseBody = null;\n    private $_errorMessage = '';\n\n    /*********************************************************\n     * Configure the Request\n    *********************************************************/\n\n    /**\n     * Set the URL of the Request\n     *\n     * @param string $url Url to set\n     *\n     * @return void\n     * @throws CAS_OutOfSequenceException If called after the Request has been sent.\n     */\n    public function setUrl ($url)\n    {\n        if ($this->_sent) {\n            throw new CAS_OutOfSequenceException(\n                'Request has already been sent cannot '.__METHOD__\n            );\n        }\n\n        $this->url = $url;\n    }\n\n    /**\n     * Add a cookie to the request.\n     *\n     * @param string $name  Name of entry\n     * @param string $value value of entry\n     *\n     * @return void\n     * @throws CAS_OutOfSequenceException If called after the Request has been sent.\n     */\n    public function addCookie ($name, $value)\n    {\n        if ($this->_sent) {\n            throw new CAS_OutOfSequenceException(\n                'Request has already been sent cannot '.__METHOD__\n            );\n        }\n\n        $this->cookies[$name] = $value;\n    }\n\n    /**\n     * Add an array of cookies to the request.\n     * The cookie array is of the form\n     *     array('cookie_name' => 'cookie_value', 'cookie_name2' => cookie_value2')\n     *\n     * @param array $cookies cookies to add\n     *\n     * @return void\n     * @throws CAS_OutOfSequenceException If called after the Request has been sent.\n     */\n    public function addCookies (array $cookies)\n    {\n        if ($this->_sent) {\n            throw new CAS_OutOfSequenceException(\n                'Request has already been sent cannot '.__METHOD__\n            );\n        }\n\n        $this->cookies = array_merge($this->cookies, $cookies);\n    }\n\n    /**\n     * Add a header string to the request.\n     *\n     * @param string $header Header to add\n     *\n     * @return void\n     * @throws CAS_OutOfSequenceException If called after the Request has been sent.\n     */\n    public function addHeader ($header)\n    {\n        if ($this->_sent) {\n            throw new CAS_OutOfSequenceException(\n                'Request has already been sent cannot '.__METHOD__\n            );\n        }\n\n        $this->headers[] = $header;\n    }\n\n    /**\n     * Add an array of header strings to the request.\n     *\n     * @param array $headers headers to add\n     *\n     * @return void\n     * @throws CAS_OutOfSequenceException If called after the Request has been sent.\n     */\n    public function addHeaders (array $headers)\n    {\n        if ($this->_sent) {\n            throw new CAS_OutOfSequenceException(\n                'Request has already been sent cannot '.__METHOD__\n            );\n        }\n\n        $this->headers = array_merge($this->headers, $headers);\n    }\n\n    /**\n     * Make the request a POST request rather than the default GET request.\n     *\n     * @return void\n     * @throws CAS_OutOfSequenceException If called after the Request has been sent.\n     */\n    public function makePost ()\n    {\n        if ($this->_sent) {\n            throw new CAS_OutOfSequenceException(\n                'Request has already been sent cannot '.__METHOD__\n            );\n        }\n\n        $this->isPost = true;\n    }\n\n    /**\n     * Add a POST body to the request\n     *\n     * @param string $body body to add\n     *\n     * @return void\n     * @throws CAS_OutOfSequenceException If called after the Request has been sent.\n     */\n    public function setPostBody ($body)\n    {\n        if ($this->_sent) {\n            throw new CAS_OutOfSequenceException(\n                'Request has already been sent cannot '.__METHOD__\n            );\n        }\n        if (!$this->isPost) {\n            throw new CAS_OutOfSequenceException(\n                'Cannot add a POST body to a GET request, use makePost() first.'\n            );\n        }\n\n        $this->postBody = $body;\n    }\n\n    /**\n     * Specify the path to an SSL CA certificate to validate the server with.\n     *\n     * @param string $caCertPath  path to cert\n     * @param bool   $validate_cn valdiate CN of certificate\n     *\n     * @return void\n     * @throws CAS_OutOfSequenceException If called after the Request has been sent.\n     */\n    public function setSslCaCert ($caCertPath,$validate_cn=true)\n    {\n        if ($this->_sent) {\n            throw new CAS_OutOfSequenceException(\n                'Request has already been sent cannot '.__METHOD__\n            );\n        }\n        $this->caCertPath = $caCertPath;\n        $this->validateCN = $validate_cn;\n    }\n\n    /*********************************************************\n     * 2. Send the Request\n    *********************************************************/\n\n    /**\n     * Perform the request.\n     *\n     * @return bool TRUE on success, FALSE on failure.\n     * @throws CAS_OutOfSequenceException If called multiple times.\n     */\n    public function send ()\n    {\n        if ($this->_sent) {\n            throw new CAS_OutOfSequenceException(\n                'Request has already been sent cannot send again.'\n            );\n        }\n        if (is_null($this->url) || !$this->url) {\n            throw new CAS_OutOfSequenceException(\n                'A url must be specified via setUrl() before the request can be sent.'\n            );\n        }\n        $this->_sent = true;\n        return $this->sendRequest();\n    }\n\n    /**\n     * Send the request and store the results.\n     *\n     * @return bool TRUE on success, FALSE on failure.\n     */\n    abstract protected function sendRequest ();\n\n    /**\n     * Store the response headers.\n     *\n     * @param array $headers headers to store\n     *\n     * @return void\n     */\n    protected function storeResponseHeaders (array $headers)\n    {\n        $this->_responseHeaders = array_merge($this->_responseHeaders, $headers);\n    }\n\n    /**\n     * Store a single response header to our array.\n     *\n     * @param string $header header to store\n     *\n     * @return void\n     */\n    protected function storeResponseHeader ($header)\n    {\n        $this->_responseHeaders[] = $header;\n    }\n\n    /**\n     * Store the response body.\n     *\n     * @param string $body body to store\n     *\n     * @return void\n     */\n    protected function storeResponseBody ($body)\n    {\n        $this->_responseBody = $body;\n    }\n\n    /**\n     * Add a string to our error message.\n     *\n     * @param string $message message to add\n     *\n     * @return void\n     */\n    protected function storeErrorMessage ($message)\n    {\n        $this->_errorMessage .= $message;\n    }\n\n    /*********************************************************\n     * 3. Access the response\n    *********************************************************/\n\n    /**\n     * Answer the headers of the response.\n     *\n     * @return array An array of header strings.\n     * @throws CAS_OutOfSequenceException If called before the Request has been sent.\n     */\n    public function getResponseHeaders ()\n    {\n        if (!$this->_sent) {\n            throw new CAS_OutOfSequenceException(\n                'Request has not been sent yet. Cannot '.__METHOD__\n            );\n        }\n        return $this->_responseHeaders;\n    }\n\n    /**\n     * Answer HTTP status code of the response\n     *\n     * @return int\n     * @throws CAS_OutOfSequenceException If called before the Request has been sent.\n     * @throws CAS_Request_Exception if the response did not contain a status code\n     */\n    public function getResponseStatusCode ()\n    {\n        if (!$this->_sent) {\n            throw new CAS_OutOfSequenceException(\n                'Request has not been sent yet. Cannot '.__METHOD__\n            );\n        }\n\n        if (!preg_match(\n            '/HTTP\\/[0-9.]+\\s+([0-9]+)\\s*(.*)/',\n            $this->_responseHeaders[0], $matches\n        )\n        ) {\n            throw new CAS_Request_Exception(\n                'Bad response, no status code was found in the first line.'\n            );\n        }\n\n        return intval($matches[1]);\n    }\n\n    /**\n     * Answer the body of response.\n     *\n     * @return string\n     * @throws CAS_OutOfSequenceException If called before the Request has been sent.\n     */\n    public function getResponseBody ()\n    {\n        if (!$this->_sent) {\n            throw new CAS_OutOfSequenceException(\n                'Request has not been sent yet. Cannot '.__METHOD__\n            );\n        }\n\n        return $this->_responseBody;\n    }\n\n    /**\n     * Answer a message describing any errors if the request failed.\n     *\n     * @return string\n     * @throws CAS_OutOfSequenceException If called before the Request has been sent.\n     */\n    public function getErrorMessage ()\n    {\n        if (!$this->_sent) {\n            throw new CAS_OutOfSequenceException(\n                'Request has not been sent yet. Cannot '.__METHOD__\n            );\n        }\n        return $this->_errorMessage;\n    }\n}\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/Request/CurlMultiRequest.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * PHP Version 7\n *\n * @file     CAS/Request/AbstractRequest.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\n/**\n * This interface defines a class library for performing multiple web requests\n * in batches. Implementations of this interface may perform requests serially\n * or in parallel.\n *\n * @class    CAS_Request_CurlMultiRequest\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\nclass CAS_Request_CurlMultiRequest\nimplements CAS_Request_MultiRequestInterface\n{\n    private $_requests = array();\n    private $_sent = false;\n\n    /*********************************************************\n     * Add Requests\n    *********************************************************/\n\n    /**\n     * Add a new Request to this batch.\n     * Note, implementations will likely restrict requests to their own concrete\n     * class hierarchy.\n     *\n     * @param CAS_Request_RequestInterface $request reqest to add\n     *\n     * @return void\n     * @throws CAS_OutOfSequenceException If called after the Request has been sent.\n     * @throws CAS_InvalidArgumentException If passed a Request of the wrong\n     * implmentation.\n     */\n    public function addRequest (CAS_Request_RequestInterface $request)\n    {\n        if ($this->_sent) {\n            throw new CAS_OutOfSequenceException(\n                'Request has already been sent cannot '.__METHOD__\n            );\n        }\n        if (!$request instanceof CAS_Request_CurlRequest) {\n            throw new CAS_InvalidArgumentException(\n                'As a CAS_Request_CurlMultiRequest, I can only work with CAS_Request_CurlRequest objects.'\n            );\n        }\n\n        $this->_requests[] = $request;\n    }\n\n    /**\n     * Retrieve the number of requests added to this batch.\n     *\n     * @return int number of request elements\n     * @throws CAS_OutOfSequenceException if the request has already been sent\n     */\n    public function getNumRequests()\n    {\n        if ($this->_sent) {\n            throw new CAS_OutOfSequenceException(\n                'Request has already been sent cannot '.__METHOD__\n            );\n        }\n        return count($this->_requests);\n    }\n\n    /*********************************************************\n     * 2. Send the Request\n    *********************************************************/\n\n    /**\n     * Perform the request. After sending, all requests will have their\n     * responses poulated.\n     *\n     * @return bool TRUE on success, FALSE on failure.\n     * @throws CAS_OutOfSequenceException If called multiple times.\n     */\n    public function send ()\n    {\n        if ($this->_sent) {\n            throw new CAS_OutOfSequenceException(\n                'Request has already been sent cannot send again.'\n            );\n        }\n        if (!count($this->_requests)) {\n            throw new CAS_OutOfSequenceException(\n                'At least one request must be added via addRequest() before the multi-request can be sent.'\n            );\n        }\n\n        $this->_sent = true;\n\n        // Initialize our handles and configure all requests.\n        $handles = array();\n        $multiHandle = curl_multi_init();\n        foreach ($this->_requests as $i => $request) {\n            $handle = $request->initAndConfigure();\n            curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);\n            $handles[$i] = $handle;\n            curl_multi_add_handle($multiHandle, $handle);\n        }\n\n        // Execute the requests in parallel.\n        do {\n            curl_multi_exec($multiHandle, $running);\n        } while ($running > 0);\n\n        // Populate all of the responses or errors back into the request objects.\n        foreach ($this->_requests as $i => $request) {\n            $buf = curl_multi_getcontent($handles[$i]);\n            $request->_storeResponseBody($buf);\n            curl_multi_remove_handle($multiHandle, $handles[$i]);\n            curl_close($handles[$i]);\n        }\n\n        curl_multi_close($multiHandle);\n    }\n}\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/Request/CurlRequest.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * PHP Version 7\n *\n * @file     CAS/Request/CurlRequest.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\n/**\n * Provides support for performing web-requests via curl\n *\n * @class    CAS_Request_CurlRequest\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\nclass CAS_Request_CurlRequest\nextends CAS_Request_AbstractRequest\nimplements CAS_Request_RequestInterface\n{\n\n    /**\n     * Set additional curl options\n     *\n     * @param array $options option to set\n     *\n     * @return void\n     */\n    public function setCurlOptions (array $options)\n    {\n        $this->_curlOptions = $options;\n    }\n    private $_curlOptions = array();\n\n    /**\n     * Send the request and store the results.\n     *\n     * @return bool true on success, false on failure.\n     */\n    protected function sendRequest ()\n    {\n        phpCAS::traceBegin();\n\n        /*********************************************************\n         * initialize the CURL session\n        *********************************************************/\n        $ch = $this->initAndConfigure();\n\n        /*********************************************************\n         * Perform the query\n        *********************************************************/\n        $buf = curl_exec($ch);\n        if ( $buf === false ) {\n            phpCAS::trace('curl_exec() failed');\n            $this->storeErrorMessage(\n                'CURL error #'.curl_errno($ch).': '.curl_error($ch)\n            );\n            $res = false;\n        } else {\n            $this->storeResponseBody($buf);\n            phpCAS::trace(\"Response Body: \\n\".$buf.\"\\n\");\n            $res = true;\n\n        }\n        // close the CURL session\n        curl_close($ch);\n\n        phpCAS::traceEnd($res);\n        return $res;\n    }\n\n    /**\n     * Internal method to initialize our cURL handle and configure the request.\n     * This method should NOT be used outside of the CurlRequest or the\n     * CurlMultiRequest.\n     *\n     * @return resource|false The cURL handle on success, false on failure\n     */\n    public function initAndConfigure()\n    {\n        /*********************************************************\n         * initialize the CURL session\n        *********************************************************/\n        $ch = curl_init($this->url);\n\n        curl_setopt_array($ch, $this->_curlOptions);\n\n        /*********************************************************\n         * Set SSL configuration\n        *********************************************************/\n        if ($this->caCertPath) {\n            if ($this->validateCN) {\n                curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);\n            } else {\n                curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);\n            }\n            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);\n            curl_setopt($ch, CURLOPT_CAINFO, $this->caCertPath);\n            phpCAS::trace('CURL: Set CURLOPT_CAINFO ' . $this->caCertPath);\n        } else {\n            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);\n            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);\n        }\n\n        /*********************************************************\n         * Configure curl to capture our output.\n        *********************************************************/\n        // return the CURL output into a variable\n        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);\n\n        // get the HTTP header with a callback\n        curl_setopt($ch, CURLOPT_HEADERFUNCTION, array($this, '_curlReadHeaders'));\n\n        /*********************************************************\n         * Add cookie headers to our request.\n        *********************************************************/\n        if (count($this->cookies)) {\n            $cookieStrings = array();\n            foreach ($this->cookies as $name => $val) {\n                $cookieStrings[] = $name.'='.$val;\n            }\n            curl_setopt($ch, CURLOPT_COOKIE, implode(';', $cookieStrings));\n        }\n\n        /*********************************************************\n         * Add any additional headers\n        *********************************************************/\n        if (count($this->headers)) {\n            curl_setopt($ch, CURLOPT_HTTPHEADER, $this->headers);\n        }\n\n        /*********************************************************\n         * Flag and Body for POST requests\n        *********************************************************/\n        if ($this->isPost) {\n            curl_setopt($ch, CURLOPT_POST, 1);\n            curl_setopt($ch, CURLOPT_POSTFIELDS, $this->postBody);\n        }\n\n        /*********************************************************\n         * Set User Agent\n         *********************************************************/\n        curl_setopt($ch, CURLOPT_USERAGENT, 'phpCAS/' . phpCAS::getVersion());\n\n        return $ch;\n    }\n\n    /**\n     * Store the response body.\n     * This method should NOT be used outside of the CurlRequest or the\n     * CurlMultiRequest.\n     *\n     * @param string $body body to stor\n     *\n     * @return void\n     */\n    public function _storeResponseBody ($body)\n    {\n        $this->storeResponseBody($body);\n    }\n\n    /**\n     * Internal method for capturing the headers from a curl request.\n     *\n     * @param resource $ch     handle of curl\n     * @param string $header header\n     *\n     * @return int\n     */\n    public function _curlReadHeaders ($ch, $header)\n    {\n        $this->storeResponseHeader($header);\n        return strlen($header);\n    }\n}\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/Request/Exception.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * PHP Version 7\n *\n * @file     CAS/Request/Exception.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\n/**\n * An Exception for problems performing requests\n *\n * @class    CAS_Request_Exception\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\nclass CAS_Request_Exception\nextends Exception\nimplements CAS_Exception\n{\n\n}\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/Request/MultiRequestInterface.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * PHP Version 7\n *\n * @file     CAS/Request/MultiRequestInterface.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\n/**\n * This interface defines a class library for performing multiple web requests\n * in batches. Implementations of this interface may perform requests serially\n * or in parallel.\n *\n * @class    CAS_Request_MultiRequestInterface\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\ninterface CAS_Request_MultiRequestInterface\n{\n\n    /*********************************************************\n     * Add Requests\n    *********************************************************/\n\n    /**\n     * Add a new Request to this batch.\n     * Note, implementations will likely restrict requests to their own concrete\n     * class hierarchy.\n     *\n     * @param CAS_Request_RequestInterface $request request interface\n     *\n     * @return void\n     * @throws CAS_OutOfSequenceException If called after the Request has been\n     * sent.\n     * @throws CAS_InvalidArgumentException If passed a Request of the wrong\n     * implmentation.\n     */\n    public function addRequest (CAS_Request_RequestInterface $request);\n\n    /**\n     * Retrieve the number of requests added to this batch.\n     *\n     * @return int number of request elements\n     */\n    public function getNumRequests ();\n\n    /*********************************************************\n     * 2. Send the Request\n    *********************************************************/\n\n    /**\n     * Perform the request. After sending, all requests will have their\n     * responses poulated.\n     *\n     * @return bool TRUE on success, FALSE on failure.\n     * @throws CAS_OutOfSequenceException If called multiple times.\n     */\n    public function send ();\n}\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/Request/RequestInterface.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * PHP Version 7\n *\n * @file     CAS/Request/RequestInterface.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\n/**\n * This interface defines a class library for performing web requests.\n *\n * @class    CAS_Request_RequestInterface\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\ninterface CAS_Request_RequestInterface\n{\n\n    /*********************************************************\n     * Configure the Request\n    *********************************************************/\n\n    /**\n     * Set the URL of the Request\n     *\n     * @param string $url url to set\n     *\n     * @return void\n     * @throws CAS_OutOfSequenceException If called after the Request has been sent.\n     */\n    public function setUrl ($url);\n\n    /**\n     * Add a cookie to the request.\n     *\n     * @param string $name  name of cookie\n     * @param string $value value of cookie\n     *\n     * @return void\n     * @throws CAS_OutOfSequenceException If called after the Request has been sent.\n     */\n    public function addCookie ($name, $value);\n\n    /**\n     * Add an array of cookies to the request.\n     * The cookie array is of the form\n     *     array('cookie_name' => 'cookie_value', 'cookie_name2' => cookie_value2')\n     *\n     * @param array $cookies cookies to add\n     *\n     * @return void\n     * @throws CAS_OutOfSequenceException If called after the Request has been sent.\n     */\n    public function addCookies (array $cookies);\n\n    /**\n     * Add a header string to the request.\n     *\n     * @param string $header header to add\n     *\n     * @return void\n     * @throws CAS_OutOfSequenceException If called after the Request has been sent.\n     */\n    public function addHeader ($header);\n\n    /**\n     * Add an array of header strings to the request.\n     *\n     * @param array $headers headers to add\n     *\n     * @return void\n     * @throws CAS_OutOfSequenceException If called after the Request has been sent.\n     */\n    public function addHeaders (array $headers);\n\n    /**\n     * Make the request a POST request rather than the default GET request.\n     *\n     * @return void\n     * @throws CAS_OutOfSequenceException If called after the Request has been sent.\n     */\n    public function makePost ();\n\n    /**\n     * Add a POST body to the request\n     *\n     * @param string $body body to add\n     *\n     * @return void\n     * @throws CAS_OutOfSequenceException If called after the Request has been sent.\n     */\n    public function setPostBody ($body);\n\n\n    /**\n     * Specify the path to an SSL CA certificate to validate the server with.\n     *\n     * @param string  $caCertPath  path to cert file\n     * @param boolean $validate_cn validate CN of SSL certificate\n     *\n     * @return void\n     * @throws CAS_OutOfSequenceException If called after the Request has been sent.\n     */\n    public function setSslCaCert ($caCertPath, $validate_cn = true);\n\n\n\n    /*********************************************************\n     * 2. Send the Request\n    *********************************************************/\n\n    /**\n     * Perform the request.\n     *\n     * @return bool TRUE on success, FALSE on failure.\n     * @throws CAS_OutOfSequenceException If called multiple times.\n     */\n    public function send ();\n\n    /*********************************************************\n     * 3. Access the response\n    *********************************************************/\n\n    /**\n     * Answer the headers of the response.\n     *\n     * @return array An array of header strings.\n     * @throws CAS_OutOfSequenceException If called before the Request has been sent.\n     */\n    public function getResponseHeaders ();\n\n    /**\n     * Answer HTTP status code of the response\n     *\n     * @return int\n     * @throws CAS_OutOfSequenceException If called before the Request has been sent.\n     */\n    public function getResponseStatusCode ();\n\n    /**\n     * Answer the body of response.\n     *\n     * @return string\n     * @throws CAS_OutOfSequenceException If called before the Request has been sent.\n     */\n    public function getResponseBody ();\n\n    /**\n     * Answer a message describing any errors if the request failed.\n     *\n     * @return string\n     * @throws CAS_OutOfSequenceException If called before the Request has been sent.\n     */\n    public function getErrorMessage ();\n}\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/ServiceBaseUrl/AllowedListDiscovery.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * PHP Version 7\n *\n * @file     CAS/ServiceBaseUrl/AllowedListDiscovery.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Henry Pan <git@phy25.com>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\n\n/**\n * Class that gets the service base URL of the PHP server by HTTP header\n * discovery and allowlist check. This is used to generate service URL\n * and PGT callback URL.\n *\n * @class    CAS_ServiceBaseUrl_AllowedListDiscovery\n * @category Authentication\n * @package  PhpCAS\n * @author   Henry Pan <git@phy25.com>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\nclass CAS_ServiceBaseUrl_AllowedListDiscovery\nextends CAS_ServiceBaseUrl_Base\n{\n    private $_list = array();\n\n    public function __construct($list) {\n        if (is_array($list)) {\n            if (count($list) === 0) {\n                throw new CAS_InvalidArgumentException('$list should not be empty');\n            }\n            foreach ($list as $value) {\n                $this->allow($value);\n            }\n        } else {\n            throw new CAS_TypeMismatchException($list, '$list', 'array');\n        }\n    }\n\n    /**\n     * Add a base URL to the allowed list.\n     *\n     * @param $url protocol, host name and port to add to the allowed list\n     *\n     * @return void\n     */\n    public function allow($url)\n    {\n        $this->_list[] = $this->removeStandardPort($url);\n    }\n\n    /**\n     * Check if the server name is allowed by configuration.\n     *\n     * @param $name server name to check\n     *\n     * @return bool whether the allowed list contains the server name\n     */\n    protected function isAllowed($name)\n    {\n        return in_array($name, $this->_list);\n    }\n\n    /**\n     * Discover the server name through HTTP headers.\n     *\n     * We read:\n     * - HTTP header X-Forwarded-Host\n     * - HTTP header X-Forwarded-Server and X-Forwarded-Port\n     * - HTTP header Host and SERVER_PORT\n     * - PHP SERVER_NAME (which can change based on the HTTP server used)\n     *\n     * The standard port will be omitted (80 for HTTP, 443 for HTTPS).\n     *\n     * @return string the discovered, unsanitized server protocol, hostname and port\n     */\n    protected function discover()\n    {\n        $isHttps = $this->isHttps();\n        $protocol = $isHttps ? 'https' : 'http';\n        $protocol .= '://';\n        if (!empty($_SERVER['HTTP_X_FORWARDED_HOST'])) {\n            // explode the host list separated by comma and use the first host\n            $hosts = explode(',', $_SERVER['HTTP_X_FORWARDED_HOST']);\n            // see rfc7239#5.3 and rfc7230#2.7.1: port is in HTTP_X_FORWARDED_HOST if non default\n            return $protocol . $hosts[0];\n        } else if (!empty($_SERVER['HTTP_X_FORWARDED_SERVER'])) {\n            $server_url = $_SERVER['HTTP_X_FORWARDED_SERVER'];\n        } else {\n            if (empty($_SERVER['SERVER_NAME'])) {\n                $server_url = $_SERVER['HTTP_HOST'];\n            } else {\n                $server_url = $_SERVER['SERVER_NAME'];\n            }\n        }\n        if (!strpos($server_url, ':')) {\n            if (empty($_SERVER['HTTP_X_FORWARDED_PORT'])) {\n                $server_port = $_SERVER['SERVER_PORT'];\n            } else {\n                $ports = explode(',', $_SERVER['HTTP_X_FORWARDED_PORT']);\n                $server_port = $ports[0];\n            }\n\n            $server_url .= ':';\n            $server_url .= $server_port;\n        }\n        return $protocol . $server_url;\n    }\n\n    /**\n     * Get PHP server base URL.\n     *\n     * @return string the server protocol, hostname and port\n     */\n    public function get()\n    {\n        phpCAS::traceBegin();\n        $result = $this->removeStandardPort($this->discover());\n        phpCAS::trace(\"Discovered server base URL: \" . $result);\n        if ($this->isAllowed($result)) {\n            phpCAS::trace(\"Server base URL is allowed\");\n            phpCAS::traceEnd(true);\n        } else {\n            $result = $this->_list[0];\n            phpCAS::trace(\"Server base URL is not allowed, using default: \" . $result);\n            phpCAS::traceEnd(false);\n        }\n        return $result;\n    }\n}\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/ServiceBaseUrl/Base.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * PHP Version 7\n *\n * @file     CAS/ServiceBaseUrl/Base.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Henry Pan <git@phy25.com>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\n/**\n * Base class of CAS/ServiceBaseUrl that implements isHTTPS method.\n *\n * @class    CAS_ServiceBaseUrl_Base\n * @category Authentication\n * @package  PhpCAS\n * @author   Henry Pan <git@phy25.com>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\nabstract class CAS_ServiceBaseUrl_Base\nimplements CAS_ServiceBaseUrl_Interface\n{\n\n    /**\n     * Get PHP server name.\n     *\n     * @return string the server hostname and port of the server\n     */\n    abstract public function get();\n\n    /**\n     * Check whether HTTPS is used.\n     *\n     * This is used to construct the protocol in the URL.\n     *\n     * @return bool true if HTTPS is used\n     */\n    public function isHttps() {\n        if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO'])) {\n            return ($_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https');\n        } elseif (!empty($_SERVER['HTTP_X_FORWARDED_PROTOCOL'])) {\n            return ($_SERVER['HTTP_X_FORWARDED_PROTOCOL'] === 'https');\n        } elseif ( isset($_SERVER['HTTPS'])\n            && !empty($_SERVER['HTTPS'])\n            && strcasecmp($_SERVER['HTTPS'], 'off') !== 0\n        ) {\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * Remove standard HTTP and HTTPS port for discovery and allowlist input.\n     *\n     * @param $url URL as https://domain:port without trailing slash\n     * @return standardized URL, or the original URL\n     * @throws CAS_InvalidArgumentException if the URL does not include the protocol\n     */\n    protected function removeStandardPort($url) {\n        if (strpos($url, \"://\") === false) {\n            throw new CAS_InvalidArgumentException(\n                \"Configured base URL should include the protocol string: \" . $url);\n        }\n\n        $url = rtrim($url, '/');\n\n        if (strpos($url, \"https://\") === 0 && substr_compare($url, ':443', -4) === 0) {\n            return substr($url, 0, -4);\n        }\n\n        if (strpos($url, \"http://\") === 0 && substr_compare($url, ':80', -3) === 0) {\n            return substr($url, 0, -3);\n        }\n\n        return $url;\n    }\n\n}\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/ServiceBaseUrl/Interface.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * PHP Version 7\n *\n * @file     CAS/ServerHostname/Interface.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Henry Pan <git@phy25.com>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\n/**\n * An interface for classes that gets the server name of the PHP server.\n * This is used to generate service URL and PGT callback URL.\n *\n * @class    CAS_ServiceBaseUrl_Interface\n * @category Authentication\n * @package  PhpCAS\n * @author   Henry Pan <git@phy25.com>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\ninterface CAS_ServiceBaseUrl_Interface\n{\n\n    /**\n     * Get PHP HTTP protocol and server name.\n     *\n     * @return string protocol, server hostname, and optionally port,\n     *                without trailing slash (https://localhost:8443)\n     */\n    public function get();\n\n    /**\n     * Check whether HTTPS is used.\n     *\n     * This is used to construct the protocol in the URL.\n     *\n     * @return bool true if HTTPS is used\n     */\n    public function isHttps();\n\n}\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/ServiceBaseUrl/Static.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * PHP Version 7\n *\n * @file     CAS/ServiceBaseUrl/Static.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Henry Pan <git@phy25.com>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\n\n/**\n * Class that gets the server name of the PHP server by statically set\n * hostname and port. This is used to generate service URL and PGT\n * callback URL.\n *\n * @class    CAS_ServiceBaseUrl_Static\n * @category Authentication\n * @package  PhpCAS\n * @author   Henry Pan <git@phy25.com>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\nclass CAS_ServiceBaseUrl_Static\nextends CAS_ServiceBaseUrl_Base\n{\n    private $_name = null;\n\n    public function __construct($name) {\n        if (is_string($name)) {\n            $this->_name = $this->removeStandardPort($name);\n        } else {\n            throw new CAS_TypeMismatchException($name, '$name', 'string');\n        }\n    }\n\n    /**\n     * Get the server name through static config.\n     *\n     * @return string the server hostname and port of the server configured\n     */\n    public function get()\n    {\n        phpCAS::traceBegin();\n        phpCAS::trace(\"Returning static server name: \" . $this->_name);\n        phpCAS::traceEnd(true);\n        return $this->_name;\n    }\n}"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/Session/PhpSession.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *\n * PHP Version 7\n *\n * @file     CAS/Session/PhpSession.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\n/**\n * Empty class used as a default implementation for phpCAS.\n *\n * Implements the standard PHP session handler without no alterations.\n *\n * @class    CAS_Session_PhpSession\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\nclass CAS_Session_PhpSession extends SessionHandler implements SessionHandlerInterface\n{\n}\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS/TypeMismatchException.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * PHP Version 7\n *\n * @file     CAS/InvalidArgumentException.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\n/**\n * Exception that denotes invalid arguments were passed.\n *\n * @class    CAS_InvalidArgumentException\n * @category Authentication\n * @package  PhpCAS\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\nclass CAS_TypeMismatchException\nextends CAS_InvalidArgumentException\n{\n    /**\n     * Constructor, provides a nice message.\n     *\n     * @param mixed   $argument     Argument\n     * @param string  $argumentName Argument Name\n     * @param string  $type         Type\n     * @param string  $message      Error Message\n     * @param integer $code         Code\n     *\n     * @return void\n     */\n    public function __construct (\n        $argument, $argumentName, $type, $message = '', $code = 0\n    ) {\n        if (is_object($argument)) {\n            $foundType = get_class($argument).' object';\n        } else {\n            $foundType = gettype($argument);\n        }\n\n        parent::__construct(\n            'type mismatched for parameter '\n            . $argumentName . ' (should be \\'' . $type .' \\'), '\n            . $foundType . ' given. ' . $message, $code\n        );\n    }\n}\n?>\n"
  },
  {
    "path": "server/vendor/jasig/phpcas/source/CAS.php",
    "content": "<?php\n\n/**\n * Licensed to Jasig under one or more contributor license\n * agreements. See the NOTICE file distributed with this work for\n * additional information regarding copyright ownership.\n *\n * Jasig licenses this file to you under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in\n * compliance with the License. You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *\n *\n * Interface class of the phpCAS library\n * PHP Version 7\n *\n * @file     CAS/CAS.php\n * @category Authentication\n * @package  PhpCAS\n * @author   Pascal Aubry <pascal.aubry@univ-rennes1.fr>\n * @author   Olivier Berger <olivier.berger@it-sudparis.eu>\n * @author   Brett Bieber <brett.bieber@gmail.com>\n * @author   Joachim Fritschi <jfritschi@freenet.de>\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n * @ingroup public\n */\n\nuse Psr\\Log\\LoggerInterface;\n\n//\n// hack by Vangelis Haniotakis to handle the absence of $_SERVER['REQUEST_URI']\n// in IIS\n//\nif (!isset($_SERVER['REQUEST_URI']) && isset($_SERVER['SCRIPT_NAME']) && isset($_SERVER['QUERY_STRING'])) {\n    $_SERVER['REQUEST_URI'] = $_SERVER['SCRIPT_NAME'] . '?' . $_SERVER['QUERY_STRING'];\n}\n\n\n// ########################################################################\n//  CONSTANTS\n// ########################################################################\n\n// ------------------------------------------------------------------------\n//  CAS VERSIONS\n// ------------------------------------------------------------------------\n\n/**\n * phpCAS version. accessible for the user by phpCAS::getVersion().\n */\ndefine('PHPCAS_VERSION', '1.6.1');\n\n/**\n * @addtogroup public\n * @{\n */\n\n/**\n * phpCAS supported protocols. accessible for the user by phpCAS::getSupportedProtocols().\n */\n\n/**\n * CAS version 1.0\n */\ndefine(\"CAS_VERSION_1_0\", '1.0');\n/*!\n * CAS version 2.0\n*/\ndefine(\"CAS_VERSION_2_0\", '2.0');\n/**\n * CAS version 3.0\n */\ndefine(\"CAS_VERSION_3_0\", '3.0');\n\n// ------------------------------------------------------------------------\n//  SAML defines\n// ------------------------------------------------------------------------\n\n/**\n * SAML protocol\n */\ndefine(\"SAML_VERSION_1_1\", 'S1');\n\n/**\n * XML header for SAML POST\n */\ndefine(\"SAML_XML_HEADER\", '<?xml version=\"1.0\" encoding=\"UTF-8\"?>');\n\n/**\n * SOAP envelope for SAML POST\n */\ndefine(\"SAML_SOAP_ENV\", '<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\"><SOAP-ENV:Header/>');\n\n/**\n * SOAP body for SAML POST\n */\ndefine(\"SAML_SOAP_BODY\", '<SOAP-ENV:Body>');\n\n/**\n * SAMLP request\n */\ndefine(\"SAMLP_REQUEST\", '<samlp:Request xmlns:samlp=\"urn:oasis:names:tc:SAML:1.0:protocol\"  MajorVersion=\"1\" MinorVersion=\"1\" RequestID=\"_192.168.16.51.1024506224022\" IssueInstant=\"2002-06-19T17:03:44.022Z\">');\ndefine(\"SAMLP_REQUEST_CLOSE\", '</samlp:Request>');\n\n/**\n * SAMLP artifact tag (for the ticket)\n */\ndefine(\"SAML_ASSERTION_ARTIFACT\", '<samlp:AssertionArtifact>');\n\n/**\n * SAMLP close\n */\ndefine(\"SAML_ASSERTION_ARTIFACT_CLOSE\", '</samlp:AssertionArtifact>');\n\n/**\n * SOAP body close\n */\ndefine(\"SAML_SOAP_BODY_CLOSE\", '</SOAP-ENV:Body>');\n\n/**\n * SOAP envelope close\n */\ndefine(\"SAML_SOAP_ENV_CLOSE\", '</SOAP-ENV:Envelope>');\n\n/**\n * SAML Attributes\n */\ndefine(\"SAML_ATTRIBUTES\", 'SAMLATTRIBS');\n\n/** @} */\n/**\n * @addtogroup publicPGTStorage\n * @{\n */\n// ------------------------------------------------------------------------\n//  FILE PGT STORAGE\n// ------------------------------------------------------------------------\n/**\n * Default path used when storing PGT's to file\n */\ndefine(\"CAS_PGT_STORAGE_FILE_DEFAULT_PATH\", session_save_path());\n/** @} */\n// ------------------------------------------------------------------------\n// SERVICE ACCESS ERRORS\n// ------------------------------------------------------------------------\n/**\n * @addtogroup publicServices\n * @{\n */\n\n/**\n * phpCAS::service() error code on success\n */\ndefine(\"PHPCAS_SERVICE_OK\", 0);\n/**\n * phpCAS::service() error code when the PT could not retrieve because\n * the CAS server did not respond.\n */\ndefine(\"PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE\", 1);\n/**\n * phpCAS::service() error code when the PT could not retrieve because\n * the response of the CAS server was ill-formed.\n */\ndefine(\"PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE\", 2);\n/**\n * phpCAS::service() error code when the PT could not retrieve because\n * the CAS server did not want to.\n */\ndefine(\"PHPCAS_SERVICE_PT_FAILURE\", 3);\n/**\n * phpCAS::service() error code when the service was not available.\n */\ndefine(\"PHPCAS_SERVICE_NOT_AVAILABLE\", 4);\n\n// ------------------------------------------------------------------------\n// SERVICE TYPES\n// ------------------------------------------------------------------------\n/**\n * phpCAS::getProxiedService() type for HTTP GET\n */\ndefine(\"PHPCAS_PROXIED_SERVICE_HTTP_GET\", 'CAS_ProxiedService_Http_Get');\n/**\n * phpCAS::getProxiedService() type for HTTP POST\n */\ndefine(\"PHPCAS_PROXIED_SERVICE_HTTP_POST\", 'CAS_ProxiedService_Http_Post');\n/**\n * phpCAS::getProxiedService() type for IMAP\n */\ndefine(\"PHPCAS_PROXIED_SERVICE_IMAP\", 'CAS_ProxiedService_Imap');\n\n\n/** @} */\n// ------------------------------------------------------------------------\n//  LANGUAGES\n// ------------------------------------------------------------------------\n/**\n * @addtogroup publicLang\n * @{\n */\n\ndefine(\"PHPCAS_LANG_ENGLISH\", 'CAS_Languages_English');\ndefine(\"PHPCAS_LANG_FRENCH\", 'CAS_Languages_French');\ndefine(\"PHPCAS_LANG_GREEK\", 'CAS_Languages_Greek');\ndefine(\"PHPCAS_LANG_GERMAN\", 'CAS_Languages_German');\ndefine(\"PHPCAS_LANG_JAPANESE\", 'CAS_Languages_Japanese');\ndefine(\"PHPCAS_LANG_SPANISH\", 'CAS_Languages_Spanish');\ndefine(\"PHPCAS_LANG_CATALAN\", 'CAS_Languages_Catalan');\ndefine(\"PHPCAS_LANG_CHINESE_SIMPLIFIED\", 'CAS_Languages_ChineseSimplified');\ndefine(\"PHPCAS_LANG_GALEGO\", 'CAS_Languages_Galego');\ndefine(\"PHPCAS_LANG_PORTUGUESE\", 'CAS_Languages_Portuguese');\n\n/** @} */\n\n/**\n * @addtogroup internalLang\n * @{\n */\n\n/**\n * phpCAS default language (when phpCAS::setLang() is not used)\n */\ndefine(\"PHPCAS_LANG_DEFAULT\", PHPCAS_LANG_ENGLISH);\n\n/** @} */\n// ------------------------------------------------------------------------\n//  DEBUG\n// ------------------------------------------------------------------------\n/**\n * @addtogroup publicDebug\n * @{\n */\n\n/**\n * The default directory for the debug file under Unix.\n * @return  string directory for the debug file\n */\nfunction gettmpdir() {\nif (!empty($_ENV['TMP'])) { return realpath($_ENV['TMP']); }\nif (!empty($_ENV['TMPDIR'])) { return realpath( $_ENV['TMPDIR']); }\nif (!empty($_ENV['TEMP'])) { return realpath( $_ENV['TEMP']); }\nreturn \"/tmp\";\n}\ndefine('DEFAULT_DEBUG_DIR', gettmpdir().\"/\");\n\n/** @} */\n\n// include the class autoloader\nrequire_once __DIR__ . '/CAS/Autoload.php';\n\n/**\n * The phpCAS class is a simple container for the phpCAS library. It provides CAS\n * authentication for web applications written in PHP.\n *\n * @ingroup public\n * @class phpCAS\n * @category Authentication\n * @package  PhpCAS\n * @author   Pascal Aubry <pascal.aubry@univ-rennes1.fr>\n * @author   Olivier Berger <olivier.berger@it-sudparis.eu>\n * @author   Brett Bieber <brett.bieber@gmail.com>\n * @author   Joachim Fritschi <jfritschi@freenet.de>\n * @author   Adam Franco <afranco@middlebury.edu>\n * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0\n * @link     https://wiki.jasig.org/display/CASC/phpCAS\n */\n\nclass phpCAS\n{\n\n    /**\n     * This variable is used by the interface class phpCAS.\n     *\n     * @var CAS_Client\n     * @hideinitializer\n     */\n    private static $_PHPCAS_CLIENT;\n\n    /**\n     * @var array\n     * This variable is used to store where the initializer is called from\n     * (to print a comprehensive error in case of multiple calls).\n     *\n     * @hideinitializer\n     */\n    private static $_PHPCAS_INIT_CALL;\n\n    /**\n     * @var array\n     * This variable is used to store phpCAS debug mode.\n     *\n     * @hideinitializer\n     */\n    private static $_PHPCAS_DEBUG;\n\n    /**\n     * This variable is used to enable verbose mode\n     * This pevents debug info to be show to the user. Since it's a security\n     * feature the default is false\n     *\n     * @hideinitializer\n     */\n    private static $_PHPCAS_VERBOSE = false;\n\n\n    // ########################################################################\n    //  INITIALIZATION\n    // ########################################################################\n\n    /**\n     * @addtogroup publicInit\n     * @{\n     */\n\n    /**\n     * phpCAS client initializer.\n     *\n     * @param string                   $server_version  the version of the CAS server\n     * @param string                   $server_hostname the hostname of the CAS server\n     * @param int                      $server_port     the port the CAS server is running on\n     * @param string                   $server_uri      the URI the CAS server is responding on\n     * @param string|string[]|CAS_ServiceBaseUrl_Interface\n     *                                 $service_base_url the base URL (protocol, host and the\n     *                                                  optional port) of the CAS client; pass\n     *                                                  in an array to use auto discovery with\n     *                                                  an allowlist; pass in\n     *                                                  CAS_ServiceBaseUrl_Interface for custom\n     *                                                  behavior. Added in 1.6.0. Similar to\n     *                                                  serverName config in other CAS clients.\n     * @param bool                     $changeSessionID Allow phpCAS to change the session_id\n     *                                                  (Single Sign Out/handleLogoutRequests\n     *                                                  is based on that change)\n     * @param \\SessionHandlerInterface $sessionHandler  the session handler\n     *\n     * @return void a newly created CAS_Client object\n     * @note Only one of the phpCAS::client() and phpCAS::proxy functions should be\n     * called, only once, and before all other methods (except phpCAS::getVersion()\n     * and phpCAS::setDebug()).\n     */\n    public static function client($server_version, $server_hostname,\n        $server_port, $server_uri, $service_base_url,\n        $changeSessionID = true, \\SessionHandlerInterface $sessionHandler = null\n    ) {\n        phpCAS :: traceBegin();\n        if (is_object(self::$_PHPCAS_CLIENT)) {\n            phpCAS :: error(self::$_PHPCAS_INIT_CALL['method'] . '() has already been called (at ' . self::$_PHPCAS_INIT_CALL['file'] . ':' . self::$_PHPCAS_INIT_CALL['line'] . ')');\n        }\n\n        // store where the initializer is called from\n        $dbg = debug_backtrace();\n        self::$_PHPCAS_INIT_CALL = array (\n            'done' => true,\n            'file' => $dbg[0]['file'],\n            'line' => $dbg[0]['line'],\n            'method' => __CLASS__ . '::' . __FUNCTION__\n        );\n\n        // initialize the object $_PHPCAS_CLIENT\n        try {\n            self::$_PHPCAS_CLIENT = new CAS_Client(\n                $server_version, false, $server_hostname, $server_port, $server_uri, $service_base_url,\n                $changeSessionID, $sessionHandler\n            );\n        } catch (Exception $e) {\n            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());\n        }\n        phpCAS :: traceEnd();\n    }\n\n    /**\n     * phpCAS proxy initializer.\n     *\n     * @param string                   $server_version  the version of the CAS server\n     * @param string                   $server_hostname the hostname of the CAS server\n     * @param string                   $server_port     the port the CAS server is running on\n     * @param string                   $server_uri      the URI the CAS server is responding on\n     * @param string|string[]|CAS_ServiceBaseUrl_Interface\n     *                                 $service_base_url the base URL (protocol, host and the\n     *                                                  optional port) of the CAS client; pass\n     *                                                  in an array to use auto discovery with\n     *                                                  an allowlist; pass in\n     *                                                  CAS_ServiceBaseUrl_Interface for custom\n     *                                                  behavior. Added in 1.6.0. Similar to\n     *                                                  serverName config in other CAS clients.\n     * @param bool                     $changeSessionID Allow phpCAS to change the session_id\n     *                                                  (Single Sign Out/handleLogoutRequests\n     *                                                  is based on that change)\n     * @param \\SessionHandlerInterface $sessionHandler  the session handler\n     *\n     * @return void a newly created CAS_Client object\n     * @note Only one of the phpCAS::client() and phpCAS::proxy functions should be\n     * called, only once, and before all other methods (except phpCAS::getVersion()\n     * and phpCAS::setDebug()).\n     */\n    public static function proxy($server_version, $server_hostname,\n        $server_port, $server_uri, $service_base_url,\n        $changeSessionID = true, \\SessionHandlerInterface $sessionHandler = null\n    ) {\n        phpCAS :: traceBegin();\n        if (is_object(self::$_PHPCAS_CLIENT)) {\n            phpCAS :: error(self::$_PHPCAS_INIT_CALL['method'] . '() has already been called (at ' . self::$_PHPCAS_INIT_CALL['file'] . ':' . self::$_PHPCAS_INIT_CALL['line'] . ')');\n        }\n\n        // store where the initialzer is called from\n        $dbg = debug_backtrace();\n        self::$_PHPCAS_INIT_CALL = array (\n            'done' => true,\n            'file' => $dbg[0]['file'],\n            'line' => $dbg[0]['line'],\n            'method' => __CLASS__ . '::' . __FUNCTION__\n        );\n\n        // initialize the object $_PHPCAS_CLIENT\n        try {\n            self::$_PHPCAS_CLIENT = new CAS_Client(\n                $server_version, true, $server_hostname, $server_port, $server_uri, $service_base_url,\n                $changeSessionID, $sessionHandler\n            );\n        } catch (Exception $e) {\n            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());\n        }\n        phpCAS :: traceEnd();\n    }\n\n    /**\n     * Answer whether or not the client or proxy has been initialized\n     *\n     * @return bool\n     */\n    public static function isInitialized ()\n    {\n        return (is_object(self::$_PHPCAS_CLIENT));\n    }\n\n    /** @} */\n    // ########################################################################\n    //  DEBUGGING\n    // ########################################################################\n\n    /**\n     * @addtogroup publicDebug\n     * @{\n     */\n\n    /**\n     * Set/unset PSR-3 logger\n     *\n     * @param LoggerInterface $logger the PSR-3 logger used for logging, or\n     * null to stop logging.\n     *\n     * @return void\n     */\n    public static function setLogger($logger = null)\n    {\n        if (empty(self::$_PHPCAS_DEBUG['unique_id'])) {\n            self::$_PHPCAS_DEBUG['unique_id'] = substr(strtoupper(md5(uniqid(''))), 0, 4);\n        }\n        self::$_PHPCAS_DEBUG['logger'] = $logger;\n        self::$_PHPCAS_DEBUG['indent'] = 0;\n        phpCAS :: trace('START ('.date(\"Y-m-d H:i:s\").') phpCAS-' . PHPCAS_VERSION . ' ******************');\n    }\n\n    /**\n     * Set/unset debug mode\n     *\n     * @param string $filename the name of the file used for logging, or false\n     * to stop debugging.\n     *\n     * @return void\n     *\n     * @deprecated\n     */\n    public static function setDebug($filename = '')\n    {\n        trigger_error('phpCAS::setDebug() is deprecated in favor of phpCAS::setLogger().', E_USER_DEPRECATED);\n\n        if ($filename != false && gettype($filename) != 'string') {\n            phpCAS :: error('type mismatched for parameter $dbg (should be false or the name of the log file)');\n        }\n        if ($filename === false) {\n            self::$_PHPCAS_DEBUG['filename'] = false;\n\n        } else {\n            if (empty ($filename)) {\n                if (preg_match('/^Win.*/', getenv('OS'))) {\n                    if (isset ($_ENV['TMP'])) {\n                        $debugDir = $_ENV['TMP'] . '/';\n                    } else {\n                        $debugDir = '';\n                    }\n                } else {\n                    $debugDir = DEFAULT_DEBUG_DIR;\n                }\n                $filename = $debugDir . 'phpCAS.log';\n            }\n\n            if (empty (self::$_PHPCAS_DEBUG['unique_id'])) {\n                self::$_PHPCAS_DEBUG['unique_id'] = substr(strtoupper(md5(uniqid(''))), 0, 4);\n            }\n\n            self::$_PHPCAS_DEBUG['filename'] = $filename;\n            self::$_PHPCAS_DEBUG['indent'] = 0;\n\n            phpCAS :: trace('START ('.date(\"Y-m-d H:i:s\").') phpCAS-' . PHPCAS_VERSION . ' ******************');\n        }\n    }\n\n    /**\n     * Enable verbose errors messages in the website output\n     * This is a security relevant since internal status info may leak an may\n     * help an attacker. Default is therefore false\n     *\n     * @param bool $verbose enable verbose output\n     *\n     * @return void\n     */\n    public static function setVerbose($verbose)\n    {\n        if ($verbose === true) {\n            self::$_PHPCAS_VERBOSE = true;\n        } else {\n            self::$_PHPCAS_VERBOSE = false;\n        }\n    }\n\n\n    /**\n     * Show is verbose mode is on\n     *\n     * @return bool verbose\n     */\n    public static function getVerbose()\n    {\n        return self::$_PHPCAS_VERBOSE;\n    }\n\n    /**\n     * Logs a string in debug mode.\n     *\n     * @param string $str the string to write\n     *\n     * @return void\n     * @private\n     */\n    public static function log($str)\n    {\n        $indent_str = \".\";\n\n\n        if (isset(self::$_PHPCAS_DEBUG['logger']) || !empty(self::$_PHPCAS_DEBUG['filename'])) {\n            for ($i = 0; $i < self::$_PHPCAS_DEBUG['indent']; $i++) {\n\n                $indent_str .= '|    ';\n            }\n            // allow for multiline output with proper identing. Usefull for\n            // dumping cas answers etc.\n            $str2 = str_replace(\"\\n\", \"\\n\" . self::$_PHPCAS_DEBUG['unique_id'] . ' ' . $indent_str, $str);\n            $str3 = self::$_PHPCAS_DEBUG['unique_id'] . ' ' . $indent_str . $str2;\n            if (isset(self::$_PHPCAS_DEBUG['logger'])) {\n                self::$_PHPCAS_DEBUG['logger']->info($str3);\n            }\n            if (!empty(self::$_PHPCAS_DEBUG['filename'])) {\n                // Check if file exists and modifiy file permissions to be only\n                // readable by the webserver\n                if (!file_exists(self::$_PHPCAS_DEBUG['filename'])) {\n                    touch(self::$_PHPCAS_DEBUG['filename']);\n                    // Chmod will fail on windows\n                    @chmod(self::$_PHPCAS_DEBUG['filename'], 0600);\n                }\n                error_log($str3 . \"\\n\", 3, self::$_PHPCAS_DEBUG['filename']);\n            }\n        }\n\n    }\n\n    /**\n     * This method is used by interface methods to print an error and where the\n     * function was originally called from.\n     *\n     * @param string $msg the message to print\n     *\n     * @return void\n     * @private\n     */\n    public static function error($msg)\n    {\n        phpCAS :: traceBegin();\n        $dbg = debug_backtrace();\n        $function = '?';\n        $file = '?';\n        $line = '?';\n        if (is_array($dbg)) {\n            for ($i = 1; $i < sizeof($dbg); $i++) {\n                if (is_array($dbg[$i]) && isset($dbg[$i]['class']) ) {\n                    if ($dbg[$i]['class'] == __CLASS__) {\n                        $function = $dbg[$i]['function'];\n                        $file = $dbg[$i]['file'];\n                        $line = $dbg[$i]['line'];\n                    }\n                }\n            }\n        }\n        if (self::$_PHPCAS_VERBOSE) {\n            echo \"<br />\\n<b>phpCAS error</b>: <font color=\\\"FF0000\\\"><b>\" . __CLASS__ . \"::\" . $function . '(): ' . htmlentities($msg) . \"</b></font> in <b>\" . $file . \"</b> on line <b>\" . $line . \"</b><br />\\n\";\n        }\n        phpCAS :: trace($msg . ' in ' . $file . 'on line ' . $line );\n        phpCAS :: traceEnd();\n\n        throw new CAS_GracefullTerminationException(__CLASS__ . \"::\" . $function . '(): ' . $msg);\n    }\n\n    /**\n     * This method is used to log something in debug mode.\n     *\n     * @param string $str string to log\n     *\n     * @return void\n     */\n    public static function trace($str)\n    {\n        $dbg = debug_backtrace();\n        phpCAS :: log($str . ' [' . basename($dbg[0]['file']) . ':' . $dbg[0]['line'] . ']');\n    }\n\n    /**\n     * This method is used to indicate the start of the execution of a function\n     * in debug mode.\n     *\n     * @return void\n     */\n    public static function traceBegin()\n    {\n        $dbg = debug_backtrace();\n        $str = '=> ';\n        if (!empty ($dbg[1]['class'])) {\n            $str .= $dbg[1]['class'] . '::';\n        }\n        $str .= $dbg[1]['function'] . '(';\n        if (is_array($dbg[1]['args'])) {\n            foreach ($dbg[1]['args'] as $index => $arg) {\n                if ($index != 0) {\n                    $str .= ', ';\n                }\n                if (is_object($arg)) {\n                    $str .= get_class($arg);\n                } else {\n                    $str .= str_replace(array(\"\\r\\n\", \"\\n\", \"\\r\"), \"\", var_export($arg, true));\n                }\n            }\n        }\n        if (isset($dbg[1]['file'])) {\n            $file = basename($dbg[1]['file']);\n        } else {\n            $file = 'unknown_file';\n        }\n        if (isset($dbg[1]['line'])) {\n            $line = $dbg[1]['line'];\n        } else {\n            $line = 'unknown_line';\n        }\n        $str .= ') [' . $file . ':' . $line . ']';\n        phpCAS :: log($str);\n        if (!isset(self::$_PHPCAS_DEBUG['indent'])) {\n            self::$_PHPCAS_DEBUG['indent'] = 0;\n        } else {\n            self::$_PHPCAS_DEBUG['indent']++;\n        }\n    }\n\n    /**\n     * This method is used to indicate the end of the execution of a function in\n     * debug mode.\n     *\n     * @param mixed $res the result of the function\n     *\n     * @return void\n     */\n    public static function traceEnd($res = '')\n    {\n        if (empty(self::$_PHPCAS_DEBUG['indent'])) {\n            self::$_PHPCAS_DEBUG['indent'] = 0;\n        } else {\n            self::$_PHPCAS_DEBUG['indent']--;\n        }\n        $str = '';\n        if (is_object($res)) {\n            $str .= '<= ' . get_class($res);\n        } else {\n            $str .= '<= ' . str_replace(array(\"\\r\\n\", \"\\n\", \"\\r\"), \"\", var_export($res, true));\n        }\n\n        phpCAS :: log($str);\n    }\n\n    /**\n     * This method is used to indicate the end of the execution of the program\n     *\n     * @return void\n     */\n    public static function traceExit()\n    {\n        phpCAS :: log('exit()');\n        while (self::$_PHPCAS_DEBUG['indent'] > 0) {\n            phpCAS :: log('-');\n            self::$_PHPCAS_DEBUG['indent']--;\n        }\n    }\n\n    /** @} */\n    // ########################################################################\n    //  INTERNATIONALIZATION\n    // ########################################################################\n    /**\n    * @addtogroup publicLang\n    * @{\n    */\n\n    /**\n     * This method is used to set the language used by phpCAS.\n     *\n     * @param string $lang string representing the language.\n     *\n     * @return void\n     *\n     * @sa PHPCAS_LANG_FRENCH, PHPCAS_LANG_ENGLISH\n     * @note Can be called only once.\n     */\n    public static function setLang($lang)\n    {\n        phpCAS::_validateClientExists();\n\n        try {\n            self::$_PHPCAS_CLIENT->setLang($lang);\n        } catch (Exception $e) {\n            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());\n        }\n    }\n\n    /** @} */\n    // ########################################################################\n    //  VERSION\n    // ########################################################################\n    /**\n    * @addtogroup public\n    * @{\n    */\n\n    /**\n     * This method returns the phpCAS version.\n     *\n     * @return string the phpCAS version.\n     */\n    public static function getVersion()\n    {\n        return PHPCAS_VERSION;\n    }\n\n    /**\n     * This method returns supported protocols.\n     *\n     * @return array an array of all supported protocols. Use internal protocol name as array key.\n     */\n    public static function getSupportedProtocols()\n    {\n        $supportedProtocols = array();\n        $supportedProtocols[CAS_VERSION_1_0] = 'CAS 1.0';\n        $supportedProtocols[CAS_VERSION_2_0] = 'CAS 2.0';\n        $supportedProtocols[CAS_VERSION_3_0] = 'CAS 3.0';\n        $supportedProtocols[SAML_VERSION_1_1] = 'SAML 1.1';\n\n        return $supportedProtocols;\n    }\n\n    /** @} */\n    // ########################################################################\n    //  HTML OUTPUT\n    // ########################################################################\n    /**\n    * @addtogroup publicOutput\n    * @{\n    */\n\n    /**\n     * This method sets the HTML header used for all outputs.\n     *\n     * @param string $header the HTML header.\n     *\n     * @return void\n     */\n    public static function setHTMLHeader($header)\n    {\n        phpCAS::_validateClientExists();\n\n        try {\n            self::$_PHPCAS_CLIENT->setHTMLHeader($header);\n        } catch (Exception $e) {\n            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());\n        }\n    }\n\n    /**\n     * This method sets the HTML footer used for all outputs.\n     *\n     * @param string $footer the HTML footer.\n     *\n     * @return void\n     */\n    public static function setHTMLFooter($footer)\n    {\n        phpCAS::_validateClientExists();\n\n        try {\n            self::$_PHPCAS_CLIENT->setHTMLFooter($footer);\n        } catch (Exception $e) {\n            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());\n        }\n    }\n\n    /** @} */\n    // ########################################################################\n    //  PGT STORAGE\n    // ########################################################################\n    /**\n    * @addtogroup publicPGTStorage\n    * @{\n    */\n\n    /**\n     * This method can be used to set a custom PGT storage object.\n     *\n     * @param CAS_PGTStorage_AbstractStorage $storage a PGT storage object that inherits from the\n     * CAS_PGTStorage_AbstractStorage class\n     *\n     * @return void\n     */\n    public static function setPGTStorage($storage)\n    {\n        phpCAS :: traceBegin();\n        phpCAS::_validateProxyExists();\n\n        try {\n            self::$_PHPCAS_CLIENT->setPGTStorage($storage);\n        } catch (Exception $e) {\n            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());\n        }\n        phpCAS :: traceEnd();\n    }\n\n    /**\n     * This method is used to tell phpCAS to store the response of the\n     * CAS server to PGT requests in a database.\n     *\n     * @param string $dsn_or_pdo     a dsn string to use for creating a PDO\n     * object or a PDO object\n     * @param string $username       the username to use when connecting to the\n     * database\n     * @param string $password       the password to use when connecting to the\n     * database\n     * @param string $table          the table to use for storing and retrieving\n     * PGT's\n     * @param string $driver_options any driver options to use when connecting\n     * to the database\n     *\n     * @return void\n     */\n    public static function setPGTStorageDb($dsn_or_pdo, $username='',\n        $password='', $table='', $driver_options=null\n    ) {\n        phpCAS :: traceBegin();\n        phpCAS::_validateProxyExists();\n\n        try {\n            self::$_PHPCAS_CLIENT->setPGTStorageDb($dsn_or_pdo, $username, $password, $table, $driver_options);\n        } catch (Exception $e) {\n            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());\n        }\n        phpCAS :: traceEnd();\n    }\n\n    /**\n     * This method is used to tell phpCAS to store the response of the\n     * CAS server to PGT requests onto the filesystem.\n     *\n     * @param string $path the path where the PGT's should be stored\n     *\n     * @return void\n     */\n    public static function setPGTStorageFile($path = '')\n    {\n        phpCAS :: traceBegin();\n        phpCAS::_validateProxyExists();\n\n        try {\n            self::$_PHPCAS_CLIENT->setPGTStorageFile($path);\n        } catch (Exception $e) {\n            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());\n        }\n        phpCAS :: traceEnd();\n    }\n    /** @} */\n    // ########################################################################\n    // ACCESS TO EXTERNAL SERVICES\n    // ########################################################################\n    /**\n    * @addtogroup publicServices\n    * @{\n    */\n\n    /**\n     * Answer a proxy-authenticated service handler.\n     *\n     * @param string $type The service type. One of\n     * PHPCAS_PROXIED_SERVICE_HTTP_GET; PHPCAS_PROXIED_SERVICE_HTTP_POST;\n     * PHPCAS_PROXIED_SERVICE_IMAP\n     *\n     * @return CAS_ProxiedService\n     * @throws InvalidArgumentException If the service type is unknown.\n     */\n    public static function getProxiedService ($type)\n    {\n        phpCAS :: traceBegin();\n        phpCAS::_validateProxyExists();\n\n        try {\n            $res = self::$_PHPCAS_CLIENT->getProxiedService($type);\n        } catch (Exception $e) {\n            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());\n        }\n\n        phpCAS :: traceEnd();\n        return $res;\n    }\n\n    /**\n     * Initialize a proxied-service handler with the proxy-ticket it should use.\n     *\n     * @param CAS_ProxiedService $proxiedService Proxied Service Handler\n     *\n     * @return void\n     * @throws CAS_ProxyTicketException If there is a proxy-ticket failure.\n     *\t\tThe code of the Exception will be one of:\n     *\t\t\tPHPCAS_SERVICE_PT_NO_SERVER_RESPONSE\n     *\t\t\tPHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE\n     *\t\t\tPHPCAS_SERVICE_PT_FAILURE\n     */\n    public static function initializeProxiedService (CAS_ProxiedService $proxiedService)\n    {\n        phpCAS::_validateProxyExists();\n\n        try {\n            self::$_PHPCAS_CLIENT->initializeProxiedService($proxiedService);\n        } catch (Exception $e) {\n            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());\n        }\n    }\n\n    /**\n     * This method is used to access an HTTP[S] service.\n     *\n     * @param string $url       the service to access.\n     * @param int &$err_code an error code Possible values are\n     * PHPCAS_SERVICE_OK (on success), PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE,\n     * PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE, PHPCAS_SERVICE_PT_FAILURE,\n     * PHPCAS_SERVICE_NOT_AVAILABLE.\n     * @param string &$output   the output of the service (also used to give an\n     * error message on failure).\n     *\n     * @return bool true on success, false otherwise (in this later case,\n     * $err_code gives the reason why it failed and $output contains an error\n     * message).\n     */\n    public static function serviceWeb($url, & $err_code, & $output)\n    {\n        phpCAS :: traceBegin();\n        phpCAS::_validateProxyExists();\n\n        try {\n            $res = self::$_PHPCAS_CLIENT->serviceWeb($url, $err_code, $output);\n        } catch (Exception $e) {\n            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());\n        }\n\n        phpCAS :: traceEnd($res);\n        return $res;\n    }\n\n    /**\n     * This method is used to access an IMAP/POP3/NNTP service.\n     *\n     * @param string $url       a string giving the URL of the service,\n     * including the mailing box for IMAP URLs, as accepted by imap_open().\n     * @param string $service   a string giving for CAS retrieve Proxy ticket\n     * @param string $flags     options given to imap_open().\n     * @param int &$err_code an error code Possible values are\n     * PHPCAS_SERVICE_OK (on success), PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE,\n     * PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE, PHPCAS_SERVICE_PT_FAILURE,\n     * PHPCAS_SERVICE_NOT_AVAILABLE.\n     * @param string &$err_msg  an error message on failure\n     * @param string &$pt       the Proxy Ticket (PT) retrieved from the CAS\n     * server to access the URL on success, false on error).\n     *\n     * @return object|false IMAP stream on success, false otherwise (in this later\n     * case, $err_code gives the reason why it failed and $err_msg contains an\n     * error message).\n     */\n    public static function serviceMail($url, $service, $flags, & $err_code, & $err_msg, & $pt)\n    {\n        phpCAS :: traceBegin();\n        phpCAS::_validateProxyExists();\n\n        try {\n            $res = self::$_PHPCAS_CLIENT->serviceMail($url, $service, $flags, $err_code, $err_msg, $pt);\n        } catch (Exception $e) {\n            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());\n        }\n\n        phpCAS :: traceEnd($res);\n        return $res;\n    }\n\n    /** @} */\n    // ########################################################################\n    //  AUTHENTICATION\n    // ########################################################################\n    /**\n    * @addtogroup publicAuth\n    * @{\n    */\n\n    /**\n     * Set the times authentication will be cached before really accessing the\n     * CAS server in gateway mode:\n     * - -1: check only once, and then never again (until you pree login)\n     * - 0: always check\n     * - n: check every \"n\" time\n     *\n     * @param int $n an integer.\n     *\n     * @return void\n     */\n    public static function setCacheTimesForAuthRecheck($n)\n    {\n        phpCAS::_validateClientExists();\n\n        try {\n            self::$_PHPCAS_CLIENT->setCacheTimesForAuthRecheck($n);\n        } catch (Exception $e) {\n            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());\n        }\n    }\n\n\n    /**\n     * Set a callback function to be run when receiving CAS attributes\n     *\n     * The callback function will be passed an $success_elements\n     * payload of the response (\\DOMElement) as its first parameter.\n     *\n     * @param string $function       Callback function\n     * @param array  $additionalArgs optional array of arguments\n     *\n     * @return void\n     */\n    public static function setCasAttributeParserCallback($function, array $additionalArgs = array())\n    {\n        phpCAS::_validateClientExists();\n\n        self::$_PHPCAS_CLIENT->setCasAttributeParserCallback($function, $additionalArgs);\n    }\n\n    /**\n     * Set a callback function to be run when a user authenticates.\n     *\n     * The callback function will be passed a $logoutTicket as its first\n     * parameter, followed by any $additionalArgs you pass. The $logoutTicket\n     * parameter is an opaque string that can be used to map the session-id to\n     * logout request in order to support single-signout in applications that\n     * manage their own sessions (rather than letting phpCAS start the session).\n     *\n     * phpCAS::forceAuthentication() will always exit and forward client unless\n     * they are already authenticated. To perform an action at the moment the user\n     * logs in (such as registering an account, performing logging, etc), register\n     * a callback function here.\n     *\n     * @param callable $function       Callback function\n     * @param array  $additionalArgs optional array of arguments\n     *\n     * @return void\n     */\n    public static function setPostAuthenticateCallback ($function, array $additionalArgs = array())\n    {\n        phpCAS::_validateClientExists();\n\n        self::$_PHPCAS_CLIENT->setPostAuthenticateCallback($function, $additionalArgs);\n    }\n\n    /**\n     * Set a callback function to be run when a single-signout request is\n     * received. The callback function will be passed a $logoutTicket as its\n     * first parameter, followed by any $additionalArgs you pass. The\n     * $logoutTicket parameter is an opaque string that can be used to map a\n     * session-id to the logout request in order to support single-signout in\n     * applications that manage their own sessions (rather than letting phpCAS\n     * start and destroy the session).\n     *\n     * @param callable $function       Callback function\n     * @param array  $additionalArgs optional array of arguments\n     *\n     * @return void\n     */\n    public static function setSingleSignoutCallback ($function, array $additionalArgs = array())\n    {\n        phpCAS::_validateClientExists();\n\n        self::$_PHPCAS_CLIENT->setSingleSignoutCallback($function, $additionalArgs);\n    }\n\n    /**\n     * This method is called to check if the user is already authenticated\n     * locally or has a global cas session. A already existing cas session is\n     * determined by a cas gateway call.(cas login call without any interactive\n     * prompt)\n     *\n     * @return bool true when the user is authenticated, false when a previous\n     * gateway login failed or the function will not return if the user is\n     * redirected to the cas server for a gateway login attempt\n     */\n    public static function checkAuthentication()\n    {\n        phpCAS :: traceBegin();\n        phpCAS::_validateClientExists();\n\n        $auth = self::$_PHPCAS_CLIENT->checkAuthentication();\n\n        // store where the authentication has been checked and the result\n        self::$_PHPCAS_CLIENT->markAuthenticationCall($auth);\n\n        phpCAS :: traceEnd($auth);\n        return $auth;\n    }\n\n    /**\n     * This method is called to force authentication if the user was not already\n     * authenticated. If the user is not authenticated, halt by redirecting to\n     * the CAS server.\n     *\n     * @return bool Authentication\n     */\n    public static function forceAuthentication()\n    {\n        phpCAS :: traceBegin();\n        phpCAS::_validateClientExists();\n        $auth = self::$_PHPCAS_CLIENT->forceAuthentication();\n\n        // store where the authentication has been checked and the result\n        self::$_PHPCAS_CLIENT->markAuthenticationCall($auth);\n\n        /*      if (!$auth) {\n         phpCAS :: trace('user is not authenticated, redirecting to the CAS server');\n        self::$_PHPCAS_CLIENT->forceAuthentication();\n        } else {\n        phpCAS :: trace('no need to authenticate (user `' . phpCAS :: getUser() . '\\' is already authenticated)');\n        }*/\n\n        phpCAS :: traceEnd();\n        return $auth;\n    }\n\n    /**\n     * This method is called to renew the authentication.\n     *\n     * @return void\n     **/\n    public static function renewAuthentication()\n    {\n        phpCAS :: traceBegin();\n        phpCAS::_validateClientExists();\n\n        $auth = self::$_PHPCAS_CLIENT->renewAuthentication();\n\n        // store where the authentication has been checked and the result\n        self::$_PHPCAS_CLIENT->markAuthenticationCall($auth);\n\n        //self::$_PHPCAS_CLIENT->renewAuthentication();\n        phpCAS :: traceEnd();\n    }\n\n    /**\n     * This method is called to check if the user is authenticated (previously or by\n     * tickets given in the URL).\n     *\n     * @return bool true when the user is authenticated.\n     */\n    public static function isAuthenticated()\n    {\n        phpCAS :: traceBegin();\n        phpCAS::_validateClientExists();\n\n        // call the isAuthenticated method of the $_PHPCAS_CLIENT object\n        $auth = self::$_PHPCAS_CLIENT->isAuthenticated();\n\n        // store where the authentication has been checked and the result\n        self::$_PHPCAS_CLIENT->markAuthenticationCall($auth);\n\n        phpCAS :: traceEnd($auth);\n        return $auth;\n    }\n\n    /**\n     * Checks whether authenticated based on $_SESSION. Useful to avoid\n     * server calls.\n     *\n     * @return bool true if authenticated, false otherwise.\n     * @since 0.4.22 by Brendan Arnold\n     */\n    public static function isSessionAuthenticated()\n    {\n        phpCAS::_validateClientExists();\n\n        return (self::$_PHPCAS_CLIENT->isSessionAuthenticated());\n    }\n\n    /**\n     * This method returns the CAS user's login name.\n     *\n     * @return string the login name of the authenticated user\n     * @warning should only be called after phpCAS::forceAuthentication()\n     * or phpCAS::checkAuthentication().\n     * */\n    public static function getUser()\n    {\n        phpCAS::_validateClientExists();\n\n        try {\n            return self::$_PHPCAS_CLIENT->getUser();\n        } catch (Exception $e) {\n            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());\n        }\n    }\n\n    /**\n     * Answer attributes about the authenticated user.\n     *\n     * @warning should only be called after phpCAS::forceAuthentication()\n     * or phpCAS::checkAuthentication().\n     *\n     * @return array\n     */\n    public static function getAttributes()\n    {\n        phpCAS::_validateClientExists();\n\n        try {\n            return self::$_PHPCAS_CLIENT->getAttributes();\n        } catch (Exception $e) {\n            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());\n        }\n    }\n\n    /**\n     * Answer true if there are attributes for the authenticated user.\n     *\n     * @warning should only be called after phpCAS::forceAuthentication()\n     * or phpCAS::checkAuthentication().\n     *\n     * @return bool\n     */\n    public static function hasAttributes()\n    {\n        phpCAS::_validateClientExists();\n\n        try {\n            return self::$_PHPCAS_CLIENT->hasAttributes();\n        } catch (Exception $e) {\n            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());\n        }\n    }\n\n    /**\n     * Answer true if an attribute exists for the authenticated user.\n     *\n     * @param string $key attribute name\n     *\n     * @return bool\n     * @warning should only be called after phpCAS::forceAuthentication()\n     * or phpCAS::checkAuthentication().\n     */\n    public static function hasAttribute($key)\n    {\n        phpCAS::_validateClientExists();\n\n        try {\n            return self::$_PHPCAS_CLIENT->hasAttribute($key);\n        } catch (Exception $e) {\n            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());\n        }\n    }\n\n    /**\n     * Answer an attribute for the authenticated user.\n     *\n     * @param string $key attribute name\n     *\n     * @return mixed string for a single value or an array if multiple values exist.\n     * @warning should only be called after phpCAS::forceAuthentication()\n     * or phpCAS::checkAuthentication().\n     */\n    public static function getAttribute($key)\n    {\n        phpCAS::_validateClientExists();\n\n        try {\n            return self::$_PHPCAS_CLIENT->getAttribute($key);\n        } catch (Exception $e) {\n            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());\n        }\n    }\n\n    /**\n     * Handle logout requests.\n     *\n     * @param bool  $check_client    additional safety check\n     * @param array $allowed_clients array of allowed clients\n     *\n     * @return void\n     */\n    public static function handleLogoutRequests($check_client = true, $allowed_clients = array())\n    {\n        phpCAS::_validateClientExists();\n\n        return (self::$_PHPCAS_CLIENT->handleLogoutRequests($check_client, $allowed_clients));\n    }\n\n    /**\n     * This method returns the URL to be used to login.\n     *\n     * @return string the login URL\n     */\n    public static function getServerLoginURL()\n    {\n        phpCAS::_validateClientExists();\n\n        return self::$_PHPCAS_CLIENT->getServerLoginURL();\n    }\n\n    /**\n     * Set the login URL of the CAS server.\n     *\n     * @param string $url the login URL\n     *\n     * @return void\n     * @since 0.4.21 by Wyman Chan\n     */\n    public static function setServerLoginURL($url = '')\n    {\n        phpCAS :: traceBegin();\n        phpCAS::_validateClientExists();\n\n        try {\n            self::$_PHPCAS_CLIENT->setServerLoginURL($url);\n        } catch (Exception $e) {\n            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());\n        }\n\n        phpCAS :: traceEnd();\n    }\n\n    /**\n     * Set the serviceValidate URL of the CAS server.\n     * Used for all CAS versions of URL validations.\n     * Examples:\n     * CAS 1.0 http://www.exemple.com/validate\n     * CAS 2.0 http://www.exemple.com/validateURL\n     * CAS 3.0 http://www.exemple.com/p3/serviceValidate\n     *\n     * @param string $url the serviceValidate URL\n     *\n     * @return void\n     */\n    public static function setServerServiceValidateURL($url = '')\n    {\n        phpCAS :: traceBegin();\n        phpCAS::_validateClientExists();\n\n        try {\n            self::$_PHPCAS_CLIENT->setServerServiceValidateURL($url);\n        } catch (Exception $e) {\n            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());\n        }\n\n        phpCAS :: traceEnd();\n    }\n\n    /**\n     * Set the proxyValidate URL of the CAS server.\n     * Used for all CAS versions of proxy URL validations\n     * Examples:\n     * CAS 1.0 http://www.exemple.com/\n     * CAS 2.0 http://www.exemple.com/proxyValidate\n     * CAS 3.0 http://www.exemple.com/p3/proxyValidate\n     *\n     * @param string $url the proxyValidate URL\n     *\n     * @return void\n     */\n    public static function setServerProxyValidateURL($url = '')\n    {\n        phpCAS :: traceBegin();\n        phpCAS::_validateClientExists();\n\n        try {\n            self::$_PHPCAS_CLIENT->setServerProxyValidateURL($url);\n        } catch (Exception $e) {\n            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());\n        }\n\n        phpCAS :: traceEnd();\n    }\n\n    /**\n     * Set the samlValidate URL of the CAS server.\n     *\n     * @param string $url the samlValidate URL\n     *\n     * @return void\n     */\n    public static function setServerSamlValidateURL($url = '')\n    {\n        phpCAS :: traceBegin();\n        phpCAS::_validateClientExists();\n\n        try {\n            self::$_PHPCAS_CLIENT->setServerSamlValidateURL($url);\n        } catch (Exception $e) {\n            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());\n        }\n\n        phpCAS :: traceEnd();\n    }\n\n    /**\n     * This method returns the URL to be used to logout.\n     *\n     * @return string the URL to use to log out\n     */\n    public static function getServerLogoutURL()\n    {\n        phpCAS::_validateClientExists();\n\n        return self::$_PHPCAS_CLIENT->getServerLogoutURL();\n    }\n\n    /**\n     * Set the logout URL of the CAS server.\n     *\n     * @param string $url the logout URL\n     *\n     * @return void\n     * @since 0.4.21 by Wyman Chan\n     */\n    public static function setServerLogoutURL($url = '')\n    {\n        phpCAS :: traceBegin();\n        phpCAS::_validateClientExists();\n\n        try {\n            self::$_PHPCAS_CLIENT->setServerLogoutURL($url);\n        } catch (Exception $e) {\n            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());\n        }\n\n        phpCAS :: traceEnd();\n    }\n\n    /**\n     * This method is used to logout from CAS.\n     *\n     * @param string $params an array that contains the optional url and\n     * service parameters that will be passed to the CAS server\n     *\n     * @return void\n     */\n    public static function logout($params = \"\")\n    {\n        phpCAS :: traceBegin();\n        phpCAS::_validateClientExists();\n\n        $parsedParams = array ();\n        if ($params != \"\") {\n            if (is_string($params)) {\n                phpCAS :: error('method `phpCAS::logout($url)\\' is now deprecated, use `phpCAS::logoutWithUrl($url)\\' instead');\n            }\n            if (!is_array($params)) {\n                phpCAS :: error('type mismatched for parameter $params (should be `array\\')');\n            }\n            foreach ($params as $key => $value) {\n                if ($key != \"service\" && $key != \"url\") {\n                    phpCAS :: error('only `url\\' and `service\\' parameters are allowed for method `phpCAS::logout($params)\\'');\n                }\n                $parsedParams[$key] = $value;\n            }\n        }\n        self::$_PHPCAS_CLIENT->logout($parsedParams);\n        // never reached\n        phpCAS :: traceEnd();\n    }\n\n    /**\n     * This method is used to logout from CAS. Halts by redirecting to the CAS\n     * server.\n     *\n     * @param string $service a URL that will be transmitted to the CAS server\n     *\n     * @return void\n     */\n    public static function logoutWithRedirectService($service)\n    {\n        phpCAS :: traceBegin();\n        phpCAS::_validateClientExists();\n\n        if (!is_string($service)) {\n            phpCAS :: error('type mismatched for parameter $service (should be `string\\')');\n        }\n        self::$_PHPCAS_CLIENT->logout(array ( \"service\" => $service ));\n        // never reached\n        phpCAS :: traceEnd();\n    }\n\n    /**\n     * This method is used to logout from CAS. Halts by redirecting to the CAS\n     * server.\n     *\n     * @param string $url a URL that will be transmitted to the CAS server\n     *\n     * @return void\n     * @deprecated The url parameter has been removed from the CAS server as of\n     * version 3.3.5.1\n     */\n    public static function logoutWithUrl($url)\n    {\n        trigger_error('Function deprecated for cas servers >= 3.3.5.1', E_USER_DEPRECATED);\n        phpCAS :: traceBegin();\n        if (!is_object(self::$_PHPCAS_CLIENT)) {\n            phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()');\n        }\n        if (!is_string($url)) {\n            phpCAS :: error('type mismatched for parameter $url (should be `string\\')');\n        }\n        self::$_PHPCAS_CLIENT->logout(array ( \"url\" => $url ));\n        // never reached\n        phpCAS :: traceEnd();\n    }\n\n    /**\n     * This method is used to logout from CAS. Halts by redirecting to the CAS\n     * server.\n     *\n     * @param string $service a URL that will be transmitted to the CAS server\n     * @param string $url     a URL that will be transmitted to the CAS server\n     *\n     * @return void\n     *\n     * @deprecated The url parameter has been removed from the CAS server as of\n     * version 3.3.5.1\n     */\n    public static function logoutWithRedirectServiceAndUrl($service, $url)\n    {\n        trigger_error('Function deprecated for cas servers >= 3.3.5.1', E_USER_DEPRECATED);\n        phpCAS :: traceBegin();\n        phpCAS::_validateClientExists();\n\n        if (!is_string($service)) {\n            phpCAS :: error('type mismatched for parameter $service (should be `string\\')');\n        }\n        if (!is_string($url)) {\n            phpCAS :: error('type mismatched for parameter $url (should be `string\\')');\n        }\n        self::$_PHPCAS_CLIENT->logout(\n            array (\n                \"service\" => $service,\n                \"url\" => $url\n            )\n        );\n        // never reached\n        phpCAS :: traceEnd();\n    }\n\n    /**\n     * Set the fixed URL that will be used by the CAS server to transmit the\n     * PGT. When this method is not called, a phpCAS script uses its own URL\n     * for the callback.\n     *\n     * @param string $url the URL\n     *\n     * @return void\n     */\n    public static function setFixedCallbackURL($url = '')\n    {\n        phpCAS :: traceBegin();\n        phpCAS::_validateProxyExists();\n\n        try {\n            self::$_PHPCAS_CLIENT->setCallbackURL($url);\n        } catch (Exception $e) {\n            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());\n        }\n\n        phpCAS :: traceEnd();\n    }\n\n    /**\n     * Set the fixed URL that will be set as the CAS service parameter. When this\n     * method is not called, a phpCAS script uses its own URL.\n     *\n     * @param string $url the URL\n     *\n     * @return void\n     */\n    public static function setFixedServiceURL($url)\n    {\n        phpCAS :: traceBegin();\n        phpCAS::_validateProxyExists();\n\n        try {\n            self::$_PHPCAS_CLIENT->setURL($url);\n        } catch (Exception $e) {\n            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());\n        }\n\n        phpCAS :: traceEnd();\n    }\n\n    /**\n     * Get the URL that is set as the CAS service parameter.\n     *\n     * @return string Service Url\n     */\n    public static function getServiceURL()\n    {\n        phpCAS::_validateProxyExists();\n        return (self::$_PHPCAS_CLIENT->getURL());\n    }\n\n    /**\n     * Retrieve a Proxy Ticket from the CAS server.\n     *\n     * @param string $target_service Url string of service to proxy\n     * @param int &$err_code      error code\n     * @param string &$err_msg       error message\n     *\n     * @return string Proxy Ticket\n     */\n    public static function retrievePT($target_service, & $err_code, & $err_msg)\n    {\n        phpCAS::_validateProxyExists();\n\n        try {\n            return (self::$_PHPCAS_CLIENT->retrievePT($target_service, $err_code, $err_msg));\n        } catch (Exception $e) {\n            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());\n        }\n    }\n\n    /**\n     * Set the certificate of the CAS server CA and if the CN should be properly\n     * verified.\n     *\n     * @param string $cert        CA certificate file name\n     * @param bool   $validate_cn Validate CN in certificate (default true)\n     *\n     * @return void\n     */\n    public static function setCasServerCACert($cert, $validate_cn = true)\n    {\n        phpCAS :: traceBegin();\n        phpCAS::_validateClientExists();\n\n        try {\n            self::$_PHPCAS_CLIENT->setCasServerCACert($cert, $validate_cn);\n        } catch (Exception $e) {\n            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());\n        }\n\n        phpCAS :: traceEnd();\n    }\n\n    /**\n     * Set no SSL validation for the CAS server.\n     *\n     * @return void\n     */\n    public static function setNoCasServerValidation()\n    {\n        phpCAS :: traceBegin();\n        phpCAS::_validateClientExists();\n\n        phpCAS :: trace('You have configured no validation of the legitimacy of the cas server. This is not recommended for production use.');\n        self::$_PHPCAS_CLIENT->setNoCasServerValidation();\n        phpCAS :: traceEnd();\n    }\n\n\n    /**\n     * Disable the removal of a CAS-Ticket from the URL when authenticating\n     * DISABLING POSES A SECURITY RISK:\n     * We normally remove the ticket by an additional redirect as a security\n     * precaution to prevent a ticket in the HTTP_REFERRER or be carried over in\n     * the URL parameter\n     *\n     * @return void\n     */\n    public static function setNoClearTicketsFromUrl()\n    {\n        phpCAS :: traceBegin();\n        phpCAS::_validateClientExists();\n\n        self::$_PHPCAS_CLIENT->setNoClearTicketsFromUrl();\n        phpCAS :: traceEnd();\n    }\n\n    /** @} */\n\n    /**\n     * Change CURL options.\n     * CURL is used to connect through HTTPS to CAS server\n     *\n     * @param string $key   the option key\n     * @param string $value the value to set\n     *\n     * @return void\n     */\n    public static function setExtraCurlOption($key, $value)\n    {\n        phpCAS :: traceBegin();\n        phpCAS::_validateClientExists();\n\n        self::$_PHPCAS_CLIENT->setExtraCurlOption($key, $value);\n        phpCAS :: traceEnd();\n    }\n\n    /**\n     * Set a salt/seed for the session-id hash to make it harder to guess.\n     *\n     * When $changeSessionID = true phpCAS will create a session-id that is derived\n     * from the service ticket. Doing so allows phpCAS to look-up and destroy the\n     * proper session on single-log-out requests. While the service tickets\n     * provided by the CAS server may include enough data to generate a strong\n     * hash, clients may provide an additional salt to ensure that session ids\n     * are not guessable if the session tickets do not have enough entropy.\n     *\n     * @param string $salt The salt to combine with the session ticket.\n     *\n     * @return void\n     */\n     public static function setSessionIdSalt($salt) {\n       phpCAS :: traceBegin();\n       phpCAS::_validateClientExists();\n       self::$_PHPCAS_CLIENT->setSessionIdSalt($salt);\n       phpCAS :: traceEnd();\n     }\n\n    /**\n     * If you want your service to be proxied you have to enable it (default\n     * disabled) and define an accepable list of proxies that are allowed to\n     * proxy your service.\n     *\n     * Add each allowed proxy definition object. For the normal CAS_ProxyChain\n     * class, the constructor takes an array of proxies to match. The list is in\n     * reverse just as seen from the service. Proxies have to be defined in reverse\n     * from the service to the user. If a user hits service A and gets proxied via\n     * B to service C the list of acceptable on C would be array(B,A). The definition\n     * of an individual proxy can be either a string or a regexp (preg_match is used)\n     * that will be matched against the proxy list supplied by the cas server\n     * when validating the proxy tickets. The strings are compared starting from\n     * the beginning and must fully match with the proxies in the list.\n     * Example:\n     * \t\tphpCAS::allowProxyChain(new CAS_ProxyChain(array(\n     *\t\t\t\t'https://app.example.com/'\n     *\t\t\t)));\n     * \t\tphpCAS::allowProxyChain(new CAS_ProxyChain(array(\n     *\t\t\t\t'/^https:\\/\\/app[0-9]\\.example\\.com\\/rest\\//',\n     *\t\t\t\t'http://client.example.com/'\n     *\t\t\t)));\n     *\n     * For quick testing or in certain production screnarios you might want to\n     * allow allow any other valid service to proxy your service. To do so, add\n     * the \"Any\" chain:\n     *\t\tphpCAS::allowProxyChain(new CAS_ProxyChain_Any);\n     * THIS SETTING IS HOWEVER NOT RECOMMENDED FOR PRODUCTION AND HAS SECURITY\n     * IMPLICATIONS: YOU ARE ALLOWING ANY SERVICE TO ACT ON BEHALF OF A USER\n     * ON THIS SERVICE.\n     *\n     * @param CAS_ProxyChain_Interface $proxy_chain A proxy-chain that will be\n     * matched against the proxies requesting access\n     *\n     * @return void\n     */\n    public static function allowProxyChain(CAS_ProxyChain_Interface $proxy_chain)\n    {\n        phpCAS :: traceBegin();\n        phpCAS::_validateClientExists();\n\n        if (self::$_PHPCAS_CLIENT->getServerVersion() !== CAS_VERSION_2_0\n            && self::$_PHPCAS_CLIENT->getServerVersion() !== CAS_VERSION_3_0\n        ) {\n            phpCAS :: error('this method can only be used with the cas 2.0/3.0 protocols');\n        }\n        self::$_PHPCAS_CLIENT->getAllowedProxyChains()->allowProxyChain($proxy_chain);\n        phpCAS :: traceEnd();\n    }\n\n    /**\n     * Answer an array of proxies that are sitting in front of this application.\n     * This method will only return a non-empty array if we have received and\n     * validated a Proxy Ticket.\n     *\n     * @return array\n     * @access public\n     * @since 6/25/09\n     */\n    public static function getProxies ()\n    {\n        phpCAS::_validateProxyExists();\n\n        return(self::$_PHPCAS_CLIENT->getProxies());\n    }\n\n    // ########################################################################\n    // PGTIOU/PGTID and logoutRequest rebroadcasting\n    // ########################################################################\n\n    /**\n     * Add a pgtIou/pgtId and logoutRequest rebroadcast node.\n     *\n     * @param string $rebroadcastNodeUrl The rebroadcast node URL. Can be\n     * hostname or IP.\n     *\n     * @return void\n     */\n    public static function addRebroadcastNode($rebroadcastNodeUrl)\n    {\n        phpCAS::traceBegin();\n        phpCAS::log('rebroadcastNodeUrl:'.$rebroadcastNodeUrl);\n        phpCAS::_validateClientExists();\n\n        try {\n            self::$_PHPCAS_CLIENT->addRebroadcastNode($rebroadcastNodeUrl);\n        } catch (Exception $e) {\n            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());\n        }\n\n        phpCAS::traceEnd();\n    }\n\n    /**\n     * This method is used to add header parameters when rebroadcasting\n     * pgtIou/pgtId or logoutRequest.\n     *\n     * @param String $header Header to send when rebroadcasting.\n     *\n     * @return void\n     */\n    public static function addRebroadcastHeader($header)\n    {\n        phpCAS :: traceBegin();\n        phpCAS::_validateClientExists();\n\n        try {\n            self::$_PHPCAS_CLIENT->addRebroadcastHeader($header);\n        } catch (Exception $e) {\n            phpCAS :: error(get_class($e) . ': ' . $e->getMessage());\n        }\n\n        phpCAS :: traceEnd();\n    }\n\n    /**\n     * Checks if a client already exists\n     *\n     * @throws CAS_OutOfSequenceBeforeClientException\n     *\n     * @return void\n     */\n    private static function _validateClientExists()\n    {\n        if (!is_object(self::$_PHPCAS_CLIENT)) {\n            throw new CAS_OutOfSequenceBeforeClientException();\n        }\n    }\n\n    /**\n     * Checks of a proxy client aready exists\n     *\n     * @throws CAS_OutOfSequenceBeforeProxyException\n     *\n     * @return void\n     */\n    private static function _validateProxyExists()\n    {\n        if (!is_object(self::$_PHPCAS_CLIENT)) {\n            throw new CAS_OutOfSequenceBeforeProxyException();\n        }\n    }\n\n    /**\n     * @return CAS_Client\n     */\n    public static function getCasClient()\n    {\n        return self::$_PHPCAS_CLIENT;\n    }\n\n    /**\n     * For testing purposes, use this method to set the client to a test double\n     *\n     * @return void\n     */\n    public static function setCasClient(\\CAS_Client $client)\n    {\n        self::$_PHPCAS_CLIENT = $client;\n    }\n}\n// ########################################################################\n// DOCUMENTATION\n// ########################################################################\n\n// ########################################################################\n//  MAIN PAGE\n\n/**\n * @mainpage\n *\n * The following pages only show the source documentation.\n *\n */\n\n// ########################################################################\n//  MODULES DEFINITION\n\n/** @defgroup public User interface */\n\n/** @defgroup publicInit Initialization\n *  @ingroup public */\n\n/** @defgroup publicAuth Authentication\n *  @ingroup public */\n\n/** @defgroup publicServices Access to external services\n *  @ingroup public */\n\n/** @defgroup publicConfig Configuration\n *  @ingroup public */\n\n/** @defgroup publicLang Internationalization\n *  @ingroup publicConfig */\n\n/** @defgroup publicOutput HTML output\n *  @ingroup publicConfig */\n\n/** @defgroup publicPGTStorage PGT storage\n *  @ingroup publicConfig */\n\n/** @defgroup publicDebug Debugging\n *  @ingroup public */\n\n/** @defgroup internal Implementation */\n\n/** @defgroup internalAuthentication Authentication\n *  @ingroup internal */\n\n/** @defgroup internalBasic CAS Basic client features (CAS 1.0, Service Tickets)\n *  @ingroup internal */\n\n/** @defgroup internalProxy CAS Proxy features (CAS 2.0, Proxy Granting Tickets)\n *  @ingroup internal */\n\n/** @defgroup internalSAML CAS SAML features (SAML 1.1)\n *  @ingroup internal */\n\n/** @defgroup internalPGTStorage PGT storage\n *  @ingroup internalProxy */\n\n/** @defgroup internalPGTStorageDb PGT storage in a database\n *  @ingroup internalPGTStorage */\n\n/** @defgroup internalPGTStorageFile PGT storage on the filesystem\n *  @ingroup internalPGTStorage */\n\n/** @defgroup internalCallback Callback from the CAS server\n *  @ingroup internalProxy */\n\n/** @defgroup internalProxyServices Proxy other services\n *  @ingroup internalProxy */\n\n/** @defgroup internalService CAS client features (CAS 2.0, Proxied service)\n *  @ingroup internal */\n\n/** @defgroup internalConfig Configuration\n *  @ingroup internal */\n\n/** @defgroup internalBehave Internal behaviour of phpCAS\n *  @ingroup internalConfig */\n\n/** @defgroup internalOutput HTML output\n *  @ingroup internalConfig */\n\n/** @defgroup internalLang Internationalization\n *  @ingroup internalConfig\n *\n * To add a new language:\n * - 1. define a new constant PHPCAS_LANG_XXXXXX in CAS/CAS.php\n * - 2. copy any file from CAS/languages to CAS/languages/XXXXXX.php\n * - 3. Make the translations\n */\n\n/** @defgroup internalDebug Debugging\n *  @ingroup internal */\n\n/** @defgroup internalMisc Miscellaneous\n *  @ingroup internal */\n\n// ########################################################################\n//  EXAMPLES\n\n/**\n * @example example_simple.php\n */\n/**\n * @example example_service.php\n */\n/**\n * @example example_service_that_proxies.php\n */\n/**\n * @example example_service_POST.php\n */\n/**\n * @example example_proxy_serviceWeb.php\n */\n/**\n * @example example_proxy_serviceWeb_chaining.php\n */\n/**\n * @example example_proxy_POST.php\n */\n/**\n * @example example_proxy_GET.php\n */\n/**\n * @example example_lang.php\n */\n/**\n * @example example_html.php\n */\n/**\n * @example example_pgt_storage_file.php\n */\n/**\n * @example example_pgt_storage_db.php\n */\n/**\n * @example example_gateway.php\n */\n/**\n * @example example_logout.php\n */\n/**\n * @example example_rebroadcast.php\n */\n/**\n * @example example_custom_urls.php\n */\n/**\n * @example example_advanced_saml11.php\n */\n"
  },
  {
    "path": "server/vendor/laravel/serializable-closure/LICENSE.md",
    "content": "The MIT License (MIT)\n\nCopyright (c) Taylor Otwell\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "server/vendor/laravel/serializable-closure/README.md",
    "content": "# Serializable Closure\n\n<a href=\"https://github.com/laravel/serializable-closure/actions\">\n    <img src=\"https://github.com/laravel/serializable-closure/workflows/tests/badge.svg\" alt=\"Build Status\">\n</a>\n<a href=\"https://packagist.org/packages/laravel/serializable-closure\">\n    <img src=\"https://img.shields.io/packagist/dt/laravel/serializable-closure\" alt=\"Total Downloads\">\n</a>\n<a href=\"https://packagist.org/packages/laravel/serializable-closure\">\n    <img src=\"https://img.shields.io/packagist/v/laravel/serializable-closure\" alt=\"Latest Stable Version\">\n</a>\n<a href=\"https://packagist.org/packages/laravel/serializable-closure\">\n    <img src=\"https://img.shields.io/packagist/l/laravel/serializable-closure\" alt=\"License\">\n</a>\n\n## Introduction\n\n> This project is a fork of the excellent [opis/closure: 3.x](https://github.com/opis/closure) package. At Laravel, we decided to fork this package as the upcoming version [4.x](https://github.com/opis/closure) is a complete rewrite on top of the [FFI extension](https://www.php.net/manual/en/book.ffi.php). As Laravel is a web framework, and FFI is not enabled by default in web requests, this fork allows us to keep using the `3.x` series while adding support for new PHP versions.\n\nLaravel Serializable Closure provides an easy and secure way to **serialize closures in PHP**.\n\n## Official Documentation\n\n### Installation\n\n> **Requires [PHP 7.4+](https://php.net/releases/)**\n\nFirst, install Laravel Serializable Closure via the [Composer](https://getcomposer.org/) package manager:\n\n```bash\ncomposer require laravel/serializable-closure\n```\n\n### Usage\n\nYou may serialize a closure this way:\n\n```php\nuse Laravel\\SerializableClosure\\SerializableClosure;\n\n$closure = fn () => 'james';\n\n// Recommended\nSerializableClosure::setSecretKey('secret');\n\n$serialized = serialize(new SerializableClosure($closure));\n$closure = unserialize($serialized)->getClosure();\n\necho $closure(); // james;\n```\n\n### Caveats\n\n* Anonymous classes cannot be created within closures.\n* Attributes cannot be used within closures.\n* Serializing closures on REPL environments like Laravel Tinker is not supported.\n* Serializing closures that reference objects with readonly properties is not supported.\n\n## Contributing\n\nThank you for considering contributing to Serializable Closure! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions).\n\n## Code of Conduct\n\nIn order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct).\n\n## Security Vulnerabilities\n\nPlease review [our security policy](https://github.com/laravel/serializable-closure/security/policy) on how to report security vulnerabilities.\n\n## License\n\nSerializable Closure is open-sourced software licensed under the [MIT license](LICENSE.md).\n"
  },
  {
    "path": "server/vendor/laravel/serializable-closure/composer.json",
    "content": "{\n    \"name\": \"laravel/serializable-closure\",\n    \"description\": \"Laravel Serializable Closure provides an easy and secure way to serialize closures in PHP.\",\n    \"keywords\": [\"laravel\", \"Serializable\", \"closure\"],\n    \"license\": \"MIT\",\n    \"support\": {\n        \"issues\": \"https://github.com/laravel/serializable-closure/issues\",\n        \"source\": \"https://github.com/laravel/serializable-closure\"\n    },\n    \"authors\": [\n        {\n            \"name\": \"Taylor Otwell\",\n            \"email\": \"taylor@laravel.com\"\n        },\n        {\n            \"name\": \"Nuno Maduro\",\n            \"email\": \"nuno@laravel.com\"\n        }\n    ],\n    \"require\": {\n        \"php\": \"^7.3|^8.0\"\n    },\n    \"require-dev\": {\n        \"illuminate/support\": \"^8.0|^9.0|^10.0|^11.0\",\n        \"nesbot/carbon\": \"^2.61|^3.0\",\n        \"pestphp/pest\": \"^1.21.3\",\n        \"phpstan/phpstan\": \"^1.8.2\",\n        \"symfony/var-dumper\": \"^5.4.11|^6.2.0|^7.0.0\"\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"Laravel\\\\SerializableClosure\\\\\": \"src/\"\n        }\n    },\n    \"autoload-dev\": {\n        \"psr-4\": {\n            \"Tests\\\\\": \"tests/\"\n        }\n    },\n    \"extra\": {\n        \"branch-alias\": {\n            \"dev-master\": \"1.x-dev\"\n        }\n    },\n    \"config\": {\n        \"sort-packages\": true,\n        \"allow-plugins\": {\n            \"pestphp/pest-plugin\": true\n        }\n    },\n    \"minimum-stability\": \"dev\",\n    \"prefer-stable\": true\n}\n"
  },
  {
    "path": "server/vendor/laravel/serializable-closure/src/Contracts/Serializable.php",
    "content": "<?php\n\nnamespace Laravel\\SerializableClosure\\Contracts;\n\ninterface Serializable\n{\n    /**\n     * Resolve the closure with the given arguments.\n     *\n     * @return mixed\n     */\n    public function __invoke();\n\n    /**\n     * Gets the closure that got serialized/unserialized.\n     *\n     * @return \\Closure\n     */\n    public function getClosure();\n}\n"
  },
  {
    "path": "server/vendor/laravel/serializable-closure/src/Contracts/Signer.php",
    "content": "<?php\n\nnamespace Laravel\\SerializableClosure\\Contracts;\n\ninterface Signer\n{\n    /**\n     * Sign the given serializable.\n     *\n     * @param  string  $serializable\n     * @return array\n     */\n    public function sign($serializable);\n\n    /**\n     * Verify the given signature.\n     *\n     * @param  array  $signature\n     * @return bool\n     */\n    public function verify($signature);\n}\n"
  },
  {
    "path": "server/vendor/laravel/serializable-closure/src/Exceptions/InvalidSignatureException.php",
    "content": "<?php\n\nnamespace Laravel\\SerializableClosure\\Exceptions;\n\nuse Exception;\n\nclass InvalidSignatureException extends Exception\n{\n    /**\n     * Create a new exception instance.\n     *\n     * @param  string  $message\n     * @return void\n     */\n    public function __construct($message = 'Your serialized closure might have been modified or it\\'s unsafe to be unserialized.')\n    {\n        parent::__construct($message);\n    }\n}\n"
  },
  {
    "path": "server/vendor/laravel/serializable-closure/src/Exceptions/MissingSecretKeyException.php",
    "content": "<?php\n\nnamespace Laravel\\SerializableClosure\\Exceptions;\n\nuse Exception;\n\nclass MissingSecretKeyException extends Exception\n{\n    /**\n     * Create a new exception instance.\n     *\n     * @param  string  $message\n     * @return void\n     */\n    public function __construct($message = 'No serializable closure secret key has been specified.')\n    {\n        parent::__construct($message);\n    }\n}\n"
  },
  {
    "path": "server/vendor/laravel/serializable-closure/src/Exceptions/PhpVersionNotSupportedException.php",
    "content": "<?php\n\nnamespace Laravel\\SerializableClosure\\Exceptions;\n\nuse Exception;\n\nclass PhpVersionNotSupportedException extends Exception\n{\n    /**\n     * Create a new exception instance.\n     *\n     * @param  string  $message\n     * @return void\n     */\n    public function __construct($message = 'PHP 7.3 is not supported.')\n    {\n        parent::__construct($message);\n    }\n}\n"
  },
  {
    "path": "server/vendor/laravel/serializable-closure/src/SerializableClosure.php",
    "content": "<?php\n\nnamespace Laravel\\SerializableClosure;\n\nuse Closure;\nuse Laravel\\SerializableClosure\\Exceptions\\InvalidSignatureException;\nuse Laravel\\SerializableClosure\\Exceptions\\PhpVersionNotSupportedException;\nuse Laravel\\SerializableClosure\\Serializers\\Signed;\nuse Laravel\\SerializableClosure\\Signers\\Hmac;\n\nclass SerializableClosure\n{\n    /**\n     * The closure's serializable.\n     *\n     * @var \\Laravel\\SerializableClosure\\Contracts\\Serializable\n     */\n    protected $serializable;\n\n    /**\n     * Creates a new serializable closure instance.\n     *\n     * @param  \\Closure  $closure\n     * @return void\n     */\n    public function __construct(Closure $closure)\n    {\n        if (\\PHP_VERSION_ID < 70400) {\n            throw new PhpVersionNotSupportedException();\n        }\n\n        $this->serializable = Serializers\\Signed::$signer\n            ? new Serializers\\Signed($closure)\n            : new Serializers\\Native($closure);\n    }\n\n    /**\n     * Resolve the closure with the given arguments.\n     *\n     * @return mixed\n     */\n    public function __invoke()\n    {\n        if (\\PHP_VERSION_ID < 70400) {\n            throw new PhpVersionNotSupportedException();\n        }\n\n        return call_user_func_array($this->serializable, func_get_args());\n    }\n\n    /**\n     * Gets the closure.\n     *\n     * @return \\Closure\n     */\n    public function getClosure()\n    {\n        if (\\PHP_VERSION_ID < 70400) {\n            throw new PhpVersionNotSupportedException();\n        }\n\n        return $this->serializable->getClosure();\n    }\n\n    /**\n     * Create a new unsigned serializable closure instance.\n     *\n     * @param  Closure  $closure\n     * @return \\Laravel\\SerializableClosure\\UnsignedSerializableClosure\n     */\n    public static function unsigned(Closure $closure)\n    {\n        return new UnsignedSerializableClosure($closure);\n    }\n\n    /**\n     * Sets the serializable closure secret key.\n     *\n     * @param  string|null  $secret\n     * @return void\n     */\n    public static function setSecretKey($secret)\n    {\n        Serializers\\Signed::$signer = $secret\n            ? new Hmac($secret)\n            : null;\n    }\n\n    /**\n     * Sets the serializable closure secret key.\n     *\n     * @param  \\Closure|null  $transformer\n     * @return void\n     */\n    public static function transformUseVariablesUsing($transformer)\n    {\n        Serializers\\Native::$transformUseVariables = $transformer;\n    }\n\n    /**\n     * Sets the serializable closure secret key.\n     *\n     * @param  \\Closure|null  $resolver\n     * @return void\n     */\n    public static function resolveUseVariablesUsing($resolver)\n    {\n        Serializers\\Native::$resolveUseVariables = $resolver;\n    }\n\n    /**\n     * Get the serializable representation of the closure.\n     *\n     * @return array\n     */\n    public function __serialize()\n    {\n        return [\n            'serializable' => $this->serializable,\n        ];\n    }\n\n    /**\n     * Restore the closure after serialization.\n     *\n     * @param  array  $data\n     * @return void\n     *\n     * @throws \\Laravel\\SerializableClosure\\Exceptions\\InvalidSignatureException\n     */\n    public function __unserialize($data)\n    {\n        if (Signed::$signer && ! $data['serializable'] instanceof Signed) {\n            throw new InvalidSignatureException();\n        }\n\n        $this->serializable = $data['serializable'];\n    }\n}\n"
  },
  {
    "path": "server/vendor/laravel/serializable-closure/src/Serializers/Native.php",
    "content": "<?php\n\nnamespace Laravel\\SerializableClosure\\Serializers;\n\nuse Closure;\nuse DateTimeInterface;\nuse Laravel\\SerializableClosure\\Contracts\\Serializable;\nuse Laravel\\SerializableClosure\\SerializableClosure;\nuse Laravel\\SerializableClosure\\Support\\ClosureScope;\nuse Laravel\\SerializableClosure\\Support\\ClosureStream;\nuse Laravel\\SerializableClosure\\Support\\ReflectionClosure;\nuse Laravel\\SerializableClosure\\Support\\SelfReference;\nuse Laravel\\SerializableClosure\\UnsignedSerializableClosure;\nuse ReflectionObject;\nuse UnitEnum;\n\nclass Native implements Serializable\n{\n    /**\n     * Transform the use variables before serialization.\n     *\n     * @var \\Closure|null\n     */\n    public static $transformUseVariables;\n\n    /**\n     * Resolve the use variables after unserialization.\n     *\n     * @var \\Closure|null\n     */\n    public static $resolveUseVariables;\n\n    /**\n     * The closure to be serialized/unserialized.\n     *\n     * @var \\Closure\n     */\n    protected $closure;\n\n    /**\n     * The closure's reflection.\n     *\n     * @var \\Laravel\\SerializableClosure\\Support\\ReflectionClosure|null\n     */\n    protected $reflector;\n\n    /**\n     * The closure's code.\n     *\n     * @var array|null\n     */\n    protected $code;\n\n    /**\n     * The closure's reference.\n     *\n     * @var string\n     */\n    protected $reference;\n\n    /**\n     * The closure's scope.\n     *\n     * @var \\Laravel\\SerializableClosure\\Support\\ClosureScope|null\n     */\n    protected $scope;\n\n    /**\n     * The \"key\" that marks an array as recursive.\n     */\n    const ARRAY_RECURSIVE_KEY = 'LARAVEL_SERIALIZABLE_RECURSIVE_KEY';\n\n    /**\n     * Creates a new serializable closure instance.\n     *\n     * @param  \\Closure  $closure\n     * @return void\n     */\n    public function __construct(Closure $closure)\n    {\n        $this->closure = $closure;\n    }\n\n    /**\n     * Resolve the closure with the given arguments.\n     *\n     * @return mixed\n     */\n    public function __invoke()\n    {\n        return call_user_func_array($this->closure, func_get_args());\n    }\n\n    /**\n     * Gets the closure.\n     *\n     * @return \\Closure\n     */\n    public function getClosure()\n    {\n        return $this->closure;\n    }\n\n    /**\n     * Get the serializable representation of the closure.\n     *\n     * @return array\n     */\n    public function __serialize()\n    {\n        if ($this->scope === null) {\n            $this->scope = new ClosureScope();\n            $this->scope->toSerialize++;\n        }\n\n        $this->scope->serializations++;\n\n        $scope = $object = null;\n        $reflector = $this->getReflector();\n\n        if ($reflector->isBindingRequired()) {\n            $object = $reflector->getClosureThis();\n\n            static::wrapClosures($object, $this->scope);\n        }\n\n        if ($scope = $reflector->getClosureScopeClass()) {\n            $scope = $scope->name;\n        }\n\n        $this->reference = spl_object_hash($this->closure);\n\n        $this->scope[$this->closure] = $this;\n\n        $use = $reflector->getUseVariables();\n\n        if (static::$transformUseVariables) {\n            $use = call_user_func(static::$transformUseVariables, $reflector->getUseVariables());\n        }\n\n        $code = $reflector->getCode();\n\n        $this->mapByReference($use);\n\n        $data = [\n            'use' => $use,\n            'function' => $code,\n            'scope' => $scope,\n            'this' => $object,\n            'self' => $this->reference,\n        ];\n\n        if (! --$this->scope->serializations && ! --$this->scope->toSerialize) {\n            $this->scope = null;\n        }\n\n        return $data;\n    }\n\n    /**\n     * Restore the closure after serialization.\n     *\n     * @param  array  $data\n     * @return void\n     */\n    public function __unserialize($data)\n    {\n        ClosureStream::register();\n\n        $this->code = $data;\n        unset($data);\n\n        $this->code['objects'] = [];\n\n        if ($this->code['use']) {\n            $this->scope = new ClosureScope();\n\n            if (static::$resolveUseVariables) {\n                $this->code['use'] = call_user_func(static::$resolveUseVariables, $this->code['use']);\n            }\n\n            $this->mapPointers($this->code['use']);\n\n            extract($this->code['use'], EXTR_OVERWRITE | EXTR_REFS);\n\n            $this->scope = null;\n        }\n\n        $this->closure = include ClosureStream::STREAM_PROTO.'://'.$this->code['function'];\n\n        if ($this->code['this'] === $this) {\n            $this->code['this'] = null;\n        }\n\n        $this->closure = $this->closure->bindTo($this->code['this'], $this->code['scope']);\n\n        if (! empty($this->code['objects'])) {\n            foreach ($this->code['objects'] as $item) {\n                $item['property']->setValue($item['instance'], $item['object']->getClosure());\n            }\n        }\n\n        $this->code = $this->code['function'];\n    }\n\n    /**\n     * Ensures the given closures are serializable.\n     *\n     * @param  mixed  $data\n     * @param  \\Laravel\\SerializableClosure\\Support\\ClosureScope  $storage\n     * @return void\n     */\n    public static function wrapClosures(&$data, $storage)\n    {\n        if ($data instanceof Closure) {\n            $data = new static($data);\n        } elseif (is_array($data)) {\n            if (isset($data[self::ARRAY_RECURSIVE_KEY])) {\n                return;\n            }\n\n            $data[self::ARRAY_RECURSIVE_KEY] = true;\n\n            foreach ($data as $key => &$value) {\n                if ($key === self::ARRAY_RECURSIVE_KEY) {\n                    continue;\n                }\n                static::wrapClosures($value, $storage);\n            }\n\n            unset($value);\n            unset($data[self::ARRAY_RECURSIVE_KEY]);\n        } elseif ($data instanceof \\stdClass) {\n            if (isset($storage[$data])) {\n                $data = $storage[$data];\n\n                return;\n            }\n\n            $data = $storage[$data] = clone $data;\n\n            foreach ($data as &$value) {\n                static::wrapClosures($value, $storage);\n            }\n\n            unset($value);\n        } elseif (is_object($data) && ! $data instanceof static && ! $data instanceof UnitEnum) {\n            if (isset($storage[$data])) {\n                $data = $storage[$data];\n\n                return;\n            }\n\n            $instance = $data;\n            $reflection = new ReflectionObject($instance);\n\n            if (! $reflection->isUserDefined()) {\n                $storage[$instance] = $data;\n\n                return;\n            }\n\n            $storage[$instance] = $data = $reflection->newInstanceWithoutConstructor();\n\n            do {\n                if (! $reflection->isUserDefined()) {\n                    break;\n                }\n\n                foreach ($reflection->getProperties() as $property) {\n                    if ($property->isStatic() || ! $property->getDeclaringClass()->isUserDefined()) {\n                        continue;\n                    }\n\n                    $property->setAccessible(true);\n\n                    if (PHP_VERSION >= 7.4 && ! $property->isInitialized($instance)) {\n                        continue;\n                    }\n\n                    $value = $property->getValue($instance);\n\n                    if (is_array($value) || is_object($value)) {\n                        static::wrapClosures($value, $storage);\n                    }\n\n                    $property->setValue($data, $value);\n                }\n            } while ($reflection = $reflection->getParentClass());\n        }\n    }\n\n    /**\n     * Gets the closure's reflector.\n     *\n     * @return \\Laravel\\SerializableClosure\\Support\\ReflectionClosure\n     */\n    public function getReflector()\n    {\n        if ($this->reflector === null) {\n            $this->code = null;\n            $this->reflector = new ReflectionClosure($this->closure);\n        }\n\n        return $this->reflector;\n    }\n\n    /**\n     * Internal method used to map closure pointers.\n     *\n     * @param  mixed  $data\n     * @return void\n     */\n    protected function mapPointers(&$data)\n    {\n        $scope = $this->scope;\n\n        if ($data instanceof static) {\n            $data = &$data->closure;\n        } elseif (is_array($data)) {\n            if (isset($data[self::ARRAY_RECURSIVE_KEY])) {\n                return;\n            }\n\n            $data[self::ARRAY_RECURSIVE_KEY] = true;\n\n            foreach ($data as $key => &$value) {\n                if ($key === self::ARRAY_RECURSIVE_KEY) {\n                    continue;\n                } elseif ($value instanceof static) {\n                    $data[$key] = &$value->closure;\n                } elseif ($value instanceof SelfReference && $value->hash === $this->code['self']) {\n                    $data[$key] = &$this->closure;\n                } else {\n                    $this->mapPointers($value);\n                }\n            }\n\n            unset($value);\n            unset($data[self::ARRAY_RECURSIVE_KEY]);\n        } elseif ($data instanceof \\stdClass) {\n            if (isset($scope[$data])) {\n                return;\n            }\n\n            $scope[$data] = true;\n\n            foreach ($data as $key => &$value) {\n                if ($value instanceof SelfReference && $value->hash === $this->code['self']) {\n                    $data->{$key} = &$this->closure;\n                } elseif (is_array($value) || is_object($value)) {\n                    $this->mapPointers($value);\n                }\n            }\n\n            unset($value);\n        } elseif (is_object($data) && ! ($data instanceof Closure)) {\n            if (isset($scope[$data])) {\n                return;\n            }\n\n            $scope[$data] = true;\n            $reflection = new ReflectionObject($data);\n\n            do {\n                if (! $reflection->isUserDefined()) {\n                    break;\n                }\n\n                foreach ($reflection->getProperties() as $property) {\n                    if ($property->isStatic() || ! $property->getDeclaringClass()->isUserDefined()) {\n                        continue;\n                    }\n\n                    $property->setAccessible(true);\n\n                    if (PHP_VERSION >= 7.4 && ! $property->isInitialized($data)) {\n                        continue;\n                    }\n\n                    if (PHP_VERSION >= 8.1 && $property->isReadOnly()) {\n                        continue;\n                    }\n\n                    $item = $property->getValue($data);\n\n                    if ($item instanceof SerializableClosure || $item instanceof UnsignedSerializableClosure || ($item instanceof SelfReference && $item->hash === $this->code['self'])) {\n                        $this->code['objects'][] = [\n                            'instance' => $data,\n                            'property' => $property,\n                            'object' => $item instanceof SelfReference ? $this : $item,\n                        ];\n                    } elseif (is_array($item) || is_object($item)) {\n                        $this->mapPointers($item);\n                        $property->setValue($data, $item);\n                    }\n                }\n            } while ($reflection = $reflection->getParentClass());\n        }\n    }\n\n    /**\n     * Internal method used to map closures by reference.\n     *\n     * @param  mixed  $data\n     * @return void\n     */\n    protected function mapByReference(&$data)\n    {\n        if ($data instanceof Closure) {\n            if ($data === $this->closure) {\n                $data = new SelfReference($this->reference);\n\n                return;\n            }\n\n            if (isset($this->scope[$data])) {\n                $data = $this->scope[$data];\n\n                return;\n            }\n\n            $instance = new static($data);\n\n            $instance->scope = $this->scope;\n\n            $data = $this->scope[$data] = $instance;\n        } elseif (is_array($data)) {\n            if (isset($data[self::ARRAY_RECURSIVE_KEY])) {\n                return;\n            }\n\n            $data[self::ARRAY_RECURSIVE_KEY] = true;\n\n            foreach ($data as $key => &$value) {\n                if ($key === self::ARRAY_RECURSIVE_KEY) {\n                    continue;\n                }\n\n                $this->mapByReference($value);\n            }\n\n            unset($value);\n            unset($data[self::ARRAY_RECURSIVE_KEY]);\n        } elseif ($data instanceof \\stdClass) {\n            if (isset($this->scope[$data])) {\n                $data = $this->scope[$data];\n\n                return;\n            }\n\n            $instance = $data;\n            $this->scope[$instance] = $data = clone $data;\n\n            foreach ($data as &$value) {\n                $this->mapByReference($value);\n            }\n\n            unset($value);\n        } elseif (is_object($data) && ! $data instanceof SerializableClosure && ! $data instanceof UnsignedSerializableClosure) {\n            if (isset($this->scope[$data])) {\n                $data = $this->scope[$data];\n\n                return;\n            }\n\n            $instance = $data;\n\n            if ($data instanceof DateTimeInterface) {\n                $this->scope[$instance] = $data;\n\n                return;\n            }\n\n            if ($data instanceof UnitEnum) {\n                $this->scope[$instance] = $data;\n\n                return;\n            }\n\n            $reflection = new ReflectionObject($data);\n\n            if (! $reflection->isUserDefined()) {\n                $this->scope[$instance] = $data;\n\n                return;\n            }\n\n            $this->scope[$instance] = $data = $reflection->newInstanceWithoutConstructor();\n\n            do {\n                if (! $reflection->isUserDefined()) {\n                    break;\n                }\n\n                foreach ($reflection->getProperties() as $property) {\n                    if ($property->isStatic() || ! $property->getDeclaringClass()->isUserDefined()) {\n                        continue;\n                    }\n\n                    $property->setAccessible(true);\n\n                    if (PHP_VERSION >= 7.4 && ! $property->isInitialized($instance)) {\n                        continue;\n                    }\n\n                    if (PHP_VERSION >= 8.1 && $property->isReadOnly() && $property->class !== $reflection->name) {\n                        continue;\n                    }\n\n                    $value = $property->getValue($instance);\n\n                    if (is_array($value) || is_object($value)) {\n                        $this->mapByReference($value);\n                    }\n\n                    $property->setValue($data, $value);\n                }\n            } while ($reflection = $reflection->getParentClass());\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/laravel/serializable-closure/src/Serializers/Signed.php",
    "content": "<?php\n\nnamespace Laravel\\SerializableClosure\\Serializers;\n\nuse Laravel\\SerializableClosure\\Contracts\\Serializable;\nuse Laravel\\SerializableClosure\\Exceptions\\InvalidSignatureException;\nuse Laravel\\SerializableClosure\\Exceptions\\MissingSecretKeyException;\n\nclass Signed implements Serializable\n{\n    /**\n     * The signer that will sign and verify the closure's signature.\n     *\n     * @var \\Laravel\\SerializableClosure\\Contracts\\Signer|null\n     */\n    public static $signer;\n\n    /**\n     * The closure to be serialized/unserialized.\n     *\n     * @var \\Closure\n     */\n    protected $closure;\n\n    /**\n     * Creates a new serializable closure instance.\n     *\n     * @param  \\Closure  $closure\n     * @return void\n     */\n    public function __construct($closure)\n    {\n        $this->closure = $closure;\n    }\n\n    /**\n     * Resolve the closure with the given arguments.\n     *\n     * @return mixed\n     */\n    public function __invoke()\n    {\n        return call_user_func_array($this->closure, func_get_args());\n    }\n\n    /**\n     * Gets the closure.\n     *\n     * @return \\Closure\n     */\n    public function getClosure()\n    {\n        return $this->closure;\n    }\n\n    /**\n     * Get the serializable representation of the closure.\n     *\n     * @return array\n     */\n    public function __serialize()\n    {\n        if (! static::$signer) {\n            throw new MissingSecretKeyException();\n        }\n\n        return static::$signer->sign(\n            serialize(new Native($this->closure))\n        );\n    }\n\n    /**\n     * Restore the closure after serialization.\n     *\n     * @param  array  $signature\n     * @return void\n     *\n     * @throws \\Laravel\\SerializableClosure\\Exceptions\\InvalidSignatureException\n     */\n    public function __unserialize($signature)\n    {\n        if (static::$signer && ! static::$signer->verify($signature)) {\n            throw new InvalidSignatureException();\n        }\n\n        /** @var \\Laravel\\SerializableClosure\\Contracts\\Serializable $serializable */\n        $serializable = unserialize($signature['serializable']);\n\n        $this->closure = $serializable->getClosure();\n    }\n}\n"
  },
  {
    "path": "server/vendor/laravel/serializable-closure/src/Signers/Hmac.php",
    "content": "<?php\n\nnamespace Laravel\\SerializableClosure\\Signers;\n\nuse Laravel\\SerializableClosure\\Contracts\\Signer;\n\nclass Hmac implements Signer\n{\n    /**\n     * The secret key.\n     *\n     * @var string\n     */\n    protected $secret;\n\n    /**\n     * Creates a new signer instance.\n     *\n     * @param  string  $secret\n     * @return void\n     */\n    public function __construct($secret)\n    {\n        $this->secret = $secret;\n    }\n\n    /**\n     * Sign the given serializable.\n     *\n     * @param  string  $serialized\n     * @return array\n     */\n    public function sign($serialized)\n    {\n        return [\n            'serializable' => $serialized,\n            'hash' => base64_encode(hash_hmac('sha256', $serialized, $this->secret, true)),\n        ];\n    }\n\n    /**\n     * Verify the given signature.\n     *\n     * @param  array  $signature\n     * @return bool\n     */\n    public function verify($signature)\n    {\n        return hash_equals(base64_encode(\n            hash_hmac('sha256', $signature['serializable'], $this->secret, true)\n        ), $signature['hash']);\n    }\n}\n"
  },
  {
    "path": "server/vendor/laravel/serializable-closure/src/Support/ClosureScope.php",
    "content": "<?php\n\nnamespace Laravel\\SerializableClosure\\Support;\n\nuse SplObjectStorage;\n\nclass ClosureScope extends SplObjectStorage\n{\n    /**\n     * The number of serializations in current scope.\n     *\n     * @var int\n     */\n    public $serializations = 0;\n\n    /**\n     * The number of closures that have to be serialized.\n     *\n     * @var int\n     */\n    public $toSerialize = 0;\n}\n"
  },
  {
    "path": "server/vendor/laravel/serializable-closure/src/Support/ClosureStream.php",
    "content": "<?php\n\nnamespace Laravel\\SerializableClosure\\Support;\n\n#[\\AllowDynamicProperties]\nclass ClosureStream\n{\n    /**\n     * The stream protocol.\n     */\n    const STREAM_PROTO = 'laravel-serializable-closure';\n\n    /**\n     * Checks if this stream is registered.\n     *\n     * @var bool\n     */\n    protected static $isRegistered = false;\n\n    /**\n     * The stream content.\n     *\n     * @var string\n     */\n    protected $content;\n\n    /**\n     * The stream content.\n     *\n     * @var int\n     */\n    protected $length;\n\n    /**\n     * The stream pointer.\n     *\n     * @var int\n     */\n    protected $pointer = 0;\n\n    /**\n     * Opens file or URL.\n     *\n     * @param  string  $path\n     * @param  string  $mode\n     * @param  string  $options\n     * @param  string|null  $opened_path\n     * @return bool\n     */\n    public function stream_open($path, $mode, $options, &$opened_path)\n    {\n        $this->content = \"<?php\\nreturn \".substr($path, strlen(static::STREAM_PROTO.'://')).';';\n        $this->length = strlen($this->content);\n\n        return true;\n    }\n\n    /**\n     * Read from stream.\n     *\n     * @param  int  $count\n     * @return string\n     */\n    public function stream_read($count)\n    {\n        $value = substr($this->content, $this->pointer, $count);\n\n        $this->pointer += $count;\n\n        return $value;\n    }\n\n    /**\n     * Tests for end-of-file on a file pointer.\n     *\n     * @return bool\n     */\n    public function stream_eof()\n    {\n        return $this->pointer >= $this->length;\n    }\n\n    /**\n     * Change stream options.\n     *\n     * @param  int  $option\n     * @param  int  $arg1\n     * @param  int  $arg2\n     * @return bool\n     */\n    public function stream_set_option($option, $arg1, $arg2)\n    {\n        return false;\n    }\n\n    /**\n     * Retrieve information about a file resource.\n     *\n     * @return array|bool\n     */\n    public function stream_stat()\n    {\n        $stat = stat(__FILE__);\n        // @phpstan-ignore-next-line\n        $stat[7] = $stat['size'] = $this->length;\n\n        return $stat;\n    }\n\n    /**\n     * Retrieve information about a file.\n     *\n     * @param  string  $path\n     * @param  int  $flags\n     * @return array|bool\n     */\n    public function url_stat($path, $flags)\n    {\n        $stat = stat(__FILE__);\n        // @phpstan-ignore-next-line\n        $stat[7] = $stat['size'] = $this->length;\n\n        return $stat;\n    }\n\n    /**\n     * Seeks to specific location in a stream.\n     *\n     * @param  int  $offset\n     * @param  int  $whence\n     * @return bool\n     */\n    public function stream_seek($offset, $whence = SEEK_SET)\n    {\n        $crt = $this->pointer;\n\n        switch ($whence) {\n            case SEEK_SET:\n                $this->pointer = $offset;\n                break;\n            case SEEK_CUR:\n                $this->pointer += $offset;\n                break;\n            case SEEK_END:\n                $this->pointer = $this->length + $offset;\n                break;\n        }\n\n        if ($this->pointer < 0 || $this->pointer >= $this->length) {\n            $this->pointer = $crt;\n\n            return false;\n        }\n\n        return true;\n    }\n\n    /**\n     * Retrieve the current position of a stream.\n     *\n     * @return int\n     */\n    public function stream_tell()\n    {\n        return $this->pointer;\n    }\n\n    /**\n     * Registers the stream.\n     *\n     * @return void\n     */\n    public static function register()\n    {\n        if (! static::$isRegistered) {\n            static::$isRegistered = stream_wrapper_register(static::STREAM_PROTO, __CLASS__);\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/laravel/serializable-closure/src/Support/ReflectionClosure.php",
    "content": "<?php\n\nnamespace Laravel\\SerializableClosure\\Support;\n\ndefined('T_NAME_QUALIFIED') || define('T_NAME_QUALIFIED', -4);\ndefined('T_NAME_FULLY_QUALIFIED') || define('T_NAME_FULLY_QUALIFIED', -5);\ndefined('T_FN') || define('T_FN', -6);\ndefined('T_NULLSAFE_OBJECT_OPERATOR') || define('T_NULLSAFE_OBJECT_OPERATOR', -7);\n\nuse Closure;\nuse ReflectionFunction;\n\nclass ReflectionClosure extends ReflectionFunction\n{\n    protected $code;\n    protected $tokens;\n    protected $hashedName;\n    protected $useVariables;\n    protected $isStaticClosure;\n    protected $isScopeRequired;\n    protected $isBindingRequired;\n    protected $isShortClosure;\n\n    protected static $files = [];\n    protected static $classes = [];\n    protected static $functions = [];\n    protected static $constants = [];\n    protected static $structures = [];\n\n    /**\n     * Creates a new reflection closure instance.\n     *\n     * @param  \\Closure  $closure\n     * @param  string|null  $code\n     * @return void\n     */\n    public function __construct(Closure $closure, $code = null)\n    {\n        parent::__construct($closure);\n    }\n\n    /**\n     * Checks if the closure is \"static\".\n     *\n     * @return bool\n     */\n    public function isStatic(): bool\n    {\n        if ($this->isStaticClosure === null) {\n            $this->isStaticClosure = strtolower(substr($this->getCode(), 0, 6)) === 'static';\n        }\n\n        return $this->isStaticClosure;\n    }\n\n    /**\n     * Checks if the closure is a \"short closure\".\n     *\n     * @return bool\n     */\n    public function isShortClosure()\n    {\n        if ($this->isShortClosure === null) {\n            $code = $this->getCode();\n\n            if ($this->isStatic()) {\n                $code = substr($code, 6);\n            }\n\n            $this->isShortClosure = strtolower(substr(trim($code), 0, 2)) === 'fn';\n        }\n\n        return $this->isShortClosure;\n    }\n\n    /**\n     * Get the closure's code.\n     *\n     * @return string\n     */\n    public function getCode()\n    {\n        if ($this->code !== null) {\n            return $this->code;\n        }\n\n        $fileName = $this->getFileName();\n        $line = $this->getStartLine() - 1;\n\n        $className = null;\n\n        if (null !== $className = $this->getClosureScopeClass()) {\n            $className = '\\\\'.trim($className->getName(), '\\\\');\n        }\n\n        $builtin_types = self::getBuiltinTypes();\n        $class_keywords = ['self', 'static', 'parent'];\n\n        $ns = $this->getClosureNamespaceName();\n        $nsf = $ns == '' ? '' : ($ns[0] == '\\\\' ? $ns : '\\\\'.$ns);\n\n        $_file = var_export($fileName, true);\n        $_dir = var_export(dirname($fileName), true);\n        $_namespace = var_export($ns, true);\n        $_class = var_export(trim($className ?: '', '\\\\'), true);\n        $_function = $ns.($ns == '' ? '' : '\\\\').'{closure}';\n        $_method = ($className == '' ? '' : trim($className, '\\\\').'::').$_function;\n        $_function = var_export($_function, true);\n        $_method = var_export($_method, true);\n        $_trait = null;\n\n        $tokens = $this->getTokens();\n        $state = $lastState = 'start';\n        $inside_structure = false;\n        $isFirstClassCallable = false;\n        $isShortClosure = false;\n\n        $inside_structure_mark = 0;\n        $open = 0;\n        $code = '';\n        $id_start = $id_start_ci = $id_name = $context = '';\n        $classes = $functions = $constants = null;\n        $use = [];\n        $lineAdd = 0;\n        $isUsingScope = false;\n        $isUsingThisObject = false;\n\n        for ($i = 0, $l = count($tokens); $i < $l; $i++) {\n            $token = $tokens[$i];\n\n            switch ($state) {\n                case 'start':\n                    if ($token[0] === T_FUNCTION || $token[0] === T_STATIC) {\n                        $code .= $token[1];\n\n                        $state = $token[0] === T_FUNCTION ? 'function' : 'static';\n                    } elseif ($token[0] === T_FN) {\n                        $isShortClosure = true;\n                        $code .= $token[1];\n                        $state = 'closure_args';\n                    } elseif ($token[0] === T_PUBLIC || $token[0] === T_PROTECTED || $token[0] === T_PRIVATE) {\n                        $code = '';\n                        $isFirstClassCallable = true;\n                    }\n                    break;\n                case 'static':\n                    if ($token[0] === T_WHITESPACE || $token[0] === T_COMMENT || $token[0] === T_FUNCTION) {\n                        $code .= $token[1];\n                        if ($token[0] === T_FUNCTION) {\n                            $state = 'function';\n                        }\n                    } elseif ($token[0] === T_FN) {\n                        $isShortClosure = true;\n                        $code .= $token[1];\n                        $state = 'closure_args';\n                    } else {\n                        $code = '';\n                        $state = 'start';\n                    }\n                    break;\n                case 'function':\n                    switch ($token[0]) {\n                        case T_STRING:\n                            if ($isFirstClassCallable) {\n                                $state = 'closure_args';\n                                break;\n                            }\n\n                            $code = '';\n                            $state = 'named_function';\n                            break;\n                        case '(':\n                            $code .= '(';\n                            $state = 'closure_args';\n                            break;\n                        default:\n                            $code .= is_array($token) ? $token[1] : $token;\n                    }\n                    break;\n                case 'named_function':\n                    if ($token[0] === T_FUNCTION || $token[0] === T_STATIC) {\n                        $code = $token[1];\n                        $state = $token[0] === T_FUNCTION ? 'function' : 'static';\n                    } elseif ($token[0] === T_FN) {\n                        $isShortClosure = true;\n                        $code .= $token[1];\n                        $state = 'closure_args';\n                    }\n                    break;\n                case 'closure_args':\n                    switch ($token[0]) {\n                        case T_NAME_QUALIFIED:\n                            [$id_start, $id_start_ci, $id_name] = $this->parseNameQualified($token[1]);\n                            $context = 'args';\n                            $state = 'id_name';\n                            $lastState = 'closure_args';\n                            break;\n                        case T_NS_SEPARATOR:\n                        case T_STRING:\n                            $id_start = $token[1];\n                            $id_start_ci = strtolower($id_start);\n                            $id_name = '';\n                            $context = 'args';\n                            $state = 'id_name';\n                            $lastState = 'closure_args';\n                            break;\n                        case T_USE:\n                            $code .= $token[1];\n                            $state = 'use';\n                            break;\n                        case T_DOUBLE_ARROW:\n                            $code .= $token[1];\n                            if ($isShortClosure) {\n                                $state = 'closure';\n                            }\n                            break;\n                        case ':':\n                            $code .= ':';\n                            $state = 'return';\n                            break;\n                        case '{':\n                            $code .= '{';\n                            $state = 'closure';\n                            $open++;\n                            break;\n                        default:\n                            $code .= is_array($token) ? $token[1] : $token;\n                    }\n                    break;\n                case 'use':\n                    switch ($token[0]) {\n                        case T_VARIABLE:\n                            $use[] = substr($token[1], 1);\n                            $code .= $token[1];\n                            break;\n                        case '{':\n                            $code .= '{';\n                            $state = 'closure';\n                            $open++;\n                            break;\n                        case ':':\n                            $code .= ':';\n                            $state = 'return';\n                            break;\n                        default:\n                            $code .= is_array($token) ? $token[1] : $token;\n                            break;\n                    }\n                    break;\n                case 'return':\n                    switch ($token[0]) {\n                        case T_WHITESPACE:\n                        case T_COMMENT:\n                        case T_DOC_COMMENT:\n                            $code .= $token[1];\n                            break;\n                        case T_NS_SEPARATOR:\n                        case T_STRING:\n                            $id_start = $token[1];\n                            $id_start_ci = strtolower($id_start);\n                            $id_name = '';\n                            $context = 'return_type';\n                            $state = 'id_name';\n                            $lastState = 'return';\n                            break 2;\n                        case T_NAME_QUALIFIED:\n                            [$id_start, $id_start_ci, $id_name] = $this->parseNameQualified($token[1]);\n                            $context = 'return_type';\n                            $state = 'id_name';\n                            $lastState = 'return';\n                            break 2;\n                        case T_DOUBLE_ARROW:\n                            $code .= $token[1];\n                            if ($isShortClosure) {\n                                $state = 'closure';\n                            }\n                            break;\n                        case '{':\n                            $code .= '{';\n                            $state = 'closure';\n                            $open++;\n                            break;\n                        default:\n                            $code .= is_array($token) ? $token[1] : $token;\n                            break;\n                    }\n                    break;\n                case 'closure':\n                    switch ($token[0]) {\n                        case T_CURLY_OPEN:\n                        case T_DOLLAR_OPEN_CURLY_BRACES:\n                        case '{':\n                            $code .= is_array($token) ? $token[1] : $token;\n                            $open++;\n                            break;\n                        case '}':\n                            $code .= '}';\n                            if (--$open === 0 && ! $isShortClosure) {\n                                break 3;\n                            } elseif ($inside_structure) {\n                                $inside_structure = ! ($open === $inside_structure_mark);\n                            }\n                            break;\n                        case '(':\n                        case '[':\n                            $code .= $token[0];\n                            if ($isShortClosure) {\n                                $open++;\n                            }\n                            break;\n                        case ')':\n                        case ']':\n                            if ($isShortClosure) {\n                                if ($open === 0) {\n                                    break 3;\n                                }\n                                $open--;\n                            }\n                            $code .= $token[0];\n                            break;\n                        case ',':\n                        case ';':\n                            if ($isShortClosure && $open === 0) {\n                                break 3;\n                            }\n                            $code .= $token[0];\n                            break;\n                        case T_LINE:\n                            $code .= $token[2] - $line + $lineAdd;\n                            break;\n                        case T_FILE:\n                            $code .= $_file;\n                            break;\n                        case T_DIR:\n                            $code .= $_dir;\n                            break;\n                        case T_NS_C:\n                            $code .= $_namespace;\n                            break;\n                        case T_CLASS_C:\n                            $code .= $inside_structure ? $token[1] : $_class;\n                            break;\n                        case T_FUNC_C:\n                            $code .= $inside_structure ? $token[1] : $_function;\n                            break;\n                        case T_METHOD_C:\n                            $code .= $inside_structure ? $token[1] : $_method;\n                            break;\n                        case T_COMMENT:\n                            if (substr($token[1], 0, 8) === '#trackme') {\n                                $timestamp = time();\n                                $code .= '/**'.PHP_EOL;\n                                $code .= '* Date      : '.date(DATE_W3C, $timestamp).PHP_EOL;\n                                $code .= '* Timestamp : '.$timestamp.PHP_EOL;\n                                $code .= '* Line      : '.($line + 1).PHP_EOL;\n                                $code .= '* File      : '.$_file.PHP_EOL.'*/'.PHP_EOL;\n                                $lineAdd += 5;\n                            } else {\n                                $code .= $token[1];\n                            }\n                            break;\n                        case T_VARIABLE:\n                            if ($token[1] == '$this' && ! $inside_structure) {\n                                $isUsingThisObject = true;\n                            }\n                            $code .= $token[1];\n                            break;\n                        case T_STATIC:\n                        case T_NS_SEPARATOR:\n                        case T_STRING:\n                            $id_start = $token[1];\n                            $id_start_ci = strtolower($id_start);\n                            $id_name = '';\n                            $context = 'root';\n                            $state = 'id_name';\n                            $lastState = 'closure';\n                            break 2;\n                        case T_NAME_QUALIFIED:\n                            [$id_start, $id_start_ci, $id_name] = $this->parseNameQualified($token[1]);\n                            $context = 'root';\n                            $state = 'id_name';\n                            $lastState = 'closure';\n                            break 2;\n                        case T_NEW:\n                            $code .= $token[1];\n                            $context = 'new';\n                            $state = 'id_start';\n                            $lastState = 'closure';\n                            break 2;\n                        case T_USE:\n                            $code .= $token[1];\n                            $context = 'use';\n                            $state = 'id_start';\n                            $lastState = 'closure';\n                            break;\n                        case T_INSTANCEOF:\n                        case T_INSTEADOF:\n                            $code .= $token[1];\n                            $context = 'instanceof';\n                            $state = 'id_start';\n                            $lastState = 'closure';\n                            break;\n                        case T_OBJECT_OPERATOR:\n                        case T_NULLSAFE_OBJECT_OPERATOR:\n                        case T_DOUBLE_COLON:\n                            $code .= $token[1];\n                            $lastState = 'closure';\n                            $state = 'ignore_next';\n                            break;\n                        case T_FUNCTION:\n                            $code .= $token[1];\n                            $state = 'closure_args';\n                            if (! $inside_structure) {\n                                $inside_structure = true;\n                                $inside_structure_mark = $open;\n                            }\n                            break;\n                        case T_TRAIT_C:\n                            if ($_trait === null) {\n                                $startLine = $this->getStartLine();\n                                $endLine = $this->getEndLine();\n                                $structures = $this->getStructures();\n\n                                $_trait = '';\n\n                                foreach ($structures as &$struct) {\n                                    if ($struct['type'] === 'trait' &&\n                                        $struct['start'] <= $startLine &&\n                                        $struct['end'] >= $endLine\n                                    ) {\n                                        $_trait = ($ns == '' ? '' : $ns.'\\\\').$struct['name'];\n                                        break;\n                                    }\n                                }\n\n                                $_trait = var_export($_trait, true);\n                            }\n\n                            $code .= $_trait;\n                            break;\n                        default:\n                            $code .= is_array($token) ? $token[1] : $token;\n                    }\n                    break;\n                case 'ignore_next':\n                    switch ($token[0]) {\n                        case T_WHITESPACE:\n                        case T_COMMENT:\n                        case T_DOC_COMMENT:\n                            $code .= $token[1];\n                            break;\n                        case T_CLASS:\n                        case T_NEW:\n                        case T_STATIC:\n                        case T_VARIABLE:\n                        case T_STRING:\n                        case T_CLASS_C:\n                        case T_FILE:\n                        case T_DIR:\n                        case T_METHOD_C:\n                        case T_FUNC_C:\n                        case T_FUNCTION:\n                        case T_INSTANCEOF:\n                        case T_LINE:\n                        case T_NS_C:\n                        case T_TRAIT_C:\n                        case T_USE:\n                            $code .= $token[1];\n                            $state = $lastState;\n                            break;\n                        default:\n                            $state = $lastState;\n                            $i--;\n                    }\n                    break;\n                case 'id_start':\n                    switch ($token[0]) {\n                        case T_WHITESPACE:\n                        case T_COMMENT:\n                        case T_DOC_COMMENT:\n                            $code .= $token[1];\n                            break;\n                        case T_NS_SEPARATOR:\n                        case T_NAME_FULLY_QUALIFIED:\n                        case T_STRING:\n                        case T_STATIC:\n                            $id_start = $token[1];\n                            $id_start_ci = strtolower($id_start);\n                            $id_name = '';\n                            $state = 'id_name';\n                            break 2;\n                        case T_NAME_QUALIFIED:\n                            [$id_start, $id_start_ci, $id_name] = $this->parseNameQualified($token[1]);\n                            $state = 'id_name';\n                            break 2;\n                        case T_VARIABLE:\n                            $code .= $token[1];\n                            $state = $lastState;\n                            break;\n                        case T_CLASS:\n                            $code .= $token[1];\n                            $state = 'anonymous';\n                            break;\n                        default:\n                            $i--; //reprocess last\n                            $state = 'id_name';\n                    }\n                    break;\n                case 'id_name':\n                    switch ($token[0]) {\n                        case $token[0] === ':' && $context !== 'instanceof':\n                            if ($lastState === 'closure' && $context === 'root') {\n                                $state = 'closure';\n                                $code .= $id_start.$token;\n                            }\n\n                            break;\n                        case T_NAME_QUALIFIED:\n                        case T_NS_SEPARATOR:\n                        case T_STRING:\n                        case T_WHITESPACE:\n                        case T_COMMENT:\n                        case T_DOC_COMMENT:\n                            $id_name .= $token[1];\n                            break;\n                        case '(':\n                            if ($isShortClosure) {\n                                $open++;\n                            }\n                            if ($context === 'new' || false !== strpos($id_name, '\\\\')) {\n                                if ($id_start_ci === 'self' || $id_start_ci === 'static') {\n                                    if (! $inside_structure) {\n                                        $isUsingScope = true;\n                                    }\n                                } elseif ($id_start !== '\\\\' && ! in_array($id_start_ci, $class_keywords)) {\n                                    if ($classes === null) {\n                                        $classes = $this->getClasses();\n                                    }\n                                    if (isset($classes[$id_start_ci])) {\n                                        $id_start = $classes[$id_start_ci];\n                                    }\n                                    if ($id_start[0] !== '\\\\') {\n                                        $id_start = $nsf.'\\\\'.$id_start;\n                                    }\n                                }\n                            } else {\n                                if ($id_start !== '\\\\') {\n                                    if ($functions === null) {\n                                        $functions = $this->getFunctions();\n                                    }\n                                    if (isset($functions[$id_start_ci])) {\n                                        $id_start = $functions[$id_start_ci];\n                                    } elseif ($nsf !== '\\\\' && function_exists($nsf.'\\\\'.$id_start)) {\n                                        $id_start = $nsf.'\\\\'.$id_start;\n                                        // Cache it to functions array\n                                        $functions[$id_start_ci] = $id_start;\n                                    }\n                                }\n                            }\n                            $code .= $id_start.$id_name.'(';\n                            $state = $lastState;\n                            break;\n                        case T_VARIABLE:\n                        case T_DOUBLE_COLON:\n                            if ($id_start !== '\\\\') {\n                                if ($id_start_ci === 'self' || $id_start_ci === 'parent') {\n                                    if (! $inside_structure) {\n                                        $isUsingScope = true;\n                                    }\n                                } elseif ($id_start_ci === 'static') {\n                                    if (! $inside_structure) {\n                                        $isUsingScope = $token[0] === T_DOUBLE_COLON;\n                                    }\n                                } elseif (! (\\PHP_MAJOR_VERSION >= 7 && in_array($id_start_ci, $builtin_types))) {\n                                    if ($classes === null) {\n                                        $classes = $this->getClasses();\n                                    }\n                                    if (isset($classes[$id_start_ci])) {\n                                        $id_start = $classes[$id_start_ci];\n                                    }\n                                    if ($id_start[0] !== '\\\\') {\n                                        $id_start = $nsf.'\\\\'.$id_start;\n                                    }\n                                }\n                            }\n\n                            $code .= $id_start.$id_name.$token[1];\n                            $state = $token[0] === T_DOUBLE_COLON ? 'ignore_next' : $lastState;\n                            break;\n                        default:\n                            if ($id_start !== '\\\\' && ! defined($id_start)) {\n                                if ($constants === null) {\n                                    $constants = $this->getConstants();\n                                }\n                                if (isset($constants[$id_start])) {\n                                    $id_start = $constants[$id_start];\n                                } elseif ($context === 'new') {\n                                    if (in_array($id_start_ci, $class_keywords)) {\n                                        if (! $inside_structure) {\n                                            $isUsingScope = true;\n                                        }\n                                    } else {\n                                        if ($classes === null) {\n                                            $classes = $this->getClasses();\n                                        }\n                                        if (isset($classes[$id_start_ci])) {\n                                            $id_start = $classes[$id_start_ci];\n                                        }\n                                        if ($id_start[0] !== '\\\\') {\n                                            $id_start = $nsf.'\\\\'.$id_start;\n                                        }\n                                    }\n                                } elseif ($context === 'use' ||\n                                    $context === 'instanceof' ||\n                                    $context === 'args' ||\n                                    $context === 'return_type' ||\n                                    $context === 'extends' ||\n                                    $context === 'root'\n                                ) {\n                                    if (in_array($id_start_ci, $class_keywords)) {\n                                        if (! $inside_structure && ! $id_start_ci === 'static') {\n                                            $isUsingScope = true;\n                                        }\n                                    } elseif (! (\\PHP_MAJOR_VERSION >= 7 && in_array($id_start_ci, $builtin_types))) {\n                                        if ($classes === null) {\n                                            $classes = $this->getClasses();\n                                        }\n                                        if (isset($classes[$id_start_ci])) {\n                                            $id_start = $classes[$id_start_ci];\n                                        }\n                                        if ($id_start[0] !== '\\\\') {\n                                            $id_start = $nsf.'\\\\'.$id_start;\n                                        }\n                                    }\n                                }\n                            }\n                            $code .= $id_start.$id_name;\n                            $state = $lastState;\n                            $i--; //reprocess last token\n                    }\n                    break;\n                case 'anonymous':\n                    switch ($token[0]) {\n                        case T_NAME_QUALIFIED:\n                            [$id_start, $id_start_ci, $id_name] = $this->parseNameQualified($token[1]);\n                            $state = 'id_name';\n                            $lastState = 'anonymous';\n                            break 2;\n                        case T_NS_SEPARATOR:\n                        case T_STRING:\n                            $id_start = $token[1];\n                            $id_start_ci = strtolower($id_start);\n                            $id_name = '';\n                            $state = 'id_name';\n                            $context = 'extends';\n                            $lastState = 'anonymous';\n                            break;\n                        case '{':\n                            $state = 'closure';\n                            if (! $inside_structure) {\n                                $inside_structure = true;\n                                $inside_structure_mark = $open;\n                            }\n                            $i--;\n                            break;\n                        default:\n                            $code .= is_array($token) ? $token[1] : $token;\n                    }\n                    break;\n            }\n        }\n\n        if ($isShortClosure) {\n            $this->useVariables = $this->getStaticVariables();\n        } else {\n            $this->useVariables = empty($use) ? $use : array_intersect_key($this->getStaticVariables(), array_flip($use));\n        }\n\n        $this->isShortClosure = $isShortClosure;\n        $this->isBindingRequired = $isUsingThisObject;\n        $this->isScopeRequired = $isUsingScope;\n\n        if (PHP_VERSION_ID >= 80100) {\n            $attributesCode = array_map(function ($attribute) {\n                $arguments = $attribute->getArguments();\n\n                $name = $attribute->getName();\n                $arguments = implode(', ', array_map(function ($argument, $key) {\n                    $argument = sprintf(\"'%s'\", str_replace(\"'\", \"\\\\'\", $argument));\n\n                    if (is_string($key)) {\n                        $argument = sprintf('%s: %s', $key, $argument);\n                    }\n\n                    return $argument;\n                }, $arguments, array_keys($arguments)));\n\n                return \"#[$name($arguments)]\";\n            }, $this->getAttributes());\n\n            if (! empty($attributesCode)) {\n                $code = implode(\"\\n\", array_merge($attributesCode, [$code]));\n            }\n        }\n\n        $this->code = $code;\n\n        return $this->code;\n    }\n\n    /**\n     * Get PHP native built in types.\n     *\n     * @return array\n     */\n    protected static function getBuiltinTypes()\n    {\n        // PHP 8.1\n        if (PHP_VERSION_ID >= 80100) {\n            return ['array', 'callable', 'string', 'int', 'bool', 'float', 'iterable', 'void', 'object', 'mixed', 'false', 'null', 'never'];\n        }\n\n        // PHP 8\n        if (\\PHP_MAJOR_VERSION === 8) {\n            return ['array', 'callable', 'string', 'int', 'bool', 'float', 'iterable', 'void', 'object', 'mixed', 'false', 'null'];\n        }\n\n        // PHP 7\n        switch (\\PHP_MINOR_VERSION) {\n            case 0:\n                return ['array', 'callable', 'string', 'int', 'bool', 'float'];\n            case 1:\n                return ['array', 'callable', 'string', 'int', 'bool', 'float', 'iterable', 'void'];\n            default:\n                return ['array', 'callable', 'string', 'int', 'bool', 'float', 'iterable', 'void', 'object'];\n        }\n    }\n\n    /**\n     * Gets the use variables by the closure.\n     *\n     * @return array\n     */\n    public function getUseVariables()\n    {\n        if ($this->useVariables !== null) {\n            return $this->useVariables;\n        }\n\n        $tokens = $this->getTokens();\n        $use = [];\n        $state = 'start';\n\n        foreach ($tokens as &$token) {\n            $is_array = is_array($token);\n\n            switch ($state) {\n                case 'start':\n                    if ($is_array && $token[0] === T_USE) {\n                        $state = 'use';\n                    }\n                    break;\n                case 'use':\n                    if ($is_array) {\n                        if ($token[0] === T_VARIABLE) {\n                            $use[] = substr($token[1], 1);\n                        }\n                    } elseif ($token == ')') {\n                        break 2;\n                    }\n                    break;\n            }\n        }\n\n        $this->useVariables = empty($use) ? $use : array_intersect_key($this->getStaticVariables(), array_flip($use));\n\n        return $this->useVariables;\n    }\n\n    /**\n     * Checks if binding is required.\n     *\n     * @return bool\n     */\n    public function isBindingRequired()\n    {\n        if ($this->isBindingRequired === null) {\n            $this->getCode();\n        }\n\n        return $this->isBindingRequired;\n    }\n\n    /**\n     * Checks if access to the scope is required.\n     *\n     * @return bool\n     */\n    public function isScopeRequired()\n    {\n        if ($this->isScopeRequired === null) {\n            $this->getCode();\n        }\n\n        return $this->isScopeRequired;\n    }\n\n    /**\n     * The hash of the current file name.\n     *\n     * @return string\n     */\n    protected function getHashedFileName()\n    {\n        if ($this->hashedName === null) {\n            $this->hashedName = sha1($this->getFileName());\n        }\n\n        return $this->hashedName;\n    }\n\n    /**\n     * Get the file tokens.\n     *\n     * @return array\n     */\n    protected function getFileTokens()\n    {\n        $key = $this->getHashedFileName();\n\n        if (! isset(static::$files[$key])) {\n            static::$files[$key] = token_get_all(file_get_contents($this->getFileName()));\n        }\n\n        return static::$files[$key];\n    }\n\n    /**\n     * Get the tokens.\n     *\n     * @return array\n     */\n    protected function getTokens()\n    {\n        if ($this->tokens === null) {\n            $tokens = $this->getFileTokens();\n            $startLine = $this->getStartLine();\n            $endLine = $this->getEndLine();\n            $results = [];\n            $start = false;\n\n            foreach ($tokens as &$token) {\n                if (! is_array($token)) {\n                    if ($start) {\n                        $results[] = $token;\n                    }\n\n                    continue;\n                }\n\n                $line = $token[2];\n\n                if ($line <= $endLine) {\n                    if ($line >= $startLine) {\n                        $start = true;\n                        $results[] = $token;\n                    }\n\n                    continue;\n                }\n\n                break;\n            }\n\n            $this->tokens = $results;\n        }\n\n        return $this->tokens;\n    }\n\n    /**\n     * Get the classes.\n     *\n     * @return array\n     */\n    protected function getClasses()\n    {\n        $key = $this->getHashedFileName();\n\n        if (! isset(static::$classes[$key])) {\n            $this->fetchItems();\n        }\n\n        return static::$classes[$key];\n    }\n\n    /**\n     * Get the functions.\n     *\n     * @return array\n     */\n    protected function getFunctions()\n    {\n        $key = $this->getHashedFileName();\n\n        if (! isset(static::$functions[$key])) {\n            $this->fetchItems();\n        }\n\n        return static::$functions[$key];\n    }\n\n    /**\n     * Gets the constants.\n     *\n     * @return array\n     */\n    protected function getConstants()\n    {\n        $key = $this->getHashedFileName();\n\n        if (! isset(static::$constants[$key])) {\n            $this->fetchItems();\n        }\n\n        return static::$constants[$key];\n    }\n\n    /**\n     * Get the structures.\n     *\n     * @return array\n     */\n    protected function getStructures()\n    {\n        $key = $this->getHashedFileName();\n\n        if (! isset(static::$structures[$key])) {\n            $this->fetchItems();\n        }\n\n        return static::$structures[$key];\n    }\n\n    /**\n     * Fetch the items.\n     *\n     * @return void.\n     */\n    protected function fetchItems()\n    {\n        $key = $this->getHashedFileName();\n\n        $classes = [];\n        $functions = [];\n        $constants = [];\n        $structures = [];\n        $tokens = $this->getFileTokens();\n\n        $open = 0;\n        $state = 'start';\n        $lastState = '';\n        $prefix = '';\n        $name = '';\n        $alias = '';\n        $isFunc = $isConst = false;\n\n        $startLine = $endLine = 0;\n        $structType = $structName = '';\n        $structIgnore = false;\n\n        foreach ($tokens as $token) {\n            switch ($state) {\n                case 'start':\n                    switch ($token[0]) {\n                        case T_CLASS:\n                        case T_INTERFACE:\n                        case T_TRAIT:\n                            $state = 'before_structure';\n                            $startLine = $token[2];\n                            $structType = $token[0] == T_CLASS\n                                                    ? 'class'\n                                                    : ($token[0] == T_INTERFACE ? 'interface' : 'trait');\n                            break;\n                        case T_USE:\n                            $state = 'use';\n                            $prefix = $name = $alias = '';\n                            $isFunc = $isConst = false;\n                            break;\n                        case T_FUNCTION:\n                            $state = 'structure';\n                            $structIgnore = true;\n                            break;\n                        case T_NEW:\n                            $state = 'new';\n                            break;\n                        case T_OBJECT_OPERATOR:\n                        case T_DOUBLE_COLON:\n                            $state = 'invoke';\n                            break;\n                    }\n                    break;\n                case 'use':\n                    switch ($token[0]) {\n                        case T_FUNCTION:\n                            $isFunc = true;\n                            break;\n                        case T_CONST:\n                            $isConst = true;\n                            break;\n                        case T_NS_SEPARATOR:\n                            $name .= $token[1];\n                            break;\n                        case T_STRING:\n                            $name .= $token[1];\n                            $alias = $token[1];\n                            break;\n                        case T_NAME_QUALIFIED:\n                            $name .= $token[1];\n                            $pieces = explode('\\\\', $token[1]);\n                            $alias = end($pieces);\n                            break;\n                        case T_AS:\n                            $lastState = 'use';\n                            $state = 'alias';\n                            break;\n                        case '{':\n                            $prefix = $name;\n                            $name = $alias = '';\n                            $state = 'use-group';\n                            break;\n                        case ',':\n                        case ';':\n                            if ($name === '' || $name[0] !== '\\\\') {\n                                $name = '\\\\'.$name;\n                            }\n\n                            if ($alias !== '') {\n                                if ($isFunc) {\n                                    $functions[strtolower($alias)] = $name;\n                                } elseif ($isConst) {\n                                    $constants[$alias] = $name;\n                                } else {\n                                    $classes[strtolower($alias)] = $name;\n                                }\n                            }\n                            $name = $alias = '';\n                            $state = $token === ';' ? 'start' : 'use';\n                            break;\n                    }\n                    break;\n                case 'use-group':\n                    switch ($token[0]) {\n                        case T_NS_SEPARATOR:\n                            $name .= $token[1];\n                            break;\n                        case T_NAME_QUALIFIED:\n                            $name .= $token[1];\n                            $pieces = explode('\\\\', $token[1]);\n                            $alias = end($pieces);\n                            break;\n                        case T_STRING:\n                            $name .= $token[1];\n                            $alias = $token[1];\n                            break;\n                        case T_AS:\n                            $lastState = 'use-group';\n                            $state = 'alias';\n                            break;\n                        case ',':\n                        case '}':\n\n                            if ($prefix === '' || $prefix[0] !== '\\\\') {\n                                $prefix = '\\\\'.$prefix;\n                            }\n\n                            if ($alias !== '') {\n                                if ($isFunc) {\n                                    $functions[strtolower($alias)] = $prefix.$name;\n                                } elseif ($isConst) {\n                                    $constants[$alias] = $prefix.$name;\n                                } else {\n                                    $classes[strtolower($alias)] = $prefix.$name;\n                                }\n                            }\n                            $name = $alias = '';\n                            $state = $token === '}' ? 'use' : 'use-group';\n                            break;\n                    }\n                    break;\n                case 'alias':\n                    if ($token[0] === T_STRING) {\n                        $alias = $token[1];\n                        $state = $lastState;\n                    }\n                    break;\n                case 'new':\n                    switch ($token[0]) {\n                        case T_WHITESPACE:\n                        case T_COMMENT:\n                        case T_DOC_COMMENT:\n                            break 2;\n                        case T_CLASS:\n                            $state = 'structure';\n                            $structIgnore = true;\n                            break;\n                        default:\n                            $state = 'start';\n                    }\n                    break;\n                case 'invoke':\n                    switch ($token[0]) {\n                        case T_WHITESPACE:\n                        case T_COMMENT:\n                        case T_DOC_COMMENT:\n                            break 2;\n                        default:\n                            $state = 'start';\n                    }\n                    break;\n                case 'before_structure':\n                    if ($token[0] == T_STRING) {\n                        $structName = $token[1];\n                        $state = 'structure';\n                    }\n                    break;\n                case 'structure':\n                    switch ($token[0]) {\n                        case '{':\n                        case T_CURLY_OPEN:\n                        case T_DOLLAR_OPEN_CURLY_BRACES:\n                            $open++;\n                            break;\n                        case '}':\n                            if (--$open == 0) {\n                                if (! $structIgnore) {\n                                    $structures[] = [\n                                        'type' => $structType,\n                                        'name' => $structName,\n                                        'start' => $startLine,\n                                        'end' => $endLine,\n                                    ];\n                                }\n                                $structIgnore = false;\n                                $state = 'start';\n                            }\n                            break;\n                        default:\n                            if (is_array($token)) {\n                                $endLine = $token[2];\n                            }\n                    }\n                    break;\n            }\n        }\n\n        static::$classes[$key] = $classes;\n        static::$functions[$key] = $functions;\n        static::$constants[$key] = $constants;\n        static::$structures[$key] = $structures;\n    }\n\n    /**\n     * Returns the namespace associated to the closure.\n     *\n     * @return string\n     */\n    protected function getClosureNamespaceName()\n    {\n        $ns = $this->getNamespaceName();\n\n        // First class callables...\n        if ($this->getName() !== '{closure}' && empty($ns) && ! is_null($this->getClosureScopeClass())) {\n            $ns = $this->getClosureScopeClass()->getNamespaceName();\n        }\n\n        return $ns;\n    }\n\n    /**\n     * Parse the given token.\n     *\n     * @param  string  $token\n     * @return array\n     */\n    protected function parseNameQualified($token)\n    {\n        $pieces = explode('\\\\', $token);\n\n        $id_start = array_shift($pieces);\n\n        $id_start_ci = strtolower($id_start);\n\n        $id_name = '\\\\'.implode('\\\\', $pieces);\n\n        return [$id_start, $id_start_ci, $id_name];\n    }\n}\n"
  },
  {
    "path": "server/vendor/laravel/serializable-closure/src/Support/SelfReference.php",
    "content": "<?php\n\nnamespace Laravel\\SerializableClosure\\Support;\n\nclass SelfReference\n{\n    /**\n     * The unique hash representing the object.\n     *\n     * @var string\n     */\n    public $hash;\n\n    /**\n     * Creates a new self reference instance.\n     *\n     * @param  string  $hash\n     * @return void\n     */\n    public function __construct($hash)\n    {\n        $this->hash = $hash;\n    }\n}\n"
  },
  {
    "path": "server/vendor/laravel/serializable-closure/src/UnsignedSerializableClosure.php",
    "content": "<?php\n\nnamespace Laravel\\SerializableClosure;\n\nuse Closure;\nuse Laravel\\SerializableClosure\\Exceptions\\PhpVersionNotSupportedException;\n\nclass UnsignedSerializableClosure\n{\n    /**\n     * The closure's serializable.\n     *\n     * @var \\Laravel\\SerializableClosure\\Contracts\\Serializable\n     */\n    protected $serializable;\n\n    /**\n     * Creates a new serializable closure instance.\n     *\n     * @param  \\Closure  $closure\n     * @return void\n     */\n    public function __construct(Closure $closure)\n    {\n        if (\\PHP_VERSION_ID < 70400) {\n            throw new PhpVersionNotSupportedException();\n        }\n\n        $this->serializable = new Serializers\\Native($closure);\n    }\n\n    /**\n     * Resolve the closure with the given arguments.\n     *\n     * @return mixed\n     */\n    public function __invoke()\n    {\n        if (\\PHP_VERSION_ID < 70400) {\n            throw new PhpVersionNotSupportedException();\n        }\n\n        return call_user_func_array($this->serializable, func_get_args());\n    }\n\n    /**\n     * Gets the closure.\n     *\n     * @return \\Closure\n     */\n    public function getClosure()\n    {\n        if (\\PHP_VERSION_ID < 70400) {\n            throw new PhpVersionNotSupportedException();\n        }\n\n        return $this->serializable->getClosure();\n    }\n\n    /**\n     * Get the serializable representation of the closure.\n     *\n     * @return array\n     */\n    public function __serialize()\n    {\n        return [\n            'serializable' => $this->serializable,\n        ];\n    }\n\n    /**\n     * Restore the closure after serialization.\n     *\n     * @param  array  $data\n     * @return void\n     */\n    public function __unserialize($data)\n    {\n        $this->serializable = $data['serializable'];\n    }\n}\n"
  },
  {
    "path": "server/vendor/league/oauth2-client/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2013-2023 Alex Bilbie <hello@alexbilbie.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "server/vendor/league/oauth2-client/README.md",
    "content": "# OAuth 2.0 Client\n\nThis package provides a base for integrating with [OAuth 2.0](http://oauth.net/2/) service providers.\n\n[![Gitter Chat](https://img.shields.io/badge/gitter-join_chat-brightgreen.svg?style=flat-square)](https://gitter.im/thephpleague/oauth2-client)\n[![Source Code](https://img.shields.io/badge/source-thephpleague/oauth2--client-blue.svg?style=flat-square)](https://github.com/thephpleague/oauth2-client)\n[![Latest Version](https://img.shields.io/github/release/thephpleague/oauth2-client.svg?style=flat-square)](https://github.com/thephpleague/oauth2-client/releases)\n[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](https://github.com/thephpleague/oauth2-client/blob/master/LICENSE)\n[![Build Status](https://img.shields.io/github/actions/workflow/status/thephpleague/oauth2-client/continuous-integration.yml?label=CI&logo=github&style=flat-square)](https://github.com/thephpleague/oauth2-client/actions?query=workflow%3ACI)\n[![Codecov Code Coverage](https://img.shields.io/codecov/c/gh/thephpleague/oauth2-client?label=codecov&logo=codecov&style=flat-square)](https://codecov.io/gh/thephpleague/oauth2-client)\n[![Total Downloads](https://img.shields.io/packagist/dt/league/oauth2-client.svg?style=flat-square)](https://packagist.org/packages/league/oauth2-client)\n\n---\n\nThe OAuth 2.0 login flow, seen commonly around the web in the form of \"Connect with Facebook/Google/etc.\" buttons, is a common integration added to web applications, but it can be tricky and tedious to do right. To help, we've created the `league/oauth2-client` package, which provides a base for integrating with various OAuth 2.0 providers, without overburdening your application with the concerns of [RFC 6749](http://tools.ietf.org/html/rfc6749).\n\nThis OAuth 2.0 client library will work with any OAuth 2.0 provider that conforms to the OAuth 2.0 Authorization Framework. Out-of-the-box, we provide a `GenericProvider` class to connect to any service provider that uses [Bearer tokens](http://tools.ietf.org/html/rfc6750). See our [basic usage guide](https://oauth2-client.thephpleague.com/usage/) for examples using `GenericProvider`.\n\nMany service providers provide additional functionality above and beyond the OAuth 2.0 specification. For this reason, you may extend and wrap this library to support additional behavior. There are already many [official](https://oauth2-client.thephpleague.com/providers/league/) and [third-party](https://oauth2-client.thephpleague.com/providers/thirdparty/) provider clients available (e.g., Facebook, GitHub, Google, Instagram, LinkedIn, etc.). If your provider isn't in the list, feel free to add it.\n\nThis package is compliant with [PSR-1][], [PSR-2][], [PSR-4][], and [PSR-7][]. If you notice compliance oversights, please send a patch via pull request. If you're interested in contributing to this library, please take a look at our [contributing guidelines](https://github.com/thephpleague/oauth2-client/blob/master/CONTRIBUTING.md).\n\n## Requirements\n\nWe support the following versions of PHP:\n\n* PHP 8.5\n* PHP 8.4\n* PHP 8.3\n* PHP 8.2\n* PHP 8.1\n* PHP 8.0\n* PHP 7.4\n* PHP 7.3\n* PHP 7.2\n* PHP 7.1\n\n## Provider Clients\n\nWe provide a list of [official PHP League provider clients](https://oauth2-client.thephpleague.com/providers/league/), as well as [third-party provider clients](https://oauth2-client.thephpleague.com/providers/thirdparty/).\n\nTo build your own provider client, please refer to \"[Implementing a Provider Client](https://oauth2-client.thephpleague.com/providers/implementing/).\"\n\n## Usage\n\nFor usage and code examples, check out our [basic usage guide](https://oauth2-client.thephpleague.com/usage/).\n\n## Contributing\n\nPlease see [our contributing guidelines](https://github.com/thephpleague/oauth2-client/blob/master/CONTRIBUTING.md) for details.\n\n## License\n\nThe MIT License (MIT). Please see [LICENSE](https://github.com/thephpleague/oauth2-client/blob/master/LICENSE) for more information.\n\n\n[PSR-1]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md\n[PSR-2]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md\n[PSR-4]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader.md\n[PSR-7]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-7-http-message.md\n"
  },
  {
    "path": "server/vendor/league/oauth2-client/composer.json",
    "content": "{\n    \"name\": \"league/oauth2-client\",\n    \"description\": \"OAuth 2.0 Client Library\",\n    \"license\": \"MIT\",\n    \"config\": {\n        \"sort-packages\": true\n    },\n    \"require\": {\n        \"php\": \"^7.1 || >=8.0.0 <8.6.0\",\n        \"ext-json\": \"*\",\n        \"guzzlehttp/guzzle\": \"^6.5.8 || ^7.4.5\"\n    },\n    \"require-dev\": {\n        \"mockery/mockery\": \"^1.3.5\",\n        \"php-parallel-lint/php-parallel-lint\": \"^1.4\",\n        \"phpunit/phpunit\": \"^7 || ^8 || ^9 || ^10 || ^11\",\n        \"squizlabs/php_codesniffer\": \"^3.11\"\n    },\n    \"keywords\": [\n        \"oauth\",\n        \"oauth2\",\n        \"authorization\",\n        \"authentication\",\n        \"idp\",\n        \"identity\",\n        \"sso\",\n        \"single sign on\"\n    ],\n    \"authors\": [\n        {\n            \"name\": \"Alex Bilbie\",\n            \"email\": \"hello@alexbilbie.com\",\n            \"homepage\": \"http://www.alexbilbie.com\",\n            \"role\": \"Developer\"\n        },\n        {\n            \"name\": \"Woody Gilk\",\n            \"homepage\": \"https://github.com/shadowhand\",\n            \"role\": \"Contributor\"\n        }\n\n    ],\n    \"autoload\": {\n        \"psr-4\": {\n            \"League\\\\OAuth2\\\\Client\\\\\": \"src/\"\n        }\n    },\n    \"autoload-dev\": {\n        \"psr-4\": {\n            \"League\\\\OAuth2\\\\Client\\\\Test\\\\\": \"test/src/\"\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/league/oauth2-client/phpunit.xml.dist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<phpunit xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:noNamespaceSchemaLocation=\"vendor/phpunit/phpunit/phpunit.xsd\"\n         bootstrap=\"./vendor/autoload.php\"\n         colors=\"true\"\n         cacheDirectory=\"build/phpunit\">\n\n    <coverage>\n        <report>\n            <clover outputFile=\"build/logs/clover.xml\"/>\n            <html outputDirectory=\"build/coverage\"/>\n            <text outputFile=\"php://stdout\"/>\n        </report>\n    </coverage>\n\n    <testsuites>\n        <testsuite name=\"all\">\n            <directory>test</directory>\n        </testsuite>\n    </testsuites>\n\n    <logging>\n        <junit outputFile=\"build/report.junit.xml\"/>\n    </logging>\n\n    <source>\n        <include>\n            <directory suffix=\".php\">src</directory>\n        </include>\n    </source>\n\n    <php>\n        <env name=\"XDEBUG_MODE\" value=\"coverage\"/>\n    </php>\n\n</phpunit>\n"
  },
  {
    "path": "server/vendor/league/oauth2-client/src/Grant/AbstractGrant.php",
    "content": "<?php\n/**\n * This file is part of the league/oauth2-client library\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n *\n * @copyright Copyright (c) Alex Bilbie <hello@alexbilbie.com>\n * @license http://opensource.org/licenses/MIT MIT\n * @link http://thephpleague.com/oauth2-client/ Documentation\n * @link https://packagist.org/packages/league/oauth2-client Packagist\n * @link https://github.com/thephpleague/oauth2-client GitHub\n */\n\nnamespace League\\OAuth2\\Client\\Grant;\n\nuse League\\OAuth2\\Client\\Tool\\RequiredParameterTrait;\n\n/**\n * Represents a type of authorization grant.\n *\n * An authorization grant is a credential representing the resource\n * owner's authorization (to access its protected resources) used by the\n * client to obtain an access token.  OAuth 2.0 defines four\n * grant types -- authorization code, implicit, resource owner password\n * credentials, and client credentials -- as well as an extensibility\n * mechanism for defining additional types.\n *\n * @link http://tools.ietf.org/html/rfc6749#section-1.3 Authorization Grant (RFC 6749, §1.3)\n */\nabstract class AbstractGrant\n{\n    use RequiredParameterTrait;\n\n    /**\n     * Returns the name of this grant, eg. 'grant_name', which is used as the\n     * grant type when encoding URL query parameters.\n     *\n     * @return string\n     */\n    abstract protected function getName();\n\n    /**\n     * Returns a list of all required request parameters.\n     *\n     * @return array\n     */\n    abstract protected function getRequiredRequestParameters();\n\n    /**\n     * Returns this grant's name as its string representation. This allows for\n     * string interpolation when building URL query parameters.\n     *\n     * @return string\n     */\n    public function __toString()\n    {\n        return $this->getName();\n    }\n\n    /**\n     * Prepares an access token request's parameters by checking that all\n     * required parameters are set, then merging with any given defaults.\n     *\n     * @param  array $defaults\n     * @param  array $options\n     * @return array\n     */\n    public function prepareRequestParameters(array $defaults, array $options)\n    {\n        $defaults['grant_type'] = $this->getName();\n\n        $required = $this->getRequiredRequestParameters();\n        $provided = array_merge($defaults, $options);\n\n        $this->checkRequiredParameters($required, $provided);\n\n        return $provided;\n    }\n}\n"
  },
  {
    "path": "server/vendor/league/oauth2-client/src/Grant/AuthorizationCode.php",
    "content": "<?php\n/**\n * This file is part of the league/oauth2-client library\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n *\n * @copyright Copyright (c) Alex Bilbie <hello@alexbilbie.com>\n * @license http://opensource.org/licenses/MIT MIT\n * @link http://thephpleague.com/oauth2-client/ Documentation\n * @link https://packagist.org/packages/league/oauth2-client Packagist\n * @link https://github.com/thephpleague/oauth2-client GitHub\n */\n\nnamespace League\\OAuth2\\Client\\Grant;\n\n/**\n * Represents an authorization code grant.\n *\n * @link http://tools.ietf.org/html/rfc6749#section-1.3.1 Authorization Code (RFC 6749, §1.3.1)\n */\nclass AuthorizationCode extends AbstractGrant\n{\n    /**\n     * @inheritdoc\n     */\n    protected function getName()\n    {\n        return 'authorization_code';\n    }\n\n    /**\n     * @inheritdoc\n     */\n    protected function getRequiredRequestParameters()\n    {\n        return [\n            'code',\n        ];\n    }\n}\n"
  },
  {
    "path": "server/vendor/league/oauth2-client/src/Grant/ClientCredentials.php",
    "content": "<?php\n/**\n * This file is part of the league/oauth2-client library\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n *\n * @copyright Copyright (c) Alex Bilbie <hello@alexbilbie.com>\n * @license http://opensource.org/licenses/MIT MIT\n * @link http://thephpleague.com/oauth2-client/ Documentation\n * @link https://packagist.org/packages/league/oauth2-client Packagist\n * @link https://github.com/thephpleague/oauth2-client GitHub\n */\n\nnamespace League\\OAuth2\\Client\\Grant;\n\n/**\n * Represents a client credentials grant.\n *\n * @link http://tools.ietf.org/html/rfc6749#section-1.3.4 Client Credentials (RFC 6749, §1.3.4)\n */\nclass ClientCredentials extends AbstractGrant\n{\n    /**\n     * @inheritdoc\n     */\n    protected function getName()\n    {\n        return 'client_credentials';\n    }\n\n    /**\n     * @inheritdoc\n     */\n    protected function getRequiredRequestParameters()\n    {\n        return [];\n    }\n}\n"
  },
  {
    "path": "server/vendor/league/oauth2-client/src/Grant/Exception/InvalidGrantException.php",
    "content": "<?php\n/**\n * This file is part of the league/oauth2-client library\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n *\n * @copyright Copyright (c) Alex Bilbie <hello@alexbilbie.com>\n * @license http://opensource.org/licenses/MIT MIT\n * @link http://thephpleague.com/oauth2-client/ Documentation\n * @link https://packagist.org/packages/league/oauth2-client Packagist\n * @link https://github.com/thephpleague/oauth2-client GitHub\n */\n\nnamespace League\\OAuth2\\Client\\Grant\\Exception;\n\nuse InvalidArgumentException;\n\n/**\n * Exception thrown if the grant does not extend from AbstractGrant.\n *\n * @see League\\OAuth2\\Client\\Grant\\AbstractGrant\n */\nclass InvalidGrantException extends InvalidArgumentException\n{\n}\n"
  },
  {
    "path": "server/vendor/league/oauth2-client/src/Grant/GrantFactory.php",
    "content": "<?php\n/**\n * This file is part of the league/oauth2-client library\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n *\n * @copyright Copyright (c) Alex Bilbie <hello@alexbilbie.com>\n * @license http://opensource.org/licenses/MIT MIT\n * @link http://thephpleague.com/oauth2-client/ Documentation\n * @link https://packagist.org/packages/league/oauth2-client Packagist\n * @link https://github.com/thephpleague/oauth2-client GitHub\n */\n\nnamespace League\\OAuth2\\Client\\Grant;\n\nuse League\\OAuth2\\Client\\Grant\\Exception\\InvalidGrantException;\n\n/**\n * Represents a factory used when retrieving an authorization grant type.\n */\nclass GrantFactory\n{\n    /**\n     * @var array\n     */\n    protected $registry = [];\n\n    /**\n     * Defines a grant singleton in the registry.\n     *\n     * @param  string $name\n     * @param  AbstractGrant $grant\n     * @return self\n     */\n    public function setGrant($name, AbstractGrant $grant)\n    {\n        $this->registry[$name] = $grant;\n\n        return $this;\n    }\n\n    /**\n     * Returns a grant singleton by name.\n     *\n     * If the grant has not be registered, a default grant will be loaded.\n     *\n     * @param  string $name\n     * @return AbstractGrant\n     */\n    public function getGrant($name)\n    {\n        if (empty($this->registry[$name])) {\n            $this->registerDefaultGrant($name);\n        }\n\n        return $this->registry[$name];\n    }\n\n    /**\n     * Registers a default grant singleton by name.\n     *\n     * @param  string $name\n     * @return self\n     */\n    protected function registerDefaultGrant($name)\n    {\n        // PascalCase the grant. E.g: 'authorization_code' becomes 'AuthorizationCode'\n        $class = str_replace(' ', '', ucwords(str_replace(['-', '_'], ' ', $name)));\n        $class = 'League\\\\OAuth2\\\\Client\\\\Grant\\\\' . $class;\n\n        $this->checkGrant($class);\n\n        return $this->setGrant($name, new $class);\n    }\n\n    /**\n     * Determines if a variable is a valid grant.\n     *\n     * @param  mixed $class\n     * @return boolean\n     */\n    public function isGrant($class)\n    {\n        return is_subclass_of($class, AbstractGrant::class);\n    }\n\n    /**\n     * Checks if a variable is a valid grant.\n     *\n     * @throws InvalidGrantException\n     * @param  mixed $class\n     * @return void\n     */\n    public function checkGrant($class)\n    {\n        if (!$this->isGrant($class)) {\n            throw new InvalidGrantException(sprintf(\n                'Grant \"%s\" must extend AbstractGrant',\n                is_object($class) ? get_class($class) : $class\n            ));\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/league/oauth2-client/src/Grant/Password.php",
    "content": "<?php\n/**\n * This file is part of the league/oauth2-client library\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n *\n * @copyright Copyright (c) Alex Bilbie <hello@alexbilbie.com>\n * @license http://opensource.org/licenses/MIT MIT\n * @link http://thephpleague.com/oauth2-client/ Documentation\n * @link https://packagist.org/packages/league/oauth2-client Packagist\n * @link https://github.com/thephpleague/oauth2-client GitHub\n */\n\nnamespace League\\OAuth2\\Client\\Grant;\n\n/**\n * Represents a resource owner password credentials grant.\n *\n * @link http://tools.ietf.org/html/rfc6749#section-1.3.3 Resource Owner Password Credentials (RFC 6749, §1.3.3)\n */\nclass Password extends AbstractGrant\n{\n    /**\n     * @inheritdoc\n     */\n    protected function getName()\n    {\n        return 'password';\n    }\n\n    /**\n     * @inheritdoc\n     */\n    protected function getRequiredRequestParameters()\n    {\n        return [\n            'username',\n            'password',\n        ];\n    }\n}\n"
  },
  {
    "path": "server/vendor/league/oauth2-client/src/Grant/RefreshToken.php",
    "content": "<?php\n/**\n * This file is part of the league/oauth2-client library\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n *\n * @copyright Copyright (c) Alex Bilbie <hello@alexbilbie.com>\n * @license http://opensource.org/licenses/MIT MIT\n * @link http://thephpleague.com/oauth2-client/ Documentation\n * @link https://packagist.org/packages/league/oauth2-client Packagist\n * @link https://github.com/thephpleague/oauth2-client GitHub\n */\n\nnamespace League\\OAuth2\\Client\\Grant;\n\n/**\n * Represents a refresh token grant.\n *\n * @link http://tools.ietf.org/html/rfc6749#section-6 Refreshing an Access Token (RFC 6749, §6)\n */\nclass RefreshToken extends AbstractGrant\n{\n    /**\n     * @inheritdoc\n     */\n    protected function getName()\n    {\n        return 'refresh_token';\n    }\n\n    /**\n     * @inheritdoc\n     */\n    protected function getRequiredRequestParameters()\n    {\n        return [\n            'refresh_token',\n        ];\n    }\n}\n"
  },
  {
    "path": "server/vendor/league/oauth2-client/src/OptionProvider/HttpBasicAuthOptionProvider.php",
    "content": "<?php\n/**\n * This file is part of the league/oauth2-client library\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n *\n * @copyright Copyright (c) Alex Bilbie <hello@alexbilbie.com>\n * @license http://opensource.org/licenses/MIT MIT\n * @link http://thephpleague.com/oauth2-client/ Documentation\n * @link https://packagist.org/packages/league/oauth2-client Packagist\n * @link https://github.com/thephpleague/oauth2-client GitHub\n */\n\nnamespace League\\OAuth2\\Client\\OptionProvider;\n\nuse InvalidArgumentException;\n\n/**\n * Add http basic auth into access token request options\n * @link https://tools.ietf.org/html/rfc6749#section-2.3.1\n */\nclass HttpBasicAuthOptionProvider extends PostAuthOptionProvider\n{\n    /**\n     * @inheritdoc\n     */\n    public function getAccessTokenOptions($method, array $params)\n    {\n        if (empty($params['client_id']) || empty($params['client_secret'])) {\n            throw new InvalidArgumentException('clientId and clientSecret are required for http basic auth');\n        }\n\n        $encodedCredentials = base64_encode(sprintf('%s:%s', $params['client_id'], $params['client_secret']));\n        unset($params['client_id'], $params['client_secret']);\n\n        $options = parent::getAccessTokenOptions($method, $params);\n        $options['headers']['Authorization'] = 'Basic ' . $encodedCredentials;\n\n        return $options;\n    }\n}\n"
  },
  {
    "path": "server/vendor/league/oauth2-client/src/OptionProvider/OptionProviderInterface.php",
    "content": "<?php\n/**\n * This file is part of the league/oauth2-client library\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n *\n * @copyright Copyright (c) Alex Bilbie <hello@alexbilbie.com>\n * @license http://opensource.org/licenses/MIT MIT\n * @link http://thephpleague.com/oauth2-client/ Documentation\n * @link https://packagist.org/packages/league/oauth2-client Packagist\n * @link https://github.com/thephpleague/oauth2-client GitHub\n */\n\nnamespace League\\OAuth2\\Client\\OptionProvider;\n\n/**\n * Interface for access token options provider\n */\ninterface OptionProviderInterface\n{\n    /**\n     * Builds request options used for requesting an access token.\n     *\n     * @param string $method\n     * @param  array $params\n     * @return array\n     */\n    public function getAccessTokenOptions($method, array $params);\n}\n"
  },
  {
    "path": "server/vendor/league/oauth2-client/src/OptionProvider/PostAuthOptionProvider.php",
    "content": "<?php\n/**\n * This file is part of the league/oauth2-client library\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n *\n * @copyright Copyright (c) Alex Bilbie <hello@alexbilbie.com>\n * @license http://opensource.org/licenses/MIT MIT\n * @link http://thephpleague.com/oauth2-client/ Documentation\n * @link https://packagist.org/packages/league/oauth2-client Packagist\n * @link https://github.com/thephpleague/oauth2-client GitHub\n */\n\nnamespace League\\OAuth2\\Client\\OptionProvider;\n\nuse League\\OAuth2\\Client\\Provider\\AbstractProvider;\nuse League\\OAuth2\\Client\\Tool\\QueryBuilderTrait;\n\n/**\n * Provide options for access token\n */\nclass PostAuthOptionProvider implements OptionProviderInterface\n{\n    use QueryBuilderTrait;\n\n    /**\n     * @inheritdoc\n     */\n    public function getAccessTokenOptions($method, array $params)\n    {\n        $options = ['headers' => ['content-type' => 'application/x-www-form-urlencoded']];\n\n        if ($method === AbstractProvider::METHOD_POST) {\n            $options['body'] = $this->getAccessTokenBody($params);\n        }\n\n        return $options;\n    }\n\n    /**\n     * Returns the request body for requesting an access token.\n     *\n     * @param  array $params\n     * @return string\n     */\n    protected function getAccessTokenBody(array $params)\n    {\n        return $this->buildQueryString($params);\n    }\n}\n"
  },
  {
    "path": "server/vendor/league/oauth2-client/src/Provider/AbstractProvider.php",
    "content": "<?php\n/**\n * This file is part of the league/oauth2-client library\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n *\n * @copyright Copyright (c) Alex Bilbie <hello@alexbilbie.com>\n * @license http://opensource.org/licenses/MIT MIT\n * @link http://thephpleague.com/oauth2-client/ Documentation\n * @link https://packagist.org/packages/league/oauth2-client Packagist\n * @link https://github.com/thephpleague/oauth2-client GitHub\n */\n\nnamespace League\\OAuth2\\Client\\Provider;\n\nuse GuzzleHttp\\Client as HttpClient;\nuse GuzzleHttp\\ClientInterface as HttpClientInterface;\nuse GuzzleHttp\\Exception\\BadResponseException;\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse InvalidArgumentException;\nuse League\\OAuth2\\Client\\Grant\\AbstractGrant;\nuse League\\OAuth2\\Client\\Grant\\GrantFactory;\nuse League\\OAuth2\\Client\\OptionProvider\\OptionProviderInterface;\nuse League\\OAuth2\\Client\\OptionProvider\\PostAuthOptionProvider;\nuse League\\OAuth2\\Client\\Provider\\Exception\\IdentityProviderException;\nuse League\\OAuth2\\Client\\Token\\AccessToken;\nuse League\\OAuth2\\Client\\Token\\AccessTokenInterface;\nuse League\\OAuth2\\Client\\Tool\\ArrayAccessorTrait;\nuse League\\OAuth2\\Client\\Tool\\GuardedPropertyTrait;\nuse League\\OAuth2\\Client\\Tool\\QueryBuilderTrait;\nuse League\\OAuth2\\Client\\Tool\\RequestFactory;\nuse Psr\\Http\\Message\\RequestInterface;\nuse Psr\\Http\\Message\\ResponseInterface;\nuse UnexpectedValueException;\n\n/**\n * Represents a service provider (authorization server).\n *\n * @link http://tools.ietf.org/html/rfc6749#section-1.1 Roles (RFC 6749, §1.1)\n */\nabstract class AbstractProvider\n{\n    use ArrayAccessorTrait;\n    use GuardedPropertyTrait;\n    use QueryBuilderTrait;\n\n    /**\n     * @var string|null Key used in a token response to identify the resource owner.\n     */\n    const ACCESS_TOKEN_RESOURCE_OWNER_ID = null;\n\n    /**\n     * @var string HTTP method used to fetch access tokens.\n     */\n    const METHOD_GET = 'GET';\n\n    /**\n     * @var string HTTP method used to fetch access tokens.\n     */\n    const METHOD_POST = 'POST';\n\n    /**\n     * @var string PKCE method used to fetch authorization token.\n     * The PKCE code challenge will be hashed with sha256 (recommended).\n     */\n    const PKCE_METHOD_S256 = 'S256';\n\n    /**\n     * @var string PKCE method used to fetch authorization token.\n     * The PKCE code challenge will be sent as plain text, this is NOT recommended.\n     * Only use `plain` if no other option is possible.\n     */\n    const PKCE_METHOD_PLAIN = 'plain';\n\n    /**\n     * @var string\n     */\n    protected $clientId;\n\n    /**\n     * @var string\n     */\n    protected $clientSecret;\n\n    /**\n     * @var string\n     */\n    protected $redirectUri;\n\n    /**\n     * @var string\n     */\n    protected $state;\n\n    /**\n     * @var string|null\n     */\n    protected $pkceCode = null;\n\n    /**\n     * @var GrantFactory\n     */\n    protected $grantFactory;\n\n    /**\n     * @var RequestFactory\n     */\n    protected $requestFactory;\n\n    /**\n     * @var HttpClientInterface\n     */\n    protected $httpClient;\n\n    /**\n     * @var OptionProviderInterface\n     */\n    protected $optionProvider;\n\n    /**\n     * Constructs an OAuth 2.0 service provider.\n     *\n     * @param array $options An array of options to set on this provider.\n     *     Options include `clientId`, `clientSecret`, `redirectUri`, and `state`.\n     *     Individual providers may introduce more options, as needed.\n     * @param array $collaborators An array of collaborators that may be used to\n     *     override this provider's default behavior. Collaborators include\n     *     `grantFactory`, `requestFactory`, and `httpClient`.\n     *     Individual providers may introduce more collaborators, as needed.\n     */\n    public function __construct(array $options = [], array $collaborators = [])\n    {\n        // We'll let the GuardedPropertyTrait handle mass assignment of incoming\n        // options, skipping any blacklisted properties defined in the provider\n        $this->fillProperties($options);\n\n        if (empty($collaborators['grantFactory'])) {\n            $collaborators['grantFactory'] = new GrantFactory();\n        }\n        $this->setGrantFactory($collaborators['grantFactory']);\n\n        if (empty($collaborators['requestFactory'])) {\n            $collaborators['requestFactory'] = new RequestFactory();\n        }\n        $this->setRequestFactory($collaborators['requestFactory']);\n\n        if (empty($collaborators['httpClient'])) {\n            $client_options = $this->getAllowedClientOptions($options);\n\n            $collaborators['httpClient'] = new HttpClient(\n                array_intersect_key($options, array_flip($client_options))\n            );\n        }\n        $this->setHttpClient($collaborators['httpClient']);\n\n        if (empty($collaborators['optionProvider'])) {\n            $collaborators['optionProvider'] = new PostAuthOptionProvider();\n        }\n        $this->setOptionProvider($collaborators['optionProvider']);\n    }\n\n    /**\n     * Returns the list of options that can be passed to the HttpClient\n     *\n     * @param array $options An array of options to set on this provider.\n     *     Options include `clientId`, `clientSecret`, `redirectUri`, and `state`.\n     *     Individual providers may introduce more options, as needed.\n     * @return array The options to pass to the HttpClient constructor\n     */\n    protected function getAllowedClientOptions(array $options)\n    {\n        $client_options = ['timeout', 'proxy'];\n\n        // Only allow turning off ssl verification if it's for a proxy\n        if (!empty($options['proxy'])) {\n            $client_options[] = 'verify';\n        }\n\n        return $client_options;\n    }\n\n    /**\n     * Sets the grant factory instance.\n     *\n     * @param  GrantFactory $factory\n     * @return self\n     */\n    public function setGrantFactory(GrantFactory $factory)\n    {\n        $this->grantFactory = $factory;\n\n        return $this;\n    }\n\n    /**\n     * Returns the current grant factory instance.\n     *\n     * @return GrantFactory\n     */\n    public function getGrantFactory()\n    {\n        return $this->grantFactory;\n    }\n\n    /**\n     * Sets the request factory instance.\n     *\n     * @param  RequestFactory $factory\n     * @return self\n     */\n    public function setRequestFactory(RequestFactory $factory)\n    {\n        $this->requestFactory = $factory;\n\n        return $this;\n    }\n\n    /**\n     * Returns the request factory instance.\n     *\n     * @return RequestFactory\n     */\n    public function getRequestFactory()\n    {\n        return $this->requestFactory;\n    }\n\n    /**\n     * Sets the HTTP client instance.\n     *\n     * @param  HttpClientInterface $client\n     * @return self\n     */\n    public function setHttpClient(HttpClientInterface $client)\n    {\n        $this->httpClient = $client;\n\n        return $this;\n    }\n\n    /**\n     * Returns the HTTP client instance.\n     *\n     * @return HttpClientInterface\n     */\n    public function getHttpClient()\n    {\n        return $this->httpClient;\n    }\n\n    /**\n     * Sets the option provider instance.\n     *\n     * @param  OptionProviderInterface $provider\n     * @return self\n     */\n    public function setOptionProvider(OptionProviderInterface $provider)\n    {\n        $this->optionProvider = $provider;\n\n        return $this;\n    }\n\n    /**\n     * Returns the option provider instance.\n     *\n     * @return OptionProviderInterface\n     */\n    public function getOptionProvider()\n    {\n        return $this->optionProvider;\n    }\n\n    /**\n     * Returns the current value of the state parameter.\n     *\n     * This can be accessed by the redirect handler during authorization.\n     *\n     * @return string\n     */\n    public function getState()\n    {\n        return $this->state;\n    }\n\n    /**\n     * Set the value of the pkceCode parameter.\n     *\n     * When using PKCE this should be set before requesting an access token.\n     *\n     * @param string $pkceCode\n     * @return self\n     */\n    public function setPkceCode($pkceCode)\n    {\n        $this->pkceCode = $pkceCode;\n        return $this;\n    }\n\n    /**\n     * Returns the current value of the pkceCode parameter.\n     *\n     * This can be accessed by the redirect handler during authorization.\n     *\n     * @return string|null\n     */\n    public function getPkceCode()\n    {\n        return $this->pkceCode;\n    }\n\n    /**\n     * Returns the base URL for authorizing a client.\n     *\n     * Eg. https://oauth.service.com/authorize\n     *\n     * @return string\n     */\n    abstract public function getBaseAuthorizationUrl();\n\n    /**\n     * Returns the base URL for requesting an access token.\n     *\n     * Eg. https://oauth.service.com/token\n     *\n     * @param array $params\n     * @return string\n     */\n    abstract public function getBaseAccessTokenUrl(array $params);\n\n    /**\n     * Returns the URL for requesting the resource owner's details.\n     *\n     * @param AccessToken $token\n     * @return string\n     */\n    abstract public function getResourceOwnerDetailsUrl(AccessToken $token);\n\n    /**\n     * Returns a new random string to use as the state parameter in an\n     * authorization flow.\n     *\n     * @param  int $length Length of the random string to be generated.\n     * @return string\n     */\n    protected function getRandomState($length = 32)\n    {\n        // Converting bytes to hex will always double length. Hence, we can reduce\n        // the amount of bytes by half to produce the correct length.\n        return bin2hex(random_bytes($length / 2));\n    }\n\n    /**\n     * Returns a new random string to use as PKCE code_verifier and\n     * hashed as code_challenge parameters in an authorization flow.\n     * Must be between 43 and 128 characters long.\n     *\n     * @param  int $length Length of the random string to be generated.\n     * @return string\n     */\n    protected function getRandomPkceCode($length = 64)\n    {\n        return substr(\n            strtr(\n                base64_encode(random_bytes($length)),\n                '+/',\n                '-_'\n            ),\n            0,\n            $length\n        );\n    }\n\n    /**\n     * Returns the default scopes used by this provider.\n     *\n     * This should only be the scopes that are required to request the details\n     * of the resource owner, rather than all the available scopes.\n     *\n     * @return array\n     */\n    abstract protected function getDefaultScopes();\n\n    /**\n     * Returns the string that should be used to separate scopes when building\n     * the URL for requesting an access token.\n     *\n     * @return string Scope separator, defaults to ','\n     */\n    protected function getScopeSeparator()\n    {\n        return ',';\n    }\n\n    /**\n     * @return string|null\n     */\n    protected function getPkceMethod()\n    {\n        return null;\n    }\n\n    /**\n     * Returns authorization parameters based on provided options.\n     *\n     * @param  array $options\n     * @return array Authorization parameters\n     * @throws InvalidArgumentException\n     */\n    protected function getAuthorizationParameters(array $options)\n    {\n        if (empty($options['state'])) {\n            $options['state'] = $this->getRandomState();\n        }\n\n        if (empty($options['scope'])) {\n            $options['scope'] = $this->getDefaultScopes();\n        }\n\n        $options += [\n            'response_type'   => 'code',\n            'approval_prompt' => 'auto'\n        ];\n\n        if (is_array($options['scope'])) {\n            $separator = $this->getScopeSeparator();\n            $options['scope'] = implode($separator, $options['scope']);\n        }\n\n        // Store the state as it may need to be accessed later on.\n        $this->state = $options['state'];\n\n        $pkceMethod = $this->getPkceMethod();\n        if (!empty($pkceMethod)) {\n            $this->pkceCode = $this->getRandomPkceCode();\n            if ($pkceMethod === static::PKCE_METHOD_S256) {\n                $options['code_challenge'] = trim(\n                    strtr(\n                        base64_encode(hash('sha256', $this->pkceCode, true)),\n                        '+/',\n                        '-_'\n                    ),\n                    '='\n                );\n            } elseif ($pkceMethod === static::PKCE_METHOD_PLAIN) {\n                $options['code_challenge'] = $this->pkceCode;\n            } else {\n                throw new InvalidArgumentException('Unknown PKCE method \"' . $pkceMethod . '\".');\n            }\n            $options['code_challenge_method'] = $pkceMethod;\n        }\n\n        // Business code layer might set a different redirect_uri parameter\n        // depending on the context, leave it as-is\n        if (!isset($options['redirect_uri'])) {\n            $options['redirect_uri'] = $this->redirectUri;\n        }\n\n        $options['client_id'] = $this->clientId;\n\n        return $options;\n    }\n\n    /**\n     * Builds the authorization URL's query string.\n     *\n     * @param  array $params Query parameters\n     * @return string Query string\n     */\n    protected function getAuthorizationQuery(array $params)\n    {\n        return $this->buildQueryString($params);\n    }\n\n    /**\n     * Builds the authorization URL.\n     *\n     * @param  array $options\n     * @return string Authorization URL\n     * @throws InvalidArgumentException\n     */\n    public function getAuthorizationUrl(array $options = [])\n    {\n        $base   = $this->getBaseAuthorizationUrl();\n        $params = $this->getAuthorizationParameters($options);\n        $query  = $this->getAuthorizationQuery($params);\n\n        return $this->appendQuery($base, $query);\n    }\n\n    /**\n     * Redirects the client for authorization.\n     *\n     * @param  array $options\n     * @param  callable|null $redirectHandler\n     * @return mixed\n     * @throws InvalidArgumentException\n     */\n    public function authorize(\n        array $options = [],\n        ?callable $redirectHandler = null\n    ) {\n        $url = $this->getAuthorizationUrl($options);\n        if ($redirectHandler) {\n            return $redirectHandler($url, $this);\n        }\n\n        // @codeCoverageIgnoreStart\n        header('Location: ' . $url);\n        exit;\n        // @codeCoverageIgnoreEnd\n    }\n\n    /**\n     * Appends a query string to a URL.\n     *\n     * @param  string $url The URL to append the query to\n     * @param  string $query The HTTP query string\n     * @return string The resulting URL\n     */\n    protected function appendQuery($url, $query)\n    {\n        $query = trim($query, '?&');\n\n        if ($query) {\n            $glue = strstr($url, '?') === false ? '?' : '&';\n            return $url . $glue . $query;\n        }\n\n        return $url;\n    }\n\n    /**\n     * Returns the method to use when requesting an access token.\n     *\n     * @return string HTTP method\n     */\n    protected function getAccessTokenMethod()\n    {\n        return self::METHOD_POST;\n    }\n\n    /**\n     * Returns the key used in the access token response to identify the resource owner.\n     *\n     * @return string|null Resource owner identifier key\n     */\n    protected function getAccessTokenResourceOwnerId()\n    {\n        return static::ACCESS_TOKEN_RESOURCE_OWNER_ID;\n    }\n\n    /**\n     * Builds the access token URL's query string.\n     *\n     * @param  array $params Query parameters\n     * @return string Query string\n     */\n    protected function getAccessTokenQuery(array $params)\n    {\n        return $this->buildQueryString($params);\n    }\n\n    /**\n     * Checks that a provided grant is valid, or attempts to produce one if the\n     * provided grant is a string.\n     *\n     * @param  AbstractGrant|string $grant\n     * @return AbstractGrant\n     */\n    protected function verifyGrant($grant)\n    {\n        if (is_string($grant)) {\n            return $this->grantFactory->getGrant($grant);\n        }\n\n        $this->grantFactory->checkGrant($grant);\n        return $grant;\n    }\n\n    /**\n     * Returns the full URL to use when requesting an access token.\n     *\n     * @param array $params Query parameters\n     * @return string\n     */\n    protected function getAccessTokenUrl(array $params)\n    {\n        $url = $this->getBaseAccessTokenUrl($params);\n\n        if ($this->getAccessTokenMethod() === self::METHOD_GET) {\n            $query = $this->getAccessTokenQuery($params);\n            return $this->appendQuery($url, $query);\n        }\n\n        return $url;\n    }\n\n    /**\n     * Returns a prepared request for requesting an access token.\n     *\n     * @param array $params Query string parameters\n     * @return RequestInterface\n     */\n    protected function getAccessTokenRequest(array $params)\n    {\n        $method  = $this->getAccessTokenMethod();\n        $url     = $this->getAccessTokenUrl($params);\n        $options = $this->optionProvider->getAccessTokenOptions($this->getAccessTokenMethod(), $params);\n\n        return $this->getRequest($method, $url, $options);\n    }\n\n    /**\n     * Requests an access token using a specified grant and option set.\n     *\n     * @param  mixed                $grant\n     * @param  array<string, mixed> $options\n     * @return AccessTokenInterface\n     * @throws IdentityProviderException\n     * @throws UnexpectedValueException\n     * @throws GuzzleException\n     */\n    public function getAccessToken($grant, array $options = [])\n    {\n        $grant = $this->verifyGrant($grant);\n\n        if (isset($options['scope']) && is_array($options['scope'])) {\n            $separator = $this->getScopeSeparator();\n            $options['scope'] = implode($separator, $options['scope']);\n        }\n\n        $params = [\n            'client_id'     => $this->clientId,\n            'client_secret' => $this->clientSecret,\n            'redirect_uri'  => $this->redirectUri,\n        ];\n\n        if (!empty($this->pkceCode)) {\n            $params['code_verifier'] = $this->pkceCode;\n        }\n\n        $params   = $grant->prepareRequestParameters($params, $options);\n        $request  = $this->getAccessTokenRequest($params);\n        $response = $this->getParsedResponse($request);\n        if (false === is_array($response)) {\n            throw new UnexpectedValueException(\n                'Invalid response received from Authorization Server. Expected JSON.'\n            );\n        }\n        $prepared = $this->prepareAccessTokenResponse($response);\n        $token    = $this->createAccessToken($prepared, $grant);\n\n        return $token;\n    }\n\n    /**\n     * Returns a PSR-7 request instance that is not authenticated.\n     *\n     * @param  string $method\n     * @param  string $url\n     * @param  array $options\n     * @return RequestInterface\n     */\n    public function getRequest($method, $url, array $options = [])\n    {\n        return $this->createRequest($method, $url, null, $options);\n    }\n\n    /**\n     * Returns an authenticated PSR-7 request instance.\n     *\n     * @param  string $method\n     * @param  string $url\n     * @param  AccessTokenInterface|string|null $token\n     * @param  array $options Any of \"headers\", \"body\", and \"protocolVersion\".\n     * @return RequestInterface\n     */\n    public function getAuthenticatedRequest($method, $url, $token, array $options = [])\n    {\n        return $this->createRequest($method, $url, $token, $options);\n    }\n\n    /**\n     * Creates a PSR-7 request instance.\n     *\n     * @param  string $method\n     * @param  string $url\n     * @param  AccessTokenInterface|string|null $token\n     * @param  array $options\n     * @return RequestInterface\n     */\n    protected function createRequest($method, $url, $token, array $options)\n    {\n        $defaults = [\n            'headers' => $this->getHeaders($token),\n        ];\n\n        $options = array_merge_recursive($defaults, $options);\n        $factory = $this->getRequestFactory();\n\n        return $factory->getRequestWithOptions($method, $url, $options);\n    }\n\n    /**\n     * Sends a request instance and returns a response instance.\n     *\n     * WARNING: This method does not attempt to catch exceptions caused by HTTP\n     * errors! It is recommended to wrap this method in a try/catch block.\n     *\n     * @param  RequestInterface $request\n     * @return ResponseInterface\n     * @throws GuzzleException\n     */\n    public function getResponse(RequestInterface $request)\n    {\n        return $this->getHttpClient()->send($request);\n    }\n\n    /**\n     * Sends a request and returns the parsed response.\n     *\n     * @param  RequestInterface $request\n     * @return mixed\n     * @throws IdentityProviderException\n     * @throws UnexpectedValueException\n     * @throws GuzzleException\n     */\n    public function getParsedResponse(RequestInterface $request)\n    {\n        try {\n            $response = $this->getResponse($request);\n        } catch (BadResponseException $e) {\n            $response = $e->getResponse();\n        }\n\n        $parsed = $this->parseResponse($response);\n\n        $this->checkResponse($response, $parsed);\n\n        return $parsed;\n    }\n\n    /**\n     * Attempts to parse a JSON response.\n     *\n     * @param  string $content JSON content from response body\n     * @return array Parsed JSON data\n     * @throws UnexpectedValueException if the content could not be parsed\n     */\n    protected function parseJson($content)\n    {\n        $content = json_decode($content, true);\n\n        if (json_last_error() !== JSON_ERROR_NONE) {\n            throw new UnexpectedValueException(sprintf(\n                \"Failed to parse JSON response: %s\",\n                json_last_error_msg()\n            ));\n        }\n\n        return $content;\n    }\n\n    /**\n     * Returns the content type header of a response.\n     *\n     * @param  ResponseInterface $response\n     * @return string Semi-colon separated join of content-type headers.\n     */\n    protected function getContentType(ResponseInterface $response)\n    {\n        return implode(';', $response->getHeader('content-type'));\n    }\n\n    /**\n     * Parses the response according to its content-type header.\n     *\n     * @throws UnexpectedValueException\n     * @param  ResponseInterface $response\n     * @return array\n     */\n    protected function parseResponse(ResponseInterface $response)\n    {\n        $content = (string) $response->getBody();\n        $type = $this->getContentType($response);\n\n        if (strpos($type, 'urlencoded') !== false) {\n            parse_str($content, $parsed);\n            return $parsed;\n        }\n\n        // Attempt to parse the string as JSON regardless of content type,\n        // since some providers use non-standard content types. Only throw an\n        // exception if the JSON could not be parsed when it was expected to.\n        try {\n            return $this->parseJson($content);\n        } catch (UnexpectedValueException $e) {\n            if (strpos($type, 'json') !== false) {\n                throw $e;\n            }\n\n            if ($response->getStatusCode() == 500) {\n                throw new UnexpectedValueException(\n                    'An OAuth server error was encountered that did not contain a JSON body',\n                    0,\n                    $e\n                );\n            }\n\n            return $content;\n        }\n    }\n\n    /**\n     * Checks a provider response for errors.\n     *\n     * @throws IdentityProviderException\n     * @param  ResponseInterface $response\n     * @param  array|string $data Parsed response data\n     * @return void\n     */\n    abstract protected function checkResponse(ResponseInterface $response, $data);\n\n    /**\n     * Prepares an parsed access token response for a grant.\n     *\n     * Custom mapping of expiration, etc should be done here. Always call the\n     * parent method when overloading this method.\n     *\n     * @param  array<string, mixed> $result\n     * @return array\n     */\n    protected function prepareAccessTokenResponse(array $result)\n    {\n        if ($this->getAccessTokenResourceOwnerId() !== null) {\n            $result['resource_owner_id'] = $this->getValueByKey(\n                $result,\n                $this->getAccessTokenResourceOwnerId()\n            );\n        }\n        return $result;\n    }\n\n    /**\n     * Creates an access token from a response.\n     *\n     * The grant that was used to fetch the response can be used to provide\n     * additional context.\n     *\n     * @param  array $response\n     * @param  AbstractGrant $grant\n     * @return AccessTokenInterface\n     */\n    protected function createAccessToken(array $response, AbstractGrant $grant)\n    {\n        return new AccessToken($response);\n    }\n\n    /**\n     * Generates a resource owner object from a successful resource owner\n     * details request.\n     *\n     * @param  array $response\n     * @param  AccessToken $token\n     * @return ResourceOwnerInterface\n     */\n    abstract protected function createResourceOwner(array $response, AccessToken $token);\n\n    /**\n     * Requests and returns the resource owner of given access token.\n     *\n     * @param  AccessToken $token\n     * @return ResourceOwnerInterface\n     * @throws IdentityProviderException\n     * @throws UnexpectedValueException\n     * @throws GuzzleException\n     */\n    public function getResourceOwner(AccessToken $token)\n    {\n        $response = $this->fetchResourceOwnerDetails($token);\n\n        return $this->createResourceOwner($response, $token);\n    }\n\n    /**\n     * Requests resource owner details.\n     *\n     * @param  AccessToken $token\n     * @return mixed\n     * @throws IdentityProviderException\n     * @throws UnexpectedValueException\n     * @throws GuzzleException\n     */\n    protected function fetchResourceOwnerDetails(AccessToken $token)\n    {\n        $url = $this->getResourceOwnerDetailsUrl($token);\n\n        $request = $this->getAuthenticatedRequest(self::METHOD_GET, $url, $token);\n\n        $response = $this->getParsedResponse($request);\n\n        if (false === is_array($response)) {\n            throw new UnexpectedValueException(\n                'Invalid response received from Authorization Server. Expected JSON.'\n            );\n        }\n\n        return $response;\n    }\n\n    /**\n     * Returns the default headers used by this provider.\n     *\n     * Typically this is used to set 'Accept' or 'Content-Type' headers.\n     *\n     * @return array\n     */\n    protected function getDefaultHeaders()\n    {\n        return [];\n    }\n\n    /**\n     * Returns the authorization headers used by this provider.\n     *\n     * Typically this is \"Bearer\" or \"MAC\". For more information see:\n     * http://tools.ietf.org/html/rfc6749#section-7.1\n     *\n     * No default is provided, providers must overload this method to activate\n     * authorization headers.\n     *\n     * @param  mixed|null $token Either a string or an access token instance\n     * @return array\n     */\n    protected function getAuthorizationHeaders($token = null)\n    {\n        return [];\n    }\n\n    /**\n     * Returns all headers used by this provider for a request.\n     *\n     * The request will be authenticated if an access token is provided.\n     *\n     * @param  mixed|null $token object or string\n     * @return array\n     */\n    public function getHeaders($token = null)\n    {\n        if ($token) {\n            return array_merge(\n                $this->getDefaultHeaders(),\n                $this->getAuthorizationHeaders($token)\n            );\n        }\n\n        return $this->getDefaultHeaders();\n    }\n}\n"
  },
  {
    "path": "server/vendor/league/oauth2-client/src/Provider/Exception/IdentityProviderException.php",
    "content": "<?php\n/**\n * This file is part of the league/oauth2-client library\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n *\n * @copyright Copyright (c) Alex Bilbie <hello@alexbilbie.com>\n * @license http://opensource.org/licenses/MIT MIT\n * @link http://thephpleague.com/oauth2-client/ Documentation\n * @link https://packagist.org/packages/league/oauth2-client Packagist\n * @link https://github.com/thephpleague/oauth2-client GitHub\n */\n\nnamespace League\\OAuth2\\Client\\Provider\\Exception;\n\n/**\n * Exception thrown if the provider response contains errors.\n */\nclass IdentityProviderException extends \\Exception\n{\n    /**\n     * @var mixed\n     */\n    protected $response;\n\n    /**\n     * @param string $message\n     * @param int $code\n     * @param mixed $response The response body\n     */\n    public function __construct($message, $code, $response)\n    {\n        $this->response = $response;\n\n        parent::__construct($message, $code);\n    }\n\n    /**\n     * Returns the exception's response body.\n     *\n     * @return mixed\n     */\n    public function getResponseBody()\n    {\n        return $this->response;\n    }\n}\n"
  },
  {
    "path": "server/vendor/league/oauth2-client/src/Provider/GenericProvider.php",
    "content": "<?php\n/**\n * This file is part of the league/oauth2-client library\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n *\n * @copyright Copyright (c) Alex Bilbie <hello@alexbilbie.com>\n * @license http://opensource.org/licenses/MIT MIT\n * @link http://thephpleague.com/oauth2-client/ Documentation\n * @link https://packagist.org/packages/league/oauth2-client Packagist\n * @link https://github.com/thephpleague/oauth2-client GitHub\n */\n\nnamespace League\\OAuth2\\Client\\Provider;\n\nuse InvalidArgumentException;\nuse League\\OAuth2\\Client\\Provider\\Exception\\IdentityProviderException;\nuse League\\OAuth2\\Client\\Token\\AccessToken;\nuse League\\OAuth2\\Client\\Tool\\BearerAuthorizationTrait;\nuse Psr\\Http\\Message\\ResponseInterface;\n\n/**\n * Represents a generic service provider that may be used to interact with any\n * OAuth 2.0 service provider, using Bearer token authentication.\n */\nclass GenericProvider extends AbstractProvider\n{\n    use BearerAuthorizationTrait;\n\n    /**\n     * @var string\n     */\n    private $urlAuthorize;\n\n    /**\n     * @var string\n     */\n    private $urlAccessToken;\n\n    /**\n     * @var string\n     */\n    private $urlResourceOwnerDetails;\n\n    /**\n     * @var string\n     */\n    private $accessTokenMethod;\n\n    /**\n     * @var string\n     */\n    private $accessTokenResourceOwnerId;\n\n    /**\n     * @var array|null\n     */\n    private $scopes = null;\n\n    /**\n     * @var string\n     */\n    private $scopeSeparator;\n\n    /**\n     * @var string\n     */\n    private $responseError = 'error';\n\n    /**\n     * @var string\n     */\n    private $responseCode;\n\n    /**\n     * @var string\n     */\n    private $responseResourceOwnerId = 'id';\n\n    /**\n     * @var string|null\n     */\n    private $pkceMethod = null;\n\n    /**\n     * @param array $options\n     * @param array $collaborators\n     */\n    public function __construct(array $options = [], array $collaborators = [])\n    {\n        $this->assertRequiredOptions($options);\n\n        $possible   = $this->getConfigurableOptions();\n        $configured = array_intersect_key($options, array_flip($possible));\n\n        foreach ($configured as $key => $value) {\n            $this->$key = $value;\n        }\n\n        // Remove all options that are only used locally\n        $options = array_diff_key($options, $configured);\n\n        parent::__construct($options, $collaborators);\n    }\n\n    /**\n     * Returns all options that can be configured.\n     *\n     * @return array\n     */\n    protected function getConfigurableOptions()\n    {\n        return array_merge($this->getRequiredOptions(), [\n            'accessTokenMethod',\n            'accessTokenResourceOwnerId',\n            'scopeSeparator',\n            'responseError',\n            'responseCode',\n            'responseResourceOwnerId',\n            'scopes',\n            'pkceMethod',\n        ]);\n    }\n\n    /**\n     * Returns all options that are required.\n     *\n     * @return array\n     */\n    protected function getRequiredOptions()\n    {\n        return [\n            'urlAuthorize',\n            'urlAccessToken',\n            'urlResourceOwnerDetails',\n        ];\n    }\n\n    /**\n     * Verifies that all required options have been passed.\n     *\n     * @param  array $options\n     * @return void\n     * @throws InvalidArgumentException\n     */\n    private function assertRequiredOptions(array $options)\n    {\n        $missing = array_diff_key(array_flip($this->getRequiredOptions()), $options);\n\n        if (!empty($missing)) {\n            throw new InvalidArgumentException(\n                'Required options not defined: ' . implode(', ', array_keys($missing))\n            );\n        }\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function getBaseAuthorizationUrl()\n    {\n        return $this->urlAuthorize;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function getBaseAccessTokenUrl(array $params)\n    {\n        return $this->urlAccessToken;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function getResourceOwnerDetailsUrl(AccessToken $token)\n    {\n        return $this->urlResourceOwnerDetails;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function getDefaultScopes()\n    {\n        return $this->scopes;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    protected function getAccessTokenMethod()\n    {\n        return $this->accessTokenMethod ?: parent::getAccessTokenMethod();\n    }\n\n    /**\n     * @inheritdoc\n     */\n    protected function getAccessTokenResourceOwnerId()\n    {\n        return $this->accessTokenResourceOwnerId ?: parent::getAccessTokenResourceOwnerId();\n    }\n\n    /**\n     * @inheritdoc\n     */\n    protected function getScopeSeparator()\n    {\n        return $this->scopeSeparator ?: parent::getScopeSeparator();\n    }\n\n    /**\n     * @inheritdoc\n     */\n    protected function getPkceMethod()\n    {\n        return $this->pkceMethod ?: parent::getPkceMethod();\n    }\n\n    /**\n     * @inheritdoc\n     */\n    protected function checkResponse(ResponseInterface $response, $data)\n    {\n        if (!empty($data[$this->responseError])) {\n            $error = $data[$this->responseError];\n            if (!is_string($error)) {\n                $error = var_export($error, true);\n            }\n            $code  = $this->responseCode && !empty($data[$this->responseCode])? $data[$this->responseCode] : 0;\n            if (!is_int($code)) {\n                $code = intval($code);\n            }\n            throw new IdentityProviderException($error, $code, $data);\n        }\n    }\n\n    /**\n     * @inheritdoc\n     */\n    protected function createResourceOwner(array $response, AccessToken $token)\n    {\n        return new GenericResourceOwner($response, $this->responseResourceOwnerId);\n    }\n}\n"
  },
  {
    "path": "server/vendor/league/oauth2-client/src/Provider/GenericResourceOwner.php",
    "content": "<?php\n/**\n * This file is part of the league/oauth2-client library\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n *\n * @copyright Copyright (c) Alex Bilbie <hello@alexbilbie.com>\n * @license http://opensource.org/licenses/MIT MIT\n * @link http://thephpleague.com/oauth2-client/ Documentation\n * @link https://packagist.org/packages/league/oauth2-client Packagist\n * @link https://github.com/thephpleague/oauth2-client GitHub\n */\n\nnamespace League\\OAuth2\\Client\\Provider;\n\n/**\n * Represents a generic resource owner for use with the GenericProvider.\n */\nclass GenericResourceOwner implements ResourceOwnerInterface\n{\n    /**\n     * @var array\n     */\n    protected $response;\n\n    /**\n     * @var string\n     */\n    protected $resourceOwnerId;\n\n    /**\n     * @param array $response\n     * @param string $resourceOwnerId\n     */\n    public function __construct(array $response, $resourceOwnerId)\n    {\n        $this->response = $response;\n        $this->resourceOwnerId = $resourceOwnerId;\n    }\n\n    /**\n     * Returns the identifier of the authorized resource owner.\n     *\n     * @return mixed\n     */\n    public function getId()\n    {\n        return $this->response[$this->resourceOwnerId];\n    }\n\n    /**\n     * Returns the raw resource owner response.\n     *\n     * @return array\n     */\n    public function toArray()\n    {\n        return $this->response;\n    }\n}\n"
  },
  {
    "path": "server/vendor/league/oauth2-client/src/Provider/ResourceOwnerInterface.php",
    "content": "<?php\n/**\n * This file is part of the league/oauth2-client library\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n *\n * @copyright Copyright (c) Alex Bilbie <hello@alexbilbie.com>\n * @license http://opensource.org/licenses/MIT MIT\n * @link http://thephpleague.com/oauth2-client/ Documentation\n * @link https://packagist.org/packages/league/oauth2-client Packagist\n * @link https://github.com/thephpleague/oauth2-client GitHub\n */\n\nnamespace League\\OAuth2\\Client\\Provider;\n\n/**\n * Classes implementing `ResourceOwnerInterface` may be used to represent\n * the resource owner authenticated with a service provider.\n */\ninterface ResourceOwnerInterface\n{\n    /**\n     * Returns the identifier of the authorized resource owner.\n     *\n     * @return mixed\n     */\n    public function getId();\n\n    /**\n     * Return all of the owner details available as an array.\n     *\n     * @return array\n     */\n    public function toArray();\n}\n"
  },
  {
    "path": "server/vendor/league/oauth2-client/src/Token/AccessToken.php",
    "content": "<?php\n/**\n * This file is part of the league/oauth2-client library\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n *\n * @copyright Copyright (c) Alex Bilbie <hello@alexbilbie.com>\n * @license http://opensource.org/licenses/MIT MIT\n * @link http://thephpleague.com/oauth2-client/ Documentation\n * @link https://packagist.org/packages/league/oauth2-client Packagist\n * @link https://github.com/thephpleague/oauth2-client GitHub\n */\n\nnamespace League\\OAuth2\\Client\\Token;\n\nuse InvalidArgumentException;\nuse RuntimeException;\n\n/**\n * Represents an access token.\n *\n * @link http://tools.ietf.org/html/rfc6749#section-1.4 Access Token (RFC 6749, §1.4)\n */\nclass AccessToken implements AccessTokenInterface, ResourceOwnerAccessTokenInterface, SettableRefreshTokenInterface\n{\n    /**\n     * @var string\n     */\n    protected $accessToken;\n\n    /**\n     * @var int\n     */\n    protected $expires;\n\n    /**\n     * @var string\n     */\n    protected $refreshToken;\n\n    /**\n     * @var string\n     */\n    protected $resourceOwnerId;\n\n    /**\n     * @var array\n     */\n    protected $values = [];\n\n    /**\n     * @var int\n     */\n    private static $timeNow;\n\n    /**\n     * Set the time now. This should only be used for testing purposes.\n     *\n     * @param int $timeNow the time in seconds since epoch\n     * @return void\n     */\n    public static function setTimeNow($timeNow)\n    {\n        self::$timeNow = $timeNow;\n    }\n\n    /**\n     * Reset the time now if it was set for test purposes.\n     *\n     * @return void\n     */\n    public static function resetTimeNow()\n    {\n        self::$timeNow = null;\n    }\n\n    /**\n     * @return int\n     */\n    public function getTimeNow()\n    {\n        return self::$timeNow ? self::$timeNow : time();\n    }\n\n    /**\n     * Constructs an access token.\n     *\n     * @param array $options An array of options returned by the service provider\n     *     in the access token request. The `access_token` option is required.\n     * @throws InvalidArgumentException if `access_token` is not provided in `$options`.\n     */\n    public function __construct(array $options = [])\n    {\n        if (empty($options['access_token'])) {\n            throw new InvalidArgumentException('Required option not passed: \"access_token\"');\n        }\n\n        $this->accessToken = $options['access_token'];\n\n        if (!empty($options['resource_owner_id'])) {\n            $this->resourceOwnerId = $options['resource_owner_id'];\n        }\n\n        if (!empty($options['refresh_token'])) {\n            $this->refreshToken = $options['refresh_token'];\n        }\n\n        // We need to know when the token expires. Show preference to\n        // 'expires_in' since it is defined in RFC6749 Section 5.1.\n        // Defer to 'expires' if it is provided instead.\n        if (isset($options['expires_in'])) {\n            if (!is_numeric($options['expires_in'])) {\n                throw new \\InvalidArgumentException('expires_in value must be an integer');\n            }\n\n            $this->expires = $options['expires_in'] != 0 ? $this->getTimeNow() + $options['expires_in'] : 0;\n        } elseif (!empty($options['expires'])) {\n            // Some providers supply the seconds until expiration rather than\n            // the exact timestamp. Take a best guess at which we received.\n            $expires = (int) $options['expires'];\n\n            if (!$this->isExpirationTimestamp($expires)) {\n                $expires += $this->getTimeNow();\n            }\n\n            $this->expires = $expires;\n        }\n\n        // Capture any additional values that might exist in the token but are\n        // not part of the standard response. Vendors will sometimes pass\n        // additional user data this way.\n        $this->values = array_diff_key($options, array_flip([\n            'access_token',\n            'resource_owner_id',\n            'refresh_token',\n            'expires_in',\n            'expires',\n        ]));\n    }\n\n    /**\n     * Check if a value is an expiration timestamp or second value.\n     *\n     * @param integer $value\n     * @return bool\n     */\n    protected function isExpirationTimestamp($value)\n    {\n        // If the given value is larger than the original OAuth 2 draft date,\n        // assume that it is meant to be a (possible expired) timestamp.\n        $oauth2InceptionDate = 1349067600; // 2012-10-01\n        return ($value > $oauth2InceptionDate);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function getToken()\n    {\n        return $this->accessToken;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function getRefreshToken()\n    {\n        return $this->refreshToken;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function setRefreshToken($refreshToken)\n    {\n        $this->refreshToken = $refreshToken;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function getExpires()\n    {\n        return $this->expires;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function getResourceOwnerId()\n    {\n        return $this->resourceOwnerId;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function hasExpired()\n    {\n        $expires = $this->getExpires();\n\n        if (empty($expires)) {\n            throw new RuntimeException('\"expires\" is not set on the token');\n        }\n\n        return $expires < $this->getTimeNow();\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function getValues()\n    {\n        return $this->values;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function __toString()\n    {\n        return (string) $this->getToken();\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function jsonSerialize()\n    {\n        $parameters = $this->values;\n\n        if ($this->accessToken) {\n            $parameters['access_token'] = $this->accessToken;\n        }\n\n        if ($this->refreshToken) {\n            $parameters['refresh_token'] = $this->refreshToken;\n        }\n\n        if ($this->expires) {\n            $parameters['expires'] = $this->expires;\n        }\n\n        if ($this->resourceOwnerId) {\n            $parameters['resource_owner_id'] = $this->resourceOwnerId;\n        }\n\n        return $parameters;\n    }\n}\n"
  },
  {
    "path": "server/vendor/league/oauth2-client/src/Token/AccessTokenInterface.php",
    "content": "<?php\n/**\n * This file is part of the league/oauth2-client library\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n *\n * @copyright Copyright (c) Alex Bilbie <hello@alexbilbie.com>\n * @license http://opensource.org/licenses/MIT MIT\n * @link http://thephpleague.com/oauth2-client/ Documentation\n * @link https://packagist.org/packages/league/oauth2-client Packagist\n * @link https://github.com/thephpleague/oauth2-client GitHub\n */\n\nnamespace League\\OAuth2\\Client\\Token;\n\nuse JsonSerializable;\nuse ReturnTypeWillChange;\nuse RuntimeException;\n\ninterface AccessTokenInterface extends JsonSerializable\n{\n    /**\n     * Returns the access token string of this instance.\n     *\n     * @return string\n     */\n    public function getToken();\n\n    /**\n     * Returns the refresh token, if defined.\n     *\n     * @return string|null\n     */\n    public function getRefreshToken();\n\n    /**\n     * Returns the expiration timestamp in seconds, if defined.\n     *\n     * @return integer|null\n     */\n    public function getExpires();\n\n    /**\n     * Checks if this token has expired.\n     *\n     * @return boolean true if the token has expired, false otherwise.\n     * @throws RuntimeException if 'expires' is not set on the token.\n     */\n    public function hasExpired();\n\n    /**\n     * Returns additional vendor values stored in the token.\n     *\n     * @return array\n     */\n    public function getValues();\n\n    /**\n     * Returns a string representation of the access token\n     *\n     * @return string\n     */\n    public function __toString();\n\n    /**\n     * Returns an array of parameters to serialize when this is serialized with\n     * json_encode().\n     *\n     * @return array\n     */\n    #[ReturnTypeWillChange]\n    public function jsonSerialize();\n}\n"
  },
  {
    "path": "server/vendor/league/oauth2-client/src/Token/ResourceOwnerAccessTokenInterface.php",
    "content": "<?php\n/**\n * This file is part of the league/oauth2-client library\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n *\n * @copyright Copyright (c) Alex Bilbie <hello@alexbilbie.com>\n * @license http://opensource.org/licenses/MIT MIT\n * @link http://thephpleague.com/oauth2-client/ Documentation\n * @link https://packagist.org/packages/league/oauth2-client Packagist\n * @link https://github.com/thephpleague/oauth2-client GitHub\n */\n\nnamespace League\\OAuth2\\Client\\Token;\n\ninterface ResourceOwnerAccessTokenInterface extends AccessTokenInterface\n{\n    /**\n     * Returns the resource owner identifier, if defined.\n     *\n     * @return string|null\n     */\n    public function getResourceOwnerId();\n}\n"
  },
  {
    "path": "server/vendor/league/oauth2-client/src/Token/SettableRefreshTokenInterface.php",
    "content": "<?php\n/**\n * This file is part of the league/oauth2-client library\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n *\n * @copyright Copyright (c) Alex Bilbie <hello@alexbilbie.com>\n * @license http://opensource.org/licenses/MIT MIT\n * @link http://thephpleague.com/oauth2-client/ Documentation\n * @link https://packagist.org/packages/league/oauth2-client Packagist\n * @link https://github.com/thephpleague/oauth2-client GitHub\n */\n\nnamespace League\\OAuth2\\Client\\Token;\n\ninterface SettableRefreshTokenInterface\n{\n    /**\n     * Sets or replaces the refresh token with the provided refresh token.\n     *\n     * @param string $refreshToken\n     * @return void\n     */\n    public function setRefreshToken($refreshToken);\n}\n"
  },
  {
    "path": "server/vendor/league/oauth2-client/src/Tool/ArrayAccessorTrait.php",
    "content": "<?php\n/**\n * This file is part of the league/oauth2-client library\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n *\n * @copyright Copyright (c) Alex Bilbie <hello@alexbilbie.com>\n * @license http://opensource.org/licenses/MIT MIT\n * @link http://thephpleague.com/oauth2-client/ Documentation\n * @link https://packagist.org/packages/league/oauth2-client Packagist\n * @link https://github.com/thephpleague/oauth2-client GitHub\n */\n\nnamespace League\\OAuth2\\Client\\Tool;\n\n/**\n * Provides generic array navigation tools.\n */\ntrait ArrayAccessorTrait\n{\n    /**\n     * Returns a value by key using dot notation.\n     *\n     * @param  array      $data\n     * @param  string     $key\n     * @param  mixed|null $default\n     * @return mixed\n     */\n    private function getValueByKey(array $data, $key, $default = null)\n    {\n        if (!is_string($key) || empty($key) || !count($data)) {\n            return $default;\n        }\n\n        if (strpos($key, '.') !== false) {\n            $keys = explode('.', $key);\n\n            foreach ($keys as $innerKey) {\n                if (!is_array($data) || !array_key_exists($innerKey, $data)) {\n                    return $default;\n                }\n\n                $data = $data[$innerKey];\n            }\n\n            return $data;\n        }\n\n        return array_key_exists($key, $data) ? $data[$key] : $default;\n    }\n}\n"
  },
  {
    "path": "server/vendor/league/oauth2-client/src/Tool/BearerAuthorizationTrait.php",
    "content": "<?php\n/**\n * This file is part of the league/oauth2-client library\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n *\n * @copyright Copyright (c) Alex Bilbie <hello@alexbilbie.com>\n * @license http://opensource.org/licenses/MIT MIT\n * @link http://thephpleague.com/oauth2-client/ Documentation\n * @link https://packagist.org/packages/league/oauth2-client Packagist\n * @link https://github.com/thephpleague/oauth2-client GitHub\n */\n\nnamespace League\\OAuth2\\Client\\Tool;\n\nuse League\\OAuth2\\Client\\Token\\AccessTokenInterface;\n\n/**\n * Enables `Bearer` header authorization for providers.\n *\n * @link http://tools.ietf.org/html/rfc6750 Bearer Token Usage (RFC 6750)\n */\ntrait BearerAuthorizationTrait\n{\n    /**\n     * Returns authorization headers for the 'bearer' grant.\n     *\n     * @param  AccessTokenInterface|string|null $token Either a string or an access token instance\n     * @return array\n     */\n    protected function getAuthorizationHeaders($token = null)\n    {\n        return ['Authorization' => 'Bearer ' . $token];\n    }\n}\n"
  },
  {
    "path": "server/vendor/league/oauth2-client/src/Tool/GuardedPropertyTrait.php",
    "content": "<?php\n/**\n * This file is part of the league/oauth2-client library\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n *\n * @copyright Copyright (c) Alex Bilbie <hello@alexbilbie.com>\n * @license http://opensource.org/licenses/MIT MIT\n * @link http://thephpleague.com/oauth2-client/ Documentation\n * @link https://packagist.org/packages/league/oauth2-client Packagist\n * @link https://github.com/thephpleague/oauth2-client GitHub\n */\n\nnamespace League\\OAuth2\\Client\\Tool;\n\n/**\n * Provides support for blacklisting explicit properties from the\n * mass assignment behavior.\n */\ntrait GuardedPropertyTrait\n{\n    /**\n     * The properties that aren't mass assignable.\n     *\n     * @var array\n     */\n    protected $guarded = [];\n\n    /**\n     * Attempts to mass assign the given options to explicitly defined properties,\n     * skipping over any properties that are defined in the guarded array.\n     *\n     * @param array $options\n     * @return mixed\n     */\n    protected function fillProperties(array $options = [])\n    {\n        if (isset($options['guarded'])) {\n            unset($options['guarded']);\n        }\n\n        foreach ($options as $option => $value) {\n            if (property_exists($this, $option) && !$this->isGuarded($option)) {\n                $this->{$option} = $value;\n            }\n        }\n    }\n\n    /**\n     * Returns current guarded properties.\n     *\n     * @return array\n     */\n    public function getGuarded()\n    {\n        return $this->guarded;\n    }\n\n    /**\n     * Determines if the given property is guarded.\n     *\n     * @param  string  $property\n     * @return bool\n     */\n    public function isGuarded($property)\n    {\n        return in_array($property, $this->getGuarded());\n    }\n}\n"
  },
  {
    "path": "server/vendor/league/oauth2-client/src/Tool/MacAuthorizationTrait.php",
    "content": "<?php\n/**\n * This file is part of the league/oauth2-client library\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n *\n * @copyright Copyright (c) Alex Bilbie <hello@alexbilbie.com>\n * @license http://opensource.org/licenses/MIT MIT\n * @link http://thephpleague.com/oauth2-client/ Documentation\n * @link https://packagist.org/packages/league/oauth2-client Packagist\n * @link https://github.com/thephpleague/oauth2-client GitHub\n */\n\nnamespace League\\OAuth2\\Client\\Tool;\n\nuse League\\OAuth2\\Client\\Token\\AccessToken;\nuse League\\OAuth2\\Client\\Token\\AccessTokenInterface;\n\n/**\n * Enables `MAC` header authorization for providers.\n *\n * @link http://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-05 Message Authentication Code (MAC) Tokens\n */\ntrait MacAuthorizationTrait\n{\n    /**\n     * Returns the id of this token for MAC generation.\n     *\n     * @param  AccessToken $token\n     * @return string\n     */\n    abstract protected function getTokenId(AccessToken $token);\n\n    /**\n     * Returns the MAC signature for the current request.\n     *\n     * @param  string $id\n     * @param  integer $ts\n     * @param  string $nonce\n     * @return string\n     */\n    abstract protected function getMacSignature($id, $ts, $nonce);\n\n    /**\n     * Returns a new random string to use as the state parameter in an\n     * authorization flow.\n     *\n     * @param  int $length Length of the random string to be generated.\n     * @return string\n     */\n    abstract protected function getRandomState($length = 32);\n\n    /**\n     * Returns the authorization headers for the 'mac' grant.\n     *\n     * @param  AccessTokenInterface|string|null $token Either a string or an access token instance\n     * @return array\n     * @codeCoverageIgnore\n     *\n     * @todo This is currently untested and provided only as an example. If you\n     * complete the implementation, please create a pull request for\n     * https://github.com/thephpleague/oauth2-client\n     */\n    protected function getAuthorizationHeaders($token = null)\n    {\n        if ($token === null) {\n            return [];\n        }\n\n        $ts    = time();\n        $id    = $this->getTokenId($token);\n        $nonce = $this->getRandomState(16);\n        $mac   = $this->getMacSignature($id, $ts, $nonce);\n\n        $parts = [];\n        foreach (compact('id', 'ts', 'nonce', 'mac') as $key => $value) {\n            $parts[] = sprintf('%s=\"%s\"', $key, $value);\n        }\n\n        return ['Authorization' => 'MAC ' . implode(', ', $parts)];\n    }\n}\n"
  },
  {
    "path": "server/vendor/league/oauth2-client/src/Tool/ProviderRedirectTrait.php",
    "content": "<?php\n\nnamespace League\\OAuth2\\Client\\Tool;\n\nuse GuzzleHttp\\Exception\\BadResponseException;\nuse GuzzleHttp\\Psr7\\Uri;\nuse InvalidArgumentException;\nuse Psr\\Http\\Message\\RequestInterface;\nuse Psr\\Http\\Message\\ResponseInterface;\n\ntrait ProviderRedirectTrait\n{\n    /**\n     * Maximum number of times to follow provider initiated redirects\n     *\n     * @var integer\n     */\n    protected $redirectLimit = 2;\n\n    /**\n     * Retrieves a response for a given request and retrieves subsequent\n     * responses, with authorization headers, if a redirect is detected.\n     *\n     * @param  RequestInterface $request\n     * @return ResponseInterface\n     * @throws BadResponseException\n     */\n    protected function followRequestRedirects(RequestInterface $request)\n    {\n        $response = null;\n        $attempts = 0;\n\n        while ($attempts < $this->redirectLimit) {\n            $attempts++;\n            $response = $this->getHttpClient()->send($request, [\n                'allow_redirects' => false\n            ]);\n\n            if ($this->isRedirect($response)) {\n                $redirectUrl = new Uri($response->getHeader('Location')[0]);\n                $request = $request->withUri($redirectUrl);\n            } else {\n                break;\n            }\n        }\n\n        return $response;\n    }\n\n    /**\n     * Returns the HTTP client instance.\n     *\n     * @return GuzzleHttp\\ClientInterface\n     */\n    abstract public function getHttpClient();\n\n    /**\n     * Retrieves current redirect limit.\n     *\n     * @return integer\n     */\n    public function getRedirectLimit()\n    {\n        return $this->redirectLimit;\n    }\n\n    /**\n     * Determines if a given response is a redirect.\n     *\n     * @param  ResponseInterface  $response\n     *\n     * @return boolean\n     */\n    protected function isRedirect(ResponseInterface $response)\n    {\n        $statusCode = $response->getStatusCode();\n\n        return $statusCode > 300 && $statusCode < 400 && $response->hasHeader('Location');\n    }\n\n    /**\n     * Sends a request instance and returns a response instance.\n     *\n     * WARNING: This method does not attempt to catch exceptions caused by HTTP\n     * errors! It is recommended to wrap this method in a try/catch block.\n     *\n     * @param  RequestInterface $request\n     * @return ResponseInterface\n     */\n    public function getResponse(RequestInterface $request)\n    {\n        try {\n            $response = $this->followRequestRedirects($request);\n        } catch (BadResponseException $e) {\n            $response = $e->getResponse();\n        }\n\n        return $response;\n    }\n\n    /**\n     * Updates the redirect limit.\n     *\n     * @param integer $limit\n     * @return League\\OAuth2\\Client\\Provider\\AbstractProvider\n     * @throws InvalidArgumentException\n     */\n    public function setRedirectLimit($limit)\n    {\n        if (!is_int($limit)) {\n            throw new InvalidArgumentException('redirectLimit must be an integer.');\n        }\n\n        if ($limit < 1) {\n            throw new InvalidArgumentException('redirectLimit must be greater than or equal to one.');\n        }\n\n        $this->redirectLimit = $limit;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "server/vendor/league/oauth2-client/src/Tool/QueryBuilderTrait.php",
    "content": "<?php\n/**\n * This file is part of the league/oauth2-client library\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n *\n * @copyright Copyright (c) Alex Bilbie <hello@alexbilbie.com>\n * @license http://opensource.org/licenses/MIT MIT\n * @link http://thephpleague.com/oauth2-client/ Documentation\n * @link https://packagist.org/packages/league/oauth2-client Packagist\n * @link https://github.com/thephpleague/oauth2-client GitHub\n */\n\nnamespace League\\OAuth2\\Client\\Tool;\n\n/**\n * Provides a standard way to generate query strings.\n */\ntrait QueryBuilderTrait\n{\n    /**\n     * Build a query string from an array.\n     *\n     * @param array $params\n     *\n     * @return string\n     */\n    protected function buildQueryString(array $params)\n    {\n        return http_build_query($params, '', '&', \\PHP_QUERY_RFC3986);\n    }\n}\n"
  },
  {
    "path": "server/vendor/league/oauth2-client/src/Tool/RequestFactory.php",
    "content": "<?php\n/**\n * This file is part of the league/oauth2-client library\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n *\n * @copyright Copyright (c) Alex Bilbie <hello@alexbilbie.com>\n * @license http://opensource.org/licenses/MIT MIT\n * @link http://thephpleague.com/oauth2-client/ Documentation\n * @link https://packagist.org/packages/league/oauth2-client Packagist\n * @link https://github.com/thephpleague/oauth2-client GitHub\n */\n\nnamespace League\\OAuth2\\Client\\Tool;\n\nuse GuzzleHttp\\Psr7\\Request;\n\n/**\n * Used to produce PSR-7 Request instances.\n *\n * @link https://github.com/guzzle/guzzle/pull/1101\n */\nclass RequestFactory\n{\n    /**\n     * Creates a PSR-7 Request instance.\n     *\n     * @param  null|string $method HTTP method for the request.\n     * @param  null|string $uri URI for the request.\n     * @param  array $headers Headers for the message.\n     * @param  string|resource|StreamInterface $body Message body.\n     * @param  string $version HTTP protocol version.\n     *\n     * @return Request\n     */\n    public function getRequest(\n        $method,\n        $uri,\n        array $headers = [],\n        $body = null,\n        $version = '1.1'\n    ) {\n        return new Request($method, $uri, $headers, $body, $version);\n    }\n\n    /**\n     * Parses simplified options.\n     *\n     * @param array $options Simplified options.\n     *\n     * @return array Extended options for use with getRequest.\n     */\n    protected function parseOptions(array $options)\n    {\n        // Should match default values for getRequest\n        $defaults = [\n            'headers' => [],\n            'body'    => null,\n            'version' => '1.1',\n        ];\n\n        return array_merge($defaults, $options);\n    }\n\n    /**\n     * Creates a request using a simplified array of options.\n     *\n     * @param  null|string $method\n     * @param  null|string $uri\n     * @param  array $options\n     *\n     * @return Request\n     */\n    public function getRequestWithOptions($method, $uri, array $options = [])\n    {\n        $options = $this->parseOptions($options);\n\n        return $this->getRequest(\n            $method,\n            $uri,\n            $options['headers'],\n            $options['body'],\n            $options['version']\n        );\n    }\n}\n"
  },
  {
    "path": "server/vendor/league/oauth2-client/src/Tool/RequiredParameterTrait.php",
    "content": "<?php\n/**\n * This file is part of the league/oauth2-client library\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n *\n * @copyright Copyright (c) Alex Bilbie <hello@alexbilbie.com>\n * @license http://opensource.org/licenses/MIT MIT\n * @link http://thephpleague.com/oauth2-client/ Documentation\n * @link https://packagist.org/packages/league/oauth2-client Packagist\n * @link https://github.com/thephpleague/oauth2-client GitHub\n */\n\nnamespace League\\OAuth2\\Client\\Tool;\n\nuse BadMethodCallException;\n\n/**\n * Provides functionality to check for required parameters.\n */\ntrait RequiredParameterTrait\n{\n    /**\n     * Checks for a required parameter in a hash.\n     *\n     * @throws BadMethodCallException\n     * @param  string $name\n     * @param  array  $params\n     * @return void\n     */\n    private function checkRequiredParameter($name, array $params)\n    {\n        if (!isset($params[$name])) {\n            throw new BadMethodCallException(sprintf(\n                'Required parameter not passed: \"%s\"',\n                $name\n            ));\n        }\n    }\n\n    /**\n     * Checks for multiple required parameters in a hash.\n     *\n     * @throws InvalidArgumentException\n     * @param  array $names\n     * @param  array $params\n     * @return void\n     */\n    private function checkRequiredParameters(array $names, array $params)\n    {\n        foreach ($names as $name) {\n            $this->checkRequiredParameter($name, $params);\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/.phpstorm.meta.php",
    "content": "<?php\nnamespace PHPSTORM_META {\n    registerArgumentsSet(\"date_units\", \"millenania\", \"millennium\", \"century\", \"centuries\", \"decade\", \"decades\", \"year\", \"years\", \"y\", \"yr\", \"yrs\", \"quarter\", \"quarters\", \"month\", \"months\", \"mo\", \"mos\", \"week\", \"weeks\", \"w\", \"day\", \"days\", \"d\", \"hour\", \"hours\", \"h\", \"minute\", \"minutes\", \"m\", \"second\", \"seconds\", \"s\", \"millisecond\", \"milliseconds\", \"milli\", \"ms\", \"microsecond\", \"microseconds\", \"micro\", \"µs\");\n    expectedArguments(\\Carbon\\Traits\\Units::add(), 0, argumentsSet(\"date_units\"));\n    expectedArguments(\\Carbon\\Traits\\Units::add(), 1, argumentsSet(\"date_units\"));\n    expectedArguments(\\Carbon\\CarbonInterface::add(), 0, argumentsSet(\"date_units\"));\n    expectedArguments(\\Carbon\\CarbonInterface::add(), 1, argumentsSet(\"date_units\"));\n\n    expectedArguments(\\Carbon\\CarbonInterface::getTimeFormatByPrecision(), 0, \"minute\", \"second\", \"m\", \"millisecond\", \"µ\", \"microsecond\", \"minutes\", \"seconds\", \"ms\", \"milliseconds\", \"µs\", \"microseconds\");\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/LICENSE",
    "content": "Copyright (C) Brian Nesbitt\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is furnished\nto do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/bin/carbon",
    "content": "#!/usr/bin/env php\n<?php\n\nuse Carbon\\Cli\\Invoker;\n\n$dir = __DIR__.'/..';\n\nif (!file_exists($dir.'/autoload.php')) {\n    $dir = __DIR__.'/../vendor';\n}\n\nif (!file_exists($dir.'/autoload.php')) {\n    $dir = __DIR__.'/../../..';\n}\n\nif (!file_exists($dir.'/autoload.php')) {\n    echo 'Autoload not found.';\n    exit(1);\n}\n\nrequire $dir.'/autoload.php';\n\nexit((new Invoker())(...$argv) ? 0 : 1);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/bin/carbon.bat",
    "content": "@ECHO OFF\nsetlocal DISABLEDELAYEDEXPANSION\nSET BIN_TARGET=%~dp0/carbon\nphp \"%BIN_TARGET%\" %*\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/composer.json",
    "content": "{\n    \"name\": \"nesbot/carbon\",\n    \"description\": \"An API extension for DateTime that supports 281 different languages.\",\n    \"license\": \"MIT\",\n    \"type\": \"library\",\n    \"keywords\": [\n        \"date\",\n        \"time\",\n        \"DateTime\"\n    ],\n    \"authors\": [\n        {\n            \"name\": \"Brian Nesbitt\",\n            \"email\": \"brian@nesbot.com\",\n            \"homepage\": \"https://markido.com\"\n        },\n        {\n            \"name\": \"kylekatarnls\",\n            \"homepage\": \"https://github.com/kylekatarnls\"\n        }\n    ],\n    \"homepage\": \"https://carbon.nesbot.com\",\n    \"support\": {\n        \"issues\": \"https://github.com/briannesbitt/Carbon/issues\",\n        \"source\": \"https://github.com/briannesbitt/Carbon\",\n        \"docs\": \"https://carbon.nesbot.com/docs\"\n    },\n    \"funding\": [\n        {\n            \"url\": \"https://github.com/sponsors/kylekatarnls\",\n            \"type\": \"github\"\n        },\n        {\n            \"url\": \"https://tidelift.com/subscription/pkg/packagist-nesbot-carbon?utm_source=packagist-nesbot-carbon&utm_medium=referral&utm_campaign=readme\",\n            \"type\": \"tidelift\"\n        },\n        {\n            \"url\": \"https://opencollective.com/Carbon#sponsor\",\n            \"type\": \"opencollective\"\n        }\n    ],\n    \"require\": {\n        \"php\": \"^7.1.8 || ^8.0\",\n        \"ext-json\": \"*\",\n        \"carbonphp/carbon-doctrine-types\": \"*\",\n        \"psr/clock\": \"^1.0\",\n        \"symfony/polyfill-mbstring\": \"^1.0\",\n        \"symfony/polyfill-php80\": \"^1.16\",\n        \"symfony/translation\": \"^3.4 || ^4.0 || ^5.0 || ^6.0\"\n    },\n    \"require-dev\": {\n        \"doctrine/dbal\": \"^2.0 || ^3.1.4 || ^4.0\",\n        \"doctrine/orm\": \"^2.7 || ^3.0\",\n        \"friendsofphp/php-cs-fixer\": \"^3.0\",\n        \"kylekatarnls/multi-tester\": \"^2.0\",\n        \"ondrejmirtes/better-reflection\": \"<6\",\n        \"phpmd/phpmd\": \"^2.9\",\n        \"phpstan/extension-installer\": \"^1.0\",\n        \"phpstan/phpstan\": \"^0.12.99 || ^1.7.14\",\n        \"phpunit/php-file-iterator\": \"^2.0.5 || ^3.0.6\",\n        \"phpunit/phpunit\": \"^7.5.20 || ^8.5.26 || ^9.5.20\",\n        \"squizlabs/php_codesniffer\": \"^3.4\"\n    },\n    \"provide\": {\n        \"psr/clock-implementation\": \"1.0\"\n    },\n    \"minimum-stability\": \"dev\",\n    \"prefer-stable\": true,\n    \"autoload\": {\n        \"psr-4\": {\n            \"Carbon\\\\\": \"src/Carbon/\"\n        }\n    },\n    \"autoload-dev\": {\n        \"psr-4\": {\n            \"Tests\\\\\": \"tests/\"\n        },\n        \"files\": [\n            \"tests/Laravel/ServiceProvider.php\"\n        ]\n    },\n    \"bin\": [\n        \"bin/carbon\"\n    ],\n    \"config\": {\n        \"allow-plugins\": {\n            \"phpstan/extension-installer\": true,\n            \"composer/package-versions-deprecated\": true\n        },\n        \"process-timeout\": 0,\n        \"sort-packages\": true\n    },\n    \"extra\": {\n        \"branch-alias\": {\n            \"dev-master\": \"3.x-dev\",\n            \"dev-2.x\": \"2.x-dev\"\n        },\n        \"laravel\": {\n            \"providers\": [\n                \"Carbon\\\\Laravel\\\\ServiceProvider\"\n            ]\n        },\n        \"phpstan\": {\n            \"includes\": [\n                \"extension.neon\"\n            ]\n        }\n    },\n    \"scripts\": {\n        \"phpcs\": \"php-cs-fixer fix -v --diff --dry-run\",\n        \"phpdoc\": \"php phpdoc.php\",\n        \"phpmd\": \"phpmd src text /phpmd.xml\",\n        \"phpmd-test\": \"phpmd tests text /tests/phpmd-test.xml\",\n        \"phpstan\": \"phpstan analyse --configuration phpstan.neon\",\n        \"phpunit\": \"phpunit --verbose\",\n        \"style-check\": [\n            \"@phpcs\",\n            \"@phpstan\",\n            \"@phpmd\"\n        ],\n        \"test\": [\n            \"@phpunit\",\n            \"@style-check\"\n        ],\n        \"sponsors\": \"php sponsors.php\"\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/extension.neon",
    "content": "services:\n    -\n        class: Carbon\\PHPStan\\MacroExtension\n        tags:\n            - phpstan.broker.methodsClassReflectionExtension\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/lazy/Carbon/MessageFormatter/MessageFormatterMapperStrongType.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\MessageFormatter;\n\nuse Symfony\\Component\\Translation\\Formatter\\MessageFormatterInterface;\n\nif (!class_exists(LazyMessageFormatter::class, false)) {\n    abstract class LazyMessageFormatter implements MessageFormatterInterface\n    {\n        public function format(string $message, string $locale, array $parameters = []): string\n        {\n            return $this->formatter->format(\n                $message,\n                $this->transformLocale($locale),\n                $parameters\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/lazy/Carbon/MessageFormatter/MessageFormatterMapperWeakType.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\MessageFormatter;\n\nuse Symfony\\Component\\Translation\\Formatter\\ChoiceMessageFormatterInterface;\nuse Symfony\\Component\\Translation\\Formatter\\MessageFormatterInterface;\n\nif (!class_exists(LazyMessageFormatter::class, false)) {\n    abstract class LazyMessageFormatter implements MessageFormatterInterface, ChoiceMessageFormatterInterface\n    {\n        abstract protected function transformLocale(?string $locale): ?string;\n\n        public function format($message, $locale, array $parameters = [])\n        {\n            return $this->formatter->format(\n                $message,\n                $this->transformLocale($locale),\n                $parameters\n            );\n        }\n\n        public function choiceFormat($message, $number, $locale, array $parameters = [])\n        {\n            return $this->formatter->choiceFormat($message, $number, $locale, $parameters);\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/lazy/Carbon/PHPStan/AbstractMacroBuiltin.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\PHPStan;\n\nuse PHPStan\\BetterReflection\\Reflection;\nuse ReflectionMethod;\n\nif (!class_exists(AbstractReflectionMacro::class, false)) {\n    abstract class AbstractReflectionMacro extends AbstractMacro\n    {\n        /**\n         * {@inheritdoc}\n         */\n        public function getReflection(): ?ReflectionMethod\n        {\n            if ($this->reflectionFunction instanceof Reflection\\ReflectionMethod) {\n                return new Reflection\\Adapter\\ReflectionMethod($this->reflectionFunction);\n            }\n\n            return $this->reflectionFunction instanceof ReflectionMethod\n                ? $this->reflectionFunction\n                : null;\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/lazy/Carbon/PHPStan/AbstractMacroStatic.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\PHPStan;\n\nuse PHPStan\\BetterReflection\\Reflection;\nuse ReflectionMethod;\n\nif (!class_exists(AbstractReflectionMacro::class, false)) {\n    abstract class AbstractReflectionMacro extends AbstractMacro\n    {\n        /**\n         * {@inheritdoc}\n         */\n        public function getReflection(): ?Reflection\\Adapter\\ReflectionMethod\n        {\n            if ($this->reflectionFunction instanceof Reflection\\Adapter\\ReflectionMethod) {\n                return $this->reflectionFunction;\n            }\n\n            if ($this->reflectionFunction instanceof Reflection\\ReflectionMethod) {\n                return new Reflection\\Adapter\\ReflectionMethod($this->reflectionFunction);\n            }\n\n            return $this->reflectionFunction instanceof ReflectionMethod\n                ? new Reflection\\Adapter\\ReflectionMethod(\n                    Reflection\\ReflectionMethod::createFromName(\n                        $this->reflectionFunction->getDeclaringClass()->getName(),\n                        $this->reflectionFunction->getName()\n                    )\n                )\n                : null;\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/lazy/Carbon/PHPStan/MacroStrongType.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\PHPStan;\n\nif (!class_exists(LazyMacro::class, false)) {\n    abstract class LazyMacro extends AbstractReflectionMacro\n    {\n        /**\n         * {@inheritdoc}\n         */\n        public function getFileName(): ?string\n        {\n            $file = $this->reflectionFunction->getFileName();\n\n            return (($file ? realpath($file) : null) ?: $file) ?: null;\n        }\n\n        /**\n         * {@inheritdoc}\n         */\n        public function getStartLine(): ?int\n        {\n            return $this->reflectionFunction->getStartLine();\n        }\n\n        /**\n         * {@inheritdoc}\n         */\n        public function getEndLine(): ?int\n        {\n            return $this->reflectionFunction->getEndLine();\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/lazy/Carbon/PHPStan/MacroWeakType.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\PHPStan;\n\nif (!class_exists(LazyMacro::class, false)) {\n    abstract class LazyMacro extends AbstractReflectionMacro\n    {\n        /**\n         * {@inheritdoc}\n         *\n         * @return string|false\n         */\n        public function getFileName()\n        {\n            $file = $this->reflectionFunction->getFileName();\n\n            return (($file ? realpath($file) : null) ?: $file) ?: null;\n        }\n\n        /**\n         * {@inheritdoc}\n         *\n         * @return int|false\n         */\n        public function getStartLine()\n        {\n            return $this->reflectionFunction->getStartLine();\n        }\n\n        /**\n         * {@inheritdoc}\n         *\n         * @return int|false\n         */\n        public function getEndLine()\n        {\n            return $this->reflectionFunction->getEndLine();\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/lazy/Carbon/TranslatorStrongType.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon;\n\nuse Symfony\\Component\\Translation\\MessageCatalogueInterface;\n\nif (!class_exists(LazyTranslator::class, false)) {\n    class LazyTranslator extends AbstractTranslator implements TranslatorStrongTypeInterface\n    {\n        public function trans(?string $id, array $parameters = [], ?string $domain = null, ?string $locale = null): string\n        {\n            return $this->translate($id, $parameters, $domain, $locale);\n        }\n\n        public function getFromCatalogue(MessageCatalogueInterface $catalogue, string $id, string $domain = 'messages')\n        {\n            $messages = $this->getPrivateProperty($catalogue, 'messages');\n\n            if (isset($messages[$domain.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX][$id])) {\n                return $messages[$domain.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX][$id];\n            }\n\n            if (isset($messages[$domain][$id])) {\n                return $messages[$domain][$id];\n            }\n\n            $fallbackCatalogue = $this->getPrivateProperty($catalogue, 'fallbackCatalogue');\n\n            if ($fallbackCatalogue !== null) {\n                return $this->getFromCatalogue($fallbackCatalogue, $id, $domain);\n            }\n\n            return $id;\n        }\n\n        private function getPrivateProperty($instance, string $field)\n        {\n            return (function (string $field) {\n                return $this->$field;\n            })->call($instance, $field);\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/lazy/Carbon/TranslatorWeakType.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon;\n\nif (!class_exists(LazyTranslator::class, false)) {\n    class LazyTranslator extends AbstractTranslator\n    {\n        /**\n         * Returns the translation.\n         *\n         * @param string|null $id\n         * @param array       $parameters\n         * @param string|null $domain\n         * @param string|null $locale\n         *\n         * @return string\n         */\n        public function trans($id, array $parameters = [], $domain = null, $locale = null)\n        {\n            return $this->translate($id, $parameters, $domain, $locale);\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/readme.md",
    "content": "# Carbon\n\n[![Latest Stable Version](https://img.shields.io/packagist/v/nesbot/carbon.svg?style=flat-square)](https://packagist.org/packages/nesbot/carbon)\n[![Total Downloads](https://img.shields.io/packagist/dt/nesbot/carbon.svg?style=flat-square)](https://packagist.org/packages/nesbot/carbon)\n[![GitHub Actions](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Factions-badge.atrox.dev%2Fbriannesbitt%2FCarbon%2Fbadge&style=flat-square&label=Build&logo=none)](https://github.com/briannesbitt/Carbon/actions)\n[![codecov.io](https://img.shields.io/codecov/c/github/briannesbitt/Carbon.svg?style=flat-square)](https://codecov.io/github/briannesbitt/Carbon?branch=master)\n[![Tidelift](https://tidelift.com/badges/github/briannesbitt/Carbon)](https://tidelift.com/subscription/pkg/packagist-nesbot-carbon?utm_source=packagist-nesbot-carbon&utm_medium=referral&utm_campaign=readme)\n\nAn international PHP extension for DateTime. [https://carbon.nesbot.com](https://carbon.nesbot.com)\n\n```php\n<?php\n\nuse Carbon\\Carbon;\n\nprintf(\"Right now is %s\", Carbon::now()->toDateTimeString());\nprintf(\"Right now in Vancouver is %s\", Carbon::now('America/Vancouver'));  //implicit __toString()\n$tomorrow = Carbon::now()->addDay();\n$lastWeek = Carbon::now()->subWeek();\n$nextSummerOlympics = Carbon::createFromDate(2016)->addYears(4);\n\n$officialDate = Carbon::now()->toRfc2822String();\n\n$howOldAmI = Carbon::createFromDate(1975, 5, 21)->age;\n\n$noonTodayLondonTime = Carbon::createFromTime(12, 0, 0, 'Europe/London');\n\n$internetWillBlowUpOn = Carbon::create(2038, 01, 19, 3, 14, 7, 'GMT');\n\n// Don't really want this to happen so mock now\nCarbon::setTestNow(Carbon::createFromDate(2000, 1, 1));\n\n// comparisons are always done in UTC\nif (Carbon::now()->gte($internetWillBlowUpOn)) {\n    die();\n}\n\n// Phew! Return to normal behaviour\nCarbon::setTestNow();\n\nif (Carbon::now()->isWeekend()) {\n    echo 'Party!';\n}\n// Over 200 languages (and over 500 regional variants) supported:\necho Carbon::now()->subMinutes(2)->diffForHumans(); // '2 minutes ago'\necho Carbon::now()->subMinutes(2)->locale('zh_CN')->diffForHumans(); // '2分钟前'\necho Carbon::parse('2019-07-23 14:51')->isoFormat('LLLL'); // 'Tuesday, July 23, 2019 2:51 PM'\necho Carbon::parse('2019-07-23 14:51')->locale('fr_FR')->isoFormat('LLLL'); // 'mardi 23 juillet 2019 14:51'\n\n// ... but also does 'from now', 'after' and 'before'\n// rolling up to seconds, minutes, hours, days, months, years\n\n$daysSinceEpoch = Carbon::createFromTimestamp(0)->diffInDays();\n```\n\n[Get supported nesbot/carbon with the Tidelift Subscription](https://tidelift.com/subscription/pkg/packagist-nesbot-carbon?utm_source=packagist-nesbot-carbon&utm_medium=referral&utm_campaign=readme)\n\n## Installation\n\n### With Composer\n\n```\n$ composer require nesbot/carbon\n```\n\n```json\n{\n    \"require\": {\n        \"nesbot/carbon\": \"^2.16\"\n    }\n}\n```\n\n```php\n<?php\nrequire 'vendor/autoload.php';\n\nuse Carbon\\Carbon;\n\nprintf(\"Now: %s\", Carbon::now());\n```\n\n### Without Composer\n\nWhy are you not using [composer](https://getcomposer.org/)? Download the Carbon [latest release](https://github.com/briannesbitt/Carbon/releases) and put the contents of the ZIP archive into a directory in your project. Then require the file `autoload.php` to get all classes and dependencies loaded on need.\n\n```php\n<?php\nrequire 'path-to-Carbon-directory/autoload.php';\n\nuse Carbon\\Carbon;\n\nprintf(\"Now: %s\", Carbon::now());\n```\n\n## Docs\n\n[https://carbon.nesbot.com/docs](https://carbon.nesbot.com/docs)\n\n## Security contact information\n\nTo report a security vulnerability, please use the\n[Tidelift security contact](https://tidelift.com/security).\nTidelift will coordinate the fix and disclosure.\n\n## Credits\n\n### Contributors\n\nThis project exists thanks to all the people who contribute. \n\n<a href=\"https://github.com/briannesbitt/Carbon/graphs/contributors\" target=\"_blank\"><img src=\"https://opencollective.com/Carbon/contributors.svg?width=890&button=false\" /></a>\n\n### Translators\n\n[Thanks to people helping us to translate Carbon in so many languages](https://carbon.nesbot.com/contribute/translators/)\n\n### Sponsors\n\nSupport this project by becoming a sponsor. Your logo will show up here with a link to your website.\n\n<a href=\"https://tidelift.com/subscription/pkg/packagist-nesbot-carbon?utm_source=packagist-nesbot-carbon&utm_medium=referral&utm_campaign=readme\" target=\"_blank\"><img src=\"https://carbon.nesbot.com/tidelift-brand.png\" width=\"256\" height=\"64\"></a><!-- <open-collective-sponsors> -->\n<a title=\"Онлайн казино 777 Україна\" href=\"https://777.ua/?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon\" target=\"_blank\"><img alt=\"Онлайн казино\" src=\"https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/7e572d50-1ce8-4d69-ae12-86cc80371373/ok-ua-777.png\" width=\"64\" height=\"64\"></a>\n<a title=\"#1 Guide To Online Gambling In Canada\" href=\"https://casinohex.org/canada/?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon\" target=\"_blank\"><img alt=\"CasinoHex Canada\" src=\"https://opencollective-production.s3.us-west-1.amazonaws.com/79fdbcc0-a997-11eb-abbc-25e48b63c6dc.jpg\" width=\"85\" height=\"64\"></a>\n<a title=\"Znajdź najlepsze zakłady bukmacherskie w Polsce w 2023 roku. Probukmacher.pl to Twoje kompendium wiedzy na temat bukmacherów!\" href=\"https://www.probukmacher.pl?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon\" target=\"_blank\"><img alt=\"Probukmacher\" src=\"https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/caf50271-4560-4ffe-a434-ea15239168db/Screenshot_1.png\" width=\"89\" height=\"64\"></a>\n<a title=\"Casino-portugal.pt\" href=\"https://casino-portugal.pt/?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon\" target=\"_blank\"><img alt=\"Casino-portugal.pt\" src=\"https://logo.clearbit.com/casino-portugal.pt\" width=\"64\" height=\"64\"></a>\n<a title=\"Gives a fun for our users\" href=\"https://slotoking.ua/games/?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon\" target=\"_blank\"><img alt=\"Игровые автоматы\" src=\"https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/94601d07-3205-4c60-9c2d-9b8194dbefb7/skg-blue.png\" width=\"64\" height=\"64\"></a>\n<a title=\"Slots City® ➢ Лучшее лицензионно казино онлайн и оффлайн на гривны в Украине. 【 Более1500 игровых автоматов и слотов】✅ Официально и Безопасно\" href=\"https://slotscity.ua/?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon\" target=\"_blank\"><img alt=\"Slots City\" src=\"https://opencollective-production.s3.us-west-1.amazonaws.com/d7e298c0-7abe-11ed-8553-230872f5e54d.png\" width=\"90\" height=\"64\"></a>\n<a title=\"inkedin\" href=\"https://inkedin.com?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon\" target=\"_blank\"><img alt=\"inkedin\" src=\"https://logo.clearbit.com/inkedin.com\" width=\"64\" height=\"64\"></a>\n<a title=\"Актуальний та повносправний рейтинг онлайн казино України, ґрунтований на відгуках реальних гравців.\" href=\"https://uk.onlinecasino.in.ua/?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon\" target=\"_blank\"><img alt=\"Онлайн казино України\" src=\"https://opencollective-production.s3.us-west-1.amazonaws.com/c0b4b090-eef8-11ec-9cb7-0527a205b226.png\" width=\"64\" height=\"64\"></a>\n<a title=\"OnlineCasinosSpelen\" href=\"https://onlinecasinosspelen.com?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon\" target=\"_blank\"><img alt=\"OnlineCasinosSpelen\" src=\"https://logo.clearbit.com/onlinecasinosspelen.com\" width=\"64\" height=\"64\"></a>\n<a title=\"Best non Gamstop sites in the UK\" href=\"https://nongamstopcasinos.net/gb/?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon\" target=\"_blank\"><img alt=\"Best non Gamstop sites in the UK\" src=\"https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/34e340b8-e1de-4932-8a76-1b3ce2ec7ee8/logo_white%20bg%20(8).png\" width=\"64\" height=\"64\"></a>\n<a title=\"Real Money Pokies\" href=\"https://www.nzfirst.org.nz/real-money-pokies/?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon\" target=\"_blank\"><img alt=\"Real Money Pokies\" src=\"https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/30d38232-a9d6-4e95-a48c-641fdc4d96fd/NZ_logo%20(6)%20(1)%20(1).jpg\" width=\"64\" height=\"64\"></a>\n<a title=\"Non GamStop Bookies UK\" href=\"https://nongamstopbookies.com/uk/?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon\" target=\"_blank\"><img alt=\"Non GamStop Bookies UK\" src=\"https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/43c5561c-8907-4ef7-a4ee-c6da054788b8/logo-site%20(3).jpg\" width=\"64\" height=\"64\"></a>\n<a title=\"Актуальний топ-рейтинг українських онлайн казино на гривні! Щоденне оновлення топу та унікальна система ранжування, основана на відгуках гравців!\" href=\"https://onlinecasino.in.ua/?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon\" target=\"_blank\"><img alt=\"Онлайн Казино Украины\" src=\"https://opencollective-production.s3.us-west-1.amazonaws.com/8fdd8aa0-e273-11ec-a95e-d38fd331cabf.png\" width=\"64\" height=\"64\"></a>\n<a title=\"Twitter Video Downloader HD Tool allows you to store tweets on your device (mobile or PC) for free.\" href=\"https://ssstwitter.online/?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon\" target=\"_blank\"><img alt=\"SSSTwitter\" src=\"https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/ba0d1daf-a894-4d98-95f7-a44d321364b3/Screenshot%202024-01-16%20at%2011.43.22.png\" width=\"76\" height=\"64\"></a>\n<a title=\"Entertainment\" href=\"https://www.nongamstopbets.com/casinos-not-on-gamstop/?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon\" target=\"_blank\"><img alt=\"Non-GamStop Bets UK\" src=\"https://logo.clearbit.com/nongamstopbets.com\" width=\"64\" height=\"64\"></a>\n<a title=\"Chudovo - international software development company with representative offices in Kyiv, Cologne, New York, Tallinn and London. It has been working on the market since 2006. Company has domain expertise in video security, logistics, medicine, finance and\" href=\"https://chudovo.com/?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon\" target=\"_blank\"><img alt=\"Chudovo\" src=\"https://opencollective-production.s3.us-west-1.amazonaws.com/326c19a0-2e87-11eb-a13a-c99a2a201d11.png\" width=\"84\" height=\"42\"></a>\n<a title=\"Entertainment\" href=\"https://casinogap.org/uk/?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon\" target=\"_blank\"><img alt=\"UK Casino Gap\" src=\"https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/143f9301-beec-4118-89d5-9a07a01345f3/casinogap-uk.png\" width=\"42\" height=\"42\"></a>\n<a title=\"NZ Gaming Portal\" href=\"https://casinodeps.co.nz?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon\" target=\"_blank\"><img alt=\"NZ Casino Deps\" src=\"https://logo.clearbit.com/casinodeps.co.nz\" width=\"42\" height=\"42\"></a>\n<a title=\"NonStop Sites\" href=\"https://uk.nonstopcasino.org/non-gamstop-casinos/?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon\" target=\"_blank\"><img alt=\"NonStopCasino.org\" src=\"https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/fd7ad905-8752-468f-ad20-582a24cca9d9/non-stop-casino.png\" width=\"42\" height=\"42\"></a>\n<a title=\"Siti Non AAMS\" href=\"https://www.outlookindia.com/outlook-spotlight/migliori-siti-non-aams-siti-scommesse-senza-licenza-sicuri-news-294715?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon\" target=\"_blank\"><img alt=\"Migliori Siti Non AAMS\" src=\"https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/392810da-6cb6-4938-a3cb-38bd0e1eb7de/migliori-siti-non-aams.png\" width=\"42\" height=\"42\"></a>\n<a title=\"List of trusted non GamStop casino reviews\" href=\"https://nongamstopcasinos.org?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon\" target=\"_blank\"><img alt=\"UK NonGamStopCasinos\" src=\"https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/cbda0ee1-26ea-4252-9580-f1f9b317b1f7/nongamstopcasinos-uk.png\" width=\"42\" height=\"42\"></a>\n<a title=\"Online TikTok Video Download Tool\" href=\"https://snaptik.pro?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon\" target=\"_blank\"><img alt=\"SnapTik\" src=\"https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/546bcd53-6615-457d-ab21-1db1c52b3af5/logo.jpg\" width=\"42\" height=\"42\"></a>\n<a title=\"Proxidize is a mobile proxy creation and management platform that provides all needed components from hardware to cloud software and SIM cards.\" href=\"https://proxidize.com/?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon\" target=\"_blank\"><img alt=\"Proxidize\" src=\"https://logo.clearbit.com/proxidize.com\" width=\"42\" height=\"42\"></a>\n<a title=\"IG Downloader is an Instagram Downloader service that offers a variety of tools to download Instagram content for free. Listed below are all the tools\" href=\"https://indownloader.app/?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon\" target=\"_blank\"><img alt=\"IG Downloader\" src=\"https://logo.clearbit.com/indownloader.app\" width=\"42\" height=\"42\"></a>\n<a title=\"Buy Instagram Likes - Real Likes &amp; Instant Delivery!\" href=\"https://blastup.com/buy-instagram-likes?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon\" target=\"_blank\"><img alt=\"Blastup\" src=\"https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/955a0beb-9fe8-4753-ad92-fae8ef5382fc/favicon--dark.jpg\" width=\"42\" height=\"42\"></a>\n<a title=\"We will boost your Social Media Likes, Followers , Comments &amp; Views. 24/7 hour support. Privacy Assured.\" href=\"https://organicsocialboost.com/?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon\" target=\"_blank\"><img alt=\"Organic Social Boost\" src=\"https://logo.clearbit.com/organicsocialboost.com\" width=\"84\" height=\"42\"></a>\n<a title=\"A self-hosted web radio management suite, including turnkey installer tools and an easy-to-use web app to manage your stations.\" href=\"https://azuracast.com/?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon\" target=\"_blank\"><img alt=\"AzuraCast\" src=\"https://opencollective-production.s3.us-west-1.amazonaws.com/3c12ea10-cdfb-11eb-9cf4-3760b386b76d.png\" width=\"42\" height=\"42\"></a>\n<a title=\"Triplebyte is the first software engineering job platform that is on the developer&#039;s side. Take our coding quiz!\" href=\"https://triplebyte.com/os/opencollective?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon\" target=\"_blank\"><img alt=\"Triplebyte\" src=\"https://opencollective-production.s3.us-west-1.amazonaws.com/43e4f9d0-30cd-11ea-9c6b-e1142996e8b2.png\" width=\"42\" height=\"42\"></a>\n<a title=\"Connect your Collective to GitHub Sponsors: https://docs.opencollective.com/help/collectives/github-sponsors\" href=\"https://github.com/sponsors/?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon\" target=\"_blank\"><img alt=\"GitHub Sponsors\" src=\"https://opencollective-production.s3.us-west-1.amazonaws.com/87b1d240-f617-11ea-9960-fd7e8ab20fe4.png\" width=\"48\" height=\"42\"></a>\n<a title=\"Salesforce\" href=\"https://engineering.salesforce.com?utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon\" target=\"_blank\"><img alt=\"Salesforce\" src=\"https://opencollective-production.s3.us-west-1.amazonaws.com/24d34880-df8d-11e9-949c-6bc2037b6bd5.png\" width=\"42\" height=\"42\"></a>\n<!-- </open-collective-sponsors> -->\n\n[[Become a sponsor via OpenCollective](https://opencollective.com/Carbon#sponsor)]\n\n<a href=\"https://github.com/johnrsimeone\" target=\"_blank\"><img src=\"https://avatars.githubusercontent.com/u/22871068?s=70&v=4\" width=\"64\" height=\"64\"></a>\n<a href=\"https://github.com/taylorotwell\" target=\"_blank\"><img src=\"https://avatars.githubusercontent.com/u/463230?s=128&v=4\" width=\"64\" height=\"64\"></a>\n<a href=\"https://github.com/getsentry\" target=\"_blank\"><img src=\"https://avatars.githubusercontent.com/u/1396951?s=128&v=4\" width=\"64\" height=\"64\"></a>\n<a href=\"https://github.com/codecov\" target=\"_blank\"><img src=\"https://avatars.githubusercontent.com/u/8226205?s=128&v=4\" width=\"64\" height=\"64\"></a>\n\n[[Become a sponsor via GitHub](https://github.com/sponsors/kylekatarnls)]\n\n### Backers\n\nThank you to all our backers! 🙏\n\n<a href=\"https://opencollective.com/Carbon#backers\" target=\"_blank\"><img src=\"https://opencollective.com/Carbon/backers.svg?width=890&version=2023-06-08-07-12\"></a>\n\n[[Become a backer](https://opencollective.com/Carbon#backer)]\n\n## Carbon for enterprise\n\nAvailable as part of the Tidelift Subscription.\n\nThe maintainers of ``Carbon`` and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/packagist-nesbot-carbon?utm_source=packagist-nesbot-carbon&utm_medium=referral&utm_campaign=enterprise&utm_term=repo)\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/sponsors.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nuse Carbon\\CarbonImmutable;\n\nrequire_once __DIR__.'/vendor/autoload.php';\n\nfunction getMaxHistoryMonthsByAmount($amount): int\n{\n    if ($amount >= 50) {\n        return 6;\n    }\n\n    if ($amount >= 20) {\n        return 4;\n    }\n\n    return 2;\n}\n\nfunction getHtmlAttribute($rawValue): string\n{\n    return str_replace(\n        ['​', \"\\r\"],\n        '',\n        trim(htmlspecialchars((string) $rawValue), \"  \\n\\r\\t\\v\\0\"),\n    );\n}\n\nfunction getOpenCollectiveSponsors(): string\n{\n    $customSponsorImages = [\n        // For consistency and equity among sponsors, as of now, we kindly ask our sponsors\n        // to provide an image having a width/height ratio between 1/1 and 2/1.\n        // By default, we'll show the member picture from OpenCollective, and will resize it if bigger\n        // int(OpenCollective.MemberId) => ImageURL\n    ];\n\n    $members = json_decode(file_get_contents('https://opencollective.com/carbon/members/all.json'), true);\n\n    $list = array_filter($members, static function ($member): bool {\n        return ($member['lastTransactionAmount'] > 3 || $member['isActive']) &&\n            $member['role'] === 'BACKER' &&\n            $member['type'] !== 'USER' &&\n            (\n                $member['totalAmountDonated'] > 100 ||\n                $member['lastTransactionAt'] > CarbonImmutable::now()\n                    ->subMonthsNoOverflow(getMaxHistoryMonthsByAmount($member['lastTransactionAmount']))\n                    ->format('Y-m-d h:i') ||\n                $member['isActive'] && $member['lastTransactionAmount'] >= 30\n            );\n    });\n\n    $list = array_map(static function (array $member): array {\n        $createdAt = CarbonImmutable::parse($member['createdAt']);\n        $lastTransactionAt = CarbonImmutable::parse($member['lastTransactionAt']);\n\n        if ($createdAt->format('d H:i:s.u') > $lastTransactionAt->format('d H:i:s.u')) {\n            $createdAt = $createdAt\n                ->setDay($lastTransactionAt->day)\n                ->modify($lastTransactionAt->format('H:i:s.u'));\n        }\n\n        $monthlyContribution = (float) ($member['totalAmountDonated'] / ceil($createdAt->floatDiffInMonths()));\n\n        if (\n            $lastTransactionAt->isAfter('last month') &&\n            $member['lastTransactionAmount'] > $monthlyContribution\n        ) {\n            $monthlyContribution = (float) $member['lastTransactionAmount'];\n        }\n\n        $yearlyContribution = (float) ($member['totalAmountDonated'] / max(1, $createdAt->floatDiffInYears()));\n        $status = null;\n\n        if ($monthlyContribution > 29) {\n            $status = 'sponsor';\n        } elseif ($monthlyContribution > 4.5 || $yearlyContribution > 29) {\n            $status = 'backer';\n        } elseif ($member['totalAmountDonated'] > 0) {\n            $status = 'helper';\n        }\n\n        return array_merge($member, [\n            'star' => ($monthlyContribution > 98 || $yearlyContribution > 500),\n            'status' => $status,\n            'monthlyContribution' => $monthlyContribution,\n            'yearlyContribution' => $yearlyContribution,\n        ]);\n    }, $list);\n\n    usort($list, static function (array $a, array $b): int {\n        return ($b['monthlyContribution'] <=> $a['monthlyContribution'])\n            ?: ($b['totalAmountDonated'] <=> $a['totalAmountDonated']);\n    });\n\n    return implode('', array_map(static function (array $member) use ($customSponsorImages): string {\n        $href = htmlspecialchars($member['website'] ?? $member['profile']);\n        $src = $customSponsorImages[$member['MemberId'] ?? ''] ?? $member['image'] ?? (strtr($member['profile'], ['https://opencollective.com/' => 'https://images.opencollective.com/']).'/avatar/256.png');\n        [$x, $y] = @getimagesize($src) ?: [0, 0];\n        $validImage = ($x && $y);\n        $src = $validImage ? htmlspecialchars($src) : 'https://opencollective.com/static/images/default-guest-logo.svg';\n        $height = $member['status'] === 'sponsor' ? 64 : 42;\n        $width = min($height * 2, $validImage ? round($x * $height / $y) : $height);\n        $href .= (strpos($href, '?') === false ? '?' : '&amp;').'utm_source=opencollective&amp;utm_medium=github&amp;utm_campaign=Carbon';\n        $title = getHtmlAttribute(($member['description'] ?? null) ?: $member['name']);\n        $alt = getHtmlAttribute($member['name']);\n\n        return \"\\n\".'<a title=\"'.$title.'\" href=\"'.$href.'\" target=\"_blank\">'.\n            '<img alt=\"'.$alt.'\" src=\"'.$src.'\" width=\"'.$width.'\" height=\"'.$height.'\">'.\n            '</a>';\n    }, $list)).\"\\n\";\n}\n\nfile_put_contents('readme.md', preg_replace_callback(\n    '/(<!-- <open-collective-sponsors> -->)[\\s\\S]+(<!-- <\\/open-collective-sponsors> -->)/',\n    static function (array $match): string {\n        return $match[1].getOpenCollectiveSponsors().$match[2];\n    },\n    file_get_contents('readme.md')\n));\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/AbstractTranslator.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon;\n\nuse Carbon\\MessageFormatter\\MessageFormatterMapper;\nuse Closure;\nuse ReflectionException;\nuse ReflectionFunction;\nuse Symfony\\Component\\Translation;\nuse Symfony\\Component\\Translation\\Formatter\\MessageFormatterInterface;\nuse Symfony\\Component\\Translation\\Loader\\ArrayLoader;\n\nabstract class AbstractTranslator extends Translation\\Translator\n{\n    /**\n     * Translator singletons for each language.\n     *\n     * @var array\n     */\n    protected static $singletons = [];\n\n    /**\n     * List of custom localized messages.\n     *\n     * @var array\n     */\n    protected $messages = [];\n\n    /**\n     * List of custom directories that contain translation files.\n     *\n     * @var string[]\n     */\n    protected $directories = [];\n\n    /**\n     * Set to true while constructing.\n     *\n     * @var bool\n     */\n    protected $initializing = false;\n\n    /**\n     * List of locales aliases.\n     *\n     * @var array<string, string>\n     */\n    protected $aliases = [\n        'me' => 'sr_Latn_ME',\n        'scr' => 'sh',\n    ];\n\n    /**\n     * Return a singleton instance of Translator.\n     *\n     * @param string|null $locale optional initial locale (\"en\" - english by default)\n     *\n     * @return static\n     */\n    public static function get($locale = null)\n    {\n        $locale = $locale ?: 'en';\n        $key = static::class === Translator::class ? $locale : static::class.'|'.$locale;\n\n        if (!isset(static::$singletons[$key])) {\n            static::$singletons[$key] = new static($locale);\n        }\n\n        return static::$singletons[$key];\n    }\n\n    public function __construct($locale, ?MessageFormatterInterface $formatter = null, $cacheDir = null, $debug = false)\n    {\n        parent::setLocale($locale);\n        $this->initializing = true;\n        $this->directories = [__DIR__.'/Lang'];\n        $this->addLoader('array', new ArrayLoader());\n        parent::__construct($locale, new MessageFormatterMapper($formatter), $cacheDir, $debug);\n        $this->initializing = false;\n    }\n\n    /**\n     * Returns the list of directories translation files are searched in.\n     *\n     * @return array\n     */\n    public function getDirectories(): array\n    {\n        return $this->directories;\n    }\n\n    /**\n     * Set list of directories translation files are searched in.\n     *\n     * @param array $directories new directories list\n     *\n     * @return $this\n     */\n    public function setDirectories(array $directories)\n    {\n        $this->directories = $directories;\n\n        return $this;\n    }\n\n    /**\n     * Add a directory to the list translation files are searched in.\n     *\n     * @param string $directory new directory\n     *\n     * @return $this\n     */\n    public function addDirectory(string $directory)\n    {\n        $this->directories[] = $directory;\n\n        return $this;\n    }\n\n    /**\n     * Remove a directory from the list translation files are searched in.\n     *\n     * @param string $directory directory path\n     *\n     * @return $this\n     */\n    public function removeDirectory(string $directory)\n    {\n        $search = rtrim(strtr($directory, '\\\\', '/'), '/');\n\n        return $this->setDirectories(array_filter($this->getDirectories(), function ($item) use ($search) {\n            return rtrim(strtr($item, '\\\\', '/'), '/') !== $search;\n        }));\n    }\n\n    /**\n     * Reset messages of a locale (all locale if no locale passed).\n     * Remove custom messages and reload initial messages from matching\n     * file in Lang directory.\n     *\n     * @param string|null $locale\n     *\n     * @return bool\n     */\n    public function resetMessages($locale = null)\n    {\n        if ($locale === null) {\n            $this->messages = [];\n\n            return true;\n        }\n\n        $this->assertValidLocale($locale);\n\n        foreach ($this->getDirectories() as $directory) {\n            $data = @include \\sprintf('%s/%s.php', rtrim($directory, '\\\\/'), $locale);\n\n            if ($data !== false) {\n                $this->messages[$locale] = $data;\n                $this->addResource('array', $this->messages[$locale], $locale);\n\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * Returns the list of files matching a given locale prefix (or all if empty).\n     *\n     * @param string $prefix prefix required to filter result\n     *\n     * @return array\n     */\n    public function getLocalesFiles($prefix = '')\n    {\n        $files = [];\n\n        foreach ($this->getDirectories() as $directory) {\n            $directory = rtrim($directory, '\\\\/');\n\n            foreach (glob(\"$directory/$prefix*.php\") as $file) {\n                $files[] = $file;\n            }\n        }\n\n        return array_unique($files);\n    }\n\n    /**\n     * Returns the list of internally available locales and already loaded custom locales.\n     * (It will ignore custom translator dynamic loading.)\n     *\n     * @param string $prefix prefix required to filter result\n     *\n     * @return array\n     */\n    public function getAvailableLocales($prefix = '')\n    {\n        $locales = [];\n        foreach ($this->getLocalesFiles($prefix) as $file) {\n            $locales[] = substr($file, strrpos($file, '/') + 1, -4);\n        }\n\n        return array_unique(array_merge($locales, array_keys($this->messages)));\n    }\n\n    protected function translate(?string $id, array $parameters = [], ?string $domain = null, ?string $locale = null): string\n    {\n        if ($domain === null) {\n            $domain = 'messages';\n        }\n\n        $catalogue = $this->getCatalogue($locale);\n        $format = $this instanceof TranslatorStrongTypeInterface\n            ? $this->getFromCatalogue($catalogue, (string) $id, $domain)\n            : $this->getCatalogue($locale)->get((string) $id, $domain); // @codeCoverageIgnore\n\n        if ($format instanceof Closure) {\n            // @codeCoverageIgnoreStart\n            try {\n                $count = (new ReflectionFunction($format))->getNumberOfRequiredParameters();\n            } catch (ReflectionException $exception) {\n                $count = 0;\n            }\n            // @codeCoverageIgnoreEnd\n\n            return $format(\n                ...array_values($parameters),\n                ...array_fill(0, max(0, $count - \\count($parameters)), null)\n            );\n        }\n\n        return parent::trans($id, $parameters, $domain, $locale);\n    }\n\n    /**\n     * Init messages language from matching file in Lang directory.\n     *\n     * @param string $locale\n     *\n     * @return bool\n     */\n    protected function loadMessagesFromFile($locale)\n    {\n        return isset($this->messages[$locale]) || $this->resetMessages($locale);\n    }\n\n    /**\n     * Set messages of a locale and take file first if present.\n     *\n     * @param string $locale\n     * @param array  $messages\n     *\n     * @return $this\n     */\n    public function setMessages($locale, $messages)\n    {\n        $this->loadMessagesFromFile($locale);\n        $this->addResource('array', $messages, $locale);\n        $this->messages[$locale] = array_merge(\n            $this->messages[$locale] ?? [],\n            $messages\n        );\n\n        return $this;\n    }\n\n    /**\n     * Set messages of the current locale and take file first if present.\n     *\n     * @param array $messages\n     *\n     * @return $this\n     */\n    public function setTranslations($messages)\n    {\n        return $this->setMessages($this->getLocale(), $messages);\n    }\n\n    /**\n     * Get messages of a locale, if none given, return all the\n     * languages.\n     *\n     * @param string|null $locale\n     *\n     * @return array\n     */\n    public function getMessages($locale = null)\n    {\n        return $locale === null ? $this->messages : $this->messages[$locale];\n    }\n\n    /**\n     * Set the current translator locale and indicate if the source locale file exists\n     *\n     * @param string $locale locale ex. en\n     *\n     * @return bool\n     */\n    public function setLocale($locale)\n    {\n        $locale = preg_replace_callback('/[-_]([a-z]{2,}|\\d{2,})/', function ($matches) {\n            // _2-letters or YUE is a region, _3+-letters is a variant\n            $upper = strtoupper($matches[1]);\n\n            if ($upper === 'YUE' || $upper === 'ISO' || \\strlen($upper) < 3) {\n                return \"_$upper\";\n            }\n\n            return '_'.ucfirst($matches[1]);\n        }, strtolower($locale));\n\n        $previousLocale = $this->getLocale();\n\n        if ($previousLocale === $locale && isset($this->messages[$locale])) {\n            return true;\n        }\n\n        unset(static::$singletons[$previousLocale]);\n\n        if ($locale === 'auto') {\n            $completeLocale = setlocale(LC_TIME, '0');\n            $locale = preg_replace('/^([^_.-]+).*$/', '$1', $completeLocale);\n            $locales = $this->getAvailableLocales($locale);\n\n            $completeLocaleChunks = preg_split('/[_.-]+/', $completeLocale);\n\n            $getScore = function ($language) use ($completeLocaleChunks) {\n                return self::compareChunkLists($completeLocaleChunks, preg_split('/[_.-]+/', $language));\n            };\n\n            usort($locales, function ($first, $second) use ($getScore) {\n                return $getScore($second) <=> $getScore($first);\n            });\n\n            $locale = $locales[0];\n        }\n\n        if (isset($this->aliases[$locale])) {\n            $locale = $this->aliases[$locale];\n        }\n\n        // If subtag (ex: en_CA) first load the macro (ex: en) to have a fallback\n        if (str_contains($locale, '_') &&\n            $this->loadMessagesFromFile($macroLocale = preg_replace('/^([^_]+).*$/', '$1', $locale))\n        ) {\n            parent::setLocale($macroLocale);\n        }\n\n        if (!$this->loadMessagesFromFile($locale) && !$this->initializing) {\n            return false;\n        }\n\n        parent::setLocale($locale);\n\n        return true;\n    }\n\n    /**\n     * Show locale on var_dump().\n     *\n     * @return array\n     */\n    public function __debugInfo()\n    {\n        return [\n            'locale' => $this->getLocale(),\n        ];\n    }\n\n    private static function compareChunkLists($referenceChunks, $chunks)\n    {\n        $score = 0;\n\n        foreach ($referenceChunks as $index => $chunk) {\n            if (!isset($chunks[$index])) {\n                $score++;\n\n                continue;\n            }\n\n            if (strtolower($chunks[$index]) === strtolower($chunk)) {\n                $score += 10;\n            }\n        }\n\n        return $score;\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Carbon.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon;\n\nuse Carbon\\Traits\\Date;\nuse Carbon\\Traits\\DeprecatedProperties;\nuse DateTime;\nuse DateTimeInterface;\nuse DateTimeZone;\n\n/**\n * A simple API extension for DateTime.\n *\n * @mixin DeprecatedProperties\n *\n * <autodoc generated by `composer phpdoc`>\n *\n * @property      int                 $year\n * @property      int                 $yearIso\n * @property      int                 $month\n * @property      int                 $day\n * @property      int                 $hour\n * @property      int                 $minute\n * @property      int                 $second\n * @property      int                 $micro\n * @property      int                 $microsecond\n * @property      int|float|string    $timestamp                                                                                      seconds since the Unix Epoch\n * @property      string              $englishDayOfWeek                                                                               the day of week in English\n * @property      string              $shortEnglishDayOfWeek                                                                          the abbreviated day of week in English\n * @property      string              $englishMonth                                                                                   the month in English\n * @property      string              $shortEnglishMonth                                                                              the abbreviated month in English\n * @property      int                 $milliseconds\n * @property      int                 $millisecond\n * @property      int                 $milli\n * @property      int                 $week                                                                                           1 through 53\n * @property      int                 $isoWeek                                                                                        1 through 53\n * @property      int                 $weekYear                                                                                       year according to week format\n * @property      int                 $isoWeekYear                                                                                    year according to ISO week format\n * @property      int                 $dayOfYear                                                                                      1 through 366\n * @property      int                 $age                                                                                            does a diffInYears() with default parameters\n * @property      int                 $offset                                                                                         the timezone offset in seconds from UTC\n * @property      int                 $offsetMinutes                                                                                  the timezone offset in minutes from UTC\n * @property      int                 $offsetHours                                                                                    the timezone offset in hours from UTC\n * @property      CarbonTimeZone      $timezone                                                                                       the current timezone\n * @property      CarbonTimeZone      $tz                                                                                             alias of $timezone\n * @property-read int                 $dayOfWeek                                                                                      0 (for Sunday) through 6 (for Saturday)\n * @property-read int                 $dayOfWeekIso                                                                                   1 (for Monday) through 7 (for Sunday)\n * @property-read int                 $weekOfYear                                                                                     ISO-8601 week number of year, weeks starting on Monday\n * @property-read int                 $daysInMonth                                                                                    number of days in the given month\n * @property-read string              $latinMeridiem                                                                                  \"am\"/\"pm\" (Ante meridiem or Post meridiem latin lowercase mark)\n * @property-read string              $latinUpperMeridiem                                                                             \"AM\"/\"PM\" (Ante meridiem or Post meridiem latin uppercase mark)\n * @property-read string              $timezoneAbbreviatedName                                                                        the current timezone abbreviated name\n * @property-read string              $tzAbbrName                                                                                     alias of $timezoneAbbreviatedName\n * @property-read string              $dayName                                                                                        long name of weekday translated according to Carbon locale, in english if no translation available for current language\n * @property-read string              $shortDayName                                                                                   short name of weekday translated according to Carbon locale, in english if no translation available for current language\n * @property-read string              $minDayName                                                                                     very short name of weekday translated according to Carbon locale, in english if no translation available for current language\n * @property-read string              $monthName                                                                                      long name of month translated according to Carbon locale, in english if no translation available for current language\n * @property-read string              $shortMonthName                                                                                 short name of month translated according to Carbon locale, in english if no translation available for current language\n * @property-read string              $meridiem                                                                                       lowercase meridiem mark translated according to Carbon locale, in latin if no translation available for current language\n * @property-read string              $upperMeridiem                                                                                  uppercase meridiem mark translated according to Carbon locale, in latin if no translation available for current language\n * @property-read int                 $noZeroHour                                                                                     current hour from 1 to 24\n * @property-read int                 $weeksInYear                                                                                    51 through 53\n * @property-read int                 $isoWeeksInYear                                                                                 51 through 53\n * @property-read int                 $weekOfMonth                                                                                    1 through 5\n * @property-read int                 $weekNumberInMonth                                                                              1 through 5\n * @property-read int                 $firstWeekDay                                                                                   0 through 6\n * @property-read int                 $lastWeekDay                                                                                    0 through 6\n * @property-read int                 $daysInYear                                                                                     365 or 366\n * @property-read int                 $quarter                                                                                        the quarter of this instance, 1 - 4\n * @property-read int                 $decade                                                                                         the decade of this instance\n * @property-read int                 $century                                                                                        the century of this instance\n * @property-read int                 $millennium                                                                                     the millennium of this instance\n * @property-read bool                $dst                                                                                            daylight savings time indicator, true if DST, false otherwise\n * @property-read bool                $local                                                                                          checks if the timezone is local, true if local, false otherwise\n * @property-read bool                $utc                                                                                            checks if the timezone is UTC, true if UTC, false otherwise\n * @property-read string              $timezoneName                                                                                   the current timezone name\n * @property-read string              $tzName                                                                                         alias of $timezoneName\n * @property-read string              $locale                                                                                         locale of the current instance\n *\n * @method        bool                isUtc()                                                                                         Check if the current instance has UTC timezone. (Both isUtc and isUTC cases are valid.)\n * @method        bool                isLocal()                                                                                       Check if the current instance has non-UTC timezone.\n * @method        bool                isValid()                                                                                       Check if the current instance is a valid date.\n * @method        bool                isDST()                                                                                         Check if the current instance is in a daylight saving time.\n * @method        bool                isSunday()                                                                                      Checks if the instance day is sunday.\n * @method        bool                isMonday()                                                                                      Checks if the instance day is monday.\n * @method        bool                isTuesday()                                                                                     Checks if the instance day is tuesday.\n * @method        bool                isWednesday()                                                                                   Checks if the instance day is wednesday.\n * @method        bool                isThursday()                                                                                    Checks if the instance day is thursday.\n * @method        bool                isFriday()                                                                                      Checks if the instance day is friday.\n * @method        bool                isSaturday()                                                                                    Checks if the instance day is saturday.\n * @method        bool                isSameYear(Carbon|DateTimeInterface|string|null $date = null)                                   Checks if the given date is in the same year as the instance. If null passed, compare to now (with the same timezone).\n * @method        bool                isCurrentYear()                                                                                 Checks if the instance is in the same year as the current moment.\n * @method        bool                isNextYear()                                                                                    Checks if the instance is in the same year as the current moment next year.\n * @method        bool                isLastYear()                                                                                    Checks if the instance is in the same year as the current moment last year.\n * @method        bool                isSameWeek(Carbon|DateTimeInterface|string|null $date = null)                                   Checks if the given date is in the same week as the instance. If null passed, compare to now (with the same timezone).\n * @method        bool                isCurrentWeek()                                                                                 Checks if the instance is in the same week as the current moment.\n * @method        bool                isNextWeek()                                                                                    Checks if the instance is in the same week as the current moment next week.\n * @method        bool                isLastWeek()                                                                                    Checks if the instance is in the same week as the current moment last week.\n * @method        bool                isSameDay(Carbon|DateTimeInterface|string|null $date = null)                                    Checks if the given date is in the same day as the instance. If null passed, compare to now (with the same timezone).\n * @method        bool                isCurrentDay()                                                                                  Checks if the instance is in the same day as the current moment.\n * @method        bool                isNextDay()                                                                                     Checks if the instance is in the same day as the current moment next day.\n * @method        bool                isLastDay()                                                                                     Checks if the instance is in the same day as the current moment last day.\n * @method        bool                isSameHour(Carbon|DateTimeInterface|string|null $date = null)                                   Checks if the given date is in the same hour as the instance. If null passed, compare to now (with the same timezone).\n * @method        bool                isCurrentHour()                                                                                 Checks if the instance is in the same hour as the current moment.\n * @method        bool                isNextHour()                                                                                    Checks if the instance is in the same hour as the current moment next hour.\n * @method        bool                isLastHour()                                                                                    Checks if the instance is in the same hour as the current moment last hour.\n * @method        bool                isSameMinute(Carbon|DateTimeInterface|string|null $date = null)                                 Checks if the given date is in the same minute as the instance. If null passed, compare to now (with the same timezone).\n * @method        bool                isCurrentMinute()                                                                               Checks if the instance is in the same minute as the current moment.\n * @method        bool                isNextMinute()                                                                                  Checks if the instance is in the same minute as the current moment next minute.\n * @method        bool                isLastMinute()                                                                                  Checks if the instance is in the same minute as the current moment last minute.\n * @method        bool                isSameSecond(Carbon|DateTimeInterface|string|null $date = null)                                 Checks if the given date is in the same second as the instance. If null passed, compare to now (with the same timezone).\n * @method        bool                isCurrentSecond()                                                                               Checks if the instance is in the same second as the current moment.\n * @method        bool                isNextSecond()                                                                                  Checks if the instance is in the same second as the current moment next second.\n * @method        bool                isLastSecond()                                                                                  Checks if the instance is in the same second as the current moment last second.\n * @method        bool                isSameMicro(Carbon|DateTimeInterface|string|null $date = null)                                  Checks if the given date is in the same microsecond as the instance. If null passed, compare to now (with the same timezone).\n * @method        bool                isCurrentMicro()                                                                                Checks if the instance is in the same microsecond as the current moment.\n * @method        bool                isNextMicro()                                                                                   Checks if the instance is in the same microsecond as the current moment next microsecond.\n * @method        bool                isLastMicro()                                                                                   Checks if the instance is in the same microsecond as the current moment last microsecond.\n * @method        bool                isSameMicrosecond(Carbon|DateTimeInterface|string|null $date = null)                            Checks if the given date is in the same microsecond as the instance. If null passed, compare to now (with the same timezone).\n * @method        bool                isCurrentMicrosecond()                                                                          Checks if the instance is in the same microsecond as the current moment.\n * @method        bool                isNextMicrosecond()                                                                             Checks if the instance is in the same microsecond as the current moment next microsecond.\n * @method        bool                isLastMicrosecond()                                                                             Checks if the instance is in the same microsecond as the current moment last microsecond.\n * @method        bool                isCurrentMonth()                                                                                Checks if the instance is in the same month as the current moment.\n * @method        bool                isNextMonth()                                                                                   Checks if the instance is in the same month as the current moment next month.\n * @method        bool                isLastMonth()                                                                                   Checks if the instance is in the same month as the current moment last month.\n * @method        bool                isCurrentQuarter()                                                                              Checks if the instance is in the same quarter as the current moment.\n * @method        bool                isNextQuarter()                                                                                 Checks if the instance is in the same quarter as the current moment next quarter.\n * @method        bool                isLastQuarter()                                                                                 Checks if the instance is in the same quarter as the current moment last quarter.\n * @method        bool                isSameDecade(Carbon|DateTimeInterface|string|null $date = null)                                 Checks if the given date is in the same decade as the instance. If null passed, compare to now (with the same timezone).\n * @method        bool                isCurrentDecade()                                                                               Checks if the instance is in the same decade as the current moment.\n * @method        bool                isNextDecade()                                                                                  Checks if the instance is in the same decade as the current moment next decade.\n * @method        bool                isLastDecade()                                                                                  Checks if the instance is in the same decade as the current moment last decade.\n * @method        bool                isSameCentury(Carbon|DateTimeInterface|string|null $date = null)                                Checks if the given date is in the same century as the instance. If null passed, compare to now (with the same timezone).\n * @method        bool                isCurrentCentury()                                                                              Checks if the instance is in the same century as the current moment.\n * @method        bool                isNextCentury()                                                                                 Checks if the instance is in the same century as the current moment next century.\n * @method        bool                isLastCentury()                                                                                 Checks if the instance is in the same century as the current moment last century.\n * @method        bool                isSameMillennium(Carbon|DateTimeInterface|string|null $date = null)                             Checks if the given date is in the same millennium as the instance. If null passed, compare to now (with the same timezone).\n * @method        bool                isCurrentMillennium()                                                                           Checks if the instance is in the same millennium as the current moment.\n * @method        bool                isNextMillennium()                                                                              Checks if the instance is in the same millennium as the current moment next millennium.\n * @method        bool                isLastMillennium()                                                                              Checks if the instance is in the same millennium as the current moment last millennium.\n * @method        $this               years(int $value)                                                                               Set current instance year to the given value.\n * @method        $this               year(int $value)                                                                                Set current instance year to the given value.\n * @method        $this               setYears(int $value)                                                                            Set current instance year to the given value.\n * @method        $this               setYear(int $value)                                                                             Set current instance year to the given value.\n * @method        $this               months(int $value)                                                                              Set current instance month to the given value.\n * @method        $this               month(int $value)                                                                               Set current instance month to the given value.\n * @method        $this               setMonths(int $value)                                                                           Set current instance month to the given value.\n * @method        $this               setMonth(int $value)                                                                            Set current instance month to the given value.\n * @method        $this               days(int $value)                                                                                Set current instance day to the given value.\n * @method        $this               day(int $value)                                                                                 Set current instance day to the given value.\n * @method        $this               setDays(int $value)                                                                             Set current instance day to the given value.\n * @method        $this               setDay(int $value)                                                                              Set current instance day to the given value.\n * @method        $this               hours(int $value)                                                                               Set current instance hour to the given value.\n * @method        $this               hour(int $value)                                                                                Set current instance hour to the given value.\n * @method        $this               setHours(int $value)                                                                            Set current instance hour to the given value.\n * @method        $this               setHour(int $value)                                                                             Set current instance hour to the given value.\n * @method        $this               minutes(int $value)                                                                             Set current instance minute to the given value.\n * @method        $this               minute(int $value)                                                                              Set current instance minute to the given value.\n * @method        $this               setMinutes(int $value)                                                                          Set current instance minute to the given value.\n * @method        $this               setMinute(int $value)                                                                           Set current instance minute to the given value.\n * @method        $this               seconds(int $value)                                                                             Set current instance second to the given value.\n * @method        $this               second(int $value)                                                                              Set current instance second to the given value.\n * @method        $this               setSeconds(int $value)                                                                          Set current instance second to the given value.\n * @method        $this               setSecond(int $value)                                                                           Set current instance second to the given value.\n * @method        $this               millis(int $value)                                                                              Set current instance millisecond to the given value.\n * @method        $this               milli(int $value)                                                                               Set current instance millisecond to the given value.\n * @method        $this               setMillis(int $value)                                                                           Set current instance millisecond to the given value.\n * @method        $this               setMilli(int $value)                                                                            Set current instance millisecond to the given value.\n * @method        $this               milliseconds(int $value)                                                                        Set current instance millisecond to the given value.\n * @method        $this               millisecond(int $value)                                                                         Set current instance millisecond to the given value.\n * @method        $this               setMilliseconds(int $value)                                                                     Set current instance millisecond to the given value.\n * @method        $this               setMillisecond(int $value)                                                                      Set current instance millisecond to the given value.\n * @method        $this               micros(int $value)                                                                              Set current instance microsecond to the given value.\n * @method        $this               micro(int $value)                                                                               Set current instance microsecond to the given value.\n * @method        $this               setMicros(int $value)                                                                           Set current instance microsecond to the given value.\n * @method        $this               setMicro(int $value)                                                                            Set current instance microsecond to the given value.\n * @method        $this               microseconds(int $value)                                                                        Set current instance microsecond to the given value.\n * @method        $this               microsecond(int $value)                                                                         Set current instance microsecond to the given value.\n * @method        $this               setMicroseconds(int $value)                                                                     Set current instance microsecond to the given value.\n * @method        $this               setMicrosecond(int $value)                                                                      Set current instance microsecond to the given value.\n * @method        $this               addYears(int $value = 1)                                                                        Add years (the $value count passed in) to the instance (using date interval).\n * @method        $this               addYear()                                                                                       Add one year to the instance (using date interval).\n * @method        $this               subYears(int $value = 1)                                                                        Sub years (the $value count passed in) to the instance (using date interval).\n * @method        $this               subYear()                                                                                       Sub one year to the instance (using date interval).\n * @method        $this               addYearsWithOverflow(int $value = 1)                                                            Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.\n * @method        $this               addYearWithOverflow()                                                                           Add one year to the instance (using date interval) with overflow explicitly allowed.\n * @method        $this               subYearsWithOverflow(int $value = 1)                                                            Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.\n * @method        $this               subYearWithOverflow()                                                                           Sub one year to the instance (using date interval) with overflow explicitly allowed.\n * @method        $this               addYearsWithoutOverflow(int $value = 1)                                                         Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               addYearWithoutOverflow()                                                                        Add one year to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               subYearsWithoutOverflow(int $value = 1)                                                         Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               subYearWithoutOverflow()                                                                        Sub one year to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               addYearsWithNoOverflow(int $value = 1)                                                          Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               addYearWithNoOverflow()                                                                         Add one year to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               subYearsWithNoOverflow(int $value = 1)                                                          Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               subYearWithNoOverflow()                                                                         Sub one year to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               addYearsNoOverflow(int $value = 1)                                                              Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               addYearNoOverflow()                                                                             Add one year to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               subYearsNoOverflow(int $value = 1)                                                              Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               subYearNoOverflow()                                                                             Sub one year to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               addMonths(int $value = 1)                                                                       Add months (the $value count passed in) to the instance (using date interval).\n * @method        $this               addMonth()                                                                                      Add one month to the instance (using date interval).\n * @method        $this               subMonths(int $value = 1)                                                                       Sub months (the $value count passed in) to the instance (using date interval).\n * @method        $this               subMonth()                                                                                      Sub one month to the instance (using date interval).\n * @method        $this               addMonthsWithOverflow(int $value = 1)                                                           Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.\n * @method        $this               addMonthWithOverflow()                                                                          Add one month to the instance (using date interval) with overflow explicitly allowed.\n * @method        $this               subMonthsWithOverflow(int $value = 1)                                                           Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.\n * @method        $this               subMonthWithOverflow()                                                                          Sub one month to the instance (using date interval) with overflow explicitly allowed.\n * @method        $this               addMonthsWithoutOverflow(int $value = 1)                                                        Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               addMonthWithoutOverflow()                                                                       Add one month to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               subMonthsWithoutOverflow(int $value = 1)                                                        Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               subMonthWithoutOverflow()                                                                       Sub one month to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               addMonthsWithNoOverflow(int $value = 1)                                                         Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               addMonthWithNoOverflow()                                                                        Add one month to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               subMonthsWithNoOverflow(int $value = 1)                                                         Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               subMonthWithNoOverflow()                                                                        Sub one month to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               addMonthsNoOverflow(int $value = 1)                                                             Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               addMonthNoOverflow()                                                                            Add one month to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               subMonthsNoOverflow(int $value = 1)                                                             Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               subMonthNoOverflow()                                                                            Sub one month to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               addDays(int $value = 1)                                                                         Add days (the $value count passed in) to the instance (using date interval).\n * @method        $this               addDay()                                                                                        Add one day to the instance (using date interval).\n * @method        $this               subDays(int $value = 1)                                                                         Sub days (the $value count passed in) to the instance (using date interval).\n * @method        $this               subDay()                                                                                        Sub one day to the instance (using date interval).\n * @method        $this               addHours(int $value = 1)                                                                        Add hours (the $value count passed in) to the instance (using date interval).\n * @method        $this               addHour()                                                                                       Add one hour to the instance (using date interval).\n * @method        $this               subHours(int $value = 1)                                                                        Sub hours (the $value count passed in) to the instance (using date interval).\n * @method        $this               subHour()                                                                                       Sub one hour to the instance (using date interval).\n * @method        $this               addMinutes(int $value = 1)                                                                      Add minutes (the $value count passed in) to the instance (using date interval).\n * @method        $this               addMinute()                                                                                     Add one minute to the instance (using date interval).\n * @method        $this               subMinutes(int $value = 1)                                                                      Sub minutes (the $value count passed in) to the instance (using date interval).\n * @method        $this               subMinute()                                                                                     Sub one minute to the instance (using date interval).\n * @method        $this               addSeconds(int $value = 1)                                                                      Add seconds (the $value count passed in) to the instance (using date interval).\n * @method        $this               addSecond()                                                                                     Add one second to the instance (using date interval).\n * @method        $this               subSeconds(int $value = 1)                                                                      Sub seconds (the $value count passed in) to the instance (using date interval).\n * @method        $this               subSecond()                                                                                     Sub one second to the instance (using date interval).\n * @method        $this               addMillis(int $value = 1)                                                                       Add milliseconds (the $value count passed in) to the instance (using date interval).\n * @method        $this               addMilli()                                                                                      Add one millisecond to the instance (using date interval).\n * @method        $this               subMillis(int $value = 1)                                                                       Sub milliseconds (the $value count passed in) to the instance (using date interval).\n * @method        $this               subMilli()                                                                                      Sub one millisecond to the instance (using date interval).\n * @method        $this               addMilliseconds(int $value = 1)                                                                 Add milliseconds (the $value count passed in) to the instance (using date interval).\n * @method        $this               addMillisecond()                                                                                Add one millisecond to the instance (using date interval).\n * @method        $this               subMilliseconds(int $value = 1)                                                                 Sub milliseconds (the $value count passed in) to the instance (using date interval).\n * @method        $this               subMillisecond()                                                                                Sub one millisecond to the instance (using date interval).\n * @method        $this               addMicros(int $value = 1)                                                                       Add microseconds (the $value count passed in) to the instance (using date interval).\n * @method        $this               addMicro()                                                                                      Add one microsecond to the instance (using date interval).\n * @method        $this               subMicros(int $value = 1)                                                                       Sub microseconds (the $value count passed in) to the instance (using date interval).\n * @method        $this               subMicro()                                                                                      Sub one microsecond to the instance (using date interval).\n * @method        $this               addMicroseconds(int $value = 1)                                                                 Add microseconds (the $value count passed in) to the instance (using date interval).\n * @method        $this               addMicrosecond()                                                                                Add one microsecond to the instance (using date interval).\n * @method        $this               subMicroseconds(int $value = 1)                                                                 Sub microseconds (the $value count passed in) to the instance (using date interval).\n * @method        $this               subMicrosecond()                                                                                Sub one microsecond to the instance (using date interval).\n * @method        $this               addMillennia(int $value = 1)                                                                    Add millennia (the $value count passed in) to the instance (using date interval).\n * @method        $this               addMillennium()                                                                                 Add one millennium to the instance (using date interval).\n * @method        $this               subMillennia(int $value = 1)                                                                    Sub millennia (the $value count passed in) to the instance (using date interval).\n * @method        $this               subMillennium()                                                                                 Sub one millennium to the instance (using date interval).\n * @method        $this               addMillenniaWithOverflow(int $value = 1)                                                        Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.\n * @method        $this               addMillenniumWithOverflow()                                                                     Add one millennium to the instance (using date interval) with overflow explicitly allowed.\n * @method        $this               subMillenniaWithOverflow(int $value = 1)                                                        Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.\n * @method        $this               subMillenniumWithOverflow()                                                                     Sub one millennium to the instance (using date interval) with overflow explicitly allowed.\n * @method        $this               addMillenniaWithoutOverflow(int $value = 1)                                                     Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               addMillenniumWithoutOverflow()                                                                  Add one millennium to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               subMillenniaWithoutOverflow(int $value = 1)                                                     Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               subMillenniumWithoutOverflow()                                                                  Sub one millennium to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               addMillenniaWithNoOverflow(int $value = 1)                                                      Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               addMillenniumWithNoOverflow()                                                                   Add one millennium to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               subMillenniaWithNoOverflow(int $value = 1)                                                      Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               subMillenniumWithNoOverflow()                                                                   Sub one millennium to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               addMillenniaNoOverflow(int $value = 1)                                                          Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               addMillenniumNoOverflow()                                                                       Add one millennium to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               subMillenniaNoOverflow(int $value = 1)                                                          Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               subMillenniumNoOverflow()                                                                       Sub one millennium to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               addCenturies(int $value = 1)                                                                    Add centuries (the $value count passed in) to the instance (using date interval).\n * @method        $this               addCentury()                                                                                    Add one century to the instance (using date interval).\n * @method        $this               subCenturies(int $value = 1)                                                                    Sub centuries (the $value count passed in) to the instance (using date interval).\n * @method        $this               subCentury()                                                                                    Sub one century to the instance (using date interval).\n * @method        $this               addCenturiesWithOverflow(int $value = 1)                                                        Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.\n * @method        $this               addCenturyWithOverflow()                                                                        Add one century to the instance (using date interval) with overflow explicitly allowed.\n * @method        $this               subCenturiesWithOverflow(int $value = 1)                                                        Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.\n * @method        $this               subCenturyWithOverflow()                                                                        Sub one century to the instance (using date interval) with overflow explicitly allowed.\n * @method        $this               addCenturiesWithoutOverflow(int $value = 1)                                                     Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               addCenturyWithoutOverflow()                                                                     Add one century to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               subCenturiesWithoutOverflow(int $value = 1)                                                     Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               subCenturyWithoutOverflow()                                                                     Sub one century to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               addCenturiesWithNoOverflow(int $value = 1)                                                      Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               addCenturyWithNoOverflow()                                                                      Add one century to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               subCenturiesWithNoOverflow(int $value = 1)                                                      Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               subCenturyWithNoOverflow()                                                                      Sub one century to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               addCenturiesNoOverflow(int $value = 1)                                                          Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               addCenturyNoOverflow()                                                                          Add one century to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               subCenturiesNoOverflow(int $value = 1)                                                          Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               subCenturyNoOverflow()                                                                          Sub one century to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               addDecades(int $value = 1)                                                                      Add decades (the $value count passed in) to the instance (using date interval).\n * @method        $this               addDecade()                                                                                     Add one decade to the instance (using date interval).\n * @method        $this               subDecades(int $value = 1)                                                                      Sub decades (the $value count passed in) to the instance (using date interval).\n * @method        $this               subDecade()                                                                                     Sub one decade to the instance (using date interval).\n * @method        $this               addDecadesWithOverflow(int $value = 1)                                                          Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.\n * @method        $this               addDecadeWithOverflow()                                                                         Add one decade to the instance (using date interval) with overflow explicitly allowed.\n * @method        $this               subDecadesWithOverflow(int $value = 1)                                                          Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.\n * @method        $this               subDecadeWithOverflow()                                                                         Sub one decade to the instance (using date interval) with overflow explicitly allowed.\n * @method        $this               addDecadesWithoutOverflow(int $value = 1)                                                       Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               addDecadeWithoutOverflow()                                                                      Add one decade to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               subDecadesWithoutOverflow(int $value = 1)                                                       Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               subDecadeWithoutOverflow()                                                                      Sub one decade to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               addDecadesWithNoOverflow(int $value = 1)                                                        Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               addDecadeWithNoOverflow()                                                                       Add one decade to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               subDecadesWithNoOverflow(int $value = 1)                                                        Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               subDecadeWithNoOverflow()                                                                       Sub one decade to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               addDecadesNoOverflow(int $value = 1)                                                            Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               addDecadeNoOverflow()                                                                           Add one decade to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               subDecadesNoOverflow(int $value = 1)                                                            Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               subDecadeNoOverflow()                                                                           Sub one decade to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               addQuarters(int $value = 1)                                                                     Add quarters (the $value count passed in) to the instance (using date interval).\n * @method        $this               addQuarter()                                                                                    Add one quarter to the instance (using date interval).\n * @method        $this               subQuarters(int $value = 1)                                                                     Sub quarters (the $value count passed in) to the instance (using date interval).\n * @method        $this               subQuarter()                                                                                    Sub one quarter to the instance (using date interval).\n * @method        $this               addQuartersWithOverflow(int $value = 1)                                                         Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.\n * @method        $this               addQuarterWithOverflow()                                                                        Add one quarter to the instance (using date interval) with overflow explicitly allowed.\n * @method        $this               subQuartersWithOverflow(int $value = 1)                                                         Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.\n * @method        $this               subQuarterWithOverflow()                                                                        Sub one quarter to the instance (using date interval) with overflow explicitly allowed.\n * @method        $this               addQuartersWithoutOverflow(int $value = 1)                                                      Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               addQuarterWithoutOverflow()                                                                     Add one quarter to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               subQuartersWithoutOverflow(int $value = 1)                                                      Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               subQuarterWithoutOverflow()                                                                     Sub one quarter to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               addQuartersWithNoOverflow(int $value = 1)                                                       Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               addQuarterWithNoOverflow()                                                                      Add one quarter to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               subQuartersWithNoOverflow(int $value = 1)                                                       Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               subQuarterWithNoOverflow()                                                                      Sub one quarter to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               addQuartersNoOverflow(int $value = 1)                                                           Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               addQuarterNoOverflow()                                                                          Add one quarter to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               subQuartersNoOverflow(int $value = 1)                                                           Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               subQuarterNoOverflow()                                                                          Sub one quarter to the instance (using date interval) with overflow explicitly forbidden.\n * @method        $this               addWeeks(int $value = 1)                                                                        Add weeks (the $value count passed in) to the instance (using date interval).\n * @method        $this               addWeek()                                                                                       Add one week to the instance (using date interval).\n * @method        $this               subWeeks(int $value = 1)                                                                        Sub weeks (the $value count passed in) to the instance (using date interval).\n * @method        $this               subWeek()                                                                                       Sub one week to the instance (using date interval).\n * @method        $this               addWeekdays(int $value = 1)                                                                     Add weekdays (the $value count passed in) to the instance (using date interval).\n * @method        $this               addWeekday()                                                                                    Add one weekday to the instance (using date interval).\n * @method        $this               subWeekdays(int $value = 1)                                                                     Sub weekdays (the $value count passed in) to the instance (using date interval).\n * @method        $this               subWeekday()                                                                                    Sub one weekday to the instance (using date interval).\n * @method        $this               addRealMicros(int $value = 1)                                                                   Add microseconds (the $value count passed in) to the instance (using timestamp).\n * @method        $this               addRealMicro()                                                                                  Add one microsecond to the instance (using timestamp).\n * @method        $this               subRealMicros(int $value = 1)                                                                   Sub microseconds (the $value count passed in) to the instance (using timestamp).\n * @method        $this               subRealMicro()                                                                                  Sub one microsecond to the instance (using timestamp).\n * @method        CarbonPeriod        microsUntil($endDate = null, int $factor = 1)                                                   Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each microsecond or every X microseconds if a factor is given.\n * @method        $this               addRealMicroseconds(int $value = 1)                                                             Add microseconds (the $value count passed in) to the instance (using timestamp).\n * @method        $this               addRealMicrosecond()                                                                            Add one microsecond to the instance (using timestamp).\n * @method        $this               subRealMicroseconds(int $value = 1)                                                             Sub microseconds (the $value count passed in) to the instance (using timestamp).\n * @method        $this               subRealMicrosecond()                                                                            Sub one microsecond to the instance (using timestamp).\n * @method        CarbonPeriod        microsecondsUntil($endDate = null, int $factor = 1)                                             Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each microsecond or every X microseconds if a factor is given.\n * @method        $this               addRealMillis(int $value = 1)                                                                   Add milliseconds (the $value count passed in) to the instance (using timestamp).\n * @method        $this               addRealMilli()                                                                                  Add one millisecond to the instance (using timestamp).\n * @method        $this               subRealMillis(int $value = 1)                                                                   Sub milliseconds (the $value count passed in) to the instance (using timestamp).\n * @method        $this               subRealMilli()                                                                                  Sub one millisecond to the instance (using timestamp).\n * @method        CarbonPeriod        millisUntil($endDate = null, int $factor = 1)                                                   Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each millisecond or every X milliseconds if a factor is given.\n * @method        $this               addRealMilliseconds(int $value = 1)                                                             Add milliseconds (the $value count passed in) to the instance (using timestamp).\n * @method        $this               addRealMillisecond()                                                                            Add one millisecond to the instance (using timestamp).\n * @method        $this               subRealMilliseconds(int $value = 1)                                                             Sub milliseconds (the $value count passed in) to the instance (using timestamp).\n * @method        $this               subRealMillisecond()                                                                            Sub one millisecond to the instance (using timestamp).\n * @method        CarbonPeriod        millisecondsUntil($endDate = null, int $factor = 1)                                             Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each millisecond or every X milliseconds if a factor is given.\n * @method        $this               addRealSeconds(int $value = 1)                                                                  Add seconds (the $value count passed in) to the instance (using timestamp).\n * @method        $this               addRealSecond()                                                                                 Add one second to the instance (using timestamp).\n * @method        $this               subRealSeconds(int $value = 1)                                                                  Sub seconds (the $value count passed in) to the instance (using timestamp).\n * @method        $this               subRealSecond()                                                                                 Sub one second to the instance (using timestamp).\n * @method        CarbonPeriod        secondsUntil($endDate = null, int $factor = 1)                                                  Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each second or every X seconds if a factor is given.\n * @method        $this               addRealMinutes(int $value = 1)                                                                  Add minutes (the $value count passed in) to the instance (using timestamp).\n * @method        $this               addRealMinute()                                                                                 Add one minute to the instance (using timestamp).\n * @method        $this               subRealMinutes(int $value = 1)                                                                  Sub minutes (the $value count passed in) to the instance (using timestamp).\n * @method        $this               subRealMinute()                                                                                 Sub one minute to the instance (using timestamp).\n * @method        CarbonPeriod        minutesUntil($endDate = null, int $factor = 1)                                                  Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each minute or every X minutes if a factor is given.\n * @method        $this               addRealHours(int $value = 1)                                                                    Add hours (the $value count passed in) to the instance (using timestamp).\n * @method        $this               addRealHour()                                                                                   Add one hour to the instance (using timestamp).\n * @method        $this               subRealHours(int $value = 1)                                                                    Sub hours (the $value count passed in) to the instance (using timestamp).\n * @method        $this               subRealHour()                                                                                   Sub one hour to the instance (using timestamp).\n * @method        CarbonPeriod        hoursUntil($endDate = null, int $factor = 1)                                                    Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each hour or every X hours if a factor is given.\n * @method        $this               addRealDays(int $value = 1)                                                                     Add days (the $value count passed in) to the instance (using timestamp).\n * @method        $this               addRealDay()                                                                                    Add one day to the instance (using timestamp).\n * @method        $this               subRealDays(int $value = 1)                                                                     Sub days (the $value count passed in) to the instance (using timestamp).\n * @method        $this               subRealDay()                                                                                    Sub one day to the instance (using timestamp).\n * @method        CarbonPeriod        daysUntil($endDate = null, int $factor = 1)                                                     Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each day or every X days if a factor is given.\n * @method        $this               addRealWeeks(int $value = 1)                                                                    Add weeks (the $value count passed in) to the instance (using timestamp).\n * @method        $this               addRealWeek()                                                                                   Add one week to the instance (using timestamp).\n * @method        $this               subRealWeeks(int $value = 1)                                                                    Sub weeks (the $value count passed in) to the instance (using timestamp).\n * @method        $this               subRealWeek()                                                                                   Sub one week to the instance (using timestamp).\n * @method        CarbonPeriod        weeksUntil($endDate = null, int $factor = 1)                                                    Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each week or every X weeks if a factor is given.\n * @method        $this               addRealMonths(int $value = 1)                                                                   Add months (the $value count passed in) to the instance (using timestamp).\n * @method        $this               addRealMonth()                                                                                  Add one month to the instance (using timestamp).\n * @method        $this               subRealMonths(int $value = 1)                                                                   Sub months (the $value count passed in) to the instance (using timestamp).\n * @method        $this               subRealMonth()                                                                                  Sub one month to the instance (using timestamp).\n * @method        CarbonPeriod        monthsUntil($endDate = null, int $factor = 1)                                                   Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each month or every X months if a factor is given.\n * @method        $this               addRealQuarters(int $value = 1)                                                                 Add quarters (the $value count passed in) to the instance (using timestamp).\n * @method        $this               addRealQuarter()                                                                                Add one quarter to the instance (using timestamp).\n * @method        $this               subRealQuarters(int $value = 1)                                                                 Sub quarters (the $value count passed in) to the instance (using timestamp).\n * @method        $this               subRealQuarter()                                                                                Sub one quarter to the instance (using timestamp).\n * @method        CarbonPeriod        quartersUntil($endDate = null, int $factor = 1)                                                 Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each quarter or every X quarters if a factor is given.\n * @method        $this               addRealYears(int $value = 1)                                                                    Add years (the $value count passed in) to the instance (using timestamp).\n * @method        $this               addRealYear()                                                                                   Add one year to the instance (using timestamp).\n * @method        $this               subRealYears(int $value = 1)                                                                    Sub years (the $value count passed in) to the instance (using timestamp).\n * @method        $this               subRealYear()                                                                                   Sub one year to the instance (using timestamp).\n * @method        CarbonPeriod        yearsUntil($endDate = null, int $factor = 1)                                                    Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each year or every X years if a factor is given.\n * @method        $this               addRealDecades(int $value = 1)                                                                  Add decades (the $value count passed in) to the instance (using timestamp).\n * @method        $this               addRealDecade()                                                                                 Add one decade to the instance (using timestamp).\n * @method        $this               subRealDecades(int $value = 1)                                                                  Sub decades (the $value count passed in) to the instance (using timestamp).\n * @method        $this               subRealDecade()                                                                                 Sub one decade to the instance (using timestamp).\n * @method        CarbonPeriod        decadesUntil($endDate = null, int $factor = 1)                                                  Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each decade or every X decades if a factor is given.\n * @method        $this               addRealCenturies(int $value = 1)                                                                Add centuries (the $value count passed in) to the instance (using timestamp).\n * @method        $this               addRealCentury()                                                                                Add one century to the instance (using timestamp).\n * @method        $this               subRealCenturies(int $value = 1)                                                                Sub centuries (the $value count passed in) to the instance (using timestamp).\n * @method        $this               subRealCentury()                                                                                Sub one century to the instance (using timestamp).\n * @method        CarbonPeriod        centuriesUntil($endDate = null, int $factor = 1)                                                Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each century or every X centuries if a factor is given.\n * @method        $this               addRealMillennia(int $value = 1)                                                                Add millennia (the $value count passed in) to the instance (using timestamp).\n * @method        $this               addRealMillennium()                                                                             Add one millennium to the instance (using timestamp).\n * @method        $this               subRealMillennia(int $value = 1)                                                                Sub millennia (the $value count passed in) to the instance (using timestamp).\n * @method        $this               subRealMillennium()                                                                             Sub one millennium to the instance (using timestamp).\n * @method        CarbonPeriod        millenniaUntil($endDate = null, int $factor = 1)                                                Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each millennium or every X millennia if a factor is given.\n * @method        $this               roundYear(float $precision = 1, string $function = \"round\")                                     Round the current instance year with given precision using the given function.\n * @method        $this               roundYears(float $precision = 1, string $function = \"round\")                                    Round the current instance year with given precision using the given function.\n * @method        $this               floorYear(float $precision = 1)                                                                 Truncate the current instance year with given precision.\n * @method        $this               floorYears(float $precision = 1)                                                                Truncate the current instance year with given precision.\n * @method        $this               ceilYear(float $precision = 1)                                                                  Ceil the current instance year with given precision.\n * @method        $this               ceilYears(float $precision = 1)                                                                 Ceil the current instance year with given precision.\n * @method        $this               roundMonth(float $precision = 1, string $function = \"round\")                                    Round the current instance month with given precision using the given function.\n * @method        $this               roundMonths(float $precision = 1, string $function = \"round\")                                   Round the current instance month with given precision using the given function.\n * @method        $this               floorMonth(float $precision = 1)                                                                Truncate the current instance month with given precision.\n * @method        $this               floorMonths(float $precision = 1)                                                               Truncate the current instance month with given precision.\n * @method        $this               ceilMonth(float $precision = 1)                                                                 Ceil the current instance month with given precision.\n * @method        $this               ceilMonths(float $precision = 1)                                                                Ceil the current instance month with given precision.\n * @method        $this               roundDay(float $precision = 1, string $function = \"round\")                                      Round the current instance day with given precision using the given function.\n * @method        $this               roundDays(float $precision = 1, string $function = \"round\")                                     Round the current instance day with given precision using the given function.\n * @method        $this               floorDay(float $precision = 1)                                                                  Truncate the current instance day with given precision.\n * @method        $this               floorDays(float $precision = 1)                                                                 Truncate the current instance day with given precision.\n * @method        $this               ceilDay(float $precision = 1)                                                                   Ceil the current instance day with given precision.\n * @method        $this               ceilDays(float $precision = 1)                                                                  Ceil the current instance day with given precision.\n * @method        $this               roundHour(float $precision = 1, string $function = \"round\")                                     Round the current instance hour with given precision using the given function.\n * @method        $this               roundHours(float $precision = 1, string $function = \"round\")                                    Round the current instance hour with given precision using the given function.\n * @method        $this               floorHour(float $precision = 1)                                                                 Truncate the current instance hour with given precision.\n * @method        $this               floorHours(float $precision = 1)                                                                Truncate the current instance hour with given precision.\n * @method        $this               ceilHour(float $precision = 1)                                                                  Ceil the current instance hour with given precision.\n * @method        $this               ceilHours(float $precision = 1)                                                                 Ceil the current instance hour with given precision.\n * @method        $this               roundMinute(float $precision = 1, string $function = \"round\")                                   Round the current instance minute with given precision using the given function.\n * @method        $this               roundMinutes(float $precision = 1, string $function = \"round\")                                  Round the current instance minute with given precision using the given function.\n * @method        $this               floorMinute(float $precision = 1)                                                               Truncate the current instance minute with given precision.\n * @method        $this               floorMinutes(float $precision = 1)                                                              Truncate the current instance minute with given precision.\n * @method        $this               ceilMinute(float $precision = 1)                                                                Ceil the current instance minute with given precision.\n * @method        $this               ceilMinutes(float $precision = 1)                                                               Ceil the current instance minute with given precision.\n * @method        $this               roundSecond(float $precision = 1, string $function = \"round\")                                   Round the current instance second with given precision using the given function.\n * @method        $this               roundSeconds(float $precision = 1, string $function = \"round\")                                  Round the current instance second with given precision using the given function.\n * @method        $this               floorSecond(float $precision = 1)                                                               Truncate the current instance second with given precision.\n * @method        $this               floorSeconds(float $precision = 1)                                                              Truncate the current instance second with given precision.\n * @method        $this               ceilSecond(float $precision = 1)                                                                Ceil the current instance second with given precision.\n * @method        $this               ceilSeconds(float $precision = 1)                                                               Ceil the current instance second with given precision.\n * @method        $this               roundMillennium(float $precision = 1, string $function = \"round\")                               Round the current instance millennium with given precision using the given function.\n * @method        $this               roundMillennia(float $precision = 1, string $function = \"round\")                                Round the current instance millennium with given precision using the given function.\n * @method        $this               floorMillennium(float $precision = 1)                                                           Truncate the current instance millennium with given precision.\n * @method        $this               floorMillennia(float $precision = 1)                                                            Truncate the current instance millennium with given precision.\n * @method        $this               ceilMillennium(float $precision = 1)                                                            Ceil the current instance millennium with given precision.\n * @method        $this               ceilMillennia(float $precision = 1)                                                             Ceil the current instance millennium with given precision.\n * @method        $this               roundCentury(float $precision = 1, string $function = \"round\")                                  Round the current instance century with given precision using the given function.\n * @method        $this               roundCenturies(float $precision = 1, string $function = \"round\")                                Round the current instance century with given precision using the given function.\n * @method        $this               floorCentury(float $precision = 1)                                                              Truncate the current instance century with given precision.\n * @method        $this               floorCenturies(float $precision = 1)                                                            Truncate the current instance century with given precision.\n * @method        $this               ceilCentury(float $precision = 1)                                                               Ceil the current instance century with given precision.\n * @method        $this               ceilCenturies(float $precision = 1)                                                             Ceil the current instance century with given precision.\n * @method        $this               roundDecade(float $precision = 1, string $function = \"round\")                                   Round the current instance decade with given precision using the given function.\n * @method        $this               roundDecades(float $precision = 1, string $function = \"round\")                                  Round the current instance decade with given precision using the given function.\n * @method        $this               floorDecade(float $precision = 1)                                                               Truncate the current instance decade with given precision.\n * @method        $this               floorDecades(float $precision = 1)                                                              Truncate the current instance decade with given precision.\n * @method        $this               ceilDecade(float $precision = 1)                                                                Ceil the current instance decade with given precision.\n * @method        $this               ceilDecades(float $precision = 1)                                                               Ceil the current instance decade with given precision.\n * @method        $this               roundQuarter(float $precision = 1, string $function = \"round\")                                  Round the current instance quarter with given precision using the given function.\n * @method        $this               roundQuarters(float $precision = 1, string $function = \"round\")                                 Round the current instance quarter with given precision using the given function.\n * @method        $this               floorQuarter(float $precision = 1)                                                              Truncate the current instance quarter with given precision.\n * @method        $this               floorQuarters(float $precision = 1)                                                             Truncate the current instance quarter with given precision.\n * @method        $this               ceilQuarter(float $precision = 1)                                                               Ceil the current instance quarter with given precision.\n * @method        $this               ceilQuarters(float $precision = 1)                                                              Ceil the current instance quarter with given precision.\n * @method        $this               roundMillisecond(float $precision = 1, string $function = \"round\")                              Round the current instance millisecond with given precision using the given function.\n * @method        $this               roundMilliseconds(float $precision = 1, string $function = \"round\")                             Round the current instance millisecond with given precision using the given function.\n * @method        $this               floorMillisecond(float $precision = 1)                                                          Truncate the current instance millisecond with given precision.\n * @method        $this               floorMilliseconds(float $precision = 1)                                                         Truncate the current instance millisecond with given precision.\n * @method        $this               ceilMillisecond(float $precision = 1)                                                           Ceil the current instance millisecond with given precision.\n * @method        $this               ceilMilliseconds(float $precision = 1)                                                          Ceil the current instance millisecond with given precision.\n * @method        $this               roundMicrosecond(float $precision = 1, string $function = \"round\")                              Round the current instance microsecond with given precision using the given function.\n * @method        $this               roundMicroseconds(float $precision = 1, string $function = \"round\")                             Round the current instance microsecond with given precision using the given function.\n * @method        $this               floorMicrosecond(float $precision = 1)                                                          Truncate the current instance microsecond with given precision.\n * @method        $this               floorMicroseconds(float $precision = 1)                                                         Truncate the current instance microsecond with given precision.\n * @method        $this               ceilMicrosecond(float $precision = 1)                                                           Ceil the current instance microsecond with given precision.\n * @method        $this               ceilMicroseconds(float $precision = 1)                                                          Ceil the current instance microsecond with given precision.\n * @method        string              shortAbsoluteDiffForHumans(DateTimeInterface $other = null, int $parts = 1)                     Get the difference (short format, 'Absolute' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.)\n * @method        string              longAbsoluteDiffForHumans(DateTimeInterface $other = null, int $parts = 1)                      Get the difference (long format, 'Absolute' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.)\n * @method        string              shortRelativeDiffForHumans(DateTimeInterface $other = null, int $parts = 1)                     Get the difference (short format, 'Relative' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.)\n * @method        string              longRelativeDiffForHumans(DateTimeInterface $other = null, int $parts = 1)                      Get the difference (long format, 'Relative' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.)\n * @method        string              shortRelativeToNowDiffForHumans(DateTimeInterface $other = null, int $parts = 1)                Get the difference (short format, 'RelativeToNow' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.)\n * @method        string              longRelativeToNowDiffForHumans(DateTimeInterface $other = null, int $parts = 1)                 Get the difference (long format, 'RelativeToNow' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.)\n * @method        string              shortRelativeToOtherDiffForHumans(DateTimeInterface $other = null, int $parts = 1)              Get the difference (short format, 'RelativeToOther' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.)\n * @method        string              longRelativeToOtherDiffForHumans(DateTimeInterface $other = null, int $parts = 1)               Get the difference (long format, 'RelativeToOther' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.)\n * @method        static static|false createFromFormat(string $format, string $time, DateTimeZone|string|false|null $timezone = null) Parse a string into a new Carbon object according to the specified format.\n * @method        static static       __set_state(array $array)                                                                       https://php.net/manual/en/datetime.set-state.php\n *\n * </autodoc>\n */\nclass Carbon extends DateTime implements CarbonInterface\n{\n    use Date;\n\n    /**\n     * Returns true if the current class/instance is mutable.\n     *\n     * @return bool\n     */\n    public static function isMutable()\n    {\n        return true;\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/CarbonConverterInterface.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon;\n\nuse DateTimeInterface;\n\ninterface CarbonConverterInterface\n{\n    public function convertDate(DateTimeInterface $dateTime, bool $negated = false): CarbonInterface;\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/CarbonImmutable.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon;\n\nuse Carbon\\Traits\\Date;\nuse Carbon\\Traits\\DeprecatedProperties;\nuse DateTimeImmutable;\nuse DateTimeInterface;\nuse DateTimeZone;\n\n/**\n * A simple API extension for DateTimeImmutable.\n *\n * @mixin DeprecatedProperties\n *\n * <autodoc generated by `composer phpdoc`>\n *\n * @property      int                 $year\n * @property      int                 $yearIso\n * @property      int                 $month\n * @property      int                 $day\n * @property      int                 $hour\n * @property      int                 $minute\n * @property      int                 $second\n * @property      int                 $micro\n * @property      int                 $microsecond\n * @property      int|float|string    $timestamp                                                                                      seconds since the Unix Epoch\n * @property      string              $englishDayOfWeek                                                                               the day of week in English\n * @property      string              $shortEnglishDayOfWeek                                                                          the abbreviated day of week in English\n * @property      string              $englishMonth                                                                                   the month in English\n * @property      string              $shortEnglishMonth                                                                              the abbreviated month in English\n * @property      int                 $milliseconds\n * @property      int                 $millisecond\n * @property      int                 $milli\n * @property      int                 $week                                                                                           1 through 53\n * @property      int                 $isoWeek                                                                                        1 through 53\n * @property      int                 $weekYear                                                                                       year according to week format\n * @property      int                 $isoWeekYear                                                                                    year according to ISO week format\n * @property      int                 $dayOfYear                                                                                      1 through 366\n * @property      int                 $age                                                                                            does a diffInYears() with default parameters\n * @property      int                 $offset                                                                                         the timezone offset in seconds from UTC\n * @property      int                 $offsetMinutes                                                                                  the timezone offset in minutes from UTC\n * @property      int                 $offsetHours                                                                                    the timezone offset in hours from UTC\n * @property      CarbonTimeZone      $timezone                                                                                       the current timezone\n * @property      CarbonTimeZone      $tz                                                                                             alias of $timezone\n * @property-read int                 $dayOfWeek                                                                                      0 (for Sunday) through 6 (for Saturday)\n * @property-read int                 $dayOfWeekIso                                                                                   1 (for Monday) through 7 (for Sunday)\n * @property-read int                 $weekOfYear                                                                                     ISO-8601 week number of year, weeks starting on Monday\n * @property-read int                 $daysInMonth                                                                                    number of days in the given month\n * @property-read string              $latinMeridiem                                                                                  \"am\"/\"pm\" (Ante meridiem or Post meridiem latin lowercase mark)\n * @property-read string              $latinUpperMeridiem                                                                             \"AM\"/\"PM\" (Ante meridiem or Post meridiem latin uppercase mark)\n * @property-read string              $timezoneAbbreviatedName                                                                        the current timezone abbreviated name\n * @property-read string              $tzAbbrName                                                                                     alias of $timezoneAbbreviatedName\n * @property-read string              $dayName                                                                                        long name of weekday translated according to Carbon locale, in english if no translation available for current language\n * @property-read string              $shortDayName                                                                                   short name of weekday translated according to Carbon locale, in english if no translation available for current language\n * @property-read string              $minDayName                                                                                     very short name of weekday translated according to Carbon locale, in english if no translation available for current language\n * @property-read string              $monthName                                                                                      long name of month translated according to Carbon locale, in english if no translation available for current language\n * @property-read string              $shortMonthName                                                                                 short name of month translated according to Carbon locale, in english if no translation available for current language\n * @property-read string              $meridiem                                                                                       lowercase meridiem mark translated according to Carbon locale, in latin if no translation available for current language\n * @property-read string              $upperMeridiem                                                                                  uppercase meridiem mark translated according to Carbon locale, in latin if no translation available for current language\n * @property-read int                 $noZeroHour                                                                                     current hour from 1 to 24\n * @property-read int                 $weeksInYear                                                                                    51 through 53\n * @property-read int                 $isoWeeksInYear                                                                                 51 through 53\n * @property-read int                 $weekOfMonth                                                                                    1 through 5\n * @property-read int                 $weekNumberInMonth                                                                              1 through 5\n * @property-read int                 $firstWeekDay                                                                                   0 through 6\n * @property-read int                 $lastWeekDay                                                                                    0 through 6\n * @property-read int                 $daysInYear                                                                                     365 or 366\n * @property-read int                 $quarter                                                                                        the quarter of this instance, 1 - 4\n * @property-read int                 $decade                                                                                         the decade of this instance\n * @property-read int                 $century                                                                                        the century of this instance\n * @property-read int                 $millennium                                                                                     the millennium of this instance\n * @property-read bool                $dst                                                                                            daylight savings time indicator, true if DST, false otherwise\n * @property-read bool                $local                                                                                          checks if the timezone is local, true if local, false otherwise\n * @property-read bool                $utc                                                                                            checks if the timezone is UTC, true if UTC, false otherwise\n * @property-read string              $timezoneName                                                                                   the current timezone name\n * @property-read string              $tzName                                                                                         alias of $timezoneName\n * @property-read string              $locale                                                                                         locale of the current instance\n *\n * @method        bool                isUtc()                                                                                         Check if the current instance has UTC timezone. (Both isUtc and isUTC cases are valid.)\n * @method        bool                isLocal()                                                                                       Check if the current instance has non-UTC timezone.\n * @method        bool                isValid()                                                                                       Check if the current instance is a valid date.\n * @method        bool                isDST()                                                                                         Check if the current instance is in a daylight saving time.\n * @method        bool                isSunday()                                                                                      Checks if the instance day is sunday.\n * @method        bool                isMonday()                                                                                      Checks if the instance day is monday.\n * @method        bool                isTuesday()                                                                                     Checks if the instance day is tuesday.\n * @method        bool                isWednesday()                                                                                   Checks if the instance day is wednesday.\n * @method        bool                isThursday()                                                                                    Checks if the instance day is thursday.\n * @method        bool                isFriday()                                                                                      Checks if the instance day is friday.\n * @method        bool                isSaturday()                                                                                    Checks if the instance day is saturday.\n * @method        bool                isSameYear(Carbon|DateTimeInterface|string|null $date = null)                                   Checks if the given date is in the same year as the instance. If null passed, compare to now (with the same timezone).\n * @method        bool                isCurrentYear()                                                                                 Checks if the instance is in the same year as the current moment.\n * @method        bool                isNextYear()                                                                                    Checks if the instance is in the same year as the current moment next year.\n * @method        bool                isLastYear()                                                                                    Checks if the instance is in the same year as the current moment last year.\n * @method        bool                isSameWeek(Carbon|DateTimeInterface|string|null $date = null)                                   Checks if the given date is in the same week as the instance. If null passed, compare to now (with the same timezone).\n * @method        bool                isCurrentWeek()                                                                                 Checks if the instance is in the same week as the current moment.\n * @method        bool                isNextWeek()                                                                                    Checks if the instance is in the same week as the current moment next week.\n * @method        bool                isLastWeek()                                                                                    Checks if the instance is in the same week as the current moment last week.\n * @method        bool                isSameDay(Carbon|DateTimeInterface|string|null $date = null)                                    Checks if the given date is in the same day as the instance. If null passed, compare to now (with the same timezone).\n * @method        bool                isCurrentDay()                                                                                  Checks if the instance is in the same day as the current moment.\n * @method        bool                isNextDay()                                                                                     Checks if the instance is in the same day as the current moment next day.\n * @method        bool                isLastDay()                                                                                     Checks if the instance is in the same day as the current moment last day.\n * @method        bool                isSameHour(Carbon|DateTimeInterface|string|null $date = null)                                   Checks if the given date is in the same hour as the instance. If null passed, compare to now (with the same timezone).\n * @method        bool                isCurrentHour()                                                                                 Checks if the instance is in the same hour as the current moment.\n * @method        bool                isNextHour()                                                                                    Checks if the instance is in the same hour as the current moment next hour.\n * @method        bool                isLastHour()                                                                                    Checks if the instance is in the same hour as the current moment last hour.\n * @method        bool                isSameMinute(Carbon|DateTimeInterface|string|null $date = null)                                 Checks if the given date is in the same minute as the instance. If null passed, compare to now (with the same timezone).\n * @method        bool                isCurrentMinute()                                                                               Checks if the instance is in the same minute as the current moment.\n * @method        bool                isNextMinute()                                                                                  Checks if the instance is in the same minute as the current moment next minute.\n * @method        bool                isLastMinute()                                                                                  Checks if the instance is in the same minute as the current moment last minute.\n * @method        bool                isSameSecond(Carbon|DateTimeInterface|string|null $date = null)                                 Checks if the given date is in the same second as the instance. If null passed, compare to now (with the same timezone).\n * @method        bool                isCurrentSecond()                                                                               Checks if the instance is in the same second as the current moment.\n * @method        bool                isNextSecond()                                                                                  Checks if the instance is in the same second as the current moment next second.\n * @method        bool                isLastSecond()                                                                                  Checks if the instance is in the same second as the current moment last second.\n * @method        bool                isSameMicro(Carbon|DateTimeInterface|string|null $date = null)                                  Checks if the given date is in the same microsecond as the instance. If null passed, compare to now (with the same timezone).\n * @method        bool                isCurrentMicro()                                                                                Checks if the instance is in the same microsecond as the current moment.\n * @method        bool                isNextMicro()                                                                                   Checks if the instance is in the same microsecond as the current moment next microsecond.\n * @method        bool                isLastMicro()                                                                                   Checks if the instance is in the same microsecond as the current moment last microsecond.\n * @method        bool                isSameMicrosecond(Carbon|DateTimeInterface|string|null $date = null)                            Checks if the given date is in the same microsecond as the instance. If null passed, compare to now (with the same timezone).\n * @method        bool                isCurrentMicrosecond()                                                                          Checks if the instance is in the same microsecond as the current moment.\n * @method        bool                isNextMicrosecond()                                                                             Checks if the instance is in the same microsecond as the current moment next microsecond.\n * @method        bool                isLastMicrosecond()                                                                             Checks if the instance is in the same microsecond as the current moment last microsecond.\n * @method        bool                isCurrentMonth()                                                                                Checks if the instance is in the same month as the current moment.\n * @method        bool                isNextMonth()                                                                                   Checks if the instance is in the same month as the current moment next month.\n * @method        bool                isLastMonth()                                                                                   Checks if the instance is in the same month as the current moment last month.\n * @method        bool                isCurrentQuarter()                                                                              Checks if the instance is in the same quarter as the current moment.\n * @method        bool                isNextQuarter()                                                                                 Checks if the instance is in the same quarter as the current moment next quarter.\n * @method        bool                isLastQuarter()                                                                                 Checks if the instance is in the same quarter as the current moment last quarter.\n * @method        bool                isSameDecade(Carbon|DateTimeInterface|string|null $date = null)                                 Checks if the given date is in the same decade as the instance. If null passed, compare to now (with the same timezone).\n * @method        bool                isCurrentDecade()                                                                               Checks if the instance is in the same decade as the current moment.\n * @method        bool                isNextDecade()                                                                                  Checks if the instance is in the same decade as the current moment next decade.\n * @method        bool                isLastDecade()                                                                                  Checks if the instance is in the same decade as the current moment last decade.\n * @method        bool                isSameCentury(Carbon|DateTimeInterface|string|null $date = null)                                Checks if the given date is in the same century as the instance. If null passed, compare to now (with the same timezone).\n * @method        bool                isCurrentCentury()                                                                              Checks if the instance is in the same century as the current moment.\n * @method        bool                isNextCentury()                                                                                 Checks if the instance is in the same century as the current moment next century.\n * @method        bool                isLastCentury()                                                                                 Checks if the instance is in the same century as the current moment last century.\n * @method        bool                isSameMillennium(Carbon|DateTimeInterface|string|null $date = null)                             Checks if the given date is in the same millennium as the instance. If null passed, compare to now (with the same timezone).\n * @method        bool                isCurrentMillennium()                                                                           Checks if the instance is in the same millennium as the current moment.\n * @method        bool                isNextMillennium()                                                                              Checks if the instance is in the same millennium as the current moment next millennium.\n * @method        bool                isLastMillennium()                                                                              Checks if the instance is in the same millennium as the current moment last millennium.\n * @method        CarbonImmutable     years(int $value)                                                                               Set current instance year to the given value.\n * @method        CarbonImmutable     year(int $value)                                                                                Set current instance year to the given value.\n * @method        CarbonImmutable     setYears(int $value)                                                                            Set current instance year to the given value.\n * @method        CarbonImmutable     setYear(int $value)                                                                             Set current instance year to the given value.\n * @method        CarbonImmutable     months(int $value)                                                                              Set current instance month to the given value.\n * @method        CarbonImmutable     month(int $value)                                                                               Set current instance month to the given value.\n * @method        CarbonImmutable     setMonths(int $value)                                                                           Set current instance month to the given value.\n * @method        CarbonImmutable     setMonth(int $value)                                                                            Set current instance month to the given value.\n * @method        CarbonImmutable     days(int $value)                                                                                Set current instance day to the given value.\n * @method        CarbonImmutable     day(int $value)                                                                                 Set current instance day to the given value.\n * @method        CarbonImmutable     setDays(int $value)                                                                             Set current instance day to the given value.\n * @method        CarbonImmutable     setDay(int $value)                                                                              Set current instance day to the given value.\n * @method        CarbonImmutable     hours(int $value)                                                                               Set current instance hour to the given value.\n * @method        CarbonImmutable     hour(int $value)                                                                                Set current instance hour to the given value.\n * @method        CarbonImmutable     setHours(int $value)                                                                            Set current instance hour to the given value.\n * @method        CarbonImmutable     setHour(int $value)                                                                             Set current instance hour to the given value.\n * @method        CarbonImmutable     minutes(int $value)                                                                             Set current instance minute to the given value.\n * @method        CarbonImmutable     minute(int $value)                                                                              Set current instance minute to the given value.\n * @method        CarbonImmutable     setMinutes(int $value)                                                                          Set current instance minute to the given value.\n * @method        CarbonImmutable     setMinute(int $value)                                                                           Set current instance minute to the given value.\n * @method        CarbonImmutable     seconds(int $value)                                                                             Set current instance second to the given value.\n * @method        CarbonImmutable     second(int $value)                                                                              Set current instance second to the given value.\n * @method        CarbonImmutable     setSeconds(int $value)                                                                          Set current instance second to the given value.\n * @method        CarbonImmutable     setSecond(int $value)                                                                           Set current instance second to the given value.\n * @method        CarbonImmutable     millis(int $value)                                                                              Set current instance millisecond to the given value.\n * @method        CarbonImmutable     milli(int $value)                                                                               Set current instance millisecond to the given value.\n * @method        CarbonImmutable     setMillis(int $value)                                                                           Set current instance millisecond to the given value.\n * @method        CarbonImmutable     setMilli(int $value)                                                                            Set current instance millisecond to the given value.\n * @method        CarbonImmutable     milliseconds(int $value)                                                                        Set current instance millisecond to the given value.\n * @method        CarbonImmutable     millisecond(int $value)                                                                         Set current instance millisecond to the given value.\n * @method        CarbonImmutable     setMilliseconds(int $value)                                                                     Set current instance millisecond to the given value.\n * @method        CarbonImmutable     setMillisecond(int $value)                                                                      Set current instance millisecond to the given value.\n * @method        CarbonImmutable     micros(int $value)                                                                              Set current instance microsecond to the given value.\n * @method        CarbonImmutable     micro(int $value)                                                                               Set current instance microsecond to the given value.\n * @method        CarbonImmutable     setMicros(int $value)                                                                           Set current instance microsecond to the given value.\n * @method        CarbonImmutable     setMicro(int $value)                                                                            Set current instance microsecond to the given value.\n * @method        CarbonImmutable     microseconds(int $value)                                                                        Set current instance microsecond to the given value.\n * @method        CarbonImmutable     microsecond(int $value)                                                                         Set current instance microsecond to the given value.\n * @method        CarbonImmutable     setMicroseconds(int $value)                                                                     Set current instance microsecond to the given value.\n * @method        CarbonImmutable     setMicrosecond(int $value)                                                                      Set current instance microsecond to the given value.\n * @method        CarbonImmutable     addYears(int $value = 1)                                                                        Add years (the $value count passed in) to the instance (using date interval).\n * @method        CarbonImmutable     addYear()                                                                                       Add one year to the instance (using date interval).\n * @method        CarbonImmutable     subYears(int $value = 1)                                                                        Sub years (the $value count passed in) to the instance (using date interval).\n * @method        CarbonImmutable     subYear()                                                                                       Sub one year to the instance (using date interval).\n * @method        CarbonImmutable     addYearsWithOverflow(int $value = 1)                                                            Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonImmutable     addYearWithOverflow()                                                                           Add one year to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonImmutable     subYearsWithOverflow(int $value = 1)                                                            Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonImmutable     subYearWithOverflow()                                                                           Sub one year to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonImmutable     addYearsWithoutOverflow(int $value = 1)                                                         Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     addYearWithoutOverflow()                                                                        Add one year to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     subYearsWithoutOverflow(int $value = 1)                                                         Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     subYearWithoutOverflow()                                                                        Sub one year to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     addYearsWithNoOverflow(int $value = 1)                                                          Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     addYearWithNoOverflow()                                                                         Add one year to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     subYearsWithNoOverflow(int $value = 1)                                                          Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     subYearWithNoOverflow()                                                                         Sub one year to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     addYearsNoOverflow(int $value = 1)                                                              Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     addYearNoOverflow()                                                                             Add one year to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     subYearsNoOverflow(int $value = 1)                                                              Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     subYearNoOverflow()                                                                             Sub one year to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     addMonths(int $value = 1)                                                                       Add months (the $value count passed in) to the instance (using date interval).\n * @method        CarbonImmutable     addMonth()                                                                                      Add one month to the instance (using date interval).\n * @method        CarbonImmutable     subMonths(int $value = 1)                                                                       Sub months (the $value count passed in) to the instance (using date interval).\n * @method        CarbonImmutable     subMonth()                                                                                      Sub one month to the instance (using date interval).\n * @method        CarbonImmutable     addMonthsWithOverflow(int $value = 1)                                                           Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonImmutable     addMonthWithOverflow()                                                                          Add one month to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonImmutable     subMonthsWithOverflow(int $value = 1)                                                           Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonImmutable     subMonthWithOverflow()                                                                          Sub one month to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonImmutable     addMonthsWithoutOverflow(int $value = 1)                                                        Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     addMonthWithoutOverflow()                                                                       Add one month to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     subMonthsWithoutOverflow(int $value = 1)                                                        Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     subMonthWithoutOverflow()                                                                       Sub one month to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     addMonthsWithNoOverflow(int $value = 1)                                                         Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     addMonthWithNoOverflow()                                                                        Add one month to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     subMonthsWithNoOverflow(int $value = 1)                                                         Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     subMonthWithNoOverflow()                                                                        Sub one month to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     addMonthsNoOverflow(int $value = 1)                                                             Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     addMonthNoOverflow()                                                                            Add one month to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     subMonthsNoOverflow(int $value = 1)                                                             Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     subMonthNoOverflow()                                                                            Sub one month to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     addDays(int $value = 1)                                                                         Add days (the $value count passed in) to the instance (using date interval).\n * @method        CarbonImmutable     addDay()                                                                                        Add one day to the instance (using date interval).\n * @method        CarbonImmutable     subDays(int $value = 1)                                                                         Sub days (the $value count passed in) to the instance (using date interval).\n * @method        CarbonImmutable     subDay()                                                                                        Sub one day to the instance (using date interval).\n * @method        CarbonImmutable     addHours(int $value = 1)                                                                        Add hours (the $value count passed in) to the instance (using date interval).\n * @method        CarbonImmutable     addHour()                                                                                       Add one hour to the instance (using date interval).\n * @method        CarbonImmutable     subHours(int $value = 1)                                                                        Sub hours (the $value count passed in) to the instance (using date interval).\n * @method        CarbonImmutable     subHour()                                                                                       Sub one hour to the instance (using date interval).\n * @method        CarbonImmutable     addMinutes(int $value = 1)                                                                      Add minutes (the $value count passed in) to the instance (using date interval).\n * @method        CarbonImmutable     addMinute()                                                                                     Add one minute to the instance (using date interval).\n * @method        CarbonImmutable     subMinutes(int $value = 1)                                                                      Sub minutes (the $value count passed in) to the instance (using date interval).\n * @method        CarbonImmutable     subMinute()                                                                                     Sub one minute to the instance (using date interval).\n * @method        CarbonImmutable     addSeconds(int $value = 1)                                                                      Add seconds (the $value count passed in) to the instance (using date interval).\n * @method        CarbonImmutable     addSecond()                                                                                     Add one second to the instance (using date interval).\n * @method        CarbonImmutable     subSeconds(int $value = 1)                                                                      Sub seconds (the $value count passed in) to the instance (using date interval).\n * @method        CarbonImmutable     subSecond()                                                                                     Sub one second to the instance (using date interval).\n * @method        CarbonImmutable     addMillis(int $value = 1)                                                                       Add milliseconds (the $value count passed in) to the instance (using date interval).\n * @method        CarbonImmutable     addMilli()                                                                                      Add one millisecond to the instance (using date interval).\n * @method        CarbonImmutable     subMillis(int $value = 1)                                                                       Sub milliseconds (the $value count passed in) to the instance (using date interval).\n * @method        CarbonImmutable     subMilli()                                                                                      Sub one millisecond to the instance (using date interval).\n * @method        CarbonImmutable     addMilliseconds(int $value = 1)                                                                 Add milliseconds (the $value count passed in) to the instance (using date interval).\n * @method        CarbonImmutable     addMillisecond()                                                                                Add one millisecond to the instance (using date interval).\n * @method        CarbonImmutable     subMilliseconds(int $value = 1)                                                                 Sub milliseconds (the $value count passed in) to the instance (using date interval).\n * @method        CarbonImmutable     subMillisecond()                                                                                Sub one millisecond to the instance (using date interval).\n * @method        CarbonImmutable     addMicros(int $value = 1)                                                                       Add microseconds (the $value count passed in) to the instance (using date interval).\n * @method        CarbonImmutable     addMicro()                                                                                      Add one microsecond to the instance (using date interval).\n * @method        CarbonImmutable     subMicros(int $value = 1)                                                                       Sub microseconds (the $value count passed in) to the instance (using date interval).\n * @method        CarbonImmutable     subMicro()                                                                                      Sub one microsecond to the instance (using date interval).\n * @method        CarbonImmutable     addMicroseconds(int $value = 1)                                                                 Add microseconds (the $value count passed in) to the instance (using date interval).\n * @method        CarbonImmutable     addMicrosecond()                                                                                Add one microsecond to the instance (using date interval).\n * @method        CarbonImmutable     subMicroseconds(int $value = 1)                                                                 Sub microseconds (the $value count passed in) to the instance (using date interval).\n * @method        CarbonImmutable     subMicrosecond()                                                                                Sub one microsecond to the instance (using date interval).\n * @method        CarbonImmutable     addMillennia(int $value = 1)                                                                    Add millennia (the $value count passed in) to the instance (using date interval).\n * @method        CarbonImmutable     addMillennium()                                                                                 Add one millennium to the instance (using date interval).\n * @method        CarbonImmutable     subMillennia(int $value = 1)                                                                    Sub millennia (the $value count passed in) to the instance (using date interval).\n * @method        CarbonImmutable     subMillennium()                                                                                 Sub one millennium to the instance (using date interval).\n * @method        CarbonImmutable     addMillenniaWithOverflow(int $value = 1)                                                        Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonImmutable     addMillenniumWithOverflow()                                                                     Add one millennium to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonImmutable     subMillenniaWithOverflow(int $value = 1)                                                        Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonImmutable     subMillenniumWithOverflow()                                                                     Sub one millennium to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonImmutable     addMillenniaWithoutOverflow(int $value = 1)                                                     Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     addMillenniumWithoutOverflow()                                                                  Add one millennium to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     subMillenniaWithoutOverflow(int $value = 1)                                                     Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     subMillenniumWithoutOverflow()                                                                  Sub one millennium to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     addMillenniaWithNoOverflow(int $value = 1)                                                      Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     addMillenniumWithNoOverflow()                                                                   Add one millennium to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     subMillenniaWithNoOverflow(int $value = 1)                                                      Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     subMillenniumWithNoOverflow()                                                                   Sub one millennium to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     addMillenniaNoOverflow(int $value = 1)                                                          Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     addMillenniumNoOverflow()                                                                       Add one millennium to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     subMillenniaNoOverflow(int $value = 1)                                                          Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     subMillenniumNoOverflow()                                                                       Sub one millennium to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     addCenturies(int $value = 1)                                                                    Add centuries (the $value count passed in) to the instance (using date interval).\n * @method        CarbonImmutable     addCentury()                                                                                    Add one century to the instance (using date interval).\n * @method        CarbonImmutable     subCenturies(int $value = 1)                                                                    Sub centuries (the $value count passed in) to the instance (using date interval).\n * @method        CarbonImmutable     subCentury()                                                                                    Sub one century to the instance (using date interval).\n * @method        CarbonImmutable     addCenturiesWithOverflow(int $value = 1)                                                        Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonImmutable     addCenturyWithOverflow()                                                                        Add one century to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonImmutable     subCenturiesWithOverflow(int $value = 1)                                                        Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonImmutable     subCenturyWithOverflow()                                                                        Sub one century to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonImmutable     addCenturiesWithoutOverflow(int $value = 1)                                                     Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     addCenturyWithoutOverflow()                                                                     Add one century to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     subCenturiesWithoutOverflow(int $value = 1)                                                     Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     subCenturyWithoutOverflow()                                                                     Sub one century to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     addCenturiesWithNoOverflow(int $value = 1)                                                      Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     addCenturyWithNoOverflow()                                                                      Add one century to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     subCenturiesWithNoOverflow(int $value = 1)                                                      Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     subCenturyWithNoOverflow()                                                                      Sub one century to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     addCenturiesNoOverflow(int $value = 1)                                                          Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     addCenturyNoOverflow()                                                                          Add one century to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     subCenturiesNoOverflow(int $value = 1)                                                          Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     subCenturyNoOverflow()                                                                          Sub one century to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     addDecades(int $value = 1)                                                                      Add decades (the $value count passed in) to the instance (using date interval).\n * @method        CarbonImmutable     addDecade()                                                                                     Add one decade to the instance (using date interval).\n * @method        CarbonImmutable     subDecades(int $value = 1)                                                                      Sub decades (the $value count passed in) to the instance (using date interval).\n * @method        CarbonImmutable     subDecade()                                                                                     Sub one decade to the instance (using date interval).\n * @method        CarbonImmutable     addDecadesWithOverflow(int $value = 1)                                                          Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonImmutable     addDecadeWithOverflow()                                                                         Add one decade to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonImmutable     subDecadesWithOverflow(int $value = 1)                                                          Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonImmutable     subDecadeWithOverflow()                                                                         Sub one decade to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonImmutable     addDecadesWithoutOverflow(int $value = 1)                                                       Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     addDecadeWithoutOverflow()                                                                      Add one decade to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     subDecadesWithoutOverflow(int $value = 1)                                                       Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     subDecadeWithoutOverflow()                                                                      Sub one decade to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     addDecadesWithNoOverflow(int $value = 1)                                                        Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     addDecadeWithNoOverflow()                                                                       Add one decade to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     subDecadesWithNoOverflow(int $value = 1)                                                        Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     subDecadeWithNoOverflow()                                                                       Sub one decade to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     addDecadesNoOverflow(int $value = 1)                                                            Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     addDecadeNoOverflow()                                                                           Add one decade to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     subDecadesNoOverflow(int $value = 1)                                                            Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     subDecadeNoOverflow()                                                                           Sub one decade to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     addQuarters(int $value = 1)                                                                     Add quarters (the $value count passed in) to the instance (using date interval).\n * @method        CarbonImmutable     addQuarter()                                                                                    Add one quarter to the instance (using date interval).\n * @method        CarbonImmutable     subQuarters(int $value = 1)                                                                     Sub quarters (the $value count passed in) to the instance (using date interval).\n * @method        CarbonImmutable     subQuarter()                                                                                    Sub one quarter to the instance (using date interval).\n * @method        CarbonImmutable     addQuartersWithOverflow(int $value = 1)                                                         Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonImmutable     addQuarterWithOverflow()                                                                        Add one quarter to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonImmutable     subQuartersWithOverflow(int $value = 1)                                                         Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonImmutable     subQuarterWithOverflow()                                                                        Sub one quarter to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonImmutable     addQuartersWithoutOverflow(int $value = 1)                                                      Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     addQuarterWithoutOverflow()                                                                     Add one quarter to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     subQuartersWithoutOverflow(int $value = 1)                                                      Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     subQuarterWithoutOverflow()                                                                     Sub one quarter to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     addQuartersWithNoOverflow(int $value = 1)                                                       Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     addQuarterWithNoOverflow()                                                                      Add one quarter to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     subQuartersWithNoOverflow(int $value = 1)                                                       Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     subQuarterWithNoOverflow()                                                                      Sub one quarter to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     addQuartersNoOverflow(int $value = 1)                                                           Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     addQuarterNoOverflow()                                                                          Add one quarter to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     subQuartersNoOverflow(int $value = 1)                                                           Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     subQuarterNoOverflow()                                                                          Sub one quarter to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonImmutable     addWeeks(int $value = 1)                                                                        Add weeks (the $value count passed in) to the instance (using date interval).\n * @method        CarbonImmutable     addWeek()                                                                                       Add one week to the instance (using date interval).\n * @method        CarbonImmutable     subWeeks(int $value = 1)                                                                        Sub weeks (the $value count passed in) to the instance (using date interval).\n * @method        CarbonImmutable     subWeek()                                                                                       Sub one week to the instance (using date interval).\n * @method        CarbonImmutable     addWeekdays(int $value = 1)                                                                     Add weekdays (the $value count passed in) to the instance (using date interval).\n * @method        CarbonImmutable     addWeekday()                                                                                    Add one weekday to the instance (using date interval).\n * @method        CarbonImmutable     subWeekdays(int $value = 1)                                                                     Sub weekdays (the $value count passed in) to the instance (using date interval).\n * @method        CarbonImmutable     subWeekday()                                                                                    Sub one weekday to the instance (using date interval).\n * @method        CarbonImmutable     addRealMicros(int $value = 1)                                                                   Add microseconds (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonImmutable     addRealMicro()                                                                                  Add one microsecond to the instance (using timestamp).\n * @method        CarbonImmutable     subRealMicros(int $value = 1)                                                                   Sub microseconds (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonImmutable     subRealMicro()                                                                                  Sub one microsecond to the instance (using timestamp).\n * @method        CarbonPeriod        microsUntil($endDate = null, int $factor = 1)                                                   Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each microsecond or every X microseconds if a factor is given.\n * @method        CarbonImmutable     addRealMicroseconds(int $value = 1)                                                             Add microseconds (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonImmutable     addRealMicrosecond()                                                                            Add one microsecond to the instance (using timestamp).\n * @method        CarbonImmutable     subRealMicroseconds(int $value = 1)                                                             Sub microseconds (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonImmutable     subRealMicrosecond()                                                                            Sub one microsecond to the instance (using timestamp).\n * @method        CarbonPeriod        microsecondsUntil($endDate = null, int $factor = 1)                                             Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each microsecond or every X microseconds if a factor is given.\n * @method        CarbonImmutable     addRealMillis(int $value = 1)                                                                   Add milliseconds (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonImmutable     addRealMilli()                                                                                  Add one millisecond to the instance (using timestamp).\n * @method        CarbonImmutable     subRealMillis(int $value = 1)                                                                   Sub milliseconds (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonImmutable     subRealMilli()                                                                                  Sub one millisecond to the instance (using timestamp).\n * @method        CarbonPeriod        millisUntil($endDate = null, int $factor = 1)                                                   Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each millisecond or every X milliseconds if a factor is given.\n * @method        CarbonImmutable     addRealMilliseconds(int $value = 1)                                                             Add milliseconds (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonImmutable     addRealMillisecond()                                                                            Add one millisecond to the instance (using timestamp).\n * @method        CarbonImmutable     subRealMilliseconds(int $value = 1)                                                             Sub milliseconds (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonImmutable     subRealMillisecond()                                                                            Sub one millisecond to the instance (using timestamp).\n * @method        CarbonPeriod        millisecondsUntil($endDate = null, int $factor = 1)                                             Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each millisecond or every X milliseconds if a factor is given.\n * @method        CarbonImmutable     addRealSeconds(int $value = 1)                                                                  Add seconds (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonImmutable     addRealSecond()                                                                                 Add one second to the instance (using timestamp).\n * @method        CarbonImmutable     subRealSeconds(int $value = 1)                                                                  Sub seconds (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonImmutable     subRealSecond()                                                                                 Sub one second to the instance (using timestamp).\n * @method        CarbonPeriod        secondsUntil($endDate = null, int $factor = 1)                                                  Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each second or every X seconds if a factor is given.\n * @method        CarbonImmutable     addRealMinutes(int $value = 1)                                                                  Add minutes (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonImmutable     addRealMinute()                                                                                 Add one minute to the instance (using timestamp).\n * @method        CarbonImmutable     subRealMinutes(int $value = 1)                                                                  Sub minutes (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonImmutable     subRealMinute()                                                                                 Sub one minute to the instance (using timestamp).\n * @method        CarbonPeriod        minutesUntil($endDate = null, int $factor = 1)                                                  Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each minute or every X minutes if a factor is given.\n * @method        CarbonImmutable     addRealHours(int $value = 1)                                                                    Add hours (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonImmutable     addRealHour()                                                                                   Add one hour to the instance (using timestamp).\n * @method        CarbonImmutable     subRealHours(int $value = 1)                                                                    Sub hours (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonImmutable     subRealHour()                                                                                   Sub one hour to the instance (using timestamp).\n * @method        CarbonPeriod        hoursUntil($endDate = null, int $factor = 1)                                                    Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each hour or every X hours if a factor is given.\n * @method        CarbonImmutable     addRealDays(int $value = 1)                                                                     Add days (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonImmutable     addRealDay()                                                                                    Add one day to the instance (using timestamp).\n * @method        CarbonImmutable     subRealDays(int $value = 1)                                                                     Sub days (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonImmutable     subRealDay()                                                                                    Sub one day to the instance (using timestamp).\n * @method        CarbonPeriod        daysUntil($endDate = null, int $factor = 1)                                                     Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each day or every X days if a factor is given.\n * @method        CarbonImmutable     addRealWeeks(int $value = 1)                                                                    Add weeks (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonImmutable     addRealWeek()                                                                                   Add one week to the instance (using timestamp).\n * @method        CarbonImmutable     subRealWeeks(int $value = 1)                                                                    Sub weeks (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonImmutable     subRealWeek()                                                                                   Sub one week to the instance (using timestamp).\n * @method        CarbonPeriod        weeksUntil($endDate = null, int $factor = 1)                                                    Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each week or every X weeks if a factor is given.\n * @method        CarbonImmutable     addRealMonths(int $value = 1)                                                                   Add months (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonImmutable     addRealMonth()                                                                                  Add one month to the instance (using timestamp).\n * @method        CarbonImmutable     subRealMonths(int $value = 1)                                                                   Sub months (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonImmutable     subRealMonth()                                                                                  Sub one month to the instance (using timestamp).\n * @method        CarbonPeriod        monthsUntil($endDate = null, int $factor = 1)                                                   Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each month or every X months if a factor is given.\n * @method        CarbonImmutable     addRealQuarters(int $value = 1)                                                                 Add quarters (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonImmutable     addRealQuarter()                                                                                Add one quarter to the instance (using timestamp).\n * @method        CarbonImmutable     subRealQuarters(int $value = 1)                                                                 Sub quarters (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonImmutable     subRealQuarter()                                                                                Sub one quarter to the instance (using timestamp).\n * @method        CarbonPeriod        quartersUntil($endDate = null, int $factor = 1)                                                 Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each quarter or every X quarters if a factor is given.\n * @method        CarbonImmutable     addRealYears(int $value = 1)                                                                    Add years (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonImmutable     addRealYear()                                                                                   Add one year to the instance (using timestamp).\n * @method        CarbonImmutable     subRealYears(int $value = 1)                                                                    Sub years (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonImmutable     subRealYear()                                                                                   Sub one year to the instance (using timestamp).\n * @method        CarbonPeriod        yearsUntil($endDate = null, int $factor = 1)                                                    Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each year or every X years if a factor is given.\n * @method        CarbonImmutable     addRealDecades(int $value = 1)                                                                  Add decades (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonImmutable     addRealDecade()                                                                                 Add one decade to the instance (using timestamp).\n * @method        CarbonImmutable     subRealDecades(int $value = 1)                                                                  Sub decades (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonImmutable     subRealDecade()                                                                                 Sub one decade to the instance (using timestamp).\n * @method        CarbonPeriod        decadesUntil($endDate = null, int $factor = 1)                                                  Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each decade or every X decades if a factor is given.\n * @method        CarbonImmutable     addRealCenturies(int $value = 1)                                                                Add centuries (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonImmutable     addRealCentury()                                                                                Add one century to the instance (using timestamp).\n * @method        CarbonImmutable     subRealCenturies(int $value = 1)                                                                Sub centuries (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonImmutable     subRealCentury()                                                                                Sub one century to the instance (using timestamp).\n * @method        CarbonPeriod        centuriesUntil($endDate = null, int $factor = 1)                                                Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each century or every X centuries if a factor is given.\n * @method        CarbonImmutable     addRealMillennia(int $value = 1)                                                                Add millennia (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonImmutable     addRealMillennium()                                                                             Add one millennium to the instance (using timestamp).\n * @method        CarbonImmutable     subRealMillennia(int $value = 1)                                                                Sub millennia (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonImmutable     subRealMillennium()                                                                             Sub one millennium to the instance (using timestamp).\n * @method        CarbonPeriod        millenniaUntil($endDate = null, int $factor = 1)                                                Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each millennium or every X millennia if a factor is given.\n * @method        CarbonImmutable     roundYear(float $precision = 1, string $function = \"round\")                                     Round the current instance year with given precision using the given function.\n * @method        CarbonImmutable     roundYears(float $precision = 1, string $function = \"round\")                                    Round the current instance year with given precision using the given function.\n * @method        CarbonImmutable     floorYear(float $precision = 1)                                                                 Truncate the current instance year with given precision.\n * @method        CarbonImmutable     floorYears(float $precision = 1)                                                                Truncate the current instance year with given precision.\n * @method        CarbonImmutable     ceilYear(float $precision = 1)                                                                  Ceil the current instance year with given precision.\n * @method        CarbonImmutable     ceilYears(float $precision = 1)                                                                 Ceil the current instance year with given precision.\n * @method        CarbonImmutable     roundMonth(float $precision = 1, string $function = \"round\")                                    Round the current instance month with given precision using the given function.\n * @method        CarbonImmutable     roundMonths(float $precision = 1, string $function = \"round\")                                   Round the current instance month with given precision using the given function.\n * @method        CarbonImmutable     floorMonth(float $precision = 1)                                                                Truncate the current instance month with given precision.\n * @method        CarbonImmutable     floorMonths(float $precision = 1)                                                               Truncate the current instance month with given precision.\n * @method        CarbonImmutable     ceilMonth(float $precision = 1)                                                                 Ceil the current instance month with given precision.\n * @method        CarbonImmutable     ceilMonths(float $precision = 1)                                                                Ceil the current instance month with given precision.\n * @method        CarbonImmutable     roundDay(float $precision = 1, string $function = \"round\")                                      Round the current instance day with given precision using the given function.\n * @method        CarbonImmutable     roundDays(float $precision = 1, string $function = \"round\")                                     Round the current instance day with given precision using the given function.\n * @method        CarbonImmutable     floorDay(float $precision = 1)                                                                  Truncate the current instance day with given precision.\n * @method        CarbonImmutable     floorDays(float $precision = 1)                                                                 Truncate the current instance day with given precision.\n * @method        CarbonImmutable     ceilDay(float $precision = 1)                                                                   Ceil the current instance day with given precision.\n * @method        CarbonImmutable     ceilDays(float $precision = 1)                                                                  Ceil the current instance day with given precision.\n * @method        CarbonImmutable     roundHour(float $precision = 1, string $function = \"round\")                                     Round the current instance hour with given precision using the given function.\n * @method        CarbonImmutable     roundHours(float $precision = 1, string $function = \"round\")                                    Round the current instance hour with given precision using the given function.\n * @method        CarbonImmutable     floorHour(float $precision = 1)                                                                 Truncate the current instance hour with given precision.\n * @method        CarbonImmutable     floorHours(float $precision = 1)                                                                Truncate the current instance hour with given precision.\n * @method        CarbonImmutable     ceilHour(float $precision = 1)                                                                  Ceil the current instance hour with given precision.\n * @method        CarbonImmutable     ceilHours(float $precision = 1)                                                                 Ceil the current instance hour with given precision.\n * @method        CarbonImmutable     roundMinute(float $precision = 1, string $function = \"round\")                                   Round the current instance minute with given precision using the given function.\n * @method        CarbonImmutable     roundMinutes(float $precision = 1, string $function = \"round\")                                  Round the current instance minute with given precision using the given function.\n * @method        CarbonImmutable     floorMinute(float $precision = 1)                                                               Truncate the current instance minute with given precision.\n * @method        CarbonImmutable     floorMinutes(float $precision = 1)                                                              Truncate the current instance minute with given precision.\n * @method        CarbonImmutable     ceilMinute(float $precision = 1)                                                                Ceil the current instance minute with given precision.\n * @method        CarbonImmutable     ceilMinutes(float $precision = 1)                                                               Ceil the current instance minute with given precision.\n * @method        CarbonImmutable     roundSecond(float $precision = 1, string $function = \"round\")                                   Round the current instance second with given precision using the given function.\n * @method        CarbonImmutable     roundSeconds(float $precision = 1, string $function = \"round\")                                  Round the current instance second with given precision using the given function.\n * @method        CarbonImmutable     floorSecond(float $precision = 1)                                                               Truncate the current instance second with given precision.\n * @method        CarbonImmutable     floorSeconds(float $precision = 1)                                                              Truncate the current instance second with given precision.\n * @method        CarbonImmutable     ceilSecond(float $precision = 1)                                                                Ceil the current instance second with given precision.\n * @method        CarbonImmutable     ceilSeconds(float $precision = 1)                                                               Ceil the current instance second with given precision.\n * @method        CarbonImmutable     roundMillennium(float $precision = 1, string $function = \"round\")                               Round the current instance millennium with given precision using the given function.\n * @method        CarbonImmutable     roundMillennia(float $precision = 1, string $function = \"round\")                                Round the current instance millennium with given precision using the given function.\n * @method        CarbonImmutable     floorMillennium(float $precision = 1)                                                           Truncate the current instance millennium with given precision.\n * @method        CarbonImmutable     floorMillennia(float $precision = 1)                                                            Truncate the current instance millennium with given precision.\n * @method        CarbonImmutable     ceilMillennium(float $precision = 1)                                                            Ceil the current instance millennium with given precision.\n * @method        CarbonImmutable     ceilMillennia(float $precision = 1)                                                             Ceil the current instance millennium with given precision.\n * @method        CarbonImmutable     roundCentury(float $precision = 1, string $function = \"round\")                                  Round the current instance century with given precision using the given function.\n * @method        CarbonImmutable     roundCenturies(float $precision = 1, string $function = \"round\")                                Round the current instance century with given precision using the given function.\n * @method        CarbonImmutable     floorCentury(float $precision = 1)                                                              Truncate the current instance century with given precision.\n * @method        CarbonImmutable     floorCenturies(float $precision = 1)                                                            Truncate the current instance century with given precision.\n * @method        CarbonImmutable     ceilCentury(float $precision = 1)                                                               Ceil the current instance century with given precision.\n * @method        CarbonImmutable     ceilCenturies(float $precision = 1)                                                             Ceil the current instance century with given precision.\n * @method        CarbonImmutable     roundDecade(float $precision = 1, string $function = \"round\")                                   Round the current instance decade with given precision using the given function.\n * @method        CarbonImmutable     roundDecades(float $precision = 1, string $function = \"round\")                                  Round the current instance decade with given precision using the given function.\n * @method        CarbonImmutable     floorDecade(float $precision = 1)                                                               Truncate the current instance decade with given precision.\n * @method        CarbonImmutable     floorDecades(float $precision = 1)                                                              Truncate the current instance decade with given precision.\n * @method        CarbonImmutable     ceilDecade(float $precision = 1)                                                                Ceil the current instance decade with given precision.\n * @method        CarbonImmutable     ceilDecades(float $precision = 1)                                                               Ceil the current instance decade with given precision.\n * @method        CarbonImmutable     roundQuarter(float $precision = 1, string $function = \"round\")                                  Round the current instance quarter with given precision using the given function.\n * @method        CarbonImmutable     roundQuarters(float $precision = 1, string $function = \"round\")                                 Round the current instance quarter with given precision using the given function.\n * @method        CarbonImmutable     floorQuarter(float $precision = 1)                                                              Truncate the current instance quarter with given precision.\n * @method        CarbonImmutable     floorQuarters(float $precision = 1)                                                             Truncate the current instance quarter with given precision.\n * @method        CarbonImmutable     ceilQuarter(float $precision = 1)                                                               Ceil the current instance quarter with given precision.\n * @method        CarbonImmutable     ceilQuarters(float $precision = 1)                                                              Ceil the current instance quarter with given precision.\n * @method        CarbonImmutable     roundMillisecond(float $precision = 1, string $function = \"round\")                              Round the current instance millisecond with given precision using the given function.\n * @method        CarbonImmutable     roundMilliseconds(float $precision = 1, string $function = \"round\")                             Round the current instance millisecond with given precision using the given function.\n * @method        CarbonImmutable     floorMillisecond(float $precision = 1)                                                          Truncate the current instance millisecond with given precision.\n * @method        CarbonImmutable     floorMilliseconds(float $precision = 1)                                                         Truncate the current instance millisecond with given precision.\n * @method        CarbonImmutable     ceilMillisecond(float $precision = 1)                                                           Ceil the current instance millisecond with given precision.\n * @method        CarbonImmutable     ceilMilliseconds(float $precision = 1)                                                          Ceil the current instance millisecond with given precision.\n * @method        CarbonImmutable     roundMicrosecond(float $precision = 1, string $function = \"round\")                              Round the current instance microsecond with given precision using the given function.\n * @method        CarbonImmutable     roundMicroseconds(float $precision = 1, string $function = \"round\")                             Round the current instance microsecond with given precision using the given function.\n * @method        CarbonImmutable     floorMicrosecond(float $precision = 1)                                                          Truncate the current instance microsecond with given precision.\n * @method        CarbonImmutable     floorMicroseconds(float $precision = 1)                                                         Truncate the current instance microsecond with given precision.\n * @method        CarbonImmutable     ceilMicrosecond(float $precision = 1)                                                           Ceil the current instance microsecond with given precision.\n * @method        CarbonImmutable     ceilMicroseconds(float $precision = 1)                                                          Ceil the current instance microsecond with given precision.\n * @method        string              shortAbsoluteDiffForHumans(DateTimeInterface $other = null, int $parts = 1)                     Get the difference (short format, 'Absolute' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.)\n * @method        string              longAbsoluteDiffForHumans(DateTimeInterface $other = null, int $parts = 1)                      Get the difference (long format, 'Absolute' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.)\n * @method        string              shortRelativeDiffForHumans(DateTimeInterface $other = null, int $parts = 1)                     Get the difference (short format, 'Relative' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.)\n * @method        string              longRelativeDiffForHumans(DateTimeInterface $other = null, int $parts = 1)                      Get the difference (long format, 'Relative' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.)\n * @method        string              shortRelativeToNowDiffForHumans(DateTimeInterface $other = null, int $parts = 1)                Get the difference (short format, 'RelativeToNow' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.)\n * @method        string              longRelativeToNowDiffForHumans(DateTimeInterface $other = null, int $parts = 1)                 Get the difference (long format, 'RelativeToNow' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.)\n * @method        string              shortRelativeToOtherDiffForHumans(DateTimeInterface $other = null, int $parts = 1)              Get the difference (short format, 'RelativeToOther' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.)\n * @method        string              longRelativeToOtherDiffForHumans(DateTimeInterface $other = null, int $parts = 1)               Get the difference (long format, 'RelativeToOther' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.)\n * @method        static static|false createFromFormat(string $format, string $time, DateTimeZone|string|false|null $timezone = null) Parse a string into a new CarbonImmutable object according to the specified format.\n * @method        static static       __set_state(array $array)                                                                       https://php.net/manual/en/datetime.set-state.php\n *\n * </autodoc>\n */\nclass CarbonImmutable extends DateTimeImmutable implements CarbonInterface\n{\n    use Date {\n        __clone as dateTraitClone;\n    }\n\n    public function __clone()\n    {\n        $this->dateTraitClone();\n        $this->endOfTime = false;\n        $this->startOfTime = false;\n    }\n\n    /**\n     * Create a very old date representing start of time.\n     *\n     * @return static\n     */\n    public static function startOfTime(): self\n    {\n        $date = static::parse('0001-01-01')->years(self::getStartOfTimeYear());\n        $date->startOfTime = true;\n\n        return $date;\n    }\n\n    /**\n     * Create a very far date representing end of time.\n     *\n     * @return static\n     */\n    public static function endOfTime(): self\n    {\n        $date = static::parse('9999-12-31 23:59:59.999999')->years(self::getEndOfTimeYear());\n        $date->endOfTime = true;\n\n        return $date;\n    }\n\n    /**\n     * @codeCoverageIgnore\n     */\n    private static function getEndOfTimeYear(): int\n    {\n        if (version_compare(PHP_VERSION, '7.3.0-dev', '<')) {\n            return 145261681241552;\n        }\n\n        // Remove if https://bugs.php.net/bug.php?id=81107 is fixed\n        if (version_compare(PHP_VERSION, '8.1.0-dev', '>=')) {\n            return 1118290769066902787;\n        }\n\n        return PHP_INT_MAX;\n    }\n\n    /**\n     * @codeCoverageIgnore\n     */\n    private static function getStartOfTimeYear(): int\n    {\n        if (version_compare(PHP_VERSION, '7.3.0-dev', '<')) {\n            return -135908816449551;\n        }\n\n        // Remove if https://bugs.php.net/bug.php?id=81107 is fixed\n        if (version_compare(PHP_VERSION, '8.1.0-dev', '>=')) {\n            return -1118290769066898816;\n        }\n\n        return max(PHP_INT_MIN, -9223372036854773760);\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/CarbonInterface.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon;\n\nuse BadMethodCallException;\nuse Carbon\\Exceptions\\BadComparisonUnitException;\nuse Carbon\\Exceptions\\ImmutableException;\nuse Carbon\\Exceptions\\InvalidDateException;\nuse Carbon\\Exceptions\\InvalidFormatException;\nuse Carbon\\Exceptions\\UnknownGetterException;\nuse Carbon\\Exceptions\\UnknownMethodException;\nuse Carbon\\Exceptions\\UnknownSetterException;\nuse Closure;\nuse DateInterval;\nuse DateTime;\nuse DateTimeImmutable;\nuse DateTimeInterface;\nuse DateTimeZone;\nuse JsonSerializable;\nuse ReflectionException;\nuse ReturnTypeWillChange;\nuse Symfony\\Component\\Translation\\TranslatorInterface;\nuse Throwable;\n\n/**\n * Common interface for Carbon and CarbonImmutable.\n *\n * <autodoc generated by `composer phpdoc`>\n *\n * @property      int              $year\n * @property      int              $yearIso\n * @property      int              $month\n * @property      int              $day\n * @property      int              $hour\n * @property      int              $minute\n * @property      int              $second\n * @property      int              $micro\n * @property      int              $microsecond\n * @property      int|float|string $timestamp                                                                         seconds since the Unix Epoch\n * @property      string           $englishDayOfWeek                                                                  the day of week in English\n * @property      string           $shortEnglishDayOfWeek                                                             the abbreviated day of week in English\n * @property      string           $englishMonth                                                                      the month in English\n * @property      string           $shortEnglishMonth                                                                 the abbreviated month in English\n * @property      int              $milliseconds\n * @property      int              $millisecond\n * @property      int              $milli\n * @property      int              $week                                                                              1 through 53\n * @property      int              $isoWeek                                                                           1 through 53\n * @property      int              $weekYear                                                                          year according to week format\n * @property      int              $isoWeekYear                                                                       year according to ISO week format\n * @property      int              $dayOfYear                                                                         1 through 366\n * @property      int              $age                                                                               does a diffInYears() with default parameters\n * @property      int              $offset                                                                            the timezone offset in seconds from UTC\n * @property      int              $offsetMinutes                                                                     the timezone offset in minutes from UTC\n * @property      int              $offsetHours                                                                       the timezone offset in hours from UTC\n * @property      CarbonTimeZone   $timezone                                                                          the current timezone\n * @property      CarbonTimeZone   $tz                                                                                alias of $timezone\n * @property-read int              $dayOfWeek                                                                         0 (for Sunday) through 6 (for Saturday)\n * @property-read int              $dayOfWeekIso                                                                      1 (for Monday) through 7 (for Sunday)\n * @property-read int              $weekOfYear                                                                        ISO-8601 week number of year, weeks starting on Monday\n * @property-read int              $daysInMonth                                                                       number of days in the given month\n * @property-read string           $latinMeridiem                                                                     \"am\"/\"pm\" (Ante meridiem or Post meridiem latin lowercase mark)\n * @property-read string           $latinUpperMeridiem                                                                \"AM\"/\"PM\" (Ante meridiem or Post meridiem latin uppercase mark)\n * @property-read string           $timezoneAbbreviatedName                                                           the current timezone abbreviated name\n * @property-read string           $tzAbbrName                                                                        alias of $timezoneAbbreviatedName\n * @property-read string           $dayName                                                                           long name of weekday translated according to Carbon locale, in english if no translation available for current language\n * @property-read string           $shortDayName                                                                      short name of weekday translated according to Carbon locale, in english if no translation available for current language\n * @property-read string           $minDayName                                                                        very short name of weekday translated according to Carbon locale, in english if no translation available for current language\n * @property-read string           $monthName                                                                         long name of month translated according to Carbon locale, in english if no translation available for current language\n * @property-read string           $shortMonthName                                                                    short name of month translated according to Carbon locale, in english if no translation available for current language\n * @property-read string           $meridiem                                                                          lowercase meridiem mark translated according to Carbon locale, in latin if no translation available for current language\n * @property-read string           $upperMeridiem                                                                     uppercase meridiem mark translated according to Carbon locale, in latin if no translation available for current language\n * @property-read int              $noZeroHour                                                                        current hour from 1 to 24\n * @property-read int              $weeksInYear                                                                       51 through 53\n * @property-read int              $isoWeeksInYear                                                                    51 through 53\n * @property-read int              $weekOfMonth                                                                       1 through 5\n * @property-read int              $weekNumberInMonth                                                                 1 through 5\n * @property-read int              $firstWeekDay                                                                      0 through 6\n * @property-read int              $lastWeekDay                                                                       0 through 6\n * @property-read int              $daysInYear                                                                        365 or 366\n * @property-read int              $quarter                                                                           the quarter of this instance, 1 - 4\n * @property-read int              $decade                                                                            the decade of this instance\n * @property-read int              $century                                                                           the century of this instance\n * @property-read int              $millennium                                                                        the millennium of this instance\n * @property-read bool             $dst                                                                               daylight savings time indicator, true if DST, false otherwise\n * @property-read bool             $local                                                                             checks if the timezone is local, true if local, false otherwise\n * @property-read bool             $utc                                                                               checks if the timezone is UTC, true if UTC, false otherwise\n * @property-read string           $timezoneName                                                                      the current timezone name\n * @property-read string           $tzName                                                                            alias of $timezoneName\n * @property-read string           $locale                                                                            locale of the current instance\n *\n * @method        bool             isUtc()                                                                            Check if the current instance has UTC timezone. (Both isUtc and isUTC cases are valid.)\n * @method        bool             isLocal()                                                                          Check if the current instance has non-UTC timezone.\n * @method        bool             isValid()                                                                          Check if the current instance is a valid date.\n * @method        bool             isDST()                                                                            Check if the current instance is in a daylight saving time.\n * @method        bool             isSunday()                                                                         Checks if the instance day is sunday.\n * @method        bool             isMonday()                                                                         Checks if the instance day is monday.\n * @method        bool             isTuesday()                                                                        Checks if the instance day is tuesday.\n * @method        bool             isWednesday()                                                                      Checks if the instance day is wednesday.\n * @method        bool             isThursday()                                                                       Checks if the instance day is thursday.\n * @method        bool             isFriday()                                                                         Checks if the instance day is friday.\n * @method        bool             isSaturday()                                                                       Checks if the instance day is saturday.\n * @method        bool             isSameYear(Carbon|DateTimeInterface|string|null $date = null)                      Checks if the given date is in the same year as the instance. If null passed, compare to now (with the same timezone).\n * @method        bool             isCurrentYear()                                                                    Checks if the instance is in the same year as the current moment.\n * @method        bool             isNextYear()                                                                       Checks if the instance is in the same year as the current moment next year.\n * @method        bool             isLastYear()                                                                       Checks if the instance is in the same year as the current moment last year.\n * @method        bool             isSameWeek(Carbon|DateTimeInterface|string|null $date = null)                      Checks if the given date is in the same week as the instance. If null passed, compare to now (with the same timezone).\n * @method        bool             isCurrentWeek()                                                                    Checks if the instance is in the same week as the current moment.\n * @method        bool             isNextWeek()                                                                       Checks if the instance is in the same week as the current moment next week.\n * @method        bool             isLastWeek()                                                                       Checks if the instance is in the same week as the current moment last week.\n * @method        bool             isSameDay(Carbon|DateTimeInterface|string|null $date = null)                       Checks if the given date is in the same day as the instance. If null passed, compare to now (with the same timezone).\n * @method        bool             isCurrentDay()                                                                     Checks if the instance is in the same day as the current moment.\n * @method        bool             isNextDay()                                                                        Checks if the instance is in the same day as the current moment next day.\n * @method        bool             isLastDay()                                                                        Checks if the instance is in the same day as the current moment last day.\n * @method        bool             isSameHour(Carbon|DateTimeInterface|string|null $date = null)                      Checks if the given date is in the same hour as the instance. If null passed, compare to now (with the same timezone).\n * @method        bool             isCurrentHour()                                                                    Checks if the instance is in the same hour as the current moment.\n * @method        bool             isNextHour()                                                                       Checks if the instance is in the same hour as the current moment next hour.\n * @method        bool             isLastHour()                                                                       Checks if the instance is in the same hour as the current moment last hour.\n * @method        bool             isSameMinute(Carbon|DateTimeInterface|string|null $date = null)                    Checks if the given date is in the same minute as the instance. If null passed, compare to now (with the same timezone).\n * @method        bool             isCurrentMinute()                                                                  Checks if the instance is in the same minute as the current moment.\n * @method        bool             isNextMinute()                                                                     Checks if the instance is in the same minute as the current moment next minute.\n * @method        bool             isLastMinute()                                                                     Checks if the instance is in the same minute as the current moment last minute.\n * @method        bool             isSameSecond(Carbon|DateTimeInterface|string|null $date = null)                    Checks if the given date is in the same second as the instance. If null passed, compare to now (with the same timezone).\n * @method        bool             isCurrentSecond()                                                                  Checks if the instance is in the same second as the current moment.\n * @method        bool             isNextSecond()                                                                     Checks if the instance is in the same second as the current moment next second.\n * @method        bool             isLastSecond()                                                                     Checks if the instance is in the same second as the current moment last second.\n * @method        bool             isSameMicro(Carbon|DateTimeInterface|string|null $date = null)                     Checks if the given date is in the same microsecond as the instance. If null passed, compare to now (with the same timezone).\n * @method        bool             isCurrentMicro()                                                                   Checks if the instance is in the same microsecond as the current moment.\n * @method        bool             isNextMicro()                                                                      Checks if the instance is in the same microsecond as the current moment next microsecond.\n * @method        bool             isLastMicro()                                                                      Checks if the instance is in the same microsecond as the current moment last microsecond.\n * @method        bool             isSameMicrosecond(Carbon|DateTimeInterface|string|null $date = null)               Checks if the given date is in the same microsecond as the instance. If null passed, compare to now (with the same timezone).\n * @method        bool             isCurrentMicrosecond()                                                             Checks if the instance is in the same microsecond as the current moment.\n * @method        bool             isNextMicrosecond()                                                                Checks if the instance is in the same microsecond as the current moment next microsecond.\n * @method        bool             isLastMicrosecond()                                                                Checks if the instance is in the same microsecond as the current moment last microsecond.\n * @method        bool             isCurrentMonth()                                                                   Checks if the instance is in the same month as the current moment.\n * @method        bool             isNextMonth()                                                                      Checks if the instance is in the same month as the current moment next month.\n * @method        bool             isLastMonth()                                                                      Checks if the instance is in the same month as the current moment last month.\n * @method        bool             isCurrentQuarter()                                                                 Checks if the instance is in the same quarter as the current moment.\n * @method        bool             isNextQuarter()                                                                    Checks if the instance is in the same quarter as the current moment next quarter.\n * @method        bool             isLastQuarter()                                                                    Checks if the instance is in the same quarter as the current moment last quarter.\n * @method        bool             isSameDecade(Carbon|DateTimeInterface|string|null $date = null)                    Checks if the given date is in the same decade as the instance. If null passed, compare to now (with the same timezone).\n * @method        bool             isCurrentDecade()                                                                  Checks if the instance is in the same decade as the current moment.\n * @method        bool             isNextDecade()                                                                     Checks if the instance is in the same decade as the current moment next decade.\n * @method        bool             isLastDecade()                                                                     Checks if the instance is in the same decade as the current moment last decade.\n * @method        bool             isSameCentury(Carbon|DateTimeInterface|string|null $date = null)                   Checks if the given date is in the same century as the instance. If null passed, compare to now (with the same timezone).\n * @method        bool             isCurrentCentury()                                                                 Checks if the instance is in the same century as the current moment.\n * @method        bool             isNextCentury()                                                                    Checks if the instance is in the same century as the current moment next century.\n * @method        bool             isLastCentury()                                                                    Checks if the instance is in the same century as the current moment last century.\n * @method        bool             isSameMillennium(Carbon|DateTimeInterface|string|null $date = null)                Checks if the given date is in the same millennium as the instance. If null passed, compare to now (with the same timezone).\n * @method        bool             isCurrentMillennium()                                                              Checks if the instance is in the same millennium as the current moment.\n * @method        bool             isNextMillennium()                                                                 Checks if the instance is in the same millennium as the current moment next millennium.\n * @method        bool             isLastMillennium()                                                                 Checks if the instance is in the same millennium as the current moment last millennium.\n * @method        CarbonInterface  years(int $value)                                                                  Set current instance year to the given value.\n * @method        CarbonInterface  year(int $value)                                                                   Set current instance year to the given value.\n * @method        CarbonInterface  setYears(int $value)                                                               Set current instance year to the given value.\n * @method        CarbonInterface  setYear(int $value)                                                                Set current instance year to the given value.\n * @method        CarbonInterface  months(int $value)                                                                 Set current instance month to the given value.\n * @method        CarbonInterface  month(int $value)                                                                  Set current instance month to the given value.\n * @method        CarbonInterface  setMonths(int $value)                                                              Set current instance month to the given value.\n * @method        CarbonInterface  setMonth(int $value)                                                               Set current instance month to the given value.\n * @method        CarbonInterface  days(int $value)                                                                   Set current instance day to the given value.\n * @method        CarbonInterface  day(int $value)                                                                    Set current instance day to the given value.\n * @method        CarbonInterface  setDays(int $value)                                                                Set current instance day to the given value.\n * @method        CarbonInterface  setDay(int $value)                                                                 Set current instance day to the given value.\n * @method        CarbonInterface  hours(int $value)                                                                  Set current instance hour to the given value.\n * @method        CarbonInterface  hour(int $value)                                                                   Set current instance hour to the given value.\n * @method        CarbonInterface  setHours(int $value)                                                               Set current instance hour to the given value.\n * @method        CarbonInterface  setHour(int $value)                                                                Set current instance hour to the given value.\n * @method        CarbonInterface  minutes(int $value)                                                                Set current instance minute to the given value.\n * @method        CarbonInterface  minute(int $value)                                                                 Set current instance minute to the given value.\n * @method        CarbonInterface  setMinutes(int $value)                                                             Set current instance minute to the given value.\n * @method        CarbonInterface  setMinute(int $value)                                                              Set current instance minute to the given value.\n * @method        CarbonInterface  seconds(int $value)                                                                Set current instance second to the given value.\n * @method        CarbonInterface  second(int $value)                                                                 Set current instance second to the given value.\n * @method        CarbonInterface  setSeconds(int $value)                                                             Set current instance second to the given value.\n * @method        CarbonInterface  setSecond(int $value)                                                              Set current instance second to the given value.\n * @method        CarbonInterface  millis(int $value)                                                                 Set current instance millisecond to the given value.\n * @method        CarbonInterface  milli(int $value)                                                                  Set current instance millisecond to the given value.\n * @method        CarbonInterface  setMillis(int $value)                                                              Set current instance millisecond to the given value.\n * @method        CarbonInterface  setMilli(int $value)                                                               Set current instance millisecond to the given value.\n * @method        CarbonInterface  milliseconds(int $value)                                                           Set current instance millisecond to the given value.\n * @method        CarbonInterface  millisecond(int $value)                                                            Set current instance millisecond to the given value.\n * @method        CarbonInterface  setMilliseconds(int $value)                                                        Set current instance millisecond to the given value.\n * @method        CarbonInterface  setMillisecond(int $value)                                                         Set current instance millisecond to the given value.\n * @method        CarbonInterface  micros(int $value)                                                                 Set current instance microsecond to the given value.\n * @method        CarbonInterface  micro(int $value)                                                                  Set current instance microsecond to the given value.\n * @method        CarbonInterface  setMicros(int $value)                                                              Set current instance microsecond to the given value.\n * @method        CarbonInterface  setMicro(int $value)                                                               Set current instance microsecond to the given value.\n * @method        CarbonInterface  microseconds(int $value)                                                           Set current instance microsecond to the given value.\n * @method        CarbonInterface  microsecond(int $value)                                                            Set current instance microsecond to the given value.\n * @method        CarbonInterface  setMicroseconds(int $value)                                                        Set current instance microsecond to the given value.\n * @method        CarbonInterface  setMicrosecond(int $value)                                                         Set current instance microsecond to the given value.\n * @method        CarbonInterface  addYears(int $value = 1)                                                           Add years (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  addYear()                                                                          Add one year to the instance (using date interval).\n * @method        CarbonInterface  subYears(int $value = 1)                                                           Sub years (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  subYear()                                                                          Sub one year to the instance (using date interval).\n * @method        CarbonInterface  addYearsWithOverflow(int $value = 1)                                               Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonInterface  addYearWithOverflow()                                                              Add one year to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonInterface  subYearsWithOverflow(int $value = 1)                                               Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonInterface  subYearWithOverflow()                                                              Sub one year to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonInterface  addYearsWithoutOverflow(int $value = 1)                                            Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addYearWithoutOverflow()                                                           Add one year to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subYearsWithoutOverflow(int $value = 1)                                            Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subYearWithoutOverflow()                                                           Sub one year to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addYearsWithNoOverflow(int $value = 1)                                             Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addYearWithNoOverflow()                                                            Add one year to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subYearsWithNoOverflow(int $value = 1)                                             Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subYearWithNoOverflow()                                                            Sub one year to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addYearsNoOverflow(int $value = 1)                                                 Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addYearNoOverflow()                                                                Add one year to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subYearsNoOverflow(int $value = 1)                                                 Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subYearNoOverflow()                                                                Sub one year to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addMonths(int $value = 1)                                                          Add months (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  addMonth()                                                                         Add one month to the instance (using date interval).\n * @method        CarbonInterface  subMonths(int $value = 1)                                                          Sub months (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  subMonth()                                                                         Sub one month to the instance (using date interval).\n * @method        CarbonInterface  addMonthsWithOverflow(int $value = 1)                                              Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonInterface  addMonthWithOverflow()                                                             Add one month to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonInterface  subMonthsWithOverflow(int $value = 1)                                              Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonInterface  subMonthWithOverflow()                                                             Sub one month to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonInterface  addMonthsWithoutOverflow(int $value = 1)                                           Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addMonthWithoutOverflow()                                                          Add one month to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subMonthsWithoutOverflow(int $value = 1)                                           Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subMonthWithoutOverflow()                                                          Sub one month to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addMonthsWithNoOverflow(int $value = 1)                                            Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addMonthWithNoOverflow()                                                           Add one month to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subMonthsWithNoOverflow(int $value = 1)                                            Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subMonthWithNoOverflow()                                                           Sub one month to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addMonthsNoOverflow(int $value = 1)                                                Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addMonthNoOverflow()                                                               Add one month to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subMonthsNoOverflow(int $value = 1)                                                Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subMonthNoOverflow()                                                               Sub one month to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addDays(int $value = 1)                                                            Add days (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  addDay()                                                                           Add one day to the instance (using date interval).\n * @method        CarbonInterface  subDays(int $value = 1)                                                            Sub days (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  subDay()                                                                           Sub one day to the instance (using date interval).\n * @method        CarbonInterface  addHours(int $value = 1)                                                           Add hours (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  addHour()                                                                          Add one hour to the instance (using date interval).\n * @method        CarbonInterface  subHours(int $value = 1)                                                           Sub hours (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  subHour()                                                                          Sub one hour to the instance (using date interval).\n * @method        CarbonInterface  addMinutes(int $value = 1)                                                         Add minutes (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  addMinute()                                                                        Add one minute to the instance (using date interval).\n * @method        CarbonInterface  subMinutes(int $value = 1)                                                         Sub minutes (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  subMinute()                                                                        Sub one minute to the instance (using date interval).\n * @method        CarbonInterface  addSeconds(int $value = 1)                                                         Add seconds (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  addSecond()                                                                        Add one second to the instance (using date interval).\n * @method        CarbonInterface  subSeconds(int $value = 1)                                                         Sub seconds (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  subSecond()                                                                        Sub one second to the instance (using date interval).\n * @method        CarbonInterface  addMillis(int $value = 1)                                                          Add milliseconds (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  addMilli()                                                                         Add one millisecond to the instance (using date interval).\n * @method        CarbonInterface  subMillis(int $value = 1)                                                          Sub milliseconds (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  subMilli()                                                                         Sub one millisecond to the instance (using date interval).\n * @method        CarbonInterface  addMilliseconds(int $value = 1)                                                    Add milliseconds (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  addMillisecond()                                                                   Add one millisecond to the instance (using date interval).\n * @method        CarbonInterface  subMilliseconds(int $value = 1)                                                    Sub milliseconds (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  subMillisecond()                                                                   Sub one millisecond to the instance (using date interval).\n * @method        CarbonInterface  addMicros(int $value = 1)                                                          Add microseconds (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  addMicro()                                                                         Add one microsecond to the instance (using date interval).\n * @method        CarbonInterface  subMicros(int $value = 1)                                                          Sub microseconds (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  subMicro()                                                                         Sub one microsecond to the instance (using date interval).\n * @method        CarbonInterface  addMicroseconds(int $value = 1)                                                    Add microseconds (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  addMicrosecond()                                                                   Add one microsecond to the instance (using date interval).\n * @method        CarbonInterface  subMicroseconds(int $value = 1)                                                    Sub microseconds (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  subMicrosecond()                                                                   Sub one microsecond to the instance (using date interval).\n * @method        CarbonInterface  addMillennia(int $value = 1)                                                       Add millennia (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  addMillennium()                                                                    Add one millennium to the instance (using date interval).\n * @method        CarbonInterface  subMillennia(int $value = 1)                                                       Sub millennia (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  subMillennium()                                                                    Sub one millennium to the instance (using date interval).\n * @method        CarbonInterface  addMillenniaWithOverflow(int $value = 1)                                           Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonInterface  addMillenniumWithOverflow()                                                        Add one millennium to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonInterface  subMillenniaWithOverflow(int $value = 1)                                           Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonInterface  subMillenniumWithOverflow()                                                        Sub one millennium to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonInterface  addMillenniaWithoutOverflow(int $value = 1)                                        Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addMillenniumWithoutOverflow()                                                     Add one millennium to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subMillenniaWithoutOverflow(int $value = 1)                                        Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subMillenniumWithoutOverflow()                                                     Sub one millennium to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addMillenniaWithNoOverflow(int $value = 1)                                         Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addMillenniumWithNoOverflow()                                                      Add one millennium to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subMillenniaWithNoOverflow(int $value = 1)                                         Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subMillenniumWithNoOverflow()                                                      Sub one millennium to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addMillenniaNoOverflow(int $value = 1)                                             Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addMillenniumNoOverflow()                                                          Add one millennium to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subMillenniaNoOverflow(int $value = 1)                                             Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subMillenniumNoOverflow()                                                          Sub one millennium to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addCenturies(int $value = 1)                                                       Add centuries (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  addCentury()                                                                       Add one century to the instance (using date interval).\n * @method        CarbonInterface  subCenturies(int $value = 1)                                                       Sub centuries (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  subCentury()                                                                       Sub one century to the instance (using date interval).\n * @method        CarbonInterface  addCenturiesWithOverflow(int $value = 1)                                           Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonInterface  addCenturyWithOverflow()                                                           Add one century to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonInterface  subCenturiesWithOverflow(int $value = 1)                                           Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonInterface  subCenturyWithOverflow()                                                           Sub one century to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonInterface  addCenturiesWithoutOverflow(int $value = 1)                                        Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addCenturyWithoutOverflow()                                                        Add one century to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subCenturiesWithoutOverflow(int $value = 1)                                        Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subCenturyWithoutOverflow()                                                        Sub one century to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addCenturiesWithNoOverflow(int $value = 1)                                         Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addCenturyWithNoOverflow()                                                         Add one century to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subCenturiesWithNoOverflow(int $value = 1)                                         Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subCenturyWithNoOverflow()                                                         Sub one century to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addCenturiesNoOverflow(int $value = 1)                                             Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addCenturyNoOverflow()                                                             Add one century to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subCenturiesNoOverflow(int $value = 1)                                             Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subCenturyNoOverflow()                                                             Sub one century to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addDecades(int $value = 1)                                                         Add decades (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  addDecade()                                                                        Add one decade to the instance (using date interval).\n * @method        CarbonInterface  subDecades(int $value = 1)                                                         Sub decades (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  subDecade()                                                                        Sub one decade to the instance (using date interval).\n * @method        CarbonInterface  addDecadesWithOverflow(int $value = 1)                                             Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonInterface  addDecadeWithOverflow()                                                            Add one decade to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonInterface  subDecadesWithOverflow(int $value = 1)                                             Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonInterface  subDecadeWithOverflow()                                                            Sub one decade to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonInterface  addDecadesWithoutOverflow(int $value = 1)                                          Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addDecadeWithoutOverflow()                                                         Add one decade to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subDecadesWithoutOverflow(int $value = 1)                                          Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subDecadeWithoutOverflow()                                                         Sub one decade to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addDecadesWithNoOverflow(int $value = 1)                                           Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addDecadeWithNoOverflow()                                                          Add one decade to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subDecadesWithNoOverflow(int $value = 1)                                           Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subDecadeWithNoOverflow()                                                          Sub one decade to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addDecadesNoOverflow(int $value = 1)                                               Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addDecadeNoOverflow()                                                              Add one decade to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subDecadesNoOverflow(int $value = 1)                                               Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subDecadeNoOverflow()                                                              Sub one decade to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addQuarters(int $value = 1)                                                        Add quarters (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  addQuarter()                                                                       Add one quarter to the instance (using date interval).\n * @method        CarbonInterface  subQuarters(int $value = 1)                                                        Sub quarters (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  subQuarter()                                                                       Sub one quarter to the instance (using date interval).\n * @method        CarbonInterface  addQuartersWithOverflow(int $value = 1)                                            Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonInterface  addQuarterWithOverflow()                                                           Add one quarter to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonInterface  subQuartersWithOverflow(int $value = 1)                                            Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonInterface  subQuarterWithOverflow()                                                           Sub one quarter to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonInterface  addQuartersWithoutOverflow(int $value = 1)                                         Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addQuarterWithoutOverflow()                                                        Add one quarter to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subQuartersWithoutOverflow(int $value = 1)                                         Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subQuarterWithoutOverflow()                                                        Sub one quarter to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addQuartersWithNoOverflow(int $value = 1)                                          Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addQuarterWithNoOverflow()                                                         Add one quarter to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subQuartersWithNoOverflow(int $value = 1)                                          Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subQuarterWithNoOverflow()                                                         Sub one quarter to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addQuartersNoOverflow(int $value = 1)                                              Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addQuarterNoOverflow()                                                             Add one quarter to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subQuartersNoOverflow(int $value = 1)                                              Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subQuarterNoOverflow()                                                             Sub one quarter to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addWeeks(int $value = 1)                                                           Add weeks (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  addWeek()                                                                          Add one week to the instance (using date interval).\n * @method        CarbonInterface  subWeeks(int $value = 1)                                                           Sub weeks (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  subWeek()                                                                          Sub one week to the instance (using date interval).\n * @method        CarbonInterface  addWeekdays(int $value = 1)                                                        Add weekdays (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  addWeekday()                                                                       Add one weekday to the instance (using date interval).\n * @method        CarbonInterface  subWeekdays(int $value = 1)                                                        Sub weekdays (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  subWeekday()                                                                       Sub one weekday to the instance (using date interval).\n * @method        CarbonInterface  addRealMicros(int $value = 1)                                                      Add microseconds (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  addRealMicro()                                                                     Add one microsecond to the instance (using timestamp).\n * @method        CarbonInterface  subRealMicros(int $value = 1)                                                      Sub microseconds (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  subRealMicro()                                                                     Sub one microsecond to the instance (using timestamp).\n * @method        CarbonPeriod     microsUntil($endDate = null, int $factor = 1)                                      Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each microsecond or every X microseconds if a factor is given.\n * @method        CarbonInterface  addRealMicroseconds(int $value = 1)                                                Add microseconds (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  addRealMicrosecond()                                                               Add one microsecond to the instance (using timestamp).\n * @method        CarbonInterface  subRealMicroseconds(int $value = 1)                                                Sub microseconds (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  subRealMicrosecond()                                                               Sub one microsecond to the instance (using timestamp).\n * @method        CarbonPeriod     microsecondsUntil($endDate = null, int $factor = 1)                                Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each microsecond or every X microseconds if a factor is given.\n * @method        CarbonInterface  addRealMillis(int $value = 1)                                                      Add milliseconds (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  addRealMilli()                                                                     Add one millisecond to the instance (using timestamp).\n * @method        CarbonInterface  subRealMillis(int $value = 1)                                                      Sub milliseconds (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  subRealMilli()                                                                     Sub one millisecond to the instance (using timestamp).\n * @method        CarbonPeriod     millisUntil($endDate = null, int $factor = 1)                                      Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each millisecond or every X milliseconds if a factor is given.\n * @method        CarbonInterface  addRealMilliseconds(int $value = 1)                                                Add milliseconds (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  addRealMillisecond()                                                               Add one millisecond to the instance (using timestamp).\n * @method        CarbonInterface  subRealMilliseconds(int $value = 1)                                                Sub milliseconds (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  subRealMillisecond()                                                               Sub one millisecond to the instance (using timestamp).\n * @method        CarbonPeriod     millisecondsUntil($endDate = null, int $factor = 1)                                Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each millisecond or every X milliseconds if a factor is given.\n * @method        CarbonInterface  addRealSeconds(int $value = 1)                                                     Add seconds (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  addRealSecond()                                                                    Add one second to the instance (using timestamp).\n * @method        CarbonInterface  subRealSeconds(int $value = 1)                                                     Sub seconds (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  subRealSecond()                                                                    Sub one second to the instance (using timestamp).\n * @method        CarbonPeriod     secondsUntil($endDate = null, int $factor = 1)                                     Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each second or every X seconds if a factor is given.\n * @method        CarbonInterface  addRealMinutes(int $value = 1)                                                     Add minutes (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  addRealMinute()                                                                    Add one minute to the instance (using timestamp).\n * @method        CarbonInterface  subRealMinutes(int $value = 1)                                                     Sub minutes (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  subRealMinute()                                                                    Sub one minute to the instance (using timestamp).\n * @method        CarbonPeriod     minutesUntil($endDate = null, int $factor = 1)                                     Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each minute or every X minutes if a factor is given.\n * @method        CarbonInterface  addRealHours(int $value = 1)                                                       Add hours (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  addRealHour()                                                                      Add one hour to the instance (using timestamp).\n * @method        CarbonInterface  subRealHours(int $value = 1)                                                       Sub hours (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  subRealHour()                                                                      Sub one hour to the instance (using timestamp).\n * @method        CarbonPeriod     hoursUntil($endDate = null, int $factor = 1)                                       Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each hour or every X hours if a factor is given.\n * @method        CarbonInterface  addRealDays(int $value = 1)                                                        Add days (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  addRealDay()                                                                       Add one day to the instance (using timestamp).\n * @method        CarbonInterface  subRealDays(int $value = 1)                                                        Sub days (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  subRealDay()                                                                       Sub one day to the instance (using timestamp).\n * @method        CarbonPeriod     daysUntil($endDate = null, int $factor = 1)                                        Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each day or every X days if a factor is given.\n * @method        CarbonInterface  addRealWeeks(int $value = 1)                                                       Add weeks (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  addRealWeek()                                                                      Add one week to the instance (using timestamp).\n * @method        CarbonInterface  subRealWeeks(int $value = 1)                                                       Sub weeks (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  subRealWeek()                                                                      Sub one week to the instance (using timestamp).\n * @method        CarbonPeriod     weeksUntil($endDate = null, int $factor = 1)                                       Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each week or every X weeks if a factor is given.\n * @method        CarbonInterface  addRealMonths(int $value = 1)                                                      Add months (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  addRealMonth()                                                                     Add one month to the instance (using timestamp).\n * @method        CarbonInterface  subRealMonths(int $value = 1)                                                      Sub months (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  subRealMonth()                                                                     Sub one month to the instance (using timestamp).\n * @method        CarbonPeriod     monthsUntil($endDate = null, int $factor = 1)                                      Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each month or every X months if a factor is given.\n * @method        CarbonInterface  addRealQuarters(int $value = 1)                                                    Add quarters (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  addRealQuarter()                                                                   Add one quarter to the instance (using timestamp).\n * @method        CarbonInterface  subRealQuarters(int $value = 1)                                                    Sub quarters (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  subRealQuarter()                                                                   Sub one quarter to the instance (using timestamp).\n * @method        CarbonPeriod     quartersUntil($endDate = null, int $factor = 1)                                    Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each quarter or every X quarters if a factor is given.\n * @method        CarbonInterface  addRealYears(int $value = 1)                                                       Add years (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  addRealYear()                                                                      Add one year to the instance (using timestamp).\n * @method        CarbonInterface  subRealYears(int $value = 1)                                                       Sub years (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  subRealYear()                                                                      Sub one year to the instance (using timestamp).\n * @method        CarbonPeriod     yearsUntil($endDate = null, int $factor = 1)                                       Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each year or every X years if a factor is given.\n * @method        CarbonInterface  addRealDecades(int $value = 1)                                                     Add decades (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  addRealDecade()                                                                    Add one decade to the instance (using timestamp).\n * @method        CarbonInterface  subRealDecades(int $value = 1)                                                     Sub decades (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  subRealDecade()                                                                    Sub one decade to the instance (using timestamp).\n * @method        CarbonPeriod     decadesUntil($endDate = null, int $factor = 1)                                     Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each decade or every X decades if a factor is given.\n * @method        CarbonInterface  addRealCenturies(int $value = 1)                                                   Add centuries (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  addRealCentury()                                                                   Add one century to the instance (using timestamp).\n * @method        CarbonInterface  subRealCenturies(int $value = 1)                                                   Sub centuries (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  subRealCentury()                                                                   Sub one century to the instance (using timestamp).\n * @method        CarbonPeriod     centuriesUntil($endDate = null, int $factor = 1)                                   Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each century or every X centuries if a factor is given.\n * @method        CarbonInterface  addRealMillennia(int $value = 1)                                                   Add millennia (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  addRealMillennium()                                                                Add one millennium to the instance (using timestamp).\n * @method        CarbonInterface  subRealMillennia(int $value = 1)                                                   Sub millennia (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  subRealMillennium()                                                                Sub one millennium to the instance (using timestamp).\n * @method        CarbonPeriod     millenniaUntil($endDate = null, int $factor = 1)                                   Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each millennium or every X millennia if a factor is given.\n * @method        CarbonInterface  roundYear(float $precision = 1, string $function = \"round\")                        Round the current instance year with given precision using the given function.\n * @method        CarbonInterface  roundYears(float $precision = 1, string $function = \"round\")                       Round the current instance year with given precision using the given function.\n * @method        CarbonInterface  floorYear(float $precision = 1)                                                    Truncate the current instance year with given precision.\n * @method        CarbonInterface  floorYears(float $precision = 1)                                                   Truncate the current instance year with given precision.\n * @method        CarbonInterface  ceilYear(float $precision = 1)                                                     Ceil the current instance year with given precision.\n * @method        CarbonInterface  ceilYears(float $precision = 1)                                                    Ceil the current instance year with given precision.\n * @method        CarbonInterface  roundMonth(float $precision = 1, string $function = \"round\")                       Round the current instance month with given precision using the given function.\n * @method        CarbonInterface  roundMonths(float $precision = 1, string $function = \"round\")                      Round the current instance month with given precision using the given function.\n * @method        CarbonInterface  floorMonth(float $precision = 1)                                                   Truncate the current instance month with given precision.\n * @method        CarbonInterface  floorMonths(float $precision = 1)                                                  Truncate the current instance month with given precision.\n * @method        CarbonInterface  ceilMonth(float $precision = 1)                                                    Ceil the current instance month with given precision.\n * @method        CarbonInterface  ceilMonths(float $precision = 1)                                                   Ceil the current instance month with given precision.\n * @method        CarbonInterface  roundDay(float $precision = 1, string $function = \"round\")                         Round the current instance day with given precision using the given function.\n * @method        CarbonInterface  roundDays(float $precision = 1, string $function = \"round\")                        Round the current instance day with given precision using the given function.\n * @method        CarbonInterface  floorDay(float $precision = 1)                                                     Truncate the current instance day with given precision.\n * @method        CarbonInterface  floorDays(float $precision = 1)                                                    Truncate the current instance day with given precision.\n * @method        CarbonInterface  ceilDay(float $precision = 1)                                                      Ceil the current instance day with given precision.\n * @method        CarbonInterface  ceilDays(float $precision = 1)                                                     Ceil the current instance day with given precision.\n * @method        CarbonInterface  roundHour(float $precision = 1, string $function = \"round\")                        Round the current instance hour with given precision using the given function.\n * @method        CarbonInterface  roundHours(float $precision = 1, string $function = \"round\")                       Round the current instance hour with given precision using the given function.\n * @method        CarbonInterface  floorHour(float $precision = 1)                                                    Truncate the current instance hour with given precision.\n * @method        CarbonInterface  floorHours(float $precision = 1)                                                   Truncate the current instance hour with given precision.\n * @method        CarbonInterface  ceilHour(float $precision = 1)                                                     Ceil the current instance hour with given precision.\n * @method        CarbonInterface  ceilHours(float $precision = 1)                                                    Ceil the current instance hour with given precision.\n * @method        CarbonInterface  roundMinute(float $precision = 1, string $function = \"round\")                      Round the current instance minute with given precision using the given function.\n * @method        CarbonInterface  roundMinutes(float $precision = 1, string $function = \"round\")                     Round the current instance minute with given precision using the given function.\n * @method        CarbonInterface  floorMinute(float $precision = 1)                                                  Truncate the current instance minute with given precision.\n * @method        CarbonInterface  floorMinutes(float $precision = 1)                                                 Truncate the current instance minute with given precision.\n * @method        CarbonInterface  ceilMinute(float $precision = 1)                                                   Ceil the current instance minute with given precision.\n * @method        CarbonInterface  ceilMinutes(float $precision = 1)                                                  Ceil the current instance minute with given precision.\n * @method        CarbonInterface  roundSecond(float $precision = 1, string $function = \"round\")                      Round the current instance second with given precision using the given function.\n * @method        CarbonInterface  roundSeconds(float $precision = 1, string $function = \"round\")                     Round the current instance second with given precision using the given function.\n * @method        CarbonInterface  floorSecond(float $precision = 1)                                                  Truncate the current instance second with given precision.\n * @method        CarbonInterface  floorSeconds(float $precision = 1)                                                 Truncate the current instance second with given precision.\n * @method        CarbonInterface  ceilSecond(float $precision = 1)                                                   Ceil the current instance second with given precision.\n * @method        CarbonInterface  ceilSeconds(float $precision = 1)                                                  Ceil the current instance second with given precision.\n * @method        CarbonInterface  roundMillennium(float $precision = 1, string $function = \"round\")                  Round the current instance millennium with given precision using the given function.\n * @method        CarbonInterface  roundMillennia(float $precision = 1, string $function = \"round\")                   Round the current instance millennium with given precision using the given function.\n * @method        CarbonInterface  floorMillennium(float $precision = 1)                                              Truncate the current instance millennium with given precision.\n * @method        CarbonInterface  floorMillennia(float $precision = 1)                                               Truncate the current instance millennium with given precision.\n * @method        CarbonInterface  ceilMillennium(float $precision = 1)                                               Ceil the current instance millennium with given precision.\n * @method        CarbonInterface  ceilMillennia(float $precision = 1)                                                Ceil the current instance millennium with given precision.\n * @method        CarbonInterface  roundCentury(float $precision = 1, string $function = \"round\")                     Round the current instance century with given precision using the given function.\n * @method        CarbonInterface  roundCenturies(float $precision = 1, string $function = \"round\")                   Round the current instance century with given precision using the given function.\n * @method        CarbonInterface  floorCentury(float $precision = 1)                                                 Truncate the current instance century with given precision.\n * @method        CarbonInterface  floorCenturies(float $precision = 1)                                               Truncate the current instance century with given precision.\n * @method        CarbonInterface  ceilCentury(float $precision = 1)                                                  Ceil the current instance century with given precision.\n * @method        CarbonInterface  ceilCenturies(float $precision = 1)                                                Ceil the current instance century with given precision.\n * @method        CarbonInterface  roundDecade(float $precision = 1, string $function = \"round\")                      Round the current instance decade with given precision using the given function.\n * @method        CarbonInterface  roundDecades(float $precision = 1, string $function = \"round\")                     Round the current instance decade with given precision using the given function.\n * @method        CarbonInterface  floorDecade(float $precision = 1)                                                  Truncate the current instance decade with given precision.\n * @method        CarbonInterface  floorDecades(float $precision = 1)                                                 Truncate the current instance decade with given precision.\n * @method        CarbonInterface  ceilDecade(float $precision = 1)                                                   Ceil the current instance decade with given precision.\n * @method        CarbonInterface  ceilDecades(float $precision = 1)                                                  Ceil the current instance decade with given precision.\n * @method        CarbonInterface  roundQuarter(float $precision = 1, string $function = \"round\")                     Round the current instance quarter with given precision using the given function.\n * @method        CarbonInterface  roundQuarters(float $precision = 1, string $function = \"round\")                    Round the current instance quarter with given precision using the given function.\n * @method        CarbonInterface  floorQuarter(float $precision = 1)                                                 Truncate the current instance quarter with given precision.\n * @method        CarbonInterface  floorQuarters(float $precision = 1)                                                Truncate the current instance quarter with given precision.\n * @method        CarbonInterface  ceilQuarter(float $precision = 1)                                                  Ceil the current instance quarter with given precision.\n * @method        CarbonInterface  ceilQuarters(float $precision = 1)                                                 Ceil the current instance quarter with given precision.\n * @method        CarbonInterface  roundMillisecond(float $precision = 1, string $function = \"round\")                 Round the current instance millisecond with given precision using the given function.\n * @method        CarbonInterface  roundMilliseconds(float $precision = 1, string $function = \"round\")                Round the current instance millisecond with given precision using the given function.\n * @method        CarbonInterface  floorMillisecond(float $precision = 1)                                             Truncate the current instance millisecond with given precision.\n * @method        CarbonInterface  floorMilliseconds(float $precision = 1)                                            Truncate the current instance millisecond with given precision.\n * @method        CarbonInterface  ceilMillisecond(float $precision = 1)                                              Ceil the current instance millisecond with given precision.\n * @method        CarbonInterface  ceilMilliseconds(float $precision = 1)                                             Ceil the current instance millisecond with given precision.\n * @method        CarbonInterface  roundMicrosecond(float $precision = 1, string $function = \"round\")                 Round the current instance microsecond with given precision using the given function.\n * @method        CarbonInterface  roundMicroseconds(float $precision = 1, string $function = \"round\")                Round the current instance microsecond with given precision using the given function.\n * @method        CarbonInterface  floorMicrosecond(float $precision = 1)                                             Truncate the current instance microsecond with given precision.\n * @method        CarbonInterface  floorMicroseconds(float $precision = 1)                                            Truncate the current instance microsecond with given precision.\n * @method        CarbonInterface  ceilMicrosecond(float $precision = 1)                                              Ceil the current instance microsecond with given precision.\n * @method        CarbonInterface  ceilMicroseconds(float $precision = 1)                                             Ceil the current instance microsecond with given precision.\n * @method        string           shortAbsoluteDiffForHumans(DateTimeInterface $other = null, int $parts = 1)        Get the difference (short format, 'Absolute' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.)\n * @method        string           longAbsoluteDiffForHumans(DateTimeInterface $other = null, int $parts = 1)         Get the difference (long format, 'Absolute' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.)\n * @method        string           shortRelativeDiffForHumans(DateTimeInterface $other = null, int $parts = 1)        Get the difference (short format, 'Relative' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.)\n * @method        string           longRelativeDiffForHumans(DateTimeInterface $other = null, int $parts = 1)         Get the difference (long format, 'Relative' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.)\n * @method        string           shortRelativeToNowDiffForHumans(DateTimeInterface $other = null, int $parts = 1)   Get the difference (short format, 'RelativeToNow' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.)\n * @method        string           longRelativeToNowDiffForHumans(DateTimeInterface $other = null, int $parts = 1)    Get the difference (long format, 'RelativeToNow' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.)\n * @method        string           shortRelativeToOtherDiffForHumans(DateTimeInterface $other = null, int $parts = 1) Get the difference (short format, 'RelativeToOther' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.)\n * @method        string           longRelativeToOtherDiffForHumans(DateTimeInterface $other = null, int $parts = 1)  Get the difference (long format, 'RelativeToOther' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.)\n *\n * </autodoc>\n */\ninterface CarbonInterface extends DateTimeInterface, JsonSerializable\n{\n    /**\n     * Diff wording options(expressed in octal).\n     */\n    public const NO_ZERO_DIFF = 01;\n    public const JUST_NOW = 02;\n    public const ONE_DAY_WORDS = 04;\n    public const TWO_DAY_WORDS = 010;\n    public const SEQUENTIAL_PARTS_ONLY = 020;\n    public const ROUND = 040;\n    public const FLOOR = 0100;\n    public const CEIL = 0200;\n\n    /**\n     * Diff syntax options.\n     */\n    public const DIFF_ABSOLUTE = 1; // backward compatibility with true\n    public const DIFF_RELATIVE_AUTO = 0; // backward compatibility with false\n    public const DIFF_RELATIVE_TO_NOW = 2;\n    public const DIFF_RELATIVE_TO_OTHER = 3;\n\n    /**\n     * Translate string options.\n     */\n    public const TRANSLATE_MONTHS = 1;\n    public const TRANSLATE_DAYS = 2;\n    public const TRANSLATE_UNITS = 4;\n    public const TRANSLATE_MERIDIEM = 8;\n    public const TRANSLATE_DIFF = 0x10;\n    public const TRANSLATE_ALL = self::TRANSLATE_MONTHS | self::TRANSLATE_DAYS | self::TRANSLATE_UNITS | self::TRANSLATE_MERIDIEM | self::TRANSLATE_DIFF;\n\n    /**\n     * The day constants.\n     */\n    public const SUNDAY = 0;\n    public const MONDAY = 1;\n    public const TUESDAY = 2;\n    public const WEDNESDAY = 3;\n    public const THURSDAY = 4;\n    public const FRIDAY = 5;\n    public const SATURDAY = 6;\n\n    /**\n     * The month constants.\n     * These aren't used by Carbon itself but exist for\n     * convenience sake alone.\n     */\n    public const JANUARY = 1;\n    public const FEBRUARY = 2;\n    public const MARCH = 3;\n    public const APRIL = 4;\n    public const MAY = 5;\n    public const JUNE = 6;\n    public const JULY = 7;\n    public const AUGUST = 8;\n    public const SEPTEMBER = 9;\n    public const OCTOBER = 10;\n    public const NOVEMBER = 11;\n    public const DECEMBER = 12;\n\n    /**\n     * Number of X in Y.\n     */\n    public const YEARS_PER_MILLENNIUM = 1000;\n    public const YEARS_PER_CENTURY = 100;\n    public const YEARS_PER_DECADE = 10;\n    public const MONTHS_PER_YEAR = 12;\n    public const MONTHS_PER_QUARTER = 3;\n    public const QUARTERS_PER_YEAR = 4;\n    public const WEEKS_PER_YEAR = 52;\n    public const WEEKS_PER_MONTH = 4;\n    public const DAYS_PER_YEAR = 365;\n    public const DAYS_PER_WEEK = 7;\n    public const HOURS_PER_DAY = 24;\n    public const MINUTES_PER_HOUR = 60;\n    public const SECONDS_PER_MINUTE = 60;\n    public const MILLISECONDS_PER_SECOND = 1000;\n    public const MICROSECONDS_PER_MILLISECOND = 1000;\n    public const MICROSECONDS_PER_SECOND = 1000000;\n\n    /**\n     * Special settings to get the start of week from current locale culture.\n     */\n    public const WEEK_DAY_AUTO = 'auto';\n\n    /**\n     * RFC7231 DateTime format.\n     *\n     * @var string\n     */\n    public const RFC7231_FORMAT = 'D, d M Y H:i:s \\G\\M\\T';\n\n    /**\n     * Default format to use for __toString method when type juggling occurs.\n     *\n     * @var string\n     */\n    public const DEFAULT_TO_STRING_FORMAT = 'Y-m-d H:i:s';\n\n    /**\n     * Format for converting mocked time, includes microseconds.\n     *\n     * @var string\n     */\n    public const MOCK_DATETIME_FORMAT = 'Y-m-d H:i:s.u';\n\n    /**\n     * Pattern detection for ->isoFormat and ::createFromIsoFormat.\n     *\n     * @var string\n     */\n    public const ISO_FORMAT_REGEXP = '(O[YMDHhms]|[Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|YYYYYY|YYYYY|YYYY|YY?|g{1,5}|G{1,5}|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?)';\n\n    // <methods>\n\n    /**\n     * Dynamically handle calls to the class.\n     *\n     * @param string $method     magic method name called\n     * @param array  $parameters parameters list\n     *\n     * @throws UnknownMethodException|BadMethodCallException|ReflectionException|Throwable\n     *\n     * @return mixed\n     */\n    public function __call($method, $parameters);\n\n    /**\n     * Dynamically handle calls to the class.\n     *\n     * @param string $method     magic method name called\n     * @param array  $parameters parameters list\n     *\n     * @throws BadMethodCallException\n     *\n     * @return mixed\n     */\n    public static function __callStatic($method, $parameters);\n\n    /**\n     * Update constructedObjectId on cloned.\n     */\n    public function __clone();\n\n    /**\n     * Create a new Carbon instance.\n     *\n     * Please see the testing aids section (specifically static::setTestNow())\n     * for more on the possibility of this constructor returning a test instance.\n     *\n     * @param DateTimeInterface|string|null $time\n     * @param DateTimeZone|string|null      $tz\n     *\n     * @throws InvalidFormatException\n     */\n    public function __construct($time = null, $tz = null);\n\n    /**\n     * Show truthy properties on var_dump().\n     *\n     * @return array\n     */\n    public function __debugInfo();\n\n    /**\n     * Get a part of the Carbon object\n     *\n     * @param string $name\n     *\n     * @throws UnknownGetterException\n     *\n     * @return string|int|bool|DateTimeZone|null\n     */\n    public function __get($name);\n\n    /**\n     * Check if an attribute exists on the object\n     *\n     * @param string $name\n     *\n     * @return bool\n     */\n    public function __isset($name);\n\n    /**\n     * Set a part of the Carbon object\n     *\n     * @param string                  $name\n     * @param string|int|DateTimeZone $value\n     *\n     * @throws UnknownSetterException|ReflectionException\n     *\n     * @return void\n     */\n    public function __set($name, $value);\n\n    /**\n     * The __set_state handler.\n     *\n     * @param string|array $dump\n     *\n     * @return static\n     */\n    #[ReturnTypeWillChange]\n    public static function __set_state($dump);\n\n    /**\n     * Returns the list of properties to dump on serialize() called on.\n     *\n     * Only used by PHP < 7.4.\n     *\n     * @return array\n     */\n    public function __sleep();\n\n    /**\n     * Format the instance as a string using the set format\n     *\n     * @example\n     * ```\n     * echo Carbon::now(); // Carbon instances can be cast to string\n     * ```\n     *\n     * @return string\n     */\n    public function __toString();\n\n    /**\n     * Add given units or interval to the current instance.\n     *\n     * @example $date->add('hour', 3)\n     * @example $date->add(15, 'days')\n     * @example $date->add(CarbonInterval::days(4))\n     *\n     * @param string|DateInterval|Closure|CarbonConverterInterface $unit\n     * @param int                                                  $value\n     * @param bool|null                                            $overflow\n     *\n     * @return static\n     */\n    #[ReturnTypeWillChange]\n    public function add($unit, $value = 1, $overflow = null);\n\n    /**\n     * Add seconds to the instance using timestamp. Positive $value travels\n     * forward while negative $value travels into the past.\n     *\n     * @param string $unit\n     * @param int    $value\n     *\n     * @return static\n     */\n    public function addRealUnit($unit, $value = 1);\n\n    /**\n     * Add given units to the current instance.\n     *\n     * @param string    $unit\n     * @param int       $value\n     * @param bool|null $overflow\n     *\n     * @return static\n     */\n    public function addUnit($unit, $value = 1, $overflow = null);\n\n    /**\n     * Add any unit to a new value without overflowing current other unit given.\n     *\n     * @param string $valueUnit    unit name to modify\n     * @param int    $value        amount to add to the input unit\n     * @param string $overflowUnit unit name to not overflow\n     *\n     * @return static\n     */\n    public function addUnitNoOverflow($valueUnit, $value, $overflowUnit);\n\n    /**\n     * Get the difference in a human readable format in the current locale from an other\n     * instance given to now\n     *\n     * @param int|array $syntax  if array passed, parameters will be extracted from it, the array may contains:\n     *                           - 'syntax' entry (see below)\n     *                           - 'short' entry (see below)\n     *                           - 'parts' entry (see below)\n     *                           - 'options' entry (see below)\n     *                           - 'join' entry determines how to join multiple parts of the string\n     *                           `  - if $join is a string, it's used as a joiner glue\n     *                           `  - if $join is a callable/closure, it get the list of string and should return a string\n     *                           `  - if $join is an array, the first item will be the default glue, and the second item\n     *                           `    will be used instead of the glue for the last item\n     *                           `  - if $join is true, it will be guessed from the locale ('list' translation file entry)\n     *                           `  - if $join is missing, a space will be used as glue\n     *                           if int passed, it add modifiers:\n     *                           Possible values:\n     *                           - CarbonInterface::DIFF_ABSOLUTE          no modifiers\n     *                           - CarbonInterface::DIFF_RELATIVE_TO_NOW   add ago/from now modifier\n     *                           - CarbonInterface::DIFF_RELATIVE_TO_OTHER add before/after modifier\n     *                           Default value: CarbonInterface::DIFF_ABSOLUTE\n     * @param bool      $short   displays short format of time units\n     * @param int       $parts   maximum number of parts to display (default value: 1: single part)\n     * @param int       $options human diff options\n     *\n     * @return string\n     */\n    public function ago($syntax = null, $short = false, $parts = 1, $options = null);\n\n    /**\n     * Modify the current instance to the average of a given instance (default now) and the current instance\n     * (second-precision).\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|null $date\n     *\n     * @return static\n     */\n    public function average($date = null);\n\n    /**\n     * Clone the current instance if it's mutable.\n     *\n     * This method is convenient to ensure you don't mutate the initial object\n     * but avoid to make a useless copy of it if it's already immutable.\n     *\n     * @return static\n     */\n    public function avoidMutation();\n\n    /**\n     * Determines if the instance is between two others.\n     *\n     * The third argument allow you to specify if bounds are included or not (true by default)\n     * but for when you including/excluding bounds may produce different results in your application,\n     * we recommend to use the explicit methods ->betweenIncluded() or ->betweenExcluded() instead.\n     *\n     * @example\n     * ```\n     * Carbon::parse('2018-07-25')->between('2018-07-14', '2018-08-01'); // true\n     * Carbon::parse('2018-07-25')->between('2018-08-01', '2018-08-20'); // false\n     * Carbon::parse('2018-07-25')->between('2018-07-25', '2018-08-01'); // true\n     * Carbon::parse('2018-07-25')->between('2018-07-25', '2018-08-01', false); // false\n     * ```\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date1\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date2\n     * @param bool                                    $equal Indicates if an equal to comparison should be done\n     *\n     * @return bool\n     */\n    public function between($date1, $date2, $equal = true): bool;\n\n    /**\n     * Determines if the instance is between two others, bounds excluded.\n     *\n     * @example\n     * ```\n     * Carbon::parse('2018-07-25')->betweenExcluded('2018-07-14', '2018-08-01'); // true\n     * Carbon::parse('2018-07-25')->betweenExcluded('2018-08-01', '2018-08-20'); // false\n     * Carbon::parse('2018-07-25')->betweenExcluded('2018-07-25', '2018-08-01'); // false\n     * ```\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date1\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date2\n     *\n     * @return bool\n     */\n    public function betweenExcluded($date1, $date2): bool;\n\n    /**\n     * Determines if the instance is between two others, bounds included.\n     *\n     * @example\n     * ```\n     * Carbon::parse('2018-07-25')->betweenIncluded('2018-07-14', '2018-08-01'); // true\n     * Carbon::parse('2018-07-25')->betweenIncluded('2018-08-01', '2018-08-20'); // false\n     * Carbon::parse('2018-07-25')->betweenIncluded('2018-07-25', '2018-08-01'); // true\n     * ```\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date1\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date2\n     *\n     * @return bool\n     */\n    public function betweenIncluded($date1, $date2): bool;\n\n    /**\n     * Returns either day of week + time (e.g. \"Last Friday at 3:30 PM\") if reference time is within 7 days,\n     * or a calendar date (e.g. \"10/29/2017\") otherwise.\n     *\n     * Language, date and time formats will change according to the current locale.\n     *\n     * @param Carbon|\\DateTimeInterface|string|null $referenceTime\n     * @param array                                 $formats\n     *\n     * @return string\n     */\n    public function calendar($referenceTime = null, array $formats = []);\n\n    /**\n     * Checks if the (date)time string is in a given format and valid to create a\n     * new instance.\n     *\n     * @example\n     * ```\n     * Carbon::canBeCreatedFromFormat('11:12:45', 'h:i:s'); // true\n     * Carbon::canBeCreatedFromFormat('13:12:45', 'h:i:s'); // false\n     * ```\n     *\n     * @param string $date\n     * @param string $format\n     *\n     * @return bool\n     */\n    public static function canBeCreatedFromFormat($date, $format);\n\n    /**\n     * Return the Carbon instance passed through, a now instance in the same timezone\n     * if null given or parse the input if string given.\n     *\n     * @param Carbon|\\Carbon\\CarbonPeriod|\\Carbon\\CarbonInterval|\\DateInterval|\\DatePeriod|DateTimeInterface|string|null $date\n     *\n     * @return static\n     */\n    public function carbonize($date = null);\n\n    /**\n     * Cast the current instance into the given class.\n     *\n     * @param string $className The $className::instance() method will be called to cast the current object.\n     *\n     * @return DateTimeInterface\n     */\n    public function cast(string $className);\n\n    /**\n     * Ceil the current instance second with given precision if specified.\n     *\n     * @param float|int|string|\\DateInterval|null $precision\n     *\n     * @return CarbonInterface\n     */\n    public function ceil($precision = 1);\n\n    /**\n     * Ceil the current instance at the given unit with given precision if specified.\n     *\n     * @param string    $unit\n     * @param float|int $precision\n     *\n     * @return CarbonInterface\n     */\n    public function ceilUnit($unit, $precision = 1);\n\n    /**\n     * Ceil the current instance week.\n     *\n     * @param int $weekStartsAt optional start allow you to specify the day of week to use to start the week\n     *\n     * @return CarbonInterface\n     */\n    public function ceilWeek($weekStartsAt = null);\n\n    /**\n     * Similar to native modify() method of DateTime but can handle more grammars.\n     *\n     * @example\n     * ```\n     * echo Carbon::now()->change('next 2pm');\n     * ```\n     *\n     * @link https://php.net/manual/en/datetime.modify.php\n     *\n     * @param string $modifier\n     *\n     * @return static|false\n     */\n    public function change($modifier);\n\n    /**\n     * Cleanup properties attached to the public scope of DateTime when a dump of the date is requested.\n     * foreach ($date as $_) {}\n     * serializer($date)\n     * var_export($date)\n     * get_object_vars($date)\n     */\n    public function cleanupDumpProperties();\n\n    /**\n     * @alias copy\n     *\n     * Get a copy of the instance.\n     *\n     * @return static\n     */\n    public function clone();\n\n    /**\n     * Get the closest date from the instance (second-precision).\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date1\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date2\n     *\n     * @return static\n     */\n    public function closest($date1, $date2);\n\n    /**\n     * Get a copy of the instance.\n     *\n     * @return static\n     */\n    public function copy();\n\n    /**\n     * Create a new Carbon instance from a specific date and time.\n     *\n     * If any of $year, $month or $day are set to null their now() values will\n     * be used.\n     *\n     * If $hour is null it will be set to its now() value and the default\n     * values for $minute and $second will be their now() values.\n     *\n     * If $hour is not null then the default values for $minute and $second\n     * will be 0.\n     *\n     * @param DateTimeInterface|int|null $year\n     * @param int|null                   $month\n     * @param int|null                   $day\n     * @param int|null                   $hour\n     * @param int|null                   $minute\n     * @param int|null                   $second\n     * @param DateTimeZone|string|null   $tz\n     *\n     * @throws InvalidFormatException\n     *\n     * @return static|false\n     */\n    public static function create($year = 0, $month = 1, $day = 1, $hour = 0, $minute = 0, $second = 0, $tz = null);\n\n    /**\n     * Create a Carbon instance from just a date. The time portion is set to now.\n     *\n     * @param int|null                 $year\n     * @param int|null                 $month\n     * @param int|null                 $day\n     * @param DateTimeZone|string|null $tz\n     *\n     * @throws InvalidFormatException\n     *\n     * @return static\n     */\n    public static function createFromDate($year = null, $month = null, $day = null, $tz = null);\n\n    /**\n     * Create a Carbon instance from a specific format.\n     *\n     * @param string                         $format Datetime format\n     * @param string                         $time\n     * @param DateTimeZone|string|false|null $tz\n     *\n     * @throws InvalidFormatException\n     *\n     * @return static|false\n     */\n    #[ReturnTypeWillChange]\n    public static function createFromFormat($format, $time, $tz = null);\n\n    /**\n     * Create a Carbon instance from a specific ISO format (same replacements as ->isoFormat()).\n     *\n     * @param string                                             $format     Datetime format\n     * @param string                                             $time\n     * @param DateTimeZone|string|false|null                     $tz         optional timezone\n     * @param string|null                                        $locale     locale to be used for LTS, LT, LL, LLL, etc. macro-formats (en by fault, unneeded if no such macro-format in use)\n     * @param \\Symfony\\Component\\Translation\\TranslatorInterface $translator optional custom translator to use for macro-formats\n     *\n     * @throws InvalidFormatException\n     *\n     * @return static|false\n     */\n    public static function createFromIsoFormat($format, $time, $tz = null, $locale = 'en', $translator = null);\n\n    /**\n     * Create a Carbon instance from a specific format and a string in a given language.\n     *\n     * @param string                         $format Datetime format\n     * @param string                         $locale\n     * @param string                         $time\n     * @param DateTimeZone|string|false|null $tz\n     *\n     * @throws InvalidFormatException\n     *\n     * @return static|false\n     */\n    public static function createFromLocaleFormat($format, $locale, $time, $tz = null);\n\n    /**\n     * Create a Carbon instance from a specific ISO format and a string in a given language.\n     *\n     * @param string                         $format Datetime ISO format\n     * @param string                         $locale\n     * @param string                         $time\n     * @param DateTimeZone|string|false|null $tz\n     *\n     * @throws InvalidFormatException\n     *\n     * @return static|false\n     */\n    public static function createFromLocaleIsoFormat($format, $locale, $time, $tz = null);\n\n    /**\n     * Create a Carbon instance from just a time. The date portion is set to today.\n     *\n     * @param int|null                 $hour\n     * @param int|null                 $minute\n     * @param int|null                 $second\n     * @param DateTimeZone|string|null $tz\n     *\n     * @throws InvalidFormatException\n     *\n     * @return static\n     */\n    public static function createFromTime($hour = 0, $minute = 0, $second = 0, $tz = null);\n\n    /**\n     * Create a Carbon instance from a time string. The date portion is set to today.\n     *\n     * @param string                   $time\n     * @param DateTimeZone|string|null $tz\n     *\n     * @throws InvalidFormatException\n     *\n     * @return static\n     */\n    public static function createFromTimeString($time, $tz = null);\n\n    /**\n     * Create a Carbon instance from a timestamp and set the timezone (use default one if not specified).\n     *\n     * Timestamp input can be given as int, float or a string containing one or more numbers.\n     *\n     * @param float|int|string          $timestamp\n     * @param \\DateTimeZone|string|null $tz\n     *\n     * @return static\n     */\n    #[ReturnTypeWillChange]\n    public static function createFromTimestamp($timestamp, $tz = null);\n\n    /**\n     * Create a Carbon instance from a timestamp in milliseconds.\n     *\n     * Timestamp input can be given as int, float or a string containing one or more numbers.\n     *\n     * @param float|int|string          $timestamp\n     * @param \\DateTimeZone|string|null $tz\n     *\n     * @return static\n     */\n    public static function createFromTimestampMs($timestamp, $tz = null);\n\n    /**\n     * Create a Carbon instance from a timestamp in milliseconds.\n     *\n     * Timestamp input can be given as int, float or a string containing one or more numbers.\n     *\n     * @param float|int|string $timestamp\n     *\n     * @return static\n     */\n    public static function createFromTimestampMsUTC($timestamp);\n\n    /**\n     * Create a Carbon instance from an timestamp keeping the timezone to UTC.\n     *\n     * Timestamp input can be given as int, float or a string containing one or more numbers.\n     *\n     * @param float|int|string $timestamp\n     *\n     * @return static\n     */\n    public static function createFromTimestampUTC($timestamp);\n\n    /**\n     * Create a Carbon instance from just a date. The time portion is set to midnight.\n     *\n     * @param int|null                 $year\n     * @param int|null                 $month\n     * @param int|null                 $day\n     * @param DateTimeZone|string|null $tz\n     *\n     * @throws InvalidFormatException\n     *\n     * @return static\n     */\n    public static function createMidnightDate($year = null, $month = null, $day = null, $tz = null);\n\n    /**\n     * Create a new safe Carbon instance from a specific date and time.\n     *\n     * If any of $year, $month or $day are set to null their now() values will\n     * be used.\n     *\n     * If $hour is null it will be set to its now() value and the default\n     * values for $minute and $second will be their now() values.\n     *\n     * If $hour is not null then the default values for $minute and $second\n     * will be 0.\n     *\n     * If one of the set values is not valid, an InvalidDateException\n     * will be thrown.\n     *\n     * @param int|null                 $year\n     * @param int|null                 $month\n     * @param int|null                 $day\n     * @param int|null                 $hour\n     * @param int|null                 $minute\n     * @param int|null                 $second\n     * @param DateTimeZone|string|null $tz\n     *\n     * @throws InvalidDateException\n     *\n     * @return static|false\n     */\n    public static function createSafe($year = null, $month = null, $day = null, $hour = null, $minute = null, $second = null, $tz = null);\n\n    /**\n     * Create a new Carbon instance from a specific date and time using strict validation.\n     *\n     * @see create()\n     *\n     * @param int|null                 $year\n     * @param int|null                 $month\n     * @param int|null                 $day\n     * @param int|null                 $hour\n     * @param int|null                 $minute\n     * @param int|null                 $second\n     * @param DateTimeZone|string|null $tz\n     *\n     * @throws InvalidFormatException\n     *\n     * @return static\n     */\n    public static function createStrict(?int $year = 0, ?int $month = 1, ?int $day = 1, ?int $hour = 0, ?int $minute = 0, ?int $second = 0, $tz = null);\n\n    /**\n     * Get/set the day of year.\n     *\n     * @param int|null $value new value for day of year if using as setter.\n     *\n     * @return static|int\n     */\n    public function dayOfYear($value = null);\n\n    /**\n     * Get the difference as a CarbonInterval instance.\n     * Return relative interval (negative if $absolute flag is not set to true and the given date is before\n     * current one).\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return CarbonInterval\n     */\n    public function diffAsCarbonInterval($date = null, $absolute = true, array $skip = []);\n\n    /**\n     * Get the difference by the given interval using a filter closure.\n     *\n     * @param CarbonInterval                                         $ci       An interval to traverse by\n     * @param Closure                                                $callback\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return int\n     */\n    public function diffFiltered(CarbonInterval $ci, Closure $callback, $date = null, $absolute = true);\n\n    /**\n     * Get the difference in a human readable format in the current locale from current instance to an other\n     * instance given (or now if null given).\n     *\n     * @example\n     * ```\n     * echo Carbon::tomorrow()->diffForHumans() . \"\\n\";\n     * echo Carbon::tomorrow()->diffForHumans(['parts' => 2]) . \"\\n\";\n     * echo Carbon::tomorrow()->diffForHumans(['parts' => 3, 'join' => true]) . \"\\n\";\n     * echo Carbon::tomorrow()->diffForHumans(Carbon::yesterday()) . \"\\n\";\n     * echo Carbon::tomorrow()->diffForHumans(Carbon::yesterday(), ['short' => true]) . \"\\n\";\n     * ```\n     *\n     * @param Carbon|\\DateTimeInterface|string|array|null $other   if array passed, will be used as parameters array, see $syntax below;\n     *                                                             if null passed, now will be used as comparison reference;\n     *                                                             if any other type, it will be converted to date and used as reference.\n     * @param int|array                                   $syntax  if array passed, parameters will be extracted from it, the array may contains:\n     *                                                             - 'syntax' entry (see below)\n     *                                                             - 'short' entry (see below)\n     *                                                             - 'parts' entry (see below)\n     *                                                             - 'options' entry (see below)\n     *                                                             - 'skip' entry, list of units to skip (array of strings or a single string,\n     *                                                             ` it can be the unit name (singular or plural) or its shortcut\n     *                                                             ` (y, m, w, d, h, min, s, ms, µs).\n     *                                                             - 'aUnit' entry, prefer \"an hour\" over \"1 hour\" if true\n     *                                                             - 'join' entry determines how to join multiple parts of the string\n     *                                                             `  - if $join is a string, it's used as a joiner glue\n     *                                                             `  - if $join is a callable/closure, it get the list of string and should return a string\n     *                                                             `  - if $join is an array, the first item will be the default glue, and the second item\n     *                                                             `    will be used instead of the glue for the last item\n     *                                                             `  - if $join is true, it will be guessed from the locale ('list' translation file entry)\n     *                                                             `  - if $join is missing, a space will be used as glue\n     *                                                             - 'other' entry (see above)\n     *                                                             - 'minimumUnit' entry determines the smallest unit of time to display can be long or\n     *                                                             `  short form of the units, e.g. 'hour' or 'h' (default value: s)\n     *                                                             if int passed, it add modifiers:\n     *                                                             Possible values:\n     *                                                             - CarbonInterface::DIFF_ABSOLUTE          no modifiers\n     *                                                             - CarbonInterface::DIFF_RELATIVE_TO_NOW   add ago/from now modifier\n     *                                                             - CarbonInterface::DIFF_RELATIVE_TO_OTHER add before/after modifier\n     *                                                             Default value: CarbonInterface::DIFF_ABSOLUTE\n     * @param bool                                        $short   displays short format of time units\n     * @param int                                         $parts   maximum number of parts to display (default value: 1: single unit)\n     * @param int                                         $options human diff options\n     *\n     * @return string\n     */\n    public function diffForHumans($other = null, $syntax = null, $short = false, $parts = 1, $options = null);\n\n    /**\n     * Get the difference in days rounded down.\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return int\n     */\n    public function diffInDays($date = null, $absolute = true);\n\n    /**\n     * Get the difference in days using a filter closure rounded down.\n     *\n     * @param Closure                                                $callback\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return int\n     */\n    public function diffInDaysFiltered(Closure $callback, $date = null, $absolute = true);\n\n    /**\n     * Get the difference in hours rounded down.\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return int\n     */\n    public function diffInHours($date = null, $absolute = true);\n\n    /**\n     * Get the difference in hours using a filter closure rounded down.\n     *\n     * @param Closure                                                $callback\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return int\n     */\n    public function diffInHoursFiltered(Closure $callback, $date = null, $absolute = true);\n\n    /**\n     * Get the difference in microseconds.\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return int\n     */\n    public function diffInMicroseconds($date = null, $absolute = true);\n\n    /**\n     * Get the difference in milliseconds rounded down.\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return int\n     */\n    public function diffInMilliseconds($date = null, $absolute = true);\n\n    /**\n     * Get the difference in minutes rounded down.\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return int\n     */\n    public function diffInMinutes($date = null, $absolute = true);\n\n    /**\n     * Get the difference in months rounded down.\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return int\n     */\n    public function diffInMonths($date = null, $absolute = true);\n\n    /**\n     * Get the difference in quarters rounded down.\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return int\n     */\n    public function diffInQuarters($date = null, $absolute = true);\n\n    /**\n     * Get the difference in hours rounded down using timestamps.\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return int\n     */\n    public function diffInRealHours($date = null, $absolute = true);\n\n    /**\n     * Get the difference in microseconds using timestamps.\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return int\n     */\n    public function diffInRealMicroseconds($date = null, $absolute = true);\n\n    /**\n     * Get the difference in milliseconds rounded down using timestamps.\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return int\n     */\n    public function diffInRealMilliseconds($date = null, $absolute = true);\n\n    /**\n     * Get the difference in minutes rounded down using timestamps.\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return int\n     */\n    public function diffInRealMinutes($date = null, $absolute = true);\n\n    /**\n     * Get the difference in seconds using timestamps.\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return int\n     */\n    public function diffInRealSeconds($date = null, $absolute = true);\n\n    /**\n     * Get the difference in seconds rounded down.\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return int\n     */\n    public function diffInSeconds($date = null, $absolute = true);\n\n    /**\n     * Get the difference in weekdays rounded down.\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return int\n     */\n    public function diffInWeekdays($date = null, $absolute = true);\n\n    /**\n     * Get the difference in weekend days using a filter rounded down.\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return int\n     */\n    public function diffInWeekendDays($date = null, $absolute = true);\n\n    /**\n     * Get the difference in weeks rounded down.\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return int\n     */\n    public function diffInWeeks($date = null, $absolute = true);\n\n    /**\n     * Get the difference in years\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return int\n     */\n    public function diffInYears($date = null, $absolute = true);\n\n    /**\n     * @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n     *             You should rather use the ->settings() method.\n     * @see settings\n     *\n     * @param int $humanDiffOption\n     */\n    public static function disableHumanDiffOption($humanDiffOption);\n\n    /**\n     * @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n     *             You should rather use the ->settings() method.\n     * @see settings\n     *\n     * @param int $humanDiffOption\n     */\n    public static function enableHumanDiffOption($humanDiffOption);\n\n    /**\n     * Modify to end of current given unit.\n     *\n     * @example\n     * ```\n     * echo Carbon::parse('2018-07-25 12:45:16.334455')\n     *   ->startOf('month')\n     *   ->endOf('week', Carbon::FRIDAY);\n     * ```\n     *\n     * @param string            $unit\n     * @param array<int, mixed> $params\n     *\n     * @return static\n     */\n    public function endOf($unit, ...$params);\n\n    /**\n     * Resets the date to end of the century and time to 23:59:59.999999\n     *\n     * @example\n     * ```\n     * echo Carbon::parse('2018-07-25 12:45:16')->endOfCentury();\n     * ```\n     *\n     * @return static\n     */\n    public function endOfCentury();\n\n    /**\n     * Resets the time to 23:59:59.999999 end of day\n     *\n     * @example\n     * ```\n     * echo Carbon::parse('2018-07-25 12:45:16')->endOfDay();\n     * ```\n     *\n     * @return static\n     */\n    public function endOfDay();\n\n    /**\n     * Resets the date to end of the decade and time to 23:59:59.999999\n     *\n     * @example\n     * ```\n     * echo Carbon::parse('2018-07-25 12:45:16')->endOfDecade();\n     * ```\n     *\n     * @return static\n     */\n    public function endOfDecade();\n\n    /**\n     * Modify to end of current hour, minutes and seconds become 59\n     *\n     * @example\n     * ```\n     * echo Carbon::parse('2018-07-25 12:45:16')->endOfHour();\n     * ```\n     *\n     * @return static\n     */\n    public function endOfHour();\n\n    /**\n     * Resets the date to end of the millennium and time to 23:59:59.999999\n     *\n     * @example\n     * ```\n     * echo Carbon::parse('2018-07-25 12:45:16')->endOfMillennium();\n     * ```\n     *\n     * @return static\n     */\n    public function endOfMillennium();\n\n    /**\n     * Modify to end of current minute, seconds become 59\n     *\n     * @example\n     * ```\n     * echo Carbon::parse('2018-07-25 12:45:16')->endOfMinute();\n     * ```\n     *\n     * @return static\n     */\n    public function endOfMinute();\n\n    /**\n     * Resets the date to end of the month and time to 23:59:59.999999\n     *\n     * @example\n     * ```\n     * echo Carbon::parse('2018-07-25 12:45:16')->endOfMonth();\n     * ```\n     *\n     * @return static\n     */\n    public function endOfMonth();\n\n    /**\n     * Resets the date to end of the quarter and time to 23:59:59.999999\n     *\n     * @example\n     * ```\n     * echo Carbon::parse('2018-07-25 12:45:16')->endOfQuarter();\n     * ```\n     *\n     * @return static\n     */\n    public function endOfQuarter();\n\n    /**\n     * Modify to end of current second, microseconds become 999999\n     *\n     * @example\n     * ```\n     * echo Carbon::parse('2018-07-25 12:45:16.334455')\n     *   ->endOfSecond()\n     *   ->format('H:i:s.u');\n     * ```\n     *\n     * @return static\n     */\n    public function endOfSecond();\n\n    /**\n     * Resets the date to end of week (defined in $weekEndsAt) and time to 23:59:59.999999\n     *\n     * @example\n     * ```\n     * echo Carbon::parse('2018-07-25 12:45:16')->endOfWeek() . \"\\n\";\n     * echo Carbon::parse('2018-07-25 12:45:16')->locale('ar')->endOfWeek() . \"\\n\";\n     * echo Carbon::parse('2018-07-25 12:45:16')->endOfWeek(Carbon::SATURDAY) . \"\\n\";\n     * ```\n     *\n     * @param int $weekEndsAt optional start allow you to specify the day of week to use to end the week\n     *\n     * @return static\n     */\n    public function endOfWeek($weekEndsAt = null);\n\n    /**\n     * Resets the date to end of the year and time to 23:59:59.999999\n     *\n     * @example\n     * ```\n     * echo Carbon::parse('2018-07-25 12:45:16')->endOfYear();\n     * ```\n     *\n     * @return static\n     */\n    public function endOfYear();\n\n    /**\n     * Determines if the instance is equal to another\n     *\n     * @example\n     * ```\n     * Carbon::parse('2018-07-25 12:45:16')->eq('2018-07-25 12:45:16'); // true\n     * Carbon::parse('2018-07-25 12:45:16')->eq(Carbon::parse('2018-07-25 12:45:16')); // true\n     * Carbon::parse('2018-07-25 12:45:16')->eq('2018-07-25 12:45:17'); // false\n     * ```\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date\n     *\n     * @see equalTo()\n     *\n     * @return bool\n     */\n    public function eq($date): bool;\n\n    /**\n     * Determines if the instance is equal to another\n     *\n     * @example\n     * ```\n     * Carbon::parse('2018-07-25 12:45:16')->equalTo('2018-07-25 12:45:16'); // true\n     * Carbon::parse('2018-07-25 12:45:16')->equalTo(Carbon::parse('2018-07-25 12:45:16')); // true\n     * Carbon::parse('2018-07-25 12:45:16')->equalTo('2018-07-25 12:45:17'); // false\n     * ```\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date\n     *\n     * @return bool\n     */\n    public function equalTo($date): bool;\n\n    /**\n     * Set the current locale to the given, execute the passed function, reset the locale to previous one,\n     * then return the result of the closure (or null if the closure was void).\n     *\n     * @param string   $locale locale ex. en\n     * @param callable $func\n     *\n     * @return mixed\n     */\n    public static function executeWithLocale($locale, $func);\n\n    /**\n     * Get the farthest date from the instance (second-precision).\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date1\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date2\n     *\n     * @return static\n     */\n    public function farthest($date1, $date2);\n\n    /**\n     * Modify to the first occurrence of a given day of the week\n     * in the current month. If no dayOfWeek is provided, modify to the\n     * first day of the current month.  Use the supplied constants\n     * to indicate the desired dayOfWeek, ex. static::MONDAY.\n     *\n     * @param int|null $dayOfWeek\n     *\n     * @return static\n     */\n    public function firstOfMonth($dayOfWeek = null);\n\n    /**\n     * Modify to the first occurrence of a given day of the week\n     * in the current quarter. If no dayOfWeek is provided, modify to the\n     * first day of the current quarter.  Use the supplied constants\n     * to indicate the desired dayOfWeek, ex. static::MONDAY.\n     *\n     * @param int|null $dayOfWeek day of the week default null\n     *\n     * @return static\n     */\n    public function firstOfQuarter($dayOfWeek = null);\n\n    /**\n     * Modify to the first occurrence of a given day of the week\n     * in the current year. If no dayOfWeek is provided, modify to the\n     * first day of the current year.  Use the supplied constants\n     * to indicate the desired dayOfWeek, ex. static::MONDAY.\n     *\n     * @param int|null $dayOfWeek day of the week default null\n     *\n     * @return static\n     */\n    public function firstOfYear($dayOfWeek = null);\n\n    /**\n     * Get the difference in days as float (microsecond-precision).\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return float\n     */\n    public function floatDiffInDays($date = null, $absolute = true);\n\n    /**\n     * Get the difference in hours as float (microsecond-precision).\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return float\n     */\n    public function floatDiffInHours($date = null, $absolute = true);\n\n    /**\n     * Get the difference in minutes as float (microsecond-precision).\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return float\n     */\n    public function floatDiffInMinutes($date = null, $absolute = true);\n\n    /**\n     * Get the difference in months as float (microsecond-precision).\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return float\n     */\n    public function floatDiffInMonths($date = null, $absolute = true);\n\n    /**\n     * Get the difference in days as float (microsecond-precision).\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return float\n     */\n    public function floatDiffInRealDays($date = null, $absolute = true);\n\n    /**\n     * Get the difference in hours as float (microsecond-precision) using timestamps.\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return float\n     */\n    public function floatDiffInRealHours($date = null, $absolute = true);\n\n    /**\n     * Get the difference in minutes as float (microsecond-precision) using timestamps.\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return float\n     */\n    public function floatDiffInRealMinutes($date = null, $absolute = true);\n\n    /**\n     * Get the difference in months as float (microsecond-precision) using timestamps.\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return float\n     */\n    public function floatDiffInRealMonths($date = null, $absolute = true);\n\n    /**\n     * Get the difference in seconds as float (microsecond-precision) using timestamps.\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return float\n     */\n    public function floatDiffInRealSeconds($date = null, $absolute = true);\n\n    /**\n     * Get the difference in weeks as float (microsecond-precision).\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return float\n     */\n    public function floatDiffInRealWeeks($date = null, $absolute = true);\n\n    /**\n     * Get the difference in year as float (microsecond-precision) using timestamps.\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return float\n     */\n    public function floatDiffInRealYears($date = null, $absolute = true);\n\n    /**\n     * Get the difference in seconds as float (microsecond-precision).\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return float\n     */\n    public function floatDiffInSeconds($date = null, $absolute = true);\n\n    /**\n     * Get the difference in weeks as float (microsecond-precision).\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return float\n     */\n    public function floatDiffInWeeks($date = null, $absolute = true);\n\n    /**\n     * Get the difference in year as float (microsecond-precision).\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return float\n     */\n    public function floatDiffInYears($date = null, $absolute = true);\n\n    /**\n     * Round the current instance second with given precision if specified.\n     *\n     * @param float|int|string|\\DateInterval|null $precision\n     *\n     * @return CarbonInterface\n     */\n    public function floor($precision = 1);\n\n    /**\n     * Truncate the current instance at the given unit with given precision if specified.\n     *\n     * @param string    $unit\n     * @param float|int $precision\n     *\n     * @return CarbonInterface\n     */\n    public function floorUnit($unit, $precision = 1);\n\n    /**\n     * Truncate the current instance week.\n     *\n     * @param int $weekStartsAt optional start allow you to specify the day of week to use to start the week\n     *\n     * @return CarbonInterface\n     */\n    public function floorWeek($weekStartsAt = null);\n\n    /**\n     * Format the instance with the current locale.  You can set the current\n     * locale using setlocale() https://php.net/setlocale.\n     *\n     * @deprecated It uses OS language package and strftime() which is deprecated since PHP 8.1.\n     *             Use ->isoFormat() instead.\n     *             Deprecated since 2.55.0\n     *\n     * @param string $format\n     *\n     * @return string\n     */\n    public function formatLocalized($format);\n\n    /**\n     * @alias diffForHumans\n     *\n     * Get the difference in a human readable format in the current locale from current instance to an other\n     * instance given (or now if null given).\n     *\n     * @param Carbon|\\DateTimeInterface|string|array|null $other   if array passed, will be used as parameters array, see $syntax below;\n     *                                                             if null passed, now will be used as comparison reference;\n     *                                                             if any other type, it will be converted to date and used as reference.\n     * @param int|array                                   $syntax  if array passed, parameters will be extracted from it, the array may contains:\n     *                                                             - 'syntax' entry (see below)\n     *                                                             - 'short' entry (see below)\n     *                                                             - 'parts' entry (see below)\n     *                                                             - 'options' entry (see below)\n     *                                                             - 'join' entry determines how to join multiple parts of the string\n     *                                                             `  - if $join is a string, it's used as a joiner glue\n     *                                                             `  - if $join is a callable/closure, it get the list of string and should return a string\n     *                                                             `  - if $join is an array, the first item will be the default glue, and the second item\n     *                                                             `    will be used instead of the glue for the last item\n     *                                                             `  - if $join is true, it will be guessed from the locale ('list' translation file entry)\n     *                                                             `  - if $join is missing, a space will be used as glue\n     *                                                             - 'other' entry (see above)\n     *                                                             if int passed, it add modifiers:\n     *                                                             Possible values:\n     *                                                             - CarbonInterface::DIFF_ABSOLUTE          no modifiers\n     *                                                             - CarbonInterface::DIFF_RELATIVE_TO_NOW   add ago/from now modifier\n     *                                                             - CarbonInterface::DIFF_RELATIVE_TO_OTHER add before/after modifier\n     *                                                             Default value: CarbonInterface::DIFF_ABSOLUTE\n     * @param bool                                        $short   displays short format of time units\n     * @param int                                         $parts   maximum number of parts to display (default value: 1: single unit)\n     * @param int                                         $options human diff options\n     *\n     * @return string\n     */\n    public function from($other = null, $syntax = null, $short = false, $parts = 1, $options = null);\n\n    /**\n     * Get the difference in a human readable format in the current locale from current\n     * instance to now.\n     *\n     * @param int|array $syntax  if array passed, parameters will be extracted from it, the array may contains:\n     *                           - 'syntax' entry (see below)\n     *                           - 'short' entry (see below)\n     *                           - 'parts' entry (see below)\n     *                           - 'options' entry (see below)\n     *                           - 'join' entry determines how to join multiple parts of the string\n     *                           `  - if $join is a string, it's used as a joiner glue\n     *                           `  - if $join is a callable/closure, it get the list of string and should return a string\n     *                           `  - if $join is an array, the first item will be the default glue, and the second item\n     *                           `    will be used instead of the glue for the last item\n     *                           `  - if $join is true, it will be guessed from the locale ('list' translation file entry)\n     *                           `  - if $join is missing, a space will be used as glue\n     *                           if int passed, it add modifiers:\n     *                           Possible values:\n     *                           - CarbonInterface::DIFF_ABSOLUTE          no modifiers\n     *                           - CarbonInterface::DIFF_RELATIVE_TO_NOW   add ago/from now modifier\n     *                           - CarbonInterface::DIFF_RELATIVE_TO_OTHER add before/after modifier\n     *                           Default value: CarbonInterface::DIFF_ABSOLUTE\n     * @param bool      $short   displays short format of time units\n     * @param int       $parts   maximum number of parts to display (default value: 1: single unit)\n     * @param int       $options human diff options\n     *\n     * @return string\n     */\n    public function fromNow($syntax = null, $short = false, $parts = 1, $options = null);\n\n    /**\n     * Create an instance from a serialized string.\n     *\n     * @param string $value\n     *\n     * @throws InvalidFormatException\n     *\n     * @return static\n     */\n    public static function fromSerialized($value);\n\n    /**\n     * Register a custom macro.\n     *\n     * @param object|callable $macro\n     * @param int             $priority marco with higher priority is tried first\n     *\n     * @return void\n     */\n    public static function genericMacro($macro, $priority = 0);\n\n    /**\n     * Get a part of the Carbon object\n     *\n     * @param string $name\n     *\n     * @throws UnknownGetterException\n     *\n     * @return string|int|bool|DateTimeZone|null\n     */\n    public function get($name);\n\n    /**\n     * Returns the alternative number for a given date property if available in the current locale.\n     *\n     * @param string $key date property\n     *\n     * @return string\n     */\n    public function getAltNumber(string $key): string;\n\n    /**\n     * Returns the list of internally available locales and already loaded custom locales.\n     * (It will ignore custom translator dynamic loading.)\n     *\n     * @return array\n     */\n    public static function getAvailableLocales();\n\n    /**\n     * Returns list of Language object for each available locale. This object allow you to get the ISO name, native\n     * name, region and variant of the locale.\n     *\n     * @return Language[]\n     */\n    public static function getAvailableLocalesInfo();\n\n    /**\n     * Returns list of calendar formats for ISO formatting.\n     *\n     * @param string|null $locale current locale used if null\n     *\n     * @return array\n     */\n    public function getCalendarFormats($locale = null);\n\n    /**\n     * Get the days of the week\n     *\n     * @return array\n     */\n    public static function getDays();\n\n    /**\n     * Return the number of days since the start of the week (using the current locale or the first parameter\n     * if explicitly given).\n     *\n     * @param int|null $weekStartsAt optional start allow you to specify the day of week to use to start the week,\n     *                               if not provided, start of week is inferred from the locale\n     *                               (Sunday for en_US, Monday for de_DE, etc.)\n     *\n     * @return int\n     */\n    public function getDaysFromStartOfWeek(?int $weekStartsAt = null): int;\n\n    /**\n     * Get the fallback locale.\n     *\n     * @see https://symfony.com/doc/current/components/translation.html#fallback-locales\n     *\n     * @return string|null\n     */\n    public static function getFallbackLocale();\n\n    /**\n     * List of replacements from date() format to isoFormat().\n     *\n     * @return array\n     */\n    public static function getFormatsToIsoReplacements();\n\n    /**\n     * Return default humanDiff() options (merged flags as integer).\n     *\n     * @return int\n     */\n    public static function getHumanDiffOptions();\n\n    /**\n     * Returns list of locale formats for ISO formatting.\n     *\n     * @param string|null $locale current locale used if null\n     *\n     * @return array\n     */\n    public function getIsoFormats($locale = null);\n\n    /**\n     * Returns list of locale units for ISO formatting.\n     *\n     * @return array\n     */\n    public static function getIsoUnits();\n\n    /**\n     * {@inheritdoc}\n     *\n     * @return array\n     */\n    #[ReturnTypeWillChange]\n    public static function getLastErrors();\n\n    /**\n     * Get the raw callable macro registered globally or locally for a given name.\n     *\n     * @param string $name\n     *\n     * @return callable|null\n     */\n    public function getLocalMacro($name);\n\n    /**\n     * Get the translator of the current instance or the default if none set.\n     *\n     * @return \\Symfony\\Component\\Translation\\TranslatorInterface\n     */\n    public function getLocalTranslator();\n\n    /**\n     * Get the current translator locale.\n     *\n     * @return string\n     */\n    public static function getLocale();\n\n    /**\n     * Get the raw callable macro registered globally for a given name.\n     *\n     * @param string $name\n     *\n     * @return callable|null\n     */\n    public static function getMacro($name);\n\n    /**\n     * get midday/noon hour\n     *\n     * @return int\n     */\n    public static function getMidDayAt();\n\n    /**\n     * Returns the offset hour and minute formatted with +/- and a given separator (\":\" by default).\n     * For example, if the time zone is 9 hours 30 minutes, you'll get \"+09:30\", with \"@@\" as first\n     * argument, \"+09@@30\", with \"\" as first argument, \"+0930\". Negative offset will return something\n     * like \"-12:00\".\n     *\n     * @param string $separator string to place between hours and minutes (\":\" by default)\n     *\n     * @return string\n     */\n    public function getOffsetString($separator = ':');\n\n    /**\n     * Returns a unit of the instance padded with 0 by default or any other string if specified.\n     *\n     * @param string $unit      Carbon unit name\n     * @param int    $length    Length of the output (2 by default)\n     * @param string $padString String to use for padding (\"0\" by default)\n     * @param int    $padType   Side(s) to pad (STR_PAD_LEFT by default)\n     *\n     * @return string\n     */\n    public function getPaddedUnit($unit, $length = 2, $padString = '0', $padType = 0);\n\n    /**\n     * Returns a timestamp rounded with the given precision (6 by default).\n     *\n     * @example getPreciseTimestamp()   1532087464437474 (microsecond maximum precision)\n     * @example getPreciseTimestamp(6)  1532087464437474\n     * @example getPreciseTimestamp(5)  153208746443747  (1/100000 second precision)\n     * @example getPreciseTimestamp(4)  15320874644375   (1/10000 second precision)\n     * @example getPreciseTimestamp(3)  1532087464437    (millisecond precision)\n     * @example getPreciseTimestamp(2)  153208746444     (1/100 second precision)\n     * @example getPreciseTimestamp(1)  15320874644      (1/10 second precision)\n     * @example getPreciseTimestamp(0)  1532087464       (second precision)\n     * @example getPreciseTimestamp(-1) 153208746        (10 second precision)\n     * @example getPreciseTimestamp(-2) 15320875         (100 second precision)\n     *\n     * @param int $precision\n     *\n     * @return float\n     */\n    public function getPreciseTimestamp($precision = 6);\n\n    /**\n     * Returns current local settings.\n     *\n     * @return array\n     */\n    public function getSettings();\n\n    /**\n     * Get the Carbon instance (real or mock) to be returned when a \"now\"\n     * instance is created.\n     *\n     * @return Closure|static the current instance used for testing\n     */\n    public static function getTestNow();\n\n    /**\n     * Return a format from H:i to H:i:s.u according to given unit precision.\n     *\n     * @param string $unitPrecision \"minute\", \"second\", \"millisecond\" or \"microsecond\"\n     *\n     * @return string\n     */\n    public static function getTimeFormatByPrecision($unitPrecision);\n\n    /**\n     * Returns the timestamp with millisecond precision.\n     *\n     * @return int\n     */\n    public function getTimestampMs();\n\n    /**\n     * Get the translation of the current week day name (with context for languages with multiple forms).\n     *\n     * @param string|null $context      whole format string\n     * @param string      $keySuffix    \"\", \"_short\" or \"_min\"\n     * @param string|null $defaultValue default value if translation missing\n     *\n     * @return string\n     */\n    public function getTranslatedDayName($context = null, $keySuffix = '', $defaultValue = null);\n\n    /**\n     * Get the translation of the current abbreviated week day name (with context for languages with multiple forms).\n     *\n     * @param string|null $context whole format string\n     *\n     * @return string\n     */\n    public function getTranslatedMinDayName($context = null);\n\n    /**\n     * Get the translation of the current month day name (with context for languages with multiple forms).\n     *\n     * @param string|null $context      whole format string\n     * @param string      $keySuffix    \"\" or \"_short\"\n     * @param string|null $defaultValue default value if translation missing\n     *\n     * @return string\n     */\n    public function getTranslatedMonthName($context = null, $keySuffix = '', $defaultValue = null);\n\n    /**\n     * Get the translation of the current short week day name (with context for languages with multiple forms).\n     *\n     * @param string|null $context whole format string\n     *\n     * @return string\n     */\n    public function getTranslatedShortDayName($context = null);\n\n    /**\n     * Get the translation of the current short month day name (with context for languages with multiple forms).\n     *\n     * @param string|null $context whole format string\n     *\n     * @return string\n     */\n    public function getTranslatedShortMonthName($context = null);\n\n    /**\n     * Returns raw translation message for a given key.\n     *\n     * @param string                                             $key        key to find\n     * @param string|null                                        $locale     current locale used if null\n     * @param string|null                                        $default    default value if translation returns the key\n     * @param \\Symfony\\Component\\Translation\\TranslatorInterface $translator an optional translator to use\n     *\n     * @return string\n     */\n    public function getTranslationMessage(string $key, ?string $locale = null, ?string $default = null, $translator = null);\n\n    /**\n     * Returns raw translation message for a given key.\n     *\n     * @param \\Symfony\\Component\\Translation\\TranslatorInterface $translator the translator to use\n     * @param string                                             $key        key to find\n     * @param string|null                                        $locale     current locale used if null\n     * @param string|null                                        $default    default value if translation returns the key\n     *\n     * @return string\n     */\n    public static function getTranslationMessageWith($translator, string $key, ?string $locale = null, ?string $default = null);\n\n    /**\n     * Get the default translator instance in use.\n     *\n     * @return \\Symfony\\Component\\Translation\\TranslatorInterface\n     */\n    public static function getTranslator();\n\n    /**\n     * Get the last day of week\n     *\n     * @return int\n     */\n    public static function getWeekEndsAt();\n\n    /**\n     * Get the first day of week\n     *\n     * @return int\n     */\n    public static function getWeekStartsAt();\n\n    /**\n     * Get weekend days\n     *\n     * @return array\n     */\n    public static function getWeekendDays();\n\n    /**\n     * Determines if the instance is greater (after) than another\n     *\n     * @example\n     * ```\n     * Carbon::parse('2018-07-25 12:45:16')->greaterThan('2018-07-25 12:45:15'); // true\n     * Carbon::parse('2018-07-25 12:45:16')->greaterThan('2018-07-25 12:45:16'); // false\n     * Carbon::parse('2018-07-25 12:45:16')->greaterThan('2018-07-25 12:45:17'); // false\n     * ```\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date\n     *\n     * @return bool\n     */\n    public function greaterThan($date): bool;\n\n    /**\n     * Determines if the instance is greater (after) than or equal to another\n     *\n     * @example\n     * ```\n     * Carbon::parse('2018-07-25 12:45:16')->greaterThanOrEqualTo('2018-07-25 12:45:15'); // true\n     * Carbon::parse('2018-07-25 12:45:16')->greaterThanOrEqualTo('2018-07-25 12:45:16'); // true\n     * Carbon::parse('2018-07-25 12:45:16')->greaterThanOrEqualTo('2018-07-25 12:45:17'); // false\n     * ```\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date\n     *\n     * @return bool\n     */\n    public function greaterThanOrEqualTo($date): bool;\n\n    /**\n     * Determines if the instance is greater (after) than another\n     *\n     * @example\n     * ```\n     * Carbon::parse('2018-07-25 12:45:16')->gt('2018-07-25 12:45:15'); // true\n     * Carbon::parse('2018-07-25 12:45:16')->gt('2018-07-25 12:45:16'); // false\n     * Carbon::parse('2018-07-25 12:45:16')->gt('2018-07-25 12:45:17'); // false\n     * ```\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date\n     *\n     * @see greaterThan()\n     *\n     * @return bool\n     */\n    public function gt($date): bool;\n\n    /**\n     * Determines if the instance is greater (after) than or equal to another\n     *\n     * @example\n     * ```\n     * Carbon::parse('2018-07-25 12:45:16')->gte('2018-07-25 12:45:15'); // true\n     * Carbon::parse('2018-07-25 12:45:16')->gte('2018-07-25 12:45:16'); // true\n     * Carbon::parse('2018-07-25 12:45:16')->gte('2018-07-25 12:45:17'); // false\n     * ```\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date\n     *\n     * @see greaterThanOrEqualTo()\n     *\n     * @return bool\n     */\n    public function gte($date): bool;\n\n    /**\n     * Checks if the (date)time string is in a given format.\n     *\n     * @example\n     * ```\n     * Carbon::hasFormat('11:12:45', 'h:i:s'); // true\n     * Carbon::hasFormat('13:12:45', 'h:i:s'); // false\n     * ```\n     *\n     * @param string $date\n     * @param string $format\n     *\n     * @return bool\n     */\n    public static function hasFormat($date, $format);\n\n    /**\n     * Checks if the (date)time string is in a given format.\n     *\n     * @example\n     * ```\n     * Carbon::hasFormatWithModifiers('31/08/2015', 'd#m#Y'); // true\n     * Carbon::hasFormatWithModifiers('31/08/2015', 'm#d#Y'); // false\n     * ```\n     *\n     * @param string $date\n     * @param string $format\n     *\n     * @return bool\n     */\n    public static function hasFormatWithModifiers($date, $format): bool;\n\n    /**\n     * Checks if macro is registered globally or locally.\n     *\n     * @param string $name\n     *\n     * @return bool\n     */\n    public function hasLocalMacro($name);\n\n    /**\n     * Return true if the current instance has its own translator.\n     *\n     * @return bool\n     */\n    public function hasLocalTranslator();\n\n    /**\n     * Checks if macro is registered globally.\n     *\n     * @param string $name\n     *\n     * @return bool\n     */\n    public static function hasMacro($name);\n\n    /**\n     * Determine if a time string will produce a relative date.\n     *\n     * @param string $time\n     *\n     * @return bool true if time match a relative date, false if absolute or invalid time string\n     */\n    public static function hasRelativeKeywords($time);\n\n    /**\n     * Determine if there is a valid test instance set. A valid test instance\n     * is anything that is not null.\n     *\n     * @return bool true if there is a test instance, otherwise false\n     */\n    public static function hasTestNow();\n\n    /**\n     * Create a Carbon instance from a DateTime one.\n     *\n     * @param DateTimeInterface $date\n     *\n     * @return static\n     */\n    public static function instance($date);\n\n    /**\n     * Returns true if the current date matches the given string.\n     *\n     * @example\n     * ```\n     * var_dump(Carbon::parse('2019-06-02 12:23:45')->is('2019')); // true\n     * var_dump(Carbon::parse('2019-06-02 12:23:45')->is('2018')); // false\n     * var_dump(Carbon::parse('2019-06-02 12:23:45')->is('2019-06')); // true\n     * var_dump(Carbon::parse('2019-06-02 12:23:45')->is('06-02')); // true\n     * var_dump(Carbon::parse('2019-06-02 12:23:45')->is('2019-06-02')); // true\n     * var_dump(Carbon::parse('2019-06-02 12:23:45')->is('Sunday')); // true\n     * var_dump(Carbon::parse('2019-06-02 12:23:45')->is('June')); // true\n     * var_dump(Carbon::parse('2019-06-02 12:23:45')->is('12:23')); // true\n     * var_dump(Carbon::parse('2019-06-02 12:23:45')->is('12:23:45')); // true\n     * var_dump(Carbon::parse('2019-06-02 12:23:45')->is('12:23:00')); // false\n     * var_dump(Carbon::parse('2019-06-02 12:23:45')->is('12h')); // true\n     * var_dump(Carbon::parse('2019-06-02 15:23:45')->is('3pm')); // true\n     * var_dump(Carbon::parse('2019-06-02 15:23:45')->is('3am')); // false\n     * ```\n     *\n     * @param string $tester day name, month name, hour, date, etc. as string\n     *\n     * @return bool\n     */\n    public function is(string $tester);\n\n    /**\n     * Determines if the instance is greater (after) than another\n     *\n     * @example\n     * ```\n     * Carbon::parse('2018-07-25 12:45:16')->isAfter('2018-07-25 12:45:15'); // true\n     * Carbon::parse('2018-07-25 12:45:16')->isAfter('2018-07-25 12:45:16'); // false\n     * Carbon::parse('2018-07-25 12:45:16')->isAfter('2018-07-25 12:45:17'); // false\n     * ```\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date\n     *\n     * @see greaterThan()\n     *\n     * @return bool\n     */\n    public function isAfter($date): bool;\n\n    /**\n     * Determines if the instance is less (before) than another\n     *\n     * @example\n     * ```\n     * Carbon::parse('2018-07-25 12:45:16')->isBefore('2018-07-25 12:45:15'); // false\n     * Carbon::parse('2018-07-25 12:45:16')->isBefore('2018-07-25 12:45:16'); // false\n     * Carbon::parse('2018-07-25 12:45:16')->isBefore('2018-07-25 12:45:17'); // true\n     * ```\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date\n     *\n     * @see lessThan()\n     *\n     * @return bool\n     */\n    public function isBefore($date): bool;\n\n    /**\n     * Determines if the instance is between two others\n     *\n     * @example\n     * ```\n     * Carbon::parse('2018-07-25')->isBetween('2018-07-14', '2018-08-01'); // true\n     * Carbon::parse('2018-07-25')->isBetween('2018-08-01', '2018-08-20'); // false\n     * Carbon::parse('2018-07-25')->isBetween('2018-07-25', '2018-08-01'); // true\n     * Carbon::parse('2018-07-25')->isBetween('2018-07-25', '2018-08-01', false); // false\n     * ```\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date1\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date2\n     * @param bool                                    $equal Indicates if an equal to comparison should be done\n     *\n     * @return bool\n     */\n    public function isBetween($date1, $date2, $equal = true): bool;\n\n    /**\n     * Check if its the birthday. Compares the date/month values of the two dates.\n     *\n     * @example\n     * ```\n     * Carbon::now()->subYears(5)->isBirthday(); // true\n     * Carbon::now()->subYears(5)->subDay()->isBirthday(); // false\n     * Carbon::parse('2019-06-05')->isBirthday(Carbon::parse('2001-06-05')); // true\n     * Carbon::parse('2019-06-05')->isBirthday(Carbon::parse('2001-06-06')); // false\n     * ```\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|null $date The instance to compare with or null to use current day.\n     *\n     * @return bool\n     */\n    public function isBirthday($date = null);\n\n    /**\n     * Determines if the instance is in the current unit given.\n     *\n     * @example\n     * ```\n     * Carbon::now()->isCurrentUnit('hour'); // true\n     * Carbon::now()->subHours(2)->isCurrentUnit('hour'); // false\n     * ```\n     *\n     * @param string $unit The unit to test.\n     *\n     * @throws BadMethodCallException\n     *\n     * @return bool\n     */\n    public function isCurrentUnit($unit);\n\n    /**\n     * Checks if this day is a specific day of the week.\n     *\n     * @example\n     * ```\n     * Carbon::parse('2019-07-17')->isDayOfWeek(Carbon::WEDNESDAY); // true\n     * Carbon::parse('2019-07-17')->isDayOfWeek(Carbon::FRIDAY); // false\n     * Carbon::parse('2019-07-17')->isDayOfWeek('Wednesday'); // true\n     * Carbon::parse('2019-07-17')->isDayOfWeek('Friday'); // false\n     * ```\n     *\n     * @param int $dayOfWeek\n     *\n     * @return bool\n     */\n    public function isDayOfWeek($dayOfWeek);\n\n    /**\n     * Check if the instance is end of day.\n     *\n     * @example\n     * ```\n     * Carbon::parse('2019-02-28 23:59:59.999999')->isEndOfDay(); // true\n     * Carbon::parse('2019-02-28 23:59:59.123456')->isEndOfDay(); // true\n     * Carbon::parse('2019-02-28 23:59:59')->isEndOfDay(); // true\n     * Carbon::parse('2019-02-28 23:59:58.999999')->isEndOfDay(); // false\n     * Carbon::parse('2019-02-28 23:59:59.999999')->isEndOfDay(true); // true\n     * Carbon::parse('2019-02-28 23:59:59.123456')->isEndOfDay(true); // false\n     * Carbon::parse('2019-02-28 23:59:59')->isEndOfDay(true); // false\n     * ```\n     *\n     * @param bool $checkMicroseconds check time at microseconds precision\n     *\n     * @return bool\n     */\n    public function isEndOfDay($checkMicroseconds = false);\n\n    /**\n     * Returns true if the date was created using CarbonImmutable::endOfTime()\n     *\n     * @return bool\n     */\n    public function isEndOfTime(): bool;\n\n    /**\n     * Determines if the instance is in the future, ie. greater (after) than now.\n     *\n     * @example\n     * ```\n     * Carbon::now()->addHours(5)->isFuture(); // true\n     * Carbon::now()->subHours(5)->isFuture(); // false\n     * ```\n     *\n     * @return bool\n     */\n    public function isFuture();\n\n    /**\n     * Returns true if the current class/instance is immutable.\n     *\n     * @return bool\n     */\n    public static function isImmutable();\n\n    /**\n     * Check if today is the last day of the Month\n     *\n     * @example\n     * ```\n     * Carbon::parse('2019-02-28')->isLastOfMonth(); // true\n     * Carbon::parse('2019-03-28')->isLastOfMonth(); // false\n     * Carbon::parse('2019-03-30')->isLastOfMonth(); // false\n     * Carbon::parse('2019-03-31')->isLastOfMonth(); // true\n     * Carbon::parse('2019-04-30')->isLastOfMonth(); // true\n     * ```\n     *\n     * @return bool\n     */\n    public function isLastOfMonth();\n\n    /**\n     * Determines if the instance is a leap year.\n     *\n     * @example\n     * ```\n     * Carbon::parse('2020-01-01')->isLeapYear(); // true\n     * Carbon::parse('2019-01-01')->isLeapYear(); // false\n     * ```\n     *\n     * @return bool\n     */\n    public function isLeapYear();\n\n    /**\n     * Determines if the instance is a long year (using ISO 8601 year).\n     *\n     * @example\n     * ```\n     * Carbon::parse('2015-01-01')->isLongIsoYear(); // true\n     * Carbon::parse('2016-01-01')->isLongIsoYear(); // true\n     * Carbon::parse('2016-01-03')->isLongIsoYear(); // false\n     * Carbon::parse('2019-12-29')->isLongIsoYear(); // false\n     * Carbon::parse('2019-12-30')->isLongIsoYear(); // true\n     * ```\n     *\n     * @see https://en.wikipedia.org/wiki/ISO_8601#Week_dates\n     *\n     * @return bool\n     */\n    public function isLongIsoYear();\n\n    /**\n     * Determines if the instance is a long year (using calendar year).\n     *\n     * ⚠️ This method completely ignores month and day to use the numeric year number,\n     * it's not correct if the exact date matters. For instance as `2019-12-30` is already\n     * in the first week of the 2020 year, if you want to know from this date if ISO week\n     * year 2020 is a long year, use `isLongIsoYear` instead.\n     *\n     * @example\n     * ```\n     * Carbon::create(2015)->isLongYear(); // true\n     * Carbon::create(2016)->isLongYear(); // false\n     * ```\n     *\n     * @see https://en.wikipedia.org/wiki/ISO_8601#Week_dates\n     *\n     * @return bool\n     */\n    public function isLongYear();\n\n    /**\n     * Check if the instance is midday.\n     *\n     * @example\n     * ```\n     * Carbon::parse('2019-02-28 11:59:59.999999')->isMidday(); // false\n     * Carbon::parse('2019-02-28 12:00:00')->isMidday(); // true\n     * Carbon::parse('2019-02-28 12:00:00.999999')->isMidday(); // true\n     * Carbon::parse('2019-02-28 12:00:01')->isMidday(); // false\n     * ```\n     *\n     * @return bool\n     */\n    public function isMidday();\n\n    /**\n     * Check if the instance is start of day / midnight.\n     *\n     * @example\n     * ```\n     * Carbon::parse('2019-02-28 00:00:00')->isMidnight(); // true\n     * Carbon::parse('2019-02-28 00:00:00.999999')->isMidnight(); // true\n     * Carbon::parse('2019-02-28 00:00:01')->isMidnight(); // false\n     * ```\n     *\n     * @return bool\n     */\n    public function isMidnight();\n\n    /**\n     * Returns true if a property can be changed via setter.\n     *\n     * @param string $unit\n     *\n     * @return bool\n     */\n    public static function isModifiableUnit($unit);\n\n    /**\n     * Returns true if the current class/instance is mutable.\n     *\n     * @return bool\n     */\n    public static function isMutable();\n\n    /**\n     * Determines if the instance is in the past, ie. less (before) than now.\n     *\n     * @example\n     * ```\n     * Carbon::now()->subHours(5)->isPast(); // true\n     * Carbon::now()->addHours(5)->isPast(); // false\n     * ```\n     *\n     * @return bool\n     */\n    public function isPast();\n\n    /**\n     * Compares the formatted values of the two dates.\n     *\n     * @example\n     * ```\n     * Carbon::parse('2019-06-13')->isSameAs('Y-d', Carbon::parse('2019-12-13')); // true\n     * Carbon::parse('2019-06-13')->isSameAs('Y-d', Carbon::parse('2019-06-14')); // false\n     * ```\n     *\n     * @param string                                        $format date formats to compare.\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|string|null $date   instance to compare with or null to use current day.\n     *\n     * @return bool\n     */\n    public function isSameAs($format, $date = null);\n\n    /**\n     * Checks if the passed in date is in the same month as the instance´s month.\n     *\n     * @example\n     * ```\n     * Carbon::parse('2019-01-12')->isSameMonth(Carbon::parse('2019-01-01')); // true\n     * Carbon::parse('2019-01-12')->isSameMonth(Carbon::parse('2019-02-01')); // false\n     * Carbon::parse('2019-01-12')->isSameMonth(Carbon::parse('2018-01-01')); // false\n     * Carbon::parse('2019-01-12')->isSameMonth(Carbon::parse('2018-01-01'), false); // true\n     * ```\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|null $date       The instance to compare with or null to use the current date.\n     * @param bool                                   $ofSameYear Check if it is the same month in the same year.\n     *\n     * @return bool\n     */\n    public function isSameMonth($date = null, $ofSameYear = true);\n\n    /**\n     * Checks if the passed in date is in the same quarter as the instance quarter (and year if needed).\n     *\n     * @example\n     * ```\n     * Carbon::parse('2019-01-12')->isSameQuarter(Carbon::parse('2019-03-01')); // true\n     * Carbon::parse('2019-01-12')->isSameQuarter(Carbon::parse('2019-04-01')); // false\n     * Carbon::parse('2019-01-12')->isSameQuarter(Carbon::parse('2018-03-01')); // false\n     * Carbon::parse('2019-01-12')->isSameQuarter(Carbon::parse('2018-03-01'), false); // true\n     * ```\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|string|null $date       The instance to compare with or null to use current day.\n     * @param bool                                          $ofSameYear Check if it is the same month in the same year.\n     *\n     * @return bool\n     */\n    public function isSameQuarter($date = null, $ofSameYear = true);\n\n    /**\n     * Determines if the instance is in the current unit given.\n     *\n     * @example\n     * ```\n     * Carbon::parse('2019-01-13')->isSameUnit('year', Carbon::parse('2019-12-25')); // true\n     * Carbon::parse('2018-12-13')->isSameUnit('year', Carbon::parse('2019-12-25')); // false\n     * ```\n     *\n     * @param string                                 $unit singular unit string\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|null $date instance to compare with or null to use current day.\n     *\n     * @throws BadComparisonUnitException\n     *\n     * @return bool\n     */\n    public function isSameUnit($unit, $date = null);\n\n    /**\n     * Check if the instance is start of day / midnight.\n     *\n     * @example\n     * ```\n     * Carbon::parse('2019-02-28 00:00:00')->isStartOfDay(); // true\n     * Carbon::parse('2019-02-28 00:00:00.999999')->isStartOfDay(); // true\n     * Carbon::parse('2019-02-28 00:00:01')->isStartOfDay(); // false\n     * Carbon::parse('2019-02-28 00:00:00.000000')->isStartOfDay(true); // true\n     * Carbon::parse('2019-02-28 00:00:00.000012')->isStartOfDay(true); // false\n     * ```\n     *\n     * @param bool $checkMicroseconds check time at microseconds precision\n     *\n     * @return bool\n     */\n    public function isStartOfDay($checkMicroseconds = false);\n\n    /**\n     * Returns true if the date was created using CarbonImmutable::startOfTime()\n     *\n     * @return bool\n     */\n    public function isStartOfTime(): bool;\n\n    /**\n     * Returns true if the strict mode is globally in use, false else.\n     * (It can be overridden in specific instances.)\n     *\n     * @return bool\n     */\n    public static function isStrictModeEnabled();\n\n    /**\n     * Determines if the instance is today.\n     *\n     * @example\n     * ```\n     * Carbon::today()->isToday(); // true\n     * Carbon::tomorrow()->isToday(); // false\n     * ```\n     *\n     * @return bool\n     */\n    public function isToday();\n\n    /**\n     * Determines if the instance is tomorrow.\n     *\n     * @example\n     * ```\n     * Carbon::tomorrow()->isTomorrow(); // true\n     * Carbon::yesterday()->isTomorrow(); // false\n     * ```\n     *\n     * @return bool\n     */\n    public function isTomorrow();\n\n    /**\n     * Determines if the instance is a weekday.\n     *\n     * @example\n     * ```\n     * Carbon::parse('2019-07-14')->isWeekday(); // false\n     * Carbon::parse('2019-07-15')->isWeekday(); // true\n     * ```\n     *\n     * @return bool\n     */\n    public function isWeekday();\n\n    /**\n     * Determines if the instance is a weekend day.\n     *\n     * @example\n     * ```\n     * Carbon::parse('2019-07-14')->isWeekend(); // true\n     * Carbon::parse('2019-07-15')->isWeekend(); // false\n     * ```\n     *\n     * @return bool\n     */\n    public function isWeekend();\n\n    /**\n     * Determines if the instance is yesterday.\n     *\n     * @example\n     * ```\n     * Carbon::yesterday()->isYesterday(); // true\n     * Carbon::tomorrow()->isYesterday(); // false\n     * ```\n     *\n     * @return bool\n     */\n    public function isYesterday();\n\n    /**\n     * Format in the current language using ISO replacement patterns.\n     *\n     * @param string      $format\n     * @param string|null $originalFormat provide context if a chunk has been passed alone\n     *\n     * @return string\n     */\n    public function isoFormat(string $format, ?string $originalFormat = null): string;\n\n    /**\n     * Get/set the week number using given first day of week and first\n     * day of year included in the first week. Or use ISO format if no settings\n     * given.\n     *\n     * @param int|null $week\n     * @param int|null $dayOfWeek\n     * @param int|null $dayOfYear\n     *\n     * @return int|static\n     */\n    public function isoWeek($week = null, $dayOfWeek = null, $dayOfYear = null);\n\n    /**\n     * Set/get the week number of year using given first day of week and first\n     * day of year included in the first week. Or use ISO format if no settings\n     * given.\n     *\n     * @param int|null $year      if null, act as a getter, if not null, set the year and return current instance.\n     * @param int|null $dayOfWeek first date of week from 0 (Sunday) to 6 (Saturday)\n     * @param int|null $dayOfYear first day of year included in the week #1\n     *\n     * @return int|static\n     */\n    public function isoWeekYear($year = null, $dayOfWeek = null, $dayOfYear = null);\n\n    /**\n     * Get/set the ISO weekday from 1 (Monday) to 7 (Sunday).\n     *\n     * @param int|null $value new value for weekday if using as setter.\n     *\n     * @return static|int\n     */\n    public function isoWeekday($value = null);\n\n    /**\n     * Get the number of weeks of the current week-year using given first day of week and first\n     * day of year included in the first week. Or use ISO format if no settings\n     * given.\n     *\n     * @param int|null $dayOfWeek first date of week from 0 (Sunday) to 6 (Saturday)\n     * @param int|null $dayOfYear first day of year included in the week #1\n     *\n     * @return int\n     */\n    public function isoWeeksInYear($dayOfWeek = null, $dayOfYear = null);\n\n    /**\n     * Prepare the object for JSON serialization.\n     *\n     * @return array|string\n     */\n    #[ReturnTypeWillChange]\n    public function jsonSerialize();\n\n    /**\n     * Modify to the last occurrence of a given day of the week\n     * in the current month. If no dayOfWeek is provided, modify to the\n     * last day of the current month.  Use the supplied constants\n     * to indicate the desired dayOfWeek, ex. static::MONDAY.\n     *\n     * @param int|null $dayOfWeek\n     *\n     * @return static\n     */\n    public function lastOfMonth($dayOfWeek = null);\n\n    /**\n     * Modify to the last occurrence of a given day of the week\n     * in the current quarter. If no dayOfWeek is provided, modify to the\n     * last day of the current quarter.  Use the supplied constants\n     * to indicate the desired dayOfWeek, ex. static::MONDAY.\n     *\n     * @param int|null $dayOfWeek day of the week default null\n     *\n     * @return static\n     */\n    public function lastOfQuarter($dayOfWeek = null);\n\n    /**\n     * Modify to the last occurrence of a given day of the week\n     * in the current year. If no dayOfWeek is provided, modify to the\n     * last day of the current year.  Use the supplied constants\n     * to indicate the desired dayOfWeek, ex. static::MONDAY.\n     *\n     * @param int|null $dayOfWeek day of the week default null\n     *\n     * @return static\n     */\n    public function lastOfYear($dayOfWeek = null);\n\n    /**\n     * Determines if the instance is less (before) than another\n     *\n     * @example\n     * ```\n     * Carbon::parse('2018-07-25 12:45:16')->lessThan('2018-07-25 12:45:15'); // false\n     * Carbon::parse('2018-07-25 12:45:16')->lessThan('2018-07-25 12:45:16'); // false\n     * Carbon::parse('2018-07-25 12:45:16')->lessThan('2018-07-25 12:45:17'); // true\n     * ```\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date\n     *\n     * @return bool\n     */\n    public function lessThan($date): bool;\n\n    /**\n     * Determines if the instance is less (before) or equal to another\n     *\n     * @example\n     * ```\n     * Carbon::parse('2018-07-25 12:45:16')->lessThanOrEqualTo('2018-07-25 12:45:15'); // false\n     * Carbon::parse('2018-07-25 12:45:16')->lessThanOrEqualTo('2018-07-25 12:45:16'); // true\n     * Carbon::parse('2018-07-25 12:45:16')->lessThanOrEqualTo('2018-07-25 12:45:17'); // true\n     * ```\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date\n     *\n     * @return bool\n     */\n    public function lessThanOrEqualTo($date): bool;\n\n    /**\n     * Get/set the locale for the current instance.\n     *\n     * @param string|null $locale\n     * @param string      ...$fallbackLocales\n     *\n     * @return $this|string\n     */\n    public function locale(?string $locale = null, ...$fallbackLocales);\n\n    /**\n     * Returns true if the given locale is internally supported and has words for 1-day diff (just now, yesterday, tomorrow).\n     * Support is considered enabled if the 3 words are translated in the given locale.\n     *\n     * @param string $locale locale ex. en\n     *\n     * @return bool\n     */\n    public static function localeHasDiffOneDayWords($locale);\n\n    /**\n     * Returns true if the given locale is internally supported and has diff syntax support (ago, from now, before, after).\n     * Support is considered enabled if the 4 sentences are translated in the given locale.\n     *\n     * @param string $locale locale ex. en\n     *\n     * @return bool\n     */\n    public static function localeHasDiffSyntax($locale);\n\n    /**\n     * Returns true if the given locale is internally supported and has words for 2-days diff (before yesterday, after tomorrow).\n     * Support is considered enabled if the 2 words are translated in the given locale.\n     *\n     * @param string $locale locale ex. en\n     *\n     * @return bool\n     */\n    public static function localeHasDiffTwoDayWords($locale);\n\n    /**\n     * Returns true if the given locale is internally supported and has period syntax support (X times, every X, from X, to X).\n     * Support is considered enabled if the 4 sentences are translated in the given locale.\n     *\n     * @param string $locale locale ex. en\n     *\n     * @return bool\n     */\n    public static function localeHasPeriodSyntax($locale);\n\n    /**\n     * Returns true if the given locale is internally supported and has short-units support.\n     * Support is considered enabled if either year, day or hour has a short variant translated.\n     *\n     * @param string $locale locale ex. en\n     *\n     * @return bool\n     */\n    public static function localeHasShortUnits($locale);\n\n    /**\n     * Determines if the instance is less (before) than another\n     *\n     * @example\n     * ```\n     * Carbon::parse('2018-07-25 12:45:16')->lt('2018-07-25 12:45:15'); // false\n     * Carbon::parse('2018-07-25 12:45:16')->lt('2018-07-25 12:45:16'); // false\n     * Carbon::parse('2018-07-25 12:45:16')->lt('2018-07-25 12:45:17'); // true\n     * ```\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date\n     *\n     * @see lessThan()\n     *\n     * @return bool\n     */\n    public function lt($date): bool;\n\n    /**\n     * Determines if the instance is less (before) or equal to another\n     *\n     * @example\n     * ```\n     * Carbon::parse('2018-07-25 12:45:16')->lte('2018-07-25 12:45:15'); // false\n     * Carbon::parse('2018-07-25 12:45:16')->lte('2018-07-25 12:45:16'); // true\n     * Carbon::parse('2018-07-25 12:45:16')->lte('2018-07-25 12:45:17'); // true\n     * ```\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date\n     *\n     * @see lessThanOrEqualTo()\n     *\n     * @return bool\n     */\n    public function lte($date): bool;\n\n    /**\n     * Register a custom macro.\n     *\n     * @example\n     * ```\n     * $userSettings = [\n     *   'locale' => 'pt',\n     *   'timezone' => 'America/Sao_Paulo',\n     * ];\n     * Carbon::macro('userFormat', function () use ($userSettings) {\n     *   return $this->copy()->locale($userSettings['locale'])->tz($userSettings['timezone'])->calendar();\n     * });\n     * echo Carbon::yesterday()->hours(11)->userFormat();\n     * ```\n     *\n     * @param string          $name\n     * @param object|callable $macro\n     *\n     * @return void\n     */\n    public static function macro($name, $macro);\n\n    /**\n     * Make a Carbon instance from given variable if possible.\n     *\n     * Always return a new instance. Parse only strings and only these likely to be dates (skip intervals\n     * and recurrences). Throw an exception for invalid format, but otherwise return null.\n     *\n     * @param mixed $var\n     *\n     * @throws InvalidFormatException\n     *\n     * @return static|null\n     */\n    public static function make($var);\n\n    /**\n     * Get the maximum instance between a given instance (default now) and the current instance.\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date\n     *\n     * @return static\n     */\n    public function max($date = null);\n\n    /**\n     * Create a Carbon instance for the greatest supported date.\n     *\n     * @return static\n     */\n    public static function maxValue();\n\n    /**\n     * Get the maximum instance between a given instance (default now) and the current instance.\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date\n     *\n     * @see max()\n     *\n     * @return static\n     */\n    public function maximum($date = null);\n\n    /**\n     * Return the meridiem of the current time in the current locale.\n     *\n     * @param bool $isLower if true, returns lowercase variant if available in the current locale.\n     *\n     * @return string\n     */\n    public function meridiem(bool $isLower = false): string;\n\n    /**\n     * Modify to midday, default to self::$midDayAt\n     *\n     * @return static\n     */\n    public function midDay();\n\n    /**\n     * Get the minimum instance between a given instance (default now) and the current instance.\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date\n     *\n     * @return static\n     */\n    public function min($date = null);\n\n    /**\n     * Create a Carbon instance for the lowest supported date.\n     *\n     * @return static\n     */\n    public static function minValue();\n\n    /**\n     * Get the minimum instance between a given instance (default now) and the current instance.\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date\n     *\n     * @see min()\n     *\n     * @return static\n     */\n    public function minimum($date = null);\n\n    /**\n     * Mix another object into the class.\n     *\n     * @example\n     * ```\n     * Carbon::mixin(new class {\n     *   public function addMoon() {\n     *     return function () {\n     *       return $this->addDays(30);\n     *     };\n     *   }\n     *   public function subMoon() {\n     *     return function () {\n     *       return $this->subDays(30);\n     *     };\n     *   }\n     * });\n     * $fullMoon = Carbon::create('2018-12-22');\n     * $nextFullMoon = $fullMoon->addMoon();\n     * $blackMoon = Carbon::create('2019-01-06');\n     * $previousBlackMoon = $blackMoon->subMoon();\n     * echo \"$nextFullMoon\\n\";\n     * echo \"$previousBlackMoon\\n\";\n     * ```\n     *\n     * @param object|string $mixin\n     *\n     * @throws ReflectionException\n     *\n     * @return void\n     */\n    public static function mixin($mixin);\n\n    /**\n     * Calls \\DateTime::modify if mutable or \\DateTimeImmutable::modify else.\n     *\n     * @see https://php.net/manual/en/datetime.modify.php\n     *\n     * @return static|false\n     */\n    #[ReturnTypeWillChange]\n    public function modify($modify);\n\n    /**\n     * Determines if the instance is not equal to another\n     *\n     * @example\n     * ```\n     * Carbon::parse('2018-07-25 12:45:16')->ne('2018-07-25 12:45:16'); // false\n     * Carbon::parse('2018-07-25 12:45:16')->ne(Carbon::parse('2018-07-25 12:45:16')); // false\n     * Carbon::parse('2018-07-25 12:45:16')->ne('2018-07-25 12:45:17'); // true\n     * ```\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date\n     *\n     * @see notEqualTo()\n     *\n     * @return bool\n     */\n    public function ne($date): bool;\n\n    /**\n     * Modify to the next occurrence of a given modifier such as a day of\n     * the week. If no modifier is provided, modify to the next occurrence\n     * of the current day of the week. Use the supplied constants\n     * to indicate the desired dayOfWeek, ex. static::MONDAY.\n     *\n     * @param string|int|null $modifier\n     *\n     * @return static|false\n     */\n    public function next($modifier = null);\n\n    /**\n     * Go forward to the next weekday.\n     *\n     * @return static\n     */\n    public function nextWeekday();\n\n    /**\n     * Go forward to the next weekend day.\n     *\n     * @return static\n     */\n    public function nextWeekendDay();\n\n    /**\n     * Determines if the instance is not equal to another\n     *\n     * @example\n     * ```\n     * Carbon::parse('2018-07-25 12:45:16')->notEqualTo('2018-07-25 12:45:16'); // false\n     * Carbon::parse('2018-07-25 12:45:16')->notEqualTo(Carbon::parse('2018-07-25 12:45:16')); // false\n     * Carbon::parse('2018-07-25 12:45:16')->notEqualTo('2018-07-25 12:45:17'); // true\n     * ```\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date\n     *\n     * @return bool\n     */\n    public function notEqualTo($date): bool;\n\n    /**\n     * Get a Carbon instance for the current date and time.\n     *\n     * @param DateTimeZone|string|null $tz\n     *\n     * @return static\n     */\n    public static function now($tz = null);\n\n    /**\n     * Returns a present instance in the same timezone.\n     *\n     * @return static\n     */\n    public function nowWithSameTz();\n\n    /**\n     * Modify to the given occurrence of a given day of the week\n     * in the current month. If the calculated occurrence is outside the scope\n     * of the current month, then return false and no modifications are made.\n     * Use the supplied constants to indicate the desired dayOfWeek, ex. static::MONDAY.\n     *\n     * @param int $nth\n     * @param int $dayOfWeek\n     *\n     * @return mixed\n     */\n    public function nthOfMonth($nth, $dayOfWeek);\n\n    /**\n     * Modify to the given occurrence of a given day of the week\n     * in the current quarter. If the calculated occurrence is outside the scope\n     * of the current quarter, then return false and no modifications are made.\n     * Use the supplied constants to indicate the desired dayOfWeek, ex. static::MONDAY.\n     *\n     * @param int $nth\n     * @param int $dayOfWeek\n     *\n     * @return mixed\n     */\n    public function nthOfQuarter($nth, $dayOfWeek);\n\n    /**\n     * Modify to the given occurrence of a given day of the week\n     * in the current year. If the calculated occurrence is outside the scope\n     * of the current year, then return false and no modifications are made.\n     * Use the supplied constants to indicate the desired dayOfWeek, ex. static::MONDAY.\n     *\n     * @param int $nth\n     * @param int $dayOfWeek\n     *\n     * @return mixed\n     */\n    public function nthOfYear($nth, $dayOfWeek);\n\n    /**\n     * Return a property with its ordinal.\n     *\n     * @param string      $key\n     * @param string|null $period\n     *\n     * @return string\n     */\n    public function ordinal(string $key, ?string $period = null): string;\n\n    /**\n     * Create a carbon instance from a string.\n     *\n     * This is an alias for the constructor that allows better fluent syntax\n     * as it allows you to do Carbon::parse('Monday next week')->fn() rather\n     * than (new Carbon('Monday next week'))->fn().\n     *\n     * @param string|DateTimeInterface|null $time\n     * @param DateTimeZone|string|null      $tz\n     *\n     * @throws InvalidFormatException\n     *\n     * @return static\n     */\n    public static function parse($time = null, $tz = null);\n\n    /**\n     * Create a carbon instance from a localized string (in French, Japanese, Arabic, etc.).\n     *\n     * @param string                   $time   date/time string in the given language (may also contain English).\n     * @param string|null              $locale if locale is null or not specified, current global locale will be\n     *                                         used instead.\n     * @param DateTimeZone|string|null $tz     optional timezone for the new instance.\n     *\n     * @throws InvalidFormatException\n     *\n     * @return static\n     */\n    public static function parseFromLocale($time, $locale = null, $tz = null);\n\n    /**\n     * Returns standardized plural of a given singular/plural unit name (in English).\n     *\n     * @param string $unit\n     *\n     * @return string\n     */\n    public static function pluralUnit(string $unit): string;\n\n    /**\n     * Modify to the previous occurrence of a given modifier such as a day of\n     * the week. If no dayOfWeek is provided, modify to the previous occurrence\n     * of the current day of the week. Use the supplied constants\n     * to indicate the desired dayOfWeek, ex. static::MONDAY.\n     *\n     * @param string|int|null $modifier\n     *\n     * @return static|false\n     */\n    public function previous($modifier = null);\n\n    /**\n     * Go backward to the previous weekday.\n     *\n     * @return static\n     */\n    public function previousWeekday();\n\n    /**\n     * Go backward to the previous weekend day.\n     *\n     * @return static\n     */\n    public function previousWeekendDay();\n\n    /**\n     * Create a iterable CarbonPeriod object from current date to a given end date (and optional interval).\n     *\n     * @param \\DateTimeInterface|Carbon|CarbonImmutable|null $end      period end date\n     * @param int|\\DateInterval|string|null                  $interval period default interval or number of the given $unit\n     * @param string|null                                    $unit     if specified, $interval must be an integer\n     *\n     * @return CarbonPeriod\n     */\n    public function range($end = null, $interval = null, $unit = null);\n\n    /**\n     * Call native PHP DateTime/DateTimeImmutable add() method.\n     *\n     * @param DateInterval $interval\n     *\n     * @return static\n     */\n    public function rawAdd(DateInterval $interval);\n\n    /**\n     * Create a Carbon instance from a specific format.\n     *\n     * @param string                         $format Datetime format\n     * @param string                         $time\n     * @param DateTimeZone|string|false|null $tz\n     *\n     * @throws InvalidFormatException\n     *\n     * @return static|false\n     */\n    public static function rawCreateFromFormat($format, $time, $tz = null);\n\n    /**\n     * @see https://php.net/manual/en/datetime.format.php\n     *\n     * @param string $format\n     *\n     * @return string\n     */\n    public function rawFormat($format);\n\n    /**\n     * Create a carbon instance from a string.\n     *\n     * This is an alias for the constructor that allows better fluent syntax\n     * as it allows you to do Carbon::parse('Monday next week')->fn() rather\n     * than (new Carbon('Monday next week'))->fn().\n     *\n     * @param string|DateTimeInterface|null $time\n     * @param DateTimeZone|string|null      $tz\n     *\n     * @throws InvalidFormatException\n     *\n     * @return static\n     */\n    public static function rawParse($time = null, $tz = null);\n\n    /**\n     * Call native PHP DateTime/DateTimeImmutable sub() method.\n     *\n     * @param DateInterval $interval\n     *\n     * @return static\n     */\n    public function rawSub(DateInterval $interval);\n\n    /**\n     * Remove all macros and generic macros.\n     */\n    public static function resetMacros();\n\n    /**\n     * @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n     *             You should rather use the ->settings() method.\n     *             Or you can use method variants: addMonthsWithOverflow/addMonthsNoOverflow, same variants\n     *             are available for quarters, years, decade, centuries, millennia (singular and plural forms).\n     * @see settings\n     *\n     * Reset the month overflow behavior.\n     *\n     * @return void\n     */\n    public static function resetMonthsOverflow();\n\n    /**\n     * Reset the format used to the default when type juggling a Carbon instance to a string\n     *\n     * @return void\n     */\n    public static function resetToStringFormat();\n\n    /**\n     * @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n     *             You should rather use the ->settings() method.\n     *             Or you can use method variants: addYearsWithOverflow/addYearsNoOverflow, same variants\n     *             are available for quarters, years, decade, centuries, millennia (singular and plural forms).\n     * @see settings\n     *\n     * Reset the month overflow behavior.\n     *\n     * @return void\n     */\n    public static function resetYearsOverflow();\n\n    /**\n     * Round the current instance second with given precision if specified.\n     *\n     * @param float|int|string|\\DateInterval|null $precision\n     * @param string                              $function\n     *\n     * @return CarbonInterface\n     */\n    public function round($precision = 1, $function = 'round');\n\n    /**\n     * Round the current instance at the given unit with given precision if specified and the given function.\n     *\n     * @param string    $unit\n     * @param float|int $precision\n     * @param string    $function\n     *\n     * @return CarbonInterface\n     */\n    public function roundUnit($unit, $precision = 1, $function = 'round');\n\n    /**\n     * Round the current instance week.\n     *\n     * @param int $weekStartsAt optional start allow you to specify the day of week to use to start the week\n     *\n     * @return CarbonInterface\n     */\n    public function roundWeek($weekStartsAt = null);\n\n    /**\n     * The number of seconds since midnight.\n     *\n     * @return int\n     */\n    public function secondsSinceMidnight();\n\n    /**\n     * The number of seconds until 23:59:59.\n     *\n     * @return int\n     */\n    public function secondsUntilEndOfDay();\n\n    /**\n     * Return a serialized string of the instance.\n     *\n     * @return string\n     */\n    public function serialize();\n\n    /**\n     * @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n     *             You should rather transform Carbon object before the serialization.\n     *\n     * JSON serialize all Carbon instances using the given callback.\n     *\n     * @param callable $callback\n     *\n     * @return void\n     */\n    public static function serializeUsing($callback);\n\n    /**\n     * Set a part of the Carbon object\n     *\n     * @param string|array            $name\n     * @param string|int|DateTimeZone $value\n     *\n     * @throws ImmutableException|UnknownSetterException\n     *\n     * @return $this\n     */\n    public function set($name, $value = null);\n\n    /**\n     * Set the date with gregorian year, month and day numbers.\n     *\n     * @see https://php.net/manual/en/datetime.setdate.php\n     *\n     * @param int $year\n     * @param int $month\n     * @param int $day\n     *\n     * @return static\n     */\n    #[ReturnTypeWillChange]\n    public function setDate($year, $month, $day);\n\n    /**\n     * Set the year, month, and date for this instance to that of the passed instance.\n     *\n     * @param Carbon|DateTimeInterface $date now if null\n     *\n     * @return static\n     */\n    public function setDateFrom($date = null);\n\n    /**\n     * Set the date and time all together.\n     *\n     * @param int $year\n     * @param int $month\n     * @param int $day\n     * @param int $hour\n     * @param int $minute\n     * @param int $second\n     * @param int $microseconds\n     *\n     * @return static\n     */\n    public function setDateTime($year, $month, $day, $hour, $minute, $second = 0, $microseconds = 0);\n\n    /**\n     * Set the date and time for this instance to that of the passed instance.\n     *\n     * @param Carbon|DateTimeInterface $date\n     *\n     * @return static\n     */\n    public function setDateTimeFrom($date = null);\n\n    /**\n     * Set the day (keeping the current time) to the start of the week + the number of days passed as the first\n     * parameter. First day of week is driven by the locale unless explicitly set with the second parameter.\n     *\n     * @param int      $numberOfDays number of days to add after the start of the current week\n     * @param int|null $weekStartsAt optional start allow you to specify the day of week to use to start the week,\n     *                               if not provided, start of week is inferred from the locale\n     *                               (Sunday for en_US, Monday for de_DE, etc.)\n     *\n     * @return static\n     */\n    public function setDaysFromStartOfWeek(int $numberOfDays, ?int $weekStartsAt = null);\n\n    /**\n     * Set the fallback locale.\n     *\n     * @see https://symfony.com/doc/current/components/translation.html#fallback-locales\n     *\n     * @param string $locale\n     */\n    public static function setFallbackLocale($locale);\n\n    /**\n     * @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n     *             You should rather use the ->settings() method.\n     * @see settings\n     *\n     * @param int $humanDiffOptions\n     */\n    public static function setHumanDiffOptions($humanDiffOptions);\n\n    /**\n     * Set a date according to the ISO 8601 standard - using weeks and day offsets rather than specific dates.\n     *\n     * @see https://php.net/manual/en/datetime.setisodate.php\n     *\n     * @param int $year\n     * @param int $week\n     * @param int $day\n     *\n     * @return static\n     */\n    #[ReturnTypeWillChange]\n    public function setISODate($year, $week, $day = 1);\n\n    /**\n     * Set the translator for the current instance.\n     *\n     * @param \\Symfony\\Component\\Translation\\TranslatorInterface $translator\n     *\n     * @return $this\n     */\n    public function setLocalTranslator(TranslatorInterface $translator);\n\n    /**\n     * Set the current translator locale and indicate if the source locale file exists.\n     * Pass 'auto' as locale to use closest language from the current LC_TIME locale.\n     *\n     * @param string $locale locale ex. en\n     *\n     * @return bool\n     */\n    public static function setLocale($locale);\n\n    /**\n     * @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n     *             You should rather consider mid-day is always 12pm, then if you need to test if it's an other\n     *             hour, test it explicitly:\n     *                 $date->format('G') == 13\n     *             or to set explicitly to a given hour:\n     *                 $date->setTime(13, 0, 0, 0)\n     *\n     * Set midday/noon hour\n     *\n     * @param int $hour midday hour\n     *\n     * @return void\n     */\n    public static function setMidDayAt($hour);\n\n    /**\n     * Set a Carbon instance (real or mock) to be returned when a \"now\"\n     * instance is created.  The provided instance will be returned\n     * specifically under the following conditions:\n     *   - A call to the static now() method, ex. Carbon::now()\n     *   - When a null (or blank string) is passed to the constructor or parse(), ex. new Carbon(null)\n     *   - When the string \"now\" is passed to the constructor or parse(), ex. new Carbon('now')\n     *   - When a string containing the desired time is passed to Carbon::parse().\n     *\n     * Note the timezone parameter was left out of the examples above and\n     * has no affect as the mock value will be returned regardless of its value.\n     *\n     * Only the moment is mocked with setTestNow(), the timezone will still be the one passed\n     * as parameter of date_default_timezone_get() as a fallback (see setTestNowAndTimezone()).\n     *\n     * To clear the test instance call this method using the default\n     * parameter of null.\n     *\n     * /!\\ Use this method for unit tests only.\n     *\n     * @param DateTimeInterface|Closure|static|string|false|null $testNow real or mock Carbon instance\n     */\n    public static function setTestNow($testNow = null);\n\n    /**\n     * Set a Carbon instance (real or mock) to be returned when a \"now\"\n     * instance is created.  The provided instance will be returned\n     * specifically under the following conditions:\n     *   - A call to the static now() method, ex. Carbon::now()\n     *   - When a null (or blank string) is passed to the constructor or parse(), ex. new Carbon(null)\n     *   - When the string \"now\" is passed to the constructor or parse(), ex. new Carbon('now')\n     *   - When a string containing the desired time is passed to Carbon::parse().\n     *\n     * It will also align default timezone (e.g. call date_default_timezone_set()) with\n     * the second argument or if null, with the timezone of the given date object.\n     *\n     * To clear the test instance call this method using the default\n     * parameter of null.\n     *\n     * /!\\ Use this method for unit tests only.\n     *\n     * @param DateTimeInterface|Closure|static|string|false|null $testNow real or mock Carbon instance\n     */\n    public static function setTestNowAndTimezone($testNow = null, $tz = null);\n\n    /**\n     * Resets the current time of the DateTime object to a different time.\n     *\n     * @see https://php.net/manual/en/datetime.settime.php\n     *\n     * @param int $hour\n     * @param int $minute\n     * @param int $second\n     * @param int $microseconds\n     *\n     * @return static\n     */\n    #[ReturnTypeWillChange]\n    public function setTime($hour, $minute, $second = 0, $microseconds = 0);\n\n    /**\n     * Set the hour, minute, second and microseconds for this instance to that of the passed instance.\n     *\n     * @param Carbon|DateTimeInterface $date now if null\n     *\n     * @return static\n     */\n    public function setTimeFrom($date = null);\n\n    /**\n     * Set the time by time string.\n     *\n     * @param string $time\n     *\n     * @return static\n     */\n    public function setTimeFromTimeString($time);\n\n    /**\n     * Set the instance's timestamp.\n     *\n     * Timestamp input can be given as int, float or a string containing one or more numbers.\n     *\n     * @param float|int|string $unixTimestamp\n     *\n     * @return static\n     */\n    #[ReturnTypeWillChange]\n    public function setTimestamp($unixTimestamp);\n\n    /**\n     * Set the instance's timezone from a string or object.\n     *\n     * @param DateTimeZone|string $value\n     *\n     * @return static\n     */\n    #[ReturnTypeWillChange]\n    public function setTimezone($value);\n\n    /**\n     * @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n     *             You should rather let Carbon object being cast to string with DEFAULT_TO_STRING_FORMAT, and\n     *             use other method or custom format passed to format() method if you need to dump another string\n     *             format.\n     *\n     * Set the default format used when type juggling a Carbon instance to a string.\n     *\n     * @param string|Closure|null $format\n     *\n     * @return void\n     */\n    public static function setToStringFormat($format);\n\n    /**\n     * Set the default translator instance to use.\n     *\n     * @param \\Symfony\\Component\\Translation\\TranslatorInterface $translator\n     *\n     * @return void\n     */\n    public static function setTranslator(TranslatorInterface $translator);\n\n    /**\n     * Set specified unit to new given value.\n     *\n     * @param string $unit  year, month, day, hour, minute, second or microsecond\n     * @param int    $value new value for given unit\n     *\n     * @return static\n     */\n    public function setUnit($unit, $value = null);\n\n    /**\n     * Set any unit to a new value without overflowing current other unit given.\n     *\n     * @param string $valueUnit    unit name to modify\n     * @param int    $value        new value for the input unit\n     * @param string $overflowUnit unit name to not overflow\n     *\n     * @return static\n     */\n    public function setUnitNoOverflow($valueUnit, $value, $overflowUnit);\n\n    /**\n     * @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n     *             You should rather use UTF-8 language packages on every machine.\n     *\n     * Set if UTF8 will be used for localized date/time.\n     *\n     * @param bool $utf8\n     */\n    public static function setUtf8($utf8);\n\n    /**\n     * @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n     *             Use $weekStartsAt optional parameter instead when using startOfWeek, floorWeek, ceilWeek\n     *             or roundWeek method. You can also use the 'first_day_of_week' locale setting to change the\n     *             start of week according to current locale selected and implicitly the end of week.\n     *\n     * Set the last day of week\n     *\n     * @param int|string $day week end day (or 'auto' to get the day before the first day of week\n     *                        from Carbon::getLocale() culture).\n     *\n     * @return void\n     */\n    public static function setWeekEndsAt($day);\n\n    /**\n     * @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n     *             Use $weekEndsAt optional parameter instead when using endOfWeek method. You can also use the\n     *             'first_day_of_week' locale setting to change the start of week according to current locale\n     *             selected and implicitly the end of week.\n     *\n     * Set the first day of week\n     *\n     * @param int|string $day week start day (or 'auto' to get the first day of week from Carbon::getLocale() culture).\n     *\n     * @return void\n     */\n    public static function setWeekStartsAt($day);\n\n    /**\n     * @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n     *             You should rather consider week-end is always saturday and sunday, and if you have some custom\n     *             week-end days to handle, give to those days an other name and create a macro for them:\n     *\n     *             ```\n     *             Carbon::macro('isDayOff', function ($date) {\n     *                 return $date->isSunday() || $date->isMonday();\n     *             });\n     *             Carbon::macro('isNotDayOff', function ($date) {\n     *                 return !$date->isDayOff();\n     *             });\n     *             if ($someDate->isDayOff()) ...\n     *             if ($someDate->isNotDayOff()) ...\n     *             // Add 5 not-off days\n     *             $count = 5;\n     *             while ($someDate->isDayOff() || ($count-- > 0)) {\n     *                 $someDate->addDay();\n     *             }\n     *             ```\n     *\n     * Set weekend days\n     *\n     * @param array $days\n     *\n     * @return void\n     */\n    public static function setWeekendDays($days);\n\n    /**\n     * Set specific options.\n     *  - strictMode: true|false|null\n     *  - monthOverflow: true|false|null\n     *  - yearOverflow: true|false|null\n     *  - humanDiffOptions: int|null\n     *  - toStringFormat: string|Closure|null\n     *  - toJsonFormat: string|Closure|null\n     *  - locale: string|null\n     *  - timezone: \\DateTimeZone|string|int|null\n     *  - macros: array|null\n     *  - genericMacros: array|null\n     *\n     * @param array $settings\n     *\n     * @return $this|static\n     */\n    public function settings(array $settings);\n\n    /**\n     * Set the instance's timezone from a string or object and add/subtract the offset difference.\n     *\n     * @param DateTimeZone|string $value\n     *\n     * @return static\n     */\n    public function shiftTimezone($value);\n\n    /**\n     * Get the month overflow global behavior (can be overridden in specific instances).\n     *\n     * @return bool\n     */\n    public static function shouldOverflowMonths();\n\n    /**\n     * Get the month overflow global behavior (can be overridden in specific instances).\n     *\n     * @return bool\n     */\n    public static function shouldOverflowYears();\n\n    /**\n     * @alias diffForHumans\n     *\n     * Get the difference in a human readable format in the current locale from current instance to an other\n     * instance given (or now if null given).\n     */\n    public function since($other = null, $syntax = null, $short = false, $parts = 1, $options = null);\n\n    /**\n     * Returns standardized singular of a given singular/plural unit name (in English).\n     *\n     * @param string $unit\n     *\n     * @return string\n     */\n    public static function singularUnit(string $unit): string;\n\n    /**\n     * Modify to start of current given unit.\n     *\n     * @example\n     * ```\n     * echo Carbon::parse('2018-07-25 12:45:16.334455')\n     *   ->startOf('month')\n     *   ->endOf('week', Carbon::FRIDAY);\n     * ```\n     *\n     * @param string            $unit\n     * @param array<int, mixed> $params\n     *\n     * @return static\n     */\n    public function startOf($unit, ...$params);\n\n    /**\n     * Resets the date to the first day of the century and the time to 00:00:00\n     *\n     * @example\n     * ```\n     * echo Carbon::parse('2018-07-25 12:45:16')->startOfCentury();\n     * ```\n     *\n     * @return static\n     */\n    public function startOfCentury();\n\n    /**\n     * Resets the time to 00:00:00 start of day\n     *\n     * @example\n     * ```\n     * echo Carbon::parse('2018-07-25 12:45:16')->startOfDay();\n     * ```\n     *\n     * @return static\n     */\n    public function startOfDay();\n\n    /**\n     * Resets the date to the first day of the decade and the time to 00:00:00\n     *\n     * @example\n     * ```\n     * echo Carbon::parse('2018-07-25 12:45:16')->startOfDecade();\n     * ```\n     *\n     * @return static\n     */\n    public function startOfDecade();\n\n    /**\n     * Modify to start of current hour, minutes and seconds become 0\n     *\n     * @example\n     * ```\n     * echo Carbon::parse('2018-07-25 12:45:16')->startOfHour();\n     * ```\n     *\n     * @return static\n     */\n    public function startOfHour();\n\n    /**\n     * Resets the date to the first day of the millennium and the time to 00:00:00\n     *\n     * @example\n     * ```\n     * echo Carbon::parse('2018-07-25 12:45:16')->startOfMillennium();\n     * ```\n     *\n     * @return static\n     */\n    public function startOfMillennium();\n\n    /**\n     * Modify to start of current minute, seconds become 0\n     *\n     * @example\n     * ```\n     * echo Carbon::parse('2018-07-25 12:45:16')->startOfMinute();\n     * ```\n     *\n     * @return static\n     */\n    public function startOfMinute();\n\n    /**\n     * Resets the date to the first day of the month and the time to 00:00:00\n     *\n     * @example\n     * ```\n     * echo Carbon::parse('2018-07-25 12:45:16')->startOfMonth();\n     * ```\n     *\n     * @return static\n     */\n    public function startOfMonth();\n\n    /**\n     * Resets the date to the first day of the quarter and the time to 00:00:00\n     *\n     * @example\n     * ```\n     * echo Carbon::parse('2018-07-25 12:45:16')->startOfQuarter();\n     * ```\n     *\n     * @return static\n     */\n    public function startOfQuarter();\n\n    /**\n     * Modify to start of current second, microseconds become 0\n     *\n     * @example\n     * ```\n     * echo Carbon::parse('2018-07-25 12:45:16.334455')\n     *   ->startOfSecond()\n     *   ->format('H:i:s.u');\n     * ```\n     *\n     * @return static\n     */\n    public function startOfSecond();\n\n    /**\n     * Resets the date to the first day of week (defined in $weekStartsAt) and the time to 00:00:00\n     *\n     * @example\n     * ```\n     * echo Carbon::parse('2018-07-25 12:45:16')->startOfWeek() . \"\\n\";\n     * echo Carbon::parse('2018-07-25 12:45:16')->locale('ar')->startOfWeek() . \"\\n\";\n     * echo Carbon::parse('2018-07-25 12:45:16')->startOfWeek(Carbon::SUNDAY) . \"\\n\";\n     * ```\n     *\n     * @param int $weekStartsAt optional start allow you to specify the day of week to use to start the week\n     *\n     * @return static\n     */\n    public function startOfWeek($weekStartsAt = null);\n\n    /**\n     * Resets the date to the first day of the year and the time to 00:00:00\n     *\n     * @example\n     * ```\n     * echo Carbon::parse('2018-07-25 12:45:16')->startOfYear();\n     * ```\n     *\n     * @return static\n     */\n    public function startOfYear();\n\n    /**\n     * Subtract given units or interval to the current instance.\n     *\n     * @example $date->sub('hour', 3)\n     * @example $date->sub(15, 'days')\n     * @example $date->sub(CarbonInterval::days(4))\n     *\n     * @param string|DateInterval|Closure|CarbonConverterInterface $unit\n     * @param int                                                  $value\n     * @param bool|null                                            $overflow\n     *\n     * @return static\n     */\n    #[ReturnTypeWillChange]\n    public function sub($unit, $value = 1, $overflow = null);\n\n    public function subRealUnit($unit, $value = 1);\n\n    /**\n     * Subtract given units to the current instance.\n     *\n     * @param string    $unit\n     * @param int       $value\n     * @param bool|null $overflow\n     *\n     * @return static\n     */\n    public function subUnit($unit, $value = 1, $overflow = null);\n\n    /**\n     * Subtract any unit to a new value without overflowing current other unit given.\n     *\n     * @param string $valueUnit    unit name to modify\n     * @param int    $value        amount to subtract to the input unit\n     * @param string $overflowUnit unit name to not overflow\n     *\n     * @return static\n     */\n    public function subUnitNoOverflow($valueUnit, $value, $overflowUnit);\n\n    /**\n     * Subtract given units or interval to the current instance.\n     *\n     * @see sub()\n     *\n     * @param string|DateInterval $unit\n     * @param int                 $value\n     * @param bool|null           $overflow\n     *\n     * @return static\n     */\n    public function subtract($unit, $value = 1, $overflow = null);\n\n    /**\n     * Get the difference in a human readable format in the current locale from current instance to an other\n     * instance given (or now if null given).\n     *\n     * @return string\n     */\n    public function timespan($other = null, $timezone = null);\n\n    /**\n     * Set the instance's timestamp.\n     *\n     * Timestamp input can be given as int, float or a string containing one or more numbers.\n     *\n     * @param float|int|string $unixTimestamp\n     *\n     * @return static\n     */\n    public function timestamp($unixTimestamp);\n\n    /**\n     * @alias setTimezone\n     *\n     * @param DateTimeZone|string $value\n     *\n     * @return static\n     */\n    public function timezone($value);\n\n    /**\n     * Get the difference in a human readable format in the current locale from an other\n     * instance given (or now if null given) to current instance.\n     *\n     * When comparing a value in the past to default now:\n     * 1 hour from now\n     * 5 months from now\n     *\n     * When comparing a value in the future to default now:\n     * 1 hour ago\n     * 5 months ago\n     *\n     * When comparing a value in the past to another value:\n     * 1 hour after\n     * 5 months after\n     *\n     * When comparing a value in the future to another value:\n     * 1 hour before\n     * 5 months before\n     *\n     * @param Carbon|\\DateTimeInterface|string|array|null $other   if array passed, will be used as parameters array, see $syntax below;\n     *                                                             if null passed, now will be used as comparison reference;\n     *                                                             if any other type, it will be converted to date and used as reference.\n     * @param int|array                                   $syntax  if array passed, parameters will be extracted from it, the array may contains:\n     *                                                             - 'syntax' entry (see below)\n     *                                                             - 'short' entry (see below)\n     *                                                             - 'parts' entry (see below)\n     *                                                             - 'options' entry (see below)\n     *                                                             - 'join' entry determines how to join multiple parts of the string\n     *                                                             `  - if $join is a string, it's used as a joiner glue\n     *                                                             `  - if $join is a callable/closure, it get the list of string and should return a string\n     *                                                             `  - if $join is an array, the first item will be the default glue, and the second item\n     *                                                             `    will be used instead of the glue for the last item\n     *                                                             `  - if $join is true, it will be guessed from the locale ('list' translation file entry)\n     *                                                             `  - if $join is missing, a space will be used as glue\n     *                                                             - 'other' entry (see above)\n     *                                                             if int passed, it add modifiers:\n     *                                                             Possible values:\n     *                                                             - CarbonInterface::DIFF_ABSOLUTE          no modifiers\n     *                                                             - CarbonInterface::DIFF_RELATIVE_TO_NOW   add ago/from now modifier\n     *                                                             - CarbonInterface::DIFF_RELATIVE_TO_OTHER add before/after modifier\n     *                                                             Default value: CarbonInterface::DIFF_ABSOLUTE\n     * @param bool                                        $short   displays short format of time units\n     * @param int                                         $parts   maximum number of parts to display (default value: 1: single unit)\n     * @param int                                         $options human diff options\n     *\n     * @return string\n     */\n    public function to($other = null, $syntax = null, $short = false, $parts = 1, $options = null);\n\n    /**\n     * Get default array representation.\n     *\n     * @example\n     * ```\n     * var_dump(Carbon::now()->toArray());\n     * ```\n     *\n     * @return array\n     */\n    public function toArray();\n\n    /**\n     * Format the instance as ATOM\n     *\n     * @example\n     * ```\n     * echo Carbon::now()->toAtomString();\n     * ```\n     *\n     * @return string\n     */\n    public function toAtomString();\n\n    /**\n     * Format the instance as COOKIE\n     *\n     * @example\n     * ```\n     * echo Carbon::now()->toCookieString();\n     * ```\n     *\n     * @return string\n     */\n    public function toCookieString();\n\n    /**\n     * @alias toDateTime\n     *\n     * Return native DateTime PHP object matching the current instance.\n     *\n     * @example\n     * ```\n     * var_dump(Carbon::now()->toDate());\n     * ```\n     *\n     * @return DateTime\n     */\n    public function toDate();\n\n    /**\n     * Format the instance as date\n     *\n     * @example\n     * ```\n     * echo Carbon::now()->toDateString();\n     * ```\n     *\n     * @return string\n     */\n    public function toDateString();\n\n    /**\n     * Return native DateTime PHP object matching the current instance.\n     *\n     * @example\n     * ```\n     * var_dump(Carbon::now()->toDateTime());\n     * ```\n     *\n     * @return DateTime\n     */\n    public function toDateTime();\n\n    /**\n     * Return native toDateTimeImmutable PHP object matching the current instance.\n     *\n     * @example\n     * ```\n     * var_dump(Carbon::now()->toDateTimeImmutable());\n     * ```\n     *\n     * @return DateTimeImmutable\n     */\n    public function toDateTimeImmutable();\n\n    /**\n     * Format the instance as date and time T-separated with no timezone\n     *\n     * @example\n     * ```\n     * echo Carbon::now()->toDateTimeLocalString();\n     * echo \"\\n\";\n     * echo Carbon::now()->toDateTimeLocalString('minute'); // You can specify precision among: minute, second, millisecond and microsecond\n     * ```\n     *\n     * @param string $unitPrecision\n     *\n     * @return string\n     */\n    public function toDateTimeLocalString($unitPrecision = 'second');\n\n    /**\n     * Format the instance as date and time\n     *\n     * @example\n     * ```\n     * echo Carbon::now()->toDateTimeString();\n     * ```\n     *\n     * @param string $unitPrecision\n     *\n     * @return string\n     */\n    public function toDateTimeString($unitPrecision = 'second');\n\n    /**\n     * Format the instance with day, date and time\n     *\n     * @example\n     * ```\n     * echo Carbon::now()->toDayDateTimeString();\n     * ```\n     *\n     * @return string\n     */\n    public function toDayDateTimeString();\n\n    /**\n     * Format the instance as a readable date\n     *\n     * @example\n     * ```\n     * echo Carbon::now()->toFormattedDateString();\n     * ```\n     *\n     * @return string\n     */\n    public function toFormattedDateString();\n\n    /**\n     * Format the instance with the day, and a readable date\n     *\n     * @example\n     * ```\n     * echo Carbon::now()->toFormattedDayDateString();\n     * ```\n     *\n     * @return string\n     */\n    public function toFormattedDayDateString(): string;\n\n    /**\n     * Return the ISO-8601 string (ex: 1977-04-22T06:00:00Z, if $keepOffset truthy, offset will be kept:\n     * 1977-04-22T01:00:00-05:00).\n     *\n     * @example\n     * ```\n     * echo Carbon::now('America/Toronto')->toISOString() . \"\\n\";\n     * echo Carbon::now('America/Toronto')->toISOString(true) . \"\\n\";\n     * ```\n     *\n     * @param bool $keepOffset Pass true to keep the date offset. Else forced to UTC.\n     *\n     * @return null|string\n     */\n    public function toISOString($keepOffset = false);\n\n    /**\n     * Return a immutable copy of the instance.\n     *\n     * @return CarbonImmutable\n     */\n    public function toImmutable();\n\n    /**\n     * Format the instance as ISO8601\n     *\n     * @example\n     * ```\n     * echo Carbon::now()->toIso8601String();\n     * ```\n     *\n     * @return string\n     */\n    public function toIso8601String();\n\n    /**\n     * Convert the instance to UTC and return as Zulu ISO8601\n     *\n     * @example\n     * ```\n     * echo Carbon::now()->toIso8601ZuluString();\n     * ```\n     *\n     * @param string $unitPrecision\n     *\n     * @return string\n     */\n    public function toIso8601ZuluString($unitPrecision = 'second');\n\n    /**\n     * Return the ISO-8601 string (ex: 1977-04-22T06:00:00Z) with UTC timezone.\n     *\n     * @example\n     * ```\n     * echo Carbon::now('America/Toronto')->toJSON();\n     * ```\n     *\n     * @return null|string\n     */\n    public function toJSON();\n\n    /**\n     * Return a mutable copy of the instance.\n     *\n     * @return Carbon\n     */\n    public function toMutable();\n\n    /**\n     * Get the difference in a human readable format in the current locale from an other\n     * instance given to now\n     *\n     * @param int|array $syntax  if array passed, parameters will be extracted from it, the array may contains:\n     *                           - 'syntax' entry (see below)\n     *                           - 'short' entry (see below)\n     *                           - 'parts' entry (see below)\n     *                           - 'options' entry (see below)\n     *                           - 'join' entry determines how to join multiple parts of the string\n     *                           `  - if $join is a string, it's used as a joiner glue\n     *                           `  - if $join is a callable/closure, it get the list of string and should return a string\n     *                           `  - if $join is an array, the first item will be the default glue, and the second item\n     *                           `    will be used instead of the glue for the last item\n     *                           `  - if $join is true, it will be guessed from the locale ('list' translation file entry)\n     *                           `  - if $join is missing, a space will be used as glue\n     *                           if int passed, it add modifiers:\n     *                           Possible values:\n     *                           - CarbonInterface::DIFF_ABSOLUTE          no modifiers\n     *                           - CarbonInterface::DIFF_RELATIVE_TO_NOW   add ago/from now modifier\n     *                           - CarbonInterface::DIFF_RELATIVE_TO_OTHER add before/after modifier\n     *                           Default value: CarbonInterface::DIFF_ABSOLUTE\n     * @param bool      $short   displays short format of time units\n     * @param int       $parts   maximum number of parts to display (default value: 1: single part)\n     * @param int       $options human diff options\n     *\n     * @return string\n     */\n    public function toNow($syntax = null, $short = false, $parts = 1, $options = null);\n\n    /**\n     * Get default object representation.\n     *\n     * @example\n     * ```\n     * var_dump(Carbon::now()->toObject());\n     * ```\n     *\n     * @return object\n     */\n    public function toObject();\n\n    /**\n     * Create a iterable CarbonPeriod object from current date to a given end date (and optional interval).\n     *\n     * @param \\DateTimeInterface|Carbon|CarbonImmutable|int|null $end      period end date or recurrences count if int\n     * @param int|\\DateInterval|string|null                      $interval period default interval or number of the given $unit\n     * @param string|null                                        $unit     if specified, $interval must be an integer\n     *\n     * @return CarbonPeriod\n     */\n    public function toPeriod($end = null, $interval = null, $unit = null);\n\n    /**\n     * Format the instance as RFC1036\n     *\n     * @example\n     * ```\n     * echo Carbon::now()->toRfc1036String();\n     * ```\n     *\n     * @return string\n     */\n    public function toRfc1036String();\n\n    /**\n     * Format the instance as RFC1123\n     *\n     * @example\n     * ```\n     * echo Carbon::now()->toRfc1123String();\n     * ```\n     *\n     * @return string\n     */\n    public function toRfc1123String();\n\n    /**\n     * Format the instance as RFC2822\n     *\n     * @example\n     * ```\n     * echo Carbon::now()->toRfc2822String();\n     * ```\n     *\n     * @return string\n     */\n    public function toRfc2822String();\n\n    /**\n     * Format the instance as RFC3339\n     *\n     * @param bool $extended\n     *\n     * @example\n     * ```\n     * echo Carbon::now()->toRfc3339String() . \"\\n\";\n     * echo Carbon::now()->toRfc3339String(true) . \"\\n\";\n     * ```\n     *\n     * @return string\n     */\n    public function toRfc3339String($extended = false);\n\n    /**\n     * Format the instance as RFC7231\n     *\n     * @example\n     * ```\n     * echo Carbon::now()->toRfc7231String();\n     * ```\n     *\n     * @return string\n     */\n    public function toRfc7231String();\n\n    /**\n     * Format the instance as RFC822\n     *\n     * @example\n     * ```\n     * echo Carbon::now()->toRfc822String();\n     * ```\n     *\n     * @return string\n     */\n    public function toRfc822String();\n\n    /**\n     * Format the instance as RFC850\n     *\n     * @example\n     * ```\n     * echo Carbon::now()->toRfc850String();\n     * ```\n     *\n     * @return string\n     */\n    public function toRfc850String();\n\n    /**\n     * Format the instance as RSS\n     *\n     * @example\n     * ```\n     * echo Carbon::now()->toRssString();\n     * ```\n     *\n     * @return string\n     */\n    public function toRssString();\n\n    /**\n     * Returns english human readable complete date string.\n     *\n     * @example\n     * ```\n     * echo Carbon::now()->toString();\n     * ```\n     *\n     * @return string\n     */\n    public function toString();\n\n    /**\n     * Format the instance as time\n     *\n     * @example\n     * ```\n     * echo Carbon::now()->toTimeString();\n     * ```\n     *\n     * @param string $unitPrecision\n     *\n     * @return string\n     */\n    public function toTimeString($unitPrecision = 'second');\n\n    /**\n     * Format the instance as W3C\n     *\n     * @example\n     * ```\n     * echo Carbon::now()->toW3cString();\n     * ```\n     *\n     * @return string\n     */\n    public function toW3cString();\n\n    /**\n     * Create a Carbon instance for today.\n     *\n     * @param DateTimeZone|string|null $tz\n     *\n     * @return static\n     */\n    public static function today($tz = null);\n\n    /**\n     * Create a Carbon instance for tomorrow.\n     *\n     * @param DateTimeZone|string|null $tz\n     *\n     * @return static\n     */\n    public static function tomorrow($tz = null);\n\n    /**\n     * Translate using translation string or callback available.\n     *\n     * @param string                                                  $key\n     * @param array                                                   $parameters\n     * @param string|int|float|null                                   $number\n     * @param \\Symfony\\Component\\Translation\\TranslatorInterface|null $translator\n     * @param bool                                                    $altNumbers\n     *\n     * @return string\n     */\n    public function translate(string $key, array $parameters = [], $number = null, ?TranslatorInterface $translator = null, bool $altNumbers = false): string;\n\n    /**\n     * Returns the alternative number for a given integer if available in the current locale.\n     *\n     * @param int $number\n     *\n     * @return string\n     */\n    public function translateNumber(int $number): string;\n\n    /**\n     * Translate a time string from a locale to an other.\n     *\n     * @param string      $timeString date/time/duration string to translate (may also contain English)\n     * @param string|null $from       input locale of the $timeString parameter (`Carbon::getLocale()` by default)\n     * @param string|null $to         output locale of the result returned (`\"en\"` by default)\n     * @param int         $mode       specify what to translate with options:\n     *                                - self::TRANSLATE_ALL (default)\n     *                                - CarbonInterface::TRANSLATE_MONTHS\n     *                                - CarbonInterface::TRANSLATE_DAYS\n     *                                - CarbonInterface::TRANSLATE_UNITS\n     *                                - CarbonInterface::TRANSLATE_MERIDIEM\n     *                                You can use pipe to group: CarbonInterface::TRANSLATE_MONTHS | CarbonInterface::TRANSLATE_DAYS\n     *\n     * @return string\n     */\n    public static function translateTimeString($timeString, $from = null, $to = null, $mode = self::TRANSLATE_ALL);\n\n    /**\n     * Translate a time string from the current locale (`$date->locale()`) to an other.\n     *\n     * @param string      $timeString time string to translate\n     * @param string|null $to         output locale of the result returned (\"en\" by default)\n     *\n     * @return string\n     */\n    public function translateTimeStringTo($timeString, $to = null);\n\n    /**\n     * Translate using translation string or callback available.\n     *\n     * @param \\Symfony\\Component\\Translation\\TranslatorInterface $translator\n     * @param string                                             $key\n     * @param array                                              $parameters\n     * @param null                                               $number\n     *\n     * @return string\n     */\n    public static function translateWith(TranslatorInterface $translator, string $key, array $parameters = [], $number = null): string;\n\n    /**\n     * Format as ->format() do (using date replacements patterns from https://php.net/manual/en/function.date.php)\n     * but translate words whenever possible (months, day names, etc.) using the current locale.\n     *\n     * @param string $format\n     *\n     * @return string\n     */\n    public function translatedFormat(string $format): string;\n\n    /**\n     * Set the timezone or returns the timezone name if no arguments passed.\n     *\n     * @param DateTimeZone|string $value\n     *\n     * @return static|string\n     */\n    public function tz($value = null);\n\n    /**\n     * @alias getTimestamp\n     *\n     * Returns the UNIX timestamp for the current date.\n     *\n     * @return int\n     */\n    public function unix();\n\n    /**\n     * @alias to\n     *\n     * Get the difference in a human readable format in the current locale from an other\n     * instance given (or now if null given) to current instance.\n     *\n     * @param Carbon|\\DateTimeInterface|string|array|null $other   if array passed, will be used as parameters array, see $syntax below;\n     *                                                             if null passed, now will be used as comparison reference;\n     *                                                             if any other type, it will be converted to date and used as reference.\n     * @param int|array                                   $syntax  if array passed, parameters will be extracted from it, the array may contains:\n     *                                                             - 'syntax' entry (see below)\n     *                                                             - 'short' entry (see below)\n     *                                                             - 'parts' entry (see below)\n     *                                                             - 'options' entry (see below)\n     *                                                             - 'join' entry determines how to join multiple parts of the string\n     *                                                             `  - if $join is a string, it's used as a joiner glue\n     *                                                             `  - if $join is a callable/closure, it get the list of string and should return a string\n     *                                                             `  - if $join is an array, the first item will be the default glue, and the second item\n     *                                                             `    will be used instead of the glue for the last item\n     *                                                             `  - if $join is true, it will be guessed from the locale ('list' translation file entry)\n     *                                                             `  - if $join is missing, a space will be used as glue\n     *                                                             - 'other' entry (see above)\n     *                                                             if int passed, it add modifiers:\n     *                                                             Possible values:\n     *                                                             - CarbonInterface::DIFF_ABSOLUTE          no modifiers\n     *                                                             - CarbonInterface::DIFF_RELATIVE_TO_NOW   add ago/from now modifier\n     *                                                             - CarbonInterface::DIFF_RELATIVE_TO_OTHER add before/after modifier\n     *                                                             Default value: CarbonInterface::DIFF_ABSOLUTE\n     * @param bool                                        $short   displays short format of time units\n     * @param int                                         $parts   maximum number of parts to display (default value: 1: single unit)\n     * @param int                                         $options human diff options\n     *\n     * @return string\n     */\n    public function until($other = null, $syntax = null, $short = false, $parts = 1, $options = null);\n\n    /**\n     * @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n     *             You should rather use the ->settings() method.\n     *             Or you can use method variants: addMonthsWithOverflow/addMonthsNoOverflow, same variants\n     *             are available for quarters, years, decade, centuries, millennia (singular and plural forms).\n     * @see settings\n     *\n     * Indicates if months should be calculated with overflow.\n     *\n     * @param bool $monthsOverflow\n     *\n     * @return void\n     */\n    public static function useMonthsOverflow($monthsOverflow = true);\n\n    /**\n     * @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n     *             You should rather use the ->settings() method.\n     * @see settings\n     *\n     * Enable the strict mode (or disable with passing false).\n     *\n     * @param bool $strictModeEnabled\n     */\n    public static function useStrictMode($strictModeEnabled = true);\n\n    /**\n     * @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n     *             You should rather use the ->settings() method.\n     *             Or you can use method variants: addYearsWithOverflow/addYearsNoOverflow, same variants\n     *             are available for quarters, years, decade, centuries, millennia (singular and plural forms).\n     * @see settings\n     *\n     * Indicates if years should be calculated with overflow.\n     *\n     * @param bool $yearsOverflow\n     *\n     * @return void\n     */\n    public static function useYearsOverflow($yearsOverflow = true);\n\n    /**\n     * Set the instance's timezone to UTC.\n     *\n     * @return static\n     */\n    public function utc();\n\n    /**\n     * Returns the minutes offset to UTC if no arguments passed, else set the timezone with given minutes shift passed.\n     *\n     * @param int|null $minuteOffset\n     *\n     * @return int|static\n     */\n    public function utcOffset(?int $minuteOffset = null);\n\n    /**\n     * Returns the milliseconds timestamps used amongst other by Date javascript objects.\n     *\n     * @return float\n     */\n    public function valueOf();\n\n    /**\n     * Get/set the week number using given first day of week and first\n     * day of year included in the first week. Or use US format if no settings\n     * given (Sunday / Jan 6).\n     *\n     * @param int|null $week\n     * @param int|null $dayOfWeek\n     * @param int|null $dayOfYear\n     *\n     * @return int|static\n     */\n    public function week($week = null, $dayOfWeek = null, $dayOfYear = null);\n\n    /**\n     * Set/get the week number of year using given first day of week and first\n     * day of year included in the first week. Or use US format if no settings\n     * given (Sunday / Jan 6).\n     *\n     * @param int|null $year      if null, act as a getter, if not null, set the year and return current instance.\n     * @param int|null $dayOfWeek first date of week from 0 (Sunday) to 6 (Saturday)\n     * @param int|null $dayOfYear first day of year included in the week #1\n     *\n     * @return int|static\n     */\n    public function weekYear($year = null, $dayOfWeek = null, $dayOfYear = null);\n\n    /**\n     * Get/set the weekday from 0 (Sunday) to 6 (Saturday).\n     *\n     * @param int|null $value new value for weekday if using as setter.\n     *\n     * @return static|int\n     */\n    public function weekday($value = null);\n\n    /**\n     * Get the number of weeks of the current week-year using given first day of week and first\n     * day of year included in the first week. Or use US format if no settings\n     * given (Sunday / Jan 6).\n     *\n     * @param int|null $dayOfWeek first date of week from 0 (Sunday) to 6 (Saturday)\n     * @param int|null $dayOfYear first day of year included in the week #1\n     *\n     * @return int\n     */\n    public function weeksInYear($dayOfWeek = null, $dayOfYear = null);\n\n    /**\n     * Temporarily sets a static date to be used within the callback.\n     * Using setTestNow to set the date, executing the callback, then\n     * clearing the test instance.\n     *\n     * /!\\ Use this method for unit tests only.\n     *\n     * @template T\n     *\n     * @param DateTimeInterface|Closure|static|string|false|null $testNow  real or mock Carbon instance\n     * @param Closure(): T                                       $callback\n     *\n     * @return T\n     */\n    public static function withTestNow($testNow, $callback);\n\n    /**\n     * Create a Carbon instance for yesterday.\n     *\n     * @param DateTimeZone|string|null $tz\n     *\n     * @return static\n     */\n    public static function yesterday($tz = null);\n\n    // </methods>\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/CarbonInterval.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon;\n\nuse Carbon\\Exceptions\\BadFluentConstructorException;\nuse Carbon\\Exceptions\\BadFluentSetterException;\nuse Carbon\\Exceptions\\InvalidCastException;\nuse Carbon\\Exceptions\\InvalidIntervalException;\nuse Carbon\\Exceptions\\OutOfRangeException;\nuse Carbon\\Exceptions\\ParseErrorException;\nuse Carbon\\Exceptions\\UnitNotConfiguredException;\nuse Carbon\\Exceptions\\UnknownGetterException;\nuse Carbon\\Exceptions\\UnknownSetterException;\nuse Carbon\\Exceptions\\UnknownUnitException;\nuse Carbon\\Traits\\IntervalRounding;\nuse Carbon\\Traits\\IntervalStep;\nuse Carbon\\Traits\\MagicParameter;\nuse Carbon\\Traits\\Mixin;\nuse Carbon\\Traits\\Options;\nuse Carbon\\Traits\\ToStringFormat;\nuse Closure;\nuse DateInterval;\nuse DateMalformedIntervalStringException;\nuse DateTimeInterface;\nuse DateTimeZone;\nuse Exception;\nuse InvalidArgumentException;\nuse ReflectionException;\nuse ReturnTypeWillChange;\nuse RuntimeException;\nuse Throwable;\n\n/**\n * A simple API extension for DateInterval.\n * The implementation provides helpers to handle weeks but only days are saved.\n * Weeks are calculated based on the total days of the current instance.\n *\n * @property int $years Total years of the current interval.\n * @property int $months Total months of the current interval.\n * @property int $weeks Total weeks of the current interval calculated from the days.\n * @property int $dayz Total days of the current interval (weeks * 7 + days).\n * @property int $hours Total hours of the current interval.\n * @property int $minutes Total minutes of the current interval.\n * @property int $seconds Total seconds of the current interval.\n * @property int $microseconds Total microseconds of the current interval.\n * @property int $milliseconds Total milliseconds of the current interval.\n * @property int $microExcludeMilli Remaining microseconds without the milliseconds.\n * @property int $dayzExcludeWeeks Total days remaining in the final week of the current instance (days % 7).\n * @property int $daysExcludeWeeks alias of dayzExcludeWeeks\n * @property-read float $totalYears Number of years equivalent to the interval.\n * @property-read float $totalMonths Number of months equivalent to the interval.\n * @property-read float $totalWeeks Number of weeks equivalent to the interval.\n * @property-read float $totalDays Number of days equivalent to the interval.\n * @property-read float $totalDayz Alias for totalDays.\n * @property-read float $totalHours Number of hours equivalent to the interval.\n * @property-read float $totalMinutes Number of minutes equivalent to the interval.\n * @property-read float $totalSeconds Number of seconds equivalent to the interval.\n * @property-read float $totalMilliseconds Number of milliseconds equivalent to the interval.\n * @property-read float $totalMicroseconds Number of microseconds equivalent to the interval.\n * @property-read string $locale locale of the current instance\n *\n * @method static CarbonInterval years($years = 1) Create instance specifying a number of years or modify the number of years if called on an instance.\n * @method static CarbonInterval year($years = 1) Alias for years()\n * @method static CarbonInterval months($months = 1) Create instance specifying a number of months or modify the number of months if called on an instance.\n * @method static CarbonInterval month($months = 1) Alias for months()\n * @method static CarbonInterval weeks($weeks = 1) Create instance specifying a number of weeks or modify the number of weeks if called on an instance.\n * @method static CarbonInterval week($weeks = 1) Alias for weeks()\n * @method static CarbonInterval days($days = 1) Create instance specifying a number of days or modify the number of days if called on an instance.\n * @method static CarbonInterval dayz($days = 1) Alias for days()\n * @method static CarbonInterval daysExcludeWeeks($days = 1) Create instance specifying a number of days or modify the number of days (keeping the current number of weeks) if called on an instance.\n * @method static CarbonInterval dayzExcludeWeeks($days = 1) Alias for daysExcludeWeeks()\n * @method static CarbonInterval day($days = 1) Alias for days()\n * @method static CarbonInterval hours($hours = 1) Create instance specifying a number of hours or modify the number of hours if called on an instance.\n * @method static CarbonInterval hour($hours = 1) Alias for hours()\n * @method static CarbonInterval minutes($minutes = 1) Create instance specifying a number of minutes or modify the number of minutes if called on an instance.\n * @method static CarbonInterval minute($minutes = 1) Alias for minutes()\n * @method static CarbonInterval seconds($seconds = 1) Create instance specifying a number of seconds or modify the number of seconds if called on an instance.\n * @method static CarbonInterval second($seconds = 1) Alias for seconds()\n * @method static CarbonInterval milliseconds($milliseconds = 1) Create instance specifying a number of milliseconds or modify the number of milliseconds if called on an instance.\n * @method static CarbonInterval millisecond($milliseconds = 1) Alias for milliseconds()\n * @method static CarbonInterval microseconds($microseconds = 1) Create instance specifying a number of microseconds or modify the number of microseconds if called on an instance.\n * @method static CarbonInterval microsecond($microseconds = 1) Alias for microseconds()\n * @method $this addYears(int $years) Add given number of years to the current interval\n * @method $this subYears(int $years) Subtract given number of years to the current interval\n * @method $this addMonths(int $months) Add given number of months to the current interval\n * @method $this subMonths(int $months) Subtract given number of months to the current interval\n * @method $this addWeeks(int|float $weeks) Add given number of weeks to the current interval\n * @method $this subWeeks(int|float $weeks) Subtract given number of weeks to the current interval\n * @method $this addDays(int|float $days) Add given number of days to the current interval\n * @method $this subDays(int|float $days) Subtract given number of days to the current interval\n * @method $this addHours(int|float $hours) Add given number of hours to the current interval\n * @method $this subHours(int|float $hours) Subtract given number of hours to the current interval\n * @method $this addMinutes(int|float $minutes) Add given number of minutes to the current interval\n * @method $this subMinutes(int|float $minutes) Subtract given number of minutes to the current interval\n * @method $this addSeconds(int|float $seconds) Add given number of seconds to the current interval\n * @method $this subSeconds(int|float $seconds) Subtract given number of seconds to the current interval\n * @method $this addMilliseconds(int|float $milliseconds) Add given number of milliseconds to the current interval\n * @method $this subMilliseconds(int|float $milliseconds) Subtract given number of milliseconds to the current interval\n * @method $this addMicroseconds(int|float $microseconds) Add given number of microseconds to the current interval\n * @method $this subMicroseconds(int|float $microseconds) Subtract given number of microseconds to the current interval\n * @method $this roundYear(int|float $precision = 1, string $function = \"round\") Round the current instance year with given precision using the given function.\n * @method $this roundYears(int|float $precision = 1, string $function = \"round\") Round the current instance year with given precision using the given function.\n * @method $this floorYear(int|float $precision = 1) Truncate the current instance year with given precision.\n * @method $this floorYears(int|float $precision = 1) Truncate the current instance year with given precision.\n * @method $this ceilYear(int|float $precision = 1) Ceil the current instance year with given precision.\n * @method $this ceilYears(int|float $precision = 1) Ceil the current instance year with given precision.\n * @method $this roundMonth(int|float $precision = 1, string $function = \"round\") Round the current instance month with given precision using the given function.\n * @method $this roundMonths(int|float $precision = 1, string $function = \"round\") Round the current instance month with given precision using the given function.\n * @method $this floorMonth(int|float $precision = 1) Truncate the current instance month with given precision.\n * @method $this floorMonths(int|float $precision = 1) Truncate the current instance month with given precision.\n * @method $this ceilMonth(int|float $precision = 1) Ceil the current instance month with given precision.\n * @method $this ceilMonths(int|float $precision = 1) Ceil the current instance month with given precision.\n * @method $this roundWeek(int|float $precision = 1, string $function = \"round\") Round the current instance day with given precision using the given function.\n * @method $this roundWeeks(int|float $precision = 1, string $function = \"round\") Round the current instance day with given precision using the given function.\n * @method $this floorWeek(int|float $precision = 1) Truncate the current instance day with given precision.\n * @method $this floorWeeks(int|float $precision = 1) Truncate the current instance day with given precision.\n * @method $this ceilWeek(int|float $precision = 1) Ceil the current instance day with given precision.\n * @method $this ceilWeeks(int|float $precision = 1) Ceil the current instance day with given precision.\n * @method $this roundDay(int|float $precision = 1, string $function = \"round\") Round the current instance day with given precision using the given function.\n * @method $this roundDays(int|float $precision = 1, string $function = \"round\") Round the current instance day with given precision using the given function.\n * @method $this floorDay(int|float $precision = 1) Truncate the current instance day with given precision.\n * @method $this floorDays(int|float $precision = 1) Truncate the current instance day with given precision.\n * @method $this ceilDay(int|float $precision = 1) Ceil the current instance day with given precision.\n * @method $this ceilDays(int|float $precision = 1) Ceil the current instance day with given precision.\n * @method $this roundHour(int|float $precision = 1, string $function = \"round\") Round the current instance hour with given precision using the given function.\n * @method $this roundHours(int|float $precision = 1, string $function = \"round\") Round the current instance hour with given precision using the given function.\n * @method $this floorHour(int|float $precision = 1) Truncate the current instance hour with given precision.\n * @method $this floorHours(int|float $precision = 1) Truncate the current instance hour with given precision.\n * @method $this ceilHour(int|float $precision = 1) Ceil the current instance hour with given precision.\n * @method $this ceilHours(int|float $precision = 1) Ceil the current instance hour with given precision.\n * @method $this roundMinute(int|float $precision = 1, string $function = \"round\") Round the current instance minute with given precision using the given function.\n * @method $this roundMinutes(int|float $precision = 1, string $function = \"round\") Round the current instance minute with given precision using the given function.\n * @method $this floorMinute(int|float $precision = 1) Truncate the current instance minute with given precision.\n * @method $this floorMinutes(int|float $precision = 1) Truncate the current instance minute with given precision.\n * @method $this ceilMinute(int|float $precision = 1) Ceil the current instance minute with given precision.\n * @method $this ceilMinutes(int|float $precision = 1) Ceil the current instance minute with given precision.\n * @method $this roundSecond(int|float $precision = 1, string $function = \"round\") Round the current instance second with given precision using the given function.\n * @method $this roundSeconds(int|float $precision = 1, string $function = \"round\") Round the current instance second with given precision using the given function.\n * @method $this floorSecond(int|float $precision = 1) Truncate the current instance second with given precision.\n * @method $this floorSeconds(int|float $precision = 1) Truncate the current instance second with given precision.\n * @method $this ceilSecond(int|float $precision = 1) Ceil the current instance second with given precision.\n * @method $this ceilSeconds(int|float $precision = 1) Ceil the current instance second with given precision.\n * @method $this roundMillennium(int|float $precision = 1, string $function = \"round\") Round the current instance millennium with given precision using the given function.\n * @method $this roundMillennia(int|float $precision = 1, string $function = \"round\") Round the current instance millennium with given precision using the given function.\n * @method $this floorMillennium(int|float $precision = 1) Truncate the current instance millennium with given precision.\n * @method $this floorMillennia(int|float $precision = 1) Truncate the current instance millennium with given precision.\n * @method $this ceilMillennium(int|float $precision = 1) Ceil the current instance millennium with given precision.\n * @method $this ceilMillennia(int|float $precision = 1) Ceil the current instance millennium with given precision.\n * @method $this roundCentury(int|float $precision = 1, string $function = \"round\") Round the current instance century with given precision using the given function.\n * @method $this roundCenturies(int|float $precision = 1, string $function = \"round\") Round the current instance century with given precision using the given function.\n * @method $this floorCentury(int|float $precision = 1) Truncate the current instance century with given precision.\n * @method $this floorCenturies(int|float $precision = 1) Truncate the current instance century with given precision.\n * @method $this ceilCentury(int|float $precision = 1) Ceil the current instance century with given precision.\n * @method $this ceilCenturies(int|float $precision = 1) Ceil the current instance century with given precision.\n * @method $this roundDecade(int|float $precision = 1, string $function = \"round\") Round the current instance decade with given precision using the given function.\n * @method $this roundDecades(int|float $precision = 1, string $function = \"round\") Round the current instance decade with given precision using the given function.\n * @method $this floorDecade(int|float $precision = 1) Truncate the current instance decade with given precision.\n * @method $this floorDecades(int|float $precision = 1) Truncate the current instance decade with given precision.\n * @method $this ceilDecade(int|float $precision = 1) Ceil the current instance decade with given precision.\n * @method $this ceilDecades(int|float $precision = 1) Ceil the current instance decade with given precision.\n * @method $this roundQuarter(int|float $precision = 1, string $function = \"round\") Round the current instance quarter with given precision using the given function.\n * @method $this roundQuarters(int|float $precision = 1, string $function = \"round\") Round the current instance quarter with given precision using the given function.\n * @method $this floorQuarter(int|float $precision = 1) Truncate the current instance quarter with given precision.\n * @method $this floorQuarters(int|float $precision = 1) Truncate the current instance quarter with given precision.\n * @method $this ceilQuarter(int|float $precision = 1) Ceil the current instance quarter with given precision.\n * @method $this ceilQuarters(int|float $precision = 1) Ceil the current instance quarter with given precision.\n * @method $this roundMillisecond(int|float $precision = 1, string $function = \"round\") Round the current instance millisecond with given precision using the given function.\n * @method $this roundMilliseconds(int|float $precision = 1, string $function = \"round\") Round the current instance millisecond with given precision using the given function.\n * @method $this floorMillisecond(int|float $precision = 1) Truncate the current instance millisecond with given precision.\n * @method $this floorMilliseconds(int|float $precision = 1) Truncate the current instance millisecond with given precision.\n * @method $this ceilMillisecond(int|float $precision = 1) Ceil the current instance millisecond with given precision.\n * @method $this ceilMilliseconds(int|float $precision = 1) Ceil the current instance millisecond with given precision.\n * @method $this roundMicrosecond(int|float $precision = 1, string $function = \"round\") Round the current instance microsecond with given precision using the given function.\n * @method $this roundMicroseconds(int|float $precision = 1, string $function = \"round\") Round the current instance microsecond with given precision using the given function.\n * @method $this floorMicrosecond(int|float $precision = 1) Truncate the current instance microsecond with given precision.\n * @method $this floorMicroseconds(int|float $precision = 1) Truncate the current instance microsecond with given precision.\n * @method $this ceilMicrosecond(int|float $precision = 1) Ceil the current instance microsecond with given precision.\n * @method $this ceilMicroseconds(int|float $precision = 1) Ceil the current instance microsecond with given precision.\n */\nclass CarbonInterval extends DateInterval implements CarbonConverterInterface\n{\n    use IntervalRounding;\n    use IntervalStep;\n    use MagicParameter;\n    use Mixin {\n        Mixin::mixin as baseMixin;\n    }\n    use Options;\n    use ToStringFormat;\n\n    /**\n     * Interval spec period designators\n     */\n    public const PERIOD_PREFIX = 'P';\n    public const PERIOD_YEARS = 'Y';\n    public const PERIOD_MONTHS = 'M';\n    public const PERIOD_DAYS = 'D';\n    public const PERIOD_TIME_PREFIX = 'T';\n    public const PERIOD_HOURS = 'H';\n    public const PERIOD_MINUTES = 'M';\n    public const PERIOD_SECONDS = 'S';\n\n    /**\n     * A translator to ... er ... translate stuff\n     *\n     * @var \\Symfony\\Component\\Translation\\TranslatorInterface\n     */\n    protected static $translator;\n\n    /**\n     * @var array|null\n     */\n    protected static $cascadeFactors;\n\n    /**\n     * @var array\n     */\n    protected static $formats = [\n        'y' => 'y',\n        'Y' => 'y',\n        'o' => 'y',\n        'm' => 'm',\n        'n' => 'm',\n        'W' => 'weeks',\n        'd' => 'd',\n        'j' => 'd',\n        'z' => 'd',\n        'h' => 'h',\n        'g' => 'h',\n        'H' => 'h',\n        'G' => 'h',\n        'i' => 'i',\n        's' => 's',\n        'u' => 'micro',\n        'v' => 'milli',\n    ];\n\n    /**\n     * @var array|null\n     */\n    private static $flipCascadeFactors;\n\n    /**\n     * @var bool\n     */\n    private static $floatSettersEnabled = false;\n\n    /**\n     * The registered macros.\n     *\n     * @var array\n     */\n    protected static $macros = [];\n\n    /**\n     * Timezone handler for settings() method.\n     *\n     * @var mixed\n     */\n    protected $tzName;\n\n    /**\n     * Set the instance's timezone from a string or object.\n     *\n     * @param \\DateTimeZone|string $tzName\n     *\n     * @return static\n     */\n    public function setTimezone($tzName)\n    {\n        $this->tzName = $tzName;\n\n        return $this;\n    }\n\n    /**\n     * @internal\n     *\n     * Set the instance's timezone from a string or object and add/subtract the offset difference.\n     *\n     * @param \\DateTimeZone|string $tzName\n     *\n     * @return static\n     */\n    public function shiftTimezone($tzName)\n    {\n        $this->tzName = $tzName;\n\n        return $this;\n    }\n\n    /**\n     * Mapping of units and factors for cascading.\n     *\n     * Should only be modified by changing the factors or referenced constants.\n     *\n     * @return array\n     */\n    public static function getCascadeFactors()\n    {\n        return static::$cascadeFactors ?: static::getDefaultCascadeFactors();\n    }\n\n    protected static function getDefaultCascadeFactors(): array\n    {\n        return [\n            'milliseconds' => [Carbon::MICROSECONDS_PER_MILLISECOND, 'microseconds'],\n            'seconds' => [Carbon::MILLISECONDS_PER_SECOND, 'milliseconds'],\n            'minutes' => [Carbon::SECONDS_PER_MINUTE, 'seconds'],\n            'hours' => [Carbon::MINUTES_PER_HOUR, 'minutes'],\n            'dayz' => [Carbon::HOURS_PER_DAY, 'hours'],\n            'weeks' => [Carbon::DAYS_PER_WEEK, 'dayz'],\n            'months' => [Carbon::WEEKS_PER_MONTH, 'weeks'],\n            'years' => [Carbon::MONTHS_PER_YEAR, 'months'],\n        ];\n    }\n\n    private static function standardizeUnit($unit)\n    {\n        $unit = rtrim($unit, 'sz').'s';\n\n        return $unit === 'days' ? 'dayz' : $unit;\n    }\n\n    private static function getFlipCascadeFactors()\n    {\n        if (!self::$flipCascadeFactors) {\n            self::$flipCascadeFactors = [];\n\n            foreach (static::getCascadeFactors() as $to => [$factor, $from]) {\n                self::$flipCascadeFactors[self::standardizeUnit($from)] = [self::standardizeUnit($to), $factor];\n            }\n        }\n\n        return self::$flipCascadeFactors;\n    }\n\n    /**\n     * Set default cascading factors for ->cascade() method.\n     *\n     * @param array $cascadeFactors\n     */\n    public static function setCascadeFactors(array $cascadeFactors)\n    {\n        self::$flipCascadeFactors = null;\n        static::$cascadeFactors = $cascadeFactors;\n    }\n\n    /**\n     * This option allow you to opt-in for the Carbon 3 behavior where float\n     * values will no longer be cast to integer (so truncated).\n     *\n     * ⚠️ This settings will be applied globally, which mean your whole application\n     * code including the third-party dependencies that also may use Carbon will\n     * adopt the new behavior.\n     */\n    public static function enableFloatSetters(bool $floatSettersEnabled = true): void\n    {\n        self::$floatSettersEnabled = $floatSettersEnabled;\n    }\n\n    ///////////////////////////////////////////////////////////////////\n    //////////////////////////// CONSTRUCTORS /////////////////////////\n    ///////////////////////////////////////////////////////////////////\n\n    /**\n     * Create a new CarbonInterval instance.\n     *\n     * @param Closure|DateInterval|string|int|null $years\n     * @param int|float|null                       $months\n     * @param int|float|null                       $weeks\n     * @param int|float|null                       $days\n     * @param int|float|null                       $hours\n     * @param int|float|null                       $minutes\n     * @param int|float|null                       $seconds\n     * @param int|float|null                       $microseconds\n     *\n     * @throws Exception when the interval_spec (passed as $years) cannot be parsed as an interval.\n     */\n    public function __construct($years = 1, $months = null, $weeks = null, $days = null, $hours = null, $minutes = null, $seconds = null, $microseconds = null)\n    {\n        if ($years instanceof Closure) {\n            $this->step = $years;\n            $years = null;\n        }\n\n        if ($years instanceof DateInterval) {\n            parent::__construct(static::getDateIntervalSpec($years));\n            $this->f = $years->f;\n            self::copyNegativeUnits($years, $this);\n\n            return;\n        }\n\n        $spec = $years;\n        $isStringSpec = (\\is_string($spec) && !preg_match('/^[\\d.]/', $spec));\n\n        if (!$isStringSpec || (float) $years) {\n            $spec = static::PERIOD_PREFIX;\n\n            $spec .= $years > 0 ? $years.static::PERIOD_YEARS : '';\n            $spec .= $months > 0 ? $months.static::PERIOD_MONTHS : '';\n\n            $specDays = 0;\n            $specDays += $weeks > 0 ? $weeks * static::getDaysPerWeek() : 0;\n            $specDays += $days > 0 ? $days : 0;\n\n            $spec .= $specDays > 0 ? $specDays.static::PERIOD_DAYS : '';\n\n            if ($hours > 0 || $minutes > 0 || $seconds > 0) {\n                $spec .= static::PERIOD_TIME_PREFIX;\n                $spec .= $hours > 0 ? $hours.static::PERIOD_HOURS : '';\n                $spec .= $minutes > 0 ? $minutes.static::PERIOD_MINUTES : '';\n                $spec .= $seconds > 0 ? $seconds.static::PERIOD_SECONDS : '';\n            }\n\n            if ($spec === static::PERIOD_PREFIX) {\n                // Allow the zero interval.\n                $spec .= '0'.static::PERIOD_YEARS;\n            }\n        }\n\n        try {\n            parent::__construct($spec);\n        } catch (Throwable $exception) {\n            try {\n                parent::__construct('PT0S');\n\n                if ($isStringSpec) {\n                    if (!preg_match('/^P\n                        (?:(?<year>[+-]?\\d*(?:\\.\\d+)?)Y)?\n                        (?:(?<month>[+-]?\\d*(?:\\.\\d+)?)M)?\n                        (?:(?<week>[+-]?\\d*(?:\\.\\d+)?)W)?\n                        (?:(?<day>[+-]?\\d*(?:\\.\\d+)?)D)?\n                        (?:T\n                            (?:(?<hour>[+-]?\\d*(?:\\.\\d+)?)H)?\n                            (?:(?<minute>[+-]?\\d*(?:\\.\\d+)?)M)?\n                            (?:(?<second>[+-]?\\d*(?:\\.\\d+)?)S)?\n                        )?\n                    $/x', $spec, $match)) {\n                        throw new InvalidArgumentException(\"Invalid duration: $spec\");\n                    }\n\n                    $years = (float) ($match['year'] ?? 0);\n                    $this->assertSafeForInteger('year', $years);\n                    $months = (float) ($match['month'] ?? 0);\n                    $this->assertSafeForInteger('month', $months);\n                    $weeks = (float) ($match['week'] ?? 0);\n                    $this->assertSafeForInteger('week', $weeks);\n                    $days = (float) ($match['day'] ?? 0);\n                    $this->assertSafeForInteger('day', $days);\n                    $hours = (float) ($match['hour'] ?? 0);\n                    $this->assertSafeForInteger('hour', $hours);\n                    $minutes = (float) ($match['minute'] ?? 0);\n                    $this->assertSafeForInteger('minute', $minutes);\n                    $seconds = (float) ($match['second'] ?? 0);\n                    $this->assertSafeForInteger('second', $seconds);\n                }\n\n                $totalDays = (($weeks * static::getDaysPerWeek()) + $days);\n                $this->assertSafeForInteger('days total (including weeks)', $totalDays);\n\n                $this->y = (int) $years;\n                $this->m = (int) $months;\n                $this->d = (int) $totalDays;\n                $this->h = (int) $hours;\n                $this->i = (int) $minutes;\n                $this->s = (int) $seconds;\n\n                if (\n                    ((float) $this->y) !== $years ||\n                    ((float) $this->m) !== $months ||\n                    ((float) $this->d) !== $totalDays ||\n                    ((float) $this->h) !== $hours ||\n                    ((float) $this->i) !== $minutes ||\n                    ((float) $this->s) !== $seconds\n                ) {\n                    $this->add(static::fromString(\n                        ($years - $this->y).' years '.\n                        ($months - $this->m).' months '.\n                        ($totalDays - $this->d).' days '.\n                        ($hours - $this->h).' hours '.\n                        ($minutes - $this->i).' minutes '.\n                        ($seconds - $this->s).' seconds '\n                    ));\n                }\n            } catch (Throwable $secondException) {\n                throw $secondException instanceof OutOfRangeException ? $secondException : $exception;\n            }\n        }\n\n        if ($microseconds !== null) {\n            $this->f = $microseconds / Carbon::MICROSECONDS_PER_SECOND;\n        }\n    }\n\n    /**\n     * Returns the factor for a given source-to-target couple.\n     *\n     * @param string $source\n     * @param string $target\n     *\n     * @return int|float|null\n     */\n    public static function getFactor($source, $target)\n    {\n        $source = self::standardizeUnit($source);\n        $target = self::standardizeUnit($target);\n        $factors = self::getFlipCascadeFactors();\n\n        if (isset($factors[$source])) {\n            [$to, $factor] = $factors[$source];\n\n            if ($to === $target) {\n                return $factor;\n            }\n\n            return $factor * static::getFactor($to, $target);\n        }\n\n        return null;\n    }\n\n    /**\n     * Returns the factor for a given source-to-target couple if set,\n     * else try to find the appropriate constant as the factor, such as Carbon::DAYS_PER_WEEK.\n     *\n     * @param string $source\n     * @param string $target\n     *\n     * @return int|float|null\n     */\n    public static function getFactorWithDefault($source, $target)\n    {\n        $factor = self::getFactor($source, $target);\n\n        if ($factor) {\n            return $factor;\n        }\n\n        static $defaults = [\n            'month' => ['year' => Carbon::MONTHS_PER_YEAR],\n            'week' => ['month' => Carbon::WEEKS_PER_MONTH],\n            'day' => ['week' => Carbon::DAYS_PER_WEEK],\n            'hour' => ['day' => Carbon::HOURS_PER_DAY],\n            'minute' => ['hour' => Carbon::MINUTES_PER_HOUR],\n            'second' => ['minute' => Carbon::SECONDS_PER_MINUTE],\n            'millisecond' => ['second' => Carbon::MILLISECONDS_PER_SECOND],\n            'microsecond' => ['millisecond' => Carbon::MICROSECONDS_PER_MILLISECOND],\n        ];\n\n        return $defaults[$source][$target] ?? null;\n    }\n\n    /**\n     * Returns current config for days per week.\n     *\n     * @return int|float\n     */\n    public static function getDaysPerWeek()\n    {\n        return static::getFactor('dayz', 'weeks') ?: Carbon::DAYS_PER_WEEK;\n    }\n\n    /**\n     * Returns current config for hours per day.\n     *\n     * @return int|float\n     */\n    public static function getHoursPerDay()\n    {\n        return static::getFactor('hours', 'dayz') ?: Carbon::HOURS_PER_DAY;\n    }\n\n    /**\n     * Returns current config for minutes per hour.\n     *\n     * @return int|float\n     */\n    public static function getMinutesPerHour()\n    {\n        return static::getFactor('minutes', 'hours') ?: Carbon::MINUTES_PER_HOUR;\n    }\n\n    /**\n     * Returns current config for seconds per minute.\n     *\n     * @return int|float\n     */\n    public static function getSecondsPerMinute()\n    {\n        return static::getFactor('seconds', 'minutes') ?: Carbon::SECONDS_PER_MINUTE;\n    }\n\n    /**\n     * Returns current config for microseconds per second.\n     *\n     * @return int|float\n     */\n    public static function getMillisecondsPerSecond()\n    {\n        return static::getFactor('milliseconds', 'seconds') ?: Carbon::MILLISECONDS_PER_SECOND;\n    }\n\n    /**\n     * Returns current config for microseconds per second.\n     *\n     * @return int|float\n     */\n    public static function getMicrosecondsPerMillisecond()\n    {\n        return static::getFactor('microseconds', 'milliseconds') ?: Carbon::MICROSECONDS_PER_MILLISECOND;\n    }\n\n    /**\n     * Create a new CarbonInterval instance from specific values.\n     * This is an alias for the constructor that allows better fluent\n     * syntax as it allows you to do CarbonInterval::create(1)->fn() rather than\n     * (new CarbonInterval(1))->fn().\n     *\n     * @param int $years\n     * @param int $months\n     * @param int $weeks\n     * @param int $days\n     * @param int $hours\n     * @param int $minutes\n     * @param int $seconds\n     * @param int $microseconds\n     *\n     * @throws Exception when the interval_spec (passed as $years) cannot be parsed as an interval.\n     *\n     * @return static\n     */\n    public static function create($years = 1, $months = null, $weeks = null, $days = null, $hours = null, $minutes = null, $seconds = null, $microseconds = null)\n    {\n        return new static($years, $months, $weeks, $days, $hours, $minutes, $seconds, $microseconds);\n    }\n\n    /**\n     * Parse a string into a new CarbonInterval object according to the specified format.\n     *\n     * @example\n     * ```\n     * echo Carboninterval::createFromFormat('H:i', '1:30');\n     * ```\n     *\n     * @param string      $format   Format of the $interval input string\n     * @param string|null $interval Input string to convert into an interval\n     *\n     * @throws \\Carbon\\Exceptions\\ParseErrorException when the $interval cannot be parsed as an interval.\n     *\n     * @return static\n     */\n    public static function createFromFormat(string $format, ?string $interval)\n    {\n        $instance = new static(0);\n        $length = mb_strlen($format);\n\n        if (preg_match('/s([,.])([uv])$/', $format, $match)) {\n            $interval = explode($match[1], $interval);\n            $index = \\count($interval) - 1;\n            $interval[$index] = str_pad($interval[$index], $match[2] === 'v' ? 3 : 6, '0');\n            $interval = implode($match[1], $interval);\n        }\n\n        $interval = $interval ?? '';\n\n        for ($index = 0; $index < $length; $index++) {\n            $expected = mb_substr($format, $index, 1);\n            $nextCharacter = mb_substr($interval, 0, 1);\n            $unit = static::$formats[$expected] ?? null;\n\n            if ($unit) {\n                if (!preg_match('/^-?\\d+/', $interval, $match)) {\n                    throw new ParseErrorException('number', $nextCharacter);\n                }\n\n                $interval = mb_substr($interval, mb_strlen($match[0]));\n                $instance->$unit += (int) ($match[0]);\n\n                continue;\n            }\n\n            if ($nextCharacter !== $expected) {\n                throw new ParseErrorException(\n                    \"'$expected'\",\n                    $nextCharacter,\n                    'Allowed substitutes for interval formats are '.implode(', ', array_keys(static::$formats)).\"\\n\".\n                    'See https://php.net/manual/en/function.date.php for their meaning'\n                );\n            }\n\n            $interval = mb_substr($interval, 1);\n        }\n\n        if ($interval !== '') {\n            throw new ParseErrorException(\n                'end of string',\n                $interval\n            );\n        }\n\n        return $instance;\n    }\n\n    /**\n     * Get a copy of the instance.\n     *\n     * @return static\n     */\n    public function copy()\n    {\n        $date = new static(0);\n        $date->copyProperties($this);\n        $date->step = $this->step;\n\n        return $date;\n    }\n\n    /**\n     * Get a copy of the instance.\n     *\n     * @return static\n     */\n    public function clone()\n    {\n        return $this->copy();\n    }\n\n    /**\n     * Provide static helpers to create instances.  Allows CarbonInterval::years(3).\n     *\n     * Note: This is done using the magic method to allow static and instance methods to\n     *       have the same names.\n     *\n     * @param string $method     magic method name called\n     * @param array  $parameters parameters list\n     *\n     * @return static|null\n     */\n    public static function __callStatic($method, $parameters)\n    {\n        try {\n            $interval = new static(0);\n            $localStrictModeEnabled = $interval->localStrictModeEnabled;\n            $interval->localStrictModeEnabled = true;\n\n            $result = static::hasMacro($method)\n                ? static::bindMacroContext(null, function () use (&$method, &$parameters, &$interval) {\n                    return $interval->callMacro($method, $parameters);\n                })\n                : $interval->$method(...$parameters);\n\n            $interval->localStrictModeEnabled = $localStrictModeEnabled;\n\n            return $result;\n        } catch (BadFluentSetterException $exception) {\n            if (Carbon::isStrictModeEnabled()) {\n                throw new BadFluentConstructorException($method, 0, $exception);\n            }\n\n            return null;\n        }\n    }\n\n    /**\n     * Evaluate the PHP generated by var_export() and recreate the exported CarbonInterval instance.\n     *\n     * @param array $dump data as exported by var_export()\n     *\n     * @return static\n     */\n    #[ReturnTypeWillChange]\n    public static function __set_state($dump)\n    {\n        /** @noinspection PhpVoidFunctionResultUsedInspection */\n        /** @var DateInterval $dateInterval */\n        $dateInterval = parent::__set_state($dump);\n\n        return static::instance($dateInterval);\n    }\n\n    /**\n     * Return the current context from inside a macro callee or a new one if static.\n     *\n     * @return static\n     */\n    protected static function this()\n    {\n        return end(static::$macroContextStack) ?: new static(0);\n    }\n\n    /**\n     * Creates a CarbonInterval from string.\n     *\n     * Format:\n     *\n     * Suffix | Unit    | Example | DateInterval expression\n     * -------|---------|---------|------------------------\n     * y      | years   |   1y    | P1Y\n     * mo     | months  |   3mo   | P3M\n     * w      | weeks   |   2w    | P2W\n     * d      | days    |  28d    | P28D\n     * h      | hours   |   4h    | PT4H\n     * m      | minutes |  12m    | PT12M\n     * s      | seconds |  59s    | PT59S\n     *\n     * e. g. `1w 3d 4h 32m 23s` is converted to 10 days 4 hours 32 minutes and 23 seconds.\n     *\n     * Special cases:\n     *  - An empty string will return a zero interval\n     *  - Fractions are allowed for weeks, days, hours and minutes and will be converted\n     *    and rounded to the next smaller value (caution: 0.5w = 4d)\n     *\n     * @param string $intervalDefinition\n     *\n     * @return static\n     */\n    public static function fromString($intervalDefinition)\n    {\n        if (empty($intervalDefinition)) {\n            return new static(0);\n        }\n\n        $years = 0;\n        $months = 0;\n        $weeks = 0;\n        $days = 0;\n        $hours = 0;\n        $minutes = 0;\n        $seconds = 0;\n        $milliseconds = 0;\n        $microseconds = 0;\n\n        $pattern = '/(\\d+(?:\\.\\d+)?)\\h*([^\\d\\h]*)/i';\n        preg_match_all($pattern, $intervalDefinition, $parts, PREG_SET_ORDER);\n\n        while ([$part, $value, $unit] = array_shift($parts)) {\n            $intValue = (int) $value;\n            $fraction = (float) $value - $intValue;\n\n            // Fix calculation precision\n            switch (round($fraction, 6)) {\n                case 1:\n                    $fraction = 0;\n                    $intValue++;\n\n                    break;\n                case 0:\n                    $fraction = 0;\n\n                    break;\n            }\n\n            switch ($unit === 'µs' ? 'µs' : strtolower($unit)) {\n                case 'millennia':\n                case 'millennium':\n                    $years += $intValue * CarbonInterface::YEARS_PER_MILLENNIUM;\n\n                    break;\n\n                case 'century':\n                case 'centuries':\n                    $years += $intValue * CarbonInterface::YEARS_PER_CENTURY;\n\n                    break;\n\n                case 'decade':\n                case 'decades':\n                    $years += $intValue * CarbonInterface::YEARS_PER_DECADE;\n\n                    break;\n\n                case 'year':\n                case 'years':\n                case 'y':\n                case 'yr':\n                case 'yrs':\n                    $years += $intValue;\n\n                    break;\n\n                case 'quarter':\n                case 'quarters':\n                    $months += $intValue * CarbonInterface::MONTHS_PER_QUARTER;\n\n                    break;\n\n                case 'month':\n                case 'months':\n                case 'mo':\n                case 'mos':\n                    $months += $intValue;\n\n                    break;\n\n                case 'week':\n                case 'weeks':\n                case 'w':\n                    $weeks += $intValue;\n\n                    if ($fraction) {\n                        $parts[] = [null, $fraction * static::getDaysPerWeek(), 'd'];\n                    }\n\n                    break;\n\n                case 'day':\n                case 'days':\n                case 'd':\n                    $days += $intValue;\n\n                    if ($fraction) {\n                        $parts[] = [null, $fraction * static::getHoursPerDay(), 'h'];\n                    }\n\n                    break;\n\n                case 'hour':\n                case 'hours':\n                case 'h':\n                    $hours += $intValue;\n\n                    if ($fraction) {\n                        $parts[] = [null, $fraction * static::getMinutesPerHour(), 'm'];\n                    }\n\n                    break;\n\n                case 'minute':\n                case 'minutes':\n                case 'm':\n                    $minutes += $intValue;\n\n                    if ($fraction) {\n                        $parts[] = [null, $fraction * static::getSecondsPerMinute(), 's'];\n                    }\n\n                    break;\n\n                case 'second':\n                case 'seconds':\n                case 's':\n                    $seconds += $intValue;\n\n                    if ($fraction) {\n                        $parts[] = [null, $fraction * static::getMillisecondsPerSecond(), 'ms'];\n                    }\n\n                    break;\n\n                case 'millisecond':\n                case 'milliseconds':\n                case 'milli':\n                case 'ms':\n                    $milliseconds += $intValue;\n\n                    if ($fraction) {\n                        $microseconds += round($fraction * static::getMicrosecondsPerMillisecond());\n                    }\n\n                    break;\n\n                case 'microsecond':\n                case 'microseconds':\n                case 'micro':\n                case 'µs':\n                    $microseconds += $intValue;\n\n                    break;\n\n                default:\n                    throw new InvalidIntervalException(\n                        \\sprintf('Invalid part %s in definition %s', $part, $intervalDefinition)\n                    );\n            }\n        }\n\n        return new static($years, $months, $weeks, $days, $hours, $minutes, $seconds, $milliseconds * Carbon::MICROSECONDS_PER_MILLISECOND + $microseconds);\n    }\n\n    /**\n     * Creates a CarbonInterval from string using a different locale.\n     *\n     * @param string      $interval interval string in the given language (may also contain English).\n     * @param string|null $locale   if locale is null or not specified, current global locale will be used instead.\n     *\n     * @return static\n     */\n    public static function parseFromLocale($interval, $locale = null)\n    {\n        return static::fromString(Carbon::translateTimeString($interval, $locale ?: static::getLocale(), 'en'));\n    }\n\n    private static function castIntervalToClass(DateInterval $interval, string $className, array $skip = [])\n    {\n        $mainClass = DateInterval::class;\n\n        if (!is_a($className, $mainClass, true)) {\n            throw new InvalidCastException(\"$className is not a sub-class of $mainClass.\");\n        }\n\n        $microseconds = $interval->f;\n        $instance = new $className(static::getDateIntervalSpec($interval, false, $skip));\n\n        if ($microseconds) {\n            $instance->f = $microseconds;\n        }\n\n        if ($interval instanceof self && is_a($className, self::class, true)) {\n            self::copyStep($interval, $instance);\n        }\n\n        self::copyNegativeUnits($interval, $instance);\n\n        return $instance;\n    }\n\n    private static function copyNegativeUnits(DateInterval $from, DateInterval $to): void\n    {\n        $to->invert = $from->invert;\n\n        foreach (['y', 'm', 'd', 'h', 'i', 's'] as $unit) {\n            if ($from->$unit < 0) {\n                $to->$unit *= -1;\n            }\n        }\n    }\n\n    private static function copyStep(self $from, self $to): void\n    {\n        $to->setStep($from->getStep());\n    }\n\n    /**\n     * Cast the current instance into the given class.\n     *\n     * @param string $className The $className::instance() method will be called to cast the current object.\n     *\n     * @return DateInterval\n     */\n    public function cast(string $className)\n    {\n        return self::castIntervalToClass($this, $className);\n    }\n\n    /**\n     * Create a CarbonInterval instance from a DateInterval one.  Can not instance\n     * DateInterval objects created from DateTime::diff() as you can't externally\n     * set the $days field.\n     *\n     * @param DateInterval $interval\n     * @param bool         $skipCopy set to true to return the passed object\n     *                               (without copying it) if it's already of the\n     *                               current class\n     *\n     * @return static\n     */\n    public static function instance(DateInterval $interval, array $skip = [], bool $skipCopy = false)\n    {\n        if ($skipCopy && $interval instanceof static) {\n            return $interval;\n        }\n\n        return self::castIntervalToClass($interval, static::class, $skip);\n    }\n\n    /**\n     * Make a CarbonInterval instance from given variable if possible.\n     *\n     * Always return a new instance. Parse only strings and only these likely to be intervals (skip dates\n     * and recurrences). Throw an exception for invalid format, but otherwise return null.\n     *\n     * @param mixed|int|DateInterval|string|Closure|null $interval interval or number of the given $unit\n     * @param string|null                                $unit     if specified, $interval must be an integer\n     * @param bool                                       $skipCopy set to true to return the passed object\n     *                                                             (without copying it) if it's already of the\n     *                                                             current class\n     *\n     * @return static|null\n     */\n    public static function make($interval, $unit = null, bool $skipCopy = false)\n    {\n        if ($unit) {\n            $interval = \"$interval \".Carbon::pluralUnit($unit);\n        }\n\n        if ($interval instanceof DateInterval) {\n            return static::instance($interval, [], $skipCopy);\n        }\n\n        if ($interval instanceof Closure) {\n            return new static($interval);\n        }\n\n        if (!\\is_string($interval)) {\n            return null;\n        }\n\n        return static::makeFromString($interval);\n    }\n\n    protected static function makeFromString(string $interval)\n    {\n        $interval = preg_replace('/\\s+/', ' ', trim($interval));\n\n        if (preg_match('/^P[T\\d]/', $interval)) {\n            return new static($interval);\n        }\n\n        if (preg_match('/^(?:\\h*\\d+(?:\\.\\d+)?\\h*[a-z]+)+$/i', $interval)) {\n            return static::fromString($interval);\n        }\n\n        // @codeCoverageIgnoreStart\n        try {\n            /** @var static $interval */\n            $interval = static::createFromDateString($interval);\n        } catch (DateMalformedIntervalStringException $e) {\n            return null;\n        }\n        // @codeCoverageIgnoreEnd\n\n        return !$interval || $interval->isEmpty() ? null : $interval;\n    }\n\n    protected function resolveInterval($interval)\n    {\n        if (!($interval instanceof self)) {\n            return self::make($interval);\n        }\n\n        return $interval;\n    }\n\n    /**\n     * Sets up a DateInterval from the relative parts of the string.\n     *\n     * @param string $time\n     *\n     * @return static\n     *\n     * @link https://php.net/manual/en/dateinterval.createfromdatestring.php\n     */\n    #[ReturnTypeWillChange]\n    public static function createFromDateString($time)\n    {\n        $interval = @parent::createFromDateString(strtr($time, [\n            ',' => ' ',\n            ' and ' => ' ',\n        ]));\n\n        if ($interval instanceof DateInterval) {\n            $interval = static::instance($interval);\n        }\n\n        return $interval;\n    }\n\n    ///////////////////////////////////////////////////////////////////\n    ///////////////////////// GETTERS AND SETTERS /////////////////////\n    ///////////////////////////////////////////////////////////////////\n\n    /**\n     * Get a part of the CarbonInterval object.\n     *\n     * @param string $name\n     *\n     * @throws UnknownGetterException\n     *\n     * @return int|float|string\n     */\n    public function get($name)\n    {\n        if (str_starts_with($name, 'total')) {\n            return $this->total(substr($name, 5));\n        }\n\n        switch ($name) {\n            case 'years':\n                return $this->y;\n\n            case 'months':\n                return $this->m;\n\n            case 'dayz':\n                return $this->d;\n\n            case 'hours':\n                return $this->h;\n\n            case 'minutes':\n                return $this->i;\n\n            case 'seconds':\n                return $this->s;\n\n            case 'milli':\n            case 'milliseconds':\n                return (int) (round($this->f * Carbon::MICROSECONDS_PER_SECOND) / Carbon::MICROSECONDS_PER_MILLISECOND);\n\n            case 'micro':\n            case 'microseconds':\n                return (int) round($this->f * Carbon::MICROSECONDS_PER_SECOND);\n\n            case 'microExcludeMilli':\n                return (int) round($this->f * Carbon::MICROSECONDS_PER_SECOND) % Carbon::MICROSECONDS_PER_MILLISECOND;\n\n            case 'weeks':\n                return (int) ($this->d / (int) static::getDaysPerWeek());\n\n            case 'daysExcludeWeeks':\n            case 'dayzExcludeWeeks':\n                return $this->d % (int) static::getDaysPerWeek();\n\n            case 'locale':\n                return $this->getTranslatorLocale();\n\n            default:\n                throw new UnknownGetterException($name);\n        }\n    }\n\n    /**\n     * Get a part of the CarbonInterval object.\n     *\n     * @param string $name\n     *\n     * @throws UnknownGetterException\n     *\n     * @return int|float|string\n     */\n    public function __get($name)\n    {\n        return $this->get($name);\n    }\n\n    /**\n     * Set a part of the CarbonInterval object.\n     *\n     * @param string|array $name\n     * @param int          $value\n     *\n     * @throws UnknownSetterException\n     *\n     * @return $this\n     */\n    public function set($name, $value = null)\n    {\n        $properties = \\is_array($name) ? $name : [$name => $value];\n\n        foreach ($properties as $key => $value) {\n            switch (Carbon::singularUnit(rtrim($key, 'z'))) {\n                case 'year':\n                    $this->checkIntegerValue($key, $value);\n                    $this->y = $value;\n                    $this->handleDecimalPart('year', $value, $this->y);\n\n                    break;\n\n                case 'month':\n                    $this->checkIntegerValue($key, $value);\n                    $this->m = $value;\n                    $this->handleDecimalPart('month', $value, $this->m);\n\n                    break;\n\n                case 'week':\n                    $this->checkIntegerValue($key, $value);\n                    $days = $value * (int) static::getDaysPerWeek();\n                    $this->assertSafeForInteger('days total (including weeks)', $days);\n                    $this->d = $days;\n                    $this->handleDecimalPart('day', $days, $this->d);\n\n                    break;\n\n                case 'day':\n                    $this->checkIntegerValue($key, $value);\n                    $this->d = $value;\n                    $this->handleDecimalPart('day', $value, $this->d);\n\n                    break;\n\n                case 'daysexcludeweek':\n                case 'dayzexcludeweek':\n                    $this->checkIntegerValue($key, $value);\n                    $days = $this->weeks * (int) static::getDaysPerWeek() + $value;\n                    $this->assertSafeForInteger('days total (including weeks)', $days);\n                    $this->d = $days;\n                    $this->handleDecimalPart('day', $days, $this->d);\n\n                    break;\n\n                case 'hour':\n                    $this->checkIntegerValue($key, $value);\n                    $this->h = $value;\n                    $this->handleDecimalPart('hour', $value, $this->h);\n\n                    break;\n\n                case 'minute':\n                    $this->checkIntegerValue($key, $value);\n                    $this->i = $value;\n                    $this->handleDecimalPart('minute', $value, $this->i);\n\n                    break;\n\n                case 'second':\n                    $this->checkIntegerValue($key, $value);\n                    $this->s = $value;\n                    $this->handleDecimalPart('second', $value, $this->s);\n\n                    break;\n\n                case 'milli':\n                case 'millisecond':\n                    $this->microseconds = $value * Carbon::MICROSECONDS_PER_MILLISECOND + $this->microseconds % Carbon::MICROSECONDS_PER_MILLISECOND;\n\n                    break;\n\n                case 'micro':\n                case 'microsecond':\n                    $this->f = $value / Carbon::MICROSECONDS_PER_SECOND;\n\n                    break;\n\n                default:\n                    if ($this->localStrictModeEnabled ?? Carbon::isStrictModeEnabled()) {\n                        throw new UnknownSetterException($key);\n                    }\n\n                    $this->$key = $value;\n            }\n        }\n\n        return $this;\n    }\n\n    /**\n     * Set a part of the CarbonInterval object.\n     *\n     * @param string $name\n     * @param int    $value\n     *\n     * @throws UnknownSetterException\n     */\n    public function __set($name, $value)\n    {\n        $this->set($name, $value);\n    }\n\n    /**\n     * Allow setting of weeks and days to be cumulative.\n     *\n     * @param int $weeks Number of weeks to set\n     * @param int $days  Number of days to set\n     *\n     * @return static\n     */\n    public function weeksAndDays($weeks, $days)\n    {\n        $this->dayz = ($weeks * static::getDaysPerWeek()) + $days;\n\n        return $this;\n    }\n\n    /**\n     * Returns true if the interval is empty for each unit.\n     *\n     * @return bool\n     */\n    public function isEmpty()\n    {\n        return $this->years === 0 &&\n            $this->months === 0 &&\n            $this->dayz === 0 &&\n            !$this->days &&\n            $this->hours === 0 &&\n            $this->minutes === 0 &&\n            $this->seconds === 0 &&\n            $this->microseconds === 0;\n    }\n\n    /**\n     * Register a custom macro.\n     *\n     * @example\n     * ```\n     * CarbonInterval::macro('twice', function () {\n     *   return $this->times(2);\n     * });\n     * echo CarbonInterval::hours(2)->twice();\n     * ```\n     *\n     * @param string          $name\n     * @param object|callable $macro\n     *\n     * @return void\n     */\n    public static function macro($name, $macro)\n    {\n        static::$macros[$name] = $macro;\n    }\n\n    /**\n     * Register macros from a mixin object.\n     *\n     * @example\n     * ```\n     * CarbonInterval::mixin(new class {\n     *   public function daysToHours() {\n     *     return function () {\n     *       $this->hours += $this->days;\n     *       $this->days = 0;\n     *\n     *       return $this;\n     *     };\n     *   }\n     *   public function hoursToDays() {\n     *     return function () {\n     *       $this->days += $this->hours;\n     *       $this->hours = 0;\n     *\n     *       return $this;\n     *     };\n     *   }\n     * });\n     * echo CarbonInterval::hours(5)->hoursToDays() . \"\\n\";\n     * echo CarbonInterval::days(5)->daysToHours() . \"\\n\";\n     * ```\n     *\n     * @param object|string $mixin\n     *\n     * @throws ReflectionException\n     *\n     * @return void\n     */\n    public static function mixin($mixin)\n    {\n        static::baseMixin($mixin);\n    }\n\n    /**\n     * Check if macro is registered.\n     *\n     * @param string $name\n     *\n     * @return bool\n     */\n    public static function hasMacro($name)\n    {\n        return isset(static::$macros[$name]);\n    }\n\n    /**\n     * Call given macro.\n     *\n     * @param string $name\n     * @param array  $parameters\n     *\n     * @return mixed\n     */\n    protected function callMacro($name, $parameters)\n    {\n        $macro = static::$macros[$name];\n\n        if ($macro instanceof Closure) {\n            $boundMacro = @$macro->bindTo($this, static::class) ?: @$macro->bindTo(null, static::class);\n\n            return ($boundMacro ?: $macro)(...$parameters);\n        }\n\n        return $macro(...$parameters);\n    }\n\n    /**\n     * Allow fluent calls on the setters... CarbonInterval::years(3)->months(5)->day().\n     *\n     * Note: This is done using the magic method to allow static and instance methods to\n     *       have the same names.\n     *\n     * @param string $method     magic method name called\n     * @param array  $parameters parameters list\n     *\n     * @throws BadFluentSetterException|Throwable\n     *\n     * @return static\n     */\n    public function __call($method, $parameters)\n    {\n        if (static::hasMacro($method)) {\n            return static::bindMacroContext($this, function () use (&$method, &$parameters) {\n                return $this->callMacro($method, $parameters);\n            });\n        }\n\n        $roundedValue = $this->callRoundMethod($method, $parameters);\n\n        if ($roundedValue !== null) {\n            return $roundedValue;\n        }\n\n        if (preg_match('/^(?<method>add|sub)(?<unit>[A-Z].*)$/', $method, $match)) {\n            $value = $this->getMagicParameter($parameters, 0, Carbon::pluralUnit($match['unit']), 0);\n\n            return $this->{$match['method']}($value, $match['unit']);\n        }\n\n        $value = $this->getMagicParameter($parameters, 0, Carbon::pluralUnit($method), 1);\n\n        try {\n            $this->set($method, $value);\n        } catch (UnknownSetterException $exception) {\n            if ($this->localStrictModeEnabled ?? Carbon::isStrictModeEnabled()) {\n                throw new BadFluentSetterException($method, 0, $exception);\n            }\n        }\n\n        return $this;\n    }\n\n    protected function getForHumansInitialVariables($syntax, $short)\n    {\n        if (\\is_array($syntax)) {\n            return $syntax;\n        }\n\n        if (\\is_int($short)) {\n            return [\n                'parts' => $short,\n                'short' => false,\n            ];\n        }\n\n        if (\\is_bool($syntax)) {\n            return [\n                'short' => $syntax,\n                'syntax' => CarbonInterface::DIFF_ABSOLUTE,\n            ];\n        }\n\n        return [];\n    }\n\n    /**\n     * @param mixed $syntax\n     * @param mixed $short\n     * @param mixed $parts\n     * @param mixed $options\n     *\n     * @return array\n     */\n    protected function getForHumansParameters($syntax = null, $short = false, $parts = -1, $options = null)\n    {\n        $optionalSpace = ' ';\n        $default = $this->getTranslationMessage('list.0') ?? $this->getTranslationMessage('list') ?? ' ';\n        $join = $default === '' ? '' : ' ';\n        $altNumbers = false;\n        $aUnit = false;\n        $minimumUnit = 's';\n        $skip = [];\n        extract($this->getForHumansInitialVariables($syntax, $short));\n        $skip = array_map('strtolower', array_filter((array) $skip, static function ($value) {\n            return \\is_string($value) && $value !== '';\n        }));\n\n        if ($syntax === null) {\n            $syntax = CarbonInterface::DIFF_ABSOLUTE;\n        }\n\n        if ($parts === -1) {\n            $parts = INF;\n        }\n\n        if ($options === null) {\n            $options = static::getHumanDiffOptions();\n        }\n\n        if ($join === false) {\n            $join = ' ';\n        } elseif ($join === true) {\n            $join = [\n                $default,\n                $this->getTranslationMessage('list.1') ?? $default,\n            ];\n        }\n\n        if ($altNumbers && $altNumbers !== true) {\n            $language = new Language($this->locale);\n            $altNumbers = \\in_array($language->getCode(), (array) $altNumbers, true);\n        }\n\n        if (\\is_array($join)) {\n            [$default, $last] = $join;\n\n            if ($default !== ' ') {\n                $optionalSpace = '';\n            }\n\n            $join = function ($list) use ($default, $last) {\n                if (\\count($list) < 2) {\n                    return implode('', $list);\n                }\n\n                $end = array_pop($list);\n\n                return implode($default, $list).$last.$end;\n            };\n        }\n\n        if (\\is_string($join)) {\n            if ($join !== ' ') {\n                $optionalSpace = '';\n            }\n\n            $glue = $join;\n            $join = function ($list) use ($glue) {\n                return implode($glue, $list);\n            };\n        }\n\n        $interpolations = [\n            ':optional-space' => $optionalSpace,\n        ];\n\n        return [$syntax, $short, $parts, $options, $join, $aUnit, $altNumbers, $interpolations, $minimumUnit, $skip];\n    }\n\n    protected static function getRoundingMethodFromOptions(int $options): ?string\n    {\n        if ($options & CarbonInterface::ROUND) {\n            return 'round';\n        }\n\n        if ($options & CarbonInterface::CEIL) {\n            return 'ceil';\n        }\n\n        if ($options & CarbonInterface::FLOOR) {\n            return 'floor';\n        }\n\n        return null;\n    }\n\n    /**\n     * Returns interval values as an array where key are the unit names and values the counts.\n     *\n     * @return int[]\n     */\n    public function toArray()\n    {\n        return [\n            'years' => $this->years,\n            'months' => $this->months,\n            'weeks' => $this->weeks,\n            'days' => $this->daysExcludeWeeks,\n            'hours' => $this->hours,\n            'minutes' => $this->minutes,\n            'seconds' => $this->seconds,\n            'microseconds' => $this->microseconds,\n        ];\n    }\n\n    /**\n     * Returns interval non-zero values as an array where key are the unit names and values the counts.\n     *\n     * @return int[]\n     */\n    public function getNonZeroValues()\n    {\n        return array_filter($this->toArray(), 'intval');\n    }\n\n    /**\n     * Returns interval values as an array where key are the unit names and values the counts\n     * from the biggest non-zero one the the smallest non-zero one.\n     *\n     * @return int[]\n     */\n    public function getValuesSequence()\n    {\n        $nonZeroValues = $this->getNonZeroValues();\n\n        if ($nonZeroValues === []) {\n            return [];\n        }\n\n        $keys = array_keys($nonZeroValues);\n        $firstKey = $keys[0];\n        $lastKey = $keys[\\count($keys) - 1];\n        $values = [];\n        $record = false;\n\n        foreach ($this->toArray() as $unit => $count) {\n            if ($unit === $firstKey) {\n                $record = true;\n            }\n\n            if ($record) {\n                $values[$unit] = $count;\n            }\n\n            if ($unit === $lastKey) {\n                $record = false;\n            }\n        }\n\n        return $values;\n    }\n\n    /**\n     * Get the current interval in a human readable format in the current locale.\n     *\n     * @example\n     * ```\n     * echo CarbonInterval::fromString('4d 3h 40m')->forHumans() . \"\\n\";\n     * echo CarbonInterval::fromString('4d 3h 40m')->forHumans(['parts' => 2]) . \"\\n\";\n     * echo CarbonInterval::fromString('4d 3h 40m')->forHumans(['parts' => 3, 'join' => true]) . \"\\n\";\n     * echo CarbonInterval::fromString('4d 3h 40m')->forHumans(['short' => true]) . \"\\n\";\n     * echo CarbonInterval::fromString('1d 24h')->forHumans(['join' => ' or ']) . \"\\n\";\n     * echo CarbonInterval::fromString('1d 24h')->forHumans(['minimumUnit' => 'hour']) . \"\\n\";\n     * ```\n     *\n     * @param int|array $syntax  if array passed, parameters will be extracted from it, the array may contains:\n     *                           - 'syntax' entry (see below)\n     *                           - 'short' entry (see below)\n     *                           - 'parts' entry (see below)\n     *                           - 'options' entry (see below)\n     *                           - 'skip' entry, list of units to skip (array of strings or a single string,\n     *                           ` it can be the unit name (singular or plural) or its shortcut\n     *                           ` (y, m, w, d, h, min, s, ms, µs).\n     *                           - 'aUnit' entry, prefer \"an hour\" over \"1 hour\" if true\n     *                           - 'join' entry determines how to join multiple parts of the string\n     *                           `  - if $join is a string, it's used as a joiner glue\n     *                           `  - if $join is a callable/closure, it get the list of string and should return a string\n     *                           `  - if $join is an array, the first item will be the default glue, and the second item\n     *                           `    will be used instead of the glue for the last item\n     *                           `  - if $join is true, it will be guessed from the locale ('list' translation file entry)\n     *                           `  - if $join is missing, a space will be used as glue\n     *                           - 'minimumUnit' entry determines the smallest unit of time to display can be long or\n     *                           `  short form of the units, e.g. 'hour' or 'h' (default value: s)\n     *                           if int passed, it add modifiers:\n     *                           Possible values:\n     *                           - CarbonInterface::DIFF_ABSOLUTE          no modifiers\n     *                           - CarbonInterface::DIFF_RELATIVE_TO_NOW   add ago/from now modifier\n     *                           - CarbonInterface::DIFF_RELATIVE_TO_OTHER add before/after modifier\n     *                           Default value: CarbonInterface::DIFF_ABSOLUTE\n     * @param bool      $short   displays short format of time units\n     * @param int       $parts   maximum number of parts to display (default value: -1: no limits)\n     * @param int       $options human diff options\n     *\n     * @throws Exception\n     *\n     * @return string\n     */\n    public function forHumans($syntax = null, $short = false, $parts = -1, $options = null)\n    {\n        [$syntax, $short, $parts, $options, $join, $aUnit, $altNumbers, $interpolations, $minimumUnit, $skip] = $this\n            ->getForHumansParameters($syntax, $short, $parts, $options);\n\n        $interval = [];\n\n        $syntax = (int) ($syntax ?? CarbonInterface::DIFF_ABSOLUTE);\n        $absolute = $syntax === CarbonInterface::DIFF_ABSOLUTE;\n        $relativeToNow = $syntax === CarbonInterface::DIFF_RELATIVE_TO_NOW;\n        $count = 1;\n        $unit = $short ? 's' : 'second';\n        $isFuture = $this->invert === 1;\n        $transId = $relativeToNow ? ($isFuture ? 'from_now' : 'ago') : ($isFuture ? 'after' : 'before');\n        $declensionMode = null;\n\n        /** @var \\Symfony\\Component\\Translation\\Translator $translator */\n        $translator = $this->getLocalTranslator();\n\n        $handleDeclensions = function ($unit, $count, $index = 0, $parts = 1) use ($interpolations, $transId, $translator, $altNumbers, $absolute, &$declensionMode) {\n            if (!$absolute) {\n                $declensionMode = $declensionMode ?? $this->translate($transId.'_mode');\n\n                if ($this->needsDeclension($declensionMode, $index, $parts)) {\n                    // Some languages have special pluralization for past and future tense.\n                    $key = $unit.'_'.$transId;\n                    $result = $this->translate($key, $interpolations, $count, $translator, $altNumbers);\n\n                    if ($result !== $key) {\n                        return $result;\n                    }\n                }\n            }\n\n            $result = $this->translate($unit, $interpolations, $count, $translator, $altNumbers);\n\n            if ($result !== $unit) {\n                return $result;\n            }\n\n            return null;\n        };\n\n        $intervalValues = $this;\n        $method = static::getRoundingMethodFromOptions($options);\n\n        if ($method) {\n            $previousCount = INF;\n\n            while (\n                \\count($intervalValues->getNonZeroValues()) > $parts &&\n                ($count = \\count($keys = array_keys($intervalValues->getValuesSequence()))) > 1\n            ) {\n                $index = min($count, $previousCount - 1) - 2;\n\n                if ($index < 0) {\n                    break;\n                }\n\n                $intervalValues = $this->copy()->roundUnit(\n                    $keys[$index],\n                    1,\n                    $method\n                );\n                $previousCount = $count;\n            }\n        }\n\n        $diffIntervalArray = [\n            ['value' => $intervalValues->years,             'unit' => 'year',        'unitShort' => 'y'],\n            ['value' => $intervalValues->months,            'unit' => 'month',       'unitShort' => 'm'],\n            ['value' => $intervalValues->weeks,             'unit' => 'week',        'unitShort' => 'w'],\n            ['value' => $intervalValues->daysExcludeWeeks,  'unit' => 'day',         'unitShort' => 'd'],\n            ['value' => $intervalValues->hours,             'unit' => 'hour',        'unitShort' => 'h'],\n            ['value' => $intervalValues->minutes,           'unit' => 'minute',      'unitShort' => 'min'],\n            ['value' => $intervalValues->seconds,           'unit' => 'second',      'unitShort' => 's'],\n            ['value' => $intervalValues->milliseconds,      'unit' => 'millisecond', 'unitShort' => 'ms'],\n            ['value' => $intervalValues->microExcludeMilli, 'unit' => 'microsecond', 'unitShort' => 'µs'],\n        ];\n\n        if (!empty($skip)) {\n            foreach ($diffIntervalArray as $index => &$unitData) {\n                $nextIndex = $index + 1;\n\n                if ($unitData['value'] &&\n                    isset($diffIntervalArray[$nextIndex]) &&\n                    \\count(array_intersect([$unitData['unit'], $unitData['unit'].'s', $unitData['unitShort']], $skip))\n                ) {\n                    $diffIntervalArray[$nextIndex]['value'] += $unitData['value'] *\n                        self::getFactorWithDefault($diffIntervalArray[$nextIndex]['unit'], $unitData['unit']);\n                    $unitData['value'] = 0;\n                }\n            }\n        }\n\n        $transChoice = function ($short, $unitData, $index, $parts) use ($absolute, $handleDeclensions, $translator, $aUnit, $altNumbers, $interpolations) {\n            $count = $unitData['value'];\n\n            if ($short) {\n                $result = $handleDeclensions($unitData['unitShort'], $count, $index, $parts);\n\n                if ($result !== null) {\n                    return $result;\n                }\n            } elseif ($aUnit) {\n                $result = $handleDeclensions('a_'.$unitData['unit'], $count, $index, $parts);\n\n                if ($result !== null) {\n                    return $result;\n                }\n            }\n\n            if (!$absolute) {\n                return $handleDeclensions($unitData['unit'], $count, $index, $parts);\n            }\n\n            return $this->translate($unitData['unit'], $interpolations, $count, $translator, $altNumbers);\n        };\n\n        $fallbackUnit = ['second', 's'];\n\n        foreach ($diffIntervalArray as $diffIntervalData) {\n            if ($diffIntervalData['value'] > 0) {\n                $unit = $short ? $diffIntervalData['unitShort'] : $diffIntervalData['unit'];\n                $count = $diffIntervalData['value'];\n                $interval[] = [$short, $diffIntervalData];\n            } elseif ($options & CarbonInterface::SEQUENTIAL_PARTS_ONLY && \\count($interval) > 0) {\n                break;\n            }\n\n            // break the loop after we get the required number of parts in array\n            if (\\count($interval) >= $parts) {\n                break;\n            }\n\n            // break the loop after we have reached the minimum unit\n            if (\\in_array($minimumUnit, [$diffIntervalData['unit'], $diffIntervalData['unitShort']], true)) {\n                $fallbackUnit = [$diffIntervalData['unit'], $diffIntervalData['unitShort']];\n\n                break;\n            }\n        }\n\n        $actualParts = \\count($interval);\n\n        foreach ($interval as $index => &$item) {\n            $item = $transChoice($item[0], $item[1], $index, $actualParts);\n        }\n\n        if (\\count($interval) === 0) {\n            if ($relativeToNow && $options & CarbonInterface::JUST_NOW) {\n                $key = 'diff_now';\n                $translation = $this->translate($key, $interpolations, null, $translator);\n\n                if ($translation !== $key) {\n                    return $translation;\n                }\n            }\n\n            $count = $options & CarbonInterface::NO_ZERO_DIFF ? 1 : 0;\n            $unit = $fallbackUnit[$short ? 1 : 0];\n            $interval[] = $this->translate($unit, $interpolations, $count, $translator, $altNumbers);\n        }\n\n        // join the interval parts by a space\n        $time = $join($interval);\n\n        unset($diffIntervalArray, $interval);\n\n        if ($absolute) {\n            return $time;\n        }\n\n        $isFuture = $this->invert === 1;\n\n        $transId = $relativeToNow ? ($isFuture ? 'from_now' : 'ago') : ($isFuture ? 'after' : 'before');\n\n        if ($parts === 1) {\n            if ($relativeToNow && $unit === 'day') {\n                if ($count === 1 && $options & CarbonInterface::ONE_DAY_WORDS) {\n                    $key = $isFuture ? 'diff_tomorrow' : 'diff_yesterday';\n                    $translation = $this->translate($key, $interpolations, null, $translator);\n\n                    if ($translation !== $key) {\n                        return $translation;\n                    }\n                }\n\n                if ($count === 2 && $options & CarbonInterface::TWO_DAY_WORDS) {\n                    $key = $isFuture ? 'diff_after_tomorrow' : 'diff_before_yesterday';\n                    $translation = $this->translate($key, $interpolations, null, $translator);\n\n                    if ($translation !== $key) {\n                        return $translation;\n                    }\n                }\n            }\n\n            $aTime = $aUnit ? $handleDeclensions('a_'.$unit, $count) : null;\n\n            $time = $aTime ?: $handleDeclensions($unit, $count) ?: $time;\n        }\n\n        $time = [':time' => $time];\n\n        return $this->translate($transId, array_merge($time, $interpolations, $time), null, $translator);\n    }\n\n    /**\n     * Format the instance as a string using the forHumans() function.\n     *\n     * @throws Exception\n     *\n     * @return string\n     */\n    public function __toString()\n    {\n        $format = $this->localToStringFormat ?? static::$toStringFormat;\n\n        if (!$format) {\n            return $this->forHumans();\n        }\n\n        if ($format instanceof Closure) {\n            return $format($this);\n        }\n\n        return $this->format($format);\n    }\n\n    /**\n     * Return native DateInterval PHP object matching the current instance.\n     *\n     * @example\n     * ```\n     * var_dump(CarbonInterval::hours(2)->toDateInterval());\n     * ```\n     *\n     * @return DateInterval\n     */\n    public function toDateInterval()\n    {\n        return self::castIntervalToClass($this, DateInterval::class);\n    }\n\n    /**\n     * Convert the interval to a CarbonPeriod.\n     *\n     * @param DateTimeInterface|string|int ...$params Start date, [end date or recurrences] and optional settings.\n     *\n     * @return CarbonPeriod\n     */\n    public function toPeriod(...$params)\n    {\n        if ($this->tzName) {\n            $tz = \\is_string($this->tzName) ? new DateTimeZone($this->tzName) : $this->tzName;\n\n            if ($tz instanceof DateTimeZone) {\n                array_unshift($params, $tz);\n            }\n        }\n\n        return CarbonPeriod::create($this, ...$params);\n    }\n\n    /**\n     * Invert the interval.\n     *\n     * @param bool|int $inverted if a parameter is passed, the passed value cast as 1 or 0 is used\n     *                           as the new value of the ->invert property.\n     *\n     * @return $this\n     */\n    public function invert($inverted = null)\n    {\n        $this->invert = (\\func_num_args() === 0 ? !$this->invert : $inverted) ? 1 : 0;\n\n        return $this;\n    }\n\n    protected function solveNegativeInterval()\n    {\n        if (!$this->isEmpty() && $this->years <= 0 && $this->months <= 0 && $this->dayz <= 0 && $this->hours <= 0 && $this->minutes <= 0 && $this->seconds <= 0 && $this->microseconds <= 0) {\n            $this->years *= -1;\n            $this->months *= -1;\n            $this->dayz *= -1;\n            $this->hours *= -1;\n            $this->minutes *= -1;\n            $this->seconds *= -1;\n            $this->microseconds *= -1;\n            $this->invert();\n        }\n\n        return $this;\n    }\n\n    /**\n     * Add the passed interval to the current instance.\n     *\n     * @param string|DateInterval $unit\n     * @param int|float           $value\n     *\n     * @return $this\n     */\n    public function add($unit, $value = 1)\n    {\n        if (is_numeric($unit)) {\n            [$value, $unit] = [$unit, $value];\n        }\n\n        if (\\is_string($unit) && !preg_match('/^\\s*\\d/', $unit)) {\n            $unit = \"$value $unit\";\n            $value = 1;\n        }\n\n        $interval = static::make($unit);\n\n        if (!$interval) {\n            throw new InvalidIntervalException('This type of data cannot be added/subtracted.');\n        }\n\n        if ($value !== 1) {\n            $interval->times($value);\n        }\n\n        $sign = ($this->invert === 1) !== ($interval->invert === 1) ? -1 : 1;\n        $this->years += $interval->y * $sign;\n        $this->months += $interval->m * $sign;\n        $this->dayz += ($interval->days === false ? $interval->d : $interval->days) * $sign;\n        $this->hours += $interval->h * $sign;\n        $this->minutes += $interval->i * $sign;\n        $this->seconds += $interval->s * $sign;\n        $this->microseconds += $interval->microseconds * $sign;\n\n        $this->solveNegativeInterval();\n\n        return $this;\n    }\n\n    /**\n     * Subtract the passed interval to the current instance.\n     *\n     * @param string|DateInterval $unit\n     * @param int|float           $value\n     *\n     * @return $this\n     */\n    public function sub($unit, $value = 1)\n    {\n        if (is_numeric($unit)) {\n            [$value, $unit] = [$unit, $value];\n        }\n\n        return $this->add($unit, -(float) $value);\n    }\n\n    /**\n     * Subtract the passed interval to the current instance.\n     *\n     * @param string|DateInterval $unit\n     * @param int|float           $value\n     *\n     * @return $this\n     */\n    public function subtract($unit, $value = 1)\n    {\n        return $this->sub($unit, $value);\n    }\n\n    /**\n     * Add given parameters to the current interval.\n     *\n     * @param int       $years\n     * @param int       $months\n     * @param int|float $weeks\n     * @param int|float $days\n     * @param int|float $hours\n     * @param int|float $minutes\n     * @param int|float $seconds\n     * @param int|float $microseconds\n     *\n     * @return $this\n     */\n    public function plus(\n        $years = 0,\n        $months = 0,\n        $weeks = 0,\n        $days = 0,\n        $hours = 0,\n        $minutes = 0,\n        $seconds = 0,\n        $microseconds = 0\n    ): self {\n        return $this->add(\"\n            $years years $months months $weeks weeks $days days\n            $hours hours $minutes minutes $seconds seconds $microseconds microseconds\n        \");\n    }\n\n    /**\n     * Add given parameters to the current interval.\n     *\n     * @param int       $years\n     * @param int       $months\n     * @param int|float $weeks\n     * @param int|float $days\n     * @param int|float $hours\n     * @param int|float $minutes\n     * @param int|float $seconds\n     * @param int|float $microseconds\n     *\n     * @return $this\n     */\n    public function minus(\n        $years = 0,\n        $months = 0,\n        $weeks = 0,\n        $days = 0,\n        $hours = 0,\n        $minutes = 0,\n        $seconds = 0,\n        $microseconds = 0\n    ): self {\n        return $this->sub(\"\n            $years years $months months $weeks weeks $days days\n            $hours hours $minutes minutes $seconds seconds $microseconds microseconds\n        \");\n    }\n\n    /**\n     * Multiply current instance given number of times. times() is naive, it multiplies each unit\n     * (so day can be greater than 31, hour can be greater than 23, etc.) and the result is rounded\n     * separately for each unit.\n     *\n     * Use times() when you want a fast and approximated calculation that does not cascade units.\n     *\n     * For a precise and cascaded calculation,\n     *\n     * @see multiply()\n     *\n     * @param float|int $factor\n     *\n     * @return $this\n     */\n    public function times($factor)\n    {\n        if ($factor < 0) {\n            $this->invert = $this->invert ? 0 : 1;\n            $factor = -$factor;\n        }\n\n        $this->years = (int) round($this->years * $factor);\n        $this->months = (int) round($this->months * $factor);\n        $this->dayz = (int) round($this->dayz * $factor);\n        $this->hours = (int) round($this->hours * $factor);\n        $this->minutes = (int) round($this->minutes * $factor);\n        $this->seconds = (int) round($this->seconds * $factor);\n        $this->microseconds = (int) round($this->microseconds * $factor);\n\n        return $this;\n    }\n\n    /**\n     * Divide current instance by a given divider. shares() is naive, it divides each unit separately\n     * and the result is rounded for each unit. So 5 hours and 20 minutes shared by 3 becomes 2 hours\n     * and 7 minutes.\n     *\n     * Use shares() when you want a fast and approximated calculation that does not cascade units.\n     *\n     * For a precise and cascaded calculation,\n     *\n     * @see divide()\n     *\n     * @param float|int $divider\n     *\n     * @return $this\n     */\n    public function shares($divider)\n    {\n        return $this->times(1 / $divider);\n    }\n\n    protected function copyProperties(self $interval, $ignoreSign = false)\n    {\n        $this->years = $interval->years;\n        $this->months = $interval->months;\n        $this->dayz = $interval->dayz;\n        $this->hours = $interval->hours;\n        $this->minutes = $interval->minutes;\n        $this->seconds = $interval->seconds;\n        $this->microseconds = $interval->microseconds;\n\n        if (!$ignoreSign) {\n            $this->invert = $interval->invert;\n        }\n\n        return $this;\n    }\n\n    /**\n     * Multiply and cascade current instance by a given factor.\n     *\n     * @param float|int $factor\n     *\n     * @return $this\n     */\n    public function multiply($factor)\n    {\n        if ($factor < 0) {\n            $this->invert = $this->invert ? 0 : 1;\n            $factor = -$factor;\n        }\n\n        $yearPart = (int) floor($this->years * $factor); // Split calculation to prevent imprecision\n\n        if ($yearPart) {\n            $this->years -= $yearPart / $factor;\n        }\n\n        return $this->copyProperties(\n            static::create($yearPart)\n                ->microseconds(abs($this->totalMicroseconds) * $factor)\n                ->cascade(),\n            true\n        );\n    }\n\n    /**\n     * Divide and cascade current instance by a given divider.\n     *\n     * @param float|int $divider\n     *\n     * @return $this\n     */\n    public function divide($divider)\n    {\n        return $this->multiply(1 / $divider);\n    }\n\n    /**\n     * Get the interval_spec string of a date interval.\n     *\n     * @param DateInterval $interval\n     *\n     * @return string\n     */\n    public static function getDateIntervalSpec(DateInterval $interval, bool $microseconds = false, array $skip = [])\n    {\n        $date = array_filter([\n            static::PERIOD_YEARS => abs($interval->y),\n            static::PERIOD_MONTHS => abs($interval->m),\n            static::PERIOD_DAYS => abs($interval->d),\n        ]);\n\n        if (\n            $interval->days >= CarbonInterface::DAYS_PER_WEEK * CarbonInterface::WEEKS_PER_MONTH &&\n            (!isset($date[static::PERIOD_YEARS]) || \\count(array_intersect(['y', 'year', 'years'], $skip))) &&\n            (!isset($date[static::PERIOD_MONTHS]) || \\count(array_intersect(['m', 'month', 'months'], $skip)))\n        ) {\n            $date = [\n                static::PERIOD_DAYS => abs($interval->days),\n            ];\n        }\n\n        $seconds = abs($interval->s);\n        if ($microseconds && $interval->f > 0) {\n            $seconds = \\sprintf('%d.%06d', $seconds, abs($interval->f) * 1000000);\n        }\n\n        $time = array_filter([\n            static::PERIOD_HOURS => abs($interval->h),\n            static::PERIOD_MINUTES => abs($interval->i),\n            static::PERIOD_SECONDS => $seconds,\n        ]);\n\n        $specString = static::PERIOD_PREFIX;\n\n        foreach ($date as $key => $value) {\n            $specString .= $value.$key;\n        }\n\n        if (\\count($time) > 0) {\n            $specString .= static::PERIOD_TIME_PREFIX;\n            foreach ($time as $key => $value) {\n                $specString .= $value.$key;\n            }\n        }\n\n        return $specString === static::PERIOD_PREFIX ? 'PT0S' : $specString;\n    }\n\n    /**\n     * Get the interval_spec string.\n     *\n     * @return string\n     */\n    public function spec(bool $microseconds = false)\n    {\n        return static::getDateIntervalSpec($this, $microseconds);\n    }\n\n    /**\n     * Comparing 2 date intervals.\n     *\n     * @param DateInterval $first\n     * @param DateInterval $second\n     *\n     * @return int\n     */\n    public static function compareDateIntervals(DateInterval $first, DateInterval $second)\n    {\n        $current = Carbon::now();\n        $passed = $current->avoidMutation()->add($second);\n        $current->add($first);\n\n        if ($current < $passed) {\n            return -1;\n        }\n        if ($current > $passed) {\n            return 1;\n        }\n\n        return 0;\n    }\n\n    /**\n     * Comparing with passed interval.\n     *\n     * @param DateInterval $interval\n     *\n     * @return int\n     */\n    public function compare(DateInterval $interval)\n    {\n        return static::compareDateIntervals($this, $interval);\n    }\n\n    private function invertCascade(array $values)\n    {\n        return $this->set(array_map(function ($value) {\n            return -$value;\n        }, $values))->doCascade(true)->invert();\n    }\n\n    private function doCascade(bool $deep)\n    {\n        $originalData = $this->toArray();\n        $originalData['milliseconds'] = (int) ($originalData['microseconds'] / static::getMicrosecondsPerMillisecond());\n        $originalData['microseconds'] = $originalData['microseconds'] % static::getMicrosecondsPerMillisecond();\n        $originalData['weeks'] = (int) ($this->d / static::getDaysPerWeek());\n        $originalData['daysExcludeWeeks'] = fmod($this->d, static::getDaysPerWeek());\n        unset($originalData['days']);\n        $newData = $originalData;\n        $previous = [];\n\n        foreach (self::getFlipCascadeFactors() as $source => [$target, $factor]) {\n            foreach (['source', 'target'] as $key) {\n                if ($$key === 'dayz') {\n                    $$key = 'daysExcludeWeeks';\n                }\n            }\n\n            $value = $newData[$source];\n            $modulo = fmod($factor + fmod($value, $factor), $factor);\n            $newData[$source] = $modulo;\n            $newData[$target] += ($value - $modulo) / $factor;\n\n            $decimalPart = fmod($newData[$source], 1);\n\n            if ($decimalPart !== 0.0) {\n                $unit = $source;\n\n                foreach ($previous as [$subUnit, $subFactor]) {\n                    $newData[$unit] -= $decimalPart;\n                    $newData[$subUnit] += $decimalPart * $subFactor;\n                    $decimalPart = fmod($newData[$subUnit], 1);\n\n                    if ($decimalPart === 0.0) {\n                        break;\n                    }\n\n                    $unit = $subUnit;\n                }\n            }\n\n            array_unshift($previous, [$source, $factor]);\n        }\n\n        $positive = null;\n\n        if (!$deep) {\n            foreach ($newData as $value) {\n                if ($value) {\n                    if ($positive === null) {\n                        $positive = ($value > 0);\n\n                        continue;\n                    }\n\n                    if (($value > 0) !== $positive) {\n                        return $this->invertCascade($originalData)\n                            ->solveNegativeInterval();\n                    }\n                }\n            }\n        }\n\n        return $this->set($newData)\n            ->solveNegativeInterval();\n    }\n\n    /**\n     * Convert overflowed values into bigger units.\n     *\n     * @return $this\n     */\n    public function cascade()\n    {\n        return $this->doCascade(false);\n    }\n\n    public function hasNegativeValues(): bool\n    {\n        foreach ($this->toArray() as $value) {\n            if ($value < 0) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    public function hasPositiveValues(): bool\n    {\n        foreach ($this->toArray() as $value) {\n            if ($value > 0) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * Get amount of given unit equivalent to the interval.\n     *\n     * @param string $unit\n     *\n     * @throws UnknownUnitException|UnitNotConfiguredException\n     *\n     * @return float\n     */\n    public function total($unit)\n    {\n        $realUnit = $unit = strtolower($unit);\n\n        if (\\in_array($unit, ['days', 'weeks'])) {\n            $realUnit = 'dayz';\n        } elseif (!\\in_array($unit, ['microseconds', 'milliseconds', 'seconds', 'minutes', 'hours', 'dayz', 'months', 'years'])) {\n            throw new UnknownUnitException($unit);\n        }\n\n        $result = 0;\n        $cumulativeFactor = 0;\n        $unitFound = false;\n        $factors = self::getFlipCascadeFactors();\n        $daysPerWeek = (int) static::getDaysPerWeek();\n\n        $values = [\n            'years' => $this->years,\n            'months' => $this->months,\n            'weeks' => (int) ($this->d / $daysPerWeek),\n            'dayz' => fmod($this->d, $daysPerWeek),\n            'hours' => $this->hours,\n            'minutes' => $this->minutes,\n            'seconds' => $this->seconds,\n            'milliseconds' => (int) ($this->microseconds / Carbon::MICROSECONDS_PER_MILLISECOND),\n            'microseconds' => $this->microseconds % Carbon::MICROSECONDS_PER_MILLISECOND,\n        ];\n\n        if (isset($factors['dayz']) && $factors['dayz'][0] !== 'weeks') {\n            $values['dayz'] += $values['weeks'] * $daysPerWeek;\n            $values['weeks'] = 0;\n        }\n\n        foreach ($factors as $source => [$target, $factor]) {\n            if ($source === $realUnit) {\n                $unitFound = true;\n                $value = $values[$source];\n                $result += $value;\n                $cumulativeFactor = 1;\n            }\n\n            if ($factor === false) {\n                if ($unitFound) {\n                    break;\n                }\n\n                $result = 0;\n                $cumulativeFactor = 0;\n\n                continue;\n            }\n\n            if ($target === $realUnit) {\n                $unitFound = true;\n            }\n\n            if ($cumulativeFactor) {\n                $cumulativeFactor *= $factor;\n                $result += $values[$target] * $cumulativeFactor;\n\n                continue;\n            }\n\n            $value = $values[$source];\n\n            $result = ($result + $value) / $factor;\n        }\n\n        if (isset($target) && !$cumulativeFactor) {\n            $result += $values[$target];\n        }\n\n        if (!$unitFound) {\n            throw new UnitNotConfiguredException($unit);\n        }\n\n        if ($this->invert) {\n            $result *= -1;\n        }\n\n        if ($unit === 'weeks') {\n            $result /= $daysPerWeek;\n        }\n\n        // Cast as int numbers with no decimal part\n        return fmod($result, 1) === 0.0 ? (int) $result : $result;\n    }\n\n    /**\n     * Determines if the instance is equal to another\n     *\n     * @param CarbonInterval|DateInterval|mixed $interval\n     *\n     * @see equalTo()\n     *\n     * @return bool\n     */\n    public function eq($interval): bool\n    {\n        return $this->equalTo($interval);\n    }\n\n    /**\n     * Determines if the instance is equal to another\n     *\n     * @param CarbonInterval|DateInterval|mixed $interval\n     *\n     * @return bool\n     */\n    public function equalTo($interval): bool\n    {\n        $interval = $this->resolveInterval($interval);\n\n        return $interval !== null && $this->totalMicroseconds === $interval->totalMicroseconds;\n    }\n\n    /**\n     * Determines if the instance is not equal to another\n     *\n     * @param CarbonInterval|DateInterval|mixed $interval\n     *\n     * @see notEqualTo()\n     *\n     * @return bool\n     */\n    public function ne($interval): bool\n    {\n        return $this->notEqualTo($interval);\n    }\n\n    /**\n     * Determines if the instance is not equal to another\n     *\n     * @param CarbonInterval|DateInterval|mixed $interval\n     *\n     * @return bool\n     */\n    public function notEqualTo($interval): bool\n    {\n        return !$this->eq($interval);\n    }\n\n    /**\n     * Determines if the instance is greater (longer) than another\n     *\n     * @param CarbonInterval|DateInterval|mixed $interval\n     *\n     * @see greaterThan()\n     *\n     * @return bool\n     */\n    public function gt($interval): bool\n    {\n        return $this->greaterThan($interval);\n    }\n\n    /**\n     * Determines if the instance is greater (longer) than another\n     *\n     * @param CarbonInterval|DateInterval|mixed $interval\n     *\n     * @return bool\n     */\n    public function greaterThan($interval): bool\n    {\n        $interval = $this->resolveInterval($interval);\n\n        return $interval === null || $this->totalMicroseconds > $interval->totalMicroseconds;\n    }\n\n    /**\n     * Determines if the instance is greater (longer) than or equal to another\n     *\n     * @param CarbonInterval|DateInterval|mixed $interval\n     *\n     * @see greaterThanOrEqualTo()\n     *\n     * @return bool\n     */\n    public function gte($interval): bool\n    {\n        return $this->greaterThanOrEqualTo($interval);\n    }\n\n    /**\n     * Determines if the instance is greater (longer) than or equal to another\n     *\n     * @param CarbonInterval|DateInterval|mixed $interval\n     *\n     * @return bool\n     */\n    public function greaterThanOrEqualTo($interval): bool\n    {\n        return $this->greaterThan($interval) || $this->equalTo($interval);\n    }\n\n    /**\n     * Determines if the instance is less (shorter) than another\n     *\n     * @param CarbonInterval|DateInterval|mixed $interval\n     *\n     * @see lessThan()\n     *\n     * @return bool\n     */\n    public function lt($interval): bool\n    {\n        return $this->lessThan($interval);\n    }\n\n    /**\n     * Determines if the instance is less (shorter) than another\n     *\n     * @param CarbonInterval|DateInterval|mixed $interval\n     *\n     * @return bool\n     */\n    public function lessThan($interval): bool\n    {\n        $interval = $this->resolveInterval($interval);\n\n        return $interval !== null && $this->totalMicroseconds < $interval->totalMicroseconds;\n    }\n\n    /**\n     * Determines if the instance is less (shorter) than or equal to another\n     *\n     * @param CarbonInterval|DateInterval|mixed $interval\n     *\n     * @see lessThanOrEqualTo()\n     *\n     * @return bool\n     */\n    public function lte($interval): bool\n    {\n        return $this->lessThanOrEqualTo($interval);\n    }\n\n    /**\n     * Determines if the instance is less (shorter) than or equal to another\n     *\n     * @param CarbonInterval|DateInterval|mixed $interval\n     *\n     * @return bool\n     */\n    public function lessThanOrEqualTo($interval): bool\n    {\n        return $this->lessThan($interval) || $this->equalTo($interval);\n    }\n\n    /**\n     * Determines if the instance is between two others.\n     *\n     * The third argument allow you to specify if bounds are included or not (true by default)\n     * but for when you including/excluding bounds may produce different results in your application,\n     * we recommend to use the explicit methods ->betweenIncluded() or ->betweenExcluded() instead.\n     *\n     * @example\n     * ```\n     * CarbonInterval::hours(48)->between(CarbonInterval::day(), CarbonInterval::days(3)); // true\n     * CarbonInterval::hours(48)->between(CarbonInterval::day(), CarbonInterval::hours(36)); // false\n     * CarbonInterval::hours(48)->between(CarbonInterval::day(), CarbonInterval::days(2)); // true\n     * CarbonInterval::hours(48)->between(CarbonInterval::day(), CarbonInterval::days(2), false); // false\n     * ```\n     *\n     * @param CarbonInterval|DateInterval|mixed $interval1\n     * @param CarbonInterval|DateInterval|mixed $interval2\n     * @param bool                              $equal     Indicates if an equal to comparison should be done\n     *\n     * @return bool\n     */\n    public function between($interval1, $interval2, $equal = true): bool\n    {\n        return $equal\n            ? $this->greaterThanOrEqualTo($interval1) && $this->lessThanOrEqualTo($interval2)\n            : $this->greaterThan($interval1) && $this->lessThan($interval2);\n    }\n\n    /**\n     * Determines if the instance is between two others, bounds excluded.\n     *\n     * @example\n     * ```\n     * CarbonInterval::hours(48)->betweenExcluded(CarbonInterval::day(), CarbonInterval::days(3)); // true\n     * CarbonInterval::hours(48)->betweenExcluded(CarbonInterval::day(), CarbonInterval::hours(36)); // false\n     * CarbonInterval::hours(48)->betweenExcluded(CarbonInterval::day(), CarbonInterval::days(2)); // true\n     * ```\n     *\n     * @param CarbonInterval|DateInterval|mixed $interval1\n     * @param CarbonInterval|DateInterval|mixed $interval2\n     *\n     * @return bool\n     */\n    public function betweenIncluded($interval1, $interval2): bool\n    {\n        return $this->between($interval1, $interval2, true);\n    }\n\n    /**\n     * Determines if the instance is between two others, bounds excluded.\n     *\n     * @example\n     * ```\n     * CarbonInterval::hours(48)->betweenExcluded(CarbonInterval::day(), CarbonInterval::days(3)); // true\n     * CarbonInterval::hours(48)->betweenExcluded(CarbonInterval::day(), CarbonInterval::hours(36)); // false\n     * CarbonInterval::hours(48)->betweenExcluded(CarbonInterval::day(), CarbonInterval::days(2)); // false\n     * ```\n     *\n     * @param CarbonInterval|DateInterval|mixed $interval1\n     * @param CarbonInterval|DateInterval|mixed $interval2\n     *\n     * @return bool\n     */\n    public function betweenExcluded($interval1, $interval2): bool\n    {\n        return $this->between($interval1, $interval2, false);\n    }\n\n    /**\n     * Determines if the instance is between two others\n     *\n     * @example\n     * ```\n     * CarbonInterval::hours(48)->isBetween(CarbonInterval::day(), CarbonInterval::days(3)); // true\n     * CarbonInterval::hours(48)->isBetween(CarbonInterval::day(), CarbonInterval::hours(36)); // false\n     * CarbonInterval::hours(48)->isBetween(CarbonInterval::day(), CarbonInterval::days(2)); // true\n     * CarbonInterval::hours(48)->isBetween(CarbonInterval::day(), CarbonInterval::days(2), false); // false\n     * ```\n     *\n     * @param CarbonInterval|DateInterval|mixed $interval1\n     * @param CarbonInterval|DateInterval|mixed $interval2\n     * @param bool                              $equal     Indicates if an equal to comparison should be done\n     *\n     * @return bool\n     */\n    public function isBetween($interval1, $interval2, $equal = true): bool\n    {\n        return $this->between($interval1, $interval2, $equal);\n    }\n\n    /**\n     * Round the current instance at the given unit with given precision if specified and the given function.\n     *\n     * @param string                             $unit\n     * @param float|int|string|DateInterval|null $precision\n     * @param string                             $function\n     *\n     * @throws Exception\n     *\n     * @return $this\n     */\n    public function roundUnit($unit, $precision = 1, $function = 'round')\n    {\n        if (static::getCascadeFactors() !== static::getDefaultCascadeFactors()) {\n            $value = $function($this->total($unit) / $precision) * $precision;\n            $inverted = $value < 0;\n\n            return $this->copyProperties(self::fromString(\n                number_format(abs($value), 12, '.', '').' '.$unit\n            )->invert($inverted)->cascade());\n        }\n\n        $base = CarbonImmutable::parse('2000-01-01 00:00:00', 'UTC')\n            ->roundUnit($unit, $precision, $function);\n        $next = $base->add($this);\n        $inverted = $next < $base;\n\n        if ($inverted) {\n            $next = $base->sub($this);\n        }\n\n        $this->copyProperties(\n            $next\n                ->roundUnit($unit, $precision, $function)\n                ->diffAsCarbonInterval($base)\n        );\n\n        return $this->invert($inverted);\n    }\n\n    /**\n     * Truncate the current instance at the given unit with given precision if specified.\n     *\n     * @param string                             $unit\n     * @param float|int|string|DateInterval|null $precision\n     *\n     * @throws Exception\n     *\n     * @return $this\n     */\n    public function floorUnit($unit, $precision = 1)\n    {\n        return $this->roundUnit($unit, $precision, 'floor');\n    }\n\n    /**\n     * Ceil the current instance at the given unit with given precision if specified.\n     *\n     * @param string                             $unit\n     * @param float|int|string|DateInterval|null $precision\n     *\n     * @throws Exception\n     *\n     * @return $this\n     */\n    public function ceilUnit($unit, $precision = 1)\n    {\n        return $this->roundUnit($unit, $precision, 'ceil');\n    }\n\n    /**\n     * Round the current instance second with given precision if specified.\n     *\n     * @param float|int|string|DateInterval|null $precision\n     * @param string                             $function\n     *\n     * @throws Exception\n     *\n     * @return $this\n     */\n    public function round($precision = 1, $function = 'round')\n    {\n        return $this->roundWith($precision, $function);\n    }\n\n    /**\n     * Round the current instance second with given precision if specified.\n     *\n     * @param float|int|string|DateInterval|null $precision\n     *\n     * @throws Exception\n     *\n     * @return $this\n     */\n    public function floor($precision = 1)\n    {\n        return $this->round($precision, 'floor');\n    }\n\n    /**\n     * Ceil the current instance second with given precision if specified.\n     *\n     * @param float|int|string|DateInterval|null $precision\n     *\n     * @throws Exception\n     *\n     * @return $this\n     */\n    public function ceil($precision = 1)\n    {\n        return $this->round($precision, 'ceil');\n    }\n\n    private function needsDeclension(string $mode, int $index, int $parts): bool\n    {\n        switch ($mode) {\n            case 'last':\n                return $index === $parts - 1;\n            default:\n                return true;\n        }\n    }\n\n    private function checkIntegerValue(string $name, $value)\n    {\n        if (\\is_int($value)) {\n            return;\n        }\n\n        $this->assertSafeForInteger($name, $value);\n\n        if (\\is_float($value) && (((float) (int) $value) === $value)) {\n            return;\n        }\n\n        if (!self::$floatSettersEnabled) {\n            $type = \\gettype($value);\n            @trigger_error(\n                \"Since 2.70.0, it's deprecated to pass $type value for $name.\\n\".\n                \"It's truncated when stored as an integer interval unit.\\n\".\n                \"From 3.0.0, decimal part will no longer be truncated and will be cascaded to smaller units.\\n\".\n                \"- To maintain the current behavior, use explicit cast: $name((int) \\$value)\\n\".\n                \"- To adopt the new behavior globally, call CarbonInterval::enableFloatSetters()\\n\",\n                \\E_USER_DEPRECATED\n            );\n        }\n    }\n\n    /**\n     * Throw an exception if precision loss when storing the given value as an integer would be >= 1.0.\n     */\n    private function assertSafeForInteger(string $name, $value)\n    {\n        if ($value && !\\is_int($value) && ($value >= 0x7fffffffffffffff || $value <= -0x7fffffffffffffff)) {\n            throw new OutOfRangeException($name, -0x7fffffffffffffff, 0x7fffffffffffffff, $value);\n        }\n    }\n\n    private function handleDecimalPart(string $unit, $value, $integerValue)\n    {\n        if (self::$floatSettersEnabled) {\n            $floatValue = (float) $value;\n            $base = (float) $integerValue;\n\n            if ($floatValue === $base) {\n                return;\n            }\n\n            $units = [\n                'y' => 'year',\n                'm' => 'month',\n                'd' => 'day',\n                'h' => 'hour',\n                'i' => 'minute',\n                's' => 'second',\n            ];\n            $upper = true;\n\n            foreach ($units as $property => $name) {\n                if ($name === $unit) {\n                    $upper = false;\n\n                    continue;\n                }\n\n                if (!$upper && $this->$property !== 0) {\n                    throw new RuntimeException(\n                        \"You cannot set $unit to a float value as $name would be overridden, \".\n                        'set it first to 0 explicitly if you really want to erase its value'\n                    );\n                }\n            }\n\n            $this->add($unit, $floatValue - $base);\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/CarbonPeriod.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon;\n\nuse Carbon\\Exceptions\\EndLessPeriodException;\nuse Carbon\\Exceptions\\InvalidCastException;\nuse Carbon\\Exceptions\\InvalidIntervalException;\nuse Carbon\\Exceptions\\InvalidPeriodDateException;\nuse Carbon\\Exceptions\\InvalidPeriodParameterException;\nuse Carbon\\Exceptions\\NotACarbonClassException;\nuse Carbon\\Exceptions\\NotAPeriodException;\nuse Carbon\\Exceptions\\UnknownGetterException;\nuse Carbon\\Exceptions\\UnknownMethodException;\nuse Carbon\\Exceptions\\UnreachableException;\nuse Carbon\\Traits\\IntervalRounding;\nuse Carbon\\Traits\\Mixin;\nuse Carbon\\Traits\\Options;\nuse Carbon\\Traits\\ToStringFormat;\nuse Closure;\nuse Countable;\nuse DateInterval;\nuse DatePeriod;\nuse DateTime;\nuse DateTimeImmutable;\nuse DateTimeInterface;\nuse DateTimeZone;\nuse InvalidArgumentException;\nuse Iterator;\nuse JsonSerializable;\nuse ReflectionException;\nuse ReturnTypeWillChange;\nuse RuntimeException;\n\n/**\n * Substitution of DatePeriod with some modifications and many more features.\n *\n * @property-read int|float $recurrences number of recurrences (if end not set).\n * @property-read bool $include_start_date rather the start date is included in the iteration.\n * @property-read bool $include_end_date rather the end date is included in the iteration (if recurrences not set).\n * @property-read CarbonInterface $start Period start date.\n * @property-read CarbonInterface $current Current date from the iteration.\n * @property-read CarbonInterface $end Period end date.\n * @property-read CarbonInterval $interval Underlying date interval instance. Always present, one day by default.\n *\n * @method static static start($date, $inclusive = null) Create instance specifying start date or modify the start date if called on an instance.\n * @method static static since($date, $inclusive = null) Alias for start().\n * @method static static sinceNow($inclusive = null) Create instance with start date set to now or set the start date to now if called on an instance.\n * @method static static end($date = null, $inclusive = null) Create instance specifying end date or modify the end date if called on an instance.\n * @method static static until($date = null, $inclusive = null) Alias for end().\n * @method static static untilNow($inclusive = null) Create instance with end date set to now or set the end date to now if called on an instance.\n * @method static static dates($start, $end = null) Create instance with start and end dates or modify the start and end dates if called on an instance.\n * @method static static between($start, $end = null) Create instance with start and end dates or modify the start and end dates if called on an instance.\n * @method static static recurrences($recurrences = null) Create instance with maximum number of recurrences or modify the number of recurrences if called on an instance.\n * @method static static times($recurrences = null) Alias for recurrences().\n * @method static static options($options = null) Create instance with options or modify the options if called on an instance.\n * @method static static toggle($options, $state = null) Create instance with options toggled on or off, or toggle options if called on an instance.\n * @method static static filter($callback, $name = null) Create instance with filter added to the stack or append a filter if called on an instance.\n * @method static static push($callback, $name = null) Alias for filter().\n * @method static static prepend($callback, $name = null) Create instance with filter prepended to the stack or prepend a filter if called on an instance.\n * @method static static filters(array $filters = []) Create instance with filters stack or replace the whole filters stack if called on an instance.\n * @method static static interval($interval) Create instance with given date interval or modify the interval if called on an instance.\n * @method static static each($interval) Create instance with given date interval or modify the interval if called on an instance.\n * @method static static every($interval) Create instance with given date interval or modify the interval if called on an instance.\n * @method static static step($interval) Create instance with given date interval or modify the interval if called on an instance.\n * @method static static stepBy($interval) Create instance with given date interval or modify the interval if called on an instance.\n * @method static static invert() Create instance with inverted date interval or invert the interval if called on an instance.\n * @method static static years($years = 1) Create instance specifying a number of years for date interval or replace the interval by the given a number of years if called on an instance.\n * @method static static year($years = 1) Alias for years().\n * @method static static months($months = 1) Create instance specifying a number of months for date interval or replace the interval by the given a number of months if called on an instance.\n * @method static static month($months = 1) Alias for months().\n * @method static static weeks($weeks = 1) Create instance specifying a number of weeks for date interval or replace the interval by the given a number of weeks if called on an instance.\n * @method static static week($weeks = 1) Alias for weeks().\n * @method static static days($days = 1) Create instance specifying a number of days for date interval or replace the interval by the given a number of days if called on an instance.\n * @method static static dayz($days = 1) Alias for days().\n * @method static static day($days = 1) Alias for days().\n * @method static static hours($hours = 1) Create instance specifying a number of hours for date interval or replace the interval by the given a number of hours if called on an instance.\n * @method static static hour($hours = 1) Alias for hours().\n * @method static static minutes($minutes = 1) Create instance specifying a number of minutes for date interval or replace the interval by the given a number of minutes if called on an instance.\n * @method static static minute($minutes = 1) Alias for minutes().\n * @method static static seconds($seconds = 1) Create instance specifying a number of seconds for date interval or replace the interval by the given a number of seconds if called on an instance.\n * @method static static second($seconds = 1) Alias for seconds().\n * @method static static milliseconds($milliseconds = 1) Create instance specifying a number of milliseconds for date interval or replace the interval by the given a number of milliseconds if called on an instance.\n * @method static static millisecond($milliseconds = 1) Alias for milliseconds().\n * @method static static microseconds($microseconds = 1) Create instance specifying a number of microseconds for date interval or replace the interval by the given a number of microseconds if called on an instance.\n * @method static static microsecond($microseconds = 1) Alias for microseconds().\n * @method $this roundYear(float $precision = 1, string $function = \"round\") Round the current instance year with given precision using the given function.\n * @method $this roundYears(float $precision = 1, string $function = \"round\") Round the current instance year with given precision using the given function.\n * @method $this floorYear(float $precision = 1) Truncate the current instance year with given precision.\n * @method $this floorYears(float $precision = 1) Truncate the current instance year with given precision.\n * @method $this ceilYear(float $precision = 1) Ceil the current instance year with given precision.\n * @method $this ceilYears(float $precision = 1) Ceil the current instance year with given precision.\n * @method $this roundMonth(float $precision = 1, string $function = \"round\") Round the current instance month with given precision using the given function.\n * @method $this roundMonths(float $precision = 1, string $function = \"round\") Round the current instance month with given precision using the given function.\n * @method $this floorMonth(float $precision = 1) Truncate the current instance month with given precision.\n * @method $this floorMonths(float $precision = 1) Truncate the current instance month with given precision.\n * @method $this ceilMonth(float $precision = 1) Ceil the current instance month with given precision.\n * @method $this ceilMonths(float $precision = 1) Ceil the current instance month with given precision.\n * @method $this roundWeek(float $precision = 1, string $function = \"round\") Round the current instance day with given precision using the given function.\n * @method $this roundWeeks(float $precision = 1, string $function = \"round\") Round the current instance day with given precision using the given function.\n * @method $this floorWeek(float $precision = 1) Truncate the current instance day with given precision.\n * @method $this floorWeeks(float $precision = 1) Truncate the current instance day with given precision.\n * @method $this ceilWeek(float $precision = 1) Ceil the current instance day with given precision.\n * @method $this ceilWeeks(float $precision = 1) Ceil the current instance day with given precision.\n * @method $this roundDay(float $precision = 1, string $function = \"round\") Round the current instance day with given precision using the given function.\n * @method $this roundDays(float $precision = 1, string $function = \"round\") Round the current instance day with given precision using the given function.\n * @method $this floorDay(float $precision = 1) Truncate the current instance day with given precision.\n * @method $this floorDays(float $precision = 1) Truncate the current instance day with given precision.\n * @method $this ceilDay(float $precision = 1) Ceil the current instance day with given precision.\n * @method $this ceilDays(float $precision = 1) Ceil the current instance day with given precision.\n * @method $this roundHour(float $precision = 1, string $function = \"round\") Round the current instance hour with given precision using the given function.\n * @method $this roundHours(float $precision = 1, string $function = \"round\") Round the current instance hour with given precision using the given function.\n * @method $this floorHour(float $precision = 1) Truncate the current instance hour with given precision.\n * @method $this floorHours(float $precision = 1) Truncate the current instance hour with given precision.\n * @method $this ceilHour(float $precision = 1) Ceil the current instance hour with given precision.\n * @method $this ceilHours(float $precision = 1) Ceil the current instance hour with given precision.\n * @method $this roundMinute(float $precision = 1, string $function = \"round\") Round the current instance minute with given precision using the given function.\n * @method $this roundMinutes(float $precision = 1, string $function = \"round\") Round the current instance minute with given precision using the given function.\n * @method $this floorMinute(float $precision = 1) Truncate the current instance minute with given precision.\n * @method $this floorMinutes(float $precision = 1) Truncate the current instance minute with given precision.\n * @method $this ceilMinute(float $precision = 1) Ceil the current instance minute with given precision.\n * @method $this ceilMinutes(float $precision = 1) Ceil the current instance minute with given precision.\n * @method $this roundSecond(float $precision = 1, string $function = \"round\") Round the current instance second with given precision using the given function.\n * @method $this roundSeconds(float $precision = 1, string $function = \"round\") Round the current instance second with given precision using the given function.\n * @method $this floorSecond(float $precision = 1) Truncate the current instance second with given precision.\n * @method $this floorSeconds(float $precision = 1) Truncate the current instance second with given precision.\n * @method $this ceilSecond(float $precision = 1) Ceil the current instance second with given precision.\n * @method $this ceilSeconds(float $precision = 1) Ceil the current instance second with given precision.\n * @method $this roundMillennium(float $precision = 1, string $function = \"round\") Round the current instance millennium with given precision using the given function.\n * @method $this roundMillennia(float $precision = 1, string $function = \"round\") Round the current instance millennium with given precision using the given function.\n * @method $this floorMillennium(float $precision = 1) Truncate the current instance millennium with given precision.\n * @method $this floorMillennia(float $precision = 1) Truncate the current instance millennium with given precision.\n * @method $this ceilMillennium(float $precision = 1) Ceil the current instance millennium with given precision.\n * @method $this ceilMillennia(float $precision = 1) Ceil the current instance millennium with given precision.\n * @method $this roundCentury(float $precision = 1, string $function = \"round\") Round the current instance century with given precision using the given function.\n * @method $this roundCenturies(float $precision = 1, string $function = \"round\") Round the current instance century with given precision using the given function.\n * @method $this floorCentury(float $precision = 1) Truncate the current instance century with given precision.\n * @method $this floorCenturies(float $precision = 1) Truncate the current instance century with given precision.\n * @method $this ceilCentury(float $precision = 1) Ceil the current instance century with given precision.\n * @method $this ceilCenturies(float $precision = 1) Ceil the current instance century with given precision.\n * @method $this roundDecade(float $precision = 1, string $function = \"round\") Round the current instance decade with given precision using the given function.\n * @method $this roundDecades(float $precision = 1, string $function = \"round\") Round the current instance decade with given precision using the given function.\n * @method $this floorDecade(float $precision = 1) Truncate the current instance decade with given precision.\n * @method $this floorDecades(float $precision = 1) Truncate the current instance decade with given precision.\n * @method $this ceilDecade(float $precision = 1) Ceil the current instance decade with given precision.\n * @method $this ceilDecades(float $precision = 1) Ceil the current instance decade with given precision.\n * @method $this roundQuarter(float $precision = 1, string $function = \"round\") Round the current instance quarter with given precision using the given function.\n * @method $this roundQuarters(float $precision = 1, string $function = \"round\") Round the current instance quarter with given precision using the given function.\n * @method $this floorQuarter(float $precision = 1) Truncate the current instance quarter with given precision.\n * @method $this floorQuarters(float $precision = 1) Truncate the current instance quarter with given precision.\n * @method $this ceilQuarter(float $precision = 1) Ceil the current instance quarter with given precision.\n * @method $this ceilQuarters(float $precision = 1) Ceil the current instance quarter with given precision.\n * @method $this roundMillisecond(float $precision = 1, string $function = \"round\") Round the current instance millisecond with given precision using the given function.\n * @method $this roundMilliseconds(float $precision = 1, string $function = \"round\") Round the current instance millisecond with given precision using the given function.\n * @method $this floorMillisecond(float $precision = 1) Truncate the current instance millisecond with given precision.\n * @method $this floorMilliseconds(float $precision = 1) Truncate the current instance millisecond with given precision.\n * @method $this ceilMillisecond(float $precision = 1) Ceil the current instance millisecond with given precision.\n * @method $this ceilMilliseconds(float $precision = 1) Ceil the current instance millisecond with given precision.\n * @method $this roundMicrosecond(float $precision = 1, string $function = \"round\") Round the current instance microsecond with given precision using the given function.\n * @method $this roundMicroseconds(float $precision = 1, string $function = \"round\") Round the current instance microsecond with given precision using the given function.\n * @method $this floorMicrosecond(float $precision = 1) Truncate the current instance microsecond with given precision.\n * @method $this floorMicroseconds(float $precision = 1) Truncate the current instance microsecond with given precision.\n * @method $this ceilMicrosecond(float $precision = 1) Ceil the current instance microsecond with given precision.\n * @method $this ceilMicroseconds(float $precision = 1) Ceil the current instance microsecond with given precision.\n *\n * @SuppressWarnings(PHPMD.CouplingBetweenObjects)\n */\nclass CarbonPeriod implements Iterator, Countable, JsonSerializable\n{\n    use IntervalRounding;\n    use Mixin {\n        Mixin::mixin as baseMixin;\n    }\n    use Options;\n    use ToStringFormat;\n\n    /**\n     * Built-in filter for limit by recurrences.\n     *\n     * @var callable\n     */\n    public const RECURRENCES_FILTER = [self::class, 'filterRecurrences'];\n\n    /**\n     * Built-in filter for limit to an end.\n     *\n     * @var callable\n     */\n    public const END_DATE_FILTER = [self::class, 'filterEndDate'];\n\n    /**\n     * Special value which can be returned by filters to end iteration. Also a filter.\n     *\n     * @var callable\n     */\n    public const END_ITERATION = [self::class, 'endIteration'];\n\n    /**\n     * Exclude start date from iteration.\n     *\n     * @var int\n     */\n    public const EXCLUDE_START_DATE = 1;\n\n    /**\n     * Exclude end date from iteration.\n     *\n     * @var int\n     */\n    public const EXCLUDE_END_DATE = 2;\n\n    /**\n     * Yield CarbonImmutable instances.\n     *\n     * @var int\n     */\n    public const IMMUTABLE = 4;\n\n    /**\n     * Number of maximum attempts before giving up on finding next valid date.\n     *\n     * @var int\n     */\n    public const NEXT_MAX_ATTEMPTS = 1000;\n\n    /**\n     * Number of maximum attempts before giving up on finding end date.\n     *\n     * @var int\n     */\n    public const END_MAX_ATTEMPTS = 10000;\n\n    /**\n     * Default date class of iteration items.\n     *\n     * @var string\n     */\n    protected const DEFAULT_DATE_CLASS = Carbon::class;\n\n    /**\n     * The registered macros.\n     *\n     * @var array\n     */\n    protected static $macros = [];\n\n    /**\n     * Date class of iteration items.\n     *\n     * @var string\n     */\n    protected $dateClass = Carbon::class;\n\n    /**\n     * Underlying date interval instance. Always present, one day by default.\n     *\n     * @var CarbonInterval\n     */\n    protected $dateInterval;\n\n    /**\n     * True once __construct is finished.\n     *\n     * @var bool\n     */\n    protected $constructed = false;\n\n    /**\n     * Whether current date interval was set by default.\n     *\n     * @var bool\n     */\n    protected $isDefaultInterval;\n\n    /**\n     * The filters stack.\n     *\n     * @var array\n     */\n    protected $filters = [];\n\n    /**\n     * Period start date. Applied on rewind. Always present, now by default.\n     *\n     * @var CarbonInterface\n     */\n    protected $startDate;\n\n    /**\n     * Period end date. For inverted interval should be before the start date. Applied via a filter.\n     *\n     * @var CarbonInterface|null\n     */\n    protected $endDate;\n\n    /**\n     * Limit for number of recurrences. Applied via a filter.\n     *\n     * @var int|null\n     */\n    protected $recurrences;\n\n    /**\n     * Iteration options.\n     *\n     * @var int\n     */\n    protected $options;\n\n    /**\n     * Index of current date. Always sequential, even if some dates are skipped by filters.\n     * Equal to null only before the first iteration.\n     *\n     * @var int\n     */\n    protected $key;\n\n    /**\n     * Current date. May temporarily hold unaccepted value when looking for a next valid date.\n     * Equal to null only before the first iteration.\n     *\n     * @var CarbonInterface\n     */\n    protected $current;\n\n    /**\n     * Timezone of current date. Taken from the start date.\n     *\n     * @var \\DateTimeZone|null\n     */\n    protected $timezone;\n\n    /**\n     * The cached validation result for current date.\n     *\n     * @var bool|string|null\n     */\n    protected $validationResult;\n\n    /**\n     * Timezone handler for settings() method.\n     *\n     * @var mixed\n     */\n    protected $tzName;\n\n    /**\n     * Make a CarbonPeriod instance from given variable if possible.\n     *\n     * @param mixed $var\n     *\n     * @return static|null\n     */\n    public static function make($var)\n    {\n        try {\n            return static::instance($var);\n        } catch (NotAPeriodException $e) {\n            return static::create($var);\n        }\n    }\n\n    /**\n     * Create a new instance from a DatePeriod or CarbonPeriod object.\n     *\n     * @param CarbonPeriod|DatePeriod $period\n     *\n     * @return static\n     */\n    public static function instance($period)\n    {\n        if ($period instanceof static) {\n            return $period->copy();\n        }\n\n        if ($period instanceof self) {\n            return new static(\n                $period->getStartDate(),\n                $period->getEndDate() ?: $period->getRecurrences(),\n                $period->getDateInterval(),\n                $period->getOptions()\n            );\n        }\n\n        if ($period instanceof DatePeriod) {\n            return new static(\n                $period->start,\n                $period->end ?: ($period->recurrences - 1),\n                $period->interval,\n                $period->include_start_date ? 0 : static::EXCLUDE_START_DATE\n            );\n        }\n\n        $class = static::class;\n        $type = \\gettype($period);\n\n        throw new NotAPeriodException(\n            'Argument 1 passed to '.$class.'::'.__METHOD__.'() '.\n            'must be an instance of DatePeriod or '.$class.', '.\n            ($type === 'object' ? 'instance of '.\\get_class($period) : $type).' given.'\n        );\n    }\n\n    /**\n     * Create a new instance.\n     *\n     * @return static\n     */\n    public static function create(...$params)\n    {\n        return static::createFromArray($params);\n    }\n\n    /**\n     * Create a new instance from an array of parameters.\n     *\n     * @param array $params\n     *\n     * @return static\n     */\n    public static function createFromArray(array $params)\n    {\n        return new static(...$params);\n    }\n\n    /**\n     * Create CarbonPeriod from ISO 8601 string.\n     *\n     * @param string   $iso\n     * @param int|null $options\n     *\n     * @return static\n     */\n    public static function createFromIso($iso, $options = null)\n    {\n        $params = static::parseIso8601($iso);\n\n        $instance = static::createFromArray($params);\n\n        if ($options !== null) {\n            $instance->setOptions($options);\n        }\n\n        return $instance;\n    }\n\n    /**\n     * Return whether given interval contains non zero value of any time unit.\n     *\n     * @param \\DateInterval $interval\n     *\n     * @return bool\n     */\n    protected static function intervalHasTime(DateInterval $interval)\n    {\n        return $interval->h || $interval->i || $interval->s || $interval->f;\n    }\n\n    /**\n     * Return whether given variable is an ISO 8601 specification.\n     *\n     * Note: Check is very basic, as actual validation will be done later when parsing.\n     * We just want to ensure that variable is not any other type of a valid parameter.\n     *\n     * @param mixed $var\n     *\n     * @return bool\n     */\n    protected static function isIso8601($var)\n    {\n        if (!\\is_string($var)) {\n            return false;\n        }\n\n        // Match slash but not within a timezone name.\n        $part = '[a-z]+(?:[_-][a-z]+)*';\n\n        preg_match(\"#\\b$part/$part\\b|(/)#i\", $var, $match);\n\n        return isset($match[1]);\n    }\n\n    /**\n     * Parse given ISO 8601 string into an array of arguments.\n     *\n     * @SuppressWarnings(PHPMD.ElseExpression)\n     *\n     * @param string $iso\n     *\n     * @return array\n     */\n    protected static function parseIso8601($iso)\n    {\n        $result = [];\n\n        $interval = null;\n        $start = null;\n        $end = null;\n        $dateClass = static::DEFAULT_DATE_CLASS;\n\n        foreach (explode('/', $iso) as $key => $part) {\n            if ($key === 0 && preg_match('/^R(\\d*|INF)$/', $part, $match)) {\n                $parsed = \\strlen($match[1]) ? (($match[1] !== 'INF') ? (int) $match[1] : INF) : null;\n            } elseif ($interval === null && $parsed = CarbonInterval::make($part)) {\n                $interval = $part;\n            } elseif ($start === null && $parsed = $dateClass::make($part)) {\n                $start = $part;\n            } elseif ($end === null && $parsed = $dateClass::make(static::addMissingParts($start ?? '', $part))) {\n                $end = $part;\n            } else {\n                throw new InvalidPeriodParameterException(\"Invalid ISO 8601 specification: $iso.\");\n            }\n\n            $result[] = $parsed;\n        }\n\n        return $result;\n    }\n\n    /**\n     * Add missing parts of the target date from the source date.\n     *\n     * @param string $source\n     * @param string $target\n     *\n     * @return string\n     */\n    protected static function addMissingParts($source, $target)\n    {\n        $pattern = '/'.preg_replace('/\\d+/', '[0-9]+', preg_quote($target, '/')).'$/';\n\n        $result = preg_replace($pattern, $target, $source, 1, $count);\n\n        return $count ? $result : $target;\n    }\n\n    /**\n     * Register a custom macro.\n     *\n     * @example\n     * ```\n     * CarbonPeriod::macro('middle', function () {\n     *   return $this->getStartDate()->average($this->getEndDate());\n     * });\n     * echo CarbonPeriod::since('2011-05-12')->until('2011-06-03')->middle();\n     * ```\n     *\n     * @param string          $name\n     * @param object|callable $macro\n     *\n     * @return void\n     */\n    public static function macro($name, $macro)\n    {\n        static::$macros[$name] = $macro;\n    }\n\n    /**\n     * Register macros from a mixin object.\n     *\n     * @example\n     * ```\n     * CarbonPeriod::mixin(new class {\n     *   public function addDays() {\n     *     return function ($count = 1) {\n     *       return $this->setStartDate(\n     *         $this->getStartDate()->addDays($count)\n     *       )->setEndDate(\n     *         $this->getEndDate()->addDays($count)\n     *       );\n     *     };\n     *   }\n     *   public function subDays() {\n     *     return function ($count = 1) {\n     *       return $this->setStartDate(\n     *         $this->getStartDate()->subDays($count)\n     *       )->setEndDate(\n     *         $this->getEndDate()->subDays($count)\n     *       );\n     *     };\n     *   }\n     * });\n     * echo CarbonPeriod::create('2000-01-01', '2000-02-01')->addDays(5)->subDays(3);\n     * ```\n     *\n     * @param object|string $mixin\n     *\n     * @throws ReflectionException\n     *\n     * @return void\n     */\n    public static function mixin($mixin)\n    {\n        static::baseMixin($mixin);\n    }\n\n    /**\n     * Check if macro is registered.\n     *\n     * @param string $name\n     *\n     * @return bool\n     */\n    public static function hasMacro($name)\n    {\n        return isset(static::$macros[$name]);\n    }\n\n    /**\n     * Provide static proxy for instance aliases.\n     *\n     * @param string $method\n     * @param array  $parameters\n     *\n     * @return mixed\n     */\n    public static function __callStatic($method, $parameters)\n    {\n        $date = new static();\n\n        if (static::hasMacro($method)) {\n            return static::bindMacroContext(null, function () use (&$method, &$parameters, &$date) {\n                return $date->callMacro($method, $parameters);\n            });\n        }\n\n        return $date->$method(...$parameters);\n    }\n\n    /**\n     * CarbonPeriod constructor.\n     *\n     * @SuppressWarnings(PHPMD.ElseExpression)\n     *\n     * @throws InvalidArgumentException\n     */\n    public function __construct(...$arguments)\n    {\n        if (is_a($this->dateClass, DateTimeImmutable::class, true)) {\n            $this->options = static::IMMUTABLE;\n        }\n\n        // Parse and assign arguments one by one. First argument may be an ISO 8601 spec,\n        // which will be first parsed into parts and then processed the same way.\n\n        $argumentsCount = \\count($arguments);\n\n        if ($argumentsCount && static::isIso8601($iso = $arguments[0])) {\n            array_splice($arguments, 0, 1, static::parseIso8601($iso));\n        }\n\n        if ($argumentsCount === 1) {\n            if ($arguments[0] instanceof DatePeriod) {\n                $arguments = [\n                    $arguments[0]->start,\n                    $arguments[0]->end ?: ($arguments[0]->recurrences - 1),\n                    $arguments[0]->interval,\n                    $arguments[0]->include_start_date ? 0 : static::EXCLUDE_START_DATE,\n                ];\n            } elseif ($arguments[0] instanceof self) {\n                $arguments = [\n                    $arguments[0]->getStartDate(),\n                    $arguments[0]->getEndDate() ?: $arguments[0]->getRecurrences(),\n                    $arguments[0]->getDateInterval(),\n                    $arguments[0]->getOptions(),\n                ];\n            }\n        }\n\n        $optionsSet = false;\n\n        foreach ($arguments as $argument) {\n            $parsedDate = null;\n\n            if ($argument instanceof DateTimeZone) {\n                $this->setTimezone($argument);\n            } elseif ($this->dateInterval === null &&\n                (\n                    (\\is_string($argument) && preg_match(\n                        '/^(-?\\d(\\d(?![\\/-])|[^\\d\\/-]([\\/-])?)*|P[T\\d].*|(?:\\h*\\d+(?:\\.\\d+)?\\h*[a-z]+)+)$/i',\n                        $argument\n                    )) ||\n                    $argument instanceof DateInterval ||\n                    $argument instanceof Closure\n                ) &&\n                $parsedInterval = @CarbonInterval::make($argument)\n            ) {\n                $this->setDateInterval($parsedInterval);\n            } elseif ($this->startDate === null && $parsedDate = $this->makeDateTime($argument)) {\n                $this->setStartDate($parsedDate);\n            } elseif ($this->endDate === null && ($parsedDate = $parsedDate ?? $this->makeDateTime($argument))) {\n                $this->setEndDate($parsedDate);\n            } elseif ($this->recurrences === null && $this->endDate === null && is_numeric($argument)) {\n                $this->setRecurrences($argument);\n            } elseif (!$optionsSet && (\\is_int($argument) || $argument === null)) {\n                $optionsSet = true;\n                $this->setOptions(((int) $this->options) | ((int) $argument));\n            } else {\n                throw new InvalidPeriodParameterException('Invalid constructor parameters.');\n            }\n        }\n\n        if ($this->startDate === null) {\n            $dateClass = $this->dateClass;\n            $this->setStartDate($dateClass::now());\n        }\n\n        if ($this->dateInterval === null) {\n            $this->setDateInterval(CarbonInterval::day());\n\n            $this->isDefaultInterval = true;\n        }\n\n        if ($this->options === null) {\n            $this->setOptions(0);\n        }\n\n        $this->constructed = true;\n    }\n\n    /**\n     * Get a copy of the instance.\n     *\n     * @return static\n     */\n    public function copy()\n    {\n        return clone $this;\n    }\n\n    /**\n     * Prepare the instance to be set (self if mutable to be mutated,\n     * copy if immutable to generate a new instance).\n     *\n     * @return static\n     */\n    protected function copyIfImmutable()\n    {\n        return $this;\n    }\n\n    /**\n     * Get the getter for a property allowing both `DatePeriod` snakeCase and camelCase names.\n     *\n     * @param string $name\n     *\n     * @return callable|null\n     */\n    protected function getGetter(string $name)\n    {\n        switch (strtolower(preg_replace('/[A-Z]/', '_$0', $name))) {\n            case 'start':\n            case 'start_date':\n                return [$this, 'getStartDate'];\n            case 'end':\n            case 'end_date':\n                return [$this, 'getEndDate'];\n            case 'interval':\n            case 'date_interval':\n                return [$this, 'getDateInterval'];\n            case 'recurrences':\n                return [$this, 'getRecurrences'];\n            case 'include_start_date':\n                return [$this, 'isStartIncluded'];\n            case 'include_end_date':\n                return [$this, 'isEndIncluded'];\n            case 'current':\n                return [$this, 'current'];\n            default:\n                return null;\n        }\n    }\n\n    /**\n     * Get a property allowing both `DatePeriod` snakeCase and camelCase names.\n     *\n     * @param string $name\n     *\n     * @return bool|CarbonInterface|CarbonInterval|int|null\n     */\n    public function get(string $name)\n    {\n        $getter = $this->getGetter($name);\n\n        if ($getter) {\n            return $getter();\n        }\n\n        throw new UnknownGetterException($name);\n    }\n\n    /**\n     * Get a property allowing both `DatePeriod` snakeCase and camelCase names.\n     *\n     * @param string $name\n     *\n     * @return bool|CarbonInterface|CarbonInterval|int|null\n     */\n    public function __get(string $name)\n    {\n        return $this->get($name);\n    }\n\n    /**\n     * Check if an attribute exists on the object\n     *\n     * @param string $name\n     *\n     * @return bool\n     */\n    public function __isset(string $name): bool\n    {\n        return $this->getGetter($name) !== null;\n    }\n\n    /**\n     * @alias copy\n     *\n     * Get a copy of the instance.\n     *\n     * @return static\n     */\n    public function clone()\n    {\n        return clone $this;\n    }\n\n    /**\n     * Set the iteration item class.\n     *\n     * @param string $dateClass\n     *\n     * @return static\n     */\n    public function setDateClass(string $dateClass)\n    {\n        if (!is_a($dateClass, CarbonInterface::class, true)) {\n            throw new NotACarbonClassException($dateClass);\n        }\n\n        $self = $this->copyIfImmutable();\n        $self->dateClass = $dateClass;\n\n        if (is_a($dateClass, Carbon::class, true)) {\n            $self->options = $self->options & ~static::IMMUTABLE;\n        } elseif (is_a($dateClass, CarbonImmutable::class, true)) {\n            $self->options = $self->options | static::IMMUTABLE;\n        }\n\n        return $self;\n    }\n\n    /**\n     * Returns iteration item date class.\n     *\n     * @return string\n     */\n    public function getDateClass(): string\n    {\n        return $this->dateClass;\n    }\n\n    /**\n     * Change the period date interval.\n     *\n     * @param DateInterval|string $interval\n     *\n     * @throws InvalidIntervalException\n     *\n     * @return static\n     */\n    public function setDateInterval($interval)\n    {\n        if (!$interval = CarbonInterval::make($interval)) {\n            throw new InvalidIntervalException('Invalid interval.');\n        }\n\n        if ($interval->spec() === 'PT0S' && !$interval->f && !$interval->getStep()) {\n            throw new InvalidIntervalException('Empty interval is not accepted.');\n        }\n\n        $self = $this->copyIfImmutable();\n        $self->dateInterval = $interval;\n\n        $self->isDefaultInterval = false;\n\n        $self->handleChangedParameters();\n\n        return $self;\n    }\n\n    /**\n     * Invert the period date interval.\n     *\n     * @return static\n     */\n    public function invertDateInterval()\n    {\n        return $this->setDateInterval($this->dateInterval->invert());\n    }\n\n    /**\n     * Set start and end date.\n     *\n     * @param DateTime|DateTimeInterface|string      $start\n     * @param DateTime|DateTimeInterface|string|null $end\n     *\n     * @return static\n     */\n    public function setDates($start, $end)\n    {\n        return $this->setStartDate($start)->setEndDate($end);\n    }\n\n    /**\n     * Change the period options.\n     *\n     * @param int|null $options\n     *\n     * @throws InvalidArgumentException\n     *\n     * @return static\n     */\n    public function setOptions($options)\n    {\n        if (!\\is_int($options) && $options !== null) {\n            throw new InvalidPeriodParameterException('Invalid options.');\n        }\n\n        $self = $this->copyIfImmutable();\n        $self->options = $options ?: 0;\n\n        $self->handleChangedParameters();\n\n        return $self;\n    }\n\n    /**\n     * Get the period options.\n     *\n     * @return int\n     */\n    public function getOptions()\n    {\n        return $this->options;\n    }\n\n    /**\n     * Toggle given options on or off.\n     *\n     * @param int       $options\n     * @param bool|null $state\n     *\n     * @throws \\InvalidArgumentException\n     *\n     * @return static\n     */\n    public function toggleOptions($options, $state = null)\n    {\n        if ($state === null) {\n            $state = ($this->options & $options) !== $options;\n        }\n\n        return $this->setOptions(\n            $state ?\n            $this->options | $options :\n            $this->options & ~$options\n        );\n    }\n\n    /**\n     * Toggle EXCLUDE_START_DATE option.\n     *\n     * @param bool $state\n     *\n     * @return static\n     */\n    public function excludeStartDate($state = true)\n    {\n        return $this->toggleOptions(static::EXCLUDE_START_DATE, $state);\n    }\n\n    /**\n     * Toggle EXCLUDE_END_DATE option.\n     *\n     * @param bool $state\n     *\n     * @return static\n     */\n    public function excludeEndDate($state = true)\n    {\n        return $this->toggleOptions(static::EXCLUDE_END_DATE, $state);\n    }\n\n    /**\n     * Get the underlying date interval.\n     *\n     * @return CarbonInterval\n     */\n    public function getDateInterval()\n    {\n        return $this->dateInterval->copy();\n    }\n\n    /**\n     * Get start date of the period.\n     *\n     * @param string|null $rounding Optional rounding 'floor', 'ceil', 'round' using the period interval.\n     *\n     * @return CarbonInterface\n     */\n    public function getStartDate(?string $rounding = null)\n    {\n        $date = $this->startDate->avoidMutation();\n\n        return $rounding ? $date->round($this->getDateInterval(), $rounding) : $date;\n    }\n\n    /**\n     * Get end date of the period.\n     *\n     * @param string|null $rounding Optional rounding 'floor', 'ceil', 'round' using the period interval.\n     *\n     * @return CarbonInterface|null\n     */\n    public function getEndDate(?string $rounding = null)\n    {\n        if (!$this->endDate) {\n            return null;\n        }\n\n        $date = $this->endDate->avoidMutation();\n\n        return $rounding ? $date->round($this->getDateInterval(), $rounding) : $date;\n    }\n\n    /**\n     * Get number of recurrences.\n     *\n     * @return int|float|null\n     */\n    public function getRecurrences()\n    {\n        return $this->recurrences;\n    }\n\n    /**\n     * Returns true if the start date should be excluded.\n     *\n     * @return bool\n     */\n    public function isStartExcluded()\n    {\n        return ($this->options & static::EXCLUDE_START_DATE) !== 0;\n    }\n\n    /**\n     * Returns true if the end date should be excluded.\n     *\n     * @return bool\n     */\n    public function isEndExcluded()\n    {\n        return ($this->options & static::EXCLUDE_END_DATE) !== 0;\n    }\n\n    /**\n     * Returns true if the start date should be included.\n     *\n     * @return bool\n     */\n    public function isStartIncluded()\n    {\n        return !$this->isStartExcluded();\n    }\n\n    /**\n     * Returns true if the end date should be included.\n     *\n     * @return bool\n     */\n    public function isEndIncluded()\n    {\n        return !$this->isEndExcluded();\n    }\n\n    /**\n     * Return the start if it's included by option, else return the start + 1 period interval.\n     *\n     * @return CarbonInterface\n     */\n    public function getIncludedStartDate()\n    {\n        $start = $this->getStartDate();\n\n        if ($this->isStartExcluded()) {\n            return $start->add($this->getDateInterval());\n        }\n\n        return $start;\n    }\n\n    /**\n     * Return the end if it's included by option, else return the end - 1 period interval.\n     * Warning: if the period has no fixed end, this method will iterate the period to calculate it.\n     *\n     * @return CarbonInterface\n     */\n    public function getIncludedEndDate()\n    {\n        $end = $this->getEndDate();\n\n        if (!$end) {\n            return $this->calculateEnd();\n        }\n\n        if ($this->isEndExcluded()) {\n            return $end->sub($this->getDateInterval());\n        }\n\n        return $end;\n    }\n\n    /**\n     * Add a filter to the stack.\n     *\n     * @SuppressWarnings(PHPMD.UnusedFormalParameter)\n     *\n     * @param callable $callback\n     * @param string   $name\n     *\n     * @return static\n     */\n    public function addFilter($callback, $name = null)\n    {\n        $self = $this->copyIfImmutable();\n        $tuple = $self->createFilterTuple(\\func_get_args());\n\n        $self->filters[] = $tuple;\n\n        $self->handleChangedParameters();\n\n        return $self;\n    }\n\n    /**\n     * Prepend a filter to the stack.\n     *\n     * @SuppressWarnings(PHPMD.UnusedFormalParameter)\n     *\n     * @param callable $callback\n     * @param string   $name\n     *\n     * @return static\n     */\n    public function prependFilter($callback, $name = null)\n    {\n        $self = $this->copyIfImmutable();\n        $tuple = $self->createFilterTuple(\\func_get_args());\n\n        array_unshift($self->filters, $tuple);\n\n        $self->handleChangedParameters();\n\n        return $self;\n    }\n\n    /**\n     * Remove a filter by instance or name.\n     *\n     * @param callable|string $filter\n     *\n     * @return static\n     */\n    public function removeFilter($filter)\n    {\n        $self = $this->copyIfImmutable();\n        $key = \\is_callable($filter) ? 0 : 1;\n\n        $self->filters = array_values(array_filter(\n            $this->filters,\n            function ($tuple) use ($key, $filter) {\n                return $tuple[$key] !== $filter;\n            }\n        ));\n\n        $self->updateInternalState();\n\n        $self->handleChangedParameters();\n\n        return $self;\n    }\n\n    /**\n     * Return whether given instance or name is in the filter stack.\n     *\n     * @param callable|string $filter\n     *\n     * @return bool\n     */\n    public function hasFilter($filter)\n    {\n        $key = \\is_callable($filter) ? 0 : 1;\n\n        foreach ($this->filters as $tuple) {\n            if ($tuple[$key] === $filter) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * Get filters stack.\n     *\n     * @return array\n     */\n    public function getFilters()\n    {\n        return $this->filters;\n    }\n\n    /**\n     * Set filters stack.\n     *\n     * @param array $filters\n     *\n     * @return static\n     */\n    public function setFilters(array $filters)\n    {\n        $self = $this->copyIfImmutable();\n        $self->filters = $filters;\n\n        $self->updateInternalState();\n\n        $self->handleChangedParameters();\n\n        return $self;\n    }\n\n    /**\n     * Reset filters stack.\n     *\n     * @return static\n     */\n    public function resetFilters()\n    {\n        $self = $this->copyIfImmutable();\n        $self->filters = [];\n\n        if ($self->endDate !== null) {\n            $self->filters[] = [static::END_DATE_FILTER, null];\n        }\n\n        if ($self->recurrences !== null) {\n            $self->filters[] = [static::RECURRENCES_FILTER, null];\n        }\n\n        $self->handleChangedParameters();\n\n        return $self;\n    }\n\n    /**\n     * Add a recurrences filter (set maximum number of recurrences).\n     *\n     * @param int|float|null $recurrences\n     *\n     * @throws InvalidArgumentException\n     *\n     * @return static\n     */\n    public function setRecurrences($recurrences)\n    {\n        if ((!is_numeric($recurrences) && $recurrences !== null) || $recurrences < 0) {\n            throw new InvalidPeriodParameterException('Invalid number of recurrences.');\n        }\n\n        if ($recurrences === null) {\n            return $this->removeFilter(static::RECURRENCES_FILTER);\n        }\n\n        /** @var self $self */\n        $self = $this->copyIfImmutable();\n        $self->recurrences = $recurrences === INF ? INF : (int) $recurrences;\n\n        if (!$self->hasFilter(static::RECURRENCES_FILTER)) {\n            return $self->addFilter(static::RECURRENCES_FILTER);\n        }\n\n        $self->handleChangedParameters();\n\n        return $self;\n    }\n\n    /**\n     * Change the period start date.\n     *\n     * @param DateTime|DateTimeInterface|string $date\n     * @param bool|null                         $inclusive\n     *\n     * @throws InvalidPeriodDateException\n     *\n     * @return static\n     */\n    public function setStartDate($date, $inclusive = null)\n    {\n        if (!$this->isInfiniteDate($date) && !($date = ([$this->dateClass, 'make'])($date))) {\n            throw new InvalidPeriodDateException('Invalid start date.');\n        }\n\n        $self = $this->copyIfImmutable();\n        $self->startDate = $date;\n\n        if ($inclusive !== null) {\n            $self = $self->toggleOptions(static::EXCLUDE_START_DATE, !$inclusive);\n        }\n\n        return $self;\n    }\n\n    /**\n     * Change the period end date.\n     *\n     * @param DateTime|DateTimeInterface|string|null $date\n     * @param bool|null                              $inclusive\n     *\n     * @throws \\InvalidArgumentException\n     *\n     * @return static\n     */\n    public function setEndDate($date, $inclusive = null)\n    {\n        if ($date !== null && !$this->isInfiniteDate($date) && !$date = ([$this->dateClass, 'make'])($date)) {\n            throw new InvalidPeriodDateException('Invalid end date.');\n        }\n\n        if (!$date) {\n            return $this->removeFilter(static::END_DATE_FILTER);\n        }\n\n        $self = $this->copyIfImmutable();\n        $self->endDate = $date;\n\n        if ($inclusive !== null) {\n            $self = $self->toggleOptions(static::EXCLUDE_END_DATE, !$inclusive);\n        }\n\n        if (!$self->hasFilter(static::END_DATE_FILTER)) {\n            return $self->addFilter(static::END_DATE_FILTER);\n        }\n\n        $self->handleChangedParameters();\n\n        return $self;\n    }\n\n    /**\n     * Check if the current position is valid.\n     *\n     * @return bool\n     */\n    #[ReturnTypeWillChange]\n    public function valid()\n    {\n        return $this->validateCurrentDate() === true;\n    }\n\n    /**\n     * Return the current key.\n     *\n     * @return int|null\n     */\n    #[ReturnTypeWillChange]\n    public function key()\n    {\n        return $this->valid()\n            ? $this->key\n            : null;\n    }\n\n    /**\n     * Return the current date.\n     *\n     * @return CarbonInterface|null\n     */\n    #[ReturnTypeWillChange]\n    public function current()\n    {\n        return $this->valid()\n            ? $this->prepareForReturn($this->current)\n            : null;\n    }\n\n    /**\n     * Move forward to the next date.\n     *\n     * @throws RuntimeException\n     *\n     * @return void\n     */\n    #[ReturnTypeWillChange]\n    public function next()\n    {\n        if ($this->current === null) {\n            $this->rewind();\n        }\n\n        if ($this->validationResult !== static::END_ITERATION) {\n            $this->key++;\n\n            $this->incrementCurrentDateUntilValid();\n        }\n    }\n\n    /**\n     * Rewind to the start date.\n     *\n     * Iterating over a date in the UTC timezone avoids bug during backward DST change.\n     *\n     * @see https://bugs.php.net/bug.php?id=72255\n     * @see https://bugs.php.net/bug.php?id=74274\n     * @see https://wiki.php.net/rfc/datetime_and_daylight_saving_time\n     *\n     * @throws RuntimeException\n     *\n     * @return void\n     */\n    #[ReturnTypeWillChange]\n    public function rewind()\n    {\n        $this->key = 0;\n        $this->current = ([$this->dateClass, 'make'])($this->startDate);\n        $settings = $this->getSettings();\n\n        if ($this->hasLocalTranslator()) {\n            $settings['locale'] = $this->getTranslatorLocale();\n        }\n\n        $this->current->settings($settings);\n        $this->timezone = static::intervalHasTime($this->dateInterval) ? $this->current->getTimezone() : null;\n\n        if ($this->timezone) {\n            $this->current = $this->current->utc();\n        }\n\n        $this->validationResult = null;\n\n        if ($this->isStartExcluded() || $this->validateCurrentDate() === false) {\n            $this->incrementCurrentDateUntilValid();\n        }\n    }\n\n    /**\n     * Skip iterations and returns iteration state (false if ended, true if still valid).\n     *\n     * @param int $count steps number to skip (1 by default)\n     *\n     * @return bool\n     */\n    public function skip($count = 1)\n    {\n        for ($i = $count; $this->valid() && $i > 0; $i--) {\n            $this->next();\n        }\n\n        return $this->valid();\n    }\n\n    /**\n     * Format the date period as ISO 8601.\n     *\n     * @return string\n     */\n    public function toIso8601String()\n    {\n        $parts = [];\n\n        if ($this->recurrences !== null) {\n            $parts[] = 'R'.$this->recurrences;\n        }\n\n        $parts[] = $this->startDate->toIso8601String();\n\n        $parts[] = $this->dateInterval->spec();\n\n        if ($this->endDate !== null) {\n            $parts[] = $this->endDate->toIso8601String();\n        }\n\n        return implode('/', $parts);\n    }\n\n    /**\n     * Convert the date period into a string.\n     *\n     * @return string\n     */\n    public function toString()\n    {\n        $format = $this->localToStringFormat ?? static::$toStringFormat;\n\n        if ($format instanceof Closure) {\n            return $format($this);\n        }\n\n        $translator = ([$this->dateClass, 'getTranslator'])();\n\n        $parts = [];\n\n        $format = $format ?? (\n            !$this->startDate->isStartOfDay() || ($this->endDate && !$this->endDate->isStartOfDay())\n                ? 'Y-m-d H:i:s'\n                : 'Y-m-d'\n        );\n\n        if ($this->recurrences !== null) {\n            $parts[] = $this->translate('period_recurrences', [], $this->recurrences, $translator);\n        }\n\n        $parts[] = $this->translate('period_interval', [':interval' => $this->dateInterval->forHumans([\n            'join' => true,\n        ])], null, $translator);\n\n        $parts[] = $this->translate('period_start_date', [':date' => $this->startDate->rawFormat($format)], null, $translator);\n\n        if ($this->endDate !== null) {\n            $parts[] = $this->translate('period_end_date', [':date' => $this->endDate->rawFormat($format)], null, $translator);\n        }\n\n        $result = implode(' ', $parts);\n\n        return mb_strtoupper(mb_substr($result, 0, 1)).mb_substr($result, 1);\n    }\n\n    /**\n     * Format the date period as ISO 8601.\n     *\n     * @return string\n     */\n    public function spec()\n    {\n        return $this->toIso8601String();\n    }\n\n    /**\n     * Cast the current instance into the given class.\n     *\n     * @param string $className The $className::instance() method will be called to cast the current object.\n     *\n     * @return DatePeriod\n     */\n    public function cast(string $className)\n    {\n        if (!method_exists($className, 'instance')) {\n            if (is_a($className, DatePeriod::class, true)) {\n                return new $className(\n                    $this->rawDate($this->getStartDate()),\n                    $this->getDateInterval(),\n                    $this->getEndDate() ? $this->rawDate($this->getIncludedEndDate()) : $this->getRecurrences(),\n                    $this->isStartExcluded() ? DatePeriod::EXCLUDE_START_DATE : 0\n                );\n            }\n\n            throw new InvalidCastException(\"$className has not the instance() method needed to cast the date.\");\n        }\n\n        return $className::instance($this);\n    }\n\n    /**\n     * Return native DatePeriod PHP object matching the current instance.\n     *\n     * @example\n     * ```\n     * var_dump(CarbonPeriod::create('2021-01-05', '2021-02-15')->toDatePeriod());\n     * ```\n     *\n     * @return DatePeriod\n     */\n    public function toDatePeriod()\n    {\n        return $this->cast(DatePeriod::class);\n    }\n\n    /**\n     * Return `true` if the period has no custom filter and is guaranteed to be endless.\n     *\n     * Note that we can't check if a period is endless as soon as it has custom filters\n     * because filters can emit `CarbonPeriod::END_ITERATION` to stop the iteration in\n     * a way we can't predict without actually iterating the period.\n     */\n    public function isUnfilteredAndEndLess(): bool\n    {\n        foreach ($this->filters as $filter) {\n            switch ($filter) {\n                case [static::RECURRENCES_FILTER, null]:\n                    if ($this->recurrences !== null && is_finite($this->recurrences)) {\n                        return false;\n                    }\n\n                    break;\n\n                case [static::END_DATE_FILTER, null]:\n                    if ($this->endDate !== null && !$this->endDate->isEndOfTime()) {\n                        return false;\n                    }\n\n                    break;\n\n                default:\n                    return false;\n            }\n        }\n\n        return true;\n    }\n\n    /**\n     * Convert the date period into an array without changing current iteration state.\n     *\n     * @return CarbonInterface[]\n     */\n    public function toArray()\n    {\n        if ($this->isUnfilteredAndEndLess()) {\n            throw new EndLessPeriodException(\"Endless period can't be converted to array nor counted.\");\n        }\n\n        $state = [\n            $this->key,\n            $this->current ? $this->current->avoidMutation() : null,\n            $this->validationResult,\n        ];\n\n        $result = iterator_to_array($this);\n\n        [$this->key, $this->current, $this->validationResult] = $state;\n\n        return $result;\n    }\n\n    /**\n     * Count dates in the date period.\n     *\n     * @return int\n     */\n    #[ReturnTypeWillChange]\n    public function count()\n    {\n        return \\count($this->toArray());\n    }\n\n    /**\n     * Return the first date in the date period.\n     *\n     * @return CarbonInterface|null\n     */\n    public function first()\n    {\n        if ($this->isUnfilteredAndEndLess()) {\n            foreach ($this as $date) {\n                $this->rewind();\n\n                return $date;\n            }\n\n            return null;\n        }\n\n        return ($this->toArray() ?: [])[0] ?? null;\n    }\n\n    /**\n     * Return the last date in the date period.\n     *\n     * @return CarbonInterface|null\n     */\n    public function last()\n    {\n        $array = $this->toArray();\n\n        return $array ? $array[\\count($array) - 1] : null;\n    }\n\n    /**\n     * Convert the date period into a string.\n     *\n     * @return string\n     */\n    public function __toString()\n    {\n        return $this->toString();\n    }\n\n    /**\n     * Add aliases for setters.\n     *\n     * CarbonPeriod::days(3)->hours(5)->invert()\n     *     ->sinceNow()->until('2010-01-10')\n     *     ->filter(...)\n     *     ->count()\n     *\n     * Note: We use magic method to let static and instance aliases with the same names.\n     *\n     * @param string $method\n     * @param array  $parameters\n     *\n     * @return mixed\n     */\n    public function __call($method, $parameters)\n    {\n        if (static::hasMacro($method)) {\n            return static::bindMacroContext($this, function () use (&$method, &$parameters) {\n                return $this->callMacro($method, $parameters);\n            });\n        }\n\n        $roundedValue = $this->callRoundMethod($method, $parameters);\n\n        if ($roundedValue !== null) {\n            return $roundedValue;\n        }\n\n        switch ($method) {\n            case 'start':\n            case 'since':\n                self::setDefaultParameters($parameters, [\n                    [0, 'date', null],\n                ]);\n\n                return $this->setStartDate(...$parameters);\n\n            case 'sinceNow':\n                return $this->setStartDate(new Carbon(), ...$parameters);\n\n            case 'end':\n            case 'until':\n                self::setDefaultParameters($parameters, [\n                    [0, 'date', null],\n                ]);\n\n                return $this->setEndDate(...$parameters);\n\n            case 'untilNow':\n                return $this->setEndDate(new Carbon(), ...$parameters);\n\n            case 'dates':\n            case 'between':\n                self::setDefaultParameters($parameters, [\n                    [0, 'start', null],\n                    [1, 'end', null],\n                ]);\n\n                return $this->setDates(...$parameters);\n\n            case 'recurrences':\n            case 'times':\n                self::setDefaultParameters($parameters, [\n                    [0, 'recurrences', null],\n                ]);\n\n                return $this->setRecurrences(...$parameters);\n\n            case 'options':\n                self::setDefaultParameters($parameters, [\n                    [0, 'options', null],\n                ]);\n\n                return $this->setOptions(...$parameters);\n\n            case 'toggle':\n                self::setDefaultParameters($parameters, [\n                    [0, 'options', null],\n                ]);\n\n                return $this->toggleOptions(...$parameters);\n\n            case 'filter':\n            case 'push':\n                return $this->addFilter(...$parameters);\n\n            case 'prepend':\n                return $this->prependFilter(...$parameters);\n\n            case 'filters':\n                self::setDefaultParameters($parameters, [\n                    [0, 'filters', []],\n                ]);\n\n                return $this->setFilters(...$parameters);\n\n            case 'interval':\n            case 'each':\n            case 'every':\n            case 'step':\n            case 'stepBy':\n                return $this->setDateInterval(...$parameters);\n\n            case 'invert':\n                return $this->invertDateInterval();\n\n            case 'years':\n            case 'year':\n            case 'months':\n            case 'month':\n            case 'weeks':\n            case 'week':\n            case 'days':\n            case 'dayz':\n            case 'day':\n            case 'hours':\n            case 'hour':\n            case 'minutes':\n            case 'minute':\n            case 'seconds':\n            case 'second':\n            case 'milliseconds':\n            case 'millisecond':\n            case 'microseconds':\n            case 'microsecond':\n                return $this->setDateInterval((\n                    // Override default P1D when instantiating via fluent setters.\n                    [$this->isDefaultInterval ? new CarbonInterval('PT0S') : $this->dateInterval, $method]\n                )(...$parameters));\n        }\n\n        $dateClass = $this->dateClass;\n\n        if ($this->localStrictModeEnabled ?? $dateClass::isStrictModeEnabled()) {\n            throw new UnknownMethodException($method);\n        }\n\n        return $this;\n    }\n\n    /**\n     * Set the instance's timezone from a string or object and apply it to start/end.\n     *\n     * @param \\DateTimeZone|string $timezone\n     *\n     * @return static\n     */\n    public function setTimezone($timezone)\n    {\n        $self = $this->copyIfImmutable();\n        $self->tzName = $timezone;\n        $self->timezone = $timezone;\n\n        if ($self->startDate) {\n            $self = $self->setStartDate($self->startDate->setTimezone($timezone));\n        }\n\n        if ($self->endDate) {\n            $self = $self->setEndDate($self->endDate->setTimezone($timezone));\n        }\n\n        return $self;\n    }\n\n    /**\n     * Set the instance's timezone from a string or object and add/subtract the offset difference to start/end.\n     *\n     * @param \\DateTimeZone|string $timezone\n     *\n     * @return static\n     */\n    public function shiftTimezone($timezone)\n    {\n        $self = $this->copyIfImmutable();\n        $self->tzName = $timezone;\n        $self->timezone = $timezone;\n\n        if ($self->startDate) {\n            $self = $self->setStartDate($self->startDate->shiftTimezone($timezone));\n        }\n\n        if ($self->endDate) {\n            $self = $self->setEndDate($self->endDate->shiftTimezone($timezone));\n        }\n\n        return $self;\n    }\n\n    /**\n     * Returns the end is set, else calculated from start an recurrences.\n     *\n     * @param string|null $rounding Optional rounding 'floor', 'ceil', 'round' using the period interval.\n     *\n     * @return CarbonInterface\n     */\n    public function calculateEnd(?string $rounding = null)\n    {\n        if ($end = $this->getEndDate($rounding)) {\n            return $end;\n        }\n\n        if ($this->dateInterval->isEmpty()) {\n            return $this->getStartDate($rounding);\n        }\n\n        $date = $this->getEndFromRecurrences() ?? $this->iterateUntilEnd();\n\n        if ($date && $rounding) {\n            $date = $date->avoidMutation()->round($this->getDateInterval(), $rounding);\n        }\n\n        return $date;\n    }\n\n    /**\n     * @return CarbonInterface|null\n     */\n    private function getEndFromRecurrences()\n    {\n        if ($this->recurrences === null) {\n            throw new UnreachableException(\n                \"Could not calculate period end without either explicit end or recurrences.\\n\".\n                \"If you're looking for a forever-period, use ->setRecurrences(INF).\"\n            );\n        }\n\n        if ($this->recurrences === INF) {\n            $start = $this->getStartDate();\n\n            return $start < $start->avoidMutation()->add($this->getDateInterval())\n                ? CarbonImmutable::endOfTime()\n                : CarbonImmutable::startOfTime();\n        }\n\n        if ($this->filters === [[static::RECURRENCES_FILTER, null]]) {\n            return $this->getStartDate()->avoidMutation()->add(\n                $this->getDateInterval()->times(\n                    $this->recurrences - ($this->isStartExcluded() ? 0 : 1)\n                )\n            );\n        }\n\n        return null;\n    }\n\n    /**\n     * @return CarbonInterface|null\n     */\n    private function iterateUntilEnd()\n    {\n        $attempts = 0;\n        $date = null;\n\n        foreach ($this as $date) {\n            if (++$attempts > static::END_MAX_ATTEMPTS) {\n                throw new UnreachableException(\n                    'Could not calculate period end after iterating '.static::END_MAX_ATTEMPTS.' times.'\n                );\n            }\n        }\n\n        return $date;\n    }\n\n    /**\n     * Returns true if the current period overlaps the given one (if 1 parameter passed)\n     * or the period between 2 dates (if 2 parameters passed).\n     *\n     * @param CarbonPeriod|\\DateTimeInterface|Carbon|CarbonImmutable|string $rangeOrRangeStart\n     * @param \\DateTimeInterface|Carbon|CarbonImmutable|string|null         $rangeEnd\n     *\n     * @return bool\n     */\n    public function overlaps($rangeOrRangeStart, $rangeEnd = null)\n    {\n        $range = $rangeEnd ? static::create($rangeOrRangeStart, $rangeEnd) : $rangeOrRangeStart;\n\n        if (!($range instanceof self)) {\n            $range = static::create($range);\n        }\n\n        [$start, $end] = $this->orderCouple($this->getStartDate(), $this->calculateEnd());\n        [$rangeStart, $rangeEnd] = $this->orderCouple($range->getStartDate(), $range->calculateEnd());\n\n        return $end > $rangeStart && $rangeEnd > $start;\n    }\n\n    /**\n     * Execute a given function on each date of the period.\n     *\n     * @example\n     * ```\n     * Carbon::create('2020-11-29')->daysUntil('2020-12-24')->forEach(function (Carbon $date) {\n     *   echo $date->diffInDays('2020-12-25').\" days before Christmas!\\n\";\n     * });\n     * ```\n     *\n     * @param callable $callback\n     */\n    public function forEach(callable $callback)\n    {\n        foreach ($this as $date) {\n            $callback($date);\n        }\n    }\n\n    /**\n     * Execute a given function on each date of the period and yield the result of this function.\n     *\n     * @example\n     * ```\n     * $period = Carbon::create('2020-11-29')->daysUntil('2020-12-24');\n     * echo implode(\"\\n\", iterator_to_array($period->map(function (Carbon $date) {\n     *   return $date->diffInDays('2020-12-25').' days before Christmas!';\n     * })));\n     * ```\n     *\n     * @param callable $callback\n     *\n     * @return \\Generator\n     */\n    public function map(callable $callback)\n    {\n        foreach ($this as $date) {\n            yield $callback($date);\n        }\n    }\n\n    /**\n     * Determines if the instance is equal to another.\n     * Warning: if options differ, instances will never be equal.\n     *\n     * @param mixed $period\n     *\n     * @see equalTo()\n     *\n     * @return bool\n     */\n    public function eq($period): bool\n    {\n        return $this->equalTo($period);\n    }\n\n    /**\n     * Determines if the instance is equal to another.\n     * Warning: if options differ, instances will never be equal.\n     *\n     * @param mixed $period\n     *\n     * @return bool\n     */\n    public function equalTo($period): bool\n    {\n        if (!($period instanceof self)) {\n            $period = self::make($period);\n        }\n\n        $end = $this->getEndDate();\n\n        return $period !== null\n            && $this->getDateInterval()->eq($period->getDateInterval())\n            && $this->getStartDate()->eq($period->getStartDate())\n            && ($end ? $end->eq($period->getEndDate()) : $this->getRecurrences() === $period->getRecurrences())\n            && ($this->getOptions() & (~static::IMMUTABLE)) === ($period->getOptions() & (~static::IMMUTABLE));\n    }\n\n    /**\n     * Determines if the instance is not equal to another.\n     * Warning: if options differ, instances will never be equal.\n     *\n     * @param mixed $period\n     *\n     * @see notEqualTo()\n     *\n     * @return bool\n     */\n    public function ne($period): bool\n    {\n        return $this->notEqualTo($period);\n    }\n\n    /**\n     * Determines if the instance is not equal to another.\n     * Warning: if options differ, instances will never be equal.\n     *\n     * @param mixed $period\n     *\n     * @return bool\n     */\n    public function notEqualTo($period): bool\n    {\n        return !$this->eq($period);\n    }\n\n    /**\n     * Determines if the start date is before an other given date.\n     * (Rather start/end are included by options is ignored.)\n     *\n     * @param mixed $date\n     *\n     * @return bool\n     */\n    public function startsBefore($date = null): bool\n    {\n        return $this->getStartDate()->lessThan($this->resolveCarbon($date));\n    }\n\n    /**\n     * Determines if the start date is before or the same as a given date.\n     * (Rather start/end are included by options is ignored.)\n     *\n     * @param mixed $date\n     *\n     * @return bool\n     */\n    public function startsBeforeOrAt($date = null): bool\n    {\n        return $this->getStartDate()->lessThanOrEqualTo($this->resolveCarbon($date));\n    }\n\n    /**\n     * Determines if the start date is after an other given date.\n     * (Rather start/end are included by options is ignored.)\n     *\n     * @param mixed $date\n     *\n     * @return bool\n     */\n    public function startsAfter($date = null): bool\n    {\n        return $this->getStartDate()->greaterThan($this->resolveCarbon($date));\n    }\n\n    /**\n     * Determines if the start date is after or the same as a given date.\n     * (Rather start/end are included by options is ignored.)\n     *\n     * @param mixed $date\n     *\n     * @return bool\n     */\n    public function startsAfterOrAt($date = null): bool\n    {\n        return $this->getStartDate()->greaterThanOrEqualTo($this->resolveCarbon($date));\n    }\n\n    /**\n     * Determines if the start date is the same as a given date.\n     * (Rather start/end are included by options is ignored.)\n     *\n     * @param mixed $date\n     *\n     * @return bool\n     */\n    public function startsAt($date = null): bool\n    {\n        return $this->getStartDate()->equalTo($this->resolveCarbon($date));\n    }\n\n    /**\n     * Determines if the end date is before an other given date.\n     * (Rather start/end are included by options is ignored.)\n     *\n     * @param mixed $date\n     *\n     * @return bool\n     */\n    public function endsBefore($date = null): bool\n    {\n        return $this->calculateEnd()->lessThan($this->resolveCarbon($date));\n    }\n\n    /**\n     * Determines if the end date is before or the same as a given date.\n     * (Rather start/end are included by options is ignored.)\n     *\n     * @param mixed $date\n     *\n     * @return bool\n     */\n    public function endsBeforeOrAt($date = null): bool\n    {\n        return $this->calculateEnd()->lessThanOrEqualTo($this->resolveCarbon($date));\n    }\n\n    /**\n     * Determines if the end date is after an other given date.\n     * (Rather start/end are included by options is ignored.)\n     *\n     * @param mixed $date\n     *\n     * @return bool\n     */\n    public function endsAfter($date = null): bool\n    {\n        return $this->calculateEnd()->greaterThan($this->resolveCarbon($date));\n    }\n\n    /**\n     * Determines if the end date is after or the same as a given date.\n     * (Rather start/end are included by options is ignored.)\n     *\n     * @param mixed $date\n     *\n     * @return bool\n     */\n    public function endsAfterOrAt($date = null): bool\n    {\n        return $this->calculateEnd()->greaterThanOrEqualTo($this->resolveCarbon($date));\n    }\n\n    /**\n     * Determines if the end date is the same as a given date.\n     * (Rather start/end are included by options is ignored.)\n     *\n     * @param mixed $date\n     *\n     * @return bool\n     */\n    public function endsAt($date = null): bool\n    {\n        return $this->calculateEnd()->equalTo($this->resolveCarbon($date));\n    }\n\n    /**\n     * Return true if start date is now or later.\n     * (Rather start/end are included by options is ignored.)\n     *\n     * @return bool\n     */\n    public function isStarted(): bool\n    {\n        return $this->startsBeforeOrAt();\n    }\n\n    /**\n     * Return true if end date is now or later.\n     * (Rather start/end are included by options is ignored.)\n     *\n     * @return bool\n     */\n    public function isEnded(): bool\n    {\n        return $this->endsBeforeOrAt();\n    }\n\n    /**\n     * Return true if now is between start date (included) and end date (excluded).\n     * (Rather start/end are included by options is ignored.)\n     *\n     * @return bool\n     */\n    public function isInProgress(): bool\n    {\n        return $this->isStarted() && !$this->isEnded();\n    }\n\n    /**\n     * Round the current instance at the given unit with given precision if specified and the given function.\n     *\n     * @param string                              $unit\n     * @param float|int|string|\\DateInterval|null $precision\n     * @param string                              $function\n     *\n     * @return static\n     */\n    public function roundUnit($unit, $precision = 1, $function = 'round')\n    {\n        $self = $this->copyIfImmutable();\n        $self = $self->setStartDate($self->getStartDate()->roundUnit($unit, $precision, $function));\n\n        if ($self->endDate) {\n            $self = $self->setEndDate($self->getEndDate()->roundUnit($unit, $precision, $function));\n        }\n\n        return $self->setDateInterval($self->getDateInterval()->roundUnit($unit, $precision, $function));\n    }\n\n    /**\n     * Truncate the current instance at the given unit with given precision if specified.\n     *\n     * @param string                              $unit\n     * @param float|int|string|\\DateInterval|null $precision\n     *\n     * @return static\n     */\n    public function floorUnit($unit, $precision = 1)\n    {\n        return $this->roundUnit($unit, $precision, 'floor');\n    }\n\n    /**\n     * Ceil the current instance at the given unit with given precision if specified.\n     *\n     * @param string                              $unit\n     * @param float|int|string|\\DateInterval|null $precision\n     *\n     * @return static\n     */\n    public function ceilUnit($unit, $precision = 1)\n    {\n        return $this->roundUnit($unit, $precision, 'ceil');\n    }\n\n    /**\n     * Round the current instance second with given precision if specified (else period interval is used).\n     *\n     * @param float|int|string|\\DateInterval|null $precision\n     * @param string                              $function\n     *\n     * @return static\n     */\n    public function round($precision = null, $function = 'round')\n    {\n        return $this->roundWith(\n            $precision ?? $this->getDateInterval()->setLocalTranslator(TranslatorImmutable::get('en'))->forHumans(),\n            $function\n        );\n    }\n\n    /**\n     * Round the current instance second with given precision if specified (else period interval is used).\n     *\n     * @param float|int|string|\\DateInterval|null $precision\n     *\n     * @return static\n     */\n    public function floor($precision = null)\n    {\n        return $this->round($precision, 'floor');\n    }\n\n    /**\n     * Ceil the current instance second with given precision if specified (else period interval is used).\n     *\n     * @param float|int|string|\\DateInterval|null $precision\n     *\n     * @return static\n     */\n    public function ceil($precision = null)\n    {\n        return $this->round($precision, 'ceil');\n    }\n\n    /**\n     * Specify data which should be serialized to JSON.\n     *\n     * @link https://php.net/manual/en/jsonserializable.jsonserialize.php\n     *\n     * @return CarbonInterface[]\n     */\n    #[ReturnTypeWillChange]\n    public function jsonSerialize()\n    {\n        return $this->toArray();\n    }\n\n    /**\n     * Return true if the given date is between start and end.\n     *\n     * @param \\Carbon\\Carbon|\\Carbon\\CarbonPeriod|\\Carbon\\CarbonInterval|\\DateInterval|\\DatePeriod|\\DateTimeInterface|string|null $date\n     *\n     * @return bool\n     */\n    public function contains($date = null): bool\n    {\n        $startMethod = 'startsBefore'.($this->isStartIncluded() ? 'OrAt' : '');\n        $endMethod = 'endsAfter'.($this->isEndIncluded() ? 'OrAt' : '');\n\n        return $this->$startMethod($date) && $this->$endMethod($date);\n    }\n\n    /**\n     * Return true if the current period follows a given other period (with no overlap).\n     * For instance, [2019-08-01 -> 2019-08-12] follows [2019-07-29 -> 2019-07-31]\n     * Note than in this example, follows() would be false if 2019-08-01 or 2019-07-31 was excluded by options.\n     *\n     * @param \\Carbon\\CarbonPeriod|\\DatePeriod|string $period\n     *\n     * @return bool\n     */\n    public function follows($period, ...$arguments): bool\n    {\n        $period = $this->resolveCarbonPeriod($period, ...$arguments);\n\n        return $this->getIncludedStartDate()->equalTo($period->getIncludedEndDate()->add($period->getDateInterval()));\n    }\n\n    /**\n     * Return true if the given other period follows the current one (with no overlap).\n     * For instance, [2019-07-29 -> 2019-07-31] is followed by [2019-08-01 -> 2019-08-12]\n     * Note than in this example, isFollowedBy() would be false if 2019-08-01 or 2019-07-31 was excluded by options.\n     *\n     * @param \\Carbon\\CarbonPeriod|\\DatePeriod|string $period\n     *\n     * @return bool\n     */\n    public function isFollowedBy($period, ...$arguments): bool\n    {\n        $period = $this->resolveCarbonPeriod($period, ...$arguments);\n\n        return $period->follows($this);\n    }\n\n    /**\n     * Return true if the given period either follows or is followed by the current one.\n     *\n     * @see follows()\n     * @see isFollowedBy()\n     *\n     * @param \\Carbon\\CarbonPeriod|\\DatePeriod|string $period\n     *\n     * @return bool\n     */\n    public function isConsecutiveWith($period, ...$arguments): bool\n    {\n        return $this->follows($period, ...$arguments) || $this->isFollowedBy($period, ...$arguments);\n    }\n\n    /**\n     * Update properties after removing built-in filters.\n     *\n     * @return void\n     */\n    protected function updateInternalState()\n    {\n        if (!$this->hasFilter(static::END_DATE_FILTER)) {\n            $this->endDate = null;\n        }\n\n        if (!$this->hasFilter(static::RECURRENCES_FILTER)) {\n            $this->recurrences = null;\n        }\n    }\n\n    /**\n     * Create a filter tuple from raw parameters.\n     *\n     * Will create an automatic filter callback for one of Carbon's is* methods.\n     *\n     * @param array $parameters\n     *\n     * @return array\n     */\n    protected function createFilterTuple(array $parameters)\n    {\n        $method = array_shift($parameters);\n\n        if (!$this->isCarbonPredicateMethod($method)) {\n            return [$method, array_shift($parameters)];\n        }\n\n        return [function ($date) use ($method, $parameters) {\n            return ([$date, $method])(...$parameters);\n        }, $method];\n    }\n\n    /**\n     * Return whether given callable is a string pointing to one of Carbon's is* methods\n     * and should be automatically converted to a filter callback.\n     *\n     * @param callable $callable\n     *\n     * @return bool\n     */\n    protected function isCarbonPredicateMethod($callable)\n    {\n        return \\is_string($callable) && str_starts_with($callable, 'is') &&\n            (method_exists($this->dateClass, $callable) || ([$this->dateClass, 'hasMacro'])($callable));\n    }\n\n    /**\n     * Recurrences filter callback (limits number of recurrences).\n     *\n     * @SuppressWarnings(PHPMD.UnusedFormalParameter)\n     *\n     * @param \\Carbon\\Carbon $current\n     * @param int            $key\n     *\n     * @return bool|string\n     */\n    protected function filterRecurrences($current, $key)\n    {\n        if ($key < $this->recurrences) {\n            return true;\n        }\n\n        return static::END_ITERATION;\n    }\n\n    /**\n     * End date filter callback.\n     *\n     * @param \\Carbon\\Carbon $current\n     *\n     * @return bool|string\n     */\n    protected function filterEndDate($current)\n    {\n        if (!$this->isEndExcluded() && $current == $this->endDate) {\n            return true;\n        }\n\n        if ($this->dateInterval->invert ? $current > $this->endDate : $current < $this->endDate) {\n            return true;\n        }\n\n        return static::END_ITERATION;\n    }\n\n    /**\n     * End iteration filter callback.\n     *\n     * @return string\n     */\n    protected function endIteration()\n    {\n        return static::END_ITERATION;\n    }\n\n    /**\n     * Handle change of the parameters.\n     */\n    protected function handleChangedParameters()\n    {\n        if (($this->getOptions() & static::IMMUTABLE) && $this->dateClass === Carbon::class) {\n            $this->dateClass = CarbonImmutable::class;\n        } elseif (!($this->getOptions() & static::IMMUTABLE) && $this->dateClass === CarbonImmutable::class) {\n            $this->dateClass = Carbon::class;\n        }\n\n        $this->validationResult = null;\n    }\n\n    /**\n     * Validate current date and stop iteration when necessary.\n     *\n     * Returns true when current date is valid, false if it is not, or static::END_ITERATION\n     * when iteration should be stopped.\n     *\n     * @return bool|string\n     */\n    protected function validateCurrentDate()\n    {\n        if ($this->current === null) {\n            $this->rewind();\n        }\n\n        // Check after the first rewind to avoid repeating the initial validation.\n        return $this->validationResult ?? ($this->validationResult = $this->checkFilters());\n    }\n\n    /**\n     * Check whether current value and key pass all the filters.\n     *\n     * @return bool|string\n     */\n    protected function checkFilters()\n    {\n        $current = $this->prepareForReturn($this->current);\n\n        foreach ($this->filters as $tuple) {\n            $result = \\call_user_func(\n                $tuple[0],\n                $current->avoidMutation(),\n                $this->key,\n                $this\n            );\n\n            if ($result === static::END_ITERATION) {\n                return static::END_ITERATION;\n            }\n\n            if (!$result) {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    /**\n     * Prepare given date to be returned to the external logic.\n     *\n     * @param CarbonInterface $date\n     *\n     * @return CarbonInterface\n     */\n    protected function prepareForReturn(CarbonInterface $date)\n    {\n        $date = ([$this->dateClass, 'make'])($date);\n\n        if ($this->timezone) {\n            $date = $date->setTimezone($this->timezone);\n        }\n\n        return $date;\n    }\n\n    /**\n     * Keep incrementing the current date until a valid date is found or the iteration is ended.\n     *\n     * @throws RuntimeException\n     *\n     * @return void\n     */\n    protected function incrementCurrentDateUntilValid()\n    {\n        $attempts = 0;\n\n        do {\n            $this->current = $this->current->add($this->dateInterval);\n\n            $this->validationResult = null;\n\n            if (++$attempts > static::NEXT_MAX_ATTEMPTS) {\n                throw new UnreachableException('Could not find next valid date.');\n            }\n        } while ($this->validateCurrentDate() === false);\n    }\n\n    /**\n     * Call given macro.\n     *\n     * @param string $name\n     * @param array  $parameters\n     *\n     * @return mixed\n     */\n    protected function callMacro($name, $parameters)\n    {\n        $macro = static::$macros[$name];\n\n        if ($macro instanceof Closure) {\n            $boundMacro = @$macro->bindTo($this, static::class) ?: @$macro->bindTo(null, static::class);\n\n            return ($boundMacro ?: $macro)(...$parameters);\n        }\n\n        return $macro(...$parameters);\n    }\n\n    /**\n     * Return the Carbon instance passed through, a now instance in the same timezone\n     * if null given or parse the input if string given.\n     *\n     * @param \\Carbon\\Carbon|\\Carbon\\CarbonPeriod|\\Carbon\\CarbonInterval|\\DateInterval|\\DatePeriod|\\DateTimeInterface|string|null $date\n     *\n     * @return \\Carbon\\CarbonInterface\n     */\n    protected function resolveCarbon($date = null)\n    {\n        return $this->getStartDate()->nowWithSameTz()->carbonize($date);\n    }\n\n    /**\n     * Resolve passed arguments or DatePeriod to a CarbonPeriod object.\n     *\n     * @param mixed $period\n     * @param mixed ...$arguments\n     *\n     * @return static\n     */\n    protected function resolveCarbonPeriod($period, ...$arguments)\n    {\n        if ($period instanceof self) {\n            return $period;\n        }\n\n        return $period instanceof DatePeriod\n            ? static::instance($period)\n            : static::create($period, ...$arguments);\n    }\n\n    private function orderCouple($first, $second): array\n    {\n        return $first > $second ? [$second, $first] : [$first, $second];\n    }\n\n    private function makeDateTime($value): ?DateTimeInterface\n    {\n        if ($value instanceof DateTimeInterface) {\n            return $value;\n        }\n\n        if (\\is_string($value)) {\n            $value = trim($value);\n\n            if (!preg_match('/^P[\\dT]/', $value) &&\n                !preg_match('/^R\\d/', $value) &&\n                preg_match('/[a-z\\d]/i', $value)\n            ) {\n                $dateClass = $this->dateClass;\n\n                return $dateClass::parse($value, $this->tzName);\n            }\n        }\n\n        return null;\n    }\n\n    private function isInfiniteDate($date): bool\n    {\n        return $date instanceof CarbonInterface && ($date->isEndOfTime() || $date->isStartOfTime());\n    }\n\n    private function rawDate($date): ?DateTimeInterface\n    {\n        if ($date === false || $date === null) {\n            return null;\n        }\n\n        if ($date instanceof CarbonInterface) {\n            return $date->isMutable()\n                ? $date->toDateTime()\n                : $date->toDateTimeImmutable();\n        }\n\n        if (\\in_array(\\get_class($date), [DateTime::class, DateTimeImmutable::class], true)) {\n            return $date;\n        }\n\n        $class = $date instanceof DateTime ? DateTime::class : DateTimeImmutable::class;\n\n        return new $class($date->format('Y-m-d H:i:s.u'), $date->getTimezone());\n    }\n\n    private static function setDefaultParameters(array &$parameters, array $defaults): void\n    {\n        foreach ($defaults as [$index, $name, $value]) {\n            if (!\\array_key_exists($index, $parameters) && !\\array_key_exists($name, $parameters)) {\n                $parameters[$index] = $value;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/CarbonPeriodImmutable.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon;\n\nclass CarbonPeriodImmutable extends CarbonPeriod\n{\n    /**\n     * Default date class of iteration items.\n     *\n     * @var string\n     */\n    protected const DEFAULT_DATE_CLASS = CarbonImmutable::class;\n\n    /**\n     * Date class of iteration items.\n     *\n     * @var string\n     */\n    protected $dateClass = CarbonImmutable::class;\n\n    /**\n     * Prepare the instance to be set (self if mutable to be mutated,\n     * copy if immutable to generate a new instance).\n     *\n     * @return static\n     */\n    protected function copyIfImmutable()\n    {\n        return $this->constructed ? clone $this : $this;\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/CarbonTimeZone.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon;\n\nuse Carbon\\Exceptions\\InvalidCastException;\nuse Carbon\\Exceptions\\InvalidTimeZoneException;\nuse DateTimeInterface;\nuse DateTimeZone;\nuse Throwable;\n\nclass CarbonTimeZone extends DateTimeZone\n{\n    public function __construct($timezone = null)\n    {\n        parent::__construct(static::getDateTimeZoneNameFromMixed($timezone));\n    }\n\n    protected static function parseNumericTimezone($timezone)\n    {\n        if ($timezone <= -100 || $timezone >= 100) {\n            throw new InvalidTimeZoneException('Absolute timezone offset cannot be greater than 100.');\n        }\n\n        return ($timezone >= 0 ? '+' : '').ltrim($timezone, '+').':00';\n    }\n\n    protected static function getDateTimeZoneNameFromMixed($timezone)\n    {\n        if ($timezone === null) {\n            return date_default_timezone_get();\n        }\n\n        if (\\is_string($timezone)) {\n            $timezone = preg_replace('/^\\s*([+-]\\d+)(\\d{2})\\s*$/', '$1:$2', $timezone);\n        }\n\n        if (is_numeric($timezone)) {\n            return static::parseNumericTimezone($timezone);\n        }\n\n        return $timezone;\n    }\n\n    protected static function getDateTimeZoneFromName(&$name)\n    {\n        return @timezone_open($name = (string) static::getDateTimeZoneNameFromMixed($name));\n    }\n\n    /**\n     * Cast the current instance into the given class.\n     *\n     * @param string $className The $className::instance() method will be called to cast the current object.\n     *\n     * @return DateTimeZone\n     */\n    public function cast(string $className)\n    {\n        if (!method_exists($className, 'instance')) {\n            if (is_a($className, DateTimeZone::class, true)) {\n                return new $className($this->getName());\n            }\n\n            throw new InvalidCastException(\"$className has not the instance() method needed to cast the date.\");\n        }\n\n        return $className::instance($this);\n    }\n\n    /**\n     * Create a CarbonTimeZone from mixed input.\n     *\n     * @param DateTimeZone|string|int|null $object     original value to get CarbonTimeZone from it.\n     * @param DateTimeZone|string|int|null $objectDump dump of the object for error messages.\n     *\n     * @throws InvalidTimeZoneException\n     *\n     * @return false|static\n     */\n    public static function instance($object = null, $objectDump = null)\n    {\n        $tz = $object;\n\n        if ($tz instanceof static) {\n            return $tz;\n        }\n\n        if ($tz === null) {\n            return new static();\n        }\n\n        if (!$tz instanceof DateTimeZone) {\n            $tz = static::getDateTimeZoneFromName($object);\n        }\n\n        if ($tz !== false) {\n            return new static($tz->getName());\n        }\n\n        if (Carbon::isStrictModeEnabled()) {\n            throw new InvalidTimeZoneException('Unknown or bad timezone ('.($objectDump ?: $object).')');\n        }\n\n        return false;\n    }\n\n    /**\n     * Returns abbreviated name of the current timezone according to DST setting.\n     *\n     * @param bool $dst\n     *\n     * @return string\n     */\n    public function getAbbreviatedName($dst = false)\n    {\n        $name = $this->getName();\n\n        foreach ($this->listAbbreviations() as $abbreviation => $zones) {\n            foreach ($zones as $zone) {\n                if ($zone['timezone_id'] === $name && $zone['dst'] == $dst) {\n                    return $abbreviation;\n                }\n            }\n        }\n\n        return 'unknown';\n    }\n\n    /**\n     * @alias getAbbreviatedName\n     *\n     * Returns abbreviated name of the current timezone according to DST setting.\n     *\n     * @param bool $dst\n     *\n     * @return string\n     */\n    public function getAbbr($dst = false)\n    {\n        return $this->getAbbreviatedName($dst);\n    }\n\n    /**\n     * Get the offset as string \"sHH:MM\" (such as \"+00:00\" or \"-12:30\").\n     *\n     * @param DateTimeInterface|null $date\n     *\n     * @return string\n     */\n    public function toOffsetName(?DateTimeInterface $date = null)\n    {\n        return static::getOffsetNameFromMinuteOffset(\n            $this->getOffset($date ?: Carbon::now($this)) / 60\n        );\n    }\n\n    /**\n     * Returns a new CarbonTimeZone object using the offset string instead of region string.\n     *\n     * @param DateTimeInterface|null $date\n     *\n     * @return CarbonTimeZone\n     */\n    public function toOffsetTimeZone(?DateTimeInterface $date = null)\n    {\n        return new static($this->toOffsetName($date));\n    }\n\n    /**\n     * Returns the first region string (such as \"America/Toronto\") that matches the current timezone or\n     * false if no match is found.\n     *\n     * @see timezone_name_from_abbr native PHP function.\n     *\n     * @param DateTimeInterface|null $date\n     * @param int                    $isDst\n     *\n     * @return string|false\n     */\n    public function toRegionName(?DateTimeInterface $date = null, $isDst = 1)\n    {\n        $name = $this->getName();\n        $firstChar = substr($name, 0, 1);\n\n        if ($firstChar !== '+' && $firstChar !== '-') {\n            return $name;\n        }\n\n        $date = $date ?: Carbon::now($this);\n\n        // Integer construction no longer supported since PHP 8\n        // @codeCoverageIgnoreStart\n        try {\n            $offset = @$this->getOffset($date) ?: 0;\n        } catch (Throwable $e) {\n            $offset = 0;\n        }\n        // @codeCoverageIgnoreEnd\n\n        $name = @timezone_name_from_abbr('', $offset, $isDst);\n\n        if ($name) {\n            return $name;\n        }\n\n        foreach (timezone_identifiers_list() as $timezone) {\n            if (Carbon::instance($date)->tz($timezone)->getOffset() === $offset) {\n                return $timezone;\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * Returns a new CarbonTimeZone object using the region string instead of offset string.\n     *\n     * @param DateTimeInterface|null $date\n     *\n     * @return CarbonTimeZone|false\n     */\n    public function toRegionTimeZone(?DateTimeInterface $date = null)\n    {\n        $tz = $this->toRegionName($date);\n\n        if ($tz !== false) {\n            return new static($tz);\n        }\n\n        if (Carbon::isStrictModeEnabled()) {\n            throw new InvalidTimeZoneException('Unknown timezone for offset '.$this->getOffset($date ?: Carbon::now($this)).' seconds.');\n        }\n\n        return false;\n    }\n\n    /**\n     * Cast to string (get timezone name).\n     *\n     * @return string\n     */\n    public function __toString()\n    {\n        return $this->getName();\n    }\n\n    /**\n     * Return the type number:\n     *\n     * Type 1; A UTC offset, such as -0300\n     * Type 2; A timezone abbreviation, such as GMT\n     * Type 3: A timezone identifier, such as Europe/London\n     */\n    public function getType(): int\n    {\n        return preg_match('/\"timezone_type\";i:(\\d)/', serialize($this), $match) ? (int) $match[1] : 3;\n    }\n\n    /**\n     * Create a CarbonTimeZone from mixed input.\n     *\n     * @param DateTimeZone|string|int|null $object\n     *\n     * @return false|static\n     */\n    public static function create($object = null)\n    {\n        return static::instance($object);\n    }\n\n    /**\n     * Create a CarbonTimeZone from int/float hour offset.\n     *\n     * @param float $hourOffset number of hour of the timezone shift (can be decimal).\n     *\n     * @return false|static\n     */\n    public static function createFromHourOffset(float $hourOffset)\n    {\n        return static::createFromMinuteOffset($hourOffset * Carbon::MINUTES_PER_HOUR);\n    }\n\n    /**\n     * Create a CarbonTimeZone from int/float minute offset.\n     *\n     * @param float $minuteOffset number of total minutes of the timezone shift.\n     *\n     * @return false|static\n     */\n    public static function createFromMinuteOffset(float $minuteOffset)\n    {\n        return static::instance(static::getOffsetNameFromMinuteOffset($minuteOffset));\n    }\n\n    /**\n     * Convert a total minutes offset into a standardized timezone offset string.\n     *\n     * @param float $minutes number of total minutes of the timezone shift.\n     *\n     * @return string\n     */\n    public static function getOffsetNameFromMinuteOffset(float $minutes): string\n    {\n        $minutes = round($minutes);\n        $unsignedMinutes = abs($minutes);\n\n        return ($minutes < 0 ? '-' : '+').\n            str_pad((string) floor($unsignedMinutes / 60), 2, '0', STR_PAD_LEFT).\n            ':'.\n            str_pad((string) ($unsignedMinutes % 60), 2, '0', STR_PAD_LEFT);\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Cli/Invoker.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Cli;\n\nclass Invoker\n{\n    public const CLI_CLASS_NAME = 'Carbon\\\\Cli';\n\n    protected function runWithCli(string $className, array $parameters): bool\n    {\n        $cli = new $className();\n\n        return $cli(...$parameters);\n    }\n\n    public function __invoke(...$parameters): bool\n    {\n        if (class_exists(self::CLI_CLASS_NAME)) {\n            return $this->runWithCli(self::CLI_CLASS_NAME, $parameters);\n        }\n\n        $function = (($parameters[1] ?? '') === 'install' ? ($parameters[2] ?? null) : null) ?: 'shell_exec';\n        $function('composer require carbon-cli/carbon-cli --no-interaction');\n\n        echo 'Installation succeeded.';\n\n        return true;\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Exceptions/BadComparisonUnitException.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Exceptions;\n\nuse Throwable;\n\nclass BadComparisonUnitException extends UnitException\n{\n    /**\n     * The unit.\n     *\n     * @var string\n     */\n    protected $unit;\n\n    /**\n     * Constructor.\n     *\n     * @param string         $unit\n     * @param int            $code\n     * @param Throwable|null $previous\n     */\n    public function __construct($unit, $code = 0, ?Throwable $previous = null)\n    {\n        $this->unit = $unit;\n\n        parent::__construct(\"Bad comparison unit: '$unit'\", $code, $previous);\n    }\n\n    /**\n     * Get the unit.\n     *\n     * @return string\n     */\n    public function getUnit(): string\n    {\n        return $this->unit;\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Exceptions/BadFluentConstructorException.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Exceptions;\n\nuse BadMethodCallException as BaseBadMethodCallException;\nuse Throwable;\n\nclass BadFluentConstructorException extends BaseBadMethodCallException implements BadMethodCallException\n{\n    /**\n     * The method.\n     *\n     * @var string\n     */\n    protected $method;\n\n    /**\n     * Constructor.\n     *\n     * @param string         $method\n     * @param int            $code\n     * @param Throwable|null $previous\n     */\n    public function __construct($method, $code = 0, ?Throwable $previous = null)\n    {\n        $this->method = $method;\n\n        parent::__construct(\\sprintf(\"Unknown fluent constructor '%s'.\", $method), $code, $previous);\n    }\n\n    /**\n     * Get the method.\n     *\n     * @return string\n     */\n    public function getMethod(): string\n    {\n        return $this->method;\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Exceptions/BadFluentSetterException.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Exceptions;\n\nuse BadMethodCallException as BaseBadMethodCallException;\nuse Throwable;\n\nclass BadFluentSetterException extends BaseBadMethodCallException implements BadMethodCallException\n{\n    /**\n     * The setter.\n     *\n     * @var string\n     */\n    protected $setter;\n\n    /**\n     * Constructor.\n     *\n     * @param string         $setter\n     * @param int            $code\n     * @param Throwable|null $previous\n     */\n    public function __construct($setter, $code = 0, ?Throwable $previous = null)\n    {\n        $this->setter = $setter;\n\n        parent::__construct(\\sprintf(\"Unknown fluent setter '%s'\", $setter), $code, $previous);\n    }\n\n    /**\n     * Get the setter.\n     *\n     * @return string\n     */\n    public function getSetter(): string\n    {\n        return $this->setter;\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Exceptions/BadMethodCallException.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Exceptions;\n\ninterface BadMethodCallException extends Exception\n{\n    //\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Exceptions/EndLessPeriodException.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Exceptions;\n\nuse RuntimeException as BaseRuntimeException;\n\nfinal class EndLessPeriodException extends BaseRuntimeException implements RuntimeException\n{\n    //\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Exceptions/Exception.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Exceptions;\n\ninterface Exception\n{\n    //\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Exceptions/ImmutableException.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Exceptions;\n\nuse RuntimeException as BaseRuntimeException;\nuse Throwable;\n\nclass ImmutableException extends BaseRuntimeException implements RuntimeException\n{\n    /**\n     * The value.\n     *\n     * @var string\n     */\n    protected $value;\n\n    /**\n     * Constructor.\n     *\n     * @param string         $value    the immutable type/value\n     * @param int            $code\n     * @param Throwable|null $previous\n     */\n    public function __construct($value, $code = 0, ?Throwable $previous = null)\n    {\n        $this->value = $value;\n        parent::__construct(\"$value is immutable.\", $code, $previous);\n    }\n\n    /**\n     * Get the value.\n     *\n     * @return string\n     */\n    public function getValue(): string\n    {\n        return $this->value;\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Exceptions/InvalidArgumentException.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Exceptions;\n\ninterface InvalidArgumentException extends Exception\n{\n    //\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Exceptions/InvalidCastException.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Exceptions;\n\nuse InvalidArgumentException as BaseInvalidArgumentException;\n\nclass InvalidCastException extends BaseInvalidArgumentException implements InvalidArgumentException\n{\n    //\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Exceptions/InvalidDateException.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Exceptions;\n\nuse InvalidArgumentException as BaseInvalidArgumentException;\nuse Throwable;\n\nclass InvalidDateException extends BaseInvalidArgumentException implements InvalidArgumentException\n{\n    /**\n     * The invalid field.\n     *\n     * @var string\n     */\n    private $field;\n\n    /**\n     * The invalid value.\n     *\n     * @var mixed\n     */\n    private $value;\n\n    /**\n     * Constructor.\n     *\n     * @param string         $field\n     * @param mixed          $value\n     * @param int            $code\n     * @param Throwable|null $previous\n     */\n    public function __construct($field, $value, $code = 0, ?Throwable $previous = null)\n    {\n        $this->field = $field;\n        $this->value = $value;\n        parent::__construct($field.' : '.$value.' is not a valid value.', $code, $previous);\n    }\n\n    /**\n     * Get the invalid field.\n     *\n     * @return string\n     */\n    public function getField()\n    {\n        return $this->field;\n    }\n\n    /**\n     * Get the invalid value.\n     *\n     * @return mixed\n     */\n    public function getValue()\n    {\n        return $this->value;\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Exceptions/InvalidFormatException.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Exceptions;\n\nuse InvalidArgumentException as BaseInvalidArgumentException;\n\nclass InvalidFormatException extends BaseInvalidArgumentException implements InvalidArgumentException\n{\n    //\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Exceptions/InvalidIntervalException.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Exceptions;\n\nuse InvalidArgumentException as BaseInvalidArgumentException;\n\nclass InvalidIntervalException extends BaseInvalidArgumentException implements InvalidArgumentException\n{\n    //\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Exceptions/InvalidPeriodDateException.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Exceptions;\n\nuse InvalidArgumentException as BaseInvalidArgumentException;\n\nclass InvalidPeriodDateException extends BaseInvalidArgumentException implements InvalidArgumentException\n{\n    //\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Exceptions/InvalidPeriodParameterException.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Exceptions;\n\nuse InvalidArgumentException as BaseInvalidArgumentException;\n\nclass InvalidPeriodParameterException extends BaseInvalidArgumentException implements InvalidArgumentException\n{\n    //\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Exceptions/InvalidTimeZoneException.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Exceptions;\n\nuse InvalidArgumentException as BaseInvalidArgumentException;\n\nclass InvalidTimeZoneException extends BaseInvalidArgumentException implements InvalidArgumentException\n{\n    //\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Exceptions/InvalidTypeException.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Exceptions;\n\nuse InvalidArgumentException as BaseInvalidArgumentException;\n\nclass InvalidTypeException extends BaseInvalidArgumentException implements InvalidArgumentException\n{\n    //\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Exceptions/NotACarbonClassException.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Exceptions;\n\nuse Carbon\\CarbonInterface;\nuse InvalidArgumentException as BaseInvalidArgumentException;\nuse Throwable;\n\nclass NotACarbonClassException extends BaseInvalidArgumentException implements InvalidArgumentException\n{\n    /**\n     * The className.\n     *\n     * @var string\n     */\n    protected $className;\n\n    /**\n     * Constructor.\n     *\n     * @param string         $className\n     * @param int            $code\n     * @param Throwable|null $previous\n     */\n    public function __construct($className, $code = 0, ?Throwable $previous = null)\n    {\n        $this->className = $className;\n\n        parent::__construct(\\sprintf('Given class does not implement %s: %s', CarbonInterface::class, $className), $code, $previous);\n    }\n\n    /**\n     * Get the className.\n     *\n     * @return string\n     */\n    public function getClassName(): string\n    {\n        return $this->className;\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Exceptions/NotAPeriodException.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Exceptions;\n\nuse InvalidArgumentException as BaseInvalidArgumentException;\n\nclass NotAPeriodException extends BaseInvalidArgumentException implements InvalidArgumentException\n{\n    //\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Exceptions/NotLocaleAwareException.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Exceptions;\n\nuse InvalidArgumentException as BaseInvalidArgumentException;\nuse Throwable;\n\nclass NotLocaleAwareException extends BaseInvalidArgumentException implements InvalidArgumentException\n{\n    /**\n     * Constructor.\n     *\n     * @param mixed          $object\n     * @param int            $code\n     * @param Throwable|null $previous\n     */\n    public function __construct($object, $code = 0, ?Throwable $previous = null)\n    {\n        $dump = \\is_object($object) ? \\get_class($object) : \\gettype($object);\n\n        parent::__construct(\"$dump does neither implements Symfony\\Contracts\\Translation\\LocaleAwareInterface nor getLocale() method.\", $code, $previous);\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Exceptions/OutOfRangeException.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Exceptions;\n\nuse InvalidArgumentException as BaseInvalidArgumentException;\nuse Throwable;\n\n// This will extends OutOfRangeException instead of InvalidArgumentException since 3.0.0\n// use OutOfRangeException as BaseOutOfRangeException;\n\nclass OutOfRangeException extends BaseInvalidArgumentException implements InvalidArgumentException\n{\n    /**\n     * The unit or name of the value.\n     *\n     * @var string\n     */\n    private $unit;\n\n    /**\n     * The range minimum.\n     *\n     * @var mixed\n     */\n    private $min;\n\n    /**\n     * The range maximum.\n     *\n     * @var mixed\n     */\n    private $max;\n\n    /**\n     * The invalid value.\n     *\n     * @var mixed\n     */\n    private $value;\n\n    /**\n     * Constructor.\n     *\n     * @param string         $unit\n     * @param mixed          $min\n     * @param mixed          $max\n     * @param mixed          $value\n     * @param int            $code\n     * @param Throwable|null $previous\n     */\n    public function __construct($unit, $min, $max, $value, $code = 0, ?Throwable $previous = null)\n    {\n        $this->unit = $unit;\n        $this->min = $min;\n        $this->max = $max;\n        $this->value = $value;\n\n        parent::__construct(\"$unit must be between $min and $max, $value given\", $code, $previous);\n    }\n\n    /**\n     * @return mixed\n     */\n    public function getMax()\n    {\n        return $this->max;\n    }\n\n    /**\n     * @return mixed\n     */\n    public function getMin()\n    {\n        return $this->min;\n    }\n\n    /**\n     * @return mixed\n     */\n    public function getUnit()\n    {\n        return $this->unit;\n    }\n\n    /**\n     * @return mixed\n     */\n    public function getValue()\n    {\n        return $this->value;\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Exceptions/ParseErrorException.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Exceptions;\n\nuse InvalidArgumentException as BaseInvalidArgumentException;\nuse Throwable;\n\nclass ParseErrorException extends BaseInvalidArgumentException implements InvalidArgumentException\n{\n    /**\n     * The expected.\n     *\n     * @var string\n     */\n    protected $expected;\n\n    /**\n     * The actual.\n     *\n     * @var string\n     */\n    protected $actual;\n\n    /**\n     * The help message.\n     *\n     * @var string\n     */\n    protected $help;\n\n    /**\n     * Constructor.\n     *\n     * @param string         $expected\n     * @param string         $actual\n     * @param int            $code\n     * @param Throwable|null $previous\n     */\n    public function __construct($expected, $actual, $help = '', $code = 0, ?Throwable $previous = null)\n    {\n        $this->expected = $expected;\n        $this->actual = $actual;\n        $this->help = $help;\n\n        $actual = $actual === '' ? 'data is missing' : \"get '$actual'\";\n\n        parent::__construct(trim(\"Format expected $expected but $actual\\n$help\"), $code, $previous);\n    }\n\n    /**\n     * Get the expected.\n     *\n     * @return string\n     */\n    public function getExpected(): string\n    {\n        return $this->expected;\n    }\n\n    /**\n     * Get the actual.\n     *\n     * @return string\n     */\n    public function getActual(): string\n    {\n        return $this->actual;\n    }\n\n    /**\n     * Get the help message.\n     *\n     * @return string\n     */\n    public function getHelp(): string\n    {\n        return $this->help;\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Exceptions/RuntimeException.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Exceptions;\n\ninterface RuntimeException extends Exception\n{\n    //\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Exceptions/UnitException.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Exceptions;\n\nuse InvalidArgumentException as BaseInvalidArgumentException;\n\nclass UnitException extends BaseInvalidArgumentException implements InvalidArgumentException\n{\n    //\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Exceptions/UnitNotConfiguredException.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Exceptions;\n\nuse Throwable;\n\nclass UnitNotConfiguredException extends UnitException\n{\n    /**\n     * The unit.\n     *\n     * @var string\n     */\n    protected $unit;\n\n    /**\n     * Constructor.\n     *\n     * @param string         $unit\n     * @param int            $code\n     * @param Throwable|null $previous\n     */\n    public function __construct($unit, $code = 0, ?Throwable $previous = null)\n    {\n        $this->unit = $unit;\n\n        parent::__construct(\"Unit $unit have no configuration to get total from other units.\", $code, $previous);\n    }\n\n    /**\n     * Get the unit.\n     *\n     * @return string\n     */\n    public function getUnit(): string\n    {\n        return $this->unit;\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Exceptions/UnknownGetterException.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Exceptions;\n\nuse InvalidArgumentException as BaseInvalidArgumentException;\nuse Throwable;\n\nclass UnknownGetterException extends BaseInvalidArgumentException implements InvalidArgumentException\n{\n    /**\n     * The getter.\n     *\n     * @var string\n     */\n    protected $getter;\n\n    /**\n     * Constructor.\n     *\n     * @param string         $getter   getter name\n     * @param int            $code\n     * @param Throwable|null $previous\n     */\n    public function __construct($getter, $code = 0, ?Throwable $previous = null)\n    {\n        $this->getter = $getter;\n\n        parent::__construct(\"Unknown getter '$getter'\", $code, $previous);\n    }\n\n    /**\n     * Get the getter.\n     *\n     * @return string\n     */\n    public function getGetter(): string\n    {\n        return $this->getter;\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Exceptions/UnknownMethodException.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Exceptions;\n\nuse BadMethodCallException as BaseBadMethodCallException;\nuse Throwable;\n\nclass UnknownMethodException extends BaseBadMethodCallException implements BadMethodCallException\n{\n    /**\n     * The method.\n     *\n     * @var string\n     */\n    protected $method;\n\n    /**\n     * Constructor.\n     *\n     * @param string         $method\n     * @param int            $code\n     * @param Throwable|null $previous\n     */\n    public function __construct($method, $code = 0, ?Throwable $previous = null)\n    {\n        $this->method = $method;\n\n        parent::__construct(\"Method $method does not exist.\", $code, $previous);\n    }\n\n    /**\n     * Get the method.\n     *\n     * @return string\n     */\n    public function getMethod(): string\n    {\n        return $this->method;\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Exceptions/UnknownSetterException.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Exceptions;\n\nuse InvalidArgumentException as BaseInvalidArgumentException;\nuse Throwable;\n\nclass UnknownSetterException extends BaseInvalidArgumentException implements BadMethodCallException\n{\n    /**\n     * The setter.\n     *\n     * @var string\n     */\n    protected $setter;\n\n    /**\n     * Constructor.\n     *\n     * @param string         $setter   setter name\n     * @param int            $code\n     * @param Throwable|null $previous\n     */\n    public function __construct($setter, $code = 0, ?Throwable $previous = null)\n    {\n        $this->setter = $setter;\n\n        parent::__construct(\"Unknown setter '$setter'\", $code, $previous);\n    }\n\n    /**\n     * Get the setter.\n     *\n     * @return string\n     */\n    public function getSetter(): string\n    {\n        return $this->setter;\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Exceptions/UnknownUnitException.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Exceptions;\n\nuse Throwable;\n\nclass UnknownUnitException extends UnitException\n{\n    /**\n     * The unit.\n     *\n     * @var string\n     */\n    protected $unit;\n\n    /**\n     * Constructor.\n     *\n     * @param string         $unit\n     * @param int            $code\n     * @param Throwable|null $previous\n     */\n    public function __construct($unit, $code = 0, ?Throwable $previous = null)\n    {\n        $this->unit = $unit;\n\n        parent::__construct(\"Unknown unit '$unit'.\", $code, $previous);\n    }\n\n    /**\n     * Get the unit.\n     *\n     * @return string\n     */\n    public function getUnit(): string\n    {\n        return $this->unit;\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Exceptions/UnreachableException.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Exceptions;\n\nuse RuntimeException as BaseRuntimeException;\n\nclass UnreachableException extends BaseRuntimeException implements RuntimeException\n{\n    //\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Factory.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon;\n\nuse Closure;\nuse DateTimeInterface;\nuse ReflectionMethod;\n\n/**\n * A factory to generate Carbon instances with common settings.\n *\n * <autodoc generated by `composer phpdoc`>\n *\n * @method bool                                               canBeCreatedFromFormat($date, $format)                                                                                       Checks if the (date)time string is in a given format and valid to create a\n *                                                                                                                                                                                         new instance.\n * @method Carbon|false                                       create($year = 0, $month = 1, $day = 1, $hour = 0, $minute = 0, $second = 0, $tz = null)                                     Create a new Carbon instance from a specific date and time.\n *                                                                                                                                                                                         If any of $year, $month or $day are set to null their now() values will\n *                                                                                                                                                                                         be used.\n *                                                                                                                                                                                         If $hour is null it will be set to its now() value and the default\n *                                                                                                                                                                                         values for $minute and $second will be their now() values.\n *                                                                                                                                                                                         If $hour is not null then the default values for $minute and $second\n *                                                                                                                                                                                         will be 0.\n * @method Carbon                                             createFromDate($year = null, $month = null, $day = null, $tz = null)                                                         Create a Carbon instance from just a date. The time portion is set to now.\n * @method Carbon|false                                       createFromFormat($format, $time, $tz = null)                                                                                 Create a Carbon instance from a specific format.\n * @method Carbon|false                                       createFromIsoFormat($format, $time, $tz = null, $locale = 'en', $translator = null)                                          Create a Carbon instance from a specific ISO format (same replacements as ->isoFormat()).\n * @method Carbon|false                                       createFromLocaleFormat($format, $locale, $time, $tz = null)                                                                  Create a Carbon instance from a specific format and a string in a given language.\n * @method Carbon|false                                       createFromLocaleIsoFormat($format, $locale, $time, $tz = null)                                                               Create a Carbon instance from a specific ISO format and a string in a given language.\n * @method Carbon                                             createFromTime($hour = 0, $minute = 0, $second = 0, $tz = null)                                                              Create a Carbon instance from just a time. The date portion is set to today.\n * @method Carbon                                             createFromTimeString($time, $tz = null)                                                                                      Create a Carbon instance from a time string. The date portion is set to today.\n * @method Carbon                                             createFromTimestamp($timestamp, $tz = null)                                                                                  Create a Carbon instance from a timestamp and set the timezone (use default one if not specified).\n *                                                                                                                                                                                         Timestamp input can be given as int, float or a string containing one or more numbers.\n * @method Carbon                                             createFromTimestampMs($timestamp, $tz = null)                                                                                Create a Carbon instance from a timestamp in milliseconds.\n *                                                                                                                                                                                         Timestamp input can be given as int, float or a string containing one or more numbers.\n * @method Carbon                                             createFromTimestampMsUTC($timestamp)                                                                                         Create a Carbon instance from a timestamp in milliseconds.\n *                                                                                                                                                                                         Timestamp input can be given as int, float or a string containing one or more numbers.\n * @method Carbon                                             createFromTimestampUTC($timestamp)                                                                                           Create a Carbon instance from an timestamp keeping the timezone to UTC.\n *                                                                                                                                                                                         Timestamp input can be given as int, float or a string containing one or more numbers.\n * @method Carbon                                             createMidnightDate($year = null, $month = null, $day = null, $tz = null)                                                     Create a Carbon instance from just a date. The time portion is set to midnight.\n * @method Carbon|false                                       createSafe($year = null, $month = null, $day = null, $hour = null, $minute = null, $second = null, $tz = null)               Create a new safe Carbon instance from a specific date and time.\n *                                                                                                                                                                                         If any of $year, $month or $day are set to null their now() values will\n *                                                                                                                                                                                         be used.\n *                                                                                                                                                                                         If $hour is null it will be set to its now() value and the default\n *                                                                                                                                                                                         values for $minute and $second will be their now() values.\n *                                                                                                                                                                                         If $hour is not null then the default values for $minute and $second\n *                                                                                                                                                                                         will be 0.\n *                                                                                                                                                                                         If one of the set values is not valid, an InvalidDateException\n *                                                                                                                                                                                         will be thrown.\n * @method CarbonInterface                                    createStrict(?int $year = 0, ?int $month = 1, ?int $day = 1, ?int $hour = 0, ?int $minute = 0, ?int $second = 0, $tz = null) Create a new Carbon instance from a specific date and time using strict validation.\n * @method Carbon                                             disableHumanDiffOption($humanDiffOption)                                                                                     @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n *                                                                                                                                                                                                     You should rather use the ->settings() method.\n * @method Carbon                                             enableHumanDiffOption($humanDiffOption)                                                                                      @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n *                                                                                                                                                                                                     You should rather use the ->settings() method.\n * @method mixed                                              executeWithLocale($locale, $func)                                                                                            Set the current locale to the given, execute the passed function, reset the locale to previous one,\n *                                                                                                                                                                                         then return the result of the closure (or null if the closure was void).\n * @method Carbon                                             fromSerialized($value)                                                                                                       Create an instance from a serialized string.\n * @method void                                               genericMacro($macro, $priority = 0)                                                                                          Register a custom macro.\n * @method array                                              getAvailableLocales()                                                                                                        Returns the list of internally available locales and already loaded custom locales.\n *                                                                                                                                                                                         (It will ignore custom translator dynamic loading.)\n * @method Language[]                                         getAvailableLocalesInfo()                                                                                                    Returns list of Language object for each available locale. This object allow you to get the ISO name, native\n *                                                                                                                                                                                         name, region and variant of the locale.\n * @method array                                              getDays()                                                                                                                    Get the days of the week\n * @method string|null                                        getFallbackLocale()                                                                                                          Get the fallback locale.\n * @method array                                              getFormatsToIsoReplacements()                                                                                                List of replacements from date() format to isoFormat().\n * @method int                                                getHumanDiffOptions()                                                                                                        Return default humanDiff() options (merged flags as integer).\n * @method array                                              getIsoUnits()                                                                                                                Returns list of locale units for ISO formatting.\n * @method array                                              getLastErrors()                                                                                                              {@inheritdoc}\n * @method string                                             getLocale()                                                                                                                  Get the current translator locale.\n * @method callable|null                                      getMacro($name)                                                                                                              Get the raw callable macro registered globally for a given name.\n * @method int                                                getMidDayAt()                                                                                                                get midday/noon hour\n * @method Closure|Carbon                                     getTestNow()                                                                                                                 Get the Carbon instance (real or mock) to be returned when a \"now\"\n *                                                                                                                                                                                         instance is created.\n * @method string                                             getTimeFormatByPrecision($unitPrecision)                                                                                     Return a format from H:i to H:i:s.u according to given unit precision.\n * @method string                                             getTranslationMessageWith($translator, string $key, ?string $locale = null, ?string $default = null)                         Returns raw translation message for a given key.\n * @method \\Symfony\\Component\\Translation\\TranslatorInterface getTranslator()                                                                                                              Get the default translator instance in use.\n * @method int                                                getWeekEndsAt()                                                                                                              Get the last day of week\n * @method int                                                getWeekStartsAt()                                                                                                            Get the first day of week\n * @method array                                              getWeekendDays()                                                                                                             Get weekend days\n * @method bool                                               hasFormat($date, $format)                                                                                                    Checks if the (date)time string is in a given format.\n * @method bool                                               hasFormatWithModifiers($date, $format)                                                                                       Checks if the (date)time string is in a given format.\n * @method bool                                               hasMacro($name)                                                                                                              Checks if macro is registered globally.\n * @method bool                                               hasRelativeKeywords($time)                                                                                                   Determine if a time string will produce a relative date.\n * @method bool                                               hasTestNow()                                                                                                                 Determine if there is a valid test instance set. A valid test instance\n *                                                                                                                                                                                         is anything that is not null.\n * @method Carbon                                             instance($date)                                                                                                              Create a Carbon instance from a DateTime one.\n * @method bool                                               isImmutable()                                                                                                                Returns true if the current class/instance is immutable.\n * @method bool                                               isModifiableUnit($unit)                                                                                                      Returns true if a property can be changed via setter.\n * @method bool                                               isMutable()                                                                                                                  Returns true if the current class/instance is mutable.\n * @method bool                                               isStrictModeEnabled()                                                                                                        Returns true if the strict mode is globally in use, false else.\n *                                                                                                                                                                                         (It can be overridden in specific instances.)\n * @method bool                                               localeHasDiffOneDayWords($locale)                                                                                            Returns true if the given locale is internally supported and has words for 1-day diff (just now, yesterday, tomorrow).\n *                                                                                                                                                                                         Support is considered enabled if the 3 words are translated in the given locale.\n * @method bool                                               localeHasDiffSyntax($locale)                                                                                                 Returns true if the given locale is internally supported and has diff syntax support (ago, from now, before, after).\n *                                                                                                                                                                                         Support is considered enabled if the 4 sentences are translated in the given locale.\n * @method bool                                               localeHasDiffTwoDayWords($locale)                                                                                            Returns true if the given locale is internally supported and has words for 2-days diff (before yesterday, after tomorrow).\n *                                                                                                                                                                                         Support is considered enabled if the 2 words are translated in the given locale.\n * @method bool                                               localeHasPeriodSyntax($locale)                                                                                               Returns true if the given locale is internally supported and has period syntax support (X times, every X, from X, to X).\n *                                                                                                                                                                                         Support is considered enabled if the 4 sentences are translated in the given locale.\n * @method bool                                               localeHasShortUnits($locale)                                                                                                 Returns true if the given locale is internally supported and has short-units support.\n *                                                                                                                                                                                         Support is considered enabled if either year, day or hour has a short variant translated.\n * @method void                                               macro($name, $macro)                                                                                                         Register a custom macro.\n * @method Carbon|null                                        make($var)                                                                                                                   Make a Carbon instance from given variable if possible.\n *                                                                                                                                                                                         Always return a new instance. Parse only strings and only these likely to be dates (skip intervals\n *                                                                                                                                                                                         and recurrences). Throw an exception for invalid format, but otherwise return null.\n * @method Carbon                                             maxValue()                                                                                                                   Create a Carbon instance for the greatest supported date.\n * @method Carbon                                             minValue()                                                                                                                   Create a Carbon instance for the lowest supported date.\n * @method void                                               mixin($mixin)                                                                                                                Mix another object into the class.\n * @method Carbon                                             now($tz = null)                                                                                                              Get a Carbon instance for the current date and time.\n * @method Carbon                                             parse($time = null, $tz = null)                                                                                              Create a carbon instance from a string.\n *                                                                                                                                                                                         This is an alias for the constructor that allows better fluent syntax\n *                                                                                                                                                                                         as it allows you to do Carbon::parse('Monday next week')->fn() rather\n *                                                                                                                                                                                         than (new Carbon('Monday next week'))->fn().\n * @method Carbon                                             parseFromLocale($time, $locale = null, $tz = null)                                                                           Create a carbon instance from a localized string (in French, Japanese, Arabic, etc.).\n * @method string                                             pluralUnit(string $unit)                                                                                                     Returns standardized plural of a given singular/plural unit name (in English).\n * @method Carbon|false                                       rawCreateFromFormat($format, $time, $tz = null)                                                                              Create a Carbon instance from a specific format.\n * @method Carbon                                             rawParse($time = null, $tz = null)                                                                                           Create a carbon instance from a string.\n *                                                                                                                                                                                         This is an alias for the constructor that allows better fluent syntax\n *                                                                                                                                                                                         as it allows you to do Carbon::parse('Monday next week')->fn() rather\n *                                                                                                                                                                                         than (new Carbon('Monday next week'))->fn().\n * @method Carbon                                             resetMacros()                                                                                                                Remove all macros and generic macros.\n * @method void                                               resetMonthsOverflow()                                                                                                        @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n *                                                                                                                                                                                                     You should rather use the ->settings() method.\n *                                                                                                                                                                                                     Or you can use method variants: addMonthsWithOverflow/addMonthsNoOverflow, same variants\n *                                                                                                                                                                                                     are available for quarters, years, decade, centuries, millennia (singular and plural forms).\n * @method void                                               resetToStringFormat()                                                                                                        Reset the format used to the default when type juggling a Carbon instance to a string\n * @method void                                               resetYearsOverflow()                                                                                                         @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n *                                                                                                                                                                                                     You should rather use the ->settings() method.\n *                                                                                                                                                                                                     Or you can use method variants: addYearsWithOverflow/addYearsNoOverflow, same variants\n *                                                                                                                                                                                                     are available for quarters, years, decade, centuries, millennia (singular and plural forms).\n * @method void                                               serializeUsing($callback)                                                                                                    @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n *                                                                                                                                                                                                     You should rather transform Carbon object before the serialization.\n *                                                                                                                                                                                         JSON serialize all Carbon instances using the given callback.\n * @method Carbon                                             setFallbackLocale($locale)                                                                                                   Set the fallback locale.\n * @method Carbon                                             setHumanDiffOptions($humanDiffOptions)                                                                                       @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n *                                                                                                                                                                                                     You should rather use the ->settings() method.\n * @method bool                                               setLocale($locale)                                                                                                           Set the current translator locale and indicate if the source locale file exists.\n *                                                                                                                                                                                         Pass 'auto' as locale to use closest language from the current LC_TIME locale.\n * @method void                                               setMidDayAt($hour)                                                                                                           @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n *                                                                                                                                                                                                     You should rather consider mid-day is always 12pm, then if you need to test if it's an other\n *                                                                                                                                                                                                     hour, test it explicitly:\n *                                                                                                                                                                                                         $date->format('G') == 13\n *                                                                                                                                                                                                     or to set explicitly to a given hour:\n *                                                                                                                                                                                                         $date->setTime(13, 0, 0, 0)\n *                                                                                                                                                                                         Set midday/noon hour\n * @method Carbon                                             setTestNow($testNow = null)                                                                                                  Set a Carbon instance (real or mock) to be returned when a \"now\"\n *                                                                                                                                                                                         instance is created.  The provided instance will be returned\n *                                                                                                                                                                                         specifically under the following conditions:\n *                                                                                                                                                                                           - A call to the static now() method, ex. Carbon::now()\n *                                                                                                                                                                                           - When a null (or blank string) is passed to the constructor or parse(), ex. new Carbon(null)\n *                                                                                                                                                                                           - When the string \"now\" is passed to the constructor or parse(), ex. new Carbon('now')\n *                                                                                                                                                                                           - When a string containing the desired time is passed to Carbon::parse().\n *                                                                                                                                                                                         Note the timezone parameter was left out of the examples above and\n *                                                                                                                                                                                         has no affect as the mock value will be returned regardless of its value.\n *                                                                                                                                                                                         Only the moment is mocked with setTestNow(), the timezone will still be the one passed\n *                                                                                                                                                                                         as parameter of date_default_timezone_get() as a fallback (see setTestNowAndTimezone()).\n *                                                                                                                                                                                         To clear the test instance call this method using the default\n *                                                                                                                                                                                         parameter of null.\n *                                                                                                                                                                                         /!\\ Use this method for unit tests only.\n * @method Carbon                                             setTestNowAndTimezone($testNow = null, $tz = null)                                                                           Set a Carbon instance (real or mock) to be returned when a \"now\"\n *                                                                                                                                                                                         instance is created.  The provided instance will be returned\n *                                                                                                                                                                                         specifically under the following conditions:\n *                                                                                                                                                                                           - A call to the static now() method, ex. Carbon::now()\n *                                                                                                                                                                                           - When a null (or blank string) is passed to the constructor or parse(), ex. new Carbon(null)\n *                                                                                                                                                                                           - When the string \"now\" is passed to the constructor or parse(), ex. new Carbon('now')\n *                                                                                                                                                                                           - When a string containing the desired time is passed to Carbon::parse().\n *                                                                                                                                                                                         It will also align default timezone (e.g. call date_default_timezone_set()) with\n *                                                                                                                                                                                         the second argument or if null, with the timezone of the given date object.\n *                                                                                                                                                                                         To clear the test instance call this method using the default\n *                                                                                                                                                                                         parameter of null.\n *                                                                                                                                                                                         /!\\ Use this method for unit tests only.\n * @method void                                               setToStringFormat($format)                                                                                                   @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n *                                                                                                                                                                                                     You should rather let Carbon object being cast to string with DEFAULT_TO_STRING_FORMAT, and\n *                                                                                                                                                                                                     use other method or custom format passed to format() method if you need to dump another string\n *                                                                                                                                                                                                     format.\n *                                                                                                                                                                                         Set the default format used when type juggling a Carbon instance to a string.\n * @method void                                               setTranslator(TranslatorInterface $translator)                                                                               Set the default translator instance to use.\n * @method Carbon                                             setUtf8($utf8)                                                                                                               @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n *                                                                                                                                                                                                     You should rather use UTF-8 language packages on every machine.\n *                                                                                                                                                                                         Set if UTF8 will be used for localized date/time.\n * @method void                                               setWeekEndsAt($day)                                                                                                          @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n *                                                                                                                                                                                                     Use $weekStartsAt optional parameter instead when using startOfWeek, floorWeek, ceilWeek\n *                                                                                                                                                                                                     or roundWeek method. You can also use the 'first_day_of_week' locale setting to change the\n *                                                                                                                                                                                                     start of week according to current locale selected and implicitly the end of week.\n *                                                                                                                                                                                         Set the last day of week\n * @method void                                               setWeekStartsAt($day)                                                                                                        @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n *                                                                                                                                                                                                     Use $weekEndsAt optional parameter instead when using endOfWeek method. You can also use the\n *                                                                                                                                                                                                     'first_day_of_week' locale setting to change the start of week according to current locale\n *                                                                                                                                                                                                     selected and implicitly the end of week.\n *                                                                                                                                                                                         Set the first day of week\n * @method void                                               setWeekendDays($days)                                                                                                        @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n *                                                                                                                                                                                                     You should rather consider week-end is always saturday and sunday, and if you have some custom\n *                                                                                                                                                                                                     week-end days to handle, give to those days an other name and create a macro for them:\n *                                                                                                                                                                                                     ```\n *                                                                                                                                                                                                     Carbon::macro('isDayOff', function ($date) {\n *                                                                                                                                                                                                         return $date->isSunday() || $date->isMonday();\n *                                                                                                                                                                                                     });\n *                                                                                                                                                                                                     Carbon::macro('isNotDayOff', function ($date) {\n *                                                                                                                                                                                                         return !$date->isDayOff();\n *                                                                                                                                                                                                     });\n *                                                                                                                                                                                                     if ($someDate->isDayOff()) ...\n *                                                                                                                                                                                                     if ($someDate->isNotDayOff()) ...\n *                                                                                                                                                                                                     // Add 5 not-off days\n *                                                                                                                                                                                                     $count = 5;\n *                                                                                                                                                                                                     while ($someDate->isDayOff() || ($count-- > 0)) {\n *                                                                                                                                                                                                         $someDate->addDay();\n *                                                                                                                                                                                                     }\n *                                                                                                                                                                                                     ```\n *                                                                                                                                                                                         Set weekend days\n * @method bool                                               shouldOverflowMonths()                                                                                                       Get the month overflow global behavior (can be overridden in specific instances).\n * @method bool                                               shouldOverflowYears()                                                                                                        Get the month overflow global behavior (can be overridden in specific instances).\n * @method string                                             singularUnit(string $unit)                                                                                                   Returns standardized singular of a given singular/plural unit name (in English).\n * @method Carbon                                             today($tz = null)                                                                                                            Create a Carbon instance for today.\n * @method Carbon                                             tomorrow($tz = null)                                                                                                         Create a Carbon instance for tomorrow.\n * @method string                                             translateTimeString($timeString, $from = null, $to = null, $mode = CarbonInterface::TRANSLATE_ALL)                           Translate a time string from a locale to an other.\n * @method string                                             translateWith(TranslatorInterface $translator, string $key, array $parameters = [], $number = null)                          Translate using translation string or callback available.\n * @method void                                               useMonthsOverflow($monthsOverflow = true)                                                                                    @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n *                                                                                                                                                                                                     You should rather use the ->settings() method.\n *                                                                                                                                                                                                     Or you can use method variants: addMonthsWithOverflow/addMonthsNoOverflow, same variants\n *                                                                                                                                                                                                     are available for quarters, years, decade, centuries, millennia (singular and plural forms).\n * @method Carbon                                             useStrictMode($strictModeEnabled = true)                                                                                     @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n *                                                                                                                                                                                                     You should rather use the ->settings() method.\n * @method void                                               useYearsOverflow($yearsOverflow = true)                                                                                      @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n *                                                                                                                                                                                                     You should rather use the ->settings() method.\n *                                                                                                                                                                                                     Or you can use method variants: addYearsWithOverflow/addYearsNoOverflow, same variants\n *                                                                                                                                                                                                     are available for quarters, years, decade, centuries, millennia (singular and plural forms).\n * @method mixed                                              withTestNow($testNow, $callback)                                                                                             Temporarily sets a static date to be used within the callback.\n *                                                                                                                                                                                         Using setTestNow to set the date, executing the callback, then\n *                                                                                                                                                                                         clearing the test instance.\n *                                                                                                                                                                                         /!\\ Use this method for unit tests only.\n * @method Carbon                                             yesterday($tz = null)                                                                                                        Create a Carbon instance for yesterday.\n *\n * </autodoc>\n */\nclass Factory\n{\n    protected $className = Carbon::class;\n\n    protected $settings = [];\n\n    public function __construct(array $settings = [], ?string $className = null)\n    {\n        if ($className) {\n            $this->className = $className;\n        }\n\n        $this->settings = $settings;\n    }\n\n    public function getClassName()\n    {\n        return $this->className;\n    }\n\n    public function setClassName(string $className)\n    {\n        $this->className = $className;\n\n        return $this;\n    }\n\n    public function className(?string $className = null)\n    {\n        return $className === null ? $this->getClassName() : $this->setClassName($className);\n    }\n\n    public function getSettings()\n    {\n        return $this->settings;\n    }\n\n    public function setSettings(array $settings)\n    {\n        $this->settings = $settings;\n\n        return $this;\n    }\n\n    public function settings(?array $settings = null)\n    {\n        return $settings === null ? $this->getSettings() : $this->setSettings($settings);\n    }\n\n    public function mergeSettings(array $settings)\n    {\n        $this->settings = array_merge($this->settings, $settings);\n\n        return $this;\n    }\n\n    public function __call($name, $arguments)\n    {\n        $method = new ReflectionMethod($this->className, $name);\n        $settings = $this->settings;\n\n        if ($settings && isset($settings['timezone'])) {\n            $tzParameters = array_filter($method->getParameters(), function ($parameter) {\n                return \\in_array($parameter->getName(), ['tz', 'timezone'], true);\n            });\n\n            if (isset($arguments[0]) && \\in_array($name, ['instance', 'make', 'create', 'parse'], true)) {\n                if ($arguments[0] instanceof DateTimeInterface) {\n                    $settings['innerTimezone'] = $settings['timezone'];\n                } elseif (\\is_string($arguments[0]) && date_parse($arguments[0])['is_localtime']) {\n                    unset($settings['timezone'], $settings['innerTimezone']);\n                }\n            } elseif (\\count($tzParameters)) {\n                array_splice($arguments, key($tzParameters), 0, [$settings['timezone']]);\n                unset($settings['timezone']);\n            }\n        }\n\n        $result = $this->className::$name(...$arguments);\n\n        return $result instanceof CarbonInterface && !empty($settings)\n            ? $result->settings($settings)\n            : $result;\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/FactoryImmutable.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon;\n\nuse Closure;\nuse DateTimeImmutable;\nuse DateTimeZone;\nuse Psr\\Clock\\ClockInterface;\n\n/**\n * A factory to generate CarbonImmutable instances with common settings.\n *\n * <autodoc generated by `composer phpdoc`>\n *\n * @method bool                                               canBeCreatedFromFormat($date, $format)                                                                                       Checks if the (date)time string is in a given format and valid to create a\n *                                                                                                                                                                                         new instance.\n * @method CarbonImmutable|false                              create($year = 0, $month = 1, $day = 1, $hour = 0, $minute = 0, $second = 0, $tz = null)                                     Create a new Carbon instance from a specific date and time.\n *                                                                                                                                                                                         If any of $year, $month or $day are set to null their now() values will\n *                                                                                                                                                                                         be used.\n *                                                                                                                                                                                         If $hour is null it will be set to its now() value and the default\n *                                                                                                                                                                                         values for $minute and $second will be their now() values.\n *                                                                                                                                                                                         If $hour is not null then the default values for $minute and $second\n *                                                                                                                                                                                         will be 0.\n * @method CarbonImmutable                                    createFromDate($year = null, $month = null, $day = null, $tz = null)                                                         Create a Carbon instance from just a date. The time portion is set to now.\n * @method CarbonImmutable|false                              createFromFormat($format, $time, $tz = null)                                                                                 Create a Carbon instance from a specific format.\n * @method CarbonImmutable|false                              createFromIsoFormat($format, $time, $tz = null, $locale = 'en', $translator = null)                                          Create a Carbon instance from a specific ISO format (same replacements as ->isoFormat()).\n * @method CarbonImmutable|false                              createFromLocaleFormat($format, $locale, $time, $tz = null)                                                                  Create a Carbon instance from a specific format and a string in a given language.\n * @method CarbonImmutable|false                              createFromLocaleIsoFormat($format, $locale, $time, $tz = null)                                                               Create a Carbon instance from a specific ISO format and a string in a given language.\n * @method CarbonImmutable                                    createFromTime($hour = 0, $minute = 0, $second = 0, $tz = null)                                                              Create a Carbon instance from just a time. The date portion is set to today.\n * @method CarbonImmutable                                    createFromTimeString($time, $tz = null)                                                                                      Create a Carbon instance from a time string. The date portion is set to today.\n * @method CarbonImmutable                                    createFromTimestamp($timestamp, $tz = null)                                                                                  Create a Carbon instance from a timestamp and set the timezone (use default one if not specified).\n *                                                                                                                                                                                         Timestamp input can be given as int, float or a string containing one or more numbers.\n * @method CarbonImmutable                                    createFromTimestampMs($timestamp, $tz = null)                                                                                Create a Carbon instance from a timestamp in milliseconds.\n *                                                                                                                                                                                         Timestamp input can be given as int, float or a string containing one or more numbers.\n * @method CarbonImmutable                                    createFromTimestampMsUTC($timestamp)                                                                                         Create a Carbon instance from a timestamp in milliseconds.\n *                                                                                                                                                                                         Timestamp input can be given as int, float or a string containing one or more numbers.\n * @method CarbonImmutable                                    createFromTimestampUTC($timestamp)                                                                                           Create a Carbon instance from an timestamp keeping the timezone to UTC.\n *                                                                                                                                                                                         Timestamp input can be given as int, float or a string containing one or more numbers.\n * @method CarbonImmutable                                    createMidnightDate($year = null, $month = null, $day = null, $tz = null)                                                     Create a Carbon instance from just a date. The time portion is set to midnight.\n * @method CarbonImmutable|false                              createSafe($year = null, $month = null, $day = null, $hour = null, $minute = null, $second = null, $tz = null)               Create a new safe Carbon instance from a specific date and time.\n *                                                                                                                                                                                         If any of $year, $month or $day are set to null their now() values will\n *                                                                                                                                                                                         be used.\n *                                                                                                                                                                                         If $hour is null it will be set to its now() value and the default\n *                                                                                                                                                                                         values for $minute and $second will be their now() values.\n *                                                                                                                                                                                         If $hour is not null then the default values for $minute and $second\n *                                                                                                                                                                                         will be 0.\n *                                                                                                                                                                                         If one of the set values is not valid, an InvalidDateException\n *                                                                                                                                                                                         will be thrown.\n * @method CarbonInterface                                    createStrict(?int $year = 0, ?int $month = 1, ?int $day = 1, ?int $hour = 0, ?int $minute = 0, ?int $second = 0, $tz = null) Create a new Carbon instance from a specific date and time using strict validation.\n * @method CarbonImmutable                                    disableHumanDiffOption($humanDiffOption)                                                                                     @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n *                                                                                                                                                                                                     You should rather use the ->settings() method.\n * @method CarbonImmutable                                    enableHumanDiffOption($humanDiffOption)                                                                                      @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n *                                                                                                                                                                                                     You should rather use the ->settings() method.\n * @method mixed                                              executeWithLocale($locale, $func)                                                                                            Set the current locale to the given, execute the passed function, reset the locale to previous one,\n *                                                                                                                                                                                         then return the result of the closure (or null if the closure was void).\n * @method CarbonImmutable                                    fromSerialized($value)                                                                                                       Create an instance from a serialized string.\n * @method void                                               genericMacro($macro, $priority = 0)                                                                                          Register a custom macro.\n * @method array                                              getAvailableLocales()                                                                                                        Returns the list of internally available locales and already loaded custom locales.\n *                                                                                                                                                                                         (It will ignore custom translator dynamic loading.)\n * @method Language[]                                         getAvailableLocalesInfo()                                                                                                    Returns list of Language object for each available locale. This object allow you to get the ISO name, native\n *                                                                                                                                                                                         name, region and variant of the locale.\n * @method array                                              getDays()                                                                                                                    Get the days of the week\n * @method string|null                                        getFallbackLocale()                                                                                                          Get the fallback locale.\n * @method array                                              getFormatsToIsoReplacements()                                                                                                List of replacements from date() format to isoFormat().\n * @method int                                                getHumanDiffOptions()                                                                                                        Return default humanDiff() options (merged flags as integer).\n * @method array                                              getIsoUnits()                                                                                                                Returns list of locale units for ISO formatting.\n * @method array                                              getLastErrors()                                                                                                              {@inheritdoc}\n * @method string                                             getLocale()                                                                                                                  Get the current translator locale.\n * @method callable|null                                      getMacro($name)                                                                                                              Get the raw callable macro registered globally for a given name.\n * @method int                                                getMidDayAt()                                                                                                                get midday/noon hour\n * @method Closure|CarbonImmutable                            getTestNow()                                                                                                                 Get the Carbon instance (real or mock) to be returned when a \"now\"\n *                                                                                                                                                                                         instance is created.\n * @method string                                             getTimeFormatByPrecision($unitPrecision)                                                                                     Return a format from H:i to H:i:s.u according to given unit precision.\n * @method string                                             getTranslationMessageWith($translator, string $key, ?string $locale = null, ?string $default = null)                         Returns raw translation message for a given key.\n * @method \\Symfony\\Component\\Translation\\TranslatorInterface getTranslator()                                                                                                              Get the default translator instance in use.\n * @method int                                                getWeekEndsAt()                                                                                                              Get the last day of week\n * @method int                                                getWeekStartsAt()                                                                                                            Get the first day of week\n * @method array                                              getWeekendDays()                                                                                                             Get weekend days\n * @method bool                                               hasFormat($date, $format)                                                                                                    Checks if the (date)time string is in a given format.\n * @method bool                                               hasFormatWithModifiers($date, $format)                                                                                       Checks if the (date)time string is in a given format.\n * @method bool                                               hasMacro($name)                                                                                                              Checks if macro is registered globally.\n * @method bool                                               hasRelativeKeywords($time)                                                                                                   Determine if a time string will produce a relative date.\n * @method bool                                               hasTestNow()                                                                                                                 Determine if there is a valid test instance set. A valid test instance\n *                                                                                                                                                                                         is anything that is not null.\n * @method CarbonImmutable                                    instance($date)                                                                                                              Create a Carbon instance from a DateTime one.\n * @method bool                                               isImmutable()                                                                                                                Returns true if the current class/instance is immutable.\n * @method bool                                               isModifiableUnit($unit)                                                                                                      Returns true if a property can be changed via setter.\n * @method bool                                               isMutable()                                                                                                                  Returns true if the current class/instance is mutable.\n * @method bool                                               isStrictModeEnabled()                                                                                                        Returns true if the strict mode is globally in use, false else.\n *                                                                                                                                                                                         (It can be overridden in specific instances.)\n * @method bool                                               localeHasDiffOneDayWords($locale)                                                                                            Returns true if the given locale is internally supported and has words for 1-day diff (just now, yesterday, tomorrow).\n *                                                                                                                                                                                         Support is considered enabled if the 3 words are translated in the given locale.\n * @method bool                                               localeHasDiffSyntax($locale)                                                                                                 Returns true if the given locale is internally supported and has diff syntax support (ago, from now, before, after).\n *                                                                                                                                                                                         Support is considered enabled if the 4 sentences are translated in the given locale.\n * @method bool                                               localeHasDiffTwoDayWords($locale)                                                                                            Returns true if the given locale is internally supported and has words for 2-days diff (before yesterday, after tomorrow).\n *                                                                                                                                                                                         Support is considered enabled if the 2 words are translated in the given locale.\n * @method bool                                               localeHasPeriodSyntax($locale)                                                                                               Returns true if the given locale is internally supported and has period syntax support (X times, every X, from X, to X).\n *                                                                                                                                                                                         Support is considered enabled if the 4 sentences are translated in the given locale.\n * @method bool                                               localeHasShortUnits($locale)                                                                                                 Returns true if the given locale is internally supported and has short-units support.\n *                                                                                                                                                                                         Support is considered enabled if either year, day or hour has a short variant translated.\n * @method void                                               macro($name, $macro)                                                                                                         Register a custom macro.\n * @method CarbonImmutable|null                               make($var)                                                                                                                   Make a Carbon instance from given variable if possible.\n *                                                                                                                                                                                         Always return a new instance. Parse only strings and only these likely to be dates (skip intervals\n *                                                                                                                                                                                         and recurrences). Throw an exception for invalid format, but otherwise return null.\n * @method CarbonImmutable                                    maxValue()                                                                                                                   Create a Carbon instance for the greatest supported date.\n * @method CarbonImmutable                                    minValue()                                                                                                                   Create a Carbon instance for the lowest supported date.\n * @method void                                               mixin($mixin)                                                                                                                Mix another object into the class.\n * @method CarbonImmutable                                    parse($time = null, $tz = null)                                                                                              Create a carbon instance from a string.\n *                                                                                                                                                                                         This is an alias for the constructor that allows better fluent syntax\n *                                                                                                                                                                                         as it allows you to do Carbon::parse('Monday next week')->fn() rather\n *                                                                                                                                                                                         than (new Carbon('Monday next week'))->fn().\n * @method CarbonImmutable                                    parseFromLocale($time, $locale = null, $tz = null)                                                                           Create a carbon instance from a localized string (in French, Japanese, Arabic, etc.).\n * @method string                                             pluralUnit(string $unit)                                                                                                     Returns standardized plural of a given singular/plural unit name (in English).\n * @method CarbonImmutable|false                              rawCreateFromFormat($format, $time, $tz = null)                                                                              Create a Carbon instance from a specific format.\n * @method CarbonImmutable                                    rawParse($time = null, $tz = null)                                                                                           Create a carbon instance from a string.\n *                                                                                                                                                                                         This is an alias for the constructor that allows better fluent syntax\n *                                                                                                                                                                                         as it allows you to do Carbon::parse('Monday next week')->fn() rather\n *                                                                                                                                                                                         than (new Carbon('Monday next week'))->fn().\n * @method CarbonImmutable                                    resetMacros()                                                                                                                Remove all macros and generic macros.\n * @method void                                               resetMonthsOverflow()                                                                                                        @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n *                                                                                                                                                                                                     You should rather use the ->settings() method.\n *                                                                                                                                                                                                     Or you can use method variants: addMonthsWithOverflow/addMonthsNoOverflow, same variants\n *                                                                                                                                                                                                     are available for quarters, years, decade, centuries, millennia (singular and plural forms).\n * @method void                                               resetToStringFormat()                                                                                                        Reset the format used to the default when type juggling a Carbon instance to a string\n * @method void                                               resetYearsOverflow()                                                                                                         @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n *                                                                                                                                                                                                     You should rather use the ->settings() method.\n *                                                                                                                                                                                                     Or you can use method variants: addYearsWithOverflow/addYearsNoOverflow, same variants\n *                                                                                                                                                                                                     are available for quarters, years, decade, centuries, millennia (singular and plural forms).\n * @method void                                               serializeUsing($callback)                                                                                                    @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n *                                                                                                                                                                                                     You should rather transform Carbon object before the serialization.\n *                                                                                                                                                                                         JSON serialize all Carbon instances using the given callback.\n * @method CarbonImmutable                                    setFallbackLocale($locale)                                                                                                   Set the fallback locale.\n * @method CarbonImmutable                                    setHumanDiffOptions($humanDiffOptions)                                                                                       @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n *                                                                                                                                                                                                     You should rather use the ->settings() method.\n * @method bool                                               setLocale($locale)                                                                                                           Set the current translator locale and indicate if the source locale file exists.\n *                                                                                                                                                                                         Pass 'auto' as locale to use closest language from the current LC_TIME locale.\n * @method void                                               setMidDayAt($hour)                                                                                                           @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n *                                                                                                                                                                                                     You should rather consider mid-day is always 12pm, then if you need to test if it's an other\n *                                                                                                                                                                                                     hour, test it explicitly:\n *                                                                                                                                                                                                         $date->format('G') == 13\n *                                                                                                                                                                                                     or to set explicitly to a given hour:\n *                                                                                                                                                                                                         $date->setTime(13, 0, 0, 0)\n *                                                                                                                                                                                         Set midday/noon hour\n * @method CarbonImmutable                                    setTestNow($testNow = null)                                                                                                  Set a Carbon instance (real or mock) to be returned when a \"now\"\n *                                                                                                                                                                                         instance is created.  The provided instance will be returned\n *                                                                                                                                                                                         specifically under the following conditions:\n *                                                                                                                                                                                           - A call to the static now() method, ex. Carbon::now()\n *                                                                                                                                                                                           - When a null (or blank string) is passed to the constructor or parse(), ex. new Carbon(null)\n *                                                                                                                                                                                           - When the string \"now\" is passed to the constructor or parse(), ex. new Carbon('now')\n *                                                                                                                                                                                           - When a string containing the desired time is passed to Carbon::parse().\n *                                                                                                                                                                                         Note the timezone parameter was left out of the examples above and\n *                                                                                                                                                                                         has no affect as the mock value will be returned regardless of its value.\n *                                                                                                                                                                                         Only the moment is mocked with setTestNow(), the timezone will still be the one passed\n *                                                                                                                                                                                         as parameter of date_default_timezone_get() as a fallback (see setTestNowAndTimezone()).\n *                                                                                                                                                                                         To clear the test instance call this method using the default\n *                                                                                                                                                                                         parameter of null.\n *                                                                                                                                                                                         /!\\ Use this method for unit tests only.\n * @method CarbonImmutable                                    setTestNowAndTimezone($testNow = null, $tz = null)                                                                           Set a Carbon instance (real or mock) to be returned when a \"now\"\n *                                                                                                                                                                                         instance is created.  The provided instance will be returned\n *                                                                                                                                                                                         specifically under the following conditions:\n *                                                                                                                                                                                           - A call to the static now() method, ex. Carbon::now()\n *                                                                                                                                                                                           - When a null (or blank string) is passed to the constructor or parse(), ex. new Carbon(null)\n *                                                                                                                                                                                           - When the string \"now\" is passed to the constructor or parse(), ex. new Carbon('now')\n *                                                                                                                                                                                           - When a string containing the desired time is passed to Carbon::parse().\n *                                                                                                                                                                                         It will also align default timezone (e.g. call date_default_timezone_set()) with\n *                                                                                                                                                                                         the second argument or if null, with the timezone of the given date object.\n *                                                                                                                                                                                         To clear the test instance call this method using the default\n *                                                                                                                                                                                         parameter of null.\n *                                                                                                                                                                                         /!\\ Use this method for unit tests only.\n * @method void                                               setToStringFormat($format)                                                                                                   @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n *                                                                                                                                                                                                     You should rather let Carbon object being cast to string with DEFAULT_TO_STRING_FORMAT, and\n *                                                                                                                                                                                                     use other method or custom format passed to format() method if you need to dump another string\n *                                                                                                                                                                                                     format.\n *                                                                                                                                                                                         Set the default format used when type juggling a Carbon instance to a string.\n * @method void                                               setTranslator(TranslatorInterface $translator)                                                                               Set the default translator instance to use.\n * @method CarbonImmutable                                    setUtf8($utf8)                                                                                                               @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n *                                                                                                                                                                                                     You should rather use UTF-8 language packages on every machine.\n *                                                                                                                                                                                         Set if UTF8 will be used for localized date/time.\n * @method void                                               setWeekEndsAt($day)                                                                                                          @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n *                                                                                                                                                                                                     Use $weekStartsAt optional parameter instead when using startOfWeek, floorWeek, ceilWeek\n *                                                                                                                                                                                                     or roundWeek method. You can also use the 'first_day_of_week' locale setting to change the\n *                                                                                                                                                                                                     start of week according to current locale selected and implicitly the end of week.\n *                                                                                                                                                                                         Set the last day of week\n * @method void                                               setWeekStartsAt($day)                                                                                                        @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n *                                                                                                                                                                                                     Use $weekEndsAt optional parameter instead when using endOfWeek method. You can also use the\n *                                                                                                                                                                                                     'first_day_of_week' locale setting to change the start of week according to current locale\n *                                                                                                                                                                                                     selected and implicitly the end of week.\n *                                                                                                                                                                                         Set the first day of week\n * @method void                                               setWeekendDays($days)                                                                                                        @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n *                                                                                                                                                                                                     You should rather consider week-end is always saturday and sunday, and if you have some custom\n *                                                                                                                                                                                                     week-end days to handle, give to those days an other name and create a macro for them:\n *                                                                                                                                                                                                     ```\n *                                                                                                                                                                                                     Carbon::macro('isDayOff', function ($date) {\n *                                                                                                                                                                                                         return $date->isSunday() || $date->isMonday();\n *                                                                                                                                                                                                     });\n *                                                                                                                                                                                                     Carbon::macro('isNotDayOff', function ($date) {\n *                                                                                                                                                                                                         return !$date->isDayOff();\n *                                                                                                                                                                                                     });\n *                                                                                                                                                                                                     if ($someDate->isDayOff()) ...\n *                                                                                                                                                                                                     if ($someDate->isNotDayOff()) ...\n *                                                                                                                                                                                                     // Add 5 not-off days\n *                                                                                                                                                                                                     $count = 5;\n *                                                                                                                                                                                                     while ($someDate->isDayOff() || ($count-- > 0)) {\n *                                                                                                                                                                                                         $someDate->addDay();\n *                                                                                                                                                                                                     }\n *                                                                                                                                                                                                     ```\n *                                                                                                                                                                                         Set weekend days\n * @method bool                                               shouldOverflowMonths()                                                                                                       Get the month overflow global behavior (can be overridden in specific instances).\n * @method bool                                               shouldOverflowYears()                                                                                                        Get the month overflow global behavior (can be overridden in specific instances).\n * @method string                                             singularUnit(string $unit)                                                                                                   Returns standardized singular of a given singular/plural unit name (in English).\n * @method CarbonImmutable                                    today($tz = null)                                                                                                            Create a Carbon instance for today.\n * @method CarbonImmutable                                    tomorrow($tz = null)                                                                                                         Create a Carbon instance for tomorrow.\n * @method string                                             translateTimeString($timeString, $from = null, $to = null, $mode = CarbonInterface::TRANSLATE_ALL)                           Translate a time string from a locale to an other.\n * @method string                                             translateWith(TranslatorInterface $translator, string $key, array $parameters = [], $number = null)                          Translate using translation string or callback available.\n * @method void                                               useMonthsOverflow($monthsOverflow = true)                                                                                    @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n *                                                                                                                                                                                                     You should rather use the ->settings() method.\n *                                                                                                                                                                                                     Or you can use method variants: addMonthsWithOverflow/addMonthsNoOverflow, same variants\n *                                                                                                                                                                                                     are available for quarters, years, decade, centuries, millennia (singular and plural forms).\n * @method CarbonImmutable                                    useStrictMode($strictModeEnabled = true)                                                                                     @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n *                                                                                                                                                                                                     You should rather use the ->settings() method.\n * @method void                                               useYearsOverflow($yearsOverflow = true)                                                                                      @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n *                                                                                                                                                                                                     You should rather use the ->settings() method.\n *                                                                                                                                                                                                     Or you can use method variants: addYearsWithOverflow/addYearsNoOverflow, same variants\n *                                                                                                                                                                                                     are available for quarters, years, decade, centuries, millennia (singular and plural forms).\n * @method mixed                                              withTestNow($testNow, $callback)                                                                                             Temporarily sets a static date to be used within the callback.\n *                                                                                                                                                                                         Using setTestNow to set the date, executing the callback, then\n *                                                                                                                                                                                         clearing the test instance.\n *                                                                                                                                                                                         /!\\ Use this method for unit tests only.\n * @method CarbonImmutable                                    yesterday($tz = null)                                                                                                        Create a Carbon instance for yesterday.\n *\n * </autodoc>\n */\nclass FactoryImmutable extends Factory implements ClockInterface\n{\n    protected $className = CarbonImmutable::class;\n\n    /**\n     * Get a Carbon instance for the current date and time.\n     *\n     * @param DateTimeZone|string|int|null $tz\n     *\n     * @return CarbonImmutable\n     */\n    public function now($tz = null): DateTimeImmutable\n    {\n        $className = $this->className;\n\n        return new $className(null, $tz);\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/aa.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/aa_DJ.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/aa_DJ.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Ge'ez Frontier Foundation    locales@geez.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD.MM.YYYY',\n    ],\n    'months' => ['Qunxa Garablu', 'Kudo', 'Ciggilta Kudo', 'Agda Baxisso', 'Caxah Alsa', 'Qasa Dirri', 'Qado Dirri', 'Liiqen', 'Waysu', 'Diteli', 'Ximoli', 'Kaxxa Garablu'],\n    'months_short' => ['qun', 'nah', 'cig', 'agd', 'cax', 'qas', 'qad', 'leq', 'way', 'dit', 'xim', 'kax'],\n    'weekdays' => ['Acaada', 'Etleeni', 'Talaata', 'Arbaqa', 'Kamiisi', 'Gumqata', 'Sabti'],\n    'weekdays_short' => ['aca', 'etl', 'tal', 'arb', 'kam', 'gum', 'sab'],\n    'weekdays_min' => ['aca', 'etl', 'tal', 'arb', 'kam', 'gum', 'sab'],\n    'first_day_of_week' => 6,\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['saaku', 'carra'],\n\n    'year' => ':count gaqambo', // less reliable\n    'y' => ':count gaqambo', // less reliable\n    'a_year' => ':count gaqambo', // less reliable\n\n    'month' => ':count àlsa',\n    'm' => ':count àlsa',\n    'a_month' => ':count àlsa',\n\n    'day' => ':count saaku', // less reliable\n    'd' => ':count saaku', // less reliable\n    'a_day' => ':count saaku', // less reliable\n\n    'hour' => ':count ayti', // less reliable\n    'h' => ':count ayti', // less reliable\n    'a_hour' => ':count ayti', // less reliable\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/aa_ER.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Ge'ez Frontier Foundation    locales@geez.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD/MM/YYYY',\n    ],\n    'months' => ['Qunxa Garablu', 'Naharsi Kudo', 'Ciggilta Kudo', 'Agda Baxisso', 'Caxah Alsa', 'Qasa Dirri', 'Qado Dirri', 'Leqeeni', 'Waysu', 'Diteli', 'Ximoli', 'Kaxxa Garablu'],\n    'months_short' => ['Qun', 'Nah', 'Cig', 'Agd', 'Cax', 'Qas', 'Qad', 'Leq', 'Way', 'Dit', 'Xim', 'Kax'],\n    'weekdays' => ['Acaada', 'Etleeni', 'Talaata', 'Arbaqa', 'Kamiisi', 'Gumqata', 'Sabti'],\n    'weekdays_short' => ['Aca', 'Etl', 'Tal', 'Arb', 'Kam', 'Gum', 'Sab'],\n    'weekdays_min' => ['Aca', 'Etl', 'Tal', 'Arb', 'Kam', 'Gum', 'Sab'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['saaku', 'carra'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/aa_ER@saaho.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Ge'ez Frontier Foundation    locales@geez.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD/MM/YYYY',\n    ],\n    'months' => ['Qunxa Garablu', 'Naharsi Kudo', 'Ciggilta Kudo', 'Agda Baxisso', 'Caxah Alsa', 'Qasa Dirri', 'Qado Dirri', 'Leqeeni', 'Waysu', 'Diteli', 'Ximoli', 'Kaxxa Garablu'],\n    'months_short' => ['Qun', 'Nah', 'Cig', 'Agd', 'Cax', 'Qas', 'Qad', 'Leq', 'Way', 'Dit', 'Xim', 'Kax'],\n    'weekdays' => ['Naba Sambat', 'Sani', 'Salus', 'Rabuq', 'Camus', 'Jumqata', 'Qunxa Sambat'],\n    'weekdays_short' => ['Nab', 'San', 'Sal', 'Rab', 'Cam', 'Jum', 'Qun'],\n    'weekdays_min' => ['Nab', 'San', 'Sal', 'Rab', 'Cam', 'Jum', 'Qun'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['saaku', 'carra'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/aa_ET.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Ge'ez Frontier Foundation    locales@geez.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD/MM/YYYY',\n    ],\n    'months' => ['Qunxa Garablu', 'Kudo', 'Ciggilta Kudo', 'Agda Baxisso', 'Caxah Alsa', 'Qasa Dirri', 'Qado Dirri', 'Liiqen', 'Waysu', 'Diteli', 'Ximoli', 'Kaxxa Garablu'],\n    'months_short' => ['Qun', 'Kud', 'Cig', 'Agd', 'Cax', 'Qas', 'Qad', 'Leq', 'Way', 'Dit', 'Xim', 'Kax'],\n    'weekdays' => ['Acaada', 'Etleeni', 'Talaata', 'Arbaqa', 'Kamiisi', 'Gumqata', 'Sabti'],\n    'weekdays_short' => ['Aca', 'Etl', 'Tal', 'Arb', 'Kam', 'Gum', 'Sab'],\n    'weekdays_min' => ['Aca', 'Etl', 'Tal', 'Arb', 'Kam', 'Gum', 'Sab'],\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['saaku', 'carra'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/af.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - François B\n * - JD Isaacks\n * - Pierre du Plessis\n */\nreturn [\n    'year' => ':count jaar',\n    'a_year' => '\\'n jaar|:count jaar',\n    'y' => ':count j.',\n    'month' => ':count maand|:count maande',\n    'a_month' => '\\'n maand|:count maande',\n    'm' => ':count maa.',\n    'week' => ':count week|:count weke',\n    'a_week' => '\\'n week|:count weke',\n    'w' => ':count w.',\n    'day' => ':count dag|:count dae',\n    'a_day' => '\\'n dag|:count dae',\n    'd' => ':count d.',\n    'hour' => ':count uur',\n    'a_hour' => '\\'n uur|:count uur',\n    'h' => ':count u.',\n    'minute' => ':count minuut|:count minute',\n    'a_minute' => '\\'n minuut|:count minute',\n    'min' => ':count min.',\n    'second' => ':count sekond|:count sekondes',\n    'a_second' => '\\'n paar sekondes|:count sekondes',\n    's' => ':count s.',\n    'ago' => ':time gelede',\n    'from_now' => 'oor :time',\n    'after' => ':time na',\n    'before' => ':time voor',\n    'diff_now' => 'Nou',\n    'diff_today' => 'Vandag',\n    'diff_today_regexp' => 'Vandag(?:\\\\s+om)?',\n    'diff_yesterday' => 'Gister',\n    'diff_yesterday_regexp' => 'Gister(?:\\\\s+om)?',\n    'diff_tomorrow' => 'Môre',\n    'diff_tomorrow_regexp' => 'Môre(?:\\\\s+om)?',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[Vandag om] LT',\n        'nextDay' => '[Môre om] LT',\n        'nextWeek' => 'dddd [om] LT',\n        'lastDay' => '[Gister om] LT',\n        'lastWeek' => '[Laas] dddd [om] LT',\n        'sameElse' => 'L',\n    ],\n    'ordinal' => function ($number) {\n        return $number.(($number === 1 || $number === 8 || $number >= 20) ? 'ste' : 'de');\n    },\n    'meridiem' => ['VM', 'NM'],\n    'months' => ['Januarie', 'Februarie', 'Maart', 'April', 'Mei', 'Junie', 'Julie', 'Augustus', 'September', 'Oktober', 'November', 'Desember'],\n    'months_short' => ['Jan', 'Feb', 'Mrt', 'Apr', 'Mei', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Des'],\n    'weekdays' => ['Sondag', 'Maandag', 'Dinsdag', 'Woensdag', 'Donderdag', 'Vrydag', 'Saterdag'],\n    'weekdays_short' => ['Son', 'Maa', 'Din', 'Woe', 'Don', 'Vry', 'Sat'],\n    'weekdays_min' => ['So', 'Ma', 'Di', 'Wo', 'Do', 'Vr', 'Sa'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n    'list' => [', ', ' en '],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/af_NA.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/af.php', [\n    'meridiem' => ['v', 'n'],\n    'weekdays' => ['Sondag', 'Maandag', 'Dinsdag', 'Woensdag', 'Donderdag', 'Vrydag', 'Saterdag'],\n    'weekdays_short' => ['So.', 'Ma.', 'Di.', 'Wo.', 'Do.', 'Vr.', 'Sa.'],\n    'weekdays_min' => ['So.', 'Ma.', 'Di.', 'Wo.', 'Do.', 'Vr.', 'Sa.'],\n    'months' => ['Januarie', 'Februarie', 'Maart', 'April', 'Mei', 'Junie', 'Julie', 'Augustus', 'September', 'Oktober', 'November', 'Desember'],\n    'months_short' => ['Jan.', 'Feb.', 'Mrt.', 'Apr.', 'Mei', 'Jun.', 'Jul.', 'Aug.', 'Sep.', 'Okt.', 'Nov.', 'Des.'],\n    'first_day_of_week' => 1,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'YYYY-MM-DD',\n        'LL' => 'DD MMM YYYY',\n        'LLL' => 'DD MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, DD MMMM YYYY HH:mm',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/af_ZA.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/af.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/agq.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'meridiem' => ['a.g', 'a.k'],\n    'weekdays' => ['tsuʔntsɨ', 'tsuʔukpà', 'tsuʔughɔe', 'tsuʔutɔ̀mlò', 'tsuʔumè', 'tsuʔughɨ̂m', 'tsuʔndzɨkɔʔɔ'],\n    'weekdays_short' => ['nts', 'kpa', 'ghɔ', 'tɔm', 'ume', 'ghɨ', 'dzk'],\n    'weekdays_min' => ['nts', 'kpa', 'ghɔ', 'tɔm', 'ume', 'ghɨ', 'dzk'],\n    'months' => ['ndzɔ̀ŋɔ̀nùm', 'ndzɔ̀ŋɔ̀kƗ̀zùʔ', 'ndzɔ̀ŋɔ̀tƗ̀dʉ̀ghà', 'ndzɔ̀ŋɔ̀tǎafʉ̄ghā', 'ndzɔ̀ŋèsèe', 'ndzɔ̀ŋɔ̀nzùghò', 'ndzɔ̀ŋɔ̀dùmlo', 'ndzɔ̀ŋɔ̀kwîfɔ̀e', 'ndzɔ̀ŋɔ̀tƗ̀fʉ̀ghàdzughù', 'ndzɔ̀ŋɔ̀ghǔuwelɔ̀m', 'ndzɔ̀ŋɔ̀chwaʔàkaa wo', 'ndzɔ̀ŋèfwòo'],\n    'months_short' => ['nùm', 'kɨz', 'tɨd', 'taa', 'see', 'nzu', 'dum', 'fɔe', 'dzu', 'lɔm', 'kaa', 'fwo'],\n    'first_day_of_week' => 1,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'D/M/YYYY',\n        'LL' => 'D MMM, YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd D MMMM YYYY HH:mm',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/agr.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/agr_PE.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/agr_PE.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - somosazucar.org    libc-alpha@sourceware.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD/MM/YY',\n    ],\n    'months' => ['Petsatin', 'Kupitin', 'Uyaitin', 'Tayutin', 'Kegketin', 'Tegmatin', 'Kuntutin', 'Yagkujutin', 'Daiktatin', 'Ipamtatin', 'Shinutin', 'Sakamtin'],\n    'months_short' => ['Pet', 'Kup', 'Uya', 'Tay', 'Keg', 'Teg', 'Kun', 'Yag', 'Dait', 'Ipam', 'Shin', 'Sak'],\n    'weekdays' => ['Tuntuamtin', 'Achutin', 'Kugkuktin', 'Saketin', 'Shimpitin', 'Imaptin', 'Bataetin'],\n    'weekdays_short' => ['Tun', 'Ach', 'Kug', 'Sak', 'Shim', 'Im', 'Bat'],\n    'weekdays_min' => ['Tun', 'Ach', 'Kug', 'Sak', 'Shim', 'Im', 'Bat'],\n    'first_day_of_week' => 0,\n    'day_of_first_week_of_year' => 7,\n    'meridiem' => ['VM', 'NM'],\n\n    'year' => ':count yaya', // less reliable\n    'y' => ':count yaya', // less reliable\n    'a_year' => ':count yaya', // less reliable\n\n    'month' => ':count nantu', // less reliable\n    'm' => ':count nantu', // less reliable\n    'a_month' => ':count nantu', // less reliable\n\n    'day' => ':count nayaim', // less reliable\n    'd' => ':count nayaim', // less reliable\n    'a_day' => ':count nayaim', // less reliable\n\n    'hour' => ':count kuwiš', // less reliable\n    'h' => ':count kuwiš', // less reliable\n    'a_hour' => ':count kuwiš', // less reliable\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ak.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/ak_GH.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ak_GH.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Sugar Labs // OLPC sugarlabs.org libc-alpha@sourceware.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'YYYY/MM/DD',\n    ],\n    'months' => ['Sanda-Ɔpɛpɔn', 'Kwakwar-Ɔgyefuo', 'Ebɔw-Ɔbenem', 'Ebɔbira-Oforisuo', 'Esusow Aketseaba-Kɔtɔnimba', 'Obirade-Ayɛwohomumu', 'Ayɛwoho-Kitawonsa', 'Difuu-Ɔsandaa', 'Fankwa-Ɛbɔ', 'Ɔbɛsɛ-Ahinime', 'Ɔberɛfɛw-Obubuo', 'Mumu-Ɔpɛnimba'],\n    'months_short' => ['S-Ɔ', 'K-Ɔ', 'E-Ɔ', 'E-O', 'E-K', 'O-A', 'A-K', 'D-Ɔ', 'F-Ɛ', 'Ɔ-A', 'Ɔ-O', 'M-Ɔ'],\n    'weekdays' => ['Kwesida', 'Dwowda', 'Benada', 'Wukuda', 'Yawda', 'Fida', 'Memeneda'],\n    'weekdays_short' => ['Kwe', 'Dwo', 'Ben', 'Wuk', 'Yaw', 'Fia', 'Mem'],\n    'weekdays_min' => ['Kwe', 'Dwo', 'Ben', 'Wuk', 'Yaw', 'Fia', 'Mem'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['AN', 'EW'],\n\n    'year' => ':count afe',\n    'y' => ':count afe',\n    'a_year' => ':count afe',\n\n    'month' => ':count bosume',\n    'm' => ':count bosume',\n    'a_month' => ':count bosume',\n\n    'day' => ':count ɛda',\n    'd' => ':count ɛda',\n    'a_day' => ':count ɛda',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/am.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/am_ET.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/am_ET.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Ge'ez Frontier Foundation    locales@geez.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD/MM/YYYY',\n    ],\n    'months' => ['ጃንዩወሪ', 'ፌብሩወሪ', 'ማርች', 'ኤፕሪል', 'ሜይ', 'ጁን', 'ጁላይ', 'ኦገስት', 'ሴፕቴምበር', 'ኦክቶበር', 'ኖቬምበር', 'ዲሴምበር'],\n    'months_short' => ['ጃንዩ', 'ፌብሩ', 'ማርች', 'ኤፕረ', 'ሜይ ', 'ጁን ', 'ጁላይ', 'ኦገስ', 'ሴፕቴ', 'ኦክተ', 'ኖቬም', 'ዲሴም'],\n    'weekdays' => ['እሑድ', 'ሰኞ', 'ማክሰኞ', 'ረቡዕ', 'ሐሙስ', 'ዓርብ', 'ቅዳሜ'],\n    'weekdays_short' => ['እሑድ', 'ሰኞ ', 'ማክሰ', 'ረቡዕ', 'ሐሙስ', 'ዓርብ', 'ቅዳሜ'],\n    'weekdays_min' => ['እሑድ', 'ሰኞ ', 'ማክሰ', 'ረቡዕ', 'ሐሙስ', 'ዓርብ', 'ቅዳሜ'],\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['ጡዋት', 'ከሰዓት'],\n\n    'year' => ':count አመት',\n    'y' => ':count አመት',\n    'a_year' => ':count አመት',\n\n    'month' => ':count ወር',\n    'm' => ':count ወር',\n    'a_month' => ':count ወር',\n\n    'week' => ':count ሳምንት',\n    'w' => ':count ሳምንት',\n    'a_week' => ':count ሳምንት',\n\n    'day' => ':count ቀን',\n    'd' => ':count ቀን',\n    'a_day' => ':count ቀን',\n\n    'hour' => ':count ሰዓት',\n    'h' => ':count ሰዓት',\n    'a_hour' => ':count ሰዓት',\n\n    'minute' => ':count ደቂቃ',\n    'min' => ':count ደቂቃ',\n    'a_minute' => ':count ደቂቃ',\n\n    'second' => ':count ሴኮንድ',\n    's' => ':count ሴኮንድ',\n    'a_second' => ':count ሴኮንድ',\n\n    'ago' => 'ከ:time በፊት',\n    'from_now' => 'በ:time ውስጥ',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/an.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/an_ES.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/an_ES.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Softaragones Jordi Mallach Pérez, Juan Pablo Martínez bug-glibc-locales@gnu.org, softaragones@softaragones.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD/MM/YYYY',\n    ],\n    'months' => ['chinero', 'febrero', 'marzo', 'abril', 'mayo', 'chunyo', 'chuliol', 'agosto', 'setiembre', 'octubre', 'noviembre', 'aviento'],\n    'months_short' => ['chi', 'feb', 'mar', 'abr', 'may', 'chn', 'chl', 'ago', 'set', 'oct', 'nov', 'avi'],\n    'weekdays' => ['domingo', 'luns', 'martes', 'mierques', 'chueves', 'viernes', 'sabado'],\n    'weekdays_short' => ['dom', 'lun', 'mar', 'mie', 'chu', 'vie', 'sab'],\n    'weekdays_min' => ['dom', 'lun', 'mar', 'mie', 'chu', 'vie', 'sab'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n\n    'year' => ':count año',\n    'y' => ':count año',\n    'a_year' => ':count año',\n\n    'month' => ':count mes',\n    'm' => ':count mes',\n    'a_month' => ':count mes',\n\n    'week' => ':count semana',\n    'w' => ':count semana',\n    'a_week' => ':count semana',\n\n    'day' => ':count día',\n    'd' => ':count día',\n    'a_day' => ':count día',\n\n    'hour' => ':count reloch', // less reliable\n    'h' => ':count reloch', // less reliable\n    'a_hour' => ':count reloch', // less reliable\n\n    'minute' => ':count minuto',\n    'min' => ':count minuto',\n    'a_minute' => ':count minuto',\n\n    'second' => ':count segundo',\n    's' => ':count segundo',\n    'a_second' => ':count segundo',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/anp.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/anp_IN.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/anp_IN.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - bhashaghar@googlegroups.com\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'D/M/YY',\n    ],\n    'months' => ['जनवरी', 'फरवरी', 'मार्च', 'अप्रैल', 'मई', 'जून', 'जुलाई', 'अगस्त', 'सितंबर', 'अक्टूबर', 'नवंबर', 'दिसंबर\"'],\n    'months_short' => ['जनवरी', 'फरवरी', 'मार्च', 'अप्रैल', 'मई', 'जून', 'जुलाई', 'अगस्त', 'सितंबर', 'अक्टूबर', 'नवंबर', 'दिसंबर'],\n    'weekdays' => ['रविवार', 'सोमवार', 'मंगलवार', 'बुधवार', 'बृहस्पतिवार', 'शुक्रवार', 'शनिवार'],\n    'weekdays_short' => ['रवि', 'सोम', 'मंगल', 'बुध', 'बृहस्पति', 'शुक्र', 'शनि'],\n    'weekdays_min' => ['रवि', 'सोम', 'मंगल', 'बुध', 'बृहस्पति', 'शुक्र', 'शनि'],\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['पूर्वाह्न', 'अपराह्न'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ar.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Atef Ben Ali (atefBB)\n * - Ibrahim AshShohail\n * - MLTDev\n * - Mohamed Sabil (mohamedsabil83)\n * - Yazan Alnugnugh (yazan-alnugnugh)\n */\n$months = [\n    'يناير',\n    'فبراير',\n    'مارس',\n    'أبريل',\n    'مايو',\n    'يونيو',\n    'يوليو',\n    'أغسطس',\n    'سبتمبر',\n    'أكتوبر',\n    'نوفمبر',\n    'ديسمبر',\n];\n\nreturn [\n    'year' => implode('|', ['{0}:count سنة', '{1}سنة', '{2}سنتين', ']2,11[:count سنوات', ']10,Inf[:count سنة']),\n    'a_year' => implode('|', ['{0}:count سنة', '{1}سنة', '{2}سنتين', ']2,11[:count سنوات', ']10,Inf[:count سنة']),\n    'month' => implode('|', ['{0}:count شهر', '{1}شهر', '{2}شهرين', ']2,11[:count أشهر', ']10,Inf[:count شهر']),\n    'a_month' => implode('|', ['{0}:count شهر', '{1}شهر', '{2}شهرين', ']2,11[:count أشهر', ']10,Inf[:count شهر']),\n    'week' => implode('|', ['{0}:count أسبوع', '{1}أسبوع', '{2}أسبوعين', ']2,11[:count أسابيع', ']10,Inf[:count أسبوع']),\n    'a_week' => implode('|', ['{0}:count أسبوع', '{1}أسبوع', '{2}أسبوعين', ']2,11[:count أسابيع', ']10,Inf[:count أسبوع']),\n    'day' => implode('|', ['{0}:count يوم', '{1}يوم', '{2}يومين', ']2,11[:count أيام', ']10,Inf[:count يوم']),\n    'a_day' => implode('|', ['{0}:count يوم', '{1}يوم', '{2}يومين', ']2,11[:count أيام', ']10,Inf[:count يوم']),\n    'hour' => implode('|', ['{0}:count ساعة', '{1}ساعة', '{2}ساعتين', ']2,11[:count ساعات', ']10,Inf[:count ساعة']),\n    'a_hour' => implode('|', ['{0}:count ساعة', '{1}ساعة', '{2}ساعتين', ']2,11[:count ساعات', ']10,Inf[:count ساعة']),\n    'minute' => implode('|', ['{0}:count دقيقة', '{1}دقيقة', '{2}دقيقتين', ']2,11[:count دقائق', ']10,Inf[:count دقيقة']),\n    'a_minute' => implode('|', ['{0}:count دقيقة', '{1}دقيقة', '{2}دقيقتين', ']2,11[:count دقائق', ']10,Inf[:count دقيقة']),\n    'second' => implode('|', ['{0}:count ثانية', '{1}ثانية', '{2}ثانيتين', ']2,11[:count ثواني', ']10,Inf[:count ثانية']),\n    'a_second' => implode('|', ['{0}:count ثانية', '{1}ثانية', '{2}ثانيتين', ']2,11[:count ثواني', ']10,Inf[:count ثانية']),\n    'ago' => 'منذ :time',\n    'from_now' => ':time من الآن',\n    'after' => 'بعد :time',\n    'before' => 'قبل :time',\n    'diff_now' => 'الآن',\n    'diff_today' => 'اليوم',\n    'diff_today_regexp' => 'اليوم(?:\\\\s+عند)?(?:\\\\s+الساعة)?',\n    'diff_yesterday' => 'أمس',\n    'diff_yesterday_regexp' => 'أمس(?:\\\\s+عند)?(?:\\\\s+الساعة)?',\n    'diff_tomorrow' => 'غداً',\n    'diff_tomorrow_regexp' => 'غدًا(?:\\\\s+عند)?(?:\\\\s+الساعة)?',\n    'diff_before_yesterday' => 'قبل الأمس',\n    'diff_after_tomorrow' => 'بعد غد',\n    'period_recurrences' => implode('|', ['{0}مرة', '{1}مرة', '{2}:count مرتين', ']2,11[:count مرات', ']10,Inf[:count مرة']),\n    'period_interval' => 'كل :interval',\n    'period_start_date' => 'من :date',\n    'period_end_date' => 'إلى :date',\n    'months' => $months,\n    'months_short' => $months,\n    'weekdays' => ['الأحد', 'الاثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعة', 'السبت'],\n    'weekdays_short' => ['أحد', 'اثنين', 'ثلاثاء', 'أربعاء', 'خميس', 'جمعة', 'سبت'],\n    'weekdays_min' => ['ح', 'اث', 'ثل', 'أر', 'خم', 'ج', 'س'],\n    'list' => ['، ', ' و '],\n    'first_day_of_week' => 6,\n    'day_of_first_week_of_year' => 1,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'D/M/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd D MMMM YYYY HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[اليوم عند الساعة] LT',\n        'nextDay' => '[غدًا عند الساعة] LT',\n        'nextWeek' => 'dddd [عند الساعة] LT',\n        'lastDay' => '[أمس عند الساعة] LT',\n        'lastWeek' => 'dddd [عند الساعة] LT',\n        'sameElse' => 'L',\n    ],\n    'meridiem' => ['ص', 'م'],\n    'weekend' => [5, 6],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ar_AE.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - IBM Globalization Center of Competency, Yamato Software Laboratory    bug-glibc-locales@gnu.org\n * - Abdullah-Alhariri\n */\nreturn array_replace_recursive(require __DIR__.'/ar.php', [\n    'formats' => [\n        'L' => 'DD MMM, YYYY',\n    ],\n    'months' => ['يناير', 'فبراير', 'مارس', 'أبريل', 'مايو', 'يونيو', 'يوليو', 'أغسطس', 'سبتمبر', 'أكتوبر', 'نوفمبر', 'ديسمبر'],\n    'months_short' => ['ينا', 'فبر', 'مار', 'أبر', 'ماي', 'يون', 'يول', 'أغس', 'سبت', 'أكت', 'نوف', 'ديس'],\n    'weekdays' => ['الأحد', 'الاثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعة', 'السبت '],\n    'weekdays_short' => ['ح', 'ن', 'ث', 'ر', 'خ', 'ج', 'س'],\n    'weekdays_min' => ['ح', 'ن', 'ث', 'ر', 'خ', 'ج', 'س'],\n    'first_day_of_week' => 6,\n    'day_of_first_week_of_year' => 1,\n    'alt_numbers' => ['۰۰', '۰۱', '۰۲', '۰۳', '۰٤', '۰٥', '۰٦', '۰۷', '۰۸', '۰۹', '۱۰', '۱۱', '۱۲', '۱۳', '۱٤', '۱٥', '۱٦', '۱۷', '۱۸', '۱۹', '۲۰', '۲۱', '۲۲', '۲۳', '۲٤', '۲٥', '۲٦', '۲۷', '۲۸', '۲۹', '۳۰', '۳۱', '۳۲', '۳۳', '۳٤', '۳٥', '۳٦', '۳۷', '۳۸', '۳۹', '٤۰', '٤۱', '٤۲', '٤۳', '٤٤', '٤٥', '٤٦', '٤۷', '٤۸', '٤۹', '٥۰', '٥۱', '٥۲', '٥۳', '٥٤', '٥٥', '٥٦', '٥۷', '٥۸', '٥۹', '٦۰', '٦۱', '٦۲', '٦۳', '٦٤', '٦٥', '٦٦', '٦۷', '٦۸', '٦۹', '۷۰', '۷۱', '۷۲', '۷۳', '۷٤', '۷٥', '۷٦', '۷۷', '۷۸', '۷۹', '۸۰', '۸۱', '۸۲', '۸۳', '۸٤', '۸٥', '۸٦', '۸۷', '۸۸', '۸۹', '۹۰', '۹۱', '۹۲', '۹۳', '۹٤', '۹٥', '۹٦', '۹۷', '۹۸', '۹۹'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ar_BH.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - IBM Globalization Center of Competency, Yamato Software Laboratory    bug-glibc-locales@gnu.org\n * - Abdullah-Alhariri\n */\nreturn array_replace_recursive(require __DIR__.'/ar.php', [\n    'formats' => [\n        'L' => 'DD MMM, YYYY',\n    ],\n    'months' => ['يناير', 'فبراير', 'مارس', 'أبريل', 'مايو', 'يونيو', 'يوليو', 'أغسطس', 'سبتمبر', 'أكتوبر', 'نوفمبر', 'ديسمبر'],\n    'months_short' => ['ينا', 'فبر', 'مار', 'أبر', 'ماي', 'يون', 'يول', 'أغس', 'سبت', 'أكت', 'نوف', 'ديس'],\n    'weekdays' => ['الأحد', 'الاثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعة', 'السبت'],\n    'weekdays_short' => ['ح', 'ن', 'ث', 'ر', 'خ', 'ج', 'س'],\n    'weekdays_min' => ['ح', 'ن', 'ث', 'ر', 'خ', 'ج', 'س'],\n    'first_day_of_week' => 6,\n    'day_of_first_week_of_year' => 1,\n    'alt_numbers' => ['۰۰', '۰۱', '۰۲', '۰۳', '۰٤', '۰٥', '۰٦', '۰۷', '۰۸', '۰۹', '۱۰', '۱۱', '۱۲', '۱۳', '۱٤', '۱٥', '۱٦', '۱۷', '۱۸', '۱۹', '۲۰', '۲۱', '۲۲', '۲۳', '۲٤', '۲٥', '۲٦', '۲۷', '۲۸', '۲۹', '۳۰', '۳۱', '۳۲', '۳۳', '۳٤', '۳٥', '۳٦', '۳۷', '۳۸', '۳۹', '٤۰', '٤۱', '٤۲', '٤۳', '٤٤', '٤٥', '٤٦', '٤۷', '٤۸', '٤۹', '٥۰', '٥۱', '٥۲', '٥۳', '٥٤', '٥٥', '٥٦', '٥۷', '٥۸', '٥۹', '٦۰', '٦۱', '٦۲', '٦۳', '٦٤', '٦٥', '٦٦', '٦۷', '٦۸', '٦۹', '۷۰', '۷۱', '۷۲', '۷۳', '۷٤', '۷٥', '۷٦', '۷۷', '۷۸', '۷۹', '۸۰', '۸۱', '۸۲', '۸۳', '۸٤', '۸٥', '۸٦', '۸۷', '۸۸', '۸۹', '۹۰', '۹۱', '۹۲', '۹۳', '۹٤', '۹٥', '۹٦', '۹۷', '۹۸', '۹۹'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ar_DJ.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/ar.php', [\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ar_DZ.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/**\n * Authors:\n * - Josh Soref\n * - Noureddine LOUAHEDJ\n * - JD Isaacks\n * - Atef Ben Ali (atefBB)\n * - Mohamed Sabil (mohamedsabil83)\n */\n$months = [\n    'جانفي',\n    'فيفري',\n    'مارس',\n    'أفريل',\n    'ماي',\n    'جوان',\n    'جويلية',\n    'أوت',\n    'سبتمبر',\n    'أكتوبر',\n    'نوفمبر',\n    'ديسمبر',\n];\n\nreturn [\n    'year' => implode('|', ['{0}:count سنة', '{1}سنة', '{2}سنتين', ']2,11[:count سنوات', ']10,Inf[:count سنة']),\n    'a_year' => implode('|', ['{0}:count سنة', '{1}سنة', '{2}سنتين', ']2,11[:count سنوات', ']10,Inf[:count سنة']),\n    'month' => implode('|', ['{0}:count شهر', '{1}شهر', '{2}شهرين', ']2,11[:count أشهر', ']10,Inf[:count شهر']),\n    'a_month' => implode('|', ['{0}:count شهر', '{1}شهر', '{2}شهرين', ']2,11[:count أشهر', ']10,Inf[:count شهر']),\n    'week' => implode('|', ['{0}:count أسبوع', '{1}أسبوع', '{2}أسبوعين', ']2,11[:count أسابيع', ']10,Inf[:count أسبوع']),\n    'a_week' => implode('|', ['{0}:count أسبوع', '{1}أسبوع', '{2}أسبوعين', ']2,11[:count أسابيع', ']10,Inf[:count أسبوع']),\n    'day' => implode('|', ['{0}:count يوم', '{1}يوم', '{2}يومين', ']2,11[:count أيام', ']10,Inf[:count يوم']),\n    'a_day' => implode('|', ['{0}:count يوم', '{1}يوم', '{2}يومين', ']2,11[:count أيام', ']10,Inf[:count يوم']),\n    'hour' => implode('|', ['{0}:count ساعة', '{1}ساعة', '{2}ساعتين', ']2,11[:count ساعات', ']10,Inf[:count ساعة']),\n    'a_hour' => implode('|', ['{0}:count ساعة', '{1}ساعة', '{2}ساعتين', ']2,11[:count ساعات', ']10,Inf[:count ساعة']),\n    'minute' => implode('|', ['{0}:count دقيقة', '{1}دقيقة', '{2}دقيقتين', ']2,11[:count دقائق', ']10,Inf[:count دقيقة']),\n    'a_minute' => implode('|', ['{0}:count دقيقة', '{1}دقيقة', '{2}دقيقتين', ']2,11[:count دقائق', ']10,Inf[:count دقيقة']),\n    'second' => implode('|', ['{0}:count ثانية', '{1}ثانية', '{2}ثانيتين', ']2,11[:count ثواني', ']10,Inf[:count ثانية']),\n    'a_second' => implode('|', ['{0}:count ثانية', '{1}ثانية', '{2}ثانيتين', ']2,11[:count ثواني', ']10,Inf[:count ثانية']),\n    'ago' => 'منذ :time',\n    'from_now' => 'في :time',\n    'after' => 'بعد :time',\n    'before' => 'قبل :time',\n    'diff_now' => 'الآن',\n    'diff_today' => 'اليوم',\n    'diff_today_regexp' => 'اليوم(?:\\\\s+على)?(?:\\\\s+الساعة)?',\n    'diff_yesterday' => 'أمس',\n    'diff_yesterday_regexp' => 'أمس(?:\\\\s+على)?(?:\\\\s+الساعة)?',\n    'diff_tomorrow' => 'غداً',\n    'diff_tomorrow_regexp' => 'غدا(?:\\\\s+على)?(?:\\\\s+الساعة)?',\n    'diff_before_yesterday' => 'قبل الأمس',\n    'diff_after_tomorrow' => 'بعد غد',\n    'period_recurrences' => implode('|', ['{0}مرة', '{1}مرة', '{2}:count مرتين', ']2,11[:count مرات', ']10,Inf[:count مرة']),\n    'period_interval' => 'كل :interval',\n    'period_start_date' => 'من :date',\n    'period_end_date' => 'إلى :date',\n    'months' => $months,\n    'months_short' => $months,\n    'weekdays' => ['الأحد', 'الاثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعة', 'السبت'],\n    'weekdays_short' => ['أحد', 'اثنين', 'ثلاثاء', 'أربعاء', 'خميس', 'جمعة', 'سبت'],\n    'weekdays_min' => ['أح', 'إث', 'ثلا', 'أر', 'خم', 'جم', 'سب'],\n    'list' => ['، ', ' و '],\n    'first_day_of_week' => 0,\n    'day_of_first_week_of_year' => 4,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd D MMMM YYYY HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[اليوم على الساعة] LT',\n        'nextDay' => '[غدا على الساعة] LT',\n        'nextWeek' => 'dddd [على الساعة] LT',\n        'lastDay' => '[أمس على الساعة] LT',\n        'lastWeek' => 'dddd [على الساعة] LT',\n        'sameElse' => 'L',\n    ],\n    'meridiem' => ['ص', 'م'],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ar_EG.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - IBM Globalization Center of Competency, Yamato Software Laboratory    bug-glibc-locales@gnu.org\n * - Abdullah-Alhariri\n */\nreturn array_replace_recursive(require __DIR__.'/ar.php', [\n    'formats' => [\n        'L' => 'DD MMM, YYYY',\n    ],\n    'months' => ['يناير', 'فبراير', 'مارس', 'أبريل', 'مايو', 'يونيو', 'يوليو', 'أغسطس', 'سبتمبر', 'أكتوبر', 'نوفمبر', 'ديسمبر'],\n    'months_short' => ['ينا', 'فبر', 'مار', 'أبر', 'ماي', 'يون', 'يول', 'أغس', 'سبت', 'أكت', 'نوف', 'ديس'],\n    'weekdays' => ['الأحد', 'الاثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعة', 'السبت'],\n    'weekdays_short' => ['ح', 'ن', 'ث', 'ر', 'خ', 'ج', 'س'],\n    'weekdays_min' => ['ح', 'ن', 'ث', 'ر', 'خ', 'ج', 'س'],\n    'first_day_of_week' => 6,\n    'day_of_first_week_of_year' => 1,\n    'alt_numbers' => ['۰۰', '۰۱', '۰۲', '۰۳', '۰٤', '۰٥', '۰٦', '۰۷', '۰۸', '۰۹', '۱۰', '۱۱', '۱۲', '۱۳', '۱٤', '۱٥', '۱٦', '۱۷', '۱۸', '۱۹', '۲۰', '۲۱', '۲۲', '۲۳', '۲٤', '۲٥', '۲٦', '۲۷', '۲۸', '۲۹', '۳۰', '۳۱', '۳۲', '۳۳', '۳٤', '۳٥', '۳٦', '۳۷', '۳۸', '۳۹', '٤۰', '٤۱', '٤۲', '٤۳', '٤٤', '٤٥', '٤٦', '٤۷', '٤۸', '٤۹', '٥۰', '٥۱', '٥۲', '٥۳', '٥٤', '٥٥', '٥٦', '٥۷', '٥۸', '٥۹', '٦۰', '٦۱', '٦۲', '٦۳', '٦٤', '٦٥', '٦٦', '٦۷', '٦۸', '٦۹', '۷۰', '۷۱', '۷۲', '۷۳', '۷٤', '۷٥', '۷٦', '۷۷', '۷۸', '۷۹', '۸۰', '۸۱', '۸۲', '۸۳', '۸٤', '۸٥', '۸٦', '۸۷', '۸۸', '۸۹', '۹۰', '۹۱', '۹۲', '۹۳', '۹٤', '۹٥', '۹٦', '۹۷', '۹۸', '۹۹'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ar_EH.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/ar.php', [\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ar_ER.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/ar.php', [\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ar_IL.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/ar.php', [\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ar_IN.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - IBM Globalization Center of Competency, Yamato Software Laboratory    bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/ar.php', [\n    'formats' => [\n        'L' => 'D/M/YY',\n    ],\n    'months' => ['يناير', 'فبراير', 'مارس', 'أبريل', 'مايو', 'يونيو', 'يوليو', 'أغسطس', 'سبتمبر', 'أكتوبر', 'نوفمبر', 'ديسمبر'],\n    'months_short' => ['ينا', 'فبر', 'مار', 'أبر', 'ماي', 'يون', 'يول', 'أغس', 'سبت', 'أكت', 'نوف', 'ديس'],\n    'weekdays' => ['الأحد', 'الاثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعة', 'السبت'],\n    'weekdays_short' => ['ح', 'ن', 'ث', 'ر', 'خ', 'ج', 'س'],\n    'weekdays_min' => ['ح', 'ن', 'ث', 'ر', 'خ', 'ج', 'س'],\n    'day_of_first_week_of_year' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ar_IQ.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - IBM Globalization Center of Competency, Yamato Software Laboratory    bug-glibc-locales@gnu.org\n * - Abdullah-Alhariri\n */\nreturn array_replace_recursive(require __DIR__.'/ar.php', [\n    'formats' => [\n        'L' => 'DD MMM, YYYY',\n    ],\n    'months' => ['كانون الثاني', 'شباط', 'آذار', 'نيسان', 'أيار', 'حزيران', 'تموز', 'آب', 'أيلول', 'تشرين الأول', 'تشرين الثاني', 'كانون الأول'],\n    'months_short' => ['كانون الثاني', 'شباط', 'آذار', 'نيسان', 'أيار', 'حزيران', 'تموز', 'آب', 'أيلول', 'تشرين الأول', 'تشرين الثاني', 'كانون الأول'],\n    'weekdays' => ['الأحد', 'الاثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعة', 'السبت'],\n    'weekdays_short' => ['ح', 'ن', 'ث', 'ر', 'خ', 'ج', 'س'],\n    'weekdays_min' => ['ح', 'ن', 'ث', 'ر', 'خ', 'ج', 'س'],\n    'first_day_of_week' => 6,\n    'day_of_first_week_of_year' => 1,\n    'alt_numbers' => ['۰۰', '۰۱', '۰۲', '۰۳', '۰٤', '۰٥', '۰٦', '۰۷', '۰۸', '۰۹', '۱۰', '۱۱', '۱۲', '۱۳', '۱٤', '۱٥', '۱٦', '۱۷', '۱۸', '۱۹', '۲۰', '۲۱', '۲۲', '۲۳', '۲٤', '۲٥', '۲٦', '۲۷', '۲۸', '۲۹', '۳۰', '۳۱', '۳۲', '۳۳', '۳٤', '۳٥', '۳٦', '۳۷', '۳۸', '۳۹', '٤۰', '٤۱', '٤۲', '٤۳', '٤٤', '٤٥', '٤٦', '٤۷', '٤۸', '٤۹', '٥۰', '٥۱', '٥۲', '٥۳', '٥٤', '٥٥', '٥٦', '٥۷', '٥۸', '٥۹', '٦۰', '٦۱', '٦۲', '٦۳', '٦٤', '٦٥', '٦٦', '٦۷', '٦۸', '٦۹', '۷۰', '۷۱', '۷۲', '۷۳', '۷٤', '۷٥', '۷٦', '۷۷', '۷۸', '۷۹', '۸۰', '۸۱', '۸۲', '۸۳', '۸٤', '۸٥', '۸٦', '۸۷', '۸۸', '۸۹', '۹۰', '۹۱', '۹۲', '۹۳', '۹٤', '۹٥', '۹٦', '۹۷', '۹۸', '۹۹'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ar_JO.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - IBM Globalization Center of Competency, Yamato Software Laboratory    bug-glibc-locales@gnu.org\n * - Abdullah-Alhariri\n */\nreturn array_replace_recursive(require __DIR__.'/ar.php', [\n    'formats' => [\n        'L' => 'DD MMM, YYYY',\n    ],\n    'months' => ['كانون الثاني', 'شباط', 'آذار', 'نيسان', 'أيار', 'حزيران', 'تموز', 'آب', 'أيلول', 'تشرين الأول', 'تشرين الثاني', 'كانون الأول'],\n    'months_short' => ['كانون الثاني', 'شباط', 'آذار', 'نيسان', 'أيار', 'حزيران', 'تموز', 'آب', 'أيلول', 'تشرين الأول', 'تشرين الثاني', 'كانون الأول'],\n    'weekdays' => ['الأحد', 'الاثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعة', 'السبت'],\n    'weekdays_short' => ['ح', 'ن', 'ث', 'ر', 'خ', 'ج', 'س'],\n    'weekdays_min' => ['ح', 'ن', 'ث', 'ر', 'خ', 'ج', 'س'],\n    'first_day_of_week' => 6,\n    'day_of_first_week_of_year' => 1,\n    'alt_numbers' => ['۰۰', '۰۱', '۰۲', '۰۳', '۰٤', '۰٥', '۰٦', '۰۷', '۰۸', '۰۹', '۱۰', '۱۱', '۱۲', '۱۳', '۱٤', '۱٥', '۱٦', '۱۷', '۱۸', '۱۹', '۲۰', '۲۱', '۲۲', '۲۳', '۲٤', '۲٥', '۲٦', '۲۷', '۲۸', '۲۹', '۳۰', '۳۱', '۳۲', '۳۳', '۳٤', '۳٥', '۳٦', '۳۷', '۳۸', '۳۹', '٤۰', '٤۱', '٤۲', '٤۳', '٤٤', '٤٥', '٤٦', '٤۷', '٤۸', '٤۹', '٥۰', '٥۱', '٥۲', '٥۳', '٥٤', '٥٥', '٥٦', '٥۷', '٥۸', '٥۹', '٦۰', '٦۱', '٦۲', '٦۳', '٦٤', '٦٥', '٦٦', '٦۷', '٦۸', '٦۹', '۷۰', '۷۱', '۷۲', '۷۳', '۷٤', '۷٥', '۷٦', '۷۷', '۷۸', '۷۹', '۸۰', '۸۱', '۸۲', '۸۳', '۸٤', '۸٥', '۸٦', '۸۷', '۸۸', '۸۹', '۹۰', '۹۱', '۹۲', '۹۳', '۹٤', '۹٥', '۹٦', '۹۷', '۹۸', '۹۹'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ar_KM.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/ar.php', [\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ar_KW.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/**\n * Authors:\n * - Josh Soref\n * - Nusret Parlak\n * - JD Isaacks\n * - Atef Ben Ali (atefBB)\n * - Mohamed Sabil (mohamedsabil83)\n * - Abdullah-Alhariri\n */\n$months = [\n    'يناير',\n    'فبراير',\n    'مارس',\n    'أبريل',\n    'ماي',\n    'يونيو',\n    'يوليوز',\n    'غشت',\n    'شتنبر',\n    'أكتوبر',\n    'نونبر',\n    'دجنبر',\n];\n\nreturn [\n    'year' => implode('|', ['{0}:count سنة', '{1}سنة', '{2}سنتين', ']2,11[:count سنوات', ']10,Inf[:count سنة']),\n    'a_year' => implode('|', ['{0}:count سنة', '{1}سنة', '{2}سنتين', ']2,11[:count سنوات', ']10,Inf[:count سنة']),\n    'month' => implode('|', ['{0}:count شهر', '{1}شهر', '{2}شهرين', ']2,11[:count أشهر', ']10,Inf[:count شهر']),\n    'a_month' => implode('|', ['{0}:count شهر', '{1}شهر', '{2}شهرين', ']2,11[:count أشهر', ']10,Inf[:count شهر']),\n    'week' => implode('|', ['{0}:count أسبوع', '{1}أسبوع', '{2}أسبوعين', ']2,11[:count أسابيع', ']10,Inf[:count أسبوع']),\n    'a_week' => implode('|', ['{0}:count أسبوع', '{1}أسبوع', '{2}أسبوعين', ']2,11[:count أسابيع', ']10,Inf[:count أسبوع']),\n    'day' => implode('|', ['{0}:count يوم', '{1}يوم', '{2}يومين', ']2,11[:count أيام', ']10,Inf[:count يوم']),\n    'a_day' => implode('|', ['{0}:count يوم', '{1}يوم', '{2}يومين', ']2,11[:count أيام', ']10,Inf[:count يوم']),\n    'hour' => implode('|', ['{0}:count ساعة', '{1}ساعة', '{2}ساعتين', ']2,11[:count ساعات', ']10,Inf[:count ساعة']),\n    'a_hour' => implode('|', ['{0}:count ساعة', '{1}ساعة', '{2}ساعتين', ']2,11[:count ساعات', ']10,Inf[:count ساعة']),\n    'minute' => implode('|', ['{0}:count دقيقة', '{1}دقيقة', '{2}دقيقتين', ']2,11[:count دقائق', ']10,Inf[:count دقيقة']),\n    'a_minute' => implode('|', ['{0}:count دقيقة', '{1}دقيقة', '{2}دقيقتين', ']2,11[:count دقائق', ']10,Inf[:count دقيقة']),\n    'second' => implode('|', ['{0}:count ثانية', '{1}ثانية', '{2}ثانيتين', ']2,11[:count ثواني', ']10,Inf[:count ثانية']),\n    'a_second' => implode('|', ['{0}:count ثانية', '{1}ثانية', '{2}ثانيتين', ']2,11[:count ثواني', ']10,Inf[:count ثانية']),\n    'ago' => 'منذ :time',\n    'from_now' => 'في :time',\n    'after' => 'بعد :time',\n    'before' => 'قبل :time',\n    'diff_now' => 'الآن',\n    'diff_today' => 'اليوم',\n    'diff_today_regexp' => 'اليوم(?:\\\\s+على)?(?:\\\\s+الساعة)?',\n    'diff_yesterday' => 'أمس',\n    'diff_yesterday_regexp' => 'أمس(?:\\\\s+على)?(?:\\\\s+الساعة)?',\n    'diff_tomorrow' => 'غداً',\n    'diff_tomorrow_regexp' => 'غدا(?:\\\\s+على)?(?:\\\\s+الساعة)?',\n    'diff_before_yesterday' => 'قبل الأمس',\n    'diff_after_tomorrow' => 'بعد غد',\n    'period_recurrences' => implode('|', ['{0}مرة', '{1}مرة', '{2}:count مرتين', ']2,11[:count مرات', ']10,Inf[:count مرة']),\n    'period_interval' => 'كل :interval',\n    'period_start_date' => 'من :date',\n    'period_end_date' => 'إلى :date',\n    'months' => $months,\n    'months_short' => $months,\n    'weekdays' => ['الأحد', 'الاثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعة', 'السبت'],\n    'weekdays_short' => ['أحد', 'اثنين', 'ثلاثاء', 'أربعاء', 'خميس', 'جمعة', 'سبت'],\n    'weekdays_min' => ['ح', 'ن', 'ث', 'ر', 'خ', 'ج', 'س'],\n    'list' => ['، ', ' و '],\n    'first_day_of_week' => 0,\n    'day_of_first_week_of_year' => 1,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd D MMMM YYYY HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[اليوم على الساعة] LT',\n        'nextDay' => '[غدا على الساعة] LT',\n        'nextWeek' => 'dddd [على الساعة] LT',\n        'lastDay' => '[أمس على الساعة] LT',\n        'lastWeek' => 'dddd [على الساعة] LT',\n        'sameElse' => 'L',\n    ],\n    'meridiem' => ['ص', 'م'],\n    'weekend' => [5, 6],\n    'alt_numbers' => ['۰۰', '۰۱', '۰۲', '۰۳', '۰٤', '۰٥', '۰٦', '۰۷', '۰۸', '۰۹', '۱۰', '۱۱', '۱۲', '۱۳', '۱٤', '۱٥', '۱٦', '۱۷', '۱۸', '۱۹', '۲۰', '۲۱', '۲۲', '۲۳', '۲٤', '۲٥', '۲٦', '۲۷', '۲۸', '۲۹', '۳۰', '۳۱', '۳۲', '۳۳', '۳٤', '۳٥', '۳٦', '۳۷', '۳۸', '۳۹', '٤۰', '٤۱', '٤۲', '٤۳', '٤٤', '٤٥', '٤٦', '٤۷', '٤۸', '٤۹', '٥۰', '٥۱', '٥۲', '٥۳', '٥٤', '٥٥', '٥٦', '٥۷', '٥۸', '٥۹', '٦۰', '٦۱', '٦۲', '٦۳', '٦٤', '٦٥', '٦٦', '٦۷', '٦۸', '٦۹', '۷۰', '۷۱', '۷۲', '۷۳', '۷٤', '۷٥', '۷٦', '۷۷', '۷۸', '۷۹', '۸۰', '۸۱', '۸۲', '۸۳', '۸٤', '۸٥', '۸٦', '۸۷', '۸۸', '۸۹', '۹۰', '۹۱', '۹۲', '۹۳', '۹٤', '۹٥', '۹٦', '۹۷', '۹۸', '۹۹'],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ar_LB.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - IBM Globalization Center of Competency, Yamato Software Laboratory    bug-glibc-locales@gnu.org\n * - Abdullah-Alhariri\n */\nreturn array_replace_recursive(require __DIR__.'/ar.php', [\n    'formats' => [\n        'L' => 'DD MMM, YYYY',\n    ],\n    'months' => ['كانون الثاني', 'شباط', 'آذار', 'نيسان', 'أيار', 'حزيران', 'تموز', 'آب', 'أيلول', 'تشرين الأول', 'تشرين الثاني', 'كانون الأول'],\n    'months_short' => ['كانون الثاني', 'شباط', 'آذار', 'نيسان', 'أيار', 'حزيران', 'تموز', 'آب', 'أيلول', 'تشرين الأول', 'تشرين الثاني', 'كانون الأول'],\n    'weekdays' => ['الأحد', 'الاثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعة', 'السبت'],\n    'weekdays_short' => ['ح', 'ن', 'ث', 'ر', 'خ', 'ج', 'س'],\n    'weekdays_min' => ['ح', 'ن', 'ث', 'ر', 'خ', 'ج', 'س'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n    'alt_numbers' => ['۰۰', '۰۱', '۰۲', '۰۳', '۰٤', '۰٥', '۰٦', '۰۷', '۰۸', '۰۹', '۱۰', '۱۱', '۱۲', '۱۳', '۱٤', '۱٥', '۱٦', '۱۷', '۱۸', '۱۹', '۲۰', '۲۱', '۲۲', '۲۳', '۲٤', '۲٥', '۲٦', '۲۷', '۲۸', '۲۹', '۳۰', '۳۱', '۳۲', '۳۳', '۳٤', '۳٥', '۳٦', '۳۷', '۳۸', '۳۹', '٤۰', '٤۱', '٤۲', '٤۳', '٤٤', '٤٥', '٤٦', '٤۷', '٤۸', '٤۹', '٥۰', '٥۱', '٥۲', '٥۳', '٥٤', '٥٥', '٥٦', '٥۷', '٥۸', '٥۹', '٦۰', '٦۱', '٦۲', '٦۳', '٦٤', '٦٥', '٦٦', '٦۷', '٦۸', '٦۹', '۷۰', '۷۱', '۷۲', '۷۳', '۷٤', '۷٥', '۷٦', '۷۷', '۷۸', '۷۹', '۸۰', '۸۱', '۸۲', '۸۳', '۸٤', '۸٥', '۸٦', '۸۷', '۸۸', '۸۹', '۹۰', '۹۱', '۹۲', '۹۳', '۹٤', '۹٥', '۹٦', '۹۷', '۹۸', '۹۹'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ar_LY.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Atef Ben Ali (atefBB)\n * - Ibrahim AshShohail\n * - MLTDev\n */\n\n$months = [\n    'يناير',\n    'فبراير',\n    'مارس',\n    'أبريل',\n    'مايو',\n    'يونيو',\n    'يوليو',\n    'أغسطس',\n    'سبتمبر',\n    'أكتوبر',\n    'نوفمبر',\n    'ديسمبر',\n];\n\nreturn [\n    'year' => implode('|', [':count سنة', 'سنة', 'سنتين', ':count سنوات', ':count سنة']),\n    'a_year' => implode('|', [':count سنة', 'سنة', 'سنتين', ':count سنوات', ':count سنة']),\n    'month' => implode('|', [':count شهر', 'شهر', 'شهرين', ':count أشهر', ':count شهر']),\n    'a_month' => implode('|', [':count شهر', 'شهر', 'شهرين', ':count أشهر', ':count شهر']),\n    'week' => implode('|', [':count أسبوع', 'أسبوع', 'أسبوعين', ':count أسابيع', ':count أسبوع']),\n    'a_week' => implode('|', [':count أسبوع', 'أسبوع', 'أسبوعين', ':count أسابيع', ':count أسبوع']),\n    'day' => implode('|', [':count يوم', 'يوم', 'يومين', ':count أيام', ':count يوم']),\n    'a_day' => implode('|', [':count يوم', 'يوم', 'يومين', ':count أيام', ':count يوم']),\n    'hour' => implode('|', [':count ساعة', 'ساعة', 'ساعتين', ':count ساعات', ':count ساعة']),\n    'a_hour' => implode('|', [':count ساعة', 'ساعة', 'ساعتين', ':count ساعات', ':count ساعة']),\n    'minute' => implode('|', [':count دقيقة', 'دقيقة', 'دقيقتين', ':count دقائق', ':count دقيقة']),\n    'a_minute' => implode('|', [':count دقيقة', 'دقيقة', 'دقيقتين', ':count دقائق', ':count دقيقة']),\n    'second' => implode('|', [':count ثانية', 'ثانية', 'ثانيتين', ':count ثواني', ':count ثانية']),\n    'a_second' => implode('|', [':count ثانية', 'ثانية', 'ثانيتين', ':count ثواني', ':count ثانية']),\n    'ago' => 'منذ :time',\n    'from_now' => ':time من الآن',\n    'after' => 'بعد :time',\n    'before' => 'قبل :time',\n    'diff_now' => 'الآن',\n    'diff_today' => 'اليوم',\n    'diff_today_regexp' => 'اليوم(?:\\\\s+عند)?(?:\\\\s+الساعة)?',\n    'diff_yesterday' => 'أمس',\n    'diff_yesterday_regexp' => 'أمس(?:\\\\s+عند)?(?:\\\\s+الساعة)?',\n    'diff_tomorrow' => 'غداً',\n    'diff_tomorrow_regexp' => 'غدًا(?:\\\\s+عند)?(?:\\\\s+الساعة)?',\n    'diff_before_yesterday' => 'قبل الأمس',\n    'diff_after_tomorrow' => 'بعد غد',\n    'period_recurrences' => implode('|', ['مرة', 'مرة', ':count مرتين', ':count مرات', ':count مرة']),\n    'period_interval' => 'كل :interval',\n    'period_start_date' => 'من :date',\n    'period_end_date' => 'إلى :date',\n    'months' => $months,\n    'months_short' => $months,\n    'weekdays' => ['الأحد', 'الاثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعة', 'السبت'],\n    'weekdays_short' => ['أحد', 'اثنين', 'ثلاثاء', 'أربعاء', 'خميس', 'جمعة', 'سبت'],\n    'weekdays_min' => ['ح', 'اث', 'ثل', 'أر', 'خم', 'ج', 'س'],\n    'list' => ['، ', ' و '],\n    'first_day_of_week' => 6,\n    'day_of_first_week_of_year' => 1,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'D/M/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd D MMMM YYYY HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[اليوم عند الساعة] LT',\n        'nextDay' => '[غدًا عند الساعة] LT',\n        'nextWeek' => 'dddd [عند الساعة] LT',\n        'lastDay' => '[أمس عند الساعة] LT',\n        'lastWeek' => 'dddd [عند الساعة] LT',\n        'sameElse' => 'L',\n    ],\n    'meridiem' => ['ص', 'م'],\n    'weekend' => [5, 6],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ar_MA.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/**\n * Authors:\n * - Josh Soref\n * - JD Isaacks\n * - Atef Ben Ali (atefBB)\n * - Mohamed Sabil (mohamedsabil83)\n */\n$months = [\n    'يناير',\n    'فبراير',\n    'مارس',\n    'أبريل',\n    'ماي',\n    'يونيو',\n    'يوليوز',\n    'غشت',\n    'شتنبر',\n    'أكتوبر',\n    'نونبر',\n    'دجنبر',\n];\n\nreturn [\n    'year' => implode('|', ['{0}:count سنة', '{1}سنة', '{2}سنتين', ']2,11[:count سنوات', ']10,Inf[:count سنة']),\n    'a_year' => implode('|', ['{0}:count سنة', '{1}سنة', '{2}سنتين', ']2,11[:count سنوات', ']10,Inf[:count سنة']),\n    'month' => implode('|', ['{0}:count شهر', '{1}شهر', '{2}شهرين', ']2,11[:count أشهر', ']10,Inf[:count شهر']),\n    'a_month' => implode('|', ['{0}:count شهر', '{1}شهر', '{2}شهرين', ']2,11[:count أشهر', ']10,Inf[:count شهر']),\n    'week' => implode('|', ['{0}:count أسبوع', '{1}أسبوع', '{2}أسبوعين', ']2,11[:count أسابيع', ']10,Inf[:count أسبوع']),\n    'a_week' => implode('|', ['{0}:count أسبوع', '{1}أسبوع', '{2}أسبوعين', ']2,11[:count أسابيع', ']10,Inf[:count أسبوع']),\n    'day' => implode('|', ['{0}:count يوم', '{1}يوم', '{2}يومين', ']2,11[:count أيام', ']10,Inf[:count يوم']),\n    'a_day' => implode('|', ['{0}:count يوم', '{1}يوم', '{2}يومين', ']2,11[:count أيام', ']10,Inf[:count يوم']),\n    'hour' => implode('|', ['{0}:count ساعة', '{1}ساعة', '{2}ساعتين', ']2,11[:count ساعات', ']10,Inf[:count ساعة']),\n    'a_hour' => implode('|', ['{0}:count ساعة', '{1}ساعة', '{2}ساعتين', ']2,11[:count ساعات', ']10,Inf[:count ساعة']),\n    'minute' => implode('|', ['{0}:count دقيقة', '{1}دقيقة', '{2}دقيقتين', ']2,11[:count دقائق', ']10,Inf[:count دقيقة']),\n    'a_minute' => implode('|', ['{0}:count دقيقة', '{1}دقيقة', '{2}دقيقتين', ']2,11[:count دقائق', ']10,Inf[:count دقيقة']),\n    'second' => implode('|', ['{0}:count ثانية', '{1}ثانية', '{2}ثانيتين', ']2,11[:count ثواني', ']10,Inf[:count ثانية']),\n    'a_second' => implode('|', ['{0}:count ثانية', '{1}ثانية', '{2}ثانيتين', ']2,11[:count ثواني', ']10,Inf[:count ثانية']),\n    'ago' => 'منذ :time',\n    'from_now' => 'في :time',\n    'after' => 'بعد :time',\n    'before' => 'قبل :time',\n    'diff_now' => 'الآن',\n    'diff_today' => 'اليوم',\n    'diff_today_regexp' => 'اليوم(?:\\\\s+على)?(?:\\\\s+الساعة)?',\n    'diff_yesterday' => 'أمس',\n    'diff_yesterday_regexp' => 'أمس(?:\\\\s+على)?(?:\\\\s+الساعة)?',\n    'diff_tomorrow' => 'غداً',\n    'diff_tomorrow_regexp' => 'غدا(?:\\\\s+على)?(?:\\\\s+الساعة)?',\n    'diff_before_yesterday' => 'قبل الأمس',\n    'diff_after_tomorrow' => 'بعد غد',\n    'period_recurrences' => implode('|', ['{0}مرة', '{1}مرة', '{2}:count مرتين', ']2,11[:count مرات', ']10,Inf[:count مرة']),\n    'period_interval' => 'كل :interval',\n    'period_start_date' => 'من :date',\n    'period_end_date' => 'إلى :date',\n    'months' => $months,\n    'months_short' => $months,\n    'weekdays' => ['الأحد', 'الاثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعة', 'السبت'],\n    'weekdays_short' => ['أحد', 'اثنين', 'ثلاثاء', 'أربعاء', 'خميس', 'جمعة', 'سبت'],\n    'weekdays_min' => ['ح', 'ن', 'ث', 'ر', 'خ', 'ج', 'س'],\n    'list' => ['، ', ' و '],\n    'first_day_of_week' => 6,\n    'day_of_first_week_of_year' => 1,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd D MMMM YYYY HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[اليوم على الساعة] LT',\n        'nextDay' => '[غدا على الساعة] LT',\n        'nextWeek' => 'dddd [على الساعة] LT',\n        'lastDay' => '[أمس على الساعة] LT',\n        'lastWeek' => 'dddd [على الساعة] LT',\n        'sameElse' => 'L',\n    ],\n    'meridiem' => ['ص', 'م'],\n    'weekend' => [5, 6],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ar_MR.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/ar.php', [\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ar_OM.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - IBM Globalization Center of Competency, Yamato Software Laboratory    bug-glibc-locales@gnu.org\n * - Abdullah-Alhariri\n */\nreturn array_replace_recursive(require __DIR__.'/ar.php', [\n    'formats' => [\n        'L' => 'DD MMM, YYYY',\n    ],\n    'months' => ['يناير', 'فبراير', 'مارس', 'أبريل', 'مايو', 'يونيو', 'يوليو', 'أغسطس', 'سبتمبر', 'أكتوبر', 'نوفمبر', 'ديسمبر'],\n    'months_short' => ['ينا', 'فبر', 'مار', 'أبر', 'ماي', 'يون', 'يول', 'أغس', 'سبت', 'أكت', 'نوف', 'ديس'],\n    'weekdays' => ['الأحد', 'الاثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعة', 'السبت'],\n    'weekdays_short' => ['ح', 'ن', 'ث', 'ر', 'خ', 'ج', 'س'],\n    'weekdays_min' => ['ح', 'ن', 'ث', 'ر', 'خ', 'ج', 'س'],\n    'first_day_of_week' => 6,\n    'day_of_first_week_of_year' => 1,\n    'alt_numbers' => ['۰۰', '۰۱', '۰۲', '۰۳', '۰٤', '۰٥', '۰٦', '۰۷', '۰۸', '۰۹', '۱۰', '۱۱', '۱۲', '۱۳', '۱٤', '۱٥', '۱٦', '۱۷', '۱۸', '۱۹', '۲۰', '۲۱', '۲۲', '۲۳', '۲٤', '۲٥', '۲٦', '۲۷', '۲۸', '۲۹', '۳۰', '۳۱', '۳۲', '۳۳', '۳٤', '۳٥', '۳٦', '۳۷', '۳۸', '۳۹', '٤۰', '٤۱', '٤۲', '٤۳', '٤٤', '٤٥', '٤٦', '٤۷', '٤۸', '٤۹', '٥۰', '٥۱', '٥۲', '٥۳', '٥٤', '٥٥', '٥٦', '٥۷', '٥۸', '٥۹', '٦۰', '٦۱', '٦۲', '٦۳', '٦٤', '٦٥', '٦٦', '٦۷', '٦۸', '٦۹', '۷۰', '۷۱', '۷۲', '۷۳', '۷٤', '۷٥', '۷٦', '۷۷', '۷۸', '۷۹', '۸۰', '۸۱', '۸۲', '۸۳', '۸٤', '۸٥', '۸٦', '۸۷', '۸۸', '۸۹', '۹۰', '۹۱', '۹۲', '۹۳', '۹٤', '۹٥', '۹٦', '۹۷', '۹۸', '۹۹'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ar_PS.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Abdullah-Alhariri\n */\nreturn array_replace_recursive(require __DIR__.'/ar.php', [\n    'alt_numbers' => ['۰۰', '۰۱', '۰۲', '۰۳', '۰٤', '۰٥', '۰٦', '۰۷', '۰۸', '۰۹', '۱۰', '۱۱', '۱۲', '۱۳', '۱٤', '۱٥', '۱٦', '۱۷', '۱۸', '۱۹', '۲۰', '۲۱', '۲۲', '۲۳', '۲٤', '۲٥', '۲٦', '۲۷', '۲۸', '۲۹', '۳۰', '۳۱', '۳۲', '۳۳', '۳٤', '۳٥', '۳٦', '۳۷', '۳۸', '۳۹', '٤۰', '٤۱', '٤۲', '٤۳', '٤٤', '٤٥', '٤٦', '٤۷', '٤۸', '٤۹', '٥۰', '٥۱', '٥۲', '٥۳', '٥٤', '٥٥', '٥٦', '٥۷', '٥۸', '٥۹', '٦۰', '٦۱', '٦۲', '٦۳', '٦٤', '٦٥', '٦٦', '٦۷', '٦۸', '٦۹', '۷۰', '۷۱', '۷۲', '۷۳', '۷٤', '۷٥', '۷٦', '۷۷', '۷۸', '۷۹', '۸۰', '۸۱', '۸۲', '۸۳', '۸٤', '۸٥', '۸٦', '۸۷', '۸۸', '۸۹', '۹۰', '۹۱', '۹۲', '۹۳', '۹٤', '۹٥', '۹٦', '۹۷', '۹۸', '۹۹'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ar_QA.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - IBM Globalization Center of Competency, Yamato Software Laboratory    bug-glibc-locales@gnu.org\n * - Abdullah-Alhariri\n */\nreturn array_replace_recursive(require __DIR__.'/ar.php', [\n    'formats' => [\n        'L' => 'DD MMM, YYYY',\n    ],\n    'months' => ['يناير', 'فبراير', 'مارس', 'أبريل', 'مايو', 'يونيو', 'يوليو', 'أغسطس', 'سبتمبر', 'أكتوبر', 'نوفمبر', 'ديسمبر'],\n    'months_short' => ['ينا', 'فبر', 'مار', 'أبر', 'ماي', 'يون', 'يول', 'أغس', 'سبت', 'أكت', 'نوف', 'ديس'],\n    'weekdays' => ['الأحد', 'الاثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعة', 'السبت'],\n    'weekdays_short' => ['ح', 'ن', 'ث', 'ر', 'خ', 'ج', 'س'],\n    'weekdays_min' => ['ح', 'ن', 'ث', 'ر', 'خ', 'ج', 'س'],\n    'first_day_of_week' => 6,\n    'day_of_first_week_of_year' => 1,\n    'alt_numbers' => ['۰۰', '۰۱', '۰۲', '۰۳', '۰٤', '۰٥', '۰٦', '۰۷', '۰۸', '۰۹', '۱۰', '۱۱', '۱۲', '۱۳', '۱٤', '۱٥', '۱٦', '۱۷', '۱۸', '۱۹', '۲۰', '۲۱', '۲۲', '۲۳', '۲٤', '۲٥', '۲٦', '۲۷', '۲۸', '۲۹', '۳۰', '۳۱', '۳۲', '۳۳', '۳٤', '۳٥', '۳٦', '۳۷', '۳۸', '۳۹', '٤۰', '٤۱', '٤۲', '٤۳', '٤٤', '٤٥', '٤٦', '٤۷', '٤۸', '٤۹', '٥۰', '٥۱', '٥۲', '٥۳', '٥٤', '٥٥', '٥٦', '٥۷', '٥۸', '٥۹', '٦۰', '٦۱', '٦۲', '٦۳', '٦٤', '٦٥', '٦٦', '٦۷', '٦۸', '٦۹', '۷۰', '۷۱', '۷۲', '۷۳', '۷٤', '۷٥', '۷٦', '۷۷', '۷۸', '۷۹', '۸۰', '۸۱', '۸۲', '۸۳', '۸٤', '۸٥', '۸٦', '۸۷', '۸۸', '۸۹', '۹۰', '۹۱', '۹۲', '۹۳', '۹٤', '۹٥', '۹٦', '۹۷', '۹۸', '۹۹'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ar_SA.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/**\n * Authors:\n * - Josh Soref\n * - JD Isaacks\n * - Atef Ben Ali (atefBB)\n * - Mohamed Sabil (mohamedsabil83)\n * - Abdullah-Alhariri\n */\n$months = [\n    'يناير',\n    'فبراير',\n    'مارس',\n    'أبريل',\n    'مايو',\n    'يونيو',\n    'يوليو',\n    'أغسطس',\n    'سبتمبر',\n    'أكتوبر',\n    'نوفمبر',\n    'ديسمبر',\n];\n\nreturn [\n    'year' => implode('|', ['{0}:count سنة', '{1}سنة', '{2}سنتين', ']2,11[:count سنوات', ']10,Inf[:count سنة']),\n    'a_year' => implode('|', ['{0}:count سنة', '{1}سنة', '{2}سنتين', ']2,11[:count سنوات', ']10,Inf[:count سنة']),\n    'month' => implode('|', ['{0}:count شهر', '{1}شهر', '{2}شهرين', ']2,11[:count أشهر', ']10,Inf[:count شهر']),\n    'a_month' => implode('|', ['{0}:count شهر', '{1}شهر', '{2}شهرين', ']2,11[:count أشهر', ']10,Inf[:count شهر']),\n    'week' => implode('|', ['{0}:count أسبوع', '{1}أسبوع', '{2}أسبوعين', ']2,11[:count أسابيع', ']10,Inf[:count أسبوع']),\n    'a_week' => implode('|', ['{0}:count أسبوع', '{1}أسبوع', '{2}أسبوعين', ']2,11[:count أسابيع', ']10,Inf[:count أسبوع']),\n    'day' => implode('|', ['{0}:count يوم', '{1}يوم', '{2}يومين', ']2,11[:count أيام', ']10,Inf[:count يوم']),\n    'a_day' => implode('|', ['{0}:count يوم', '{1}يوم', '{2}يومين', ']2,11[:count أيام', ']10,Inf[:count يوم']),\n    'hour' => implode('|', ['{0}:count ساعة', '{1}ساعة', '{2}ساعتين', ']2,11[:count ساعات', ']10,Inf[:count ساعة']),\n    'a_hour' => implode('|', ['{0}:count ساعة', '{1}ساعة', '{2}ساعتين', ']2,11[:count ساعات', ']10,Inf[:count ساعة']),\n    'minute' => implode('|', ['{0}:count دقيقة', '{1}دقيقة', '{2}دقيقتين', ']2,11[:count دقائق', ']10,Inf[:count دقيقة']),\n    'a_minute' => implode('|', ['{0}:count دقيقة', '{1}دقيقة', '{2}دقيقتين', ']2,11[:count دقائق', ']10,Inf[:count دقيقة']),\n    'second' => implode('|', ['{0}:count ثانية', '{1}ثانية', '{2}ثانيتين', ']2,11[:count ثواني', ']10,Inf[:count ثانية']),\n    'a_second' => implode('|', ['{0}:count ثانية', '{1}ثانية', '{2}ثانيتين', ']2,11[:count ثواني', ']10,Inf[:count ثانية']),\n    'ago' => 'منذ :time',\n    'from_now' => 'في :time',\n    'after' => 'بعد :time',\n    'before' => 'قبل :time',\n    'diff_now' => 'الآن',\n    'diff_today' => 'اليوم',\n    'diff_today_regexp' => 'اليوم(?:\\\\s+على)?(?:\\\\s+الساعة)?',\n    'diff_yesterday' => 'أمس',\n    'diff_yesterday_regexp' => 'أمس(?:\\\\s+على)?(?:\\\\s+الساعة)?',\n    'diff_tomorrow' => 'غداً',\n    'diff_tomorrow_regexp' => 'غدا(?:\\\\s+على)?(?:\\\\s+الساعة)?',\n    'diff_before_yesterday' => 'قبل الأمس',\n    'diff_after_tomorrow' => 'بعد غد',\n    'period_recurrences' => implode('|', ['{0}مرة', '{1}مرة', '{2}:count مرتين', ']2,11[:count مرات', ']10,Inf[:count مرة']),\n    'period_interval' => 'كل :interval',\n    'period_start_date' => 'من :date',\n    'period_end_date' => 'إلى :date',\n    'months' => $months,\n    'months_short' => $months,\n    'weekdays' => ['الأحد', 'الاثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعة', 'السبت'],\n    'weekdays_short' => ['أحد', 'اثنين', 'ثلاثاء', 'أربعاء', 'خميس', 'جمعة', 'سبت'],\n    'weekdays_min' => ['ح', 'ن', 'ث', 'ر', 'خ', 'ج', 'س'],\n    'list' => ['، ', ' و '],\n    'first_day_of_week' => 6,\n    'day_of_first_week_of_year' => 1,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd D MMMM YYYY HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[اليوم على الساعة] LT',\n        'nextDay' => '[غدا على الساعة] LT',\n        'nextWeek' => 'dddd [على الساعة] LT',\n        'lastDay' => '[أمس على الساعة] LT',\n        'lastWeek' => 'dddd [على الساعة] LT',\n        'sameElse' => 'L',\n    ],\n    'meridiem' => ['ص', 'م'],\n    'weekend' => [5, 6],\n    'alt_numbers' => ['۰۰', '۰۱', '۰۲', '۰۳', '۰٤', '۰٥', '۰٦', '۰۷', '۰۸', '۰۹', '۱۰', '۱۱', '۱۲', '۱۳', '۱٤', '۱٥', '۱٦', '۱۷', '۱۸', '۱۹', '۲۰', '۲۱', '۲۲', '۲۳', '۲٤', '۲٥', '۲٦', '۲۷', '۲۸', '۲۹', '۳۰', '۳۱', '۳۲', '۳۳', '۳٤', '۳٥', '۳٦', '۳۷', '۳۸', '۳۹', '٤۰', '٤۱', '٤۲', '٤۳', '٤٤', '٤٥', '٤٦', '٤۷', '٤۸', '٤۹', '٥۰', '٥۱', '٥۲', '٥۳', '٥٤', '٥٥', '٥٦', '٥۷', '٥۸', '٥۹', '٦۰', '٦۱', '٦۲', '٦۳', '٦٤', '٦٥', '٦٦', '٦۷', '٦۸', '٦۹', '۷۰', '۷۱', '۷۲', '۷۳', '۷٤', '۷٥', '۷٦', '۷۷', '۷۸', '۷۹', '۸۰', '۸۱', '۸۲', '۸۳', '۸٤', '۸٥', '۸٦', '۸۷', '۸۸', '۸۹', '۹۰', '۹۱', '۹۲', '۹۳', '۹٤', '۹٥', '۹٦', '۹۷', '۹۸', '۹۹'],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ar_SD.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - IBM Globalization Center of Competency, Yamato Software Laboratory    bug-glibc-locales@gnu.org\n * - Abdullah-Alhariri\n */\nreturn array_replace_recursive(require __DIR__.'/ar.php', [\n    'formats' => [\n        'L' => 'DD MMM, YYYY',\n    ],\n    'months' => ['يناير', 'فبراير', 'مارس', 'أبريل', 'مايو', 'يونيو', 'يوليو', 'أغسطس', 'سبتمبر', 'أكتوبر', 'نوفمبر', 'ديسمبر'],\n    'months_short' => ['ينا', 'فبر', 'مار', 'أبر', 'ماي', 'يون', 'يول', 'أغس', 'سبت', 'أكت', 'نوف', 'ديس'],\n    'weekdays' => ['الأحد', 'الاثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعة', 'السبت'],\n    'weekdays_short' => ['ح', 'ن', 'ث', 'ر', 'خ', 'ج', 'س'],\n    'weekdays_min' => ['ح', 'ن', 'ث', 'ر', 'خ', 'ج', 'س'],\n    'first_day_of_week' => 6,\n    'day_of_first_week_of_year' => 1,\n    'alt_numbers' => ['۰۰', '۰۱', '۰۲', '۰۳', '۰٤', '۰٥', '۰٦', '۰۷', '۰۸', '۰۹', '۱۰', '۱۱', '۱۲', '۱۳', '۱٤', '۱٥', '۱٦', '۱۷', '۱۸', '۱۹', '۲۰', '۲۱', '۲۲', '۲۳', '۲٤', '۲٥', '۲٦', '۲۷', '۲۸', '۲۹', '۳۰', '۳۱', '۳۲', '۳۳', '۳٤', '۳٥', '۳٦', '۳۷', '۳۸', '۳۹', '٤۰', '٤۱', '٤۲', '٤۳', '٤٤', '٤٥', '٤٦', '٤۷', '٤۸', '٤۹', '٥۰', '٥۱', '٥۲', '٥۳', '٥٤', '٥٥', '٥٦', '٥۷', '٥۸', '٥۹', '٦۰', '٦۱', '٦۲', '٦۳', '٦٤', '٦٥', '٦٦', '٦۷', '٦۸', '٦۹', '۷۰', '۷۱', '۷۲', '۷۳', '۷٤', '۷٥', '۷٦', '۷۷', '۷۸', '۷۹', '۸۰', '۸۱', '۸۲', '۸۳', '۸٤', '۸٥', '۸٦', '۸۷', '۸۸', '۸۹', '۹۰', '۹۱', '۹۲', '۹۳', '۹٤', '۹٥', '۹٦', '۹۷', '۹۸', '۹۹'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ar_SO.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/ar.php', [\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ar_SS.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - IBM Globalization Center of Competency, Yamato Software Laboratory    bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/ar.php', [\n    'formats' => [\n        'L' => 'DD MMM, YYYY',\n    ],\n    'months' => ['يناير', 'فبراير', 'مارس', 'أبريل', 'مايو', 'يونيو', 'يوليو', 'أغسطس', 'سبتمبر', 'أكتوبر', 'نوفمبر', 'ديسمبر'],\n    'months_short' => ['ينا', 'فبر', 'مار', 'أبر', 'ماي', 'يون', 'يول', 'أغس', 'سبت', 'أكت', 'نوف', 'ديس'],\n    'weekdays' => ['الأحد', 'الاثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعة', 'السبت'],\n    'weekdays_short' => ['ح', 'ن', 'ث', 'ر', 'خ', 'ج', 'س'],\n    'weekdays_min' => ['ح', 'ن', 'ث', 'ر', 'خ', 'ج', 'س'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ar_SY.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - IBM Globalization Center of Competency, Yamato Software Laboratory    bug-glibc-locales@gnu.org\n * - Abdullah-Alhariri\n */\nreturn array_replace_recursive(require __DIR__.'/ar.php', [\n    'formats' => [\n        'L' => 'DD MMM, YYYY',\n    ],\n    'months' => ['كانون الثاني', 'شباط', 'آذار', 'نيسان', 'أيار', 'حزيران', 'تموز', 'آب', 'أيلول', 'تشرين الأول', 'تشرين الثاني', 'كانون الأول'],\n    'months_short' => ['كانون الثاني', 'شباط', 'آذار', 'نيسان', 'أيار', 'حزيران', 'تموز', 'آب', 'أيلول', 'تشرين الأول', 'تشرين الثاني', 'كانون الأول'],\n    'weekdays' => ['الأحد', 'الاثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعة', 'السبت'],\n    'weekdays_short' => ['ح', 'ن', 'ث', 'ر', 'خ', 'ج', 'س'],\n    'weekdays_min' => ['ح', 'ن', 'ث', 'ر', 'خ', 'ج', 'س'],\n    'first_day_of_week' => 6,\n    'day_of_first_week_of_year' => 1,\n    'alt_numbers' => ['۰۰', '۰۱', '۰۲', '۰۳', '۰٤', '۰٥', '۰٦', '۰۷', '۰۸', '۰۹', '۱۰', '۱۱', '۱۲', '۱۳', '۱٤', '۱٥', '۱٦', '۱۷', '۱۸', '۱۹', '۲۰', '۲۱', '۲۲', '۲۳', '۲٤', '۲٥', '۲٦', '۲۷', '۲۸', '۲۹', '۳۰', '۳۱', '۳۲', '۳۳', '۳٤', '۳٥', '۳٦', '۳۷', '۳۸', '۳۹', '٤۰', '٤۱', '٤۲', '٤۳', '٤٤', '٤٥', '٤٦', '٤۷', '٤۸', '٤۹', '٥۰', '٥۱', '٥۲', '٥۳', '٥٤', '٥٥', '٥٦', '٥۷', '٥۸', '٥۹', '٦۰', '٦۱', '٦۲', '٦۳', '٦٤', '٦٥', '٦٦', '٦۷', '٦۸', '٦۹', '۷۰', '۷۱', '۷۲', '۷۳', '۷٤', '۷٥', '۷٦', '۷۷', '۷۸', '۷۹', '۸۰', '۸۱', '۸۲', '۸۳', '۸٤', '۸٥', '۸٦', '۸۷', '۸۸', '۸۹', '۹۰', '۹۱', '۹۲', '۹۳', '۹٤', '۹٥', '۹٦', '۹۷', '۹۸', '۹۹'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ar_Shakl.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Abdellah Chadidi\n * - Atef Ben Ali (atefBB)\n * - Mohamed Sabil (mohamedsabil83)\n */\n// Same for long and short\n$months = [\n    // @TODO add shakl to months\n    'يناير',\n    'فبراير',\n    'مارس',\n    'أبريل',\n    'مايو',\n    'يونيو',\n    'يوليو',\n    'أغسطس',\n    'سبتمبر',\n    'أكتوبر',\n    'نوفمبر',\n    'ديسمبر',\n];\n\nreturn [\n    'year' => implode('|', ['{0}:count سَنَة', '{1}سَنَة', '{2}سَنَتَيْن', ']2,11[:count سَنَوَات', ']10,Inf[:count سَنَة']),\n    'a_year' => implode('|', ['{0}:count سَنَة', '{1}سَنَة', '{2}سَنَتَيْن', ']2,11[:count سَنَوَات', ']10,Inf[:count سَنَة']),\n    'month' => implode('|', ['{0}:count شَهْرَ', '{1}شَهْرَ', '{2}شَهْرَيْن', ']2,11[:count أَشْهُر', ']10,Inf[:count شَهْرَ']),\n    'a_month' => implode('|', ['{0}:count شَهْرَ', '{1}شَهْرَ', '{2}شَهْرَيْن', ']2,11[:count أَشْهُر', ']10,Inf[:count شَهْرَ']),\n    'week' => implode('|', ['{0}:count أُسْبُوع', '{1}أُسْبُوع', '{2}أُسْبُوعَيْن', ']2,11[:count أَسَابِيع', ']10,Inf[:count أُسْبُوع']),\n    'a_week' => implode('|', ['{0}:count أُسْبُوع', '{1}أُسْبُوع', '{2}أُسْبُوعَيْن', ']2,11[:count أَسَابِيع', ']10,Inf[:count أُسْبُوع']),\n    'day' => implode('|', ['{0}:count يَوْم', '{1}يَوْم', '{2}يَوْمَيْن', ']2,11[:count أَيَّام', ']10,Inf[:count يَوْم']),\n    'a_day' => implode('|', ['{0}:count يَوْم', '{1}يَوْم', '{2}يَوْمَيْن', ']2,11[:count أَيَّام', ']10,Inf[:count يَوْم']),\n    'hour' => implode('|', ['{0}:count سَاعَة', '{1}سَاعَة', '{2}سَاعَتَيْن', ']2,11[:count سَاعَات', ']10,Inf[:count سَاعَة']),\n    'a_hour' => implode('|', ['{0}:count سَاعَة', '{1}سَاعَة', '{2}سَاعَتَيْن', ']2,11[:count سَاعَات', ']10,Inf[:count سَاعَة']),\n    'minute' => implode('|', ['{0}:count دَقِيقَة', '{1}دَقِيقَة', '{2}دَقِيقَتَيْن', ']2,11[:count دَقَائِق', ']10,Inf[:count دَقِيقَة']),\n    'a_minute' => implode('|', ['{0}:count دَقِيقَة', '{1}دَقِيقَة', '{2}دَقِيقَتَيْن', ']2,11[:count دَقَائِق', ']10,Inf[:count دَقِيقَة']),\n    'second' => implode('|', ['{0}:count ثَانِيَة', '{1}ثَانِيَة', '{2}ثَانِيَتَيْن', ']2,11[:count ثَوَان', ']10,Inf[:count ثَانِيَة']),\n    'a_second' => implode('|', ['{0}:count ثَانِيَة', '{1}ثَانِيَة', '{2}ثَانِيَتَيْن', ']2,11[:count ثَوَان', ']10,Inf[:count ثَانِيَة']),\n    'ago' => 'مُنْذُ :time',\n    'from_now' => 'مِنَ الْآن :time',\n    'after' => 'بَعْدَ :time',\n    'before' => 'قَبْلَ :time',\n\n    // @TODO add shakl to translations below\n    'diff_now' => 'الآن',\n    'diff_today' => 'اليوم',\n    'diff_today_regexp' => 'اليوم(?:\\\\s+عند)?(?:\\\\s+الساعة)?',\n    'diff_yesterday' => 'أمس',\n    'diff_yesterday_regexp' => 'أمس(?:\\\\s+عند)?(?:\\\\s+الساعة)?',\n    'diff_tomorrow' => 'غداً',\n    'diff_tomorrow_regexp' => 'غدًا(?:\\\\s+عند)?(?:\\\\s+الساعة)?',\n    'diff_before_yesterday' => 'قبل الأمس',\n    'diff_after_tomorrow' => 'بعد غد',\n    'period_recurrences' => implode('|', ['{0}مرة', '{1}مرة', '{2}:count مرتين', ']2,11[:count مرات', ']10,Inf[:count مرة']),\n    'period_interval' => 'كل :interval',\n    'period_start_date' => 'من :date',\n    'period_end_date' => 'إلى :date',\n    'months' => $months,\n    'months_short' => $months,\n    'weekdays' => ['الأحد', 'الاثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعة', 'السبت'],\n    'weekdays_short' => ['أحد', 'اثنين', 'ثلاثاء', 'أربعاء', 'خميس', 'جمعة', 'سبت'],\n    'weekdays_min' => ['ح', 'اث', 'ثل', 'أر', 'خم', 'ج', 'س'],\n    'list' => ['، ', ' و '],\n    'first_day_of_week' => 6,\n    'day_of_first_week_of_year' => 1,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'D/M/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd D MMMM YYYY HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[اليوم عند الساعة] LT',\n        'nextDay' => '[غدًا عند الساعة] LT',\n        'nextWeek' => 'dddd [عند الساعة] LT',\n        'lastDay' => '[أمس عند الساعة] LT',\n        'lastWeek' => 'dddd [عند الساعة] LT',\n        'sameElse' => 'L',\n    ],\n    'meridiem' => ['ص', 'م'],\n    'weekend' => [5, 6],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ar_TD.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/ar.php', [\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ar_TN.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/**\n * Authors:\n * - JD Isaacks\n * - Atef Ben Ali (atefBB)\n * - Mohamed Sabil (mohamedsabil83)\n */\n$months = [\n    'جانفي',\n    'فيفري',\n    'مارس',\n    'أفريل',\n    'ماي',\n    'جوان',\n    'جويلية',\n    'أوت',\n    'سبتمبر',\n    'أكتوبر',\n    'نوفمبر',\n    'ديسمبر',\n];\n\nreturn [\n    'year' => implode('|', ['{0}:count سنة', '{1}سنة', '{2}سنتين', ']2,11[:count سنوات', ']10,Inf[:count سنة']),\n    'a_year' => implode('|', ['{0}:count سنة', '{1}سنة', '{2}سنتين', ']2,11[:count سنوات', ']10,Inf[:count سنة']),\n    'month' => implode('|', ['{0}:count شهر', '{1}شهر', '{2}شهرين', ']2,11[:count أشهر', ']10,Inf[:count شهر']),\n    'a_month' => implode('|', ['{0}:count شهر', '{1}شهر', '{2}شهرين', ']2,11[:count أشهر', ']10,Inf[:count شهر']),\n    'week' => implode('|', ['{0}:count أسبوع', '{1}أسبوع', '{2}أسبوعين', ']2,11[:count أسابيع', ']10,Inf[:count أسبوع']),\n    'a_week' => implode('|', ['{0}:count أسبوع', '{1}أسبوع', '{2}أسبوعين', ']2,11[:count أسابيع', ']10,Inf[:count أسبوع']),\n    'day' => implode('|', ['{0}:count يوم', '{1}يوم', '{2}يومين', ']2,11[:count أيام', ']10,Inf[:count يوم']),\n    'a_day' => implode('|', ['{0}:count يوم', '{1}يوم', '{2}يومين', ']2,11[:count أيام', ']10,Inf[:count يوم']),\n    'hour' => implode('|', ['{0}:count ساعة', '{1}ساعة', '{2}ساعتين', ']2,11[:count ساعات', ']10,Inf[:count ساعة']),\n    'a_hour' => implode('|', ['{0}:count ساعة', '{1}ساعة', '{2}ساعتين', ']2,11[:count ساعات', ']10,Inf[:count ساعة']),\n    'minute' => implode('|', ['{0}:count دقيقة', '{1}دقيقة', '{2}دقيقتين', ']2,11[:count دقائق', ']10,Inf[:count دقيقة']),\n    'a_minute' => implode('|', ['{0}:count دقيقة', '{1}دقيقة', '{2}دقيقتين', ']2,11[:count دقائق', ']10,Inf[:count دقيقة']),\n    'second' => implode('|', ['{0}:count ثانية', '{1}ثانية', '{2}ثانيتين', ']2,11[:count ثواني', ']10,Inf[:count ثانية']),\n    'a_second' => implode('|', ['{0}:count ثانية', '{1}ثانية', '{2}ثانيتين', ']2,11[:count ثواني', ']10,Inf[:count ثانية']),\n    'ago' => 'منذ :time',\n    'from_now' => 'في :time',\n    'after' => 'بعد :time',\n    'before' => 'قبل :time',\n    'diff_now' => 'الآن',\n    'diff_today' => 'اليوم',\n    'diff_today_regexp' => 'اليوم(?:\\\\s+على)?(?:\\\\s+الساعة)?',\n    'diff_yesterday' => 'أمس',\n    'diff_yesterday_regexp' => 'أمس(?:\\\\s+على)?(?:\\\\s+الساعة)?',\n    'diff_tomorrow' => 'غداً',\n    'diff_tomorrow_regexp' => 'غدا(?:\\\\s+على)?(?:\\\\s+الساعة)?',\n    'diff_before_yesterday' => 'قبل الأمس',\n    'diff_after_tomorrow' => 'بعد غد',\n    'period_recurrences' => implode('|', ['{0}مرة', '{1}مرة', '{2}:count مرتين', ']2,11[:count مرات', ']10,Inf[:count مرة']),\n    'period_interval' => 'كل :interval',\n    'period_start_date' => 'من :date',\n    'period_end_date' => 'إلى :date',\n    'months' => $months,\n    'months_short' => $months,\n    'weekdays' => ['الأحد', 'الاثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعة', 'السبت'],\n    'weekdays_short' => ['أحد', 'اثنين', 'ثلاثاء', 'أربعاء', 'خميس', 'جمعة', 'سبت'],\n    'weekdays_min' => ['ح', 'ن', 'ث', 'ر', 'خ', 'ج', 'س'],\n    'list' => ['، ', ' و '],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd D MMMM YYYY HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[اليوم على الساعة] LT',\n        'nextDay' => '[غدا على الساعة] LT',\n        'nextWeek' => 'dddd [على الساعة] LT',\n        'lastDay' => '[أمس على الساعة] LT',\n        'lastWeek' => 'dddd [على الساعة] LT',\n        'sameElse' => 'L',\n    ],\n    'meridiem' => ['ص', 'م'],\n    'weekend' => [5, 6],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ar_YE.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - IBM Globalization Center of Competency, Yamato Software Laboratory    bug-glibc-locales@gnu.org\n * - Abdullah-Alhariri\n */\nreturn array_replace_recursive(require __DIR__.'/ar.php', [\n    'formats' => [\n        'L' => 'DD MMM, YYYY',\n    ],\n    'months' => ['يناير', 'فبراير', 'مارس', 'أبريل', 'مايو', 'يونيو', 'يوليو', 'أغسطس', 'سبتمبر', 'أكتوبر', 'نوفمبر', 'ديسمبر'],\n    'months_short' => ['ينا', 'فبر', 'مار', 'أبر', 'ماي', 'يون', 'يول', 'أغس', 'سبت', 'أكت', 'نوف', 'ديس'],\n    'weekdays' => ['الأحد', 'الاثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعة', 'السبت'],\n    'weekdays_short' => ['ح', 'ن', 'ث', 'ر', 'خ', 'ج', 'س'],\n    'weekdays_min' => ['ح', 'ن', 'ث', 'ر', 'خ', 'ج', 'س'],\n    'day_of_first_week_of_year' => 1,\n    'alt_numbers' => ['۰۰', '۰۱', '۰۲', '۰۳', '۰٤', '۰٥', '۰٦', '۰۷', '۰۸', '۰۹', '۱۰', '۱۱', '۱۲', '۱۳', '۱٤', '۱٥', '۱٦', '۱۷', '۱۸', '۱۹', '۲۰', '۲۱', '۲۲', '۲۳', '۲٤', '۲٥', '۲٦', '۲۷', '۲۸', '۲۹', '۳۰', '۳۱', '۳۲', '۳۳', '۳٤', '۳٥', '۳٦', '۳۷', '۳۸', '۳۹', '٤۰', '٤۱', '٤۲', '٤۳', '٤٤', '٤٥', '٤٦', '٤۷', '٤۸', '٤۹', '٥۰', '٥۱', '٥۲', '٥۳', '٥٤', '٥٥', '٥٦', '٥۷', '٥۸', '٥۹', '٦۰', '٦۱', '٦۲', '٦۳', '٦٤', '٦٥', '٦٦', '٦۷', '٦۸', '٦۹', '۷۰', '۷۱', '۷۲', '۷۳', '۷٤', '۷٥', '۷٦', '۷۷', '۷۸', '۷۹', '۸۰', '۸۱', '۸۲', '۸۳', '۸٤', '۸٥', '۸٦', '۸۷', '۸۸', '۸۹', '۹۰', '۹۱', '۹۲', '۹۳', '۹٤', '۹٥', '۹٦', '۹۷', '۹۸', '۹۹'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/as.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/as_IN.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/as_IN.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Amitakhya Phukan, Red Hat    bug-glibc@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'D-MM-YYYY',\n    ],\n    'months' => ['জানুৱাৰী', 'ফেব্ৰুৱাৰী', 'মাৰ্চ', 'এপ্ৰিল', 'মে', 'জুন', 'জুলাই', 'আগষ্ট', 'ছেপ্তেম্বৰ', 'অক্টোবৰ', 'নৱেম্বৰ', 'ডিচেম্বৰ'],\n    'months_short' => ['জানু', 'ফেব্ৰু', 'মাৰ্চ', 'এপ্ৰিল', 'মে', 'জুন', 'জুলাই', 'আগ', 'সেপ্ট', 'অক্টো', 'নভে', 'ডিসে'],\n    'weekdays' => ['দেওবাৰ', 'সোমবাৰ', 'মঙ্গলবাৰ', 'বুধবাৰ', 'বৃহষ্পতিবাৰ', 'শুক্ৰবাৰ', 'শনিবাৰ'],\n    'weekdays_short' => ['দেও', 'সোম', 'মঙ্গল', 'বুধ', 'বৃহষ্পতি', 'শুক্ৰ', 'শনি'],\n    'weekdays_min' => ['দেও', 'সোম', 'মঙ্গল', 'বুধ', 'বৃহষ্পতি', 'শুক্ৰ', 'শনি'],\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['পূৰ্ব্বাহ্ন', 'অপৰাহ্ন'],\n\n    'year' => ':count বছৰ',\n    'y' => ':count বছৰ',\n    'a_year' => ':count বছৰ',\n\n    'month' => ':count মাহ',\n    'm' => ':count মাহ',\n    'a_month' => ':count মাহ',\n\n    'week' => ':count সপ্তাহ',\n    'w' => ':count সপ্তাহ',\n    'a_week' => ':count সপ্তাহ',\n\n    'day' => ':count বাৰ',\n    'd' => ':count বাৰ',\n    'a_day' => ':count বাৰ',\n\n    'hour' => ':count ঘণ্টা',\n    'h' => ':count ঘণ্টা',\n    'a_hour' => ':count ঘণ্টা',\n\n    'minute' => ':count মিনিট',\n    'min' => ':count মিনিট',\n    'a_minute' => ':count মিনিট',\n\n    'second' => ':count দ্বিতীয়',\n    's' => ':count দ্বিতীয়',\n    'a_second' => ':count দ্বিতীয়',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/asa.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'meridiem' => ['icheheavo', 'ichamthi'],\n    'weekdays' => ['Jumapili', 'Jumatatu', 'Jumanne', 'Jumatano', 'Alhamisi', 'Ijumaa', 'Jumamosi'],\n    'weekdays_short' => ['Jpi', 'Jtt', 'Jnn', 'Jtn', 'Alh', 'Ijm', 'Jmo'],\n    'weekdays_min' => ['Jpi', 'Jtt', 'Jnn', 'Jtn', 'Alh', 'Ijm', 'Jmo'],\n    'months' => ['Januari', 'Februari', 'Machi', 'Aprili', 'Mei', 'Juni', 'Julai', 'Agosti', 'Septemba', 'Oktoba', 'Novemba', 'Desemba'],\n    'months_short' => ['Jan', 'Feb', 'Mac', 'Apr', 'Mei', 'Jun', 'Jul', 'Ago', 'Sep', 'Okt', 'Nov', 'Dec'],\n    'first_day_of_week' => 1,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY HH:mm',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ast.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Jordi Mallach jordi@gnu.org\n * - Adolfo Jayme-Barrientos (fitojb)\n */\nreturn array_replace_recursive(require __DIR__.'/es.php', [\n    'formats' => [\n        'L' => 'DD/MM/YY',\n    ],\n    'months' => ['de xineru', 'de febreru', 'de marzu', 'd’abril', 'de mayu', 'de xunu', 'de xunetu', 'd’agostu', 'de setiembre', 'd’ochobre', 'de payares', 'd’avientu'],\n    'months_short' => ['xin', 'feb', 'mar', 'abr', 'may', 'xun', 'xnt', 'ago', 'set', 'och', 'pay', 'avi'],\n    'weekdays' => ['domingu', 'llunes', 'martes', 'miércoles', 'xueves', 'vienres', 'sábadu'],\n    'weekdays_short' => ['dom', 'llu', 'mar', 'mié', 'xue', 'vie', 'sáb'],\n    'weekdays_min' => ['dom', 'llu', 'mar', 'mié', 'xue', 'vie', 'sáb'],\n\n    'year' => ':count añu|:count años',\n    'y' => ':count añu|:count años',\n    'a_year' => 'un añu|:count años',\n\n    'month' => ':count mes',\n    'm' => ':count mes',\n    'a_month' => 'un mes|:count mes',\n\n    'week' => ':count selmana|:count selmanes',\n    'w' => ':count selmana|:count selmanes',\n    'a_week' => 'una selmana|:count selmanes',\n\n    'day' => ':count día|:count díes',\n    'd' => ':count día|:count díes',\n    'a_day' => 'un día|:count díes',\n\n    'hour' => ':count hora|:count hores',\n    'h' => ':count hora|:count hores',\n    'a_hour' => 'una hora|:count hores',\n\n    'minute' => ':count minutu|:count minutos',\n    'min' => ':count minutu|:count minutos',\n    'a_minute' => 'un minutu|:count minutos',\n\n    'second' => ':count segundu|:count segundos',\n    's' => ':count segundu|:count segundos',\n    'a_second' => 'un segundu|:count segundos',\n\n    'ago' => 'hai :time',\n    'from_now' => 'en :time',\n    'after' => ':time dempués',\n    'before' => ':time enantes',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ast_ES.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/ast.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ayc.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/ayc_PE.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ayc_PE.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - runasimipi.org    libc-alpha@sourceware.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD/MM/YY',\n    ],\n    'months' => ['inïru', 'phiwriru', 'marsu', 'awrila', 'mayu', 'junyu', 'julyu', 'awustu', 'sitimri', 'uktuwri', 'nuwimri', 'risimri'],\n    'months_short' => ['ini', 'phi', 'mar', 'awr', 'may', 'jun', 'jul', 'awu', 'sit', 'ukt', 'nuw', 'ris'],\n    'weekdays' => ['tuminku', 'lunisa', 'martisa', 'mirkulisa', 'juywisa', 'wirnisa', 'sawäru'],\n    'weekdays_short' => ['tum', 'lun', 'mar', 'mir', 'juy', 'wir', 'saw'],\n    'weekdays_min' => ['tum', 'lun', 'mar', 'mir', 'juy', 'wir', 'saw'],\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['VM', 'NM'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/az.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Josh Soref\n * - Kunal Marwaha\n * - François B\n * - JD Isaacks\n * - Orxan\n * - Şəhriyar İmanov\n * - Baran Şengül\n */\nreturn [\n    'year' => ':count il',\n    'a_year' => '{1}bir il|]1,Inf[:count il',\n    'y' => ':count il',\n    'month' => ':count ay',\n    'a_month' => '{1}bir ay|]1,Inf[:count ay',\n    'm' => ':count ay',\n    'week' => ':count həftə',\n    'a_week' => '{1}bir həftə|]1,Inf[:count həftə',\n    'w' => ':count h.',\n    'day' => ':count gün',\n    'a_day' => '{1}bir gün|]1,Inf[:count gün',\n    'd' => ':count g.',\n    'hour' => ':count saat',\n    'a_hour' => '{1}bir saat|]1,Inf[:count saat',\n    'h' => ':count saat',\n    'minute' => ':count d.',\n    'a_minute' => '{1}bir dəqiqə|]1,Inf[:count dəqiqə',\n    'min' => ':count dəqiqə',\n    'second' => ':count san.',\n    'a_second' => '{1}birneçə saniyə|]1,Inf[:count saniyə',\n    's' => ':count saniyə',\n    'ago' => ':time əvvəl',\n    'from_now' => ':time sonra',\n    'after' => ':time sonra',\n    'before' => ':time əvvəl',\n    'diff_now' => 'indi',\n    'diff_today' => 'bugün',\n    'diff_today_regexp' => 'bugün(?:\\\\s+saat)?',\n    'diff_yesterday' => 'dünən',\n    'diff_tomorrow' => 'sabah',\n    'diff_tomorrow_regexp' => 'sabah(?:\\\\s+saat)?',\n    'diff_before_yesterday' => 'srağagün',\n    'diff_after_tomorrow' => 'birisi gün',\n    'period_recurrences' => ':count dəfədən bir',\n    'period_interval' => 'hər :interval',\n    'period_start_date' => ':date tarixindən başlayaraq',\n    'period_end_date' => ':date tarixinədək',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD.MM.YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[bugün saat] LT',\n        'nextDay' => '[sabah saat] LT',\n        'nextWeek' => '[gələn həftə] dddd [saat] LT',\n        'lastDay' => '[dünən] LT',\n        'lastWeek' => '[keçən həftə] dddd [saat] LT',\n        'sameElse' => 'L',\n    ],\n    'ordinal' => function ($number) {\n        if ($number === 0) { // special case for zero\n            return \"$number-ıncı\";\n        }\n\n        static $suffixes = [\n            1 => '-inci',\n            5 => '-inci',\n            8 => '-inci',\n            70 => '-inci',\n            80 => '-inci',\n            2 => '-nci',\n            7 => '-nci',\n            20 => '-nci',\n            50 => '-nci',\n            3 => '-üncü',\n            4 => '-üncü',\n            100 => '-üncü',\n            6 => '-ncı',\n            9 => '-uncu',\n            10 => '-uncu',\n            30 => '-uncu',\n            60 => '-ıncı',\n            90 => '-ıncı',\n        ];\n\n        $lastDigit = $number % 10;\n\n        return $number.($suffixes[$lastDigit] ?? $suffixes[$number % 100 - $lastDigit] ?? $suffixes[$number >= 100 ? 100 : -1] ?? '');\n    },\n    'meridiem' => function ($hour) {\n        if ($hour < 4) {\n            return 'gecə';\n        }\n        if ($hour < 12) {\n            return 'səhər';\n        }\n        if ($hour < 17) {\n            return 'gündüz';\n        }\n\n        return 'axşam';\n    },\n    'months' => ['yanvar', 'fevral', 'mart', 'aprel', 'may', 'iyun', 'iyul', 'avqust', 'sentyabr', 'oktyabr', 'noyabr', 'dekabr'],\n    'months_short' => ['yan', 'fev', 'mar', 'apr', 'may', 'iyn', 'iyl', 'avq', 'sen', 'okt', 'noy', 'dek'],\n    'months_standalone' => ['Yanvar', 'Fevral', 'Mart', 'Aprel', 'May', 'İyun', 'İyul', 'Avqust', 'Sentyabr', 'Oktyabr', 'Noyabr', 'Dekabr'],\n    'weekdays' => ['bazar', 'bazar ertəsi', 'çərşənbə axşamı', 'çərşənbə', 'cümə axşamı', 'cümə', 'şənbə'],\n    'weekdays_short' => ['baz', 'bze', 'çax', 'çər', 'cax', 'cüm', 'şən'],\n    'weekdays_min' => ['bz', 'be', 'ça', 'çə', 'ca', 'cü', 'şə'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n    'list' => [', ', ' və '],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/az_AZ.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Pablo Saratxaga pablo@mandrakesoft.com\n */\nreturn array_replace_recursive(require __DIR__.'/az.php', [\n    'months_short' => ['Yan', 'Fev', 'Mar', 'Apr', 'May', 'İyn', 'İyl', 'Avq', 'Sen', 'Okt', 'Noy', 'Dek'],\n    'weekdays' => ['bazar günü', 'bazar ertəsi', 'çərşənbə axşamı', 'çərşənbə', 'cümə axşamı', 'cümə', 'şənbə'],\n    'weekdays_short' => ['baz', 'ber', 'çax', 'çər', 'cax', 'cüm', 'şnb'],\n    'weekdays_min' => ['baz', 'ber', 'çax', 'çər', 'cax', 'cüm', 'şnb'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/az_Cyrl.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/az.php', [\n    'weekdays' => ['базар', 'базар ертәси', 'чәршәнбә ахшамы', 'чәршәнбә', 'ҹүмә ахшамы', 'ҹүмә', 'шәнбә'],\n    'weekdays_short' => ['Б.', 'Б.Е.', 'Ч.А.', 'Ч.', 'Ҹ.А.', 'Ҹ.', 'Ш.'],\n    'weekdays_min' => ['Б.', 'Б.Е.', 'Ч.А.', 'Ч.', 'Ҹ.А.', 'Ҹ.', 'Ш.'],\n    'months' => ['јанвар', 'феврал', 'март', 'апрел', 'май', 'ијун', 'ијул', 'август', 'сентјабр', 'октјабр', 'нојабр', 'декабр'],\n    'months_short' => ['јан', 'фев', 'мар', 'апр', 'май', 'ијн', 'ијл', 'авг', 'сен', 'окт', 'ној', 'дек'],\n    'months_standalone' => ['Јанвар', 'Феврал', 'Март', 'Апрел', 'Май', 'Ијун', 'Ијул', 'Август', 'Сентјабр', 'Октјабр', 'Нојабр', 'Декабр'],\n    'meridiem' => ['а', 'п'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/az_IR.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Mousa Moradi mousamk@gmail.com\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'OY/OM/OD',\n    ],\n    'months' => ['ژانویه', 'فوریه', 'مارس', 'آوریل', 'مئی', 'ژوئن', 'جولای', 'آقۇست', 'سپتامبر', 'اوْکتوْبر', 'نوْوامبر', 'دسامبر'],\n    'months_short' => ['ژانویه', 'فوریه', 'مارس', 'آوریل', 'مئی', 'ژوئن', 'جولای', 'آقۇست', 'سپتامبر', 'اوْکتوْبر', 'نوْوامبر', 'دسامبر'],\n    'weekdays' => ['یکشنبه', 'دوشنبه', 'سه‌شنبه', 'چارشنبه', 'جۆمعه آخشامی', 'جۆمعه', 'شنبه'],\n    'weekdays_short' => ['یکشنبه', 'دوشنبه', 'سه‌شنبه', 'چارشنبه', 'جۆمعه آخشامی', 'جۆمعه', 'شنبه'],\n    'weekdays_min' => ['یکشنبه', 'دوشنبه', 'سه‌شنبه', 'چارشنبه', 'جۆمعه آخشامی', 'جۆمعه', 'شنبه'],\n    'first_day_of_week' => 6,\n    'alt_numbers' => ['۰۰', '۰۱', '۰۲', '۰۳', '۰۴', '۰۵', '۰۶', '۰۷', '۰۸', '۰۹', '۱۰', '۱۱', '۱۲', '۱۳', '۱۴', '۱۵', '۱۶', '۱۷', '۱۸', '۱۹', '۲۰', '۲۱', '۲۲', '۲۳', '۲۴', '۲۵', '۲۶', '۲۷', '۲۸', '۲۹', '۳۰', '۳۱', '۳۲', '۳۳', '۳۴', '۳۵', '۳۶', '۳۷', '۳۸', '۳۹', '۴۰', '۴۱', '۴۲', '۴۳', '۴۴', '۴۵', '۴۶', '۴۷', '۴۸', '۴۹', '۵۰', '۵۱', '۵۲', '۵۳', '۵۴', '۵۵', '۵۶', '۵۷', '۵۸', '۵۹', '۶۰', '۶۱', '۶۲', '۶۳', '۶۴', '۶۵', '۶۶', '۶۷', '۶۸', '۶۹', '۷۰', '۷۱', '۷۲', '۷۳', '۷۴', '۷۵', '۷۶', '۷۷', '۷۸', '۷۹', '۸۰', '۸۱', '۸۲', '۸۳', '۸۴', '۸۵', '۸۶', '۸۷', '۸۸', '۸۹', '۹۰', '۹۱', '۹۲', '۹۳', '۹۴', '۹۵', '۹۶', '۹۷', '۹۸', '۹۹'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/az_Latn.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/az.php', [\n    'meridiem' => ['a', 'p'],\n    'weekdays' => ['bazar', 'bazar ertəsi', 'çərşənbə axşamı', 'çərşənbə', 'cümə axşamı', 'cümə', 'şənbə'],\n    'weekdays_short' => ['B.', 'B.E.', 'Ç.A.', 'Ç.', 'C.A.', 'C.', 'Ş.'],\n    'weekdays_min' => ['B.', 'B.E.', 'Ç.A.', 'Ç.', 'C.A.', 'C.', 'Ş.'],\n    'months' => ['yanvar', 'fevral', 'mart', 'aprel', 'may', 'iyun', 'iyul', 'avqust', 'sentyabr', 'oktyabr', 'noyabr', 'dekabr'],\n    'months_short' => ['yan', 'fev', 'mar', 'apr', 'may', 'iyn', 'iyl', 'avq', 'sen', 'okt', 'noy', 'dek'],\n    'months_standalone' => ['Yanvar', 'Fevral', 'Mart', 'Aprel', 'May', 'İyun', 'İyul', 'Avqust', 'Sentyabr', 'Oktyabr', 'Noyabr', 'Dekabr'],\n    'first_day_of_week' => 1,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD.MM.YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'D MMMM YYYY, dddd HH:mm',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/bas.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'meridiem' => ['I bikɛ̂glà', 'I ɓugajɔp'],\n    'weekdays' => ['ŋgwà nɔ̂y', 'ŋgwà njaŋgumba', 'ŋgwà ûm', 'ŋgwà ŋgê', 'ŋgwà mbɔk', 'ŋgwà kɔɔ', 'ŋgwà jôn'],\n    'weekdays_short' => ['nɔy', 'nja', 'uum', 'ŋge', 'mbɔ', 'kɔɔ', 'jon'],\n    'weekdays_min' => ['nɔy', 'nja', 'uum', 'ŋge', 'mbɔ', 'kɔɔ', 'jon'],\n    'months' => ['Kɔndɔŋ', 'Màcɛ̂l', 'Màtùmb', 'Màtop', 'M̀puyɛ', 'Hìlòndɛ̀', 'Njèbà', 'Hìkaŋ', 'Dìpɔ̀s', 'Bìòôm', 'Màyɛsèp', 'Lìbuy li ńyèe'],\n    'months_short' => ['kɔn', 'mac', 'mat', 'mto', 'mpu', 'hil', 'nje', 'hik', 'dip', 'bio', 'may', 'liɓ'],\n    'first_day_of_week' => 1,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'D/M/YYYY',\n        'LL' => 'D MMM, YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd D MMMM YYYY HH:mm',\n    ],\n\n    'second' => ':count móndî', // less reliable\n    's' => ':count móndî', // less reliable\n    'a_second' => ':count móndî', // less reliable\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/be.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nuse Carbon\\CarbonInterface;\nuse Symfony\\Component\\Translation\\PluralizationRules;\n\n// @codeCoverageIgnoreStart\nif (class_exists(PluralizationRules::class)) {\n    PluralizationRules::set(static function ($number) {\n        return (($number % 10 == 1) && ($number % 100 != 11)) ? 0 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 10) || ($number % 100 >= 20))) ? 1 : 2);\n    }, 'be');\n}\n// @codeCoverageIgnoreEnd\n\n/*\n * Authors:\n * - Josh Soref\n * - SobakaSlava\n * - François B\n * - Serhan Apaydın\n * - JD Isaacks\n * - AbadonnaAbbys\n * - Siomkin Alexander\n */\nreturn [\n    'year' => ':count год|:count гады|:count гадоў',\n    'a_year' => '{1}год|:count год|:count гады|:count гадоў',\n    'y' => ':count год|:count гады|:count гадоў',\n    'month' => ':count месяц|:count месяцы|:count месяцаў',\n    'a_month' => '{1}месяц|:count месяц|:count месяцы|:count месяцаў',\n    'm' => ':count месяц|:count месяцы|:count месяцаў',\n    'week' => ':count тыдзень|:count тыдні|:count тыдняў',\n    'a_week' => '{1}тыдзень|:count тыдзень|:count тыдні|:count тыдняў',\n    'w' => ':count тыдзень|:count тыдні|:count тыдняў',\n    'day' => ':count дзень|:count дні|:count дзён',\n    'a_day' => '{1}дзень|:count дзень|:count дні|:count дзён',\n    'd' => ':count дн',\n    'hour' => ':count гадзіну|:count гадзіны|:count гадзін',\n    'a_hour' => '{1}гадзіна|:count гадзіна|:count гадзіны|:count гадзін',\n    'h' => ':count гадзіна|:count гадзіны|:count гадзін',\n    'minute' => ':count хвіліна|:count хвіліны|:count хвілін',\n    'a_minute' => '{1}хвіліна|:count хвіліна|:count хвіліны|:count хвілін',\n    'min' => ':count хв',\n    'second' => ':count секунда|:count секунды|:count секунд',\n    'a_second' => '{1}некалькі секунд|:count секунда|:count секунды|:count секунд',\n    's' => ':count сек',\n\n    'hour_ago' => ':count гадзіну|:count гадзіны|:count гадзін',\n    'a_hour_ago' => '{1}гадзіну|:count гадзіну|:count гадзіны|:count гадзін',\n    'h_ago' => ':count гадзіну|:count гадзіны|:count гадзін',\n    'minute_ago' => ':count хвіліну|:count хвіліны|:count хвілін',\n    'a_minute_ago' => '{1}хвіліну|:count хвіліну|:count хвіліны|:count хвілін',\n    'min_ago' => ':count хвіліну|:count хвіліны|:count хвілін',\n    'second_ago' => ':count секунду|:count секунды|:count секунд',\n    'a_second_ago' => '{1}некалькі секунд|:count секунду|:count секунды|:count секунд',\n    's_ago' => ':count секунду|:count секунды|:count секунд',\n\n    'hour_from_now' => ':count гадзіну|:count гадзіны|:count гадзін',\n    'a_hour_from_now' => '{1}гадзіну|:count гадзіну|:count гадзіны|:count гадзін',\n    'h_from_now' => ':count гадзіну|:count гадзіны|:count гадзін',\n    'minute_from_now' => ':count хвіліну|:count хвіліны|:count хвілін',\n    'a_minute_from_now' => '{1}хвіліну|:count хвіліну|:count хвіліны|:count хвілін',\n    'min_from_now' => ':count хвіліну|:count хвіліны|:count хвілін',\n    'second_from_now' => ':count секунду|:count секунды|:count секунд',\n    'a_second_from_now' => '{1}некалькі секунд|:count секунду|:count секунды|:count секунд',\n    's_from_now' => ':count секунду|:count секунды|:count секунд',\n\n    'hour_after' => ':count гадзіну|:count гадзіны|:count гадзін',\n    'a_hour_after' => '{1}гадзіну|:count гадзіну|:count гадзіны|:count гадзін',\n    'h_after' => ':count гадзіну|:count гадзіны|:count гадзін',\n    'minute_after' => ':count хвіліну|:count хвіліны|:count хвілін',\n    'a_minute_after' => '{1}хвіліну|:count хвіліну|:count хвіліны|:count хвілін',\n    'min_after' => ':count хвіліну|:count хвіліны|:count хвілін',\n    'second_after' => ':count секунду|:count секунды|:count секунд',\n    'a_second_after' => '{1}некалькі секунд|:count секунду|:count секунды|:count секунд',\n    's_after' => ':count секунду|:count секунды|:count секунд',\n\n    'hour_before' => ':count гадзіну|:count гадзіны|:count гадзін',\n    'a_hour_before' => '{1}гадзіну|:count гадзіну|:count гадзіны|:count гадзін',\n    'h_before' => ':count гадзіну|:count гадзіны|:count гадзін',\n    'minute_before' => ':count хвіліну|:count хвіліны|:count хвілін',\n    'a_minute_before' => '{1}хвіліну|:count хвіліну|:count хвіліны|:count хвілін',\n    'min_before' => ':count хвіліну|:count хвіліны|:count хвілін',\n    'second_before' => ':count секунду|:count секунды|:count секунд',\n    'a_second_before' => '{1}некалькі секунд|:count секунду|:count секунды|:count секунд',\n    's_before' => ':count секунду|:count секунды|:count секунд',\n\n    'ago' => ':time таму',\n    'from_now' => 'праз :time',\n    'after' => ':time пасля',\n    'before' => ':time да',\n    'diff_now' => 'цяпер',\n    'diff_today' => 'Сёння',\n    'diff_today_regexp' => 'Сёння(?:\\\\s+ў)?',\n    'diff_yesterday' => 'учора',\n    'diff_yesterday_regexp' => 'Учора(?:\\\\s+ў)?',\n    'diff_tomorrow' => 'заўтра',\n    'diff_tomorrow_regexp' => 'Заўтра(?:\\\\s+ў)?',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD.MM.YYYY',\n        'LL' => 'D MMMM YYYY г.',\n        'LLL' => 'D MMMM YYYY г., HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY г., HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[Сёння ў] LT',\n        'nextDay' => '[Заўтра ў] LT',\n        'nextWeek' => '[У] dddd [ў] LT',\n        'lastDay' => '[Учора ў] LT',\n        'lastWeek' => function (CarbonInterface $current) {\n            switch ($current->dayOfWeek) {\n                case 1:\n                case 2:\n                case 4:\n                    return '[У мінулы] dddd [ў] LT';\n                default:\n                    return '[У мінулую] dddd [ў] LT';\n            }\n        },\n        'sameElse' => 'L',\n    ],\n    'ordinal' => function ($number, $period) {\n        switch ($period) {\n            case 'M':\n            case 'd':\n            case 'DDD':\n            case 'w':\n            case 'W':\n                return ($number % 10 === 2 || $number % 10 === 3) && ($number % 100 !== 12 && $number % 100 !== 13) ? $number.'-і' : $number.'-ы';\n            case 'D':\n                return $number.'-га';\n            default:\n                return $number;\n        }\n    },\n    'meridiem' => function ($hour) {\n        if ($hour < 4) {\n            return 'ночы';\n        }\n        if ($hour < 12) {\n            return 'раніцы';\n        }\n        if ($hour < 17) {\n            return 'дня';\n        }\n\n        return 'вечара';\n    },\n    'months' => ['студзеня', 'лютага', 'сакавіка', 'красавіка', 'траўня', 'чэрвеня', 'ліпеня', 'жніўня', 'верасня', 'кастрычніка', 'лістапада', 'снежня'],\n    'months_standalone' => ['студзень', 'люты', 'сакавік', 'красавік', 'травень', 'чэрвень', 'ліпень', 'жнівень', 'верасень', 'кастрычнік', 'лістапад', 'снежань'],\n    'months_short' => ['студ', 'лют', 'сак', 'крас', 'трав', 'чэрв', 'ліп', 'жнів', 'вер', 'каст', 'ліст', 'снеж'],\n    'months_regexp' => '/(DD?o?\\.?(\\[[^\\[\\]]*\\]|\\s)+MMMM?|L{2,4}|l{2,4})/',\n    'weekdays' => ['нядзелю', 'панядзелак', 'аўторак', 'сераду', 'чацвер', 'пятніцу', 'суботу'],\n    'weekdays_standalone' => ['нядзеля', 'панядзелак', 'аўторак', 'серада', 'чацвер', 'пятніца', 'субота'],\n    'weekdays_short' => ['нд', 'пн', 'ат', 'ср', 'чц', 'пт', 'сб'],\n    'weekdays_min' => ['нд', 'пн', 'ат', 'ср', 'чц', 'пт', 'сб'],\n    'weekdays_regexp' => '/\\[ ?[Ууў] ?(?:мінулую|наступную)? ?\\] ?dddd/',\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n    'list' => [', ', ' і '],\n    'months_short_standalone' => ['сту', 'лют', 'сак', 'кра', 'май', 'чэр', 'ліп', 'жні', 'вер', 'кас', 'ліс', 'сне'],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/be_BY.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/be.php', [\n    'months' => ['студзеня', 'лютага', 'сакавіка', 'красавіка', 'мая', 'чэрвеня', 'ліпеня', 'жніўня', 'верасня', 'кастрычніка', 'лістапада', 'снежня'],\n    'months_short' => ['сту', 'лют', 'сак', 'кра', 'мая', 'чэр', 'ліп', 'жні', 'вер', 'кас', 'ліс', 'сне'],\n    'weekdays' => ['Нядзеля', 'Панядзелак', 'Аўторак', 'Серада', 'Чацвер', 'Пятніца', 'Субота'],\n    'weekdays_short' => ['Няд', 'Пан', 'Аўт', 'Срд', 'Чцв', 'Пят', 'Суб'],\n    'weekdays_min' => ['Няд', 'Пан', 'Аўт', 'Срд', 'Чцв', 'Пят', 'Суб'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/be_BY@latin.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD.MM.YYYY',\n    ],\n    'months' => ['studzienia', 'lutaha', 'sakavika', 'krasavika', 'maja', 'červienia', 'lipienia', 'žniŭnia', 'vieraśnia', 'kastryčnika', 'listapada', 'śniežnia'],\n    'months_short' => ['Stu', 'Lut', 'Sak', 'Kra', 'Maj', 'Čer', 'Lip', 'Žni', 'Vie', 'Kas', 'Lis', 'Śni'],\n    'weekdays' => ['Niadziela', 'Paniadziełak', 'Aŭtorak', 'Sierada', 'Čaćvier', 'Piatnica', 'Subota'],\n    'weekdays_short' => ['Nia', 'Pan', 'Aŭt', 'Sie', 'Čać', 'Pia', 'Sub'],\n    'weekdays_min' => ['Nia', 'Pan', 'Aŭt', 'Sie', 'Čać', 'Pia', 'Sub'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/bem.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/bem_ZM.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/bem_ZM.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - ANLoc Martin Benjamin locales@africanlocalization.net\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'MM/DD/YYYY',\n    ],\n    'months' => ['Januari', 'Februari', 'Machi', 'Epreo', 'Mei', 'Juni', 'Julai', 'Ogasti', 'Septemba', 'Oktoba', 'Novemba', 'Disemba'],\n    'months_short' => ['Jan', 'Feb', 'Mac', 'Epr', 'Mei', 'Jun', 'Jul', 'Oga', 'Sep', 'Okt', 'Nov', 'Dis'],\n    'weekdays' => ['Pa Mulungu', 'Palichimo', 'Palichibuli', 'Palichitatu', 'Palichine', 'Palichisano', 'Pachibelushi'],\n    'weekdays_short' => ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],\n    'weekdays_min' => ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['uluchelo', 'akasuba'],\n\n    'year' => 'myaka :count',\n    'y' => 'myaka :count',\n    'a_year' => 'myaka :count',\n\n    'month' => 'myeshi :count',\n    'm' => 'myeshi :count',\n    'a_month' => 'myeshi :count',\n\n    'week' => 'umulungu :count',\n    'w' => 'umulungu :count',\n    'a_week' => 'umulungu :count',\n\n    'day' => 'inshiku :count',\n    'd' => 'inshiku :count',\n    'a_day' => 'inshiku :count',\n\n    'hour' => 'awala :count',\n    'h' => 'awala :count',\n    'a_hour' => 'awala :count',\n\n    'minute' => 'miniti :count',\n    'min' => 'miniti :count',\n    'a_minute' => 'miniti :count',\n\n    'second' => 'sekondi :count',\n    's' => 'sekondi :count',\n    'a_second' => 'sekondi :count',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ber.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/ber_DZ.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ber_DZ.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Pablo Saratxaga pablo@mandrakesoft.com\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD.MM.YYYY',\n    ],\n    'months' => ['yanvar', 'fevral', 'mart', 'aprel', 'may', 'iyun', 'iyul', 'avqust', 'sentyabr', 'oktyabr', 'noyabr', 'dekabr'],\n    'months_short' => ['Yan', 'Fev', 'Mar', 'Apr', 'May', 'İyn', 'İyl', 'Avq', 'Sen', 'Okt', 'Noy', 'Dek'],\n    'weekdays' => ['bazar günü', 'birinci gün', 'ikinci gün', 'üçüncü gün', 'dördüncü gün', 'beşinci gün', 'altıncı gün'],\n    'weekdays_short' => ['baz', 'bir', 'iki', 'üçü', 'dör', 'beş', 'alt'],\n    'weekdays_min' => ['baz', 'bir', 'iki', 'üçü', 'dör', 'beş', 'alt'],\n    'first_day_of_week' => 6,\n    'day_of_first_week_of_year' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ber_MA.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Pablo Saratxaga pablo@mandrakesoft.com\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD.MM.YYYY',\n    ],\n    'months' => ['yanvar', 'fevral', 'mart', 'aprel', 'may', 'iyun', 'iyul', 'avqust', 'sentyabr', 'oktyabr', 'noyabr', 'dekabr'],\n    'months_short' => ['Yan', 'Fev', 'Mar', 'Apr', 'May', 'İyn', 'İyl', 'Avq', 'Sen', 'Okt', 'Noy', 'Dek'],\n    'weekdays' => ['bazar günü', 'birinci gün', 'ikinci gün', 'üçüncü gün', 'dördüncü gün', 'beşinci gün', 'altıncı gün'],\n    'weekdays_short' => ['baz', 'bir', 'iki', 'üçü', 'dör', 'beş', 'alt'],\n    'weekdays_min' => ['baz', 'bir', 'iki', 'üçü', 'dör', 'beş', 'alt'],\n    'first_day_of_week' => 6,\n    'day_of_first_week_of_year' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/bez.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'meridiem' => ['pamilau', 'pamunyi'],\n    'weekdays' => ['pa mulungu', 'pa shahuviluha', 'pa hivili', 'pa hidatu', 'pa hitayi', 'pa hihanu', 'pa shahulembela'],\n    'weekdays_short' => ['Mul', 'Vil', 'Hiv', 'Hid', 'Hit', 'Hih', 'Lem'],\n    'weekdays_min' => ['Mul', 'Vil', 'Hiv', 'Hid', 'Hit', 'Hih', 'Lem'],\n    'months' => ['pa mwedzi gwa hutala', 'pa mwedzi gwa wuvili', 'pa mwedzi gwa wudatu', 'pa mwedzi gwa wutai', 'pa mwedzi gwa wuhanu', 'pa mwedzi gwa sita', 'pa mwedzi gwa saba', 'pa mwedzi gwa nane', 'pa mwedzi gwa tisa', 'pa mwedzi gwa kumi', 'pa mwedzi gwa kumi na moja', 'pa mwedzi gwa kumi na mbili'],\n    'months_short' => ['Hut', 'Vil', 'Dat', 'Tai', 'Han', 'Sit', 'Sab', 'Nan', 'Tis', 'Kum', 'Kmj', 'Kmb'],\n    'first_day_of_week' => 1,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY HH:mm',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/bg.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Josh Soref\n * - François B\n * - Serhan Apaydın\n * - JD Isaacks\n * - Glavić\n */\n\nuse Carbon\\CarbonInterface;\n\nreturn [\n    'year' => ':count година|:count години',\n    'a_year' => 'година|:count години',\n    'y' => ':count година|:count години',\n    'month' => ':count месец|:count месеца',\n    'a_month' => 'месец|:count месеца',\n    'm' => ':count месец|:count месеца',\n    'week' => ':count седмица|:count седмици',\n    'a_week' => 'седмица|:count седмици',\n    'w' => ':count седмица|:count седмици',\n    'day' => ':count ден|:count дни',\n    'a_day' => 'ден|:count дни',\n    'd' => ':count ден|:count дни',\n    'hour' => ':count час|:count часа',\n    'a_hour' => 'час|:count часа',\n    'h' => ':count час|:count часа',\n    'minute' => ':count минута|:count минути',\n    'a_minute' => 'минута|:count минути',\n    'min' => ':count минута|:count минути',\n    'second' => ':count секунда|:count секунди',\n    'a_second' => 'няколко секунди|:count секунди',\n    's' => ':count секунда|:count секунди',\n    'ago' => 'преди :time',\n    'from_now' => 'след :time',\n    'after' => 'след :time',\n    'before' => 'преди :time',\n    'diff_now' => 'сега',\n    'diff_today' => 'Днес',\n    'diff_today_regexp' => 'Днес(?:\\\\s+в)?',\n    'diff_yesterday' => 'вчера',\n    'diff_yesterday_regexp' => 'Вчера(?:\\\\s+в)?',\n    'diff_tomorrow' => 'утре',\n    'diff_tomorrow_regexp' => 'Утре(?:\\\\s+в)?',\n    'formats' => [\n        'LT' => 'H:mm',\n        'LTS' => 'H:mm:ss',\n        'L' => 'D.MM.YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY H:mm',\n        'LLLL' => 'dddd, D MMMM YYYY H:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[Днес в] LT',\n        'nextDay' => '[Утре в] LT',\n        'nextWeek' => 'dddd [в] LT',\n        'lastDay' => '[Вчера в] LT',\n        'lastWeek' => function (CarbonInterface $current) {\n            switch ($current->dayOfWeek) {\n                case 0:\n                case 3:\n                case 6:\n                    return '[В изминалата] dddd [в] LT';\n                default:\n                    return '[В изминалия] dddd [в] LT';\n            }\n        },\n        'sameElse' => 'L',\n    ],\n    'ordinal' => function ($number) {\n        $lastDigit = $number % 10;\n        $last2Digits = $number % 100;\n        if ($number === 0) {\n            return \"$number-ев\";\n        }\n        if ($last2Digits === 0) {\n            return \"$number-ен\";\n        }\n        if ($last2Digits > 10 && $last2Digits < 20) {\n            return \"$number-ти\";\n        }\n        if ($lastDigit === 1) {\n            return \"$number-ви\";\n        }\n        if ($lastDigit === 2) {\n            return \"$number-ри\";\n        }\n        if ($lastDigit === 7 || $lastDigit === 8) {\n            return \"$number-ми\";\n        }\n\n        return \"$number-ти\";\n    },\n    'months' => ['януари', 'февруари', 'март', 'април', 'май', 'юни', 'юли', 'август', 'септември', 'октомври', 'ноември', 'декември'],\n    'months_short' => ['яну', 'фев', 'мар', 'апр', 'май', 'юни', 'юли', 'авг', 'сеп', 'окт', 'ное', 'дек'],\n    'weekdays' => ['неделя', 'понеделник', 'вторник', 'сряда', 'четвъртък', 'петък', 'събота'],\n    'weekdays_short' => ['нед', 'пон', 'вто', 'сря', 'чет', 'пет', 'съб'],\n    'weekdays_min' => ['нд', 'пн', 'вт', 'ср', 'чт', 'пт', 'сб'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n    'list' => [', ', ' и '],\n    'meridiem' => ['преди обяд', 'следобед'],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/bg_BG.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/bg.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/bhb.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/bhb_IN.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/bhb_IN.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Samsung Electronics Co., Ltd.    alexey.merzlyakov@samsung.com\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'D/M/YY',\n    ],\n    'months' => ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],\n    'months_short' => ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],\n    'weekdays' => ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],\n    'weekdays_short' => ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],\n    'weekdays_min' => ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],\n    'day_of_first_week_of_year' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/bho.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/bho_IN.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/bho_IN.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - bhashaghar@googlegroups.com\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'D/M/YY',\n    ],\n    'months' => ['जनवरी', 'फरवरी', 'मार्च', 'अप्रैल', 'मई', 'जून', 'जुलाई', 'अगस्त', 'सितम्बर', 'अक्टूबर', 'नवम्बर', 'दिसम्बर\"'],\n    'months_short' => ['जनवरी', 'फरवरी', 'मार्च', 'अप्रैल', 'मई', 'जून', 'जुलाई', 'अगस्त', 'सितम्बर', 'अक्टूबर', 'नवम्बर', 'दिसम्बर\"'],\n    'weekdays' => ['रविवार', 'सोमवार', 'मंगलवार', 'बुधवार', 'गुरुवार', 'शुक्रवार', 'शनिवार'],\n    'weekdays_short' => ['रवि', 'सोम', 'मंगल', 'बुध', 'गुरु', 'शुक्र', 'शनि'],\n    'weekdays_min' => ['रवि', 'सोम', 'मंगल', 'बुध', 'गुरु', 'शुक्र', 'शनि'],\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['पूर्वाह्न', 'अपराह्न'],\n\n    'hour' => ':count मौसम',\n    'h' => ':count मौसम',\n    'a_hour' => ':count मौसम',\n\n    'minute' => ':count कला',\n    'min' => ':count कला',\n    'a_minute' => ':count कला',\n\n    'second' => ':count सोमार',\n    's' => ':count सोमार',\n    'a_second' => ':count सोमार',\n\n    'year' => ':count साल',\n    'y' => ':count साल',\n    'a_year' => ':count साल',\n\n    'month' => ':count महिना',\n    'm' => ':count महिना',\n    'a_month' => ':count महिना',\n\n    'week' => ':count सप्ताह',\n    'w' => ':count सप्ताह',\n    'a_week' => ':count सप्ताह',\n\n    'day' => ':count दिन',\n    'd' => ':count दिन',\n    'a_day' => ':count दिन',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/bi.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/bi_VU.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/bi_VU.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Samsung Electronics Co., Ltd.    akhilesh.k@samsung.com & maninder1.s@samsung.com\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'dddd DD MMM YYYY',\n    ],\n    'months' => ['jenuware', 'febwari', 'maj', 'epril', 'mei', 'jun', 'julae', 'ogis', 'septemba', 'oktoba', 'novemba', 'disemba'],\n    'months_short' => ['jen', 'feb', 'maj', 'epr', 'mei', 'jun', 'jul', 'ogi', 'sep', 'okt', 'nov', 'dis'],\n    'weekdays' => ['sande', 'mande', 'maj', 'wota', 'fraede', 'sarede'],\n    'weekdays_short' => ['san', 'man', 'maj', 'wot', 'fra', 'sar'],\n    'weekdays_min' => ['san', 'man', 'maj', 'wot', 'fra', 'sar'],\n\n    'year' => ':count seven', // less reliable\n    'y' => ':count seven', // less reliable\n    'a_year' => ':count seven', // less reliable\n\n    'month' => ':count mi', // less reliable\n    'm' => ':count mi', // less reliable\n    'a_month' => ':count mi', // less reliable\n\n    'week' => ':count sarede', // less reliable\n    'w' => ':count sarede', // less reliable\n    'a_week' => ':count sarede', // less reliable\n\n    'day' => ':count betde', // less reliable\n    'd' => ':count betde', // less reliable\n    'a_day' => ':count betde', // less reliable\n\n    'hour' => ':count klok', // less reliable\n    'h' => ':count klok', // less reliable\n    'a_hour' => ':count klok', // less reliable\n\n    'minute' => ':count smol', // less reliable\n    'min' => ':count smol', // less reliable\n    'a_minute' => ':count smol', // less reliable\n\n    'second' => ':count tu', // less reliable\n    's' => ':count tu', // less reliable\n    'a_second' => ':count tu', // less reliable\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/bm.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Estelle Comment\n */\nreturn [\n    'year' => 'san :count',\n    'a_year' => '{1}san kelen|san :count',\n    'y' => 'san :count',\n    'month' => 'kalo :count',\n    'a_month' => '{1}kalo kelen|kalo :count',\n    'm' => 'k. :count',\n    'week' => 'dɔgɔkun :count',\n    'a_week' => 'dɔgɔkun kelen',\n    'w' => 'd. :count',\n    'day' => 'tile :count',\n    'd' => 't. :count',\n    'a_day' => '{1}tile kelen|tile :count',\n    'hour' => 'lɛrɛ :count',\n    'a_hour' => '{1}lɛrɛ kelen|lɛrɛ :count',\n    'h' => 'l. :count',\n    'minute' => 'miniti :count',\n    'a_minute' => '{1}miniti kelen|miniti :count',\n    'min' => 'm. :count',\n    'second' => 'sekondi :count',\n    'a_second' => '{1}sanga dama dama|sekondi :count',\n    's' => 'sek. :count',\n    'ago' => 'a bɛ :time bɔ',\n    'from_now' => ':time kɔnɔ',\n    'diff_today' => 'Bi',\n    'diff_yesterday' => 'Kunu',\n    'diff_yesterday_regexp' => 'Kunu(?:\\\\s+lɛrɛ)?',\n    'diff_tomorrow' => 'Sini',\n    'diff_tomorrow_regexp' => 'Sini(?:\\\\s+lɛrɛ)?',\n    'diff_today_regexp' => 'Bi(?:\\\\s+lɛrɛ)?',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'MMMM [tile] D [san] YYYY',\n        'LLL' => 'MMMM [tile] D [san] YYYY [lɛrɛ] HH:mm',\n        'LLLL' => 'dddd MMMM [tile] D [san] YYYY [lɛrɛ] HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[Bi lɛrɛ] LT',\n        'nextDay' => '[Sini lɛrɛ] LT',\n        'nextWeek' => 'dddd [don lɛrɛ] LT',\n        'lastDay' => '[Kunu lɛrɛ] LT',\n        'lastWeek' => 'dddd [tɛmɛnen lɛrɛ] LT',\n        'sameElse' => 'L',\n    ],\n    'months' => ['Zanwuyekalo', 'Fewuruyekalo', 'Marisikalo', 'Awirilikalo', 'Mɛkalo', 'Zuwɛnkalo', 'Zuluyekalo', 'Utikalo', 'Sɛtanburukalo', 'ɔkutɔburukalo', 'Nowanburukalo', 'Desanburukalo'],\n    'months_short' => ['Zan', 'Few', 'Mar', 'Awi', 'Mɛ', 'Zuw', 'Zul', 'Uti', 'Sɛt', 'ɔku', 'Now', 'Des'],\n    'weekdays' => ['Kari', 'Ntɛnɛn', 'Tarata', 'Araba', 'Alamisa', 'Juma', 'Sibiri'],\n    'weekdays_short' => ['Kar', 'Ntɛ', 'Tar', 'Ara', 'Ala', 'Jum', 'Sib'],\n    'weekdays_min' => ['Ka', 'Nt', 'Ta', 'Ar', 'Al', 'Ju', 'Si'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n    'list' => [', ', ' ni '],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/bn.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Josh Soref\n * - Shakib Hossain\n * - Raju\n * - Aniruddha Adhikary\n * - JD Isaacks\n * - Saiful Islam\n * - Faisal Islam\n */\nreturn [\n    'year' => ':count বছর',\n    'a_year' => 'এক বছর|:count বছর',\n    'y' => '১ বছর|:count বছর',\n    'month' => ':count মাস',\n    'a_month' => 'এক মাস|:count মাস',\n    'm' => '১ মাস|:count মাস',\n    'week' => ':count সপ্তাহ',\n    'a_week' => '১ সপ্তাহ|:count সপ্তাহ',\n    'w' => '১ সপ্তাহ|:count সপ্তাহ',\n    'day' => ':count দিন',\n    'a_day' => 'এক দিন|:count দিন',\n    'd' => '১ দিন|:count দিন',\n    'hour' => ':count ঘন্টা',\n    'a_hour' => 'এক ঘন্টা|:count ঘন্টা',\n    'h' => '১ ঘন্টা|:count ঘন্টা',\n    'minute' => ':count মিনিট',\n    'a_minute' => 'এক মিনিট|:count মিনিট',\n    'min' => '১ মিনিট|:count মিনিট',\n    'second' => ':count সেকেন্ড',\n    'a_second' => 'কয়েক সেকেন্ড|:count সেকেন্ড',\n    's' => '১ সেকেন্ড|:count সেকেন্ড',\n    'ago' => ':time আগে',\n    'from_now' => ':time পরে',\n    'after' => ':time পরে',\n    'before' => ':time আগে',\n    'diff_now' => 'এখন',\n    'diff_today' => 'আজ',\n    'diff_yesterday' => 'গতকাল',\n    'diff_tomorrow' => 'আগামীকাল',\n    'period_recurrences' => ':count বার|:count বার',\n    'period_interval' => 'প্রতি :interval',\n    'period_start_date' => ':date থেকে',\n    'period_end_date' => ':date পর্যন্ত',\n    'formats' => [\n        'LT' => 'A Oh:Om সময়',\n        'LTS' => 'A Oh:Om:Os সময়',\n        'L' => 'OD/OM/OY',\n        'LL' => 'OD MMMM OY',\n        'LLL' => 'OD MMMM OY, A Oh:Om সময়',\n        'LLLL' => 'dddd, OD MMMM OY, A Oh:Om সময়',\n    ],\n    'calendar' => [\n        'sameDay' => '[আজ] LT',\n        'nextDay' => '[আগামীকাল] LT',\n        'nextWeek' => 'dddd, LT',\n        'lastDay' => '[গতকাল] LT',\n        'lastWeek' => '[গত] dddd, LT',\n        'sameElse' => 'L',\n    ],\n    'meridiem' => function ($hour) {\n        if ($hour < 4) {\n            return 'রাত';\n        }\n        if ($hour < 10) {\n            return 'সকাল';\n        }\n        if ($hour < 17) {\n            return 'দুপুর';\n        }\n        if ($hour < 20) {\n            return 'বিকাল';\n        }\n\n        return 'রাত';\n    },\n    'months' => ['জানুয়ারী', 'ফেব্রুয়ারি', 'মার্চ', 'এপ্রিল', 'মে', 'জুন', 'জুলাই', 'আগস্ট', 'সেপ্টেম্বর', 'অক্টোবর', 'নভেম্বর', 'ডিসেম্বর'],\n    'months_short' => ['জানু', 'ফেব', 'মার্চ', 'এপ্র', 'মে', 'জুন', 'জুল', 'আগ', 'সেপ্ট', 'অক্টো', 'নভে', 'ডিসে'],\n    'weekdays' => ['রবিবার', 'সোমবার', 'মঙ্গলবার', 'বুধবার', 'বৃহস্পতিবার', 'শুক্রবার', 'শনিবার'],\n    'weekdays_short' => ['রবি', 'সোম', 'মঙ্গল', 'বুধ', 'বৃহস্পতি', 'শুক্র', 'শনি'],\n    'weekdays_min' => ['রবি', 'সোম', 'মঙ্গ', 'বুধ', 'বৃহঃ', 'শুক্র', 'শনি'],\n    'list' => [', ', ' এবং '],\n    'first_day_of_week' => 0,\n    'day_of_first_week_of_year' => 1,\n    'weekdays_standalone' => ['রবিবার', 'সোমবার', 'মঙ্গলবার', 'বুধবার', 'বৃহষ্পতিবার', 'শুক্রবার', 'শনিবার'],\n    'weekdays_min_standalone' => ['রঃ', 'সোঃ', 'মঃ', 'বুঃ', 'বৃঃ', 'শুঃ', 'শনি'],\n    'months_short_standalone' => ['জানুয়ারী', 'ফেব্রুয়ারী', 'মার্চ', 'এপ্রিল', 'মে', 'জুন', 'জুলাই', 'আগস্ট', 'সেপ্টেম্বর', 'অক্টোবর', 'নভেম্বর', 'ডিসেম্বর'],\n    'alt_numbers' => ['০', '১', '২', '৩', '৪', '৫', '৬', '৭', '৮', '৯'],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/bn_BD.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Ankur Group, Taneem Ahmed, Jamil Ahmed\n */\nreturn array_replace_recursive(require __DIR__.'/bn.php', [\n    'formats' => [\n        'L' => 'D/M/YY',\n    ],\n    'months' => ['জানুয়ারী', 'ফেব্রুয়ারী', 'মার্চ', 'এপ্রিল', 'মে', 'জুন', 'জুলাই', 'আগস্ট', 'সেপ্টেম্বর', 'অক্টোবর', 'নভেম্বর', 'ডিসেম্বর'],\n    'months_short' => ['জানু', 'ফেব', 'মার্চ', 'এপ্রিল', 'মে', 'জুন', 'জুলাই', 'আগস্ট', 'সেপ্টেম্বর', 'অক্টোবর', 'নভেম্বর', 'ডিসেম্বর'],\n    'weekdays' => ['রবিবার', 'সোমবার', 'মঙ্গলবার', 'বুধবার', 'বৃহস্পতিবার', 'শুক্রবার', 'শনিবার'],\n    'weekdays_short' => ['রবি', 'সোম', 'মঙ্গল', 'বুধ', 'বৃহঃ', 'শুক্র', 'শনি'],\n    'weekdays_min' => ['রবি', 'সোম', 'মঙ্গল', 'বুধ', 'বৃহঃ', 'শুক্র', 'শনি'],\n    'first_day_of_week' => 5,\n    'day_of_first_week_of_year' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/bn_IN.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - IBM Globalization Center of Competency, Yamato Software Laboratory    bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/bn.php', [\n    'formats' => [\n        'L' => 'D/M/YY',\n    ],\n    'months' => ['জানুয়ারী', 'ফেব্রুয়ারী', 'মার্চ', 'এপ্রিল', 'মে', 'জুন', 'জুলাই', 'আগস্ট', 'সেপ্টেম্বর', 'অক্টোবর', 'নভেম্বর', 'ডিসেম্বর'],\n    'months_short' => ['জানু', 'ফেব', 'মার্চ', 'এপ্রিল', 'মে', 'জুন', 'জুলাই', 'আগস্ট', 'সেপ্টেম্বর', 'অক্টোবর', 'নভেম্বর', 'ডিসেম্বর'],\n    'weekdays' => ['রবিবার', 'সোমবার', 'মঙ্গলবার', 'বুধবার', 'বৃহস্পতিবার', 'শুক্রবার', 'শনিবার'],\n    'weekdays_short' => ['রবি', 'সোম', 'মঙ্গল', 'বুধ', 'বৃহস্পতি', 'শুক্র', 'শনি'],\n    'weekdays_min' => ['রবি', 'সোম', 'মঙ্গল', 'বুধ', 'বৃহস্পতি', 'শুক্র', 'শনি'],\n    'day_of_first_week_of_year' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/bo.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Josh Soref\n * - JD Isaacks\n */\nreturn [\n    'year' => '{1}ལོ་གཅིག|]1,Inf[:count ལོ',\n    'month' => '{1}ཟླ་བ་གཅིག|]1,Inf[:count ཟླ་བ',\n    'week' => ':count བདུན་ཕྲག',\n    'day' => '{1}ཉིན་གཅིག|]1,Inf[:count ཉིན་',\n    'hour' => '{1}ཆུ་ཚོད་གཅིག|]1,Inf[:count ཆུ་ཚོད',\n    'minute' => '{1}སྐར་མ་གཅིག|]1,Inf[:count སྐར་མ',\n    'second' => '{1}ལམ་སང|]1,Inf[:count སྐར་ཆ།',\n    'ago' => ':time སྔན་ལ',\n    'from_now' => ':time ལ་',\n    'diff_yesterday' => 'ཁ་སང',\n    'diff_today' => 'དི་རིང',\n    'diff_tomorrow' => 'སང་ཉིན',\n    'formats' => [\n        'LT' => 'A h:mm',\n        'LTS' => 'A h:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY, A h:mm',\n        'LLLL' => 'dddd, D MMMM YYYY, A h:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[དི་རིང] LT',\n        'nextDay' => '[སང་ཉིན] LT',\n        'nextWeek' => '[བདུན་ཕྲག་རྗེས་མ], LT',\n        'lastDay' => '[ཁ་སང] LT',\n        'lastWeek' => '[བདུན་ཕྲག་མཐའ་མ] dddd, LT',\n        'sameElse' => 'L',\n    ],\n    'meridiem' => function ($hour) {\n        if ($hour < 4) {\n            return 'མཚན་མོ';\n        }\n        if ($hour < 10) {\n            return 'ཞོགས་ཀས';\n        }\n        if ($hour < 17) {\n            return 'ཉིན་གུང';\n        }\n        if ($hour < 20) {\n            return 'དགོང་དག';\n        }\n\n        return 'མཚན་མོ';\n    },\n    'months' => ['ཟླ་བ་དང་པོ', 'ཟླ་བ་གཉིས་པ', 'ཟླ་བ་གསུམ་པ', 'ཟླ་བ་བཞི་པ', 'ཟླ་བ་ལྔ་པ', 'ཟླ་བ་དྲུག་པ', 'ཟླ་བ་བདུན་པ', 'ཟླ་བ་བརྒྱད་པ', 'ཟླ་བ་དགུ་པ', 'ཟླ་བ་བཅུ་པ', 'ཟླ་བ་བཅུ་གཅིག་པ', 'ཟླ་བ་བཅུ་གཉིས་པ'],\n    'months_short' => ['ཟླ་བ་དང་པོ', 'ཟླ་བ་གཉིས་པ', 'ཟླ་བ་གསུམ་པ', 'ཟླ་བ་བཞི་པ', 'ཟླ་བ་ལྔ་པ', 'ཟླ་བ་དྲུག་པ', 'ཟླ་བ་བདུན་པ', 'ཟླ་བ་བརྒྱད་པ', 'ཟླ་བ་དགུ་པ', 'ཟླ་བ་བཅུ་པ', 'ཟླ་བ་བཅུ་གཅིག་པ', 'ཟླ་བ་བཅུ་གཉིས་པ'],\n    'weekdays' => ['གཟའ་ཉི་མ་', 'གཟའ་ཟླ་བ་', 'གཟའ་མིག་དམར་', 'གཟའ་ལྷག་པ་', 'གཟའ་ཕུར་བུ', 'གཟའ་པ་སངས་', 'གཟའ་སྤེན་པ་'],\n    'weekdays_short' => ['ཉི་མ་', 'ཟླ་བ་', 'མིག་དམར་', 'ལྷག་པ་', 'ཕུར་བུ', 'པ་སངས་', 'སྤེན་པ་'],\n    'weekdays_min' => ['ཉི་མ་', 'ཟླ་བ་', 'མིག་དམར་', 'ལྷག་པ་', 'ཕུར་བུ', 'པ་སངས་', 'སྤེན་པ་'],\n    'list' => [', ', ' ཨནད་ '],\n    'first_day_of_week' => 0,\n    'day_of_first_week_of_year' => 1,\n    'months_standalone' => ['ཟླ་བ་དང་པོ་', 'ཟླ་བ་གཉིས་པ་', 'ཟླ་བ་གསུམ་པ་', 'ཟླ་བ་བཞི་པ་', 'ཟླ་བ་ལྔ་པ་', 'ཟླ་བ་དྲུག་པ་', 'ཟླ་བ་བདུན་པ་', 'ཟླ་བ་བརྒྱད་པ་', 'ཟླ་བ་དགུ་པ་', 'ཟླ་བ་བཅུ་པ་', 'ཟླ་བ་བཅུ་གཅིག་པ་', 'ཟླ་བ་བཅུ་གཉིས་པ་'],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/bo_CN.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/bo.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/bo_IN.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/bo.php', [\n    'meridiem' => ['སྔ་དྲོ་', 'ཕྱི་དྲོ་'],\n    'weekdays' => ['གཟའ་ཉི་མ་', 'གཟའ་ཟླ་བ་', 'གཟའ་མིག་དམར་', 'གཟའ་ལྷག་པ་', 'གཟའ་ཕུར་བུ་', 'གཟའ་པ་སངས་', 'གཟའ་སྤེན་པ་'],\n    'weekdays_short' => ['ཉི་མ་', 'ཟླ་བ་', 'མིག་དམར་', 'ལྷག་པ་', 'ཕུར་བུ་', 'པ་སངས་', 'སྤེན་པ་'],\n    'weekdays_min' => ['ཉི་མ་', 'ཟླ་བ་', 'མིག་དམར་', 'ལྷག་པ་', 'ཕུར་བུ་', 'པ་སངས་', 'སྤེན་པ་'],\n    'months' => ['ཟླ་བ་དང་པོ', 'ཟླ་བ་གཉིས་པ', 'ཟླ་བ་གསུམ་པ', 'ཟླ་བ་བཞི་པ', 'ཟླ་བ་ལྔ་པ', 'ཟླ་བ་དྲུག་པ', 'ཟླ་བ་བདུན་པ', 'ཟླ་བ་བརྒྱད་པ', 'ཟླ་བ་དགུ་པ', 'ཟླ་བ་བཅུ་པ', 'ཟླ་བ་བཅུ་གཅིག་པ', 'ཟླ་བ་བཅུ་གཉིས་པ'],\n    'months_short' => ['ཟླ་༡', 'ཟླ་༢', 'ཟླ་༣', 'ཟླ་༤', 'ཟླ་༥', 'ཟླ་༦', 'ཟླ་༧', 'ཟླ་༨', 'ཟླ་༩', 'ཟླ་༡༠', 'ཟླ་༡༡', 'ཟླ་༡༢'],\n    'months_standalone' => ['ཟླ་བ་དང་པོ་', 'ཟླ་བ་གཉིས་པ་', 'ཟླ་བ་གསུམ་པ་', 'ཟླ་བ་བཞི་པ་', 'ཟླ་བ་ལྔ་པ་', 'ཟླ་བ་དྲུག་པ་', 'ཟླ་བ་བདུན་པ་', 'ཟླ་བ་བརྒྱད་པ་', 'ཟླ་བ་དགུ་པ་', 'ཟླ་བ་བཅུ་པ་', 'ཟླ་བ་བཅུ་གཅིག་པ་', 'ཟླ་བ་བཅུ་གཉིས་པ་'],\n    'weekend' => [0, 0],\n    'formats' => [\n        'LT' => 'h:mm a',\n        'LTS' => 'h:mm:ss a',\n        'L' => 'YYYY-MM-DD',\n        'LL' => 'YYYY ལོའི་MMMཚེས་D',\n        'LLL' => 'སྤྱི་ལོ་YYYY MMMMའི་ཚེས་D h:mm a',\n        'LLLL' => 'YYYY MMMMའི་ཚེས་D, dddd h:mm a',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/br.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - François B\n * - Serhan Apaydın\n * - JD Isaacks\n */\nreturn [\n    'year' => '{1}:count bloaz|{3,4,5,9}:count bloaz|[0,Inf[:count vloaz',\n    'a_year' => '{1}ur bloaz|{3,4,5,9}:count bloaz|[0,Inf[:count vloaz',\n    'month' => '{1}:count miz|{2}:count viz|[0,Inf[:count miz',\n    'a_month' => '{1}ur miz|{2}:count viz|[0,Inf[:count miz',\n    'week' => ':count sizhun',\n    'a_week' => '{1}ur sizhun|:count sizhun',\n    'day' => '{1}:count devezh|{2}:count zevezh|[0,Inf[:count devezh',\n    'a_day' => '{1}un devezh|{2}:count zevezh|[0,Inf[:count devezh',\n    'hour' => ':count eur',\n    'a_hour' => '{1}un eur|:count eur',\n    'minute' => '{1}:count vunutenn|{2}:count vunutenn|[0,Inf[:count munutenn',\n    'a_minute' => '{1}ur vunutenn|{2}:count vunutenn|[0,Inf[:count munutenn',\n    'second' => ':count eilenn',\n    'a_second' => '{1}un nebeud segondennoù|[0,Inf[:count eilenn',\n    'ago' => ':time \\'zo',\n    'from_now' => 'a-benn :time',\n    'diff_now' => 'bremañ',\n    'diff_today' => 'Hiziv',\n    'diff_today_regexp' => 'Hiziv(?:\\\\s+da)?',\n    'diff_yesterday' => 'decʼh',\n    'diff_yesterday_regexp' => 'Dec\\'h(?:\\\\s+da)?',\n    'diff_tomorrow' => 'warcʼhoazh',\n    'diff_tomorrow_regexp' => 'Warc\\'hoazh(?:\\\\s+da)?',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D [a viz] MMMM YYYY',\n        'LLL' => 'D [a viz] MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D [a viz] MMMM YYYY HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[Hiziv da] LT',\n        'nextDay' => '[Warc\\'hoazh da] LT',\n        'nextWeek' => 'dddd [da] LT',\n        'lastDay' => '[Dec\\'h da] LT',\n        'lastWeek' => 'dddd [paset da] LT',\n        'sameElse' => 'L',\n    ],\n    'ordinal' => function ($number) {\n        return $number.($number === 1 ? 'añ' : 'vet');\n    },\n    'months' => ['Genver', 'C\\'hwevrer', 'Meurzh', 'Ebrel', 'Mae', 'Mezheven', 'Gouere', 'Eost', 'Gwengolo', 'Here', 'Du', 'Kerzu'],\n    'months_short' => ['Gen', 'C\\'hwe', 'Meu', 'Ebr', 'Mae', 'Eve', 'Gou', 'Eos', 'Gwe', 'Her', 'Du', 'Ker'],\n    'weekdays' => ['Sul', 'Lun', 'Meurzh', 'Merc\\'her', 'Yaou', 'Gwener', 'Sadorn'],\n    'weekdays_short' => ['Sul', 'Lun', 'Meu', 'Mer', 'Yao', 'Gwe', 'Sad'],\n    'weekdays_min' => ['Su', 'Lu', 'Me', 'Mer', 'Ya', 'Gw', 'Sa'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n    'list' => [', ', ' hag '],\n    'meridiem' => ['A.M.', 'G.M.'],\n\n    'y' => ':count bl.',\n    'd' => ':count d',\n    'h' => ':count e',\n    'min' => ':count min',\n    's' => ':count s',\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/br_FR.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/br.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/brx.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/brx_IN.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/brx_IN.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Red Hat Pune    bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'M/D/YY',\n    ],\n    'months' => ['जानुवारी', 'फेब्रुवारी', 'मार्स', 'एफ्रिल', 'मे', 'जुन', 'जुलाइ', 'आगस्थ', 'सेबथेज्ब़र', 'अखथबर', 'नबेज्ब़र', 'दिसेज्ब़र'],\n    'months_short' => ['जानुवारी', 'फेब्रुवारी', 'मार्स', 'एप्रिल', 'मे', 'जुन', 'जुलाइ', 'आगस्थ', 'सेबथेज्ब़र', 'अखथबर', 'नबेज्ब़र', 'दिसेज्ब़र'],\n    'weekdays' => ['रबिबार', 'सोबार', 'मंगलबार', 'बुदबार', 'बिसथिबार', 'सुखुरबार', 'सुनिबार'],\n    'weekdays_short' => ['रबि', 'सम', 'मंगल', 'बुद', 'बिसथि', 'सुखुर', 'सुनि'],\n    'weekdays_min' => ['रबि', 'सम', 'मंगल', 'बुद', 'बिसथि', 'सुखुर', 'सुनि'],\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['फुं.', 'बेलासे.'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/bs.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - bokideckonja\n * - Josh Soref\n * - François B\n * - shaishavgandhi05\n * - Serhan Apaydın\n * - JD Isaacks\n */\n\nuse Carbon\\CarbonInterface;\n\nreturn [\n    'year' => ':count godina|:count godine|:count godina',\n    'y' => ':count godina|:count godine|:count godina',\n    'month' => ':count mjesec|:count mjeseca|:count mjeseci',\n    'm' => ':count mjesec|:count mjeseca|:count mjeseci',\n    'week' => ':count sedmice|:count sedmicu|:count sedmica',\n    'w' => ':count sedmice|:count sedmicu|:count sedmica',\n    'day' => ':count dan|:count dana|:count dana',\n    'd' => ':count dan|:count dana|:count dana',\n    'hour' => ':count sat|:count sata|:count sati',\n    'h' => ':count sat|:count sata|:count sati',\n    'minute' => ':count minut|:count minuta|:count minuta',\n    'min' => ':count minut|:count minuta|:count minuta',\n    'second' => ':count sekund|:count sekunda|:count sekundi',\n    's' => ':count sekund|:count sekunda|:count sekundi',\n    'ago' => 'prije :time',\n    'from_now' => 'za :time',\n    'after' => 'nakon :time',\n    'before' => ':time ranije',\n    'diff_now' => 'sada',\n    'diff_today' => 'danas',\n    'diff_today_regexp' => 'danas(?:\\\\s+u)?',\n    'diff_yesterday' => 'jučer',\n    'diff_yesterday_regexp' => 'jučer(?:\\\\s+u)?',\n    'diff_tomorrow' => 'sutra',\n    'diff_tomorrow_regexp' => 'sutra(?:\\\\s+u)?',\n    'formats' => [\n        'LT' => 'H:mm',\n        'LTS' => 'H:mm:ss',\n        'L' => 'DD.MM.YYYY',\n        'LL' => 'D. MMMM YYYY',\n        'LLL' => 'D. MMMM YYYY H:mm',\n        'LLLL' => 'dddd, D. MMMM YYYY H:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[danas u] LT',\n        'nextDay' => '[sutra u] LT',\n        'nextWeek' => function (CarbonInterface $current) {\n            switch ($current->dayOfWeek) {\n                case 0:\n                    return '[u] [nedjelju] [u] LT';\n                case 3:\n                    return '[u] [srijedu] [u] LT';\n                case 6:\n                    return '[u] [subotu] [u] LT';\n                default:\n                    return '[u] dddd [u] LT';\n            }\n        },\n        'lastDay' => '[jučer u] LT',\n        'lastWeek' => function (CarbonInterface $current) {\n            switch ($current->dayOfWeek) {\n                case 0:\n                case 3:\n                    return '[prošlu] dddd [u] LT';\n                case 6:\n                    return '[prošle] [subote] [u] LT';\n                default:\n                    return '[prošli] dddd [u] LT';\n            }\n        },\n        'sameElse' => 'L',\n    ],\n    'ordinal' => ':number.',\n    'months' => ['januar', 'februar', 'mart', 'april', 'maj', 'juni', 'juli', 'august', 'septembar', 'oktobar', 'novembar', 'decembar'],\n    'months_short' => ['jan.', 'feb.', 'mar.', 'apr.', 'maj.', 'jun.', 'jul.', 'aug.', 'sep.', 'okt.', 'nov.', 'dec.'],\n    'weekdays' => ['nedjelja', 'ponedjeljak', 'utorak', 'srijeda', 'četvrtak', 'petak', 'subota'],\n    'weekdays_short' => ['ned.', 'pon.', 'uto.', 'sri.', 'čet.', 'pet.', 'sub.'],\n    'weekdays_min' => ['ne', 'po', 'ut', 'sr', 'če', 'pe', 'su'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n    'list' => [', ', ' i '],\n    'meridiem' => ['prijepodne', 'popodne'],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/bs_BA.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/bs.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/bs_Cyrl.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/bs.php', [\n    'meridiem' => ['пре подне', 'поподне'],\n    'weekdays' => ['недјеља', 'понедјељак', 'уторак', 'сриједа', 'четвртак', 'петак', 'субота'],\n    'weekdays_short' => ['нед', 'пон', 'уто', 'сри', 'чет', 'пет', 'суб'],\n    'weekdays_min' => ['нед', 'пон', 'уто', 'сри', 'чет', 'пет', 'суб'],\n    'months' => ['јануар', 'фебруар', 'март', 'април', 'мај', 'јуни', 'јули', 'аугуст', 'септембар', 'октобар', 'новембар', 'децембар'],\n    'months_short' => ['јан', 'феб', 'мар', 'апр', 'мај', 'јун', 'јул', 'ауг', 'сеп', 'окт', 'нов', 'дец'],\n    'first_day_of_week' => 1,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'D.M.YYYY.',\n        'LL' => 'DD.MM.YYYY.',\n        'LLL' => 'DD. MMMM YYYY. HH:mm',\n        'LLLL' => 'dddd, DD. MMMM YYYY. HH:mm',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/bs_Latn.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/bs.php', [\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/byn.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/byn_ER.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/byn_ER.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Ge'ez Frontier Foundation    locales@geez.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD/MM/YYYY',\n    ],\n    'months' => ['ልደትሪ', 'ካብኽብቲ', 'ክብላ', 'ፋጅኺሪ', 'ክቢቅሪ', 'ምኪኤል ትጓ̅ኒሪ', 'ኰርኩ', 'ማርያም ትሪ', 'ያኸኒ መሳቅለሪ', 'መተሉ', 'ምኪኤል መሽወሪ', 'ተሕሳስሪ'],\n    'months_short' => ['ልደት', 'ካብኽ', 'ክብላ', 'ፋጅኺ', 'ክቢቅ', 'ም/ት', 'ኰር', 'ማርያ', 'ያኸኒ', 'መተሉ', 'ም/ም', 'ተሕሳ'],\n    'weekdays' => ['ሰንበር ቅዳዅ', 'ሰኑ', 'ሰሊጝ', 'ለጓ ወሪ ለብዋ', 'ኣምድ', 'ኣርብ', 'ሰንበር ሽጓዅ'],\n    'weekdays_short' => ['ሰ/ቅ', 'ሰኑ', 'ሰሊጝ', 'ለጓ', 'ኣምድ', 'ኣርብ', 'ሰ/ሽ'],\n    'weekdays_min' => ['ሰ/ቅ', 'ሰኑ', 'ሰሊጝ', 'ለጓ', 'ኣምድ', 'ኣርብ', 'ሰ/ሽ'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['ፋዱስ ጃብ', 'ፋዱስ ደምቢ'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ca.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - mestremuten\n * - François B\n * - Marc Ordinas i Llopis\n * - Pere Orga\n * - JD Isaacks\n * - Quentí\n * - Víctor Díaz\n * - Xavi\n * - qcardona\n */\n\nuse Carbon\\CarbonInterface;\n\nreturn [\n    'year' => ':count any|:count anys',\n    'a_year' => 'un any|:count anys',\n    'y' => ':count any|:count anys',\n    'month' => ':count mes|:count mesos',\n    'a_month' => 'un mes|:count mesos',\n    'm' => ':count mes|:count mesos',\n    'week' => ':count setmana|:count setmanes',\n    'a_week' => 'una setmana|:count setmanes',\n    'w' => ':count setmana|:count setmanes',\n    'day' => ':count dia|:count dies',\n    'a_day' => 'un dia|:count dies',\n    'd' => ':count d',\n    'hour' => ':count hora|:count hores',\n    'a_hour' => 'una hora|:count hores',\n    'h' => ':count h',\n    'minute' => ':count minut|:count minuts',\n    'a_minute' => 'un minut|:count minuts',\n    'min' => ':count min',\n    'second' => ':count segon|:count segons',\n    'a_second' => 'uns segons|:count segons',\n    's' => ':count s',\n    'ago' => 'fa :time',\n    'from_now' => 'd\\'aquí a :time',\n    'after' => ':time després',\n    'before' => ':time abans',\n    'diff_now' => 'ara mateix',\n    'diff_today' => 'avui',\n    'diff_today_regexp' => 'avui(?:\\\\s+a)?(?:\\\\s+les)?',\n    'diff_yesterday' => 'ahir',\n    'diff_yesterday_regexp' => 'ahir(?:\\\\s+a)?(?:\\\\s+les)?',\n    'diff_tomorrow' => 'demà',\n    'diff_tomorrow_regexp' => 'demà(?:\\\\s+a)?(?:\\\\s+les)?',\n    'diff_before_yesterday' => 'abans d\\'ahir',\n    'diff_after_tomorrow' => 'demà passat',\n    'period_recurrences' => ':count cop|:count cops',\n    'period_interval' => 'cada :interval',\n    'period_start_date' => 'de :date',\n    'period_end_date' => 'fins a :date',\n    'formats' => [\n        'LT' => 'H:mm',\n        'LTS' => 'H:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM [de] YYYY',\n        'LLL' => 'D MMMM [de] YYYY [a les] H:mm',\n        'LLLL' => 'dddd D MMMM [de] YYYY [a les] H:mm',\n    ],\n    'calendar' => [\n        'sameDay' => function (CarbonInterface $current) {\n            return '[avui a '.($current->hour !== 1 ? 'les' : 'la').'] LT';\n        },\n        'nextDay' => function (CarbonInterface $current) {\n            return '[demà a '.($current->hour !== 1 ? 'les' : 'la').'] LT';\n        },\n        'nextWeek' => function (CarbonInterface $current) {\n            return 'dddd [a '.($current->hour !== 1 ? 'les' : 'la').'] LT';\n        },\n        'lastDay' => function (CarbonInterface $current) {\n            return '[ahir a '.($current->hour !== 1 ? 'les' : 'la').'] LT';\n        },\n        'lastWeek' => function (CarbonInterface $current) {\n            return '[el] dddd [passat a '.($current->hour !== 1 ? 'les' : 'la').'] LT';\n        },\n        'sameElse' => 'L',\n    ],\n    'ordinal' => function ($number, $period) {\n        return $number.(\n            ($period === 'w' || $period === 'W') ? 'a' : (\n                ($number === 1) ? 'r' : (\n                    ($number === 2) ? 'n' : (\n                        ($number === 3) ? 'r' : (\n                            ($number === 4) ? 't' : 'è'\n                        )\n                    )\n                )\n            )\n        );\n    },\n    'months' => ['de gener', 'de febrer', 'de març', 'd\\'abril', 'de maig', 'de juny', 'de juliol', 'd\\'agost', 'de setembre', 'd\\'octubre', 'de novembre', 'de desembre'],\n    'months_standalone' => ['gener', 'febrer', 'març', 'abril', 'maig', 'juny', 'juliol', 'agost', 'setembre', 'octubre', 'novembre', 'desembre'],\n    'months_short' => ['de gen.', 'de febr.', 'de març', 'd\\'abr.', 'de maig', 'de juny', 'de jul.', 'd\\'ag.', 'de set.', 'd\\'oct.', 'de nov.', 'de des.'],\n    'months_short_standalone' => ['gen.', 'febr.', 'març', 'abr.', 'maig', 'juny', 'jul.', 'ag.', 'set.', 'oct.', 'nov.', 'des.'],\n    'months_regexp' => '/(D[oD]?[\\s,]+MMMM?|L{2,4}|l{2,4})/',\n    'weekdays' => ['diumenge', 'dilluns', 'dimarts', 'dimecres', 'dijous', 'divendres', 'dissabte'],\n    'weekdays_short' => ['dg.', 'dl.', 'dt.', 'dc.', 'dj.', 'dv.', 'ds.'],\n    'weekdays_min' => ['dg', 'dl', 'dt', 'dc', 'dj', 'dv', 'ds'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n    'list' => [', ', ' i '],\n    'meridiem' => ['a. m.', 'p. m.'],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ca_AD.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/ca.php', [\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ca_ES.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/ca.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ca_ES_Valencia.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nuse Symfony\\Component\\Translation\\PluralizationRules;\n\n// @codeCoverageIgnoreStart\nif (class_exists(PluralizationRules::class)) {\n    PluralizationRules::set(static function ($number) {\n        return PluralizationRules::get($number, 'ca');\n    }, 'ca_ES_Valencia');\n}\n// @codeCoverageIgnoreEnd\n\nreturn array_replace_recursive(require __DIR__.'/ca.php', [\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ca_FR.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/ca.php', [\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ca_IT.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/ca.php', [\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ccp.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'weekdays' => ['𑄢𑄧𑄝𑄨𑄝𑄢𑄴', '𑄥𑄧𑄟𑄴𑄝𑄢𑄴', '𑄟𑄧𑄁𑄉𑄧𑄣𑄴𑄝𑄢𑄴', '𑄝𑄪𑄖𑄴𑄝𑄢𑄴', '𑄝𑄳𑄢𑄨𑄥𑄪𑄛𑄴𑄝𑄢𑄴', '𑄥𑄪𑄇𑄴𑄇𑄮𑄢𑄴𑄝𑄢𑄴', '𑄥𑄧𑄚𑄨𑄝𑄢𑄴'],\n    'weekdays_short' => ['𑄢𑄧𑄝𑄨', '𑄥𑄧𑄟𑄴', '𑄟𑄧𑄁𑄉𑄧𑄣𑄴', '𑄝𑄪𑄖𑄴', '𑄝𑄳𑄢𑄨𑄥𑄪𑄛𑄴', '𑄥𑄪𑄇𑄴𑄇𑄮𑄢𑄴', '𑄥𑄧𑄚𑄨'],\n    'weekdays_min' => ['𑄢𑄧𑄝𑄨', '𑄥𑄧𑄟𑄴', '𑄟𑄧𑄁𑄉𑄧𑄣𑄴', '𑄝𑄪𑄖𑄴', '𑄝𑄳𑄢𑄨𑄥𑄪𑄛𑄴', '𑄥𑄪𑄇𑄴𑄇𑄮𑄢𑄴', '𑄥𑄧𑄚𑄨'],\n    'months' => ['𑄎𑄚𑄪𑄠𑄢𑄨', '𑄜𑄬𑄛𑄴𑄝𑄳𑄢𑄪𑄠𑄢𑄨', '𑄟𑄢𑄴𑄌𑄧', '𑄃𑄬𑄛𑄳𑄢𑄨𑄣𑄴', '𑄟𑄬', '𑄎𑄪𑄚𑄴', '𑄎𑄪𑄣𑄭', '𑄃𑄉𑄧𑄌𑄴𑄑𑄴', '𑄥𑄬𑄛𑄴𑄑𑄬𑄟𑄴𑄝𑄧𑄢𑄴', '𑄃𑄧𑄇𑄴𑄑𑄬𑄝𑄧𑄢𑄴', '𑄚𑄧𑄞𑄬𑄟𑄴𑄝𑄧𑄢𑄴', '𑄓𑄨𑄥𑄬𑄟𑄴𑄝𑄧𑄢𑄴'],\n    'months_short' => ['𑄎𑄚𑄪', '𑄜𑄬𑄛𑄴', '𑄟𑄢𑄴𑄌𑄧', '𑄃𑄬𑄛𑄳𑄢𑄨𑄣𑄴', '𑄟𑄬', '𑄎𑄪𑄚𑄴', '𑄎𑄪𑄣𑄭', '𑄃𑄉𑄧𑄌𑄴𑄑𑄴', '𑄥𑄬𑄛𑄴𑄑𑄬𑄟𑄴𑄝𑄧𑄢𑄴', '𑄃𑄧𑄇𑄴𑄑𑄮𑄝𑄧𑄢𑄴', '𑄚𑄧𑄞𑄬𑄟𑄴𑄝𑄧𑄢𑄴', '𑄓𑄨𑄥𑄬𑄟𑄴𑄝𑄢𑄴'],\n    'months_short_standalone' => ['𑄎𑄚𑄪𑄠𑄢𑄨', '𑄜𑄬𑄛𑄴𑄝𑄳𑄢𑄪𑄠𑄢𑄨', '𑄟𑄢𑄴𑄌𑄧', '𑄃𑄬𑄛𑄳𑄢𑄨𑄣𑄴', '𑄟𑄬', '𑄎𑄪𑄚𑄴', '𑄎𑄪𑄣𑄭', '𑄃𑄉𑄧𑄌𑄴𑄑𑄴', '𑄥𑄬𑄛𑄴𑄑𑄬𑄟𑄴𑄝𑄧𑄢𑄴', '𑄃𑄧𑄇𑄴𑄑𑄮𑄝𑄧𑄢𑄴', '𑄚𑄧𑄞𑄬𑄟𑄴𑄝𑄧𑄢𑄴', '𑄓𑄨𑄥𑄬𑄟𑄴𑄝𑄧𑄢𑄴'],\n    'formats' => [\n        'LT' => 'h:mm a',\n        'LTS' => 'h:mm:ss a',\n        'L' => 'D/M/YYYY',\n        'LL' => 'D MMM, YYYY',\n        'LLL' => 'D MMMM, YYYY h:mm a',\n        'LLLL' => 'dddd, D MMMM, YYYY h:mm a',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ccp_IN.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/ccp.php', [\n    'weekend' => [0, 0],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ce.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/ce_RU.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ce_RU.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - ANCHR\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'YYYY.DD.MM',\n    ],\n    'months' => ['Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'],\n    'months_short' => ['янв', 'фев', 'мар', 'апр', 'май', 'июн', 'июл', 'авг', 'сен', 'окт', 'ноя', 'дек'],\n    'weekdays' => ['КӀиранан де', 'Оршотан де', 'Шинарин де', 'Кхаарин де', 'Еарин де', 'ПӀераскан де', 'Шот де'],\n    'weekdays_short' => ['КӀ', 'Ор', 'Ши', 'Кх', 'Еа', 'ПӀ', 'Шо'],\n    'weekdays_min' => ['КӀ', 'Ор', 'Ши', 'Кх', 'Еа', 'ПӀ', 'Шо'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n\n    'year' => ':count шо',\n    'y' => ':count шо',\n    'a_year' => ':count шо',\n\n    'month' => ':count бутт',\n    'm' => ':count бутт',\n    'a_month' => ':count бутт',\n\n    'week' => ':count кӏира',\n    'w' => ':count кӏира',\n    'a_week' => ':count кӏира',\n\n    'day' => ':count де',\n    'd' => ':count де',\n    'a_day' => ':count де',\n\n    'hour' => ':count сахьт',\n    'h' => ':count сахьт',\n    'a_hour' => ':count сахьт',\n\n    'minute' => ':count минот',\n    'min' => ':count минот',\n    'a_minute' => ':count минот',\n\n    'second' => ':count секунд',\n    's' => ':count секунд',\n    'a_second' => ':count секунд',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/cgg.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'weekdays' => ['Sande', 'Orwokubanza', 'Orwakabiri', 'Orwakashatu', 'Orwakana', 'Orwakataano', 'Orwamukaaga'],\n    'weekdays_short' => ['SAN', 'ORK', 'OKB', 'OKS', 'OKN', 'OKT', 'OMK'],\n    'weekdays_min' => ['SAN', 'ORK', 'OKB', 'OKS', 'OKN', 'OKT', 'OMK'],\n    'months' => ['Okwokubanza', 'Okwakabiri', 'Okwakashatu', 'Okwakana', 'Okwakataana', 'Okwamukaaga', 'Okwamushanju', 'Okwamunaana', 'Okwamwenda', 'Okwaikumi', 'Okwaikumi na kumwe', 'Okwaikumi na ibiri'],\n    'months_short' => ['KBZ', 'KBR', 'KST', 'KKN', 'KTN', 'KMK', 'KMS', 'KMN', 'KMW', 'KKM', 'KNK', 'KNB'],\n    'first_day_of_week' => 1,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY HH:mm',\n    ],\n\n    'day' => ':count ruhanga', // less reliable\n    'd' => ':count ruhanga', // less reliable\n    'a_day' => ':count ruhanga', // less reliable\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/chr.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/chr_US.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/chr_US.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Cherokee Nation Joseph Erb josepherb7@gmail.com\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'MM/DD/YYYY',\n    ],\n    'months' => ['ᎤᏃᎸᏔᏅ', 'ᎧᎦᎵ', 'ᎠᏅᏱ', 'ᎧᏬᏂ', 'ᎠᏂᏍᎬᏘ', 'ᏕᎭᎷᏱ', 'ᎫᏰᏉᏂ', 'ᎦᎶᏂ', 'ᏚᎵᏍᏗ', 'ᏚᏂᏅᏗ', 'ᏅᏓᏕᏆ', 'ᎥᏍᎩᏱ'],\n    'months_short' => ['ᎤᏃ', 'ᎧᎦ', 'ᎠᏅ', 'ᎧᏬ', 'ᎠᏂ', 'ᏕᎭ', 'ᎫᏰ', 'ᎦᎶ', 'ᏚᎵ', 'ᏚᏂ', 'ᏅᏓ', 'ᎥᏍ'],\n    'weekdays' => ['ᎤᎾᏙᏓᏆᏍᎬ', 'ᎤᎾᏙᏓᏉᏅᎯ', 'ᏔᎵᏁᎢᎦ', 'ᏦᎢᏁᎢᎦ', 'ᏅᎩᏁᎢᎦ', 'ᏧᎾᎩᎶᏍᏗ', 'ᎤᎾᏙᏓᏈᏕᎾ'],\n    'weekdays_short' => ['ᏆᏍᎬ', 'ᏉᏅᎯ', 'ᏔᎵᏁ', 'ᏦᎢᏁ', 'ᏅᎩᏁ', 'ᏧᎾᎩ', 'ᏈᏕᎾ'],\n    'weekdays_min' => ['ᏆᏍᎬ', 'ᏉᏅᎯ', 'ᏔᎵᏁ', 'ᏦᎢᏁ', 'ᏅᎩᏁ', 'ᏧᎾᎩ', 'ᏈᏕᎾ'],\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['ᏌᎾᎴ', 'ᏒᎯᏱᎢᏗᏢ', 'ꮜꮎꮄ', 'ꮢꭿᏹꭲꮧꮲ'],\n\n    'second' => ':count ᏐᎢ', // less reliable\n    's' => ':count ᏐᎢ', // less reliable\n    'a_second' => ':count ᏐᎢ', // less reliable\n\n    'year' => ':count ᏑᏕᏘᏴᏓ',\n    'y' => ':count ᏑᏕᏘᏴᏓ',\n    'a_year' => ':count ᏑᏕᏘᏴᏓ',\n\n    'month' => ':count ᏏᏅᏙ',\n    'm' => ':count ᏏᏅᏙ',\n    'a_month' => ':count ᏏᏅᏙ',\n\n    'week' => ':count ᏑᎾᏙᏓᏆᏍᏗ',\n    'w' => ':count ᏑᎾᏙᏓᏆᏍᏗ',\n    'a_week' => ':count ᏑᎾᏙᏓᏆᏍᏗ',\n\n    'day' => ':count ᎢᎦ',\n    'd' => ':count ᎢᎦ',\n    'a_day' => ':count ᎢᎦ',\n\n    'hour' => ':count ᏑᏟᎶᏛ',\n    'h' => ':count ᏑᏟᎶᏛ',\n    'a_hour' => ':count ᏑᏟᎶᏛ',\n\n    'minute' => ':count ᎢᏯᏔᏬᏍᏔᏅ',\n    'min' => ':count ᎢᏯᏔᏬᏍᏔᏅ',\n    'a_minute' => ':count ᎢᏯᏔᏬᏍᏔᏅ',\n\n    'ago' => ':time ᏥᎨᏒ',\n    'from_now' => 'ᎾᎿ :time',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ckb.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Swara Mohammed\n */\n$months = [\n    'ڕێبەندان',\n    'ڕەشەمە',\n    'نەورۆز',\n    'گوڵان',\n    'جۆزەردان',\n    'پوشپەڕ',\n    'گەلاوێژ',\n    'خەرمانان',\n    'ڕەزبەر',\n    'گەڵاڕێزان',\n    'سەرماوەرز',\n    'بەفرانبار',\n];\n\nreturn [\n    'year' => implode('|', ['{0}:count ساڵێک', '{1}ساڵێک', '{2}دوو ساڵ', ']2,11[:count ساڵ', ']10,Inf[:count ساڵ']),\n    'a_year' => implode('|', ['{0}:count ساڵێک', '{1}ساڵێک', '{2}دوو ساڵ', ']2,11[:count ساڵ', ']10,Inf[:count ساڵ']),\n    'month' => implode('|', ['{0}:count مانگێک', '{1}مانگێک', '{2}دوو مانگ', ']2,11[:count مانگ', ']10,Inf[:count مانگ']),\n    'a_month' => implode('|', ['{0}:count مانگێک', '{1}مانگێک', '{2}دوو مانگ', ']2,11[:count مانگ', ']10,Inf[:count مانگ']),\n    'week' => implode('|', ['{0}:count هەفتەیەک', '{1}هەفتەیەک', '{2}دوو هەفتە', ']2,11[:count هەفتە', ']10,Inf[:count هەفتە']),\n    'a_week' => implode('|', ['{0}:count هەفتەیەک', '{1}هەفتەیەک', '{2}دوو هەفتە', ']2,11[:count هەفتە', ']10,Inf[:count هەفتە']),\n    'day' => implode('|', ['{0}:count ڕۆژێک', '{1}ڕۆژێک', '{2}دوو ڕۆژ', ']2,11[:count ڕۆژ', ']10,Inf[:count ڕۆژ']),\n    'a_day' => implode('|', ['{0}:count ڕۆژێک', '{1}ڕۆژێک', '{2}دوو ڕۆژ', ']2,11[:count ڕۆژ', ']10,Inf[:count ڕۆژ']),\n    'hour' => implode('|', ['{0}:count کاتژمێرێک', '{1}کاتژمێرێک', '{2}دوو کاتژمێر', ']2,11[:count کاتژمێر', ']10,Inf[:count کاتژمێر']),\n    'a_hour' => implode('|', ['{0}:count کاتژمێرێک', '{1}کاتژمێرێک', '{2}دوو کاتژمێر', ']2,11[:count کاتژمێر', ']10,Inf[:count کاتژمێر']),\n    'minute' => implode('|', ['{0}:count خولەکێک', '{1}خولەکێک', '{2}دوو خولەک', ']2,11[:count خولەک', ']10,Inf[:count خولەک']),\n    'a_minute' => implode('|', ['{0}:count خولەکێک', '{1}خولەکێک', '{2}دوو خولەک', ']2,11[:count خولەک', ']10,Inf[:count خولەک']),\n    'second' => implode('|', ['{0}:count چرکەیەک', '{1}چرکەیەک', '{2}دوو چرکە', ']2,11[:count چرکە', ']10,Inf[:count چرکە']),\n    'a_second' => implode('|', ['{0}:count چرکەیەک', '{1}چرکەیەک', '{2}دوو چرکە', ']2,11[:count چرکە', ']10,Inf[:count چرکە']),\n    'ago' => 'پێش :time',\n    'from_now' => ':time لە ئێستاوە',\n    'after' => 'دوای :time',\n    'before' => 'پێش :time',\n    'diff_now' => 'ئێستا',\n    'diff_today' => 'ئەمڕۆ',\n    'diff_today_regexp' => 'ڕۆژ(?:\\\\s+لە)?(?:\\\\s+کاتژمێر)?',\n    'diff_yesterday' => 'دوێنێ',\n    'diff_yesterday_regexp' => 'دوێنێ(?:\\\\s+لە)?(?:\\\\s+کاتژمێر)?',\n    'diff_tomorrow' => 'سبەینێ',\n    'diff_tomorrow_regexp' => 'سبەینێ(?:\\\\s+لە)?(?:\\\\s+کاتژمێر)?',\n    'diff_before_yesterday' => 'پێش دوێنێ',\n    'diff_after_tomorrow' => 'دوای سبەینێ',\n    'period_recurrences' => implode('|', ['{0}جار', '{1}جار', '{2}:count دووجار', ']2,11[:count جار', ']10,Inf[:count جار']),\n    'period_interval' => 'هەموو :interval',\n    'period_start_date' => 'لە :date',\n    'period_end_date' => 'بۆ :date',\n    'months' => $months,\n    'months_short' => $months,\n    'weekdays' => ['یەکشەممە', 'دووشەممە', 'سێشەممە', 'چوارشەممە', 'پێنجشەممە', 'هەینی', 'شەممە'],\n    'weekdays_short' => ['یەکشەممە', 'دووشەممە', 'سێشەممە', 'چوارشەممە', 'پێنجشەممە', 'هەینی', 'شەممە'],\n    'weekdays_min' => ['یەکشەممە', 'دووشەممە', 'سێشەممە', 'چوارشەممە', 'پێنجشەممە', 'هەینی', 'شەممە'],\n    'list' => ['، ', ' و '],\n    'first_day_of_week' => 6,\n    'day_of_first_week_of_year' => 1,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'D/M/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd D MMMM YYYY HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[ئەمڕۆ لە کاتژمێر] LT',\n        'nextDay' => '[سبەینێ لە کاتژمێر] LT',\n        'nextWeek' => 'dddd [لە کاتژمێر] LT',\n        'lastDay' => '[دوێنێ لە کاتژمێر] LT',\n        'lastWeek' => 'dddd [لە کاتژمێر] LT',\n        'sameElse' => 'L',\n    ],\n    'meridiem' => ['پ.ن', 'د.ن'],\n    'weekend' => [5, 6],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/cmn.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/cmn_TW.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/cmn_TW.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'YYYY年MM月DD號',\n    ],\n    'months' => ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'],\n    'months_short' => [' 1月', ' 2月', ' 3月', ' 4月', ' 5月', ' 6月', ' 7月', ' 8月', ' 9月', '10月', '11月', '12月'],\n    'weekdays' => ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'],\n    'weekdays_short' => ['日', '一', '二', '三', '四', '五', '六'],\n    'weekdays_min' => ['日', '一', '二', '三', '四', '五', '六'],\n    'meridiem' => ['上午', '下午'],\n\n    'year' => ':count 年',\n    'y' => ':count 年',\n    'a_year' => ':count 年',\n\n    'month' => ':count 月',\n    'm' => ':count 月',\n    'a_month' => ':count 月',\n\n    'week' => ':count 周',\n    'w' => ':count 周',\n    'a_week' => ':count 周',\n\n    'day' => ':count 白天',\n    'd' => ':count 白天',\n    'a_day' => ':count 白天',\n\n    'hour' => ':count 小时',\n    'h' => ':count 小时',\n    'a_hour' => ':count 小时',\n\n    'minute' => ':count 分钟',\n    'min' => ':count 分钟',\n    'a_minute' => ':count 分钟',\n\n    'second' => ':count 秒',\n    's' => ':count 秒',\n    'a_second' => ':count 秒',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/crh.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/crh_UA.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/crh_UA.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Reşat SABIQ tilde.birlik@gmail.com\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD.MM.YYYY',\n    ],\n    'months' => ['Yanvar', 'Fevral', 'Mart', 'Aprel', 'Mayıs', 'İyun', 'İyul', 'Avgust', 'Sentâbr', 'Oktâbr', 'Noyabr', 'Dekabr'],\n    'months_short' => ['Yan', 'Fev', 'Mar', 'Apr', 'May', 'İyn', 'İyl', 'Avg', 'Sen', 'Okt', 'Noy', 'Dek'],\n    'weekdays' => ['Bazar', 'Bazarertesi', 'Salı', 'Çarşembe', 'Cumaaqşamı', 'Cuma', 'Cumaertesi'],\n    'weekdays_short' => ['Baz', 'Ber', 'Sal', 'Çar', 'Caq', 'Cum', 'Cer'],\n    'weekdays_min' => ['Baz', 'Ber', 'Sal', 'Çar', 'Caq', 'Cum', 'Cer'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['ÜE', 'ÜS'],\n\n    'year' => ':count yıl',\n    'y' => ':count yıl',\n    'a_year' => ':count yıl',\n\n    'month' => ':count ay',\n    'm' => ':count ay',\n    'a_month' => ':count ay',\n\n    'week' => ':count afta',\n    'w' => ':count afta',\n    'a_week' => ':count afta',\n\n    'day' => ':count kün',\n    'd' => ':count kün',\n    'a_day' => ':count kün',\n\n    'hour' => ':count saat',\n    'h' => ':count saat',\n    'a_hour' => ':count saat',\n\n    'minute' => ':count daqqa',\n    'min' => ':count daqqa',\n    'a_minute' => ':count daqqa',\n\n    'second' => ':count ekinci',\n    's' => ':count ekinci',\n    'a_second' => ':count ekinci',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/cs.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Philippe Vaucher\n * - Jakub Tesinsky\n * - Martin Suja\n * - Nikos Timiopulos\n * - Bohuslav Blín\n * - Tsutomu Kuroda\n * - tjku\n * - Lukas Svoboda\n * - Max Melentiev\n * - Juanito Fatas\n * - Akira Matsuda\n * - Christopher Dell\n * - Václav Pávek\n * - CodeSkills\n * - Tlapi\n * - newman101\n * - Petr Kadlec\n * - tommaskraus\n * - Karel Sommer (calvera)\n */\n$za = function ($time) {\n    return 'za '.strtr($time, [\n        'hodina' => 'hodinu',\n        'minuta' => 'minutu',\n        'sekunda' => 'sekundu',\n    ]);\n};\n\n$pred = function ($time) {\n    $time = strtr($time, [\n        'hodina' => 'hodinou',\n        'minuta' => 'minutou',\n        'sekunda' => 'sekundou',\n    ]);\n    $time = preg_replace('/hodiny?(?!\\w)/', 'hodinami', $time);\n    $time = preg_replace('/minuty?(?!\\w)/', 'minutami', $time);\n    $time = preg_replace('/sekundy?(?!\\w)/', 'sekundami', $time);\n\n    return \"před $time\";\n};\n\nreturn [\n    'year' => ':count rok|:count roky|:count let',\n    'y' => ':count rok|:count roky|:count let',\n    'a_year' => 'rok|:count roky|:count let',\n    'month' => ':count měsíc|:count měsíce|:count měsíců',\n    'm' => ':count měs.',\n    'a_month' => 'měsíc|:count měsíce|:count měsíců',\n    'week' => ':count týden|:count týdny|:count týdnů',\n    'w' => ':count týd.',\n    'a_week' => 'týden|:count týdny|:count týdnů',\n    'day' => ':count den|:count dny|:count dní',\n    'd' => ':count den|:count dny|:count dní',\n    'a_day' => 'den|:count dny|:count dní',\n    'hour' => ':count hodina|:count hodiny|:count hodin',\n    'h' => ':count hod.',\n    'a_hour' => 'hodina|:count hodiny|:count hodin',\n    'minute' => ':count minuta|:count minuty|:count minut',\n    'min' => ':count min.',\n    'a_minute' => 'minuta|:count minuty|:count minut',\n    'second' => ':count sekunda|:count sekundy|:count sekund',\n    's' => ':count sek.',\n    'a_second' => 'pár sekund|:count sekundy|:count sekund',\n\n    'month_ago' => ':count měsícem|:count měsíci|:count měsíci',\n    'a_month_ago' => 'měsícem|:count měsíci|:count měsíci',\n    'day_ago' => ':count dnem|:count dny|:count dny',\n    'a_day_ago' => 'dnem|:count dny|:count dny',\n    'week_ago' => ':count týdnem|:count týdny|:count týdny',\n    'a_week_ago' => 'týdnem|:count týdny|:count týdny',\n    'year_ago' => ':count rokem|:count roky|:count lety',\n    'y_ago' => ':count rok.|:count rok.|:count let.',\n    'a_year_ago' => 'rokem|:count roky|:count lety',\n\n    'month_before' => ':count měsícem|:count měsíci|:count měsíci',\n    'a_month_before' => 'měsícem|:count měsíci|:count měsíci',\n    'day_before' => ':count dnem|:count dny|:count dny',\n    'a_day_before' => 'dnem|:count dny|:count dny',\n    'week_before' => ':count týdnem|:count týdny|:count týdny',\n    'a_week_before' => 'týdnem|:count týdny|:count týdny',\n    'year_before' => ':count rokem|:count roky|:count lety',\n    'y_before' => ':count rok.|:count rok.|:count let.',\n    'a_year_before' => 'rokem|:count roky|:count lety',\n\n    'ago' => $pred,\n    'from_now' => $za,\n    'before' => $pred,\n    'after' => $za,\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n    'months' => ['ledna', 'února', 'března', 'dubna', 'května', 'června', 'července', 'srpna', 'září', 'října', 'listopadu', 'prosince'],\n    'months_standalone' => ['leden', 'únor', 'březen', 'duben', 'květen', 'červen', 'červenec', 'srpen', 'září', 'říjen', 'listopad', 'prosinec'],\n    'months_short' => ['led', 'úno', 'bře', 'dub', 'kvě', 'čvn', 'čvc', 'srp', 'zář', 'říj', 'lis', 'pro'],\n    'weekdays' => ['neděle', 'pondělí', 'úterý', 'středa', 'čtvrtek', 'pátek', 'sobota'],\n    'weekdays_short' => ['ned', 'pon', 'úte', 'stř', 'čtv', 'pát', 'sob'],\n    'weekdays_min' => ['ne', 'po', 'út', 'st', 'čt', 'pá', 'so'],\n    'list' => [', ', ' a '],\n    'diff_now' => 'nyní',\n    'diff_yesterday' => 'včera',\n    'diff_tomorrow' => 'zítra',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD. MM. YYYY',\n        'LL' => 'D. MMMM YYYY',\n        'LLL' => 'D. MMMM YYYY HH:mm',\n        'LLLL' => 'dddd D. MMMM YYYY HH:mm',\n    ],\n    'meridiem' => ['dopoledne', 'odpoledne'],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/cs_CZ.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/cs.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/csb.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/csb_PL.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/csb_PL.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - csb_PL locale Michal Ostrowski bug-glibc-locales@gnu.org\n */\nreturn [\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'YYYY-MM-DD',\n        'LL' => 'MMMM DD, YYYY',\n        'LLL' => 'DD MMM HH:mm',\n        'LLLL' => 'MMMM DD, YYYY HH:mm',\n    ],\n    'months' => ['stëcznika', 'gromicznika', 'strëmiannika', 'łżëkwiata', 'maja', 'czerwińca', 'lëpińca', 'zélnika', 'séwnika', 'rujana', 'lëstopadnika', 'gòdnika'],\n    'months_short' => ['stë', 'gro', 'str', 'łżë', 'maj', 'cze', 'lëp', 'zél', 'séw', 'ruj', 'lës', 'gòd'],\n    'weekdays' => ['niedzela', 'pòniedzôłk', 'wtórk', 'strzoda', 'czwiôrtk', 'piątk', 'sobòta'],\n    'weekdays_short' => ['nie', 'pòn', 'wtó', 'str', 'czw', 'pią', 'sob'],\n    'weekdays_min' => ['nie', 'pòn', 'wtó', 'str', 'czw', 'pią', 'sob'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n    'list' => [', ', ' a téż '],\n    'two_words_connector' => ' a téż ',\n    'year' => ':count rok',\n    'month' => ':count miesiąc',\n    'week' => ':count tidzéń',\n    'day' => ':count dzéń',\n    'hour' => ':count gòdzëna',\n    'minute' => ':count minuta',\n    'second' => ':count sekunda',\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/cu.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'months' => ['M01', 'M02', 'M03', 'M04', 'M05', 'M06', 'M07', 'M08', 'M09', 'M10', 'M11', 'M12'],\n    'months_short' => ['M01', 'M02', 'M03', 'M04', 'M05', 'M06', 'M07', 'M08', 'M09', 'M10', 'M11', 'M12'],\n    'first_day_of_week' => 1,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'YYYY-MM-DD',\n        'LL' => 'YYYY MMM D',\n        'LLL' => 'YYYY MMMM D HH:mm',\n        'LLLL' => 'YYYY MMMM D, dddd HH:mm',\n    ],\n\n    'year' => ':count лѣто',\n    'y' => ':count лѣто',\n    'a_year' => ':count лѣто',\n\n    'month' => ':count мѣсѧць',\n    'm' => ':count мѣсѧць',\n    'a_month' => ':count мѣсѧць',\n\n    'week' => ':count сєдмица',\n    'w' => ':count сєдмица',\n    'a_week' => ':count сєдмица',\n\n    'day' => ':count дьнь',\n    'd' => ':count дьнь',\n    'a_day' => ':count дьнь',\n\n    'hour' => ':count година',\n    'h' => ':count година',\n    'a_hour' => ':count година',\n\n    'minute' => ':count малъ', // less reliable\n    'min' => ':count малъ', // less reliable\n    'a_minute' => ':count малъ', // less reliable\n\n    'second' => ':count въторъ',\n    's' => ':count въторъ',\n    'a_second' => ':count въторъ',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/cv.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Josh Soref\n * - François B\n * - JD Isaacks\n */\nreturn [\n    'year' => ':count ҫул',\n    'a_year' => '{1}пӗр ҫул|:count ҫул',\n    'month' => ':count уйӑх',\n    'a_month' => '{1}пӗр уйӑх|:count уйӑх',\n    'week' => ':count эрне',\n    'a_week' => '{1}пӗр эрне|:count эрне',\n    'day' => ':count кун',\n    'a_day' => '{1}пӗр кун|:count кун',\n    'hour' => ':count сехет',\n    'a_hour' => '{1}пӗр сехет|:count сехет',\n    'minute' => ':count минут',\n    'a_minute' => '{1}пӗр минут|:count минут',\n    'second' => ':count ҫеккунт',\n    'a_second' => '{1}пӗр-ик ҫеккунт|:count ҫеккунт',\n    'ago' => ':time каялла',\n    'from_now' => function ($time) {\n        return $time.(preg_match('/сехет$/u', $time) ? 'рен' : (preg_match('/ҫул/u', $time) ? 'тан' : 'ран'));\n    },\n    'diff_yesterday' => 'Ӗнер',\n    'diff_today' => 'Паян',\n    'diff_tomorrow' => 'Ыран',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD-MM-YYYY',\n        'LL' => 'YYYY [ҫулхи] MMMM [уйӑхӗн] D[-мӗшӗ]',\n        'LLL' => 'YYYY [ҫулхи] MMMM [уйӑхӗн] D[-мӗшӗ], HH:mm',\n        'LLLL' => 'dddd, YYYY [ҫулхи] MMMM [уйӑхӗн] D[-мӗшӗ], HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[Паян] LT [сехетре]',\n        'nextDay' => '[Ыран] LT [сехетре]',\n        'nextWeek' => '[Ҫитес] dddd LT [сехетре]',\n        'lastDay' => '[Ӗнер] LT [сехетре]',\n        'lastWeek' => '[Иртнӗ] dddd LT [сехетре]',\n        'sameElse' => 'L',\n    ],\n    'ordinal' => ':number-мӗш',\n    'months' => ['кӑрлач', 'нарӑс', 'пуш', 'ака', 'май', 'ҫӗртме', 'утӑ', 'ҫурла', 'авӑн', 'юпа', 'чӳк', 'раштав'],\n    'months_short' => ['кӑр', 'нар', 'пуш', 'ака', 'май', 'ҫӗр', 'утӑ', 'ҫур', 'авн', 'юпа', 'чӳк', 'раш'],\n    'weekdays' => ['вырсарникун', 'тунтикун', 'ытларикун', 'юнкун', 'кӗҫнерникун', 'эрнекун', 'шӑматкун'],\n    'weekdays_short' => ['выр', 'тун', 'ытл', 'юн', 'кӗҫ', 'эрн', 'шӑм'],\n    'weekdays_min' => ['вр', 'тн', 'ыт', 'юн', 'кҫ', 'эр', 'шм'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n    'list' => [', ', ' тата '],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/cv_RU.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/cv.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/cy.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - François B\n * - JD Isaacks\n * - Daniel Monaghan\n */\nreturn [\n    'year' => '{1}blwyddyn|]1,Inf[:count flynedd',\n    'y' => ':countbl',\n    'month' => '{1}mis|]1,Inf[:count mis',\n    'm' => ':countmi',\n    'week' => ':count wythnos',\n    'w' => ':countw',\n    'day' => '{1}diwrnod|]1,Inf[:count diwrnod',\n    'd' => ':countd',\n    'hour' => '{1}awr|]1,Inf[:count awr',\n    'h' => ':counth',\n    'minute' => '{1}munud|]1,Inf[:count munud',\n    'min' => ':countm',\n    'second' => '{1}ychydig eiliadau|]1,Inf[:count eiliad',\n    's' => ':counts',\n    'ago' => ':time yn ôl',\n    'from_now' => 'mewn :time',\n    'after' => ':time ar ôl',\n    'before' => ':time o\\'r blaen',\n    'diff_now' => 'nawr',\n    'diff_today' => 'Heddiw',\n    'diff_today_regexp' => 'Heddiw(?:\\\\s+am)?',\n    'diff_yesterday' => 'ddoe',\n    'diff_yesterday_regexp' => 'Ddoe(?:\\\\s+am)?',\n    'diff_tomorrow' => 'yfory',\n    'diff_tomorrow_regexp' => 'Yfory(?:\\\\s+am)?',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[Heddiw am] LT',\n        'nextDay' => '[Yfory am] LT',\n        'nextWeek' => 'dddd [am] LT',\n        'lastDay' => '[Ddoe am] LT',\n        'lastWeek' => 'dddd [diwethaf am] LT',\n        'sameElse' => 'L',\n    ],\n    'ordinal' => function ($number) {\n        return $number.(\n            $number > 20\n                ? (\\in_array((int) $number, [40, 50, 60, 80, 100], true) ? 'fed' : 'ain')\n                : ([\n                    '', 'af', 'il', 'ydd', 'ydd', 'ed', 'ed', 'ed', 'fed', 'fed', 'fed', // 1af to 10fed\n                    'eg', 'fed', 'eg', 'eg', 'fed', 'eg', 'eg', 'fed', 'eg', 'fed', // 11eg to 20fed\n                ])[$number] ?? ''\n        );\n    },\n    'months' => ['Ionawr', 'Chwefror', 'Mawrth', 'Ebrill', 'Mai', 'Mehefin', 'Gorffennaf', 'Awst', 'Medi', 'Hydref', 'Tachwedd', 'Rhagfyr'],\n    'months_short' => ['Ion', 'Chwe', 'Maw', 'Ebr', 'Mai', 'Meh', 'Gor', 'Aws', 'Med', 'Hyd', 'Tach', 'Rhag'],\n    'weekdays' => ['Dydd Sul', 'Dydd Llun', 'Dydd Mawrth', 'Dydd Mercher', 'Dydd Iau', 'Dydd Gwener', 'Dydd Sadwrn'],\n    'weekdays_short' => ['Sul', 'Llun', 'Maw', 'Mer', 'Iau', 'Gwe', 'Sad'],\n    'weekdays_min' => ['Su', 'Ll', 'Ma', 'Me', 'Ia', 'Gw', 'Sa'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n    'list' => [', ', ' a '],\n    'meridiem' => ['yb', 'yh'],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/cy_GB.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/cy.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/da.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Rune Mønnike\n * - François B\n * - codenhagen\n * - JD Isaacks\n * - Jens Herlevsen\n * - Ulrik McArdle (mcardle)\n * - Frederik Sauer (FrittenKeeZ)\n * - Janus Bahs Jacquet (kokoshneta)\n */\nreturn [\n    'year' => ':count år|:count år',\n    'a_year' => 'et år|:count år',\n    'y' => ':count år|:count år',\n    'month' => ':count måned|:count måneder',\n    'a_month' => 'en måned|:count måneder',\n    'm' => ':count mdr.',\n    'week' => ':count uge|:count uger',\n    'a_week' => 'en uge|:count uger',\n    'w' => ':count u.',\n    'day' => ':count dag|:count dage',\n    'a_day' => ':count dag|:count dage',\n    'd' => ':count d.',\n    'hour' => ':count time|:count timer',\n    'a_hour' => 'en time|:count timer',\n    'h' => ':count t.',\n    'minute' => ':count minut|:count minutter',\n    'a_minute' => 'et minut|:count minutter',\n    'min' => ':count min.',\n    'second' => ':count sekund|:count sekunder',\n    'a_second' => 'få sekunder|:count sekunder',\n    's' => ':count s.',\n    'ago' => 'for :time siden',\n    'from_now' => 'om :time',\n    'after' => ':time efter',\n    'before' => ':time før',\n    'diff_now' => 'nu',\n    'diff_today' => 'i dag',\n    'diff_today_regexp' => 'i dag(?:\\\\s+kl.)?',\n    'diff_yesterday' => 'i går',\n    'diff_yesterday_regexp' => 'i går(?:\\\\s+kl.)?',\n    'diff_tomorrow' => 'i morgen',\n    'diff_tomorrow_regexp' => 'i morgen(?:\\\\s+kl.)?',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD.MM.YYYY',\n        'LL' => 'D. MMMM YYYY',\n        'LLL' => 'D. MMMM YYYY HH:mm',\n        'LLLL' => 'dddd [d.] D. MMMM YYYY [kl.] HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[i dag kl.] LT',\n        'nextDay' => '[i morgen kl.] LT',\n        'nextWeek' => 'på dddd [kl.] LT',\n        'lastDay' => '[i går kl.] LT',\n        'lastWeek' => '[i] dddd[s kl.] LT',\n        'sameElse' => 'L',\n    ],\n    'ordinal' => ':number.',\n    'months' => ['januar', 'februar', 'marts', 'april', 'maj', 'juni', 'juli', 'august', 'september', 'oktober', 'november', 'december'],\n    'months_short' => ['jan.', 'feb.', 'mar.', 'apr.', 'maj.', 'jun.', 'jul.', 'aug.', 'sep.', 'okt.', 'nov.', 'dec.'],\n    'weekdays' => ['søndag', 'mandag', 'tirsdag', 'onsdag', 'torsdag', 'fredag', 'lørdag'],\n    'weekdays_short' => ['søn.', 'man.', 'tir.', 'ons.', 'tor.', 'fre.', 'lør.'],\n    'weekdays_min' => ['sø', 'ma', 'ti', 'on', 'to', 'fr', 'lø'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n    'list' => [', ', ' og '],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/da_DK.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/da.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/da_GL.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/da.php', [\n    'formats' => [\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D. MMM YYYY',\n        'LLL' => 'D. MMMM YYYY HH.mm',\n        'LLLL' => 'dddd [den] D. MMMM YYYY HH.mm',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/dav.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'meridiem' => ['Luma lwa K', 'luma lwa p'],\n    'weekdays' => ['Ituku ja jumwa', 'Kuramuka jimweri', 'Kuramuka kawi', 'Kuramuka kadadu', 'Kuramuka kana', 'Kuramuka kasanu', 'Kifula nguwo'],\n    'weekdays_short' => ['Jum', 'Jim', 'Kaw', 'Kad', 'Kan', 'Kas', 'Ngu'],\n    'weekdays_min' => ['Jum', 'Jim', 'Kaw', 'Kad', 'Kan', 'Kas', 'Ngu'],\n    'months' => ['Mori ghwa imbiri', 'Mori ghwa kawi', 'Mori ghwa kadadu', 'Mori ghwa kana', 'Mori ghwa kasanu', 'Mori ghwa karandadu', 'Mori ghwa mfungade', 'Mori ghwa wunyanya', 'Mori ghwa ikenda', 'Mori ghwa ikumi', 'Mori ghwa ikumi na imweri', 'Mori ghwa ikumi na iwi'],\n    'months_short' => ['Imb', 'Kaw', 'Kad', 'Kan', 'Kas', 'Kar', 'Mfu', 'Wun', 'Ike', 'Iku', 'Imw', 'Iwi'],\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY HH:mm',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/de.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Michael Hohl\n * - sheriffmarley\n * - dennisoderwald\n * - Timo\n * - Karag2006\n * - Pete Scopes (pdscopes)\n */\nreturn [\n    'year' => ':count Jahr|:count Jahre',\n    'a_year' => 'ein Jahr|:count Jahre',\n    'y' => ':count J.',\n    'month' => ':count Monat|:count Monate',\n    'a_month' => 'ein Monat|:count Monate',\n    'm' => ':count Mon.',\n    'week' => ':count Woche|:count Wochen',\n    'a_week' => 'eine Woche|:count Wochen',\n    'w' => ':count Wo.',\n    'day' => ':count Tag|:count Tage',\n    'a_day' => 'ein Tag|:count Tage',\n    'd' => ':count Tg.',\n    'hour' => ':count Stunde|:count Stunden',\n    'a_hour' => 'eine Stunde|:count Stunden',\n    'h' => ':count Std.',\n    'minute' => ':count Minute|:count Minuten',\n    'a_minute' => 'eine Minute|:count Minuten',\n    'min' => ':count Min.',\n    'second' => ':count Sekunde|:count Sekunden',\n    'a_second' => 'ein paar Sekunden|:count Sekunden',\n    's' => ':count Sek.',\n    'millisecond' => ':count Millisekunde|:count Millisekunden',\n    'a_millisecond' => 'eine Millisekunde|:count Millisekunden',\n    'ms' => ':countms',\n    'microsecond' => ':count Mikrosekunde|:count Mikrosekunden',\n    'a_microsecond' => 'eine Mikrosekunde|:count Mikrosekunden',\n    'µs' => ':countµs',\n    'ago' => 'vor :time',\n    'from_now' => 'in :time',\n    'after' => ':time später',\n    'before' => ':time zuvor',\n\n    'year_from_now' => ':count Jahr|:count Jahren',\n    'month_from_now' => ':count Monat|:count Monaten',\n    'week_from_now' => ':count Woche|:count Wochen',\n    'day_from_now' => ':count Tag|:count Tagen',\n    'year_ago' => ':count Jahr|:count Jahren',\n    'month_ago' => ':count Monat|:count Monaten',\n    'week_ago' => ':count Woche|:count Wochen',\n    'day_ago' => ':count Tag|:count Tagen',\n    'a_year_from_now' => 'ein Jahr|:count Jahren',\n    'a_month_from_now' => 'ein Monat|:count Monaten',\n    'a_week_from_now' => 'eine Woche|:count Wochen',\n    'a_day_from_now' => 'ein Tag|:count Tagen',\n    'a_year_ago' => 'ein Jahr|:count Jahren',\n    'a_month_ago' => 'ein Monat|:count Monaten',\n    'a_week_ago' => 'eine Woche|:count Wochen',\n    'a_day_ago' => 'ein Tag|:count Tagen',\n\n    'diff_now' => 'Gerade eben',\n    'diff_today' => 'heute',\n    'diff_today_regexp' => 'heute(?:\\\\s+um)?',\n    'diff_yesterday' => 'Gestern',\n    'diff_yesterday_regexp' => 'gestern(?:\\\\s+um)?',\n    'diff_tomorrow' => 'Morgen',\n    'diff_tomorrow_regexp' => 'morgen(?:\\\\s+um)?',\n    'diff_before_yesterday' => 'Vorgestern',\n    'diff_after_tomorrow' => 'Übermorgen',\n\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD.MM.YYYY',\n        'LL' => 'D. MMMM YYYY',\n        'LLL' => 'D. MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D. MMMM YYYY HH:mm',\n    ],\n\n    'calendar' => [\n        'sameDay' => '[heute um] LT [Uhr]',\n        'nextDay' => '[morgen um] LT [Uhr]',\n        'nextWeek' => 'dddd [um] LT [Uhr]',\n        'lastDay' => '[gestern um] LT [Uhr]',\n        'lastWeek' => '[letzten] dddd [um] LT [Uhr]',\n        'sameElse' => 'L',\n    ],\n\n    'months' => ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'],\n    'months_short' => ['Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'],\n    'weekdays' => ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'],\n    'weekdays_short' => ['So.', 'Mo.', 'Di.', 'Mi.', 'Do.', 'Fr.', 'Sa.'],\n    'weekdays_min' => ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa'],\n    'ordinal' => ':number.',\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n    'list' => [', ', ' und '],\n    'ordinal_words' => [\n        'of' => 'im',\n        'first' => 'erster',\n        'second' => 'zweiter',\n        'third' => 'dritter',\n        'fourth' => 'vierten',\n        'fifth' => 'fünfter',\n        'last' => 'letzten',\n    ],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/de_AT.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - sheriffmarley\n * - Timo\n * - Michael Hohl\n * - Namoshek\n * - Bernhard Baumrock (BernhardBaumrock)\n */\nreturn array_replace_recursive(require __DIR__.'/de.php', [\n    'months' => [\n        0 => 'Jänner',\n    ],\n    'months_short' => [\n        0 => 'Jän',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/de_BE.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - RAP    bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/de.php', [\n    'formats' => [\n        'L' => 'YYYY-MM-DD',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/de_CH.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - sheriffmarley\n * - Timo\n * - Michael Hohl\n */\nreturn array_replace_recursive(require __DIR__.'/de.php', [\n    'weekdays_short' => ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/de_DE.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Free Software Foundation, Inc.    bug-glibc-locales@gnu.org\n */\nreturn require __DIR__.'/de.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/de_IT.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Matthias Dieter Wallno:fer libc-locales@sourceware.org\n */\nreturn require __DIR__.'/de.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/de_LI.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/de.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/de_LU.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - RAP    bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/de.php', [\n    'formats' => [\n        'L' => 'YYYY-MM-DD',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/dje.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'meridiem' => ['Subbaahi', 'Zaarikay b'],\n    'weekdays' => ['Alhadi', 'Atinni', 'Atalaata', 'Alarba', 'Alhamisi', 'Alzuma', 'Asibti'],\n    'weekdays_short' => ['Alh', 'Ati', 'Ata', 'Ala', 'Alm', 'Alz', 'Asi'],\n    'weekdays_min' => ['Alh', 'Ati', 'Ata', 'Ala', 'Alm', 'Alz', 'Asi'],\n    'months' => ['Žanwiye', 'Feewiriye', 'Marsi', 'Awiril', 'Me', 'Žuweŋ', 'Žuyye', 'Ut', 'Sektanbur', 'Oktoobur', 'Noowanbur', 'Deesanbur'],\n    'months_short' => ['Žan', 'Fee', 'Mar', 'Awi', 'Me', 'Žuw', 'Žuy', 'Ut', 'Sek', 'Okt', 'Noo', 'Dee'],\n    'first_day_of_week' => 1,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'D/M/YYYY',\n        'LL' => 'D MMM, YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd D MMMM YYYY HH:mm',\n    ],\n\n    'year' => ':count hari', // less reliable\n    'y' => ':count hari', // less reliable\n    'a_year' => ':count hari', // less reliable\n\n    'week' => ':count alzuma', // less reliable\n    'w' => ':count alzuma', // less reliable\n    'a_week' => ':count alzuma', // less reliable\n\n    'second' => ':count atinni', // less reliable\n    's' => ':count atinni', // less reliable\n    'a_second' => ':count atinni', // less reliable\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/doi.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/doi_IN.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/doi_IN.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Red Hat Pune    libc-alpha@sourceware.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'D/M/YY',\n    ],\n    'months' => ['जनवरी', 'फरवरी', 'मार्च', 'एप्रैल', 'मेई', 'जून', 'जूलै', 'अगस्त', 'सितंबर', 'अक्तूबर', 'नवंबर', 'दिसंबर'],\n    'months_short' => ['जनवरी', 'फरवरी', 'मार्च', 'एप्रैल', 'मेई', 'जून', 'जूलै', 'अगस्त', 'सितंबर', 'अक्तूबर', 'नवंबर', 'दिसंबर'],\n    'weekdays' => ['ऐतबार', 'सोमबार', 'मंगलबर', 'बुधबार', 'बीरबार', 'शुक्करबार', 'श्नीचरबार'],\n    'weekdays_short' => ['ऐत', 'सोम', 'मंगल', 'बुध', 'बीर', 'शुक्कर', 'श्नीचर'],\n    'weekdays_min' => ['ऐत', 'सोम', 'मंगल', 'बुध', 'बीर', 'शुक्कर', 'श्नीचर'],\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['सञं', 'सबेर'],\n\n    'second' => ':count सङार', // less reliable\n    's' => ':count सङार', // less reliable\n    'a_second' => ':count सङार', // less reliable\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/dsb.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/dsb_DE.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/dsb_DE.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Information from Michael Wolf    bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD.MM.YYYY',\n        'LL' => 'DD. MMMM YYYY',\n        'LLL' => 'DD. MMMM, HH:mm [góź.]',\n        'LLLL' => 'dddd, DD. MMMM YYYY, HH:mm [góź.]',\n    ],\n    'months' => ['januara', 'februara', 'měrca', 'apryla', 'maja', 'junija', 'julija', 'awgusta', 'septembra', 'oktobra', 'nowembra', 'decembra'],\n    'months_short' => ['Jan', 'Feb', 'Měr', 'Apr', 'Maj', 'Jun', 'Jul', 'Awg', 'Sep', 'Okt', 'Now', 'Dec'],\n    'weekdays' => ['Njeźela', 'Pónjeźele', 'Wałtora', 'Srjoda', 'Stwórtk', 'Pětk', 'Sobota'],\n    'weekdays_short' => ['Nj', 'Pó', 'Wa', 'Sr', 'St', 'Pě', 'So'],\n    'weekdays_min' => ['Nj', 'Pó', 'Wa', 'Sr', 'St', 'Pě', 'So'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n\n    'year' => ':count lěto',\n    'y' => ':count lěto',\n    'a_year' => ':count lěto',\n\n    'month' => ':count mjasec',\n    'm' => ':count mjasec',\n    'a_month' => ':count mjasec',\n\n    'week' => ':count tyźeń',\n    'w' => ':count tyźeń',\n    'a_week' => ':count tyźeń',\n\n    'day' => ':count źeń',\n    'd' => ':count źeń',\n    'a_day' => ':count źeń',\n\n    'hour' => ':count góźina',\n    'h' => ':count góźina',\n    'a_hour' => ':count góźina',\n\n    'minute' => ':count minuta',\n    'min' => ':count minuta',\n    'a_minute' => ':count minuta',\n\n    'second' => ':count drugi',\n    's' => ':count drugi',\n    'a_second' => ':count drugi',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/dua.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'meridiem' => ['idiɓa', 'ebyámu'],\n    'weekdays' => ['éti', 'mɔ́sú', 'kwasú', 'mukɔ́sú', 'ŋgisú', 'ɗónɛsú', 'esaɓasú'],\n    'weekdays_short' => ['ét', 'mɔ́s', 'kwa', 'muk', 'ŋgi', 'ɗón', 'esa'],\n    'weekdays_min' => ['ét', 'mɔ́s', 'kwa', 'muk', 'ŋgi', 'ɗón', 'esa'],\n    'months' => ['dimɔ́di', 'ŋgɔndɛ', 'sɔŋɛ', 'diɓáɓá', 'emiasele', 'esɔpɛsɔpɛ', 'madiɓɛ́díɓɛ́', 'diŋgindi', 'nyɛtɛki', 'mayésɛ́', 'tiníní', 'eláŋgɛ́'],\n    'months_short' => ['di', 'ŋgɔn', 'sɔŋ', 'diɓ', 'emi', 'esɔ', 'mad', 'diŋ', 'nyɛt', 'may', 'tin', 'elá'],\n    'first_day_of_week' => 1,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'D/M/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd D MMMM YYYY HH:mm',\n    ],\n\n    'year' => ':count ma mbu', // less reliable\n    'y' => ':count ma mbu', // less reliable\n    'a_year' => ':count ma mbu', // less reliable\n\n    'month' => ':count myo̱di', // less reliable\n    'm' => ':count myo̱di', // less reliable\n    'a_month' => ':count myo̱di', // less reliable\n\n    'week' => ':count woki', // less reliable\n    'w' => ':count woki', // less reliable\n    'a_week' => ':count woki', // less reliable\n\n    'day' => ':count buńa', // less reliable\n    'd' => ':count buńa', // less reliable\n    'a_day' => ':count buńa', // less reliable\n\n    'hour' => ':count ma awa', // less reliable\n    'h' => ':count ma awa', // less reliable\n    'a_hour' => ':count ma awa', // less reliable\n\n    'minute' => ':count minuti', // less reliable\n    'min' => ':count minuti', // less reliable\n    'a_minute' => ':count minuti', // less reliable\n\n    'second' => ':count maba', // less reliable\n    's' => ':count maba', // less reliable\n    'a_second' => ':count maba', // less reliable\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/dv.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n$months = [\n    'ޖެނުއަރީ',\n    'ފެބްރުއަރީ',\n    'މާރިޗު',\n    'އޭޕްރީލު',\n    'މޭ',\n    'ޖޫން',\n    'ޖުލައި',\n    'އޯގަސްޓު',\n    'ސެޕްޓެމްބަރު',\n    'އޮކްޓޯބަރު',\n    'ނޮވެމްބަރު',\n    'ޑިސެމްބަރު',\n];\n\n$weekdays = [\n    'އާދިއްތަ',\n    'ހޯމަ',\n    'އަންގާރަ',\n    'ބުދަ',\n    'ބުރާސްފަތި',\n    'ހުކުރު',\n    'ހޮނިހިރު',\n];\n\n/*\n * Authors:\n * - Josh Soref\n * - Jawish Hameed\n */\nreturn [\n    'year' => ':count '.'އަހަރު',\n    'a_year' => '{1}'.'އަހަރެއް'.'|:count '.'އަހަރު',\n    'month' => ':count '.'މަސް',\n    'a_month' => '{1}'.'މަހެއް'.'|:count '.'މަސް',\n    'week' => ':count '.'ހަފްތާ',\n    'a_week' => '{1}'.'ސިކުންތުކޮޅެއް'.'|:count '.'ހަފްތާ',\n    'day' => ':count '.'ދުވަސް',\n    'a_day' => '{1}'.'ދުވަހެއް'.'|:count '.'ދުވަސް',\n    'hour' => ':count '.'ގަޑިއިރު',\n    'a_hour' => '{1}'.'ގަޑިއިރެއް'.'|:count '.'ގަޑިއިރު',\n    'minute' => ':count '.'މިނިޓު',\n    'a_minute' => '{1}'.'މިނިޓެއް'.'|:count '.'މިނިޓު',\n    'second' => ':count '.'ސިކުންތު',\n    'a_second' => '{1}'.'ސިކުންތުކޮޅެއް'.'|:count '.'ސިކުންތު',\n    'ago' => 'ކުރިން :time',\n    'from_now' => 'ތެރޭގައި :time',\n    'after' => ':time ފަހުން',\n    'before' => ':time ކުރި',\n    'diff_yesterday' => 'އިއްޔެ',\n    'diff_today' => 'މިއަދު',\n    'diff_tomorrow' => 'މާދަމާ',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'D/M/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd D MMMM YYYY HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[މިއަދު] LT',\n        'nextDay' => '[މާދަމާ] LT',\n        'nextWeek' => 'dddd LT',\n        'lastDay' => '[އިއްޔެ] LT',\n        'lastWeek' => '[ފާއިތުވި] dddd LT',\n        'sameElse' => 'L',\n    ],\n    'meridiem' => ['މކ', 'މފ'],\n    'months' => $months,\n    'months_short' => $months,\n    'weekdays' => $weekdays,\n    'weekdays_short' => $weekdays,\n    'weekdays_min' => ['އާދި', 'ހޯމަ', 'އަން', 'ބުދަ', 'ބުރާ', 'ހުކު', 'ހޮނި'],\n    'list' => [', ', ' އަދި '],\n    'first_day_of_week' => 0,\n    'day_of_first_week_of_year' => 1,\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/dv_MV.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Ahmed Ali\n */\n\n$months = [\n    'ޖެނުއަރީ',\n    'ފެބްރުއަރީ',\n    'މާރިޗު',\n    'އޭޕްރީލު',\n    'މޭ',\n    'ޖޫން',\n    'ޖުލައި',\n    'އޯގަސްޓު',\n    'ސެޕްޓެމްބަރު',\n    'އޮކްޓޯބަރު',\n    'ނޮވެމްބަރު',\n    'ޑިސެމްބަރު',\n];\n\n$weekdays = [\n    'އާދިއްތަ',\n    'ހޯމަ',\n    'އަންގާރަ',\n    'ބުދަ',\n    'ބުރާސްފަތި',\n    'ހުކުރު',\n    'ހޮނިހިރު',\n];\n\nreturn [\n    'year' => '{0}އަހަރެއް|[1,Inf]:count އަހަރު',\n    'y' => '{0}އަހަރެއް|[1,Inf]:count އަހަރު',\n    'month' => '{0}މައްސަރެއް|[1,Inf]:count މަސް',\n    'm' => '{0}މައްސަރެއް|[1,Inf]:count މަސް',\n    'week' => '{0}ހަފްތާއެއް|[1,Inf]:count ހަފްތާ',\n    'w' => '{0}ހަފްތާއެއް|[1,Inf]:count ހަފްތާ',\n    'day' => '{0}ދުވަސް|[1,Inf]:count ދުވަސް',\n    'd' => '{0}ދުވަސް|[1,Inf]:count ދުވަސް',\n    'hour' => '{0}ގަޑިއިރެއް|[1,Inf]:count ގަޑި',\n    'h' => '{0}ގަޑިއިރެއް|[1,Inf]:count ގަޑި',\n    'minute' => '{0}މިނެޓެއް|[1,Inf]:count މިނެޓް',\n    'min' => '{0}މިނެޓެއް|[1,Inf]:count މިނެޓް',\n    'second' => '{0}ސިކުންތެއް|[1,Inf]:count ސިކުންތު',\n    's' => '{0}ސިކުންތެއް|[1,Inf]:count ސިކުންތު',\n    'ago' => ':time ކުރިން',\n    'from_now' => ':time ފަހުން',\n    'after' => ':time ފަހުން',\n    'before' => ':time ކުރި',\n    'diff_yesterday' => 'އިއްޔެ',\n    'diff_today' => 'މިއަދު',\n    'diff_tomorrow' => 'މާދަމާ',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'D/M/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd D MMMM YYYY HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[މިއަދު] LT',\n        'nextDay' => '[މާދަމާ] LT',\n        'nextWeek' => 'dddd LT',\n        'lastDay' => '[އިއްޔެ] LT',\n        'lastWeek' => '[ފާއިތުވި] dddd LT',\n        'sameElse' => 'L',\n    ],\n    'meridiem' => ['މކ', 'މފ'],\n    'months' => $months,\n    'months_short' => $months,\n    'weekdays' => $weekdays,\n    'weekdays_short' => $weekdays,\n    'weekdays_min' => ['އާދި', 'ހޯމަ', 'އަން', 'ބުދަ', 'ބުރާ', 'ހުކު', 'ހޮނި'],\n    'list' => [', ', ' އަދި '],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/dyo.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'weekdays' => ['Dimas', 'Teneŋ', 'Talata', 'Alarbay', 'Aramisay', 'Arjuma', 'Sibiti'],\n    'weekdays_short' => ['Dim', 'Ten', 'Tal', 'Ala', 'Ara', 'Arj', 'Sib'],\n    'weekdays_min' => ['Dim', 'Ten', 'Tal', 'Ala', 'Ara', 'Arj', 'Sib'],\n    'months' => ['Sanvie', 'Fébirie', 'Mars', 'Aburil', 'Mee', 'Sueŋ', 'Súuyee', 'Ut', 'Settembar', 'Oktobar', 'Novembar', 'Disambar'],\n    'months_short' => ['Sa', 'Fe', 'Ma', 'Ab', 'Me', 'Su', 'Sú', 'Ut', 'Se', 'Ok', 'No', 'De'],\n    'first_day_of_week' => 1,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'D/M/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd D MMMM YYYY HH:mm',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/dz.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/dz_BT.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/dz_BT.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Sherubtse College    bug-glibc@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'པསྱི་ལོYYཟལMMཚེསDD',\n    ],\n    'months' => ['ཟླ་བ་དང་པ་', 'ཟླ་བ་གཉིས་པ་', 'ཟླ་བ་གསུམ་པ་', 'ཟླ་བ་བཞི་པ་', 'ཟླ་བ་ལྔ་ཕ་', 'ཟླ་བ་དྲུག་པ་', 'ཟླ་བ་བདུནཔ་', 'ཟླ་བ་བརྒྱད་པ་', 'ཟླ་བ་དགུ་པ་', 'ཟླ་བ་བཅུ་པ་', 'ཟླ་བ་བཅུ་གཅིག་པ་', 'ཟླ་བ་བཅུ་གཉིས་པ་'],\n    'months_short' => ['ཟླ་༡', 'ཟླ་༢', 'ཟླ་༣', 'ཟླ་༤', 'ཟླ་༥', 'ཟླ་༦', 'ཟླ་༧', 'ཟླ་༨', 'ཟླ་༩', 'ཟླ་༡༠', 'ཟླ་༡༡', 'ཟླ་༡༢'],\n    'weekdays' => ['གཟའ་ཟླ་བ་', 'གཟའ་མིག་དམར་', 'གཟའ་ལྷག་ཕ་', 'གཟའ་པུར་བུ་', 'གཟའ་པ་སངས་', 'གཟའ་སྤེན་ཕ་', 'གཟའ་ཉི་མ་'],\n    'weekdays_short' => ['ཟླ་', 'མིར་', 'ལྷག་', 'པུར་', 'སངས་', 'སྤེན་', 'ཉི་'],\n    'weekdays_min' => ['ཟླ་', 'མིར་', 'ལྷག་', 'པུར་', 'སངས་', 'སྤེན་', 'ཉི་'],\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['ངས་ཆ', 'ཕྱི་ཆ'],\n\n    'year' => ':count ཆརཔ', // less reliable\n    'y' => ':count ཆརཔ', // less reliable\n    'a_year' => ':count ཆརཔ', // less reliable\n\n    'month' => ':count ཟླ་བ', // less reliable\n    'm' => ':count ཟླ་བ', // less reliable\n    'a_month' => ':count ཟླ་བ', // less reliable\n\n    'day' => ':count ཉི', // less reliable\n    'd' => ':count ཉི', // less reliable\n    'a_day' => ':count ཉི', // less reliable\n\n    'second' => ':count ཆ', // less reliable\n    's' => ':count ཆ', // less reliable\n    'a_second' => ':count ཆ', // less reliable\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ebu.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'meridiem' => ['KI', 'UT'],\n    'weekdays' => ['Kiumia', 'Njumatatu', 'Njumaine', 'Njumatano', 'Aramithi', 'Njumaa', 'NJumamothii'],\n    'weekdays_short' => ['Kma', 'Tat', 'Ine', 'Tan', 'Arm', 'Maa', 'NMM'],\n    'weekdays_min' => ['Kma', 'Tat', 'Ine', 'Tan', 'Arm', 'Maa', 'NMM'],\n    'months' => ['Mweri wa mbere', 'Mweri wa kaĩri', 'Mweri wa kathatũ', 'Mweri wa kana', 'Mweri wa gatano', 'Mweri wa gatantatũ', 'Mweri wa mũgwanja', 'Mweri wa kanana', 'Mweri wa kenda', 'Mweri wa ikũmi', 'Mweri wa ikũmi na ũmwe', 'Mweri wa ikũmi na Kaĩrĩ'],\n    'months_short' => ['Mbe', 'Kai', 'Kat', 'Kan', 'Gat', 'Gan', 'Mug', 'Knn', 'Ken', 'Iku', 'Imw', 'Igi'],\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY HH:mm',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ee.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'meridiem' => ['ŋ', 'ɣ'],\n    'weekdays' => ['kɔsiɖa', 'dzoɖa', 'blaɖa', 'kuɖa', 'yawoɖa', 'fiɖa', 'memleɖa'],\n    'weekdays_short' => ['kɔs', 'dzo', 'bla', 'kuɖ', 'yaw', 'fiɖ', 'mem'],\n    'weekdays_min' => ['kɔs', 'dzo', 'bla', 'kuɖ', 'yaw', 'fiɖ', 'mem'],\n    'months' => ['dzove', 'dzodze', 'tedoxe', 'afɔfĩe', 'dama', 'masa', 'siamlɔm', 'deasiamime', 'anyɔnyɔ', 'kele', 'adeɛmekpɔxe', 'dzome'],\n    'months_short' => ['dzv', 'dzd', 'ted', 'afɔ', 'dam', 'mas', 'sia', 'dea', 'any', 'kel', 'ade', 'dzm'],\n    'first_day_of_week' => 1,\n    'formats' => [\n        'LT' => 'a [ga] h:mm',\n        'LTS' => 'a [ga] h:mm:ss',\n        'L' => 'M/D/YYYY',\n        'LL' => 'MMM D [lia], YYYY',\n        'LLL' => 'a [ga] h:mm MMMM D [lia] YYYY',\n        'LLLL' => 'a [ga] h:mm dddd, MMMM D [lia] YYYY',\n    ],\n\n    'year' => 'ƒe :count',\n    'y' => 'ƒe :count',\n    'a_year' => 'ƒe :count',\n\n    'month' => 'ɣleti :count',\n    'm' => 'ɣleti :count',\n    'a_month' => 'ɣleti :count',\n\n    'week' => 'kwasiɖa :count',\n    'w' => 'kwasiɖa :count',\n    'a_week' => 'kwasiɖa :count',\n\n    'day' => 'ŋkeke :count',\n    'd' => 'ŋkeke :count',\n    'a_day' => 'ŋkeke :count',\n\n    'hour' => 'gaƒoƒo :count',\n    'h' => 'gaƒoƒo :count',\n    'a_hour' => 'gaƒoƒo :count',\n\n    'minute' => 'miniti :count', // less reliable\n    'min' => 'miniti :count', // less reliable\n    'a_minute' => 'miniti :count', // less reliable\n\n    'second' => 'sɛkɛnd :count', // less reliable\n    's' => 'sɛkɛnd :count', // less reliable\n    'a_second' => 'sɛkɛnd :count', // less reliable\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ee_TG.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/ee.php', [\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'LLL' => 'HH:mm MMMM D [lia] YYYY',\n        'LLLL' => 'HH:mm dddd, MMMM D [lia] YYYY',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/el.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Alessandro Di Felice\n * - François B\n * - Tim Fish\n * - Gabriel Monteagudo\n * - JD Isaacks\n * - yiannisdesp\n * - Ilias Kasmeridis (iliaskasm)\n */\n\nuse Carbon\\CarbonInterface;\n\nreturn [\n    'year' => ':count χρόνος|:count χρόνια',\n    'a_year' => 'ένας χρόνος|:count χρόνια',\n    'y' => ':count χρ.',\n    'month' => ':count μήνας|:count μήνες',\n    'a_month' => 'ένας μήνας|:count μήνες',\n    'm' => ':count μήν.',\n    'week' => ':count εβδομάδα|:count εβδομάδες',\n    'a_week' => 'μια εβδομάδα|:count εβδομάδες',\n    'w' => ':count εβδ.',\n    'day' => ':count μέρα|:count μέρες',\n    'a_day' => 'μία μέρα|:count μέρες',\n    'd' => ':count μέρ.',\n    'hour' => ':count ώρα|:count ώρες',\n    'a_hour' => 'μία ώρα|:count ώρες',\n    'h' => ':count ώρα|:count ώρες',\n    'minute' => ':count λεπτό|:count λεπτά',\n    'a_minute' => 'ένα λεπτό|:count λεπτά',\n    'min' => ':count λεπ.',\n    'second' => ':count δευτερόλεπτο|:count δευτερόλεπτα',\n    'a_second' => 'λίγα δευτερόλεπτα|:count δευτερόλεπτα',\n    's' => ':count δευ.',\n    'ago' => 'πριν :time',\n    'from_now' => 'σε :time',\n    'after' => ':time μετά',\n    'before' => ':time πριν',\n    'diff_now' => 'τώρα',\n    'diff_today' => 'Σήμερα',\n    'diff_today_regexp' => 'Σήμερα(?:\\\\s+{})?',\n    'diff_yesterday' => 'χθες',\n    'diff_yesterday_regexp' => 'Χθες(?:\\\\s+{})?',\n    'diff_tomorrow' => 'αύριο',\n    'diff_tomorrow_regexp' => 'Αύριο(?:\\\\s+{})?',\n    'formats' => [\n        'LT' => 'h:mm A',\n        'LTS' => 'h:mm:ss A',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY h:mm A',\n        'LLLL' => 'dddd, D MMMM YYYY h:mm A',\n    ],\n    'calendar' => [\n        'sameDay' => '[Σήμερα {}] LT',\n        'nextDay' => '[Αύριο {}] LT',\n        'nextWeek' => 'dddd [{}] LT',\n        'lastDay' => '[Χθες {}] LT',\n        'lastWeek' => function (CarbonInterface $current) {\n            switch ($current->dayOfWeek) {\n                case 6:\n                    return '[το προηγούμενο] dddd [{}] LT';\n                default:\n                    return '[την προηγούμενη] dddd [{}] LT';\n            }\n        },\n        'sameElse' => 'L',\n    ],\n    'ordinal' => ':numberη',\n    'meridiem' => ['ΠΜ', 'ΜΜ', 'πμ', 'μμ'],\n    'months' => ['Ιανουαρίου', 'Φεβρουαρίου', 'Μαρτίου', 'Απριλίου', 'Μαΐου', 'Ιουνίου', 'Ιουλίου', 'Αυγούστου', 'Σεπτεμβρίου', 'Οκτωβρίου', 'Νοεμβρίου', 'Δεκεμβρίου'],\n    'months_standalone' => ['Ιανουάριος', 'Φεβρουάριος', 'Μάρτιος', 'Απρίλιος', 'Μάιος', 'Ιούνιος', 'Ιούλιος', 'Αύγουστος', 'Σεπτέμβριος', 'Οκτώβριος', 'Νοέμβριος', 'Δεκέμβριος'],\n    'months_regexp' => '/(D[oD]?[\\s,]+MMMM|L{2,4}|l{2,4})/',\n    'months_short' => ['Ιαν', 'Φεβ', 'Μαρ', 'Απρ', 'Μαϊ', 'Ιουν', 'Ιουλ', 'Αυγ', 'Σεπ', 'Οκτ', 'Νοε', 'Δεκ'],\n    'weekdays' => ['Κυριακή', 'Δευτέρα', 'Τρίτη', 'Τετάρτη', 'Πέμπτη', 'Παρασκευή', 'Σάββατο'],\n    'weekdays_short' => ['Κυρ', 'Δευ', 'Τρι', 'Τετ', 'Πεμ', 'Παρ', 'Σαβ'],\n    'weekdays_min' => ['Κυ', 'Δε', 'Τρ', 'Τε', 'Πε', 'Πα', 'Σα'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n    'list' => [', ', ' και '],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/el_CY.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Greek Debian Translation Team    bug-glibc@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/el.php', [\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/el_GR.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - RAP    bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/el.php', [\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Milos Sakovic\n * - Paul\n * - Pete Scopes (pdscopes)\n */\nreturn [\n    /*\n     * {1}, {0} and ]1,Inf[ are not needed as it's the default for English pluralization.\n     * But as some languages are using en.php as a fallback, it's better to specify it\n     * explicitly so those languages also fallback to English pluralization when a unit\n     * is missing.\n     */\n    'year' => '{1}:count year|{0}:count years|]1,Inf[:count years',\n    'a_year' => '{1}a year|{0}:count years|]1,Inf[:count years',\n    'y' => '{1}:countyr|{0}:countyrs|]1,Inf[:countyrs',\n    'month' => '{1}:count month|{0}:count months|]1,Inf[:count months',\n    'a_month' => '{1}a month|{0}:count months|]1,Inf[:count months',\n    'm' => '{1}:countmo|{0}:countmos|]1,Inf[:countmos',\n    'week' => '{1}:count week|{0}:count weeks|]1,Inf[:count weeks',\n    'a_week' => '{1}a week|{0}:count weeks|]1,Inf[:count weeks',\n    'w' => ':countw',\n    'day' => '{1}:count day|{0}:count days|]1,Inf[:count days',\n    'a_day' => '{1}a day|{0}:count days|]1,Inf[:count days',\n    'd' => ':countd',\n    'hour' => '{1}:count hour|{0}:count hours|]1,Inf[:count hours',\n    'a_hour' => '{1}an hour|{0}:count hours|]1,Inf[:count hours',\n    'h' => ':counth',\n    'minute' => '{1}:count minute|{0}:count minutes|]1,Inf[:count minutes',\n    'a_minute' => '{1}a minute|{0}:count minutes|]1,Inf[:count minutes',\n    'min' => ':countm',\n    'second' => '{1}:count second|{0}:count seconds|]1,Inf[:count seconds',\n    'a_second' => '{1}a few seconds|{0}:count seconds|]1,Inf[:count seconds',\n    's' => ':counts',\n    'millisecond' => '{1}:count millisecond|{0}:count milliseconds|]1,Inf[:count milliseconds',\n    'a_millisecond' => '{1}a millisecond|{0}:count milliseconds|]1,Inf[:count milliseconds',\n    'ms' => ':countms',\n    'microsecond' => '{1}:count microsecond|{0}:count microseconds|]1,Inf[:count microseconds',\n    'a_microsecond' => '{1}a microsecond|{0}:count microseconds|]1,Inf[:count microseconds',\n    'µs' => ':countµs',\n    'ago' => ':time ago',\n    'from_now' => ':time from now',\n    'after' => ':time after',\n    'before' => ':time before',\n    'diff_now' => 'just now',\n    'diff_today' => 'today',\n    'diff_yesterday' => 'yesterday',\n    'diff_tomorrow' => 'tomorrow',\n    'diff_before_yesterday' => 'before yesterday',\n    'diff_after_tomorrow' => 'after tomorrow',\n    'period_recurrences' => '{1}once|{0}:count times|]1,Inf[:count times',\n    'period_interval' => 'every :interval',\n    'period_start_date' => 'from :date',\n    'period_end_date' => 'to :date',\n    'months' => ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],\n    'months_short' => ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],\n    'weekdays' => ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],\n    'weekdays_short' => ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],\n    'weekdays_min' => ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'],\n    'ordinal' => function ($number) {\n        $lastDigit = $number % 10;\n\n        return $number.(\n            ((int) ($number % 100 / 10) === 1) ? 'th' : (\n                ($lastDigit === 1) ? 'st' : (\n                    ($lastDigit === 2) ? 'nd' : (\n                        ($lastDigit === 3) ? 'rd' : 'th'\n                    )\n                )\n            )\n        );\n    },\n    'list' => [', ', ' and '],\n    'first_day_of_week' => 0,\n    'day_of_first_week_of_year' => 1,\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_001.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_150.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_AG.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Free Software Foundation, Inc.  bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD/MM/YY',\n    ],\n    'day_of_first_week_of_year' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_AI.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_AS.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/en.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_AT.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_AU.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Kunal Marwaha\n * - François B\n * - Mayank Badola\n * - JD Isaacks\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'from_now' => 'in :time',\n    'formats' => [\n        'LT' => 'h:mm A',\n        'LTS' => 'h:mm:ss A',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY h:mm A',\n        'LLLL' => 'dddd, D MMMM YYYY h:mm A',\n    ],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_BB.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_BE.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_BI.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_BM.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_BS.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/en.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_BW.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/en.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_BZ.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/en.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_CA.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - François B\n * - Zhan Tong Zhang\n * - Mayank Badola\n * - JD Isaacks\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'from_now' => 'in :time',\n    'formats' => [\n        'LT' => 'h:mm A',\n        'LTS' => 'h:mm:ss A',\n        'L' => 'YYYY-MM-DD',\n        'LL' => 'MMMM D, YYYY',\n        'LLL' => 'MMMM D, YYYY h:mm A',\n        'LLLL' => 'dddd, MMMM D, YYYY h:mm A',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_CC.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_CH.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD.MM.YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd D MMMM YYYY HH:mm',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_CK.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_CM.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_CX.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_CY.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - NehaGautam\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'from_now' => 'in :time',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD-MM-YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY HH:mm',\n    ],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_DE.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_DG.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_DK.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Danish Standards Association  bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'YYYY-MM-DD',\n    ],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_DM.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/en.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_ER.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_FI.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_FJ.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_FK.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_FM.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_GB.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - François B\n * - Mayank Badola\n * - JD Isaacks\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'from_now' => 'in :time',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY HH:mm',\n    ],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_GD.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_GG.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_GH.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_GI.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_GM.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_GU.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/en.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_GY.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_HK.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - IBM Globalization Center of Competency, Yamato Software Laboratory  bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'day_of_first_week_of_year' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_IE.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Martin McWhorter\n * - François B\n * - Chris Cartlidge\n * - JD Isaacks\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'from_now' => 'in :time',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD-MM-YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd D MMMM YYYY HH:mm',\n    ],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_IL.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Yoav Amit\n * - François B\n * - Mayank Badola\n * - JD Isaacks\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'from_now' => 'in :time',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY HH:mm',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_IM.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_IN.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - IBM Globalization Center of Competency, Yamato Software Laboratory  bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YY',\n        'LL' => 'MMMM DD, YYYY',\n        'LLL' => 'DD MMM HH:mm',\n        'LLLL' => 'MMMM DD, YYYY HH:mm',\n    ],\n    'day_of_first_week_of_year' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_IO.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_ISO.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'YYYY-MM-dd',\n        'LL' => 'YYYY MMM D',\n        'LLL' => 'YYYY MMMM D HH:mm',\n        'LLLL' => 'dddd, YYYY MMMM DD HH:mm',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_JE.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_JM.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/en.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_KE.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/en.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_KI.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_KN.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_KY.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_LC.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_LR.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_LS.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_MG.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_MH.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/en.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_MO.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/en.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_MP.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_MS.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_MT.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/en.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_MU.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_MW.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_MY.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_NA.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_NF.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_NG.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD/MM/YY',\n    ],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_NL.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_NR.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_NU.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_NZ.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - François B\n * - Mayank Badola\n * - Luke McGregor\n * - JD Isaacks\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'from_now' => 'in :time',\n    'formats' => [\n        'LT' => 'h:mm A',\n        'LTS' => 'h:mm:ss A',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY h:mm A',\n        'LLLL' => 'dddd, D MMMM YYYY h:mm A',\n    ],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_PG.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_PH.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - IBM Globalization Center of Competency, Yamato Software Laboratory  bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'day_of_first_week_of_year' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_PK.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/en.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_PN.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_PR.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/en.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_PW.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_RW.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_SB.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_SC.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_SD.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 6,\n    'weekend' => [5, 6],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_SE.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_SG.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'from_now' => 'in :time',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY HH:mm',\n    ],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_SH.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_SI.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_SL.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_SS.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_SX.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_SZ.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_TC.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_TK.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_TO.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_TT.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/en.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_TV.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_TZ.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_UG.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_UM.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/en.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_US.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/en.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_US_Posix.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/en.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_VC.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_VG.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_VI.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/en.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_VU.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_WS.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/en.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_ZA.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Zuza Software Foundation (Translate.org.za) Dwayne Bailey dwayne@translate.org.za\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YY',\n        'LL' => 'MMMM DD, YYYY',\n        'LLL' => 'DD MMM HH:mm',\n        'LLLL' => 'MMMM DD, YYYY HH:mm',\n    ],\n    'day_of_first_week_of_year' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_ZM.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - ANLoc Martin Benjamin locales@africanlocalization.net\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD/MM/YY',\n    ],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/en_ZW.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/en.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/eo.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Josh Soref\n * - François B\n * - Mia Nordentoft\n * - JD Isaacks\n */\nreturn [\n    'year' => ':count jaro|:count jaroj',\n    'a_year' => 'jaro|:count jaroj',\n    'y' => ':count j.',\n    'month' => ':count monato|:count monatoj',\n    'a_month' => 'monato|:count monatoj',\n    'm' => ':count mo.',\n    'week' => ':count semajno|:count semajnoj',\n    'a_week' => 'semajno|:count semajnoj',\n    'w' => ':count sem.',\n    'day' => ':count tago|:count tagoj',\n    'a_day' => 'tago|:count tagoj',\n    'd' => ':count t.',\n    'hour' => ':count horo|:count horoj',\n    'a_hour' => 'horo|:count horoj',\n    'h' => ':count h.',\n    'minute' => ':count minuto|:count minutoj',\n    'a_minute' => 'minuto|:count minutoj',\n    'min' => ':count min.',\n    'second' => ':count sekundo|:count sekundoj',\n    'a_second' => 'sekundoj|:count sekundoj',\n    's' => ':count sek.',\n    'ago' => 'antaŭ :time',\n    'from_now' => 'post :time',\n    'after' => ':time poste',\n    'before' => ':time antaŭe',\n    'diff_yesterday' => 'Hieraŭ',\n    'diff_yesterday_regexp' => 'Hieraŭ(?:\\\\s+je)?',\n    'diff_today' => 'Hodiaŭ',\n    'diff_today_regexp' => 'Hodiaŭ(?:\\\\s+je)?',\n    'diff_tomorrow' => 'Morgaŭ',\n    'diff_tomorrow_regexp' => 'Morgaŭ(?:\\\\s+je)?',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'YYYY-MM-DD',\n        'LL' => 'D[-a de] MMMM, YYYY',\n        'LLL' => 'D[-a de] MMMM, YYYY HH:mm',\n        'LLLL' => 'dddd, [la] D[-a de] MMMM, YYYY HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[Hodiaŭ je] LT',\n        'nextDay' => '[Morgaŭ je] LT',\n        'nextWeek' => 'dddd [je] LT',\n        'lastDay' => '[Hieraŭ je] LT',\n        'lastWeek' => '[pasinta] dddd [je] LT',\n        'sameElse' => 'L',\n    ],\n    'ordinal' => ':numbera',\n    'meridiem' => ['a.t.m.', 'p.t.m.'],\n    'months' => ['januaro', 'februaro', 'marto', 'aprilo', 'majo', 'junio', 'julio', 'aŭgusto', 'septembro', 'oktobro', 'novembro', 'decembro'],\n    'months_short' => ['jan', 'feb', 'mar', 'apr', 'maj', 'jun', 'jul', 'aŭg', 'sep', 'okt', 'nov', 'dec'],\n    'weekdays' => ['dimanĉo', 'lundo', 'mardo', 'merkredo', 'ĵaŭdo', 'vendredo', 'sabato'],\n    'weekdays_short' => ['dim', 'lun', 'mard', 'merk', 'ĵaŭ', 'ven', 'sab'],\n    'weekdays_min' => ['di', 'lu', 'ma', 'me', 'ĵa', 've', 'sa'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n    'list' => [', ', ' kaj '],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/es.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Kunal Marwaha\n * - kostas\n * - François B\n * - Tim Fish\n * - Claire Coloma\n * - Steven Heinrich\n * - JD Isaacks\n * - Raphael Amorim\n * - Jorge Y. Castillo\n * - Víctor Díaz\n * - Diego\n * - Sebastian Thierer\n * - quinterocesar\n * - Daniel Commesse Liévanos (danielcommesse)\n * - Pete Scopes (pdscopes)\n * - gam04\n */\n\nuse Carbon\\CarbonInterface;\n\nreturn [\n    'year' => ':count año|:count años',\n    'a_year' => 'un año|:count años',\n    'y' => ':count año|:count años',\n    'month' => ':count mes|:count meses',\n    'a_month' => 'un mes|:count meses',\n    'm' => ':count mes|:count meses',\n    'week' => ':count semana|:count semanas',\n    'a_week' => 'una semana|:count semanas',\n    'w' => ':countsem',\n    'day' => ':count día|:count días',\n    'a_day' => 'un día|:count días',\n    'd' => ':countd',\n    'hour' => ':count hora|:count horas',\n    'a_hour' => 'una hora|:count horas',\n    'h' => ':counth',\n    'minute' => ':count minuto|:count minutos',\n    'a_minute' => 'un minuto|:count minutos',\n    'min' => ':countm',\n    'second' => ':count segundo|:count segundos',\n    'a_second' => 'unos segundos|:count segundos',\n    's' => ':counts',\n    'millisecond' => ':count milisegundo|:count milisegundos',\n    'a_millisecond' => 'un milisegundo|:count milisegundos',\n    'ms' => ':countms',\n    'microsecond' => ':count microsegundo|:count microsegundos',\n    'a_microsecond' => 'un microsegundo|:count microsegundos',\n    'µs' => ':countµs',\n    'ago' => 'hace :time',\n    'from_now' => 'en :time',\n    'after' => ':time después',\n    'before' => ':time antes',\n    'diff_now' => 'ahora mismo',\n    'diff_today' => 'hoy',\n    'diff_today_regexp' => 'hoy(?:\\\\s+a)?(?:\\\\s+las)?',\n    'diff_yesterday' => 'ayer',\n    'diff_yesterday_regexp' => 'ayer(?:\\\\s+a)?(?:\\\\s+las)?',\n    'diff_tomorrow' => 'mañana',\n    'diff_tomorrow_regexp' => 'mañana(?:\\\\s+a)?(?:\\\\s+las)?',\n    'diff_before_yesterday' => 'anteayer',\n    'diff_after_tomorrow' => 'pasado mañana',\n    'formats' => [\n        'LT' => 'H:mm',\n        'LTS' => 'H:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D [de] MMMM [de] YYYY',\n        'LLL' => 'D [de] MMMM [de] YYYY H:mm',\n        'LLLL' => 'dddd, D [de] MMMM [de] YYYY H:mm',\n    ],\n    'calendar' => [\n        'sameDay' => function (CarbonInterface $current) {\n            return '[hoy a la'.($current->hour !== 1 ? 's' : '').'] LT';\n        },\n        'nextDay' => function (CarbonInterface $current) {\n            return '[mañana a la'.($current->hour !== 1 ? 's' : '').'] LT';\n        },\n        'nextWeek' => function (CarbonInterface $current) {\n            return 'dddd [a la'.($current->hour !== 1 ? 's' : '').'] LT';\n        },\n        'lastDay' => function (CarbonInterface $current) {\n            return '[ayer a la'.($current->hour !== 1 ? 's' : '').'] LT';\n        },\n        'lastWeek' => function (CarbonInterface $current) {\n            return '[el] dddd [pasado a la'.($current->hour !== 1 ? 's' : '').'] LT';\n        },\n        'sameElse' => 'L',\n    ],\n    'months' => ['enero', 'febrero', 'marzo', 'abril', 'mayo', 'junio', 'julio', 'agosto', 'septiembre', 'octubre', 'noviembre', 'diciembre'],\n    'months_short' => ['ene', 'feb', 'mar', 'abr', 'may', 'jun', 'jul', 'ago', 'sep', 'oct', 'nov', 'dic'],\n    'mmm_suffix' => '.',\n    'ordinal' => ':numberº',\n    'weekdays' => ['domingo', 'lunes', 'martes', 'miércoles', 'jueves', 'viernes', 'sábado'],\n    'weekdays_short' => ['dom.', 'lun.', 'mar.', 'mié.', 'jue.', 'vie.', 'sáb.'],\n    'weekdays_min' => ['do', 'lu', 'ma', 'mi', 'ju', 'vi', 'sá'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n    'list' => [', ', ' y '],\n    'meridiem' => ['a. m.', 'p. m.'],\n    'ordinal_words' => [\n        'of' => 'de',\n        'first' => 'primer',\n        'second' => 'segundo',\n        'third' => 'tercer',\n        'fourth' => 'cuarto',\n        'fifth' => 'quinto',\n        'last' => 'último',\n    ],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/es_419.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - RAP    bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/es.php', [\n    'first_day_of_week' => 0,\n    'day_of_first_week_of_year' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/es_AR.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - RAP    bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/es.php', [\n    'first_day_of_week' => 0,\n    'day_of_first_week_of_year' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/es_BO.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - RAP    bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/es.php', [\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/es_BR.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/es.php', [\n    'first_day_of_week' => 0,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/es_BZ.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/es.php', [\n    'first_day_of_week' => 0,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/es_CL.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - RAP    bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/es.php', [\n    'first_day_of_week' => 0,\n    'day_of_first_week_of_year' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/es_CO.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - RAP    bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/es.php', [\n    'first_day_of_week' => 0,\n    'day_of_first_week_of_year' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/es_CR.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Free Software Foundation, Inc.    bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/es.php', [\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/es_CU.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/es.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/es_DO.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - kostas\n * - François B\n * - Tim Fish\n * - Chiel Robben\n * - Claire Coloma\n * - Steven Heinrich\n * - JD Isaacks\n * - Raphael Amorim\n */\nreturn array_replace_recursive(require __DIR__.'/es.php', [\n    'diff_before_yesterday' => 'anteayer',\n    'formats' => [\n        'LT' => 'h:mm A',\n        'LTS' => 'h:mm:ss A',\n        'LLL' => 'D [de] MMMM [de] YYYY h:mm A',\n        'LLLL' => 'dddd, D [de] MMMM [de] YYYY h:mm A',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/es_EA.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/es.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/es_EC.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - RAP    bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/es.php', [\n    'first_day_of_week' => 0,\n    'day_of_first_week_of_year' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/es_ES.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - RAP    bug-glibc-locales@gnu.org\n */\nreturn require __DIR__.'/es.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/es_GQ.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/es.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/es_GT.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - RAP    bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/es.php', [\n    'first_day_of_week' => 0,\n    'day_of_first_week_of_year' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/es_HN.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - RAP    bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/es.php', [\n    'first_day_of_week' => 0,\n    'day_of_first_week_of_year' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/es_IC.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/es.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/es_MX.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - RAP    bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/es.php', [\n    'diff_before_yesterday' => 'antier',\n    'first_day_of_week' => 0,\n    'day_of_first_week_of_year' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/es_NI.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Free Software Foundation, Inc.    bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/es.php', [\n    'first_day_of_week' => 0,\n    'day_of_first_week_of_year' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/es_PA.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - RAP    bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/es.php', [\n    'first_day_of_week' => 0,\n    'day_of_first_week_of_year' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/es_PE.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - RAP    bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/es.php', [\n    'first_day_of_week' => 0,\n    'day_of_first_week_of_year' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/es_PH.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/es.php', [\n    'first_day_of_week' => 0,\n    'formats' => [\n        'LT' => 'h:mm a',\n        'LTS' => 'h:mm:ss a',\n        'L' => 'D/M/yy',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D [de] MMMM [de] YYYY h:mm a',\n        'LLLL' => 'dddd, D [de] MMMM [de] YYYY h:mm a',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/es_PR.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Free Software Foundation, Inc.    bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/es.php', [\n    'first_day_of_week' => 0,\n    'day_of_first_week_of_year' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/es_PY.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - RAP    bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/es.php', [\n    'first_day_of_week' => 0,\n    'day_of_first_week_of_year' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/es_SV.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - RAP    bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/es.php', [\n    'months' => ['enero', 'febrero', 'marzo', 'abril', 'mayo', 'junio', 'julio', 'agosto', 'septiembre', 'octubre', 'noviembre', 'diciembre'],\n    'months_short' => ['ene', 'feb', 'mar', 'abr', 'may', 'jun', 'jul', 'ago', 'sep', 'oct', 'nov', 'dic'],\n    'day_of_first_week_of_year' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/es_US.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Kunal Marwaha\n * - Josh Soref\n * - Jørn Ølmheim\n * - Craig Patik\n * - bustta\n * - François B\n * - Tim Fish\n * - Claire Coloma\n * - Steven Heinrich\n * - JD Isaacks\n * - Raphael Amorim\n */\nreturn array_replace_recursive(require __DIR__.'/es.php', [\n    'diff_before_yesterday' => 'anteayer',\n    'formats' => [\n        'LT' => 'h:mm A',\n        'LTS' => 'h:mm:ss A',\n        'L' => 'MM/DD/YYYY',\n        'LL' => 'MMMM [de] D [de] YYYY',\n        'LLL' => 'MMMM [de] D [de] YYYY h:mm A',\n        'LLLL' => 'dddd, MMMM [de] D [de] YYYY h:mm A',\n    ],\n    'first_day_of_week' => 0,\n    'day_of_first_week_of_year' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/es_UY.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - RAP    bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/es.php', [\n    'months' => ['enero', 'febrero', 'marzo', 'abril', 'mayo', 'junio', 'julio', 'agosto', 'setiembre', 'octubre', 'noviembre', 'diciembre'],\n    'months_short' => ['ene', 'feb', 'mar', 'abr', 'may', 'jun', 'jul', 'ago', 'set', 'oct', 'nov', 'dic'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/es_VE.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - RAP    bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/es.php', [\n    'first_day_of_week' => 0,\n    'day_of_first_week_of_year' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/et.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Philippe Vaucher\n * - Andres Ivanov\n * - Tsutomu Kuroda\n * - tjku\n * - Max Melentiev\n * - Juanito Fatas\n * - RM87\n * - Akira Matsuda\n * - Christopher Dell\n * - Enrique Vidal\n * - Simone Carletti\n * - Aaron Patterson\n * - Esko Lehtme\n * - Mart Karu\n * - Nicolás Hock Isaza\n * - Kevin Valdek\n * - Zahhar Kirillov\n * - João Magalhães\n * - Ingmar\n * - Illimar Tambek\n * - Mihkel\n */\nreturn [\n    'year' => ':count aasta|:count aastat',\n    'y' => ':count a',\n    'month' => ':count kuu|:count kuud',\n    'm' => ':count k',\n    'week' => ':count nädal|:count nädalat',\n    'w' => ':count näd',\n    'day' => ':count päev|:count päeva',\n    'd' => ':count p',\n    'hour' => ':count tund|:count tundi',\n    'h' => ':count t',\n    'minute' => ':count minut|:count minutit',\n    'min' => ':count min',\n    'second' => ':count sekund|:count sekundit',\n    's' => ':count s',\n    'ago' => ':time tagasi',\n    'from_now' => ':time pärast',\n    'after' => ':time pärast',\n    'before' => ':time enne',\n    'year_from_now' => ':count aasta',\n    'month_from_now' => ':count kuu',\n    'week_from_now' => ':count nädala',\n    'day_from_now' => ':count päeva',\n    'hour_from_now' => ':count tunni',\n    'minute_from_now' => ':count minuti',\n    'second_from_now' => ':count sekundi',\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n    'diff_now' => 'nüüd',\n    'diff_today' => 'täna',\n    'diff_yesterday' => 'eile',\n    'diff_tomorrow' => 'homme',\n    'diff_before_yesterday' => 'üleeile',\n    'diff_after_tomorrow' => 'ülehomme',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD.MM.YYYY',\n        'LL' => 'D. MMMM YYYY',\n        'LLL' => 'D. MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D. MMMM YYYY HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[täna] LT',\n        'nextDay' => '[homme] LT',\n        'lastDay' => '[eile] LT',\n        'nextWeek' => 'dddd LT',\n        'lastWeek' => '[eelmine] dddd LT',\n        'sameElse' => 'L',\n    ],\n    'months' => ['jaanuar', 'veebruar', 'märts', 'aprill', 'mai', 'juuni', 'juuli', 'august', 'september', 'oktoober', 'november', 'detsember'],\n    'months_short' => ['jaan', 'veebr', 'märts', 'apr', 'mai', 'juuni', 'juuli', 'aug', 'sept', 'okt', 'nov', 'dets'],\n    'weekdays' => ['pühapäev', 'esmaspäev', 'teisipäev', 'kolmapäev', 'neljapäev', 'reede', 'laupäev'],\n    'weekdays_short' => ['P', 'E', 'T', 'K', 'N', 'R', 'L'],\n    'weekdays_min' => ['P', 'E', 'T', 'K', 'N', 'R', 'L'],\n    'list' => [', ', ' ja '],\n    'meridiem' => ['enne lõunat', 'pärast lõunat'],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/et_EE.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/et.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/eu.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Josh Soref\n * - François B\n * - JD Isaacks\n */\nreturn [\n    'year' => 'urte bat|:count urte',\n    'y' => 'Urte 1|:count urte',\n    'month' => 'hilabete bat|:count hilabete',\n    'm' => 'Hile 1|:count hile',\n    'week' => 'Aste 1|:count aste',\n    'w' => 'Aste 1|:count aste',\n    'day' => 'egun bat|:count egun',\n    'd' => 'Egun 1|:count egun',\n    'hour' => 'ordu bat|:count ordu',\n    'h' => 'Ordu 1|:count ordu',\n    'minute' => 'minutu bat|:count minutu',\n    'min' => 'Minutu 1|:count minutu',\n    'second' => 'segundo batzuk|:count segundo',\n    's' => 'Segundu 1|:count segundu',\n    'ago' => 'duela :time',\n    'from_now' => ':time barru',\n    'after' => ':time geroago',\n    'before' => ':time lehenago',\n    'diff_now' => 'orain',\n    'diff_today' => 'gaur',\n    'diff_yesterday' => 'atzo',\n    'diff_tomorrow' => 'bihar',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'YYYY-MM-DD',\n        'LL' => 'YYYY[ko] MMMM[ren] D[a]',\n        'LLL' => 'YYYY[ko] MMMM[ren] D[a] HH:mm',\n        'LLLL' => 'dddd, YYYY[ko] MMMM[ren] D[a] HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[gaur] LT[etan]',\n        'nextDay' => '[bihar] LT[etan]',\n        'nextWeek' => 'dddd LT[etan]',\n        'lastDay' => '[atzo] LT[etan]',\n        'lastWeek' => '[aurreko] dddd LT[etan]',\n        'sameElse' => 'L',\n    ],\n    'ordinal' => ':number.',\n    'months' => ['urtarrila', 'otsaila', 'martxoa', 'apirila', 'maiatza', 'ekaina', 'uztaila', 'abuztua', 'iraila', 'urria', 'azaroa', 'abendua'],\n    'months_short' => ['urt.', 'ots.', 'mar.', 'api.', 'mai.', 'eka.', 'uzt.', 'abu.', 'ira.', 'urr.', 'aza.', 'abe.'],\n    'weekdays' => ['igandea', 'astelehena', 'asteartea', 'asteazkena', 'osteguna', 'ostirala', 'larunbata'],\n    'weekdays_short' => ['ig.', 'al.', 'ar.', 'az.', 'og.', 'ol.', 'lr.'],\n    'weekdays_min' => ['ig', 'al', 'ar', 'az', 'og', 'ol', 'lr'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n    'list' => [', ', ' eta '],\n    'meridiem' => ['g', 'a'],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/eu_ES.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/eu.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ewo.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'meridiem' => ['kíkíríg', 'ngəgógəle'],\n    'weekdays' => ['sɔ́ndɔ', 'mɔ́ndi', 'sɔ́ndɔ məlú mə́bɛ̌', 'sɔ́ndɔ məlú mə́lɛ́', 'sɔ́ndɔ məlú mə́nyi', 'fúladé', 'séradé'],\n    'weekdays_short' => ['sɔ́n', 'mɔ́n', 'smb', 'sml', 'smn', 'fúl', 'sér'],\n    'weekdays_min' => ['sɔ́n', 'mɔ́n', 'smb', 'sml', 'smn', 'fúl', 'sér'],\n    'months' => ['ngɔn osú', 'ngɔn bɛ̌', 'ngɔn lála', 'ngɔn nyina', 'ngɔn tána', 'ngɔn saməna', 'ngɔn zamgbála', 'ngɔn mwom', 'ngɔn ebulú', 'ngɔn awóm', 'ngɔn awóm ai dziá', 'ngɔn awóm ai bɛ̌'],\n    'months_short' => ['ngo', 'ngb', 'ngl', 'ngn', 'ngt', 'ngs', 'ngz', 'ngm', 'nge', 'nga', 'ngad', 'ngab'],\n    'first_day_of_week' => 1,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'D/M/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd D MMMM YYYY HH:mm',\n    ],\n\n    // Too unreliable\n    /*\n    'year' => ':count mbu', // less reliable\n    'y' => ':count mbu', // less reliable\n    'a_year' => ':count mbu', // less reliable\n\n    'month' => ':count ngòn', // less reliable\n    'm' => ':count ngòn', // less reliable\n    'a_month' => ':count ngòn', // less reliable\n\n    'week' => ':count mësë', // less reliable\n    'w' => ':count mësë', // less reliable\n    'a_week' => ':count mësë', // less reliable\n\n    'day' => ':count mësë', // less reliable\n    'd' => ':count mësë', // less reliable\n    'a_day' => ':count mësë', // less reliable\n\n    'hour' => ':count awola', // less reliable\n    'h' => ':count awola', // less reliable\n    'a_hour' => ':count awola', // less reliable\n\n    'minute' => ':count awola', // less reliable\n    'min' => ':count awola', // less reliable\n    'a_minute' => ':count awola', // less reliable\n    */\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fa.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Josh Soref\n * - François B\n * - Nasser Ghiasi\n * - JD Isaacks\n * - Hossein Jabbari\n * - nimamo\n * - hafezdivandari\n * - Hassan Pezeshk (hpez)\n */\nreturn [\n    'year' => ':count سال',\n    'a_year' => 'یک سال'.'|:count '.'سال',\n    'y' => ':count سال',\n    'month' => ':count ماه',\n    'a_month' => 'یک ماه'.'|:count '.'ماه',\n    'm' => ':count ماه',\n    'week' => ':count هفته',\n    'a_week' => 'یک هفته'.'|:count '.'هفته',\n    'w' => ':count هفته',\n    'day' => ':count روز',\n    'a_day' => 'یک روز'.'|:count '.'روز',\n    'd' => ':count روز',\n    'hour' => ':count ساعت',\n    'a_hour' => 'یک ساعت'.'|:count '.'ساعت',\n    'h' => ':count ساعت',\n    'minute' => ':count دقیقه',\n    'a_minute' => 'یک دقیقه'.'|:count '.'دقیقه',\n    'min' => ':count دقیقه',\n    'second' => ':count ثانیه',\n    's' => ':count ثانیه',\n    'ago' => ':time پیش',\n    'from_now' => ':time دیگر',\n    'after' => ':time پس از',\n    'before' => ':time پیش از',\n    'diff_now' => 'اکنون',\n    'diff_today' => 'امروز',\n    'diff_today_regexp' => 'امروز(?:\\\\s+ساعت)?',\n    'diff_yesterday' => 'دیروز',\n    'diff_yesterday_regexp' => 'دیروز(?:\\\\s+ساعت)?',\n    'diff_tomorrow' => 'فردا',\n    'diff_tomorrow_regexp' => 'فردا(?:\\\\s+ساعت)?',\n    'formats' => [\n        'LT' => 'OH:Om',\n        'LTS' => 'OH:Om:Os',\n        'L' => 'OD/OM/OY',\n        'LL' => 'OD MMMM OY',\n        'LLL' => 'OD MMMM OY OH:Om',\n        'LLLL' => 'dddd, OD MMMM OY OH:Om',\n    ],\n    'calendar' => [\n        'sameDay' => '[امروز ساعت] LT',\n        'nextDay' => '[فردا ساعت] LT',\n        'nextWeek' => 'dddd [ساعت] LT',\n        'lastDay' => '[دیروز ساعت] LT',\n        'lastWeek' => 'dddd [پیش] [ساعت] LT',\n        'sameElse' => 'L',\n    ],\n    'ordinal' => ':timeم',\n    'meridiem' => ['قبل از ظهر', 'بعد از ظهر'],\n    'months' => ['ژانویه', 'فوریه', 'مارس', 'آوریل', 'مه', 'ژوئن', 'ژوئیه', 'اوت', 'سپتامبر', 'اکتبر', 'نوامبر', 'دسامبر'],\n    'months_short' => ['ژانویه', 'فوریه', 'مارس', 'آوریل', 'مه', 'ژوئن', 'ژوئیه', 'اوت', 'سپتامبر', 'اکتبر', 'نوامبر', 'دسامبر'],\n    'weekdays' => ['یکشنبه', 'دوشنبه', 'سه‌شنبه', 'چهارشنبه', 'پنجشنبه', 'جمعه', 'شنبه'],\n    'weekdays_short' => ['یکشنبه', 'دوشنبه', 'سه‌شنبه', 'چهارشنبه', 'پنجشنبه', 'جمعه', 'شنبه'],\n    'weekdays_min' => ['ی', 'د', 'س', 'چ', 'پ', 'ج', 'ش'],\n    'first_day_of_week' => 6,\n    'day_of_first_week_of_year' => 1,\n    'list' => ['، ', ' و '],\n    'alt_numbers' => ['۰۰', '۰۱', '۰۲', '۰۳', '۰۴', '۰۵', '۰۶', '۰۷', '۰۸', '۰۹', '۱۰', '۱۱', '۱۲', '۱۳', '۱۴', '۱۵', '۱۶', '۱۷', '۱۸', '۱۹', '۲۰', '۲۱', '۲۲', '۲۳', '۲۴', '۲۵', '۲۶', '۲۷', '۲۸', '۲۹', '۳۰', '۳۱', '۳۲', '۳۳', '۳۴', '۳۵', '۳۶', '۳۷', '۳۸', '۳۹', '۴۰', '۴۱', '۴۲', '۴۳', '۴۴', '۴۵', '۴۶', '۴۷', '۴۸', '۴۹', '۵۰', '۵۱', '۵۲', '۵۳', '۵۴', '۵۵', '۵۶', '۵۷', '۵۸', '۵۹', '۶۰', '۶۱', '۶۲', '۶۳', '۶۴', '۶۵', '۶۶', '۶۷', '۶۸', '۶۹', '۷۰', '۷۱', '۷۲', '۷۳', '۷۴', '۷۵', '۷۶', '۷۷', '۷۸', '۷۹', '۸۰', '۸۱', '۸۲', '۸۳', '۸۴', '۸۵', '۸۶', '۸۷', '۸۸', '۸۹', '۹۰', '۹۱', '۹۲', '۹۳', '۹۴', '۹۵', '۹۶', '۹۷', '۹۸', '۹۹'],\n    'months_short_standalone' => ['ژانویه', 'فوریه', 'مارس', 'آوریل', 'مه', 'ژوئن', 'ژوئیه', 'اوت', 'سپتامبر', 'اکتبر', 'نوامبر', 'دسامبر'],\n    'weekend' => [5, 5],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fa_AF.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/fa.php', [\n    'meridiem' => ['ق', 'ب'],\n    'weekend' => [4, 5],\n    'formats' => [\n        'L' => 'OY/OM/OD',\n        'LL' => 'OD MMM OY',\n        'LLL' => 'OD MMMM OY،‏ H:mm',\n        'LLLL' => 'dddd OD MMMM OY،‏ H:mm',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fa_IR.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/fa.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ff.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMM, YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd D MMMM YYYY HH:mm',\n    ],\n    'months' => ['siilo', 'colte', 'mbooy', 'seeɗto', 'duujal', 'korse', 'morso', 'juko', 'siilto', 'yarkomaa', 'jolal', 'bowte'],\n    'months_short' => ['sii', 'col', 'mbo', 'see', 'duu', 'kor', 'mor', 'juk', 'slt', 'yar', 'jol', 'bow'],\n    'weekdays' => ['dewo', 'aaɓnde', 'mawbaare', 'njeslaare', 'naasaande', 'mawnde', 'hoore-biir'],\n    'weekdays_short' => ['dew', 'aaɓ', 'maw', 'nje', 'naa', 'mwd', 'hbi'],\n    'weekdays_min' => ['dew', 'aaɓ', 'maw', 'nje', 'naa', 'mwd', 'hbi'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['subaka', 'kikiiɗe'],\n\n    'year' => ':count baret', // less reliable\n    'y' => ':count baret', // less reliable\n    'a_year' => ':count baret', // less reliable\n\n    'month' => ':count lewru', // less reliable\n    'm' => ':count lewru', // less reliable\n    'a_month' => ':count lewru', // less reliable\n\n    'week' => ':count naange', // less reliable\n    'w' => ':count naange', // less reliable\n    'a_week' => ':count naange', // less reliable\n\n    'day' => ':count dian', // less reliable\n    'd' => ':count dian', // less reliable\n    'a_day' => ':count dian', // less reliable\n\n    'hour' => ':count montor', // less reliable\n    'h' => ':count montor', // less reliable\n    'a_hour' => ':count montor', // less reliable\n\n    'minute' => ':count tokossuoum', // less reliable\n    'min' => ':count tokossuoum', // less reliable\n    'a_minute' => ':count tokossuoum', // less reliable\n\n    'second' => ':count tenen', // less reliable\n    's' => ':count tenen', // less reliable\n    'a_second' => ':count tenen', // less reliable\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ff_CM.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/ff.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ff_GN.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/ff.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ff_MR.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/ff.php', [\n    'formats' => [\n        'LT' => 'h:mm a',\n        'LTS' => 'h:mm:ss a',\n        'L' => 'D/M/YYYY',\n        'LL' => 'D MMM, YYYY',\n        'LLL' => 'D MMMM YYYY h:mm a',\n        'LLLL' => 'dddd D MMMM YYYY h:mm a',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ff_SN.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Pular-Fulfulde.org Ibrahima Sarr admin@pulaar-fulfulde.org\n */\nreturn require __DIR__.'/ff.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fi.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Philippe Vaucher\n * - Janne Warén\n * - digitalfrost\n * - Tsutomu Kuroda\n * - Roope Salmi\n * - tjku\n * - Max Melentiev\n * - Sami Haahtinen\n * - Teemu Leisti\n * - Artem Ignatyev\n * - Akira Matsuda\n * - Christopher Dell\n * - Enrique Vidal\n * - Simone Carletti\n * - Robert Bjarnason\n * - Aaron Patterson\n * - Nicolás Hock Isaza\n * - Tom Hughes\n * - Sven Fuchs\n * - Petri Kivikangas\n * - Nizar Jouini\n * - Marko Seppae\n * - Tomi Mynttinen (Pikseli)\n * - Petteri (powergrip)\n */\nreturn [\n    'year' => ':count vuosi|:count vuotta',\n    'y' => ':count v',\n    'month' => ':count kuukausi|:count kuukautta',\n    'm' => ':count kk',\n    'week' => ':count viikko|:count viikkoa',\n    'w' => ':count vk',\n    'day' => ':count päivä|:count päivää',\n    'd' => ':count pv',\n    'hour' => ':count tunti|:count tuntia',\n    'h' => ':count t',\n    'minute' => ':count minuutti|:count minuuttia',\n    'min' => ':count min',\n    'second' => ':count sekunti|:count sekuntia',\n    'a_second' => 'muutama sekunti|:count sekuntia',\n    's' => ':count s',\n    'ago' => ':time sitten',\n    'from_now' => ':time päästä',\n    'year_from_now' => ':count vuoden',\n    'month_from_now' => ':count kuukauden',\n    'week_from_now' => ':count viikon',\n    'day_from_now' => ':count päivän',\n    'hour_from_now' => ':count tunnin',\n    'minute_from_now' => ':count minuutin',\n    'second_from_now' => ':count sekunnin',\n    'after' => ':time sen jälkeen',\n    'before' => ':time ennen',\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n    'list' => [', ', ' ja '],\n    'diff_now' => 'nyt',\n    'diff_yesterday' => 'eilen',\n    'diff_tomorrow' => 'huomenna',\n    'formats' => [\n        'LT' => 'HH.mm',\n        'LTS' => 'HH.mm:ss',\n        'L' => 'D.M.YYYY',\n        'LL' => 'dddd D. MMMM[ta] YYYY',\n        'll' => 'ddd D. MMM YYYY',\n        'LLL' => 'D.MM. HH.mm',\n        'LLLL' => 'D. MMMM[ta] YYYY HH.mm',\n        'llll' => 'D. MMM YY HH.mm',\n    ],\n    'weekdays' => ['sunnuntai', 'maanantai', 'tiistai', 'keskiviikko', 'torstai', 'perjantai', 'lauantai'],\n    'weekdays_short' => ['su', 'ma', 'ti', 'ke', 'to', 'pe', 'la'],\n    'weekdays_min' => ['su', 'ma', 'ti', 'ke', 'to', 'pe', 'la'],\n    'months' => ['tammikuu', 'helmikuu', 'maaliskuu', 'huhtikuu', 'toukokuu', 'kesäkuu', 'heinäkuu', 'elokuu', 'syyskuu', 'lokakuu', 'marraskuu', 'joulukuu'],\n    'months_short' => ['tammi', 'helmi', 'maalis', 'huhti', 'touko', 'kesä', 'heinä', 'elo', 'syys', 'loka', 'marras', 'joulu'],\n    'meridiem' => ['aamupäivä', 'iltapäivä'],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fi_FI.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/fi.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fil.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/fil_PH.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fil_PH.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Rene Torres Rene Torres, Pablo Saratxaga rgtorre@rocketmail.com, pablo@mandrakesoft.com\n * - Jaycee Mariano (alohajaycee)\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'MM/DD/YY',\n    ],\n    'months' => ['Enero', 'Pebrero', 'Marso', 'Abril', 'Mayo', 'Hunyo', 'Hulyo', 'Agosto', 'Setyembre', 'Oktubre', 'Nobyembre', 'Disyembre'],\n    'months_short' => ['Ene', 'Peb', 'Mar', 'Abr', 'May', 'Hun', 'Hul', 'Ago', 'Set', 'Okt', 'Nob', 'Dis'],\n    'weekdays' => ['Linggo', 'Lunes', 'Martes', 'Miyerkoles', 'Huwebes', 'Biyernes', 'Sabado'],\n    'weekdays_short' => ['Lin', 'Lun', 'Mar', 'Miy', 'Huw', 'Biy', 'Sab'],\n    'weekdays_min' => ['Lin', 'Lun', 'Mar', 'Miy', 'Huw', 'Biy', 'Sab'],\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['N.U.', 'N.H.'],\n\n    'before' => ':time bago',\n    'after' => ':time pagkatapos',\n\n    'year' => ':count taon',\n    'y' => ':count taon',\n    'a_year' => ':count taon',\n\n    'month' => ':count buwan',\n    'm' => ':count buwan',\n    'a_month' => ':count buwan',\n\n    'week' => ':count linggo',\n    'w' => ':count linggo',\n    'a_week' => ':count linggo',\n\n    'day' => ':count araw',\n    'd' => ':count araw',\n    'a_day' => ':count araw',\n\n    'hour' => ':count oras',\n    'h' => ':count oras',\n    'a_hour' => ':count oras',\n\n    'minute' => ':count minuto',\n    'min' => ':count minuto',\n    'a_minute' => ':count minuto',\n\n    'second' => ':count segundo',\n    's' => ':count segundo',\n    'a_second' => ':count segundo',\n\n    'ago' => ':time ang nakalipas',\n    'from_now' => 'sa :time',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fo.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Kristian Sakarisson\n * - François B\n * - JD Isaacks\n * - Sverri Mohr Olsen\n */\nreturn [\n    'year' => 'eitt ár|:count ár',\n    'y' => ':count ár|:count ár',\n    'month' => 'ein mánaði|:count mánaðir',\n    'm' => ':count mánaður|:count mánaðir',\n    'week' => ':count vika|:count vikur',\n    'w' => ':count vika|:count vikur',\n    'day' => 'ein dagur|:count dagar',\n    'd' => ':count dag|:count dagar',\n    'hour' => 'ein tími|:count tímar',\n    'h' => ':count tími|:count tímar',\n    'minute' => 'ein minutt|:count minuttir',\n    'min' => ':count minutt|:count minuttir',\n    'second' => 'fá sekund|:count sekundir',\n    's' => ':count sekund|:count sekundir',\n    'ago' => ':time síðani',\n    'from_now' => 'um :time',\n    'after' => ':time aftaná',\n    'before' => ':time áðrenn',\n    'diff_today' => 'Í',\n    'diff_yesterday' => 'Í',\n    'diff_yesterday_regexp' => 'Í(?:\\\\s+gjár)?(?:\\\\s+kl.)?',\n    'diff_tomorrow' => 'Í',\n    'diff_tomorrow_regexp' => 'Í(?:\\\\s+morgin)?(?:\\\\s+kl.)?',\n    'diff_today_regexp' => 'Í(?:\\\\s+dag)?(?:\\\\s+kl.)?',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd D. MMMM, YYYY HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[Í dag kl.] LT',\n        'nextDay' => '[Í morgin kl.] LT',\n        'nextWeek' => 'dddd [kl.] LT',\n        'lastDay' => '[Í gjár kl.] LT',\n        'lastWeek' => '[síðstu] dddd [kl] LT',\n        'sameElse' => 'L',\n    ],\n    'ordinal' => ':number.',\n    'months' => ['januar', 'februar', 'mars', 'apríl', 'mai', 'juni', 'juli', 'august', 'september', 'oktober', 'november', 'desember'],\n    'months_short' => ['jan', 'feb', 'mar', 'apr', 'mai', 'jun', 'jul', 'aug', 'sep', 'okt', 'nov', 'des'],\n    'weekdays' => ['sunnudagur', 'mánadagur', 'týsdagur', 'mikudagur', 'hósdagur', 'fríggjadagur', 'leygardagur'],\n    'weekdays_short' => ['sun', 'mán', 'týs', 'mik', 'hós', 'frí', 'ley'],\n    'weekdays_min' => ['su', 'má', 'tý', 'mi', 'hó', 'fr', 'le'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n    'list' => [', ', ' og '],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fo_DK.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/fo.php', [\n    'formats' => [\n        'L' => 'DD.MM.yy',\n        'LL' => 'DD.MM.YYYY',\n        'LLL' => 'D. MMMM YYYY, HH:mm',\n        'LLLL' => 'dddd, D. MMMM YYYY, HH:mm',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fo_FO.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/fo.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fr.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Dieter Sting\n * - François B\n * - Maxime VALY\n * - JD Isaacks\n * - Dieter Sting\n * - François B\n * - JD Isaacks\n * - Sebastian Thierer\n * - Fastfuel\n * - Pete Scopes (pdscopes)\n */\nreturn [\n    'year' => ':count an|:count ans',\n    'a_year' => 'un an|:count ans',\n    'y' => ':count an|:count ans',\n    'month' => ':count mois|:count mois',\n    'a_month' => 'un mois|:count mois',\n    'm' => ':count mois',\n    'week' => ':count semaine|:count semaines',\n    'a_week' => 'une semaine|:count semaines',\n    'w' => ':count sem.',\n    'day' => ':count jour|:count jours',\n    'a_day' => 'un jour|:count jours',\n    'd' => ':count j',\n    'hour' => ':count heure|:count heures',\n    'a_hour' => 'une heure|:count heures',\n    'h' => ':count h',\n    'minute' => ':count minute|:count minutes',\n    'a_minute' => 'une minute|:count minutes',\n    'min' => ':count min',\n    'second' => ':count seconde|:count secondes',\n    'a_second' => 'quelques secondes|:count secondes',\n    's' => ':count s',\n    'millisecond' => ':count milliseconde|:count millisecondes',\n    'a_millisecond' => 'une milliseconde|:count millisecondes',\n    'ms' => ':countms',\n    'microsecond' => ':count microseconde|:count microsecondes',\n    'a_microsecond' => 'une microseconde|:count microsecondes',\n    'µs' => ':countµs',\n    'ago' => 'il y a :time',\n    'from_now' => 'dans :time',\n    'after' => ':time après',\n    'before' => ':time avant',\n    'diff_now' => \"à l'instant\",\n    'diff_today' => \"aujourd'hui\",\n    'diff_today_regexp' => \"aujourd'hui(?:\\s+à)?\",\n    'diff_yesterday' => 'hier',\n    'diff_yesterday_regexp' => 'hier(?:\\s+à)?',\n    'diff_tomorrow' => 'demain',\n    'diff_tomorrow_regexp' => 'demain(?:\\s+à)?',\n    'diff_before_yesterday' => 'avant-hier',\n    'diff_after_tomorrow' => 'après-demain',\n    'period_recurrences' => ':count fois',\n    'period_interval' => 'tous les :interval',\n    'period_start_date' => 'de :date',\n    'period_end_date' => 'à :date',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd D MMMM YYYY HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[Aujourd’hui à] LT',\n        'nextDay' => '[Demain à] LT',\n        'nextWeek' => 'dddd [à] LT',\n        'lastDay' => '[Hier à] LT',\n        'lastWeek' => 'dddd [dernier à] LT',\n        'sameElse' => 'L',\n    ],\n    'months' => ['janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'],\n    'months_short' => ['janv.', 'févr.', 'mars', 'avr.', 'mai', 'juin', 'juil.', 'août', 'sept.', 'oct.', 'nov.', 'déc.'],\n    'weekdays' => ['dimanche', 'lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi'],\n    'weekdays_short' => ['dim.', 'lun.', 'mar.', 'mer.', 'jeu.', 'ven.', 'sam.'],\n    'weekdays_min' => ['di', 'lu', 'ma', 'me', 'je', 've', 'sa'],\n    'ordinal' => function ($number, $period) {\n        switch ($period) {\n            // In French, only the first has to be ordinal, other number remains cardinal\n            // @link https://fr.wikihow.com/%C3%A9crire-la-date-en-fran%C3%A7ais\n            case 'D':\n                return $number.($number === 1 ? 'er' : '');\n\n            default:\n            case 'M':\n            case 'Q':\n            case 'DDD':\n            case 'd':\n                return $number.($number === 1 ? 'er' : 'e');\n\n            // Words with feminine grammatical gender: semaine\n            case 'w':\n            case 'W':\n                return $number.($number === 1 ? 're' : 'e');\n        }\n    },\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n    'list' => [', ', ' et '],\n    'ordinal_words' => [\n        'of' => 'de',\n        'first' => 'premier',\n        'second' => 'deuxième',\n        'third' => 'troisième',\n        'fourth' => 'quatrième',\n        'fifth' => 'cinquième',\n        'last' => 'dernier',\n    ],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fr_BE.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - RAP    bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/fr.php', [\n    'months_short' => ['jan', 'fév', 'mar', 'avr', 'mai', 'jun', 'jui', 'aoû', 'sep', 'oct', 'nov', 'déc'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fr_BF.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/fr.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fr_BI.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/fr.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fr_BJ.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/fr.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fr_BL.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/fr.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fr_CA.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Dieter Sting\n * - François B\n * - Maxime VALY\n * - JD Isaacks\n */\nreturn array_replace_recursive(require __DIR__.'/fr.php', [\n    'formats' => [\n        'L' => 'YYYY-MM-DD',\n    ],\n    'first_day_of_week' => 0,\n    'day_of_first_week_of_year' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fr_CD.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/fr.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fr_CF.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/fr.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fr_CG.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/fr.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fr_CH.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Dieter Sting\n * - François B\n * - Gaspard Bucher\n * - Maxime VALY\n * - JD Isaacks\n */\nreturn array_replace_recursive(require __DIR__.'/fr.php', [\n    'formats' => [\n        'L' => 'DD.MM.YYYY',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fr_CI.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/fr.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fr_CM.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/fr.php', [\n    'meridiem' => ['mat.', 'soir'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fr_DJ.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/fr.php', [\n    'first_day_of_week' => 6,\n    'formats' => [\n        'LT' => 'h:mm a',\n        'LTS' => 'h:mm:ss a',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY h:mm a',\n        'LLLL' => 'dddd D MMMM YYYY h:mm a',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fr_DZ.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/fr.php', [\n    'first_day_of_week' => 6,\n    'weekend' => [5, 6],\n    'formats' => [\n        'LT' => 'h:mm a',\n        'LTS' => 'h:mm:ss a',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY h:mm a',\n        'LLLL' => 'dddd D MMMM YYYY h:mm a',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fr_FR.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/fr.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fr_GA.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/fr.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fr_GF.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/fr.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fr_GN.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/fr.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fr_GP.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/fr.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fr_GQ.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/fr.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fr_HT.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/fr.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fr_KM.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/fr.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fr_LU.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - RAP    bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/fr.php', [\n    'formats' => [\n        'L' => 'DD.MM.YYYY',\n    ],\n    'months_short' => ['jan', 'fév', 'mar', 'avr', 'mai', 'jun', 'jui', 'aoû', 'sep', 'oct', 'nov', 'déc'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fr_MA.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/fr.php', [\n    'first_day_of_week' => 6,\n    'weekend' => [5, 6],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fr_MC.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/fr.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fr_MF.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/fr.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fr_MG.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/fr.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fr_ML.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/fr.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fr_MQ.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/fr.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fr_MR.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/fr.php', [\n    'formats' => [\n        'LT' => 'h:mm a',\n        'LTS' => 'h:mm:ss a',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY h:mm a',\n        'LLLL' => 'dddd D MMMM YYYY h:mm a',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fr_MU.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/fr.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fr_NC.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/fr.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fr_NE.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/fr.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fr_PF.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/fr.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fr_PM.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/fr.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fr_RE.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/fr.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fr_RW.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/fr.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fr_SC.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/fr.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fr_SN.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/fr.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fr_SY.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/fr.php', [\n    'first_day_of_week' => 6,\n    'weekend' => [5, 6],\n    'formats' => [\n        'LT' => 'h:mm a',\n        'LTS' => 'h:mm:ss a',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY h:mm a',\n        'LLLL' => 'dddd D MMMM YYYY h:mm a',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fr_TD.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/fr.php', [\n    'formats' => [\n        'LT' => 'h:mm a',\n        'LTS' => 'h:mm:ss a',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY h:mm a',\n        'LLLL' => 'dddd D MMMM YYYY h:mm a',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fr_TG.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/fr.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fr_TN.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/fr.php', [\n    'weekend' => [5, 6],\n    'formats' => [\n        'LT' => 'h:mm a',\n        'LTS' => 'h:mm:ss a',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY h:mm a',\n        'LLLL' => 'dddd D MMMM YYYY h:mm a',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fr_VU.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/fr.php', [\n    'formats' => [\n        'LT' => 'h:mm a',\n        'LTS' => 'h:mm:ss a',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY h:mm a',\n        'LLLL' => 'dddd D MMMM YYYY h:mm a',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fr_WF.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/fr.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fr_YT.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/fr.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fur.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/fur_IT.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fur_IT.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Pablo Saratxaga pablo@mandrakesoft.com\n */\nreturn [\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD. MM. YY',\n        'LL' => 'DD di MMMM dal YYYY',\n        'LLL' => 'DD di MMM HH:mm',\n        'LLLL' => 'DD di MMMM dal YYYY HH:mm',\n    ],\n    'months' => ['zenâr', 'fevrâr', 'març', 'avrîl', 'mai', 'jugn', 'lui', 'avost', 'setembar', 'otubar', 'novembar', 'dicembar'],\n    'months_short' => ['zen', 'fev', 'mar', 'avr', 'mai', 'jug', 'lui', 'avo', 'set', 'otu', 'nov', 'dic'],\n    'weekdays' => ['domenie', 'lunis', 'martars', 'miercus', 'joibe', 'vinars', 'sabide'],\n    'weekdays_short' => ['dom', 'lun', 'mar', 'mie', 'joi', 'vin', 'sab'],\n    'weekdays_min' => ['dom', 'lun', 'mar', 'mie', 'joi', 'vin', 'sab'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n    'year' => ':count an',\n    'month' => ':count mês',\n    'week' => ':count setemane',\n    'day' => ':count zornade',\n    'hour' => ':count ore',\n    'minute' => ':count minût',\n    'second' => ':count secont',\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fy.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - François B\n * - Tim Fish\n * - JD Isaacks\n */\nreturn [\n    'year' => ':count jier|:count jierren',\n    'a_year' => 'ien jier|:count jierren',\n    'y' => ':count j',\n    'month' => ':count moanne|:count moannen',\n    'a_month' => 'ien moanne|:count moannen',\n    'm' => ':count moa.',\n    'week' => ':count wike|:count wiken',\n    'a_week' => 'in wike|:count wiken',\n    'a' => ':count w.',\n    'day' => ':count dei|:count dagen',\n    'a_day' => 'ien dei|:count dagen',\n    'd' => ':count d.',\n    'hour' => ':count oere|:count oeren',\n    'a_hour' => 'ien oere|:count oeren',\n    'h' => ':count o.',\n    'minute' => ':count minút|:count minuten',\n    'a_minute' => 'ien minút|:count minuten',\n    'min' => ':count min.',\n    'second' => ':count sekonde|:count sekonden',\n    'a_second' => 'in pear sekonden|:count sekonden',\n    's' => ':count s.',\n    'ago' => ':time lyn',\n    'from_now' => 'oer :time',\n    'diff_yesterday' => 'juster',\n    'diff_yesterday_regexp' => 'juster(?:\\\\s+om)?',\n    'diff_today' => 'hjoed',\n    'diff_today_regexp' => 'hjoed(?:\\\\s+om)?',\n    'diff_tomorrow' => 'moarn',\n    'diff_tomorrow_regexp' => 'moarn(?:\\\\s+om)?',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD-MM-YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd D MMMM YYYY HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[hjoed om] LT',\n        'nextDay' => '[moarn om] LT',\n        'nextWeek' => 'dddd [om] LT',\n        'lastDay' => '[juster om] LT',\n        'lastWeek' => '[ôfrûne] dddd [om] LT',\n        'sameElse' => 'L',\n    ],\n    'ordinal' => function ($number) {\n        return $number.(($number === 1 || $number === 8 || $number >= 20) ? 'ste' : 'de');\n    },\n    'months' => ['jannewaris', 'febrewaris', 'maart', 'april', 'maaie', 'juny', 'july', 'augustus', 'septimber', 'oktober', 'novimber', 'desimber'],\n    'months_short' => ['jan', 'feb', 'mrt', 'apr', 'mai', 'jun', 'jul', 'aug', 'sep', 'okt', 'nov', 'des'],\n    'mmm_suffix' => '.',\n    'weekdays' => ['snein', 'moandei', 'tiisdei', 'woansdei', 'tongersdei', 'freed', 'sneon'],\n    'weekdays_short' => ['si.', 'mo.', 'ti.', 'wo.', 'to.', 'fr.', 'so.'],\n    'weekdays_min' => ['Si', 'Mo', 'Ti', 'Wo', 'To', 'Fr', 'So'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n    'list' => [', ', ' en '],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fy_DE.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - information from Kenneth Christiansen Kenneth Christiansen, Pablo Saratxaga kenneth@gnu.org, pablo@mandriva.com\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD.MM.YYYY',\n    ],\n    'months' => ['Jaunuwoa', 'Februwoa', 'Moaz', 'Aprell', 'Mai', 'Juni', 'Juli', 'August', 'Septamba', 'Oktoba', 'Nowamba', 'Dezamba'],\n    'months_short' => ['Jan', 'Feb', 'Moz', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Now', 'Dez'],\n    'weekdays' => ['Sinndag', 'Mondag', 'Dingsdag', 'Meddwäakj', 'Donnadag', 'Friedag', 'Sinnowend'],\n    'weekdays_short' => ['Sdg', 'Mdg', 'Dsg', 'Mwk', 'Ddg', 'Fdg', 'Swd'],\n    'weekdays_min' => ['Sdg', 'Mdg', 'Dsg', 'Mwk', 'Ddg', 'Fdg', 'Swd'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/fy_NL.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Free Software Foundation, Inc.    bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/fy.php', [\n    'formats' => [\n        'L' => 'DD-MM-YY',\n    ],\n    'months' => ['Jannewaris', 'Febrewaris', 'Maart', 'April', 'Maaie', 'Juny', 'July', 'Augustus', 'Septimber', 'Oktober', 'Novimber', 'Desimber'],\n    'months_short' => ['Jan', 'Feb', 'Mrt', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Des'],\n    'weekdays' => ['Snein', 'Moandei', 'Tiisdei', 'Woansdei', 'Tongersdei', 'Freed', 'Sneon'],\n    'weekdays_short' => ['Sn', 'Mo', 'Ti', 'Wo', 'To', 'Fr', 'Sn'],\n    'weekdays_min' => ['Sn', 'Mo', 'Ti', 'Wo', 'To', 'Fr', 'Sn'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ga.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Thanks to André Silva : https://github.com/askpt\n */\n\nreturn [\n    'year' => ':count bliain',\n    'a_year' => '{1}bliain|:count bliain',\n    'y' => ':countb',\n    'month' => ':count mí',\n    'a_month' => '{1}mí|:count mí',\n    'm' => ':countm',\n    'week' => ':count sheachtain',\n    'a_week' => '{1}sheachtain|:count sheachtain',\n    'w' => ':countsh',\n    'day' => ':count lá',\n    'a_day' => '{1}lá|:count lá',\n    'd' => ':countl',\n    'hour' => ':count uair an chloig',\n    'a_hour' => '{1}uair an chloig|:count uair an chloig',\n    'h' => ':countu',\n    'minute' => ':count nóiméad',\n    'a_minute' => '{1}nóiméad|:count nóiméad',\n    'min' => ':countn',\n    'second' => ':count soicind',\n    'a_second' => '{1}cúpla soicind|:count soicind',\n    's' => ':countso',\n    'ago' => ':time ó shin',\n    'from_now' => 'i :time',\n    'after' => ':time tar éis',\n    'before' => ':time roimh',\n    'diff_now' => 'anois',\n    'diff_today' => 'Inniu',\n    'diff_today_regexp' => 'Inniu(?:\\\\s+ag)?',\n    'diff_yesterday' => 'inné',\n    'diff_yesterday_regexp' => 'Inné(?:\\\\s+aig)?',\n    'diff_tomorrow' => 'amárach',\n    'diff_tomorrow_regexp' => 'Amárach(?:\\\\s+ag)?',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[Inniu ag] LT',\n        'nextDay' => '[Amárach ag] LT',\n        'nextWeek' => 'dddd [ag] LT',\n        'lastDay' => '[Inné aig] LT',\n        'lastWeek' => 'dddd [seo caite] [ag] LT',\n        'sameElse' => 'L',\n    ],\n    'months' => ['Eanáir', 'Feabhra', 'Márta', 'Aibreán', 'Bealtaine', 'Méitheamh', 'Iúil', 'Lúnasa', 'Meán Fómhair', 'Deaireadh Fómhair', 'Samhain', 'Nollaig'],\n    'months_short' => ['Eaná', 'Feab', 'Márt', 'Aibr', 'Beal', 'Méit', 'Iúil', 'Lúna', 'Meán', 'Deai', 'Samh', 'Noll'],\n    'weekdays' => ['Dé Domhnaigh', 'Dé Luain', 'Dé Máirt', 'Dé Céadaoin', 'Déardaoin', 'Dé hAoine', 'Dé Satharn'],\n    'weekdays_short' => ['Dom', 'Lua', 'Mái', 'Céa', 'Déa', 'hAo', 'Sat'],\n    'weekdays_min' => ['Do', 'Lu', 'Má', 'Ce', 'Dé', 'hA', 'Sa'],\n    'ordinal' => function ($number) {\n        return $number.($number === 1 ? 'd' : ($number % 10 === 2 ? 'na' : 'mh'));\n    },\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n    'list' => [', ', ' agus '],\n    'meridiem' => ['r.n.', 'i.n.'],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ga_IE.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/ga.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/gd.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - François B\n * - Jon Ashdown\n */\nreturn [\n    'year' => ':count bliadhna',\n    'a_year' => '{1}bliadhna|:count bliadhna',\n    'y' => ':count b.',\n    'month' => ':count mìosan',\n    'a_month' => '{1}mìos|:count mìosan',\n    'm' => ':count ms.',\n    'week' => ':count seachdainean',\n    'a_week' => '{1}seachdain|:count seachdainean',\n    'w' => ':count s.',\n    'day' => ':count latha',\n    'a_day' => '{1}latha|:count latha',\n    'd' => ':count l.',\n    'hour' => ':count uairean',\n    'a_hour' => '{1}uair|:count uairean',\n    'h' => ':count u.',\n    'minute' => ':count mionaidean',\n    'a_minute' => '{1}mionaid|:count mionaidean',\n    'min' => ':count md.',\n    'second' => ':count diogan',\n    'a_second' => '{1}beagan diogan|:count diogan',\n    's' => ':count d.',\n    'ago' => 'bho chionn :time',\n    'from_now' => 'ann an :time',\n    'diff_yesterday' => 'An-dè',\n    'diff_yesterday_regexp' => 'An-dè(?:\\\\s+aig)?',\n    'diff_today' => 'An-diugh',\n    'diff_today_regexp' => 'An-diugh(?:\\\\s+aig)?',\n    'diff_tomorrow' => 'A-màireach',\n    'diff_tomorrow_regexp' => 'A-màireach(?:\\\\s+aig)?',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[An-diugh aig] LT',\n        'nextDay' => '[A-màireach aig] LT',\n        'nextWeek' => 'dddd [aig] LT',\n        'lastDay' => '[An-dè aig] LT',\n        'lastWeek' => 'dddd [seo chaidh] [aig] LT',\n        'sameElse' => 'L',\n    ],\n    'ordinal' => function ($number) {\n        return $number.($number === 1 ? 'd' : ($number % 10 === 2 ? 'na' : 'mh'));\n    },\n    'months' => ['Am Faoilleach', 'An Gearran', 'Am Màrt', 'An Giblean', 'An Cèitean', 'An t-Ògmhios', 'An t-Iuchar', 'An Lùnastal', 'An t-Sultain', 'An Dàmhair', 'An t-Samhain', 'An Dùbhlachd'],\n    'months_short' => ['Faoi', 'Gear', 'Màrt', 'Gibl', 'Cèit', 'Ògmh', 'Iuch', 'Lùn', 'Sult', 'Dàmh', 'Samh', 'Dùbh'],\n    'weekdays' => ['Didòmhnaich', 'Diluain', 'Dimàirt', 'Diciadain', 'Diardaoin', 'Dihaoine', 'Disathairne'],\n    'weekdays_short' => ['Did', 'Dil', 'Dim', 'Dic', 'Dia', 'Dih', 'Dis'],\n    'weekdays_min' => ['Dò', 'Lu', 'Mà', 'Ci', 'Ar', 'Ha', 'Sa'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n    'list' => [', ', ' agus '],\n    'meridiem' => ['m', 'f'],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/gd_GB.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/gd.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/gez.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/gez_ER.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/gez_ER.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Ge'ez Frontier Foundation    locales@geez.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD/MM/YYYY',\n    ],\n    'months' => ['ጠሐረ', 'ከተተ', 'መገበ', 'አኀዘ', 'ግንባት', 'ሠንየ', 'ሐመለ', 'ነሐሰ', 'ከረመ', 'ጠቀመ', 'ኀደረ', 'ኀሠሠ'],\n    'months_short' => ['ጠሐረ', 'ከተተ', 'መገበ', 'አኀዘ', 'ግንባ', 'ሠንየ', 'ሐመለ', 'ነሐሰ', 'ከረመ', 'ጠቀመ', 'ኀደረ', 'ኀሠሠ'],\n    'weekdays' => ['እኁድ', 'ሰኑይ', 'ሠሉስ', 'ራብዕ', 'ሐሙስ', 'ዓርበ', 'ቀዳሚት'],\n    'weekdays_short' => ['እኁድ', 'ሰኑይ', 'ሠሉስ', 'ራብዕ', 'ሐሙስ', 'ዓርበ', 'ቀዳሚ'],\n    'weekdays_min' => ['እኁድ', 'ሰኑይ', 'ሠሉስ', 'ራብዕ', 'ሐሙስ', 'ዓርበ', 'ቀዳሚ'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['ጽባሕ', 'ምሴት'],\n\n    'month' => ':count ወርሕ', // less reliable\n    'm' => ':count ወርሕ', // less reliable\n    'a_month' => ':count ወርሕ', // less reliable\n\n    'week' => ':count ሰብዑ', // less reliable\n    'w' => ':count ሰብዑ', // less reliable\n    'a_week' => ':count ሰብዑ', // less reliable\n\n    'hour' => ':count አንትሙ', // less reliable\n    'h' => ':count አንትሙ', // less reliable\n    'a_hour' => ':count አንትሙ', // less reliable\n\n    'minute' => ':count ንኡስ', // less reliable\n    'min' => ':count ንኡስ', // less reliable\n    'a_minute' => ':count ንኡስ', // less reliable\n\n    'year' => ':count ዓመት',\n    'y' => ':count ዓመት',\n    'a_year' => ':count ዓመት',\n\n    'day' => ':count ዕለት',\n    'd' => ':count ዕለት',\n    'a_day' => ':count ዕለት',\n\n    'second' => ':count ካልእ',\n    's' => ':count ካልእ',\n    'a_second' => ':count ካልእ',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/gez_ET.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Ge'ez Frontier Foundation    locales@geez.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD/MM/YYYY',\n    ],\n    'months' => ['ጃንዩወሪ', 'ፌብሩወሪ', 'ማርች', 'ኤፕረል', 'ሜይ', 'ጁን', 'ጁላይ', 'ኦገስት', 'ሴፕቴምበር', 'ኦክተውበር', 'ኖቬምበር', 'ዲሴምበር'],\n    'months_short' => ['ጃንዩ', 'ፌብሩ', 'ማርች', 'ኤፕረ', 'ሜይ ', 'ጁን ', 'ጁላይ', 'ኦገስ', 'ሴፕቴ', 'ኦክተ', 'ኖቬም', 'ዲሴም'],\n    'weekdays' => ['እኁድ', 'ሰኑይ', 'ሠሉስ', 'ራብዕ', 'ሐሙስ', 'ዓርበ', 'ቀዳሚት'],\n    'weekdays_short' => ['እኁድ', 'ሰኑይ', 'ሠሉስ', 'ራብዕ', 'ሐሙስ', 'ዓርበ', 'ቀዳሚ'],\n    'weekdays_min' => ['እኁድ', 'ሰኑይ', 'ሠሉስ', 'ራብዕ', 'ሐሙስ', 'ዓርበ', 'ቀዳሚ'],\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['ጽባሕ', 'ምሴት'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/gl.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - François B\n * - Fidel Pita\n * - JD Isaacks\n * - Diego Vilariño\n * - Sebastian Thierer\n */\n\nuse Carbon\\CarbonInterface;\n\nreturn [\n    'year' => ':count ano|:count anos',\n    'a_year' => 'un ano|:count anos',\n    'y' => ':count a.',\n    'month' => ':count mes|:count meses',\n    'a_month' => 'un mes|:count meses',\n    'm' => ':count mes.',\n    'week' => ':count semana|:count semanas',\n    'a_week' => 'unha semana|:count semanas',\n    'w' => ':count sem.',\n    'day' => ':count día|:count días',\n    'a_day' => 'un día|:count días',\n    'd' => ':count d.',\n    'hour' => ':count hora|:count horas',\n    'a_hour' => 'unha hora|:count horas',\n    'h' => ':count h.',\n    'minute' => ':count minuto|:count minutos',\n    'a_minute' => 'un minuto|:count minutos',\n    'min' => ':count min.',\n    'second' => ':count segundo|:count segundos',\n    'a_second' => 'uns segundos|:count segundos',\n    's' => ':count seg.',\n    'ago' => 'hai :time',\n    'from_now' => function ($time) {\n        if (str_starts_with($time, 'un')) {\n            return \"n$time\";\n        }\n\n        return \"en $time\";\n    },\n    'diff_now' => 'agora',\n    'diff_today' => 'hoxe',\n    'diff_today_regexp' => 'hoxe(?:\\\\s+ás)?',\n    'diff_yesterday' => 'onte',\n    'diff_yesterday_regexp' => 'onte(?:\\\\s+á)?',\n    'diff_tomorrow' => 'mañá',\n    'diff_tomorrow_regexp' => 'mañá(?:\\\\s+ás)?',\n    'after' => ':time despois',\n    'before' => ':time antes',\n    'formats' => [\n        'LT' => 'H:mm',\n        'LTS' => 'H:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D [de] MMMM [de] YYYY',\n        'LLL' => 'D [de] MMMM [de] YYYY H:mm',\n        'LLLL' => 'dddd, D [de] MMMM [de] YYYY H:mm',\n    ],\n    'calendar' => [\n        'sameDay' => function (CarbonInterface $current) {\n            return '[hoxe '.($current->hour !== 1 ? 'ás' : 'á').'] LT';\n        },\n        'nextDay' => function (CarbonInterface $current) {\n            return '[mañá '.($current->hour !== 1 ? 'ás' : 'á').'] LT';\n        },\n        'nextWeek' => function (CarbonInterface $current) {\n            return 'dddd ['.($current->hour !== 1 ? 'ás' : 'á').'] LT';\n        },\n        'lastDay' => function (CarbonInterface $current) {\n            return '[onte '.($current->hour !== 1 ? 'á' : 'a').'] LT';\n        },\n        'lastWeek' => function (CarbonInterface $current) {\n            return '[o] dddd [pasado '.($current->hour !== 1 ? 'ás' : 'á').'] LT';\n        },\n        'sameElse' => 'L',\n    ],\n    'ordinal' => ':numberº',\n    'months' => ['xaneiro', 'febreiro', 'marzo', 'abril', 'maio', 'xuño', 'xullo', 'agosto', 'setembro', 'outubro', 'novembro', 'decembro'],\n    'months_short' => ['xan.', 'feb.', 'mar.', 'abr.', 'mai.', 'xuñ.', 'xul.', 'ago.', 'set.', 'out.', 'nov.', 'dec.'],\n    'weekdays' => ['domingo', 'luns', 'martes', 'mércores', 'xoves', 'venres', 'sábado'],\n    'weekdays_short' => ['dom.', 'lun.', 'mar.', 'mér.', 'xov.', 'ven.', 'sáb.'],\n    'weekdays_min' => ['do', 'lu', 'ma', 'mé', 'xo', 've', 'sá'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n    'list' => [', ', ' e '],\n    'meridiem' => ['a.m.', 'p.m.'],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/gl_ES.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/gl.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/gom.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/gom_Latn.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/gom_Latn.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn [\n    'year' => ':count voros|:count vorsam',\n    'y' => ':countv',\n    'month' => ':count mhoino|:count mhoine',\n    'm' => ':countmh',\n    'week' => ':count satolleacho|:count satolleache',\n    'w' => ':countsa|:countsa',\n    'day' => ':count dis',\n    'd' => ':countd',\n    'hour' => ':count hor|:count horam',\n    'h' => ':counth',\n    'minute' => ':count minute|:count mintam',\n    'min' => ':countm',\n    'second' => ':count second',\n    's' => ':counts',\n\n    'diff_today' => 'Aiz',\n    'diff_yesterday' => 'Kal',\n    'diff_tomorrow' => 'Faleam',\n    'formats' => [\n        'LT' => 'A h:mm [vazta]',\n        'LTS' => 'A h:mm:ss [vazta]',\n        'L' => 'DD-MM-YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY A h:mm [vazta]',\n        'LLLL' => 'dddd, MMMM[achea] Do, YYYY, A h:mm [vazta]',\n        'llll' => 'ddd, D MMM YYYY, A h:mm [vazta]',\n    ],\n\n    'calendar' => [\n        'sameDay' => '[Aiz] LT',\n        'nextDay' => '[Faleam] LT',\n        'nextWeek' => '[Ieta to] dddd[,] LT',\n        'lastDay' => '[Kal] LT',\n        'lastWeek' => '[Fatlo] dddd[,] LT',\n        'sameElse' => 'L',\n    ],\n\n    'months' => ['Janer', 'Febrer', 'Mars', 'Abril', 'Mai', 'Jun', 'Julai', 'Agost', 'Setembr', 'Otubr', 'Novembr', 'Dezembr'],\n    'months_short' => ['Jan.', 'Feb.', 'Mars', 'Abr.', 'Mai', 'Jun', 'Jul.', 'Ago.', 'Set.', 'Otu.', 'Nov.', 'Dez.'],\n    'weekdays' => ['Aitar', 'Somar', 'Mongllar', 'Budvar', 'Brestar', 'Sukrar', 'Son\\'var'],\n    'weekdays_short' => ['Ait.', 'Som.', 'Mon.', 'Bud.', 'Bre.', 'Suk.', 'Son.'],\n    'weekdays_min' => ['Ai', 'Sm', 'Mo', 'Bu', 'Br', 'Su', 'Sn'],\n\n    'ordinal' => function ($number, $period) {\n        return $number.($period === 'D' ? 'er' : '');\n    },\n\n    'meridiem' => function ($hour) {\n        if ($hour < 4) {\n            return 'rati';\n        }\n        if ($hour < 12) {\n            return 'sokalli';\n        }\n        if ($hour < 16) {\n            return 'donparam';\n        }\n        if ($hour < 20) {\n            return 'sanje';\n        }\n\n        return 'rati';\n    },\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n    'list' => [', ', ' ani '],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/gsw.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Christopher Dell\n * - Akira Matsuda\n * - Enrique Vidal\n * - Simone Carletti\n * - Henning Kiel\n * - Aaron Patterson\n * - Florian Hanke\n */\nreturn [\n    'year' => ':count Johr',\n    'month' => ':count Monet',\n    'week' => ':count Woche',\n    'day' => ':count Tag',\n    'hour' => ':count Schtund',\n    'minute' => ':count Minute',\n    'second' => ':count Sekunde',\n    'weekdays' => ['Sunntig', 'Mäntig', 'Ziischtig', 'Mittwuch', 'Dunschtig', 'Friitig', 'Samschtig'],\n    'weekdays_short' => ['Su', 'Mä', 'Zi', 'Mi', 'Du', 'Fr', 'Sa'],\n    'weekdays_min' => ['Su', 'Mä', 'Zi', 'Mi', 'Du', 'Fr', 'Sa'],\n    'months' => ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'Auguscht', 'September', 'Oktober', 'November', 'Dezember'],\n    'months_short' => ['Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'],\n    'meridiem' => ['am Vormittag', 'am Namittag'],\n    'ordinal' => ':number.',\n    'list' => [', ', ' und '],\n    'diff_now' => 'now',\n    'diff_yesterday' => 'geschter',\n    'diff_tomorrow' => 'moorn',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD.MM.YYYY',\n        'LL' => 'Do MMMM YYYY',\n        'LLL' => 'Do MMMM, HH:mm [Uhr]',\n        'LLLL' => 'dddd, Do MMMM YYYY, HH:mm [Uhr]',\n    ],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/gsw_CH.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/gsw.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/gsw_FR.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/gsw.php', [\n    'meridiem' => ['vorm.', 'nam.'],\n    'months' => ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'Auguscht', 'Septämber', 'Oktoober', 'Novämber', 'Dezämber'],\n    'first_day_of_week' => 1,\n    'formats' => [\n        'LLL' => 'Do MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, Do MMMM YYYY HH:mm',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/gsw_LI.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/gsw.php', [\n    'meridiem' => ['vorm.', 'nam.'],\n    'months' => ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'Auguscht', 'Septämber', 'Oktoober', 'Novämber', 'Dezämber'],\n    'first_day_of_week' => 1,\n    'formats' => [\n        'LLL' => 'Do MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, Do MMMM YYYY HH:mm',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/gu.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Josh Soref\n * - Kaushik Thanki\n * - Josh Soref\n */\nreturn [\n    'year' => 'એક વર્ષ|:count વર્ષ',\n    'y' => ':countવર્ષ|:countવર્ષો',\n    'month' => 'એક મહિનો|:count મહિના',\n    'm' => ':countમહિનો|:countમહિના',\n    'week' => ':count અઠવાડિયું|:count અઠવાડિયા',\n    'w' => ':countઅઠ.|:countઅઠ.',\n    'day' => 'એક દિવસ|:count દિવસ',\n    'd' => ':countદિ.|:countદિ.',\n    'hour' => 'એક કલાક|:count કલાક',\n    'h' => ':countક.|:countક.',\n    'minute' => 'એક મિનિટ|:count મિનિટ',\n    'min' => ':countમિ.|:countમિ.',\n    'second' => 'અમુક પળો|:count સેકંડ',\n    's' => ':countસે.|:countસે.',\n    'ago' => ':time પેહલા',\n    'from_now' => ':time મા',\n    'after' => ':time પછી',\n    'before' => ':time પહેલા',\n    'diff_now' => 'હમણાં',\n    'diff_today' => 'આજ',\n    'diff_yesterday' => 'ગઇકાલે',\n    'diff_tomorrow' => 'કાલે',\n    'formats' => [\n        'LT' => 'A h:mm વાગ્યે',\n        'LTS' => 'A h:mm:ss વાગ્યે',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY, A h:mm વાગ્યે',\n        'LLLL' => 'dddd, D MMMM YYYY, A h:mm વાગ્યે',\n    ],\n    'calendar' => [\n        'sameDay' => '[આજ] LT',\n        'nextDay' => '[કાલે] LT',\n        'nextWeek' => 'dddd, LT',\n        'lastDay' => '[ગઇકાલે] LT',\n        'lastWeek' => '[પાછલા] dddd, LT',\n        'sameElse' => 'L',\n    ],\n    'meridiem' => function ($hour) {\n        if ($hour < 4) {\n            return 'રાત';\n        }\n        if ($hour < 10) {\n            return 'સવાર';\n        }\n        if ($hour < 17) {\n            return 'બપોર';\n        }\n        if ($hour < 20) {\n            return 'સાંજ';\n        }\n\n        return 'રાત';\n    },\n    'months' => ['જાન્યુઆરી', 'ફેબ્રુઆરી', 'માર્ચ', 'એપ્રિલ', 'મે', 'જૂન', 'જુલાઈ', 'ઑગસ્ટ', 'સપ્ટેમ્બર', 'ઑક્ટ્બર', 'નવેમ્બર', 'ડિસેમ્બર'],\n    'months_short' => ['જાન્યુ.', 'ફેબ્રુ.', 'માર્ચ', 'એપ્રિ.', 'મે', 'જૂન', 'જુલા.', 'ઑગ.', 'સપ્ટે.', 'ઑક્ટ્.', 'નવે.', 'ડિસે.'],\n    'weekdays' => ['રવિવાર', 'સોમવાર', 'મંગળવાર', 'બુધ્વાર', 'ગુરુવાર', 'શુક્રવાર', 'શનિવાર'],\n    'weekdays_short' => ['રવિ', 'સોમ', 'મંગળ', 'બુધ્', 'ગુરુ', 'શુક્ર', 'શનિ'],\n    'weekdays_min' => ['ર', 'સો', 'મં', 'બુ', 'ગુ', 'શુ', 'શ'],\n    'list' => [', ', ' અને '],\n    'first_day_of_week' => 0,\n    'day_of_first_week_of_year' => 1,\n    'weekend' => [0, 0],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/gu_IN.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/gu.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/guz.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'meridiem' => ['Ma', 'Mo'],\n    'weekdays' => ['Chumapiri', 'Chumatato', 'Chumaine', 'Chumatano', 'Aramisi', 'Ichuma', 'Esabato'],\n    'weekdays_short' => ['Cpr', 'Ctt', 'Cmn', 'Cmt', 'Ars', 'Icm', 'Est'],\n    'weekdays_min' => ['Cpr', 'Ctt', 'Cmn', 'Cmt', 'Ars', 'Icm', 'Est'],\n    'months' => ['Chanuari', 'Feburari', 'Machi', 'Apiriri', 'Mei', 'Juni', 'Chulai', 'Agosti', 'Septemba', 'Okitoba', 'Nobemba', 'Disemba'],\n    'months_short' => ['Can', 'Feb', 'Mac', 'Apr', 'Mei', 'Jun', 'Cul', 'Agt', 'Sep', 'Okt', 'Nob', 'Dis'],\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY HH:mm',\n    ],\n\n    'month' => ':count omotunyi', // less reliable\n    'm' => ':count omotunyi', // less reliable\n    'a_month' => ':count omotunyi', // less reliable\n\n    'week' => ':count isano naibere', // less reliable\n    'w' => ':count isano naibere', // less reliable\n    'a_week' => ':count isano naibere', // less reliable\n\n    'second' => ':count ibere', // less reliable\n    's' => ':count ibere', // less reliable\n    'a_second' => ':count ibere', // less reliable\n\n    'year' => ':count omwaka',\n    'y' => ':count omwaka',\n    'a_year' => ':count omwaka',\n\n    'day' => ':count rituko',\n    'd' => ':count rituko',\n    'a_day' => ':count rituko',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/gv.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/gv_GB.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/gv_GB.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Alastair McKinstry    bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD/MM/YY',\n    ],\n    'months' => ['Jerrey-geuree', 'Toshiaght-arree', 'Mayrnt', 'Averil', 'Boaldyn', 'Mean-souree', 'Jerrey-souree', 'Luanistyn', 'Mean-fouyir', 'Jerrey-fouyir', 'Mee Houney', 'Mee ny Nollick'],\n    'months_short' => ['J-guer', 'T-arree', 'Mayrnt', 'Avrril', 'Boaldyn', 'M-souree', 'J-souree', 'Luanistyn', 'M-fouyir', 'J-fouyir', 'M.Houney', 'M.Nollick'],\n    'weekdays' => ['Jedoonee', 'Jelhein', 'Jemayrt', 'Jercean', 'Jerdein', 'Jeheiney', 'Jesarn'],\n    'weekdays_short' => ['Jed', 'Jel', 'Jem', 'Jerc', 'Jerd', 'Jeh', 'Jes'],\n    'weekdays_min' => ['Jed', 'Jel', 'Jem', 'Jerc', 'Jerd', 'Jeh', 'Jes'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n\n    'year' => ':count blein',\n    'y' => ':count blein',\n    'a_year' => ':count blein',\n\n    'month' => ':count mee',\n    'm' => ':count mee',\n    'a_month' => ':count mee',\n\n    'week' => ':count shiaghtin',\n    'w' => ':count shiaghtin',\n    'a_week' => ':count shiaghtin',\n\n    'day' => ':count laa',\n    'd' => ':count laa',\n    'a_day' => ':count laa',\n\n    'hour' => ':count oor',\n    'h' => ':count oor',\n    'a_hour' => ':count oor',\n\n    'minute' => ':count feer veg',\n    'min' => ':count feer veg',\n    'a_minute' => ':count feer veg',\n\n    'second' => ':count derrey',\n    's' => ':count derrey',\n    'a_second' => ':count derrey',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ha.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - pablo@mandriva.com\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'D/M/YYYY',\n        'LL' => 'D MMM, YYYY',\n        'LLL' => 'D MMMM, YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM, YYYY HH:mm',\n    ],\n    'months' => ['Janairu', 'Faburairu', 'Maris', 'Afirilu', 'Mayu', 'Yuni', 'Yuli', 'Agusta', 'Satumba', 'Oktoba', 'Nuwamba', 'Disamba'],\n    'months_short' => ['Jan', 'Fab', 'Mar', 'Afi', 'May', 'Yun', 'Yul', 'Agu', 'Sat', 'Okt', 'Nuw', 'Dis'],\n    'weekdays' => ['Lahadi', 'Litini', 'Talata', 'Laraba', 'Alhamis', 'Jumaʼa', 'Asabar'],\n    'weekdays_short' => ['Lah', 'Lit', 'Tal', 'Lar', 'Alh', 'Jum', 'Asa'],\n    'weekdays_min' => ['Lh', 'Li', 'Ta', 'Lr', 'Al', 'Ju', 'As'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n\n    'year' => 'shekara :count',\n    'y' => 'shekara :count',\n    'a_year' => 'shekara :count',\n\n    'month' => ':count wátàa',\n    'm' => ':count wátàa',\n    'a_month' => ':count wátàa',\n\n    'week' => ':count mako',\n    'w' => ':count mako',\n    'a_week' => ':count mako',\n\n    'day' => ':count rana',\n    'd' => ':count rana',\n    'a_day' => ':count rana',\n\n    'hour' => ':count áwàa',\n    'h' => ':count áwàa',\n    'a_hour' => ':count áwàa',\n\n    'minute' => 'minti :count',\n    'min' => 'minti :count',\n    'a_minute' => 'minti :count',\n\n    'second' => ':count ná bíyú',\n    's' => ':count ná bíyú',\n    'a_second' => ':count ná bíyú',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ha_GH.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/ha.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ha_NE.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/ha.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ha_NG.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/ha.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/hak.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/hak_TW.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/hak_TW.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'YYYY年MM月DD日',\n    ],\n    'months' => ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'],\n    'months_short' => [' 1月', ' 2月', ' 3月', ' 4月', ' 5月', ' 6月', ' 7月', ' 8月', ' 9月', '10月', '11月', '12月'],\n    'weekdays' => ['禮拜日', '禮拜一', '禮拜二', '禮拜三', '禮拜四', '禮拜五', '禮拜六'],\n    'weekdays_short' => ['日', '一', '二', '三', '四', '五', '六'],\n    'weekdays_min' => ['日', '一', '二', '三', '四', '五', '六'],\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['上晝', '下晝'],\n\n    'year' => ':count ngien11',\n    'y' => ':count ngien11',\n    'a_year' => ':count ngien11',\n\n    'month' => ':count ngie̍t',\n    'm' => ':count ngie̍t',\n    'a_month' => ':count ngie̍t',\n\n    'week' => ':count lî-pai',\n    'w' => ':count lî-pai',\n    'a_week' => ':count lî-pai',\n\n    'day' => ':count ngit',\n    'd' => ':count ngit',\n    'a_day' => ':count ngit',\n\n    'hour' => ':count sṳ̀',\n    'h' => ':count sṳ̀',\n    'a_hour' => ':count sṳ̀',\n\n    'minute' => ':count fûn',\n    'min' => ':count fûn',\n    'a_minute' => ':count fûn',\n\n    'second' => ':count miéu',\n    's' => ':count miéu',\n    'a_second' => ':count miéu',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/haw.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'months' => ['Ianuali', 'Pepeluali', 'Malaki', 'ʻApelila', 'Mei', 'Iune', 'Iulai', 'ʻAukake', 'Kepakemapa', 'ʻOkakopa', 'Nowemapa', 'Kekemapa'],\n    'months_short' => ['Ian.', 'Pep.', 'Mal.', 'ʻAp.', 'Mei', 'Iun.', 'Iul.', 'ʻAu.', 'Kep.', 'ʻOk.', 'Now.', 'Kek.'],\n    'weekdays' => ['Lāpule', 'Poʻakahi', 'Poʻalua', 'Poʻakolu', 'Poʻahā', 'Poʻalima', 'Poʻaono'],\n    'weekdays_short' => ['LP', 'P1', 'P2', 'P3', 'P4', 'P5', 'P6'],\n    'weekdays_min' => ['S', 'M', 'T', 'W', 'T', 'F', 'S'],\n    'formats' => [\n        'LT' => 'h:mm a',\n        'LTS' => 'h:mm:ss a',\n        'L' => 'D/M/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY h:mm a',\n        'LLLL' => 'dddd, D MMMM YYYY h:mm a',\n    ],\n\n    'year' => ':count makahiki',\n    'y' => ':count makahiki',\n    'a_year' => ':count makahiki',\n\n    'month' => ':count mahina',\n    'm' => ':count mahina',\n    'a_month' => ':count mahina',\n\n    'week' => ':count pule',\n    'w' => ':count pule',\n    'a_week' => ':count pule',\n\n    'day' => ':count lā',\n    'd' => ':count lā',\n    'a_day' => ':count lā',\n\n    'hour' => ':count hola',\n    'h' => ':count hola',\n    'a_hour' => ':count hola',\n\n    'minute' => ':count minuke',\n    'min' => ':count minuke',\n    'a_minute' => ':count minuke',\n\n    'second' => ':count lua',\n    's' => ':count lua',\n    'a_second' => ':count lua',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/he.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Daniel Cohen Gindi\n * - JD Isaacks\n * - Itai Nathaniel\n * - GabMic\n * - Yaakov Dahan (yakidahan)\n */\nreturn [\n    'year' => 'שנה|{2}שנתיים|:count שנים',\n    'y' => 'שנה|:count שנ׳',\n    'month' => 'חודש|{2}חודשיים|:count חודשים',\n    'm' => 'חודש|:count חו׳',\n    'week' => 'שבוע|{2}שבועיים|:count שבועות',\n    'w' => 'שבוע|:count שב׳',\n    'day' => 'יום|{2}יומיים|:count ימים',\n    'd' => 'יום|:count ימ׳',\n    'hour' => 'שעה|{2}שעתיים|:count שעות',\n    'h' => 'שעה|:count שע׳',\n    'minute' => 'דקה|{2}שתי דקות|:count דקות',\n    'min' => 'דקה|:count דק׳',\n    'second' => 'שנייה|:count שניות',\n    'a_second' => 'כמה שניות|:count שניות',\n    's' => 'שניה|:count שנ׳',\n    'ago' => 'לפני :time',\n    'from_now' => 'בעוד :time מעכשיו',\n    'after' => 'אחרי :time',\n    'before' => 'לפני :time',\n    'diff_now' => 'עכשיו',\n    'diff_today' => 'היום',\n    'diff_today_regexp' => 'היום(?:\\\\s+ב־)?',\n    'diff_yesterday' => 'אתמול',\n    'diff_yesterday_regexp' => 'אתמול(?:\\\\s+ב־)?',\n    'diff_tomorrow' => 'מחר',\n    'diff_tomorrow_regexp' => 'מחר(?:\\\\s+ב־)?',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D [ב]MMMM YYYY',\n        'LLL' => 'D [ב]MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D [ב]MMMM YYYY HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[היום ב־]LT',\n        'nextDay' => '[מחר ב־]LT',\n        'nextWeek' => 'dddd [בשעה] LT',\n        'lastDay' => '[אתמול ב־]LT',\n        'lastWeek' => '[ביום] dddd [האחרון בשעה] LT',\n        'sameElse' => 'L',\n    ],\n    'meridiem' => function ($hour, $minute, $isLower) {\n        if ($hour < 5) {\n            return 'לפנות בוקר';\n        }\n        if ($hour < 10) {\n            return 'בבוקר';\n        }\n        if ($hour < 12) {\n            return $isLower ? 'לפנה\"צ' : 'לפני הצהריים';\n        }\n        if ($hour < 18) {\n            return $isLower ? 'אחה\"צ' : 'אחרי הצהריים';\n        }\n\n        return 'בערב';\n    },\n    'months' => ['ינואר', 'פברואר', 'מרץ', 'אפריל', 'מאי', 'יוני', 'יולי', 'אוגוסט', 'ספטמבר', 'אוקטובר', 'נובמבר', 'דצמבר'],\n    'months_short' => ['ינו׳', 'פבר׳', 'מרץ', 'אפר׳', 'מאי', 'יוני', 'יולי', 'אוג׳', 'ספט׳', 'אוק׳', 'נוב׳', 'דצמ׳'],\n    'weekdays' => ['ראשון', 'שני', 'שלישי', 'רביעי', 'חמישי', 'שישי', 'שבת'],\n    'weekdays_short' => ['א׳', 'ב׳', 'ג׳', 'ד׳', 'ה׳', 'ו׳', 'ש׳'],\n    'weekdays_min' => ['א', 'ב', 'ג', 'ד', 'ה', 'ו', 'ש'],\n    'list' => [', ', ' ו -'],\n    'weekend' => [5, 6],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/he_IL.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/he.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/hi.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - abhimanyu003\n * - Josh Soref\n * - JD Isaacks\n */\nreturn [\n    'year' => 'एक वर्ष|:count वर्ष',\n    'y' => '1 वर्ष|:count वर्षों',\n    'month' => 'एक महीने|:count महीने',\n    'm' => '1 माह|:count महीने',\n    'week' => '1 सप्ताह|:count सप्ताह',\n    'w' => '1 सप्ताह|:count सप्ताह',\n    'day' => 'एक दिन|:count दिन',\n    'd' => '1 दिन|:count दिनों',\n    'hour' => 'एक घंटा|:count घंटे',\n    'h' => '1 घंटा|:count घंटे',\n    'minute' => 'एक मिनट|:count मिनट',\n    'min' => '1 मिनट|:count मिनटों',\n    'second' => 'कुछ ही क्षण|:count सेकंड',\n    's' => '1 सेकंड|:count सेकंड',\n    'ago' => ':time पहले',\n    'from_now' => ':time में',\n    'after' => ':time के बाद',\n    'before' => ':time के पहले',\n    'diff_now' => 'अब',\n    'diff_today' => 'आज',\n    'diff_yesterday' => 'कल',\n    'diff_tomorrow' => 'कल',\n    'formats' => [\n        'LT' => 'A h:mm बजे',\n        'LTS' => 'A h:mm:ss बजे',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY, A h:mm बजे',\n        'LLLL' => 'dddd, D MMMM YYYY, A h:mm बजे',\n    ],\n    'calendar' => [\n        'sameDay' => '[आज] LT',\n        'nextDay' => '[कल] LT',\n        'nextWeek' => 'dddd, LT',\n        'lastDay' => '[कल] LT',\n        'lastWeek' => '[पिछले] dddd, LT',\n        'sameElse' => 'L',\n    ],\n    'meridiem' => function ($hour) {\n        if ($hour < 4) {\n            return 'रात';\n        }\n        if ($hour < 10) {\n            return 'सुबह';\n        }\n        if ($hour < 17) {\n            return 'दोपहर';\n        }\n        if ($hour < 20) {\n            return 'शाम';\n        }\n\n        return 'रात';\n    },\n    'months' => ['जनवरी', 'फ़रवरी', 'मार्च', 'अप्रैल', 'मई', 'जून', 'जुलाई', 'अगस्त', 'सितम्बर', 'अक्टूबर', 'नवम्बर', 'दिसम्बर'],\n    'months_short' => ['जन.', 'फ़र.', 'मार्च', 'अप्रै.', 'मई', 'जून', 'जुल.', 'अग.', 'सित.', 'अक्टू.', 'नव.', 'दिस.'],\n    'weekdays' => ['रविवार', 'सोमवार', 'मंगलवार', 'बुधवार', 'गुरूवार', 'शुक्रवार', 'शनिवार'],\n    'weekdays_short' => ['रवि', 'सोम', 'मंगल', 'बुध', 'गुरू', 'शुक्र', 'शनि'],\n    'weekdays_min' => ['र', 'सो', 'मं', 'बु', 'गु', 'शु', 'श'],\n    'list' => [', ', ' और '],\n    'first_day_of_week' => 0,\n    'day_of_first_week_of_year' => 1,\n    'weekend' => [0, 0],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/hi_IN.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/hi.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/hif.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/hif_FJ.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/hif_FJ.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Samsung Electronics Co., Ltd.    akhilesh.k@samsung.com\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'dddd DD MMM YYYY',\n    ],\n    'months' => ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],\n    'months_short' => ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],\n    'weekdays' => ['Ravivar', 'Somvar', 'Mangalvar', 'Budhvar', 'Guruvar', 'Shukravar', 'Shanivar'],\n    'weekdays_short' => ['Ravi', 'Som', 'Mangal', 'Budh', 'Guru', 'Shukra', 'Shani'],\n    'weekdays_min' => ['Ravi', 'Som', 'Mangal', 'Budh', 'Guru', 'Shukra', 'Shani'],\n    'meridiem' => ['Purvahan', 'Aparaahna'],\n\n    'hour' => ':count minit', // less reliable\n    'h' => ':count minit', // less reliable\n    'a_hour' => ':count minit', // less reliable\n\n    'year' => ':count saal',\n    'y' => ':count saal',\n    'a_year' => ':count saal',\n\n    'month' => ':count Mahina',\n    'm' => ':count Mahina',\n    'a_month' => ':count Mahina',\n\n    'week' => ':count Hafta',\n    'w' => ':count Hafta',\n    'a_week' => ':count Hafta',\n\n    'day' => ':count Din',\n    'd' => ':count Din',\n    'a_day' => ':count Din',\n\n    'minute' => ':count Minit',\n    'min' => ':count Minit',\n    'a_minute' => ':count Minit',\n\n    'second' => ':count Second',\n    's' => ':count Second',\n    'a_second' => ':count Second',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/hne.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/hne_IN.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/hne_IN.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Red Hat, Pune    bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'D/M/YY',\n    ],\n    'months' => ['जनवरी', 'फरवरी', 'मार्च', 'अपरेल', 'मई', 'जून', 'जुलाई', 'अगस्त', 'सितमबर', 'अकटूबर', 'नवमबर', 'दिसमबर'],\n    'months_short' => ['जन', 'फर', 'मार्च', 'अप', 'मई', 'जून', 'जुला', 'अग', 'सित', 'अकटू', 'नव', 'दिस'],\n    'weekdays' => ['इतवार', 'सोमवार', 'मंगलवार', 'बुधवार', 'बिरसपत', 'सुकरवार', 'सनिवार'],\n    'weekdays_short' => ['इत', 'सोम', 'मंग', 'बुध', 'बिर', 'सुक', 'सनि'],\n    'weekdays_min' => ['इत', 'सोम', 'मंग', 'बुध', 'बिर', 'सुक', 'सनि'],\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['बिहिनियाँ', 'मंझनियाँ'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/hr.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Josh Soref\n * - François B\n * - Tim Fish\n * - shaishavgandhi05\n * - Serhan Apaydın\n * - JD Isaacks\n * - tomhorvat\n * - Josh Soref\n * - François B\n * - shaishavgandhi05\n * - Serhan Apaydın\n * - JD Isaacks\n * - tomhorvat\n * - Stjepan Majdak\n * - Vanja Retkovac (vr00)\n */\n\nuse Carbon\\CarbonInterface;\n\nreturn [\n    'year' => ':count godinu|:count godine|:count godina',\n    'y' => ':count god.|:count god.|:count god.',\n    'month' => ':count mjesec|:count mjeseca|:count mjeseci',\n    'm' => ':count mj.|:count mj.|:count mj.',\n    'week' => ':count tjedan|:count tjedna|:count tjedana',\n    'w' => ':count tj.|:count tj.|:count tj.',\n    'day' => ':count dan|:count dana|:count dana',\n    'd' => ':count d.|:count d.|:count d.',\n    'hour' => ':count sat|:count sata|:count sati',\n    'h' => ':count sat|:count sata|:count sati',\n    'minute' => ':count minutu|:count minute|:count minuta',\n    'min' => ':count min.|:count min.|:count min.',\n    'second' => ':count sekundu|:count sekunde|:count sekundi',\n    'a_second' => 'nekoliko sekundi|:count sekunde|:count sekundi',\n    's' => ':count sek.|:count sek.|:count sek.',\n    'ago' => 'prije :time',\n    'from_now' => 'za :time',\n    'after' => ':time poslije',\n    'before' => ':time prije',\n    'diff_now' => 'sad',\n    'diff_today' => 'danas',\n    'diff_today_regexp' => 'danas(?:\\\\s+u)?',\n    'diff_yesterday' => 'jučer',\n    'diff_yesterday_regexp' => 'jučer(?:\\\\s+u)?',\n    'diff_tomorrow' => 'sutra',\n    'diff_tomorrow_regexp' => 'sutra(?:\\\\s+u)?',\n    'diff_before_yesterday' => 'prekjučer',\n    'diff_after_tomorrow' => 'prekosutra',\n    'formats' => [\n        'LT' => 'H:mm',\n        'LTS' => 'H:mm:ss',\n        'L' => 'D. M. YYYY.',\n        'LL' => 'D. MMMM YYYY.',\n        'LLL' => 'D. MMMM YYYY. H:mm',\n        'LLLL' => 'dddd, D. MMMM YYYY. H:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[danas u] LT',\n        'nextDay' => '[sutra u] LT',\n        'nextWeek' => function (CarbonInterface $date) {\n            switch ($date->dayOfWeek) {\n                case 0:\n                    return '[u] [nedjelju] [u] LT';\n                case 3:\n                    return '[u] [srijedu] [u] LT';\n                case 6:\n                    return '[u] [subotu] [u] LT';\n                default:\n                    return '[u] dddd [u] LT';\n            }\n        },\n        'lastDay' => '[jučer u] LT',\n        'lastWeek' => function (CarbonInterface $date) {\n            switch ($date->dayOfWeek) {\n                case 0:\n                case 3:\n                    return '[prošlu] dddd [u] LT';\n                case 6:\n                    return '[prošle] [subote] [u] LT';\n                default:\n                    return '[prošli] dddd [u] LT';\n            }\n        },\n        'sameElse' => 'L',\n    ],\n    'ordinal' => ':number.',\n    'months' => ['siječnja', 'veljače', 'ožujka', 'travnja', 'svibnja', 'lipnja', 'srpnja', 'kolovoza', 'rujna', 'listopada', 'studenoga', 'prosinca'],\n    'months_standalone' => ['siječanj', 'veljača', 'ožujak', 'travanj', 'svibanj', 'lipanj', 'srpanj', 'kolovoz', 'rujan', 'listopad', 'studeni', 'prosinac'],\n    'months_short' => ['sij.', 'velj.', 'ožu.', 'tra.', 'svi.', 'lip.', 'srp.', 'kol.', 'ruj.', 'lis.', 'stu.', 'pro.'],\n    'months_regexp' => '/(D[oD]?(\\[[^\\[\\]]*\\]|\\s)+MMMM?|L{2,4}|l{2,4})/',\n    'weekdays' => ['nedjelju', 'ponedjeljak', 'utorak', 'srijedu', 'četvrtak', 'petak', 'subotu'],\n    'weekdays_standalone' => ['nedjelja', 'ponedjeljak', 'utorak', 'srijeda', 'četvrtak', 'petak', 'subota'],\n    'weekdays_short' => ['ned.', 'pon.', 'uto.', 'sri.', 'čet.', 'pet.', 'sub.'],\n    'weekdays_min' => ['ne', 'po', 'ut', 'sr', 'če', 'pe', 'su'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n    'list' => [', ', ' i '],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/hr_BA.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - DarkoDevelop\n */\nreturn array_replace_recursive(require __DIR__.'/hr.php', [\n    'weekdays' => ['nedjelja', 'ponedjeljak', 'utorak', 'srijeda', 'četvrtak', 'petak', 'subota'],\n    'weekdays_short' => ['ned', 'pon', 'uto', 'sri', 'čet', 'pet', 'sub'],\n    'weekdays_min' => ['ned', 'pon', 'uto', 'sri', 'čet', 'pet', 'sub'],\n    'months' => ['siječnja', 'veljače', 'ožujka', 'travnja', 'svibnja', 'lipnja', 'srpnja', 'kolovoza', 'rujna', 'listopada', 'studenoga', 'prosinca'],\n    'months_short' => ['sij', 'velj', 'ožu', 'tra', 'svi', 'lip', 'srp', 'kol', 'ruj', 'lis', 'stu', 'pro'],\n    'months_standalone' => ['siječanj', 'veljača', 'ožujak', 'travanj', 'svibanj', 'lipanj', 'srpanj', 'kolovoz', 'rujan', 'listopad', 'studeni', 'prosinac'],\n    'first_day_of_week' => 1,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'D. M. yy.',\n        'LL' => 'D. MMM YYYY.',\n        'LLL' => 'D. MMMM YYYY. HH:mm',\n        'LLLL' => 'dddd, D. MMMM YYYY. HH:mm',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/hr_HR.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/hr.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/hsb.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/hsb_DE.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/hsb_DE.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Information from Michael Wolf Andrzej Krzysztofowicz ankry@mif.pg.gda.pl\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD.MM.YYYY',\n        'LL' => 'DD. MMMM YYYY',\n        'LLL' => 'DD. MMMM, HH:mm [hodź.]',\n        'LLLL' => 'dddd, DD. MMMM YYYY, HH:mm [hodź.]',\n    ],\n    'months' => ['januara', 'februara', 'měrca', 'apryla', 'meje', 'junija', 'julija', 'awgusta', 'septembra', 'oktobra', 'nowembra', 'decembra'],\n    'months_short' => ['Jan', 'Feb', 'Měr', 'Apr', 'Mej', 'Jun', 'Jul', 'Awg', 'Sep', 'Okt', 'Now', 'Dec'],\n    'weekdays' => ['Njedźela', 'Póndźela', 'Wutora', 'Srjeda', 'Štvórtk', 'Pjatk', 'Sobota'],\n    'weekdays_short' => ['Nj', 'Pó', 'Wu', 'Sr', 'Št', 'Pj', 'So'],\n    'weekdays_min' => ['Nj', 'Pó', 'Wu', 'Sr', 'Št', 'Pj', 'So'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n\n    'year' => ':count lěto',\n    'y' => ':count lěto',\n    'a_year' => ':count lěto',\n\n    'month' => ':count měsac',\n    'm' => ':count měsac',\n    'a_month' => ':count měsac',\n\n    'week' => ':count tydźeń',\n    'w' => ':count tydźeń',\n    'a_week' => ':count tydźeń',\n\n    'day' => ':count dźeń',\n    'd' => ':count dźeń',\n    'a_day' => ':count dźeń',\n\n    'hour' => ':count hodźina',\n    'h' => ':count hodźina',\n    'a_hour' => ':count hodźina',\n\n    'minute' => ':count chwila',\n    'min' => ':count chwila',\n    'a_minute' => ':count chwila',\n\n    'second' => ':count druhi',\n    's' => ':count druhi',\n    'a_second' => ':count druhi',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ht.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/ht_HT.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ht_HT.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Sugar Labs // OLPC sugarlabs.org libc-alpha@sourceware.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD/MM/YYYY',\n    ],\n    'months' => ['janvye', 'fevriye', 'mas', 'avril', 'me', 'jen', 'jiyè', 'out', 'septanm', 'oktòb', 'novanm', 'desanm'],\n    'months_short' => ['jan', 'fev', 'mas', 'avr', 'me', 'jen', 'jiy', 'out', 'sep', 'okt', 'nov', 'des'],\n    'weekdays' => ['dimanch', 'lendi', 'madi', 'mèkredi', 'jedi', 'vandredi', 'samdi'],\n    'weekdays_short' => ['dim', 'len', 'mad', 'mèk', 'jed', 'van', 'sam'],\n    'weekdays_min' => ['dim', 'len', 'mad', 'mèk', 'jed', 'van', 'sam'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n\n    'year' => ':count lane',\n    'y' => ':count lane',\n    'a_year' => ':count lane',\n\n    'month' => 'mwa :count',\n    'm' => 'mwa :count',\n    'a_month' => 'mwa :count',\n\n    'week' => 'semèn :count',\n    'w' => 'semèn :count',\n    'a_week' => 'semèn :count',\n\n    'day' => ':count jou',\n    'd' => ':count jou',\n    'a_day' => ':count jou',\n\n    'hour' => ':count lè',\n    'h' => ':count lè',\n    'a_hour' => ':count lè',\n\n    'minute' => ':count minit',\n    'min' => ':count minit',\n    'a_minute' => ':count minit',\n\n    'second' => ':count segonn',\n    's' => ':count segonn',\n    'a_second' => ':count segonn',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/hu.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Adam Brunner\n * - Brett Johnson\n * - balping\n */\n\nuse Carbon\\CarbonInterface;\n\n$huWeekEndings = ['vasárnap', 'hétfőn', 'kedden', 'szerdán', 'csütörtökön', 'pénteken', 'szombaton'];\n\nreturn [\n    'year' => ':count év',\n    'y' => ':count év',\n    'month' => ':count hónap',\n    'm' => ':count hónap',\n    'week' => ':count hét',\n    'w' => ':count hét',\n    'day' => ':count nap',\n    'd' => ':count nap',\n    'hour' => ':count óra',\n    'h' => ':count óra',\n    'minute' => ':count perc',\n    'min' => ':count perc',\n    'second' => ':count másodperc',\n    's' => ':count másodperc',\n    'ago' => ':time',\n    'from_now' => ':time múlva',\n    'after' => ':time később',\n    'before' => ':time korábban',\n    'year_ago' => ':count éve',\n    'y_ago' => ':count éve',\n    'month_ago' => ':count hónapja',\n    'm_ago' => ':count hónapja',\n    'week_ago' => ':count hete',\n    'w_ago' => ':count hete',\n    'day_ago' => ':count napja',\n    'd_ago' => ':count napja',\n    'hour_ago' => ':count órája',\n    'h_ago' => ':count órája',\n    'minute_ago' => ':count perce',\n    'min_ago' => ':count perce',\n    'second_ago' => ':count másodperce',\n    's_ago' => ':count másodperce',\n    'year_after' => ':count évvel',\n    'y_after' => ':count évvel',\n    'month_after' => ':count hónappal',\n    'm_after' => ':count hónappal',\n    'week_after' => ':count héttel',\n    'w_after' => ':count héttel',\n    'day_after' => ':count nappal',\n    'd_after' => ':count nappal',\n    'hour_after' => ':count órával',\n    'h_after' => ':count órával',\n    'minute_after' => ':count perccel',\n    'min_after' => ':count perccel',\n    'second_after' => ':count másodperccel',\n    's_after' => ':count másodperccel',\n    'year_before' => ':count évvel',\n    'y_before' => ':count évvel',\n    'month_before' => ':count hónappal',\n    'm_before' => ':count hónappal',\n    'week_before' => ':count héttel',\n    'w_before' => ':count héttel',\n    'day_before' => ':count nappal',\n    'd_before' => ':count nappal',\n    'hour_before' => ':count órával',\n    'h_before' => ':count órával',\n    'minute_before' => ':count perccel',\n    'min_before' => ':count perccel',\n    'second_before' => ':count másodperccel',\n    's_before' => ':count másodperccel',\n    'months' => ['január', 'február', 'március', 'április', 'május', 'június', 'július', 'augusztus', 'szeptember', 'október', 'november', 'december'],\n    'months_short' => ['jan.', 'febr.', 'márc.', 'ápr.', 'máj.', 'jún.', 'júl.', 'aug.', 'szept.', 'okt.', 'nov.', 'dec.'],\n    'weekdays' => ['vasárnap', 'hétfő', 'kedd', 'szerda', 'csütörtök', 'péntek', 'szombat'],\n    'weekdays_short' => ['vas', 'hét', 'kedd', 'sze', 'csüt', 'pén', 'szo'],\n    'weekdays_min' => ['v', 'h', 'k', 'sze', 'cs', 'p', 'sz'],\n    'ordinal' => ':number.',\n    'diff_now' => 'most',\n    'diff_today' => 'ma',\n    'diff_yesterday' => 'tegnap',\n    'diff_tomorrow' => 'holnap',\n    'formats' => [\n        'LT' => 'H:mm',\n        'LTS' => 'H:mm:ss',\n        'L' => 'YYYY.MM.DD.',\n        'LL' => 'YYYY. MMMM D.',\n        'LLL' => 'YYYY. MMMM D. H:mm',\n        'LLLL' => 'YYYY. MMMM D., dddd H:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[ma] LT[-kor]',\n        'nextDay' => '[holnap] LT[-kor]',\n        'nextWeek' => function (CarbonInterface $date) use ($huWeekEndings) {\n            return '['.$huWeekEndings[$date->dayOfWeek].'] LT[-kor]';\n        },\n        'lastDay' => '[tegnap] LT[-kor]',\n        'lastWeek' => function (CarbonInterface $date) use ($huWeekEndings) {\n            return '[múlt '.$huWeekEndings[$date->dayOfWeek].'] LT[-kor]';\n        },\n        'sameElse' => 'L',\n    ],\n    'meridiem' => ['DE', 'DU'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n    'list' => [', ', ' és '],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/hu_HU.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/hu.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/hy.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - mhamlet\n */\nreturn [\n    'year' => ':count տարի',\n    'a_year' => 'տարի|:count տարի',\n    'y' => ':countտ',\n    'month' => ':count ամիս',\n    'a_month' => 'ամիս|:count ամիս',\n    'm' => ':countամ',\n    'week' => ':count շաբաթ',\n    'a_week' => 'շաբաթ|:count շաբաթ',\n    'w' => ':countշ',\n    'day' => ':count օր',\n    'a_day' => 'օր|:count օր',\n    'd' => ':countօր',\n    'hour' => ':count ժամ',\n    'a_hour' => 'ժամ|:count ժամ',\n    'h' => ':countժ',\n    'minute' => ':count րոպե',\n    'a_minute' => 'րոպե|:count րոպե',\n    'min' => ':countր',\n    'second' => ':count վայրկյան',\n    'a_second' => 'մի քանի վայրկյան|:count վայրկյան',\n    's' => ':countվրկ',\n    'ago' => ':time առաջ',\n    'from_now' => ':timeից',\n    'after' => ':time հետո',\n    'before' => ':time առաջ',\n    'diff_now' => 'հիմա',\n    'diff_today' => 'այսօր',\n    'diff_yesterday' => 'երեկ',\n    'diff_tomorrow' => 'վաղը',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD.MM.YYYY',\n        'LL' => 'D MMMM YYYY թ.',\n        'LLL' => 'D MMMM YYYY թ., HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY թ., HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[այսօր] LT',\n        'nextDay' => '[վաղը] LT',\n        'nextWeek' => 'dddd [օրը ժամը] LT',\n        'lastDay' => '[երեկ] LT',\n        'lastWeek' => '[անցած] dddd [օրը ժամը] LT',\n        'sameElse' => 'L',\n    ],\n    'ordinal' => function ($number, $period) {\n        switch ($period) {\n            case 'DDD':\n            case 'w':\n            case 'W':\n            case 'DDDo':\n                return $number.($number === 1 ? '-ին' : '-րդ');\n            default:\n                return $number;\n        }\n    },\n    'meridiem' => function ($hour) {\n        if ($hour < 4) {\n            return 'գիշերվա';\n        }\n        if ($hour < 12) {\n            return 'առավոտվա';\n        }\n        if ($hour < 17) {\n            return 'ցերեկվա';\n        }\n\n        return 'երեկոյան';\n    },\n    'months' => ['հունվարի', 'փետրվարի', 'մարտի', 'ապրիլի', 'մայիսի', 'հունիսի', 'հուլիսի', 'օգոստոսի', 'սեպտեմբերի', 'հոկտեմբերի', 'նոյեմբերի', 'դեկտեմբերի'],\n    'months_standalone' => ['հունվար', 'փետրվար', 'մարտ', 'ապրիլ', 'մայիս', 'հունիս', 'հուլիս', 'օգոստոս', 'սեպտեմբեր', 'հոկտեմբեր', 'նոյեմբեր', 'դեկտեմբեր'],\n    'months_short' => ['հնվ', 'փտր', 'մրտ', 'ապր', 'մյս', 'հնս', 'հլս', 'օգս', 'սպտ', 'հկտ', 'նմբ', 'դկտ'],\n    'months_regexp' => '/(D[oD]?(\\[[^\\[\\]]*\\]|\\s)+MMMM?|L{2,4}|l{2,4})/',\n    'weekdays' => ['կիրակի', 'երկուշաբթի', 'երեքշաբթի', 'չորեքշաբթի', 'հինգշաբթի', 'ուրբաթ', 'շաբաթ'],\n    'weekdays_short' => ['կրկ', 'երկ', 'երք', 'չրք', 'հնգ', 'ուրբ', 'շբթ'],\n    'weekdays_min' => ['կրկ', 'երկ', 'երք', 'չրք', 'հնգ', 'ուրբ', 'շբթ'],\n    'list' => [', ', ' եւ '],\n    'first_day_of_week' => 1,\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/hy_AM.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Josh Soref\n * - François B\n * - Tim Fish\n * - Serhan Apaydın\n * - JD Isaacks\n */\nreturn array_replace_recursive(require __DIR__.'/hy.php', [\n    'from_now' => ':time հետո',\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/i18n.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'YYYY-MM-DD',\n    ],\n    'months' => ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'],\n    'months_short' => ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'],\n    'weekdays' => ['1', '2', '3', '4', '5', '6', '7'],\n    'weekdays_short' => ['1', '2', '3', '4', '5', '6', '7'],\n    'weekdays_min' => ['1', '2', '3', '4', '5', '6', '7'],\n    'first_day_of_week' => 0,\n    'day_of_first_week_of_year' => 4,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ia.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/ia_FR.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ia_FR.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Fedora Project Nik Kalach nikka@fedoraproject.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD.MM.YYYY',\n    ],\n    'months' => ['januario', 'februario', 'martio', 'april', 'maio', 'junio', 'julio', 'augusto', 'septembre', 'octobre', 'novembre', 'decembre'],\n    'months_short' => ['jan', 'feb', 'mar', 'apr', 'mai', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec'],\n    'weekdays' => ['dominica', 'lunedi', 'martedi', 'mercuridi', 'jovedi', 'venerdi', 'sabbato'],\n    'weekdays_short' => ['dom', 'lun', 'mar', 'mer', 'jov', 'ven', 'sab'],\n    'weekdays_min' => ['dom', 'lun', 'mar', 'mer', 'jov', 'ven', 'sab'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n\n    'year' => 'anno :count',\n    'y' => 'anno :count',\n    'a_year' => 'anno :count',\n\n    'month' => ':count mense',\n    'm' => ':count mense',\n    'a_month' => ':count mense',\n\n    'week' => ':count septimana',\n    'w' => ':count septimana',\n    'a_week' => ':count septimana',\n\n    'day' => ':count die',\n    'd' => ':count die',\n    'a_day' => ':count die',\n\n    'hour' => ':count hora',\n    'h' => ':count hora',\n    'a_hour' => ':count hora',\n\n    'minute' => ':count minuscule',\n    'min' => ':count minuscule',\n    'a_minute' => ':count minuscule',\n\n    'second' => ':count secunda',\n    's' => ':count secunda',\n    'a_second' => ':count secunda',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/id.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Josh Soref\n * - du\n * - JD Isaacks\n * - Nafies Luthfi\n * - Raymundus Jati Primanda (mundusjp)\n * - diankur313\n * - a-wip0\n */\nreturn [\n    'year' => ':count tahun',\n    'a_year' => '{1}setahun|]1,Inf[:count tahun',\n    'y' => ':countthn',\n    'month' => ':count bulan',\n    'a_month' => '{1}sebulan|]1,Inf[:count bulan',\n    'm' => ':countbln',\n    'week' => ':count minggu',\n    'a_week' => '{1}seminggu|]1,Inf[:count minggu',\n    'w' => ':countmgg',\n    'day' => ':count hari',\n    'a_day' => '{1}sehari|]1,Inf[:count hari',\n    'd' => ':counthr',\n    'hour' => ':count jam',\n    'a_hour' => '{1}sejam|]1,Inf[:count jam',\n    'h' => ':countj',\n    'minute' => ':count menit',\n    'a_minute' => '{1}semenit|]1,Inf[:count menit',\n    'min' => ':countmnt',\n    'second' => ':count detik',\n    'a_second' => '{1}beberapa detik|]1,Inf[:count detik',\n    's' => ':countdt',\n    'ago' => ':time yang lalu',\n    'from_now' => ':time dari sekarang',\n    'after' => ':time setelahnya',\n    'before' => ':time sebelumnya',\n    'diff_now' => 'sekarang',\n    'diff_today' => 'Hari',\n    'diff_today_regexp' => 'Hari(?:\\\\s+ini)?(?:\\\\s+pukul)?',\n    'diff_yesterday' => 'kemarin',\n    'diff_yesterday_regexp' => 'Kemarin(?:\\\\s+pukul)?',\n    'diff_tomorrow' => 'besok',\n    'diff_tomorrow_regexp' => 'Besok(?:\\\\s+pukul)?',\n    'formats' => [\n        'LT' => 'HH.mm',\n        'LTS' => 'HH.mm.ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY [pukul] HH.mm',\n        'LLLL' => 'dddd, D MMMM YYYY [pukul] HH.mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[Hari ini pukul] LT',\n        'nextDay' => '[Besok pukul] LT',\n        'nextWeek' => 'dddd [pukul] LT',\n        'lastDay' => '[Kemarin pukul] LT',\n        'lastWeek' => 'dddd [lalu pukul] LT',\n        'sameElse' => 'L',\n    ],\n    'meridiem' => function ($hour) {\n        if ($hour < 11) {\n            return 'pagi';\n        }\n        if ($hour < 15) {\n            return 'siang';\n        }\n        if ($hour < 19) {\n            return 'sore';\n        }\n\n        return 'malam';\n    },\n    'months' => ['Januari', 'Februari', 'Maret', 'April', 'Mei', 'Juni', 'Juli', 'Agustus', 'September', 'Oktober', 'November', 'Desember'],\n    'months_short' => ['Jan', 'Feb', 'Mar', 'Apr', 'Mei', 'Jun', 'Jul', 'Agt', 'Sep', 'Okt', 'Nov', 'Des'],\n    'weekdays' => ['Minggu', 'Senin', 'Selasa', 'Rabu', 'Kamis', 'Jumat', 'Sabtu'],\n    'weekdays_short' => ['Min', 'Sen', 'Sel', 'Rab', 'Kam', 'Jum', 'Sab'],\n    'weekdays_min' => ['Mg', 'Sn', 'Sl', 'Rb', 'Km', 'Jm', 'Sb'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n    'list' => [', ', ' dan '],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/id_ID.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/id.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ig.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/ig_NG.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ig_NG.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - pablo@mandriva.com\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD/MM/YY',\n    ],\n    'months' => ['Jenụwarị', 'Febrụwarị', 'Maachị', 'Eprel', 'Mee', 'Juun', 'Julaị', 'Ọgọọst', 'Septemba', 'Ọktoba', 'Novemba', 'Disemba'],\n    'months_short' => ['Jen', 'Feb', 'Maa', 'Epr', 'Mee', 'Juu', 'Jul', 'Ọgọ', 'Sep', 'Ọkt', 'Nov', 'Dis'],\n    'weekdays' => ['sọnde', 'mọnde', 'tuzde', 'wenzde', 'tọsde', 'fraịde', 'satọde'],\n    'weekdays_short' => ['sọn', 'mọn', 'tuz', 'wen', 'tọs', 'fra', 'sat'],\n    'weekdays_min' => ['sọn', 'mọn', 'tuz', 'wen', 'tọs', 'fra', 'sat'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n\n    'year' => 'afo :count',\n    'y' => 'afo :count',\n    'a_year' => 'afo :count',\n\n    'month' => 'önwa :count',\n    'm' => 'önwa :count',\n    'a_month' => 'önwa :count',\n\n    'week' => 'izu :count',\n    'w' => 'izu :count',\n    'a_week' => 'izu :count',\n\n    'day' => 'ụbọchị :count',\n    'd' => 'ụbọchị :count',\n    'a_day' => 'ụbọchị :count',\n\n    'hour' => 'awa :count',\n    'h' => 'awa :count',\n    'a_hour' => 'awa :count',\n\n    'minute' => 'minit :count',\n    'min' => 'minit :count',\n    'a_minute' => 'minit :count',\n\n    'second' => 'sekọnd :count',\n    's' => 'sekọnd :count',\n    'a_second' => 'sekọnd :count',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ii.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'meridiem' => ['ꎸꄑ', 'ꁯꋒ'],\n    'weekdays' => ['ꑭꆏꑍ', 'ꆏꊂꋍ', 'ꆏꊂꑍ', 'ꆏꊂꌕ', 'ꆏꊂꇖ', 'ꆏꊂꉬ', 'ꆏꊂꃘ'],\n    'weekdays_short' => ['ꑭꆏ', 'ꆏꋍ', 'ꆏꑍ', 'ꆏꌕ', 'ꆏꇖ', 'ꆏꉬ', 'ꆏꃘ'],\n    'weekdays_min' => ['ꑭꆏ', 'ꆏꋍ', 'ꆏꑍ', 'ꆏꌕ', 'ꆏꇖ', 'ꆏꉬ', 'ꆏꃘ'],\n    'months' => null,\n    'months_short' => ['ꋍꆪ', 'ꑍꆪ', 'ꌕꆪ', 'ꇖꆪ', 'ꉬꆪ', 'ꃘꆪ', 'ꏃꆪ', 'ꉆꆪ', 'ꈬꆪ', 'ꊰꆪ', 'ꊰꊪꆪ', 'ꊰꑋꆪ'],\n    'formats' => [\n        'LT' => 'h:mm a',\n        'LTS' => 'h:mm:ss a',\n        'L' => 'YYYY-MM-dd',\n        'LL' => 'YYYY MMM D',\n        'LLL' => 'YYYY MMMM D h:mm a',\n        'LLLL' => 'YYYY MMMM D, dddd h:mm a',\n    ],\n\n    'year' => ':count ꒉ', // less reliable\n    'y' => ':count ꒉ', // less reliable\n    'a_year' => ':count ꒉ', // less reliable\n\n    'month' => ':count ꆪ',\n    'm' => ':count ꆪ',\n    'a_month' => ':count ꆪ',\n\n    'week' => ':count ꏃ', // less reliable\n    'w' => ':count ꏃ', // less reliable\n    'a_week' => ':count ꏃ', // less reliable\n\n    'day' => ':count ꏜ', // less reliable\n    'd' => ':count ꏜ', // less reliable\n    'a_day' => ':count ꏜ', // less reliable\n\n    'hour' => ':count ꄮꈉ',\n    'h' => ':count ꄮꈉ',\n    'a_hour' => ':count ꄮꈉ',\n\n    'minute' => ':count ꀄꊭ', // less reliable\n    'min' => ':count ꀄꊭ', // less reliable\n    'a_minute' => ':count ꀄꊭ', // less reliable\n\n    'second' => ':count ꇅ', // less reliable\n    's' => ':count ꇅ', // less reliable\n    'a_second' => ':count ꇅ', // less reliable\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ik.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/ik_CA.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ik_CA.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - pablo@mandriva.com\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD/MM/YY',\n    ],\n    'months' => ['Siqiññaatchiaq', 'Siqiññaasrugruk', 'Paniqsiqsiivik', 'Qilġich Tatqiat', 'Suppivik', 'Iġñivik', 'Itchavik', 'Tiññivik', 'Amiġaiqsivik', 'Sikkuvik', 'Nippivik', 'Siqiñġiḷaq'],\n    'months_short' => ['Sñt', 'Sñs', 'Pan', 'Qil', 'Sup', 'Iġñ', 'Itc', 'Tiñ', 'Ami', 'Sik', 'Nip', 'Siq'],\n    'weekdays' => ['Minġuiqsioiq', 'Savałłiq', 'Ilaqtchiioiq', 'Qitchiioiq', 'Sisamiioiq', 'Tallimmiioiq', 'Maqinġuoiq'],\n    'weekdays_short' => ['Min', 'Sav', 'Ila', 'Qit', 'Sis', 'Tal', 'Maq'],\n    'weekdays_min' => ['Min', 'Sav', 'Ila', 'Qit', 'Sis', 'Tal', 'Maq'],\n    'day_of_first_week_of_year' => 1,\n\n    'year' => ':count ukiuq',\n    'y' => ':count ukiuq',\n    'a_year' => ':count ukiuq',\n\n    'month' => ':count Tatqiat',\n    'm' => ':count Tatqiat',\n    'a_month' => ':count Tatqiat',\n\n    'week' => ':count tatqiat', // less reliable\n    'w' => ':count tatqiat', // less reliable\n    'a_week' => ':count tatqiat', // less reliable\n\n    'day' => ':count siqiñiq', // less reliable\n    'd' => ':count siqiñiq', // less reliable\n    'a_day' => ':count siqiñiq', // less reliable\n\n    'hour' => ':count Siḷa', // less reliable\n    'h' => ':count Siḷa', // less reliable\n    'a_hour' => ':count Siḷa', // less reliable\n\n    'second' => ':count iġñiq', // less reliable\n    's' => ':count iġñiq', // less reliable\n    'a_second' => ':count iġñiq', // less reliable\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/in.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/id.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/is.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Kristján Ingi Geirsson\n */\nreturn [\n    'year' => '1 ár|:count ár',\n    'y' => '1 ár|:count ár',\n    'month' => '1 mánuður|:count mánuðir',\n    'm' => '1 mánuður|:count mánuðir',\n    'week' => '1 vika|:count vikur',\n    'w' => '1 vika|:count vikur',\n    'day' => '1 dagur|:count dagar',\n    'd' => '1 dagur|:count dagar',\n    'hour' => '1 klukkutími|:count klukkutímar',\n    'h' => '1 klukkutími|:count klukkutímar',\n    'minute' => '1 mínúta|:count mínútur',\n    'min' => '1 mínúta|:count mínútur',\n    'second' => '1 sekúnda|:count sekúndur',\n    's' => '1 sekúnda|:count sekúndur',\n    'ago' => ':time síðan',\n    'from_now' => ':time síðan',\n    'after' => ':time eftir',\n    'before' => ':time fyrir',\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n    'list' => [', ', ' og '],\n    'meridiem' => ['fh', 'eh'],\n    'diff_now' => 'núna',\n    'diff_yesterday' => 'í gær',\n    'diff_tomorrow' => 'á morgun',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD.MM.YYYY',\n        'LL' => 'D. MMMM YYYY',\n        'LLL' => 'D. MMMM [kl.] HH:mm',\n        'LLLL' => 'dddd D. MMMM YYYY [kl.] HH:mm',\n    ],\n    'weekdays' => ['sunnudaginn', 'mánudaginn', 'þriðjudaginn', 'miðvikudaginn', 'fimmtudaginn', 'föstudaginn', 'laugardaginn'],\n    'weekdays_short' => ['sun', 'mán', 'þri', 'mið', 'fim', 'fös', 'lau'],\n    'weekdays_min' => ['sun', 'mán', 'þri', 'mið', 'fim', 'fös', 'lau'],\n    'months' => ['janúar', 'febrúar', 'mars', 'apríl', 'maí', 'júní', 'júlí', 'ágúst', 'september', 'október', 'nóvember', 'desember'],\n    'months_short' => ['jan', 'feb', 'mar', 'apr', 'maí', 'jún', 'júl', 'ágú', 'sep', 'okt', 'nóv', 'des'],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/is_IS.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/is.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/it.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Ash\n * - François B\n * - Marco Perrando\n * - Massimiliano Caniparoli\n * - JD Isaacks\n * - Andrea Martini\n * - Francesco Marasco\n * - Tizianoz93\n * - Davide Casiraghi (davide-casiraghi)\n * - Pete Scopes (pdscopes)\n */\n\nuse Carbon\\CarbonInterface;\n\nreturn [\n    'year' => ':count anno|:count anni',\n    'a_year' => 'un anno|:count anni',\n    'y' => ':count anno|:count anni',\n    'month' => ':count mese|:count mesi',\n    'a_month' => 'un mese|:count mesi',\n    'm' => ':count mese|:count mesi',\n    'week' => ':count settimana|:count settimane',\n    'a_week' => 'una settimana|:count settimane',\n    'w' => ':count set.',\n    'day' => ':count giorno|:count giorni',\n    'a_day' => 'un giorno|:count giorni',\n    'd' => ':count g|:count gg',\n    'hour' => ':count ora|:count ore',\n    'a_hour' => 'un\\'ora|:count ore',\n    'h' => ':count h',\n    'minute' => ':count minuto|:count minuti',\n    'a_minute' => 'un minuto|:count minuti',\n    'min' => ':count min.',\n    'second' => ':count secondo|:count secondi',\n    'a_second' => 'alcuni secondi|:count secondi',\n    's' => ':count sec.',\n    'millisecond' => ':count millisecondo|:count millisecondi',\n    'a_millisecond' => 'un millisecondo|:count millisecondi',\n    'ms' => ':countms',\n    'microsecond' => ':count microsecondo|:count microsecondi',\n    'a_microsecond' => 'un microsecondo|:count microsecondi',\n    'µs' => ':countµs',\n    'ago' => ':time fa',\n    'from_now' => function ($time) {\n        return (preg_match('/^\\d.+$/', $time) ? 'tra' : 'in').\" $time\";\n    },\n    'after' => ':time dopo',\n    'before' => ':time prima',\n    'diff_now' => 'proprio ora',\n    'diff_today' => 'Oggi',\n    'diff_today_regexp' => 'Oggi(?:\\\\s+alle)?',\n    'diff_yesterday' => 'ieri',\n    'diff_yesterday_regexp' => 'Ieri(?:\\\\s+alle)?',\n    'diff_tomorrow' => 'domani',\n    'diff_tomorrow_regexp' => 'Domani(?:\\\\s+alle)?',\n    'diff_before_yesterday' => 'l\\'altro ieri',\n    'diff_after_tomorrow' => 'dopodomani',\n    'period_interval' => 'ogni :interval',\n    'period_start_date' => 'dal :date',\n    'period_end_date' => 'al :date',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd D MMMM YYYY HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[Oggi alle] LT',\n        'nextDay' => '[Domani alle] LT',\n        'nextWeek' => 'dddd [alle] LT',\n        'lastDay' => '[Ieri alle] LT',\n        'lastWeek' => function (CarbonInterface $date) {\n            switch ($date->dayOfWeek) {\n                case 0:\n                    return '[la scorsa] dddd [alle] LT';\n                default:\n                    return '[lo scorso] dddd [alle] LT';\n            }\n        },\n        'sameElse' => 'L',\n    ],\n    'ordinal' => ':numberº',\n    'months' => ['gennaio', 'febbraio', 'marzo', 'aprile', 'maggio', 'giugno', 'luglio', 'agosto', 'settembre', 'ottobre', 'novembre', 'dicembre'],\n    'months_short' => ['gen', 'feb', 'mar', 'apr', 'mag', 'giu', 'lug', 'ago', 'set', 'ott', 'nov', 'dic'],\n    'weekdays' => ['domenica', 'lunedì', 'martedì', 'mercoledì', 'giovedì', 'venerdì', 'sabato'],\n    'weekdays_short' => ['dom', 'lun', 'mar', 'mer', 'gio', 'ven', 'sab'],\n    'weekdays_min' => ['do', 'lu', 'ma', 'me', 'gi', 've', 'sa'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n    'list' => [', ', ' e '],\n    'ordinal_words' => [\n        'of' => 'di',\n        'first' => 'primo',\n        'second' => 'secondo',\n        'third' => 'terzo',\n        'fourth' => 'quarto',\n        'fifth' => 'quinto',\n        'last' => 'ultimo',\n    ],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/it_CH.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Propaganistas\n */\nreturn array_replace_recursive(require __DIR__.'/it.php', [\n    'formats' => [\n        'L' => 'DD.MM.YYYY',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/it_IT.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - RAP    bug-glibc-locales@gnu.org\n */\nreturn require __DIR__.'/it.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/it_SM.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/it.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/it_VA.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/it.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/iu.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/iu_CA.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/iu_CA.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Pablo Saratxaga pablo@mandriva.com\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'MM/DD/YY',\n    ],\n    'months' => ['ᔮᓄᐊᓕ', 'ᕕᕗᐊᓕ', 'ᒪᔅᓯ', 'ᐃᐳᓗ', 'ᒪᐃ', 'ᔪᓂ', 'ᔪᓚᐃ', 'ᐊᒋᓯ', 'ᓯᑎᕙ', 'ᐊᑦᑐᕙ', 'ᓄᕕᕙ', 'ᑎᓯᕝᕙ'],\n    'months_short' => ['ᔮᓄ', 'ᕕᕗ', 'ᒪᔅ', 'ᐃᐳ', 'ᒪᐃ', 'ᔪᓂ', 'ᔪᓚ', 'ᐊᒋ', 'ᓯᑎ', 'ᐊᑦ', 'ᓄᕕ', 'ᑎᓯ'],\n    'weekdays' => ['ᓈᑦᑎᖑᔭᕐᕕᒃ', 'ᓇᒡᒐᔾᔭᐅ', 'ᓇᒡᒐᔾᔭᐅᓕᖅᑭᑦ', 'ᐱᖓᓲᓕᖅᓯᐅᑦ', 'ᕿᑎᖅᑰᑦ', 'ᐅᓪᓗᕈᓘᑐᐃᓇᖅ', 'ᓯᕙᑖᕕᒃ'],\n    'weekdays_short' => ['ᓈ', 'ᓇ', 'ᓕ', 'ᐱ', 'ᕿ', 'ᐅ', 'ᓯ'],\n    'weekdays_min' => ['ᓈ', 'ᓇ', 'ᓕ', 'ᐱ', 'ᕿ', 'ᐅ', 'ᓯ'],\n    'day_of_first_week_of_year' => 1,\n\n    'year' => ':count ᐅᑭᐅᖅ',\n    'y' => ':count ᐅᑭᐅᖅ',\n    'a_year' => ':count ᐅᑭᐅᖅ',\n\n    'month' => ':count qaammat',\n    'm' => ':count qaammat',\n    'a_month' => ':count qaammat',\n\n    'week' => ':count sapaatip akunnera',\n    'w' => ':count sapaatip akunnera',\n    'a_week' => ':count sapaatip akunnera',\n\n    'day' => ':count ulloq',\n    'd' => ':count ulloq',\n    'a_day' => ':count ulloq',\n\n    'hour' => ':count ikarraq',\n    'h' => ':count ikarraq',\n    'a_hour' => ':count ikarraq',\n\n    'minute' => ':count titiqqaralaaq', // less reliable\n    'min' => ':count titiqqaralaaq', // less reliable\n    'a_minute' => ':count titiqqaralaaq', // less reliable\n\n    'second' => ':count marluk', // less reliable\n    's' => ':count marluk', // less reliable\n    'a_second' => ':count marluk', // less reliable\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/iw.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'months' => ['ינואר', 'פברואר', 'מרץ', 'אפריל', 'מאי', 'יוני', 'יולי', 'אוגוסט', 'ספטמבר', 'אוקטובר', 'נובמבר', 'דצמבר'],\n    'months_short' => ['ינו׳', 'פבר׳', 'מרץ', 'אפר׳', 'מאי', 'יוני', 'יולי', 'אוג׳', 'ספט׳', 'אוק׳', 'נוב׳', 'דצמ׳'],\n    'weekdays' => ['יום ראשון', 'יום שני', 'יום שלישי', 'יום רביעי', 'יום חמישי', 'יום שישי', 'יום שבת'],\n    'weekdays_short' => ['יום א׳', 'יום ב׳', 'יום ג׳', 'יום ד׳', 'יום ה׳', 'יום ו׳', 'שבת'],\n    'weekdays_min' => ['א׳', 'ב׳', 'ג׳', 'ד׳', 'ה׳', 'ו׳', 'ש׳'],\n    'meridiem' => ['לפנה״צ', 'אחה״צ'],\n    'formats' => [\n        'LT' => 'H:mm',\n        'LTS' => 'H:mm:ss',\n        'L' => 'D.M.YYYY',\n        'LL' => 'D בMMM YYYY',\n        'LLL' => 'D בMMMM YYYY H:mm',\n        'LLLL' => 'dddd, D בMMMM YYYY H:mm',\n    ],\n\n    'year' => ':count שנה',\n    'y' => ':count שנה',\n    'a_year' => ':count שנה',\n\n    'month' => ':count חודש',\n    'm' => ':count חודש',\n    'a_month' => ':count חודש',\n\n    'week' => ':count שבוע',\n    'w' => ':count שבוע',\n    'a_week' => ':count שבוע',\n\n    'day' => ':count יום',\n    'd' => ':count יום',\n    'a_day' => ':count יום',\n\n    'hour' => ':count שעה',\n    'h' => ':count שעה',\n    'a_hour' => ':count שעה',\n\n    'minute' => ':count דקה',\n    'min' => ':count דקה',\n    'a_minute' => ':count דקה',\n\n    'second' => ':count שניה',\n    's' => ':count שניה',\n    'a_second' => ':count שניה',\n\n    'ago' => 'לפני :time',\n    'from_now' => 'בעוד :time',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ja.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Takuya Sawada\n * - Atsushi Tanaka\n * - François B\n * - Jason Katz-Brown\n * - Serhan Apaydın\n * - XueWei\n * - JD Isaacks\n * - toyama satoshi\n * - atakigawa\n */\n\nuse Carbon\\CarbonInterface;\n\nreturn [\n    'year' => ':count年',\n    'y' => ':count年',\n    'month' => ':countヶ月',\n    'm' => ':countヶ月',\n    'week' => ':count週間',\n    'w' => ':count週間',\n    'day' => ':count日',\n    'd' => ':count日',\n    'hour' => ':count時間',\n    'h' => ':count時間',\n    'minute' => ':count分',\n    'min' => ':count分',\n    'second' => ':count秒',\n    'a_second' => '{1}数秒|]1,Inf[:count秒',\n    's' => ':count秒',\n    'ago' => ':time前',\n    'from_now' => ':time後',\n    'after' => ':time後',\n    'before' => ':time前',\n    'diff_now' => '今',\n    'diff_today' => '今日',\n    'diff_yesterday' => '昨日',\n    'diff_tomorrow' => '明日',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'YYYY/MM/DD',\n        'LL' => 'YYYY年M月D日',\n        'LLL' => 'YYYY年M月D日 HH:mm',\n        'LLLL' => 'YYYY年M月D日 dddd HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[今日] LT',\n        'nextDay' => '[明日] LT',\n        'nextWeek' => function (CarbonInterface $current, CarbonInterface $other) {\n            if ($other->week !== $current->week) {\n                return '[来週]dddd LT';\n            }\n\n            return 'dddd LT';\n        },\n        'lastDay' => '[昨日] LT',\n        'lastWeek' => function (CarbonInterface $current, CarbonInterface $other) {\n            if ($other->week !== $current->week) {\n                return '[先週]dddd LT';\n            }\n\n            return 'dddd LT';\n        },\n        'sameElse' => 'L',\n    ],\n    'ordinal' => function ($number, $period) {\n        switch ($period) {\n            case 'd':\n            case 'D':\n            case 'DDD':\n                return $number.'日';\n            default:\n                return $number;\n        }\n    },\n    'meridiem' => ['午前', '午後'],\n    'months' => ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],\n    'months_short' => ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],\n    'weekdays' => ['日曜日', '月曜日', '火曜日', '水曜日', '木曜日', '金曜日', '土曜日'],\n    'weekdays_short' => ['日', '月', '火', '水', '木', '金', '土'],\n    'weekdays_min' => ['日', '月', '火', '水', '木', '金', '土'],\n    'list' => '、',\n    'alt_numbers' => ['〇', '一', '二', '三', '四', '五', '六', '七', '八', '九', '十', '十一', '十二', '十三', '十四', '十五', '十六', '十七', '十八', '十九', '二十', '二十一', '二十二', '二十三', '二十四', '二十五', '二十六', '二十七', '二十八', '二十九', '三十', '三十一', '三十二', '三十三', '三十四', '三十五', '三十六', '三十七', '三十八', '三十九', '四十', '四十一', '四十二', '四十三', '四十四', '四十五', '四十六', '四十七', '四十八', '四十九', '五十', '五十一', '五十二', '五十三', '五十四', '五十五', '五十六', '五十七', '五十八', '五十九', '六十', '六十一', '六十二', '六十三', '六十四', '六十五', '六十六', '六十七', '六十八', '六十九', '七十', '七十一', '七十二', '七十三', '七十四', '七十五', '七十六', '七十七', '七十八', '七十九', '八十', '八十一', '八十二', '八十三', '八十四', '八十五', '八十六', '八十七', '八十八', '八十九', '九十', '九十一', '九十二', '九十三', '九十四', '九十五', '九十六', '九十七', '九十八', '九十九'],\n    'alt_numbers_pow' => [\n        10000 => '万',\n        1000 => '千',\n        100 => '百',\n    ],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ja_JP.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/ja.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/jgo.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/jmc.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'meridiem' => ['utuko', 'kyiukonyi'],\n    'weekdays' => ['Jumapilyi', 'Jumatatuu', 'Jumanne', 'Jumatanu', 'Alhamisi', 'Ijumaa', 'Jumamosi'],\n    'weekdays_short' => ['Jpi', 'Jtt', 'Jnn', 'Jtn', 'Alh', 'Iju', 'Jmo'],\n    'weekdays_min' => ['Jpi', 'Jtt', 'Jnn', 'Jtn', 'Alh', 'Iju', 'Jmo'],\n    'months' => ['Januari', 'Februari', 'Machi', 'Aprilyi', 'Mei', 'Junyi', 'Julyai', 'Agusti', 'Septemba', 'Oktoba', 'Novemba', 'Desemba'],\n    'months_short' => ['Jan', 'Feb', 'Mac', 'Apr', 'Mei', 'Jun', 'Jul', 'Ago', 'Sep', 'Okt', 'Nov', 'Des'],\n    'first_day_of_week' => 1,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY HH:mm',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/jv.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Josh Soref\n * - tgfjt\n * - JD Isaacks\n */\nreturn [\n    'year' => '{1}setaun|]1,Inf[:count taun',\n    'month' => '{1}sewulan|]1,Inf[:count wulan',\n    'week' => '{1}sakminggu|]1,Inf[:count minggu',\n    'day' => '{1}sedinten|]1,Inf[:count dinten',\n    'hour' => '{1}setunggal jam|]1,Inf[:count jam',\n    'minute' => '{1}setunggal menit|]1,Inf[:count menit',\n    'second' => '{1}sawetawis detik|]1,Inf[:count detik',\n    'ago' => ':time ingkang kepengker',\n    'from_now' => 'wonten ing :time',\n    'diff_today' => 'Dinten',\n    'diff_yesterday' => 'Kala',\n    'diff_yesterday_regexp' => 'Kala(?:\\\\s+wingi)?(?:\\\\s+pukul)?',\n    'diff_tomorrow' => 'Mbenjang',\n    'diff_tomorrow_regexp' => 'Mbenjang(?:\\\\s+pukul)?',\n    'diff_today_regexp' => 'Dinten(?:\\\\s+puniko)?(?:\\\\s+pukul)?',\n    'formats' => [\n        'LT' => 'HH.mm',\n        'LTS' => 'HH.mm.ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY [pukul] HH.mm',\n        'LLLL' => 'dddd, D MMMM YYYY [pukul] HH.mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[Dinten puniko pukul] LT',\n        'nextDay' => '[Mbenjang pukul] LT',\n        'nextWeek' => 'dddd [pukul] LT',\n        'lastDay' => '[Kala wingi pukul] LT',\n        'lastWeek' => 'dddd [kepengker pukul] LT',\n        'sameElse' => 'L',\n    ],\n    'meridiem' => function ($hour) {\n        if ($hour < 11) {\n            return 'enjing';\n        }\n        if ($hour < 15) {\n            return 'siyang';\n        }\n        if ($hour < 19) {\n            return 'sonten';\n        }\n\n        return 'ndalu';\n    },\n    'months' => ['Januari', 'Februari', 'Maret', 'April', 'Mei', 'Juni', 'Juli', 'Agustus', 'September', 'Oktober', 'Nopember', 'Desember'],\n    'months_short' => ['Jan', 'Feb', 'Mar', 'Apr', 'Mei', 'Jun', 'Jul', 'Ags', 'Sep', 'Okt', 'Nop', 'Des'],\n    'weekdays' => ['Minggu', 'Senen', 'Seloso', 'Rebu', 'Kemis', 'Jemuwah', 'Septu'],\n    'weekdays_short' => ['Min', 'Sen', 'Sel', 'Reb', 'Kem', 'Jem', 'Sep'],\n    'weekdays_min' => ['Mg', 'Sn', 'Sl', 'Rb', 'Km', 'Jm', 'Sp'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n    'list' => [', ', ' lan '],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ka.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Tornike Razmadze\n * - François B\n * - Lasha Dolidze\n * - Tim Fish\n * - JD Isaacks\n * - Tornike Razmadze\n * - François B\n * - Lasha Dolidze\n * - JD Isaacks\n * - LONGMAN\n * - Avtandil Kikabidze (akalongman)\n * - Levan Velijanashvili (Stichoza)\n */\n\nuse Carbon\\CarbonInterface;\n\nreturn [\n    'year' => ':count წელი',\n    'y' => ':count წელი',\n    'a_year' => '{1}წელი|]1,Inf[:count წელი',\n    'month' => ':count თვე',\n    'm' => ':count თვე',\n    'a_month' => '{1}თვე|]1,Inf[:count თვე',\n    'week' => ':count კვირა',\n    'w' => ':count კვირა',\n    'a_week' => '{1}კვირა|]1,Inf[:count კვირა',\n    'day' => ':count დღე',\n    'd' => ':count დღე',\n    'a_day' => '{1}დღე|]1,Inf[:count დღე',\n    'hour' => ':count საათი',\n    'h' => ':count საათი',\n    'a_hour' => '{1}საათი|]1,Inf[:count საათი',\n    'minute' => ':count წუთი',\n    'min' => ':count წუთი',\n    'a_minute' => '{1}წუთი|]1,Inf[:count წუთი',\n    'second' => ':count წამი',\n    's' => ':count წამი',\n    'a_second' => '{1}რამდენიმე წამი|]1,Inf[:count წამი',\n    'ago' => function ($time) {\n        $replacements = [\n            // year\n            'წელი' => 'წლის',\n            // month\n            'თვე' => 'თვის',\n            // week\n            'კვირა' => 'კვირის',\n            // day\n            'დღე' => 'დღის',\n            // hour\n            'საათი' => 'საათის',\n            // minute\n            'წუთი' => 'წუთის',\n            // second\n            'წამი' => 'წამის',\n        ];\n        $time = strtr($time, array_flip($replacements));\n        $time = strtr($time, $replacements);\n\n        return \"$time წინ\";\n    },\n    'from_now' => function ($time) {\n        $replacements = [\n            // year\n            'წელი' => 'წელიწადში',\n            // week\n            'კვირა' => 'კვირაში',\n            // day\n            'დღე' => 'დღეში',\n            // month\n            'თვე' => 'თვეში',\n            // hour\n            'საათი' => 'საათში',\n            // minute\n            'წუთი' => 'წუთში',\n            // second\n            'წამი' => 'წამში',\n        ];\n        $time = strtr($time, array_flip($replacements));\n        $time = strtr($time, $replacements);\n\n        return $time;\n    },\n    'after' => function ($time) {\n        $replacements = [\n            // year\n            'წელი' => 'წლის',\n            // month\n            'თვე' => 'თვის',\n            // week\n            'კვირა' => 'კვირის',\n            // day\n            'დღე' => 'დღის',\n            // hour\n            'საათი' => 'საათის',\n            // minute\n            'წუთი' => 'წუთის',\n            // second\n            'წამი' => 'წამის',\n        ];\n        $time = strtr($time, array_flip($replacements));\n        $time = strtr($time, $replacements);\n\n        return \"$time შემდეგ\";\n    },\n    'before' => function ($time) {\n        $replacements = [\n            // year\n            'წელი' => 'წლით',\n            // month\n            'თვე' => 'თვით',\n            // week\n            'კვირა' => 'კვირით',\n            // day\n            'დღე' => 'დღით',\n            // hour\n            'საათი' => 'საათით',\n            // minute\n            'წუთი' => 'წუთით',\n            // second\n            'წამი' => 'წამით',\n        ];\n        $time = strtr($time, array_flip($replacements));\n        $time = strtr($time, $replacements);\n\n        return \"$time ადრე\";\n    },\n    'diff_now' => 'ახლა',\n    'diff_today' => 'დღეს',\n    'diff_yesterday' => 'გუშინ',\n    'diff_tomorrow' => 'ხვალ',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[დღეს], LT[-ზე]',\n        'nextDay' => '[ხვალ], LT[-ზე]',\n        'nextWeek' => function (CarbonInterface $current, CarbonInterface $other) {\n            return ($current->isSameWeek($other) ? '' : '[შემდეგ] ').'dddd, LT[-ზე]';\n        },\n        'lastDay' => '[გუშინ], LT[-ზე]',\n        'lastWeek' => '[წინა] dddd, LT-ზე',\n        'sameElse' => 'L',\n    ],\n    'ordinal' => function ($number) {\n        if ($number === 0) {\n            return $number;\n        }\n        if ($number === 1) {\n            return $number.'-ლი';\n        }\n        if (($number < 20) || ($number <= 100 && ($number % 20 === 0)) || ($number % 100 === 0)) {\n            return 'მე-'.$number;\n        }\n\n        return $number.'-ე';\n    },\n    'months' => ['იანვარი', 'თებერვალი', 'მარტი', 'აპრილი', 'მაისი', 'ივნისი', 'ივლისი', 'აგვისტო', 'სექტემბერი', 'ოქტომბერი', 'ნოემბერი', 'დეკემბერი'],\n    'months_standalone' => ['იანვარს', 'თებერვალს', 'მარტს', 'აპრილს', 'მაისს', 'ივნისს', 'ივლისს', 'აგვისტოს', 'სექტემბერს', 'ოქტომბერს', 'ნოემბერს', 'დეკემბერს'],\n    'months_short' => ['იან', 'თებ', 'მარ', 'აპრ', 'მაი', 'ივნ', 'ივლ', 'აგვ', 'სექ', 'ოქტ', 'ნოე', 'დეკ'],\n    'months_regexp' => '/(D[oD]?(\\[[^\\[\\]]*\\]|\\s)+MMMM?|L{2,4}|l{2,4})/',\n    'weekdays' => ['კვირას', 'ორშაბათს', 'სამშაბათს', 'ოთხშაბათს', 'ხუთშაბათს', 'პარასკევს', 'შაბათს'],\n    'weekdays_standalone' => ['კვირა', 'ორშაბათი', 'სამშაბათი', 'ოთხშაბათი', 'ხუთშაბათი', 'პარასკევი', 'შაბათი'],\n    'weekdays_short' => ['კვი', 'ორშ', 'სამ', 'ოთხ', 'ხუთ', 'პარ', 'შაბ'],\n    'weekdays_min' => ['კვ', 'ორ', 'სა', 'ოთ', 'ხუ', 'პა', 'შა'],\n    'weekdays_regexp' => '/^([^d].*|.*[^d])$/',\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n    'list' => [', ', ' და '],\n    'meridiem' => function ($hour) {\n        if ($hour >= 4) {\n            if ($hour < 11) {\n                return 'დილის';\n            }\n\n            if ($hour < 16) {\n                return 'შუადღის';\n            }\n\n            if ($hour < 22) {\n                return 'საღამოს';\n            }\n        }\n\n        return 'ღამის';\n    },\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ka_GE.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/ka.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/kab.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/kab_DZ.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/kab_DZ.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - belkacem77@gmail.com\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD/MM/YYYY',\n    ],\n    'months' => ['Yennayer', 'Fuṛar', 'Meɣres', 'Yebrir', 'Mayyu', 'Yunyu', 'Yulyu', 'ɣuct', 'Ctembeṛ', 'Tubeṛ', 'Wambeṛ', 'Dujembeṛ'],\n    'months_short' => ['Yen', 'Fur', 'Meɣ', 'Yeb', 'May', 'Yun', 'Yul', 'ɣuc', 'Cte', 'Tub', 'Wam', 'Duj'],\n    'weekdays' => ['Acer', 'Arim', 'Aram', 'Ahad', 'Amhad', 'Sem', 'Sed'],\n    'weekdays_short' => ['Ace', 'Ari', 'Ara', 'Aha', 'Amh', 'Sem', 'Sed'],\n    'weekdays_min' => ['Ace', 'Ari', 'Ara', 'Aha', 'Amh', 'Sem', 'Sed'],\n    'first_day_of_week' => 6,\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['FT', 'MD'],\n\n    'year' => ':count n yiseggasen',\n    'y' => ':count n yiseggasen',\n    'a_year' => ':count n yiseggasen',\n\n    'month' => ':count n wayyuren',\n    'm' => ':count n wayyuren',\n    'a_month' => ':count n wayyuren',\n\n    'week' => ':count n ledwaṛ', // less reliable\n    'w' => ':count n ledwaṛ', // less reliable\n    'a_week' => ':count n ledwaṛ', // less reliable\n\n    'day' => ':count n wussan',\n    'd' => ':count n wussan',\n    'a_day' => ':count n wussan',\n\n    'hour' => ':count n tsaɛtin',\n    'h' => ':count n tsaɛtin',\n    'a_hour' => ':count n tsaɛtin',\n\n    'minute' => ':count n tedqiqin',\n    'min' => ':count n tedqiqin',\n    'a_minute' => ':count n tedqiqin',\n\n    'second' => ':count tasdidt', // less reliable\n    's' => ':count tasdidt', // less reliable\n    'a_second' => ':count tasdidt', // less reliable\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/kam.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'meridiem' => ['Ĩyakwakya', 'Ĩyawĩoo'],\n    'weekdays' => ['Wa kyumwa', 'Wa kwambĩlĩlya', 'Wa kelĩ', 'Wa katatũ', 'Wa kana', 'Wa katano', 'Wa thanthatũ'],\n    'weekdays_short' => ['Wky', 'Wkw', 'Wkl', 'Wtũ', 'Wkn', 'Wtn', 'Wth'],\n    'weekdays_min' => ['Wky', 'Wkw', 'Wkl', 'Wtũ', 'Wkn', 'Wtn', 'Wth'],\n    'months' => ['Mwai wa mbee', 'Mwai wa kelĩ', 'Mwai wa katatũ', 'Mwai wa kana', 'Mwai wa katano', 'Mwai wa thanthatũ', 'Mwai wa muonza', 'Mwai wa nyaanya', 'Mwai wa kenda', 'Mwai wa ĩkumi', 'Mwai wa ĩkumi na ĩmwe', 'Mwai wa ĩkumi na ilĩ'],\n    'months_short' => ['Mbe', 'Kel', 'Ktũ', 'Kan', 'Ktn', 'Tha', 'Moo', 'Nya', 'Knd', 'Ĩku', 'Ĩkm', 'Ĩkl'],\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY HH:mm',\n    ],\n\n    // Too unreliable\n    /*\n    'year' => ':count mbua', // less reliable\n    'y' => ':count mbua', // less reliable\n    'a_year' => ':count mbua', // less reliable\n\n    'month' => ':count ndakitali', // less reliable\n    'm' => ':count ndakitali', // less reliable\n    'a_month' => ':count ndakitali', // less reliable\n\n    'day' => ':count wia', // less reliable\n    'd' => ':count wia', // less reliable\n    'a_day' => ':count wia', // less reliable\n\n    'hour' => ':count orasan', // less reliable\n    'h' => ':count orasan', // less reliable\n    'a_hour' => ':count orasan', // less reliable\n\n    'minute' => ':count orasan', // less reliable\n    'min' => ':count orasan', // less reliable\n    'a_minute' => ':count orasan', // less reliable\n    */\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/kde.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'meridiem' => ['Muhi', 'Chilo'],\n    'weekdays' => ['Liduva lyapili', 'Liduva lyatatu', 'Liduva lyanchechi', 'Liduva lyannyano', 'Liduva lyannyano na linji', 'Liduva lyannyano na mavili', 'Liduva litandi'],\n    'weekdays_short' => ['Ll2', 'Ll3', 'Ll4', 'Ll5', 'Ll6', 'Ll7', 'Ll1'],\n    'weekdays_min' => ['Ll2', 'Ll3', 'Ll4', 'Ll5', 'Ll6', 'Ll7', 'Ll1'],\n    'months' => ['Mwedi Ntandi', 'Mwedi wa Pili', 'Mwedi wa Tatu', 'Mwedi wa Nchechi', 'Mwedi wa Nnyano', 'Mwedi wa Nnyano na Umo', 'Mwedi wa Nnyano na Mivili', 'Mwedi wa Nnyano na Mitatu', 'Mwedi wa Nnyano na Nchechi', 'Mwedi wa Nnyano na Nnyano', 'Mwedi wa Nnyano na Nnyano na U', 'Mwedi wa Nnyano na Nnyano na M'],\n    'months_short' => ['Jan', 'Feb', 'Mac', 'Apr', 'Mei', 'Jun', 'Jul', 'Ago', 'Sep', 'Okt', 'Nov', 'Des'],\n    'first_day_of_week' => 1,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY HH:mm',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/kea.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'meridiem' => ['a', 'p'],\n    'weekdays' => ['dumingu', 'sigunda-fera', 'tersa-fera', 'kuarta-fera', 'kinta-fera', 'sesta-fera', 'sabadu'],\n    'weekdays_short' => ['dum', 'sig', 'ter', 'kua', 'kin', 'ses', 'sab'],\n    'weekdays_min' => ['du', 'si', 'te', 'ku', 'ki', 'se', 'sa'],\n    'weekdays_standalone' => ['dumingu', 'sigunda-fera', 'tersa-fera', 'kuarta-fera', 'kinta-fera', 'sesta-fera', 'sábadu'],\n    'months' => ['Janeru', 'Febreru', 'Marsu', 'Abril', 'Maiu', 'Junhu', 'Julhu', 'Agostu', 'Setenbru', 'Otubru', 'Nuvenbru', 'Dizenbru'],\n    'months_short' => ['Jan', 'Feb', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set', 'Otu', 'Nuv', 'Diz'],\n    'first_day_of_week' => 1,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'D/M/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D [di] MMMM [di] YYYY HH:mm',\n        'LLLL' => 'dddd, D [di] MMMM [di] YYYY HH:mm',\n    ],\n\n    'year' => ':count otunu', // less reliable\n    'y' => ':count otunu', // less reliable\n    'a_year' => ':count otunu', // less reliable\n\n    'week' => ':count día dumingu', // less reliable\n    'w' => ':count día dumingu', // less reliable\n    'a_week' => ':count día dumingu', // less reliable\n\n    'day' => ':count diâ', // less reliable\n    'd' => ':count diâ', // less reliable\n    'a_day' => ':count diâ', // less reliable\n\n    'minute' => ':count sugundu', // less reliable\n    'min' => ':count sugundu', // less reliable\n    'a_minute' => ':count sugundu', // less reliable\n\n    'second' => ':count dós', // less reliable\n    's' => ':count dós', // less reliable\n    'a_second' => ':count dós', // less reliable\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/khq.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'meridiem' => ['Adduha', 'Aluula'],\n    'weekdays' => ['Alhadi', 'Atini', 'Atalata', 'Alarba', 'Alhamiisa', 'Aljuma', 'Assabdu'],\n    'weekdays_short' => ['Alh', 'Ati', 'Ata', 'Ala', 'Alm', 'Alj', 'Ass'],\n    'weekdays_min' => ['Alh', 'Ati', 'Ata', 'Ala', 'Alm', 'Alj', 'Ass'],\n    'months' => ['Žanwiye', 'Feewiriye', 'Marsi', 'Awiril', 'Me', 'Žuweŋ', 'Žuyye', 'Ut', 'Sektanbur', 'Oktoobur', 'Noowanbur', 'Deesanbur'],\n    'months_short' => ['Žan', 'Fee', 'Mar', 'Awi', 'Me', 'Žuw', 'Žuy', 'Ut', 'Sek', 'Okt', 'Noo', 'Dee'],\n    'first_day_of_week' => 1,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'D/M/YYYY',\n        'LL' => 'D MMM, YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd D MMMM YYYY HH:mm',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ki.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'meridiem' => ['Kiroko', 'Hwaĩ-inĩ'],\n    'weekdays' => ['Kiumia', 'Njumatatũ', 'Njumaine', 'Njumatana', 'Aramithi', 'Njumaa', 'Njumamothi'],\n    'weekdays_short' => ['KMA', 'NTT', 'NMN', 'NMT', 'ART', 'NMA', 'NMM'],\n    'weekdays_min' => ['KMA', 'NTT', 'NMN', 'NMT', 'ART', 'NMA', 'NMM'],\n    'months' => ['Njenuarĩ', 'Mwere wa kerĩ', 'Mwere wa gatatũ', 'Mwere wa kana', 'Mwere wa gatano', 'Mwere wa gatandatũ', 'Mwere wa mũgwanja', 'Mwere wa kanana', 'Mwere wa kenda', 'Mwere wa ikũmi', 'Mwere wa ikũmi na ũmwe', 'Ndithemba'],\n    'months_short' => ['JEN', 'WKR', 'WGT', 'WKN', 'WTN', 'WTD', 'WMJ', 'WNN', 'WKD', 'WIK', 'WMW', 'DIT'],\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY HH:mm',\n    ],\n\n    'year' => ':count mĩaka', // less reliable\n    'y' => ':count mĩaka', // less reliable\n    'a_year' => ':count mĩaka', // less reliable\n\n    'month' => ':count mweri', // less reliable\n    'm' => ':count mweri', // less reliable\n    'a_month' => ':count mweri', // less reliable\n\n    'week' => ':count kiumia', // less reliable\n    'w' => ':count kiumia', // less reliable\n    'a_week' => ':count kiumia', // less reliable\n\n    'day' => ':count mũthenya', // less reliable\n    'd' => ':count mũthenya', // less reliable\n    'a_day' => ':count mũthenya', // less reliable\n\n    'hour' => ':count thaa', // less reliable\n    'h' => ':count thaa', // less reliable\n    'a_hour' => ':count thaa', // less reliable\n\n    'minute' => ':count mundu', // less reliable\n    'min' => ':count mundu', // less reliable\n    'a_minute' => ':count mundu', // less reliable\n\n    'second' => ':count igego', // less reliable\n    's' => ':count igego', // less reliable\n    'a_second' => ':count igego', // less reliable\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/kk.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Josh Soref\n * - François B\n * - Talat Uspanov\n * - Нурлан Рахимжанов\n * - Toleugazy Kali\n */\nreturn [\n    'year' => ':count жыл',\n    'a_year' => '{1}бір жыл|:count жыл',\n    'y' => ':count ж.',\n    'month' => ':count ай',\n    'a_month' => '{1}бір ай|:count ай',\n    'm' => ':count ай',\n    'week' => ':count апта',\n    'a_week' => '{1}бір апта',\n    'w' => ':count ап.',\n    'day' => ':count күн',\n    'a_day' => '{1}бір күн|:count күн',\n    'd' => ':count к.',\n    'hour' => ':count сағат',\n    'a_hour' => '{1}бір сағат|:count сағат',\n    'h' => ':count са.',\n    'minute' => ':count минут',\n    'a_minute' => '{1}бір минут|:count минут',\n    'min' => ':count м.',\n    'second' => ':count секунд',\n    'a_second' => '{1}бірнеше секунд|:count секунд',\n    's' => ':count се.',\n    'ago' => ':time бұрын',\n    'from_now' => ':time ішінде',\n    'after' => ':time кейін',\n    'before' => ':time бұрын',\n    'diff_now' => 'қазір',\n    'diff_today' => 'Бүгін',\n    'diff_today_regexp' => 'Бүгін(?:\\\\s+сағат)?',\n    'diff_yesterday' => 'кеше',\n    'diff_yesterday_regexp' => 'Кеше(?:\\\\s+сағат)?',\n    'diff_tomorrow' => 'ертең',\n    'diff_tomorrow_regexp' => 'Ертең(?:\\\\s+сағат)?',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD.MM.YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[Бүгін сағат] LT',\n        'nextDay' => '[Ертең сағат] LT',\n        'nextWeek' => 'dddd [сағат] LT',\n        'lastDay' => '[Кеше сағат] LT',\n        'lastWeek' => '[Өткен аптаның] dddd [сағат] LT',\n        'sameElse' => 'L',\n    ],\n    'ordinal' => function ($number) {\n        static $suffixes = [\n            0 => '-ші',\n            1 => '-ші',\n            2 => '-ші',\n            3 => '-ші',\n            4 => '-ші',\n            5 => '-ші',\n            6 => '-шы',\n            7 => '-ші',\n            8 => '-ші',\n            9 => '-шы',\n            10 => '-шы',\n            20 => '-шы',\n            30 => '-шы',\n            40 => '-шы',\n            50 => '-ші',\n            60 => '-шы',\n            70 => '-ші',\n            80 => '-ші',\n            90 => '-шы',\n            100 => '-ші',\n        ];\n\n        return $number.($suffixes[$number] ?? $suffixes[$number % 10] ?? $suffixes[$number >= 100 ? 100 : -1] ?? '');\n    },\n    'months' => ['қаңтар', 'ақпан', 'наурыз', 'сәуір', 'мамыр', 'маусым', 'шілде', 'тамыз', 'қыркүйек', 'қазан', 'қараша', 'желтоқсан'],\n    'months_short' => ['қаң', 'ақп', 'нау', 'сәу', 'мам', 'мау', 'шіл', 'там', 'қыр', 'қаз', 'қар', 'жел'],\n    'weekdays' => ['жексенбі', 'дүйсенбі', 'сейсенбі', 'сәрсенбі', 'бейсенбі', 'жұма', 'сенбі'],\n    'weekdays_short' => ['жек', 'дүй', 'сей', 'сәр', 'бей', 'жұм', 'сен'],\n    'weekdays_min' => ['жк', 'дй', 'сй', 'ср', 'бй', 'жм', 'сн'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n    'list' => [', ', ' және '],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/kk_KZ.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/kk.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/kkj.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/kl.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/kl_GL.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/kl_GL.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Danish Standards Association    bug-glibc-locales@gnu.org\n * - John Eyðstein Johannesen (mashema)\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD.MM.YYYY',\n        'LL' => 'D. MMMM YYYY',\n        'LLL' => 'D. MMMM YYYY HH:mm',\n        'LLLL' => 'dddd [d.] D. MMMM YYYY [kl.] HH:mm',\n    ],\n    'months' => ['januaarip', 'februaarip', 'marsip', 'apriilip', 'maajip', 'juunip', 'juulip', 'aggustip', 'septembarip', 'oktobarip', 'novembarip', 'decembarip'],\n    'months_short' => ['jan', 'feb', 'mar', 'apr', 'maj', 'jun', 'jul', 'aug', 'sep', 'okt', 'nov', 'dec'],\n    'weekdays' => ['sapaat', 'ataasinngorneq', 'marlunngorneq', 'pingasunngorneq', 'sisamanngorneq', 'tallimanngorneq', 'arfininngorneq'],\n    'weekdays_short' => ['sap', 'ata', 'mar', 'pin', 'sis', 'tal', 'arf'],\n    'weekdays_min' => ['sap', 'ata', 'mar', 'pin', 'sis', 'tal', 'arf'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n\n    'year' => '{1}ukioq :count|{0}:count ukiut|]1,Inf[ukiut :count',\n    'a_year' => '{1}ukioq|{0}:count ukiut|]1,Inf[ukiut :count',\n    'y' => '{1}:countyr|{0}:countyrs|]1,Inf[:countyrs',\n\n    'month' => '{1}qaammat :count|{0}:count qaammatit|]1,Inf[qaammatit :count',\n    'a_month' => '{1}qaammat|{0}:count qaammatit|]1,Inf[qaammatit :count',\n    'm' => '{1}:countmo|{0}:countmos|]1,Inf[:countmos',\n\n    'week' => '{1}:count sap. ak.|{0}:count sap. ak.|]1,Inf[:count sap. ak.',\n    'a_week' => '{1}a sap. ak.|{0}:count sap. ak.|]1,Inf[:count sap. ak.',\n    'w' => ':countw',\n\n    'day' => '{1}:count ulloq|{0}:count ullut|]1,Inf[:count ullut',\n    'a_day' => '{1}a ulloq|{0}:count ullut|]1,Inf[:count ullut',\n    'd' => ':countd',\n\n    'hour' => '{1}:count tiimi|{0}:count tiimit|]1,Inf[:count tiimit',\n    'a_hour' => '{1}tiimi|{0}:count tiimit|]1,Inf[:count tiimit',\n    'h' => ':counth',\n\n    'minute' => '{1}:count minutsi|{0}:count minutsit|]1,Inf[:count minutsit',\n    'a_minute' => '{1}a minutsi|{0}:count minutsit|]1,Inf[:count minutsit',\n    'min' => ':countm',\n\n    'second' => '{1}:count sikunti|{0}:count sikuntit|]1,Inf[:count sikuntit',\n    'a_second' => '{1}sikunti|{0}:count sikuntit|]1,Inf[:count sikuntit',\n    's' => ':counts',\n\n    'ago' => ':time matuma siorna',\n\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/kln.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'meridiem' => ['krn', 'koosk'],\n    'weekdays' => ['Kotisap', 'Kotaai', 'Koaeng’', 'Kosomok', 'Koang’wan', 'Komuut', 'Kolo'],\n    'weekdays_short' => ['Kts', 'Kot', 'Koo', 'Kos', 'Koa', 'Kom', 'Kol'],\n    'weekdays_min' => ['Kts', 'Kot', 'Koo', 'Kos', 'Koa', 'Kom', 'Kol'],\n    'months' => ['Mulgul', 'Ng’atyaato', 'Kiptaamo', 'Iwootkuut', 'Mamuut', 'Paagi', 'Ng’eiyeet', 'Rooptui', 'Bureet', 'Epeeso', 'Kipsuunde ne taai', 'Kipsuunde nebo aeng’'],\n    'months_short' => ['Mul', 'Ngat', 'Taa', 'Iwo', 'Mam', 'Paa', 'Nge', 'Roo', 'Bur', 'Epe', 'Kpt', 'Kpa'],\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY HH:mm',\n    ],\n\n    'year' => ':count maghatiat', // less reliable\n    'y' => ':count maghatiat', // less reliable\n    'a_year' => ':count maghatiat', // less reliable\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/km.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Kruy Vanna\n * - Sereysethy Touch\n * - JD Isaacks\n * - Sovichet Tep\n */\nreturn [\n    'year' => '{1}មួយឆ្នាំ|]1,Inf[:count ឆ្នាំ',\n    'y' => ':count ឆ្នាំ',\n    'month' => '{1}មួយខែ|]1,Inf[:count ខែ',\n    'm' => ':count ខែ',\n    'week' => ':count សប្ដាហ៍',\n    'w' => ':count សប្ដាហ៍',\n    'day' => '{1}មួយថ្ងៃ|]1,Inf[:count ថ្ងៃ',\n    'd' => ':count ថ្ងៃ',\n    'hour' => '{1}មួយម៉ោង|]1,Inf[:count ម៉ោង',\n    'h' => ':count ម៉ោង',\n    'minute' => '{1}មួយនាទី|]1,Inf[:count នាទី',\n    'min' => ':count នាទី',\n    'second' => '{1}ប៉ុន្មានវិនាទី|]1,Inf[:count វិនាទី',\n    's' => ':count វិនាទី',\n    'ago' => ':timeមុន',\n    'from_now' => ':timeទៀត',\n    'after' => 'នៅ​ក្រោយ :time',\n    'before' => 'នៅ​មុន :time',\n    'diff_now' => 'ឥឡូវ',\n    'diff_today' => 'ថ្ងៃនេះ',\n    'diff_today_regexp' => 'ថ្ងៃនេះ(?:\\\\s+ម៉ោង)?',\n    'diff_yesterday' => 'ម្សិលមិញ',\n    'diff_yesterday_regexp' => 'ម្សិលមិញ(?:\\\\s+ម៉ោង)?',\n    'diff_tomorrow' => 'ថ្ងៃ​ស្អែក',\n    'diff_tomorrow_regexp' => 'ស្អែក(?:\\\\s+ម៉ោង)?',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[ថ្ងៃនេះ ម៉ោង] LT',\n        'nextDay' => '[ស្អែក ម៉ោង] LT',\n        'nextWeek' => 'dddd [ម៉ោង] LT',\n        'lastDay' => '[ម្សិលមិញ ម៉ោង] LT',\n        'lastWeek' => 'dddd [សប្តាហ៍មុន] [ម៉ោង] LT',\n        'sameElse' => 'L',\n    ],\n    'ordinal' => 'ទី:number',\n    'meridiem' => ['ព្រឹក', 'ល្ងាច'],\n    'months' => ['មករា', 'កុម្ភៈ', 'មីនា', 'មេសា', 'ឧសភា', 'មិថុនា', 'កក្កដា', 'សីហា', 'កញ្ញា', 'តុលា', 'វិច្ឆិកា', 'ធ្នូ'],\n    'months_short' => ['មករា', 'កុម្ភៈ', 'មីនា', 'មេសា', 'ឧសភា', 'មិថុនា', 'កក្កដា', 'សីហា', 'កញ្ញា', 'តុលា', 'វិច្ឆិកា', 'ធ្នូ'],\n    'weekdays' => ['អាទិត្យ', 'ច័ន្ទ', 'អង្គារ', 'ពុធ', 'ព្រហស្បតិ៍', 'សុក្រ', 'សៅរ៍'],\n    'weekdays_short' => ['អា', 'ច', 'អ', 'ព', 'ព្រ', 'សុ', 'ស'],\n    'weekdays_min' => ['អា', 'ច', 'អ', 'ព', 'ព្រ', 'សុ', 'ស'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n    'list' => [', ', 'និង '],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/km_KH.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/km.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/kn.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Josh Soref\n * - MOHAN M U\n * - François B\n * - rajeevnaikte\n */\nreturn [\n    'year' => '{1}ಒಂದು ವರ್ಷ|]1,Inf[:count ವರ್ಷ',\n    'month' => '{1}ಒಂದು ತಿಂಗಳು|]1,Inf[:count ತಿಂಗಳು',\n    'week' => '{1}ಒಂದು ವಾರ|]1,Inf[:count ವಾರಗಳು',\n    'day' => '{1}ಒಂದು ದಿನ|]1,Inf[:count ದಿನ',\n    'hour' => '{1}ಒಂದು ಗಂಟೆ|]1,Inf[:count ಗಂಟೆ',\n    'minute' => '{1}ಒಂದು ನಿಮಿಷ|]1,Inf[:count ನಿಮಿಷ',\n    'second' => '{1}ಕೆಲವು ಕ್ಷಣಗಳು|]1,Inf[:count ಸೆಕೆಂಡುಗಳು',\n    'ago' => ':time ಹಿಂದೆ',\n    'from_now' => ':time ನಂತರ',\n    'diff_now' => 'ಈಗ',\n    'diff_today' => 'ಇಂದು',\n    'diff_yesterday' => 'ನಿನ್ನೆ',\n    'diff_tomorrow' => 'ನಾಳೆ',\n    'formats' => [\n        'LT' => 'A h:mm',\n        'LTS' => 'A h:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY, A h:mm',\n        'LLLL' => 'dddd, D MMMM YYYY, A h:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[ಇಂದು] LT',\n        'nextDay' => '[ನಾಳೆ] LT',\n        'nextWeek' => 'dddd, LT',\n        'lastDay' => '[ನಿನ್ನೆ] LT',\n        'lastWeek' => '[ಕೊನೆಯ] dddd, LT',\n        'sameElse' => 'L',\n    ],\n    'ordinal' => ':numberನೇ',\n    'meridiem' => function ($hour) {\n        if ($hour < 4) {\n            return 'ರಾತ್ರಿ';\n        }\n        if ($hour < 10) {\n            return 'ಬೆಳಿಗ್ಗೆ';\n        }\n        if ($hour < 17) {\n            return 'ಮಧ್ಯಾಹ್ನ';\n        }\n        if ($hour < 20) {\n            return 'ಸಂಜೆ';\n        }\n\n        return 'ರಾತ್ರಿ';\n    },\n    'months' => ['ಜನವರಿ', 'ಫೆಬ್ರವರಿ', 'ಮಾರ್ಚ್', 'ಏಪ್ರಿಲ್', 'ಮೇ', 'ಜೂನ್', 'ಜುಲೈ', 'ಆಗಸ್ಟ್', 'ಸೆಪ್ಟೆಂಬರ್', 'ಅಕ್ಟೋಬರ್', 'ನವೆಂಬರ್', 'ಡಿಸೆಂಬರ್'],\n    'months_short' => ['ಜನ', 'ಫೆಬ್ರ', 'ಮಾರ್ಚ್', 'ಏಪ್ರಿಲ್', 'ಮೇ', 'ಜೂನ್', 'ಜುಲೈ', 'ಆಗಸ್ಟ್', 'ಸೆಪ್ಟೆಂ', 'ಅಕ್ಟೋ', 'ನವೆಂ', 'ಡಿಸೆಂ'],\n    'weekdays' => ['ಭಾನುವಾರ', 'ಸೋಮವಾರ', 'ಮಂಗಳವಾರ', 'ಬುಧವಾರ', 'ಗುರುವಾರ', 'ಶುಕ್ರವಾರ', 'ಶನಿವಾರ'],\n    'weekdays_short' => ['ಭಾನು', 'ಸೋಮ', 'ಮಂಗಳ', 'ಬುಧ', 'ಗುರು', 'ಶುಕ್ರ', 'ಶನಿ'],\n    'weekdays_min' => ['ಭಾ', 'ಸೋ', 'ಮಂ', 'ಬು', 'ಗು', 'ಶು', 'ಶ'],\n    'list' => ', ',\n    'first_day_of_week' => 0,\n    'day_of_first_week_of_year' => 1,\n    'weekend' => [0, 0],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/kn_IN.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/kn.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ko.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Kunal Marwaha\n * - FourwingsY\n * - François B\n * - Jason Katz-Brown\n * - Seokjun Kim\n * - Junho Kim\n * - JD Isaacks\n * - Juwon Kim\n */\nreturn [\n    'year' => ':count년',\n    'a_year' => '{1}일년|]1,Inf[:count년',\n    'y' => ':count년',\n    'month' => ':count개월',\n    'a_month' => '{1}한달|]1,Inf[:count개월',\n    'm' => ':count개월',\n    'week' => ':count주',\n    'a_week' => '{1}일주일|]1,Inf[:count 주',\n    'w' => ':count주일',\n    'day' => ':count일',\n    'a_day' => '{1}하루|]1,Inf[:count일',\n    'd' => ':count일',\n    'hour' => ':count시간',\n    'a_hour' => '{1}한시간|]1,Inf[:count시간',\n    'h' => ':count시간',\n    'minute' => ':count분',\n    'a_minute' => '{1}일분|]1,Inf[:count분',\n    'min' => ':count분',\n    'second' => ':count초',\n    'a_second' => '{1}몇초|]1,Inf[:count초',\n    's' => ':count초',\n    'ago' => ':time 전',\n    'from_now' => ':time 후',\n    'after' => ':time 후',\n    'before' => ':time 전',\n    'diff_now' => '지금',\n    'diff_today' => '오늘',\n    'diff_yesterday' => '어제',\n    'diff_tomorrow' => '내일',\n    'formats' => [\n        'LT' => 'A h:mm',\n        'LTS' => 'A h:mm:ss',\n        'L' => 'YYYY.MM.DD.',\n        'LL' => 'YYYY년 MMMM D일',\n        'LLL' => 'YYYY년 MMMM D일 A h:mm',\n        'LLLL' => 'YYYY년 MMMM D일 dddd A h:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '오늘 LT',\n        'nextDay' => '내일 LT',\n        'nextWeek' => 'dddd LT',\n        'lastDay' => '어제 LT',\n        'lastWeek' => '지난주 dddd LT',\n        'sameElse' => 'L',\n    ],\n    'ordinal' => function ($number, $period) {\n        switch ($period) {\n            case 'd':\n            case 'D':\n            case 'DDD':\n                return $number.'일';\n            case 'M':\n                return $number.'월';\n            case 'w':\n            case 'W':\n                return $number.'주';\n            default:\n                return $number;\n        }\n    },\n    'meridiem' => ['오전', '오후'],\n    'months' => ['1월', '2월', '3월', '4월', '5월', '6월', '7월', '8월', '9월', '10월', '11월', '12월'],\n    'months_short' => ['1월', '2월', '3월', '4월', '5월', '6월', '7월', '8월', '9월', '10월', '11월', '12월'],\n    'weekdays' => ['일요일', '월요일', '화요일', '수요일', '목요일', '금요일', '토요일'],\n    'weekdays_short' => ['일', '월', '화', '수', '목', '금', '토'],\n    'weekdays_min' => ['일', '월', '화', '수', '목', '금', '토'],\n    'list' => ' ',\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ko_KP.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/ko.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ko_KR.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/ko.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/kok.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/kok_IN.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/kok_IN.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Red Hat, Pune    bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'D-M-YY',\n    ],\n    'months' => ['जानेवारी', 'फेब्रुवारी', 'मार्च', 'एप्रिल', 'मे', 'जून', 'जुलै', 'ओगस्ट', 'सेप्टेंबर', 'ओक्टोबर', 'नोव्हेंबर', 'डिसेंबर'],\n    'months_short' => ['जानेवारी', 'फेब्रुवारी', 'मार्च', 'एप्रिल', 'मे', 'जून', 'जुलै', 'ओगस्ट', 'सेप्टेंबर', 'ओक्टोबर', 'नोव्हेंबर', 'डिसेंबर'],\n    'weekdays' => ['आयतार', 'सोमार', 'मंगळवार', 'बुधवार', 'बेरेसतार', 'शुकरार', 'शेनवार'],\n    'weekdays_short' => ['आयतार', 'सोमार', 'मंगळवार', 'बुधवार', 'बेरेसतार', 'शुकरार', 'शेनवार'],\n    'weekdays_min' => ['आयतार', 'सोमार', 'मंगळवार', 'बुधवार', 'बेरेसतार', 'शुकरार', 'शेनवार'],\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['म.पू.', 'म.नं.'],\n\n    'year' => ':count वैशाकु', // less reliable\n    'y' => ':count वैशाकु', // less reliable\n    'a_year' => ':count वैशाकु', // less reliable\n\n    'week' => ':count आदित्यवार', // less reliable\n    'w' => ':count आदित्यवार', // less reliable\n    'a_week' => ':count आदित्यवार', // less reliable\n\n    'minute' => ':count नोंद', // less reliable\n    'min' => ':count नोंद', // less reliable\n    'a_minute' => ':count नोंद', // less reliable\n\n    'second' => ':count तेंको', // less reliable\n    's' => ':count तेंको', // less reliable\n    'a_second' => ':count तेंको', // less reliable\n\n    'month' => ':count मैनो',\n    'm' => ':count मैनो',\n    'a_month' => ':count मैनो',\n\n    'day' => ':count दिवसु',\n    'd' => ':count दिवसु',\n    'a_day' => ':count दिवसु',\n\n    'hour' => ':count घंते',\n    'h' => ':count घंते',\n    'a_hour' => ':count घंते',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ks.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/ks_IN.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ks_IN.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Red Hat, Pune    bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'M/D/YY',\n    ],\n    'months' => ['جنؤری', 'فرؤری', 'مارٕچ', 'اپریل', 'میٔ', 'جوٗن', 'جوٗلایی', 'اگست', 'ستمبر', 'اکتوٗبر', 'نومبر', 'دسمبر'],\n    'months_short' => ['جنؤری', 'فرؤری', 'مارٕچ', 'اپریل', 'میٔ', 'جوٗن', 'جوٗلایی', 'اگست', 'ستمبر', 'اکتوٗبر', 'نومبر', 'دسمبر'],\n    'weekdays' => ['آتهوار', 'ژءندروار', 'بوءںوار', 'بودهوار', 'برىسوار', 'جمع', 'بٹوار'],\n    'weekdays_short' => ['آتهوار', 'ژءنتروار', 'بوءںوار', 'بودهوار', 'برىسوار', 'جمع', 'بٹوار'],\n    'weekdays_min' => ['آتهوار', 'ژءنتروار', 'بوءںوار', 'بودهوار', 'برىسوار', 'جمع', 'بٹوار'],\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['دوپھربرونھ', 'دوپھرپتھ'],\n\n    'year' => ':count آب', // less reliable\n    'y' => ':count آب', // less reliable\n    'a_year' => ':count آب', // less reliable\n\n    'month' => ':count रान्', // less reliable\n    'm' => ':count रान्', // less reliable\n    'a_month' => ':count रान्', // less reliable\n\n    'week' => ':count آتھٕوار', // less reliable\n    'w' => ':count آتھٕوار', // less reliable\n    'a_week' => ':count آتھٕوار', // less reliable\n\n    'hour' => ':count سۄن', // less reliable\n    'h' => ':count سۄن', // less reliable\n    'a_hour' => ':count سۄن', // less reliable\n\n    'minute' => ':count فَن', // less reliable\n    'min' => ':count فَن', // less reliable\n    'a_minute' => ':count فَن', // less reliable\n\n    'second' => ':count दोʼयुम', // less reliable\n    's' => ':count दोʼयुम', // less reliable\n    'a_second' => ':count दोʼयुम', // less reliable\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ks_IN@devanagari.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - ks-gnome-trans-commits@lists.code.indlinux.net\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'M/D/YY',\n    ],\n    'months' => ['जनवरी', 'फ़रवरी', 'मार्च', 'अप्रेल', 'मई', 'जून', 'जुलाई', 'अगस्त', 'सितम्बर', 'अक्टूबर', 'नवम्बर', 'दिसम्बर'],\n    'months_short' => ['जनवरी', 'फ़रवरी', 'मार्च', 'अप्रेल', 'मई', 'जून', 'जुलाई', 'अगस्त', 'सितम्बर', 'अक्टूबर', 'नवम्बर', 'दिसम्बर'],\n    'weekdays' => ['आथवार', 'चॅ़दुरवार', 'बोमवार', 'ब्वदवार', 'ब्रसवार', 'शोकुरवार', 'बटुवार'],\n    'weekdays_short' => ['आथ ', 'चॅ़दुर', 'बोम', 'ब्वद', 'ब्रस', 'शोकुर', 'बटु'],\n    'weekdays_min' => ['आथ ', 'चॅ़दुर', 'बोम', 'ब्वद', 'ब्रस', 'शोकुर', 'बटु'],\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['पूर्वाह्न', 'अपराह्न'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ksb.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'meridiem' => ['makeo', 'nyiaghuo'],\n    'weekdays' => ['Jumaapii', 'Jumaatatu', 'Jumaane', 'Jumaatano', 'Alhamisi', 'Ijumaa', 'Jumaamosi'],\n    'weekdays_short' => ['Jpi', 'Jtt', 'Jmn', 'Jtn', 'Alh', 'Iju', 'Jmo'],\n    'weekdays_min' => ['Jpi', 'Jtt', 'Jmn', 'Jtn', 'Alh', 'Iju', 'Jmo'],\n    'months' => ['Januali', 'Febluali', 'Machi', 'Aplili', 'Mei', 'Juni', 'Julai', 'Agosti', 'Septemba', 'Oktoba', 'Novemba', 'Desemba'],\n    'months_short' => ['Jan', 'Feb', 'Mac', 'Apr', 'Mei', 'Jun', 'Jul', 'Ago', 'Sep', 'Okt', 'Nov', 'Des'],\n    'first_day_of_week' => 1,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY HH:mm',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ksf.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'meridiem' => ['sárúwá', 'cɛɛ́nko'],\n    'weekdays' => ['sɔ́ndǝ', 'lǝndí', 'maadí', 'mɛkrɛdí', 'jǝǝdí', 'júmbá', 'samdí'],\n    'weekdays_short' => ['sɔ́n', 'lǝn', 'maa', 'mɛk', 'jǝǝ', 'júm', 'sam'],\n    'weekdays_min' => ['sɔ́n', 'lǝn', 'maa', 'mɛk', 'jǝǝ', 'júm', 'sam'],\n    'months' => ['ŋwíí a ntɔ́ntɔ', 'ŋwíí akǝ bɛ́ɛ', 'ŋwíí akǝ ráá', 'ŋwíí akǝ nin', 'ŋwíí akǝ táan', 'ŋwíí akǝ táafɔk', 'ŋwíí akǝ táabɛɛ', 'ŋwíí akǝ táaraa', 'ŋwíí akǝ táanin', 'ŋwíí akǝ ntɛk', 'ŋwíí akǝ ntɛk di bɔ́k', 'ŋwíí akǝ ntɛk di bɛ́ɛ'],\n    'months_short' => ['ŋ1', 'ŋ2', 'ŋ3', 'ŋ4', 'ŋ5', 'ŋ6', 'ŋ7', 'ŋ8', 'ŋ9', 'ŋ10', 'ŋ11', 'ŋ12'],\n    'first_day_of_week' => 1,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'D/M/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd D MMMM YYYY HH:mm',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ksh.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'meridiem' => ['v.M.', 'n.M.'],\n    'weekdays' => ['Sunndaach', 'Mohndaach', 'Dinnsdaach', 'Metwoch', 'Dunnersdaach', 'Friidaach', 'Samsdaach'],\n    'weekdays_short' => ['Su.', 'Mo.', 'Di.', 'Me.', 'Du.', 'Fr.', 'Sa.'],\n    'weekdays_min' => ['Su', 'Mo', 'Di', 'Me', 'Du', 'Fr', 'Sa'],\n    'months' => ['Jannewa', 'Fäbrowa', 'Määz', 'Aprell', 'Mai', 'Juuni', 'Juuli', 'Oujoß', 'Septämber', 'Oktohber', 'Novämber', 'Dezämber'],\n    'months_short' => ['Jan', 'Fäb', 'Mäz', 'Apr', 'Mai', 'Jun', 'Jul', 'Ouj', 'Säp', 'Okt', 'Nov', 'Dez'],\n    'months_short_standalone' => ['Jan.', 'Fäb.', 'Mäz.', 'Apr.', 'Mai', 'Jun.', 'Jul.', 'Ouj.', 'Säp.', 'Okt.', 'Nov.', 'Dez.'],\n    'first_day_of_week' => 1,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'D. M. YYYY',\n        'LL' => 'D. MMM. YYYY',\n        'LLL' => 'D. MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, [dä] D. MMMM YYYY HH:mm',\n    ],\n\n    'year' => ':count Johr',\n    'y' => ':count Johr',\n    'a_year' => ':count Johr',\n\n    'month' => ':count Moohnd',\n    'm' => ':count Moohnd',\n    'a_month' => ':count Moohnd',\n\n    'week' => ':count woch',\n    'w' => ':count woch',\n    'a_week' => ':count woch',\n\n    'day' => ':count Daach',\n    'd' => ':count Daach',\n    'a_day' => ':count Daach',\n\n    'hour' => ':count Uhr',\n    'h' => ':count Uhr',\n    'a_hour' => ':count Uhr',\n\n    'minute' => ':count Menutt',\n    'min' => ':count Menutt',\n    'a_minute' => ':count Menutt',\n\n    'second' => ':count Sekůndt',\n    's' => ':count Sekůndt',\n    'a_second' => ':count Sekůndt',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ku.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Unicode, Inc.\n */\n\nreturn [\n    'ago' => 'berî :time',\n    'from_now' => 'di :time de',\n    'after' => ':time piştî',\n    'before' => ':time berê',\n    'year' => ':count sal',\n    'year_ago' => ':count salê|:count salan',\n    'year_from_now' => 'salekê|:count salan',\n    'month' => ':count meh',\n    'week' => ':count hefte',\n    'day' => ':count roj',\n    'hour' => ':count saet',\n    'minute' => ':count deqîqe',\n    'second' => ':count saniye',\n    'months' => ['rêbendanê', 'reşemiyê', 'adarê', 'avrêlê', 'gulanê', 'pûşperê', 'tîrmehê', 'gelawêjê', 'rezberê', 'kewçêrê', 'sermawezê', 'berfanbarê'],\n    'months_standalone' => ['rêbendan', 'reşemî', 'adar', 'avrêl', 'gulan', 'pûşper', 'tîrmeh', 'gelawêj', 'rezber', 'kewçêr', 'sermawez', 'berfanbar'],\n    'months_short' => ['rêb', 'reş', 'ada', 'avr', 'gul', 'pûş', 'tîr', 'gel', 'rez', 'kew', 'ser', 'ber'],\n    'weekdays' => ['yekşem', 'duşem', 'sêşem', 'çarşem', 'pêncşem', 'în', 'şemî'],\n    'weekdays_short' => ['yş', 'dş', 'sş', 'çş', 'pş', 'în', 'ş'],\n    'weekdays_min' => ['Y', 'D', 'S', 'Ç', 'P', 'Î', 'Ş'],\n    'list' => [', ', ' û '],\n    'first_day_of_week' => 6,\n    'day_of_first_week_of_year' => 1,\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ku_TR.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/ku.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/kw.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/kw_GB.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/kw_GB.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Alastair McKinstry    bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD/MM/YY',\n    ],\n    'months' => ['mis Genver', 'mis Hwevrer', 'mis Meurth', 'mis Ebrel', 'mis Me', 'mis Metheven', 'mis Gortheren', 'mis Est', 'mis Gwynngala', 'mis Hedra', 'mis Du', 'mis Kevardhu'],\n    'months_short' => ['Gen', 'Hwe', 'Meu', 'Ebr', 'Me', 'Met', 'Gor', 'Est', 'Gwn', 'Hed', 'Du', 'Kev'],\n    'weekdays' => ['De Sul', 'De Lun', 'De Merth', 'De Merher', 'De Yow', 'De Gwener', 'De Sadorn'],\n    'weekdays_short' => ['Sul', 'Lun', 'Mth', 'Mhr', 'Yow', 'Gwe', 'Sad'],\n    'weekdays_min' => ['Sul', 'Lun', 'Mth', 'Mhr', 'Yow', 'Gwe', 'Sad'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n\n    'year' => ':count bledhen',\n    'y' => ':count bledhen',\n    'a_year' => ':count bledhen',\n\n    'month' => ':count mis',\n    'm' => ':count mis',\n    'a_month' => ':count mis',\n\n    'week' => ':count seythen',\n    'w' => ':count seythen',\n    'a_week' => ':count seythen',\n\n    'day' => ':count dydh',\n    'd' => ':count dydh',\n    'a_day' => ':count dydh',\n\n    'hour' => ':count eur',\n    'h' => ':count eur',\n    'a_hour' => ':count eur',\n\n    'minute' => ':count mynysen',\n    'min' => ':count mynysen',\n    'a_minute' => ':count mynysen',\n\n    'second' => ':count pryjwyth',\n    's' => ':count pryjwyth',\n    'a_second' => ':count pryjwyth',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ky.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - acutexyz\n * - Josh Soref\n * - François B\n * - Chyngyz Arystan uulu\n * - Chyngyz\n * - acutexyz\n * - Josh Soref\n * - François B\n * - Chyngyz Arystan uulu\n */\nreturn [\n    'year' => ':count жыл',\n    'a_year' => '{1}бир жыл|:count жыл',\n    'y' => ':count жыл',\n    'month' => ':count ай',\n    'a_month' => '{1}бир ай|:count ай',\n    'm' => ':count ай',\n    'week' => ':count апта',\n    'a_week' => '{1}бир апта|:count апта',\n    'w' => ':count апт.',\n    'day' => ':count күн',\n    'a_day' => '{1}бир күн|:count күн',\n    'd' => ':count күн',\n    'hour' => ':count саат',\n    'a_hour' => '{1}бир саат|:count саат',\n    'h' => ':count саат.',\n    'minute' => ':count мүнөт',\n    'a_minute' => '{1}бир мүнөт|:count мүнөт',\n    'min' => ':count мүн.',\n    'second' => ':count секунд',\n    'a_second' => '{1}бирнече секунд|:count секунд',\n    's' => ':count сек.',\n    'ago' => ':time мурун',\n    'from_now' => ':time ичинде',\n    'diff_now' => 'азыр',\n    'diff_today' => 'Бүгүн',\n    'diff_today_regexp' => 'Бүгүн(?:\\\\s+саат)?',\n    'diff_yesterday' => 'кечээ',\n    'diff_yesterday_regexp' => 'Кече(?:\\\\s+саат)?',\n    'diff_tomorrow' => 'эртең',\n    'diff_tomorrow_regexp' => 'Эртең(?:\\\\s+саат)?',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD.MM.YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[Бүгүн саат] LT',\n        'nextDay' => '[Эртең саат] LT',\n        'nextWeek' => 'dddd [саат] LT',\n        'lastDay' => '[Кече саат] LT',\n        'lastWeek' => '[Өткен аптанын] dddd [күнү] [саат] LT',\n        'sameElse' => 'L',\n    ],\n    'ordinal' => function ($number) {\n        static $suffixes = [\n            0 => '-чү',\n            1 => '-чи',\n            2 => '-чи',\n            3 => '-чү',\n            4 => '-чү',\n            5 => '-чи',\n            6 => '-чы',\n            7 => '-чи',\n            8 => '-чи',\n            9 => '-чу',\n            10 => '-чу',\n            20 => '-чы',\n            30 => '-чу',\n            40 => '-чы',\n            50 => '-чү',\n            60 => '-чы',\n            70 => '-чи',\n            80 => '-чи',\n            90 => '-чу',\n            100 => '-чү',\n        ];\n\n        return $number.($suffixes[$number] ?? $suffixes[$number % 10] ?? $suffixes[$number >= 100 ? 100 : -1] ?? '');\n    },\n    'months' => ['январь', 'февраль', 'март', 'апрель', 'май', 'июнь', 'июль', 'август', 'сентябрь', 'октябрь', 'ноябрь', 'декабрь'],\n    'months_short' => ['янв', 'фев', 'март', 'апр', 'май', 'июнь', 'июль', 'авг', 'сен', 'окт', 'ноя', 'дек'],\n    'weekdays' => ['Жекшемби', 'Дүйшөмбү', 'Шейшемби', 'Шаршемби', 'Бейшемби', 'Жума', 'Ишемби'],\n    'weekdays_short' => ['Жек', 'Дүй', 'Шей', 'Шар', 'Бей', 'Жум', 'Ише'],\n    'weekdays_min' => ['Жк', 'Дй', 'Шй', 'Шр', 'Бй', 'Жм', 'Иш'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n    'list' => ' ',\n    'meridiem' => ['таңкы', 'түштөн кийинки'],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ky_KG.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/ky.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/lag.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'meridiem' => ['TOO', 'MUU'],\n    'weekdays' => ['Jumapíiri', 'Jumatátu', 'Jumaíne', 'Jumatáano', 'Alamíisi', 'Ijumáa', 'Jumamóosi'],\n    'weekdays_short' => ['Píili', 'Táatu', 'Íne', 'Táano', 'Alh', 'Ijm', 'Móosi'],\n    'weekdays_min' => ['Píili', 'Táatu', 'Íne', 'Táano', 'Alh', 'Ijm', 'Móosi'],\n    'months' => ['Kʉfúngatɨ', 'Kʉnaanɨ', 'Kʉkeenda', 'Kwiikumi', 'Kwiinyambála', 'Kwiidwaata', 'Kʉmʉʉnchɨ', 'Kʉvɨɨrɨ', 'Kʉsaatʉ', 'Kwiinyi', 'Kʉsaano', 'Kʉsasatʉ'],\n    'months_short' => ['Fúngatɨ', 'Naanɨ', 'Keenda', 'Ikúmi', 'Inyambala', 'Idwaata', 'Mʉʉnchɨ', 'Vɨɨrɨ', 'Saatʉ', 'Inyi', 'Saano', 'Sasatʉ'],\n    'first_day_of_week' => 1,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY HH:mm',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/lb.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Philippe Vaucher\n * - Tsutomu Kuroda\n * - dan-nl\n * - Simon Lelorrain (slelorrain)\n */\n\nuse Carbon\\CarbonInterface;\n\nreturn [\n    'year' => ':count Joer',\n    'y' => ':countJ',\n    'month' => ':count Mount|:count Méint',\n    'm' => ':countMo',\n    'week' => ':count Woch|:count Wochen',\n    'w' => ':countWo|:countWo',\n    'day' => ':count Dag|:count Deeg',\n    'd' => ':countD',\n    'hour' => ':count Stonn|:count Stonnen',\n    'h' => ':countSto',\n    'minute' => ':count Minutt|:count Minutten',\n    'min' => ':countM',\n    'second' => ':count Sekonn|:count Sekonnen',\n    's' => ':countSek',\n\n    'ago' => 'virun :time',\n    'from_now' => 'an :time',\n    'before' => ':time virdrun',\n    'after' => ':time duerno',\n\n    'diff_today' => 'Haut',\n    'diff_yesterday' => 'Gëschter',\n    'diff_yesterday_regexp' => 'Gëschter(?:\\\\s+um)?',\n    'diff_tomorrow' => 'Muer',\n    'diff_tomorrow_regexp' => 'Muer(?:\\\\s+um)?',\n    'diff_today_regexp' => 'Haut(?:\\\\s+um)?',\n    'formats' => [\n        'LT' => 'H:mm [Auer]',\n        'LTS' => 'H:mm:ss [Auer]',\n        'L' => 'DD.MM.YYYY',\n        'LL' => 'D. MMMM YYYY',\n        'LLL' => 'D. MMMM YYYY H:mm [Auer]',\n        'LLLL' => 'dddd, D. MMMM YYYY H:mm [Auer]',\n    ],\n\n    'calendar' => [\n        'sameDay' => '[Haut um] LT',\n        'nextDay' => '[Muer um] LT',\n        'nextWeek' => 'dddd [um] LT',\n        'lastDay' => '[Gëschter um] LT',\n        'lastWeek' => function (CarbonInterface $date) {\n            // Different date string for 'Dënschdeg' (Tuesday) and 'Donneschdeg' (Thursday) due to phonological rule\n            switch ($date->dayOfWeek) {\n                case 2:\n                case 4:\n                    return '[Leschten] dddd [um] LT';\n                default:\n                    return '[Leschte] dddd [um] LT';\n            }\n        },\n        'sameElse' => 'L',\n    ],\n\n    'months' => ['Januar', 'Februar', 'Mäerz', 'Abrëll', 'Mee', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'],\n    'months_short' => ['Jan.', 'Febr.', 'Mrz.', 'Abr.', 'Mee', 'Jun.', 'Jul.', 'Aug.', 'Sept.', 'Okt.', 'Nov.', 'Dez.'],\n    'weekdays' => ['Sonndeg', 'Méindeg', 'Dënschdeg', 'Mëttwoch', 'Donneschdeg', 'Freideg', 'Samschdeg'],\n    'weekdays_short' => ['So.', 'Mé.', 'Dë.', 'Më.', 'Do.', 'Fr.', 'Sa.'],\n    'weekdays_min' => ['So', 'Mé', 'Dë', 'Më', 'Do', 'Fr', 'Sa'],\n    'ordinal' => ':number.',\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n    'list' => [', ', ' an '],\n    'meridiem' => ['moies', 'mëttes'],\n    'weekdays_short_standalone' => ['Son', 'Méi', 'Dën', 'Mët', 'Don', 'Fre', 'Sam'],\n    'months_short_standalone' => ['Jan', 'Feb', 'Mäe', 'Abr', 'Mee', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/lb_LU.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/lb.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/lg.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/lg_UG.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/lg_UG.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Akademe ya Luganda Kizito Birabwa kompyuta@kizito.uklinux.net\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD/MM/YY',\n    ],\n    'months' => ['Janwaliyo', 'Febwaliyo', 'Marisi', 'Apuli', 'Maayi', 'Juuni', 'Julaayi', 'Agusito', 'Sebuttemba', 'Okitobba', 'Novemba', 'Desemba'],\n    'months_short' => ['Jan', 'Feb', 'Mar', 'Apu', 'Maa', 'Juu', 'Jul', 'Agu', 'Seb', 'Oki', 'Nov', 'Des'],\n    'weekdays' => ['Sabiiti', 'Balaza', 'Lwakubiri', 'Lwakusatu', 'Lwakuna', 'Lwakutaano', 'Lwamukaaga'],\n    'weekdays_short' => ['Sab', 'Bal', 'Lw2', 'Lw3', 'Lw4', 'Lw5', 'Lw6'],\n    'weekdays_min' => ['Sab', 'Bal', 'Lw2', 'Lw3', 'Lw4', 'Lw5', 'Lw6'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n\n    'month' => ':count njuba', // less reliable\n    'm' => ':count njuba', // less reliable\n    'a_month' => ':count njuba', // less reliable\n\n    'year' => ':count mwaaka',\n    'y' => ':count mwaaka',\n    'a_year' => ':count mwaaka',\n\n    'week' => ':count sabbiiti',\n    'w' => ':count sabbiiti',\n    'a_week' => ':count sabbiiti',\n\n    'day' => ':count lunaku',\n    'd' => ':count lunaku',\n    'a_day' => ':count lunaku',\n\n    'hour' => 'saawa :count',\n    'h' => 'saawa :count',\n    'a_hour' => 'saawa :count',\n\n    'minute' => 'ddakiika :count',\n    'min' => 'ddakiika :count',\n    'a_minute' => 'ddakiika :count',\n\n    'second' => ':count kyʼokubiri',\n    's' => ':count kyʼokubiri',\n    'a_second' => ':count kyʼokubiri',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/li.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/li_NL.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/li_NL.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - information from Kenneth Christiansen Kenneth Christiansen, Pablo Saratxaga kenneth@gnu.org, pablo@mandriva.com\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD.MM.YYYY',\n    ],\n    'months' => ['jannewarie', 'fibberwarie', 'miert', 'eprèl', 'meij', 'junie', 'julie', 'augustus', 'september', 'oktober', 'november', 'desember'],\n    'months_short' => ['jan', 'fib', 'mie', 'epr', 'mei', 'jun', 'jul', 'aug', 'sep', 'okt', 'nov', 'des'],\n    'weekdays' => ['zóndig', 'maondig', 'daensdig', 'goonsdig', 'dónderdig', 'vriedig', 'zaoterdig'],\n    'weekdays_short' => ['zón', 'mao', 'dae', 'goo', 'dón', 'vri', 'zao'],\n    'weekdays_min' => ['zón', 'mao', 'dae', 'goo', 'dón', 'vri', 'zao'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n\n    'minute' => ':count momênt', // less reliable\n    'min' => ':count momênt', // less reliable\n    'a_minute' => ':count momênt', // less reliable\n\n    'year' => ':count jaor',\n    'y' => ':count jaor',\n    'a_year' => ':count jaor',\n\n    'month' => ':count maond',\n    'm' => ':count maond',\n    'a_month' => ':count maond',\n\n    'week' => ':count waek',\n    'w' => ':count waek',\n    'a_week' => ':count waek',\n\n    'day' => ':count daag',\n    'd' => ':count daag',\n    'a_day' => ':count daag',\n\n    'hour' => ':count oer',\n    'h' => ':count oer',\n    'a_hour' => ':count oer',\n\n    'second' => ':count Secónd',\n    's' => ':count Secónd',\n    'a_second' => ':count Secónd',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/lij.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/lij_IT.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/lij_IT.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Gastaldi    alessio.gastaldi@libero.it\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD/MM/YYYY',\n    ],\n    'months' => ['zenâ', 'fevrâ', 'marzo', 'avrî', 'mazzo', 'zûgno', 'lûggio', 'agosto', 'settembre', 'ottobre', 'novembre', 'dixembre'],\n    'months_short' => ['zen', 'fev', 'mar', 'arv', 'maz', 'zûg', 'lûg', 'ago', 'set', 'ött', 'nov', 'dix'],\n    'weekdays' => ['domenega', 'lûnedì', 'martedì', 'mercUrdì', 'zêggia', 'venardì', 'sabbo'],\n    'weekdays_short' => ['dom', 'lûn', 'mar', 'mer', 'zêu', 'ven', 'sab'],\n    'weekdays_min' => ['dom', 'lûn', 'mar', 'mer', 'zêu', 'ven', 'sab'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n\n    'year' => ':count etæ', // less reliable\n    'y' => ':count etæ', // less reliable\n    'a_year' => ':count etæ', // less reliable\n\n    'month' => ':count meize',\n    'm' => ':count meize',\n    'a_month' => ':count meize',\n\n    'week' => ':count settemannha',\n    'w' => ':count settemannha',\n    'a_week' => ':count settemannha',\n\n    'day' => ':count giorno',\n    'd' => ':count giorno',\n    'a_day' => ':count giorno',\n\n    'hour' => ':count reléuio', // less reliable\n    'h' => ':count reléuio', // less reliable\n    'a_hour' => ':count reléuio', // less reliable\n\n    'minute' => ':count menûo',\n    'min' => ':count menûo',\n    'a_minute' => ':count menûo',\n\n    'second' => ':count segondo',\n    's' => ':count segondo',\n    'a_second' => ':count segondo',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/lkt.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n\n    'month' => ':count haŋwí', // less reliable\n    'm' => ':count haŋwí', // less reliable\n    'a_month' => ':count haŋwí', // less reliable\n\n    'week' => ':count šakówiŋ', // less reliable\n    'w' => ':count šakówiŋ', // less reliable\n    'a_week' => ':count šakówiŋ', // less reliable\n\n    'hour' => ':count maza škaŋškaŋ', // less reliable\n    'h' => ':count maza škaŋškaŋ', // less reliable\n    'a_hour' => ':count maza škaŋškaŋ', // less reliable\n\n    'minute' => ':count číkʼala', // less reliable\n    'min' => ':count číkʼala', // less reliable\n    'a_minute' => ':count číkʼala', // less reliable\n\n    'year' => ':count waníyetu',\n    'y' => ':count waníyetu',\n    'a_year' => ':count waníyetu',\n\n    'day' => ':count aŋpétu',\n    'd' => ':count aŋpétu',\n    'a_day' => ':count aŋpétu',\n\n    'second' => ':count icinuŋpa',\n    's' => ':count icinuŋpa',\n    'a_second' => ':count icinuŋpa',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ln.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Ubuntu René Manassé GALEKWA renemanasse@gmail.com\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'D/M/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd D MMMM YYYY HH:mm',\n    ],\n    'months' => ['sánzá ya yambo', 'sánzá ya míbalé', 'sánzá ya mísáto', 'sánzá ya mínei', 'sánzá ya mítáno', 'sánzá ya motóbá', 'sánzá ya nsambo', 'sánzá ya mwambe', 'sánzá ya libwa', 'sánzá ya zómi', 'sánzá ya zómi na mɔ̌kɔ́', 'sánzá ya zómi na míbalé'],\n    'months_short' => ['yan', 'fbl', 'msi', 'apl', 'mai', 'yun', 'yul', 'agt', 'stb', 'ɔtb', 'nvb', 'dsb'],\n    'weekdays' => ['Lomíngo', 'Mosálá mɔ̌kɔ́', 'Misálá míbalé', 'Misálá mísáto', 'Misálá mínei', 'Misálá mítáno', 'Mpɔ́sɔ'],\n    'weekdays_short' => ['m1.', 'm2.', 'm3.', 'm4.', 'm5.', 'm6.', 'm7.'],\n    'weekdays_min' => ['m1.', 'm2.', 'm3.', 'm4.', 'm5.', 'm6.', 'm7.'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n\n    'year' => 'mbula :count',\n    'y' => 'mbula :count',\n    'a_year' => 'mbula :count',\n\n    'month' => 'sánzá :count',\n    'm' => 'sánzá :count',\n    'a_month' => 'sánzá :count',\n\n    'week' => 'mpɔ́sɔ :count',\n    'w' => 'mpɔ́sɔ :count',\n    'a_week' => 'mpɔ́sɔ :count',\n\n    'day' => 'mokɔlɔ :count',\n    'd' => 'mokɔlɔ :count',\n    'a_day' => 'mokɔlɔ :count',\n\n    'hour' => 'ngonga :count',\n    'h' => 'ngonga :count',\n    'a_hour' => 'ngonga :count',\n\n    'minute' => 'miniti :count',\n    'min' => 'miniti :count',\n    'a_minute' => 'miniti :count',\n\n    'second' => 'segɔnde :count',\n    's' => 'segɔnde :count',\n    'a_second' => 'segɔnde :count',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ln_AO.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/ln.php', [\n    'weekdays' => ['eyenga', 'mokɔlɔ mwa yambo', 'mokɔlɔ mwa míbalé', 'mokɔlɔ mwa mísáto', 'mokɔlɔ ya mínéi', 'mokɔlɔ ya mítáno', 'mpɔ́sɔ'],\n    'weekdays_short' => ['eye', 'ybo', 'mbl', 'mst', 'min', 'mtn', 'mps'],\n    'weekdays_min' => ['eye', 'ybo', 'mbl', 'mst', 'min', 'mtn', 'mps'],\n    'meridiem' => ['ntɔ́ngɔ́', 'mpókwa'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ln_CD.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Ubuntu René Manassé GALEKWA renemanasse@gmail.com\n */\nreturn require __DIR__.'/ln.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ln_CF.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/ln.php', [\n    'weekdays' => ['eyenga', 'mokɔlɔ mwa yambo', 'mokɔlɔ mwa míbalé', 'mokɔlɔ mwa mísáto', 'mokɔlɔ ya mínéi', 'mokɔlɔ ya mítáno', 'mpɔ́sɔ'],\n    'weekdays_short' => ['eye', 'ybo', 'mbl', 'mst', 'min', 'mtn', 'mps'],\n    'weekdays_min' => ['eye', 'ybo', 'mbl', 'mst', 'min', 'mtn', 'mps'],\n    'meridiem' => ['ntɔ́ngɔ́', 'mpókwa'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ln_CG.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/ln.php', [\n    'weekdays' => ['eyenga', 'mokɔlɔ mwa yambo', 'mokɔlɔ mwa míbalé', 'mokɔlɔ mwa mísáto', 'mokɔlɔ ya mínéi', 'mokɔlɔ ya mítáno', 'mpɔ́sɔ'],\n    'weekdays_short' => ['eye', 'ybo', 'mbl', 'mst', 'min', 'mtn', 'mps'],\n    'weekdays_min' => ['eye', 'ybo', 'mbl', 'mst', 'min', 'mtn', 'mps'],\n    'meridiem' => ['ntɔ́ngɔ́', 'mpókwa'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/lo.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - François B\n * - ryanhart2\n */\nreturn [\n    'year' => ':count ປີ',\n    'y' => ':count ປີ',\n    'month' => ':count ເດືອນ',\n    'm' => ':count ດ. ',\n    'week' => ':count ອາທິດ',\n    'w' => ':count ອທ. ',\n    'day' => ':count ມື້',\n    'd' => ':count ມື້',\n    'hour' => ':count ຊົ່ວໂມງ',\n    'h' => ':count ຊມ. ',\n    'minute' => ':count ນາທີ',\n    'min' => ':count ນທ. ',\n    'second' => '{1}ບໍ່ເທົ່າໃດວິນາທີ|]1,Inf[:count ວິນາທີ',\n    's' => ':count ວິ. ',\n    'ago' => ':timeຜ່ານມາ',\n    'from_now' => 'ອີກ :time',\n    'diff_now' => 'ຕອນນີ້',\n    'diff_today' => 'ມື້ນີ້ເວລາ',\n    'diff_yesterday' => 'ມື້ວານນີ້ເວລາ',\n    'diff_tomorrow' => 'ມື້ອື່ນເວລາ',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'ວັນdddd D MMMM YYYY HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[ມື້ນີ້ເວລາ] LT',\n        'nextDay' => '[ມື້ອື່ນເວລາ] LT',\n        'nextWeek' => '[ວັນ]dddd[ໜ້າເວລາ] LT',\n        'lastDay' => '[ມື້ວານນີ້ເວລາ] LT',\n        'lastWeek' => '[ວັນ]dddd[ແລ້ວນີ້ເວລາ] LT',\n        'sameElse' => 'L',\n    ],\n    'ordinal' => 'ທີ່:number',\n    'meridiem' => ['ຕອນເຊົ້າ', 'ຕອນແລງ'],\n    'months' => ['ມັງກອນ', 'ກຸມພາ', 'ມີນາ', 'ເມສາ', 'ພຶດສະພາ', 'ມິຖຸນາ', 'ກໍລະກົດ', 'ສິງຫາ', 'ກັນຍາ', 'ຕຸລາ', 'ພະຈິກ', 'ທັນວາ'],\n    'months_short' => ['ມັງກອນ', 'ກຸມພາ', 'ມີນາ', 'ເມສາ', 'ພຶດສະພາ', 'ມິຖຸນາ', 'ກໍລະກົດ', 'ສິງຫາ', 'ກັນຍາ', 'ຕຸລາ', 'ພະຈິກ', 'ທັນວາ'],\n    'weekdays' => ['ອາທິດ', 'ຈັນ', 'ອັງຄານ', 'ພຸດ', 'ພະຫັດ', 'ສຸກ', 'ເສົາ'],\n    'weekdays_short' => ['ທິດ', 'ຈັນ', 'ອັງຄານ', 'ພຸດ', 'ພະຫັດ', 'ສຸກ', 'ເສົາ'],\n    'weekdays_min' => ['ທ', 'ຈ', 'ອຄ', 'ພ', 'ພຫ', 'ສກ', 'ສ'],\n    'list' => [', ', 'ແລະ '],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/lo_LA.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/lo.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/lrc.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n\n    'minute' => ':count هنر', // less reliable\n    'min' => ':count هنر', // less reliable\n    'a_minute' => ':count هنر', // less reliable\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/lrc_IQ.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/lrc.php', [\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/lt.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Philippe Vaucher\n * - Tsutomu Kuroda\n * - tjku\n * - valdas406\n * - Justas Palumickas\n * - Max Melentiev\n * - Andrius Janauskas\n * - Juanito Fatas\n * - Akira Matsuda\n * - Christopher Dell\n * - Enrique Vidal\n * - Simone Carletti\n * - Aaron Patterson\n * - Nicolás Hock Isaza\n * - Laurynas Butkus\n * - Sven Fuchs\n * - Dominykas Tijūnaitis\n * - Justinas Bolys\n * - Ričardas\n * - Kirill Chalkin\n * - Rolandas\n * - Justinas (Gamesh)\n */\nreturn [\n    'year' => ':count metai|:count metai|:count metų',\n    'y' => ':count m.',\n    'month' => ':count mėnuo|:count mėnesiai|:count mėnesį',\n    'm' => ':count mėn.',\n    'week' => ':count savaitė|:count savaitės|:count savaitę',\n    'w' => ':count sav.',\n    'day' => ':count diena|:count dienos|:count dienų',\n    'd' => ':count d.',\n    'hour' => ':count valanda|:count valandos|:count valandų',\n    'h' => ':count val.',\n    'minute' => ':count minutė|:count minutės|:count minutę',\n    'min' => ':count min.',\n    'second' => ':count sekundė|:count sekundės|:count sekundžių',\n    's' => ':count sek.',\n\n    'year_ago' => ':count metus|:count metus|:count metų',\n    'month_ago' => ':count mėnesį|:count mėnesius|:count mėnesių',\n    'week_ago' => ':count savaitę|:count savaites|:count savaičių',\n    'day_ago' => ':count dieną|:count dienas|:count dienų',\n    'hour_ago' => ':count valandą|:count valandas|:count valandų',\n    'minute_ago' => ':count minutę|:count minutes|:count minučių',\n    'second_ago' => ':count sekundę|:count sekundes|:count sekundžių',\n\n    'year_from_now' => ':count metų',\n    'month_from_now' => ':count mėnesio|:count mėnesių|:count mėnesių',\n    'week_from_now' => ':count savaitės|:count savaičių|:count savaičių',\n    'day_from_now' => ':count dienos|:count dienų|:count dienų',\n    'hour_from_now' => ':count valandos|:count valandų|:count valandų',\n    'minute_from_now' => ':count minutės|:count minučių|:count minučių',\n    'second_from_now' => ':count sekundės|:count sekundžių|:count sekundžių',\n\n    'year_after' => ':count metų',\n    'month_after' => ':count mėnesio|:count mėnesių|:count mėnesių',\n    'week_after' => ':count savaitės|:count savaičių|:count savaičių',\n    'day_after' => ':count dienos|:count dienų|:count dienų',\n    'hour_after' => ':count valandos|:count valandų|:count valandų',\n    'minute_after' => ':count minutės|:count minučių|:count minučių',\n    'second_after' => ':count sekundės|:count sekundžių|:count sekundžių',\n\n    'ago' => 'prieš :time',\n    'from_now' => ':time nuo dabar',\n    'after' => 'po :time',\n    'before' => 'už :time',\n\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n\n    'diff_now' => 'ką tik',\n    'diff_today' => 'Šiandien',\n    'diff_yesterday' => 'vakar',\n    'diff_yesterday_regexp' => 'Vakar',\n    'diff_tomorrow' => 'rytoj',\n    'diff_tomorrow_regexp' => 'Rytoj',\n    'diff_before_yesterday' => 'užvakar',\n    'diff_after_tomorrow' => 'poryt',\n\n    'period_recurrences' => 'kartą|:count kartų',\n    'period_interval' => 'kiekvieną :interval',\n    'period_start_date' => 'nuo :date',\n    'period_end_date' => 'iki :date',\n\n    'months' => ['sausio', 'vasario', 'kovo', 'balandžio', 'gegužės', 'birželio', 'liepos', 'rugpjūčio', 'rugsėjo', 'spalio', 'lapkričio', 'gruodžio'],\n    'months_standalone' => ['sausis', 'vasaris', 'kovas', 'balandis', 'gegužė', 'birželis', 'liepa', 'rugpjūtis', 'rugsėjis', 'spalis', 'lapkritis', 'gruodis'],\n    'months_regexp' => '/(L{2,4}|D[oD]?(\\[[^\\[\\]]*\\]|\\s)+MMMM?|MMMM?(\\[[^\\[\\]]*\\]|\\s)+D[oD]?)/',\n    'months_short' => ['sau', 'vas', 'kov', 'bal', 'geg', 'bir', 'lie', 'rgp', 'rgs', 'spa', 'lap', 'gru'],\n    'weekdays' => ['sekmadienį', 'pirmadienį', 'antradienį', 'trečiadienį', 'ketvirtadienį', 'penktadienį', 'šeštadienį'],\n    'weekdays_standalone' => ['sekmadienis', 'pirmadienis', 'antradienis', 'trečiadienis', 'ketvirtadienis', 'penktadienis', 'šeštadienis'],\n    'weekdays_short' => ['sek', 'pir', 'ant', 'tre', 'ket', 'pen', 'šeš'],\n    'weekdays_min' => ['se', 'pi', 'an', 'tr', 'ke', 'pe', 'še'],\n    'list' => [', ', ' ir '],\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'YYYY-MM-DD',\n        'LL' => 'MMMM DD, YYYY',\n        'LLL' => 'DD MMM HH:mm',\n        'LLLL' => 'MMMM DD, YYYY HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[Šiandien] LT',\n        'nextDay' => '[Rytoj] LT',\n        'nextWeek' => 'dddd LT',\n        'lastDay' => '[Vakar] LT',\n        'lastWeek' => '[Paskutinį] dddd LT',\n        'sameElse' => 'L',\n    ],\n    'ordinal' => function ($number) {\n        switch ($number) {\n            case 0:\n                return '0-is';\n            case 3:\n                return '3-ias';\n            default:\n                return \"$number-as\";\n        }\n    },\n    'meridiem' => ['priešpiet', 'popiet'],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/lt_LT.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/lt.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/lu.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'meridiem' => ['Dinda', 'Dilolo'],\n    'weekdays' => ['Lumingu', 'Nkodya', 'Ndàayà', 'Ndangù', 'Njòwa', 'Ngòvya', 'Lubingu'],\n    'weekdays_short' => ['Lum', 'Nko', 'Ndy', 'Ndg', 'Njw', 'Ngv', 'Lub'],\n    'weekdays_min' => ['Lum', 'Nko', 'Ndy', 'Ndg', 'Njw', 'Ngv', 'Lub'],\n    'months' => ['Ciongo', 'Lùishi', 'Lusòlo', 'Mùuyà', 'Lumùngùlù', 'Lufuimi', 'Kabàlàshìpù', 'Lùshìkà', 'Lutongolo', 'Lungùdi', 'Kaswèkèsè', 'Ciswà'],\n    'months_short' => ['Cio', 'Lui', 'Lus', 'Muu', 'Lum', 'Luf', 'Kab', 'Lush', 'Lut', 'Lun', 'Kas', 'Cis'],\n    'first_day_of_week' => 1,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'D/M/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd D MMMM YYYY HH:mm',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/luo.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'meridiem' => ['OD', 'OT'],\n    'weekdays' => ['Jumapil', 'Wuok Tich', 'Tich Ariyo', 'Tich Adek', 'Tich Ang’wen', 'Tich Abich', 'Ngeso'],\n    'weekdays_short' => ['JMP', 'WUT', 'TAR', 'TAD', 'TAN', 'TAB', 'NGS'],\n    'weekdays_min' => ['JMP', 'WUT', 'TAR', 'TAD', 'TAN', 'TAB', 'NGS'],\n    'months' => ['Dwe mar Achiel', 'Dwe mar Ariyo', 'Dwe mar Adek', 'Dwe mar Ang’wen', 'Dwe mar Abich', 'Dwe mar Auchiel', 'Dwe mar Abiriyo', 'Dwe mar Aboro', 'Dwe mar Ochiko', 'Dwe mar Apar', 'Dwe mar gi achiel', 'Dwe mar Apar gi ariyo'],\n    'months_short' => ['DAC', 'DAR', 'DAD', 'DAN', 'DAH', 'DAU', 'DAO', 'DAB', 'DOC', 'DAP', 'DGI', 'DAG'],\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY HH:mm',\n    ],\n\n    'year' => 'higni :count',\n    'y' => 'higni :count',\n    'a_year' => ':higni :count',\n\n    'month' => 'dweche :count',\n    'm' => 'dweche :count',\n    'a_month' => 'dweche :count',\n\n    'week' => 'jumbe :count',\n    'w' => 'jumbe :count',\n    'a_week' => 'jumbe :count',\n\n    'day' => 'ndalo :count',\n    'd' => 'ndalo :count',\n    'a_day' => 'ndalo :count',\n\n    'hour' => 'seche :count',\n    'h' => 'seche :count',\n    'a_hour' => 'seche :count',\n\n    'minute' => 'dakika :count',\n    'min' => 'dakika :count',\n    'a_minute' => 'dakika :count',\n\n    'second' => 'nus dakika :count',\n    's' => 'nus dakika :count',\n    'a_second' => 'nus dakika :count',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/luy.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'weekdays' => ['Jumapiri', 'Jumatatu', 'Jumanne', 'Jumatano', 'Murwa wa Kanne', 'Murwa wa Katano', 'Jumamosi'],\n    'weekdays_short' => ['J2', 'J3', 'J4', 'J5', 'Al', 'Ij', 'J1'],\n    'weekdays_min' => ['J2', 'J3', 'J4', 'J5', 'Al', 'Ij', 'J1'],\n    'months' => ['Januari', 'Februari', 'Machi', 'Aprili', 'Mei', 'Juni', 'Julai', 'Agosti', 'Septemba', 'Oktoba', 'Novemba', 'Desemba'],\n    'months_short' => ['Jan', 'Feb', 'Mar', 'Apr', 'Mei', 'Jun', 'Jul', 'Ago', 'Sep', 'Okt', 'Nov', 'Des'],\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY HH:mm',\n    ],\n\n    // Too unreliable\n    /*\n    'year' => ':count liliino', // less reliable\n    'y' => ':count liliino', // less reliable\n    'a_year' => ':count liliino', // less reliable\n\n    'month' => ':count kumwesi', // less reliable\n    'm' => ':count kumwesi', // less reliable\n    'a_month' => ':count kumwesi', // less reliable\n\n    'week' => ':count olutambi', // less reliable\n    'w' => ':count olutambi', // less reliable\n    'a_week' => ':count olutambi', // less reliable\n\n    'day' => ':count luno', // less reliable\n    'd' => ':count luno', // less reliable\n    'a_day' => ':count luno', // less reliable\n\n    'hour' => ':count ekengele', // less reliable\n    'h' => ':count ekengele', // less reliable\n    'a_hour' => ':count ekengele', // less reliable\n\n    'minute' => ':count omundu', // less reliable\n    'min' => ':count omundu', // less reliable\n    'a_minute' => ':count omundu', // less reliable\n\n    'second' => ':count liliino', // less reliable\n    's' => ':count liliino', // less reliable\n    'a_second' => ':count liliino', // less reliable\n    */\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/lv.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nuse Carbon\\CarbonInterface;\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Philippe Vaucher\n * - pirminis\n * - Tsutomu Kuroda\n * - tjku\n * - Andris Zāģeris\n * - Max Melentiev\n * - Edgars Beigarts\n * - Juanito Fatas\n * - Vitauts Stočka\n * - Akira Matsuda\n * - Christopher Dell\n * - Enrique Vidal\n * - Simone Carletti\n * - Aaron Patterson\n * - Kaspars Bankovskis\n * - Nicolás Hock Isaza\n * - Viesturs Kavacs (Kavacky)\n * - zakse\n * - Janis Eglitis (janiseglitis)\n * - Guntars\n * - Juris Sudmalis\n */\n$daysOfWeek = ['svētdiena', 'pirmdiena', 'otrdiena', 'trešdiena', 'ceturtdiena', 'piektdiena', 'sestdiena'];\n$daysOfWeekLocativum = ['svētdien', 'pirmdien', 'otrdien', 'trešdien', 'ceturtdien', 'piektdien', 'sestdien'];\n\n$transformDiff = function ($input) {\n    return strtr($input, [\n        // Nominative => \"pirms/pēc\" Dative\n        'gads' => 'gada',\n        'gadi' => 'gadiem',\n        'gadu' => 'gadiem',\n        'mēnesis' => 'mēneša',\n        'mēneši' => 'mēnešiem',\n        'mēnešu' => 'mēnešiem',\n        'nedēļa' => 'nedēļas',\n        'nedēļas' => 'nedēļām',\n        'nedēļu' => 'nedēļām',\n        'diena' => 'dienas',\n        'dienas' => 'dienām',\n        'dienu' => 'dienām',\n        'stunda' => 'stundas',\n        'stundas' => 'stundām',\n        'stundu' => 'stundām',\n        'minūte' => 'minūtes',\n        'minūtes' => 'minūtēm',\n        'minūšu' => 'minūtēm',\n        'sekunde' => 'sekundes',\n        'sekundes' => 'sekundēm',\n        'sekunžu' => 'sekundēm',\n    ]);\n};\n\nreturn [\n    'ago' => function ($time) use ($transformDiff) {\n        return 'pirms '.$transformDiff($time);\n    },\n    'from_now' => function ($time) use ($transformDiff) {\n        return 'pēc '.$transformDiff($time);\n    },\n\n    'year' => '0 gadu|:count gads|:count gadi',\n    'y' => ':count g.',\n    'a_year' => '{1}gads|0 gadu|:count gads|:count gadi',\n    'month' => '0 mēnešu|:count mēnesis|:count mēneši',\n    'm' => ':count mēn.',\n    'a_month' => '{1}mēnesis|0 mēnešu|:count mēnesis|:count mēneši',\n    'week' => '0 nedēļu|:count nedēļa|:count nedēļas',\n    'w' => ':count ned.',\n    'a_week' => '{1}nedēļa|0 nedēļu|:count nedēļa|:count nedēļas',\n    'day' => '0 dienu|:count diena|:count dienas',\n    'd' => ':count d.',\n    'a_day' => '{1}diena|0 dienu|:count diena|:count dienas',\n    'hour' => '0 stundu|:count stunda|:count stundas',\n    'h' => ':count st.',\n    'a_hour' => '{1}stunda|0 stundu|:count stunda|:count stundas',\n    'minute' => '0 minūšu|:count minūte|:count minūtes',\n    'min' => ':count min.',\n    'a_minute' => '{1}minūte|0 minūšu|:count minūte|:count minūtes',\n    'second' => '0 sekunžu|:count sekunde|:count sekundes',\n    's' => ':count sek.',\n    'a_second' => '{1}sekunde|0 sekunžu|:count sekunde|:count sekundes',\n\n    'after' => ':time vēlāk',\n    'year_after' => '0 gadus|:count gadu|:count gadus',\n    'a_year_after' => '{1}gadu|0 gadus|:count gadu|:count gadus',\n    'month_after' => '0 mēnešus|:count mēnesi|:count mēnešus',\n    'a_month_after' => '{1}mēnesi|0 mēnešus|:count mēnesi|:count mēnešus',\n    'week_after' => '0 nedēļas|:count nedēļu|:count nedēļas',\n    'a_week_after' => '{1}nedēļu|0 nedēļas|:count nedēļu|:count nedēļas',\n    'day_after' => '0 dienas|:count dienu|:count dienas',\n    'a_day_after' => '{1}dienu|0 dienas|:count dienu|:count dienas',\n    'hour_after' => '0 stundas|:count stundu|:count stundas',\n    'a_hour_after' => '{1}stundu|0 stundas|:count stundu|:count stundas',\n    'minute_after' => '0 minūtes|:count minūti|:count minūtes',\n    'a_minute_after' => '{1}minūti|0 minūtes|:count minūti|:count minūtes',\n    'second_after' => '0 sekundes|:count sekundi|:count sekundes',\n    'a_second_after' => '{1}sekundi|0 sekundes|:count sekundi|:count sekundes',\n\n    'before' => ':time agrāk',\n    'year_before' => '0 gadus|:count gadu|:count gadus',\n    'a_year_before' => '{1}gadu|0 gadus|:count gadu|:count gadus',\n    'month_before' => '0 mēnešus|:count mēnesi|:count mēnešus',\n    'a_month_before' => '{1}mēnesi|0 mēnešus|:count mēnesi|:count mēnešus',\n    'week_before' => '0 nedēļas|:count nedēļu|:count nedēļas',\n    'a_week_before' => '{1}nedēļu|0 nedēļas|:count nedēļu|:count nedēļas',\n    'day_before' => '0 dienas|:count dienu|:count dienas',\n    'a_day_before' => '{1}dienu|0 dienas|:count dienu|:count dienas',\n    'hour_before' => '0 stundas|:count stundu|:count stundas',\n    'a_hour_before' => '{1}stundu|0 stundas|:count stundu|:count stundas',\n    'minute_before' => '0 minūtes|:count minūti|:count minūtes',\n    'a_minute_before' => '{1}minūti|0 minūtes|:count minūti|:count minūtes',\n    'second_before' => '0 sekundes|:count sekundi|:count sekundes',\n    'a_second_before' => '{1}sekundi|0 sekundes|:count sekundi|:count sekundes',\n\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n    'list' => [', ', ' un '],\n\n    'diff_now' => 'tagad',\n    'diff_today' => 'šodien',\n    'diff_yesterday' => 'vakar',\n    'diff_before_yesterday' => 'aizvakar',\n    'diff_tomorrow' => 'rīt',\n    'diff_after_tomorrow' => 'parīt',\n\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD.MM.YYYY.',\n        'LL' => 'YYYY. [gada] D. MMMM',\n        'LLL' => 'DD.MM.YYYY., HH:mm',\n        'LLLL' => 'YYYY. [gada] D. MMMM, HH:mm',\n    ],\n\n    'calendar' => [\n        'sameDay' => '[šodien] [plkst.] LT',\n        'nextDay' => '[rīt] [plkst.] LT',\n        'nextWeek' => function (CarbonInterface $current, CarbonInterface $other) use ($daysOfWeekLocativum) {\n            if ($current->week !== $other->week) {\n                return '[nākošo] ['.$daysOfWeekLocativum[$current->dayOfWeek].'] [plkst.] LT';\n            }\n\n            return '['.$daysOfWeekLocativum[$current->dayOfWeek].'] [plkst.] LT';\n        },\n        'lastDay' => '[vakar] [plkst.] LT',\n        'lastWeek' => function (CarbonInterface $current) use ($daysOfWeekLocativum) {\n            return '[pagājušo] ['.$daysOfWeekLocativum[$current->dayOfWeek].'] [plkst.] LT';\n        },\n        'sameElse' => 'L',\n    ],\n\n    'weekdays' => $daysOfWeek,\n    'weekdays_short' => ['Sv.', 'P.', 'O.', 'T.', 'C.', 'Pk.', 'S.'],\n    'weekdays_min' => ['Sv.', 'P.', 'O.', 'T.', 'C.', 'Pk.', 'S.'],\n    'months' => ['janvāris', 'februāris', 'marts', 'aprīlis', 'maijs', 'jūnijs', 'jūlijs', 'augusts', 'septembris', 'oktobris', 'novembris', 'decembris'],\n    'months_standalone' => ['janvārī', 'februārī', 'martā', 'aprīlī', 'maijā', 'jūnijā', 'jūlijā', 'augustā', 'septembrī', 'oktobrī', 'novembrī', 'decembrī'],\n    'months_short' => ['janv.', 'febr.', 'martā', 'apr.', 'maijā', 'jūn.', 'jūl.', 'aug.', 'sept.', 'okt.', 'nov.', 'dec.'],\n    'meridiem' => ['priekšpusdiena', 'pēcpusdiena'],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/lv_LV.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/lv.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/lzh.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/lzh_TW.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/lzh_TW.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'OY[年]MMMMOD[日]',\n    ],\n    'months' => ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'],\n    'months_short' => [' 一 ', ' 二 ', ' 三 ', ' 四 ', ' 五 ', ' 六 ', ' 七 ', ' 八 ', ' 九 ', ' 十 ', '十一', '十二'],\n    'weekdays' => ['週日', '週一', '週二', '週三', '週四', '週五', '週六'],\n    'weekdays_short' => ['日', '一', '二', '三', '四', '五', '六'],\n    'weekdays_min' => ['日', '一', '二', '三', '四', '五', '六'],\n    'day_of_first_week_of_year' => 1,\n    'alt_numbers' => ['〇', '一', '二', '三', '四', '五', '六', '七', '八', '九', '十', '十一', '十二', '十三', '十四', '十五', '十六', '十七', '十八', '十九', '廿', '廿一', '廿二', '廿三', '廿四', '廿五', '廿六', '廿七', '廿八', '廿九', '卅', '卅一'],\n    'meridiem' => ['朝', '暮'],\n\n    'year' => ':count 夏', // less reliable\n    'y' => ':count 夏', // less reliable\n    'a_year' => ':count 夏', // less reliable\n\n    'month' => ':count 月', // less reliable\n    'm' => ':count 月', // less reliable\n    'a_month' => ':count 月', // less reliable\n\n    'hour' => ':count 氧', // less reliable\n    'h' => ':count 氧', // less reliable\n    'a_hour' => ':count 氧', // less reliable\n\n    'minute' => ':count 點', // less reliable\n    'min' => ':count 點', // less reliable\n    'a_minute' => ':count 點', // less reliable\n\n    'second' => ':count 楚', // less reliable\n    's' => ':count 楚', // less reliable\n    'a_second' => ':count 楚', // less reliable\n\n    'week' => ':count 星期',\n    'w' => ':count 星期',\n    'a_week' => ':count 星期',\n\n    'day' => ':count 日(曆法)',\n    'd' => ':count 日(曆法)',\n    'a_day' => ':count 日(曆法)',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/mag.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/mag_IN.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/mag_IN.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - bhashaghar@googlegroups.com\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'D/M/YY',\n    ],\n    'months' => ['जनवरी', 'फ़रवरी', 'मार्च', 'अप्रेल', 'मई', 'जून', 'जुलाई', 'अगस्त', 'सितम्बर', 'अक्टूबर', 'नवम्बर', 'दिसम्बर'],\n    'months_short' => ['जनवरी', 'फ़रवरी', 'मार्च', 'अप्रेल', 'मई', 'जून', 'जुलाई', 'अगस्त', 'सितम्बर', 'अक्टूबर', 'नवम्बर', 'दिसम्बर'],\n    'weekdays' => ['एतवार', 'सोमार', 'मंगर', 'बुध', 'बिफे', 'सूक', 'सनिचर'],\n    'weekdays_short' => ['एतवार', 'सोमार', 'मंगर', 'बुध', 'बिफे', 'सूक', 'सनिचर'],\n    'weekdays_min' => ['एतवार', 'सोमार', 'मंगर', 'बुध', 'बिफे', 'सूक', 'सनिचर'],\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['पूर्वाह्न', 'अपराह्न'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/mai.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/mai_IN.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/mai_IN.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Maithili Computing Research Center, Pune, India    rajeshkajha@yahoo.com,akhilesh.k@samusng.com\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'D/M/YY',\n    ],\n    'months' => ['बैसाख', 'जेठ', 'अषाढ़', 'सावोन', 'भादो', 'आसिन', 'कातिक', 'अगहन', 'पूस', 'माघ', 'फागुन', 'चैति'],\n    'months_short' => ['बैसाख', 'जेठ', 'अषाढ़', 'सावोन', 'भादो', 'आसिन', 'कातिक', 'अगहन', 'पूस', 'माघ', 'फागुन', 'चैति'],\n    'weekdays' => ['रविदिन', 'सोमदिन', 'मंगलदिन', 'बुधदिन', 'बृहस्पतीदिन', 'शुक्रदिन', 'शनीदिन'],\n    'weekdays_short' => ['रवि', 'सोम', 'मंगल', 'बुध', 'बृहस्पती', 'शुक्र', 'शनी'],\n    'weekdays_min' => ['रवि', 'सोम', 'मंगल', 'बुध', 'बृहस्पती', 'शुक्र', 'शनी'],\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['पूर्वाह्न', 'अपराह्न'],\n\n    'year' => ':count ऋतु', // less reliable\n    'y' => ':count ऋतु', // less reliable\n    'a_year' => ':count ऋतु', // less reliable\n\n    'month' => ':count महिना',\n    'm' => ':count महिना',\n    'a_month' => ':count महिना',\n\n    'week' => ':count श्रेणी:क्यालेन्डर', // less reliable\n    'w' => ':count श्रेणी:क्यालेन्डर', // less reliable\n    'a_week' => ':count श्रेणी:क्यालेन्डर', // less reliable\n\n    'day' => ':count दिन',\n    'd' => ':count दिन',\n    'a_day' => ':count दिन',\n\n    'hour' => ':count घण्टा',\n    'h' => ':count घण्टा',\n    'a_hour' => ':count घण्टा',\n\n    'minute' => ':count समय', // less reliable\n    'min' => ':count समय', // less reliable\n    'a_minute' => ':count समय', // less reliable\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/mas.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'meridiem' => ['Ɛnkakɛnyá', 'Ɛndámâ'],\n    'weekdays' => ['Jumapílí', 'Jumatátu', 'Jumane', 'Jumatánɔ', 'Alaámisi', 'Jumáa', 'Jumamósi'],\n    'weekdays_short' => ['Jpi', 'Jtt', 'Jnn', 'Jtn', 'Alh', 'Iju', 'Jmo'],\n    'weekdays_min' => ['Jpi', 'Jtt', 'Jnn', 'Jtn', 'Alh', 'Iju', 'Jmo'],\n    'months' => ['Oladalʉ́', 'Arát', 'Ɔɛnɨ́ɔɨŋɔk', 'Olodoyíóríê inkókúâ', 'Oloilépūnyīē inkókúâ', 'Kújúɔrɔk', 'Mórusásin', 'Ɔlɔ́ɨ́bɔ́rárɛ', 'Kúshîn', 'Olgísan', 'Pʉshʉ́ka', 'Ntʉ́ŋʉ́s'],\n    'months_short' => ['Dal', 'Ará', 'Ɔɛn', 'Doy', 'Lép', 'Rok', 'Sás', 'Bɔ́r', 'Kús', 'Gís', 'Shʉ́', 'Ntʉ́'],\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY HH:mm',\n    ],\n\n    'year' => ':count olameyu', // less reliable\n    'y' => ':count olameyu', // less reliable\n    'a_year' => ':count olameyu', // less reliable\n\n    'week' => ':count engolongeare orwiki', // less reliable\n    'w' => ':count engolongeare orwiki', // less reliable\n    'a_week' => ':count engolongeare orwiki', // less reliable\n\n    'hour' => ':count esahabu', // less reliable\n    'h' => ':count esahabu', // less reliable\n    'a_hour' => ':count esahabu', // less reliable\n\n    'second' => ':count are', // less reliable\n    's' => ':count are', // less reliable\n    'a_second' => ':count are', // less reliable\n\n    'month' => ':count olapa',\n    'm' => ':count olapa',\n    'a_month' => ':count olapa',\n\n    'day' => ':count enkolongʼ',\n    'd' => ':count enkolongʼ',\n    'a_day' => ':count enkolongʼ',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/mas_TZ.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/mas.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/mer.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'meridiem' => ['RŨ', 'ŨG'],\n    'weekdays' => ['Kiumia', 'Muramuko', 'Wairi', 'Wethatu', 'Wena', 'Wetano', 'Jumamosi'],\n    'weekdays_short' => ['KIU', 'MRA', 'WAI', 'WET', 'WEN', 'WTN', 'JUM'],\n    'weekdays_min' => ['KIU', 'MRA', 'WAI', 'WET', 'WEN', 'WTN', 'JUM'],\n    'months' => ['Januarĩ', 'Feburuarĩ', 'Machi', 'Ĩpurũ', 'Mĩĩ', 'Njuni', 'Njuraĩ', 'Agasti', 'Septemba', 'Oktũba', 'Novemba', 'Dicemba'],\n    'months_short' => ['JAN', 'FEB', 'MAC', 'ĨPU', 'MĨĨ', 'NJU', 'NJR', 'AGA', 'SPT', 'OKT', 'NOV', 'DEC'],\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY HH:mm',\n    ],\n\n    'year' => ':count murume', // less reliable\n    'y' => ':count murume', // less reliable\n    'a_year' => ':count murume', // less reliable\n\n    'month' => ':count muchaara', // less reliable\n    'm' => ':count muchaara', // less reliable\n    'a_month' => ':count muchaara', // less reliable\n\n    'minute' => ':count monto', // less reliable\n    'min' => ':count monto', // less reliable\n    'a_minute' => ':count monto', // less reliable\n\n    'second' => ':count gikeno', // less reliable\n    's' => ':count gikeno', // less reliable\n    'a_second' => ':count gikeno', // less reliable\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/mfe.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/mfe_MU.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/mfe_MU.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Samsung Electronics Co., Ltd.    akhilesh.k@samsung.com\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD/MM/YY',\n    ],\n    'months' => ['zanvie', 'fevriye', 'mars', 'avril', 'me', 'zin', 'zilye', 'out', 'septam', 'oktob', 'novam', 'desam'],\n    'months_short' => ['zan', 'fev', 'mar', 'avr', 'me', 'zin', 'zil', 'out', 'sep', 'okt', 'nov', 'des'],\n    'weekdays' => ['dimans', 'lindi', 'mardi', 'merkredi', 'zedi', 'vandredi', 'samdi'],\n    'weekdays_short' => ['dim', 'lin', 'mar', 'mer', 'ze', 'van', 'sam'],\n    'weekdays_min' => ['dim', 'lin', 'mar', 'mer', 'ze', 'van', 'sam'],\n\n    'year' => ':count banané',\n    'y' => ':count banané',\n    'a_year' => ':count banané',\n\n    'month' => ':count mwa',\n    'm' => ':count mwa',\n    'a_month' => ':count mwa',\n\n    'week' => ':count sémenn',\n    'w' => ':count sémenn',\n    'a_week' => ':count sémenn',\n\n    'day' => ':count zour',\n    'd' => ':count zour',\n    'a_day' => ':count zour',\n\n    'hour' => ':count -er-tan',\n    'h' => ':count -er-tan',\n    'a_hour' => ':count -er-tan',\n\n    'minute' => ':count minitt',\n    'min' => ':count minitt',\n    'a_minute' => ':count minitt',\n\n    'second' => ':count déziém',\n    's' => ':count déziém',\n    'a_second' => ':count déziém',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/mg.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/mg_MG.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/mg_MG.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - The Debian Project modified by GNU//Linux Malagasy Rado Ramarotafika,Do-Risika RAFIEFERANTSIARONJY rado@linuxmg.org,dourix@free.fr\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD.MM.YYYY',\n    ],\n    'months' => ['Janoary', 'Febroary', 'Martsa', 'Aprily', 'Mey', 'Jona', 'Jolay', 'Aogositra', 'Septambra', 'Oktobra', 'Novambra', 'Desambra'],\n    'months_short' => ['Jan', 'Feb', 'Mar', 'Apr', 'Mey', 'Jon', 'Jol', 'Aog', 'Sep', 'Okt', 'Nov', 'Des'],\n    'weekdays' => ['alahady', 'alatsinainy', 'talata', 'alarobia', 'alakamisy', 'zoma', 'sabotsy'],\n    'weekdays_short' => ['lhd', 'lts', 'tlt', 'lrb', 'lkm', 'zom', 'sab'],\n    'weekdays_min' => ['lhd', 'lts', 'tlt', 'lrb', 'lkm', 'zom', 'sab'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n\n    'minute' => ':count minitra', // less reliable\n    'min' => ':count minitra', // less reliable\n    'a_minute' => ':count minitra', // less reliable\n\n    'year' => ':count taona',\n    'y' => ':count taona',\n    'a_year' => ':count taona',\n\n    'month' => ':count volana',\n    'm' => ':count volana',\n    'a_month' => ':count volana',\n\n    'week' => ':count herinandro',\n    'w' => ':count herinandro',\n    'a_week' => ':count herinandro',\n\n    'day' => ':count andro',\n    'd' => ':count andro',\n    'a_day' => ':count andro',\n\n    'hour' => ':count ora',\n    'h' => ':count ora',\n    'a_hour' => ':count ora',\n\n    'second' => ':count segondra',\n    's' => ':count segondra',\n    'a_second' => ':count segondra',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/mgh.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'meridiem' => ['wichishu', 'mchochil’l'],\n    'weekdays' => ['Sabato', 'Jumatatu', 'Jumanne', 'Jumatano', 'Arahamisi', 'Ijumaa', 'Jumamosi'],\n    'weekdays_short' => ['Sab', 'Jtt', 'Jnn', 'Jtn', 'Ara', 'Iju', 'Jmo'],\n    'weekdays_min' => ['Sab', 'Jtt', 'Jnn', 'Jtn', 'Ara', 'Iju', 'Jmo'],\n    'months' => ['Mweri wo kwanza', 'Mweri wo unayeli', 'Mweri wo uneraru', 'Mweri wo unecheshe', 'Mweri wo unethanu', 'Mweri wo thanu na mocha', 'Mweri wo saba', 'Mweri wo nane', 'Mweri wo tisa', 'Mweri wo kumi', 'Mweri wo kumi na moja', 'Mweri wo kumi na yel’li'],\n    'months_short' => ['Kwa', 'Una', 'Rar', 'Che', 'Tha', 'Moc', 'Sab', 'Nan', 'Tis', 'Kum', 'Moj', 'Yel'],\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY HH:mm',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/mgo.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'weekdays' => ['Aneg 1', 'Aneg 2', 'Aneg 3', 'Aneg 4', 'Aneg 5', 'Aneg 6', 'Aneg 7'],\n    'weekdays_short' => ['Aneg 1', 'Aneg 2', 'Aneg 3', 'Aneg 4', 'Aneg 5', 'Aneg 6', 'Aneg 7'],\n    'weekdays_min' => ['1', '2', '3', '4', '5', '6', '7'],\n    'months' => ['iməg mbegtug', 'imeg àbùbì', 'imeg mbəŋchubi', 'iməg ngwə̀t', 'iməg fog', 'iməg ichiibɔd', 'iməg àdùmbə̀ŋ', 'iməg ichika', 'iməg kud', 'iməg tèsiʼe', 'iməg zò', 'iməg krizmed'],\n    'months_short' => ['mbegtug', 'imeg àbùbì', 'imeg mbəŋchubi', 'iməg ngwə̀t', 'iməg fog', 'iməg ichiibɔd', 'iməg àdùmbə̀ŋ', 'iməg ichika', 'iməg kud', 'iməg tèsiʼe', 'iməg zò', 'iməg krizmed'],\n    'first_day_of_week' => 1,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'YYYY-MM-dd',\n        'LL' => 'YYYY MMM D',\n        'LLL' => 'YYYY MMMM D HH:mm',\n        'LLLL' => 'dddd, YYYY MMMM DD HH:mm',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/mhr.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/mhr_RU.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/mhr_RU.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - PeshSajSoft Ltd. Vyacheslav Kileev slavakileev@yandex.ru\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'YYYY.MM.DD',\n    ],\n    'months' => ['Шорыкйол', 'Пургыж', 'Ӱярня', 'Вӱдшор', 'Ага', 'Пеледыш', 'Сӱрем', 'Сорла', 'Идым', 'Шыжа', 'Кылме', 'Теле'],\n    'months_short' => ['Шрк', 'Пгж', 'Ӱрн', 'Вшр', 'Ага', 'Пдш', 'Срм', 'Срл', 'Идм', 'Шыж', 'Клм', 'Тел'],\n    'weekdays' => ['Рушарня', 'Шочмо', 'Кушкыжмо', 'Вӱргече', 'Изарня', 'Кугарня', 'Шуматкече'],\n    'weekdays_short' => ['Ршр', 'Шчм', 'Кжм', 'Вгч', 'Изр', 'Кгр', 'Шмт'],\n    'weekdays_min' => ['Ршр', 'Шчм', 'Кжм', 'Вгч', 'Изр', 'Кгр', 'Шмт'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n\n    'year' => ':count идалык',\n    'y' => ':count идалык',\n    'a_year' => ':count идалык',\n\n    'month' => ':count Тылзе',\n    'm' => ':count Тылзе',\n    'a_month' => ':count Тылзе',\n\n    'week' => ':count арня',\n    'w' => ':count арня',\n    'a_week' => ':count арня',\n\n    'day' => ':count кече',\n    'd' => ':count кече',\n    'a_day' => ':count кече',\n\n    'hour' => ':count час',\n    'h' => ':count час',\n    'a_hour' => ':count час',\n\n    'minute' => ':count минут',\n    'min' => ':count минут',\n    'a_minute' => ':count минут',\n\n    'second' => ':count кокымшан',\n    's' => ':count кокымшан',\n    'a_second' => ':count кокымшан',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/mi.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - François B\n * - John Corrigan\n * - François B\n */\nreturn [\n    'year' => ':count tau',\n    'a_year' => '{1}he tau|:count tau',\n    'month' => ':count marama',\n    'a_month' => '{1}he marama|:count marama',\n    'week' => ':count wiki',\n    'a_week' => '{1}he wiki|:count wiki',\n    'day' => ':count ra',\n    'a_day' => '{1}he ra|:count ra',\n    'hour' => ':count haora',\n    'a_hour' => '{1}te haora|:count haora',\n    'minute' => ':count meneti',\n    'a_minute' => '{1}he meneti|:count meneti',\n    'second' => ':count hēkona',\n    'a_second' => '{1}te hēkona ruarua|:count hēkona',\n    'ago' => ':time i mua',\n    'from_now' => 'i roto i :time',\n    'diff_yesterday' => 'inanahi',\n    'diff_yesterday_regexp' => 'inanahi(?:\\\\s+i)?',\n    'diff_today' => 'i teie',\n    'diff_today_regexp' => 'i teie(?:\\\\s+mahana,)?(?:\\\\s+i)?',\n    'diff_tomorrow' => 'apopo',\n    'diff_tomorrow_regexp' => 'apopo(?:\\\\s+i)?',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY [i] HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY [i] HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[i teie mahana, i] LT',\n        'nextDay' => '[apopo i] LT',\n        'nextWeek' => 'dddd [i] LT',\n        'lastDay' => '[inanahi i] LT',\n        'lastWeek' => 'dddd [whakamutunga i] LT',\n        'sameElse' => 'L',\n    ],\n    'ordinal' => ':numberº',\n    'months' => ['Kohi-tāte', 'Hui-tanguru', 'Poutū-te-rangi', 'Paenga-whāwhā', 'Haratua', 'Pipiri', 'Hōngoingoi', 'Here-turi-kōkā', 'Mahuru', 'Whiringa-ā-nuku', 'Whiringa-ā-rangi', 'Hakihea'],\n    'months_short' => ['Kohi', 'Hui', 'Pou', 'Pae', 'Hara', 'Pipi', 'Hōngoi', 'Here', 'Mahu', 'Whi-nu', 'Whi-ra', 'Haki'],\n    'weekdays' => ['Rātapu', 'Mane', 'Tūrei', 'Wenerei', 'Tāite', 'Paraire', 'Hātarei'],\n    'weekdays_short' => ['Ta', 'Ma', 'Tū', 'We', 'Tāi', 'Pa', 'Hā'],\n    'weekdays_min' => ['Ta', 'Ma', 'Tū', 'We', 'Tāi', 'Pa', 'Hā'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n    'list' => [', ', ' me te '],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/mi_NZ.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/mi.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/miq.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/miq_NI.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/miq_NI.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD/MM/YY',\n    ],\n    'months' => ['siakwa kati', 'kuswa kati', 'kakamuk kati', 'lî wainhka kati', 'lih mairin kati', 'lî kati', 'pastara kati', 'sikla kati', 'wîs kati', 'waupasa kati', 'yahbra kati', 'trisu kati'],\n    'months_short' => ['siakwa kati', 'kuswa kati', 'kakamuk kati', 'lî wainhka kati', 'lih mairin kati', 'lî kati', 'pastara kati', 'sikla kati', 'wîs kati', 'waupasa kati', 'yahbra kati', 'trisu kati'],\n    'weekdays' => ['sandi', 'mundi', 'tiusdi', 'wensde', 'tausde', 'praidi', 'satadi'],\n    'weekdays_short' => ['san', 'mun', 'tius', 'wens', 'taus', 'prai', 'sat'],\n    'weekdays_min' => ['san', 'mun', 'tius', 'wens', 'taus', 'prai', 'sat'],\n    'first_day_of_week' => 0,\n    'day_of_first_week_of_year' => 7,\n    'meridiem' => ['VM', 'NM'],\n\n    'month' => ':count kati', // less reliable\n    'm' => ':count kati', // less reliable\n    'a_month' => ':count kati', // less reliable\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/mjw.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/mjw_IN.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/mjw_IN.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Jor Teron    bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'D/M/YY',\n    ],\n    'months' => ['Arkoi', 'Thangthang', 'There', 'Jangmi', 'Aru', 'Vosik', 'Jakhong', 'Paipai', 'Chiti', 'Phere', 'Phaikuni', 'Matijong'],\n    'months_short' => ['Ark', 'Thang', 'The', 'Jang', 'Aru', 'Vos', 'Jak', 'Pai', 'Chi', 'Phe', 'Phai', 'Mati'],\n    'weekdays' => ['Bhomkuru', 'Urmi', 'Durmi', 'Thelang', 'Theman', 'Bhomta', 'Bhomti'],\n    'weekdays_short' => ['Bhom', 'Ur', 'Dur', 'Tkel', 'Tkem', 'Bhta', 'Bhti'],\n    'weekdays_min' => ['Bhom', 'Ur', 'Dur', 'Tkel', 'Tkem', 'Bhta', 'Bhti'],\n    'first_day_of_week' => 0,\n    'day_of_first_week_of_year' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/mk.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Sashko Todorov\n * - Josh Soref\n * - François B\n * - Serhan Apaydın\n * - Borislav Mickov\n * - JD Isaacks\n * - Tomi Atanasoski\n */\n\nuse Carbon\\CarbonInterface;\n\nreturn [\n    'year' => ':count година|:count години',\n    'a_year' => 'година|:count години',\n    'y' => ':count год.',\n    'month' => ':count месец|:count месеци',\n    'a_month' => 'месец|:count месеци',\n    'm' => ':count месец|:count месеци',\n    'week' => ':count седмица|:count седмици',\n    'a_week' => 'седмица|:count седмици',\n    'w' => ':count седмица|:count седмици',\n    'day' => ':count ден|:count дена',\n    'a_day' => 'ден|:count дена',\n    'd' => ':count ден|:count дена',\n    'hour' => ':count час|:count часа',\n    'a_hour' => 'час|:count часа',\n    'h' => ':count час|:count часа',\n    'minute' => ':count минута|:count минути',\n    'a_minute' => 'минута|:count минути',\n    'min' => ':count мин.',\n    'second' => ':count секунда|:count секунди',\n    'a_second' => 'неколку секунди|:count секунди',\n    's' => ':count сек.',\n    'ago' => 'пред :time',\n    'from_now' => 'после :time',\n    'after' => 'по :time',\n    'before' => 'пред :time',\n    'diff_now' => 'сега',\n    'diff_today' => 'Денес',\n    'diff_today_regexp' => 'Денес(?:\\\\s+во)?',\n    'diff_yesterday' => 'вчера',\n    'diff_yesterday_regexp' => 'Вчера(?:\\\\s+во)?',\n    'diff_tomorrow' => 'утре',\n    'diff_tomorrow_regexp' => 'Утре(?:\\\\s+во)?',\n    'formats' => [\n        'LT' => 'H:mm',\n        'LTS' => 'H:mm:ss',\n        'L' => 'D.MM.YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY H:mm',\n        'LLLL' => 'dddd, D MMMM YYYY H:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[Денес во] LT',\n        'nextDay' => '[Утре во] LT',\n        'nextWeek' => '[Во] dddd [во] LT',\n        'lastDay' => '[Вчера во] LT',\n        'lastWeek' => function (CarbonInterface $date) {\n            switch ($date->dayOfWeek) {\n                case 0:\n                case 3:\n                case 6:\n                    return '[Изминатата] dddd [во] LT';\n                default:\n                    return '[Изминатиот] dddd [во] LT';\n            }\n        },\n        'sameElse' => 'L',\n    ],\n    'ordinal' => function ($number) {\n        $lastDigit = $number % 10;\n        $last2Digits = $number % 100;\n        if ($number === 0) {\n            return $number.'-ев';\n        }\n        if ($last2Digits === 0) {\n            return $number.'-ен';\n        }\n        if ($last2Digits > 10 && $last2Digits < 20) {\n            return $number.'-ти';\n        }\n        if ($lastDigit === 1) {\n            return $number.'-ви';\n        }\n        if ($lastDigit === 2) {\n            return $number.'-ри';\n        }\n        if ($lastDigit === 7 || $lastDigit === 8) {\n            return $number.'-ми';\n        }\n\n        return $number.'-ти';\n    },\n    'months' => ['јануари', 'февруари', 'март', 'април', 'мај', 'јуни', 'јули', 'август', 'септември', 'октомври', 'ноември', 'декември'],\n    'months_short' => ['јан', 'фев', 'мар', 'апр', 'мај', 'јун', 'јул', 'авг', 'сеп', 'окт', 'ное', 'дек'],\n    'weekdays' => ['недела', 'понеделник', 'вторник', 'среда', 'четврток', 'петок', 'сабота'],\n    'weekdays_short' => ['нед', 'пон', 'вто', 'сре', 'чет', 'пет', 'саб'],\n    'weekdays_min' => ['нe', 'пo', 'вт', 'ср', 'че', 'пе', 'сa'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n    'list' => [', ', ' и '],\n    'meridiem' => ['АМ', 'ПМ'],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/mk_MK.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/mk.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ml.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - JD Isaacks\n */\nreturn [\n    'year' => ':count വർഷം',\n    'a_year' => 'ഒരു വർഷം|:count വർഷം',\n    'month' => ':count മാസം',\n    'a_month' => 'ഒരു മാസം|:count മാസം',\n    'week' => ':count ആഴ്ച',\n    'a_week' => 'ഒരാഴ്ച|:count ആഴ്ച',\n    'day' => ':count ദിവസം',\n    'a_day' => 'ഒരു ദിവസം|:count ദിവസം',\n    'hour' => ':count മണിക്കൂർ',\n    'a_hour' => 'ഒരു മണിക്കൂർ|:count മണിക്കൂർ',\n    'minute' => ':count മിനിറ്റ്',\n    'a_minute' => 'ഒരു മിനിറ്റ്|:count മിനിറ്റ്',\n    'second' => ':count സെക്കൻഡ്',\n    'a_second' => 'അൽപ നിമിഷങ്ങൾ|:count സെക്കൻഡ്',\n    'ago' => ':time മുൻപ്',\n    'from_now' => ':time കഴിഞ്ഞ്',\n    'diff_now' => 'ഇപ്പോൾ',\n    'diff_today' => 'ഇന്ന്',\n    'diff_yesterday' => 'ഇന്നലെ',\n    'diff_tomorrow' => 'നാളെ',\n    'formats' => [\n        'LT' => 'A h:mm -നു',\n        'LTS' => 'A h:mm:ss -നു',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY, A h:mm -നു',\n        'LLLL' => 'dddd, D MMMM YYYY, A h:mm -നു',\n    ],\n    'calendar' => [\n        'sameDay' => '[ഇന്ന്] LT',\n        'nextDay' => '[നാളെ] LT',\n        'nextWeek' => 'dddd, LT',\n        'lastDay' => '[ഇന്നലെ] LT',\n        'lastWeek' => '[കഴിഞ്ഞ] dddd, LT',\n        'sameElse' => 'L',\n    ],\n    'meridiem' => function ($hour) {\n        if ($hour < 4) {\n            return 'രാത്രി';\n        }\n        if ($hour < 12) {\n            return 'രാവിലെ';\n        }\n        if ($hour < 17) {\n            return 'ഉച്ച കഴിഞ്ഞ്';\n        }\n        if ($hour < 20) {\n            return 'വൈകുന്നേരം';\n        }\n\n        return 'രാത്രി';\n    },\n    'months' => ['ജനുവരി', 'ഫെബ്രുവരി', 'മാർച്ച്', 'ഏപ്രിൽ', 'മേയ്', 'ജൂൺ', 'ജൂലൈ', 'ഓഗസ്റ്റ്', 'സെപ്റ്റംബർ', 'ഒക്ടോബർ', 'നവംബർ', 'ഡിസംബർ'],\n    'months_short' => ['ജനു.', 'ഫെബ്രു.', 'മാർ.', 'ഏപ്രി.', 'മേയ്', 'ജൂൺ', 'ജൂലൈ.', 'ഓഗ.', 'സെപ്റ്റ.', 'ഒക്ടോ.', 'നവം.', 'ഡിസം.'],\n    'weekdays' => ['ഞായറാഴ്ച', 'തിങ്കളാഴ്ച', 'ചൊവ്വാഴ്ച', 'ബുധനാഴ്ച', 'വ്യാഴാഴ്ച', 'വെള്ളിയാഴ്ച', 'ശനിയാഴ്ച'],\n    'weekdays_short' => ['ഞായർ', 'തിങ്കൾ', 'ചൊവ്വ', 'ബുധൻ', 'വ്യാഴം', 'വെള്ളി', 'ശനി'],\n    'weekdays_min' => ['ഞാ', 'തി', 'ചൊ', 'ബു', 'വ്യാ', 'വെ', 'ശ'],\n    'list' => ', ',\n    'weekend' => [0, 0],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ml_IN.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/ml.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/mn.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Philippe Vaucher\n * - Tsutomu Kuroda\n * - tjku\n * - Max Melentiev\n * - Zolzaya Erdenebaatar\n * - Tom Hughes\n * - Akira Matsuda\n * - Christopher Dell\n * - Michael Kessler\n * - Enrique Vidal\n * - Simone Carletti\n * - Aaron Patterson\n * - Nicolás Hock Isaza\n * - Ochirkhuyag\n * - Batmandakh\n * - lucifer-crybaby\n */\nreturn [\n    'year' => ':count жил',\n    'y' => ':count жил',\n    'month' => ':count сар',\n    'm' => ':count сар',\n    'week' => ':count долоо хоног',\n    'w' => ':count долоо хоног',\n    'day' => ':count өдөр',\n    'd' => ':count өдөр',\n    'hour' => ':count цаг',\n    'h' => ':countц',\n    'minute' => ':count минут',\n    'min' => ':countм',\n    'second' => ':count секунд',\n    's' => ':countс',\n\n    'ago_mode' => 'last',\n    'ago' => ':time өмнө',\n    'year_ago' => ':count жилийн',\n    'y_ago' => ':count жилийн',\n    'month_ago' => ':count сарын',\n    'm_ago' => ':count сарын',\n    'day_ago' => ':count хоногийн',\n    'd_ago' => ':count хоногийн',\n    'week_ago' => ':count долоо хоногийн',\n    'w_ago' => ':count долоо хоногийн',\n    'hour_ago' => ':count цагийн',\n    'minute_ago' => ':count минутын',\n    'second_ago' => ':count секундын',\n\n    'from_now_mode' => 'last',\n    'from_now' => 'одоогоос :time',\n    'year_from_now' => ':count жилийн дараа',\n    'y_from_now' => ':count жилийн дараа',\n    'month_from_now' => ':count сарын дараа',\n    'm_from_now' => ':count сарын дараа',\n    'day_from_now' => ':count хоногийн дараа',\n    'd_from_now' => ':count хоногийн дараа',\n    'hour_from_now' => ':count цагийн дараа',\n    'minute_from_now' => ':count минутын дараа',\n    'second_from_now' => ':count секундын дараа',\n\n    'after_mode' => 'last',\n    'after' => ':time дараа',\n    'year_after' => ':count жилийн',\n    'y_after' => ':count жилийн',\n    'month_after' => ':count сарын',\n    'm_after' => ':count сарын',\n    'day_after' => ':count хоногийн',\n    'd_after' => ':count хоногийн',\n    'hour_after' => ':count цагийн',\n    'minute_after' => ':count минутын',\n    'second_after' => ':count секундын',\n\n    'before_mode' => 'last',\n    'before' => ':time өмнө',\n    'year_before' => ':count жилийн',\n    'y_before' => ':count жилийн',\n    'month_before' => ':count сарын',\n    'm_before' => ':count сарын',\n    'day_before' => ':count хоногийн',\n    'd_before' => ':count хоногийн',\n    'hour_before' => ':count цагийн',\n    'minute_before' => ':count минутын',\n    'second_before' => ':count секундын',\n\n    'list' => ', ',\n    'diff_now' => 'одоо',\n    'diff_yesterday' => 'өчигдөр',\n    'diff_tomorrow' => 'маргааш',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'YYYY-MM-DD',\n        'LL' => 'YYYY MMMM DD',\n        'LLL' => 'YY-MM-DD, HH:mm',\n        'LLLL' => 'YYYY MMMM DD, HH:mm',\n    ],\n    'weekdays' => ['Ням', 'Даваа', 'Мягмар', 'Лхагва', 'Пүрэв', 'Баасан', 'Бямба'],\n    'weekdays_short' => ['Ня', 'Да', 'Мя', 'Лх', 'Пү', 'Ба', 'Бя'],\n    'weekdays_min' => ['Ня', 'Да', 'Мя', 'Лх', 'Пү', 'Ба', 'Бя'],\n    'months' => ['1 сар', '2 сар', '3 сар', '4 сар', '5 сар', '6 сар', '7 сар', '8 сар', '9 сар', '10 сар', '11 сар', '12 сар'],\n    'months_short' => ['1 сар', '2 сар', '3 сар', '4 сар', '5 сар', '6 сар', '7 сар', '8 сар', '9 сар', '10 сар', '11 сар', '12 сар'],\n    'meridiem' => ['өглөө', 'орой'],\n    'first_day_of_week' => 1,\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/mn_MN.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/mn.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/mni.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/mni_IN.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/mni_IN.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Red Hat Pune    libc-alpha@sourceware.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'D/M/YY',\n    ],\n    'months' => ['জানুৱারি', 'ফেব্রুৱারি', 'মার্চ', 'এপ্রিল', 'মে', 'জুন', 'জুলাই', 'আগষ্ট', 'সেপ্তেম্বর', 'ওক্তোবর', 'নবেম্বর', 'ডিসেম্বর'],\n    'months_short' => ['জান', 'ফেব', 'মার', 'এপ্রি', 'মে', 'জুন', 'জুল', 'আগ', 'সেপ', 'ওক্ত', 'নবে', 'ডিস'],\n    'weekdays' => ['নোংমাইজিং', 'নিংথৌকাবা', 'লৈবাকপোকপা', 'য়ুমশকৈশা', 'শগোলশেন', 'ইরাই', 'থাংজ'],\n    'weekdays_short' => ['নোং', 'নিং', 'লৈবাক', 'য়ুম', 'শগোল', 'ইরা', 'থাং'],\n    'weekdays_min' => ['নোং', 'নিং', 'লৈবাক', 'য়ুম', 'শগোল', 'ইরা', 'থাং'],\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['এ.ম.', 'প.ম.'],\n\n    'year' => ':count ইসিং', // less reliable\n    'y' => ':count ইসিং', // less reliable\n    'a_year' => ':count ইসিং', // less reliable\n\n    'second' => ':count ꯅꯤꯡꯊꯧꯀꯥꯕ', // less reliable\n    's' => ':count ꯅꯤꯡꯊꯧꯀꯥꯕ', // less reliable\n    'a_second' => ':count ꯅꯤꯡꯊꯧꯀꯥꯕ', // less reliable\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/mo.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/ro.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/mr.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Vikram-enyota\n */\nreturn [\n    'year' => ':count वर्ष',\n    'y' => ':count वर्ष',\n    'month' => ':count महिना|:count महिने',\n    'm' => ':count महिना|:count महिने',\n    'week' => ':count आठवडा|:count आठवडे',\n    'w' => ':count आठवडा|:count आठवडे',\n    'day' => ':count दिवस',\n    'd' => ':count दिवस',\n    'hour' => ':count तास',\n    'h' => ':count तास',\n    'minute' => ':count मिनिटे',\n    'min' => ':count मिनिटे',\n    'second' => ':count सेकंद',\n    's' => ':count सेकंद',\n\n    'ago' => ':timeपूर्वी',\n    'from_now' => ':timeमध्ये',\n    'before' => ':timeपूर्वी',\n    'after' => ':timeनंतर',\n\n    'diff_now' => 'आत्ता',\n    'diff_today' => 'आज',\n    'diff_yesterday' => 'काल',\n    'diff_tomorrow' => 'उद्या',\n\n    'formats' => [\n        'LT' => 'A h:mm वाजता',\n        'LTS' => 'A h:mm:ss वाजता',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY, A h:mm वाजता',\n        'LLLL' => 'dddd, D MMMM YYYY, A h:mm वाजता',\n    ],\n\n    'calendar' => [\n        'sameDay' => '[आज] LT',\n        'nextDay' => '[उद्या] LT',\n        'nextWeek' => 'dddd, LT',\n        'lastDay' => '[काल] LT',\n        'lastWeek' => '[मागील] dddd, LT',\n        'sameElse' => 'L',\n    ],\n\n    'meridiem' => function ($hour) {\n        if ($hour < 4) {\n            return 'रात्री';\n        }\n        if ($hour < 10) {\n            return 'सकाळी';\n        }\n        if ($hour < 17) {\n            return 'दुपारी';\n        }\n        if ($hour < 20) {\n            return 'सायंकाळी';\n        }\n\n        return 'रात्री';\n    },\n\n    'months' => ['जानेवारी', 'फेब्रुवारी', 'मार्च', 'एप्रिल', 'मे', 'जून', 'जुलै', 'ऑगस्ट', 'सप्टेंबर', 'ऑक्टोबर', 'नोव्हेंबर', 'डिसेंबर'],\n    'months_short' => ['जाने.', 'फेब्रु.', 'मार्च.', 'एप्रि.', 'मे.', 'जून.', 'जुलै.', 'ऑग.', 'सप्टें.', 'ऑक्टो.', 'नोव्हें.', 'डिसें.'],\n    'weekdays' => ['रविवार', 'सोमवार', 'मंगळवार', 'बुधवार', 'गुरूवार', 'शुक्रवार', 'शनिवार'],\n    'weekdays_short' => ['रवि', 'सोम', 'मंगळ', 'बुध', 'गुरू', 'शुक्र', 'शनि'],\n    'weekdays_min' => ['र', 'सो', 'मं', 'बु', 'गु', 'शु', 'श'],\n    'list' => [', ', ' आणि '],\n    'first_day_of_week' => 0,\n    'day_of_first_week_of_year' => 1,\n    'weekend' => [0, 0],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/mr_IN.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/mr.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ms.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Josh Soref\n * - Azri Jamil\n * - JD Isaacks\n * - Josh Soref\n * - Azri Jamil\n * - Hariadi Hinta\n * - Ashraf Kamarudin\n */\nreturn [\n    'year' => ':count tahun',\n    'a_year' => '{1}setahun|]1,Inf[:count tahun',\n    'y' => ':count tahun',\n    'month' => ':count bulan',\n    'a_month' => '{1}sebulan|]1,Inf[:count bulan',\n    'm' => ':count bulan',\n    'week' => ':count minggu',\n    'a_week' => '{1}seminggu|]1,Inf[:count minggu',\n    'w' => ':count minggu',\n    'day' => ':count hari',\n    'a_day' => '{1}sehari|]1,Inf[:count hari',\n    'd' => ':count hari',\n    'hour' => ':count jam',\n    'a_hour' => '{1}sejam|]1,Inf[:count jam',\n    'h' => ':count jam',\n    'minute' => ':count minit',\n    'a_minute' => '{1}seminit|]1,Inf[:count minit',\n    'min' => ':count minit',\n    'second' => ':count saat',\n    'a_second' => '{1}beberapa saat|]1,Inf[:count saat',\n    'millisecond' => ':count milisaat',\n    'a_millisecond' => '{1}semilisaat|]1,Inf[:count milliseconds',\n    'microsecond' => ':count mikrodetik',\n    'a_microsecond' => '{1}semikrodetik|]1,Inf[:count mikrodetik',\n    's' => ':count saat',\n    'ago' => ':time yang lepas',\n    'from_now' => ':time dari sekarang',\n    'after' => ':time kemudian',\n    'before' => ':time sebelum',\n    'diff_now' => 'sekarang',\n    'diff_today' => 'Hari',\n    'diff_today_regexp' => 'Hari(?:\\\\s+ini)?(?:\\\\s+pukul)?',\n    'diff_yesterday' => 'semalam',\n    'diff_yesterday_regexp' => 'Semalam(?:\\\\s+pukul)?',\n    'diff_tomorrow' => 'esok',\n    'diff_tomorrow_regexp' => 'Esok(?:\\\\s+pukul)?',\n    'diff_before_yesterday' => 'kelmarin',\n    'diff_after_tomorrow' => 'lusa',\n    'formats' => [\n        'LT' => 'HH.mm',\n        'LTS' => 'HH.mm.ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY [pukul] HH.mm',\n        'LLLL' => 'dddd, D MMMM YYYY [pukul] HH.mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[Hari ini pukul] LT',\n        'nextDay' => '[Esok pukul] LT',\n        'nextWeek' => 'dddd [pukul] LT',\n        'lastDay' => '[Kelmarin pukul] LT',\n        'lastWeek' => 'dddd [lepas pukul] LT',\n        'sameElse' => 'L',\n    ],\n    'meridiem' => function ($hour) {\n        if ($hour < 1) {\n            return 'tengah malam';\n        }\n\n        if ($hour < 12) {\n            return 'pagi';\n        }\n\n        if ($hour < 13) {\n            return 'tengah hari';\n        }\n\n        if ($hour < 19) {\n            return 'petang';\n        }\n\n        return 'malam';\n    },\n    'months' => ['Januari', 'Februari', 'Mac', 'April', 'Mei', 'Jun', 'Julai', 'Ogos', 'September', 'Oktober', 'November', 'Disember'],\n    'months_short' => ['Jan', 'Feb', 'Mac', 'Apr', 'Mei', 'Jun', 'Jul', 'Ogs', 'Sep', 'Okt', 'Nov', 'Dis'],\n    'weekdays' => ['Ahad', 'Isnin', 'Selasa', 'Rabu', 'Khamis', 'Jumaat', 'Sabtu'],\n    'weekdays_short' => ['Ahd', 'Isn', 'Sel', 'Rab', 'Kha', 'Jum', 'Sab'],\n    'weekdays_min' => ['Ah', 'Is', 'Sl', 'Rb', 'Km', 'Jm', 'Sb'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n    'list' => [', ', ' dan '],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ms_BN.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/ms.php', [\n    'formats' => [\n        'LT' => 'h:mm a',\n        'LTS' => 'h:mm:ss a',\n        'L' => 'D/MM/yy',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY, h:mm a',\n        'LLLL' => 'dd MMMM YYYY, h:mm a',\n    ],\n    'meridiem' => ['a', 'p'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ms_MY.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Josh Soref\n * - Azri Jamil\n * - JD Isaacks\n */\nreturn require __DIR__.'/ms.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ms_SG.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/ms.php', [\n    'formats' => [\n        'LT' => 'h:mm a',\n        'LTS' => 'h:mm:ss a',\n        'L' => 'D/MM/yy',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY, h:mm a',\n        'LLLL' => 'dddd, D MMMM YYYY, h:mm a',\n    ],\n    'meridiem' => ['a', 'p'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/mt.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Alessandro Maruccia\n */\nreturn [\n    'year' => 'sena|:count sni|:count sni|:count sni',\n    'y' => 'sa sena|:count snin|:count snin|:count snin',\n    'month' => 'xahar|:count xhur|:count xhur|:count xhur',\n    'm' => ':count xahar|:count xhur|:count xhur|:count xhur',\n    'week' => 'gimgħa|:count ġimgħat|:count ġimgħat|:count ġimgħat',\n    'w' => 'ġimgħa|:count ġimgħat|:count ġimgħat|:count ġimgħat',\n    'day' => 'ġurnata|:count ġranet|:count ġranet|:count ġranet',\n    'd' => 'ġurnata|:count ġranet|:count ġranet|:count ġranet',\n    'hour' => 'siegħa|:count siegħat|:count siegħat|:count siegħat',\n    'h' => 'siegħa|:count sigħat|:count sigħat|:count sigħat',\n    'minute' => 'minuta|:count minuti|:count minuti|:count minuti',\n    'min' => 'min.|:count min.|:count min.|:count min.',\n    'second' => 'ftit sekondi|:count sekondi|:count sekondi|:count sekondi',\n    's' => 'sek.|:count sek.|:count sek.|:count sek.',\n    'ago' => ':time ilu',\n    'from_now' => 'f’ :time',\n    'diff_now' => 'issa',\n    'diff_today' => 'Illum',\n    'diff_today_regexp' => 'Illum(?:\\\\s+fil-)?',\n    'diff_yesterday' => 'lbieraħ',\n    'diff_yesterday_regexp' => 'Il-bieraħ(?:\\\\s+fil-)?',\n    'diff_tomorrow' => 'għada',\n    'diff_tomorrow_regexp' => 'Għada(?:\\\\s+fil-)?',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[Illum fil-]LT',\n        'nextDay' => '[Għada fil-]LT',\n        'nextWeek' => 'dddd [fil-]LT',\n        'lastDay' => '[Il-bieraħ fil-]LT',\n        'lastWeek' => 'dddd [li għadda] [fil-]LT',\n        'sameElse' => 'L',\n    ],\n    'ordinal' => ':numberº',\n    'months' => ['Jannar', 'Frar', 'Marzu', 'April', 'Mejju', 'Ġunju', 'Lulju', 'Awwissu', 'Settembru', 'Ottubru', 'Novembru', 'Diċembru'],\n    'months_short' => ['Jan', 'Fra', 'Mar', 'Apr', 'Mej', 'Ġun', 'Lul', 'Aww', 'Set', 'Ott', 'Nov', 'Diċ'],\n    'weekdays' => ['Il-Ħadd', 'It-Tnejn', 'It-Tlieta', 'L-Erbgħa', 'Il-Ħamis', 'Il-Ġimgħa', 'Is-Sibt'],\n    'weekdays_short' => ['Ħad', 'Tne', 'Tli', 'Erb', 'Ħam', 'Ġim', 'Sib'],\n    'weekdays_min' => ['Ħa', 'Tn', 'Tl', 'Er', 'Ħa', 'Ġi', 'Si'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n    'list' => [', ', ' u '],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/mt_MT.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/mt.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/mua.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'meridiem' => ['comme', 'lilli'],\n    'weekdays' => ['Com’yakke', 'Comlaaɗii', 'Comzyiiɗii', 'Comkolle', 'Comkaldǝɓlii', 'Comgaisuu', 'Comzyeɓsuu'],\n    'weekdays_short' => ['Cya', 'Cla', 'Czi', 'Cko', 'Cka', 'Cga', 'Cze'],\n    'weekdays_min' => ['Cya', 'Cla', 'Czi', 'Cko', 'Cka', 'Cga', 'Cze'],\n    'months' => ['Fĩi Loo', 'Cokcwaklaŋne', 'Cokcwaklii', 'Fĩi Marfoo', 'Madǝǝuutǝbijaŋ', 'Mamǝŋgwãafahbii', 'Mamǝŋgwãalii', 'Madǝmbii', 'Fĩi Dǝɓlii', 'Fĩi Mundaŋ', 'Fĩi Gwahlle', 'Fĩi Yuru'],\n    'months_short' => ['FLO', 'CLA', 'CKI', 'FMF', 'MAD', 'MBI', 'MLI', 'MAM', 'FDE', 'FMU', 'FGW', 'FYU'],\n    'first_day_of_week' => 1,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'D/M/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd D MMMM YYYY HH:mm',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/my.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Josh Soref\n * - JD Isaacks\n * - Nay Lin Aung\n */\nreturn [\n    'year' => '{1}တစ်နှစ်|]1,Inf[:count နှစ်',\n    'y' => ':count နှစ်',\n    'month' => '{1}တစ်လ|]1,Inf[:count လ',\n    'm' => ':count လ',\n    'week' => ':count ပတ်',\n    'w' => ':count ပတ်',\n    'day' => '{1}တစ်ရက်|]1,Inf[:count ရက်',\n    'd' => ':count ရက်',\n    'hour' => '{1}တစ်နာရီ|]1,Inf[:count နာရီ',\n    'h' => ':count နာရီ',\n    'minute' => '{1}တစ်မိနစ်|]1,Inf[:count မိနစ်',\n    'min' => ':count မိနစ်',\n    'second' => '{1}စက္ကန်.အနည်းငယ်|]1,Inf[:count စက္ကန့်',\n    's' => ':count စက္ကန့်',\n    'ago' => 'လွန်ခဲ့သော :time က',\n    'from_now' => 'လာမည့် :time မှာ',\n    'after' => ':time ကြာပြီးနောက်',\n    'before' => ':time မတိုင်ခင်',\n    'diff_now' => 'အခုလေးတင်',\n    'diff_today' => 'ယနေ.',\n    'diff_yesterday' => 'မနေ့က',\n    'diff_yesterday_regexp' => 'မနေ.က',\n    'diff_tomorrow' => 'မနက်ဖြန်',\n    'diff_before_yesterday' => 'တမြန်နေ့က',\n    'diff_after_tomorrow' => 'တဘက်ခါ',\n    'period_recurrences' => ':count ကြိမ်',\n    'formats' => [\n        'LT' => 'Oh:Om A',\n        'LTS' => 'Oh:Om:Os A',\n        'L' => 'OD/OM/OY',\n        'LL' => 'OD MMMM OY',\n        'LLL' => 'OD MMMM OY Oh:Om A',\n        'LLLL' => 'dddd OD MMMM OY Oh:Om A',\n    ],\n    'calendar' => [\n        'sameDay' => '[ယနေ.] LT [မှာ]',\n        'nextDay' => '[မနက်ဖြန်] LT [မှာ]',\n        'nextWeek' => 'dddd LT [မှာ]',\n        'lastDay' => '[မနေ.က] LT [မှာ]',\n        'lastWeek' => '[ပြီးခဲ့သော] dddd LT [မှာ]',\n        'sameElse' => 'L',\n    ],\n    'months' => ['ဇန်နဝါရီ', 'ဖေဖော်ဝါရီ', 'မတ်', 'ဧပြီ', 'မေ', 'ဇွန်', 'ဇူလိုင်', 'သြဂုတ်', 'စက်တင်ဘာ', 'အောက်တိုဘာ', 'နိုဝင်ဘာ', 'ဒီဇင်ဘာ'],\n    'months_short' => ['ဇန်', 'ဖေ', 'မတ်', 'ပြီ', 'မေ', 'ဇွန်', 'လိုင်', 'သြ', 'စက်', 'အောက်', 'နို', 'ဒီ'],\n    'weekdays' => ['တနင်္ဂနွေ', 'တနင်္လာ', 'အင်္ဂါ', 'ဗုဒ္ဓဟူး', 'ကြာသပတေး', 'သောကြာ', 'စနေ'],\n    'weekdays_short' => ['နွေ', 'လာ', 'ဂါ', 'ဟူး', 'ကြာ', 'သော', 'နေ'],\n    'weekdays_min' => ['နွေ', 'လာ', 'ဂါ', 'ဟူး', 'ကြာ', 'သော', 'နေ'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n    'alt_numbers' => ['၀၀', '၀၁', '၀၂', '၀၃', '၀၄', '၀၅', '၀၆', '၀၇', '၀၈', '၀၉', '၁၀', '၁၁', '၁၂', '၁၃', '၁၄', '၁၅', '၁၆', '၁၇', '၁၈', '၁၉', '၂၀', '၂၁', '၂၂', '၂၃', '၂၄', '၂၅', '၂၆', '၂၇', '၂၈', '၂၉', '၃၀', '၃၁', '၃၂', '၃၃', '၃၄', '၃၅', '၃၆', '၃၇', '၃၈', '၃၉', '၄၀', '၄၁', '၄၂', '၄၃', '၄၄', '၄၅', '၄၆', '၄၇', '၄၈', '၄၉', '၅၀', '၅၁', '၅၂', '၅၃', '၅၄', '၅၅', '၅၆', '၅၇', '၅၈', '၅၉', '၆၀', '၆၁', '၆၂', '၆၃', '၆၄', '၆၅', '၆၆', '၆၇', '၆၈', '၆၉', '၇၀', '၇၁', '၇၂', '၇၃', '၇၄', '၇၅', '၇၆', '၇၇', '၇၈', '၇၉', '၈၀', '၈၁', '၈၂', '၈၃', '၈၄', '၈၅', '၈၆', '၈၇', '၈၈', '၈၉', '၉၀', '၉၁', '၉၂', '၉၃', '၉၄', '၉၅', '၉၆', '၉၇', '၉၈', '၉၉'],\n    'meridiem' => ['နံနက်', 'ညနေ'],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/my_MM.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/my.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/mzn.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/fa.php', [\n    'months' => ['ژانویه', 'فوریه', 'مارس', 'آوریل', 'مه', 'ژوئن', 'ژوئیه', 'اوت', 'سپتامبر', 'اکتبر', 'نوامبر', 'دسامبر'],\n    'months_short' => ['ژانویه', 'فوریه', 'مارس', 'آوریل', 'مه', 'ژوئن', 'ژوئیه', 'اوت', 'سپتامبر', 'اکتبر', 'نوامبر', 'دسامبر'],\n    'first_day_of_week' => 6,\n    'weekend' => [5, 5],\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'YYYY-MM-dd',\n        'LL' => 'YYYY MMM D',\n        'LLL' => 'YYYY MMMM D HH:mm',\n        'LLLL' => 'YYYY MMMM D, dddd HH:mm',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/nan.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/nan_TW.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/nan_TW.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'YYYY年MM月DD日',\n    ],\n    'months' => ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'],\n    'months_short' => [' 1月', ' 2月', ' 3月', ' 4月', ' 5月', ' 6月', ' 7月', ' 8月', ' 9月', '10月', '11月', '12月'],\n    'weekdays' => ['禮拜日', '禮拜一', '禮拜二', '禮拜三', '禮拜四', '禮拜五', '禮拜六'],\n    'weekdays_short' => ['日', '一', '二', '三', '四', '五', '六'],\n    'weekdays_min' => ['日', '一', '二', '三', '四', '五', '六'],\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['頂晡', '下晡'],\n\n    'year' => ':count 年',\n    'y' => ':count 年',\n    'a_year' => ':count 年',\n\n    'month' => ':count goe̍h',\n    'm' => ':count goe̍h',\n    'a_month' => ':count goe̍h',\n\n    'week' => ':count lé-pài',\n    'w' => ':count lé-pài',\n    'a_week' => ':count lé-pài',\n\n    'day' => ':count 日',\n    'd' => ':count 日',\n    'a_day' => ':count 日',\n\n    'hour' => ':count tiám-cheng',\n    'h' => ':count tiám-cheng',\n    'a_hour' => ':count tiám-cheng',\n\n    'minute' => ':count Hun-cheng',\n    'min' => ':count Hun-cheng',\n    'a_minute' => ':count Hun-cheng',\n\n    'second' => ':count Bió',\n    's' => ':count Bió',\n    'a_second' => ':count Bió',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/nan_TW@latin.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Arne Goetje arne@canonical.com\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'YYYY-MM-DD',\n    ],\n    'months' => ['1goe̍h', '2goe̍h', '3goe̍h', '4goe̍h', '5goe̍h', '6goe̍h', '7goe̍h', '8goe̍h', '9goe̍h', '10goe̍h', '11goe̍h', '12goe̍h'],\n    'months_short' => ['1g', '2g', '3g', '4g', '5g', '6g', '7g', '8g', '9g', '10g', '11g', '12g'],\n    'weekdays' => ['lé-pài-ji̍t', 'pài-it', 'pài-jī', 'pài-saⁿ', 'pài-sì', 'pài-gō͘', 'pài-la̍k'],\n    'weekdays_short' => ['lp', 'p1', 'p2', 'p3', 'p4', 'p5', 'p6'],\n    'weekdays_min' => ['lp', 'p1', 'p2', 'p3', 'p4', 'p5', 'p6'],\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['téng-po͘', 'ē-po͘'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/naq.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'meridiem' => ['ǁgoagas', 'ǃuias'],\n    'weekdays' => ['Sontaxtsees', 'Mantaxtsees', 'Denstaxtsees', 'Wunstaxtsees', 'Dondertaxtsees', 'Fraitaxtsees', 'Satertaxtsees'],\n    'weekdays_short' => ['Son', 'Ma', 'De', 'Wu', 'Do', 'Fr', 'Sat'],\n    'weekdays_min' => ['Son', 'Ma', 'De', 'Wu', 'Do', 'Fr', 'Sat'],\n    'months' => ['ǃKhanni', 'ǃKhanǀgôab', 'ǀKhuuǁkhâb', 'ǃHôaǂkhaib', 'ǃKhaitsâb', 'Gamaǀaeb', 'ǂKhoesaob', 'Aoǁkhuumûǁkhâb', 'Taraǀkhuumûǁkhâb', 'ǂNûǁnâiseb', 'ǀHooǂgaeb', 'Hôasoreǁkhâb'],\n    'months_short' => ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],\n    'first_day_of_week' => 1,\n    'formats' => [\n        'LT' => 'h:mm a',\n        'LTS' => 'h:mm:ss a',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY h:mm a',\n        'LLLL' => 'dddd, D MMMM YYYY h:mm a',\n    ],\n\n    'year' => ':count kurigu',\n    'y' => ':count kurigu',\n    'a_year' => ':count kurigu',\n\n    'month' => ':count ǁaub', // less reliable\n    'm' => ':count ǁaub', // less reliable\n    'a_month' => ':count ǁaub', // less reliable\n\n    'week' => ':count hû', // less reliable\n    'w' => ':count hû', // less reliable\n    'a_week' => ':count hû', // less reliable\n\n    'day' => ':count ǀhobas', // less reliable\n    'd' => ':count ǀhobas', // less reliable\n    'a_day' => ':count ǀhobas', // less reliable\n\n    'hour' => ':count ǂgaes', // less reliable\n    'h' => ':count ǂgaes', // less reliable\n    'a_hour' => ':count ǂgaes', // less reliable\n\n    'minute' => ':count minutga', // less reliable\n    'min' => ':count minutga', // less reliable\n    'a_minute' => ':count minutga', // less reliable\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/nb.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - François B\n * - Alexander Tømmerås\n * - Sigurd Gartmann\n * - JD Isaacks\n */\nreturn [\n    'year' => ':count år|:count år',\n    'a_year' => 'ett år|:count år',\n    'y' => ':count år|:count år',\n    'month' => ':count måned|:count måneder',\n    'a_month' => 'en måned|:count måneder',\n    'm' => ':count md.',\n    'week' => ':count uke|:count uker',\n    'a_week' => 'en uke|:count uker',\n    'w' => ':count u.',\n    'day' => ':count dag|:count dager',\n    'a_day' => 'en dag|:count dager',\n    'd' => ':count d.',\n    'hour' => ':count time|:count timer',\n    'a_hour' => 'en time|:count timer',\n    'h' => ':count t',\n    'minute' => ':count minutt|:count minutter',\n    'a_minute' => 'ett minutt|:count minutter',\n    'min' => ':count min',\n    'second' => ':count sekund|:count sekunder',\n    'a_second' => 'noen sekunder|:count sekunder',\n    's' => ':count sek',\n    'ago' => ':time siden',\n    'from_now' => 'om :time',\n    'after' => ':time etter',\n    'before' => ':time før',\n    'diff_now' => 'akkurat nå',\n    'diff_today' => 'i dag',\n    'diff_today_regexp' => 'i dag(?:\\\\s+kl.)?',\n    'diff_yesterday' => 'i går',\n    'diff_yesterday_regexp' => 'i går(?:\\\\s+kl.)?',\n    'diff_tomorrow' => 'i morgen',\n    'diff_tomorrow_regexp' => 'i morgen(?:\\\\s+kl.)?',\n    'diff_before_yesterday' => 'i forgårs',\n    'diff_after_tomorrow' => 'i overmorgen',\n    'period_recurrences' => 'en gang|:count ganger',\n    'period_interval' => 'hver :interval',\n    'period_start_date' => 'fra :date',\n    'period_end_date' => 'til :date',\n    'months' => ['januar', 'februar', 'mars', 'april', 'mai', 'juni', 'juli', 'august', 'september', 'oktober', 'november', 'desember'],\n    'months_short' => ['jan', 'feb', 'mar', 'apr', 'mai', 'jun', 'jul', 'aug', 'sep', 'okt', 'nov', 'des'],\n    'weekdays' => ['søndag', 'mandag', 'tirsdag', 'onsdag', 'torsdag', 'fredag', 'lørdag'],\n    'weekdays_short' => ['søn', 'man', 'tir', 'ons', 'tor', 'fre', 'lør'],\n    'weekdays_min' => ['sø', 'ma', 'ti', 'on', 'to', 'fr', 'lø'],\n    'ordinal' => ':number.',\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD.MM.YYYY',\n        'LL' => 'D. MMMM YYYY',\n        'LLL' => 'D. MMMM YYYY [kl.] HH:mm',\n        'LLLL' => 'dddd D. MMMM YYYY [kl.] HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[i dag kl.] LT',\n        'nextDay' => '[i morgen kl.] LT',\n        'nextWeek' => 'dddd [kl.] LT',\n        'lastDay' => '[i går kl.] LT',\n        'lastWeek' => '[forrige] dddd [kl.] LT',\n        'sameElse' => 'L',\n    ],\n    'list' => [', ', ' og '],\n    'meridiem' => ['a.m.', 'p.m.'],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/nb_NO.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/nb.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/nb_SJ.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/nb.php', [\n    'formats' => [\n        'LL' => 'D. MMM YYYY',\n        'LLL' => 'D. MMMM YYYY, HH:mm',\n        'LLLL' => 'dddd D. MMMM YYYY, HH:mm',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/nd.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'weekdays' => ['Sonto', 'Mvulo', 'Sibili', 'Sithathu', 'Sine', 'Sihlanu', 'Mgqibelo'],\n    'weekdays_short' => ['Son', 'Mvu', 'Sib', 'Sit', 'Sin', 'Sih', 'Mgq'],\n    'weekdays_min' => ['Son', 'Mvu', 'Sib', 'Sit', 'Sin', 'Sih', 'Mgq'],\n    'months' => ['Zibandlela', 'Nhlolanja', 'Mbimbitho', 'Mabasa', 'Nkwenkwezi', 'Nhlangula', 'Ntulikazi', 'Ncwabakazi', 'Mpandula', 'Mfumfu', 'Lwezi', 'Mpalakazi'],\n    'months_short' => ['Zib', 'Nhlo', 'Mbi', 'Mab', 'Nkw', 'Nhla', 'Ntu', 'Ncw', 'Mpan', 'Mfu', 'Lwe', 'Mpal'],\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY HH:mm',\n    ],\n\n    'year' => 'okweminyaka engu-:count', // less reliable\n    'y' => 'okweminyaka engu-:count', // less reliable\n    'a_year' => 'okweminyaka engu-:count', // less reliable\n\n    'month' => 'inyanga ezingu-:count',\n    'm' => 'inyanga ezingu-:count',\n    'a_month' => 'inyanga ezingu-:count',\n\n    'week' => 'amaviki angu-:count',\n    'w' => 'amaviki angu-:count',\n    'a_week' => 'amaviki angu-:count',\n\n    'day' => 'kwamalanga angu-:count',\n    'd' => 'kwamalanga angu-:count',\n    'a_day' => 'kwamalanga angu-:count',\n\n    'hour' => 'amahola angu-:count',\n    'h' => 'amahola angu-:count',\n    'a_hour' => 'amahola angu-:count',\n\n    'minute' => 'imizuzu engu-:count',\n    'min' => 'imizuzu engu-:count',\n    'a_minute' => 'imizuzu engu-:count',\n\n    'second' => 'imizuzwana engu-:count',\n    's' => 'imizuzwana engu-:count',\n    'a_second' => 'imizuzwana engu-:count',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/nds.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/nds_DE.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/nds_DE.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - information from Kenneth Christiansen Kenneth Christiansen, Pablo Saratxaga kenneth@gnu.org, pablo@mandrakesoft.com\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD.MM.YYYY',\n    ],\n    'months' => ['Jannuaar', 'Feberwaar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'],\n    'months_short' => ['Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'],\n    'weekdays' => ['Sünndag', 'Maandag', 'Dingsdag', 'Middeweek', 'Dunnersdag', 'Freedag', 'Sünnavend'],\n    'weekdays_short' => ['Sdag', 'Maan', 'Ding', 'Midd', 'Dunn', 'Free', 'Svd.'],\n    'weekdays_min' => ['Sd', 'Ma', 'Di', 'Mi', 'Du', 'Fr', 'Sa'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n\n    'year' => ':count Johr',\n    'y' => ':countJ',\n    'a_year' => '{1}een Johr|:count Johr',\n\n    'month' => ':count Maand',\n    'm' => ':countM',\n    'a_month' => '{1}een Maand|:count Maand',\n\n    'week' => ':count Week|:count Weken',\n    'w' => ':countW',\n    'a_week' => '{1}een Week|:count Week|:count Weken',\n\n    'day' => ':count Dag|:count Daag',\n    'd' => ':countD',\n    'a_day' => '{1}een Dag|:count Dag|:count Daag',\n\n    'hour' => ':count Stünn|:count Stünnen',\n    'h' => ':countSt',\n    'a_hour' => '{1}een Stünn|:count Stünn|:count Stünnen',\n\n    'minute' => ':count Minuut|:count Minuten',\n    'min' => ':countm',\n    'a_minute' => '{1}een Minuut|:count Minuut|:count Minuten',\n\n    'second' => ':count Sekunn|:count Sekunnen',\n    's' => ':counts',\n    'a_second' => 'en poor Sekunnen|:count Sekunn|:count Sekunnen',\n\n    'ago' => 'vör :time',\n    'from_now' => 'in :time',\n    'before' => ':time vörher',\n    'after' => ':time later',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/nds_NL.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - information from Kenneth Christiansen Kenneth Christiansen, Pablo Saratxaga kenneth@gnu.org, pablo@mandrakesoft.com\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD.MM.YYYY',\n    ],\n    'months' => ['Jaunuwoa', 'Februwoa', 'Moaz', 'Aprell', 'Mai', 'Juni', 'Juli', 'August', 'Septamba', 'Oktoba', 'Nowamba', 'Dezamba'],\n    'months_short' => ['Jan', 'Feb', 'Moz', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Now', 'Dez'],\n    'weekdays' => ['Sinndag', 'Mondag', 'Dingsdag', 'Meddwäakj', 'Donnadag', 'Friedag', 'Sinnowend'],\n    'weekdays_short' => ['Sdg', 'Mdg', 'Dsg', 'Mwk', 'Ddg', 'Fdg', 'Swd'],\n    'weekdays_min' => ['Sdg', 'Mdg', 'Dsg', 'Mwk', 'Ddg', 'Fdg', 'Swd'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ne.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - nootanghimire\n * - Josh Soref\n * - Nj Subedi\n * - JD Isaacks\n */\nreturn [\n    'year' => 'एक बर्ष|:count बर्ष',\n    'y' => ':count वर्ष',\n    'month' => 'एक महिना|:count महिना',\n    'm' => ':count महिना',\n    'week' => ':count हप्ता',\n    'w' => ':count हप्ता',\n    'day' => 'एक दिन|:count दिन',\n    'd' => ':count दिन',\n    'hour' => 'एक घण्टा|:count घण्टा',\n    'h' => ':count घण्टा',\n    'minute' => 'एक मिनेट|:count मिनेट',\n    'min' => ':count मिनेट',\n    'second' => 'केही क्षण|:count सेकेण्ड',\n    's' => ':count सेकेण्ड',\n    'ago' => ':time अगाडि',\n    'from_now' => ':timeमा',\n    'after' => ':time पछि',\n    'before' => ':time अघि',\n    'diff_now' => 'अहिले',\n    'diff_today' => 'आज',\n    'diff_yesterday' => 'हिजो',\n    'diff_tomorrow' => 'भोलि',\n    'formats' => [\n        'LT' => 'Aको h:mm बजे',\n        'LTS' => 'Aको h:mm:ss बजे',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY, Aको h:mm बजे',\n        'LLLL' => 'dddd, D MMMM YYYY, Aको h:mm बजे',\n    ],\n    'calendar' => [\n        'sameDay' => '[आज] LT',\n        'nextDay' => '[भोलि] LT',\n        'nextWeek' => '[आउँदो] dddd[,] LT',\n        'lastDay' => '[हिजो] LT',\n        'lastWeek' => '[गएको] dddd[,] LT',\n        'sameElse' => 'L',\n    ],\n    'meridiem' => function ($hour) {\n        if ($hour < 3) {\n            return 'राति';\n        }\n        if ($hour < 12) {\n            return 'बिहान';\n        }\n        if ($hour < 16) {\n            return 'दिउँसो';\n        }\n        if ($hour < 20) {\n            return 'साँझ';\n        }\n\n        return 'राति';\n    },\n    'months' => ['जनवरी', 'फेब्रुवरी', 'मार्च', 'अप्रिल', 'मई', 'जुन', 'जुलाई', 'अगष्ट', 'सेप्टेम्बर', 'अक्टोबर', 'नोभेम्बर', 'डिसेम्बर'],\n    'months_short' => ['जन.', 'फेब्रु.', 'मार्च', 'अप्रि.', 'मई', 'जुन', 'जुलाई.', 'अग.', 'सेप्ट.', 'अक्टो.', 'नोभे.', 'डिसे.'],\n    'weekdays' => ['आइतबार', 'सोमबार', 'मङ्गलबार', 'बुधबार', 'बिहिबार', 'शुक्रबार', 'शनिबार'],\n    'weekdays_short' => ['आइत.', 'सोम.', 'मङ्गल.', 'बुध.', 'बिहि.', 'शुक्र.', 'शनि.'],\n    'weekdays_min' => ['आ.', 'सो.', 'मं.', 'बु.', 'बि.', 'शु.', 'श.'],\n    'list' => [', ', ' र '],\n    'first_day_of_week' => 0,\n    'day_of_first_week_of_year' => 1,\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ne_IN.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/ne.php', [\n    'formats' => [\n        'LT' => 'h:mm a',\n        'LTS' => 'h:mm:ss a',\n        'L' => 'yy/M/d',\n        'LL' => 'YYYY MMM D',\n        'LLL' => 'YYYY MMMM D, h:mm a',\n        'LLLL' => 'YYYY MMMM D, dddd, h:mm a',\n    ],\n    'months' => ['जनवरी', 'फेब्रुअरी', 'मार्च', 'अप्रिल', 'मे', 'जुन', 'जुलाई', 'अगस्ट', 'सेप्टेम्बर', 'अक्टोबर', 'नोभेम्बर', 'डिसेम्बर'],\n    'months_short' => ['जनवरी', 'फेब्रुअरी', 'मार्च', 'अप्रिल', 'मे', 'जुन', 'जुलाई', 'अगस्ट', 'सेप्टेम्बर', 'अक्टोबर', 'नोभेम्बर', 'डिसेम्बर'],\n    'weekend' => [0, 0],\n    'meridiem' => ['पूर्वाह्न', 'अपराह्न'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ne_NP.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/ne.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/nhn.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/nhn_MX.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/nhn_MX.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - RAP    libc-alpha@sourceware.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD/MM/YY',\n    ],\n    'months' => ['enero', 'febrero', 'marzo', 'abril', 'mayo', 'junio', 'julio', 'agosto', 'septiembre', 'octubre', 'noviembre', 'diciembre'],\n    'months_short' => ['ene', 'feb', 'mar', 'abr', 'may', 'jun', 'jul', 'ago', 'sep', 'oct', 'nov', 'dic'],\n    'weekdays' => ['teoilhuitl', 'ceilhuitl', 'omeilhuitl', 'yeilhuitl', 'nahuilhuitl', 'macuililhuitl', 'chicuaceilhuitl'],\n    'weekdays_short' => ['teo', 'cei', 'ome', 'yei', 'nau', 'mac', 'chi'],\n    'weekdays_min' => ['teo', 'cei', 'ome', 'yei', 'nau', 'mac', 'chi'],\n    'day_of_first_week_of_year' => 1,\n\n    'month' => ':count metztli', // less reliable\n    'm' => ':count metztli', // less reliable\n    'a_month' => ':count metztli', // less reliable\n\n    'week' => ':count tonalli', // less reliable\n    'w' => ':count tonalli', // less reliable\n    'a_week' => ':count tonalli', // less reliable\n\n    'day' => ':count tonatih', // less reliable\n    'd' => ':count tonatih', // less reliable\n    'a_day' => ':count tonatih', // less reliable\n\n    'minute' => ':count toltecayotl', // less reliable\n    'min' => ':count toltecayotl', // less reliable\n    'a_minute' => ':count toltecayotl', // less reliable\n\n    'second' => ':count ome', // less reliable\n    's' => ':count ome', // less reliable\n    'a_second' => ':count ome', // less reliable\n\n    'year' => ':count xihuitl',\n    'y' => ':count xihuitl',\n    'a_year' => ':count xihuitl',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/niu.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/niu_NU.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/niu_NU.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - RockET Systems Emani Fakaotimanava-Lui emani@niue.nu\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD/MM/YY',\n    ],\n    'months' => ['Ianuali', 'Fepuali', 'Masi', 'Apelila', 'Me', 'Iuni', 'Iulai', 'Aokuso', 'Sepetema', 'Oketopa', 'Novema', 'Tesemo'],\n    'months_short' => ['Ian', 'Fep', 'Mas', 'Ape', 'Me', 'Iun', 'Iul', 'Aok', 'Sep', 'Oke', 'Nov', 'Tes'],\n    'weekdays' => ['Aho Tapu', 'Aho Gofua', 'Aho Ua', 'Aho Lotu', 'Aho Tuloto', 'Aho Falaile', 'Aho Faiumu'],\n    'weekdays_short' => ['Tapu', 'Gofua', 'Ua', 'Lotu', 'Tuloto', 'Falaile', 'Faiumu'],\n    'weekdays_min' => ['Tapu', 'Gofua', 'Ua', 'Lotu', 'Tuloto', 'Falaile', 'Faiumu'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n\n    'year' => ':count tau',\n    'y' => ':count tau',\n    'a_year' => ':count tau',\n\n    'month' => ':count mahina',\n    'm' => ':count mahina',\n    'a_month' => ':count mahina',\n\n    'week' => ':count faahi tapu',\n    'w' => ':count faahi tapu',\n    'a_week' => ':count faahi tapu',\n\n    'day' => ':count aho',\n    'd' => ':count aho',\n    'a_day' => ':count aho',\n\n    'hour' => ':count e tulā',\n    'h' => ':count e tulā',\n    'a_hour' => ':count e tulā',\n\n    'minute' => ':count minuti',\n    'min' => ':count minuti',\n    'a_minute' => ':count minuti',\n\n    'second' => ':count sekone',\n    's' => ':count sekone',\n    'a_second' => ':count sekone',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/nl.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Roy\n * - Stephan\n * - François B\n * - Tim Fish\n * - Kevin Huang\n * - Jacob Middag\n * - JD Isaacks\n * - Roy\n * - Stephan\n * - François B\n * - Tim Fish\n * - Jacob Middag\n * - JD Isaacks\n * - Propaganistas\n * - MegaXLR\n * - adriaanzon\n * - MonkeyPhysics\n * - JeroenG\n * - RikSomers\n * - proclame\n * - Rik de Groot (hwdegroot)\n */\nreturn [\n    'year' => ':count jaar|:count jaar',\n    'a_year' => 'een jaar|:count jaar',\n    'y' => ':countj',\n    'month' => ':count maand|:count maanden',\n    'a_month' => 'een maand|:count maanden',\n    'm' => ':countmnd',\n    'week' => ':count week|:count weken',\n    'a_week' => 'een week|:count weken',\n    'w' => ':countw',\n    'day' => ':count dag|:count dagen',\n    'a_day' => 'een dag|:count dagen',\n    'd' => ':countd',\n    'hour' => ':count uur|:count uur',\n    'a_hour' => 'een uur|:count uur',\n    'h' => ':countu',\n    'minute' => ':count minuut|:count minuten',\n    'a_minute' => 'een minuut|:count minuten',\n    'min' => ':countmin',\n    'second' => ':count seconde|:count seconden',\n    'a_second' => 'een paar seconden|:count seconden',\n    's' => ':counts',\n    'ago' => ':time geleden',\n    'from_now' => 'over :time',\n    'after' => ':time later',\n    'before' => ':time eerder',\n    'diff_now' => 'nu',\n    'diff_today' => 'vandaag',\n    'diff_today_regexp' => 'vandaag(?:\\\\s+om)?',\n    'diff_yesterday' => 'gisteren',\n    'diff_yesterday_regexp' => 'gisteren(?:\\\\s+om)?',\n    'diff_tomorrow' => 'morgen',\n    'diff_tomorrow_regexp' => 'morgen(?:\\\\s+om)?',\n    'diff_after_tomorrow' => 'overmorgen',\n    'diff_before_yesterday' => 'eergisteren',\n    'period_recurrences' => ':count keer',\n    'period_interval' => function (string $interval = '') {\n        /** @var string $output */\n        $output = preg_replace('/^(een|één|1)\\s+/u', '', $interval);\n\n        if (preg_match('/^(een|één|1)( jaar|j| uur|u)/u', $interval)) {\n            return \"elk $output\";\n        }\n\n        return \"elke $output\";\n    },\n    'period_start_date' => 'van :date',\n    'period_end_date' => 'tot :date',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD-MM-YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd D MMMM YYYY HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[vandaag om] LT',\n        'nextDay' => '[morgen om] LT',\n        'nextWeek' => 'dddd [om] LT',\n        'lastDay' => '[gisteren om] LT',\n        'lastWeek' => '[afgelopen] dddd [om] LT',\n        'sameElse' => 'L',\n    ],\n    'ordinal' => function ($number) {\n        return $number.(($number === 1 || $number === 8 || $number >= 20) ? 'ste' : 'de');\n    },\n    'months' => ['januari', 'februari', 'maart', 'april', 'mei', 'juni', 'juli', 'augustus', 'september', 'oktober', 'november', 'december'],\n    'months_short' => ['jan', 'feb', 'mrt', 'apr', 'mei', 'jun', 'jul', 'aug', 'sep', 'okt', 'nov', 'dec'],\n    'mmm_suffix' => '.',\n    'weekdays' => ['zondag', 'maandag', 'dinsdag', 'woensdag', 'donderdag', 'vrijdag', 'zaterdag'],\n    'weekdays_short' => ['zo.', 'ma.', 'di.', 'wo.', 'do.', 'vr.', 'za.'],\n    'weekdays_min' => ['zo', 'ma', 'di', 'wo', 'do', 'vr', 'za'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n    'list' => [', ', ' en '],\n    'meridiem' => ['\\'s ochtends', '\\'s middags'],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/nl_AW.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Free Software Foundation, Inc.    bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/nl.php', [\n    'formats' => [\n        'L' => 'DD-MM-YY',\n    ],\n    'months' => ['januari', 'februari', 'maart', 'april', 'mei', 'juni', 'juli', 'augustus', 'september', 'oktober', 'november', 'december'],\n    'months_short' => ['jan', 'feb', 'mrt', 'apr', 'mei', 'jun', 'jul', 'aug', 'sep', 'okt', 'nov', 'dec'],\n    'weekdays' => ['zondag', 'maandag', 'dinsdag', 'woensdag', 'donderdag', 'vrijdag', 'zaterdag'],\n    'weekdays_short' => ['zo', 'ma', 'di', 'wo', 'do', 'vr', 'za'],\n    'weekdays_min' => ['zo', 'ma', 'di', 'wo', 'do', 'vr', 'za'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/nl_BE.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Roy\n * - Stephan\n * - François B\n * - Tim Fish\n * - Kevin Huang\n * - Jacob Middag\n * - JD Isaacks\n * - Propaganistas\n */\nreturn array_replace_recursive(require __DIR__.'/nl.php', [\n    'formats' => [\n        'L' => 'DD/MM/YYYY',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/nl_BQ.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/nl.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/nl_CW.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/nl.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/nl_NL.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - RAP    bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/nl.php', [\n    'months' => ['januari', 'februari', 'maart', 'april', 'mei', 'juni', 'juli', 'augustus', 'september', 'oktober', 'november', 'december'],\n    'months_short' => ['jan', 'feb', 'mrt', 'apr', 'mei', 'jun', 'jul', 'aug', 'sep', 'okt', 'nov', 'dec'],\n    'weekdays' => ['zondag', 'maandag', 'dinsdag', 'woensdag', 'donderdag', 'vrijdag', 'zaterdag'],\n    'weekdays_short' => ['zo', 'ma', 'di', 'wo', 'do', 'vr', 'za'],\n    'weekdays_min' => ['zo', 'ma', 'di', 'wo', 'do', 'vr', 'za'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/nl_SR.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/nl.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/nl_SX.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/nl.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/nmg.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'meridiem' => ['maná', 'kugú'],\n    'weekdays' => ['sɔ́ndɔ', 'mɔ́ndɔ', 'sɔ́ndɔ mafú mába', 'sɔ́ndɔ mafú málal', 'sɔ́ndɔ mafú mána', 'mabágá má sukul', 'sásadi'],\n    'weekdays_short' => ['sɔ́n', 'mɔ́n', 'smb', 'sml', 'smn', 'mbs', 'sas'],\n    'weekdays_min' => ['sɔ́n', 'mɔ́n', 'smb', 'sml', 'smn', 'mbs', 'sas'],\n    'months' => ['ngwɛn matáhra', 'ngwɛn ńmba', 'ngwɛn ńlal', 'ngwɛn ńna', 'ngwɛn ńtan', 'ngwɛn ńtuó', 'ngwɛn hɛmbuɛrí', 'ngwɛn lɔmbi', 'ngwɛn rɛbvuâ', 'ngwɛn wum', 'ngwɛn wum navǔr', 'krísimin'],\n    'months_short' => ['ng1', 'ng2', 'ng3', 'ng4', 'ng5', 'ng6', 'ng7', 'ng8', 'ng9', 'ng10', 'ng11', 'kris'],\n    'first_day_of_week' => 1,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'D/M/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd D MMMM YYYY HH:mm',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/nn.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - François B\n * - Alexander Tømmerås\n * - Øystein\n * - JD Isaacks\n * - Gaute Hvoslef Kvalnes (gaute)\n */\nreturn [\n    'year' => ':count år',\n    'a_year' => 'eit år|:count år',\n    'y' => ':count år',\n    'month' => ':count månad|:count månader',\n    'a_month' => 'ein månad|:count månader',\n    'm' => ':count md',\n    'week' => ':count veke|:count veker',\n    'a_week' => 'ei veke|:count veker',\n    'w' => ':countv',\n    'day' => ':count dag|:count dagar',\n    'a_day' => 'ein dag|:count dagar',\n    'd' => ':countd',\n    'hour' => ':count time|:count timar',\n    'a_hour' => 'ein time|:count timar',\n    'h' => ':countt',\n    'minute' => ':count minutt',\n    'a_minute' => 'eit minutt|:count minutt',\n    'min' => ':countm',\n    'second' => ':count sekund',\n    'a_second' => 'nokre sekund|:count sekund',\n    's' => ':counts',\n    'ago' => ':time sidan',\n    'from_now' => 'om :time',\n    'after' => ':time etter',\n    'before' => ':time før',\n    'diff_today' => 'I dag',\n    'diff_yesterday' => 'I går',\n    'diff_yesterday_regexp' => 'I går(?:\\\\s+klokka)?',\n    'diff_tomorrow' => 'I morgon',\n    'diff_tomorrow_regexp' => 'I morgon(?:\\\\s+klokka)?',\n    'diff_today_regexp' => 'I dag(?:\\\\s+klokka)?',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD.MM.YYYY',\n        'LL' => 'D. MMMM YYYY',\n        'LLL' => 'D. MMMM YYYY [kl.] H:mm',\n        'LLLL' => 'dddd D. MMMM YYYY [kl.] HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[I dag klokka] LT',\n        'nextDay' => '[I morgon klokka] LT',\n        'nextWeek' => 'dddd [klokka] LT',\n        'lastDay' => '[I går klokka] LT',\n        'lastWeek' => '[Føregåande] dddd [klokka] LT',\n        'sameElse' => 'L',\n    ],\n    'ordinal' => ':number.',\n    'months' => ['januar', 'februar', 'mars', 'april', 'mai', 'juni', 'juli', 'august', 'september', 'oktober', 'november', 'desember'],\n    'months_short' => ['jan', 'feb', 'mar', 'apr', 'mai', 'jun', 'jul', 'aug', 'sep', 'okt', 'nov', 'des'],\n    'weekdays' => ['sundag', 'måndag', 'tysdag', 'onsdag', 'torsdag', 'fredag', 'laurdag'],\n    'weekdays_short' => ['sun', 'mån', 'tys', 'ons', 'tor', 'fre', 'lau'],\n    'weekdays_min' => ['su', 'må', 'ty', 'on', 'to', 'fr', 'la'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n    'list' => [', ', ' og '],\n    'meridiem' => ['f.m.', 'e.m.'],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/nn_NO.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/nn.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/nnh.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'meridiem' => ['mbaʼámbaʼ', 'ncwònzém'],\n    'weekdays' => null,\n    'weekdays_short' => ['lyɛʼɛ́ sẅíŋtè', 'mvfò lyɛ̌ʼ', 'mbɔ́ɔntè mvfò lyɛ̌ʼ', 'tsètsɛ̀ɛ lyɛ̌ʼ', 'mbɔ́ɔntè tsetsɛ̀ɛ lyɛ̌ʼ', 'mvfò màga lyɛ̌ʼ', 'màga lyɛ̌ʼ'],\n    'weekdays_min' => null,\n    'months' => null,\n    'months_short' => ['saŋ tsetsɛ̀ɛ lùm', 'saŋ kàg ngwóŋ', 'saŋ lepyè shúm', 'saŋ cÿó', 'saŋ tsɛ̀ɛ cÿó', 'saŋ njÿoláʼ', 'saŋ tyɛ̀b tyɛ̀b mbʉ̀ŋ', 'saŋ mbʉ̀ŋ', 'saŋ ngwɔ̀ʼ mbÿɛ', 'saŋ tàŋa tsetsáʼ', 'saŋ mejwoŋó', 'saŋ lùm'],\n    'first_day_of_week' => 1,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/yy',\n        'LL' => 'D MMM, YYYY',\n        'LLL' => '[lyɛ]̌ʼ d [na] MMMM, YYYY HH:mm',\n        'LLLL' => 'dddd , [lyɛ]̌ʼ d [na] MMMM, YYYY HH:mm',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/no.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Daniel S. Billing\n * - Paul\n * - Jimmie Johansson\n * - Jens Herlevsen\n */\nreturn array_replace_recursive(require __DIR__.'/nb.php', [\n    'formats' => [\n        'LLL' => 'D. MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D. MMMM YYYY [kl.] HH:mm',\n    ],\n    'calendar' => [\n        'nextWeek' => 'på dddd [kl.] LT',\n        'lastWeek' => '[i] dddd[s kl.] LT',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/nr.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/nr_ZA.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/nr_ZA.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Zuza Software Foundation (Translate.org.za) Dwayne Bailey dwayne@translate.org.za\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD/MM/YYYY',\n    ],\n    'months' => ['Janabari', 'uFeberbari', 'uMatjhi', 'u-Apreli', 'Meyi', 'Juni', 'Julayi', 'Arhostosi', 'Septemba', 'Oktoba', 'Usinyikhaba', 'Disemba'],\n    'months_short' => ['Jan', 'Feb', 'Mat', 'Apr', 'Mey', 'Jun', 'Jul', 'Arh', 'Sep', 'Okt', 'Usi', 'Dis'],\n    'weekdays' => ['uSonto', 'uMvulo', 'uLesibili', 'lesithathu', 'uLesine', 'ngoLesihlanu', 'umGqibelo'],\n    'weekdays_short' => ['Son', 'Mvu', 'Bil', 'Tha', 'Ne', 'Hla', 'Gqi'],\n    'weekdays_min' => ['Son', 'Mvu', 'Bil', 'Tha', 'Ne', 'Hla', 'Gqi'],\n    'day_of_first_week_of_year' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/nso.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/nso_ZA.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/nso_ZA.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Zuza Software Foundation (Translate.org.za) Dwayne Bailey dwayne@translate.org.za\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD/MM/YYYY',\n    ],\n    'months' => ['Janaware', 'Febereware', 'Matšhe', 'Aprele', 'Mei', 'June', 'Julae', 'Agostose', 'Setemere', 'Oktobere', 'Nofemere', 'Disemere'],\n    'months_short' => ['Jan', 'Feb', 'Mat', 'Apr', 'Mei', 'Jun', 'Jul', 'Ago', 'Set', 'Okt', 'Nof', 'Dis'],\n    'weekdays' => ['LaMorena', 'Mošupologo', 'Labobedi', 'Laboraro', 'Labone', 'Labohlano', 'Mokibelo'],\n    'weekdays_short' => ['Son', 'Moš', 'Bed', 'Rar', 'Ne', 'Hla', 'Mok'],\n    'weekdays_min' => ['Son', 'Moš', 'Bed', 'Rar', 'Ne', 'Hla', 'Mok'],\n    'day_of_first_week_of_year' => 1,\n\n    'year' => ':count ngwaga',\n    'y' => ':count ngwaga',\n    'a_year' => ':count ngwaga',\n\n    'month' => ':count Kgwedi',\n    'm' => ':count Kgwedi',\n    'a_month' => ':count Kgwedi',\n\n    'week' => ':count Beke',\n    'w' => ':count Beke',\n    'a_week' => ':count Beke',\n\n    'day' => ':count Letšatši',\n    'd' => ':count Letšatši',\n    'a_day' => ':count Letšatši',\n\n    'hour' => ':count Iri',\n    'h' => ':count Iri',\n    'a_hour' => ':count Iri',\n\n    'minute' => ':count Motsotso',\n    'min' => ':count Motsotso',\n    'a_minute' => ':count Motsotso',\n\n    'second' => ':count motsotswana',\n    's' => ':count motsotswana',\n    'a_second' => ':count motsotswana',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/nus.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'meridiem' => ['RW', 'TŊ'],\n    'weekdays' => ['Cäŋ kuɔth', 'Jiec la̱t', 'Rɛw lätni', 'Diɔ̱k lätni', 'Ŋuaan lätni', 'Dhieec lätni', 'Bäkɛl lätni'],\n    'weekdays_short' => ['Cäŋ', 'Jiec', 'Rɛw', 'Diɔ̱k', 'Ŋuaan', 'Dhieec', 'Bäkɛl'],\n    'weekdays_min' => ['Cäŋ', 'Jiec', 'Rɛw', 'Diɔ̱k', 'Ŋuaan', 'Dhieec', 'Bäkɛl'],\n    'months' => ['Tiop thar pɛt', 'Pɛt', 'Duɔ̱ɔ̱ŋ', 'Guak', 'Duät', 'Kornyoot', 'Pay yie̱tni', 'Tho̱o̱r', 'Tɛɛr', 'Laath', 'Kur', 'Tio̱p in di̱i̱t'],\n    'months_short' => ['Tiop', 'Pɛt', 'Duɔ̱ɔ̱', 'Guak', 'Duä', 'Kor', 'Pay', 'Thoo', 'Tɛɛ', 'Laa', 'Kur', 'Tid'],\n    'first_day_of_week' => 1,\n    'formats' => [\n        'LT' => 'h:mm a',\n        'LTS' => 'h:mm:ss a',\n        'L' => 'D/MM/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY h:mm a',\n        'LLLL' => 'dddd D MMMM YYYY h:mm a',\n    ],\n\n    'year' => ':count jiök', // less reliable\n    'y' => ':count jiök', // less reliable\n    'a_year' => ':count jiök', // less reliable\n\n    'month' => ':count pay', // less reliable\n    'm' => ':count pay', // less reliable\n    'a_month' => ':count pay', // less reliable\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/nyn.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'weekdays' => ['Sande', 'Orwokubanza', 'Orwakabiri', 'Orwakashatu', 'Orwakana', 'Orwakataano', 'Orwamukaaga'],\n    'weekdays_short' => ['SAN', 'ORK', 'OKB', 'OKS', 'OKN', 'OKT', 'OMK'],\n    'weekdays_min' => ['SAN', 'ORK', 'OKB', 'OKS', 'OKN', 'OKT', 'OMK'],\n    'months' => ['Okwokubanza', 'Okwakabiri', 'Okwakashatu', 'Okwakana', 'Okwakataana', 'Okwamukaaga', 'Okwamushanju', 'Okwamunaana', 'Okwamwenda', 'Okwaikumi', 'Okwaikumi na kumwe', 'Okwaikumi na ibiri'],\n    'months_short' => ['KBZ', 'KBR', 'KST', 'KKN', 'KTN', 'KMK', 'KMS', 'KMN', 'KMW', 'KKM', 'KNK', 'KNB'],\n    'first_day_of_week' => 1,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY HH:mm',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/oc.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Quentí\n */\n// @codeCoverageIgnoreStart\nuse Symfony\\Component\\Translation\\PluralizationRules;\n\nif (class_exists('Symfony\\\\Component\\\\Translation\\\\PluralizationRules')) {\n    PluralizationRules::set(static function ($number) {\n        return $number == 1 ? 0 : 1;\n    }, 'oc');\n}\n// @codeCoverageIgnoreEnd\n\nreturn [\n    'year' => ':count an|:count ans',\n    'a_year' => 'un an|:count ans',\n    'y' => ':count an|:count ans',\n    'month' => ':count mes|:count meses',\n    'a_month' => 'un mes|:count meses',\n    'm' => ':count mes|:count meses',\n    'week' => ':count setmana|:count setmanas',\n    'a_week' => 'una setmana|:count setmanas',\n    'w' => ':count setmana|:count setmanas',\n    'day' => ':count jorn|:count jorns',\n    'a_day' => 'un jorn|:count jorns',\n    'd' => ':count jorn|:count jorns',\n    'hour' => ':count ora|:count oras',\n    'a_hour' => 'una ora|:count oras',\n    'h' => ':count ora|:count oras',\n    'minute' => ':count minuta|:count minutas',\n    'a_minute' => 'una minuta|:count minutas',\n    'min' => ':count minuta|:count minutas',\n    'second' => ':count segonda|:count segondas',\n    'a_second' => 'una segonda|:count segondas',\n    's' => ':count segonda|:count segondas',\n    'ago' => 'fa :time',\n    'from_now' => 'd\\'aquí :time',\n    'after' => ':time aprèp',\n    'before' => ':time abans',\n    'diff_now' => 'ara meteis',\n    'diff_today' => 'Uèi',\n    'diff_today_regexp' => 'Uèi(?:\\\\s+a)?',\n    'diff_yesterday' => 'ièr',\n    'diff_yesterday_regexp' => 'Ièr(?:\\\\s+a)?',\n    'diff_tomorrow' => 'deman',\n    'diff_tomorrow_regexp' => 'Deman(?:\\\\s+a)?',\n    'diff_before_yesterday' => 'ièr delà',\n    'diff_after_tomorrow' => 'deman passat',\n    'period_recurrences' => ':count còp|:count còps',\n    'period_interval' => 'cada :interval',\n    'period_start_date' => 'de :date',\n    'period_end_date' => 'fins a :date',\n    'formats' => [\n        'LT' => 'H:mm',\n        'LTS' => 'H:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM [de] YYYY',\n        'LLL' => 'D MMMM [de] YYYY [a] H:mm',\n        'LLLL' => 'dddd D MMMM [de] YYYY [a] H:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[Uèi a] LT',\n        'nextDay' => '[Deman a] LT',\n        'nextWeek' => 'dddd [a] LT',\n        'lastDay' => '[Ièr a] LT',\n        'lastWeek' => 'dddd [passat a] LT',\n        'sameElse' => 'L',\n    ],\n    'months' => ['de genièr', 'de febrièr', 'de març', 'd\\'abrial', 'de mai', 'de junh', 'de julhet', 'd\\'agost', 'de setembre', 'd’octòbre', 'de novembre', 'de decembre'],\n    'months_standalone' => ['genièr', 'febrièr', 'març', 'abrial', 'mai', 'junh', 'julh', 'agost', 'setembre', 'octòbre', 'novembre', 'decembre'],\n    'months_short' => ['gen.', 'feb.', 'març', 'abr.', 'mai', 'junh', 'julh', 'ago.', 'sep.', 'oct.', 'nov.', 'dec.'],\n    'weekdays' => ['dimenge', 'diluns', 'dimars', 'dimècres', 'dijòus', 'divendres', 'dissabte'],\n    'weekdays_short' => ['dg', 'dl', 'dm', 'dc', 'dj', 'dv', 'ds'],\n    'weekdays_min' => ['dg', 'dl', 'dm', 'dc', 'dj', 'dv', 'ds'],\n    'ordinal' => function ($number, string $period = '') {\n        $ordinal = [1 => 'èr', 2 => 'nd'][(int) $number] ?? 'en';\n\n        // feminine for year, week, hour, minute, second\n        if (preg_match('/^[yYwWhHgGis]$/', $period)) {\n            $ordinal .= 'a';\n        }\n\n        return $number.$ordinal;\n    },\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n    'list' => [', ', ' e '],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/oc_FR.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/oc.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/om.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Ge'ez Frontier Foundation & Sagalee Oromoo Publishing Co. Inc.    locales@geez.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'dd-MMM-YYYY',\n        'LLL' => 'dd MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, MMMM D, YYYY HH:mm',\n    ],\n    'months' => ['Amajjii', 'Guraandhala', 'Bitooteessa', 'Elba', 'Caamsa', 'Waxabajjii', 'Adooleessa', 'Hagayya', 'Fuulbana', 'Onkololeessa', 'Sadaasa', 'Muddee'],\n    'months_short' => ['Ama', 'Gur', 'Bit', 'Elb', 'Cam', 'Wax', 'Ado', 'Hag', 'Ful', 'Onk', 'Sad', 'Mud'],\n    'weekdays' => ['Dilbata', 'Wiixata', 'Qibxata', 'Roobii', 'Kamiisa', 'Jimaata', 'Sanbata'],\n    'weekdays_short' => ['Dil', 'Wix', 'Qib', 'Rob', 'Kam', 'Jim', 'San'],\n    'weekdays_min' => ['Dil', 'Wix', 'Qib', 'Rob', 'Kam', 'Jim', 'San'],\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['WD', 'WB'],\n\n    'year' => 'wggoota :count',\n    'y' => 'wggoota :count',\n    'a_year' => 'wggoota :count',\n\n    'month' => 'ji’a :count',\n    'm' => 'ji’a :count',\n    'a_month' => 'ji’a :count',\n\n    'week' => 'torban :count',\n    'w' => 'torban :count',\n    'a_week' => 'torban :count',\n\n    'day' => 'guyyaa :count',\n    'd' => 'guyyaa :count',\n    'a_day' => 'guyyaa :count',\n\n    'hour' => 'saʼaatii :count',\n    'h' => 'saʼaatii :count',\n    'a_hour' => 'saʼaatii :count',\n\n    'minute' => 'daqiiqaa :count',\n    'min' => 'daqiiqaa :count',\n    'a_minute' => 'daqiiqaa :count',\n\n    'second' => 'sekoondii :count',\n    's' => 'sekoondii :count',\n    'a_second' => 'sekoondii :count',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/om_ET.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/om.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/om_KE.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/om.php', [\n    'day_of_first_week_of_year' => 0,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/or.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/or_IN.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/or_IN.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - IBM AP Linux Technology Center, Yamato Software Laboratory    bug-glibc@gnu.org\n */\nreturn [\n    'diff_now' => 'ବର୍ତ୍ତମାନ',\n    'diff_yesterday' => 'ଗତକାଲି',\n    'diff_tomorrow' => 'ଆସନ୍ତାକାଲି',\n    'formats' => [\n        'LT' => 'Oh:Om A',\n        'LTS' => 'Oh:Om:Os A',\n        'L' => 'OD-OM-OY',\n        'LL' => 'OD MMMM OY',\n        'LLL' => 'OD MMMM OY Oh:Om A',\n        'LLLL' => 'dddd OD MMMM OY Oh:Om A',\n    ],\n    'months' => ['ଜାନୁଆରୀ', 'ଫେବୃଆରୀ', 'ମାର୍ଚ୍ଚ', 'ଅପ୍ରେଲ', 'ମଇ', 'ଜୁନ', 'ଜୁଲାଇ', 'ଅଗଷ୍ଟ', 'ସେପ୍ଟେମ୍ବର', 'ଅକ୍ଟୋବର', 'ନଭେମ୍ବର', 'ଡିସେମ୍ବର'],\n    'months_short' => ['ଜାନୁଆରୀ', 'ଫେବୃଆରୀ', 'ମାର୍ଚ୍ଚ', 'ଅପ୍ରେଲ', 'ମଇ', 'ଜୁନ', 'ଜୁଲାଇ', 'ଅଗଷ୍ଟ', 'ସେପ୍ଟେମ୍ବର', 'ଅକ୍ଟୋବର', 'ନଭେମ୍ବର', 'ଡିସେମ୍ବର'],\n    'weekdays' => ['ରବିବାର', 'ସୋମବାର', 'ମଙ୍ଗଳବାର', 'ବୁଧବାର', 'ଗୁରୁବାର', 'ଶୁକ୍ରବାର', 'ଶନିବାର'],\n    'weekdays_short' => ['ରବି', 'ସୋମ', 'ମଙ୍ଗଳ', 'ବୁଧ', 'ଗୁରୁ', 'ଶୁକ୍ର', 'ଶନି'],\n    'weekdays_min' => ['ରବି', 'ସୋମ', 'ମଙ୍ଗଳ', 'ବୁଧ', 'ଗୁରୁ', 'ଶୁକ୍ର', 'ଶନି'],\n    'day_of_first_week_of_year' => 1,\n    'alt_numbers' => ['୦', '୧', '୨', '୩', '୪', '୫', '୬', '୭', '୮', '୯', '୧୦', '୧୧', '୧୨', '୧୩', '୧୪', '୧୫', '୧୬', '୧୭', '୧୮', '୧୯', '୨୦', '୨୧', '୨୨', '୨୩', '୨୪', '୨୫', '୨୬', '୨୭', '୨୮', '୨୯', '୩୦', '୩୧', '୩୨', '୩୩', '୩୪', '୩୫', '୩୬', '୩୭', '୩୮', '୩୯', '୪୦', '୪୧', '୪୨', '୪୩', '୪୪', '୪୫', '୪୬', '୪୭', '୪୮', '୪୯', '୫୦', '୫୧', '୫୨', '୫୩', '୫୪', '୫୫', '୫୬', '୫୭', '୫୮', '୫୯', '୬୦', '୬୧', '୬୨', '୬୩', '୬୪', '୬୫', '୬୬', '୬୭', '୬୮', '୬୯', '୭୦', '୭୧', '୭୨', '୭୩', '୭୪', '୭୫', '୭୬', '୭୭', '୭୮', '୭୯', '୮୦', '୮୧', '୮୨', '୮୩', '୮୪', '୮୫', '୮୬', '୮୭', '୮୮', '୮୯', '୯୦', '୯୧', '୯୨', '୯୩', '୯୪', '୯୫', '୯୬', '୯୭', '୯୮', '୯୯'],\n    'year' => ':count ବର୍ଷ',\n    'y' => ':count ବ.',\n    'month' => ':count ମାସ',\n    'm' => ':count ମା.',\n    'week' => ':count ସପ୍ତାହ',\n    'w' => ':count ସପ୍ତା.',\n    'day' => ':count ଦିନ',\n    'd' => ':count ଦିନ',\n    'hour' => ':count ଘଣ୍ତ',\n    'h' => ':count ଘ.',\n    'minute' => ':count ମିନଟ',\n    'min' => ':count ମି.',\n    'second' => ':count ସେକଣ୍ଢ',\n    's' => ':count ସେ.',\n    'ago' => ':time ପୂର୍ବେ',\n    'from_now' => ':timeରେ',\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/os.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/os_RU.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/os_RU.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD.MM.YYYY',\n    ],\n    'months' => ['январы', 'февралы', 'мартъийы', 'апрелы', 'майы', 'июны', 'июлы', 'августы', 'сентябры', 'октябры', 'ноябры', 'декабры'],\n    'months_short' => ['Янв', 'Фев', 'Мар', 'Апр', 'Май', 'Июн', 'Июл', 'Авг', 'Сен', 'Окт', 'Ноя', 'Дек'],\n    'weekdays' => ['Хуыцаубон', 'Къуырисæр', 'Дыццæг', 'Æртыццæг', 'Цыппæрæм', 'Майрæмбон', 'Сабат'],\n    'weekdays_short' => ['Хцб', 'Крс', 'Дцг', 'Æрт', 'Цпр', 'Мрб', 'Сбт'],\n    'weekdays_min' => ['Хцб', 'Крс', 'Дцг', 'Æрт', 'Цпр', 'Мрб', 'Сбт'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n\n    'minute' => ':count гыццыл', // less reliable\n    'min' => ':count гыццыл', // less reliable\n    'a_minute' => ':count гыццыл', // less reliable\n\n    'second' => ':count æндæр', // less reliable\n    's' => ':count æндæр', // less reliable\n    'a_second' => ':count æндæр', // less reliable\n\n    'year' => ':count аз',\n    'y' => ':count аз',\n    'a_year' => ':count аз',\n\n    'month' => ':count мӕй',\n    'm' => ':count мӕй',\n    'a_month' => ':count мӕй',\n\n    'week' => ':count къуыри',\n    'w' => ':count къуыри',\n    'a_week' => ':count къуыри',\n\n    'day' => ':count бон',\n    'd' => ':count бон',\n    'a_day' => ':count бон',\n\n    'hour' => ':count сахат',\n    'h' => ':count сахат',\n    'a_hour' => ':count сахат',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/pa.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Philippe Vaucher\n * - Tsutomu Kuroda\n * - Punjab\n */\nreturn [\n    'year' => 'ਇੱਕ ਸਾਲ|:count ਸਾਲ',\n    'month' => 'ਇੱਕ ਮਹੀਨਾ|:count ਮਹੀਨੇ',\n    'week' => 'ਹਫਤਾ|:count ਹਫ਼ਤੇ',\n    'day' => 'ਇੱਕ ਦਿਨ|:count ਦਿਨ',\n    'hour' => 'ਇੱਕ ਘੰਟਾ|:count ਘੰਟੇ',\n    'minute' => 'ਇਕ ਮਿੰਟ|:count ਮਿੰਟ',\n    'second' => 'ਕੁਝ ਸਕਿੰਟ|:count ਸਕਿੰਟ',\n    'ago' => ':time ਪਹਿਲਾਂ',\n    'from_now' => ':time ਵਿੱਚ',\n    'before' => ':time ਤੋਂ ਪਹਿਲਾਂ',\n    'after' => ':time ਤੋਂ ਬਾਅਦ',\n    'diff_now' => 'ਹੁਣ',\n    'diff_today' => 'ਅਜ',\n    'diff_yesterday' => 'ਕਲ',\n    'diff_tomorrow' => 'ਕਲ',\n    'formats' => [\n        'LT' => 'A h:mm ਵਜੇ',\n        'LTS' => 'A h:mm:ss ਵਜੇ',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY, A h:mm ਵਜੇ',\n        'LLLL' => 'dddd, D MMMM YYYY, A h:mm ਵਜੇ',\n    ],\n    'calendar' => [\n        'sameDay' => '[ਅਜ] LT',\n        'nextDay' => '[ਕਲ] LT',\n        'nextWeek' => '[ਅਗਲਾ] dddd, LT',\n        'lastDay' => '[ਕਲ] LT',\n        'lastWeek' => '[ਪਿਛਲੇ] dddd, LT',\n        'sameElse' => 'L',\n    ],\n    'meridiem' => function ($hour) {\n        if ($hour < 4) {\n            return 'ਰਾਤ';\n        }\n        if ($hour < 10) {\n            return 'ਸਵੇਰ';\n        }\n        if ($hour < 17) {\n            return 'ਦੁਪਹਿਰ';\n        }\n        if ($hour < 20) {\n            return 'ਸ਼ਾਮ';\n        }\n\n        return 'ਰਾਤ';\n    },\n    'months' => ['ਜਨਵਰੀ', 'ਫ਼ਰਵਰੀ', 'ਮਾਰਚ', 'ਅਪ੍ਰੈਲ', 'ਮਈ', 'ਜੂਨ', 'ਜੁਲਾਈ', 'ਅਗਸਤ', 'ਸਤੰਬਰ', 'ਅਕਤੂਬਰ', 'ਨਵੰਬਰ', 'ਦਸੰਬਰ'],\n    'months_short' => ['ਜਨਵਰੀ', 'ਫ਼ਰਵਰੀ', 'ਮਾਰਚ', 'ਅਪ੍ਰੈਲ', 'ਮਈ', 'ਜੂਨ', 'ਜੁਲਾਈ', 'ਅਗਸਤ', 'ਸਤੰਬਰ', 'ਅਕਤੂਬਰ', 'ਨਵੰਬਰ', 'ਦਸੰਬਰ'],\n    'weekdays' => ['ਐਤਵਾਰ', 'ਸੋਮਵਾਰ', 'ਮੰਗਲਵਾਰ', 'ਬੁਧਵਾਰ', 'ਵੀਰਵਾਰ', 'ਸ਼ੁੱਕਰਵਾਰ', 'ਸ਼ਨੀਚਰਵਾਰ'],\n    'weekdays_short' => ['ਐਤ', 'ਸੋਮ', 'ਮੰਗਲ', 'ਬੁਧ', 'ਵੀਰ', 'ਸ਼ੁਕਰ', 'ਸ਼ਨੀ'],\n    'weekdays_min' => ['ਐਤ', 'ਸੋਮ', 'ਮੰਗਲ', 'ਬੁਧ', 'ਵੀਰ', 'ਸ਼ੁਕਰ', 'ਸ਼ਨੀ'],\n    'first_day_of_week' => 0,\n    'day_of_first_week_of_year' => 1,\n    'list' => [', ', ' ਅਤੇ '],\n    'weekend' => [0, 0],\n    'alt_numbers' => ['੦', '੧', '੨', '੩', '੪', '੫', '੬', '੭', '੮', '੯'],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/pa_Arab.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/ur.php', [\n    'weekdays' => ['اتوار', 'پیر', 'منگل', 'بُدھ', 'جمعرات', 'جمعہ', 'ہفتہ'],\n    'weekdays_short' => ['اتوار', 'پیر', 'منگل', 'بُدھ', 'جمعرات', 'جمعہ', 'ہفتہ'],\n    'weekdays_min' => ['اتوار', 'پیر', 'منگل', 'بُدھ', 'جمعرات', 'جمعہ', 'ہفتہ'],\n    'months' => ['جنوری', 'فروری', 'مارچ', 'اپریل', 'مئ', 'جون', 'جولائی', 'اگست', 'ستمبر', 'اکتوبر', 'نومبر', 'دسمبر'],\n    'months_short' => ['جنوری', 'فروری', 'مارچ', 'اپریل', 'مئ', 'جون', 'جولائی', 'اگست', 'ستمبر', 'اکتوبر', 'نومبر', 'دسمبر'],\n    'formats' => [\n        'LT' => 'h:mm a',\n        'LTS' => 'h:mm:ss a',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY h:mm a',\n        'LLLL' => 'dddd, DD MMMM YYYY h:mm a',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/pa_Guru.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/pa.php', [\n    'formats' => [\n        'LT' => 'h:mm a',\n        'LTS' => 'h:mm:ss a',\n        'L' => 'D/M/yy',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY, h:mm a',\n        'LLLL' => 'dddd, D MMMM YYYY, h:mm a',\n    ],\n    'months' => ['ਜਨਵਰੀ', 'ਫ਼ਰਵਰੀ', 'ਮਾਰਚ', 'ਅਪ੍ਰੈਲ', 'ਮਈ', 'ਜੂਨ', 'ਜੁਲਾਈ', 'ਅਗਸਤ', 'ਸਤੰਬਰ', 'ਅਕਤੂਬਰ', 'ਨਵੰਬਰ', 'ਦਸੰਬਰ'],\n    'months_short' => ['ਜਨ', 'ਫ਼ਰ', 'ਮਾਰਚ', 'ਅਪ੍ਰੈ', 'ਮਈ', 'ਜੂਨ', 'ਜੁਲਾ', 'ਅਗ', 'ਸਤੰ', 'ਅਕਤੂ', 'ਨਵੰ', 'ਦਸੰ'],\n    'weekdays' => ['ਐਤਵਾਰ', 'ਸੋਮਵਾਰ', 'ਮੰਗਲਵਾਰ', 'ਬੁੱਧਵਾਰ', 'ਵੀਰਵਾਰ', 'ਸ਼ੁੱਕਰਵਾਰ', 'ਸ਼ਨਿੱਚਰਵਾਰ'],\n    'weekdays_short' => ['ਐਤ', 'ਸੋਮ', 'ਮੰਗਲ', 'ਬੁੱਧ', 'ਵੀਰ', 'ਸ਼ੁੱਕਰ', 'ਸ਼ਨਿੱਚਰ'],\n    'weekdays_min' => ['ਐਤ', 'ਸੋਮ', 'ਮੰਗ', 'ਬੁੱਧ', 'ਵੀਰ', 'ਸ਼ੁੱਕ', 'ਸ਼ਨਿੱ'],\n    'weekend' => [0, 0],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/pa_IN.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Guo Xiang Tan\n * - Josh Soref\n * - Ash\n * - harpreetkhalsagtbit\n */\nreturn require __DIR__.'/pa.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/pa_PK.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD/MM/YYYY',\n    ],\n    'months' => ['جنوري', 'فروري', 'مارچ', 'اپريل', 'مٓی', 'جون', 'جولاي', 'اگست', 'ستمبر', 'اكتوبر', 'نومبر', 'دسمبر'],\n    'months_short' => ['جنوري', 'فروري', 'مارچ', 'اپريل', 'مٓی', 'جون', 'جولاي', 'اگست', 'ستمبر', 'اكتوبر', 'نومبر', 'دسمبر'],\n    'weekdays' => ['اتوار', 'پير', 'منگل', 'بدھ', 'جمعرات', 'جمعه', 'هفته'],\n    'weekdays_short' => ['اتوار', 'پير', 'منگل', 'بدھ', 'جمعرات', 'جمعه', 'هفته'],\n    'weekdays_min' => ['اتوار', 'پير', 'منگل', 'بدھ', 'جمعرات', 'جمعه', 'هفته'],\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['ص', 'ش'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/pap.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn [\n    'formats' => [\n        'LT' => 'HH.mm',\n        'LTS' => 'HH.mm:ss',\n        'L' => 'DD-MM-YY',\n        'LL' => 'MMMM [di] DD, YYYY',\n        'LLL' => 'DD MMM HH.mm',\n        'LLLL' => 'MMMM DD, YYYY HH.mm',\n    ],\n    'months' => ['yanüari', 'febrüari', 'mart', 'aprel', 'mei', 'yüni', 'yüli', 'ougùstùs', 'sèptèmber', 'oktober', 'novèmber', 'desèmber'],\n    'months_short' => ['yan', 'feb', 'mar', 'apr', 'mei', 'yün', 'yül', 'oug', 'sèp', 'okt', 'nov', 'des'],\n    'weekdays' => ['djadomingo', 'djaluna', 'djamars', 'djawebs', 'djarason', 'djabierne', 'djasabra'],\n    'weekdays_short' => ['do', 'lu', 'ma', 'we', 'ra', 'bi', 'sa'],\n    'weekdays_min' => ['do', 'lu', 'ma', 'we', 'ra', 'bi', 'sa'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n    'year' => ':count aña',\n    'month' => ':count luna',\n    'week' => ':count siman',\n    'day' => ':count dia',\n    'hour' => ':count ora',\n    'minute' => ':count minüt',\n    'second' => ':count sekònde',\n    'list' => [', ', ' i '],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/pap_AW.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - information from native speaker Pablo Saratxaga pablo@mandrakesoft.com\n */\nreturn require __DIR__.'/pap.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/pap_CW.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - information from native speaker Pablo Saratxaga pablo@mandrakesoft.com\n */\nreturn require __DIR__.'/pap.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/pl.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Wacław Jacek\n * - François B\n * - Tim Fish\n * - Serhan Apaydın\n * - Massimiliano Caniparoli\n * - JD Isaacks\n * - Jakub Szwacz\n * - Jan\n * - Paul\n * - damlys\n * - Marek (marast78)\n * - Peter (UnrulyNatives)\n * - Qrzysio\n * - Jan (aso824)\n * - diverpl\n */\n\nuse Carbon\\CarbonInterface;\n\nreturn [\n    'year' => ':count rok|:count lata|:count lat',\n    'a_year' => 'rok|:count lata|:count lat',\n    'y' => ':count r|:count l|:count l',\n    'month' => ':count miesiąc|:count miesiące|:count miesięcy',\n    'a_month' => 'miesiąc|:count miesiące|:count miesięcy',\n    'm' => ':count mies.',\n    'week' => ':count tydzień|:count tygodnie|:count tygodni',\n    'a_week' => 'tydzień|:count tygodnie|:count tygodni',\n    'w' => ':count tyg.',\n    'day' => ':count dzień|:count dni|:count dni',\n    'a_day' => 'dzień|:count dni|:count dni',\n    'd' => ':count d',\n    'hour' => ':count godzina|:count godziny|:count godzin',\n    'a_hour' => 'godzina|:count godziny|:count godzin',\n    'h' => ':count godz.',\n    'minute' => ':count minuta|:count minuty|:count minut',\n    'a_minute' => 'minuta|:count minuty|:count minut',\n    'min' => ':count min',\n    'second' => ':count sekunda|:count sekundy|:count sekund',\n    'a_second' => '{1}kilka sekund|:count sekunda|:count sekundy|:count sekund',\n    's' => ':count sek.',\n    'ago' => ':time temu',\n    'from_now' => static function ($time) {\n        return 'za '.strtr($time, [\n            'godzina' => 'godzinę',\n            'minuta' => 'minutę',\n            'sekunda' => 'sekundę',\n        ]);\n    },\n    'after' => ':time po',\n    'before' => ':time przed',\n    'diff_now' => 'teraz',\n    'diff_today' => 'Dziś',\n    'diff_today_regexp' => 'Dziś(?:\\\\s+o)?',\n    'diff_yesterday' => 'wczoraj',\n    'diff_yesterday_regexp' => 'Wczoraj(?:\\\\s+o)?',\n    'diff_tomorrow' => 'jutro',\n    'diff_tomorrow_regexp' => 'Jutro(?:\\\\s+o)?',\n    'diff_before_yesterday' => 'przedwczoraj',\n    'diff_after_tomorrow' => 'pojutrze',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD.MM.YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[Dziś o] LT',\n        'nextDay' => '[Jutro o] LT',\n        'nextWeek' => function (CarbonInterface $date) {\n            switch ($date->dayOfWeek) {\n                case 0:\n                    return '[W niedzielę o] LT';\n                case 2:\n                    return '[We wtorek o] LT';\n                case 3:\n                    return '[W środę o] LT';\n                case 6:\n                    return '[W sobotę o] LT';\n                default:\n                    return '[W] dddd [o] LT';\n            }\n        },\n        'lastDay' => '[Wczoraj o] LT',\n        'lastWeek' => function (CarbonInterface $date) {\n            switch ($date->dayOfWeek) {\n                case 0:\n                    return '[W zeszłą niedzielę o] LT';\n                case 3:\n                    return '[W zeszłą środę o] LT';\n                case 6:\n                    return '[W zeszłą sobotę o] LT';\n                default:\n                    return '[W zeszły] dddd [o] LT';\n            }\n        },\n        'sameElse' => 'L',\n    ],\n    'ordinal' => ':number.',\n    'months' => ['stycznia', 'lutego', 'marca', 'kwietnia', 'maja', 'czerwca', 'lipca', 'sierpnia', 'września', 'października', 'listopada', 'grudnia'],\n    'months_standalone' => ['styczeń', 'luty', 'marzec', 'kwiecień', 'maj', 'czerwiec', 'lipiec', 'sierpień', 'wrzesień', 'październik', 'listopad', 'grudzień'],\n    'months_short' => ['sty', 'lut', 'mar', 'kwi', 'maj', 'cze', 'lip', 'sie', 'wrz', 'paź', 'lis', 'gru'],\n    'months_regexp' => '/(DD?o?\\.?(\\[[^\\[\\]]*\\]|\\s)+MMMM?|L{2,4}|l{2,4})/',\n    'weekdays' => ['niedziela', 'poniedziałek', 'wtorek', 'środa', 'czwartek', 'piątek', 'sobota'],\n    'weekdays_short' => ['ndz', 'pon', 'wt', 'śr', 'czw', 'pt', 'sob'],\n    'weekdays_min' => ['Nd', 'Pn', 'Wt', 'Śr', 'Cz', 'Pt', 'So'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n    'list' => [', ', ' i '],\n    'meridiem' => ['przed południem', 'po południu'],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/pl_PL.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/pl.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/prg.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'months' => ['M01', 'M02', 'M03', 'M04', 'M05', 'M06', 'M07', 'M08', 'M09', 'M10', 'M11', 'M12'],\n    'months_short' => ['M01', 'M02', 'M03', 'M04', 'M05', 'M06', 'M07', 'M08', 'M09', 'M10', 'M11', 'M12'],\n    'first_day_of_week' => 1,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'YYYY-MM-dd',\n        'LL' => 'YYYY MMM D',\n        'LLL' => 'YYYY MMMM D HH:mm',\n        'LLLL' => 'YYYY MMMM D, dddd HH:mm',\n    ],\n\n    'year' => ':count meta',\n    'y' => ':count meta',\n    'a_year' => ':count meta',\n\n    'month' => ':count mēniks', // less reliable\n    'm' => ':count mēniks', // less reliable\n    'a_month' => ':count mēniks', // less reliable\n\n    'week' => ':count sawaītin', // less reliable\n    'w' => ':count sawaītin', // less reliable\n    'a_week' => ':count sawaītin', // less reliable\n\n    'day' => ':count di',\n    'd' => ':count di',\n    'a_day' => ':count di',\n\n    'hour' => ':count bruktēt', // less reliable\n    'h' => ':count bruktēt', // less reliable\n    'a_hour' => ':count bruktēt', // less reliable\n\n    'minute' => ':count līkuts', // less reliable\n    'min' => ':count līkuts', // less reliable\n    'a_minute' => ':count līkuts', // less reliable\n\n    'second' => ':count kitan', // less reliable\n    's' => ':count kitan', // less reliable\n    'a_second' => ':count kitan', // less reliable\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ps.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Muhammad Nasir Rahimi\n * - Nassim Nasibullah (spinzar)\n */\nreturn [\n    'year' => ':count کال|:count کاله',\n    'y' => ':countکال|:countکاله',\n    'month' => ':count مياشت|:count مياشتي',\n    'm' => ':countمياشت|:countمياشتي',\n    'week' => ':count اونۍ|:count اونۍ',\n    'w' => ':countاونۍ|:countاونۍ',\n    'day' => ':count ورځ|:count ورځي',\n    'd' => ':countورځ|:countورځي',\n    'hour' => ':count ساعت|:count ساعته',\n    'h' => ':countساعت|:countساعته',\n    'minute' => ':count دقيقه|:count دقيقې',\n    'min' => ':countدقيقه|:countدقيقې',\n    'second' => ':count ثانيه|:count ثانيې',\n    's' => ':countثانيه|:countثانيې',\n    'ago' => ':time دمخه',\n    'from_now' => ':time له اوس څخه',\n    'after' => ':time وروسته',\n    'before' => ':time دمخه',\n    'list' => ['، ', ' او '],\n    'meridiem' => ['غ.م.', 'غ.و.'],\n    'weekdays' => ['اتوار', 'ګل', 'نهه', 'شورو', 'زيارت', 'جمعه', 'خالي'],\n    'weekdays_short' => ['ا', 'ګ', 'ن', 'ش', 'ز', 'ج', 'خ'],\n    'weekdays_min' => ['ا', 'ګ', 'ن', 'ش', 'ز', 'ج', 'خ'],\n    'months' => ['جنوري', 'فبروري', 'مارچ', 'اپریل', 'مۍ', 'جون', 'جولای', 'اگست', 'سېپتمبر', 'اکتوبر', 'نومبر', 'دسمبر'],\n    'months_short' => ['جنوري', 'فبروري', 'مارچ', 'اپریل', 'مۍ', 'جون', 'جولای', 'اگست', 'سېپتمبر', 'اکتوبر', 'نومبر', 'دسمبر'],\n    'months_standalone' => ['جنوري', 'فېبروري', 'مارچ', 'اپریل', 'مۍ', 'جون', 'جولای', 'اگست', 'سپتمبر', 'اکتوبر', 'نومبر', 'دسمبر'],\n    'months_short_standalone' => ['جنوري', 'فبروري', 'مارچ', 'اپریل', 'مۍ', 'جون', 'جولای', 'اگست', 'سپتمبر', 'اکتوبر', 'نومبر', 'دسمبر'],\n    'first_day_of_week' => 6,\n    'weekend' => [4, 5],\n    'formats' => [\n        'LT' => 'H:mm',\n        'LTS' => 'H:mm:ss',\n        'L' => 'YYYY/M/d',\n        'LL' => 'YYYY MMM D',\n        'LLL' => 'د YYYY د MMMM D H:mm',\n        'LLLL' => 'dddd د YYYY د MMMM D H:mm',\n    ],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ps_AF.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/ps.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/pt.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Cassiano Montanari\n * - Matt Pope\n * - François B\n * - Prodis\n * - JD Isaacks\n * - Raphael Amorim\n * - João Magalhães\n * - victortobias\n * - Paulo Freitas\n * - Sebastian Thierer\n * - Claudson Martins (claudsonm)\n */\n\nuse Carbon\\CarbonInterface;\n\nreturn [\n    'year' => ':count ano|:count anos',\n    'a_year' => 'um ano|:count anos',\n    'y' => ':counta',\n    'month' => ':count mês|:count meses',\n    'a_month' => 'um mês|:count meses',\n    'm' => ':countm',\n    'week' => ':count semana|:count semanas',\n    'a_week' => 'uma semana|:count semanas',\n    'w' => ':countsem',\n    'day' => ':count dia|:count dias',\n    'a_day' => 'um dia|:count dias',\n    'd' => ':countd',\n    'hour' => ':count hora|:count horas',\n    'a_hour' => 'uma hora|:count horas',\n    'h' => ':counth',\n    'minute' => ':count minuto|:count minutos',\n    'a_minute' => 'um minuto|:count minutos',\n    'min' => ':countmin',\n    'second' => ':count segundo|:count segundos',\n    'a_second' => 'alguns segundos|:count segundos',\n    's' => ':counts',\n    'millisecond' => ':count milissegundo|:count milissegundos',\n    'a_millisecond' => 'um milissegundo|:count milissegundos',\n    'ms' => ':countms',\n    'microsecond' => ':count microssegundo|:count microssegundos',\n    'a_microsecond' => 'um microssegundo|:count microssegundos',\n    'µs' => ':countµs',\n    'ago' => 'há :time',\n    'from_now' => 'em :time',\n    'after' => ':time depois',\n    'before' => ':time antes',\n    'diff_now' => 'agora',\n    'diff_today' => 'Hoje',\n    'diff_today_regexp' => 'Hoje(?:\\\\s+às)?',\n    'diff_yesterday' => 'ontem',\n    'diff_yesterday_regexp' => 'Ontem(?:\\\\s+às)?',\n    'diff_tomorrow' => 'amanhã',\n    'diff_tomorrow_regexp' => 'Amanhã(?:\\\\s+às)?',\n    'diff_before_yesterday' => 'anteontem',\n    'diff_after_tomorrow' => 'depois de amanhã',\n    'period_recurrences' => 'uma vez|:count vezes',\n    'period_interval' => 'cada :interval',\n    'period_start_date' => 'de :date',\n    'period_end_date' => 'até :date',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D [de] MMMM [de] YYYY',\n        'LLL' => 'D [de] MMMM [de] YYYY HH:mm',\n        'LLLL' => 'dddd, D [de] MMMM [de] YYYY HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[Hoje às] LT',\n        'nextDay' => '[Amanhã às] LT',\n        'nextWeek' => 'dddd [às] LT',\n        'lastDay' => '[Ontem às] LT',\n        'lastWeek' => function (CarbonInterface $date) {\n            switch ($date->dayOfWeek) {\n                case 0:\n                case 6:\n                    return '[Último] dddd [às] LT';\n                default:\n                    return '[Última] dddd [às] LT';\n            }\n        },\n        'sameElse' => 'L',\n    ],\n    'ordinal' => ':numberº',\n    'months' => ['janeiro', 'fevereiro', 'março', 'abril', 'maio', 'junho', 'julho', 'agosto', 'setembro', 'outubro', 'novembro', 'dezembro'],\n    'months_short' => ['jan', 'fev', 'mar', 'abr', 'mai', 'jun', 'jul', 'ago', 'set', 'out', 'nov', 'dez'],\n    'weekdays' => ['domingo', 'segunda-feira', 'terça-feira', 'quarta-feira', 'quinta-feira', 'sexta-feira', 'sábado'],\n    'weekdays_short' => ['dom', 'seg', 'ter', 'qua', 'qui', 'sex', 'sáb'],\n    'weekdays_min' => ['Do', '2ª', '3ª', '4ª', '5ª', '6ª', 'Sá'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n    'list' => [', ', ' e '],\n    'ordinal_words' => [\n        'of' => 'de',\n        'first' => 'primeira',\n        'second' => 'segunda',\n        'third' => 'terceira',\n        'fourth' => 'quarta',\n        'fifth' => 'quinta',\n        'last' => 'última',\n    ],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/pt_AO.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/pt.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/pt_BR.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Cassiano Montanari\n * - Eduardo Dalla Vecchia\n * - David Rodrigues\n * - Matt Pope\n * - François B\n * - Prodis\n * - Marlon Maxwel\n * - JD Isaacks\n * - Raphael Amorim\n * - Rafael Raupp\n * - felipeleite1\n * - swalker\n * - Lucas Macedo\n * - Paulo Freitas\n * - Sebastian Thierer\n */\nreturn array_replace_recursive(require __DIR__.'/pt.php', [\n    'period_recurrences' => 'uma|:count vez',\n    'period_interval' => 'toda :interval',\n    'formats' => [\n        'LLL' => 'D [de] MMMM [de] YYYY [às] HH:mm',\n        'LLLL' => 'dddd, D [de] MMMM [de] YYYY [às] HH:mm',\n    ],\n    'first_day_of_week' => 0,\n    'day_of_first_week_of_year' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/pt_CH.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/pt.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/pt_CV.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/pt.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/pt_GQ.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/pt.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/pt_GW.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/pt.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/pt_LU.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/pt.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/pt_MO.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/pt.php', [\n    'formats' => [\n        'LT' => 'h:mm a',\n        'LTS' => 'h:mm:ss a',\n        'LLL' => 'D [de] MMMM [de] YYYY, h:mm a',\n        'LLLL' => 'dddd, D [de] MMMM [de] YYYY, h:mm a',\n    ],\n    'first_day_of_week' => 0,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/pt_MZ.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/pt.php', [\n    'first_day_of_week' => 0,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/pt_PT.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - RAP    bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/pt.php', [\n    'formats' => [\n        'L' => 'DD/MM/YYYY',\n    ],\n    'months' => ['janeiro', 'fevereiro', 'março', 'abril', 'maio', 'junho', 'julho', 'agosto', 'setembro', 'outubro', 'novembro', 'dezembro'],\n    'months_short' => ['jan', 'fev', 'mar', 'abr', 'mai', 'jun', 'jul', 'ago', 'set', 'out', 'nov', 'dez'],\n    'weekdays' => ['domingo', 'segunda', 'terça', 'quarta', 'quinta', 'sexta', 'sábado'],\n    'weekdays_short' => ['dom', 'seg', 'ter', 'qua', 'qui', 'sex', 'sáb'],\n    'weekdays_min' => ['dom', 'seg', 'ter', 'qua', 'qui', 'sex', 'sáb'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/pt_ST.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/pt.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/pt_TL.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/pt.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/qu.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/es_UY.php', [\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM, YYYY HH:mm',\n    ],\n    'first_day_of_week' => 0,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/qu_BO.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/qu.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/qu_EC.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/qu.php', [\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/quz.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/quz_PE.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/quz_PE.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Sugar Labs // OLPC sugarlabs.org libc-alpha@sourceware.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD/MM/YY',\n    ],\n    'months' => ['iniru', 'phiwriru', 'marsu', 'awril', 'mayu', 'huniyu', 'huliyu', 'agustu', 'siptiyimri', 'uktuwri', 'nuwiyimri', 'tisiyimri'],\n    'months_short' => ['ini', 'phi', 'mar', 'awr', 'may', 'hun', 'hul', 'agu', 'sip', 'ukt', 'nuw', 'tis'],\n    'weekdays' => ['tuminku', 'lunis', 'martis', 'miyirkulis', 'juywis', 'wiyirnis', 'sawatu'],\n    'weekdays_short' => ['tum', 'lun', 'mar', 'miy', 'juy', 'wiy', 'saw'],\n    'weekdays_min' => ['tum', 'lun', 'mar', 'miy', 'juy', 'wiy', 'saw'],\n    'day_of_first_week_of_year' => 1,\n\n    'minute' => ':count uchuy', // less reliable\n    'min' => ':count uchuy', // less reliable\n    'a_minute' => ':count uchuy', // less reliable\n\n    'year' => ':count wata',\n    'y' => ':count wata',\n    'a_year' => ':count wata',\n\n    'month' => ':count killa',\n    'm' => ':count killa',\n    'a_month' => ':count killa',\n\n    'week' => ':count simana',\n    'w' => ':count simana',\n    'a_week' => ':count simana',\n\n    'day' => ':count pʼunchaw',\n    'd' => ':count pʼunchaw',\n    'a_day' => ':count pʼunchaw',\n\n    'hour' => ':count ura',\n    'h' => ':count ura',\n    'a_hour' => ':count ura',\n\n    'second' => ':count iskay ñiqin',\n    's' => ':count iskay ñiqin',\n    'a_second' => ':count iskay ñiqin',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/raj.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/raj_IN.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/raj_IN.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - meghrajsuthar03@gmail.com\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'D/M/YY',\n    ],\n    'months' => ['जनवरी', 'फरवरी', 'मार्च', 'अप्रैल', 'मई', 'जून', 'जुलाई', 'अगस्त', 'सितंबर', 'अक्टूबर', 'नवंबर', 'दिसंबर'],\n    'months_short' => ['जन', 'फर', 'मार्च', 'अप्रै', 'मई', 'जून', 'जुल', 'अग', 'सित', 'अक्टू', 'नव', 'दिस'],\n    'weekdays' => ['रविवार', 'सोमवार', 'मंगल्लवार', 'बुधवार', 'बृहस्पतिवार', 'शुक्रवार', 'शनिवार'],\n    'weekdays_short' => ['रवि', 'सोम', 'मंगल', 'बुध', 'बृहस्पति', 'शुक्र', 'शनि'],\n    'weekdays_min' => ['रवि', 'सोम', 'मंगल', 'बुध', 'बृहस्पति', 'शुक्र', 'शनि'],\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['पूर्वाह्न', 'अपराह्न'],\n\n    'year' => ':count आंहू', // less reliable\n    'y' => ':count आंहू', // less reliable\n    'a_year' => ':count आंहू', // less reliable\n\n    'month' => ':count सूरज', // less reliable\n    'm' => ':count सूरज', // less reliable\n    'a_month' => ':count सूरज', // less reliable\n\n    'week' => ':count निवाज', // less reliable\n    'w' => ':count निवाज', // less reliable\n    'a_week' => ':count निवाज', // less reliable\n\n    'day' => ':count अेक', // less reliable\n    'd' => ':count अेक', // less reliable\n    'a_day' => ':count अेक', // less reliable\n\n    'hour' => ':count दुनियांण', // less reliable\n    'h' => ':count दुनियांण', // less reliable\n    'a_hour' => ':count दुनियांण', // less reliable\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/rm.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Philippe Vaucher\n * - tjku\n * - Max Melentiev\n * - Juanito Fatas\n * - Tsutomu Kuroda\n * - Akira Matsuda\n * - Christopher Dell\n * - Enrique Vidal\n * - Simone Carletti\n * - Aaron Patterson\n * - Nicolás Hock Isaza\n * - sebastian de castelberg\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD.MM.YYYY',\n        'LL' => 'Do MMMM YYYY',\n        'LLL' => 'Do MMMM, HH:mm [Uhr]',\n        'LLLL' => 'dddd, Do MMMM YYYY, HH:mm [Uhr]',\n    ],\n    'year' => ':count onn|:count onns',\n    'month' => ':count mais',\n    'week' => ':count emna|:count emnas',\n    'day' => ':count di|:count dis',\n    'hour' => ':count oura|:count ouras',\n    'minute' => ':count minuta|:count minutas',\n    'second' => ':count secunda|:count secundas',\n    'weekdays' => ['dumengia', 'glindesdi', 'mardi', 'mesemna', 'gievgia', 'venderdi', 'sonda'],\n    'weekdays_short' => ['du', 'gli', 'ma', 'me', 'gie', 've', 'so'],\n    'weekdays_min' => ['du', 'gli', 'ma', 'me', 'gie', 've', 'so'],\n    'months' => ['schaner', 'favrer', 'mars', 'avrigl', 'matg', 'zercladur', 'fanadur', 'avust', 'settember', 'october', 'november', 'december'],\n    'months_short' => ['schan', 'favr', 'mars', 'avr', 'matg', 'zercl', 'fan', 'avust', 'sett', 'oct', 'nov', 'dec'],\n    'meridiem' => ['avantmezdi', 'suentermezdi'],\n    'list' => [', ', ' e '],\n    'first_day_of_week' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/rn.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'meridiem' => ['Z.MU.', 'Z.MW.'],\n    'weekdays' => ['Ku w’indwi', 'Ku wa mbere', 'Ku wa kabiri', 'Ku wa gatatu', 'Ku wa kane', 'Ku wa gatanu', 'Ku wa gatandatu'],\n    'weekdays_short' => ['cu.', 'mbe.', 'kab.', 'gtu.', 'kan.', 'gnu.', 'gnd.'],\n    'weekdays_min' => ['cu.', 'mbe.', 'kab.', 'gtu.', 'kan.', 'gnu.', 'gnd.'],\n    'months' => ['Nzero', 'Ruhuhuma', 'Ntwarante', 'Ndamukiza', 'Rusama', 'Ruheshi', 'Mukakaro', 'Nyandagaro', 'Nyakanga', 'Gitugutu', 'Munyonyo', 'Kigarama'],\n    'months_short' => ['Mut.', 'Gas.', 'Wer.', 'Mat.', 'Gic.', 'Kam.', 'Nya.', 'Kan.', 'Nze.', 'Ukw.', 'Ugu.', 'Uku.'],\n    'first_day_of_week' => 1,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'D/M/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd D MMMM YYYY HH:mm',\n    ],\n\n    'year' => 'imyaka :count',\n    'y' => 'imyaka :count',\n    'a_year' => 'imyaka :count',\n\n    'month' => 'amezi :count',\n    'm' => 'amezi :count',\n    'a_month' => 'amezi :count',\n\n    'week' => 'indwi :count',\n    'w' => 'indwi :count',\n    'a_week' => 'indwi :count',\n\n    'day' => 'imisi :count',\n    'd' => 'imisi :count',\n    'a_day' => 'imisi :count',\n\n    'hour' => 'amasaha :count',\n    'h' => 'amasaha :count',\n    'a_hour' => 'amasaha :count',\n\n    'minute' => 'iminuta :count',\n    'min' => 'iminuta :count',\n    'a_minute' => 'iminuta :count',\n\n    'second' => 'inguvu :count', // less reliable\n    's' => 'inguvu :count', // less reliable\n    'a_second' => 'inguvu :count', // less reliable\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ro.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Josh Soref\n * - JD Isaacks\n * - Cătălin Georgescu\n * - Valentin Ivaşcu (oriceon)\n */\nreturn [\n    'year' => ':count an|:count ani|:count ani',\n    'a_year' => 'un an|:count ani|:count ani',\n    'y' => ':count a.',\n    'month' => ':count lună|:count luni|:count luni',\n    'a_month' => 'o lună|:count luni|:count luni',\n    'm' => ':count l.',\n    'week' => ':count săptămână|:count săptămâni|:count săptămâni',\n    'a_week' => 'o săptămână|:count săptămâni|:count săptămâni',\n    'w' => ':count săp.',\n    'day' => ':count zi|:count zile|:count zile',\n    'a_day' => 'o zi|:count zile|:count zile',\n    'd' => ':count z.',\n    'hour' => ':count oră|:count ore|:count ore',\n    'a_hour' => 'o oră|:count ore|:count ore',\n    'h' => ':count o.',\n    'minute' => ':count minut|:count minute|:count minute',\n    'a_minute' => 'un minut|:count minute|:count minute',\n    'min' => ':count m.',\n    'second' => ':count secundă|:count secunde|:count secunde',\n    'a_second' => 'câteva secunde|:count secunde|:count secunde',\n    's' => ':count sec.',\n    'ago' => ':time în urmă',\n    'from_now' => 'peste :time',\n    'after' => 'peste :time',\n    'before' => 'acum :time',\n    'diff_now' => 'acum',\n    'diff_today' => 'azi',\n    'diff_today_regexp' => 'azi(?:\\\\s+la)?',\n    'diff_yesterday' => 'ieri',\n    'diff_yesterday_regexp' => 'ieri(?:\\\\s+la)?',\n    'diff_tomorrow' => 'mâine',\n    'diff_tomorrow_regexp' => 'mâine(?:\\\\s+la)?',\n    'formats' => [\n        'LT' => 'H:mm',\n        'LTS' => 'H:mm:ss',\n        'L' => 'DD.MM.YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY H:mm',\n        'LLLL' => 'dddd, D MMMM YYYY H:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[azi la] LT',\n        'nextDay' => '[mâine la] LT',\n        'nextWeek' => 'dddd [la] LT',\n        'lastDay' => '[ieri la] LT',\n        'lastWeek' => '[fosta] dddd [la] LT',\n        'sameElse' => 'L',\n    ],\n    'months' => ['ianuarie', 'februarie', 'martie', 'aprilie', 'mai', 'iunie', 'iulie', 'august', 'septembrie', 'octombrie', 'noiembrie', 'decembrie'],\n    'months_short' => ['ian.', 'feb.', 'mar.', 'apr.', 'mai', 'iun.', 'iul.', 'aug.', 'sept.', 'oct.', 'nov.', 'dec.'],\n    'weekdays' => ['duminică', 'luni', 'marți', 'miercuri', 'joi', 'vineri', 'sâmbătă'],\n    'weekdays_short' => ['dum', 'lun', 'mar', 'mie', 'joi', 'vin', 'sâm'],\n    'weekdays_min' => ['du', 'lu', 'ma', 'mi', 'jo', 'vi', 'sâ'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n    'list' => [', ', ' și '],\n    'meridiem' => ['a.m.', 'p.m.'],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ro_MD.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/ro.php', [\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD.MM.YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY, HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY, HH:mm',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ro_RO.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/ro.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/rof.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'meridiem' => ['kang’ama', 'kingoto'],\n    'weekdays' => ['Ijumapili', 'Ijumatatu', 'Ijumanne', 'Ijumatano', 'Alhamisi', 'Ijumaa', 'Ijumamosi'],\n    'weekdays_short' => ['Ijp', 'Ijt', 'Ijn', 'Ijtn', 'Alh', 'Iju', 'Ijm'],\n    'weekdays_min' => ['Ijp', 'Ijt', 'Ijn', 'Ijtn', 'Alh', 'Iju', 'Ijm'],\n    'months' => ['Mweri wa kwanza', 'Mweri wa kaili', 'Mweri wa katatu', 'Mweri wa kaana', 'Mweri wa tanu', 'Mweri wa sita', 'Mweri wa saba', 'Mweri wa nane', 'Mweri wa tisa', 'Mweri wa ikumi', 'Mweri wa ikumi na moja', 'Mweri wa ikumi na mbili'],\n    'months_short' => ['M1', 'M2', 'M3', 'M4', 'M5', 'M6', 'M7', 'M8', 'M9', 'M10', 'M11', 'M12'],\n    'first_day_of_week' => 1,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY HH:mm',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ru.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Bari Badamshin\n * - Jørn Ølmheim\n * - François B\n * - Tim Fish\n * - Коренберг Марк (imac)\n * - Serhan Apaydın\n * - RomeroMsk\n * - vsn4ik\n * - JD Isaacks\n * - Bari Badamshin\n * - Jørn Ølmheim\n * - François B\n * - Коренберг Марк (imac)\n * - Serhan Apaydın\n * - RomeroMsk\n * - vsn4ik\n * - JD Isaacks\n * - Fellzo\n * - andrey-helldar\n * - Pavel Skripkin (psxx)\n * - AlexWalkerson\n * - Vladislav UnsealedOne\n * - dima-bzz\n */\n\nuse Carbon\\CarbonInterface;\n\n$transformDiff = function ($input) {\n    return strtr($input, [\n        'неделя' => 'неделю',\n        'секунда' => 'секунду',\n        'минута' => 'минуту',\n    ]);\n};\n\nreturn [\n    'year' => ':count год|:count года|:count лет',\n    'y' => ':count г.|:count г.|:count л.',\n    'a_year' => '{1}год|:count год|:count года|:count лет',\n    'month' => ':count месяц|:count месяца|:count месяцев',\n    'm' => ':count мес.',\n    'a_month' => '{1}месяц|:count месяц|:count месяца|:count месяцев',\n    'week' => ':count неделя|:count недели|:count недель',\n    'w' => ':count нед.',\n    'a_week' => '{1}неделя|:count неделю|:count недели|:count недель',\n    'day' => ':count день|:count дня|:count дней',\n    'd' => ':count д.',\n    'a_day' => '{1}день|:count день|:count дня|:count дней',\n    'hour' => ':count час|:count часа|:count часов',\n    'h' => ':count ч.',\n    'a_hour' => '{1}час|:count час|:count часа|:count часов',\n    'minute' => ':count минута|:count минуты|:count минут',\n    'min' => ':count мин.',\n    'a_minute' => '{1}минута|:count минута|:count минуты|:count минут',\n    'second' => ':count секунда|:count секунды|:count секунд',\n    's' => ':count сек.',\n    'a_second' => '{1}несколько секунд|:count секунду|:count секунды|:count секунд',\n    'ago' => function ($time) use ($transformDiff) {\n        return $transformDiff($time).' назад';\n    },\n    'from_now' => function ($time) use ($transformDiff) {\n        return 'через '.$transformDiff($time);\n    },\n    'after' => function ($time) use ($transformDiff) {\n        return $transformDiff($time).' после';\n    },\n    'before' => function ($time) use ($transformDiff) {\n        return $transformDiff($time).' до';\n    },\n    'diff_now' => 'только что',\n    'diff_today' => 'Сегодня,',\n    'diff_today_regexp' => 'Сегодня,?(?:\\\\s+в)?',\n    'diff_yesterday' => 'вчера',\n    'diff_yesterday_regexp' => 'Вчера,?(?:\\\\s+в)?',\n    'diff_tomorrow' => 'завтра',\n    'diff_tomorrow_regexp' => 'Завтра,?(?:\\\\s+в)?',\n    'diff_before_yesterday' => 'позавчера',\n    'diff_after_tomorrow' => 'послезавтра',\n    'formats' => [\n        'LT' => 'H:mm',\n        'LTS' => 'H:mm:ss',\n        'L' => 'DD.MM.YYYY',\n        'LL' => 'D MMMM YYYY г.',\n        'LLL' => 'D MMMM YYYY г., H:mm',\n        'LLLL' => 'dddd, D MMMM YYYY г., H:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[Сегодня, в] LT',\n        'nextDay' => '[Завтра, в] LT',\n        'nextWeek' => function (CarbonInterface $current, CarbonInterface $other) {\n            if ($current->week !== $other->week) {\n                switch ($current->dayOfWeek) {\n                    case 0:\n                        return '[В следующее] dddd, [в] LT';\n                    case 1:\n                    case 2:\n                    case 4:\n                        return '[В следующий] dddd, [в] LT';\n                    case 3:\n                    case 5:\n                    case 6:\n                        return '[В следующую] dddd, [в] LT';\n                }\n            }\n\n            if ($current->dayOfWeek === 2) {\n                return '[Во] dddd, [в] LT';\n            }\n\n            return '[В] dddd, [в] LT';\n        },\n        'lastDay' => '[Вчера, в] LT',\n        'lastWeek' => function (CarbonInterface $current, CarbonInterface $other) {\n            if ($current->week !== $other->week) {\n                switch ($current->dayOfWeek) {\n                    case 0:\n                        return '[В прошлое] dddd, [в] LT';\n                    case 1:\n                    case 2:\n                    case 4:\n                        return '[В прошлый] dddd, [в] LT';\n                    case 3:\n                    case 5:\n                    case 6:\n                        return '[В прошлую] dddd, [в] LT';\n                }\n            }\n\n            if ($current->dayOfWeek === 2) {\n                return '[Во] dddd, [в] LT';\n            }\n\n            return '[В] dddd, [в] LT';\n        },\n        'sameElse' => 'L',\n    ],\n    'ordinal' => function ($number, $period) {\n        switch ($period) {\n            case 'M':\n            case 'd':\n            case 'DDD':\n                return $number.'-й';\n            case 'D':\n                return $number.'-го';\n            case 'w':\n            case 'W':\n                return $number.'-я';\n            default:\n                return $number;\n        }\n    },\n    'meridiem' => function ($hour) {\n        if ($hour < 4) {\n            return 'ночи';\n        }\n        if ($hour < 12) {\n            return 'утра';\n        }\n        if ($hour < 17) {\n            return 'дня';\n        }\n\n        return 'вечера';\n    },\n    'months' => ['января', 'февраля', 'марта', 'апреля', 'мая', 'июня', 'июля', 'августа', 'сентября', 'октября', 'ноября', 'декабря'],\n    'months_standalone' => ['январь', 'февраль', 'март', 'апрель', 'май', 'июнь', 'июль', 'август', 'сентябрь', 'октябрь', 'ноябрь', 'декабрь'],\n    'months_short' => ['янв', 'фев', 'мар', 'апр', 'мая', 'июн', 'июл', 'авг', 'сен', 'окт', 'ноя', 'дек'],\n    'months_short_standalone' => ['янв', 'фев', 'мар', 'апр', 'май', 'июн', 'июл', 'авг', 'сен', 'окт', 'ноя', 'дек'],\n    'months_regexp' => '/(DD?o?\\.?(\\[[^\\[\\]]*\\]|\\s)+MMMM?|L{2,4}|l{2,4})/',\n    'weekdays' => ['воскресенье', 'понедельник', 'вторник', 'среду', 'четверг', 'пятницу', 'субботу'],\n    'weekdays_standalone' => ['воскресенье', 'понедельник', 'вторник', 'среда', 'четверг', 'пятница', 'суббота'],\n    'weekdays_short' => ['вск', 'пнд', 'втр', 'срд', 'чтв', 'птн', 'сбт'],\n    'weekdays_min' => ['вс', 'пн', 'вт', 'ср', 'чт', 'пт', 'сб'],\n    'weekdays_regexp' => '/\\[\\s*(В|в)\\s*((?:прошлую|следующую|эту)\\s*)?\\]\\s*dddd/',\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n    'list' => [', ', ' и '],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ru_BY.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/ru.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ru_KG.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/ru.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ru_KZ.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/ru.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ru_MD.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/ru.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ru_RU.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/ru.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ru_UA.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - RFC 2319    bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/ru.php', [\n    'weekdays' => ['воскресенье', 'понедельник', 'вторник', 'среда', 'четверг', 'пятница', 'суббота'],\n    'weekdays_short' => ['вск', 'пнд', 'вто', 'срд', 'чтв', 'птн', 'суб'],\n    'weekdays_min' => ['вс', 'пн', 'вт', 'ср', 'чт', 'пт', 'су'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/rw.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/rw_RW.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/rw_RW.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Rwanda Steve Murphy murf@e-tools.com\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD.MM.YYYY',\n    ],\n    'months' => ['Mutarama', 'Gashyantare', 'Werurwe', 'Mata', 'Gicuransi', 'Kamena', 'Nyakanga', 'Kanama', 'Nzeli', 'Ukwakira', 'Ugushyingo', 'Ukuboza'],\n    'months_short' => ['Mut', 'Gas', 'Wer', 'Mat', 'Gic', 'Kam', 'Nya', 'Kan', 'Nze', 'Ukw', 'Ugu', 'Uku'],\n    'weekdays' => ['Ku cyumweru', 'Kuwa mbere', 'Kuwa kabiri', 'Kuwa gatatu', 'Kuwa kane', 'Kuwa gatanu', 'Kuwa gatandatu'],\n    'weekdays_short' => ['Mwe', 'Mbe', 'Kab', 'Gtu', 'Kan', 'Gnu', 'Gnd'],\n    'weekdays_min' => ['Mwe', 'Mbe', 'Kab', 'Gtu', 'Kan', 'Gnu', 'Gnd'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n\n    'second' => ':count vuna', // less reliable\n    's' => ':count vuna', // less reliable\n    'a_second' => ':count vuna', // less reliable\n\n    'year' => 'aka :count',\n    'y' => 'aka :count',\n    'a_year' => 'aka :count',\n\n    'month' => 'ezi :count',\n    'm' => 'ezi :count',\n    'a_month' => 'ezi :count',\n\n    'week' => ':count icyumweru',\n    'w' => ':count icyumweru',\n    'a_week' => ':count icyumweru',\n\n    'day' => ':count nsi',\n    'd' => ':count nsi',\n    'a_day' => ':count nsi',\n\n    'hour' => 'saha :count',\n    'h' => 'saha :count',\n    'a_hour' => 'saha :count',\n\n    'minute' => ':count -nzinya',\n    'min' => ':count -nzinya',\n    'a_minute' => ':count -nzinya',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/rwk.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'meridiem' => ['utuko', 'kyiukonyi'],\n    'weekdays' => ['Jumapilyi', 'Jumatatuu', 'Jumanne', 'Jumatanu', 'Alhamisi', 'Ijumaa', 'Jumamosi'],\n    'weekdays_short' => ['Jpi', 'Jtt', 'Jnn', 'Jtn', 'Alh', 'Iju', 'Jmo'],\n    'weekdays_min' => ['Jpi', 'Jtt', 'Jnn', 'Jtn', 'Alh', 'Iju', 'Jmo'],\n    'months' => ['Januari', 'Februari', 'Machi', 'Aprilyi', 'Mei', 'Junyi', 'Julyai', 'Agusti', 'Septemba', 'Oktoba', 'Novemba', 'Desemba'],\n    'months_short' => ['Jan', 'Feb', 'Mac', 'Apr', 'Mei', 'Jun', 'Jul', 'Ago', 'Sep', 'Okt', 'Nov', 'Des'],\n    'first_day_of_week' => 1,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY HH:mm',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/sa.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/sa_IN.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/sa_IN.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - The Debian project Christian Perrier bubulle@debian.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'D-MM-YY',\n    ],\n    'months' => ['जनवरी', 'फ़रवरी', 'मार्च', 'अप्रेल', 'मई', 'जून', 'जुलाई', 'अगस्त', 'सितम्बर', 'अक्टूबर', 'नवम्बर', 'दिसम्बर'],\n    'months_short' => ['जनवरी', 'फ़रवरी', 'मार्च', 'अप्रेल', 'मई', 'जून', 'जुलाई', 'अगस्त', 'सितम्बर', 'अक्टूबर', 'नवम्बर', 'दिसम्बर'],\n    'weekdays' => ['रविवासर:', 'सोमवासर:', 'मंगलवासर:', 'बुधवासर:', 'बृहस्पतिवासरः', 'शुक्रवासर', 'शनिवासर:'],\n    'weekdays_short' => ['रविः', 'सोम:', 'मंगल:', 'बुध:', 'बृहस्पतिः', 'शुक्र', 'शनि:'],\n    'weekdays_min' => ['रविः', 'सोम:', 'मंगल:', 'बुध:', 'बृहस्पतिः', 'शुक्र', 'शनि:'],\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['पूर्वाह्न', 'अपराह्न'],\n\n    'minute' => ':count होरा', // less reliable\n    'min' => ':count होरा', // less reliable\n    'a_minute' => ':count होरा', // less reliable\n\n    'year' => ':count वर्ष',\n    'y' => ':count वर्ष',\n    'a_year' => ':count वर्ष',\n\n    'month' => ':count मास',\n    'm' => ':count मास',\n    'a_month' => ':count मास',\n\n    'week' => ':count सप्ताहः saptahaĥ',\n    'w' => ':count सप्ताहः saptahaĥ',\n    'a_week' => ':count सप्ताहः saptahaĥ',\n\n    'day' => ':count दिन',\n    'd' => ':count दिन',\n    'a_day' => ':count दिन',\n\n    'hour' => ':count घण्टा',\n    'h' => ':count घण्टा',\n    'a_hour' => ':count घण्टा',\n\n    'second' => ':count द्वितीयः',\n    's' => ':count द्वितीयः',\n    'a_second' => ':count द्वितीयः',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/sah.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/sah_RU.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/sah_RU.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Valery Timiriliyev Valery Timiriliyev timiriliyev@gmail.com\n */\nreturn array_replace_recursive(require __DIR__.'/ru.php', [\n    'formats' => [\n        'L' => 'YYYY.MM.DD',\n    ],\n    'months' => ['тохсунньу', 'олунньу', 'кулун тутар', 'муус устар', 'ыам ыйын', 'бэс ыйын', 'от ыйын', 'атырдьах ыйын', 'балаҕан ыйын', 'алтынньы', 'сэтинньи', 'ахсынньы'],\n    'months_short' => ['тохс', 'олун', 'кул', 'муус', 'ыам', 'бэс', 'от', 'атыр', 'бал', 'алт', 'сэт', 'ахс'],\n    'weekdays' => ['баскыһыанньа', 'бэнидиэнньик', 'оптуорунньук', 'сэрэдэ', 'чэппиэр', 'бээтинсэ', 'субуота'],\n    'weekdays_short' => ['бс', 'бн', 'оп', 'ср', 'чп', 'бт', 'сб'],\n    'weekdays_min' => ['бс', 'бн', 'оп', 'ср', 'чп', 'бт', 'сб'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/saq.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'meridiem' => ['Tesiran', 'Teipa'],\n    'weekdays' => ['Mderot ee are', 'Mderot ee kuni', 'Mderot ee ong’wan', 'Mderot ee inet', 'Mderot ee ile', 'Mderot ee sapa', 'Mderot ee kwe'],\n    'weekdays_short' => ['Are', 'Kun', 'Ong', 'Ine', 'Ile', 'Sap', 'Kwe'],\n    'weekdays_min' => ['Are', 'Kun', 'Ong', 'Ine', 'Ile', 'Sap', 'Kwe'],\n    'months' => ['Lapa le obo', 'Lapa le waare', 'Lapa le okuni', 'Lapa le ong’wan', 'Lapa le imet', 'Lapa le ile', 'Lapa le sapa', 'Lapa le isiet', 'Lapa le saal', 'Lapa le tomon', 'Lapa le tomon obo', 'Lapa le tomon waare'],\n    'months_short' => ['Obo', 'Waa', 'Oku', 'Ong', 'Ime', 'Ile', 'Sap', 'Isi', 'Saa', 'Tom', 'Tob', 'Tow'],\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY HH:mm',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/sat.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/sat_IN.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/sat_IN.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Red Hat Pune    libc-alpha@sourceware.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'D/M/YY',\n    ],\n    'months' => ['जनवरी', 'फरवरी', 'मार्च', 'अप्रेल', 'मई', 'जुन', 'जुलाई', 'अगस्त', 'सितम्बर', 'अखथबर', 'नवम्बर', 'दिसम्बर'],\n    'months_short' => ['जनवरी', 'फरवरी', 'मार्च', 'अप्रेल', 'मई', 'जुन', 'जुलाई', 'अगस्त', 'सितम्बर', 'अखथबर', 'नवम्बर', 'दिसम्बर'],\n    'weekdays' => ['सिंगेमाँहाँ', 'ओतेमाँहाँ', 'बालेमाँहाँ', 'सागुनमाँहाँ', 'सारदीमाँहाँ', 'जारुममाँहाँ', 'ञुहुममाँहाँ'],\n    'weekdays_short' => ['सिंगे', 'ओते', 'बाले', 'सागुन', 'सारदी', 'जारुम', 'ञुहुम'],\n    'weekdays_min' => ['सिंगे', 'ओते', 'बाले', 'सागुन', 'सारदी', 'जारुम', 'ञुहुम'],\n    'day_of_first_week_of_year' => 1,\n\n    'month' => ':count ńindạ cando', // less reliable\n    'm' => ':count ńindạ cando', // less reliable\n    'a_month' => ':count ńindạ cando', // less reliable\n\n    'week' => ':count mãhã', // less reliable\n    'w' => ':count mãhã', // less reliable\n    'a_week' => ':count mãhã', // less reliable\n\n    'hour' => ':count ᱥᱳᱱᱚ', // less reliable\n    'h' => ':count ᱥᱳᱱᱚ', // less reliable\n    'a_hour' => ':count ᱥᱳᱱᱚ', // less reliable\n\n    'minute' => ':count ᱯᱤᱞᱪᱩ', // less reliable\n    'min' => ':count ᱯᱤᱞᱪᱩ', // less reliable\n    'a_minute' => ':count ᱯᱤᱞᱪᱩ', // less reliable\n\n    'second' => ':count ar', // less reliable\n    's' => ':count ar', // less reliable\n    'a_second' => ':count ar', // less reliable\n\n    'year' => ':count ne̲s',\n    'y' => ':count ne̲s',\n    'a_year' => ':count ne̲s',\n\n    'day' => ':count ᱫᱤᱱ',\n    'd' => ':count ᱫᱤᱱ',\n    'a_day' => ':count ᱫᱤᱱ',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/sbp.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'meridiem' => ['Lwamilawu', 'Pashamihe'],\n    'weekdays' => ['Mulungu', 'Jumatatu', 'Jumanne', 'Jumatano', 'Alahamisi', 'Ijumaa', 'Jumamosi'],\n    'weekdays_short' => ['Mul', 'Jtt', 'Jnn', 'Jtn', 'Alh', 'Iju', 'Jmo'],\n    'weekdays_min' => ['Mul', 'Jtt', 'Jnn', 'Jtn', 'Alh', 'Iju', 'Jmo'],\n    'months' => ['Mupalangulwa', 'Mwitope', 'Mushende', 'Munyi', 'Mushende Magali', 'Mujimbi', 'Mushipepo', 'Mupuguto', 'Munyense', 'Mokhu', 'Musongandembwe', 'Muhaano'],\n    'months_short' => ['Mup', 'Mwi', 'Msh', 'Mun', 'Mag', 'Muj', 'Msp', 'Mpg', 'Mye', 'Mok', 'Mus', 'Muh'],\n    'first_day_of_week' => 1,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY HH:mm',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/sc.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/sc_IT.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/sc_IT.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Sardinian Translators Team Massimeddu Cireddu massimeddu@gmail.com\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD. MM. YY',\n    ],\n    'months' => ['Ghennàrgiu', 'Freàrgiu', 'Martzu', 'Abrile', 'Maju', 'Làmpadas', 'Argiolas//Trìulas', 'Austu', 'Cabudanni', 'Santugaine//Ladàmine', 'Onniasantu//Santandria', 'Nadale//Idas'],\n    'months_short' => ['Ghe', 'Fre', 'Mar', 'Abr', 'Maj', 'Làm', 'Arg', 'Aus', 'Cab', 'Lad', 'Onn', 'Nad'],\n    'weekdays' => ['Domìnigu', 'Lunis', 'Martis', 'Mèrcuris', 'Giòbia', 'Chenàbura', 'Sàbadu'],\n    'weekdays_short' => ['Dom', 'Lun', 'Mar', 'Mèr', 'Giò', 'Che', 'Sàb'],\n    'weekdays_min' => ['Dom', 'Lun', 'Mar', 'Mèr', 'Giò', 'Che', 'Sàb'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n\n    'minute' => ':count mementu', // less reliable\n    'min' => ':count mementu', // less reliable\n    'a_minute' => ':count mementu', // less reliable\n\n    'year' => ':count annu',\n    'y' => ':count annu',\n    'a_year' => ':count annu',\n\n    'month' => ':count mese',\n    'm' => ':count mese',\n    'a_month' => ':count mese',\n\n    'week' => ':count chida',\n    'w' => ':count chida',\n    'a_week' => ':count chida',\n\n    'day' => ':count dí',\n    'd' => ':count dí',\n    'a_day' => ':count dí',\n\n    'hour' => ':count ora',\n    'h' => ':count ora',\n    'a_hour' => ':count ora',\n\n    'second' => ':count secundu',\n    's' => ':count secundu',\n    'a_second' => ':count secundu',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/sd.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n$months = [\n    'جنوري',\n    'فيبروري',\n    'مارچ',\n    'اپريل',\n    'مئي',\n    'جون',\n    'جولاءِ',\n    'آگسٽ',\n    'سيپٽمبر',\n    'آڪٽوبر',\n    'نومبر',\n    'ڊسمبر',\n];\n\n$weekdays = [\n    'آچر',\n    'سومر',\n    'اڱارو',\n    'اربع',\n    'خميس',\n    'جمع',\n    'ڇنڇر',\n];\n\n/*\n * Authors:\n * - Narain Sagar\n * - Sawood Alam\n * - Narain Sagar\n */\nreturn [\n    'year' => '{1}'.'هڪ سال'.'|:count '.'سال',\n    'month' => '{1}'.'هڪ مهينو'.'|:count '.'مهينا',\n    'week' => '{1}'.'ھڪ ھفتو'.'|:count '.'هفتا',\n    'day' => '{1}'.'هڪ ڏينهن'.'|:count '.'ڏينهن',\n    'hour' => '{1}'.'هڪ ڪلاڪ'.'|:count '.'ڪلاڪ',\n    'minute' => '{1}'.'هڪ منٽ'.'|:count '.'منٽ',\n    'second' => '{1}'.'چند سيڪنڊ'.'|:count '.'سيڪنڊ',\n    'ago' => ':time اڳ',\n    'from_now' => ':time پوء',\n    'diff_yesterday' => 'ڪالهه',\n    'diff_today' => 'اڄ',\n    'diff_tomorrow' => 'سڀاڻي',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd، D MMMM YYYY HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[اڄ] LT',\n        'nextDay' => '[سڀاڻي] LT',\n        'nextWeek' => 'dddd [اڳين هفتي تي] LT',\n        'lastDay' => '[ڪالهه] LT',\n        'lastWeek' => '[گزريل هفتي] dddd [تي] LT',\n        'sameElse' => 'L',\n    ],\n    'meridiem' => ['صبح', 'شام'],\n    'months' => $months,\n    'months_short' => $months,\n    'weekdays' => $weekdays,\n    'weekdays_short' => $weekdays,\n    'weekdays_min' => $weekdays,\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n    'list' => ['، ', ' ۽ '],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/sd_IN.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Red Hat, Pune    bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/sd.php', [\n    'formats' => [\n        'L' => 'D/M/YY',\n    ],\n    'months' => ['جنوري', 'فبروري', 'مارچ', 'اپريل', 'مي', 'جون', 'جولاءِ', 'آگسٽ', 'سيپٽيمبر', 'آڪٽوبر', 'نومبر', 'ڊسمبر'],\n    'months_short' => ['جنوري', 'فبروري', 'مارچ', 'اپريل', 'مي', 'جون', 'جولاءِ', 'آگسٽ', 'سيپٽيمبر', 'آڪٽوبر', 'نومبر', 'ڊسمبر'],\n    'weekdays' => ['آرتوارُ', 'سومرُ', 'منگلُ', 'ٻُڌرُ', 'وسپت', 'جُمو', 'ڇنڇر'],\n    'weekdays_short' => ['آرتوارُ', 'سومرُ', 'منگلُ', 'ٻُڌرُ', 'وسپت', 'جُمو', 'ڇنڇر'],\n    'weekdays_min' => ['آرتوارُ', 'سومرُ', 'منگلُ', 'ٻُڌرُ', 'وسپت', 'جُمو', 'ڇنڇر'],\n    'day_of_first_week_of_year' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/sd_IN@devanagari.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Red Hat, Pune    bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/sd.php', [\n    'formats' => [\n        'L' => 'D/M/YY',\n    ],\n    'months' => ['जनवरी', 'फबरवरी', 'मार्चि', 'अप्रेल', 'मे', 'जूनि', 'जूलाइ', 'आगस्टु', 'सेप्टेंबरू', 'आक्टूबरू', 'नवंबरू', 'ॾिसंबरू'],\n    'months_short' => ['जनवरी', 'फबरवरी', 'मार्चि', 'अप्रेल', 'मे', 'जूनि', 'जूलाइ', 'आगस्टु', 'सेप्टेंबरू', 'आक्टूबरू', 'नवंबरू', 'ॾिसंबरू'],\n    'weekdays' => ['आर्तवारू', 'सूमरू', 'मंगलू', 'ॿुधरू', 'विस्पति', 'जुमो', 'छंछस'],\n    'weekdays_short' => ['आर्तवारू', 'सूमरू', 'मंगलू', 'ॿुधरू', 'विस्पति', 'जुमो', 'छंछस'],\n    'weekdays_min' => ['आर्तवारू', 'सूमरू', 'मंगलू', 'ॿुधरू', 'विस्पति', 'जुमो', 'छंछस'],\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['म.पू.', 'म.नं.'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/se.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - François B\n * - Karamell\n */\nreturn [\n    'year' => '{1}:count jahki|:count jagit',\n    'a_year' => '{1}okta jahki|:count jagit',\n    'y' => ':count j.',\n    'month' => '{1}:count mánnu|:count mánut',\n    'a_month' => '{1}okta mánnu|:count mánut',\n    'm' => ':count mán.',\n    'week' => '{1}:count vahkku|:count vahkku',\n    'a_week' => '{1}okta vahkku|:count vahkku',\n    'w' => ':count v.',\n    'day' => '{1}:count beaivi|:count beaivvit',\n    'a_day' => '{1}okta beaivi|:count beaivvit',\n    'd' => ':count b.',\n    'hour' => '{1}:count diimmu|:count diimmut',\n    'a_hour' => '{1}okta diimmu|:count diimmut',\n    'h' => ':count d.',\n    'minute' => '{1}:count minuhta|:count minuhtat',\n    'a_minute' => '{1}okta minuhta|:count minuhtat',\n    'min' => ':count min.',\n    'second' => '{1}:count sekunddat|:count sekunddat',\n    'a_second' => '{1}moadde sekunddat|:count sekunddat',\n    's' => ':count s.',\n    'ago' => 'maŋit :time',\n    'from_now' => ':time geažes',\n    'diff_yesterday' => 'ikte',\n    'diff_yesterday_regexp' => 'ikte(?:\\\\s+ti)?',\n    'diff_today' => 'otne',\n    'diff_today_regexp' => 'otne(?:\\\\s+ti)?',\n    'diff_tomorrow' => 'ihttin',\n    'diff_tomorrow_regexp' => 'ihttin(?:\\\\s+ti)?',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD.MM.YYYY',\n        'LL' => 'MMMM D. [b.] YYYY',\n        'LLL' => 'MMMM D. [b.] YYYY [ti.] HH:mm',\n        'LLLL' => 'dddd, MMMM D. [b.] YYYY [ti.] HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[otne ti] LT',\n        'nextDay' => '[ihttin ti] LT',\n        'nextWeek' => 'dddd [ti] LT',\n        'lastDay' => '[ikte ti] LT',\n        'lastWeek' => '[ovddit] dddd [ti] LT',\n        'sameElse' => 'L',\n    ],\n    'ordinal' => ':number.',\n    'months' => ['ođđajagemánnu', 'guovvamánnu', 'njukčamánnu', 'cuoŋománnu', 'miessemánnu', 'geassemánnu', 'suoidnemánnu', 'borgemánnu', 'čakčamánnu', 'golggotmánnu', 'skábmamánnu', 'juovlamánnu'],\n    'months_short' => ['ođđj', 'guov', 'njuk', 'cuo', 'mies', 'geas', 'suoi', 'borg', 'čakč', 'golg', 'skáb', 'juov'],\n    'weekdays' => ['sotnabeaivi', 'vuossárga', 'maŋŋebárga', 'gaskavahkku', 'duorastat', 'bearjadat', 'lávvardat'],\n    'weekdays_short' => ['sotn', 'vuos', 'maŋ', 'gask', 'duor', 'bear', 'láv'],\n    'weekdays_min' => ['s', 'v', 'm', 'g', 'd', 'b', 'L'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n    'list' => [', ', ' ja '],\n    'meridiem' => ['i.b.', 'e.b.'],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/se_FI.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/se.php', [\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD.MM.YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd D MMMM YYYY HH:mm',\n    ],\n    'months' => ['ođđajagemánnu', 'guovvamánnu', 'njukčamánnu', 'cuoŋománnu', 'miessemánnu', 'geassemánnu', 'suoidnemánnu', 'borgemánnu', 'čakčamánnu', 'golggotmánnu', 'skábmamánnu', 'juovlamánnu'],\n    'months_short' => ['ođđj', 'guov', 'njuk', 'cuoŋ', 'mies', 'geas', 'suoi', 'borg', 'čakč', 'golg', 'skáb', 'juov'],\n    'weekdays' => ['sotnabeaivi', 'mánnodat', 'disdat', 'gaskavahkku', 'duorastat', 'bearjadat', 'lávvordat'],\n    'weekdays_short' => ['so', 'má', 'di', 'ga', 'du', 'be', 'lá'],\n    'weekdays_min' => ['so', 'má', 'di', 'ga', 'du', 'be', 'lá'],\n    'meridiem' => ['i', 'e'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/se_NO.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/se.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/se_SE.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/se.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/seh.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'weekdays' => ['Dimingu', 'Chiposi', 'Chipiri', 'Chitatu', 'Chinai', 'Chishanu', 'Sabudu'],\n    'weekdays_short' => ['Dim', 'Pos', 'Pir', 'Tat', 'Nai', 'Sha', 'Sab'],\n    'weekdays_min' => ['Dim', 'Pos', 'Pir', 'Tat', 'Nai', 'Sha', 'Sab'],\n    'months' => ['Janeiro', 'Fevreiro', 'Marco', 'Abril', 'Maio', 'Junho', 'Julho', 'Augusto', 'Setembro', 'Otubro', 'Novembro', 'Decembro'],\n    'months_short' => ['Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Aug', 'Set', 'Otu', 'Nov', 'Dec'],\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'D/M/YYYY',\n        'LL' => 'd [de] MMM [de] YYYY',\n        'LLL' => 'd [de] MMMM [de] YYYY HH:mm',\n        'LLLL' => 'dddd, d [de] MMMM [de] YYYY HH:mm',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ses.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'meridiem' => ['Adduha', 'Aluula'],\n    'weekdays' => ['Alhadi', 'Atinni', 'Atalaata', 'Alarba', 'Alhamiisa', 'Alzuma', 'Asibti'],\n    'weekdays_short' => ['Alh', 'Ati', 'Ata', 'Ala', 'Alm', 'Alz', 'Asi'],\n    'weekdays_min' => ['Alh', 'Ati', 'Ata', 'Ala', 'Alm', 'Alz', 'Asi'],\n    'months' => ['Žanwiye', 'Feewiriye', 'Marsi', 'Awiril', 'Me', 'Žuweŋ', 'Žuyye', 'Ut', 'Sektanbur', 'Oktoobur', 'Noowanbur', 'Deesanbur'],\n    'months_short' => ['Žan', 'Fee', 'Mar', 'Awi', 'Me', 'Žuw', 'Žuy', 'Ut', 'Sek', 'Okt', 'Noo', 'Dee'],\n    'first_day_of_week' => 1,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'D/M/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd D MMMM YYYY HH:mm',\n    ],\n\n    'month' => ':count alaada', // less reliable\n    'm' => ':count alaada', // less reliable\n    'a_month' => ':count alaada', // less reliable\n\n    'hour' => ':count ɲaajin', // less reliable\n    'h' => ':count ɲaajin', // less reliable\n    'a_hour' => ':count ɲaajin', // less reliable\n\n    'minute' => ':count zarbu', // less reliable\n    'min' => ':count zarbu', // less reliable\n    'a_minute' => ':count zarbu', // less reliable\n\n    'year' => ':count jiiri',\n    'y' => ':count jiiri',\n    'a_year' => ':count jiiri',\n\n    'week' => ':count jirbiiyye',\n    'w' => ':count jirbiiyye',\n    'a_week' => ':count jirbiiyye',\n\n    'day' => ':count zaari',\n    'd' => ':count zaari',\n    'a_day' => ':count zaari',\n\n    'second' => ':count ihinkante',\n    's' => ':count ihinkante',\n    'a_second' => ':count ihinkante',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/sg.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'meridiem' => ['ND', 'LK'],\n    'weekdays' => ['Bikua-ôko', 'Bïkua-ûse', 'Bïkua-ptâ', 'Bïkua-usïö', 'Bïkua-okü', 'Lâpôsö', 'Lâyenga'],\n    'weekdays_short' => ['Bk1', 'Bk2', 'Bk3', 'Bk4', 'Bk5', 'Lâp', 'Lây'],\n    'weekdays_min' => ['Bk1', 'Bk2', 'Bk3', 'Bk4', 'Bk5', 'Lâp', 'Lây'],\n    'months' => ['Nyenye', 'Fulundïgi', 'Mbängü', 'Ngubùe', 'Bêläwü', 'Föndo', 'Lengua', 'Kükürü', 'Mvuka', 'Ngberere', 'Nabändüru', 'Kakauka'],\n    'months_short' => ['Nye', 'Ful', 'Mbä', 'Ngu', 'Bêl', 'Fön', 'Len', 'Kük', 'Mvu', 'Ngb', 'Nab', 'Kak'],\n    'first_day_of_week' => 1,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'D/M/YYYY',\n        'LL' => 'D MMM, YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd D MMMM YYYY HH:mm',\n    ],\n\n    'year' => ':count dā', // less reliable\n    'y' => ':count dā', // less reliable\n    'a_year' => ':count dā', // less reliable\n\n    'week' => ':count bïkua-okü', // less reliable\n    'w' => ':count bïkua-okü', // less reliable\n    'a_week' => ':count bïkua-okü', // less reliable\n\n    'day' => ':count ziggawâ', // less reliable\n    'd' => ':count ziggawâ', // less reliable\n    'a_day' => ':count ziggawâ', // less reliable\n\n    'hour' => ':count yângâködörö', // less reliable\n    'h' => ':count yângâködörö', // less reliable\n    'a_hour' => ':count yângâködörö', // less reliable\n\n    'second' => ':count bïkua-ôko', // less reliable\n    's' => ':count bïkua-ôko', // less reliable\n    'a_second' => ':count bïkua-ôko', // less reliable\n\n    'month' => ':count Nze tî ngu',\n    'm' => ':count Nze tî ngu',\n    'a_month' => ':count Nze tî ngu',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/sgs.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/sgs_LT.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/sgs_LT.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Arnas Udovičius bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'YYYY.MM.DD',\n    ],\n    'months' => ['sausė', 'vasarė', 'kuova', 'balondė', 'gegožės', 'bėrželė', 'lëpas', 'rogpjūtė', 'siejės', 'spalė', 'lapkrėstė', 'grůdė'],\n    'months_short' => ['Sau', 'Vas', 'Kuo', 'Bal', 'Geg', 'Bėr', 'Lëp', 'Rgp', 'Sie', 'Spa', 'Lap', 'Grd'],\n    'weekdays' => ['nedielės dëna', 'panedielis', 'oterninks', 'sereda', 'četvergs', 'petnīčė', 'sobata'],\n    'weekdays_short' => ['Nd', 'Pn', 'Ot', 'Sr', 'Čt', 'Pt', 'Sb'],\n    'weekdays_min' => ['Nd', 'Pn', 'Ot', 'Sr', 'Čt', 'Pt', 'Sb'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n\n    'minute' => ':count mažos', // less reliable\n    'min' => ':count mažos', // less reliable\n    'a_minute' => ':count mažos', // less reliable\n\n    'year' => ':count metā',\n    'y' => ':count metā',\n    'a_year' => ':count metā',\n\n    'month' => ':count mienou',\n    'm' => ':count mienou',\n    'a_month' => ':count mienou',\n\n    'week' => ':count nedielė',\n    'w' => ':count nedielė',\n    'a_week' => ':count nedielė',\n\n    'day' => ':count dīna',\n    'd' => ':count dīna',\n    'a_day' => ':count dīna',\n\n    'hour' => ':count adīna',\n    'h' => ':count adīna',\n    'a_hour' => ':count adīna',\n\n    'second' => ':count Sekondė',\n    's' => ':count Sekondė',\n    'a_second' => ':count Sekondė',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/sh.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n// @codeCoverageIgnoreStart\nuse Symfony\\Component\\Translation\\PluralizationRules;\n\nif (class_exists('Symfony\\\\Component\\\\Translation\\\\PluralizationRules')) {\n    PluralizationRules::set(static function ($number) {\n        return (($number % 10 == 1) && ($number % 100 != 11)) ? 0 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 10) || ($number % 100 >= 20))) ? 1 : 2);\n    }, 'sh');\n}\n// @codeCoverageIgnoreEnd\n\n/*\n * Authors:\n * - Томица Кораћ\n * - Enrique Vidal\n * - Christopher Dell\n * - dmilisic\n * - danijel\n * - Miroslav Matkovic (mikki021)\n */\nreturn [\n    'diff_now' => 'sada',\n    'diff_yesterday' => 'juče',\n    'diff_tomorrow' => 'sutra',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'MMMM D, YYYY',\n        'LLL' => 'DD MMM HH:mm',\n        'LLLL' => 'MMMM DD, YYYY HH:mm',\n    ],\n    'year' => ':count godina|:count godine|:count godina',\n    'y' => ':count g.',\n    'month' => ':count mesec|:count meseca|:count meseci',\n    'm' => ':count m.',\n    'week' => ':count nedelja|:count nedelje|:count nedelja',\n    'w' => ':count n.',\n    'day' => ':count dan|:count dana|:count dana',\n    'd' => ':count d.',\n    'hour' => ':count sat|:count sata|:count sati',\n    'h' => ':count č.',\n    'minute' => ':count minut|:count minuta|:count minuta',\n    'min' => ':count min.',\n    'second' => ':count sekund|:count sekunde|:count sekundi',\n    's' => ':count s.',\n    'ago' => 'pre :time',\n    'from_now' => 'za :time',\n    'after' => 'nakon :time',\n    'before' => ':time raniјe',\n    'weekdays' => ['Nedelja', 'Ponedeljak', 'Utorak', 'Sreda', 'Četvrtak', 'Petak', 'Subota'],\n    'weekdays_short' => ['Ned', 'Pon', 'Uto', 'Sre', 'Čet', 'Pet', 'Sub'],\n    'weekdays_min' => ['Ned', 'Pon', 'Uto', 'Sre', 'Čet', 'Pet', 'Sub'],\n    'months' => ['Januar', 'Februar', 'Mart', 'April', 'Maj', 'Jun', 'Jul', 'Avgust', 'Septembar', 'Oktobar', 'Novembar', 'Decembar'],\n    'months_short' => ['Jan', 'Feb', 'Mar', 'Apr', 'Maj', 'Jun', 'Jul', 'Avg', 'Sep', 'Okt', 'Nov', 'Dec'],\n    'list' => [', ', ' i '],\n    'meridiem' => ['pre podne', 'po podne'],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/shi.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'meridiem' => ['ⵜⵉⴼⴰⵡⵜ', 'ⵜⴰⴷⴳⴳⵯⴰⵜ'],\n    'weekdays' => ['ⴰⵙⴰⵎⴰⵙ', 'ⴰⵢⵏⴰⵙ', 'ⴰⵙⵉⵏⴰⵙ', 'ⴰⴽⵕⴰⵙ', 'ⴰⴽⵡⴰⵙ', 'ⵙⵉⵎⵡⴰⵙ', 'ⴰⵙⵉⴹⵢⴰⵙ'],\n    'weekdays_short' => ['ⴰⵙⴰ', 'ⴰⵢⵏ', 'ⴰⵙⵉ', 'ⴰⴽⵕ', 'ⴰⴽⵡ', 'ⴰⵙⵉⵎ', 'ⴰⵙⵉⴹ'],\n    'weekdays_min' => ['ⴰⵙⴰ', 'ⴰⵢⵏ', 'ⴰⵙⵉ', 'ⴰⴽⵕ', 'ⴰⴽⵡ', 'ⴰⵙⵉⵎ', 'ⴰⵙⵉⴹ'],\n    'months' => ['ⵉⵏⵏⴰⵢⵔ', 'ⴱⵕⴰⵢⵕ', 'ⵎⴰⵕⵚ', 'ⵉⴱⵔⵉⵔ', 'ⵎⴰⵢⵢⵓ', 'ⵢⵓⵏⵢⵓ', 'ⵢⵓⵍⵢⵓⵣ', 'ⵖⵓⵛⵜ', 'ⵛⵓⵜⴰⵏⴱⵉⵔ', 'ⴽⵜⵓⴱⵔ', 'ⵏⵓⵡⴰⵏⴱⵉⵔ', 'ⴷⵓⵊⴰⵏⴱⵉⵔ'],\n    'months_short' => ['ⵉⵏⵏ', 'ⴱⵕⴰ', 'ⵎⴰⵕ', 'ⵉⴱⵔ', 'ⵎⴰⵢ', 'ⵢⵓⵏ', 'ⵢⵓⵍ', 'ⵖⵓⵛ', 'ⵛⵓⵜ', 'ⴽⵜⵓ', 'ⵏⵓⵡ', 'ⴷⵓⵊ'],\n    'first_day_of_week' => 6,\n    'weekend' => [5, 6],\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'D/M/YYYY',\n        'LL' => 'D MMM, YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd D MMMM YYYY HH:mm',\n    ],\n\n    'year' => ':count aseggwas',\n    'y' => ':count aseggwas',\n    'a_year' => ':count aseggwas',\n\n    'month' => ':count ayyur',\n    'm' => ':count ayyur',\n    'a_month' => ':count ayyur',\n\n    'week' => ':count imalass',\n    'w' => ':count imalass',\n    'a_week' => ':count imalass',\n\n    'day' => ':count ass',\n    'd' => ':count ass',\n    'a_day' => ':count ass',\n\n    'hour' => ':count urɣ', // less reliable\n    'h' => ':count urɣ', // less reliable\n    'a_hour' => ':count urɣ', // less reliable\n\n    'minute' => ':count ⴰⵎⵥⵉ', // less reliable\n    'min' => ':count ⴰⵎⵥⵉ', // less reliable\n    'a_minute' => ':count ⴰⵎⵥⵉ', // less reliable\n\n    'second' => ':count sin', // less reliable\n    's' => ':count sin', // less reliable\n    'a_second' => ':count sin', // less reliable\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/shi_Latn.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/shi.php', [\n    'meridiem' => ['tifawt', 'tadggʷat'],\n    'weekdays' => ['asamas', 'aynas', 'asinas', 'akṛas', 'akwas', 'asimwas', 'asiḍyas'],\n    'weekdays_short' => ['asa', 'ayn', 'asi', 'akṛ', 'akw', 'asim', 'asiḍ'],\n    'weekdays_min' => ['asa', 'ayn', 'asi', 'akṛ', 'akw', 'asim', 'asiḍ'],\n    'months' => ['innayr', 'bṛayṛ', 'maṛṣ', 'ibrir', 'mayyu', 'yunyu', 'yulyuz', 'ɣuct', 'cutanbir', 'ktubr', 'nuwanbir', 'dujanbir'],\n    'months_short' => ['inn', 'bṛa', 'maṛ', 'ibr', 'may', 'yun', 'yul', 'ɣuc', 'cut', 'ktu', 'nuw', 'duj'],\n    'first_day_of_week' => 6,\n    'weekend' => [5, 6],\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'D/M/YYYY',\n        'LL' => 'D MMM, YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd D MMMM YYYY HH:mm',\n    ],\n\n    'minute' => ':count agur', // less reliable\n    'min' => ':count agur', // less reliable\n    'a_minute' => ':count agur', // less reliable\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/shi_Tfng.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/shi.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/shn.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/shn_MM.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/shn_MM.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - ubuntu Myanmar LoCo Team https://ubuntu-mm.net Bone Pyae Sone bone.burma@mail.com\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'OY MMM OD dddd',\n    ],\n    'months' => ['လိူၼ်ၵမ်', 'လိူၼ်သၢမ်', 'လိူၼ်သီ', 'လိူၼ်ႁႃႈ', 'လိူၼ်ႁူၵ်း', 'လိူၼ်ၸဵတ်း', 'လိူၼ်ပႅတ်ႇ', 'လိူၼ်ၵဝ်ႈ', 'လိူၼ်သိပ်း', 'လိူၼ်သိပ်းဢိတ်း', 'လိူၼ်သိပ်းဢိတ်းသွင်', 'လိူၼ်ၸဵင်'],\n    'months_short' => ['လိူၼ်ၵမ်', 'လိူၼ်သၢမ်', 'လိူၼ်သီ', 'လိူၼ်ႁႃႈ', 'လိူၼ်ႁူၵ်း', 'လိူၼ်ၸဵတ်း', 'လိူၼ်ပႅတ်ႇ', 'လိူၼ်ၵဝ်ႈ', 'လိူၼ်သိပ်း', 'လိူၼ်သိပ်းဢိတ်း', 'လိူၼ်သိပ်းဢိတ်းသွင်', 'လိူၼ်ၸဵင်'],\n    'weekdays' => ['ဝၼ်းဢႃးတိတ်ႉ', 'ဝၼ်းၸၼ်', 'ဝၼ်း​ဢၢင်း​ၵၢၼ်း', 'ဝၼ်းပူတ်ႉ', 'ဝၼ်းၽတ်း', 'ဝၼ်းသုၵ်း', 'ဝၼ်းသဝ်'],\n    'weekdays_short' => ['တိတ့်', 'ၸၼ်', 'ၵၢၼ်း', 'ပုတ့်', 'ၽတ်း', 'သုၵ်း', 'သဝ်'],\n    'weekdays_min' => ['တိတ့်', 'ၸၼ်', 'ၵၢၼ်း', 'ပုတ့်', 'ၽတ်း', 'သုၵ်း', 'သဝ်'],\n    'alt_numbers' => ['႐႐', '႐႑', '႐႒', '႐႓', '႐႔', '႐႕', '႐႖', '႐႗', '႐႘', '႐႙', '႑႐', '႑႑', '႑႒', '႑႓', '႑႔', '႑႕', '႑႖', '႑႗', '႑႘', '႑႙', '႒႐', '႒႑', '႒႒', '႒႓', '႒႔', '႒႕', '႒႖', '႒႗', '႒႘', '႒႙', '႓႐', '႓႑', '႓႒', '႓႓', '႓႔', '႓႕', '႓႖', '႓႗', '႓႘', '႓႙', '႔႐', '႔႑', '႔႒', '႔႓', '႔႔', '႔႕', '႔႖', '႔႗', '႔႘', '႔႙', '႕႐', '႕႑', '႕႒', '႕႓', '႕႔', '႕႕', '႕႖', '႕႗', '႕႘', '႕႙', '႖႐', '႖႑', '႖႒', '႖႓', '႖႔', '႖႕', '႖႖', '႖႗', '႖႘', '႖႙', '႗႐', '႗႑', '႗႒', '႗႓', '႗႔', '႗႕', '႗႖', '႗႗', '႗႘', '႗႙', '႘႐', '႘႑', '႘႒', '႘႓', '႘႔', '႘႕', '႘႖', '႘႗', '႘႘', '႘႙', '႙႐', '႙႑', '႙႒', '႙႓', '႙႔', '႙႕', '႙႖', '႙႗', '႙႘', '႙႙'],\n    'meridiem' => ['ၵၢင်ၼႂ်', 'တၢမ်းၶမ်ႈ'],\n\n    'month' => ':count လိူၼ်', // less reliable\n    'm' => ':count လိူၼ်', // less reliable\n    'a_month' => ':count လိူၼ်', // less reliable\n\n    'week' => ':count ဝၼ်း', // less reliable\n    'w' => ':count ဝၼ်း', // less reliable\n    'a_week' => ':count ဝၼ်း', // less reliable\n\n    'hour' => ':count ຕີ', // less reliable\n    'h' => ':count ຕີ', // less reliable\n    'a_hour' => ':count ຕີ', // less reliable\n\n    'minute' => ':count ເດັກ', // less reliable\n    'min' => ':count ເດັກ', // less reliable\n    'a_minute' => ':count ເດັກ', // less reliable\n\n    'second' => ':count ဢိုၼ်ႇ', // less reliable\n    's' => ':count ဢိုၼ်ႇ', // less reliable\n    'a_second' => ':count ဢိုၼ်ႇ', // less reliable\n\n    'year' => ':count ပီ',\n    'y' => ':count ပီ',\n    'a_year' => ':count ပီ',\n\n    'day' => ':count ກາງວັນ',\n    'd' => ':count ກາງວັນ',\n    'a_day' => ':count ກາງວັນ',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/shs.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/shs_CA.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/shs_CA.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Neskie Manuel    bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD/MM/YY',\n    ],\n    'months' => ['Pellkwet̓min', 'Pelctsipwen̓ten', 'Pellsqépts', 'Peslléwten', 'Pell7ell7é7llqten', 'Pelltspéntsk', 'Pelltqwelq̓wél̓t', 'Pellct̓éxel̓cten', 'Pesqelqlélten', 'Pesllwélsten', 'Pellc7ell7é7llcwten̓', 'Pelltetétq̓em'],\n    'months_short' => ['Kwe', 'Tsi', 'Sqe', 'Éwt', 'Ell', 'Tsp', 'Tqw', 'Ct̓é', 'Qel', 'Wél', 'U7l', 'Tet'],\n    'weekdays' => ['Sxetspesq̓t', 'Spetkesq̓t', 'Selesq̓t', 'Skellesq̓t', 'Smesesq̓t', 'Stselkstesq̓t', 'Stqmekstesq̓t'],\n    'weekdays_short' => ['Sxe', 'Spe', 'Sel', 'Ske', 'Sme', 'Sts', 'Stq'],\n    'weekdays_min' => ['Sxe', 'Spe', 'Sel', 'Ske', 'Sme', 'Sts', 'Stq'],\n    'day_of_first_week_of_year' => 1,\n\n    'year' => ':count sqlélten', // less reliable\n    'y' => ':count sqlélten', // less reliable\n    'a_year' => ':count sqlélten', // less reliable\n\n    'month' => ':count swewll', // less reliable\n    'm' => ':count swewll', // less reliable\n    'a_month' => ':count swewll', // less reliable\n\n    'hour' => ':count seqwlút', // less reliable\n    'h' => ':count seqwlút', // less reliable\n    'a_hour' => ':count seqwlút', // less reliable\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/si.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - François B\n * - Serhan Apaydın\n * - JD Isaacks\n * - Malinda Weerasinghe (MalindaWMD)\n */\nreturn [\n    'year' => '{1}වසර 1|වසර :count',\n    'a_year' => '{1}වසරක්|වසර :count',\n    'month' => '{1}මාස 1|මාස :count',\n    'a_month' => '{1}මාසය|මාස :count',\n    'week' => '{1}සති 1|සති :count',\n    'a_week' => '{1}සතියක්|සති :count',\n    'day' => '{1}දින 1|දින :count',\n    'a_day' => '{1}දිනක්|දින :count',\n    'hour' => '{1}පැය 1|පැය :count',\n    'a_hour' => '{1}පැයක්|පැය :count',\n    'minute' => '{1}මිනිත්තු 1|මිනිත්තු :count',\n    'a_minute' => '{1}මිනිත්තුවක්|මිනිත්තු :count',\n    'second' => '{1}තත්පර 1|තත්පර :count',\n    'a_second' => '{1}තත්පර කිහිපයකට|තත්පර :count',\n    'ago' => ':time කට පෙර',\n    'from_now' => function ($time) {\n        if (preg_match('/දින \\d/u', $time)) {\n            return $time.' න්';\n        }\n\n        return $time.' කින්';\n    },\n    'before' => ':time කට පෙර',\n    'after' => function ($time) {\n        if (preg_match('/දින \\d/u', $time)) {\n            return $time.' න්';\n        }\n\n        return $time.' කින්';\n    },\n    'diff_now' => 'දැන්',\n    'diff_today' => 'අද',\n    'diff_yesterday' => 'ඊයේ',\n    'diff_tomorrow' => 'හෙට',\n    'formats' => [\n        'LT' => 'a h:mm',\n        'LTS' => 'a h:mm:ss',\n        'L' => 'YYYY/MM/DD',\n        'LL' => 'YYYY MMMM D',\n        'LLL' => 'YYYY MMMM D, a h:mm',\n        'LLLL' => 'YYYY MMMM D [වැනි] dddd, a h:mm:ss',\n    ],\n    'calendar' => [\n        'sameDay' => '[අද] LT[ට]',\n        'nextDay' => '[හෙට] LT[ට]',\n        'nextWeek' => 'dddd LT[ට]',\n        'lastDay' => '[ඊයේ] LT[ට]',\n        'lastWeek' => '[පසුගිය] dddd LT[ට]',\n        'sameElse' => 'L',\n    ],\n    'ordinal' => ':number වැනි',\n    'meridiem' => ['පෙර වරු', 'පස් වරු', 'පෙ.ව.', 'ප.ව.'],\n    'months' => ['ජනවාරි', 'පෙබරවාරි', 'මාර්තු', 'අප්‍රේල්', 'මැයි', 'ජූනි', 'ජූලි', 'අගෝස්තු', 'සැප්තැම්බර්', 'ඔක්තෝබර්', 'නොවැම්බර්', 'දෙසැම්බර්'],\n    'months_short' => ['ජන', 'පෙබ', 'මාර්', 'අප්', 'මැයි', 'ජූනි', 'ජූලි', 'අගෝ', 'සැප්', 'ඔක්', 'නොවැ', 'දෙසැ'],\n    'weekdays' => ['ඉරිදා', 'සඳුදා', 'අඟහරුවාදා', 'බදාදා', 'බ්‍රහස්පතින්දා', 'සිකුරාදා', 'සෙනසුරාදා'],\n    'weekdays_short' => ['ඉරි', 'සඳු', 'අඟ', 'බදා', 'බ්‍රහ', 'සිකු', 'සෙන'],\n    'weekdays_min' => ['ඉ', 'ස', 'අ', 'බ', 'බ්‍ර', 'සි', 'සෙ'],\n    'first_day_of_week' => 1,\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/si_LK.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/si.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/sid.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/sid_ET.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/sid_ET.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Ge'ez Frontier Foundation    locales@geez.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD/MM/YYYY',\n    ],\n    'months' => ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],\n    'months_short' => ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],\n    'weekdays' => ['Sambata', 'Sanyo', 'Maakisanyo', 'Roowe', 'Hamuse', 'Arbe', 'Qidaame'],\n    'weekdays_short' => ['Sam', 'San', 'Mak', 'Row', 'Ham', 'Arb', 'Qid'],\n    'weekdays_min' => ['Sam', 'San', 'Mak', 'Row', 'Ham', 'Arb', 'Qid'],\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['soodo', 'hawwaro'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/sk.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Philippe Vaucher\n * - Martin Suja\n * - Tsutomu Kuroda\n * - tjku\n * - Max Melentiev\n * - Juanito Fatas\n * - Ivan Stana\n * - Akira Matsuda\n * - Christopher Dell\n * - James McKinney\n * - Enrique Vidal\n * - Simone Carletti\n * - Aaron Patterson\n * - Jozef Fulop\n * - Nicolás Hock Isaza\n * - Tom Hughes\n * - Simon Hürlimann (CyT)\n * - jofi\n * - Jakub ADAMEC\n * - Marek Adamický\n * - AlterwebStudio\n */\n\nuse Carbon\\CarbonInterface;\n\n$fromNow = function ($time) {\n    return 'o '.strtr($time, [\n            'hodina' => 'hodinu',\n            'minúta' => 'minútu',\n            'sekunda' => 'sekundu',\n        ]);\n};\n\n$ago = function ($time) {\n    $replacements = [\n        '/\\bhodina\\b/' => 'hodinou',\n        '/\\bminúta\\b/' => 'minútou',\n        '/\\bsekunda\\b/' => 'sekundou',\n        '/\\bdeň\\b/u' => 'dňom',\n        '/\\btýždeň\\b/u' => 'týždňom',\n        '/\\bmesiac\\b/' => 'mesiacom',\n        '/\\brok\\b/' => 'rokom',\n    ];\n\n    $replacementsPlural = [\n        '/\\bhodiny\\b/' => 'hodinami',\n        '/\\bminúty\\b/' => 'minútami',\n        '/\\bsekundy\\b/' => 'sekundami',\n        '/\\bdni\\b/' => 'dňami',\n        '/\\btýždne\\b/' => 'týždňami',\n        '/\\bmesiace\\b/' => 'mesiacmi',\n        '/\\broky\\b/' => 'rokmi',\n    ];\n\n    foreach ($replacements + $replacementsPlural as $pattern => $replacement) {\n        $time = preg_replace($pattern, $replacement, $time);\n    }\n\n    return \"pred $time\";\n};\n\nreturn [\n    'year' => ':count rok|:count roky|:count rokov',\n    'a_year' => 'rok|:count roky|:count rokov',\n    'y' => ':count r',\n    'month' => ':count mesiac|:count mesiace|:count mesiacov',\n    'a_month' => 'mesiac|:count mesiace|:count mesiacov',\n    'm' => ':count m',\n    'week' => ':count týždeň|:count týždne|:count týždňov',\n    'a_week' => 'týždeň|:count týždne|:count týždňov',\n    'w' => ':count t',\n    'day' => ':count deň|:count dni|:count dní',\n    'a_day' => 'deň|:count dni|:count dní',\n    'd' => ':count d',\n    'hour' => ':count hodina|:count hodiny|:count hodín',\n    'a_hour' => 'hodina|:count hodiny|:count hodín',\n    'h' => ':count h',\n    'minute' => ':count minúta|:count minúty|:count minút',\n    'a_minute' => 'minúta|:count minúty|:count minút',\n    'min' => ':count min',\n    'second' => ':count sekunda|:count sekundy|:count sekúnd',\n    'a_second' => 'sekunda|:count sekundy|:count sekúnd',\n    's' => ':count s',\n    'millisecond' => ':count milisekunda|:count milisekundy|:count milisekúnd',\n    'a_millisecond' => 'milisekunda|:count milisekundy|:count milisekúnd',\n    'ms' => ':count ms',\n    'microsecond' => ':count mikrosekunda|:count mikrosekundy|:count mikrosekúnd',\n    'a_microsecond' => 'mikrosekunda|:count mikrosekundy|:count mikrosekúnd',\n    'µs' => ':count µs',\n\n    'ago' => $ago,\n    'from_now' => $fromNow,\n    'before' => ':time pred',\n    'after' => ':time po',\n\n    'hour_after' => ':count hodinu|:count hodiny|:count hodín',\n    'minute_after' => ':count minútu|:count minúty|:count minút',\n    'second_after' => ':count sekundu|:count sekundy|:count sekúnd',\n\n    'hour_before' => ':count hodinu|:count hodiny|:count hodín',\n    'minute_before' => ':count minútu|:count minúty|:count minút',\n    'second_before' => ':count sekundu|:count sekundy|:count sekúnd',\n\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n    'list' => [', ', ' a '],\n    'diff_now' => 'teraz',\n    'diff_yesterday' => 'včera',\n    'diff_tomorrow' => 'zajtra',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD.MM.YYYY',\n        'LL' => 'DD. MMMM YYYY',\n        'LLL' => 'D. M. HH:mm',\n        'LLLL' => 'dddd D. MMMM YYYY HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[dnes o] LT',\n        'nextDay' => '[zajtra o] LT',\n        'lastDay' => '[včera o] LT',\n        'nextWeek' => 'dddd [o] LT',\n        'lastWeek' => static function (CarbonInterface $date) {\n            switch ($date->dayOfWeek) {\n                case 1:\n                case 2:\n                case 4:\n                case 5:\n                    return '[minulý] dddd [o] LT'; //pondelok/utorok/štvrtok/piatok\n                default:\n                    return '[minulá] dddd [o] LT';\n            }\n        },\n        'sameElse' => 'L',\n    ],\n    'weekdays' => ['nedeľa', 'pondelok', 'utorok', 'streda', 'štvrtok', 'piatok', 'sobota'],\n    'weekdays_short' => ['ned', 'pon', 'uto', 'str', 'štv', 'pia', 'sob'],\n    'weekdays_min' => ['ne', 'po', 'ut', 'st', 'št', 'pi', 'so'],\n    'months' => ['január', 'február', 'marec', 'apríl', 'máj', 'jún', 'júl', 'august', 'september', 'október', 'november', 'december'],\n    'months_short' => ['jan', 'feb', 'mar', 'apr', 'máj', 'jún', 'júl', 'aug', 'sep', 'okt', 'nov', 'dec'],\n    'meridiem' => ['dopoludnia', 'popoludní'],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/sk_SK.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/sk.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/sl.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Philippe Vaucher\n * - Tsutomu Kuroda\n * - tjku\n * - Max Melentiev\n * - Juanito Fatas\n * - Akira Matsuda\n * - Christopher Dell\n * - Enrique Vidal\n * - Simone Carletti\n * - Aaron Patterson\n * - Nicolás Hock Isaza\n * - Miha Rebernik\n * - Gal Jakič (morpheus7CS)\n * - Glavić\n * - Anže Časar\n * - Lovro Tramšek (Lovro1107)\n * - burut13\n */\n\nuse Carbon\\CarbonInterface;\n\nreturn [\n    'year' => ':count leto|:count leti|:count leta|:count let',\n    'y' => ':count leto|:count leti|:count leta|:count let',\n    'month' => ':count mesec|:count meseca|:count mesece|:count mesecev',\n    'm' => ':count mes.',\n    'week' => ':count teden|:count tedna|:count tedne|:count tednov',\n    'w' => ':count ted.',\n    'day' => ':count dan|:count dni|:count dni|:count dni',\n    'd' => ':count dan|:count dni|:count dni|:count dni',\n    'hour' => ':count ura|:count uri|:count ure|:count ur',\n    'h' => ':count h',\n    'minute' => ':count minuta|:count minuti|:count minute|:count minut',\n    'min' => ':count min.',\n    'second' => ':count sekunda|:count sekundi|:count sekunde|:count sekund',\n    'a_second' => '{1}nekaj sekund|:count sekunda|:count sekundi|:count sekunde|:count sekund',\n    's' => ':count s',\n\n    'year_ago' => ':count letom|:count letoma|:count leti|:count leti',\n    'y_ago' => ':count letom|:count letoma|:count leti|:count leti',\n    'month_ago' => ':count mesecem|:count mesecema|:count meseci|:count meseci',\n    'week_ago' => ':count tednom|:count tednoma|:count tedni|:count tedni',\n    'day_ago' => ':count dnem|:count dnevoma|:count dnevi|:count dnevi',\n    'd_ago' => ':count dnem|:count dnevoma|:count dnevi|:count dnevi',\n    'hour_ago' => ':count uro|:count urama|:count urami|:count urami',\n    'minute_ago' => ':count minuto|:count minutama|:count minutami|:count minutami',\n    'second_ago' => ':count sekundo|:count sekundama|:count sekundami|:count sekundami',\n\n    'day_from_now' => ':count dan|:count dneva|:count dni|:count dni',\n    'd_from_now' => ':count dan|:count dneva|:count dni|:count dni',\n    'hour_from_now' => ':count uro|:count uri|:count ure|:count ur',\n    'minute_from_now' => ':count minuto|:count minuti|:count minute|:count minut',\n    'second_from_now' => ':count sekundo|:count sekundi|:count sekunde|:count sekund',\n\n    'ago' => 'pred :time',\n    'from_now' => 'čez :time',\n    'after' => ':time kasneje',\n    'before' => ':time prej',\n\n    'diff_now' => 'ravnokar',\n    'diff_today' => 'danes',\n    'diff_today_regexp' => 'danes(?:\\\\s+ob)?',\n    'diff_yesterday' => 'včeraj',\n    'diff_yesterday_regexp' => 'včeraj(?:\\\\s+ob)?',\n    'diff_tomorrow' => 'jutri',\n    'diff_tomorrow_regexp' => 'jutri(?:\\\\s+ob)?',\n    'diff_before_yesterday' => 'predvčerajšnjim',\n    'diff_after_tomorrow' => 'pojutrišnjem',\n\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n\n    'period_start_date' => 'od :date',\n    'period_end_date' => 'do :date',\n\n    'formats' => [\n        'LT' => 'H:mm',\n        'LTS' => 'H:mm:ss',\n        'L' => 'DD.MM.YYYY',\n        'LL' => 'D. MMMM YYYY',\n        'LLL' => 'D. MMMM YYYY H:mm',\n        'LLLL' => 'dddd, D. MMMM YYYY H:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[danes ob] LT',\n        'nextDay' => '[jutri ob] LT',\n        'nextWeek' => 'dddd [ob] LT',\n        'lastDay' => '[včeraj ob] LT',\n        'lastWeek' => function (CarbonInterface $date) {\n            switch ($date->dayOfWeek) {\n                case 0:\n                    return '[preteklo] [nedeljo] [ob] LT';\n                case 1:\n                    return '[pretekli] [ponedeljek] [ob] LT';\n                case 2:\n                    return '[pretekli] [torek] [ob] LT';\n                case 3:\n                    return '[preteklo] [sredo] [ob] LT';\n                case 4:\n                    return '[pretekli] [četrtek] [ob] LT';\n                case 5:\n                    return '[pretekli] [petek] [ob] LT';\n                case 6:\n                    return '[preteklo] [soboto] [ob] LT';\n            }\n        },\n        'sameElse' => 'L',\n    ],\n    'months' => ['januar', 'februar', 'marec', 'april', 'maj', 'junij', 'julij', 'avgust', 'september', 'oktober', 'november', 'december'],\n    'months_short' => ['jan', 'feb', 'mar', 'apr', 'maj', 'jun', 'jul', 'avg', 'sep', 'okt', 'nov', 'dec'],\n    'weekdays' => ['nedelja', 'ponedeljek', 'torek', 'sreda', 'četrtek', 'petek', 'sobota'],\n    'weekdays_short' => ['ned', 'pon', 'tor', 'sre', 'čet', 'pet', 'sob'],\n    'weekdays_min' => ['ne', 'po', 'to', 'sr', 'če', 'pe', 'so'],\n    'list' => [', ', ' in '],\n    'meridiem' => ['dopoldan', 'popoldan'],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/sl_SI.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/sl.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/sm.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/sm_WS.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/sm_WS.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Samsung Electronics Co., Ltd.    akhilesh.k@samsung.com\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD/MM/YYYY',\n    ],\n    'months' => ['Ianuari', 'Fepuari', 'Mati', 'Aperila', 'Me', 'Iuni', 'Iulai', 'Auguso', 'Setema', 'Oketopa', 'Novema', 'Tesema'],\n    'months_short' => ['Ian', 'Fep', 'Mat', 'Ape', 'Me', 'Iun', 'Iul', 'Aug', 'Set', 'Oke', 'Nov', 'Tes'],\n    'weekdays' => ['Aso Sa', 'Aso Gafua', 'Aso Lua', 'Aso Lulu', 'Aso Tofi', 'Aso Farail', 'Aso To\\'ana\\'i'],\n    'weekdays_short' => ['Aso Sa', 'Aso Gaf', 'Aso Lua', 'Aso Lul', 'Aso Tof', 'Aso Far', 'Aso To\\''],\n    'weekdays_min' => ['Aso Sa', 'Aso Gaf', 'Aso Lua', 'Aso Lul', 'Aso Tof', 'Aso Far', 'Aso To\\''],\n\n    'hour' => ':count uati', // less reliable\n    'h' => ':count uati', // less reliable\n    'a_hour' => ':count uati', // less reliable\n\n    'minute' => ':count itiiti', // less reliable\n    'min' => ':count itiiti', // less reliable\n    'a_minute' => ':count itiiti', // less reliable\n\n    'second' => ':count lua', // less reliable\n    's' => ':count lua', // less reliable\n    'a_second' => ':count lua', // less reliable\n\n    'year' => ':count tausaga',\n    'y' => ':count tausaga',\n    'a_year' => ':count tausaga',\n\n    'month' => ':count māsina',\n    'm' => ':count māsina',\n    'a_month' => ':count māsina',\n\n    'week' => ':count vaiaso',\n    'w' => ':count vaiaso',\n    'a_week' => ':count vaiaso',\n\n    'day' => ':count aso',\n    'd' => ':count aso',\n    'a_day' => ':count aso',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/smn.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'meridiem' => ['ip.', 'ep.'],\n    'weekdays' => ['pasepeeivi', 'vuossaargâ', 'majebaargâ', 'koskoho', 'tuorâstuv', 'vástuppeeivi', 'lávurduv'],\n    'weekdays_short' => ['pas', 'vuo', 'maj', 'kos', 'tuo', 'vás', 'láv'],\n    'weekdays_min' => ['pa', 'vu', 'ma', 'ko', 'tu', 'vá', 'lá'],\n    'weekdays_standalone' => ['pasepeivi', 'vuossargâ', 'majebargâ', 'koskokko', 'tuorâstâh', 'vástuppeivi', 'lávurdâh'],\n    'months' => ['uđđâivemáánu', 'kuovâmáánu', 'njuhčâmáánu', 'cuáŋuimáánu', 'vyesimáánu', 'kesimáánu', 'syeinimáánu', 'porgemáánu', 'čohčâmáánu', 'roovvâdmáánu', 'skammâmáánu', 'juovlâmáánu'],\n    'months_short' => ['uđiv', 'kuovâ', 'njuhčâ', 'cuáŋui', 'vyesi', 'kesi', 'syeini', 'porge', 'čohčâ', 'roovvâd', 'skammâ', 'juovlâ'],\n    'first_day_of_week' => 1,\n    'formats' => [\n        'LT' => 'H.mm',\n        'LTS' => 'H.mm.ss',\n        'L' => 'D.M.YYYY',\n        'LL' => 'MMM D. YYYY',\n        'LLL' => 'MMMM D. YYYY H.mm',\n        'LLLL' => 'dddd, MMMM D. YYYY H.mm',\n    ],\n\n    'hour' => ':count äigi', // less reliable\n    'h' => ':count äigi', // less reliable\n    'a_hour' => ':count äigi', // less reliable\n\n    'year' => ':count ihe',\n    'y' => ':count ihe',\n    'a_year' => ':count ihe',\n\n    'month' => ':count mánuppaje',\n    'm' => ':count mánuppaje',\n    'a_month' => ':count mánuppaje',\n\n    'week' => ':count okko',\n    'w' => ':count okko',\n    'a_week' => ':count okko',\n\n    'day' => ':count peivi',\n    'd' => ':count peivi',\n    'a_day' => ':count peivi',\n\n    'minute' => ':count miinut',\n    'min' => ':count miinut',\n    'a_minute' => ':count miinut',\n\n    'second' => ':count nubbe',\n    's' => ':count nubbe',\n    'a_second' => ':count nubbe',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/sn.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'meridiem' => ['a', 'p'],\n    'weekdays' => ['Svondo', 'Muvhuro', 'Chipiri', 'Chitatu', 'China', 'Chishanu', 'Mugovera'],\n    'weekdays_short' => ['Svo', 'Muv', 'Chp', 'Cht', 'Chn', 'Chs', 'Mug'],\n    'weekdays_min' => ['Sv', 'Mu', 'Cp', 'Ct', 'Cn', 'Cs', 'Mg'],\n    'months' => ['Ndira', 'Kukadzi', 'Kurume', 'Kubvumbi', 'Chivabvu', 'Chikumi', 'Chikunguru', 'Nyamavhuvhu', 'Gunyana', 'Gumiguru', 'Mbudzi', 'Zvita'],\n    'months_short' => ['Ndi', 'Kuk', 'Kur', 'Kub', 'Chv', 'Chk', 'Chg', 'Nya', 'Gun', 'Gum', 'Mbu', 'Zvi'],\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'YYYY-MM-dd',\n        'LL' => 'YYYY MMM D',\n        'LLL' => 'YYYY MMMM D HH:mm',\n        'LLLL' => 'YYYY MMMM D, dddd HH:mm',\n    ],\n\n    'year' => 'makore :count',\n    'y' => 'makore :count',\n    'a_year' => 'makore :count',\n\n    'month' => 'mwedzi :count',\n    'm' => 'mwedzi :count',\n    'a_month' => 'mwedzi :count',\n\n    'week' => 'vhiki :count',\n    'w' => 'vhiki :count',\n    'a_week' => 'vhiki :count',\n\n    'day' => 'mazuva :count',\n    'd' => 'mazuva :count',\n    'a_day' => 'mazuva :count',\n\n    'hour' => 'maawa :count',\n    'h' => 'maawa :count',\n    'a_hour' => 'maawa :count',\n\n    'minute' => 'minitsi :count',\n    'min' => 'minitsi :count',\n    'a_minute' => 'minitsi :count',\n\n    'second' => 'sekonzi :count',\n    's' => 'sekonzi :count',\n    'a_second' => 'sekonzi :count',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/so.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Author:\n * - Abdifatah Abdilahi(@abdifatahz)\n */\nreturn [\n    'year' => ':count sanad|:count sanadood',\n    'a_year' => 'sanad|:count sanadood',\n    'y' => '{1}:countsn|{0}:countsns|]1,Inf[:countsn',\n    'month' => ':count bil|:count bilood',\n    'a_month' => 'bil|:count bilood',\n    'm' => ':countbil',\n    'week' => ':count isbuuc',\n    'a_week' => 'isbuuc|:count isbuuc',\n    'w' => ':countis',\n    'day' => ':count maalin|:count maalmood',\n    'a_day' => 'maalin|:count maalmood',\n    'd' => ':countml',\n    'hour' => ':count saac',\n    'a_hour' => 'saacad|:count saac',\n    'h' => ':countsc',\n    'minute' => ':count daqiiqo',\n    'a_minute' => 'daqiiqo|:count daqiiqo',\n    'min' => ':countdq',\n    'second' => ':count ilbidhiqsi',\n    'a_second' => 'xooga ilbidhiqsiyo|:count ilbidhiqsi',\n    's' => ':countil',\n    'ago' => ':time kahor',\n    'from_now' => ':time gudahood',\n    'after' => ':time kedib',\n    'before' => ':time kahor',\n    'diff_now' => 'hada',\n    'diff_today' => 'maanta',\n    'diff_today_regexp' => 'maanta(?:\\s+markay\\s+(?:tahay|ahayd))?',\n    'diff_yesterday' => 'shalayto',\n    'diff_yesterday_regexp' => 'shalayto(?:\\s+markay\\s+ahayd)?',\n    'diff_tomorrow' => 'beri',\n    'diff_tomorrow_regexp' => 'beri(?:\\s+markay\\s+tahay)?',\n    'diff_before_yesterday' => 'doraato',\n    'diff_after_tomorrow' => 'saadanbe',\n    'period_recurrences' => 'mar|:count jeer',\n    'period_interval' => ':interval kasta',\n    'period_start_date' => 'laga bilaabo :date',\n    'period_end_date' => 'ilaa :date',\n    'months' => ['Janaayo', 'Febraayo', 'Abriil', 'Maajo', 'Juun', 'Luuliyo', 'Agoosto', 'Sebteembar', 'Oktoobar', 'Nofeembar', 'Diseembar'],\n    'months_short' => ['Jan', 'Feb', 'Mar', 'Abr', 'Mjo', 'Jun', 'Lyo', 'Agt', 'Seb', 'Okt', 'Nof', 'Dis'],\n    'weekdays' => ['Axad', 'Isniin', 'Talaada', 'Arbaca', 'Khamiis', 'Jimce', 'Sabti'],\n    'weekdays_short' => ['Axd', 'Isn', 'Tal', 'Arb', 'Kha', 'Jim', 'Sbt'],\n    'weekdays_min' => ['Ax', 'Is', 'Ta', 'Ar', 'Kh', 'Ji', 'Sa'],\n    'list' => [', ', ' and '],\n    'first_day_of_week' => 6,\n    'day_of_first_week_of_year' => 1,\n    'formats' => [\n        'L' => 'DD/MM/YYYY',\n    ],\n    'calendar' => [\n        'sameDay' => '[Maanta markay tahay] LT',\n        'nextDay' => '[Beri markay tahay] LT',\n        'nextWeek' => 'dddd [markay tahay] LT',\n        'lastDay' => '[Shalay markay ahayd] LT',\n        'lastWeek' => '[Hore] dddd [Markay ahayd] LT',\n        'sameElse' => 'L',\n    ],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/so_DJ.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Ge'ez Frontier Foundation    locales@geez.org\n */\nreturn array_replace_recursive(require __DIR__.'/so.php', [\n    'formats' => [\n        'L' => 'DD.MM.YYYY',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/so_ET.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Ge'ez Frontier Foundation    locales@geez.org\n */\nreturn require __DIR__.'/so.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/so_KE.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Ge'ez Frontier Foundation    locales@geez.org\n */\nreturn require __DIR__.'/so.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/so_SO.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Ge'ez Frontier Foundation    locales@geez.org\n */\nreturn require __DIR__.'/so.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/sq.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - François B\n * - JD Isaacks\n * - Fadion Dashi\n */\nreturn [\n    'year' => ':count vit|:count vjet',\n    'a_year' => 'një vit|:count vite',\n    'y' => ':count v.',\n    'month' => ':count muaj',\n    'a_month' => 'një muaj|:count muaj',\n    'm' => ':count muaj',\n    'week' => ':count javë',\n    'a_week' => ':count javë|:count javë',\n    'w' => ':count j.',\n    'day' => ':count ditë',\n    'a_day' => 'një ditë|:count ditë',\n    'd' => ':count d.',\n    'hour' => ':count orë',\n    'a_hour' => 'një orë|:count orë',\n    'h' => ':count o.',\n    'minute' => ':count minutë|:count minuta',\n    'a_minute' => 'një minutë|:count minuta',\n    'min' => ':count min.',\n    'second' => ':count sekondë|:count sekonda',\n    'a_second' => 'disa sekonda|:count sekonda',\n    's' => ':count s.',\n    'ago' => ':time më parë',\n    'from_now' => 'në :time',\n    'after' => ':time pas',\n    'before' => ':time para',\n    'diff_now' => 'tani',\n    'diff_today' => 'Sot',\n    'diff_today_regexp' => 'Sot(?:\\\\s+në)?',\n    'diff_yesterday' => 'dje',\n    'diff_yesterday_regexp' => 'Dje(?:\\\\s+në)?',\n    'diff_tomorrow' => 'nesër',\n    'diff_tomorrow_regexp' => 'Nesër(?:\\\\s+në)?',\n    'diff_before_yesterday' => 'pardje',\n    'diff_after_tomorrow' => 'pasnesër',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[Sot në] LT',\n        'nextDay' => '[Nesër në] LT',\n        'nextWeek' => 'dddd [në] LT',\n        'lastDay' => '[Dje në] LT',\n        'lastWeek' => 'dddd [e kaluar në] LT',\n        'sameElse' => 'L',\n    ],\n    'ordinal' => ':number.',\n    'meridiem' => ['PD', 'MD'],\n    'months' => ['janar', 'shkurt', 'mars', 'prill', 'maj', 'qershor', 'korrik', 'gusht', 'shtator', 'tetor', 'nëntor', 'dhjetor'],\n    'months_short' => ['jan', 'shk', 'mar', 'pri', 'maj', 'qer', 'kor', 'gus', 'sht', 'tet', 'nën', 'dhj'],\n    'weekdays' => ['e diel', 'e hënë', 'e martë', 'e mërkurë', 'e enjte', 'e premte', 'e shtunë'],\n    'weekdays_short' => ['die', 'hën', 'mar', 'mër', 'enj', 'pre', 'sht'],\n    'weekdays_min' => ['d', 'h', 'ma', 'më', 'e', 'p', 'sh'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n    'list' => [', ', ' dhe '],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/sq_AL.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/sq.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/sq_MK.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/sq.php', [\n    'formats' => [\n        'L' => 'D.M.YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY, HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY, HH:mm',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/sq_XK.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/sq.php', [\n    'formats' => [\n        'L' => 'D.M.YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY, HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY, HH:mm',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/sr.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Josh Soref\n * - François B\n * - shaishavgandhi05\n * - Serhan Apaydın\n * - JD Isaacks\n * - Glavić\n * - Milos Sakovic\n */\n\nuse Carbon\\CarbonInterface;\n\nreturn [\n    'year' => ':count godina|:count godine|:count godina',\n    'y' => ':count g.',\n    'month' => ':count mesec|:count meseca|:count meseci',\n    'm' => ':count mj.',\n    'week' => ':count nedelja|:count nedelje|:count nedelja',\n    'w' => ':count ned.',\n    'day' => ':count dan|:count dana|:count dana',\n    'd' => ':count d.',\n    'hour' => ':count sat|:count sata|:count sati',\n    'h' => ':count č.',\n    'minute' => ':count minut|:count minuta|:count minuta',\n    'min' => ':count min.',\n    'second' => ':count sekundu|:count sekunde|:count sekundi',\n    's' => ':count sek.',\n    'ago' => 'pre :time',\n    'from_now' => 'za :time',\n    'after' => 'nakon :time',\n    'before' => 'pre :time',\n\n    'year_from_now' => ':count godinu|:count godine|:count godina',\n    'year_ago' => ':count godinu|:count godine|:count godina',\n    'week_from_now' => ':count nedelju|:count nedelje|:count nedelja',\n    'week_ago' => ':count nedelju|:count nedelje|:count nedelja',\n\n    'diff_now' => 'upravo sada',\n    'diff_today' => 'danas',\n    'diff_today_regexp' => 'danas(?:\\\\s+u)?',\n    'diff_yesterday' => 'juče',\n    'diff_yesterday_regexp' => 'juče(?:\\\\s+u)?',\n    'diff_tomorrow' => 'sutra',\n    'diff_tomorrow_regexp' => 'sutra(?:\\\\s+u)?',\n    'diff_before_yesterday' => 'prekjuče',\n    'diff_after_tomorrow' => 'preksutra',\n    'formats' => [\n        'LT' => 'H:mm',\n        'LTS' => 'H:mm:ss',\n        'L' => 'DD.MM.YYYY',\n        'LL' => 'D. MMMM YYYY',\n        'LLL' => 'D. MMMM YYYY H:mm',\n        'LLLL' => 'dddd, D. MMMM YYYY H:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[danas u] LT',\n        'nextDay' => '[sutra u] LT',\n        'nextWeek' => function (CarbonInterface $date) {\n            switch ($date->dayOfWeek) {\n                case 0:\n                    return '[u nedelju u] LT';\n                case 3:\n                    return '[u sredu u] LT';\n                case 6:\n                    return '[u subotu u] LT';\n                default:\n                    return '[u] dddd [u] LT';\n            }\n        },\n        'lastDay' => '[juče u] LT',\n        'lastWeek' => function (CarbonInterface $date) {\n            switch ($date->dayOfWeek) {\n                case 0:\n                    return '[prošle nedelje u] LT';\n                case 1:\n                    return '[prošlog ponedeljka u] LT';\n                case 2:\n                    return '[prošlog utorka u] LT';\n                case 3:\n                    return '[prošle srede u] LT';\n                case 4:\n                    return '[prošlog četvrtka u] LT';\n                case 5:\n                    return '[prošlog petka u] LT';\n                default:\n                    return '[prošle subote u] LT';\n            }\n        },\n        'sameElse' => 'L',\n    ],\n    'ordinal' => ':number.',\n    'months' => ['januar', 'februar', 'mart', 'april', 'maj', 'jun', 'jul', 'avgust', 'septembar', 'oktobar', 'novembar', 'decembar'],\n    'months_short' => ['jan.', 'feb.', 'mar.', 'apr.', 'maj', 'jun', 'jul', 'avg.', 'sep.', 'okt.', 'nov.', 'dec.'],\n    'weekdays' => ['nedelja', 'ponedeljak', 'utorak', 'sreda', 'četvrtak', 'petak', 'subota'],\n    'weekdays_short' => ['ned.', 'pon.', 'uto.', 'sre.', 'čet.', 'pet.', 'sub.'],\n    'weekdays_min' => ['ne', 'po', 'ut', 'sr', 'če', 'pe', 'su'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n    'list' => [', ', ' i '],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/sr_Cyrl.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Josh Soref\n * - François B\n * - shaishavgandhi05\n * - Serhan Apaydın\n * - JD Isaacks\n * - Glavić\n * - Nikola Zeravcic\n * - Milos Sakovic\n */\n\nuse Carbon\\CarbonInterface;\n\nreturn [\n    'year' => ':count година|:count године|:count година',\n    'y' => ':count г.',\n    'month' => ':count месец|:count месеца|:count месеци',\n    'm' => ':count м.',\n    'week' => ':count недеља|:count недеље|:count недеља',\n    'w' => ':count нед.',\n    'day' => ':count дан|:count дана|:count дана',\n    'd' => ':count д.',\n    'hour' => ':count сат|:count сата|:count сати',\n    'h' => ':count ч.',\n    'minute' => ':count минут|:count минута|:count минута',\n    'min' => ':count мин.',\n    'second' => ':count секунд|:count секунде|:count секунди',\n    's' => ':count сек.',\n    'ago' => 'пре :time',\n    'from_now' => 'за :time',\n    'after' => ':time након',\n    'before' => ':time пре',\n    'year_from_now' => ':count годину|:count године|:count година',\n    'year_ago' => ':count годину|:count године|:count година',\n    'week_from_now' => ':count недељу|:count недеље|:count недеља',\n    'week_ago' => ':count недељу|:count недеље|:count недеља',\n    'diff_now' => 'управо сада',\n    'diff_today' => 'данас',\n    'diff_today_regexp' => 'данас(?:\\\\s+у)?',\n    'diff_yesterday' => 'јуче',\n    'diff_yesterday_regexp' => 'јуче(?:\\\\s+у)?',\n    'diff_tomorrow' => 'сутра',\n    'diff_tomorrow_regexp' => 'сутра(?:\\\\s+у)?',\n    'diff_before_yesterday' => 'прекјуче',\n    'diff_after_tomorrow' => 'прекосутра',\n    'formats' => [\n        'LT' => 'H:mm',\n        'LTS' => 'H:mm:ss',\n        'L' => 'DD.MM.YYYY',\n        'LL' => 'D. MMMM YYYY',\n        'LLL' => 'D. MMMM YYYY H:mm',\n        'LLLL' => 'dddd, D. MMMM YYYY H:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[данас у] LT',\n        'nextDay' => '[сутра у] LT',\n        'nextWeek' => function (CarbonInterface $date) {\n            switch ($date->dayOfWeek) {\n                case 0:\n                    return '[у недељу у] LT';\n                case 3:\n                    return '[у среду у] LT';\n                case 6:\n                    return '[у суботу у] LT';\n                default:\n                    return '[у] dddd [у] LT';\n            }\n        },\n        'lastDay' => '[јуче у] LT',\n        'lastWeek' => function (CarbonInterface $date) {\n            switch ($date->dayOfWeek) {\n                case 0:\n                    return '[прошле недеље у] LT';\n                case 1:\n                    return '[прошлог понедељка у] LT';\n                case 2:\n                    return '[прошлог уторка у] LT';\n                case 3:\n                    return '[прошле среде у] LT';\n                case 4:\n                    return '[прошлог четвртка у] LT';\n                case 5:\n                    return '[прошлог петка у] LT';\n                default:\n                    return '[прошле суботе у] LT';\n            }\n        },\n        'sameElse' => 'L',\n    ],\n    'ordinal' => ':number.',\n    'months' => ['јануар', 'фебруар', 'март', 'април', 'мај', 'јун', 'јул', 'август', 'септембар', 'октобар', 'новембар', 'децембар'],\n    'months_short' => ['јан.', 'феб.', 'мар.', 'апр.', 'мај', 'јун', 'јул', 'авг.', 'сеп.', 'окт.', 'нов.', 'дец.'],\n    'weekdays' => ['недеља', 'понедељак', 'уторак', 'среда', 'четвртак', 'петак', 'субота'],\n    'weekdays_short' => ['нед.', 'пон.', 'уто.', 'сре.', 'чет.', 'пет.', 'суб.'],\n    'weekdays_min' => ['не', 'по', 'ут', 'ср', 'че', 'пе', 'су'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n    'list' => [', ', ' и '],\n    'meridiem' => ['АМ', 'ПМ'],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/sr_Cyrl_BA.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nuse Symfony\\Component\\Translation\\PluralizationRules;\n\n// @codeCoverageIgnoreStart\nif (class_exists(PluralizationRules::class)) {\n    PluralizationRules::set(static function ($number) {\n        return PluralizationRules::get($number, 'sr');\n    }, 'sr_Cyrl_BA');\n}\n// @codeCoverageIgnoreEnd\n\nreturn array_replace_recursive(require __DIR__.'/sr_Cyrl.php', [\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'D.M.yy.',\n        'LL' => 'DD.MM.YYYY.',\n        'LLL' => 'DD. MMMM YYYY. HH:mm',\n        'LLLL' => 'dddd, DD. MMMM YYYY. HH:mm',\n    ],\n    'weekdays' => ['недјеља', 'понедељак', 'уторак', 'сриједа', 'четвртак', 'петак', 'субота'],\n    'weekdays_short' => ['нед.', 'пон.', 'ут.', 'ср.', 'чет.', 'пет.', 'суб.'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/sr_Cyrl_ME.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Glavić\n * - Milos Sakovic\n */\n\nuse Carbon\\CarbonInterface;\nuse Symfony\\Component\\Translation\\PluralizationRules;\n\n// @codeCoverageIgnoreStart\nif (class_exists(PluralizationRules::class)) {\n    PluralizationRules::set(static function ($number) {\n        return PluralizationRules::get($number, 'sr');\n    }, 'sr_Cyrl_ME');\n}\n// @codeCoverageIgnoreEnd\n\nreturn [\n    'year' => ':count година|:count године|:count година',\n    'y' => ':count г.',\n    'month' => ':count мјесец|:count мјесеца|:count мјесеци',\n    'm' => ':count мј.',\n    'week' => ':count недјеља|:count недјеље|:count недјеља',\n    'w' => ':count нед.',\n    'day' => ':count дан|:count дана|:count дана',\n    'd' => ':count д.',\n    'hour' => ':count сат|:count сата|:count сати',\n    'h' => ':count ч.',\n    'minute' => ':count минут|:count минута|:count минута',\n    'min' => ':count мин.',\n    'second' => ':count секунд|:count секунде|:count секунди',\n    's' => ':count сек.',\n    'ago' => 'прије :time',\n    'from_now' => 'за :time',\n    'after' => ':time након',\n    'before' => ':time прије',\n\n    'year_from_now' => ':count годину|:count године|:count година',\n    'year_ago' => ':count годину|:count године|:count година',\n\n    'week_from_now' => ':count недјељу|:count недјеље|:count недјеља',\n    'week_ago' => ':count недјељу|:count недјеље|:count недјеља',\n\n    'diff_now' => 'управо сада',\n    'diff_today' => 'данас',\n    'diff_today_regexp' => 'данас(?:\\\\s+у)?',\n    'diff_yesterday' => 'јуче',\n    'diff_yesterday_regexp' => 'јуче(?:\\\\s+у)?',\n    'diff_tomorrow' => 'сутра',\n    'diff_tomorrow_regexp' => 'сутра(?:\\\\s+у)?',\n    'diff_before_yesterday' => 'прекјуче',\n    'diff_after_tomorrow' => 'прекосјутра',\n    'formats' => [\n        'LT' => 'H:mm',\n        'LTS' => 'H:mm:ss',\n        'L' => 'DD.MM.YYYY',\n        'LL' => 'D. MMMM YYYY',\n        'LLL' => 'D. MMMM YYYY H:mm',\n        'LLLL' => 'dddd, D. MMMM YYYY H:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[данас у] LT',\n        'nextDay' => '[сутра у] LT',\n        'nextWeek' => function (CarbonInterface $date) {\n            switch ($date->dayOfWeek) {\n                case 0:\n                    return '[у недељу у] LT';\n                case 3:\n                    return '[у среду у] LT';\n                case 6:\n                    return '[у суботу у] LT';\n                default:\n                    return '[у] dddd [у] LT';\n            }\n        },\n        'lastDay' => '[јуче у] LT',\n        'lastWeek' => function (CarbonInterface $date) {\n            switch ($date->dayOfWeek) {\n                case 0:\n                    return '[прошле недеље у] LT';\n                case 1:\n                    return '[прошлог понедељка у] LT';\n                case 2:\n                    return '[прошлог уторка у] LT';\n                case 3:\n                    return '[прошле среде у] LT';\n                case 4:\n                    return '[прошлог четвртка у] LT';\n                case 5:\n                    return '[прошлог петка у] LT';\n                default:\n                    return '[прошле суботе у] LT';\n            }\n        },\n        'sameElse' => 'L',\n    ],\n    'ordinal' => ':number.',\n    'months' => ['јануар', 'фебруар', 'март', 'април', 'мај', 'јун', 'јул', 'август', 'септембар', 'октобар', 'новембар', 'децембар'],\n    'months_short' => ['јан.', 'феб.', 'мар.', 'апр.', 'мај', 'јун', 'јул', 'авг.', 'сеп.', 'окт.', 'нов.', 'дец.'],\n    'weekdays' => ['недеља', 'понедељак', 'уторак', 'среда', 'четвртак', 'петак', 'субота'],\n    'weekdays_short' => ['нед.', 'пон.', 'уто.', 'сре.', 'чет.', 'пет.', 'суб.'],\n    'weekdays_min' => ['не', 'по', 'ут', 'ср', 'че', 'пе', 'су'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n    'list' => [', ', ' и '],\n    'meridiem' => ['АМ', 'ПМ'],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/sr_Cyrl_XK.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nuse Symfony\\Component\\Translation\\PluralizationRules;\n\n// @codeCoverageIgnoreStart\nif (class_exists(PluralizationRules::class)) {\n    PluralizationRules::set(static function ($number) {\n        return PluralizationRules::get($number, 'sr');\n    }, 'sr_Cyrl_XK');\n}\n// @codeCoverageIgnoreEnd\n\nreturn array_replace_recursive(require __DIR__.'/sr_Cyrl_BA.php', [\n    'weekdays' => ['недеља', 'понедељак', 'уторак', 'среда', 'четвртак', 'петак', 'субота'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/sr_Latn.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/sr.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/sr_Latn_BA.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nuse Symfony\\Component\\Translation\\PluralizationRules;\n\n// @codeCoverageIgnoreStart\nif (class_exists(PluralizationRules::class)) {\n    PluralizationRules::set(static function ($number) {\n        return PluralizationRules::get($number, 'sr');\n    }, 'sr_Latn_BA');\n}\n// @codeCoverageIgnoreEnd\n\nreturn array_replace_recursive(require __DIR__.'/sr_Latn.php', [\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'D.M.yy.',\n        'LL' => 'DD.MM.YYYY.',\n        'LLL' => 'DD. MMMM YYYY. HH:mm',\n        'LLLL' => 'dddd, DD. MMMM YYYY. HH:mm',\n    ],\n    'weekdays' => ['nedjelja', 'ponedeljak', 'utorak', 'srijeda', 'četvrtak', 'petak', 'subota'],\n    'weekdays_short' => ['ned.', 'pon.', 'ut.', 'sr.', 'čet.', 'pet.', 'sub.'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/sr_Latn_ME.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Glavić\n * - Milos Sakovic\n */\n\nuse Carbon\\CarbonInterface;\nuse Symfony\\Component\\Translation\\PluralizationRules;\n\n// @codeCoverageIgnoreStart\nif (class_exists(PluralizationRules::class)) {\n    PluralizationRules::set(static function ($number) {\n        return PluralizationRules::get($number, 'sr');\n    }, 'sr_Latn_ME');\n}\n// @codeCoverageIgnoreEnd\n\nreturn array_replace_recursive(require __DIR__.'/sr.php', [\n    'month' => ':count mjesec|:count mjeseca|:count mjeseci',\n    'week' => ':count nedjelja|:count nedjelje|:count nedjelja',\n    'second' => ':count sekund|:count sekunde|:count sekundi',\n    'ago' => 'prije :time',\n    'from_now' => 'za :time',\n    'after' => ':time nakon',\n    'before' => ':time prije',\n    'week_from_now' => ':count nedjelju|:count nedjelje|:count nedjelja',\n    'week_ago' => ':count nedjelju|:count nedjelje|:count nedjelja',\n    'second_ago' => ':count sekund|:count sekunde|:count sekundi',\n    'diff_tomorrow' => 'sjutra',\n    'calendar' => [\n        'nextDay' => '[sjutra u] LT',\n        'nextWeek' => function (CarbonInterface $date) {\n            switch ($date->dayOfWeek) {\n                case 0:\n                    return '[u nedjelju u] LT';\n                case 3:\n                    return '[u srijedu u] LT';\n                case 6:\n                    return '[u subotu u] LT';\n                default:\n                    return '[u] dddd [u] LT';\n            }\n        },\n        'lastWeek' => function (CarbonInterface $date) {\n            switch ($date->dayOfWeek) {\n                case 0:\n                    return '[prošle nedjelje u] LT';\n                case 1:\n                    return '[prošle nedjelje u] LT';\n                case 2:\n                    return '[prošlog utorka u] LT';\n                case 3:\n                    return '[prošle srijede u] LT';\n                case 4:\n                    return '[prošlog četvrtka u] LT';\n                case 5:\n                    return '[prošlog petka u] LT';\n                default:\n                    return '[prošle subote u] LT';\n            }\n        },\n    ],\n    'weekdays' => ['nedjelja', 'ponedjeljak', 'utorak', 'srijeda', 'četvrtak', 'petak', 'subota'],\n    'weekdays_short' => ['ned.', 'pon.', 'uto.', 'sri.', 'čet.', 'pet.', 'sub.'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/sr_Latn_XK.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nuse Symfony\\Component\\Translation\\PluralizationRules;\n\n// @codeCoverageIgnoreStart\nif (class_exists(PluralizationRules::class)) {\n    PluralizationRules::set(static function ($number) {\n        return PluralizationRules::get($number, 'sr');\n    }, 'sr_Latn_XK');\n}\n// @codeCoverageIgnoreEnd\n\nreturn array_replace_recursive(require __DIR__.'/sr_Latn_BA.php', [\n    'weekdays' => ['nedelja', 'ponedeljak', 'utorak', 'sreda', 'četvrtak', 'petak', 'subota'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/sr_ME.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/sr_Latn_ME.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/sr_RS.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - sr_YU, sr_CS locale Danilo Segan bug-glibc-locales@gnu.org\n */\nreturn require __DIR__.'/sr_Cyrl.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/sr_RS@latin.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/sr.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ss.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - François B\n * - Nicolai Davies\n */\nreturn [\n    'year' => '{1}umnyaka|:count iminyaka',\n    'month' => '{1}inyanga|:count tinyanga',\n    'week' => '{1}:count liviki|:count emaviki',\n    'day' => '{1}lilanga|:count emalanga',\n    'hour' => '{1}lihora|:count emahora',\n    'minute' => '{1}umzuzu|:count emizuzu',\n    'second' => '{1}emizuzwana lomcane|:count mzuzwana',\n    'ago' => 'wenteka nga :time',\n    'from_now' => 'nga :time',\n    'diff_yesterday' => 'Itolo',\n    'diff_yesterday_regexp' => 'Itolo(?:\\\\s+nga)?',\n    'diff_today' => 'Namuhla',\n    'diff_today_regexp' => 'Namuhla(?:\\\\s+nga)?',\n    'diff_tomorrow' => 'Kusasa',\n    'diff_tomorrow_regexp' => 'Kusasa(?:\\\\s+nga)?',\n    'formats' => [\n        'LT' => 'h:mm A',\n        'LTS' => 'h:mm:ss A',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY h:mm A',\n        'LLLL' => 'dddd, D MMMM YYYY h:mm A',\n    ],\n    'calendar' => [\n        'sameDay' => '[Namuhla nga] LT',\n        'nextDay' => '[Kusasa nga] LT',\n        'nextWeek' => 'dddd [nga] LT',\n        'lastDay' => '[Itolo nga] LT',\n        'lastWeek' => 'dddd [leliphelile] [nga] LT',\n        'sameElse' => 'L',\n    ],\n    'ordinal' => function ($number) {\n        $lastDigit = $number % 10;\n\n        return $number.(\n            ((int) ($number % 100 / 10) === 1) ? 'e' : (\n                ($lastDigit === 1 || $lastDigit === 2) ? 'a' : 'e'\n            )\n        );\n    },\n    'meridiem' => function ($hour) {\n        if ($hour < 11) {\n            return 'ekuseni';\n        }\n        if ($hour < 15) {\n            return 'emini';\n        }\n        if ($hour < 19) {\n            return 'entsambama';\n        }\n\n        return 'ebusuku';\n    },\n    'months' => ['Bhimbidvwane', 'Indlovana', 'Indlov\\'lenkhulu', 'Mabasa', 'Inkhwekhweti', 'Inhlaba', 'Kholwane', 'Ingci', 'Inyoni', 'Imphala', 'Lweti', 'Ingongoni'],\n    'months_short' => ['Bhi', 'Ina', 'Inu', 'Mab', 'Ink', 'Inh', 'Kho', 'Igc', 'Iny', 'Imp', 'Lwe', 'Igo'],\n    'weekdays' => ['Lisontfo', 'Umsombuluko', 'Lesibili', 'Lesitsatfu', 'Lesine', 'Lesihlanu', 'Umgcibelo'],\n    'weekdays_short' => ['Lis', 'Umb', 'Lsb', 'Les', 'Lsi', 'Lsh', 'Umg'],\n    'weekdays_min' => ['Li', 'Us', 'Lb', 'Lt', 'Ls', 'Lh', 'Ug'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ss_ZA.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/ss.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/st.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/st_ZA.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/st_ZA.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Zuza Software Foundation (Translate.org.za) Dwayne Bailey dwayne@translate.org.za\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD/MM/YYYY',\n    ],\n    'months' => ['Pherekgong', 'Hlakola', 'Tlhakubele', 'Mmese', 'Motsheanong', 'Phupjane', 'Phupu', 'Phato', 'Leotse', 'Mphalane', 'Pudungwana', 'Tshitwe'],\n    'months_short' => ['Phe', 'Hla', 'TlH', 'Mme', 'Mot', 'Jan', 'Upu', 'Pha', 'Leo', 'Mph', 'Pud', 'Tsh'],\n    'weekdays' => ['Sontaha', 'Mantaha', 'Labobedi', 'Laboraro', 'Labone', 'Labohlano', 'Moqebelo'],\n    'weekdays_short' => ['Son', 'Mma', 'Bed', 'Rar', 'Ne', 'Hla', 'Moq'],\n    'weekdays_min' => ['Son', 'Mma', 'Bed', 'Rar', 'Ne', 'Hla', 'Moq'],\n    'day_of_first_week_of_year' => 1,\n\n    'week' => ':count Sontaha', // less reliable\n    'w' => ':count Sontaha', // less reliable\n    'a_week' => ':count Sontaha', // less reliable\n\n    'day' => ':count letsatsi', // less reliable\n    'd' => ':count letsatsi', // less reliable\n    'a_day' => ':count letsatsi', // less reliable\n\n    'hour' => ':count sešupanako', // less reliable\n    'h' => ':count sešupanako', // less reliable\n    'a_hour' => ':count sešupanako', // less reliable\n\n    'minute' => ':count menyane', // less reliable\n    'min' => ':count menyane', // less reliable\n    'a_minute' => ':count menyane', // less reliable\n\n    'second' => ':count thusa', // less reliable\n    's' => ':count thusa', // less reliable\n    'a_second' => ':count thusa', // less reliable\n\n    'year' => ':count selemo',\n    'y' => ':count selemo',\n    'a_year' => ':count selemo',\n\n    'month' => ':count kgwedi',\n    'm' => ':count kgwedi',\n    'a_month' => ':count kgwedi',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/sv.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - François B\n * - Kristoffer Snabb\n * - JD Isaacks\n * - Jens Herlevsen\n * - Nightpine\n * - Anders Nygren (litemerafrukt)\n */\nreturn [\n    'year' => ':count år',\n    'a_year' => 'ett år|:count år',\n    'y' => ':count år',\n    'month' => ':count månad|:count månader',\n    'a_month' => 'en månad|:count månader',\n    'm' => ':count mån',\n    'week' => ':count vecka|:count veckor',\n    'a_week' => 'en vecka|:count veckor',\n    'w' => ':count v',\n    'day' => ':count dag|:count dagar',\n    'a_day' => 'en dag|:count dagar',\n    'd' => ':count dgr',\n    'hour' => ':count timme|:count timmar',\n    'a_hour' => 'en timme|:count timmar',\n    'h' => ':count tim',\n    'minute' => ':count minut|:count minuter',\n    'a_minute' => 'en minut|:count minuter',\n    'min' => ':count min',\n    'second' => ':count sekund|:count sekunder',\n    'a_second' => 'några sekunder|:count sekunder',\n    's' => ':count s',\n    'ago' => 'för :time sedan',\n    'from_now' => 'om :time',\n    'after' => ':time efter',\n    'before' => ':time före',\n    'diff_now' => 'nu',\n    'diff_today' => 'I dag',\n    'diff_yesterday' => 'i går',\n    'diff_yesterday_regexp' => 'I går',\n    'diff_tomorrow' => 'i morgon',\n    'diff_tomorrow_regexp' => 'I morgon',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'YYYY-MM-DD',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY [kl.] HH:mm',\n        'LLLL' => 'dddd D MMMM YYYY [kl.] HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[I dag] LT',\n        'nextDay' => '[I morgon] LT',\n        'nextWeek' => '[På] dddd LT',\n        'lastDay' => '[I går] LT',\n        'lastWeek' => '[I] dddd[s] LT',\n        'sameElse' => 'L',\n    ],\n    'ordinal' => function ($number) {\n        $lastDigit = $number % 10;\n\n        return $number.(\n            ((int) ($number % 100 / 10) === 1) ? 'e' : (\n                ($lastDigit === 1 || $lastDigit === 2) ? 'a' : 'e'\n            )\n        );\n    },\n    'months' => ['januari', 'februari', 'mars', 'april', 'maj', 'juni', 'juli', 'augusti', 'september', 'oktober', 'november', 'december'],\n    'months_short' => ['jan', 'feb', 'mar', 'apr', 'maj', 'jun', 'jul', 'aug', 'sep', 'okt', 'nov', 'dec'],\n    'weekdays' => ['söndag', 'måndag', 'tisdag', 'onsdag', 'torsdag', 'fredag', 'lördag'],\n    'weekdays_short' => ['sön', 'mån', 'tis', 'ons', 'tors', 'fre', 'lör'],\n    'weekdays_min' => ['sö', 'må', 'ti', 'on', 'to', 'fr', 'lö'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n    'list' => [', ', ' och '],\n    'meridiem' => ['fm', 'em'],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/sv_AX.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/sv.php', [\n    'formats' => [\n        'L' => 'YYYY-MM-dd',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd D MMMM YYYY HH:mm',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/sv_FI.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/sv.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/sv_SE.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/sv.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/sw.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - leyluj\n * - Josh Soref\n * - ryanhart2\n */\nreturn [\n    'year' => 'mwaka :count|miaka :count',\n    'a_year' => 'mwaka mmoja|miaka :count',\n    'y' => 'mwaka :count|miaka :count',\n    'month' => 'mwezi :count|miezi :count',\n    'a_month' => 'mwezi mmoja|miezi :count',\n    'm' => 'mwezi :count|miezi :count',\n    'week' => 'wiki :count',\n    'a_week' => 'wiki mmoja|wiki :count',\n    'w' => 'w. :count',\n    'day' => 'siku :count',\n    'a_day' => 'siku moja|masiku :count',\n    'd' => 'si. :count',\n    'hour' => 'saa :count|masaa :count',\n    'a_hour' => 'saa limoja|masaa :count',\n    'h' => 'saa :count|masaa :count',\n    'minute' => 'dakika :count',\n    'a_minute' => 'dakika moja|dakika :count',\n    'min' => 'd. :count',\n    'second' => 'sekunde :count',\n    'a_second' => 'hivi punde|sekunde :count',\n    's' => 'se. :count',\n    'ago' => 'tokea :time',\n    'from_now' => ':time baadaye',\n    'after' => ':time baada',\n    'before' => ':time kabla',\n    'diff_now' => 'sasa hivi',\n    'diff_today' => 'leo',\n    'diff_today_regexp' => 'leo(?:\\\\s+saa)?',\n    'diff_yesterday' => 'jana',\n    'diff_tomorrow' => 'kesho',\n    'diff_tomorrow_regexp' => 'kesho(?:\\\\s+saa)?',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD.MM.YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[leo saa] LT',\n        'nextDay' => '[kesho saa] LT',\n        'nextWeek' => '[wiki ijayo] dddd [saat] LT',\n        'lastDay' => '[jana] LT',\n        'lastWeek' => '[wiki iliyopita] dddd [saat] LT',\n        'sameElse' => 'L',\n    ],\n    'months' => ['Januari', 'Februari', 'Machi', 'Aprili', 'Mei', 'Juni', 'Julai', 'Agosti', 'Septemba', 'Oktoba', 'Novemba', 'Desemba'],\n    'months_short' => ['Jan', 'Feb', 'Mac', 'Apr', 'Mei', 'Jun', 'Jul', 'Ago', 'Sep', 'Okt', 'Nov', 'Des'],\n    'weekdays' => ['Jumapili', 'Jumatatu', 'Jumanne', 'Jumatano', 'Alhamisi', 'Ijumaa', 'Jumamosi'],\n    'weekdays_short' => ['Jpl', 'Jtat', 'Jnne', 'Jtan', 'Alh', 'Ijm', 'Jmos'],\n    'weekdays_min' => ['J2', 'J3', 'J4', 'J5', 'Al', 'Ij', 'J1'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n    'list' => [', ', ' na '],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/sw_CD.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/sw.php', [\n    'formats' => [\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMM YYYY',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/sw_KE.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Kamusi Project Martin Benjamin locales@kamusi.org\n */\nreturn array_replace_recursive(require __DIR__.'/sw.php', [\n    'formats' => [\n        'L' => 'DD/MM/YYYY',\n    ],\n    'months' => ['Januari', 'Februari', 'Machi', 'Aprili', 'Mei', 'Juni', 'Julai', 'Agosti', 'Septemba', 'Oktoba', 'Novemba', 'Desemba'],\n    'months_short' => ['Jan', 'Feb', 'Mac', 'Apr', 'Mei', 'Jun', 'Jul', 'Ago', 'Sep', 'Okt', 'Nov', 'Des'],\n    'weekdays' => ['Jumapili', 'Jumatatu', 'Jumanne', 'Jumatano', 'Alhamisi', 'Ijumaa', 'Jumamosi'],\n    'weekdays_short' => ['J2', 'J3', 'J4', 'J5', 'Alh', 'Ij', 'J1'],\n    'weekdays_min' => ['J2', 'J3', 'J4', 'J5', 'Alh', 'Ij', 'J1'],\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['asubuhi', 'alasiri'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/sw_TZ.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Kamusi Project Martin Benjamin locales@kamusi.org\n */\nreturn array_replace_recursive(require __DIR__.'/sw.php', [\n    'formats' => [\n        'L' => 'DD/MM/YYYY',\n    ],\n    'months' => ['Januari', 'Februari', 'Machi', 'Aprili', 'Mei', 'Juni', 'Julai', 'Agosti', 'Septemba', 'Oktoba', 'Novemba', 'Desemba'],\n    'months_short' => ['Jan', 'Feb', 'Mac', 'Apr', 'Mei', 'Jun', 'Jul', 'Ago', 'Sep', 'Okt', 'Nov', 'Des'],\n    'weekdays' => ['Jumapili', 'Jumatatu', 'Jumanne', 'Jumatano', 'Alhamisi', 'Ijumaa', 'Jumamosi'],\n    'weekdays_short' => ['J2', 'J3', 'J4', 'J5', 'Alh', 'Ij', 'J1'],\n    'weekdays_min' => ['J2', 'J3', 'J4', 'J5', 'Alh', 'Ij', 'J1'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['asubuhi', 'alasiri'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/sw_UG.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/sw.php', [\n    'formats' => [\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMM YYYY',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/szl.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/szl_PL.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/szl_PL.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - szl_PL locale Przemyslaw Buczkowski libc-alpha@sourceware.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD.MM.YYYY',\n    ],\n    'months' => ['styczyń', 'luty', 'merc', 'kwjeciyń', 'moj', 'czyrwjyń', 'lipjyń', 'siyrpjyń', 'wrzesiyń', 'październik', 'listopad', 'grudziyń'],\n    'months_short' => ['sty', 'lut', 'mer', 'kwj', 'moj', 'czy', 'lip', 'siy', 'wrz', 'paź', 'lis', 'gru'],\n    'weekdays' => ['niydziela', 'pyńdziŏek', 'wtŏrek', 'strzŏda', 'sztwortek', 'pjōntek', 'sobŏta'],\n    'weekdays_short' => ['niy', 'pyń', 'wtŏ', 'str', 'szt', 'pjō', 'sob'],\n    'weekdays_min' => ['niy', 'pyń', 'wtŏ', 'str', 'szt', 'pjō', 'sob'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n\n    'year' => ':count rok',\n    'y' => ':count rok',\n    'a_year' => ':count rok',\n\n    'month' => ':count mjeśůnc',\n    'm' => ':count mjeśůnc',\n    'a_month' => ':count mjeśůnc',\n\n    'week' => ':count tydźyń',\n    'w' => ':count tydźyń',\n    'a_week' => ':count tydźyń',\n\n    'day' => ':count dźyń',\n    'd' => ':count dźyń',\n    'a_day' => ':count dźyń',\n\n    'hour' => ':count godzina',\n    'h' => ':count godzina',\n    'a_hour' => ':count godzina',\n\n    'minute' => ':count minuta',\n    'min' => ':count minuta',\n    'a_minute' => ':count minuta',\n\n    'second' => ':count sekůnda',\n    's' => ':count sekůnda',\n    'a_second' => ':count sekůnda',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ta.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Josh Soref\n * - François B\n * - JD Isaacks\n * - Satheez\n */\nreturn [\n    'year' => ':count வருடம்|:count ஆண்டுகள்',\n    'a_year' => 'ஒரு வருடம்|:count ஆண்டுகள்',\n    'y' => ':count வருட.|:count ஆண்.',\n    'month' => ':count மாதம்|:count மாதங்கள்',\n    'a_month' => 'ஒரு மாதம்|:count மாதங்கள்',\n    'm' => ':count மாத.',\n    'week' => ':count வாரம்|:count வாரங்கள்',\n    'a_week' => 'ஒரு வாரம்|:count வாரங்கள்',\n    'w' => ':count வார.',\n    'day' => ':count நாள்|:count நாட்கள்',\n    'a_day' => 'ஒரு நாள்|:count நாட்கள்',\n    'd' => ':count நாள்|:count நாட்.',\n    'hour' => ':count மணி நேரம்|:count மணி நேரம்',\n    'a_hour' => 'ஒரு மணி நேரம்|:count மணி நேரம்',\n    'h' => ':count மணி.',\n    'minute' => ':count நிமிடம்|:count நிமிடங்கள்',\n    'a_minute' => 'ஒரு நிமிடம்|:count நிமிடங்கள்',\n    'min' => ':count நிமி.',\n    'second' => ':count சில விநாடிகள்|:count விநாடிகள்',\n    'a_second' => 'ஒரு சில விநாடிகள்|:count விநாடிகள்',\n    's' => ':count விநா.',\n    'ago' => ':time முன்',\n    'from_now' => ':time இல்',\n    'before' => ':time முன்',\n    'after' => ':time பின்',\n    'diff_now' => 'இப்போது',\n    'diff_today' => 'இன்று',\n    'diff_yesterday' => 'நேற்று',\n    'diff_tomorrow' => 'நாளை',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY, HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY, HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[இன்று] LT',\n        'nextDay' => '[நாளை] LT',\n        'nextWeek' => 'dddd, LT',\n        'lastDay' => '[நேற்று] LT',\n        'lastWeek' => '[கடந்த வாரம்] dddd, LT',\n        'sameElse' => 'L',\n    ],\n    'ordinal' => ':numberவது',\n    'meridiem' => function ($hour) {\n        if ($hour < 2) {\n            return ' யாமம்';\n        }\n        if ($hour < 6) {\n            return ' வைகறை';\n        }\n        if ($hour < 10) {\n            return ' காலை';\n        }\n        if ($hour < 14) {\n            return ' நண்பகல்';\n        }\n        if ($hour < 18) {\n            return ' எற்பாடு';\n        }\n        if ($hour < 22) {\n            return ' மாலை';\n        }\n\n        return ' யாமம்';\n    },\n    'months' => ['ஜனவரி', 'பிப்ரவரி', 'மார்ச்', 'ஏப்ரல்', 'மே', 'ஜூன்', 'ஜூலை', 'ஆகஸ்ட்', 'செப்டெம்பர்', 'அக்டோபர்', 'நவம்பர்', 'டிசம்பர்'],\n    'months_short' => ['ஜனவரி', 'பிப்ரவரி', 'மார்ச்', 'ஏப்ரல்', 'மே', 'ஜூன்', 'ஜூலை', 'ஆகஸ்ட்', 'செப்டெம்பர்', 'அக்டோபர்', 'நவம்பர்', 'டிசம்பர்'],\n    'weekdays' => ['ஞாயிற்றுக்கிழமை', 'திங்கட்கிழமை', 'செவ்வாய்கிழமை', 'புதன்கிழமை', 'வியாழக்கிழமை', 'வெள்ளிக்கிழமை', 'சனிக்கிழமை'],\n    'weekdays_short' => ['ஞாயிறு', 'திங்கள்', 'செவ்வாய்', 'புதன்', 'வியாழன்', 'வெள்ளி', 'சனி'],\n    'weekdays_min' => ['ஞா', 'தி', 'செ', 'பு', 'வி', 'வெ', 'ச'],\n    'first_day_of_week' => 0,\n    'day_of_first_week_of_year' => 1,\n    'list' => [', ', ' மற்றும் '],\n    'weekend' => [0, 0],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ta_IN.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - IBM Globalization Center of Competency, Yamato Software Laboratory    bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/ta.php', [\n    'formats' => [\n        'L' => 'D/M/YY',\n    ],\n    'months' => ['ஜனவரி', 'பிப்ரவரி', 'மார்ச்', 'ஏப்ரல்', 'மே', 'ஜூன்', 'ஜூலை', 'ஆகஸ்ட்', 'செப்டம்பர்', 'அக்டோபர்', 'நவம்பர்', 'டிசம்பர்'],\n    'months_short' => ['ஜன.', 'பிப்.', 'மார்.', 'ஏப்.', 'மே', 'ஜூன்', 'ஜூலை', 'ஆக.', 'செப்.', 'அக்.', 'நவ.', 'டிச.'],\n    'weekdays' => ['ஞாயிறு', 'திங்கள்', 'செவ்வாய்', 'புதன்', 'வியாழன்', 'வெள்ளி', 'சனி'],\n    'weekdays_short' => ['ஞா', 'தி', 'செ', 'பு', 'வி', 'வெ', 'ச'],\n    'weekdays_min' => ['ஞா', 'தி', 'செ', 'பு', 'வி', 'வெ', 'ச'],\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['காலை', 'மாலை'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ta_LK.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - J.Yogaraj 94-777-315206 yogaraj.ubuntu@gmail.com\n */\nreturn array_replace_recursive(require __DIR__.'/ta.php', [\n    'formats' => [\n        'L' => 'D/M/YY',\n    ],\n    'months' => ['ஜனவரி', 'பிப்ரவரி', 'மார்ச்', 'ஏப்ரல்', 'மே', 'ஜூன்', 'ஜூலை', 'ஆகஸ்ட்', 'செப்டம்பர்', 'அக்டோபர்', 'நவம்பர்', 'டிசம்பர்'],\n    'months_short' => ['ஜன', 'பிப்', 'மார்', 'ஏப்', 'மே', 'ஜூன்', 'ஜூலை', 'ஆக', 'செப்', 'அக்', 'நவ', 'டிச'],\n    'weekdays' => ['ஞாயிறு', 'திங்கள்', 'செவ்வாய்', 'புதன்', 'வியாழன்', 'வெள்ளி', 'சனி'],\n    'weekdays_short' => ['ஞா', 'தி', 'செ', 'பு', 'வி', 'வெ', 'ச'],\n    'weekdays_min' => ['ஞா', 'தி', 'செ', 'பு', 'வி', 'வெ', 'ச'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['காலை', 'மாலை'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ta_MY.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/ta.php', [\n    'formats' => [\n        'LT' => 'a h:mm',\n        'LTS' => 'a h:mm:ss',\n        'L' => 'D/M/yy',\n        'LL' => 'D MMM, YYYY',\n        'LLL' => 'D MMMM, YYYY, a h:mm',\n        'LLLL' => 'dddd, D MMMM, YYYY, a h:mm',\n    ],\n    'months' => ['ஜனவரி', 'பிப்ரவரி', 'மார்ச்', 'ஏப்ரல்', 'மே', 'ஜூன்', 'ஜூலை', 'ஆகஸ்ட்', 'செப்டம்பர்', 'அக்டோபர்', 'நவம்பர்', 'டிசம்பர்'],\n    'months_short' => ['ஜன.', 'பிப்.', 'மார்.', 'ஏப்.', 'மே', 'ஜூன்', 'ஜூலை', 'ஆக.', 'செப்.', 'அக்.', 'நவ.', 'டிச.'],\n    'weekdays' => ['ஞாயிறு', 'திங்கள்', 'செவ்வாய்', 'புதன்', 'வியாழன்', 'வெள்ளி', 'சனி'],\n    'weekdays_short' => ['ஞாயி.', 'திங்.', 'செவ்.', 'புத.', 'வியா.', 'வெள்.', 'சனி'],\n    'weekdays_min' => ['ஞா', 'தி', 'செ', 'பு', 'வி', 'வெ', 'ச'],\n    'first_day_of_week' => 1,\n    'meridiem' => ['மு.ப', 'பி.ப'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ta_SG.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/ta.php', [\n    'formats' => [\n        'LT' => 'a h:mm',\n        'LTS' => 'a h:mm:ss',\n        'L' => 'D/M/yy',\n        'LL' => 'D MMM, YYYY',\n        'LLL' => 'D MMMM, YYYY, a h:mm',\n        'LLLL' => 'dddd, D MMMM, YYYY, a h:mm',\n    ],\n    'months' => ['ஜனவரி', 'பிப்ரவரி', 'மார்ச்', 'ஏப்ரல்', 'மே', 'ஜூன்', 'ஜூலை', 'ஆகஸ்ட்', 'செப்டம்பர்', 'அக்டோபர்', 'நவம்பர்', 'டிசம்பர்'],\n    'months_short' => ['ஜன.', 'பிப்.', 'மார்.', 'ஏப்.', 'மே', 'ஜூன்', 'ஜூலை', 'ஆக.', 'செப்.', 'அக்.', 'நவ.', 'டிச.'],\n    'weekdays' => ['ஞாயிறு', 'திங்கள்', 'செவ்வாய்', 'புதன்', 'வியாழன்', 'வெள்ளி', 'சனி'],\n    'weekdays_short' => ['ஞாயி.', 'திங்.', 'செவ்.', 'புத.', 'வியா.', 'வெள்.', 'சனி'],\n    'weekdays_min' => ['ஞா', 'தி', 'செ', 'பு', 'வி', 'வெ', 'ச'],\n    'meridiem' => ['மு.ப', 'பி.ப'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/tcy.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/tcy_IN.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/tcy_IN.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - IndLinux.org, Samsung Electronics Co., Ltd.    alexey.merzlyakov@samsung.com\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'D/M/YY',\n    ],\n    'months' => ['ಜನವರಿ', 'ಫೆಬ್ರುವರಿ', 'ಮಾರ್ಚ್', 'ಏಪ್ರಿಲ್‌‌', 'ಮೇ', 'ಜೂನ್', 'ಜುಲೈ', 'ಆಗಸ್ಟ್', 'ಸೆಪ್ಟೆಂಬರ್‌', 'ಅಕ್ಟೋಬರ್', 'ನವೆಂಬರ್', 'ಡಿಸೆಂಬರ್'],\n    'months_short' => ['ಜ', 'ಫೆ', 'ಮಾ', 'ಏ', 'ಮೇ', 'ಜೂ', 'ಜು', 'ಆ', 'ಸೆ', 'ಅ', 'ನ', 'ಡಿ'],\n    'weekdays' => ['ಐಥಾರ', 'ಸೋಮಾರ', 'ಅಂಗರೆ', 'ಬುಧಾರ', 'ಗುರುವಾರ', 'ಶುಕ್ರರ', 'ಶನಿವಾರ'],\n    'weekdays_short' => ['ಐ', 'ಸೋ', 'ಅಂ', 'ಬು', 'ಗು', 'ಶು', 'ಶ'],\n    'weekdays_min' => ['ಐ', 'ಸೋ', 'ಅಂ', 'ಬು', 'ಗು', 'ಶು', 'ಶ'],\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['ಕಾಂಡೆ', 'ಬಯ್ಯ'],\n\n    'year' => ':count ನೀರ್', // less reliable\n    'y' => ':count ನೀರ್', // less reliable\n    'a_year' => ':count ನೀರ್', // less reliable\n\n    'month' => ':count ಮೀನ್', // less reliable\n    'm' => ':count ಮೀನ್', // less reliable\n    'a_month' => ':count ಮೀನ್', // less reliable\n\n    'day' => ':count ಸುಗ್ಗಿ', // less reliable\n    'd' => ':count ಸುಗ್ಗಿ', // less reliable\n    'a_day' => ':count ಸುಗ್ಗಿ', // less reliable\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/te.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Kunal Marwaha\n * - Josh Soref\n * - François B\n * - kc\n */\nreturn [\n    'year' => ':count సంవత్సరం|:count సంవత్సరాలు',\n    'a_year' => 'ఒక సంవత్సరం|:count సంవత్సరాలు',\n    'y' => ':count సం.',\n    'month' => ':count నెల|:count నెలలు',\n    'a_month' => 'ఒక నెల|:count నెలలు',\n    'm' => ':count నెల|:count నెల.',\n    'week' => ':count వారం|:count వారాలు',\n    'a_week' => 'ఒక వారం|:count వారాలు',\n    'w' => ':count వార.|:count వారా.',\n    'day' => ':count రోజు|:count రోజులు',\n    'a_day' => 'ఒక రోజు|:count రోజులు',\n    'd' => ':count రోజు|:count రోజు.',\n    'hour' => ':count గంట|:count గంటలు',\n    'a_hour' => 'ఒక గంట|:count గంటలు',\n    'h' => ':count గం.',\n    'minute' => ':count నిమిషం|:count నిమిషాలు',\n    'a_minute' => 'ఒక నిమిషం|:count నిమిషాలు',\n    'min' => ':count నిమి.',\n    'second' => ':count సెకను|:count సెకన్లు',\n    'a_second' => 'కొన్ని క్షణాలు|:count సెకన్లు',\n    's' => ':count సెక.',\n    'ago' => ':time క్రితం',\n    'from_now' => ':time లో',\n    'diff_now' => 'ప్రస్తుతం',\n    'diff_today' => 'నేడు',\n    'diff_yesterday' => 'నిన్న',\n    'diff_tomorrow' => 'రేపు',\n    'formats' => [\n        'LT' => 'A h:mm',\n        'LTS' => 'A h:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY, A h:mm',\n        'LLLL' => 'dddd, D MMMM YYYY, A h:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[నేడు] LT',\n        'nextDay' => '[రేపు] LT',\n        'nextWeek' => 'dddd, LT',\n        'lastDay' => '[నిన్న] LT',\n        'lastWeek' => '[గత] dddd, LT',\n        'sameElse' => 'L',\n    ],\n    'ordinal' => ':numberవ',\n    'meridiem' => function ($hour) {\n        if ($hour < 4) {\n            return 'రాత్రి';\n        }\n        if ($hour < 10) {\n            return 'ఉదయం';\n        }\n        if ($hour < 17) {\n            return 'మధ్యాహ్నం';\n        }\n        if ($hour < 20) {\n            return 'సాయంత్రం';\n        }\n\n        return ' రాత్రి';\n    },\n    'months' => ['జనవరి', 'ఫిబ్రవరి', 'మార్చి', 'ఏప్రిల్', 'మే', 'జూన్', 'జూలై', 'ఆగస్టు', 'సెప్టెంబర్', 'అక్టోబర్', 'నవంబర్', 'డిసెంబర్'],\n    'months_short' => ['జన.', 'ఫిబ్ర.', 'మార్చి', 'ఏప్రి.', 'మే', 'జూన్', 'జూలై', 'ఆగ.', 'సెప్.', 'అక్టో.', 'నవ.', 'డిసె.'],\n    'weekdays' => ['ఆదివారం', 'సోమవారం', 'మంగళవారం', 'బుధవారం', 'గురువారం', 'శుక్రవారం', 'శనివారం'],\n    'weekdays_short' => ['ఆది', 'సోమ', 'మంగళ', 'బుధ', 'గురు', 'శుక్ర', 'శని'],\n    'weekdays_min' => ['ఆ', 'సో', 'మం', 'బు', 'గు', 'శు', 'శ'],\n    'list' => ', ',\n    'first_day_of_week' => 0,\n    'day_of_first_week_of_year' => 1,\n    'weekend' => [0, 0],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/te_IN.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/te.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/teo.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/ta.php', [\n    'meridiem' => ['Taparachu', 'Ebongi'],\n    'weekdays' => ['Nakaejuma', 'Nakaebarasa', 'Nakaare', 'Nakauni', 'Nakaung’on', 'Nakakany', 'Nakasabiti'],\n    'weekdays_short' => ['Jum', 'Bar', 'Aar', 'Uni', 'Ung', 'Kan', 'Sab'],\n    'weekdays_min' => ['Jum', 'Bar', 'Aar', 'Uni', 'Ung', 'Kan', 'Sab'],\n    'months' => ['Orara', 'Omuk', 'Okwamg’', 'Odung’el', 'Omaruk', 'Omodok’king’ol', 'Ojola', 'Opedel', 'Osokosokoma', 'Otibar', 'Olabor', 'Opoo'],\n    'months_short' => ['Rar', 'Muk', 'Kwa', 'Dun', 'Mar', 'Mod', 'Jol', 'Ped', 'Sok', 'Tib', 'Lab', 'Poo'],\n    'first_day_of_week' => 1,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY HH:mm',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/teo_KE.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/teo.php', [\n    'first_day_of_week' => 0,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/tet.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Joshua Brooks\n * - François B\n */\nreturn [\n    'year' => 'tinan :count',\n    'a_year' => '{1}tinan ida|tinan :count',\n    'month' => 'fulan :count',\n    'a_month' => '{1}fulan ida|fulan :count',\n    'week' => 'semana :count',\n    'a_week' => '{1}semana ida|semana :count',\n    'day' => 'loron :count',\n    'a_day' => '{1}loron ida|loron :count',\n    'hour' => 'oras :count',\n    'a_hour' => '{1}oras ida|oras :count',\n    'minute' => 'minutu :count',\n    'a_minute' => '{1}minutu ida|minutu :count',\n    'second' => 'segundu :count',\n    'a_second' => '{1}segundu balun|segundu :count',\n    'ago' => ':time liuba',\n    'from_now' => 'iha :time',\n    'diff_yesterday' => 'Horiseik',\n    'diff_yesterday_regexp' => 'Horiseik(?:\\\\s+iha)?',\n    'diff_today' => 'Ohin',\n    'diff_today_regexp' => 'Ohin(?:\\\\s+iha)?',\n    'diff_tomorrow' => 'Aban',\n    'diff_tomorrow_regexp' => 'Aban(?:\\\\s+iha)?',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[Ohin iha] LT',\n        'nextDay' => '[Aban iha] LT',\n        'nextWeek' => 'dddd [iha] LT',\n        'lastDay' => '[Horiseik iha] LT',\n        'lastWeek' => 'dddd [semana kotuk] [iha] LT',\n        'sameElse' => 'L',\n    ],\n    'ordinal' => ':numberº',\n    'months' => ['Janeiru', 'Fevereiru', 'Marsu', 'Abril', 'Maiu', 'Juñu', 'Jullu', 'Agustu', 'Setembru', 'Outubru', 'Novembru', 'Dezembru'],\n    'months_short' => ['Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set', 'Out', 'Nov', 'Dez'],\n    'weekdays' => ['Domingu', 'Segunda', 'Tersa', 'Kuarta', 'Kinta', 'Sesta', 'Sabadu'],\n    'weekdays_short' => ['Dom', 'Seg', 'Ters', 'Kua', 'Kint', 'Sest', 'Sab'],\n    'weekdays_min' => ['Do', 'Seg', 'Te', 'Ku', 'Ki', 'Ses', 'Sa'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/tg.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Orif N. Jr\n */\nreturn [\n    'year' => '{1}як сол|:count сол',\n    'month' => '{1}як моҳ|:count моҳ',\n    'week' => '{1}як ҳафта|:count ҳафта',\n    'day' => '{1}як рӯз|:count рӯз',\n    'hour' => '{1}як соат|:count соат',\n    'minute' => '{1}як дақиқа|:count дақиқа',\n    'second' => '{1}якчанд сония|:count сония',\n    'ago' => ':time пеш',\n    'from_now' => 'баъди :time',\n    'diff_today' => 'Имрӯз',\n    'diff_yesterday' => 'Дирӯз',\n    'diff_yesterday_regexp' => 'Дирӯз(?:\\\\s+соати)?',\n    'diff_tomorrow' => 'Пагоҳ',\n    'diff_tomorrow_regexp' => 'Пагоҳ(?:\\\\s+соати)?',\n    'diff_today_regexp' => 'Имрӯз(?:\\\\s+соати)?',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[Имрӯз соати] LT',\n        'nextDay' => '[Пагоҳ соати] LT',\n        'nextWeek' => 'dddd[и] [ҳафтаи оянда соати] LT',\n        'lastDay' => '[Дирӯз соати] LT',\n        'lastWeek' => 'dddd[и] [ҳафтаи гузашта соати] LT',\n        'sameElse' => 'L',\n    ],\n    'ordinal' => function ($number) {\n        if ($number === 0) { // special case for zero\n            return \"$number-ıncı\";\n        }\n\n        static $suffixes = [\n            0 => '-ум',\n            1 => '-ум',\n            2 => '-юм',\n            3 => '-юм',\n            4 => '-ум',\n            5 => '-ум',\n            6 => '-ум',\n            7 => '-ум',\n            8 => '-ум',\n            9 => '-ум',\n            10 => '-ум',\n            12 => '-ум',\n            13 => '-ум',\n            20 => '-ум',\n            30 => '-юм',\n            40 => '-ум',\n            50 => '-ум',\n            60 => '-ум',\n            70 => '-ум',\n            80 => '-ум',\n            90 => '-ум',\n            100 => '-ум',\n        ];\n\n        return $number.($suffixes[$number] ?? $suffixes[$number % 10] ?? $suffixes[$number >= 100 ? 100 : -1] ?? '');\n    },\n    'meridiem' => function ($hour) {\n        if ($hour < 4) {\n            return 'шаб';\n        }\n        if ($hour < 11) {\n            return 'субҳ';\n        }\n        if ($hour < 16) {\n            return 'рӯз';\n        }\n        if ($hour < 19) {\n            return 'бегоҳ';\n        }\n\n        return 'шаб';\n    },\n    'months' => ['январ', 'феврал', 'март', 'апрел', 'май', 'июн', 'июл', 'август', 'сентябр', 'октябр', 'ноябр', 'декабр'],\n    'months_short' => ['янв', 'фев', 'мар', 'апр', 'май', 'июн', 'июл', 'авг', 'сен', 'окт', 'ноя', 'дек'],\n    'weekdays' => ['якшанбе', 'душанбе', 'сешанбе', 'чоршанбе', 'панҷшанбе', 'ҷумъа', 'шанбе'],\n    'weekdays_short' => ['яшб', 'дшб', 'сшб', 'чшб', 'пшб', 'ҷум', 'шнб'],\n    'weekdays_min' => ['яш', 'дш', 'сш', 'чш', 'пш', 'ҷм', 'шб'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n    'list' => [', ', ' ва '],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/tg_TJ.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/tg.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/th.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Nate Whittaker\n * - John MacAslan\n * - Chanintorn Asavavichairoj\n * - JD Isaacks\n * - ROKAISAKKON\n * - RO'KAISAKKON\n * - Andreas Möller\n * - nithisa\n */\nreturn [\n    'year' => ':count ปี',\n    'y' => ':count ปี',\n    'month' => ':count เดือน',\n    'm' => ':count เดือน',\n    'week' => ':count สัปดาห์',\n    'w' => ':count สัปดาห์',\n    'day' => ':count วัน',\n    'd' => ':count วัน',\n    'hour' => ':count ชั่วโมง',\n    'h' => ':count ชั่วโมง',\n    'minute' => ':count นาที',\n    'min' => ':count นาที',\n    'second' => ':count วินาที',\n    'a_second' => '{1}ไม่กี่วินาที|]1,Inf[:count วินาที',\n    's' => ':count วินาที',\n    'ago' => ':timeที่แล้ว',\n    'from_now' => 'อีก :time',\n    'after' => ':timeหลังจากนี้',\n    'before' => ':timeก่อน',\n    'diff_now' => 'ขณะนี้',\n    'diff_today' => 'วันนี้',\n    'diff_today_regexp' => 'วันนี้(?:\\\\s+เวลา)?',\n    'diff_yesterday' => 'เมื่อวาน',\n    'diff_yesterday_regexp' => 'เมื่อวานนี้(?:\\\\s+เวลา)?',\n    'diff_tomorrow' => 'พรุ่งนี้',\n    'diff_tomorrow_regexp' => 'พรุ่งนี้(?:\\\\s+เวลา)?',\n    'formats' => [\n        'LT' => 'H:mm',\n        'LTS' => 'H:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY เวลา H:mm',\n        'LLLL' => 'วันddddที่ D MMMM YYYY เวลา H:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[วันนี้ เวลา] LT',\n        'nextDay' => '[พรุ่งนี้ เวลา] LT',\n        'nextWeek' => 'dddd[หน้า เวลา] LT',\n        'lastDay' => '[เมื่อวานนี้ เวลา] LT',\n        'lastWeek' => '[วัน]dddd[ที่แล้ว เวลา] LT',\n        'sameElse' => 'L',\n    ],\n    'meridiem' => ['ก่อนเที่ยง', 'หลังเที่ยง'],\n    'months' => ['มกราคม', 'กุมภาพันธ์', 'มีนาคม', 'เมษายน', 'พฤษภาคม', 'มิถุนายน', 'กรกฎาคม', 'สิงหาคม', 'กันยายน', 'ตุลาคม', 'พฤศจิกายน', 'ธันวาคม'],\n    'months_short' => ['ม.ค.', 'ก.พ.', 'มี.ค.', 'เม.ย.', 'พ.ค.', 'มิ.ย.', 'ก.ค.', 'ส.ค.', 'ก.ย.', 'ต.ค.', 'พ.ย.', 'ธ.ค.'],\n    'weekdays' => ['อาทิตย์', 'จันทร์', 'อังคาร', 'พุธ', 'พฤหัสบดี', 'ศุกร์', 'เสาร์'],\n    'weekdays_short' => ['อาทิตย์', 'จันทร์', 'อังคาร', 'พุธ', 'พฤหัส', 'ศุกร์', 'เสาร์'],\n    'weekdays_min' => ['อา.', 'จ.', 'อ.', 'พ.', 'พฤ.', 'ศ.', 'ส.'],\n    'list' => [', ', ' และ '],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/th_TH.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/th.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/the.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/the_NP.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/the_NP.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Chitwanix OS Development    info@chitwanix.com\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'dddd DD MMM YYYY',\n    ],\n    'months' => ['जनवरी', 'फ़रवरी', 'मार्च', 'अप्रेल', 'मई', 'जून', 'जुलाई', 'अगस्त', 'सितम्बर', 'अक्टूबर', 'नवम्बर', 'दिसम्बर'],\n    'months_short' => ['जनवरी', 'फ़रवरी', 'मार्च', 'अप्रेल', 'मई', 'जून', 'जुलाई', 'अगस्त', 'सितम्बर', 'अक्टूबर', 'नवम्बर', 'दिसम्बर'],\n    'weekdays' => ['आइतबार', 'सोमबार', 'मंगलबार', 'बुधबार', 'बिहिबार', 'शुक्रबार', 'शनिबार'],\n    'weekdays_short' => ['आइत', 'सोम', 'मंगल', 'बुध', 'बिहि', 'शुक्र', 'शनि'],\n    'weekdays_min' => ['आइत', 'सोम', 'मंगल', 'बुध', 'बिहि', 'शुक्र', 'शनि'],\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['पूर्वाह्न', 'अपराह्न'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ti.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/ti_ER.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ti_ER.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Ge'ez Frontier Foundation    locales@geez.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD/MM/YYYY',\n    ],\n    'months' => ['ጥሪ', 'ለካቲት', 'መጋቢት', 'ሚያዝያ', 'ግንቦት', 'ሰነ', 'ሓምለ', 'ነሓሰ', 'መስከረም', 'ጥቅምቲ', 'ሕዳር', 'ታሕሳስ'],\n    'months_short' => ['ጥሪ ', 'ለካቲ', 'መጋቢ', 'ሚያዝ', 'ግንቦ', 'ሰነ ', 'ሓምለ', 'ነሓሰ', 'መስከ', 'ጥቅም', 'ሕዳር', 'ታሕሳ'],\n    'weekdays' => ['ሰንበት', 'ሰኑይ', 'ሰሉስ', 'ረቡዕ', 'ሓሙስ', 'ዓርቢ', 'ቀዳም'],\n    'weekdays_short' => ['ሰንበ', 'ሰኑይ', 'ሰሉስ', 'ረቡዕ', 'ሓሙስ', 'ዓርቢ', 'ቀዳም'],\n    'weekdays_min' => ['ሰንበ', 'ሰኑይ', 'ሰሉስ', 'ረቡዕ', 'ሓሙስ', 'ዓርቢ', 'ቀዳም'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['ንጉሆ ሰዓተ', 'ድሕር ሰዓት'],\n\n    'year' => ':count ዓመት',\n    'y' => ':count ዓመት',\n    'a_year' => ':count ዓመት',\n\n    'month' => 'ወርሒ :count',\n    'm' => 'ወርሒ :count',\n    'a_month' => 'ወርሒ :count',\n\n    'week' => ':count ሰሙን',\n    'w' => ':count ሰሙን',\n    'a_week' => ':count ሰሙን',\n\n    'day' => ':count መዓልቲ',\n    'd' => ':count መዓልቲ',\n    'a_day' => ':count መዓልቲ',\n\n    'hour' => ':count ሰዓት',\n    'h' => ':count ሰዓት',\n    'a_hour' => ':count ሰዓት',\n\n    'minute' => ':count ደቒቕ',\n    'min' => ':count ደቒቕ',\n    'a_minute' => ':count ደቒቕ',\n\n    'second' => ':count ሰከንድ',\n    's' => ':count ሰከንድ',\n    'a_second' => ':count ሰከንድ',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ti_ET.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Ge'ez Frontier Foundation    locales@geez.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD/MM/YYYY',\n    ],\n    'months' => ['ጃንዩወሪ', 'ፌብሩወሪ', 'ማርች', 'ኤፕረል', 'ሜይ', 'ጁን', 'ጁላይ', 'ኦገስት', 'ሴፕቴምበር', 'ኦክተውበር', 'ኖቬምበር', 'ዲሴምበር'],\n    'months_short' => ['ጃንዩ', 'ፌብሩ', 'ማርች', 'ኤፕረ', 'ሜይ ', 'ጁን ', 'ጁላይ', 'ኦገስ', 'ሴፕቴ', 'ኦክተ', 'ኖቬም', 'ዲሴም'],\n    'weekdays' => ['ሰንበት', 'ሰኑይ', 'ሰሉስ', 'ረቡዕ', 'ሓሙስ', 'ዓርቢ', 'ቀዳም'],\n    'weekdays_short' => ['ሰንበ', 'ሰኑይ', 'ሰሉስ', 'ረቡዕ', 'ሓሙስ', 'ዓርቢ', 'ቀዳም'],\n    'weekdays_min' => ['ሰንበ', 'ሰኑይ', 'ሰሉስ', 'ረቡዕ', 'ሓሙስ', 'ዓርቢ', 'ቀዳም'],\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['ንጉሆ ሰዓተ', 'ድሕር ሰዓት'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/tig.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/tig_ER.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/tig_ER.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Ge'ez Frontier Foundation    locales@geez.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD/MM/YYYY',\n    ],\n    'months' => ['ጥሪ', 'ለካቲት', 'መጋቢት', 'ሚያዝያ', 'ግንቦት', 'ሰነ', 'ሓምለ', 'ነሓሰ', 'መስከረም', 'ጥቅምቲ', 'ሕዳር', 'ታሕሳስ'],\n    'months_short' => ['ጥሪ ', 'ለካቲ', 'መጋቢ', 'ሚያዝ', 'ግንቦ', 'ሰነ ', 'ሓምለ', 'ነሓሰ', 'መስከ', 'ጥቅም', 'ሕዳር', 'ታሕሳ'],\n    'weekdays' => ['ሰንበት ዓባይ', 'ሰኖ', 'ታላሸኖ', 'ኣረርባዓ', 'ከሚሽ', 'ጅምዓት', 'ሰንበት ንኢሽ'],\n    'weekdays_short' => ['ሰ//ዓ', 'ሰኖ ', 'ታላሸ', 'ኣረር', 'ከሚሽ', 'ጅምዓ', 'ሰ//ን'],\n    'weekdays_min' => ['ሰ//ዓ', 'ሰኖ ', 'ታላሸ', 'ኣረር', 'ከሚሽ', 'ጅምዓ', 'ሰ//ን'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['ቀደም ሰር ምዕል', 'ሓቆ ሰር ምዕል'],\n\n    'year' => ':count ማይ', // less reliable\n    'y' => ':count ማይ', // less reliable\n    'a_year' => ':count ማይ', // less reliable\n\n    'month' => ':count ሸምሽ', // less reliable\n    'm' => ':count ሸምሽ', // less reliable\n    'a_month' => ':count ሸምሽ', // less reliable\n\n    'week' => ':count ሰቡዕ', // less reliable\n    'w' => ':count ሰቡዕ', // less reliable\n    'a_week' => ':count ሰቡዕ', // less reliable\n\n    'day' => ':count ዎሮ', // less reliable\n    'd' => ':count ዎሮ', // less reliable\n    'a_day' => ':count ዎሮ', // less reliable\n\n    'hour' => ':count ሰዓት', // less reliable\n    'h' => ':count ሰዓት', // less reliable\n    'a_hour' => ':count ሰዓት', // less reliable\n\n    'minute' => ':count ካልኣይት', // less reliable\n    'min' => ':count ካልኣይት', // less reliable\n    'a_minute' => ':count ካልኣይት', // less reliable\n\n    'second' => ':count ካልኣይ',\n    's' => ':count ካልኣይ',\n    'a_second' => ':count ካልኣይ',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/tk.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/tk_TM.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/tk_TM.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/**\n * Authors:\n * - Ghorban M. Tavakoly Pablo Saratxaga & Ghorban M. Tavakoly pablo@walon.org & gmt314@yahoo.com\n * - SuperManPHP\n * - Maksat Meredow (isadma)\n */\n$transformDiff = function ($input) {\n    return strtr($input, [\n        'sekunt' => 'sekunt',\n        'hepde' => 'hepde',\n    ]);\n};\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD.MM.YYYY',\n    ],\n    'months' => ['Ýanwar', 'Fewral', 'Mart', 'Aprel', 'Maý', 'Iýun', 'Iýul', 'Awgust', 'Sentýabr', 'Oktýabr', 'Noýabr', 'Dekabr'],\n    'months_short' => ['Ýan', 'Few', 'Mar', 'Apr', 'Maý', 'Iýn', 'Iýl', 'Awg', 'Sen', 'Okt', 'Noý', 'Dek'],\n    'weekdays' => ['Duşenbe', 'Sişenbe', 'Çarşenbe', 'Penşenbe', 'Anna', 'Şenbe', 'Ýekşenbe'],\n    'weekdays_short' => ['Duş', 'Siş', 'Çar', 'Pen', 'Ann', 'Şen', 'Ýek'],\n    'weekdays_min' => ['Du', 'Si', 'Ça', 'Pe', 'An', 'Şe', 'Ýe'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n\n    'year' => ':count ýyl',\n    'y' => ':count ýyl',\n    'a_year' => ':count ýyl',\n\n    'month' => ':count aý',\n    'm' => ':count aý',\n    'a_month' => ':count aý',\n\n    'week' => ':count hepde',\n    'w' => ':count hepde',\n    'a_week' => ':count hepde',\n\n    'day' => ':count gün',\n    'd' => ':count gün',\n    'a_day' => ':count gün',\n\n    'hour' => ':count sagat',\n    'h' => ':count sagat',\n    'a_hour' => ':count sagat',\n\n    'minute' => ':count minut',\n    'min' => ':count minut',\n    'a_minute' => ':count minut',\n\n    'second' => ':count sekunt',\n    's' => ':count sekunt',\n    'a_second' => ':count sekunt',\n\n    'ago' => function ($time) use ($transformDiff) {\n        return $transformDiff($time).' ozal';\n    },\n    'from_now' => function ($time) use ($transformDiff) {\n        return $transformDiff($time).' soňra';\n    },\n    'after' => function ($time) use ($transformDiff) {\n        return $transformDiff($time).' soň';\n    },\n    'before' => function ($time) use ($transformDiff) {\n        return $transformDiff($time).' öň';\n    },\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/tl.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn [\n    'year' => ':count taon',\n    'a_year' => '{1}isang taon|:count taon',\n    'month' => ':count buwan',\n    'a_month' => '{1}isang buwan|:count buwan',\n    'week' => ':count linggo',\n    'a_week' => '{1}isang linggo|:count linggo',\n    'day' => ':count araw',\n    'a_day' => '{1}isang araw|:count araw',\n    'hour' => ':count oras',\n    'a_hour' => '{1}isang oras|:count oras',\n    'minute' => ':count minuto',\n    'a_minute' => '{1}isang minuto|:count minuto',\n    'min' => ':count min.',\n    'second' => ':count segundo',\n    'a_second' => '{1}ilang segundo|:count segundo',\n    's' => ':count seg.',\n    'ago' => ':time ang nakalipas',\n    'from_now' => 'sa loob ng :time',\n    'diff_now' => 'ngayon',\n    'diff_today' => 'ngayong',\n    'diff_today_regexp' => 'ngayong(?:\\\\s+araw)?',\n    'diff_yesterday' => 'kahapon',\n    'diff_tomorrow' => 'bukas',\n    'diff_tomorrow_regexp' => 'Bukas(?:\\\\s+ng)?',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'MM/D/YYYY',\n        'LL' => 'MMMM D, YYYY',\n        'LLL' => 'MMMM D, YYYY HH:mm',\n        'LLLL' => 'dddd, MMMM DD, YYYY HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => 'LT [ngayong araw]',\n        'nextDay' => '[Bukas ng] LT',\n        'nextWeek' => 'LT [sa susunod na] dddd',\n        'lastDay' => 'LT [kahapon]',\n        'lastWeek' => 'LT [noong nakaraang] dddd',\n        'sameElse' => 'L',\n    ],\n    'months' => ['Enero', 'Pebrero', 'Marso', 'Abril', 'Mayo', 'Hunyo', 'Hulyo', 'Agosto', 'Setyembre', 'Oktubre', 'Nobyembre', 'Disyembre'],\n    'months_short' => ['Ene', 'Peb', 'Mar', 'Abr', 'May', 'Hun', 'Hul', 'Ago', 'Set', 'Okt', 'Nob', 'Dis'],\n    'weekdays' => ['Linggo', 'Lunes', 'Martes', 'Miyerkules', 'Huwebes', 'Biyernes', 'Sabado'],\n    'weekdays_short' => ['Lin', 'Lun', 'Mar', 'Miy', 'Huw', 'Biy', 'Sab'],\n    'weekdays_min' => ['Li', 'Lu', 'Ma', 'Mi', 'Hu', 'Bi', 'Sab'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n    'list' => [', ', ' at '],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/tl_PH.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - François B\n * - Ian De La Cruz\n * - JD Isaacks\n */\nreturn require __DIR__.'/tl.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/tlh.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - François B\n * - Serhan Apaydın\n * - Dominika\n */\nreturn [\n    'year' => '{1}wa’ DIS|:count DIS',\n    'month' => '{1}wa’ jar|:count jar',\n    'week' => '{1}wa’ hogh|:count hogh',\n    'day' => '{1}wa’ jaj|:count jaj',\n    'hour' => '{1}wa’ rep|:count rep',\n    'minute' => '{1}wa’ tup|:count tup',\n    'second' => '{1}puS lup|:count lup',\n    'ago' => function ($time) {\n        $output = strtr($time, [\n            'jaj' => 'Hu’',\n            'jar' => 'wen',\n            'DIS' => 'ben',\n        ]);\n\n        return $output === $time ? \"$time ret\" : $output;\n    },\n    'from_now' => function ($time) {\n        $output = strtr($time, [\n            'jaj' => 'leS',\n            'jar' => 'waQ',\n            'DIS' => 'nem',\n        ]);\n\n        return $output === $time ? \"$time pIq\" : $output;\n    },\n    'diff_yesterday' => 'wa’Hu’',\n    'diff_today' => 'DaHjaj',\n    'diff_tomorrow' => 'wa’leS',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD.MM.YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[DaHjaj] LT',\n        'nextDay' => '[wa’leS] LT',\n        'nextWeek' => 'LLL',\n        'lastDay' => '[wa’Hu’] LT',\n        'lastWeek' => 'LLL',\n        'sameElse' => 'L',\n    ],\n    'ordinal' => ':number.',\n    'months' => ['tera’ jar wa’', 'tera’ jar cha’', 'tera’ jar wej', 'tera’ jar loS', 'tera’ jar vagh', 'tera’ jar jav', 'tera’ jar Soch', 'tera’ jar chorgh', 'tera’ jar Hut', 'tera’ jar wa’maH', 'tera’ jar wa’maH wa’', 'tera’ jar wa’maH cha’'],\n    'months_short' => ['jar wa’', 'jar cha’', 'jar wej', 'jar loS', 'jar vagh', 'jar jav', 'jar Soch', 'jar chorgh', 'jar Hut', 'jar wa’maH', 'jar wa’maH wa’', 'jar wa’maH cha’'],\n    'weekdays' => ['lojmItjaj', 'DaSjaj', 'povjaj', 'ghItlhjaj', 'loghjaj', 'buqjaj', 'ghInjaj'],\n    'weekdays_short' => ['lojmItjaj', 'DaSjaj', 'povjaj', 'ghItlhjaj', 'loghjaj', 'buqjaj', 'ghInjaj'],\n    'weekdays_min' => ['lojmItjaj', 'DaSjaj', 'povjaj', 'ghItlhjaj', 'loghjaj', 'buqjaj', 'ghInjaj'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n    'list' => [', ', ' ’ej '],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/tn.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/tn_ZA.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/tn_ZA.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Zuza Software Foundation (Translate.org.za) Dwayne Bailey dwayne@translate.org.za\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD/MM/YYYY',\n    ],\n    'months' => ['Ferikgong', 'Tlhakole', 'Mopitlwe', 'Moranang', 'Motsheganong', 'Seetebosigo', 'Phukwi', 'Phatwe', 'Lwetse', 'Diphalane', 'Ngwanatsele', 'Sedimonthole'],\n    'months_short' => ['Fer', 'Tlh', 'Mop', 'Mor', 'Mot', 'See', 'Phu', 'Pha', 'Lwe', 'Dip', 'Ngw', 'Sed'],\n    'weekdays' => ['laTshipi', 'Mosupologo', 'Labobedi', 'Laboraro', 'Labone', 'Labotlhano', 'Lamatlhatso'],\n    'weekdays_short' => ['Tsh', 'Mos', 'Bed', 'Rar', 'Ne', 'Tlh', 'Mat'],\n    'weekdays_min' => ['Tsh', 'Mos', 'Bed', 'Rar', 'Ne', 'Tlh', 'Mat'],\n    'day_of_first_week_of_year' => 1,\n\n    'year' => 'dingwaga di le :count',\n    'y' => 'dingwaga di le :count',\n    'a_year' => 'dingwaga di le :count',\n\n    'month' => 'dikgwedi di le :count',\n    'm' => 'dikgwedi di le :count',\n    'a_month' => 'dikgwedi di le :count',\n\n    'week' => 'dibeke di le :count',\n    'w' => 'dibeke di le :count',\n    'a_week' => 'dibeke di le :count',\n\n    'day' => 'malatsi :count',\n    'd' => 'malatsi :count',\n    'a_day' => 'malatsi :count',\n\n    'hour' => 'diura di le :count',\n    'h' => 'diura di le :count',\n    'a_hour' => 'diura di le :count',\n\n    'minute' => 'metsotso e le :count',\n    'min' => 'metsotso e le :count',\n    'a_minute' => 'metsotso e le :count',\n\n    'second' => 'metsotswana e le :count',\n    's' => 'metsotswana e le :count',\n    'a_second' => 'metsotswana e le :count',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/to.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/to_TO.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/to_TO.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - International Components for Unicode    akhilesh.k@samsung.com\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'dddd DD MMM YYYY',\n    ],\n    'months' => ['Sānuali', 'Fēpueli', 'Maʻasi', 'ʻEpeleli', 'Mē', 'Sune', 'Siulai', 'ʻAokosi', 'Sepitema', 'ʻOkatopa', 'Nōvema', 'Tīsema'],\n    'months_short' => ['Sān', 'Fēp', 'Maʻa', 'ʻEpe', 'Mē', 'Sun', 'Siu', 'ʻAok', 'Sep', 'ʻOka', 'Nōv', 'Tīs'],\n    'weekdays' => ['Sāpate', 'Mōnite', 'Tūsite', 'Pulelulu', 'Tuʻapulelulu', 'Falaite', 'Tokonaki'],\n    'weekdays_short' => ['Sāp', 'Mōn', 'Tūs', 'Pul', 'Tuʻa', 'Fal', 'Tok'],\n    'weekdays_min' => ['Sāp', 'Mōn', 'Tūs', 'Pul', 'Tuʻa', 'Fal', 'Tok'],\n    'meridiem' => ['hengihengi', 'efiafi'],\n\n    'year' => ':count fitu', // less reliable\n    'y' => ':count fitu', // less reliable\n    'a_year' => ':count fitu', // less reliable\n\n    'month' => ':count mahina', // less reliable\n    'm' => ':count mahina', // less reliable\n    'a_month' => ':count mahina', // less reliable\n\n    'week' => ':count Sapate', // less reliable\n    'w' => ':count Sapate', // less reliable\n    'a_week' => ':count Sapate', // less reliable\n\n    'day' => ':count ʻaho', // less reliable\n    'd' => ':count ʻaho', // less reliable\n    'a_day' => ':count ʻaho', // less reliable\n\n    'hour' => ':count houa',\n    'h' => ':count houa',\n    'a_hour' => ':count houa',\n\n    'minute' => ':count miniti',\n    'min' => ':count miniti',\n    'a_minute' => ':count miniti',\n\n    'second' => ':count sekoni',\n    's' => ':count sekoni',\n    'a_second' => ':count sekoni',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/tpi.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/tpi_PG.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/tpi_PG.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Samsung Electronics Co., Ltd.    akhilesh.k@samsung.com\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD/MM/YYYY',\n    ],\n    'months' => ['Janueri', 'Februeri', 'Mas', 'Epril', 'Me', 'Jun', 'Julai', 'Ogas', 'Septemba', 'Oktoba', 'Novemba', 'Desemba'],\n    'months_short' => ['Jan', 'Feb', 'Mas', 'Epr', 'Me', 'Jun', 'Jul', 'Oga', 'Sep', 'Okt', 'Nov', 'Des'],\n    'weekdays' => ['Sande', 'Mande', 'Tunde', 'Trinde', 'Fonde', 'Fraide', 'Sarere'],\n    'weekdays_short' => ['San', 'Man', 'Tun', 'Tri', 'Fon', 'Fra', 'Sar'],\n    'weekdays_min' => ['San', 'Man', 'Tun', 'Tri', 'Fon', 'Fra', 'Sar'],\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['biknait', 'apinun'],\n\n    'year' => 'yia :count',\n    'y' => 'yia :count',\n    'a_year' => 'yia :count',\n\n    'month' => ':count mun',\n    'm' => ':count mun',\n    'a_month' => ':count mun',\n\n    'week' => ':count wik',\n    'w' => ':count wik',\n    'a_week' => ':count wik',\n\n    'day' => ':count de',\n    'd' => ':count de',\n    'a_day' => ':count de',\n\n    'hour' => ':count aua',\n    'h' => ':count aua',\n    'a_hour' => ':count aua',\n\n    'minute' => ':count minit',\n    'min' => ':count minit',\n    'a_minute' => ':count minit',\n\n    'second' => ':count namba tu',\n    's' => ':count namba tu',\n    'a_second' => ':count namba tu',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/tr.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Josh Soref\n * - Alan Agius\n * - Erhan Gundogan\n * - François B\n * - JD Isaacks\n * - Murat Yüksel\n * - Baran Şengül\n * - Selami (selamialtin)\n * - TeomanBey\n */\nreturn [\n    'year' => ':count yıl',\n    'a_year' => '{1}bir yıl|]1,Inf[:count yıl',\n    'y' => ':county',\n    'month' => ':count ay',\n    'a_month' => '{1}bir ay|]1,Inf[:count ay',\n    'm' => ':countay',\n    'week' => ':count hafta',\n    'a_week' => '{1}bir hafta|]1,Inf[:count hafta',\n    'w' => ':counth',\n    'day' => ':count gün',\n    'a_day' => '{1}bir gün|]1,Inf[:count gün',\n    'd' => ':countg',\n    'hour' => ':count saat',\n    'a_hour' => '{1}bir saat|]1,Inf[:count saat',\n    'h' => ':countsa',\n    'minute' => ':count dakika',\n    'a_minute' => '{1}bir dakika|]1,Inf[:count dakika',\n    'min' => ':countdk',\n    'second' => ':count saniye',\n    'a_second' => '{1}birkaç saniye|]1,Inf[:count saniye',\n    's' => ':countsn',\n    'ago' => ':time önce',\n    'from_now' => ':time sonra',\n    'after' => ':time sonra',\n    'before' => ':time önce',\n    'diff_now' => 'şimdi',\n    'diff_today' => 'bugün',\n    'diff_today_regexp' => 'bugün(?:\\\\s+saat)?',\n    'diff_yesterday' => 'dün',\n    'diff_tomorrow' => 'yarın',\n    'diff_tomorrow_regexp' => 'yarın(?:\\\\s+saat)?',\n    'diff_before_yesterday' => 'evvelsi gün',\n    'diff_after_tomorrow' => 'öbür gün',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD.MM.YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[bugün saat] LT',\n        'nextDay' => '[yarın saat] LT',\n        'nextWeek' => '[gelecek] dddd [saat] LT',\n        'lastDay' => '[dün] LT',\n        'lastWeek' => '[geçen] dddd [saat] LT',\n        'sameElse' => 'L',\n    ],\n    'ordinal' => function ($number, $period) {\n        switch ($period) {\n            case 'd':\n            case 'D':\n            case 'Do':\n            case 'DD':\n                return $number;\n            default:\n                if ($number === 0) {  // special case for zero\n                    return \"$number'ıncı\";\n                }\n\n                static $suffixes = [\n                    1 => '\\'inci',\n                    5 => '\\'inci',\n                    8 => '\\'inci',\n                    70 => '\\'inci',\n                    80 => '\\'inci',\n                    2 => '\\'nci',\n                    7 => '\\'nci',\n                    20 => '\\'nci',\n                    50 => '\\'nci',\n                    3 => '\\'üncü',\n                    4 => '\\'üncü',\n                    100 => '\\'üncü',\n                    6 => '\\'ncı',\n                    9 => '\\'uncu',\n                    10 => '\\'uncu',\n                    30 => '\\'uncu',\n                    60 => '\\'ıncı',\n                    90 => '\\'ıncı',\n                ];\n\n                $lastDigit = $number % 10;\n\n                return $number.($suffixes[$lastDigit] ?? $suffixes[$number % 100 - $lastDigit] ?? $suffixes[$number >= 100 ? 100 : -1] ?? '');\n        }\n    },\n    'meridiem' => ['ÖÖ', 'ÖS', 'öö', 'ös'],\n    'months' => ['Ocak', 'Şubat', 'Mart', 'Nisan', 'Mayıs', 'Haziran', 'Temmuz', 'Ağustos', 'Eylül', 'Ekim', 'Kasım', 'Aralık'],\n    'months_short' => ['Oca', 'Şub', 'Mar', 'Nis', 'May', 'Haz', 'Tem', 'Ağu', 'Eyl', 'Eki', 'Kas', 'Ara'],\n    'weekdays' => ['Pazar', 'Pazartesi', 'Salı', 'Çarşamba', 'Perşembe', 'Cuma', 'Cumartesi'],\n    'weekdays_short' => ['Paz', 'Pts', 'Sal', 'Çar', 'Per', 'Cum', 'Cts'],\n    'weekdays_min' => ['Pz', 'Pt', 'Sa', 'Ça', 'Pe', 'Cu', 'Ct'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n    'list' => [', ', ' ve '],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/tr_CY.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/tr.php', [\n    'weekdays_short' => ['Paz', 'Pzt', 'Sal', 'Çar', 'Per', 'Cum', 'Cmt'],\n    'weekdays_min' => ['Pa', 'Pt', 'Sa', 'Ça', 'Pe', 'Cu', 'Ct'],\n    'formats' => [\n        'LT' => 'h:mm a',\n        'LTS' => 'h:mm:ss a',\n        'L' => 'D.MM.YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY h:mm a',\n        'LLLL' => 'D MMMM YYYY dddd h:mm a',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/tr_TR.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/tr.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ts.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/ts_ZA.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ts_ZA.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Zuza Software Foundation (Translate.org.za) Dwayne Bailey dwayne@translate.org.za\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD/MM/YYYY',\n    ],\n    'months' => ['Sunguti', 'Nyenyenyani', 'Nyenyankulu', 'Dzivamisoko', 'Mudyaxihi', 'Khotavuxika', 'Mawuwani', 'Mhawuri', 'Ndzhati', 'Nhlangula', 'Hukuri', 'N\\'wendzamhala'],\n    'months_short' => ['Sun', 'Yan', 'Kul', 'Dzi', 'Mud', 'Kho', 'Maw', 'Mha', 'Ndz', 'Nhl', 'Huk', 'N\\'w'],\n    'weekdays' => ['Sonto', 'Musumbhunuku', 'Ravumbirhi', 'Ravunharhu', 'Ravumune', 'Ravuntlhanu', 'Mugqivela'],\n    'weekdays_short' => ['Son', 'Mus', 'Bir', 'Har', 'Ne', 'Tlh', 'Mug'],\n    'weekdays_min' => ['Son', 'Mus', 'Bir', 'Har', 'Ne', 'Tlh', 'Mug'],\n    'day_of_first_week_of_year' => 1,\n\n    'year' => 'malembe ya :count',\n    'y' => 'malembe ya :count',\n    'a_year' => 'malembe ya :count',\n\n    'month' => 'tin’hweti ta :count',\n    'm' => 'tin’hweti ta :count',\n    'a_month' => 'tin’hweti ta :count',\n\n    'week' => 'mavhiki ya :count',\n    'w' => 'mavhiki ya :count',\n    'a_week' => 'mavhiki ya :count',\n\n    'day' => 'masiku :count',\n    'd' => 'masiku :count',\n    'a_day' => 'masiku :count',\n\n    'hour' => 'tiawara ta :count',\n    'h' => 'tiawara ta :count',\n    'a_hour' => 'tiawara ta :count',\n\n    'minute' => 'timinete ta :count',\n    'min' => 'timinete ta :count',\n    'a_minute' => 'timinete ta :count',\n\n    'second' => 'tisekoni ta :count',\n    's' => 'tisekoni ta :count',\n    'a_second' => 'tisekoni ta :count',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/tt.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/tt_RU.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/tt_RU.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Rinat Norkin Pablo Saratxaga, Rinat Norkin pablo@mandrakesoft.com, rinat@taif.ru\n */\nreturn [\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD.MM.YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'DD MMM, HH:mm',\n        'LLLL' => 'DD MMMM YYYY, HH:mm',\n    ],\n    'months' => ['января', 'февраля', 'марта', 'апреля', 'мая', 'июня', 'июля', 'августа', 'сентября', 'октября', 'ноября', 'декабря'],\n    'months_short' => ['янв', 'фев', 'мар', 'апр', 'май', 'июн', 'июл', 'авг', 'сен', 'окт', 'ноя', 'дек'],\n    'weekdays' => ['якшәмбе', 'дышәмбе', 'сишәмбе', 'чәршәәмбе', 'пәнҗешмбе', 'җомга', 'шимбә'],\n    'weekdays_short' => ['якш', 'дыш', 'сиш', 'чәрш', 'пәнҗ', 'җом', 'шим'],\n    'weekdays_min' => ['якш', 'дыш', 'сиш', 'чәрш', 'пәнҗ', 'җом', 'шим'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n    'year' => ':count ел',\n    'month' => ':count ай',\n    'week' => ':count атна',\n    'day' => ':count көн',\n    'hour' => ':count сәгать',\n    'minute' => ':count минут',\n    'second' => ':count секунд',\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/tt_RU@iqtelif.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Reshat Sabiq tatar.iqtelif.i18n@gmail.com\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD.MM.YYYY',\n    ],\n    'months' => ['Ğınwar', 'Fiwral\\'', 'Mart', 'April', 'May', 'Yün', 'Yül', 'Awgust', 'Sintebír', 'Üktebír', 'Noyebír', 'Dikebír'],\n    'months_short' => ['Ğın', 'Fiw', 'Mar', 'Apr', 'May', 'Yün', 'Yül', 'Awg', 'Sin', 'Ükt', 'Noy', 'Dik'],\n    'weekdays' => ['Yekşembí', 'Düşembí', 'Sişembí', 'Çerşembí', 'Pencíşembí', 'Comğa', 'Şimbe'],\n    'weekdays_short' => ['Yek', 'Düş', 'Siş', 'Çer', 'Pen', 'Com', 'Şim'],\n    'weekdays_min' => ['Yek', 'Düş', 'Siş', 'Çer', 'Pen', 'Com', 'Şim'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['ÖA', 'ÖS'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/twq.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/ses.php', [\n    'meridiem' => ['Subbaahi', 'Zaarikay b'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/tzl.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn [\n    'year' => '[0,1]:count ar|:count ars',\n    'y' => '[0,1]:count ar|:count ars',\n    'month' => '[0,1]:count mes|:count mesen',\n    'm' => '[0,1]:count mes|:count mesen',\n    'week' => '[0,1]:count seifetziua|:count seifetziuas',\n    'w' => '[0,1]:count seifetziua|:count seifetziuas',\n    'day' => '[0,1]:count ziua|:count ziuas',\n    'd' => '[0,1]:count ziua|:count ziuas',\n    'hour' => '[0,1]:count þora|:count þoras',\n    'h' => '[0,1]:count þora|:count þoras',\n    'minute' => '[0,1]:count míut|:count míuts',\n    'min' => '[0,1]:count míut|:count míuts',\n    'second' => ':count secunds',\n    's' => ':count secunds',\n\n    'ago' => 'ja :time',\n    'from_now' => 'osprei :time',\n\n    'diff_yesterday' => 'ieiri',\n    'diff_yesterday_regexp' => 'ieiri(?:\\\\s+à)?',\n    'diff_today' => 'oxhi',\n    'diff_today_regexp' => 'oxhi(?:\\\\s+à)?',\n    'diff_tomorrow' => 'demà',\n    'diff_tomorrow_regexp' => 'demà(?:\\\\s+à)?',\n\n    'formats' => [\n        'LT' => 'HH.mm',\n        'LTS' => 'HH.mm.ss',\n        'L' => 'DD.MM.YYYY',\n        'LL' => 'D. MMMM [dallas] YYYY',\n        'LLL' => 'D. MMMM [dallas] YYYY HH.mm',\n        'LLLL' => 'dddd, [li] D. MMMM [dallas] YYYY HH.mm',\n    ],\n\n    'calendar' => [\n        'sameDay' => '[oxhi à] LT',\n        'nextDay' => '[demà à] LT',\n        'nextWeek' => 'dddd [à] LT',\n        'lastDay' => '[ieiri à] LT',\n        'lastWeek' => '[sür el] dddd [lasteu à] LT',\n        'sameElse' => 'L',\n    ],\n\n    'meridiem' => [\"D'A\", \"D'O\"],\n    'months' => ['Januar', 'Fevraglh', 'Març', 'Avrïu', 'Mai', 'Gün', 'Julia', 'Guscht', 'Setemvar', 'Listopäts', 'Noemvar', 'Zecemvar'],\n    'months_short' => ['Jan', 'Fev', 'Mar', 'Avr', 'Mai', 'Gün', 'Jul', 'Gus', 'Set', 'Lis', 'Noe', 'Zec'],\n    'weekdays' => ['Súladi', 'Lúneçi', 'Maitzi', 'Márcuri', 'Xhúadi', 'Viénerçi', 'Sáturi'],\n    'weekdays_short' => ['Súl', 'Lún', 'Mai', 'Már', 'Xhú', 'Vié', 'Sát'],\n    'weekdays_min' => ['Sú', 'Lú', 'Ma', 'Má', 'Xh', 'Vi', 'Sá'],\n    'ordinal' => ':number.',\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/tzm.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Josh Soref\n * - JD Isaacks\n */\nreturn [\n    'year' => '{1}ⴰⵙⴳⴰⵙ|:count ⵉⵙⴳⴰⵙⵏ',\n    'month' => '{1}ⴰⵢoⵓⵔ|:count ⵉⵢⵢⵉⵔⵏ',\n    'week' => ':count ⵉⵎⴰⵍⴰⵙⵙ',\n    'day' => '{1}ⴰⵙⵙ|:count oⵙⵙⴰⵏ',\n    'hour' => '{1}ⵙⴰⵄⴰ|:count ⵜⴰⵙⵙⴰⵄⵉⵏ',\n    'minute' => '{1}ⵎⵉⵏⵓⴺ|:count ⵎⵉⵏⵓⴺ',\n    'second' => '{1}ⵉⵎⵉⴽ|:count ⵉⵎⵉⴽ',\n    'ago' => 'ⵢⴰⵏ :time',\n    'from_now' => 'ⴷⴰⴷⵅ ⵙ ⵢⴰⵏ :time',\n    'diff_today' => 'ⴰⵙⴷⵅ',\n    'diff_yesterday' => 'ⴰⵚⴰⵏⵜ',\n    'diff_yesterday_regexp' => 'ⴰⵚⴰⵏⵜ(?:\\\\s+ⴴ)?',\n    'diff_tomorrow' => 'ⴰⵙⴽⴰ',\n    'diff_tomorrow_regexp' => 'ⴰⵙⴽⴰ(?:\\\\s+ⴴ)?',\n    'diff_today_regexp' => 'ⴰⵙⴷⵅ(?:\\\\s+ⴴ)?',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd D MMMM YYYY HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[ⴰⵙⴷⵅ ⴴ] LT',\n        'nextDay' => '[ⴰⵙⴽⴰ ⴴ] LT',\n        'nextWeek' => 'dddd [ⴴ] LT',\n        'lastDay' => '[ⴰⵚⴰⵏⵜ ⴴ] LT',\n        'lastWeek' => 'dddd [ⴴ] LT',\n        'sameElse' => 'L',\n    ],\n    'months' => ['ⵉⵏⵏⴰⵢⵔ', 'ⴱⵕⴰⵢⵕ', 'ⵎⴰⵕⵚ', 'ⵉⴱⵔⵉⵔ', 'ⵎⴰⵢⵢⵓ', 'ⵢⵓⵏⵢⵓ', 'ⵢⵓⵍⵢⵓⵣ', 'ⵖⵓⵛⵜ', 'ⵛⵓⵜⴰⵏⴱⵉⵔ', 'ⴽⵟⵓⴱⵕ', 'ⵏⵓⵡⴰⵏⴱⵉⵔ', 'ⴷⵓⵊⵏⴱⵉⵔ'],\n    'months_short' => ['ⵉⵏⵏⴰⵢⵔ', 'ⴱⵕⴰⵢⵕ', 'ⵎⴰⵕⵚ', 'ⵉⴱⵔⵉⵔ', 'ⵎⴰⵢⵢⵓ', 'ⵢⵓⵏⵢⵓ', 'ⵢⵓⵍⵢⵓⵣ', 'ⵖⵓⵛⵜ', 'ⵛⵓⵜⴰⵏⴱⵉⵔ', 'ⴽⵟⵓⴱⵕ', 'ⵏⵓⵡⴰⵏⴱⵉⵔ', 'ⴷⵓⵊⵏⴱⵉⵔ'],\n    'weekdays' => ['ⴰⵙⴰⵎⴰⵙ', 'ⴰⵢⵏⴰⵙ', 'ⴰⵙⵉⵏⴰⵙ', 'ⴰⴽⵔⴰⵙ', 'ⴰⴽⵡⴰⵙ', 'ⴰⵙⵉⵎⵡⴰⵙ', 'ⴰⵙⵉⴹⵢⴰⵙ'],\n    'weekdays_short' => ['ⴰⵙⴰⵎⴰⵙ', 'ⴰⵢⵏⴰⵙ', 'ⴰⵙⵉⵏⴰⵙ', 'ⴰⴽⵔⴰⵙ', 'ⴰⴽⵡⴰⵙ', 'ⴰⵙⵉⵎⵡⴰⵙ', 'ⴰⵙⵉⴹⵢⴰⵙ'],\n    'weekdays_min' => ['ⴰⵙⴰⵎⴰⵙ', 'ⴰⵢⵏⴰⵙ', 'ⴰⵙⵉⵏⴰⵙ', 'ⴰⴽⵔⴰⵙ', 'ⴰⴽⵡⴰⵙ', 'ⴰⵙⵉⵎⵡⴰⵙ', 'ⴰⵙⵉⴹⵢⴰⵙ'],\n    'first_day_of_week' => 6,\n    'day_of_first_week_of_year' => 1,\n    'weekend' => [5, 6],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/tzm_Latn.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Josh Soref\n * - JD Isaacks\n */\nreturn [\n    'year' => '{1}:count asgas|:count isgasn',\n    'a_year' => 'asgas|:count isgasn',\n    'month' => '{1}:count ayowr|:count iyyirn',\n    'a_month' => 'ayowr|:count iyyirn',\n    'week' => ':count imalass',\n    'a_week' => ':imalass',\n    'day' => '{1}:count ass|:count ossan',\n    'a_day' => 'ass|:count ossan',\n    'hour' => '{1}:count saɛa|:count tassaɛin',\n    'a_hour' => '{1}saɛa|:count tassaɛin',\n    'minute' => ':count minuḍ',\n    'a_minute' => '{1}minuḍ|:count minuḍ',\n    'second' => ':count imik',\n    'a_second' => '{1}imik|:count imik',\n    'ago' => 'yan :time',\n    'from_now' => 'dadkh s yan :time',\n    'diff_yesterday' => 'assant',\n    'diff_yesterday_regexp' => 'assant(?:\\\\s+g)?',\n    'diff_today' => 'asdkh',\n    'diff_today_regexp' => 'asdkh(?:\\\\s+g)?',\n    'diff_tomorrow' => 'aska',\n    'diff_tomorrow_regexp' => 'aska(?:\\\\s+g)?',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd D MMMM YYYY HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[asdkh g] LT',\n        'nextDay' => '[aska g] LT',\n        'nextWeek' => 'dddd [g] LT',\n        'lastDay' => '[assant g] LT',\n        'lastWeek' => 'dddd [g] LT',\n        'sameElse' => 'L',\n    ],\n    'months' => ['innayr', 'brˤayrˤ', 'marˤsˤ', 'ibrir', 'mayyw', 'ywnyw', 'ywlywz', 'ɣwšt', 'šwtanbir', 'ktˤwbrˤ', 'nwwanbir', 'dwjnbir'],\n    'months_short' => ['innayr', 'brˤayrˤ', 'marˤsˤ', 'ibrir', 'mayyw', 'ywnyw', 'ywlywz', 'ɣwšt', 'šwtanbir', 'ktˤwbrˤ', 'nwwanbir', 'dwjnbir'],\n    'weekdays' => ['asamas', 'aynas', 'asinas', 'akras', 'akwas', 'asimwas', 'asiḍyas'],\n    'weekdays_short' => ['asamas', 'aynas', 'asinas', 'akras', 'akwas', 'asimwas', 'asiḍyas'],\n    'weekdays_min' => ['asamas', 'aynas', 'asinas', 'akras', 'akwas', 'asimwas', 'asiḍyas'],\n    'meridiem' => ['Zdat azal', 'Ḍeffir aza'],\n    'first_day_of_week' => 6,\n    'day_of_first_week_of_year' => 1,\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ug.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Philippe Vaucher\n * - Tsutomu Kuroda\n * - yasinn\n */\nreturn [\n    'year' => '{1}'.'بىر يىل'.'|:count '.'يىل',\n    'month' => '{1}'.'بىر ئاي'.'|:count '.'ئاي',\n    'week' => '{1}'.'بىر ھەپتە'.'|:count '.'ھەپتە',\n    'day' => '{1}'.'بىر كۈن'.'|:count '.'كۈن',\n    'hour' => '{1}'.'بىر سائەت'.'|:count '.'سائەت',\n    'minute' => '{1}'.'بىر مىنۇت'.'|:count '.'مىنۇت',\n    'second' => '{1}'.'نەچچە سېكونت'.'|:count '.'سېكونت',\n    'ago' => ':time بۇرۇن',\n    'from_now' => ':time كېيىن',\n    'diff_today' => 'بۈگۈن',\n    'diff_yesterday' => 'تۆنۈگۈن',\n    'diff_tomorrow' => 'ئەتە',\n    'diff_tomorrow_regexp' => 'ئەتە(?:\\\\s+سائەت)?',\n    'diff_today_regexp' => 'بۈگۈن(?:\\\\s+سائەت)?',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'YYYY-MM-DD',\n        'LL' => 'YYYY-يىلىM-ئاينىڭD-كۈنى',\n        'LLL' => 'YYYY-يىلىM-ئاينىڭD-كۈنى، HH:mm',\n        'LLLL' => 'dddd، YYYY-يىلىM-ئاينىڭD-كۈنى، HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[بۈگۈن سائەت] LT',\n        'nextDay' => '[ئەتە سائەت] LT',\n        'nextWeek' => '[كېلەركى] dddd [سائەت] LT',\n        'lastDay' => '[تۆنۈگۈن] LT',\n        'lastWeek' => '[ئالدىنقى] dddd [سائەت] LT',\n        'sameElse' => 'L',\n    ],\n    'ordinal' => function ($number, $period) {\n        switch ($period) {\n            case 'd':\n            case 'D':\n            case 'DDD':\n                return $number.'-كۈنى';\n            case 'w':\n            case 'W':\n                return $number.'-ھەپتە';\n            default:\n                return $number;\n        }\n    },\n    'meridiem' => function ($hour, $minute) {\n        $time = $hour * 100 + $minute;\n        if ($time < 600) {\n            return 'يېرىم كېچە';\n        }\n        if ($time < 900) {\n            return 'سەھەر';\n        }\n        if ($time < 1130) {\n            return 'چۈشتىن بۇرۇن';\n        }\n        if ($time < 1230) {\n            return 'چۈش';\n        }\n        if ($time < 1800) {\n            return 'چۈشتىن كېيىن';\n        }\n\n        return 'كەچ';\n    },\n    'months' => ['يانۋار', 'فېۋرال', 'مارت', 'ئاپرېل', 'ماي', 'ئىيۇن', 'ئىيۇل', 'ئاۋغۇست', 'سېنتەبىر', 'ئۆكتەبىر', 'نويابىر', 'دېكابىر'],\n    'months_short' => ['يانۋار', 'فېۋرال', 'مارت', 'ئاپرېل', 'ماي', 'ئىيۇن', 'ئىيۇل', 'ئاۋغۇست', 'سېنتەبىر', 'ئۆكتەبىر', 'نويابىر', 'دېكابىر'],\n    'weekdays' => ['يەكشەنبە', 'دۈشەنبە', 'سەيشەنبە', 'چارشەنبە', 'پەيشەنبە', 'جۈمە', 'شەنبە'],\n    'weekdays_short' => ['يە', 'دۈ', 'سە', 'چا', 'پە', 'جۈ', 'شە'],\n    'weekdays_min' => ['يە', 'دۈ', 'سە', 'چا', 'پە', 'جۈ', 'شە'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n    'list' => [', ', ' ۋە '],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ug_CN.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Kunal Marwaha\n * - Alim Boyaq\n */\nreturn require __DIR__.'/ug.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/uk.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nuse Carbon\\CarbonInterface;\n\n$processHoursFunction = function (CarbonInterface $date, string $format) {\n    return $format.'о'.($date->hour === 11 ? 'б' : '').'] LT';\n};\n\n/*\n * Authors:\n * - Kunal Marwaha\n * - Josh Soref\n * - François B\n * - Tim Fish\n * - Serhan Apaydın\n * - Max Mykhailenko\n * - JD Isaacks\n * - Max Kovpak\n * - AucT\n * - Philippe Vaucher\n * - Ilya Shaplyko\n * - Vadym Ievsieiev\n * - Denys Kurets\n * - Igor Kasyanchuk\n * - Tsutomu Kuroda\n * - tjku\n * - Max Melentiev\n * - Oleh\n * - epaminond\n * - Juanito Fatas\n * - Vitalii Khustochka\n * - Akira Matsuda\n * - Christopher Dell\n * - Enrique Vidal\n * - Simone Carletti\n * - Aaron Patterson\n * - Andriy Tyurnikov\n * - Nicolás Hock Isaza\n * - Iwakura Taro\n * - Andrii Ponomarov\n * - alecrabbit\n * - vystepanenko\n * - AlexWalkerson\n * - Andre Havryliuk (Andrend)\n * - Max Datsenko (datsenko-md)\n */\nreturn [\n    'year' => ':count рік|:count роки|:count років',\n    'y' => ':countр|:countрр|:countрр',\n    'a_year' => '{1}рік|:count рік|:count роки|:count років',\n    'month' => ':count місяць|:count місяці|:count місяців',\n    'm' => ':countм',\n    'a_month' => '{1}місяць|:count місяць|:count місяці|:count місяців',\n    'week' => ':count тиждень|:count тижні|:count тижнів',\n    'w' => ':countт',\n    'a_week' => '{1}тиждень|:count тиждень|:count тижні|:count тижнів',\n    'day' => ':count день|:count дні|:count днів',\n    'd' => ':countд',\n    'a_day' => '{1}день|:count день|:count дні|:count днів',\n    'hour' => ':count година|:count години|:count годин',\n    'h' => ':countг',\n    'a_hour' => '{1}година|:count година|:count години|:count годин',\n    'minute' => ':count хвилина|:count хвилини|:count хвилин',\n    'min' => ':countхв',\n    'a_minute' => '{1}хвилина|:count хвилина|:count хвилини|:count хвилин',\n    'second' => ':count секунда|:count секунди|:count секунд',\n    's' => ':countсек',\n    'a_second' => '{1}декілька секунд|:count секунда|:count секунди|:count секунд',\n\n    'hour_ago' => ':count годину|:count години|:count годин',\n    'a_hour_ago' => '{1}годину|:count годину|:count години|:count годин',\n    'minute_ago' => ':count хвилину|:count хвилини|:count хвилин',\n    'a_minute_ago' => '{1}хвилину|:count хвилину|:count хвилини|:count хвилин',\n    'second_ago' => ':count секунду|:count секунди|:count секунд',\n    'a_second_ago' => '{1}декілька секунд|:count секунду|:count секунди|:count секунд',\n\n    'hour_from_now' => ':count годину|:count години|:count годин',\n    'a_hour_from_now' => '{1}годину|:count годину|:count години|:count годин',\n    'minute_from_now' => ':count хвилину|:count хвилини|:count хвилин',\n    'a_minute_from_now' => '{1}хвилину|:count хвилину|:count хвилини|:count хвилин',\n    'second_from_now' => ':count секунду|:count секунди|:count секунд',\n    'a_second_from_now' => '{1}декілька секунд|:count секунду|:count секунди|:count секунд',\n\n    'hour_after' => ':count годину|:count години|:count годин',\n    'a_hour_after' => '{1}годину|:count годину|:count години|:count годин',\n    'minute_after' => ':count хвилину|:count хвилини|:count хвилин',\n    'a_minute_after' => '{1}хвилину|:count хвилину|:count хвилини|:count хвилин',\n    'second_after' => ':count секунду|:count секунди|:count секунд',\n    'a_second_after' => '{1}декілька секунд|:count секунду|:count секунди|:count секунд',\n\n    'hour_before' => ':count годину|:count години|:count годин',\n    'a_hour_before' => '{1}годину|:count годину|:count години|:count годин',\n    'minute_before' => ':count хвилину|:count хвилини|:count хвилин',\n    'a_minute_before' => '{1}хвилину|:count хвилину|:count хвилини|:count хвилин',\n    'second_before' => ':count секунду|:count секунди|:count секунд',\n    'a_second_before' => '{1}декілька секунд|:count секунду|:count секунди|:count секунд',\n\n    'ago' => ':time тому',\n    'from_now' => 'за :time',\n    'after' => ':time після',\n    'before' => ':time до',\n    'diff_now' => 'щойно',\n    'diff_today' => 'Сьогодні',\n    'diff_today_regexp' => 'Сьогодні(?:\\\\s+о)?',\n    'diff_yesterday' => 'вчора',\n    'diff_yesterday_regexp' => 'Вчора(?:\\\\s+о)?',\n    'diff_tomorrow' => 'завтра',\n    'diff_tomorrow_regexp' => 'Завтра(?:\\\\s+о)?',\n    'diff_before_yesterday' => 'позавчора',\n    'diff_after_tomorrow' => 'післязавтра',\n    'period_recurrences' => 'один раз|:count рази|:count разів',\n    'period_interval' => 'кожні :interval',\n    'period_start_date' => 'з :date',\n    'period_end_date' => 'до :date',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD.MM.YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY, HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY, HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => function (CarbonInterface $date) use ($processHoursFunction) {\n            return $processHoursFunction($date, '[Сьогодні ');\n        },\n        'nextDay' => function (CarbonInterface $date) use ($processHoursFunction) {\n            return $processHoursFunction($date, '[Завтра ');\n        },\n        'nextWeek' => function (CarbonInterface $date) use ($processHoursFunction) {\n            return $processHoursFunction($date, '[У] dddd [');\n        },\n        'lastDay' => function (CarbonInterface $date) use ($processHoursFunction) {\n            return $processHoursFunction($date, '[Вчора ');\n        },\n        'lastWeek' => function (CarbonInterface $date) use ($processHoursFunction) {\n            switch ($date->dayOfWeek) {\n                case 0:\n                case 3:\n                case 5:\n                case 6:\n                    return $processHoursFunction($date, '[Минулої] dddd [');\n                default:\n                    return $processHoursFunction($date, '[Минулого] dddd [');\n            }\n        },\n        'sameElse' => 'L',\n    ],\n    'ordinal' => function ($number, $period) {\n        switch ($period) {\n            case 'M':\n            case 'd':\n            case 'DDD':\n            case 'w':\n            case 'W':\n                return $number.'-й';\n            case 'D':\n                return $number.'-го';\n            default:\n                return $number;\n        }\n    },\n    'meridiem' => function ($hour) {\n        if ($hour < 4) {\n            return 'ночі';\n        }\n        if ($hour < 12) {\n            return 'ранку';\n        }\n        if ($hour < 17) {\n            return 'дня';\n        }\n\n        return 'вечора';\n    },\n    'months' => ['січня', 'лютого', 'березня', 'квітня', 'травня', 'червня', 'липня', 'серпня', 'вересня', 'жовтня', 'листопада', 'грудня'],\n    'months_standalone' => ['січень', 'лютий', 'березень', 'квітень', 'травень', 'червень', 'липень', 'серпень', 'вересень', 'жовтень', 'листопад', 'грудень'],\n    'months_short' => ['січ', 'лют', 'бер', 'кві', 'тра', 'чер', 'лип', 'сер', 'вер', 'жов', 'лис', 'гру'],\n    'months_regexp' => '/(D[oD]?(\\[[^\\[\\]]*\\]|\\s)+MMMM?|L{2,4}|l{2,4})/',\n    'weekdays' => function (CarbonInterface $date, $format, $index) {\n        static $words = [\n            'nominative' => ['неділя', 'понеділок', 'вівторок', 'середа', 'четвер', 'п’ятниця', 'субота'],\n            'accusative' => ['неділю', 'понеділок', 'вівторок', 'середу', 'четвер', 'п’ятницю', 'суботу'],\n            'genitive' => ['неділі', 'понеділка', 'вівторка', 'середи', 'четверга', 'п’ятниці', 'суботи'],\n        ];\n\n        $format = $format ?? '';\n        $nounCase = preg_match('/(\\[(В|в|У|у)\\])\\s+dddd/u', $format)\n            ? 'accusative'\n            : (\n                preg_match('/\\[?(?:минулої|наступної)?\\s*\\]\\s+dddd/u', $format)\n                    ? 'genitive'\n                    : 'nominative'\n            );\n\n        return $words[$nounCase][$index] ?? null;\n    },\n    'weekdays_short' => ['нд', 'пн', 'вт', 'ср', 'чт', 'пт', 'сб'],\n    'weekdays_min' => ['нд', 'пн', 'вт', 'ср', 'чт', 'пт', 'сб'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n    'list' => [', ', ' i '],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/uk_UA.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/uk.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/unm.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/unm_US.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/unm_US.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD/MM/YY',\n    ],\n    'months' => ['enikwsi', 'chkwali', 'xamokhwite', 'kwetayoxe', 'tainipen', 'kichinipen', 'lainipen', 'winaminke', 'kichitahkok', 'puksit', 'wini', 'muxkotae'],\n    'months_short' => ['eni', 'chk', 'xam', 'kwe', 'tai', 'nip', 'lai', 'win', 'tah', 'puk', 'kun', 'mux'],\n    'weekdays' => ['kentuwei', 'manteke', 'tusteke', 'lelai', 'tasteke', 'pelaiteke', 'sateteke'],\n    'weekdays_short' => ['ken', 'man', 'tus', 'lel', 'tas', 'pel', 'sat'],\n    'weekdays_min' => ['ken', 'man', 'tus', 'lel', 'tas', 'pel', 'sat'],\n    'day_of_first_week_of_year' => 1,\n\n    // Too unreliable\n    /*\n    'year' => ':count kaxtëne',\n    'y' => ':count kaxtëne',\n    'a_year' => ':count kaxtëne',\n\n    'month' => ':count piskewëni kishux', // less reliable\n    'm' => ':count piskewëni kishux', // less reliable\n    'a_month' => ':count piskewëni kishux', // less reliable\n\n    'week' => ':count kishku', // less reliable\n    'w' => ':count kishku', // less reliable\n    'a_week' => ':count kishku', // less reliable\n\n    'day' => ':count kishku',\n    'd' => ':count kishku',\n    'a_day' => ':count kishku',\n\n    'hour' => ':count xkuk', // less reliable\n    'h' => ':count xkuk', // less reliable\n    'a_hour' => ':count xkuk', // less reliable\n\n    'minute' => ':count txituwàk', // less reliable\n    'min' => ':count txituwàk', // less reliable\n    'a_minute' => ':count txituwàk', // less reliable\n\n    'second' => ':count nisha', // less reliable\n    's' => ':count nisha', // less reliable\n    'a_second' => ':count nisha', // less reliable\n    */\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ur.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n$months = [\n    'جنوری',\n    'فروری',\n    'مارچ',\n    'اپریل',\n    'مئی',\n    'جون',\n    'جولائی',\n    'اگست',\n    'ستمبر',\n    'اکتوبر',\n    'نومبر',\n    'دسمبر',\n];\n\n$weekdays = [\n    'اتوار',\n    'پیر',\n    'منگل',\n    'بدھ',\n    'جمعرات',\n    'جمعہ',\n    'ہفتہ',\n];\n\n/*\n * Authors:\n * - Sawood Alam\n * - Mehshan\n * - Philippe Vaucher\n * - Tsutomu Kuroda\n * - tjku\n * - Zaid Akram\n * - Max Melentiev\n * - hafezdivandari\n * - Hossein Jabbari\n * - nimamo\n */\nreturn [\n    'year' => 'ایک سال|:count سال',\n    'month' => 'ایک ماہ|:count ماہ',\n    'week' => ':count ہفتے',\n    'day' => 'ایک دن|:count دن',\n    'hour' => 'ایک گھنٹہ|:count گھنٹے',\n    'minute' => 'ایک منٹ|:count منٹ',\n    'second' => 'چند سیکنڈ|:count سیکنڈ',\n    'ago' => ':time قبل',\n    'from_now' => ':time بعد',\n    'after' => ':time بعد',\n    'before' => ':time پہلے',\n    'diff_now' => 'اب',\n    'diff_today' => 'آج',\n    'diff_today_regexp' => 'آج(?:\\\\s+بوقت)?',\n    'diff_yesterday' => 'گزشتہ کل',\n    'diff_yesterday_regexp' => 'گذشتہ(?:\\\\s+روز)?(?:\\\\s+بوقت)?',\n    'diff_tomorrow' => 'آئندہ کل',\n    'diff_tomorrow_regexp' => 'کل(?:\\\\s+بوقت)?',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd، D MMMM YYYY HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[آج بوقت] LT',\n        'nextDay' => '[کل بوقت] LT',\n        'nextWeek' => 'dddd [بوقت] LT',\n        'lastDay' => '[گذشتہ روز بوقت] LT',\n        'lastWeek' => '[گذشتہ] dddd [بوقت] LT',\n        'sameElse' => 'L',\n    ],\n    'meridiem' => ['صبح', 'شام'],\n    'months' => $months,\n    'months_short' => $months,\n    'weekdays' => $weekdays,\n    'weekdays_short' => $weekdays,\n    'weekdays_min' => $weekdays,\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n    'list' => ['، ', ' اور '],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ur_IN.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Red Hat, Pune    bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/ur.php', [\n    'formats' => [\n        'L' => 'D/M/YY',\n    ],\n    'months' => ['جنوری', 'فروری', 'مارچ', 'اپریل', 'مئی', 'جون', 'جولائی', 'اگست', 'ستمبر', 'اکتوبر', 'نومبر', 'دسمبر'],\n    'months_short' => ['جنوری', 'فروری', 'مارچ', 'اپریل', 'مئی', 'جون', 'جولائی', 'اگست', 'ستمبر', 'اکتوبر', 'نومبر', 'دسمبر'],\n    'weekdays' => ['اتوار', 'پیر', 'منگل', 'بدھ', 'جمعرات', 'جمعہ', 'سنیچر'],\n    'weekdays_short' => ['اتوار', 'پیر', 'منگل', 'بدھ', 'جمعرات', 'جمعہ', 'سنیچر'],\n    'weekdays_min' => ['اتوار', 'پیر', 'منگل', 'بدھ', 'جمعرات', 'جمعہ', 'سنیچر'],\n    'day_of_first_week_of_year' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ur_PK.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/ur.php', [\n    'formats' => [\n        'L' => 'DD/MM/YYYY',\n    ],\n    'months' => ['جنوری', 'فروری', 'مارچ', 'اپریل', 'مئی', 'جون', 'جولائی', 'اگست', 'ستمبر', 'اکتوبر', 'نومبر', 'دسمبر'],\n    'months_short' => ['جنوری', 'فروری', 'مارچ', 'اپریل', 'مئی', 'جون', 'جولائی', 'اگست', 'ستمبر', 'اکتوبر', 'نومبر', 'دسمبر'],\n    'weekdays' => ['اتوار', 'پير', 'منگل', 'بدھ', 'جمعرات', 'جمعه', 'هفته'],\n    'weekdays_short' => ['اتوار', 'پير', 'منگل', 'بدھ', 'جمعرات', 'جمعه', 'هفته'],\n    'weekdays_min' => ['اتوار', 'پير', 'منگل', 'بدھ', 'جمعرات', 'جمعه', 'هفته'],\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['ص', 'ش'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/uz.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Dmitriy Shabanov\n * - JD Isaacks\n * - Inoyatulloh\n * - Jamshid\n * - aarkhipov\n * - Philippe Vaucher\n * - felixthemagnificent\n * - Tsutomu Kuroda\n * - tjku\n * - Max Melentiev\n * - Juanito Fatas\n * - Alisher Ulugbekov\n * - Ergashev Adizbek\n */\nreturn [\n    'year' => ':count йил',\n    'a_year' => '{1}бир йил|:count йил',\n    'y' => ':count й',\n    'month' => ':count ой',\n    'a_month' => '{1}бир ой|:count ой',\n    'm' => ':count о',\n    'week' => ':count ҳафта',\n    'a_week' => '{1}бир ҳафта|:count ҳафта',\n    'w' => ':count ҳ',\n    'day' => ':count кун',\n    'a_day' => '{1}бир кун|:count кун',\n    'd' => ':count к',\n    'hour' => ':count соат',\n    'a_hour' => '{1}бир соат|:count соат',\n    'h' => ':count с',\n    'minute' => ':count дақиқа',\n    'a_minute' => '{1}бир дақиқа|:count дақиқа',\n    'min' => ':count д',\n    'second' => ':count сония',\n    'a_second' => '{1}сония|:count сония',\n    's' => ':count с',\n    'ago' => ':time аввал',\n    'from_now' => 'Якин :time ичида',\n    'after' => ':timeдан кейин',\n    'before' => ':time олдин',\n    'diff_now' => 'ҳозир',\n    'diff_today' => 'Бугун',\n    'diff_today_regexp' => 'Бугун(?:\\\\s+соат)?',\n    'diff_yesterday' => 'Кеча',\n    'diff_yesterday_regexp' => 'Кеча(?:\\\\s+соат)?',\n    'diff_tomorrow' => 'Эртага',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'D MMMM YYYY, dddd HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[Бугун соат] LT [да]',\n        'nextDay' => '[Эртага] LT [да]',\n        'nextWeek' => 'dddd [куни соат] LT [да]',\n        'lastDay' => '[Кеча соат] LT [да]',\n        'lastWeek' => '[Утган] dddd [куни соат] LT [да]',\n        'sameElse' => 'L',\n    ],\n    'months' => ['январ', 'феврал', 'март', 'апрел', 'май', 'июн', 'июл', 'август', 'сентябр', 'октябр', 'ноябр', 'декабр'],\n    'months_short' => ['янв', 'фев', 'мар', 'апр', 'май', 'июн', 'июл', 'авг', 'сен', 'окт', 'ноя', 'дек'],\n    'weekdays' => ['якшанба', 'душанба', 'сешанба', 'чоршанба', 'пайшанба', 'жума', 'шанба'],\n    'weekdays_short' => ['якш', 'душ', 'сеш', 'чор', 'пай', 'жум', 'шан'],\n    'weekdays_min' => ['як', 'ду', 'се', 'чо', 'па', 'жу', 'ша'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['эрталаб', 'кечаси'],\n    'list' => [', ', ' ва '],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/uz_Arab.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/fa.php', [\n    'weekdays' => ['یکشنبه', 'دوشنبه', 'سه‌شنبه', 'چهارشنبه', 'پنجشنبه', 'جمعه', 'شنبه'],\n    'weekdays_short' => ['ی.', 'د.', 'س.', 'چ.', 'پ.', 'ج.', 'ش.'],\n    'weekdays_min' => ['ی.', 'د.', 'س.', 'چ.', 'پ.', 'ج.', 'ش.'],\n    'months' => ['جنوری', 'فبروری', 'مارچ', 'اپریل', 'می', 'جون', 'جولای', 'اگست', 'سپتمبر', 'اکتوبر', 'نومبر', 'دسمبر'],\n    'months_short' => ['جنو', 'فبر', 'مار', 'اپر', 'می', 'جون', 'جول', 'اگس', 'سپت', 'اکت', 'نوم', 'دسم'],\n    'first_day_of_week' => 6,\n    'weekend' => [4, 5],\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'YYYY-MM-dd',\n        'LL' => 'YYYY MMM D',\n        'LLL' => 'YYYY MMMM D HH:mm',\n        'LLLL' => 'YYYY MMMM D, dddd HH:mm',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/uz_Cyrl.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/uz.php', [\n    'formats' => [\n        'L' => 'DD/MM/yy',\n        'LL' => 'D MMM, YYYY',\n        'LLL' => 'D MMMM, YYYY HH:mm',\n        'LLLL' => 'dddd, DD MMMM, YYYY HH:mm',\n    ],\n    'meridiem' => ['ТО', 'ТК'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/uz_Latn.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Josh Soref\n * - Rasulbek\n * - Ilyosjon Kamoldinov (ilyosjon09)\n */\nreturn [\n    'year' => ':count yil',\n    'a_year' => '{1}bir yil|:count yil',\n    'y' => ':count y',\n    'month' => ':count oy',\n    'a_month' => '{1}bir oy|:count oy',\n    'm' => ':count o',\n    'week' => ':count hafta',\n    'a_week' => '{1}bir hafta|:count hafta',\n    'w' => ':count h',\n    'day' => ':count kun',\n    'a_day' => '{1}bir kun|:count kun',\n    'd' => ':count k',\n    'hour' => ':count soat',\n    'a_hour' => '{1}bir soat|:count soat',\n    'h' => ':count soat',\n    'minute' => ':count daqiqa',\n    'a_minute' => '{1}bir daqiqa|:count daqiqa',\n    'min' => ':count d',\n    'second' => ':count soniya',\n    'a_second' => '{1}soniya|:count soniya',\n    's' => ':count son.',\n    'ago' => ':time avval',\n    'from_now' => 'Yaqin :time ichida',\n    'after' => ':timedan keyin',\n    'before' => ':time oldin',\n    'diff_yesterday' => 'Kecha',\n    'diff_yesterday_regexp' => 'Kecha(?:\\\\s+soat)?',\n    'diff_today' => 'Bugun',\n    'diff_today_regexp' => 'Bugun(?:\\\\s+soat)?',\n    'diff_tomorrow' => 'Ertaga',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'D MMMM YYYY, dddd HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[Bugun soat] LT [da]',\n        'nextDay' => '[Ertaga] LT [da]',\n        'nextWeek' => 'dddd [kuni soat] LT [da]',\n        'lastDay' => '[Kecha soat] LT [da]',\n        'lastWeek' => '[O\\'tgan] dddd [kuni soat] LT [da]',\n        'sameElse' => 'L',\n    ],\n    'months' => ['Yanvar', 'Fevral', 'Mart', 'Aprel', 'May', 'Iyun', 'Iyul', 'Avgust', 'Sentabr', 'Oktabr', 'Noyabr', 'Dekabr'],\n    'months_short' => ['Yan', 'Fev', 'Mar', 'Apr', 'May', 'Iyun', 'Iyul', 'Avg', 'Sen', 'Okt', 'Noy', 'Dek'],\n    'weekdays' => ['Yakshanba', 'Dushanba', 'Seshanba', 'Chorshanba', 'Payshanba', 'Juma', 'Shanba'],\n    'weekdays_short' => ['Yak', 'Dush', 'Sesh', 'Chor', 'Pay', 'Jum', 'Shan'],\n    'weekdays_min' => ['Ya', 'Du', 'Se', 'Cho', 'Pa', 'Ju', 'Sha'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n    'list' => [', ', ' va '],\n    'meridiem' => ['TO', 'TK'],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/uz_UZ.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Bobir Ismailov Bobir Ismailov, Pablo Saratxaga, Mashrab Kuvatov bobir_is@yahoo.com, pablo@mandrakesoft.com, kmashrab@uni-bremen.de\n */\nreturn array_replace_recursive(require __DIR__.'/uz_Latn.php', [\n    'formats' => [\n        'L' => 'DD/MM/YY',\n    ],\n    'months' => ['Yanvar', 'Fevral', 'Mart', 'Aprel', 'May', 'Iyun', 'Iyul', 'Avgust', 'Sentabr', 'Oktabr', 'Noyabr', 'Dekabr'],\n    'months_short' => ['Yan', 'Fev', 'Mar', 'Apr', 'May', 'Iyn', 'Iyl', 'Avg', 'Sen', 'Okt', 'Noy', 'Dek'],\n    'weekdays' => ['Yakshanba', 'Dushanba', 'Seshanba', 'Chorshanba', 'Payshanba', 'Juma', 'Shanba'],\n    'weekdays_short' => ['Yak', 'Du', 'Se', 'Cho', 'Pay', 'Ju', 'Sha'],\n    'weekdays_min' => ['Yak', 'Du', 'Se', 'Cho', 'Pay', 'Ju', 'Sha'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/uz_UZ@cyrillic.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Mashrab Kuvatov Mashrab Kuvatov, Pablo Saratxaga kmashrab@uni-bremen.de, pablo@mandrakesoft.com\n */\nreturn array_replace_recursive(require __DIR__.'/uz.php', [\n    'formats' => [\n        'L' => 'DD/MM/YY',\n    ],\n    'months' => ['Январ', 'Феврал', 'Март', 'Апрел', 'Май', 'Июн', 'Июл', 'Август', 'Сентябр', 'Октябр', 'Ноябр', 'Декабр'],\n    'months_short' => ['Янв', 'Фев', 'Мар', 'Апр', 'Май', 'Июн', 'Июл', 'Авг', 'Сен', 'Окт', 'Ноя', 'Дек'],\n    'weekdays' => ['Якшанба', 'Душанба', 'Сешанба', 'Чоршанба', 'Пайшанба', 'Жума', 'Шанба'],\n    'weekdays_short' => ['Якш', 'Душ', 'Сеш', 'Чор', 'Пай', 'Жум', 'Шан'],\n    'weekdays_min' => ['Якш', 'Душ', 'Сеш', 'Чор', 'Пай', 'Жум', 'Шан'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/vai.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'weekdays' => ['ꕞꕌꔵ', 'ꗳꗡꘉ', 'ꕚꕞꕚ', 'ꕉꕞꕒ', 'ꕉꔤꕆꕢ', 'ꕉꔤꕀꕮ', 'ꔻꔬꔳ'],\n    'weekdays_short' => ['ꕞꕌꔵ', 'ꗳꗡꘉ', 'ꕚꕞꕚ', 'ꕉꕞꕒ', 'ꕉꔤꕆꕢ', 'ꕉꔤꕀꕮ', 'ꔻꔬꔳ'],\n    'weekdays_min' => ['ꕞꕌꔵ', 'ꗳꗡꘉ', 'ꕚꕞꕚ', 'ꕉꕞꕒ', 'ꕉꔤꕆꕢ', 'ꕉꔤꕀꕮ', 'ꔻꔬꔳ'],\n    'months' => ['ꖨꖕ ꕪꕴ ꔞꔀꕮꕊ', 'ꕒꕡꖝꖕ', 'ꕾꖺ', 'ꖢꖕ', 'ꖑꕱ', 'ꖱꘋ', 'ꖱꕞꔤ', 'ꗛꔕ', 'ꕢꕌ', 'ꕭꖃ', 'ꔞꘋꕔꕿ ꕸꖃꗏ', 'ꖨꖕ ꕪꕴ ꗏꖺꕮꕊ'],\n    'months_short' => ['ꖨꖕꔞ', 'ꕒꕡ', 'ꕾꖺ', 'ꖢꖕ', 'ꖑꕱ', 'ꖱꘋ', 'ꖱꕞ', 'ꗛꔕ', 'ꕢꕌ', 'ꕭꖃ', 'ꔞꘋ', 'ꖨꖕꗏ'],\n    'first_day_of_week' => 1,\n    'formats' => [\n        'LT' => 'h:mm a',\n        'LTS' => 'h:mm:ss a',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY h:mm a',\n        'LLLL' => 'dddd, D MMMM YYYY h:mm a',\n    ],\n\n    'year' => ':count ꕀ', // less reliable\n    'y' => ':count ꕀ', // less reliable\n    'a_year' => ':count ꕀ', // less reliable\n\n    'second' => ':count ꗱꕞꕯꕊ', // less reliable\n    's' => ':count ꗱꕞꕯꕊ', // less reliable\n    'a_second' => ':count ꗱꕞꕯꕊ', // less reliable\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/vai_Latn.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'weekdays' => ['lahadi', 'tɛɛnɛɛ', 'talata', 'alaba', 'aimisa', 'aijima', 'siɓiti'],\n    'weekdays_short' => ['lahadi', 'tɛɛnɛɛ', 'talata', 'alaba', 'aimisa', 'aijima', 'siɓiti'],\n    'weekdays_min' => ['lahadi', 'tɛɛnɛɛ', 'talata', 'alaba', 'aimisa', 'aijima', 'siɓiti'],\n    'months' => ['luukao kemã', 'ɓandaɓu', 'vɔɔ', 'fulu', 'goo', '6', '7', 'kɔnde', 'saah', 'galo', 'kenpkato ɓololɔ', 'luukao lɔma'],\n    'months_short' => ['luukao kemã', 'ɓandaɓu', 'vɔɔ', 'fulu', 'goo', '6', '7', 'kɔnde', 'saah', 'galo', 'kenpkato ɓololɔ', 'luukao lɔma'],\n    'first_day_of_week' => 1,\n    'formats' => [\n        'LT' => 'h:mm a',\n        'LTS' => 'h:mm:ss a',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY h:mm a',\n        'LLLL' => 'dddd, D MMMM YYYY h:mm a',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/vai_Vaii.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/vai.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ve.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/ve_ZA.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/ve_ZA.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Zuza Software Foundation (Translate.org.za) Dwayne Bailey dwayne@translate.org.za\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD/MM/YYYY',\n    ],\n    'months' => ['Phando', 'Luhuhi', 'Ṱhafamuhwe', 'Lambamai', 'Shundunthule', 'Fulwi', 'Fulwana', 'Ṱhangule', 'Khubvumedzi', 'Tshimedzi', 'Ḽara', 'Nyendavhusiku'],\n    'months_short' => ['Pha', 'Luh', 'Fam', 'Lam', 'Shu', 'Lwi', 'Lwa', 'Ngu', 'Khu', 'Tsh', 'Ḽar', 'Nye'],\n    'weekdays' => ['Swondaha', 'Musumbuluwo', 'Ḽavhuvhili', 'Ḽavhuraru', 'Ḽavhuṋa', 'Ḽavhuṱanu', 'Mugivhela'],\n    'weekdays_short' => ['Swo', 'Mus', 'Vhi', 'Rar', 'ṋa', 'Ṱan', 'Mug'],\n    'weekdays_min' => ['Swo', 'Mus', 'Vhi', 'Rar', 'ṋa', 'Ṱan', 'Mug'],\n    'day_of_first_week_of_year' => 1,\n\n    // Too unreliable\n    /*\n    'day' => ':count vhege', // less reliable\n    'd' => ':count vhege', // less reliable\n    'a_day' => ':count vhege', // less reliable\n\n    'hour' => ':count watshi', // less reliable\n    'h' => ':count watshi', // less reliable\n    'a_hour' => ':count watshi', // less reliable\n\n    'minute' => ':count watshi', // less reliable\n    'min' => ':count watshi', // less reliable\n    'a_minute' => ':count watshi', // less reliable\n\n    'second' => ':count Mu', // less reliable\n    's' => ':count Mu', // less reliable\n    'a_second' => ':count Mu', // less reliable\n\n    'week' => ':count vhege',\n    'w' => ':count vhege',\n    'a_week' => ':count vhege',\n    */\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/vi.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - François B\n * - Andre Polykanine A.K.A. Menelion Elensúlë\n * - JD Isaacks\n */\nreturn [\n    'year' => ':count năm',\n    'a_year' => '{1}một năm|]1, Inf[:count năm',\n    'y' => ':count năm',\n    'month' => ':count tháng',\n    'a_month' => '{1}một tháng|]1, Inf[:count tháng',\n    'm' => ':count tháng',\n    'week' => ':count tuần',\n    'a_week' => '{1}một tuần|]1, Inf[:count tuần',\n    'w' => ':count tuần',\n    'day' => ':count ngày',\n    'a_day' => '{1}một ngày|]1, Inf[:count ngày',\n    'd' => ':count ngày',\n    'hour' => ':count giờ',\n    'a_hour' => '{1}một giờ|]1, Inf[:count giờ',\n    'h' => ':count giờ',\n    'minute' => ':count phút',\n    'a_minute' => '{1}một phút|]1, Inf[:count phút',\n    'min' => ':count phút',\n    'second' => ':count giây',\n    'a_second' => '{1}vài giây|]1, Inf[:count giây',\n    's' => ':count giây',\n    'ago' => ':time trước',\n    'from_now' => ':time tới',\n    'after' => ':time sau',\n    'before' => ':time trước',\n    'diff_now' => 'bây giờ',\n    'diff_today' => 'Hôm',\n    'diff_today_regexp' => 'Hôm(?:\\\\s+nay)?(?:\\\\s+lúc)?',\n    'diff_yesterday' => 'Hôm qua',\n    'diff_yesterday_regexp' => 'Hôm(?:\\\\s+qua)?(?:\\\\s+lúc)?',\n    'diff_tomorrow' => 'Ngày mai',\n    'diff_tomorrow_regexp' => 'Ngày(?:\\\\s+mai)?(?:\\\\s+lúc)?',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM [năm] YYYY',\n        'LLL' => 'D MMMM [năm] YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM [năm] YYYY HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[Hôm nay lúc] LT',\n        'nextDay' => '[Ngày mai lúc] LT',\n        'nextWeek' => 'dddd [tuần tới lúc] LT',\n        'lastDay' => '[Hôm qua lúc] LT',\n        'lastWeek' => 'dddd [tuần trước lúc] LT',\n        'sameElse' => 'L',\n    ],\n    'meridiem' => ['SA', 'CH'],\n    'months' => ['tháng 1', 'tháng 2', 'tháng 3', 'tháng 4', 'tháng 5', 'tháng 6', 'tháng 7', 'tháng 8', 'tháng 9', 'tháng 10', 'tháng 11', 'tháng 12'],\n    'months_short' => ['Th01', 'Th02', 'Th03', 'Th04', 'Th05', 'Th06', 'Th07', 'Th08', 'Th09', 'Th10', 'Th11', 'Th12'],\n    'weekdays' => ['chủ nhật', 'thứ hai', 'thứ ba', 'thứ tư', 'thứ năm', 'thứ sáu', 'thứ bảy'],\n    'weekdays_short' => ['CN', 'T2', 'T3', 'T4', 'T5', 'T6', 'T7'],\n    'weekdays_min' => ['CN', 'T2', 'T3', 'T4', 'T5', 'T6', 'T7'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n    'list' => [', ', ' và '],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/vi_VN.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/vi.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/vo.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'months' => ['M01', 'M02', 'M03', 'M04', 'M05', 'M06', 'M07', 'M08', 'M09', 'M10', 'M11', 'M12'],\n    'months_short' => ['M01', 'M02', 'M03', 'M04', 'M05', 'M06', 'M07', 'M08', 'M09', 'M10', 'M11', 'M12'],\n    'first_day_of_week' => 1,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'YYYY-MM-dd',\n        'LL' => 'YYYY MMM D',\n        'LLL' => 'YYYY MMMM D HH:mm',\n        'LLLL' => 'YYYY MMMM D, dddd HH:mm',\n    ],\n\n    'year' => ':count yel',\n    'y' => ':count yel',\n    'a_year' => ':count yel',\n\n    'month' => ':count mul',\n    'm' => ':count mul',\n    'a_month' => ':count mul',\n\n    'week' => ':count vig',\n    'w' => ':count vig',\n    'a_week' => ':count vig',\n\n    'day' => ':count del',\n    'd' => ':count del',\n    'a_day' => ':count del',\n\n    'hour' => ':count düp',\n    'h' => ':count düp',\n    'a_hour' => ':count düp',\n\n    'minute' => ':count minut',\n    'min' => ':count minut',\n    'a_minute' => ':count minut',\n\n    'second' => ':count sekun',\n    's' => ':count sekun',\n    'a_second' => ':count sekun',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/vun.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'meridiem' => ['utuko', 'kyiukonyi'],\n    'weekdays' => ['Jumapilyi', 'Jumatatuu', 'Jumanne', 'Jumatanu', 'Alhamisi', 'Ijumaa', 'Jumamosi'],\n    'weekdays_short' => ['Jpi', 'Jtt', 'Jnn', 'Jtn', 'Alh', 'Iju', 'Jmo'],\n    'weekdays_min' => ['Jpi', 'Jtt', 'Jnn', 'Jtn', 'Alh', 'Iju', 'Jmo'],\n    'months' => ['Januari', 'Februari', 'Machi', 'Aprilyi', 'Mei', 'Junyi', 'Julyai', 'Agusti', 'Septemba', 'Oktoba', 'Novemba', 'Desemba'],\n    'months_short' => ['Jan', 'Feb', 'Mac', 'Apr', 'Mei', 'Jun', 'Jul', 'Ago', 'Sep', 'Okt', 'Nov', 'Des'],\n    'first_day_of_week' => 1,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY HH:mm',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/wa.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/wa_BE.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/wa_BE.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Djan SACRE Pablo Saratxaga pablo@mandrakesoft.com\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD/MM/YYYY',\n    ],\n    'months' => ['di djanvî', 'di fevrî', 'di måss', 'd’ avri', 'di may', 'di djun', 'di djulete', 'd’ awousse', 'di setimbe', 'd’ octôbe', 'di nôvimbe', 'di decimbe'],\n    'months_short' => ['dja', 'fev', 'mås', 'avr', 'may', 'djn', 'djl', 'awo', 'set', 'oct', 'nôv', 'dec'],\n    'weekdays' => ['dimegne', 'londi', 'mårdi', 'mierkidi', 'djudi', 'vénrdi', 'semdi'],\n    'weekdays_short' => ['dim', 'lon', 'mår', 'mie', 'dju', 'vén', 'sem'],\n    'weekdays_min' => ['dim', 'lon', 'mår', 'mie', 'dju', 'vén', 'sem'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n\n    'year' => ':count anêye',\n    'y' => ':count anêye',\n    'a_year' => ':count anêye',\n\n    'month' => ':count meûs',\n    'm' => ':count meûs',\n    'a_month' => ':count meûs',\n\n    'week' => ':count samwinne',\n    'w' => ':count samwinne',\n    'a_week' => ':count samwinne',\n\n    'day' => ':count djoû',\n    'd' => ':count djoû',\n    'a_day' => ':count djoû',\n\n    'hour' => ':count eure',\n    'h' => ':count eure',\n    'a_hour' => ':count eure',\n\n    'minute' => ':count munute',\n    'min' => ':count munute',\n    'a_minute' => ':count munute',\n\n    'second' => ':count Sigonde',\n    's' => ':count Sigonde',\n    'a_second' => ':count Sigonde',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/wae.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/wae_CH.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/wae_CH.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Walser Translation Team ml@translate-wae.ch\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'YYYY-MM-DD',\n    ],\n    'months' => ['Jenner', 'Hornig', 'Märze', 'Abrille', 'Meije', 'Bráčet', 'Heiwet', 'Öigšte', 'Herbštmánet', 'Wímánet', 'Wintermánet', 'Chrištmánet'],\n    'months_short' => ['Jen', 'Hor', 'Mär', 'Abr', 'Mei', 'Brá', 'Hei', 'Öig', 'Her', 'Wím', 'Win', 'Chr'],\n    'weekdays' => ['Suntag', 'Mäntag', 'Zischtag', 'Mittwuch', 'Frontag', 'Fritag', 'Samschtag'],\n    'weekdays_short' => ['Sun', 'Män', 'Zis', 'Mit', 'Fro', 'Fri', 'Sam'],\n    'weekdays_min' => ['Sun', 'Män', 'Zis', 'Mit', 'Fro', 'Fri', 'Sam'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n\n    'month' => ':count Maano', // less reliable\n    'm' => ':count Maano', // less reliable\n    'a_month' => ':count Maano', // less reliable\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/wal.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/wal_ET.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/wal_ET.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Ge'ez Frontier Foundation    locales@geez.org\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD/MM/YYYY',\n    ],\n    'months' => ['ጃንዩወሪ', 'ፌብሩወሪ', 'ማርች', 'ኤፕረል', 'ሜይ', 'ጁን', 'ጁላይ', 'ኦገስት', 'ሴፕቴምበር', 'ኦክተውበር', 'ኖቬምበር', 'ዲሴምበር'],\n    'months_short' => ['ጃንዩ', 'ፌብሩ', 'ማርች', 'ኤፕረ', 'ሜይ ', 'ጁን ', 'ጁላይ', 'ኦገስ', 'ሴፕቴ', 'ኦክተ', 'ኖቬም', 'ዲሴም'],\n    'weekdays' => ['ወጋ', 'ሳይኖ', 'ማቆሳኛ', 'አሩዋ', 'ሃሙሳ', 'አርባ', 'ቄራ'],\n    'weekdays_short' => ['ወጋ ', 'ሳይኖ', 'ማቆሳ', 'አሩዋ', 'ሃሙሳ', 'አርባ', 'ቄራ '],\n    'weekdays_min' => ['ወጋ ', 'ሳይኖ', 'ማቆሳ', 'አሩዋ', 'ሃሙሳ', 'አርባ', 'ቄራ '],\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['ማለዶ', 'ቃማ'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/wo.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/wo_SN.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/wo_SN.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - The Debian Project Christian Perrier bubulle@debian.org\n */\nreturn [\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD.MM.YYYY',\n        'LL' => 'MMMM DD, YYYY',\n        'LLL' => 'DD MMM HH:mm',\n        'LLLL' => 'MMMM DD, YYYY HH:mm',\n    ],\n    'months' => ['sanwiy\\'e', 'feebriy\\'e', 'mars', 'awril', 'me', 'suwen', 'sulet', 'uut', 'septaambar', 'oktoobar', 'nowaambar', 'desaambar'],\n    'months_short' => ['san', 'fee', 'mar', 'awr', 'me ', 'suw', 'sul', 'uut', 'sep', 'okt', 'now', 'des'],\n    'weekdays' => ['dib\\'eer', 'altine', 'talaata', 'allarba', 'alxames', 'ajjuma', 'gaawu'],\n    'weekdays_short' => ['dib', 'alt', 'tal', 'all', 'alx', 'ajj', 'gaa'],\n    'weekdays_min' => ['dib', 'alt', 'tal', 'all', 'alx', 'ajj', 'gaa'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n    'year' => ':count at',\n    'month' => ':count wèr',\n    'week' => ':count ayubés',\n    'day' => ':count bés',\n    'hour' => ':count waxtu',\n    'minute' => ':count simili',\n    'second' => ':count saa',\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/xh.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/xh_ZA.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/xh_ZA.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Zuza Software Foundation (Translate.org.za) Dwayne Bailey dwayne@translate.org.za\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD/MM/YYYY',\n    ],\n    'months' => ['eyoMqungu', 'eyoMdumba', 'eyoKwindla', 'uTshazimpuzi', 'uCanzibe', 'eyeSilimela', 'eyeKhala', 'eyeThupa', 'eyoMsintsi', 'eyeDwarha', 'eyeNkanga', 'eyoMnga'],\n    'months_short' => ['Mqu', 'Mdu', 'Kwi', 'Tsh', 'Can', 'Sil', 'Kha', 'Thu', 'Msi', 'Dwa', 'Nka', 'Mng'],\n    'weekdays' => ['iCawa', 'uMvulo', 'lwesiBini', 'lwesiThathu', 'ulweSine', 'lwesiHlanu', 'uMgqibelo'],\n    'weekdays_short' => ['Caw', 'Mvu', 'Bin', 'Tha', 'Sin', 'Hla', 'Mgq'],\n    'weekdays_min' => ['Caw', 'Mvu', 'Bin', 'Tha', 'Sin', 'Hla', 'Mgq'],\n    'day_of_first_week_of_year' => 1,\n\n    'year' => ':count ihlobo', // less reliable\n    'y' => ':count ihlobo', // less reliable\n    'a_year' => ':count ihlobo', // less reliable\n\n    'hour' => ':count iwotshi', // less reliable\n    'h' => ':count iwotshi', // less reliable\n    'a_hour' => ':count iwotshi', // less reliable\n\n    'minute' => ':count ingqalelo', // less reliable\n    'min' => ':count ingqalelo', // less reliable\n    'a_minute' => ':count ingqalelo', // less reliable\n\n    'second' => ':count nceda', // less reliable\n    's' => ':count nceda', // less reliable\n    'a_second' => ':count nceda', // less reliable\n\n    'month' => ':count inyanga',\n    'm' => ':count inyanga',\n    'a_month' => ':count inyanga',\n\n    'week' => ':count veki',\n    'w' => ':count veki',\n    'a_week' => ':count veki',\n\n    'day' => ':count imini',\n    'd' => ':count imini',\n    'a_day' => ':count imini',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/xog.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'meridiem' => ['Munkyo', 'Eigulo'],\n    'weekdays' => ['Sabiiti', 'Balaza', 'Owokubili', 'Owokusatu', 'Olokuna', 'Olokutaanu', 'Olomukaaga'],\n    'weekdays_short' => ['Sabi', 'Bala', 'Kubi', 'Kusa', 'Kuna', 'Kuta', 'Muka'],\n    'weekdays_min' => ['Sabi', 'Bala', 'Kubi', 'Kusa', 'Kuna', 'Kuta', 'Muka'],\n    'months' => ['Janwaliyo', 'Febwaliyo', 'Marisi', 'Apuli', 'Maayi', 'Juuni', 'Julaayi', 'Agusito', 'Sebuttemba', 'Okitobba', 'Novemba', 'Desemba'],\n    'months_short' => ['Jan', 'Feb', 'Mar', 'Apu', 'Maa', 'Juu', 'Jul', 'Agu', 'Seb', 'Oki', 'Nov', 'Des'],\n    'first_day_of_week' => 1,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY HH:mm',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/yav.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'meridiem' => ['kiɛmɛ́ɛm', 'kisɛ́ndɛ'],\n    'weekdays' => ['sɔ́ndiɛ', 'móndie', 'muányáŋmóndie', 'metúkpíápɛ', 'kúpélimetúkpiapɛ', 'feléte', 'séselé'],\n    'weekdays_short' => ['sd', 'md', 'mw', 'et', 'kl', 'fl', 'ss'],\n    'weekdays_min' => ['sd', 'md', 'mw', 'et', 'kl', 'fl', 'ss'],\n    'months' => ['pikítíkítie, oólí ú kutúan', 'siɛyɛ́, oóli ú kándíɛ', 'ɔnsúmbɔl, oóli ú kátátúɛ', 'mesiŋ, oóli ú kénie', 'ensil, oóli ú kátánuɛ', 'ɔsɔn', 'efute', 'pisuyú', 'imɛŋ i puɔs', 'imɛŋ i putúk,oóli ú kátíɛ', 'makandikɛ', 'pilɔndɔ́'],\n    'months_short' => ['o.1', 'o.2', 'o.3', 'o.4', 'o.5', 'o.6', 'o.7', 'o.8', 'o.9', 'o.10', 'o.11', 'o.12'],\n    'first_day_of_week' => 1,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'D/M/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd D MMMM YYYY HH:mm',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/yi.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/yi_US.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/yi_US.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - http://www.uyip.org/ Pablo Saratxaga pablo@mandrakesoft.com\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD/MM/YY',\n    ],\n    'months' => ['יאַנואַר', 'פֿעברואַר', 'מערץ', 'אַפּריל', 'מיי', 'יוני', 'יולי', 'אויגוסט', 'סעפּטעמבער', 'אקטאבער', 'נאוועמבער', 'דעצעמבער'],\n    'months_short' => ['יאַנ', 'פֿעב', 'מאַר', 'אַפּר', 'מײַ ', 'יונ', 'יול', 'אױג', 'סעפּ', 'אָקט', 'נאָװ', 'דעצ'],\n    'weekdays' => ['זונטיק', 'מאָנטיק', 'דינסטיק', 'מיטװאָך', 'דאָנערשטיק', 'פֿרײַטיק', 'שבת'],\n    'weekdays_short' => ['זונ\\'', 'מאָנ\\'', 'דינ\\'', 'מיט\\'', 'דאָנ\\'', 'פֿרײַ\\'', 'שבת'],\n    'weekdays_min' => ['זונ\\'', 'מאָנ\\'', 'דינ\\'', 'מיט\\'', 'דאָנ\\'', 'פֿרײַ\\'', 'שבת'],\n    'day_of_first_week_of_year' => 1,\n\n    'year' => ':count יאר',\n    'y' => ':count יאר',\n    'a_year' => ':count יאר',\n\n    'month' => ':count חודש',\n    'm' => ':count חודש',\n    'a_month' => ':count חודש',\n\n    'week' => ':count וואָך',\n    'w' => ':count וואָך',\n    'a_week' => ':count וואָך',\n\n    'day' => ':count טאָג',\n    'd' => ':count טאָג',\n    'a_day' => ':count טאָג',\n\n    'hour' => ':count שעה',\n    'h' => ':count שעה',\n    'a_hour' => ':count שעה',\n\n    'minute' => ':count מינוט',\n    'min' => ':count מינוט',\n    'a_minute' => ':count מינוט',\n\n    'second' => ':count סעקונדע',\n    's' => ':count סעקונדע',\n    'a_second' => ':count סעקונדע',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/yo.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - François B\n * - Atolagbe Abisoye\n */\nreturn [\n    'year' => 'ọdún :count',\n    'a_year' => '{1}ọdún kan|ọdún :count',\n    'month' => 'osù :count',\n    'a_month' => '{1}osù kan|osù :count',\n    'week' => 'ọsẹ :count',\n    'a_week' => '{1}ọsẹ kan|ọsẹ :count',\n    'day' => 'ọjọ́ :count',\n    'a_day' => '{1}ọjọ́ kan|ọjọ́ :count',\n    'hour' => 'wákati :count',\n    'a_hour' => '{1}wákati kan|wákati :count',\n    'minute' => 'ìsẹjú :count',\n    'a_minute' => '{1}ìsẹjú kan|ìsẹjú :count',\n    'second' => 'iaayá :count',\n    'a_second' => '{1}ìsẹjú aayá die|aayá :count',\n    'ago' => ':time kọjá',\n    'from_now' => 'ní :time',\n    'diff_yesterday' => 'Àna',\n    'diff_yesterday_regexp' => 'Àna(?:\\\\s+ni)?',\n    'diff_today' => 'Ònì',\n    'diff_today_regexp' => 'Ònì(?:\\\\s+ni)?',\n    'diff_tomorrow' => 'Ọ̀la',\n    'diff_tomorrow_regexp' => 'Ọ̀la(?:\\\\s+ni)?',\n    'formats' => [\n        'LT' => 'h:mm A',\n        'LTS' => 'h:mm:ss A',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY h:mm A',\n        'LLLL' => 'dddd, D MMMM YYYY h:mm A',\n    ],\n    'calendar' => [\n        'sameDay' => '[Ònì ni] LT',\n        'nextDay' => '[Ọ̀la ni] LT',\n        'nextWeek' => 'dddd [Ọsẹ̀ tón\\'bọ] [ni] LT',\n        'lastDay' => '[Àna ni] LT',\n        'lastWeek' => 'dddd [Ọsẹ̀ tólọ́] [ni] LT',\n        'sameElse' => 'L',\n    ],\n    'ordinal' => 'ọjọ́ :number',\n    'months' => ['Sẹ́rẹ́', 'Èrèlè', 'Ẹrẹ̀nà', 'Ìgbé', 'Èbibi', 'Òkùdu', 'Agẹmo', 'Ògún', 'Owewe', 'Ọ̀wàrà', 'Bélú', 'Ọ̀pẹ̀̀'],\n    'months_short' => ['Sẹ́r', 'Èrl', 'Ẹrn', 'Ìgb', 'Èbi', 'Òkù', 'Agẹ', 'Ògú', 'Owe', 'Ọ̀wà', 'Bél', 'Ọ̀pẹ̀̀'],\n    'weekdays' => ['Àìkú', 'Ajé', 'Ìsẹ́gun', 'Ọjọ́rú', 'Ọjọ́bọ', 'Ẹtì', 'Àbámẹ́ta'],\n    'weekdays_short' => ['Àìk', 'Ajé', 'Ìsẹ́', 'Ọjr', 'Ọjb', 'Ẹtì', 'Àbá'],\n    'weekdays_min' => ['Àì', 'Aj', 'Ìs', 'Ọr', 'Ọb', 'Ẹt', 'Àb'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n    'meridiem' => ['Àárọ̀', 'Ọ̀sán'],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/yo_BJ.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn array_replace_recursive(require __DIR__.'/yo.php', [\n    'meridiem' => ['Àárɔ̀', 'Ɔ̀sán'],\n    'weekdays' => ['Ɔjɔ́ Àìkú', 'Ɔjɔ́ Ajé', 'Ɔjɔ́ Ìsɛ́gun', 'Ɔjɔ́rú', 'Ɔjɔ́bɔ', 'Ɔjɔ́ Ɛtì', 'Ɔjɔ́ Àbámɛ́ta'],\n    'weekdays_short' => ['Àìkú', 'Ajé', 'Ìsɛ́gun', 'Ɔjɔ́rú', 'Ɔjɔ́bɔ', 'Ɛtì', 'Àbámɛ́ta'],\n    'weekdays_min' => ['Àìkú', 'Ajé', 'Ìsɛ́gun', 'Ɔjɔ́rú', 'Ɔjɔ́bɔ', 'Ɛtì', 'Àbámɛ́ta'],\n    'months' => ['Oshù Shɛ́rɛ́', 'Oshù Èrèlè', 'Oshù Ɛrɛ̀nà', 'Oshù Ìgbé', 'Oshù Ɛ̀bibi', 'Oshù Òkúdu', 'Oshù Agɛmɔ', 'Oshù Ògún', 'Oshù Owewe', 'Oshù Ɔ̀wàrà', 'Oshù Bélú', 'Oshù Ɔ̀pɛ̀'],\n    'months_short' => ['Shɛ́rɛ́', 'Èrèlè', 'Ɛrɛ̀nà', 'Ìgbé', 'Ɛ̀bibi', 'Òkúdu', 'Agɛmɔ', 'Ògún', 'Owewe', 'Ɔ̀wàrà', 'Bélú', 'Ɔ̀pɛ̀'],\n    'first_day_of_week' => 1,\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd, D MMMM YYYY HH:mm',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/yo_NG.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/yo.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/yue.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/yue_HK.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/yue_HK.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/zh_HK.php', [\n    'formats' => [\n        'L' => 'YYYY年MM月DD日 dddd',\n    ],\n    'months' => ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],\n    'months_short' => ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],\n    'weekdays' => ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'],\n    'weekdays_short' => ['日', '一', '二', '三', '四', '五', '六'],\n    'weekdays_min' => ['日', '一', '二', '三', '四', '五', '六'],\n    'first_day_of_week' => 0,\n    'day_of_first_week_of_year' => 1,\n    'meridiem' => ['上午', '下午'],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/yue_Hans.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/zh_Hans.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/yue_Hant.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/zh_Hant.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/yuw.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/yuw_PG.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/yuw_PG.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Information from native speakers Hannah Sarvasy nungon.localization@gmail.com\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD/MM/YY',\n    ],\n    'months' => ['jenuari', 'febuari', 'mas', 'epril', 'mei', 'jun', 'julai', 'ögus', 'septemba', 'öktoba', 'nöwemba', 'diksemba'],\n    'months_short' => ['jen', 'feb', 'mas', 'epr', 'mei', 'jun', 'jul', 'ögu', 'sep', 'ökt', 'nöw', 'dis'],\n    'weekdays' => ['sönda', 'mönda', 'sinda', 'mitiwö', 'sogipbono', 'nenggo', 'söndanggie'],\n    'weekdays_short' => ['sön', 'mön', 'sin', 'mit', 'soi', 'nen', 'sab'],\n    'weekdays_min' => ['sön', 'mön', 'sin', 'mit', 'soi', 'nen', 'sab'],\n    'day_of_first_week_of_year' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/zgh.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - BAKTETE Miloud\n */\nreturn [\n    'year' => ':count ⵓⵙⴳⴳⵯⴰⵙ|:count ⵉⵙⴳⴳⵓⵙⴰ',\n    'a_year' => 'ⵓⵙⴳⴳⵯⴰⵙ|:count ⵉⵙⴳⴳⵓⵙⴰ',\n    'y' => ':count ⵓⵙⴳⴳⵯⴰⵙ|:count ⵉⵙⴳⴳⵓⵙⴰ',\n    'month' => ':count ⵡⴰⵢⵢⵓⵔ|:count ⴰⵢⵢⵓⵔⵏ',\n    'a_month' => 'ⵉⴷⵊ ⵡⴰⵢⵢⵓⵔ|:count ⴰⵢⵢⵓⵔⵏ',\n    'm' => ':count ⴰⵢⵢⵓⵔⵏ',\n    'week' => ':count ⵉⵎⴰⵍⴰⵙⵙ|:count ⵉⵎⴰⵍⴰⵙⵙⵏ',\n    'a_week' => 'ⵉⵛⵜ ⵉⵎⴰⵍⴰⵙⵙ|:count ⵉⵎⴰⵍⴰⵙⵙⵏ',\n    'w' => ':count ⵉⵎⴰⵍⴰⵙⵙ.',\n    'day' => ':count ⵡⴰⵙⵙ|:count ⵓⵙⵙⴰⵏ',\n    'a_day' => 'ⵉⴷⵊ ⵡⴰⵙⵙ|:count ⵓⵙⵙⴰⵏ',\n    'd' => ':count ⵓ',\n    'hour' => ':count ⵜⵙⵔⴰⴳⵜ|:count ⵜⵉⵙⵔⴰⴳⵉⵏ',\n    'a_hour' => 'ⵉⵛⵜ ⵜⵙⵔⴰⴳⵜ|:count ⵜⵉⵙⵔⴰⴳⵉⵏ',\n    'h' => ':count ⵜ',\n    'minute' => ':count ⵜⵓⵙⴷⵉⴷⵜ|:count ⵜⵓⵙⴷⵉⴷⵉⵏ',\n    'a_minute' => 'ⵉⵛⵜ ⵜⵓⵙⴷⵉⴷⵜ|:count ⵜⵓⵙⴷⵉⴷⵉⵏ',\n    'min' => ':count ⵜⵓⵙ',\n    'second' => ':count ⵜⵙⵉⵏⵜ|:count ⵜⵉⵙⵉⵏⴰ',\n    'a_second' => 'ⴽⵔⴰ ⵜⵉⵙⵉⵏⴰ|:count ⵜⵉⵙⵉⵏⴰ',\n    's' => ':count ⵜ',\n    'ago' => 'ⵣⴳ :time',\n    'from_now' => 'ⴷⴳ :time',\n    'after' => ':time ⴰⵡⴰⵔ',\n    'before' => ':time ⴷⴰⵜ',\n    'diff_now' => 'ⴰⴷⵡⴰⵍⵉ',\n    'diff_today' => 'ⴰⵙⵙ',\n    'diff_today_regexp' => 'ⴰⵙⵙ(?:\\\\s+ⴰ/ⴰⴷ)?(?:\\\\s+ⴳ)?',\n    'diff_yesterday' => 'ⴰⵙⵙⵏⵏⴰⵟ',\n    'diff_yesterday_regexp' => 'ⴰⵙⵙⵏⵏⴰⵟ(?:\\\\s+ⴳ)?',\n    'diff_tomorrow' => 'ⴰⵙⴽⴽⴰ',\n    'diff_tomorrow_regexp' => 'ⴰⵙⴽⴽⴰ(?:\\\\s+ⴳ)?',\n    'diff_before_yesterday' => 'ⴼⵔ ⵉⴹⵏⵏⴰⵟ',\n    'diff_after_tomorrow' => 'ⵏⴰⴼ ⵓⵙⴽⴽⴰ',\n    'period_recurrences' => ':count ⵜⵉⴽⴽⴰⵍ',\n    'period_interval' => 'ⴽⵓ :interval',\n    'period_start_date' => 'ⴳ :date',\n    'period_end_date' => 'ⵉ :date',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'DD/MM/YYYY',\n        'LL' => 'D MMMM YYYY',\n        'LLL' => 'D MMMM YYYY HH:mm',\n        'LLLL' => 'dddd D MMMM YYYY HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[ⴰⵙⵙ ⴰ/ⴰⴷ ⴳ] LT',\n        'nextDay' => '[ⴰⵙⴽⴽⴰ ⴳ] LT',\n        'nextWeek' => 'dddd [ⴳ] LT',\n        'lastDay' => '[ⴰⵙⵙⵏⵏⴰⵟ ⴳ] LT',\n        'lastWeek' => 'dddd [ⴰⵎⴳⴳⴰⵔⵓ ⴳ] LT',\n        'sameElse' => 'L',\n    ],\n    'meridiem' => ['ⵜⵉⴼⴰⵡⵜ', 'ⵜⴰⴷⴳⴳⵯⴰⵜ'],\n    'months' => ['ⵉⵏⵏⴰⵢⵔ', 'ⴱⵕⴰⵢⵕ', 'ⵎⴰⵕⵚ', 'ⵉⴱⵔⵉⵔ', 'ⵎⴰⵢⵢⵓ', 'ⵢⵓⵏⵢⵓ', 'ⵢⵓⵍⵢⵓⵣ', 'ⵖⵓⵛⵜ', 'ⵛⵓⵜⴰⵏⴱⵉⵔ', 'ⴽⵟⵓⴱⵕ', 'ⵏⵓⵡⴰⵏⴱⵉⵔ', 'ⴷⵓⵊⴰⵏⴱⵉⵔ'],\n    'months_short' => ['ⵉⵏⵏ', 'ⴱⵕⴰ', 'ⵎⴰⵕ', 'ⵉⴱⵔ', 'ⵎⴰⵢ', 'ⵢⵓⵏ', 'ⵢⵓⵍ', 'ⵖⵓⵛ', 'ⵛⵓⵜ', 'ⴽⵟⵓ', 'ⵏⵓⵡ', 'ⴷⵓⵊ'],\n    'weekdays' => ['ⵓⵙⴰⵎⴰⵙ', 'ⵡⴰⵢⵏⴰⵙ', 'ⵓⵙⵉⵏⴰⵙ', 'ⵡⴰⴽⵕⴰⵙ', 'ⵓⴽⵡⴰⵙ', 'ⵓⵙⵉⵎⵡⴰⵙ', 'ⵓⵙⵉⴹⵢⴰⵙ'],\n    'weekdays_short' => ['ⵓⵙⴰ', 'ⵡⴰⵢ', 'ⵓⵙⵉ', 'ⵡⴰⴽ', 'ⵓⴽⵡ', 'ⵓⵙⵉⵎ', 'ⵓⵙⵉⴹ'],\n    'weekdays_min' => ['ⵓⵙⴰ', 'ⵡⴰⵢ', 'ⵓⵙⵉ', 'ⵡⴰⴽ', 'ⵓⴽⵡ', 'ⵓⵙⵉⵎ', 'ⵓⵙⵉⴹ'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 1,\n    'list' => [', ', ' ⴷ '],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/zh.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - xuri\n * - sycuato\n * - bokideckonja\n * - Luo Ning\n * - William Yang (williamyang233)\n */\nreturn array_merge(require __DIR__.'/zh_Hans.php', [\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'YYYY/MM/DD',\n        'LL' => 'YYYY年M月D日',\n        'LLL' => 'YYYY年M月D日 A h点mm分',\n        'LLLL' => 'YYYY年M月D日dddd A h点mm分',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/zh_CN.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - monkeycon\n * - François B\n * - Jason Katz-Brown\n * - Serhan Apaydın\n * - Matt Johnson\n * - JD Isaacks\n * - Zeno Zeng\n * - Chris Hemp\n * - shankesgk2\n */\nreturn array_merge(require __DIR__.'/zh.php', [\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'YYYY/MM/DD',\n        'LL' => 'YYYY年M月D日',\n        'LLL' => 'YYYY年M月D日Ah点mm分',\n        'LLLL' => 'YYYY年M月D日ddddAh点mm分',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/zh_HK.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/zh_Hant_HK.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/zh_Hans.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - monkeycon\n * - François B\n * - Jason Katz-Brown\n * - Konstantin Konev\n * - Chris Lam\n * - Serhan Apaydın\n * - Gary Lo\n * - JD Isaacks\n * - Chris Hemp\n * - shankesgk2\n * - Daniel Cheung (danvim)\n */\nreturn [\n    'year' => ':count:optional-space年',\n    'y' => ':count:optional-space年',\n    'month' => ':count:optional-space个月',\n    'm' => ':count:optional-space个月',\n    'week' => ':count:optional-space周',\n    'w' => ':count:optional-space周',\n    'day' => ':count:optional-space天',\n    'd' => ':count:optional-space天',\n    'hour' => ':count:optional-space小时',\n    'h' => ':count:optional-space小时',\n    'minute' => ':count:optional-space分钟',\n    'min' => ':count:optional-space分钟',\n    'second' => ':count:optional-space秒',\n    'a_second' => '{1}几秒|]1,Inf[:count:optional-space秒',\n    's' => ':count:optional-space秒',\n    'ago' => ':time前',\n    'from_now' => ':time后',\n    'after' => ':time后',\n    'before' => ':time前',\n    'diff_now' => '现在',\n    'diff_today' => '今天',\n    'diff_yesterday' => '昨天',\n    'diff_tomorrow' => '明天',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'YYYY/MM/DD',\n        'LL' => 'YYYY年M月D日',\n        'LLL' => 'YYYY年M月D日 HH:mm',\n        'LLLL' => 'YYYY年M月D日dddd HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[今天]LT',\n        'nextDay' => '[明天]LT',\n        'nextWeek' => '[下]ddddLT',\n        'lastDay' => '[昨天]LT',\n        'lastWeek' => '[上]ddddLT',\n        'sameElse' => 'L',\n    ],\n    'ordinal' => function ($number, $period) {\n        switch ($period) {\n            case 'd':\n            case 'D':\n            case 'DDD':\n                return $number.'日';\n            case 'M':\n                return $number.'月';\n            case 'w':\n            case 'W':\n                return $number.'周';\n            default:\n                return $number;\n        }\n    },\n    'meridiem' => function ($hour, $minute) {\n        $time = $hour * 100 + $minute;\n        if ($time < 600) {\n            return '凌晨';\n        }\n        if ($time < 900) {\n            return '早上';\n        }\n        if ($time < 1130) {\n            return '上午';\n        }\n        if ($time < 1230) {\n            return '中午';\n        }\n        if ($time < 1800) {\n            return '下午';\n        }\n\n        return '晚上';\n    },\n    'months' => ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'],\n    'months_short' => ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],\n    'weekdays' => ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'],\n    'weekdays_short' => ['周日', '周一', '周二', '周三', '周四', '周五', '周六'],\n    'weekdays_min' => ['日', '一', '二', '三', '四', '五', '六'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n    'list' => '',\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/zh_Hans_HK.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/zh_Hans.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/zh_Hans_MO.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/zh_Hans.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/zh_Hans_SG.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/zh_Hans.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/zh_Hant.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Adam\n * - monkeycon\n * - François B\n * - Jason Katz-Brown\n * - Chris Lam\n * - Serhan Apaydın\n * - Gary Lo\n * - JD Isaacks\n * - Chris Hemp\n * - Eddie\n * - KID\n * - shankesgk2\n * - Daniel Cheung (danvim)\n */\nreturn [\n    'year' => ':count:optional-space年',\n    'y' => ':count:optional-space年',\n    'month' => ':count:optional-space個月',\n    'm' => ':count:optional-space月',\n    'week' => ':count:optional-space週',\n    'w' => ':count:optional-space週',\n    'day' => ':count:optional-space天',\n    'd' => ':count:optional-space天',\n    'hour' => ':count:optional-space小時',\n    'h' => ':count:optional-space小時',\n    'minute' => ':count:optional-space分鐘',\n    'min' => ':count:optional-space分鐘',\n    'second' => ':count:optional-space秒',\n    'a_second' => '{1}幾秒|]1,Inf[:count:optional-space秒',\n    's' => ':count:optional-space秒',\n    'ago' => ':time前',\n    'from_now' => ':time後',\n    'after' => ':time後',\n    'before' => ':time前',\n    'diff_now' => '現在',\n    'diff_today' => '今天',\n    'diff_yesterday' => '昨天',\n    'diff_tomorrow' => '明天',\n    'formats' => [\n        'LT' => 'HH:mm',\n        'LTS' => 'HH:mm:ss',\n        'L' => 'YYYY/MM/DD',\n        'LL' => 'YYYY年M月D日',\n        'LLL' => 'YYYY年M月D日 HH:mm',\n        'LLLL' => 'YYYY年M月D日dddd HH:mm',\n    ],\n    'calendar' => [\n        'sameDay' => '[今天] LT',\n        'nextDay' => '[明天] LT',\n        'nextWeek' => '[下]dddd LT',\n        'lastDay' => '[昨天] LT',\n        'lastWeek' => '[上]dddd LT',\n        'sameElse' => 'L',\n    ],\n    'ordinal' => function ($number, $period) {\n        switch ($period) {\n            case 'd':\n            case 'D':\n            case 'DDD':\n                return $number.'日';\n            case 'M':\n                return $number.'月';\n            case 'w':\n            case 'W':\n                return $number.'周';\n            default:\n                return $number;\n        }\n    },\n    'meridiem' => function ($hour, $minute) {\n        $time = $hour * 100 + $minute;\n        if ($time < 600) {\n            return '凌晨';\n        }\n        if ($time < 900) {\n            return '早上';\n        }\n        if ($time < 1130) {\n            return '上午';\n        }\n        if ($time < 1230) {\n            return '中午';\n        }\n        if ($time < 1800) {\n            return '下午';\n        }\n\n        return '晚上';\n    },\n    'months' => ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'],\n    'months_short' => ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],\n    'weekdays' => ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'],\n    'weekdays_short' => ['週日', '週一', '週二', '週三', '週四', '週五', '週六'],\n    'weekdays_min' => ['日', '一', '二', '三', '四', '五', '六'],\n    'first_day_of_week' => 1,\n    'day_of_first_week_of_year' => 4,\n    'list' => '',\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/zh_Hant_HK.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/zh_Hant.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/zh_Hant_MO.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/zh_Hant.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/zh_Hant_TW.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/zh_Hant.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/zh_MO.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - tarunvelli\n * - Eddie\n * - KID\n * - shankesgk2\n */\nreturn array_replace_recursive(require __DIR__.'/zh_Hant.php', [\n    'after' => ':time后',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/zh_SG.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - IBM Globalization Center of Competency, Yamato Software Laboratory    bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/zh.php', [\n    'formats' => [\n        'L' => 'YYYY年MM月DD日',\n    ],\n    'months' => ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'],\n    'months_short' => ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'],\n    'weekdays' => ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'],\n    'weekdays_short' => ['日', '一', '二', '三', '四', '五', '六'],\n    'weekdays_min' => ['日', '一', '二', '三', '四', '五', '六'],\n    'day_of_first_week_of_year' => 1,\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/zh_TW.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn require __DIR__.'/zh_Hant_TW.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/zh_YUE.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - IBM Globalization Center of Competency, Yamato Software Laboratory    bug-glibc-locales@gnu.org\n */\nreturn array_replace_recursive(require __DIR__.'/zh.php', [\n    'formats' => [\n        'L' => 'YYYY-MM-DD',\n    ],\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/zu.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Unknown default region, use the first alphabetically.\n */\nreturn require __DIR__.'/zu_ZA.php';\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Lang/zu_ZA.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * Authors:\n * - Zuza Software Foundation (Translate.org.za) Dwayne Bailey dwayne@translate.org.za\n */\nreturn array_replace_recursive(require __DIR__.'/en.php', [\n    'formats' => [\n        'L' => 'DD/MM/YYYY',\n    ],\n    'months' => ['Januwari', 'Februwari', 'Mashi', 'Ephreli', 'Meyi', 'Juni', 'Julayi', 'Agasti', 'Septhemba', 'Okthoba', 'Novemba', 'Disemba'],\n    'months_short' => ['Jan', 'Feb', 'Mas', 'Eph', 'Mey', 'Jun', 'Jul', 'Aga', 'Sep', 'Okt', 'Nov', 'Dis'],\n    'weekdays' => ['iSonto', 'uMsombuluko', 'uLwesibili', 'uLwesithathu', 'uLwesine', 'uLwesihlanu', 'uMgqibelo'],\n    'weekdays_short' => ['Son', 'Mso', 'Bil', 'Tha', 'Sin', 'Hla', 'Mgq'],\n    'weekdays_min' => ['Son', 'Mso', 'Bil', 'Tha', 'Sin', 'Hla', 'Mgq'],\n    'day_of_first_week_of_year' => 1,\n\n    'year' => 'kweminyaka engu-:count',\n    'y' => 'kweminyaka engu-:count',\n    'a_year' => 'kweminyaka engu-:count',\n\n    'month' => 'izinyanga ezingu-:count',\n    'm' => 'izinyanga ezingu-:count',\n    'a_month' => 'izinyanga ezingu-:count',\n\n    'week' => 'lwamasonto angu-:count',\n    'w' => 'lwamasonto angu-:count',\n    'a_week' => 'lwamasonto angu-:count',\n\n    'day' => 'ezingaba ngu-:count',\n    'd' => 'ezingaba ngu-:count',\n    'a_day' => 'ezingaba ngu-:count',\n\n    'hour' => 'amahora angu-:count',\n    'h' => 'amahora angu-:count',\n    'a_hour' => 'amahora angu-:count',\n\n    'minute' => 'ngemizuzu engu-:count',\n    'min' => 'ngemizuzu engu-:count',\n    'a_minute' => 'ngemizuzu engu-:count',\n\n    'second' => 'imizuzwana engu-:count',\n    's' => 'imizuzwana engu-:count',\n    'a_second' => 'imizuzwana engu-:count',\n]);\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Language.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon;\n\nuse JsonSerializable;\nuse ReturnTypeWillChange;\n\nclass Language implements JsonSerializable\n{\n    /**\n     * @var array\n     */\n    protected static $languagesNames;\n\n    /**\n     * @var array\n     */\n    protected static $regionsNames;\n\n    /**\n     * @var string\n     */\n    protected $id;\n\n    /**\n     * @var string\n     */\n    protected $code;\n\n    /**\n     * @var string|null\n     */\n    protected $variant;\n\n    /**\n     * @var string|null\n     */\n    protected $region;\n\n    /**\n     * @var array\n     */\n    protected $names;\n\n    /**\n     * @var string\n     */\n    protected $isoName;\n\n    /**\n     * @var string\n     */\n    protected $nativeName;\n\n    public function __construct(string $id)\n    {\n        $this->id = str_replace('-', '_', $id);\n        $parts = explode('_', $this->id);\n        $this->code = $parts[0];\n\n        if (isset($parts[1])) {\n            if (!preg_match('/^[A-Z]+$/', $parts[1])) {\n                $this->variant = $parts[1];\n                $parts[1] = $parts[2] ?? null;\n            }\n            if ($parts[1]) {\n                $this->region = $parts[1];\n            }\n        }\n    }\n\n    /**\n     * Get the list of the known languages.\n     *\n     * @return array\n     */\n    public static function all()\n    {\n        if (!static::$languagesNames) {\n            static::$languagesNames = require __DIR__.'/List/languages.php';\n        }\n\n        return static::$languagesNames;\n    }\n\n    /**\n     * Get the list of the known regions.\n     *\n     * @return array\n     */\n    public static function regions()\n    {\n        if (!static::$regionsNames) {\n            static::$regionsNames = require __DIR__.'/List/regions.php';\n        }\n\n        return static::$regionsNames;\n    }\n\n    /**\n     * Get both isoName and nativeName as an array.\n     *\n     * @return array\n     */\n    public function getNames(): array\n    {\n        if (!$this->names) {\n            $this->names = static::all()[$this->code] ?? [\n                'isoName' => $this->code,\n                'nativeName' => $this->code,\n            ];\n        }\n\n        return $this->names;\n    }\n\n    /**\n     * Returns the original locale ID.\n     *\n     * @return string\n     */\n    public function getId(): string\n    {\n        return $this->id;\n    }\n\n    /**\n     * Returns the code of the locale \"en\"/\"fr\".\n     *\n     * @return string\n     */\n    public function getCode(): string\n    {\n        return $this->code;\n    }\n\n    /**\n     * Returns the variant code such as cyrl/latn.\n     *\n     * @return string|null\n     */\n    public function getVariant(): ?string\n    {\n        return $this->variant;\n    }\n\n    /**\n     * Returns the variant such as Cyrillic/Latin.\n     *\n     * @return string|null\n     */\n    public function getVariantName(): ?string\n    {\n        if ($this->variant === 'Latn') {\n            return 'Latin';\n        }\n\n        if ($this->variant === 'Cyrl') {\n            return 'Cyrillic';\n        }\n\n        return $this->variant;\n    }\n\n    /**\n     * Returns the region part of the locale.\n     *\n     * @return string|null\n     */\n    public function getRegion(): ?string\n    {\n        return $this->region;\n    }\n\n    /**\n     * Returns the region name for the current language.\n     *\n     * @return string|null\n     */\n    public function getRegionName(): ?string\n    {\n        return $this->region ? (static::regions()[$this->region] ?? $this->region) : null;\n    }\n\n    /**\n     * Returns the long ISO language name.\n     *\n     * @return string\n     */\n    public function getFullIsoName(): string\n    {\n        if (!$this->isoName) {\n            $this->isoName = $this->getNames()['isoName'];\n        }\n\n        return $this->isoName;\n    }\n\n    /**\n     * Set the ISO language name.\n     *\n     * @param string $isoName\n     */\n    public function setIsoName(string $isoName): self\n    {\n        $this->isoName = $isoName;\n\n        return $this;\n    }\n\n    /**\n     * Return the full name of the language in this language.\n     *\n     * @return string\n     */\n    public function getFullNativeName(): string\n    {\n        if (!$this->nativeName) {\n            $this->nativeName = $this->getNames()['nativeName'];\n        }\n\n        return $this->nativeName;\n    }\n\n    /**\n     * Set the name of the language in this language.\n     *\n     * @param string $nativeName\n     */\n    public function setNativeName(string $nativeName): self\n    {\n        $this->nativeName = $nativeName;\n\n        return $this;\n    }\n\n    /**\n     * Returns the short ISO language name.\n     *\n     * @return string\n     */\n    public function getIsoName(): string\n    {\n        $name = $this->getFullIsoName();\n\n        return trim(strstr($name, ',', true) ?: $name);\n    }\n\n    /**\n     * Get the short name of the language in this language.\n     *\n     * @return string\n     */\n    public function getNativeName(): string\n    {\n        $name = $this->getFullNativeName();\n\n        return trim(strstr($name, ',', true) ?: $name);\n    }\n\n    /**\n     * Get a string with short ISO name, region in parentheses if applicable, variant in parentheses if applicable.\n     *\n     * @return string\n     */\n    public function getIsoDescription()\n    {\n        $region = $this->getRegionName();\n        $variant = $this->getVariantName();\n\n        return $this->getIsoName().($region ? ' ('.$region.')' : '').($variant ? ' ('.$variant.')' : '');\n    }\n\n    /**\n     * Get a string with short native name, region in parentheses if applicable, variant in parentheses if applicable.\n     *\n     * @return string\n     */\n    public function getNativeDescription()\n    {\n        $region = $this->getRegionName();\n        $variant = $this->getVariantName();\n\n        return $this->getNativeName().($region ? ' ('.$region.')' : '').($variant ? ' ('.$variant.')' : '');\n    }\n\n    /**\n     * Get a string with long ISO name, region in parentheses if applicable, variant in parentheses if applicable.\n     *\n     * @return string\n     */\n    public function getFullIsoDescription()\n    {\n        $region = $this->getRegionName();\n        $variant = $this->getVariantName();\n\n        return $this->getFullIsoName().($region ? ' ('.$region.')' : '').($variant ? ' ('.$variant.')' : '');\n    }\n\n    /**\n     * Get a string with long native name, region in parentheses if applicable, variant in parentheses if applicable.\n     *\n     * @return string\n     */\n    public function getFullNativeDescription()\n    {\n        $region = $this->getRegionName();\n        $variant = $this->getVariantName();\n\n        return $this->getFullNativeName().($region ? ' ('.$region.')' : '').($variant ? ' ('.$variant.')' : '');\n    }\n\n    /**\n     * Returns the original locale ID.\n     *\n     * @return string\n     */\n    public function __toString()\n    {\n        return $this->getId();\n    }\n\n    /**\n     * Get a string with short ISO name, region in parentheses if applicable, variant in parentheses if applicable.\n     *\n     * @return string\n     */\n    #[ReturnTypeWillChange]\n    public function jsonSerialize()\n    {\n        return $this->getIsoDescription();\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Laravel/ServiceProvider.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Laravel;\n\nuse Carbon\\Carbon;\nuse Carbon\\CarbonImmutable;\nuse Carbon\\CarbonInterval;\nuse Carbon\\CarbonPeriod;\nuse Illuminate\\Contracts\\Events\\Dispatcher as DispatcherContract;\nuse Illuminate\\Events\\Dispatcher;\nuse Illuminate\\Events\\EventDispatcher;\nuse Illuminate\\Support\\Carbon as IlluminateCarbon;\nuse Illuminate\\Support\\Facades\\Date;\nuse Throwable;\n\nclass ServiceProvider extends \\Illuminate\\Support\\ServiceProvider\n{\n    /** @var callable|null */\n    protected $appGetter = null;\n\n    /** @var callable|null */\n    protected $localeGetter = null;\n\n    public function setAppGetter(?callable $appGetter): void\n    {\n        $this->appGetter = $appGetter;\n    }\n\n    public function setLocaleGetter(?callable $localeGetter): void\n    {\n        $this->localeGetter = $localeGetter;\n    }\n\n    public function boot()\n    {\n        $this->updateLocale();\n\n        if (!$this->app->bound('events')) {\n            return;\n        }\n\n        $service = $this;\n        $events = $this->app['events'];\n\n        if ($this->isEventDispatcher($events)) {\n            $events->listen(class_exists('Illuminate\\Foundation\\Events\\LocaleUpdated') ? 'Illuminate\\Foundation\\Events\\LocaleUpdated' : 'locale.changed', function () use ($service) {\n                $service->updateLocale();\n            });\n        }\n    }\n\n    public function updateLocale()\n    {\n        $locale = $this->getLocale();\n\n        if ($locale === null) {\n            return;\n        }\n\n        Carbon::setLocale($locale);\n        CarbonImmutable::setLocale($locale);\n        CarbonPeriod::setLocale($locale);\n        CarbonInterval::setLocale($locale);\n\n        if (class_exists(IlluminateCarbon::class)) {\n            IlluminateCarbon::setLocale($locale);\n        }\n\n        if (class_exists(Date::class)) {\n            try {\n                $root = Date::getFacadeRoot();\n                $root->setLocale($locale);\n            } catch (Throwable $e) {\n                // Non Carbon class in use in Date facade\n            }\n        }\n    }\n\n    public function register()\n    {\n        // Needed for Laravel < 5.3 compatibility\n    }\n\n    protected function getLocale()\n    {\n        if ($this->localeGetter) {\n            return ($this->localeGetter)();\n        }\n\n        $app = $this->getApp();\n        $app = $app && method_exists($app, 'getLocale')\n            ? $app\n            : $this->getGlobalApp('translator');\n\n        return $app ? $app->getLocale() : null;\n    }\n\n    protected function getApp()\n    {\n        if ($this->appGetter) {\n            return ($this->appGetter)();\n        }\n\n        return $this->app ?? $this->getGlobalApp();\n    }\n\n    protected function getGlobalApp(...$args)\n    {\n        return \\function_exists('app') ? \\app(...$args) : null;\n    }\n\n    protected function isEventDispatcher($instance)\n    {\n        return $instance instanceof EventDispatcher\n            || $instance instanceof Dispatcher\n            || $instance instanceof DispatcherContract;\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/List/languages.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nreturn [\n    /*\n     * ISO 639-2\n     */\n    'ab' => [\n        'isoName' => 'Abkhazian',\n        'nativeName' => 'аҧсуа бызшәа, аҧсшәа',\n    ],\n    'aa' => [\n        'isoName' => 'Afar',\n        'nativeName' => 'Afaraf',\n    ],\n    'af' => [\n        'isoName' => 'Afrikaans',\n        'nativeName' => 'Afrikaans',\n    ],\n    'ak' => [\n        'isoName' => 'Akan',\n        'nativeName' => 'Akan',\n    ],\n    'sq' => [\n        'isoName' => 'Albanian',\n        'nativeName' => 'Shqip',\n    ],\n    'am' => [\n        'isoName' => 'Amharic',\n        'nativeName' => 'አማርኛ',\n    ],\n    'ar' => [\n        'isoName' => 'Arabic',\n        'nativeName' => 'العربية',\n    ],\n    'an' => [\n        'isoName' => 'Aragonese',\n        'nativeName' => 'aragonés',\n    ],\n    'hy' => [\n        'isoName' => 'Armenian',\n        'nativeName' => 'Հայերեն',\n    ],\n    'as' => [\n        'isoName' => 'Assamese',\n        'nativeName' => 'অসমীয়া',\n    ],\n    'av' => [\n        'isoName' => 'Avaric',\n        'nativeName' => 'авар мацӀ, магӀарул мацӀ',\n    ],\n    'ae' => [\n        'isoName' => 'Avestan',\n        'nativeName' => 'avesta',\n    ],\n    'ay' => [\n        'isoName' => 'Aymara',\n        'nativeName' => 'aymar aru',\n    ],\n    'az' => [\n        'isoName' => 'Azerbaijani',\n        'nativeName' => 'azərbaycan dili',\n    ],\n    'bm' => [\n        'isoName' => 'Bambara',\n        'nativeName' => 'bamanankan',\n    ],\n    'ba' => [\n        'isoName' => 'Bashkir',\n        'nativeName' => 'башҡорт теле',\n    ],\n    'eu' => [\n        'isoName' => 'Basque',\n        'nativeName' => 'euskara, euskera',\n    ],\n    'be' => [\n        'isoName' => 'Belarusian',\n        'nativeName' => 'беларуская мова',\n    ],\n    'bn' => [\n        'isoName' => 'Bengali',\n        'nativeName' => 'বাংলা',\n    ],\n    'bh' => [\n        'isoName' => 'Bihari languages',\n        'nativeName' => 'भोजपुरी',\n    ],\n    'bi' => [\n        'isoName' => 'Bislama',\n        'nativeName' => 'Bislama',\n    ],\n    'bs' => [\n        'isoName' => 'Bosnian',\n        'nativeName' => 'bosanski jezik',\n    ],\n    'br' => [\n        'isoName' => 'Breton',\n        'nativeName' => 'brezhoneg',\n    ],\n    'bg' => [\n        'isoName' => 'Bulgarian',\n        'nativeName' => 'български език',\n    ],\n    'my' => [\n        'isoName' => 'Burmese',\n        'nativeName' => 'ဗမာစာ',\n    ],\n    'ca' => [\n        'isoName' => 'Catalan, Valencian',\n        'nativeName' => 'català, valencià',\n    ],\n    'ch' => [\n        'isoName' => 'Chamorro',\n        'nativeName' => 'Chamoru',\n    ],\n    'ce' => [\n        'isoName' => 'Chechen',\n        'nativeName' => 'нохчийн мотт',\n    ],\n    'ny' => [\n        'isoName' => 'Chichewa, Chewa, Nyanja',\n        'nativeName' => 'chiCheŵa, chinyanja',\n    ],\n    'zh' => [\n        'isoName' => 'Chinese',\n        'nativeName' => '中文 (Zhōngwén), 汉语, 漢語',\n    ],\n    'cv' => [\n        'isoName' => 'Chuvash',\n        'nativeName' => 'чӑваш чӗлхи',\n    ],\n    'kw' => [\n        'isoName' => 'Cornish',\n        'nativeName' => 'Kernewek',\n    ],\n    'co' => [\n        'isoName' => 'Corsican',\n        'nativeName' => 'corsu, lingua corsa',\n    ],\n    'cr' => [\n        'isoName' => 'Cree',\n        'nativeName' => 'ᓀᐦᐃᔭᐍᐏᐣ',\n    ],\n    'hr' => [\n        'isoName' => 'Croatian',\n        'nativeName' => 'hrvatski jezik',\n    ],\n    'cs' => [\n        'isoName' => 'Czech',\n        'nativeName' => 'čeština, český jazyk',\n    ],\n    'da' => [\n        'isoName' => 'Danish',\n        'nativeName' => 'dansk',\n    ],\n    'dv' => [\n        'isoName' => 'Divehi, Dhivehi, Maldivian',\n        'nativeName' => 'ދިވެހި',\n    ],\n    'nl' => [\n        'isoName' => 'Dutch, Flemish',\n        'nativeName' => 'Nederlands, Vlaams',\n    ],\n    'dz' => [\n        'isoName' => 'Dzongkha',\n        'nativeName' => 'རྫོང་ཁ',\n    ],\n    'en' => [\n        'isoName' => 'English',\n        'nativeName' => 'English',\n    ],\n    'eo' => [\n        'isoName' => 'Esperanto',\n        'nativeName' => 'Esperanto',\n    ],\n    'et' => [\n        'isoName' => 'Estonian',\n        'nativeName' => 'eesti, eesti keel',\n    ],\n    'ee' => [\n        'isoName' => 'Ewe',\n        'nativeName' => 'Eʋegbe',\n    ],\n    'fo' => [\n        'isoName' => 'Faroese',\n        'nativeName' => 'føroyskt',\n    ],\n    'fj' => [\n        'isoName' => 'Fijian',\n        'nativeName' => 'vosa Vakaviti',\n    ],\n    'fi' => [\n        'isoName' => 'Finnish',\n        'nativeName' => 'suomi, suomen kieli',\n    ],\n    'fr' => [\n        'isoName' => 'French',\n        'nativeName' => 'français',\n    ],\n    'ff' => [\n        'isoName' => 'Fulah',\n        'nativeName' => 'Fulfulde, Pulaar, Pular',\n    ],\n    'gl' => [\n        'isoName' => 'Galician',\n        'nativeName' => 'Galego',\n    ],\n    'ka' => [\n        'isoName' => 'Georgian',\n        'nativeName' => 'ქართული',\n    ],\n    'de' => [\n        'isoName' => 'German',\n        'nativeName' => 'Deutsch',\n    ],\n    'el' => [\n        'isoName' => 'Greek (modern)',\n        'nativeName' => 'ελληνικά',\n    ],\n    'gn' => [\n        'isoName' => 'Guaraní',\n        'nativeName' => 'Avañe\\'ẽ',\n    ],\n    'gu' => [\n        'isoName' => 'Gujarati',\n        'nativeName' => 'ગુજરાતી',\n    ],\n    'ht' => [\n        'isoName' => 'Haitian, Haitian Creole',\n        'nativeName' => 'Kreyòl ayisyen',\n    ],\n    'ha' => [\n        'isoName' => 'Hausa',\n        'nativeName' => '(Hausa) هَوُسَ',\n    ],\n    'he' => [\n        'isoName' => 'Hebrew (modern)',\n        'nativeName' => 'עברית',\n    ],\n    'hz' => [\n        'isoName' => 'Herero',\n        'nativeName' => 'Otjiherero',\n    ],\n    'hi' => [\n        'isoName' => 'Hindi',\n        'nativeName' => 'हिन्दी, हिंदी',\n    ],\n    'ho' => [\n        'isoName' => 'Hiri Motu',\n        'nativeName' => 'Hiri Motu',\n    ],\n    'hu' => [\n        'isoName' => 'Hungarian',\n        'nativeName' => 'magyar',\n    ],\n    'ia' => [\n        'isoName' => 'Interlingua',\n        'nativeName' => 'Interlingua',\n    ],\n    'id' => [\n        'isoName' => 'Indonesian',\n        'nativeName' => 'Bahasa Indonesia',\n    ],\n    'ie' => [\n        'isoName' => 'Interlingue',\n        'nativeName' => 'Originally called Occidental; then Interlingue after WWII',\n    ],\n    'ga' => [\n        'isoName' => 'Irish',\n        'nativeName' => 'Gaeilge',\n    ],\n    'ig' => [\n        'isoName' => 'Igbo',\n        'nativeName' => 'Asụsụ Igbo',\n    ],\n    'ik' => [\n        'isoName' => 'Inupiaq',\n        'nativeName' => 'Iñupiaq, Iñupiatun',\n    ],\n    'io' => [\n        'isoName' => 'Ido',\n        'nativeName' => 'Ido',\n    ],\n    'is' => [\n        'isoName' => 'Icelandic',\n        'nativeName' => 'Íslenska',\n    ],\n    'it' => [\n        'isoName' => 'Italian',\n        'nativeName' => 'Italiano',\n    ],\n    'iu' => [\n        'isoName' => 'Inuktitut',\n        'nativeName' => 'ᐃᓄᒃᑎᑐᑦ',\n    ],\n    'ja' => [\n        'isoName' => 'Japanese',\n        'nativeName' => '日本語 (にほんご)',\n    ],\n    'jv' => [\n        'isoName' => 'Javanese',\n        'nativeName' => 'ꦧꦱꦗꦮ, Basa Jawa',\n    ],\n    'kl' => [\n        'isoName' => 'Kalaallisut, Greenlandic',\n        'nativeName' => 'kalaallisut, kalaallit oqaasii',\n    ],\n    'kn' => [\n        'isoName' => 'Kannada',\n        'nativeName' => 'ಕನ್ನಡ',\n    ],\n    'kr' => [\n        'isoName' => 'Kanuri',\n        'nativeName' => 'Kanuri',\n    ],\n    'ks' => [\n        'isoName' => 'Kashmiri',\n        'nativeName' => 'कश्मीरी, كشميري‎',\n    ],\n    'kk' => [\n        'isoName' => 'Kazakh',\n        'nativeName' => 'қазақ тілі',\n    ],\n    'km' => [\n        'isoName' => 'Central Khmer',\n        'nativeName' => 'ខ្មែរ, ខេមរភាសា, ភាសាខ្មែរ',\n    ],\n    'ki' => [\n        'isoName' => 'Kikuyu, Gikuyu',\n        'nativeName' => 'Gĩkũyũ',\n    ],\n    'rw' => [\n        'isoName' => 'Kinyarwanda',\n        'nativeName' => 'Ikinyarwanda',\n    ],\n    'ky' => [\n        'isoName' => 'Kirghiz, Kyrgyz',\n        'nativeName' => 'Кыргызча, Кыргыз тили',\n    ],\n    'kv' => [\n        'isoName' => 'Komi',\n        'nativeName' => 'коми кыв',\n    ],\n    'kg' => [\n        'isoName' => 'Kongo',\n        'nativeName' => 'Kikongo',\n    ],\n    'ko' => [\n        'isoName' => 'Korean',\n        'nativeName' => '한국어',\n    ],\n    'ku' => [\n        'isoName' => 'Kurdish',\n        'nativeName' => 'Kurdî, کوردی‎',\n    ],\n    'kj' => [\n        'isoName' => 'Kuanyama, Kwanyama',\n        'nativeName' => 'Kuanyama',\n    ],\n    'la' => [\n        'isoName' => 'Latin',\n        'nativeName' => 'latine, lingua latina',\n    ],\n    'lb' => [\n        'isoName' => 'Luxembourgish, Letzeburgesch',\n        'nativeName' => 'Lëtzebuergesch',\n    ],\n    'lg' => [\n        'isoName' => 'Ganda',\n        'nativeName' => 'Luganda',\n    ],\n    'li' => [\n        'isoName' => 'Limburgan, Limburger, Limburgish',\n        'nativeName' => 'Limburgs',\n    ],\n    'ln' => [\n        'isoName' => 'Lingala',\n        'nativeName' => 'Lingála',\n    ],\n    'lo' => [\n        'isoName' => 'Lao',\n        'nativeName' => 'ພາສາລາວ',\n    ],\n    'lt' => [\n        'isoName' => 'Lithuanian',\n        'nativeName' => 'lietuvių kalba',\n    ],\n    'lu' => [\n        'isoName' => 'Luba-Katanga',\n        'nativeName' => 'Kiluba',\n    ],\n    'lv' => [\n        'isoName' => 'Latvian',\n        'nativeName' => 'latviešu valoda',\n    ],\n    'gv' => [\n        'isoName' => 'Manx',\n        'nativeName' => 'Gaelg, Gailck',\n    ],\n    'mk' => [\n        'isoName' => 'Macedonian',\n        'nativeName' => 'македонски јазик',\n    ],\n    'mg' => [\n        'isoName' => 'Malagasy',\n        'nativeName' => 'fiteny malagasy',\n    ],\n    'ms' => [\n        'isoName' => 'Malay',\n        'nativeName' => 'Bahasa Melayu, بهاس ملايو‎',\n    ],\n    'ml' => [\n        'isoName' => 'Malayalam',\n        'nativeName' => 'മലയാളം',\n    ],\n    'mt' => [\n        'isoName' => 'Maltese',\n        'nativeName' => 'Malti',\n    ],\n    'mi' => [\n        'isoName' => 'Maori',\n        'nativeName' => 'te reo Māori',\n    ],\n    'mr' => [\n        'isoName' => 'Marathi',\n        'nativeName' => 'मराठी',\n    ],\n    'mh' => [\n        'isoName' => 'Marshallese',\n        'nativeName' => 'Kajin M̧ajeļ',\n    ],\n    'mn' => [\n        'isoName' => 'Mongolian',\n        'nativeName' => 'Монгол хэл',\n    ],\n    'na' => [\n        'isoName' => 'Nauru',\n        'nativeName' => 'Dorerin Naoero',\n    ],\n    'nv' => [\n        'isoName' => 'Navajo, Navaho',\n        'nativeName' => 'Diné bizaad',\n    ],\n    'nd' => [\n        'isoName' => 'North Ndebele',\n        'nativeName' => 'isiNdebele',\n    ],\n    'ne' => [\n        'isoName' => 'Nepali',\n        'nativeName' => 'नेपाली',\n    ],\n    'ng' => [\n        'isoName' => 'Ndonga',\n        'nativeName' => 'Owambo',\n    ],\n    'nb' => [\n        'isoName' => 'Norwegian Bokmål',\n        'nativeName' => 'Norsk Bokmål',\n    ],\n    'nn' => [\n        'isoName' => 'Norwegian Nynorsk',\n        'nativeName' => 'Norsk Nynorsk',\n    ],\n    'no' => [\n        'isoName' => 'Norwegian',\n        'nativeName' => 'Norsk',\n    ],\n    'ii' => [\n        'isoName' => 'Sichuan Yi, Nuosu',\n        'nativeName' => 'ꆈꌠ꒿ Nuosuhxop',\n    ],\n    'nr' => [\n        'isoName' => 'South Ndebele',\n        'nativeName' => 'isiNdebele',\n    ],\n    'oc' => [\n        'isoName' => 'Occitan',\n        'nativeName' => 'occitan, lenga d\\'òc',\n    ],\n    'oj' => [\n        'isoName' => 'Ojibwa',\n        'nativeName' => 'ᐊᓂᔑᓈᐯᒧᐎᓐ',\n    ],\n    'cu' => [\n        'isoName' => 'Church Slavic, Church Slavonic, Old Church Slavonic, Old Slavonic, Old Bulgarian',\n        'nativeName' => 'ѩзыкъ словѣньскъ',\n    ],\n    'om' => [\n        'isoName' => 'Oromo',\n        'nativeName' => 'Afaan Oromoo',\n    ],\n    'or' => [\n        'isoName' => 'Oriya',\n        'nativeName' => 'ଓଡ଼ିଆ',\n    ],\n    'os' => [\n        'isoName' => 'Ossetian, Ossetic',\n        'nativeName' => 'ирон æвзаг',\n    ],\n    'pa' => [\n        'isoName' => 'Panjabi, Punjabi',\n        'nativeName' => 'ਪੰਜਾਬੀ',\n    ],\n    'pi' => [\n        'isoName' => 'Pali',\n        'nativeName' => 'पाऴि',\n    ],\n    'fa' => [\n        'isoName' => 'Persian',\n        'nativeName' => 'فارسی',\n    ],\n    'pl' => [\n        'isoName' => 'Polish',\n        'nativeName' => 'język polski, polszczyzna',\n    ],\n    'ps' => [\n        'isoName' => 'Pashto, Pushto',\n        'nativeName' => 'پښتو',\n    ],\n    'pt' => [\n        'isoName' => 'Portuguese',\n        'nativeName' => 'Português',\n    ],\n    'qu' => [\n        'isoName' => 'Quechua',\n        'nativeName' => 'Runa Simi, Kichwa',\n    ],\n    'rm' => [\n        'isoName' => 'Romansh',\n        'nativeName' => 'Rumantsch Grischun',\n    ],\n    'rn' => [\n        'isoName' => 'Rundi',\n        'nativeName' => 'Ikirundi',\n    ],\n    'ro' => [\n        'isoName' => 'Romanian, Moldavian, Moldovan',\n        'nativeName' => 'Română',\n    ],\n    'ru' => [\n        'isoName' => 'Russian',\n        'nativeName' => 'русский',\n    ],\n    'sa' => [\n        'isoName' => 'Sanskrit',\n        'nativeName' => 'संस्कृतम्',\n    ],\n    'sc' => [\n        'isoName' => 'Sardinian',\n        'nativeName' => 'sardu',\n    ],\n    'sd' => [\n        'isoName' => 'Sindhi',\n        'nativeName' => 'सिन्धी, سنڌي، سندھی‎',\n    ],\n    'se' => [\n        'isoName' => 'Northern Sami',\n        'nativeName' => 'Davvisámegiella',\n    ],\n    'sm' => [\n        'isoName' => 'Samoan',\n        'nativeName' => 'gagana fa\\'a Samoa',\n    ],\n    'sg' => [\n        'isoName' => 'Sango',\n        'nativeName' => 'yângâ tî sängö',\n    ],\n    'sr' => [\n        'isoName' => 'Serbian',\n        'nativeName' => 'српски језик',\n    ],\n    'gd' => [\n        'isoName' => 'Gaelic, Scottish Gaelic',\n        'nativeName' => 'Gàidhlig',\n    ],\n    'sn' => [\n        'isoName' => 'Shona',\n        'nativeName' => 'chiShona',\n    ],\n    'si' => [\n        'isoName' => 'Sinhala, Sinhalese',\n        'nativeName' => 'සිංහල',\n    ],\n    'sk' => [\n        'isoName' => 'Slovak',\n        'nativeName' => 'Slovenčina, Slovenský Jazyk',\n    ],\n    'sl' => [\n        'isoName' => 'Slovene',\n        'nativeName' => 'Slovenski Jezik, Slovenščina',\n    ],\n    'so' => [\n        'isoName' => 'Somali',\n        'nativeName' => 'Soomaaliga, af Soomaali',\n    ],\n    'st' => [\n        'isoName' => 'Southern Sotho',\n        'nativeName' => 'Sesotho',\n    ],\n    'es' => [\n        'isoName' => 'Spanish, Castilian',\n        'nativeName' => 'Español',\n    ],\n    'su' => [\n        'isoName' => 'Sundanese',\n        'nativeName' => 'Basa Sunda',\n    ],\n    'sw' => [\n        'isoName' => 'Swahili',\n        'nativeName' => 'Kiswahili',\n    ],\n    'ss' => [\n        'isoName' => 'Swati',\n        'nativeName' => 'SiSwati',\n    ],\n    'sv' => [\n        'isoName' => 'Swedish',\n        'nativeName' => 'Svenska',\n    ],\n    'ta' => [\n        'isoName' => 'Tamil',\n        'nativeName' => 'தமிழ்',\n    ],\n    'te' => [\n        'isoName' => 'Telugu',\n        'nativeName' => 'తెలుగు',\n    ],\n    'tg' => [\n        'isoName' => 'Tajik',\n        'nativeName' => 'тоҷикӣ, toçikī, تاجیکی‎',\n    ],\n    'th' => [\n        'isoName' => 'Thai',\n        'nativeName' => 'ไทย',\n    ],\n    'ti' => [\n        'isoName' => 'Tigrinya',\n        'nativeName' => 'ትግርኛ',\n    ],\n    'bo' => [\n        'isoName' => 'Tibetan',\n        'nativeName' => 'བོད་ཡིག',\n    ],\n    'tk' => [\n        'isoName' => 'Turkmen',\n        'nativeName' => 'Türkmen, Түркмен',\n    ],\n    'tl' => [\n        'isoName' => 'Tagalog',\n        'nativeName' => 'Wikang Tagalog',\n    ],\n    'tn' => [\n        'isoName' => 'Tswana',\n        'nativeName' => 'Setswana',\n    ],\n    'to' => [\n        'isoName' => 'Tongan (Tonga Islands)',\n        'nativeName' => 'Faka Tonga',\n    ],\n    'tr' => [\n        'isoName' => 'Turkish',\n        'nativeName' => 'Türkçe',\n    ],\n    'ts' => [\n        'isoName' => 'Tsonga',\n        'nativeName' => 'Xitsonga',\n    ],\n    'tt' => [\n        'isoName' => 'Tatar',\n        'nativeName' => 'татар теле, tatar tele',\n    ],\n    'tw' => [\n        'isoName' => 'Twi',\n        'nativeName' => 'Twi',\n    ],\n    'ty' => [\n        'isoName' => 'Tahitian',\n        'nativeName' => 'Reo Tahiti',\n    ],\n    'ug' => [\n        'isoName' => 'Uighur, Uyghur',\n        'nativeName' => 'Uyƣurqə, ‫ئۇيغۇرچ',\n    ],\n    'uk' => [\n        'isoName' => 'Ukrainian',\n        'nativeName' => 'Українська',\n    ],\n    'ur' => [\n        'isoName' => 'Urdu',\n        'nativeName' => 'اردو',\n    ],\n    'uz' => [\n        'isoName' => 'Uzbek',\n        'nativeName' => 'Oʻzbek, Ўзбек, أۇزبېك‎',\n    ],\n    've' => [\n        'isoName' => 'Venda',\n        'nativeName' => 'Tshivenḓa',\n    ],\n    'vi' => [\n        'isoName' => 'Vietnamese',\n        'nativeName' => 'Tiếng Việt',\n    ],\n    'vo' => [\n        'isoName' => 'Volapük',\n        'nativeName' => 'Volapük',\n    ],\n    'wa' => [\n        'isoName' => 'Walloon',\n        'nativeName' => 'Walon',\n    ],\n    'cy' => [\n        'isoName' => 'Welsh',\n        'nativeName' => 'Cymraeg',\n    ],\n    'wo' => [\n        'isoName' => 'Wolof',\n        'nativeName' => 'Wollof',\n    ],\n    'fy' => [\n        'isoName' => 'Western Frisian',\n        'nativeName' => 'Frysk',\n    ],\n    'xh' => [\n        'isoName' => 'Xhosa',\n        'nativeName' => 'isiXhosa',\n    ],\n    'yi' => [\n        'isoName' => 'Yiddish',\n        'nativeName' => 'ייִדיש',\n    ],\n    'yo' => [\n        'isoName' => 'Yoruba',\n        'nativeName' => 'Yorùbá',\n    ],\n    'za' => [\n        'isoName' => 'Zhuang, Chuang',\n        'nativeName' => 'Saɯ cueŋƅ, Saw cuengh',\n    ],\n    'zu' => [\n        'isoName' => 'Zulu',\n        'nativeName' => 'isiZulu',\n    ],\n    /*\n     * Add ISO 639-3 languages available in Carbon\n     */\n    'agq' => [\n        'isoName' => 'Aghem',\n        'nativeName' => 'Aghem',\n    ],\n    'agr' => [\n        'isoName' => 'Aguaruna',\n        'nativeName' => 'Aguaruna',\n    ],\n    'anp' => [\n        'isoName' => 'Angika',\n        'nativeName' => 'Angika',\n    ],\n    'asa' => [\n        'isoName' => 'Asu',\n        'nativeName' => 'Asu',\n    ],\n    'ast' => [\n        'isoName' => 'Asturian',\n        'nativeName' => 'Asturian',\n    ],\n    'ayc' => [\n        'isoName' => 'Southern Aymara',\n        'nativeName' => 'Southern Aymara',\n    ],\n    'bas' => [\n        'isoName' => 'Basaa',\n        'nativeName' => 'Basaa',\n    ],\n    'bem' => [\n        'isoName' => 'Bemba',\n        'nativeName' => 'Bemba',\n    ],\n    'bez' => [\n        'isoName' => 'Bena',\n        'nativeName' => 'Bena',\n    ],\n    'bhb' => [\n        'isoName' => 'Bhili',\n        'nativeName' => 'Bhili',\n    ],\n    'bho' => [\n        'isoName' => 'Bhojpuri',\n        'nativeName' => 'Bhojpuri',\n    ],\n    'brx' => [\n        'isoName' => 'Bodo',\n        'nativeName' => 'Bodo',\n    ],\n    'byn' => [\n        'isoName' => 'Bilin',\n        'nativeName' => 'Bilin',\n    ],\n    'ccp' => [\n        'isoName' => 'Chakma',\n        'nativeName' => 'Chakma',\n    ],\n    'cgg' => [\n        'isoName' => 'Chiga',\n        'nativeName' => 'Chiga',\n    ],\n    'chr' => [\n        'isoName' => 'Cherokee',\n        'nativeName' => 'Cherokee',\n    ],\n    'cmn' => [\n        'isoName' => 'Chinese',\n        'nativeName' => 'Chinese',\n    ],\n    'crh' => [\n        'isoName' => 'Crimean Turkish',\n        'nativeName' => 'Crimean Turkish',\n    ],\n    'csb' => [\n        'isoName' => 'Kashubian',\n        'nativeName' => 'Kashubian',\n    ],\n    'dav' => [\n        'isoName' => 'Taita',\n        'nativeName' => 'Taita',\n    ],\n    'dje' => [\n        'isoName' => 'Zarma',\n        'nativeName' => 'Zarma',\n    ],\n    'doi' => [\n        'isoName' => 'Dogri (macrolanguage)',\n        'nativeName' => 'Dogri (macrolanguage)',\n    ],\n    'dsb' => [\n        'isoName' => 'Lower Sorbian',\n        'nativeName' => 'Lower Sorbian',\n    ],\n    'dua' => [\n        'isoName' => 'Duala',\n        'nativeName' => 'Duala',\n    ],\n    'dyo' => [\n        'isoName' => 'Jola-Fonyi',\n        'nativeName' => 'Jola-Fonyi',\n    ],\n    'ebu' => [\n        'isoName' => 'Embu',\n        'nativeName' => 'Embu',\n    ],\n    'ewo' => [\n        'isoName' => 'Ewondo',\n        'nativeName' => 'Ewondo',\n    ],\n    'fil' => [\n        'isoName' => 'Filipino',\n        'nativeName' => 'Filipino',\n    ],\n    'fur' => [\n        'isoName' => 'Friulian',\n        'nativeName' => 'Friulian',\n    ],\n    'gez' => [\n        'isoName' => 'Geez',\n        'nativeName' => 'Geez',\n    ],\n    'gom' => [\n        'isoName' => 'Konkani, Goan',\n        'nativeName' => 'ಕೊಂಕಣಿ',\n    ],\n    'gsw' => [\n        'isoName' => 'Swiss German',\n        'nativeName' => 'Swiss German',\n    ],\n    'guz' => [\n        'isoName' => 'Gusii',\n        'nativeName' => 'Gusii',\n    ],\n    'hak' => [\n        'isoName' => 'Hakka Chinese',\n        'nativeName' => 'Hakka Chinese',\n    ],\n    'haw' => [\n        'isoName' => 'Hawaiian',\n        'nativeName' => 'Hawaiian',\n    ],\n    'hif' => [\n        'isoName' => 'Fiji Hindi',\n        'nativeName' => 'Fiji Hindi',\n    ],\n    'hne' => [\n        'isoName' => 'Chhattisgarhi',\n        'nativeName' => 'Chhattisgarhi',\n    ],\n    'hsb' => [\n        'isoName' => 'Upper Sorbian',\n        'nativeName' => 'Upper Sorbian',\n    ],\n    'jgo' => [\n        'isoName' => 'Ngomba',\n        'nativeName' => 'Ngomba',\n    ],\n    'jmc' => [\n        'isoName' => 'Machame',\n        'nativeName' => 'Machame',\n    ],\n    'kab' => [\n        'isoName' => 'Kabyle',\n        'nativeName' => 'Kabyle',\n    ],\n    'kam' => [\n        'isoName' => 'Kamba',\n        'nativeName' => 'Kamba',\n    ],\n    'kde' => [\n        'isoName' => 'Makonde',\n        'nativeName' => 'Makonde',\n    ],\n    'kea' => [\n        'isoName' => 'Kabuverdianu',\n        'nativeName' => 'Kabuverdianu',\n    ],\n    'khq' => [\n        'isoName' => 'Koyra Chiini',\n        'nativeName' => 'Koyra Chiini',\n    ],\n    'kkj' => [\n        'isoName' => 'Kako',\n        'nativeName' => 'Kako',\n    ],\n    'kln' => [\n        'isoName' => 'Kalenjin',\n        'nativeName' => 'Kalenjin',\n    ],\n    'kok' => [\n        'isoName' => 'Konkani',\n        'nativeName' => 'Konkani',\n    ],\n    'ksb' => [\n        'isoName' => 'Shambala',\n        'nativeName' => 'Shambala',\n    ],\n    'ksf' => [\n        'isoName' => 'Bafia',\n        'nativeName' => 'Bafia',\n    ],\n    'ksh' => [\n        'isoName' => 'Colognian',\n        'nativeName' => 'Colognian',\n    ],\n    'lag' => [\n        'isoName' => 'Langi',\n        'nativeName' => 'Langi',\n    ],\n    'lij' => [\n        'isoName' => 'Ligurian',\n        'nativeName' => 'Ligurian',\n    ],\n    'lkt' => [\n        'isoName' => 'Lakota',\n        'nativeName' => 'Lakota',\n    ],\n    'lrc' => [\n        'isoName' => 'Northern Luri',\n        'nativeName' => 'Northern Luri',\n    ],\n    'luo' => [\n        'isoName' => 'Luo',\n        'nativeName' => 'Luo',\n    ],\n    'luy' => [\n        'isoName' => 'Luyia',\n        'nativeName' => 'Luyia',\n    ],\n    'lzh' => [\n        'isoName' => 'Literary Chinese',\n        'nativeName' => 'Literary Chinese',\n    ],\n    'mag' => [\n        'isoName' => 'Magahi',\n        'nativeName' => 'Magahi',\n    ],\n    'mai' => [\n        'isoName' => 'Maithili',\n        'nativeName' => 'Maithili',\n    ],\n    'mas' => [\n        'isoName' => 'Masai',\n        'nativeName' => 'Masai',\n    ],\n    'mer' => [\n        'isoName' => 'Meru',\n        'nativeName' => 'Meru',\n    ],\n    'mfe' => [\n        'isoName' => 'Morisyen',\n        'nativeName' => 'Morisyen',\n    ],\n    'mgh' => [\n        'isoName' => 'Makhuwa-Meetto',\n        'nativeName' => 'Makhuwa-Meetto',\n    ],\n    'mgo' => [\n        'isoName' => 'Metaʼ',\n        'nativeName' => 'Metaʼ',\n    ],\n    'mhr' => [\n        'isoName' => 'Eastern Mari',\n        'nativeName' => 'Eastern Mari',\n    ],\n    'miq' => [\n        'isoName' => 'Mískito',\n        'nativeName' => 'Mískito',\n    ],\n    'mjw' => [\n        'isoName' => 'Karbi',\n        'nativeName' => 'Karbi',\n    ],\n    'mni' => [\n        'isoName' => 'Manipuri',\n        'nativeName' => 'Manipuri',\n    ],\n    'mua' => [\n        'isoName' => 'Mundang',\n        'nativeName' => 'Mundang',\n    ],\n    'mzn' => [\n        'isoName' => 'Mazanderani',\n        'nativeName' => 'Mazanderani',\n    ],\n    'nan' => [\n        'isoName' => 'Min Nan Chinese',\n        'nativeName' => 'Min Nan Chinese',\n    ],\n    'naq' => [\n        'isoName' => 'Nama',\n        'nativeName' => 'Nama',\n    ],\n    'nds' => [\n        'isoName' => 'Low German',\n        'nativeName' => 'Low German',\n    ],\n    'nhn' => [\n        'isoName' => 'Central Nahuatl',\n        'nativeName' => 'Central Nahuatl',\n    ],\n    'niu' => [\n        'isoName' => 'Niuean',\n        'nativeName' => 'Niuean',\n    ],\n    'nmg' => [\n        'isoName' => 'Kwasio',\n        'nativeName' => 'Kwasio',\n    ],\n    'nnh' => [\n        'isoName' => 'Ngiemboon',\n        'nativeName' => 'Ngiemboon',\n    ],\n    'nso' => [\n        'isoName' => 'Northern Sotho',\n        'nativeName' => 'Northern Sotho',\n    ],\n    'nus' => [\n        'isoName' => 'Nuer',\n        'nativeName' => 'Nuer',\n    ],\n    'nyn' => [\n        'isoName' => 'Nyankole',\n        'nativeName' => 'Nyankole',\n    ],\n    'pap' => [\n        'isoName' => 'Papiamento',\n        'nativeName' => 'Papiamento',\n    ],\n    'prg' => [\n        'isoName' => 'Prussian',\n        'nativeName' => 'Prussian',\n    ],\n    'quz' => [\n        'isoName' => 'Cusco Quechua',\n        'nativeName' => 'Cusco Quechua',\n    ],\n    'raj' => [\n        'isoName' => 'Rajasthani',\n        'nativeName' => 'Rajasthani',\n    ],\n    'rof' => [\n        'isoName' => 'Rombo',\n        'nativeName' => 'Rombo',\n    ],\n    'rwk' => [\n        'isoName' => 'Rwa',\n        'nativeName' => 'Rwa',\n    ],\n    'sah' => [\n        'isoName' => 'Sakha',\n        'nativeName' => 'Sakha',\n    ],\n    'saq' => [\n        'isoName' => 'Samburu',\n        'nativeName' => 'Samburu',\n    ],\n    'sat' => [\n        'isoName' => 'Santali',\n        'nativeName' => 'Santali',\n    ],\n    'sbp' => [\n        'isoName' => 'Sangu',\n        'nativeName' => 'Sangu',\n    ],\n    'scr' => [\n        'isoName' => 'Serbo Croatian',\n        'nativeName' => 'Serbo Croatian',\n    ],\n    'seh' => [\n        'isoName' => 'Sena',\n        'nativeName' => 'Sena',\n    ],\n    'ses' => [\n        'isoName' => 'Koyraboro Senni',\n        'nativeName' => 'Koyraboro Senni',\n    ],\n    'sgs' => [\n        'isoName' => 'Samogitian',\n        'nativeName' => 'Samogitian',\n    ],\n    'shi' => [\n        'isoName' => 'Tachelhit',\n        'nativeName' => 'Tachelhit',\n    ],\n    'shn' => [\n        'isoName' => 'Shan',\n        'nativeName' => 'Shan',\n    ],\n    'shs' => [\n        'isoName' => 'Shuswap',\n        'nativeName' => 'Shuswap',\n    ],\n    'sid' => [\n        'isoName' => 'Sidamo',\n        'nativeName' => 'Sidamo',\n    ],\n    'smn' => [\n        'isoName' => 'Inari Sami',\n        'nativeName' => 'Inari Sami',\n    ],\n    'szl' => [\n        'isoName' => 'Silesian',\n        'nativeName' => 'Silesian',\n    ],\n    'tcy' => [\n        'isoName' => 'Tulu',\n        'nativeName' => 'Tulu',\n    ],\n    'teo' => [\n        'isoName' => 'Teso',\n        'nativeName' => 'Teso',\n    ],\n    'tet' => [\n        'isoName' => 'Tetum',\n        'nativeName' => 'Tetum',\n    ],\n    'the' => [\n        'isoName' => 'Chitwania Tharu',\n        'nativeName' => 'Chitwania Tharu',\n    ],\n    'tig' => [\n        'isoName' => 'Tigre',\n        'nativeName' => 'Tigre',\n    ],\n    'tlh' => [\n        'isoName' => 'Klingon',\n        'nativeName' => 'tlhIngan Hol',\n    ],\n    'tpi' => [\n        'isoName' => 'Tok Pisin',\n        'nativeName' => 'Tok Pisin',\n    ],\n    'twq' => [\n        'isoName' => 'Tasawaq',\n        'nativeName' => 'Tasawaq',\n    ],\n    'tzl' => [\n        'isoName' => 'Talossan',\n        'nativeName' => 'Talossan',\n    ],\n    'tzm' => [\n        'isoName' => 'Tamazight, Central Atlas',\n        'nativeName' => 'ⵜⵎⴰⵣⵉⵖⵜ',\n    ],\n    'unm' => [\n        'isoName' => 'Unami',\n        'nativeName' => 'Unami',\n    ],\n    'vai' => [\n        'isoName' => 'Vai',\n        'nativeName' => 'Vai',\n    ],\n    'vun' => [\n        'isoName' => 'Vunjo',\n        'nativeName' => 'Vunjo',\n    ],\n    'wae' => [\n        'isoName' => 'Walser',\n        'nativeName' => 'Walser',\n    ],\n    'wal' => [\n        'isoName' => 'Wolaytta',\n        'nativeName' => 'Wolaytta',\n    ],\n    'xog' => [\n        'isoName' => 'Soga',\n        'nativeName' => 'Soga',\n    ],\n    'yav' => [\n        'isoName' => 'Yangben',\n        'nativeName' => 'Yangben',\n    ],\n    'yue' => [\n        'isoName' => 'Cantonese',\n        'nativeName' => 'Cantonese',\n    ],\n    'yuw' => [\n        'isoName' => 'Yau (Morobe Province)',\n        'nativeName' => 'Yau (Morobe Province)',\n    ],\n    'zgh' => [\n        'isoName' => 'Standard Moroccan Tamazight',\n        'nativeName' => 'Standard Moroccan Tamazight',\n    ],\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/List/regions.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/*\n * ISO 3166-2\n */\nreturn [\n    'AD' => 'Andorra',\n    'AE' => 'United Arab Emirates',\n    'AF' => 'Afghanistan',\n    'AG' => 'Antigua and Barbuda',\n    'AI' => 'Anguilla',\n    'AL' => 'Albania',\n    'AM' => 'Armenia',\n    'AO' => 'Angola',\n    'AQ' => 'Antarctica',\n    'AR' => 'Argentina',\n    'AS' => 'American Samoa',\n    'AT' => 'Austria',\n    'AU' => 'Australia',\n    'AW' => 'Aruba',\n    'AX' => 'Åland Islands',\n    'AZ' => 'Azerbaijan',\n    'BA' => 'Bosnia and Herzegovina',\n    'BB' => 'Barbados',\n    'BD' => 'Bangladesh',\n    'BE' => 'Belgium',\n    'BF' => 'Burkina Faso',\n    'BG' => 'Bulgaria',\n    'BH' => 'Bahrain',\n    'BI' => 'Burundi',\n    'BJ' => 'Benin',\n    'BL' => 'Saint Barthélemy',\n    'BM' => 'Bermuda',\n    'BN' => 'Brunei Darussalam',\n    'BO' => 'Bolivia (Plurinational State of)',\n    'BQ' => 'Bonaire, Sint Eustatius and Saba',\n    'BR' => 'Brazil',\n    'BS' => 'Bahamas',\n    'BT' => 'Bhutan',\n    'BV' => 'Bouvet Island',\n    'BW' => 'Botswana',\n    'BY' => 'Belarus',\n    'BZ' => 'Belize',\n    'CA' => 'Canada',\n    'CC' => 'Cocos (Keeling) Islands',\n    'CD' => 'Congo, Democratic Republic of the',\n    'CF' => 'Central African Republic',\n    'CG' => 'Congo',\n    'CH' => 'Switzerland',\n    'CI' => 'Côte d\\'Ivoire',\n    'CK' => 'Cook Islands',\n    'CL' => 'Chile',\n    'CM' => 'Cameroon',\n    'CN' => 'China',\n    'CO' => 'Colombia',\n    'CR' => 'Costa Rica',\n    'CU' => 'Cuba',\n    'CV' => 'Cabo Verde',\n    'CW' => 'Curaçao',\n    'CX' => 'Christmas Island',\n    'CY' => 'Cyprus',\n    'CZ' => 'Czechia',\n    'DE' => 'Germany',\n    'DJ' => 'Djibouti',\n    'DK' => 'Denmark',\n    'DM' => 'Dominica',\n    'DO' => 'Dominican Republic',\n    'DZ' => 'Algeria',\n    'EC' => 'Ecuador',\n    'EE' => 'Estonia',\n    'EG' => 'Egypt',\n    'EH' => 'Western Sahara',\n    'ER' => 'Eritrea',\n    'ES' => 'Spain',\n    'ET' => 'Ethiopia',\n    'FI' => 'Finland',\n    'FJ' => 'Fiji',\n    'FK' => 'Falkland Islands (Malvinas)',\n    'FM' => 'Micronesia (Federated States of)',\n    'FO' => 'Faroe Islands',\n    'FR' => 'France',\n    'GA' => 'Gabon',\n    'GB' => 'United Kingdom of Great Britain and Northern Ireland',\n    'GD' => 'Grenada',\n    'GE' => 'Georgia',\n    'GF' => 'French Guiana',\n    'GG' => 'Guernsey',\n    'GH' => 'Ghana',\n    'GI' => 'Gibraltar',\n    'GL' => 'Greenland',\n    'GM' => 'Gambia',\n    'GN' => 'Guinea',\n    'GP' => 'Guadeloupe',\n    'GQ' => 'Equatorial Guinea',\n    'GR' => 'Greece',\n    'GS' => 'South Georgia and the South Sandwich Islands',\n    'GT' => 'Guatemala',\n    'GU' => 'Guam',\n    'GW' => 'Guinea-Bissau',\n    'GY' => 'Guyana',\n    'HK' => 'Hong Kong',\n    'HM' => 'Heard Island and McDonald Islands',\n    'HN' => 'Honduras',\n    'HR' => 'Croatia',\n    'HT' => 'Haiti',\n    'HU' => 'Hungary',\n    'ID' => 'Indonesia',\n    'IE' => 'Ireland',\n    'IL' => 'Israel',\n    'IM' => 'Isle of Man',\n    'IN' => 'India',\n    'IO' => 'British Indian Ocean Territory',\n    'IQ' => 'Iraq',\n    'IR' => 'Iran (Islamic Republic of)',\n    'IS' => 'Iceland',\n    'IT' => 'Italy',\n    'JE' => 'Jersey',\n    'JM' => 'Jamaica',\n    'JO' => 'Jordan',\n    'JP' => 'Japan',\n    'KE' => 'Kenya',\n    'KG' => 'Kyrgyzstan',\n    'KH' => 'Cambodia',\n    'KI' => 'Kiribati',\n    'KM' => 'Comoros',\n    'KN' => 'Saint Kitts and Nevis',\n    'KP' => 'Korea (Democratic People\\'s Republic of)',\n    'KR' => 'Korea, Republic of',\n    'KW' => 'Kuwait',\n    'KY' => 'Cayman Islands',\n    'KZ' => 'Kazakhstan',\n    'LA' => 'Lao People\\'s Democratic Republic',\n    'LB' => 'Lebanon',\n    'LC' => 'Saint Lucia',\n    'LI' => 'Liechtenstein',\n    'LK' => 'Sri Lanka',\n    'LR' => 'Liberia',\n    'LS' => 'Lesotho',\n    'LT' => 'Lithuania',\n    'LU' => 'Luxembourg',\n    'LV' => 'Latvia',\n    'LY' => 'Libya',\n    'MA' => 'Morocco',\n    'MC' => 'Monaco',\n    'MD' => 'Moldova, Republic of',\n    'ME' => 'Montenegro',\n    'MF' => 'Saint Martin (French part)',\n    'MG' => 'Madagascar',\n    'MH' => 'Marshall Islands',\n    'MK' => 'Macedonia, the former Yugoslav Republic of',\n    'ML' => 'Mali',\n    'MM' => 'Myanmar',\n    'MN' => 'Mongolia',\n    'MO' => 'Macao',\n    'MP' => 'Northern Mariana Islands',\n    'MQ' => 'Martinique',\n    'MR' => 'Mauritania',\n    'MS' => 'Montserrat',\n    'MT' => 'Malta',\n    'MU' => 'Mauritius',\n    'MV' => 'Maldives',\n    'MW' => 'Malawi',\n    'MX' => 'Mexico',\n    'MY' => 'Malaysia',\n    'MZ' => 'Mozambique',\n    'NA' => 'Namibia',\n    'NC' => 'New Caledonia',\n    'NE' => 'Niger',\n    'NF' => 'Norfolk Island',\n    'NG' => 'Nigeria',\n    'NI' => 'Nicaragua',\n    'NL' => 'Netherlands',\n    'NO' => 'Norway',\n    'NP' => 'Nepal',\n    'NR' => 'Nauru',\n    'NU' => 'Niue',\n    'NZ' => 'New Zealand',\n    'OM' => 'Oman',\n    'PA' => 'Panama',\n    'PE' => 'Peru',\n    'PF' => 'French Polynesia',\n    'PG' => 'Papua New Guinea',\n    'PH' => 'Philippines',\n    'PK' => 'Pakistan',\n    'PL' => 'Poland',\n    'PM' => 'Saint Pierre and Miquelon',\n    'PN' => 'Pitcairn',\n    'PR' => 'Puerto Rico',\n    'PS' => 'Palestine, State of',\n    'PT' => 'Portugal',\n    'PW' => 'Palau',\n    'PY' => 'Paraguay',\n    'QA' => 'Qatar',\n    'RE' => 'Réunion',\n    'RO' => 'Romania',\n    'RS' => 'Serbia',\n    'RU' => 'Russian Federation',\n    'RW' => 'Rwanda',\n    'SA' => 'Saudi Arabia',\n    'SB' => 'Solomon Islands',\n    'SC' => 'Seychelles',\n    'SD' => 'Sudan',\n    'SE' => 'Sweden',\n    'SG' => 'Singapore',\n    'SH' => 'Saint Helena, Ascension and Tristan da Cunha',\n    'SI' => 'Slovenia',\n    'SJ' => 'Svalbard and Jan Mayen',\n    'SK' => 'Slovakia',\n    'SL' => 'Sierra Leone',\n    'SM' => 'San Marino',\n    'SN' => 'Senegal',\n    'SO' => 'Somalia',\n    'SR' => 'Suriname',\n    'SS' => 'South Sudan',\n    'ST' => 'Sao Tome and Principe',\n    'SV' => 'El Salvador',\n    'SX' => 'Sint Maarten (Dutch part)',\n    'SY' => 'Syrian Arab Republic',\n    'SZ' => 'Eswatini',\n    'TC' => 'Turks and Caicos Islands',\n    'TD' => 'Chad',\n    'TF' => 'French Southern Territories',\n    'TG' => 'Togo',\n    'TH' => 'Thailand',\n    'TJ' => 'Tajikistan',\n    'TK' => 'Tokelau',\n    'TL' => 'Timor-Leste',\n    'TM' => 'Turkmenistan',\n    'TN' => 'Tunisia',\n    'TO' => 'Tonga',\n    'TR' => 'Turkey',\n    'TT' => 'Trinidad and Tobago',\n    'TV' => 'Tuvalu',\n    'TW' => 'Taiwan, Province of China',\n    'TZ' => 'Tanzania, United Republic of',\n    'UA' => 'Ukraine',\n    'UG' => 'Uganda',\n    'UM' => 'United States Minor Outlying Islands',\n    'US' => 'United States of America',\n    'UY' => 'Uruguay',\n    'UZ' => 'Uzbekistan',\n    'VA' => 'Holy See',\n    'VC' => 'Saint Vincent and the Grenadines',\n    'VE' => 'Venezuela (Bolivarian Republic of)',\n    'VG' => 'Virgin Islands (British)',\n    'VI' => 'Virgin Islands (U.S.)',\n    'VN' => 'Viet Nam',\n    'VU' => 'Vanuatu',\n    'WF' => 'Wallis and Futuna',\n    'WS' => 'Samoa',\n    'YE' => 'Yemen',\n    'YT' => 'Mayotte',\n    'ZA' => 'South Africa',\n    'ZM' => 'Zambia',\n    'ZW' => 'Zimbabwe',\n];\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/MessageFormatter/MessageFormatterMapper.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\MessageFormatter;\n\nuse ReflectionMethod;\nuse Symfony\\Component\\Translation\\Formatter\\MessageFormatter;\nuse Symfony\\Component\\Translation\\Formatter\\MessageFormatterInterface;\n\n// @codeCoverageIgnoreStart\n$transMethod = new ReflectionMethod(MessageFormatterInterface::class, 'format');\n\nrequire $transMethod->getParameters()[0]->hasType()\n    ? __DIR__.'/../../../lazy/Carbon/MessageFormatter/MessageFormatterMapperStrongType.php'\n    : __DIR__.'/../../../lazy/Carbon/MessageFormatter/MessageFormatterMapperWeakType.php';\n// @codeCoverageIgnoreEnd\n\nfinal class MessageFormatterMapper extends LazyMessageFormatter\n{\n    /**\n     * Wrapped formatter.\n     *\n     * @var MessageFormatterInterface\n     */\n    protected $formatter;\n\n    public function __construct(?MessageFormatterInterface $formatter = null)\n    {\n        $this->formatter = $formatter ?? new MessageFormatter();\n    }\n\n    protected function transformLocale(?string $locale): ?string\n    {\n        return $locale ? preg_replace('/[_@][A-Za-z][a-z]{2,}/', '', $locale) : $locale;\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/PHPStan/AbstractMacro.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\PHPStan;\n\nuse Closure;\nuse InvalidArgumentException;\nuse PHPStan\\BetterReflection\\Reflection\\Adapter\\ReflectionParameter as AdapterReflectionParameter;\nuse PHPStan\\BetterReflection\\Reflection\\Adapter\\ReflectionType as AdapterReflectionType;\nuse PHPStan\\BetterReflection\\Reflection\\ReflectionClass as BetterReflectionClass;\nuse PHPStan\\BetterReflection\\Reflection\\ReflectionFunction as BetterReflectionFunction;\nuse PHPStan\\BetterReflection\\Reflection\\ReflectionParameter as BetterReflectionParameter;\nuse PHPStan\\Reflection\\Php\\BuiltinMethodReflection;\nuse PHPStan\\TrinaryLogic;\nuse ReflectionClass;\nuse ReflectionFunction;\nuse ReflectionMethod;\nuse ReflectionParameter;\nuse ReflectionType;\nuse stdClass;\nuse Throwable;\n\nabstract class AbstractMacro implements BuiltinMethodReflection\n{\n    /**\n     * The reflection function/method.\n     *\n     * @var ReflectionFunction|ReflectionMethod\n     */\n    protected $reflectionFunction;\n\n    /**\n     * The class name.\n     *\n     * @var class-string\n     */\n    private $className;\n\n    /**\n     * The method name.\n     *\n     * @var string\n     */\n    private $methodName;\n\n    /**\n     * The parameters.\n     *\n     * @var ReflectionParameter[]\n     */\n    private $parameters;\n\n    /**\n     * The is static.\n     *\n     * @var bool\n     */\n    private $static = false;\n\n    /**\n     * Macro constructor.\n     *\n     * @param class-string $className\n     * @param string       $methodName\n     * @param callable     $macro\n     */\n    public function __construct(string $className, string $methodName, $macro)\n    {\n        $this->className = $className;\n        $this->methodName = $methodName;\n        $rawReflectionFunction = \\is_array($macro)\n            ? new ReflectionMethod($macro[0], $macro[1])\n            : new ReflectionFunction($macro);\n        $this->reflectionFunction = self::hasModernParser()\n            ? $this->getReflectionFunction($macro)\n            : $rawReflectionFunction; // @codeCoverageIgnore\n        $this->parameters = array_map(\n            function ($parameter) {\n                if ($parameter instanceof BetterReflectionParameter) {\n                    return new AdapterReflectionParameter($parameter);\n                }\n\n                return $parameter; // @codeCoverageIgnore\n            },\n            $this->reflectionFunction->getParameters()\n        );\n\n        if ($rawReflectionFunction->isClosure()) {\n            try {\n                $closure = $rawReflectionFunction->getClosure();\n                $boundClosure = Closure::bind($closure, new stdClass());\n                $this->static = (!$boundClosure || (new ReflectionFunction($boundClosure))->getClosureThis() === null);\n            } catch (Throwable $e) {\n                $this->static = true;\n            }\n        }\n    }\n\n    private function getReflectionFunction($spec)\n    {\n        if (\\is_array($spec) && \\count($spec) === 2 && \\is_string($spec[1])) {\n            \\assert($spec[1] !== '');\n\n            if (\\is_object($spec[0])) {\n                return BetterReflectionClass::createFromInstance($spec[0])\n                    ->getMethod($spec[1]);\n            }\n\n            return BetterReflectionClass::createFromName($spec[0])\n                ->getMethod($spec[1]);\n        }\n\n        if (\\is_string($spec)) {\n            return BetterReflectionFunction::createFromName($spec);\n        }\n\n        if ($spec instanceof Closure) {\n            return BetterReflectionFunction::createFromClosure($spec);\n        }\n\n        throw new InvalidArgumentException('Could not create reflection from the spec given'); // @codeCoverageIgnore\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getDeclaringClass(): ReflectionClass\n    {\n        return new ReflectionClass($this->className);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function isPrivate(): bool\n    {\n        return false;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function isPublic(): bool\n    {\n        return true;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function isFinal(): bool\n    {\n        return false;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function isInternal(): bool\n    {\n        return false;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function isAbstract(): bool\n    {\n        return false;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function isStatic(): bool\n    {\n        return $this->static;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getDocComment(): ?string\n    {\n        return $this->reflectionFunction->getDocComment() ?: null;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getName(): string\n    {\n        return $this->methodName;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getParameters(): array\n    {\n        return $this->parameters;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getReturnType(): ?ReflectionType\n    {\n        $type = $this->reflectionFunction->getReturnType();\n\n        if ($type instanceof ReflectionType) {\n            return $type; // @codeCoverageIgnore\n        }\n\n        return self::adaptType($type);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function isDeprecated(): TrinaryLogic\n    {\n        return TrinaryLogic::createFromBoolean(\n            $this->reflectionFunction->isDeprecated() ||\n            preg_match('/@deprecated/i', $this->getDocComment() ?: '')\n        );\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function isVariadic(): bool\n    {\n        return $this->reflectionFunction->isVariadic();\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getPrototype(): BuiltinMethodReflection\n    {\n        return $this;\n    }\n\n    public function getTentativeReturnType(): ?ReflectionType\n    {\n        return null;\n    }\n\n    public function returnsByReference(): TrinaryLogic\n    {\n        return TrinaryLogic::createNo();\n    }\n\n    private static function adaptType($type)\n    {\n        $method = method_exists(AdapterReflectionType::class, 'fromTypeOrNull')\n            ? 'fromTypeOrNull'\n            : 'fromReturnTypeOrNull'; // @codeCoverageIgnore\n\n        return AdapterReflectionType::$method($type);\n    }\n\n    private static function hasModernParser(): bool\n    {\n        static $modernParser = null;\n\n        if ($modernParser !== null) {\n            return $modernParser;\n        }\n\n        $modernParser = method_exists(AdapterReflectionType::class, 'fromTypeOrNull');\n\n        return $modernParser;\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/PHPStan/Macro.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\PHPStan;\n\nuse PHPStan\\BetterReflection\\Reflection\\Adapter;\nuse PHPStan\\Reflection\\Php\\BuiltinMethodReflection;\nuse ReflectionMethod;\n\n$method = new ReflectionMethod(BuiltinMethodReflection::class, 'getReflection');\n\nrequire $method->hasReturnType() && $method->getReturnType()->getName() === Adapter\\ReflectionMethod::class\n    ? __DIR__.'/../../../lazy/Carbon/PHPStan/AbstractMacroStatic.php'\n    : __DIR__.'/../../../lazy/Carbon/PHPStan/AbstractMacroBuiltin.php';\n\n$method = new ReflectionMethod(BuiltinMethodReflection::class, 'getFileName');\n\nrequire $method->hasReturnType()\n    ? __DIR__.'/../../../lazy/Carbon/PHPStan/MacroStrongType.php'\n    : __DIR__.'/../../../lazy/Carbon/PHPStan/MacroWeakType.php';\n\nfinal class Macro extends LazyMacro\n{\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/PHPStan/MacroExtension.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\PHPStan;\n\nuse PHPStan\\Reflection\\Assertions;\nuse PHPStan\\Reflection\\ClassReflection;\nuse PHPStan\\Reflection\\MethodReflection;\nuse PHPStan\\Reflection\\MethodsClassReflectionExtension;\nuse PHPStan\\Reflection\\Php\\PhpMethodReflectionFactory;\nuse PHPStan\\Reflection\\ReflectionProvider;\nuse PHPStan\\Type\\TypehintHelper;\n\n/**\n * Class MacroExtension.\n *\n * @codeCoverageIgnore Pure PHPStan wrapper.\n */\nfinal class MacroExtension implements MethodsClassReflectionExtension\n{\n    /**\n     * @var PhpMethodReflectionFactory\n     */\n    protected $methodReflectionFactory;\n\n    /**\n     * @var MacroScanner\n     */\n    protected $scanner;\n\n    /**\n     * Extension constructor.\n     *\n     * @param PhpMethodReflectionFactory $methodReflectionFactory\n     * @param ReflectionProvider         $reflectionProvider\n     */\n    public function __construct(\n        PhpMethodReflectionFactory $methodReflectionFactory,\n        ReflectionProvider $reflectionProvider\n    ) {\n        $this->scanner = new MacroScanner($reflectionProvider);\n        $this->methodReflectionFactory = $methodReflectionFactory;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function hasMethod(ClassReflection $classReflection, string $methodName): bool\n    {\n        return $this->scanner->hasMethod($classReflection->getName(), $methodName);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getMethod(ClassReflection $classReflection, string $methodName): MethodReflection\n    {\n        $builtinMacro = $this->scanner->getMethod($classReflection->getName(), $methodName);\n        $supportAssertions = class_exists(Assertions::class);\n\n        return $this->methodReflectionFactory->create(\n            $classReflection,\n            null,\n            $builtinMacro,\n            $classReflection->getActiveTemplateTypeMap(),\n            [],\n            TypehintHelper::decideTypeFromReflection($builtinMacro->getReturnType()),\n            null,\n            null,\n            $builtinMacro->isDeprecated()->yes(),\n            $builtinMacro->isInternal(),\n            $builtinMacro->isFinal(),\n            $supportAssertions ? null : $builtinMacro->getDocComment(),\n            $supportAssertions ? Assertions::createEmpty() : null,\n            null,\n            $builtinMacro->getDocComment(),\n            []\n        );\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/PHPStan/MacroScanner.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\PHPStan;\n\nuse Carbon\\CarbonInterface;\nuse PHPStan\\Reflection\\ReflectionProvider;\nuse ReflectionClass;\nuse ReflectionException;\n\nfinal class MacroScanner\n{\n    /**\n     * @var \\PHPStan\\Reflection\\ReflectionProvider\n     */\n    private $reflectionProvider;\n\n    /**\n     * MacroScanner constructor.\n     *\n     * @param \\PHPStan\\Reflection\\ReflectionProvider $reflectionProvider\n     */\n    public function __construct(ReflectionProvider $reflectionProvider)\n    {\n        $this->reflectionProvider = $reflectionProvider;\n    }\n\n    /**\n     * Return true if the given pair class-method is a Carbon macro.\n     *\n     * @param class-string $className\n     * @param string       $methodName\n     *\n     * @return bool\n     */\n    public function hasMethod(string $className, string $methodName): bool\n    {\n        $classReflection = $this->reflectionProvider->getClass($className);\n\n        if (\n            $classReflection->getName() !== CarbonInterface::class &&\n            !$classReflection->isSubclassOf(CarbonInterface::class)\n        ) {\n            return false;\n        }\n\n        return \\is_callable([$className, 'hasMacro']) &&\n            $className::hasMacro($methodName);\n    }\n\n    /**\n     * Return the Macro for a given pair class-method.\n     *\n     * @param class-string $className\n     * @param string       $methodName\n     *\n     * @throws ReflectionException\n     *\n     * @return Macro\n     */\n    public function getMethod(string $className, string $methodName): Macro\n    {\n        $reflectionClass = new ReflectionClass($className);\n        $property = $reflectionClass->getProperty('globalMacros');\n\n        $property->setAccessible(true);\n        $macro = $property->getValue()[$methodName];\n\n        return new Macro(\n            $className,\n            $methodName,\n            $macro\n        );\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Traits/Boundaries.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Traits;\n\nuse Carbon\\Exceptions\\UnknownUnitException;\n\n/**\n * Trait Boundaries.\n *\n * startOf, endOf and derived method for each unit.\n *\n * Depends on the following properties:\n *\n * @property int $year\n * @property int $month\n * @property int $daysInMonth\n * @property int $quarter\n *\n * Depends on the following methods:\n *\n * @method $this setTime(int $hour, int $minute, int $second = 0, int $microseconds = 0)\n * @method $this setDate(int $year, int $month, int $day)\n * @method $this addMonths(int $value = 1)\n */\ntrait Boundaries\n{\n    /**\n     * Resets the time to 00:00:00 start of day\n     *\n     * @example\n     * ```\n     * echo Carbon::parse('2018-07-25 12:45:16')->startOfDay();\n     * ```\n     *\n     * @return static\n     */\n    public function startOfDay()\n    {\n        return $this->setTime(0, 0, 0, 0);\n    }\n\n    /**\n     * Resets the time to 23:59:59.999999 end of day\n     *\n     * @example\n     * ```\n     * echo Carbon::parse('2018-07-25 12:45:16')->endOfDay();\n     * ```\n     *\n     * @return static\n     */\n    public function endOfDay()\n    {\n        return $this->setTime(static::HOURS_PER_DAY - 1, static::MINUTES_PER_HOUR - 1, static::SECONDS_PER_MINUTE - 1, static::MICROSECONDS_PER_SECOND - 1);\n    }\n\n    /**\n     * Resets the date to the first day of the month and the time to 00:00:00\n     *\n     * @example\n     * ```\n     * echo Carbon::parse('2018-07-25 12:45:16')->startOfMonth();\n     * ```\n     *\n     * @return static\n     */\n    public function startOfMonth()\n    {\n        return $this->setDate($this->year, $this->month, 1)->startOfDay();\n    }\n\n    /**\n     * Resets the date to end of the month and time to 23:59:59.999999\n     *\n     * @example\n     * ```\n     * echo Carbon::parse('2018-07-25 12:45:16')->endOfMonth();\n     * ```\n     *\n     * @return static\n     */\n    public function endOfMonth()\n    {\n        return $this->setDate($this->year, $this->month, $this->daysInMonth)->endOfDay();\n    }\n\n    /**\n     * Resets the date to the first day of the quarter and the time to 00:00:00\n     *\n     * @example\n     * ```\n     * echo Carbon::parse('2018-07-25 12:45:16')->startOfQuarter();\n     * ```\n     *\n     * @return static\n     */\n    public function startOfQuarter()\n    {\n        $month = ($this->quarter - 1) * static::MONTHS_PER_QUARTER + 1;\n\n        return $this->setDate($this->year, $month, 1)->startOfDay();\n    }\n\n    /**\n     * Resets the date to end of the quarter and time to 23:59:59.999999\n     *\n     * @example\n     * ```\n     * echo Carbon::parse('2018-07-25 12:45:16')->endOfQuarter();\n     * ```\n     *\n     * @return static\n     */\n    public function endOfQuarter()\n    {\n        return $this->startOfQuarter()->addMonths(static::MONTHS_PER_QUARTER - 1)->endOfMonth();\n    }\n\n    /**\n     * Resets the date to the first day of the year and the time to 00:00:00\n     *\n     * @example\n     * ```\n     * echo Carbon::parse('2018-07-25 12:45:16')->startOfYear();\n     * ```\n     *\n     * @return static\n     */\n    public function startOfYear()\n    {\n        return $this->setDate($this->year, 1, 1)->startOfDay();\n    }\n\n    /**\n     * Resets the date to end of the year and time to 23:59:59.999999\n     *\n     * @example\n     * ```\n     * echo Carbon::parse('2018-07-25 12:45:16')->endOfYear();\n     * ```\n     *\n     * @return static\n     */\n    public function endOfYear()\n    {\n        return $this->setDate($this->year, 12, 31)->endOfDay();\n    }\n\n    /**\n     * Resets the date to the first day of the decade and the time to 00:00:00\n     *\n     * @example\n     * ```\n     * echo Carbon::parse('2018-07-25 12:45:16')->startOfDecade();\n     * ```\n     *\n     * @return static\n     */\n    public function startOfDecade()\n    {\n        $year = $this->year - $this->year % static::YEARS_PER_DECADE;\n\n        return $this->setDate($year, 1, 1)->startOfDay();\n    }\n\n    /**\n     * Resets the date to end of the decade and time to 23:59:59.999999\n     *\n     * @example\n     * ```\n     * echo Carbon::parse('2018-07-25 12:45:16')->endOfDecade();\n     * ```\n     *\n     * @return static\n     */\n    public function endOfDecade()\n    {\n        $year = $this->year - $this->year % static::YEARS_PER_DECADE + static::YEARS_PER_DECADE - 1;\n\n        return $this->setDate($year, 12, 31)->endOfDay();\n    }\n\n    /**\n     * Resets the date to the first day of the century and the time to 00:00:00\n     *\n     * @example\n     * ```\n     * echo Carbon::parse('2018-07-25 12:45:16')->startOfCentury();\n     * ```\n     *\n     * @return static\n     */\n    public function startOfCentury()\n    {\n        $year = $this->year - ($this->year - 1) % static::YEARS_PER_CENTURY;\n\n        return $this->setDate($year, 1, 1)->startOfDay();\n    }\n\n    /**\n     * Resets the date to end of the century and time to 23:59:59.999999\n     *\n     * @example\n     * ```\n     * echo Carbon::parse('2018-07-25 12:45:16')->endOfCentury();\n     * ```\n     *\n     * @return static\n     */\n    public function endOfCentury()\n    {\n        $year = $this->year - 1 - ($this->year - 1) % static::YEARS_PER_CENTURY + static::YEARS_PER_CENTURY;\n\n        return $this->setDate($year, 12, 31)->endOfDay();\n    }\n\n    /**\n     * Resets the date to the first day of the millennium and the time to 00:00:00\n     *\n     * @example\n     * ```\n     * echo Carbon::parse('2018-07-25 12:45:16')->startOfMillennium();\n     * ```\n     *\n     * @return static\n     */\n    public function startOfMillennium()\n    {\n        $year = $this->year - ($this->year - 1) % static::YEARS_PER_MILLENNIUM;\n\n        return $this->setDate($year, 1, 1)->startOfDay();\n    }\n\n    /**\n     * Resets the date to end of the millennium and time to 23:59:59.999999\n     *\n     * @example\n     * ```\n     * echo Carbon::parse('2018-07-25 12:45:16')->endOfMillennium();\n     * ```\n     *\n     * @return static\n     */\n    public function endOfMillennium()\n    {\n        $year = $this->year - 1 - ($this->year - 1) % static::YEARS_PER_MILLENNIUM + static::YEARS_PER_MILLENNIUM;\n\n        return $this->setDate($year, 12, 31)->endOfDay();\n    }\n\n    /**\n     * Resets the date to the first day of week (defined in $weekStartsAt) and the time to 00:00:00\n     *\n     * @example\n     * ```\n     * echo Carbon::parse('2018-07-25 12:45:16')->startOfWeek() . \"\\n\";\n     * echo Carbon::parse('2018-07-25 12:45:16')->locale('ar')->startOfWeek() . \"\\n\";\n     * echo Carbon::parse('2018-07-25 12:45:16')->startOfWeek(Carbon::SUNDAY) . \"\\n\";\n     * ```\n     *\n     * @param int $weekStartsAt optional start allow you to specify the day of week to use to start the week\n     *\n     * @return static\n     */\n    public function startOfWeek($weekStartsAt = null)\n    {\n        return $this->subDays((7 + $this->dayOfWeek - ($weekStartsAt ?? $this->firstWeekDay)) % 7)->startOfDay();\n    }\n\n    /**\n     * Resets the date to end of week (defined in $weekEndsAt) and time to 23:59:59.999999\n     *\n     * @example\n     * ```\n     * echo Carbon::parse('2018-07-25 12:45:16')->endOfWeek() . \"\\n\";\n     * echo Carbon::parse('2018-07-25 12:45:16')->locale('ar')->endOfWeek() . \"\\n\";\n     * echo Carbon::parse('2018-07-25 12:45:16')->endOfWeek(Carbon::SATURDAY) . \"\\n\";\n     * ```\n     *\n     * @param int $weekEndsAt optional start allow you to specify the day of week to use to end the week\n     *\n     * @return static\n     */\n    public function endOfWeek($weekEndsAt = null)\n    {\n        return $this->addDays((7 - $this->dayOfWeek + ($weekEndsAt ?? $this->lastWeekDay)) % 7)->endOfDay();\n    }\n\n    /**\n     * Modify to start of current hour, minutes and seconds become 0\n     *\n     * @example\n     * ```\n     * echo Carbon::parse('2018-07-25 12:45:16')->startOfHour();\n     * ```\n     *\n     * @return static\n     */\n    public function startOfHour()\n    {\n        return $this->setTime($this->hour, 0, 0, 0);\n    }\n\n    /**\n     * Modify to end of current hour, minutes and seconds become 59\n     *\n     * @example\n     * ```\n     * echo Carbon::parse('2018-07-25 12:45:16')->endOfHour();\n     * ```\n     *\n     * @return static\n     */\n    public function endOfHour()\n    {\n        return $this->setTime($this->hour, static::MINUTES_PER_HOUR - 1, static::SECONDS_PER_MINUTE - 1, static::MICROSECONDS_PER_SECOND - 1);\n    }\n\n    /**\n     * Modify to start of current minute, seconds become 0\n     *\n     * @example\n     * ```\n     * echo Carbon::parse('2018-07-25 12:45:16')->startOfMinute();\n     * ```\n     *\n     * @return static\n     */\n    public function startOfMinute()\n    {\n        return $this->setTime($this->hour, $this->minute, 0, 0);\n    }\n\n    /**\n     * Modify to end of current minute, seconds become 59\n     *\n     * @example\n     * ```\n     * echo Carbon::parse('2018-07-25 12:45:16')->endOfMinute();\n     * ```\n     *\n     * @return static\n     */\n    public function endOfMinute()\n    {\n        return $this->setTime($this->hour, $this->minute, static::SECONDS_PER_MINUTE - 1, static::MICROSECONDS_PER_SECOND - 1);\n    }\n\n    /**\n     * Modify to start of current second, microseconds become 0\n     *\n     * @example\n     * ```\n     * echo Carbon::parse('2018-07-25 12:45:16.334455')\n     *   ->startOfSecond()\n     *   ->format('H:i:s.u');\n     * ```\n     *\n     * @return static\n     */\n    public function startOfSecond()\n    {\n        return $this->setTime($this->hour, $this->minute, $this->second, 0);\n    }\n\n    /**\n     * Modify to end of current second, microseconds become 999999\n     *\n     * @example\n     * ```\n     * echo Carbon::parse('2018-07-25 12:45:16.334455')\n     *   ->endOfSecond()\n     *   ->format('H:i:s.u');\n     * ```\n     *\n     * @return static\n     */\n    public function endOfSecond()\n    {\n        return $this->setTime($this->hour, $this->minute, $this->second, static::MICROSECONDS_PER_SECOND - 1);\n    }\n\n    /**\n     * Modify to start of current given unit.\n     *\n     * @example\n     * ```\n     * echo Carbon::parse('2018-07-25 12:45:16.334455')\n     *   ->startOf('month')\n     *   ->endOf('week', Carbon::FRIDAY);\n     * ```\n     *\n     * @param string            $unit\n     * @param array<int, mixed> $params\n     *\n     * @return static\n     */\n    public function startOf($unit, ...$params)\n    {\n        $ucfUnit = ucfirst(static::singularUnit($unit));\n        $method = \"startOf$ucfUnit\";\n        if (!method_exists($this, $method)) {\n            throw new UnknownUnitException($unit);\n        }\n\n        return $this->$method(...$params);\n    }\n\n    /**\n     * Modify to end of current given unit.\n     *\n     * @example\n     * ```\n     * echo Carbon::parse('2018-07-25 12:45:16.334455')\n     *   ->startOf('month')\n     *   ->endOf('week', Carbon::FRIDAY);\n     * ```\n     *\n     * @param string            $unit\n     * @param array<int, mixed> $params\n     *\n     * @return static\n     */\n    public function endOf($unit, ...$params)\n    {\n        $ucfUnit = ucfirst(static::singularUnit($unit));\n        $method = \"endOf$ucfUnit\";\n        if (!method_exists($this, $method)) {\n            throw new UnknownUnitException($unit);\n        }\n\n        return $this->$method(...$params);\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Traits/Cast.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Traits;\n\nuse Carbon\\Exceptions\\InvalidCastException;\nuse DateTimeInterface;\n\n/**\n * Trait Cast.\n *\n * Utils to cast into an other class.\n */\ntrait Cast\n{\n    /**\n     * Cast the current instance into the given class.\n     *\n     * @param string $className The $className::instance() method will be called to cast the current object.\n     *\n     * @return DateTimeInterface\n     */\n    public function cast(string $className)\n    {\n        if (!method_exists($className, 'instance')) {\n            if (is_a($className, DateTimeInterface::class, true)) {\n                return new $className($this->rawFormat('Y-m-d H:i:s.u'), $this->getTimezone());\n            }\n\n            throw new InvalidCastException(\"$className has not the instance() method needed to cast the date.\");\n        }\n\n        return $className::instance($this);\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Traits/Comparison.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Traits;\n\nuse BadMethodCallException;\nuse Carbon\\CarbonInterface;\nuse Carbon\\Exceptions\\BadComparisonUnitException;\nuse InvalidArgumentException;\n\n/**\n * Trait Comparison.\n *\n * Comparison utils and testers. All the following methods return booleans.\n * nowWithSameTz\n *\n * Depends on the following methods:\n *\n * @method static        resolveCarbon($date)\n * @method static        copy()\n * @method static        nowWithSameTz()\n * @method static static yesterday($timezone = null)\n * @method static static tomorrow($timezone = null)\n */\ntrait Comparison\n{\n    /** @var bool */\n    protected $endOfTime = false;\n\n    /** @var bool */\n    protected $startOfTime = false;\n\n    /**\n     * Determines if the instance is equal to another\n     *\n     * @example\n     * ```\n     * Carbon::parse('2018-07-25 12:45:16')->eq('2018-07-25 12:45:16'); // true\n     * Carbon::parse('2018-07-25 12:45:16')->eq(Carbon::parse('2018-07-25 12:45:16')); // true\n     * Carbon::parse('2018-07-25 12:45:16')->eq('2018-07-25 12:45:17'); // false\n     * ```\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date\n     *\n     * @see equalTo()\n     *\n     * @return bool\n     */\n    public function eq($date): bool\n    {\n        return $this->equalTo($date);\n    }\n\n    /**\n     * Determines if the instance is equal to another\n     *\n     * @example\n     * ```\n     * Carbon::parse('2018-07-25 12:45:16')->equalTo('2018-07-25 12:45:16'); // true\n     * Carbon::parse('2018-07-25 12:45:16')->equalTo(Carbon::parse('2018-07-25 12:45:16')); // true\n     * Carbon::parse('2018-07-25 12:45:16')->equalTo('2018-07-25 12:45:17'); // false\n     * ```\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date\n     *\n     * @return bool\n     */\n    public function equalTo($date): bool\n    {\n        $this->discourageNull($date);\n        $this->discourageBoolean($date);\n\n        return $this == $this->resolveCarbon($date);\n    }\n\n    /**\n     * Determines if the instance is not equal to another\n     *\n     * @example\n     * ```\n     * Carbon::parse('2018-07-25 12:45:16')->ne('2018-07-25 12:45:16'); // false\n     * Carbon::parse('2018-07-25 12:45:16')->ne(Carbon::parse('2018-07-25 12:45:16')); // false\n     * Carbon::parse('2018-07-25 12:45:16')->ne('2018-07-25 12:45:17'); // true\n     * ```\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date\n     *\n     * @see notEqualTo()\n     *\n     * @return bool\n     */\n    public function ne($date): bool\n    {\n        return $this->notEqualTo($date);\n    }\n\n    /**\n     * Determines if the instance is not equal to another\n     *\n     * @example\n     * ```\n     * Carbon::parse('2018-07-25 12:45:16')->notEqualTo('2018-07-25 12:45:16'); // false\n     * Carbon::parse('2018-07-25 12:45:16')->notEqualTo(Carbon::parse('2018-07-25 12:45:16')); // false\n     * Carbon::parse('2018-07-25 12:45:16')->notEqualTo('2018-07-25 12:45:17'); // true\n     * ```\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date\n     *\n     * @return bool\n     */\n    public function notEqualTo($date): bool\n    {\n        return !$this->equalTo($date);\n    }\n\n    /**\n     * Determines if the instance is greater (after) than another\n     *\n     * @example\n     * ```\n     * Carbon::parse('2018-07-25 12:45:16')->gt('2018-07-25 12:45:15'); // true\n     * Carbon::parse('2018-07-25 12:45:16')->gt('2018-07-25 12:45:16'); // false\n     * Carbon::parse('2018-07-25 12:45:16')->gt('2018-07-25 12:45:17'); // false\n     * ```\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date\n     *\n     * @see greaterThan()\n     *\n     * @return bool\n     */\n    public function gt($date): bool\n    {\n        return $this->greaterThan($date);\n    }\n\n    /**\n     * Determines if the instance is greater (after) than another\n     *\n     * @example\n     * ```\n     * Carbon::parse('2018-07-25 12:45:16')->greaterThan('2018-07-25 12:45:15'); // true\n     * Carbon::parse('2018-07-25 12:45:16')->greaterThan('2018-07-25 12:45:16'); // false\n     * Carbon::parse('2018-07-25 12:45:16')->greaterThan('2018-07-25 12:45:17'); // false\n     * ```\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date\n     *\n     * @return bool\n     */\n    public function greaterThan($date): bool\n    {\n        $this->discourageNull($date);\n        $this->discourageBoolean($date);\n\n        return $this > $this->resolveCarbon($date);\n    }\n\n    /**\n     * Determines if the instance is greater (after) than another\n     *\n     * @example\n     * ```\n     * Carbon::parse('2018-07-25 12:45:16')->isAfter('2018-07-25 12:45:15'); // true\n     * Carbon::parse('2018-07-25 12:45:16')->isAfter('2018-07-25 12:45:16'); // false\n     * Carbon::parse('2018-07-25 12:45:16')->isAfter('2018-07-25 12:45:17'); // false\n     * ```\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date\n     *\n     * @see greaterThan()\n     *\n     * @return bool\n     */\n    public function isAfter($date): bool\n    {\n        return $this->greaterThan($date);\n    }\n\n    /**\n     * Determines if the instance is greater (after) than or equal to another\n     *\n     * @example\n     * ```\n     * Carbon::parse('2018-07-25 12:45:16')->gte('2018-07-25 12:45:15'); // true\n     * Carbon::parse('2018-07-25 12:45:16')->gte('2018-07-25 12:45:16'); // true\n     * Carbon::parse('2018-07-25 12:45:16')->gte('2018-07-25 12:45:17'); // false\n     * ```\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date\n     *\n     * @see greaterThanOrEqualTo()\n     *\n     * @return bool\n     */\n    public function gte($date): bool\n    {\n        return $this->greaterThanOrEqualTo($date);\n    }\n\n    /**\n     * Determines if the instance is greater (after) than or equal to another\n     *\n     * @example\n     * ```\n     * Carbon::parse('2018-07-25 12:45:16')->greaterThanOrEqualTo('2018-07-25 12:45:15'); // true\n     * Carbon::parse('2018-07-25 12:45:16')->greaterThanOrEqualTo('2018-07-25 12:45:16'); // true\n     * Carbon::parse('2018-07-25 12:45:16')->greaterThanOrEqualTo('2018-07-25 12:45:17'); // false\n     * ```\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date\n     *\n     * @return bool\n     */\n    public function greaterThanOrEqualTo($date): bool\n    {\n        $this->discourageNull($date);\n        $this->discourageBoolean($date);\n\n        return $this >= $this->resolveCarbon($date);\n    }\n\n    /**\n     * Determines if the instance is less (before) than another\n     *\n     * @example\n     * ```\n     * Carbon::parse('2018-07-25 12:45:16')->lt('2018-07-25 12:45:15'); // false\n     * Carbon::parse('2018-07-25 12:45:16')->lt('2018-07-25 12:45:16'); // false\n     * Carbon::parse('2018-07-25 12:45:16')->lt('2018-07-25 12:45:17'); // true\n     * ```\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date\n     *\n     * @see lessThan()\n     *\n     * @return bool\n     */\n    public function lt($date): bool\n    {\n        return $this->lessThan($date);\n    }\n\n    /**\n     * Determines if the instance is less (before) than another\n     *\n     * @example\n     * ```\n     * Carbon::parse('2018-07-25 12:45:16')->lessThan('2018-07-25 12:45:15'); // false\n     * Carbon::parse('2018-07-25 12:45:16')->lessThan('2018-07-25 12:45:16'); // false\n     * Carbon::parse('2018-07-25 12:45:16')->lessThan('2018-07-25 12:45:17'); // true\n     * ```\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date\n     *\n     * @return bool\n     */\n    public function lessThan($date): bool\n    {\n        $this->discourageNull($date);\n        $this->discourageBoolean($date);\n\n        return $this < $this->resolveCarbon($date);\n    }\n\n    /**\n     * Determines if the instance is less (before) than another\n     *\n     * @example\n     * ```\n     * Carbon::parse('2018-07-25 12:45:16')->isBefore('2018-07-25 12:45:15'); // false\n     * Carbon::parse('2018-07-25 12:45:16')->isBefore('2018-07-25 12:45:16'); // false\n     * Carbon::parse('2018-07-25 12:45:16')->isBefore('2018-07-25 12:45:17'); // true\n     * ```\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date\n     *\n     * @see lessThan()\n     *\n     * @return bool\n     */\n    public function isBefore($date): bool\n    {\n        return $this->lessThan($date);\n    }\n\n    /**\n     * Determines if the instance is less (before) or equal to another\n     *\n     * @example\n     * ```\n     * Carbon::parse('2018-07-25 12:45:16')->lte('2018-07-25 12:45:15'); // false\n     * Carbon::parse('2018-07-25 12:45:16')->lte('2018-07-25 12:45:16'); // true\n     * Carbon::parse('2018-07-25 12:45:16')->lte('2018-07-25 12:45:17'); // true\n     * ```\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date\n     *\n     * @see lessThanOrEqualTo()\n     *\n     * @return bool\n     */\n    public function lte($date): bool\n    {\n        return $this->lessThanOrEqualTo($date);\n    }\n\n    /**\n     * Determines if the instance is less (before) or equal to another\n     *\n     * @example\n     * ```\n     * Carbon::parse('2018-07-25 12:45:16')->lessThanOrEqualTo('2018-07-25 12:45:15'); // false\n     * Carbon::parse('2018-07-25 12:45:16')->lessThanOrEqualTo('2018-07-25 12:45:16'); // true\n     * Carbon::parse('2018-07-25 12:45:16')->lessThanOrEqualTo('2018-07-25 12:45:17'); // true\n     * ```\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date\n     *\n     * @return bool\n     */\n    public function lessThanOrEqualTo($date): bool\n    {\n        $this->discourageNull($date);\n        $this->discourageBoolean($date);\n\n        return $this <= $this->resolveCarbon($date);\n    }\n\n    /**\n     * Determines if the instance is between two others.\n     *\n     * The third argument allow you to specify if bounds are included or not (true by default)\n     * but for when you including/excluding bounds may produce different results in your application,\n     * we recommend to use the explicit methods ->betweenIncluded() or ->betweenExcluded() instead.\n     *\n     * @example\n     * ```\n     * Carbon::parse('2018-07-25')->between('2018-07-14', '2018-08-01'); // true\n     * Carbon::parse('2018-07-25')->between('2018-08-01', '2018-08-20'); // false\n     * Carbon::parse('2018-07-25')->between('2018-07-25', '2018-08-01'); // true\n     * Carbon::parse('2018-07-25')->between('2018-07-25', '2018-08-01', false); // false\n     * ```\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date1\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date2\n     * @param bool                                    $equal Indicates if an equal to comparison should be done\n     *\n     * @return bool\n     */\n    public function between($date1, $date2, $equal = true): bool\n    {\n        $date1 = $this->resolveCarbon($date1);\n        $date2 = $this->resolveCarbon($date2);\n\n        if ($date1->greaterThan($date2)) {\n            [$date1, $date2] = [$date2, $date1];\n        }\n\n        if ($equal) {\n            return $this >= $date1 && $this <= $date2;\n        }\n\n        return $this > $date1 && $this < $date2;\n    }\n\n    /**\n     * Determines if the instance is between two others, bounds included.\n     *\n     * @example\n     * ```\n     * Carbon::parse('2018-07-25')->betweenIncluded('2018-07-14', '2018-08-01'); // true\n     * Carbon::parse('2018-07-25')->betweenIncluded('2018-08-01', '2018-08-20'); // false\n     * Carbon::parse('2018-07-25')->betweenIncluded('2018-07-25', '2018-08-01'); // true\n     * ```\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date1\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date2\n     *\n     * @return bool\n     */\n    public function betweenIncluded($date1, $date2): bool\n    {\n        return $this->between($date1, $date2, true);\n    }\n\n    /**\n     * Determines if the instance is between two others, bounds excluded.\n     *\n     * @example\n     * ```\n     * Carbon::parse('2018-07-25')->betweenExcluded('2018-07-14', '2018-08-01'); // true\n     * Carbon::parse('2018-07-25')->betweenExcluded('2018-08-01', '2018-08-20'); // false\n     * Carbon::parse('2018-07-25')->betweenExcluded('2018-07-25', '2018-08-01'); // false\n     * ```\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date1\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date2\n     *\n     * @return bool\n     */\n    public function betweenExcluded($date1, $date2): bool\n    {\n        return $this->between($date1, $date2, false);\n    }\n\n    /**\n     * Determines if the instance is between two others\n     *\n     * @example\n     * ```\n     * Carbon::parse('2018-07-25')->isBetween('2018-07-14', '2018-08-01'); // true\n     * Carbon::parse('2018-07-25')->isBetween('2018-08-01', '2018-08-20'); // false\n     * Carbon::parse('2018-07-25')->isBetween('2018-07-25', '2018-08-01'); // true\n     * Carbon::parse('2018-07-25')->isBetween('2018-07-25', '2018-08-01', false); // false\n     * ```\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date1\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date2\n     * @param bool                                    $equal Indicates if an equal to comparison should be done\n     *\n     * @return bool\n     */\n    public function isBetween($date1, $date2, $equal = true): bool\n    {\n        return $this->between($date1, $date2, $equal);\n    }\n\n    /**\n     * Determines if the instance is a weekday.\n     *\n     * @example\n     * ```\n     * Carbon::parse('2019-07-14')->isWeekday(); // false\n     * Carbon::parse('2019-07-15')->isWeekday(); // true\n     * ```\n     *\n     * @return bool\n     */\n    public function isWeekday()\n    {\n        return !$this->isWeekend();\n    }\n\n    /**\n     * Determines if the instance is a weekend day.\n     *\n     * @example\n     * ```\n     * Carbon::parse('2019-07-14')->isWeekend(); // true\n     * Carbon::parse('2019-07-15')->isWeekend(); // false\n     * ```\n     *\n     * @return bool\n     */\n    public function isWeekend()\n    {\n        return \\in_array($this->dayOfWeek, static::$weekendDays, true);\n    }\n\n    /**\n     * Determines if the instance is yesterday.\n     *\n     * @example\n     * ```\n     * Carbon::yesterday()->isYesterday(); // true\n     * Carbon::tomorrow()->isYesterday(); // false\n     * ```\n     *\n     * @return bool\n     */\n    public function isYesterday()\n    {\n        return $this->toDateString() === static::yesterday($this->getTimezone())->toDateString();\n    }\n\n    /**\n     * Determines if the instance is today.\n     *\n     * @example\n     * ```\n     * Carbon::today()->isToday(); // true\n     * Carbon::tomorrow()->isToday(); // false\n     * ```\n     *\n     * @return bool\n     */\n    public function isToday()\n    {\n        return $this->toDateString() === $this->nowWithSameTz()->toDateString();\n    }\n\n    /**\n     * Determines if the instance is tomorrow.\n     *\n     * @example\n     * ```\n     * Carbon::tomorrow()->isTomorrow(); // true\n     * Carbon::yesterday()->isTomorrow(); // false\n     * ```\n     *\n     * @return bool\n     */\n    public function isTomorrow()\n    {\n        return $this->toDateString() === static::tomorrow($this->getTimezone())->toDateString();\n    }\n\n    /**\n     * Determines if the instance is in the future, ie. greater (after) than now.\n     *\n     * @example\n     * ```\n     * Carbon::now()->addHours(5)->isFuture(); // true\n     * Carbon::now()->subHours(5)->isFuture(); // false\n     * ```\n     *\n     * @return bool\n     */\n    public function isFuture()\n    {\n        return $this->greaterThan($this->nowWithSameTz());\n    }\n\n    /**\n     * Determines if the instance is in the past, ie. less (before) than now.\n     *\n     * @example\n     * ```\n     * Carbon::now()->subHours(5)->isPast(); // true\n     * Carbon::now()->addHours(5)->isPast(); // false\n     * ```\n     *\n     * @return bool\n     */\n    public function isPast()\n    {\n        return $this->lessThan($this->nowWithSameTz());\n    }\n\n    /**\n     * Determines if the instance is a leap year.\n     *\n     * @example\n     * ```\n     * Carbon::parse('2020-01-01')->isLeapYear(); // true\n     * Carbon::parse('2019-01-01')->isLeapYear(); // false\n     * ```\n     *\n     * @return bool\n     */\n    public function isLeapYear()\n    {\n        return $this->rawFormat('L') === '1';\n    }\n\n    /**\n     * Determines if the instance is a long year (using calendar year).\n     *\n     * ⚠️ This method completely ignores month and day to use the numeric year number,\n     * it's not correct if the exact date matters. For instance as `2019-12-30` is already\n     * in the first week of the 2020 year, if you want to know from this date if ISO week\n     * year 2020 is a long year, use `isLongIsoYear` instead.\n     *\n     * @example\n     * ```\n     * Carbon::create(2015)->isLongYear(); // true\n     * Carbon::create(2016)->isLongYear(); // false\n     * ```\n     *\n     * @see https://en.wikipedia.org/wiki/ISO_8601#Week_dates\n     *\n     * @return bool\n     */\n    public function isLongYear()\n    {\n        return static::create($this->year, 12, 28, 0, 0, 0, $this->tz)->weekOfYear === 53;\n    }\n\n    /**\n     * Determines if the instance is a long year (using ISO 8601 year).\n     *\n     * @example\n     * ```\n     * Carbon::parse('2015-01-01')->isLongIsoYear(); // true\n     * Carbon::parse('2016-01-01')->isLongIsoYear(); // true\n     * Carbon::parse('2016-01-03')->isLongIsoYear(); // false\n     * Carbon::parse('2019-12-29')->isLongIsoYear(); // false\n     * Carbon::parse('2019-12-30')->isLongIsoYear(); // true\n     * ```\n     *\n     * @see https://en.wikipedia.org/wiki/ISO_8601#Week_dates\n     *\n     * @return bool\n     */\n    public function isLongIsoYear()\n    {\n        return static::create($this->isoWeekYear, 12, 28, 0, 0, 0, $this->tz)->weekOfYear === 53;\n    }\n\n    /**\n     * Compares the formatted values of the two dates.\n     *\n     * @example\n     * ```\n     * Carbon::parse('2019-06-13')->isSameAs('Y-d', Carbon::parse('2019-12-13')); // true\n     * Carbon::parse('2019-06-13')->isSameAs('Y-d', Carbon::parse('2019-06-14')); // false\n     * ```\n     *\n     * @param string                                        $format date formats to compare.\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|string|null $date   instance to compare with or null to use current day.\n     *\n     * @return bool\n     */\n    public function isSameAs($format, $date = null)\n    {\n        return $this->rawFormat($format) === $this->resolveCarbon($date)->rawFormat($format);\n    }\n\n    /**\n     * Determines if the instance is in the current unit given.\n     *\n     * @example\n     * ```\n     * Carbon::parse('2019-01-13')->isSameUnit('year', Carbon::parse('2019-12-25')); // true\n     * Carbon::parse('2018-12-13')->isSameUnit('year', Carbon::parse('2019-12-25')); // false\n     * ```\n     *\n     * @param string                                 $unit singular unit string\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|null $date instance to compare with or null to use current day.\n     *\n     * @throws BadComparisonUnitException\n     *\n     * @return bool\n     */\n    public function isSameUnit($unit, $date = null)\n    {\n        $units = [\n            // @call isSameUnit\n            'year' => 'Y',\n            // @call isSameUnit\n            'week' => 'o-W',\n            // @call isSameUnit\n            'day' => 'Y-m-d',\n            // @call isSameUnit\n            'hour' => 'Y-m-d H',\n            // @call isSameUnit\n            'minute' => 'Y-m-d H:i',\n            // @call isSameUnit\n            'second' => 'Y-m-d H:i:s',\n            // @call isSameUnit\n            'micro' => 'Y-m-d H:i:s.u',\n            // @call isSameUnit\n            'microsecond' => 'Y-m-d H:i:s.u',\n        ];\n\n        if (isset($units[$unit])) {\n            return $this->isSameAs($units[$unit], $date);\n        }\n\n        if (isset($this->$unit)) {\n            return $this->resolveCarbon($date)->$unit === $this->$unit;\n        }\n\n        if ($this->localStrictModeEnabled ?? static::isStrictModeEnabled()) {\n            throw new BadComparisonUnitException($unit);\n        }\n\n        return false;\n    }\n\n    /**\n     * Determines if the instance is in the current unit given.\n     *\n     * @example\n     * ```\n     * Carbon::now()->isCurrentUnit('hour'); // true\n     * Carbon::now()->subHours(2)->isCurrentUnit('hour'); // false\n     * ```\n     *\n     * @param string $unit The unit to test.\n     *\n     * @throws BadMethodCallException\n     *\n     * @return bool\n     */\n    public function isCurrentUnit($unit)\n    {\n        return $this->{'isSame'.ucfirst($unit)}();\n    }\n\n    /**\n     * Checks if the passed in date is in the same quarter as the instance quarter (and year if needed).\n     *\n     * @example\n     * ```\n     * Carbon::parse('2019-01-12')->isSameQuarter(Carbon::parse('2019-03-01')); // true\n     * Carbon::parse('2019-01-12')->isSameQuarter(Carbon::parse('2019-04-01')); // false\n     * Carbon::parse('2019-01-12')->isSameQuarter(Carbon::parse('2018-03-01')); // false\n     * Carbon::parse('2019-01-12')->isSameQuarter(Carbon::parse('2018-03-01'), false); // true\n     * ```\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|string|null $date       The instance to compare with or null to use current day.\n     * @param bool                                          $ofSameYear Check if it is the same month in the same year.\n     *\n     * @return bool\n     */\n    public function isSameQuarter($date = null, $ofSameYear = true)\n    {\n        $date = $this->resolveCarbon($date);\n\n        return $this->quarter === $date->quarter && (!$ofSameYear || $this->isSameYear($date));\n    }\n\n    /**\n     * Checks if the passed in date is in the same month as the instance´s month.\n     *\n     * @example\n     * ```\n     * Carbon::parse('2019-01-12')->isSameMonth(Carbon::parse('2019-01-01')); // true\n     * Carbon::parse('2019-01-12')->isSameMonth(Carbon::parse('2019-02-01')); // false\n     * Carbon::parse('2019-01-12')->isSameMonth(Carbon::parse('2018-01-01')); // false\n     * Carbon::parse('2019-01-12')->isSameMonth(Carbon::parse('2018-01-01'), false); // true\n     * ```\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|null $date       The instance to compare with or null to use the current date.\n     * @param bool                                   $ofSameYear Check if it is the same month in the same year.\n     *\n     * @return bool\n     */\n    public function isSameMonth($date = null, $ofSameYear = true)\n    {\n        return $this->isSameAs($ofSameYear ? 'Y-m' : 'm', $date);\n    }\n\n    /**\n     * Checks if this day is a specific day of the week.\n     *\n     * @example\n     * ```\n     * Carbon::parse('2019-07-17')->isDayOfWeek(Carbon::WEDNESDAY); // true\n     * Carbon::parse('2019-07-17')->isDayOfWeek(Carbon::FRIDAY); // false\n     * Carbon::parse('2019-07-17')->isDayOfWeek('Wednesday'); // true\n     * Carbon::parse('2019-07-17')->isDayOfWeek('Friday'); // false\n     * ```\n     *\n     * @param int $dayOfWeek\n     *\n     * @return bool\n     */\n    public function isDayOfWeek($dayOfWeek)\n    {\n        if (\\is_string($dayOfWeek) && \\defined($constant = static::class.'::'.strtoupper($dayOfWeek))) {\n            $dayOfWeek = \\constant($constant);\n        }\n\n        return $this->dayOfWeek === $dayOfWeek;\n    }\n\n    /**\n     * Check if its the birthday. Compares the date/month values of the two dates.\n     *\n     * @example\n     * ```\n     * Carbon::now()->subYears(5)->isBirthday(); // true\n     * Carbon::now()->subYears(5)->subDay()->isBirthday(); // false\n     * Carbon::parse('2019-06-05')->isBirthday(Carbon::parse('2001-06-05')); // true\n     * Carbon::parse('2019-06-05')->isBirthday(Carbon::parse('2001-06-06')); // false\n     * ```\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|null $date The instance to compare with or null to use current day.\n     *\n     * @return bool\n     */\n    public function isBirthday($date = null)\n    {\n        return $this->isSameAs('md', $date);\n    }\n\n    /**\n     * Check if today is the last day of the Month\n     *\n     * @example\n     * ```\n     * Carbon::parse('2019-02-28')->isLastOfMonth(); // true\n     * Carbon::parse('2019-03-28')->isLastOfMonth(); // false\n     * Carbon::parse('2019-03-30')->isLastOfMonth(); // false\n     * Carbon::parse('2019-03-31')->isLastOfMonth(); // true\n     * Carbon::parse('2019-04-30')->isLastOfMonth(); // true\n     * ```\n     *\n     * @return bool\n     */\n    public function isLastOfMonth()\n    {\n        return $this->day === $this->daysInMonth;\n    }\n\n    /**\n     * Check if the instance is start of day / midnight.\n     *\n     * @example\n     * ```\n     * Carbon::parse('2019-02-28 00:00:00')->isStartOfDay(); // true\n     * Carbon::parse('2019-02-28 00:00:00.999999')->isStartOfDay(); // true\n     * Carbon::parse('2019-02-28 00:00:01')->isStartOfDay(); // false\n     * Carbon::parse('2019-02-28 00:00:00.000000')->isStartOfDay(true); // true\n     * Carbon::parse('2019-02-28 00:00:00.000012')->isStartOfDay(true); // false\n     * ```\n     *\n     * @param bool $checkMicroseconds check time at microseconds precision\n     *\n     * @return bool\n     */\n    public function isStartOfDay($checkMicroseconds = false)\n    {\n        /* @var CarbonInterface $this */\n        return $checkMicroseconds\n            ? $this->rawFormat('H:i:s.u') === '00:00:00.000000'\n            : $this->rawFormat('H:i:s') === '00:00:00';\n    }\n\n    /**\n     * Check if the instance is end of day.\n     *\n     * @example\n     * ```\n     * Carbon::parse('2019-02-28 23:59:59.999999')->isEndOfDay(); // true\n     * Carbon::parse('2019-02-28 23:59:59.123456')->isEndOfDay(); // true\n     * Carbon::parse('2019-02-28 23:59:59')->isEndOfDay(); // true\n     * Carbon::parse('2019-02-28 23:59:58.999999')->isEndOfDay(); // false\n     * Carbon::parse('2019-02-28 23:59:59.999999')->isEndOfDay(true); // true\n     * Carbon::parse('2019-02-28 23:59:59.123456')->isEndOfDay(true); // false\n     * Carbon::parse('2019-02-28 23:59:59')->isEndOfDay(true); // false\n     * ```\n     *\n     * @param bool $checkMicroseconds check time at microseconds precision\n     *\n     * @return bool\n     */\n    public function isEndOfDay($checkMicroseconds = false)\n    {\n        /* @var CarbonInterface $this */\n        return $checkMicroseconds\n            ? $this->rawFormat('H:i:s.u') === '23:59:59.999999'\n            : $this->rawFormat('H:i:s') === '23:59:59';\n    }\n\n    /**\n     * Check if the instance is start of day / midnight.\n     *\n     * @example\n     * ```\n     * Carbon::parse('2019-02-28 00:00:00')->isMidnight(); // true\n     * Carbon::parse('2019-02-28 00:00:00.999999')->isMidnight(); // true\n     * Carbon::parse('2019-02-28 00:00:01')->isMidnight(); // false\n     * ```\n     *\n     * @return bool\n     */\n    public function isMidnight()\n    {\n        return $this->isStartOfDay();\n    }\n\n    /**\n     * Check if the instance is midday.\n     *\n     * @example\n     * ```\n     * Carbon::parse('2019-02-28 11:59:59.999999')->isMidday(); // false\n     * Carbon::parse('2019-02-28 12:00:00')->isMidday(); // true\n     * Carbon::parse('2019-02-28 12:00:00.999999')->isMidday(); // true\n     * Carbon::parse('2019-02-28 12:00:01')->isMidday(); // false\n     * ```\n     *\n     * @return bool\n     */\n    public function isMidday()\n    {\n        /* @var CarbonInterface $this */\n        return $this->rawFormat('G:i:s') === static::$midDayAt.':00:00';\n    }\n\n    /**\n     * Checks if the (date)time string is in a given format.\n     *\n     * @example\n     * ```\n     * Carbon::hasFormat('11:12:45', 'h:i:s'); // true\n     * Carbon::hasFormat('13:12:45', 'h:i:s'); // false\n     * ```\n     *\n     * @param string $date\n     * @param string $format\n     *\n     * @return bool\n     */\n    public static function hasFormat($date, $format)\n    {\n        // createFromFormat() is known to handle edge cases silently.\n        // E.g. \"1975-5-1\" (Y-n-j) will still be parsed correctly when \"Y-m-d\" is supplied as the format.\n        // To ensure we're really testing against our desired format, perform an additional regex validation.\n\n        return self::matchFormatPattern((string) $date, preg_quote((string) $format, '/'), static::$regexFormats);\n    }\n\n    /**\n     * Checks if the (date)time string is in a given format.\n     *\n     * @example\n     * ```\n     * Carbon::hasFormatWithModifiers('31/08/2015', 'd#m#Y'); // true\n     * Carbon::hasFormatWithModifiers('31/08/2015', 'm#d#Y'); // false\n     * ```\n     *\n     * @param string $date\n     * @param string $format\n     *\n     * @return bool\n     */\n    public static function hasFormatWithModifiers($date, $format): bool\n    {\n        return self::matchFormatPattern((string) $date, (string) $format, array_merge(static::$regexFormats, static::$regexFormatModifiers));\n    }\n\n    /**\n     * Checks if the (date)time string is in a given format and valid to create a\n     * new instance.\n     *\n     * @example\n     * ```\n     * Carbon::canBeCreatedFromFormat('11:12:45', 'h:i:s'); // true\n     * Carbon::canBeCreatedFromFormat('13:12:45', 'h:i:s'); // false\n     * ```\n     *\n     * @param string $date\n     * @param string $format\n     *\n     * @return bool\n     */\n    public static function canBeCreatedFromFormat($date, $format)\n    {\n        try {\n            // Try to create a DateTime object. Throws an InvalidArgumentException if the provided time string\n            // doesn't match the format in any way.\n            if (!static::rawCreateFromFormat($format, $date)) {\n                return false;\n            }\n        } catch (InvalidArgumentException $e) {\n            return false;\n        }\n\n        return static::hasFormatWithModifiers($date, $format);\n    }\n\n    /**\n     * Returns true if the current date matches the given string.\n     *\n     * @example\n     * ```\n     * var_dump(Carbon::parse('2019-06-02 12:23:45')->is('2019')); // true\n     * var_dump(Carbon::parse('2019-06-02 12:23:45')->is('2018')); // false\n     * var_dump(Carbon::parse('2019-06-02 12:23:45')->is('2019-06')); // true\n     * var_dump(Carbon::parse('2019-06-02 12:23:45')->is('06-02')); // true\n     * var_dump(Carbon::parse('2019-06-02 12:23:45')->is('2019-06-02')); // true\n     * var_dump(Carbon::parse('2019-06-02 12:23:45')->is('Sunday')); // true\n     * var_dump(Carbon::parse('2019-06-02 12:23:45')->is('June')); // true\n     * var_dump(Carbon::parse('2019-06-02 12:23:45')->is('12:23')); // true\n     * var_dump(Carbon::parse('2019-06-02 12:23:45')->is('12:23:45')); // true\n     * var_dump(Carbon::parse('2019-06-02 12:23:45')->is('12:23:00')); // false\n     * var_dump(Carbon::parse('2019-06-02 12:23:45')->is('12h')); // true\n     * var_dump(Carbon::parse('2019-06-02 15:23:45')->is('3pm')); // true\n     * var_dump(Carbon::parse('2019-06-02 15:23:45')->is('3am')); // false\n     * ```\n     *\n     * @param string $tester day name, month name, hour, date, etc. as string\n     *\n     * @return bool\n     */\n    public function is(string $tester)\n    {\n        $tester = trim($tester);\n\n        if (preg_match('/^\\d+$/', $tester)) {\n            return $this->year === (int) $tester;\n        }\n\n        if (preg_match('/^(?:Jan|January|Feb|February|Mar|March|Apr|April|May|Jun|June|Jul|July|Aug|August|Sep|September|Oct|October|Nov|November|Dec|December)$/i', $tester)) {\n            return $this->isSameMonth(static::parse($tester), false);\n        }\n\n        if (preg_match('/^\\d{3,}-\\d{1,2}$/', $tester)) {\n            return $this->isSameMonth(static::parse($tester));\n        }\n\n        if (preg_match('/^\\d{1,2}-\\d{1,2}$/', $tester)) {\n            return $this->isSameDay(static::parse($this->year.'-'.$tester));\n        }\n\n        $modifier = preg_replace('/(\\d)h$/i', '$1:00', $tester);\n\n        /* @var CarbonInterface $max */\n        $median = static::parse('5555-06-15 12:30:30.555555')->modify($modifier);\n        $current = $this->avoidMutation();\n        /* @var CarbonInterface $other */\n        $other = $this->avoidMutation()->modify($modifier);\n\n        if ($current->eq($other)) {\n            return true;\n        }\n\n        if (preg_match('/\\d:\\d{1,2}:\\d{1,2}$/', $tester)) {\n            return $current->startOfSecond()->eq($other);\n        }\n\n        if (preg_match('/\\d:\\d{1,2}$/', $tester)) {\n            return $current->startOfMinute()->eq($other);\n        }\n\n        if (preg_match('/\\d(?:h|am|pm)$/', $tester)) {\n            return $current->startOfHour()->eq($other);\n        }\n\n        if (preg_match(\n            '/^(?:january|february|march|april|may|june|july|august|september|october|november|december)(?:\\s+\\d+)?$/i',\n            $tester\n        )) {\n            return $current->startOfMonth()->eq($other->startOfMonth());\n        }\n\n        $units = [\n            'month' => [1, 'year'],\n            'day' => [1, 'month'],\n            'hour' => [0, 'day'],\n            'minute' => [0, 'hour'],\n            'second' => [0, 'minute'],\n            'microsecond' => [0, 'second'],\n        ];\n\n        foreach ($units as $unit => [$minimum, $startUnit]) {\n            if ($minimum === $median->$unit) {\n                $current = $current->startOf($startUnit);\n\n                break;\n            }\n        }\n\n        return $current->eq($other);\n    }\n\n    /**\n     * Checks if the (date)time string is in a given format with\n     * given list of pattern replacements.\n     *\n     * @example\n     * ```\n     * Carbon::hasFormat('11:12:45', 'h:i:s'); // true\n     * Carbon::hasFormat('13:12:45', 'h:i:s'); // false\n     * ```\n     *\n     * @param string $date\n     * @param string $format\n     * @param array  $replacements\n     *\n     * @return bool\n     */\n    private static function matchFormatPattern(string $date, string $format, array $replacements): bool\n    {\n        // Preg quote, but remove escaped backslashes since we'll deal with escaped characters in the format string.\n        $regex = str_replace('\\\\\\\\', '\\\\', $format);\n        // Replace not-escaped letters\n        $regex = preg_replace_callback(\n            '/(?<!\\\\\\\\)((?:\\\\\\\\{2})*)(['.implode('', array_keys($replacements)).'])/',\n            function ($match) use ($replacements) {\n                return $match[1].strtr($match[2], $replacements);\n            },\n            $regex\n        );\n        // Replace escaped letters by the letter itself\n        $regex = preg_replace('/(?<!\\\\\\\\)((?:\\\\\\\\{2})*)\\\\\\\\(\\w)/', '$1$2', $regex);\n        // Escape not escaped slashes\n        $regex = preg_replace('#(?<!\\\\\\\\)((?:\\\\\\\\{2})*)/#', '$1\\\\/', $regex);\n\n        return (bool) @preg_match('/^'.$regex.'$/', $date);\n    }\n\n    /**\n     * Returns true if the date was created using CarbonImmutable::startOfTime()\n     *\n     * @return bool\n     */\n    public function isStartOfTime(): bool\n    {\n        return $this->startOfTime ?? false;\n    }\n\n    /**\n     * Returns true if the date was created using CarbonImmutable::endOfTime()\n     *\n     * @return bool\n     */\n    public function isEndOfTime(): bool\n    {\n        return $this->endOfTime ?? false;\n    }\n\n    private function discourageNull($value): void\n    {\n        if ($value === null) {\n            @trigger_error(\"Since 2.61.0, it's deprecated to compare a date to null, meaning of such comparison is ambiguous and will no longer be possible in 3.0.0, you should explicitly pass 'now' or make an other check to eliminate null values.\", \\E_USER_DEPRECATED);\n        }\n    }\n\n    private function discourageBoolean($value): void\n    {\n        if (\\is_bool($value)) {\n            @trigger_error(\"Since 2.61.0, it's deprecated to compare a date to true or false, meaning of such comparison is ambiguous and will no longer be possible in 3.0.0, you should explicitly pass 'now' or make an other check to eliminate boolean values.\", \\E_USER_DEPRECATED);\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Traits/Converter.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Traits;\n\nuse Carbon\\Carbon;\nuse Carbon\\CarbonImmutable;\nuse Carbon\\CarbonInterface;\nuse Carbon\\CarbonInterval;\nuse Carbon\\CarbonPeriod;\nuse Carbon\\CarbonPeriodImmutable;\nuse Carbon\\Exceptions\\UnitException;\nuse Closure;\nuse DateTime;\nuse DateTimeImmutable;\nuse ReturnTypeWillChange;\n\n/**\n * Trait Converter.\n *\n * Change date into different string formats and types and\n * handle the string cast.\n *\n * Depends on the following methods:\n *\n * @method static copy()\n */\ntrait Converter\n{\n    use ToStringFormat;\n\n    /**\n     * Returns the formatted date string on success or FALSE on failure.\n     *\n     * @see https://php.net/manual/en/datetime.format.php\n     *\n     * @param string $format\n     *\n     * @return string\n     */\n    #[ReturnTypeWillChange]\n    public function format($format)\n    {\n        $function = $this->localFormatFunction ?: static::$formatFunction;\n\n        if (!$function) {\n            return $this->rawFormat($format);\n        }\n\n        if (\\is_string($function) && method_exists($this, $function)) {\n            $function = [$this, $function];\n        }\n\n        return $function(...\\func_get_args());\n    }\n\n    /**\n     * @see https://php.net/manual/en/datetime.format.php\n     *\n     * @param string $format\n     *\n     * @return string\n     */\n    public function rawFormat($format)\n    {\n        return parent::format($format);\n    }\n\n    /**\n     * Format the instance as a string using the set format\n     *\n     * @example\n     * ```\n     * echo Carbon::now(); // Carbon instances can be cast to string\n     * ```\n     *\n     * @return string\n     */\n    public function __toString()\n    {\n        $format = $this->localToStringFormat ?? static::$toStringFormat;\n\n        return $format instanceof Closure\n            ? $format($this)\n            : $this->rawFormat($format ?: (\n                \\defined('static::DEFAULT_TO_STRING_FORMAT')\n                    ? static::DEFAULT_TO_STRING_FORMAT\n                    : CarbonInterface::DEFAULT_TO_STRING_FORMAT\n            ));\n    }\n\n    /**\n     * Format the instance as date\n     *\n     * @example\n     * ```\n     * echo Carbon::now()->toDateString();\n     * ```\n     *\n     * @return string\n     */\n    public function toDateString()\n    {\n        return $this->rawFormat('Y-m-d');\n    }\n\n    /**\n     * Format the instance as a readable date\n     *\n     * @example\n     * ```\n     * echo Carbon::now()->toFormattedDateString();\n     * ```\n     *\n     * @return string\n     */\n    public function toFormattedDateString()\n    {\n        return $this->rawFormat('M j, Y');\n    }\n\n    /**\n     * Format the instance with the day, and a readable date\n     *\n     * @example\n     * ```\n     * echo Carbon::now()->toFormattedDayDateString();\n     * ```\n     *\n     * @return string\n     */\n    public function toFormattedDayDateString(): string\n    {\n        return $this->rawFormat('D, M j, Y');\n    }\n\n    /**\n     * Format the instance as time\n     *\n     * @example\n     * ```\n     * echo Carbon::now()->toTimeString();\n     * ```\n     *\n     * @param string $unitPrecision\n     *\n     * @return string\n     */\n    public function toTimeString($unitPrecision = 'second')\n    {\n        return $this->rawFormat(static::getTimeFormatByPrecision($unitPrecision));\n    }\n\n    /**\n     * Format the instance as date and time\n     *\n     * @example\n     * ```\n     * echo Carbon::now()->toDateTimeString();\n     * ```\n     *\n     * @param string $unitPrecision\n     *\n     * @return string\n     */\n    public function toDateTimeString($unitPrecision = 'second')\n    {\n        return $this->rawFormat('Y-m-d '.static::getTimeFormatByPrecision($unitPrecision));\n    }\n\n    /**\n     * Return a format from H:i to H:i:s.u according to given unit precision.\n     *\n     * @param string $unitPrecision \"minute\", \"second\", \"millisecond\" or \"microsecond\"\n     *\n     * @return string\n     */\n    public static function getTimeFormatByPrecision($unitPrecision)\n    {\n        switch (static::singularUnit($unitPrecision)) {\n            case 'minute':\n                return 'H:i';\n            case 'second':\n                return 'H:i:s';\n            case 'm':\n            case 'millisecond':\n                return 'H:i:s.v';\n            case 'µ':\n            case 'microsecond':\n                return 'H:i:s.u';\n        }\n\n        throw new UnitException('Precision unit expected among: minute, second, millisecond and microsecond.');\n    }\n\n    /**\n     * Format the instance as date and time T-separated with no timezone\n     *\n     * @example\n     * ```\n     * echo Carbon::now()->toDateTimeLocalString();\n     * echo \"\\n\";\n     * echo Carbon::now()->toDateTimeLocalString('minute'); // You can specify precision among: minute, second, millisecond and microsecond\n     * ```\n     *\n     * @param string $unitPrecision\n     *\n     * @return string\n     */\n    public function toDateTimeLocalString($unitPrecision = 'second')\n    {\n        return $this->rawFormat('Y-m-d\\T'.static::getTimeFormatByPrecision($unitPrecision));\n    }\n\n    /**\n     * Format the instance with day, date and time\n     *\n     * @example\n     * ```\n     * echo Carbon::now()->toDayDateTimeString();\n     * ```\n     *\n     * @return string\n     */\n    public function toDayDateTimeString()\n    {\n        return $this->rawFormat('D, M j, Y g:i A');\n    }\n\n    /**\n     * Format the instance as ATOM\n     *\n     * @example\n     * ```\n     * echo Carbon::now()->toAtomString();\n     * ```\n     *\n     * @return string\n     */\n    public function toAtomString()\n    {\n        return $this->rawFormat(DateTime::ATOM);\n    }\n\n    /**\n     * Format the instance as COOKIE\n     *\n     * @example\n     * ```\n     * echo Carbon::now()->toCookieString();\n     * ```\n     *\n     * @return string\n     */\n    public function toCookieString()\n    {\n        return $this->rawFormat(DateTime::COOKIE);\n    }\n\n    /**\n     * Format the instance as ISO8601\n     *\n     * @example\n     * ```\n     * echo Carbon::now()->toIso8601String();\n     * ```\n     *\n     * @return string\n     */\n    public function toIso8601String()\n    {\n        return $this->toAtomString();\n    }\n\n    /**\n     * Format the instance as RFC822\n     *\n     * @example\n     * ```\n     * echo Carbon::now()->toRfc822String();\n     * ```\n     *\n     * @return string\n     */\n    public function toRfc822String()\n    {\n        return $this->rawFormat(DateTime::RFC822);\n    }\n\n    /**\n     * Convert the instance to UTC and return as Zulu ISO8601\n     *\n     * @example\n     * ```\n     * echo Carbon::now()->toIso8601ZuluString();\n     * ```\n     *\n     * @param string $unitPrecision\n     *\n     * @return string\n     */\n    public function toIso8601ZuluString($unitPrecision = 'second')\n    {\n        return $this->avoidMutation()\n            ->utc()\n            ->rawFormat('Y-m-d\\T'.static::getTimeFormatByPrecision($unitPrecision).'\\Z');\n    }\n\n    /**\n     * Format the instance as RFC850\n     *\n     * @example\n     * ```\n     * echo Carbon::now()->toRfc850String();\n     * ```\n     *\n     * @return string\n     */\n    public function toRfc850String()\n    {\n        return $this->rawFormat(DateTime::RFC850);\n    }\n\n    /**\n     * Format the instance as RFC1036\n     *\n     * @example\n     * ```\n     * echo Carbon::now()->toRfc1036String();\n     * ```\n     *\n     * @return string\n     */\n    public function toRfc1036String()\n    {\n        return $this->rawFormat(DateTime::RFC1036);\n    }\n\n    /**\n     * Format the instance as RFC1123\n     *\n     * @example\n     * ```\n     * echo Carbon::now()->toRfc1123String();\n     * ```\n     *\n     * @return string\n     */\n    public function toRfc1123String()\n    {\n        return $this->rawFormat(DateTime::RFC1123);\n    }\n\n    /**\n     * Format the instance as RFC2822\n     *\n     * @example\n     * ```\n     * echo Carbon::now()->toRfc2822String();\n     * ```\n     *\n     * @return string\n     */\n    public function toRfc2822String()\n    {\n        return $this->rawFormat(DateTime::RFC2822);\n    }\n\n    /**\n     * Format the instance as RFC3339\n     *\n     * @param bool $extended\n     *\n     * @example\n     * ```\n     * echo Carbon::now()->toRfc3339String() . \"\\n\";\n     * echo Carbon::now()->toRfc3339String(true) . \"\\n\";\n     * ```\n     *\n     * @return string\n     */\n    public function toRfc3339String($extended = false)\n    {\n        $format = DateTime::RFC3339;\n        if ($extended) {\n            $format = DateTime::RFC3339_EXTENDED;\n        }\n\n        return $this->rawFormat($format);\n    }\n\n    /**\n     * Format the instance as RSS\n     *\n     * @example\n     * ```\n     * echo Carbon::now()->toRssString();\n     * ```\n     *\n     * @return string\n     */\n    public function toRssString()\n    {\n        return $this->rawFormat(DateTime::RSS);\n    }\n\n    /**\n     * Format the instance as W3C\n     *\n     * @example\n     * ```\n     * echo Carbon::now()->toW3cString();\n     * ```\n     *\n     * @return string\n     */\n    public function toW3cString()\n    {\n        return $this->rawFormat(DateTime::W3C);\n    }\n\n    /**\n     * Format the instance as RFC7231\n     *\n     * @example\n     * ```\n     * echo Carbon::now()->toRfc7231String();\n     * ```\n     *\n     * @return string\n     */\n    public function toRfc7231String()\n    {\n        return $this->avoidMutation()\n            ->setTimezone('GMT')\n            ->rawFormat(\\defined('static::RFC7231_FORMAT') ? static::RFC7231_FORMAT : CarbonInterface::RFC7231_FORMAT);\n    }\n\n    /**\n     * Get default array representation.\n     *\n     * @example\n     * ```\n     * var_dump(Carbon::now()->toArray());\n     * ```\n     *\n     * @return array\n     */\n    public function toArray()\n    {\n        return [\n            'year' => $this->year,\n            'month' => $this->month,\n            'day' => $this->day,\n            'dayOfWeek' => $this->dayOfWeek,\n            'dayOfYear' => $this->dayOfYear,\n            'hour' => $this->hour,\n            'minute' => $this->minute,\n            'second' => $this->second,\n            'micro' => $this->micro,\n            'timestamp' => $this->timestamp,\n            'formatted' => $this->rawFormat(\\defined('static::DEFAULT_TO_STRING_FORMAT') ? static::DEFAULT_TO_STRING_FORMAT : CarbonInterface::DEFAULT_TO_STRING_FORMAT),\n            'timezone' => $this->timezone,\n        ];\n    }\n\n    /**\n     * Get default object representation.\n     *\n     * @example\n     * ```\n     * var_dump(Carbon::now()->toObject());\n     * ```\n     *\n     * @return object\n     */\n    public function toObject()\n    {\n        return (object) $this->toArray();\n    }\n\n    /**\n     * Returns english human readable complete date string.\n     *\n     * @example\n     * ```\n     * echo Carbon::now()->toString();\n     * ```\n     *\n     * @return string\n     */\n    public function toString()\n    {\n        return $this->avoidMutation()->locale('en')->isoFormat('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ');\n    }\n\n    /**\n     * Return the ISO-8601 string (ex: 1977-04-22T06:00:00Z, if $keepOffset truthy, offset will be kept:\n     * 1977-04-22T01:00:00-05:00).\n     *\n     * @example\n     * ```\n     * echo Carbon::now('America/Toronto')->toISOString() . \"\\n\";\n     * echo Carbon::now('America/Toronto')->toISOString(true) . \"\\n\";\n     * ```\n     *\n     * @param bool $keepOffset Pass true to keep the date offset. Else forced to UTC.\n     *\n     * @return null|string\n     */\n    public function toISOString($keepOffset = false)\n    {\n        if (!$this->isValid()) {\n            return null;\n        }\n\n        $yearFormat = $this->year < 0 || $this->year > 9999 ? 'YYYYYY' : 'YYYY';\n        $tzFormat = $keepOffset ? 'Z' : '[Z]';\n        $date = $keepOffset ? $this : $this->avoidMutation()->utc();\n\n        return $date->isoFormat(\"$yearFormat-MM-DD[T]HH:mm:ss.SSSSSS$tzFormat\");\n    }\n\n    /**\n     * Return the ISO-8601 string (ex: 1977-04-22T06:00:00Z) with UTC timezone.\n     *\n     * @example\n     * ```\n     * echo Carbon::now('America/Toronto')->toJSON();\n     * ```\n     *\n     * @return null|string\n     */\n    public function toJSON()\n    {\n        return $this->toISOString();\n    }\n\n    /**\n     * Return native DateTime PHP object matching the current instance.\n     *\n     * @example\n     * ```\n     * var_dump(Carbon::now()->toDateTime());\n     * ```\n     *\n     * @return DateTime\n     */\n    public function toDateTime()\n    {\n        return new DateTime($this->rawFormat('Y-m-d H:i:s.u'), $this->getTimezone());\n    }\n\n    /**\n     * Return native toDateTimeImmutable PHP object matching the current instance.\n     *\n     * @example\n     * ```\n     * var_dump(Carbon::now()->toDateTimeImmutable());\n     * ```\n     *\n     * @return DateTimeImmutable\n     */\n    public function toDateTimeImmutable()\n    {\n        return new DateTimeImmutable($this->rawFormat('Y-m-d H:i:s.u'), $this->getTimezone());\n    }\n\n    /**\n     * @alias toDateTime\n     *\n     * Return native DateTime PHP object matching the current instance.\n     *\n     * @example\n     * ```\n     * var_dump(Carbon::now()->toDate());\n     * ```\n     *\n     * @return DateTime\n     */\n    public function toDate()\n    {\n        return $this->toDateTime();\n    }\n\n    /**\n     * Create a iterable CarbonPeriod object from current date to a given end date (and optional interval).\n     *\n     * @param \\DateTimeInterface|Carbon|CarbonImmutable|int|null $end      period end date or recurrences count if int\n     * @param int|\\DateInterval|string|null                      $interval period default interval or number of the given $unit\n     * @param string|null                                        $unit     if specified, $interval must be an integer\n     *\n     * @return CarbonPeriod\n     */\n    public function toPeriod($end = null, $interval = null, $unit = null)\n    {\n        if ($unit) {\n            $interval = CarbonInterval::make(\"$interval \".static::pluralUnit($unit));\n        }\n\n        $period = ($this->isMutable() ? new CarbonPeriod() : new CarbonPeriodImmutable())\n            ->setDateClass(static::class)\n            ->setStartDate($this);\n\n        if ($interval) {\n            $period = $period->setDateInterval($interval);\n        }\n\n        if (\\is_int($end) || (\\is_string($end) && ctype_digit($end))) {\n            $period = $period->setRecurrences($end);\n        } elseif ($end) {\n            $period = $period->setEndDate($end);\n        }\n\n        return $period;\n    }\n\n    /**\n     * Create a iterable CarbonPeriod object from current date to a given end date (and optional interval).\n     *\n     * @param \\DateTimeInterface|Carbon|CarbonImmutable|null $end      period end date\n     * @param int|\\DateInterval|string|null                  $interval period default interval or number of the given $unit\n     * @param string|null                                    $unit     if specified, $interval must be an integer\n     *\n     * @return CarbonPeriod\n     */\n    public function range($end = null, $interval = null, $unit = null)\n    {\n        return $this->toPeriod($end, $interval, $unit);\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Traits/Creator.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Traits;\n\nuse Carbon\\Carbon;\nuse Carbon\\CarbonImmutable;\nuse Carbon\\CarbonInterface;\nuse Carbon\\Exceptions\\InvalidDateException;\nuse Carbon\\Exceptions\\InvalidFormatException;\nuse Carbon\\Exceptions\\OutOfRangeException;\nuse Carbon\\Translator;\nuse Closure;\nuse DateMalformedStringException;\nuse DateTimeImmutable;\nuse DateTimeInterface;\nuse DateTimeZone;\nuse Exception;\nuse ReturnTypeWillChange;\n\n/**\n * Trait Creator.\n *\n * Static creators.\n *\n * Depends on the following methods:\n *\n * @method static Carbon|CarbonImmutable getTestNow()\n */\ntrait Creator\n{\n    use ObjectInitialisation;\n\n    /**\n     * The errors that can occur.\n     *\n     * @var array\n     */\n    protected static $lastErrors;\n\n    /**\n     * Create a new Carbon instance.\n     *\n     * Please see the testing aids section (specifically static::setTestNow())\n     * for more on the possibility of this constructor returning a test instance.\n     *\n     * @param DateTimeInterface|string|null $time\n     * @param DateTimeZone|string|null      $tz\n     *\n     * @throws InvalidFormatException\n     */\n    public function __construct($time = null, $tz = null)\n    {\n        if ($time instanceof DateTimeInterface) {\n            $time = $this->constructTimezoneFromDateTime($time, $tz)->format('Y-m-d H:i:s.u');\n        }\n\n        if (is_numeric($time) && (!\\is_string($time) || !preg_match('/^\\d{1,14}$/', $time))) {\n            $time = static::createFromTimestampUTC($time)->format('Y-m-d\\TH:i:s.uP');\n        }\n\n        // If the class has a test now set and we are trying to create a now()\n        // instance then override as required\n        $isNow = empty($time) || $time === 'now';\n\n        if (method_exists(static::class, 'hasTestNow') &&\n            method_exists(static::class, 'getTestNow') &&\n            static::hasTestNow() &&\n            ($isNow || static::hasRelativeKeywords($time))\n        ) {\n            static::mockConstructorParameters($time, $tz);\n        }\n\n        // Work-around for PHP bug https://bugs.php.net/bug.php?id=67127\n        if (!str_contains((string) .1, '.')) {\n            $locale = setlocale(LC_NUMERIC, '0'); // @codeCoverageIgnore\n            setlocale(LC_NUMERIC, 'C'); // @codeCoverageIgnore\n        }\n\n        try {\n            parent::__construct($time ?: 'now', static::safeCreateDateTimeZone($tz) ?: null);\n        } catch (Exception $exception) {\n            throw new InvalidFormatException($exception->getMessage(), 0, $exception);\n        }\n\n        $this->constructedObjectId = spl_object_hash($this);\n\n        if (isset($locale)) {\n            setlocale(LC_NUMERIC, $locale); // @codeCoverageIgnore\n        }\n\n        self::setLastErrors(parent::getLastErrors());\n    }\n\n    /**\n     * Get timezone from a datetime instance.\n     *\n     * @param DateTimeInterface        $date\n     * @param DateTimeZone|string|null $tz\n     *\n     * @return DateTimeInterface\n     */\n    private function constructTimezoneFromDateTime(DateTimeInterface $date, &$tz)\n    {\n        if ($tz !== null) {\n            $safeTz = static::safeCreateDateTimeZone($tz);\n\n            if ($safeTz) {\n                return ($date instanceof DateTimeImmutable ? $date : clone $date)->setTimezone($safeTz);\n            }\n\n            return $date;\n        }\n\n        $tz = $date->getTimezone();\n\n        return $date;\n    }\n\n    /**\n     * Update constructedObjectId on cloned.\n     */\n    public function __clone()\n    {\n        $this->constructedObjectId = spl_object_hash($this);\n    }\n\n    /**\n     * Create a Carbon instance from a DateTime one.\n     *\n     * @param DateTimeInterface $date\n     *\n     * @return static\n     */\n    public static function instance($date)\n    {\n        if ($date instanceof static) {\n            return clone $date;\n        }\n\n        static::expectDateTime($date);\n\n        $instance = new static($date->format('Y-m-d H:i:s.u'), $date->getTimezone());\n\n        if ($date instanceof CarbonInterface) {\n            $settings = $date->getSettings();\n\n            if (!$date->hasLocalTranslator()) {\n                unset($settings['locale']);\n            }\n\n            $instance->settings($settings);\n        }\n\n        return $instance;\n    }\n\n    /**\n     * Create a carbon instance from a string.\n     *\n     * This is an alias for the constructor that allows better fluent syntax\n     * as it allows you to do Carbon::parse('Monday next week')->fn() rather\n     * than (new Carbon('Monday next week'))->fn().\n     *\n     * @param string|DateTimeInterface|null $time\n     * @param DateTimeZone|string|null      $tz\n     *\n     * @throws InvalidFormatException\n     *\n     * @return static\n     */\n    public static function rawParse($time = null, $tz = null)\n    {\n        if ($time instanceof DateTimeInterface) {\n            return static::instance($time);\n        }\n\n        try {\n            return new static($time, $tz);\n        } catch (Exception $exception) {\n            // @codeCoverageIgnoreStart\n            try {\n                $date = @static::now($tz)->change($time);\n            } catch (DateMalformedStringException $ignoredException) {\n                $date = null;\n            }\n            // @codeCoverageIgnoreEnd\n\n            if (!$date) {\n                throw new InvalidFormatException(\"Could not parse '$time': \".$exception->getMessage(), 0, $exception);\n            }\n\n            return $date;\n        }\n    }\n\n    /**\n     * Create a carbon instance from a string.\n     *\n     * This is an alias for the constructor that allows better fluent syntax\n     * as it allows you to do Carbon::parse('Monday next week')->fn() rather\n     * than (new Carbon('Monday next week'))->fn().\n     *\n     * @param string|DateTimeInterface|null $time\n     * @param DateTimeZone|string|null      $tz\n     *\n     * @throws InvalidFormatException\n     *\n     * @return static\n     */\n    public static function parse($time = null, $tz = null)\n    {\n        $function = static::$parseFunction;\n\n        if (!$function) {\n            return static::rawParse($time, $tz);\n        }\n\n        if (\\is_string($function) && method_exists(static::class, $function)) {\n            $function = [static::class, $function];\n        }\n\n        return $function(...\\func_get_args());\n    }\n\n    /**\n     * Create a carbon instance from a localized string (in French, Japanese, Arabic, etc.).\n     *\n     * @param string                   $time   date/time string in the given language (may also contain English).\n     * @param string|null              $locale if locale is null or not specified, current global locale will be\n     *                                         used instead.\n     * @param DateTimeZone|string|null $tz     optional timezone for the new instance.\n     *\n     * @throws InvalidFormatException\n     *\n     * @return static\n     */\n    public static function parseFromLocale($time, $locale = null, $tz = null)\n    {\n        return static::rawParse(static::translateTimeString($time, $locale, 'en'), $tz);\n    }\n\n    /**\n     * Get a Carbon instance for the current date and time.\n     *\n     * @param DateTimeZone|string|null $tz\n     *\n     * @return static\n     */\n    public static function now($tz = null)\n    {\n        return new static(null, $tz);\n    }\n\n    /**\n     * Create a Carbon instance for today.\n     *\n     * @param DateTimeZone|string|null $tz\n     *\n     * @return static\n     */\n    public static function today($tz = null)\n    {\n        return static::rawParse('today', $tz);\n    }\n\n    /**\n     * Create a Carbon instance for tomorrow.\n     *\n     * @param DateTimeZone|string|null $tz\n     *\n     * @return static\n     */\n    public static function tomorrow($tz = null)\n    {\n        return static::rawParse('tomorrow', $tz);\n    }\n\n    /**\n     * Create a Carbon instance for yesterday.\n     *\n     * @param DateTimeZone|string|null $tz\n     *\n     * @return static\n     */\n    public static function yesterday($tz = null)\n    {\n        return static::rawParse('yesterday', $tz);\n    }\n\n    /**\n     * Create a Carbon instance for the greatest supported date.\n     *\n     * @return static\n     */\n    public static function maxValue()\n    {\n        if (self::$PHPIntSize === 4) {\n            // 32 bit\n            return static::createFromTimestamp(PHP_INT_MAX); // @codeCoverageIgnore\n        }\n\n        // 64 bit\n        return static::create(9999, 12, 31, 23, 59, 59);\n    }\n\n    /**\n     * Create a Carbon instance for the lowest supported date.\n     *\n     * @return static\n     */\n    public static function minValue()\n    {\n        if (self::$PHPIntSize === 4) {\n            // 32 bit\n            return static::createFromTimestamp(~PHP_INT_MAX); // @codeCoverageIgnore\n        }\n\n        // 64 bit\n        return static::create(1, 1, 1, 0, 0, 0);\n    }\n\n    private static function assertBetween($unit, $value, $min, $max)\n    {\n        if (static::isStrictModeEnabled() && ($value < $min || $value > $max)) {\n            throw new OutOfRangeException($unit, $min, $max, $value);\n        }\n    }\n\n    private static function createNowInstance($tz)\n    {\n        if (!static::hasTestNow()) {\n            return static::now($tz);\n        }\n\n        $now = static::getTestNow();\n\n        if ($now instanceof Closure) {\n            return $now(static::now($tz));\n        }\n\n        return $now->avoidMutation()->tz($tz);\n    }\n\n    /**\n     * Create a new Carbon instance from a specific date and time.\n     *\n     * If any of $year, $month or $day are set to null their now() values will\n     * be used.\n     *\n     * If $hour is null it will be set to its now() value and the default\n     * values for $minute and $second will be their now() values.\n     *\n     * If $hour is not null then the default values for $minute and $second\n     * will be 0.\n     *\n     * @param DateTimeInterface|int|null $year\n     * @param int|null                   $month\n     * @param int|null                   $day\n     * @param int|null                   $hour\n     * @param int|null                   $minute\n     * @param int|null                   $second\n     * @param DateTimeZone|string|null   $tz\n     *\n     * @throws InvalidFormatException\n     *\n     * @return static|false\n     */\n    public static function create($year = 0, $month = 1, $day = 1, $hour = 0, $minute = 0, $second = 0, $tz = null)\n    {\n        if ((\\is_string($year) && !is_numeric($year)) || $year instanceof DateTimeInterface) {\n            return static::parse($year, $tz ?: (\\is_string($month) || $month instanceof DateTimeZone ? $month : null));\n        }\n\n        $defaults = null;\n        $getDefault = function ($unit) use ($tz, &$defaults) {\n            if ($defaults === null) {\n                $now = self::createNowInstance($tz);\n\n                $defaults = array_combine([\n                    'year',\n                    'month',\n                    'day',\n                    'hour',\n                    'minute',\n                    'second',\n                ], explode('-', $now->rawFormat('Y-n-j-G-i-s.u')));\n            }\n\n            return $defaults[$unit];\n        };\n\n        $year = $year ?? $getDefault('year');\n        $month = $month ?? $getDefault('month');\n        $day = $day ?? $getDefault('day');\n        $hour = $hour ?? $getDefault('hour');\n        $minute = $minute ?? $getDefault('minute');\n        $second = (float) ($second ?? $getDefault('second'));\n\n        self::assertBetween('month', $month, 0, 99);\n        self::assertBetween('day', $day, 0, 99);\n        self::assertBetween('hour', $hour, 0, 99);\n        self::assertBetween('minute', $minute, 0, 99);\n        self::assertBetween('second', $second, 0, 99);\n\n        $fixYear = null;\n\n        if ($year < 0) {\n            $fixYear = $year;\n            $year = 0;\n        } elseif ($year > 9999) {\n            $fixYear = $year - 9999;\n            $year = 9999;\n        }\n\n        $second = ($second < 10 ? '0' : '').number_format($second, 6);\n        $instance = static::rawCreateFromFormat('!Y-n-j G:i:s.u', \\sprintf('%s-%s-%s %s:%02s:%02s', $year, $month, $day, $hour, $minute, $second), $tz);\n\n        if ($fixYear !== null) {\n            $instance = $instance->addYears($fixYear);\n        }\n\n        return $instance;\n    }\n\n    /**\n     * Create a new safe Carbon instance from a specific date and time.\n     *\n     * If any of $year, $month or $day are set to null their now() values will\n     * be used.\n     *\n     * If $hour is null it will be set to its now() value and the default\n     * values for $minute and $second will be their now() values.\n     *\n     * If $hour is not null then the default values for $minute and $second\n     * will be 0.\n     *\n     * If one of the set values is not valid, an InvalidDateException\n     * will be thrown.\n     *\n     * @param int|null                 $year\n     * @param int|null                 $month\n     * @param int|null                 $day\n     * @param int|null                 $hour\n     * @param int|null                 $minute\n     * @param int|null                 $second\n     * @param DateTimeZone|string|null $tz\n     *\n     * @throws InvalidDateException\n     *\n     * @return static|false\n     */\n    public static function createSafe($year = null, $month = null, $day = null, $hour = null, $minute = null, $second = null, $tz = null)\n    {\n        $fields = static::getRangesByUnit();\n\n        foreach ($fields as $field => $range) {\n            if ($$field !== null && (!\\is_int($$field) || $$field < $range[0] || $$field > $range[1])) {\n                if (static::isStrictModeEnabled()) {\n                    throw new InvalidDateException($field, $$field);\n                }\n\n                return false;\n            }\n        }\n\n        $instance = static::create($year, $month, $day, $hour, $minute, $second, $tz);\n\n        foreach (array_reverse($fields) as $field => $range) {\n            if ($$field !== null && (!\\is_int($$field) || $$field !== $instance->$field)) {\n                if (static::isStrictModeEnabled()) {\n                    throw new InvalidDateException($field, $$field);\n                }\n\n                return false;\n            }\n        }\n\n        return $instance;\n    }\n\n    /**\n     * Create a new Carbon instance from a specific date and time using strict validation.\n     *\n     * @see create()\n     *\n     * @param int|null                 $year\n     * @param int|null                 $month\n     * @param int|null                 $day\n     * @param int|null                 $hour\n     * @param int|null                 $minute\n     * @param int|null                 $second\n     * @param DateTimeZone|string|null $tz\n     *\n     * @throws InvalidFormatException\n     *\n     * @return static\n     */\n    public static function createStrict(?int $year = 0, ?int $month = 1, ?int $day = 1, ?int $hour = 0, ?int $minute = 0, ?int $second = 0, $tz = null): self\n    {\n        $initialStrictMode = static::isStrictModeEnabled();\n        static::useStrictMode(true);\n\n        try {\n            $date = static::create($year, $month, $day, $hour, $minute, $second, $tz);\n        } finally {\n            static::useStrictMode($initialStrictMode);\n        }\n\n        return $date;\n    }\n\n    /**\n     * Create a Carbon instance from just a date. The time portion is set to now.\n     *\n     * @param int|null                 $year\n     * @param int|null                 $month\n     * @param int|null                 $day\n     * @param DateTimeZone|string|null $tz\n     *\n     * @throws InvalidFormatException\n     *\n     * @return static\n     */\n    public static function createFromDate($year = null, $month = null, $day = null, $tz = null)\n    {\n        return static::create($year, $month, $day, null, null, null, $tz);\n    }\n\n    /**\n     * Create a Carbon instance from just a date. The time portion is set to midnight.\n     *\n     * @param int|null                 $year\n     * @param int|null                 $month\n     * @param int|null                 $day\n     * @param DateTimeZone|string|null $tz\n     *\n     * @throws InvalidFormatException\n     *\n     * @return static\n     */\n    public static function createMidnightDate($year = null, $month = null, $day = null, $tz = null)\n    {\n        return static::create($year, $month, $day, 0, 0, 0, $tz);\n    }\n\n    /**\n     * Create a Carbon instance from just a time. The date portion is set to today.\n     *\n     * @param int|null                 $hour\n     * @param int|null                 $minute\n     * @param int|null                 $second\n     * @param DateTimeZone|string|null $tz\n     *\n     * @throws InvalidFormatException\n     *\n     * @return static\n     */\n    public static function createFromTime($hour = 0, $minute = 0, $second = 0, $tz = null)\n    {\n        return static::create(null, null, null, $hour, $minute, $second, $tz);\n    }\n\n    /**\n     * Create a Carbon instance from a time string. The date portion is set to today.\n     *\n     * @param string                   $time\n     * @param DateTimeZone|string|null $tz\n     *\n     * @throws InvalidFormatException\n     *\n     * @return static\n     */\n    public static function createFromTimeString($time, $tz = null)\n    {\n        return static::today($tz)->setTimeFromTimeString($time);\n    }\n\n    /**\n     * @param string                         $format     Datetime format\n     * @param string                         $time\n     * @param DateTimeZone|string|false|null $originalTz\n     *\n     * @return DateTimeInterface|false\n     */\n    private static function createFromFormatAndTimezone($format, $time, $originalTz)\n    {\n        // Work-around for https://bugs.php.net/bug.php?id=75577\n        // @codeCoverageIgnoreStart\n        if (version_compare(PHP_VERSION, '7.3.0-dev', '<')) {\n            $format = str_replace('.v', '.u', $format);\n        }\n        // @codeCoverageIgnoreEnd\n\n        if ($originalTz === null) {\n            return parent::createFromFormat($format, (string) $time);\n        }\n\n        $tz = \\is_int($originalTz)\n            ? @timezone_name_from_abbr('', (int) ($originalTz * static::MINUTES_PER_HOUR * static::SECONDS_PER_MINUTE), 1)\n            : $originalTz;\n\n        $tz = static::safeCreateDateTimeZone($tz, $originalTz);\n\n        if ($tz === false) {\n            return false;\n        }\n\n        return parent::createFromFormat($format, (string) $time, $tz);\n    }\n\n    /**\n     * Create a Carbon instance from a specific format.\n     *\n     * @param string                         $format Datetime format\n     * @param string                         $time\n     * @param DateTimeZone|string|false|null $tz\n     *\n     * @throws InvalidFormatException\n     *\n     * @return static|false\n     */\n    public static function rawCreateFromFormat($format, $time, $tz = null)\n    {\n        // Work-around for https://bugs.php.net/bug.php?id=80141\n        $format = preg_replace('/(?<!\\\\\\\\)((?:\\\\\\\\{2})*)c/', '$1Y-m-d\\TH:i:sP', $format);\n\n        if (preg_match('/(?<!\\\\\\\\)(?:\\\\\\\\{2})*(a|A)/', $format, $aMatches, PREG_OFFSET_CAPTURE) &&\n            preg_match('/(?<!\\\\\\\\)(?:\\\\\\\\{2})*(h|g|H|G)/', $format, $hMatches, PREG_OFFSET_CAPTURE) &&\n            $aMatches[1][1] < $hMatches[1][1] &&\n            preg_match('/(am|pm|AM|PM)/', $time)\n        ) {\n            $format = preg_replace('/^(.*)(?<!\\\\\\\\)((?:\\\\\\\\{2})*)(a|A)(.*)$/U', '$1$2$4 $3', $format);\n            $time = preg_replace('/^(.*)(am|pm|AM|PM)(.*)$/U', '$1$3 $2', $time);\n        }\n\n        if ($tz === false) {\n            $tz = null;\n        }\n\n        // First attempt to create an instance, so that error messages are based on the unmodified format.\n        $date = self::createFromFormatAndTimezone($format, $time, $tz);\n        $lastErrors = parent::getLastErrors();\n        /** @var \\Carbon\\CarbonImmutable|\\Carbon\\Carbon|null $mock */\n        $mock = static::getMockedTestNow($tz);\n\n        if ($mock && $date instanceof DateTimeInterface) {\n            // Set timezone from mock if custom timezone was neither given directly nor as a part of format.\n            // First let's skip the part that will be ignored by the parser.\n            $nonEscaped = '(?<!\\\\\\\\)(\\\\\\\\{2})*';\n\n            $nonIgnored = preg_replace(\"/^.*{$nonEscaped}!/s\", '', $format);\n\n            if ($tz === null && !preg_match(\"/{$nonEscaped}[eOPT]/\", $nonIgnored)) {\n                $tz = clone $mock->getTimezone();\n            }\n\n            $mock = $mock->copy();\n\n            // Prepend mock datetime only if the format does not contain non escaped unix epoch reset flag.\n            if (!preg_match(\"/{$nonEscaped}[!|]/\", $format)) {\n                if (preg_match('/[HhGgisvuB]/', $format)) {\n                    $mock = $mock->setTime(0, 0);\n                }\n\n                $format = static::MOCK_DATETIME_FORMAT.' '.$format;\n                $time = ($mock instanceof self ? $mock->rawFormat(static::MOCK_DATETIME_FORMAT) : $mock->format(static::MOCK_DATETIME_FORMAT)).' '.$time;\n            }\n\n            // Regenerate date from the modified format to base result on the mocked instance instead of now.\n            $date = self::createFromFormatAndTimezone($format, $time, $tz);\n        }\n\n        if ($date instanceof DateTimeInterface) {\n            $instance = static::instance($date);\n            $instance::setLastErrors($lastErrors);\n\n            return $instance;\n        }\n\n        if (static::isStrictModeEnabled()) {\n            throw new InvalidFormatException(implode(PHP_EOL, $lastErrors['errors']));\n        }\n\n        return false;\n    }\n\n    /**\n     * Create a Carbon instance from a specific format.\n     *\n     * @param string                         $format Datetime format\n     * @param string                         $time\n     * @param DateTimeZone|string|false|null $tz\n     *\n     * @throws InvalidFormatException\n     *\n     * @return static|false\n     */\n    #[ReturnTypeWillChange]\n    public static function createFromFormat($format, $time, $tz = null)\n    {\n        $function = static::$createFromFormatFunction;\n\n        if (!$function) {\n            return static::rawCreateFromFormat($format, $time, $tz);\n        }\n\n        if (\\is_string($function) && method_exists(static::class, $function)) {\n            $function = [static::class, $function];\n        }\n\n        return $function(...\\func_get_args());\n    }\n\n    /**\n     * Create a Carbon instance from a specific ISO format (same replacements as ->isoFormat()).\n     *\n     * @param string                                             $format     Datetime format\n     * @param string                                             $time\n     * @param DateTimeZone|string|false|null                     $tz         optional timezone\n     * @param string|null                                        $locale     locale to be used for LTS, LT, LL, LLL, etc. macro-formats (en by fault, unneeded if no such macro-format in use)\n     * @param \\Symfony\\Component\\Translation\\TranslatorInterface $translator optional custom translator to use for macro-formats\n     *\n     * @throws InvalidFormatException\n     *\n     * @return static|false\n     */\n    public static function createFromIsoFormat($format, $time, $tz = null, $locale = 'en', $translator = null)\n    {\n        $format = preg_replace_callback('/(?<!\\\\\\\\)(\\\\\\\\{2})*(LTS|LT|[Ll]{1,4})/', function ($match) use ($locale, $translator) {\n            [$code] = $match;\n\n            static $formats = null;\n\n            if ($formats === null) {\n                $translator = $translator ?: Translator::get($locale);\n\n                $formats = [\n                    'LT' => static::getTranslationMessageWith($translator, 'formats.LT', $locale, 'h:mm A'),\n                    'LTS' => static::getTranslationMessageWith($translator, 'formats.LTS', $locale, 'h:mm:ss A'),\n                    'L' => static::getTranslationMessageWith($translator, 'formats.L', $locale, 'MM/DD/YYYY'),\n                    'LL' => static::getTranslationMessageWith($translator, 'formats.LL', $locale, 'MMMM D, YYYY'),\n                    'LLL' => static::getTranslationMessageWith($translator, 'formats.LLL', $locale, 'MMMM D, YYYY h:mm A'),\n                    'LLLL' => static::getTranslationMessageWith($translator, 'formats.LLLL', $locale, 'dddd, MMMM D, YYYY h:mm A'),\n                ];\n            }\n\n            return $formats[$code] ?? preg_replace_callback(\n                '/MMMM|MM|DD|dddd/',\n                function ($code) {\n                    return mb_substr($code[0], 1);\n                },\n                $formats[strtoupper($code)] ?? ''\n            );\n        }, $format);\n\n        $format = preg_replace_callback('/(?<!\\\\\\\\)(\\\\\\\\{2})*('.CarbonInterface::ISO_FORMAT_REGEXP.'|[A-Za-z])/', function ($match) {\n            [$code] = $match;\n\n            static $replacements = null;\n\n            if ($replacements === null) {\n                $replacements = [\n                    'OD' => 'd',\n                    'OM' => 'M',\n                    'OY' => 'Y',\n                    'OH' => 'G',\n                    'Oh' => 'g',\n                    'Om' => 'i',\n                    'Os' => 's',\n                    'D' => 'd',\n                    'DD' => 'd',\n                    'Do' => 'd',\n                    'd' => '!',\n                    'dd' => '!',\n                    'ddd' => 'D',\n                    'dddd' => 'D',\n                    'DDD' => 'z',\n                    'DDDD' => 'z',\n                    'DDDo' => 'z',\n                    'e' => '!',\n                    'E' => '!',\n                    'H' => 'G',\n                    'HH' => 'H',\n                    'h' => 'g',\n                    'hh' => 'h',\n                    'k' => 'G',\n                    'kk' => 'G',\n                    'hmm' => 'gi',\n                    'hmmss' => 'gis',\n                    'Hmm' => 'Gi',\n                    'Hmmss' => 'Gis',\n                    'm' => 'i',\n                    'mm' => 'i',\n                    'a' => 'a',\n                    'A' => 'a',\n                    's' => 's',\n                    'ss' => 's',\n                    'S' => '*',\n                    'SS' => '*',\n                    'SSS' => '*',\n                    'SSSS' => '*',\n                    'SSSSS' => '*',\n                    'SSSSSS' => 'u',\n                    'SSSSSSS' => 'u*',\n                    'SSSSSSSS' => 'u*',\n                    'SSSSSSSSS' => 'u*',\n                    'M' => 'm',\n                    'MM' => 'm',\n                    'MMM' => 'M',\n                    'MMMM' => 'M',\n                    'Mo' => 'm',\n                    'Q' => '!',\n                    'Qo' => '!',\n                    'G' => '!',\n                    'GG' => '!',\n                    'GGG' => '!',\n                    'GGGG' => '!',\n                    'GGGGG' => '!',\n                    'g' => '!',\n                    'gg' => '!',\n                    'ggg' => '!',\n                    'gggg' => '!',\n                    'ggggg' => '!',\n                    'W' => '!',\n                    'WW' => '!',\n                    'Wo' => '!',\n                    'w' => '!',\n                    'ww' => '!',\n                    'wo' => '!',\n                    'x' => 'U???',\n                    'X' => 'U',\n                    'Y' => 'Y',\n                    'YY' => 'y',\n                    'YYYY' => 'Y',\n                    'YYYYY' => 'Y',\n                    'YYYYYY' => 'Y',\n                    'z' => 'e',\n                    'zz' => 'e',\n                    'Z' => 'e',\n                    'ZZ' => 'e',\n                ];\n            }\n\n            $format = $replacements[$code] ?? '?';\n\n            if ($format === '!') {\n                throw new InvalidFormatException(\"Format $code not supported for creation.\");\n            }\n\n            return $format;\n        }, $format);\n\n        return static::rawCreateFromFormat($format, $time, $tz);\n    }\n\n    /**\n     * Create a Carbon instance from a specific format and a string in a given language.\n     *\n     * @param string                         $format Datetime format\n     * @param string                         $locale\n     * @param string                         $time\n     * @param DateTimeZone|string|false|null $tz\n     *\n     * @throws InvalidFormatException\n     *\n     * @return static|false\n     */\n    public static function createFromLocaleFormat($format, $locale, $time, $tz = null)\n    {\n        $format = preg_replace_callback(\n            '/(?:\\\\\\\\[a-zA-Z]|[bfkqCEJKQRV]){2,}/',\n            static function (array $match) use ($locale): string {\n                $word = str_replace('\\\\', '', $match[0]);\n                $translatedWord = static::translateTimeString($word, $locale, 'en');\n\n                return $word === $translatedWord\n                    ? $match[0]\n                    : preg_replace('/[a-zA-Z]/', '\\\\\\\\$0', $translatedWord);\n            },\n            $format\n        );\n\n        return static::rawCreateFromFormat($format, static::translateTimeString($time, $locale, 'en'), $tz);\n    }\n\n    /**\n     * Create a Carbon instance from a specific ISO format and a string in a given language.\n     *\n     * @param string                         $format Datetime ISO format\n     * @param string                         $locale\n     * @param string                         $time\n     * @param DateTimeZone|string|false|null $tz\n     *\n     * @throws InvalidFormatException\n     *\n     * @return static|false\n     */\n    public static function createFromLocaleIsoFormat($format, $locale, $time, $tz = null)\n    {\n        $time = static::translateTimeString($time, $locale, 'en', CarbonInterface::TRANSLATE_MONTHS | CarbonInterface::TRANSLATE_DAYS | CarbonInterface::TRANSLATE_MERIDIEM);\n\n        return static::createFromIsoFormat($format, $time, $tz, $locale);\n    }\n\n    /**\n     * Make a Carbon instance from given variable if possible.\n     *\n     * Always return a new instance. Parse only strings and only these likely to be dates (skip intervals\n     * and recurrences). Throw an exception for invalid format, but otherwise return null.\n     *\n     * @param mixed $var\n     *\n     * @throws InvalidFormatException\n     *\n     * @return static|null\n     */\n    public static function make($var)\n    {\n        if ($var instanceof DateTimeInterface) {\n            return static::instance($var);\n        }\n\n        $date = null;\n\n        if (\\is_string($var)) {\n            $var = trim($var);\n\n            if (!preg_match('/^P[\\dT]/', $var) &&\n                !preg_match('/^R\\d/', $var) &&\n                preg_match('/[a-z\\d]/i', $var)\n            ) {\n                $date = static::parse($var);\n            }\n        }\n\n        return $date;\n    }\n\n    /**\n     * Set last errors.\n     *\n     * @param array|bool $lastErrors\n     *\n     * @return void\n     */\n    private static function setLastErrors($lastErrors)\n    {\n        if (\\is_array($lastErrors) || $lastErrors === false) {\n            static::$lastErrors = \\is_array($lastErrors) ? $lastErrors : [\n                'warning_count' => 0,\n                'warnings' => [],\n                'error_count' => 0,\n                'errors' => [],\n            ];\n        }\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @return array\n     */\n    #[ReturnTypeWillChange]\n    public static function getLastErrors()\n    {\n        return static::$lastErrors;\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Traits/Date.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Traits;\n\nuse BadMethodCallException;\nuse Carbon\\Carbon;\nuse Carbon\\CarbonInterface;\nuse Carbon\\CarbonPeriod;\nuse Carbon\\CarbonTimeZone;\nuse Carbon\\Exceptions\\BadComparisonUnitException;\nuse Carbon\\Exceptions\\ImmutableException;\nuse Carbon\\Exceptions\\InvalidTimeZoneException;\nuse Carbon\\Exceptions\\InvalidTypeException;\nuse Carbon\\Exceptions\\UnknownGetterException;\nuse Carbon\\Exceptions\\UnknownMethodException;\nuse Carbon\\Exceptions\\UnknownSetterException;\nuse Carbon\\Exceptions\\UnknownUnitException;\nuse Closure;\nuse DateInterval;\nuse DatePeriod;\nuse DateTime;\nuse DateTimeImmutable;\nuse DateTimeInterface;\nuse DateTimeZone;\nuse InvalidArgumentException;\nuse ReflectionException;\nuse ReturnTypeWillChange;\nuse Throwable;\n\n/**\n * A simple API extension for DateTime.\n *\n * @mixin DeprecatedProperties\n *\n * <autodoc generated by `composer phpdoc`>\n *\n * @property      int              $year\n * @property      int              $yearIso\n * @property      int              $month\n * @property      int              $day\n * @property      int              $hour\n * @property      int              $minute\n * @property      int              $second\n * @property      int              $micro\n * @property      int              $microsecond\n * @property      int|float|string $timestamp                                                                         seconds since the Unix Epoch\n * @property      string           $englishDayOfWeek                                                                  the day of week in English\n * @property      string           $shortEnglishDayOfWeek                                                             the abbreviated day of week in English\n * @property      string           $englishMonth                                                                      the month in English\n * @property      string           $shortEnglishMonth                                                                 the abbreviated month in English\n * @property      int              $milliseconds\n * @property      int              $millisecond\n * @property      int              $milli\n * @property      int              $week                                                                              1 through 53\n * @property      int              $isoWeek                                                                           1 through 53\n * @property      int              $weekYear                                                                          year according to week format\n * @property      int              $isoWeekYear                                                                       year according to ISO week format\n * @property      int              $dayOfYear                                                                         1 through 366\n * @property      int              $age                                                                               does a diffInYears() with default parameters\n * @property      int              $offset                                                                            the timezone offset in seconds from UTC\n * @property      int              $offsetMinutes                                                                     the timezone offset in minutes from UTC\n * @property      int              $offsetHours                                                                       the timezone offset in hours from UTC\n * @property      CarbonTimeZone   $timezone                                                                          the current timezone\n * @property      CarbonTimeZone   $tz                                                                                alias of $timezone\n * @property-read int              $dayOfWeek                                                                         0 (for Sunday) through 6 (for Saturday)\n * @property-read int              $dayOfWeekIso                                                                      1 (for Monday) through 7 (for Sunday)\n * @property-read int              $weekOfYear                                                                        ISO-8601 week number of year, weeks starting on Monday\n * @property-read int              $daysInMonth                                                                       number of days in the given month\n * @property-read string           $latinMeridiem                                                                     \"am\"/\"pm\" (Ante meridiem or Post meridiem latin lowercase mark)\n * @property-read string           $latinUpperMeridiem                                                                \"AM\"/\"PM\" (Ante meridiem or Post meridiem latin uppercase mark)\n * @property-read string           $timezoneAbbreviatedName                                                           the current timezone abbreviated name\n * @property-read string           $tzAbbrName                                                                        alias of $timezoneAbbreviatedName\n * @property-read string           $dayName                                                                           long name of weekday translated according to Carbon locale, in english if no translation available for current language\n * @property-read string           $shortDayName                                                                      short name of weekday translated according to Carbon locale, in english if no translation available for current language\n * @property-read string           $minDayName                                                                        very short name of weekday translated according to Carbon locale, in english if no translation available for current language\n * @property-read string           $monthName                                                                         long name of month translated according to Carbon locale, in english if no translation available for current language\n * @property-read string           $shortMonthName                                                                    short name of month translated according to Carbon locale, in english if no translation available for current language\n * @property-read string           $meridiem                                                                          lowercase meridiem mark translated according to Carbon locale, in latin if no translation available for current language\n * @property-read string           $upperMeridiem                                                                     uppercase meridiem mark translated according to Carbon locale, in latin if no translation available for current language\n * @property-read int              $noZeroHour                                                                        current hour from 1 to 24\n * @property-read int              $weeksInYear                                                                       51 through 53\n * @property-read int              $isoWeeksInYear                                                                    51 through 53\n * @property-read int              $weekOfMonth                                                                       1 through 5\n * @property-read int              $weekNumberInMonth                                                                 1 through 5\n * @property-read int              $firstWeekDay                                                                      0 through 6\n * @property-read int              $lastWeekDay                                                                       0 through 6\n * @property-read int              $daysInYear                                                                        365 or 366\n * @property-read int              $quarter                                                                           the quarter of this instance, 1 - 4\n * @property-read int              $decade                                                                            the decade of this instance\n * @property-read int              $century                                                                           the century of this instance\n * @property-read int              $millennium                                                                        the millennium of this instance\n * @property-read bool             $dst                                                                               daylight savings time indicator, true if DST, false otherwise\n * @property-read bool             $local                                                                             checks if the timezone is local, true if local, false otherwise\n * @property-read bool             $utc                                                                               checks if the timezone is UTC, true if UTC, false otherwise\n * @property-read string           $timezoneName                                                                      the current timezone name\n * @property-read string           $tzName                                                                            alias of $timezoneName\n * @property-read string           $locale                                                                            locale of the current instance\n *\n * @method        bool             isUtc()                                                                            Check if the current instance has UTC timezone. (Both isUtc and isUTC cases are valid.)\n * @method        bool             isLocal()                                                                          Check if the current instance has non-UTC timezone.\n * @method        bool             isValid()                                                                          Check if the current instance is a valid date.\n * @method        bool             isDST()                                                                            Check if the current instance is in a daylight saving time.\n * @method        bool             isSunday()                                                                         Checks if the instance day is sunday.\n * @method        bool             isMonday()                                                                         Checks if the instance day is monday.\n * @method        bool             isTuesday()                                                                        Checks if the instance day is tuesday.\n * @method        bool             isWednesday()                                                                      Checks if the instance day is wednesday.\n * @method        bool             isThursday()                                                                       Checks if the instance day is thursday.\n * @method        bool             isFriday()                                                                         Checks if the instance day is friday.\n * @method        bool             isSaturday()                                                                       Checks if the instance day is saturday.\n * @method        bool             isSameYear(Carbon|DateTimeInterface|string|null $date = null)                      Checks if the given date is in the same year as the instance. If null passed, compare to now (with the same timezone).\n * @method        bool             isCurrentYear()                                                                    Checks if the instance is in the same year as the current moment.\n * @method        bool             isNextYear()                                                                       Checks if the instance is in the same year as the current moment next year.\n * @method        bool             isLastYear()                                                                       Checks if the instance is in the same year as the current moment last year.\n * @method        bool             isSameWeek(Carbon|DateTimeInterface|string|null $date = null)                      Checks if the given date is in the same week as the instance. If null passed, compare to now (with the same timezone).\n * @method        bool             isCurrentWeek()                                                                    Checks if the instance is in the same week as the current moment.\n * @method        bool             isNextWeek()                                                                       Checks if the instance is in the same week as the current moment next week.\n * @method        bool             isLastWeek()                                                                       Checks if the instance is in the same week as the current moment last week.\n * @method        bool             isSameDay(Carbon|DateTimeInterface|string|null $date = null)                       Checks if the given date is in the same day as the instance. If null passed, compare to now (with the same timezone).\n * @method        bool             isCurrentDay()                                                                     Checks if the instance is in the same day as the current moment.\n * @method        bool             isNextDay()                                                                        Checks if the instance is in the same day as the current moment next day.\n * @method        bool             isLastDay()                                                                        Checks if the instance is in the same day as the current moment last day.\n * @method        bool             isSameHour(Carbon|DateTimeInterface|string|null $date = null)                      Checks if the given date is in the same hour as the instance. If null passed, compare to now (with the same timezone).\n * @method        bool             isCurrentHour()                                                                    Checks if the instance is in the same hour as the current moment.\n * @method        bool             isNextHour()                                                                       Checks if the instance is in the same hour as the current moment next hour.\n * @method        bool             isLastHour()                                                                       Checks if the instance is in the same hour as the current moment last hour.\n * @method        bool             isSameMinute(Carbon|DateTimeInterface|string|null $date = null)                    Checks if the given date is in the same minute as the instance. If null passed, compare to now (with the same timezone).\n * @method        bool             isCurrentMinute()                                                                  Checks if the instance is in the same minute as the current moment.\n * @method        bool             isNextMinute()                                                                     Checks if the instance is in the same minute as the current moment next minute.\n * @method        bool             isLastMinute()                                                                     Checks if the instance is in the same minute as the current moment last minute.\n * @method        bool             isSameSecond(Carbon|DateTimeInterface|string|null $date = null)                    Checks if the given date is in the same second as the instance. If null passed, compare to now (with the same timezone).\n * @method        bool             isCurrentSecond()                                                                  Checks if the instance is in the same second as the current moment.\n * @method        bool             isNextSecond()                                                                     Checks if the instance is in the same second as the current moment next second.\n * @method        bool             isLastSecond()                                                                     Checks if the instance is in the same second as the current moment last second.\n * @method        bool             isSameMicro(Carbon|DateTimeInterface|string|null $date = null)                     Checks if the given date is in the same microsecond as the instance. If null passed, compare to now (with the same timezone).\n * @method        bool             isCurrentMicro()                                                                   Checks if the instance is in the same microsecond as the current moment.\n * @method        bool             isNextMicro()                                                                      Checks if the instance is in the same microsecond as the current moment next microsecond.\n * @method        bool             isLastMicro()                                                                      Checks if the instance is in the same microsecond as the current moment last microsecond.\n * @method        bool             isSameMicrosecond(Carbon|DateTimeInterface|string|null $date = null)               Checks if the given date is in the same microsecond as the instance. If null passed, compare to now (with the same timezone).\n * @method        bool             isCurrentMicrosecond()                                                             Checks if the instance is in the same microsecond as the current moment.\n * @method        bool             isNextMicrosecond()                                                                Checks if the instance is in the same microsecond as the current moment next microsecond.\n * @method        bool             isLastMicrosecond()                                                                Checks if the instance is in the same microsecond as the current moment last microsecond.\n * @method        bool             isCurrentMonth()                                                                   Checks if the instance is in the same month as the current moment.\n * @method        bool             isNextMonth()                                                                      Checks if the instance is in the same month as the current moment next month.\n * @method        bool             isLastMonth()                                                                      Checks if the instance is in the same month as the current moment last month.\n * @method        bool             isCurrentQuarter()                                                                 Checks if the instance is in the same quarter as the current moment.\n * @method        bool             isNextQuarter()                                                                    Checks if the instance is in the same quarter as the current moment next quarter.\n * @method        bool             isLastQuarter()                                                                    Checks if the instance is in the same quarter as the current moment last quarter.\n * @method        bool             isSameDecade(Carbon|DateTimeInterface|string|null $date = null)                    Checks if the given date is in the same decade as the instance. If null passed, compare to now (with the same timezone).\n * @method        bool             isCurrentDecade()                                                                  Checks if the instance is in the same decade as the current moment.\n * @method        bool             isNextDecade()                                                                     Checks if the instance is in the same decade as the current moment next decade.\n * @method        bool             isLastDecade()                                                                     Checks if the instance is in the same decade as the current moment last decade.\n * @method        bool             isSameCentury(Carbon|DateTimeInterface|string|null $date = null)                   Checks if the given date is in the same century as the instance. If null passed, compare to now (with the same timezone).\n * @method        bool             isCurrentCentury()                                                                 Checks if the instance is in the same century as the current moment.\n * @method        bool             isNextCentury()                                                                    Checks if the instance is in the same century as the current moment next century.\n * @method        bool             isLastCentury()                                                                    Checks if the instance is in the same century as the current moment last century.\n * @method        bool             isSameMillennium(Carbon|DateTimeInterface|string|null $date = null)                Checks if the given date is in the same millennium as the instance. If null passed, compare to now (with the same timezone).\n * @method        bool             isCurrentMillennium()                                                              Checks if the instance is in the same millennium as the current moment.\n * @method        bool             isNextMillennium()                                                                 Checks if the instance is in the same millennium as the current moment next millennium.\n * @method        bool             isLastMillennium()                                                                 Checks if the instance is in the same millennium as the current moment last millennium.\n * @method        CarbonInterface  years(int $value)                                                                  Set current instance year to the given value.\n * @method        CarbonInterface  year(int $value)                                                                   Set current instance year to the given value.\n * @method        CarbonInterface  setYears(int $value)                                                               Set current instance year to the given value.\n * @method        CarbonInterface  setYear(int $value)                                                                Set current instance year to the given value.\n * @method        CarbonInterface  months(int $value)                                                                 Set current instance month to the given value.\n * @method        CarbonInterface  month(int $value)                                                                  Set current instance month to the given value.\n * @method        CarbonInterface  setMonths(int $value)                                                              Set current instance month to the given value.\n * @method        CarbonInterface  setMonth(int $value)                                                               Set current instance month to the given value.\n * @method        CarbonInterface  days(int $value)                                                                   Set current instance day to the given value.\n * @method        CarbonInterface  day(int $value)                                                                    Set current instance day to the given value.\n * @method        CarbonInterface  setDays(int $value)                                                                Set current instance day to the given value.\n * @method        CarbonInterface  setDay(int $value)                                                                 Set current instance day to the given value.\n * @method        CarbonInterface  hours(int $value)                                                                  Set current instance hour to the given value.\n * @method        CarbonInterface  hour(int $value)                                                                   Set current instance hour to the given value.\n * @method        CarbonInterface  setHours(int $value)                                                               Set current instance hour to the given value.\n * @method        CarbonInterface  setHour(int $value)                                                                Set current instance hour to the given value.\n * @method        CarbonInterface  minutes(int $value)                                                                Set current instance minute to the given value.\n * @method        CarbonInterface  minute(int $value)                                                                 Set current instance minute to the given value.\n * @method        CarbonInterface  setMinutes(int $value)                                                             Set current instance minute to the given value.\n * @method        CarbonInterface  setMinute(int $value)                                                              Set current instance minute to the given value.\n * @method        CarbonInterface  seconds(int $value)                                                                Set current instance second to the given value.\n * @method        CarbonInterface  second(int $value)                                                                 Set current instance second to the given value.\n * @method        CarbonInterface  setSeconds(int $value)                                                             Set current instance second to the given value.\n * @method        CarbonInterface  setSecond(int $value)                                                              Set current instance second to the given value.\n * @method        CarbonInterface  millis(int $value)                                                                 Set current instance millisecond to the given value.\n * @method        CarbonInterface  milli(int $value)                                                                  Set current instance millisecond to the given value.\n * @method        CarbonInterface  setMillis(int $value)                                                              Set current instance millisecond to the given value.\n * @method        CarbonInterface  setMilli(int $value)                                                               Set current instance millisecond to the given value.\n * @method        CarbonInterface  milliseconds(int $value)                                                           Set current instance millisecond to the given value.\n * @method        CarbonInterface  millisecond(int $value)                                                            Set current instance millisecond to the given value.\n * @method        CarbonInterface  setMilliseconds(int $value)                                                        Set current instance millisecond to the given value.\n * @method        CarbonInterface  setMillisecond(int $value)                                                         Set current instance millisecond to the given value.\n * @method        CarbonInterface  micros(int $value)                                                                 Set current instance microsecond to the given value.\n * @method        CarbonInterface  micro(int $value)                                                                  Set current instance microsecond to the given value.\n * @method        CarbonInterface  setMicros(int $value)                                                              Set current instance microsecond to the given value.\n * @method        CarbonInterface  setMicro(int $value)                                                               Set current instance microsecond to the given value.\n * @method        CarbonInterface  microseconds(int $value)                                                           Set current instance microsecond to the given value.\n * @method        CarbonInterface  microsecond(int $value)                                                            Set current instance microsecond to the given value.\n * @method        CarbonInterface  setMicroseconds(int $value)                                                        Set current instance microsecond to the given value.\n * @method        CarbonInterface  setMicrosecond(int $value)                                                         Set current instance microsecond to the given value.\n * @method        CarbonInterface  addYears(int $value = 1)                                                           Add years (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  addYear()                                                                          Add one year to the instance (using date interval).\n * @method        CarbonInterface  subYears(int $value = 1)                                                           Sub years (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  subYear()                                                                          Sub one year to the instance (using date interval).\n * @method        CarbonInterface  addYearsWithOverflow(int $value = 1)                                               Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonInterface  addYearWithOverflow()                                                              Add one year to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonInterface  subYearsWithOverflow(int $value = 1)                                               Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonInterface  subYearWithOverflow()                                                              Sub one year to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonInterface  addYearsWithoutOverflow(int $value = 1)                                            Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addYearWithoutOverflow()                                                           Add one year to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subYearsWithoutOverflow(int $value = 1)                                            Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subYearWithoutOverflow()                                                           Sub one year to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addYearsWithNoOverflow(int $value = 1)                                             Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addYearWithNoOverflow()                                                            Add one year to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subYearsWithNoOverflow(int $value = 1)                                             Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subYearWithNoOverflow()                                                            Sub one year to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addYearsNoOverflow(int $value = 1)                                                 Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addYearNoOverflow()                                                                Add one year to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subYearsNoOverflow(int $value = 1)                                                 Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subYearNoOverflow()                                                                Sub one year to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addMonths(int $value = 1)                                                          Add months (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  addMonth()                                                                         Add one month to the instance (using date interval).\n * @method        CarbonInterface  subMonths(int $value = 1)                                                          Sub months (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  subMonth()                                                                         Sub one month to the instance (using date interval).\n * @method        CarbonInterface  addMonthsWithOverflow(int $value = 1)                                              Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonInterface  addMonthWithOverflow()                                                             Add one month to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonInterface  subMonthsWithOverflow(int $value = 1)                                              Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonInterface  subMonthWithOverflow()                                                             Sub one month to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonInterface  addMonthsWithoutOverflow(int $value = 1)                                           Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addMonthWithoutOverflow()                                                          Add one month to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subMonthsWithoutOverflow(int $value = 1)                                           Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subMonthWithoutOverflow()                                                          Sub one month to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addMonthsWithNoOverflow(int $value = 1)                                            Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addMonthWithNoOverflow()                                                           Add one month to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subMonthsWithNoOverflow(int $value = 1)                                            Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subMonthWithNoOverflow()                                                           Sub one month to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addMonthsNoOverflow(int $value = 1)                                                Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addMonthNoOverflow()                                                               Add one month to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subMonthsNoOverflow(int $value = 1)                                                Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subMonthNoOverflow()                                                               Sub one month to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addDays(int $value = 1)                                                            Add days (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  addDay()                                                                           Add one day to the instance (using date interval).\n * @method        CarbonInterface  subDays(int $value = 1)                                                            Sub days (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  subDay()                                                                           Sub one day to the instance (using date interval).\n * @method        CarbonInterface  addHours(int $value = 1)                                                           Add hours (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  addHour()                                                                          Add one hour to the instance (using date interval).\n * @method        CarbonInterface  subHours(int $value = 1)                                                           Sub hours (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  subHour()                                                                          Sub one hour to the instance (using date interval).\n * @method        CarbonInterface  addMinutes(int $value = 1)                                                         Add minutes (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  addMinute()                                                                        Add one minute to the instance (using date interval).\n * @method        CarbonInterface  subMinutes(int $value = 1)                                                         Sub minutes (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  subMinute()                                                                        Sub one minute to the instance (using date interval).\n * @method        CarbonInterface  addSeconds(int $value = 1)                                                         Add seconds (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  addSecond()                                                                        Add one second to the instance (using date interval).\n * @method        CarbonInterface  subSeconds(int $value = 1)                                                         Sub seconds (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  subSecond()                                                                        Sub one second to the instance (using date interval).\n * @method        CarbonInterface  addMillis(int $value = 1)                                                          Add milliseconds (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  addMilli()                                                                         Add one millisecond to the instance (using date interval).\n * @method        CarbonInterface  subMillis(int $value = 1)                                                          Sub milliseconds (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  subMilli()                                                                         Sub one millisecond to the instance (using date interval).\n * @method        CarbonInterface  addMilliseconds(int $value = 1)                                                    Add milliseconds (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  addMillisecond()                                                                   Add one millisecond to the instance (using date interval).\n * @method        CarbonInterface  subMilliseconds(int $value = 1)                                                    Sub milliseconds (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  subMillisecond()                                                                   Sub one millisecond to the instance (using date interval).\n * @method        CarbonInterface  addMicros(int $value = 1)                                                          Add microseconds (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  addMicro()                                                                         Add one microsecond to the instance (using date interval).\n * @method        CarbonInterface  subMicros(int $value = 1)                                                          Sub microseconds (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  subMicro()                                                                         Sub one microsecond to the instance (using date interval).\n * @method        CarbonInterface  addMicroseconds(int $value = 1)                                                    Add microseconds (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  addMicrosecond()                                                                   Add one microsecond to the instance (using date interval).\n * @method        CarbonInterface  subMicroseconds(int $value = 1)                                                    Sub microseconds (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  subMicrosecond()                                                                   Sub one microsecond to the instance (using date interval).\n * @method        CarbonInterface  addMillennia(int $value = 1)                                                       Add millennia (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  addMillennium()                                                                    Add one millennium to the instance (using date interval).\n * @method        CarbonInterface  subMillennia(int $value = 1)                                                       Sub millennia (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  subMillennium()                                                                    Sub one millennium to the instance (using date interval).\n * @method        CarbonInterface  addMillenniaWithOverflow(int $value = 1)                                           Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonInterface  addMillenniumWithOverflow()                                                        Add one millennium to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonInterface  subMillenniaWithOverflow(int $value = 1)                                           Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonInterface  subMillenniumWithOverflow()                                                        Sub one millennium to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonInterface  addMillenniaWithoutOverflow(int $value = 1)                                        Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addMillenniumWithoutOverflow()                                                     Add one millennium to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subMillenniaWithoutOverflow(int $value = 1)                                        Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subMillenniumWithoutOverflow()                                                     Sub one millennium to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addMillenniaWithNoOverflow(int $value = 1)                                         Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addMillenniumWithNoOverflow()                                                      Add one millennium to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subMillenniaWithNoOverflow(int $value = 1)                                         Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subMillenniumWithNoOverflow()                                                      Sub one millennium to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addMillenniaNoOverflow(int $value = 1)                                             Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addMillenniumNoOverflow()                                                          Add one millennium to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subMillenniaNoOverflow(int $value = 1)                                             Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subMillenniumNoOverflow()                                                          Sub one millennium to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addCenturies(int $value = 1)                                                       Add centuries (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  addCentury()                                                                       Add one century to the instance (using date interval).\n * @method        CarbonInterface  subCenturies(int $value = 1)                                                       Sub centuries (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  subCentury()                                                                       Sub one century to the instance (using date interval).\n * @method        CarbonInterface  addCenturiesWithOverflow(int $value = 1)                                           Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonInterface  addCenturyWithOverflow()                                                           Add one century to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonInterface  subCenturiesWithOverflow(int $value = 1)                                           Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonInterface  subCenturyWithOverflow()                                                           Sub one century to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonInterface  addCenturiesWithoutOverflow(int $value = 1)                                        Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addCenturyWithoutOverflow()                                                        Add one century to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subCenturiesWithoutOverflow(int $value = 1)                                        Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subCenturyWithoutOverflow()                                                        Sub one century to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addCenturiesWithNoOverflow(int $value = 1)                                         Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addCenturyWithNoOverflow()                                                         Add one century to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subCenturiesWithNoOverflow(int $value = 1)                                         Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subCenturyWithNoOverflow()                                                         Sub one century to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addCenturiesNoOverflow(int $value = 1)                                             Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addCenturyNoOverflow()                                                             Add one century to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subCenturiesNoOverflow(int $value = 1)                                             Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subCenturyNoOverflow()                                                             Sub one century to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addDecades(int $value = 1)                                                         Add decades (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  addDecade()                                                                        Add one decade to the instance (using date interval).\n * @method        CarbonInterface  subDecades(int $value = 1)                                                         Sub decades (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  subDecade()                                                                        Sub one decade to the instance (using date interval).\n * @method        CarbonInterface  addDecadesWithOverflow(int $value = 1)                                             Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonInterface  addDecadeWithOverflow()                                                            Add one decade to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonInterface  subDecadesWithOverflow(int $value = 1)                                             Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonInterface  subDecadeWithOverflow()                                                            Sub one decade to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonInterface  addDecadesWithoutOverflow(int $value = 1)                                          Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addDecadeWithoutOverflow()                                                         Add one decade to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subDecadesWithoutOverflow(int $value = 1)                                          Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subDecadeWithoutOverflow()                                                         Sub one decade to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addDecadesWithNoOverflow(int $value = 1)                                           Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addDecadeWithNoOverflow()                                                          Add one decade to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subDecadesWithNoOverflow(int $value = 1)                                           Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subDecadeWithNoOverflow()                                                          Sub one decade to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addDecadesNoOverflow(int $value = 1)                                               Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addDecadeNoOverflow()                                                              Add one decade to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subDecadesNoOverflow(int $value = 1)                                               Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subDecadeNoOverflow()                                                              Sub one decade to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addQuarters(int $value = 1)                                                        Add quarters (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  addQuarter()                                                                       Add one quarter to the instance (using date interval).\n * @method        CarbonInterface  subQuarters(int $value = 1)                                                        Sub quarters (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  subQuarter()                                                                       Sub one quarter to the instance (using date interval).\n * @method        CarbonInterface  addQuartersWithOverflow(int $value = 1)                                            Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonInterface  addQuarterWithOverflow()                                                           Add one quarter to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonInterface  subQuartersWithOverflow(int $value = 1)                                            Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonInterface  subQuarterWithOverflow()                                                           Sub one quarter to the instance (using date interval) with overflow explicitly allowed.\n * @method        CarbonInterface  addQuartersWithoutOverflow(int $value = 1)                                         Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addQuarterWithoutOverflow()                                                        Add one quarter to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subQuartersWithoutOverflow(int $value = 1)                                         Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subQuarterWithoutOverflow()                                                        Sub one quarter to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addQuartersWithNoOverflow(int $value = 1)                                          Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addQuarterWithNoOverflow()                                                         Add one quarter to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subQuartersWithNoOverflow(int $value = 1)                                          Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subQuarterWithNoOverflow()                                                         Sub one quarter to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addQuartersNoOverflow(int $value = 1)                                              Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addQuarterNoOverflow()                                                             Add one quarter to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subQuartersNoOverflow(int $value = 1)                                              Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  subQuarterNoOverflow()                                                             Sub one quarter to the instance (using date interval) with overflow explicitly forbidden.\n * @method        CarbonInterface  addWeeks(int $value = 1)                                                           Add weeks (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  addWeek()                                                                          Add one week to the instance (using date interval).\n * @method        CarbonInterface  subWeeks(int $value = 1)                                                           Sub weeks (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  subWeek()                                                                          Sub one week to the instance (using date interval).\n * @method        CarbonInterface  addWeekdays(int $value = 1)                                                        Add weekdays (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  addWeekday()                                                                       Add one weekday to the instance (using date interval).\n * @method        CarbonInterface  subWeekdays(int $value = 1)                                                        Sub weekdays (the $value count passed in) to the instance (using date interval).\n * @method        CarbonInterface  subWeekday()                                                                       Sub one weekday to the instance (using date interval).\n * @method        CarbonInterface  addRealMicros(int $value = 1)                                                      Add microseconds (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  addRealMicro()                                                                     Add one microsecond to the instance (using timestamp).\n * @method        CarbonInterface  subRealMicros(int $value = 1)                                                      Sub microseconds (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  subRealMicro()                                                                     Sub one microsecond to the instance (using timestamp).\n * @method        CarbonPeriod     microsUntil($endDate = null, int $factor = 1)                                      Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each microsecond or every X microseconds if a factor is given.\n * @method        CarbonInterface  addRealMicroseconds(int $value = 1)                                                Add microseconds (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  addRealMicrosecond()                                                               Add one microsecond to the instance (using timestamp).\n * @method        CarbonInterface  subRealMicroseconds(int $value = 1)                                                Sub microseconds (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  subRealMicrosecond()                                                               Sub one microsecond to the instance (using timestamp).\n * @method        CarbonPeriod     microsecondsUntil($endDate = null, int $factor = 1)                                Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each microsecond or every X microseconds if a factor is given.\n * @method        CarbonInterface  addRealMillis(int $value = 1)                                                      Add milliseconds (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  addRealMilli()                                                                     Add one millisecond to the instance (using timestamp).\n * @method        CarbonInterface  subRealMillis(int $value = 1)                                                      Sub milliseconds (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  subRealMilli()                                                                     Sub one millisecond to the instance (using timestamp).\n * @method        CarbonPeriod     millisUntil($endDate = null, int $factor = 1)                                      Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each millisecond or every X milliseconds if a factor is given.\n * @method        CarbonInterface  addRealMilliseconds(int $value = 1)                                                Add milliseconds (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  addRealMillisecond()                                                               Add one millisecond to the instance (using timestamp).\n * @method        CarbonInterface  subRealMilliseconds(int $value = 1)                                                Sub milliseconds (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  subRealMillisecond()                                                               Sub one millisecond to the instance (using timestamp).\n * @method        CarbonPeriod     millisecondsUntil($endDate = null, int $factor = 1)                                Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each millisecond or every X milliseconds if a factor is given.\n * @method        CarbonInterface  addRealSeconds(int $value = 1)                                                     Add seconds (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  addRealSecond()                                                                    Add one second to the instance (using timestamp).\n * @method        CarbonInterface  subRealSeconds(int $value = 1)                                                     Sub seconds (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  subRealSecond()                                                                    Sub one second to the instance (using timestamp).\n * @method        CarbonPeriod     secondsUntil($endDate = null, int $factor = 1)                                     Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each second or every X seconds if a factor is given.\n * @method        CarbonInterface  addRealMinutes(int $value = 1)                                                     Add minutes (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  addRealMinute()                                                                    Add one minute to the instance (using timestamp).\n * @method        CarbonInterface  subRealMinutes(int $value = 1)                                                     Sub minutes (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  subRealMinute()                                                                    Sub one minute to the instance (using timestamp).\n * @method        CarbonPeriod     minutesUntil($endDate = null, int $factor = 1)                                     Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each minute or every X minutes if a factor is given.\n * @method        CarbonInterface  addRealHours(int $value = 1)                                                       Add hours (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  addRealHour()                                                                      Add one hour to the instance (using timestamp).\n * @method        CarbonInterface  subRealHours(int $value = 1)                                                       Sub hours (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  subRealHour()                                                                      Sub one hour to the instance (using timestamp).\n * @method        CarbonPeriod     hoursUntil($endDate = null, int $factor = 1)                                       Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each hour or every X hours if a factor is given.\n * @method        CarbonInterface  addRealDays(int $value = 1)                                                        Add days (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  addRealDay()                                                                       Add one day to the instance (using timestamp).\n * @method        CarbonInterface  subRealDays(int $value = 1)                                                        Sub days (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  subRealDay()                                                                       Sub one day to the instance (using timestamp).\n * @method        CarbonPeriod     daysUntil($endDate = null, int $factor = 1)                                        Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each day or every X days if a factor is given.\n * @method        CarbonInterface  addRealWeeks(int $value = 1)                                                       Add weeks (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  addRealWeek()                                                                      Add one week to the instance (using timestamp).\n * @method        CarbonInterface  subRealWeeks(int $value = 1)                                                       Sub weeks (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  subRealWeek()                                                                      Sub one week to the instance (using timestamp).\n * @method        CarbonPeriod     weeksUntil($endDate = null, int $factor = 1)                                       Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each week or every X weeks if a factor is given.\n * @method        CarbonInterface  addRealMonths(int $value = 1)                                                      Add months (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  addRealMonth()                                                                     Add one month to the instance (using timestamp).\n * @method        CarbonInterface  subRealMonths(int $value = 1)                                                      Sub months (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  subRealMonth()                                                                     Sub one month to the instance (using timestamp).\n * @method        CarbonPeriod     monthsUntil($endDate = null, int $factor = 1)                                      Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each month or every X months if a factor is given.\n * @method        CarbonInterface  addRealQuarters(int $value = 1)                                                    Add quarters (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  addRealQuarter()                                                                   Add one quarter to the instance (using timestamp).\n * @method        CarbonInterface  subRealQuarters(int $value = 1)                                                    Sub quarters (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  subRealQuarter()                                                                   Sub one quarter to the instance (using timestamp).\n * @method        CarbonPeriod     quartersUntil($endDate = null, int $factor = 1)                                    Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each quarter or every X quarters if a factor is given.\n * @method        CarbonInterface  addRealYears(int $value = 1)                                                       Add years (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  addRealYear()                                                                      Add one year to the instance (using timestamp).\n * @method        CarbonInterface  subRealYears(int $value = 1)                                                       Sub years (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  subRealYear()                                                                      Sub one year to the instance (using timestamp).\n * @method        CarbonPeriod     yearsUntil($endDate = null, int $factor = 1)                                       Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each year or every X years if a factor is given.\n * @method        CarbonInterface  addRealDecades(int $value = 1)                                                     Add decades (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  addRealDecade()                                                                    Add one decade to the instance (using timestamp).\n * @method        CarbonInterface  subRealDecades(int $value = 1)                                                     Sub decades (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  subRealDecade()                                                                    Sub one decade to the instance (using timestamp).\n * @method        CarbonPeriod     decadesUntil($endDate = null, int $factor = 1)                                     Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each decade or every X decades if a factor is given.\n * @method        CarbonInterface  addRealCenturies(int $value = 1)                                                   Add centuries (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  addRealCentury()                                                                   Add one century to the instance (using timestamp).\n * @method        CarbonInterface  subRealCenturies(int $value = 1)                                                   Sub centuries (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  subRealCentury()                                                                   Sub one century to the instance (using timestamp).\n * @method        CarbonPeriod     centuriesUntil($endDate = null, int $factor = 1)                                   Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each century or every X centuries if a factor is given.\n * @method        CarbonInterface  addRealMillennia(int $value = 1)                                                   Add millennia (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  addRealMillennium()                                                                Add one millennium to the instance (using timestamp).\n * @method        CarbonInterface  subRealMillennia(int $value = 1)                                                   Sub millennia (the $value count passed in) to the instance (using timestamp).\n * @method        CarbonInterface  subRealMillennium()                                                                Sub one millennium to the instance (using timestamp).\n * @method        CarbonPeriod     millenniaUntil($endDate = null, int $factor = 1)                                   Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each millennium or every X millennia if a factor is given.\n * @method        CarbonInterface  roundYear(float $precision = 1, string $function = \"round\")                        Round the current instance year with given precision using the given function.\n * @method        CarbonInterface  roundYears(float $precision = 1, string $function = \"round\")                       Round the current instance year with given precision using the given function.\n * @method        CarbonInterface  floorYear(float $precision = 1)                                                    Truncate the current instance year with given precision.\n * @method        CarbonInterface  floorYears(float $precision = 1)                                                   Truncate the current instance year with given precision.\n * @method        CarbonInterface  ceilYear(float $precision = 1)                                                     Ceil the current instance year with given precision.\n * @method        CarbonInterface  ceilYears(float $precision = 1)                                                    Ceil the current instance year with given precision.\n * @method        CarbonInterface  roundMonth(float $precision = 1, string $function = \"round\")                       Round the current instance month with given precision using the given function.\n * @method        CarbonInterface  roundMonths(float $precision = 1, string $function = \"round\")                      Round the current instance month with given precision using the given function.\n * @method        CarbonInterface  floorMonth(float $precision = 1)                                                   Truncate the current instance month with given precision.\n * @method        CarbonInterface  floorMonths(float $precision = 1)                                                  Truncate the current instance month with given precision.\n * @method        CarbonInterface  ceilMonth(float $precision = 1)                                                    Ceil the current instance month with given precision.\n * @method        CarbonInterface  ceilMonths(float $precision = 1)                                                   Ceil the current instance month with given precision.\n * @method        CarbonInterface  roundDay(float $precision = 1, string $function = \"round\")                         Round the current instance day with given precision using the given function.\n * @method        CarbonInterface  roundDays(float $precision = 1, string $function = \"round\")                        Round the current instance day with given precision using the given function.\n * @method        CarbonInterface  floorDay(float $precision = 1)                                                     Truncate the current instance day with given precision.\n * @method        CarbonInterface  floorDays(float $precision = 1)                                                    Truncate the current instance day with given precision.\n * @method        CarbonInterface  ceilDay(float $precision = 1)                                                      Ceil the current instance day with given precision.\n * @method        CarbonInterface  ceilDays(float $precision = 1)                                                     Ceil the current instance day with given precision.\n * @method        CarbonInterface  roundHour(float $precision = 1, string $function = \"round\")                        Round the current instance hour with given precision using the given function.\n * @method        CarbonInterface  roundHours(float $precision = 1, string $function = \"round\")                       Round the current instance hour with given precision using the given function.\n * @method        CarbonInterface  floorHour(float $precision = 1)                                                    Truncate the current instance hour with given precision.\n * @method        CarbonInterface  floorHours(float $precision = 1)                                                   Truncate the current instance hour with given precision.\n * @method        CarbonInterface  ceilHour(float $precision = 1)                                                     Ceil the current instance hour with given precision.\n * @method        CarbonInterface  ceilHours(float $precision = 1)                                                    Ceil the current instance hour with given precision.\n * @method        CarbonInterface  roundMinute(float $precision = 1, string $function = \"round\")                      Round the current instance minute with given precision using the given function.\n * @method        CarbonInterface  roundMinutes(float $precision = 1, string $function = \"round\")                     Round the current instance minute with given precision using the given function.\n * @method        CarbonInterface  floorMinute(float $precision = 1)                                                  Truncate the current instance minute with given precision.\n * @method        CarbonInterface  floorMinutes(float $precision = 1)                                                 Truncate the current instance minute with given precision.\n * @method        CarbonInterface  ceilMinute(float $precision = 1)                                                   Ceil the current instance minute with given precision.\n * @method        CarbonInterface  ceilMinutes(float $precision = 1)                                                  Ceil the current instance minute with given precision.\n * @method        CarbonInterface  roundSecond(float $precision = 1, string $function = \"round\")                      Round the current instance second with given precision using the given function.\n * @method        CarbonInterface  roundSeconds(float $precision = 1, string $function = \"round\")                     Round the current instance second with given precision using the given function.\n * @method        CarbonInterface  floorSecond(float $precision = 1)                                                  Truncate the current instance second with given precision.\n * @method        CarbonInterface  floorSeconds(float $precision = 1)                                                 Truncate the current instance second with given precision.\n * @method        CarbonInterface  ceilSecond(float $precision = 1)                                                   Ceil the current instance second with given precision.\n * @method        CarbonInterface  ceilSeconds(float $precision = 1)                                                  Ceil the current instance second with given precision.\n * @method        CarbonInterface  roundMillennium(float $precision = 1, string $function = \"round\")                  Round the current instance millennium with given precision using the given function.\n * @method        CarbonInterface  roundMillennia(float $precision = 1, string $function = \"round\")                   Round the current instance millennium with given precision using the given function.\n * @method        CarbonInterface  floorMillennium(float $precision = 1)                                              Truncate the current instance millennium with given precision.\n * @method        CarbonInterface  floorMillennia(float $precision = 1)                                               Truncate the current instance millennium with given precision.\n * @method        CarbonInterface  ceilMillennium(float $precision = 1)                                               Ceil the current instance millennium with given precision.\n * @method        CarbonInterface  ceilMillennia(float $precision = 1)                                                Ceil the current instance millennium with given precision.\n * @method        CarbonInterface  roundCentury(float $precision = 1, string $function = \"round\")                     Round the current instance century with given precision using the given function.\n * @method        CarbonInterface  roundCenturies(float $precision = 1, string $function = \"round\")                   Round the current instance century with given precision using the given function.\n * @method        CarbonInterface  floorCentury(float $precision = 1)                                                 Truncate the current instance century with given precision.\n * @method        CarbonInterface  floorCenturies(float $precision = 1)                                               Truncate the current instance century with given precision.\n * @method        CarbonInterface  ceilCentury(float $precision = 1)                                                  Ceil the current instance century with given precision.\n * @method        CarbonInterface  ceilCenturies(float $precision = 1)                                                Ceil the current instance century with given precision.\n * @method        CarbonInterface  roundDecade(float $precision = 1, string $function = \"round\")                      Round the current instance decade with given precision using the given function.\n * @method        CarbonInterface  roundDecades(float $precision = 1, string $function = \"round\")                     Round the current instance decade with given precision using the given function.\n * @method        CarbonInterface  floorDecade(float $precision = 1)                                                  Truncate the current instance decade with given precision.\n * @method        CarbonInterface  floorDecades(float $precision = 1)                                                 Truncate the current instance decade with given precision.\n * @method        CarbonInterface  ceilDecade(float $precision = 1)                                                   Ceil the current instance decade with given precision.\n * @method        CarbonInterface  ceilDecades(float $precision = 1)                                                  Ceil the current instance decade with given precision.\n * @method        CarbonInterface  roundQuarter(float $precision = 1, string $function = \"round\")                     Round the current instance quarter with given precision using the given function.\n * @method        CarbonInterface  roundQuarters(float $precision = 1, string $function = \"round\")                    Round the current instance quarter with given precision using the given function.\n * @method        CarbonInterface  floorQuarter(float $precision = 1)                                                 Truncate the current instance quarter with given precision.\n * @method        CarbonInterface  floorQuarters(float $precision = 1)                                                Truncate the current instance quarter with given precision.\n * @method        CarbonInterface  ceilQuarter(float $precision = 1)                                                  Ceil the current instance quarter with given precision.\n * @method        CarbonInterface  ceilQuarters(float $precision = 1)                                                 Ceil the current instance quarter with given precision.\n * @method        CarbonInterface  roundMillisecond(float $precision = 1, string $function = \"round\")                 Round the current instance millisecond with given precision using the given function.\n * @method        CarbonInterface  roundMilliseconds(float $precision = 1, string $function = \"round\")                Round the current instance millisecond with given precision using the given function.\n * @method        CarbonInterface  floorMillisecond(float $precision = 1)                                             Truncate the current instance millisecond with given precision.\n * @method        CarbonInterface  floorMilliseconds(float $precision = 1)                                            Truncate the current instance millisecond with given precision.\n * @method        CarbonInterface  ceilMillisecond(float $precision = 1)                                              Ceil the current instance millisecond with given precision.\n * @method        CarbonInterface  ceilMilliseconds(float $precision = 1)                                             Ceil the current instance millisecond with given precision.\n * @method        CarbonInterface  roundMicrosecond(float $precision = 1, string $function = \"round\")                 Round the current instance microsecond with given precision using the given function.\n * @method        CarbonInterface  roundMicroseconds(float $precision = 1, string $function = \"round\")                Round the current instance microsecond with given precision using the given function.\n * @method        CarbonInterface  floorMicrosecond(float $precision = 1)                                             Truncate the current instance microsecond with given precision.\n * @method        CarbonInterface  floorMicroseconds(float $precision = 1)                                            Truncate the current instance microsecond with given precision.\n * @method        CarbonInterface  ceilMicrosecond(float $precision = 1)                                              Ceil the current instance microsecond with given precision.\n * @method        CarbonInterface  ceilMicroseconds(float $precision = 1)                                             Ceil the current instance microsecond with given precision.\n * @method        string           shortAbsoluteDiffForHumans(DateTimeInterface $other = null, int $parts = 1)        Get the difference (short format, 'Absolute' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.)\n * @method        string           longAbsoluteDiffForHumans(DateTimeInterface $other = null, int $parts = 1)         Get the difference (long format, 'Absolute' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.)\n * @method        string           shortRelativeDiffForHumans(DateTimeInterface $other = null, int $parts = 1)        Get the difference (short format, 'Relative' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.)\n * @method        string           longRelativeDiffForHumans(DateTimeInterface $other = null, int $parts = 1)         Get the difference (long format, 'Relative' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.)\n * @method        string           shortRelativeToNowDiffForHumans(DateTimeInterface $other = null, int $parts = 1)   Get the difference (short format, 'RelativeToNow' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.)\n * @method        string           longRelativeToNowDiffForHumans(DateTimeInterface $other = null, int $parts = 1)    Get the difference (long format, 'RelativeToNow' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.)\n * @method        string           shortRelativeToOtherDiffForHumans(DateTimeInterface $other = null, int $parts = 1) Get the difference (short format, 'RelativeToOther' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.)\n * @method        string           longRelativeToOtherDiffForHumans(DateTimeInterface $other = null, int $parts = 1)  Get the difference (long format, 'RelativeToOther' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.)\n *\n * </autodoc>\n */\ntrait Date\n{\n    use Boundaries;\n    use Comparison;\n    use Converter;\n    use Creator;\n    use Difference;\n    use Macro;\n    use MagicParameter;\n    use Modifiers;\n    use Mutability;\n    use ObjectInitialisation;\n    use Options;\n    use Rounding;\n    use Serialization;\n    use Test;\n    use Timestamp;\n    use Units;\n    use Week;\n\n    /**\n     * Names of days of the week.\n     *\n     * @var array\n     */\n    protected static $days = [\n        // @call isDayOfWeek\n        CarbonInterface::SUNDAY => 'Sunday',\n        // @call isDayOfWeek\n        CarbonInterface::MONDAY => 'Monday',\n        // @call isDayOfWeek\n        CarbonInterface::TUESDAY => 'Tuesday',\n        // @call isDayOfWeek\n        CarbonInterface::WEDNESDAY => 'Wednesday',\n        // @call isDayOfWeek\n        CarbonInterface::THURSDAY => 'Thursday',\n        // @call isDayOfWeek\n        CarbonInterface::FRIDAY => 'Friday',\n        // @call isDayOfWeek\n        CarbonInterface::SATURDAY => 'Saturday',\n    ];\n\n    /**\n     * Will UTF8 encoding be used to print localized date/time ?\n     *\n     * @var bool\n     */\n    protected static $utf8 = false;\n\n    /**\n     * List of unit and magic methods associated as doc-comments.\n     *\n     * @var array\n     */\n    protected static $units = [\n        // @call setUnit\n        // @call addUnit\n        'year',\n        // @call setUnit\n        // @call addUnit\n        'month',\n        // @call setUnit\n        // @call addUnit\n        'day',\n        // @call setUnit\n        // @call addUnit\n        'hour',\n        // @call setUnit\n        // @call addUnit\n        'minute',\n        // @call setUnit\n        // @call addUnit\n        'second',\n        // @call setUnit\n        // @call addUnit\n        'milli',\n        // @call setUnit\n        // @call addUnit\n        'millisecond',\n        // @call setUnit\n        // @call addUnit\n        'micro',\n        // @call setUnit\n        // @call addUnit\n        'microsecond',\n    ];\n\n    /**\n     * Creates a DateTimeZone from a string, DateTimeZone or integer offset.\n     *\n     * @param DateTimeZone|string|int|null $object     original value to get CarbonTimeZone from it.\n     * @param DateTimeZone|string|int|null $objectDump dump of the object for error messages.\n     *\n     * @throws InvalidTimeZoneException\n     *\n     * @return CarbonTimeZone|false\n     */\n    protected static function safeCreateDateTimeZone($object, $objectDump = null)\n    {\n        return CarbonTimeZone::instance($object, $objectDump);\n    }\n\n    /**\n     * Get the TimeZone associated with the Carbon instance (as CarbonTimeZone).\n     *\n     * @return CarbonTimeZone\n     *\n     * @link https://php.net/manual/en/datetime.gettimezone.php\n     */\n    #[ReturnTypeWillChange]\n    public function getTimezone()\n    {\n        return CarbonTimeZone::instance(parent::getTimezone());\n    }\n\n    /**\n     * List of minimum and maximums for each unit.\n     *\n     * @param int $daysInMonth\n     *\n     * @return array\n     */\n    protected static function getRangesByUnit(int $daysInMonth = 31): array\n    {\n        return [\n            // @call roundUnit\n            'year' => [1, 9999],\n            // @call roundUnit\n            'month' => [1, static::MONTHS_PER_YEAR],\n            // @call roundUnit\n            'day' => [1, $daysInMonth],\n            // @call roundUnit\n            'hour' => [0, static::HOURS_PER_DAY - 1],\n            // @call roundUnit\n            'minute' => [0, static::MINUTES_PER_HOUR - 1],\n            // @call roundUnit\n            'second' => [0, static::SECONDS_PER_MINUTE - 1],\n        ];\n    }\n\n    /**\n     * Get a copy of the instance.\n     *\n     * @return static\n     */\n    public function copy()\n    {\n        return clone $this;\n    }\n\n    /**\n     * @alias copy\n     *\n     * Get a copy of the instance.\n     *\n     * @return static\n     */\n    public function clone()\n    {\n        return clone $this;\n    }\n\n    /**\n     * Clone the current instance if it's mutable.\n     *\n     * This method is convenient to ensure you don't mutate the initial object\n     * but avoid to make a useless copy of it if it's already immutable.\n     *\n     * @return static\n     */\n    public function avoidMutation(): self\n    {\n        if ($this instanceof DateTimeImmutable) {\n            return $this;\n        }\n\n        return clone $this;\n    }\n\n    /**\n     * Returns a present instance in the same timezone.\n     *\n     * @return static\n     */\n    public function nowWithSameTz()\n    {\n        return static::now($this->getTimezone());\n    }\n\n    /**\n     * Throws an exception if the given object is not a DateTime and does not implement DateTimeInterface.\n     *\n     * @param mixed        $date\n     * @param string|array $other\n     *\n     * @throws InvalidTypeException\n     */\n    protected static function expectDateTime($date, $other = [])\n    {\n        $message = 'Expected ';\n        foreach ((array) $other as $expect) {\n            $message .= \"$expect, \";\n        }\n\n        if (!$date instanceof DateTime && !$date instanceof DateTimeInterface) {\n            throw new InvalidTypeException(\n                $message.'DateTime or DateTimeInterface, '.\n                (\\is_object($date) ? \\get_class($date) : \\gettype($date)).' given'\n            );\n        }\n    }\n\n    /**\n     * Return the Carbon instance passed through, a now instance in the same timezone\n     * if null given or parse the input if string given.\n     *\n     * @param Carbon|DateTimeInterface|string|null $date\n     *\n     * @return static\n     */\n    protected function resolveCarbon($date = null)\n    {\n        if (!$date) {\n            return $this->nowWithSameTz();\n        }\n\n        if (\\is_string($date)) {\n            return static::parse($date, $this->getTimezone());\n        }\n\n        static::expectDateTime($date, ['null', 'string']);\n\n        return $date instanceof self ? $date : static::instance($date);\n    }\n\n    /**\n     * Return the Carbon instance passed through, a now instance in UTC\n     * if null given or parse the input if string given (using current timezone\n     * then switching to UTC).\n     *\n     * @param Carbon|DateTimeInterface|string|null $date\n     *\n     * @return static\n     */\n    protected function resolveUTC($date = null): self\n    {\n        if (!$date) {\n            return static::now('UTC');\n        }\n\n        if (\\is_string($date)) {\n            return static::parse($date, $this->getTimezone())->utc();\n        }\n\n        static::expectDateTime($date, ['null', 'string']);\n\n        return $date instanceof self ? $date : static::instance($date)->utc();\n    }\n\n    /**\n     * Return the Carbon instance passed through, a now instance in the same timezone\n     * if null given or parse the input if string given.\n     *\n     * @param Carbon|\\Carbon\\CarbonPeriod|\\Carbon\\CarbonInterval|\\DateInterval|\\DatePeriod|DateTimeInterface|string|null $date\n     *\n     * @return static\n     */\n    public function carbonize($date = null)\n    {\n        if ($date instanceof DateInterval) {\n            return $this->avoidMutation()->add($date);\n        }\n\n        if ($date instanceof DatePeriod || $date instanceof CarbonPeriod) {\n            $date = $date->getStartDate();\n        }\n\n        return $this->resolveCarbon($date);\n    }\n\n    ///////////////////////////////////////////////////////////////////\n    ///////////////////////// GETTERS AND SETTERS /////////////////////\n    ///////////////////////////////////////////////////////////////////\n\n    /**\n     * Get a part of the Carbon object\n     *\n     * @param string $name\n     *\n     * @throws UnknownGetterException\n     *\n     * @return string|int|bool|DateTimeZone|null\n     */\n    public function __get($name)\n    {\n        return $this->get($name);\n    }\n\n    /**\n     * Get a part of the Carbon object\n     *\n     * @param string $name\n     *\n     * @throws UnknownGetterException\n     *\n     * @return string|int|bool|DateTimeZone|null\n     */\n    public function get($name)\n    {\n        static $formats = [\n            // @property int\n            'year' => 'Y',\n            // @property int\n            'yearIso' => 'o',\n            // @property int\n            // @call isSameUnit\n            'month' => 'n',\n            // @property int\n            'day' => 'j',\n            // @property int\n            'hour' => 'G',\n            // @property int\n            'minute' => 'i',\n            // @property int\n            'second' => 's',\n            // @property int\n            'micro' => 'u',\n            // @property int\n            'microsecond' => 'u',\n            // @property-read int 0 (for Sunday) through 6 (for Saturday)\n            'dayOfWeek' => 'w',\n            // @property-read int 1 (for Monday) through 7 (for Sunday)\n            'dayOfWeekIso' => 'N',\n            // @property-read int ISO-8601 week number of year, weeks starting on Monday\n            'weekOfYear' => 'W',\n            // @property-read int number of days in the given month\n            'daysInMonth' => 't',\n            // @property int|float|string seconds since the Unix Epoch\n            'timestamp' => 'U',\n            // @property-read string \"am\"/\"pm\" (Ante meridiem or Post meridiem latin lowercase mark)\n            'latinMeridiem' => 'a',\n            // @property-read string \"AM\"/\"PM\" (Ante meridiem or Post meridiem latin uppercase mark)\n            'latinUpperMeridiem' => 'A',\n            // @property string the day of week in English\n            'englishDayOfWeek' => 'l',\n            // @property string the abbreviated day of week in English\n            'shortEnglishDayOfWeek' => 'D',\n            // @property string the month in English\n            'englishMonth' => 'F',\n            // @property string the abbreviated month in English\n            'shortEnglishMonth' => 'M',\n            // @property string the day of week in current locale LC_TIME\n            // @deprecated\n            //   reason: It uses OS language package and strftime() which is deprecated since PHP 8.1.\n            //   replacement: Use ->isoFormat('MMM') instead.\n            //   since: 2.55.0\n            'localeDayOfWeek' => '%A',\n            // @property string the abbreviated day of week in current locale LC_TIME\n            // @deprecated\n            //   reason: It uses OS language package and strftime() which is deprecated since PHP 8.1.\n            //   replacement: Use ->isoFormat('dddd') instead.\n            //   since: 2.55.0\n            'shortLocaleDayOfWeek' => '%a',\n            // @property string the month in current locale LC_TIME\n            // @deprecated\n            //   reason: It uses OS language package and strftime() which is deprecated since PHP 8.1.\n            //   replacement: Use ->isoFormat('ddd') instead.\n            //   since: 2.55.0\n            'localeMonth' => '%B',\n            // @property string the abbreviated month in current locale LC_TIME\n            // @deprecated\n            //   reason: It uses OS language package and strftime() which is deprecated since PHP 8.1.\n            //   replacement: Use ->isoFormat('MMMM') instead.\n            //   since: 2.55.0\n            'shortLocaleMonth' => '%b',\n            // @property-read string $timezoneAbbreviatedName the current timezone abbreviated name\n            'timezoneAbbreviatedName' => 'T',\n            // @property-read string $tzAbbrName alias of $timezoneAbbreviatedName\n            'tzAbbrName' => 'T',\n        ];\n\n        switch (true) {\n            case isset($formats[$name]):\n                $format = $formats[$name];\n                $method = str_starts_with($format, '%') ? 'formatLocalized' : 'rawFormat';\n                $value = $this->$method($format);\n\n                return is_numeric($value) ? (int) $value : $value;\n\n            // @property-read string long name of weekday translated according to Carbon locale, in english if no translation available for current language\n            case $name === 'dayName':\n                return $this->getTranslatedDayName();\n            // @property-read string short name of weekday translated according to Carbon locale, in english if no translation available for current language\n            case $name === 'shortDayName':\n                return $this->getTranslatedShortDayName();\n            // @property-read string very short name of weekday translated according to Carbon locale, in english if no translation available for current language\n            case $name === 'minDayName':\n                return $this->getTranslatedMinDayName();\n            // @property-read string long name of month translated according to Carbon locale, in english if no translation available for current language\n            case $name === 'monthName':\n                return $this->getTranslatedMonthName();\n            // @property-read string short name of month translated according to Carbon locale, in english if no translation available for current language\n            case $name === 'shortMonthName':\n                return $this->getTranslatedShortMonthName();\n            // @property-read string lowercase meridiem mark translated according to Carbon locale, in latin if no translation available for current language\n            case $name === 'meridiem':\n                return $this->meridiem(true);\n            // @property-read string uppercase meridiem mark translated according to Carbon locale, in latin if no translation available for current language\n            case $name === 'upperMeridiem':\n                return $this->meridiem();\n            // @property-read int current hour from 1 to 24\n            case $name === 'noZeroHour':\n                return $this->hour ?: 24;\n            // @property int\n            case $name === 'milliseconds':\n            // @property int\n            case $name === 'millisecond':\n            // @property int\n            case $name === 'milli':\n                return (int) floor(((int) $this->rawFormat('u')) / 1000);\n\n            // @property int 1 through 53\n            case $name === 'week':\n                return (int) $this->week();\n\n            // @property int 1 through 53\n            case $name === 'isoWeek':\n                return (int) $this->isoWeek();\n\n            // @property int year according to week format\n            case $name === 'weekYear':\n                return (int) $this->weekYear();\n\n            // @property int year according to ISO week format\n            case $name === 'isoWeekYear':\n                return (int) $this->isoWeekYear();\n\n            // @property-read int 51 through 53\n            case $name === 'weeksInYear':\n                return $this->weeksInYear();\n\n            // @property-read int 51 through 53\n            case $name === 'isoWeeksInYear':\n                return $this->isoWeeksInYear();\n\n            // @property-read int 1 through 5\n            case $name === 'weekOfMonth':\n                return (int) ceil($this->day / static::DAYS_PER_WEEK);\n\n            // @property-read int 1 through 5\n            case $name === 'weekNumberInMonth':\n                return (int) ceil(($this->day + $this->avoidMutation()->startOfMonth()->dayOfWeekIso - 1) / static::DAYS_PER_WEEK);\n\n            // @property-read int 0 through 6\n            case $name === 'firstWeekDay':\n                return $this->localTranslator ? ($this->getTranslationMessage('first_day_of_week') ?? 0) : static::getWeekStartsAt();\n\n            // @property-read int 0 through 6\n            case $name === 'lastWeekDay':\n                return $this->localTranslator ? (($this->getTranslationMessage('first_day_of_week') ?? 0) + static::DAYS_PER_WEEK - 1) % static::DAYS_PER_WEEK : static::getWeekEndsAt();\n\n            // @property int 1 through 366\n            case $name === 'dayOfYear':\n                return 1 + (int) ($this->rawFormat('z'));\n\n            // @property-read int 365 or 366\n            case $name === 'daysInYear':\n                return $this->isLeapYear() ? 366 : 365;\n\n            // @property int does a diffInYears() with default parameters\n            case $name === 'age':\n                return $this->diffInYears();\n\n            // @property-read int the quarter of this instance, 1 - 4\n            // @call isSameUnit\n            case $name === 'quarter':\n                return (int) ceil($this->month / static::MONTHS_PER_QUARTER);\n\n            // @property-read int the decade of this instance\n            // @call isSameUnit\n            case $name === 'decade':\n                return (int) ceil($this->year / static::YEARS_PER_DECADE);\n\n            // @property-read int the century of this instance\n            // @call isSameUnit\n            case $name === 'century':\n                $factor = 1;\n                $year = $this->year;\n                if ($year < 0) {\n                    $year = -$year;\n                    $factor = -1;\n                }\n\n                return (int) ($factor * ceil($year / static::YEARS_PER_CENTURY));\n\n            // @property-read int the millennium of this instance\n            // @call isSameUnit\n            case $name === 'millennium':\n                $factor = 1;\n                $year = $this->year;\n                if ($year < 0) {\n                    $year = -$year;\n                    $factor = -1;\n                }\n\n                return (int) ($factor * ceil($year / static::YEARS_PER_MILLENNIUM));\n\n            // @property int the timezone offset in seconds from UTC\n            case $name === 'offset':\n                return $this->getOffset();\n\n            // @property int the timezone offset in minutes from UTC\n            case $name === 'offsetMinutes':\n                return $this->getOffset() / static::SECONDS_PER_MINUTE;\n\n            // @property int the timezone offset in hours from UTC\n            case $name === 'offsetHours':\n                return $this->getOffset() / static::SECONDS_PER_MINUTE / static::MINUTES_PER_HOUR;\n\n            // @property-read bool daylight savings time indicator, true if DST, false otherwise\n            case $name === 'dst':\n                return $this->rawFormat('I') === '1';\n\n            // @property-read bool checks if the timezone is local, true if local, false otherwise\n            case $name === 'local':\n                return $this->getOffset() === $this->avoidMutation()->setTimezone(date_default_timezone_get())->getOffset();\n\n            // @property-read bool checks if the timezone is UTC, true if UTC, false otherwise\n            case $name === 'utc':\n                return $this->getOffset() === 0;\n\n            // @property CarbonTimeZone $timezone the current timezone\n            // @property CarbonTimeZone $tz alias of $timezone\n            case $name === 'timezone' || $name === 'tz':\n                return CarbonTimeZone::instance($this->getTimezone());\n\n            // @property-read string $timezoneName the current timezone name\n            // @property-read string $tzName alias of $timezoneName\n            case $name === 'timezoneName' || $name === 'tzName':\n                return $this->getTimezone()->getName();\n\n            // @property-read string locale of the current instance\n            case $name === 'locale':\n                return $this->getTranslatorLocale();\n\n            default:\n                $macro = $this->getLocalMacro('get'.ucfirst($name));\n\n                if ($macro) {\n                    return $this->executeCallableWithContext($macro);\n                }\n\n                throw new UnknownGetterException($name);\n        }\n    }\n\n    /**\n     * Check if an attribute exists on the object\n     *\n     * @param string $name\n     *\n     * @return bool\n     */\n    public function __isset($name)\n    {\n        try {\n            $this->__get($name);\n        } catch (UnknownGetterException | ReflectionException $e) {\n            return false;\n        }\n\n        return true;\n    }\n\n    /**\n     * Set a part of the Carbon object\n     *\n     * @param string                  $name\n     * @param string|int|DateTimeZone $value\n     *\n     * @throws UnknownSetterException|ReflectionException\n     *\n     * @return void\n     */\n    public function __set($name, $value)\n    {\n        if ($this->constructedObjectId === spl_object_hash($this)) {\n            $this->set($name, $value);\n\n            return;\n        }\n\n        $this->$name = $value;\n    }\n\n    /**\n     * Set a part of the Carbon object\n     *\n     * @param string|array            $name\n     * @param string|int|DateTimeZone $value\n     *\n     * @throws ImmutableException|UnknownSetterException\n     *\n     * @return $this\n     */\n    public function set($name, $value = null)\n    {\n        if ($this->isImmutable()) {\n            throw new ImmutableException(\\sprintf('%s class', static::class));\n        }\n\n        if (\\is_array($name)) {\n            foreach ($name as $key => $value) {\n                $this->set($key, $value);\n            }\n\n            return $this;\n        }\n\n        switch ($name) {\n            case 'milliseconds':\n            case 'millisecond':\n            case 'milli':\n            case 'microseconds':\n            case 'microsecond':\n            case 'micro':\n                if (str_starts_with($name, 'milli')) {\n                    $value *= 1000;\n                }\n\n                while ($value < 0) {\n                    $this->subSecond();\n                    $value += static::MICROSECONDS_PER_SECOND;\n                }\n\n                while ($value >= static::MICROSECONDS_PER_SECOND) {\n                    $this->addSecond();\n                    $value -= static::MICROSECONDS_PER_SECOND;\n                }\n\n                $this->modify($this->rawFormat('H:i:s.').str_pad((string) round($value), 6, '0', STR_PAD_LEFT));\n\n                break;\n\n            case 'year':\n            case 'month':\n            case 'day':\n            case 'hour':\n            case 'minute':\n            case 'second':\n                [$year, $month, $day, $hour, $minute, $second] = array_map('intval', explode('-', $this->rawFormat('Y-n-j-G-i-s')));\n                $$name = $value;\n                $this->setDateTime($year, $month, $day, $hour, $minute, $second);\n\n                break;\n\n            case 'week':\n                $this->week($value);\n\n                break;\n\n            case 'isoWeek':\n                $this->isoWeek($value);\n\n                break;\n\n            case 'weekYear':\n                $this->weekYear($value);\n\n                break;\n\n            case 'isoWeekYear':\n                $this->isoWeekYear($value);\n\n                break;\n\n            case 'dayOfYear':\n                $this->addDays($value - $this->dayOfYear);\n\n                break;\n\n            case 'timestamp':\n                $this->setTimestamp($value);\n\n                break;\n\n            case 'offset':\n                $this->setTimezone(static::safeCreateDateTimeZone($value / static::SECONDS_PER_MINUTE / static::MINUTES_PER_HOUR));\n\n                break;\n\n            case 'offsetMinutes':\n                $this->setTimezone(static::safeCreateDateTimeZone($value / static::MINUTES_PER_HOUR));\n\n                break;\n\n            case 'offsetHours':\n                $this->setTimezone(static::safeCreateDateTimeZone($value));\n\n                break;\n\n            case 'timezone':\n            case 'tz':\n                $this->setTimezone($value);\n\n                break;\n\n            default:\n                $macro = $this->getLocalMacro('set'.ucfirst($name));\n\n                if ($macro) {\n                    $this->executeCallableWithContext($macro, $value);\n\n                    break;\n                }\n\n                if ($this->localStrictModeEnabled ?? static::isStrictModeEnabled()) {\n                    throw new UnknownSetterException($name);\n                }\n\n                $this->$name = $value;\n        }\n\n        return $this;\n    }\n\n    protected function getTranslatedFormByRegExp($baseKey, $keySuffix, $context, $subKey, $defaultValue)\n    {\n        $key = $baseKey.$keySuffix;\n        $standaloneKey = \"{$key}_standalone\";\n        $baseTranslation = $this->getTranslationMessage($key);\n\n        if ($baseTranslation instanceof Closure) {\n            return $baseTranslation($this, $context, $subKey) ?: $defaultValue;\n        }\n\n        if (\n            $this->getTranslationMessage(\"$standaloneKey.$subKey\") &&\n            (!$context || (($regExp = $this->getTranslationMessage(\"{$baseKey}_regexp\")) && !preg_match($regExp, $context)))\n        ) {\n            $key = $standaloneKey;\n        }\n\n        return $this->getTranslationMessage(\"$key.$subKey\", null, $defaultValue);\n    }\n\n    /**\n     * Get the translation of the current week day name (with context for languages with multiple forms).\n     *\n     * @param string|null $context      whole format string\n     * @param string      $keySuffix    \"\", \"_short\" or \"_min\"\n     * @param string|null $defaultValue default value if translation missing\n     *\n     * @return string\n     */\n    public function getTranslatedDayName($context = null, $keySuffix = '', $defaultValue = null)\n    {\n        return $this->getTranslatedFormByRegExp('weekdays', $keySuffix, $context, $this->dayOfWeek, $defaultValue ?: $this->englishDayOfWeek);\n    }\n\n    /**\n     * Get the translation of the current short week day name (with context for languages with multiple forms).\n     *\n     * @param string|null $context whole format string\n     *\n     * @return string\n     */\n    public function getTranslatedShortDayName($context = null)\n    {\n        return $this->getTranslatedDayName($context, '_short', $this->shortEnglishDayOfWeek);\n    }\n\n    /**\n     * Get the translation of the current abbreviated week day name (with context for languages with multiple forms).\n     *\n     * @param string|null $context whole format string\n     *\n     * @return string\n     */\n    public function getTranslatedMinDayName($context = null)\n    {\n        return $this->getTranslatedDayName($context, '_min', $this->shortEnglishDayOfWeek);\n    }\n\n    /**\n     * Get the translation of the current month day name (with context for languages with multiple forms).\n     *\n     * @param string|null $context      whole format string\n     * @param string      $keySuffix    \"\" or \"_short\"\n     * @param string|null $defaultValue default value if translation missing\n     *\n     * @return string\n     */\n    public function getTranslatedMonthName($context = null, $keySuffix = '', $defaultValue = null)\n    {\n        return $this->getTranslatedFormByRegExp('months', $keySuffix, $context, $this->month - 1, $defaultValue ?: $this->englishMonth);\n    }\n\n    /**\n     * Get the translation of the current short month day name (with context for languages with multiple forms).\n     *\n     * @param string|null $context whole format string\n     *\n     * @return string\n     */\n    public function getTranslatedShortMonthName($context = null)\n    {\n        return $this->getTranslatedMonthName($context, '_short', $this->shortEnglishMonth);\n    }\n\n    /**\n     * Get/set the day of year.\n     *\n     * @param int|null $value new value for day of year if using as setter.\n     *\n     * @return static|int\n     */\n    public function dayOfYear($value = null)\n    {\n        $dayOfYear = $this->dayOfYear;\n\n        return $value === null ? $dayOfYear : $this->addDays($value - $dayOfYear);\n    }\n\n    /**\n     * Get/set the weekday from 0 (Sunday) to 6 (Saturday).\n     *\n     * @param int|null $value new value for weekday if using as setter.\n     *\n     * @return static|int\n     */\n    public function weekday($value = null)\n    {\n        if ($value === null) {\n            return $this->dayOfWeek;\n        }\n\n        $firstDay = (int) ($this->getTranslationMessage('first_day_of_week') ?? 0);\n        $dayOfWeek = ($this->dayOfWeek + 7 - $firstDay) % 7;\n\n        return $this->addDays((($value + 7 - $firstDay) % 7) - $dayOfWeek);\n    }\n\n    /**\n     * Get/set the ISO weekday from 1 (Monday) to 7 (Sunday).\n     *\n     * @param int|null $value new value for weekday if using as setter.\n     *\n     * @return static|int\n     */\n    public function isoWeekday($value = null)\n    {\n        $dayOfWeekIso = $this->dayOfWeekIso;\n\n        return $value === null ? $dayOfWeekIso : $this->addDays($value - $dayOfWeekIso);\n    }\n\n    /**\n     * Return the number of days since the start of the week (using the current locale or the first parameter\n     * if explicitly given).\n     *\n     * @param int|null $weekStartsAt optional start allow you to specify the day of week to use to start the week,\n     *                               if not provided, start of week is inferred from the locale\n     *                               (Sunday for en_US, Monday for de_DE, etc.)\n     *\n     * @return int\n     */\n    public function getDaysFromStartOfWeek(?int $weekStartsAt = null): int\n    {\n        $firstDay = (int) ($weekStartsAt ?? $this->getTranslationMessage('first_day_of_week') ?? 0);\n\n        return ($this->dayOfWeek + 7 - $firstDay) % 7;\n    }\n\n    /**\n     * Set the day (keeping the current time) to the start of the week + the number of days passed as the first\n     * parameter. First day of week is driven by the locale unless explicitly set with the second parameter.\n     *\n     * @param int      $numberOfDays number of days to add after the start of the current week\n     * @param int|null $weekStartsAt optional start allow you to specify the day of week to use to start the week,\n     *                               if not provided, start of week is inferred from the locale\n     *                               (Sunday for en_US, Monday for de_DE, etc.)\n     *\n     * @return static\n     */\n    public function setDaysFromStartOfWeek(int $numberOfDays, ?int $weekStartsAt = null)\n    {\n        return $this->addDays($numberOfDays - $this->getDaysFromStartOfWeek($weekStartsAt));\n    }\n\n    /**\n     * Set any unit to a new value without overflowing current other unit given.\n     *\n     * @param string $valueUnit    unit name to modify\n     * @param int    $value        new value for the input unit\n     * @param string $overflowUnit unit name to not overflow\n     *\n     * @return static\n     */\n    public function setUnitNoOverflow($valueUnit, $value, $overflowUnit)\n    {\n        try {\n            $original = $this->avoidMutation();\n            /** @var static $date */\n            $date = $this->$valueUnit($value);\n            $end = $original->avoidMutation()->endOf($overflowUnit);\n            $start = $original->avoidMutation()->startOf($overflowUnit);\n            if ($date < $start) {\n                $date = $date->setDateTimeFrom($start);\n            } elseif ($date > $end) {\n                $date = $date->setDateTimeFrom($end);\n            }\n\n            return $date;\n        } catch (BadMethodCallException | ReflectionException $exception) {\n            throw new UnknownUnitException($valueUnit, 0, $exception);\n        }\n    }\n\n    /**\n     * Add any unit to a new value without overflowing current other unit given.\n     *\n     * @param string $valueUnit    unit name to modify\n     * @param int    $value        amount to add to the input unit\n     * @param string $overflowUnit unit name to not overflow\n     *\n     * @return static\n     */\n    public function addUnitNoOverflow($valueUnit, $value, $overflowUnit)\n    {\n        return $this->setUnitNoOverflow($valueUnit, $this->$valueUnit + $value, $overflowUnit);\n    }\n\n    /**\n     * Subtract any unit to a new value without overflowing current other unit given.\n     *\n     * @param string $valueUnit    unit name to modify\n     * @param int    $value        amount to subtract to the input unit\n     * @param string $overflowUnit unit name to not overflow\n     *\n     * @return static\n     */\n    public function subUnitNoOverflow($valueUnit, $value, $overflowUnit)\n    {\n        return $this->setUnitNoOverflow($valueUnit, $this->$valueUnit - $value, $overflowUnit);\n    }\n\n    /**\n     * Returns the minutes offset to UTC if no arguments passed, else set the timezone with given minutes shift passed.\n     *\n     * @param int|null $minuteOffset\n     *\n     * @return int|static\n     */\n    public function utcOffset(?int $minuteOffset = null)\n    {\n        if (\\func_num_args() < 1) {\n            return $this->offsetMinutes;\n        }\n\n        return $this->setTimezone(CarbonTimeZone::createFromMinuteOffset($minuteOffset));\n    }\n\n    /**\n     * Set the date with gregorian year, month and day numbers.\n     *\n     * @see https://php.net/manual/en/datetime.setdate.php\n     *\n     * @param int $year\n     * @param int $month\n     * @param int $day\n     *\n     * @return static\n     */\n    #[ReturnTypeWillChange]\n    public function setDate($year, $month, $day)\n    {\n        return parent::setDate((int) $year, (int) $month, (int) $day);\n    }\n\n    /**\n     * Set a date according to the ISO 8601 standard - using weeks and day offsets rather than specific dates.\n     *\n     * @see https://php.net/manual/en/datetime.setisodate.php\n     *\n     * @param int $year\n     * @param int $week\n     * @param int $day\n     *\n     * @return static\n     */\n    #[ReturnTypeWillChange]\n    public function setISODate($year, $week, $day = 1)\n    {\n        return parent::setISODate((int) $year, (int) $week, (int) $day);\n    }\n\n    /**\n     * Set the date and time all together.\n     *\n     * @param int $year\n     * @param int $month\n     * @param int $day\n     * @param int $hour\n     * @param int $minute\n     * @param int $second\n     * @param int $microseconds\n     *\n     * @return static\n     */\n    public function setDateTime($year, $month, $day, $hour, $minute, $second = 0, $microseconds = 0)\n    {\n        return $this->setDate($year, $month, $day)->setTime((int) $hour, (int) $minute, (int) $second, (int) $microseconds);\n    }\n\n    /**\n     * Resets the current time of the DateTime object to a different time.\n     *\n     * @see https://php.net/manual/en/datetime.settime.php\n     *\n     * @param int $hour\n     * @param int $minute\n     * @param int $second\n     * @param int $microseconds\n     *\n     * @return static\n     */\n    #[ReturnTypeWillChange]\n    public function setTime($hour, $minute, $second = 0, $microseconds = 0)\n    {\n        return parent::setTime((int) $hour, (int) $minute, (int) $second, (int) $microseconds);\n    }\n\n    /**\n     * Set the instance's timestamp.\n     *\n     * Timestamp input can be given as int, float or a string containing one or more numbers.\n     *\n     * @param float|int|string $unixTimestamp\n     *\n     * @return static\n     */\n    #[ReturnTypeWillChange]\n    public function setTimestamp($unixTimestamp)\n    {\n        [$timestamp, $microseconds] = self::getIntegerAndDecimalParts($unixTimestamp);\n\n        return parent::setTimestamp((int) $timestamp)->setMicroseconds((int) $microseconds);\n    }\n\n    /**\n     * Set the time by time string.\n     *\n     * @param string $time\n     *\n     * @return static\n     */\n    public function setTimeFromTimeString($time)\n    {\n        if (!str_contains($time, ':')) {\n            $time .= ':0';\n        }\n\n        return $this->modify($time);\n    }\n\n    /**\n     * @alias setTimezone\n     *\n     * @param DateTimeZone|string $value\n     *\n     * @return static\n     */\n    public function timezone($value)\n    {\n        return $this->setTimezone($value);\n    }\n\n    /**\n     * Set the timezone or returns the timezone name if no arguments passed.\n     *\n     * @param DateTimeZone|string $value\n     *\n     * @return static|string\n     */\n    public function tz($value = null)\n    {\n        if (\\func_num_args() < 1) {\n            return $this->tzName;\n        }\n\n        return $this->setTimezone($value);\n    }\n\n    /**\n     * Set the instance's timezone from a string or object.\n     *\n     * @param DateTimeZone|string $value\n     *\n     * @return static\n     */\n    #[ReturnTypeWillChange]\n    public function setTimezone($value)\n    {\n        $tz = static::safeCreateDateTimeZone($value);\n\n        if ($tz === false && !self::isStrictModeEnabled()) {\n            $tz = new CarbonTimeZone();\n        }\n\n        return parent::setTimezone($tz);\n    }\n\n    /**\n     * Set the instance's timezone from a string or object and add/subtract the offset difference.\n     *\n     * @param DateTimeZone|string $value\n     *\n     * @return static\n     */\n    public function shiftTimezone($value)\n    {\n        $dateTimeString = $this->format('Y-m-d H:i:s.u');\n\n        return $this\n            ->setTimezone($value)\n            ->modify($dateTimeString);\n    }\n\n    /**\n     * Set the instance's timezone to UTC.\n     *\n     * @return static\n     */\n    public function utc()\n    {\n        return $this->setTimezone('UTC');\n    }\n\n    /**\n     * Set the year, month, and date for this instance to that of the passed instance.\n     *\n     * @param Carbon|DateTimeInterface $date now if null\n     *\n     * @return static\n     */\n    public function setDateFrom($date = null)\n    {\n        $date = $this->resolveCarbon($date);\n\n        return $this->setDate($date->year, $date->month, $date->day);\n    }\n\n    /**\n     * Set the hour, minute, second and microseconds for this instance to that of the passed instance.\n     *\n     * @param Carbon|DateTimeInterface $date now if null\n     *\n     * @return static\n     */\n    public function setTimeFrom($date = null)\n    {\n        $date = $this->resolveCarbon($date);\n\n        return $this->setTime($date->hour, $date->minute, $date->second, $date->microsecond);\n    }\n\n    /**\n     * Set the date and time for this instance to that of the passed instance.\n     *\n     * @param Carbon|DateTimeInterface $date\n     *\n     * @return static\n     */\n    public function setDateTimeFrom($date = null)\n    {\n        $date = $this->resolveCarbon($date);\n\n        return $this->modify($date->rawFormat('Y-m-d H:i:s.u'));\n    }\n\n    /**\n     * Get the days of the week\n     *\n     * @return array\n     */\n    public static function getDays()\n    {\n        return static::$days;\n    }\n\n    ///////////////////////////////////////////////////////////////////\n    /////////////////////// WEEK SPECIAL DAYS /////////////////////////\n    ///////////////////////////////////////////////////////////////////\n\n    private static function getFirstDayOfWeek(): int\n    {\n        return (int) static::getTranslationMessageWith(\n            static::getTranslator(),\n            'first_day_of_week'\n        );\n    }\n\n    /**\n     * Get the first day of week\n     *\n     * @return int\n     */\n    public static function getWeekStartsAt()\n    {\n        if (static::$weekStartsAt === static::WEEK_DAY_AUTO) {\n            return self::getFirstDayOfWeek();\n        }\n\n        return static::$weekStartsAt;\n    }\n\n    /**\n     * @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n     *             Use $weekEndsAt optional parameter instead when using endOfWeek method. You can also use the\n     *             'first_day_of_week' locale setting to change the start of week according to current locale\n     *             selected and implicitly the end of week.\n     *\n     * Set the first day of week\n     *\n     * @param int|string $day week start day (or 'auto' to get the first day of week from Carbon::getLocale() culture).\n     *\n     * @return void\n     */\n    public static function setWeekStartsAt($day)\n    {\n        static::$weekStartsAt = $day === static::WEEK_DAY_AUTO ? $day : max(0, (7 + $day) % 7);\n    }\n\n    /**\n     * Get the last day of week\n     *\n     * @return int\n     */\n    public static function getWeekEndsAt()\n    {\n        if (static::$weekStartsAt === static::WEEK_DAY_AUTO) {\n            return (int) (static::DAYS_PER_WEEK - 1 + self::getFirstDayOfWeek()) % static::DAYS_PER_WEEK;\n        }\n\n        return static::$weekEndsAt;\n    }\n\n    /**\n     * @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n     *             Use $weekStartsAt optional parameter instead when using startOfWeek, floorWeek, ceilWeek\n     *             or roundWeek method. You can also use the 'first_day_of_week' locale setting to change the\n     *             start of week according to current locale selected and implicitly the end of week.\n     *\n     * Set the last day of week\n     *\n     * @param int|string $day week end day (or 'auto' to get the day before the first day of week\n     *                        from Carbon::getLocale() culture).\n     *\n     * @return void\n     */\n    public static function setWeekEndsAt($day)\n    {\n        static::$weekEndsAt = $day === static::WEEK_DAY_AUTO ? $day : max(0, (7 + $day) % 7);\n    }\n\n    /**\n     * Get weekend days\n     *\n     * @return array\n     */\n    public static function getWeekendDays()\n    {\n        return static::$weekendDays;\n    }\n\n    /**\n     * @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n     *             You should rather consider week-end is always saturday and sunday, and if you have some custom\n     *             week-end days to handle, give to those days an other name and create a macro for them:\n     *\n     *             ```\n     *             Carbon::macro('isDayOff', function ($date) {\n     *                 return $date->isSunday() || $date->isMonday();\n     *             });\n     *             Carbon::macro('isNotDayOff', function ($date) {\n     *                 return !$date->isDayOff();\n     *             });\n     *             if ($someDate->isDayOff()) ...\n     *             if ($someDate->isNotDayOff()) ...\n     *             // Add 5 not-off days\n     *             $count = 5;\n     *             while ($someDate->isDayOff() || ($count-- > 0)) {\n     *                 $someDate->addDay();\n     *             }\n     *             ```\n     *\n     * Set weekend days\n     *\n     * @param array $days\n     *\n     * @return void\n     */\n    public static function setWeekendDays($days)\n    {\n        static::$weekendDays = $days;\n    }\n\n    /**\n     * Determine if a time string will produce a relative date.\n     *\n     * @param string $time\n     *\n     * @return bool true if time match a relative date, false if absolute or invalid time string\n     */\n    public static function hasRelativeKeywords($time)\n    {\n        if (!$time || strtotime($time) === false) {\n            return false;\n        }\n\n        $date1 = new DateTime('2000-01-01T00:00:00Z');\n        $date1->modify($time);\n        $date2 = new DateTime('2001-12-25T00:00:00Z');\n        $date2->modify($time);\n\n        return $date1 != $date2;\n    }\n\n    ///////////////////////////////////////////////////////////////////\n    /////////////////////// STRING FORMATTING /////////////////////////\n    ///////////////////////////////////////////////////////////////////\n\n    /**\n     * @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n     *             You should rather use UTF-8 language packages on every machine.\n     *\n     * Set if UTF8 will be used for localized date/time.\n     *\n     * @param bool $utf8\n     */\n    public static function setUtf8($utf8)\n    {\n        static::$utf8 = $utf8;\n    }\n\n    /**\n     * Format the instance with the current locale.  You can set the current\n     * locale using setlocale() https://php.net/setlocale.\n     *\n     * @deprecated It uses OS language package and strftime() which is deprecated since PHP 8.1.\n     *             Use ->isoFormat() instead.\n     *             Deprecated since 2.55.0\n     *\n     * @param string $format\n     *\n     * @return string\n     */\n    public function formatLocalized($format)\n    {\n        // Check for Windows to find and replace the %e modifier correctly.\n        if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {\n            $format = preg_replace('#(?<!%)((?:%%)*)%e#', '\\1%#d', $format); // @codeCoverageIgnore\n        }\n\n        $time = strtotime($this->toDateTimeString());\n        $formatted = ($this->localStrictModeEnabled ?? static::isStrictModeEnabled())\n            ? strftime($format, $time)\n            : @strftime($format, $time);\n\n        return static::$utf8\n            ? (\n                \\function_exists('mb_convert_encoding')\n                ? mb_convert_encoding($formatted, 'UTF-8', mb_list_encodings())\n                : utf8_encode($formatted)\n            )\n            : $formatted;\n    }\n\n    /**\n     * Returns list of locale formats for ISO formatting.\n     *\n     * @param string|null $locale current locale used if null\n     *\n     * @return array\n     */\n    public function getIsoFormats($locale = null)\n    {\n        return [\n            'LT' => $this->getTranslationMessage('formats.LT', $locale, 'h:mm A'),\n            'LTS' => $this->getTranslationMessage('formats.LTS', $locale, 'h:mm:ss A'),\n            'L' => $this->getTranslationMessage('formats.L', $locale, 'MM/DD/YYYY'),\n            'LL' => $this->getTranslationMessage('formats.LL', $locale, 'MMMM D, YYYY'),\n            'LLL' => $this->getTranslationMessage('formats.LLL', $locale, 'MMMM D, YYYY h:mm A'),\n            'LLLL' => $this->getTranslationMessage('formats.LLLL', $locale, 'dddd, MMMM D, YYYY h:mm A'),\n            'l' => $this->getTranslationMessage('formats.l', $locale),\n            'll' => $this->getTranslationMessage('formats.ll', $locale),\n            'lll' => $this->getTranslationMessage('formats.lll', $locale),\n            'llll' => $this->getTranslationMessage('formats.llll', $locale),\n        ];\n    }\n\n    /**\n     * Returns list of calendar formats for ISO formatting.\n     *\n     * @param string|null $locale current locale used if null\n     *\n     * @return array\n     */\n    public function getCalendarFormats($locale = null)\n    {\n        return [\n            'sameDay' => $this->getTranslationMessage('calendar.sameDay', $locale, '[Today at] LT'),\n            'nextDay' => $this->getTranslationMessage('calendar.nextDay', $locale, '[Tomorrow at] LT'),\n            'nextWeek' => $this->getTranslationMessage('calendar.nextWeek', $locale, 'dddd [at] LT'),\n            'lastDay' => $this->getTranslationMessage('calendar.lastDay', $locale, '[Yesterday at] LT'),\n            'lastWeek' => $this->getTranslationMessage('calendar.lastWeek', $locale, '[Last] dddd [at] LT'),\n            'sameElse' => $this->getTranslationMessage('calendar.sameElse', $locale, 'L'),\n        ];\n    }\n\n    /**\n     * Returns list of locale units for ISO formatting.\n     *\n     * @return array\n     */\n    public static function getIsoUnits()\n    {\n        static $units = null;\n\n        if ($units === null) {\n            $units = [\n                'OD' => ['getAltNumber', ['day']],\n                'OM' => ['getAltNumber', ['month']],\n                'OY' => ['getAltNumber', ['year']],\n                'OH' => ['getAltNumber', ['hour']],\n                'Oh' => ['getAltNumber', ['h']],\n                'Om' => ['getAltNumber', ['minute']],\n                'Os' => ['getAltNumber', ['second']],\n                'D' => 'day',\n                'DD' => ['rawFormat', ['d']],\n                'Do' => ['ordinal', ['day', 'D']],\n                'd' => 'dayOfWeek',\n                'dd' => function (CarbonInterface $date, $originalFormat = null) {\n                    return $date->getTranslatedMinDayName($originalFormat);\n                },\n                'ddd' => function (CarbonInterface $date, $originalFormat = null) {\n                    return $date->getTranslatedShortDayName($originalFormat);\n                },\n                'dddd' => function (CarbonInterface $date, $originalFormat = null) {\n                    return $date->getTranslatedDayName($originalFormat);\n                },\n                'DDD' => 'dayOfYear',\n                'DDDD' => ['getPaddedUnit', ['dayOfYear', 3]],\n                'DDDo' => ['ordinal', ['dayOfYear', 'DDD']],\n                'e' => ['weekday', []],\n                'E' => 'dayOfWeekIso',\n                'H' => ['rawFormat', ['G']],\n                'HH' => ['rawFormat', ['H']],\n                'h' => ['rawFormat', ['g']],\n                'hh' => ['rawFormat', ['h']],\n                'k' => 'noZeroHour',\n                'kk' => ['getPaddedUnit', ['noZeroHour']],\n                'hmm' => ['rawFormat', ['gi']],\n                'hmmss' => ['rawFormat', ['gis']],\n                'Hmm' => ['rawFormat', ['Gi']],\n                'Hmmss' => ['rawFormat', ['Gis']],\n                'm' => 'minute',\n                'mm' => ['rawFormat', ['i']],\n                'a' => 'meridiem',\n                'A' => 'upperMeridiem',\n                's' => 'second',\n                'ss' => ['getPaddedUnit', ['second']],\n                'S' => function (CarbonInterface $date) {\n                    return (string) floor($date->micro / 100000);\n                },\n                'SS' => function (CarbonInterface $date) {\n                    return str_pad((string) floor($date->micro / 10000), 2, '0', STR_PAD_LEFT);\n                },\n                'SSS' => function (CarbonInterface $date) {\n                    return str_pad((string) floor($date->micro / 1000), 3, '0', STR_PAD_LEFT);\n                },\n                'SSSS' => function (CarbonInterface $date) {\n                    return str_pad((string) floor($date->micro / 100), 4, '0', STR_PAD_LEFT);\n                },\n                'SSSSS' => function (CarbonInterface $date) {\n                    return str_pad((string) floor($date->micro / 10), 5, '0', STR_PAD_LEFT);\n                },\n                'SSSSSS' => ['getPaddedUnit', ['micro', 6]],\n                'SSSSSSS' => function (CarbonInterface $date) {\n                    return str_pad((string) floor($date->micro * 10), 7, '0', STR_PAD_LEFT);\n                },\n                'SSSSSSSS' => function (CarbonInterface $date) {\n                    return str_pad((string) floor($date->micro * 100), 8, '0', STR_PAD_LEFT);\n                },\n                'SSSSSSSSS' => function (CarbonInterface $date) {\n                    return str_pad((string) floor($date->micro * 1000), 9, '0', STR_PAD_LEFT);\n                },\n                'M' => 'month',\n                'MM' => ['rawFormat', ['m']],\n                'MMM' => function (CarbonInterface $date, $originalFormat = null) {\n                    $month = $date->getTranslatedShortMonthName($originalFormat);\n                    $suffix = $date->getTranslationMessage('mmm_suffix');\n                    if ($suffix && $month !== $date->monthName) {\n                        $month .= $suffix;\n                    }\n\n                    return $month;\n                },\n                'MMMM' => function (CarbonInterface $date, $originalFormat = null) {\n                    return $date->getTranslatedMonthName($originalFormat);\n                },\n                'Mo' => ['ordinal', ['month', 'M']],\n                'Q' => 'quarter',\n                'Qo' => ['ordinal', ['quarter', 'M']],\n                'G' => 'isoWeekYear',\n                'GG' => ['getPaddedUnit', ['isoWeekYear']],\n                'GGG' => ['getPaddedUnit', ['isoWeekYear', 3]],\n                'GGGG' => ['getPaddedUnit', ['isoWeekYear', 4]],\n                'GGGGG' => ['getPaddedUnit', ['isoWeekYear', 5]],\n                'g' => 'weekYear',\n                'gg' => ['getPaddedUnit', ['weekYear']],\n                'ggg' => ['getPaddedUnit', ['weekYear', 3]],\n                'gggg' => ['getPaddedUnit', ['weekYear', 4]],\n                'ggggg' => ['getPaddedUnit', ['weekYear', 5]],\n                'W' => 'isoWeek',\n                'WW' => ['getPaddedUnit', ['isoWeek']],\n                'Wo' => ['ordinal', ['isoWeek', 'W']],\n                'w' => 'week',\n                'ww' => ['getPaddedUnit', ['week']],\n                'wo' => ['ordinal', ['week', 'w']],\n                'x' => ['valueOf', []],\n                'X' => 'timestamp',\n                'Y' => 'year',\n                'YY' => ['rawFormat', ['y']],\n                'YYYY' => ['getPaddedUnit', ['year', 4]],\n                'YYYYY' => ['getPaddedUnit', ['year', 5]],\n                'YYYYYY' => function (CarbonInterface $date) {\n                    return ($date->year < 0 ? '' : '+').$date->getPaddedUnit('year', 6);\n                },\n                'z' => ['rawFormat', ['T']],\n                'zz' => 'tzName',\n                'Z' => ['getOffsetString', []],\n                'ZZ' => ['getOffsetString', ['']],\n            ];\n        }\n\n        return $units;\n    }\n\n    /**\n     * Returns a unit of the instance padded with 0 by default or any other string if specified.\n     *\n     * @param string $unit      Carbon unit name\n     * @param int    $length    Length of the output (2 by default)\n     * @param string $padString String to use for padding (\"0\" by default)\n     * @param int    $padType   Side(s) to pad (STR_PAD_LEFT by default)\n     *\n     * @return string\n     */\n    public function getPaddedUnit($unit, $length = 2, $padString = '0', $padType = STR_PAD_LEFT)\n    {\n        return ($this->$unit < 0 ? '-' : '').str_pad((string) abs($this->$unit), $length, $padString, $padType);\n    }\n\n    /**\n     * Return a property with its ordinal.\n     *\n     * @param string      $key\n     * @param string|null $period\n     *\n     * @return string\n     */\n    public function ordinal(string $key, ?string $period = null): string\n    {\n        $number = $this->$key;\n        $result = $this->translate('ordinal', [\n            ':number' => $number,\n            ':period' => (string) $period,\n        ]);\n\n        return (string) ($result === 'ordinal' ? $number : $result);\n    }\n\n    /**\n     * Return the meridiem of the current time in the current locale.\n     *\n     * @param bool $isLower if true, returns lowercase variant if available in the current locale.\n     *\n     * @return string\n     */\n    public function meridiem(bool $isLower = false): string\n    {\n        $hour = $this->hour;\n        $index = $hour < 12 ? 0 : 1;\n\n        if ($isLower) {\n            $key = 'meridiem.'.($index + 2);\n            $result = $this->translate($key);\n\n            if ($result !== $key) {\n                return $result;\n            }\n        }\n\n        $key = \"meridiem.$index\";\n        $result = $this->translate($key);\n        if ($result === $key) {\n            $result = $this->translate('meridiem', [\n                ':hour' => $this->hour,\n                ':minute' => $this->minute,\n                ':isLower' => $isLower,\n            ]);\n\n            if ($result === 'meridiem') {\n                return $isLower ? $this->latinMeridiem : $this->latinUpperMeridiem;\n            }\n        } elseif ($isLower) {\n            $result = mb_strtolower($result);\n        }\n\n        return $result;\n    }\n\n    /**\n     * Returns the alternative number for a given date property if available in the current locale.\n     *\n     * @param string $key date property\n     *\n     * @return string\n     */\n    public function getAltNumber(string $key): string\n    {\n        return $this->translateNumber(\\strlen($key) > 1 ? $this->$key : $this->rawFormat('h'));\n    }\n\n    /**\n     * Format in the current language using ISO replacement patterns.\n     *\n     * @param string      $format\n     * @param string|null $originalFormat provide context if a chunk has been passed alone\n     *\n     * @return string\n     */\n    public function isoFormat(string $format, ?string $originalFormat = null): string\n    {\n        $result = '';\n        $length = mb_strlen($format);\n        $originalFormat = $originalFormat ?: $format;\n        $inEscaped = false;\n        $formats = null;\n        $units = null;\n\n        for ($i = 0; $i < $length; $i++) {\n            $char = mb_substr($format, $i, 1);\n\n            if ($char === '\\\\') {\n                $result .= mb_substr($format, ++$i, 1);\n\n                continue;\n            }\n\n            if ($char === '[' && !$inEscaped) {\n                $inEscaped = true;\n\n                continue;\n            }\n\n            if ($char === ']' && $inEscaped) {\n                $inEscaped = false;\n\n                continue;\n            }\n\n            if ($inEscaped) {\n                $result .= $char;\n\n                continue;\n            }\n\n            $input = mb_substr($format, $i);\n\n            if (preg_match('/^(LTS|LT|l{1,4}|L{1,4})/', $input, $match)) {\n                if ($formats === null) {\n                    $formats = $this->getIsoFormats();\n                }\n\n                $code = $match[0];\n                $sequence = $formats[$code] ?? preg_replace_callback(\n                    '/MMMM|MM|DD|dddd/',\n                    function ($code) {\n                        return mb_substr($code[0], 1);\n                    },\n                    $formats[strtoupper($code)] ?? ''\n                );\n                $rest = mb_substr($format, $i + mb_strlen($code));\n                $format = mb_substr($format, 0, $i).$sequence.$rest;\n                $length = mb_strlen($format);\n                $input = $sequence.$rest;\n            }\n\n            if (preg_match('/^'.CarbonInterface::ISO_FORMAT_REGEXP.'/', $input, $match)) {\n                $code = $match[0];\n\n                if ($units === null) {\n                    $units = static::getIsoUnits();\n                }\n\n                $sequence = $units[$code] ?? '';\n\n                if ($sequence instanceof Closure) {\n                    $sequence = $sequence($this, $originalFormat);\n                } elseif (\\is_array($sequence)) {\n                    try {\n                        $sequence = $this->{$sequence[0]}(...$sequence[1]);\n                    } catch (ReflectionException | InvalidArgumentException | BadMethodCallException $e) {\n                        $sequence = '';\n                    }\n                } elseif (\\is_string($sequence)) {\n                    $sequence = $this->$sequence ?? $code;\n                }\n\n                $format = mb_substr($format, 0, $i).$sequence.mb_substr($format, $i + mb_strlen($code));\n                $i += mb_strlen((string) $sequence) - 1;\n                $length = mb_strlen($format);\n                $char = $sequence;\n            }\n\n            $result .= $char;\n        }\n\n        return $result;\n    }\n\n    /**\n     * List of replacements from date() format to isoFormat().\n     *\n     * @return array\n     */\n    public static function getFormatsToIsoReplacements()\n    {\n        static $replacements = null;\n\n        if ($replacements === null) {\n            $replacements = [\n                'd' => true,\n                'D' => 'ddd',\n                'j' => true,\n                'l' => 'dddd',\n                'N' => true,\n                'S' => function ($date) {\n                    $day = $date->rawFormat('j');\n\n                    return str_replace((string) $day, '', $date->isoFormat('Do'));\n                },\n                'w' => true,\n                'z' => true,\n                'W' => true,\n                'F' => 'MMMM',\n                'm' => true,\n                'M' => 'MMM',\n                'n' => true,\n                't' => true,\n                'L' => true,\n                'o' => true,\n                'Y' => true,\n                'y' => true,\n                'a' => 'a',\n                'A' => 'A',\n                'B' => true,\n                'g' => true,\n                'G' => true,\n                'h' => true,\n                'H' => true,\n                'i' => true,\n                's' => true,\n                'u' => true,\n                'v' => true,\n                'E' => true,\n                'I' => true,\n                'O' => true,\n                'P' => true,\n                'Z' => true,\n                'c' => true,\n                'r' => true,\n                'U' => true,\n                'T' => true,\n            ];\n        }\n\n        return $replacements;\n    }\n\n    /**\n     * Format as ->format() do (using date replacements patterns from https://php.net/manual/en/function.date.php)\n     * but translate words whenever possible (months, day names, etc.) using the current locale.\n     *\n     * @param string $format\n     *\n     * @return string\n     */\n    public function translatedFormat(string $format): string\n    {\n        $replacements = static::getFormatsToIsoReplacements();\n        $context = '';\n        $isoFormat = '';\n        $length = mb_strlen($format);\n\n        for ($i = 0; $i < $length; $i++) {\n            $char = mb_substr($format, $i, 1);\n\n            if ($char === '\\\\') {\n                $replacement = mb_substr($format, $i, 2);\n                $isoFormat .= $replacement;\n                $i++;\n\n                continue;\n            }\n\n            if (!isset($replacements[$char])) {\n                $replacement = preg_match('/^[A-Za-z]$/', $char) ? \"\\\\$char\" : $char;\n                $isoFormat .= $replacement;\n                $context .= $replacement;\n\n                continue;\n            }\n\n            $replacement = $replacements[$char];\n\n            if ($replacement === true) {\n                static $contextReplacements = null;\n\n                if ($contextReplacements === null) {\n                    $contextReplacements = [\n                        'm' => 'MM',\n                        'd' => 'DD',\n                        't' => 'D',\n                        'j' => 'D',\n                        'N' => 'e',\n                        'w' => 'e',\n                        'n' => 'M',\n                        'o' => 'YYYY',\n                        'Y' => 'YYYY',\n                        'y' => 'YY',\n                        'g' => 'h',\n                        'G' => 'H',\n                        'h' => 'hh',\n                        'H' => 'HH',\n                        'i' => 'mm',\n                        's' => 'ss',\n                    ];\n                }\n\n                $isoFormat .= '['.$this->rawFormat($char).']';\n                $context .= $contextReplacements[$char] ?? ' ';\n\n                continue;\n            }\n\n            if ($replacement instanceof Closure) {\n                $replacement = '['.$replacement($this).']';\n                $isoFormat .= $replacement;\n                $context .= $replacement;\n\n                continue;\n            }\n\n            $isoFormat .= $replacement;\n            $context .= $replacement;\n        }\n\n        return $this->isoFormat($isoFormat, $context);\n    }\n\n    /**\n     * Returns the offset hour and minute formatted with +/- and a given separator (\":\" by default).\n     * For example, if the time zone is 9 hours 30 minutes, you'll get \"+09:30\", with \"@@\" as first\n     * argument, \"+09@@30\", with \"\" as first argument, \"+0930\". Negative offset will return something\n     * like \"-12:00\".\n     *\n     * @param string $separator string to place between hours and minutes (\":\" by default)\n     *\n     * @return string\n     */\n    public function getOffsetString($separator = ':')\n    {\n        $second = $this->getOffset();\n        $symbol = $second < 0 ? '-' : '+';\n        $minute = abs($second) / static::SECONDS_PER_MINUTE;\n        $hour = str_pad((string) floor($minute / static::MINUTES_PER_HOUR), 2, '0', STR_PAD_LEFT);\n        $minute = str_pad((string) (((int) $minute) % static::MINUTES_PER_HOUR), 2, '0', STR_PAD_LEFT);\n\n        return \"$symbol$hour$separator$minute\";\n    }\n\n    protected static function executeStaticCallable($macro, ...$parameters)\n    {\n        return static::bindMacroContext(null, function () use (&$macro, &$parameters) {\n            if ($macro instanceof Closure) {\n                $boundMacro = @Closure::bind($macro, null, static::class);\n\n                return ($boundMacro ?: $macro)(...$parameters);\n            }\n\n            return $macro(...$parameters);\n        });\n    }\n\n    /**\n     * Dynamically handle calls to the class.\n     *\n     * @param string $method     magic method name called\n     * @param array  $parameters parameters list\n     *\n     * @throws BadMethodCallException\n     *\n     * @return mixed\n     */\n    public static function __callStatic($method, $parameters)\n    {\n        if (!static::hasMacro($method)) {\n            foreach (static::getGenericMacros() as $callback) {\n                try {\n                    return static::executeStaticCallable($callback, $method, ...$parameters);\n                } catch (BadMethodCallException $exception) {\n                    continue;\n                }\n            }\n            if (static::isStrictModeEnabled()) {\n                throw new UnknownMethodException(\\sprintf('%s::%s', static::class, $method));\n            }\n\n            return null;\n        }\n\n        return static::executeStaticCallable(static::$globalMacros[$method], ...$parameters);\n    }\n\n    /**\n     * Set specified unit to new given value.\n     *\n     * @param string $unit  year, month, day, hour, minute, second or microsecond\n     * @param int    $value new value for given unit\n     *\n     * @return static\n     */\n    public function setUnit($unit, $value = null)\n    {\n        $unit = static::singularUnit($unit);\n        $dateUnits = ['year', 'month', 'day'];\n        if (\\in_array($unit, $dateUnits)) {\n            return $this->setDate(...array_map(function ($name) use ($unit, $value) {\n                return (int) ($name === $unit ? $value : $this->$name);\n            }, $dateUnits));\n        }\n\n        $units = ['hour', 'minute', 'second', 'micro'];\n        if ($unit === 'millisecond' || $unit === 'milli') {\n            $value *= 1000;\n            $unit = 'micro';\n        } elseif ($unit === 'microsecond') {\n            $unit = 'micro';\n        }\n\n        return $this->setTime(...array_map(function ($name) use ($unit, $value) {\n            return (int) ($name === $unit ? $value : $this->$name);\n        }, $units));\n    }\n\n    /**\n     * Returns standardized singular of a given singular/plural unit name (in English).\n     *\n     * @param string $unit\n     *\n     * @return string\n     */\n    public static function singularUnit(string $unit): string\n    {\n        $unit = rtrim(mb_strtolower($unit), 's');\n\n        if ($unit === 'centurie') {\n            return 'century';\n        }\n\n        if ($unit === 'millennia') {\n            return 'millennium';\n        }\n\n        return $unit;\n    }\n\n    /**\n     * Returns standardized plural of a given singular/plural unit name (in English).\n     *\n     * @param string $unit\n     *\n     * @return string\n     */\n    public static function pluralUnit(string $unit): string\n    {\n        $unit = rtrim(strtolower($unit), 's');\n\n        if ($unit === 'century') {\n            return 'centuries';\n        }\n\n        if ($unit === 'millennium' || $unit === 'millennia') {\n            return 'millennia';\n        }\n\n        return \"{$unit}s\";\n    }\n\n    protected function executeCallable($macro, ...$parameters)\n    {\n        if ($macro instanceof Closure) {\n            $boundMacro = @$macro->bindTo($this, static::class) ?: @$macro->bindTo(null, static::class);\n\n            return ($boundMacro ?: $macro)(...$parameters);\n        }\n\n        return $macro(...$parameters);\n    }\n\n    protected function executeCallableWithContext($macro, ...$parameters)\n    {\n        return static::bindMacroContext($this, function () use (&$macro, &$parameters) {\n            return $this->executeCallable($macro, ...$parameters);\n        });\n    }\n\n    protected static function getGenericMacros()\n    {\n        foreach (static::$globalGenericMacros as $list) {\n            foreach ($list as $macro) {\n                yield $macro;\n            }\n        }\n    }\n\n    /**\n     * Dynamically handle calls to the class.\n     *\n     * @param string $method     magic method name called\n     * @param array  $parameters parameters list\n     *\n     * @throws UnknownMethodException|BadMethodCallException|ReflectionException|Throwable\n     *\n     * @return mixed\n     */\n    public function __call($method, $parameters)\n    {\n        $diffSizes = [\n            // @mode diffForHumans\n            'short' => true,\n            // @mode diffForHumans\n            'long' => false,\n        ];\n        $diffSyntaxModes = [\n            // @call diffForHumans\n            'Absolute' => CarbonInterface::DIFF_ABSOLUTE,\n            // @call diffForHumans\n            'Relative' => CarbonInterface::DIFF_RELATIVE_AUTO,\n            // @call diffForHumans\n            'RelativeToNow' => CarbonInterface::DIFF_RELATIVE_TO_NOW,\n            // @call diffForHumans\n            'RelativeToOther' => CarbonInterface::DIFF_RELATIVE_TO_OTHER,\n        ];\n        $sizePattern = implode('|', array_keys($diffSizes));\n        $syntaxPattern = implode('|', array_keys($diffSyntaxModes));\n\n        if (preg_match(\"/^(?<size>$sizePattern)(?<syntax>$syntaxPattern)DiffForHumans$/\", $method, $match)) {\n            $dates = array_filter($parameters, function ($parameter) {\n                return $parameter instanceof DateTimeInterface;\n            });\n            $other = null;\n\n            if (\\count($dates)) {\n                $key = key($dates);\n                $other = current($dates);\n                array_splice($parameters, $key, 1);\n            }\n\n            return $this->diffForHumans($other, $diffSyntaxModes[$match['syntax']], $diffSizes[$match['size']], ...$parameters);\n        }\n\n        $roundedValue = $this->callRoundMethod($method, $parameters);\n\n        if ($roundedValue !== null) {\n            return $roundedValue;\n        }\n\n        $unit = rtrim($method, 's');\n\n        if (str_starts_with($unit, 'is')) {\n            $word = substr($unit, 2);\n\n            if (\\in_array($word, static::$days, true)) {\n                return $this->isDayOfWeek($word);\n            }\n\n            switch ($word) {\n                // @call is Check if the current instance has UTC timezone. (Both isUtc and isUTC cases are valid.)\n                case 'Utc':\n                case 'UTC':\n                    return $this->utc;\n                // @call is Check if the current instance has non-UTC timezone.\n                case 'Local':\n                    return $this->local;\n                // @call is Check if the current instance is a valid date.\n                case 'Valid':\n                    return $this->year !== 0;\n                // @call is Check if the current instance is in a daylight saving time.\n                case 'DST':\n                    return $this->dst;\n            }\n        }\n\n        $action = substr($unit, 0, 3);\n        $overflow = null;\n\n        if ($action === 'set') {\n            $unit = strtolower(substr($unit, 3));\n        }\n\n        if (\\in_array($unit, static::$units, true)) {\n            return $this->setUnit($unit, ...$parameters);\n        }\n\n        if ($action === 'add' || $action === 'sub') {\n            $unit = substr($unit, 3);\n\n            if (str_starts_with($unit, 'Real')) {\n                $unit = static::singularUnit(substr($unit, 4));\n\n                return $this->{\"{$action}RealUnit\"}($unit, ...$parameters);\n            }\n\n            if (preg_match('/^(Month|Quarter|Year|Decade|Century|Centurie|Millennium|Millennia)s?(No|With|Without|WithNo)Overflow$/', $unit, $match)) {\n                $unit = $match[1];\n                $overflow = $match[2] === 'With';\n            }\n\n            $unit = static::singularUnit($unit);\n        }\n\n        if (static::isModifiableUnit($unit)) {\n            return $this->{\"{$action}Unit\"}($unit, $this->getMagicParameter($parameters, 0, 'value', 1), $overflow);\n        }\n\n        $sixFirstLetters = substr($unit, 0, 6);\n        $factor = -1;\n\n        if ($sixFirstLetters === 'isLast') {\n            $sixFirstLetters = 'isNext';\n            $factor = 1;\n        }\n\n        if ($sixFirstLetters === 'isNext') {\n            $lowerUnit = strtolower(substr($unit, 6));\n\n            if (static::isModifiableUnit($lowerUnit)) {\n                return $this->copy()->addUnit($lowerUnit, $factor, false)->isSameUnit($lowerUnit, ...$parameters);\n            }\n        }\n\n        if ($sixFirstLetters === 'isSame') {\n            try {\n                return $this->isSameUnit(strtolower(substr($unit, 6)), ...$parameters);\n            } catch (BadComparisonUnitException $exception) {\n                // Try next\n            }\n        }\n\n        if (str_starts_with($unit, 'isCurrent')) {\n            try {\n                return $this->isCurrentUnit(strtolower(substr($unit, 9)));\n            } catch (BadComparisonUnitException | BadMethodCallException $exception) {\n                // Try next\n            }\n        }\n\n        if (str_ends_with($method, 'Until')) {\n            try {\n                $unit = static::singularUnit(substr($method, 0, -5));\n\n                return $this->range(\n                    $this->getMagicParameter($parameters, 0, 'endDate', $this),\n                    $this->getMagicParameter($parameters, 1, 'factor', 1),\n                    $unit\n                );\n            } catch (InvalidArgumentException $exception) {\n                // Try macros\n            }\n        }\n\n        return static::bindMacroContext($this, function () use (&$method, &$parameters) {\n            $macro = $this->getLocalMacro($method);\n\n            if (!$macro) {\n                foreach ([$this->localGenericMacros ?: [], static::getGenericMacros()] as $list) {\n                    foreach ($list as $callback) {\n                        try {\n                            return $this->executeCallable($callback, $method, ...$parameters);\n                        } catch (BadMethodCallException $exception) {\n                            continue;\n                        }\n                    }\n                }\n\n                if ($this->localStrictModeEnabled ?? static::isStrictModeEnabled()) {\n                    throw new UnknownMethodException($method);\n                }\n\n                return null;\n            }\n\n            return $this->executeCallable($macro, ...$parameters);\n        });\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Traits/DeprecatedProperties.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Traits;\n\ntrait DeprecatedProperties\n{\n    /**\n     * the day of week in current locale LC_TIME\n     *\n     * @var string\n     *\n     * @deprecated It uses OS language package and strftime() which is deprecated since PHP 8.1.\n     *             Use ->isoFormat('MMM') instead.\n     *             Deprecated since 2.55.0\n     */\n    public $localeDayOfWeek;\n\n    /**\n     * the abbreviated day of week in current locale LC_TIME\n     *\n     * @var string\n     *\n     * @deprecated It uses OS language package and strftime() which is deprecated since PHP 8.1.\n     *             Use ->isoFormat('dddd') instead.\n     *             Deprecated since 2.55.0\n     */\n    public $shortLocaleDayOfWeek;\n\n    /**\n     * the month in current locale LC_TIME\n     *\n     * @var string\n     *\n     * @deprecated It uses OS language package and strftime() which is deprecated since PHP 8.1.\n     *             Use ->isoFormat('ddd') instead.\n     *             Deprecated since 2.55.0\n     */\n    public $localeMonth;\n\n    /**\n     * the abbreviated month in current locale LC_TIME\n     *\n     * @var string\n     *\n     * @deprecated It uses OS language package and strftime() which is deprecated since PHP 8.1.\n     *             Use ->isoFormat('MMMM') instead.\n     *             Deprecated since 2.55.0\n     */\n    public $shortLocaleMonth;\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Traits/Difference.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Traits;\n\nuse Carbon\\Carbon;\nuse Carbon\\CarbonImmutable;\nuse Carbon\\CarbonInterface;\nuse Carbon\\CarbonInterval;\nuse Carbon\\CarbonPeriod;\nuse Carbon\\Translator;\nuse Closure;\nuse DateInterval;\nuse DateTimeInterface;\nuse ReturnTypeWillChange;\n\n/**\n * Trait Difference.\n *\n * Depends on the following methods:\n *\n * @method bool lessThan($date)\n * @method static copy()\n * @method static resolveCarbon($date = null)\n * @method static Translator translator()\n */\ntrait Difference\n{\n    /**\n     * @codeCoverageIgnore\n     *\n     * @param CarbonInterval $diff\n     */\n    protected static function fixNegativeMicroseconds(CarbonInterval $diff)\n    {\n        if ($diff->s !== 0 || $diff->i !== 0 || $diff->h !== 0 || $diff->d !== 0 || $diff->m !== 0 || $diff->y !== 0) {\n            $diff->f = (round($diff->f * 1000000) + 1000000) / 1000000;\n            $diff->s--;\n\n            if ($diff->s < 0) {\n                $diff->s += 60;\n                $diff->i--;\n\n                if ($diff->i < 0) {\n                    $diff->i += 60;\n                    $diff->h--;\n\n                    if ($diff->h < 0) {\n                        $diff->h += 24;\n                        $diff->d--;\n\n                        if ($diff->d < 0) {\n                            $diff->d += 30;\n                            $diff->m--;\n\n                            if ($diff->m < 0) {\n                                $diff->m += 12;\n                                $diff->y--;\n                            }\n                        }\n                    }\n                }\n            }\n\n            return;\n        }\n\n        $diff->f *= -1;\n        $diff->invert();\n    }\n\n    /**\n     * @param DateInterval $diff\n     * @param bool         $absolute\n     *\n     * @return CarbonInterval\n     */\n    protected static function fixDiffInterval(DateInterval $diff, $absolute, array $skip = [])\n    {\n        $diff = CarbonInterval::instance($diff, $skip);\n\n        // Work-around for https://bugs.php.net/bug.php?id=77145\n        // @codeCoverageIgnoreStart\n        if ($diff->f > 0 && $diff->y === -1 && $diff->m === 11 && $diff->d >= 27 && $diff->h === 23 && $diff->i === 59 && $diff->s === 59) {\n            $diff->y = 0;\n            $diff->m = 0;\n            $diff->d = 0;\n            $diff->h = 0;\n            $diff->i = 0;\n            $diff->s = 0;\n            $diff->f = (1000000 - round($diff->f * 1000000)) / 1000000;\n            $diff->invert();\n        } elseif ($diff->f < 0) {\n            static::fixNegativeMicroseconds($diff);\n        }\n        // @codeCoverageIgnoreEnd\n\n        if ($absolute && $diff->invert) {\n            $diff->invert();\n        }\n\n        return $diff;\n    }\n\n    /**\n     * Get the difference as a DateInterval instance.\n     * Return relative interval (negative if $absolute flag is not set to true and the given date is before\n     * current one).\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return DateInterval\n     */\n    #[ReturnTypeWillChange]\n    public function diff($date = null, $absolute = false)\n    {\n        $other = $this->resolveCarbon($date);\n\n        // Work-around for https://bugs.php.net/bug.php?id=81458\n        // It was initially introduced for https://bugs.php.net/bug.php?id=80998\n        // The very specific case of 80998 was fixed in PHP 8.1beta3, but it introduced 81458\n        // So we still need to keep this for now\n        // @codeCoverageIgnoreStart\n        if (version_compare(PHP_VERSION, '8.1.0-dev', '>=') && $other->tz !== $this->tz) {\n            $other = $other->avoidMutation()->tz($this->tz);\n        }\n        // @codeCoverageIgnoreEnd\n\n        return parent::diff($other, (bool) $absolute);\n    }\n\n    /**\n     * Get the difference as a CarbonInterval instance.\n     * Return relative interval (negative if $absolute flag is not set to true and the given date is before\n     * current one).\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return CarbonInterval\n     */\n    public function diffAsCarbonInterval($date = null, $absolute = true, array $skip = [])\n    {\n        return static::fixDiffInterval($this->diff($this->resolveCarbon($date), $absolute), $absolute, $skip);\n    }\n\n    /**\n     * Get the difference in years\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return int\n     */\n    public function diffInYears($date = null, $absolute = true)\n    {\n        return (int) $this->diff($this->resolveCarbon($date), $absolute)->format('%r%y');\n    }\n\n    /**\n     * Get the difference in quarters rounded down.\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return int\n     */\n    public function diffInQuarters($date = null, $absolute = true)\n    {\n        return (int) ($this->diffInMonths($date, $absolute) / static::MONTHS_PER_QUARTER);\n    }\n\n    /**\n     * Get the difference in months rounded down.\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return int\n     */\n    public function diffInMonths($date = null, $absolute = true)\n    {\n        $date = $this->resolveCarbon($date)->avoidMutation()->tz($this->tz);\n\n        [$yearStart, $monthStart, $dayStart] = explode('-', $this->format('Y-m-dHisu'));\n        [$yearEnd, $monthEnd, $dayEnd] = explode('-', $date->format('Y-m-dHisu'));\n\n        $diff = (((int) $yearEnd) - ((int) $yearStart)) * static::MONTHS_PER_YEAR +\n            ((int) $monthEnd) - ((int) $monthStart);\n\n        if ($diff > 0) {\n            $diff -= ($dayStart > $dayEnd ? 1 : 0);\n        } elseif ($diff < 0) {\n            $diff += ($dayStart < $dayEnd ? 1 : 0);\n        }\n\n        return $absolute ? abs($diff) : $diff;\n    }\n\n    /**\n     * Get the difference in weeks rounded down.\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return int\n     */\n    public function diffInWeeks($date = null, $absolute = true)\n    {\n        return (int) ($this->diffInDays($date, $absolute) / static::DAYS_PER_WEEK);\n    }\n\n    /**\n     * Get the difference in days rounded down.\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return int\n     */\n    public function diffInDays($date = null, $absolute = true)\n    {\n        return $this->getIntervalDayDiff($this->diff($this->resolveCarbon($date), $absolute));\n    }\n\n    /**\n     * Get the difference in days using a filter closure rounded down.\n     *\n     * @param Closure                                                $callback\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return int\n     */\n    public function diffInDaysFiltered(Closure $callback, $date = null, $absolute = true)\n    {\n        return $this->diffFiltered(CarbonInterval::day(), $callback, $date, $absolute);\n    }\n\n    /**\n     * Get the difference in hours using a filter closure rounded down.\n     *\n     * @param Closure                                                $callback\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return int\n     */\n    public function diffInHoursFiltered(Closure $callback, $date = null, $absolute = true)\n    {\n        return $this->diffFiltered(CarbonInterval::hour(), $callback, $date, $absolute);\n    }\n\n    /**\n     * Get the difference by the given interval using a filter closure.\n     *\n     * @param CarbonInterval                                         $ci       An interval to traverse by\n     * @param Closure                                                $callback\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return int\n     */\n    public function diffFiltered(CarbonInterval $ci, Closure $callback, $date = null, $absolute = true)\n    {\n        $start = $this;\n        $end = $this->resolveCarbon($date);\n        $inverse = false;\n\n        if ($end < $start) {\n            $start = $end;\n            $end = $this;\n            $inverse = true;\n        }\n\n        $options = CarbonPeriod::EXCLUDE_END_DATE | ($this->isMutable() ? 0 : CarbonPeriod::IMMUTABLE);\n        $diff = $ci->toPeriod($start, $end, $options)->filter($callback)->count();\n\n        return $inverse && !$absolute ? -$diff : $diff;\n    }\n\n    /**\n     * Get the difference in weekdays rounded down.\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return int\n     */\n    public function diffInWeekdays($date = null, $absolute = true)\n    {\n        return $this->diffInDaysFiltered(static function (CarbonInterface $date) {\n            return $date->isWeekday();\n        }, $this->resolveCarbon($date)->avoidMutation()->modify($this->format('H:i:s.u')), $absolute);\n    }\n\n    /**\n     * Get the difference in weekend days using a filter rounded down.\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return int\n     */\n    public function diffInWeekendDays($date = null, $absolute = true)\n    {\n        return $this->diffInDaysFiltered(static function (CarbonInterface $date) {\n            return $date->isWeekend();\n        }, $this->resolveCarbon($date)->avoidMutation()->modify($this->format('H:i:s.u')), $absolute);\n    }\n\n    /**\n     * Get the difference in hours rounded down.\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return int\n     */\n    public function diffInHours($date = null, $absolute = true)\n    {\n        return (int) ($this->diffInSeconds($date, $absolute) / static::SECONDS_PER_MINUTE / static::MINUTES_PER_HOUR);\n    }\n\n    /**\n     * Get the difference in hours rounded down using timestamps.\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return int\n     */\n    public function diffInRealHours($date = null, $absolute = true)\n    {\n        return (int) ($this->diffInRealSeconds($date, $absolute) / static::SECONDS_PER_MINUTE / static::MINUTES_PER_HOUR);\n    }\n\n    /**\n     * Get the difference in minutes rounded down.\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return int\n     */\n    public function diffInMinutes($date = null, $absolute = true)\n    {\n        return (int) ($this->diffInSeconds($date, $absolute) / static::SECONDS_PER_MINUTE);\n    }\n\n    /**\n     * Get the difference in minutes rounded down using timestamps.\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return int\n     */\n    public function diffInRealMinutes($date = null, $absolute = true)\n    {\n        return (int) ($this->diffInRealSeconds($date, $absolute) / static::SECONDS_PER_MINUTE);\n    }\n\n    /**\n     * Get the difference in seconds rounded down.\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return int\n     */\n    public function diffInSeconds($date = null, $absolute = true)\n    {\n        $diff = $this->diff($date);\n\n        if ($diff->days === 0) {\n            $diff = static::fixDiffInterval($diff, $absolute);\n        }\n\n        $value = (((($diff->m || $diff->y ? $diff->days : $diff->d) * static::HOURS_PER_DAY) +\n            $diff->h) * static::MINUTES_PER_HOUR +\n            $diff->i) * static::SECONDS_PER_MINUTE +\n            $diff->s;\n\n        return $absolute || !$diff->invert ? $value : -$value;\n    }\n\n    /**\n     * Get the difference in microseconds.\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return int\n     */\n    public function diffInMicroseconds($date = null, $absolute = true)\n    {\n        $diff = $this->diff($date);\n        $value = (int) round(((((($diff->m || $diff->y ? $diff->days : $diff->d) * static::HOURS_PER_DAY) +\n            $diff->h) * static::MINUTES_PER_HOUR +\n            $diff->i) * static::SECONDS_PER_MINUTE +\n            ($diff->f + $diff->s)) * static::MICROSECONDS_PER_SECOND);\n\n        return $absolute || !$diff->invert ? $value : -$value;\n    }\n\n    /**\n     * Get the difference in milliseconds rounded down.\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return int\n     */\n    public function diffInMilliseconds($date = null, $absolute = true)\n    {\n        return (int) ($this->diffInMicroseconds($date, $absolute) / static::MICROSECONDS_PER_MILLISECOND);\n    }\n\n    /**\n     * Get the difference in seconds using timestamps.\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return int\n     */\n    public function diffInRealSeconds($date = null, $absolute = true)\n    {\n        /** @var CarbonInterface $date */\n        $date = $this->resolveCarbon($date);\n        $value = $date->getTimestamp() - $this->getTimestamp();\n\n        return $absolute ? abs($value) : $value;\n    }\n\n    /**\n     * Get the difference in microseconds using timestamps.\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return int\n     */\n    public function diffInRealMicroseconds($date = null, $absolute = true)\n    {\n        /** @var CarbonInterface $date */\n        $date = $this->resolveCarbon($date);\n        $value = ($date->timestamp - $this->timestamp) * static::MICROSECONDS_PER_SECOND +\n            $date->micro - $this->micro;\n\n        return $absolute ? abs($value) : $value;\n    }\n\n    /**\n     * Get the difference in milliseconds rounded down using timestamps.\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return int\n     */\n    public function diffInRealMilliseconds($date = null, $absolute = true)\n    {\n        return (int) ($this->diffInRealMicroseconds($date, $absolute) / static::MICROSECONDS_PER_MILLISECOND);\n    }\n\n    /**\n     * Get the difference in seconds as float (microsecond-precision).\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return float\n     */\n    public function floatDiffInSeconds($date = null, $absolute = true)\n    {\n        return (float) ($this->diffInMicroseconds($date, $absolute) / static::MICROSECONDS_PER_SECOND);\n    }\n\n    /**\n     * Get the difference in minutes as float (microsecond-precision).\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return float\n     */\n    public function floatDiffInMinutes($date = null, $absolute = true)\n    {\n        return $this->floatDiffInSeconds($date, $absolute) / static::SECONDS_PER_MINUTE;\n    }\n\n    /**\n     * Get the difference in hours as float (microsecond-precision).\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return float\n     */\n    public function floatDiffInHours($date = null, $absolute = true)\n    {\n        return $this->floatDiffInMinutes($date, $absolute) / static::MINUTES_PER_HOUR;\n    }\n\n    /**\n     * Get the difference in days as float (microsecond-precision).\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return float\n     */\n    public function floatDiffInDays($date = null, $absolute = true)\n    {\n        $hoursDiff = $this->floatDiffInHours($date, $absolute);\n        $interval = $this->diff($date, $absolute);\n\n        if ($interval->y === 0 && $interval->m === 0 && $interval->d === 0) {\n            return $hoursDiff / static::HOURS_PER_DAY;\n        }\n\n        $daysDiff = $this->getIntervalDayDiff($interval);\n\n        return $daysDiff + fmod($hoursDiff, static::HOURS_PER_DAY) / static::HOURS_PER_DAY;\n    }\n\n    /**\n     * Get the difference in weeks as float (microsecond-precision).\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return float\n     */\n    public function floatDiffInWeeks($date = null, $absolute = true)\n    {\n        return $this->floatDiffInDays($date, $absolute) / static::DAYS_PER_WEEK;\n    }\n\n    /**\n     * Get the difference in months as float (microsecond-precision).\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return float\n     */\n    public function floatDiffInMonths($date = null, $absolute = true)\n    {\n        $start = $this;\n        $end = $this->resolveCarbon($date);\n        $ascending = ($start <= $end);\n        $sign = $absolute || $ascending ? 1 : -1;\n        if (!$ascending) {\n            [$start, $end] = [$end, $start];\n        }\n        $monthsDiff = $start->diffInMonths($end);\n        /** @var Carbon|CarbonImmutable $floorEnd */\n        $floorEnd = $start->avoidMutation()->addMonths($monthsDiff);\n\n        if ($floorEnd >= $end) {\n            return $sign * $monthsDiff;\n        }\n\n        /** @var Carbon|CarbonImmutable $startOfMonthAfterFloorEnd */\n        $startOfMonthAfterFloorEnd = $floorEnd->avoidMutation()->addMonth()->startOfMonth();\n\n        if ($startOfMonthAfterFloorEnd > $end) {\n            return $sign * ($monthsDiff + $floorEnd->floatDiffInDays($end) / $floorEnd->daysInMonth);\n        }\n\n        return $sign * ($monthsDiff + $floorEnd->floatDiffInDays($startOfMonthAfterFloorEnd) / $floorEnd->daysInMonth + $startOfMonthAfterFloorEnd->floatDiffInDays($end) / $end->daysInMonth);\n    }\n\n    /**\n     * Get the difference in year as float (microsecond-precision).\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return float\n     */\n    public function floatDiffInYears($date = null, $absolute = true)\n    {\n        $start = $this;\n        $end = $this->resolveCarbon($date);\n        $ascending = ($start <= $end);\n        $sign = $absolute || $ascending ? 1 : -1;\n        if (!$ascending) {\n            [$start, $end] = [$end, $start];\n        }\n        $yearsDiff = $start->diffInYears($end);\n        /** @var Carbon|CarbonImmutable $floorEnd */\n        $floorEnd = $start->avoidMutation()->addYears($yearsDiff);\n\n        if ($floorEnd >= $end) {\n            return $sign * $yearsDiff;\n        }\n\n        /** @var Carbon|CarbonImmutable $startOfYearAfterFloorEnd */\n        $startOfYearAfterFloorEnd = $floorEnd->avoidMutation()->addYear()->startOfYear();\n\n        if ($startOfYearAfterFloorEnd > $end) {\n            return $sign * ($yearsDiff + $floorEnd->floatDiffInDays($end) / $floorEnd->daysInYear);\n        }\n\n        return $sign * ($yearsDiff + $floorEnd->floatDiffInDays($startOfYearAfterFloorEnd) / $floorEnd->daysInYear + $startOfYearAfterFloorEnd->floatDiffInDays($end) / $end->daysInYear);\n    }\n\n    /**\n     * Get the difference in seconds as float (microsecond-precision) using timestamps.\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return float\n     */\n    public function floatDiffInRealSeconds($date = null, $absolute = true)\n    {\n        return $this->diffInRealMicroseconds($date, $absolute) / static::MICROSECONDS_PER_SECOND;\n    }\n\n    /**\n     * Get the difference in minutes as float (microsecond-precision) using timestamps.\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return float\n     */\n    public function floatDiffInRealMinutes($date = null, $absolute = true)\n    {\n        return $this->floatDiffInRealSeconds($date, $absolute) / static::SECONDS_PER_MINUTE;\n    }\n\n    /**\n     * Get the difference in hours as float (microsecond-precision) using timestamps.\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return float\n     */\n    public function floatDiffInRealHours($date = null, $absolute = true)\n    {\n        return $this->floatDiffInRealMinutes($date, $absolute) / static::MINUTES_PER_HOUR;\n    }\n\n    /**\n     * Get the difference in days as float (microsecond-precision).\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return float\n     */\n    public function floatDiffInRealDays($date = null, $absolute = true)\n    {\n        $date = $this->resolveUTC($date);\n        $utc = $this->avoidMutation()->utc();\n        $hoursDiff = $utc->floatDiffInRealHours($date, $absolute);\n\n        return ($hoursDiff < 0 ? -1 : 1) * $utc->diffInDays($date) + fmod($hoursDiff, static::HOURS_PER_DAY) / static::HOURS_PER_DAY;\n    }\n\n    /**\n     * Get the difference in weeks as float (microsecond-precision).\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return float\n     */\n    public function floatDiffInRealWeeks($date = null, $absolute = true)\n    {\n        return $this->floatDiffInRealDays($date, $absolute) / static::DAYS_PER_WEEK;\n    }\n\n    /**\n     * Get the difference in months as float (microsecond-precision) using timestamps.\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return float\n     */\n    public function floatDiffInRealMonths($date = null, $absolute = true)\n    {\n        $start = $this;\n        $end = $this->resolveCarbon($date);\n        $ascending = ($start <= $end);\n        $sign = $absolute || $ascending ? 1 : -1;\n        if (!$ascending) {\n            [$start, $end] = [$end, $start];\n        }\n        $monthsDiff = $start->diffInMonths($end);\n        /** @var Carbon|CarbonImmutable $floorEnd */\n        $floorEnd = $start->avoidMutation()->addMonths($monthsDiff);\n\n        if ($floorEnd >= $end) {\n            return $sign * $monthsDiff;\n        }\n\n        /** @var Carbon|CarbonImmutable $startOfMonthAfterFloorEnd */\n        $startOfMonthAfterFloorEnd = $floorEnd->avoidMutation()->addMonth()->startOfMonth();\n\n        if ($startOfMonthAfterFloorEnd > $end) {\n            return $sign * ($monthsDiff + $floorEnd->floatDiffInRealDays($end) / $floorEnd->daysInMonth);\n        }\n\n        return $sign * ($monthsDiff + $floorEnd->floatDiffInRealDays($startOfMonthAfterFloorEnd) / $floorEnd->daysInMonth + $startOfMonthAfterFloorEnd->floatDiffInRealDays($end) / $end->daysInMonth);\n    }\n\n    /**\n     * Get the difference in year as float (microsecond-precision) using timestamps.\n     *\n     * @param \\Carbon\\CarbonInterface|\\DateTimeInterface|string|null $date\n     * @param bool                                                   $absolute Get the absolute of the difference\n     *\n     * @return float\n     */\n    public function floatDiffInRealYears($date = null, $absolute = true)\n    {\n        $start = $this;\n        $end = $this->resolveCarbon($date);\n        $ascending = ($start <= $end);\n        $sign = $absolute || $ascending ? 1 : -1;\n        if (!$ascending) {\n            [$start, $end] = [$end, $start];\n        }\n        $yearsDiff = $start->diffInYears($end);\n        /** @var Carbon|CarbonImmutable $floorEnd */\n        $floorEnd = $start->avoidMutation()->addYears($yearsDiff);\n\n        if ($floorEnd >= $end) {\n            return $sign * $yearsDiff;\n        }\n\n        /** @var Carbon|CarbonImmutable $startOfYearAfterFloorEnd */\n        $startOfYearAfterFloorEnd = $floorEnd->avoidMutation()->addYear()->startOfYear();\n\n        if ($startOfYearAfterFloorEnd > $end) {\n            return $sign * ($yearsDiff + $floorEnd->floatDiffInRealDays($end) / $floorEnd->daysInYear);\n        }\n\n        return $sign * ($yearsDiff + $floorEnd->floatDiffInRealDays($startOfYearAfterFloorEnd) / $floorEnd->daysInYear + $startOfYearAfterFloorEnd->floatDiffInRealDays($end) / $end->daysInYear);\n    }\n\n    /**\n     * The number of seconds since midnight.\n     *\n     * @return int\n     */\n    public function secondsSinceMidnight()\n    {\n        return $this->diffInSeconds($this->avoidMutation()->startOfDay());\n    }\n\n    /**\n     * The number of seconds until 23:59:59.\n     *\n     * @return int\n     */\n    public function secondsUntilEndOfDay()\n    {\n        return $this->diffInSeconds($this->avoidMutation()->endOfDay());\n    }\n\n    /**\n     * Get the difference in a human readable format in the current locale from current instance to an other\n     * instance given (or now if null given).\n     *\n     * @example\n     * ```\n     * echo Carbon::tomorrow()->diffForHumans() . \"\\n\";\n     * echo Carbon::tomorrow()->diffForHumans(['parts' => 2]) . \"\\n\";\n     * echo Carbon::tomorrow()->diffForHumans(['parts' => 3, 'join' => true]) . \"\\n\";\n     * echo Carbon::tomorrow()->diffForHumans(Carbon::yesterday()) . \"\\n\";\n     * echo Carbon::tomorrow()->diffForHumans(Carbon::yesterday(), ['short' => true]) . \"\\n\";\n     * ```\n     *\n     * @param Carbon|\\DateTimeInterface|string|array|null $other   if array passed, will be used as parameters array, see $syntax below;\n     *                                                             if null passed, now will be used as comparison reference;\n     *                                                             if any other type, it will be converted to date and used as reference.\n     * @param int|array                                   $syntax  if array passed, parameters will be extracted from it, the array may contains:\n     *                                                             - 'syntax' entry (see below)\n     *                                                             - 'short' entry (see below)\n     *                                                             - 'parts' entry (see below)\n     *                                                             - 'options' entry (see below)\n     *                                                             - 'skip' entry, list of units to skip (array of strings or a single string,\n     *                                                             ` it can be the unit name (singular or plural) or its shortcut\n     *                                                             ` (y, m, w, d, h, min, s, ms, µs).\n     *                                                             - 'aUnit' entry, prefer \"an hour\" over \"1 hour\" if true\n     *                                                             - 'join' entry determines how to join multiple parts of the string\n     *                                                             `  - if $join is a string, it's used as a joiner glue\n     *                                                             `  - if $join is a callable/closure, it get the list of string and should return a string\n     *                                                             `  - if $join is an array, the first item will be the default glue, and the second item\n     *                                                             `    will be used instead of the glue for the last item\n     *                                                             `  - if $join is true, it will be guessed from the locale ('list' translation file entry)\n     *                                                             `  - if $join is missing, a space will be used as glue\n     *                                                             - 'other' entry (see above)\n     *                                                             - 'minimumUnit' entry determines the smallest unit of time to display can be long or\n     *                                                             `  short form of the units, e.g. 'hour' or 'h' (default value: s)\n     *                                                             if int passed, it add modifiers:\n     *                                                             Possible values:\n     *                                                             - CarbonInterface::DIFF_ABSOLUTE          no modifiers\n     *                                                             - CarbonInterface::DIFF_RELATIVE_TO_NOW   add ago/from now modifier\n     *                                                             - CarbonInterface::DIFF_RELATIVE_TO_OTHER add before/after modifier\n     *                                                             Default value: CarbonInterface::DIFF_ABSOLUTE\n     * @param bool                                        $short   displays short format of time units\n     * @param int                                         $parts   maximum number of parts to display (default value: 1: single unit)\n     * @param int                                         $options human diff options\n     *\n     * @return string\n     */\n    public function diffForHumans($other = null, $syntax = null, $short = false, $parts = 1, $options = null)\n    {\n        /* @var CarbonInterface $this */\n        if (\\is_array($other)) {\n            $other['syntax'] = \\array_key_exists('syntax', $other) ? $other['syntax'] : $syntax;\n            $syntax = $other;\n            $other = $syntax['other'] ?? null;\n        }\n\n        $intSyntax = &$syntax;\n        if (\\is_array($syntax)) {\n            $syntax['syntax'] = $syntax['syntax'] ?? null;\n            $intSyntax = &$syntax['syntax'];\n        }\n        $intSyntax = (int) ($intSyntax ?? static::DIFF_RELATIVE_AUTO);\n        $intSyntax = $intSyntax === static::DIFF_RELATIVE_AUTO && $other === null ? static::DIFF_RELATIVE_TO_NOW : $intSyntax;\n\n        $parts = min(7, max(1, (int) $parts));\n        $skip = \\is_array($syntax) ? ($syntax['skip'] ?? []) : [];\n\n        return $this->diffAsCarbonInterval($other, false, (array) $skip)\n            ->setLocalTranslator($this->getLocalTranslator())\n            ->forHumans($syntax, (bool) $short, $parts, $options ?? $this->localHumanDiffOptions ?? static::getHumanDiffOptions());\n    }\n\n    /**\n     * @alias diffForHumans\n     *\n     * Get the difference in a human readable format in the current locale from current instance to an other\n     * instance given (or now if null given).\n     *\n     * @param Carbon|\\DateTimeInterface|string|array|null $other   if array passed, will be used as parameters array, see $syntax below;\n     *                                                             if null passed, now will be used as comparison reference;\n     *                                                             if any other type, it will be converted to date and used as reference.\n     * @param int|array                                   $syntax  if array passed, parameters will be extracted from it, the array may contains:\n     *                                                             - 'syntax' entry (see below)\n     *                                                             - 'short' entry (see below)\n     *                                                             - 'parts' entry (see below)\n     *                                                             - 'options' entry (see below)\n     *                                                             - 'join' entry determines how to join multiple parts of the string\n     *                                                             `  - if $join is a string, it's used as a joiner glue\n     *                                                             `  - if $join is a callable/closure, it get the list of string and should return a string\n     *                                                             `  - if $join is an array, the first item will be the default glue, and the second item\n     *                                                             `    will be used instead of the glue for the last item\n     *                                                             `  - if $join is true, it will be guessed from the locale ('list' translation file entry)\n     *                                                             `  - if $join is missing, a space will be used as glue\n     *                                                             - 'other' entry (see above)\n     *                                                             if int passed, it add modifiers:\n     *                                                             Possible values:\n     *                                                             - CarbonInterface::DIFF_ABSOLUTE          no modifiers\n     *                                                             - CarbonInterface::DIFF_RELATIVE_TO_NOW   add ago/from now modifier\n     *                                                             - CarbonInterface::DIFF_RELATIVE_TO_OTHER add before/after modifier\n     *                                                             Default value: CarbonInterface::DIFF_ABSOLUTE\n     * @param bool                                        $short   displays short format of time units\n     * @param int                                         $parts   maximum number of parts to display (default value: 1: single unit)\n     * @param int                                         $options human diff options\n     *\n     * @return string\n     */\n    public function from($other = null, $syntax = null, $short = false, $parts = 1, $options = null)\n    {\n        return $this->diffForHumans($other, $syntax, $short, $parts, $options);\n    }\n\n    /**\n     * @alias diffForHumans\n     *\n     * Get the difference in a human readable format in the current locale from current instance to an other\n     * instance given (or now if null given).\n     */\n    public function since($other = null, $syntax = null, $short = false, $parts = 1, $options = null)\n    {\n        return $this->diffForHumans($other, $syntax, $short, $parts, $options);\n    }\n\n    /**\n     * Get the difference in a human readable format in the current locale from an other\n     * instance given (or now if null given) to current instance.\n     *\n     * When comparing a value in the past to default now:\n     * 1 hour from now\n     * 5 months from now\n     *\n     * When comparing a value in the future to default now:\n     * 1 hour ago\n     * 5 months ago\n     *\n     * When comparing a value in the past to another value:\n     * 1 hour after\n     * 5 months after\n     *\n     * When comparing a value in the future to another value:\n     * 1 hour before\n     * 5 months before\n     *\n     * @param Carbon|\\DateTimeInterface|string|array|null $other   if array passed, will be used as parameters array, see $syntax below;\n     *                                                             if null passed, now will be used as comparison reference;\n     *                                                             if any other type, it will be converted to date and used as reference.\n     * @param int|array                                   $syntax  if array passed, parameters will be extracted from it, the array may contains:\n     *                                                             - 'syntax' entry (see below)\n     *                                                             - 'short' entry (see below)\n     *                                                             - 'parts' entry (see below)\n     *                                                             - 'options' entry (see below)\n     *                                                             - 'join' entry determines how to join multiple parts of the string\n     *                                                             `  - if $join is a string, it's used as a joiner glue\n     *                                                             `  - if $join is a callable/closure, it get the list of string and should return a string\n     *                                                             `  - if $join is an array, the first item will be the default glue, and the second item\n     *                                                             `    will be used instead of the glue for the last item\n     *                                                             `  - if $join is true, it will be guessed from the locale ('list' translation file entry)\n     *                                                             `  - if $join is missing, a space will be used as glue\n     *                                                             - 'other' entry (see above)\n     *                                                             if int passed, it add modifiers:\n     *                                                             Possible values:\n     *                                                             - CarbonInterface::DIFF_ABSOLUTE          no modifiers\n     *                                                             - CarbonInterface::DIFF_RELATIVE_TO_NOW   add ago/from now modifier\n     *                                                             - CarbonInterface::DIFF_RELATIVE_TO_OTHER add before/after modifier\n     *                                                             Default value: CarbonInterface::DIFF_ABSOLUTE\n     * @param bool                                        $short   displays short format of time units\n     * @param int                                         $parts   maximum number of parts to display (default value: 1: single unit)\n     * @param int                                         $options human diff options\n     *\n     * @return string\n     */\n    public function to($other = null, $syntax = null, $short = false, $parts = 1, $options = null)\n    {\n        if (!$syntax && !$other) {\n            $syntax = CarbonInterface::DIFF_RELATIVE_TO_NOW;\n        }\n\n        return $this->resolveCarbon($other)->diffForHumans($this, $syntax, $short, $parts, $options);\n    }\n\n    /**\n     * @alias to\n     *\n     * Get the difference in a human readable format in the current locale from an other\n     * instance given (or now if null given) to current instance.\n     *\n     * @param Carbon|\\DateTimeInterface|string|array|null $other   if array passed, will be used as parameters array, see $syntax below;\n     *                                                             if null passed, now will be used as comparison reference;\n     *                                                             if any other type, it will be converted to date and used as reference.\n     * @param int|array                                   $syntax  if array passed, parameters will be extracted from it, the array may contains:\n     *                                                             - 'syntax' entry (see below)\n     *                                                             - 'short' entry (see below)\n     *                                                             - 'parts' entry (see below)\n     *                                                             - 'options' entry (see below)\n     *                                                             - 'join' entry determines how to join multiple parts of the string\n     *                                                             `  - if $join is a string, it's used as a joiner glue\n     *                                                             `  - if $join is a callable/closure, it get the list of string and should return a string\n     *                                                             `  - if $join is an array, the first item will be the default glue, and the second item\n     *                                                             `    will be used instead of the glue for the last item\n     *                                                             `  - if $join is true, it will be guessed from the locale ('list' translation file entry)\n     *                                                             `  - if $join is missing, a space will be used as glue\n     *                                                             - 'other' entry (see above)\n     *                                                             if int passed, it add modifiers:\n     *                                                             Possible values:\n     *                                                             - CarbonInterface::DIFF_ABSOLUTE          no modifiers\n     *                                                             - CarbonInterface::DIFF_RELATIVE_TO_NOW   add ago/from now modifier\n     *                                                             - CarbonInterface::DIFF_RELATIVE_TO_OTHER add before/after modifier\n     *                                                             Default value: CarbonInterface::DIFF_ABSOLUTE\n     * @param bool                                        $short   displays short format of time units\n     * @param int                                         $parts   maximum number of parts to display (default value: 1: single unit)\n     * @param int                                         $options human diff options\n     *\n     * @return string\n     */\n    public function until($other = null, $syntax = null, $short = false, $parts = 1, $options = null)\n    {\n        return $this->to($other, $syntax, $short, $parts, $options);\n    }\n\n    /**\n     * Get the difference in a human readable format in the current locale from current\n     * instance to now.\n     *\n     * @param int|array $syntax  if array passed, parameters will be extracted from it, the array may contains:\n     *                           - 'syntax' entry (see below)\n     *                           - 'short' entry (see below)\n     *                           - 'parts' entry (see below)\n     *                           - 'options' entry (see below)\n     *                           - 'join' entry determines how to join multiple parts of the string\n     *                           `  - if $join is a string, it's used as a joiner glue\n     *                           `  - if $join is a callable/closure, it get the list of string and should return a string\n     *                           `  - if $join is an array, the first item will be the default glue, and the second item\n     *                           `    will be used instead of the glue for the last item\n     *                           `  - if $join is true, it will be guessed from the locale ('list' translation file entry)\n     *                           `  - if $join is missing, a space will be used as glue\n     *                           if int passed, it add modifiers:\n     *                           Possible values:\n     *                           - CarbonInterface::DIFF_ABSOLUTE          no modifiers\n     *                           - CarbonInterface::DIFF_RELATIVE_TO_NOW   add ago/from now modifier\n     *                           - CarbonInterface::DIFF_RELATIVE_TO_OTHER add before/after modifier\n     *                           Default value: CarbonInterface::DIFF_ABSOLUTE\n     * @param bool      $short   displays short format of time units\n     * @param int       $parts   maximum number of parts to display (default value: 1: single unit)\n     * @param int       $options human diff options\n     *\n     * @return string\n     */\n    public function fromNow($syntax = null, $short = false, $parts = 1, $options = null)\n    {\n        $other = null;\n\n        if ($syntax instanceof DateTimeInterface) {\n            [$other, $syntax, $short, $parts, $options] = array_pad(\\func_get_args(), 5, null);\n        }\n\n        return $this->from($other, $syntax, $short, $parts, $options);\n    }\n\n    /**\n     * Get the difference in a human readable format in the current locale from an other\n     * instance given to now\n     *\n     * @param int|array $syntax  if array passed, parameters will be extracted from it, the array may contains:\n     *                           - 'syntax' entry (see below)\n     *                           - 'short' entry (see below)\n     *                           - 'parts' entry (see below)\n     *                           - 'options' entry (see below)\n     *                           - 'join' entry determines how to join multiple parts of the string\n     *                           `  - if $join is a string, it's used as a joiner glue\n     *                           `  - if $join is a callable/closure, it get the list of string and should return a string\n     *                           `  - if $join is an array, the first item will be the default glue, and the second item\n     *                           `    will be used instead of the glue for the last item\n     *                           `  - if $join is true, it will be guessed from the locale ('list' translation file entry)\n     *                           `  - if $join is missing, a space will be used as glue\n     *                           if int passed, it add modifiers:\n     *                           Possible values:\n     *                           - CarbonInterface::DIFF_ABSOLUTE          no modifiers\n     *                           - CarbonInterface::DIFF_RELATIVE_TO_NOW   add ago/from now modifier\n     *                           - CarbonInterface::DIFF_RELATIVE_TO_OTHER add before/after modifier\n     *                           Default value: CarbonInterface::DIFF_ABSOLUTE\n     * @param bool      $short   displays short format of time units\n     * @param int       $parts   maximum number of parts to display (default value: 1: single part)\n     * @param int       $options human diff options\n     *\n     * @return string\n     */\n    public function toNow($syntax = null, $short = false, $parts = 1, $options = null)\n    {\n        return $this->to(null, $syntax, $short, $parts, $options);\n    }\n\n    /**\n     * Get the difference in a human readable format in the current locale from an other\n     * instance given to now\n     *\n     * @param int|array $syntax  if array passed, parameters will be extracted from it, the array may contains:\n     *                           - 'syntax' entry (see below)\n     *                           - 'short' entry (see below)\n     *                           - 'parts' entry (see below)\n     *                           - 'options' entry (see below)\n     *                           - 'join' entry determines how to join multiple parts of the string\n     *                           `  - if $join is a string, it's used as a joiner glue\n     *                           `  - if $join is a callable/closure, it get the list of string and should return a string\n     *                           `  - if $join is an array, the first item will be the default glue, and the second item\n     *                           `    will be used instead of the glue for the last item\n     *                           `  - if $join is true, it will be guessed from the locale ('list' translation file entry)\n     *                           `  - if $join is missing, a space will be used as glue\n     *                           if int passed, it add modifiers:\n     *                           Possible values:\n     *                           - CarbonInterface::DIFF_ABSOLUTE          no modifiers\n     *                           - CarbonInterface::DIFF_RELATIVE_TO_NOW   add ago/from now modifier\n     *                           - CarbonInterface::DIFF_RELATIVE_TO_OTHER add before/after modifier\n     *                           Default value: CarbonInterface::DIFF_ABSOLUTE\n     * @param bool      $short   displays short format of time units\n     * @param int       $parts   maximum number of parts to display (default value: 1: single part)\n     * @param int       $options human diff options\n     *\n     * @return string\n     */\n    public function ago($syntax = null, $short = false, $parts = 1, $options = null)\n    {\n        $other = null;\n\n        if ($syntax instanceof DateTimeInterface) {\n            [$other, $syntax, $short, $parts, $options] = array_pad(\\func_get_args(), 5, null);\n        }\n\n        return $this->from($other, $syntax, $short, $parts, $options);\n    }\n\n    /**\n     * Get the difference in a human readable format in the current locale from current instance to an other\n     * instance given (or now if null given).\n     *\n     * @return string\n     */\n    public function timespan($other = null, $timezone = null)\n    {\n        if (!$other instanceof DateTimeInterface) {\n            $other = static::parse($other, $timezone);\n        }\n\n        return $this->diffForHumans($other, [\n            'join' => ', ',\n            'syntax' => CarbonInterface::DIFF_ABSOLUTE,\n            'options' => CarbonInterface::NO_ZERO_DIFF,\n            'parts' => -1,\n        ]);\n    }\n\n    /**\n     * Returns either day of week + time (e.g. \"Last Friday at 3:30 PM\") if reference time is within 7 days,\n     * or a calendar date (e.g. \"10/29/2017\") otherwise.\n     *\n     * Language, date and time formats will change according to the current locale.\n     *\n     * @param Carbon|\\DateTimeInterface|string|null $referenceTime\n     * @param array                                 $formats\n     *\n     * @return string\n     */\n    public function calendar($referenceTime = null, array $formats = [])\n    {\n        /** @var CarbonInterface $current */\n        $current = $this->avoidMutation()->startOfDay();\n        /** @var CarbonInterface $other */\n        $other = $this->resolveCarbon($referenceTime)->avoidMutation()->setTimezone($this->getTimezone())->startOfDay();\n        $diff = $other->diffInDays($current, false);\n        $format = $diff < -6 ? 'sameElse' : (\n            $diff < -1 ? 'lastWeek' : (\n                $diff < 0 ? 'lastDay' : (\n                    $diff < 1 ? 'sameDay' : (\n                        $diff < 2 ? 'nextDay' : (\n                            $diff < 7 ? 'nextWeek' : 'sameElse'\n                        )\n                    )\n                )\n            )\n        );\n        $format = array_merge($this->getCalendarFormats(), $formats)[$format];\n        if ($format instanceof Closure) {\n            $format = $format($current, $other) ?? '';\n        }\n\n        return $this->isoFormat((string) $format);\n    }\n\n    private function getIntervalDayDiff(DateInterval $interval): int\n    {\n        $daysDiff = (int) $interval->format('%a');\n        $sign = $interval->format('%r') === '-' ? -1 : 1;\n\n        if (\\is_int($interval->days) &&\n            $interval->y === 0 &&\n            $interval->m === 0 &&\n            version_compare(PHP_VERSION, '8.1.0-dev', '<') &&\n            abs($interval->d - $daysDiff) === 1\n        ) {\n            $daysDiff = abs($interval->d); // @codeCoverageIgnore\n        }\n\n        return $daysDiff * $sign;\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Traits/IntervalRounding.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Traits;\n\nuse Carbon\\CarbonInterval;\nuse Carbon\\Exceptions\\InvalidIntervalException;\nuse DateInterval;\n\n/**\n * Trait to call rounding methods to interval or the interval of a period.\n */\ntrait IntervalRounding\n{\n    protected function callRoundMethod(string $method, array $parameters)\n    {\n        $action = substr($method, 0, 4);\n\n        if ($action !== 'ceil') {\n            $action = substr($method, 0, 5);\n        }\n\n        if (\\in_array($action, ['round', 'floor', 'ceil'])) {\n            return $this->{$action.'Unit'}(substr($method, \\strlen($action)), ...$parameters);\n        }\n\n        return null;\n    }\n\n    protected function roundWith($precision, $function)\n    {\n        $unit = 'second';\n\n        if ($precision instanceof DateInterval) {\n            $precision = (string) CarbonInterval::instance($precision, [], true);\n        }\n\n        if (\\is_string($precision) && preg_match('/^\\s*(?<precision>\\d+)?\\s*(?<unit>\\w+)(?<other>\\W.*)?$/', $precision, $match)) {\n            if (trim($match['other'] ?? '') !== '') {\n                throw new InvalidIntervalException('Rounding is only possible with single unit intervals.');\n            }\n\n            $precision = (int) ($match['precision'] ?: 1);\n            $unit = $match['unit'];\n        }\n\n        return $this->roundUnit($unit, $precision, $function);\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Traits/IntervalStep.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Traits;\n\nuse Carbon\\Carbon;\nuse Carbon\\CarbonImmutable;\nuse Carbon\\CarbonInterface;\nuse Closure;\nuse DateTimeImmutable;\nuse DateTimeInterface;\n\ntrait IntervalStep\n{\n    /**\n     * Step to apply instead of a fixed interval to get the new date.\n     *\n     * @var Closure|null\n     */\n    protected $step;\n\n    /**\n     * Get the dynamic step in use.\n     *\n     * @return Closure\n     */\n    public function getStep(): ?Closure\n    {\n        return $this->step;\n    }\n\n    /**\n     * Set a step to apply instead of a fixed interval to get the new date.\n     *\n     * Or pass null to switch to fixed interval.\n     *\n     * @param Closure|null $step\n     */\n    public function setStep(?Closure $step): void\n    {\n        $this->step = $step;\n    }\n\n    /**\n     * Take a date and apply either the step if set, or the current interval else.\n     *\n     * The interval/step is applied negatively (typically subtraction instead of addition) if $negated is true.\n     *\n     * @param DateTimeInterface $dateTime\n     * @param bool              $negated\n     *\n     * @return CarbonInterface\n     */\n    public function convertDate(DateTimeInterface $dateTime, bool $negated = false): CarbonInterface\n    {\n        /** @var CarbonInterface $carbonDate */\n        $carbonDate = $dateTime instanceof CarbonInterface ? $dateTime : $this->resolveCarbon($dateTime);\n\n        if ($this->step) {\n            return $carbonDate->setDateTimeFrom(($this->step)($carbonDate->avoidMutation(), $negated));\n        }\n\n        if ($negated) {\n            return $carbonDate->rawSub($this);\n        }\n\n        return $carbonDate->rawAdd($this);\n    }\n\n    /**\n     * Convert DateTimeImmutable instance to CarbonImmutable instance and DateTime instance to Carbon instance.\n     *\n     * @param DateTimeInterface $dateTime\n     *\n     * @return Carbon|CarbonImmutable\n     */\n    private function resolveCarbon(DateTimeInterface $dateTime)\n    {\n        if ($dateTime instanceof DateTimeImmutable) {\n            return CarbonImmutable::instance($dateTime);\n        }\n\n        return Carbon::instance($dateTime);\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Traits/Localization.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Traits;\n\nuse Carbon\\CarbonInterface;\nuse Carbon\\Exceptions\\InvalidTypeException;\nuse Carbon\\Exceptions\\NotLocaleAwareException;\nuse Carbon\\Language;\nuse Carbon\\Translator;\nuse Carbon\\TranslatorStrongTypeInterface;\nuse Closure;\nuse Symfony\\Component\\Translation\\TranslatorBagInterface;\nuse Symfony\\Component\\Translation\\TranslatorInterface;\nuse Symfony\\Contracts\\Translation\\LocaleAwareInterface;\nuse Symfony\\Contracts\\Translation\\TranslatorInterface as ContractsTranslatorInterface;\n\n// @codeCoverageIgnoreStart\nif (interface_exists('Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface') &&\n    !interface_exists('Symfony\\\\Component\\\\Translation\\\\TranslatorInterface')\n) {\n    class_alias(\n        'Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface',\n        'Symfony\\\\Component\\\\Translation\\\\TranslatorInterface'\n    );\n}\n// @codeCoverageIgnoreEnd\n\n/**\n * Trait Localization.\n *\n * Embed default and locale translators and translation base methods.\n */\ntrait Localization\n{\n    /**\n     * Default translator.\n     *\n     * @var \\Symfony\\Component\\Translation\\TranslatorInterface\n     */\n    protected static $translator;\n\n    /**\n     * Specific translator of the current instance.\n     *\n     * @var \\Symfony\\Component\\Translation\\TranslatorInterface\n     */\n    protected $localTranslator;\n\n    /**\n     * Options for diffForHumans().\n     *\n     * @var int\n     */\n    protected static $humanDiffOptions = CarbonInterface::NO_ZERO_DIFF;\n\n    /**\n     * @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n     *             You should rather use the ->settings() method.\n     * @see settings\n     *\n     * @param int $humanDiffOptions\n     */\n    public static function setHumanDiffOptions($humanDiffOptions)\n    {\n        static::$humanDiffOptions = $humanDiffOptions;\n    }\n\n    /**\n     * @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n     *             You should rather use the ->settings() method.\n     * @see settings\n     *\n     * @param int $humanDiffOption\n     */\n    public static function enableHumanDiffOption($humanDiffOption)\n    {\n        static::$humanDiffOptions = static::getHumanDiffOptions() | $humanDiffOption;\n    }\n\n    /**\n     * @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n     *             You should rather use the ->settings() method.\n     * @see settings\n     *\n     * @param int $humanDiffOption\n     */\n    public static function disableHumanDiffOption($humanDiffOption)\n    {\n        static::$humanDiffOptions = static::getHumanDiffOptions() & ~$humanDiffOption;\n    }\n\n    /**\n     * Return default humanDiff() options (merged flags as integer).\n     *\n     * @return int\n     */\n    public static function getHumanDiffOptions()\n    {\n        return static::$humanDiffOptions;\n    }\n\n    /**\n     * Get the default translator instance in use.\n     *\n     * @return \\Symfony\\Component\\Translation\\TranslatorInterface\n     */\n    public static function getTranslator()\n    {\n        return static::translator();\n    }\n\n    /**\n     * Set the default translator instance to use.\n     *\n     * @param \\Symfony\\Component\\Translation\\TranslatorInterface $translator\n     *\n     * @return void\n     */\n    public static function setTranslator(TranslatorInterface $translator)\n    {\n        static::$translator = $translator;\n    }\n\n    /**\n     * Return true if the current instance has its own translator.\n     *\n     * @return bool\n     */\n    public function hasLocalTranslator()\n    {\n        return isset($this->localTranslator);\n    }\n\n    /**\n     * Get the translator of the current instance or the default if none set.\n     *\n     * @return \\Symfony\\Component\\Translation\\TranslatorInterface\n     */\n    public function getLocalTranslator()\n    {\n        return $this->localTranslator ?: static::translator();\n    }\n\n    /**\n     * Set the translator for the current instance.\n     *\n     * @param \\Symfony\\Component\\Translation\\TranslatorInterface $translator\n     *\n     * @return $this\n     */\n    public function setLocalTranslator(TranslatorInterface $translator)\n    {\n        $this->localTranslator = $translator;\n\n        return $this;\n    }\n\n    /**\n     * Returns raw translation message for a given key.\n     *\n     * @param \\Symfony\\Component\\Translation\\TranslatorInterface $translator the translator to use\n     * @param string                                             $key        key to find\n     * @param string|null                                        $locale     current locale used if null\n     * @param string|null                                        $default    default value if translation returns the key\n     *\n     * @return string\n     */\n    public static function getTranslationMessageWith($translator, string $key, ?string $locale = null, ?string $default = null)\n    {\n        if (!($translator instanceof TranslatorBagInterface && $translator instanceof TranslatorInterface)) {\n            throw new InvalidTypeException(\n                'Translator does not implement '.TranslatorInterface::class.' and '.TranslatorBagInterface::class.'. '.\n                (\\is_object($translator) ? \\get_class($translator) : \\gettype($translator)).' has been given.'\n            );\n        }\n\n        if (!$locale && $translator instanceof LocaleAwareInterface) {\n            $locale = $translator->getLocale();\n        }\n\n        $result = self::getFromCatalogue($translator, $translator->getCatalogue($locale), $key);\n\n        return $result === $key ? $default : $result;\n    }\n\n    /**\n     * Returns raw translation message for a given key.\n     *\n     * @param string                                             $key        key to find\n     * @param string|null                                        $locale     current locale used if null\n     * @param string|null                                        $default    default value if translation returns the key\n     * @param \\Symfony\\Component\\Translation\\TranslatorInterface $translator an optional translator to use\n     *\n     * @return string\n     */\n    public function getTranslationMessage(string $key, ?string $locale = null, ?string $default = null, $translator = null)\n    {\n        return static::getTranslationMessageWith($translator ?: $this->getLocalTranslator(), $key, $locale, $default);\n    }\n\n    /**\n     * Translate using translation string or callback available.\n     *\n     * @param \\Symfony\\Component\\Translation\\TranslatorInterface $translator\n     * @param string                                             $key\n     * @param array                                              $parameters\n     * @param null                                               $number\n     *\n     * @return string\n     */\n    public static function translateWith(TranslatorInterface $translator, string $key, array $parameters = [], $number = null): string\n    {\n        $message = static::getTranslationMessageWith($translator, $key, null, $key);\n        if ($message instanceof Closure) {\n            return (string) $message(...array_values($parameters));\n        }\n\n        if ($number !== null) {\n            $parameters['%count%'] = $number;\n        }\n        if (isset($parameters['%count%'])) {\n            $parameters[':count'] = $parameters['%count%'];\n        }\n\n        // @codeCoverageIgnoreStart\n        $choice = $translator instanceof ContractsTranslatorInterface\n            ? $translator->trans($key, $parameters)\n            : $translator->transChoice($key, $number, $parameters);\n        // @codeCoverageIgnoreEnd\n\n        return (string) $choice;\n    }\n\n    /**\n     * Translate using translation string or callback available.\n     *\n     * @param string                                                  $key\n     * @param array                                                   $parameters\n     * @param string|int|float|null                                   $number\n     * @param \\Symfony\\Component\\Translation\\TranslatorInterface|null $translator\n     * @param bool                                                    $altNumbers\n     *\n     * @return string\n     */\n    public function translate(string $key, array $parameters = [], $number = null, ?TranslatorInterface $translator = null, bool $altNumbers = false): string\n    {\n        $translation = static::translateWith($translator ?: $this->getLocalTranslator(), $key, $parameters, $number);\n\n        if ($number !== null && $altNumbers) {\n            return str_replace($number, $this->translateNumber($number), $translation);\n        }\n\n        return $translation;\n    }\n\n    /**\n     * Returns the alternative number for a given integer if available in the current locale.\n     *\n     * @param int $number\n     *\n     * @return string\n     */\n    public function translateNumber(int $number): string\n    {\n        $translateKey = \"alt_numbers.$number\";\n        $symbol = $this->translate($translateKey);\n\n        if ($symbol !== $translateKey) {\n            return $symbol;\n        }\n\n        if ($number > 99 && $this->translate('alt_numbers.99') !== 'alt_numbers.99') {\n            $start = '';\n            foreach ([10000, 1000, 100] as $exp) {\n                $key = \"alt_numbers_pow.$exp\";\n                if ($number >= $exp && $number < $exp * 10 && ($pow = $this->translate($key)) !== $key) {\n                    $unit = floor($number / $exp);\n                    $number -= $unit * $exp;\n                    $start .= ($unit > 1 ? $this->translate(\"alt_numbers.$unit\") : '').$pow;\n                }\n            }\n            $result = '';\n            while ($number) {\n                $chunk = $number % 100;\n                $result = $this->translate(\"alt_numbers.$chunk\").$result;\n                $number = floor($number / 100);\n            }\n\n            return \"$start$result\";\n        }\n\n        if ($number > 9 && $this->translate('alt_numbers.9') !== 'alt_numbers.9') {\n            $result = '';\n            while ($number) {\n                $chunk = $number % 10;\n                $result = $this->translate(\"alt_numbers.$chunk\").$result;\n                $number = floor($number / 10);\n            }\n\n            return $result;\n        }\n\n        return (string) $number;\n    }\n\n    /**\n     * Translate a time string from a locale to an other.\n     *\n     * @param string      $timeString date/time/duration string to translate (may also contain English)\n     * @param string|null $from       input locale of the $timeString parameter (`Carbon::getLocale()` by default)\n     * @param string|null $to         output locale of the result returned (`\"en\"` by default)\n     * @param int         $mode       specify what to translate with options:\n     *                                - CarbonInterface::TRANSLATE_ALL (default)\n     *                                - CarbonInterface::TRANSLATE_MONTHS\n     *                                - CarbonInterface::TRANSLATE_DAYS\n     *                                - CarbonInterface::TRANSLATE_UNITS\n     *                                - CarbonInterface::TRANSLATE_MERIDIEM\n     *                                You can use pipe to group: CarbonInterface::TRANSLATE_MONTHS | CarbonInterface::TRANSLATE_DAYS\n     *\n     * @return string\n     */\n    public static function translateTimeString($timeString, $from = null, $to = null, $mode = CarbonInterface::TRANSLATE_ALL)\n    {\n        // Fallback source and destination locales\n        $from = $from ?: static::getLocale();\n        $to = $to ?: 'en';\n\n        if ($from === $to) {\n            return $timeString;\n        }\n\n        // Standardize apostrophe\n        $timeString = strtr($timeString, ['’' => \"'\"]);\n\n        $fromTranslations = [];\n        $toTranslations = [];\n\n        foreach (['from', 'to'] as $key) {\n            $language = $$key;\n            $translator = Translator::get($language);\n            $translations = $translator->getMessages();\n\n            if (!isset($translations[$language])) {\n                return $timeString;\n            }\n\n            $translationKey = $key.'Translations';\n            $messages = $translations[$language];\n            $months = $messages['months'] ?? [];\n            $weekdays = $messages['weekdays'] ?? [];\n            $meridiem = $messages['meridiem'] ?? ['AM', 'PM'];\n\n            if (isset($messages['ordinal_words'])) {\n                $timeString = self::replaceOrdinalWords(\n                    $timeString,\n                    $key === 'from' ? array_flip($messages['ordinal_words']) : $messages['ordinal_words']\n                );\n            }\n\n            if ($key === 'from') {\n                foreach (['months', 'weekdays'] as $variable) {\n                    $list = $messages[$variable.'_standalone'] ?? null;\n\n                    if ($list) {\n                        foreach ($$variable as $index => &$name) {\n                            $name .= '|'.$messages[$variable.'_standalone'][$index];\n                        }\n                    }\n                }\n            }\n\n            $$translationKey = array_merge(\n                $mode & CarbonInterface::TRANSLATE_MONTHS ? static::getTranslationArray($months, 12, $timeString) : [],\n                $mode & CarbonInterface::TRANSLATE_MONTHS ? static::getTranslationArray($messages['months_short'] ?? [], 12, $timeString) : [],\n                $mode & CarbonInterface::TRANSLATE_DAYS ? static::getTranslationArray($weekdays, 7, $timeString) : [],\n                $mode & CarbonInterface::TRANSLATE_DAYS ? static::getTranslationArray($messages['weekdays_short'] ?? [], 7, $timeString) : [],\n                $mode & CarbonInterface::TRANSLATE_DIFF ? static::translateWordsByKeys([\n                    'diff_now',\n                    'diff_today',\n                    'diff_yesterday',\n                    'diff_tomorrow',\n                    'diff_before_yesterday',\n                    'diff_after_tomorrow',\n                ], $messages, $key) : [],\n                $mode & CarbonInterface::TRANSLATE_UNITS ? static::translateWordsByKeys([\n                    'year',\n                    'month',\n                    'week',\n                    'day',\n                    'hour',\n                    'minute',\n                    'second',\n                ], $messages, $key) : [],\n                $mode & CarbonInterface::TRANSLATE_MERIDIEM ? array_map(function ($hour) use ($meridiem) {\n                    if (\\is_array($meridiem)) {\n                        return $meridiem[$hour < 12 ? 0 : 1];\n                    }\n\n                    return $meridiem($hour, 0, false);\n                }, range(0, 23)) : []\n            );\n        }\n\n        return substr(preg_replace_callback('/(?<=[\\d\\s+.\\/,_-])('.implode('|', $fromTranslations).')(?=[\\d\\s+.\\/,_-])/iu', function ($match) use ($fromTranslations, $toTranslations) {\n            [$chunk] = $match;\n\n            foreach ($fromTranslations as $index => $word) {\n                if (preg_match(\"/^$word\\$/iu\", $chunk)) {\n                    return $toTranslations[$index] ?? '';\n                }\n            }\n\n            return $chunk; // @codeCoverageIgnore\n        }, \" $timeString \"), 1, -1);\n    }\n\n    /**\n     * Translate a time string from the current locale (`$date->locale()`) to an other.\n     *\n     * @param string      $timeString time string to translate\n     * @param string|null $to         output locale of the result returned (\"en\" by default)\n     *\n     * @return string\n     */\n    public function translateTimeStringTo($timeString, $to = null)\n    {\n        return static::translateTimeString($timeString, $this->getTranslatorLocale(), $to);\n    }\n\n    /**\n     * Get/set the locale for the current instance.\n     *\n     * @param string|null $locale\n     * @param string      ...$fallbackLocales\n     *\n     * @return $this|string\n     */\n    public function locale(?string $locale = null, ...$fallbackLocales)\n    {\n        if ($locale === null) {\n            return $this->getTranslatorLocale();\n        }\n\n        if (!$this->localTranslator || $this->getTranslatorLocale($this->localTranslator) !== $locale) {\n            $translator = Translator::get($locale);\n\n            if (!empty($fallbackLocales)) {\n                $translator->setFallbackLocales($fallbackLocales);\n\n                foreach ($fallbackLocales as $fallbackLocale) {\n                    $messages = Translator::get($fallbackLocale)->getMessages();\n\n                    if (isset($messages[$fallbackLocale])) {\n                        $translator->setMessages($fallbackLocale, $messages[$fallbackLocale]);\n                    }\n                }\n            }\n\n            $this->localTranslator = $translator;\n        }\n\n        return $this;\n    }\n\n    /**\n     * Get the current translator locale.\n     *\n     * @return string\n     */\n    public static function getLocale()\n    {\n        return static::getLocaleAwareTranslator()->getLocale();\n    }\n\n    /**\n     * Set the current translator locale and indicate if the source locale file exists.\n     * Pass 'auto' as locale to use closest language from the current LC_TIME locale.\n     *\n     * @param string $locale locale ex. en\n     *\n     * @return bool\n     */\n    public static function setLocale($locale)\n    {\n        return static::getLocaleAwareTranslator()->setLocale($locale) !== false;\n    }\n\n    /**\n     * Set the fallback locale.\n     *\n     * @see https://symfony.com/doc/current/components/translation.html#fallback-locales\n     *\n     * @param string $locale\n     */\n    public static function setFallbackLocale($locale)\n    {\n        $translator = static::getTranslator();\n\n        if (method_exists($translator, 'setFallbackLocales')) {\n            $translator->setFallbackLocales([$locale]);\n\n            if ($translator instanceof Translator) {\n                $preferredLocale = $translator->getLocale();\n                $translator->setMessages($preferredLocale, array_replace_recursive(\n                    $translator->getMessages()[$locale] ?? [],\n                    Translator::get($locale)->getMessages()[$locale] ?? [],\n                    $translator->getMessages($preferredLocale)\n                ));\n            }\n        }\n    }\n\n    /**\n     * Get the fallback locale.\n     *\n     * @see https://symfony.com/doc/current/components/translation.html#fallback-locales\n     *\n     * @return string|null\n     */\n    public static function getFallbackLocale()\n    {\n        $translator = static::getTranslator();\n\n        if (method_exists($translator, 'getFallbackLocales')) {\n            return $translator->getFallbackLocales()[0] ?? null;\n        }\n\n        return null;\n    }\n\n    /**\n     * Set the current locale to the given, execute the passed function, reset the locale to previous one,\n     * then return the result of the closure (or null if the closure was void).\n     *\n     * @param string   $locale locale ex. en\n     * @param callable $func\n     *\n     * @return mixed\n     */\n    public static function executeWithLocale($locale, $func)\n    {\n        $currentLocale = static::getLocale();\n        $result = $func(static::setLocale($locale) ? static::getLocale() : false, static::translator());\n        static::setLocale($currentLocale);\n\n        return $result;\n    }\n\n    /**\n     * Returns true if the given locale is internally supported and has short-units support.\n     * Support is considered enabled if either year, day or hour has a short variant translated.\n     *\n     * @param string $locale locale ex. en\n     *\n     * @return bool\n     */\n    public static function localeHasShortUnits($locale)\n    {\n        return static::executeWithLocale($locale, function ($newLocale, TranslatorInterface $translator) {\n            return ($newLocale && (($y = static::translateWith($translator, 'y')) !== 'y' && $y !== static::translateWith($translator, 'year'))) || (\n                ($y = static::translateWith($translator, 'd')) !== 'd' &&\n                    $y !== static::translateWith($translator, 'day')\n            ) || (\n                ($y = static::translateWith($translator, 'h')) !== 'h' &&\n                    $y !== static::translateWith($translator, 'hour')\n            );\n        });\n    }\n\n    /**\n     * Returns true if the given locale is internally supported and has diff syntax support (ago, from now, before, after).\n     * Support is considered enabled if the 4 sentences are translated in the given locale.\n     *\n     * @param string $locale locale ex. en\n     *\n     * @return bool\n     */\n    public static function localeHasDiffSyntax($locale)\n    {\n        return static::executeWithLocale($locale, function ($newLocale, TranslatorInterface $translator) {\n            if (!$newLocale) {\n                return false;\n            }\n\n            foreach (['ago', 'from_now', 'before', 'after'] as $key) {\n                if ($translator instanceof TranslatorBagInterface &&\n                    self::getFromCatalogue($translator, $translator->getCatalogue($newLocale), $key) instanceof Closure\n                ) {\n                    continue;\n                }\n\n                if ($translator->trans($key) === $key) {\n                    return false;\n                }\n            }\n\n            return true;\n        });\n    }\n\n    /**\n     * Returns true if the given locale is internally supported and has words for 1-day diff (just now, yesterday, tomorrow).\n     * Support is considered enabled if the 3 words are translated in the given locale.\n     *\n     * @param string $locale locale ex. en\n     *\n     * @return bool\n     */\n    public static function localeHasDiffOneDayWords($locale)\n    {\n        return static::executeWithLocale($locale, function ($newLocale, TranslatorInterface $translator) {\n            return $newLocale &&\n                $translator->trans('diff_now') !== 'diff_now' &&\n                $translator->trans('diff_yesterday') !== 'diff_yesterday' &&\n                $translator->trans('diff_tomorrow') !== 'diff_tomorrow';\n        });\n    }\n\n    /**\n     * Returns true if the given locale is internally supported and has words for 2-days diff (before yesterday, after tomorrow).\n     * Support is considered enabled if the 2 words are translated in the given locale.\n     *\n     * @param string $locale locale ex. en\n     *\n     * @return bool\n     */\n    public static function localeHasDiffTwoDayWords($locale)\n    {\n        return static::executeWithLocale($locale, function ($newLocale, TranslatorInterface $translator) {\n            return $newLocale &&\n                $translator->trans('diff_before_yesterday') !== 'diff_before_yesterday' &&\n                $translator->trans('diff_after_tomorrow') !== 'diff_after_tomorrow';\n        });\n    }\n\n    /**\n     * Returns true if the given locale is internally supported and has period syntax support (X times, every X, from X, to X).\n     * Support is considered enabled if the 4 sentences are translated in the given locale.\n     *\n     * @param string $locale locale ex. en\n     *\n     * @return bool\n     */\n    public static function localeHasPeriodSyntax($locale)\n    {\n        return static::executeWithLocale($locale, function ($newLocale, TranslatorInterface $translator) {\n            return $newLocale &&\n                $translator->trans('period_recurrences') !== 'period_recurrences' &&\n                $translator->trans('period_interval') !== 'period_interval' &&\n                $translator->trans('period_start_date') !== 'period_start_date' &&\n                $translator->trans('period_end_date') !== 'period_end_date';\n        });\n    }\n\n    /**\n     * Returns the list of internally available locales and already loaded custom locales.\n     * (It will ignore custom translator dynamic loading.)\n     *\n     * @return array\n     */\n    public static function getAvailableLocales()\n    {\n        $translator = static::getLocaleAwareTranslator();\n\n        return $translator instanceof Translator\n            ? $translator->getAvailableLocales()\n            : [$translator->getLocale()];\n    }\n\n    /**\n     * Returns list of Language object for each available locale. This object allow you to get the ISO name, native\n     * name, region and variant of the locale.\n     *\n     * @return Language[]\n     */\n    public static function getAvailableLocalesInfo()\n    {\n        $languages = [];\n        foreach (static::getAvailableLocales() as $id) {\n            $languages[$id] = new Language($id);\n        }\n\n        return $languages;\n    }\n\n    /**\n     * Initialize the default translator instance if necessary.\n     *\n     * @return \\Symfony\\Component\\Translation\\TranslatorInterface\n     */\n    protected static function translator()\n    {\n        if (static::$translator === null) {\n            static::$translator = Translator::get();\n        }\n\n        return static::$translator;\n    }\n\n    /**\n     * Get the locale of a given translator.\n     *\n     * If null or omitted, current local translator is used.\n     * If no local translator is in use, current global translator is used.\n     *\n     * @param null $translator\n     *\n     * @return string|null\n     */\n    protected function getTranslatorLocale($translator = null): ?string\n    {\n        if (\\func_num_args() === 0) {\n            $translator = $this->getLocalTranslator();\n        }\n\n        $translator = static::getLocaleAwareTranslator($translator);\n\n        return $translator ? $translator->getLocale() : null;\n    }\n\n    /**\n     * Throw an error if passed object is not LocaleAwareInterface.\n     *\n     * @param LocaleAwareInterface|null $translator\n     *\n     * @return LocaleAwareInterface|null\n     */\n    protected static function getLocaleAwareTranslator($translator = null)\n    {\n        if (\\func_num_args() === 0) {\n            $translator = static::translator();\n        }\n\n        if ($translator && !($translator instanceof LocaleAwareInterface || method_exists($translator, 'getLocale'))) {\n            throw new NotLocaleAwareException($translator); // @codeCoverageIgnore\n        }\n\n        return $translator;\n    }\n\n    /**\n     * @param mixed                                                    $translator\n     * @param \\Symfony\\Component\\Translation\\MessageCatalogueInterface $catalogue\n     *\n     * @return mixed\n     */\n    private static function getFromCatalogue($translator, $catalogue, string $id, string $domain = 'messages')\n    {\n        return $translator instanceof TranslatorStrongTypeInterface\n            ? $translator->getFromCatalogue($catalogue, $id, $domain) // @codeCoverageIgnore\n            : $catalogue->get($id, $domain);\n    }\n\n    /**\n     * Return the word cleaned from its translation codes.\n     *\n     * @param string $word\n     *\n     * @return string\n     */\n    private static function cleanWordFromTranslationString($word)\n    {\n        $word = str_replace([':count', '%count', ':time'], '', $word);\n        $word = strtr($word, ['’' => \"'\"]);\n        $word = preg_replace('/({\\d+(,(\\d+|Inf))?}|[\\[\\]]\\d+(,(\\d+|Inf))?[\\[\\]])/', '', $word);\n\n        return trim($word);\n    }\n\n    /**\n     * Translate a list of words.\n     *\n     * @param string[] $keys     keys to translate.\n     * @param string[] $messages messages bag handling translations.\n     * @param string   $key      'to' (to get the translation) or 'from' (to get the detection RegExp pattern).\n     *\n     * @return string[]\n     */\n    private static function translateWordsByKeys($keys, $messages, $key): array\n    {\n        return array_map(function ($wordKey) use ($messages, $key) {\n            $message = $key === 'from' && isset($messages[$wordKey.'_regexp'])\n                ? $messages[$wordKey.'_regexp']\n                : ($messages[$wordKey] ?? null);\n\n            if (!$message) {\n                return '>>DO NOT REPLACE<<';\n            }\n\n            $parts = explode('|', $message);\n\n            return $key === 'to'\n                ? self::cleanWordFromTranslationString(end($parts))\n                : '(?:'.implode('|', array_map([static::class, 'cleanWordFromTranslationString'], $parts)).')';\n        }, $keys);\n    }\n\n    /**\n     * Get an array of translations based on the current date.\n     *\n     * @param callable $translation\n     * @param int      $length\n     * @param string   $timeString\n     *\n     * @return string[]\n     */\n    private static function getTranslationArray($translation, $length, $timeString): array\n    {\n        $filler = '>>DO NOT REPLACE<<';\n\n        if (\\is_array($translation)) {\n            return array_pad($translation, $length, $filler);\n        }\n\n        $list = [];\n        $date = static::now();\n\n        for ($i = 0; $i < $length; $i++) {\n            $list[] = $translation($date, $timeString, $i) ?? $filler;\n        }\n\n        return $list;\n    }\n\n    private static function replaceOrdinalWords(string $timeString, array $ordinalWords): string\n    {\n        return preg_replace_callback('/(?<![a-z])[a-z]+(?![a-z])/i', function (array $match) use ($ordinalWords) {\n            return $ordinalWords[mb_strtolower($match[0])] ?? $match[0];\n        }, $timeString);\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Traits/Macro.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Traits;\n\n/**\n * Trait Macros.\n *\n * Allows users to register macros within the Carbon class.\n */\ntrait Macro\n{\n    use Mixin;\n\n    /**\n     * The registered macros.\n     *\n     * @var array\n     */\n    protected static $globalMacros = [];\n\n    /**\n     * The registered generic macros.\n     *\n     * @var array\n     */\n    protected static $globalGenericMacros = [];\n\n    /**\n     * Register a custom macro.\n     *\n     * @example\n     * ```\n     * $userSettings = [\n     *   'locale' => 'pt',\n     *   'timezone' => 'America/Sao_Paulo',\n     * ];\n     * Carbon::macro('userFormat', function () use ($userSettings) {\n     *   return $this->copy()->locale($userSettings['locale'])->tz($userSettings['timezone'])->calendar();\n     * });\n     * echo Carbon::yesterday()->hours(11)->userFormat();\n     * ```\n     *\n     * @param string          $name\n     * @param object|callable $macro\n     *\n     * @return void\n     */\n    public static function macro($name, $macro)\n    {\n        static::$globalMacros[$name] = $macro;\n    }\n\n    /**\n     * Remove all macros and generic macros.\n     */\n    public static function resetMacros()\n    {\n        static::$globalMacros = [];\n        static::$globalGenericMacros = [];\n    }\n\n    /**\n     * Register a custom macro.\n     *\n     * @param object|callable $macro\n     * @param int             $priority marco with higher priority is tried first\n     *\n     * @return void\n     */\n    public static function genericMacro($macro, $priority = 0)\n    {\n        if (!isset(static::$globalGenericMacros[$priority])) {\n            static::$globalGenericMacros[$priority] = [];\n            krsort(static::$globalGenericMacros, SORT_NUMERIC);\n        }\n\n        static::$globalGenericMacros[$priority][] = $macro;\n    }\n\n    /**\n     * Checks if macro is registered globally.\n     *\n     * @param string $name\n     *\n     * @return bool\n     */\n    public static function hasMacro($name)\n    {\n        return isset(static::$globalMacros[$name]);\n    }\n\n    /**\n     * Get the raw callable macro registered globally for a given name.\n     *\n     * @param string $name\n     *\n     * @return callable|null\n     */\n    public static function getMacro($name)\n    {\n        return static::$globalMacros[$name] ?? null;\n    }\n\n    /**\n     * Checks if macro is registered globally or locally.\n     *\n     * @param string $name\n     *\n     * @return bool\n     */\n    public function hasLocalMacro($name)\n    {\n        return ($this->localMacros && isset($this->localMacros[$name])) || static::hasMacro($name);\n    }\n\n    /**\n     * Get the raw callable macro registered globally or locally for a given name.\n     *\n     * @param string $name\n     *\n     * @return callable|null\n     */\n    public function getLocalMacro($name)\n    {\n        return ($this->localMacros ?? [])[$name] ?? static::getMacro($name);\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Traits/MagicParameter.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Traits;\n\n/**\n * Trait MagicParameter.\n *\n * Allows to retrieve parameter in magic calls by index or name.\n */\ntrait MagicParameter\n{\n    private function getMagicParameter(array $parameters, int $index, string $key, $default)\n    {\n        if (\\array_key_exists($index, $parameters)) {\n            return $parameters[$index];\n        }\n\n        if (\\array_key_exists($key, $parameters)) {\n            return $parameters[$key];\n        }\n\n        return $default;\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Traits/Mixin.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Traits;\n\nuse Carbon\\CarbonInterface;\nuse Carbon\\CarbonInterval;\nuse Carbon\\CarbonPeriod;\nuse Closure;\nuse Generator;\nuse ReflectionClass;\nuse ReflectionException;\nuse ReflectionMethod;\nuse Throwable;\n\n/**\n * Trait Mixin.\n *\n * Allows mixing in entire classes with multiple macros.\n */\ntrait Mixin\n{\n    /**\n     * Stack of macro instance contexts.\n     *\n     * @var array\n     */\n    protected static $macroContextStack = [];\n\n    /**\n     * Mix another object into the class.\n     *\n     * @example\n     * ```\n     * Carbon::mixin(new class {\n     *   public function addMoon() {\n     *     return function () {\n     *       return $this->addDays(30);\n     *     };\n     *   }\n     *   public function subMoon() {\n     *     return function () {\n     *       return $this->subDays(30);\n     *     };\n     *   }\n     * });\n     * $fullMoon = Carbon::create('2018-12-22');\n     * $nextFullMoon = $fullMoon->addMoon();\n     * $blackMoon = Carbon::create('2019-01-06');\n     * $previousBlackMoon = $blackMoon->subMoon();\n     * echo \"$nextFullMoon\\n\";\n     * echo \"$previousBlackMoon\\n\";\n     * ```\n     *\n     * @param object|string $mixin\n     *\n     * @throws ReflectionException\n     *\n     * @return void\n     */\n    public static function mixin($mixin)\n    {\n        \\is_string($mixin) && trait_exists($mixin)\n            ? self::loadMixinTrait($mixin)\n            : self::loadMixinClass($mixin);\n    }\n\n    /**\n     * @param object|string $mixin\n     *\n     * @throws ReflectionException\n     */\n    private static function loadMixinClass($mixin)\n    {\n        $methods = (new ReflectionClass($mixin))->getMethods(\n            ReflectionMethod::IS_PUBLIC | ReflectionMethod::IS_PROTECTED\n        );\n\n        foreach ($methods as $method) {\n            if ($method->isConstructor() || $method->isDestructor()) {\n                continue;\n            }\n\n            $method->setAccessible(true);\n\n            static::macro($method->name, $method->invoke($mixin));\n        }\n    }\n\n    /**\n     * @param string $trait\n     */\n    private static function loadMixinTrait($trait)\n    {\n        $context = eval(self::getAnonymousClassCodeForTrait($trait));\n        $className = \\get_class($context);\n        $baseClass = static::class;\n\n        foreach (self::getMixableMethods($context) as $name) {\n            $closureBase = Closure::fromCallable([$context, $name]);\n\n            static::macro($name, function (...$parameters) use ($closureBase, $className, $baseClass) {\n                $downContext = isset($this) ? ($this) : new $baseClass();\n                $context = isset($this) ? $this->cast($className) : new $className();\n\n                try {\n                    // @ is required to handle error if not converted into exceptions\n                    $closure = @$closureBase->bindTo($context);\n                } catch (Throwable $throwable) { // @codeCoverageIgnore\n                    $closure = $closureBase; // @codeCoverageIgnore\n                }\n\n                // in case of errors not converted into exceptions\n                $closure = $closure ?: $closureBase;\n\n                $result = $closure(...$parameters);\n\n                if (!($result instanceof $className)) {\n                    return $result;\n                }\n\n                if ($downContext instanceof CarbonInterface && $result instanceof CarbonInterface) {\n                    if ($context !== $result) {\n                        $downContext = $downContext->copy();\n                    }\n\n                    return $downContext\n                        ->setTimezone($result->getTimezone())\n                        ->modify($result->format('Y-m-d H:i:s.u'))\n                        ->settings($result->getSettings());\n                }\n\n                if ($downContext instanceof CarbonInterval && $result instanceof CarbonInterval) {\n                    if ($context !== $result) {\n                        $downContext = $downContext->copy();\n                    }\n\n                    $downContext->copyProperties($result);\n                    self::copyStep($downContext, $result);\n                    self::copyNegativeUnits($downContext, $result);\n\n                    return $downContext->settings($result->getSettings());\n                }\n\n                if ($downContext instanceof CarbonPeriod && $result instanceof CarbonPeriod) {\n                    if ($context !== $result) {\n                        $downContext = $downContext->copy();\n                    }\n\n                    return $downContext\n                        ->setDates($result->getStartDate(), $result->getEndDate())\n                        ->setRecurrences($result->getRecurrences())\n                        ->setOptions($result->getOptions())\n                        ->settings($result->getSettings());\n                }\n\n                return $result;\n            });\n        }\n    }\n\n    private static function getAnonymousClassCodeForTrait(string $trait)\n    {\n        return 'return new class() extends '.static::class.' {use '.$trait.';};';\n    }\n\n    private static function getMixableMethods(self $context): Generator\n    {\n        foreach (get_class_methods($context) as $name) {\n            if (method_exists(static::class, $name)) {\n                continue;\n            }\n\n            yield $name;\n        }\n    }\n\n    /**\n     * Stack a Carbon context from inside calls of self::this() and execute a given action.\n     *\n     * @param static|null $context\n     * @param callable    $callable\n     *\n     * @throws Throwable\n     *\n     * @return mixed\n     */\n    protected static function bindMacroContext($context, callable $callable)\n    {\n        static::$macroContextStack[] = $context;\n\n        try {\n            return $callable();\n        } finally {\n            array_pop(static::$macroContextStack);\n        }\n    }\n\n    /**\n     * Return the current context from inside a macro callee or a null if static.\n     *\n     * @return static|null\n     */\n    protected static function context()\n    {\n        return end(static::$macroContextStack) ?: null;\n    }\n\n    /**\n     * Return the current context from inside a macro callee or a new one if static.\n     *\n     * @return static\n     */\n    protected static function this()\n    {\n        return end(static::$macroContextStack) ?: new static();\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Traits/Modifiers.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Traits;\n\nuse Carbon\\CarbonInterface;\nuse ReturnTypeWillChange;\n\n/**\n * Trait Modifiers.\n *\n * Returns dates relative to current date using modifier short-hand.\n */\ntrait Modifiers\n{\n    /**\n     * Midday/noon hour.\n     *\n     * @var int\n     */\n    protected static $midDayAt = 12;\n\n    /**\n     * get midday/noon hour\n     *\n     * @return int\n     */\n    public static function getMidDayAt()\n    {\n        return static::$midDayAt;\n    }\n\n    /**\n     * @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n     *             You should rather consider mid-day is always 12pm, then if you need to test if it's an other\n     *             hour, test it explicitly:\n     *                 $date->format('G') == 13\n     *             or to set explicitly to a given hour:\n     *                 $date->setTime(13, 0, 0, 0)\n     *\n     * Set midday/noon hour\n     *\n     * @param int $hour midday hour\n     *\n     * @return void\n     */\n    public static function setMidDayAt($hour)\n    {\n        static::$midDayAt = $hour;\n    }\n\n    /**\n     * Modify to midday, default to self::$midDayAt\n     *\n     * @return static\n     */\n    public function midDay()\n    {\n        return $this->setTime(static::$midDayAt, 0, 0, 0);\n    }\n\n    /**\n     * Modify to the next occurrence of a given modifier such as a day of\n     * the week. If no modifier is provided, modify to the next occurrence\n     * of the current day of the week. Use the supplied constants\n     * to indicate the desired dayOfWeek, ex. static::MONDAY.\n     *\n     * @param string|int|null $modifier\n     *\n     * @return static|false\n     */\n    public function next($modifier = null)\n    {\n        if ($modifier === null) {\n            $modifier = $this->dayOfWeek;\n        }\n\n        return $this->change(\n            'next '.(\\is_string($modifier) ? $modifier : static::$days[$modifier])\n        );\n    }\n\n    /**\n     * Go forward or backward to the next week- or weekend-day.\n     *\n     * @param bool $weekday\n     * @param bool $forward\n     *\n     * @return static\n     */\n    private function nextOrPreviousDay($weekday = true, $forward = true)\n    {\n        /** @var CarbonInterface $date */\n        $date = $this;\n        $step = $forward ? 1 : -1;\n\n        do {\n            $date = $date->addDays($step);\n        } while ($weekday ? $date->isWeekend() : $date->isWeekday());\n\n        return $date;\n    }\n\n    /**\n     * Go forward to the next weekday.\n     *\n     * @return static\n     */\n    public function nextWeekday()\n    {\n        return $this->nextOrPreviousDay();\n    }\n\n    /**\n     * Go backward to the previous weekday.\n     *\n     * @return static\n     */\n    public function previousWeekday()\n    {\n        return $this->nextOrPreviousDay(true, false);\n    }\n\n    /**\n     * Go forward to the next weekend day.\n     *\n     * @return static\n     */\n    public function nextWeekendDay()\n    {\n        return $this->nextOrPreviousDay(false);\n    }\n\n    /**\n     * Go backward to the previous weekend day.\n     *\n     * @return static\n     */\n    public function previousWeekendDay()\n    {\n        return $this->nextOrPreviousDay(false, false);\n    }\n\n    /**\n     * Modify to the previous occurrence of a given modifier such as a day of\n     * the week. If no dayOfWeek is provided, modify to the previous occurrence\n     * of the current day of the week. Use the supplied constants\n     * to indicate the desired dayOfWeek, ex. static::MONDAY.\n     *\n     * @param string|int|null $modifier\n     *\n     * @return static|false\n     */\n    public function previous($modifier = null)\n    {\n        if ($modifier === null) {\n            $modifier = $this->dayOfWeek;\n        }\n\n        return $this->change(\n            'last '.(\\is_string($modifier) ? $modifier : static::$days[$modifier])\n        );\n    }\n\n    /**\n     * Modify to the first occurrence of a given day of the week\n     * in the current month. If no dayOfWeek is provided, modify to the\n     * first day of the current month.  Use the supplied constants\n     * to indicate the desired dayOfWeek, ex. static::MONDAY.\n     *\n     * @param int|null $dayOfWeek\n     *\n     * @return static\n     */\n    public function firstOfMonth($dayOfWeek = null)\n    {\n        $date = $this->startOfDay();\n\n        if ($dayOfWeek === null) {\n            return $date->day(1);\n        }\n\n        return $date->modify('first '.static::$days[$dayOfWeek].' of '.$date->rawFormat('F').' '.$date->year);\n    }\n\n    /**\n     * Modify to the last occurrence of a given day of the week\n     * in the current month. If no dayOfWeek is provided, modify to the\n     * last day of the current month.  Use the supplied constants\n     * to indicate the desired dayOfWeek, ex. static::MONDAY.\n     *\n     * @param int|null $dayOfWeek\n     *\n     * @return static\n     */\n    public function lastOfMonth($dayOfWeek = null)\n    {\n        $date = $this->startOfDay();\n\n        if ($dayOfWeek === null) {\n            return $date->day($date->daysInMonth);\n        }\n\n        return $date->modify('last '.static::$days[$dayOfWeek].' of '.$date->rawFormat('F').' '.$date->year);\n    }\n\n    /**\n     * Modify to the given occurrence of a given day of the week\n     * in the current month. If the calculated occurrence is outside the scope\n     * of the current month, then return false and no modifications are made.\n     * Use the supplied constants to indicate the desired dayOfWeek, ex. static::MONDAY.\n     *\n     * @param int $nth\n     * @param int $dayOfWeek\n     *\n     * @return mixed\n     */\n    public function nthOfMonth($nth, $dayOfWeek)\n    {\n        $date = $this->avoidMutation()->firstOfMonth();\n        $check = $date->rawFormat('Y-m');\n        $date = $date->modify('+'.$nth.' '.static::$days[$dayOfWeek]);\n\n        return $date->rawFormat('Y-m') === $check ? $this->modify((string) $date) : false;\n    }\n\n    /**\n     * Modify to the first occurrence of a given day of the week\n     * in the current quarter. If no dayOfWeek is provided, modify to the\n     * first day of the current quarter.  Use the supplied constants\n     * to indicate the desired dayOfWeek, ex. static::MONDAY.\n     *\n     * @param int|null $dayOfWeek day of the week default null\n     *\n     * @return static\n     */\n    public function firstOfQuarter($dayOfWeek = null)\n    {\n        return $this->setDate($this->year, $this->quarter * static::MONTHS_PER_QUARTER - 2, 1)->firstOfMonth($dayOfWeek);\n    }\n\n    /**\n     * Modify to the last occurrence of a given day of the week\n     * in the current quarter. If no dayOfWeek is provided, modify to the\n     * last day of the current quarter.  Use the supplied constants\n     * to indicate the desired dayOfWeek, ex. static::MONDAY.\n     *\n     * @param int|null $dayOfWeek day of the week default null\n     *\n     * @return static\n     */\n    public function lastOfQuarter($dayOfWeek = null)\n    {\n        return $this->setDate($this->year, $this->quarter * static::MONTHS_PER_QUARTER, 1)->lastOfMonth($dayOfWeek);\n    }\n\n    /**\n     * Modify to the given occurrence of a given day of the week\n     * in the current quarter. If the calculated occurrence is outside the scope\n     * of the current quarter, then return false and no modifications are made.\n     * Use the supplied constants to indicate the desired dayOfWeek, ex. static::MONDAY.\n     *\n     * @param int $nth\n     * @param int $dayOfWeek\n     *\n     * @return mixed\n     */\n    public function nthOfQuarter($nth, $dayOfWeek)\n    {\n        $date = $this->avoidMutation()->day(1)->month($this->quarter * static::MONTHS_PER_QUARTER);\n        $lastMonth = $date->month;\n        $year = $date->year;\n        $date = $date->firstOfQuarter()->modify('+'.$nth.' '.static::$days[$dayOfWeek]);\n\n        return ($lastMonth < $date->month || $year !== $date->year) ? false : $this->modify((string) $date);\n    }\n\n    /**\n     * Modify to the first occurrence of a given day of the week\n     * in the current year. If no dayOfWeek is provided, modify to the\n     * first day of the current year.  Use the supplied constants\n     * to indicate the desired dayOfWeek, ex. static::MONDAY.\n     *\n     * @param int|null $dayOfWeek day of the week default null\n     *\n     * @return static\n     */\n    public function firstOfYear($dayOfWeek = null)\n    {\n        return $this->month(1)->firstOfMonth($dayOfWeek);\n    }\n\n    /**\n     * Modify to the last occurrence of a given day of the week\n     * in the current year. If no dayOfWeek is provided, modify to the\n     * last day of the current year.  Use the supplied constants\n     * to indicate the desired dayOfWeek, ex. static::MONDAY.\n     *\n     * @param int|null $dayOfWeek day of the week default null\n     *\n     * @return static\n     */\n    public function lastOfYear($dayOfWeek = null)\n    {\n        return $this->month(static::MONTHS_PER_YEAR)->lastOfMonth($dayOfWeek);\n    }\n\n    /**\n     * Modify to the given occurrence of a given day of the week\n     * in the current year. If the calculated occurrence is outside the scope\n     * of the current year, then return false and no modifications are made.\n     * Use the supplied constants to indicate the desired dayOfWeek, ex. static::MONDAY.\n     *\n     * @param int $nth\n     * @param int $dayOfWeek\n     *\n     * @return mixed\n     */\n    public function nthOfYear($nth, $dayOfWeek)\n    {\n        $date = $this->avoidMutation()->firstOfYear()->modify('+'.$nth.' '.static::$days[$dayOfWeek]);\n\n        return $this->year === $date->year ? $this->modify((string) $date) : false;\n    }\n\n    /**\n     * Modify the current instance to the average of a given instance (default now) and the current instance\n     * (second-precision).\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|null $date\n     *\n     * @return static\n     */\n    public function average($date = null)\n    {\n        return $this->addRealMicroseconds((int) ($this->diffInRealMicroseconds($this->resolveCarbon($date), false) / 2));\n    }\n\n    /**\n     * Get the closest date from the instance (second-precision).\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date1\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date2\n     *\n     * @return static\n     */\n    public function closest($date1, $date2)\n    {\n        return $this->diffInRealMicroseconds($date1) < $this->diffInRealMicroseconds($date2) ? $date1 : $date2;\n    }\n\n    /**\n     * Get the farthest date from the instance (second-precision).\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date1\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date2\n     *\n     * @return static\n     */\n    public function farthest($date1, $date2)\n    {\n        return $this->diffInRealMicroseconds($date1) > $this->diffInRealMicroseconds($date2) ? $date1 : $date2;\n    }\n\n    /**\n     * Get the minimum instance between a given instance (default now) and the current instance.\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date\n     *\n     * @return static\n     */\n    public function min($date = null)\n    {\n        $date = $this->resolveCarbon($date);\n\n        return $this->lt($date) ? $this : $date;\n    }\n\n    /**\n     * Get the minimum instance between a given instance (default now) and the current instance.\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date\n     *\n     * @see min()\n     *\n     * @return static\n     */\n    public function minimum($date = null)\n    {\n        return $this->min($date);\n    }\n\n    /**\n     * Get the maximum instance between a given instance (default now) and the current instance.\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date\n     *\n     * @return static\n     */\n    public function max($date = null)\n    {\n        $date = $this->resolveCarbon($date);\n\n        return $this->gt($date) ? $this : $date;\n    }\n\n    /**\n     * Get the maximum instance between a given instance (default now) and the current instance.\n     *\n     * @param \\Carbon\\Carbon|\\DateTimeInterface|mixed $date\n     *\n     * @see max()\n     *\n     * @return static\n     */\n    public function maximum($date = null)\n    {\n        return $this->max($date);\n    }\n\n    /**\n     * Calls \\DateTime::modify if mutable or \\DateTimeImmutable::modify else.\n     *\n     * @see https://php.net/manual/en/datetime.modify.php\n     *\n     * @return static|false\n     */\n    #[ReturnTypeWillChange]\n    public function modify($modify)\n    {\n        return parent::modify((string) $modify);\n    }\n\n    /**\n     * Similar to native modify() method of DateTime but can handle more grammars.\n     *\n     * @example\n     * ```\n     * echo Carbon::now()->change('next 2pm');\n     * ```\n     *\n     * @link https://php.net/manual/en/datetime.modify.php\n     *\n     * @param string $modifier\n     *\n     * @return static|false\n     */\n    public function change($modifier)\n    {\n        return $this->modify(preg_replace_callback('/^(next|previous|last)\\s+(\\d{1,2}(h|am|pm|:\\d{1,2}(:\\d{1,2})?))$/i', function ($match) {\n            $match[2] = str_replace('h', ':00', $match[2]);\n            $test = $this->avoidMutation()->modify($match[2]);\n            $method = $match[1] === 'next' ? 'lt' : 'gt';\n            $match[1] = $test->$method($this) ? $match[1].' day' : 'today';\n\n            return $match[1].' '.$match[2];\n        }, strtr(trim($modifier), [\n            ' at ' => ' ',\n            'just now' => 'now',\n            'after tomorrow' => 'tomorrow +1 day',\n            'before yesterday' => 'yesterday -1 day',\n        ])));\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Traits/Mutability.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Traits;\n\nuse Carbon\\Carbon;\nuse Carbon\\CarbonImmutable;\n\n/**\n * Trait Mutability.\n *\n * Utils to know if the current object is mutable or immutable and convert it.\n */\ntrait Mutability\n{\n    use Cast;\n\n    /**\n     * Returns true if the current class/instance is mutable.\n     *\n     * @return bool\n     */\n    public static function isMutable()\n    {\n        return false;\n    }\n\n    /**\n     * Returns true if the current class/instance is immutable.\n     *\n     * @return bool\n     */\n    public static function isImmutable()\n    {\n        return !static::isMutable();\n    }\n\n    /**\n     * Return a mutable copy of the instance.\n     *\n     * @return Carbon\n     */\n    public function toMutable()\n    {\n        /** @var Carbon $date */\n        $date = $this->cast(Carbon::class);\n\n        return $date;\n    }\n\n    /**\n     * Return a immutable copy of the instance.\n     *\n     * @return CarbonImmutable\n     */\n    public function toImmutable()\n    {\n        /** @var CarbonImmutable $date */\n        $date = $this->cast(CarbonImmutable::class);\n\n        return $date;\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Traits/ObjectInitialisation.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Traits;\n\ntrait ObjectInitialisation\n{\n    /**\n     * True when parent::__construct has been called.\n     *\n     * @var string\n     */\n    protected $constructedObjectId;\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Traits/Options.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Traits;\n\nuse Carbon\\CarbonInterface;\nuse DateTimeInterface;\nuse Throwable;\n\n/**\n * Trait Options.\n *\n * Embed base methods to change settings of Carbon classes.\n *\n * Depends on the following methods:\n *\n * @method static shiftTimezone($timezone) Set the timezone\n */\ntrait Options\n{\n    use Localization;\n\n    /**\n     * Customizable PHP_INT_SIZE override.\n     *\n     * @var int\n     */\n    public static $PHPIntSize = PHP_INT_SIZE;\n\n    /**\n     * First day of week.\n     *\n     * @var int|string\n     */\n    protected static $weekStartsAt = CarbonInterface::MONDAY;\n\n    /**\n     * Last day of week.\n     *\n     * @var int|string\n     */\n    protected static $weekEndsAt = CarbonInterface::SUNDAY;\n\n    /**\n     * Days of weekend.\n     *\n     * @var array\n     */\n    protected static $weekendDays = [\n        CarbonInterface::SATURDAY,\n        CarbonInterface::SUNDAY,\n    ];\n\n    /**\n     * Format regex patterns.\n     *\n     * @var array<string, string>\n     */\n    protected static $regexFormats = [\n        'd' => '(3[01]|[12][0-9]|0[1-9])',\n        'D' => '(Sun|Mon|Tue|Wed|Thu|Fri|Sat)',\n        'j' => '([123][0-9]|[1-9])',\n        'l' => '([a-zA-Z]{2,})',\n        'N' => '([1-7])',\n        'S' => '(st|nd|rd|th)',\n        'w' => '([0-6])',\n        'z' => '(36[0-5]|3[0-5][0-9]|[12][0-9]{2}|[1-9]?[0-9])',\n        'W' => '(5[012]|[1-4][0-9]|0?[1-9])',\n        'F' => '([a-zA-Z]{2,})',\n        'm' => '(1[012]|0[1-9])',\n        'M' => '([a-zA-Z]{3})',\n        'n' => '(1[012]|[1-9])',\n        't' => '(2[89]|3[01])',\n        'L' => '(0|1)',\n        'o' => '([1-9][0-9]{0,4})',\n        'Y' => '([1-9]?[0-9]{4})',\n        'y' => '([0-9]{2})',\n        'a' => '(am|pm)',\n        'A' => '(AM|PM)',\n        'B' => '([0-9]{3})',\n        'g' => '(1[012]|[1-9])',\n        'G' => '(2[0-3]|1?[0-9])',\n        'h' => '(1[012]|0[1-9])',\n        'H' => '(2[0-3]|[01][0-9])',\n        'i' => '([0-5][0-9])',\n        's' => '([0-5][0-9])',\n        'u' => '([0-9]{1,6})',\n        'v' => '([0-9]{1,3})',\n        'e' => '([a-zA-Z]{1,5})|([a-zA-Z]*\\\\/[a-zA-Z]*)',\n        'I' => '(0|1)',\n        'O' => '([+-](1[0123]|0[0-9])[0134][05])',\n        'P' => '([+-](1[0123]|0[0-9]):[0134][05])',\n        'p' => '(Z|[+-](1[0123]|0[0-9]):[0134][05])',\n        'T' => '([a-zA-Z]{1,5})',\n        'Z' => '(-?[1-5]?[0-9]{1,4})',\n        'U' => '([0-9]*)',\n\n        // The formats below are combinations of the above formats.\n        'c' => '(([1-9]?[0-9]{4})-(1[012]|0[1-9])-(3[01]|[12][0-9]|0[1-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])[+-](1[012]|0[0-9]):([0134][05]))', // Y-m-dTH:i:sP\n        'r' => '(([a-zA-Z]{3}), ([123][0-9]|0[1-9]) ([a-zA-Z]{3}) ([1-9]?[0-9]{4}) (2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9]) [+-](1[012]|0[0-9])([0134][05]))', // D, d M Y H:i:s O\n    ];\n\n    /**\n     * Format modifiers (such as available in createFromFormat) regex patterns.\n     *\n     * @var array\n     */\n    protected static $regexFormatModifiers = [\n        '*' => '.+',\n        ' ' => '[   ]',\n        '#' => '[;:\\\\/.,()-]',\n        '?' => '([^a]|[a])',\n        '!' => '',\n        '|' => '',\n        '+' => '',\n    ];\n\n    /**\n     * Indicates if months should be calculated with overflow.\n     * Global setting.\n     *\n     * @var bool\n     */\n    protected static $monthsOverflow = true;\n\n    /**\n     * Indicates if years should be calculated with overflow.\n     * Global setting.\n     *\n     * @var bool\n     */\n    protected static $yearsOverflow = true;\n\n    /**\n     * Indicates if the strict mode is in use.\n     * Global setting.\n     *\n     * @var bool\n     */\n    protected static $strictModeEnabled = true;\n\n    /**\n     * Function to call instead of format.\n     *\n     * @var string|callable|null\n     */\n    protected static $formatFunction;\n\n    /**\n     * Function to call instead of createFromFormat.\n     *\n     * @var string|callable|null\n     */\n    protected static $createFromFormatFunction;\n\n    /**\n     * Function to call instead of parse.\n     *\n     * @var string|callable|null\n     */\n    protected static $parseFunction;\n\n    /**\n     * Indicates if months should be calculated with overflow.\n     * Specific setting.\n     *\n     * @var bool|null\n     */\n    protected $localMonthsOverflow;\n\n    /**\n     * Indicates if years should be calculated with overflow.\n     * Specific setting.\n     *\n     * @var bool|null\n     */\n    protected $localYearsOverflow;\n\n    /**\n     * Indicates if the strict mode is in use.\n     * Specific setting.\n     *\n     * @var bool|null\n     */\n    protected $localStrictModeEnabled;\n\n    /**\n     * Options for diffForHumans and forHumans methods.\n     *\n     * @var bool|null\n     */\n    protected $localHumanDiffOptions;\n\n    /**\n     * Format to use on string cast.\n     *\n     * @var string|null\n     */\n    protected $localToStringFormat;\n\n    /**\n     * Format to use on JSON serialization.\n     *\n     * @var string|null\n     */\n    protected $localSerializer;\n\n    /**\n     * Instance-specific macros.\n     *\n     * @var array|null\n     */\n    protected $localMacros;\n\n    /**\n     * Instance-specific generic macros.\n     *\n     * @var array|null\n     */\n    protected $localGenericMacros;\n\n    /**\n     * Function to call instead of format.\n     *\n     * @var string|callable|null\n     */\n    protected $localFormatFunction;\n\n    /**\n     * @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n     *             You should rather use the ->settings() method.\n     * @see settings\n     *\n     * Enable the strict mode (or disable with passing false).\n     *\n     * @param bool $strictModeEnabled\n     */\n    public static function useStrictMode($strictModeEnabled = true)\n    {\n        static::$strictModeEnabled = $strictModeEnabled;\n    }\n\n    /**\n     * Returns true if the strict mode is globally in use, false else.\n     * (It can be overridden in specific instances.)\n     *\n     * @return bool\n     */\n    public static function isStrictModeEnabled()\n    {\n        return static::$strictModeEnabled;\n    }\n\n    /**\n     * @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n     *             You should rather use the ->settings() method.\n     *             Or you can use method variants: addMonthsWithOverflow/addMonthsNoOverflow, same variants\n     *             are available for quarters, years, decade, centuries, millennia (singular and plural forms).\n     * @see settings\n     *\n     * Indicates if months should be calculated with overflow.\n     *\n     * @param bool $monthsOverflow\n     *\n     * @return void\n     */\n    public static function useMonthsOverflow($monthsOverflow = true)\n    {\n        static::$monthsOverflow = $monthsOverflow;\n    }\n\n    /**\n     * @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n     *             You should rather use the ->settings() method.\n     *             Or you can use method variants: addMonthsWithOverflow/addMonthsNoOverflow, same variants\n     *             are available for quarters, years, decade, centuries, millennia (singular and plural forms).\n     * @see settings\n     *\n     * Reset the month overflow behavior.\n     *\n     * @return void\n     */\n    public static function resetMonthsOverflow()\n    {\n        static::$monthsOverflow = true;\n    }\n\n    /**\n     * Get the month overflow global behavior (can be overridden in specific instances).\n     *\n     * @return bool\n     */\n    public static function shouldOverflowMonths()\n    {\n        return static::$monthsOverflow;\n    }\n\n    /**\n     * @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n     *             You should rather use the ->settings() method.\n     *             Or you can use method variants: addYearsWithOverflow/addYearsNoOverflow, same variants\n     *             are available for quarters, years, decade, centuries, millennia (singular and plural forms).\n     * @see settings\n     *\n     * Indicates if years should be calculated with overflow.\n     *\n     * @param bool $yearsOverflow\n     *\n     * @return void\n     */\n    public static function useYearsOverflow($yearsOverflow = true)\n    {\n        static::$yearsOverflow = $yearsOverflow;\n    }\n\n    /**\n     * @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n     *             You should rather use the ->settings() method.\n     *             Or you can use method variants: addYearsWithOverflow/addYearsNoOverflow, same variants\n     *             are available for quarters, years, decade, centuries, millennia (singular and plural forms).\n     * @see settings\n     *\n     * Reset the month overflow behavior.\n     *\n     * @return void\n     */\n    public static function resetYearsOverflow()\n    {\n        static::$yearsOverflow = true;\n    }\n\n    /**\n     * Get the month overflow global behavior (can be overridden in specific instances).\n     *\n     * @return bool\n     */\n    public static function shouldOverflowYears()\n    {\n        return static::$yearsOverflow;\n    }\n\n    /**\n     * Set specific options.\n     *  - strictMode: true|false|null\n     *  - monthOverflow: true|false|null\n     *  - yearOverflow: true|false|null\n     *  - humanDiffOptions: int|null\n     *  - toStringFormat: string|Closure|null\n     *  - toJsonFormat: string|Closure|null\n     *  - locale: string|null\n     *  - timezone: \\DateTimeZone|string|int|null\n     *  - macros: array|null\n     *  - genericMacros: array|null\n     *\n     * @param array $settings\n     *\n     * @return $this|static\n     */\n    public function settings(array $settings)\n    {\n        $this->localStrictModeEnabled = $settings['strictMode'] ?? null;\n        $this->localMonthsOverflow = $settings['monthOverflow'] ?? null;\n        $this->localYearsOverflow = $settings['yearOverflow'] ?? null;\n        $this->localHumanDiffOptions = $settings['humanDiffOptions'] ?? null;\n        $this->localToStringFormat = $settings['toStringFormat'] ?? null;\n        $this->localSerializer = $settings['toJsonFormat'] ?? null;\n        $this->localMacros = $settings['macros'] ?? null;\n        $this->localGenericMacros = $settings['genericMacros'] ?? null;\n        $this->localFormatFunction = $settings['formatFunction'] ?? null;\n\n        if (isset($settings['locale'])) {\n            $locales = $settings['locale'];\n\n            if (!\\is_array($locales)) {\n                $locales = [$locales];\n            }\n\n            $this->locale(...$locales);\n        }\n\n        if (isset($settings['innerTimezone'])) {\n            return $this->setTimezone($settings['innerTimezone']);\n        }\n\n        if (isset($settings['timezone'])) {\n            return $this->shiftTimezone($settings['timezone']);\n        }\n\n        return $this;\n    }\n\n    /**\n     * Returns current local settings.\n     *\n     * @return array\n     */\n    public function getSettings()\n    {\n        $settings = [];\n        $map = [\n            'localStrictModeEnabled' => 'strictMode',\n            'localMonthsOverflow' => 'monthOverflow',\n            'localYearsOverflow' => 'yearOverflow',\n            'localHumanDiffOptions' => 'humanDiffOptions',\n            'localToStringFormat' => 'toStringFormat',\n            'localSerializer' => 'toJsonFormat',\n            'localMacros' => 'macros',\n            'localGenericMacros' => 'genericMacros',\n            'locale' => 'locale',\n            'tzName' => 'timezone',\n            'localFormatFunction' => 'formatFunction',\n        ];\n\n        foreach ($map as $property => $key) {\n            $value = $this->$property ?? null;\n\n            if ($value !== null && ($key !== 'locale' || $value !== 'en' || $this->localTranslator)) {\n                $settings[$key] = $value;\n            }\n        }\n\n        return $settings;\n    }\n\n    /**\n     * Show truthy properties on var_dump().\n     *\n     * @return array\n     */\n    public function __debugInfo()\n    {\n        $infos = array_filter(get_object_vars($this), static function ($var) {\n            return $var;\n        });\n\n        foreach (['dumpProperties', 'constructedObjectId', 'constructed'] as $property) {\n            if (isset($infos[$property])) {\n                unset($infos[$property]);\n            }\n        }\n\n        $this->addExtraDebugInfos($infos);\n\n        return $infos;\n    }\n\n    protected function addExtraDebugInfos(&$infos): void\n    {\n        if ($this instanceof DateTimeInterface) {\n            try {\n                if (!isset($infos['date'])) {\n                    $infos['date'] = $this->format(CarbonInterface::MOCK_DATETIME_FORMAT);\n                }\n\n                if (!isset($infos['timezone'])) {\n                    $infos['timezone'] = $this->tzName;\n                }\n            } catch (Throwable $exception) {\n                // noop\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Traits/Rounding.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Traits;\n\nuse Carbon\\CarbonInterface;\nuse Carbon\\Exceptions\\UnknownUnitException;\n\n/**\n * Trait Rounding.\n *\n * Round, ceil, floor units.\n *\n * Depends on the following methods:\n *\n * @method static copy()\n * @method static startOfWeek(int $weekStartsAt = null)\n */\ntrait Rounding\n{\n    use IntervalRounding;\n\n    /**\n     * Round the current instance at the given unit with given precision if specified and the given function.\n     *\n     * @param string    $unit\n     * @param float|int $precision\n     * @param string    $function\n     *\n     * @return CarbonInterface\n     */\n    public function roundUnit($unit, $precision = 1, $function = 'round')\n    {\n        $metaUnits = [\n            // @call roundUnit\n            'millennium' => [static::YEARS_PER_MILLENNIUM, 'year'],\n            // @call roundUnit\n            'century' => [static::YEARS_PER_CENTURY, 'year'],\n            // @call roundUnit\n            'decade' => [static::YEARS_PER_DECADE, 'year'],\n            // @call roundUnit\n            'quarter' => [static::MONTHS_PER_QUARTER, 'month'],\n            // @call roundUnit\n            'millisecond' => [1000, 'microsecond'],\n        ];\n        $normalizedUnit = static::singularUnit($unit);\n        $ranges = array_merge(static::getRangesByUnit($this->daysInMonth), [\n            // @call roundUnit\n            'microsecond' => [0, 999999],\n        ]);\n        $factor = 1;\n\n        if ($normalizedUnit === 'week') {\n            $normalizedUnit = 'day';\n            $precision *= static::DAYS_PER_WEEK;\n        }\n\n        if (isset($metaUnits[$normalizedUnit])) {\n            [$factor, $normalizedUnit] = $metaUnits[$normalizedUnit];\n        }\n\n        $precision *= $factor;\n\n        if (!isset($ranges[$normalizedUnit])) {\n            throw new UnknownUnitException($unit);\n        }\n\n        $found = false;\n        $fraction = 0;\n        $arguments = null;\n        $initialValue = null;\n        $factor = $this->year < 0 ? -1 : 1;\n        $changes = [];\n        $minimumInc = null;\n\n        foreach ($ranges as $unit => [$minimum, $maximum]) {\n            if ($normalizedUnit === $unit) {\n                $arguments = [$this->$unit, $minimum];\n                $initialValue = $this->$unit;\n                $fraction = $precision - floor($precision);\n                $found = true;\n\n                continue;\n            }\n\n            if ($found) {\n                $delta = $maximum + 1 - $minimum;\n                $factor /= $delta;\n                $fraction *= $delta;\n                $inc = ($this->$unit - $minimum) * $factor;\n\n                if ($inc !== 0.0) {\n                    $minimumInc = $minimumInc ?? ($arguments[0] / pow(2, 52));\n\n                    // If value is still the same when adding a non-zero increment/decrement,\n                    // it means precision got lost in the addition\n                    if (abs($inc) < $minimumInc) {\n                        $inc = $minimumInc * ($inc < 0 ? -1 : 1);\n                    }\n\n                    // If greater than $precision, assume precision loss caused an overflow\n                    if ($function !== 'floor' || abs($arguments[0] + $inc - $initialValue) >= $precision) {\n                        $arguments[0] += $inc;\n                    }\n                }\n\n                $changes[$unit] = round(\n                    $minimum + ($fraction ? $fraction * $function(($this->$unit - $minimum) / $fraction) : 0)\n                );\n\n                // Cannot use modulo as it lose double precision\n                while ($changes[$unit] >= $delta) {\n                    $changes[$unit] -= $delta;\n                }\n\n                $fraction -= floor($fraction);\n            }\n        }\n\n        [$value, $minimum] = $arguments;\n        $normalizedValue = floor($function(($value - $minimum) / $precision) * $precision + $minimum);\n\n        /** @var CarbonInterface $result */\n        $result = $this;\n\n        foreach ($changes as $unit => $value) {\n            $result = $result->$unit($value);\n        }\n\n        return $result->$normalizedUnit($normalizedValue);\n    }\n\n    /**\n     * Truncate the current instance at the given unit with given precision if specified.\n     *\n     * @param string    $unit\n     * @param float|int $precision\n     *\n     * @return CarbonInterface\n     */\n    public function floorUnit($unit, $precision = 1)\n    {\n        return $this->roundUnit($unit, $precision, 'floor');\n    }\n\n    /**\n     * Ceil the current instance at the given unit with given precision if specified.\n     *\n     * @param string    $unit\n     * @param float|int $precision\n     *\n     * @return CarbonInterface\n     */\n    public function ceilUnit($unit, $precision = 1)\n    {\n        return $this->roundUnit($unit, $precision, 'ceil');\n    }\n\n    /**\n     * Round the current instance second with given precision if specified.\n     *\n     * @param float|int|string|\\DateInterval|null $precision\n     * @param string                              $function\n     *\n     * @return CarbonInterface\n     */\n    public function round($precision = 1, $function = 'round')\n    {\n        return $this->roundWith($precision, $function);\n    }\n\n    /**\n     * Round the current instance second with given precision if specified.\n     *\n     * @param float|int|string|\\DateInterval|null $precision\n     *\n     * @return CarbonInterface\n     */\n    public function floor($precision = 1)\n    {\n        return $this->round($precision, 'floor');\n    }\n\n    /**\n     * Ceil the current instance second with given precision if specified.\n     *\n     * @param float|int|string|\\DateInterval|null $precision\n     *\n     * @return CarbonInterface\n     */\n    public function ceil($precision = 1)\n    {\n        return $this->round($precision, 'ceil');\n    }\n\n    /**\n     * Round the current instance week.\n     *\n     * @param int $weekStartsAt optional start allow you to specify the day of week to use to start the week\n     *\n     * @return CarbonInterface\n     */\n    public function roundWeek($weekStartsAt = null)\n    {\n        return $this->closest(\n            $this->avoidMutation()->floorWeek($weekStartsAt),\n            $this->avoidMutation()->ceilWeek($weekStartsAt)\n        );\n    }\n\n    /**\n     * Truncate the current instance week.\n     *\n     * @param int $weekStartsAt optional start allow you to specify the day of week to use to start the week\n     *\n     * @return CarbonInterface\n     */\n    public function floorWeek($weekStartsAt = null)\n    {\n        return $this->startOfWeek($weekStartsAt);\n    }\n\n    /**\n     * Ceil the current instance week.\n     *\n     * @param int $weekStartsAt optional start allow you to specify the day of week to use to start the week\n     *\n     * @return CarbonInterface\n     */\n    public function ceilWeek($weekStartsAt = null)\n    {\n        if ($this->isMutable()) {\n            $startOfWeek = $this->avoidMutation()->startOfWeek($weekStartsAt);\n\n            return $startOfWeek != $this ?\n                $this->startOfWeek($weekStartsAt)->addWeek() :\n                $this;\n        }\n\n        $startOfWeek = $this->startOfWeek($weekStartsAt);\n\n        return $startOfWeek != $this ?\n            $startOfWeek->addWeek() :\n            $this->avoidMutation();\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Traits/Serialization.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Traits;\n\nuse Carbon\\Exceptions\\InvalidFormatException;\nuse ReturnTypeWillChange;\nuse Throwable;\n\n/**\n * Trait Serialization.\n *\n * Serialization and JSON stuff.\n *\n * Depends on the following properties:\n *\n * @property int $year\n * @property int $month\n * @property int $daysInMonth\n * @property int $quarter\n *\n * Depends on the following methods:\n *\n * @method string|static locale(string $locale = null, string ...$fallbackLocales)\n * @method string        toJSON()\n */\ntrait Serialization\n{\n    use ObjectInitialisation;\n\n    /**\n     * The custom Carbon JSON serializer.\n     *\n     * @var callable|null\n     */\n    protected static $serializer;\n\n    /**\n     * List of key to use for dump/serialization.\n     *\n     * @var string[]\n     */\n    protected $dumpProperties = ['date', 'timezone_type', 'timezone'];\n\n    /**\n     * Locale to dump comes here before serialization.\n     *\n     * @var string|null\n     */\n    protected $dumpLocale;\n\n    /**\n     * Embed date properties to dump in a dedicated variables so it won't overlap native\n     * DateTime ones.\n     *\n     * @var array|null\n     */\n    protected $dumpDateProperties;\n\n    /**\n     * Return a serialized string of the instance.\n     *\n     * @return string\n     */\n    public function serialize()\n    {\n        return serialize($this);\n    }\n\n    /**\n     * Create an instance from a serialized string.\n     *\n     * @param string $value\n     *\n     * @throws InvalidFormatException\n     *\n     * @return static\n     */\n    public static function fromSerialized($value)\n    {\n        $instance = @unserialize((string) $value);\n\n        if (!$instance instanceof static) {\n            throw new InvalidFormatException(\"Invalid serialized value: $value\");\n        }\n\n        return $instance;\n    }\n\n    /**\n     * The __set_state handler.\n     *\n     * @param string|array $dump\n     *\n     * @return static\n     */\n    #[ReturnTypeWillChange]\n    public static function __set_state($dump)\n    {\n        if (\\is_string($dump)) {\n            return static::parse($dump);\n        }\n\n        /** @var \\DateTimeInterface $date */\n        $date = get_parent_class(static::class) && method_exists(parent::class, '__set_state')\n            ? parent::__set_state((array) $dump)\n            : (object) $dump;\n\n        return static::instance($date);\n    }\n\n    /**\n     * Returns the list of properties to dump on serialize() called on.\n     *\n     * Only used by PHP < 7.4.\n     *\n     * @return array\n     */\n    public function __sleep()\n    {\n        $properties = $this->getSleepProperties();\n\n        if ($this->localTranslator ?? null) {\n            $properties[] = 'dumpLocale';\n            $this->dumpLocale = $this->locale ?? null;\n        }\n\n        return $properties;\n    }\n\n    /**\n     * Returns the values to dump on serialize() called on.\n     *\n     * Only used by PHP >= 7.4.\n     *\n     * @return array\n     */\n    public function __serialize(): array\n    {\n        // @codeCoverageIgnoreStart\n        if (isset($this->timezone_type, $this->timezone, $this->date)) {\n            return [\n                'date' => $this->date ?? null,\n                'timezone_type' => $this->timezone_type,\n                'timezone' => $this->timezone ?? null,\n            ];\n        }\n        // @codeCoverageIgnoreEnd\n\n        $timezone = $this->getTimezone();\n        $export = [\n            'date' => $this->format('Y-m-d H:i:s.u'),\n            'timezone_type' => $timezone->getType(),\n            'timezone' => $timezone->getName(),\n        ];\n\n        // @codeCoverageIgnoreStart\n        if (\\extension_loaded('msgpack') && isset($this->constructedObjectId)) {\n            $export['dumpDateProperties'] = [\n                'date' => $this->format('Y-m-d H:i:s.u'),\n                'timezone' => serialize($this->timezone ?? null),\n            ];\n        }\n        // @codeCoverageIgnoreEnd\n\n        if ($this->localTranslator ?? null) {\n            $export['dumpLocale'] = $this->locale ?? null;\n        }\n\n        return $export;\n    }\n\n    /**\n     * Set locale if specified on unserialize() called.\n     *\n     * Only used by PHP < 7.4.\n     *\n     * @return void\n     */\n    #[ReturnTypeWillChange]\n    public function __wakeup()\n    {\n        if (parent::class && method_exists(parent::class, '__wakeup')) {\n            // @codeCoverageIgnoreStart\n            try {\n                parent::__wakeup();\n            } catch (Throwable $exception) {\n                try {\n                    // FatalError occurs when calling msgpack_unpack() in PHP 7.4 or later.\n                    ['date' => $date, 'timezone' => $timezone] = $this->dumpDateProperties;\n                    parent::__construct($date, unserialize($timezone));\n                } catch (Throwable $ignoredException) {\n                    throw $exception;\n                }\n            }\n            // @codeCoverageIgnoreEnd\n        }\n\n        $this->constructedObjectId = spl_object_hash($this);\n\n        if (isset($this->dumpLocale)) {\n            $this->locale($this->dumpLocale);\n            $this->dumpLocale = null;\n        }\n\n        $this->cleanupDumpProperties();\n    }\n\n    /**\n     * Set locale if specified on unserialize() called.\n     *\n     * Only used by PHP >= 7.4.\n     *\n     * @return void\n     */\n    public function __unserialize(array $data): void\n    {\n        // @codeCoverageIgnoreStart\n        try {\n            $this->__construct($data['date'] ?? null, $data['timezone'] ?? null);\n        } catch (Throwable $exception) {\n            if (!isset($data['dumpDateProperties']['date'], $data['dumpDateProperties']['timezone'])) {\n                throw $exception;\n            }\n\n            try {\n                // FatalError occurs when calling msgpack_unpack() in PHP 7.4 or later.\n                ['date' => $date, 'timezone' => $timezone] = $data['dumpDateProperties'];\n                $this->__construct($date, unserialize($timezone));\n            } catch (Throwable $ignoredException) {\n                throw $exception;\n            }\n        }\n        // @codeCoverageIgnoreEnd\n\n        if (isset($data['dumpLocale'])) {\n            $this->locale($data['dumpLocale']);\n        }\n    }\n\n    /**\n     * Prepare the object for JSON serialization.\n     *\n     * @return array|string\n     */\n    #[ReturnTypeWillChange]\n    public function jsonSerialize()\n    {\n        $serializer = $this->localSerializer ?? static::$serializer;\n\n        if ($serializer) {\n            return \\is_string($serializer)\n                ? $this->rawFormat($serializer)\n                : $serializer($this);\n        }\n\n        return $this->toJSON();\n    }\n\n    /**\n     * @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n     *             You should rather transform Carbon object before the serialization.\n     *\n     * JSON serialize all Carbon instances using the given callback.\n     *\n     * @param callable $callback\n     *\n     * @return void\n     */\n    public static function serializeUsing($callback)\n    {\n        static::$serializer = $callback;\n    }\n\n    /**\n     * Cleanup properties attached to the public scope of DateTime when a dump of the date is requested.\n     * foreach ($date as $_) {}\n     * serializer($date)\n     * var_export($date)\n     * get_object_vars($date)\n     */\n    public function cleanupDumpProperties()\n    {\n        // @codeCoverageIgnoreStart\n        if (PHP_VERSION < 8.2) {\n            foreach ($this->dumpProperties as $property) {\n                if (isset($this->$property)) {\n                    unset($this->$property);\n                }\n            }\n        }\n        // @codeCoverageIgnoreEnd\n\n        return $this;\n    }\n\n    private function getSleepProperties(): array\n    {\n        $properties = $this->dumpProperties;\n\n        // @codeCoverageIgnoreStart\n        if (!\\extension_loaded('msgpack')) {\n            return $properties;\n        }\n\n        if (isset($this->constructedObjectId)) {\n            $this->dumpDateProperties = [\n                'date' => $this->format('Y-m-d H:i:s.u'),\n                'timezone' => serialize($this->timezone ?? null),\n            ];\n\n            $properties[] = 'dumpDateProperties';\n        }\n\n        return $properties;\n        // @codeCoverageIgnoreEnd\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Traits/Test.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Traits;\n\nuse Carbon\\CarbonInterface;\nuse Carbon\\CarbonTimeZone;\nuse Closure;\nuse DateTimeImmutable;\nuse DateTimeInterface;\nuse InvalidArgumentException;\nuse Throwable;\n\ntrait Test\n{\n    ///////////////////////////////////////////////////////////////////\n    ///////////////////////// TESTING AIDS ////////////////////////////\n    ///////////////////////////////////////////////////////////////////\n\n    /**\n     * A test Carbon instance to be returned when now instances are created.\n     *\n     * @var Closure|static|null\n     */\n    protected static $testNow;\n\n    /**\n     * The timezone to resto to when clearing the time mock.\n     *\n     * @var string|null\n     */\n    protected static $testDefaultTimezone;\n\n    /**\n     * Set a Carbon instance (real or mock) to be returned when a \"now\"\n     * instance is created.  The provided instance will be returned\n     * specifically under the following conditions:\n     *   - A call to the static now() method, ex. Carbon::now()\n     *   - When a null (or blank string) is passed to the constructor or parse(), ex. new Carbon(null)\n     *   - When the string \"now\" is passed to the constructor or parse(), ex. new Carbon('now')\n     *   - When a string containing the desired time is passed to Carbon::parse().\n     *\n     * Note the timezone parameter was left out of the examples above and\n     * has no affect as the mock value will be returned regardless of its value.\n     *\n     * Only the moment is mocked with setTestNow(), the timezone will still be the one passed\n     * as parameter of date_default_timezone_get() as a fallback (see setTestNowAndTimezone()).\n     *\n     * To clear the test instance call this method using the default\n     * parameter of null.\n     *\n     * /!\\ Use this method for unit tests only.\n     *\n     * @param DateTimeInterface|Closure|static|string|false|null $testNow real or mock Carbon instance\n     */\n    public static function setTestNow($testNow = null)\n    {\n        static::$testNow = $testNow instanceof self || $testNow instanceof Closure\n            ? $testNow\n            : static::make($testNow);\n    }\n\n    /**\n     * Set a Carbon instance (real or mock) to be returned when a \"now\"\n     * instance is created.  The provided instance will be returned\n     * specifically under the following conditions:\n     *   - A call to the static now() method, ex. Carbon::now()\n     *   - When a null (or blank string) is passed to the constructor or parse(), ex. new Carbon(null)\n     *   - When the string \"now\" is passed to the constructor or parse(), ex. new Carbon('now')\n     *   - When a string containing the desired time is passed to Carbon::parse().\n     *\n     * It will also align default timezone (e.g. call date_default_timezone_set()) with\n     * the second argument or if null, with the timezone of the given date object.\n     *\n     * To clear the test instance call this method using the default\n     * parameter of null.\n     *\n     * /!\\ Use this method for unit tests only.\n     *\n     * @param DateTimeInterface|Closure|static|string|false|null $testNow real or mock Carbon instance\n     */\n    public static function setTestNowAndTimezone($testNow = null, $tz = null)\n    {\n        if ($testNow) {\n            self::$testDefaultTimezone = self::$testDefaultTimezone ?? date_default_timezone_get();\n        }\n\n        $useDateInstanceTimezone = $testNow instanceof DateTimeInterface;\n\n        if ($useDateInstanceTimezone) {\n            self::setDefaultTimezone($testNow->getTimezone()->getName(), $testNow);\n        }\n\n        static::setTestNow($testNow);\n\n        if (!$useDateInstanceTimezone) {\n            $now = static::getMockedTestNow(\\func_num_args() === 1 ? null : $tz);\n            $tzName = $now ? $now->tzName : null;\n            self::setDefaultTimezone($tzName ?? self::$testDefaultTimezone ?? 'UTC', $now);\n        }\n\n        if (!$testNow) {\n            self::$testDefaultTimezone = null;\n        }\n    }\n\n    /**\n     * Temporarily sets a static date to be used within the callback.\n     * Using setTestNow to set the date, executing the callback, then\n     * clearing the test instance.\n     *\n     * /!\\ Use this method for unit tests only.\n     *\n     * @template T\n     *\n     * @param DateTimeInterface|Closure|static|string|false|null $testNow  real or mock Carbon instance\n     * @param Closure(): T                                       $callback\n     *\n     * @return T\n     */\n    public static function withTestNow($testNow, $callback)\n    {\n        static::setTestNow($testNow);\n\n        try {\n            $result = $callback();\n        } finally {\n            static::setTestNow();\n        }\n\n        return $result;\n    }\n\n    /**\n     * Get the Carbon instance (real or mock) to be returned when a \"now\"\n     * instance is created.\n     *\n     * @return Closure|static the current instance used for testing\n     */\n    public static function getTestNow()\n    {\n        return static::$testNow;\n    }\n\n    /**\n     * Determine if there is a valid test instance set. A valid test instance\n     * is anything that is not null.\n     *\n     * @return bool true if there is a test instance, otherwise false\n     */\n    public static function hasTestNow()\n    {\n        return static::getTestNow() !== null;\n    }\n\n    /**\n     * Get the mocked date passed in setTestNow() and if it's a Closure, execute it.\n     *\n     * @param string|\\DateTimeZone $tz\n     *\n     * @return \\Carbon\\CarbonImmutable|\\Carbon\\Carbon|null\n     */\n    protected static function getMockedTestNow($tz)\n    {\n        $testNow = static::getTestNow();\n\n        if ($testNow instanceof Closure) {\n            $realNow = new DateTimeImmutable('now');\n            $testNow = $testNow(static::parse(\n                $realNow->format('Y-m-d H:i:s.u'),\n                $tz ?: $realNow->getTimezone()\n            ));\n        }\n        /* @var \\Carbon\\CarbonImmutable|\\Carbon\\Carbon|null $testNow */\n\n        return $testNow instanceof CarbonInterface\n            ? $testNow->avoidMutation()->tz($tz)\n            : $testNow;\n    }\n\n    protected static function mockConstructorParameters(&$time, $tz)\n    {\n        /** @var \\Carbon\\CarbonImmutable|\\Carbon\\Carbon $testInstance */\n        $testInstance = clone static::getMockedTestNow($tz);\n\n        if (static::hasRelativeKeywords($time)) {\n            $testInstance = $testInstance->modify($time);\n        }\n\n        $time = $testInstance instanceof self\n            ? $testInstance->rawFormat(static::MOCK_DATETIME_FORMAT)\n            : $testInstance->format(static::MOCK_DATETIME_FORMAT);\n    }\n\n    private static function setDefaultTimezone($timezone, ?DateTimeInterface $date = null)\n    {\n        $previous = null;\n        $success = false;\n\n        try {\n            $success = date_default_timezone_set($timezone);\n        } catch (Throwable $exception) {\n            $previous = $exception;\n        }\n\n        if (!$success) {\n            $suggestion = @CarbonTimeZone::create($timezone)->toRegionName($date);\n\n            throw new InvalidArgumentException(\n                \"Timezone ID '$timezone' is invalid\".\n                ($suggestion && $suggestion !== $timezone ? \", did you mean '$suggestion'?\" : '.').\"\\n\".\n                \"It must be one of the IDs from DateTimeZone::listIdentifiers(),\\n\".\n                'For the record, hours/minutes offset are relevant only for a particular moment, '.\n                'but not as a default timezone.',\n                0,\n                $previous\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Traits/Timestamp.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Traits;\n\n/**\n * Trait Timestamp.\n */\ntrait Timestamp\n{\n    /**\n     * Create a Carbon instance from a timestamp and set the timezone (use default one if not specified).\n     *\n     * Timestamp input can be given as int, float or a string containing one or more numbers.\n     *\n     * @param float|int|string          $timestamp\n     * @param \\DateTimeZone|string|null $tz\n     *\n     * @return static\n     */\n    #[\\ReturnTypeWillChange]\n    public static function createFromTimestamp($timestamp, $tz = null)\n    {\n        return static::createFromTimestampUTC($timestamp)->setTimezone($tz);\n    }\n\n    /**\n     * Create a Carbon instance from an timestamp keeping the timezone to UTC.\n     *\n     * Timestamp input can be given as int, float or a string containing one or more numbers.\n     *\n     * @param float|int|string $timestamp\n     *\n     * @return static\n     */\n    public static function createFromTimestampUTC($timestamp)\n    {\n        [$integer, $decimal] = self::getIntegerAndDecimalParts($timestamp);\n        $delta = floor($decimal / static::MICROSECONDS_PER_SECOND);\n        $integer += $delta;\n        $decimal -= $delta * static::MICROSECONDS_PER_SECOND;\n        $decimal = str_pad((string) $decimal, 6, '0', STR_PAD_LEFT);\n\n        return static::rawCreateFromFormat('U u', \"$integer $decimal\");\n    }\n\n    /**\n     * Create a Carbon instance from a timestamp in milliseconds.\n     *\n     * Timestamp input can be given as int, float or a string containing one or more numbers.\n     *\n     * @param float|int|string $timestamp\n     *\n     * @return static\n     */\n    public static function createFromTimestampMsUTC($timestamp)\n    {\n        [$milliseconds, $microseconds] = self::getIntegerAndDecimalParts($timestamp, 3);\n        $sign = $milliseconds < 0 || ($milliseconds === 0.0 && $microseconds < 0) ? -1 : 1;\n        $milliseconds = abs($milliseconds);\n        $microseconds = $sign * abs($microseconds) + static::MICROSECONDS_PER_MILLISECOND * ($milliseconds % static::MILLISECONDS_PER_SECOND);\n        $seconds = $sign * floor($milliseconds / static::MILLISECONDS_PER_SECOND);\n        $delta = floor($microseconds / static::MICROSECONDS_PER_SECOND);\n        $seconds += $delta;\n        $microseconds -= $delta * static::MICROSECONDS_PER_SECOND;\n        $microseconds = str_pad($microseconds, 6, '0', STR_PAD_LEFT);\n\n        return static::rawCreateFromFormat('U u', \"$seconds $microseconds\");\n    }\n\n    /**\n     * Create a Carbon instance from a timestamp in milliseconds.\n     *\n     * Timestamp input can be given as int, float or a string containing one or more numbers.\n     *\n     * @param float|int|string          $timestamp\n     * @param \\DateTimeZone|string|null $tz\n     *\n     * @return static\n     */\n    public static function createFromTimestampMs($timestamp, $tz = null)\n    {\n        return static::createFromTimestampMsUTC($timestamp)\n            ->setTimezone($tz);\n    }\n\n    /**\n     * Set the instance's timestamp.\n     *\n     * Timestamp input can be given as int, float or a string containing one or more numbers.\n     *\n     * @param float|int|string $unixTimestamp\n     *\n     * @return static\n     */\n    public function timestamp($unixTimestamp)\n    {\n        return $this->setTimestamp($unixTimestamp);\n    }\n\n    /**\n     * Returns a timestamp rounded with the given precision (6 by default).\n     *\n     * @example getPreciseTimestamp()   1532087464437474 (microsecond maximum precision)\n     * @example getPreciseTimestamp(6)  1532087464437474\n     * @example getPreciseTimestamp(5)  153208746443747  (1/100000 second precision)\n     * @example getPreciseTimestamp(4)  15320874644375   (1/10000 second precision)\n     * @example getPreciseTimestamp(3)  1532087464437    (millisecond precision)\n     * @example getPreciseTimestamp(2)  153208746444     (1/100 second precision)\n     * @example getPreciseTimestamp(1)  15320874644      (1/10 second precision)\n     * @example getPreciseTimestamp(0)  1532087464       (second precision)\n     * @example getPreciseTimestamp(-1) 153208746        (10 second precision)\n     * @example getPreciseTimestamp(-2) 15320875         (100 second precision)\n     *\n     * @param int $precision\n     *\n     * @return float\n     */\n    public function getPreciseTimestamp($precision = 6)\n    {\n        return round(((float) $this->rawFormat('Uu')) / pow(10, 6 - $precision));\n    }\n\n    /**\n     * Returns the milliseconds timestamps used amongst other by Date javascript objects.\n     *\n     * @return float\n     */\n    public function valueOf()\n    {\n        return $this->getPreciseTimestamp(3);\n    }\n\n    /**\n     * Returns the timestamp with millisecond precision.\n     *\n     * @return int\n     */\n    public function getTimestampMs()\n    {\n        return (int) $this->getPreciseTimestamp(3);\n    }\n\n    /**\n     * @alias getTimestamp\n     *\n     * Returns the UNIX timestamp for the current date.\n     *\n     * @return int\n     */\n    public function unix()\n    {\n        return $this->getTimestamp();\n    }\n\n    /**\n     * Return an array with integer part digits and decimals digits split from one or more positive numbers\n     * (such as timestamps) as string with the given number of decimals (6 by default).\n     *\n     * By splitting integer and decimal, this method obtain a better precision than\n     * number_format when the input is a string.\n     *\n     * @param float|int|string $numbers  one or more numbers\n     * @param int              $decimals number of decimals precision (6 by default)\n     *\n     * @return array 0-index is integer part, 1-index is decimal part digits\n     */\n    private static function getIntegerAndDecimalParts($numbers, $decimals = 6)\n    {\n        if (\\is_int($numbers) || \\is_float($numbers)) {\n            $numbers = number_format($numbers, $decimals, '.', '');\n        }\n\n        $sign = str_starts_with($numbers, '-') ? -1 : 1;\n        $integer = 0;\n        $decimal = 0;\n\n        foreach (preg_split('`[^\\d.]+`', $numbers) as $chunk) {\n            [$integerPart, $decimalPart] = explode('.', \"$chunk.\");\n\n            $integer += (int) $integerPart;\n            $decimal += (float) (\"0.$decimalPart\");\n        }\n\n        $overflow = floor($decimal);\n        $integer += $overflow;\n        $decimal -= $overflow;\n\n        return [$sign * $integer, $decimal === 0.0 ? 0.0 : $sign * round($decimal * pow(10, $decimals))];\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Traits/ToStringFormat.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Traits;\n\nuse Closure;\n\n/**\n * Trait ToStringFormat.\n *\n * Handle global format customization for string cast of the object.\n */\ntrait ToStringFormat\n{\n    /**\n     * Format to use for __toString method when type juggling occurs.\n     *\n     * @var string|Closure|null\n     */\n    protected static $toStringFormat;\n\n    /**\n     * Reset the format used to the default when type juggling a Carbon instance to a string\n     *\n     * @return void\n     */\n    public static function resetToStringFormat()\n    {\n        static::setToStringFormat(null);\n    }\n\n    /**\n     * @deprecated To avoid conflict between different third-party libraries, static setters should not be used.\n     *             You should rather let Carbon object being cast to string with DEFAULT_TO_STRING_FORMAT, and\n     *             use other method or custom format passed to format() method if you need to dump another string\n     *             format.\n     *\n     * Set the default format used when type juggling a Carbon instance to a string.\n     *\n     * @param string|Closure|null $format\n     *\n     * @return void\n     */\n    public static function setToStringFormat($format)\n    {\n        static::$toStringFormat = $format;\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Traits/Units.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Traits;\n\nuse Carbon\\CarbonConverterInterface;\nuse Carbon\\CarbonInterface;\nuse Carbon\\CarbonInterval;\nuse Carbon\\Exceptions\\UnitException;\nuse Closure;\nuse DateInterval;\nuse DateMalformedStringException;\nuse ReturnTypeWillChange;\n\n/**\n * Trait Units.\n *\n * Add, subtract and set units.\n */\ntrait Units\n{\n    /**\n     * Add seconds to the instance using timestamp. Positive $value travels\n     * forward while negative $value travels into the past.\n     *\n     * @param string $unit\n     * @param int    $value\n     *\n     * @return static\n     */\n    public function addRealUnit($unit, $value = 1)\n    {\n        switch ($unit) {\n            // @call addRealUnit\n            case 'micro':\n\n            // @call addRealUnit\n            case 'microsecond':\n                /* @var CarbonInterface $this */\n                $diff = $this->microsecond + $value;\n                $time = $this->getTimestamp();\n                $seconds = (int) floor($diff / static::MICROSECONDS_PER_SECOND);\n                $time += $seconds;\n                $diff -= $seconds * static::MICROSECONDS_PER_SECOND;\n                $microtime = str_pad((string) $diff, 6, '0', STR_PAD_LEFT);\n                $tz = $this->tz;\n\n                return $this->tz('UTC')->modify(\"@$time.$microtime\")->tz($tz);\n\n            // @call addRealUnit\n            case 'milli':\n            // @call addRealUnit\n            case 'millisecond':\n                return $this->addRealUnit('microsecond', $value * static::MICROSECONDS_PER_MILLISECOND);\n\n            // @call addRealUnit\n            case 'second':\n                break;\n\n            // @call addRealUnit\n            case 'minute':\n                $value *= static::SECONDS_PER_MINUTE;\n\n                break;\n\n            // @call addRealUnit\n            case 'hour':\n                $value *= static::MINUTES_PER_HOUR * static::SECONDS_PER_MINUTE;\n\n                break;\n\n            // @call addRealUnit\n            case 'day':\n                $value *= static::HOURS_PER_DAY * static::MINUTES_PER_HOUR * static::SECONDS_PER_MINUTE;\n\n                break;\n\n            // @call addRealUnit\n            case 'week':\n                $value *= static::DAYS_PER_WEEK * static::HOURS_PER_DAY * static::MINUTES_PER_HOUR * static::SECONDS_PER_MINUTE;\n\n                break;\n\n            // @call addRealUnit\n            case 'month':\n                $value *= 30 * static::HOURS_PER_DAY * static::MINUTES_PER_HOUR * static::SECONDS_PER_MINUTE;\n\n                break;\n\n            // @call addRealUnit\n            case 'quarter':\n                $value *= static::MONTHS_PER_QUARTER * 30 * static::HOURS_PER_DAY * static::MINUTES_PER_HOUR * static::SECONDS_PER_MINUTE;\n\n                break;\n\n            // @call addRealUnit\n            case 'year':\n                $value *= 365 * static::HOURS_PER_DAY * static::MINUTES_PER_HOUR * static::SECONDS_PER_MINUTE;\n\n                break;\n\n            // @call addRealUnit\n            case 'decade':\n                $value *= static::YEARS_PER_DECADE * 365 * static::HOURS_PER_DAY * static::MINUTES_PER_HOUR * static::SECONDS_PER_MINUTE;\n\n                break;\n\n            // @call addRealUnit\n            case 'century':\n                $value *= static::YEARS_PER_CENTURY * 365 * static::HOURS_PER_DAY * static::MINUTES_PER_HOUR * static::SECONDS_PER_MINUTE;\n\n                break;\n\n            // @call addRealUnit\n            case 'millennium':\n                $value *= static::YEARS_PER_MILLENNIUM * 365 * static::HOURS_PER_DAY * static::MINUTES_PER_HOUR * static::SECONDS_PER_MINUTE;\n\n                break;\n\n            default:\n                if ($this->localStrictModeEnabled ?? static::isStrictModeEnabled()) {\n                    throw new UnitException(\"Invalid unit for real timestamp add/sub: '$unit'\");\n                }\n\n                return $this;\n        }\n\n        /* @var CarbonInterface $this */\n        return $this->setTimestamp((int) ($this->getTimestamp() + $value));\n    }\n\n    public function subRealUnit($unit, $value = 1)\n    {\n        return $this->addRealUnit($unit, -$value);\n    }\n\n    /**\n     * Returns true if a property can be changed via setter.\n     *\n     * @param string $unit\n     *\n     * @return bool\n     */\n    public static function isModifiableUnit($unit)\n    {\n        static $modifiableUnits = [\n            // @call addUnit\n            'millennium',\n            // @call addUnit\n            'century',\n            // @call addUnit\n            'decade',\n            // @call addUnit\n            'quarter',\n            // @call addUnit\n            'week',\n            // @call addUnit\n            'weekday',\n        ];\n\n        return \\in_array($unit, $modifiableUnits, true) || \\in_array($unit, static::$units, true);\n    }\n\n    /**\n     * Call native PHP DateTime/DateTimeImmutable add() method.\n     *\n     * @param DateInterval $interval\n     *\n     * @return static\n     */\n    public function rawAdd(DateInterval $interval)\n    {\n        return parent::add($interval);\n    }\n\n    /**\n     * Add given units or interval to the current instance.\n     *\n     * @example $date->add('hour', 3)\n     * @example $date->add(15, 'days')\n     * @example $date->add(CarbonInterval::days(4))\n     *\n     * @param string|DateInterval|Closure|CarbonConverterInterface $unit\n     * @param int                                                  $value\n     * @param bool|null                                            $overflow\n     *\n     * @return static\n     */\n    #[ReturnTypeWillChange]\n    public function add($unit, $value = 1, $overflow = null)\n    {\n        if (\\is_string($unit) && \\func_num_args() === 1) {\n            $unit = CarbonInterval::make($unit, [], true);\n        }\n\n        if ($unit instanceof CarbonConverterInterface) {\n            return $this->resolveCarbon($unit->convertDate($this, false));\n        }\n\n        if ($unit instanceof Closure) {\n            return $this->resolveCarbon($unit($this, false));\n        }\n\n        if ($unit instanceof DateInterval) {\n            return parent::add($unit);\n        }\n\n        if (is_numeric($unit)) {\n            [$value, $unit] = [$unit, $value];\n        }\n\n        return $this->addUnit($unit, $value, $overflow);\n    }\n\n    /**\n     * Add given units to the current instance.\n     *\n     * @param string    $unit\n     * @param int       $value\n     * @param bool|null $overflow\n     *\n     * @return static\n     */\n    public function addUnit($unit, $value = 1, $overflow = null)\n    {\n        $originalArgs = \\func_get_args();\n\n        $date = $this;\n\n        if (!is_numeric($value) || !(float) $value) {\n            return $date->isMutable() ? $date : $date->avoidMutation();\n        }\n\n        $unit = self::singularUnit($unit);\n        $metaUnits = [\n            'millennium' => [static::YEARS_PER_MILLENNIUM, 'year'],\n            'century' => [static::YEARS_PER_CENTURY, 'year'],\n            'decade' => [static::YEARS_PER_DECADE, 'year'],\n            'quarter' => [static::MONTHS_PER_QUARTER, 'month'],\n        ];\n\n        if (isset($metaUnits[$unit])) {\n            [$factor, $unit] = $metaUnits[$unit];\n            $value *= $factor;\n        }\n\n        if ($unit === 'weekday') {\n            $weekendDays = static::getWeekendDays();\n\n            if ($weekendDays !== [static::SATURDAY, static::SUNDAY]) {\n                $absoluteValue = abs($value);\n                $sign = $value / max(1, $absoluteValue);\n                $weekDaysCount = 7 - min(6, \\count(array_unique($weekendDays)));\n                $weeks = floor($absoluteValue / $weekDaysCount);\n\n                for ($diff = $absoluteValue % $weekDaysCount; $diff; $diff--) {\n                    /** @var static $date */\n                    $date = $date->addDays($sign);\n\n                    while (\\in_array($date->dayOfWeek, $weekendDays, true)) {\n                        $date = $date->addDays($sign);\n                    }\n                }\n\n                $value = $weeks * $sign;\n                $unit = 'week';\n            }\n\n            $timeString = $date->toTimeString();\n        } elseif ($canOverflow = (\\in_array($unit, [\n                'month',\n                'year',\n            ]) && ($overflow === false || (\n                $overflow === null &&\n                ($ucUnit = ucfirst($unit).'s') &&\n                !($this->{'local'.$ucUnit.'Overflow'} ?? static::{'shouldOverflow'.$ucUnit}())\n            )))) {\n            $day = $date->day;\n        }\n\n        $value = (int) $value;\n\n        if ($unit === 'milli' || $unit === 'millisecond') {\n            $unit = 'microsecond';\n            $value *= static::MICROSECONDS_PER_MILLISECOND;\n        }\n\n        // Work-around for bug https://bugs.php.net/bug.php?id=75642\n        if ($unit === 'micro' || $unit === 'microsecond') {\n            $microseconds = $this->micro + $value;\n            $second = (int) floor($microseconds / static::MICROSECONDS_PER_SECOND);\n            $microseconds %= static::MICROSECONDS_PER_SECOND;\n            if ($microseconds < 0) {\n                $microseconds += static::MICROSECONDS_PER_SECOND;\n            }\n            $date = $date->microseconds($microseconds);\n            $unit = 'second';\n            $value = $second;\n        }\n\n        try {\n            $date = $date->modify(\"$value $unit\");\n\n            if (isset($timeString)) {\n                $date = $date->setTimeFromTimeString($timeString);\n            } elseif (isset($canOverflow, $day) && $canOverflow && $day !== $date->day) {\n                $date = $date->modify('last day of previous month');\n            }\n        } catch (DateMalformedStringException $ignoredException) { // @codeCoverageIgnore\n            $date = null; // @codeCoverageIgnore\n        }\n\n        if (!$date) {\n            throw new UnitException('Unable to add unit '.var_export($originalArgs, true));\n        }\n\n        return $date;\n    }\n\n    /**\n     * Subtract given units to the current instance.\n     *\n     * @param string    $unit\n     * @param int       $value\n     * @param bool|null $overflow\n     *\n     * @return static\n     */\n    public function subUnit($unit, $value = 1, $overflow = null)\n    {\n        return $this->addUnit($unit, -$value, $overflow);\n    }\n\n    /**\n     * Call native PHP DateTime/DateTimeImmutable sub() method.\n     *\n     * @param DateInterval $interval\n     *\n     * @return static\n     */\n    public function rawSub(DateInterval $interval)\n    {\n        return parent::sub($interval);\n    }\n\n    /**\n     * Subtract given units or interval to the current instance.\n     *\n     * @example $date->sub('hour', 3)\n     * @example $date->sub(15, 'days')\n     * @example $date->sub(CarbonInterval::days(4))\n     *\n     * @param string|DateInterval|Closure|CarbonConverterInterface $unit\n     * @param int                                                  $value\n     * @param bool|null                                            $overflow\n     *\n     * @return static\n     */\n    #[ReturnTypeWillChange]\n    public function sub($unit, $value = 1, $overflow = null)\n    {\n        if (\\is_string($unit) && \\func_num_args() === 1) {\n            $unit = CarbonInterval::make($unit, [], true);\n        }\n\n        if ($unit instanceof CarbonConverterInterface) {\n            return $this->resolveCarbon($unit->convertDate($this, true));\n        }\n\n        if ($unit instanceof Closure) {\n            return $this->resolveCarbon($unit($this, true));\n        }\n\n        if ($unit instanceof DateInterval) {\n            return parent::sub($unit);\n        }\n\n        if (is_numeric($unit)) {\n            [$value, $unit] = [$unit, $value];\n        }\n\n        return $this->addUnit($unit, -(float) $value, $overflow);\n    }\n\n    /**\n     * Subtract given units or interval to the current instance.\n     *\n     * @see sub()\n     *\n     * @param string|DateInterval $unit\n     * @param int                 $value\n     * @param bool|null           $overflow\n     *\n     * @return static\n     */\n    public function subtract($unit, $value = 1, $overflow = null)\n    {\n        if (\\is_string($unit) && \\func_num_args() === 1) {\n            $unit = CarbonInterval::make($unit, [], true);\n        }\n\n        return $this->sub($unit, $value, $overflow);\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Traits/Week.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon\\Traits;\n\n/**\n * Trait Week.\n *\n * week and ISO week number, year and count in year.\n *\n * Depends on the following properties:\n *\n * @property int $daysInYear\n * @property int $dayOfWeek\n * @property int $dayOfYear\n * @property int $year\n *\n * Depends on the following methods:\n *\n * @method static addWeeks(int $weeks = 1)\n * @method static copy()\n * @method static dayOfYear(int $dayOfYear)\n * @method string getTranslationMessage(string $key, ?string $locale = null, ?string $default = null, $translator = null)\n * @method static next(int|string $day = null)\n * @method static startOfWeek(int $day = 1)\n * @method static subWeeks(int $weeks = 1)\n * @method static year(int $year = null)\n */\ntrait Week\n{\n    /**\n     * Set/get the week number of year using given first day of week and first\n     * day of year included in the first week. Or use ISO format if no settings\n     * given.\n     *\n     * @param int|null $year      if null, act as a getter, if not null, set the year and return current instance.\n     * @param int|null $dayOfWeek first date of week from 0 (Sunday) to 6 (Saturday)\n     * @param int|null $dayOfYear first day of year included in the week #1\n     *\n     * @return int|static\n     */\n    public function isoWeekYear($year = null, $dayOfWeek = null, $dayOfYear = null)\n    {\n        return $this->weekYear(\n            $year,\n            $dayOfWeek ?? 1,\n            $dayOfYear ?? 4\n        );\n    }\n\n    /**\n     * Set/get the week number of year using given first day of week and first\n     * day of year included in the first week. Or use US format if no settings\n     * given (Sunday / Jan 6).\n     *\n     * @param int|null $year      if null, act as a getter, if not null, set the year and return current instance.\n     * @param int|null $dayOfWeek first date of week from 0 (Sunday) to 6 (Saturday)\n     * @param int|null $dayOfYear first day of year included in the week #1\n     *\n     * @return int|static\n     */\n    public function weekYear($year = null, $dayOfWeek = null, $dayOfYear = null)\n    {\n        $dayOfWeek = $dayOfWeek ?? $this->getTranslationMessage('first_day_of_week') ?? 0;\n        $dayOfYear = $dayOfYear ?? $this->getTranslationMessage('day_of_first_week_of_year') ?? 1;\n\n        if ($year !== null) {\n            $year = (int) round($year);\n\n            if ($this->weekYear(null, $dayOfWeek, $dayOfYear) === $year) {\n                return $this->avoidMutation();\n            }\n\n            $week = $this->week(null, $dayOfWeek, $dayOfYear);\n            $day = $this->dayOfWeek;\n            $date = $this->year($year);\n            switch ($date->weekYear(null, $dayOfWeek, $dayOfYear) - $year) {\n                case 1:\n                    $date = $date->subWeeks(26);\n\n                    break;\n                case -1:\n                    $date = $date->addWeeks(26);\n\n                    break;\n            }\n\n            $date = $date->addWeeks($week - $date->week(null, $dayOfWeek, $dayOfYear))->startOfWeek($dayOfWeek);\n\n            if ($date->dayOfWeek === $day) {\n                return $date;\n            }\n\n            return $date->next($day);\n        }\n\n        $year = $this->year;\n        $day = $this->dayOfYear;\n        $date = $this->avoidMutation()->dayOfYear($dayOfYear)->startOfWeek($dayOfWeek);\n\n        if ($date->year === $year && $day < $date->dayOfYear) {\n            return $year - 1;\n        }\n\n        $date = $this->avoidMutation()->addYear()->dayOfYear($dayOfYear)->startOfWeek($dayOfWeek);\n\n        if ($date->year === $year && $day >= $date->dayOfYear) {\n            return $year + 1;\n        }\n\n        return $year;\n    }\n\n    /**\n     * Get the number of weeks of the current week-year using given first day of week and first\n     * day of year included in the first week. Or use ISO format if no settings\n     * given.\n     *\n     * @param int|null $dayOfWeek first date of week from 0 (Sunday) to 6 (Saturday)\n     * @param int|null $dayOfYear first day of year included in the week #1\n     *\n     * @return int\n     */\n    public function isoWeeksInYear($dayOfWeek = null, $dayOfYear = null)\n    {\n        return $this->weeksInYear(\n            $dayOfWeek ?? 1,\n            $dayOfYear ?? 4\n        );\n    }\n\n    /**\n     * Get the number of weeks of the current week-year using given first day of week and first\n     * day of year included in the first week. Or use US format if no settings\n     * given (Sunday / Jan 6).\n     *\n     * @param int|null $dayOfWeek first date of week from 0 (Sunday) to 6 (Saturday)\n     * @param int|null $dayOfYear first day of year included in the week #1\n     *\n     * @return int\n     */\n    public function weeksInYear($dayOfWeek = null, $dayOfYear = null)\n    {\n        $dayOfWeek = $dayOfWeek ?? $this->getTranslationMessage('first_day_of_week') ?? 0;\n        $dayOfYear = $dayOfYear ?? $this->getTranslationMessage('day_of_first_week_of_year') ?? 1;\n        $year = $this->year;\n        $start = $this->avoidMutation()->dayOfYear($dayOfYear)->startOfWeek($dayOfWeek);\n        $startDay = $start->dayOfYear;\n        if ($start->year !== $year) {\n            $startDay -= $start->daysInYear;\n        }\n        $end = $this->avoidMutation()->addYear()->dayOfYear($dayOfYear)->startOfWeek($dayOfWeek);\n        $endDay = $end->dayOfYear;\n        if ($end->year !== $year) {\n            $endDay += $this->daysInYear;\n        }\n\n        return (int) round(($endDay - $startDay) / 7);\n    }\n\n    /**\n     * Get/set the week number using given first day of week and first\n     * day of year included in the first week. Or use US format if no settings\n     * given (Sunday / Jan 6).\n     *\n     * @param int|null $week\n     * @param int|null $dayOfWeek\n     * @param int|null $dayOfYear\n     *\n     * @return int|static\n     */\n    public function week($week = null, $dayOfWeek = null, $dayOfYear = null)\n    {\n        $date = $this;\n        $dayOfWeek = $dayOfWeek ?? $this->getTranslationMessage('first_day_of_week') ?? 0;\n        $dayOfYear = $dayOfYear ?? $this->getTranslationMessage('day_of_first_week_of_year') ?? 1;\n\n        if ($week !== null) {\n            return $date->addWeeks(round($week) - $this->week(null, $dayOfWeek, $dayOfYear));\n        }\n\n        $start = $date->avoidMutation()->dayOfYear($dayOfYear)->startOfWeek($dayOfWeek);\n        $end = $date->avoidMutation()->startOfWeek($dayOfWeek);\n        if ($start > $end) {\n            $start = $start->subWeeks(26)->dayOfYear($dayOfYear)->startOfWeek($dayOfWeek);\n        }\n        $week = (int) ($start->diffInDays($end) / 7 + 1);\n\n        return $week > $end->weeksInYear($dayOfWeek, $dayOfYear) ? 1 : $week;\n    }\n\n    /**\n     * Get/set the week number using given first day of week and first\n     * day of year included in the first week. Or use ISO format if no settings\n     * given.\n     *\n     * @param int|null $week\n     * @param int|null $dayOfWeek\n     * @param int|null $dayOfYear\n     *\n     * @return int|static\n     */\n    public function isoWeek($week = null, $dayOfWeek = null, $dayOfYear = null)\n    {\n        return $this->week(\n            $week,\n            $dayOfWeek ?? 1,\n            $dayOfYear ?? 4\n        );\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/Translator.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon;\n\nuse ReflectionMethod;\nuse Symfony\\Component\\Translation;\nuse Symfony\\Contracts\\Translation\\TranslatorInterface;\n\n$transMethod = new ReflectionMethod(\n    class_exists(TranslatorInterface::class)\n        ? TranslatorInterface::class\n        : Translation\\Translator::class,\n    'trans'\n);\n\nrequire $transMethod->hasReturnType()\n    ? __DIR__.'/../../lazy/Carbon/TranslatorStrongType.php'\n    : __DIR__.'/../../lazy/Carbon/TranslatorWeakType.php';\n\nclass Translator extends LazyTranslator\n{\n    // Proxy dynamically loaded LazyTranslator in a static way\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/TranslatorImmutable.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon;\n\nuse Carbon\\Exceptions\\ImmutableException;\nuse Symfony\\Component\\Config\\ConfigCacheFactoryInterface;\nuse Symfony\\Component\\Translation\\Formatter\\MessageFormatterInterface;\n\nclass TranslatorImmutable extends Translator\n{\n    /** @var bool */\n    private $constructed = false;\n\n    public function __construct($locale, ?MessageFormatterInterface $formatter = null, $cacheDir = null, $debug = false)\n    {\n        parent::__construct($locale, $formatter, $cacheDir, $debug);\n        $this->constructed = true;\n    }\n\n    /**\n     * @codeCoverageIgnore\n     */\n    public function setDirectories(array $directories)\n    {\n        $this->disallowMutation(__METHOD__);\n\n        return parent::setDirectories($directories);\n    }\n\n    public function setLocale($locale)\n    {\n        $this->disallowMutation(__METHOD__);\n\n        return parent::setLocale($locale);\n    }\n\n    /**\n     * @codeCoverageIgnore\n     */\n    public function setMessages($locale, $messages)\n    {\n        $this->disallowMutation(__METHOD__);\n\n        return parent::setMessages($locale, $messages);\n    }\n\n    /**\n     * @codeCoverageIgnore\n     */\n    public function setTranslations($messages)\n    {\n        $this->disallowMutation(__METHOD__);\n\n        return parent::setTranslations($messages);\n    }\n\n    /**\n     * @codeCoverageIgnore\n     */\n    public function setConfigCacheFactory(ConfigCacheFactoryInterface $configCacheFactory): void\n    {\n        $this->disallowMutation(__METHOD__);\n\n        parent::setConfigCacheFactory($configCacheFactory);\n    }\n\n    public function resetMessages($locale = null)\n    {\n        $this->disallowMutation(__METHOD__);\n\n        return parent::resetMessages($locale);\n    }\n\n    /**\n     * @codeCoverageIgnore\n     */\n    public function setFallbackLocales(array $locales)\n    {\n        $this->disallowMutation(__METHOD__);\n\n        parent::setFallbackLocales($locales);\n    }\n\n    private function disallowMutation($method)\n    {\n        if ($this->constructed) {\n            throw new ImmutableException($method.' not allowed on '.static::class);\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/nesbot/carbon/src/Carbon/TranslatorStrongTypeInterface.php",
    "content": "<?php\n\n/**\n * This file is part of the Carbon package.\n *\n * (c) Brian Nesbitt <brian@nesbot.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Carbon;\n\nuse Symfony\\Component\\Translation\\MessageCatalogueInterface;\n\n/**\n * Mark translator using strong type from symfony/translation >= 6.\n */\ninterface TranslatorStrongTypeInterface\n{\n    public function getFromCatalogue(MessageCatalogueInterface $catalogue, string $id, string $domain = 'messages');\n}\n"
  },
  {
    "path": "server/vendor/nikic/fast-route/.gitignore",
    "content": "/vendor/\n.idea/\n\n# ignore lock file since we have no extra dependencies\ncomposer.lock\n"
  },
  {
    "path": "server/vendor/nikic/fast-route/.hhconfig",
    "content": "assume_php=false\n"
  },
  {
    "path": "server/vendor/nikic/fast-route/.travis.yml",
    "content": "sudo: false\nlanguage: php\n\nphp:\n  - 5.4\n  - 5.5\n  - 5.6\n  - 7.0\n  - 7.1\n  - 7.2\n  - hhvm\n\nscript:\n  - ./vendor/bin/phpunit\n\nbefore_install:\n  - travis_retry composer self-update\n\ninstall:\n  - composer install\n"
  },
  {
    "path": "server/vendor/nikic/fast-route/FastRoute.hhi",
    "content": "<?hh // decl\n\nnamespace FastRoute {\n    class BadRouteException extends \\LogicException {\n    }\n\n    interface RouteParser {\n        public function parse(string $route): array<array>;\n    }\n\n    class RouteCollector {\n        public function __construct(RouteParser $routeParser, DataGenerator $dataGenerator);\n        public function addRoute(mixed $httpMethod, string $route, mixed $handler): void;\n        public function getData(): array;\n    }\n\n    class Route {\n        public function __construct(string $httpMethod, mixed $handler, string $regex, array $variables);\n        public function matches(string $str): bool;\n    }\n\n    interface DataGenerator {\n        public function addRoute(string $httpMethod, array $routeData, mixed $handler);\n        public function getData(): array;\n    }\n\n    interface Dispatcher {\n        const int NOT_FOUND = 0;\n        const int FOUND = 1;\n        const int METHOD_NOT_ALLOWED = 2;\n        public function dispatch(string $httpMethod, string $uri): array;\n    }\n\n    function simpleDispatcher(\n        (function(RouteCollector): void) $routeDefinitionCallback,\n        shape(\n          ?'routeParser' => classname<RouteParser>,\n          ?'dataGenerator' => classname<DataGenerator>,\n          ?'dispatcher' => classname<Dispatcher>,\n          ?'routeCollector' => classname<RouteCollector>,\n        ) $options = shape()): Dispatcher;\n\n    function cachedDispatcher(\n        (function(RouteCollector): void) $routeDefinitionCallback,\n        shape(\n          ?'routeParser' => classname<RouteParser>,\n          ?'dataGenerator' => classname<DataGenerator>,\n          ?'dispatcher' => classname<Dispatcher>,\n          ?'routeCollector' => classname<RouteCollector>,\n          ?'cacheDisabled' => bool,\n          ?'cacheFile' => string,\n        ) $options = shape()): Dispatcher;\n}\n\nnamespace FastRoute\\DataGenerator {\n    abstract class RegexBasedAbstract implements \\FastRoute\\DataGenerator {\n        protected abstract function getApproxChunkSize();\n        protected abstract function processChunk($regexToRoutesMap);\n\n        public function addRoute(string $httpMethod, array $routeData, mixed $handler): void;\n        public function getData(): array;\n    }\n\n    class CharCountBased extends RegexBasedAbstract {\n        protected function getApproxChunkSize(): int;\n        protected function processChunk(array<string, string> $regexToRoutesMap): array<string, mixed>;\n    }\n\n    class GroupCountBased extends RegexBasedAbstract {\n        protected function getApproxChunkSize(): int;\n        protected function processChunk(array<string, string> $regexToRoutesMap): array<string, mixed>;\n    }\n\n    class GroupPosBased extends RegexBasedAbstract {\n        protected function getApproxChunkSize(): int;\n        protected function processChunk(array<string, string> $regexToRoutesMap): array<string, mixed>;\n    }\n\n    class MarkBased extends RegexBasedAbstract {\n        protected function getApproxChunkSize(): int;\n        protected function processChunk(array<string, string> $regexToRoutesMap): array<string, mixed>;\n    }\n}\n\nnamespace FastRoute\\Dispatcher {\n    abstract class RegexBasedAbstract implements \\FastRoute\\Dispatcher {\n        protected abstract function dispatchVariableRoute(array<array> $routeData, string $uri): array;\n\n        public function dispatch(string $httpMethod, string $uri): array;\n    }\n\n    class GroupPosBased extends RegexBasedAbstract {\n        public function __construct(array $data);\n        protected function dispatchVariableRoute(array<array> $routeData, string $uri): array;\n    }\n\n    class GroupCountBased extends RegexBasedAbstract {\n        public function __construct(array $data);\n        protected function dispatchVariableRoute(array<array> $routeData, string $uri): array;\n    }\n\n    class CharCountBased extends RegexBasedAbstract {\n        public function __construct(array $data);\n        protected function dispatchVariableRoute(array<array> $routeData, string $uri): array;\n    }\n\n    class MarkBased extends RegexBasedAbstract {\n        public function __construct(array $data);\n        protected function dispatchVariableRoute(array<array> $routeData, string $uri): array;\n    }\n}\n\nnamespace FastRoute\\RouteParser {\n    class Std implements \\FastRoute\\RouteParser {\n        const string VARIABLE_REGEX = <<<'REGEX'\n\\{\n    \\s* ([a-zA-Z][a-zA-Z0-9_]*) \\s*\n    (?:\n        : \\s* ([^{}]*(?:\\{(?-1)\\}[^{}]*)*)\n    )?\n\\}\nREGEX;\n        const string DEFAULT_DISPATCH_REGEX = '[^/]+';\n        public function parse(string $route): array<array>;\n    }\n}\n"
  },
  {
    "path": "server/vendor/nikic/fast-route/LICENSE",
    "content": "Copyright (c) 2013 by Nikita Popov.\n\nSome rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n    * Redistributions of source code must retain the above copyright\n      notice, this list of conditions and the following disclaimer.\n\n    * Redistributions in binary form must reproduce the above\n      copyright notice, this list of conditions and the following\n      disclaimer in the documentation and/or other materials provided\n      with the distribution.\n\n    * The names of the contributors may not be used to endorse or\n      promote products derived from this software without specific\n      prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "server/vendor/nikic/fast-route/README.md",
    "content": "FastRoute - Fast request router for PHP\n=======================================\n\nThis library provides a fast implementation of a regular expression based router. [Blog post explaining how the\nimplementation works and why it is fast.][blog_post]\n\nInstall\n-------\n\nTo install with composer:\n\n```sh\ncomposer require nikic/fast-route\n```\n\nRequires PHP 5.4 or newer.\n\nUsage\n-----\n\nHere's a basic usage example:\n\n```php\n<?php\n\nrequire '/path/to/vendor/autoload.php';\n\n$dispatcher = FastRoute\\simpleDispatcher(function(FastRoute\\RouteCollector $r) {\n    $r->addRoute('GET', '/users', 'get_all_users_handler');\n    // {id} must be a number (\\d+)\n    $r->addRoute('GET', '/user/{id:\\d+}', 'get_user_handler');\n    // The /{title} suffix is optional\n    $r->addRoute('GET', '/articles/{id:\\d+}[/{title}]', 'get_article_handler');\n});\n\n// Fetch method and URI from somewhere\n$httpMethod = $_SERVER['REQUEST_METHOD'];\n$uri = $_SERVER['REQUEST_URI'];\n\n// Strip query string (?foo=bar) and decode URI\nif (false !== $pos = strpos($uri, '?')) {\n    $uri = substr($uri, 0, $pos);\n}\n$uri = rawurldecode($uri);\n\n$routeInfo = $dispatcher->dispatch($httpMethod, $uri);\nswitch ($routeInfo[0]) {\n    case FastRoute\\Dispatcher::NOT_FOUND:\n        // ... 404 Not Found\n        break;\n    case FastRoute\\Dispatcher::METHOD_NOT_ALLOWED:\n        $allowedMethods = $routeInfo[1];\n        // ... 405 Method Not Allowed\n        break;\n    case FastRoute\\Dispatcher::FOUND:\n        $handler = $routeInfo[1];\n        $vars = $routeInfo[2];\n        // ... call $handler with $vars\n        break;\n}\n```\n\n### Defining routes\n\nThe routes are defined by calling the `FastRoute\\simpleDispatcher()` function, which accepts\na callable taking a `FastRoute\\RouteCollector` instance. The routes are added by calling\n`addRoute()` on the collector instance:\n\n```php\n$r->addRoute($method, $routePattern, $handler);\n```\n\nThe `$method` is an uppercase HTTP method string for which a certain route should match. It\nis possible to specify multiple valid methods using an array:\n\n```php\n// These two calls\n$r->addRoute('GET', '/test', 'handler');\n$r->addRoute('POST', '/test', 'handler');\n// Are equivalent to this one call\n$r->addRoute(['GET', 'POST'], '/test', 'handler');\n```\n\nBy default the `$routePattern` uses a syntax where `{foo}` specifies a placeholder with name `foo`\nand matching the regex `[^/]+`. To adjust the pattern the placeholder matches, you can specify\na custom pattern by writing `{bar:[0-9]+}`. Some examples:\n\n```php\n// Matches /user/42, but not /user/xyz\n$r->addRoute('GET', '/user/{id:\\d+}', 'handler');\n\n// Matches /user/foobar, but not /user/foo/bar\n$r->addRoute('GET', '/user/{name}', 'handler');\n\n// Matches /user/foo/bar as well\n$r->addRoute('GET', '/user/{name:.+}', 'handler');\n```\n\nCustom patterns for route placeholders cannot use capturing groups. For example `{lang:(en|de)}`\nis not a valid placeholder, because `()` is a capturing group. Instead you can use either\n`{lang:en|de}` or `{lang:(?:en|de)}`.\n\nFurthermore parts of the route enclosed in `[...]` are considered optional, so that `/foo[bar]`\nwill match both `/foo` and `/foobar`. Optional parts are only supported in a trailing position,\nnot in the middle of a route.\n\n```php\n// This route\n$r->addRoute('GET', '/user/{id:\\d+}[/{name}]', 'handler');\n// Is equivalent to these two routes\n$r->addRoute('GET', '/user/{id:\\d+}', 'handler');\n$r->addRoute('GET', '/user/{id:\\d+}/{name}', 'handler');\n\n// Multiple nested optional parts are possible as well\n$r->addRoute('GET', '/user[/{id:\\d+}[/{name}]]', 'handler');\n\n// This route is NOT valid, because optional parts can only occur at the end\n$r->addRoute('GET', '/user[/{id:\\d+}]/{name}', 'handler');\n```\n\nThe `$handler` parameter does not necessarily have to be a callback, it could also be a controller\nclass name or any other kind of data you wish to associate with the route. FastRoute only tells you\nwhich handler corresponds to your URI, how you interpret it is up to you.\n\n#### Shorcut methods for common request methods\n\nFor the `GET`, `POST`, `PUT`, `PATCH`, `DELETE` and `HEAD` request methods shortcut methods are available. For example:\n\n```php\n$r->get('/get-route', 'get_handler');\n$r->post('/post-route', 'post_handler');\n```\n\nIs equivalent to:\n\n```php\n$r->addRoute('GET', '/get-route', 'get_handler');\n$r->addRoute('POST', '/post-route', 'post_handler');\n```\n\n#### Route Groups\n\nAdditionally, you can specify routes inside of a group. All routes defined inside a group will have a common prefix.\n\nFor example, defining your routes as:\n\n```php\n$r->addGroup('/admin', function (RouteCollector $r) {\n    $r->addRoute('GET', '/do-something', 'handler');\n    $r->addRoute('GET', '/do-another-thing', 'handler');\n    $r->addRoute('GET', '/do-something-else', 'handler');\n});\n```\n\nWill have the same result as:\n\n ```php\n$r->addRoute('GET', '/admin/do-something', 'handler');\n$r->addRoute('GET', '/admin/do-another-thing', 'handler');\n$r->addRoute('GET', '/admin/do-something-else', 'handler');\n ```\n\nNested groups are also supported, in which case the prefixes of all the nested groups are combined.\n\n### Caching\n\nThe reason `simpleDispatcher` accepts a callback for defining the routes is to allow seamless\ncaching. By using `cachedDispatcher` instead of `simpleDispatcher` you can cache the generated\nrouting data and construct the dispatcher from the cached information:\n\n```php\n<?php\n\n$dispatcher = FastRoute\\cachedDispatcher(function(FastRoute\\RouteCollector $r) {\n    $r->addRoute('GET', '/user/{name}/{id:[0-9]+}', 'handler0');\n    $r->addRoute('GET', '/user/{id:[0-9]+}', 'handler1');\n    $r->addRoute('GET', '/user/{name}', 'handler2');\n}, [\n    'cacheFile' => __DIR__ . '/route.cache', /* required */\n    'cacheDisabled' => IS_DEBUG_ENABLED,     /* optional, enabled by default */\n]);\n```\n\nThe second parameter to the function is an options array, which can be used to specify the cache\nfile location, among other things.\n\n### Dispatching a URI\n\nA URI is dispatched by calling the `dispatch()` method of the created dispatcher. This method\naccepts the HTTP method and a URI. Getting those two bits of information (and normalizing them\nappropriately) is your job - this library is not bound to the PHP web SAPIs.\n\nThe `dispatch()` method returns an array whose first element contains a status code. It is one\nof `Dispatcher::NOT_FOUND`, `Dispatcher::METHOD_NOT_ALLOWED` and `Dispatcher::FOUND`. For the\nmethod not allowed status the second array element contains a list of HTTP methods allowed for\nthe supplied URI. For example:\n\n    [FastRoute\\Dispatcher::METHOD_NOT_ALLOWED, ['GET', 'POST']]\n\n> **NOTE:** The HTTP specification requires that a `405 Method Not Allowed` response include the\n`Allow:` header to detail available methods for the requested resource. Applications using FastRoute\nshould use the second array element to add this header when relaying a 405 response.\n\nFor the found status the second array element is the handler that was associated with the route\nand the third array element is a dictionary of placeholder names to their values. For example:\n\n    /* Routing against GET /user/nikic/42 */\n\n    [FastRoute\\Dispatcher::FOUND, 'handler0', ['name' => 'nikic', 'id' => '42']]\n\n### Overriding the route parser and dispatcher\n\nThe routing process makes use of three components: A route parser, a data generator and a\ndispatcher. The three components adhere to the following interfaces:\n\n```php\n<?php\n\nnamespace FastRoute;\n\ninterface RouteParser {\n    public function parse($route);\n}\n\ninterface DataGenerator {\n    public function addRoute($httpMethod, $routeData, $handler);\n    public function getData();\n}\n\ninterface Dispatcher {\n    const NOT_FOUND = 0, FOUND = 1, METHOD_NOT_ALLOWED = 2;\n\n    public function dispatch($httpMethod, $uri);\n}\n```\n\nThe route parser takes a route pattern string and converts it into an array of route infos, where\neach route info is again an array of it's parts. The structure is best understood using an example:\n\n    /* The route /user/{id:\\d+}[/{name}] converts to the following array: */\n    [\n        [\n            '/user/',\n            ['id', '\\d+'],\n        ],\n        [\n            '/user/',\n            ['id', '\\d+'],\n            '/',\n            ['name', '[^/]+'],\n        ],\n    ]\n\nThis array can then be passed to the `addRoute()` method of a data generator. After all routes have\nbeen added the `getData()` of the generator is invoked, which returns all the routing data required\nby the dispatcher. The format of this data is not further specified - it is tightly coupled to\nthe corresponding dispatcher.\n\nThe dispatcher accepts the routing data via a constructor and provides a `dispatch()` method, which\nyou're already familiar with.\n\nThe route parser can be overwritten individually (to make use of some different pattern syntax),\nhowever the data generator and dispatcher should always be changed as a pair, as the output from\nthe former is tightly coupled to the input of the latter. The reason the generator and the\ndispatcher are separate is that only the latter is needed when using caching (as the output of\nthe former is what is being cached.)\n\nWhen using the `simpleDispatcher` / `cachedDispatcher` functions from above the override happens\nthrough the options array:\n\n```php\n<?php\n\n$dispatcher = FastRoute\\simpleDispatcher(function(FastRoute\\RouteCollector $r) {\n    /* ... */\n}, [\n    'routeParser' => 'FastRoute\\\\RouteParser\\\\Std',\n    'dataGenerator' => 'FastRoute\\\\DataGenerator\\\\GroupCountBased',\n    'dispatcher' => 'FastRoute\\\\Dispatcher\\\\GroupCountBased',\n]);\n```\n\nThe above options array corresponds to the defaults. By replacing `GroupCountBased` by\n`GroupPosBased` you could switch to a different dispatching strategy.\n\n### A Note on HEAD Requests\n\nThe HTTP spec requires servers to [support both GET and HEAD methods][2616-511]:\n\n> The methods GET and HEAD MUST be supported by all general-purpose servers\n\nTo avoid forcing users to manually register HEAD routes for each resource we fallback to matching an\navailable GET route for a given resource. The PHP web SAPI transparently removes the entity body\nfrom HEAD responses so this behavior has no effect on the vast majority of users.\n\nHowever, implementers using FastRoute outside the web SAPI environment (e.g. a custom server) MUST\nNOT send entity bodies generated in response to HEAD requests. If you are a non-SAPI user this is\n*your responsibility*; FastRoute has no purview to prevent you from breaking HTTP in such cases.\n\nFinally, note that applications MAY always specify their own HEAD method route for a given\nresource to bypass this behavior entirely.\n\n### Credits\n\nThis library is based on a router that [Levi Morrison][levi] implemented for the Aerys server.\n\nA large number of tests, as well as HTTP compliance considerations, were provided by [Daniel Lowrey][rdlowrey].\n\n\n[2616-511]: http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.1 \"RFC 2616 Section 5.1.1\"\n[blog_post]: http://nikic.github.io/2014/02/18/Fast-request-routing-using-regular-expressions.html\n[levi]: https://github.com/morrisonlevi\n[rdlowrey]: https://github.com/rdlowrey\n"
  },
  {
    "path": "server/vendor/nikic/fast-route/composer.json",
    "content": "{\n  \"name\": \"nikic/fast-route\",\n  \"description\": \"Fast request router for PHP\",\n  \"keywords\": [\"routing\", \"router\"],\n  \"license\": \"BSD-3-Clause\",\n  \"authors\": [\n    {\n      \"name\": \"Nikita Popov\",\n      \"email\": \"nikic@php.net\"\n    }\n  ],\n  \"autoload\": {\n    \"psr-4\": {\n      \"FastRoute\\\\\": \"src/\"\n    },\n    \"files\": [\"src/functions.php\"]\n  },\n  \"require\": {\n    \"php\": \">=5.4.0\"\n  },\n  \"require-dev\": {\n    \"phpunit/phpunit\": \"^4.8.35|~5.7\"\n  }\n}\n"
  },
  {
    "path": "server/vendor/nikic/fast-route/phpunit.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<phpunit backupGlobals=\"false\"\n         backupStaticAttributes=\"false\"\n         colors=\"true\"\n         convertErrorsToExceptions=\"true\"\n         convertNoticesToExceptions=\"true\"\n         convertWarningsToExceptions=\"true\"\n         processIsolation=\"false\"\n         syntaxCheck=\"false\"\n         bootstrap=\"test/bootstrap.php\"\n        >\n    <testsuites>\n        <testsuite name=\"FastRoute Tests\">\n            <directory>./test/</directory>\n        </testsuite>\n    </testsuites>\n\n    <filter>\n        <whitelist>\n            <directory>./src/</directory>\n        </whitelist>\n    </filter>\n</phpunit>\n"
  },
  {
    "path": "server/vendor/nikic/fast-route/psalm.xml",
    "content": "<?xml version=\"1.0\"?>\n<psalm\n    name=\"Example Psalm config with recommended defaults\"\n    stopOnFirstError=\"false\"\n    useDocblockTypes=\"true\"\n    totallyTyped=\"false\"\n    requireVoidReturnType=\"false\"\n>\n    <projectFiles>\n        <directory name=\"src\" />\n    </projectFiles>\n\n    <issueHandlers>\n        <LessSpecificReturnType errorLevel=\"info\" />\n\n        <!-- level 3 issues - slightly lazy code writing, but provably low false-negatives -->\n        <DeprecatedMethod errorLevel=\"info\" />\n\n        <MissingClosureReturnType errorLevel=\"info\" />\n        <MissingReturnType errorLevel=\"info\" />\n        <MissingPropertyType errorLevel=\"info\" />\n        <InvalidDocblock errorLevel=\"info\" />\n        <MisplacedRequiredParam errorLevel=\"info\" />\n\n        <PropertyNotSetInConstructor errorLevel=\"info\" />\n        <MissingConstructor errorLevel=\"info\" />\n    </issueHandlers>\n</psalm>\n"
  },
  {
    "path": "server/vendor/nikic/fast-route/src/BadRouteException.php",
    "content": "<?php\n\nnamespace FastRoute;\n\nclass BadRouteException extends \\LogicException\n{\n}\n"
  },
  {
    "path": "server/vendor/nikic/fast-route/src/DataGenerator/CharCountBased.php",
    "content": "<?php\n\nnamespace FastRoute\\DataGenerator;\n\nclass CharCountBased extends RegexBasedAbstract\n{\n    protected function getApproxChunkSize()\n    {\n        return 30;\n    }\n\n    protected function processChunk($regexToRoutesMap)\n    {\n        $routeMap = [];\n        $regexes = [];\n\n        $suffixLen = 0;\n        $suffix = '';\n        $count = count($regexToRoutesMap);\n        foreach ($regexToRoutesMap as $regex => $route) {\n            $suffixLen++;\n            $suffix .= \"\\t\";\n\n            $regexes[] = '(?:' . $regex . '/(\\t{' . $suffixLen . '})\\t{' . ($count - $suffixLen) . '})';\n            $routeMap[$suffix] = [$route->handler, $route->variables];\n        }\n\n        $regex = '~^(?|' . implode('|', $regexes) . ')$~';\n        return ['regex' => $regex, 'suffix' => '/' . $suffix, 'routeMap' => $routeMap];\n    }\n}\n"
  },
  {
    "path": "server/vendor/nikic/fast-route/src/DataGenerator/GroupCountBased.php",
    "content": "<?php\n\nnamespace FastRoute\\DataGenerator;\n\nclass GroupCountBased extends RegexBasedAbstract\n{\n    protected function getApproxChunkSize()\n    {\n        return 10;\n    }\n\n    protected function processChunk($regexToRoutesMap)\n    {\n        $routeMap = [];\n        $regexes = [];\n        $numGroups = 0;\n        foreach ($regexToRoutesMap as $regex => $route) {\n            $numVariables = count($route->variables);\n            $numGroups = max($numGroups, $numVariables);\n\n            $regexes[] = $regex . str_repeat('()', $numGroups - $numVariables);\n            $routeMap[$numGroups + 1] = [$route->handler, $route->variables];\n\n            ++$numGroups;\n        }\n\n        $regex = '~^(?|' . implode('|', $regexes) . ')$~';\n        return ['regex' => $regex, 'routeMap' => $routeMap];\n    }\n}\n"
  },
  {
    "path": "server/vendor/nikic/fast-route/src/DataGenerator/GroupPosBased.php",
    "content": "<?php\n\nnamespace FastRoute\\DataGenerator;\n\nclass GroupPosBased extends RegexBasedAbstract\n{\n    protected function getApproxChunkSize()\n    {\n        return 10;\n    }\n\n    protected function processChunk($regexToRoutesMap)\n    {\n        $routeMap = [];\n        $regexes = [];\n        $offset = 1;\n        foreach ($regexToRoutesMap as $regex => $route) {\n            $regexes[] = $regex;\n            $routeMap[$offset] = [$route->handler, $route->variables];\n\n            $offset += count($route->variables);\n        }\n\n        $regex = '~^(?:' . implode('|', $regexes) . ')$~';\n        return ['regex' => $regex, 'routeMap' => $routeMap];\n    }\n}\n"
  },
  {
    "path": "server/vendor/nikic/fast-route/src/DataGenerator/MarkBased.php",
    "content": "<?php\n\nnamespace FastRoute\\DataGenerator;\n\nclass MarkBased extends RegexBasedAbstract\n{\n    protected function getApproxChunkSize()\n    {\n        return 30;\n    }\n\n    protected function processChunk($regexToRoutesMap)\n    {\n        $routeMap = [];\n        $regexes = [];\n        $markName = 'a';\n        foreach ($regexToRoutesMap as $regex => $route) {\n            $regexes[] = $regex . '(*MARK:' . $markName . ')';\n            $routeMap[$markName] = [$route->handler, $route->variables];\n\n            ++$markName;\n        }\n\n        $regex = '~^(?|' . implode('|', $regexes) . ')$~';\n        return ['regex' => $regex, 'routeMap' => $routeMap];\n    }\n}\n"
  },
  {
    "path": "server/vendor/nikic/fast-route/src/DataGenerator/RegexBasedAbstract.php",
    "content": "<?php\n\nnamespace FastRoute\\DataGenerator;\n\nuse FastRoute\\BadRouteException;\nuse FastRoute\\DataGenerator;\nuse FastRoute\\Route;\n\nabstract class RegexBasedAbstract implements DataGenerator\n{\n    /** @var mixed[][] */\n    protected $staticRoutes = [];\n\n    /** @var Route[][] */\n    protected $methodToRegexToRoutesMap = [];\n\n    /**\n     * @return int\n     */\n    abstract protected function getApproxChunkSize();\n\n    /**\n     * @return mixed[]\n     */\n    abstract protected function processChunk($regexToRoutesMap);\n\n    public function addRoute($httpMethod, $routeData, $handler)\n    {\n        if ($this->isStaticRoute($routeData)) {\n            $this->addStaticRoute($httpMethod, $routeData, $handler);\n        } else {\n            $this->addVariableRoute($httpMethod, $routeData, $handler);\n        }\n    }\n\n    /**\n     * @return mixed[]\n     */\n    public function getData()\n    {\n        if (empty($this->methodToRegexToRoutesMap)) {\n            return [$this->staticRoutes, []];\n        }\n\n        return [$this->staticRoutes, $this->generateVariableRouteData()];\n    }\n\n    /**\n     * @return mixed[]\n     */\n    private function generateVariableRouteData()\n    {\n        $data = [];\n        foreach ($this->methodToRegexToRoutesMap as $method => $regexToRoutesMap) {\n            $chunkSize = $this->computeChunkSize(count($regexToRoutesMap));\n            $chunks = array_chunk($regexToRoutesMap, $chunkSize, true);\n            $data[$method] = array_map([$this, 'processChunk'], $chunks);\n        }\n        return $data;\n    }\n\n    /**\n     * @param int\n     * @return int\n     */\n    private function computeChunkSize($count)\n    {\n        $numParts = max(1, round($count / $this->getApproxChunkSize()));\n        return (int) ceil($count / $numParts);\n    }\n\n    /**\n     * @param mixed[]\n     * @return bool\n     */\n    private function isStaticRoute($routeData)\n    {\n        return count($routeData) === 1 && is_string($routeData[0]);\n    }\n\n    private function addStaticRoute($httpMethod, $routeData, $handler)\n    {\n        $routeStr = $routeData[0];\n\n        if (isset($this->staticRoutes[$httpMethod][$routeStr])) {\n            throw new BadRouteException(sprintf(\n                'Cannot register two routes matching \"%s\" for method \"%s\"',\n                $routeStr, $httpMethod\n            ));\n        }\n\n        if (isset($this->methodToRegexToRoutesMap[$httpMethod])) {\n            foreach ($this->methodToRegexToRoutesMap[$httpMethod] as $route) {\n                if ($route->matches($routeStr)) {\n                    throw new BadRouteException(sprintf(\n                        'Static route \"%s\" is shadowed by previously defined variable route \"%s\" for method \"%s\"',\n                        $routeStr, $route->regex, $httpMethod\n                    ));\n                }\n            }\n        }\n\n        $this->staticRoutes[$httpMethod][$routeStr] = $handler;\n    }\n\n    private function addVariableRoute($httpMethod, $routeData, $handler)\n    {\n        list($regex, $variables) = $this->buildRegexForRoute($routeData);\n\n        if (isset($this->methodToRegexToRoutesMap[$httpMethod][$regex])) {\n            throw new BadRouteException(sprintf(\n                'Cannot register two routes matching \"%s\" for method \"%s\"',\n                $regex, $httpMethod\n            ));\n        }\n\n        $this->methodToRegexToRoutesMap[$httpMethod][$regex] = new Route(\n            $httpMethod, $handler, $regex, $variables\n        );\n    }\n\n    /**\n     * @param mixed[]\n     * @return mixed[]\n     */\n    private function buildRegexForRoute($routeData)\n    {\n        $regex = '';\n        $variables = [];\n        foreach ($routeData as $part) {\n            if (is_string($part)) {\n                $regex .= preg_quote($part, '~');\n                continue;\n            }\n\n            list($varName, $regexPart) = $part;\n\n            if (isset($variables[$varName])) {\n                throw new BadRouteException(sprintf(\n                    'Cannot use the same placeholder \"%s\" twice', $varName\n                ));\n            }\n\n            if ($this->regexHasCapturingGroups($regexPart)) {\n                throw new BadRouteException(sprintf(\n                    'Regex \"%s\" for parameter \"%s\" contains a capturing group',\n                    $regexPart, $varName\n                ));\n            }\n\n            $variables[$varName] = $varName;\n            $regex .= '(' . $regexPart . ')';\n        }\n\n        return [$regex, $variables];\n    }\n\n    /**\n     * @param string\n     * @return bool\n     */\n    private function regexHasCapturingGroups($regex)\n    {\n        if (false === strpos($regex, '(')) {\n            // Needs to have at least a ( to contain a capturing group\n            return false;\n        }\n\n        // Semi-accurate detection for capturing groups\n        return (bool) preg_match(\n            '~\n                (?:\n                    \\(\\?\\(\n                  | \\[ [^\\]\\\\\\\\]* (?: \\\\\\\\ . [^\\]\\\\\\\\]* )* \\]\n                  | \\\\\\\\ .\n                ) (*SKIP)(*FAIL) |\n                \\(\n                (?!\n                    \\? (?! <(?![!=]) | P< | \\' )\n                  | \\*\n                )\n            ~x',\n            $regex\n        );\n    }\n}\n"
  },
  {
    "path": "server/vendor/nikic/fast-route/src/DataGenerator.php",
    "content": "<?php\n\nnamespace FastRoute;\n\ninterface DataGenerator\n{\n    /**\n     * Adds a route to the data generator. The route data uses the\n     * same format that is returned by RouterParser::parser().\n     *\n     * The handler doesn't necessarily need to be a callable, it\n     * can be arbitrary data that will be returned when the route\n     * matches.\n     *\n     * @param string $httpMethod\n     * @param array $routeData\n     * @param mixed $handler\n     */\n    public function addRoute($httpMethod, $routeData, $handler);\n\n    /**\n     * Returns dispatcher data in some unspecified format, which\n     * depends on the used method of dispatch.\n     */\n    public function getData();\n}\n"
  },
  {
    "path": "server/vendor/nikic/fast-route/src/Dispatcher/CharCountBased.php",
    "content": "<?php\n\nnamespace FastRoute\\Dispatcher;\n\nclass CharCountBased extends RegexBasedAbstract\n{\n    public function __construct($data)\n    {\n        list($this->staticRouteMap, $this->variableRouteData) = $data;\n    }\n\n    protected function dispatchVariableRoute($routeData, $uri)\n    {\n        foreach ($routeData as $data) {\n            if (!preg_match($data['regex'], $uri . $data['suffix'], $matches)) {\n                continue;\n            }\n\n            list($handler, $varNames) = $data['routeMap'][end($matches)];\n\n            $vars = [];\n            $i = 0;\n            foreach ($varNames as $varName) {\n                $vars[$varName] = $matches[++$i];\n            }\n            return [self::FOUND, $handler, $vars];\n        }\n\n        return [self::NOT_FOUND];\n    }\n}\n"
  },
  {
    "path": "server/vendor/nikic/fast-route/src/Dispatcher/GroupCountBased.php",
    "content": "<?php\n\nnamespace FastRoute\\Dispatcher;\n\nclass GroupCountBased extends RegexBasedAbstract\n{\n    public function __construct($data)\n    {\n        list($this->staticRouteMap, $this->variableRouteData) = $data;\n    }\n\n    protected function dispatchVariableRoute($routeData, $uri)\n    {\n        foreach ($routeData as $data) {\n            if (!preg_match($data['regex'], $uri, $matches)) {\n                continue;\n            }\n\n            list($handler, $varNames) = $data['routeMap'][count($matches)];\n\n            $vars = [];\n            $i = 0;\n            foreach ($varNames as $varName) {\n                $vars[$varName] = $matches[++$i];\n            }\n            return [self::FOUND, $handler, $vars];\n        }\n\n        return [self::NOT_FOUND];\n    }\n}\n"
  },
  {
    "path": "server/vendor/nikic/fast-route/src/Dispatcher/GroupPosBased.php",
    "content": "<?php\n\nnamespace FastRoute\\Dispatcher;\n\nclass GroupPosBased extends RegexBasedAbstract\n{\n    public function __construct($data)\n    {\n        list($this->staticRouteMap, $this->variableRouteData) = $data;\n    }\n\n    protected function dispatchVariableRoute($routeData, $uri)\n    {\n        foreach ($routeData as $data) {\n            if (!preg_match($data['regex'], $uri, $matches)) {\n                continue;\n            }\n\n            // find first non-empty match\n            for ($i = 1; '' === $matches[$i]; ++$i);\n\n            list($handler, $varNames) = $data['routeMap'][$i];\n\n            $vars = [];\n            foreach ($varNames as $varName) {\n                $vars[$varName] = $matches[$i++];\n            }\n            return [self::FOUND, $handler, $vars];\n        }\n\n        return [self::NOT_FOUND];\n    }\n}\n"
  },
  {
    "path": "server/vendor/nikic/fast-route/src/Dispatcher/MarkBased.php",
    "content": "<?php\n\nnamespace FastRoute\\Dispatcher;\n\nclass MarkBased extends RegexBasedAbstract\n{\n    public function __construct($data)\n    {\n        list($this->staticRouteMap, $this->variableRouteData) = $data;\n    }\n\n    protected function dispatchVariableRoute($routeData, $uri)\n    {\n        foreach ($routeData as $data) {\n            if (!preg_match($data['regex'], $uri, $matches)) {\n                continue;\n            }\n\n            list($handler, $varNames) = $data['routeMap'][$matches['MARK']];\n\n            $vars = [];\n            $i = 0;\n            foreach ($varNames as $varName) {\n                $vars[$varName] = $matches[++$i];\n            }\n            return [self::FOUND, $handler, $vars];\n        }\n\n        return [self::NOT_FOUND];\n    }\n}\n"
  },
  {
    "path": "server/vendor/nikic/fast-route/src/Dispatcher/RegexBasedAbstract.php",
    "content": "<?php\n\nnamespace FastRoute\\Dispatcher;\n\nuse FastRoute\\Dispatcher;\n\nabstract class RegexBasedAbstract implements Dispatcher\n{\n    /** @var mixed[][] */\n    protected $staticRouteMap = [];\n\n    /** @var mixed[] */\n    protected $variableRouteData = [];\n\n    /**\n     * @return mixed[]\n     */\n    abstract protected function dispatchVariableRoute($routeData, $uri);\n\n    public function dispatch($httpMethod, $uri)\n    {\n        if (isset($this->staticRouteMap[$httpMethod][$uri])) {\n            $handler = $this->staticRouteMap[$httpMethod][$uri];\n            return [self::FOUND, $handler, []];\n        }\n\n        $varRouteData = $this->variableRouteData;\n        if (isset($varRouteData[$httpMethod])) {\n            $result = $this->dispatchVariableRoute($varRouteData[$httpMethod], $uri);\n            if ($result[0] === self::FOUND) {\n                return $result;\n            }\n        }\n\n        // For HEAD requests, attempt fallback to GET\n        if ($httpMethod === 'HEAD') {\n            if (isset($this->staticRouteMap['GET'][$uri])) {\n                $handler = $this->staticRouteMap['GET'][$uri];\n                return [self::FOUND, $handler, []];\n            }\n            if (isset($varRouteData['GET'])) {\n                $result = $this->dispatchVariableRoute($varRouteData['GET'], $uri);\n                if ($result[0] === self::FOUND) {\n                    return $result;\n                }\n            }\n        }\n\n        // If nothing else matches, try fallback routes\n        if (isset($this->staticRouteMap['*'][$uri])) {\n            $handler = $this->staticRouteMap['*'][$uri];\n            return [self::FOUND, $handler, []];\n        }\n        if (isset($varRouteData['*'])) {\n            $result = $this->dispatchVariableRoute($varRouteData['*'], $uri);\n            if ($result[0] === self::FOUND) {\n                return $result;\n            }\n        }\n\n        // Find allowed methods for this URI by matching against all other HTTP methods as well\n        $allowedMethods = [];\n\n        foreach ($this->staticRouteMap as $method => $uriMap) {\n            if ($method !== $httpMethod && isset($uriMap[$uri])) {\n                $allowedMethods[] = $method;\n            }\n        }\n\n        foreach ($varRouteData as $method => $routeData) {\n            if ($method === $httpMethod) {\n                continue;\n            }\n\n            $result = $this->dispatchVariableRoute($routeData, $uri);\n            if ($result[0] === self::FOUND) {\n                $allowedMethods[] = $method;\n            }\n        }\n\n        // If there are no allowed methods the route simply does not exist\n        if ($allowedMethods) {\n            return [self::METHOD_NOT_ALLOWED, $allowedMethods];\n        }\n\n        return [self::NOT_FOUND];\n    }\n}\n"
  },
  {
    "path": "server/vendor/nikic/fast-route/src/Dispatcher.php",
    "content": "<?php\n\nnamespace FastRoute;\n\ninterface Dispatcher\n{\n    const NOT_FOUND = 0;\n    const FOUND = 1;\n    const METHOD_NOT_ALLOWED = 2;\n\n    /**\n     * Dispatches against the provided HTTP method verb and URI.\n     *\n     * Returns array with one of the following formats:\n     *\n     *     [self::NOT_FOUND]\n     *     [self::METHOD_NOT_ALLOWED, ['GET', 'OTHER_ALLOWED_METHODS']]\n     *     [self::FOUND, $handler, ['varName' => 'value', ...]]\n     *\n     * @param string $httpMethod\n     * @param string $uri\n     *\n     * @return array\n     */\n    public function dispatch($httpMethod, $uri);\n}\n"
  },
  {
    "path": "server/vendor/nikic/fast-route/src/Route.php",
    "content": "<?php\n\nnamespace FastRoute;\n\nclass Route\n{\n    /** @var string */\n    public $httpMethod;\n\n    /** @var string */\n    public $regex;\n\n    /** @var array */\n    public $variables;\n\n    /** @var mixed */\n    public $handler;\n\n    /**\n     * Constructs a route (value object).\n     *\n     * @param string $httpMethod\n     * @param mixed  $handler\n     * @param string $regex\n     * @param array  $variables\n     */\n    public function __construct($httpMethod, $handler, $regex, $variables)\n    {\n        $this->httpMethod = $httpMethod;\n        $this->handler = $handler;\n        $this->regex = $regex;\n        $this->variables = $variables;\n    }\n\n    /**\n     * Tests whether this route matches the given string.\n     *\n     * @param string $str\n     *\n     * @return bool\n     */\n    public function matches($str)\n    {\n        $regex = '~^' . $this->regex . '$~';\n        return (bool) preg_match($regex, $str);\n    }\n}\n"
  },
  {
    "path": "server/vendor/nikic/fast-route/src/RouteCollector.php",
    "content": "<?php\n\nnamespace FastRoute;\n\nclass RouteCollector\n{\n    /** @var RouteParser */\n    protected $routeParser;\n\n    /** @var DataGenerator */\n    protected $dataGenerator;\n\n    /** @var string */\n    protected $currentGroupPrefix;\n\n    /**\n     * Constructs a route collector.\n     *\n     * @param RouteParser   $routeParser\n     * @param DataGenerator $dataGenerator\n     */\n    public function __construct(RouteParser $routeParser, DataGenerator $dataGenerator)\n    {\n        $this->routeParser = $routeParser;\n        $this->dataGenerator = $dataGenerator;\n        $this->currentGroupPrefix = '';\n    }\n\n    /**\n     * Adds a route to the collection.\n     *\n     * The syntax used in the $route string depends on the used route parser.\n     *\n     * @param string|string[] $httpMethod\n     * @param string $route\n     * @param mixed  $handler\n     */\n    public function addRoute($httpMethod, $route, $handler)\n    {\n        $route = $this->currentGroupPrefix . $route;\n        $routeDatas = $this->routeParser->parse($route);\n        foreach ((array) $httpMethod as $method) {\n            foreach ($routeDatas as $routeData) {\n                $this->dataGenerator->addRoute($method, $routeData, $handler);\n            }\n        }\n    }\n\n    /**\n     * Create a route group with a common prefix.\n     *\n     * All routes created in the passed callback will have the given group prefix prepended.\n     *\n     * @param string $prefix\n     * @param callable $callback\n     */\n    public function addGroup($prefix, callable $callback)\n    {\n        $previousGroupPrefix = $this->currentGroupPrefix;\n        $this->currentGroupPrefix = $previousGroupPrefix . $prefix;\n        $callback($this);\n        $this->currentGroupPrefix = $previousGroupPrefix;\n    }\n\n    /**\n     * Adds a GET route to the collection\n     * \n     * This is simply an alias of $this->addRoute('GET', $route, $handler)\n     *\n     * @param string $route\n     * @param mixed  $handler\n     */\n    public function get($route, $handler)\n    {\n        $this->addRoute('GET', $route, $handler);\n    }\n\n    /**\n     * Adds a POST route to the collection\n     * \n     * This is simply an alias of $this->addRoute('POST', $route, $handler)\n     *\n     * @param string $route\n     * @param mixed  $handler\n     */\n    public function post($route, $handler)\n    {\n        $this->addRoute('POST', $route, $handler);\n    }\n\n    /**\n     * Adds a PUT route to the collection\n     * \n     * This is simply an alias of $this->addRoute('PUT', $route, $handler)\n     *\n     * @param string $route\n     * @param mixed  $handler\n     */\n    public function put($route, $handler)\n    {\n        $this->addRoute('PUT', $route, $handler);\n    }\n\n    /**\n     * Adds a DELETE route to the collection\n     * \n     * This is simply an alias of $this->addRoute('DELETE', $route, $handler)\n     *\n     * @param string $route\n     * @param mixed  $handler\n     */\n    public function delete($route, $handler)\n    {\n        $this->addRoute('DELETE', $route, $handler);\n    }\n\n    /**\n     * Adds a PATCH route to the collection\n     * \n     * This is simply an alias of $this->addRoute('PATCH', $route, $handler)\n     *\n     * @param string $route\n     * @param mixed  $handler\n     */\n    public function patch($route, $handler)\n    {\n        $this->addRoute('PATCH', $route, $handler);\n    }\n\n    /**\n     * Adds a HEAD route to the collection\n     *\n     * This is simply an alias of $this->addRoute('HEAD', $route, $handler)\n     *\n     * @param string $route\n     * @param mixed  $handler\n     */\n    public function head($route, $handler)\n    {\n        $this->addRoute('HEAD', $route, $handler);\n    }\n\n    /**\n     * Returns the collected route data, as provided by the data generator.\n     *\n     * @return array\n     */\n    public function getData()\n    {\n        return $this->dataGenerator->getData();\n    }\n}\n"
  },
  {
    "path": "server/vendor/nikic/fast-route/src/RouteParser/Std.php",
    "content": "<?php\n\nnamespace FastRoute\\RouteParser;\n\nuse FastRoute\\BadRouteException;\nuse FastRoute\\RouteParser;\n\n/**\n * Parses route strings of the following form:\n *\n * \"/user/{name}[/{id:[0-9]+}]\"\n */\nclass Std implements RouteParser\n{\n    const VARIABLE_REGEX = <<<'REGEX'\n\\{\n    \\s* ([a-zA-Z_][a-zA-Z0-9_-]*) \\s*\n    (?:\n        : \\s* ([^{}]*(?:\\{(?-1)\\}[^{}]*)*)\n    )?\n\\}\nREGEX;\n    const DEFAULT_DISPATCH_REGEX = '[^/]+';\n\n    public function parse($route)\n    {\n        $routeWithoutClosingOptionals = rtrim($route, ']');\n        $numOptionals = strlen($route) - strlen($routeWithoutClosingOptionals);\n\n        // Split on [ while skipping placeholders\n        $segments = preg_split('~' . self::VARIABLE_REGEX . '(*SKIP)(*F) | \\[~x', $routeWithoutClosingOptionals);\n        if ($numOptionals !== count($segments) - 1) {\n            // If there are any ] in the middle of the route, throw a more specific error message\n            if (preg_match('~' . self::VARIABLE_REGEX . '(*SKIP)(*F) | \\]~x', $routeWithoutClosingOptionals)) {\n                throw new BadRouteException('Optional segments can only occur at the end of a route');\n            }\n            throw new BadRouteException(\"Number of opening '[' and closing ']' does not match\");\n        }\n\n        $currentRoute = '';\n        $routeDatas = [];\n        foreach ($segments as $n => $segment) {\n            if ($segment === '' && $n !== 0) {\n                throw new BadRouteException('Empty optional part');\n            }\n\n            $currentRoute .= $segment;\n            $routeDatas[] = $this->parsePlaceholders($currentRoute);\n        }\n        return $routeDatas;\n    }\n\n    /**\n     * Parses a route string that does not contain optional segments.\n     *\n     * @param string\n     * @return mixed[]\n     */\n    private function parsePlaceholders($route)\n    {\n        if (!preg_match_all(\n            '~' . self::VARIABLE_REGEX . '~x', $route, $matches,\n            PREG_OFFSET_CAPTURE | PREG_SET_ORDER\n        )) {\n            return [$route];\n        }\n\n        $offset = 0;\n        $routeData = [];\n        foreach ($matches as $set) {\n            if ($set[0][1] > $offset) {\n                $routeData[] = substr($route, $offset, $set[0][1] - $offset);\n            }\n            $routeData[] = [\n                $set[1][0],\n                isset($set[2]) ? trim($set[2][0]) : self::DEFAULT_DISPATCH_REGEX\n            ];\n            $offset = $set[0][1] + strlen($set[0][0]);\n        }\n\n        if ($offset !== strlen($route)) {\n            $routeData[] = substr($route, $offset);\n        }\n\n        return $routeData;\n    }\n}\n"
  },
  {
    "path": "server/vendor/nikic/fast-route/src/RouteParser.php",
    "content": "<?php\n\nnamespace FastRoute;\n\ninterface RouteParser\n{\n    /**\n     * Parses a route string into multiple route data arrays.\n     *\n     * The expected output is defined using an example:\n     *\n     * For the route string \"/fixedRoutePart/{varName}[/moreFixed/{varName2:\\d+}]\", if {varName} is interpreted as\n     * a placeholder and [...] is interpreted as an optional route part, the expected result is:\n     *\n     * [\n     *     // first route: without optional part\n     *     [\n     *         \"/fixedRoutePart/\",\n     *         [\"varName\", \"[^/]+\"],\n     *     ],\n     *     // second route: with optional part\n     *     [\n     *         \"/fixedRoutePart/\",\n     *         [\"varName\", \"[^/]+\"],\n     *         \"/moreFixed/\",\n     *         [\"varName2\", [0-9]+\"],\n     *     ],\n     * ]\n     *\n     * Here one route string was converted into two route data arrays.\n     *\n     * @param string $route Route string to parse\n     *\n     * @return mixed[][] Array of route data arrays\n     */\n    public function parse($route);\n}\n"
  },
  {
    "path": "server/vendor/nikic/fast-route/src/bootstrap.php",
    "content": "<?php\n\nnamespace FastRoute;\n\nrequire __DIR__ . '/functions.php';\n\nspl_autoload_register(function ($class) {\n    if (strpos($class, 'FastRoute\\\\') === 0) {\n        $name = substr($class, strlen('FastRoute'));\n        require __DIR__ . strtr($name, '\\\\', DIRECTORY_SEPARATOR) . '.php';\n    }\n});\n"
  },
  {
    "path": "server/vendor/nikic/fast-route/src/functions.php",
    "content": "<?php\n\nnamespace FastRoute;\n\nif (!function_exists('FastRoute\\simpleDispatcher')) {\n    /**\n     * @param callable $routeDefinitionCallback\n     * @param array $options\n     *\n     * @return Dispatcher\n     */\n    function simpleDispatcher(callable $routeDefinitionCallback, array $options = [])\n    {\n        $options += [\n            'routeParser' => 'FastRoute\\\\RouteParser\\\\Std',\n            'dataGenerator' => 'FastRoute\\\\DataGenerator\\\\GroupCountBased',\n            'dispatcher' => 'FastRoute\\\\Dispatcher\\\\GroupCountBased',\n            'routeCollector' => 'FastRoute\\\\RouteCollector',\n        ];\n\n        /** @var RouteCollector $routeCollector */\n        $routeCollector = new $options['routeCollector'](\n            new $options['routeParser'], new $options['dataGenerator']\n        );\n        $routeDefinitionCallback($routeCollector);\n\n        return new $options['dispatcher']($routeCollector->getData());\n    }\n\n    /**\n     * @param callable $routeDefinitionCallback\n     * @param array $options\n     *\n     * @return Dispatcher\n     */\n    function cachedDispatcher(callable $routeDefinitionCallback, array $options = [])\n    {\n        $options += [\n            'routeParser' => 'FastRoute\\\\RouteParser\\\\Std',\n            'dataGenerator' => 'FastRoute\\\\DataGenerator\\\\GroupCountBased',\n            'dispatcher' => 'FastRoute\\\\Dispatcher\\\\GroupCountBased',\n            'routeCollector' => 'FastRoute\\\\RouteCollector',\n            'cacheDisabled' => false,\n        ];\n\n        if (!isset($options['cacheFile'])) {\n            throw new \\LogicException('Must specify \"cacheFile\" option');\n        }\n\n        if (!$options['cacheDisabled'] && file_exists($options['cacheFile'])) {\n            $dispatchData = require $options['cacheFile'];\n            if (!is_array($dispatchData)) {\n                throw new \\RuntimeException('Invalid cache file \"' . $options['cacheFile'] . '\"');\n            }\n            return new $options['dispatcher']($dispatchData);\n        }\n\n        $routeCollector = new $options['routeCollector'](\n            new $options['routeParser'], new $options['dataGenerator']\n        );\n        $routeDefinitionCallback($routeCollector);\n\n        /** @var RouteCollector $routeCollector */\n        $dispatchData = $routeCollector->getData();\n        if (!$options['cacheDisabled']) {\n            file_put_contents(\n                $options['cacheFile'],\n                '<?php return ' . var_export($dispatchData, true) . ';'\n            );\n        }\n\n        return new $options['dispatcher']($dispatchData);\n    }\n}\n"
  },
  {
    "path": "server/vendor/nikic/fast-route/test/Dispatcher/CharCountBasedTest.php",
    "content": "<?php\n\nnamespace FastRoute\\Dispatcher;\n\nclass CharCountBasedTest extends DispatcherTest\n{\n    protected function getDispatcherClass()\n    {\n        return 'FastRoute\\\\Dispatcher\\\\CharCountBased';\n    }\n\n    protected function getDataGeneratorClass()\n    {\n        return 'FastRoute\\\\DataGenerator\\\\CharCountBased';\n    }\n}\n"
  },
  {
    "path": "server/vendor/nikic/fast-route/test/Dispatcher/DispatcherTest.php",
    "content": "<?php\n\nnamespace FastRoute\\Dispatcher;\n\nuse FastRoute\\RouteCollector;\nuse PHPUnit\\Framework\\TestCase;\n\nabstract class DispatcherTest extends TestCase\n{\n    /**\n     * Delegate dispatcher selection to child test classes\n     */\n    abstract protected function getDispatcherClass();\n\n    /**\n     * Delegate dataGenerator selection to child test classes\n     */\n    abstract protected function getDataGeneratorClass();\n\n    /**\n     * Set appropriate options for the specific Dispatcher class we're testing\n     */\n    private function generateDispatcherOptions()\n    {\n        return [\n            'dataGenerator' => $this->getDataGeneratorClass(),\n            'dispatcher' => $this->getDispatcherClass()\n        ];\n    }\n\n    /**\n     * @dataProvider provideFoundDispatchCases\n     */\n    public function testFoundDispatches($method, $uri, $callback, $handler, $argDict)\n    {\n        $dispatcher = \\FastRoute\\simpleDispatcher($callback, $this->generateDispatcherOptions());\n        $info = $dispatcher->dispatch($method, $uri);\n        $this->assertSame($dispatcher::FOUND, $info[0]);\n        $this->assertSame($handler, $info[1]);\n        $this->assertSame($argDict, $info[2]);\n    }\n\n    /**\n     * @dataProvider provideNotFoundDispatchCases\n     */\n    public function testNotFoundDispatches($method, $uri, $callback)\n    {\n        $dispatcher = \\FastRoute\\simpleDispatcher($callback, $this->generateDispatcherOptions());\n        $routeInfo = $dispatcher->dispatch($method, $uri);\n        $this->assertArrayNotHasKey(1, $routeInfo,\n            'NOT_FOUND result must only contain a single element in the returned info array'\n        );\n        $this->assertSame($dispatcher::NOT_FOUND, $routeInfo[0]);\n    }\n\n    /**\n     * @dataProvider provideMethodNotAllowedDispatchCases\n     */\n    public function testMethodNotAllowedDispatches($method, $uri, $callback, $availableMethods)\n    {\n        $dispatcher = \\FastRoute\\simpleDispatcher($callback, $this->generateDispatcherOptions());\n        $routeInfo = $dispatcher->dispatch($method, $uri);\n        $this->assertArrayHasKey(1, $routeInfo,\n            'METHOD_NOT_ALLOWED result must return an array of allowed methods at index 1'\n        );\n\n        list($routedStatus, $methodArray) = $dispatcher->dispatch($method, $uri);\n        $this->assertSame($dispatcher::METHOD_NOT_ALLOWED, $routedStatus);\n        $this->assertSame($availableMethods, $methodArray);\n    }\n\n    /**\n     * @expectedException \\FastRoute\\BadRouteException\n     * @expectedExceptionMessage Cannot use the same placeholder \"test\" twice\n     */\n    public function testDuplicateVariableNameError()\n    {\n        \\FastRoute\\simpleDispatcher(function (RouteCollector $r) {\n            $r->addRoute('GET', '/foo/{test}/{test:\\d+}', 'handler0');\n        }, $this->generateDispatcherOptions());\n    }\n\n    /**\n     * @expectedException \\FastRoute\\BadRouteException\n     * @expectedExceptionMessage Cannot register two routes matching \"/user/([^/]+)\" for method \"GET\"\n     */\n    public function testDuplicateVariableRoute()\n    {\n        \\FastRoute\\simpleDispatcher(function (RouteCollector $r) {\n            $r->addRoute('GET', '/user/{id}', 'handler0'); // oops, forgot \\d+ restriction ;)\n            $r->addRoute('GET', '/user/{name}', 'handler1');\n        }, $this->generateDispatcherOptions());\n    }\n\n    /**\n     * @expectedException \\FastRoute\\BadRouteException\n     * @expectedExceptionMessage Cannot register two routes matching \"/user\" for method \"GET\"\n     */\n    public function testDuplicateStaticRoute()\n    {\n        \\FastRoute\\simpleDispatcher(function (RouteCollector $r) {\n            $r->addRoute('GET', '/user', 'handler0');\n            $r->addRoute('GET', '/user', 'handler1');\n        }, $this->generateDispatcherOptions());\n    }\n\n    /**\n     * @expectedException \\FastRoute\\BadRouteException\n     * @expectedExceptionMessage Static route \"/user/nikic\" is shadowed by previously defined variable route \"/user/([^/]+)\" for method \"GET\"\n     */\n    public function testShadowedStaticRoute()\n    {\n        \\FastRoute\\simpleDispatcher(function (RouteCollector $r) {\n            $r->addRoute('GET', '/user/{name}', 'handler0');\n            $r->addRoute('GET', '/user/nikic', 'handler1');\n        }, $this->generateDispatcherOptions());\n    }\n\n    /**\n     * @expectedException \\FastRoute\\BadRouteException\n     * @expectedExceptionMessage Regex \"(en|de)\" for parameter \"lang\" contains a capturing group\n     */\n    public function testCapturing()\n    {\n        \\FastRoute\\simpleDispatcher(function (RouteCollector $r) {\n            $r->addRoute('GET', '/{lang:(en|de)}', 'handler0');\n        }, $this->generateDispatcherOptions());\n    }\n\n    public function provideFoundDispatchCases()\n    {\n        $cases = [];\n\n        // 0 -------------------------------------------------------------------------------------->\n\n        $callback = function (RouteCollector $r) {\n            $r->addRoute('GET', '/resource/123/456', 'handler0');\n        };\n\n        $method = 'GET';\n        $uri = '/resource/123/456';\n        $handler = 'handler0';\n        $argDict = [];\n\n        $cases[] = [$method, $uri, $callback, $handler, $argDict];\n\n        // 1 -------------------------------------------------------------------------------------->\n\n        $callback = function (RouteCollector $r) {\n            $r->addRoute('GET', '/handler0', 'handler0');\n            $r->addRoute('GET', '/handler1', 'handler1');\n            $r->addRoute('GET', '/handler2', 'handler2');\n        };\n\n        $method = 'GET';\n        $uri = '/handler2';\n        $handler = 'handler2';\n        $argDict = [];\n\n        $cases[] = [$method, $uri, $callback, $handler, $argDict];\n\n        // 2 -------------------------------------------------------------------------------------->\n\n        $callback = function (RouteCollector $r) {\n            $r->addRoute('GET', '/user/{name}/{id:[0-9]+}', 'handler0');\n            $r->addRoute('GET', '/user/{id:[0-9]+}', 'handler1');\n            $r->addRoute('GET', '/user/{name}', 'handler2');\n        };\n\n        $method = 'GET';\n        $uri = '/user/rdlowrey';\n        $handler = 'handler2';\n        $argDict = ['name' => 'rdlowrey'];\n\n        $cases[] = [$method, $uri, $callback, $handler, $argDict];\n\n        // 3 -------------------------------------------------------------------------------------->\n\n        // reuse $callback from #2\n\n        $method = 'GET';\n        $uri = '/user/12345';\n        $handler = 'handler1';\n        $argDict = ['id' => '12345'];\n\n        $cases[] = [$method, $uri, $callback, $handler, $argDict];\n\n        // 4 -------------------------------------------------------------------------------------->\n\n        // reuse $callback from #3\n\n        $method = 'GET';\n        $uri = '/user/NaN';\n        $handler = 'handler2';\n        $argDict = ['name' => 'NaN'];\n\n        $cases[] = [$method, $uri, $callback, $handler, $argDict];\n\n        // 5 -------------------------------------------------------------------------------------->\n\n        // reuse $callback from #4\n\n        $method = 'GET';\n        $uri = '/user/rdlowrey/12345';\n        $handler = 'handler0';\n        $argDict = ['name' => 'rdlowrey', 'id' => '12345'];\n\n        $cases[] = [$method, $uri, $callback, $handler, $argDict];\n\n        // 6 -------------------------------------------------------------------------------------->\n\n        $callback = function (RouteCollector $r) {\n            $r->addRoute('GET', '/user/{id:[0-9]+}', 'handler0');\n            $r->addRoute('GET', '/user/12345/extension', 'handler1');\n            $r->addRoute('GET', '/user/{id:[0-9]+}.{extension}', 'handler2');\n        };\n\n        $method = 'GET';\n        $uri = '/user/12345.svg';\n        $handler = 'handler2';\n        $argDict = ['id' => '12345', 'extension' => 'svg'];\n\n        $cases[] = [$method, $uri, $callback, $handler, $argDict];\n\n        // 7 ----- Test GET method fallback on HEAD route miss ------------------------------------>\n\n        $callback = function (RouteCollector $r) {\n            $r->addRoute('GET', '/user/{name}', 'handler0');\n            $r->addRoute('GET', '/user/{name}/{id:[0-9]+}', 'handler1');\n            $r->addRoute('GET', '/static0', 'handler2');\n            $r->addRoute('GET', '/static1', 'handler3');\n            $r->addRoute('HEAD', '/static1', 'handler4');\n        };\n\n        $method = 'HEAD';\n        $uri = '/user/rdlowrey';\n        $handler = 'handler0';\n        $argDict = ['name' => 'rdlowrey'];\n\n        $cases[] = [$method, $uri, $callback, $handler, $argDict];\n\n        // 8 ----- Test GET method fallback on HEAD route miss ------------------------------------>\n\n        // reuse $callback from #7\n\n        $method = 'HEAD';\n        $uri = '/user/rdlowrey/1234';\n        $handler = 'handler1';\n        $argDict = ['name' => 'rdlowrey', 'id' => '1234'];\n\n        $cases[] = [$method, $uri, $callback, $handler, $argDict];\n\n        // 9 ----- Test GET method fallback on HEAD route miss ------------------------------------>\n\n        // reuse $callback from #8\n\n        $method = 'HEAD';\n        $uri = '/static0';\n        $handler = 'handler2';\n        $argDict = [];\n\n        $cases[] = [$method, $uri, $callback, $handler, $argDict];\n\n        // 10 ---- Test existing HEAD route used if available (no fallback) ----------------------->\n\n        // reuse $callback from #9\n\n        $method = 'HEAD';\n        $uri = '/static1';\n        $handler = 'handler4';\n        $argDict = [];\n\n        $cases[] = [$method, $uri, $callback, $handler, $argDict];\n\n        // 11 ---- More specified routes are not shadowed by less specific of another method ------>\n\n        $callback = function (RouteCollector $r) {\n            $r->addRoute('GET', '/user/{name}', 'handler0');\n            $r->addRoute('POST', '/user/{name:[a-z]+}', 'handler1');\n        };\n\n        $method = 'POST';\n        $uri = '/user/rdlowrey';\n        $handler = 'handler1';\n        $argDict = ['name' => 'rdlowrey'];\n\n        $cases[] = [$method, $uri, $callback, $handler, $argDict];\n\n        // 12 ---- Handler of more specific routes is used, if it occurs first -------------------->\n\n        $callback = function (RouteCollector $r) {\n            $r->addRoute('GET', '/user/{name}', 'handler0');\n            $r->addRoute('POST', '/user/{name:[a-z]+}', 'handler1');\n            $r->addRoute('POST', '/user/{name}', 'handler2');\n        };\n\n        $method = 'POST';\n        $uri = '/user/rdlowrey';\n        $handler = 'handler1';\n        $argDict = ['name' => 'rdlowrey'];\n\n        $cases[] = [$method, $uri, $callback, $handler, $argDict];\n\n        // 13 ---- Route with constant suffix ----------------------------------------------------->\n\n        $callback = function (RouteCollector $r) {\n            $r->addRoute('GET', '/user/{name}', 'handler0');\n            $r->addRoute('GET', '/user/{name}/edit', 'handler1');\n        };\n\n        $method = 'GET';\n        $uri = '/user/rdlowrey/edit';\n        $handler = 'handler1';\n        $argDict = ['name' => 'rdlowrey'];\n\n        $cases[] = [$method, $uri, $callback, $handler, $argDict];\n\n        // 14 ---- Handle multiple methods with the same handler ---------------------------------->\n\n        $callback = function (RouteCollector $r) {\n            $r->addRoute(['GET', 'POST'], '/user', 'handlerGetPost');\n            $r->addRoute(['DELETE'], '/user', 'handlerDelete');\n            $r->addRoute([], '/user', 'handlerNone');\n        };\n\n        $argDict = [];\n        $cases[] = ['GET', '/user', $callback, 'handlerGetPost', $argDict];\n        $cases[] = ['POST', '/user', $callback, 'handlerGetPost', $argDict];\n        $cases[] = ['DELETE', '/user', $callback, 'handlerDelete', $argDict];\n\n        // 17 ----\n\n        $callback = function (RouteCollector $r) {\n            $r->addRoute('POST', '/user.json', 'handler0');\n            $r->addRoute('GET', '/{entity}.json', 'handler1');\n        };\n\n        $cases[] = ['GET', '/user.json', $callback, 'handler1', ['entity' => 'user']];\n\n        // 18 ----\n\n        $callback = function (RouteCollector $r) {\n            $r->addRoute('GET', '', 'handler0');\n        };\n\n        $cases[] = ['GET', '', $callback, 'handler0', []];\n\n        // 19 ----\n\n        $callback = function (RouteCollector $r) {\n            $r->addRoute('HEAD', '/a/{foo}', 'handler0');\n            $r->addRoute('GET', '/b/{foo}', 'handler1');\n        };\n\n        $cases[] = ['HEAD', '/b/bar', $callback, 'handler1', ['foo' => 'bar']];\n\n        // 20 ----\n\n        $callback = function (RouteCollector $r) {\n            $r->addRoute('HEAD', '/a', 'handler0');\n            $r->addRoute('GET', '/b', 'handler1');\n        };\n\n        $cases[] = ['HEAD', '/b', $callback, 'handler1', []];\n\n        // 21 ----\n\n        $callback = function (RouteCollector $r) {\n            $r->addRoute('GET', '/foo', 'handler0');\n            $r->addRoute('HEAD', '/{bar}', 'handler1');\n        };\n\n        $cases[] = ['HEAD', '/foo', $callback, 'handler1', ['bar' => 'foo']];\n\n        // 22 ----\n\n        $callback = function (RouteCollector $r) {\n            $r->addRoute('*', '/user', 'handler0');\n            $r->addRoute('*', '/{user}', 'handler1');\n            $r->addRoute('GET', '/user', 'handler2');\n        };\n\n        $cases[] = ['GET', '/user', $callback, 'handler2', []];\n\n        // 23 ----\n\n        $callback = function (RouteCollector $r) {\n            $r->addRoute('*', '/user', 'handler0');\n            $r->addRoute('GET', '/user', 'handler1');\n        };\n\n        $cases[] = ['POST', '/user', $callback, 'handler0', []];\n\n        // 24 ----\n\n        $cases[] = ['HEAD', '/user', $callback, 'handler1', []];\n\n        // 25 ----\n\n        $callback = function (RouteCollector $r) {\n            $r->addRoute('GET', '/{bar}', 'handler0');\n            $r->addRoute('*', '/foo', 'handler1');\n        };\n\n        $cases[] = ['GET', '/foo', $callback, 'handler0', ['bar' => 'foo']];\n\n        // 26 ----\n\n        $callback = function(RouteCollector $r) {\n            $r->addRoute('GET', '/user', 'handler0');\n            $r->addRoute('*', '/{foo:.*}', 'handler1');\n        };\n\n        $cases[] = ['POST', '/bar', $callback, 'handler1', ['foo' => 'bar']];\n\n        // x -------------------------------------------------------------------------------------->\n\n        return $cases;\n    }\n\n    public function provideNotFoundDispatchCases()\n    {\n        $cases = [];\n\n        // 0 -------------------------------------------------------------------------------------->\n\n        $callback = function (RouteCollector $r) {\n            $r->addRoute('GET', '/resource/123/456', 'handler0');\n        };\n\n        $method = 'GET';\n        $uri = '/not-found';\n\n        $cases[] = [$method, $uri, $callback];\n\n        // 1 -------------------------------------------------------------------------------------->\n\n        // reuse callback from #0\n        $method = 'POST';\n        $uri = '/not-found';\n\n        $cases[] = [$method, $uri, $callback];\n\n        // 2 -------------------------------------------------------------------------------------->\n\n        // reuse callback from #1\n        $method = 'PUT';\n        $uri = '/not-found';\n\n        $cases[] = [$method, $uri, $callback];\n\n        // 3 -------------------------------------------------------------------------------------->\n\n        $callback = function (RouteCollector $r) {\n            $r->addRoute('GET', '/handler0', 'handler0');\n            $r->addRoute('GET', '/handler1', 'handler1');\n            $r->addRoute('GET', '/handler2', 'handler2');\n        };\n\n        $method = 'GET';\n        $uri = '/not-found';\n\n        $cases[] = [$method, $uri, $callback];\n\n        // 4 -------------------------------------------------------------------------------------->\n\n        $callback = function (RouteCollector $r) {\n            $r->addRoute('GET', '/user/{name}/{id:[0-9]+}', 'handler0');\n            $r->addRoute('GET', '/user/{id:[0-9]+}', 'handler1');\n            $r->addRoute('GET', '/user/{name}', 'handler2');\n        };\n\n        $method = 'GET';\n        $uri = '/not-found';\n\n        $cases[] = [$method, $uri, $callback];\n\n        // 5 -------------------------------------------------------------------------------------->\n\n        // reuse callback from #4\n        $method = 'GET';\n        $uri = '/user/rdlowrey/12345/not-found';\n\n        $cases[] = [$method, $uri, $callback];\n\n        // 6 -------------------------------------------------------------------------------------->\n\n        // reuse callback from #5\n        $method = 'HEAD';\n\n        $cases[] = [$method, $uri, $callback];\n\n        // x -------------------------------------------------------------------------------------->\n\n        return $cases;\n    }\n\n    public function provideMethodNotAllowedDispatchCases()\n    {\n        $cases = [];\n\n        // 0 -------------------------------------------------------------------------------------->\n\n        $callback = function (RouteCollector $r) {\n            $r->addRoute('GET', '/resource/123/456', 'handler0');\n        };\n\n        $method = 'POST';\n        $uri = '/resource/123/456';\n        $allowedMethods = ['GET'];\n\n        $cases[] = [$method, $uri, $callback, $allowedMethods];\n\n        // 1 -------------------------------------------------------------------------------------->\n\n        $callback = function (RouteCollector $r) {\n            $r->addRoute('GET', '/resource/123/456', 'handler0');\n            $r->addRoute('POST', '/resource/123/456', 'handler1');\n            $r->addRoute('PUT', '/resource/123/456', 'handler2');\n            $r->addRoute('*', '/', 'handler3');\n        };\n\n        $method = 'DELETE';\n        $uri = '/resource/123/456';\n        $allowedMethods = ['GET', 'POST', 'PUT'];\n\n        $cases[] = [$method, $uri, $callback, $allowedMethods];\n\n        // 2 -------------------------------------------------------------------------------------->\n\n        $callback = function (RouteCollector $r) {\n            $r->addRoute('GET', '/user/{name}/{id:[0-9]+}', 'handler0');\n            $r->addRoute('POST', '/user/{name}/{id:[0-9]+}', 'handler1');\n            $r->addRoute('PUT', '/user/{name}/{id:[0-9]+}', 'handler2');\n            $r->addRoute('PATCH', '/user/{name}/{id:[0-9]+}', 'handler3');\n        };\n\n        $method = 'DELETE';\n        $uri = '/user/rdlowrey/42';\n        $allowedMethods = ['GET', 'POST', 'PUT', 'PATCH'];\n\n        $cases[] = [$method, $uri, $callback, $allowedMethods];\n\n        // 3 -------------------------------------------------------------------------------------->\n\n        $callback = function (RouteCollector $r) {\n            $r->addRoute('POST', '/user/{name}', 'handler1');\n            $r->addRoute('PUT', '/user/{name:[a-z]+}', 'handler2');\n            $r->addRoute('PATCH', '/user/{name:[a-z]+}', 'handler3');\n        };\n\n        $method = 'GET';\n        $uri = '/user/rdlowrey';\n        $allowedMethods = ['POST', 'PUT', 'PATCH'];\n\n        $cases[] = [$method, $uri, $callback, $allowedMethods];\n\n        // 4 -------------------------------------------------------------------------------------->\n\n        $callback = function (RouteCollector $r) {\n            $r->addRoute(['GET', 'POST'], '/user', 'handlerGetPost');\n            $r->addRoute(['DELETE'], '/user', 'handlerDelete');\n            $r->addRoute([], '/user', 'handlerNone');\n        };\n\n        $cases[] = ['PUT', '/user', $callback, ['GET', 'POST', 'DELETE']];\n\n        // 5\n\n        $callback = function (RouteCollector $r) {\n            $r->addRoute('POST', '/user.json', 'handler0');\n            $r->addRoute('GET', '/{entity}.json', 'handler1');\n        };\n\n        $cases[] = ['PUT', '/user.json', $callback, ['POST', 'GET']];\n\n        // x -------------------------------------------------------------------------------------->\n\n        return $cases;\n    }\n}\n"
  },
  {
    "path": "server/vendor/nikic/fast-route/test/Dispatcher/GroupCountBasedTest.php",
    "content": "<?php\n\nnamespace FastRoute\\Dispatcher;\n\nclass GroupCountBasedTest extends DispatcherTest\n{\n    protected function getDispatcherClass()\n    {\n        return 'FastRoute\\\\Dispatcher\\\\GroupCountBased';\n    }\n\n    protected function getDataGeneratorClass()\n    {\n        return 'FastRoute\\\\DataGenerator\\\\GroupCountBased';\n    }\n}\n"
  },
  {
    "path": "server/vendor/nikic/fast-route/test/Dispatcher/GroupPosBasedTest.php",
    "content": "<?php\n\nnamespace FastRoute\\Dispatcher;\n\nclass GroupPosBasedTest extends DispatcherTest\n{\n    protected function getDispatcherClass()\n    {\n        return 'FastRoute\\\\Dispatcher\\\\GroupPosBased';\n    }\n\n    protected function getDataGeneratorClass()\n    {\n        return 'FastRoute\\\\DataGenerator\\\\GroupPosBased';\n    }\n}\n"
  },
  {
    "path": "server/vendor/nikic/fast-route/test/Dispatcher/MarkBasedTest.php",
    "content": "<?php\n\nnamespace FastRoute\\Dispatcher;\n\nclass MarkBasedTest extends DispatcherTest\n{\n    public function setUp()\n    {\n        preg_match('/(*MARK:A)a/', 'a', $matches);\n        if (!isset($matches['MARK'])) {\n            $this->markTestSkipped('PHP 5.6 required for MARK support');\n        }\n    }\n\n    protected function getDispatcherClass()\n    {\n        return 'FastRoute\\\\Dispatcher\\\\MarkBased';\n    }\n\n    protected function getDataGeneratorClass()\n    {\n        return 'FastRoute\\\\DataGenerator\\\\MarkBased';\n    }\n}\n"
  },
  {
    "path": "server/vendor/nikic/fast-route/test/HackTypechecker/HackTypecheckerTest.php",
    "content": "<?php\n\nnamespace FastRoute;\n\nuse PHPUnit\\Framework\\TestCase;\n\nclass HackTypecheckerTest extends TestCase\n{\n    const SERVER_ALREADY_RUNNING_CODE = 77;\n\n    public function testTypechecks($recurse = true)\n    {\n        if (!defined('HHVM_VERSION')) {\n            $this->markTestSkipped('HHVM only');\n        }\n        if (!version_compare(HHVM_VERSION, '3.9.0', '>=')) {\n          $this->markTestSkipped('classname<T> requires HHVM 3.9+');\n        }\n\n        // The typechecker recurses the whole tree, so it makes sure\n        // that everything in fixtures/ is valid when this runs.\n\n        $output = [];\n        $exit_code = null;\n        exec(\n            'hh_server --check ' . escapeshellarg(__DIR__ . '/../../') . ' 2>&1',\n            $output,\n            $exit_code\n        );\n        if ($exit_code === self::SERVER_ALREADY_RUNNING_CODE) {\n            $this->assertTrue(\n              $recurse,\n              'Typechecker still running after running hh_client stop'\n            );\n            // Server already running - 3.10 => 3.11 regression:\n            // https://github.com/facebook/hhvm/issues/6646\n            exec('hh_client stop 2>/dev/null');\n            $this->testTypechecks(/* recurse = */ false);\n            return;\n\n        }\n        $this->assertSame(0, $exit_code, implode(\"\\n\", $output));\n    }\n}\n"
  },
  {
    "path": "server/vendor/nikic/fast-route/test/HackTypechecker/fixtures/all_options.php",
    "content": "<?hh\n\nnamespace FastRoute\\TestFixtures;\n\nfunction all_options_simple(): \\FastRoute\\Dispatcher {\n    return \\FastRoute\\simpleDispatcher(\n      $collector ==> {},\n      shape(\n        'routeParser' => \\FastRoute\\RouteParser\\Std::class,\n        'dataGenerator' => \\FastRoute\\DataGenerator\\GroupCountBased::class,\n        'dispatcher' => \\FastRoute\\Dispatcher\\GroupCountBased::class,\n        'routeCollector' => \\FastRoute\\RouteCollector::class,\n      ),\n    );\n}\n\nfunction all_options_cached(): \\FastRoute\\Dispatcher {\n    return \\FastRoute\\cachedDispatcher(\n      $collector ==> {},\n      shape(\n        'routeParser' => \\FastRoute\\RouteParser\\Std::class,\n        'dataGenerator' => \\FastRoute\\DataGenerator\\GroupCountBased::class,\n        'dispatcher' => \\FastRoute\\Dispatcher\\GroupCountBased::class,\n        'routeCollector' => \\FastRoute\\RouteCollector::class,\n        'cacheFile' => '/dev/null',\n        'cacheDisabled' => false,\n      ),\n    );\n}\n"
  },
  {
    "path": "server/vendor/nikic/fast-route/test/HackTypechecker/fixtures/empty_options.php",
    "content": "<?hh\n\nnamespace FastRoute\\TestFixtures;\n\nfunction empty_options_simple(): \\FastRoute\\Dispatcher {\n    return \\FastRoute\\simpleDispatcher($collector ==> {}, shape());\n}\n\nfunction empty_options_cached(): \\FastRoute\\Dispatcher {\n    return \\FastRoute\\cachedDispatcher($collector ==> {}, shape());\n}\n"
  },
  {
    "path": "server/vendor/nikic/fast-route/test/HackTypechecker/fixtures/no_options.php",
    "content": "<?hh\n\nnamespace FastRoute\\TestFixtures;\n\nfunction no_options_simple(): \\FastRoute\\Dispatcher {\n    return \\FastRoute\\simpleDispatcher($collector ==> {});\n}\n\nfunction no_options_cached(): \\FastRoute\\Dispatcher {\n    return \\FastRoute\\cachedDispatcher($collector ==> {});\n}\n"
  },
  {
    "path": "server/vendor/nikic/fast-route/test/RouteCollectorTest.php",
    "content": "<?php\n\nnamespace FastRoute;\n\nuse PHPUnit\\Framework\\TestCase;\n\nclass RouteCollectorTest extends TestCase\n{\n    public function testShortcuts()\n    {\n        $r = new DummyRouteCollector();\n\n        $r->delete('/delete', 'delete');\n        $r->get('/get', 'get');\n        $r->head('/head', 'head');\n        $r->patch('/patch', 'patch');\n        $r->post('/post', 'post');\n        $r->put('/put', 'put');\n\n        $expected = [\n            ['DELETE', '/delete', 'delete'],\n            ['GET', '/get', 'get'],\n            ['HEAD', '/head', 'head'],\n            ['PATCH', '/patch', 'patch'],\n            ['POST', '/post', 'post'],\n            ['PUT', '/put', 'put'],\n        ];\n\n        $this->assertSame($expected, $r->routes);\n    }\n\n    public function testGroups()\n    {\n        $r = new DummyRouteCollector();\n\n        $r->delete('/delete', 'delete');\n        $r->get('/get', 'get');\n        $r->head('/head', 'head');\n        $r->patch('/patch', 'patch');\n        $r->post('/post', 'post');\n        $r->put('/put', 'put');\n\n        $r->addGroup('/group-one', function (DummyRouteCollector $r) {\n            $r->delete('/delete', 'delete');\n            $r->get('/get', 'get');\n            $r->head('/head', 'head');\n            $r->patch('/patch', 'patch');\n            $r->post('/post', 'post');\n            $r->put('/put', 'put');\n\n            $r->addGroup('/group-two', function (DummyRouteCollector $r) {\n                $r->delete('/delete', 'delete');\n                $r->get('/get', 'get');\n                $r->head('/head', 'head');\n                $r->patch('/patch', 'patch');\n                $r->post('/post', 'post');\n                $r->put('/put', 'put');\n            });\n        });\n\n        $r->addGroup('/admin', function (DummyRouteCollector $r) {\n            $r->get('-some-info', 'admin-some-info');\n        });\n        $r->addGroup('/admin-', function (DummyRouteCollector $r) {\n            $r->get('more-info', 'admin-more-info');\n        });\n\n        $expected = [\n            ['DELETE', '/delete', 'delete'],\n            ['GET', '/get', 'get'],\n            ['HEAD', '/head', 'head'],\n            ['PATCH', '/patch', 'patch'],\n            ['POST', '/post', 'post'],\n            ['PUT', '/put', 'put'],\n            ['DELETE', '/group-one/delete', 'delete'],\n            ['GET', '/group-one/get', 'get'],\n            ['HEAD', '/group-one/head', 'head'],\n            ['PATCH', '/group-one/patch', 'patch'],\n            ['POST', '/group-one/post', 'post'],\n            ['PUT', '/group-one/put', 'put'],\n            ['DELETE', '/group-one/group-two/delete', 'delete'],\n            ['GET', '/group-one/group-two/get', 'get'],\n            ['HEAD', '/group-one/group-two/head', 'head'],\n            ['PATCH', '/group-one/group-two/patch', 'patch'],\n            ['POST', '/group-one/group-two/post', 'post'],\n            ['PUT', '/group-one/group-two/put', 'put'],\n            ['GET', '/admin-some-info', 'admin-some-info'],\n            ['GET', '/admin-more-info', 'admin-more-info'],\n        ];\n\n        $this->assertSame($expected, $r->routes);\n    }\n}\n\nclass DummyRouteCollector extends RouteCollector\n{\n    public $routes = [];\n\n    public function __construct()\n    {\n    }\n\n    public function addRoute($method, $route, $handler)\n    {\n        $route = $this->currentGroupPrefix . $route;\n        $this->routes[] = [$method, $route, $handler];\n    }\n}\n"
  },
  {
    "path": "server/vendor/nikic/fast-route/test/RouteParser/StdTest.php",
    "content": "<?php\n\nnamespace FastRoute\\RouteParser;\n\nuse PHPUnit\\Framework\\TestCase;\n\nclass StdTest extends TestCase\n{\n    /** @dataProvider provideTestParse */\n    public function testParse($routeString, $expectedRouteDatas)\n    {\n        $parser = new Std();\n        $routeDatas = $parser->parse($routeString);\n        $this->assertSame($expectedRouteDatas, $routeDatas);\n    }\n\n    /** @dataProvider provideTestParseError */\n    public function testParseError($routeString, $expectedExceptionMessage)\n    {\n        $parser = new Std();\n        $this->setExpectedException('FastRoute\\\\BadRouteException', $expectedExceptionMessage);\n        $parser->parse($routeString);\n    }\n\n    public function provideTestParse()\n    {\n        return [\n            [\n                '/test',\n                [\n                    ['/test'],\n                ]\n            ],\n            [\n                '/test/{param}',\n                [\n                    ['/test/', ['param', '[^/]+']],\n                ]\n            ],\n            [\n                '/te{ param }st',\n                [\n                    ['/te', ['param', '[^/]+'], 'st']\n                ]\n            ],\n            [\n                '/test/{param1}/test2/{param2}',\n                [\n                    ['/test/', ['param1', '[^/]+'], '/test2/', ['param2', '[^/]+']]\n                ]\n            ],\n            [\n                '/test/{param:\\d+}',\n                [\n                    ['/test/', ['param', '\\d+']]\n                ]\n            ],\n            [\n                '/test/{ param : \\d{1,9} }',\n                [\n                    ['/test/', ['param', '\\d{1,9}']]\n                ]\n            ],\n            [\n                '/test[opt]',\n                [\n                    ['/test'],\n                    ['/testopt'],\n                ]\n            ],\n            [\n                '/test[/{param}]',\n                [\n                    ['/test'],\n                    ['/test/', ['param', '[^/]+']],\n                ]\n            ],\n            [\n                '/{param}[opt]',\n                [\n                    ['/', ['param', '[^/]+']],\n                    ['/', ['param', '[^/]+'], 'opt']\n                ]\n            ],\n            [\n                '/test[/{name}[/{id:[0-9]+}]]',\n                [\n                    ['/test'],\n                    ['/test/', ['name', '[^/]+']],\n                    ['/test/', ['name', '[^/]+'], '/', ['id', '[0-9]+']],\n                ]\n            ],\n            [\n                '',\n                [\n                    [''],\n                ]\n            ],\n            [\n                '[test]',\n                [\n                    [''],\n                    ['test'],\n                ]\n            ],\n            [\n                '/{foo-bar}',\n                [\n                    ['/', ['foo-bar', '[^/]+']]\n                ]\n            ],\n            [\n                '/{_foo:.*}',\n                [\n                    ['/', ['_foo', '.*']]\n                ]\n            ],\n        ];\n    }\n\n    public function provideTestParseError()\n    {\n        return [\n            [\n                '/test[opt',\n                \"Number of opening '[' and closing ']' does not match\"\n            ],\n            [\n                '/test[opt[opt2]',\n                \"Number of opening '[' and closing ']' does not match\"\n            ],\n            [\n                '/testopt]',\n                \"Number of opening '[' and closing ']' does not match\"\n            ],\n            [\n                '/test[]',\n                'Empty optional part'\n            ],\n            [\n                '/test[[opt]]',\n                'Empty optional part'\n            ],\n            [\n                '[[test]]',\n                'Empty optional part'\n            ],\n            [\n                '/test[/opt]/required',\n                'Optional segments can only occur at the end of a route'\n            ],\n        ];\n    }\n}\n"
  },
  {
    "path": "server/vendor/nikic/fast-route/test/bootstrap.php",
    "content": "<?php\n\nrequire_once __DIR__ . '/../src/functions.php';\n\nspl_autoload_register(function ($class) {\n    if (strpos($class, 'FastRoute\\\\') === 0) {\n        $dir = strcasecmp(substr($class, -4), 'Test') ? 'src/' : 'test/';\n        $name = substr($class, strlen('FastRoute'));\n        require __DIR__ . '/../' . $dir . strtr($name, '\\\\', DIRECTORY_SEPARATOR) . '.php';\n    }\n});\n"
  },
  {
    "path": "server/vendor/php-di/invoker/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) Matthieu Napoli\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "server/vendor/php-di/invoker/README.md",
    "content": "# Invoker\n\nGeneric and extensible callable invoker.\n\n[![CI](https://github.com/PHP-DI/Invoker/actions/workflows/ci.yml/badge.svg)](https://github.com/PHP-DI/Invoker/actions/workflows/ci.yml)\n[![Latest Version](https://img.shields.io/github/release/PHP-DI/invoker.svg?style=flat-square)](https://packagist.org/packages/PHP-DI/invoker)\n[![Total Downloads](https://img.shields.io/packagist/dt/php-di/invoker.svg?style=flat-square)](https://packagist.org/packages/php-di/invoker)\n\n## Why?\n\nWho doesn't need an over-engineered `call_user_func()`?\n\n### Named parameters\n\nDoes this [Silex](https://github.com/silexphp/Silex#readme) example look familiar:\n\n```php\n$app->get('/project/{project}/issue/{issue}', function ($project, $issue) {\n    // ...\n});\n```\n\nOr this command defined with [Silly](https://github.com/mnapoli/silly#usage):\n\n```php\n$app->command('greet [name] [--yell]', function ($name, $yell) {\n    // ...\n});\n```\n\nSame pattern in [Slim](https://www.slimframework.com):\n\n```php\n$app->get('/hello/:name', function ($name) {\n    // ...\n});\n```\n\nYou get the point. These frameworks invoke the controller/command/handler using something akin to named parameters: whatever the order of the parameters, they are matched by their name.\n\n**This library allows to invoke callables with named parameters in a generic and extensible way.**\n\n### Dependency injection\n\nAnyone familiar with AngularJS is familiar with how dependency injection is performed:\n\n```js\nangular.controller('MyController', ['dep1', 'dep2', function(dep1, dep2) {\n    // ...\n}]);\n```\n\nIn PHP we find this pattern again in some frameworks and DI containers with partial to full support. For example in Silex you can type-hint the application to get it injected, but it only works with `Silex\\Application`:\n\n```php\n$app->get('/hello/{name}', function (Silex\\Application $app, $name) {\n    // ...\n});\n```\n\nIn Silly, it only works with `OutputInterface` to inject the application output:\n\n```php\n$app->command('greet [name]', function ($name, OutputInterface $output) {\n    // ...\n});\n```\n\n[PHP-DI](https://php-di.org/doc/container.html) provides a way to invoke a callable and resolve all dependencies from the container using type-hints:\n\n```php\n$container->call(function (Logger $logger, EntityManager $em) {\n    // ...\n});\n```\n\n**This library provides clear extension points to let frameworks implement any kind of dependency injection support they want.**\n\n### TL/DR\n\nIn short, this library is meant to be a base building block for calling a function with named parameters and/or dependency injection.\n\n## Installation\n\n```sh\n$ composer require PHP-DI/invoker\n```\n\n## Usage\n\n### Default behavior\n\nBy default the `Invoker` can call using named parameters:\n\n```php\n$invoker = new Invoker\\Invoker;\n\n$invoker->call(function () {\n    echo 'Hello world!';\n});\n\n// Simple parameter array\n$invoker->call(function ($name) {\n    echo 'Hello ' . $name;\n}, ['John']);\n\n// Named parameters\n$invoker->call(function ($name) {\n    echo 'Hello ' . $name;\n}, [\n    'name' => 'John'\n]);\n\n// Use the default value\n$invoker->call(function ($name = 'world') {\n    echo 'Hello ' . $name;\n});\n\n// Invoke any PHP callable\n$invoker->call(['MyClass', 'myStaticMethod']);\n\n// Using Class::method syntax\n$invoker->call('MyClass::myStaticMethod');\n```\n\nDependency injection in parameters is supported but needs to be configured with your container. Read on or jump to [*Built-in support for dependency injection*](#built-in-support-for-dependency-injection) if you are impatient.\n\nAdditionally, callables can also be resolved from your container. Read on or jump to [*Resolving callables from a container*](#resolving-callables-from-a-container) if you are impatient.\n\n### Parameter resolvers\n\nExtending the behavior of the `Invoker` is easy and is done by implementing a [`ParameterResolver`](https://github.com/PHP-DI/Invoker/blob/master/src/ParameterResolver/ParameterResolver.php).\n\nThis is explained in details the [Parameter resolvers documentation](doc/parameter-resolvers.md).\n\n#### Built-in support for dependency injection\n\nRather than have you re-implement support for dependency injection with different containers every time, this package ships with 2 optional resolvers:\n\n- [`TypeHintContainerResolver`](https://github.com/PHP-DI/Invoker/blob/master/src/ParameterResolver/Container/TypeHintContainerResolver.php)\n\n    This resolver will inject container entries by searching for the class name using the type-hint:\n\n    ```php\n    $invoker->call(function (Psr\\Logger\\LoggerInterface $logger) {\n        // ...\n    });\n    ```\n\n    In this example it will `->get('Psr\\Logger\\LoggerInterface')` from the container and inject it.\n\n    This resolver is only useful if you store objects in your container using the class (or interface) name. Silex or Symfony for example store services under a custom name (e.g. `twig`, `db`, etc.) instead of the class name: in that case use the resolver shown below.\n\n- [`ParameterNameContainerResolver`](https://github.com/PHP-DI/Invoker/blob/master/src/ParameterResolver/Container/ParameterNameContainerResolver.php)\n\n    This resolver will inject container entries by searching for the name of the parameter:\n\n    ```php\n    $invoker->call(function ($twig) {\n        // ...\n    });\n    ```\n\n    In this example it will `->get('twig')` from the container and inject it.\n\nThese resolvers can work with any dependency injection container compliant with [PSR-11](http://www.php-fig.org/psr/psr-11/).\n\nSetting up those resolvers is simple:\n\n```php\n// $container must be an instance of Psr\\Container\\ContainerInterface\n$container = ...\n\n$containerResolver = new TypeHintContainerResolver($container);\n// or\n$containerResolver = new ParameterNameContainerResolver($container);\n\n$invoker = new Invoker\\Invoker;\n// Register it before all the other parameter resolvers\n$invoker->getParameterResolver()->prependResolver($containerResolver);\n```\n\nYou can also register both resolvers at the same time if you wish by prepending both. Implementing support for more tricky things is easy and up to you!\n\n### Resolving callables from a container\n\nThe `Invoker` can be wired to your DI container to resolve the callables.\n\nFor example with an invokable class:\n\n```php\nclass MyHandler\n{\n    public function __invoke()\n    {\n        // ...\n    }\n}\n\n// By default this doesn't work: an instance of the class should be provided\n$invoker->call('MyHandler');\n\n// If we set up the container to use\n$invoker = new Invoker\\Invoker(null, $container);\n// Now 'MyHandler' is resolved using the container!\n$invoker->call('MyHandler');\n```\n\nThe same works for a class method:\n\n```php\nclass WelcomeController\n{\n    public function home()\n    {\n        // ...\n    }\n}\n\n// By default this doesn't work: home() is not a static method\n$invoker->call(['WelcomeController', 'home']);\n\n// If we set up the container to use\n$invoker = new Invoker\\Invoker(null, $container);\n// Now 'WelcomeController' is resolved using the container!\n$invoker->call(['WelcomeController', 'home']);\n// Alternatively we can use the Class::method syntax\n$invoker->call('WelcomeController::home');\n```\n\nThat feature can be used as the base building block for a framework's dispatcher.\n\nAgain, any [PSR-11](https://www.php-fig.org/psr/psr-11/) compliant container can be provided.\n\n"
  },
  {
    "path": "server/vendor/php-di/invoker/composer.json",
    "content": "{\n    \"name\": \"php-di/invoker\",\n    \"description\": \"Generic and extensible callable invoker\",\n    \"keywords\": [\"invoker\", \"dependency-injection\", \"dependency\", \"injection\", \"callable\", \"invoke\"],\n    \"homepage\": \"https://github.com/PHP-DI/Invoker\",\n    \"license\": \"MIT\",\n    \"type\": \"library\",\n    \"autoload\": {\n        \"psr-4\": {\n            \"Invoker\\\\\": \"src/\"\n        }\n    },\n    \"autoload-dev\": {\n        \"psr-4\": {\n            \"Invoker\\\\Test\\\\\": \"tests/\"\n        }\n    },\n    \"require\": {\n        \"php\": \">=7.3\",\n        \"psr/container\": \"^1.0|^2.0\"\n    },\n    \"require-dev\": {\n        \"phpunit/phpunit\": \"^9.0\",\n        \"athletic/athletic\": \"~0.1.8\",\n        \"mnapoli/hard-mode\": \"~0.3.0\"\n    },\n    \"config\": {\n        \"allow-plugins\": {\n            \"dealerdirect/phpcodesniffer-composer-installer\": true\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/invoker/src/CallableResolver.php",
    "content": "<?php declare(strict_types=1);\n\nnamespace Invoker;\n\nuse Closure;\nuse Invoker\\Exception\\NotCallableException;\nuse Psr\\Container\\ContainerInterface;\nuse Psr\\Container\\NotFoundExceptionInterface;\nuse ReflectionException;\nuse ReflectionMethod;\n\n/**\n * Resolves a callable from a container.\n */\nclass CallableResolver\n{\n    /** @var ContainerInterface */\n    private $container;\n\n    public function __construct(ContainerInterface $container)\n    {\n        $this->container = $container;\n    }\n\n    /**\n     * Resolve the given callable into a real PHP callable.\n     *\n     * @param callable|string|array $callable\n     * @return callable Real PHP callable.\n     * @throws NotCallableException|ReflectionException\n     */\n    public function resolve($callable): callable\n    {\n        if (is_string($callable) && strpos($callable, '::') !== false) {\n            $callable = explode('::', $callable, 2);\n        }\n\n        $callable = $this->resolveFromContainer($callable);\n\n        if (! is_callable($callable)) {\n            throw NotCallableException::fromInvalidCallable($callable, true);\n        }\n\n        return $callable;\n    }\n\n    /**\n     * @param callable|string|array $callable\n     * @return callable|mixed\n     * @throws NotCallableException|ReflectionException\n     */\n    private function resolveFromContainer($callable)\n    {\n        // Shortcut for a very common use case\n        if ($callable instanceof Closure) {\n            return $callable;\n        }\n\n        // If it's already a callable there is nothing to do\n        if (is_callable($callable)) {\n            // TODO with PHP 8 that should not be necessary to check this anymore\n            if (! $this->isStaticCallToNonStaticMethod($callable)) {\n                return $callable;\n            }\n        }\n\n        // The callable is a container entry name\n        if (is_string($callable)) {\n            try {\n                return $this->container->get($callable);\n            } catch (NotFoundExceptionInterface $e) {\n                if ($this->container->has($callable)) {\n                    throw $e;\n                }\n                throw NotCallableException::fromInvalidCallable($callable, true);\n            }\n        }\n\n        // The callable is an array whose first item is a container entry name\n        // e.g. ['some-container-entry', 'methodToCall']\n        if (is_array($callable) && is_string($callable[0])) {\n            try {\n                // Replace the container entry name by the actual object\n                $callable[0] = $this->container->get($callable[0]);\n                return $callable;\n            } catch (NotFoundExceptionInterface $e) {\n                if ($this->container->has($callable[0])) {\n                    throw $e;\n                }\n                throw new NotCallableException(sprintf(\n                    'Cannot call %s() on %s because it is not a class nor a valid container entry',\n                    $callable[1],\n                    $callable[0]\n                ));\n            }\n        }\n\n        // Unrecognized stuff, we let it fail later\n        return $callable;\n    }\n\n    /**\n     * Check if the callable represents a static call to a non-static method.\n     *\n     * @param mixed $callable\n     * @throws ReflectionException\n     */\n    private function isStaticCallToNonStaticMethod($callable): bool\n    {\n        if (is_array($callable) && is_string($callable[0])) {\n            [$class, $method] = $callable;\n\n            if (! method_exists($class, $method)) {\n                return false;\n            }\n\n            $reflection = new ReflectionMethod($class, $method);\n\n            return ! $reflection->isStatic();\n        }\n\n        return false;\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/invoker/src/Exception/InvocationException.php",
    "content": "<?php declare(strict_types=1);\n\nnamespace Invoker\\Exception;\n\n/**\n * Impossible to invoke the callable.\n */\nclass InvocationException extends \\Exception\n{\n}\n"
  },
  {
    "path": "server/vendor/php-di/invoker/src/Exception/NotCallableException.php",
    "content": "<?php declare(strict_types=1);\n\nnamespace Invoker\\Exception;\n\n/**\n * The given callable is not actually callable.\n */\nclass NotCallableException extends InvocationException\n{\n    /**\n     * @param mixed $value\n     */\n    public static function fromInvalidCallable($value, bool $containerEntry = false): self\n    {\n        if (is_object($value)) {\n            $message = sprintf('Instance of %s is not a callable', get_class($value));\n        } elseif (is_array($value) && isset($value[0], $value[1])) {\n            $class = is_object($value[0]) ? get_class($value[0]) : $value[0];\n\n            $extra = method_exists($class, '__call') || method_exists($class, '__callStatic')\n                ? ' A __call() or __callStatic() method exists but magic methods are not supported.'\n                : '';\n\n            $message = sprintf('%s::%s() is not a callable.%s', $class, $value[1], $extra);\n        } elseif ($containerEntry) {\n            $message = var_export($value, true) . ' is neither a callable nor a valid container entry';\n        } else {\n            $message = var_export($value, true) . ' is not a callable';\n        }\n\n        return new self($message);\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/invoker/src/Exception/NotEnoughParametersException.php",
    "content": "<?php declare(strict_types=1);\n\nnamespace Invoker\\Exception;\n\n/**\n * Not enough parameters could be resolved to invoke the callable.\n */\nclass NotEnoughParametersException extends InvocationException\n{\n}\n"
  },
  {
    "path": "server/vendor/php-di/invoker/src/Invoker.php",
    "content": "<?php declare(strict_types=1);\n\nnamespace Invoker;\n\nuse Invoker\\Exception\\NotCallableException;\nuse Invoker\\Exception\\NotEnoughParametersException;\nuse Invoker\\ParameterResolver\\AssociativeArrayResolver;\nuse Invoker\\ParameterResolver\\DefaultValueResolver;\nuse Invoker\\ParameterResolver\\NumericArrayResolver;\nuse Invoker\\ParameterResolver\\ParameterResolver;\nuse Invoker\\ParameterResolver\\ResolverChain;\nuse Invoker\\Reflection\\CallableReflection;\nuse Psr\\Container\\ContainerInterface;\nuse ReflectionParameter;\n\n/**\n * Invoke a callable.\n */\nclass Invoker implements InvokerInterface\n{\n    /** @var CallableResolver|null */\n    private $callableResolver;\n\n    /** @var ParameterResolver */\n    private $parameterResolver;\n\n    /** @var ContainerInterface|null */\n    private $container;\n\n    public function __construct(?ParameterResolver $parameterResolver = null, ?ContainerInterface $container = null)\n    {\n        $this->parameterResolver = $parameterResolver ?: $this->createParameterResolver();\n        $this->container = $container;\n\n        if ($container) {\n            $this->callableResolver = new CallableResolver($container);\n        }\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function call($callable, array $parameters = [])\n    {\n        if ($this->callableResolver) {\n            $callable = $this->callableResolver->resolve($callable);\n        }\n\n        if (! is_callable($callable)) {\n            throw new NotCallableException(sprintf(\n                '%s is not a callable',\n                is_object($callable) ? 'Instance of ' . get_class($callable) : var_export($callable, true)\n            ));\n        }\n\n        $callableReflection = CallableReflection::create($callable);\n\n        $args = $this->parameterResolver->getParameters($callableReflection, $parameters, []);\n\n        // Sort by array keys is needed since the resolved arguments returned by the resolver are indexed by numeric keys\n        // that correspond to the parameters of the callable, but may be out of order.\n        ksort($args);\n\n        // Check all parameters are resolved\n        $diff = array_diff_key($callableReflection->getParameters(), $args);\n        $parameter = reset($diff);\n        if ($parameter && \\assert($parameter instanceof ReflectionParameter) && ! $parameter->isVariadic()) {\n            throw new NotEnoughParametersException(sprintf(\n                'Unable to invoke the callable because no value was given for parameter %d ($%s)',\n                $parameter->getPosition() + 1,\n                $parameter->name\n            ));\n        }\n\n        return $callable(...$args);\n    }\n\n    /**\n     * Create the default parameter resolver.\n     */\n    private function createParameterResolver(): ParameterResolver\n    {\n        return new ResolverChain([\n            new NumericArrayResolver,\n            new AssociativeArrayResolver,\n            new DefaultValueResolver,\n        ]);\n    }\n\n    /**\n     * @return ParameterResolver By default it's a ResolverChain\n     */\n    public function getParameterResolver(): ParameterResolver\n    {\n        return $this->parameterResolver;\n    }\n\n    public function getContainer(): ?ContainerInterface\n    {\n        return $this->container;\n    }\n\n    /**\n     * @return CallableResolver|null Returns null if no container was given in the constructor.\n     */\n    public function getCallableResolver(): ?CallableResolver\n    {\n        return $this->callableResolver;\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/invoker/src/InvokerInterface.php",
    "content": "<?php declare(strict_types=1);\n\nnamespace Invoker;\n\nuse Invoker\\Exception\\InvocationException;\nuse Invoker\\Exception\\NotCallableException;\nuse Invoker\\Exception\\NotEnoughParametersException;\n\n/**\n * Invoke a callable.\n */\ninterface InvokerInterface\n{\n    /**\n     * Call the given function using the given parameters.\n     *\n     * @param callable|array|string $callable Function to call.\n     * @param array $parameters Parameters to use.\n     * @return mixed Result of the function.\n     * @throws InvocationException Base exception class for all the sub-exceptions below.\n     * @throws NotCallableException\n     * @throws NotEnoughParametersException\n     */\n    public function call($callable, array $parameters = []);\n}\n"
  },
  {
    "path": "server/vendor/php-di/invoker/src/ParameterResolver/AssociativeArrayResolver.php",
    "content": "<?php declare(strict_types=1);\n\nnamespace Invoker\\ParameterResolver;\n\nuse ReflectionFunctionAbstract;\n\n/**\n * Tries to map an associative array (string-indexed) to the parameter names.\n *\n * E.g. `->call($callable, ['foo' => 'bar'])` will inject the string `'bar'`\n * in the parameter named `$foo`.\n *\n * Parameters that are not indexed by a string are ignored.\n */\nclass AssociativeArrayResolver implements ParameterResolver\n{\n    public function getParameters(\n        ReflectionFunctionAbstract $reflection,\n        array $providedParameters,\n        array $resolvedParameters\n    ): array {\n        $parameters = $reflection->getParameters();\n\n        // Skip parameters already resolved\n        if (! empty($resolvedParameters)) {\n            $parameters = array_diff_key($parameters, $resolvedParameters);\n        }\n\n        foreach ($parameters as $index => $parameter) {\n            if (array_key_exists($parameter->name, $providedParameters)) {\n                $resolvedParameters[$index] = $providedParameters[$parameter->name];\n            }\n        }\n\n        return $resolvedParameters;\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/invoker/src/ParameterResolver/Container/ParameterNameContainerResolver.php",
    "content": "<?php declare(strict_types=1);\n\nnamespace Invoker\\ParameterResolver\\Container;\n\nuse Invoker\\ParameterResolver\\ParameterResolver;\nuse Psr\\Container\\ContainerInterface;\nuse ReflectionFunctionAbstract;\n\n/**\n * Inject entries from a DI container using the parameter names.\n */\nclass ParameterNameContainerResolver implements ParameterResolver\n{\n    /** @var ContainerInterface */\n    private $container;\n\n    /**\n     * @param ContainerInterface $container The container to get entries from.\n     */\n    public function __construct(ContainerInterface $container)\n    {\n        $this->container = $container;\n    }\n\n    public function getParameters(\n        ReflectionFunctionAbstract $reflection,\n        array $providedParameters,\n        array $resolvedParameters\n    ): array {\n        $parameters = $reflection->getParameters();\n\n        // Skip parameters already resolved\n        if (! empty($resolvedParameters)) {\n            $parameters = array_diff_key($parameters, $resolvedParameters);\n        }\n\n        foreach ($parameters as $index => $parameter) {\n            $name = $parameter->name;\n\n            if ($name && $this->container->has($name)) {\n                $resolvedParameters[$index] = $this->container->get($name);\n            }\n        }\n\n        return $resolvedParameters;\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/invoker/src/ParameterResolver/Container/TypeHintContainerResolver.php",
    "content": "<?php declare(strict_types=1);\n\nnamespace Invoker\\ParameterResolver\\Container;\n\nuse Invoker\\ParameterResolver\\ParameterResolver;\nuse Psr\\Container\\ContainerInterface;\nuse ReflectionFunctionAbstract;\nuse ReflectionNamedType;\n\n/**\n * Inject entries from a DI container using the type-hints.\n */\nclass TypeHintContainerResolver implements ParameterResolver\n{\n    /** @var ContainerInterface */\n    private $container;\n\n    /**\n     * @param ContainerInterface $container The container to get entries from.\n     */\n    public function __construct(ContainerInterface $container)\n    {\n        $this->container = $container;\n    }\n\n    public function getParameters(\n        ReflectionFunctionAbstract $reflection,\n        array $providedParameters,\n        array $resolvedParameters\n    ): array {\n        $parameters = $reflection->getParameters();\n\n        // Skip parameters already resolved\n        if (! empty($resolvedParameters)) {\n            $parameters = array_diff_key($parameters, $resolvedParameters);\n        }\n\n        foreach ($parameters as $index => $parameter) {\n            $parameterType = $parameter->getType();\n            if (! $parameterType) {\n                // No type\n                continue;\n            }\n            if (! $parameterType instanceof ReflectionNamedType) {\n                // Union types are not supported\n                continue;\n            }\n            if ($parameterType->isBuiltin()) {\n                // Primitive types are not supported\n                continue;\n            }\n\n            $parameterClass = $parameterType->getName();\n            if ($parameterClass === 'self') {\n                $parameterClass = $parameter->getDeclaringClass()->getName();\n            }\n\n            if ($this->container->has($parameterClass)) {\n                $resolvedParameters[$index] = $this->container->get($parameterClass);\n            }\n        }\n\n        return $resolvedParameters;\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/invoker/src/ParameterResolver/DefaultValueResolver.php",
    "content": "<?php declare(strict_types=1);\n\nnamespace Invoker\\ParameterResolver;\n\nuse ReflectionException;\nuse ReflectionFunctionAbstract;\n\n/**\n * Finds the default value for a parameter, *if it exists*.\n */\nclass DefaultValueResolver implements ParameterResolver\n{\n    public function getParameters(\n        ReflectionFunctionAbstract $reflection,\n        array $providedParameters,\n        array $resolvedParameters\n    ): array {\n        $parameters = $reflection->getParameters();\n\n        // Skip parameters already resolved\n        if (! empty($resolvedParameters)) {\n            $parameters = array_diff_key($parameters, $resolvedParameters);\n        }\n\n        foreach ($parameters as $index => $parameter) {\n            \\assert($parameter instanceof \\ReflectionParameter);\n            if ($parameter->isDefaultValueAvailable()) {\n                try {\n                    $resolvedParameters[$index] = $parameter->getDefaultValue();\n                } catch (ReflectionException $e) {\n                    // Can't get default values from PHP internal classes and functions\n                }\n            } else {\n                $parameterType = $parameter->getType();\n                if ($parameterType && $parameterType->allowsNull()) {\n                    $resolvedParameters[$index] = null;\n                }\n            }\n        }\n\n        return $resolvedParameters;\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/invoker/src/ParameterResolver/NumericArrayResolver.php",
    "content": "<?php declare(strict_types=1);\n\nnamespace Invoker\\ParameterResolver;\n\nuse ReflectionFunctionAbstract;\n\n/**\n * Simply returns all the values of the $providedParameters array that are\n * indexed by the parameter position (i.e. a number).\n *\n * E.g. `->call($callable, ['foo', 'bar'])` will simply resolve the parameters\n * to `['foo', 'bar']`.\n *\n * Parameters that are not indexed by a number (i.e. parameter position)\n * will be ignored.\n */\nclass NumericArrayResolver implements ParameterResolver\n{\n    public function getParameters(\n        ReflectionFunctionAbstract $reflection,\n        array $providedParameters,\n        array $resolvedParameters\n    ): array {\n        // Skip parameters already resolved\n        if (! empty($resolvedParameters)) {\n            $providedParameters = array_diff_key($providedParameters, $resolvedParameters);\n        }\n\n        foreach ($providedParameters as $key => $value) {\n            if (is_int($key)) {\n                $resolvedParameters[$key] = $value;\n            }\n        }\n\n        return $resolvedParameters;\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/invoker/src/ParameterResolver/ParameterResolver.php",
    "content": "<?php declare(strict_types=1);\n\nnamespace Invoker\\ParameterResolver;\n\nuse ReflectionFunctionAbstract;\n\n/**\n * Resolves the parameters to use to call the callable.\n */\ninterface ParameterResolver\n{\n    /**\n     * Resolves the parameters to use to call the callable.\n     *\n     * `$resolvedParameters` contains parameters that have already been resolved.\n     *\n     * Each ParameterResolver must resolve parameters that are not already\n     * in `$resolvedParameters`. That allows to chain multiple ParameterResolver.\n     *\n     * @param ReflectionFunctionAbstract $reflection Reflection object for the callable.\n     * @param array $providedParameters Parameters provided by the caller.\n     * @param array $resolvedParameters Parameters resolved (indexed by parameter position).\n     * @return array\n     */\n    public function getParameters(\n        ReflectionFunctionAbstract $reflection,\n        array $providedParameters,\n        array $resolvedParameters\n    );\n}\n"
  },
  {
    "path": "server/vendor/php-di/invoker/src/ParameterResolver/ResolverChain.php",
    "content": "<?php declare(strict_types=1);\n\nnamespace Invoker\\ParameterResolver;\n\nuse ReflectionFunctionAbstract;\n\n/**\n * Dispatches the call to other resolvers until all parameters are resolved.\n *\n * Chain of responsibility pattern.\n */\nclass ResolverChain implements ParameterResolver\n{\n    /** @var ParameterResolver[] */\n    private $resolvers;\n\n    public function __construct(array $resolvers = [])\n    {\n        $this->resolvers = $resolvers;\n    }\n\n    public function getParameters(\n        ReflectionFunctionAbstract $reflection,\n        array $providedParameters,\n        array $resolvedParameters\n    ): array {\n        $reflectionParameters = $reflection->getParameters();\n\n        foreach ($this->resolvers as $resolver) {\n            $resolvedParameters = $resolver->getParameters(\n                $reflection,\n                $providedParameters,\n                $resolvedParameters\n            );\n\n            $diff = array_diff_key($reflectionParameters, $resolvedParameters);\n            if (empty($diff)) {\n                // Stop traversing: all parameters are resolved\n                return $resolvedParameters;\n            }\n        }\n\n        return $resolvedParameters;\n    }\n\n    /**\n     * Push a parameter resolver after the ones already registered.\n     */\n    public function appendResolver(ParameterResolver $resolver): void\n    {\n        $this->resolvers[] = $resolver;\n    }\n\n    /**\n     * Insert a parameter resolver before the ones already registered.\n     */\n    public function prependResolver(ParameterResolver $resolver): void\n    {\n        array_unshift($this->resolvers, $resolver);\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/invoker/src/ParameterResolver/TypeHintResolver.php",
    "content": "<?php declare(strict_types=1);\n\nnamespace Invoker\\ParameterResolver;\n\nuse ReflectionFunctionAbstract;\nuse ReflectionNamedType;\n\n/**\n * Inject entries using type-hints.\n *\n * Tries to match type-hints with the parameters provided.\n */\nclass TypeHintResolver implements ParameterResolver\n{\n    public function getParameters(\n        ReflectionFunctionAbstract $reflection,\n        array $providedParameters,\n        array $resolvedParameters\n    ): array {\n        $parameters = $reflection->getParameters();\n\n        // Skip parameters already resolved\n        if (! empty($resolvedParameters)) {\n            $parameters = array_diff_key($parameters, $resolvedParameters);\n        }\n\n        foreach ($parameters as $index => $parameter) {\n            $parameterType = $parameter->getType();\n            if (! $parameterType) {\n                // No type\n                continue;\n            }\n            if (! $parameterType instanceof ReflectionNamedType) {\n                // Union types are not supported\n                continue;\n            }\n            if ($parameterType->isBuiltin()) {\n                // Primitive types are not supported\n                continue;\n            }\n\n            $parameterClass = $parameterType->getName();\n            if ($parameterClass === 'self') {\n                $parameterClass = $parameter->getDeclaringClass()->getName();\n            }\n\n            if (array_key_exists($parameterClass, $providedParameters)) {\n                $resolvedParameters[$index] = $providedParameters[$parameterClass];\n            }\n        }\n\n        return $resolvedParameters;\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/invoker/src/Reflection/CallableReflection.php",
    "content": "<?php declare(strict_types=1);\n\nnamespace Invoker\\Reflection;\n\nuse Closure;\nuse Invoker\\Exception\\NotCallableException;\nuse ReflectionException;\nuse ReflectionFunction;\nuse ReflectionFunctionAbstract;\nuse ReflectionMethod;\n\n/**\n * Create a reflection object from a callable or a callable-like.\n *\n * @internal\n */\nclass CallableReflection\n{\n    /**\n     * @param callable|array|string $callable Can be a callable or a callable-like.\n     * @throws NotCallableException|ReflectionException\n     */\n    public static function create($callable): ReflectionFunctionAbstract\n    {\n        // Closure\n        if ($callable instanceof Closure) {\n            return new ReflectionFunction($callable);\n        }\n\n        // Array callable\n        if (is_array($callable)) {\n            [$class, $method] = $callable;\n\n            if (! method_exists($class, $method)) {\n                throw NotCallableException::fromInvalidCallable($callable);\n            }\n\n            return new ReflectionMethod($class, $method);\n        }\n\n        // Callable object (i.e. implementing __invoke())\n        if (is_object($callable) && method_exists($callable, '__invoke')) {\n            return new ReflectionMethod($callable, '__invoke');\n        }\n\n        // Standard function\n        if (is_string($callable) && function_exists($callable)) {\n            return new ReflectionFunction($callable);\n        }\n\n        throw new NotCallableException(sprintf(\n            '%s is not a callable',\n            is_string($callable) ? $callable : 'Instance of ' . get_class($callable)\n        ));\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) Matthieu Napoli\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and\nassociated documentation files (the \"Software\"), to deal in the Software without restriction,\nincluding without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,\nand/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial\nportions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT\nNOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\nWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "server/vendor/php-di/php-di/README.md",
    "content": "---\nlayout: home\n---\n\n[![](doc/img.png)](https://php-di.org/)\n\n[![Downloads per months](https://img.shields.io/packagist/dm/PHP-DI/PHP-DI.svg?style=flat-square)](https://packagist.org/packages/PHP-DI/PHP-DI)\n[![Total downloads](https://img.shields.io/packagist/dt/PHP-DI/PHP-DI.svg?style=flat-square)](https://packagist.org/packages/PHP-DI/PHP-DI)\n\n[![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/PHP-DI/PHP-DI.svg)](http://isitmaintained.com/project/PHP-DI/PHP-DI \"Average time to resolve an issue\")\n[![Percentage of issues still open](http://isitmaintained.com/badge/open/PHP-DI/PHP-DI.svg)](http://isitmaintained.com/project/PHP-DI/PHP-DI \"Percentage of issues still open\")\n\nPHP-DI is a dependency injection container meant to be practical, powerful, and framework-agnostic.\n\nRead more on the website: **[php-di.org](https://php-di.org)**\n\nGet community support in the Gitter chat room: [![Gitter chat](https://badges.gitter.im/PHP-DI/PHP-DI.png)](https://gitter.im/PHP-DI/PHP-DI)\n\n## For Enterprise\n\n*Available as part of the Tidelift Subscription*\n\nThe maintainers of php-di/php-di and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/packagist-php-di-php-di?utm_source=packagist-php-di-php-di&utm_medium=referral&utm_campaign=enterprise&utm_term=repo)\n"
  },
  {
    "path": "server/vendor/php-di/php-di/change-log.md",
    "content": "# Change log\n\n## 6.1.0\n\n- [#791](https://github.com/PHP-DI/PHP-DI/issues/791) Support PHP 8.1, remove support for PHP 7.2\n\n## 6.0.2\n\n- Fix potential regression introduced when fixing [#582](https://github.com/PHP-DI/PHP-DI/issues/582)\n\n## 6.0.1\n\n- Fix [#526](https://github.com/PHP-DI/PHP-DI/issues/526): Support optional parameters in factories\n- [#585](https://github.com/PHP-DI/PHP-DI/issues/585) Add support for PHP-Parser 4.0\n- [#582](https://github.com/PHP-DI/PHP-DI/issues/582) Register `ContainerInterface` to point to the wrapper container if it was defined\n\n## 6.0\n\nThis is the complete change log. You can also read the [migration guide](doc/migration/6.0.md) for upgrading or the [blog article](news/22-php-di-6-0-released.md) to see what's new.\n\nImprovements:\n\n- [#494](https://github.com/PHP-DI/PHP-DI/pull/494) The container can now be compiled for optimum performances in production\n- [#294](https://github.com/PHP-DI/PHP-DI/issues/294), [#349](https://github.com/PHP-DI/PHP-DI/issues/349), [#449](https://github.com/PHP-DI/PHP-DI/pull/449): `DI\\object()` has been replaced by more specific and less ambiguous helpers:\n    - `DI\\create()` creates an object, overrides autowiring and previous definitions\n    - `DI\\autowire()` autowires an object and allows to override specific constructor and method parameters\n- The container can now be built without parameters: `new Container()`\n- Definitions can be nested:\n    - [#490](https://github.com/PHP-DI/PHP-DI/issues/490) Definitions can be nested in arrays (by [@yuloh](https://github.com/yuloh))\n    - [#501](https://github.com/PHP-DI/PHP-DI/issues/501) & [#540](https://github.com/PHP-DI/PHP-DI/issues/540) Autowire definitions can be nested in other definitions\n    - [#487](https://github.com/PHP-DI/PHP-DI/issues/487) & [#540](https://github.com/PHP-DI/PHP-DI/issues/540) Closures are now handled as factories when they are nested in other definitions\n- [#487](https://github.com/PHP-DI/PHP-DI/issues/487) Closures in the config are now always interpreted as factories, even when nested inside other definitions\n- [#242](https://github.com/PHP-DI/PHP-DI/issues/242) Error in case a definition is not indexed by a string\n- [#505](https://github.com/PHP-DI/PHP-DI/pull/505) Debug container entries\n- [#564](https://github.com/PHP-DI/PHP-DI/pull/564) Caching was made almost entirely obsolete by the container compilation, however there is still a caching system entirely rebuilt over APCu for covering the last cases that compilation could not address (see [php-di.org/doc/performances.html](https://php-di.org/doc/performances.html))\n\nFixes:\n\n- [#499](https://github.com/PHP-DI/PHP-DI/issues/499) & [#488](https://github.com/PHP-DI/PHP-DI/issues/488) Standardize resolution of nested definitions everywhere.\n    In PHP-DI 5, definitions could be nested in some places (e.g. use a get() in an object definition, etc.). However it did not behave everywhere the same, for example it didn't work for sub-definitions in arrays.\n    Now in PHP-DI 6 all nested definitions will all be recognized and resolved correctly everywhere. Since #494 (compiled container) performance will not be affected so we can implement a more robust behavior.\n- [#343](https://github.com/PHP-DI/PHP-DI/issues/343) Autowiring and Annotations do not work for `object()` inside arrays: it now works with the new `create()` and `autowire()` helpers\n\nBC breaks:\n\n- PHP 7 or greater is required and HHVM is no longer supported\n- `DI\\object()` has been removed, use `DI\\create()` or `DI\\autowire()` instead\n- [#409](https://github.com/PHP-DI/PHP-DI/issues/409): Scopes are removed, read more in the [scopes](doc/scopes.md) documentation.\n- Caching was replaced by compiling the container: `ContainerBuilder::setDefinitionCache()` was removed, use `ContainerBuilder::enableCompilation()` instead.\n- [#463](https://github.com/PHP-DI/PHP-DI/issues/463) & [#485](https://github.com/PHP-DI/PHP-DI/issues/485): Container-interop support was removed, PSR-11 is used instead (by [@juliangut](https://github.com/juliangut))\n- The deprecated `DI\\link()` helper was removed, used `DI\\get()` instead\n- [#484](https://github.com/PHP-DI/PHP-DI/pull/484) The deprecated `\\DI\\Debug` class has been removed. Definitions can be cast to string directly\n- The exception `DI\\Definition\\Exception\\DefinitionException` was renamed to `DI\\Definition\\Exception\\InvalidDefinition`\n- The exception `DI\\Definition\\Exception\\AnnotationException` was renamed to `DI\\Definition\\Exception\\InvalidAnnotation`\n- [#516](https://github.com/PHP-DI/PHP-DI/issues/516) `DI\\InvokerInterface` was removed in favor of `Invoker\\InvokerInterface`.\n\nBe also aware that internal classes or interfaces may have changed.\n\n## 5.4.6\n\n- Fix [#554](https://github.com/PHP-DI/PHP-DI/issues/554): `Container::make()` fails when combined with `decorate()`.\n\n## 5.4.5\n\nFixup of 5.4.4.\n\n- [#531](https://github.com/PHP-DI/PHP-DI/issues/531): performance improvement.\n\n## 5.4.4\n\nThis release was broken because it was tagged against the wrong branch.\n\n- [#531](https://github.com/PHP-DI/PHP-DI/issues/531): performance improvement.\n\n## 5.4.3\n\n- [#467](https://github.com/PHP-DI/PHP-DI/issues/467): register the container against the PSR ContainerInterface\n\n## 5.4.2\n\n- Minor patch to add the `provide: psr/container-implementation` to `composer.json`.\n\n## 5.4.1\n\n- [PSR-11](http://www.php-fig.org/psr/) compliance\n\nNote that PHP-DI was already compliant with PSR-11 because it was implementing container-interop, and container-interop 1.2 extends PSR-11. This new version just makes it more explicit and will allow to drop container-interop support in the next major versions.\n\n## 5.4\n\nRead the [news entry](news/20-php-di-5-4-released.md).\n\nNew features:\n\n- [#362](https://github.com/PHP-DI/PHP-DI/issues/362) implemented in [#428](https://github.com/PHP-DI/PHP-DI/pull/428), [#430](https://github.com/PHP-DI/PHP-DI/pull/430), [#431](https://github.com/PHP-DI/PHP-DI/pull/431) and [#432](https://github.com/PHP-DI/PHP-DI/pull/432): factory parameters can now be configured, for example:\n    ```php\n    return [\n        'Database' => DI\\factory(function ($host) {...})\n            ->parameter('host', DI\\get('db.host')),\n    ];\n    ```\n    Read the [factories documentation](https://php-di.org/doc/php-definitions.html#factories) to learn more. Feature implemented by [@predakanga](https://github.com/predakanga).\n\nImprovements:\n\n- [#429](https://github.com/PHP-DI/PHP-DI/pull/429): performance improvements in definition resolution (by [@mnapoli](https://github.com/mnapoli))\n- [#421](https://github.com/PHP-DI/PHP-DI/issues/421): once a `ContainerBuilder` has built a container, it is locked to prevent confusion when adding new definitions to it (by [@mnapoli](https://github.com/mnapoli))\n- [#423](https://github.com/PHP-DI/PHP-DI/pull/423): improved exception messages (by [@mnapoli](https://github.com/mnapoli))\n\n## 5.3\n\nRead the [news entry](news/19-php-di-5-3-released.md).\n\n- release of the [2.0 version](https://github.com/PHP-DI/Symfony-Bridge/releases/tag/2.0.0) of the Symfony bridge (by [@mnapoli](https://github.com/mnapoli))\n- PHP 5.5 or above is now required\n- a lot of documentation improvements by 9 different contributors\n- [#389](https://github.com/PHP-DI/PHP-DI/pull/389): exception message improvement by [@mopahle](https://github.com/mopahle)\n- [#359](https://github.com/PHP-DI/PHP-DI/issues/359), [#411](https://github.com/PHP-DI/PHP-DI/issues/411), [#414](https://github.com/PHP-DI/PHP-DI/pull/414), [#412](https://github.com/PHP-DI/PHP-DI/pull/412): compatibility with ProxyManager 1.* and 2.* (by [@holtkamp](https://github.com/holtkamp) and [@mnapoli](https://github.com/mnapoli))\n- [#416](https://github.com/PHP-DI/PHP-DI/pull/416): dumping definitions was refactored into a more lightweight and simple solution; definition \"dumpers\" have been removed (internal classes), definitions can now be cast to string directly (by [@mnapoli](https://github.com/mnapoli))\n\n## 5.2\n\nRead the [news entry](news/17-php-di-5-2-released.md).\n\nImprovements:\n\n- [#347](https://github.com/PHP-DI/PHP-DI/pull/347) (includes [#333](https://github.com/PHP-DI/PHP-DI/pull/333) and [#345](https://github.com/PHP-DI/PHP-DI/pull/345)): by [@jdreesen](https://github.com/jdreesen), [@quimcalpe](https://github.com/quimcalpe) and [@mnapoli](https://github.com/mnapoli)\n    - Allow injection of any container object as factory parameter via type hinting\n    - Allow injection of a `DI\\Factory\\RequestedEntry` object to get the requested entry name\n- [#272](https://github.com/PHP-DI/PHP-DI/issues/272): Support `\"Class::method\"\"` syntax for callables (by [@jdreesen](https://github.com/jdreesen))\n- [#332](https://github.com/PHP-DI/PHP-DI/issues/332): IDE support (plugin and documentation) (by [@pulyaevskiy](https://github.com/pulyaevskiy), [@avant1](https://github.com/avant1) and [@mnapoli](https://github.com/mnapoli))\n- [#326](https://github.com/PHP-DI/PHP-DI/pull/326): Exception messages are simpler and more consistent (by [@mnapoli](https://github.com/mnapoli))\n- [#325](https://github.com/PHP-DI/PHP-DI/pull/325): Add a \"Edit this page\" button in the website to encourage users to improve the documentation (by [@jdreesen](https://github.com/jdreesen))\n\nBugfixes:\n\n- [#321](https://github.com/PHP-DI/PHP-DI/pull/321): Allow factory definitions to reference arbitrary container entries as callables (by [@jdreesen](https://github.com/jdreesen))\n- [#335](https://github.com/PHP-DI/PHP-DI/issues/335): Class imports in traits are now considered when parsing annotations (by [@thebigb](https://github.com/thebigb))\n\n## 5.1\n\nRead the [news entry](news/16-php-di-5-1-released.md).\n\nImprovements:\n\n- [Zend Framework 2 integration](https://github.com/PHP-DI/ZF2-Bridge) (by @Rastusik)\n- [#308](https://github.com/PHP-DI/PHP-DI/pull/308): Instantiate factories using the container (`DI\\factory(['FooFactory', 'create'])`)\n- Many performances improvements - some benchmarks show up to 35% performance improvements, real results may vary of course\n- Many documentation improvements (@jdreesen, @mindplay-dk, @mnapoli, @holtkamp, @Rastusik)\n- [#296](https://github.com/PHP-DI/PHP-DI/issues/296): Provide a faster `ArrayCache` implementation, mostly useful in micro-benchmarks\n\nBugfixes:\n\n- [#257](https://github.com/PHP-DI/PHP-DI/issues/257) & [#274](https://github.com/PHP-DI/PHP-DI/issues/274): Private properties of parent classes are not injected when using annotations\n- [#300](https://github.com/PHP-DI/PHP-DI/pull/300): Exception if object definition extends an incompatible definition\n- [#306](https://github.com/PHP-DI/PHP-DI/issues/306): Errors when using parameters passed by reference (fixed by @bradynpoulsen)\n- [#318](https://github.com/PHP-DI/PHP-DI/issues/318): `Container::call()` ignores parameter's default value\n\nInternal changes:\n\n- [#276](https://github.com/PHP-DI/PHP-DI/pull/276): Tests now pass on Windows (@bgaillard)\n\n## 5.0\n\nThis is the complete change log. You can also read the [migration guide](doc/migration/5.0.md) for upgrading, or [the news article](news/15-php-di-5-0-released.md) for a nicer introduction to this new version.\n\nImprovements:\n\n- Moved to an organization on GitHub: [github.com/PHP-DI/PHP-DI](https://github.com/PHP-DI/PHP-DI)\n- The package has been renamed to: from `mnapoli/php-di` to [`php-di/php-di`](https://packagist.org/packages/php-di/php-di)\n- New [Silex integration](doc/frameworks/silex.md)\n- Lighter package: from 10 to 3 Composer dependencies!\n- [#235](https://github.com/PHP-DI/PHP-DI/issues/235): `DI\\link()` is now deprecated in favor of `DI\\get()`. There is no BC break as `DI\\link()` still works.\n- [#207](https://github.com/PHP-DI/PHP-DI/issues/207): Support for `DI\\link()` in arrays\n- [#203](https://github.com/PHP-DI/PHP-DI/issues/203): New `DI\\string()` helper ([documentation](doc/php-definitions.md))\n- [#208](https://github.com/PHP-DI/PHP-DI/issues/208): Support for nested definitions\n- [#226](https://github.com/PHP-DI/PHP-DI/pull/226): `DI\\factory()` can now be omitted with closures:\n\n    ```php\n    // before\n    'My\\Class' => DI\\factory(function () { ... })\n    // now (optional shortcut)\n    'My\\Class' => function () { ... }\n    ```\n- [#193](https://github.com/PHP-DI/PHP-DI/issues/193): `DI\\object()->method()` now supports calling the same method twice (or more).\n- [#248](https://github.com/PHP-DI/PHP-DI/issues/248): New `DI\\decorate()` helper to decorate a previously defined entry ([documentation](doc/definition-overriding.md))\n- [#215](https://github.com/PHP-DI/PHP-DI/pull/215): New `DI\\add()` helper to add entries to an existing array ([documentation](doc/definition-overriding.md))\n- [#218](https://github.com/PHP-DI/PHP-DI/issues/218): `ContainerBuilder::addDefinitions()` can now take an array of definitions\n- [#211](https://github.com/PHP-DI/PHP-DI/pull/211): `ContainerBuilder::addDefinitions()` is now fluent (return `$this`)\n- [#250](https://github.com/PHP-DI/PHP-DI/issues/250): `Container::call()` now also accepts parameters not indexed by name as well as embedded definitions ([documentation](doc/container.md))\n- Various performance improvements, e.g. lower the number of files loaded, simpler architecture, …\n\nBC breaks:\n\n- PHP-DI now requires a version of PHP >= 5.4.0\n- The package is lighter by default:\n    - [#251](https://github.com/PHP-DI/PHP-DI/issues/251): Annotations are disabled by default, if you use annotations enable them with `$containerBuilder->useAnnotations(true)`. Additionally the `doctrine/annotations` package isn't required by default anymore, so you also need to run `composer require doctrine/annotations`.\n    - `doctrine/cache` is not installed by default anymore, you need to require it in `composer.json` (`~1.0`) if you want to configure a cache for PHP-DI\n    - [#198](https://github.com/PHP-DI/PHP-DI/issues/198): `ocramius/proxy-manager` is not installed by default anymore, you need to require it in `composer.json` (`~1.0`) if you want to use **lazy injection**\n- Closures are now converted into factory definitions automatically. If you ever defined a closure as a value (e.g. to have the closure injected in a class), you need to wrap the closure with the new `DI\\value()` helper.\n- [#223](https://github.com/PHP-DI/PHP-DI/issues/223): `DI\\ContainerInterface` was deprecated since v4.1 and has been removed\n\nInternal changes in case you were replacing/extending some parts:\n\n- the definition sources architecture has been refactored, if you defined custom definition sources you will need to update your code (it should be much easier now)\n- [#252](https://github.com/PHP-DI/PHP-DI/pull/252): `DI\\Scope` internal implementation has changed. You are encouraged to use the constants (`DI\\Scope::SINGLETON` and `DI\\Scope::PROTOTYPE`) instead of the static methods, but backward compatibility is kept (static methods still work).\n- [#241](https://github.com/PHP-DI/PHP-DI/issues/241): `Container::call()` now uses the *Invoker* external library\n\n## 4.4\n\nRead the [news entry](news/13-php-di-4-4-released.md).\n\n- [#185](https://github.com/PHP-DI/PHP-DI/issues/185) Support for invokable objects in `Container::call()`\n- [#192](https://github.com/PHP-DI/PHP-DI/pull/192) Support for invokable classes in `Container::call()` (will instantiate the class)\n- [#184](https://github.com/PHP-DI/PHP-DI/pull/184) Option to ignore phpdoc errors\n\n## 4.3\n\nRead the [news entry](news/11-php-di-4-3-released.md).\n\n- [#176](https://github.com/PHP-DI/PHP-DI/pull/176) New definition type for reading environment variables: `DI\\env()`\n- [#181](https://github.com/PHP-DI/PHP-DI/pull/181) `DI\\FactoryInterface` and `DI\\InvokerInterface` are now auto-registered inside the container so that you can inject them without any configuration needed\n- [#173](https://github.com/PHP-DI/PHP-DI/pull/173) `$container->call(['MyClass', 'method]);` will get `MyClass` from the container if `method()` is not a static method\n\n## 4.2.2\n\n- Fixed [#180](https://github.com/PHP-DI/PHP-DI/pull/180): `Container::call()` with object methods (`[$object, 'method']`) is now supported\n\n## 4.2.1\n\n- Support for PHP 5.3.3, which was previously incomplete because of a bug in the reflection (there is now a workaround for this bug)\n\nBut if you can, seriously avoid this (really old) PHP version and upgrade.\n\n## 4.2\n\nRead the [news entry](news/10-php-di-4-2-released.md).\n\n**Minor BC-break**: Optional parameters (that were not configured) were injected, they are now ignored, which is what naturally makes sense since they are optional.\nExample:\n\n```php\n    public function __construct(Bar $bar = null)\n    {\n        $this->bar = $bar ?: $this->createDefaultBar();\n    }\n```\n\nBefore 4.2, PHP-DI would try to inject a `Bar` instance. From 4.2 and onwards, it will inject `null`.\n\nOf course, you can still explicitly define an injection for the optional parameters and that will work.\n\nAll changes:\n\n* [#162](https://github.com/PHP-DI/PHP-DI/pull/162) Added `Container::call()` to call functions with dependency injection\n* [#156](https://github.com/PHP-DI/PHP-DI/issues/156) Wildcards (`*`) in definitions\n* [#164](https://github.com/PHP-DI/PHP-DI/issues/164) Prototype scope is now available for `factory()` definitions too\n* FIXED [#168](https://github.com/PHP-DI/PHP-DI/pull/168) `Container::has()` now returns false for interfaces and abstract classes that are not mapped in the definitions\n* FIXED [#171](https://github.com/PHP-DI/PHP-DI/issues/171) Optional parameters are now ignored (not injected) if not set in the definitions (see the BC-break warning above)\n\n## 4.1\n\nRead the [news entry](news/09-php-di-4-1-released.md).\n\nBC-breaks: None.\n\n* [#138](https://github.com/PHP-DI/PHP-DI/issues/138) [Container-interop](https://github.com/container-interop/container-interop) compliance\n* [#143](https://github.com/PHP-DI/PHP-DI/issues/143) Much more explicit exception messages\n* [#157](https://github.com/PHP-DI/PHP-DI/issues/157) HHVM support\n* [#158](https://github.com/PHP-DI/PHP-DI/issues/158) Improved the documentation for [Symfony 2 integration](https://php-di.org/doc/frameworks/symfony2.html)\n\n## 4.0\n\nMajor changes:\n\n* The configuration format has changed ([read more here to understand why](news/06-php-di-4-0-new-definitions.md))\n\nRead the migration guide if you are using 3.x: [Migration guide from 3.x to 4.0](doc/migration/4.0.md).\n\nBC-breaks:\n\n* YAML, XML and JSON definitions have been removed, and the PHP definition format has changed (see above)\n* `ContainerSingleton` has been removed\n* You cannot configure an injection as lazy anymore, you can only configure a container entry as lazy\n* The Container constructor now takes mandatory parameters. Use the ContainerBuilder to create a Container.\n* Removed `ContainerBuilder::setDefinitionsValidation()` (no definition validation anymore)\n* `ContainerBuilder::useReflection()` is now named: `ContainerBuilder::useAutowiring()`\n* `ContainerBuilder::addDefinitionsFromFile()` is now named: `ContainerBuilder::addDefinitions()`\n* The `$proxy` parameter in `Container::get($name, $proxy = true)` hase been removed. To get a proxy, you now need to define an entry as \"lazy\".\n\nOther changes:\n\n* Added `ContainerInterface` and `FactoryInterface`, both implemented by the container.\n* [#115](https://github.com/PHP-DI/PHP-DI/issues/115) Added `Container::has()`\n* [#142](https://github.com/PHP-DI/PHP-DI/issues/142) Added `Container::make()` to resolve an entry\n* [#127](https://github.com/PHP-DI/PHP-DI/issues/127) Added support for cases where PHP-DI is wrapped by another container (like Acclimate): PHP-DI can now use the wrapping container to perform injections\n* [#128](https://github.com/PHP-DI/PHP-DI/issues/128) Configure entry aliases\n* [#110](https://github.com/PHP-DI/PHP-DI/issues/110) XML definitions are not supported anymore\n* [#122](https://github.com/PHP-DI/PHP-DI/issues/122) JSON definitions are not supported anymore\n* `ContainerSingleton` has finally been removed\n* Added `ContainerBuilder::buildDevContainer()` to get started with a default container very easily.\n* [#99](https://github.com/PHP-DI/PHP-DI/issues/99) Fixed \"`@param` with PHP internal type throws exception\"\n\n## 3.5.1\n\n* FIXED [#126](https://github.com/PHP-DI/PHP-DI/issues/126): `Container::set` without effect if a value has already been set and retrieved\n\n## 3.5\n\nRead the [news entry](news/05-php-di-3-5.md).\n\n* Importing `@Inject` and `@Injectable` annotations is now optional! It means that you don't have to write `use DI\\Annotation\\Inject` anymore\n* FIXED [#124](https://github.com/PHP-DI/PHP-DI/issues/124): `@Injects` annotation conflicts with other annotations\n\n## 3.4\n\nRead the [news entry](news/04-php-di-3-4.md).\n\n* [#106](https://github.com/PHP-DI/PHP-DI/pull/106) You can now define arrays of values (in YAML, PHP, …) thanks to [@unkind](https://github.com/unkind)\n* [#98](https://github.com/PHP-DI/PHP-DI/issues/98) `ContainerBuilder` is now fluent thanks to [@drdamour](https://github.com/drdamour)\n* [#101](https://github.com/PHP-DI/PHP-DI/pull/101) Optional parameters are now supported: if you don't define a value to inject, their default value will be used\n* XML definitions have been deprecated, there weren't even documented and were not maintained. They will be removed in 4.0.\n* FIXED [#100](https://github.com/PHP-DI/PHP-DI/issues/100): bug for lazy injection in constructors\n\n## 3.3\n\nRead the [news entry](news/03-php-di-3-3.md).\n\n* Inject dependencies on an existing instance with `Container::injectOn` (work from [Jeff Flitton](https://github.com/jflitton): [#89](https://github.com/PHP-DI/PHP-DI/pull/89)).\n* [#86](https://github.com/PHP-DI/PHP-DI/issues/86): Optimized definition lookup (faster)\n* FIXED [#87](https://github.com/PHP-DI/PHP-DI/issues/87): Rare bug in the `PhpDocParser`, fixed by [drdamour](https://github.com/drdamour)\n\n## 3.2\n\nRead the [news entry](news/02-php-di-3-2.md).\n\nSmall BC-break: PHP-DI 3.0 and 3.1 injected properties before calling the constructor. This was confusing and [not supported for internal classes](https://github.com/PHP-DI/PHP-DI/issues/74).\nFrom 3.2 and on, properties are injected after calling the constructor.\n\n* **[Lazy injection](doc/lazy-injection.md)**: it is now possible to use lazy injection on properties and methods (setters and constructors).\n* Lazy dependencies are now proxies that extend the class they proxy, so type-hinting works.\n* Addition of the **`ContainerBuilder`** object, that helps to [create and configure a `Container`](doc/container-configuration.md).\n* Some methods for configuring the Container have gone **deprecated** in favor of the `ContainerBuilder`. Fear not, these deprecated methods will remain until next major version (4.0).\n    * `Container::useReflection`, use ContainerBuilder::useReflection instead\n    * `Container::useAnnotations`, use ContainerBuilder::useAnnotations instead\n    * `Container::setDefinitionCache`, use ContainerBuilder::setDefinitionCache instead\n    * `Container::setDefinitionsValidation`, use ContainerBuilder::setDefinitionsValidation instead\n* The container is now auto-registered (as 'DI\\Container'). You can now inject the container without registering it.\n\n## 3.1.1\n\n* Value definitions (`$container->set('foo', 80)`) are not cached anymore\n* FIXED [#82](https://github.com/PHP-DI/PHP-DI/issues/82): Serialization error when using a cache\n\n## 3.1\n\nRead the [news entry](news/01-php-di-3-1.md).\n\n* Zend Framework 1 integration through the [PHP-DI-ZF1 project](https://github.com/PHP-DI/PHP-DI-ZF1)\n* Fixed the order of priorities when you mix different definition sources (reflection, annotations, files, …). See [Definition overriding](doc/definition-overriding.md)\n* Now possible to define null values with  `$container->set('foo', null)` (see [#79](https://github.com/PHP-DI/PHP-DI/issues/79)).\n* Deprecated usage of `ContainerSingleton`, will be removed in next major version (4.0)\n\n## 3.0.6\n\n* FIXED [#76](https://github.com/PHP-DI/PHP-DI/issues/76): Definition conflict when setting a closure for a class name\n\n## 3.0.5\n\n* FIXED [#70](https://github.com/PHP-DI/PHP-DI/issues/70): Definition conflict when setting a value for a class name\n\n## 3.0.4\n\n* FIXED [#69](https://github.com/PHP-DI/PHP-DI/issues/69): YamlDefinitionFileLoader crashes if YAML file is empty\n\n## 3.0.3\n\n* Fixed over-restrictive dependencies in composer.json\n\n## 3.0.2\n\n* [#64](https://github.com/PHP-DI/PHP-DI/issues/64): Non PHP-DI exceptions are not captured-rethrown anymore when injecting dependencies (cleaner stack trace)\n\n## 3.0.1\n\n* [#62](https://github.com/PHP-DI/PHP-DI/issues/62): When using aliases, definitions are now merged\n\n## 3.0\n\nMajor compatibility breaks with 2.x.\n\n* The container is no longer a Singleton (but `ContainerSingleton::getInstance()` is available for fools who like it)\n* Setter injection\n* Constructor injection\n* Scopes: singleton (share the same instance of the class) or prototype (create a new instance each time it is fetched). Defined at class level.\n* Configuration is reworked from scratch. Now every configuration backend can do 100% of the job.\n* Provided configuration backends:\n    * Reflection\n    * Annotations: @Inject, @Injectable\n    * PHP code (`Container::set()`)\n    * PHP array\n    * YAML file\n* As a consequence, annotations are not mandatory anymore, all functionalities can be used with or without annotations.\n* Renamed `DI\\Annotations\\` to `DI\\Annotation\\`\n* `Container` no longer implements ArrayAccess, use only `$container->get($key)` now\n* ZF1 integration broken and removed (work in progress for next releases)\n* Code now follows PSR1 and PSR2 coding styles\n* FIXED: [#58](https://github.com/PHP-DI/PHP-DI/issues/58) Getting a proxy of an alias didn't work\n\n## 2.1\n\n* `use` statements to import classes from other namespaces are now taken into account with the `@var` annotation\n* Updated and lightened the dependencies : `doctrine/common` has been replaced with more specific `doctrine/annotations` and `doctrine/cache`\n\n## 2.0\n\nMajor compatibility breaks with 1.x.\n\n* `Container::resolveDependencies()` has been renamed to `Container::injectAll()`\n* Dependencies are now injected **before** the constructor is called, and thus are available in the constructor\n* Merged `@Value` annotation with `@Inject`: no difference between value and bean injection anymore\n* Container implements ArrayAccess for get() and set() (`$container['db.host'] = 'localhost';`)\n* Ini configuration files removed: configuration is done in PHP\n* Allow to define beans within closures for lazy-loading\n* Switched to MIT License\n\nWarning:\n\n* If you use PHP 5.3 and __wakeup() methods, they will be called when PHP-DI creates new instances of those classes.\n\n## 1.1\n\n* Caching of annotations based on Doctrine caches\n\n## 1.0\n\n* DependencyManager renamed to Container\n* Refactored basic Container usage with `get` and `set`\n* Allow named injection `@Inject(name=\"\")`\n* Zend Framework integration\n"
  },
  {
    "path": "server/vendor/php-di/php-di/composer.json",
    "content": "{\n    \"name\": \"php-di/php-di\",\n    \"type\": \"library\",\n    \"description\": \"The dependency injection container for humans\",\n    \"keywords\": [\"di\", \"dependency injection\", \"container\", \"ioc\", \"psr-11\", \"psr11\", \"container-interop\"],\n    \"homepage\": \"https://php-di.org/\",\n    \"license\": \"MIT\",\n    \"autoload\": {\n        \"psr-4\": {\n            \"DI\\\\\": \"src/\"\n        },\n        \"files\": [\n            \"src/functions.php\"\n        ]\n    },\n    \"autoload-dev\": {\n        \"psr-4\": {\n            \"DI\\\\Test\\\\IntegrationTest\\\\\": \"tests/IntegrationTest/\",\n            \"DI\\\\Test\\\\UnitTest\\\\\": \"tests/UnitTest/\"\n        }\n    },\n    \"scripts\": {\n        \"test\": \"phpunit\",\n        \"format-code\": \"php-cs-fixer fix --allow-risky=yes\",\n        \"phpstan\": \"phpstan analyse -l 5 -c phpstan.neon src\"\n    },\n    \"require\": {\n        \"php\": \">=7.4.0\",\n        \"psr/container\": \"^1.0\",\n        \"php-di/invoker\": \"^2.0\",\n        \"php-di/phpdoc-reader\": \"^2.0.1\",\n        \"laravel/serializable-closure\": \"^1.0\"\n    },\n    \"require-dev\": {\n        \"phpunit/phpunit\": \"^9.5\",\n        \"mnapoli/phpunit-easymock\": \"^1.2\",\n        \"doctrine/annotations\": \"~1.10\",\n        \"ocramius/proxy-manager\": \"^2.11.2\",\n        \"friendsofphp/php-cs-fixer\": \"^2.4\",\n        \"phpstan/phpstan\": \"^0.12\"\n    },\n    \"provide\": {\n        \"psr/container-implementation\": \"^1.0\"\n    },\n    \"suggest\": {\n        \"doctrine/annotations\": \"Install it if you want to use annotations (version ~1.2)\",\n        \"ocramius/proxy-manager\": \"Install it if you want to use lazy injection (version ~2.0)\"\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Annotation/Inject.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Annotation;\n\nuse DI\\Definition\\Exception\\InvalidAnnotation;\n\n/**\n * \"Inject\" annotation.\n *\n * Marks a property or method as an injection point\n *\n * @api\n *\n * @Annotation\n * @Target({\"METHOD\",\"PROPERTY\"})\n *\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\nfinal class Inject\n{\n    /**\n     * Entry name.\n     * @var string\n     */\n    private $name;\n\n    /**\n     * Parameters, indexed by the parameter number (index) or name.\n     *\n     * Used if the annotation is set on a method\n     * @var array\n     */\n    private $parameters = [];\n\n    /**\n     * @throws InvalidAnnotation\n     */\n    public function __construct(array $values)\n    {\n        // Process the parameters as a list AND as a parameter array (we don't know on what the annotation is)\n\n        // @Inject(name=\"foo\")\n        if (isset($values['name']) && is_string($values['name'])) {\n            $this->name = $values['name'];\n\n            return;\n        }\n\n        // @Inject\n        if (! isset($values['value'])) {\n            return;\n        }\n\n        $values = $values['value'];\n\n        // @Inject(\"foo\")\n        if (is_string($values)) {\n            $this->name = $values;\n        }\n\n        // @Inject({...}) on a method\n        if (is_array($values)) {\n            foreach ($values as $key => $value) {\n                if (! is_string($value)) {\n                    throw new InvalidAnnotation(sprintf(\n                        '@Inject({\"param\" = \"value\"}) expects \"value\" to be a string, %s given.',\n                        json_encode($value)\n                    ));\n                }\n\n                $this->parameters[$key] = $value;\n            }\n        }\n    }\n\n    /**\n     * @return string|null Name of the entry to inject\n     */\n    public function getName()\n    {\n        return $this->name;\n    }\n\n    /**\n     * @return array Parameters, indexed by the parameter number (index) or name\n     */\n    public function getParameters() : array\n    {\n        return $this->parameters;\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Annotation/Injectable.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Annotation;\n\n/**\n * \"Injectable\" annotation.\n *\n * Marks a class as injectable\n *\n * @api\n *\n * @Annotation\n * @Target(\"CLASS\")\n *\n * @author Domenic Muskulus <domenic@muskulus.eu>\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\nfinal class Injectable\n{\n    /**\n     * Should the object be lazy-loaded.\n     * @var bool|null\n     */\n    private $lazy;\n\n    public function __construct(array $values)\n    {\n        if (isset($values['lazy'])) {\n            $this->lazy = (bool) $values['lazy'];\n        }\n    }\n\n    /**\n     * @return bool|null\n     */\n    public function isLazy()\n    {\n        return $this->lazy;\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/CompiledContainer.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI;\n\nuse DI\\Compiler\\RequestedEntryHolder;\nuse DI\\Definition\\Definition;\nuse DI\\Definition\\Exception\\InvalidDefinition;\nuse DI\\Invoker\\FactoryParameterResolver;\nuse Invoker\\Exception\\NotCallableException;\nuse Invoker\\Exception\\NotEnoughParametersException;\nuse Invoker\\Invoker;\nuse Invoker\\InvokerInterface;\nuse Invoker\\ParameterResolver\\AssociativeArrayResolver;\nuse Invoker\\ParameterResolver\\DefaultValueResolver;\nuse Invoker\\ParameterResolver\\NumericArrayResolver;\nuse Invoker\\ParameterResolver\\ResolverChain;\n\n/**\n * Compiled version of the dependency injection container.\n *\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\nabstract class CompiledContainer extends Container\n{\n    /**\n     * This const is overridden in child classes (compiled containers).\n     * @var array\n     */\n    protected const METHOD_MAPPING = [];\n\n    /**\n     * @var InvokerInterface\n     */\n    private $factoryInvoker;\n\n    /**\n     * {@inheritdoc}\n     */\n    public function get($name)\n    {\n        // Try to find the entry in the singleton map\n        if (isset($this->resolvedEntries[$name]) || array_key_exists($name, $this->resolvedEntries)) {\n            return $this->resolvedEntries[$name];\n        }\n\n        $method = static::METHOD_MAPPING[$name] ?? null;\n\n        // If it's a compiled entry, then there is a method in this class\n        if ($method !== null) {\n            // Check if we are already getting this entry -> circular dependency\n            if (isset($this->entriesBeingResolved[$name])) {\n                throw new DependencyException(\"Circular dependency detected while trying to resolve entry '$name'\");\n            }\n            $this->entriesBeingResolved[$name] = true;\n\n            try {\n                $value = $this->$method();\n            } finally {\n                unset($this->entriesBeingResolved[$name]);\n            }\n\n            // Store the entry to always return it without recomputing it\n            $this->resolvedEntries[$name] = $value;\n\n            return $value;\n        }\n\n        return parent::get($name);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function has($name)\n    {\n        if (! is_string($name)) {\n            throw new \\InvalidArgumentException(sprintf(\n                'The name parameter must be of type string, %s given',\n                is_object($name) ? get_class($name) : gettype($name)\n            ));\n        }\n\n        // The parent method is overridden to check in our array, it avoids resolving definitions\n        if (isset(static::METHOD_MAPPING[$name])) {\n            return true;\n        }\n\n        return parent::has($name);\n    }\n\n    protected function setDefinition(string $name, Definition $definition)\n    {\n        // It needs to be forbidden because that would mean get() must go through the definitions\n        // every time, which kinds of defeats the performance gains of the compiled container\n        throw new \\LogicException('You cannot set a definition at runtime on a compiled container. You can either put your definitions in a file, disable compilation or ->set() a raw value directly (PHP object, string, int, ...) instead of a PHP-DI definition.');\n    }\n\n    /**\n     * Invoke the given callable.\n     */\n    protected function resolveFactory($callable, $entryName, array $extraParameters = [])\n    {\n        // Initialize the factory resolver\n        if (! $this->factoryInvoker) {\n            $parameterResolver = new ResolverChain([\n                new AssociativeArrayResolver,\n                new FactoryParameterResolver($this->delegateContainer),\n                new NumericArrayResolver,\n                new DefaultValueResolver,\n            ]);\n\n            $this->factoryInvoker = new Invoker($parameterResolver, $this->delegateContainer);\n        }\n\n        $parameters = [$this->delegateContainer, new RequestedEntryHolder($entryName)];\n\n        $parameters = array_merge($parameters, $extraParameters);\n\n        try {\n            return $this->factoryInvoker->call($callable, $parameters);\n        } catch (NotCallableException $e) {\n            throw new InvalidDefinition(\"Entry \\\"$entryName\\\" cannot be resolved: factory \" . $e->getMessage());\n        } catch (NotEnoughParametersException $e) {\n            throw new InvalidDefinition(\"Entry \\\"$entryName\\\" cannot be resolved: \" . $e->getMessage());\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Compiler/Compiler.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Compiler;\n\nuse function chmod;\nuse DI\\Definition\\ArrayDefinition;\nuse DI\\Definition\\DecoratorDefinition;\nuse DI\\Definition\\Definition;\nuse DI\\Definition\\EnvironmentVariableDefinition;\nuse DI\\Definition\\Exception\\InvalidDefinition;\nuse DI\\Definition\\FactoryDefinition;\nuse DI\\Definition\\ObjectDefinition;\nuse DI\\Definition\\Reference;\nuse DI\\Definition\\Source\\DefinitionSource;\nuse DI\\Definition\\StringDefinition;\nuse DI\\Definition\\ValueDefinition;\nuse DI\\DependencyException;\nuse DI\\Proxy\\ProxyFactory;\nuse function dirname;\nuse function file_put_contents;\nuse InvalidArgumentException;\nuse Laravel\\SerializableClosure\\Support\\ReflectionClosure;\nuse function rename;\nuse function sprintf;\nuse function tempnam;\nuse function unlink;\n\n/**\n * Compiles the container into PHP code much more optimized for performances.\n *\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\nclass Compiler\n{\n    /**\n     * @var string\n     */\n    private $containerClass;\n\n    /**\n     * @var string\n     */\n    private $containerParentClass;\n\n    /**\n     * Definitions indexed by the entry name. The value can be null if the definition needs to be fetched.\n     *\n     * Keys are strings, values are `Definition` objects or null.\n     *\n     * @var \\ArrayIterator\n     */\n    private $entriesToCompile;\n\n    /**\n     * Progressive counter for definitions.\n     *\n     * Each key in $entriesToCompile is defined as 'SubEntry' + counter\n     * and each definition has always the same key in the CompiledContainer\n     * if PHP-DI configuration does not change.\n     *\n     * @var int\n     */\n    private $subEntryCounter;\n\n    /**\n     * Progressive counter for CompiledContainer get methods.\n     *\n     * Each CompiledContainer method name is defined as 'get' + counter\n     * and remains the same after each recompilation\n     * if PHP-DI configuration does not change.\n     *\n     * @var int\n     */\n    private $methodMappingCounter;\n\n    /**\n     * Map of entry names to method names.\n     *\n     * @var string[]\n     */\n    private $entryToMethodMapping = [];\n\n    /**\n     * @var string[]\n     */\n    private $methods = [];\n\n    /**\n     * @var bool\n     */\n    private $autowiringEnabled;\n\n    /**\n     * @var ProxyFactory\n     */\n    private $proxyFactory;\n\n    public function __construct(ProxyFactory $proxyFactory)\n    {\n        $this->proxyFactory = $proxyFactory;\n    }\n\n    public function getProxyFactory() : ProxyFactory\n    {\n        return $this->proxyFactory;\n    }\n\n    /**\n     * Compile the container.\n     *\n     * @return string The compiled container file name.\n     */\n    public function compile(\n        DefinitionSource $definitionSource,\n        string $directory,\n        string $className,\n        string $parentClassName,\n        bool $autowiringEnabled\n    ) : string {\n        $fileName = rtrim($directory, '/') . '/' . $className . '.php';\n\n        if (file_exists($fileName)) {\n            // The container is already compiled\n            return $fileName;\n        }\n\n        $this->autowiringEnabled = $autowiringEnabled;\n\n        // Validate that a valid class name was provided\n        $validClassName = preg_match('/^[a-zA-Z_][a-zA-Z0-9_]*$/', $className);\n        if (!$validClassName) {\n            throw new InvalidArgumentException(\"The container cannot be compiled: `$className` is not a valid PHP class name\");\n        }\n\n        $this->entriesToCompile = new \\ArrayIterator($definitionSource->getDefinitions());\n\n        // We use an ArrayIterator so that we can keep adding new items to the list while we compile entries\n        foreach ($this->entriesToCompile as $entryName => $definition) {\n            $silenceErrors = false;\n            // This is an entry found by reference during autowiring\n            if (!$definition) {\n                $definition = $definitionSource->getDefinition($entryName);\n                // We silence errors for those entries because type-hints may reference interfaces/abstract classes\n                // which could later be defined, or even not used (we don't want to block the compilation for those)\n                $silenceErrors = true;\n            }\n            if (!$definition) {\n                // We do not throw a `NotFound` exception here because the dependency\n                // could be defined at runtime\n                continue;\n            }\n            // Check that the definition can be compiled\n            $errorMessage = $this->isCompilable($definition);\n            if ($errorMessage !== true) {\n                continue;\n            }\n            try {\n                $this->compileDefinition($entryName, $definition);\n            } catch (InvalidDefinition $e) {\n                if ($silenceErrors) {\n                    // forget the entry\n                    unset($this->entryToMethodMapping[$entryName]);\n                } else {\n                    throw $e;\n                }\n            }\n        }\n\n        $this->containerClass = $className;\n        $this->containerParentClass = $parentClassName;\n\n        ob_start();\n        require __DIR__ . '/Template.php';\n        $fileContent = ob_get_clean();\n\n        $fileContent = \"<?php\\n\" . $fileContent;\n\n        $this->createCompilationDirectory(dirname($fileName));\n        $this->writeFileAtomic($fileName, $fileContent);\n\n        return $fileName;\n    }\n\n    private function writeFileAtomic(string $fileName, string $content) : int\n    {\n        $tmpFile = @tempnam(dirname($fileName), 'swap-compile');\n        if ($tmpFile === false) {\n            throw new InvalidArgumentException(\n                sprintf('Error while creating temporary file in %s', dirname($fileName))\n            );\n        }\n        @chmod($tmpFile, 0666);\n\n        $written = file_put_contents($tmpFile, $content);\n        if ($written === false) {\n            @unlink($tmpFile);\n\n            throw new InvalidArgumentException(sprintf('Error while writing to %s', $tmpFile));\n        }\n\n        @chmod($tmpFile, 0666);\n        $renamed = @rename($tmpFile, $fileName);\n        if (!$renamed) {\n            @unlink($tmpFile);\n            throw new InvalidArgumentException(sprintf('Error while renaming %s to %s', $tmpFile, $fileName));\n        }\n\n        return $written;\n    }\n\n    /**\n     * @throws DependencyException\n     * @throws InvalidDefinition\n     * @return string The method name\n     */\n    private function compileDefinition(string $entryName, Definition $definition) : string\n    {\n        // Generate a unique method name\n        $methodName = 'get' . (++$this->methodMappingCounter);\n        $this->entryToMethodMapping[$entryName] = $methodName;\n\n        switch (true) {\n            case $definition instanceof ValueDefinition:\n                $value = $definition->getValue();\n                $code = 'return ' . $this->compileValue($value) . ';';\n                break;\n            case $definition instanceof Reference:\n                $targetEntryName = $definition->getTargetEntryName();\n                $code = 'return $this->delegateContainer->get(' . $this->compileValue($targetEntryName) . ');';\n                // If this method is not yet compiled we store it for compilation\n                if (!isset($this->entriesToCompile[$targetEntryName])) {\n                    $this->entriesToCompile[$targetEntryName] = null;\n                }\n                break;\n            case $definition instanceof StringDefinition:\n                $entryName = $this->compileValue($definition->getName());\n                $expression = $this->compileValue($definition->getExpression());\n                $code = 'return \\DI\\Definition\\StringDefinition::resolveExpression(' . $entryName . ', ' . $expression . ', $this->delegateContainer);';\n                break;\n            case $definition instanceof EnvironmentVariableDefinition:\n                $variableName = $this->compileValue($definition->getVariableName());\n                $isOptional = $this->compileValue($definition->isOptional());\n                $defaultValue = $this->compileValue($definition->getDefaultValue());\n                $code = <<<PHP\n        \\$value = \\$_ENV[$variableName] ?? \\$_SERVER[$variableName] ?? getenv($variableName);\n        if (false !== \\$value) return \\$value;\n        if (!$isOptional) {\n            throw new \\DI\\Definition\\Exception\\InvalidDefinition(\"The environment variable '{$definition->getVariableName()}' has not been defined\");\n        }\n        return $defaultValue;\nPHP;\n                break;\n            case $definition instanceof ArrayDefinition:\n                try {\n                    $code = 'return ' . $this->compileValue($definition->getValues()) . ';';\n                } catch (\\Exception $e) {\n                    throw new DependencyException(sprintf(\n                        'Error while compiling %s. %s',\n                        $definition->getName(),\n                        $e->getMessage()\n                    ), 0, $e);\n                }\n                break;\n            case $definition instanceof ObjectDefinition:\n                $compiler = new ObjectCreationCompiler($this);\n                $code = $compiler->compile($definition);\n                $code .= \"\\n        return \\$object;\";\n                break;\n            case $definition instanceof DecoratorDefinition:\n                $decoratedDefinition = $definition->getDecoratedDefinition();\n                if (! $decoratedDefinition instanceof Definition) {\n                    if (! $definition->getName()) {\n                        throw new InvalidDefinition('Decorators cannot be nested in another definition');\n                    }\n                    throw new InvalidDefinition(sprintf(\n                        'Entry \"%s\" decorates nothing: no previous definition with the same name was found',\n                        $definition->getName()\n                    ));\n                }\n                $code = sprintf(\n                    'return call_user_func(%s, %s, $this->delegateContainer);',\n                    $this->compileValue($definition->getCallable()),\n                    $this->compileValue($decoratedDefinition)\n                );\n                break;\n            case $definition instanceof FactoryDefinition:\n                $value = $definition->getCallable();\n\n                // Custom error message to help debugging\n                $isInvokableClass = is_string($value) && class_exists($value) && method_exists($value, '__invoke');\n                if ($isInvokableClass && !$this->autowiringEnabled) {\n                    throw new InvalidDefinition(sprintf(\n                        'Entry \"%s\" cannot be compiled. Invokable classes cannot be automatically resolved if autowiring is disabled on the container, you need to enable autowiring or define the entry manually.',\n                        $entryName\n                    ));\n                }\n\n                $definitionParameters = '';\n                if (!empty($definition->getParameters())) {\n                    $definitionParameters = ', ' . $this->compileValue($definition->getParameters());\n                }\n\n                $code = sprintf(\n                    'return $this->resolveFactory(%s, %s%s);',\n                    $this->compileValue($value),\n                    var_export($entryName, true),\n                    $definitionParameters\n                );\n\n                break;\n            default:\n                // This case should not happen (so it cannot be tested)\n                throw new \\Exception('Cannot compile definition of type ' . get_class($definition));\n        }\n\n        $this->methods[$methodName] = $code;\n\n        return $methodName;\n    }\n\n    public function compileValue($value) : string\n    {\n        // Check that the value can be compiled\n        $errorMessage = $this->isCompilable($value);\n        if ($errorMessage !== true) {\n            throw new InvalidDefinition($errorMessage);\n        }\n\n        if ($value instanceof Definition) {\n            // Give it an arbitrary unique name\n            $subEntryName = 'subEntry' . (++$this->subEntryCounter);\n            // Compile the sub-definition in another method\n            $methodName = $this->compileDefinition($subEntryName, $value);\n            // The value is now a method call to that method (which returns the value)\n            return \"\\$this->$methodName()\";\n        }\n\n        if (is_array($value)) {\n            $value = array_map(function ($value, $key) {\n                $compiledValue = $this->compileValue($value);\n                $key = var_export($key, true);\n\n                return \"            $key => $compiledValue,\\n\";\n            }, $value, array_keys($value));\n            $value = implode('', $value);\n\n            return \"[\\n$value        ]\";\n        }\n\n        if ($value instanceof \\Closure) {\n            return $this->compileClosure($value);\n        }\n\n        return var_export($value, true);\n    }\n\n    private function createCompilationDirectory(string $directory)\n    {\n        if (!is_dir($directory) && !@mkdir($directory, 0777, true) && !is_dir($directory)) {\n            throw new InvalidArgumentException(sprintf('Compilation directory does not exist and cannot be created: %s.', $directory));\n        }\n        if (!is_writable($directory)) {\n            throw new InvalidArgumentException(sprintf('Compilation directory is not writable: %s.', $directory));\n        }\n    }\n\n    /**\n     * @return string|true If true is returned that means that the value is compilable.\n     */\n    private function isCompilable($value)\n    {\n        if ($value instanceof ValueDefinition) {\n            return $this->isCompilable($value->getValue());\n        }\n        if ($value instanceof DecoratorDefinition) {\n            if (empty($value->getName())) {\n                return 'Decorators cannot be nested in another definition';\n            }\n        }\n        // All other definitions are compilable\n        if ($value instanceof Definition) {\n            return true;\n        }\n        if ($value instanceof \\Closure) {\n            return true;\n        }\n        if (is_object($value)) {\n            return 'An object was found but objects cannot be compiled';\n        }\n        if (is_resource($value)) {\n            return 'A resource was found but resources cannot be compiled';\n        }\n\n        return true;\n    }\n\n    /**\n     * @throws \\DI\\Definition\\Exception\\InvalidDefinition\n     */\n    private function compileClosure(\\Closure $closure) : string\n    {\n        $reflector = new ReflectionClosure($closure);\n\n        if ($reflector->getUseVariables()) {\n            throw new InvalidDefinition('Cannot compile closures which import variables using the `use` keyword');\n        }\n\n        if ($reflector->isBindingRequired() || $reflector->isScopeRequired()) {\n            throw new InvalidDefinition('Cannot compile closures which use $this or self/static/parent references');\n        }\n\n        // Force all closures to be static (add the `static` keyword), i.e. they can't use\n        // $this, which makes sense since their code is copied into another class.\n        $code = ($reflector->isStatic() ? '' : 'static ') . $reflector->getCode();\n\n        $code = trim($code, \"\\t\\n\\r;\");\n\n        return $code;\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Compiler/ObjectCreationCompiler.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Compiler;\n\nuse DI\\Definition\\Exception\\InvalidDefinition;\nuse DI\\Definition\\ObjectDefinition;\nuse DI\\Definition\\ObjectDefinition\\MethodInjection;\nuse ReflectionClass;\nuse ReflectionMethod;\nuse ReflectionParameter;\nuse ReflectionProperty;\n\n/**\n * Compiles an object definition into native PHP code that, when executed, creates the object.\n *\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\nclass ObjectCreationCompiler\n{\n    /**\n     * @var Compiler\n     */\n    private $compiler;\n\n    public function __construct(Compiler $compiler)\n    {\n        $this->compiler = $compiler;\n    }\n\n    public function compile(ObjectDefinition $definition) : string\n    {\n        $this->assertClassIsNotAnonymous($definition);\n        $this->assertClassIsInstantiable($definition);\n\n        // Lazy?\n        if ($definition->isLazy()) {\n            return $this->compileLazyDefinition($definition);\n        }\n\n        try {\n            $classReflection = new ReflectionClass($definition->getClassName());\n            $constructorArguments = $this->resolveParameters($definition->getConstructorInjection(), $classReflection->getConstructor());\n            $dumpedConstructorArguments = array_map(function ($value) {\n                return $this->compiler->compileValue($value);\n            }, $constructorArguments);\n\n            $code = [];\n            $code[] = sprintf(\n                '$object = new %s(%s);',\n                $definition->getClassName(),\n                implode(', ', $dumpedConstructorArguments)\n            );\n\n            // Property injections\n            foreach ($definition->getPropertyInjections() as $propertyInjection) {\n                $value = $propertyInjection->getValue();\n                $value = $this->compiler->compileValue($value);\n\n                $className = $propertyInjection->getClassName() ?: $definition->getClassName();\n                $property = new ReflectionProperty($className, $propertyInjection->getPropertyName());\n                if ($property->isPublic()) {\n                    $code[] = sprintf('$object->%s = %s;', $propertyInjection->getPropertyName(), $value);\n                } else {\n                    // Private/protected property\n                    $code[] = sprintf(\n                        '\\DI\\Definition\\Resolver\\ObjectCreator::setPrivatePropertyValue(%s, $object, \\'%s\\', %s);',\n                        var_export($propertyInjection->getClassName(), true),\n                        $propertyInjection->getPropertyName(),\n                        $value\n                    );\n                }\n            }\n\n            // Method injections\n            foreach ($definition->getMethodInjections() as $methodInjection) {\n                $methodReflection = new \\ReflectionMethod($definition->getClassName(), $methodInjection->getMethodName());\n                $parameters = $this->resolveParameters($methodInjection, $methodReflection);\n\n                $dumpedParameters = array_map(function ($value) {\n                    return $this->compiler->compileValue($value);\n                }, $parameters);\n\n                $code[] = sprintf(\n                    '$object->%s(%s);',\n                    $methodInjection->getMethodName(),\n                    implode(', ', $dumpedParameters)\n                );\n            }\n        } catch (InvalidDefinition $e) {\n            throw InvalidDefinition::create($definition, sprintf(\n                'Entry \"%s\" cannot be compiled: %s',\n                $definition->getName(),\n                $e->getMessage()\n            ));\n        }\n\n        return implode(\"\\n        \", $code);\n    }\n\n    public function resolveParameters(MethodInjection $definition = null, ReflectionMethod $method = null) : array\n    {\n        $args = [];\n\n        if (! $method) {\n            return $args;\n        }\n\n        $definitionParameters = $definition ? $definition->getParameters() : [];\n\n        foreach ($method->getParameters() as $index => $parameter) {\n            if (array_key_exists($index, $definitionParameters)) {\n                // Look in the definition\n                $value = &$definitionParameters[$index];\n            } elseif ($parameter->isOptional()) {\n                // If the parameter is optional and wasn't specified, we take its default value\n                $args[] = $this->getParameterDefaultValue($parameter, $method);\n                continue;\n            } else {\n                throw new InvalidDefinition(sprintf(\n                    'Parameter $%s of %s has no value defined or guessable',\n                    $parameter->getName(),\n                    $this->getFunctionName($method)\n                ));\n            }\n\n            $args[] = &$value;\n        }\n\n        return $args;\n    }\n\n    private function compileLazyDefinition(ObjectDefinition $definition) : string\n    {\n        $subDefinition = clone $definition;\n        $subDefinition->setLazy(false);\n        $subDefinition = $this->compiler->compileValue($subDefinition);\n\n        $this->compiler->getProxyFactory()->generateProxyClass($definition->getClassName());\n\n        return <<<PHP\n        \\$object = \\$this->proxyFactory->createProxy(\n            '{$definition->getClassName()}',\n            function (&\\$wrappedObject, \\$proxy, \\$method, \\$params, &\\$initializer) {\n                \\$wrappedObject = $subDefinition;\n                \\$initializer = null; // turning off further lazy initialization\n                return true;\n            }\n        );\nPHP;\n    }\n\n    /**\n     * Returns the default value of a function parameter.\n     *\n     * @throws InvalidDefinition Can't get default values from PHP internal classes and functions\n     * @return mixed\n     */\n    private function getParameterDefaultValue(ReflectionParameter $parameter, ReflectionMethod $function)\n    {\n        try {\n            return $parameter->getDefaultValue();\n        } catch (\\ReflectionException $e) {\n            throw new InvalidDefinition(sprintf(\n                'The parameter \"%s\" of %s has no type defined or guessable. It has a default value, '\n                . 'but the default value can\\'t be read through Reflection because it is a PHP internal class.',\n                $parameter->getName(),\n                $this->getFunctionName($function)\n            ));\n        }\n    }\n\n    private function getFunctionName(ReflectionMethod $method) : string\n    {\n        return $method->getName() . '()';\n    }\n\n    private function assertClassIsNotAnonymous(ObjectDefinition $definition)\n    {\n        if (strpos($definition->getClassName(), '@') !== false) {\n            throw InvalidDefinition::create($definition, sprintf(\n                'Entry \"%s\" cannot be compiled: anonymous classes cannot be compiled',\n                $definition->getName()\n            ));\n        }\n    }\n\n    private function assertClassIsInstantiable(ObjectDefinition $definition)\n    {\n        if ($definition->isInstantiable()) {\n            return;\n        }\n\n        $message = ! $definition->classExists()\n            ? 'Entry \"%s\" cannot be compiled: the class doesn\\'t exist'\n            : 'Entry \"%s\" cannot be compiled: the class is not instantiable';\n\n        throw InvalidDefinition::create($definition, sprintf($message, $definition->getName()));\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Compiler/RequestedEntryHolder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Compiler;\n\nuse DI\\Factory\\RequestedEntry;\n\n/**\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\nclass RequestedEntryHolder implements RequestedEntry\n{\n    /**\n     * @var string\n     */\n    private $name;\n\n    public function __construct(string $name)\n    {\n        $this->name = $name;\n    }\n\n    public function getName() : string\n    {\n        return $this->name;\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Compiler/Template.php",
    "content": "/**\n * This class has been auto-generated by PHP-DI.\n */\nclass <?=$this->containerClass; ?> extends <?=$this->containerParentClass; ?>\n{\n    const METHOD_MAPPING = <?php var_export($this->entryToMethodMapping); ?>;\n\n<?php foreach ($this->methods as $methodName => $methodContent) : ?>\n    protected function <?=$methodName; ?>()\n    {\n        <?=$methodContent; ?>\n\n    }\n\n<?php endforeach; ?>\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Container.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI;\n\nuse DI\\Definition\\Definition;\nuse DI\\Definition\\Exception\\InvalidDefinition;\nuse DI\\Definition\\FactoryDefinition;\nuse DI\\Definition\\Helper\\DefinitionHelper;\nuse DI\\Definition\\InstanceDefinition;\nuse DI\\Definition\\ObjectDefinition;\nuse DI\\Definition\\Resolver\\DefinitionResolver;\nuse DI\\Definition\\Resolver\\ResolverDispatcher;\nuse DI\\Definition\\Source\\DefinitionArray;\nuse DI\\Definition\\Source\\MutableDefinitionSource;\nuse DI\\Definition\\Source\\ReflectionBasedAutowiring;\nuse DI\\Definition\\Source\\SourceChain;\nuse DI\\Definition\\ValueDefinition;\nuse DI\\Invoker\\DefinitionParameterResolver;\nuse DI\\Proxy\\ProxyFactory;\nuse InvalidArgumentException;\nuse Invoker\\Invoker;\nuse Invoker\\InvokerInterface;\nuse Invoker\\ParameterResolver\\AssociativeArrayResolver;\nuse Invoker\\ParameterResolver\\Container\\TypeHintContainerResolver;\nuse Invoker\\ParameterResolver\\DefaultValueResolver;\nuse Invoker\\ParameterResolver\\NumericArrayResolver;\nuse Invoker\\ParameterResolver\\ResolverChain;\nuse Psr\\Container\\ContainerInterface;\n\n/**\n * Dependency Injection Container.\n *\n * @api\n *\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\nclass Container implements ContainerInterface, FactoryInterface, InvokerInterface\n{\n    /**\n     * Map of entries that are already resolved.\n     * @var array\n     */\n    protected $resolvedEntries = [];\n\n    /**\n     * @var MutableDefinitionSource\n     */\n    private $definitionSource;\n\n    /**\n     * @var DefinitionResolver\n     */\n    private $definitionResolver;\n\n    /**\n     * Map of definitions that are already fetched (local cache).\n     *\n     * @var (Definition|null)[]\n     */\n    private $fetchedDefinitions = [];\n\n    /**\n     * Array of entries being resolved. Used to avoid circular dependencies and infinite loops.\n     * @var array\n     */\n    protected $entriesBeingResolved = [];\n\n    /**\n     * @var InvokerInterface|null\n     */\n    private $invoker;\n\n    /**\n     * Container that wraps this container. If none, points to $this.\n     *\n     * @var ContainerInterface\n     */\n    protected $delegateContainer;\n\n    /**\n     * @var ProxyFactory\n     */\n    protected $proxyFactory;\n\n    /**\n     * Use `$container = new Container()` if you want a container with the default configuration.\n     *\n     * If you want to customize the container's behavior, you are discouraged to create and pass the\n     * dependencies yourself, the ContainerBuilder class is here to help you instead.\n     *\n     * @see ContainerBuilder\n     *\n     * @param ContainerInterface $wrapperContainer If the container is wrapped by another container.\n     */\n    public function __construct(\n        MutableDefinitionSource $definitionSource = null,\n        ProxyFactory $proxyFactory = null,\n        ContainerInterface $wrapperContainer = null\n    ) {\n        $this->delegateContainer = $wrapperContainer ?: $this;\n\n        $this->definitionSource = $definitionSource ?: $this->createDefaultDefinitionSource();\n        $this->proxyFactory = $proxyFactory ?: new ProxyFactory(false);\n        $this->definitionResolver = new ResolverDispatcher($this->delegateContainer, $this->proxyFactory);\n\n        // Auto-register the container\n        $this->resolvedEntries = [\n            self::class => $this,\n            ContainerInterface::class => $this->delegateContainer,\n            FactoryInterface::class => $this,\n            InvokerInterface::class => $this,\n        ];\n    }\n\n    /**\n     * Returns an entry of the container by its name.\n     *\n     * @template T\n     * @param string|class-string<T> $name Entry name or a class name.\n     *\n     * @throws DependencyException Error while resolving the entry.\n     * @throws NotFoundException No entry found for the given name.\n     * @return mixed|T\n     */\n    public function get($name)\n    {\n        // If the entry is already resolved we return it\n        if (isset($this->resolvedEntries[$name]) || array_key_exists($name, $this->resolvedEntries)) {\n            return $this->resolvedEntries[$name];\n        }\n\n        $definition = $this->getDefinition($name);\n        if (! $definition) {\n            throw new NotFoundException(\"No entry or class found for '$name'\");\n        }\n\n        $value = $this->resolveDefinition($definition);\n\n        $this->resolvedEntries[$name] = $value;\n\n        return $value;\n    }\n\n    /**\n     * @param string $name\n     *\n     * @return Definition|null\n     */\n    private function getDefinition($name)\n    {\n        // Local cache that avoids fetching the same definition twice\n        if (!array_key_exists($name, $this->fetchedDefinitions)) {\n            $this->fetchedDefinitions[$name] = $this->definitionSource->getDefinition($name);\n        }\n\n        return $this->fetchedDefinitions[$name];\n    }\n\n    /**\n     * Build an entry of the container by its name.\n     *\n     * This method behave like get() except resolves the entry again every time.\n     * For example if the entry is a class then a new instance will be created each time.\n     *\n     * This method makes the container behave like a factory.\n     *\n     * @template T\n     * @param string|class-string<T> $name       Entry name or a class name.\n     * @param array                  $parameters Optional parameters to use to build the entry. Use this to force\n     *                                           specific parameters to specific values. Parameters not defined in this\n     *                                           array will be resolved using the container.\n     *\n     * @throws InvalidArgumentException The name parameter must be of type string.\n     * @throws DependencyException Error while resolving the entry.\n     * @throws NotFoundException No entry found for the given name.\n     * @return mixed|T\n     */\n    public function make($name, array $parameters = [])\n    {\n        if (! is_string($name)) {\n            throw new InvalidArgumentException(sprintf(\n                'The name parameter must be of type string, %s given',\n                is_object($name) ? get_class($name) : gettype($name)\n            ));\n        }\n\n        $definition = $this->getDefinition($name);\n        if (! $definition) {\n            // If the entry is already resolved we return it\n            if (array_key_exists($name, $this->resolvedEntries)) {\n                return $this->resolvedEntries[$name];\n            }\n\n            throw new NotFoundException(\"No entry or class found for '$name'\");\n        }\n\n        return $this->resolveDefinition($definition, $parameters);\n    }\n\n    /**\n     * Test if the container can provide something for the given name.\n     *\n     * @param string $name Entry name or a class name.\n     *\n     * @throws InvalidArgumentException The name parameter must be of type string.\n     * @return bool\n     */\n    public function has($name)\n    {\n        if (! is_string($name)) {\n            throw new InvalidArgumentException(sprintf(\n                'The name parameter must be of type string, %s given',\n                is_object($name) ? get_class($name) : gettype($name)\n            ));\n        }\n\n        if (array_key_exists($name, $this->resolvedEntries)) {\n            return true;\n        }\n\n        $definition = $this->getDefinition($name);\n        if ($definition === null) {\n            return false;\n        }\n\n        return $this->definitionResolver->isResolvable($definition);\n    }\n\n    /**\n     * Inject all dependencies on an existing instance.\n     *\n     * @template T\n     * @param object|T $instance Object to perform injection upon\n     * @throws InvalidArgumentException\n     * @throws DependencyException Error while injecting dependencies\n     * @return object|T $instance Returns the same instance\n     */\n    public function injectOn($instance)\n    {\n        if (!$instance) {\n            return $instance;\n        }\n\n        $className = get_class($instance);\n\n        // If the class is anonymous, don't cache its definition\n        // Checking for anonymous classes is cleaner via Reflection, but also slower\n        $objectDefinition = false !== strpos($className, '@anonymous')\n            ? $this->definitionSource->getDefinition($className)\n            : $this->getDefinition($className);\n\n        if (! $objectDefinition instanceof ObjectDefinition) {\n            return $instance;\n        }\n\n        $definition = new InstanceDefinition($instance, $objectDefinition);\n\n        $this->definitionResolver->resolve($definition);\n\n        return $instance;\n    }\n\n    /**\n     * Call the given function using the given parameters.\n     *\n     * Missing parameters will be resolved from the container.\n     *\n     * @param callable $callable   Function to call.\n     * @param array    $parameters Parameters to use. Can be indexed by the parameter names\n     *                             or not indexed (same order as the parameters).\n     *                             The array can also contain DI definitions, e.g. DI\\get().\n     *\n     * @return mixed Result of the function.\n     */\n    public function call($callable, array $parameters = [])\n    {\n        return $this->getInvoker()->call($callable, $parameters);\n    }\n\n    /**\n     * Define an object or a value in the container.\n     *\n     * @param string $name Entry name\n     * @param mixed|DefinitionHelper $value Value, use definition helpers to define objects\n     */\n    public function set(string $name, $value)\n    {\n        if ($value instanceof DefinitionHelper) {\n            $value = $value->getDefinition($name);\n        } elseif ($value instanceof \\Closure) {\n            $value = new FactoryDefinition($name, $value);\n        }\n\n        if ($value instanceof ValueDefinition) {\n            $this->resolvedEntries[$name] = $value->getValue();\n        } elseif ($value instanceof Definition) {\n            $value->setName($name);\n            $this->setDefinition($name, $value);\n        } else {\n            $this->resolvedEntries[$name] = $value;\n        }\n    }\n\n    /**\n     * Get defined container entries.\n     *\n     * @return string[]\n     */\n    public function getKnownEntryNames() : array\n    {\n        $entries = array_unique(array_merge(\n            array_keys($this->definitionSource->getDefinitions()),\n            array_keys($this->resolvedEntries)\n        ));\n        sort($entries);\n\n        return $entries;\n    }\n\n    /**\n     * Get entry debug information.\n     *\n     * @param string $name Entry name\n     *\n     * @throws InvalidDefinition\n     * @throws NotFoundException\n     */\n    public function debugEntry(string $name) : string\n    {\n        $definition = $this->definitionSource->getDefinition($name);\n        if ($definition instanceof Definition) {\n            return (string) $definition;\n        }\n\n        if (array_key_exists($name, $this->resolvedEntries)) {\n            return $this->getEntryType($this->resolvedEntries[$name]);\n        }\n\n        throw new NotFoundException(\"No entry or class found for '$name'\");\n    }\n\n    /**\n     * Get formatted entry type.\n     *\n     * @param mixed $entry\n     */\n    private function getEntryType($entry) : string\n    {\n        if (is_object($entry)) {\n            return sprintf(\"Object (\\n    class = %s\\n)\", get_class($entry));\n        }\n\n        if (is_array($entry)) {\n            return preg_replace(['/^array \\(/', '/\\)$/'], ['[', ']'], var_export($entry, true));\n        }\n\n        if (is_string($entry)) {\n            return sprintf('Value (\\'%s\\')', $entry);\n        }\n\n        if (is_bool($entry)) {\n            return sprintf('Value (%s)', $entry === true ? 'true' : 'false');\n        }\n\n        return sprintf('Value (%s)', is_scalar($entry) ? $entry : ucfirst(gettype($entry)));\n    }\n\n    /**\n     * Resolves a definition.\n     *\n     * Checks for circular dependencies while resolving the definition.\n     *\n     * @throws DependencyException Error while resolving the entry.\n     * @return mixed\n     */\n    private function resolveDefinition(Definition $definition, array $parameters = [])\n    {\n        $entryName = $definition->getName();\n\n        // Check if we are already getting this entry -> circular dependency\n        if (isset($this->entriesBeingResolved[$entryName])) {\n            throw new DependencyException(\"Circular dependency detected while trying to resolve entry '$entryName'\");\n        }\n        $this->entriesBeingResolved[$entryName] = true;\n\n        // Resolve the definition\n        try {\n            $value = $this->definitionResolver->resolve($definition, $parameters);\n        } finally {\n            unset($this->entriesBeingResolved[$entryName]);\n        }\n\n        return $value;\n    }\n\n    protected function setDefinition(string $name, Definition $definition)\n    {\n        // Clear existing entry if it exists\n        if (array_key_exists($name, $this->resolvedEntries)) {\n            unset($this->resolvedEntries[$name]);\n        }\n        $this->fetchedDefinitions = []; // Completely clear this local cache\n\n        $this->definitionSource->addDefinition($definition);\n    }\n\n    private function getInvoker() : InvokerInterface\n    {\n        if (! $this->invoker) {\n            $parameterResolver = new ResolverChain([\n                new DefinitionParameterResolver($this->definitionResolver),\n                new NumericArrayResolver,\n                new AssociativeArrayResolver,\n                new DefaultValueResolver,\n                new TypeHintContainerResolver($this->delegateContainer),\n            ]);\n\n            $this->invoker = new Invoker($parameterResolver, $this);\n        }\n\n        return $this->invoker;\n    }\n\n    private function createDefaultDefinitionSource() : SourceChain\n    {\n        $source = new SourceChain([new ReflectionBasedAutowiring]);\n        $source->setMutableDefinitionSource(new DefinitionArray([], new ReflectionBasedAutowiring));\n\n        return $source;\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/ContainerBuilder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI;\n\nuse DI\\Compiler\\Compiler;\nuse DI\\Definition\\Source\\AnnotationBasedAutowiring;\nuse DI\\Definition\\Source\\DefinitionArray;\nuse DI\\Definition\\Source\\DefinitionFile;\nuse DI\\Definition\\Source\\DefinitionSource;\nuse DI\\Definition\\Source\\NoAutowiring;\nuse DI\\Definition\\Source\\ReflectionBasedAutowiring;\nuse DI\\Definition\\Source\\SourceCache;\nuse DI\\Definition\\Source\\SourceChain;\nuse DI\\Proxy\\ProxyFactory;\nuse InvalidArgumentException;\nuse Psr\\Container\\ContainerInterface;\n\n/**\n * Helper to create and configure a Container.\n *\n * With the default options, the container created is appropriate for the development environment.\n *\n * Example:\n *\n *     $builder = new ContainerBuilder();\n *     $container = $builder->build();\n *\n * @api\n *\n * @since  3.2\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\nclass ContainerBuilder\n{\n    /**\n     * Name of the container class, used to create the container.\n     * @var string\n     */\n    private $containerClass;\n\n    /**\n     * Name of the container parent class, used on compiled container.\n     * @var string\n     */\n    private $containerParentClass;\n\n    /**\n     * @var bool\n     */\n    private $useAutowiring = true;\n\n    /**\n     * @var bool\n     */\n    private $useAnnotations = false;\n\n    /**\n     * @var bool\n     */\n    private $ignorePhpDocErrors = false;\n\n    /**\n     * If true, write the proxies to disk to improve performances.\n     * @var bool\n     */\n    private $writeProxiesToFile = false;\n\n    /**\n     * Directory where to write the proxies (if $writeProxiesToFile is enabled).\n     * @var string|null\n     */\n    private $proxyDirectory;\n\n    /**\n     * If PHP-DI is wrapped in another container, this references the wrapper.\n     * @var ContainerInterface\n     */\n    private $wrapperContainer;\n\n    /**\n     * @var DefinitionSource[]|string[]|array[]\n     */\n    private $definitionSources = [];\n\n    /**\n     * Whether the container has already been built.\n     * @var bool\n     */\n    private $locked = false;\n\n    /**\n     * @var string|null\n     */\n    private $compileToDirectory;\n\n    /**\n     * @var bool\n     */\n    private $sourceCache = false;\n\n    /**\n     * @var string\n     */\n    protected $sourceCacheNamespace;\n\n    /**\n     * Build a container configured for the dev environment.\n     */\n    public static function buildDevContainer() : Container\n    {\n        return new Container;\n    }\n\n    /**\n     * @param string $containerClass Name of the container class, used to create the container.\n     */\n    public function __construct(string $containerClass = Container::class)\n    {\n        $this->containerClass = $containerClass;\n    }\n\n    /**\n     * Build and return a container.\n     *\n     * @return Container\n     */\n    public function build()\n    {\n        $sources = array_reverse($this->definitionSources);\n\n        if ($this->useAnnotations) {\n            $autowiring = new AnnotationBasedAutowiring($this->ignorePhpDocErrors);\n            $sources[] = $autowiring;\n        } elseif ($this->useAutowiring) {\n            $autowiring = new ReflectionBasedAutowiring;\n            $sources[] = $autowiring;\n        } else {\n            $autowiring = new NoAutowiring;\n        }\n\n        $sources = array_map(function ($definitions) use ($autowiring) {\n            if (is_string($definitions)) {\n                // File\n                return new DefinitionFile($definitions, $autowiring);\n            } elseif (is_array($definitions)) {\n                return new DefinitionArray($definitions, $autowiring);\n            }\n\n            return $definitions;\n        }, $sources);\n        $source = new SourceChain($sources);\n\n        // Mutable definition source\n        $source->setMutableDefinitionSource(new DefinitionArray([], $autowiring));\n\n        if ($this->sourceCache) {\n            if (!SourceCache::isSupported()) {\n                throw new \\Exception('APCu is not enabled, PHP-DI cannot use it as a cache');\n            }\n            // Wrap the source with the cache decorator\n            $source = new SourceCache($source, $this->sourceCacheNamespace);\n        }\n\n        $proxyFactory = new ProxyFactory(\n            $this->writeProxiesToFile,\n            $this->proxyDirectory\n        );\n\n        $this->locked = true;\n\n        $containerClass = $this->containerClass;\n\n        if ($this->compileToDirectory) {\n            $compiler = new Compiler($proxyFactory);\n            $compiledContainerFile = $compiler->compile(\n                $source,\n                $this->compileToDirectory,\n                $containerClass,\n                $this->containerParentClass,\n                $this->useAutowiring || $this->useAnnotations\n            );\n            // Only load the file if it hasn't been already loaded\n            // (the container can be created multiple times in the same process)\n            if (!class_exists($containerClass, false)) {\n                require $compiledContainerFile;\n            }\n        }\n\n        return new $containerClass($source, $proxyFactory, $this->wrapperContainer);\n    }\n\n    /**\n     * Compile the container for optimum performances.\n     *\n     * Be aware that the container is compiled once and never updated!\n     *\n     * Therefore:\n     *\n     * - in production you should clear that directory every time you deploy\n     * - in development you should not compile the container\n     *\n     * @see https://php-di.org/doc/performances.html\n     *\n     * @param string $directory Directory in which to put the compiled container.\n     * @param string $containerClass Name of the compiled class. Customize only if necessary.\n     * @param string $containerParentClass Name of the compiled container parent class. Customize only if necessary.\n     */\n    public function enableCompilation(\n        string $directory,\n        string $containerClass = 'CompiledContainer',\n        string $containerParentClass = CompiledContainer::class\n    ) : self {\n        $this->ensureNotLocked();\n\n        $this->compileToDirectory = $directory;\n        $this->containerClass = $containerClass;\n        $this->containerParentClass = $containerParentClass;\n\n        return $this;\n    }\n\n    /**\n     * Enable or disable the use of autowiring to guess injections.\n     *\n     * Enabled by default.\n     *\n     * @return $this\n     */\n    public function useAutowiring(bool $bool) : self\n    {\n        $this->ensureNotLocked();\n\n        $this->useAutowiring = $bool;\n\n        return $this;\n    }\n\n    /**\n     * Enable or disable the use of annotations to guess injections.\n     *\n     * Disabled by default.\n     *\n     * @return $this\n     */\n    public function useAnnotations(bool $bool) : self\n    {\n        $this->ensureNotLocked();\n\n        $this->useAnnotations = $bool;\n\n        return $this;\n    }\n\n    /**\n     * Enable or disable ignoring phpdoc errors (non-existent classes in `@param` or `@var`).\n     *\n     * @return $this\n     */\n    public function ignorePhpDocErrors(bool $bool) : self\n    {\n        $this->ensureNotLocked();\n\n        $this->ignorePhpDocErrors = $bool;\n\n        return $this;\n    }\n\n    /**\n     * Configure the proxy generation.\n     *\n     * For dev environment, use `writeProxiesToFile(false)` (default configuration)\n     * For production environment, use `writeProxiesToFile(true, 'tmp/proxies')`\n     *\n     * @see https://php-di.org/doc/lazy-injection.html\n     *\n     * @param bool $writeToFile If true, write the proxies to disk to improve performances\n     * @param string|null $proxyDirectory Directory where to write the proxies\n     * @throws InvalidArgumentException when writeToFile is set to true and the proxy directory is null\n     * @return $this\n     */\n    public function writeProxiesToFile(bool $writeToFile, string $proxyDirectory = null) : self\n    {\n        $this->ensureNotLocked();\n\n        $this->writeProxiesToFile = $writeToFile;\n\n        if ($writeToFile && $proxyDirectory === null) {\n            throw new InvalidArgumentException(\n                'The proxy directory must be specified if you want to write proxies on disk'\n            );\n        }\n        $this->proxyDirectory = $proxyDirectory;\n\n        return $this;\n    }\n\n    /**\n     * If PHP-DI's container is wrapped by another container, we can\n     * set this so that PHP-DI will use the wrapper rather than itself for building objects.\n     *\n     * @return $this\n     */\n    public function wrapContainer(ContainerInterface $otherContainer) : self\n    {\n        $this->ensureNotLocked();\n\n        $this->wrapperContainer = $otherContainer;\n\n        return $this;\n    }\n\n    /**\n     * Add definitions to the container.\n     *\n     * @param string|array|DefinitionSource ...$definitions Can be an array of definitions, the\n     *                                                      name of a file containing definitions\n     *                                                      or a DefinitionSource object.\n     * @return $this\n     */\n    public function addDefinitions(...$definitions) : self\n    {\n        $this->ensureNotLocked();\n\n        foreach ($definitions as $definition) {\n            if (!is_string($definition) && !is_array($definition) && !($definition instanceof DefinitionSource)) {\n                throw new InvalidArgumentException(sprintf(\n                    '%s parameter must be a string, an array or a DefinitionSource object, %s given',\n                    'ContainerBuilder::addDefinitions()',\n                    is_object($definition) ? get_class($definition) : gettype($definition)\n                ));\n            }\n\n            $this->definitionSources[] = $definition;\n        }\n\n        return $this;\n    }\n\n    /**\n     * Enables the use of APCu to cache definitions.\n     *\n     * You must have APCu enabled to use it.\n     *\n     * Before using this feature, you should try these steps first:\n     * - enable compilation if not already done (see `enableCompilation()`)\n     * - if you use autowiring or annotations, add all the classes you are using into your configuration so that\n     *   PHP-DI knows about them and compiles them\n     * Once this is done, you can try to optimize performances further with APCu. It can also be useful if you use\n     * `Container::make()` instead of `get()` (`make()` calls cannot be compiled so they are not optimized).\n     *\n     * Remember to clear APCu on each deploy else your application will have a stale cache. Do not enable the cache\n     * in development environment: any change you will make to the code will be ignored because of the cache.\n     *\n     * @see https://php-di.org/doc/performances.html\n     *\n     * @param string $cacheNamespace use unique namespace per container when sharing a single APC memory pool to prevent cache collisions\n     * @return $this\n     */\n    public function enableDefinitionCache(string $cacheNamespace = '') : self\n    {\n        $this->ensureNotLocked();\n\n        $this->sourceCache = true;\n        $this->sourceCacheNamespace = $cacheNamespace;\n\n        return $this;\n    }\n\n    /**\n     * Are we building a compiled container?\n     */\n    public function isCompilationEnabled() : bool\n    {\n        return (bool) $this->compileToDirectory;\n    }\n\n    private function ensureNotLocked()\n    {\n        if ($this->locked) {\n            throw new \\LogicException('The ContainerBuilder cannot be modified after the container has been built');\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Definition/ArrayDefinition.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Definition;\n\n/**\n * Definition of an array containing values or references.\n *\n * @since 5.0\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\nclass ArrayDefinition implements Definition\n{\n    /**\n     * Entry name.\n     * @var string\n     */\n    private $name = '';\n\n    /**\n     * @var array\n     */\n    private $values;\n\n    public function __construct(array $values)\n    {\n        $this->values = $values;\n    }\n\n    public function getName() : string\n    {\n        return $this->name;\n    }\n\n    public function setName(string $name)\n    {\n        $this->name = $name;\n    }\n\n    public function getValues() : array\n    {\n        return $this->values;\n    }\n\n    public function replaceNestedDefinitions(callable $replacer)\n    {\n        $this->values = array_map($replacer, $this->values);\n    }\n\n    public function __toString()\n    {\n        $str = '[' . \\PHP_EOL;\n\n        foreach ($this->values as $key => $value) {\n            if (is_string($key)) {\n                $key = \"'\" . $key . \"'\";\n            }\n\n            $str .= '    ' . $key . ' => ';\n\n            if ($value instanceof Definition) {\n                $str .= str_replace(\\PHP_EOL, \\PHP_EOL . '    ', (string) $value);\n            } else {\n                $str .= var_export($value, true);\n            }\n\n            $str .= ',' . \\PHP_EOL;\n        }\n\n        return $str . ']';\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Definition/ArrayDefinitionExtension.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Definition;\n\nuse DI\\Definition\\Exception\\InvalidDefinition;\n\n/**\n * Extends an array definition by adding new elements into it.\n *\n * @since 5.0\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\nclass ArrayDefinitionExtension extends ArrayDefinition implements ExtendsPreviousDefinition\n{\n    /**\n     * @var ArrayDefinition\n     */\n    private $subDefinition;\n\n    public function getValues() : array\n    {\n        if (! $this->subDefinition) {\n            return parent::getValues();\n        }\n\n        return array_merge($this->subDefinition->getValues(), parent::getValues());\n    }\n\n    public function setExtendedDefinition(Definition $definition)\n    {\n        if (! $definition instanceof ArrayDefinition) {\n            throw new InvalidDefinition(sprintf(\n                'Definition %s tries to add array entries but the previous definition is not an array',\n                $this->getName()\n            ));\n        }\n\n        $this->subDefinition = $definition;\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Definition/AutowireDefinition.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Definition;\n\n/**\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\nclass AutowireDefinition extends ObjectDefinition\n{\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Definition/DecoratorDefinition.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Definition;\n\n/**\n * Factory that decorates a sub-definition.\n *\n * @since 5.0\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\nclass DecoratorDefinition extends FactoryDefinition implements Definition, ExtendsPreviousDefinition\n{\n    /**\n     * @var Definition|null\n     */\n    private $decorated;\n\n    public function setExtendedDefinition(Definition $definition)\n    {\n        $this->decorated = $definition;\n    }\n\n    /**\n     * @return Definition|null\n     */\n    public function getDecoratedDefinition()\n    {\n        return $this->decorated;\n    }\n\n    public function replaceNestedDefinitions(callable $replacer)\n    {\n        // no nested definitions\n    }\n\n    public function __toString()\n    {\n        return 'Decorate(' . $this->getName() . ')';\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Definition/Definition.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Definition;\n\nuse DI\\Factory\\RequestedEntry;\n\n/**\n * Definition.\n *\n * @internal This interface is internal to PHP-DI and may change between minor versions.\n *\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\ninterface Definition extends RequestedEntry\n{\n    /**\n     * Returns the name of the entry in the container.\n     */\n    public function getName() : string;\n\n    /**\n     * Set the name of the entry in the container.\n     */\n    public function setName(string $name);\n\n    /**\n     * Apply a callable that replaces the definitions nested in this definition.\n     */\n    public function replaceNestedDefinitions(callable $replacer);\n\n    /**\n     * Definitions can be cast to string for debugging information.\n     */\n    public function __toString();\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Definition/Dumper/ObjectDefinitionDumper.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Definition\\Dumper;\n\nuse DI\\Definition\\Definition;\nuse DI\\Definition\\ObjectDefinition;\nuse DI\\Definition\\ObjectDefinition\\MethodInjection;\nuse ReflectionException;\n\n/**\n * Dumps object definitions to string for debugging purposes.\n *\n * @since 4.1\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\nclass ObjectDefinitionDumper\n{\n    /**\n     * Returns the definition as string representation.\n     */\n    public function dump(ObjectDefinition $definition) : string\n    {\n        $className = $definition->getClassName();\n        $classExist = class_exists($className) || interface_exists($className);\n\n        // Class\n        if (! $classExist) {\n            $warning = '#UNKNOWN# ';\n        } else {\n            $class = new \\ReflectionClass($className);\n            $warning = $class->isInstantiable() ? '' : '#NOT INSTANTIABLE# ';\n        }\n        $str = sprintf('    class = %s%s', $warning, $className);\n\n        // Lazy\n        $str .= \\PHP_EOL . '    lazy = ' . var_export($definition->isLazy(), true);\n\n        if ($classExist) {\n            // Constructor\n            $str .= $this->dumpConstructor($className, $definition);\n\n            // Properties\n            $str .= $this->dumpProperties($definition);\n\n            // Methods\n            $str .= $this->dumpMethods($className, $definition);\n        }\n\n        return sprintf('Object (' . \\PHP_EOL . '%s' . \\PHP_EOL . ')', $str);\n    }\n\n    private function dumpConstructor(string $className, ObjectDefinition $definition) : string\n    {\n        $str = '';\n\n        $constructorInjection = $definition->getConstructorInjection();\n\n        if ($constructorInjection !== null) {\n            $parameters = $this->dumpMethodParameters($className, $constructorInjection);\n\n            $str .= sprintf(\\PHP_EOL . '    __construct(' . \\PHP_EOL . '        %s' . \\PHP_EOL . '    )', $parameters);\n        }\n\n        return $str;\n    }\n\n    private function dumpProperties(ObjectDefinition $definition) : string\n    {\n        $str = '';\n\n        foreach ($definition->getPropertyInjections() as $propertyInjection) {\n            $value = $propertyInjection->getValue();\n            $valueStr = $value instanceof Definition ? (string) $value : var_export($value, true);\n\n            $str .= sprintf(\\PHP_EOL . '    $%s = %s', $propertyInjection->getPropertyName(), $valueStr);\n        }\n\n        return $str;\n    }\n\n    private function dumpMethods(string $className, ObjectDefinition $definition) : string\n    {\n        $str = '';\n\n        foreach ($definition->getMethodInjections() as $methodInjection) {\n            $parameters = $this->dumpMethodParameters($className, $methodInjection);\n\n            $str .= sprintf(\\PHP_EOL . '    %s(' . \\PHP_EOL . '        %s' . \\PHP_EOL . '    )', $methodInjection->getMethodName(), $parameters);\n        }\n\n        return $str;\n    }\n\n    private function dumpMethodParameters(string $className, MethodInjection $methodInjection) : string\n    {\n        $methodReflection = new \\ReflectionMethod($className, $methodInjection->getMethodName());\n\n        $args = [];\n\n        $definitionParameters = $methodInjection->getParameters();\n\n        foreach ($methodReflection->getParameters() as $index => $parameter) {\n            if (array_key_exists($index, $definitionParameters)) {\n                $value = $definitionParameters[$index];\n                $valueStr = $value instanceof Definition ? (string) $value : var_export($value, true);\n\n                $args[] = sprintf('$%s = %s', $parameter->getName(), $valueStr);\n\n                continue;\n            }\n\n            // If the parameter is optional and wasn't specified, we take its default value\n            if ($parameter->isOptional()) {\n                try {\n                    $value = $parameter->getDefaultValue();\n\n                    $args[] = sprintf(\n                        '$%s = (default value) %s',\n                        $parameter->getName(),\n                        var_export($value, true)\n                    );\n                    continue;\n                } catch (ReflectionException $e) {\n                    // The default value can't be read through Reflection because it is a PHP internal class\n                }\n            }\n\n            $args[] = sprintf('$%s = #UNDEFINED#', $parameter->getName());\n        }\n\n        return implode(\\PHP_EOL . '        ', $args);\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Definition/EnvironmentVariableDefinition.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Definition;\n\n/**\n * Defines a reference to an environment variable, with fallback to a default\n * value if the environment variable is not defined.\n *\n * @author James Harris <james.harris@icecave.com.au>\n */\nclass EnvironmentVariableDefinition implements Definition\n{\n    /**\n     * Entry name.\n     * @var string\n     */\n    private $name = '';\n\n    /**\n     * The name of the environment variable.\n     * @var string\n     */\n    private $variableName;\n\n    /**\n     * Whether or not the environment variable definition is optional.\n     *\n     * If true and the environment variable given by $variableName has not been\n     * defined, $defaultValue is used.\n     *\n     * @var bool\n     */\n    private $isOptional;\n\n    /**\n     * The default value to use if the environment variable is optional and not provided.\n     * @var mixed\n     */\n    private $defaultValue;\n\n    /**\n     * @param string $variableName The name of the environment variable\n     * @param bool $isOptional Whether or not the environment variable definition is optional\n     * @param mixed $defaultValue The default value to use if the environment variable is optional and not provided\n     */\n    public function __construct(string $variableName, bool $isOptional = false, $defaultValue = null)\n    {\n        $this->variableName = $variableName;\n        $this->isOptional = $isOptional;\n        $this->defaultValue = $defaultValue;\n    }\n\n    public function getName() : string\n    {\n        return $this->name;\n    }\n\n    public function setName(string $name)\n    {\n        $this->name = $name;\n    }\n\n    /**\n     * @return string The name of the environment variable\n     */\n    public function getVariableName() : string\n    {\n        return $this->variableName;\n    }\n\n    /**\n     * @return bool Whether or not the environment variable definition is optional\n     */\n    public function isOptional() : bool\n    {\n        return $this->isOptional;\n    }\n\n    /**\n     * @return mixed The default value to use if the environment variable is optional and not provided\n     */\n    public function getDefaultValue()\n    {\n        return $this->defaultValue;\n    }\n\n    public function replaceNestedDefinitions(callable $replacer)\n    {\n        $this->defaultValue = $replacer($this->defaultValue);\n    }\n\n    public function __toString()\n    {\n        $str = '    variable = ' . $this->variableName . \\PHP_EOL\n            . '    optional = ' . ($this->isOptional ? 'yes' : 'no');\n\n        if ($this->isOptional) {\n            if ($this->defaultValue instanceof Definition) {\n                $nestedDefinition = (string) $this->defaultValue;\n                $defaultValueStr = str_replace(\\PHP_EOL, \\PHP_EOL . '    ', $nestedDefinition);\n            } else {\n                $defaultValueStr = var_export($this->defaultValue, true);\n            }\n\n            $str .= \\PHP_EOL . '    default = ' . $defaultValueStr;\n        }\n\n        return sprintf('Environment variable (' . \\PHP_EOL . '%s' . \\PHP_EOL . ')', $str);\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Definition/Exception/InvalidAnnotation.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Definition\\Exception;\n\n/**\n * Error in the definitions using annotations.\n *\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\nclass InvalidAnnotation extends InvalidDefinition\n{\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Definition/Exception/InvalidDefinition.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Definition\\Exception;\n\nuse DI\\Definition\\Definition;\nuse Psr\\Container\\ContainerExceptionInterface;\n\n/**\n * Invalid DI definitions.\n *\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\nclass InvalidDefinition extends \\Exception implements ContainerExceptionInterface\n{\n    public static function create(Definition $definition, string $message, \\Exception $previous = null) : self\n    {\n        return new self(sprintf(\n            '%s' . \\PHP_EOL . 'Full definition:' . \\PHP_EOL . '%s',\n            $message,\n            (string) $definition\n        ), 0, $previous);\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Definition/ExtendsPreviousDefinition.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Definition;\n\n/**\n * A definition that extends a previous definition with the same name.\n *\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\ninterface ExtendsPreviousDefinition extends Definition\n{\n    public function setExtendedDefinition(Definition $definition);\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Definition/FactoryDefinition.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Definition;\n\n/**\n * Definition of a value or class with a factory.\n *\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\nclass FactoryDefinition implements Definition\n{\n    /**\n     * Entry name.\n     * @var string\n     */\n    private $name;\n\n    /**\n     * Callable that returns the value.\n     * @var callable\n     */\n    private $factory;\n\n    /**\n     * Factory parameters.\n     * @var mixed[]\n     */\n    private $parameters = [];\n\n    /**\n     * @param string $name Entry name\n     * @param callable $factory Callable that returns the value associated to the entry name.\n     * @param array $parameters Parameters to be passed to the callable\n     */\n    public function __construct(string $name, $factory, array $parameters = [])\n    {\n        $this->name = $name;\n        $this->factory = $factory;\n        $this->parameters = $parameters;\n    }\n\n    public function getName() : string\n    {\n        return $this->name;\n    }\n\n    public function setName(string $name)\n    {\n        $this->name = $name;\n    }\n\n    /**\n     * @return callable Callable that returns the value associated to the entry name.\n     */\n    public function getCallable()\n    {\n        return $this->factory;\n    }\n\n    /**\n     * @return array Array containing the parameters to be passed to the callable, indexed by name.\n     */\n    public function getParameters() : array\n    {\n        return $this->parameters;\n    }\n\n    public function replaceNestedDefinitions(callable $replacer)\n    {\n        $this->parameters = array_map($replacer, $this->parameters);\n    }\n\n    public function __toString()\n    {\n        return 'Factory';\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Definition/Helper/AutowireDefinitionHelper.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Definition\\Helper;\n\nuse DI\\Definition\\AutowireDefinition;\n\n/**\n * Helps defining how to create an instance of a class using autowiring.\n *\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\nclass AutowireDefinitionHelper extends CreateDefinitionHelper\n{\n    const DEFINITION_CLASS = AutowireDefinition::class;\n\n    /**\n     * Defines a value for a specific argument of the constructor.\n     *\n     * This method is usually used together with annotations or autowiring, when a parameter\n     * is not (or cannot be) type-hinted. Using this method instead of constructor() allows to\n     * avoid defining all the parameters (letting them being resolved using annotations or autowiring)\n     * and only define one.\n     *\n     * @param string|int $parameter Parameter name of position for which the value will be given.\n     * @param mixed $value Value to give to this parameter.\n     *\n     * @return $this\n     */\n    public function constructorParameter($parameter, $value)\n    {\n        $this->constructor[$parameter] = $value;\n\n        return $this;\n    }\n\n    /**\n     * Defines a method to call and a value for a specific argument.\n     *\n     * This method is usually used together with annotations or autowiring, when a parameter\n     * is not (or cannot be) type-hinted. Using this method instead of method() allows to\n     * avoid defining all the parameters (letting them being resolved using annotations or\n     * autowiring) and only define one.\n     *\n     * If multiple calls to the method have been configured already (e.g. in a previous definition)\n     * then this method only overrides the parameter for the *first* call.\n     *\n     * @param string $method Name of the method to call.\n     * @param string|int $parameter Parameter name of position for which the value will be given.\n     * @param mixed $value Value to give to this parameter.\n     *\n     * @return $this\n     */\n    public function methodParameter(string $method, $parameter, $value)\n    {\n        // Special case for the constructor\n        if ($method === '__construct') {\n            $this->constructor[$parameter] = $value;\n\n            return $this;\n        }\n\n        if (! isset($this->methods[$method])) {\n            $this->methods[$method] = [0 => []];\n        }\n\n        $this->methods[$method][0][$parameter] = $value;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Definition/Helper/CreateDefinitionHelper.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Definition\\Helper;\n\nuse DI\\Definition\\Definition;\nuse DI\\Definition\\Exception\\InvalidDefinition;\nuse DI\\Definition\\ObjectDefinition;\nuse DI\\Definition\\ObjectDefinition\\MethodInjection;\nuse DI\\Definition\\ObjectDefinition\\PropertyInjection;\n\n/**\n * Helps defining how to create an instance of a class.\n *\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\nclass CreateDefinitionHelper implements DefinitionHelper\n{\n    const DEFINITION_CLASS = ObjectDefinition::class;\n\n    /**\n     * @var string|null\n     */\n    private $className;\n\n    /**\n     * @var bool|null\n     */\n    private $lazy;\n\n    /**\n     * Array of constructor parameters.\n     * @var array\n     */\n    protected $constructor = [];\n\n    /**\n     * Array of properties and their value.\n     * @var array\n     */\n    private $properties = [];\n\n    /**\n     * Array of methods and their parameters.\n     * @var array\n     */\n    protected $methods = [];\n\n    /**\n     * Helper for defining an object.\n     *\n     * @param string|null $className Class name of the object.\n     *                               If null, the name of the entry (in the container) will be used as class name.\n     */\n    public function __construct(string $className = null)\n    {\n        $this->className = $className;\n    }\n\n    /**\n     * Define the entry as lazy.\n     *\n     * A lazy entry is created only when it is used, a proxy is injected instead.\n     *\n     * @return $this\n     */\n    public function lazy()\n    {\n        $this->lazy = true;\n\n        return $this;\n    }\n\n    /**\n     * Defines the arguments to use to call the constructor.\n     *\n     * This method takes a variable number of arguments, example:\n     *     ->constructor($param1, $param2, $param3)\n     *\n     * @param mixed... $parameters Parameters to use for calling the constructor of the class.\n     *\n     * @return $this\n     */\n    public function constructor(...$parameters)\n    {\n        $this->constructor = $parameters;\n\n        return $this;\n    }\n\n    /**\n     * Defines a value to inject in a property of the object.\n     *\n     * @param string $property Entry in which to inject the value.\n     * @param mixed  $value    Value to inject in the property.\n     *\n     * @return $this\n     */\n    public function property(string $property, $value)\n    {\n        $this->properties[$property] = $value;\n\n        return $this;\n    }\n\n    /**\n     * Defines a method to call and the arguments to use.\n     *\n     * This method takes a variable number of arguments after the method name, example:\n     *\n     *     ->method('myMethod', $param1, $param2)\n     *\n     * Can be used multiple times to declare multiple calls.\n     *\n     * @param string $method       Name of the method to call.\n     * @param mixed... $parameters Parameters to use for calling the method.\n     *\n     * @return $this\n     */\n    public function method(string $method, ...$parameters)\n    {\n        if (! isset($this->methods[$method])) {\n            $this->methods[$method] = [];\n        }\n\n        $this->methods[$method][] = $parameters;\n\n        return $this;\n    }\n\n    /**\n     * @return ObjectDefinition\n     */\n    public function getDefinition(string $entryName) : Definition\n    {\n        $class = $this::DEFINITION_CLASS;\n        /** @var ObjectDefinition $definition */\n        $definition = new $class($entryName, $this->className);\n\n        if ($this->lazy !== null) {\n            $definition->setLazy($this->lazy);\n        }\n\n        if (! empty($this->constructor)) {\n            $parameters = $this->fixParameters($definition, '__construct', $this->constructor);\n            $constructorInjection = MethodInjection::constructor($parameters);\n            $definition->setConstructorInjection($constructorInjection);\n        }\n\n        if (! empty($this->properties)) {\n            foreach ($this->properties as $property => $value) {\n                $definition->addPropertyInjection(\n                    new PropertyInjection($property, $value)\n                );\n            }\n        }\n\n        if (! empty($this->methods)) {\n            foreach ($this->methods as $method => $calls) {\n                foreach ($calls as $parameters) {\n                    $parameters = $this->fixParameters($definition, $method, $parameters);\n                    $methodInjection = new MethodInjection($method, $parameters);\n                    $definition->addMethodInjection($methodInjection);\n                }\n            }\n        }\n\n        return $definition;\n    }\n\n    /**\n     * Fixes parameters indexed by the parameter name -> reindex by position.\n     *\n     * This is necessary so that merging definitions between sources is possible.\n     *\n     * @throws InvalidDefinition\n     */\n    private function fixParameters(ObjectDefinition $definition, string $method, array $parameters) : array\n    {\n        $fixedParameters = [];\n\n        foreach ($parameters as $index => $parameter) {\n            // Parameter indexed by the parameter name, we reindex it with its position\n            if (is_string($index)) {\n                $callable = [$definition->getClassName(), $method];\n\n                try {\n                    $reflectionParameter = new \\ReflectionParameter($callable, $index);\n                } catch (\\ReflectionException $e) {\n                    throw InvalidDefinition::create($definition, sprintf(\"Parameter with name '%s' could not be found. %s.\", $index, $e->getMessage()));\n                }\n\n                $index = $reflectionParameter->getPosition();\n            }\n\n            $fixedParameters[$index] = $parameter;\n        }\n\n        return $fixedParameters;\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Definition/Helper/DefinitionHelper.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Definition\\Helper;\n\nuse DI\\Definition\\Definition;\n\n/**\n * Helps defining container entries.\n *\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\ninterface DefinitionHelper\n{\n    /**\n     * @param string $entryName Container entry name\n     */\n    public function getDefinition(string $entryName) : Definition;\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Definition/Helper/FactoryDefinitionHelper.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Definition\\Helper;\n\nuse DI\\Definition\\DecoratorDefinition;\nuse DI\\Definition\\Definition;\nuse DI\\Definition\\FactoryDefinition;\n\n/**\n * Helps defining how to create an instance of a class using a factory (callable).\n *\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\nclass FactoryDefinitionHelper implements DefinitionHelper\n{\n    /**\n     * @var callable\n     */\n    private $factory;\n\n    /**\n     * @var bool\n     */\n    private $decorate;\n\n    /**\n     * @var array\n     */\n    private $parameters = [];\n\n    /**\n     * @param callable $factory\n     * @param bool $decorate Is the factory decorating a previous definition?\n     */\n    public function __construct($factory, bool $decorate = false)\n    {\n        $this->factory = $factory;\n        $this->decorate = $decorate;\n    }\n\n    /**\n     * @param string $entryName Container entry name\n     * @return FactoryDefinition\n     */\n    public function getDefinition(string $entryName) : Definition\n    {\n        if ($this->decorate) {\n            return new DecoratorDefinition($entryName, $this->factory, $this->parameters);\n        }\n\n        return new FactoryDefinition($entryName, $this->factory, $this->parameters);\n    }\n\n    /**\n     * Defines arguments to pass to the factory.\n     *\n     * Because factory methods do not yet support annotations or autowiring, this method\n     * should be used to define all parameters except the ContainerInterface and RequestedEntry.\n     *\n     * Multiple calls can be made to the method to override individual values.\n     *\n     * @param string $parameter Name or index of the parameter for which the value will be given.\n     * @param mixed  $value     Value to give to this parameter.\n     *\n     * @return $this\n     */\n    public function parameter(string $parameter, $value)\n    {\n        $this->parameters[$parameter] = $value;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Definition/InstanceDefinition.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Definition;\n\n/**\n * Defines injections on an existing class instance.\n *\n * @since  5.0\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\nclass InstanceDefinition implements Definition\n{\n    /**\n     * Instance on which to inject dependencies.\n     *\n     * @var object\n     */\n    private $instance;\n\n    /**\n     * @var ObjectDefinition\n     */\n    private $objectDefinition;\n\n    /**\n     * @param object $instance\n     */\n    public function __construct($instance, ObjectDefinition $objectDefinition)\n    {\n        $this->instance = $instance;\n        $this->objectDefinition = $objectDefinition;\n    }\n\n    public function getName() : string\n    {\n        // Name are superfluous for instance definitions\n        return '';\n    }\n\n    public function setName(string $name)\n    {\n        // Name are superfluous for instance definitions\n    }\n\n    /**\n     * @return object\n     */\n    public function getInstance()\n    {\n        return $this->instance;\n    }\n\n    public function getObjectDefinition() : ObjectDefinition\n    {\n        return $this->objectDefinition;\n    }\n\n    public function replaceNestedDefinitions(callable $replacer)\n    {\n        $this->objectDefinition->replaceNestedDefinitions($replacer);\n    }\n\n    public function __toString()\n    {\n        return 'Instance';\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Definition/ObjectDefinition/MethodInjection.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Definition\\ObjectDefinition;\n\nuse DI\\Definition\\Definition;\n\n/**\n * Describe an injection in an object method.\n *\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\nclass MethodInjection implements Definition\n{\n    /**\n     * @var string\n     */\n    private $methodName;\n\n    /**\n     * @var mixed[]\n     */\n    private $parameters = [];\n\n    public function __construct(string $methodName, array $parameters = [])\n    {\n        $this->methodName = $methodName;\n        $this->parameters = $parameters;\n    }\n\n    public static function constructor(array $parameters = []) : self\n    {\n        return new self('__construct', $parameters);\n    }\n\n    public function getMethodName() : string\n    {\n        return $this->methodName;\n    }\n\n    /**\n     * @return mixed[]\n     */\n    public function getParameters() : array\n    {\n        return $this->parameters;\n    }\n\n    /**\n     * Replace the parameters of the definition by a new array of parameters.\n     */\n    public function replaceParameters(array $parameters)\n    {\n        $this->parameters = $parameters;\n    }\n\n    public function merge(self $definition)\n    {\n        // In case of conflicts, the current definition prevails.\n        $this->parameters = $this->parameters + $definition->parameters;\n    }\n\n    public function getName() : string\n    {\n        return '';\n    }\n\n    public function setName(string $name)\n    {\n        // The name does not matter for method injections\n    }\n\n    public function replaceNestedDefinitions(callable $replacer)\n    {\n        $this->parameters = array_map($replacer, $this->parameters);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function __toString()\n    {\n        return sprintf('method(%s)', $this->methodName);\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Definition/ObjectDefinition/PropertyInjection.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Definition\\ObjectDefinition;\n\n/**\n * Describe an injection in a class property.\n *\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\nclass PropertyInjection\n{\n    /**\n     * Property name.\n     * @var string\n     */\n    private $propertyName;\n\n    /**\n     * Value that should be injected in the property.\n     * @var mixed\n     */\n    private $value;\n\n    /**\n     * Use for injecting in properties of parent classes: the class name\n     * must be the name of the parent class because private properties\n     * can be attached to the parent classes, not the one we are resolving.\n     * @var string|null\n     */\n    private $className;\n\n    /**\n     * @param string $propertyName Property name\n     * @param mixed $value Value that should be injected in the property\n     */\n    public function __construct(string $propertyName, $value, string $className = null)\n    {\n        $this->propertyName = $propertyName;\n        $this->value = $value;\n        $this->className = $className;\n    }\n\n    public function getPropertyName() : string\n    {\n        return $this->propertyName;\n    }\n\n    /**\n     * @return mixed Value that should be injected in the property\n     */\n    public function getValue()\n    {\n        return $this->value;\n    }\n\n    /**\n     * @return string|null\n     */\n    public function getClassName()\n    {\n        return $this->className;\n    }\n\n    public function replaceNestedDefinition(callable $replacer)\n    {\n        $this->value = $replacer($this->value);\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Definition/ObjectDefinition.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Definition;\n\nuse DI\\Definition\\Dumper\\ObjectDefinitionDumper;\nuse DI\\Definition\\ObjectDefinition\\MethodInjection;\nuse DI\\Definition\\ObjectDefinition\\PropertyInjection;\nuse DI\\Definition\\Source\\DefinitionArray;\nuse ReflectionClass;\n\n/**\n * Defines how an object can be instantiated.\n *\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\nclass ObjectDefinition implements Definition\n{\n    /**\n     * Entry name (most of the time, same as $classname).\n     * @var string\n     */\n    private $name;\n\n    /**\n     * Class name (if null, then the class name is $name).\n     * @var string|null\n     */\n    protected $className;\n\n    /**\n     * Constructor parameter injection.\n     * @var MethodInjection|null\n     */\n    protected $constructorInjection;\n\n    /**\n     * Property injections.\n     * @var PropertyInjection[]\n     */\n    protected $propertyInjections = [];\n\n    /**\n     * Method calls.\n     * @var MethodInjection[][]\n     */\n    protected $methodInjections = [];\n\n    /**\n     * @var bool|null\n     */\n    protected $lazy;\n\n    /**\n     * Store if the class exists. Storing it (in cache) avoids recomputing this.\n     *\n     * @var bool\n     */\n    private $classExists;\n\n    /**\n     * Store if the class is instantiable. Storing it (in cache) avoids recomputing this.\n     *\n     * @var bool\n     */\n    private $isInstantiable;\n\n    /**\n     * @param string $name Entry name\n     */\n    public function __construct(string $name, string $className = null)\n    {\n        $this->name = $name;\n        $this->setClassName($className);\n    }\n\n    public function getName() : string\n    {\n        return $this->name;\n    }\n\n    public function setName(string $name)\n    {\n        $this->name = $name;\n    }\n\n    public function setClassName(string $className = null)\n    {\n        $this->className = $className;\n\n        $this->updateCache();\n    }\n\n    public function getClassName() : string\n    {\n        if ($this->className !== null) {\n            return $this->className;\n        }\n\n        return $this->name;\n    }\n\n    /**\n     * @return MethodInjection|null\n     */\n    public function getConstructorInjection()\n    {\n        return $this->constructorInjection;\n    }\n\n    public function setConstructorInjection(MethodInjection $constructorInjection)\n    {\n        $this->constructorInjection = $constructorInjection;\n    }\n\n    public function completeConstructorInjection(MethodInjection $injection)\n    {\n        if ($this->constructorInjection !== null) {\n            // Merge\n            $this->constructorInjection->merge($injection);\n        } else {\n            // Set\n            $this->constructorInjection = $injection;\n        }\n    }\n\n    /**\n     * @return PropertyInjection[] Property injections\n     */\n    public function getPropertyInjections() : array\n    {\n        return $this->propertyInjections;\n    }\n\n    public function addPropertyInjection(PropertyInjection $propertyInjection)\n    {\n        $className = $propertyInjection->getClassName();\n        if ($className) {\n            // Index with the class name to avoid collisions between parent and\n            // child private properties with the same name\n            $key = $className . '::' . $propertyInjection->getPropertyName();\n        } else {\n            $key = $propertyInjection->getPropertyName();\n        }\n\n        $this->propertyInjections[$key] = $propertyInjection;\n    }\n\n    /**\n     * @return MethodInjection[] Method injections\n     */\n    public function getMethodInjections() : array\n    {\n        // Return array leafs\n        $injections = [];\n        array_walk_recursive($this->methodInjections, function ($injection) use (&$injections) {\n            $injections[] = $injection;\n        });\n\n        return $injections;\n    }\n\n    public function addMethodInjection(MethodInjection $methodInjection)\n    {\n        $method = $methodInjection->getMethodName();\n        if (! isset($this->methodInjections[$method])) {\n            $this->methodInjections[$method] = [];\n        }\n        $this->methodInjections[$method][] = $methodInjection;\n    }\n\n    public function completeFirstMethodInjection(MethodInjection $injection)\n    {\n        $method = $injection->getMethodName();\n\n        if (isset($this->methodInjections[$method][0])) {\n            // Merge\n            $this->methodInjections[$method][0]->merge($injection);\n        } else {\n            // Set\n            $this->addMethodInjection($injection);\n        }\n    }\n\n    public function setLazy(bool $lazy = null)\n    {\n        $this->lazy = $lazy;\n    }\n\n    public function isLazy() : bool\n    {\n        if ($this->lazy !== null) {\n            return $this->lazy;\n        }\n        // Default value\n        return false;\n    }\n\n    public function classExists() : bool\n    {\n        return $this->classExists;\n    }\n\n    public function isInstantiable() : bool\n    {\n        return $this->isInstantiable;\n    }\n\n    public function replaceNestedDefinitions(callable $replacer)\n    {\n        array_walk($this->propertyInjections, function (PropertyInjection $propertyInjection) use ($replacer) {\n            $propertyInjection->replaceNestedDefinition($replacer);\n        });\n\n        if ($this->constructorInjection) {\n            $this->constructorInjection->replaceNestedDefinitions($replacer);\n        }\n\n        array_walk($this->methodInjections, function ($injectionArray) use ($replacer) {\n            array_walk($injectionArray, function (MethodInjection $methodInjection) use ($replacer) {\n                $methodInjection->replaceNestedDefinitions($replacer);\n            });\n        });\n    }\n\n    /**\n     * Replaces all the wildcards in the string with the given replacements.\n     *\n     * @param string[] $replacements\n     */\n    public function replaceWildcards(array $replacements)\n    {\n        $className = $this->getClassName();\n\n        foreach ($replacements as $replacement) {\n            $pos = strpos($className, DefinitionArray::WILDCARD);\n            if ($pos !== false) {\n                $className = substr_replace($className, $replacement, $pos, 1);\n            }\n        }\n\n        $this->setClassName($className);\n    }\n\n    public function __toString()\n    {\n        return (new ObjectDefinitionDumper)->dump($this);\n    }\n\n    private function updateCache()\n    {\n        $className = $this->getClassName();\n\n        $this->classExists = class_exists($className) || interface_exists($className);\n\n        if (! $this->classExists) {\n            $this->isInstantiable = false;\n\n            return;\n        }\n\n        $class = new ReflectionClass($className);\n        $this->isInstantiable = $class->isInstantiable();\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Definition/Reference.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Definition;\n\nuse Psr\\Container\\ContainerInterface;\n\n/**\n * Represents a reference to another entry.\n *\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\nclass Reference implements Definition, SelfResolvingDefinition\n{\n    /**\n     * Entry name.\n     * @var string\n     */\n    private $name = '';\n\n    /**\n     * Name of the target entry.\n     * @var string\n     */\n    private $targetEntryName;\n\n    /**\n     * @param string $targetEntryName Name of the target entry\n     */\n    public function __construct(string $targetEntryName)\n    {\n        $this->targetEntryName = $targetEntryName;\n    }\n\n    public function getName() : string\n    {\n        return $this->name;\n    }\n\n    public function setName(string $name)\n    {\n        $this->name = $name;\n    }\n\n    public function getTargetEntryName() : string\n    {\n        return $this->targetEntryName;\n    }\n\n    public function resolve(ContainerInterface $container)\n    {\n        return $container->get($this->getTargetEntryName());\n    }\n\n    public function isResolvable(ContainerInterface $container) : bool\n    {\n        return $container->has($this->getTargetEntryName());\n    }\n\n    public function replaceNestedDefinitions(callable $replacer)\n    {\n        // no nested definitions\n    }\n\n    public function __toString()\n    {\n        return sprintf(\n            'get(%s)',\n            $this->targetEntryName\n        );\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Definition/Resolver/ArrayResolver.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Definition\\Resolver;\n\nuse DI\\Definition\\ArrayDefinition;\nuse DI\\Definition\\Definition;\nuse DI\\DependencyException;\nuse Exception;\n\n/**\n * Resolves an array definition to a value.\n *\n * @since 5.0\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\nclass ArrayResolver implements DefinitionResolver\n{\n    /**\n     * @var DefinitionResolver\n     */\n    private $definitionResolver;\n\n    /**\n     * @param DefinitionResolver $definitionResolver Used to resolve nested definitions.\n     */\n    public function __construct(DefinitionResolver $definitionResolver)\n    {\n        $this->definitionResolver = $definitionResolver;\n    }\n\n    /**\n     * Resolve an array definition to a value.\n     *\n     * An array definition can contain simple values or references to other entries.\n     *\n     * @param ArrayDefinition $definition\n     */\n    public function resolve(Definition $definition, array $parameters = []) : array\n    {\n        $values = $definition->getValues();\n\n        // Resolve nested definitions\n        array_walk_recursive($values, function (& $value, $key) use ($definition) {\n            if ($value instanceof Definition) {\n                $value = $this->resolveDefinition($value, $definition, $key);\n            }\n        });\n\n        return $values;\n    }\n\n    public function isResolvable(Definition $definition, array $parameters = []) : bool\n    {\n        return true;\n    }\n\n    private function resolveDefinition(Definition $value, ArrayDefinition $definition, $key)\n    {\n        try {\n            return $this->definitionResolver->resolve($value);\n        } catch (DependencyException $e) {\n            throw $e;\n        } catch (Exception $e) {\n            throw new DependencyException(sprintf(\n                'Error while resolving %s[%s]. %s',\n                $definition->getName(),\n                $key,\n                $e->getMessage()\n            ), 0, $e);\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Definition/Resolver/DecoratorResolver.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Definition\\Resolver;\n\nuse DI\\Definition\\DecoratorDefinition;\nuse DI\\Definition\\Definition;\nuse DI\\Definition\\Exception\\InvalidDefinition;\nuse Psr\\Container\\ContainerInterface;\n\n/**\n * Resolves a decorator definition to a value.\n *\n * @since 5.0\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\nclass DecoratorResolver implements DefinitionResolver\n{\n    /**\n     * @var ContainerInterface\n     */\n    private $container;\n\n    /**\n     * @var DefinitionResolver\n     */\n    private $definitionResolver;\n\n    /**\n     * The resolver needs a container. This container will be passed to the factory as a parameter\n     * so that the factory can access other entries of the container.\n     *\n     * @param DefinitionResolver $definitionResolver Used to resolve nested definitions.\n     */\n    public function __construct(ContainerInterface $container, DefinitionResolver $definitionResolver)\n    {\n        $this->container = $container;\n        $this->definitionResolver = $definitionResolver;\n    }\n\n    /**\n     * Resolve a decorator definition to a value.\n     *\n     * This will call the callable of the definition and pass it the decorated entry.\n     *\n     * @param DecoratorDefinition $definition\n     */\n    public function resolve(Definition $definition, array $parameters = [])\n    {\n        $callable = $definition->getCallable();\n\n        if (! is_callable($callable)) {\n            throw new InvalidDefinition(sprintf(\n                'The decorator \"%s\" is not callable',\n                $definition->getName()\n            ));\n        }\n\n        $decoratedDefinition = $definition->getDecoratedDefinition();\n\n        if (! $decoratedDefinition instanceof Definition) {\n            if (! $definition->getName()) {\n                throw new InvalidDefinition('Decorators cannot be nested in another definition');\n            }\n\n            throw new InvalidDefinition(sprintf(\n                'Entry \"%s\" decorates nothing: no previous definition with the same name was found',\n                $definition->getName()\n            ));\n        }\n\n        $decorated = $this->definitionResolver->resolve($decoratedDefinition, $parameters);\n\n        return call_user_func($callable, $decorated, $this->container);\n    }\n\n    public function isResolvable(Definition $definition, array $parameters = []) : bool\n    {\n        return true;\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Definition/Resolver/DefinitionResolver.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Definition\\Resolver;\n\nuse DI\\Definition\\Definition;\nuse DI\\Definition\\Exception\\InvalidDefinition;\n\n/**\n * Resolves a definition to a value.\n *\n * @since 4.0\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\ninterface DefinitionResolver\n{\n    /**\n     * Resolve a definition to a value.\n     *\n     * @param Definition $definition Object that defines how the value should be obtained.\n     * @param array      $parameters Optional parameters to use to build the entry.\n     *\n     * @throws InvalidDefinition If the definition cannot be resolved.\n     *\n     * @return mixed Value obtained from the definition.\n     */\n    public function resolve(Definition $definition, array $parameters = []);\n\n    /**\n     * Check if a definition can be resolved.\n     *\n     * @param Definition $definition Object that defines how the value should be obtained.\n     * @param array      $parameters Optional parameters to use to build the entry.\n     */\n    public function isResolvable(Definition $definition, array $parameters = []) : bool;\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Definition/Resolver/EnvironmentVariableResolver.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Definition\\Resolver;\n\nuse DI\\Definition\\Definition;\nuse DI\\Definition\\EnvironmentVariableDefinition;\nuse DI\\Definition\\Exception\\InvalidDefinition;\n\n/**\n * Resolves a environment variable definition to a value.\n *\n * @author James Harris <james.harris@icecave.com.au>\n */\nclass EnvironmentVariableResolver implements DefinitionResolver\n{\n    /**\n     * @var DefinitionResolver\n     */\n    private $definitionResolver;\n\n    /**\n     * @var callable\n     */\n    private $variableReader;\n\n    public function __construct(DefinitionResolver $definitionResolver, $variableReader = null)\n    {\n        $this->definitionResolver = $definitionResolver;\n        $this->variableReader = $variableReader ?? [$this, 'getEnvVariable'];\n    }\n\n    /**\n     * Resolve an environment variable definition to a value.\n     *\n     * @param EnvironmentVariableDefinition $definition\n     */\n    public function resolve(Definition $definition, array $parameters = [])\n    {\n        $value = call_user_func($this->variableReader, $definition->getVariableName());\n\n        if (false !== $value) {\n            return $value;\n        }\n\n        if (!$definition->isOptional()) {\n            throw new InvalidDefinition(sprintf(\n                \"The environment variable '%s' has not been defined\",\n                $definition->getVariableName()\n            ));\n        }\n\n        $value = $definition->getDefaultValue();\n\n        // Nested definition\n        if ($value instanceof Definition) {\n            return $this->definitionResolver->resolve($value);\n        }\n\n        return $value;\n    }\n\n    public function isResolvable(Definition $definition, array $parameters = []) : bool\n    {\n        return true;\n    }\n\n    protected function getEnvVariable(string $variableName)\n    {\n        if (isset($_ENV[$variableName])) {\n            return $_ENV[$variableName];\n        } elseif (isset($_SERVER[$variableName])) {\n            return $_SERVER[$variableName];\n        }\n\n        return getenv($variableName);\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Definition/Resolver/FactoryResolver.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Definition\\Resolver;\n\nuse DI\\Definition\\Definition;\nuse DI\\Definition\\Exception\\InvalidDefinition;\nuse DI\\Definition\\FactoryDefinition;\nuse DI\\Invoker\\FactoryParameterResolver;\nuse Invoker\\Exception\\NotCallableException;\nuse Invoker\\Exception\\NotEnoughParametersException;\nuse Invoker\\Invoker;\nuse Invoker\\ParameterResolver\\AssociativeArrayResolver;\nuse Invoker\\ParameterResolver\\DefaultValueResolver;\nuse Invoker\\ParameterResolver\\NumericArrayResolver;\nuse Invoker\\ParameterResolver\\ResolverChain;\nuse Psr\\Container\\ContainerInterface;\n\n/**\n * Resolves a factory definition to a value.\n *\n * @since 4.0\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\nclass FactoryResolver implements DefinitionResolver\n{\n    /**\n     * @var ContainerInterface\n     */\n    private $container;\n\n    /**\n     * @var Invoker|null\n     */\n    private $invoker;\n\n    /**\n     * @var DefinitionResolver\n     */\n    private $resolver;\n\n    /**\n     * The resolver needs a container. This container will be passed to the factory as a parameter\n     * so that the factory can access other entries of the container.\n     */\n    public function __construct(ContainerInterface $container, DefinitionResolver $resolver)\n    {\n        $this->container = $container;\n        $this->resolver = $resolver;\n    }\n\n    /**\n     * Resolve a factory definition to a value.\n     *\n     * This will call the callable of the definition.\n     *\n     * @param FactoryDefinition $definition\n     */\n    public function resolve(Definition $definition, array $parameters = [])\n    {\n        if (! $this->invoker) {\n            $parameterResolver = new ResolverChain([\n                new AssociativeArrayResolver,\n                new FactoryParameterResolver($this->container),\n                new NumericArrayResolver,\n                new DefaultValueResolver,\n            ]);\n\n            $this->invoker = new Invoker($parameterResolver, $this->container);\n        }\n\n        $callable = $definition->getCallable();\n\n        try {\n            $providedParams = [$this->container, $definition];\n            $extraParams = $this->resolveExtraParams($definition->getParameters());\n            $providedParams = array_merge($providedParams, $extraParams, $parameters);\n\n            return $this->invoker->call($callable, $providedParams);\n        } catch (NotCallableException $e) {\n            // Custom error message to help debugging\n            if (is_string($callable) && class_exists($callable) && method_exists($callable, '__invoke')) {\n                throw new InvalidDefinition(sprintf(\n                    'Entry \"%s\" cannot be resolved: factory %s. Invokable classes cannot be automatically resolved if autowiring is disabled on the container, you need to enable autowiring or define the entry manually.',\n                    $definition->getName(),\n                    $e->getMessage()\n                ));\n            }\n\n            throw new InvalidDefinition(sprintf(\n                'Entry \"%s\" cannot be resolved: factory %s',\n                $definition->getName(),\n                $e->getMessage()\n            ));\n        } catch (NotEnoughParametersException $e) {\n            throw new InvalidDefinition(sprintf(\n                'Entry \"%s\" cannot be resolved: %s',\n                $definition->getName(),\n                $e->getMessage()\n            ));\n        }\n    }\n\n    public function isResolvable(Definition $definition, array $parameters = []) : bool\n    {\n        return true;\n    }\n\n    private function resolveExtraParams(array $params) : array\n    {\n        $resolved = [];\n        foreach ($params as $key => $value) {\n            // Nested definitions\n            if ($value instanceof Definition) {\n                $value = $this->resolver->resolve($value);\n            }\n            $resolved[$key] = $value;\n        }\n\n        return $resolved;\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Definition/Resolver/InstanceInjector.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Definition\\Resolver;\n\nuse DI\\Definition\\Definition;\nuse DI\\Definition\\InstanceDefinition;\nuse DI\\DependencyException;\nuse Psr\\Container\\NotFoundExceptionInterface;\n\n/**\n * Injects dependencies on an existing instance.\n *\n * @since 5.0\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\nclass InstanceInjector extends ObjectCreator\n{\n    /**\n     * Injects dependencies on an existing instance.\n     *\n     * @param InstanceDefinition $definition\n     */\n    public function resolve(Definition $definition, array $parameters = [])\n    {\n        try {\n            $this->injectMethodsAndProperties($definition->getInstance(), $definition->getObjectDefinition());\n        } catch (NotFoundExceptionInterface $e) {\n            $message = sprintf(\n                'Error while injecting dependencies into %s: %s',\n                get_class($definition->getInstance()),\n                $e->getMessage()\n            );\n\n            throw new DependencyException($message, 0, $e);\n        }\n\n        return $definition;\n    }\n\n    public function isResolvable(Definition $definition, array $parameters = []) : bool\n    {\n        return true;\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Definition/Resolver/ObjectCreator.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Definition\\Resolver;\n\nuse DI\\Definition\\Definition;\nuse DI\\Definition\\Exception\\InvalidDefinition;\nuse DI\\Definition\\ObjectDefinition;\nuse DI\\Definition\\ObjectDefinition\\PropertyInjection;\nuse DI\\DependencyException;\nuse DI\\Proxy\\ProxyFactory;\nuse Exception;\nuse ProxyManager\\Proxy\\LazyLoadingInterface;\nuse Psr\\Container\\NotFoundExceptionInterface;\nuse ReflectionClass;\nuse ReflectionProperty;\n\n/**\n * Create objects based on an object definition.\n *\n * @since 4.0\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\nclass ObjectCreator implements DefinitionResolver\n{\n    /**\n     * @var ProxyFactory\n     */\n    private $proxyFactory;\n\n    /**\n     * @var ParameterResolver\n     */\n    private $parameterResolver;\n\n    /**\n     * @var DefinitionResolver\n     */\n    private $definitionResolver;\n\n    /**\n     * @param DefinitionResolver $definitionResolver Used to resolve nested definitions.\n     * @param ProxyFactory       $proxyFactory       Used to create proxies for lazy injections.\n     */\n    public function __construct(\n        DefinitionResolver $definitionResolver,\n        ProxyFactory $proxyFactory\n    ) {\n        $this->definitionResolver = $definitionResolver;\n        $this->proxyFactory = $proxyFactory;\n        $this->parameterResolver = new ParameterResolver($definitionResolver);\n    }\n\n    /**\n     * Resolve a class definition to a value.\n     *\n     * This will create a new instance of the class using the injections points defined.\n     *\n     * @param ObjectDefinition $definition\n     *\n     * @return object|null\n     */\n    public function resolve(Definition $definition, array $parameters = [])\n    {\n        // Lazy?\n        if ($definition->isLazy()) {\n            return $this->createProxy($definition, $parameters);\n        }\n\n        return $this->createInstance($definition, $parameters);\n    }\n\n    /**\n     * The definition is not resolvable if the class is not instantiable (interface or abstract)\n     * or if the class doesn't exist.\n     *\n     * @param ObjectDefinition $definition\n     */\n    public function isResolvable(Definition $definition, array $parameters = []) : bool\n    {\n        return $definition->isInstantiable();\n    }\n\n    /**\n     * Returns a proxy instance.\n     */\n    private function createProxy(ObjectDefinition $definition, array $parameters) : LazyLoadingInterface\n    {\n        /** @noinspection PhpUnusedParameterInspection */\n        $proxy = $this->proxyFactory->createProxy(\n            $definition->getClassName(),\n            function (& $wrappedObject, $proxy, $method, $params, & $initializer) use ($definition, $parameters) {\n                $wrappedObject = $this->createInstance($definition, $parameters);\n                $initializer = null; // turning off further lazy initialization\n\n                return true;\n            }\n        );\n\n        return $proxy;\n    }\n\n    /**\n     * Creates an instance of the class and injects dependencies..\n     *\n     * @param array            $parameters      Optional parameters to use to create the instance.\n     *\n     * @throws InvalidDefinition\n     * @throws DependencyException\n     * @return object\n     */\n    private function createInstance(ObjectDefinition $definition, array $parameters)\n    {\n        // Check that the class is instantiable\n        if (! $definition->isInstantiable()) {\n            // Check that the class exists\n            if (! $definition->classExists()) {\n                throw InvalidDefinition::create($definition, sprintf(\n                    'Entry \"%s\" cannot be resolved: the class doesn\\'t exist',\n                    $definition->getName()\n                ));\n            }\n\n            throw InvalidDefinition::create($definition, sprintf(\n                'Entry \"%s\" cannot be resolved: the class is not instantiable',\n                $definition->getName()\n            ));\n        }\n\n        $classname = $definition->getClassName();\n        $classReflection = new ReflectionClass($classname);\n\n        $constructorInjection = $definition->getConstructorInjection();\n\n        try {\n            $args = $this->parameterResolver->resolveParameters(\n                $constructorInjection,\n                $classReflection->getConstructor(),\n                $parameters\n            );\n\n            $object = new $classname(...$args);\n\n            $this->injectMethodsAndProperties($object, $definition);\n        } catch (NotFoundExceptionInterface $e) {\n            throw new DependencyException(sprintf(\n                'Error while injecting dependencies into %s: %s',\n                $classReflection->getName(),\n                $e->getMessage()\n            ), 0, $e);\n        } catch (InvalidDefinition $e) {\n            throw InvalidDefinition::create($definition, sprintf(\n                'Entry \"%s\" cannot be resolved: %s',\n                $definition->getName(),\n                $e->getMessage()\n            ));\n        }\n\n        return $object;\n    }\n\n    protected function injectMethodsAndProperties($object, ObjectDefinition $objectDefinition)\n    {\n        // Property injections\n        foreach ($objectDefinition->getPropertyInjections() as $propertyInjection) {\n            $this->injectProperty($object, $propertyInjection);\n        }\n\n        // Method injections\n        foreach ($objectDefinition->getMethodInjections() as $methodInjection) {\n            $methodReflection = new \\ReflectionMethod($object, $methodInjection->getMethodName());\n            $args = $this->parameterResolver->resolveParameters($methodInjection, $methodReflection);\n\n            $methodReflection->invokeArgs($object, $args);\n        }\n    }\n\n    /**\n     * Inject dependencies into properties.\n     *\n     * @param object            $object            Object to inject dependencies into\n     * @param PropertyInjection $propertyInjection Property injection definition\n     *\n     * @throws DependencyException\n     * @throws InvalidDefinition\n     */\n    private function injectProperty($object, PropertyInjection $propertyInjection)\n    {\n        $propertyName = $propertyInjection->getPropertyName();\n\n        $value = $propertyInjection->getValue();\n\n        if ($value instanceof Definition) {\n            try {\n                $value = $this->definitionResolver->resolve($value);\n            } catch (DependencyException $e) {\n                throw $e;\n            } catch (Exception $e) {\n                throw new DependencyException(sprintf(\n                    'Error while injecting in %s::%s. %s',\n                    get_class($object),\n                    $propertyName,\n                    $e->getMessage()\n                ), 0, $e);\n            }\n        }\n\n        self::setPrivatePropertyValue($propertyInjection->getClassName(), $object, $propertyName, $value);\n    }\n\n    public static function setPrivatePropertyValue(string $className = null, $object, string $propertyName, $propertyValue)\n    {\n        $className = $className ?: get_class($object);\n\n        $property = new ReflectionProperty($className, $propertyName);\n        if (! $property->isPublic()) {\n            $property->setAccessible(true);\n        }\n        $property->setValue($object, $propertyValue);\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Definition/Resolver/ParameterResolver.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Definition\\Resolver;\n\nuse DI\\Definition\\Definition;\nuse DI\\Definition\\Exception\\InvalidDefinition;\nuse DI\\Definition\\ObjectDefinition\\MethodInjection;\nuse ReflectionMethod;\nuse ReflectionParameter;\n\n/**\n * Resolves parameters for a function call.\n *\n * @since  4.2\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\nclass ParameterResolver\n{\n    /**\n     * @var DefinitionResolver\n     */\n    private $definitionResolver;\n\n    /**\n     * @param DefinitionResolver $definitionResolver Will be used to resolve nested definitions.\n     */\n    public function __construct(DefinitionResolver $definitionResolver)\n    {\n        $this->definitionResolver = $definitionResolver;\n    }\n\n    /**\n     * @throws InvalidDefinition A parameter has no value defined or guessable.\n     * @return array Parameters to use to call the function.\n     */\n    public function resolveParameters(\n        MethodInjection $definition = null,\n        ReflectionMethod $method = null,\n        array $parameters = []\n    ) {\n        $args = [];\n\n        if (! $method) {\n            return $args;\n        }\n\n        $definitionParameters = $definition ? $definition->getParameters() : [];\n\n        foreach ($method->getParameters() as $index => $parameter) {\n            if (array_key_exists($parameter->getName(), $parameters)) {\n                // Look in the $parameters array\n                $value = &$parameters[$parameter->getName()];\n            } elseif (array_key_exists($index, $definitionParameters)) {\n                // Look in the definition\n                $value = &$definitionParameters[$index];\n            } else {\n                // If the parameter is optional and wasn't specified, we take its default value\n                if ($parameter->isDefaultValueAvailable() || $parameter->isOptional()) {\n                    $args[] = $this->getParameterDefaultValue($parameter, $method);\n                    continue;\n                }\n\n                throw new InvalidDefinition(sprintf(\n                    'Parameter $%s of %s has no value defined or guessable',\n                    $parameter->getName(),\n                    $this->getFunctionName($method)\n                ));\n            }\n\n            // Nested definitions\n            if ($value instanceof Definition) {\n                // If the container cannot produce the entry, we can use the default parameter value\n                if ($parameter->isOptional() && ! $this->definitionResolver->isResolvable($value)) {\n                    $value = $this->getParameterDefaultValue($parameter, $method);\n                } else {\n                    $value = $this->definitionResolver->resolve($value);\n                }\n            }\n\n            $args[] = &$value;\n        }\n\n        return $args;\n    }\n\n    /**\n     * Returns the default value of a function parameter.\n     *\n     * @throws InvalidDefinition Can't get default values from PHP internal classes and functions\n     * @return mixed\n     */\n    private function getParameterDefaultValue(ReflectionParameter $parameter, ReflectionMethod $function)\n    {\n        try {\n            return $parameter->getDefaultValue();\n        } catch (\\ReflectionException $e) {\n            throw new InvalidDefinition(sprintf(\n                'The parameter \"%s\" of %s has no type defined or guessable. It has a default value, '\n                . 'but the default value can\\'t be read through Reflection because it is a PHP internal class.',\n                $parameter->getName(),\n                $this->getFunctionName($function)\n            ));\n        }\n    }\n\n    private function getFunctionName(ReflectionMethod $method) : string\n    {\n        return $method->getName() . '()';\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Definition/Resolver/ResolverDispatcher.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Definition\\Resolver;\n\nuse DI\\Definition\\ArrayDefinition;\nuse DI\\Definition\\DecoratorDefinition;\nuse DI\\Definition\\Definition;\nuse DI\\Definition\\EnvironmentVariableDefinition;\nuse DI\\Definition\\Exception\\InvalidDefinition;\nuse DI\\Definition\\FactoryDefinition;\nuse DI\\Definition\\InstanceDefinition;\nuse DI\\Definition\\ObjectDefinition;\nuse DI\\Definition\\SelfResolvingDefinition;\nuse DI\\Proxy\\ProxyFactory;\nuse Psr\\Container\\ContainerInterface;\n\n/**\n * Dispatches to more specific resolvers.\n *\n * Dynamic dispatch pattern.\n *\n * @since 5.0\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\nclass ResolverDispatcher implements DefinitionResolver\n{\n    /**\n     * @var ContainerInterface\n     */\n    private $container;\n\n    /**\n     * @var ProxyFactory\n     */\n    private $proxyFactory;\n\n    private $arrayResolver;\n    private $factoryResolver;\n    private $decoratorResolver;\n    private $objectResolver;\n    private $instanceResolver;\n    private $envVariableResolver;\n\n    public function __construct(ContainerInterface $container, ProxyFactory $proxyFactory)\n    {\n        $this->container = $container;\n        $this->proxyFactory = $proxyFactory;\n    }\n\n    /**\n     * Resolve a definition to a value.\n     *\n     * @param Definition $definition Object that defines how the value should be obtained.\n     * @param array      $parameters Optional parameters to use to build the entry.\n     *\n     * @throws InvalidDefinition If the definition cannot be resolved.\n     *\n     * @return mixed Value obtained from the definition.\n     */\n    public function resolve(Definition $definition, array $parameters = [])\n    {\n        // Special case, tested early for speed\n        if ($definition instanceof SelfResolvingDefinition) {\n            return $definition->resolve($this->container);\n        }\n\n        $definitionResolver = $this->getDefinitionResolver($definition);\n\n        return $definitionResolver->resolve($definition, $parameters);\n    }\n\n    public function isResolvable(Definition $definition, array $parameters = []) : bool\n    {\n        // Special case, tested early for speed\n        if ($definition instanceof SelfResolvingDefinition) {\n            return $definition->isResolvable($this->container);\n        }\n\n        $definitionResolver = $this->getDefinitionResolver($definition);\n\n        return $definitionResolver->isResolvable($definition, $parameters);\n    }\n\n    /**\n     * Returns a resolver capable of handling the given definition.\n     *\n     * @throws \\RuntimeException No definition resolver was found for this type of definition.\n     */\n    private function getDefinitionResolver(Definition $definition) : DefinitionResolver\n    {\n        switch (true) {\n            case $definition instanceof ObjectDefinition:\n                if (! $this->objectResolver) {\n                    $this->objectResolver = new ObjectCreator($this, $this->proxyFactory);\n                }\n\n                return $this->objectResolver;\n            case $definition instanceof DecoratorDefinition:\n                if (! $this->decoratorResolver) {\n                    $this->decoratorResolver = new DecoratorResolver($this->container, $this);\n                }\n\n                return $this->decoratorResolver;\n            case $definition instanceof FactoryDefinition:\n                if (! $this->factoryResolver) {\n                    $this->factoryResolver = new FactoryResolver($this->container, $this);\n                }\n\n                return $this->factoryResolver;\n            case $definition instanceof ArrayDefinition:\n                if (! $this->arrayResolver) {\n                    $this->arrayResolver = new ArrayResolver($this);\n                }\n\n                return $this->arrayResolver;\n            case $definition instanceof EnvironmentVariableDefinition:\n                if (! $this->envVariableResolver) {\n                    $this->envVariableResolver = new EnvironmentVariableResolver($this);\n                }\n\n                return $this->envVariableResolver;\n            case $definition instanceof InstanceDefinition:\n                if (! $this->instanceResolver) {\n                    $this->instanceResolver = new InstanceInjector($this, $this->proxyFactory);\n                }\n\n                return $this->instanceResolver;\n            default:\n                throw new \\RuntimeException('No definition resolver was configured for definition of type ' . get_class($definition));\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Definition/SelfResolvingDefinition.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Definition;\n\nuse Psr\\Container\\ContainerInterface;\n\n/**\n * Describes a definition that can resolve itself.\n *\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\ninterface SelfResolvingDefinition\n{\n    /**\n     * Resolve the definition and return the resulting value.\n     *\n     * @return mixed\n     */\n    public function resolve(ContainerInterface $container);\n\n    /**\n     * Check if a definition can be resolved.\n     */\n    public function isResolvable(ContainerInterface $container) : bool;\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Definition/Source/AnnotationBasedAutowiring.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Definition\\Source;\n\nuse DI\\Annotation\\Inject;\nuse DI\\Annotation\\Injectable;\nuse DI\\Definition\\Exception\\InvalidAnnotation;\nuse DI\\Definition\\ObjectDefinition;\nuse DI\\Definition\\ObjectDefinition\\MethodInjection;\nuse DI\\Definition\\ObjectDefinition\\PropertyInjection;\nuse DI\\Definition\\Reference;\nuse Doctrine\\Common\\Annotations\\AnnotationRegistry;\nuse Doctrine\\Common\\Annotations\\Reader;\nuse Doctrine\\Common\\Annotations\\SimpleAnnotationReader;\nuse InvalidArgumentException;\nuse PhpDocReader\\PhpDocReader;\nuse ReflectionClass;\nuse ReflectionMethod;\nuse ReflectionNamedType;\nuse ReflectionParameter;\nuse ReflectionProperty;\nuse UnexpectedValueException;\n\n/**\n * Provides DI definitions by reading annotations such as @ Inject and @ var annotations.\n *\n * Uses Autowiring, Doctrine's Annotations and regex docblock parsing.\n * This source automatically includes the reflection source.\n *\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\nclass AnnotationBasedAutowiring implements DefinitionSource, Autowiring\n{\n    /**\n     * @var Reader\n     */\n    private $annotationReader;\n\n    /**\n     * @var PhpDocReader\n     */\n    private $phpDocReader;\n\n    /**\n     * @var bool\n     */\n    private $ignorePhpDocErrors;\n\n    public function __construct($ignorePhpDocErrors = false)\n    {\n        $this->ignorePhpDocErrors = (bool) $ignorePhpDocErrors;\n    }\n\n    public function autowire(string $name, ObjectDefinition $definition = null)\n    {\n        $className = $definition ? $definition->getClassName() : $name;\n\n        if (!class_exists($className) && !interface_exists($className)) {\n            return $definition;\n        }\n\n        $definition = $definition ?: new ObjectDefinition($name);\n\n        $class = new ReflectionClass($className);\n\n        $this->readInjectableAnnotation($class, $definition);\n\n        // Browse the class properties looking for annotated properties\n        $this->readProperties($class, $definition);\n\n        // Browse the object's methods looking for annotated methods\n        $this->readMethods($class, $definition);\n\n        return $definition;\n    }\n\n    /**\n     * {@inheritdoc}\n     * @throws InvalidAnnotation\n     * @throws InvalidArgumentException The class doesn't exist\n     */\n    public function getDefinition(string $name)\n    {\n        return $this->autowire($name);\n    }\n\n    /**\n     * Autowiring cannot guess all existing definitions.\n     */\n    public function getDefinitions() : array\n    {\n        return [];\n    }\n\n    /**\n     * Browse the class properties looking for annotated properties.\n     */\n    private function readProperties(ReflectionClass $class, ObjectDefinition $definition)\n    {\n        foreach ($class->getProperties() as $property) {\n            if ($property->isStatic()) {\n                continue;\n            }\n            $this->readProperty($property, $definition);\n        }\n\n        // Read also the *private* properties of the parent classes\n        /** @noinspection PhpAssignmentInConditionInspection */\n        while ($class = $class->getParentClass()) {\n            foreach ($class->getProperties(ReflectionProperty::IS_PRIVATE) as $property) {\n                if ($property->isStatic()) {\n                    continue;\n                }\n                $this->readProperty($property, $definition, $class->getName());\n            }\n        }\n    }\n\n    private function readProperty(ReflectionProperty $property, ObjectDefinition $definition, $classname = null)\n    {\n        // Look for @Inject annotation\n        $annotation = $this->getAnnotationReader()->getPropertyAnnotation($property, 'DI\\Annotation\\Inject');\n        if (!$annotation instanceof Inject) {\n            return;\n        }\n\n        // Try to @Inject(\"name\") or look for @var content\n        $entryName = $annotation->getName() ?: $this->getPhpDocReader()->getPropertyClass($property);\n\n        // Try using PHP7.4 typed properties\n        if (\\PHP_VERSION_ID > 70400\n            && $entryName === null\n            && $property->getType() instanceof ReflectionNamedType\n            && (class_exists($property->getType()->getName()) || interface_exists($property->getType()->getName()))\n        ) {\n            $entryName = $property->getType()->getName();\n        }\n\n        if ($entryName === null) {\n            throw new InvalidAnnotation(sprintf(\n                '@Inject found on property %s::%s but unable to guess what to inject, use a @var annotation',\n                $property->getDeclaringClass()->getName(),\n                $property->getName()\n            ));\n        }\n\n        $definition->addPropertyInjection(\n            new PropertyInjection($property->getName(), new Reference($entryName), $classname)\n        );\n    }\n\n    /**\n     * Browse the object's methods looking for annotated methods.\n     */\n    private function readMethods(ReflectionClass $class, ObjectDefinition $objectDefinition)\n    {\n        // This will look in all the methods, including those of the parent classes\n        foreach ($class->getMethods(ReflectionMethod::IS_PUBLIC) as $method) {\n            if ($method->isStatic()) {\n                continue;\n            }\n\n            $methodInjection = $this->getMethodInjection($method);\n\n            if (! $methodInjection) {\n                continue;\n            }\n\n            if ($method->isConstructor()) {\n                $objectDefinition->completeConstructorInjection($methodInjection);\n            } else {\n                $objectDefinition->completeFirstMethodInjection($methodInjection);\n            }\n        }\n    }\n\n    /**\n     * @return MethodInjection|null\n     */\n    private function getMethodInjection(ReflectionMethod $method)\n    {\n        // Look for @Inject annotation\n        try {\n            $annotation = $this->getAnnotationReader()->getMethodAnnotation($method, 'DI\\Annotation\\Inject');\n        } catch (InvalidAnnotation $e) {\n            throw new InvalidAnnotation(sprintf(\n                '@Inject annotation on %s::%s is malformed. %s',\n                $method->getDeclaringClass()->getName(),\n                $method->getName(),\n                $e->getMessage()\n            ), 0, $e);\n        }\n\n        // @Inject on constructor is implicit\n        if (! ($annotation || $method->isConstructor())) {\n            return null;\n        }\n\n        $annotationParameters = $annotation instanceof Inject ? $annotation->getParameters() : [];\n\n        $parameters = [];\n        foreach ($method->getParameters() as $index => $parameter) {\n            $entryName = $this->getMethodParameter($index, $parameter, $annotationParameters);\n\n            if ($entryName !== null) {\n                $parameters[$index] = new Reference($entryName);\n            }\n        }\n\n        if ($method->isConstructor()) {\n            return MethodInjection::constructor($parameters);\n        }\n\n        return new MethodInjection($method->getName(), $parameters);\n    }\n\n    /**\n     * @param int                 $parameterIndex\n     *\n     * @return string|null Entry name or null if not found.\n     */\n    private function getMethodParameter($parameterIndex, ReflectionParameter $parameter, array $annotationParameters)\n    {\n        // @Inject has definition for this parameter (by index, or by name)\n        if (isset($annotationParameters[$parameterIndex])) {\n            return $annotationParameters[$parameterIndex];\n        }\n        if (isset($annotationParameters[$parameter->getName()])) {\n            return $annotationParameters[$parameter->getName()];\n        }\n\n        // Skip optional parameters if not explicitly defined\n        if ($parameter->isOptional()) {\n            return null;\n        }\n\n        // Try to use the type-hinting\n        $parameterType = $parameter->getType();\n        if ($parameterType && $parameterType instanceof ReflectionNamedType && !$parameterType->isBuiltin()) {\n            return $parameterType->getName();\n        }\n\n        // Last resort, look for @param tag\n        return $this->getPhpDocReader()->getParameterClass($parameter);\n    }\n\n    /**\n     * @return Reader The annotation reader\n     */\n    public function getAnnotationReader()\n    {\n        if ($this->annotationReader === null) {\n            AnnotationRegistry::registerLoader('class_exists');\n            $this->annotationReader = new SimpleAnnotationReader();\n            $this->annotationReader->addNamespace('DI\\Annotation');\n        }\n\n        return $this->annotationReader;\n    }\n\n    /**\n     * @return PhpDocReader\n     */\n    private function getPhpDocReader()\n    {\n        if ($this->phpDocReader === null) {\n            $this->phpDocReader = new PhpDocReader($this->ignorePhpDocErrors);\n        }\n\n        return $this->phpDocReader;\n    }\n\n    private function readInjectableAnnotation(ReflectionClass $class, ObjectDefinition $definition)\n    {\n        try {\n            /** @var Injectable|null $annotation */\n            $annotation = $this->getAnnotationReader()\n                ->getClassAnnotation($class, 'DI\\Annotation\\Injectable');\n        } catch (UnexpectedValueException $e) {\n            throw new InvalidAnnotation(sprintf(\n                'Error while reading @Injectable on %s: %s',\n                $class->getName(),\n                $e->getMessage()\n            ), 0, $e);\n        }\n\n        if (! $annotation) {\n            return;\n        }\n\n        if ($annotation->isLazy() !== null) {\n            $definition->setLazy($annotation->isLazy());\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Definition/Source/Autowiring.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Definition\\Source;\n\nuse DI\\Definition\\Exception\\InvalidDefinition;\nuse DI\\Definition\\ObjectDefinition;\n\n/**\n * Source of definitions for entries of the container.\n *\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\ninterface Autowiring\n{\n    /**\n     * Autowire the given definition.\n     *\n     * @throws InvalidDefinition An invalid definition was found.\n     * @return ObjectDefinition|null\n     */\n    public function autowire(string $name, ObjectDefinition $definition = null);\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Definition/Source/DefinitionArray.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Definition\\Source;\n\nuse DI\\Definition\\Definition;\n\n/**\n * Reads DI definitions from a PHP array.\n *\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\nclass DefinitionArray implements DefinitionSource, MutableDefinitionSource\n{\n    const WILDCARD = '*';\n    /**\n     * Matches anything except \"\\\".\n     */\n    const WILDCARD_PATTERN = '([^\\\\\\\\]+)';\n\n    /**\n     * DI definitions in a PHP array.\n     * @var array\n     */\n    private $definitions = [];\n\n    /**\n     * Cache of wildcard definitions.\n     * @var array|null\n     */\n    private $wildcardDefinitions;\n\n    /**\n     * @var DefinitionNormalizer\n     */\n    private $normalizer;\n\n    public function __construct(array $definitions = [], Autowiring $autowiring = null)\n    {\n        if (isset($definitions[0])) {\n            throw new \\Exception('The PHP-DI definition is not indexed by an entry name in the definition array');\n        }\n\n        $this->definitions = $definitions;\n\n        $autowiring = $autowiring ?: new NoAutowiring;\n        $this->normalizer = new DefinitionNormalizer($autowiring);\n    }\n\n    /**\n     * @param array $definitions DI definitions in a PHP array indexed by the definition name.\n     */\n    public function addDefinitions(array $definitions)\n    {\n        if (isset($definitions[0])) {\n            throw new \\Exception('The PHP-DI definition is not indexed by an entry name in the definition array');\n        }\n\n        // The newly added data prevails\n        // \"for keys that exist in both arrays, the elements from the left-hand array will be used\"\n        $this->definitions = $definitions + $this->definitions;\n\n        // Clear cache\n        $this->wildcardDefinitions = null;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function addDefinition(Definition $definition)\n    {\n        $this->definitions[$definition->getName()] = $definition;\n\n        // Clear cache\n        $this->wildcardDefinitions = null;\n    }\n\n    public function getDefinition(string $name)\n    {\n        // Look for the definition by name\n        if (array_key_exists($name, $this->definitions)) {\n            $definition = $this->definitions[$name];\n            $definition = $this->normalizer->normalizeRootDefinition($definition, $name);\n\n            return $definition;\n        }\n\n        // Build the cache of wildcard definitions\n        if ($this->wildcardDefinitions === null) {\n            $this->wildcardDefinitions = [];\n            foreach ($this->definitions as $key => $definition) {\n                if (strpos($key, self::WILDCARD) !== false) {\n                    $this->wildcardDefinitions[$key] = $definition;\n                }\n            }\n        }\n\n        // Look in wildcards definitions\n        foreach ($this->wildcardDefinitions as $key => $definition) {\n            // Turn the pattern into a regex\n            $key = preg_quote($key);\n            $key = '#' . str_replace('\\\\' . self::WILDCARD, self::WILDCARD_PATTERN, $key) . '#';\n            if (preg_match($key, $name, $matches) === 1) {\n                array_shift($matches);\n                $definition = $this->normalizer->normalizeRootDefinition($definition, $name, $matches);\n\n                return $definition;\n            }\n        }\n\n        return null;\n    }\n\n    public function getDefinitions() : array\n    {\n        // Return all definitions except wildcard definitions\n        $definitions = [];\n        foreach ($this->definitions as $key => $definition) {\n            if (strpos($key, self::WILDCARD) === false) {\n                $definitions[$key] = $definition;\n            }\n        }\n\n        return $definitions;\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Definition/Source/DefinitionFile.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Definition\\Source;\n\n/**\n * Reads DI definitions from a file returning a PHP array.\n *\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\nclass DefinitionFile extends DefinitionArray\n{\n    /**\n     * @var bool\n     */\n    private $initialized = false;\n\n    /**\n     * File containing definitions, or null if the definitions are given as a PHP array.\n     * @var string|null\n     */\n    private $file;\n\n    /**\n     * @param string $file File in which the definitions are returned as an array.\n     */\n    public function __construct($file, Autowiring $autowiring = null)\n    {\n        // Lazy-loading to improve performances\n        $this->file = $file;\n\n        parent::__construct([], $autowiring);\n    }\n\n    public function getDefinition(string $name)\n    {\n        $this->initialize();\n\n        return parent::getDefinition($name);\n    }\n\n    public function getDefinitions() : array\n    {\n        $this->initialize();\n\n        return parent::getDefinitions();\n    }\n\n    /**\n     * Lazy-loading of the definitions.\n     */\n    private function initialize()\n    {\n        if ($this->initialized === true) {\n            return;\n        }\n\n        $definitions = require $this->file;\n\n        if (! is_array($definitions)) {\n            throw new \\Exception(\"File {$this->file} should return an array of definitions\");\n        }\n\n        $this->addDefinitions($definitions);\n\n        $this->initialized = true;\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Definition/Source/DefinitionNormalizer.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Definition\\Source;\n\nuse DI\\Definition\\ArrayDefinition;\nuse DI\\Definition\\AutowireDefinition;\nuse DI\\Definition\\DecoratorDefinition;\nuse DI\\Definition\\Definition;\nuse DI\\Definition\\Exception\\InvalidDefinition;\nuse DI\\Definition\\FactoryDefinition;\nuse DI\\Definition\\Helper\\DefinitionHelper;\nuse DI\\Definition\\ObjectDefinition;\nuse DI\\Definition\\ValueDefinition;\n\n/**\n * Turns raw definitions/definition helpers into definitions ready\n * to be resolved or compiled.\n *\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\nclass DefinitionNormalizer\n{\n    /**\n     * @var Autowiring\n     */\n    private $autowiring;\n\n    public function __construct(Autowiring $autowiring)\n    {\n        $this->autowiring = $autowiring;\n    }\n\n    /**\n     * Normalize a definition that is *not* nested in another one.\n     *\n     * This is usually a definition declared at the root of a definition array.\n     *\n     * @param mixed $definition\n     * @param string $name The definition name.\n     * @param string[] $wildcardsReplacements Replacements for wildcard definitions.\n     *\n     * @throws InvalidDefinition\n     */\n    public function normalizeRootDefinition($definition, string $name, array $wildcardsReplacements = null) : Definition\n    {\n        if ($definition instanceof DefinitionHelper) {\n            $definition = $definition->getDefinition($name);\n        } elseif (is_array($definition)) {\n            $definition = new ArrayDefinition($definition);\n        } elseif ($definition instanceof \\Closure) {\n            $definition = new FactoryDefinition($name, $definition);\n        } elseif (! $definition instanceof Definition) {\n            $definition = new ValueDefinition($definition);\n        }\n\n        // For a class definition, we replace * in the class name with the matches\n        // *Interface -> *Impl => FooInterface -> FooImpl\n        if ($wildcardsReplacements && $definition instanceof ObjectDefinition) {\n            $definition->replaceWildcards($wildcardsReplacements);\n        }\n\n        if ($definition instanceof AutowireDefinition) {\n            $definition = $this->autowiring->autowire($name, $definition);\n        }\n\n        $definition->setName($name);\n\n        try {\n            $definition->replaceNestedDefinitions([$this, 'normalizeNestedDefinition']);\n        } catch (InvalidDefinition $e) {\n            throw InvalidDefinition::create($definition, sprintf(\n                'Definition \"%s\" contains an error: %s',\n                $definition->getName(),\n                $e->getMessage()\n            ), $e);\n        }\n\n        return $definition;\n    }\n\n    /**\n     * Normalize a definition that is nested in another one.\n     *\n     * @param mixed $definition\n     * @return mixed\n     *\n     * @throws InvalidDefinition\n     */\n    public function normalizeNestedDefinition($definition)\n    {\n        $name = '<nested definition>';\n\n        if ($definition instanceof DefinitionHelper) {\n            $definition = $definition->getDefinition($name);\n        } elseif (is_array($definition)) {\n            $definition = new ArrayDefinition($definition);\n        } elseif ($definition instanceof \\Closure) {\n            $definition = new FactoryDefinition($name, $definition);\n        }\n\n        if ($definition instanceof DecoratorDefinition) {\n            throw new InvalidDefinition('Decorators cannot be nested in another definition');\n        }\n\n        if ($definition instanceof AutowireDefinition) {\n            $definition = $this->autowiring->autowire($name, $definition);\n        }\n\n        if ($definition instanceof Definition) {\n            $definition->setName($name);\n\n            // Recursively traverse nested definitions\n            $definition->replaceNestedDefinitions([$this, 'normalizeNestedDefinition']);\n        }\n\n        return $definition;\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Definition/Source/DefinitionSource.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Definition\\Source;\n\nuse DI\\Definition\\Definition;\nuse DI\\Definition\\Exception\\InvalidDefinition;\n\n/**\n * Source of definitions for entries of the container.\n *\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\ninterface DefinitionSource\n{\n    /**\n     * Returns the DI definition for the entry name.\n     *\n     * @throws InvalidDefinition An invalid definition was found.\n     * @return Definition|null\n     */\n    public function getDefinition(string $name);\n\n    /**\n     * @return Definition[] Definitions indexed by their name.\n     */\n    public function getDefinitions() : array;\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Definition/Source/MutableDefinitionSource.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Definition\\Source;\n\nuse DI\\Definition\\Definition;\n\n/**\n * Describes a definition source to which we can add new definitions.\n *\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\ninterface MutableDefinitionSource extends DefinitionSource\n{\n    public function addDefinition(Definition $definition);\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Definition/Source/NoAutowiring.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Definition\\Source;\n\nuse DI\\Definition\\Exception\\InvalidDefinition;\nuse DI\\Definition\\ObjectDefinition;\n\n/**\n * Implementation used when autowiring is completely disabled.\n *\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\nclass NoAutowiring implements Autowiring\n{\n    public function autowire(string $name, ObjectDefinition $definition = null)\n    {\n        throw new InvalidDefinition(sprintf(\n            'Cannot autowire entry \"%s\" because autowiring is disabled',\n            $name\n        ));\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Definition/Source/ReflectionBasedAutowiring.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Definition\\Source;\n\nuse DI\\Definition\\ObjectDefinition;\nuse DI\\Definition\\ObjectDefinition\\MethodInjection;\nuse DI\\Definition\\Reference;\nuse ReflectionNamedType;\n\n/**\n * Reads DI class definitions using reflection.\n *\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\nclass ReflectionBasedAutowiring implements DefinitionSource, Autowiring\n{\n    public function autowire(string $name, ObjectDefinition $definition = null)\n    {\n        $className = $definition ? $definition->getClassName() : $name;\n\n        if (!class_exists($className) && !interface_exists($className)) {\n            return $definition;\n        }\n\n        $definition = $definition ?: new ObjectDefinition($name);\n\n        // Constructor\n        $class = new \\ReflectionClass($className);\n        $constructor = $class->getConstructor();\n        if ($constructor && $constructor->isPublic()) {\n            $constructorInjection = MethodInjection::constructor($this->getParametersDefinition($constructor));\n            $definition->completeConstructorInjection($constructorInjection);\n        }\n\n        return $definition;\n    }\n\n    public function getDefinition(string $name)\n    {\n        return $this->autowire($name);\n    }\n\n    /**\n     * Autowiring cannot guess all existing definitions.\n     */\n    public function getDefinitions() : array\n    {\n        return [];\n    }\n\n    /**\n     * Read the type-hinting from the parameters of the function.\n     */\n    private function getParametersDefinition(\\ReflectionFunctionAbstract $constructor) : array\n    {\n        $parameters = [];\n\n        foreach ($constructor->getParameters() as $index => $parameter) {\n            // Skip optional parameters\n            if ($parameter->isOptional()) {\n                continue;\n            }\n\n            $parameterType = $parameter->getType();\n            if (!$parameterType) {\n                // No type\n                continue;\n            }\n            if (!$parameterType instanceof ReflectionNamedType) {\n                // Union types are not supported\n                continue;\n            }\n            if ($parameterType->isBuiltin()) {\n                // Primitive types are not supported\n                continue;\n            }\n\n            $parameters[$index] = new Reference($parameterType->getName());\n        }\n\n        return $parameters;\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Definition/Source/SourceCache.php",
    "content": "<?php\n\nnamespace DI\\Definition\\Source;\n\nuse DI\\Definition\\AutowireDefinition;\nuse DI\\Definition\\Definition;\nuse DI\\Definition\\ObjectDefinition;\n\n/**\n * Decorator that caches another definition source.\n *\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\nclass SourceCache implements DefinitionSource, MutableDefinitionSource\n{\n    /**\n     * @var string\n     */\n    const CACHE_KEY = 'php-di.definitions.';\n\n    /**\n     * @var DefinitionSource\n     */\n    private $cachedSource;\n\n    /**\n     * @var string\n     */\n    private $cacheNamespace;\n\n    public function __construct(DefinitionSource $cachedSource, string $cacheNamespace = '')\n    {\n        $this->cachedSource = $cachedSource;\n        $this->cacheNamespace = $cacheNamespace;\n    }\n\n    public function getDefinition(string $name)\n    {\n        $definition = apcu_fetch($this->getCacheKey($name));\n\n        if ($definition === false) {\n            $definition = $this->cachedSource->getDefinition($name);\n\n            // Update the cache\n            if ($this->shouldBeCached($definition)) {\n                apcu_store($this->getCacheKey($name), $definition);\n            }\n        }\n\n        return $definition;\n    }\n\n    /**\n     * Used only for the compilation so we can skip the cache safely.\n     */\n    public function getDefinitions() : array\n    {\n        return $this->cachedSource->getDefinitions();\n    }\n\n    public static function isSupported() : bool\n    {\n        return function_exists('apcu_fetch')\n            && ini_get('apc.enabled')\n            && ! ('cli' === \\PHP_SAPI && ! ini_get('apc.enable_cli'));\n    }\n\n    public function getCacheKey(string $name) : string\n    {\n        return self::CACHE_KEY . $this->cacheNamespace . $name;\n    }\n\n    public function addDefinition(Definition $definition)\n    {\n        throw new \\LogicException('You cannot set a definition at runtime on a container that has caching enabled. Doing so would risk caching the definition for the next execution, where it might be different. You can either put your definitions in a file, remove the cache or ->set() a raw value directly (PHP object, string, int, ...) instead of a PHP-DI definition.');\n    }\n\n    private function shouldBeCached(Definition $definition = null) : bool\n    {\n        return\n            // Cache missing definitions\n            ($definition === null)\n            // Object definitions are used with `make()`\n            || ($definition instanceof ObjectDefinition)\n            // Autowired definitions cannot be all compiled and are used with `make()`\n            || ($definition instanceof AutowireDefinition);\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Definition/Source/SourceChain.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Definition\\Source;\n\nuse DI\\Definition\\Definition;\nuse DI\\Definition\\ExtendsPreviousDefinition;\n\n/**\n * Manages a chain of other definition sources.\n *\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\nclass SourceChain implements DefinitionSource, MutableDefinitionSource\n{\n    /**\n     * @var DefinitionSource[]\n     */\n    private $sources;\n\n    /**\n     * @var DefinitionSource\n     */\n    private $rootSource;\n\n    /**\n     * @var MutableDefinitionSource|null\n     */\n    private $mutableSource;\n\n    /**\n     * @param DefinitionSource[] $sources\n     */\n    public function __construct(array $sources)\n    {\n        // We want a numerically indexed array to ease the traversal later\n        $this->sources = array_values($sources);\n        $this->rootSource = $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @param int $startIndex Use this parameter to start looking from a specific\n     *                        point in the source chain.\n     */\n    public function getDefinition(string $name, int $startIndex = 0)\n    {\n        $count = count($this->sources);\n        for ($i = $startIndex; $i < $count; ++$i) {\n            $source = $this->sources[$i];\n\n            $definition = $source->getDefinition($name);\n\n            if ($definition) {\n                if ($definition instanceof ExtendsPreviousDefinition) {\n                    $this->resolveExtendedDefinition($definition, $i);\n                }\n\n                return $definition;\n            }\n        }\n\n        return null;\n    }\n\n    public function getDefinitions() : array\n    {\n        $names = [];\n        foreach ($this->sources as $source) {\n            $names = array_merge($names, $source->getDefinitions());\n        }\n        $names = array_keys($names);\n\n        $definitions = array_combine($names, array_map(function (string $name) {\n            return $this->getDefinition($name);\n        }, $names));\n\n        return $definitions;\n    }\n\n    public function addDefinition(Definition $definition)\n    {\n        if (! $this->mutableSource) {\n            throw new \\LogicException(\"The container's definition source has not been initialized correctly\");\n        }\n\n        $this->mutableSource->addDefinition($definition);\n    }\n\n    private function resolveExtendedDefinition(ExtendsPreviousDefinition $definition, int $currentIndex)\n    {\n        // Look in the next sources only (else infinite recursion, and we can only extend\n        // entries defined in the previous definition files - a previous == next here because\n        // the array was reversed ;) )\n        $subDefinition = $this->getDefinition($definition->getName(), $currentIndex + 1);\n\n        if ($subDefinition) {\n            $definition->setExtendedDefinition($subDefinition);\n        }\n    }\n\n    public function setMutableDefinitionSource(MutableDefinitionSource $mutableSource)\n    {\n        $this->mutableSource = $mutableSource;\n\n        array_unshift($this->sources, $mutableSource);\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Definition/StringDefinition.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Definition;\n\nuse DI\\DependencyException;\nuse Psr\\Container\\ContainerInterface;\nuse Psr\\Container\\NotFoundExceptionInterface;\n\n/**\n * Definition of a string composed of other strings.\n *\n * @since 5.0\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\nclass StringDefinition implements Definition, SelfResolvingDefinition\n{\n    /**\n     * Entry name.\n     * @var string\n     */\n    private $name = '';\n\n    /**\n     * @var string\n     */\n    private $expression;\n\n    public function __construct(string $expression)\n    {\n        $this->expression = $expression;\n    }\n\n    public function getName() : string\n    {\n        return $this->name;\n    }\n\n    public function setName(string $name)\n    {\n        $this->name = $name;\n    }\n\n    public function getExpression() : string\n    {\n        return $this->expression;\n    }\n\n    public function resolve(ContainerInterface $container) : string\n    {\n        return self::resolveExpression($this->name, $this->expression, $container);\n    }\n\n    public function isResolvable(ContainerInterface $container) : bool\n    {\n        return true;\n    }\n\n    public function replaceNestedDefinitions(callable $replacer)\n    {\n        // no nested definitions\n    }\n\n    public function __toString()\n    {\n        return $this->expression;\n    }\n\n    /**\n     * Resolve a string expression.\n     */\n    public static function resolveExpression(\n        string $entryName,\n        string $expression,\n        ContainerInterface $container\n    ) : string {\n        $callback = function (array $matches) use ($entryName, $container) {\n            try {\n                return $container->get($matches[1]);\n            } catch (NotFoundExceptionInterface $e) {\n                throw new DependencyException(sprintf(\n                    \"Error while parsing string expression for entry '%s': %s\",\n                    $entryName,\n                    $e->getMessage()\n                ), 0, $e);\n            }\n        };\n\n        $result = preg_replace_callback('#\\{([^\\{\\}]+)\\}#', $callback, $expression);\n        if ($result === null) {\n            throw new \\RuntimeException(sprintf('An unknown error occurred while parsing the string definition: \\'%s\\'', $expression));\n        }\n\n        return $result;\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Definition/ValueDefinition.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Definition;\n\nuse Psr\\Container\\ContainerInterface;\n\n/**\n * Definition of a value for dependency injection.\n *\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\nclass ValueDefinition implements Definition, SelfResolvingDefinition\n{\n    /**\n     * Entry name.\n     * @var string\n     */\n    private $name = '';\n\n    /**\n     * @var mixed\n     */\n    private $value;\n\n    /**\n     * @param mixed $value\n     */\n    public function __construct($value)\n    {\n        $this->value = $value;\n    }\n\n    public function getName() : string\n    {\n        return $this->name;\n    }\n\n    public function setName(string $name)\n    {\n        $this->name = $name;\n    }\n\n    /**\n     * @return mixed\n     */\n    public function getValue()\n    {\n        return $this->value;\n    }\n\n    public function resolve(ContainerInterface $container)\n    {\n        return $this->getValue();\n    }\n\n    public function isResolvable(ContainerInterface $container) : bool\n    {\n        return true;\n    }\n\n    public function replaceNestedDefinitions(callable $replacer)\n    {\n        // no nested definitions\n    }\n\n    public function __toString()\n    {\n        return sprintf('Value (%s)', var_export($this->value, true));\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/DependencyException.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI;\n\nuse Psr\\Container\\ContainerExceptionInterface;\n\n/**\n * Exception for the Container.\n */\nclass DependencyException extends \\Exception implements ContainerExceptionInterface\n{\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Factory/RequestedEntry.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Factory;\n\n/**\n * Represents the container entry that was requested.\n *\n * Implementations of this interface can be injected in factory parameters in order\n * to know what was the name of the requested entry.\n *\n * @api\n *\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\ninterface RequestedEntry\n{\n    /**\n     * Returns the name of the entry that was requested by the container.\n     */\n    public function getName() : string;\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/FactoryInterface.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI;\n\n/**\n * Describes the basic interface of a factory.\n *\n * @api\n *\n * @since 4.0\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\ninterface FactoryInterface\n{\n    /**\n     * Resolves an entry by its name. If given a class name, it will return a new instance of that class.\n     *\n     * @param string $name       Entry name or a class name.\n     * @param array  $parameters Optional parameters to use to build the entry. Use this to force specific\n     *                           parameters to specific values. Parameters not defined in this array will\n     *                           be automatically resolved.\n     *\n     * @throws \\InvalidArgumentException The name parameter must be of type string.\n     * @throws DependencyException       Error while resolving the entry.\n     * @throws NotFoundException         No entry or class found for the given name.\n     * @return mixed\n     */\n    public function make($name, array $parameters = []);\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Invoker/DefinitionParameterResolver.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Invoker;\n\nuse DI\\Definition\\Definition;\nuse DI\\Definition\\Helper\\DefinitionHelper;\nuse DI\\Definition\\Resolver\\DefinitionResolver;\nuse Invoker\\ParameterResolver\\ParameterResolver;\nuse ReflectionFunctionAbstract;\n\n/**\n * Resolves callable parameters using definitions.\n *\n * @since 5.0\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\nclass DefinitionParameterResolver implements ParameterResolver\n{\n    /**\n     * @var DefinitionResolver\n     */\n    private $definitionResolver;\n\n    public function __construct(DefinitionResolver $definitionResolver)\n    {\n        $this->definitionResolver = $definitionResolver;\n    }\n\n    public function getParameters(\n        ReflectionFunctionAbstract $reflection,\n        array $providedParameters,\n        array $resolvedParameters\n    ) : array {\n        // Skip parameters already resolved\n        if (! empty($resolvedParameters)) {\n            $providedParameters = array_diff_key($providedParameters, $resolvedParameters);\n        }\n\n        foreach ($providedParameters as $key => $value) {\n            if ($value instanceof DefinitionHelper) {\n                $value = $value->getDefinition('');\n            }\n\n            if (! $value instanceof Definition) {\n                continue;\n            }\n\n            $value = $this->definitionResolver->resolve($value);\n\n            if (is_int($key)) {\n                // Indexed by position\n                $resolvedParameters[$key] = $value;\n            } else {\n                // Indexed by parameter name\n                // TODO optimize?\n                $reflectionParameters = $reflection->getParameters();\n                foreach ($reflectionParameters as $reflectionParameter) {\n                    if ($key === $reflectionParameter->name) {\n                        $resolvedParameters[$reflectionParameter->getPosition()] = $value;\n                    }\n                }\n            }\n        }\n\n        return $resolvedParameters;\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Invoker/FactoryParameterResolver.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Invoker;\n\nuse Invoker\\ParameterResolver\\ParameterResolver;\nuse Psr\\Container\\ContainerInterface;\nuse ReflectionFunctionAbstract;\nuse ReflectionNamedType;\n\n/**\n * Inject the container, the definition or any other service using type-hints.\n *\n * {@internal This class is similar to TypeHintingResolver and TypeHintingContainerResolver,\n *            we use this instead for performance reasons}\n *\n * @author Quim Calpe <quim@kalpe.com>\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\nclass FactoryParameterResolver implements ParameterResolver\n{\n    /**\n     * @var ContainerInterface\n     */\n    private $container;\n\n    public function __construct(ContainerInterface $container)\n    {\n        $this->container = $container;\n    }\n\n    public function getParameters(\n        ReflectionFunctionAbstract $reflection,\n        array $providedParameters,\n        array $resolvedParameters\n    ) : array {\n        $parameters = $reflection->getParameters();\n\n        // Skip parameters already resolved\n        if (! empty($resolvedParameters)) {\n            $parameters = array_diff_key($parameters, $resolvedParameters);\n        }\n\n        foreach ($parameters as $index => $parameter) {\n            $parameterType = $parameter->getType();\n            if (!$parameterType) {\n                // No type\n                continue;\n            }\n            if (!$parameterType instanceof ReflectionNamedType) {\n                // Union types are not supported\n                continue;\n            }\n            if ($parameterType->isBuiltin()) {\n                // Primitive types are not supported\n                continue;\n            }\n\n            $parameterClass = $parameterType->getName();\n\n            if ($parameterClass === 'Psr\\Container\\ContainerInterface') {\n                $resolvedParameters[$index] = $this->container;\n            } elseif ($parameterClass === 'DI\\Factory\\RequestedEntry') {\n                // By convention the second parameter is the definition\n                $resolvedParameters[$index] = $providedParameters[1];\n            } elseif ($this->container->has($parameterClass)) {\n                $resolvedParameters[$index] = $this->container->get($parameterClass);\n            }\n        }\n\n        return $resolvedParameters;\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/NotFoundException.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI;\n\nuse Psr\\Container\\NotFoundExceptionInterface;\n\n/**\n * Exception thrown when a class or a value is not found in the container.\n */\nclass NotFoundException extends \\Exception implements NotFoundExceptionInterface\n{\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/Proxy/ProxyFactory.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI\\Proxy;\n\nuse ProxyManager\\Configuration;\nuse ProxyManager\\Factory\\LazyLoadingValueHolderFactory;\nuse ProxyManager\\FileLocator\\FileLocator;\nuse ProxyManager\\GeneratorStrategy\\EvaluatingGeneratorStrategy;\nuse ProxyManager\\GeneratorStrategy\\FileWriterGeneratorStrategy;\nuse ProxyManager\\Proxy\\LazyLoadingInterface;\n\n/**\n * Creates proxy classes.\n *\n * Wraps Ocramius/ProxyManager LazyLoadingValueHolderFactory.\n *\n * @see \\ProxyManager\\Factory\\LazyLoadingValueHolderFactory\n *\n * @since  5.0\n * @author Matthieu Napoli <matthieu@mnapoli.fr>\n */\nclass ProxyFactory\n{\n    /**\n     * If true, write the proxies to disk to improve performances.\n     * @var bool\n     */\n    private $writeProxiesToFile;\n\n    /**\n     * Directory where to write the proxies (if $writeProxiesToFile is enabled).\n     * @var string|null\n     */\n    private $proxyDirectory;\n\n    /**\n     * @var LazyLoadingValueHolderFactory|null\n     */\n    private $proxyManager;\n\n    public function __construct(bool $writeProxiesToFile = false, string $proxyDirectory = null)\n    {\n        $this->writeProxiesToFile = $writeProxiesToFile;\n        $this->proxyDirectory = $proxyDirectory;\n    }\n\n    /**\n     * Creates a new lazy proxy instance of the given class with\n     * the given initializer.\n     *\n     * @param string $className name of the class to be proxied\n     * @param \\Closure $initializer initializer to be passed to the proxy\n     */\n    public function createProxy(string $className, \\Closure $initializer) : LazyLoadingInterface\n    {\n        $this->createProxyManager();\n\n        return $this->proxyManager->createProxy($className, $initializer);\n    }\n\n    /**\n     * Generates and writes the proxy class to file.\n     *\n     * @param string $className name of the class to be proxied\n     */\n    public function generateProxyClass(string $className)\n    {\n        // If proxy classes a written to file then we pre-generate the class\n        // If they are not written to file then there is no point to do this\n        if ($this->writeProxiesToFile) {\n            $this->createProxyManager();\n            $this->createProxy($className, function () {});\n        }\n    }\n\n    private function createProxyManager()\n    {\n        if ($this->proxyManager !== null) {\n            return;\n        }\n\n        if (! class_exists(Configuration::class)) {\n            throw new \\RuntimeException('The ocramius/proxy-manager library is not installed. Lazy injection requires that library to be installed with Composer in order to work. Run \"composer require ocramius/proxy-manager:~2.0\".');\n        }\n\n        $config = new Configuration();\n\n        if ($this->writeProxiesToFile) {\n            $config->setProxiesTargetDir($this->proxyDirectory);\n            $config->setGeneratorStrategy(new FileWriterGeneratorStrategy(new FileLocator($this->proxyDirectory)));\n            // @phpstan-ignore-next-line\n            spl_autoload_register($config->getProxyAutoloader());\n        } else {\n            $config->setGeneratorStrategy(new EvaluatingGeneratorStrategy());\n        }\n\n        $this->proxyManager = new LazyLoadingValueHolderFactory($config);\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/src/functions.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace DI;\n\nuse DI\\Definition\\ArrayDefinitionExtension;\nuse DI\\Definition\\EnvironmentVariableDefinition;\nuse DI\\Definition\\Helper\\AutowireDefinitionHelper;\nuse DI\\Definition\\Helper\\CreateDefinitionHelper;\nuse DI\\Definition\\Helper\\FactoryDefinitionHelper;\nuse DI\\Definition\\Reference;\nuse DI\\Definition\\StringDefinition;\nuse DI\\Definition\\ValueDefinition;\n\nif (! function_exists('DI\\value')) {\n    /**\n     * Helper for defining a value.\n     *\n     * @param mixed $value\n     */\n    function value($value) : ValueDefinition\n    {\n        return new ValueDefinition($value);\n    }\n}\n\nif (! function_exists('DI\\create')) {\n    /**\n     * Helper for defining an object.\n     *\n     * @param string|null $className Class name of the object.\n     *                               If null, the name of the entry (in the container) will be used as class name.\n     */\n    function create(string $className = null) : CreateDefinitionHelper\n    {\n        return new CreateDefinitionHelper($className);\n    }\n}\n\nif (! function_exists('DI\\autowire')) {\n    /**\n     * Helper for autowiring an object.\n     *\n     * @param string|null $className Class name of the object.\n     *                               If null, the name of the entry (in the container) will be used as class name.\n     */\n    function autowire(string $className = null) : AutowireDefinitionHelper\n    {\n        return new AutowireDefinitionHelper($className);\n    }\n}\n\nif (! function_exists('DI\\factory')) {\n    /**\n     * Helper for defining a container entry using a factory function/callable.\n     *\n     * @param callable $factory The factory is a callable that takes the container as parameter\n     *                          and returns the value to register in the container.\n     */\n    function factory($factory) : FactoryDefinitionHelper\n    {\n        return new FactoryDefinitionHelper($factory);\n    }\n}\n\nif (! function_exists('DI\\decorate')) {\n    /**\n     * Decorate the previous definition using a callable.\n     *\n     * Example:\n     *\n     *     'foo' => decorate(function ($foo, $container) {\n     *         return new CachedFoo($foo, $container->get('cache'));\n     *     })\n     *\n     * @param callable $callable The callable takes the decorated object as first parameter and\n     *                           the container as second.\n     */\n    function decorate($callable) : FactoryDefinitionHelper\n    {\n        return new FactoryDefinitionHelper($callable, true);\n    }\n}\n\nif (! function_exists('DI\\get')) {\n    /**\n     * Helper for referencing another container entry in an object definition.\n     */\n    function get(string $entryName) : Reference\n    {\n        return new Reference($entryName);\n    }\n}\n\nif (! function_exists('DI\\env')) {\n    /**\n     * Helper for referencing environment variables.\n     *\n     * @param string $variableName The name of the environment variable.\n     * @param mixed $defaultValue The default value to be used if the environment variable is not defined.\n     */\n    function env(string $variableName, $defaultValue = null) : EnvironmentVariableDefinition\n    {\n        // Only mark as optional if the default value was *explicitly* provided.\n        $isOptional = 2 === func_num_args();\n\n        return new EnvironmentVariableDefinition($variableName, $isOptional, $defaultValue);\n    }\n}\n\nif (! function_exists('DI\\add')) {\n    /**\n     * Helper for extending another definition.\n     *\n     * Example:\n     *\n     *     'log.backends' => DI\\add(DI\\get('My\\Custom\\LogBackend'))\n     *\n     * or:\n     *\n     *     'log.backends' => DI\\add([\n     *         DI\\get('My\\Custom\\LogBackend')\n     *     ])\n     *\n     * @param mixed|array $values A value or an array of values to add to the array.\n     *\n     * @since 5.0\n     */\n    function add($values) : ArrayDefinitionExtension\n    {\n        if (! is_array($values)) {\n            $values = [$values];\n        }\n\n        return new ArrayDefinitionExtension($values);\n    }\n}\n\nif (! function_exists('DI\\string')) {\n    /**\n     * Helper for concatenating strings.\n     *\n     * Example:\n     *\n     *     'log.filename' => DI\\string('{app.path}/app.log')\n     *\n     * @param string $expression A string expression. Use the `{}` placeholders to reference other container entries.\n     *\n     * @since 5.0\n     */\n    function string(string $expression) : StringDefinition\n    {\n        return new StringDefinition($expression);\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/php-di/support.md",
    "content": "---\nlayout: documentation\ncurrent_menu: enterprise-support\ntitle: Enterprise support for PHP-DI\n---\n\n# PHP-DI for Enterprise\n\n> *Available as part of the Tidelift Subscription*\n\nTidelift is working with the maintainers of PHP-DI and thousands of other\nopen source projects to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use.\n\n#### [Learn more](https://tidelift.com/subscription/pkg/packagist-php-di-php-di?utm_source=packagist-php-di-php-di&utm_medium=referral&utm_campaign=enterprise) | [**Request a demo**](https://tidelift.com/subscription/request-a-demo?utm_source=packagist-php-di-php-di&utm_medium=referral&utm_campaign=enterprise)\n\n## Enterprise-ready open source software—managed for you\n\nThe Tidelift Subscription is a managed open source subscription for application dependencies covering millions of open source projects across JavaScript, Python, Java, PHP, Ruby, .NET, and more.\n\nYour subscription includes:\n\n- **Security updates**\n    Tidelift’s security response team coordinates patches for new breaking security vulnerabilities and alerts immediately through a private channel, so your software supply chain is always secure.\n\n- **Licensing verification and indemnification**\n    Tidelift verifies license information to enable easy policy enforcement and adds intellectual property indemnification to cover creators and users in case something goes wrong. You always have a 100% up-to-date bill of materials for your dependencies to share with your legal team, customers, or partners.\n\n- **Maintenance and code improvement**\n    Tidelift ensures the software you rely on keeps working as long as you need it to work. Your managed dependencies are actively maintained and we recruit additional maintainers where required.\n\n- **Package selection and version guidance**\n    We help you choose the best open source packages from the start—and then guide you through updates to stay on the best releases as new issues arise.\n\n- **Roadmap input**\n    Take a seat at the table with the creators behind the software you use. Tidelift’s participating maintainers earn more income as their software is used by more subscribers, so they’re interested in knowing what you need.\n\n- **Tooling and cloud integration**\n    Tidelift works with GitHub, GitLab, BitBucket, and more. We support every cloud platform (and other deployment targets, too).\n\nThe end result? All of the capabilities you expect from commercial-grade software, for the full breadth of open source you use. That means less time grappling with esoteric open source trivia, and more time building your own applications—and your business.\n\n[Learn more](https://tidelift.com/subscription/pkg/packagist-php-di-php-di?utm_source=packagist-php-di-php-di&utm_medium=referral&utm_campaign=enterprise) | [**Request a demo**](https://tidelift.com/subscription/request-a-demo?utm_source=packagist-php-di-php-di&utm_medium=referral&utm_campaign=enterprise)\n"
  },
  {
    "path": "server/vendor/php-di/phpdoc-reader/.gitattributes",
    "content": "# .gitattributes\ntests/ export-ignore\nphpunit.xml.dist export-ignore\n.travis.yml export-ignore\n\n# Auto detect text files and perform LF normalization\n* text=auto\n"
  },
  {
    "path": "server/vendor/php-di/phpdoc-reader/.github/workflows/ci.yml",
    "content": "name: CI\n\non:\n    push:\n        branches: ['master']\n    pull_request:\n        branches: ['*']\n    schedule:\n        -   cron: '0 0 * * *'\n\njobs:\n\n    tests:\n        name: Tests - PHP ${{ matrix.php }} ${{ matrix.dependency-version }}\n        runs-on: ubuntu-latest\n        timeout-minutes: 15\n        strategy:\n            matrix:\n                php: [ '7.2', '7.3', '7.4', '8.0' ]\n                dependency-version: [ '' ]\n                include:\n                    -   php: '7.2'\n                        dependency-version: '--prefer-lowest'\n        steps:\n            -   name: Checkout\n                uses: actions/checkout@v2\n            -   name: Setup PHP\n                uses: shivammathur/setup-php@v2\n                with:\n                    php-version: ${{ matrix.php }}\n                    tools: composer:v2\n                    coverage: none\n            -   name: Cache Composer dependencies\n                uses: actions/cache@v2\n                with:\n                    path: ~/.composer/cache\n                    key: php-${{ matrix.php }}-composer-locked-${{ hashFiles('composer.lock') }}\n                    restore-keys: php-${{ matrix.php }}-composer-locked-\n            -   name: Install PHP dependencies\n                run: composer update ${{ matrix.dependency-version }} --prefer-dist --no-interaction --no-progress --no-suggest\n            -   name: PHPUnit\n                run: vendor/bin/phpunit\n\n    cs:\n        name: Coding standards\n        runs-on: ubuntu-latest\n        steps:\n            -   name: Checkout\n                uses: actions/checkout@v2\n            -   name: Setup PHP\n                uses: shivammathur/setup-php@v2\n                with:\n                    php-version: 7.4\n                    tools: composer:v2, cs2pr\n                    coverage: none\n            -   name: Cache Composer dependencies\n                uses: actions/cache@v2\n                with:\n                    path: ~/.composer/cache\n                    key: php-74-composer-locked-${{ hashFiles('composer.lock') }}\n                    restore-keys: php-74-composer-locked-\n            -   name: Install PHP dependencies\n                run: composer install --no-interaction --no-progress --no-suggest\n            -   name: PHP CodeSniffer\n                run: vendor/bin/phpcs -q --no-colors --report=checkstyle | cs2pr\n"
  },
  {
    "path": "server/vendor/php-di/phpdoc-reader/.gitignore",
    "content": ".DS_Store\n.idea/*\nvendor/*\ncomposer.phar\ncomposer.lock\n.phpcs-cache\n.phpunit.result.cache\n"
  },
  {
    "path": "server/vendor/php-di/phpdoc-reader/.phpcs.xml.dist",
    "content": "<?xml version=\"1.0\"?>\n<ruleset>\n    <arg name=\"basepath\" value=\".\"/>\n    <arg name=\"extensions\" value=\"php\"/>\n    <arg name=\"cache\" value=\".phpcs-cache\"/>\n    <!-- Show sniff names -->\n    <arg value=\"s\"/>\n\n    <file>src</file>\n    <exclude-pattern>src/PhpDocReader/PhpParser/TokenParser.php</exclude-pattern>\n    <file>tests</file>\n    <exclude-pattern>tests/Fixtures</exclude-pattern>\n\n    <rule ref=\"HardMode\"/>\n\n    <!-- Ignore PhpDocReader\\AnnotationException -->\n    <rule ref=\"SlevomatCodingStandard.Classes.SuperfluousExceptionNaming.SuperfluousSuffix\">\n        <severity>0</severity>\n    </rule>\n\n</ruleset>\n"
  },
  {
    "path": "server/vendor/php-di/phpdoc-reader/LICENSE",
    "content": "Copyright (C) 2019 Matthieu Napoli\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and\nassociated documentation files (the \"Software\"), to deal in the Software without restriction,\nincluding without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,\nand/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial\nportions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT\nNOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\nWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "server/vendor/php-di/phpdoc-reader/README.md",
    "content": "# PhpDocReader\n\n![](https://img.shields.io/packagist/dt/PHP-DI/phpdoc-reader.svg)\n\nThis project is used by:\n\n- [PHP-DI 6](http://php-di.org/)\n- [phockito-unit-php-di](https://github.com/balihoo/phockito-unit-php-di)\n\nFork the README to add your project here.\n\n## Features\n\nPhpDocReader parses `@var` and `@param` values in PHP docblocks:\n\n```php\n\nuse My\\Cache\\Backend;\n\nclass Cache\n{\n    /**\n     * @var Backend\n     */\n    protected $backend;\n\n    /**\n     * @param Backend $backend\n     */\n    public function __construct($backend)\n    {\n    }\n}\n```\n\nIt supports namespaced class names with the same resolution rules as PHP:\n\n- fully qualified name (starting with `\\`)\n- imported class name (eg. `use My\\Cache\\Backend;`)\n- relative class name (from the current namespace, like `SubNamespace\\MyClass`)\n- aliased class name  (eg. `use My\\Cache\\Backend as FooBar;`)\n\nPrimitive types (`@var string`) are ignored (returns null), only valid class names are returned.\n\n## Usage\n\n```php\n$reader = new PhpDocReader();\n\n// Read a property type (@var phpdoc)\n$property = new ReflectionProperty($className, $propertyName);\n$propertyClass = $reader->getPropertyClass($property);\n\n// Read a parameter type (@param phpdoc)\n$parameter = new ReflectionParameter(array($className, $methodName), $parameterName);\n$parameterClass = $reader->getParameterClass($parameter);\n```\n"
  },
  {
    "path": "server/vendor/php-di/phpdoc-reader/composer.json",
    "content": "{\n    \"name\": \"php-di/phpdoc-reader\",\n    \"type\": \"library\",\n    \"description\": \"PhpDocReader parses @var and @param values in PHP docblocks (supports namespaced class names with the same resolution rules as PHP)\",\n    \"keywords\": [\"phpdoc\", \"reflection\"],\n    \"license\": \"MIT\",\n    \"autoload\": {\n        \"psr-4\": {\n            \"PhpDocReader\\\\\": \"src/PhpDocReader\"\n        }\n    },\n    \"autoload-dev\": {\n        \"psr-4\": {\n            \"UnitTest\\\\PhpDocReader\\\\\": \"tests/\"\n        }\n    },\n    \"require\": {\n        \"php\": \">=7.2.0\"\n    },\n    \"require-dev\": {\n        \"phpunit/phpunit\": \"^8.5|^9.0\",\n        \"mnapoli/hard-mode\": \"~0.3.0\"\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/phpdoc-reader/src/PhpDocReader/AnnotationException.php",
    "content": "<?php declare(strict_types=1);\n\nnamespace PhpDocReader;\n\n/**\n * We stumbled upon an invalid class/property/method annotation.\n */\nclass AnnotationException extends \\Exception\n{\n}\n"
  },
  {
    "path": "server/vendor/php-di/phpdoc-reader/src/PhpDocReader/PhpDocReader.php",
    "content": "<?php declare(strict_types=1);\n\nnamespace PhpDocReader;\n\nuse PhpDocReader\\PhpParser\\UseStatementParser;\nuse ReflectionClass;\nuse ReflectionMethod;\nuse ReflectionParameter;\nuse ReflectionProperty;\nuse Reflector;\n\n/**\n * PhpDoc reader\n */\nclass PhpDocReader\n{\n    /** @var UseStatementParser */\n    private $parser;\n\n    private const PRIMITIVE_TYPES = [\n        'bool' => 'bool',\n        'boolean' => 'bool',\n        'string' => 'string',\n        'int' => 'int',\n        'integer' => 'int',\n        'float' => 'float',\n        'double' => 'float',\n        'array' => 'array',\n        'object' => 'object',\n        'callable' => 'callable',\n        'resource' => 'resource',\n        'mixed' => 'mixed',\n        'iterable' => 'iterable',\n    ];\n\n    /** @var bool */\n    private $ignorePhpDocErrors;\n\n    /**\n     * @param bool $ignorePhpDocErrors Enable or disable throwing errors when PhpDoc errors occur (when parsing annotations).\n     */\n    public function __construct(bool $ignorePhpDocErrors = false)\n    {\n        $this->parser = new UseStatementParser;\n        $this->ignorePhpDocErrors = $ignorePhpDocErrors;\n    }\n\n    /**\n     * Parse the docblock of the property to get the type (class or primitive type) of the var annotation.\n     *\n     * @return string|null Type of the property (content of var annotation)\n     * @throws AnnotationException\n     */\n    public function getPropertyType(ReflectionProperty $property): ?string\n    {\n        return $this->readPropertyType($property, true);\n    }\n\n    /**\n     * Parse the docblock of the property to get the class of the var annotation.\n     *\n     * @return string|null Type of the property (content of var annotation)\n     * @throws AnnotationException\n     */\n    public function getPropertyClass(ReflectionProperty $property): ?string\n    {\n        return $this->readPropertyType($property, false);\n    }\n\n    private function readPropertyType(ReflectionProperty $property, bool $allowPrimitiveTypes): ?string\n    {\n        // Get the content of the @var annotation\n        $docComment = $property->getDocComment();\n        if (! $docComment) {\n            return null;\n        }\n        if (preg_match('/@var\\s+([^\\s]+)/', $docComment, $matches)) {\n            [, $type] = $matches;\n        } else {\n            return null;\n        }\n\n        // Ignore primitive types\n        if (isset(self::PRIMITIVE_TYPES[$type])) {\n            if ($allowPrimitiveTypes) {\n                return self::PRIMITIVE_TYPES[$type];\n            }\n            return null;\n        }\n\n        // Ignore types containing special characters ([], <> ...)\n        if (! preg_match('/^[a-zA-Z0-9\\\\\\\\_]+$/', $type)) {\n            return null;\n        }\n\n        $class = $property->getDeclaringClass();\n\n        // If the class name is not fully qualified (i.e. doesn't start with a \\)\n        if ($type[0] !== '\\\\') {\n            // Try to resolve the FQN using the class context\n            $resolvedType = $this->tryResolveFqn($type, $class, $property);\n\n            if (! $resolvedType && ! $this->ignorePhpDocErrors) {\n                throw new AnnotationException(sprintf(\n                    'The @var annotation on %s::%s contains a non existent class \"%s\". '\n                        . 'Did you maybe forget to add a \"use\" statement for this annotation?',\n                    $class->name,\n                    $property->getName(),\n                    $type\n                ));\n            }\n\n            $type = $resolvedType;\n        }\n\n        if (! $this->ignorePhpDocErrors && ! $this->classExists($type)) {\n            throw new AnnotationException(sprintf(\n                'The @var annotation on %s::%s contains a non existent class \"%s\"',\n                $class->name,\n                $property->getName(),\n                $type\n            ));\n        }\n\n        // Remove the leading \\ (FQN shouldn't contain it)\n        $type = is_string($type) ? ltrim($type, '\\\\') : null;\n\n        return $type;\n    }\n\n    /**\n     * Parse the docblock of the property to get the type (class or primitive type) of the param annotation.\n     *\n     * @return string|null Type of the property (content of var annotation)\n     * @throws AnnotationException\n     */\n    public function getParameterType(ReflectionParameter $parameter): ?string\n    {\n        return $this->readParameterClass($parameter, true);\n    }\n\n    /**\n     * Parse the docblock of the property to get the class of the param annotation.\n     *\n     * @return string|null Type of the property (content of var annotation)\n     * @throws AnnotationException\n     */\n    public function getParameterClass(ReflectionParameter $parameter): ?string\n    {\n        return $this->readParameterClass($parameter, false);\n    }\n\n    private function readParameterClass(ReflectionParameter $parameter, bool $allowPrimitiveTypes): ?string\n    {\n        // Use reflection\n        $parameterType = $parameter->getType();\n        if ($parameterType && $parameterType instanceof \\ReflectionNamedType && ! $parameterType->isBuiltin()) {\n            return $parameterType->getName();\n        }\n\n        $parameterName = $parameter->name;\n        // Get the content of the @param annotation\n        $method = $parameter->getDeclaringFunction();\n        $docComment = $method->getDocComment();\n        if (! $docComment) {\n            return null;\n        }\n        if (preg_match('/@param\\s+([^\\s]+)\\s+\\$' . $parameterName . '/', $docComment, $matches)) {\n            [, $type] = $matches;\n        } else {\n            return null;\n        }\n\n        // Ignore primitive types\n        if (isset(self::PRIMITIVE_TYPES[$type])) {\n            if ($allowPrimitiveTypes) {\n                return self::PRIMITIVE_TYPES[$type];\n            }\n            return null;\n        }\n\n        // Ignore types containing special characters ([], <> ...)\n        if (! preg_match('/^[a-zA-Z0-9\\\\\\\\_]+$/', $type)) {\n            return null;\n        }\n\n        $class = $parameter->getDeclaringClass();\n\n        // If the class name is not fully qualified (i.e. doesn't start with a \\)\n        if ($type[0] !== '\\\\') {\n            // Try to resolve the FQN using the class context\n            $resolvedType = $this->tryResolveFqn($type, $class, $parameter);\n\n            if (! $resolvedType && ! $this->ignorePhpDocErrors) {\n                throw new AnnotationException(sprintf(\n                    'The @param annotation for parameter \"%s\" of %s::%s contains a non existent class \"%s\". '\n                        . 'Did you maybe forget to add a \"use\" statement for this annotation?',\n                    $parameterName,\n                    $class->name,\n                    $method->name,\n                    $type\n                ));\n            }\n\n            $type = $resolvedType;\n        }\n\n        if (! $this->ignorePhpDocErrors && ! $this->classExists($type)) {\n            throw new AnnotationException(sprintf(\n                'The @param annotation for parameter \"%s\" of %s::%s contains a non existent class \"%s\"',\n                $parameterName,\n                $class->name,\n                $method->name,\n                $type\n            ));\n        }\n\n        // Remove the leading \\ (FQN shouldn't contain it)\n        $type = is_string($type) ? ltrim($type, '\\\\') : null;\n\n        return $type;\n    }\n\n    /**\n     * Attempts to resolve the FQN of the provided $type based on the $class and $member context.\n     *\n     * @return string|null Fully qualified name of the type, or null if it could not be resolved\n     */\n    private function tryResolveFqn(string $type, ReflectionClass $class, Reflector $member): ?string\n    {\n        $alias = ($pos = strpos($type, '\\\\')) === false ? $type : substr($type, 0, $pos);\n        $loweredAlias = strtolower($alias);\n\n        // Retrieve \"use\" statements\n        $uses = $this->parser->parseUseStatements($class);\n\n        if (isset($uses[$loweredAlias])) {\n            // Imported classes\n            if ($pos !== false) {\n                return $uses[$loweredAlias] . substr($type, $pos);\n            }\n            return $uses[$loweredAlias];\n        }\n\n        if ($this->classExists($class->getNamespaceName() . '\\\\' . $type)) {\n            return $class->getNamespaceName() . '\\\\' . $type;\n        }\n\n        if (isset($uses['__NAMESPACE__']) && $this->classExists($uses['__NAMESPACE__'] . '\\\\' . $type)) {\n            // Class namespace\n            return $uses['__NAMESPACE__'] . '\\\\' . $type;\n        }\n\n        if ($this->classExists($type)) {\n            // No namespace\n            return $type;\n        }\n\n        // If all fail, try resolving through related traits\n        return $this->tryResolveFqnInTraits($type, $class, $member);\n    }\n\n    /**\n     * Attempts to resolve the FQN of the provided $type based on the $class and $member context, specifically searching\n     * through the traits that are used by the provided $class.\n     *\n     * @return string|null Fully qualified name of the type, or null if it could not be resolved\n     */\n    private function tryResolveFqnInTraits(string $type, ReflectionClass $class, Reflector $member): ?string\n    {\n        /** @var ReflectionClass[] $traits */\n        $traits = [];\n\n        // Get traits for the class and its parents\n        while ($class) {\n            $traits = array_merge($traits, $class->getTraits());\n            $class = $class->getParentClass();\n        }\n\n        foreach ($traits as $trait) {\n            // Eliminate traits that don't have the property/method/parameter\n            if ($member instanceof ReflectionProperty && ! $trait->hasProperty($member->name)) {\n                continue;\n            }\n            if ($member instanceof ReflectionMethod && ! $trait->hasMethod($member->name)) {\n                continue;\n            }\n            if ($member instanceof ReflectionParameter && ! $trait->hasMethod($member->getDeclaringFunction()->name)) {\n                continue;\n            }\n\n            // Run the resolver again with the ReflectionClass instance for the trait\n            $resolvedType = $this->tryResolveFqn($type, $trait, $member);\n\n            if ($resolvedType) {\n                return $resolvedType;\n            }\n        }\n\n        return null;\n    }\n\n    private function classExists(string $class): bool\n    {\n        return class_exists($class) || interface_exists($class);\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/phpdoc-reader/src/PhpDocReader/PhpParser/TokenParser.php",
    "content": "<?php declare(strict_types=1);\n\nnamespace PhpDocReader\\PhpParser;\n\n/**\n * Parses a file for namespaces/use/class declarations.\n *\n * Class taken and adapted from doctrine/annotations to avoid pulling the whole package.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n * @author Christian Kaps <christian.kaps@mohiva.com>\n */\nclass TokenParser\n{\n    /**\n     * The token list.\n     *\n     * @var list<mixed[]>\n     */\n    private $tokens;\n\n    /**\n     * The number of tokens.\n     *\n     * @var int\n     */\n    private $numTokens;\n\n    /**\n     * The current array pointer.\n     *\n     * @var int\n     */\n    private $pointer = 0;\n\n    /**\n     * @param string $contents\n     */\n    public function __construct($contents)\n    {\n        $this->tokens = token_get_all($contents);\n\n        // The PHP parser sets internal compiler globals for certain things. Annoyingly, the last docblock comment it\n        // saw gets stored in doc_comment. When it comes to compile the next thing to be include()d this stored\n        // doc_comment becomes owned by the first thing the compiler sees in the file that it considers might have a\n        // docblock. If the first thing in the file is a class without a doc block this would cause calls to\n        // getDocBlock() on said class to return our long lost doc_comment. Argh.\n        // To workaround, cause the parser to parse an empty docblock. Sure getDocBlock() will return this, but at least\n        // it's harmless to us.\n        token_get_all(\"<?php\\n/**\\n *\\n */\");\n\n        $this->numTokens = count($this->tokens);\n    }\n\n    /**\n     * Gets all use statements.\n     *\n     * @param string $namespaceName The namespace name of the reflected class.\n     *\n     * @return array<string, string> A list with all found use statements.\n     */\n    public function parseUseStatements($namespaceName)\n    {\n        $statements = [];\n        while (($token = $this->next())) {\n            if ($token[0] === T_USE) {\n                $statements = array_merge($statements, $this->parseUseStatement());\n                continue;\n            }\n\n            if ($token[0] !== T_NAMESPACE || $this->parseNamespace() !== $namespaceName) {\n                continue;\n            }\n\n            // Get fresh array for new namespace. This is to prevent the parser to collect the use statements\n            // for a previous namespace with the same name. This is the case if a namespace is defined twice\n            // or if a namespace with the same name is commented out.\n            $statements = [];\n        }\n\n        return $statements;\n    }\n\n    /**\n     * Gets the next non whitespace and non comment token.\n     *\n     * @param bool $docCommentIsComment If TRUE then a doc comment is considered a comment and skipped.\n     *                                  If FALSE then only whitespace and normal comments are skipped.\n     *\n     * @return mixed[]|string|null The token if exists, null otherwise.\n     */\n    private function next($docCommentIsComment = true)\n    {\n        for ($i = $this->pointer; $i < $this->numTokens; $i++) {\n            $this->pointer++;\n            if (\n                $this->tokens[$i][0] === T_WHITESPACE ||\n                $this->tokens[$i][0] === T_COMMENT ||\n                ($docCommentIsComment && $this->tokens[$i][0] === T_DOC_COMMENT)\n            ) {\n                continue;\n            }\n\n            return $this->tokens[$i];\n        }\n\n        return null;\n    }\n\n    /**\n     * Parses a single use statement.\n     *\n     * @return array<string, string> A list with all found class names for a use statement.\n     */\n    private function parseUseStatement()\n    {\n        $groupRoot = '';\n        $class = '';\n        $alias = '';\n        $statements = [];\n        $explicitAlias = false;\n        while (($token = $this->next())) {\n            if (! $explicitAlias && $token[0] === T_STRING) {\n                $class .= $token[1];\n                $alias = $token[1];\n            } elseif ($explicitAlias && $token[0] === T_STRING) {\n                $alias = $token[1];\n            } elseif (\n                PHP_VERSION_ID >= 80000 &&\n                ($token[0] === T_NAME_QUALIFIED || $token[0] === T_NAME_FULLY_QUALIFIED)\n            ) {\n                $class .= $token[1];\n\n                $classSplit = explode('\\\\', $token[1]);\n                $alias = $classSplit[count($classSplit) - 1];\n            } elseif ($token[0] === T_NS_SEPARATOR) {\n                $class .= '\\\\';\n                $alias = '';\n            } elseif ($token[0] === T_AS) {\n                $explicitAlias = true;\n                $alias = '';\n            } elseif ($token === ',') {\n                $statements[strtolower($alias)] = $groupRoot . $class;\n                $class = '';\n                $alias = '';\n                $explicitAlias = false;\n            } elseif ($token === ';') {\n                $statements[strtolower($alias)] = $groupRoot . $class;\n                break;\n            } elseif ($token === '{') {\n                $groupRoot = $class;\n                $class = '';\n            } elseif ($token === '}') {\n                continue;\n            } else {\n                break;\n            }\n        }\n\n        return $statements;\n    }\n\n    /**\n     * Gets the namespace.\n     *\n     * @return string The found namespace.\n     */\n    private function parseNamespace()\n    {\n        $name = '';\n        while (\n            ($token = $this->next()) && ($token[0] === T_STRING || $token[0] === T_NS_SEPARATOR || (\n                    PHP_VERSION_ID >= 80000 &&\n                    ($token[0] === T_NAME_QUALIFIED || $token[0] === T_NAME_FULLY_QUALIFIED)\n                ))\n        ) {\n            $name .= $token[1];\n        }\n\n        return $name;\n    }\n}\n"
  },
  {
    "path": "server/vendor/php-di/phpdoc-reader/src/PhpDocReader/PhpParser/UseStatementParser.php",
    "content": "<?php declare(strict_types=1);\n\nnamespace PhpDocReader\\PhpParser;\n\nuse SplFileObject;\n\n/**\n * Parses a file for \"use\" declarations.\n *\n * Class taken and adapted from doctrine/annotations to avoid pulling the whole package.\n *\n * Authors: Fabien Potencier <fabien@symfony.com> and Christian Kaps <christian.kaps@mohiva.com>\n */\nclass UseStatementParser\n{\n    /**\n     * @return array A list with use statements in the form (Alias => FQN).\n     */\n    public function parseUseStatements(\\ReflectionClass $class): array\n    {\n        $filename = $class->getFilename();\n        if ($filename === false) {\n            return [];\n        }\n\n        $content = $this->getFileContent($filename, $class->getStartLine());\n\n        if ($content === null) {\n            return [];\n        }\n\n        $namespace = preg_quote($class->getNamespaceName(), '/');\n        $content = preg_replace('/^.*?(\\bnamespace\\s+' . $namespace . '\\s*[;{].*)$/s', '\\\\1', $content);\n        $tokenizer = new TokenParser('<?php ' . $content);\n\n        return $tokenizer->parseUseStatements($class->getNamespaceName());\n    }\n\n    /**\n     * Gets the content of the file right up to the given line number.\n     *\n     * @param string $filename The name of the file to load.\n     * @param int $lineNumber The number of lines to read from file.\n     */\n    private function getFileContent(string $filename, int $lineNumber): string\n    {\n        if (! is_file($filename)) {\n            throw new \\RuntimeException(\"Unable to read file $filename\");\n        }\n\n        $content = '';\n        $lineCnt = 0;\n        $file = new SplFileObject($filename);\n        while (! $file->eof()) {\n            if ($lineCnt++ === $lineNumber) {\n                break;\n            }\n\n            $content .= $file->fgets();\n        }\n\n        return $content;\n    }\n}\n"
  },
  {
    "path": "server/vendor/phpoption/phpoption/LICENSE",
    "content": "                                 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": "server/vendor/phpoption/phpoption/composer.json",
    "content": "{\n    \"name\": \"phpoption/phpoption\",\n    \"description\": \"Option Type for PHP\",\n    \"keywords\": [\"php\", \"option\", \"language\", \"type\"],\n    \"license\": \"Apache-2.0\",\n    \"authors\": [\n        {\n            \"name\": \"Johannes M. Schmitt\",\n            \"email\": \"schmittjoh@gmail.com\",\n            \"homepage\": \"https://github.com/schmittjoh\"\n        },\n        {\n            \"name\": \"Graham Campbell\",\n            \"email\": \"hello@gjcampbell.co.uk\",\n            \"homepage\": \"https://github.com/GrahamCampbell\"\n        }\n    ],\n    \"require\": {\n        \"php\": \"^7.2.5 || ^8.0\"\n    },\n    \"require-dev\": {\n        \"bamarni/composer-bin-plugin\": \"^1.8.2\",\n        \"phpunit/phpunit\": \"^8.5.39 || ^9.6.20 || ^10.5.28\"\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"PhpOption\\\\\": \"src/PhpOption/\"\n        }\n    },\n    \"autoload-dev\": {\n        \"psr-4\": {\n            \"PhpOption\\\\Tests\\\\\": \"tests/PhpOption/Tests/\"\n        }\n    },\n    \"config\": {\n        \"allow-plugins\": {\n            \"bamarni/composer-bin-plugin\": true\n        },\n        \"preferred-install\": \"dist\"\n    },\n    \"extra\": {\n        \"bamarni-bin\": {\n            \"bin-links\": true,\n            \"forward-command\": false\n        },\n        \"branch-alias\": {\n            \"dev-master\": \"1.9-dev\"\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/phpoption/phpoption/src/PhpOption/LazyOption.php",
    "content": "<?php\n\n/*\n * Copyright 2012 Johannes M. Schmitt <schmittjoh@gmail.com>\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\nnamespace PhpOption;\n\nuse Traversable;\n\n/**\n * @template T\n *\n * @extends Option<T>\n */\nfinal class LazyOption extends Option\n{\n    /** @var callable(mixed...):(Option<T>) */\n    private $callback;\n\n    /** @var array<int, mixed> */\n    private $arguments;\n\n    /** @var Option<T>|null */\n    private $option;\n\n    /**\n     * @template S\n     * @param callable(mixed...):(Option<S>) $callback\n     * @param array<int, mixed>              $arguments\n     *\n     * @return LazyOption<S>\n     */\n    public static function create($callback, array $arguments = []): self\n    {\n        return new self($callback, $arguments);\n    }\n\n    /**\n     * @param callable(mixed...):(Option<T>) $callback\n     * @param array<int, mixed>              $arguments\n     */\n    public function __construct($callback, array $arguments = [])\n    {\n        if (!is_callable($callback)) {\n            throw new \\InvalidArgumentException('Invalid callback given');\n        }\n\n        $this->callback = $callback;\n        $this->arguments = $arguments;\n    }\n\n    public function isDefined(): bool\n    {\n        return $this->option()->isDefined();\n    }\n\n    public function isEmpty(): bool\n    {\n        return $this->option()->isEmpty();\n    }\n\n    public function get()\n    {\n        return $this->option()->get();\n    }\n\n    public function getOrElse($default)\n    {\n        return $this->option()->getOrElse($default);\n    }\n\n    public function getOrCall($callable)\n    {\n        return $this->option()->getOrCall($callable);\n    }\n\n    public function getOrThrow(\\Exception $ex)\n    {\n        return $this->option()->getOrThrow($ex);\n    }\n\n    public function orElse(Option $else)\n    {\n        return $this->option()->orElse($else);\n    }\n\n    public function ifDefined($callable)\n    {\n        $this->option()->forAll($callable);\n    }\n\n    public function forAll($callable)\n    {\n        return $this->option()->forAll($callable);\n    }\n\n    public function map($callable)\n    {\n        return $this->option()->map($callable);\n    }\n\n    public function flatMap($callable)\n    {\n        return $this->option()->flatMap($callable);\n    }\n\n    public function filter($callable)\n    {\n        return $this->option()->filter($callable);\n    }\n\n    public function filterNot($callable)\n    {\n        return $this->option()->filterNot($callable);\n    }\n\n    public function select($value)\n    {\n        return $this->option()->select($value);\n    }\n\n    public function reject($value)\n    {\n        return $this->option()->reject($value);\n    }\n\n    /**\n     * @return Traversable<T>\n     */\n    public function getIterator(): Traversable\n    {\n        return $this->option()->getIterator();\n    }\n\n    public function foldLeft($initialValue, $callable)\n    {\n        return $this->option()->foldLeft($initialValue, $callable);\n    }\n\n    public function foldRight($initialValue, $callable)\n    {\n        return $this->option()->foldRight($initialValue, $callable);\n    }\n\n    /**\n     * @return Option<T>\n     */\n    private function option(): Option\n    {\n        if (null === $this->option) {\n            /** @var mixed */\n            $option = call_user_func_array($this->callback, $this->arguments);\n            if ($option instanceof Option) {\n                $this->option = $option;\n            } else {\n                throw new \\RuntimeException(sprintf('Expected instance of %s', Option::class));\n            }\n        }\n\n        return $this->option;\n    }\n}\n"
  },
  {
    "path": "server/vendor/phpoption/phpoption/src/PhpOption/None.php",
    "content": "<?php\n\n/*\n * Copyright 2012 Johannes M. Schmitt <schmittjoh@gmail.com>\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\nnamespace PhpOption;\n\nuse EmptyIterator;\n\n/**\n * @extends Option<mixed>\n */\nfinal class None extends Option\n{\n    /** @var None|null */\n    private static $instance;\n\n    /**\n     * @return None\n     */\n    public static function create(): self\n    {\n        if (null === self::$instance) {\n            self::$instance = new self();\n        }\n\n        return self::$instance;\n    }\n\n    public function get()\n    {\n        throw new \\RuntimeException('None has no value.');\n    }\n\n    public function getOrCall($callable)\n    {\n        return $callable();\n    }\n\n    public function getOrElse($default)\n    {\n        return $default;\n    }\n\n    public function getOrThrow(\\Exception $ex)\n    {\n        throw $ex;\n    }\n\n    public function isEmpty(): bool\n    {\n        return true;\n    }\n\n    public function isDefined(): bool\n    {\n        return false;\n    }\n\n    public function orElse(Option $else)\n    {\n        return $else;\n    }\n\n    public function ifDefined($callable)\n    {\n        // Just do nothing in that case.\n    }\n\n    public function forAll($callable)\n    {\n        return $this;\n    }\n\n    public function map($callable)\n    {\n        return $this;\n    }\n\n    public function flatMap($callable)\n    {\n        return $this;\n    }\n\n    public function filter($callable)\n    {\n        return $this;\n    }\n\n    public function filterNot($callable)\n    {\n        return $this;\n    }\n\n    public function select($value)\n    {\n        return $this;\n    }\n\n    public function reject($value)\n    {\n        return $this;\n    }\n\n    public function getIterator(): EmptyIterator\n    {\n        return new EmptyIterator();\n    }\n\n    public function foldLeft($initialValue, $callable)\n    {\n        return $initialValue;\n    }\n\n    public function foldRight($initialValue, $callable)\n    {\n        return $initialValue;\n    }\n\n    private function __construct()\n    {\n    }\n}\n"
  },
  {
    "path": "server/vendor/phpoption/phpoption/src/PhpOption/Option.php",
    "content": "<?php\n\n/*\n * Copyright 2012 Johannes M. Schmitt <schmittjoh@gmail.com>\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\nnamespace PhpOption;\n\nuse ArrayAccess;\nuse IteratorAggregate;\n\n/**\n * @template T\n *\n * @implements IteratorAggregate<T>\n */\nabstract class Option implements IteratorAggregate\n{\n    /**\n     * Creates an option given a return value.\n     *\n     * This is intended for consuming existing APIs and allows you to easily\n     * convert them to an option. By default, we treat ``null`` as the None\n     * case, and everything else as Some.\n     *\n     * @template S\n     *\n     * @param S $value     The actual return value.\n     * @param S $noneValue The value which should be considered \"None\"; null by\n     *                     default.\n     *\n     * @return Option<S>\n     */\n    public static function fromValue($value, $noneValue = null)\n    {\n        if ($value === $noneValue) {\n            return None::create();\n        }\n\n        return new Some($value);\n    }\n\n    /**\n     * Creates an option from an array's value.\n     *\n     * If the key does not exist in the array, the array is not actually an\n     * array, or the array's value at the given key is null, None is returned.\n     * Otherwise, Some is returned wrapping the value at the given key.\n     *\n     * @template S\n     *\n     * @param array<string|int,S>|ArrayAccess<string|int,S>|null $array A potential array or \\ArrayAccess value.\n     * @param string|int|null                                    $key   The key to check.\n     *\n     * @return Option<S>\n     */\n    public static function fromArraysValue($array, $key)\n    {\n        if ($key === null || !(is_array($array) || $array instanceof ArrayAccess) || !isset($array[$key])) {\n            return None::create();\n        }\n\n        return new Some($array[$key]);\n    }\n\n    /**\n     * Creates a lazy-option with the given callback.\n     *\n     * This is also a helper constructor for lazy-consuming existing APIs where\n     * the return value is not yet an option. By default, we treat ``null`` as\n     * None case, and everything else as Some.\n     *\n     * @template S\n     *\n     * @param callable $callback  The callback to evaluate.\n     * @param array    $arguments The arguments for the callback.\n     * @param S        $noneValue The value which should be considered \"None\";\n    *                             null by default.\n     *\n     * @return LazyOption<S>\n     */\n    public static function fromReturn($callback, array $arguments = [], $noneValue = null)\n    {\n        return new LazyOption(static function () use ($callback, $arguments, $noneValue) {\n            /** @var mixed */\n            $return = call_user_func_array($callback, $arguments);\n\n            if ($return === $noneValue) {\n                return None::create();\n            }\n\n            return new Some($return);\n        });\n    }\n\n    /**\n     * Option factory, which creates new option based on passed value.\n     *\n     * If value is already an option, it simply returns. If value is callable,\n     * LazyOption with passed callback created and returned. If Option\n     * returned from callback, it returns directly. On other case value passed\n     * to Option::fromValue() method.\n     *\n     * @template S\n     *\n     * @param Option<S>|callable|S $value\n     * @param S                    $noneValue Used when $value is mixed or\n     *                                        callable, for None-check.\n     *\n     * @return Option<S>|LazyOption<S>\n     */\n    public static function ensure($value, $noneValue = null)\n    {\n        if ($value instanceof self) {\n            return $value;\n        } elseif (is_callable($value)) {\n            return new LazyOption(static function () use ($value, $noneValue) {\n                /** @var mixed */\n                $return = $value();\n\n                if ($return instanceof self) {\n                    return $return;\n                } else {\n                    return self::fromValue($return, $noneValue);\n                }\n            });\n        } else {\n            return self::fromValue($value, $noneValue);\n        }\n    }\n\n    /**\n     * Lift a function so that it accepts Option as parameters.\n     *\n     * We return a new closure that wraps the original callback. If any of the\n     * parameters passed to the lifted function is empty, the function will\n     * return a value of None. Otherwise, we will pass all parameters to the\n     * original callback and return the value inside a new Option, unless an\n     * Option is returned from the function, in which case, we use that.\n     *\n     * @template S\n     *\n     * @param callable $callback\n     * @param mixed    $noneValue\n     *\n     * @return callable\n     */\n    public static function lift($callback, $noneValue = null)\n    {\n        return static function () use ($callback, $noneValue) {\n            /** @var array<int, mixed> */\n            $args = func_get_args();\n\n            $reduced_args = array_reduce(\n                $args,\n                /** @param bool $status */\n                static function ($status, self $o) {\n                    return $o->isEmpty() ? true : $status;\n                },\n                false\n            );\n            // if at least one parameter is empty, return None\n            if ($reduced_args) {\n                return None::create();\n            }\n\n            $args = array_map(\n                /** @return T */\n                static function (self $o) {\n                    // it is safe to do so because the fold above checked\n                    // that all arguments are of type Some\n                    /** @var T */\n                    return $o->get();\n                },\n                $args\n            );\n\n            return self::ensure(call_user_func_array($callback, $args), $noneValue);\n        };\n    }\n\n    /**\n     * Returns the value if available, or throws an exception otherwise.\n     *\n     * @throws \\RuntimeException If value is not available.\n     *\n     * @return T\n     */\n    abstract public function get();\n\n    /**\n     * Returns the value if available, or the default value if not.\n     *\n     * @template S\n     *\n     * @param S $default\n     *\n     * @return T|S\n     */\n    abstract public function getOrElse($default);\n\n    /**\n     * Returns the value if available, or the results of the callable.\n     *\n     * This is preferable over ``getOrElse`` if the computation of the default\n     * value is expensive.\n     *\n     * @template S\n     *\n     * @param callable():S $callable\n     *\n     * @return T|S\n     */\n    abstract public function getOrCall($callable);\n\n    /**\n     * Returns the value if available, or throws the passed exception.\n     *\n     * @param \\Exception $ex\n     *\n     * @return T\n     */\n    abstract public function getOrThrow(\\Exception $ex);\n\n    /**\n     * Returns true if no value is available, false otherwise.\n     *\n     * @return bool\n     */\n    abstract public function isEmpty();\n\n    /**\n     * Returns true if a value is available, false otherwise.\n     *\n     * @return bool\n     */\n    abstract public function isDefined();\n\n    /**\n     * Returns this option if non-empty, or the passed option otherwise.\n     *\n     * This can be used to try multiple alternatives, and is especially useful\n     * with lazy evaluating options:\n     *\n     * ```php\n     *     $repo->findSomething()\n     *         ->orElse(new LazyOption(array($repo, 'findSomethingElse')))\n     *         ->orElse(new LazyOption(array($repo, 'createSomething')));\n     * ```\n     *\n     * @param Option<T> $else\n     *\n     * @return Option<T>\n     */\n    abstract public function orElse(self $else);\n\n    /**\n     * This is similar to map() below except that the return value has no meaning;\n     * the passed callable is simply executed if the option is non-empty, and\n     * ignored if the option is empty.\n     *\n     * In all cases, the return value of the callable is discarded.\n     *\n     * ```php\n     *     $comment->getMaybeFile()->ifDefined(function($file) {\n     *         // Do something with $file here.\n     *     });\n     * ```\n     *\n     * If you're looking for something like ``ifEmpty``, you can use ``getOrCall``\n     * and ``getOrElse`` in these cases.\n     *\n     * @deprecated Use forAll() instead.\n     *\n     * @param callable(T):mixed $callable\n     *\n     * @return void\n     */\n    abstract public function ifDefined($callable);\n\n    /**\n     * This is similar to map() except that the return value of the callable has no meaning.\n     *\n     * The passed callable is simply executed if the option is non-empty, and ignored if the\n     * option is empty. This method is preferred for callables with side-effects, while map()\n     * is intended for callables without side-effects.\n     *\n     * @param callable(T):mixed $callable\n     *\n     * @return Option<T>\n     */\n    abstract public function forAll($callable);\n\n    /**\n     * Applies the callable to the value of the option if it is non-empty,\n     * and returns the return value of the callable wrapped in Some().\n     *\n     * If the option is empty, then the callable is not applied.\n     *\n     * ```php\n     *     (new Some(\"foo\"))->map('strtoupper')->get(); // \"FOO\"\n     * ```\n     *\n     * @template S\n     *\n     * @param callable(T):S $callable\n     *\n     * @return Option<S>\n     */\n    abstract public function map($callable);\n\n    /**\n     * Applies the callable to the value of the option if it is non-empty, and\n     * returns the return value of the callable directly.\n     *\n     * In contrast to ``map``, the return value of the callable is expected to\n     * be an Option itself; it is not automatically wrapped in Some().\n     *\n     * @template S\n     *\n     * @param callable(T):Option<S> $callable must return an Option\n     *\n     * @return Option<S>\n     */\n    abstract public function flatMap($callable);\n\n    /**\n     * If the option is empty, it is returned immediately without applying the callable.\n     *\n     * If the option is non-empty, the callable is applied, and if it returns true,\n     * the option itself is returned; otherwise, None is returned.\n     *\n     * @param callable(T):bool $callable\n     *\n     * @return Option<T>\n     */\n    abstract public function filter($callable);\n\n    /**\n     * If the option is empty, it is returned immediately without applying the callable.\n     *\n     * If the option is non-empty, the callable is applied, and if it returns false,\n     * the option itself is returned; otherwise, None is returned.\n     *\n     * @param callable(T):bool $callable\n     *\n     * @return Option<T>\n     */\n    abstract public function filterNot($callable);\n\n    /**\n     * If the option is empty, it is returned immediately.\n     *\n     * If the option is non-empty, and its value does not equal the passed value\n     * (via a shallow comparison ===), then None is returned. Otherwise, the\n     * Option is returned.\n     *\n     * In other words, this will filter all but the passed value.\n     *\n     * @param T $value\n     *\n     * @return Option<T>\n     */\n    abstract public function select($value);\n\n    /**\n     * If the option is empty, it is returned immediately.\n     *\n     * If the option is non-empty, and its value does equal the passed value (via\n     * a shallow comparison ===), then None is returned; otherwise, the Option is\n     * returned.\n     *\n     * In other words, this will let all values through except the passed value.\n     *\n     * @param T $value\n     *\n     * @return Option<T>\n     */\n    abstract public function reject($value);\n\n    /**\n     * Binary operator for the initial value and the option's value.\n     *\n     * If empty, the initial value is returned. If non-empty, the callable\n     * receives the initial value and the option's value as arguments.\n     *\n     * ```php\n     *\n     *     $some = new Some(5);\n     *     $none = None::create();\n     *     $result = $some->foldLeft(1, function($a, $b) { return $a + $b; }); // int(6)\n     *     $result = $none->foldLeft(1, function($a, $b) { return $a + $b; }); // int(1)\n     *\n     *     // This can be used instead of something like the following:\n     *     $option = Option::fromValue($integerOrNull);\n     *     $result = 1;\n     *     if ( ! $option->isEmpty()) {\n     *         $result += $option->get();\n     *     }\n     * ```\n     *\n     * @template S\n     *\n     * @param S                $initialValue\n     * @param callable(S, T):S $callable\n     *\n     * @return S\n     */\n    abstract public function foldLeft($initialValue, $callable);\n\n    /**\n     * foldLeft() but with reversed arguments for the callable.\n     *\n     * @template S\n     *\n     * @param S                $initialValue\n     * @param callable(T, S):S $callable\n     *\n     * @return S\n     */\n    abstract public function foldRight($initialValue, $callable);\n}\n"
  },
  {
    "path": "server/vendor/phpoption/phpoption/src/PhpOption/Some.php",
    "content": "<?php\n\n/*\n * Copyright 2012 Johannes M. Schmitt <schmittjoh@gmail.com>\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\nnamespace PhpOption;\n\nuse ArrayIterator;\n\n/**\n * @template T\n *\n * @extends Option<T>\n */\nfinal class Some extends Option\n{\n    /** @var T */\n    private $value;\n\n    /**\n     * @param T $value\n     */\n    public function __construct($value)\n    {\n        $this->value = $value;\n    }\n\n    /**\n     * @template U\n     *\n     * @param U $value\n     *\n     * @return Some<U>\n     */\n    public static function create($value): self\n    {\n        return new self($value);\n    }\n\n    public function isDefined(): bool\n    {\n        return true;\n    }\n\n    public function isEmpty(): bool\n    {\n        return false;\n    }\n\n    public function get()\n    {\n        return $this->value;\n    }\n\n    public function getOrElse($default)\n    {\n        return $this->value;\n    }\n\n    public function getOrCall($callable)\n    {\n        return $this->value;\n    }\n\n    public function getOrThrow(\\Exception $ex)\n    {\n        return $this->value;\n    }\n\n    public function orElse(Option $else)\n    {\n        return $this;\n    }\n\n    public function ifDefined($callable)\n    {\n        $this->forAll($callable);\n    }\n\n    public function forAll($callable)\n    {\n        $callable($this->value);\n\n        return $this;\n    }\n\n    public function map($callable)\n    {\n        return new self($callable($this->value));\n    }\n\n    public function flatMap($callable)\n    {\n        /** @var mixed */\n        $rs = $callable($this->value);\n        if (!$rs instanceof Option) {\n            throw new \\RuntimeException('Callables passed to flatMap() must return an Option. Maybe you should use map() instead?');\n        }\n\n        return $rs;\n    }\n\n    public function filter($callable)\n    {\n        if (true === $callable($this->value)) {\n            return $this;\n        }\n\n        return None::create();\n    }\n\n    public function filterNot($callable)\n    {\n        if (false === $callable($this->value)) {\n            return $this;\n        }\n\n        return None::create();\n    }\n\n    public function select($value)\n    {\n        if ($this->value === $value) {\n            return $this;\n        }\n\n        return None::create();\n    }\n\n    public function reject($value)\n    {\n        if ($this->value === $value) {\n            return None::create();\n        }\n\n        return $this;\n    }\n\n    /**\n     * @return ArrayIterator<int, T>\n     */\n    public function getIterator(): ArrayIterator\n    {\n        return new ArrayIterator([$this->value]);\n    }\n\n    public function foldLeft($initialValue, $callable)\n    {\n        return $callable($initialValue, $this->value);\n    }\n\n    public function foldRight($initialValue, $callable)\n    {\n        return $callable($this->value, $initialValue);\n    }\n}\n"
  },
  {
    "path": "server/vendor/psr/cache/CHANGELOG.md",
    "content": "# Changelog\n\nAll notable changes to this project will be documented in this file, in reverse chronological order by release.\n\n## 1.0.1 - 2016-08-06\n\n### Fixed\n\n- Make spacing consistent in phpdoc annotations php-fig/cache#9 - chalasr\n- Fix grammar in phpdoc annotations php-fig/cache#10 - chalasr\n- Be more specific in docblocks that `getItems()` and `deleteItems()` take an array of strings (`string[]`) compared to just `array` php-fig/cache#8 - GrahamCampbell\n- For `expiresAt()` and `expiresAfter()` in CacheItemInterface fix docblock to specify null as a valid parameters as well as an implementation of DateTimeInterface php-fig/cache#7 - GrahamCampbell\n\n## 1.0.0 - 2015-12-11\n\nInitial stable release; reflects accepted PSR-6 specification\n"
  },
  {
    "path": "server/vendor/psr/cache/LICENSE.txt",
    "content": "Copyright (c) 2015 PHP Framework Interoperability Group\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "server/vendor/psr/cache/README.md",
    "content": "Caching Interface\n==============\n\nThis repository holds all interfaces related to [PSR-6 (Caching Interface)][psr-url].\n\nNote that this is not a Caching implementation of its own. It is merely interfaces that describe the components of a Caching mechanism.\n\nThe installable [package][package-url] and [implementations][implementation-url] are listed on Packagist.\n\n[psr-url]: https://www.php-fig.org/psr/psr-6/\n[package-url]: https://packagist.org/packages/psr/cache\n[implementation-url]: https://packagist.org/providers/psr/cache-implementation\n"
  },
  {
    "path": "server/vendor/psr/cache/composer.json",
    "content": "{\n    \"name\": \"psr/cache\",\n    \"description\": \"Common interface for caching libraries\",\n    \"keywords\": [\"psr\", \"psr-6\", \"cache\"],\n    \"license\": \"MIT\",\n    \"authors\": [\n        {\n            \"name\": \"PHP-FIG\",\n            \"homepage\": \"https://www.php-fig.org/\"\n        }\n    ],\n    \"require\": {\n        \"php\": \">=8.0.0\"\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"Psr\\\\Cache\\\\\": \"src/\"\n        }\n    },\n    \"extra\": {\n        \"branch-alias\": {\n            \"dev-master\": \"1.0.x-dev\"\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/psr/cache/src/CacheException.php",
    "content": "<?php\n\nnamespace Psr\\Cache;\n\n/**\n * Exception interface for all exceptions thrown by an Implementing Library.\n */\ninterface CacheException extends \\Throwable\n{\n}\n"
  },
  {
    "path": "server/vendor/psr/cache/src/CacheItemInterface.php",
    "content": "<?php\n\nnamespace Psr\\Cache;\n\n/**\n * CacheItemInterface defines an interface for interacting with objects inside a cache.\n *\n * Each Item object MUST be associated with a specific key, which can be set\n * according to the implementing system and is typically passed by the\n * Cache\\CacheItemPoolInterface object.\n *\n * The Cache\\CacheItemInterface object encapsulates the storage and retrieval of\n * cache items. Each Cache\\CacheItemInterface is generated by a\n * Cache\\CacheItemPoolInterface object, which is responsible for any required\n * setup as well as associating the object with a unique Key.\n * Cache\\CacheItemInterface objects MUST be able to store and retrieve any type\n * of PHP value defined in the Data section of the specification.\n *\n * Calling Libraries MUST NOT instantiate Item objects themselves. They may only\n * be requested from a Pool object via the getItem() method.  Calling Libraries\n * SHOULD NOT assume that an Item created by one Implementing Library is\n * compatible with a Pool from another Implementing Library.\n */\ninterface CacheItemInterface\n{\n    /**\n     * Returns the key for the current cache item.\n     *\n     * The key is loaded by the Implementing Library, but should be available to\n     * the higher level callers when needed.\n     *\n     * @return string\n     *   The key string for this cache item.\n     */\n    public function getKey(): string;\n\n    /**\n     * Retrieves the value of the item from the cache associated with this object's key.\n     *\n     * The value returned must be identical to the value originally stored by set().\n     *\n     * If isHit() returns false, this method MUST return null. Note that null\n     * is a legitimate cached value, so the isHit() method SHOULD be used to\n     * differentiate between \"null value was found\" and \"no value was found.\"\n     *\n     * @return mixed\n     *   The value corresponding to this cache item's key, or null if not found.\n     */\n    public function get(): mixed;\n\n    /**\n     * Confirms if the cache item lookup resulted in a cache hit.\n     *\n     * Note: This method MUST NOT have a race condition between calling isHit()\n     * and calling get().\n     *\n     * @return bool\n     *   True if the request resulted in a cache hit. False otherwise.\n     */\n    public function isHit(): bool;\n\n    /**\n     * Sets the value represented by this cache item.\n     *\n     * The $value argument may be any item that can be serialized by PHP,\n     * although the method of serialization is left up to the Implementing\n     * Library.\n     *\n     * @param mixed $value\n     *   The serializable value to be stored.\n     *\n     * @return static\n     *   The invoked object.\n     */\n    public function set(mixed $value): static;\n\n    /**\n     * Sets the expiration time for this cache item.\n     *\n     * @param ?\\DateTimeInterface $expiration\n     *   The point in time after which the item MUST be considered expired.\n     *   If null is passed explicitly, a default value MAY be used. If none is set,\n     *   the value should be stored permanently or for as long as the\n     *   implementation allows.\n     *\n     * @return static\n     *   The called object.\n     */\n    public function expiresAt(?\\DateTimeInterface $expiration): static;\n\n    /**\n     * Sets the expiration time for this cache item.\n     *\n     * @param int|\\DateInterval|null $time\n     *   The period of time from the present after which the item MUST be considered\n     *   expired. An integer parameter is understood to be the time in seconds until\n     *   expiration. If null is passed explicitly, a default value MAY be used.\n     *   If none is set, the value should be stored permanently or for as long as the\n     *   implementation allows.\n     *\n     * @return static\n     *   The called object.\n     */\n    public function expiresAfter(int|\\DateInterval|null $time): static;\n}\n"
  },
  {
    "path": "server/vendor/psr/cache/src/CacheItemPoolInterface.php",
    "content": "<?php\n\nnamespace Psr\\Cache;\n\n/**\n * CacheItemPoolInterface generates CacheItemInterface objects.\n *\n * The primary purpose of Cache\\CacheItemPoolInterface is to accept a key from\n * the Calling Library and return the associated Cache\\CacheItemInterface object.\n * It is also the primary point of interaction with the entire cache collection.\n * All configuration and initialization of the Pool is left up to an\n * Implementing Library.\n */\ninterface CacheItemPoolInterface\n{\n    /**\n     * Returns a Cache Item representing the specified key.\n     *\n     * This method must always return a CacheItemInterface object, even in case of\n     * a cache miss. It MUST NOT return null.\n     *\n     * @param string $key\n     *   The key for which to return the corresponding Cache Item.\n     *\n     * @throws InvalidArgumentException\n     *   If the $key string is not a legal value a \\Psr\\Cache\\InvalidArgumentException\n     *   MUST be thrown.\n     *\n     * @return CacheItemInterface\n     *   The corresponding Cache Item.\n     */\n    public function getItem(string $key): CacheItemInterface;\n\n    /**\n     * Returns a traversable set of cache items.\n     *\n     * @param string[] $keys\n     *   An indexed array of keys of items to retrieve.\n     *\n     * @throws InvalidArgumentException\n     *   If any of the keys in $keys are not a legal value a \\Psr\\Cache\\InvalidArgumentException\n     *   MUST be thrown.\n     *\n     * @return iterable\n     *   An iterable collection of Cache Items keyed by the cache keys of\n     *   each item. A Cache item will be returned for each key, even if that\n     *   key is not found. However, if no keys are specified then an empty\n     *   traversable MUST be returned instead.\n     */\n    public function getItems(array $keys = []): iterable;\n\n    /**\n     * Confirms if the cache contains specified cache item.\n     *\n     * Note: This method MAY avoid retrieving the cached value for performance reasons.\n     * This could result in a race condition with CacheItemInterface::get(). To avoid\n     * such situation use CacheItemInterface::isHit() instead.\n     *\n     * @param string $key\n     *   The key for which to check existence.\n     *\n     * @throws InvalidArgumentException\n     *   If the $key string is not a legal value a \\Psr\\Cache\\InvalidArgumentException\n     *   MUST be thrown.\n     *\n     * @return bool\n     *   True if item exists in the cache, false otherwise.\n     */\n    public function hasItem(string $key): bool;\n\n    /**\n     * Deletes all items in the pool.\n     *\n     * @return bool\n     *   True if the pool was successfully cleared. False if there was an error.\n     */\n    public function clear(): bool;\n\n    /**\n     * Removes the item from the pool.\n     *\n     * @param string $key\n     *   The key to delete.\n     *\n     * @throws InvalidArgumentException\n     *   If the $key string is not a legal value a \\Psr\\Cache\\InvalidArgumentException\n     *   MUST be thrown.\n     *\n     * @return bool\n     *   True if the item was successfully removed. False if there was an error.\n     */\n    public function deleteItem(string $key): bool;\n\n    /**\n     * Removes multiple items from the pool.\n     *\n     * @param string[] $keys\n     *   An array of keys that should be removed from the pool.\n     *\n     * @throws InvalidArgumentException\n     *   If any of the keys in $keys are not a legal value a \\Psr\\Cache\\InvalidArgumentException\n     *   MUST be thrown.\n     *\n     * @return bool\n     *   True if the items were successfully removed. False if there was an error.\n     */\n    public function deleteItems(array $keys): bool;\n\n    /**\n     * Persists a cache item immediately.\n     *\n     * @param CacheItemInterface $item\n     *   The cache item to save.\n     *\n     * @return bool\n     *   True if the item was successfully persisted. False if there was an error.\n     */\n    public function save(CacheItemInterface $item): bool;\n\n    /**\n     * Sets a cache item to be persisted later.\n     *\n     * @param CacheItemInterface $item\n     *   The cache item to save.\n     *\n     * @return bool\n     *   False if the item could not be queued or if a commit was attempted and failed. True otherwise.\n     */\n    public function saveDeferred(CacheItemInterface $item): bool;\n\n    /**\n     * Persists any deferred cache items.\n     *\n     * @return bool\n     *   True if all not-yet-saved items were successfully saved or there were none. False otherwise.\n     */\n    public function commit(): bool;\n}\n"
  },
  {
    "path": "server/vendor/psr/cache/src/InvalidArgumentException.php",
    "content": "<?php\n\nnamespace Psr\\Cache;\n\n/**\n * Exception interface for invalid cache arguments.\n *\n * Any time an invalid argument is passed into a method it must throw an\n * exception class which implements Psr\\Cache\\InvalidArgumentException.\n */\ninterface InvalidArgumentException extends CacheException\n{\n}\n"
  },
  {
    "path": "server/vendor/psr/clock/CHANGELOG.md",
    "content": "# Changelog\n\nAll notable changes to this project will be documented in this file, in reverse chronological order by release.\n\n## 1.0.0\n\nFirst stable release after PSR-20 acceptance\n\n## 0.1.0\n\nFirst release\n"
  },
  {
    "path": "server/vendor/psr/clock/LICENSE",
    "content": "Copyright (c) 2017 PHP Framework Interoperability Group\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "server/vendor/psr/clock/README.md",
    "content": "# PSR Clock\n\nThis repository holds the interface for [PSR-20][psr-url].\n\nNote that this is not a clock of its own. It is merely an interface that\ndescribes a clock. See the specification for more details.\n\n## Installation\n\n```bash\ncomposer require psr/clock\n```\n\n## Usage\n\nIf you need a clock, you can use the interface like this:\n\n```php\n<?php\n\nuse Psr\\Clock\\ClockInterface;\n\nclass Foo\n{\n    private ClockInterface $clock;\n\n    public function __construct(ClockInterface $clock)\n    {\n        $this->clock = $clock;\n    }\n\n    public function doSomething()\n    {\n        /** @var DateTimeImmutable $currentDateAndTime */\n        $currentDateAndTime = $this->clock->now();\n        // do something useful with that information\n    }\n}\n```\n\nYou can then pick one of the [implementations][implementation-url] of the interface to get a clock.\n\nIf you want to implement the interface, you can require this package and\nimplement `Psr\\Clock\\ClockInterface` in your code. \n\nDon't forget to add `psr/clock-implementation` to your `composer.json`s `provides`-section like this:\n\n```json\n{\n  \"provides\": {\n    \"psr/clock-implementation\": \"1.0\"\n  }\n}\n```\n\nAnd please read the [specification text][specification-url] for details on the interface.\n\n[psr-url]: https://www.php-fig.org/psr/psr-20\n[package-url]: https://packagist.org/packages/psr/clock\n[implementation-url]: https://packagist.org/providers/psr/clock-implementation\n[specification-url]: https://github.com/php-fig/fig-standards/blob/master/proposed/clock.md\n"
  },
  {
    "path": "server/vendor/psr/clock/composer.json",
    "content": "{\n  \"name\": \"psr/clock\",\n  \"description\": \"Common interface for reading the clock.\",\n  \"keywords\": [\"psr\", \"psr-20\", \"time\", \"clock\", \"now\"],\n  \"homepage\": \"https://github.com/php-fig/clock\",\n  \"license\": \"MIT\",\n  \"authors\": [\n    {\n      \"name\": \"PHP-FIG\",\n      \"homepage\": \"https://www.php-fig.org/\"\n    }\n  ],\n  \"require\": {\n    \"php\": \"^7.0 || ^8.0\"\n  },\n  \"autoload\": {\n    \"psr-4\": {\n      \"Psr\\\\Clock\\\\\": \"src/\"\n    }\n  }\n}\n"
  },
  {
    "path": "server/vendor/psr/clock/src/ClockInterface.php",
    "content": "<?php\n\nnamespace Psr\\Clock;\n\nuse DateTimeImmutable;\n\ninterface ClockInterface\n{\n    /**\n     * Returns the current time as a DateTimeImmutable Object\n     */\n    public function now(): DateTimeImmutable;\n}\n"
  },
  {
    "path": "server/vendor/psr/container/.gitignore",
    "content": "composer.lock\ncomposer.phar\n/vendor/\n"
  },
  {
    "path": "server/vendor/psr/container/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2013-2016 container-interop\nCopyright (c) 2016 PHP Framework Interoperability Group\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "server/vendor/psr/container/README.md",
    "content": "Container interface\n==============\n\nThis repository holds all interfaces related to [PSR-11 (Container Interface)][psr-url].\n\nNote that this is not a Container implementation of its own. It is merely abstractions that describe the components of a Dependency Injection Container.\n\nThe installable [package][package-url] and [implementations][implementation-url] are listed on Packagist.\n\n[psr-url]: https://www.php-fig.org/psr/psr-11/\n[package-url]: https://packagist.org/packages/psr/container\n[implementation-url]: https://packagist.org/providers/psr/container-implementation\n\n"
  },
  {
    "path": "server/vendor/psr/container/composer.json",
    "content": "{\n    \"name\": \"psr/container\",\n    \"type\": \"library\",\n    \"description\": \"Common Container Interface (PHP FIG PSR-11)\",\n    \"keywords\": [\"psr\", \"psr-11\", \"container\", \"container-interop\", \"container-interface\"],\n    \"homepage\": \"https://github.com/php-fig/container\",\n    \"license\": \"MIT\",\n    \"authors\": [\n        {\n            \"name\": \"PHP-FIG\",\n            \"homepage\": \"https://www.php-fig.org/\"\n        }\n    ],\n    \"require\": {\n        \"php\": \">=7.4.0\"\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"Psr\\\\Container\\\\\": \"src/\"\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/psr/container/src/ContainerExceptionInterface.php",
    "content": "<?php\n\nnamespace Psr\\Container;\n\nuse Throwable;\n\n/**\n * Base interface representing a generic exception in a container.\n */\ninterface ContainerExceptionInterface extends Throwable\n{\n}\n"
  },
  {
    "path": "server/vendor/psr/container/src/ContainerInterface.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Psr\\Container;\n\n/**\n * Describes the interface of a container that exposes methods to read its entries.\n */\ninterface ContainerInterface\n{\n    /**\n     * Finds an entry of the container by its identifier and returns it.\n     *\n     * @param string $id Identifier of the entry to look for.\n     *\n     * @throws NotFoundExceptionInterface  No entry was found for **this** identifier.\n     * @throws ContainerExceptionInterface Error while retrieving the entry.\n     *\n     * @return mixed Entry.\n     */\n    public function get(string $id);\n\n    /**\n     * Returns true if the container can return an entry for the given identifier.\n     * Returns false otherwise.\n     *\n     * `has($id)` returning true does not mean that `get($id)` will not throw an exception.\n     * It does however mean that `get($id)` will not throw a `NotFoundExceptionInterface`.\n     *\n     * @param string $id Identifier of the entry to look for.\n     *\n     * @return bool\n     */\n    public function has(string $id);\n}\n"
  },
  {
    "path": "server/vendor/psr/container/src/NotFoundExceptionInterface.php",
    "content": "<?php\n\nnamespace Psr\\Container;\n\n/**\n * No entry was found in the container.\n */\ninterface NotFoundExceptionInterface extends ContainerExceptionInterface\n{\n}\n"
  },
  {
    "path": "server/vendor/psr/http-factory/LICENSE",
    "content": "MIT License\n\nCopyright (c) 2018 PHP-FIG\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "server/vendor/psr/http-factory/README.md",
    "content": "HTTP Factories\n==============\n\nThis repository holds all interfaces related to [PSR-17 (HTTP Factories)][psr-url].\n\nNote that this is not a HTTP Factory implementation of its own. It is merely interfaces that describe the components of a HTTP Factory.\n\nThe installable [package][package-url] and [implementations][implementation-url] are listed on Packagist.\n\n[psr-url]: https://www.php-fig.org/psr/psr-17/\n[package-url]: https://packagist.org/packages/psr/http-factory\n[implementation-url]: https://packagist.org/providers/psr/http-factory-implementation\n"
  },
  {
    "path": "server/vendor/psr/http-factory/composer.json",
    "content": "{\n    \"name\": \"psr/http-factory\",\n    \"description\": \"Common interfaces for PSR-7 HTTP message factories\",\n    \"keywords\": [\n        \"psr\",\n        \"psr-7\",\n        \"psr-17\",\n        \"http\",\n        \"factory\",\n        \"message\",\n        \"request\",\n        \"response\"\n    ],\n    \"license\": \"MIT\",\n    \"authors\": [\n        {\n            \"name\": \"PHP-FIG\",\n            \"homepage\": \"https://www.php-fig.org/\"\n        }\n    ],\n    \"require\": {\n        \"php\": \">=7.0.0\",\n        \"psr/http-message\": \"^1.0 || ^2.0\"\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"Psr\\\\Http\\\\Message\\\\\": \"src/\"\n        }\n    },\n    \"extra\": {\n        \"branch-alias\": {\n            \"dev-master\": \"1.0.x-dev\"\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/psr/http-factory/src/RequestFactoryInterface.php",
    "content": "<?php\n\nnamespace Psr\\Http\\Message;\n\ninterface RequestFactoryInterface\n{\n    /**\n     * Create a new request.\n     *\n     * @param string $method The HTTP method associated with the request.\n     * @param UriInterface|string $uri The URI associated with the request. If\n     *     the value is a string, the factory MUST create a UriInterface\n     *     instance based on it.\n     *\n     * @return RequestInterface\n     */\n    public function createRequest(string $method, $uri): RequestInterface;\n}\n"
  },
  {
    "path": "server/vendor/psr/http-factory/src/ResponseFactoryInterface.php",
    "content": "<?php\n\nnamespace Psr\\Http\\Message;\n\ninterface ResponseFactoryInterface\n{\n    /**\n     * Create a new response.\n     *\n     * @param int $code HTTP status code; defaults to 200\n     * @param string $reasonPhrase Reason phrase to associate with status code\n     *     in generated response; if none is provided implementations MAY use\n     *     the defaults as suggested in the HTTP specification.\n     *\n     * @return ResponseInterface\n     */\n    public function createResponse(int $code = 200, string $reasonPhrase = ''): ResponseInterface;\n}\n"
  },
  {
    "path": "server/vendor/psr/http-factory/src/ServerRequestFactoryInterface.php",
    "content": "<?php\n\nnamespace Psr\\Http\\Message;\n\ninterface ServerRequestFactoryInterface\n{\n    /**\n     * Create a new server request.\n     *\n     * Note that server-params are taken precisely as given - no parsing/processing\n     * of the given values is performed, and, in particular, no attempt is made to\n     * determine the HTTP method or URI, which must be provided explicitly.\n     *\n     * @param string $method The HTTP method associated with the request.\n     * @param UriInterface|string $uri The URI associated with the request. If\n     *     the value is a string, the factory MUST create a UriInterface\n     *     instance based on it.\n     * @param array $serverParams Array of SAPI parameters with which to seed\n     *     the generated request instance.\n     *\n     * @return ServerRequestInterface\n     */\n    public function createServerRequest(string $method, $uri, array $serverParams = []): ServerRequestInterface;\n}\n"
  },
  {
    "path": "server/vendor/psr/http-factory/src/StreamFactoryInterface.php",
    "content": "<?php\n\nnamespace Psr\\Http\\Message;\n\ninterface StreamFactoryInterface\n{\n    /**\n     * Create a new stream from a string.\n     *\n     * The stream SHOULD be created with a temporary resource.\n     *\n     * @param string $content String content with which to populate the stream.\n     *\n     * @return StreamInterface\n     */\n    public function createStream(string $content = ''): StreamInterface;\n\n    /**\n     * Create a stream from an existing file.\n     *\n     * The file MUST be opened using the given mode, which may be any mode\n     * supported by the `fopen` function.\n     *\n     * The `$filename` MAY be any string supported by `fopen()`.\n     *\n     * @param string $filename Filename or stream URI to use as basis of stream.\n     * @param string $mode Mode with which to open the underlying filename/stream.\n     *\n     * @return StreamInterface\n     * @throws \\RuntimeException If the file cannot be opened.\n     * @throws \\InvalidArgumentException If the mode is invalid.\n     */\n    public function createStreamFromFile(string $filename, string $mode = 'r'): StreamInterface;\n\n    /**\n     * Create a new stream from an existing resource.\n     *\n     * The stream MUST be readable and may be writable.\n     *\n     * @param resource $resource PHP resource to use as basis of stream.\n     *\n     * @return StreamInterface\n     */\n    public function createStreamFromResource($resource): StreamInterface;\n}\n"
  },
  {
    "path": "server/vendor/psr/http-factory/src/UploadedFileFactoryInterface.php",
    "content": "<?php\n\nnamespace Psr\\Http\\Message;\n\ninterface UploadedFileFactoryInterface\n{\n    /**\n     * Create a new uploaded file.\n     *\n     * If a size is not provided it will be determined by checking the size of\n     * the file.\n     *\n     * @see http://php.net/manual/features.file-upload.post-method.php\n     * @see http://php.net/manual/features.file-upload.errors.php\n     *\n     * @param StreamInterface $stream Underlying stream representing the\n     *     uploaded file content.\n     * @param int $size in bytes\n     * @param int $error PHP file upload error\n     * @param string $clientFilename Filename as provided by the client, if any.\n     * @param string $clientMediaType Media type as provided by the client, if any.\n     *\n     * @return UploadedFileInterface\n     *\n     * @throws \\InvalidArgumentException If the file resource is not readable.\n     */\n    public function createUploadedFile(\n        StreamInterface $stream,\n        int $size = null,\n        int $error = \\UPLOAD_ERR_OK,\n        string $clientFilename = null,\n        string $clientMediaType = null\n    ): UploadedFileInterface;\n}\n"
  },
  {
    "path": "server/vendor/psr/http-factory/src/UriFactoryInterface.php",
    "content": "<?php\n\nnamespace Psr\\Http\\Message;\n\ninterface UriFactoryInterface\n{\n    /**\n     * Create a new URI.\n     *\n     * @param string $uri\n     *\n     * @return UriInterface\n     *\n     * @throws \\InvalidArgumentException If the given URI cannot be parsed.\n     */\n    public function createUri(string $uri = ''): UriInterface;\n}\n"
  },
  {
    "path": "server/vendor/psr/http-message/CHANGELOG.md",
    "content": "# Changelog\n\nAll notable changes to this project will be documented in this file, in reverse chronological order by release.\n\n## 1.0.1 - 2016-08-06\n\n### Added\n\n- Nothing.\n\n### Deprecated\n\n- Nothing.\n\n### Removed\n\n- Nothing.\n\n### Fixed\n\n- Updated all `@return self` annotation references in interfaces to use\n  `@return static`, which more closelly follows the semantics of the\n  specification.\n- Updated the `MessageInterface::getHeaders()` return annotation to use the\n  value `string[][]`, indicating the format is a nested array of strings.\n- Updated the `@link` annotation for `RequestInterface::withRequestTarget()`\n  to point to the correct section of RFC 7230.\n- Updated the `ServerRequestInterface::withUploadedFiles()` parameter annotation\n  to add the parameter name (`$uploadedFiles`).\n- Updated a `@throws` annotation for the `UploadedFileInterface::moveTo()`\n  method to correctly reference the method parameter (it was referencing an\n  incorrect parameter name previously).\n\n## 1.0.0 - 2016-05-18\n\nInitial stable release; reflects accepted PSR-7 specification.\n"
  },
  {
    "path": "server/vendor/psr/http-message/LICENSE",
    "content": "Copyright (c) 2014 PHP Framework Interoperability Group\n\nPermission is hereby granted, free of charge, to any person obtaining a copy \nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights \nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell \ncopies of the Software, and to permit persons to whom the Software is \nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in \nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "server/vendor/psr/http-message/README.md",
    "content": "PSR Http Message\n================\n\nThis repository holds all interfaces/classes/traits related to\n[PSR-7](http://www.php-fig.org/psr/psr-7/).\n\nNote that this is not a HTTP message implementation of its own. It is merely an\ninterface that describes a HTTP message. See the specification for more details.\n\nUsage\n-----\n\nBefore reading the usage guide we recommend reading the PSR-7 interfaces method list:\n\n* [`PSR-7 Interfaces Method List`](docs/PSR7-Interfaces.md)\n* [`PSR-7 Usage Guide`](docs/PSR7-Usage.md)"
  },
  {
    "path": "server/vendor/psr/http-message/composer.json",
    "content": "{\n    \"name\": \"psr/http-message\",\n    \"description\": \"Common interface for HTTP messages\",\n    \"keywords\": [\"psr\", \"psr-7\", \"http\", \"http-message\", \"request\", \"response\"],\n    \"homepage\": \"https://github.com/php-fig/http-message\",\n    \"license\": \"MIT\",\n    \"authors\": [\n        {\n            \"name\": \"PHP-FIG\",\n            \"homepage\": \"http://www.php-fig.org/\"\n        }\n    ],\n    \"require\": {\n        \"php\": \"^7.2 || ^8.0\"\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"Psr\\\\Http\\\\Message\\\\\": \"src/\"\n        }\n    },\n    \"extra\": {\n        \"branch-alias\": {\n            \"dev-master\": \"1.1.x-dev\"\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/psr/http-message/docs/PSR7-Interfaces.md",
    "content": "# Interfaces\n\nThe purpose of this list is to help in finding the methods when working with PSR-7. This can be considered as a cheatsheet for PSR-7 interfaces.\n\nThe interfaces defined in PSR-7 are the following:\n\n| Class Name | Description |\n|---|---|\n| [Psr\\Http\\Message\\MessageInterface](http://www.php-fig.org/psr/psr-7/#psrhttpmessagemessageinterface) | Representation of a HTTP message |\n| [Psr\\Http\\Message\\RequestInterface](http://www.php-fig.org/psr/psr-7/#psrhttpmessagerequestinterface) | Representation of an outgoing, client-side request. |\n| [Psr\\Http\\Message\\ServerRequestInterface](http://www.php-fig.org/psr/psr-7/#psrhttpmessageserverrequestinterface) | Representation of an incoming, server-side HTTP request. | \n| [Psr\\Http\\Message\\ResponseInterface](http://www.php-fig.org/psr/psr-7/#psrhttpmessageresponseinterface) | Representation of an outgoing, server-side response. |\n| [Psr\\Http\\Message\\StreamInterface](http://www.php-fig.org/psr/psr-7/#psrhttpmessagestreaminterface) | Describes a data stream |\n| [Psr\\Http\\Message\\UriInterface](http://www.php-fig.org/psr/psr-7/#psrhttpmessageuriinterface) | Value object representing a URI. |\n| [Psr\\Http\\Message\\UploadedFileInterface](http://www.php-fig.org/psr/psr-7/#psrhttpmessageuploadedfileinterface) | Value object representing a file uploaded through an HTTP request. |\n\n## `Psr\\Http\\Message\\MessageInterface` Methods\n\n| Method Name                        | Description | Notes |\n|------------------------------------| ----------- | ----- |\n| `getProtocolVersion()`             | Retrieve HTTP protocol version          |  1.0 or 1.1 |\n| `withProtocolVersion($version)`    | Returns new message instance with given HTTP protocol version          |      |\n| `getHeaders()`                     | Retrieve all HTTP Headers               | [Request Header List](https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Request_fields), [Response Header List](https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Response_fields)      |\n| `hasHeader($name)`                 | Checks if HTTP Header with given name exists  | |\n| `getHeader($name)`                 | Retrieves a array with the values for a single header | |\n| `getHeaderLine($name)`             | Retrieves a comma-separated string of the values for a single header |  |\n| `withHeader($name, $value)`        | Returns new message instance with given HTTP Header | if the header existed in the original instance, replaces the header value from the original message with the value provided when creating the new instance. |\n| `withAddedHeader($name, $value)`   | Returns new message instance with appended value to given header | If header already exists value will be appended, if not a new header will be created |\n| `withoutHeader($name)`             | Removes HTTP Header with given name| |\n| `getBody()`                        | Retrieves the HTTP Message Body | Returns object implementing `StreamInterface`|\n| `withBody(StreamInterface $body)`  | Returns new message instance with given HTTP Message Body | |\n\n\n## `Psr\\Http\\Message\\RequestInterface` Methods\n\nSame methods as `Psr\\Http\\Message\\MessageInterface`  + the following methods:\n\n| Method Name                        | Description | Notes |\n|------------------------------------| ----------- | ----- |\n| `getRequestTarget()`                | Retrieves the message's request target              | origin-form, absolute-form, authority-form, asterisk-form ([RFC7230](https://www.rfc-editor.org/rfc/rfc7230.txt)) |\n| `withRequestTarget($requestTarget)` | Return a new message instance with the specific request-target |      |\n| `getMethod()`                       | Retrieves the HTTP method of the request.  |  GET, HEAD, POST, PUT, DELETE, CONNECT, OPTIONS, TRACE (defined in [RFC7231](https://tools.ietf.org/html/rfc7231)), PATCH (defined in [RFC5789](https://tools.ietf.org/html/rfc5789)) |\n| `withMethod($method)`               | Returns a new message instance with the provided HTTP method  | |\n| `getUri()`                 | Retrieves the URI instance | |\n| `withUri(UriInterface $uri, $preserveHost = false)` | Returns a new message instance with the provided URI |  |\n\n\n## `Psr\\Http\\Message\\ServerRequestInterface` Methods\n\nSame methods as `Psr\\Http\\Message\\RequestInterface`  + the following methods:\n\n| Method Name                        | Description | Notes |\n|------------------------------------| ----------- | ----- |\n| `getServerParams() `               | Retrieve server parameters  | Typically derived from `$_SERVER`  |\n| `getCookieParams()`                | Retrieves cookies sent by the client to the server. | Typically derived from `$_COOKIES` |\n| `withCookieParams(array $cookies)` |  Returns a new request instance with the specified cookies      |   | \n| `withQueryParams(array $query)` | Returns a new request instance with the specified query string arguments  |  |\n| `getUploadedFiles()` | Retrieve normalized file upload data  |  |\n| `withUploadedFiles(array $uploadedFiles)` | Returns a new request instance with the specified uploaded files  |  |\n| `getParsedBody()` | Retrieve any parameters provided in the request body  |  |\n| `withParsedBody($data)` | Returns a new request instance with the specified body parameters  |  |\n| `getAttributes()` | Retrieve attributes derived from the request  |  |\n| `getAttribute($name, $default = null)` | Retrieve a single derived request attribute  |  |\n| `withAttribute($name, $value)` | Returns a new request instance with the specified derived request attribute  |  |\n| `withoutAttribute($name)` | Returns a new request instance that without the specified derived request attribute  |  |\n\n## `Psr\\Http\\Message\\ResponseInterface` Methods:\n\nSame methods as `Psr\\Http\\Message\\MessageInterface`  + the following methods:\n\n| Method Name                        | Description | Notes |\n|------------------------------------| ----------- | ----- |\n| `getStatusCode()` | Gets the response status code. | |\n| `withStatus($code, $reasonPhrase = '')` | Returns a new response instance with the specified status code and, optionally, reason phrase. | |\n| `getReasonPhrase()` | Gets the response reason phrase associated with the status code. | |\n\n##  `Psr\\Http\\Message\\StreamInterface` Methods\n\n| Method Name                        | Description | Notes |\n|------------------------------------| ----------- | ----- |\n| `__toString()` | Reads all data from the stream into a string, from the beginning to end. | |\n| `close()` | Closes the stream and any underlying resources. | |\n| `detach()` | Separates any underlying resources from the stream. | |\n| `getSize()` | Get the size of the stream if known. | |\n| `eof()` | Returns true if the stream is at the end of the stream.| |\n| `isSeekable()` |  Returns whether or not the stream is seekable. | |\n| `seek($offset, $whence = SEEK_SET)` | Seek to a position in the stream. | |\n| `rewind()` | Seek to the beginning of the stream. | |\n| `isWritable()` | Returns whether or not the stream is writable. | |\n| `write($string)` | Write data to the stream. | |\n| `isReadable()` | Returns whether or not the stream is readable. | |\n| `read($length)` | Read data from the stream. | |\n| `getContents()` | Returns the remaining contents in a string | |\n| `getMetadata($key = null)()` | Get stream metadata as an associative array or retrieve a specific key. | |\n\n## `Psr\\Http\\Message\\UriInterface` Methods\n\n| Method Name                        | Description | Notes |\n|------------------------------------| ----------- | ----- |\n| `getScheme()` | Retrieve the scheme component of the URI. | |\n| `getAuthority()` | Retrieve the authority component of the URI. | |\n| `getUserInfo()` | Retrieve the user information component of the URI. | |\n| `getHost()` | Retrieve the host component of the URI. | |\n| `getPort()` | Retrieve the port component of the URI. | |\n| `getPath()` | Retrieve the path component of the URI. | |\n| `getQuery()` | Retrieve the query string of the URI. | |\n| `getFragment()` | Retrieve the fragment component of the URI. | |\n| `withScheme($scheme)` | Return an instance with the specified scheme. | |\n| `withUserInfo($user, $password = null)` | Return an instance with the specified user information. | |\n| `withHost($host)` | Return an instance with the specified host. | |\n| `withPort($port)` | Return an instance with the specified port. | |\n| `withPath($path)` | Return an instance with the specified path. | |\n| `withQuery($query)` | Return an instance with the specified query string. | |\n| `withFragment($fragment)` | Return an instance with the specified URI fragment. | |\n| `__toString()` | Return the string representation as a URI reference. | |\n\n## `Psr\\Http\\Message\\UploadedFileInterface` Methods\n\n| Method Name                        | Description | Notes |\n|------------------------------------| ----------- | ----- |\n| `getStream()` | Retrieve a stream representing the uploaded file. | |\n| `moveTo($targetPath)` | Move the uploaded file to a new location. | |\n| `getSize()` | Retrieve the file size. | |\n| `getError()` | Retrieve the error associated with the uploaded file. | |\n| `getClientFilename()` | Retrieve the filename sent by the client. | |\n| `getClientMediaType()` | Retrieve the media type sent by the client. | |\n\n> `RequestInterface`, `ServerRequestInterface`, `ResponseInterface` extend `MessageInterface`  because the `Request` and the `Response` are `HTTP Messages`.\n> When using `ServerRequestInterface`, both `RequestInterface` and `Psr\\Http\\Message\\MessageInterface` methods are considered.\n\n"
  },
  {
    "path": "server/vendor/psr/http-message/docs/PSR7-Usage.md",
    "content": "### PSR-7 Usage\n\nAll PSR-7 applications comply with these interfaces \nThey were created to establish a standard between middleware implementations.\n\n> `RequestInterface`, `ServerRequestInterface`, `ResponseInterface` extend `MessageInterface`  because the `Request` and the `Response` are `HTTP Messages`.\n> When using `ServerRequestInterface`, both `RequestInterface` and `Psr\\Http\\Message\\MessageInterface` methods are considered.\n\n\nThe following examples will illustrate how basic operations are done in PSR-7.\n\n##### Examples\n\n\nFor this examples to work (at least) a PSR-7 implementation package is required. (eg: zendframework/zend-diactoros, guzzlehttp/psr7, slim/slim, etc)\nAll PSR-7 implementations should have the same behaviour.\n\nThe following will be assumed: \n`$request` is an object of `Psr\\Http\\Message\\RequestInterface` and\n\n`$response` is an object implementing `Psr\\Http\\Message\\RequestInterface`\n\n\n### Working with HTTP Headers\n\n#### Adding headers to response:\n\n```php\n$response->withHeader('My-Custom-Header', 'My Custom Message');\n```\n\n#### Appending values to headers\n\n```php\n$response->withAddedHeader('My-Custom-Header', 'The second message');\n```\n\n#### Checking if header exists:\n\n```php\n$request->hasHeader('My-Custom-Header'); // will return false\n$response->hasHeader('My-Custom-Header'); // will return true\n```\n\n> Note: My-Custom-Header was only added in the Response\n\n#### Getting comma-separated values from a header (also applies to request)\n\n```php\n// getting value from request headers\n$request->getHeaderLine('Content-Type'); // will return: \"text/html; charset=UTF-8\"\n// getting value from response headers\n$response->getHeaderLine('My-Custom-Header'); // will return:  \"My Custom Message; The second message\"\n```\n\n#### Getting array of value from a header (also applies to request)\n```php\n// getting value from request headers\n$request->getHeader('Content-Type'); // will return: [\"text/html\", \"charset=UTF-8\"]\n// getting value from response headers\n$response->getHeader('My-Custom-Header'); // will return:  [\"My Custom Message\",  \"The second message\"]\n```\n\n#### Removing headers from HTTP Messages\n```php\n// removing a header from Request, removing deprecated \"Content-MD5\" header\n$request->withoutHeader('Content-MD5'); \n\n// removing a header from Response\n// effect: the browser won't know the size of the stream\n// the browser will download the stream till it ends\n$response->withoutHeader('Content-Length');\n```\n\n### Working with HTTP Message Body\n\nWhen working with the PSR-7 there are two methods of implementation:\n#### 1. Getting the body separately\n\n> This method makes the body handling easier to understand and is useful when repeatedly calling body methods. (You only call `getBody()` once). Using this method mistakes like `$response->write()` are also prevented.\n\n```php\n$body = $response->getBody();\n// operations on body, eg. read, write, seek\n// ...\n// replacing the old body\n$response->withBody($body); \n// this last statement is optional as we working with objects\n// in this case the \"new\" body is same with the \"old\" one\n// the $body variable has the same value as the one in $request, only the reference is passed\n```\n\n#### 2. Working directly on response\n\n> This method is useful when only performing few operations as the `$request->getBody()` statement fragment is required\n\n```php\n$response->getBody()->write('hello');\n```\n\n### Getting the body contents\n\nThe following snippet gets the contents of a stream contents.\n> Note: Streams must be rewinded, if content was written into streams, it will be ignored when calling `getContents()` because the stream pointer is set to the last character, which is `\\0` - meaning end of stream.\n```php \n$body = $response->getBody();\n$body->rewind(); // or $body->seek(0);\n$bodyText = $body->getContents();\n```\n> Note: If `$body->seek(1)` is called before `$body->getContents()`, the first character will be ommited as the starting pointer is set to `1`, not `0`. This is why using `$body->rewind()` is recommended.\n\n### Append to body\n\n```php\n$response->getBody()->write('Hello'); // writing directly\n$body = $request->getBody(); // which is a `StreamInterface`\n$body->write('xxxxx');\n```\n\n### Prepend to body\nPrepending is different when it comes to streams. The content must be copied before writing the content to be prepended.\nThe following example will explain the behaviour of streams.\n\n```php\n// assuming our response is initially empty\n$body = $repsonse->getBody();\n// writing the string \"abcd\"\n$body->write('abcd');\n\n// seeking to start of stream\n$body->seek(0);\n// writing 'ef'\n$body->write('ef'); // at this point the stream contains \"efcd\"\n```\n\n#### Prepending by rewriting separately\n\n```php\n// assuming our response body stream only contains: \"abcd\"\n$body = $response->getBody();\n$body->rewind();\n$contents = $body->getContents(); // abcd\n// seeking the stream to beginning\n$body->rewind();\n$body->write('ef'); // stream contains \"efcd\"\n$body->write($contents); // stream contains \"efabcd\"\n```\n\n> Note: `getContents()` seeks the stream while reading it, therefore if the second `rewind()` method call was not present the stream would have resulted in `abcdefabcd` because the `write()` method appends to stream if not preceeded by `rewind()` or `seek(0)`.\n\n#### Prepending by using contents as a string\n```php\n$body = $response->getBody();\n$body->rewind();\n$contents = $body->getContents(); // efabcd\n$contents = 'ef'.$contents;\n$body->rewind();\n$body->write($contents);\n```\n"
  },
  {
    "path": "server/vendor/psr/http-message/src/MessageInterface.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Psr\\Http\\Message;\n\n/**\n * HTTP messages consist of requests from a client to a server and responses\n * from a server to a client. This interface defines the methods common to\n * each.\n *\n * Messages are considered immutable; all methods that might change state MUST\n * be implemented such that they retain the internal state of the current\n * message and return an instance that contains the changed state.\n *\n * @link http://www.ietf.org/rfc/rfc7230.txt\n * @link http://www.ietf.org/rfc/rfc7231.txt\n */\ninterface MessageInterface\n{\n    /**\n     * Retrieves the HTTP protocol version as a string.\n     *\n     * The string MUST contain only the HTTP version number (e.g., \"1.1\", \"1.0\").\n     *\n     * @return string HTTP protocol version.\n     */\n    public function getProtocolVersion();\n\n    /**\n     * Return an instance with the specified HTTP protocol version.\n     *\n     * The version string MUST contain only the HTTP version number (e.g.,\n     * \"1.1\", \"1.0\").\n     *\n     * This method MUST be implemented in such a way as to retain the\n     * immutability of the message, and MUST return an instance that has the\n     * new protocol version.\n     *\n     * @param string $version HTTP protocol version\n     * @return static\n     */\n    public function withProtocolVersion(string $version);\n\n    /**\n     * Retrieves all message header values.\n     *\n     * The keys represent the header name as it will be sent over the wire, and\n     * each value is an array of strings associated with the header.\n     *\n     *     // Represent the headers as a string\n     *     foreach ($message->getHeaders() as $name => $values) {\n     *         echo $name . \": \" . implode(\", \", $values);\n     *     }\n     *\n     *     // Emit headers iteratively:\n     *     foreach ($message->getHeaders() as $name => $values) {\n     *         foreach ($values as $value) {\n     *             header(sprintf('%s: %s', $name, $value), false);\n     *         }\n     *     }\n     *\n     * While header names are not case-sensitive, getHeaders() will preserve the\n     * exact case in which headers were originally specified.\n     *\n     * @return string[][] Returns an associative array of the message's headers. Each\n     *     key MUST be a header name, and each value MUST be an array of strings\n     *     for that header.\n     */\n    public function getHeaders();\n\n    /**\n     * Checks if a header exists by the given case-insensitive name.\n     *\n     * @param string $name Case-insensitive header field name.\n     * @return bool Returns true if any header names match the given header\n     *     name using a case-insensitive string comparison. Returns false if\n     *     no matching header name is found in the message.\n     */\n    public function hasHeader(string $name);\n\n    /**\n     * Retrieves a message header value by the given case-insensitive name.\n     *\n     * This method returns an array of all the header values of the given\n     * case-insensitive header name.\n     *\n     * If the header does not appear in the message, this method MUST return an\n     * empty array.\n     *\n     * @param string $name Case-insensitive header field name.\n     * @return string[] An array of string values as provided for the given\n     *    header. If the header does not appear in the message, this method MUST\n     *    return an empty array.\n     */\n    public function getHeader(string $name);\n\n    /**\n     * Retrieves a comma-separated string of the values for a single header.\n     *\n     * This method returns all of the header values of the given\n     * case-insensitive header name as a string concatenated together using\n     * a comma.\n     *\n     * NOTE: Not all header values may be appropriately represented using\n     * comma concatenation. For such headers, use getHeader() instead\n     * and supply your own delimiter when concatenating.\n     *\n     * If the header does not appear in the message, this method MUST return\n     * an empty string.\n     *\n     * @param string $name Case-insensitive header field name.\n     * @return string A string of values as provided for the given header\n     *    concatenated together using a comma. If the header does not appear in\n     *    the message, this method MUST return an empty string.\n     */\n    public function getHeaderLine(string $name);\n\n    /**\n     * Return an instance with the provided value replacing the specified header.\n     *\n     * While header names are case-insensitive, the casing of the header will\n     * be preserved by this function, and returned from getHeaders().\n     *\n     * This method MUST be implemented in such a way as to retain the\n     * immutability of the message, and MUST return an instance that has the\n     * new and/or updated header and value.\n     *\n     * @param string $name Case-insensitive header field name.\n     * @param string|string[] $value Header value(s).\n     * @return static\n     * @throws \\InvalidArgumentException for invalid header names or values.\n     */\n    public function withHeader(string $name, $value);\n\n    /**\n     * Return an instance with the specified header appended with the given value.\n     *\n     * Existing values for the specified header will be maintained. The new\n     * value(s) will be appended to the existing list. If the header did not\n     * exist previously, it will be added.\n     *\n     * This method MUST be implemented in such a way as to retain the\n     * immutability of the message, and MUST return an instance that has the\n     * new header and/or value.\n     *\n     * @param string $name Case-insensitive header field name to add.\n     * @param string|string[] $value Header value(s).\n     * @return static\n     * @throws \\InvalidArgumentException for invalid header names or values.\n     */\n    public function withAddedHeader(string $name, $value);\n\n    /**\n     * Return an instance without the specified header.\n     *\n     * Header resolution MUST be done without case-sensitivity.\n     *\n     * This method MUST be implemented in such a way as to retain the\n     * immutability of the message, and MUST return an instance that removes\n     * the named header.\n     *\n     * @param string $name Case-insensitive header field name to remove.\n     * @return static\n     */\n    public function withoutHeader(string $name);\n\n    /**\n     * Gets the body of the message.\n     *\n     * @return StreamInterface Returns the body as a stream.\n     */\n    public function getBody();\n\n    /**\n     * Return an instance with the specified message body.\n     *\n     * The body MUST be a StreamInterface object.\n     *\n     * This method MUST be implemented in such a way as to retain the\n     * immutability of the message, and MUST return a new instance that has the\n     * new body stream.\n     *\n     * @param StreamInterface $body Body.\n     * @return static\n     * @throws \\InvalidArgumentException When the body is not valid.\n     */\n    public function withBody(StreamInterface $body);\n}\n"
  },
  {
    "path": "server/vendor/psr/http-message/src/RequestInterface.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Psr\\Http\\Message;\n\n/**\n * Representation of an outgoing, client-side request.\n *\n * Per the HTTP specification, this interface includes properties for\n * each of the following:\n *\n * - Protocol version\n * - HTTP method\n * - URI\n * - Headers\n * - Message body\n *\n * During construction, implementations MUST attempt to set the Host header from\n * a provided URI if no Host header is provided.\n *\n * Requests are considered immutable; all methods that might change state MUST\n * be implemented such that they retain the internal state of the current\n * message and return an instance that contains the changed state.\n */\ninterface RequestInterface extends MessageInterface\n{\n    /**\n     * Retrieves the message's request target.\n     *\n     * Retrieves the message's request-target either as it will appear (for\n     * clients), as it appeared at request (for servers), or as it was\n     * specified for the instance (see withRequestTarget()).\n     *\n     * In most cases, this will be the origin-form of the composed URI,\n     * unless a value was provided to the concrete implementation (see\n     * withRequestTarget() below).\n     *\n     * If no URI is available, and no request-target has been specifically\n     * provided, this method MUST return the string \"/\".\n     *\n     * @return string\n     */\n    public function getRequestTarget();\n\n    /**\n     * Return an instance with the specific request-target.\n     *\n     * If the request needs a non-origin-form request-target — e.g., for\n     * specifying an absolute-form, authority-form, or asterisk-form —\n     * this method may be used to create an instance with the specified\n     * request-target, verbatim.\n     *\n     * This method MUST be implemented in such a way as to retain the\n     * immutability of the message, and MUST return an instance that has the\n     * changed request target.\n     *\n     * @link http://tools.ietf.org/html/rfc7230#section-5.3 (for the various\n     *     request-target forms allowed in request messages)\n     * @param string $requestTarget\n     * @return static\n     */\n    public function withRequestTarget(string $requestTarget);\n\n    /**\n     * Retrieves the HTTP method of the request.\n     *\n     * @return string Returns the request method.\n     */\n    public function getMethod();\n\n    /**\n     * Return an instance with the provided HTTP method.\n     *\n     * While HTTP method names are typically all uppercase characters, HTTP\n     * method names are case-sensitive and thus implementations SHOULD NOT\n     * modify the given string.\n     *\n     * This method MUST be implemented in such a way as to retain the\n     * immutability of the message, and MUST return an instance that has the\n     * changed request method.\n     *\n     * @param string $method Case-sensitive method.\n     * @return static\n     * @throws \\InvalidArgumentException for invalid HTTP methods.\n     */\n    public function withMethod(string $method);\n\n    /**\n     * Retrieves the URI instance.\n     *\n     * This method MUST return a UriInterface instance.\n     *\n     * @link http://tools.ietf.org/html/rfc3986#section-4.3\n     * @return UriInterface Returns a UriInterface instance\n     *     representing the URI of the request.\n     */\n    public function getUri();\n\n    /**\n     * Returns an instance with the provided URI.\n     *\n     * This method MUST update the Host header of the returned request by\n     * default if the URI contains a host component. If the URI does not\n     * contain a host component, any pre-existing Host header MUST be carried\n     * over to the returned request.\n     *\n     * You can opt-in to preserving the original state of the Host header by\n     * setting `$preserveHost` to `true`. When `$preserveHost` is set to\n     * `true`, this method interacts with the Host header in the following ways:\n     *\n     * - If the Host header is missing or empty, and the new URI contains\n     *   a host component, this method MUST update the Host header in the returned\n     *   request.\n     * - If the Host header is missing or empty, and the new URI does not contain a\n     *   host component, this method MUST NOT update the Host header in the returned\n     *   request.\n     * - If a Host header is present and non-empty, this method MUST NOT update\n     *   the Host header in the returned request.\n     *\n     * This method MUST be implemented in such a way as to retain the\n     * immutability of the message, and MUST return an instance that has the\n     * new UriInterface instance.\n     *\n     * @link http://tools.ietf.org/html/rfc3986#section-4.3\n     * @param UriInterface $uri New request URI to use.\n     * @param bool $preserveHost Preserve the original state of the Host header.\n     * @return static\n     */\n    public function withUri(UriInterface $uri, bool $preserveHost = false);\n}\n"
  },
  {
    "path": "server/vendor/psr/http-message/src/ResponseInterface.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Psr\\Http\\Message;\n\n/**\n * Representation of an outgoing, server-side response.\n *\n * Per the HTTP specification, this interface includes properties for\n * each of the following:\n *\n * - Protocol version\n * - Status code and reason phrase\n * - Headers\n * - Message body\n *\n * Responses are considered immutable; all methods that might change state MUST\n * be implemented such that they retain the internal state of the current\n * message and return an instance that contains the changed state.\n */\ninterface ResponseInterface extends MessageInterface\n{\n    /**\n     * Gets the response status code.\n     *\n     * The status code is a 3-digit integer result code of the server's attempt\n     * to understand and satisfy the request.\n     *\n     * @return int Status code.\n     */\n    public function getStatusCode();\n\n    /**\n     * Return an instance with the specified status code and, optionally, reason phrase.\n     *\n     * If no reason phrase is specified, implementations MAY choose to default\n     * to the RFC 7231 or IANA recommended reason phrase for the response's\n     * status code.\n     *\n     * This method MUST be implemented in such a way as to retain the\n     * immutability of the message, and MUST return an instance that has the\n     * updated status and reason phrase.\n     *\n     * @link http://tools.ietf.org/html/rfc7231#section-6\n     * @link http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml\n     * @param int $code The 3-digit integer result code to set.\n     * @param string $reasonPhrase The reason phrase to use with the\n     *     provided status code; if none is provided, implementations MAY\n     *     use the defaults as suggested in the HTTP specification.\n     * @return static\n     * @throws \\InvalidArgumentException For invalid status code arguments.\n     */\n    public function withStatus(int $code, string $reasonPhrase = '');\n\n    /**\n     * Gets the response reason phrase associated with the status code.\n     *\n     * Because a reason phrase is not a required element in a response\n     * status line, the reason phrase value MAY be null. Implementations MAY\n     * choose to return the default RFC 7231 recommended reason phrase (or those\n     * listed in the IANA HTTP Status Code Registry) for the response's\n     * status code.\n     *\n     * @link http://tools.ietf.org/html/rfc7231#section-6\n     * @link http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml\n     * @return string Reason phrase; must return an empty string if none present.\n     */\n    public function getReasonPhrase();\n}\n"
  },
  {
    "path": "server/vendor/psr/http-message/src/ServerRequestInterface.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Psr\\Http\\Message;\n\n/**\n * Representation of an incoming, server-side HTTP request.\n *\n * Per the HTTP specification, this interface includes properties for\n * each of the following:\n *\n * - Protocol version\n * - HTTP method\n * - URI\n * - Headers\n * - Message body\n *\n * Additionally, it encapsulates all data as it has arrived to the\n * application from the CGI and/or PHP environment, including:\n *\n * - The values represented in $_SERVER.\n * - Any cookies provided (generally via $_COOKIE)\n * - Query string arguments (generally via $_GET, or as parsed via parse_str())\n * - Upload files, if any (as represented by $_FILES)\n * - Deserialized body parameters (generally from $_POST)\n *\n * $_SERVER values MUST be treated as immutable, as they represent application\n * state at the time of request; as such, no methods are provided to allow\n * modification of those values. The other values provide such methods, as they\n * can be restored from $_SERVER or the request body, and may need treatment\n * during the application (e.g., body parameters may be deserialized based on\n * content type).\n *\n * Additionally, this interface recognizes the utility of introspecting a\n * request to derive and match additional parameters (e.g., via URI path\n * matching, decrypting cookie values, deserializing non-form-encoded body\n * content, matching authorization headers to users, etc). These parameters\n * are stored in an \"attributes\" property.\n *\n * Requests are considered immutable; all methods that might change state MUST\n * be implemented such that they retain the internal state of the current\n * message and return an instance that contains the changed state.\n */\ninterface ServerRequestInterface extends RequestInterface\n{\n    /**\n     * Retrieve server parameters.\n     *\n     * Retrieves data related to the incoming request environment,\n     * typically derived from PHP's $_SERVER superglobal. The data IS NOT\n     * REQUIRED to originate from $_SERVER.\n     *\n     * @return array\n     */\n    public function getServerParams();\n\n    /**\n     * Retrieve cookies.\n     *\n     * Retrieves cookies sent by the client to the server.\n     *\n     * The data MUST be compatible with the structure of the $_COOKIE\n     * superglobal.\n     *\n     * @return array\n     */\n    public function getCookieParams();\n\n    /**\n     * Return an instance with the specified cookies.\n     *\n     * The data IS NOT REQUIRED to come from the $_COOKIE superglobal, but MUST\n     * be compatible with the structure of $_COOKIE. Typically, this data will\n     * be injected at instantiation.\n     *\n     * This method MUST NOT update the related Cookie header of the request\n     * instance, nor related values in the server params.\n     *\n     * This method MUST be implemented in such a way as to retain the\n     * immutability of the message, and MUST return an instance that has the\n     * updated cookie values.\n     *\n     * @param array $cookies Array of key/value pairs representing cookies.\n     * @return static\n     */\n    public function withCookieParams(array $cookies);\n\n    /**\n     * Retrieve query string arguments.\n     *\n     * Retrieves the deserialized query string arguments, if any.\n     *\n     * Note: the query params might not be in sync with the URI or server\n     * params. If you need to ensure you are only getting the original\n     * values, you may need to parse the query string from `getUri()->getQuery()`\n     * or from the `QUERY_STRING` server param.\n     *\n     * @return array\n     */\n    public function getQueryParams();\n\n    /**\n     * Return an instance with the specified query string arguments.\n     *\n     * These values SHOULD remain immutable over the course of the incoming\n     * request. They MAY be injected during instantiation, such as from PHP's\n     * $_GET superglobal, or MAY be derived from some other value such as the\n     * URI. In cases where the arguments are parsed from the URI, the data\n     * MUST be compatible with what PHP's parse_str() would return for\n     * purposes of how duplicate query parameters are handled, and how nested\n     * sets are handled.\n     *\n     * Setting query string arguments MUST NOT change the URI stored by the\n     * request, nor the values in the server params.\n     *\n     * This method MUST be implemented in such a way as to retain the\n     * immutability of the message, and MUST return an instance that has the\n     * updated query string arguments.\n     *\n     * @param array $query Array of query string arguments, typically from\n     *     $_GET.\n     * @return static\n     */\n    public function withQueryParams(array $query);\n\n    /**\n     * Retrieve normalized file upload data.\n     *\n     * This method returns upload metadata in a normalized tree, with each leaf\n     * an instance of Psr\\Http\\Message\\UploadedFileInterface.\n     *\n     * These values MAY be prepared from $_FILES or the message body during\n     * instantiation, or MAY be injected via withUploadedFiles().\n     *\n     * @return array An array tree of UploadedFileInterface instances; an empty\n     *     array MUST be returned if no data is present.\n     */\n    public function getUploadedFiles();\n\n    /**\n     * Create a new instance with the specified uploaded files.\n     *\n     * This method MUST be implemented in such a way as to retain the\n     * immutability of the message, and MUST return an instance that has the\n     * updated body parameters.\n     *\n     * @param array $uploadedFiles An array tree of UploadedFileInterface instances.\n     * @return static\n     * @throws \\InvalidArgumentException if an invalid structure is provided.\n     */\n    public function withUploadedFiles(array $uploadedFiles);\n\n    /**\n     * Retrieve any parameters provided in the request body.\n     *\n     * If the request Content-Type is either application/x-www-form-urlencoded\n     * or multipart/form-data, and the request method is POST, this method MUST\n     * return the contents of $_POST.\n     *\n     * Otherwise, this method may return any results of deserializing\n     * the request body content; as parsing returns structured content, the\n     * potential types MUST be arrays or objects only. A null value indicates\n     * the absence of body content.\n     *\n     * @return null|array|object The deserialized body parameters, if any.\n     *     These will typically be an array or object.\n     */\n    public function getParsedBody();\n\n    /**\n     * Return an instance with the specified body parameters.\n     *\n     * These MAY be injected during instantiation.\n     *\n     * If the request Content-Type is either application/x-www-form-urlencoded\n     * or multipart/form-data, and the request method is POST, use this method\n     * ONLY to inject the contents of $_POST.\n     *\n     * The data IS NOT REQUIRED to come from $_POST, but MUST be the results of\n     * deserializing the request body content. Deserialization/parsing returns\n     * structured data, and, as such, this method ONLY accepts arrays or objects,\n     * or a null value if nothing was available to parse.\n     *\n     * As an example, if content negotiation determines that the request data\n     * is a JSON payload, this method could be used to create a request\n     * instance with the deserialized parameters.\n     *\n     * This method MUST be implemented in such a way as to retain the\n     * immutability of the message, and MUST return an instance that has the\n     * updated body parameters.\n     *\n     * @param null|array|object $data The deserialized body data. This will\n     *     typically be in an array or object.\n     * @return static\n     * @throws \\InvalidArgumentException if an unsupported argument type is\n     *     provided.\n     */\n    public function withParsedBody($data);\n\n    /**\n     * Retrieve attributes derived from the request.\n     *\n     * The request \"attributes\" may be used to allow injection of any\n     * parameters derived from the request: e.g., the results of path\n     * match operations; the results of decrypting cookies; the results of\n     * deserializing non-form-encoded message bodies; etc. Attributes\n     * will be application and request specific, and CAN be mutable.\n     *\n     * @return array Attributes derived from the request.\n     */\n    public function getAttributes();\n\n    /**\n     * Retrieve a single derived request attribute.\n     *\n     * Retrieves a single derived request attribute as described in\n     * getAttributes(). If the attribute has not been previously set, returns\n     * the default value as provided.\n     *\n     * This method obviates the need for a hasAttribute() method, as it allows\n     * specifying a default value to return if the attribute is not found.\n     *\n     * @see getAttributes()\n     * @param string $name The attribute name.\n     * @param mixed $default Default value to return if the attribute does not exist.\n     * @return mixed\n     */\n    public function getAttribute(string $name, $default = null);\n\n    /**\n     * Return an instance with the specified derived request attribute.\n     *\n     * This method allows setting a single derived request attribute as\n     * described in getAttributes().\n     *\n     * This method MUST be implemented in such a way as to retain the\n     * immutability of the message, and MUST return an instance that has the\n     * updated attribute.\n     *\n     * @see getAttributes()\n     * @param string $name The attribute name.\n     * @param mixed $value The value of the attribute.\n     * @return static\n     */\n    public function withAttribute(string $name, $value);\n\n    /**\n     * Return an instance that removes the specified derived request attribute.\n     *\n     * This method allows removing a single derived request attribute as\n     * described in getAttributes().\n     *\n     * This method MUST be implemented in such a way as to retain the\n     * immutability of the message, and MUST return an instance that removes\n     * the attribute.\n     *\n     * @see getAttributes()\n     * @param string $name The attribute name.\n     * @return static\n     */\n    public function withoutAttribute(string $name);\n}\n"
  },
  {
    "path": "server/vendor/psr/http-message/src/StreamInterface.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Psr\\Http\\Message;\n\n/**\n * Describes a data stream.\n *\n * Typically, an instance will wrap a PHP stream; this interface provides\n * a wrapper around the most common operations, including serialization of\n * the entire stream to a string.\n */\ninterface StreamInterface\n{\n    /**\n     * Reads all data from the stream into a string, from the beginning to end.\n     *\n     * This method MUST attempt to seek to the beginning of the stream before\n     * reading data and read the stream until the end is reached.\n     *\n     * Warning: This could attempt to load a large amount of data into memory.\n     *\n     * This method MUST NOT raise an exception in order to conform with PHP's\n     * string casting operations.\n     *\n     * @see http://php.net/manual/en/language.oop5.magic.php#object.tostring\n     * @return string\n     */\n    public function __toString();\n\n    /**\n     * Closes the stream and any underlying resources.\n     *\n     * @return void\n     */\n    public function close();\n\n    /**\n     * Separates any underlying resources from the stream.\n     *\n     * After the stream has been detached, the stream is in an unusable state.\n     *\n     * @return resource|null Underlying PHP stream, if any\n     */\n    public function detach();\n\n    /**\n     * Get the size of the stream if known.\n     *\n     * @return int|null Returns the size in bytes if known, or null if unknown.\n     */\n    public function getSize();\n\n    /**\n     * Returns the current position of the file read/write pointer\n     *\n     * @return int Position of the file pointer\n     * @throws \\RuntimeException on error.\n     */\n    public function tell();\n\n    /**\n     * Returns true if the stream is at the end of the stream.\n     *\n     * @return bool\n     */\n    public function eof();\n\n    /**\n     * Returns whether or not the stream is seekable.\n     *\n     * @return bool\n     */\n    public function isSeekable();\n\n    /**\n     * Seek to a position in the stream.\n     *\n     * @link http://www.php.net/manual/en/function.fseek.php\n     * @param int $offset Stream offset\n     * @param int $whence Specifies how the cursor position will be calculated\n     *     based on the seek offset. Valid values are identical to the built-in\n     *     PHP $whence values for `fseek()`.  SEEK_SET: Set position equal to\n     *     offset bytes SEEK_CUR: Set position to current location plus offset\n     *     SEEK_END: Set position to end-of-stream plus offset.\n     * @throws \\RuntimeException on failure.\n     */\n    public function seek(int $offset, int $whence = SEEK_SET);\n\n    /**\n     * Seek to the beginning of the stream.\n     *\n     * If the stream is not seekable, this method will raise an exception;\n     * otherwise, it will perform a seek(0).\n     *\n     * @see seek()\n     * @link http://www.php.net/manual/en/function.fseek.php\n     * @throws \\RuntimeException on failure.\n     */\n    public function rewind();\n\n    /**\n     * Returns whether or not the stream is writable.\n     *\n     * @return bool\n     */\n    public function isWritable();\n\n    /**\n     * Write data to the stream.\n     *\n     * @param string $string The string that is to be written.\n     * @return int Returns the number of bytes written to the stream.\n     * @throws \\RuntimeException on failure.\n     */\n    public function write(string $string);\n\n    /**\n     * Returns whether or not the stream is readable.\n     *\n     * @return bool\n     */\n    public function isReadable();\n\n    /**\n     * Read data from the stream.\n     *\n     * @param int $length Read up to $length bytes from the object and return\n     *     them. Fewer than $length bytes may be returned if underlying stream\n     *     call returns fewer bytes.\n     * @return string Returns the data read from the stream, or an empty string\n     *     if no bytes are available.\n     * @throws \\RuntimeException if an error occurs.\n     */\n    public function read(int $length);\n\n    /**\n     * Returns the remaining contents in a string\n     *\n     * @return string\n     * @throws \\RuntimeException if unable to read or an error occurs while\n     *     reading.\n     */\n    public function getContents();\n\n    /**\n     * Get stream metadata as an associative array or retrieve a specific key.\n     *\n     * The keys returned are identical to the keys returned from PHP's\n     * stream_get_meta_data() function.\n     *\n     * @link http://php.net/manual/en/function.stream-get-meta-data.php\n     * @param string|null $key Specific metadata to retrieve.\n     * @return array|mixed|null Returns an associative array if no key is\n     *     provided. Returns a specific key value if a key is provided and the\n     *     value is found, or null if the key is not found.\n     */\n    public function getMetadata(?string $key = null);\n}\n"
  },
  {
    "path": "server/vendor/psr/http-message/src/UploadedFileInterface.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Psr\\Http\\Message;\n\n/**\n * Value object representing a file uploaded through an HTTP request.\n *\n * Instances of this interface are considered immutable; all methods that\n * might change state MUST be implemented such that they retain the internal\n * state of the current instance and return an instance that contains the\n * changed state.\n */\ninterface UploadedFileInterface\n{\n    /**\n     * Retrieve a stream representing the uploaded file.\n     *\n     * This method MUST return a StreamInterface instance, representing the\n     * uploaded file. The purpose of this method is to allow utilizing native PHP\n     * stream functionality to manipulate the file upload, such as\n     * stream_copy_to_stream() (though the result will need to be decorated in a\n     * native PHP stream wrapper to work with such functions).\n     *\n     * If the moveTo() method has been called previously, this method MUST raise\n     * an exception.\n     *\n     * @return StreamInterface Stream representation of the uploaded file.\n     * @throws \\RuntimeException in cases when no stream is available or can be\n     *     created.\n     */\n    public function getStream();\n\n    /**\n     * Move the uploaded file to a new location.\n     *\n     * Use this method as an alternative to move_uploaded_file(). This method is\n     * guaranteed to work in both SAPI and non-SAPI environments.\n     * Implementations must determine which environment they are in, and use the\n     * appropriate method (move_uploaded_file(), rename(), or a stream\n     * operation) to perform the operation.\n     *\n     * $targetPath may be an absolute path, or a relative path. If it is a\n     * relative path, resolution should be the same as used by PHP's rename()\n     * function.\n     *\n     * The original file or stream MUST be removed on completion.\n     *\n     * If this method is called more than once, any subsequent calls MUST raise\n     * an exception.\n     *\n     * When used in an SAPI environment where $_FILES is populated, when writing\n     * files via moveTo(), is_uploaded_file() and move_uploaded_file() SHOULD be\n     * used to ensure permissions and upload status are verified correctly.\n     *\n     * If you wish to move to a stream, use getStream(), as SAPI operations\n     * cannot guarantee writing to stream destinations.\n     *\n     * @see http://php.net/is_uploaded_file\n     * @see http://php.net/move_uploaded_file\n     * @param string $targetPath Path to which to move the uploaded file.\n     * @throws \\InvalidArgumentException if the $targetPath specified is invalid.\n     * @throws \\RuntimeException on any error during the move operation, or on\n     *     the second or subsequent call to the method.\n     */\n    public function moveTo(string $targetPath);\n    \n    /**\n     * Retrieve the file size.\n     *\n     * Implementations SHOULD return the value stored in the \"size\" key of\n     * the file in the $_FILES array if available, as PHP calculates this based\n     * on the actual size transmitted.\n     *\n     * @return int|null The file size in bytes or null if unknown.\n     */\n    public function getSize();\n    \n    /**\n     * Retrieve the error associated with the uploaded file.\n     *\n     * The return value MUST be one of PHP's UPLOAD_ERR_XXX constants.\n     *\n     * If the file was uploaded successfully, this method MUST return\n     * UPLOAD_ERR_OK.\n     *\n     * Implementations SHOULD return the value stored in the \"error\" key of\n     * the file in the $_FILES array.\n     *\n     * @see http://php.net/manual/en/features.file-upload.errors.php\n     * @return int One of PHP's UPLOAD_ERR_XXX constants.\n     */\n    public function getError();\n    \n    /**\n     * Retrieve the filename sent by the client.\n     *\n     * Do not trust the value returned by this method. A client could send\n     * a malicious filename with the intention to corrupt or hack your\n     * application.\n     *\n     * Implementations SHOULD return the value stored in the \"name\" key of\n     * the file in the $_FILES array.\n     *\n     * @return string|null The filename sent by the client or null if none\n     *     was provided.\n     */\n    public function getClientFilename();\n    \n    /**\n     * Retrieve the media type sent by the client.\n     *\n     * Do not trust the value returned by this method. A client could send\n     * a malicious media type with the intention to corrupt or hack your\n     * application.\n     *\n     * Implementations SHOULD return the value stored in the \"type\" key of\n     * the file in the $_FILES array.\n     *\n     * @return string|null The media type sent by the client or null if none\n     *     was provided.\n     */\n    public function getClientMediaType();\n}\n"
  },
  {
    "path": "server/vendor/psr/http-message/src/UriInterface.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Psr\\Http\\Message;\n\n/**\n * Value object representing a URI.\n *\n * This interface is meant to represent URIs according to RFC 3986 and to\n * provide methods for most common operations. Additional functionality for\n * working with URIs can be provided on top of the interface or externally.\n * Its primary use is for HTTP requests, but may also be used in other\n * contexts.\n *\n * Instances of this interface are considered immutable; all methods that\n * might change state MUST be implemented such that they retain the internal\n * state of the current instance and return an instance that contains the\n * changed state.\n *\n * Typically the Host header will be also be present in the request message.\n * For server-side requests, the scheme will typically be discoverable in the\n * server parameters.\n *\n * @link http://tools.ietf.org/html/rfc3986 (the URI specification)\n */\ninterface UriInterface\n{\n    /**\n     * Retrieve the scheme component of the URI.\n     *\n     * If no scheme is present, this method MUST return an empty string.\n     *\n     * The value returned MUST be normalized to lowercase, per RFC 3986\n     * Section 3.1.\n     *\n     * The trailing \":\" character is not part of the scheme and MUST NOT be\n     * added.\n     *\n     * @see https://tools.ietf.org/html/rfc3986#section-3.1\n     * @return string The URI scheme.\n     */\n    public function getScheme();\n\n    /**\n     * Retrieve the authority component of the URI.\n     *\n     * If no authority information is present, this method MUST return an empty\n     * string.\n     *\n     * The authority syntax of the URI is:\n     *\n     * <pre>\n     * [user-info@]host[:port]\n     * </pre>\n     *\n     * If the port component is not set or is the standard port for the current\n     * scheme, it SHOULD NOT be included.\n     *\n     * @see https://tools.ietf.org/html/rfc3986#section-3.2\n     * @return string The URI authority, in \"[user-info@]host[:port]\" format.\n     */\n    public function getAuthority();\n\n    /**\n     * Retrieve the user information component of the URI.\n     *\n     * If no user information is present, this method MUST return an empty\n     * string.\n     *\n     * If a user is present in the URI, this will return that value;\n     * additionally, if the password is also present, it will be appended to the\n     * user value, with a colon (\":\") separating the values.\n     *\n     * The trailing \"@\" character is not part of the user information and MUST\n     * NOT be added.\n     *\n     * @return string The URI user information, in \"username[:password]\" format.\n     */\n    public function getUserInfo();\n\n    /**\n     * Retrieve the host component of the URI.\n     *\n     * If no host is present, this method MUST return an empty string.\n     *\n     * The value returned MUST be normalized to lowercase, per RFC 3986\n     * Section 3.2.2.\n     *\n     * @see http://tools.ietf.org/html/rfc3986#section-3.2.2\n     * @return string The URI host.\n     */\n    public function getHost();\n\n    /**\n     * Retrieve the port component of the URI.\n     *\n     * If a port is present, and it is non-standard for the current scheme,\n     * this method MUST return it as an integer. If the port is the standard port\n     * used with the current scheme, this method SHOULD return null.\n     *\n     * If no port is present, and no scheme is present, this method MUST return\n     * a null value.\n     *\n     * If no port is present, but a scheme is present, this method MAY return\n     * the standard port for that scheme, but SHOULD return null.\n     *\n     * @return null|int The URI port.\n     */\n    public function getPort();\n\n    /**\n     * Retrieve the path component of the URI.\n     *\n     * The path can either be empty or absolute (starting with a slash) or\n     * rootless (not starting with a slash). Implementations MUST support all\n     * three syntaxes.\n     *\n     * Normally, the empty path \"\" and absolute path \"/\" are considered equal as\n     * defined in RFC 7230 Section 2.7.3. But this method MUST NOT automatically\n     * do this normalization because in contexts with a trimmed base path, e.g.\n     * the front controller, this difference becomes significant. It's the task\n     * of the user to handle both \"\" and \"/\".\n     *\n     * The value returned MUST be percent-encoded, but MUST NOT double-encode\n     * any characters. To determine what characters to encode, please refer to\n     * RFC 3986, Sections 2 and 3.3.\n     *\n     * As an example, if the value should include a slash (\"/\") not intended as\n     * delimiter between path segments, that value MUST be passed in encoded\n     * form (e.g., \"%2F\") to the instance.\n     *\n     * @see https://tools.ietf.org/html/rfc3986#section-2\n     * @see https://tools.ietf.org/html/rfc3986#section-3.3\n     * @return string The URI path.\n     */\n    public function getPath();\n\n    /**\n     * Retrieve the query string of the URI.\n     *\n     * If no query string is present, this method MUST return an empty string.\n     *\n     * The leading \"?\" character is not part of the query and MUST NOT be\n     * added.\n     *\n     * The value returned MUST be percent-encoded, but MUST NOT double-encode\n     * any characters. To determine what characters to encode, please refer to\n     * RFC 3986, Sections 2 and 3.4.\n     *\n     * As an example, if a value in a key/value pair of the query string should\n     * include an ampersand (\"&\") not intended as a delimiter between values,\n     * that value MUST be passed in encoded form (e.g., \"%26\") to the instance.\n     *\n     * @see https://tools.ietf.org/html/rfc3986#section-2\n     * @see https://tools.ietf.org/html/rfc3986#section-3.4\n     * @return string The URI query string.\n     */\n    public function getQuery();\n\n    /**\n     * Retrieve the fragment component of the URI.\n     *\n     * If no fragment is present, this method MUST return an empty string.\n     *\n     * The leading \"#\" character is not part of the fragment and MUST NOT be\n     * added.\n     *\n     * The value returned MUST be percent-encoded, but MUST NOT double-encode\n     * any characters. To determine what characters to encode, please refer to\n     * RFC 3986, Sections 2 and 3.5.\n     *\n     * @see https://tools.ietf.org/html/rfc3986#section-2\n     * @see https://tools.ietf.org/html/rfc3986#section-3.5\n     * @return string The URI fragment.\n     */\n    public function getFragment();\n\n    /**\n     * Return an instance with the specified scheme.\n     *\n     * This method MUST retain the state of the current instance, and return\n     * an instance that contains the specified scheme.\n     *\n     * Implementations MUST support the schemes \"http\" and \"https\" case\n     * insensitively, and MAY accommodate other schemes if required.\n     *\n     * An empty scheme is equivalent to removing the scheme.\n     *\n     * @param string $scheme The scheme to use with the new instance.\n     * @return static A new instance with the specified scheme.\n     * @throws \\InvalidArgumentException for invalid or unsupported schemes.\n     */\n    public function withScheme(string $scheme);\n\n    /**\n     * Return an instance with the specified user information.\n     *\n     * This method MUST retain the state of the current instance, and return\n     * an instance that contains the specified user information.\n     *\n     * Password is optional, but the user information MUST include the\n     * user; an empty string for the user is equivalent to removing user\n     * information.\n     *\n     * @param string $user The user name to use for authority.\n     * @param null|string $password The password associated with $user.\n     * @return static A new instance with the specified user information.\n     */\n    public function withUserInfo(string $user, ?string $password = null);\n\n    /**\n     * Return an instance with the specified host.\n     *\n     * This method MUST retain the state of the current instance, and return\n     * an instance that contains the specified host.\n     *\n     * An empty host value is equivalent to removing the host.\n     *\n     * @param string $host The hostname to use with the new instance.\n     * @return static A new instance with the specified host.\n     * @throws \\InvalidArgumentException for invalid hostnames.\n     */\n    public function withHost(string $host);\n\n    /**\n     * Return an instance with the specified port.\n     *\n     * This method MUST retain the state of the current instance, and return\n     * an instance that contains the specified port.\n     *\n     * Implementations MUST raise an exception for ports outside the\n     * established TCP and UDP port ranges.\n     *\n     * A null value provided for the port is equivalent to removing the port\n     * information.\n     *\n     * @param null|int $port The port to use with the new instance; a null value\n     *     removes the port information.\n     * @return static A new instance with the specified port.\n     * @throws \\InvalidArgumentException for invalid ports.\n     */\n    public function withPort(?int $port);\n\n    /**\n     * Return an instance with the specified path.\n     *\n     * This method MUST retain the state of the current instance, and return\n     * an instance that contains the specified path.\n     *\n     * The path can either be empty or absolute (starting with a slash) or\n     * rootless (not starting with a slash). Implementations MUST support all\n     * three syntaxes.\n     *\n     * If the path is intended to be domain-relative rather than path relative then\n     * it must begin with a slash (\"/\"). Paths not starting with a slash (\"/\")\n     * are assumed to be relative to some base path known to the application or\n     * consumer.\n     *\n     * Users can provide both encoded and decoded path characters.\n     * Implementations ensure the correct encoding as outlined in getPath().\n     *\n     * @param string $path The path to use with the new instance.\n     * @return static A new instance with the specified path.\n     * @throws \\InvalidArgumentException for invalid paths.\n     */\n    public function withPath(string $path);\n\n    /**\n     * Return an instance with the specified query string.\n     *\n     * This method MUST retain the state of the current instance, and return\n     * an instance that contains the specified query string.\n     *\n     * Users can provide both encoded and decoded query characters.\n     * Implementations ensure the correct encoding as outlined in getQuery().\n     *\n     * An empty query string value is equivalent to removing the query string.\n     *\n     * @param string $query The query string to use with the new instance.\n     * @return static A new instance with the specified query string.\n     * @throws \\InvalidArgumentException for invalid query strings.\n     */\n    public function withQuery(string $query);\n\n    /**\n     * Return an instance with the specified URI fragment.\n     *\n     * This method MUST retain the state of the current instance, and return\n     * an instance that contains the specified URI fragment.\n     *\n     * Users can provide both encoded and decoded fragment characters.\n     * Implementations ensure the correct encoding as outlined in getFragment().\n     *\n     * An empty fragment value is equivalent to removing the fragment.\n     *\n     * @param string $fragment The fragment to use with the new instance.\n     * @return static A new instance with the specified fragment.\n     */\n    public function withFragment(string $fragment);\n\n    /**\n     * Return the string representation as a URI reference.\n     *\n     * Depending on which components of the URI are present, the resulting\n     * string is either a full URI or relative reference according to RFC 3986,\n     * Section 4.1. The method concatenates the various components of the URI,\n     * using the appropriate delimiters:\n     *\n     * - If a scheme is present, it MUST be suffixed by \":\".\n     * - If an authority is present, it MUST be prefixed by \"//\".\n     * - The path can be concatenated without delimiters. But there are two\n     *   cases where the path has to be adjusted to make the URI reference\n     *   valid as PHP does not allow to throw an exception in __toString():\n     *     - If the path is rootless and an authority is present, the path MUST\n     *       be prefixed by \"/\".\n     *     - If the path is starting with more than one \"/\" and no authority is\n     *       present, the starting slashes MUST be reduced to one.\n     * - If a query is present, it MUST be prefixed by \"?\".\n     * - If a fragment is present, it MUST be prefixed by \"#\".\n     *\n     * @see http://tools.ietf.org/html/rfc3986#section-4.1\n     * @return string\n     */\n    public function __toString();\n}\n"
  },
  {
    "path": "server/vendor/psr/http-server-handler/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2016 PHP Framework Interoperability Group\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "server/vendor/psr/http-server-handler/README.md",
    "content": "HTTP Server Request Handlers for Middleware\n===========================================\n\nThis repository holds the `RequestHandlerInterface` related to [PSR-15 (HTTP Server Request Handlers)][psr-url].\n\nNote that this is not a Server Request Handler implementation of its own. It is merely the interface that describe a Server Request Handler.\n\nThe installable [package][package-url] and [implementations][implementation-url] are listed on Packagist.\n\n[psr-url]: https://www.php-fig.org/psr/psr-15/\n[package-url]: https://packagist.org/packages/psr/http-server-handler\n[implementation-url]: https://packagist.org/providers/psr/http-server-handler-implementation\n"
  },
  {
    "path": "server/vendor/psr/http-server-handler/composer.json",
    "content": "{\n    \"name\": \"psr/http-server-handler\",\n    \"description\": \"Common interface for HTTP server-side request handler\",\n    \"keywords\": [\n        \"psr\",\n        \"psr-7\",\n        \"psr-15\",\n        \"http-interop\",\n        \"http\",\n        \"server\",\n        \"handler\",\n        \"request\",\n        \"response\"\n    ],\n    \"license\": \"MIT\",\n    \"authors\": [\n        {\n            \"name\": \"PHP-FIG\",\n            \"homepage\": \"https://www.php-fig.org/\"\n        }\n    ],\n    \"require\": {\n        \"php\": \">=7.0\",\n        \"psr/http-message\": \"^1.0 || ^2.0\"\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"Psr\\\\Http\\\\Server\\\\\": \"src/\"\n        }\n    },\n    \"extra\": {\n        \"branch-alias\": {\n            \"dev-master\": \"1.0.x-dev\"\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/psr/http-server-handler/src/RequestHandlerInterface.php",
    "content": "<?php\n\nnamespace Psr\\Http\\Server;\n\nuse Psr\\Http\\Message\\ResponseInterface;\nuse Psr\\Http\\Message\\ServerRequestInterface;\n\n/**\n * Handles a server request and produces a response.\n *\n * An HTTP request handler process an HTTP request in order to produce an\n * HTTP response.\n */\ninterface RequestHandlerInterface\n{\n    /**\n     * Handles a request and produces a response.\n     *\n     * May call other collaborating code to generate the response.\n     */\n    public function handle(ServerRequestInterface $request): ResponseInterface;\n}\n"
  },
  {
    "path": "server/vendor/psr/http-server-middleware/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2016 PHP Framework Interoperability Group\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "server/vendor/psr/http-server-middleware/README.md",
    "content": "HTTP Server Middleware\n==============\n\nThis repository holds the `MiddlewareInterface` related to [PSR-15 (HTTP Server Request Handlers)][psr-url].\n\nNote that this is not a Middleware implementation of its own. It is merely the interface that describe a Middleware.\n\nThe installable [package][package-url] and [implementations][implementation-url] are listed on Packagist.\n\n[psr-url]: https://www.php-fig.org/psr/psr-15/\n[package-url]: https://packagist.org/packages/psr/http-server-middleware\n[implementation-url]: https://packagist.org/providers/psr/http-server-middleware-implementation\n"
  },
  {
    "path": "server/vendor/psr/http-server-middleware/composer.json",
    "content": "{\n    \"name\": \"psr/http-server-middleware\",\n    \"description\": \"Common interface for HTTP server-side middleware\",\n    \"keywords\": [\n        \"psr\",\n        \"psr-7\",\n        \"psr-15\",\n        \"http-interop\",\n        \"http\",\n        \"middleware\",\n        \"request\",\n        \"response\"\n    ],\n    \"license\": \"MIT\",\n    \"authors\": [\n        {\n            \"name\": \"PHP-FIG\",\n            \"homepage\": \"https://www.php-fig.org/\"\n        }\n    ],\n    \"require\": {\n        \"php\": \">=7.0\",\n        \"psr/http-message\": \"^1.0 || ^2.0\",\n        \"psr/http-server-handler\": \"^1.0\"\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"Psr\\\\Http\\\\Server\\\\\": \"src/\"\n        }\n    },\n    \"extra\": {\n        \"branch-alias\": {\n            \"dev-master\": \"1.0.x-dev\"\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/psr/http-server-middleware/src/MiddlewareInterface.php",
    "content": "<?php\n\nnamespace Psr\\Http\\Server;\n\nuse Psr\\Http\\Message\\ResponseInterface;\nuse Psr\\Http\\Message\\ServerRequestInterface;\n\n/**\n * Participant in processing a server request and response.\n *\n * An HTTP middleware component participates in processing an HTTP message:\n * by acting on the request, generating the response, or forwarding the\n * request to a subsequent middleware and possibly acting on its response.\n */\ninterface MiddlewareInterface\n{\n    /**\n     * Process an incoming server request.\n     *\n     * Processes an incoming server request in order to produce a response.\n     * If unable to produce the response itself, it may delegate to the provided\n     * request handler to do so.\n     */\n    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface;\n}\n"
  },
  {
    "path": "server/vendor/psr/log/LICENSE",
    "content": "Copyright (c) 2012 PHP Framework Interoperability Group\n\nPermission is hereby granted, free of charge, to any person obtaining a copy \nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights \nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell \ncopies of the Software, and to permit persons to whom the Software is \nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in \nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "server/vendor/psr/log/README.md",
    "content": "PSR Log\n=======\n\nThis repository holds all interfaces/classes/traits related to\n[PSR-3](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md).\n\nNote that this is not a logger of its own. It is merely an interface that\ndescribes a logger. See the specification for more details.\n\nInstallation\n------------\n\n```bash\ncomposer require psr/log\n```\n\nUsage\n-----\n\nIf you need a logger, you can use the interface like this:\n\n```php\n<?php\n\nuse Psr\\Log\\LoggerInterface;\n\nclass Foo\n{\n    private $logger;\n\n    public function __construct(LoggerInterface $logger = null)\n    {\n        $this->logger = $logger;\n    }\n\n    public function doSomething()\n    {\n        if ($this->logger) {\n            $this->logger->info('Doing work');\n        }\n           \n        try {\n            $this->doSomethingElse();\n        } catch (Exception $exception) {\n            $this->logger->error('Oh no!', array('exception' => $exception));\n        }\n\n        // do something useful\n    }\n}\n```\n\nYou can then pick one of the implementations of the interface to get a logger.\n\nIf you want to implement the interface, you can require this package and\nimplement `Psr\\Log\\LoggerInterface` in your code. Please read the\n[specification text](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md)\nfor details.\n"
  },
  {
    "path": "server/vendor/psr/log/composer.json",
    "content": "{\n    \"name\": \"psr/log\",\n    \"description\": \"Common interface for logging libraries\",\n    \"keywords\": [\"psr\", \"psr-3\", \"log\"],\n    \"homepage\": \"https://github.com/php-fig/log\",\n    \"license\": \"MIT\",\n    \"authors\": [\n        {\n            \"name\": \"PHP-FIG\",\n            \"homepage\": \"https://www.php-fig.org/\"\n        }\n    ],\n    \"require\": {\n        \"php\": \">=8.0.0\"\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"Psr\\\\Log\\\\\": \"src\"\n        }\n    },\n    \"extra\": {\n        \"branch-alias\": {\n            \"dev-master\": \"2.0.x-dev\"\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/psr/log/src/AbstractLogger.php",
    "content": "<?php\n\nnamespace Psr\\Log;\n\n/**\n * This is a simple Logger implementation that other Loggers can inherit from.\n *\n * It simply delegates all log-level-specific methods to the `log` method to\n * reduce boilerplate code that a simple Logger that does the same thing with\n * messages regardless of the error level has to implement.\n */\nabstract class AbstractLogger implements LoggerInterface\n{\n    use LoggerTrait;\n}\n"
  },
  {
    "path": "server/vendor/psr/log/src/InvalidArgumentException.php",
    "content": "<?php\n\nnamespace Psr\\Log;\n\nclass InvalidArgumentException extends \\InvalidArgumentException\n{\n}\n"
  },
  {
    "path": "server/vendor/psr/log/src/LogLevel.php",
    "content": "<?php\n\nnamespace Psr\\Log;\n\n/**\n * Describes log levels.\n */\nclass LogLevel\n{\n    const EMERGENCY = 'emergency';\n    const ALERT     = 'alert';\n    const CRITICAL  = 'critical';\n    const ERROR     = 'error';\n    const WARNING   = 'warning';\n    const NOTICE    = 'notice';\n    const INFO      = 'info';\n    const DEBUG     = 'debug';\n}\n"
  },
  {
    "path": "server/vendor/psr/log/src/LoggerAwareInterface.php",
    "content": "<?php\n\nnamespace Psr\\Log;\n\n/**\n * Describes a logger-aware instance.\n */\ninterface LoggerAwareInterface\n{\n    /**\n     * Sets a logger instance on the object.\n     *\n     * @param LoggerInterface $logger\n     *\n     * @return void\n     */\n    public function setLogger(LoggerInterface $logger);\n}\n"
  },
  {
    "path": "server/vendor/psr/log/src/LoggerAwareTrait.php",
    "content": "<?php\n\nnamespace Psr\\Log;\n\n/**\n * Basic Implementation of LoggerAwareInterface.\n */\ntrait LoggerAwareTrait\n{\n    /**\n     * The logger instance.\n     *\n     * @var LoggerInterface|null\n     */\n    protected ?LoggerInterface $logger = null;\n\n    /**\n     * Sets a logger.\n     *\n     * @param LoggerInterface $logger\n     */\n    public function setLogger(LoggerInterface $logger)\n    {\n        $this->logger = $logger;\n    }\n}\n"
  },
  {
    "path": "server/vendor/psr/log/src/LoggerInterface.php",
    "content": "<?php\n\nnamespace Psr\\Log;\n\n/**\n * Describes a logger instance.\n *\n * The message MUST be a string or object implementing __toString().\n *\n * The message MAY contain placeholders in the form: {foo} where foo\n * will be replaced by the context data in key \"foo\".\n *\n * The context array can contain arbitrary data. The only assumption that\n * can be made by implementors is that if an Exception instance is given\n * to produce a stack trace, it MUST be in a key named \"exception\".\n *\n * See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md\n * for the full interface specification.\n */\ninterface LoggerInterface\n{\n    /**\n     * System is unusable.\n     *\n     * @param string|\\Stringable $message\n     * @param mixed[] $context\n     *\n     * @return void\n     */\n    public function emergency(string|\\Stringable $message, array $context = []);\n\n    /**\n     * Action must be taken immediately.\n     *\n     * Example: Entire website down, database unavailable, etc. This should\n     * trigger the SMS alerts and wake you up.\n     *\n     * @param string|\\Stringable $message\n     * @param mixed[] $context\n     *\n     * @return void\n     */\n    public function alert(string|\\Stringable $message, array $context = []);\n\n    /**\n     * Critical conditions.\n     *\n     * Example: Application component unavailable, unexpected exception.\n     *\n     * @param string|\\Stringable $message\n     * @param mixed[] $context\n     *\n     * @return void\n     */\n    public function critical(string|\\Stringable $message, array $context = []);\n\n    /**\n     * Runtime errors that do not require immediate action but should typically\n     * be logged and monitored.\n     *\n     * @param string|\\Stringable $message\n     * @param mixed[] $context\n     *\n     * @return void\n     */\n    public function error(string|\\Stringable $message, array $context = []);\n\n    /**\n     * Exceptional occurrences that are not errors.\n     *\n     * Example: Use of deprecated APIs, poor use of an API, undesirable things\n     * that are not necessarily wrong.\n     *\n     * @param string|\\Stringable $message\n     * @param mixed[] $context\n     *\n     * @return void\n     */\n    public function warning(string|\\Stringable $message, array $context = []);\n\n    /**\n     * Normal but significant events.\n     *\n     * @param string|\\Stringable $message\n     * @param mixed[] $context\n     *\n     * @return void\n     */\n    public function notice(string|\\Stringable $message, array $context = []);\n\n    /**\n     * Interesting events.\n     *\n     * Example: User logs in, SQL logs.\n     *\n     * @param string|\\Stringable $message\n     * @param mixed[] $context\n     *\n     * @return void\n     */\n    public function info(string|\\Stringable $message, array $context = []);\n\n    /**\n     * Detailed debug information.\n     *\n     * @param string|\\Stringable $message\n     * @param mixed[] $context\n     *\n     * @return void\n     */\n    public function debug(string|\\Stringable $message, array $context = []);\n\n    /**\n     * Logs with an arbitrary level.\n     *\n     * @param mixed   $level\n     * @param string|\\Stringable $message\n     * @param mixed[] $context\n     *\n     * @return void\n     *\n     * @throws \\Psr\\Log\\InvalidArgumentException\n     */\n    public function log($level, string|\\Stringable $message, array $context = []);\n}\n"
  },
  {
    "path": "server/vendor/psr/log/src/LoggerTrait.php",
    "content": "<?php\n\nnamespace Psr\\Log;\n\n/**\n * This is a simple Logger trait that classes unable to extend AbstractLogger\n * (because they extend another class, etc) can include.\n *\n * It simply delegates all log-level-specific methods to the `log` method to\n * reduce boilerplate code that a simple Logger that does the same thing with\n * messages regardless of the error level has to implement.\n */\ntrait LoggerTrait\n{\n    /**\n     * System is unusable.\n     *\n     * @param string|\\Stringable $message\n     * @param array  $context\n     *\n     * @return void\n     */\n    public function emergency(string|\\Stringable $message, array $context = [])\n    {\n        $this->log(LogLevel::EMERGENCY, $message, $context);\n    }\n\n    /**\n     * Action must be taken immediately.\n     *\n     * Example: Entire website down, database unavailable, etc. This should\n     * trigger the SMS alerts and wake you up.\n     *\n     * @param string|\\Stringable $message\n     * @param array  $context\n     *\n     * @return void\n     */\n    public function alert(string|\\Stringable $message, array $context = [])\n    {\n        $this->log(LogLevel::ALERT, $message, $context);\n    }\n\n    /**\n     * Critical conditions.\n     *\n     * Example: Application component unavailable, unexpected exception.\n     *\n     * @param string|\\Stringable $message\n     * @param array  $context\n     *\n     * @return void\n     */\n    public function critical(string|\\Stringable $message, array $context = [])\n    {\n        $this->log(LogLevel::CRITICAL, $message, $context);\n    }\n\n    /**\n     * Runtime errors that do not require immediate action but should typically\n     * be logged and monitored.\n     *\n     * @param string|\\Stringable $message\n     * @param array  $context\n     *\n     * @return void\n     */\n    public function error(string|\\Stringable $message, array $context = [])\n    {\n        $this->log(LogLevel::ERROR, $message, $context);\n    }\n\n    /**\n     * Exceptional occurrences that are not errors.\n     *\n     * Example: Use of deprecated APIs, poor use of an API, undesirable things\n     * that are not necessarily wrong.\n     *\n     * @param string|\\Stringable $message\n     * @param array  $context\n     *\n     * @return void\n     */\n    public function warning(string|\\Stringable $message, array $context = [])\n    {\n        $this->log(LogLevel::WARNING, $message, $context);\n    }\n\n    /**\n     * Normal but significant events.\n     *\n     * @param string|\\Stringable $message\n     * @param array  $context\n     *\n     * @return void\n     */\n    public function notice(string|\\Stringable $message, array $context = [])\n    {\n        $this->log(LogLevel::NOTICE, $message, $context);\n    }\n\n    /**\n     * Interesting events.\n     *\n     * Example: User logs in, SQL logs.\n     *\n     * @param string|\\Stringable $message\n     * @param array  $context\n     *\n     * @return void\n     */\n    public function info(string|\\Stringable $message, array $context = [])\n    {\n        $this->log(LogLevel::INFO, $message, $context);\n    }\n\n    /**\n     * Detailed debug information.\n     *\n     * @param string|\\Stringable $message\n     * @param array  $context\n     *\n     * @return void\n     */\n    public function debug(string|\\Stringable $message, array $context = [])\n    {\n        $this->log(LogLevel::DEBUG, $message, $context);\n    }\n\n    /**\n     * Logs with an arbitrary level.\n     *\n     * @param mixed  $level\n     * @param string|\\Stringable $message\n     * @param array  $context\n     *\n     * @return void\n     *\n     * @throws \\Psr\\Log\\InvalidArgumentException\n     */\n    abstract public function log($level, string|\\Stringable $message, array $context = []);\n}\n"
  },
  {
    "path": "server/vendor/psr/log/src/NullLogger.php",
    "content": "<?php\n\nnamespace Psr\\Log;\n\n/**\n * This Logger can be used to avoid conditional log calls.\n *\n * Logging should always be optional, and if no logger is provided to your\n * library creating a NullLogger instance to have something to throw logs at\n * is a good way to avoid littering your code with `if ($this->logger) { }`\n * blocks.\n */\nclass NullLogger extends AbstractLogger\n{\n    /**\n     * Logs with an arbitrary level.\n     *\n     * @param mixed  $level\n     * @param string|\\Stringable $message\n     * @param array $context\n     *\n     * @return void\n     *\n     * @throws \\Psr\\Log\\InvalidArgumentException\n     */\n    public function log($level, string|\\Stringable $message, array $context = [])\n    {\n        // noop\n    }\n}\n"
  },
  {
    "path": "server/vendor/psr/simple-cache/.editorconfig",
    "content": "; This file is for unifying the coding style for different editors and IDEs.\n; More information at http://editorconfig.org\n\nroot = true\n\n[*]\ncharset = utf-8\nindent_size = 4\nindent_style = space\nend_of_line = lf\ninsert_final_newline = true\ntrim_trailing_whitespace = true\n"
  },
  {
    "path": "server/vendor/psr/simple-cache/LICENSE.md",
    "content": "# The MIT License (MIT)\n\nCopyright (c) 2016 PHP Framework Interoperability Group\n\n> Permission is hereby granted, free of charge, to any person obtaining a copy\n> of this software and associated documentation files (the \"Software\"), to deal\n> in the Software without restriction, including without limitation the rights\n> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n> copies of the Software, and to permit persons to whom the Software is\n> furnished to do so, subject to the following conditions:\n>\n> The above copyright notice and this permission notice shall be included in\n> all copies or substantial portions of the Software.\n>\n> THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n> THE SOFTWARE.\n"
  },
  {
    "path": "server/vendor/psr/simple-cache/README.md",
    "content": "PHP FIG Simple Cache PSR\n========================\n\nThis repository holds all interfaces related to PSR-16.\n\nNote that this is not a cache implementation of its own. It is merely an interface that describes a cache implementation. See [the specification](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-16-simple-cache.md) for more details.\n\nYou can find implementations of the specification by looking for packages providing the [psr/simple-cache-implementation](https://packagist.org/providers/psr/simple-cache-implementation) virtual package.\n"
  },
  {
    "path": "server/vendor/psr/simple-cache/composer.json",
    "content": "{\n    \"name\": \"psr/simple-cache\",\n    \"description\": \"Common interfaces for simple caching\",\n    \"keywords\": [\"psr\", \"psr-16\", \"cache\", \"simple-cache\", \"caching\"],\n    \"license\": \"MIT\",\n    \"authors\": [\n        {\n            \"name\": \"PHP-FIG\",\n            \"homepage\": \"http://www.php-fig.org/\"\n        }\n    ],\n    \"require\": {\n        \"php\": \">=5.3.0\"\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"Psr\\\\SimpleCache\\\\\": \"src/\"\n        }\n    },\n    \"extra\": {\n        \"branch-alias\": {\n            \"dev-master\": \"1.0.x-dev\"\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/psr/simple-cache/src/CacheException.php",
    "content": "<?php\n\nnamespace Psr\\SimpleCache;\n\n/**\n * Interface used for all types of exceptions thrown by the implementing library.\n */\ninterface CacheException\n{\n}\n"
  },
  {
    "path": "server/vendor/psr/simple-cache/src/CacheInterface.php",
    "content": "<?php\n\nnamespace Psr\\SimpleCache;\n\ninterface CacheInterface\n{\n    /**\n     * Fetches a value from the cache.\n     *\n     * @param string $key     The unique key of this item in the cache.\n     * @param mixed  $default Default value to return if the key does not exist.\n     *\n     * @return mixed The value of the item from the cache, or $default in case of cache miss.\n     *\n     * @throws \\Psr\\SimpleCache\\InvalidArgumentException\n     *   MUST be thrown if the $key string is not a legal value.\n     */\n    public function get($key, $default = null);\n\n    /**\n     * Persists data in the cache, uniquely referenced by a key with an optional expiration TTL time.\n     *\n     * @param string                 $key   The key of the item to store.\n     * @param mixed                  $value The value of the item to store, must be serializable.\n     * @param null|int|\\DateInterval $ttl   Optional. The TTL value of this item. If no value is sent and\n     *                                      the driver supports TTL then the library may set a default value\n     *                                      for it or let the driver take care of that.\n     *\n     * @return bool True on success and false on failure.\n     *\n     * @throws \\Psr\\SimpleCache\\InvalidArgumentException\n     *   MUST be thrown if the $key string is not a legal value.\n     */\n    public function set($key, $value, $ttl = null);\n\n    /**\n     * Delete an item from the cache by its unique key.\n     *\n     * @param string $key The unique cache key of the item to delete.\n     *\n     * @return bool True if the item was successfully removed. False if there was an error.\n     *\n     * @throws \\Psr\\SimpleCache\\InvalidArgumentException\n     *   MUST be thrown if the $key string is not a legal value.\n     */\n    public function delete($key);\n\n    /**\n     * Wipes clean the entire cache's keys.\n     *\n     * @return bool True on success and false on failure.\n     */\n    public function clear();\n\n    /**\n     * Obtains multiple cache items by their unique keys.\n     *\n     * @param iterable $keys    A list of keys that can obtained in a single operation.\n     * @param mixed    $default Default value to return for keys that do not exist.\n     *\n     * @return iterable A list of key => value pairs. Cache keys that do not exist or are stale will have $default as value.\n     *\n     * @throws \\Psr\\SimpleCache\\InvalidArgumentException\n     *   MUST be thrown if $keys is neither an array nor a Traversable,\n     *   or if any of the $keys are not a legal value.\n     */\n    public function getMultiple($keys, $default = null);\n\n    /**\n     * Persists a set of key => value pairs in the cache, with an optional TTL.\n     *\n     * @param iterable               $values A list of key => value pairs for a multiple-set operation.\n     * @param null|int|\\DateInterval $ttl    Optional. The TTL value of this item. If no value is sent and\n     *                                       the driver supports TTL then the library may set a default value\n     *                                       for it or let the driver take care of that.\n     *\n     * @return bool True on success and false on failure.\n     *\n     * @throws \\Psr\\SimpleCache\\InvalidArgumentException\n     *   MUST be thrown if $values is neither an array nor a Traversable,\n     *   or if any of the $values are not a legal value.\n     */\n    public function setMultiple($values, $ttl = null);\n\n    /**\n     * Deletes multiple cache items in a single operation.\n     *\n     * @param iterable $keys A list of string-based keys to be deleted.\n     *\n     * @return bool True if the items were successfully removed. False if there was an error.\n     *\n     * @throws \\Psr\\SimpleCache\\InvalidArgumentException\n     *   MUST be thrown if $keys is neither an array nor a Traversable,\n     *   or if any of the $keys are not a legal value.\n     */\n    public function deleteMultiple($keys);\n\n    /**\n     * Determines whether an item is present in the cache.\n     *\n     * NOTE: It is recommended that has() is only to be used for cache warming type purposes\n     * and not to be used within your live applications operations for get/set, as this method\n     * is subject to a race condition where your has() will return true and immediately after,\n     * another script can remove it making the state of your app out of date.\n     *\n     * @param string $key The cache item key.\n     *\n     * @return bool\n     *\n     * @throws \\Psr\\SimpleCache\\InvalidArgumentException\n     *   MUST be thrown if the $key string is not a legal value.\n     */\n    public function has($key);\n}\n"
  },
  {
    "path": "server/vendor/psr/simple-cache/src/InvalidArgumentException.php",
    "content": "<?php\n\nnamespace Psr\\SimpleCache;\n\n/**\n * Exception interface for invalid cache arguments.\n *\n * When an invalid argument is passed it must throw an exception which implements\n * this interface\n */\ninterface InvalidArgumentException extends CacheException\n{\n}\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/.gitignore",
    "content": ".vscode/\n.idea/"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/.travis.yml",
    "content": "language: php\nphp:\n  - 5.6\nnotifications:\n  email:\n    recipients:\n      - wjielai@tencent.com\n      - fysntian@tencent.com\n\nbefore_script:\n  - composer install --prefer-dist --dev --no-interaction\n\nscript: \n  - phpunit -v --coverage-clover=coverage.xml\n\nafter_success:\n    - bash <(curl -s https://codecov.io/bash)\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/CHANGELOG.md",
    "content": "cos-php-sdk-v5 Upgrade Guide\n====================\n2.1.6 to 2.2.0\n----------\n`PutObject` interface supports ci image process\n`GetObject` interface supports ci image process\nAdd `ImageInfo` interface, which is used for get image info\nAdd `ImageExif` interface, which is used for get image exif\nAdd `ImageAve` interface, which is used for get image ave\nAdd `ImageProcess` interface, which is used for data processing on cloud\nAdd `Qrcode` interface, which is used for qrcode recognition\nAdd `QrcodeGenerate` interface, which is used for generate qrcode\nAdd `DetectLabel` interface, which is used for detect image label\nAdd `PutBucketImageStyle` interface, which is used for add bucket image style\nAdd `GetBucketImageStyle` interface, which is used for get bucket image style\nAdd `DeleteBucketImageStyle` interface, which is used for delete bucket image style\nAdd `PutBucketGuetzli` interface, which is used for open bucket guetzli state\nAdd `GetBucketGuetzli` interface, which is used for get bucket guetzli state\nAdd `DeleteBucketGuetzli` interface, which is used for close bucket guetzli state\n\n2.1.5 to 2.1.6\n----------\n- Add `allow_redirects` parameter\n- Fix `selectObjectContent` interface\n\n2.1.3 to 2.1.5\n----------\n- The `download` interface supports breakpoint\n- Rename `getPresignetUrl` to `getPresignedUrl`\n\n2.1.2 to 2.1.3\n----------\n- Add `download` interface, which is used for concurrent block download\n- Add callback of `upload` and `download` progress\n- Fix request retry\n\n2.1.1 to 2.1.2\n----------\n- The interface supports custom parameters\n- Fix `ListBucketInventoryConfigurations`\n\n2.1.0 to 2.1.1\n----------\n- Fix bug of urlencode when calculating signature\n\n2.0.9 to 2.1.0\n----------\n- `upload` support upload with multithread\n- Add `retry` params for interface retry\n- Support add customer header\n- Signature will restrict part of the header and all parameters\n- Fix `listBuckets` with `doamin`\n\n2.0.8 to 2.0.9\n----------\n- Fix bug of `listObjectVersions`\n- Update `getObject` with param of `saveas`\n\n2.0.7 to 2.0.8\n----------\n- Fix presigned url when using tmpSecretId/tmpSecretKey/Token\n\n2.0.6 to 2.0.7\n----------\n- Fix response of `ListParts`\n\n2.0.5 to 2.0.6\n----------\n- Support Domain\n- Add Select Object Content Interface\n- Add Traffic Limit\n- Fix bug of object endswith /\n\n2.0.4 to 2.0.5\n----------\n- Fix bug when upload object with metadata\n\n2.0.3 to 2.0.4\n----------\n- Fix bug when using ip-port\n\n2.0.2 to 2.0.3\n----------\n- Fix path parse bug with /0/\n\n2.0.1 to 2.0.2\n----------\n- Fix bug of `putObject` with `fopen`\n- Add ut\n\n\n2.0.0 to 2.0.1\n----------\n- Add interface of inventory/tagging/logging\n- Fix bug of some interface with query string\n\n\n1.3 to 2.0\n----------\ncos-php-sdk-v5 now uses [GuzzleHttp] for HTTP message.\nDue to fact, it depending on PHP >= 5.6.\n\n- Use the `Qcloud\\Cos\\Client\\getPresignetUrl()` method instead of the `Qcloud\\Cos\\Command\\createPresignedUrl()`\n\nv2:\n```php\n$signedUrl = $cosClient->getPresignetUrl($method='putObject',\n                                         $args=['Bucket'=>'examplebucket-1250000000', 'Key'=>'exampleobject', 'Body'=>''],\n                                         $expires='+30 minutes');\n```\n\nv1:\n```php\n$command = $cosClient->getCommand('putObject', array(\n    'Bucket' => \"examplebucket-1250000000\",\n    'Key' => \"exampleobject\",\n    'Body' => '', \n));\n$signedUrl = $command->createPresignedUrl('+30 minutes');\n```\n\n- `$copSource` parameters of the `Qcloud\\Cos\\Client\\Copy` interface are no longer compatible with older versions.\n\nv2:\n\n```php\n$result = $cosClient->copy( \n    $bucket = '<srcBucket>', \n    $Key = '<srcKey>', \n    $copySorce = array(\n        'Region' => '<sourceRegion>', \n        'Bucket' => '<sourceBucket>', \n        'Key' => '<sourceKey>', \n    )\n);\n```\n\nv1:\n```php\n$result = $cosClient->Copy(\n    $bucket = '<srcBucket>',\n    $key = '<srcKey>', \n    $copysource = '<sourceBucket>.cos.<sourceRegion>.myqcloud.com/<sourceKey>'\n);\n```\n- Now when uploading files with using `open()` to upload stream, if the local file does not exist, a 0 byte file will be uploaded without throwing an exception, only a warning.\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/LICENSE",
    "content": "MIT License\n\nCopyright (c) 2017 腾讯云\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/README.md",
    "content": "# COS-PHP-SDK-V5\n\n腾讯云 COS-PHP-SDK-V5（[XML API](https://cloud.tencent.com/document/product/436/7751)）\n\n[![Latest Stable Version](https://poser.pugx.org/qcloud/cos-sdk-v5/v/stable)](https://packagist.org/packages/qcloud/cos-sdk-v5)\n[![Total Downloads](https://img.shields.io/packagist/dt/qcloud/cos-sdk-v5.svg?style=flat)](https://packagist.org/packages/qcloud/cos-sdk-v5)\n[![Build Status](https://travis-ci.com/tencentyun/cos-php-sdk-v5.svg?branch=master)](https://travis-ci.com/tencentyun/cos-php-sdk-v5)\n[![codecov](https://codecov.io/gh/tencentyun/cos-php-sdk-v5/branch/master/graph/badge.svg)](https://codecov.io/gh/tencentyun/cos-php-sdk-v5)\n\n## 环境准备\n\n- PHP 5.6+ 您可以通过`php -v`命令查看当前的 PHP 版本。\n\n> - 如果您的 php 版本 `>=5.3` 且 `<5.6` , 请使用 [v1.3](https://github.com/tencentyun/cos-php-sdk-v5/tree/1.3) 版本\n\n- cURL 扩展 您可以通过`php -m`命令查看 cURL 扩展是否已经安装好。\n\n> - Ubuntu 系统中，您可以使用 apt-get 包管理器安装 PHP 的 cURL 扩展，安装命令如下。\n\n```\nsudo apt-get install php-curl\n```\n\n> - CentOS 系统中，您可以使用 yum 包管理器安装 PHP 的 cURL 扩展。\n\n```\nsudo yum install php-curl\n```\n\n## SDK 安装\n\nSDK 安装有三种方式：\n\n- Composer 方式\n- Phar 方式\n- 源码方式\n\n### Composer 方式\n\n推荐使用 Composer 安装 cos-php-sdk-v5，Composer 是 PHP 的依赖管理工具，允许您声明项目所需的依赖，然后自动将它们安装到您的项目中。\n\n> 您可以在 [Composer 官网](https://getcomposer.org/) 上找到更多关于如何安装 Composer，配置自动加载以及用于定义依赖项的其他最佳实践等相关信息。\n\n#### 安装步骤：\n\n1. 打开终端。\n2. 下载 Composer，执行以下命令。\n\n```\ncurl -sS https://getcomposer.org/installer | php\n```\n\n3. 创建一个名为`composer.json`的文件，内容如下。\n\n```json\n{\n    \"require\": {\n        \"qcloud/cos-sdk-v5\": \"2.*\"\n    }\n}\n```\n\n4. 使用 Composer 安装，执行以下命令。\n\n```\nphp composer.phar install\n```\n\n使用该命令后会在当前目录中创建一个 vendor 文件夹，里面包含 SDK 的依赖库和一个 autoload.php 脚本，方便在项目中调用。\n\n5. 通过 autoload.php 脚本调用 cos-php-sdk-v5。\n\n```php\nrequire '/path/to/vendor/autoload.php';\n```\n\n现在您的项目已经可以使用 COS 的 V5 版本 SDK 了。\n\n### Phar 方式\n\nPhar 方式安装 SDK 的步骤如下：\n\n1. 在 [GitHub 发布页面](https://github.com/tencentyun/cos-php-sdk-v5/releases) 下载相应的 phar 文件。\n2. 在代码中引入 phar 文件：\n\n```php\nrequire '/path/to/cos-sdk-v5.phar';\n```\n\n### 源码方式\n\n源码方式安装 SDK 的步骤如下：\n\n1.  在 [GitHub 发布页面](https://github.com/tencentyun/cos-php-sdk-v5/releases) 下载相应的 cos-sdk-v5.tar.gz 文件。\n2.  解压后通过 autoload.php 脚本加载 SDK：\n\n```php\nrequire '/path/to/cos-php-sdk-v5/vendor/autoload.php';\n```\n\n## 快速入门\n\n可参照 Demo 程序，详见 [sample 目录](https://github.com/tencentyun/cos-php-sdk-v5/tree/master/sample)。\n\n## 接口文档\n\nPHP SDK 接口文档，详见 [https://cloud.tencent.com/document/product/436/12267](https://cloud.tencent.com/document/product/436/12267)\n\n### 配置文件\n\n```php\n$cosClient = new Qcloud\\Cos\\Client(array(\n    'region' => '<Region>',\n    'credentials' => array(\n        'secretId' => '<SecretId>',\n        'secretKey' => '<SecretKey>'\n    )\n));\n```\n\n若您使用 [临时密钥](https://cloud.tencent.com/document/product/436/14048) 初始化，请用下面方式创建实例。\n\n```php\n$cosClient = new Qcloud\\Cos\\Client(array(\n    'region' => '<Region>',\n    'credentials' => array(\n        'secretId' => '<SecretId>',\n        'secretKey' => '<SecretKey>',\n        'token' => '<XCosSecurityToken>'\n    )\n));\n```\n\n### 上传文件\n\n- 使用 putObject 接口上传文件(最大 5G)\n- 使用 Upload 接口分块上传文件\n\n```php\n# 上传文件\n## putObject(上传接口，最大支持上传5G文件)\n### 上传内存中的字符串\n//bucket 的命名规则为{name}-{appid} ，此处填写的存储桶名称必须为此格式\ntry {\n    $result = $cosClient->putObject(array(\n        'Bucket' => $bucket,\n        'Key' => $key,\n        'Body' => 'Hello World!'));\n    print_r($result);\n} catch (\\Exception $e) {\n    echo \"$e\\n\";\n}\n\n### 上传文件流\ntry {\n    $result = $cosClient->putObject(array(\n        'Bucket' => $bucket,\n        'Key' => $key,\n        'Body' => fopen($local_path, 'rb')));\n    print_r($result);\n} catch (\\Exception $e) {\n    echo \"$e\\n\";\n}\n\n### 设置header和meta\ntry {\n    $result = $cosClient->putObject(array(\n        'Bucket' => $bucket,\n        'Key' => $key,\n        'Body' => fopen($local_path, 'rb'),\n        'ACL' => 'string',\n        'CacheControl' => 'string',\n        'ContentDisposition' => 'string',\n        'ContentEncoding' => 'string',\n        'ContentLanguage' => 'string',\n        'ContentLength' => integer,\n        'ContentType' => 'string',\n        'Expires' => 'mixed type: string (date format)|int (unix timestamp)|\\DateTime',\n        'Metadata' => array(\n            'string' => 'string',\n        ),\n        'StorageClass' => 'string'));\n    print_r($result);\n} catch (\\Exception $e) {\n    echo \"$e\\n\";\n}\n\n## Upload(高级上传接口，默认使用分块上传最大支持50T)\n### 上传内存中的字符串\ntry {\n    $result = $cosClient->Upload(\n        $bucket = $bucket,\n        $key = $key,\n        $body = 'Hello World!');\n    print_r($result);\n} catch (\\Exception $e) {\n    echo \"$e\\n\";\n}\n\n### 上传文件流\ntry {\n    $result = $cosClient->Upload(\n        $bucket = $bucket,\n        $key = $key,\n        $body = fopen($local_path, 'rb'));\n    print_r($result);\n} catch (\\Exception $e) {\n    echo \"$e\\n\";\n}\n\n### 设置header和meta\ntry {\n    $result = $cosClient->Upload(\n        $bucket= $bucket,\n        $key = $key,\n        $body = fopen($local_path, 'rb'),\n        $options = array(\n            'ACL' => 'string',\n            'CacheControl' => 'string',\n            'ContentDisposition' => 'string',\n            'ContentEncoding' => 'string',\n            'ContentLanguage' => 'string',\n            'ContentLength' => integer,\n            'ContentType' => 'string',\n            'Expires' => 'mixed type: string (date format)|int (unix timestamp)|\\DateTime',\n            'Metadata' => array(\n                'string' => 'string',\n            ),\n            'StorageClass' => 'string'));\n    print_r($result);\n} catch (\\Exception $e) {\n    echo \"$e\\n\";\n}\n```\n\n### 下载文件\n\n- 使用 getObject 接口下载文件\n- 使用 getObjectUrl 接口获取文件下载 URL\n\n```php\n# 下载文件\n## getObject(下载文件)\n### 下载到内存\n//bucket 的命名规则为{name}-{appid} ，此处填写的存储桶名称必须为此格式\ntry {\n    $result = $cosClient->getObject(array(\n        'Bucket' => $bucket,\n        'Key' => $key));\n    echo($result['Body']);\n} catch (\\Exception $e) {\n    echo \"$e\\n\";\n}\n\n### 下载到本地\ntry {\n    $result = $cosClient->getObject(array(\n        'Bucket' => $bucket,\n        'Key' => $key,\n        'SaveAs' => $local_path));\n} catch (\\Exception $e) {\n    echo \"$e\\n\";\n}\n\n### 指定下载范围\n/*\n * Range 字段格式为 'bytes=a-b'\n */\ntry {\n    $result = $cosClient->getObject(array(\n        'Bucket' => $bucket,\n        'Key' => $key,\n        'Range' => 'bytes=0-10',\n        'SaveAs' => $local_path));\n} catch (\\Exception $e) {\n    echo \"$e\\n\";\n}\n\n### 设置返回header\ntry {\n    $result = $cosClient->getObject(array(\n        'Bucket' => $bucket,\n        'Key' => $key,\n        'ResponseCacheControl' => 'string',\n        'ResponseContentDisposition' => 'string',\n        'ResponseContentEncoding' => 'string',\n        'ResponseContentLanguage' => 'string',\n        'ResponseContentType' => 'string',\n        'ResponseExpires' => 'mixed type: string (date format)|int (unix timestamp)|\\DateTime',\n        'SaveAs' => $local_path));\n} catch (\\Exception $e) {\n    echo \"$e\\n\";\n}\n\n## getObjectUrl(获取文件UrL)\ntry {\n    $signedUrl = $cosClient->getObjectUrl($bucket, $key, '+10 minutes');\n    echo $signedUrl;\n} catch (\\Exception $e) {\n    print_r($e);\n}\n```\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/composer.json",
    "content": "{\n    \"name\": \"qcloud/cos-sdk-v5\",\n    \"description\": \"PHP SDK for QCloud COS\",\n    \"keywords\": [\n        \"qcloud\", \"cos\", \"php\"\n    ],\n    \"license\": \"MIT\",\n    \"authors\": [\n        {\n            \"name\": \"yaozongyou\",\n            \"email\": \"yaozongyou@vip.qq.com\"\n        },\n        {\n            \"name\": \"lewzylu\",\n            \"email\": \"327874225@qq.com\"\n        }\n    ],\n    \"autoload\": {\n        \"psr-4\": {\n            \"Qcloud\\\\Cos\\\\\": \"src/Qcloud/Cos/\"\n        },\n        \"files\": [\"src/Qcloud/Cos/Common.php\"]\n    },\n    \"require\": {\n        \"php\": \">=5.3.0\",\n        \"guzzlehttp/guzzle\": \"~6.3\",\n        \"guzzlehttp/guzzle-services\": \"~1.1\"\n    }\n}\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/phpunit.xml",
    "content": "<phpunit bootstrap=\"vendor/autoload.php\">\n  <testsuites>\n    <testsuite name=\"cos\">\n      <directory>src/Qcloud/Cos/Tests</directory>\n    </testsuite>\n  </testsuites>\n  <filter>\n    <whitelist addUncoveredFilesFromWhitelist=\"true\">\n      <directory suffix=\".php\">src/</directory>\n    </whitelist>\n  </filter>\n  <logging>\n    <log type=\"coverage-clover\" target=\"clover.xml\"/>\n  </logging>\n</phpunit>\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/abortMultipartUpload.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $result = $cosClient->abortMultipartUpload(array(\n        'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID\n        'Key' => 'exampleobject', \n        'UploadId' => 'string',\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/blindWatermark.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $blindWatermarkTemplate = new Qcloud\\Cos\\ImageParamTemplate\\BlindWatermarkTemplate();\n    $blindWatermarkTemplate->setImage(\"http://examplebucket-125000000.cos.ap-beijing.myqcloud.com/shuiyin.jpeg\");\n    $blindWatermarkTemplate->setType(2);\n    $blindWatermarkTemplate->setLevel(3);\n    $result = $cosClient->getObject(array(\n        'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID\n        'Key' => 'exampleobject',\n        'ImageHandleParam' => $blindWatermarkTemplate->queryString(),\n        'SaveAs' => '/data/exampleobject'\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/catchException.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $result = $cosClient->getBucketAcl(array(\n        'Bucket' => 'examplebucket-125000000' //格式：BucketName-APPID\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    $statusCode = $e->getStatusCode(); // 获取错误码\n    $errorMessage = $e->getMessage(); // 获取错误信息\n    $requestId = $e->getRequestId(); // 获取错误的requestId\n    $errorCode = $e->getCosErrorCode(); // 获取错误名称\n    $request = $e->getRequest(); // 获取完整的请求\n    $response = $e->getResponse(); // 获取完整的响应\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/ciTransformation.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $imageMogrTemplate = new Qcloud\\Cos\\ImageParamTemplate\\ImageMogrTemplate();\n    $imageMogrTemplate->thumbnailByScale(50);\n    $imageMogrTemplate->rotate(50);\n    $imageViewTemplate = new Qcloud\\Cos\\ImageParamTemplate\\ImageViewTemplate();\n    $imageViewTemplate->setMode(1);\n    $imageViewTemplate->setWidth(400);\n    $imageViewTemplate->setHeight(600);\n    $imageViewTemplate->setQuality(1, 85);\n    $ciParamTransformation = new Qcloud\\Cos\\ImageParamTemplate\\CIParamTransformation();\n    $ciParamTransformation->addRule($imageMogrTemplate);\n    $ciParamTransformation->addRule($imageViewTemplate);\n    $result = $cosClient->getObject(array(\n        'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID\n        'Key' => 'exampleobject',\n        'ImageHandleParam' => $ciParamTransformation->queryString(),\n        'SaveAs' => '/data/exampleobject',\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/completeMultipartUpload.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $result = $cosClient->completeMultipartUpload(array(\n        'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID\n        'Key' => 'exampleobject', \n        'UploadId' => 'string',\n        'Parts' => array(\n            array(\n                'ETag' => 'string',\n                'PartNumber' => integer,\n            ),\n            array(\n                'ETag' => 'string',\n                'PartNumber' => integer,\n            )),\n            // ... repeated\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/copy.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\n$local_path = \"/data/exampleobject\";\ntry {\n    $result = $cosClient->copy(\n        $bucket = 'examplebucket-125000000', //格式：BucketName-APPID\n        $key = 'exampleobject',\n        $copySorce = array(\n            'Region' => '<sourceRegion>', \n            'Bucket' => '<sourceBucket>', \n            'Key' => '<sourceKey>', \n        )\n    );\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/copyObject.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $result = $cosClient->copyObject(array(\n        'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID\n        'Key' => 'exampleobject',\n        'CopySource' => 'examplebucket2-125000000.cos.ap-guangzhou.myqcloud.com/exampleobject',\n        'MetadataDirective' => 'Replaced',\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/cosClient.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$token = \"COS_TMPTOKEN\"; //\"云 API 临时密钥 Token\"\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region, //园区\n        'schema' => 'https', //协议头部，默认为http\n        'timeout' => 10, //超时时间\n        'connect_timeout' => 10, //连接超时时间\n        'ip' => '', //ip\n        'port' => '', //端口\n        'endpoint' => '', //endpoint\n        'domain' => '', //自定义域名\n        'proxy' => '', //代理服务器\n        'retry' => 10, //重试次数\n        'userAgent' => '', //UA\n        'allow_redirects' => false, //是否follow302\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey,\n            'token'     => $token,\n            'anonymous' => true, //匿名模式\n        )\n    )\n);\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/createBucket.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $result = $cosClient->createBucket(array(\n        'Bucket' => 'examplebucket-125000000' //格式：BucketName-APPID\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/createFolder.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $result = $cosClient->putObject(array(\n        'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID\n        'Key' => 'folder/',\n        'Body' => \"\",\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/createMultipartUpload.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $result = $cosClient->createMultipartUpload(array(\n        'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID\n        'Key' => 'exampleobject',\n        /*\n        'CacheControl' => 'string',\n        'ContentDisposition' => 'string',\n        'ContentEncoding' => 'string',\n        'ContentLanguage' => 'string',\n        'ContentLength' => integer,\n        'ContentType' => 'string',\n        'Expires' => 'string',\n        'Metadata' => array(\n            'string' => 'string',\n        ),\n        'StorageClass' => 'string'\n        */\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/deleteBucket.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $result = $cosClient->deleteBucket(array(\n        'Bucket' => 'examplebucket-125000000' //格式：BucketName-APPID\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/deleteBucketCors.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $result = $cosClient->deleteBucketCors(array(\n        'Bucket' => 'examplebucket-125000000' //格式：BucketName-APPID\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/deleteBucketDomain.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry { \n    $result = $cosClient->deleteBucketDomain(array( \n        'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID \n    ));\n    // 请求成功 \n    print_r($result); \n} catch (\\Exception $e) { \n    // 请求失败 \n    echo \"$e\\n\"; \n}\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/deleteBucketGuetzli.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $result = $cosClient->DeleteBucketGuetzli(array(\n        'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/deleteBucketImageStyle.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $result = $cosClient->DeleteBucketImageStyle(array(\n        'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/deleteBucketLifecycle.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $result = $cosClient->deleteBucketLifecycle(array(\n        'Bucket' => 'examplebucket-125000000' //格式：BucketName-APPID\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/deleteBucketTagging.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $result = $cosClient->deleteBucketTagging(array(\n        'Bucket' => 'examplebucket-125000000' //格式：BucketName-APPID\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/deleteBucketWebsite.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry { \n    $result = $cosClient->deleteBucketWebsite(array( \n        'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID \n    ));\n    // 请求成功 \n    print_r($result); \n} catch (\\Exception $e) { \n    // 请求失败 \n    echo \"$e\\n\"; \n}\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/deleteFolder.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\n\n$cos_path = \"cos/folder\";\n$nextMarker = '';\n$isTruncated = true;\nwhile ( $isTruncated ) {\n    try {\n        $result = $cosClient->listObjects(\n            ['Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID\n            'Delimiter' => '',\n            'EncodingType' => 'url',\n            'Marker' => $nextMarker,\n            'Prefix' => $cos_path,\n            'MaxKeys' => 1000]\n        );    \n        $isTruncated = $result['IsTruncated'];\n        $nextMarker = $result['NextMarker'];\n        foreach ( $result['Contents'] as $content ) {\n            $cos_file_path = $content['Key'];\n            $local_file_path = $content['Key'];\n            // 按照需求自定义拼接下载路径\n            try {\n                $cosClient->deleteObject(array(\n                    'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID\n                    'Key' => $cos_file_path,\n                ));\n                echo ( $cos_file_path . \"\\n\" );\n            } catch ( \\Exception $e ) {\n                echo( $e );\n            }\n        }\n    } catch ( \\Exception $e ) {\n        echo( $e );\n    }\n}\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/deleteObject.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $result = $cosClient->deleteObject(array(\n        'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID\n        'Key' => 'exampleobject',\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/detectLable.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $result = $cosClient->DetectLabel(array(\n        'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID\n        'Key' => 'exampleobject',\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/download.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\n$local_path = \"/data/exampleobject\";\n\n$printbar = function($totolSize, $downloadedSize) {\n    printf(\"downloaded [%d/%d]\\n\", $downloadedSize, $totolSize);\n};\n\ntry {\n    $result = $cosClient->download(\n        $bucket = 'examplebucket-125000000', //格式：BucketName-APPID\n        $key = 'exampleobject',\n        $saveAs = $local_path,\n        $options=['Progress' => $printbar, //指定进度条\n                  'PartSize' => 10 * 1024 * 1024, //分块大小\n                  'Concurrency' => 5, //并发数\n                  'ResumableDownload' => true, //是否开启断点续传，默认为false\n                  'ResumableTaskFile' => 'tmp.cosresumabletask' //断点文件信息路径，默认为<localpath>.cosresumabletask\n                ]\n    );\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/downloadFolder.php",
    "content": "<?php\n\nrequire dirname( __FILE__ ) . '/../vendor/autoload.php';\n\n$secretId = 'COS_SECRETID';\n//'云 API 密钥 SecretId';\n$secretKey = 'COS_SECRETKEY';\n//'云 API 密钥 SecretKey';\n$region = 'ap-beijing';\n//设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey\n        )\n    )\n);\n$cos_path = 'cos/folder';\n$nextMarker = '';\n$isTruncated = true;\n\nwhile ( $isTruncated ) {\n    try {\n        $result = $cosClient->listObjects(\n            ['Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID\n            'Delimiter' => '',\n            'EncodingType' => 'url',\n            'Marker' => $nextMarker,\n            'Prefix' => $cos_path,\n            'MaxKeys' => 1000]\n        );\n    } catch ( \\Exception $e ) {\n        echo( $e );\n    }\n    $isTruncated = $result['IsTruncated'];\n    $nextMarker = $result['NextMarker'];\n    foreach ( $result['Contents'] as $content ) {\n        $cos_file_path = $content['Key'];\n        $local_file_path = $content['Key'];\n        // 按照需求自定义拼接下载路径\n        try {\n            $result = $cosClient->download(\n                $bucket = 'examplebucket-125000000', //格式：BucketName-APPID\n                $key = $cos_file_path,\n                $saveAs = $local_file_path\n            );\n            echo ( $cos_file_path . \"\\n\" );\n        } catch ( \\Exception $e ) {\n            echo( $e );\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/getBlindWatermark.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\n$local_path = \"/data/exampleobject\";\ntry {\n    $blindWatermarkTemplate = new Qcloud\\Cos\\ImageParamTemplate\\BlindWatermarkTemplate();\n    $blindWatermarkTemplate->setPick();\n    $blindWatermarkTemplate->setImage(\"http://examplebucket-125000000.cos.ap-beijing.myqcloud.com/shuiyin.jpeg\");\n    $blindWatermarkTemplate->setType(2);\n    $picOperationsTemplate = new Qcloud\\Cos\\ImageParamTemplate\\PicOperationsTransformation();\n    $picOperationsTemplate->setIsPicInfo(1);\n    $picOperationsTemplate->addRule($blindWatermarkTemplate, \"resultobject\");\n    $result = $cosClient->putObject(array(\n        'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID\n        'Key' => 'exampleobject',\n        'Body' => fopen($local_path, 'rb'),\n        'PicOperations' => $picOperationsTemplate->queryString(),\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/getBucketAcl.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $result = $cosClient->getBucketAcl(array(\n        'Bucket' => 'examplebucket-125000000' //格式：BucketName-APPID\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/getBucketCors.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $result = $cosClient->getBucketCors(array(\n        'Bucket' => 'examplebucket-125000000' //格式：BucketName-APPID\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/getBucketDomain.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry { \n    $result = $cosClient->getBucketDomain(array( \n        'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID \n    ));\n    // 请求成功 \n    print_r($result); \n} catch (\\Exception $e) { \n    // 请求失败 \n    echo \"$e\\n\"; \n}\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/getBucketGuetzli.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $result = $cosClient->GetBucketGuetzli(array(\n        'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/getBucketImageStyle.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $result = $cosClient->GetBucketImageStyle(array(\n        'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID\n        'StyleName' => 'stylename',\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/getBucketInventory.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $result = $cosClient->getBucketInvnetory(array(\n        'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID\n        'Id' => 'string',\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/getBucketLifecycle.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $result = $cosClient->getBucketLifecycle(array(\n        'Bucket' => 'examplebucket-125000000' //格式：BucketName-APPID\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/getBucketLogging.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $result = $cosClient->getBucketLogging(array(\n        'Bucket' => 'examplebucket-125000000' //格式：BucketName-APPID\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/getBucketTagging.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $result = $cosClient->getBucketTagging(array(\n        'Bucket' => 'examplebucket-125000000' //格式：BucketName-APPID\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/getBucketWebsite.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry { \n    $result = $cosClient->getBucketWebsite(array( \n        'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID \n    ));\n    // 请求成功 \n    print_r($result); \n} catch (\\Exception $e) { \n    // 请求失败 \n    echo \"$e\\n\"; \n}\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/getObject.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $result = $cosClient->getObject(array(\n        'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID\n        'Key' => 'exampleobject',\n        'SaveAs' => '/data/exampleobject',\n        /*\n        'Range' => 'bytes=0-10',\n        'ResponseCacheControl' => 'string',\n        'ResponseContentDisposition' => 'string',\n        'ResponseContentEncoding' => 'string',\n        'ResponseContentLanguage' => 'string',\n        'ResponseContentType' => 'string',\n        'ResponseExpires' => 'string',\n        */\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/getObjectUrl.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials' => array(\n            'secretId' => $secretId,\n            'secretKey' => $secretKey\n        )\n    )\n);\n$local_path = \"/data/exampleobject\";\n\ntry {\n    $bucket = \"examplebucket-1250000000\"; //存储桶，格式：BucketName-APPID\n    $key = \"exampleobject\"; //对象在存储桶中的位置，即对象键\n    $signedUrl = $cosClient->getObjectUrl(\n        $bucket,\n        $key,\n        '+10 minutes', //签名的有效时间\n        [\n            'ResponseContentDisposition' => '111',\n            'Params' => [ // Params中可以传自定义querystring\n                'aaa' => 'bbb',\n                'ccc' => 'ddd'\n            ]\n        ]\n    );\n    // 请求成功\n    echo $signedUrl;\n} catch (\\Exception $e) {\n    // 请求失败\n    print_r($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/getPresignedUrl.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\n$local_path = \"/data/exampleobject\";\ntry {\n    $signedUrl = $cosClient->getPresignedUrl(\n                                $method='putObject',\n                                $args=['Bucket'=>'examplebucket-1250000000', //格式：BucketName-APPID\n                                       'Key'=>'exampleobject',\n                                       'Body'=>''],\n                                $expires='+30 minutes\"');\n    // 请求成功\n    echo($signedUrl);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/headBucket.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $result = $cosClient->headBucket(array(\n        'Bucket' => 'examplebucket-125000000' //格式：BucketName-APPID\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/headObject.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $result = $cosClient->headObject(array(\n        'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID\n        'Key' => 'exampleobject',\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/imageAve.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $result = $cosClient->ImageAve(array(\n        'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID\n        'Key' => 'exampleobject',\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/imageExif.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $result = $cosClient->ImageExif(array(\n        'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID\n        'Key' => 'exampleobject',\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/imageInfo.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $result = $cosClient->ImageInfo(array(\n        'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID\n        'Key' => 'exampleobject',\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/imageMogr.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $imageMogrTemplate = new Qcloud\\Cos\\ImageParamTemplate\\ImageMogrTemplate();\n    $imageMogrTemplate->thumbnailByScale(50);\n    $imageMogrTemplate->rotate(50);\n    $result = $cosClient->getObject(array(\n        'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID\n        'Key' => 'exampleobject',\n        'ImageHandleParam' => $imageMogrTemplate->queryString(),\n        'SaveAs' => '/data/exampleobject',\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/imageProcess.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $imageMogrTemplate = new Qcloud\\Cos\\ImageParamTemplate\\ImageMogrTemplate();\n    $imageMogrTemplate->thumbnailByScale(50);\n    $picOperationsTemplate = new Qcloud\\Cos\\ImageParamTemplate\\PicOperationsTransformation();\n    $picOperationsTemplate->setIsPicInfo(1);\n    $picOperationsTemplate->addRule($imageMogrTemplate, \"resultobject\");\n    $result = $cosClient->ImageProcess(array(\n        'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID\n        'Key' => 'exampleobject',\n        'PicOperations' => $picOperationsTemplate->queryString(),\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/imageView.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $imageViewTemplate = new Qcloud\\Cos\\ImageParamTemplate\\ImageViewTemplate();\n    $imageViewTemplate->setMode(1);\n    $imageViewTemplate->setWidth(400);\n    $imageViewTemplate->setHeight(600);\n    $imageViewTemplate->setQuality(1, 85);\n    $result = $cosClient->getObject(array(\n        'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID\n        'Key' => 'exampleobject',\n        'ImageHandleParam' => $imageViewTemplate->queryString(),\n        'SaveAs' => '/data/exampleobject'\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/imageWatermark.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $imageWatermarkTemplate = new Qcloud\\Cos\\ImageParamTemplate\\ImageWatermarkTemplate();\n    $imageWatermarkTemplate->setImage(\"http://examplebucket-125000000.cos.ap-beijing.myqcloud.com/shuiyin.jpeg\");\n    $imageWatermarkTemplate->setGravity('center');\n    $imageWatermarkTemplate->setDx(10);\n    $imageWatermarkTemplate->setDy(10);\n    $imageWatermarkTemplate->setSpcent(100);\n    $result = $cosClient->getObject(array(\n        'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID\n        'Key' => 'exampleobject',\n        'ImageHandleParam' => $imageWatermarkTemplate->queryString(),\n        'SaveAs' => '/data/exampleobject'\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/listBucket.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\n\ntry {\n    $result = $cosClient->listBuckets();\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/listMultipartUploads.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $result = $cosClient->listMultipartUploads(array(\n        'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID\n        'Delimiter' => '/',\n        'EncodingType' => 'url',\n        'KeyMarker' => 'string',\n        'UploadIdMarker' => 'string',\n        'Prefix' => 'prfix',\n        'MaxUploads' => 1000,\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/listObjects.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $result = $cosClient->listObjects(array(\n        'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID\n        'Delimiter' => '/',\n        'EncodingType' => 'url',\n        'Marker' => 'prefix/picture.jpg',\n        'Prefix' => 'prfix',\n        'MaxKeys' => 1000,\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/listParts.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $result = $cosClient->listParts(array(\n        'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID\n        'Key' => 'exampleobject',\n        'UploadId' => 'NWNhNDY0YzFfMmZiNTM1MGFfNTM2YV8xYjliMTg',\n        'PartNumberMarker' => 1,\n        'MaxParts' => 1000,\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/picOperations.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\n$local_path = \"/data/exampleobject\";\ntry {\n    $imageMogrTemplate = new Qcloud\\Cos\\ImageParamTemplate\\ImageMogrTemplate();\n    $imageMogrTemplate->thumbnailByScale(50);\n    $picOperationsTemplate = new Qcloud\\Cos\\ImageParamTemplate\\PicOperationsTransformation();\n    $picOperationsTemplate->setIsPicInfo(0);\n    $picOperationsTemplate->addRule($imageMogrTemplate, \"resultobject\");\n    $result = $cosClient->putObject(array(\n        'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID\n        'Key' => 'exampleobject',\n        'Body' => fopen($local_path, 'rb'),\n        'PicOperations' => $picOperationsTemplate->queryString(),\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/putBlindWatermark.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\n$local_path = \"/data/exampleobject\";\ntry {\n    $blindWatermarkTemplate = new Qcloud\\Cos\\ImageParamTemplate\\BlindWatermarkTemplate();\n    $blindWatermarkTemplate->setText(\"Test\");\n    $blindWatermarkTemplate->setType(3);\n    $picOperationsTemplate = new Qcloud\\Cos\\ImageParamTemplate\\PicOperationsTransformation();\n    $picOperationsTemplate->setIsPicInfo(1);\n    $picOperationsTemplate->addRule($blindWatermarkTemplate, \"resultobject\");\n    $result = $cosClient->putObject(array(\n        'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID\n        'Key' => 'exampleobject',\n        'Body' => fopen($local_path, 'rb'),\n        'PicOperations' => $picOperationsTemplate->queryString(),\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/putBucketAcl.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $result = $cosClient->putBucketAcl(array(\n        //bucket的命名规则为{name}-{appid} ，此处填写的存储桶名称必须为此格式\n        'Bucket' => 'examplebucket-125000000',\n        'ACL' => 'private',\n        'Grants' => array(\n            array(\n                'Grantee' => array(\n                    'DisplayName' => 'qcs::cam::uin/100000000001:uin/100000000001',\n                    'ID' => 'qcs::cam::uin/100000000001:uin/100000000001',\n                    'Type' => 'CanonicalUser',\n                ),\n                'Permission' => 'FULL_CONTROL',\n            ),\n            // ... repeated\n        ),\n        'Owner' => array(\n            'DisplayName' => 'qcs::cam::uin/3210232098:uin/3210232098',\n            'ID' => 'qcs::cam::uin/3210232098:uin/3210232098',\n        )));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo \"$e\\n\";\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/putBucketCors.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $result = $cosClient->putBucketCors(array(\n        'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID\n        'CORSRules' => array(\n            array(\n                'ID' => '1234',\n                'AllowedHeaders' => array('*'),\n                'AllowedMethods' => array('PUT'),\n                'AllowedOrigins' => array('http://www.qq.com'),\n            ),\n        ), \n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo \"$e\\n\";\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/putBucketDomain.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry { \n    $result = $cosClient->putBucketDomain(array( \n        'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID \n        'DomainRules' => array( \n            array( \n                'Name' => 'www.qq.com', \n                'Status' => 'ENABLED', \n                'Type' => 'REST', \n                'ForcedReplacement' => 'CNAME', \n            ),  \n            // ... repeated \n        ),  \n    )); \n    // 请求成功 \n    print_r($result); \n} catch (\\Exception $e) { \n    // 请求失败 \n    echo \"$e\\n\"; \n}\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/putBucketGuetzli.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $result = $cosClient->PutBucketGuetzli(array(\n        'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/putBucketImageStyle.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $result = $cosClient->PutBucketImageStyle(array(\n        'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID\n        'StyleName' => 'stylename',\n        'StyleBody' => 'imageMogr2/thumbnail/!50px',\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/putBucketInventory.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $result = $cosClient->putBucketInventory(array(\n        'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID\n        'Id' => 'string',\n        'Destination' => array(\n            'COSBucketDestination'=>array(\n                'Format' => 'CSV',\n                'AccountId' => '125000000',\n                'Bucket' => 'qcs::cos:ap-chengdu::examplebucket-125000000',\n                'Prefix' => 'string',\n            )\n        ),      \n        'IsEnabled' => 'True',\n        'Schedule' => array(\n            'Frequency' => 'Daily',\n        ),  \n        'Filter' => array(\n            'Prefix' => 'string',\n        ),  \n        'IncludedObjectVersions' => 'Current',\n        'OptionalFields' => array(\n            'Size', \n            'ETag',\n        )\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo \"$e\\n\";\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/putBucketLifecycle.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $result = $cosClient->putBucketLifecycle(array(\n        'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID\n        'Rules' => array(\n            array(\n                'Expiration' => array(\n                    'Days' => integer,\n                ),  \n                'ID' => 'string',\n                'Filter' => array(\n                    'Prefix' => 'string'\n                ),  \n                'Status' => 'string',\n                'Transitions' => array(\n                    array(\n                        'Days' => integer,\n                        'StorageClass' => 'string'\n                    ),  \n                    // ... repeated\n                ),  \n            ),  \n            // ... repeated\n        )\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo \"$e\\n\";\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/putBucketLogging.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $result = $cosClient->putBucketLogging(array(\n        'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID\n        'LoggingEnabled' => array(\n            'TargetBucket' => 'examplebucket2-125000000', //格式：BucketName-APPID\n            'TargetPrefix' => '', \n        )   \n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo \"$e\\n\";\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/putBucketTagging.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $result = $cosClient->putBucketTagging(array(\n        'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID\n        'TagSet' => array(\n            array('Key'=>'key1',\n                  'Value'=>'value1',\n            ),  \n            array('Key'=>'key2',\n                  'Value'=>'value2',\n            ),  \n        ),  \n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo \"$e\\n\";\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/putBucketWebsite.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\n\ntry {\n    $result = $cosClient->putBucketWebsite(array(\n        'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID\n        'IndexDocument' => array(\n            'Suffix' => 'index.html',\n        ),\n        'RedirectAllRequestsTo' => array(\n            'Protocol' => 'https',\n        ),\n        'ErrorDocument' => array(\n            'Key' => 'Error.html',\n        ),\n        'RoutingRules' => array(\n            array(\n                'Condition' => array(\n                    'HttpErrorCodeReturnedEquals' => '405',\n                ),\n                'Redirect' => array(\n                    'Protocol' => 'https',\n                    'ReplaceKeyWith' => '404.html',\n                ),\n            ),  \n            // ... repeated\n        ),  \n    )); \n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo \"$e\\n\";\n}\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/putImageStyle.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\n$local_path = \"/data/exampleobject\";\ntry {\n    $imageStyleTemplate = new Qcloud\\Cos\\ImageParamTemplate\\ImageStyleTemplate();\n    $imageStyleTemplate->setStyle(\"stylename\");\n    $picOperationsTemplate = new \\Qcloud\\Cos\\ImageParamTemplate\\PicOperationsTransformation();\n    $picOperationsTemplate->setIsPicInfo(1);\n    $picOperationsTemplate->addRule($imageStyleTemplate, \"resultobject\");\n    $result = $cosClient->putObject(array(\n        'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID\n        'Key' => 'exampleobject',\n        'Body' => fopen($local_path, 'rb'),\n        'PicOperations' => $picOperationsTemplate->queryString(),\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/putObject.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\n$local_path = \"/data/exampleobject\";\ntry {\n    $result = $cosClient->putObject(array(\n        'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID\n        'Key' => 'exampleobject',\n        'Body' => fopen($local_path, 'rb'),\n        /*\n        'CacheControl' => 'string',\n        'ContentDisposition' => 'string',\n        'ContentEncoding' => 'string',\n        'ContentLanguage' => 'string',\n        'ContentLength' => integer,\n        'ContentType' => 'string',\n        'Expires' => 'string',\n        'Metadata' => array(\n            'string' => 'string',\n        ),\n        'StorageClass' => 'string'\n        */\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/putQrcode.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\n$local_path = \"/data/exampleobject\";\ntry {\n    $imageQrcodeTemplate = new Qcloud\\Cos\\ImageParamTemplate\\ImageQrcodeTemplate();\n    $imageQrcodeTemplate->setMode(0);\n    $picOperationsTemplate = new Qcloud\\Cos\\ImageParamTemplate\\PicOperationsTransformation();\n    $picOperationsTemplate->setIsPicInfo(1);\n    $picOperationsTemplate->addRule($imageQrcodeTemplate, \"resultobject\");\n    $result = $cosClient->putObject(array(\n        'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID\n        'Key' => 'exampleobject',\n        'Body' => fopen($local_path, 'rb'),\n        'PicOperations' => $picOperationsTemplate->queryString(),\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/qrcode.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $result = $cosClient->Qrcode(array(\n        'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID\n        'Key' => 'exampleobject',\n        'Cover' => 0,\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/qrcodeGenerate.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $result = $cosClient->QrcodeGenerate(array(\n        'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID\n        'QrcodeContent' => '<https://www.baidu.com>',\n        'QrcodeMode' => 0,\n        'QrcodeWidth' => '200',\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/restoreObject.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $result = $cosClient->restoreObject(array(\n        'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID\n        'Key' => 'exampleobject',\n        'Days' => integer,\n        'CASJobParameters' => array(\n            'Tier' =>'string'\n        )      \n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/selectObjectContent.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(array(\n    'region' => $region,\n    'schema' => 'https', //协议头部，默认为http\n    'credentials'=> array(\n        'secretId'  => $secretId ,\n        'secretKey' => $secretKey\n    )\n));\ntry { \n    $result = $cosClient->selectObjectContent(array( \n        'Bucket' => $bucket, //格式：BucketName-APPID\n        'Key' => $key, \n        'Expression' => 'Select * from COSObject s', \n        'ExpressionType' => 'SQL', \n        'InputSerialization' => array( \n            'CompressionType' => 'None', \n            'CSV' => array( \n                'FileHeaderInfo' => 'NONE', \n                'RecordDelimiter' => '\\n', \n                'FieldDelimiter' => ',', \n                'QuoteEscapeCharacter' => '\"', \n                'Comments' => '#', \n                'AllowQuotedRecordDelimiter' => 'FALSE' \n                )   \n            ),  \n        'OutputSerialization' => array( \n            'CSV' => array( \n                'QuoteField' => 'ASNEEDED', \n                'RecordDelimiter' => '\\n', \n                'FieldDelimiter' => ',', \n                'QuoteCharacter' => '\"', \n                'QuoteEscapeCharacter' => '\"' \n                )   \n            ),  \n        'RequestProgress' => array( \n                'Enabled' => 'FALSE' \n        )   \n    ));  \n    // 请求成功\n    foreach ($result['Data'] as $data) { \n        // 迭代遍历select结果\n        print_r($data); \n    }\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e); \n}\n\ntry { \n    $result = $cosClient->selectObjectContent(array( \n        'Bucket' => $bucket, //格式：BucketName-APPID\n        'Key' => $key, \n        'Expression' => 'Select * from COSObject s', \n        'ExpressionType' => 'SQL', \n        'InputSerialization' => array( \n            'CompressionType' => 'None', \n            'JSON' => array( \n                'Type' => 'DOCUMENT'\n                )   \n            ),  \n        'OutputSerialization' => array( \n            'JSON' => array( \n                'RecordDelimiter' => '\\n', \n                )   \n            ),  \n        'RequestProgress' => array( \n            'Enabled' => 'FALSE' \n        )   \n    ));  \n    // 请求成功\n    foreach ($result['Data'] as $data) { \n        // 迭代遍历select结果\n        print_r($data); \n    }\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e); \n}\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/textWatermark.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $textWatermarkTemplate = new Qcloud\\Cos\\ImageParamTemplate\\TextWatermarkTemplate();\n    $textWatermarkTemplate->setText(\"testetst\");\n    $textWatermarkTemplate->setGravity('center');\n    $textWatermarkTemplate->setFontsize(30);\n    $result = $cosClient->getObject(array(\n        'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID\n        'Key' => 'exampleobject',\n        'ImageHandleParam' => $textWatermarkTemplate->queryString(),\n        'SaveAs' => '/data/exampleobject'\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/upload.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\n$local_path = \"/data/exampleobject\";\n\n$printbar = function($totolSize, $uploadedSize) {\n    printf(\"uploaded [%d/%d]\\n\", $uploadedSize, $totolSize);\n};\n\ntry {\n    $result = $cosClient->upload(\n        $bucket = 'examplebucket-125000000', //格式：BucketName-APPID\n        $key = 'exampleobject',\n        $body = fopen($local_path, 'rb')\n        /*\n        $options = array(\n            'ACL' => 'string',\n            'CacheControl' => 'string',\n            'ContentDisposition' => 'string',\n            'ContentEncoding' => 'string',\n            'ContentLanguage' => 'string',\n            'ContentLength' => integer,\n            'ContentType' => 'string',\n            'Expires' => 'string',\n            'GrantFullControl' => 'string',\n            'GrantRead' => 'string',\n            'GrantWrite' => 'string',\n            'Metadata' => array(\n                'string' => 'string',\n            ),\n            'ContentMD5' => 'string',\n            'ServerSideEncryption' => 'string',\n            'StorageClass' => 'string', //存储类型\n            'Progress' => $printbar, //指定进度条\n            'PartSize' => 10 * 1024 * 1024, //分块大小\n            'Concurrency' => 5 //并发数\n        )\n        */\n    );\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/uploadFolder.php",
    "content": "<?php\n\nrequire dirname( __FILE__ ) . '/../vendor/autoload.php';\n\n$secretId = 'COS_SECRETID';\n//'云 API 密钥 SecretId';\n$secretKey = 'COS_SECRETKEY';\n//'云 API 密钥 SecretKey';\n$region = 'ap-beijing';\n//设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey\n        )\n    )\n);\n\nfunction uploadfiles( $path, $cosClient ) {\n    foreach ( scandir( $path ) as $afile ) {\n        if ( $afile == '.' || $afile == '..' ) continue;\n        if ( is_dir( $path.'/'.$afile ) ) {\n            uploadfiles( $path.'/'.$afile, $cosClient );\n        } else {\n            $local_file_path = $path.'/'.$afile;\n            $cos_file_path = $local_file_path;\n            // 按照需求自定义拼接上传路径\n            try {\n                $cosClient->upload(\n                    $bucket = 'examplebucket-125000000', //格式：BucketName-APPID\n                    $key = $cos_file_path,\n                    $body = fopen( $cos_file_path, 'rb' )\n                );\n            } catch ( \\Exception $e ) {\n                echo( $e );\n            }\n        }\n    }\n}\n\n$local_path = '/data/home/folder';\nuploadfiles( $local_path, $cosClient );"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/sample/uploadPart.php",
    "content": "<?php\n\nrequire dirname(__FILE__) . '/../vendor/autoload.php';\n\n$secretId = \"COS_SECRETID\"; //\"云 API 密钥 SecretId\";\n$secretKey = \"COS_SECRETKEY\"; //\"云 API 密钥 SecretKey\";\n$region = \"ap-beijing\"; //设置一个默认的存储桶地域\n$cosClient = new Qcloud\\Cos\\Client(\n    array(\n        'region' => $region,\n        'schema' => 'https', //协议头部，默认为http\n        'credentials'=> array(\n            'secretId'  => $secretId ,\n            'secretKey' => $secretKey)));\ntry {\n    $result = $cosClient->uploadPart(array(\n        'Bucket' => 'examplebucket-125000000', //格式：BucketName-APPID\n        'Key' => 'exampleobject', \n        'Body' => 'string',\n        'UploadId' => 'NWNhNDY0YzFfMmZiNTM1MGFfNTM2YV8xYjliMTg',\n        'PartNumber' => 1,\n        'ContentMD5' => 'string',\n        'ContentLength' => 100,\n    ));\n    // 请求成功\n    print_r($result);\n} catch (\\Exception $e) {\n    // 请求失败\n    echo($e);\n}\n\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/src/Qcloud/Cos/Client.php",
    "content": "<?php\n\nnamespace Qcloud\\Cos;\n\nuse Qcloud\\Cos\\Signature;\nuse GuzzleHttp\\Client as HttpClient;\nuse GuzzleHttp\\HandlerStack;\nuse Psr\\Http\\Message\\RequestInterface;\nuse Psr\\Http\\Message\\ResponseInterface;\nuse GuzzleHttp\\Command\\Guzzle\\Description;\nuse GuzzleHttp\\Command\\Guzzle\\GuzzleClient;\nuse GuzzleHttp\\Command\\Guzzle\\Deserializer;\nuse GuzzleHttp\\Exception\\RequestException;\nuse GuzzleHttp\\Command\\CommandInterface;\nuse GuzzleHttp\\Command\\Exception\\CommandException;\nuse GuzzleHttp\\Exception\\ConnectException;\nuse GuzzleHttp\\Middleware;\nuse GuzzleHttp\\Psr7;\n\n/**\n * @method object AbortMultipartUpload (array $arg)\n * @method object CreateBucket (array $arg)\n * @method object CompleteMultipartUpload (array $arg)\n * @method object CreateMultipartUpload (array $arg)\n * @method object CopyObject (array $arg)\n * @method object DeleteBucket (array $arg)\n * @method object DeleteBucketCors (array $arg)\n * @method object DeleteBucketTagging (array $arg)\n * @method object DeleteBucketInventory (array $arg)\n * @method object DeleteObject (array $arg)\n * @method object DeleteObjects (array $arg)\n * @method object DeleteBucketWebsite (array $arg)\n * @method object DeleteBucketLifecycle (array $arg)\n * @method object DeleteBucketReplication (array $arg)\n * @method object GetObject (array $arg)\n * @method object GetObjectAcl (array $arg)\n * @method object GetBucketAcl (array $arg)\n * @method object GetBucketCors (array $arg)\n * @method object GetBucketDomain (array $arg)\n * @method object GetBucketAccelerate (array $arg)\n * @method object GetBucketWebsite (array $arg)\n * @method object GetBucketLifecycle (array $arg)\n * @method object GetBucketVersioning (array $arg)\n * @method object GetBucketReplication (array $arg)\n * @method object GetBucketLocation (array $arg)\n * @method object GetBucketNotification (array $arg)\n * @method object GetBucketLogging (array $arg)\n * @method object GetBucketInventory (array $arg)\n * @method object GetBucketTagging (array $arg)\n * @method object UploadPart (array $arg)\n * @method object PutObject (array $arg)\n * @method object PutObjectAcl (array $arg)\n * @method object PutBucketAcl (array $arg)\n * @method object PutBucketCors (array $arg)\n * @method object PutBucketDomain (array $arg)\n * @method object PutBucketLifecycle (array $arg)\n * @method object PutBucketVersioning (array $arg)\n * @method object PutBucketAccelerate (array $arg)\n * @method object PutBucketWebsite (array $arg)\n * @method object PutBucketReplication (array $arg)\n * @method object PutBucketNotification (array $arg)\n * @method object PutBucketTagging (array $arg)\n * @method object PutBucketLogging (array $arg)\n * @method object PutBucketInventory (array $arg)\n * @method object RestoreObject (array $arg)\n * @method object ListParts (array $arg)\n * @method object ListObjects (array $arg)\n * @method object ListBuckets\n * @method object ListObjectVersions (array $arg)\n * @method object ListMultipartUploads (array $arg)\n * @method object ListBucketInventoryConfigurations (array $arg)\n * @method object HeadObject (array $arg)\n * @method object HeadBucket (array $arg)\n * @method object UploadPartCopy (array $arg)\n * @method object SelectObjectContent (array $arg)\n * @method object PutBucketIntelligentTiering (array $arg)\n * @method object GetBucketIntelligentTiering (array $arg)\n * @method object ImageInfo (array $arg)\n * @method object ImageExif (array $arg)\n * @method object ImageAve (array $arg)\n * @method object ImageProcess (array $arg)\n * @method object Qrcode (array $arg)\n * @method object QrcodeGenerate (array $arg)\n * @method object DetectLabel (array $arg)\n * @method object PutBucketImageStyle (array $arg)\n * @method object GetBucketImageStyle (array $arg)\n * @method object DeleteBucketImageStyle (array $arg)\n * @method object PutBucketGuetzli (array $arg)\n * @method object GetBucketGuetzli (array $arg)\n * @method object DeleteBucketGuetzli (array $arg)\n */\nclass Client extends GuzzleClient {\n    const VERSION = '2.2.0';\n\n    public $httpClient;\n    \n    private $api;\n    private $desc;\n    private $action;\n    private $operation;\n    private $cosConfig;\n    private $signature;\n    private $rawCosConfig;\n\n    public function __construct($cosConfig) {\n        $this->rawCosConfig = $cosConfig;\n        $this->cosConfig['schema'] = isset($cosConfig['schema']) ? $cosConfig['schema'] : 'http';\n        $this->cosConfig['region'] = region_map($cosConfig['region']);\n        $this->cosConfig['appId'] = isset($cosConfig['credentials']['appId']) ? $cosConfig['credentials']['appId'] : null;\n        $this->cosConfig['secretId'] = isset($cosConfig['credentials']['secretId']) ? $cosConfig['credentials']['secretId'] : \"\";\n        $this->cosConfig['secretKey'] = isset($cosConfig['credentials']['secretKey']) ? $cosConfig['credentials']['secretKey'] : \"\";\n        $this->cosConfig['anonymous'] = isset($cosConfig['credentials']['anonymous']) ? $cosConfig['anonymous']['anonymous'] : false;\n        $this->cosConfig['token'] = isset($cosConfig['credentials']['token']) ? $cosConfig['credentials']['token'] : null;\n        $this->cosConfig['timeout'] = isset($cosConfig['timeout']) ? $cosConfig['timeout'] : 3600;\n        $this->cosConfig['connect_timeout'] = isset($cosConfig['connect_timeout']) ? $cosConfig['connect_timeout'] : 3600;\n        $this->cosConfig['ip'] = isset($cosConfig['ip']) ? $cosConfig['ip'] : null;\n        $this->cosConfig['port'] = isset($cosConfig['port']) ? $cosConfig['port'] : null;\n        $this->cosConfig['endpoint'] = isset($cosConfig['endpoint']) ? $cosConfig['endpoint'] : null;\n        $this->cosConfig['domain'] = isset($cosConfig['domain']) ? $cosConfig['domain'] : null;\n        $this->cosConfig['proxy'] = isset($cosConfig['proxy']) ? $cosConfig['proxy'] : null;\n        $this->cosConfig['retry'] = isset($cosConfig['retry']) ? $cosConfig['retry'] : 1;\n        $this->cosConfig['userAgent'] = isset($cosConfig['userAgent']) ? $cosConfig['userAgent'] : 'cos-php-sdk-v5.'. Client::VERSION;\n        $this->cosConfig['pathStyle'] = isset($cosConfig['pathStyle']) ? $cosConfig['pathStyle'] : false;\n        $this->cosConfig['allow_redirects'] = isset($cosConfig['allow_redirects']) ? $cosConfig['allow_redirects'] : false;\n        \n        $service = Service::getService();\n        $handler = HandlerStack::create();\n        $handler->push(Middleware::retry($this->retryDecide(), $this->retryDelay()));\n\t\t$handler->push(Middleware::mapRequest(function (RequestInterface $request) {\n\t\t\treturn $request->withHeader('User-Agent', $this->cosConfig['userAgent']);\n        }));\n        if ($this->cosConfig['anonymous'] != true) {\n            $handler->push($this::handleSignature($this->cosConfig['secretId'], $this->cosConfig['secretKey']));\n        }\n        if ($this->cosConfig['token'] != null) {\n            $handler->push(Middleware::mapRequest(function (RequestInterface $request) {\n                return $request->withHeader('x-cos-security-token', $this->cosConfig['token']);\n            }));\n        }\n        $handler->push($this::handleErrors());\n        $this->signature = new Signature($this->cosConfig['secretId'], $this->cosConfig['secretKey'], $this->cosConfig['token']);\n        $this->httpClient = new HttpClient([\n            'base_uri' => $this->cosConfig['schema'].'://cos.' . $this->cosConfig['region'] . '.myqcloud.com/',\n            'timeout' => $this->cosConfig['timeout'],\n            'handler' => $handler,\n            'proxy' => $this->cosConfig['proxy'],\n            'allow_redirects' => $this->cosConfig['allow_redirects']\n        ]);\n        $this->desc = new Description($service);\n        $this->api = (array)($this->desc->getOperations());\n        parent::__construct($this->httpClient, $this->desc, [$this,\n        'commandToRequestTransformer'], [$this, 'responseToResultTransformer'],\n        null);\n    }\n    public function retryDecide() {\n      return function (\n        $retries,\n        RequestInterface $request,\n        ResponseInterface $response = null,\n        \\Exception $exception = null\n      ) {\n        if ($retries >= $this->cosConfig['retry']) {\n          return false;\n        }\n        if ($response != null && $response->getStatusCode() >= 400 ) {\n            return true;\n        }\n        if ($exception instanceof \\Qcloud\\Cos\\Exception\\ServiceResponseException) {\n            if ($exception->getStatusCode() >= 400) {\n                return true;\n            }\n        }\n  \n        if ($exception instanceof ConnectException) {\n          return true;\n        }\n  \n        return false;\n      };\n    }\n\n    public function retryDelay() {\n        return function ($numberOfRetries) {\n        return 1000 * $numberOfRetries;\n        };\n    }\n    public function commandToRequestTransformer(CommandInterface $command)\n    {\n        $this->action = $command->GetName();\n        $this->operation = $this->api[$this->action];\n        $transformer = new CommandToRequestTransformer($this->cosConfig, $this->operation); \n        $seri = new Serializer($this->desc);\n        $request = $seri($command);\n        $request = $transformer->bucketStyleTransformer($command, $request);\n        $request = $transformer->uploadBodyTransformer($command, $request);\n        $request = $transformer->metadataTransformer($command, $request);\n        $request = $transformer->queryStringTransformer($command, $request);\n        $request = $transformer->md5Transformer($command, $request);\n        $request = $transformer->specialParamTransformer($command, $request);\n        $request = $transformer->ciParamTransformer($command, $request);\n        return $request;\n    }\n\n    public function responseToResultTransformer(ResponseInterface $response, RequestInterface $request, CommandInterface $command)\n    {\n        $transformer = new ResultTransformer($this->cosConfig, $this->operation); \n        $transformer->writeDataToLocal($command, $request, $response);\n        $deseri = new Deserializer($this->desc, true);\n        $result = $deseri($response, $request, $command);\n\n        $result = $transformer->metaDataTransformer($command, $response, $result);\n        $result = $transformer->extraHeadersTransformer($command, $request, $result);\n        $result = $transformer->selectContentTransformer($command, $result);\n        $result = $transformer->ciContentInfoTransformer($command, $result);\n        return $result;\n    }\n    \n    public function __destruct() {\n    }\n\n    public function __call($method, array $args) {\n        try {\n            $rt = parent::__call(ucfirst($method), $args);\n            return $rt;\n        } catch (\\Exception $e) {\n            $previous = $e->getPrevious();\n            if ($previous !== null) {\n                throw $previous;\n            } else {\n                throw $e;\n            }\n        }\n    }\n\n    public function getApi() {\n        return $this->api;\n    }\n\n    private function getCosConfig() {\n        return $this->cosConfig;\n    }\n\n    private function createPresignedUrl(RequestInterface $request, $expires) {\n        return $this->signature->createPresignedUrl($request, $expires);\n    }\n\n    public function getPresignetUrl($method, $args, $expires = \"+30 minutes\") {\n        return $this->getPresignedUrl($method, $args, $expires);\n    }\n\n    public function getPresignedUrl($method, $args, $expires = \"+30 minutes\") {\n        $command = $this->getCommand($method, $args);\n        $request = $this->commandToRequestTransformer($command);\n        return $this->createPresignedUrl($request, $expires);\n    }\n\n\n    public function getObjectUrl($bucket, $key, $expires = \"+30 minutes\", array $args = array()) {\n        $command = $this->getCommand('GetObject', $args + array('Bucket' => $bucket, 'Key' => $key));\n        $request = $this->commandToRequestTransformer($command);\n        return $this->createPresignedUrl($request, $expires)->__toString();\n    }\n\n    public function upload($bucket, $key, $body, $options = array()) {\n        $body = Psr7\\stream_for($body);\n        $options['Retry'] = $this->cosConfig['retry'];\n        $options['PartSize'] = isset($options['PartSize']) ? $options['PartSize'] : MultipartUpload::DEFAULT_PART_SIZE;\n        if ($body->getSize() < $options['PartSize']) {\n            $rt = $this->putObject(array(\n                    'Bucket' => $bucket,\n                    'Key'    => $key,\n                    'Body'   => $body,\n                ) + $options);\n        }\n        else {\n            $multipartUpload = new MultipartUpload($this, $body, array(\n                    'Bucket' => $bucket,\n                    'Key' => $key,\n                ) + $options);\n\n            $rt = $multipartUpload->performUploading();\n        }\n        return $rt;\n    }\n\n    public function download($bucket, $key, $saveAs, $options = array()) {\n        $options['PartSize'] = isset($options['PartSize']) ? $options['PartSize'] : RangeDownload::DEFAULT_PART_SIZE;\n        $contentLength = 0;\n        $versionId = isset($options['VersionId']) ? $options['VersionId'] : \"\";\n        try {\n            $rt = $this->headObject(array(\n                    'Bucket'=>$bucket,\n                    'Key'=>$key,\n                    'VersionId'=>$versionId,\n                )\n            );\n            $contentLength = $rt['ContentLength'];\n            $resumableJson = [\n                'LastModified' => $rt['LastModified'],\n                'ContentLength' => $rt['ContentLength'],\n                'ETag' => $rt['ETag'],\n                'Crc64ecma' => $rt['Crc64ecma']\n            ];\n            $options['ResumableJson'] = $resumableJson;\n        } catch (\\Exception $e) {\n            throw ($e);\n        }\n        if ($contentLength < $options['PartSize']) {\n            $rt = $this->getObject(array(\n                    'Bucket' => $bucket,\n                    'Key'    => $key,\n                    'SaveAs'   => $saveAs,\n                ) + $options);\n        } else {\n            $rangeDownload = new RangeDownload($this, $contentLength, $saveAs, array(\n                    'Bucket' => $bucket,\n                    'Key' => $key,\n                ) + $options);\n\n            $rt = $rangeDownload->performDownloading();\n        }\n        return $rt;\n    }\n\n    public function resumeUpload($bucket, $key, $body, $uploadId, $options = array()) {\n        $body = Psr7\\stream_for($body);\n        $options['PartSize'] = isset($options['PartSize']) ? $options['PartSize'] : MultipartUpload::DEFAULT_PART_SIZE;\n        $multipartUpload = new MultipartUpload($this, $body, array(\n                'Bucket' => $bucket,\n                'Key' => $key,\n                'UploadId' => $uploadId,\n            ) + $options);\n\n        $rt = $multipartUpload->resumeUploading();\n        return $rt;\n    }\n\n    public function copy($bucket, $key, $copySource, $options = array()) {\n\n        $options['PartSize'] = isset($options['PartSize']) ? $options['PartSize'] : Copy::DEFAULT_PART_SIZE;\n\n        // set copysource client\n        $sourceConfig = $this->rawCosConfig;\n        $sourceConfig['region'] = $copySource['Region'];\n        $cosSourceClient = new Client($sourceConfig);\n        $copySource['VersionId'] = isset($copySource['VersionId']) ? $copySource['VersionId'] : \"\";\n        try {\n            $rt = $cosSourceClient->headObject(\n                array('Bucket'=>$copySource['Bucket'],\n                    'Key'=>$copySource['Key'],\n                    'VersionId'=>$copySource['VersionId'],\n                )\n            );\n        } catch (\\Exception $e) {\n            throw $e;\n        }\n\n        $contentLength =$rt['ContentLength'];\n        // sample copy\n        if ($contentLength < $options['PartSize']) {\n            $rt = $this->copyObject(array(\n                    'Bucket' => $bucket,\n                    'Key'    => $key,\n                    'CopySource'   => $copySource['Bucket']. '.cos.'. $copySource['Region'].\n                                      \".myqcloud.com/\". $copySource['Key']. \"?versionId=\". $copySource['VersionId'],\n                ) + $options\n            );\n            return $rt;\n        }\n        // multi part copy\n        $copySource['ContentLength'] = $contentLength;\n        $copy = new Copy($this, $copySource, array(\n                'Bucket' => $bucket,\n                'Key'    => $key\n            ) + $options\n        );\n        return $copy->copy();\n    }\n\n    public function doesBucketExist($bucket, array $options = array())\n    {\n        try {\n            $this->HeadBucket(array(\n                'Bucket' => $bucket));\n            return True;\n        } catch (\\Exception $e){\n            return False;\n        }\n    }\n\n    public function doesObjectExist($bucket, $key, array $options = array())\n    {\n        try {\n            $this->HeadObject(array(\n                'Bucket' => $bucket,\n                'Key' => $key));\n            return True;\n        } catch (\\Exception $e){\n            return False;\n        }\n    }\n    \n    public static function explodeKey($key) {\n        // Remove a leading slash if one is found\n        $split_key = explode('/', $key && $key[0] == '/' ? substr($key, 1) : $key);\n        // Remove empty element\n        $split_key = array_filter($split_key, function($var) {\n            return !($var == '' || $var == null);\n        });\n        $final_key = implode(\"/\", $split_key);\n        if (substr($key, -1)  == '/') {\n            $final_key = $final_key . '/';\n        }\n        return $final_key;\n    }\n\n\n    public static function handleSignature($secretId, $secretKey) {\n            return function (callable $handler) use ($secretId, $secretKey) {\n                    return new SignatureMiddleware($handler, $secretId, $secretKey);\n            };\n    }\n\n    public static function handleErrors() {\n            return function (callable $handler) {\n                    return new ExceptionMiddleware($handler);\n            };\n    }\n}\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/src/Qcloud/Cos/CommandToRequestTransformer.php",
    "content": "<?php\n\nnamespace Qcloud\\Cos;\n\nuse Psr\\Http\\Message\\RequestInterface;\nuse GuzzleHttp\\Command\\CommandInterface;\nuse GuzzleHttp\\Psr7\\Uri;\nuse InvalidArgumentException;\n\nclass CommandToRequestTransformer {\n    private $config;\n    private $operation;\n\n    public function __construct( $config, $operation ) {\n        $this->config = $config;\n        $this->operation = $operation;\n    }\n\n    // format bucket style\n\n    public function bucketStyleTransformer( CommandInterface $command, RequestInterface $request ) {\n        $action = $command->getName();\n        if ($action == 'ListBuckets') {\n            $uri =  \"service.cos.myqcloud.com\";\n    \n            if ($this->config['endpoint'] != null) {\n                $uri = $this->config['endpoint'];\n            }   \n            if ($this->config['domain'] != null) {\n                $uri = $this->config['domain'];\n            }   \n            if ($this->config['ip'] != null) {\n                $uri = $this->config['ip'];\n                if ($this->config['port'] != null) {\n                    $uri = $this->config['ip'] . \":\" . $this->config['port'];\n                }   \n            }\n            return $request->withUri(new Uri($this->config['schema'].\"://\". $uri. \"/\"));\n        }\n        $operation = $this->operation;\n        $bucketname = $command['Bucket'];\n\n        $appId = $this->config['appId'];\n        if ( $appId != null && endWith( $bucketname, '-'.$appId ) == False ) {\n            $bucketname = $bucketname.'-'.$appId;\n        }\n        $command['Bucket'] = $bucketname;\n        $path = '';\n\n        $http_method = $operation['httpMethod'];\n        $uri = $operation['uri'];\n\n        // Hoststyle is used by default\n        // Pathstyle\n        if ( $this->config['pathStyle'] != true ) {\n            if ( isset( $operation['parameters']['Bucket'] ) && $command->hasParam( 'Bucket' ) ) {\n                $uri = str_replace( '{Bucket}', '', $uri );\n            }\n\n            if ( isset( $operation['parameters']['Key'] ) && $command->hasParam( 'Key' ) ) {\n                $uri = str_replace( '{/Key*}', encodeKey( $command['Key'] ), $uri );\n            }\n        }\n\n        if ($this->config['endpoint'] == null) {\n            $this->config['endpoint'] = \"myqcloud.com\";\n        }\n\n        $domain_type = '.cos.';\n        if ($action == 'PutBucketImageStyle' || $action == 'GetBucketImageStyle' || $action == 'DeleteBucketImageStyle'\n            || $action == 'PutBucketGuetzli' || $action == 'GetBucketGuetzli' || $action == 'DeleteBucketGuetzli') {\n            $domain_type = '.pic.';\n        }\n\n        $origin_host = $bucketname . $domain_type . $this->config['region'] . '.' . $this->config['endpoint'];\n        // domain\n        if ( $this->config['domain'] != null ) {\n            $origin_host = $this->config['domain'];\n        }\n        $host = $origin_host;\n        if ( $this->config['ip'] != null ) {\n            $host = $this->config['ip'];\n            if ( $this->config['port'] != null ) {\n                $host = $this->config['ip'] . ':' . $this->config['port'];\n            }\n        }\n\n        $path = $this->config['schema'].'://'. $host . $uri;\n        $uri = new Uri( $path );\n        $query = $request->getUri()->getQuery();\n        if ( $uri->getQuery() != $query && $uri->getQuery() != '' ) {\n            $query =   $uri->getQuery() . '&' . $request->getUri()->getQuery();\n        }\n        $uri = $uri->withQuery( $query );\n        $request = $request->withUri( $uri );\n        $request = $request->withHeader( 'Host', $origin_host );\n        return $request;\n    }\n\n    // format upload body\n\n    public function uploadBodyTransformer( CommandInterface $command, $request, $bodyParameter = 'Body', $sourceParameter = 'SourceFile' ) {\n\n        $operation = $this->operation;\n        if ( !isset( $operation['parameters']['Body'] ) ) {\n            return $request;\n        }\n        $source = isset( $command[$sourceParameter] ) ? $command[$sourceParameter] : null;\n        $body = isset( $command[$bodyParameter] ) ? $command[$bodyParameter] : null;\n        // If a file path is passed in then get the file handle\n        if ( is_string( $source ) && file_exists( $source ) ) {\n            $body = fopen( $source, 'rb' );\n        }\n        // Prepare the body parameter and remove the source file parameter\n        if ( null !== $body ) {\n            return $request;\n        } else {\n            throw new InvalidArgumentException(\n                \"You must specify a non-null value for the {$bodyParameter} or {$sourceParameter} parameters.\" );\n            }\n        }\n\n        // update md5\n\n        public function md5Transformer( CommandInterface $command, $request ) {\n            $operation = $this->operation;\n            if ( isset( $operation['data']['contentMd5'] ) ) {\n                $request = $this->addMd5( $request );\n            }\n            if ( isset( $operation['parameters']['ContentMD5'] ) &&\n            isset( $command['ContentMD5'] ) ) {\n                $value = $command['ContentMD5'];\n                if ( $value != false ) {\n                    $request = $this->addMd5( $request );\n                }\n            }\n\n            return $request;\n        }\n\n        // add Query string\n\n        public function queryStringTransformer( CommandInterface $command, $request ) {\n            $operation = $this->operation;\n            if ( isset( $command['Params'] ) ) {\n                $params = $command['Params'];\n                foreach ( $params as $key => $value ) {\n                    $uri = $request->getUri();\n                    $query = $uri->getQuery();\n                    $uri = $uri->withQuery($query. \"&\" . $key . \"=\" . $value );\n                    $request = $request->withUri( $uri );\n                }\n            }\n\n            return $request;\n        }\n\n        // add meta\n\n        public function metadataTransformer( CommandInterface $command, $request ) {\n            $operation = $this->operation;\n            if ( isset( $command['Metadata'] ) ) {\n                $meta = $command['Metadata'];\n                foreach ( $meta as $key => $value ) {\n                    $request = $request->withHeader( 'x-cos-meta-' . $key, $value );\n                }\n            }\n            $request = headersMap( $command, $request );\n\n            return $request;\n        }\n\n        // count md5\n\n        private function addMd5( $request ) {\n            $body = $request->getBody();\n            if ( $body && $body->getSize() > 0 ) {\n                $md5 = base64_encode( md5( $body, true ) );\n                return $request->withHeader( 'Content-MD5', $md5 );\n            }\n            return $request;\n        }\n\n        // inventoryId\n\n        public function specialParamTransformer( CommandInterface $command, $request ) {\n            $action = $command->getName();\n            if ( $action == 'PutBucketInventory' ) {\n                $id = $command['Id'];\n                $uri = $request->getUri();\n                $query = $uri->getQuery();\n                $uri = $uri->withQuery( $query . '&Id='.$id );\n                return $request->withUri( $uri );\n            }\n            return $request;\n        }\n\n        public function ciParamTransformer( CommandInterface $command, $request ) {\n            $action = $command->getName();\n            if ( $action == 'GetObject' ) {\n                if(isset($command['ImageHandleParam']) && $command['ImageHandleParam']){\n                    $uri = $request->getUri();\n                    $query = $uri->getQuery();\n                    if($query){\n                        $query .= \"&\" . urlencode($command['ImageHandleParam']);\n                    }else{\n                        $query .= urlencode($command['ImageHandleParam']);\n                    }\n                    $uri = $uri->withQuery($query);\n                    $request = $request->withUri( $uri );\n                }\n            }\n            return $request;\n        }\n\n        public function __destruct() {\n        }\n\n    }\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/src/Qcloud/Cos/Common.php",
    "content": "<?php\n\nnamespace Qcloud\\Cos;\n\nfunction region_map( $region ) {\n    $regionmap = array( 'cn-east'=>'ap-shanghai',\n    'cn-south'=>'ap-guangzhou',\n    'cn-north'=>'ap-beijing-1',\n    'cn-south-2'=>'ap-guangzhou-2',\n    'cn-southwest'=>'ap-chengdu',\n    'sg'=>'ap-singapore',\n    'tj'=>'ap-beijing-1',\n    'bj'=>'ap-beijing',\n    'sh'=>'ap-shanghai',\n    'gz'=>'ap-guangzhou',\n    'cd'=>'ap-chengdu',\n    'sgp'=>'ap-singapore' );\n    if ( isset($regionmap[ $region]) ) {\n        return $regionmap[$region];\n    }\n    return $region;\n}\n\nfunction encodeKey( $key ) {\n    return str_replace( '%2F', '/', rawurlencode( $key ) );\n}\n\nfunction endWith( $haystack, $needle ) {\n    $length = strlen( $needle );\n    if ( $length == 0 ) {\n        return true;\n    }\n    return ( substr( $haystack, -$length ) === $needle );\n}\n\nfunction startWith( $haystack, $needle ) {\n    $length = strlen( $needle );\n    if ( $length == 0 ) {\n        return true;\n    }\n    return ( substr( $haystack, $length ) === $needle );\n}\n\nfunction headersMap( $command, $request ) {\n    $headermap = array(\n        'TransferEncoding'=>'Transfer-Encoding',\n        'ChannelId'=>'x-cos-channel-id'\n    );\n    foreach ( $headermap as $key => $value ) {\n        if ( isset( $command[$key] ) ) {\n            $request = $request->withHeader( $value, $command[$key] );\n        }\n    }\n    return $request;\n}\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/src/Qcloud/Cos/Copy.php",
    "content": "<?php\n\nnamespace Qcloud\\Cos;\n\nuse GuzzleHttp\\Psr7\\Request;\nuse GuzzleHttp\\Pool;\n\nclass Copy {\n    const MIN_PART_SIZE = 1048576;\n    const MAX_PART_SIZE = 5368709120;\n    const DEFAULT_PART_SIZE = 52428800;\n    const MAX_PARTS     = 10000;\n\n    private $client;\n    private $copySource;\n    private $options;\n    private $partSize;\n    private $parts;\n    private $size;\n    private $commandList = [];\n    private $requestList = [];\n\n    public function __construct($client, $source, $options = array()) {\n        $minPartSize = $options['PartSize'];\n        unset($options['PartSize']);\n        $this->client = $client;\n        $this->copySource = $source;\n        $this->options = $options;\n        $this->size = $source['ContentLength'];\n        unset($source['ContentLength']);\n        $this->partSize = $this->calculatePartSize($minPartSize);\n        $this->concurrency = isset($options['Concurrency']) ? $options['Concurrency'] : 10;\n        $this->retry = isset($options['Retry']) ? $options['Retry'] : 5;\n    }\n    public function copy() {\n        $uploadId= $this->initiateMultipartUpload();\n        for ($i = 0; $i < $this->retry; $i += 1) {\n            $rt = $this->uploadParts($uploadId);\n            if ($rt == 0) {\n                break;\n            }\n            sleep(1 << $i);\n        }\n        foreach ( $this->parts as $key => $row ){\n            $num1[$key] = $row ['PartNumber'];\n            $num2[$key] = $row ['ETag'];\n        }\n        array_multisort($num1, SORT_ASC, $num2, SORT_ASC, $this->parts);\n        return $this->client->completeMultipartUpload(array(\n            'Bucket' => $this->options['Bucket'],\n            'Key' => $this->options['Key'],\n            'UploadId' => $uploadId,\n            'Parts' => $this->parts)\n        );\n\n    }\n    public function uploadParts($uploadId) {\n        $copyRequests = function ($uploadId) {\n            $offset = 0;\n            $partNumber = 1;\n            $partSize = $this->partSize;\n            $finishedNum = 0;\n            $this->parts = array();\n            for ($index = 1; ; $index ++) {\n                if ($offset + $partSize  >= $this->size)\n                {\n                    $partSize = $this->size - $offset;\n                }\n                $copySourcePath = $this->copySource['Bucket']. '.cos.'. $this->copySource['Region'].\n                    \".myqcloud.com/\". $this->copySource['Key']. \"?versionId=\". $this->copySource['VersionId'];\n                $params = array(\n                    'Bucket' => $this->options['Bucket'],\n                    'Key' => $this->options['Key'],\n                    'UploadId' => $uploadId,\n                    'PartNumber' => $partNumber,\n                    'CopySource'=> $copySourcePath,\n                    'CopySourceRange' => 'bytes='.((string)$offset).'-'.(string)($offset+$partSize - 1),\n                );\n                if(!isset($this->parts[$partNumber])) {\n                    $command = $this->client->getCommand('uploadPartCopy', $params);\n                    $request = $this->client->commandToRequestTransformer($command);\n                    $this->commandList[$index] = $command;\n                    $this->requestList[$index] = $request;\n                    yield $request;\n                }\n                ++$partNumber;\n                $offset += $partSize;\n                if ($this->size == $offset) {\n                    break;\n                }\n            }\n        };\n        $pool = new Pool($this->client->httpClient, $copyRequests($uploadId), [\n            'concurrency' => $this->concurrency,\n            'fulfilled' => function ($response, $index) {\n                $index = $index + 1;\n                $response = $this->client->responseToResultTransformer($response, $this->requestList[$index], $this->commandList[$index]);\n                $part = array('PartNumber' => $index, 'ETag' => $response['ETag']);\n                $this->parts[$index] = $part;\n            },\n           \n            'rejected' => function ($reason, $index) { \n                $index = $index += 1;\n                $retry = 2;\n                for ($i = 1; $i <= $retry; $i++) {\n                    try {\n                        $rt =$this->client->execute($this->commandList[$index]);\n                        $part = array('PartNumber' => $index, 'ETag' => $rt['ETag']);\n                        $this->parts[$index] = $part;\n                    } catch(\\Exception $e) {\n                        if ($i == $retry) {\n                            throw($e);\n                        }\n                    }\n                }\n            },\n        ]);\n        \n        // Initiate the transfers and create a promise\n        $promise = $pool->promise();\n        \n        // Force the pool of requests to complete.\n        $promise->wait();\n    }\n\n\n    private function calculatePartSize($minPartSize)\n    {\n        $partSize = intval(ceil(($this->size / self::MAX_PARTS)));\n        $partSize = max($minPartSize, $partSize);\n        $partSize = min($partSize, self::MAX_PART_SIZE);\n        $partSize = max($partSize, self::MIN_PART_SIZE);\n        return $partSize;\n    }\n\n    private function initiateMultipartUpload() {\n        $result = $this->client->createMultipartUpload($this->options);\n        return $result['UploadId'];\n    }\n\n}\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/src/Qcloud/Cos/Exception/CosException.php",
    "content": "<?php\n\nnamespace Qcloud\\Cos\\Exception;\n\nuse Qcloud\\Cos\\Exception\\ServiceResponseException;\n\nclass CosException extends ServiceResponseException {}\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/src/Qcloud/Cos/Exception/ServiceResponseException.php",
    "content": "<?php\n\nnamespace Qcloud\\Cos\\Exception;\n\nuse Psr\\Http\\Message\\RequestInterface;\nuse Psr\\Http\\Message\\ResponseInterface;\n\nclass ServiceResponseException extends \\RuntimeException {\n\n    /**\n     * @var Response Response\n     */\n    protected $response;\n\n    /**\n     * @var RequestInterface Request\n     */\n    protected $request;\n\n    /**\n     * @var string Request ID\n     */\n    protected $requestId;\n\n    /**\n     * @var string Exception type (client / server)\n     */\n    protected $exceptionType;\n\n    /**\n     * @var string Exception code\n     */\n    protected $exceptionCode;\n\n    /**\n     * Set the exception code\n     *\n     * @param string $code Exception code\n     */\n    public function setExceptionCode($code) {\n        $this->exceptionCode = $code;\n    }\n\n    /**\n     * Get the exception code\n     *\n     * @return string|null\n     */\n    public function getExceptionCode() {\n        return $this->exceptionCode;\n    }\n\n    /**\n     * Set the exception type\n     *\n     * @param string $type Exception type\n     */\n    public function setExceptionType($type) {\n        $this->exceptionType = $type;\n    }\n\n    /**\n     * Get the exception type (one of client or server)\n     *\n     * @return string|null\n     */\n    public function getExceptionType() {\n        return $this->exceptionType;\n    }\n\n    /**\n     * Set the request ID\n     *\n     * @param string $id Request ID\n     */\n    public function setRequestId($id) {\n        $this->requestId = $id;\n    }\n\n    /**\n     * Get the Request ID\n     *\n     * @return string|null\n     */\n    public function getRequestId() {\n        return $this->requestId;\n    }\n\n    /**\n     * Set the associated response\n     *\n     * @param Response $response Response\n     */\n    public function setResponse(ResponseInterface $response) {\n        $this->response = $response;\n    }\n\n    /**\n     * Get the associated response object\n     *\n     * @return Response|null\n     */\n    public function getResponse() {\n        return $this->response;\n    }\n\n    /**\n     * Set the associated request\n     *\n     * @param RequestInterface $request\n     */\n    public function setRequest(RequestInterface $request) {\n        $this->request = $request;\n    }\n\n    /**\n     * Get the associated request object\n     *\n     * @return RequestInterface|null\n     */\n    public function getRequest() {\n        return $this->request;\n    }\n\n    /**\n     * Get the status code of the response\n     *\n     * @return int|null\n     */\n    public function getStatusCode() {\n        return $this->response ? $this->response->getStatusCode() : null;\n    }\n\n    /**\n     * Cast to a string\n     *\n     * @return string\n     */\n    public function __toString() {\n        $message = get_class($this) . ': '\n            . 'Cos Error Code: ' . $this->getExceptionCode() . ', '\n            . 'Status Code: ' . $this->getStatusCode() . ', '\n            . 'Cos Request ID: ' . $this->getRequestId() . ', '\n            . 'Cos Error Type: ' . $this->getExceptionType() . ', '\n            . 'Cos Error Message: ' . $this->getMessage();\n\n        // Add the User-Agent if available\n        if ($this->request) {\n            $message .= ', ' . 'User-Agent: ' . $this->request->getHeader('User-Agent')[0];\n        }\n\n        return $message;\n    }\n\n    /**\n     * Get the request ID of the error. This value is only present if a\n     * response was received, and is not present in the event of a networking\n     * error.\n     *\n     * Same as `getRequestId()` method, but matches the interface for SDKv3.\n     *\n     * @return string|null Returns null if no response was received\n     */\n    public function getCosRequestId() {\n        return $this->requestId;\n    }\n\n    /**\n     * Get the Cos error type.\n     *\n     * Same as `getExceptionType()` method, but matches the interface for SDKv3.\n     *\n     * @return string|null Returns null if no response was received\n     */\n    public function getCosErrorType() {\n        return $this->exceptionType;\n    }\n\n    /**\n     * Get the Cos error code.\n     *\n     * Same as `getExceptionCode()` method, but matches the interface for SDKv3.\n     *\n     * @return string|null Returns null if no response was received\n     */\n    public function getCosErrorCode() {\n        return $this->exceptionCode;\n    }\n}\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/src/Qcloud/Cos/ExceptionMiddleware.php",
    "content": "<?php\n\nnamespace Qcloud\\Cos;\n\nuse Qcloud\\Cos\\Exception\\ServiceResponseException;\nuse GuzzleHttp\\Promise\\PromiseInterface;\nuse GuzzleHttp\\Psr7;\nuse Psr\\Http\\Message\\RequestInterface;\nuse Psr\\Http\\Message\\ResponseInterface;\nuse GuzzleHttp\\Exception\\RequestException;\n\nclass ExceptionMiddleware {\n    private $nextHandler;\n    protected $parser;\n    protected $defaultException;\n\n    /**\n     * @param callable $nextHandler Next handler to invoke.\n     */\n    public function __construct(callable $nextHandler) {\n        $this->nextHandler = $nextHandler;\n        $this->parser = new ExceptionParser();\n        $this->defaultException = 'Qcloud\\Cos\\Exception\\ServiceResponseException';\n    }\n\n    /**\n     * @param RequestInterface $request\n     * @param array            $options\n     *\n     * @return PromiseInterface\n     */\n    public function __invoke(RequestInterface $request, array $options) {\n        $fn = $this->nextHandler;\n        return $fn($request, $options)->then(\n                    function (ResponseInterface $response) use ($request) {\n\t\t\t\t\t\treturn $this->handle($request, $response);\n                    }\n\t\t);\n\t}\n\n\tpublic function handle(RequestInterface $request, ResponseInterface $response) {\n\t\t$code = $response->getStatusCode();\n\t\tif ($code < 400) {\n\t\t\treturn $response;\n\t\t}\n\n\t\t//throw RequestException::create($request, $response);\n        $parts = $this->parser->parse($request, $response);\n\n        $className = 'Qcloud\\\\Cos\\\\Exception\\\\' . $parts['code'];\n        if (substr($className, -9) !== 'Exception') {\n            $className .= 'Exception';\n        }\n\n        $className = class_exists($className) ? $className : $this->defaultException;\n\n        throw $this->createException($className, $request, $response, $parts);\n\t}\n\n    protected function createException($className, RequestInterface $request, ResponseInterface $response, array $parts) {\n        $class = new $className($parts['message']);\n\n        if ($class instanceof ServiceResponseException) {\n            $class->setExceptionCode($parts['code']);\n            $class->setExceptionType($parts['type']);\n            $class->setResponse($response);\n            $class->setRequest($request);\n            $class->setRequestId($parts['request_id']);\n        }\n        return $class;\n    }\n}\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/src/Qcloud/Cos/ExceptionParser.php",
    "content": "<?php\n\nnamespace Qcloud\\Cos;\n\nuse Psr\\Http\\Message\\RequestInterface;\nuse Psr\\Http\\Message\\ResponseInterface;\n\n/**\n * Parses default XML exception responses\n */\nclass ExceptionParser {\n\n    public function parse(RequestInterface $request, ResponseInterface $response) {\n        $data = array(\n            'code'       => null,\n            'message'    => null,\n            //'type'       => $response->isClientError() ? 'client' : 'server',\n            'type'       => 'client',\n            'request_id' => null,\n            'parsed'     => null\n        );\n\n\t\t$body = strval($response->getBody());\n\n        if (empty($body)) {\n            $this->parseHeaders($request, $response, $data);\n            return $data;\n        }\n\n        try {\n            $xml = new \\SimpleXMLElement(utf8_encode($body));\n            $this->parseBody($xml, $data);\n            return $data;\n        } catch (\\Exception $e) {\n            $data['code'] = 'PhpInternalXmlParseError';\n            $data['message'] = 'A non-XML response was received';\n            return $data;\n        }\n    }\n\n    /**\n     * Parses additional exception information from the response headers\n     *\n     * @param RequestInterface $request  Request that was issued\n     * @param Response         $response The response from the request\n     * @param array            $data     The current set of exception data\n     */\n    protected function parseHeaders(RequestInterface $request, ResponseInterface $response, array &$data) {\n        $data['message'] = $response->getStatusCode() . ' ' . $response->getReasonPhrase();\n        $requestId = $response->getHeader('x-cos-request-id');\n        if (isset($requestId[0])) {\n            $requestId = $requestId[0];\n            $data['request_id'] = $requestId;\n            $data['message'] .= \" (Request-ID: $requestId)\";\n        }\n\n        // Get the request\n        $status  = $response->getStatusCode();\n        $method  = $request->getMethod();\n\n        // Attempt to determine code for 403s and 404s\n        if ($status === 403) {\n            $data['code'] = 'AccessDenied';\n        } elseif ($method === 'HEAD' && $status === 404) {\n            $path   = explode('/', trim($request->getUri()->getPath(), '/'));\n            $host   = explode('.', $request->getUri()->getHost());\n            $bucket = (count($host) >= 4) ? $host[0] : array_shift($path);\n            $object = array_shift($path);\n\n            if ($bucket && $object) {\n                $data['code'] = 'NoSuchKey';\n            } elseif ($bucket) {\n                $data['code'] = 'NoSuchBucket';\n            }\n        }\n    }\n\n    /**\n     * Parses additional exception information from the response body\n     *\n     * @param \\SimpleXMLElement $body The response body as XML\n     * @param array             $data The current set of exception data\n     */\n    protected function parseBody(\\SimpleXMLElement $body, array &$data) {\n        $data['parsed'] = $body;\n\n        $namespaces = $body->getDocNamespaces();\n        if (isset($namespaces[''])) {\n            // Account for the default namespace being defined and PHP not being able to handle it :(\n            $body->registerXPathNamespace('ns', $namespaces['']);\n            $prefix = 'ns:';\n        } else {\n            $prefix = '';\n        }\n\n        if ($tempXml = $body->xpath(\"//{$prefix}Code[1]\")) {\n            $data['code'] = (string) $tempXml[0];\n        }\n\n        if ($tempXml = $body->xpath(\"//{$prefix}Message[1]\")) {\n            $data['message'] = (string) $tempXml[0];\n        }\n\n        $tempXml = $body->xpath(\"//{$prefix}RequestId[1]\");\n        if (empty($tempXml)) {\n            $tempXml = $body->xpath(\"//{$prefix}RequestID[1]\");\n        }\n        if (isset($tempXml[0])) {\n            $data['request_id'] = (string) $tempXml[0];\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/src/Qcloud/Cos/ImageParamTemplate/BlindWatermarkTemplate.php",
    "content": "<?php\n\nnamespace Qcloud\\Cos\\ImageParamTemplate;\n\nclass BlindWatermarkTemplate extends ImageTemplate {\n    private $markType;\n    private $type;\n    private $image;\n    private $text;\n    private $level;\n\n    public function __construct() {\n        parent::__construct();\n        $this->markType = 3;\n        $this->type = \"\";\n        $this->image = \"\";\n        $this->text = \"\";\n        $this->level = \"\";\n\n    }\n\n    public function setPick() {\n        $this->markType = 4;\n    }\n\n    public function setType($value) {\n        $this->type = \"/type/\" . $value;\n    }\n\n    public function setImage($value) {\n        $this->image = \"/image/\" . $this->ciBase64($value);\n    }\n\n    public function setText($value) {\n        $this->text = \"/text/\" . $this->ciBase64($value);\n    }\n\n    public function setLevel($value) {\n        $this->level = \"/level/\" . $value;\n    }\n\n    public function getType() {\n        return $this->type;\n    }\n\n    public function getImage() {\n        return $this->image;\n    }\n\n    public function getText() {\n        return $this->text;\n    }\n\n    public function getLevel() {\n        return $this->level;\n    }\n\n\n    public function queryString() {\n        $head = \"watermark/$this->markType\";\n        $res = \"\";\n        if($this->type){\n            $res .= $this->type;\n        }\n        if($this->image){\n            $res .= $this->image;\n        }\n        if($this->text){\n            $res .= $this->text;\n        }\n        if($this->level){\n            $res .= $this->level;\n        }\n        if($res){\n            $res = $head . $res;\n        }\n        return $res;\n    }\n\n    public function resetRule() {\n        $this->markType = 3;\n        $this->type = \"\";\n        $this->image = \"\";\n        $this->text = \"\";\n        $this->level = \"\";\n    }\n}\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/src/Qcloud/Cos/ImageParamTemplate/CIParamTransformation.php",
    "content": "<?php\n\nnamespace Qcloud\\Cos\\ImageParamTemplate;\n\nclass CIParamTransformation extends ImageTemplate{\n\n    private $tranParams;\n    private $tranString;\n    private $spilt;\n\n    public function __construct($spilt = \"|\") {\n        parent::__construct();\n        $this->spilt = $spilt;\n        $this->tranParams = array();\n        $this->tranString = \"\";\n    }\n\n    public function addRule(ImageTemplate $template) {\n        if($template->queryString()){\n            $this->tranParams[] = $template->queryString();\n        }\n    }\n\n    public function queryString() {\n        if($this->tranParams) {\n            $this->tranString = implode($this->spilt, $this->tranParams);\n        }\n        return $this->tranString;\n    }\n\n    public function resetRule() {\n        $this->tranParams = array();\n        $this->tranString = \"\";\n    }\n\n    public function defineRule($value) {\n        $this->tranParams[] = $value;\n    }\n}\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/src/Qcloud/Cos/ImageParamTemplate/ImageMogrTemplate.php",
    "content": "<?php\n\nnamespace Qcloud\\Cos\\ImageParamTemplate;\n\nclass ImageMogrTemplate extends ImageTemplate\n{\n    private $tranParams;\n    private $tranString;\n\n    public function __construct() {\n        parent::__construct();\n        $this->tranParams = array();\n        $this->tranString = \"\";\n    }\n\n    public function thumbnailByScale($widthScale) {\n        $this->tranParams[] = \"/thumbnail/!\" . $widthScale . \"p\";\n    }\n\n    public function thumbnailByWidthScale($heightScale) {\n        $this->tranParams[] = \"/thumbnail/!\" . $heightScale . \"px\";\n    }\n\n    public function thumbnailByHeightScale($scale) {\n        $this->tranParams[] = \"/thumbnail/!x\" . $scale . \"p\";\n    }\n\n    public function thumbnailByWidth($width) {\n        $this->tranParams[] = \"/thumbnail/\" . $width . \"x\";\n    }\n\n    public function thumbnailByHeight($height) {\n        $this->tranParams[] = \"/thumbnail/x\" . $height;\n    }\n\n    public function thumbnailByMaxWH($maxW, $maxH) {\n        $this->tranParams[] = \"/thumbnail/\" . $maxW . \"x\" . $maxH;\n    }\n\n    public function thumbnailByMinWH($minW, $minH) {\n        $this->tranParams[] = \"/thumbnail/!\" . $minW . \"x\" . $minH . \"r\" ;\n    }\n\n    public function thumbnailByWH($width, $height) {\n        $this->tranParams[] = \"/thumbnail/\" . $width  . \"x\" . $height . \"!\";\n    }\n\n    public function thumbnailByPixel($pixel) {\n        $this->tranParams[] = \"/thumbnail/\" . $pixel . \"@\";\n    }\n\n    public function cut($width, $height, $dx, $dy) {\n        $this->tranParams[] = \"/cut/\" . $width . \"x\" . \"$height\" . \"x\" . $dx . \"x\" . $dy;\n    }\n\n    public function cropByWidth($width, $gravity = \"\") {\n        $temp = \"/crop/\" . $width . \"x\";\n        if($gravity){\n            $temp .= \"/gravity/\" . $gravity;\n        }\n        $this->tranParams[] = $temp;\n    }\n\n    public function cropByHeight($height, $gravity = \"\") {\n        $temp = \"/crop/x\" . $height;\n        if($gravity){\n            $temp .= \"/gravity/\" . $gravity;\n        }\n        $this->tranParams[] = $temp;\n    }\n\n    public function cropByWH($width, $height, $gravity = \"\") {\n        $temp = \"/crop/\" . $width . \"x\" . $height;\n        if($gravity){\n            $temp .= \"/gravity/\" . $gravity;\n        }\n        $this->tranParams[] = $temp;\n    }\n\n    public function iradius($radius) {\n        $this->tranParams[] = \"/iradius/\" . $radius;\n    }\n\n    public function rradius($radius) {\n        $this->tranParams[] = \"/rradius/\" . $radius;\n    }\n\n    public function scrop($width, $height) {\n        $this->tranParams[] = \"/scrop/\" . $width . \"x\" . $height;\n    }\n\n    public function rotate($degree) {\n        $this->tranParams[] = \"/rotate/\" . $degree;\n    }\n\n    public function autoOrient() {\n        $this->tranParams[] = \"/rotate/auto-orient\";\n    }\n\n    public function format($format) {\n        $this->tranParams[] = \"/format/\" . $format;\n    }\n\n    public function gifOptimization($frameNumber) {\n        $this->tranParams[] = \"/cgif/\" . $frameNumber;\n    }\n\n    public function jpegInterlaceMode($mode) {\n        $this->tranParams[] = \"/interlace/\" . $mode;\n    }\n\n    public function quality($value, $force = 0) {\n        $temp = \"/quality/\" . $value;\n        if($force){\n            $temp .= \"!\";\n        }\n        $this->tranParams[] = $temp;\n    }\n\n    public function lowestQuality($value) {\n        $this->tranParams[] = \"/lquality/\" . $value;\n    }\n\n    public function relativelyQuality($value) {\n        $this->tranParams[] = \"/rquality/\" . $value;\n    }\n\n    public function blur($radius, $sigma) {\n        $this->tranParams[] = \"/blur/\" . $radius . \"x\" . $sigma;\n    }\n\n    public function bright($value) {\n        $this->tranParams[] = \"/bright/\" . $value;\n    }\n\n    public function contrast($value) {\n        $this->tranParams[] = \"/contrast/\" . $value;\n    }\n\n    public function sharpen($value) {\n        $this->tranParams[] = \"/sharpen/\" . $value;\n    }\n\n    public function strip() {\n        $this->tranParams[] = \"/strip\";\n    }\n\n    public function queryString() {\n        if($this->tranParams) {\n            $this->tranString = \"imageMogr2\" . implode(\"\", $this->tranParams);\n        }\n        return $this->tranString;\n    }\n\n    public function resetRule() {\n        $this->tranString = \"\";\n        $this->tranParams = array();\n    }\n}\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/src/Qcloud/Cos/ImageParamTemplate/ImageQrcodeTemplate.php",
    "content": "<?php\n\nnamespace Qcloud\\Cos\\ImageParamTemplate;\n\nclass ImageQrcodeTemplate extends ImageTemplate\n{\n    private $mode;\n\n    public function __construct() {\n        parent::__construct();\n        $this->mode = \"\";\n    }\n\n    public function setMode($mode) {\n        $this->mode = \"/cover/\" . $mode;\n    }\n\n    public function getMode() {\n        return $this->mode;\n    }\n\n    public function queryString() {\n        $head = \"QRcode\";\n        $res = \"\";\n        if($this->mode) {\n            $res .= $this->mode;\n        }\n        if($res) {\n            $res = $head . $res;\n        }\n        return $res;\n    }\n\n    public function resetRule() {\n        $this->mode = \"\";\n    }\n}\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/src/Qcloud/Cos/ImageParamTemplate/ImageStyleTemplate.php",
    "content": "<?php\n\nnamespace Qcloud\\Cos\\ImageParamTemplate;\n\nclass ImageStyleTemplate extends ImageTemplate\n{\n    private $style;\n\n    public function __construct() {\n        parent::__construct();\n        $this->style = \"\";\n    }\n\n    public function setStyle($styleName) {\n        $this->style = \"style/\" . $styleName;\n    }\n\n    public function getStyle() {\n        return $this->style;\n    }\n\n    public function queryString() {\n        $res = \"\";\n        if($this->style) {\n            $res = $this->style;\n        }\n        return $res;\n    }\n\n    public function resetRule() {\n        $this->style = \"\";\n    }\n}\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/src/Qcloud/Cos/ImageParamTemplate/ImageTemplate.php",
    "content": "<?php\n\nnamespace Qcloud\\Cos\\ImageParamTemplate;\n\nclass ImageTemplate\n{\n\n    public function __construct() {\n    }\n\n    public function queryString() {\n        return \"\";\n    }\n\n    public function ciBase64($value) {\n        return  str_replace(\"/\", \"_\", str_replace(\"+\", \"-\", base64_encode($value)));\n    }\n}\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/src/Qcloud/Cos/ImageParamTemplate/ImageViewTemplate.php",
    "content": "<?php\n\nnamespace Qcloud\\Cos\\ImageParamTemplate;\n\n/**\n * Parses default XML exception responses\n */\nclass ImageViewTemplate extends ImageTemplate\n{\n    private $mode;\n    private $width;\n    private $height;\n    private $format;\n    private $quality;\n\n\n    public function __construct() {\n        parent::__construct();\n        $this->mode = \"\";\n        $this->width = \"\";\n        $this->height = \"\";\n        $this->format = \"\";\n        $this->quality = \"\";\n    }\n\n    public function setMode($value) {\n        $this->mode = \"/\" . $value;\n    }\n\n    public function setWidth($value) {\n        $this->width = \"/w/\" . $value;\n    }\n\n    public function setHeight($value) {\n        $this->height = \"/h/\" . $value;\n    }\n\n    public function setFormat($value) {\n        $this->format = \"/format/\" . $value;\n    }\n\n    public function setQuality($qualityType, $qualityValue, $force = 0) {\n        if($qualityType == 1){\n            $this->quality = \"/q/$qualityValue\" ;\n            if($force){\n                $this->quality .= \"!\";\n            }\n        }else if($qualityType == 2){\n            $this->quality = \"/rq/$qualityValue\" ;\n        }else if ($qualityType == 3){\n            $this->quality = \"/lq/$qualityValue\" ;\n        }\n    }\n\n    public function getMode() {\n        return $this->mode;\n    }\n\n    public function getWidth() {\n        return $this->width;\n    }\n\n    public function getHeight() {\n        return $this->height;\n    }\n\n    public function getFormat() {\n        return $this->format;\n    }\n\n    public function getQuality() {\n        return $this->quality;\n    }\n\n    public function queryString() {\n        $head = \"imageView2\";\n        $res = \"\";\n        if($this->mode) {\n            $res .= $this->mode;\n        }\n        if($this->width) {\n            $res .= $this->width;\n        }\n        if($this->height) {\n            $res .= $this->height;\n        }\n        if($this->format) {\n            $res .= $this->format;\n        }\n        if($this->quality) {\n            $res .= $this->quality;\n        }\n        if($res) {\n            $res = $head . $res;\n        }\n        return $res;\n    }\n\n    public function resetRule() {\n        $this->mode = \"\";\n        $this->width = \"\";\n        $this->height = \"\";\n        $this->format = \"\";\n        $this->quality = \"\";\n    }\n}\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/src/Qcloud/Cos/ImageParamTemplate/ImageWatermarkTemplate.php",
    "content": "<?php\n\nnamespace Qcloud\\Cos\\ImageParamTemplate;\n\nclass ImageWatermarkTemplate extends ImageTemplate\n{\n\n    private $image;\n    private $gravity;\n    private $dx;\n    private $dy;\n    private $blogo;\n    private $scatype;\n    private $spcent;\n\n    public function __construct() {\n        parent::__construct();\n        $this->image = \"\";\n        $this->gravity = \"\";\n        $this->dx = \"\";\n        $this->dy = \"\";\n        $this->blogo = \"\";\n        $this->scatype = \"\";\n        $this->spcent = \"\";\n    }\n\n    public function setImage($value) {\n        $this->image = \"/image/\" . $this->ciBase64($value);\n    }\n\n    public function setGravity($value) {\n        $this->gravity = \"/gravity/\" . $value;\n    }\n\n    public function setDx($value) {\n        $this->dx = \"/dx/\" . $value;\n    }\n\n    public function setDy($value) {\n        $this->dy = \"/dy/\" . $value;\n    }\n\n    public function setBlogo($value) {\n        $this->blogo = \"/blogo/\" . $value;\n    }\n\n    public function setScatype($value) {\n        $this->scatype = \"/scatype/\" . $value;\n    }\n\n    public function setSpcent($value) {\n        $this->spcent = \"/spcent/\" . $value;\n    }\n\n    public function getImage() {\n        return $this->image;\n    }\n\n    public function getGravity() {\n        return $this->gravity;\n    }\n\n    public function getDx() {\n        return $this->dx;\n    }\n\n    public function getDy() {\n        return $this->dy;\n    }\n\n    public function getBlogo() {\n        return $this->blogo;\n    }\n\n    public function getScatype() {\n        return $this->scatype;\n    }\n\n    public function getSpcent() {\n        return $this->spcent;\n    }\n\n    public function queryString() {\n        $head = \"watermark/1\";\n        $res = \"\";\n        if($this->image) {\n            $res .= $this->image;\n        }\n        if($this->gravity) {\n            $res .= $this->gravity;\n        }\n        if($this->dx) {\n            $res .= $this->dx;\n        }\n        if($this->dy) {\n            $res .= $this->dy;\n        }\n        if($this->blogo) {\n            $res .= $this->blogo;\n        }\n        if($this->scatype) {\n            $res .= $this->scatype;\n        }\n        if($this->spcent) {\n            $res .= $this->spcent;\n        }\n        if($res) {\n            $res = $head . $res;\n        }\n        return $res;\n    }\n\n    public function resetRule() {\n        $this->image = \"\";\n        $this->gravity = \"\";\n        $this->dx = \"\";\n        $this->dy = \"\";\n        $this->blogo = \"\";\n        $this->scatype = \"\";\n        $this->spcent = \"\";\n    }\n}\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/src/Qcloud/Cos/ImageParamTemplate/PicOperationsTransformation.php",
    "content": "<?php\n\nnamespace Qcloud\\Cos\\ImageParamTemplate;\n\nclass PicOperationsTransformation {\n    private $isPicInfo;\n    private $rules;\n\n    public function __construct() {\n        $this->isPicInfo = 0;\n        $this->rules = array();\n    }\n\n    public function setIsPicInfo($value) {\n        $this->isPicInfo = $value;\n    }\n\n    public function addRule(ImageTemplate $template, $fileid = \"\", $bucket = \"\") {\n        $rule = $template->queryString();\n        if($rule){\n            $item = array();\n            $item['rule'] = $rule;\n            if($fileid){\n                $item['fileid'] = $fileid;\n            }\n            if($bucket) {\n                $item['bucket'] = $bucket;\n            }\n            $this->rules[] = $item;\n        }\n    }\n\n    public function getIsPicInfo() {\n        return $this->isPicInfo;\n    }\n\n    public function getRules() {\n        return $this->rules;\n    }\n\n    public function queryString() {\n        $res = \"\";\n        $picOperations = array();\n       if($this->isPicInfo){\n           $picOperations['is_pic_info'] = $this->isPicInfo;\n       }\n       if($this->rules){\n           $picOperations['rules'] = $this->rules;\n       }\n       if($picOperations){\n           $res = json_encode($picOperations);\n       }\n       return $res;\n    }\n\n    public function resetRule() {\n        $this->isPicInfo = 0;\n        $this->rules = array();\n    }\n}\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/src/Qcloud/Cos/ImageParamTemplate/TextWatermarkTemplate.php",
    "content": "<?php\n\nnamespace Qcloud\\Cos\\ImageParamTemplate;\n\n/**\n * Parses default XML exception responses\n */\nclass TextWatermarkTemplate extends ImageTemplate\n{\n    private $text;\n    private $font;\n    private $fontsize;\n    private $fill;\n    private $dissolve;\n    private $gravity;\n    private $dx;\n    private $dy;\n    private $batch;\n    private $degree;\n\n    public function __construct() {\n        parent::__construct();\n        $this->text = \"\";\n        $this->font = \"\";\n        $this->fontsize = \"\";\n        $this->fill = \"\";\n        $this->dissolve = \"\";\n        $this->gravity = \"\";\n        $this->dx = \"\";\n        $this->dy = \"\";\n        $this->batch = \"\";\n        $this->degree = \"\";\n    }\n\n    public function setText($value) {\n        $this->text = \"/text/\" . $this->ciBase64($value);\n    }\n\n    public function setFont($value) {\n        $this->font = \"/font/\" . $this->ciBase64($value);\n    }\n\n    public function setFontsize($value) {\n        $this->fontsize = \"/fontsize/\" . $value;\n    }\n\n    public function setFill($value) {\n        $this->fill = \"/fill/\" . $this->ciBase64($value);\n    }\n\n    public function setDissolve($value) {\n        $this->dissolve = \"/dissolve/\" . $value;\n    }\n\n    public function setGravity($value) {\n        $this->gravity = \"/gravity/\" . $value;\n    }\n\n    public function setDx($value) {\n        $this->dx = \"/dx/\" . $value;\n    }\n\n    public function setDy($value) {\n        $this->dy = \"/dy/\" . $value;\n    }\n\n    public function setBatch($value) {\n        $this->batch = \"/batch/\" . $value;\n    }\n\n    public function setDegree($value) {\n        $this->degree = \"/degree/\" . $value;\n    }\n\n    public function getText() {\n        return $this->text;\n    }\n\n    public function getFont() {\n        return $this->font;\n    }\n\n    public function getFontsize() {\n        return $this->fontsize;\n    }\n\n    public function getFill() {\n        return $this->fill;\n    }\n\n    public function getDissolve() {\n        return $this->dissolve;\n    }\n\n    public function getGravity() {\n        return $this->gravity;\n    }\n\n    public function getDx() {\n        return $this->dx;\n    }\n\n    public function getDy() {\n        return $this->dy;\n    }\n\n    public function getBatch() {\n        return $this->batch;\n    }\n\n    public function getDegree() {\n        return $this->degree;\n    }\n\n    public function queryString() {\n        $head = \"watermark/2\";\n        $res = \"\";\n        if($this->text) {\n            $res .= $this->text;\n        }\n        if($this->font) {\n            $res .= $this->font;\n        }\n        if($this->fontsize) {\n            $res .= $this->fontsize;\n        }\n        if($this->fill) {\n            $res .= $this->fill;\n        }\n        if($this->dissolve) {\n            $res .= $this->dissolve;\n        }\n        if($this->gravity) {\n            $res .= $this->gravity;\n        }\n        if($this->dx) {\n            $res .= $this->dx;\n        }\n        if($this->dy) {\n            $res .= $this->dy;\n        }\n        if($this->batch) {\n            $res .= $this->batch;\n        }\n        if($this->degree) {\n            $res .= $this->degree;\n        }\n        if($res) {\n            $res = $head . $res;\n        }\n        return $res;\n    }\n\n    public function resetRule() {\n        $this->text = \"\";\n        $this->font = \"\";\n        $this->fontsize = \"\";\n        $this->fill = \"\";\n        $this->dissolve = \"\";\n        $this->gravity = \"\";\n        $this->dx = \"\";\n        $this->dy = \"\";\n        $this->batch = \"\";\n        $this->degree = \"\";\n    }\n}\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/src/Qcloud/Cos/MultipartUpload.php",
    "content": "<?php\n\nnamespace Qcloud\\Cos;\n\nuse Qcloud\\Cos\\Exception\\CosException;\nuse GuzzleHttp\\Pool;\n\nuse function GuzzleHttp\\Promise\\rejection_for;\n\nclass MultipartUpload {\n    const MIN_PART_SIZE = 1048576;\n    const MAX_PART_SIZE = 5368709120;\n    const DEFAULT_PART_SIZE = 52428800;\n    const MAX_PARTS     = 10000;\n\n    private $client;\n    private $options;\n    private $partSize;\n    private $parts;\n    private $body;\n    private $progress;\n    private $totolSize;\n    private $uploadedSize;\n\n    public function __construct($client, $body, $options = array()) {\n        $minPartSize = $options['PartSize'];\n        unset($options['PartSize']);\n        $this->body = $body;\n        $this->client = $client;\n        $this->options = $options;\n        $this->partSize = $this->calculatePartSize($minPartSize);\n        $this->concurrency = isset($options['Concurrency']) ? $options['Concurrency'] : 10;\n        $this->progress = isset($options['Progress']) ? $options['Progress'] : function($totolSize, $uploadedSize) {};\n        $this->parts = [];\n        $this->partNumberList = [];\n        $this->uploadedSize = 0;\n        $this->totolSize = $this->body->getSize();\n        $this->needMd5 = isset($options['ContentMD5']) ? $options['ContentMD5'] : true;\n        $this->retry = isset($options['Retry']) ? $options['Retry'] : 3;\n    }\n    public function performUploading() {\n        $uploadId= $this->initiateMultipartUpload();\n        $this->uploadParts($uploadId);\n        foreach ( $this->parts as $key => $row ){\n            $num1[$key] = $row ['PartNumber'];\n            $num2[$key] = $row ['ETag'];\n        }\n        array_multisort($num1, SORT_ASC, $num2, SORT_ASC, $this->parts);\n        return $this->client->completeMultipartUpload(array(\n            'Bucket' => $this->options['Bucket'],\n            'Key' => $this->options['Key'],\n            'UploadId' => $uploadId,\n            'Parts' => $this->parts)\n        );\n\n    }\n    public function uploadParts($uploadId) {\n        $uploadRequests = function ($uploadId) {\n            $partNumber = 1;\n            $index = 1;\n            $offset = 0;\n            $partSize = 0;\n            for ( ; ; $partNumber ++) {\n                if ($this->body->eof()) {\n                    break;\n                }\n                $body = $this->body->read($this->partSize);\n                $partSize = $this->partSize;\n                if ($offset + $this->partSize >= $this->totolSize) {\n                    $partSize = $this->totolSize - $offset;\n                }\n                $offset += $partSize;\n                if (empty($body)) {\n                    break;\n                }\n                if (isset($this->parts[$partNumber])) {\n                    continue;\n                }\n                $this->partNumberList[$index]['PartNumber'] = $partNumber;\n                $this->partNumberList[$index]['PartSize'] = $partSize;\n                $params = array(\n                    'Bucket' => $this->options['Bucket'],\n                    'Key' => $this->options['Key'],\n                    'UploadId' => $uploadId,\n                    'PartNumber' => $partNumber,\n                    'Body' => $body,\n                    'ContentMD5' => $this->needMd5\n                );\n                if ($this->needMd5 == false) {\n                    unset($params[\"ContentMD5\"]);\n                }\n                if (!isset($this->parts[$partNumber])) {\n                    $command = $this->client->getCommand('uploadPart', $params);\n                    $request = $this->client->commandToRequestTransformer($command);\n                    $index ++;\n                    yield $request;\n                }\n            }\n        }; \n        $pool = new Pool($this->client->httpClient, $uploadRequests($uploadId), [\n            'concurrency' => $this->concurrency,\n            'fulfilled' => function ($response, $index) {\n                $index = $index + 1;\n                $partNumber = $this->partNumberList[$index]['PartNumber'];\n                $partSize = $this->partNumberList[$index]['PartSize'];\n                $etag = $response->getHeaders()[\"ETag\"][0];\n                $part = array('PartNumber' => $partNumber, 'ETag' => $etag);\n                $this->parts[$partNumber] = $part;\n                $this->uploadedSize += $partSize;\n                call_user_func_array($this->progress, [$this->totolSize, $this->uploadedSize]);\n            },\n           \n            'rejected' => function ($reason, $index) {\n                printf(\"part [%d] upload failed, reason: %s\\n\", $index, $reason);\n                throw($reason);\n            }\n        ]);\n        $promise = $pool->promise();\n        $promise->wait();\n    }\n\n    public function resumeUploading() {\n        $uploadId = $this->options['UploadId'];\n        $rt = $this->client->ListParts(\n            array('UploadId' => $uploadId,\n                'Bucket'=>$this->options['Bucket'],\n                'Key'=>$this->options['Key']));\n                $parts = array();\n        if (count($rt['Parts']) > 0) {\n            foreach ($rt['Parts'] as $part) {\n                $this->parts[$part['PartNumber']] = array('PartNumber' => $part['PartNumber'], 'ETag' => $part['ETag']);\n            }\n        }\n        $this->uploadParts($uploadId);\n        foreach ( $this->parts as $key => $row ){\n            $num1[$key] = $row ['PartNumber'];\n            $num2[$key] = $row ['ETag'];\n        }\n        array_multisort($num1, SORT_ASC, $num2, SORT_ASC, $this->parts);\n        return $this->client->completeMultipartUpload(array(\n            'Bucket' => $this->options['Bucket'],\n            'Key' => $this->options['Key'],\n            'UploadId' => $uploadId,\n            'Parts' => $this->parts)\n        );\n    }\n\n    private function calculatePartSize($minPartSize)\n    {   \n        $partSize = intval(ceil(($this->body->getSize() / self::MAX_PARTS)));\n        $partSize = max($minPartSize, $partSize);\n        $partSize = min($partSize, self::MAX_PART_SIZE);\n        $partSize = max($partSize, self::MIN_PART_SIZE);\n        return $partSize;\n    }\n\n    private function initiateMultipartUpload() {\n        $result = $this->client->createMultipartUpload($this->options);\n        return $result['UploadId'];\n    }\n\n}\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/src/Qcloud/Cos/RangeDownload.php",
    "content": "<?php\n\nnamespace Qcloud\\Cos;\n\nuse Exception;\nuse Qcloud\\Cos\\Exception\\CosException;\nuse GuzzleHttp\\Pool;\n\nclass RangeDownload {\n    const DEFAULT_PART_SIZE = 52428800;\n\n    private $client;\n    private $options;\n    private $partSize;\n    private $parts;\n    private $progress;\n    private $totolSize;\n    private $resumableJson;\n\n    public function __construct( $client, $contentLength, $saveAs, $options = array() ) {\n        $this->client = $client;\n        $this->options = $options;\n        $this->partSize = isset( $options['PartSize'] ) ? $options['PartSize'] : self::DEFAULT_PART_SIZE;\n        $this->concurrency = isset( $options['Concurrency'] ) ? $options['Concurrency'] : 10;\n        $this->progress = isset( $options['Progress'] ) ? $options['Progress'] : function( $totolSize, $downloadedSize ) {\n        }\n        ;\n        $this->parts = [];\n        $this->partNumberList = [];\n        $this->downloadedSize = 0;\n        $this->totolSize = $contentLength;\n        $this->saveAs = $saveAs;\n        $this->resumableJson = [];\n        $this->resumableJson = isset( $options['ResumableJson'] ) ? $options['ResumableJson'] : [];\n        unset( $options['ResumableJson'] );\n        $this->resumableTaskFile = isset( $options['ResumableTaskFile'] ) ? $options['ResumableTaskFile'] : $saveAs . '.cosresumabletask';\n        $this->resumableDownload = isset( $options['ResumableDownload'] ) ? $options['ResumableDownload'] : false;\n    }\n\n    public function performdownloading() {\n        if ( $this->resumableDownload ) {\n            try {\n                if ( file_exists( $this->resumableTaskFile ) ) {\n                    $origin_content = file_get_contents( $this->resumableTaskFile );\n                    $this->resumableJsonLocal = json_decode( $origin_content, true );\n                    if ( $this->resumableJsonLocal == null ) {\n                        $this->resumableJsonLocal = [];\n                    } else if ( $this->resumableJsonLocal['LastModified'] != $this->resumableJson['LastModified'] ||\n                    $this->resumableJsonLocal['ContentLength'] != $this->resumableJson['ContentLength'] ||\n                    $this->resumableJsonLocal['ETag'] != $this->resumableJson['ETag'] ||\n                    $this->resumableJsonLocal['Crc64ecma'] != $this->resumableJson['Crc64ecma'] ) {\n                        $this->resumableDownload = false;\n                    }\n                }\n            } catch ( \\Exception $e ) {\n                $this->resumableDownload = false;\n            }\n        }\n        try {\n            if ($this->resumableDownload) {\n                $this->fp = fopen( $this->saveAs, 'r+' );\n            } else {\n                $this->fp = fopen( $this->saveAs, 'wb' );\n            }\n            $rt = $this->donwloadParts();\n            $this->resumableJson['DownloadedBlocks'] = [];\n            if (file_exists( $this->resumableTaskFile )) {\n                unlink($this->resumableTaskFile);\n            }\n        } catch ( \\Exception $e ) {\n            $this->fp_resume = fopen( $this->resumableTaskFile, 'wb' );\n            fwrite( $this->fp_resume, json_encode( $this->resumableJson ) );\n            fclose( $this->fp_resume );\n            throw ( $e );\n        }\n        finally {\n            fclose( $this->fp );\n        }\n        return $rt;\n    }\n\n    public function donwloadParts() {\n        $uploadRequests = function () {\n            $index = 1;\n            $partSize = 0;\n            for ( $offset = 0; $offset < $this->totolSize; ) {\n                $partSize = $this->partSize;\n                if ( $offset + $this->partSize >= $this->totolSize ) {\n                    $partSize = $this->totolSize - $offset;\n                }\n                $this->parts[$index]['PartSize'] = $partSize;\n                $this->parts[$index]['Offset'] = $offset;\n                $begin = $offset;\n                $end = $offset + $partSize - 1;\n                if ( !( $this->resumableDownload &&\n                isset( $this->resumableJsonLocal['DownloadedBlocks'] ) &&\n                in_array( ['from' => $begin, 'to' => $end], $this->resumableJsonLocal['DownloadedBlocks'] ) ) ) {\n                    $params = array(\n                        'Bucket' => $this->options['Bucket'],\n                        'Key' => $this->options['Key'],\n                        'Range' => sprintf( 'bytes=%d-%d', $begin, $end )\n                    );\n                    $command = $this->client->getCommand( 'getObject', $params );\n                    $request = $this->client->commandToRequestTransformer( $command );\n                    $index += 1;\n                    yield $request;\n                } else {\n                    $this->resumableJson['DownloadedBlocks'][] = ['from' => $begin, 'to' => $end];\n                    $this->downloadedSize += $partSize;\n                    call_user_func_array( $this->progress, [$this->totolSize, $this->downloadedSize] );\n                }\n                $offset += $partSize;\n            }\n\n        }\n        ;\n\n        $pool = new Pool( $this->client->httpClient, $uploadRequests(), [\n            'concurrency' => $this->concurrency,\n            'fulfilled' => function ( $response, $index ) {\n                $index = $index + 1;\n                $stream = $response->getBody();\n                $offset = $this->parts[$index]['Offset'];\n                $partsize = 8192;\n                $begin = $offset;\n                fseek( $this->fp, $offset );\n                while ( !$stream->eof() ) {\n                    $output = $stream->read( $partsize );\n                    $writeLen = fwrite( $this->fp, $output );\n                    $offset += $writeLen;\n                }\n                $end = $offset - 1;\n                $this->resumableJson['DownloadedBlocks'][] = ['from' => $begin, 'to' => $end];\n                $partSize = $this->parts[$index]['PartSize'];\n                $this->downloadedSize += $partSize;\n                call_user_func_array( $this->progress, [$this->totolSize, $this->downloadedSize] );\n            }\n            ,\n            'rejected' => function ( $reason, $index ) {\n                throw( $reason );\n            }\n        ] );\n        $promise = $pool->promise();\n        $promise->wait();\n    }\n\n}\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/src/Qcloud/Cos/Request/BodyLocation.php",
    "content": "<?php\n\nnamespace Qcloud\\Cos\\Request;\n\nuse GuzzleHttp\\Command\\Guzzle\\RequestLocation\\AbstractLocation;\nuse GuzzleHttp\\Command\\CommandInterface;\nuse GuzzleHttp\\Command\\Guzzle\\Parameter;\nuse GuzzleHttp\\Psr7;\nuse Psr\\Http\\Message\\MessageInterface;\nuse Psr\\Http\\Message\\RequestInterface;\n\n/**\n * Adds a raw/binary body to a request.\n * This is here because: https://github.com/guzzle/guzzle-services/issues/160\n */\nclass BodyLocation extends AbstractLocation\n{\n\n    /**\n     * Set the name of the location\n     *\n     * @param string $locationName\n     */\n    public function __construct($locationName = 'body')\n    {\n        parent::__construct($locationName);\n    }\n\n    /**\n     * @param CommandInterface $command\n     * @param RequestInterface $request\n     * @param Parameter        $param\n     *\n     * @return MessageInterface\n     */\n    public function visit(\n        CommandInterface $command,\n        RequestInterface $request,\n        Parameter $param\n    ) {\n        $value = $request->getBody()->getContents();\n        if ('' !== $value) {\n            throw new \\RuntimeException('Only one \"body\" location may exist per operation');\n        }\n        // binary string data from bound parameter\n        $value = $command[$param->getName()];\n        return $request->withBody(Psr7\\stream_for($value));\n    }\n}\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/src/Qcloud/Cos/ResultTransformer.php",
    "content": "<?php\n\nnamespace Qcloud\\Cos;\n\nuse Guzzle\\Service\\Description\\Parameter;\nuse Guzzle\\Service\\Description\\ServiceDescription;\nuse GuzzleHttp\\HandlerStack;\nuse Psr\\Http\\Message\\RequestInterface;\nuse Psr\\Http\\Message\\ResponseInterface;\nuse Qcloud\\Cos\\Signature;\nuse GuzzleHttp\\Command\\Guzzle\\Description;\nuse GuzzleHttp\\Command\\Guzzle\\GuzzleClient;\nuse GuzzleHttp\\Command\\CommandInterface;\nuse GuzzleHttp\\Exception\\RequestException;\nuse GuzzleHttp\\Middleware;\nuse GuzzleHttp\\Psr7;\nuse GuzzleHttp\\Psr7\\Uri;\nuse GuzzleHttp\\Command\\Result;\nuse InvalidArgumentException;\n\n\nclass ResultTransformer {\n    private $config;\n    private $operation;\n\n    public function __construct($config, $operation) {\n        $this->config = $config;\n        $this->operation = $operation;\n    }\n\n    public function writeDataToLocal(CommandInterface $command, RequestInterface $request, ResponseInterface $response) {\n        $action = $command->getName();\n        if ($action == \"GetObject\") {\n            if (isset($command['SaveAs'])) {\n                $fp = fopen($command['SaveAs'], \"wb\");\n                $stream = $response->getBody();\n                $offset = 0;\n                $partsize = 8192;\n                while (!$stream->eof()) {\n                    $output = $stream->read($partsize);\n                    fseek($fp, $offset);\n                    fwrite($fp, $output);\n                    $offset += $partsize;\n                }\n                fclose($fp);\n            }\n        }\n    }\n\n    public function metaDataTransformer(CommandInterface $command, ResponseInterface $response, Result $result) {\n        $headers = $response->getHeaders();\n        $metadata = array();\n        foreach ($headers as $key => $value) {\n            if (strpos($key, \"x-cos-meta-\") === 0) {\n                $metadata[substr($key, 11)] = $value[0];\n            }\n        }\n        if (!empty($metadata)) {\n            $result['Metadata'] = $metadata;\n        }\n        return $result;\n    }\n\n    public function extraHeadersTransformer(CommandInterface $command, RequestInterface $request, Result $result) {\n        if ($command['Key'] != null && $result['Key'] == null) {\n            $result['Key'] = $command['Key'];\n        }\n        if ($command['Bucket'] != null && $result['Bucket'] == null) {\n            $result['Bucket'] = $command['Bucket'];\n        }\n        $result['Location'] = $request->getHeader(\"Host\")[0] .  $request->getUri()->getPath();\n        return $result;\n    }\n\n    public function selectContentTransformer(CommandInterface $command, Result $result) {\n        $action = $command->getName();\n        if ($action == \"SelectObjectContent\") {\n            $result['Data'] = $this->getSelectContents($result);\n        }\n        return $result;\n    }\n\n    public function ciContentInfoTransformer(CommandInterface $command, Result $result) {\n        $action = $command->getName();\n        if ($action == \"ImageInfo\" || $action == \"ImageExif\" || $action == \"ImageAve\") {\n            $length = intval($result['ContentLength']);\n            if($length > 0){\n                $result['Data'] = $this->geCiContentInfo($result, $length);\n            }\n        }\n\n        if ($action == \"PutObject\" && isset($command[\"PicOperations\"]) &&  $command[\"PicOperations\"]) {\n            $picOperations = json_decode($command[\"PicOperations\"], true);\n            $picRuleSize = isset($picOperations['rules']) && is_array($picOperations['rules']) ? sizeof($picOperations['rules']) : 0;\n            $length = intval($result['ContentLength']);\n            if($length > 0){\n                $content = $this->geCiContentInfo($result, $length);\n                $obj = simplexml_load_string($content, \"SimpleXMLElement\", LIBXML_NOCDATA);\n                $xmlData = json_decode(json_encode($obj),true);\n                if ($picRuleSize == 1 && isset($xmlData['ProcessResults']['Object'])){\n                    $tmp = $xmlData['ProcessResults']['Object'];\n                    unset($xmlData['ProcessResults']['Object']);\n                    $xmlData['ProcessResults']['Object'][] = $tmp;\n                }\n                $result['Data'] = $xmlData;\n            }\n        }\n\n        if ($action == \"GetBucketGuetzli\" ) {\n            $length = intval($result['ContentLength']);\n            if($length > 0){\n                $content = $this->geCiContentInfo($result, $length);\n                $obj = simplexml_load_string($content, \"SimpleXMLElement\", LIBXML_NOCDATA);\n                $arr = json_decode(json_encode($obj),true);\n                $result['GuetzliStatus'] = isset($arr[0]) ? $arr[0] : '';\n            }\n        }\n\n        return $result;\n    }\n\n    public function geCiContentInfo($result, $length) {\n        $f = $result['Body'];\n        $data = \"\";\n        while (!$f->eof()) {\n            $tmp = $f->read($length);\n            if (empty($tmp)) {\n                break;\n            }\n            $data .= $tmp;\n        }\n        return $data;\n    }\n\n    public function getSelectContents($result) {\n        $f = $result['RawData'];\n        while (!$f->eof()) {\n            $data = array();\n            $tmp = $f->read(4);\n            if (empty($tmp)) {\n                break;\n            }\n            $totol_length = (int)(unpack(\"N\", $tmp)[1]);\n            $headers_length = (int)(unpack(\"N\", $f->read(4))[1]);\n            $body_length = $totol_length - $headers_length - 16;\n            $predule_crc = (int)(unpack(\"N\", $f->read(4))[1]);\n            $headers = array();\n            for ($offset = 0; $offset < $headers_length;) {\n                $key_length = (int)(unpack(\"C\", $f->read(1))[1]);\n                $key = $f->read($key_length);\n    \n                $head_value_type = (int)(unpack(\"C\", $f->read(1))[1]);\n    \n                $value_length = (int)(unpack(\"n\", $f->read(2))[1]);\n                $value = $f->read($value_length);\n                $offset += 4 + $key_length + $value_length;\n                if ($key == \":message-type\") {\n                    $data['MessageType'] = $value;\n                }\n                if ($key == \":event-type\") {\n                    $data['EventType'] = $value;\n                }\n                if ($key == \":error-code\") {\n                    $data['ErrorCode'] = $value;\n                }\n                if ($key == \":error-message\") {\n                    $data['ErrorMessage'] = $value;\n                }\n            }\n            $body = $f->read($body_length);\n            $message_crc = (int)(unpack(\"N\", $f->read(4))[1]);\n            $data['Body'] = $body;\n            yield $data;\n        }\n    }\n    public function __destruct() {\n    }\n\n}\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/src/Qcloud/Cos/Serializer.php",
    "content": "<?php\nnamespace Qcloud\\Cos;\nuse GuzzleHttp\\Command\\CommandInterface;\nuse GuzzleHttp\\Command\\Guzzle\\SchemaValidator;\nuse GuzzleHttp\\Command\\Guzzle\\DescriptionInterface;\nuse GuzzleHttp\\Command\\Guzzle\\Serializer as DefaultSerializer;\nuse Psr\\Http\\Message\\RequestInterface;\n/**\n * Override Request serializer to modify authentication mechanism\n */\nclass Serializer extends DefaultSerializer\n{\n    /**\n     * {@inheritdoc}\n     */\n    public function __construct(\n        DescriptionInterface $description,\n        array $requestLocations = []\n    ) {\n        // Override Guzzle's body location as it isn't raw binary data\n        $requestLocations['body'] = new Request\\BodyLocation;\n        parent::__construct($description, $requestLocations);\n    }\n    /**\n     * Authorization header is Loco's preferred authorization method.\n     * Add Authorization header to request if API key is set, unless query is explicitly configured as auth method.\n     * Unset key from command to avoid sending it as a query param.\n     *\n     * @override\n     *\n     * @param CommandInterface $command\n     * @param RequestInterface $request\n     *\n     * @return RequestInterface\n     *\n     * @throws \\InvalidArgumentException\n     */\n    protected function prepareRequest(\n        CommandInterface $command,\n        RequestInterface $request\n    ) {\n\t\t/*\n        if ($command->offsetExists('key') === true) {\n            $mode = empty($command->offsetGet('auth')) === false\n                    ? $command->offsetGet('auth')\n                    : 'loco';\n            if ($mode !== 'query') {\n                // else use Authorization header of various types\n                if ($mode === 'loco') {\n                    $value = 'Loco '.$command->offsetGet('key');\n                    $request = $request->withHeader('Authorization', $value);\n                } elseif ($mode === 'basic') {\n                    $value = 'Basic '.base64_encode($command->offsetGet('key').':');\n                    $request = $request->withHeader('Authorization', $value);\n                } else {\n                    throw new \\InvalidArgumentException(\"Invalid auth type: {$mode}\");\n                }\n                // avoid request sending key parameter in query string\n                $command->offsetUnset('key');\n            }\n        }\n        // Remap legacy parameters to common `data` binding on request body\n        static $remap = [\n            'import' => ['src'=>'data'],\n            'translate' => ['translation'=>'data'],\n        ];\n        $name = $command->getName();\n        if (isset($remap[$name])) {\n            foreach ($remap[$name] as $old => $new) {\n                if ($command->offsetExists($old)) {\n                    $command->offsetSet($new, $command->offsetGet($old));\n                    $command->offsetUnset($old);\n                }\n            }\n        }\n\t\t*/\n        return parent::prepareRequest($command, $request);\n    }\n}\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/src/Qcloud/Cos/Service.php",
    "content": "<?php\nnamespace Qcloud\\Cos;\n// http://guzzle3.readthedocs.io/webservice-client/guzzle-service-descriptions.html\nclass Service {\n    public static function getService() {\n        return array(\n            'name' => 'Cos Service',\n            'apiVersion' => 'V5',\n            'description' => 'Cos V5 API Service',\n            'operations' => array(\n                // 舍弃一个分块上传且删除已上传的分片块的方法.\n                'AbortMultipartUpload' => array(\n                    'httpMethod' => 'DELETE',\n                    'uri' => '/{Bucket}{/Key*}',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'AbortMultipartUploadOutput',\n                    'responseType' => 'model',\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri'),\n                        'Key' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                            'minLength' => 1,\n                            'filters' => array(\n                                'Qcloud\\\\Cos\\\\Client::explodeKey')),\n                        'UploadId' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'query',\n                            'sentAs' => 'uploadId'\n                        )\n                    )\n                ),\n                // 创建存储桶（Bucket）的方法.\n                'CreateBucket' => array(\n                    'httpMethod' => 'PUT',\n                    'uri' => '/{Bucket}',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'CreateBucketOutput',\n                    'responseType' => 'model',\n                    'data' => array(\n                        'xmlRoot' => array(\n                            'name' => 'CreateBucketConfiguration')),\n                    'parameters' => array(\n                        'ACL' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-acl'),\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri'\n                        )\n                    )\n                ),\n                // 完成整个分块上传的方法.\n                'CompleteMultipartUpload' => array(\n                    'httpMethod' => 'POST',\n                    'uri' => '/{Bucket}{/Key*}',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'CompleteMultipartUploadOutput',\n                    'responseType' => 'model',\n                    'data' => array(\n                        'xmlRoot' => array(\n                            'name' => 'CompleteMultipartUpload'\n                        )\n                    ),\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri'),\n                        'Key' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                            'minLength' => 1,\n                            'filters' => array(\n                                'Qcloud\\\\Cos\\\\Client::explodeKey'\n                            )\n                        ),\n                        'Parts' => array(\n                            'type' => 'array',\n                            'location' => 'xml',\n                            'data' => array(\n                                'xmlFlattened' => true),\n                            'items' => array(\n                                'name' => 'CompletedPart',\n                                'type' => 'object',\n                                'sentAs' => 'Part',\n                                'properties' => array(\n                                    'ETag' => array(\n                                        'type' => 'string'\n                                    ),\n                                    'PartNumber' => array(\n                                        'type' => 'numeric'\n                                    )\n                                )\n                            )\n                        ),\n                        'UploadId' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'query',\n                            'sentAs' => 'uploadId',\n                        ),\n                        'PicOperations' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'Pic-Operations',\n                        )\n                    )\n                ),\n                // 初始化分块上传的方法.\n                'CreateMultipartUpload' => array(\n                    'httpMethod' => 'POST',\n                    'uri' => '/{Bucket}{/Key*}?uploads',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'CreateMultipartUploadOutput',\n                    'responseType' => 'model',\n                    'data' => array(\n                        'xmlRoot' => array(\n                            'name' => 'CreateMultipartUploadRequest'\n                        )\n                    ),\n                    'parameters' => array(\n                        'ACL' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-acl',\n                        ),\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        ),\n                        'CacheControl' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'Cache-Control',\n                        ),\n                        'ContentDisposition' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'Content-Disposition',\n                        ),\n                        'ContentEncoding' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'Content-Encoding',\n                        ),\n                        'ContentLanguage' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'Content-Language',\n                        ),\n                        'ContentType' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'Content-Type',\n                        ),\n                        'Expires' => array(\n                            'type' => array(\n                                'object',\n                                'string',\n                                'integer',\n                            ),\n                            'format' => 'date-time-http',\n                            'location' => 'header',\n                        ),\n                        'GrantFullControl' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-grant-full-control',\n                        ),\n                        'GrantRead' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-grant-read',\n                        ),\n                        'GrantReadACP' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-grant-read-acp',\n                        ),\n                        'GrantWriteACP' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-grant-write-acp',\n                        ),\n                        'Key' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                            'minLength' => 1,\n                            'filters' => array(\n                                'Qcloud\\\\Cos\\\\Client::explodeKey'\n                            )\n                        ),\n                        'ServerSideEncryption' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption',\n                        ),\n                        'StorageClass' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-storage-class',\n                        ),\n                        'WebsiteRedirectLocation' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-website-redirect-location',\n                        ),\n                        'SSECustomerAlgorithm' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption-customer-algorithm',\n                        ),\n                        'SSECustomerKey' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption-customer-key',\n                        ),\n                        'SSECustomerKeyMD5' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption-customer-key-MD5',\n                        ),\n                        'SSEKMSKeyId' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption-aws-kms-key-id',\n                        ),\n                        'RequestPayer' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-payer',\n                        ),\n                        'ACP' => array(\n                            'type' => 'object',\n                            'additionalProperties' => true,\n                        ),\n                        'PicOperations' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'Pic-Operations',\n                        )\n                    )\n                ),\n                // 复制对象的方法.\n                'CopyObject' => array(\n                    'httpMethod' => 'PUT',\n                    'uri' => '/{Bucket}{/Key*}',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'CopyObjectOutput',\n                    'responseType' => 'model',\n                    'data' => array(\n                        'xmlRoot' => array(\n                            'name' => 'CopyObjectRequest',\n                        ),\n                    ),\n                    'parameters' => array(\n                        'ACL' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-acl',\n                        ),\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        ),\n                        'CacheControl' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'Cache-Control',\n                        ),\n                        'ContentDisposition' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'Content-Disposition',\n                        ),\n                        'ContentEncoding' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'Content-Encoding',\n                        ),\n                        'ContentLanguage' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'Content-Language',\n                        ),\n                        'ContentType' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'Content-Type',\n                        ),\n                        'CopySource' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-copy-source',\n                        ),\n                        'CopySourceIfMatch' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-copy-source-if-match',\n                        ),\n                        'CopySourceIfModifiedSince' => array(\n                            'type' => array(\n                                'object',\n                                'string',\n                                'integer',\n                            ),\n                            'format' => 'date-time-http',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-copy-source-if-modified-since',\n                        ),\n                        'CopySourceIfNoneMatch' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-copy-source-if-none-match',\n                        ),\n                        'CopySourceIfUnmodifiedSince' => array(\n                            'type' => array(\n                                'object',\n                                'string',\n                                'integer',\n                            ),\n                            'format' => 'date-time-http',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-copy-source-if-unmodified-since',\n                        ),\n                        'Expires' => array(\n                            'type' => array(\n                                'object',\n                                'string',\n                                'integer',\n                            ),\n                            'format' => 'date-time-http',\n                            'location' => 'header',\n                        ),\n                        'GrantFullControl' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-grant-full-control',\n                        ),\n                        'GrantRead' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-grant-read',\n                        ),\n                        'GrantReadACP' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-grant-read-acp',\n                        ),\n                        'GrantWriteACP' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-grant-write-acp',\n                        ),\n                        'Key' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                            'minLength' => 1,\n                            'filters' => array(\n                                'Qcloud\\\\Cos\\\\Client::explodeKey')\n                        ),\n                        'MetadataDirective' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-metadata-directive',\n                        ),\n                        'ServerSideEncryption' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption',\n                        ),\n                        'StorageClass' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-storage-class',\n                        ),\n                        'WebsiteRedirectLocation' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-website-redirect-location',\n                        ),\n                        'SSECustomerAlgorithm' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption-customer-algorithm',\n                        ),\n                        'SSECustomerKey' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption-customer-key',\n                        ),\n                        'CopySourceSSECustomerAlgorithm' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-copy-source-server-side-encryption-customer-algorithm',\n                        ),\n                        'CopySourceSSECustomerKey' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-copy-source-server-side-encryption-customer-key',\n                        ),\n                        'CopySourceSSECustomerKeyMD5' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-copy-source-server-side-encryption-customer-key-MD5',\n                        ),\n                        'RequestPayer' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-payer',\n                        ),\n                        'ACP' => array(\n                            'type' => 'object',\n                            'additionalProperties' => true,\n                        )\n                    ),\n                ),\n                // 删除存储桶 (Bucket)的方法.\n                'DeleteBucket' => array(\n                    'httpMethod' => 'DELETE',\n                    'uri' => '/{Bucket}',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'DeleteBucketOutput',\n                    'responseType' => 'model',\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri'\n                        )\n                    )\n                ),\n                // 删除跨域访问配置信息的方法\n                'DeleteBucketCors' => array(\n                    'httpMethod' => 'DELETE',\n                    'uri' => '/{Bucket}?cors',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'DeleteBucketCorsOutput',\n                    'responseType' => 'model',\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        ),\n                    ),\n                ),\n                // 删除存储桶标签信息的方法\n                'DeleteBucketTagging' => array(\n                    'httpMethod' => 'DELETE',\n                    'uri' => '/{Bucket}?tagging',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'DeleteBucketTaggingOutput',\n                    'responseType' => 'model',\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        ),\n                    ),\n                ),\n                // 删除存储桶标清单任务的方法\n                'DeleteBucketInventory' => array(\n                    'httpMethod' => 'Delete',\n                    'uri' => '/{Bucket}?inventory',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'DeleteBucketInventoryOutput',\n                    'responseType' => 'model',\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        ),\n                        'Id' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'query',\n                            'sentAs' => 'id',\n                        )\n                    ),\n                ),\n                // 删除 COS 上单个对象的方法.\n                'DeleteObject' => array(\n                    'httpMethod' => 'DELETE',\n                    'uri' => '/{Bucket}{/Key*}',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'DeleteObjectOutput',\n                    'responseType' => 'model',\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri'\n                        ),\n                        'Key' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                            'minLength' => 1,\n                            'filters' => array(\n                                'Qcloud\\\\Cos\\\\Client::explodeKey'\n                            )\n                        ),\n                        'MFA' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-mfa',\n                        ),\n                        'VersionId' => array(\n                            'type' => 'string',\n                            'location' => 'query',\n                            'sentAs' => 'versionId',\n                        ),\n                        'RequestPayer' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-payer',\n                        )\n                    )\n                ),\n                // 批量删除 COS 对象的方法.\n                'DeleteObjects' => array(\n                    'httpMethod' => 'POST',\n                    'uri' => '/{Bucket}?delete',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'DeleteObjectsOutput',\n                    'responseType' => 'model',\n                    'data' => array(\n                        'xmlRoot' => array(\n                            'name' => 'Delete',\n                        ),\n                        'contentMd5' => true,\n                    ),\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        ),\n                        'Objects' => array(\n                            'required' => true,\n                            'type' => 'array',\n                            'location' => 'xml',\n                            'data' => array(\n                                'xmlFlattened' => true,\n                            ),\n                            'items' => array(\n                                'type' => 'object',\n                                'sentAs' => 'Object',\n                                'properties' => array(\n                                    'Key' => array(\n                                        'required' => true,\n                                        'type' => 'string',\n                                        'minLength' => 1,\n                                    ),\n                                    'VersionId' => array(\n                                        'type' => 'string',\n                                    ),\n                                ),\n                            ),\n                        ),\n                        'Quiet' => array(\n                            'type' => 'boolean',\n                            'format' => 'boolean-string',\n                            'location' => 'xml',\n                        ),\n                        'MFA' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-mfa',\n                        ),\n                        'RequestPayer' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-payer',\n                        )\n                    ),\n                ),\n                // 删除存储桶（Bucket） 的website的方法.\n                'DeleteBucketWebsite' => array(\n                    'httpMethod' => 'DELETE',\n                    'uri' => '/{Bucket}?website',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'DeleteBucketWebsiteOutput',\n                    'responseType' => 'model',\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        ),\n                    ),\n                ),\n                // 删除存储桶（Bucket） 的生命周期配置的方法.\n                'DeleteBucketLifecycle' => array(\n                    'httpMethod' => 'DELETE',\n                    'uri' => '/{Bucket}?lifecycle',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'DeleteBucketLifecycleOutput',\n                    'responseType' => 'model',\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        ),\n                    ),\n                ),\n                // 删除跨区域复制配置的方法.\n                'DeleteBucketReplication' => array(\n                    'httpMethod' => 'DELETE',\n                    'uri' => '/{Bucket}?replication',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'DeleteBucketReplicationOutput',\n                    'responseType' => 'model',\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        ),\n                    ),\n                ),\n                // 下载对象的方法.\n                'GetObject' => array(\n                    'httpMethod' => 'GET',\n                    'uri' => '/{Bucket}{/Key*}',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'GetObjectOutput',\n                    'responseType' => 'model',\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri'\n                        ),\n                        'IfMatch' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'If-Match'\n                        ),\n                        'IfModifiedSince' => array(\n                            'type' => array(\n                                'object',\n                                'string',\n                                'integer'\n                            ),\n                            'format' => 'date-time-http',\n                            'location' => 'header',\n                            'sentAs' => 'If-Modified-Since'\n                        ),\n                        'IfNoneMatch' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'If-None-Match'\n                        ),\n                        'IfUnmodifiedSince' => array(\n                            'type' => array(\n                                'object',\n                                'string',\n                                'integer'\n                            ),\n                            'format' => 'date-time-http',\n                            'location' => 'header',\n                            'sentAs' => 'If-Unmodified-Since'\n                        ),\n                        'Key' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                            'minLength' => 1,\n                            'filters' => array(\n                                'Qcloud\\\\Cos\\\\Client::explodeKey'\n                            )\n                        ),\n                        'Range' => array(\n                            'type' => 'string',\n                            'location' => 'header'),\n                        'ResponseCacheControl' => array(\n                            'type' => 'string',\n                            'location' => 'query',\n                            'sentAs' => 'response-cache-control'\n                        ),\n                        'ResponseContentDisposition' => array(\n                            'type' => 'string',\n                            'location' => 'query',\n                            'sentAs' => 'response-content-disposition'\n                        ),\n                        'ResponseContentEncoding' => array(\n                            'type' => 'string',\n                            'location' => 'query',\n                            'sentAs' => 'response-content-encoding'\n                        ),\n                        'ResponseContentLanguage' => array(\n                            'type' => 'string',\n                            'location' => 'query',\n                            'sentAs' => 'response-content-language'\n                        ),\n                        'ResponseContentType' => array(\n                            'type' => 'string',\n                            'location' => 'query',\n                            'sentAs' => 'response-content-type'\n                        ),\n                        'ResponseExpires' => array(\n                            'type' => array(\n                                'object',\n                                'string',\n                                'integer'\n                            ),\n                            'format' => 'date-time-http',\n                            'location' => 'query',\n                            'sentAs' => 'response-expires'\n                        ),\n                        'VersionId' => array(\n                            'type' => 'string',\n                            'location' => 'query',\n                            'sentAs' => 'versionId',\n                        ),\n                        'SSECustomerAlgorithm' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption-customer-algorithm',\n                        ),\n                        'SSECustomerKey' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption-customer-key',\n                        ),\n                        'SSECustomerKeyMD5' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption-customer-key-MD5',\n                        ),\n                        'TrafficLimit' => array(\n                            'type' => 'integer',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-traffic-limit',\n                        )\n                    )\n                ),\n                // 获取 COS 对象的访问权限信息（Access Control List, ACL）的方法.\n                'GetObjectAcl' => array(\n                    'httpMethod' => 'GET',\n                    'uri' => '/{Bucket}{/Key*}?acl',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'GetObjectAclOutput',\n                    'responseType' => 'model',\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        ),\n                        'Key' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                            'minLength' => 1,\n                            'filters' => array(\n                                'Qcloud\\\\Cos\\\\Client::explodeKey')\n                        ),\n                        'VersionId' => array(\n                            'type' => 'string',\n                            'location' => 'query',\n                            'sentAs' => 'versionId',\n                        ),\n                        'RequestPayer' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-payer',\n                        )\n                    )\n                ),\n                // 获取存储桶（Bucket) 的访问权限信息（Access Control List, ACL）的方法.\n                'GetBucketAcl' => array(\n                    'httpMethod' => 'GET',\n                    'uri' => '/{Bucket}?acl',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'GetBucketAclOutput',\n                    'responseType' => 'model',\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri'\n                        )\n                    )\n                ),\n                // 查询存储桶（Bucket) 跨域访问配置信息的方法.\n                'GetBucketCors' => array(\n                    'httpMethod' => 'GET',\n                    'uri' => '/{Bucket}?cors',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'GetBucketCorsOutput',\n                    'responseType' => 'model',\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        )\n                    ),\n                ),\n                // 查询存储桶（Bucket) Domain配置信息的方法.\n                'GetBucketDomain' => array(\n                    'httpMethod' => 'GET',\n                    'uri' => '/{Bucket}?domain',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'GetBucketDomainOutput',\n                    'responseType' => 'model',\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        )\n                    ),\n                ),\n                // 查询存储桶（Bucket) Accelerate配置信息的方法.\n                'GetBucketAccelerate' => array(\n                    'httpMethod' => 'GET',\n                    'uri' => '/{Bucket}?accelerate',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'GetBucketAccelerateOutput',\n                    'responseType' => 'model',\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        )\n                    ),\n                ),\n                // 查询存储桶（Bucket) Website配置信息的方法.\n                'GetBucketWebsite' => array(\n                    'httpMethod' => 'GET',\n                    'uri' => '/{Bucket}?website',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'GetBucketWebsiteOutput',\n                    'responseType' => 'model',\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        )\n                    ),\n                ),\n                // 查询存储桶（Bucket) 的生命周期配置的方法.\n                'GetBucketLifecycle' => array(\n                    'httpMethod' => 'GET',\n                    'uri' => '/{Bucket}?lifecycle',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'GetBucketLifecycleOutput',\n                    'responseType' => 'model',\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        )\n                    ),\n                ),\n                // 获取存储桶（Bucket）版本控制信息的方法.\n                'GetBucketVersioning' => array(\n                    'httpMethod' => 'GET',\n                    'uri' => '/{Bucket}?versioning',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'GetBucketVersioningOutput',\n                    'responseType' => 'model',\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        )\n                    ),\n                ),\n                // 获取存储桶（Bucket) 跨区域复制配置信息的方法.\n                'GetBucketReplication' => array(\n                    'httpMethod' => 'GET',\n                    'uri' => '/{Bucket}?replication',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'GetBucketReplicationOutput',\n                    'responseType' => 'model',\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        )\n                    ),\n                ),\n                // 获取存储桶（Bucket) 所在的地域信息的方法.\n                'GetBucketLocation' => array(\n                    'httpMethod' => 'GET',\n                    'uri' => '/{Bucket}?location',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'GetBucketLocationOutput',\n                    'responseType' => 'model',\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        ),\n                    ),\n                ),\n                // 获取存储桶（Bucket) Notification信息的方法.\n                'GetBucketNotification' => array(\n                    'httpMethod' => 'GET',\n                    'uri' => '/{Bucket}?notification',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'GetBucketNotificationOutput',\n                    'responseType' => 'model',\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        )\n                    ),\n                ),\n                // 获取存储桶（Bucket) 日志信息的方法.\n                'GetBucketLogging' => array(\n                    'httpMethod' => 'GET',\n                    'uri' => '/{Bucket}?logging',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'GetBucketLoggingOutput',\n                    'responseType' => 'model',\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        )\n                    ),\n                ),\n                // 获取存储桶（Bucket) 清单信息的方法.\n                'GetBucketInventory' => array(\n                    'httpMethod' => 'GET',\n                    'uri' => '/{Bucket}?inventory',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'GetBucketInventoryOutput',\n                    'responseType' => 'model',\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        ),\n                        'Id' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'query',\n                            'sentAs' => 'id',\n                        )\n                    ),\n                ),\n                // 获取存储桶（Bucket) 标签信息的方法.\n                'GetBucketTagging' => array(\n                    'httpMethod' => 'GET',\n                    'uri' => '/{Bucket}?tagging',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'GetBucketTaggingOutput',\n                    'responseType' => 'model',\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        )\n                    ),\n                ),\n                // 分块上传的方法.\n                'UploadPart' => array(\n                    'httpMethod' => 'PUT',\n                    'uri' => '/{Bucket}{/Key*}',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'UploadPartOutput',\n                    'responseType' => 'model',\n                    'data' => array(\n                        'xmlRoot' => array(\n                            'name' => 'UploadPartRequest'\n                        )\n                    ),\n                    'parameters' => array(\n                        'Body' => array(\n                            'type' => array(\n                                'any'),\n                            'location' => 'body'\n                        ),\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri'\n                        ),\n                        'ContentLength' => array(\n                            'type' => 'numeric',\n                            'minimum'=> 0,\n                            'location' => 'header',\n                            'sentAs' => 'Content-Length'\n                        ),\n                        'ContentMD5' => array(\n                            'type' => array(\n                                'string',\n                                'boolean'\n                            ),\n                            'location' => 'header',\n                            'sentAs' => 'Content-MD5'\n                        ),\n                        'Key' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                            'minLength' => 1,\n                            'filters' => array(\n                                'Qcloud\\\\Cos\\\\Client::explodeKey'\n                            )\n                        ),\n                        'PartNumber' => array(\n                            'required' => true,\n                            'type' => 'numeric',\n                            'location' => 'query',\n                            'sentAs' => 'partNumber'),\n                        'UploadId' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'query',\n                            'sentAs' => 'uploadId'),\n                        'ServerSideEncryption' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption',\n                        ),\n                        'SSECustomerAlgorithm' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption-customer-algorithm',\n                        ),\n                        'SSECustomerKey' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption-customer-key',\n                        ),\n                        'SSECustomerKeyMD5' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption-customer-key-MD5',\n                        ),\n                        'RequestPayer' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-payer',\n                        ),\n                        'TrafficLimit' => array(\n                            'type' => 'integer',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-traffic-limit',\n                        )\n                    )\n                ),\n                // 上传对象的方法.\n                'PutObject' => array(\n                    'httpMethod' => 'PUT',\n                    'uri' => '/{Bucket}{/Key*}',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'PutObjectOutput',\n                    'responseType' => 'model',\n                    'data' => array(\n                        'xmlRoot' => array(\n                            'name' => 'PutObjectRequest'\n                        )\n                    ),\n                    'parameters' => array(\n                        'ACL' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-acl'\n                        ),\n                        'Body' => array(\n                            'required' => true,\n                            'type' => array(\n                                'any'\n                            ),\n                            'location' => 'body'\n                        ),\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri'\n                        ),\n                        'CacheControl' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'Cache-Control'\n                        ),\n                        'ContentDisposition' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'Content-Disposition'\n                        ),\n                        'ContentEncoding' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'Content-Encoding'\n                        ),\n                        'ContentLanguage' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'Content-Language'\n                        ),\n                        'ContentLength' => array(\n                            'type' => 'numeric',\n                            'minimum'=> 0,\n                            'location' => 'header',\n                            'sentAs' => 'Content-Length'\n                        ),\n                        'ContentMD5' => array(\n                            'type' => array(\n                                'string',\n                                'boolean'\n                            ),\n                            'location' => 'header',\n                            'sentAs' => 'Content-MD5'\n                        ),\n                        'ContentType' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'Content-Type'\n                        ),\n                        'Key' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                            'minLength' => 1,\n                            'filters' => array(\n                                'Qcloud\\\\Cos\\\\Client::explodeKey'\n                            )\n                        ),\n                        'ServerSideEncryption' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption',\n                        ),\n                        'StorageClass' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-storage-class',\n                        ),\n                        'WebsiteRedirectLocation' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-website-redirect-location',\n                        ),\n                        'SSECustomerAlgorithm' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption-customer-algorithm',\n                        ),\n                        'SSECustomerKey' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption-customer-key',\n                        ),\n                        'SSECustomerKeyMD5' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption-customer-key-MD5',\n                        ),\n                        'SSEKMSKeyId' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption-cos-kms-key-id',\n                        ),\n                        'RequestPayer' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-payer',\n                        ),\n                        'ACP' => array(\n                            'type' => 'object',\n                            'additionalProperties' => true,\n                        ),\n                        'PicOperations' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'Pic-Operations',\n                        ),\n                        'TrafficLimit' => array(\n                            'type' => 'integer',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-traffic-limit',\n                        )\n                    )\n                ),\n                // 设置 COS 对象的访问权限信息（Access Control List, ACL）的方法.\n                'PutObjectAcl' => array(\n                    'httpMethod' => 'PUT',\n                    'uri' => '/{Bucket}{/Key*}?acl',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'PutObjectAclOutput',\n                    'responseType' => 'model',\n                    'data' => array(\n                        'xmlRoot' => array(\n                            'name' => 'AccessControlPolicy',\n                        ),\n                    ),\n                    'parameters' => array(\n                        'ACL' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-acl',\n                        ),\n                        'Grants' => array(\n                            'type' => 'array',\n                            'location' => 'xml',\n                            'sentAs' => 'AccessControlList',\n                            'items' => array(\n                                'name' => 'Grant',\n                                'type' => 'object',\n                                'properties' => array(\n                                    'Grantee' => array(\n                                        'type' => 'object',\n                                        'properties' => array(\n                                            'DisplayName' => array(\n                                                'type' => 'string'),\n                                            'ID' => array(\n                                                'type' => 'string'),\n                                            'Type' => array(\n                                                'type' => 'string',\n                                                'sentAs' => 'xsi:type',\n                                                'data' => array(\n                                                    'xmlAttribute' => true,\n                                                    'xmlNamespace' => 'http://www.w3.org/2001/XMLSchema-instance')),\n                                            'URI' => array(\n                                                'type' => 'string') )),\n                                    'Permission' => array(\n                                        'type' => 'string',\n                                    ),\n                                ),\n                            ),\n                        ),\n                        'Owner' => array(\n                            'type' => 'object',\n                            'location' => 'xml',\n                            'properties' => array(\n                                'DisplayName' => array(\n                                    'type' => 'string',\n                                ),\n                                'ID' => array(\n                                    'type' => 'string',\n                                ),\n                            ),\n                        ),\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        ),\n                        'GrantFullControl' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-grant-full-control',\n                        ),\n                        'GrantRead' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-grant-read',\n                        ),\n                        'GrantReadACP' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-grant-read-acp',\n                        ),\n                        'GrantWrite' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-grant-write',\n                        ),\n                        'GrantWriteACP' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-grant-write-acp',\n                        ),\n                        'Key' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                            'minLength' => 1,\n                            'filters' => array(\n                                'Qcloud\\\\Cos\\\\Client::explodeKey')\n                        ),\n                        'RequestPayer' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-payer',\n                        ),\n                        'ACP' => array(\n                            'type' => 'object',\n                            'additionalProperties' => true,\n                        ),\n                    )\n                ),\n                // 设置存储桶（Bucket） 的访问权限（Access Control List, ACL)的方法.\n                'PutBucketAcl' => array(\n                    'httpMethod' => 'PUT',\n                    'uri' => '/{Bucket}?acl',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'PutBucketAclOutput',\n                    'responseType' => 'model',\n                    'data' => array(\n                        'xmlRoot' => array(\n                            'name' => 'AccessControlPolicy',\n                        ),\n                    ),\n                    'parameters' => array(\n                        'ACL' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-acl',\n                        ),\n                        'Grants' => array(\n                            'type' => 'array',\n                            'location' => 'xml',\n                            'sentAs' => 'AccessControlList',\n                            'items' => array(\n                                'name' => 'Grant',\n                                'type' => 'object',\n                                'properties' => array(\n                                    'Grantee' => array(\n                                        'type' => 'object',\n                                        'properties' => array(\n                                            'DisplayName' => array(\n                                                'type' => 'string',\n                                            ),\n                                            'EmailAddress' => array(\n                                                'type' => 'string',\n                                            ),\n                                            'ID' => array(\n                                                'type' => 'string',\n                                            ),\n                                            'Type' => array(\n                                                'required' => true,\n                                                'type' => 'string',\n                                                'sentAs' => 'xsi:type',\n                                                'data' => array(\n                                                    'xmlAttribute' => true,\n                                                    'xmlNamespace' => 'http://www.w3.org/2001/XMLSchema-instance',\n                                                ),\n                                            ),\n                                            'URI' => array(\n                                                'type' => 'string',\n                                            ),\n                                        ),\n                                    ),\n                                    'Permission' => array(\n                                        'type' => 'string',\n                                    ),\n                                ),\n                            ),\n                        ),\n                        'Owner' => array(\n                            'type' => 'object',\n                            'location' => 'xml',\n                            'properties' => array(\n                                'DisplayName' => array(\n                                    'type' => 'string',\n                                ),\n                                'ID' => array(\n                                    'type' => 'string',\n                                ),\n                            ),\n                        ),\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        ),\n                        'GrantFullControl' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-grant-full-control',\n                        ),\n                        'GrantRead' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-grant-read',\n                        ),\n                        'GrantReadACP' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-grant-read-acp',\n                        ),\n                        'GrantWrite' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-grant-write',\n                        ),\n                        'GrantWriteACP' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-grant-write-acp',\n                        ),\n                        'ACP' => array(\n                            'type' => 'object',\n                            'additionalProperties' => true,\n                        ),\n                    ),\n                ),\n                // 设置存储桶（Bucket） 的跨域配置信息的方法.\n                'PutBucketCors' => array(\n                    'httpMethod' => 'PUT',\n                    'uri' => '/{Bucket}?cors',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'PutBucketCorsOutput',\n                    'responseType' => 'model',\n                    'data' => array(\n                        'xmlRoot' => array(\n                            'name' => 'CORSConfiguration',\n                        ),\n                        'contentMd5' => true,\n                    ),\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        ),\n                        'CORSRules' => array(\n                            'required' => true,\n                            'type' => 'array',\n                            'location' => 'xml',\n                            'data' => array(\n                                'xmlFlattened' => true,\n                            ),\n                            'items' => array(\n                                'name' => 'CORSRule',\n                                'type' => 'object',\n                                'sentAs' => 'CORSRule',\n                                'properties' => array(\n                                    'ID' => array(\n                                        'type' => 'string',\n                                    ),\n                                    'AllowedHeaders' => array(\n                                        'type' => 'array',\n                                        'data' => array(\n                                            'xmlFlattened' => true,\n                                        ),\n                                        'items' => array(\n                                            'name' => 'AllowedHeader',\n                                            'type' => 'string',\n                                            'sentAs' => 'AllowedHeader',\n                                        ),\n                                    ),\n                                    'AllowedMethods' => array(\n                                        'required' => true,\n                                        'type' => 'array',\n                                        'data' => array(\n                                            'xmlFlattened' => true,\n                                        ),\n                                        'items' => array(\n                                            'name' => 'AllowedMethod',\n                                            'type' => 'string',\n                                            'sentAs' => 'AllowedMethod',\n                                        ),\n                                    ),\n                                    'AllowedOrigins' => array(\n                                        'required' => true,\n                                        'type' => 'array',\n                                        'data' => array(\n                                            'xmlFlattened' => true,\n                                        ),\n                                        'items' => array(\n                                            'name' => 'AllowedOrigin',\n                                            'type' => 'string',\n                                            'sentAs' => 'AllowedOrigin',\n                                        ),\n                                    ),\n                                    'ExposeHeaders' => array(\n                                        'type' => 'array',\n                                        'data' => array(\n                                            'xmlFlattened' => true,\n                                        ),\n                                        'items' => array(\n                                            'name' => 'ExposeHeader',\n                                            'type' => 'string',\n                                            'sentAs' => 'ExposeHeader',\n                                        ),\n                                    ),\n                                    'MaxAgeSeconds' => array(\n                                        'type' => 'numeric',\n                                    ),\n                                ),\n                            ),\n                        ),\n                    ),\n                ),\n                // 设置存储桶（Bucket） 的Domain信息的方法.\n                'PutBucketDomain' => array(\n                    'httpMethod' => 'PUT',\n                    'uri' => '/{Bucket}?domain',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'PutBucketDomainOutput',\n                    'responseType' => 'model',\n                    'data' => array(\n                        'xmlRoot' => array(\n                            'name' => 'DomainConfiguration',\n                        ),\n                        'contentMd5' => true,\n                    ),\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        ),\n                        'DomainRules' => array(\n                            'required' => true,\n                            'type' => 'array',\n                            'location' => 'xml',\n                            'data' => array(\n                                'xmlFlattened' => true,\n                            ),\n                            'items' => array(\n                                'name' => 'DomainRule',\n                                'type' => 'object',\n                                'sentAs' => 'DomainRule',\n                                'properties' => array(\n                                    'Status' => array(\n                                        'required' => true,\n                                        'type' => 'string',\n                                    ),\n                                    'Name' => array(\n                                        'required' => true,\n                                        'type' => 'string',\n                                    ),\n                                    'Type' => array(\n                                        'required' => true,\n                                        'type' => 'string',\n                                    ),\n                                    'ForcedReplacement' => array(\n                                        'type' => 'string',\n                                    ),\n                                ),\n                            ),\n                        ),\n                    ),\n                ),\n                // 设置存储桶（Bucket) 生命周期配置的方法.\n                'PutBucketLifecycle' => array(\n                    'httpMethod' => 'PUT',\n                    'uri' => '/{Bucket}?lifecycle',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'PutBucketLifecycleOutput',\n                    'responseType' => 'model',\n                    'data' => array(\n                        'xmlRoot' => array(\n                            'name' => 'LifecycleConfiguration',\n                        ),\n                        'contentMd5' => true,\n                    ),\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        ),\n                        'Rules' => array(\n                            'required' => true,\n                            'type' => 'array',\n                            'location' => 'xml',\n                            'data' => array(\n                                'xmlFlattened' => true,\n                            ),\n                            'items' => array(\n                                'name' => 'Rule',\n                                'type' => 'object',\n                                'sentAs' => 'Rule',\n                                'properties' => array(\n                                    'Expiration' => array(\n                                        'type' => 'object',\n                                        'properties' => array(\n                                            'Date' => array(\n                                                'type' => array(\n                                                    'object',\n                                                    'string',\n                                                    'integer',\n                                                ),\n                                                'format' => 'date-time',\n                                            ),\n                                            'Days' => array(\n                                                'type' => 'numeric',\n                                            ),\n                                        ),\n                                    ),\n                                    'ID' => array(\n                                        'type' => 'string',\n                                    ),\n                                    'Filter' => array(\n                                        'type' => 'object',\n                                        'require' => true,\n                                        'properties' => array(\n                                            'Prefix' => array(\n                                                'type' => 'string',\n                                                'require' => true,\n                                            ),\n                                            'Tag' => array(\n                                                'type' => 'object',\n                                                'require' => true,\n                                                'properties' => array(\n                                                    'Key' => array(\n                                                        'type' => 'string'\n                                                    ),\n                                                    'filters' => array(\n                                                        'Qcloud\\\\Cos\\\\Client::explodeKey'),\n                                                    'Value' => array(\n                                                        'type' => 'string'\n                                                    ),\n                                                )\n                                            )\n                                        ),\n                                    ),\n                                    'Status' => array(\n                                        'required' => true,\n                                        'type' => 'string',\n                                    ),\n                                    'Transitions' => array(\n                                        'type' => 'array',\n                                        'location' => 'xml',\n                                        'data' => array(\n                                            'xmlFlattened' => true,\n                                        ),\n                                        'items' => array(\n                                            'name' => 'Transition',\n                                            'type' => 'object',\n                                            'sentAs' => 'Transition',\n                                            'properties' => array(\n                                                'Date' => array(\n                                                    'type' => array(\n                                                        'object',\n                                                        'string',\n                                                        'integer',\n                                                    ),\n                                                    'format' => 'date-time',\n                                                ),\n                                                'Days' => array(\n                                                    'type' => 'numeric',\n                                                ),\n                                                'StorageClass' => array(\n                                                    'type' => 'string',\n                                                )))),\n                                    'NoncurrentVersionTransition' => array(\n                                        'type' => 'object',\n                                        'properties' => array(\n                                            'NoncurrentDays' => array(\n                                                'type' => 'numeric',\n                                            ),\n                                            'StorageClass' => array(\n                                                'type' => 'string',\n                                            ),\n                                        ),\n                                    ),\n                                    'NoncurrentVersionExpiration' => array(\n                                        'type' => 'object',\n                                        'properties' => array(\n                                            'NoncurrentDays' => array(\n                                                'type' => 'numeric',\n                                            ),\n                                        ),\n                                    ),\n                                ),\n                            ),\n                        ),\n                    ),\n                ),\n                // 存储桶（Bucket）版本控制的方法.\n                'PutBucketVersioning' => array(\n                    'httpMethod' => 'PUT',\n                    'uri' => '/{Bucket}?versioning',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'PutBucketVersioningOutput',\n                    'responseType' => 'model',\n                    'data' => array(\n                        'xmlRoot' => array(\n                            'name' => 'VersioningConfiguration',\n                        ),\n                    ),\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        ),\n                        'MFA' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-mfa',\n                        ),\n                        'MFADelete' => array(\n                            'type' => 'string',\n                            'location' => 'xml',\n                            'sentAs' => 'MfaDelete',\n                        ),\n                        'Status' => array(\n                            'type' => 'string',\n                            'location' => 'xml',\n                        ),\n                    ),\n                ),\n                // 配置存储桶（Bucket) Accelerate的方法.\n                'PutBucketAccelerate' => array(\n                    'httpMethod' => 'PUT',\n                    'uri' => '/{Bucket}?accelerate',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'PutBucketAccelerateOutput',\n                    'responseType' => 'model',\n                    'data' => array(\n                        'xmlRoot' => array(\n                            'name' => 'AccelerateConfiguration',\n                        ),\n                        'xmlAllowEmpty' => true,\n                    ),\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        ),\n                        'Status' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'xml',\n                        ),\n                        'Type' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'xml',\n                        ),\n                    ),\n                ),\n                // 配置存储桶（Bucket) website的方法.\n                'PutBucketWebsite' => array(\n                    'httpMethod' => 'PUT',\n                    'uri' => '/{Bucket}?website',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'PutBucketWebsiteOutput',\n                    'responseType' => 'model',\n                    'data' => array(\n                        'xmlRoot' => array(\n                            'name' => 'WebsiteConfiguration',\n                        ),\n                        'xmlAllowEmpty' => true,\n                    ),\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        ),\n                        'ErrorDocument' => array(\n                            'type' => 'object',\n                            'location' => 'xml',\n                            'properties' => array(\n                                'Key' => array(\n                                    'type' => 'string',\n                                    'minLength' => 1,\n                                ),\n                            ),\n                        ),\n                        'IndexDocument' => array(\n                            'required' => true,\n                            'type' => 'object',\n                            'location' => 'xml',\n                            'properties' => array(\n                                'Suffix' => array(\n                                    'required' => true,\n                                    'type' => 'string',\n                                ),\n                            ),\n                        ),\n                        'RedirectAllRequestsTo' => array(\n                            'type' => 'object',\n                            'location' => 'xml',\n                            'properties' => array(\n                                'HostName' => array(\n                                    'type' => 'string',\n                                ),\n                                'Protocol' => array(\n                                    'type' => 'string',\n                                ),\n                            ),\n                        ),\n                        'RoutingRules' => array(\n                            'type' => 'array',\n                            'location' => 'xml',\n                            'items' => array(\n                                'name' => 'RoutingRule',\n                                'type' => 'object',\n                                'properties' => array(\n                                    'Condition' => array(\n                                        'type' => 'object',\n                                        'properties' => array(\n                                            'HttpErrorCodeReturnedEquals' => array(\n                                                'type' => 'string',\n                                            ),\n                                            'KeyPrefixEquals' => array(\n                                                'type' => 'string',\n                                            ),\n                                        ),\n                                    ),\n                                    'Redirect' => array(\n                                        'type' => 'object',\n                                        'properties' => array(\n                                            'HostName' => array(\n                                                'type' => 'string',\n                                            ),\n                                            'HttpRedirectCode' => array(\n                                                'type' => 'string',\n                                            ),\n                                            'Protocol' => array(\n                                                'type' => 'string',\n                                            ),\n                                            'ReplaceKeyPrefixWith' => array(\n                                                'type' => 'string',\n                                            ),\n                                            'ReplaceKeyWith' => array(\n                                                'type' => 'string',\n                                            ),\n                                        ),\n                                    ),\n                                ),\n                            ),\n                        ),\n                    ),\n                ),\n                // 配置存储桶（Bucket) 跨区域复制的方法.\n                'PutBucketReplication' => array(\n                    'httpMethod' => 'PUT',\n                    'uri' => '/{Bucket}?replication',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'PutBucketReplicationOutput',\n                    'responseType' => 'model',\n                    'data' => array(\n                        'xmlRoot' => array(\n                            'name' => 'ReplicationConfiguration',\n                        ),\n                        'contentMd5' => true,\n                    ),\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        ),\n                        'Role' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'xml',\n                        ),\n                        'Rules' => array(\n                            'required' => true,\n                            'type' => 'array',\n                            'location' => 'xml',\n                            'data' => array(\n                                'xmlFlattened' => true,\n                            ),\n                            'items' => array(\n                                'name' => 'ReplicationRule',\n                                'type' => 'object',\n                                'sentAs' => 'Rule',\n                                'properties' => array(\n                                    'ID' => array(\n                                        'type' => 'string',\n                                    ),\n                                    'Prefix' => array(\n                                        'required' => true,\n                                        'type' => 'string',\n                                    ),\n                                    'Status' => array(\n                                        'required' => true,\n                                        'type' => 'string',\n                                    ),\n                                    'Destination' => array(\n                                        'required' => true,\n                                        'type' => 'object',\n                                        'properties' => array(\n                                            'Bucket' => array(\n                                                'required' => true,\n                                                'type' => 'string',\n                                            ),\n                                            'StorageClass' => array(\n                                                'type' => 'string',\n                                            ),\n                                        ),\n                                    ),\n                                ),\n                            ),\n                        ),\n                    ),\n                ),\n                // 设置存储桶（Bucket） 的回调设置的方法.\n                'PutBucketNotification' => array(\n                    'httpMethod' => 'PUT',\n                    'uri' => '/{Bucket}?notification',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'PutBucketNotificationOutput',\n                    'responseType' => 'model',\n                    'data' => array(\n                        'xmlRoot' => array(\n                            'name' => 'NotificationConfiguration',\n                        ),\n                    ),\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        ),\n                        'CloudFunctionConfigurations' => array(\n                            'type' => 'array',\n                            'location' => 'xml',\n                            'data' => array(\n                                'xmlFlattened' => true,\n                            ),\n                            'items' => array(\n                                'name' => 'CloudFunctionConfiguration',\n                                'type' => 'object',\n                                'sentAs' => 'CloudFunctionConfiguration',\n                                'properties' => array(\n                                    'Id' => array(\n                                        'type' => 'string',\n                                    ),\n                                    'CloudFunction' => array(\n                                        'required' => true,\n                                        'type' => 'string',\n                                        'sentAs' => 'CloudFunction',\n                                    ),\n                                    'Events' => array(\n                                        'required' => true,\n                                        'type' => 'array',\n                                        'data' => array(\n                                            'xmlFlattened' => true,\n                                        ),\n                                        'items' => array(\n                                            'name' => 'Event',\n                                            'type' => 'string',\n                                            'sentAs' => 'Event',\n                                        ),\n                                    ),\n                                    'Filter' => array(\n                                        'type' => 'object',\n                                        'properties' => array(\n                                            'Key' => array(\n                                                'type' => 'object',\n                                                'sentAs' => 'Key',\n                                                'properties' => array(\n                                                    'FilterRules' => array(\n                                                        'type' => 'array',\n                                                        'data' => array(\n                                                            'xmlFlattened' => true,\n                                                        ),\n                                                        'items' => array(\n                                                            'name' => 'FilterRule',\n                                                            'type' => 'object',\n                                                            'sentAs' => 'FilterRule',\n                                                            'properties' => array(\n                                                                'Name' => array(\n                                                                    'type' => 'string',\n                                                                ),\n                                                                'Value' => array(\n                                                                    'type' => 'string',\n                                                                ),\n                                                            ),\n                                                        ),\n                                                    ),\n                                                ),\n                                            ),\n                                            'filters' => array(\n                                                'Qcloud\\\\Cos\\\\Client::explodeKey')\n                                        ),\n                                    ),\n                                ),\n                            ),\n                        ),\n                    ),\n                ),\n                // 配置存储桶（Bucket) 标签的方法.\n                'PutBucketTagging' => array(\n                    'httpMethod' => 'PUT',\n                    'uri' => '/{Bucket}?tagging',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'PutBucketTaggingOutput',\n                    'responseType' => 'model',\n                    'data' => array(\n                        'xmlRoot' => array(\n                            'name' => 'Tagging',\n                        ),\n                        'contentMd5' => true,\n                    ),\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        ),\n                        'TagSet' => array(\n                            'required' => true,\n                            'type' => 'array',\n                            'location' => 'xml',\n                            'items' => array(\n                                'name' => 'TagRule',\n                                'type' => 'object',\n                                'sentAs' => 'Tag',\n                                'properties' => array(\n                                    'Key' => array(\n                                        'required' => true,\n                                        'type' => 'string',\n                                    ),\n                                    'Value' => array(\n                                        'required' => true,\n                                        'type' => 'string',\n                                    ),\n                                ),\n                            ),\n                        ),\n                    ),\n                ),\n                //开启存储桶（Bucket) 日志服务的方法.\n                'PutBucketLogging' => array(\n                    'httpMethod' => 'PUT',\n                    'uri' => '/{Bucket}?logging',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'PutBucketLoggingOutput',\n                    'responseType' => 'model',\n                    'data' => array(\n                        'xmlRoot' => array(\n                            'name' => 'BucketLoggingStatus',\n                        ),\n                        'contentMd5' => true,\n                    ),\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        ),\n                        'LoggingEnabled' => array(\n                            'location' => 'xml',\n                            'type' => 'object',\n                            'properties' => array(\n                                'TargetBucket' => array(\n                                    'type' => 'string',\n                                    'location' => 'xml',\n                                ),\n                                'TargetPrefix' => array(\n                                    'type' => 'string',\n                                    'location' => 'xml',\n                                ),\n                            )\n                        ),\n                    ),\n                ),\n                // 配置存储桶（Bucket) 清单的方法.\n                'PutBucketInventory' => array(\n                    'httpMethod' => 'PUT',\n                    'uri' => '/{Bucket}?inventory',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'PutBucketInventoryOutput',\n                    'responseType' => 'model',\n                    'data' => array(\n                        'xmlRoot' => array(\n                            'name' => 'InventoryConfiguration',\n                        ),\n                        'contentMd5' => true,\n                    ),\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        ),\n                        'Id' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'xml',\n                        ),\n                        'IsEnabled' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'xml',\n                        ),\n                        'Destination' => array(\n                            'type' => 'object',\n                            'location' => 'xml',\n                            'properties' => array(\n                                'COSBucketDestination'=> array(\n                                    'type' => 'object',\n                                    'properties' => array(\n                                        'Format' => array(\n                                            'type' => 'string',\n                                            'require' => true,\n                                        ),\n                                        'AccountId' => array(\n                                            'type' => 'string',\n                                            'require' => true,\n                                        ),\n                                        'Bucket' => array(\n                                            'type' => 'string',\n                                            'require' => true,\n                                        ),\n                                        'Prefix' => array(\n                                            'type' => 'string',\n                                        ),\n                                        'Encryption' => array(\n                                            'type' => 'object',\n                                            'properties' => array(\n                                                'SSE-COS' => array(\n                                                    'type' => 'string',\n                                                ),\n                                            ),\n                                        ),\n                                    ),\n                                ),\n                            ),\n                        ),\n                        'Schedule' => array(\n                            'required' => true,\n                            'type' => 'object',\n                            'location' => 'xml',\n                            'properties' => array(\n                                'Frequency' => array(\n                                    'type' => 'string',\n                                    'require' => true,\n                                ),\n                            )\n                        ),\n                        'Filter' => array(\n                            'type' => 'object',\n                            'location' => 'xml',\n                            'properties' => array(\n                                'Prefix' => array(\n                                    'type' => 'string',\n                                ),\n                            )\n                        ),\n                        'IncludedObjectVersions' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'xml',\n                        ),\n                        'OptionalFields' => array(\n                            'type' => 'array',\n                            'location' => 'xml',\n                            'items' => array(\n                                'name' => 'Fields',\n                                'type' => 'string',\n                                'sentAs' => 'Field',\n                            ),\n                        ),\n                    ),\n                ),\n                // 回热归档对象的方法.\n                'RestoreObject' => array(\n                    'httpMethod' => 'POST',\n                    'uri' => '/{Bucket}{/Key*}?restore',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'RestoreObjectOutput',\n                    'responseType' => 'model',\n                    'data' => array(\n                        'xmlRoot' => array(\n                            'name' => 'RestoreRequest',\n                        ),\n                    ),\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        ),\n                        'Key' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                            'minLength' => 1,\n                            'filters' => array(\n                                'Qcloud\\\\Cos\\\\Client::explodeKey')\n                        ),\n                        'VersionId' => array(\n                            'type' => 'string',\n                            'location' => 'query',\n                            'sentAs' => 'versionId',\n                        ),\n                        'Days' => array(\n                            'required' => true,\n                            'type' => 'numeric',\n                            'location' => 'xml',\n                        ),\n                        'CASJobParameters' => array(\n                            'type' => 'object',\n                            'location' => 'xml',\n                            'properties' => array(\n                                'Tier' => array(\n                                    'type' => 'string',\n                                    'required' => true,\n                                ),\n                            ),\n                        ),\n                        'RequestPayer' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-payer',\n                        ),\n                    ),\n                ),\n                // 查询存储桶（Bucket）中正在进行中的分块上传对象的方法.\n                'ListParts' => array(\n                    'httpMethod' => 'GET',\n                    'uri' => '/{Bucket}{/Key*}',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'ListPartsOutput',\n                    'responseType' => 'model',\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri'\n                        ),\n                        'Key' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                            'minLength' => 1,\n                            'filters' => array(\n                                'Qcloud\\\\Cos\\\\Client::explodeKey'\n                            )\n                        ),\n                        'MaxParts' => array(\n                            'type' => 'numeric',\n                            'location' => 'query',\n                            'sentAs' => 'max-parts'),\n                        'PartNumberMarker' => array(\n                            'type' => 'numeric',\n                            'location' => 'query',\n                            'sentAs' => 'part-number-marker'\n                        ),\n                        'UploadId' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'query',\n                            'sentAs' => 'uploadId'\n                        )\n                    )\n                ),\n                // 查询存储桶（Bucket) 下的部分或者全部对象的方法.\n                'ListObjects' => array(\n                    'httpMethod' => 'GET',\n                    'uri' => '/{Bucket}',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'ListObjectsOutput',\n                    'responseType' => 'model',\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri'\n                        ),\n                        'Delimiter' => array(\n                            'type' => 'string',\n                            'location' => 'query',\n                            'sentAs' => 'delimiter'\n                        ),\n                        'EncodingType' => array(\n                            'type' => 'string',\n                            'location' => 'query',\n                            'sentAs' => 'encoding-type'\n                        ),\n                        'Marker' => array(\n                            'type' => 'string',\n                            'location' => 'query',\n                            'sentAs' => 'marker'\n                        ),\n                        'MaxKeys' => array(\n                            'type' => 'numeric',\n                            'location' => 'query',\n                            'sentAs' => 'max-keys'\n                        ),\n                        'Prefix' => array(\n                            'type' => 'string',\n                            'location' => 'query',\n                            'sentAs' => 'prefix'\n                        )\n                    )\n                ),\n                // 获取所属账户的所有存储空间列表的方法.\n                'ListBuckets' => array(\n                    'httpMethod' => 'GET',\n                    'uri' => '/',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'ListBucketsOutput',\n                    'responseType' => 'model',\n                    'parameters' => array(\n                    ),\n                ),\n                // 获取多版本对象的方法.\n                'ListObjectVersions' => array(\n                    'httpMethod' => 'GET',\n                    'uri' => '/{Bucket}?versions',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'ListObjectVersionsOutput',\n                    'responseType' => 'model',\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        ),\n                        'Delimiter' => array(\n                            'type' => 'string',\n                            'location' => 'query',\n                            'sentAs' => 'delimiter',\n                        ),\n                        'EncodingType' => array(\n                            'type' => 'string',\n                            'location' => 'query',\n                            'sentAs' => 'encoding-type',\n                        ),\n                        'KeyMarker' => array(\n                            'type' => 'string',\n                            'location' => 'query',\n                            'sentAs' => 'key-marker',\n                        ),\n                        'MaxKeys' => array(\n                            'type' => 'numeric',\n                            'location' => 'query',\n                            'sentAs' => 'max-keys',\n                        ),\n                        'Prefix' => array(\n                            'type' => 'string',\n                            'location' => 'query',\n                            'sentAs' => 'prefix',\n                        ),\n                        'VersionIdMarker' => array(\n                            'type' => 'string',\n                            'location' => 'query',\n                            'sentAs' => 'version-id-marker',\n                        )\n                    ),\n                ),\n                // 获取已上传分块列表的方法\n                'ListMultipartUploads' => array(\n                    'httpMethod' => 'GET',\n                    'uri' => '/{Bucket}?uploads',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'ListMultipartUploadsOutput',\n                    'responseType' => 'model',\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        ),\n                        'Delimiter' => array(\n                            'type' => 'string',\n                            'location' => 'query',\n                            'sentAs' => 'delimiter',\n                        ),\n                        'EncodingType' => array(\n                            'type' => 'string',\n                            'location' => 'query',\n                            'sentAs' => 'encoding-type',\n                        ),\n                        'KeyMarker' => array(\n                            'type' => 'string',\n                            'location' => 'query',\n                            'sentAs' => 'key-marker',\n                        ),\n                        'MaxUploads' => array(\n                            'type' => 'numeric',\n                            'location' => 'query',\n                            'sentAs' => 'max-uploads',\n                        ),\n                        'Prefix' => array(\n                            'type' => 'string',\n                            'location' => 'query',\n                            'sentAs' => 'prefix',\n                        ),\n                        'UploadIdMarker' => array(\n                            'type' => 'string',\n                            'location' => 'query',\n                            'sentAs' => 'upload-id-marker',\n                        )\n                    ),\n                ),\n                // 获取清单列表的方法.\n                'ListBucketInventoryConfigurations' => array(\n                    'httpMethod' => 'GET',\n                    'uri' => '/{Bucket}?inventory',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'ListBucketInventoryConfigurationsOutput',\n                    'responseType' => 'model',\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri'\n                        ),\n                        'ContinuationToken' => array(\n                            'type' => 'string',\n                            'location' => 'query',\n                            'sentAs' => 'continuation-token',\n                        ),\n                    ),\n                ),\n                // 获取对象的meta信息的方法\n                'HeadObject' => array(\n                    'httpMethod' => 'HEAD',\n                    'uri' => '/{Bucket}{/Key*}',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'HeadObjectOutput',\n                    'responseType' => 'model',\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        ),\n                        'IfMatch' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'If-Match',\n                        ),\n                        'IfModifiedSince' => array(\n                            'type' => array(\n                                'object',\n                                'string',\n                                'integer',\n                            ),\n                            'format' => 'date-time-http',\n                            'location' => 'header',\n                            'sentAs' => 'If-Modified-Since',\n                        ),\n                        'IfNoneMatch' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'If-None-Match',\n                        ),\n                        'IfUnmodifiedSince' => array(\n                            'type' => array(\n                                'object',\n                                'string',\n                                'integer',\n                            ),\n                            'format' => 'date-time-http',\n                            'location' => 'header',\n                            'sentAs' => 'If-Unmodified-Since',\n                        ),\n                        'Key' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                            'minLength' => 1,\n                            'filters' => array(\n                                'Qcloud\\\\Cos\\\\Client::explodeKey')\n                        ),\n                        'Range' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                        ),\n                        'VersionId' => array(\n                            'type' => 'string',\n                            'location' => 'query',\n                            'sentAs' => 'versionId',\n                        ),\n                        'SSECustomerAlgorithm' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption-customer-algorithm',\n                        ),\n                        'SSECustomerKey' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption-customer-key',\n                        ),\n                        'SSECustomerKeyMD5' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption-customer-key-MD5',\n                        ),\n                        'RequestPayer' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-payer',\n                        ),\n                    )\n                ),\n                // 存储桶（Bucket） 是否存在的方法.\n                'HeadBucket' => array(\n                    'httpMethod' => 'HEAD',\n                    'uri' => '/{Bucket}',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'HeadBucketOutput',\n                    'responseType' => 'model',\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        ),\n                    )\n                ),\n                // 分块copy的方法.\n                'UploadPartCopy' => array(\n                    'httpMethod' => 'PUT',\n                    'uri' => '/{Bucket}{/Key*}',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'UploadPartCopyOutput',\n                    'responseType' => 'model',\n                    'data' => array(\n                        'xmlRoot' => array(\n                            'name' => 'UploadPartCopyRequest',\n                        ),\n                    ),\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        ),\n                        'CopySource' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-copy-source',\n                        ),\n                        'CopySourceIfMatch' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-copy-source-if-match',\n                        ),\n                        'CopySourceIfModifiedSince' => array(\n                            'type' => array(\n                                'object',\n                                'string',\n                                'integer',\n                            ),\n                            'format' => 'date-time-http',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-copy-source-if-modified-since',\n                        ),\n                        'CopySourceIfNoneMatch' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-copy-source-if-none-match',\n                        ),\n                        'CopySourceIfUnmodifiedSince' => array(\n                            'type' => array(\n                                'object',\n                                'string',\n                                'integer',\n                            ),\n                            'format' => 'date-time-http',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-copy-source-if-unmodified-since',\n                        ),\n                        'CopySourceRange' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-copy-source-range',\n                        ),\n                        'Key' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                            'minLength' => 1,\n                            'filters' => array(\n                                'Qcloud\\\\Cos\\\\Client::explodeKey')\n                        ),\n                        'PartNumber' => array(\n                            'required' => true,\n                            'type' => 'numeric',\n                            'location' => 'query',\n                            'sentAs' => 'partNumber',\n                        ),\n                        'UploadId' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'query',\n                            'sentAs' => 'uploadId',\n                        ),\n                        'SSECustomerAlgorithm' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption-customer-algorithm',\n                        ),\n                        'SSECustomerKey' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption-customer-key',\n                        ),\n                        'SSECustomerKeyMD5' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption-customer-key-MD5',\n                        ),\n                        'CopySourceSSECustomerAlgorithm' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-copy-source-server-side-encryption-customer-algorithm',\n                        ),\n                        'CopySourceSSECustomerKey' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-copy-source-server-side-encryption-customer-key',\n                        ),\n                        'CopySourceSSECustomerKeyMD5' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-copy-source-server-side-encryption-customer-key-MD5',\n                        ),\n                        'RequestPayer' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-payer',\n                        )\n                    ),\n                ),\n                'SelectObjectContent' => array(\n                    'httpMethod' => 'Post',\n                    'uri' => '/{/Key*}?select&select-type=2',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'SelectObjectContentOutput',\n                    'responseType' => 'model',\n                    'data' => array(\n                        'xmlRoot' => array(\n                            'name' => 'SelectRequest',\n                        ),\n                        'contentMd5' => true,\n                    ),\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        ),\n                        'Key' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                            'minLength' => 1,\n                            'filters' => array(\n                                'Qcloud\\\\Cos\\\\Client::explodeKey')\n                        ),\n                        'Expression' => array(\n                            'type' => 'string',\n                            'location' => 'xml'\n                        ),\n                        'ExpressionType' => array(\n                            'type' => 'string',\n                            'location' => 'xml'\n                        ),\n                        'InputSerialization' => array(\n                            'location' => 'xml',\n                            'type' => 'object',\n                            'properties' => array(\n                                'CompressionType' => array(\n                                    'type' => 'string',\n                                    'location' => 'xml',\n                                ),\n                                'CSV' => array(\n                                    'type' => 'object',\n                                    'location' => 'xml',\n                                    'properties' => array(\n                                        'FileHeaderInfo' => array(\n                                            'type' => 'string',\n                                            'location' => 'xml',\n                                        ),\n                                        'RecordDelimiter' => array(\n                                            'type' => 'string',\n                                            'location' => 'xml',\n                                        ),\n                                        'FieldDelimiter' => array(\n                                            'type' => 'string',\n                                            'location' => 'xml',\n                                        ),\n                                        'QuoteCharacter' => array(\n                                            'type' => 'string',\n                                            'location' => 'xml',\n                                        ),\n                                        'QuoteEscapeCharacter' => array(\n                                            'type' => 'string',\n                                            'location' => 'xml',\n                                        ),\n                                        'Comments' => array(\n                                            'type' => 'string',\n                                            'location' => 'xml',\n                                        ),\n                                        'AllowQuotedRecordDelimiter' => array(\n                                            'type' => 'string',\n                                            'location' => 'xml',\n                                        ),\n                                    )\n                                ),\n                                'JSON' => array(\n                                    'type' => 'object',\n                                    'location' => 'xml',\n                                    'properties' => array(\n                                        'Type' => array(\n                                            'type' => 'string',\n                                            'location' => 'xml',\n                                        )\n                                    )\n                                ),\n                            )\n                        ),\n                        'OutputSerialization' => array(\n                            'location' => 'xml',\n                            'type' => 'object',\n                            'properties' => array(\n                                'CompressionType' => array(\n                                    'type' => 'string',\n                                    'location' => 'xml',\n                                ),\n                                'CSV' => array(\n                                    'type' => 'object',\n                                    'location' => 'xml',\n                                    'properties' => array(\n                                        'QuoteFields' => array(\n                                            'type' => 'string',\n                                            'location' => 'xml',\n                                        ),\n                                        'RecordDelimiter' => array(\n                                            'type' => 'string',\n                                            'location' => 'xml',\n                                        ),\n                                        'FieldDelimiter' => array(\n                                            'type' => 'string',\n                                            'location' => 'xml',\n                                        ),\n                                        'QuoteCharacter' => array(\n                                            'type' => 'string',\n                                            'location' => 'xml',\n                                        ),\n                                        'QuoteEscapeCharacter' => array(\n                                            'type' => 'string',\n                                            'location' => 'xml',\n                                        ),\n                                    )\n                                ),\n                                'JSON' => array(\n                                    'type' => 'object',\n                                    'location' => 'xml',\n                                    'properties' => array(\n                                        'RecordDelimiter' => array(\n                                            'type' => 'string',\n                                            'location' => 'xml',\n                                        )\n                                    )\n                                ),\n                            )\n                        ),\n                        'RequestProgress' => array(\n                            'location' => 'xml',\n                            'type' => 'object',\n                            'properties' => array(\n                                'Enabled' => array(\n                                    'type' => 'string',\n                                    'location' => 'xml',\n                                ),\n                            )\n                        ),\n                    ),\n                ),\n                // 存储桶（Bucket）开启智能分层\n                'PutBucketIntelligentTiering' => array(\n                    'httpMethod' => 'PUT',\n                    'uri' => '/{Bucket}?intelligenttiering',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'PutBucketIntelligentTieringOutput',\n                    'responseType' => 'model',\n                    'data' => array(\n                        'xmlRoot' => array(\n                            'name' => 'IntelligentTieringConfiguration',\n                        ),\n                    ),\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        ),\n                        'Status' => array(\n                            'type' => 'string',\n                            'location' => 'xml',\n                        ),\n                        'Transition' => array(\n                            'location' => 'xml',\n                            'type' => 'object',\n                            'properties' => array(\n                                'Days' => array(\n                                    'type' => 'integer',\n                                    'location' => 'xml',\n                                ),\n                                'RequestFrequent' => array(\n                                    'type' => 'integer',\n                                    'location' => 'xml',\n                                ),\n                            )\n                        ),\n                    ),\n                ),\n                // 查询存储桶（Bucket）智能分层\n                'GetBucketIntelligentTiering' => array(\n                    'httpMethod' => 'GET',\n                    'uri' => '/{Bucket}?intelligenttiering',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'GetBucketIntelligentTieringOutput',\n                    'responseType' => 'model',\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        ),\n                    ),\n                ),\n                //万象-获取图片基本信息\n                'ImageInfo' => array(\n                    'httpMethod' => 'GET',\n                    'uri' => '/{Bucket}{/Key*}?imageInfo',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'ImageInfoOutput',\n                    'responseType' => 'model',\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        ),\n                        'Key' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                            'minLength' => 1,\n                            'filters' => array(\n                                'Qcloud\\\\Cos\\\\Client::explodeKey'\n                            )\n                        ),\n                    )\n                ),\n                //万象-获取图片EXIF信息\n                'ImageExif' => array(\n                    'httpMethod' => 'GET',\n                    'uri' => '/{Bucket}{/Key*}?exif',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'ImageExifOutput',\n                    'responseType' => 'model',\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        ),\n                        'Key' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                            'minLength' => 1,\n                            'filters' => array(\n                                'Qcloud\\\\Cos\\\\Client::explodeKey'\n                            )\n                        ),\n                    )\n                ),\n                //万象-获取图片主色调信息\n                'ImageAve' => array(\n                    'httpMethod' => 'GET',\n                    'uri' => '/{Bucket}{/Key*}?imageAve',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'ImageAveOutput',\n                    'responseType' => 'model',\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        ),\n                        'Key' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                            'minLength' => 1,\n                            'filters' => array(\n                                'Qcloud\\\\Cos\\\\Client::explodeKey'\n                            )\n                        ),\n                    ),\n                ),\n                //万象-云上数据处理\n                'ImageProcess' => array(\n                    'httpMethod' => 'POST',\n                    'uri' => '/{Bucket}{/Key*}?image_process',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'ImageProcessOutput',\n                    'responseType' => 'model',\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        ),\n                        'Key' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                            'minLength' => 1,\n                            'filters' => array(\n                                'Qcloud\\\\Cos\\\\Client::explodeKey'\n                            )\n                        ),\n                        'ContentType' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'Content-Type',\n                        ),\n                        'PicOperations' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'Pic-Operations',\n                        ),\n                    ),\n                ),\n                //万象-二维码下载时识别\n                'Qrcode' => array(\n                    'httpMethod' => 'GET',\n                    'uri' => '/{Bucket}{/Key*}?ci-process=QRcode',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'QrcodeOutput',\n                    'responseType' => 'model',\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        ),\n                        'Key' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                            'minLength' => 1,\n                            'filters' => array(\n                                'Qcloud\\\\Cos\\\\Client::explodeKey'\n                            )\n                        ),\n                        'Cover' => array(\n                            'type' => 'integer',\n                            'location' => 'query',\n                            'sentAs' => 'cover'\n                        ),\n                    ),\n                ),\n                //万象-二维码生成\n                'QrcodeGenerate' => array(\n                    'httpMethod' => 'GET',\n                    'uri' => '/{Bucket}?ci-process=qrcode-generate',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'QrcodeGenerateOutput',\n                    'responseType' => 'model',\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        ),\n                        'QrcodeContent' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'query',\n                            'sentAs' => 'qrcode-content'\n                        ),\n                        'QrcodeMode' => array(\n                            'type' => 'integer',\n                            'location' => 'query',\n                            'sentAs' => 'mode'\n                        ),\n                        'QrcodeWidth' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'query',\n                            'sentAs' => 'width'\n                        ),\n                    ),\n                ),\n                //万象-图片标签\n                'DetectLabel' => array(\n                    'httpMethod' => 'GET',\n                    'uri' => '/{Bucket}{/Key*}?ci-process=detect-label',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'DetectLabelOutput',\n                    'responseType' => 'model',\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        ),\n                        'Key' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                            'minLength' => 1,\n                            'filters' => array(\n                                'Qcloud\\\\Cos\\\\Client::explodeKey'\n                            )\n                        ),\n                    ),\n                ),\n                //万象-增加样式\n                'PutBucketImageStyle' => array(\n                    'httpMethod' => 'PUT',\n                    'uri' => '/{Bucket}?style',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'PutBucketImageStyleOutput',\n                    'responseType' => 'model',\n                    'data' => array(\n                        'xmlRoot' => array(\n                            'name' => 'AddStyle',\n                        ),\n                    ),\n                    'parameters' => array(\n                        'StyleName' => array(\n                            'type' => 'string',\n                            'location' => 'xml',\n                        ),\n                        'StyleBody' => array(\n                            'type' => 'string',\n                            'location' => 'xml',\n                        ),\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        ),\n                    ),\n                ),\n                //万象-查询样式\n                'GetBucketImageStyle' => array(\n                    'httpMethod' => 'GET',\n                    'uri' => '/{Bucket}?style',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'GetBucketImageStyleOutput',\n                    'responseType' => 'model',\n                    'data' => array(\n                        'xmlRoot' => array(\n                            'name' => 'GetStyle',\n                        ),\n                    ),\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        ),\n                        'StyleName' => array(\n                            'type' => 'string',\n                            'location' => 'xml',\n                        ),\n                    ),\n                ),\n                //万象-删除样式\n                'DeleteBucketImageStyle' => array(\n                    'httpMethod' => 'Delete',\n                    'uri' => '/{Bucket}?style',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'DeleteBucketImageStyleOutput',\n                    'responseType' => 'model',\n                    'data' => array(\n                        'xmlRoot' => array(\n                            'name' => 'DeleteStyle',\n                        ),\n                    ),\n                    'parameters' => array(\n                        'StyleName' => array(\n                            'type' => 'string',\n                            'location' => 'xml',\n                        ),\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        ),\n                    ),\n                ),\n                //万象-开通Guetzli压缩\n                'PutBucketGuetzli' => array(\n                    'httpMethod' => 'PUT',\n                    'uri' => '/{Bucket}?guetzli',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'PutBucketGuetzliOutput',\n                    'responseType' => 'model',\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        ),\n                    ),\n                ),\n                //万象-查询Guetzli状态\n                'GetBucketGuetzli' => array(\n                    'httpMethod' => 'GET',\n                    'uri' => '/{Bucket}?guetzli',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'GetBucketGuetzliOutput',\n                    'responseType' => 'model',\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        ),\n                    ),\n                ),\n                //万象-关闭Guetzli压缩\n                'DeleteBucketGuetzli' => array(\n                    'httpMethod' => 'Delete',\n                    'uri' => '/{Bucket}?guetzli',\n                    'class' => 'Qcloud\\\\Cos\\\\Command',\n                    'responseClass' => 'DeleteBucketGuetzliOutput',\n                    'responseType' => 'model',\n                    'parameters' => array(\n                        'Bucket' => array(\n                            'required' => true,\n                            'type' => 'string',\n                            'location' => 'uri',\n                        ),\n                    ),\n                ),\n            ),\n            'models' => array(\n                'AbortMultipartUploadOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id'\n                        )\n                    )\n                ),\n                'CreateBucketOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'Location' => array(\n                            'type' => 'string',\n                            'location' => 'header'\n                        ),\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id'\n                        )\n                    )\n                ),\n                'CompleteMultipartUploadOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'Location' => array(\n                            'type' => 'string',\n                            'location' => 'xml',\n                        ),\n                        'Bucket' => array(\n                            'type' => 'string',\n                            'location' => 'xml',\n                        ),\n                        'Key' => array(\n                            'type' => 'string',\n                            'location' => 'xml'\n                        ),\n                        'Expiration' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-expiration',\n                        ),\n                        'ETag' => array(\n                            'type' => 'string',\n                            'location' => 'xml',\n                        ),\n                        'ServerSideEncryption' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption',\n                        ),\n                        'VersionId' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-version-id',\n                        ),\n                        'SSEKMSKeyId' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption-aws-kms-key-id',\n                        ),\n                        'RequestCharged' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-charged',\n                        ),\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                        'ImageInfo' => array(\n                            'type' => 'object',\n                            'location' => 'xml',\n                            'properties' => array(\n                                'Format' => array(\n                                    'type' => 'string',\n                                ),\n                                'Width' => array(\n                                    'type' => 'string',\n                                ),\n                                'Height' => array(\n                                    'type' => 'string',\n                                ),\n                                'Quality' => array(\n                                    'type' => 'string',\n                                ),\n                                'Ave' => array(\n                                    'type' => 'string',\n                                ),\n                                'Orientation' => array(\n                                    'type' => 'string',\n                                ),\n                            ),\n                        ),\n                        'ProcessResults' => array(\n                            'type' => 'object',\n                            'location' => 'xml',\n                            'properties' => array(\n                                'Object' => array(\n                                    'type' => 'array',\n                                    'items' => array(\n                                        'type' => 'object',\n                                        'properties' => array(\n                                            'Key' => array(\n                                                'type' => 'string',\n                                            ),\n                                            'Location' => array(\n                                                'type' => 'string',\n                                            ),\n                                            'Format' => array(\n                                                'type' => 'string',\n                                            ),\n                                            'Width' => array(\n                                                'type' => 'string',\n                                            ),\n                                            'Height' => array(\n                                                'type' => 'string',\n                                            ),\n                                            'Size' => array(\n                                                'type' => 'string',\n                                            ),\n                                            'Quality' => array(\n                                                'type' => 'string',\n                                            ),\n                                            'ETag' => array(\n                                                'type' => 'string',\n                                            ),\n                                            'WatermarkStatus' => array(\n                                                'type' => 'integer',\n                                            ),\n                                        ),\n                                    ),\n                                ),\n                            ),\n                        ),\n                    ),\n                ),\n                'CreateMultipartUploadOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'Bucket' => array(\n                            'type' => 'string',\n                            'location' => 'xml',\n                            'sentAs' => 'Bucket'\n                        ),\n                        'Key' => array(\n                            'type' => 'string',\n                            'location' => 'xml'\n                        ),\n                        'UploadId' => array(\n                            'type' => 'string',\n                            'location' => 'xml'\n                        ),\n                        'ServerSideEncryption' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption',\n                        ),\n                        'SSECustomerAlgorithm' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption-customer-algorithm',\n                        ),\n                        'SSECustomerKeyMD5' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption-customer-key-MD5',\n                        ),\n                        'SSEKMSKeyId' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption-aws-kms-key-id',\n                        ),\n                        'RequestCharged' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-charged',\n                        ),\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        )\n                    )\n                ),\n                'CopyObjectOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'ETag' => array(\n                            'type' => 'string',\n                            'location' => 'xml',\n                        ),\n                        'LastModified' => array(\n                            'type' => 'string',\n                            'location' => 'xml',\n                        ),\n                        'Expiration' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-expiration',\n                        ),\n                        'CopySourceVersionId' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-copy-source-version-id',\n                        ),\n                        'VersionId' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-version-id',\n                        ),\n                        'ServerSideEncryption' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption',\n                        ),\n                        'SSECustomerAlgorithm' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption-customer-algorithm',\n                        ),\n                        'RequestCharged' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-charged',\n                        ),\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                    ),\n                ),\n                'DeleteBucketOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id'\n                        )\n                    )\n                ),\n                'DeleteBucketCorsOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                    ),\n                ),\n                'DeleteBucketTaggingOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                    ),\n                ),\n                'DeleteBucketInventoryOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                    ),\n                ),\n                'DeleteObjectOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'DeleteMarker' => array(\n                            'type' => 'boolean',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-delete-marker',\n                        ),\n                        'VersionId' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-version-id',\n                        ),\n                        'RequestCharged' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-charged',\n                        ),\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                    ),\n                ),\n                'DeleteObjectsOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'Deleted' => array(\n                            'type' => 'array',\n                            'location' => 'xml',\n                            'sentAs' => 'Deleted',\n                            'data' => array(\n                                'xmlFlattened' => true,\n                            ),\n                            'items' => array(\n                                'type' => 'object',\n                                'properties' => array(\n                                    'Key' => array(\n                                        'type' => 'string',\n                                    ),\n                                    'VersionId' => array(\n                                        'type' => 'string',\n                                    ),\n                                    'DeleteMarker' => array(\n                                        'type' => 'boolean',\n                                    ),\n                                    'DeleteMarkerVersionId' => array(\n                                        'type' => 'string',\n                                    ),\n                                ),\n                            ),\n                        ),\n                        'RequestCharged' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-charged',\n                        ),\n                        'Errors' => array(\n                            'type' => 'array',\n                            'location' => 'xml',\n                            'sentAs' => 'Error',\n                            'data' => array(\n                                'xmlFlattened' => true,\n                            ),\n                            'items' => array(\n                                'type' => 'object',\n                                'properties' => array(\n                                    'Key' => array(\n                                        'type' => 'string',\n                                    ),\n                                    'VersionId' => array(\n                                        'type' => 'string',\n                                    ),\n                                    'Code' => array(\n                                        'type' => 'string',\n                                    ),\n                                    'Message' => array(\n                                        'type' => 'string',\n                                    ),\n                                ),\n                            ),\n                        ),\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                    ),\n                ),\n                'DeleteBucketLifecycleOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                    ),\n                ),\n                'DeleteBucketReplicationOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                    ),\n                ),\n                'DeleteBucketWebsiteOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                    ),\n                ),\n                'GetObjectOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'Body' => array(\n                            'type' => 'string',\n                            'instanceOf' => 'GuzzleHttp\\\\Psr7\\\\Stream',\n                            'location' => 'body',\n                        ),\n                        'DeleteMarker' => array(\n                            'type' => 'boolean',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-delete-marker',\n                        ),\n                        'AcceptRanges' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'accept-ranges',\n                        ),\n                        'Expiration' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-expiration',\n                        ),\n                        'Restore' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-restore',\n                        ),\n                        'LastModified' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'Last-Modified',\n                        ),\n                        'ContentLength' => array(\n                            'type' => 'numeric',\n                            'minimum'=> 0,\n                            'location' => 'header',\n                            'sentAs' => 'Content-Length',\n                        ),\n                        'ETag' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                        ),\n                        'MissingMeta' => array(\n                            'type' => 'numeric',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-missing-meta',\n                        ),\n                        'VersionId' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-version-id',\n                        ),\n                        'CacheControl' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'Cache-Control',\n                        ),\n                        'ContentDisposition' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'Content-Disposition',\n                        ),\n                        'ContentEncoding' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'Content-Encoding',\n                        ),\n                        'ContentLanguage' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'Content-Language',\n                        ),\n                        'ContentRange' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'Content-Range',\n                        ),\n                        'ContentType' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'Content-Type',\n                        ),\n                        'Expires' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                        ),\n                        'WebsiteRedirectLocation' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-website-redirect-location',\n                        ),\n                        'ServerSideEncryption' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption',\n                        ),\n                        'SSECustomerAlgorithm' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption-customer-algorithm',\n                        ),\n                        'SSECustomerKeyMD5' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption-customer-key-MD5',\n                        ),\n                        'SSEKMSKeyId' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption-aws-kms-key-id',\n                        ),\n                        'StorageClass' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-storage-class',\n                        ),\n                        'RequestCharged' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-charged',\n                        ),\n                        'ReplicationStatus' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-replication-status',\n                        ),\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                    ),\n                ),\n                'GetObjectAclOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'Owner' => array(\n                            'type' => 'object',\n                            'location' => 'xml',\n                            'properties' => array(\n                                'DisplayName' => array(\n                                    'type' => 'string',\n                                ),\n                                'ID' => array(\n                                    'type' => 'string',\n                                ),\n                            ),\n                        ),\n                        'Grants' => array(\n                            'type' => 'array',\n                            'location' => 'xml',\n                            'sentAs' => 'AccessControlList',\n                            'items' => array(\n                                'type' => 'object',\n                                'properties' => array(\n                                    'Grantee' => array(\n                                        'type' => 'object',\n                                        'properties' => array(\n                                            'DisplayName' => array(\n                                                'type' => 'string'),\n                                            'ID' => array(\n                                                'type' => 'string'))),\n                                    'Permission' => array(\n                                        'type' => 'string',\n                                    ),\n                                ),\n                            ),\n                        ),\n                        'RequestCharged' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-charged',\n                        ),\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                    ),\n                ),\n                'GetBucketAclOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'Owner' => array(\n                            'type' => 'object',\n                            'location' => 'xml',\n                            'properties' => array(\n                                'DisplayName' => array(\n                                    'type' => 'string'\n                                ),\n                                'ID' => array(\n                                    'type' => 'string'\n                                )\n                            )\n                        ),\n                        'Grants' => array(\n                            'type' => 'array',\n                            'location' => 'xml',\n                            'sentAs' => 'AccessControlList',\n                            'items' => array(\n                                'type' => 'object',\n                                'properties' => array(\n                                    'Grantee' => array(\n                                        'type' => 'object',\n                                        'properties' => array(\n                                            'DisplayName' => array(\n                                                'type' => 'string'\n                                            ),\n                                            'ID' => array(\n                                                'type' => 'string'\n                                            )\n                                        )\n                                    ),\n                                    'Permission' => array(\n                                        'type' => 'string'\n                                    )\n                                )\n                            )\n                        ),\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id'\n                        )\n                    )\n                ),\n                'GetBucketCorsOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'CORSRules' => array(\n                            'type' => 'array',\n                            'location' => 'xml',\n                            'sentAs' => 'CORSRule',\n                            'data' => array(\n                                'xmlFlattened' => true,\n                            ),\n                            'items' => array(\n                                'type' => 'object',\n                                'properties' => array(\n                                    'ID' => array(\n                                        'type' => 'string'),\n                                    'AllowedHeaders' => array(\n                                        'type' => 'array',\n                                        'sentAs' => 'AllowedHeader',\n                                        'data' => array(\n                                            'xmlFlattened' => true,\n                                        ),\n                                        'items' => [\n                                            'type' => 'string',\n                                        ]\n                                    ),\n                                    'AllowedMethods' => array(\n                                        'type' => 'array',\n                                        'sentAs' => 'AllowedMethod',\n                                        'data' => array(\n                                            'xmlFlattened' => true,\n                                        ),\n                                        'items' => array(\n                                            'type' => 'string',\n                                        ),\n                                    ),\n                                    'AllowedOrigins' => array(\n                                        'type' => 'array',\n                                        'sentAs' => 'AllowedOrigin',\n                                        'data' => array(\n                                            'xmlFlattened' => true,\n                                        ),\n                                        'items' => array(\n                                            'type' => 'string',\n                                        ),\n                                    ),\n                                    'ExposeHeaders' => array(\n                                        'type' => 'array',\n                                        'sentAs' => 'ExposeHeader',\n                                        'data' => array(\n                                            'xmlFlattened' => true,\n                                        ),\n                                        'items' => array(\n                                            'type' => 'string',\n                                        ),\n                                    ),\n                                    'MaxAgeSeconds' => array(\n                                        'type' => 'numeric',\n                                    ),\n                                ),\n                            ),\n                        ),\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                    ),\n                ),\n                'GetBucketDomainOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'DomainRules' => array(\n                            'type' => 'array',\n                            'location' => 'xml',\n                            'sentAs' => 'DomainRule',\n                            'data' => array(\n                                'xmlFlattened' => true,\n                            ),\n                            'items' => array(\n                                'type' => 'object',\n                                'properties' => array(\n                                    'Status' => array(\n                                        'type' => 'string'\n                                    ),\n                                    'Name' => array(\n                                        'type' => 'string'\n                                    ),\n                                    'Type' => array(\n                                        'type' => 'string'\n                                    ),\n                                    'ForcedReplacement' => array(\n                                        'type' => 'string'\n                                    ),\n                                ),\n                            ),\n                        ),\n                        'DomainTxtVerification' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-domain-txt-verification',\n                        ),\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                    ),\n                ),\n                'GetBucketLifecycleOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'Rules' => array(\n                            'type' => 'array',\n                            'location' => 'xml',\n                            'sentAs' => 'Rule',\n                            'data' => array(\n                                'xmlFlattened' => true,\n                            ),\n                            'items' => array(\n                                'type' => 'object',\n                                'properties' => array(\n                                    'Expiration' => array(\n                                        'type' => 'object',\n                                        'properties' => array(\n                                            'Date' => array(\n                                                'type' => 'string',\n                                            ),\n                                            'Days' => array(\n                                                'type' => 'numeric',\n                                            ),\n                                        ),\n                                    ),\n                                    'ID' => array(\n                                        'type' => 'string',\n                                    ),\n                                    'Filter' => array(\n                                        'type' => 'object',\n                                        'properties' => array(\n                                            'Prefix' => array(\n                                                'type' => 'string',\n                                            ),\n                                            'Tag' => array(\n                                                'type' => 'object',\n                                                'properties' => array(\n                                                    'Key' => array(\n                                                        'type' => 'string'\n                                                    ),\n                                                    'Value' => array(\n                                                        'type' => 'string'\n                                                    ),\n                                                )\n                                            )\n                                        ),\n                                    ),\n                                    'Status' => array(\n                                        'type' => 'string',\n                                    ),\n                                    'Transition' => array(\n                                        'type' => 'object',\n                                        'properties' => array(\n                                            'Date' => array(\n                                                'type' => 'string',\n                                            ),\n                                            'Days' => array(\n                                                'type' => 'numeric',\n                                            ),\n                                            'StorageClass' => array(\n                                                'type' => 'string',\n                                            ),\n                                        ),\n                                    ),\n                                    'NoncurrentVersionTransition' => array(\n                                        'type' => 'object',\n                                        'properties' => array(\n                                            'NoncurrentDays' => array(\n                                                'type' => 'numeric',\n                                            ),\n                                            'StorageClass' => array(\n                                                'type' => 'string',\n                                            ),\n                                        ),\n                                    ),\n                                    'NoncurrentVersionExpiration' => array(\n                                        'type' => 'object',\n                                        'properties' => array(\n                                            'NoncurrentDays' => array(\n                                                'type' => 'numeric',\n                                            ),\n                                        ),\n                                    ),\n                                ),\n                            ),\n                        ),\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                    ),\n                ),\n                'GetBucketVersioningOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'Status' => array(\n                            'type' => 'string',\n                            'location' => 'xml',\n                        ),\n                        'MFADelete' => array(\n                            'type' => 'string',\n                            'location' => 'xml',\n                            'sentAs' => 'MfaDelete',\n                        ),\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                    ),\n                ),\n                'GetBucketReplicationOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'Role' => array(\n                            'type' => 'string',\n                            'location' => 'xml',\n                        ),\n                        'Rules' => array(\n                            'type' => 'array',\n                            'location' => 'xml',\n                            'sentAs' => 'Rule',\n                            'data' => array(\n                                'xmlFlattened' => true,\n                            ),\n                            'items' => array(\n                                'type' => 'object',\n                                'properties' => array(\n                                    'ID' => array(\n                                        'type' => 'string',\n                                    ),\n                                    'Prefix' => array(\n                                        'type' => 'string',\n                                    ),\n                                    'Status' => array(\n                                        'type' => 'string',\n                                    ),\n                                    'Destination' => array(\n                                        'type' => 'object',\n                                        'properties' => array(\n                                            'Bucket' => array(\n                                                'type' => 'string',\n                                            ),\n                                            'StorageClass' => array(\n                                                'type' => 'string',\n                                            ),\n                                        ),\n                                    ),\n                                ),\n                            ),\n                        ),\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                    ),\n                ),\n                'GetBucketLocationOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'Location' => array(\n                            'type' => 'string',\n                            'location' => 'body',\n                            'filters' => array(\n                                'strval',\n                                'strip_tags',\n                                'trim',\n                            ),\n                        ),\n                    ),\n                ),\n                'GetBucketAccelerateOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'Status' => array(\n                            'type' => 'string',\n                            'location' => 'xml',\n                        ),\n                        'Type' => array(\n                            'type' => 'string',\n                            'location' => 'xml',\n                        ),\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                    ),\n                ),\n                'GetBucketWebsiteOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'RedirectAllRequestsTo' => array(\n                            'type' => 'object',\n                            'location' => 'xml',\n                            'properties' => array(\n                                'HostName' => array(\n                                    'type' => 'string',\n                                ),\n                                'Protocol' => array(\n                                    'type' => 'string',\n                                ),\n                            ),\n                        ),\n                        'IndexDocument' => array(\n                            'type' => 'object',\n                            'location' => 'xml',\n                            'properties' => array(\n                                'Suffix' => array(\n                                    'type' => 'string',\n                                ),\n                            ),\n                        ),\n                        'ErrorDocument' => array(\n                            'type' => 'object',\n                            'location' => 'xml',\n                            'properties' => array(\n                                'Key' => array(\n                                    'type' => 'string',\n                                ),\n                            ),\n                        ),\n                        'RoutingRules' => array(\n                            'type' => 'array',\n                            'location' => 'xml',\n                            'items' => array(\n                                'name' => 'RoutingRule',\n                                'type' => 'object',\n                                'sentAs' => 'RoutingRule',\n                                'properties' => array(\n                                    'Condition' => array(\n                                        'type' => 'object',\n                                        'properties' => array(\n                                            'HttpErrorCodeReturnedEquals' => array(\n                                                'type' => 'string',\n                                            ),\n                                            'KeyPrefixEquals' => array(\n                                                'type' => 'string',\n                                            ),\n                                        ),\n                                    ),\n                                    'Redirect' => array(\n                                        'type' => 'object',\n                                        'properties' => array(\n                                            'HostName' => array(\n                                                'type' => 'string',\n                                            ),\n                                            'HttpRedirectCode' => array(\n                                                'type' => 'string',\n                                            ),\n                                            'Protocol' => array(\n                                                'type' => 'string',\n                                            ),\n                                            'ReplaceKeyPrefixWith' => array(\n                                                'type' => 'string',\n                                            ),\n                                            'ReplaceKeyWith' => array(\n                                                'type' => 'string',\n                                            ),\n                                        ),\n                                    ),\n                                ),\n                            ),\n                        ),\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                    ),\n                ),\n                'GetBucketInventoryOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'Destination' => array(\n                            'type' => 'object',\n                            'location' => 'xml',\n                            'properties' => array(\n                                'COSBucketDestination' => array(\n                                    'type' => 'object',\n                                    'properties' => array(\n                                        'Format' => array(\n                                            'type' => 'string',\n                                        ),\n                                        'AccountId' => array(\n                                            'type' => 'string',\n                                        ),\n                                        'Bucket' => array(\n                                            'type' => 'string',\n                                        ),\n                                        'Prefix' => array(\n                                            'type' => 'string',\n                                        ),\n                                        'Encryption' => array(\n                                            'type' => 'object',\n                                            'properties' => array(\n                                                'SSE-COS' => array(\n                                                    'type' => 'string',\n                                                )\n                                            )\n                                        ),\n                                        \n                                    ),\n                                ),\n                            ),\n                        ),\n                        'Schedule' => array(\n                            'type' => 'object',\n                            'location' => 'xml',\n                            'properties' => array(\n                                'Frequency' => array(\n                                    'type' => 'string',\n                                ),\n                            ),\n                        ),\n                        'OptionalFields' => array(\n                            'type' => 'array',\n                            'location' => 'xml',\n                            'properties' => array(\n                                'Key' => array(\n                                    'type' => 'string',\n                                ),\n                            ),\n                        ),\n                        'OptionalFields' => array(\n                            'type' => 'array',\n                            'location' => 'xml',\n                            'items' => array(\n                                'name' => 'Field',\n                                'type' => 'string',\n                                'sentAs' => 'Field',\n                            ),\n                        ),\n                        'IsEnabled' => array(\n                            'type' => 'string',\n                            'location' => 'xml',\n                        ),\n                        'Id' => array(\n                            'type' => 'string',\n                            'location' => 'xml',\n                        ),\n                        'IncludedObjectVersions' => array(\n                            'type' => 'string',\n                            'location' => 'xml',\n                        ),\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                    ),\n                ),\n                'GetBucketTaggingOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'TagSet' => array(\n                            'type' => 'array',\n                            'location' => 'xml',\n                            'items' => array(\n                                'sentAs' => 'Tag',\n                                'type' => 'object',\n                                'properties' => array(\n                                    'Key' => array(\n                                        'type' => 'string',\n                                    ),\n                                    'Value' => array(\n                                        'type' => 'string',\n                                    ),\n                                ),\n                            ),\n                        ),\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                    ),\n                ),\n                'GetBucketNotificationOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'CloudFunctionConfigurations' => array(\n                            'type' => 'array',\n                            'location' => 'xml',\n                            'sentAs' => 'CloudFunctionConfiguration',\n                            'data' => array(\n                                'xmlFlattened' => true,\n                            ),\n                            'items' => array(\n                                'type' => 'object',\n                                'properties' => array(\n                                    'Id' => array(\n                                        'type' => 'string',\n                                    ),\n                                    'CloudFunction' => array(\n                                        'type' => 'string',\n                                        'sentAs' => 'CloudFunction',\n                                    ),\n                                    'Events' => array(\n                                        'type' => 'array',\n                                        'sentAs' => 'Event',\n                                        'data' => array(\n                                            'xmlFlattened' => true,\n                                        ),\n                                        'items' => array(\n                                            'type' => 'string',\n                                        ),\n                                    ),\n                                    'Filter' => array(\n                                        'type' => 'object',\n                                        'properties' => array(\n                                            'Key' => array(\n                                                'type' => 'object',\n                                                'sentAs' => 'Key',\n                                                'properties' => array(\n                                                    'FilterRules' => array(\n                                                        'type' => 'array',\n                                                        'sentAs' => 'FilterRule',\n                                                        'data' => array(\n                                                            'xmlFlattened' => true,\n                                                        ),\n                                                        'items' => array(\n                                                            'type' => 'object',\n                                                            'properties' => array(\n                                                                'Name' => array(\n                                                                    'type' => 'string',\n                                                                ),\n                                                                'Value' => array(\n                                                                    'type' => 'string',\n                                                                ),\n                                                            ),\n                                                        ),\n                                                    ),\n                                                ),\n                                            ),\n                                        ),\n                                    ),\n                                ),\n                            ),\n                        ),\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                    ),\n                ),\n                'GetBucketLoggingOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'LoggingEnabled' => array(\n                            'location' => 'xml',\n                            'type' => 'object',\n                            'properties' => array(\n                                'TargetBucket' => array(\n                                    'type' => 'string',\n                                    'location' => 'xml',\n                                ),\n                                'TargetPrefix' => array(\n                                    'type' => 'string',\n                                ),\n                            ),\n                        ),\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                    ),\n                ),\n                'UploadPartOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'ServerSideEncryption' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption',\n                        ),\n                        'ETag' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                        ),\n                        'SSECustomerAlgorithm' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption-customer-algorithm',\n                        ),\n                        'SSECustomerKeyMD5' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption-customer-key-MD5',\n                        ),\n                        'SSEKMSKeyId' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption-aws-kms-key-id',\n                        ),\n                        'RequestCharged' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-charged',\n                        ),\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                    ),\n                ),\n                'UploadPartCopyOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'CopySourceVersionId' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-copy-source-version-id',\n                        ),\n                        'ETag' => array(\n                            'type' => 'string',\n                            'location' => 'xml',\n                        ),\n                        'LastModified' => array(\n                            'type' => 'string',\n                            'location' => 'xml',\n                        ),\n                        'ServerSideEncryption' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption',\n                        ),\n                        'SSECustomerAlgorithm' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption-customer-algorithm',\n                        ),\n                        'SSECustomerKeyMD5' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption-customer-key-MD5',\n                        ),\n                        'SSEKMSKeyId' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption-aws-kms-key-id',\n                        ),\n                        'RequestCharged' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-charged',\n                        ),\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                    ),\n                ),\n                'PutBucketAclOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id'\n                        )\n                    )\n                ),\n                'PutObjectOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'Expiration' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-expiration',\n                        ),\n                        'ETag' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                        ),\n                        'ServerSideEncryption' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption',\n                        ),\n                        'VersionId' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-version-id',\n                        ),\n                        'SSECustomerAlgorithm' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption-customer-algorithm',\n                        ),\n                        'SSECustomerKeyMD5' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption-customer-key-MD5',\n                        ),\n                        'SSEKMSKeyId' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption-aws-kms-key-id',\n                        ),\n                        'RequestCharged' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-charged',\n                        ),\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                        'ContentLength' => array(\n                            'type' => 'numeric',\n                            'minimum'=> 0,\n                            'location' => 'header',\n                            'sentAs' => 'Content-Length',\n                        ),\n                        'Body' => array(\n                            'type' => 'string',\n                            'instanceOf' => 'GuzzleHttp\\\\Psr7\\\\Stream',\n                            'location' => 'body',\n                        ),\n                    ),\n                ),\n                'PutObjectAclOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'RequestCharged' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-charged',\n                        ),\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                    ),\n                ),\n                'PutBucketCorsOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                    ),\n                ),\n                'PutBucketDomainOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                    ),\n                ),\n                'PutBucketLifecycleOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                    ),\n                ),\n                'PutBucketVersioningOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                    ),\n                ),\n                'PutBucketReplicationOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                    ),\n                ),\n                'PutBucketNotificationOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                    ),\n                ),\n                'PutBucketWebsiteOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'RequestId' => array(\n                            'location' => 'header', \n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                    ),\n                ),\n                'PutBucketAccelerateOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                    ),\n                ),\n                'PutBucketLoggingOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                    ),\n                ),\n                'PutBucketInventoryOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                    ),\n                ),\n                'PutBucketTaggingOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                    ),\n                ),\n                'RestoreObjectOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'RequestCharged' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-charged',\n                        ),\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                    ),\n                ),\n                'ListPartsOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'Bucket' => array(\n                            'type' => 'string',\n                            'location' => 'xml'\n                        ),\n                        'Key' => array(\n                            'type' => 'string',\n                            'location' => 'xml'\n                        ),\n                        'UploadId' => array(\n                            'type' => 'string',\n                            'location' => 'xml'\n                        ),\n                        'PartNumberMarker' => array(\n                            'type' => 'numeric',\n                            'location' => 'xml'\n                        ),\n                        'NextPartNumberMarker' => array(\n                            'type' => 'numeric',\n                            'location' => 'xml'\n                        ),\n                        'MaxParts' => array(\n                            'type' => 'numeric',\n                            'location' => 'xml'\n                        ),\n                        'IsTruncated' => array(\n                            'type' => 'boolean',\n                            'location' => 'xml'\n                        ),\n                        'Parts' => array(\n                            'type' => 'array',\n                            'location' => 'xml',\n                            'sentAs' => 'Part',\n                            'data' => array(\n                                'xmlFlattened' => true\n                            ),\n                            'items' => array(\n                                'type' => 'object',\n                                'properties' => array(\n                                    'PartNumber' => array(\n                                        'type' => 'numeric'\n                                    ),\n                                    'LastModified' => array(\n                                        'type' => 'string'\n                                    ),\n                                    'ETag' => array(\n                                        'type' => 'string'\n                                    ),\n                                    'Size' => array(\n                                        'type' => 'numeric'\n                                    )\n                                )\n                            )\n                        ),\n                        'Initiator' => array(\n                            'type' => 'object',\n                            'location' => 'xml',\n                            'properties' => array(\n                                'ID' => array(\n                                    'type' => 'string'\n                                ),\n                                'DisplayName' => array(\n                                    'type' => 'string'\n                                )\n                            )\n                        ),\n                        'Owner' => array(\n                            'type' => 'object',\n                            'location' => 'xml',\n                            'properties' => array(\n                                'DisplayName' => array(\n                                    'type' => 'string'\n                                ),\n                                'ID' => array(\n                                    'type' => 'string'\n                                )\n                            )\n                        ),\n                        'StorageClass' => array(\n                            'type' => 'string',\n                            'location' => 'xml'\n                        ),\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id'\n                        )\n                    )\n                ),\n                'ListObjectsOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'IsTruncated' => array(\n                            'type' => 'boolean',\n                            'location' => 'xml'\n                        ),\n                        'Marker' => array(\n                            'type' => 'string',\n                            'location' => 'xml'\n                        ),\n                        'NextMarker' => array(\n                            'type' => 'string',\n                            'location' => 'xml'\n                        ),\n                        'Contents' => array(\n                            'type' => 'array',\n                            'location' => 'xml',\n                            'data' => array(\n                                'xmlFlattened' => true\n                            ),\n                            'items' => array(\n                                'type' => 'object',\n                                'properties' => array(\n                                    'Key' => array(\n                                        'type' => 'string'\n                                    ),\n                                    'LastModified' => array(\n                                        'type' => 'string'\n                                    ),\n                                    'ETag' => array(\n                                        'type' => 'string'\n                                    ),\n                                    'Size' => array(\n                                        'type' => 'numeric'\n                                    ),\n                                    'StorageClass' => array(\n                                        'type' => 'string'\n                                    ),\n                                    'Owner' => array(\n                                        'type' => 'object',\n                                        'properties' => array(\n                                            'DisplayName' => array(\n                                                'type' => 'string'\n                                            ),\n                                            'ID' => array(\n                                                'type' => 'string'\n                                            )\n                                        )\n                                    )\n                                )\n                            )\n                        ),\n                        'Name' => array(\n                            'type' => 'string',\n                            'location' => 'xml'\n                        ),\n                        'Prefix' => array(\n                            'type' => 'string',\n                            'location' => 'xml'\n                        ),\n                        'Delimiter' => array(\n                            'type' => 'string',\n                            'location' => 'xml'\n                        ),\n                        'MaxKeys' => array(\n                            'type' => 'numeric',\n                            'location' => 'xml'\n                        ),\n                        'CommonPrefixes' => array(\n                            'type' => 'array',\n                            'location' => 'xml',\n                            'data' => array(\n                                'xmlFlattened' => true\n                            ),\n                            'items' => array(\n                                'type' => 'object',\n                                'properties' => array(\n                                    'Prefix' => array(\n                                        'type' => 'string'\n                                    )\n                                )\n                            )\n                        ),\n                        'EncodingType' => array(\n                            'type' => 'string',\n                            'location' => 'xml'),\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id'\n                        )\n                    )\n                ),\n                'ListBucketsOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'Buckets' => array(\n                            'type' => 'array',\n                            'location' => 'xml',\n                            'items' => array(\n                                'type' => 'object',\n                                'properties' => array(\n                                    'Name' => array(\n                                        'type' => 'string',\n                                    ),\n                                    'CreationDate' => array(\n                                        'type' => 'string',\n                                    ),\n                                ),\n                            ),\n                        ),\n                        'Owner' => array(\n                            'type' => 'object',\n                            'location' => 'xml',\n                            'properties' => array(\n                                'DisplayName' => array(\n                                    'type' => 'string',\n                                ),\n                                'ID' => array(\n                                    'type' => 'string',\n                                ),\n                            ),\n                        ),\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                    ),\n                ),\n                'ListObjectVersionsOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'IsTruncated' => array(\n                            'type' => 'boolean',\n                            'location' => 'xml',\n                        ),\n                        'KeyMarker' => array(\n                            'type' => 'string',\n                            'location' => 'xml',\n                        ),\n                        'VersionIdMarker' => array(\n                            'type' => 'string',\n                            'location' => 'xml',\n                        ),\n                        'NextKeyMarker' => array(\n                            'type' => 'string',\n                            'location' => 'xml',\n                        ),\n                        'NextVersionIdMarker' => array(\n                            'type' => 'string',\n                            'location' => 'xml',\n                        ),\n                        'Version' => array(\n                            'type' => 'array',\n                            'location' => 'xml',\n                            'data' => array(\n                                'xmlFlattened' => true,\n                            ),\n                            'items' => array(\n                                'type' => 'object',\n                                'properties' => array(\n                                    'ETag' => array(\n                                        'type' => 'string',\n                                    ),\n                                    'Size' => array(\n                                        'type' => 'numeric',\n                                    ),\n                                    'StorageClass' => array(\n                                        'type' => 'string',\n                                    ),\n                                    'Key' => array(\n                                        'type' => 'string',\n                                    ),\n                                    'VersionId' => array(\n                                        'type' => 'string',\n                                    ),\n                                    'IsLatest' => array(\n                                        'type' => 'boolean',\n                                    ),\n                                    'LastModified' => array(\n                                        'type' => 'string',\n                                    ),\n                                    'Owner' => array(\n                                        'type' => 'object',\n                                        'properties' => array(\n                                            'DisplayName' => array(\n                                                'type' => 'string',\n                                            ),\n                                            'ID' => array(\n                                                'type' => 'string',\n                                            ),\n                                        ),\n                                    ),\n                                ),\n                            ),\n                        ),\n                        'DeleteMarkers' => array(\n                            'type' => 'array',\n                            'location' => 'xml',\n                            'sentAs' => 'DeleteMarker',\n                            'data' => array(\n                                'xmlFlattened' => true,\n                            ),\n                            'items' => array(\n                                'type' => 'object',\n                                'properties' => array(\n                                    'Owner' => array(\n                                        'type' => 'object',\n                                        'properties' => array(\n                                            'DisplayName' => array(\n                                                'type' => 'string',\n                                            ),\n                                            'ID' => array(\n                                                'type' => 'string',\n                                            ),\n                                        ),\n                                    ),\n                                    'Key' => array(\n                                        'type' => 'string',\n                                    ),\n                                    'VersionId' => array(\n                                        'type' => 'string',\n                                    ),\n                                    'IsLatest' => array(\n                                        'type' => 'boolean',\n                                    ),\n                                    'LastModified' => array(\n                                        'type' => 'string',\n                                    ),\n                                ),\n                            ),\n                        ),\n                        'Name' => array(\n                            'type' => 'string',\n                            'location' => 'xml',\n                        ),\n                        'Prefix' => array(\n                            'type' => 'string',\n                            'location' => 'xml',\n                        ),\n                        'Delimiter' => array(\n                            'type' => 'string',\n                            'location' => 'xml',\n                        ),\n                        'MaxKeys' => array(\n                            'type' => 'numeric',\n                            'location' => 'xml',\n                        ),\n                        'CommonPrefixes' => array(\n                            'type' => 'array',\n                            'location' => 'xml',\n                            'data' => array(\n                                'xmlFlattened' => true,\n                            ),\n                            'items' => array(\n                                'type' => 'object',\n                                'properties' => array(\n                                    'Prefix' => array(\n                                        'type' => 'string',\n                                    ),\n                                ),\n                            ),\n                        ),\n                        'EncodingType' => array(\n                            'type' => 'string',\n                            'location' => 'xml',\n                        ),\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                    ),\n                ),\n                'ListMultipartUploadsOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'Bucket' => array(\n                            'type' => 'string',\n                            'location' => 'xml',\n                        ),\n                        'KeyMarker' => array(\n                            'type' => 'string',\n                            'location' => 'xml',\n                        ),\n                        'UploadIdMarker' => array(\n                            'type' => 'string',\n                            'location' => 'xml',\n                        ),\n                        'NextKeyMarker' => array(\n                            'type' => 'string',\n                            'location' => 'xml',\n                        ),\n                        'Prefix' => array(\n                            'type' => 'string',\n                            'location' => 'xml',\n                        ),\n                        'Delimiter' => array(\n                            'type' => 'string',\n                            'location' => 'xml',\n                        ),\n                        'NextUploadIdMarker' => array(\n                            'type' => 'string',\n                            'location' => 'xml',\n                        ),\n                        'MaxUploads' => array(\n                            'type' => 'numeric',\n                            'location' => 'xml',\n                        ),\n                        'IsTruncated' => array(\n                            'type' => 'boolean',\n                            'location' => 'xml',\n                        ),\n                        'Uploads' => array(\n                            'type' => 'array',\n                            'location' => 'xml',\n                            'sentAs' => 'Upload',\n                            'data' => array(\n                                'xmlFlattened' => true,\n                            ),\n                            'items' => array(\n                                'type' => 'object',\n                                'properties' => array(\n                                    'UploadId' => array(\n                                        'type' => 'string',\n                                    ),\n                                    'Key' => array(\n                                        'type' => 'string',\n                                    ),\n                                    'Initiated' => array(\n                                        'type' => 'string',\n                                    ),\n                                    'StorageClass' => array(\n                                        'type' => 'string',\n                                    ),\n                                    'Owner' => array(\n                                        'type' => 'object',\n                                        'properties' => array(\n                                            'DisplayName' => array(\n                                                'type' => 'string',\n                                            ),\n                                            'ID' => array(\n                                                'type' => 'string',\n                                            ),\n                                        ),\n                                    ),\n                                    'Initiator' => array(\n                                        'type' => 'object',\n                                        'properties' => array(\n                                            'ID' => array(\n                                                'type' => 'string',\n                                            ),\n                                            'DisplayName' => array(\n                                                'type' => 'string',\n                                            ),\n                                        ),\n                                    ),\n                                ),\n                            ),\n                        ),\n                        'CommonPrefixes' => array(\n                            'type' => 'array',\n                            'location' => 'xml',\n                            'data' => array(\n                                'xmlFlattened' => true,\n                            ),\n                            'items' => array(\n                                'type' => 'object',\n                                'properties' => array(\n                                    'Prefix' => array(\n                                        'type' => 'string',\n                                    ),\n                                ),\n                            ),\n                        ),\n                        'EncodingType' => array(\n                            'type' => 'string',\n                            'location' => 'xml',\n                        ),\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                    ),\n                ),\n                'ListBucketInventoryConfigurationsOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'InventoryConfiguration' => array(\n                            'type' => 'array',\n                            'location' => 'xml',\n                            'sentAs' => 'InventoryConfiguration',\n                            'items' => array(\n                                'type' => 'object',\n                                'properties' => array(\n                                    'Destination' => array(\n                                        'type' => 'object',\n                                        'location' => 'xml',\n                                        'properties' => array(\n                                            'COSBucketDestination' => array(\n                                                'type' => 'object',\n                                                'properties' => array(\n                                                    'Format' => array(\n                                                        'type' => 'string',\n                                                    ),\n                                                    'AccountId' => array(\n                                                        'type' => 'string',\n                                                    ),\n                                                    'Bucket' => array(\n                                                        'type' => 'string',\n                                                    ),\n                                                    'Prefix' => array(\n                                                        'type' => 'string',\n                                                    ),\n                                                    'Encryption' => array(\n                                                        'type' => 'object',\n                                                        'properties' => array(\n                                                            'SSE-COS' => array(\n                                                                'type' => 'string',\n                                                            )\n                                                        )\n                                                    ),\n                                                    \n                                                ),\n                                            ),\n                                        ),\n                                    ),\n                                    'Schedule' => array(\n                                        'type' => 'object',\n                                        'location' => 'xml',\n                                        'properties' => array(\n                                            'Frequency' => array(\n                                                'type' => 'string',\n                                            ),\n                                        ),\n                                    ),\n                                    'OptionalFields' => array(\n                                        'type' => 'array',\n                                        'location' => 'xml',\n                                        'properties' => array(\n                                            'Key' => array(\n                                                'type' => 'string',\n                                            ),\n                                        ),\n                                    ),\n                                    'OptionalFields' => array(\n                                        'type' => 'array',\n                                        'location' => 'xml',\n                                        'items' => array(\n                                            'name' => 'Field',\n                                            'type' => 'string',\n                                            'sentAs' => 'Field',\n                                        ),\n                                    ),\n                                    'IsEnabled' => array(\n                                        'type' => 'string',\n                                        'location' => 'xml',\n                                    ),\n                                    'Id' => array(\n                                        'type' => 'string',\n                                        'location' => 'xml',\n                                    ),\n                                    'IncludedObjectVersions' => array(\n                                        'type' => 'string',\n                                        'location' => 'xml',\n                                    ),\n                                    'RequestId' => array(\n                                        'location' => 'header',\n                                        'sentAs' => 'x-cos-request-id',\n                                    ),\n                                ),\n                            ),\n                        ),\n                    ),\n                ),\n                'HeadObjectOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'DeleteMarker' => array(\n                            'type' => 'boolean',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-delete-marker',\n                        ),\n                        'AcceptRanges' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'accept-ranges',\n                        ),\n                        'Expiration' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-expiration',\n                        ),\n                        'Restore' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-restore',\n                        ),\n                        'LastModified' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'Last-Modified',\n                        ),\n                        'ContentLength' => array(\n                            'type' => 'numeric',\n                            'minimum'=> 0,\n                            'location' => 'header',\n                            'sentAs' => 'Content-Length',\n                        ),\n                        'ETag' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                        ),\n                        'MissingMeta' => array(\n                            'type' => 'numeric',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-missing-meta',\n                        ),\n                        'VersionId' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-version-id',\n                        ),\n                        'CacheControl' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'Cache-Control',\n                        ),\n                        'ContentDisposition' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'Content-Disposition',\n                        ),\n                        'ContentEncoding' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'Content-Encoding',\n                        ),\n                        'ContentLanguage' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'Content-Language',\n                        ),\n                        'ContentType' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'Content-Type',\n                        ),\n                        'Expires' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                        ),\n                        'WebsiteRedirectLocation' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-website-redirect-location',\n                        ),\n                        'ServerSideEncryption' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption',\n                        ),\n                        'SSECustomerAlgorithm' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption-customer-algorithm',\n                        ),\n                        'SSECustomerKeyMD5' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption-customer-key-MD5',\n                        ),\n                        'SSEKMSKeyId' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-server-side-encryption-aws-kms-key-id',\n                        ),\n                        'StorageClass' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-storage-class',\n                        ),\n                        'RequestCharged' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-charged',\n                        ),\n                        'ReplicationStatus' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-replication-status',\n                        ),\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        )\n                    )\n                ),\n                'HeadBucketOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                    ),\n                ),\n                'SelectObjectContentOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'RawData' => array(\n                            'type' => 'string',\n                            'instanceOf' => 'GuzzleHttp\\\\Psr7\\\\Stream',\n                            'location' => 'body',\n                        ),\n                    ),\n                ),\n                'GetBucketIntelligentTieringOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'Status' => array(\n                            'type' => 'string',\n                            'location' => 'xml',\n                        ),\n                        'Transition' => array(\n                            'type' => 'object',\n                            'location' => 'xml',\n                            'properties' => array(\n                                'Days' => array(\n                                    'type' => 'string',\n                                ),\n                                'RequestFrequent' => array(\n                                    'type' => 'string',\n                                ),\n                            )\n                        ),\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                    ),\n                ),\n                'PutBucketIntelligentTieringOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                    ),\n                ),\n                'ImageInfoOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'Body' => array(\n                            'type' => 'string',\n                            'instanceOf' => 'GuzzleHttp\\\\Psr7\\\\Stream',\n                            'location' => 'body',\n                        ),\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                        'ContentType' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'Content-Type',\n                        ),\n                        'ContentLength' => array(\n                            'type' => 'numeric',\n                            'minimum'=> 0,\n                            'location' => 'header',\n                            'sentAs' => 'Content-Length',\n                        ),\n                    ),\n                ),\n                'ImageExifOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'Body' => array(\n                            'type' => 'string',\n                            'instanceOf' => 'GuzzleHttp\\\\Psr7\\\\Stream',\n                            'location' => 'body',\n                        ),\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                        'ContentType' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'Content-Type',\n                        ),\n                        'ContentLength' => array(\n                            'type' => 'numeric',\n                            'minimum'=> 0,\n                            'location' => 'header',\n                            'sentAs' => 'Content-Length',\n                        ),\n                    ),\n                ),\n                'ImageAveOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'Body' => array(\n                            'type' => 'string',\n                            'instanceOf' => 'GuzzleHttp\\\\Psr7\\\\Stream',\n                            'location' => 'body',\n                        ),\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                        'ContentType' => array(\n                            'type' => 'string',\n                            'location' => 'header',\n                            'sentAs' => 'Content-Type',\n                        ),\n                        'ContentLength' => array(\n                            'type' => 'numeric',\n                            'minimum'=> 0,\n                            'location' => 'header',\n                            'sentAs' => 'Content-Length',\n                        ),\n                    ),\n                ),\n                'ImageProcessOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                        'OriginalInfo' => array(\n                            'type' => 'object',\n                            'location' => 'xml',\n                            'properties' => array(\n                                'Key' => array(\n                                    'type' => 'string',\n                                ),\n                                'Location' => array(\n                                    'type' => 'string',\n                                ),\n                                'ETag' => array(\n                                    'type' => 'string',\n                                ),\n                                'ImageInfo' => array(\n                                    'type' => 'object',\n                                    'properties' => array(\n                                        'Format' => array(\n                                            'type' => 'string',\n                                        ),\n                                        'Width' => array(\n                                            'type' => 'string',\n                                        ),\n                                        'Height' => array(\n                                            'type' => 'string',\n                                        ),\n                                        'Quality' => array(\n                                            'type' => 'string',\n                                        ),\n                                        'Ave' => array(\n                                            'type' => 'string',\n                                        ),\n                                        'Orientation' => array(\n                                            'type' => 'string',\n                                        ),\n                                    ),\n                                ),\n                            ),\n                        ),\n                        'ProcessResults' => array(\n                            'type' => 'object',\n                            'location' => 'xml',\n                            'properties' => array(\n                                'Object' => array(\n                                    'type' => 'array',\n                                    'items' => array(\n                                        'type' => 'object',\n                                        'properties' => array(\n                                            'Key' => array(\n                                                'type' => 'string',\n                                            ),\n                                            'Location' => array(\n                                                'type' => 'string',\n                                            ),\n                                            'Format' => array(\n                                                'type' => 'string',\n                                            ),\n                                            'Width' => array(\n                                                'type' => 'string',\n                                            ),\n                                            'Height' => array(\n                                                'type' => 'string',\n                                            ),\n                                            'Size' => array(\n                                                'type' => 'string',\n                                            ),\n                                            'Quality' => array(\n                                                'type' => 'string',\n                                            ),\n                                            'ETag' => array(\n                                                'type' => 'string',\n                                            ),\n                                            'WatermarkStatus' => array(\n                                                'type' => 'integer',\n                                            ),\n                                        ),\n                                    ),\n                                ),\n                            ),\n                        ),\n                    ),\n                ),\n                'QrcodeOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                        'CodeStatus' => array(\n                            'type' => 'integer',\n                            'location' => 'xml',\n                        ),\n                        'QRcodeInfo' => array(\n                            'type' => 'array',\n                            'location' => 'xml',\n                            'items' => array(\n                                'type' => 'object',\n                                'properties' => array(\n                                    'CodeUrl' => array(\n                                        'type' => 'string',\n                                    ),\n                                    'Point' => array(\n                                        'type' => 'array',\n                                        'items' => array(\n                                            'type' => 'string',\n                                        ),\n                                    ),\n                                ),\n                            ),\n                        ),\n                        'ResultImage' => array(\n                            'type' => 'string',\n                            'location' => 'xml',\n                        ),\n                    ),\n                ),\n                'QrcodeGenerateOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                        'ResultImage' => array(\n                            'type' => 'string',\n                            'location' => 'xml',\n                        ),\n                    ),\n                ),\n                'DetectLabelOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                        'Labels' => array(\n                            'type' => 'array',\n                            'location' => 'xml',\n                            'items' => array(\n                                'type' => 'object',\n                                'properties' => array(\n                                    'Confidence' => array(\n                                        'type' => 'integer',\n                                    ),\n                                    'Name' => array(\n                                        'type' => 'string',\n                                    ),\n                                ),\n                            ),\n                        ),\n                    ),\n                ),\n                'PutBucketImageStyleOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                    ),\n                ),\n                'GetBucketImageStyleOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                        'StyleRule' => array(\n                            'type' => 'array',\n                            'location' => 'xml',\n                            'items' => array(\n                                'type' => 'object',\n                                'properties' => array(\n                                    'StyleName' => array(\n                                        'type' => 'string',\n                                    ),\n                                    'StyleBody' => array(\n                                        'type' => 'string',\n                                    ),\n                                ),\n                            ),\n                        ),\n                    ),\n                ),\n                'DeleteBucketImageStyleOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                    ),\n                ),\n                'PutBucketGuetzliOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                    ),\n                ),\n                'GetBucketGuetzliOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                        'ContentLength' => array(\n                            'type' => 'numeric',\n                            'minimum'=> 0,\n                            'location' => 'header',\n                            'sentAs' => 'Content-Length',\n                        ),\n                        'Body' => array(\n                            'type' => 'string',\n                            'instanceOf' => 'GuzzleHttp\\\\Psr7\\\\Stream',\n                            'location' => 'body',\n                        ),\n                    ),\n                ),\n                'DeleteBucketGuetzliOutput' => array(\n                    'type' => 'object',\n                    'additionalProperties' => true,\n                    'properties' => array(\n                        'RequestId' => array(\n                            'location' => 'header',\n                            'sentAs' => 'x-cos-request-id',\n                        ),\n                    ),\n                ),\n            )\n        );\n    }\n}\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/src/Qcloud/Cos/Signature.php",
    "content": "<?php\n\nnamespace Qcloud\\Cos;\n\nuse Psr\\Http\\Message\\RequestInterface;\n\nclass Signature {\n    private $accessKey;\n    // string: access key.\n    private $secretKey;\n    // string: secret key.\n\n    public function __construct( $accessKey, $secretKey, $token = null ) {\n        $this->accessKey = $accessKey;\n        $this->secretKey = $secretKey;\n        $this->token = $token;\n        $this->signHeader = [\n            'host',\n            'content-type',\n            'content-md5',\n            'content-disposition',\n            'content-encoding',\n            'content-length',\n            'transfer-encoding',\n            'range',\n        ];\n        date_default_timezone_set( 'PRC' );\n    }\n\n    public function __destruct() {\n    }\n\n    public function needCheckHeader( $header ) {\n        if ( startWith( $header, 'x-cos-' ) ) {\n            return true;\n        }\n        if ( in_array( $header, $this->signHeader ) ) {\n            return true;\n        }\n        return false;\n    }\n\n    public function signRequest( RequestInterface $request ) {\n        $authorization = $this->createAuthorization( $request );\n        return $request->withHeader( 'Authorization', $authorization );\n    }\n\n    public function createAuthorization( RequestInterface $request, $expires = '+30 minutes' ) {\n        if ( is_null( $expires ) ) {\n            $expires = '+30 minutes';\n        }\n        $signTime = ( string )( time() - 60 ) . ';' . ( string )( strtotime( $expires ) );\n        $urlParamListArray = [];\n        foreach ( explode( '&', $request->getUri()->getQuery() ) as $query ) {\n            if (!empty($query)) {\n                $tmpquery = explode( '=', $query );\n                $key = strtolower( $tmpquery[0] );\n                if (count($tmpquery) >= 2) {\n                    $value = $tmpquery[1];\n                } else {\n                    $value = \"\";\n                }\n                $urlParamListArray[$key] = $key. '='. $value;\n            }\n        }\n        ksort($urlParamListArray);\n        $urlParamList = join(';', array_keys($urlParamListArray));\n        $httpParameters = join('&', array_values($urlParamListArray));\n\n        $headerListArray = [];\n        foreach ( $request->getHeaders() as $key => $value ) {\n            $key = strtolower( urlencode( $key ) );\n            $value = rawurlencode( $value[0] );\n            if ( $this->needCheckHeader( $key ) ) {\n                $headerListArray[$key] = $key. '='. $value;\n            }\n        }\n        ksort($headerListArray);\n        $headerList = join(';', array_keys($headerListArray));\n        $httpHeaders = join('&', array_values($headerListArray));\n        $httpString = strtolower( $request->getMethod() ) . \"\\n\" . urldecode( $request->getUri()->getPath() ) . \"\\n\" . $httpParameters.\n        \"\\n\". $httpHeaders. \"\\n\";\n        $sha1edHttpString = sha1( $httpString );\n        $stringToSign = \"sha1\\n$signTime\\n$sha1edHttpString\\n\";\n        $signKey = hash_hmac( 'sha1', $signTime, $this->secretKey );\n        $signature = hash_hmac( 'sha1', $stringToSign, $signKey );\n        $authorization = 'q-sign-algorithm=sha1&q-ak='. $this->accessKey .\n        \"&q-sign-time=$signTime&q-key-time=$signTime&q-header-list=$headerList&q-url-param-list=$urlParamList&\" .\n        \"q-signature=$signature\";\n        return $authorization;\n    }\n\n    public function createPresignedUrl( RequestInterface $request, $expires = '+30 minutes' ) {\n        $authorization = $this->createAuthorization( $request, $expires );\n        $uri = $request->getUri();\n        $query = 'sign='.urlencode( $authorization ) . '&' . $uri->getQuery();\n        if ( $this->token != null ) {\n            $query = $query.'&x-cos-security-token='.$this->token;\n        }\n        $uri = $uri->withQuery( $query );\n        return $uri;\n    }\n}\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/src/Qcloud/Cos/SignatureMiddleware.php",
    "content": "<?php\n\nnamespace Qcloud\\Cos;\n\nuse Qcloud\\Cos\\Exception\\ServiceResponseException;\nuse GuzzleHttp\\Promise\\PromiseInterface;\nuse GuzzleHttp\\Psr7;\nuse Psr\\Http\\Message\\RequestInterface;\nuse Psr\\Http\\Message\\ResponseInterface;\nuse GuzzleHttp\\Exception\\RequestException;\n\nclass SignatureMiddleware {\n    private $nextHandler;\n    protected $signature;\n\n    /**\n     * @param callable $nextHandler Next handler to invoke.\n     */\n    public function __construct(callable $nextHandler, $accessKey, $secretKey) {\n        $this->nextHandler = $nextHandler;\n        $this->signature = new Signature($accessKey, $secretKey);\n    }\n\n    public function __invoke(RequestInterface $request, array $options) {\n        $fn = $this->nextHandler;\n        return $fn($this->signature->signRequest($request), $options);\n\t}\n}\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/src/Qcloud/Cos/Tests/COSTest.php",
    "content": "<?php\n\nnamespace Qcloud\\Cos\\Tests;\n\nuse Qcloud\\Cos\\Client;\nuse Qcloud\\Cos\\Exception\\ServiceResponseException;\nclass COSTest extends \\PHPUnit\\Framework\\TestCase\n{\n    const SYNC_TIME = 5;\n    private $cosClient;\n    private $bucket;\n    private $region;\n    protected function setUp(): void\n    {\n        $this->bucket = getenv('COS_BUCKET');\n        $this->region = getenv('COS_REGION');\n        $this->bucket2 = \"tmp\".$this->bucket;\n        $this->cosClient = new Client(array('region' => $this->region,\n            'credentials' => array(\n                'secretId' => getenv('COS_KEY'),\n                'secretKey' => getenv('COS_SECRET'))));\n        try {\n            $this->cosClient->createBucket(['Bucket' => $this->bucket]);\n        } catch(\\Exception $e) {\n        }\n    }\n\n    protected function tearDown(): void {\n    }\n\n    function generateRandomString($length = 10) { \n        $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; \n        $randomString = ''; \n        for ($i = 0; $i < $length; $i++) { \n            $randomString .= $characters[rand(0, strlen($characters) - 1)]; \n        } \n        return $randomString; \n    }\n\n    function generateRandomFile($size = 10, $filename = 'random-file') { \n        exec(\"dd if=/dev/urandom of=\". $filename. \" bs=1 count=\". (string)$size);\n    }\n    \n    /**********************************\n     * TestBucket\n     **********************************/\n    \n     /*\n     * put bucket,bucket已经存在\n     * BucketAlreadyOwnedByYou\n     * 409\n     */\n    public function testCreateExistingBucket()\n    {\n        try {\n            $this->cosClient->createBucket(['Bucket' => $this->bucket]);\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            $this->assertTrue($e->getExceptionCode() === 'BucketAlreadyOwnedByYou' && $e->getStatusCode() === 409);\n        }\n    }\n\n    /*\n     * put bucket, 创建所有region的bucket\n     * 409\n     */\n    public function testValidRegionBucket()\n    {\n        $regionlist = array('cn-east','ap-shanghai',\n        'cn-south','ap-guangzhou',\n        'cn-north','ap-beijing-1',\n        'cn-southwest','ap-chengdu',\n        'sg','ap-singapore',\n        'tj','ap-beijing-1',\n        'bj','ap-beijing',\n        'sh','ap-shanghai',\n        'gz','ap-guangzhou',\n        'cd','ap-chengdu',\n        'sgp','ap-singapore');\n        foreach ($regionlist as$region) {\n            try {\n                $this->cosClient = new Client(array('region' => $region,\n                    'credentials' => array(\n                        'appId' => getenv('COS_APPID'),\n                        'secretId' => getenv('COS_KEY'),\n                        'secretKey' => getenv('COS_SECRET'))));\n                $this->cosClient->createBucket(['Bucket' => $this->bucket]);\n                $this->assertTrue(True);\n            } catch (ServiceResponseException $e) {\n                $this->assertEquals([$e->getStatusCode()], [409]);\n            }\n        }\n    }\n\n    /*\n     * put bucket, 不合法的region名\n     * 409\n     */\n    public function testInvalidRegionBucket()\n    {\n        $regionlist = array('cn-east-2','ap-shanghai-3');\n        foreach ($regionlist as$region) {\n            try {\n                $this->cosClient = new Client(array('region' => $region,\n                    'credentials' => array(\n                        'appId' => getenv('COS_APPID'),\n                        'secretId' => getenv('COS_KEY'),\n                        'secretKey' => getenv('COS_SECRET'))));\n                $this->cosClient->createBucket(['Bucket' => $this->bucket]);\n                $this->assertTrue(True);\n            } catch (ServiceResponseException $e) {\n                $this->assertFalse(TRUE);\n            } catch (\\GuzzleHttp\\Exception\\ConnectException $e) {\n                $this->assertTrue(TRUE);\n            }\n        }\n    }\n\n    /*\n     * get Service\n     * 200\n     */\n    public function testGetService()\n    {\n        try {\n            $this->cosClient->ListBuckets();\n            $this->assertTrue(TRUE);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n    /*\n     * put bucket,bucket名称非法\n     * InvalidBucketName\n     * 400\n     */\n    public function testCreateInvalidBucket()\n    {\n        try {\n            $this->cosClient->createBucket(array('Bucket' => 'qwe_123' . $this->bucket));\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertTrue($e->getExceptionCode() === 'InvalidBucketName' && $e->getStatusCode() === 400);\n        }\n    }\n\n    /*\n     * put bucket，设置bucket公公权限为private\n     * 200\n     */\n    public function testCreatePrivateBucket()\n    {\n        try {\n            TestHelper::nuke($this->bucket2);\n            sleep(COSTest::SYNC_TIME);\n            $this->cosClient->createBucket(\n                array(\n                    'Bucket' => $this->bucket2,\n                    'ACL'=>'private'\n                ));\n            sleep(COSTest::SYNC_TIME);\n            TestHelper::nuke($this->bucket2);\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n    /*\n     * put bucket，设置bucket公公权限为public-read\n     * 200\n     */\n    public function testCreatePublicReadBucket()\n    {\n        try {\n            TestHelper::nuke($this->bucket2);\n            sleep(COSTest::SYNC_TIME);\n            $this->cosClient->createBucket(\n                array(\n                    'Bucket' => $this->bucket2,\n                    'ACL'=>'public-read'\n                )\n            );\n            sleep(COSTest::SYNC_TIME);\n            TestHelper::nuke($this->bucket2);\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n    /*\n     * put bucket，公共权限非法\n     * InvalidArgument\n     * 400\n     */\n    public function testCreateInvalidACLBucket()\n    {\n        try {\n            TestHelper::nuke($this->bucket2);\n            sleep(COSTest::SYNC_TIME);\n            $this->cosClient->createBucket(\n                array(\n                    'Bucket' => $this->bucket2,\n                    'ACL'=>'public'\n                )\n            );\n            sleep(COSTest::SYNC_TIME);\n            TestHelper::nuke($this->bucket2);\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            $this->assertTrue($e->getExceptionCode() === 'InvalidArgument' && $e->getStatusCode() === 400);\n        }\n    }\n\n    /*\n     * put bucket acl，设置bucket公共权限为private\n     * 200\n     */\n    public function testPutBucketAclPrivate()\n    {\n        try {\n            $this->cosClient->PutBucketAcl(\n                array(\n                    'Bucket' => $this->bucket,\n                    'ACL'=>'private'\n                )\n            );\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n    /*\n     * put bucket acl，设置bucket公共权限为public-read\n     * 200\n     */\n    public function testPutBucketAclPublicRead()\n    {\n        try {\n            $this->cosClient->PutBucketAcl(\n                array(\n                    'Bucket' => $this->bucket,\n                    'ACL'=>'public-read'\n                )\n            );\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n    /*\n     * put bucket acl，公共权限非法\n     * InvalidArgument\n     * 400\n     */\n    public function testPutBucketAclInvalid()\n    {\n        try {\n            $this->cosClient->PutBucketAcl(\n                array(\n                    'Bucket' => $this->bucket,\n                    'ACL'=>'public'\n                )\n            );\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            $this->assertTrue($e->getExceptionCode() === 'InvalidArgument' && $e->getStatusCode() === 400);\n        }\n    }\n\n    /*\n     * put bucket acl，设置bucket账号权限为grant-read\n     * 200\n     */\n    public function testPutBucketAclReadToUser()\n    {\n        try {\n            $this->cosClient->PutBucketAcl(\n                array(\n                    'Bucket' =>  $this->bucket,\n                    'GrantRead' => 'id=\"qcs::cam::uin/2779643970:uin/2779643970\"'\n                )\n            );\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n    /*\n     * put bucket acl，设置bucket账号权限为grant-write\n     * 200\n     */\n    public function testPutBucketAclWriteToUser()\n    {\n        try {\n            $this->cosClient->PutBucketAcl(\n                array(\n                    'Bucket' =>  $this->bucket,\n                    'GrantWrite' => 'id=\"qcs::cam::uin/2779643970:uin/2779643970\"'\n                )\n            );\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n    /*\n     * put bucket acl，设置bucket账号权限为grant-full-control\n     * 200\n     */\n    public function testPutBucketAclFullToUser()\n    {\n        try {\n            $this->cosClient->PutBucketAcl(\n                array(\n                    'Bucket' =>  $this->bucket,\n                    'GrantFullControl' => 'id=\"qcs::cam::uin/2779643970:uin/2779643970\"'\n                )\n            );\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n    /*\n     * put bucket acl，设置bucket账号权限，同时授权给多个账户\n     * 200\n     */\n    public function testPutBucketAclToUsers()\n    {\n        try {\n            $this->cosClient->PutBucketAcl(\n                array(\n                    'Bucket' =>  $this->bucket,\n                    'GrantFullControl' => 'id=\"qcs::cam::uin/2779643970:uin/2779643970\",id=\"qcs::cam::uin/2779643970:uin/2779643970\",id=\"qcs::cam::uin/2779643970:uin/2779643970\"'\n                )\n            );\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n    /*\n     * put bucket acl，设置bucket账号权限，授权给子账号\n     * 200\n     */\n    public function testPutBucketAclToSubuser()\n    {\n        try {\n            $this->cosClient->PutBucketAcl(\n                array(\n                    'Bucket' =>  $this->bucket,\n                    'GrantFullControl' => 'id=\"qcs::cam::uin/2779643970:uin/2779643970\"'\n                )\n            );\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n    /*\n     * put bucket acl，设置bucket账号权限，同时指定read、write和fullcontrol\n     * 200\n     */\n    public function testPutBucketAclReadWriteFull()\n    {\n        try {\n            $this->cosClient->PutBucketAcl(\n                array(\n                    'Bucket' =>  $this->bucket,\n                    'GrantRead' => 'id=\"qcs::cam::uin/123:uin/123\"',\n                    'GrantWrite' => 'id=\"qcs::cam::uin/2779643970:uin/2779643970\"',\n                    'GrantFullControl' => 'id=\"qcs::cam::uin/2779643970:uin/2779643970\"'\n                )\n            );\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n    /*\n     * put bucket acl，设置bucket账号权限，grant值非法\n     * InvalidArgument\n     * 400\n     */\n    public function testPutBucketAclInvalidGrant()\n    {\n        try {\n            $this->cosClient->PutBucketAcl(\n                array(\n                    'Bucket' =>  $this->bucket,\n                    'GrantFullControl' => 'id=\"qcs::camuin/321023:uin/2779643970\"'\n                )\n            );\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            $this->assertTrue($e->getExceptionCode() === 'InvalidArgument' && $e->getStatusCode() === 400);\n        }\n    }\n\n    /*\n     * put bucket acl，设置bucket账号权限，通过body方式授权\n     * 200\n     */\n    public function testPutBucketAclByBody()\n    {\n        try {\n            $this->cosClient->PutBucketAcl(\n                array(\n                    'Bucket' => $this->bucket,\n                    'Grants' => array(\n                        array(\n                            'Grantee' => array(\n                                'DisplayName' => 'qcs::cam::uin/2779643970:uin/2779643970',\n                                'ID' => 'qcs::cam::uin/2779643970:uin/2779643970',\n                                'Type' => 'CanonicalUser',\n                            ),\n                            'Permission' => 'FULL_CONTROL',\n                        ),\n                    ),\n                    'Owner' => array(\n                        'DisplayName' => 'qcs::cam::uin/2779643970:uin/2779643970',\n                        'ID' => 'qcs::cam::uin/2779643970:uin/2779643970',\n                    )\n                )\n            );\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n    /*\n     * put bucket acl，设置bucket账号权限，通过body方式授权给anyone\n     * 200\n     */\n    public function testPutBucketAclByBodyToAnyone()\n    {\n        try {\n            $this->cosClient->PutBucketAcl(\n                array(\n                    'Bucket' => $this->bucket,\n                    'Grants' => array(\n                        array(\n                            'Grantee' => array(\n                                'DisplayName' => 'qcs::cam::anyone:anyone',\n                                'ID' => 'qcs::cam::anyone:anyone',\n                                'Type' => 'CanonicalUser',\n                            ),\n                            'Permission' => 'FULL_CONTROL',\n                        ),\n                    ),\n                    'Owner' => array(\n                        'DisplayName' => 'qcs::cam::uin/2779643970:uin/2779643970',\n                        'ID' => 'qcs::cam::uin/2779643970:uin/2779643970',\n                    )\n                )\n            );\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n    /*\n     * put bucket acl，bucket不存在\n     * NoSuchBucket\n     * 404\n     */\n    public function testPutBucketAclBucketNonexisted()\n    {\n        try {\n            TestHelper::nuke($this->bucket2);\n            sleep(COSTest::SYNC_TIME);\n            $this->cosClient->PutBucketAcl(\n                array(\n                    'Bucket' =>  $this->bucket2,\n                    'GrantFullControl' => 'id=\"qcs::cam::uin/321023:uin/2779643970\"'\n                )\n            );\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            $this->assertTrue($e->getExceptionCode() === 'NoSuchBucket' && $e->getStatusCode() === 404);\n        }\n    }\n\n    /*\n     * put bucket acl，覆盖设置\n     * x200\n     */\n    public function testPutBucketAclCover()\n    {\n        try {\n            $this->cosClient->PutBucketAcl(array(\n                'Bucket' =>  $this->bucket,\n                'GrantFullControl' => 'id=\"qcs::cam::uin/2779643970:uin/2779643970\"',\n                'GrantRead' => 'id=\"qcs::cam::uin/2779643970:uin/2779643970\"',\n                'GrantWrite' => 'id=\"qcs::cam::uin/2779643970:uin/2779643970\"'));\n            $this->cosClient->PutBucketAcl(array(\n                'Bucket' =>  $this->bucket,\n                'GrantWrite' => 'id=\"qcs::cam::uin/2779643970:uin/2779643970\"'));\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n    /*\n     * 正常head bucket\n     * 200\n     */\n    public function testHeadBucket()\n    {\n        try {\n            $this->cosClient->HeadBucket(array(\n                'Bucket' =>  $this->bucket));\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n    /*\n     * head bucket，bucket不存在\n     * NoSuchBucket\n     * 404\n     */\n    public function testHeadBucketNonexisted()\n    {\n        try {\n            TestHelper::nuke($this->bucket2);\n            sleep(COSTest::SYNC_TIME);\n            $this->cosClient->HeadBucket(array(\n                'Bucket' =>  $this->bucket2));\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            $this->assertTrue($e->getExceptionCode() === 'NoSuchBucket' && $e->getStatusCode() === 404);\n        }\n    }\n\n    /*\n     * get bucket,bucket为空\n     * 200\n     */\n    public function testGetBucketEmpty()\n    {\n        try {\n            $this->cosClient->ListObjects(array(\n                'Bucket' =>  $this->bucket));\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n    /*\n     * get bucket, prefix为中文\n     * 200\n     */\n    public function testGetBucketWithChinese()\n    {\n        try {\n            $this->cosClient->ListObjects(array(\n                'Bucket' =>  $this->bucket,\n                'Prefix' => '中文',\n                'Delimiter' => '/'));\n            $this->assertTrue(TRUE);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n    /*\n     * get bucket，bucket不存在\n     * NoSuchBucket\n     * 404\n     */\n    public function testGetBucketNonexisted()\n    {\n        try {\n            TestHelper::nuke($this->bucket2);\n            sleep(COSTest::SYNC_TIME);\n            $this->cosClient->ListObjects(\n                array(\n                    'Bucket' =>  $this->bucket2\n                )\n            );\n            $this->assertTrue(False);\n        } catch (ServiceResponseException $e) {\n            $this->assertTrue($e->getExceptionCode() === 'NoSuchBucket' && $e->getStatusCode() === 404);\n        }\n    }\n\n\n    /*\n     * put bucket cors，cors规则包含多条\n     * 200\n     */\n    public function testPutBucketCors()\n    {\n        try {\n            $this->cosClient->putBucketCors(\n                array(\n                    'Bucket' => $this->bucket,\n                    'CORSRules' => array(\n                        array(\n                            'ID' => '1234',\n                            'AllowedHeaders' => array('*',),\n                            'AllowedMethods' => array('PUT',),\n                            'AllowedOrigins' => array('*',),\n                            'ExposeHeaders' => array('*',),\n                            'MaxAgeSeconds' => 1,\n                        ),\n                        array(\n                            'ID' => '12345',\n                            'AllowedHeaders' => array('*',),\n                            'AllowedMethods' => array('GET',),\n                            'AllowedOrigins' => array('*',),\n                            'ExposeHeaders' => array('*',),\n                            'MaxAgeSeconds' => 1,\n                        ),\n                    ),\n                )\n            );\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n\n    /*\n     * 正常get bucket cors\n     * 200\n     */\n    public function testGetBucketCors()\n    {\n        try {\n            $this->cosClient->putBucketCors(\n                array(\n                    'Bucket' => $this->bucket,\n                    'CORSRules' => array(\n                        array(\n                            'ID' => '1234',\n                            'AllowedHeaders' => array('*',),\n                            'AllowedMethods' => array('PUT',),\n                            'AllowedOrigins' => array('*',),\n                            'ExposeHeaders' => array('*',),\n                            'MaxAgeSeconds' => 1,\n                        ),\n                        array(\n                            'ID' => '12345',\n                            'AllowedHeaders' => array('*',),\n                            'AllowedMethods' => array('GET',),\n                            'AllowedOrigins' => array('*',),\n                            'ExposeHeaders' => array('*',),\n                            'MaxAgeSeconds' => 1,\n                        ),\n                    ),\n                )\n            );\n            $this->cosClient->getBucketCors(\n                array(\n                    'Bucket' => $this->bucket\n                )\n            );\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n    /*\n     * bucket未设置cors规则，发送get bucket cors\n     * NoSuchCORSConfiguration\n     * 404\n     */\n    public function testGetBucketCorsNull()\n    {\n        try {\n            $this->cosClient->deleteBucketCors(\n                array(\n                    'Bucket' => $this->bucket\n                )\n            );\n            $rt = $this->cosClient->getBucketCors(\n                array(\n                    'Bucket' => $this->bucket\n                )\n            );\n            print_r($rt);\n            $this->assertTrue(False);\n        } catch (ServiceResponseException $e) {\n            $this->assertTrue($e->getExceptionCode() === 'NoSuchCORSConfiguration' && $e->getStatusCode() === 404);\n        }\n    }\n\n    /*\n     * 正常get bucket lifecycle\n     * 200\n     */\n    public function testGetBucketLifecycle()\n    {\n        try {\n            $result = $this->cosClient->putBucketLifecycle(\n                array(\n                    'Bucket' => $this->bucket,\n                    'Rules' => array(\n                        array(\n                            'Status' => 'Enabled',\n                            'Filter' => array(\n                                'Tag' => array(\n                                    'Key' => 'datalevel',\n                                    'Value' => 'backup'\n                                )\n                            ),\n                            'Transitions' => array(\n                                array(\n                                    # 30天后转换为Standard_IA\n                                    'Days' => 30,\n                                    'StorageClass' => 'Standard_IA'),\n                                array(\n                                    # 365天后转换为Archive\n                                    'Days' => 365,\n                                    'StorageClass' => 'Archive')\n                            ),\n                            'Expiration' => array(\n                                # 3650天后过期删除\n                                'Days' => 3650,\n                            )\n                        )\n                    )\n                )\n            );\n            $result = $this->cosClient->getBucketLifecycle(array(\n                'Bucket' => $this->bucket,\n            ));\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n    /*\n     * 正常delete bucket lifecycle\n     * 200\n     */\n    public function testDeleteBucketLifecycle()\n    {\n        try {\n            $result = $this->cosClient->putBucketLifecycle(\n                array(\n                    'Bucket' => $this->bucket,\n                    'Rules' => array(\n                        array(\n                            'Status' => 'Enabled',\n                            'Filter' => array(\n                                'Tag' => array(\n                                    'Key' => 'datalevel',\n                                    'Value' => 'backup'\n                                )\n                            ),\n                            'Transitions' => array(\n                                array(\n                                    # 30天后转换为Standard_IA\n                                    'Days' => 30,\n                                    'StorageClass' => 'Standard_IA'),\n                                array(\n                                    # 365天后转换为Archive\n                                    'Days' => 365,\n                                    'StorageClass' => 'Archive')\n                            ),\n                            'Expiration' => array(\n                                # 3650天后过期删除\n                                'Days' => 3650,\n                            )\n                        )\n                    )\n                )\n            );\n            $result = $this->cosClient->deleteBucketLifecycle(array(\n                // Bucket is required\n                'Bucket' => $this->bucket,\n            ));\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n    /*\n     * put bucket lifecycle，请求body中不指定filter\n     * 200\n     */\n    public function testPutBucketLifecycleNonFilter()\n    {\n        try {\n            $result = $this->cosClient->putBucketLifecycle(\n                array(\n                    'Bucket' => $this->bucket,\n                    'Rules' => array(\n                        array(\n                            'Expiration' => array(\n                                'Days' => 1000,\n                            ),\n                            'ID' => 'id1',\n                            'Status' => 'Enabled',\n                            'Transitions' => array(\n                                array(\n                                    'Days' => 100,\n                                    'StorageClass' => 'Standard_IA'),\n                            ),\n                        ),\n                    )\n                )\n            );\n            $result = $this->cosClient->deleteBucketLifecycle(array(\n                // Bucket is required\n                'Bucket' => $this->bucket,\n            ));\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(True);\n        }\n    }\n\n    /*\n     * put bucket,bucket名称带有-\n     * 200\n     */\n    public function testPutBucket2()\n    {\n        try {\n            try{\n                $this->cosClient->deleteBucket(array('Bucket' => '12345-'.$this->bucket));\n            } catch (\\Exception $e) {\n            }\n            $this->cosClient->createBucket(array('Bucket' => '12345-'.$this->bucket));\n            sleep(COSTest::SYNC_TIME);\n            $this->cosClient->deleteBucket(array('Bucket' => '12345-'.$this->bucket));\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n    /*\n     * put bucket,bucket名称带有两个-\n     * 200\n     */\n    public function testPutBucket3()\n    {\n        try {\n            $this->cosClient->createBucket(array('Bucket' => '12-333-4445' . $this->bucket));\n            $this->cosClient->deleteBucket(array('Bucket' => '12-333-4445' . $this->bucket));\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n    /*\n     * 正常get bucket location\n     * 200\n     */\n        public function testGetBucketLocation()\n    {\n        try {\n            $this->cosClient->getBucketLocation(array('Bucket' => $this->bucket));\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n    /*\n     * bucket不存在，发送get bucket location请求\n     * NoSuchBucket\n     * 404\n     */\n    public function testGetBucketLocationNonExisted()\n    {\n        try {\n            TestHelper::nuke($this->bucket2);\n            sleep(COSTest::SYNC_TIME);\n            $this->cosClient->getBucketLocation(array('Bucket' => $this->bucket2));\n            $this->assertTrue(False);\n        } catch (ServiceResponseException $e) {\n            $this->assertTrue($e->getExceptionCode() === 'NoSuchBucket' && $e->getStatusCode() === 404);\n        }\n    }\n\n    /**********************************\n     * TestObject\n     **********************************/\n\n    /*\n     * put object, 从本地上传文件\n     * 200\n     */\n    public function testPutObjectLocalObject() {\n        try {\n            $key = '你好.txt';\n            $body = $this->generateRandomString(1024+1023);\n            $md5 = base64_encode(md5($body, true));\n            $local_test_key = \"local_test_file\";\n            $f = fopen($local_test_key, \"wb\");\n            fwrite($f, $body);\n            fclose($f);\n            $this->cosClient->putObject(['Bucket' => $this->bucket,\n                                         'Key' => $key,\n                                         'Body' => fopen($local_test_key, \"rb\")]);\n            $rt = $this->cosClient->getObject(['Bucket'=>$this->bucket, 'Key'=>$key]);\n            $download_md5 = base64_encode(md5($rt['Body'], true));\n            $this->assertEquals($md5, $download_md5);\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n    /*\n     * upload, 从本地上传\n     * 200\n     */\n    public function testUploadLocalObject() {\n        try {\n            $key = '你好.txt';\n            $body = $this->generateRandomString(1024+1023);\n            $md5 = base64_encode(md5($body, true));\n            $local_test_key = \"local_test_file\";\n            $f = fopen($local_test_key, \"wb\");\n            fwrite($f, $body);\n            fclose($f);\n            $this->cosClient->upload($bucket=$this->bucket,\n                                     $key=$key,\n                                     $body=fopen($local_test_key, \"rb\"),\n                                     $options=['PartSize'=>1024 * 1024 + 1]);\n            $rt = $this->cosClient->getObject(['Bucket'=>$this->bucket, 'Key'=>$key]);\n            $download_md5 = base64_encode(md5($rt['Body'], true));\n            $this->assertEquals($md5, $download_md5);\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n    /*\n     * put object,请求头部携带服务端加密参数\n     * 200\n     */\n    public function testPutObjectEncryption()\n    {\n        try {\n            $this->cosClient->putObject(\n                array(\n                    'Bucket' => $this->bucket,\n                    'Key' => '11//32//43',\n                    'Body' => 'Hello World!',\n                    'ServerSideEncryption' => 'AES256'\n                )\n            );\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n    /*\n     * 上传文件Bucket不存在\n     * NoSuchBucket\n     * 404\n     */\n    public function testPutObjectIntoNonexistedBucket() {\n        try {\n            TestHelper::nuke($this->bucket2);\n            sleep(COSTest::SYNC_TIME);\n            $this->cosClient->putObject(\n                array(\n                    'Bucket' => $this->bucket2, 'Key' => 'hello.txt', 'Body' => 'Hello World'\n                )\n            );\n            $this->assertTrue(False);\n        } catch (ServiceResponseException $e) {\n            $this->assertTrue($e->getExceptionCode() === 'NoSuchBucket');\n            $this->assertTrue($e->getStatusCode() === 404);\n        }\n    }\n\n\n    /*\n     * 上传小文件\n     * 200\n     */\n    public function testUploadSmallObject() {\n        try {\n            $this->cosClient->upload($this->bucket, '你好.txt', 'Hello World');\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n    /*\n     * 上传空文件\n     * 200\n     */\n    public function testPutObjectEmpty() {\n        try {\n            $this->cosClient->upload($this->bucket, '你好.txt', '');\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n    /*\n     * 上传已存在的文件\n     * 200\n     */\n    public function testPutObjectExisted() {\n        try {\n            $this->cosClient->upload($this->bucket, '你好.txt', '1234124');\n            $this->cosClient->upload($this->bucket, '你好.txt', '请二位qwe');\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n    /*\n     * put object，请求头部携带自定义头部x-cos-meta-\n     * 200\n     */\n    public function testPutObjectMeta() {\n        try {\n            $key = '你好.txt';\n            $meta = array(\n                'test' => str_repeat('a', 1 * 1024),\n                'test-meta' => '中文qwe-23ds-ad-xcz.asd.*qweqw'\n            );\n            $this->cosClient->putObject(array(\n                'Bucket' => $this->bucket,\n                'Key' => '你好.txt',\n                'Body' => '1234124',\n                'Metadata' => $meta\n                     \n            ));\n            $rt = $this->cosClient->headObject(['Bucket'=>$this->bucket, 'Key'=>$key]);\n            $this->assertEquals($rt['Metadata'], $meta);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n    /*\n     * upload large object，请求头部携带自定义头部x-cos-meta-\n     * 200\n     */\n    public function testUploadLargeObjectMeta() {\n        try {\n            $key = '你好.txt';\n            $meta = array(\n                'test' => str_repeat('a', 1 * 1024),\n                'test-meta' => 'qwe-23ds-ad-xcz.asd.*qweqw'\n            );\n            $body = $this->generateRandomString(2*1024*1024+1023);\n            $this->cosClient->upload($bucket=$this->bucket,\n                                     $key=$key,\n                                     $body=$body,\n                                     $options=['PartSize'=>1024 * 1024 + 1, 'Metadata'=>$meta]);\n            $rt = $this->cosClient->headObject(['Bucket'=>$this->bucket, 'Key'=>$key]);\n            $this->assertEquals($rt['Metadata'], $meta);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n    /*\n     * put object，请求头部携带自定义头部x-cos-meta-\n     * KeyTooLong\n     * 400\n     */\n    public function testPutObjectMeta2K() {\n        try {\n            $this->cosClient->putObject(array(\n                'Bucket' => $this->bucket,\n                'Key' => '你好.txt',\n                'Body' => '1234124',\n                'Metadata' => array(\n                    'lew' => str_repeat('a', 3 * 1024),\n                )));\n            $this->assertTrue(False);\n        } catch (ServiceResponseException $e) {\n            $this->assertEquals(\n                [$e->getStatusCode(), $e->getExceptionCode()],\n                [400, 'KeyTooLong']\n            );\n            print $e;\n        }\n    }\n\n    /*\n     * 上传复杂文件名的文件\n     * 200\n     */\n    public function testUploadComplexObject() {\n        try {\n            $key = '→↓←→↖↗↙↘! \\\"#$%&\\'()*+,-./0123456789:;<=>@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`abcdefghijklmnopqrstuvwxyz{|}~';\n            $this->cosClient->upload($this->bucket, $key, 'Hello World');\n            $this->cosClient->headObject(array(\n                'Bucket' => $this->bucket,\n                'Key' => $key\n            ));\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n    /*\n     * 上传大文件\n     * 200\n     */\n    public function testUploadLargeObject() {\n        try {\n            $key = '你好.txt';\n            $body = $this->generateRandomString(2*1024*1024+1023);\n            $md5 = base64_encode(md5($body, true));\n            $this->cosClient->upload($bucket=$this->bucket,\n                                     $key=$key,\n                                     $body=$body,\n                                     $options=['PartSize'=>1024 * 1024 + 1]);\n            $rt = $this->cosClient->getObject(['Bucket'=>$this->bucket, 'Key'=>$key]);\n            $download_md5 = base64_encode(md5($rt['Body'], true));\n            $this->assertEquals($md5, $download_md5);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n    /*\n     * 断点重传\n     * 200\n     */\n    public function testResumeUpload() {\n        try {\n            $key = '你好.txt';\n            $body = $this->generateRandomString(3*1024*1024+1023);\n            $partSize = 1024 * 1024 + 1;\n            $md5 = base64_encode(md5($body, true));\n            $rt = $this->cosClient->CreateMultipartUpload(['Bucket' => $this->bucket,\n                                                           'Key' => $key]);\n            $uploadId = $rt['UploadId'];\n            $this->cosClient->uploadPart(['Bucket' => $this->bucket,\n                                          'Key' => $key,\n                                          'Body' => substr($body, 0, $partSize),\n                                          'UploadId' => $uploadId,\n                                          'PartNumber' => 1]);\n            $rt = $this->cosClient->ListParts(['Bucket' => $this->bucket,\n                                          'Key' => $key,\n                                          'UploadId' => $uploadId]);\n            $this->assertEquals(count($rt['Parts']), 1);\n            $this->cosClient->resumeUpload($bucket=$this->bucket,\n                                           $key=$key,\n                                           $body=$body,\n                                           $uploadId=$uploadId,\n                                           $options=['PartSize'=>$partSize]);\n            $rt = $this->cosClient->getObject(['Bucket'=>$this->bucket, 'Key'=>$key]);\n            $download_md5 = base64_encode(md5($rt['Body'], true));\n            $this->assertEquals($md5, $download_md5);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n    /*\n     * 下载文件\n     * 200\n     */\n    public function testGetObject() {\n        try {\n            $this->cosClient->upload($this->bucket, '你好.txt', 'Hello World');\n            $this->cosClient->getObject(array(\n                'Bucket' => $this->bucket,\n                'Key' => '你好.txt',));\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n    /*\n     * range下载大文件\n     * 200\n     */\n    public function testDownloadLargeObject() {\n        try {\n            $key = '你好.txt';\n            $local_path = \"test_tmp_file\";\n            $body = $this->generateRandomString(2*1024*1024+1023);\n            $md5 = base64_encode(md5($body, true));\n            $this->cosClient->upload($bucket=$this->bucket,\n                                     $key=$key,\n                                     $body=$body,\n                                     $options=['PartSize'=>1024 * 1024 + 1]);\n            $rt = $this->cosClient->download($bucket=$this->bucket,\n                                            $key=$key,\n                                            $saveAs=$local_path,\n                                            $options=['PartSize'=>1024 * 1024 + 1]);\n            $body = file_get_contents($local_path);\n            $download_md5 = base64_encode(md5($body, true));\n            $this->assertEquals($md5, $download_md5);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n    /*\n     * get object，object名称包含特殊字符\n     * 200\n     */\n    public function testGetObjectSpecialName() {\n        try {\n            $this->cosClient->upload($this->bucket, '你好<>!@#^%^&*&(&^!@#@!.txt', 'Hello World');\n            $this->cosClient->getObject(array(\n                'Bucket' => $this->bucket,\n                'Key' => '你好<>!@#^%^&*&(&^!@#@!.txt',));\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n    /*\n     * get object，请求头部带if-match，参数值为true\n     * 200\n     */\n    public function testGetObjectIfMatchTrue() {\n        try {\n            $this->cosClient->upload($this->bucket, '你好.txt', 'Hello World');\n            $this->cosClient->getObject(array(\n                'Bucket' => $this->bucket,\n                'Key' => '你好.txt',\n                'IfMatch' => '\"b10a8db164e0754105b7a99be72e3fe5\"'));\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n\n    /*\n     * get object，请求头部带if-match，参数值为false\n     * PreconditionFailed\n     * 412\n     */\n    public function testGetObjectIfMatchFalse() {\n        try {\n            $this->cosClient->upload($this->bucket, '你好.txt', 'Hello World');\n            $this->cosClient->getObject(array(\n                'Bucket' => $this->bucket,\n                'Key' => '你好.txt',\n                'IfMatch' => '\"\"'));\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            $this->assertEquals(\n                [$e->getStatusCode(), $e->getExceptionCode()],\n                [412, 'PreconditionFailed']\n            );\n            print $e;\n        }\n    }\n\n    /*\n     * get object，请求头部带if-none-match，参数值为true\n     * 200\n     */\n    public function testGetObjectIfNoneMatchTrue() {\n        try {\n            $this->cosClient->upload($this->bucket, '你好.txt', 'Hello World');\n            $rt = $this->cosClient->getObject(array(\n                'Bucket' => $this->bucket,\n                'Key' => '你好.txt',\n                'IfNoneMatch' => '\"b10a8db164e0754105b7a99be72e3fe5\"'));\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n\n    /*\n     * get object，请求头部带if-none-match，参数值为false\n     * PreconditionFailed\n     * 412\n     */\n    public function testGetObjectIfNoneMatchFalse() {\n        try {\n            $this->cosClient->upload($this->bucket, '你好.txt', 'Hello World');\n            $this->cosClient->getObject(array(\n                'Bucket' => $this->bucket,\n                'Key' => '你好.txt',\n                'IfNoneMatch' => '\"\"'));\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n    /*\n     * 获取文件url\n     * 200\n     */\n    public function testGetObjectUrl() {\n        try{\n            $this->cosClient->getObjectUrl($this->bucket, 'hello.txt', '+10 minutes');\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n    /*\n     * 复制小文件\n     * 200\n     */\n    public function testCopySmallObject() {\n        try{\n            $this->cosClient->upload($this->bucket, '你好.txt', 'Hello World');\n            $this->cosClient->copy($bucket=$this->bucket,\n                                   $key='hi.txt', \n                                   $copySource = ['Bucket'=>$this->bucket,\n                                                  'Region'=>$this->region,\n                                                  'Key'=>'你好.txt']);\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n    /*\n     * 复制大文件\n     * 200\n     */\n    public function testCopyLargeObject() {\n        try{\n            $src_key = '你好.txt';\n            $dst_key = 'hi.txt';\n            $body = $this->generateRandomString(2*1024*1024+333);\n            $md5 = base64_encode(md5($body, true));\n            $this->cosClient->upload($bucket=$this->bucket,\n                                     $key=$src_key,\n                                     $body=$body,\n                                     $options=['PartSize'=>1024 * 1024 + 1]);\n            $this->cosClient->copy($bucket=$this->bucket,\n                                   $key=$dst_key, \n                                   $copySource = ['Bucket'=>$this->bucket,\n                                                  'Region'=>$this->region,\n                                                  'Key'=>$src_key],\n                                   $options=['PartSize'=>1024 * 1024 + 1]);\n            \n            $rt = $this->cosClient->getObject(['Bucket'=>$this->bucket, 'Key'=>$dst_key]);\n            $download_md5 = base64_encode(md5($rt['Body'], true));\n            $this->assertEquals($md5, $download_md5);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n    /*\n     * 设置objectacl\n     * 200\n     */\n    public function testPutObjectACL() {\n        try {\n            $this->cosClient->upload($this->bucket, '11', 'hello.txt');\n            $this->cosClient->PutObjectAcl(\n                    array(\n                    'Bucket' => $this->bucket,\n                    'Key' => '11',\n                    'Grants' => array(\n                        array(\n                            'Grantee' => array(\n                                'DisplayName' => 'qcs::cam::uin/2779643970:uin/2779643970',\n                                'ID' => 'qcs::cam::uin/2779643970:uin/2779643970',\n                                'Type' => 'CanonicalUser',\n                            ),\n                            'Permission' => 'FULL_CONTROL',\n                        ),\n                        // ... repeated\n                    ),\n                    'Owner' => array(\n                        'DisplayName' => 'qcs::cam::uin/2779643970:uin/2779643970',\n                        'ID' => 'qcs::cam::uin/2779643970:uin/2779643970',\n                    )\n                )\n            );\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n\n    }\n\n\n    /*\n     * 获取objectacl\n     * 200\n     */\n    public function testGetObjectACL()\n    {\n        try {\n            $this->cosClient->upload($this->bucket, '11', 'hello.txt');\n            $this->cosClient->PutObjectAcl(\n                array(\n                    'Bucket' => $this->bucket,\n                    'Key' => '11',\n                    'Grants' => array(\n                        array(\n                            'Grantee' => array(\n                                'DisplayName' => 'qcs::cam::uin/2779643970:uin/2779643970',\n                                'ID' => 'qcs::cam::uin/2779643970:uin/2779643970',\n                                'Type' => 'CanonicalUser',\n                            ),\n                            'Permission' => 'FULL_CONTROL',\n                        ),\n                    ),\n                    'Owner' => array(\n                        'DisplayName' => 'qcs::cam::uin/2779643970:uin/2779643970',\n                        'ID' => 'qcs::cam::uin/2779643970:uin/2779643970',\n                    )\n                )\n            );\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n    /*\n        * put object acl，设置object公共权限为private\n        * 200\n        */\n    public function testPutObjectAclPrivate()\n    {\n        try {\n            $this->cosClient->putObject(array('Bucket' => $this->bucket,'Key' => '你好.txt', 'Body' => '123'));\n            $this->cosClient->PutObjectAcl(\n                array(\n                    'Bucket' => $this->bucket,\n                    'Key' => '你好.txt',\n                    'ACL'=>'private'\n                )\n            );\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n    /*\n     * put object acl，设置object公共权限为public-read\n     * 200\n     */\n    public function testPutObjectAclPublicRead()\n    {\n        try {\n            $this->cosClient->putObject(array('Bucket' => $this->bucket,'Key' => '你好.txt', 'Body' => '123'));\n            $this->cosClient->PutObjectAcl(\n                array(\n                    'Bucket' => $this->bucket,\n                    'Key' => '你好.txt',\n                    'ACL'=>'public-read'\n                )\n            );\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n    /*\n     * put object acl，公共权限非法\n     * InvalidArgument\n     * 400\n     */\n    public function testPutObjectAclInvalid()\n    {\n        try {\n            $this->cosClient->putObject(array('Bucket' => $this->bucket,'Key' => '你好.txt', 'Body' => '123'));\n            $this->cosClient->PutObjectAcl(\n                array(\n                    'Bucket' => $this->bucket,\n                    'Key' => '你好.txt',\n                    'ACL'=>'public'\n                )\n            );\n            $this->assertTrue(False);\n        } catch (ServiceResponseException $e) {\n            $this->assertTrue($e->getExceptionCode() === 'InvalidArgument' && $e->getStatusCode() === 400);\n        }\n    }\n\n    /*\n     * put object acl，设置object账号权限为grant-read\n     * 200\n     */\n    public function testPutObjectAclReadToUser()\n    {\n        try {\n            $this->cosClient->putObject(array('Bucket' => $this->bucket,'Key' => '你好.txt', 'Body' => '123'));\n            $this->cosClient->PutObjectAcl(\n                array(\n                    'Bucket' =>  $this->bucket,\n                    'Key' => '你好.txt',\n                    'GrantRead' => 'id=\"qcs::cam::uin/2779643970:uin/2779643970\"'\n                )\n            );\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n    /*\n     * put object acl，设置object账号权限为grant-full-control\n     * 200\n     */\n    public function testPutObjectAclFullToUser()\n    {\n        try {\n            $this->cosClient->putObject(array('Bucket' => $this->bucket,'Key' => '你好.txt', 'Body' => '123'));\n            $this->cosClient->PutObjectAcl(\n                array(\n                    'Bucket' =>  $this->bucket,\n                    'Key' => '你好.txt',\n                    'GrantFullControl' => 'id=\"qcs::cam::uin/2779643970:uin/2779643970\"'\n                )\n            );\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n    /*\n     * put object acl，设置object账号权限，同时授权给多个账户\n     * 200\n     */\n    public function testPutObjectAclToUsers()\n    {\n        try {\n            $this->cosClient->putObject(array('Bucket' => $this->bucket,'Key' => '你好.txt', 'Body' => '123'));\n            $this->cosClient->PutObjectAcl(\n                array(\n                    'Bucket' =>  $this->bucket,\n                    'Key' => '你好.txt',\n                    'GrantFullControl' => 'id=\"qcs::cam::uin/2779643970:uin/2779643970\",id=\"qcs::cam::uin/2779643970:uin/2779643970\",id=\"qcs::cam::uin/2779643970:uin/2779643970\"'\n                )\n            );\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n    /*\n     * put object acl，设置object账号权限，授权给子账号\n     * 200\n     */\n    public function testPutObjectAclToSubuser()\n    {\n        try {\n            $this->cosClient->putObject(array('Bucket' => $this->bucket,'Key' => '你好.txt', 'Body' => '123'));\n            $this->cosClient->PutObjectAcl(\n                array(\n                    'Bucket' =>  $this->bucket,\n                    'Key' => '你好.txt',\n                    'GrantFullControl' => 'id=\"qcs::cam::uin/2779643970:uin/2779643970\"'\n                )\n            );\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n    /*\n     * put object acl，设置object账号权限，grant值非法\n     * InvalidArgument\n     * 400\n     */\n    public function testPutObjectAclInvalidGrant()\n    {\n        try {\n            $this->cosClient->putObject(array('Bucket' => $this->bucket,'Key' => '你好.txt', 'Body' => '123'));\n            $this->cosClient->PutObjectAcl(\n                array(\n                    'Bucket' =>  $this->bucket,\n                    'Key' => '你好.txt',\n                    'GrantFullControl' => 'id=\"qcs::camuin/321023:uin/2779643970\"'\n                )\n            );\n            $this->assertTrue(False);\n        } catch (ServiceResponseException $e) {\n            $this->assertTrue($e->getExceptionCode() === 'InvalidArgument' && $e->getStatusCode() === 400);\n        }\n    }\n\n    /*\n     * put object acl，设置object账号权限，通过body方式授权\n     * 200\n     */\n    public function testPutObjectAclByBody()\n    {\n        try {\n            $this->cosClient->putObject(array('Bucket' => $this->bucket,'Key' => '你好.txt', 'Body' => '123'));\n            $this->cosClient->PutObjectAcl(\n                array(\n                    'Bucket' => $this->bucket,\n                    'Key' => '你好.txt',\n                    'Grants' => array(\n                        array(\n                            'Grantee' => array(\n                                'DisplayName' => 'qcs::cam::uin/2779643970:uin/2779643970',\n                                'ID' => 'qcs::cam::uin/2779643970:uin/2779643970',\n                                'Type' => 'CanonicalUser',\n                            ),\n                            'Permission' => 'FULL_CONTROL',\n                        ),\n                        // ... repeated\n                    ),\n                    'Owner' => array(\n                        'DisplayName' => 'qcs::cam::uin/2779643970:uin/2779643970',\n                        'ID' => 'qcs::cam::uin/2779643970:uin/2779643970',\n                    )\n                )\n            );\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n    /*\n     * put object acl，设置object账号权限，通过body方式授权给anyone\n     * 200\n     */\n    public function testPutObjectAclByBodyToAnyone()\n    {\n        try {\n            $this->cosClient->putObject(array('Bucket' => $this->bucket,'Key' => '你好.txt', 'Body' => '123'));\n            $this->cosClient->putObjectAcl(\n                array(\n                    'Bucket' => $this->bucket,\n                    'Key' => '你好.txt',\n                    'Grants' => array(\n                        array(\n                            'Grantee' => array(\n                                'DisplayName' => 'qcs::cam::anyone:anyone',\n                                'ID' => 'qcs::cam::anyone:anyone',\n                                'Type' => 'CanonicalUser',\n                            ),\n                            'Permission' => 'FULL_CONTROL',\n                        ),\n                        // ... repeated\n                    ),\n                    'Owner' => array(\n                        'DisplayName' => 'qcs::cam::uin/2779643970:uin/2779643970',\n                        'ID' => 'qcs::cam::uin/2779643970:uin/2779643970',\n                    )\n                )\n            );\n            $this->assertTrue(True);\n        } catch (ServiceResponseException $e) {\n            print $e;\n            $this->assertFalse(TRUE);\n        }\n    }\n\n    /*\n    * selectobject，select检索数据\n    * 200\n    */\n    public function testSelectObjectContent()\n    {\n        $key = '你好.txt';\n        try {\n            $body = \"appid,bucket,region\n12500001,22weqwe,sh\n12500002,we2qwe,sh\n12500003,weq3we,sh\n12500004,weqw4e,sh\n3278522,azxc,gz\n4343,ewqew,tj\";\n            $this->cosClient->putObject(array('Bucket' => $this->bucket,'Key' => $key, 'Body' => $body));\n            $result = $this->cosClient->selectObjectContent(array(\n                        'Bucket' => $this->bucket, //格式：BucketName-APPID\n                        'Key' => $key,\n                        'Expression' => 'Select * from COSObject s',\n                        'ExpressionType' => 'SQL',\n                        'InputSerialization' => array(\n                            'CompressionType' => 'NONE',\n                            'CSV' => array(\n                                'FileHeaderInfo' => 'USE',\n                                'RecordDelimiter' => '\\n',\n                                'FieldDelimiter' => ',',\n                                'QuoteEscapeCharacter' => '\"',\n                                'Comments' => '#',\n                                'AllowQuotedRecordDelimiter' => 'FALSE'\n                                )   \n                            ),  \n                        'OutputSerialization' => array(\n                            'CSV' => array(\n                                'QuoteField' => 'ASNEEDED',\n                                'RecordDelimiter' => '\\n',\n                                'FieldDelimiter' => ',',\n                                'QuoteCharacter' => '\"',\n                                'QuoteEscapeCharacter' => '\"' \n                                )   \n                            ),  \n                        'RequestProgress' => array(\n                                'Enabled' => 'FALSE'\n                                )   \n                            )); \n            foreach ($result['Data'] as $data) {\n            }\n            $this->assertTrue(True);\n        } catch (\\Exception $e) {\n            print ($e);\n            $this->assertFalse(TRUE);\n        }\n    }\n\n}\n"
  },
  {
    "path": "server/vendor/qcloud/cos-sdk-v5/src/Qcloud/Cos/Tests/TestHelper.php",
    "content": "<?php\n\nnamespace Qcloud\\Cos\\Tests;\n\nuse Qcloud\\Cos\\Client;\n\nclass TestHelper {\n\n    public static function nuke($bucket) {\n        try {\n            $cosClient = new Client(array('region' => getenv('COS_REGION'),\n                        'credentials'=> array(\n                        'secretId'    => getenv('COS_KEY'),\n                        'secretKey' => getenv('COS_SECRET'))));\n            $result = $cosClient->listObjects(array('Bucket' => $bucket));\n            if (isset($result['Contents'])) {\n                foreach ($result['Contents'] as $content) {\n                    $cosClient->deleteObject(array('Bucket' => $bucket, 'Key' => $content['Key']));\n                }\n            }\n\n            while(True){\n                $result = $cosClient->ListMultipartUploads(\n                    array('Bucket' => $bucket));\n                if ($result['Uploads'] == []) {\n                    break;\n                }\n                foreach ($result['Uploads'] as $upload) {\n                    try {\n                        $rt = $cosClient->AbortMultipartUpload(\n                            array('Bucket' => $bucket,\n                                'Key' => $upload['Key'],\n                                'UploadId' => $upload['UploadId']));\n                    } catch (\\Exception $e) {\n                        print_r($e);\n                    }\n                }\n            }        \n            $cosClient->deleteBucket(array('Bucket' => $bucket));\n        } catch (\\Exception $e) {\n            // echo \"$e\\n\";\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/ralouphie/getallheaders/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2014 Ralph Khattar\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "server/vendor/ralouphie/getallheaders/README.md",
    "content": "getallheaders\n=============\n\nPHP `getallheaders()` polyfill. Compatible with PHP >= 5.3.\n\n[![Build Status](https://travis-ci.org/ralouphie/getallheaders.svg?branch=master)](https://travis-ci.org/ralouphie/getallheaders)\n[![Coverage Status](https://coveralls.io/repos/ralouphie/getallheaders/badge.png?branch=master)](https://coveralls.io/r/ralouphie/getallheaders?branch=master)\n[![Latest Stable Version](https://poser.pugx.org/ralouphie/getallheaders/v/stable.png)](https://packagist.org/packages/ralouphie/getallheaders)\n[![Latest Unstable Version](https://poser.pugx.org/ralouphie/getallheaders/v/unstable.png)](https://packagist.org/packages/ralouphie/getallheaders)\n[![License](https://poser.pugx.org/ralouphie/getallheaders/license.png)](https://packagist.org/packages/ralouphie/getallheaders)\n\n\nThis is a simple polyfill for [`getallheaders()`](http://www.php.net/manual/en/function.getallheaders.php).\n\n## Install\n\nFor PHP version **`>= 5.6`**:\n\n```\ncomposer require ralouphie/getallheaders\n```\n\nFor PHP version **`< 5.6`**:\n\n```\ncomposer require ralouphie/getallheaders \"^2\"\n```\n"
  },
  {
    "path": "server/vendor/ralouphie/getallheaders/composer.json",
    "content": "{\n\t\"name\": \"ralouphie/getallheaders\",\n\t\"description\": \"A polyfill for getallheaders.\",\n\t\"license\": \"MIT\",\n\t\"authors\": [\n\t\t{\n\t\t\t\"name\": \"Ralph Khattar\",\n\t\t\t\"email\": \"ralph.khattar@gmail.com\"\n\t\t}\n\t],\n\t\"require\": {\n\t\t\"php\": \">=5.6\"\n\t},\n\t\"require-dev\": {\n\t\t\"phpunit/phpunit\": \"^5 || ^6.5\",\n\t\t\"php-coveralls/php-coveralls\": \"^2.1\"\n\t},\n\t\"autoload\": {\n\t\t\"files\": [\"src/getallheaders.php\"]\n\t},\n\t\"autoload-dev\": {\n\t\t\"psr-4\": {\n\t\t\t\"getallheaders\\\\Tests\\\\\": \"tests/\"\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "server/vendor/ralouphie/getallheaders/src/getallheaders.php",
    "content": "<?php\n\nif (!function_exists('getallheaders')) {\n\n    /**\n     * Get all HTTP header key/values as an associative array for the current request.\n     *\n     * @return string[string] The HTTP header key/value pairs.\n     */\n    function getallheaders()\n    {\n        $headers = array();\n\n        $copy_server = array(\n            'CONTENT_TYPE'   => 'Content-Type',\n            'CONTENT_LENGTH' => 'Content-Length',\n            'CONTENT_MD5'    => 'Content-Md5',\n        );\n\n        foreach ($_SERVER as $key => $value) {\n            if (substr($key, 0, 5) === 'HTTP_') {\n                $key = substr($key, 5);\n                if (!isset($copy_server[$key]) || !isset($_SERVER[$key])) {\n                    $key = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', $key))));\n                    $headers[$key] = $value;\n                }\n            } elseif (isset($copy_server[$key])) {\n                $headers[$copy_server[$key]] = $value;\n            }\n        }\n\n        if (!isset($headers['Authorization'])) {\n            if (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])) {\n                $headers['Authorization'] = $_SERVER['REDIRECT_HTTP_AUTHORIZATION'];\n            } elseif (isset($_SERVER['PHP_AUTH_USER'])) {\n                $basic_pass = isset($_SERVER['PHP_AUTH_PW']) ? $_SERVER['PHP_AUTH_PW'] : '';\n                $headers['Authorization'] = 'Basic ' . base64_encode($_SERVER['PHP_AUTH_USER'] . ':' . $basic_pass);\n            } elseif (isset($_SERVER['PHP_AUTH_DIGEST'])) {\n                $headers['Authorization'] = $_SERVER['PHP_AUTH_DIGEST'];\n            }\n        }\n\n        return $headers;\n    }\n\n}\n"
  },
  {
    "path": "server/vendor/slim/psr7/LICENSE.md",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2015 Slim Framework\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n"
  },
  {
    "path": "server/vendor/slim/psr7/MAINTAINERS.md",
    "content": "# Maintainers\n\nThere aren't many rules for maintainers of Slim-Psr7 to remember; what we have is listed here.\n\n## We don't merge our own PRs\n\nOur code is better if more than one set of eyes looks at it. Therefore we do not merge our own pull requests unless there is an exceptional circumstance. This helps to spot errors in the patch and also enables us to share information about the project around the maintainer team.\n\n## PRs tagged `[WIP]` are not ready to be merged\n\nSometimes it's helpful to collaborate on a patch before it's ready to be merged. We use the `[WIP]` tag (for _Work in Progress_) in the title to mark these PRs. \n\nIf a PR has `[WIP]` in its title, then it is not to be merged. The person who raised the PR will remove the `[WIP]` tag when they are ready for a full review and merge.\n\n## Assign a merged PR to a milestone\n\nBy ensuring that all merged PRs are assigned to a milestone, we can easily find which PRs were in which release.\n"
  },
  {
    "path": "server/vendor/slim/psr7/composer.json",
    "content": "{\n  \"name\": \"slim/psr7\",\n  \"type\": \"library\",\n  \"description\": \"Strict PSR-7 implementation\",\n  \"keywords\": [\"psr7\",\"psr-7\",\"http\"],\n  \"homepage\": \"https://www.slimframework.com\",\n  \"license\": \"MIT\",\n  \"authors\": [\n    {\n      \"name\": \"Josh Lockhart\",\n      \"email\": \"hello@joshlockhart.com\",\n      \"homepage\": \"http://joshlockhart.com\"\n    },\n    {\n      \"name\": \"Andrew Smith\",\n      \"email\": \"a.smith@silentworks.co.uk\",\n      \"homepage\": \"http://silentworks.co.uk\"\n    },\n    {\n      \"name\": \"Rob Allen\",\n      \"email\": \"rob@akrabat.com\",\n      \"homepage\": \"http://akrabat.com\"\n    },\n    {\n      \"name\": \"Pierre Berube\",\n      \"email\": \"pierre@lgse.com\",\n      \"homepage\": \"http://www.lgse.com\"\n    }\n  ],\n  \"require\": {\n    \"php\": \"^7.4 || ^8.0\",\n    \"fig/http-message-util\": \"^1.1.5\",\n    \"psr/http-factory\": \"^1.0\",\n    \"psr/http-message\": \"^1.0\",\n    \"ralouphie/getallheaders\": \"^3.0\",\n    \"symfony/polyfill-php80\": \"^1.26\"\n  },\n  \"require-dev\": {\n    \"ext-json\": \"*\",\n    \"adriansuter/php-autoload-override\": \"^1.3\",\n    \"http-interop/http-factory-tests\": \"^1.0 || ^2.0\",\n    \"php-http/psr7-integration-tests\": \"^1.4\",\n    \"phpspec/prophecy\": \"^1.15\",\n    \"phpspec/prophecy-phpunit\": \"^2.0\",\n    \"phpstan/phpstan\": \"^1.8\",\n    \"phpunit/phpunit\": \"^9.5 || ^10\",\n    \"squizlabs/php_codesniffer\": \"^3.7\"\n  },\n  \"provide\": {\n    \"psr/http-message-implementation\": \"1.0\",\n    \"psr/http-factory-implementation\": \"1.0\"\n  },\n  \"autoload\": {\n    \"psr-4\": {\n      \"Slim\\\\Psr7\\\\\": \"src\"\n    }\n  },\n  \"autoload-dev\": {\n    \"psr-4\": {\n      \"Slim\\\\Tests\\\\Psr7\\\\\": \"tests\"\n    }\n  },\n  \"scripts\": {\n    \"test\": [\n      \"@phpunit\",\n      \"@phpcs\",\n      \"@phpstan\"\n    ],\n    \"phpunit\": \"phpunit\",\n    \"phpcs\": \"phpcs\",\n    \"phpstan\": \"phpstan --memory-limit=-1\"\n  },\n  \"config\": {\n    \"sort-packages\": true\n  }\n}\n"
  },
  {
    "path": "server/vendor/slim/psr7/src/Cookies.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim-Psr7/blob/master/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Psr7;\n\nuse InvalidArgumentException;\n\nuse function array_key_exists;\nuse function array_replace;\nuse function count;\nuse function explode;\nuse function gmdate;\nuse function in_array;\nuse function is_array;\nuse function is_string;\nuse function preg_split;\nuse function rtrim;\nuse function strtolower;\nuse function strtotime;\nuse function urldecode;\nuse function urlencode;\n\nclass Cookies\n{\n    /**\n     * Cookies from HTTP request\n     */\n    protected array $requestCookies = [];\n\n    /**\n     * Cookies for HTTP response\n     */\n    protected array $responseCookies = [];\n\n    /**\n     * Default cookie properties\n     */\n    protected array $defaults = [\n        'value' => '',\n        'domain' => null,\n        'hostonly' => null,\n        'path' => null,\n        'expires' => null,\n        'secure' => false,\n        'httponly' => false,\n        'samesite' => null\n    ];\n\n    /**\n     * @param array $cookies\n     */\n    public function __construct(array $cookies = [])\n    {\n        $this->requestCookies = $cookies;\n    }\n\n    /**\n     * Set default cookie properties\n     *\n     * @param array $settings\n     *\n     * @return static\n     */\n    public function setDefaults(array $settings): self\n    {\n        $this->defaults = array_replace($this->defaults, $settings);\n\n        return $this;\n    }\n\n    /**\n     * Get cookie\n     *\n     * @param string            $name\n     * @param string|array|null $default\n     * @return mixed|null\n     */\n    public function get(string $name, $default = null)\n    {\n        return array_key_exists($name, $this->requestCookies) ? $this->requestCookies[$name] : $default;\n    }\n\n    /**\n     * Set cookie\n     *\n     * @param string       $name\n     * @param string|array $value\n     * @return static\n     */\n    public function set(string $name, $value): self\n    {\n        if (!is_array($value)) {\n            $value = ['value' => $value];\n        }\n\n        $this->responseCookies[$name] = array_replace($this->defaults, $value);\n\n        return $this;\n    }\n\n    /**\n     * Convert all response cookies into an associate array of header values\n     *\n     * @return array\n     */\n    public function toHeaders(): array\n    {\n        $headers = [];\n\n        foreach ($this->responseCookies as $name => $properties) {\n            $headers[] = $this->toHeader($name, $properties);\n        }\n\n        return $headers;\n    }\n\n    /**\n     * Convert to `Set-Cookie` header\n     *\n     * @param  string $name       Cookie name\n     * @param  array  $properties Cookie properties\n     *\n     * @return string\n     */\n    protected function toHeader(string $name, array $properties): string\n    {\n        $result = urlencode($name) . '=' . urlencode($properties['value']);\n\n        if (isset($properties['domain'])) {\n            $result .= '; domain=' . $properties['domain'];\n        }\n\n        if (isset($properties['path'])) {\n            $result .= '; path=' . $properties['path'];\n        }\n\n        if (isset($properties['expires'])) {\n            if (is_string($properties['expires'])) {\n                $timestamp = strtotime($properties['expires']);\n            } else {\n                $timestamp = (int) $properties['expires'];\n            }\n            if ($timestamp && $timestamp !== 0) {\n                $result .= '; expires=' . gmdate('D, d-M-Y H:i:s e', $timestamp);\n            }\n        }\n\n        if (isset($properties['secure']) && $properties['secure']) {\n            $result .= '; secure';\n        }\n\n        if (isset($properties['hostonly']) && $properties['hostonly']) {\n            $result .= '; HostOnly';\n        }\n\n        if (isset($properties['httponly']) && $properties['httponly']) {\n            $result .= '; HttpOnly';\n        }\n\n        if (\n            isset($properties['samesite'])\n            && in_array(strtolower($properties['samesite']), ['lax', 'strict', 'none'], true)\n        ) {\n            // While strtolower is needed for correct comparison, the RFC doesn't care about case\n            $result .= '; SameSite=' . $properties['samesite'];\n        }\n\n        return $result;\n    }\n\n    /**\n     * Parse cookie values from header value\n     *\n     * Returns an associative array of cookie names and values\n     *\n     * @param string|array $header\n     *\n     * @return array\n     */\n    public static function parseHeader($header): array\n    {\n        if (is_array($header)) {\n            $header = $header[0] ?? '';\n        }\n\n        if (!is_string($header)) {\n            throw new InvalidArgumentException('Cannot parse Cookie data. Header value must be a string.');\n        }\n\n        $header = rtrim($header, \"\\r\\n\");\n        $pieces = preg_split('@[;]\\s*@', $header);\n        $cookies = [];\n\n        if (is_array($pieces)) {\n            foreach ($pieces as $cookie) {\n                $cookie = explode('=', $cookie, 2);\n\n                if (count($cookie) === 2) {\n                    $key = urldecode($cookie[0]);\n                    $value = urldecode($cookie[1]);\n\n                    if (!isset($cookies[$key])) {\n                        $cookies[$key] = $value;\n                    }\n                }\n            }\n        }\n\n        return $cookies;\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/psr7/src/Environment.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim-Psr7/blob/master/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Psr7;\n\nuse function array_merge;\nuse function microtime;\nuse function time;\n\nclass Environment\n{\n    /**\n     * @param  array $data Array of custom environment keys and values\n     *\n     * @return array\n     */\n    public static function mock(array $data = []): array\n    {\n        if (\n            (isset($data['HTTPS']) && $data['HTTPS'] !== 'off')\n            || ((isset($data['REQUEST_SCHEME']) && $data['REQUEST_SCHEME'] === 'https'))\n        ) {\n            $scheme = 'https';\n            $port = 443;\n        } else {\n            $scheme = 'http';\n            $port = 80;\n        }\n\n        return array_merge([\n            'HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',\n            'HTTP_ACCEPT_CHARSET' => 'ISO-8859-1,utf-8;q=0.7,*;q=0.3',\n            'HTTP_ACCEPT_LANGUAGE' => 'en-US,en;q=0.8',\n            'HTTP_USER_AGENT' => 'Slim Framework',\n            'QUERY_STRING' => '',\n            'REMOTE_ADDR' => '127.0.0.1',\n            'REQUEST_METHOD' => 'GET',\n            'REQUEST_SCHEME' => $scheme,\n            'REQUEST_TIME' => time(),\n            'REQUEST_TIME_FLOAT' => microtime(true),\n            'REQUEST_URI' => '',\n            'SCRIPT_NAME' => '',\n            'SERVER_NAME' => 'localhost',\n            'SERVER_PORT' => $port,\n            'SERVER_PROTOCOL' => 'HTTP/1.1',\n        ], $data);\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/psr7/src/Factory/RequestFactory.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim-Psr7/blob/master/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Psr7\\Factory;\n\nuse InvalidArgumentException;\nuse Psr\\Http\\Message\\RequestFactoryInterface;\nuse Psr\\Http\\Message\\RequestInterface;\nuse Psr\\Http\\Message\\StreamFactoryInterface;\nuse Psr\\Http\\Message\\UriFactoryInterface;\nuse Psr\\Http\\Message\\UriInterface;\nuse Slim\\Psr7\\Headers;\nuse Slim\\Psr7\\Request;\n\nuse function is_string;\n\nclass RequestFactory implements RequestFactoryInterface\n{\n    protected StreamFactoryInterface $streamFactory;\n\n    protected UriFactoryInterface $uriFactory;\n\n    /**\n     * @param StreamFactoryInterface|null $streamFactory\n     * @param UriFactoryInterface|null    $uriFactory\n     */\n    public function __construct(?StreamFactoryInterface $streamFactory = null, ?UriFactoryInterface $uriFactory = null)\n    {\n        $this->streamFactory = $streamFactory ?? new StreamFactory();\n        $this->uriFactory = $uriFactory ?? new UriFactory();\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function createRequest(string $method, $uri): RequestInterface\n    {\n        if (is_string($uri)) {\n            $uri = $this->uriFactory->createUri($uri);\n        }\n\n        if (!$uri instanceof UriInterface) {\n            throw new InvalidArgumentException(\n                'Parameter 2 of RequestFactory::createRequest() must be a string or a compatible UriInterface.'\n            );\n        }\n\n        $body = $this->streamFactory->createStream();\n\n        return new Request($method, $uri, new Headers(), [], [], $body);\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/psr7/src/Factory/ResponseFactory.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim-Psr7/blob/master/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Psr7\\Factory;\n\nuse Fig\\Http\\Message\\StatusCodeInterface;\nuse Psr\\Http\\Message\\ResponseFactoryInterface;\nuse Psr\\Http\\Message\\ResponseInterface;\nuse Slim\\Psr7\\Response;\n\nclass ResponseFactory implements ResponseFactoryInterface\n{\n    /**\n     * {@inheritdoc}\n     */\n    public function createResponse(\n        int $code = StatusCodeInterface::STATUS_OK,\n        string $reasonPhrase = ''\n    ): ResponseInterface {\n        $res = new Response($code);\n\n        if ($reasonPhrase !== '') {\n            $res = $res->withStatus($code, $reasonPhrase);\n        }\n\n        return $res;\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/psr7/src/Factory/ServerRequestFactory.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim-Psr7/blob/master/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Psr7\\Factory;\n\nuse InvalidArgumentException;\nuse Psr\\Http\\Message\\ServerRequestFactoryInterface;\nuse Psr\\Http\\Message\\ServerRequestInterface;\nuse Psr\\Http\\Message\\StreamFactoryInterface;\nuse Psr\\Http\\Message\\UriFactoryInterface;\nuse Psr\\Http\\Message\\UriInterface;\nuse Slim\\Psr7\\Cookies;\nuse Slim\\Psr7\\Headers;\nuse Slim\\Psr7\\Request;\nuse Slim\\Psr7\\Stream;\nuse Slim\\Psr7\\UploadedFile;\n\nuse function current;\nuse function explode;\nuse function fopen;\nuse function in_array;\nuse function is_string;\n\nclass ServerRequestFactory implements ServerRequestFactoryInterface\n{\n    protected StreamFactoryInterface $streamFactory;\n\n    protected UriFactoryInterface $uriFactory;\n\n    /**\n     * @param StreamFactoryInterface|null $streamFactory\n     * @param UriFactoryInterface|null    $uriFactory\n     */\n    public function __construct(?StreamFactoryInterface $streamFactory = null, ?UriFactoryInterface $uriFactory = null)\n    {\n        $this->streamFactory = $streamFactory ?? new StreamFactory();\n        $this->uriFactory = $uriFactory ?? new UriFactory();\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function createServerRequest(string $method, $uri, array $serverParams = []): ServerRequestInterface\n    {\n        if (is_string($uri)) {\n            $uri = $this->uriFactory->createUri($uri);\n        }\n\n        if (!$uri instanceof UriInterface) {\n            throw new InvalidArgumentException('URI must either be string or instance of ' . UriInterface::class);\n        }\n\n        $body = $this->streamFactory->createStream();\n        $headers = new Headers();\n        $cookies = [];\n\n        if (!empty($serverParams)) {\n            $headers = Headers::createFromGlobals();\n            $cookies = Cookies::parseHeader($headers->getHeader('Cookie', []));\n        }\n\n        return new Request($method, $uri, $headers, $cookies, $serverParams, $body);\n    }\n\n    /**\n     * Create new ServerRequest from environment.\n     *\n     * @internal This method is not part of PSR-17\n     *\n     * @return Request\n     */\n    public static function createFromGlobals(): Request\n    {\n        $method = $_SERVER['REQUEST_METHOD'] ?? 'GET';\n        $uri = (new UriFactory())->createFromGlobals($_SERVER);\n\n        $headers = Headers::createFromGlobals();\n        $cookies = Cookies::parseHeader($headers->getHeader('Cookie', []));\n\n        // Cache the php://input stream as it cannot be re-read\n        $cacheResource = fopen('php://temp', 'wb+');\n        $cache = $cacheResource ? new Stream($cacheResource) : null;\n\n        $body = (new StreamFactory())->createStreamFromFile('php://input', 'r', $cache);\n        $uploadedFiles = UploadedFile::createFromGlobals($_SERVER);\n\n        $request = new Request($method, $uri, $headers, $cookies, $_SERVER, $body, $uploadedFiles);\n        $contentTypes = $request->getHeader('Content-Type');\n\n        $parsedContentType = '';\n        foreach ($contentTypes as $contentType) {\n            $fragments = explode(';', $contentType);\n            $parsedContentType = current($fragments);\n        }\n\n        $contentTypesWithParsedBodies = ['application/x-www-form-urlencoded', 'multipart/form-data'];\n        if ($method === 'POST' && in_array($parsedContentType, $contentTypesWithParsedBodies)) {\n            return $request->withParsedBody($_POST);\n        }\n\n        return $request;\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/psr7/src/Factory/StreamFactory.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim-Psr7/blob/master/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Psr7\\Factory;\n\nuse InvalidArgumentException;\nuse Psr\\Http\\Message\\StreamFactoryInterface;\nuse Psr\\Http\\Message\\StreamInterface;\nuse RuntimeException;\nuse Slim\\Psr7\\Stream;\nuse ValueError;\n\nuse function fopen;\nuse function fwrite;\nuse function is_resource;\nuse function restore_error_handler;\nuse function rewind;\nuse function set_error_handler;\n\nclass StreamFactory implements StreamFactoryInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @throws RuntimeException\n     */\n    public function createStream(string $content = ''): StreamInterface\n    {\n        $resource = fopen('php://temp', 'rw+');\n\n        if (!is_resource($resource)) {\n            throw new RuntimeException('StreamFactory::createStream() could not open temporary file stream.');\n        }\n\n        fwrite($resource, $content);\n        rewind($resource);\n\n        return $this->createStreamFromResource($resource);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function createStreamFromFile(\n        string $filename,\n        string $mode = 'r',\n        ?StreamInterface $cache = null\n    ): StreamInterface {\n        set_error_handler(\n            static function (int $errno, string $errstr) use ($filename, $mode): void {\n                throw new RuntimeException(\n                    \"Unable to open $filename using mode $mode: $errstr\",\n                    $errno\n                );\n            }\n        );\n\n        try {\n            $resource = fopen($filename, $mode);\n        } catch (ValueError $exception) {\n            throw new RuntimeException(\"Unable to open $filename using mode $mode: \" . $exception->getMessage());\n        } finally {\n            restore_error_handler();\n        }\n\n        if (!is_resource($resource)) {\n            throw new RuntimeException(\n                \"StreamFactory::createStreamFromFile() could not create resource from file `$filename`\"\n            );\n        }\n\n        return new Stream($resource, $cache);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function createStreamFromResource($resource, ?StreamInterface $cache = null): StreamInterface\n    {\n        if (!is_resource($resource)) {\n            throw new InvalidArgumentException(\n                'Parameter 1 of StreamFactory::createStreamFromResource() must be a resource.'\n            );\n        }\n\n        return new Stream($resource, $cache);\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/psr7/src/Factory/UploadedFileFactory.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim-Psr7/blob/master/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Psr7\\Factory;\n\nuse InvalidArgumentException;\nuse Psr\\Http\\Message\\StreamInterface;\nuse Psr\\Http\\Message\\UploadedFileFactoryInterface;\nuse Psr\\Http\\Message\\UploadedFileInterface;\nuse Slim\\Psr7\\UploadedFile;\n\nuse function is_string;\n\nuse const UPLOAD_ERR_OK;\n\nclass UploadedFileFactory implements UploadedFileFactoryInterface\n{\n    /**\n     * {@inheritdoc}\n     */\n    public function createUploadedFile(\n        StreamInterface $stream,\n        ?int $size = null,\n        int $error = UPLOAD_ERR_OK,\n        ?string $clientFilename = null,\n        ?string $clientMediaType = null\n    ): UploadedFileInterface {\n        $file = $stream->getMetadata('uri');\n\n        if (!is_string($file) || !$stream->isReadable()) {\n            throw new InvalidArgumentException('File is not readable.');\n        }\n\n        if ($size === null) {\n            $size = $stream->getSize();\n        }\n\n        return new UploadedFile($stream, $clientFilename, $clientMediaType, $size, $error);\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/psr7/src/Factory/UriFactory.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim-Psr7/blob/master/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Psr7\\Factory;\n\nuse InvalidArgumentException;\nuse Psr\\Http\\Message\\UriFactoryInterface;\nuse Psr\\Http\\Message\\UriInterface;\nuse Slim\\Psr7\\Uri;\n\nuse function count;\nuse function explode;\nuse function parse_url;\nuse function preg_match;\nuse function strpos;\nuse function strstr;\nuse function substr;\n\nuse const PHP_URL_QUERY;\n\nclass UriFactory implements UriFactoryInterface\n{\n    /**\n     * {@inheritdoc}\n     */\n    public function createUri(string $uri = ''): UriInterface\n    {\n        $parts = parse_url($uri);\n\n        if ($parts === false) {\n            throw new InvalidArgumentException('URI cannot be parsed');\n        }\n\n        $scheme = $parts['scheme'] ?? '';\n        $user = $parts['user'] ?? '';\n        $pass = $parts['pass'] ?? '';\n        $host = $parts['host'] ?? '';\n        $port = $parts['port'] ?? null;\n        $path = $parts['path'] ?? '';\n        $query = $parts['query'] ?? '';\n        $fragment = $parts['fragment'] ?? '';\n\n        return new Uri($scheme, $host, $port, $path, $query, $fragment, $user, $pass);\n    }\n\n    /**\n     * Create new Uri from environment.\n     *\n     * @internal This method is not part of PSR-17\n     *\n     * @param array $globals The global server variables.\n     *\n     * @return Uri\n     */\n    public function createFromGlobals(array $globals): Uri\n    {\n        // Scheme\n        $https = $globals['HTTPS'] ?? false;\n        $scheme = !$https || $https === 'off' ? 'http' : 'https';\n\n        // Authority: Username and password\n        $username = $globals['PHP_AUTH_USER'] ?? '';\n        $password = $globals['PHP_AUTH_PW'] ?? '';\n\n        // Authority: Host\n        $host = '';\n        if (isset($globals['HTTP_HOST'])) {\n            $host = $globals['HTTP_HOST'];\n        } elseif (isset($globals['SERVER_NAME'])) {\n            $host = $globals['SERVER_NAME'];\n        }\n\n        // Authority: Port\n        $port = !empty($globals['SERVER_PORT']) ? (int)$globals['SERVER_PORT'] : ($scheme === 'https' ? 443 : 80);\n        if (preg_match('/^(\\[[a-fA-F0-9:.]+])(:\\d+)?\\z/', $host, $matches)) {\n            $host = $matches[1];\n\n            if (isset($matches[2])) {\n                $port = (int) substr($matches[2], 1);\n            }\n        } else {\n            $pos = strpos($host, ':');\n            if ($pos !== false) {\n                $port = (int) substr($host, $pos + 1);\n                $host = strstr($host, ':', true);\n            }\n        }\n\n        // Query string\n        $queryString = $globals['QUERY_STRING'] ?? '';\n\n        // Request URI\n        $requestUri = '';\n        if (isset($globals['REQUEST_URI'])) {\n            $uriFragments = explode('?', $globals['REQUEST_URI']);\n            $requestUri = $uriFragments[0];\n\n            if ($queryString === '' && count($uriFragments) > 1) {\n                $queryString = parse_url('https://www.example.com' . $globals['REQUEST_URI'], PHP_URL_QUERY) ?? '';\n            }\n        }\n\n        // Build Uri and return\n        return new Uri($scheme, $host, $port, $requestUri, $queryString, '', $username, $password);\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/psr7/src/Header.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim-Psr7/blob/master/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Psr7;\n\nuse InvalidArgumentException;\n\nuse function array_merge;\nuse function is_array;\nuse function is_string;\n\nclass Header\n{\n    private string $originalName;\n\n    private string $normalizedName;\n\n    private array $values;\n\n    /**\n     * Header constructor.\n     *\n     * @param string $originalName\n     * @param string $normalizedName\n     * @param array  $values\n     */\n    public function __construct(string $originalName, string $normalizedName, array $values)\n    {\n        $this->originalName = $originalName;\n        $this->normalizedName = $normalizedName;\n        $this->values = $values;\n    }\n\n    /**\n     * @return string\n     */\n    public function getOriginalName(): string\n    {\n        return $this->originalName;\n    }\n\n    /**\n     * @return string\n     */\n    public function getNormalizedName(): string\n    {\n        return $this->normalizedName;\n    }\n\n    /**\n     * @param string $value\n     *\n     * @return self\n     */\n    public function addValue(string $value): self\n    {\n        $this->values[] = $value;\n\n        return $this;\n    }\n\n    /**\n     * @param array|string $values\n     *\n     * @return self\n     */\n    public function addValues($values): self\n    {\n        if (is_string($values)) {\n            return $this->addValue($values);\n        }\n\n        if (!is_array($values)) {\n            throw new InvalidArgumentException('Parameter 1 of Header::addValues() should be a string or an array.');\n        }\n\n        $this->values = array_merge($this->values, $values);\n\n        return $this;\n    }\n\n    /**\n     * @return array\n     */\n    public function getValues(): array\n    {\n        return $this->values;\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/psr7/src/Headers.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim-Psr7/blob/master/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Psr7;\n\nuse InvalidArgumentException;\nuse Slim\\Psr7\\Interfaces\\HeadersInterface;\n\nuse function base64_encode;\nuse function function_exists;\nuse function getallheaders;\nuse function is_array;\nuse function is_numeric;\nuse function is_string;\nuse function preg_match;\nuse function strpos;\nuse function strtolower;\nuse function strtr;\nuse function substr;\nuse function trim;\n\nclass Headers implements HeadersInterface\n{\n    protected array $globals;\n\n    /**\n     * @var Header[]\n     */\n    protected array $headers;\n\n    /**\n     * @param array      $headers\n     * @param array|null $globals\n     */\n    final public function __construct(array $headers = [], ?array $globals = null)\n    {\n        $this->globals = $globals ?? $_SERVER;\n        $this->setHeaders($headers);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function addHeader($name, $value): HeadersInterface\n    {\n        [$values, $originalName, $normalizedName] = $this->prepareHeader($name, $value);\n\n        if (isset($this->headers[$normalizedName])) {\n            $header = $this->headers[$normalizedName];\n            $header->addValues($values);\n        } else {\n            $this->headers[$normalizedName] = new Header($originalName, $normalizedName, $values);\n        }\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function removeHeader(string $name): HeadersInterface\n    {\n        $name = $this->normalizeHeaderName($name);\n        unset($this->headers[$name]);\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getHeader(string $name, $default = []): array\n    {\n        $name = $this->normalizeHeaderName($name);\n\n        if (isset($this->headers[$name])) {\n            $header = $this->headers[$name];\n            return $header->getValues();\n        }\n\n        if (empty($default)) {\n            return $default;\n        }\n\n        $this->validateHeader($name, $default);\n        return $this->trimHeaderValue($default);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function setHeader($name, $value): HeadersInterface\n    {\n        [$values, $originalName, $normalizedName] = $this->prepareHeader($name, $value);\n\n        // Ensure we preserve original case if the header already exists in the stack\n        if (isset($this->headers[$normalizedName])) {\n            $existingHeader = $this->headers[$normalizedName];\n            $originalName = $existingHeader->getOriginalName();\n        }\n\n        $this->headers[$normalizedName] = new Header($originalName, $normalizedName, $values);\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function setHeaders(array $headers): HeadersInterface\n    {\n        $this->headers = [];\n\n        foreach ($this->parseAuthorizationHeader($headers) as $name => $value) {\n            $this->addHeader($name, $value);\n        }\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function hasHeader(string $name): bool\n    {\n        $name = $this->normalizeHeaderName($name);\n        return isset($this->headers[$name]);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getHeaders(bool $originalCase = false): array\n    {\n        $headers = [];\n\n        foreach ($this->headers as $header) {\n            $name = $originalCase ? $header->getOriginalName() : $header->getNormalizedName();\n            $headers[$name] = $header->getValues();\n        }\n\n        return $headers;\n    }\n\n    /**\n     * @param string $name\n     * @param bool   $preserveCase\n     * @return string\n     */\n    protected function normalizeHeaderName(string $name, bool $preserveCase = false): string\n    {\n        $name = strtr($name, '_', '-');\n\n        if (!$preserveCase) {\n            $name = strtolower($name);\n        }\n\n        if (strpos(strtolower($name), 'http-') === 0) {\n            $name = substr($name, 5);\n        }\n\n        return $name;\n    }\n\n    /**\n     * Parse incoming headers and determine Authorization header from original headers\n     *\n     * @param array $headers\n     * @return array\n     */\n    protected function parseAuthorizationHeader(array $headers): array\n    {\n        $hasAuthorizationHeader = false;\n        foreach ($headers as $name => $value) {\n            if (strtolower((string) $name) === 'authorization') {\n                $hasAuthorizationHeader = true;\n                break;\n            }\n        }\n\n        if (!$hasAuthorizationHeader) {\n            if (isset($this->globals['REDIRECT_HTTP_AUTHORIZATION'])) {\n                $headers['Authorization'] = $this->globals['REDIRECT_HTTP_AUTHORIZATION'];\n            } elseif (isset($this->globals['PHP_AUTH_USER'])) {\n                $pw = $this->globals['PHP_AUTH_PW'] ?? '';\n                $headers['Authorization'] = 'Basic ' . base64_encode($this->globals['PHP_AUTH_USER'] . ':' . $pw);\n            } elseif (isset($this->globals['PHP_AUTH_DIGEST'])) {\n                $headers['Authorization'] = $this->globals['PHP_AUTH_DIGEST'];\n            }\n        }\n\n        return $headers;\n    }\n\n    /**\n     * @param array|string $value\n     *\n     * @return array\n     */\n    protected function trimHeaderValue($value): array\n    {\n        $items = is_array($value) ? $value : [$value];\n        $result = [];\n        foreach ($items as $item) {\n            $result[] = trim((string) $item, \" \\t\");\n        }\n        return $result;\n    }\n\n    /**\n     * @param string       $name\n     * @param array|string $value\n     *\n     * @throws InvalidArgumentException\n     *\n     * @return array\n     */\n    protected function prepareHeader($name, $value): array\n    {\n        $this->validateHeader($name, $value);\n        $values = $this->trimHeaderValue($value);\n        $originalName = $this->normalizeHeaderName($name, true);\n        $normalizedName = $this->normalizeHeaderName($name);\n        return [$values, $originalName, $normalizedName];\n    }\n\n    /**\n     * Make sure the header complies with RFC 7230.\n     *\n     * Header names must be a non-empty string consisting of token characters.\n     *\n     * Header values must be strings consisting of visible characters with all optional\n     * leading and trailing whitespace stripped. This method will always strip such\n     * optional whitespace. Note that the method does not allow folding whitespace within\n     * the values as this was deprecated for almost all instances by the RFC.\n     *\n     * header-field = field-name \":\" OWS field-value OWS\n     * field-name   = 1*( \"!\" / \"#\" / \"$\" / \"%\" / \"&\" / \"'\" / \"*\" / \"+\" / \"-\" / \".\" / \"^\"\n     *              / \"_\" / \"`\" / \"|\" / \"~\" / %x30-39 / ( %x41-5A / %x61-7A ) )\n     * OWS          = *( SP / HTAB )\n     * field-value  = *( ( %x21-7E / %x80-FF ) [ 1*( SP / HTAB ) ( %x21-7E / %x80-FF ) ] )\n     *\n     * @see https://tools.ietf.org/html/rfc7230#section-3.2.4\n     *\n     * @param string        $name\n     * @param array|string  $value\n     *\n     * @throws InvalidArgumentException;\n     */\n    protected function validateHeader($name, $value): void\n    {\n        $this->validateHeaderName($name);\n        $this->validateHeaderValue($value);\n    }\n\n    /**\n     * @param mixed $name\n     *\n     * @throws InvalidArgumentException\n     */\n    protected function validateHeaderName($name): void\n    {\n        if (!is_string($name) || preg_match(\"@^[!#$%&'*+.^_`|~0-9A-Za-z-]+$@D\", $name) !== 1) {\n            throw new InvalidArgumentException('Header name must be an RFC 7230 compatible string.');\n        }\n    }\n\n    /**\n     * @param mixed $value\n     *\n     * @throws InvalidArgumentException\n     */\n    protected function validateHeaderValue($value): void\n    {\n        $items = is_array($value) ? $value : [$value];\n\n        if (empty($items)) {\n            throw new InvalidArgumentException(\n                'Header values must be a string or an array of strings, empty array given.'\n            );\n        }\n\n        $pattern = \"@^[ \\t\\x21-\\x7E\\x80-\\xFF]*$@D\";\n        foreach ($items as $item) {\n            $hasInvalidType = !is_numeric($item) && !is_string($item);\n            $rejected = $hasInvalidType || preg_match($pattern, (string) $item) !== 1;\n            if ($rejected) {\n                throw new InvalidArgumentException(\n                    'Header values must be RFC 7230 compatible strings.'\n                );\n            }\n        }\n    }\n\n    /**\n     * @return static\n     */\n    public static function createFromGlobals()\n    {\n        $headers = null;\n\n        if (function_exists('getallheaders')) {\n            $headers = getallheaders();\n        }\n\n        if (!is_array($headers)) {\n            $headers = [];\n        }\n\n        return new static($headers);\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/psr7/src/Interfaces/HeadersInterface.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim-Psr7/blob/master/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Psr7\\Interfaces;\n\nuse InvalidArgumentException;\n\ninterface HeadersInterface\n{\n    /**\n     * Add header value\n     *\n     * This method appends the value to the existing array of values\n     *\n     * @param string       $name\n     * @param array|string $value\n     *\n     * @return HeadersInterface\n     *\n     * @throws InvalidArgumentException\n     */\n    public function addHeader($name, $value): HeadersInterface;\n\n    /**\n     * Remove header value\n     *\n     * @param string $name\n     * @return HeadersInterface\n     */\n    public function removeHeader(string $name): HeadersInterface;\n\n    /**\n     * Get header value or values.\n     * If the array has a single value it will return that single value.\n     * If the array has multiple values, it will return an array of values.\n     *\n     * @param string   $name\n     * @param string[] $default\n     *\n     * @return array\n     */\n    public function getHeader(string $name, $default = []): array;\n\n    /**\n     * Replaces the existing header value with the new value.\n     *\n     * @param string       $name\n     * @param array|string $value\n     *\n     * @return HeadersInterface\n     *\n     * @throws InvalidArgumentException\n     */\n    public function setHeader($name, $value): HeadersInterface;\n\n    /**\n     * Replaces all existing headers with the new values.\n     *\n     * @param array $headers\n     *\n     * @return HeadersInterface\n     *\n     * @throws InvalidArgumentException\n     */\n    public function setHeaders(array $headers): HeadersInterface;\n\n    /**\n     * Is the header present in the stack.\n     *\n     * @param string $name\n     * @return bool\n     */\n    public function hasHeader(string $name): bool;\n\n    /**\n     * Return all headers in the stack.\n     *\n     * @param bool $originalCase\n     *\n     * @return array\n     */\n    public function getHeaders(bool $originalCase): array;\n}\n"
  },
  {
    "path": "server/vendor/slim/psr7/src/Message.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim-Psr7/blob/master/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Psr7;\n\nuse InvalidArgumentException;\nuse Psr\\Http\\Message\\MessageInterface;\nuse Psr\\Http\\Message\\StreamInterface;\nuse Slim\\Psr7\\Interfaces\\HeadersInterface;\n\nuse function array_keys;\nuse function header;\nuse function header_remove;\nuse function implode;\nuse function sprintf;\n\nabstract class Message implements MessageInterface\n{\n    protected string $protocolVersion = '1.1';\n\n    protected static array $validProtocolVersions = [\n        '1.0' => true,\n        '1.1' => true,\n        '2.0' => true,\n        '2' => true,\n    ];\n\n    /**\n     * @var HeadersInterface\n     */\n    protected $headers;\n\n    /**\n     * @var StreamInterface\n     */\n    protected $body;\n\n    /**\n     * Disable magic setter to ensure immutability\n     *\n     * @param string $name  The property name\n     * @param mixed  $value The property value\n     *\n     * @return void\n     */\n    public function __set($name, $value): void\n    {\n        // Do nothing\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getProtocolVersion(): string\n    {\n        return $this->protocolVersion;\n    }\n\n    /**\n     * @return static\n     * {@inheritdoc}\n     */\n    public function withProtocolVersion($version)\n    {\n        if (!isset(self::$validProtocolVersions[$version])) {\n            throw new InvalidArgumentException(\n                'Invalid HTTP version. Must be one of: '\n                . implode(', ', array_keys(self::$validProtocolVersions))\n            );\n        }\n\n        $clone = clone $this;\n        $clone->protocolVersion = $version;\n\n        return $clone;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getHeaders(): array\n    {\n        return $this->headers->getHeaders(true);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function hasHeader($name): bool\n    {\n        return $this->headers->hasHeader($name);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getHeader($name): array\n    {\n        return $this->headers->getHeader($name);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getHeaderLine($name): string\n    {\n        $values = $this->headers->getHeader($name);\n        return implode(',', $values);\n    }\n\n    /**\n     * @return static\n     * {@inheritdoc}\n     */\n    public function withHeader($name, $value)\n    {\n        $clone = clone $this;\n        $clone->headers->setHeader($name, $value);\n\n        if ($this instanceof Response && $this->body instanceof NonBufferedBody) {\n            header(sprintf('%s: %s', $name, $clone->getHeaderLine($name)));\n        }\n\n        return $clone;\n    }\n\n    /**\n     * @return static\n     * {@inheritdoc}\n     */\n    public function withAddedHeader($name, $value)\n    {\n        $clone = clone $this;\n        $clone->headers->addHeader($name, $value);\n\n        if ($this instanceof Response && $this->body instanceof NonBufferedBody) {\n            header(sprintf('%s: %s', $name, $clone->getHeaderLine($name)));\n        }\n\n        return $clone;\n    }\n\n    /**\n     * @return static\n     * {@inheritdoc}\n     */\n    public function withoutHeader($name)\n    {\n        $clone = clone $this;\n        $clone->headers->removeHeader($name);\n\n        if ($this instanceof Response && $this->body instanceof NonBufferedBody) {\n            header_remove($name);\n        }\n\n        return $clone;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getBody(): StreamInterface\n    {\n        return $this->body;\n    }\n\n    /**\n     * @return static\n     * {@inheritdoc}\n     */\n    public function withBody(StreamInterface $body)\n    {\n        $clone = clone $this;\n        $clone->body = $body;\n\n        return $clone;\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/psr7/src/NonBufferedBody.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim-Psr7/blob/master/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Psr7;\n\nuse Psr\\Http\\Message\\StreamInterface;\nuse RuntimeException;\n\nuse function flush;\nuse function ob_get_clean;\nuse function ob_get_level;\nuse function strlen;\n\nuse const SEEK_SET;\n\nclass NonBufferedBody implements StreamInterface\n{\n    /**\n     * {@inheritdoc}\n     */\n    public function __toString(): string\n    {\n        return '';\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function close(): void\n    {\n        throw new RuntimeException('A NonBufferedBody is not closable.');\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function detach()\n    {\n        return null;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getSize(): ?int\n    {\n        return null;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function tell(): int\n    {\n        return 0;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function eof(): bool\n    {\n        return true;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function isSeekable(): bool\n    {\n        return false;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function seek($offset, $whence = SEEK_SET): void\n    {\n        throw new RuntimeException('A NonBufferedBody is not seekable.');\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function rewind(): void\n    {\n        throw new RuntimeException('A NonBufferedBody is not rewindable.');\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function isWritable(): bool\n    {\n        return true;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function write($string): int\n    {\n        $buffered = '';\n        while (0 < ob_get_level()) {\n            $buffered = ob_get_clean() . $buffered;\n        }\n\n        echo $buffered . $string;\n\n        flush();\n\n        return strlen($string) + strlen($buffered);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function isReadable(): bool\n    {\n        return false;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function read($length): string\n    {\n        throw new RuntimeException('A NonBufferedBody is not readable.');\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getContents(): string\n    {\n        return '';\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getMetadata($key = null): ?array\n    {\n        return null;\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/psr7/src/Request.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim-Psr7/blob/master/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Psr7;\n\nuse InvalidArgumentException;\nuse Psr\\Http\\Message\\ServerRequestInterface;\nuse Psr\\Http\\Message\\StreamInterface;\nuse Psr\\Http\\Message\\UploadedFileInterface;\nuse Psr\\Http\\Message\\UriInterface;\nuse Slim\\Psr7\\Interfaces\\HeadersInterface;\n\nuse function get_class;\nuse function gettype;\nuse function is_array;\nuse function is_null;\nuse function is_object;\nuse function is_string;\nuse function ltrim;\nuse function parse_str;\nuse function preg_match;\nuse function sprintf;\nuse function str_replace;\n\nclass Request extends Message implements ServerRequestInterface\n{\n    /**\n     * @var string\n     */\n    protected $method;\n\n    /**\n     * @var UriInterface\n     */\n    protected $uri;\n\n    /**\n     * @var string\n     */\n    protected $requestTarget;\n\n    /**\n     * @var ?array\n     */\n    protected $queryParams;\n\n    protected array $cookies;\n\n    protected array $serverParams;\n\n    protected array $attributes;\n\n    /**\n     * @var null|array|object\n     */\n    protected $parsedBody;\n\n    /**\n     * @var UploadedFileInterface[]\n     */\n    protected array $uploadedFiles;\n\n    /**\n     * @param string           $method        The request method\n     * @param UriInterface     $uri           The request URI object\n     * @param HeadersInterface $headers       The request headers collection\n     * @param array            $cookies       The request cookies collection\n     * @param array            $serverParams  The server environment variables\n     * @param StreamInterface  $body          The request body object\n     * @param array            $uploadedFiles The request uploadedFiles collection\n     * @throws InvalidArgumentException on invalid HTTP method\n     */\n    public function __construct(\n        $method,\n        UriInterface $uri,\n        HeadersInterface $headers,\n        array $cookies,\n        array $serverParams,\n        StreamInterface $body,\n        array $uploadedFiles = []\n    ) {\n        $this->method = $this->filterMethod($method);\n        $this->uri = $uri;\n        $this->headers = $headers;\n        $this->cookies = $cookies;\n        $this->serverParams = $serverParams;\n        $this->attributes = [];\n        $this->body = $body;\n        $this->uploadedFiles = $uploadedFiles;\n\n        if (isset($serverParams['SERVER_PROTOCOL'])) {\n            $this->protocolVersion = str_replace('HTTP/', '', $serverParams['SERVER_PROTOCOL']);\n        }\n\n        if (!$this->headers->hasHeader('Host') || $this->uri->getHost() !== '') {\n            $this->headers->setHeader('Host', $this->uri->getHost());\n        }\n    }\n\n    /**\n     * This method is applied to the cloned object after PHP performs an initial shallow-copy.\n     * This method completes a deep-copy by creating new objects for the cloned object's internal reference pointers.\n     */\n    public function __clone()\n    {\n        $this->headers = clone $this->headers;\n        $this->body = clone $this->body;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getMethod(): string\n    {\n        return $this->method;\n    }\n\n    /**\n     * {@inheritdoc}\n     * @return static\n     */\n    public function withMethod($method)\n    {\n        $method = $this->filterMethod($method);\n        $clone = clone $this;\n        $clone->method = $method;\n\n        return $clone;\n    }\n\n    /**\n     * Validate the HTTP method\n     *\n     * @param  string $method\n     *\n     * @return string\n     *\n     * @throws InvalidArgumentException on invalid HTTP method.\n     */\n    protected function filterMethod($method): string\n    {\n        /** @var mixed $method */\n        if (!is_string($method)) {\n            throw new InvalidArgumentException(sprintf(\n                'Unsupported HTTP method; must be a string, received %s',\n                (is_object($method) ? get_class($method) : gettype($method))\n            ));\n        }\n\n        if (preg_match(\"/^[!#$%&'*+.^_`|~0-9a-z-]+$/i\", $method) !== 1) {\n            throw new InvalidArgumentException(sprintf(\n                'Unsupported HTTP method \"%s\" provided',\n                $method\n            ));\n        }\n\n        return $method;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getRequestTarget(): string\n    {\n        if ($this->requestTarget) {\n            return $this->requestTarget;\n        }\n\n        if ($this->uri === null) {\n            return '/';\n        }\n\n        $path = $this->uri->getPath();\n        $path = '/' . ltrim($path, '/');\n\n        $query = $this->uri->getQuery();\n        if ($query) {\n            $path .= '?' . $query;\n        }\n\n        return $path;\n    }\n\n    /**\n     * {@inheritdoc}\n     * @return static\n     */\n    public function withRequestTarget($requestTarget)\n    {\n        if (!is_string($requestTarget) || preg_match('#\\s#', $requestTarget)) {\n            throw new InvalidArgumentException(\n                'Invalid request target provided; must be a string and cannot contain whitespace'\n            );\n        }\n\n        $clone = clone $this;\n        $clone->requestTarget = $requestTarget;\n\n        return $clone;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getUri(): UriInterface\n    {\n        return $this->uri;\n    }\n\n    /**\n     * {@inheritdoc}\n     * @return static\n     */\n    public function withUri(UriInterface $uri, $preserveHost = false)\n    {\n        $clone = clone $this;\n        $clone->uri = $uri;\n\n        if (!$preserveHost && $uri->getHost() !== '') {\n            $clone->headers->setHeader('Host', $uri->getHost());\n            return $clone;\n        }\n\n        if (($uri->getHost() !== '' && !$this->hasHeader('Host') || $this->getHeaderLine('Host') === '')) {\n            $clone->headers->setHeader('Host', $uri->getHost());\n            return $clone;\n        }\n\n        return $clone;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getCookieParams(): array\n    {\n        return $this->cookies;\n    }\n\n    /**\n     * {@inheritdoc}\n     * @return static\n     */\n    public function withCookieParams(array $cookies)\n    {\n        $clone = clone $this;\n        $clone->cookies = $cookies;\n\n        return $clone;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getQueryParams(): array\n    {\n        if (is_array($this->queryParams)) {\n            return $this->queryParams;\n        }\n\n        if ($this->uri === null) {\n            return [];\n        }\n\n        parse_str($this->uri->getQuery(), $this->queryParams); // <-- URL decodes data\n        assert(is_array($this->queryParams));\n\n        return $this->queryParams;\n    }\n\n    /**\n     * {@inheritdoc}\n     * @return static\n     */\n    public function withQueryParams(array $query)\n    {\n        $clone = clone $this;\n        $clone->queryParams = $query;\n\n        return $clone;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getUploadedFiles(): array\n    {\n        return $this->uploadedFiles;\n    }\n\n    /**\n     * {@inheritdoc}\n     * @return static\n     */\n    public function withUploadedFiles(array $uploadedFiles)\n    {\n        $clone = clone $this;\n        $clone->uploadedFiles = $uploadedFiles;\n\n        return $clone;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getServerParams(): array\n    {\n        return $this->serverParams;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getAttributes(): array\n    {\n        return $this->attributes;\n    }\n\n    /**\n     * {@inheritdoc}\n     * @return mixed\n     */\n    public function getAttribute($name, $default = null)\n    {\n        return $this->attributes[$name] ?? $default;\n    }\n\n    /**\n     * {@inheritdoc}\n     * @return static\n     */\n    public function withAttribute($name, $value)\n    {\n        $clone = clone $this;\n        $clone->attributes[$name] = $value;\n\n        return $clone;\n    }\n\n    /**\n     * {@inheritdoc}\n     * @return static\n     */\n    public function withoutAttribute($name)\n    {\n        $clone = clone $this;\n\n        unset($clone->attributes[$name]);\n\n        return $clone;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getParsedBody()\n    {\n        return $this->parsedBody;\n    }\n\n    /**\n     * {@inheritdoc}\n     * @return static\n     */\n    public function withParsedBody($data)\n    {\n        /** @var mixed $data */\n        if (!is_null($data) && !is_object($data) && !is_array($data)) {\n            throw new InvalidArgumentException('Parsed body value must be an array, an object, or null');\n        }\n\n        $clone = clone $this;\n        $clone->parsedBody = $data;\n\n        return $clone;\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/psr7/src/Response.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim-Psr7/blob/master/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Psr7;\n\nuse Fig\\Http\\Message\\StatusCodeInterface;\nuse InvalidArgumentException;\nuse Psr\\Http\\Message\\ResponseInterface;\nuse Psr\\Http\\Message\\StreamInterface;\nuse Slim\\Psr7\\Factory\\StreamFactory;\nuse Slim\\Psr7\\Interfaces\\HeadersInterface;\n\nuse function is_integer;\nuse function is_object;\nuse function is_string;\nuse function method_exists;\n\nclass Response extends Message implements ResponseInterface\n{\n    protected int $status = StatusCodeInterface::STATUS_OK;\n\n    protected string $reasonPhrase = '';\n\n    protected static array $messages = [\n        // Informational 1xx\n        StatusCodeInterface::STATUS_CONTINUE => 'Continue',\n        StatusCodeInterface::STATUS_SWITCHING_PROTOCOLS => 'Switching Protocols',\n        StatusCodeInterface::STATUS_PROCESSING => 'Processing',\n\n        // Successful 2xx\n        StatusCodeInterface::STATUS_OK => 'OK',\n        StatusCodeInterface::STATUS_CREATED => 'Created',\n        StatusCodeInterface::STATUS_ACCEPTED => 'Accepted',\n        StatusCodeInterface::STATUS_NON_AUTHORITATIVE_INFORMATION => 'Non-Authoritative Information',\n        StatusCodeInterface::STATUS_NO_CONTENT => 'No Content',\n        StatusCodeInterface::STATUS_RESET_CONTENT => 'Reset Content',\n        StatusCodeInterface::STATUS_PARTIAL_CONTENT => 'Partial Content',\n        StatusCodeInterface::STATUS_MULTI_STATUS => 'Multi-Status',\n        StatusCodeInterface::STATUS_ALREADY_REPORTED => 'Already Reported',\n        StatusCodeInterface::STATUS_IM_USED => 'IM Used',\n\n        // Redirection 3xx\n        StatusCodeInterface::STATUS_MULTIPLE_CHOICES => 'Multiple Choices',\n        StatusCodeInterface::STATUS_MOVED_PERMANENTLY => 'Moved Permanently',\n        StatusCodeInterface::STATUS_FOUND => 'Found',\n        StatusCodeInterface::STATUS_SEE_OTHER => 'See Other',\n        StatusCodeInterface::STATUS_NOT_MODIFIED => 'Not Modified',\n        StatusCodeInterface::STATUS_USE_PROXY => 'Use Proxy',\n        StatusCodeInterface::STATUS_RESERVED => '(Unused)',\n        StatusCodeInterface::STATUS_TEMPORARY_REDIRECT => 'Temporary Redirect',\n        StatusCodeInterface::STATUS_PERMANENT_REDIRECT => 'Permanent Redirect',\n\n        // Client Error 4xx\n        StatusCodeInterface::STATUS_BAD_REQUEST => 'Bad Request',\n        StatusCodeInterface::STATUS_UNAUTHORIZED => 'Unauthorized',\n        StatusCodeInterface::STATUS_PAYMENT_REQUIRED => 'Payment Required',\n        StatusCodeInterface::STATUS_FORBIDDEN => 'Forbidden',\n        StatusCodeInterface::STATUS_NOT_FOUND => 'Not Found',\n        StatusCodeInterface::STATUS_METHOD_NOT_ALLOWED => 'Method Not Allowed',\n        StatusCodeInterface::STATUS_NOT_ACCEPTABLE => 'Not Acceptable',\n        StatusCodeInterface::STATUS_PROXY_AUTHENTICATION_REQUIRED => 'Proxy Authentication Required',\n        StatusCodeInterface::STATUS_REQUEST_TIMEOUT => 'Request Timeout',\n        StatusCodeInterface::STATUS_CONFLICT => 'Conflict',\n        StatusCodeInterface::STATUS_GONE => 'Gone',\n        StatusCodeInterface::STATUS_LENGTH_REQUIRED => 'Length Required',\n        StatusCodeInterface::STATUS_PRECONDITION_FAILED => 'Precondition Failed',\n        StatusCodeInterface::STATUS_PAYLOAD_TOO_LARGE => 'Request Entity Too Large',\n        StatusCodeInterface::STATUS_URI_TOO_LONG => 'Request-URI Too Long',\n        StatusCodeInterface::STATUS_UNSUPPORTED_MEDIA_TYPE => 'Unsupported Media Type',\n        StatusCodeInterface::STATUS_RANGE_NOT_SATISFIABLE => 'Requested Range Not Satisfiable',\n        StatusCodeInterface::STATUS_EXPECTATION_FAILED => 'Expectation Failed',\n        StatusCodeInterface::STATUS_IM_A_TEAPOT => 'I\\'m a teapot',\n        StatusCodeInterface::STATUS_MISDIRECTED_REQUEST => 'Misdirected Request',\n        StatusCodeInterface::STATUS_UNPROCESSABLE_ENTITY => 'Unprocessable Entity',\n        StatusCodeInterface::STATUS_LOCKED => 'Locked',\n        StatusCodeInterface::STATUS_FAILED_DEPENDENCY => 'Failed Dependency',\n        StatusCodeInterface::STATUS_UPGRADE_REQUIRED => 'Upgrade Required',\n        StatusCodeInterface::STATUS_PRECONDITION_REQUIRED => 'Precondition Required',\n        StatusCodeInterface::STATUS_TOO_MANY_REQUESTS => 'Too Many Requests',\n        StatusCodeInterface::STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE => 'Request Header Fields Too Large',\n        444 => 'Connection Closed Without Response',\n        StatusCodeInterface::STATUS_UNAVAILABLE_FOR_LEGAL_REASONS => 'Unavailable For Legal Reasons',\n        499 => 'Client Closed Request',\n\n        // Server Error 5xx\n        StatusCodeInterface::STATUS_INTERNAL_SERVER_ERROR => 'Internal Server Error',\n        StatusCodeInterface::STATUS_NOT_IMPLEMENTED => 'Not Implemented',\n        StatusCodeInterface::STATUS_BAD_GATEWAY => 'Bad Gateway',\n        StatusCodeInterface::STATUS_SERVICE_UNAVAILABLE => 'Service Unavailable',\n        StatusCodeInterface::STATUS_GATEWAY_TIMEOUT => 'Gateway Timeout',\n        StatusCodeInterface::STATUS_VERSION_NOT_SUPPORTED => 'HTTP Version Not Supported',\n        StatusCodeInterface::STATUS_VARIANT_ALSO_NEGOTIATES => 'Variant Also Negotiates',\n        StatusCodeInterface::STATUS_INSUFFICIENT_STORAGE => 'Insufficient Storage',\n        StatusCodeInterface::STATUS_LOOP_DETECTED => 'Loop Detected',\n        StatusCodeInterface::STATUS_NOT_EXTENDED => 'Not Extended',\n        StatusCodeInterface::STATUS_NETWORK_AUTHENTICATION_REQUIRED => 'Network Authentication Required',\n        599 => 'Network Connect Timeout Error',\n    ];\n\n    /**\n     * @param int                   $status  The response status code.\n     * @param HeadersInterface|null $headers The response headers.\n     * @param StreamInterface|null  $body    The response body.\n     */\n    public function __construct(\n        int $status = StatusCodeInterface::STATUS_OK,\n        ?HeadersInterface $headers = null,\n        ?StreamInterface $body = null\n    ) {\n        $this->status = $this->filterStatus($status);\n        $this->headers = $headers ?: new Headers([], []);\n        $this->body = $body ?: (new StreamFactory())->createStream();\n    }\n\n    /**\n     * This method is applied to the cloned object after PHP performs an initial shallow-copy.\n     * This method completes a deep-copy by creating new objects for the cloned object's internal reference pointers.\n     */\n    public function __clone()\n    {\n        $this->headers = clone $this->headers;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getStatusCode(): int\n    {\n        return $this->status;\n    }\n\n    /**\n     * {@inheritdoc}\n     * @return static\n     */\n    public function withStatus($code, $reasonPhrase = '')\n    {\n        $code = $this->filterStatus($code);\n        $reasonPhrase = $this->filterReasonPhrase($reasonPhrase);\n\n        $clone = clone $this;\n        $clone->status = $code;\n        $clone->reasonPhrase = $reasonPhrase;\n\n        return $clone;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getReasonPhrase(): string\n    {\n        if ($this->reasonPhrase !== '') {\n            return $this->reasonPhrase;\n        }\n\n        if (isset(static::$messages[$this->status])) {\n            return static::$messages[$this->status];\n        }\n\n        return '';\n    }\n\n    /**\n     * Filter HTTP status code.\n     *\n     * @param  int $status HTTP status code.\n     *\n     * @return int\n     *\n     * @throws InvalidArgumentException If an invalid HTTP status code is provided.\n     */\n    protected function filterStatus($status): int\n    {\n        if (!is_integer($status) || $status < StatusCodeInterface::STATUS_CONTINUE || $status > 599) {\n            throw new InvalidArgumentException('Invalid HTTP status code.');\n        }\n\n        return $status;\n    }\n\n    /**\n     * Filter Reason Phrase\n     *\n     * @param mixed $reasonPhrase\n     *\n     * @return string\n     *\n     * @throws InvalidArgumentException\n     */\n    protected function filterReasonPhrase($reasonPhrase = ''): string\n    {\n        if (is_object($reasonPhrase) && method_exists($reasonPhrase, '__toString')) {\n            $reasonPhrase = (string) $reasonPhrase;\n        }\n\n        if (!is_string($reasonPhrase)) {\n            throw new InvalidArgumentException('Response reason phrase must be a string.');\n        }\n\n        if (strpos($reasonPhrase, \"\\r\") !== false || strpos($reasonPhrase, \"\\n\") !== false) {\n            throw new InvalidArgumentException(\n                'Reason phrase contains one of the following prohibited characters: \\r \\n'\n            );\n        }\n\n        return $reasonPhrase;\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/psr7/src/Stream.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim-Psr7/blob/master/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Psr7;\n\nuse InvalidArgumentException;\nuse Psr\\Http\\Message\\StreamInterface;\nuse RuntimeException;\n\nuse function fclose;\nuse function feof;\nuse function fread;\nuse function fseek;\nuse function fstat;\nuse function ftell;\nuse function fwrite;\nuse function is_array;\nuse function is_resource;\nuse function is_string;\nuse function pclose;\nuse function rewind;\nuse function stream_get_contents;\nuse function stream_get_meta_data;\nuse function strstr;\n\nuse const SEEK_SET;\n\nclass Stream implements StreamInterface\n{\n    /**\n     * Bit mask to determine if the stream is a pipe\n     *\n     * This is octal as per header stat.h\n     */\n    public const FSTAT_MODE_S_IFIFO = 0010000;\n\n    /**\n     * The underlying stream resource\n     *\n     * @var resource|null\n     */\n    protected $stream;\n\n    protected ?array $meta;\n\n    protected ?bool $readable = null;\n\n    protected ?bool $writable = null;\n\n    protected ?bool $seekable = null;\n\n    protected ?int $size = null;\n\n    protected ?bool $isPipe = null;\n\n    protected bool $finished = false;\n\n    protected ?StreamInterface $cache;\n\n    /**\n     * @param resource             $stream A PHP resource handle.\n     * @param StreamInterface|null $cache  A stream to cache $stream (useful for non-seekable streams)\n     *\n     * @throws InvalidArgumentException If argument is not a resource.\n     */\n    public function __construct($stream, ?StreamInterface $cache = null)\n    {\n        $this->attach($stream);\n\n        if ($cache && (!$cache->isSeekable() || !$cache->isWritable())) {\n            throw new RuntimeException('Cache stream must be seekable and writable');\n        }\n        $this->cache = $cache;\n    }\n\n    /**\n     * {@inheritdoc}\n     * @return array|mixed\n     */\n    public function getMetadata($key = null)\n    {\n        if (!$this->stream) {\n            return null;\n        }\n\n        $this->meta = stream_get_meta_data($this->stream);\n\n        if (!$key) {\n            return $this->meta;\n        }\n\n        return $this->meta[$key] ?? null;\n    }\n\n    /**\n     * Attach new resource to this object.\n     *\n     * @internal This method is not part of the PSR-7 standard.\n     *\n     * @param resource $stream A PHP resource handle.\n     *\n     * @throws InvalidArgumentException If argument is not a valid PHP resource.\n     *\n     * @return void\n     */\n    protected function attach($stream): void\n    {\n        if (!is_resource($stream)) {\n            throw new InvalidArgumentException(__METHOD__ . ' argument must be a valid PHP resource');\n        }\n\n        if ($this->stream) {\n            $this->detach();\n        }\n\n        $this->stream = $stream;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function detach()\n    {\n        $oldResource = $this->stream;\n        $this->stream = null;\n        $this->meta = null;\n        $this->readable = null;\n        $this->writable = null;\n        $this->seekable = null;\n        $this->size = null;\n        $this->isPipe = null;\n\n        $this->cache = null;\n        $this->finished = false;\n\n        return $oldResource;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function __toString(): string\n    {\n        if (!$this->stream) {\n            return '';\n        }\n        if ($this->cache && $this->finished) {\n            $this->cache->rewind();\n            return $this->cache->getContents();\n        }\n        if ($this->isSeekable()) {\n            $this->rewind();\n        }\n        return $this->getContents();\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function close(): void\n    {\n        if ($this->stream) {\n            if ($this->isPipe()) {\n                pclose($this->stream);\n            } else {\n                fclose($this->stream);\n            }\n        }\n\n        $this->detach();\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getSize(): ?int\n    {\n        if ($this->stream && !$this->size) {\n            $stats = fstat($this->stream);\n\n            if ($stats) {\n                $this->size = !$this->isPipe() ? $stats['size'] : null;\n            }\n        }\n\n        return $this->size;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function tell(): int\n    {\n        $position = false;\n\n        if ($this->stream) {\n            $position = ftell($this->stream);\n        }\n\n        if ($position === false || $this->isPipe()) {\n            throw new RuntimeException('Could not get the position of the pointer in stream.');\n        }\n\n        return $position;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function eof(): bool\n    {\n        return !$this->stream || feof($this->stream);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function isReadable(): bool\n    {\n        if ($this->readable !== null) {\n            return $this->readable;\n        }\n\n        $this->readable = false;\n\n        if ($this->stream) {\n            $mode = $this->getMetadata('mode');\n\n            if (is_string($mode) && (strstr($mode, 'r') !== false || strstr($mode, '+') !== false)) {\n                $this->readable = true;\n            }\n        }\n\n        return $this->readable;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function isWritable(): bool\n    {\n        if ($this->writable === null) {\n            $this->writable = false;\n\n            if ($this->stream) {\n                $mode = $this->getMetadata('mode');\n\n                if (is_string($mode) && (strstr($mode, 'w') !== false || strstr($mode, '+') !== false)) {\n                    $this->writable = true;\n                }\n            }\n        }\n\n        return $this->writable;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function isSeekable(): bool\n    {\n        if ($this->seekable === null) {\n            $this->seekable = false;\n\n            if ($this->stream) {\n                $this->seekable = !$this->isPipe() && $this->getMetadata('seekable');\n            }\n        }\n\n        return $this->seekable;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function seek($offset, $whence = SEEK_SET): void\n    {\n        if (!$this->isSeekable() || $this->stream && fseek($this->stream, $offset, $whence) === -1) {\n            throw new RuntimeException('Could not seek in stream.');\n        }\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function rewind(): void\n    {\n        if (!$this->isSeekable() || $this->stream && rewind($this->stream) === false) {\n            throw new RuntimeException('Could not rewind stream.');\n        }\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function read($length): string\n    {\n        $data = false;\n\n        if ($this->isReadable() && $this->stream && $length > 0) {\n            $data = fread($this->stream, $length);\n        }\n\n        if (is_string($data)) {\n            if ($this->cache) {\n                $this->cache->write($data);\n            }\n            if ($this->eof()) {\n                $this->finished = true;\n            }\n            return $data;\n        }\n\n        throw new RuntimeException('Could not read from stream.');\n    }\n\n    /**\n     * {@inheritdoc}\n     * @return int\n     */\n    public function write($string)\n    {\n        $written = false;\n\n        if ($this->isWritable() && $this->stream) {\n            $written = fwrite($this->stream, $string);\n        }\n\n        if ($written !== false) {\n            $this->size = null;\n            return $written;\n        }\n\n        throw new RuntimeException('Could not write to stream.');\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getContents(): string\n    {\n        if ($this->cache && $this->finished) {\n            $this->cache->rewind();\n            return $this->cache->getContents();\n        }\n\n        $contents = false;\n\n        if ($this->stream) {\n            $contents = stream_get_contents($this->stream);\n        }\n\n        if (is_string($contents)) {\n            if ($this->cache) {\n                $this->cache->write($contents);\n            }\n            if ($this->eof()) {\n                $this->finished = true;\n            }\n            return $contents;\n        }\n\n        throw new RuntimeException('Could not get contents of stream.');\n    }\n\n    /**\n     * Returns whether or not the stream is a pipe.\n     *\n     * @internal This method is not part of the PSR-7 standard.\n     *\n     * @return bool\n     */\n    public function isPipe(): bool\n    {\n        if ($this->isPipe === null) {\n            $this->isPipe = false;\n\n            if ($this->stream) {\n                $stats = fstat($this->stream);\n\n                if (is_array($stats)) {\n                    $this->isPipe = ($stats['mode'] & self::FSTAT_MODE_S_IFIFO) !== 0;\n                }\n            }\n        }\n\n        return $this->isPipe;\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/psr7/src/UploadedFile.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim-Psr7/blob/master/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Psr7;\n\nuse InvalidArgumentException;\nuse Psr\\Http\\Message\\StreamInterface;\nuse Psr\\Http\\Message\\UploadedFileInterface;\nuse RuntimeException;\nuse Slim\\Psr7\\Factory\\StreamFactory;\n\nuse function copy;\nuse function dirname;\nuse function is_array;\nuse function is_string;\nuse function is_uploaded_file;\nuse function is_writable;\nuse function move_uploaded_file;\nuse function rename;\nuse function sprintf;\nuse function strpos;\nuse function unlink;\n\nuse const UPLOAD_ERR_OK;\n\nclass UploadedFile implements UploadedFileInterface\n{\n    /**\n     * The client-provided full path to the file\n     */\n    protected string $file;\n\n    /**\n     * The client-provided file name.\n     */\n    protected ?string $name;\n\n    /**\n     * The client-provided media type of the file.\n     */\n    protected ?string $type;\n\n    protected ?int $size;\n\n    /**\n     * A valid PHP UPLOAD_ERR_xxx code for the file upload.\n     */\n    protected int $error = UPLOAD_ERR_OK;\n\n    /**\n     * Indicates if the upload is from a SAPI environment.\n     */\n    protected bool $sapi = false;\n\n    /**\n     * @var StreamInterface|null\n     */\n    protected $stream;\n\n    /**\n     * Indicates if the uploaded file has already been moved.\n     */\n    protected bool $moved = false;\n\n    /**\n     * @param string|StreamInterface $fileNameOrStream The full path to the uploaded file provided by the client,\n     *                                                 or a StreamInterface instance.\n     * @param string|null            $name             The file name.\n     * @param string|null            $type             The file media type.\n     * @param int|null               $size             The file size in bytes.\n     * @param int                    $error            The UPLOAD_ERR_XXX code representing the status of the upload.\n     * @param bool                   $sapi             Indicates if the upload is in a SAPI environment.\n     */\n    final public function __construct(\n        $fileNameOrStream,\n        ?string $name = null,\n        ?string $type = null,\n        ?int $size = null,\n        int $error = UPLOAD_ERR_OK,\n        bool $sapi = false\n    ) {\n        if ($fileNameOrStream instanceof StreamInterface) {\n            $file = $fileNameOrStream->getMetadata('uri');\n            if (!is_string($file)) {\n                throw new InvalidArgumentException('No URI associated with the stream.');\n            }\n            $this->file = $file;\n            $this->stream = $fileNameOrStream;\n        } elseif (is_string($fileNameOrStream)) {\n            $this->file = $fileNameOrStream;\n        } else {\n            throw new InvalidArgumentException(\n                'Please provide a string (full path to the uploaded file) or an instance of StreamInterface.'\n            );\n        }\n        $this->name = $name;\n        $this->type = $type;\n        $this->size = $size;\n        $this->error = $error;\n        $this->sapi = $sapi;\n    }\n\n    /**\n     * {@inheritdoc}\n     * @return StreamInterface\n     */\n    public function getStream()\n    {\n        if ($this->moved) {\n            throw new RuntimeException(sprintf('Uploaded file %s has already been moved', $this->name));\n        }\n\n        if (!$this->stream) {\n            $this->stream = (new StreamFactory())->createStreamFromFile($this->file);\n        }\n\n        return $this->stream;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function moveTo($targetPath): void\n    {\n        if ($this->moved) {\n            throw new RuntimeException('Uploaded file already moved');\n        }\n\n        $targetIsStream = strpos($targetPath, '://') > 0;\n        if (!$targetIsStream && !is_writable(dirname($targetPath))) {\n            throw new InvalidArgumentException('Upload target path is not writable');\n        }\n\n        if ($targetIsStream) {\n            if (!copy($this->file, $targetPath)) {\n                throw new RuntimeException(sprintf('Error moving uploaded file %s to %s', $this->name, $targetPath));\n            }\n\n            if (!unlink($this->file)) {\n                throw new RuntimeException(sprintf('Error removing uploaded file %s', $this->name));\n            }\n        } elseif ($this->sapi) {\n            if (!is_uploaded_file($this->file)) {\n                throw new RuntimeException(sprintf('%s is not a valid uploaded file', $this->file));\n            }\n\n            if (!move_uploaded_file($this->file, $targetPath)) {\n                throw new RuntimeException(sprintf('Error moving uploaded file %s to %s', $this->name, $targetPath));\n            }\n        } else {\n            if (!rename($this->file, $targetPath)) {\n                throw new RuntimeException(sprintf('Error moving uploaded file %s to %s', $this->name, $targetPath));\n            }\n        }\n\n        $this->moved = true;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getError(): int\n    {\n        return $this->error;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getClientFilename(): ?string\n    {\n        return $this->name;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getClientMediaType(): ?string\n    {\n        return $this->type;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getSize(): ?int\n    {\n        return $this->size;\n    }\n\n    /**\n     * Returns the client-provided full path to the file\n     *\n     * @internal This method is not part of the PSR-7 standard\n     *\n     * @return string\n     */\n    public function getFilePath(): string\n    {\n        return $this->file;\n    }\n\n    /**\n     * Create a normalized tree of UploadedFile instances from the Environment.\n     *\n     * @internal This method is not part of the PSR-7 standard.\n     *\n     * @param array $globals The global server variables.\n     *\n     * @return array A normalized tree of UploadedFile instances or null if none are provided.\n     */\n    public static function createFromGlobals(array $globals): array\n    {\n        if (isset($globals['slim.files']) && is_array($globals['slim.files'])) {\n            return $globals['slim.files'];\n        }\n\n        if (!empty($_FILES)) {\n            return self::parseUploadedFiles($_FILES);\n        }\n\n        return [];\n    }\n\n    /**\n     * Parse a non-normalized, i.e. $_FILES superglobal, tree of uploaded file data.\n     *\n     * @internal This method is not part of the PSR-7 standard.\n     *\n     * @param array $uploadedFiles The non-normalized tree of uploaded file data.\n     *\n     * @return array A normalized tree of UploadedFile instances.\n     */\n    private static function parseUploadedFiles(array $uploadedFiles): array\n    {\n        $parsed = [];\n        foreach ($uploadedFiles as $field => $uploadedFile) {\n            if (!isset($uploadedFile['error'])) {\n                if (is_array($uploadedFile)) {\n                    $parsed[$field] = self::parseUploadedFiles($uploadedFile);\n                }\n                continue;\n            }\n\n            $parsed[$field] = [];\n            if (!is_array($uploadedFile['error'])) {\n                $parsed[$field] = new static(\n                    $uploadedFile['tmp_name'],\n                    $uploadedFile['name'] ?? null,\n                    $uploadedFile['type'] ?? null,\n                    $uploadedFile['size'] ?? null,\n                    $uploadedFile['error'],\n                    true\n                );\n            } else {\n                $subArray = [];\n                foreach ($uploadedFile['error'] as $fileIdx => $error) {\n                    // Normalize sub array and re-parse to move the input's key name up a level\n                    $subArray[$fileIdx]['name'] = $uploadedFile['name'][$fileIdx];\n                    $subArray[$fileIdx]['type'] = $uploadedFile['type'][$fileIdx];\n                    $subArray[$fileIdx]['tmp_name'] = $uploadedFile['tmp_name'][$fileIdx];\n                    $subArray[$fileIdx]['error'] = $uploadedFile['error'][$fileIdx];\n                    $subArray[$fileIdx]['size'] = $uploadedFile['size'][$fileIdx];\n\n                    $parsed[$field] = self::parseUploadedFiles($subArray);\n                }\n            }\n        }\n\n        return $parsed;\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/psr7/src/Uri.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim-Psr7/blob/master/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Psr7;\n\nuse InvalidArgumentException;\nuse Psr\\Http\\Message\\UriInterface;\n\nuse function filter_var;\nuse function is_integer;\nuse function is_null;\nuse function is_object;\nuse function is_string;\nuse function ltrim;\nuse function method_exists;\nuse function preg_replace_callback;\nuse function rawurlencode;\nuse function str_replace;\nuse function strtolower;\n\nuse const FILTER_FLAG_IPV6;\nuse const FILTER_VALIDATE_IP;\n\nclass Uri implements UriInterface\n{\n    public const SUPPORTED_SCHEMES = [\n        '' => null,\n        'http' => 80,\n        'https' => 443\n    ];\n\n    /**\n     * Uri scheme (without \"://\" suffix)\n     */\n    protected string $scheme = '';\n\n    protected string $user = '';\n\n    protected string $password = '';\n\n    protected string $host = '';\n\n    protected ?int $port;\n\n    protected string $path = '';\n\n    /**\n     * Uri query string (without \"?\" prefix)\n     */\n    protected string $query = '';\n\n    /**\n     * Uri fragment string (without \"#\" prefix)\n     */\n    protected string $fragment = '';\n\n    /**\n     * @param string   $scheme   Uri scheme.\n     * @param string   $host     Uri host.\n     * @param int|null $port     Uri port number.\n     * @param string   $path     Uri path.\n     * @param string   $query    Uri query string.\n     * @param string   $fragment Uri fragment.\n     * @param string   $user     Uri user.\n     * @param string   $password Uri password.\n     */\n    public function __construct(\n        string $scheme,\n        string $host,\n        ?int $port = null,\n        string $path = '/',\n        string $query = '',\n        string $fragment = '',\n        string $user = '',\n        string $password = ''\n    ) {\n        $this->scheme = $this->filterScheme($scheme);\n        $this->host = $this->filterHost($host);\n        $this->port = $this->filterPort($port);\n        $this->path = $this->filterPath($path);\n        $this->query = $this->filterQuery($query);\n        $this->fragment = $this->filterFragment($fragment);\n        $this->user = $this->filterUserInfo($user);\n        $this->password = $this->filterUserInfo($password);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getScheme(): string\n    {\n        return $this->scheme;\n    }\n\n    /**\n     * {@inheritdoc}\n     * @return static\n     */\n    public function withScheme($scheme)\n    {\n        $scheme = $this->filterScheme($scheme);\n        $clone = clone $this;\n        $clone->scheme = $scheme;\n\n        return $clone;\n    }\n\n    /**\n     * Filter Uri scheme.\n     *\n     * @param  mixed $scheme Raw Uri scheme.\n     *\n     * @return string\n     *\n     * @throws InvalidArgumentException If the Uri scheme is not a string.\n     * @throws InvalidArgumentException If Uri scheme is not exists in SUPPORTED_SCHEMES\n     */\n    protected function filterScheme($scheme): string\n    {\n        if (!is_string($scheme)) {\n            throw new InvalidArgumentException('Uri scheme must be a string.');\n        }\n\n        $scheme = str_replace('://', '', strtolower($scheme));\n        if (!key_exists($scheme, static::SUPPORTED_SCHEMES)) {\n            throw new InvalidArgumentException(\n                'Uri scheme must be one of: \"' . implode('\", \"', array_keys(static::SUPPORTED_SCHEMES)) . '\"'\n            );\n        }\n\n        return $scheme;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getAuthority(): string\n    {\n        $userInfo = $this->getUserInfo();\n        $host = $this->getHost();\n        $port = $this->getPort();\n\n        return ($userInfo !== '' ? $userInfo . '@' : '') . $host . ($port !== null ? ':' . $port : '');\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getUserInfo(): string\n    {\n        $info = $this->user;\n\n        if ($this->password !== '') {\n            $info .= ':' . $this->password;\n        }\n\n        return $info;\n    }\n\n    /**\n     * {@inheritdoc}\n     * @return static\n     */\n    public function withUserInfo($user, $password = null)\n    {\n        $clone = clone $this;\n        $clone->user = $this->filterUserInfo($user);\n\n        if ($clone->user !== '') {\n            $clone->password = $this->filterUserInfo($password);\n        } else {\n            $clone->password = '';\n        }\n\n        return $clone;\n    }\n\n    /**\n     * Filters the user info string.\n     *\n     * Returns the percent-encoded query string.\n     *\n     * @param string|null $info The raw uri query string.\n     *\n     * @return string\n     */\n    protected function filterUserInfo(?string $info = null): string\n    {\n        if (!is_string($info)) {\n            return '';\n        }\n\n        $match =  preg_replace_callback(\n            '/(?:[^%a-zA-Z0-9_\\-\\.~!\\$&\\'\\(\\)\\*\\+,;=]+|%(?![A-Fa-f0-9]{2}))/',\n            function ($match) {\n                return rawurlencode($match[0]);\n            },\n            $info\n        );\n\n        return is_string($match) ? $match : '';\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getHost(): string\n    {\n        return $this->host;\n    }\n\n    /**\n     * {@inheritdoc}\n     * @return static\n     */\n    public function withHost($host)\n    {\n        $clone = clone $this;\n        $clone->host = $this->filterHost($host);\n\n        return $clone;\n    }\n\n    /**\n     * Filter Uri host.\n     *\n     * If the supplied host is an IPv6 address, then it is converted to a reference\n     * as per RFC 2373.\n     *\n     * @param  mixed $host The host to filter.\n     *\n     * @return string\n     *\n     * @throws InvalidArgumentException for invalid host names.\n     */\n    protected function filterHost($host): string\n    {\n        if (is_object($host) && method_exists($host, '__toString')) {\n            $host = (string) $host;\n        }\n\n        if (!is_string($host)) {\n            throw new InvalidArgumentException('Uri host must be a string');\n        }\n\n        if (filter_var($host, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {\n            $host = '[' . $host . ']';\n        }\n\n        return strtolower($host);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getPort(): ?int\n    {\n        return $this->port && !$this->hasStandardPort() ? $this->port : null;\n    }\n\n    /**\n     * {@inheritdoc}\n     * @return static\n     */\n    public function withPort($port)\n    {\n        $port = $this->filterPort($port);\n        $clone = clone $this;\n        $clone->port = $port;\n\n        return $clone;\n    }\n\n    /**\n     * Does this Uri use a standard port?\n     *\n     * @return bool\n     */\n    protected function hasStandardPort(): bool\n    {\n        return static::SUPPORTED_SCHEMES[$this->scheme] === $this->port;\n    }\n\n    /**\n     * Filter Uri port.\n     *\n     * @param  int|null $port The Uri port number.\n     *\n     * @return int|null\n     *\n     * @throws InvalidArgumentException If the port is invalid.\n     */\n    protected function filterPort($port): ?int\n    {\n        if (is_null($port) || (is_integer($port) && ($port >= 1 && $port <= 65535))) {\n            return $port;\n        }\n\n        throw new InvalidArgumentException('Uri port must be null or an integer between 1 and 65535 (inclusive)');\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getPath(): string\n    {\n        $path = $this->path;\n\n        // If the path starts with a / then remove all leading slashes except one.\n        if (strpos($path, '/') === 0) {\n            $path = '/' . ltrim($path, '/');\n        }\n\n        return $path;\n    }\n\n    /**\n     * {@inheritdoc}\n     * @return static\n     */\n    public function withPath($path)\n    {\n        if (!is_string($path)) {\n            throw new InvalidArgumentException('Uri path must be a string');\n        }\n\n        $clone = clone $this;\n        $clone->path = $this->filterPath($path);\n\n        return $clone;\n    }\n\n    /**\n     * Filter Uri path.\n     *\n     * This method percent-encodes all reserved characters in the provided path string.\n     * This method will NOT double-encode characters that are already percent-encoded.\n     *\n     * @param  string $path The raw uri path.\n     *\n     * @return string       The RFC 3986 percent-encoded uri path.\n     *\n     * @link   http://www.faqs.org/rfcs/rfc3986.html\n     */\n    protected function filterPath($path): string\n    {\n        $match = preg_replace_callback(\n            '/(?:[^a-zA-Z0-9_\\-\\.~:@&=\\+\\$,\\/;%]+|%(?![A-Fa-f0-9]{2}))/',\n            function ($match) {\n                return rawurlencode($match[0]);\n            },\n            $path\n        );\n\n        return is_string($match) ? $match : '';\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getQuery(): string\n    {\n        return $this->query;\n    }\n\n    /**\n     * {@inheritdoc}\n     * @return static\n     */\n    public function withQuery($query)\n    {\n        $query = ltrim($this->filterQuery($query), '?');\n        $clone = clone $this;\n        $clone->query = $query;\n\n        return $clone;\n    }\n\n    /**\n     * Filters the query string of a URI.\n     *\n     * Returns the percent-encoded query string.\n     *\n     * @param mixed $query The raw uri query string.\n     *\n     * @return string\n     */\n    protected function filterQuery($query): string\n    {\n        if (is_object($query) && method_exists($query, '__toString')) {\n            $query = (string) $query;\n        }\n\n        if (!is_string($query)) {\n            throw new InvalidArgumentException('Uri query must be a string.');\n        }\n\n        $match = preg_replace_callback(\n            '/(?:[^a-zA-Z0-9_\\-\\.~!\\$&\\'\\(\\)\\*\\+,;=%:@\\/\\?]+|%(?![A-Fa-f0-9]{2}))/',\n            function ($match) {\n                return rawurlencode($match[0]);\n            },\n            $query\n        );\n\n        return is_string($match) ? $match : '';\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getFragment(): string\n    {\n        return $this->fragment;\n    }\n\n    /**\n     * {@inheritdoc}\n     * @return static\n     */\n    public function withFragment($fragment)\n    {\n        $fragment = $this->filterFragment($fragment);\n        $clone = clone $this;\n        $clone->fragment = $fragment;\n\n        return $clone;\n    }\n\n    /**\n     * Filters fragment of a URI.\n     *\n     * Returns the percent-encoded fragment.\n     *\n     * @param mixed $fragment The raw uri query string.\n     *\n     * @return string\n     */\n    protected function filterFragment($fragment): string\n    {\n        if (is_object($fragment) && method_exists($fragment, '__toString')) {\n            $fragment = (string) $fragment;\n        }\n\n        if (!is_string($fragment)) {\n            throw new InvalidArgumentException('Uri fragment must be a string.');\n        }\n\n        $fragment = ltrim($fragment, '#');\n\n        $match = preg_replace_callback(\n            '/(?:[^a-zA-Z0-9_\\-\\.~!\\$&\\'\\(\\)\\*\\+,;=%:@\\/\\?]+|%(?![A-Fa-f0-9]{2}))/',\n            function ($match) {\n                return rawurlencode($match[0]);\n            },\n            $fragment\n        );\n\n        return is_string($match) ? $match : '';\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function __toString(): string\n    {\n        $scheme = $this->getScheme();\n        $authority = $this->getAuthority();\n        $path = $this->path;\n        $query = $this->getQuery();\n        $fragment = $this->getFragment();\n\n        if ($path !== '') {\n            if ($path[0] !== '/') {\n                if ($authority !== '') {\n                    // If the path is rootless and an authority is present, the path MUST be prefixed by \"/\".\n                    $path = '/' . $path;\n                }\n            } elseif (isset($path[1]) && $path[1] === '/') {\n                if ($authority === '') {\n                    // If the path is starting with more than one \"/\" and no authority is present,\n                    // the starting slashes MUST be reduced to one.\n                    $path = ltrim($path, '/');\n                    $path = '/' . $path;\n                }\n            }\n        }\n\n        return ($scheme !== '' ? $scheme . ':' : '')\n            . ($authority !== '' ? '//' . $authority : '')\n            . $path\n            . ($query !== '' ? '?' . $query : '')\n            . ($fragment !== '' ? '#' . $fragment : '');\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/CHANGELOG.md",
    "content": "# Changelog\n\n# 4.11.0 - 2022-11-06\n- [3180: Declare types](https://github.com/slimphp/Slim/pull/3180) thanks to @nbayramberdiyev\n- [3181: Update laminas/laminas-diactoros requirement from ^2.8 to ^2.9](https://github.com/slimphp/Slim/pull/3181) thanks to @dependabot[bot]\n- [3182: Update guzzlehttp/psr7 requirement from ^2.1 to ^2.2](https://github.com/slimphp/Slim/pull/3182) thanks to @dependabot[bot]\n- [3183: Update phpstan/phpstan requirement from ^1.4 to ^1.5](https://github.com/slimphp/Slim/pull/3183) thanks to @dependabot[bot]\n- [3184: Update adriansuter/php-autoload-override requirement from ^1.2 to ^1.3](https://github.com/slimphp/Slim/pull/3184) thanks to @dependabot[bot]\n- [3189: Update phpstan/phpstan requirement from ^1.5 to ^1.6](https://github.com/slimphp/Slim/pull/3189) thanks to @dependabot[bot]\n- [3191: Adding property types to Middleware classes](https://github.com/slimphp/Slim/pull/3191) thanks to @ashleycoles\n- [3193: Handlers types](https://github.com/slimphp/Slim/pull/3193) thanks to @ashleycoles\n- [3194: Adding types to AbstractErrorRenderer](https://github.com/slimphp/Slim/pull/3194) thanks to @ashleycoles\n- [3195: Adding prop types for Exception classes](https://github.com/slimphp/Slim/pull/3195) thanks to @ashleycoles\n- [3196: Adding property type declarations for Factory classes](https://github.com/slimphp/Slim/pull/3196) thanks to @ashleycoles\n- [3197: Remove redundant docblock types](https://github.com/slimphp/Slim/pull/3197) thanks to @theodorejb\n- [3199: Update laminas/laminas-diactoros requirement from ^2.9 to ^2.11](https://github.com/slimphp/Slim/pull/3199) thanks to @dependabot[bot]\n- [3200: Update phpstan/phpstan requirement from ^1.6 to ^1.7](https://github.com/slimphp/Slim/pull/3200) thanks to @dependabot[bot]\n- [3205: Update guzzlehttp/psr7 requirement from ^2.2 to ^2.4](https://github.com/slimphp/Slim/pull/3205) thanks to @dependabot[bot]\n- [3206: Update squizlabs/php_codesniffer requirement from ^3.6 to ^3.7](https://github.com/slimphp/Slim/pull/3206) thanks to @dependabot[bot]\n- [3207: Update phpstan/phpstan requirement from ^1.7 to ^1.8](https://github.com/slimphp/Slim/pull/3207) thanks to @dependabot[bot]\n- [3211: Assign null coalescing to coalesce equal](https://github.com/slimphp/Slim/pull/3211) thanks to @MathiasReker\n- [3213: Void return](https://github.com/slimphp/Slim/pull/3213) thanks to @MathiasReker\n- [3214: Is null](https://github.com/slimphp/Slim/pull/3214) thanks to @MathiasReker\n- [3216: Refactor](https://github.com/slimphp/Slim/pull/3216) thanks to @mehdihasanpour\n- [3218: Refactor some code](https://github.com/slimphp/Slim/pull/3218) thanks to @mehdihasanpour\n- [3221: Cleanup](https://github.com/slimphp/Slim/pull/3221) thanks to @mehdihasanpour\n- [3225: Update laminas/laminas-diactoros requirement from ^2.11 to ^2.14](https://github.com/slimphp/Slim/pull/3225) thanks to @dependabot[bot]\n- [3228: Using assertSame to let assert equal be restricted](https://github.com/slimphp/Slim/pull/3228) thanks to @peter279k\n- [3229: Update laminas/laminas-diactoros requirement from ^2.14 to ^2.17](https://github.com/slimphp/Slim/pull/3229) thanks to @dependabot[bot]\n- [3235: Persist routes indexed by name in RouteCollector for improved performance.](https://github.com/slimphp/Slim/pull/3235) thanks to @BusterNeece\n\n# 4.10.0 - 2022-03-14\n- [3120: Add a new PSR-17 factory to Psr17FactoryProvider](https://github.com/slimphp/Slim/pull/3120) thanks to @solventt\n- [3123: Replace deprecated setMethods() in tests](https://github.com/slimphp/Slim/pull/3123) thanks to @solventt\n- [3126: Update guzzlehttp/psr7 requirement from ^2.0 to ^2.1](https://github.com/slimphp/Slim/pull/3126) thanks to @dependabot[bot]\n- [3127: PHPStan v1.0](https://github.com/slimphp/Slim/pull/3127) thanks to @t0mmy742\n- [3128: Update phpstan/phpstan requirement from ^1.0 to ^1.2](https://github.com/slimphp/Slim/pull/3128) thanks to @dependabot[bot]\n- [3129: Deprecate PHP 7.3](https://github.com/slimphp/Slim/pull/3129) thanks to @l0gicgate\n- [3130: Removed double defined PHP 7.4](https://github.com/slimphp/Slim/pull/3130) thanks to @flangofas\n- [3132: Add new `RequestResponseNamedArgs` route strategy](https://github.com/slimphp/Slim/pull/3132) thanks to @adoy\n- [3133: Improve typehinting for `RouteParserInterface`](https://github.com/slimphp/Slim/pull/3133) thanks to @jerowork\n- [3135: Update phpstan/phpstan requirement from ^1.2 to ^1.3](https://github.com/slimphp/Slim/pull/3135) thanks to @dependabot[bot]\n- [3137: Update phpspec/prophecy requirement from ^1.14 to ^1.15](https://github.com/slimphp/Slim/pull/3137) thanks to @dependabot[bot]\n- [3138: Update license year](https://github.com/slimphp/Slim/pull/3138) thanks to @Awilum\n- [3139: Fixed #1730 (reintroduced in 4.x)](https://github.com/slimphp/Slim/pull/3139) thanks to @adoy\n- [3145: Update phpstan/phpstan requirement from ^1.3 to ^1.4](https://github.com/slimphp/Slim/pull/3145) thanks to @dependabot[bot]\n- [3146: Inherit HttpException from RuntimeException](https://github.com/slimphp/Slim/pull/3146) thanks to @nbayramberdiyev\n- [3148: Upgrade to HTML5](https://github.com/slimphp/Slim/pull/3148) thanks to @nbayramberdiyev\n- [3172: Update nyholm/psr7 requirement from ^1.4 to ^1.5](https://github.com/slimphp/Slim/pull/3172) thanks to @dependabot[bot]\n\n# 4.9.0 - 2021-10-05\n- [3058: Implement exception class for Gone Http error](https://github.com/slimphp/Slim/pull/3058) thanks to @TheKernelPanic\n- [3086: Update slim/psr7 requirement from ^1.3 to ^1.4](https://github.com/slimphp/Slim/pull/3086) thanks to @dependabot[bot]\n- [3087: Update nyholm/psr7-server requirement from ^1.0.1 to ^1.0.2](https://github.com/slimphp/Slim/pull/3087) thanks to @dependabot[bot]\n- [3093: Update phpstan/phpstan requirement from ^0.12.85 to ^0.12.90](https://github.com/slimphp/Slim/pull/3093) thanks to @dependabot[bot]\n- [3099: Allow updated psr log](https://github.com/slimphp/Slim/pull/3099) thanks to @t0mmy742\n- [3104: Drop php7.2](https://github.com/slimphp/Slim/pull/3104) thanks to @t0mmy742\n- [3106: Use PSR-17 factory from Guzzle/psr7 2.0](https://github.com/slimphp/Slim/pull/3106) thanks to @t0mmy742\n- [3108: Update README file](https://github.com/slimphp/Slim/pull/3108) thanks to @t0mmy742\n- [3112: Update laminas/laminas-diactoros requirement from ^2.6 to ^2.8](https://github.com/slimphp/Slim/pull/3112) thanks to @dependabot[bot]\n- [3114: Update slim/psr7 requirement from ^1.4 to ^1.5](https://github.com/slimphp/Slim/pull/3114) thanks to @dependabot[bot]\n- [3115: Update phpstan/phpstan requirement from ^0.12.96 to ^0.12.99](https://github.com/slimphp/Slim/pull/3115) thanks to @dependabot[bot]\n- [3116: Remove Zend Diactoros references](https://github.com/slimphp/Slim/pull/3116) thanks to @l0gicgate\n\n# 4.8.0 - 2021-05-19\n- [3034: Fix phpunit dependency version](https://github.com/slimphp/Slim/pull/3034) thanks to @l0gicgate\n- [3037: Replace Travis by GitHub Actions](https://github.com/slimphp/Slim/pull/3037) thanks to @t0mmy742\n- [3043: Cover App creation from AppFactory with empty Container](https://github.com/slimphp/Slim/pull/3043) thanks to @t0mmy742\n- [3045: Update phpstan/phpstan requirement from ^0.12.58 to ^0.12.64](https://github.com/slimphp/Slim/pull/3045) thanks to @dependabot-preview[bot]\n- [3047: documentation: min php 7.2 required](https://github.com/slimphp/Slim/pull/3047) thanks to @Rotzbua\n- [3054: Update phpstan/phpstan requirement from ^0.12.64 to ^0.12.70](https://github.com/slimphp/Slim/pull/3054) thanks to @dependabot-preview[bot]\n- [3056: Fix docblock in ErrorMiddleware](https://github.com/slimphp/Slim/pull/3056) thanks to @piotr-cz\n- [3060: Update phpstan/phpstan requirement from ^0.12.70 to ^0.12.80](https://github.com/slimphp/Slim/pull/3060) thanks to @dependabot-preview[bot]\n- [3061: Update nyholm/psr7 requirement from ^1.3 to ^1.4](https://github.com/slimphp/Slim/pull/3061) thanks to @dependabot-preview[bot]\n- [3063: Allow ^1.0 || ^2.0 in psr/container](https://github.com/slimphp/Slim/pull/3063) thanks to @Ayesh\n- [3069: Classname/Method Callable Arrays](https://github.com/slimphp/Slim/pull/3069) thanks to @ddrv\n- [3078: Update squizlabs/php&#95;codesniffer requirement from ^3.5 to ^3.6](https://github.com/slimphp/Slim/pull/3078) thanks to @dependabot[bot]\n- [3079: Update phpspec/prophecy requirement from ^1.12 to ^1.13](https://github.com/slimphp/Slim/pull/3079) thanks to @dependabot[bot]\n- [3080: Update guzzlehttp/psr7 requirement from ^1.7 to ^1.8](https://github.com/slimphp/Slim/pull/3080) thanks to @dependabot[bot]\n- [3082: Update phpstan/phpstan requirement from ^0.12.80 to ^0.12.85](https://github.com/slimphp/Slim/pull/3082) thanks to @dependabot[bot]\n\n# 4.7.0 - 2020-11-30\n\n### Fixed\n- [3027: Fix: FastRoute dispatcher and data generator should match](https://github.com/slimphp/Slim/pull/3027) thanks to @edudobay\n\n### Added\n- [3015: PHP 8 support](https://github.com/slimphp/Slim/pull/3015) thanks to @edudobay\n\n### Optimizations\n- [3024: Randomize tests](https://github.com/slimphp/Slim/pull/3024) thanks to @pawel-slowik\n\n## 4.6.0 - 2020-11-15\n\n### Fixed\n- [2942: Fix PHPdoc for error handlers in ErrorMiddleware ](https://github.com/slimphp/Slim/pull/2942) thanks to @TiMESPLiNTER\n- [2944: Remove unused function in ErrorHandler](https://github.com/slimphp/Slim/pull/2944) thanks to @l0gicgate\n- [2960: Fix phpstan 0.12 errors](https://github.com/slimphp/Slim/pull/2960) thanks to @adriansuter\n- [2982: Removing cloning statements in tests](https://github.com/slimphp/Slim/pull/2982) thanks to @l0gicgate\n- [3017: Fix request creator factory test](https://github.com/slimphp/Slim/pull/3017) thanks to @pawel-slowik\n- [3022: Ensure RouteParser Always Present After Routing](https://github.com/slimphp/Slim/pull/3022) thanks to @l0gicgate\n\n### Added\n- [2949: Add the support in composer.json](https://github.com/slimphp/Slim/pull/2949) thanks to @ddrv\n- [2958: Strict empty string content type checking in BodyParsingMiddleware::getMediaType](https://github.com/slimphp/Slim/pull/2958) thanks to @Ayesh\n- [2997: Add hints to methods](https://github.com/slimphp/Slim/pull/2997) thanks to @evgsavosin - [3000: Fix route controller test](https://github.com/slimphp/Slim/pull/3000) thanks to @pawel-slowik\n- [3001: Add missing `$strategy` parameter in a Route test](https://github.com/slimphp/Slim/pull/3001) thanks to @pawel-slowik\n\n### Optimizations\n- [2951: Minor optimizations in if() blocks](https://github.com/slimphp/Slim/pull/2951) thanks to @Ayesh\n- [2959: Micro optimization: Declare closures in BodyParsingMiddleware as static](https://github.com/slimphp/Slim/pull/2959) thanks to @Ayesh\n- [2978: Split the routing results to its own function.](https://github.com/slimphp/Slim/pull/2978) thanks to @dlundgren\n\n### Dependencies Updated\n- [2953: Update nyholm/psr7-server requirement from ^0.4.1](https://github.com/slimphp/Slim/pull/2953) thanks to @dependabot-preview[bot]\n- [2954: Update laminas/laminas-diactoros requirement from ^2.1 to ^2.3](https://github.com/slimphp/Slim/pull/2954) thanks to @dependabot-preview[bot]\n- [2955: Update guzzlehttp/psr7 requirement from ^1.5 to ^1.6](https://github.com/slimphp/Slim/pull/2955) thanks to @dependabot-preview[bot]\n- [2956: Update slim/psr7 requirement from ^1.0 to ^1.1](https://github.com/slimphp/Slim/pull/2956) thanks to @dependabot-preview[bot]\n- [2957: Update nyholm/psr7 requirement from ^1.1 to ^1.2](https://github.com/slimphp/Slim/pull/2957) thanks to @dependabot-preview[bot]\n- [2963: Update phpstan/phpstan requirement from ^0.12.23 to ^0.12.25](https://github.com/slimphp/Slim/pull/2963) thanks to @dependabot-preview[bot]\n- [2965: Update adriansuter/php-autoload-override requirement from ^1.0 to ^1.1](https://github.com/slimphp/Slim/pull/2965) thanks to @dependabot-preview[bot]\n- [2967: Update nyholm/psr7 requirement from ^1.2 to ^1.3](https://github.com/slimphp/Slim/pull/2967) thanks to @dependabot-preview[bot]\n- [2969: Update nyholm/psr7-server requirement from ^0.4.1 to ^1.0.0](https://github.com/slimphp/Slim/pull/2969) thanks to @dependabot-preview[bot]\n- [2970: Update phpstan/phpstan requirement from ^0.12.25 to ^0.12.26](https://github.com/slimphp/Slim/pull/2970) thanks to @dependabot-preview[bot]\n- [2971: Update phpstan/phpstan requirement from ^0.12.26 to ^0.12.27](https://github.com/slimphp/Slim/pull/2971) thanks to @dependabot-preview[bot]\n- [2972: Update phpstan/phpstan requirement from ^0.12.27 to ^0.12.28](https://github.com/slimphp/Slim/pull/2972) thanks to @dependabot-preview[bot]\n- [2973: Update phpstan/phpstan requirement from ^0.12.28 to ^0.12.29](https://github.com/slimphp/Slim/pull/2973) thanks to @dependabot-preview[bot]\n- [2975: Update phpstan/phpstan requirement from ^0.12.29 to ^0.12.30](https://github.com/slimphp/Slim/pull/2975) thanks to @dependabot-preview[bot]\n- [2976: Update phpstan/phpstan requirement from ^0.12.30 to ^0.12.31](https://github.com/slimphp/Slim/pull/2976) thanks to @dependabot-preview[bot]\n- [2980: Update phpstan/phpstan requirement from ^0.12.31 to ^0.12.32](https://github.com/slimphp/Slim/pull/2980) thanks to @dependabot-preview[bot]\n- [2981: Update phpspec/prophecy requirement from ^1.10 to ^1.11](https://github.com/slimphp/Slim/pull/2981) thanks to @dependabot-preview[bot]\n- [2986: Update phpstan/phpstan requirement from ^0.12.32 to ^0.12.33](https://github.com/slimphp/Slim/pull/2986) thanks to @dependabot-preview[bot]\n- [2990: Update phpstan/phpstan requirement from ^0.12.33 to ^0.12.34](https://github.com/slimphp/Slim/pull/2990) thanks to @dependabot-preview[bot]\n- [2991: Update phpstan/phpstan requirement from ^0.12.34 to ^0.12.35](https://github.com/slimphp/Slim/pull/2991) thanks to @dependabot-preview[bot]\n- [2993: Update phpstan/phpstan requirement from ^0.12.35 to ^0.12.36](https://github.com/slimphp/Slim/pull/2993) thanks to @dependabot-preview[bot]\n- [2995: Update phpstan/phpstan requirement from ^0.12.36 to ^0.12.37](https://github.com/slimphp/Slim/pull/2995) thanks to @dependabot-preview[bot]\n- [3010: Update guzzlehttp/psr7 requirement from ^1.6 to ^1.7](https://github.com/slimphp/Slim/pull/3010) thanks to @dependabot-preview[bot]\n- [3011: Update phpspec/prophecy requirement from ^1.11 to ^1.12](https://github.com/slimphp/Slim/pull/3011) thanks to @dependabot-preview[bot]\n- [3012: Update slim/http requirement from ^1.0 to ^1.1](https://github.com/slimphp/Slim/pull/3012) thanks to @dependabot-preview[bot]\n- [3013: Update slim/psr7 requirement from ^1.1 to ^1.2](https://github.com/slimphp/Slim/pull/3013) thanks to @dependabot-preview[bot]\n- [3014: Update laminas/laminas-diactoros requirement from ^2.3 to ^2.4](https://github.com/slimphp/Slim/pull/3014) thanks to @dependabot-preview[bot]\n- [3018: Update phpstan/phpstan requirement from ^0.12.37 to ^0.12.54](https://github.com/slimphp/Slim/pull/3018) thanks to @dependabot-preview[bot]\n\n## 4.5.0 - 2020-04-14\n\n### Added\n- [2928](https://github.com/slimphp/Slim/pull/2928) Test against PHP 7.4\n- [2937](https://github.com/slimphp/Slim/pull/2937) Add support for PSR-3\n\n### Fixed\n- [2916](https://github.com/slimphp/Slim/pull/2916) Rename phpcs.xml to phpcs.xml.dist\n- [2917](https://github.com/slimphp/Slim/pull/2917) Update .editorconfig\n- [2925](https://github.com/slimphp/Slim/pull/2925) ResponseEmitter: Don't remove Content-Type and Content-Length when body is empt\n- [2932](https://github.com/slimphp/Slim/pull/2932) Update the Tidelift enterprise language\n- [2938](https://github.com/slimphp/Slim/pull/2938) Modify usage of deprecated expectExceptionMessageRegExp() method\n\n## 4.4.0 - 2020-01-04\n\n### Added\n- [2862](https://github.com/slimphp/Slim/pull/2862) Optionally handle subclasses of exceptions in custom error handler\n- [2869](https://github.com/slimphp/Slim/pull/2869) php-di/php-di added in composer suggestion\n- [2874](https://github.com/slimphp/Slim/pull/2874) Add `null` to param type-hints\n- [2889](https://github.com/slimphp/Slim/pull/2889) Make `RouteContext` attributes customizable and change default to use private names\n- [2907](https://github.com/slimphp/Slim/pull/2907) Migrate to PSR-12 convention\n- [2910](https://github.com/slimphp/Slim/pull/2910) Migrate Zend to Laminas\n- [2912](https://github.com/slimphp/Slim/pull/2912) Add Laminas PSR17 Factory\n- [2913](https://github.com/slimphp/Slim/pull/2913) Update php-autoload-override version\n- [2914](https://github.com/slimphp/Slim/pull/2914) Added ability to add handled exceptions as an array\n\n### Fixed\n- [2864](https://github.com/slimphp/Slim/pull/2864) Optimize error message in error handling if displayErrorDetails was not set\n- [2876](https://github.com/slimphp/Slim/pull/2876) Update links from http to https\n- [2877](https://github.com/slimphp/Slim/pull/2877) Fix docblock for `Slim\\Routing\\RouteCollector::cacheFile`\n- [2878](https://github.com/slimphp/Slim/pull/2878) check body is writable only on ouput buffering append\n- [2896](https://github.com/slimphp/Slim/pull/2896) Render errors uniformly\n- [2902](https://github.com/slimphp/Slim/pull/2902) Fix prophecies\n- [2908](https://github.com/slimphp/Slim/pull/2908) Use autoload-dev for `Slim\\Tests` namespace\n\n### Removed\n- [2871](https://github.com/slimphp/Slim/pull/2871) Remove explicit type-hint\n- [2872](https://github.com/slimphp/Slim/pull/2872) Remove type-hint\n\n## 4.3.0 - 2019-10-05\n\n### Added\n- [2819](https://github.com/slimphp/Slim/pull/2819) Added description to addRoutingMiddleware()\n- [2820](https://github.com/slimphp/Slim/pull/2820) Update link to homepage in composer.json\n- [2828](https://github.com/slimphp/Slim/pull/2828) Allow URIs with leading multi-slashes\n- [2832](https://github.com/slimphp/Slim/pull/2832) Refactor `FastRouteDispatcher`\n- [2835](https://github.com/slimphp/Slim/pull/2835) Rename `pathFor` to `urlFor` in docblock\n- [2846](https://github.com/slimphp/Slim/pull/2846) Correcting the branch name as per issue-2843\n- [2849](https://github.com/slimphp/Slim/pull/2849) Create class alias for FastRoute\\RouteCollector\n- [2855](https://github.com/slimphp/Slim/pull/2855) Add list of allowed methods to HttpMethodNotAllowedException\n- [2860](https://github.com/slimphp/Slim/pull/2860) Add base path to `$request` and use `RouteContext` to read\n\n### Fixed\n- [2839](https://github.com/slimphp/Slim/pull/2839) Fix description for handler signature in phpdocs\n- [2844](https://github.com/slimphp/Slim/pull/2844) Handle base path by routeCollector instead of RouteCollectorProxy\n- [2845](https://github.com/slimphp/Slim/pull/2845) Fix composer scripts\n- [2851](https://github.com/slimphp/Slim/pull/2851) Fix example of 'Hello World' app\n- [2854](https://github.com/slimphp/Slim/pull/2854) Fix undefined property in tests\n\n### Removed\n- [2853](https://github.com/slimphp/Slim/pull/2853) Remove unused classes\n\n## 4.2.0 - 2019-08-20\n\n### Added\n- [2787](https://github.com/slimphp/Slim/pull/2787) Add an advanced callable resolver\n- [2791](https://github.com/slimphp/Slim/pull/2791) Add `inferPrivatePropertyTypeFromConstructor` to phpstan\n- [2793](https://github.com/slimphp/Slim/pull/2793) Add ability to configure application via a container in `AppFactory`\n- [2798](https://github.com/slimphp/Slim/pull/2798) Add PSR-7 Agnostic Body Parsing Middleware\n- [2801](https://github.com/slimphp/Slim/pull/2801) Add `setLogErrorRenderer()` method to `ErrorHandler`\n- [2807](https://github.com/slimphp/Slim/pull/2807) Add check for Slim callable notation if no resolver given\n- [2803](https://github.com/slimphp/Slim/pull/2803) Add ability to emit non seekable streams in `ResponseEmitter`\n- [2817](https://github.com/slimphp/Slim/pull/2817) Add the ability to pass in a custom `MiddlewareDispatcherInterface` to the `App`\n\n### Fixed\n- [2789](https://github.com/slimphp/Slim/pull/2789) Fix Cookie header detection in `ResponseEmitter`\n- [2796](https://github.com/slimphp/Slim/pull/2796) Fix http message format\n- [2800](https://github.com/slimphp/Slim/pull/2800) Fix null comparisons more clear in `ErrorHandler`\n- [2802](https://github.com/slimphp/Slim/pull/2802) Fix incorrect search of a header in stack\n- [2806](https://github.com/slimphp/Slim/pull/2806) Simplify `Route::prepare()` method argument preparation\n- [2809](https://github.com/slimphp/Slim/pull/2809) Eliminate a duplicate code via HOF in `MiddlewareDispatcher`\n- [2816](https://github.com/slimphp/Slim/pull/2816) Fix RouteCollectorProxy::redirect() bug\n\n### Removed\n- [2811](https://github.com/slimphp/Slim/pull/2811) Remove `DeferredCallable`\n\n## 4.1.0 - 2019-08-06\n\n### Added\n- [#2779](https://github.com/slimphp/Slim/pull/2774) Add support for Slim callables `Class:method` resolution & Container Closure auto-binding in `MiddlewareDispatcher`\n- [#2774](https://github.com/slimphp/Slim/pull/2774) Add possibility for custom `RequestHandler` invocation strategies\n\n### Fixed\n- [#2776](https://github.com/slimphp/Slim/pull/2774) Fix group middleware on multiple nested groups\n"
  },
  {
    "path": "server/vendor/slim/slim/LICENSE.md",
    "content": "Copyright (c) 2011-2022 Josh Lockhart\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is furnished\nto do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "server/vendor/slim/slim/MAINTAINERS.md",
    "content": "# Maintainers\n\nThere aren't many rules for maintainers of Slim to remember; what we have is listed here.\n\n## We don't merge our own PRs\n\nOur code is better if more than one set of eyes looks at it. Therefore we do not merge our own pull requests unless there is an exceptional circumstance. This helps to spot errors in the patch and also enables us to share information about the project around the maintainer team.\n\n## PRs tagged `WIP` are not ready to be merged\n\nSometimes it's helpful to collaborate on a patch before it's ready to be merged. We use the text `WIP` (for _Work in Progress_) in the title to mark these PRs. \n\nIf a PR has `WIP` in its title, then it is not to be merged. The person who raised the PR will remove the `WIP` text when they are ready for a full review and merge.\n\n## Assign a merged PR to a milestone\n\nBy ensuring that all merged PRs are assigned to a milestone, we can easily find which PRs were in which release.\n"
  },
  {
    "path": "server/vendor/slim/slim/SECURITY.md",
    "content": "# Security Policy\n\n### Supported Versions\n\n\n| Version | Supported          |\n| ------- | ------------------ |\n| 3.x.x   | :white_check_mark: |\n| 4.x.x   | :white_check_mark: |\n\n\n### Reporting a Vulnerability\n\nTo report a vulnerability please send an email to security@slimframework.com\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/App.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim;\n\nuse Psr\\Container\\ContainerInterface;\nuse Psr\\Http\\Message\\ResponseFactoryInterface;\nuse Psr\\Http\\Message\\ResponseInterface;\nuse Psr\\Http\\Message\\ServerRequestInterface;\nuse Psr\\Http\\Server\\MiddlewareInterface;\nuse Psr\\Http\\Server\\RequestHandlerInterface;\nuse Psr\\Log\\LoggerInterface;\nuse Slim\\Factory\\ServerRequestCreatorFactory;\nuse Slim\\Interfaces\\CallableResolverInterface;\nuse Slim\\Interfaces\\MiddlewareDispatcherInterface;\nuse Slim\\Interfaces\\RouteCollectorInterface;\nuse Slim\\Interfaces\\RouteResolverInterface;\nuse Slim\\Middleware\\BodyParsingMiddleware;\nuse Slim\\Middleware\\ErrorMiddleware;\nuse Slim\\Middleware\\RoutingMiddleware;\nuse Slim\\Routing\\RouteCollectorProxy;\nuse Slim\\Routing\\RouteResolver;\nuse Slim\\Routing\\RouteRunner;\n\nuse function strtoupper;\n\nclass App extends RouteCollectorProxy implements RequestHandlerInterface\n{\n    /**\n     * Current version\n     *\n     * @var string\n     */\n    public const VERSION = '4.12.0';\n\n    protected RouteResolverInterface $routeResolver;\n\n    protected MiddlewareDispatcherInterface $middlewareDispatcher;\n\n    public function __construct(\n        ResponseFactoryInterface $responseFactory,\n        ?ContainerInterface $container = null,\n        ?CallableResolverInterface $callableResolver = null,\n        ?RouteCollectorInterface $routeCollector = null,\n        ?RouteResolverInterface $routeResolver = null,\n        ?MiddlewareDispatcherInterface $middlewareDispatcher = null\n    ) {\n        parent::__construct(\n            $responseFactory,\n            $callableResolver ?? new CallableResolver($container),\n            $container,\n            $routeCollector\n        );\n\n        $this->routeResolver = $routeResolver ?? new RouteResolver($this->routeCollector);\n        $routeRunner = new RouteRunner($this->routeResolver, $this->routeCollector->getRouteParser(), $this);\n\n        if (!$middlewareDispatcher) {\n            $middlewareDispatcher = new MiddlewareDispatcher($routeRunner, $this->callableResolver, $container);\n        } else {\n            $middlewareDispatcher->seedMiddlewareStack($routeRunner);\n        }\n\n        $this->middlewareDispatcher = $middlewareDispatcher;\n    }\n\n    /**\n     * @return RouteResolverInterface\n     */\n    public function getRouteResolver(): RouteResolverInterface\n    {\n        return $this->routeResolver;\n    }\n\n    /**\n     * @return MiddlewareDispatcherInterface\n     */\n    public function getMiddlewareDispatcher(): MiddlewareDispatcherInterface\n    {\n        return $this->middlewareDispatcher;\n    }\n\n    /**\n     * @param MiddlewareInterface|string|callable $middleware\n     */\n    public function add($middleware): self\n    {\n        $this->middlewareDispatcher->add($middleware);\n        return $this;\n    }\n\n    /**\n     * @param MiddlewareInterface $middleware\n     */\n    public function addMiddleware(MiddlewareInterface $middleware): self\n    {\n        $this->middlewareDispatcher->addMiddleware($middleware);\n        return $this;\n    }\n\n    /**\n     * Add the Slim built-in routing middleware to the app middleware stack\n     *\n     * This method can be used to control middleware order and is not required for default routing operation.\n     *\n     * @return RoutingMiddleware\n     */\n    public function addRoutingMiddleware(): RoutingMiddleware\n    {\n        $routingMiddleware = new RoutingMiddleware(\n            $this->getRouteResolver(),\n            $this->getRouteCollector()->getRouteParser()\n        );\n        $this->add($routingMiddleware);\n        return $routingMiddleware;\n    }\n\n    /**\n     * Add the Slim built-in error middleware to the app middleware stack\n     *\n     * @param bool                 $displayErrorDetails\n     * @param bool                 $logErrors\n     * @param bool                 $logErrorDetails\n     * @param LoggerInterface|null $logger\n     *\n     * @return ErrorMiddleware\n     */\n    public function addErrorMiddleware(\n        bool $displayErrorDetails,\n        bool $logErrors,\n        bool $logErrorDetails,\n        ?LoggerInterface $logger = null\n    ): ErrorMiddleware {\n        $errorMiddleware = new ErrorMiddleware(\n            $this->getCallableResolver(),\n            $this->getResponseFactory(),\n            $displayErrorDetails,\n            $logErrors,\n            $logErrorDetails,\n            $logger\n        );\n        $this->add($errorMiddleware);\n        return $errorMiddleware;\n    }\n\n    /**\n     * Add the Slim body parsing middleware to the app middleware stack\n     *\n     * @param callable[] $bodyParsers\n     *\n     * @return BodyParsingMiddleware\n     */\n    public function addBodyParsingMiddleware(array $bodyParsers = []): BodyParsingMiddleware\n    {\n        $bodyParsingMiddleware = new BodyParsingMiddleware($bodyParsers);\n        $this->add($bodyParsingMiddleware);\n        return $bodyParsingMiddleware;\n    }\n\n    /**\n     * Run application\n     *\n     * This method traverses the application middleware stack and then sends the\n     * resultant Response object to the HTTP client.\n     *\n     * @param ServerRequestInterface|null $request\n     * @return void\n     */\n    public function run(?ServerRequestInterface $request = null): void\n    {\n        if (!$request) {\n            $serverRequestCreator = ServerRequestCreatorFactory::create();\n            $request = $serverRequestCreator->createServerRequestFromGlobals();\n        }\n\n        $response = $this->handle($request);\n        $responseEmitter = new ResponseEmitter();\n        $responseEmitter->emit($response);\n    }\n\n    /**\n     * Handle a request\n     *\n     * This method traverses the application middleware stack and then returns the\n     * resultant Response object.\n     *\n     * @param ServerRequestInterface $request\n     * @return ResponseInterface\n     */\n    public function handle(ServerRequestInterface $request): ResponseInterface\n    {\n        $response = $this->middlewareDispatcher->handle($request);\n\n        /**\n         * This is to be in compliance with RFC 2616, Section 9.\n         * If the incoming request method is HEAD, we need to ensure that the response body\n         * is empty as the request may fall back on a GET route handler due to FastRoute's\n         * routing logic which could potentially append content to the response body\n         * https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.4\n         */\n        $method = strtoupper($request->getMethod());\n        if ($method === 'HEAD') {\n            $emptyBody = $this->responseFactory->createResponse()->getBody();\n            return $response->withBody($emptyBody);\n        }\n\n        return $response;\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/CallableResolver.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim;\n\nuse Closure;\nuse Psr\\Container\\ContainerInterface;\nuse Psr\\Http\\Server\\MiddlewareInterface;\nuse Psr\\Http\\Server\\RequestHandlerInterface;\nuse RuntimeException;\nuse Slim\\Interfaces\\AdvancedCallableResolverInterface;\n\nuse function class_exists;\nuse function is_array;\nuse function is_callable;\nuse function is_object;\nuse function is_string;\nuse function json_encode;\nuse function preg_match;\nuse function sprintf;\n\nfinal class CallableResolver implements AdvancedCallableResolverInterface\n{\n    public static string $callablePattern = '!^([^\\:]+)\\:([a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*)$!';\n\n    private ?ContainerInterface $container;\n\n    public function __construct(?ContainerInterface $container = null)\n    {\n        $this->container = $container;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function resolve($toResolve): callable\n    {\n        $toResolve = $this->prepareToResolve($toResolve);\n        if (is_callable($toResolve)) {\n            return $this->bindToContainer($toResolve);\n        }\n        $resolved = $toResolve;\n        if (is_string($toResolve)) {\n            $resolved = $this->resolveSlimNotation($toResolve);\n            $resolved[1] ??= '__invoke';\n        }\n        $callable = $this->assertCallable($resolved, $toResolve);\n        return $this->bindToContainer($callable);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function resolveRoute($toResolve): callable\n    {\n        return $this->resolveByPredicate($toResolve, [$this, 'isRoute'], 'handle');\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function resolveMiddleware($toResolve): callable\n    {\n        return $this->resolveByPredicate($toResolve, [$this, 'isMiddleware'], 'process');\n    }\n\n    /**\n     * @param string|callable $toResolve\n     *\n     * @throws RuntimeException\n     */\n    private function resolveByPredicate($toResolve, callable $predicate, string $defaultMethod): callable\n    {\n        $toResolve = $this->prepareToResolve($toResolve);\n        if (is_callable($toResolve)) {\n            return $this->bindToContainer($toResolve);\n        }\n        $resolved = $toResolve;\n        if ($predicate($toResolve)) {\n            $resolved = [$toResolve, $defaultMethod];\n        }\n        if (is_string($toResolve)) {\n            [$instance, $method] = $this->resolveSlimNotation($toResolve);\n            if ($method === null && $predicate($instance)) {\n                $method = $defaultMethod;\n            }\n            $resolved = [$instance, $method ?? '__invoke'];\n        }\n        $callable = $this->assertCallable($resolved, $toResolve);\n        return $this->bindToContainer($callable);\n    }\n\n    /**\n     * @param mixed $toResolve\n     */\n    private function isRoute($toResolve): bool\n    {\n        return $toResolve instanceof RequestHandlerInterface;\n    }\n\n    /**\n     * @param mixed $toResolve\n     */\n    private function isMiddleware($toResolve): bool\n    {\n        return $toResolve instanceof MiddlewareInterface;\n    }\n\n    /**\n     * @throws RuntimeException\n     *\n     * @return array{object, string|null} [Instance, Method Name]\n     */\n    private function resolveSlimNotation(string $toResolve): array\n    {\n        preg_match(CallableResolver::$callablePattern, $toResolve, $matches);\n        [$class, $method] = $matches ? [$matches[1], $matches[2]] : [$toResolve, null];\n\n        /** @var string $class */\n        /** @var string|null $method */\n        if ($this->container && $this->container->has($class)) {\n            $instance = $this->container->get($class);\n            if (!is_object($instance)) {\n                throw new RuntimeException(sprintf('%s container entry is not an object', $class));\n            }\n        } else {\n            if (!class_exists($class)) {\n                if ($method) {\n                    $class .= '::' . $method . '()';\n                }\n                throw new RuntimeException(sprintf('Callable %s does not exist', $class));\n            }\n            $instance = new $class($this->container);\n        }\n        return [$instance, $method];\n    }\n\n    /**\n     * @param mixed $resolved\n     * @param mixed $toResolve\n     *\n     * @throws RuntimeException\n     */\n    private function assertCallable($resolved, $toResolve): callable\n    {\n        if (!is_callable($resolved)) {\n            if (is_callable($toResolve) || is_object($toResolve) || is_array($toResolve)) {\n                $formatedToResolve = ($toResolveJson = json_encode($toResolve)) !== false ? $toResolveJson : '';\n            } else {\n                $formatedToResolve = is_string($toResolve) ? $toResolve : '';\n            }\n            throw new RuntimeException(sprintf('%s is not resolvable', $formatedToResolve));\n        }\n        return $resolved;\n    }\n\n    private function bindToContainer(callable $callable): callable\n    {\n        if (is_array($callable) && $callable[0] instanceof Closure) {\n            $callable = $callable[0];\n        }\n        if ($this->container && $callable instanceof Closure) {\n            /** @var Closure $callable */\n            $callable = $callable->bindTo($this->container);\n        }\n        return $callable;\n    }\n\n    /**\n     * @param string|callable $toResolve\n     * @return string|callable\n     */\n    private function prepareToResolve($toResolve)\n    {\n        if (!is_array($toResolve)) {\n            return $toResolve;\n        }\n        $candidate = $toResolve;\n        $class = array_shift($candidate);\n        $method = array_shift($candidate);\n        if (is_string($class) && is_string($method)) {\n            return $class . ':' . $method;\n        }\n        return $toResolve;\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Error/AbstractErrorRenderer.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Error;\n\nuse Slim\\Exception\\HttpException;\nuse Slim\\Interfaces\\ErrorRendererInterface;\nuse Throwable;\n\n/**\n * Abstract Slim application error renderer\n *\n * It outputs the error message and diagnostic information in one of the following formats:\n * JSON, XML, Plain Text or HTML\n */\nabstract class AbstractErrorRenderer implements ErrorRendererInterface\n{\n    protected string $defaultErrorTitle = 'Slim Application Error';\n\n    protected string $defaultErrorDescription = 'A website error has occurred. Sorry for the temporary inconvenience.';\n\n    protected function getErrorTitle(Throwable $exception): string\n    {\n        if ($exception instanceof HttpException) {\n            return $exception->getTitle();\n        }\n\n        return $this->defaultErrorTitle;\n    }\n\n    protected function getErrorDescription(Throwable $exception): string\n    {\n        if ($exception instanceof HttpException) {\n            return $exception->getDescription();\n        }\n\n        return $this->defaultErrorDescription;\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Error/Renderers/HtmlErrorRenderer.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Error\\Renderers;\n\nuse Slim\\Error\\AbstractErrorRenderer;\nuse Throwable;\n\nuse function get_class;\nuse function htmlentities;\nuse function sprintf;\n\n/**\n * Default Slim application HTML Error Renderer\n */\nclass HtmlErrorRenderer extends AbstractErrorRenderer\n{\n    public function __invoke(Throwable $exception, bool $displayErrorDetails): string\n    {\n        if ($displayErrorDetails) {\n            $html = '<p>The application could not run because of the following error:</p>';\n            $html .= '<h2>Details</h2>';\n            $html .= $this->renderExceptionFragment($exception);\n        } else {\n            $html = \"<p>{$this->getErrorDescription($exception)}</p>\";\n        }\n\n        return $this->renderHtmlBody($this->getErrorTitle($exception), $html);\n    }\n\n    private function renderExceptionFragment(Throwable $exception): string\n    {\n        $html = sprintf('<div><strong>Type:</strong> %s</div>', get_class($exception));\n\n        /** @var int|string $code */\n        $code = $exception->getCode();\n        $html .= sprintf('<div><strong>Code:</strong> %s</div>', $code);\n\n        $html .= sprintf('<div><strong>Message:</strong> %s</div>', htmlentities($exception->getMessage()));\n\n        $html .= sprintf('<div><strong>File:</strong> %s</div>', $exception->getFile());\n\n        $html .= sprintf('<div><strong>Line:</strong> %s</div>', $exception->getLine());\n\n        $html .= '<h2>Trace</h2>';\n        $html .= sprintf('<pre>%s</pre>', htmlentities($exception->getTraceAsString()));\n\n        return $html;\n    }\n\n    public function renderHtmlBody(string $title = '', string $html = ''): string\n    {\n        return sprintf(\n            '<!doctype html>' .\n            '<html lang=\"en\">' .\n            '    <head>' .\n            '        <meta charset=\"utf-8\">' .\n            '        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">' .\n            '        <title>%s</title>' .\n            '        <style>' .\n            '            body{margin:0;padding:30px;font:12px/1.5 Helvetica,Arial,Verdana,sans-serif}' .\n            '            h1{margin:0;font-size:48px;font-weight:normal;line-height:48px}' .\n            '            strong{display:inline-block;width:65px}' .\n            '        </style>' .\n            '    </head>' .\n            '    <body>' .\n            '        <h1>%s</h1>' .\n            '        <div>%s</div>' .\n            '        <a href=\"#\" onclick=\"window.history.go(-1)\">Go Back</a>' .\n            '    </body>' .\n            '</html>',\n            $title,\n            $title,\n            $html\n        );\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Error/Renderers/JsonErrorRenderer.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Error\\Renderers;\n\nuse Slim\\Error\\AbstractErrorRenderer;\nuse Throwable;\n\nuse function get_class;\nuse function json_encode;\n\nuse const JSON_PRETTY_PRINT;\nuse const JSON_UNESCAPED_SLASHES;\n\n/**\n * Default Slim application JSON Error Renderer\n */\nclass JsonErrorRenderer extends AbstractErrorRenderer\n{\n    public function __invoke(Throwable $exception, bool $displayErrorDetails): string\n    {\n        $error = ['message' => $this->getErrorTitle($exception)];\n\n        if ($displayErrorDetails) {\n            $error['exception'] = [];\n            do {\n                $error['exception'][] = $this->formatExceptionFragment($exception);\n            } while ($exception = $exception->getPrevious());\n        }\n\n        return (string) json_encode($error, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);\n    }\n\n    /**\n     * @return array<string|int>\n     */\n    private function formatExceptionFragment(Throwable $exception): array\n    {\n        /** @var int|string $code */\n        $code = $exception->getCode();\n        return [\n            'type' => get_class($exception),\n            'code' => $code,\n            'message' => $exception->getMessage(),\n            'file' => $exception->getFile(),\n            'line' => $exception->getLine(),\n        ];\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Error/Renderers/PlainTextErrorRenderer.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Error\\Renderers;\n\nuse Slim\\Error\\AbstractErrorRenderer;\nuse Throwable;\n\nuse function get_class;\nuse function htmlentities;\nuse function sprintf;\n\n/**\n * Default Slim application Plain Text Error Renderer\n */\nclass PlainTextErrorRenderer extends AbstractErrorRenderer\n{\n    public function __invoke(Throwable $exception, bool $displayErrorDetails): string\n    {\n        $text = \"{$this->getErrorTitle($exception)}\\n\";\n\n        if ($displayErrorDetails) {\n            $text .= $this->formatExceptionFragment($exception);\n\n            while ($exception = $exception->getPrevious()) {\n                $text .= \"\\nPrevious Error:\\n\";\n                $text .= $this->formatExceptionFragment($exception);\n            }\n        }\n\n        return $text;\n    }\n\n    private function formatExceptionFragment(Throwable $exception): string\n    {\n        $text = sprintf(\"Type: %s\\n\", get_class($exception));\n\n        $code = $exception->getCode();\n        /** @var int|string $code */\n        $text .= sprintf(\"Code: %s\\n\", $code);\n\n        $text .= sprintf(\"Message: %s\\n\", htmlentities($exception->getMessage()));\n\n        $text .= sprintf(\"File: %s\\n\", $exception->getFile());\n\n        $text .= sprintf(\"Line: %s\\n\", $exception->getLine());\n\n        $text .= sprintf('Trace: %s', $exception->getTraceAsString());\n\n        return $text;\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Error/Renderers/XmlErrorRenderer.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Error\\Renderers;\n\nuse Slim\\Error\\AbstractErrorRenderer;\nuse Throwable;\n\nuse function get_class;\nuse function sprintf;\nuse function str_replace;\n\n/**\n * Default Slim application XML Error Renderer\n */\nclass XmlErrorRenderer extends AbstractErrorRenderer\n{\n    public function __invoke(Throwable $exception, bool $displayErrorDetails): string\n    {\n        $xml = '<' . '?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?' . \">\\n\";\n        $xml .= \"<error>\\n  <message>\" . $this->createCdataSection($this->getErrorTitle($exception)) . \"</message>\\n\";\n\n        if ($displayErrorDetails) {\n            do {\n                $xml .= \"  <exception>\\n\";\n                $xml .= '    <type>' . get_class($exception) . \"</type>\\n\";\n                $xml .= '    <code>' . $exception->getCode() . \"</code>\\n\";\n                $xml .= '    <message>' . $this->createCdataSection($exception->getMessage()) . \"</message>\\n\";\n                $xml .= '    <file>' . $exception->getFile() . \"</file>\\n\";\n                $xml .= '    <line>' . $exception->getLine() . \"</line>\\n\";\n                $xml .= \"  </exception>\\n\";\n            } while ($exception = $exception->getPrevious());\n        }\n\n        $xml .= '</error>';\n\n        return $xml;\n    }\n\n    /**\n     * Returns a CDATA section with the given content.\n     */\n    private function createCdataSection(string $content): string\n    {\n        return sprintf('<![CDATA[%s]]>', str_replace(']]>', ']]]]><![CDATA[>', $content));\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Exception/HttpBadRequestException.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Exception;\n\nclass HttpBadRequestException extends HttpSpecializedException\n{\n    /**\n     * @var int\n     */\n    protected $code = 400;\n\n    /**\n     * @var string\n     */\n    protected $message = 'Bad request.';\n\n    protected string $title = '400 Bad Request';\n    protected string $description = 'The server cannot or will not process ' .\n        'the request due to an apparent client error.';\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Exception/HttpException.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Exception;\n\nuse Psr\\Http\\Message\\ServerRequestInterface;\nuse RuntimeException;\nuse Throwable;\n\n/**\n * @method int getCode()\n */\nclass HttpException extends RuntimeException\n{\n    protected ServerRequestInterface $request;\n\n    protected string $title = '';\n\n    protected string $description = '';\n\n    public function __construct(\n        ServerRequestInterface $request,\n        string $message = '',\n        int $code = 0,\n        ?Throwable $previous = null\n    ) {\n        parent::__construct($message, $code, $previous);\n        $this->request = $request;\n    }\n\n    public function getRequest(): ServerRequestInterface\n    {\n        return $this->request;\n    }\n\n    public function getTitle(): string\n    {\n        return $this->title;\n    }\n\n    public function setTitle(string $title): self\n    {\n        $this->title = $title;\n        return $this;\n    }\n\n    public function getDescription(): string\n    {\n        return $this->description;\n    }\n\n    public function setDescription(string $description): self\n    {\n        $this->description = $description;\n        return $this;\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Exception/HttpForbiddenException.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Exception;\n\nclass HttpForbiddenException extends HttpSpecializedException\n{\n    /**\n     * @var int\n     */\n    protected $code = 403;\n\n    /**\n     * @var string\n     */\n    protected $message = 'Forbidden.';\n\n    protected string $title = '403 Forbidden';\n    protected string $description = 'You are not permitted to perform the requested operation.';\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Exception/HttpGoneException.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Exception;\n\nclass HttpGoneException extends HttpSpecializedException\n{\n    /**\n     * @var int\n     */\n    protected $code = 410;\n\n    /**\n     * @var string\n     */\n    protected $message = 'Gone.';\n\n    protected string $title = '410 Gone';\n    protected string $description = 'The target resource is no longer available at the origin server.';\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Exception/HttpInternalServerErrorException.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Exception;\n\nclass HttpInternalServerErrorException extends HttpSpecializedException\n{\n    /**\n     * @var int\n     */\n    protected $code = 500;\n\n    /**\n     * @var string\n     */\n    protected $message = 'Internal server error.';\n\n    protected string $title = '500 Internal Server Error';\n    protected string $description = 'Unexpected condition encountered preventing server from fulfilling request.';\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Exception/HttpMethodNotAllowedException.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Exception;\n\nuse function implode;\n\nclass HttpMethodNotAllowedException extends HttpSpecializedException\n{\n    /**\n     * @var string[]\n     */\n    protected array $allowedMethods = [];\n\n    /**\n     * @var int\n     */\n    protected $code = 405;\n\n    /**\n     * @var string\n     */\n    protected $message = 'Method not allowed.';\n\n    protected string $title = '405 Method Not Allowed';\n    protected string $description = 'The request method is not supported for the requested resource.';\n\n    /**\n     * @return string[]\n     */\n    public function getAllowedMethods(): array\n    {\n        return $this->allowedMethods;\n    }\n\n    /**\n     * @param string[] $methods\n     */\n    public function setAllowedMethods(array $methods): self\n    {\n        $this->allowedMethods = $methods;\n        $this->message = 'Method not allowed. Must be one of: ' . implode(', ', $methods);\n        return $this;\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Exception/HttpNotFoundException.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Exception;\n\nclass HttpNotFoundException extends HttpSpecializedException\n{\n    /**\n     * @var int\n     */\n    protected $code = 404;\n\n    /**\n     * @var string\n     */\n    protected $message = 'Not found.';\n\n    protected string $title = '404 Not Found';\n    protected string $description = 'The requested resource could not be found. Please verify the URI and try again.';\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Exception/HttpNotImplementedException.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Exception;\n\nclass HttpNotImplementedException extends HttpSpecializedException\n{\n    /**\n     * @var int\n     */\n    protected $code = 501;\n\n    /**\n     * @var string\n     */\n    protected $message = 'Not implemented.';\n\n    protected string $title = '501 Not Implemented';\n    protected string $description = 'The server does not support the functionality required to fulfill the request.';\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Exception/HttpSpecializedException.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Exception;\n\nuse Psr\\Http\\Message\\ServerRequestInterface;\nuse Throwable;\n\nabstract class HttpSpecializedException extends HttpException\n{\n    /**\n     * @param ServerRequestInterface $request\n     * @param string|null            $message\n     * @param Throwable|null         $previous\n     */\n    public function __construct(ServerRequestInterface $request, ?string $message = null, ?Throwable $previous = null)\n    {\n        if ($message !== null) {\n            $this->message = $message;\n        }\n\n        parent::__construct($request, $this->message, $this->code, $previous);\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Exception/HttpTooManyRequestsException.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Exception;\n\nclass HttpTooManyRequestsException extends HttpSpecializedException\n{\n    /**\n     * @var int\n     */\n    protected $code = 429;\n\n    /**\n     * @var string\n     */\n    protected $message = 'Too many requests.';\n\n    protected string $title = '429 Too Many Requests';\n    protected string $description = 'The client application has surpassed its rate limit, ' .\n                                    'or number of requests they can send in a given period of time.';\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Exception/HttpUnauthorizedException.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Exception;\n\nclass HttpUnauthorizedException extends HttpSpecializedException\n{\n    /**\n     * @var int\n     */\n    protected $code = 401;\n\n    /**\n     * @var string\n     */\n    protected $message = 'Unauthorized.';\n\n    protected string $title = '401 Unauthorized';\n    protected string $description = 'The request requires valid user authentication.';\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Factory/AppFactory.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Factory;\n\nuse Psr\\Container\\ContainerInterface;\nuse Psr\\Http\\Message\\ResponseFactoryInterface;\nuse Psr\\Http\\Message\\StreamFactoryInterface;\nuse RuntimeException;\nuse Slim\\App;\nuse Slim\\Factory\\Psr17\\Psr17Factory;\nuse Slim\\Factory\\Psr17\\Psr17FactoryProvider;\nuse Slim\\Factory\\Psr17\\SlimHttpPsr17Factory;\nuse Slim\\Interfaces\\CallableResolverInterface;\nuse Slim\\Interfaces\\MiddlewareDispatcherInterface;\nuse Slim\\Interfaces\\Psr17FactoryProviderInterface;\nuse Slim\\Interfaces\\RouteCollectorInterface;\nuse Slim\\Interfaces\\RouteResolverInterface;\n\nclass AppFactory\n{\n    protected static ?Psr17FactoryProviderInterface $psr17FactoryProvider = null;\n\n    protected static ?ResponseFactoryInterface $responseFactory = null;\n\n    protected static ?StreamFactoryInterface $streamFactory = null;\n\n    protected static ?ContainerInterface $container = null;\n\n    protected static ?CallableResolverInterface $callableResolver = null;\n\n    protected static ?RouteCollectorInterface $routeCollector = null;\n\n    protected static ?RouteResolverInterface $routeResolver = null;\n\n    protected static ?MiddlewareDispatcherInterface $middlewareDispatcher = null;\n\n    protected static bool $slimHttpDecoratorsAutomaticDetectionEnabled = true;\n\n    public static function create(\n        ?ResponseFactoryInterface $responseFactory = null,\n        ?ContainerInterface $container = null,\n        ?CallableResolverInterface $callableResolver = null,\n        ?RouteCollectorInterface $routeCollector = null,\n        ?RouteResolverInterface $routeResolver = null,\n        ?MiddlewareDispatcherInterface $middlewareDispatcher = null\n    ): App {\n        static::$responseFactory = $responseFactory ?? static::$responseFactory;\n        return new App(\n            self::determineResponseFactory(),\n            $container ?? static::$container,\n            $callableResolver ?? static::$callableResolver,\n            $routeCollector ?? static::$routeCollector,\n            $routeResolver ?? static::$routeResolver,\n            $middlewareDispatcher ?? static::$middlewareDispatcher\n        );\n    }\n\n    public static function createFromContainer(ContainerInterface $container): App\n    {\n        $responseFactory = $container->has(ResponseFactoryInterface::class)\n        && (\n            $responseFactoryFromContainer = $container->get(ResponseFactoryInterface::class)\n        ) instanceof ResponseFactoryInterface\n            ? $responseFactoryFromContainer\n            : self::determineResponseFactory();\n\n        $callableResolver = $container->has(CallableResolverInterface::class)\n        && (\n            $callableResolverFromContainer = $container->get(CallableResolverInterface::class)\n        ) instanceof CallableResolverInterface\n            ? $callableResolverFromContainer\n            : null;\n\n        $routeCollector = $container->has(RouteCollectorInterface::class)\n        && (\n            $routeCollectorFromContainer = $container->get(RouteCollectorInterface::class)\n        ) instanceof RouteCollectorInterface\n            ? $routeCollectorFromContainer\n            : null;\n\n        $routeResolver = $container->has(RouteResolverInterface::class)\n        && (\n            $routeResolverFromContainer = $container->get(RouteResolverInterface::class)\n        ) instanceof RouteResolverInterface\n            ? $routeResolverFromContainer\n            : null;\n\n        $middlewareDispatcher = $container->has(MiddlewareDispatcherInterface::class)\n        && (\n            $middlewareDispatcherFromContainer = $container->get(MiddlewareDispatcherInterface::class)\n        ) instanceof MiddlewareDispatcherInterface\n            ? $middlewareDispatcherFromContainer\n            : null;\n\n        return new App(\n            $responseFactory,\n            $container,\n            $callableResolver,\n            $routeCollector,\n            $routeResolver,\n            $middlewareDispatcher\n        );\n    }\n\n    /**\n     * @throws RuntimeException\n     */\n    public static function determineResponseFactory(): ResponseFactoryInterface\n    {\n        if (static::$responseFactory) {\n            if (static::$streamFactory) {\n                return static::attemptResponseFactoryDecoration(static::$responseFactory, static::$streamFactory);\n            }\n            return static::$responseFactory;\n        }\n\n        $psr17FactoryProvider = static::$psr17FactoryProvider ?? new Psr17FactoryProvider();\n\n        /** @var Psr17Factory $psr17factory */\n        foreach ($psr17FactoryProvider->getFactories() as $psr17factory) {\n            if ($psr17factory::isResponseFactoryAvailable()) {\n                $responseFactory = $psr17factory::getResponseFactory();\n\n                if (static::$streamFactory || $psr17factory::isStreamFactoryAvailable()) {\n                    $streamFactory = static::$streamFactory ?? $psr17factory::getStreamFactory();\n                    return static::attemptResponseFactoryDecoration($responseFactory, $streamFactory);\n                }\n\n                return $responseFactory;\n            }\n        }\n\n        throw new RuntimeException(\n            \"Could not detect any PSR-17 ResponseFactory implementations. \" .\n            \"Please install a supported implementation in order to use `AppFactory::create()`. \" .\n            \"See https://github.com/slimphp/Slim/blob/4.x/README.md for a list of supported implementations.\"\n        );\n    }\n\n    protected static function attemptResponseFactoryDecoration(\n        ResponseFactoryInterface $responseFactory,\n        StreamFactoryInterface $streamFactory\n    ): ResponseFactoryInterface {\n        if (\n            static::$slimHttpDecoratorsAutomaticDetectionEnabled\n            && SlimHttpPsr17Factory::isResponseFactoryAvailable()\n        ) {\n            return SlimHttpPsr17Factory::createDecoratedResponseFactory($responseFactory, $streamFactory);\n        }\n\n        return $responseFactory;\n    }\n\n    public static function setPsr17FactoryProvider(Psr17FactoryProviderInterface $psr17FactoryProvider): void\n    {\n        static::$psr17FactoryProvider = $psr17FactoryProvider;\n    }\n\n    public static function setResponseFactory(ResponseFactoryInterface $responseFactory): void\n    {\n        static::$responseFactory = $responseFactory;\n    }\n\n    public static function setStreamFactory(StreamFactoryInterface $streamFactory): void\n    {\n        static::$streamFactory = $streamFactory;\n    }\n\n    public static function setContainer(ContainerInterface $container): void\n    {\n        static::$container = $container;\n    }\n\n    public static function setCallableResolver(CallableResolverInterface $callableResolver): void\n    {\n        static::$callableResolver = $callableResolver;\n    }\n\n    public static function setRouteCollector(RouteCollectorInterface $routeCollector): void\n    {\n        static::$routeCollector = $routeCollector;\n    }\n\n    public static function setRouteResolver(RouteResolverInterface $routeResolver): void\n    {\n        static::$routeResolver = $routeResolver;\n    }\n\n    public static function setMiddlewareDispatcher(MiddlewareDispatcherInterface $middlewareDispatcher): void\n    {\n        static::$middlewareDispatcher = $middlewareDispatcher;\n    }\n\n    public static function setSlimHttpDecoratorsAutomaticDetection(bool $enabled): void\n    {\n        static::$slimHttpDecoratorsAutomaticDetectionEnabled = $enabled;\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Factory/Psr17/GuzzlePsr17Factory.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Factory\\Psr17;\n\nclass GuzzlePsr17Factory extends Psr17Factory\n{\n    protected static string $responseFactoryClass = 'GuzzleHttp\\Psr7\\HttpFactory';\n    protected static string $streamFactoryClass = 'GuzzleHttp\\Psr7\\HttpFactory';\n    protected static string $serverRequestCreatorClass = 'GuzzleHttp\\Psr7\\ServerRequest';\n    protected static string $serverRequestCreatorMethod = 'fromGlobals';\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Factory/Psr17/HttpSoftPsr17Factory.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Factory\\Psr17;\n\nclass HttpSoftPsr17Factory extends Psr17Factory\n{\n    protected static string $responseFactoryClass = 'HttpSoft\\Message\\ResponseFactory';\n    protected static string $streamFactoryClass = 'HttpSoft\\Message\\StreamFactory';\n    protected static string $serverRequestCreatorClass = 'HttpSoft\\ServerRequest\\ServerRequestCreator';\n    protected static string $serverRequestCreatorMethod = 'createFromGlobals';\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Factory/Psr17/LaminasDiactorosPsr17Factory.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Factory\\Psr17;\n\nclass LaminasDiactorosPsr17Factory extends Psr17Factory\n{\n    protected static string $responseFactoryClass = 'Laminas\\Diactoros\\ResponseFactory';\n    protected static string $streamFactoryClass = 'Laminas\\Diactoros\\StreamFactory';\n    protected static string $serverRequestCreatorClass = 'Laminas\\Diactoros\\ServerRequestFactory';\n    protected static string $serverRequestCreatorMethod = 'fromGlobals';\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Factory/Psr17/NyholmPsr17Factory.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Factory\\Psr17;\n\nuse Slim\\Interfaces\\ServerRequestCreatorInterface;\n\nclass NyholmPsr17Factory extends Psr17Factory\n{\n    protected static string $responseFactoryClass = 'Nyholm\\Psr7\\Factory\\Psr17Factory';\n    protected static string $streamFactoryClass = 'Nyholm\\Psr7\\Factory\\Psr17Factory';\n    protected static string $serverRequestCreatorClass = 'Nyholm\\Psr7Server\\ServerRequestCreator';\n    protected static string $serverRequestCreatorMethod = 'fromGlobals';\n\n    /**\n     * {@inheritdoc}\n     */\n    public static function getServerRequestCreator(): ServerRequestCreatorInterface\n    {\n        /*\n         * Nyholm Psr17Factory implements all factories in one unified\n         * factory which implements all of the PSR-17 factory interfaces\n         */\n        $psr17Factory = new static::$responseFactoryClass();\n\n        $serverRequestCreator = new static::$serverRequestCreatorClass(\n            $psr17Factory,\n            $psr17Factory,\n            $psr17Factory,\n            $psr17Factory\n        );\n\n        return new ServerRequestCreator($serverRequestCreator, static::$serverRequestCreatorMethod);\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Factory/Psr17/Psr17Factory.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Factory\\Psr17;\n\nuse Psr\\Http\\Message\\ResponseFactoryInterface;\nuse Psr\\Http\\Message\\StreamFactoryInterface;\nuse RuntimeException;\nuse Slim\\Interfaces\\Psr17FactoryInterface;\nuse Slim\\Interfaces\\ServerRequestCreatorInterface;\n\nuse function class_exists;\nuse function get_called_class;\n\nabstract class Psr17Factory implements Psr17FactoryInterface\n{\n    protected static string $responseFactoryClass;\n\n    protected static string $streamFactoryClass;\n\n    protected static string $serverRequestCreatorClass;\n\n    protected static string $serverRequestCreatorMethod;\n\n    /**\n     * {@inheritdoc}\n     */\n    public static function getResponseFactory(): ResponseFactoryInterface\n    {\n        if (\n            !static::isResponseFactoryAvailable()\n            || !(($responseFactory = new static::$responseFactoryClass()) instanceof ResponseFactoryInterface)\n        ) {\n            throw new RuntimeException(get_called_class() . ' could not instantiate a response factory.');\n        }\n\n        return $responseFactory;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public static function getStreamFactory(): StreamFactoryInterface\n    {\n        if (\n            !static::isStreamFactoryAvailable()\n            || !(($streamFactory = new static::$streamFactoryClass()) instanceof StreamFactoryInterface)\n        ) {\n            throw new RuntimeException(get_called_class() . ' could not instantiate a stream factory.');\n        }\n\n        return $streamFactory;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public static function getServerRequestCreator(): ServerRequestCreatorInterface\n    {\n        if (!static::isServerRequestCreatorAvailable()) {\n            throw new RuntimeException(get_called_class() . ' could not instantiate a server request creator.');\n        }\n\n        return new ServerRequestCreator(static::$serverRequestCreatorClass, static::$serverRequestCreatorMethod);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public static function isResponseFactoryAvailable(): bool\n    {\n        return static::$responseFactoryClass && class_exists(static::$responseFactoryClass);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public static function isStreamFactoryAvailable(): bool\n    {\n        return static::$streamFactoryClass && class_exists(static::$streamFactoryClass);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public static function isServerRequestCreatorAvailable(): bool\n    {\n        return (\n            static::$serverRequestCreatorClass\n            && static::$serverRequestCreatorMethod\n            && class_exists(static::$serverRequestCreatorClass)\n        );\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Factory/Psr17/Psr17FactoryProvider.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Factory\\Psr17;\n\nuse Slim\\Interfaces\\Psr17FactoryProviderInterface;\n\nuse function array_unshift;\n\nclass Psr17FactoryProvider implements Psr17FactoryProviderInterface\n{\n    /**\n     * @var string[]\n     */\n    protected static array $factories = [\n        SlimPsr17Factory::class,\n        HttpSoftPsr17Factory::class,\n        NyholmPsr17Factory::class,\n        LaminasDiactorosPsr17Factory::class,\n        GuzzlePsr17Factory::class,\n    ];\n\n    /**\n     * {@inheritdoc}\n     */\n    public static function getFactories(): array\n    {\n        return static::$factories;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public static function setFactories(array $factories): void\n    {\n        static::$factories = $factories;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public static function addFactory(string $factory): void\n    {\n        array_unshift(static::$factories, $factory);\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Factory/Psr17/ServerRequestCreator.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Factory\\Psr17;\n\nuse Closure;\nuse Psr\\Http\\Message\\ServerRequestInterface;\nuse Slim\\Interfaces\\ServerRequestCreatorInterface;\n\nclass ServerRequestCreator implements ServerRequestCreatorInterface\n{\n    /**\n     * @var object|string\n     */\n    protected $serverRequestCreator;\n\n    protected string $serverRequestCreatorMethod;\n\n    /**\n     * @param object|string $serverRequestCreator\n     */\n    public function __construct($serverRequestCreator, string $serverRequestCreatorMethod)\n    {\n        $this->serverRequestCreator = $serverRequestCreator;\n        $this->serverRequestCreatorMethod = $serverRequestCreatorMethod;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function createServerRequestFromGlobals(): ServerRequestInterface\n    {\n        /** @var callable $callable */\n        $callable = [$this->serverRequestCreator, $this->serverRequestCreatorMethod];\n        return (Closure::fromCallable($callable))();\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Factory/Psr17/SlimHttpPsr17Factory.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Factory\\Psr17;\n\nuse Psr\\Http\\Message\\ResponseFactoryInterface;\nuse Psr\\Http\\Message\\StreamFactoryInterface;\nuse RuntimeException;\n\nclass SlimHttpPsr17Factory extends Psr17Factory\n{\n    protected static string $responseFactoryClass = 'Slim\\Http\\Factory\\DecoratedResponseFactory';\n\n    /**\n     * @throws RuntimeException when the factory could not be instantiated\n     */\n    public static function createDecoratedResponseFactory(\n        ResponseFactoryInterface $responseFactory,\n        StreamFactoryInterface $streamFactory\n    ): ResponseFactoryInterface {\n        if (\n            !((\n                $decoratedResponseFactory = new static::$responseFactoryClass($responseFactory, $streamFactory)\n                ) instanceof ResponseFactoryInterface\n            )\n        ) {\n            throw new RuntimeException(get_called_class() . ' could not instantiate a decorated response factory.');\n        }\n\n        return $decoratedResponseFactory;\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Factory/Psr17/SlimHttpServerRequestCreator.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Factory\\Psr17;\n\nuse Psr\\Http\\Message\\ServerRequestInterface;\nuse RuntimeException;\nuse Slim\\Interfaces\\ServerRequestCreatorInterface;\n\nuse function class_exists;\n\nclass SlimHttpServerRequestCreator implements ServerRequestCreatorInterface\n{\n    protected ServerRequestCreatorInterface $serverRequestCreator;\n\n    protected static string $serverRequestDecoratorClass = 'Slim\\Http\\ServerRequest';\n\n    public function __construct(ServerRequestCreatorInterface $serverRequestCreator)\n    {\n        $this->serverRequestCreator = $serverRequestCreator;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function createServerRequestFromGlobals(): ServerRequestInterface\n    {\n        if (!static::isServerRequestDecoratorAvailable()) {\n            throw new RuntimeException('The Slim-Http ServerRequest decorator is not available.');\n        }\n\n        $request = $this->serverRequestCreator->createServerRequestFromGlobals();\n\n        if (\n            !((\n                $decoratedServerRequest = new static::$serverRequestDecoratorClass($request)\n                ) instanceof ServerRequestInterface)\n        ) {\n            throw new RuntimeException(get_called_class() . ' could not instantiate a decorated server request.');\n        }\n\n        return $decoratedServerRequest;\n    }\n\n    public static function isServerRequestDecoratorAvailable(): bool\n    {\n        return class_exists(static::$serverRequestDecoratorClass);\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Factory/Psr17/SlimPsr17Factory.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Factory\\Psr17;\n\nclass SlimPsr17Factory extends Psr17Factory\n{\n    protected static string $responseFactoryClass = 'Slim\\Psr7\\Factory\\ResponseFactory';\n    protected static string $streamFactoryClass = 'Slim\\Psr7\\Factory\\StreamFactory';\n    protected static string $serverRequestCreatorClass = 'Slim\\Psr7\\Factory\\ServerRequestFactory';\n    protected static string $serverRequestCreatorMethod = 'createFromGlobals';\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Factory/ServerRequestCreatorFactory.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Factory;\n\nuse RuntimeException;\nuse Slim\\Factory\\Psr17\\Psr17Factory;\nuse Slim\\Factory\\Psr17\\Psr17FactoryProvider;\nuse Slim\\Factory\\Psr17\\SlimHttpServerRequestCreator;\nuse Slim\\Interfaces\\Psr17FactoryProviderInterface;\nuse Slim\\Interfaces\\ServerRequestCreatorInterface;\n\nclass ServerRequestCreatorFactory\n{\n    protected static ?Psr17FactoryProviderInterface $psr17FactoryProvider = null;\n\n    protected static ?ServerRequestCreatorInterface $serverRequestCreator = null;\n\n    protected static bool $slimHttpDecoratorsAutomaticDetectionEnabled = true;\n\n    public static function create(): ServerRequestCreatorInterface\n    {\n        return static::determineServerRequestCreator();\n    }\n\n    /**\n     * @throws RuntimeException\n     */\n    public static function determineServerRequestCreator(): ServerRequestCreatorInterface\n    {\n        if (static::$serverRequestCreator) {\n            return static::attemptServerRequestCreatorDecoration(static::$serverRequestCreator);\n        }\n\n        $psr17FactoryProvider = static::$psr17FactoryProvider ?? new Psr17FactoryProvider();\n\n        /** @var Psr17Factory $psr17Factory */\n        foreach ($psr17FactoryProvider->getFactories() as $psr17Factory) {\n            if ($psr17Factory::isServerRequestCreatorAvailable()) {\n                $serverRequestCreator = $psr17Factory::getServerRequestCreator();\n                return static::attemptServerRequestCreatorDecoration($serverRequestCreator);\n            }\n        }\n\n        throw new RuntimeException(\n            \"Could not detect any ServerRequest creator implementations. \" .\n            \"Please install a supported implementation in order to use `App::run()` \" .\n            \"without having to pass in a `ServerRequest` object. \" .\n            \"See https://github.com/slimphp/Slim/blob/4.x/README.md for a list of supported implementations.\"\n        );\n    }\n\n    protected static function attemptServerRequestCreatorDecoration(\n        ServerRequestCreatorInterface $serverRequestCreator\n    ): ServerRequestCreatorInterface {\n        if (\n            static::$slimHttpDecoratorsAutomaticDetectionEnabled\n            && SlimHttpServerRequestCreator::isServerRequestDecoratorAvailable()\n        ) {\n            return new SlimHttpServerRequestCreator($serverRequestCreator);\n        }\n\n        return $serverRequestCreator;\n    }\n\n    public static function setPsr17FactoryProvider(Psr17FactoryProviderInterface $psr17FactoryProvider): void\n    {\n        static::$psr17FactoryProvider = $psr17FactoryProvider;\n    }\n\n    public static function setServerRequestCreator(ServerRequestCreatorInterface $serverRequestCreator): void\n    {\n        self::$serverRequestCreator = $serverRequestCreator;\n    }\n\n    public static function setSlimHttpDecoratorsAutomaticDetection(bool $enabled): void\n    {\n        static::$slimHttpDecoratorsAutomaticDetectionEnabled = $enabled;\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Handlers/ErrorHandler.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Handlers;\n\nuse Psr\\Http\\Message\\ResponseFactoryInterface;\nuse Psr\\Http\\Message\\ResponseInterface;\nuse Psr\\Http\\Message\\ServerRequestInterface;\nuse Psr\\Log\\LoggerInterface;\nuse RuntimeException;\nuse Slim\\Error\\Renderers\\HtmlErrorRenderer;\nuse Slim\\Error\\Renderers\\JsonErrorRenderer;\nuse Slim\\Error\\Renderers\\PlainTextErrorRenderer;\nuse Slim\\Error\\Renderers\\XmlErrorRenderer;\nuse Slim\\Exception\\HttpException;\nuse Slim\\Exception\\HttpMethodNotAllowedException;\nuse Slim\\Interfaces\\CallableResolverInterface;\nuse Slim\\Interfaces\\ErrorHandlerInterface;\nuse Slim\\Interfaces\\ErrorRendererInterface;\nuse Slim\\Logger;\nuse Throwable;\n\nuse function array_intersect;\nuse function array_key_exists;\nuse function array_keys;\nuse function call_user_func;\nuse function count;\nuse function current;\nuse function explode;\nuse function implode;\nuse function next;\nuse function preg_match;\n\n/**\n * Default Slim application error handler\n *\n * It outputs the error message and diagnostic information in one of the following formats:\n * JSON, XML, Plain Text or HTML based on the Accept header.\n */\nclass ErrorHandler implements ErrorHandlerInterface\n{\n    protected string $defaultErrorRendererContentType = 'text/html';\n\n    /**\n     * @var ErrorRendererInterface|string|callable\n     */\n    protected $defaultErrorRenderer = HtmlErrorRenderer::class;\n\n    /**\n     * @var ErrorRendererInterface|string|callable\n     */\n    protected $logErrorRenderer = PlainTextErrorRenderer::class;\n\n    /**\n     * @var array<string|callable>\n     */\n    protected array $errorRenderers = [\n        'application/json' => JsonErrorRenderer::class,\n        'application/xml' => XmlErrorRenderer::class,\n        'text/xml' => XmlErrorRenderer::class,\n        'text/html' => HtmlErrorRenderer::class,\n        'text/plain' => PlainTextErrorRenderer::class,\n    ];\n\n    protected bool $displayErrorDetails = false;\n\n    protected bool $logErrors;\n\n    protected bool $logErrorDetails = false;\n\n    protected ?string $contentType = null;\n\n    protected ?string $method = null;\n\n    protected ServerRequestInterface $request;\n\n    protected Throwable $exception;\n\n    protected int $statusCode;\n\n    protected CallableResolverInterface $callableResolver;\n\n    protected ResponseFactoryInterface $responseFactory;\n\n    protected LoggerInterface $logger;\n\n    public function __construct(\n        CallableResolverInterface $callableResolver,\n        ResponseFactoryInterface $responseFactory,\n        ?LoggerInterface $logger = null\n    ) {\n        $this->callableResolver = $callableResolver;\n        $this->responseFactory = $responseFactory;\n        $this->logger = $logger ?: $this->getDefaultLogger();\n    }\n\n    /**\n     * Invoke error handler\n     *\n     * @param ServerRequestInterface $request             The most recent Request object\n     * @param Throwable              $exception           The caught Exception object\n     * @param bool                   $displayErrorDetails Whether or not to display the error details\n     * @param bool                   $logErrors           Whether or not to log errors\n     * @param bool                   $logErrorDetails     Whether or not to log error details\n     */\n    public function __invoke(\n        ServerRequestInterface $request,\n        Throwable $exception,\n        bool $displayErrorDetails,\n        bool $logErrors,\n        bool $logErrorDetails\n    ): ResponseInterface {\n        $this->displayErrorDetails = $displayErrorDetails;\n        $this->logErrors = $logErrors;\n        $this->logErrorDetails = $logErrorDetails;\n        $this->request = $request;\n        $this->exception = $exception;\n        $this->method = $request->getMethod();\n        $this->statusCode = $this->determineStatusCode();\n        if ($this->contentType === null) {\n            $this->contentType = $this->determineContentType($request);\n        }\n\n        if ($logErrors) {\n            $this->writeToErrorLog();\n        }\n\n        return $this->respond();\n    }\n\n    /**\n     * Force the content type for all error handler responses.\n     *\n     * @param string|null $contentType The content type\n     */\n    public function forceContentType(?string $contentType): void\n    {\n        $this->contentType = $contentType;\n    }\n\n    protected function determineStatusCode(): int\n    {\n        if ($this->method === 'OPTIONS') {\n            return 200;\n        }\n\n        if ($this->exception instanceof HttpException) {\n            return $this->exception->getCode();\n        }\n\n        return 500;\n    }\n\n    /**\n     * Determine which content type we know about is wanted using Accept header\n     *\n     * Note: This method is a bare-bones implementation designed specifically for\n     * Slim's error handling requirements. Consider a fully-feature solution such\n     * as willdurand/negotiation for any other situation.\n     */\n    protected function determineContentType(ServerRequestInterface $request): ?string\n    {\n        $acceptHeader = $request->getHeaderLine('Accept');\n        $selectedContentTypes = array_intersect(\n            explode(',', $acceptHeader),\n            array_keys($this->errorRenderers)\n        );\n        $count = count($selectedContentTypes);\n\n        if ($count) {\n            $current = current($selectedContentTypes);\n\n            /**\n             * Ensure other supported content types take precedence over text/plain\n             * when multiple content types are provided via Accept header.\n             */\n            if ($current === 'text/plain' && $count > 1) {\n                $next = next($selectedContentTypes);\n                if (is_string($next)) {\n                    return $next;\n                }\n            }\n\n            if (is_string($current)) {\n                return $current;\n            }\n        }\n\n        if (preg_match('/\\+(json|xml)/', $acceptHeader, $matches)) {\n            $mediaType = 'application/' . $matches[1];\n            if (array_key_exists($mediaType, $this->errorRenderers)) {\n                return $mediaType;\n            }\n        }\n\n        return null;\n    }\n\n    /**\n     * Determine which renderer to use based on content type\n     *\n     * @throws RuntimeException\n     */\n    protected function determineRenderer(): callable\n    {\n        if ($this->contentType !== null && array_key_exists($this->contentType, $this->errorRenderers)) {\n            $renderer = $this->errorRenderers[$this->contentType];\n        } else {\n            $renderer = $this->defaultErrorRenderer;\n        }\n\n        return $this->callableResolver->resolve($renderer);\n    }\n\n    /**\n     * Register an error renderer for a specific content-type\n     *\n     * @param string  $contentType  The content-type this renderer should be registered to\n     * @param ErrorRendererInterface|string|callable $errorRenderer The error renderer\n     */\n    public function registerErrorRenderer(string $contentType, $errorRenderer): void\n    {\n        $this->errorRenderers[$contentType] = $errorRenderer;\n    }\n\n    /**\n     * Set the default error renderer\n     *\n     * @param string                                 $contentType   The content type of the default error renderer\n     * @param ErrorRendererInterface|string|callable $errorRenderer The default error renderer\n     */\n    public function setDefaultErrorRenderer(string $contentType, $errorRenderer): void\n    {\n        $this->defaultErrorRendererContentType = $contentType;\n        $this->defaultErrorRenderer = $errorRenderer;\n    }\n\n    /**\n     * Set the renderer for the error logger\n     *\n     * @param ErrorRendererInterface|string|callable $logErrorRenderer\n     */\n    public function setLogErrorRenderer($logErrorRenderer): void\n    {\n        $this->logErrorRenderer = $logErrorRenderer;\n    }\n\n    /**\n     * Write to the error log if $logErrors has been set to true\n     */\n    protected function writeToErrorLog(): void\n    {\n        $renderer = $this->callableResolver->resolve($this->logErrorRenderer);\n        $error = $renderer($this->exception, $this->logErrorDetails);\n        if (!$this->displayErrorDetails) {\n            $error .= \"\\nTips: To display error details in HTTP response \";\n            $error .= 'set \"displayErrorDetails\" to true in the ErrorHandler constructor.';\n        }\n        $this->logError($error);\n    }\n\n    /**\n     * Wraps the error_log function so that this can be easily tested\n     */\n    protected function logError(string $error): void\n    {\n        $this->logger->error($error);\n    }\n\n    /**\n     * Returns a default logger implementation.\n     */\n    protected function getDefaultLogger(): LoggerInterface\n    {\n        return new Logger();\n    }\n\n    protected function respond(): ResponseInterface\n    {\n        $response = $this->responseFactory->createResponse($this->statusCode);\n        if ($this->contentType !== null && array_key_exists($this->contentType, $this->errorRenderers)) {\n            $response = $response->withHeader('Content-type', $this->contentType);\n        } else {\n            $response = $response->withHeader('Content-type', $this->defaultErrorRendererContentType);\n        }\n\n        if ($this->exception instanceof HttpMethodNotAllowedException) {\n            $allowedMethods = implode(', ', $this->exception->getAllowedMethods());\n            $response = $response->withHeader('Allow', $allowedMethods);\n        }\n\n        $renderer = $this->determineRenderer();\n        $body = call_user_func($renderer, $this->exception, $this->displayErrorDetails);\n        if ($body !== false) {\n            /** @var string $body */\n            $response->getBody()->write($body);\n        }\n\n        return $response;\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Handlers/Strategies/RequestHandler.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Handlers\\Strategies;\n\nuse Psr\\Http\\Message\\ResponseInterface;\nuse Psr\\Http\\Message\\ServerRequestInterface;\nuse Slim\\Interfaces\\RequestHandlerInvocationStrategyInterface;\n\n/**\n * PSR-15 RequestHandler invocation strategy\n */\nclass RequestHandler implements RequestHandlerInvocationStrategyInterface\n{\n    protected bool $appendRouteArgumentsToRequestAttributes;\n\n    public function __construct(bool $appendRouteArgumentsToRequestAttributes = false)\n    {\n        $this->appendRouteArgumentsToRequestAttributes = $appendRouteArgumentsToRequestAttributes;\n    }\n\n    /**\n     * Invoke a route callable that implements RequestHandlerInterface\n     *\n     * @param array<string, string>  $routeArguments\n     */\n    public function __invoke(\n        callable $callable,\n        ServerRequestInterface $request,\n        ResponseInterface $response,\n        array $routeArguments\n    ): ResponseInterface {\n        if ($this->appendRouteArgumentsToRequestAttributes) {\n            foreach ($routeArguments as $k => $v) {\n                $request = $request->withAttribute($k, $v);\n            }\n        }\n\n        return $callable($request);\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Handlers/Strategies/RequestResponse.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Handlers\\Strategies;\n\nuse Psr\\Http\\Message\\ResponseInterface;\nuse Psr\\Http\\Message\\ServerRequestInterface;\nuse Slim\\Interfaces\\InvocationStrategyInterface;\n\n/**\n * Default route callback strategy with route parameters as an array of arguments.\n */\nclass RequestResponse implements InvocationStrategyInterface\n{\n    /**\n     * Invoke a route callable with request, response, and all route parameters\n     * as an array of arguments.\n     *\n     * @param array<string, string>  $routeArguments\n     */\n    public function __invoke(\n        callable $callable,\n        ServerRequestInterface $request,\n        ResponseInterface $response,\n        array $routeArguments\n    ): ResponseInterface {\n        foreach ($routeArguments as $k => $v) {\n            $request = $request->withAttribute($k, $v);\n        }\n\n        return $callable($request, $response, $routeArguments);\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Handlers/Strategies/RequestResponseArgs.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Handlers\\Strategies;\n\nuse Psr\\Http\\Message\\ResponseInterface;\nuse Psr\\Http\\Message\\ServerRequestInterface;\nuse Slim\\Interfaces\\InvocationStrategyInterface;\n\nuse function array_values;\n\n/**\n * Route callback strategy with route parameters as individual arguments.\n */\nclass RequestResponseArgs implements InvocationStrategyInterface\n{\n    /**\n     * Invoke a route callable with request, response and all route parameters\n     * as individual arguments.\n     *\n     * @param array<string, string>  $routeArguments\n     */\n    public function __invoke(\n        callable $callable,\n        ServerRequestInterface $request,\n        ResponseInterface $response,\n        array $routeArguments\n    ): ResponseInterface {\n        return $callable($request, $response, ...array_values($routeArguments));\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Handlers/Strategies/RequestResponseNamedArgs.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Handlers\\Strategies;\n\nuse Psr\\Http\\Message\\ResponseInterface;\nuse Psr\\Http\\Message\\ServerRequestInterface;\nuse Slim\\Interfaces\\InvocationStrategyInterface;\nuse RuntimeException;\n\n/**\n * Route callback strategy with route parameters as individual arguments.\n */\nclass RequestResponseNamedArgs implements InvocationStrategyInterface\n{\n    public function __construct()\n    {\n        if (PHP_VERSION_ID < 80000) {\n            throw new RuntimeException('Named arguments are only available for PHP >= 8.0.0');\n        }\n    }\n\n    /**\n     * Invoke a route callable with request, response and all route parameters\n     * as individual arguments.\n     *\n     * @param array<string, string>  $routeArguments\n     */\n    public function __invoke(\n        callable $callable,\n        ServerRequestInterface $request,\n        ResponseInterface $response,\n        array $routeArguments\n    ): ResponseInterface {\n        return $callable($request, $response, ...$routeArguments);\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Interfaces/AdvancedCallableResolverInterface.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Interfaces;\n\ninterface AdvancedCallableResolverInterface extends CallableResolverInterface\n{\n    /**\n     * Resolve $toResolve into a callable\n     *\n     * @param string|callable $toResolve\n     */\n    public function resolveRoute($toResolve): callable;\n\n    /**\n     * Resolve $toResolve into a callable\n     *\n     * @param string|callable $toResolve\n     */\n    public function resolveMiddleware($toResolve): callable;\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Interfaces/CallableResolverInterface.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Interfaces;\n\ninterface CallableResolverInterface\n{\n    /**\n     * Resolve $toResolve into a callable\n     *\n     * @param string|callable $toResolve\n     */\n    public function resolve($toResolve): callable;\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Interfaces/DispatcherInterface.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Interfaces;\n\nuse Slim\\Routing\\RoutingResults;\n\ninterface DispatcherInterface\n{\n    /**\n     * Get routing results for a given request method and uri\n     */\n    public function dispatch(string $method, string $uri): RoutingResults;\n\n    /**\n     * Get allowed methods for a given uri\n     *\n     * @return string[]\n     */\n    public function getAllowedMethods(string $uri): array;\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Interfaces/ErrorHandlerInterface.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Interfaces;\n\nuse Psr\\Http\\Message\\ResponseInterface;\nuse Psr\\Http\\Message\\ServerRequestInterface;\nuse Throwable;\n\ninterface ErrorHandlerInterface\n{\n    public function __invoke(\n        ServerRequestInterface $request,\n        Throwable $exception,\n        bool $displayErrorDetails,\n        bool $logErrors,\n        bool $logErrorDetails\n    ): ResponseInterface;\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Interfaces/ErrorRendererInterface.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Interfaces;\n\nuse Throwable;\n\ninterface ErrorRendererInterface\n{\n    public function __invoke(Throwable $exception, bool $displayErrorDetails): string;\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Interfaces/InvocationStrategyInterface.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Interfaces;\n\nuse Psr\\Http\\Message\\ResponseInterface;\nuse Psr\\Http\\Message\\ServerRequestInterface;\n\n/**\n * Defines a contract for invoking a route callable.\n */\ninterface InvocationStrategyInterface\n{\n    /**\n     * Invoke a route callable.\n     *\n     * @param callable               $callable       The callable to invoke using the strategy.\n     * @param ServerRequestInterface $request        The request object.\n     * @param ResponseInterface      $response       The response object.\n     * @param array<string, string>  $routeArguments The route's placeholder arguments\n     *\n     * @return ResponseInterface The response from the callable.\n     */\n    public function __invoke(\n        callable $callable,\n        ServerRequestInterface $request,\n        ResponseInterface $response,\n        array $routeArguments\n    ): ResponseInterface;\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Interfaces/MiddlewareDispatcherInterface.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Interfaces;\n\nuse Psr\\Http\\Server\\MiddlewareInterface;\nuse Psr\\Http\\Server\\RequestHandlerInterface;\n\ninterface MiddlewareDispatcherInterface extends RequestHandlerInterface\n{\n    /**\n     * Add a new middleware to the stack\n     *\n     * Middleware are organized as a stack. That means middleware\n     * that have been added before will be executed after the newly\n     * added one (last in, first out).\n     *\n     * @param MiddlewareInterface|string|callable $middleware\n     */\n    public function add($middleware): self;\n\n    /**\n     * Add a new middleware to the stack\n     *\n     * Middleware are organized as a stack. That means middleware\n     * that have been added before will be executed after the newly\n     * added one (last in, first out).\n     */\n    public function addMiddleware(MiddlewareInterface $middleware): self;\n\n    /**\n     * Seed the middleware stack with the inner request handler\n     */\n    public function seedMiddlewareStack(RequestHandlerInterface $kernel): void;\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Interfaces/Psr17FactoryInterface.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Interfaces;\n\nuse Psr\\Http\\Message\\ResponseFactoryInterface;\nuse Psr\\Http\\Message\\StreamFactoryInterface;\nuse RuntimeException;\n\ninterface Psr17FactoryInterface\n{\n    /**\n     * @throws RuntimeException when the factory could not be instantiated\n     */\n    public static function getResponseFactory(): ResponseFactoryInterface;\n\n    /**\n     * @throws RuntimeException when the factory could not be instantiated\n     */\n    public static function getStreamFactory(): StreamFactoryInterface;\n\n    /**\n     * @throws RuntimeException when the factory could not be instantiated\n     */\n    public static function getServerRequestCreator(): ServerRequestCreatorInterface;\n\n    /**\n     * Is the PSR-17 ResponseFactory available\n     */\n    public static function isResponseFactoryAvailable(): bool;\n\n    /**\n     * Is the PSR-17 StreamFactory available\n     */\n    public static function isStreamFactoryAvailable(): bool;\n\n    /**\n     * Is the ServerRequest creator available\n     */\n    public static function isServerRequestCreatorAvailable(): bool;\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Interfaces/Psr17FactoryProviderInterface.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Interfaces;\n\ninterface Psr17FactoryProviderInterface\n{\n    /**\n     * @return string[]\n     */\n    public static function getFactories(): array;\n\n    /**\n     * @param string[] $factories\n     */\n    public static function setFactories(array $factories): void;\n\n    public static function addFactory(string $factory): void;\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Interfaces/RequestHandlerInvocationStrategyInterface.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Interfaces;\n\ninterface RequestHandlerInvocationStrategyInterface extends InvocationStrategyInterface\n{\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Interfaces/RouteCollectorInterface.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Interfaces;\n\nuse InvalidArgumentException;\nuse RuntimeException;\n\ninterface RouteCollectorInterface\n{\n    /**\n     * Get the route parser\n     */\n    public function getRouteParser(): RouteParserInterface;\n\n    /**\n     * Get default route invocation strategy\n     */\n    public function getDefaultInvocationStrategy(): InvocationStrategyInterface;\n\n    /**\n     * Set default route invocation strategy\n     */\n    public function setDefaultInvocationStrategy(InvocationStrategyInterface $strategy): RouteCollectorInterface;\n\n    /**\n     * Get path to FastRoute cache file\n     */\n    public function getCacheFile(): ?string;\n\n    /**\n     * Set path to FastRoute cache file\n     *\n     * @throws InvalidArgumentException\n     * @throws RuntimeException\n     */\n    public function setCacheFile(string $cacheFile): RouteCollectorInterface;\n\n    /**\n     * Get the base path used in pathFor()\n     */\n    public function getBasePath(): string;\n\n    /**\n     * Set the base path used in pathFor()\n     */\n    public function setBasePath(string $basePath): RouteCollectorInterface;\n\n    /**\n     * Get route objects\n     *\n     * @return RouteInterface[]\n     */\n    public function getRoutes(): array;\n\n    /**\n     * Get named route object\n     *\n     * @param string $name Route name\n     *\n     * @throws RuntimeException   If named route does not exist\n     */\n    public function getNamedRoute(string $name): RouteInterface;\n\n    /**\n     * Remove named route\n     *\n     * @param string $name Route name\n     *\n     * @throws RuntimeException   If named route does not exist\n     */\n    public function removeNamedRoute(string $name): RouteCollectorInterface;\n\n    /**\n     * Lookup a route via the route's unique identifier\n     *\n     * @throws RuntimeException   If route of identifier does not exist\n     */\n    public function lookupRoute(string $identifier): RouteInterface;\n\n    /**\n     * Add route group\n     * @param string|callable $callable\n     */\n    public function group(string $pattern, $callable): RouteGroupInterface;\n\n    /**\n     * Add route\n     *\n     * @param string[]        $methods Array of HTTP methods\n     * @param string          $pattern The route pattern\n     * @param callable|string $handler The route callable\n     */\n    public function map(array $methods, string $pattern, $handler): RouteInterface;\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Interfaces/RouteCollectorProxyInterface.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Interfaces;\n\nuse Psr\\Container\\ContainerInterface;\nuse Psr\\Http\\Message\\ResponseFactoryInterface;\nuse Psr\\Http\\Message\\UriInterface;\n\ninterface RouteCollectorProxyInterface\n{\n    public function getResponseFactory(): ResponseFactoryInterface;\n\n    public function getCallableResolver(): CallableResolverInterface;\n\n    public function getContainer(): ?ContainerInterface;\n\n    public function getRouteCollector(): RouteCollectorInterface;\n\n    /**\n     * Get the RouteCollectorProxy's base path\n     */\n    public function getBasePath(): string;\n\n    /**\n     * Set the RouteCollectorProxy's base path\n     */\n    public function setBasePath(string $basePath): RouteCollectorProxyInterface;\n\n    /**\n     * Add GET route\n     *\n     * @param  string          $pattern  The route URI pattern\n     * @param  callable|string $callable The route callback routine\n     */\n    public function get(string $pattern, $callable): RouteInterface;\n\n    /**\n     * Add POST route\n     *\n     * @param  string          $pattern  The route URI pattern\n     * @param  callable|string $callable The route callback routine\n     */\n    public function post(string $pattern, $callable): RouteInterface;\n\n    /**\n     * Add PUT route\n     *\n     * @param  string          $pattern  The route URI pattern\n     * @param  callable|string $callable The route callback routine\n     */\n    public function put(string $pattern, $callable): RouteInterface;\n\n    /**\n     * Add PATCH route\n     *\n     * @param  string          $pattern  The route URI pattern\n     * @param  callable|string $callable The route callback routine\n     */\n    public function patch(string $pattern, $callable): RouteInterface;\n\n    /**\n     * Add DELETE route\n     *\n     * @param  string          $pattern  The route URI pattern\n     * @param  callable|string $callable The route callback routine\n     */\n    public function delete(string $pattern, $callable): RouteInterface;\n\n    /**\n     * Add OPTIONS route\n     *\n     * @param  string          $pattern  The route URI pattern\n     * @param  callable|string $callable The route callback routine\n     */\n    public function options(string $pattern, $callable): RouteInterface;\n\n    /**\n     * Add route for any HTTP method\n     *\n     * @param  string          $pattern  The route URI pattern\n     * @param  callable|string $callable The route callback routine\n     */\n    public function any(string $pattern, $callable): RouteInterface;\n\n    /**\n     * Add route with multiple methods\n     *\n     * @param  string[]        $methods  Numeric array of HTTP method names\n     * @param  string          $pattern  The route URI pattern\n     * @param  callable|string $callable The route callback routine\n     */\n    public function map(array $methods, string $pattern, $callable): RouteInterface;\n\n    /**\n     * Route Groups\n     *\n     * This method accepts a route pattern and a callback. All route\n     * declarations in the callback will be prepended by the group(s)\n     * that it is in.\n     * @param string|callable $callable\n     */\n    public function group(string $pattern, $callable): RouteGroupInterface;\n\n    /**\n     * Add a route that sends an HTTP redirect\n     *\n     * @param string|UriInterface $to\n     */\n    public function redirect(string $from, $to, int $status = 302): RouteInterface;\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Interfaces/RouteGroupInterface.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Interfaces;\n\nuse Psr\\Http\\Server\\MiddlewareInterface;\nuse Slim\\MiddlewareDispatcher;\n\ninterface RouteGroupInterface\n{\n    public function collectRoutes(): RouteGroupInterface;\n\n    /**\n     * Add middleware to the route group\n     *\n     * @param MiddlewareInterface|string|callable $middleware\n     */\n    public function add($middleware): RouteGroupInterface;\n\n    /**\n     * Add middleware to the route group\n     */\n    public function addMiddleware(MiddlewareInterface $middleware): RouteGroupInterface;\n\n    /**\n     * Append the group's middleware to the MiddlewareDispatcher\n     */\n    public function appendMiddlewareToDispatcher(MiddlewareDispatcher $dispatcher): RouteGroupInterface;\n\n    /**\n     * Get the RouteGroup's pattern\n     */\n    public function getPattern(): string;\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Interfaces/RouteInterface.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Interfaces;\n\nuse Psr\\Http\\Message\\ResponseInterface;\nuse Psr\\Http\\Message\\ServerRequestInterface;\nuse Psr\\Http\\Server\\MiddlewareInterface;\n\ninterface RouteInterface\n{\n    /**\n     * Get route invocation strategy\n     */\n    public function getInvocationStrategy(): InvocationStrategyInterface;\n\n    /**\n     * Set route invocation strategy\n     */\n    public function setInvocationStrategy(InvocationStrategyInterface $invocationStrategy): RouteInterface;\n\n    /**\n     * Get route methods\n     *\n     * @return string[]\n     */\n    public function getMethods(): array;\n\n    /**\n     * Get route pattern\n     */\n    public function getPattern(): string;\n\n    /**\n     * Set route pattern\n     */\n    public function setPattern(string $pattern): RouteInterface;\n\n    /**\n     * Get route callable\n     *\n     * @return callable|string\n     */\n    public function getCallable();\n\n    /**\n     * Set route callable\n     *\n     * @param callable|string $callable\n     */\n    public function setCallable($callable): RouteInterface;\n\n    /**\n     * Get route name\n     */\n    public function getName(): ?string;\n\n    /**\n     * Set route name\n     *\n     * @return static\n     */\n    public function setName(string $name): RouteInterface;\n\n    /**\n     * Get the route's unique identifier\n     */\n    public function getIdentifier(): string;\n\n    /**\n     * Retrieve a specific route argument\n     */\n    public function getArgument(string $name, ?string $default = null): ?string;\n\n    /**\n     * Get route arguments\n     *\n     * @return array<string, string>\n     */\n    public function getArguments(): array;\n\n    /**\n     * Set a route argument\n     */\n    public function setArgument(string $name, string $value): RouteInterface;\n\n    /**\n     * Replace route arguments\n     *\n     * @param array<string, string> $arguments\n     */\n    public function setArguments(array $arguments): self;\n\n    /**\n     * @param MiddlewareInterface|string|callable $middleware\n     */\n    public function add($middleware): self;\n\n    public function addMiddleware(MiddlewareInterface $middleware): self;\n\n    /**\n     * Prepare the route for use\n     *\n     * @param array<string, string> $arguments\n     */\n    public function prepare(array $arguments): self;\n\n    /**\n     * Run route\n     *\n     * This method traverses the middleware stack, including the route's callable\n     * and captures the resultant HTTP response object. It then sends the response\n     * back to the Application.\n     */\n    public function run(ServerRequestInterface $request): ResponseInterface;\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Interfaces/RouteParserInterface.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Interfaces;\n\nuse InvalidArgumentException;\nuse Psr\\Http\\Message\\UriInterface;\nuse RuntimeException;\n\ninterface RouteParserInterface\n{\n    /**\n     * Build the path for a named route excluding the base path\n     *\n     * @param string                $routeName   Route name\n     * @param array<string, string> $data        Named argument replacement data\n     * @param array<string, string> $queryParams Optional query string parameters\n     *\n     * @throws RuntimeException         If named route does not exist\n     * @throws InvalidArgumentException If required data not provided\n     */\n    public function relativeUrlFor(string $routeName, array $data = [], array $queryParams = []): string;\n\n    /**\n     * Build the path for a named route including the base path\n     *\n     * @param string                $routeName   Route name\n     * @param array<string, string> $data        Named argument replacement data\n     * @param array<string, string> $queryParams Optional query string parameters\n     *\n     * @throws RuntimeException         If named route does not exist\n     * @throws InvalidArgumentException If required data not provided\n     */\n    public function urlFor(string $routeName, array $data = [], array $queryParams = []): string;\n\n    /**\n     * Get fully qualified URL for named route\n     *\n     * @param UriInterface              $uri\n     * @param string                    $routeName   Route name\n     * @param array<string, string>     $data        Named argument replacement data\n     * @param array<string, string>     $queryParams Optional query string parameters\n     */\n    public function fullUrlFor(UriInterface $uri, string $routeName, array $data = [], array $queryParams = []): string;\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Interfaces/RouteResolverInterface.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Interfaces;\n\nuse Slim\\Routing\\RoutingResults;\n\ninterface RouteResolverInterface\n{\n    /**\n     * @param string $uri Should be ServerRequestInterface::getUri()->getPath()\n     */\n    public function computeRoutingResults(string $uri, string $method): RoutingResults;\n\n    public function resolveRoute(string $identifier): RouteInterface;\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Interfaces/ServerRequestCreatorInterface.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Interfaces;\n\nuse Psr\\Http\\Message\\ServerRequestInterface;\n\ninterface ServerRequestCreatorInterface\n{\n    public function createServerRequestFromGlobals(): ServerRequestInterface;\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Logger.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim;\n\nuse Psr\\Log\\AbstractLogger;\nuse Psr\\Log\\InvalidArgumentException;\nuse Stringable;\n\nuse function error_log;\n\nclass Logger extends AbstractLogger\n{\n    /**\n     * @param mixed             $level\n     * @param string|Stringable $message\n     * @param array<mixed>      $context\n     *\n     * @throws InvalidArgumentException\n     */\n    public function log($level, $message, array $context = []): void\n    {\n        error_log((string) $message);\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Middleware/BodyParsingMiddleware.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Middleware;\n\nuse Psr\\Http\\Message\\ResponseInterface;\nuse Psr\\Http\\Message\\ServerRequestInterface;\nuse Psr\\Http\\Server\\MiddlewareInterface;\nuse Psr\\Http\\Server\\RequestHandlerInterface;\nuse RuntimeException;\n\nuse function count;\nuse function explode;\nuse function is_array;\nuse function is_null;\nuse function is_object;\nuse function is_string;\nuse function json_decode;\nuse function libxml_clear_errors;\nuse function libxml_disable_entity_loader;\nuse function libxml_use_internal_errors;\nuse function parse_str;\nuse function simplexml_load_string;\nuse function strtolower;\nuse function trim;\n\nuse const LIBXML_VERSION;\n\nclass BodyParsingMiddleware implements MiddlewareInterface\n{\n    /**\n     * @var callable[]\n     */\n    protected array $bodyParsers;\n\n    /**\n     * @param callable[] $bodyParsers list of body parsers as an associative array of mediaType => callable\n     */\n    public function __construct(array $bodyParsers = [])\n    {\n        $this->registerDefaultBodyParsers();\n\n        foreach ($bodyParsers as $mediaType => $parser) {\n            $this->registerBodyParser($mediaType, $parser);\n        }\n    }\n\n    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface\n    {\n        $parsedBody = $request->getParsedBody();\n\n        if (empty($parsedBody)) {\n            $parsedBody = $this->parseBody($request);\n            $request = $request->withParsedBody($parsedBody);\n        }\n\n        return $handler->handle($request);\n    }\n\n    /**\n     * @param string   $mediaType A HTTP media type (excluding content-type params).\n     * @param callable $callable  A callable that returns parsed contents for media type.\n     */\n    public function registerBodyParser(string $mediaType, callable $callable): self\n    {\n        $this->bodyParsers[$mediaType] = $callable;\n        return $this;\n    }\n\n    /**\n     * @param string   $mediaType A HTTP media type (excluding content-type params).\n     */\n    public function hasBodyParser(string $mediaType): bool\n    {\n        return isset($this->bodyParsers[$mediaType]);\n    }\n\n    /**\n     * @param string    $mediaType A HTTP media type (excluding content-type params).\n     * @throws RuntimeException\n     */\n    public function getBodyParser(string $mediaType): callable\n    {\n        if (!isset($this->bodyParsers[$mediaType])) {\n            throw new RuntimeException('No parser for type ' . $mediaType);\n        }\n        return $this->bodyParsers[$mediaType];\n    }\n\n    protected function registerDefaultBodyParsers(): void\n    {\n        $this->registerBodyParser('application/json', static function ($input) {\n            $result = json_decode($input, true);\n\n            if (!is_array($result)) {\n                return null;\n            }\n\n            return $result;\n        });\n\n        $this->registerBodyParser('application/x-www-form-urlencoded', static function ($input) {\n            parse_str($input, $data);\n            return $data;\n        });\n\n        $xmlCallable = static function ($input) {\n            $backup = self::disableXmlEntityLoader(true);\n            $backup_errors = libxml_use_internal_errors(true);\n            $result = simplexml_load_string($input);\n\n            self::disableXmlEntityLoader($backup);\n            libxml_clear_errors();\n            libxml_use_internal_errors($backup_errors);\n\n            if ($result === false) {\n                return null;\n            }\n\n            return $result;\n        };\n\n        $this->registerBodyParser('application/xml', $xmlCallable);\n        $this->registerBodyParser('text/xml', $xmlCallable);\n    }\n\n    /**\n     * @return null|array<mixed>|object\n     */\n    protected function parseBody(ServerRequestInterface $request)\n    {\n        $mediaType = $this->getMediaType($request);\n        if ($mediaType === null) {\n            return null;\n        }\n\n        // Check if this specific media type has a parser registered first\n        if (!isset($this->bodyParsers[$mediaType])) {\n            // If not, look for a media type with a structured syntax suffix (RFC 6839)\n            $parts = explode('+', $mediaType);\n            if (count($parts) >= 2) {\n                $mediaType = 'application/' . $parts[count($parts) - 1];\n            }\n        }\n\n        if (isset($this->bodyParsers[$mediaType])) {\n            $body = (string)$request->getBody();\n            $parsed = $this->bodyParsers[$mediaType]($body);\n\n            if ($parsed !== null && !is_object($parsed) && !is_array($parsed)) {\n                throw new RuntimeException(\n                    'Request body media type parser return value must be an array, an object, or null'\n                );\n            }\n\n            return $parsed;\n        }\n\n        return null;\n    }\n\n    /**\n     * @return string|null The serverRequest media type, minus content-type params\n     */\n    protected function getMediaType(ServerRequestInterface $request): ?string\n    {\n        $contentType = $request->getHeader('Content-Type')[0] ?? null;\n\n        if (is_string($contentType) && trim($contentType) !== '') {\n            $contentTypeParts = explode(';', $contentType);\n            return strtolower(trim($contentTypeParts[0]));\n        }\n\n        return null;\n    }\n\n    protected static function disableXmlEntityLoader(bool $disable): bool\n    {\n        if (LIBXML_VERSION >= 20900) {\n            // libxml >= 2.9.0 disables entity loading by default, so it is\n            // safe to skip the real call (deprecated in PHP 8).\n            return true;\n        }\n\n        // @codeCoverageIgnoreStart\n        return libxml_disable_entity_loader($disable);\n        // @codeCoverageIgnoreEnd\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Middleware/ContentLengthMiddleware.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Middleware;\n\nuse Psr\\Http\\Message\\ResponseInterface;\nuse Psr\\Http\\Message\\ServerRequestInterface;\nuse Psr\\Http\\Server\\MiddlewareInterface;\nuse Psr\\Http\\Server\\RequestHandlerInterface;\n\nclass ContentLengthMiddleware implements MiddlewareInterface\n{\n    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface\n    {\n        $response = $handler->handle($request);\n\n        // Add Content-Length header if not already added\n        $size = $response->getBody()->getSize();\n        if ($size !== null && !$response->hasHeader('Content-Length')) {\n            $response = $response->withHeader('Content-Length', (string) $size);\n        }\n\n        return $response;\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Middleware/ErrorMiddleware.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Middleware;\n\nuse Psr\\Http\\Message\\ResponseFactoryInterface;\nuse Psr\\Http\\Message\\ResponseInterface;\nuse Psr\\Http\\Message\\ServerRequestInterface;\nuse Psr\\Http\\Server\\MiddlewareInterface;\nuse Psr\\Http\\Server\\RequestHandlerInterface;\nuse Psr\\Log\\LoggerInterface;\nuse Slim\\Exception\\HttpException;\nuse Slim\\Handlers\\ErrorHandler;\nuse Slim\\Interfaces\\CallableResolverInterface;\nuse Slim\\Interfaces\\ErrorHandlerInterface;\nuse Throwable;\n\nuse function get_class;\nuse function is_subclass_of;\n\nclass ErrorMiddleware implements MiddlewareInterface\n{\n    protected CallableResolverInterface $callableResolver;\n\n    protected ResponseFactoryInterface $responseFactory;\n\n    protected bool $displayErrorDetails;\n\n    protected bool $logErrors;\n\n    protected bool $logErrorDetails;\n\n    protected ?LoggerInterface $logger = null;\n\n    /**\n     * @var ErrorHandlerInterface[]|callable[]|string[]\n     */\n    protected array $handlers = [];\n\n    /**\n     * @var ErrorHandlerInterface[]|callable[]|string[]\n     */\n    protected array $subClassHandlers = [];\n\n    /**\n     * @var ErrorHandlerInterface|callable|string|null\n     */\n    protected $defaultErrorHandler;\n\n    public function __construct(\n        CallableResolverInterface $callableResolver,\n        ResponseFactoryInterface $responseFactory,\n        bool $displayErrorDetails,\n        bool $logErrors,\n        bool $logErrorDetails,\n        ?LoggerInterface $logger = null\n    ) {\n        $this->callableResolver = $callableResolver;\n        $this->responseFactory = $responseFactory;\n        $this->displayErrorDetails = $displayErrorDetails;\n        $this->logErrors = $logErrors;\n        $this->logErrorDetails = $logErrorDetails;\n        $this->logger = $logger;\n    }\n\n    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface\n    {\n        try {\n            return $handler->handle($request);\n        } catch (Throwable $e) {\n            return $this->handleException($request, $e);\n        }\n    }\n\n    public function handleException(ServerRequestInterface $request, Throwable $exception): ResponseInterface\n    {\n        if ($exception instanceof HttpException) {\n            $request = $exception->getRequest();\n        }\n\n        $exceptionType = get_class($exception);\n        $handler = $this->getErrorHandler($exceptionType);\n\n        return $handler($request, $exception, $this->displayErrorDetails, $this->logErrors, $this->logErrorDetails);\n    }\n\n    /**\n     * Get callable to handle scenarios where an error\n     * occurs when processing the current request.\n     *\n     * @param string $type Exception/Throwable name. ie: RuntimeException::class\n     * @return callable|ErrorHandler\n     */\n    public function getErrorHandler(string $type)\n    {\n        if (isset($this->handlers[$type])) {\n            return $this->callableResolver->resolve($this->handlers[$type]);\n        }\n\n        if (isset($this->subClassHandlers[$type])) {\n            return $this->callableResolver->resolve($this->subClassHandlers[$type]);\n        }\n\n        foreach ($this->subClassHandlers as $class => $handler) {\n            if (is_subclass_of($type, $class)) {\n                return $this->callableResolver->resolve($handler);\n            }\n        }\n\n        return $this->getDefaultErrorHandler();\n    }\n\n    /**\n     * Get default error handler\n     *\n     * @return ErrorHandler|callable\n     */\n    public function getDefaultErrorHandler()\n    {\n        if ($this->defaultErrorHandler === null) {\n            $this->defaultErrorHandler = new ErrorHandler(\n                $this->callableResolver,\n                $this->responseFactory,\n                $this->logger\n            );\n        }\n\n        return $this->callableResolver->resolve($this->defaultErrorHandler);\n    }\n\n    /**\n     * Set callable as the default Slim application error handler.\n     *\n     * The callable signature MUST match the ErrorHandlerInterface\n     *\n     * @see \\Slim\\Interfaces\\ErrorHandlerInterface\n     *\n     * 1. Instance of \\Psr\\Http\\Message\\ServerRequestInterface\n     * 2. Instance of \\Throwable\n     * 3. Boolean $displayErrorDetails\n     * 4. Boolean $logErrors\n     * 5. Boolean $logErrorDetails\n     *\n     * The callable MUST return an instance of\n     * \\Psr\\Http\\Message\\ResponseInterface.\n     *\n     * @param string|callable|ErrorHandler $handler\n     */\n    public function setDefaultErrorHandler($handler): self\n    {\n        $this->defaultErrorHandler = $handler;\n        return $this;\n    }\n\n    /**\n     * Set callable to handle scenarios where an error\n     * occurs when processing the current request.\n     *\n     * The callable signature MUST match the ErrorHandlerInterface\n     *\n     * Pass true to $handleSubclasses to make the handler handle all subclasses of\n     * the type as well. Pass an array of classes to make the same function handle multiple exceptions.\n     *\n     * @see \\Slim\\Interfaces\\ErrorHandlerInterface\n     *\n     * 1. Instance of \\Psr\\Http\\Message\\ServerRequestInterface\n     * 2. Instance of \\Throwable\n     * 3. Boolean $displayErrorDetails\n     * 4. Boolean $logErrors\n     * 5. Boolean $logErrorDetails\n     *\n     * The callable MUST return an instance of\n     * \\Psr\\Http\\Message\\ResponseInterface.\n     *\n     * @param string|string[] $typeOrTypes Exception/Throwable name.\n     * ie: RuntimeException::class or an array of classes\n     * ie: [HttpNotFoundException::class, HttpMethodNotAllowedException::class]\n     * @param string|callable|ErrorHandlerInterface $handler\n     */\n    public function setErrorHandler($typeOrTypes, $handler, bool $handleSubclasses = false): self\n    {\n        if (is_array($typeOrTypes)) {\n            foreach ($typeOrTypes as $type) {\n                $this->addErrorHandler($type, $handler, $handleSubclasses);\n            }\n        } else {\n            $this->addErrorHandler($typeOrTypes, $handler, $handleSubclasses);\n        }\n\n        return $this;\n    }\n\n    /**\n     * Used internally to avoid code repetition when passing multiple exceptions to setErrorHandler().\n     * @param string|callable|ErrorHandlerInterface $handler\n     */\n    private function addErrorHandler(string $type, $handler, bool $handleSubclasses): void\n    {\n        if ($handleSubclasses) {\n            $this->subClassHandlers[$type] = $handler;\n        } else {\n            $this->handlers[$type] = $handler;\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Middleware/MethodOverrideMiddleware.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Middleware;\n\nuse Psr\\Http\\Message\\ResponseInterface;\nuse Psr\\Http\\Message\\ServerRequestInterface;\nuse Psr\\Http\\Server\\MiddlewareInterface;\nuse Psr\\Http\\Server\\RequestHandlerInterface;\n\nuse function is_array;\nuse function strtoupper;\n\nclass MethodOverrideMiddleware implements MiddlewareInterface\n{\n    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface\n    {\n        $methodHeader = $request->getHeaderLine('X-Http-Method-Override');\n\n        if ($methodHeader) {\n            $request = $request->withMethod($methodHeader);\n        } elseif (strtoupper($request->getMethod()) === 'POST') {\n            $body = $request->getParsedBody();\n\n            if (is_array($body) && !empty($body['_METHOD'])) {\n                $request = $request->withMethod($body['_METHOD']);\n            }\n\n            if ($request->getBody()->eof()) {\n                $request->getBody()->rewind();\n            }\n        }\n\n        return $handler->handle($request);\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Middleware/OutputBufferingMiddleware.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Middleware;\n\nuse InvalidArgumentException;\nuse Psr\\Http\\Message\\ResponseInterface;\nuse Psr\\Http\\Message\\ServerRequestInterface;\nuse Psr\\Http\\Message\\StreamFactoryInterface;\nuse Psr\\Http\\Server\\MiddlewareInterface;\nuse Psr\\Http\\Server\\RequestHandlerInterface;\nuse Throwable;\n\nuse function in_array;\nuse function ob_end_clean;\nuse function ob_get_clean;\nuse function ob_start;\n\nclass OutputBufferingMiddleware implements MiddlewareInterface\n{\n    public const APPEND = 'append';\n    public const PREPEND = 'prepend';\n\n    protected StreamFactoryInterface $streamFactory;\n\n    protected string $style;\n\n    /**\n     * @param string $style Either \"append\" or \"prepend\"\n     */\n    public function __construct(StreamFactoryInterface $streamFactory, string $style = 'append')\n    {\n        $this->streamFactory = $streamFactory;\n        $this->style = $style;\n\n        if (!in_array($style, [static::APPEND, static::PREPEND], true)) {\n            throw new InvalidArgumentException(\"Invalid style `{$style}`. Must be `append` or `prepend`\");\n        }\n    }\n\n    /**\n     * @throws Throwable\n     */\n    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface\n    {\n        try {\n            ob_start();\n            $response = $handler->handle($request);\n            $output = ob_get_clean();\n        } catch (Throwable $e) {\n            ob_end_clean();\n            throw $e;\n        }\n\n        if (!empty($output)) {\n            if ($this->style === static::PREPEND) {\n                $body = $this->streamFactory->createStream();\n                $body->write($output . $response->getBody());\n                $response = $response->withBody($body);\n            } elseif ($this->style === static::APPEND && $response->getBody()->isWritable()) {\n                $response->getBody()->write($output);\n            }\n        }\n\n        return $response;\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Middleware/RoutingMiddleware.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Middleware;\n\nuse Psr\\Http\\Message\\ResponseInterface;\nuse Psr\\Http\\Message\\ServerRequestInterface;\nuse Psr\\Http\\Server\\MiddlewareInterface;\nuse Psr\\Http\\Server\\RequestHandlerInterface;\nuse RuntimeException;\nuse Slim\\Exception\\HttpMethodNotAllowedException;\nuse Slim\\Exception\\HttpNotFoundException;\nuse Slim\\Interfaces\\RouteParserInterface;\nuse Slim\\Interfaces\\RouteResolverInterface;\nuse Slim\\Routing\\RouteContext;\nuse Slim\\Routing\\RoutingResults;\n\nclass RoutingMiddleware implements MiddlewareInterface\n{\n    protected RouteResolverInterface $routeResolver;\n\n    protected RouteParserInterface $routeParser;\n\n    public function __construct(RouteResolverInterface $routeResolver, RouteParserInterface $routeParser)\n    {\n        $this->routeResolver = $routeResolver;\n        $this->routeParser = $routeParser;\n    }\n\n    /**\n     * @throws HttpNotFoundException\n     * @throws HttpMethodNotAllowedException\n     * @throws RuntimeException\n     */\n    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface\n    {\n        $request = $this->performRouting($request);\n        return $handler->handle($request);\n    }\n\n    /**\n     * Perform routing\n     *\n     * @param  ServerRequestInterface $request PSR7 Server Request\n     *\n     * @throws HttpNotFoundException\n     * @throws HttpMethodNotAllowedException\n     * @throws RuntimeException\n     */\n    public function performRouting(ServerRequestInterface $request): ServerRequestInterface\n    {\n        $request = $request->withAttribute(RouteContext::ROUTE_PARSER, $this->routeParser);\n\n        $routingResults = $this->resolveRoutingResultsFromRequest($request);\n        $routeStatus = $routingResults->getRouteStatus();\n\n        $request = $request->withAttribute(RouteContext::ROUTING_RESULTS, $routingResults);\n\n        switch ($routeStatus) {\n            case RoutingResults::FOUND:\n                $routeArguments = $routingResults->getRouteArguments();\n                $routeIdentifier = $routingResults->getRouteIdentifier() ?? '';\n                $route = $this->routeResolver\n                    ->resolveRoute($routeIdentifier)\n                    ->prepare($routeArguments);\n                return $request->withAttribute(RouteContext::ROUTE, $route);\n\n            case RoutingResults::NOT_FOUND:\n                throw new HttpNotFoundException($request);\n\n            case RoutingResults::METHOD_NOT_ALLOWED:\n                $exception = new HttpMethodNotAllowedException($request);\n                $exception->setAllowedMethods($routingResults->getAllowedMethods());\n                throw $exception;\n\n            default:\n                throw new RuntimeException('An unexpected error occurred while performing routing.');\n        }\n    }\n\n    /**\n     * Resolves the route from the given request\n     */\n    protected function resolveRoutingResultsFromRequest(ServerRequestInterface $request): RoutingResults\n    {\n        return $this->routeResolver->computeRoutingResults(\n            $request->getUri()->getPath(),\n            $request->getMethod()\n        );\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/MiddlewareDispatcher.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim;\n\nuse Closure;\nuse Psr\\Container\\ContainerInterface;\nuse Psr\\Http\\Message\\ResponseInterface;\nuse Psr\\Http\\Message\\ServerRequestInterface;\nuse Psr\\Http\\Server\\MiddlewareInterface;\nuse Psr\\Http\\Server\\RequestHandlerInterface;\nuse RuntimeException;\nuse Slim\\Interfaces\\AdvancedCallableResolverInterface;\nuse Slim\\Interfaces\\CallableResolverInterface;\nuse Slim\\Interfaces\\MiddlewareDispatcherInterface;\n\nuse function class_exists;\nuse function function_exists;\nuse function is_callable;\nuse function is_string;\nuse function preg_match;\nuse function sprintf;\n\nclass MiddlewareDispatcher implements MiddlewareDispatcherInterface\n{\n    /**\n     * Tip of the middleware call stack\n     */\n    protected RequestHandlerInterface $tip;\n\n    protected ?CallableResolverInterface $callableResolver;\n\n    protected ?ContainerInterface $container;\n\n    public function __construct(\n        RequestHandlerInterface $kernel,\n        ?CallableResolverInterface $callableResolver = null,\n        ?ContainerInterface $container = null\n    ) {\n        $this->seedMiddlewareStack($kernel);\n        $this->callableResolver = $callableResolver;\n        $this->container = $container;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function seedMiddlewareStack(RequestHandlerInterface $kernel): void\n    {\n        $this->tip = $kernel;\n    }\n\n    /**\n     * Invoke the middleware stack\n     */\n    public function handle(ServerRequestInterface $request): ResponseInterface\n    {\n        return $this->tip->handle($request);\n    }\n\n    /**\n     * Add a new middleware to the stack\n     *\n     * Middleware are organized as a stack. That means middleware\n     * that have been added before will be executed after the newly\n     * added one (last in, first out).\n     *\n     * @param MiddlewareInterface|string|callable $middleware\n     */\n    public function add($middleware): MiddlewareDispatcherInterface\n    {\n        if ($middleware instanceof MiddlewareInterface) {\n            return $this->addMiddleware($middleware);\n        }\n\n        if (is_string($middleware)) {\n            return $this->addDeferred($middleware);\n        }\n\n        if (is_callable($middleware)) {\n            return $this->addCallable($middleware);\n        }\n\n        /** @phpstan-ignore-next-line */\n        throw new RuntimeException(\n            'A middleware must be an object/class name referencing an implementation of ' .\n            'MiddlewareInterface or a callable with a matching signature.'\n        );\n    }\n\n    /**\n     * Add a new middleware to the stack\n     *\n     * Middleware are organized as a stack. That means middleware\n     * that have been added before will be executed after the newly\n     * added one (last in, first out).\n     */\n    public function addMiddleware(MiddlewareInterface $middleware): MiddlewareDispatcherInterface\n    {\n        $next = $this->tip;\n        $this->tip = new class ($middleware, $next) implements RequestHandlerInterface {\n            private MiddlewareInterface $middleware;\n\n            private RequestHandlerInterface $next;\n\n            public function __construct(MiddlewareInterface $middleware, RequestHandlerInterface $next)\n            {\n                $this->middleware = $middleware;\n                $this->next = $next;\n            }\n\n            public function handle(ServerRequestInterface $request): ResponseInterface\n            {\n                return $this->middleware->process($request, $this->next);\n            }\n        };\n\n        return $this;\n    }\n\n    /**\n     * Add a new middleware by class name\n     *\n     * Middleware are organized as a stack. That means middleware\n     * that have been added before will be executed after the newly\n     * added one (last in, first out).\n     */\n    public function addDeferred(string $middleware): self\n    {\n        $next = $this->tip;\n        $this->tip = new class (\n            $middleware,\n            $next,\n            $this->container,\n            $this->callableResolver\n        ) implements RequestHandlerInterface {\n            private string $middleware;\n\n            private RequestHandlerInterface $next;\n\n            private ?ContainerInterface $container;\n\n            private ?CallableResolverInterface $callableResolver;\n\n            public function __construct(\n                string $middleware,\n                RequestHandlerInterface $next,\n                ?ContainerInterface $container = null,\n                ?CallableResolverInterface $callableResolver = null\n            ) {\n                $this->middleware = $middleware;\n                $this->next = $next;\n                $this->container = $container;\n                $this->callableResolver = $callableResolver;\n            }\n\n            public function handle(ServerRequestInterface $request): ResponseInterface\n            {\n                if ($this->callableResolver instanceof AdvancedCallableResolverInterface) {\n                    $callable = $this->callableResolver->resolveMiddleware($this->middleware);\n                    return $callable($request, $this->next);\n                }\n\n                $callable = null;\n\n                if ($this->callableResolver instanceof CallableResolverInterface) {\n                    try {\n                        $callable = $this->callableResolver->resolve($this->middleware);\n                    } catch (RuntimeException $e) {\n                        // Do Nothing\n                    }\n                }\n\n                if (!$callable) {\n                    $resolved = $this->middleware;\n                    $instance = null;\n                    $method = null;\n\n                    // Check for Slim callable as `class:method`\n                    if (preg_match(CallableResolver::$callablePattern, $resolved, $matches)) {\n                        $resolved = $matches[1];\n                        $method = $matches[2];\n                    }\n\n                    if ($this->container && $this->container->has($resolved)) {\n                        $instance = $this->container->get($resolved);\n                        if ($instance instanceof MiddlewareInterface) {\n                            return $instance->process($request, $this->next);\n                        }\n                    } elseif (!function_exists($resolved)) {\n                        if (!class_exists($resolved)) {\n                            throw new RuntimeException(sprintf('Middleware %s does not exist', $resolved));\n                        }\n                        $instance = new $resolved($this->container);\n                    }\n\n                    if ($instance && $instance instanceof MiddlewareInterface) {\n                        return $instance->process($request, $this->next);\n                    }\n\n                    $callable = $instance ?? $resolved;\n                    if ($instance && $method) {\n                        $callable = [$instance, $method];\n                    }\n\n                    if ($this->container && $callable instanceof Closure) {\n                        $callable = $callable->bindTo($this->container);\n                    }\n                }\n\n                if (!is_callable($callable)) {\n                    throw new RuntimeException(\n                        sprintf(\n                            'Middleware %s is not resolvable',\n                            $this->middleware\n                        )\n                    );\n                }\n\n                return $callable($request, $this->next);\n            }\n        };\n\n        return $this;\n    }\n\n    /**\n     * Add a (non-standard) callable middleware to the stack\n     *\n     * Middleware are organized as a stack. That means middleware\n     * that have been added before will be executed after the newly\n     * added one (last in, first out).\n     */\n    public function addCallable(callable $middleware): self\n    {\n        $next = $this->tip;\n\n        if ($this->container && $middleware instanceof Closure) {\n            /** @var Closure $middleware */\n            $middleware = $middleware->bindTo($this->container);\n        }\n\n        $this->tip = new class ($middleware, $next) implements RequestHandlerInterface {\n            /**\n             * @var callable\n             */\n            private $middleware;\n\n            /**\n             * @var RequestHandlerInterface\n             */\n            private $next;\n\n            public function __construct(callable $middleware, RequestHandlerInterface $next)\n            {\n                $this->middleware = $middleware;\n                $this->next = $next;\n            }\n\n            public function handle(ServerRequestInterface $request): ResponseInterface\n            {\n                return ($this->middleware)($request, $this->next);\n            }\n        };\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/ResponseEmitter.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim;\n\nuse Psr\\Http\\Message\\ResponseInterface;\n\nuse function connection_status;\nuse function header;\nuse function headers_sent;\nuse function in_array;\nuse function min;\nuse function sprintf;\nuse function strlen;\nuse function strtolower;\n\nuse const CONNECTION_NORMAL;\n\nclass ResponseEmitter\n{\n    private int $responseChunkSize;\n\n    public function __construct(int $responseChunkSize = 4096)\n    {\n        $this->responseChunkSize = $responseChunkSize;\n    }\n\n    /**\n     * Send the response the client\n     */\n    public function emit(ResponseInterface $response): void\n    {\n        $isEmpty = $this->isResponseEmpty($response);\n        if (headers_sent() === false) {\n            $this->emitHeaders($response);\n\n            // Set the status _after_ the headers, because of PHP's \"helpful\" behavior with location headers.\n            // See https://github.com/slimphp/Slim/issues/1730\n\n            $this->emitStatusLine($response);\n        }\n\n        if (!$isEmpty) {\n            $this->emitBody($response);\n        }\n    }\n\n    /**\n     * Emit Response Headers\n     */\n    private function emitHeaders(ResponseInterface $response): void\n    {\n        foreach ($response->getHeaders() as $name => $values) {\n            $first = strtolower($name) !== 'set-cookie';\n            foreach ($values as $value) {\n                $header = sprintf('%s: %s', $name, $value);\n                header($header, $first);\n                $first = false;\n            }\n        }\n    }\n\n    /**\n     * Emit Status Line\n     */\n    private function emitStatusLine(ResponseInterface $response): void\n    {\n        $statusLine = sprintf(\n            'HTTP/%s %s %s',\n            $response->getProtocolVersion(),\n            $response->getStatusCode(),\n            $response->getReasonPhrase()\n        );\n        header($statusLine, true, $response->getStatusCode());\n    }\n\n    /**\n     * Emit Body\n     */\n    private function emitBody(ResponseInterface $response): void\n    {\n        $body = $response->getBody();\n        if ($body->isSeekable()) {\n            $body->rewind();\n        }\n\n        $amountToRead = (int) $response->getHeaderLine('Content-Length');\n        if (!$amountToRead) {\n            $amountToRead = $body->getSize();\n        }\n\n        if ($amountToRead) {\n            while ($amountToRead > 0 && !$body->eof()) {\n                $length = min($this->responseChunkSize, $amountToRead);\n                $data = $body->read($length);\n                echo $data;\n\n                $amountToRead -= strlen($data);\n\n                if (connection_status() !== CONNECTION_NORMAL) {\n                    break;\n                }\n            }\n        } else {\n            while (!$body->eof()) {\n                echo $body->read($this->responseChunkSize);\n                if (connection_status() !== CONNECTION_NORMAL) {\n                    break;\n                }\n            }\n        }\n    }\n\n    /**\n     * Asserts response body is empty or status code is 204, 205 or 304\n     */\n    public function isResponseEmpty(ResponseInterface $response): bool\n    {\n        if (in_array($response->getStatusCode(), [204, 205, 304], true)) {\n            return true;\n        }\n        $stream = $response->getBody();\n        $seekable = $stream->isSeekable();\n        if ($seekable) {\n            $stream->rewind();\n        }\n        return $seekable ? $stream->read(1) === '' : $stream->eof();\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Routing/Dispatcher.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Routing;\n\nuse FastRoute\\DataGenerator\\GroupCountBased;\nuse FastRoute\\RouteCollector as FastRouteCollector;\nuse FastRoute\\RouteParser\\Std;\nuse Slim\\Interfaces\\DispatcherInterface;\nuse Slim\\Interfaces\\RouteCollectorInterface;\n\nclass Dispatcher implements DispatcherInterface\n{\n    private RouteCollectorInterface $routeCollector;\n\n    private ?FastRouteDispatcher $dispatcher = null;\n\n    public function __construct(RouteCollectorInterface $routeCollector)\n    {\n        $this->routeCollector = $routeCollector;\n    }\n\n    protected function createDispatcher(): FastRouteDispatcher\n    {\n        if ($this->dispatcher) {\n            return $this->dispatcher;\n        }\n\n        $routeDefinitionCallback = function (FastRouteCollector $r): void {\n            $basePath = $this->routeCollector->getBasePath();\n\n            foreach ($this->routeCollector->getRoutes() as $route) {\n                $r->addRoute($route->getMethods(), $basePath . $route->getPattern(), $route->getIdentifier());\n            }\n        };\n\n        $cacheFile = $this->routeCollector->getCacheFile();\n        if ($cacheFile) {\n            /** @var FastRouteDispatcher $dispatcher */\n            $dispatcher = \\FastRoute\\cachedDispatcher($routeDefinitionCallback, [\n                'dataGenerator' => GroupCountBased::class,\n                'dispatcher' => FastRouteDispatcher::class,\n                'routeParser' => new Std(),\n                'cacheFile' => $cacheFile,\n            ]);\n        } else {\n            /** @var FastRouteDispatcher $dispatcher */\n            $dispatcher = \\FastRoute\\simpleDispatcher($routeDefinitionCallback, [\n                'dataGenerator' => GroupCountBased::class,\n                'dispatcher' => FastRouteDispatcher::class,\n                'routeParser' => new Std(),\n            ]);\n        }\n\n        $this->dispatcher = $dispatcher;\n        return $this->dispatcher;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function dispatch(string $method, string $uri): RoutingResults\n    {\n        $dispatcher = $this->createDispatcher();\n        $results = $dispatcher->dispatch($method, $uri);\n        return new RoutingResults($this, $method, $uri, $results[0], $results[1], $results[2]);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getAllowedMethods(string $uri): array\n    {\n        $dispatcher = $this->createDispatcher();\n        return $dispatcher->getAllowedMethods($uri);\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Routing/FastRouteDispatcher.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Routing;\n\nuse FastRoute\\Dispatcher\\GroupCountBased;\n\nclass FastRouteDispatcher extends GroupCountBased\n{\n    /**\n     * @var string[][]\n     */\n    private array $allowedMethods = [];\n\n    /**\n     * @param string $httpMethod\n     * @param string $uri\n     *\n     * @return array{int, string|null, array<string, string>}\n     */\n    public function dispatch($httpMethod, $uri): array\n    {\n        $routingResults = $this->routingResults($httpMethod, $uri);\n        if ($routingResults[0] === self::FOUND) {\n            return $routingResults;\n        }\n\n        // For HEAD requests, attempt fallback to GET\n        if ($httpMethod === 'HEAD') {\n            $routingResults = $this->routingResults('GET', $uri);\n            if ($routingResults[0] === self::FOUND) {\n                return $routingResults;\n            }\n        }\n\n        // If nothing else matches, try fallback routes\n        $routingResults = $this->routingResults('*', $uri);\n        if ($routingResults[0] === self::FOUND) {\n            return $routingResults;\n        }\n\n        if (!empty($this->getAllowedMethods($uri))) {\n            return [self::METHOD_NOT_ALLOWED, null, []];\n        }\n\n        return [self::NOT_FOUND, null, []];\n    }\n\n    /**\n     * @param string $httpMethod\n     * @param string $uri\n     *\n     * @return array{int, string|null, array<string, string>}\n     */\n    private function routingResults(string $httpMethod, string $uri): array\n    {\n        if (isset($this->staticRouteMap[$httpMethod][$uri])) {\n            /** @var string $routeIdentifier */\n            $routeIdentifier = $this->staticRouteMap[$httpMethod][$uri];\n            return [self::FOUND, $routeIdentifier, []];\n        }\n\n        if (isset($this->variableRouteData[$httpMethod])) {\n            /** @var array{0: int, 1?: string, 2?: array<string, string>} $result */\n            $result = $this->dispatchVariableRoute($this->variableRouteData[$httpMethod], $uri);\n            if ($result[0] === self::FOUND) {\n                /** @var array{int, string, array<string, string>} $result */\n                return [self::FOUND, $result[1], $result[2]];\n            }\n        }\n\n        return [self::NOT_FOUND, null, []];\n    }\n\n    /**\n     * @param string $uri\n     *\n     * @return string[]\n     */\n    public function getAllowedMethods(string $uri): array\n    {\n        if (isset($this->allowedMethods[$uri])) {\n            return $this->allowedMethods[$uri];\n        }\n\n        $allowedMethods = [];\n        foreach ($this->staticRouteMap as $method => $uriMap) {\n            if (isset($uriMap[$uri])) {\n                $allowedMethods[$method] = true;\n            }\n        }\n\n        foreach ($this->variableRouteData as $method => $routeData) {\n            $result = $this->dispatchVariableRoute($routeData, $uri);\n            if ($result[0] === self::FOUND) {\n                $allowedMethods[$method] = true;\n            }\n        }\n\n        return $this->allowedMethods[$uri] = array_keys($allowedMethods);\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Routing/Route.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Routing;\n\nuse Psr\\Container\\ContainerInterface;\nuse Psr\\Http\\Message\\ResponseFactoryInterface;\nuse Psr\\Http\\Message\\ResponseInterface;\nuse Psr\\Http\\Message\\ServerRequestInterface;\nuse Psr\\Http\\Server\\MiddlewareInterface;\nuse Psr\\Http\\Server\\RequestHandlerInterface;\nuse Slim\\Handlers\\Strategies\\RequestHandler;\nuse Slim\\Handlers\\Strategies\\RequestResponse;\nuse Slim\\Interfaces\\AdvancedCallableResolverInterface;\nuse Slim\\Interfaces\\CallableResolverInterface;\nuse Slim\\Interfaces\\InvocationStrategyInterface;\nuse Slim\\Interfaces\\RequestHandlerInvocationStrategyInterface;\nuse Slim\\Interfaces\\RouteGroupInterface;\nuse Slim\\Interfaces\\RouteInterface;\nuse Slim\\MiddlewareDispatcher;\n\nuse function array_key_exists;\nuse function array_replace;\nuse function array_reverse;\nuse function class_implements;\nuse function in_array;\nuse function is_array;\n\nclass Route implements RouteInterface, RequestHandlerInterface\n{\n    /**\n     * HTTP methods supported by this route\n     *\n     * @var string[]\n     */\n    protected array $methods = [];\n\n    /**\n     * Route identifier\n     */\n    protected string $identifier;\n\n    /**\n     * Route name\n     */\n    protected ?string $name = null;\n\n    /**\n     * Parent route groups\n     *\n     * @var RouteGroupInterface[]\n     */\n    protected array $groups;\n\n    protected InvocationStrategyInterface $invocationStrategy;\n\n    /**\n     * Route parameters\n     *\n     * @var array<string, string>\n     */\n    protected array $arguments = [];\n\n    /**\n     * Route arguments parameters\n     *\n     * @var string[]\n     */\n    protected array $savedArguments = [];\n\n    /**\n     * Container\n     */\n    protected ?ContainerInterface $container = null;\n\n    protected MiddlewareDispatcher $middlewareDispatcher;\n\n    /**\n     * Route callable\n     *\n     * @var callable|string\n     */\n    protected $callable;\n\n    protected CallableResolverInterface $callableResolver;\n\n    protected ResponseFactoryInterface $responseFactory;\n\n    /**\n     * Route pattern\n     */\n    protected string $pattern;\n\n    protected bool $groupMiddlewareAppended = false;\n\n    /**\n     * @param string[]                         $methods    The route HTTP methods\n     * @param string                           $pattern    The route pattern\n     * @param callable|string                  $callable   The route callable\n     * @param ResponseFactoryInterface         $responseFactory\n     * @param CallableResolverInterface        $callableResolver\n     * @param ContainerInterface|null          $container\n     * @param InvocationStrategyInterface|null $invocationStrategy\n     * @param RouteGroupInterface[]            $groups     The parent route groups\n     * @param int                              $identifier The route identifier\n     */\n    public function __construct(\n        array $methods,\n        string $pattern,\n        $callable,\n        ResponseFactoryInterface $responseFactory,\n        CallableResolverInterface $callableResolver,\n        ?ContainerInterface $container = null,\n        ?InvocationStrategyInterface $invocationStrategy = null,\n        array $groups = [],\n        int $identifier = 0\n    ) {\n        $this->methods = $methods;\n        $this->pattern = $pattern;\n        $this->callable = $callable;\n        $this->responseFactory = $responseFactory;\n        $this->callableResolver = $callableResolver;\n        $this->container = $container;\n        $this->invocationStrategy = $invocationStrategy ?? new RequestResponse();\n        $this->groups = $groups;\n        $this->identifier = 'route' . $identifier;\n        $this->middlewareDispatcher = new MiddlewareDispatcher($this, $callableResolver, $container);\n    }\n\n    public function getCallableResolver(): CallableResolverInterface\n    {\n        return $this->callableResolver;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getInvocationStrategy(): InvocationStrategyInterface\n    {\n        return $this->invocationStrategy;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function setInvocationStrategy(InvocationStrategyInterface $invocationStrategy): RouteInterface\n    {\n        $this->invocationStrategy = $invocationStrategy;\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getMethods(): array\n    {\n        return $this->methods;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getPattern(): string\n    {\n        return $this->pattern;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function setPattern(string $pattern): RouteInterface\n    {\n        $this->pattern = $pattern;\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getCallable()\n    {\n        return $this->callable;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function setCallable($callable): RouteInterface\n    {\n        $this->callable = $callable;\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getName(): ?string\n    {\n        return $this->name;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function setName(string $name): RouteInterface\n    {\n        $this->name = $name;\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getIdentifier(): string\n    {\n        return $this->identifier;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getArgument(string $name, ?string $default = null): ?string\n    {\n        if (array_key_exists($name, $this->arguments)) {\n            return $this->arguments[$name];\n        }\n        return $default;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getArguments(): array\n    {\n        return $this->arguments;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function setArguments(array $arguments, bool $includeInSavedArguments = true): RouteInterface\n    {\n        if ($includeInSavedArguments) {\n            $this->savedArguments = $arguments;\n        }\n\n        $this->arguments = $arguments;\n        return $this;\n    }\n\n    /**\n     * @return RouteGroupInterface[]\n     */\n    public function getGroups(): array\n    {\n        return $this->groups;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function add($middleware): RouteInterface\n    {\n        $this->middlewareDispatcher->add($middleware);\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function addMiddleware(MiddlewareInterface $middleware): RouteInterface\n    {\n        $this->middlewareDispatcher->addMiddleware($middleware);\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function prepare(array $arguments): RouteInterface\n    {\n        $this->arguments = array_replace($this->savedArguments, $arguments);\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function setArgument(string $name, string $value, bool $includeInSavedArguments = true): RouteInterface\n    {\n        if ($includeInSavedArguments) {\n            $this->savedArguments[$name] = $value;\n        }\n\n        $this->arguments[$name] = $value;\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function run(ServerRequestInterface $request): ResponseInterface\n    {\n        if (!$this->groupMiddlewareAppended) {\n            $this->appendGroupMiddlewareToRoute();\n        }\n\n        return $this->middlewareDispatcher->handle($request);\n    }\n\n    /**\n     * @return void\n     */\n    protected function appendGroupMiddlewareToRoute(): void\n    {\n        $inner = $this->middlewareDispatcher;\n        $this->middlewareDispatcher = new MiddlewareDispatcher($inner, $this->callableResolver, $this->container);\n\n        /** @var RouteGroupInterface $group */\n        foreach (array_reverse($this->groups) as $group) {\n            $group->appendMiddlewareToDispatcher($this->middlewareDispatcher);\n        }\n\n        $this->groupMiddlewareAppended = true;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function handle(ServerRequestInterface $request): ResponseInterface\n    {\n        if ($this->callableResolver instanceof AdvancedCallableResolverInterface) {\n            $callable = $this->callableResolver->resolveRoute($this->callable);\n        } else {\n            $callable = $this->callableResolver->resolve($this->callable);\n        }\n        $strategy = $this->invocationStrategy;\n\n        /** @var string[] $strategyImplements */\n        $strategyImplements = class_implements($strategy);\n\n        if (\n            is_array($callable)\n            && $callable[0] instanceof RequestHandlerInterface\n            && !in_array(RequestHandlerInvocationStrategyInterface::class, $strategyImplements)\n        ) {\n            $strategy = new RequestHandler();\n        }\n\n        $response = $this->responseFactory->createResponse();\n        return $strategy($callable, $request, $response, $this->arguments);\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Routing/RouteCollector.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Routing;\n\nuse Psr\\Container\\ContainerInterface;\nuse Psr\\Http\\Message\\ResponseFactoryInterface;\nuse RuntimeException;\nuse Slim\\Handlers\\Strategies\\RequestResponse;\nuse Slim\\Interfaces\\CallableResolverInterface;\nuse Slim\\Interfaces\\InvocationStrategyInterface;\nuse Slim\\Interfaces\\RouteCollectorInterface;\nuse Slim\\Interfaces\\RouteCollectorProxyInterface;\nuse Slim\\Interfaces\\RouteGroupInterface;\nuse Slim\\Interfaces\\RouteInterface;\nuse Slim\\Interfaces\\RouteParserInterface;\n\nuse function array_pop;\nuse function dirname;\nuse function file_exists;\nuse function sprintf;\nuse function is_readable;\nuse function is_writable;\n\n/**\n * RouteCollector is used to collect routes and route groups\n * as well as generate paths and URLs relative to its environment\n */\nclass RouteCollector implements RouteCollectorInterface\n{\n    protected RouteParserInterface $routeParser;\n\n    protected CallableResolverInterface $callableResolver;\n\n    protected ?ContainerInterface $container = null;\n\n    protected InvocationStrategyInterface $defaultInvocationStrategy;\n\n    /**\n     * Base path used in pathFor()\n     */\n    protected string $basePath = '';\n\n    /**\n     * Path to fast route cache file. Set to null to disable route caching\n     */\n    protected ?string $cacheFile = null;\n\n    /**\n     * Routes\n     *\n     * @var RouteInterface[]\n     */\n    protected array $routes = [];\n\n    /**\n     * Routes indexed by name\n     *\n     * @var RouteInterface[]\n     */\n    protected array $routesByName = [];\n\n    /**\n     * Route groups\n     *\n     * @var RouteGroupInterface[]\n     */\n    protected array $routeGroups = [];\n\n    /**\n     * Route counter incrementer\n     */\n    protected int $routeCounter = 0;\n\n    protected ResponseFactoryInterface $responseFactory;\n\n    public function __construct(\n        ResponseFactoryInterface $responseFactory,\n        CallableResolverInterface $callableResolver,\n        ?ContainerInterface $container = null,\n        ?InvocationStrategyInterface $defaultInvocationStrategy = null,\n        ?RouteParserInterface $routeParser = null,\n        ?string $cacheFile = null\n    ) {\n        $this->responseFactory = $responseFactory;\n        $this->callableResolver = $callableResolver;\n        $this->container = $container;\n        $this->defaultInvocationStrategy = $defaultInvocationStrategy ?? new RequestResponse();\n        $this->routeParser = $routeParser ?? new RouteParser($this);\n\n        if ($cacheFile) {\n            $this->setCacheFile($cacheFile);\n        }\n    }\n\n    public function getRouteParser(): RouteParserInterface\n    {\n        return $this->routeParser;\n    }\n\n    /**\n     * Get default route invocation strategy\n     */\n    public function getDefaultInvocationStrategy(): InvocationStrategyInterface\n    {\n        return $this->defaultInvocationStrategy;\n    }\n\n    public function setDefaultInvocationStrategy(InvocationStrategyInterface $strategy): RouteCollectorInterface\n    {\n        $this->defaultInvocationStrategy = $strategy;\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getCacheFile(): ?string\n    {\n        return $this->cacheFile;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function setCacheFile(string $cacheFile): RouteCollectorInterface\n    {\n        if (file_exists($cacheFile) && !is_readable($cacheFile)) {\n            throw new RuntimeException(\n                sprintf('Route collector cache file `%s` is not readable', $cacheFile)\n            );\n        }\n\n        if (!file_exists($cacheFile) && !is_writable(dirname($cacheFile))) {\n            throw new RuntimeException(\n                sprintf('Route collector cache file directory `%s` is not writable', dirname($cacheFile))\n            );\n        }\n\n        $this->cacheFile = $cacheFile;\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getBasePath(): string\n    {\n        return $this->basePath;\n    }\n\n    /**\n     * Set the base path used in urlFor()\n     */\n    public function setBasePath(string $basePath): RouteCollectorInterface\n    {\n        $this->basePath = $basePath;\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getRoutes(): array\n    {\n        return $this->routes;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function removeNamedRoute(string $name): RouteCollectorInterface\n    {\n        $route = $this->getNamedRoute($name);\n\n        unset($this->routesByName[$route->getName()], $this->routes[$route->getIdentifier()]);\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getNamedRoute(string $name): RouteInterface\n    {\n        if (isset($this->routesByName[$name])) {\n            $route = $this->routesByName[$name];\n            if ($route->getName() === $name) {\n                return $route;\n            }\n\n            unset($this->routesByName[$name]);\n        }\n\n        foreach ($this->routes as $route) {\n            if ($name === $route->getName()) {\n                $this->routesByName[$name] = $route;\n                return $route;\n            }\n        }\n\n        throw new RuntimeException('Named route does not exist for name: ' . $name);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function lookupRoute(string $identifier): RouteInterface\n    {\n        if (!isset($this->routes[$identifier])) {\n            throw new RuntimeException('Route not found, looks like your route cache is stale.');\n        }\n        return $this->routes[$identifier];\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function group(string $pattern, $callable): RouteGroupInterface\n    {\n        $routeGroup = $this->createGroup($pattern, $callable);\n        $this->routeGroups[] = $routeGroup;\n\n        $routeGroup->collectRoutes();\n        array_pop($this->routeGroups);\n\n        return $routeGroup;\n    }\n\n    /**\n     * @param string|callable $callable\n     */\n    protected function createGroup(string $pattern, $callable): RouteGroupInterface\n    {\n        $routeCollectorProxy = $this->createProxy($pattern);\n        return new RouteGroup($pattern, $callable, $this->callableResolver, $routeCollectorProxy);\n    }\n\n    protected function createProxy(string $pattern): RouteCollectorProxyInterface\n    {\n        return new RouteCollectorProxy(\n            $this->responseFactory,\n            $this->callableResolver,\n            $this->container,\n            $this,\n            $pattern\n        );\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function map(array $methods, string $pattern, $handler): RouteInterface\n    {\n        $route = $this->createRoute($methods, $pattern, $handler);\n        $this->routes[$route->getIdentifier()] = $route;\n\n        $routeName = $route->getName();\n        if ($routeName !== null && !isset($this->routesByName[$routeName])) {\n            $this->routesByName[$routeName] = $route;\n        }\n\n        $this->routeCounter++;\n\n        return $route;\n    }\n\n    /**\n     * @param string[]        $methods\n     * @param callable|string $callable\n     */\n    protected function createRoute(array $methods, string $pattern, $callable): RouteInterface\n    {\n        return new Route(\n            $methods,\n            $pattern,\n            $callable,\n            $this->responseFactory,\n            $this->callableResolver,\n            $this->container,\n            $this->defaultInvocationStrategy,\n            $this->routeGroups,\n            $this->routeCounter\n        );\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Routing/RouteCollectorProxy.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Routing;\n\nuse Psr\\Container\\ContainerInterface;\nuse Psr\\Http\\Message\\ResponseFactoryInterface;\nuse Slim\\Interfaces\\CallableResolverInterface;\nuse Slim\\Interfaces\\RouteCollectorInterface;\nuse Slim\\Interfaces\\RouteCollectorProxyInterface;\nuse Slim\\Interfaces\\RouteGroupInterface;\nuse Slim\\Interfaces\\RouteInterface;\n\nclass RouteCollectorProxy implements RouteCollectorProxyInterface\n{\n    protected ResponseFactoryInterface $responseFactory;\n\n    protected CallableResolverInterface $callableResolver;\n\n    protected ?ContainerInterface $container = null;\n\n    protected RouteCollectorInterface $routeCollector;\n\n    protected string $groupPattern;\n\n    public function __construct(\n        ResponseFactoryInterface $responseFactory,\n        CallableResolverInterface $callableResolver,\n        ?ContainerInterface $container = null,\n        ?RouteCollectorInterface $routeCollector = null,\n        string $groupPattern = ''\n    ) {\n        $this->responseFactory = $responseFactory;\n        $this->callableResolver = $callableResolver;\n        $this->container = $container;\n        $this->routeCollector = $routeCollector ?? new RouteCollector($responseFactory, $callableResolver, $container);\n        $this->groupPattern = $groupPattern;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getResponseFactory(): ResponseFactoryInterface\n    {\n        return $this->responseFactory;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getCallableResolver(): CallableResolverInterface\n    {\n        return $this->callableResolver;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getContainer(): ?ContainerInterface\n    {\n        return $this->container;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getRouteCollector(): RouteCollectorInterface\n    {\n        return $this->routeCollector;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getBasePath(): string\n    {\n        return $this->routeCollector->getBasePath();\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function setBasePath(string $basePath): RouteCollectorProxyInterface\n    {\n        $this->routeCollector->setBasePath($basePath);\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function get(string $pattern, $callable): RouteInterface\n    {\n        return $this->map(['GET'], $pattern, $callable);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function post(string $pattern, $callable): RouteInterface\n    {\n        return $this->map(['POST'], $pattern, $callable);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function put(string $pattern, $callable): RouteInterface\n    {\n        return $this->map(['PUT'], $pattern, $callable);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function patch(string $pattern, $callable): RouteInterface\n    {\n        return $this->map(['PATCH'], $pattern, $callable);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function delete(string $pattern, $callable): RouteInterface\n    {\n        return $this->map(['DELETE'], $pattern, $callable);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function options(string $pattern, $callable): RouteInterface\n    {\n        return $this->map(['OPTIONS'], $pattern, $callable);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function any(string $pattern, $callable): RouteInterface\n    {\n        return $this->map(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'], $pattern, $callable);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function map(array $methods, string $pattern, $callable): RouteInterface\n    {\n        $pattern = $this->groupPattern . $pattern;\n\n        return $this->routeCollector->map($methods, $pattern, $callable);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function group(string $pattern, $callable): RouteGroupInterface\n    {\n        $pattern = $this->groupPattern . $pattern;\n\n        return $this->routeCollector->group($pattern, $callable);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function redirect(string $from, $to, int $status = 302): RouteInterface\n    {\n        $responseFactory = $this->responseFactory;\n\n        $handler = function () use ($to, $status, $responseFactory) {\n            $response = $responseFactory->createResponse($status);\n            return $response->withHeader('Location', (string) $to);\n        };\n\n        return $this->get($from, $handler);\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Routing/RouteContext.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Routing;\n\nuse Psr\\Http\\Message\\ServerRequestInterface;\nuse RuntimeException;\nuse Slim\\Interfaces\\RouteInterface;\nuse Slim\\Interfaces\\RouteParserInterface;\n\nfinal class RouteContext\n{\n    public const ROUTE = '__route__';\n\n    public const ROUTE_PARSER = '__routeParser__';\n\n    public const ROUTING_RESULTS = '__routingResults__';\n\n    public const BASE_PATH = '__basePath__';\n\n    public static function fromRequest(ServerRequestInterface $serverRequest): self\n    {\n        $route = $serverRequest->getAttribute(self::ROUTE);\n        $routeParser = $serverRequest->getAttribute(self::ROUTE_PARSER);\n        $routingResults = $serverRequest->getAttribute(self::ROUTING_RESULTS);\n        $basePath = $serverRequest->getAttribute(self::BASE_PATH);\n\n        if ($routeParser === null || $routingResults === null) {\n            throw new RuntimeException('Cannot create RouteContext before routing has been completed');\n        }\n\n        /** @var RouteInterface|null $route */\n        /** @var RouteParserInterface $routeParser */\n        /** @var RoutingResults $routingResults */\n        /** @var string|null $basePath */\n        return new self($route, $routeParser, $routingResults, $basePath);\n    }\n\n    private ?RouteInterface $route;\n\n    private RouteParserInterface $routeParser;\n\n    private RoutingResults $routingResults;\n\n    private ?string $basePath;\n\n    private function __construct(\n        ?RouteInterface $route,\n        RouteParserInterface $routeParser,\n        RoutingResults $routingResults,\n        ?string $basePath = null\n    ) {\n        $this->route = $route;\n        $this->routeParser = $routeParser;\n        $this->routingResults = $routingResults;\n        $this->basePath = $basePath;\n    }\n\n    public function getRoute(): ?RouteInterface\n    {\n        return $this->route;\n    }\n\n    public function getRouteParser(): RouteParserInterface\n    {\n        return $this->routeParser;\n    }\n\n    public function getRoutingResults(): RoutingResults\n    {\n        return $this->routingResults;\n    }\n\n    public function getBasePath(): string\n    {\n        if ($this->basePath === null) {\n            throw new RuntimeException('No base path defined.');\n        }\n        return $this->basePath;\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Routing/RouteGroup.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Routing;\n\nuse Psr\\Http\\Server\\MiddlewareInterface;\nuse Slim\\Interfaces\\AdvancedCallableResolverInterface;\nuse Slim\\Interfaces\\CallableResolverInterface;\nuse Slim\\Interfaces\\RouteCollectorProxyInterface;\nuse Slim\\Interfaces\\RouteGroupInterface;\nuse Slim\\MiddlewareDispatcher;\n\nclass RouteGroup implements RouteGroupInterface\n{\n    /**\n     * @var callable|string\n     */\n    protected $callable;\n\n    protected CallableResolverInterface $callableResolver;\n\n    protected RouteCollectorProxyInterface $routeCollectorProxy;\n\n    /**\n     * @var MiddlewareInterface[]|string[]|callable[]\n     */\n    protected array $middleware = [];\n\n    protected string $pattern;\n\n    /**\n     * @param callable|string              $callable\n     */\n    public function __construct(\n        string $pattern,\n        $callable,\n        CallableResolverInterface $callableResolver,\n        RouteCollectorProxyInterface $routeCollectorProxy\n    ) {\n        $this->pattern = $pattern;\n        $this->callable = $callable;\n        $this->callableResolver = $callableResolver;\n        $this->routeCollectorProxy = $routeCollectorProxy;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function collectRoutes(): RouteGroupInterface\n    {\n        if ($this->callableResolver instanceof AdvancedCallableResolverInterface) {\n            $callable = $this->callableResolver->resolveRoute($this->callable);\n        } else {\n            $callable = $this->callableResolver->resolve($this->callable);\n        }\n        $callable($this->routeCollectorProxy);\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function add($middleware): RouteGroupInterface\n    {\n        $this->middleware[] = $middleware;\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function addMiddleware(MiddlewareInterface $middleware): RouteGroupInterface\n    {\n        $this->middleware[] = $middleware;\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function appendMiddlewareToDispatcher(MiddlewareDispatcher $dispatcher): RouteGroupInterface\n    {\n        foreach ($this->middleware as $middleware) {\n            $dispatcher->add($middleware);\n        }\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getPattern(): string\n    {\n        return $this->pattern;\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Routing/RouteParser.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Routing;\n\nuse FastRoute\\RouteParser\\Std;\nuse InvalidArgumentException;\nuse Psr\\Http\\Message\\UriInterface;\nuse Slim\\Interfaces\\RouteCollectorInterface;\nuse Slim\\Interfaces\\RouteParserInterface;\n\nuse function array_key_exists;\nuse function array_reverse;\nuse function http_build_query;\nuse function implode;\nuse function is_string;\n\nclass RouteParser implements RouteParserInterface\n{\n    private RouteCollectorInterface $routeCollector;\n\n    private Std $routeParser;\n\n    public function __construct(RouteCollectorInterface $routeCollector)\n    {\n        $this->routeCollector = $routeCollector;\n        $this->routeParser = new Std();\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function relativeUrlFor(string $routeName, array $data = [], array $queryParams = []): string\n    {\n        $route = $this->routeCollector->getNamedRoute($routeName);\n        $pattern = $route->getPattern();\n\n        $segments = [];\n        $segmentName = '';\n\n        /*\n         * $routes is an associative array of expressions representing a route as multiple segments\n         * There is an expression for each optional parameter plus one without the optional parameters\n         * The most specific is last, hence why we reverse the array before iterating over it\n         */\n        $expressions = array_reverse($this->routeParser->parse($pattern));\n        foreach ($expressions as $expression) {\n            foreach ($expression as $segment) {\n                /*\n                 * Each $segment is either a string or an array of strings\n                 * containing optional parameters of an expression\n                 */\n                if (is_string($segment)) {\n                    $segments[] = $segment;\n                    continue;\n                }\n\n                /** @var string[] $segment */\n                /*\n                 * If we don't have a data element for this segment in the provided $data\n                 * we cancel testing to move onto the next expression with a less specific item\n                 */\n                if (!array_key_exists($segment[0], $data)) {\n                    $segments = [];\n                    $segmentName = $segment[0];\n                    break;\n                }\n\n                $segments[] = $data[$segment[0]];\n            }\n\n            /*\n             * If we get to this logic block we have found all the parameters\n             * for the provided $data which means we don't need to continue testing\n             * less specific expressions\n             */\n            if (!empty($segments)) {\n                break;\n            }\n        }\n\n        if (empty($segments)) {\n            throw new InvalidArgumentException('Missing data for URL segment: ' . $segmentName);\n        }\n\n        $url = implode('', $segments);\n        if ($queryParams) {\n            $url .= '?' . http_build_query($queryParams);\n        }\n\n        return $url;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function urlFor(string $routeName, array $data = [], array $queryParams = []): string\n    {\n        $basePath = $this->routeCollector->getBasePath();\n        $url = $this->relativeUrlFor($routeName, $data, $queryParams);\n\n        if ($basePath) {\n            $url = $basePath . $url;\n        }\n\n        return $url;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function fullUrlFor(UriInterface $uri, string $routeName, array $data = [], array $queryParams = []): string\n    {\n        $path = $this->urlFor($routeName, $data, $queryParams);\n        $scheme = $uri->getScheme();\n        $authority = $uri->getAuthority();\n        $protocol = ($scheme ? $scheme . ':' : '') . ($authority ? '//' . $authority : '');\n        return $protocol . $path;\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Routing/RouteResolver.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Routing;\n\nuse RuntimeException;\nuse Slim\\Interfaces\\DispatcherInterface;\nuse Slim\\Interfaces\\RouteCollectorInterface;\nuse Slim\\Interfaces\\RouteInterface;\nuse Slim\\Interfaces\\RouteResolverInterface;\n\nuse function rawurldecode;\n\n/**\n * RouteResolver instantiates the FastRoute dispatcher\n * and computes the routing results of a given URI and request method\n */\nclass RouteResolver implements RouteResolverInterface\n{\n    protected RouteCollectorInterface $routeCollector;\n\n    private DispatcherInterface $dispatcher;\n\n    public function __construct(RouteCollectorInterface $routeCollector, ?DispatcherInterface $dispatcher = null)\n    {\n        $this->routeCollector = $routeCollector;\n        $this->dispatcher = $dispatcher ?? new Dispatcher($routeCollector);\n    }\n\n    /**\n     * @param string $uri Should be $request->getUri()->getPath()\n     */\n    public function computeRoutingResults(string $uri, string $method): RoutingResults\n    {\n        $uri = rawurldecode($uri);\n        if ($uri === '' || $uri[0] !== '/') {\n            $uri = '/' . $uri;\n        }\n        return $this->dispatcher->dispatch($method, $uri);\n    }\n\n    /**\n     * @throws RuntimeException\n     */\n    public function resolveRoute(string $identifier): RouteInterface\n    {\n        return $this->routeCollector->lookupRoute($identifier);\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Routing/RouteRunner.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Routing;\n\nuse Psr\\Http\\Message\\ResponseInterface;\nuse Psr\\Http\\Message\\ServerRequestInterface;\nuse Psr\\Http\\Server\\RequestHandlerInterface;\nuse Slim\\Exception\\HttpMethodNotAllowedException;\nuse Slim\\Exception\\HttpNotFoundException;\nuse Slim\\Interfaces\\RouteCollectorProxyInterface;\nuse Slim\\Interfaces\\RouteParserInterface;\nuse Slim\\Interfaces\\RouteResolverInterface;\nuse Slim\\Middleware\\RoutingMiddleware;\n\nclass RouteRunner implements RequestHandlerInterface\n{\n    private RouteResolverInterface $routeResolver;\n\n    private RouteParserInterface $routeParser;\n\n    private ?RouteCollectorProxyInterface $routeCollectorProxy;\n\n    public function __construct(\n        RouteResolverInterface $routeResolver,\n        RouteParserInterface $routeParser,\n        ?RouteCollectorProxyInterface $routeCollectorProxy = null\n    ) {\n        $this->routeResolver = $routeResolver;\n        $this->routeParser = $routeParser;\n        $this->routeCollectorProxy = $routeCollectorProxy;\n    }\n\n    /**\n     * This request handler is instantiated automatically in App::__construct()\n     * It is at the very tip of the middleware queue meaning it will be executed\n     * last and it detects whether or not routing has been performed in the user\n     * defined middleware stack. In the event that the user did not perform routing\n     * it is done here\n     *\n     * @throws HttpNotFoundException\n     * @throws HttpMethodNotAllowedException\n     */\n    public function handle(ServerRequestInterface $request): ResponseInterface\n    {\n        // If routing hasn't been done, then do it now so we can dispatch\n        if ($request->getAttribute(RouteContext::ROUTING_RESULTS) === null) {\n            $routingMiddleware = new RoutingMiddleware($this->routeResolver, $this->routeParser);\n            $request = $routingMiddleware->performRouting($request);\n        }\n\n        if ($this->routeCollectorProxy !== null) {\n            $request = $request->withAttribute(\n                RouteContext::BASE_PATH,\n                $this->routeCollectorProxy->getBasePath()\n            );\n        }\n\n        /** @var Route $route */\n        $route = $request->getAttribute(RouteContext::ROUTE);\n        return $route->run($request);\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/Slim/Routing/RoutingResults.php",
    "content": "<?php\n\n/**\n * Slim Framework (https://slimframework.com)\n *\n * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)\n */\n\ndeclare(strict_types=1);\n\nnamespace Slim\\Routing;\n\nuse Slim\\Interfaces\\DispatcherInterface;\n\nuse function rawurldecode;\n\nclass RoutingResults\n{\n    public const NOT_FOUND = 0;\n    public const FOUND = 1;\n    public const METHOD_NOT_ALLOWED = 2;\n\n    protected DispatcherInterface $dispatcher;\n\n    protected string $method;\n\n    protected string $uri;\n\n    /**\n     * The status is one of the constants shown above\n     * NOT_FOUND = 0\n     * FOUND = 1\n     * METHOD_NOT_ALLOWED = 2\n     */\n    protected int $routeStatus;\n\n    protected ?string $routeIdentifier = null;\n\n    /**\n     * @var array<string, string>\n     */\n    protected array $routeArguments;\n\n    /**\n     * @param array<string, string> $routeArguments\n     */\n    public function __construct(\n        DispatcherInterface $dispatcher,\n        string $method,\n        string $uri,\n        int $routeStatus,\n        ?string $routeIdentifier = null,\n        array $routeArguments = []\n    ) {\n        $this->dispatcher = $dispatcher;\n        $this->method = $method;\n        $this->uri = $uri;\n        $this->routeStatus = $routeStatus;\n        $this->routeIdentifier = $routeIdentifier;\n        $this->routeArguments = $routeArguments;\n    }\n\n    public function getDispatcher(): DispatcherInterface\n    {\n        return $this->dispatcher;\n    }\n\n    public function getMethod(): string\n    {\n        return $this->method;\n    }\n\n    public function getUri(): string\n    {\n        return $this->uri;\n    }\n\n    public function getRouteStatus(): int\n    {\n        return $this->routeStatus;\n    }\n\n    public function getRouteIdentifier(): ?string\n    {\n        return $this->routeIdentifier;\n    }\n\n    /**\n     * @return array<string, string>\n     */\n    public function getRouteArguments(bool $urlDecode = true): array\n    {\n        if (!$urlDecode) {\n            return $this->routeArguments;\n        }\n\n        $routeArguments = [];\n        foreach ($this->routeArguments as $key => $value) {\n            $routeArguments[$key] = rawurldecode($value);\n        }\n\n        return $routeArguments;\n    }\n\n    /**\n     * @return string[]\n     */\n    public function getAllowedMethods(): array\n    {\n        return $this->dispatcher->getAllowedMethods($this->uri);\n    }\n}\n"
  },
  {
    "path": "server/vendor/slim/slim/composer.json",
    "content": "{\n    \"name\": \"slim/slim\",\n    \"type\": \"library\",\n    \"description\": \"Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs\",\n    \"keywords\": [\"framework\",\"micro\",\"api\",\"router\"],\n    \"homepage\": \"https://www.slimframework.com\",\n    \"license\": \"MIT\",\n    \"authors\": [\n        {\n            \"name\": \"Josh Lockhart\",\n            \"email\": \"hello@joshlockhart.com\",\n            \"homepage\": \"https://joshlockhart.com\"\n        },\n        {\n            \"name\": \"Andrew Smith\",\n            \"email\": \"a.smith@silentworks.co.uk\",\n            \"homepage\": \"http://silentworks.co.uk\"\n        },\n        {\n            \"name\": \"Rob Allen\",\n            \"email\": \"rob@akrabat.com\",\n            \"homepage\": \"http://akrabat.com\"\n        },\n        {\n            \"name\": \"Pierre Berube\",\n            \"email\": \"pierre@lgse.com\",\n            \"homepage\": \"http://www.lgse.com\"\n        },\n        {\n            \"name\": \"Gabriel Manricks\",\n            \"email\": \"gmanricks@me.com\",\n            \"homepage\": \"http://gabrielmanricks.com\"\n        }\n    ],\n    \"support\": {\n        \"docs\": \"https://www.slimframework.com/docs/v4/\",\n        \"forum\": \"https://discourse.slimframework.com/\",\n        \"irc\": \"irc://irc.freenode.net:6667/slimphp\",\n        \"issues\": \"https://github.com/slimphp/Slim/issues\",\n        \"rss\": \"https://www.slimframework.com/blog/feed.rss\",\n        \"slack\": \"https://slimphp.slack.com/\",\n        \"source\": \"https://github.com/slimphp/Slim\",\n        \"wiki\": \"https://github.com/slimphp/Slim/wiki\"\n    },\n    \"require\": {\n        \"php\": \"^7.4 || ^8.0\",\n        \"ext-json\": \"*\",\n        \"nikic/fast-route\": \"^1.3\",\n        \"psr/container\": \"^1.0 || ^2.0\",\n        \"psr/http-factory\": \"^1.0\",\n        \"psr/http-message\": \"^1.1 || ^2.0\",\n        \"psr/http-server-handler\": \"^1.0\",\n        \"psr/http-server-middleware\": \"^1.0\",\n        \"psr/log\": \"^1.1 || ^2.0 || ^3.0\"\n    },\n    \"require-dev\": {\n        \"ext-simplexml\": \"*\",\n        \"adriansuter/php-autoload-override\": \"^1.4\",\n        \"guzzlehttp/psr7\": \"^2.6\",\n        \"httpsoft/http-message\": \"^1.1\",\n        \"httpsoft/http-server-request\": \"^1.1\",\n        \"laminas/laminas-diactoros\": \"^2.17 || ^3\",\n        \"nyholm/psr7\": \"^1.8\",\n        \"nyholm/psr7-server\": \"^1.1\",\n        \"phpspec/prophecy\": \"^1.19\",\n        \"phpspec/prophecy-phpunit\": \"^2.1\",\n        \"phpstan/phpstan\": \"^1.10\",\n        \"phpunit/phpunit\": \"^9.6\",\n        \"slim/http\": \"^1.3\",\n        \"slim/psr7\": \"^1.6\",\n        \"squizlabs/php_codesniffer\": \"^3.9\"\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"Slim\\\\\": \"Slim\"\n        }\n    },\n    \"autoload-dev\": {\n        \"psr-4\": {\n            \"Slim\\\\Tests\\\\\": \"tests\"\n        }\n    },\n    \"scripts\": {\n        \"test\": [\n            \"@phpunit\",\n            \"@phpcs\",\n            \"@phpstan\"\n        ],\n        \"phpunit\": \"phpunit\",\n        \"phpcs\": \"phpcs\",\n        \"phpstan\": \"phpstan --memory-limit=-1\"\n    },\n    \"suggest\": {\n        \"ext-simplexml\": \"Needed to support XML format in BodyParsingMiddleware\",\n        \"ext-xml\": \"Needed to support XML format in BodyParsingMiddleware\",\n        \"slim/psr7\": \"Slim PSR-7 implementation. See https://www.slimframework.com/docs/v4/start/installation.html for more information.\",\n        \"php-di/php-di\": \"PHP-DI is the recommended container library to be used with Slim\"\n    },\n    \"config\": {\n        \"sort-packages\": true\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Application.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console;\n\nuse Symfony\\Component\\Console\\Command\\Command;\nuse Symfony\\Component\\Console\\Command\\CompleteCommand;\nuse Symfony\\Component\\Console\\Command\\DumpCompletionCommand;\nuse Symfony\\Component\\Console\\Command\\HelpCommand;\nuse Symfony\\Component\\Console\\Command\\LazyCommand;\nuse Symfony\\Component\\Console\\Command\\ListCommand;\nuse Symfony\\Component\\Console\\Command\\SignalableCommandInterface;\nuse Symfony\\Component\\Console\\CommandLoader\\CommandLoaderInterface;\nuse Symfony\\Component\\Console\\Completion\\CompletionInput;\nuse Symfony\\Component\\Console\\Completion\\CompletionSuggestions;\nuse Symfony\\Component\\Console\\Event\\ConsoleCommandEvent;\nuse Symfony\\Component\\Console\\Event\\ConsoleErrorEvent;\nuse Symfony\\Component\\Console\\Event\\ConsoleSignalEvent;\nuse Symfony\\Component\\Console\\Event\\ConsoleTerminateEvent;\nuse Symfony\\Component\\Console\\Exception\\CommandNotFoundException;\nuse Symfony\\Component\\Console\\Exception\\ExceptionInterface;\nuse Symfony\\Component\\Console\\Exception\\LogicException;\nuse Symfony\\Component\\Console\\Exception\\NamespaceNotFoundException;\nuse Symfony\\Component\\Console\\Exception\\RuntimeException;\nuse Symfony\\Component\\Console\\Formatter\\OutputFormatter;\nuse Symfony\\Component\\Console\\Helper\\DebugFormatterHelper;\nuse Symfony\\Component\\Console\\Helper\\FormatterHelper;\nuse Symfony\\Component\\Console\\Helper\\Helper;\nuse Symfony\\Component\\Console\\Helper\\HelperSet;\nuse Symfony\\Component\\Console\\Helper\\ProcessHelper;\nuse Symfony\\Component\\Console\\Helper\\QuestionHelper;\nuse Symfony\\Component\\Console\\Input\\ArgvInput;\nuse Symfony\\Component\\Console\\Input\\ArrayInput;\nuse Symfony\\Component\\Console\\Input\\InputArgument;\nuse Symfony\\Component\\Console\\Input\\InputAwareInterface;\nuse Symfony\\Component\\Console\\Input\\InputDefinition;\nuse Symfony\\Component\\Console\\Input\\InputInterface;\nuse Symfony\\Component\\Console\\Input\\InputOption;\nuse Symfony\\Component\\Console\\Output\\ConsoleOutput;\nuse Symfony\\Component\\Console\\Output\\ConsoleOutputInterface;\nuse Symfony\\Component\\Console\\Output\\OutputInterface;\nuse Symfony\\Component\\Console\\SignalRegistry\\SignalRegistry;\nuse Symfony\\Component\\Console\\Style\\SymfonyStyle;\nuse Symfony\\Component\\ErrorHandler\\ErrorHandler;\nuse Symfony\\Contracts\\EventDispatcher\\EventDispatcherInterface;\nuse Symfony\\Contracts\\Service\\ResetInterface;\n\n/**\n * An Application is the container for a collection of commands.\n *\n * It is the main entry point of a Console application.\n *\n * This class is optimized for a standard CLI environment.\n *\n * Usage:\n *\n *     $app = new Application('myapp', '1.0 (stable)');\n *     $app->add(new SimpleCommand());\n *     $app->run();\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass Application implements ResetInterface\n{\n    private $commands = [];\n    private $wantHelps = false;\n    private $runningCommand;\n    private $name;\n    private $version;\n    private $commandLoader;\n    private $catchExceptions = true;\n    private $autoExit = true;\n    private $definition;\n    private $helperSet;\n    private $dispatcher;\n    private $terminal;\n    private $defaultCommand;\n    private $singleCommand = false;\n    private $initialized;\n    private $signalRegistry;\n    private $signalsToDispatchEvent = [];\n\n    public function __construct(string $name = 'UNKNOWN', string $version = 'UNKNOWN')\n    {\n        $this->name = $name;\n        $this->version = $version;\n        $this->terminal = new Terminal();\n        $this->defaultCommand = 'list';\n        if (\\defined('SIGINT') && SignalRegistry::isSupported()) {\n            $this->signalRegistry = new SignalRegistry();\n            $this->signalsToDispatchEvent = [\\SIGINT, \\SIGTERM, \\SIGUSR1, \\SIGUSR2];\n        }\n    }\n\n    /**\n     * @final\n     */\n    public function setDispatcher(EventDispatcherInterface $dispatcher)\n    {\n        $this->dispatcher = $dispatcher;\n    }\n\n    public function setCommandLoader(CommandLoaderInterface $commandLoader)\n    {\n        $this->commandLoader = $commandLoader;\n    }\n\n    public function getSignalRegistry(): SignalRegistry\n    {\n        if (!$this->signalRegistry) {\n            throw new RuntimeException('Signals are not supported. Make sure that the `pcntl` extension is installed and that \"pcntl_*\" functions are not disabled by your php.ini\\'s \"disable_functions\" directive.');\n        }\n\n        return $this->signalRegistry;\n    }\n\n    public function setSignalsToDispatchEvent(int ...$signalsToDispatchEvent)\n    {\n        $this->signalsToDispatchEvent = $signalsToDispatchEvent;\n    }\n\n    /**\n     * Runs the current application.\n     *\n     * @return int 0 if everything went fine, or an error code\n     *\n     * @throws \\Exception When running fails. Bypass this when {@link setCatchExceptions()}.\n     */\n    public function run(?InputInterface $input = null, ?OutputInterface $output = null)\n    {\n        if (\\function_exists('putenv')) {\n            @putenv('LINES='.$this->terminal->getHeight());\n            @putenv('COLUMNS='.$this->terminal->getWidth());\n        }\n\n        if (null === $input) {\n            $input = new ArgvInput();\n        }\n\n        if (null === $output) {\n            $output = new ConsoleOutput();\n        }\n\n        $renderException = function (\\Throwable $e) use ($output) {\n            if ($output instanceof ConsoleOutputInterface) {\n                $this->renderThrowable($e, $output->getErrorOutput());\n            } else {\n                $this->renderThrowable($e, $output);\n            }\n        };\n        if ($phpHandler = set_exception_handler($renderException)) {\n            restore_exception_handler();\n            if (!\\is_array($phpHandler) || !$phpHandler[0] instanceof ErrorHandler) {\n                $errorHandler = true;\n            } elseif ($errorHandler = $phpHandler[0]->setExceptionHandler($renderException)) {\n                $phpHandler[0]->setExceptionHandler($errorHandler);\n            }\n        }\n\n        try {\n            $this->configureIO($input, $output);\n\n            $exitCode = $this->doRun($input, $output);\n        } catch (\\Exception $e) {\n            if (!$this->catchExceptions) {\n                throw $e;\n            }\n\n            $renderException($e);\n\n            $exitCode = $e->getCode();\n            if (is_numeric($exitCode)) {\n                $exitCode = (int) $exitCode;\n                if ($exitCode <= 0) {\n                    $exitCode = 1;\n                }\n            } else {\n                $exitCode = 1;\n            }\n        } finally {\n            // if the exception handler changed, keep it\n            // otherwise, unregister $renderException\n            if (!$phpHandler) {\n                if (set_exception_handler($renderException) === $renderException) {\n                    restore_exception_handler();\n                }\n                restore_exception_handler();\n            } elseif (!$errorHandler) {\n                $finalHandler = $phpHandler[0]->setExceptionHandler(null);\n                if ($finalHandler !== $renderException) {\n                    $phpHandler[0]->setExceptionHandler($finalHandler);\n                }\n            }\n        }\n\n        if ($this->autoExit) {\n            if ($exitCode > 255) {\n                $exitCode = 255;\n            }\n\n            exit($exitCode);\n        }\n\n        return $exitCode;\n    }\n\n    /**\n     * Runs the current application.\n     *\n     * @return int 0 if everything went fine, or an error code\n     */\n    public function doRun(InputInterface $input, OutputInterface $output)\n    {\n        if (true === $input->hasParameterOption(['--version', '-V'], true)) {\n            $output->writeln($this->getLongVersion());\n\n            return 0;\n        }\n\n        try {\n            // Makes ArgvInput::getFirstArgument() able to distinguish an option from an argument.\n            $input->bind($this->getDefinition());\n        } catch (ExceptionInterface $e) {\n            // Errors must be ignored, full binding/validation happens later when the command is known.\n        }\n\n        $name = $this->getCommandName($input);\n        if (true === $input->hasParameterOption(['--help', '-h'], true)) {\n            if (!$name) {\n                $name = 'help';\n                $input = new ArrayInput(['command_name' => $this->defaultCommand]);\n            } else {\n                $this->wantHelps = true;\n            }\n        }\n\n        if (!$name) {\n            $name = $this->defaultCommand;\n            $definition = $this->getDefinition();\n            $definition->setArguments(array_merge(\n                $definition->getArguments(),\n                [\n                    'command' => new InputArgument('command', InputArgument::OPTIONAL, $definition->getArgument('command')->getDescription(), $name),\n                ]\n            ));\n        }\n\n        try {\n            $this->runningCommand = null;\n            // the command name MUST be the first element of the input\n            $command = $this->find($name);\n        } catch (\\Throwable $e) {\n            if (!($e instanceof CommandNotFoundException && !$e instanceof NamespaceNotFoundException) || 1 !== \\count($alternatives = $e->getAlternatives()) || !$input->isInteractive()) {\n                if (null !== $this->dispatcher) {\n                    $event = new ConsoleErrorEvent($input, $output, $e);\n                    $this->dispatcher->dispatch($event, ConsoleEvents::ERROR);\n\n                    if (0 === $event->getExitCode()) {\n                        return 0;\n                    }\n\n                    $e = $event->getError();\n                }\n\n                throw $e;\n            }\n\n            $alternative = $alternatives[0];\n\n            $style = new SymfonyStyle($input, $output);\n            $output->writeln('');\n            $formattedBlock = (new FormatterHelper())->formatBlock(sprintf('Command \"%s\" is not defined.', $name), 'error', true);\n            $output->writeln($formattedBlock);\n            if (!$style->confirm(sprintf('Do you want to run \"%s\" instead? ', $alternative), false)) {\n                if (null !== $this->dispatcher) {\n                    $event = new ConsoleErrorEvent($input, $output, $e);\n                    $this->dispatcher->dispatch($event, ConsoleEvents::ERROR);\n\n                    return $event->getExitCode();\n                }\n\n                return 1;\n            }\n\n            $command = $this->find($alternative);\n        }\n\n        if ($command instanceof LazyCommand) {\n            $command = $command->getCommand();\n        }\n\n        $this->runningCommand = $command;\n        $exitCode = $this->doRunCommand($command, $input, $output);\n        $this->runningCommand = null;\n\n        return $exitCode;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function reset()\n    {\n    }\n\n    public function setHelperSet(HelperSet $helperSet)\n    {\n        $this->helperSet = $helperSet;\n    }\n\n    /**\n     * Get the helper set associated with the command.\n     *\n     * @return HelperSet\n     */\n    public function getHelperSet()\n    {\n        if (!$this->helperSet) {\n            $this->helperSet = $this->getDefaultHelperSet();\n        }\n\n        return $this->helperSet;\n    }\n\n    public function setDefinition(InputDefinition $definition)\n    {\n        $this->definition = $definition;\n    }\n\n    /**\n     * Gets the InputDefinition related to this Application.\n     *\n     * @return InputDefinition\n     */\n    public function getDefinition()\n    {\n        if (!$this->definition) {\n            $this->definition = $this->getDefaultInputDefinition();\n        }\n\n        if ($this->singleCommand) {\n            $inputDefinition = $this->definition;\n            $inputDefinition->setArguments();\n\n            return $inputDefinition;\n        }\n\n        return $this->definition;\n    }\n\n    /**\n     * Adds suggestions to $suggestions for the current completion input (e.g. option or argument).\n     */\n    public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void\n    {\n        if (\n            CompletionInput::TYPE_ARGUMENT_VALUE === $input->getCompletionType()\n            && 'command' === $input->getCompletionName()\n        ) {\n            $commandNames = [];\n            foreach ($this->all() as $name => $command) {\n                // skip hidden commands and aliased commands as they already get added below\n                if ($command->isHidden() || $command->getName() !== $name) {\n                    continue;\n                }\n                $commandNames[] = $command->getName();\n                foreach ($command->getAliases() as $name) {\n                    $commandNames[] = $name;\n                }\n            }\n            $suggestions->suggestValues(array_filter($commandNames));\n\n            return;\n        }\n\n        if (CompletionInput::TYPE_OPTION_NAME === $input->getCompletionType()) {\n            $suggestions->suggestOptions($this->getDefinition()->getOptions());\n\n            return;\n        }\n    }\n\n    /**\n     * Gets the help message.\n     *\n     * @return string\n     */\n    public function getHelp()\n    {\n        return $this->getLongVersion();\n    }\n\n    /**\n     * Gets whether to catch exceptions or not during commands execution.\n     *\n     * @return bool\n     */\n    public function areExceptionsCaught()\n    {\n        return $this->catchExceptions;\n    }\n\n    /**\n     * Sets whether to catch exceptions or not during commands execution.\n     */\n    public function setCatchExceptions(bool $boolean)\n    {\n        $this->catchExceptions = $boolean;\n    }\n\n    /**\n     * Gets whether to automatically exit after a command execution or not.\n     *\n     * @return bool\n     */\n    public function isAutoExitEnabled()\n    {\n        return $this->autoExit;\n    }\n\n    /**\n     * Sets whether to automatically exit after a command execution or not.\n     */\n    public function setAutoExit(bool $boolean)\n    {\n        $this->autoExit = $boolean;\n    }\n\n    /**\n     * Gets the name of the application.\n     *\n     * @return string\n     */\n    public function getName()\n    {\n        return $this->name;\n    }\n\n    /**\n     * Sets the application name.\n     **/\n    public function setName(string $name)\n    {\n        $this->name = $name;\n    }\n\n    /**\n     * Gets the application version.\n     *\n     * @return string\n     */\n    public function getVersion()\n    {\n        return $this->version;\n    }\n\n    /**\n     * Sets the application version.\n     */\n    public function setVersion(string $version)\n    {\n        $this->version = $version;\n    }\n\n    /**\n     * Returns the long version of the application.\n     *\n     * @return string\n     */\n    public function getLongVersion()\n    {\n        if ('UNKNOWN' !== $this->getName()) {\n            if ('UNKNOWN' !== $this->getVersion()) {\n                return sprintf('%s <info>%s</info>', $this->getName(), $this->getVersion());\n            }\n\n            return $this->getName();\n        }\n\n        return 'Console Tool';\n    }\n\n    /**\n     * Registers a new command.\n     *\n     * @return Command\n     */\n    public function register(string $name)\n    {\n        return $this->add(new Command($name));\n    }\n\n    /**\n     * Adds an array of command objects.\n     *\n     * If a Command is not enabled it will not be added.\n     *\n     * @param Command[] $commands An array of commands\n     */\n    public function addCommands(array $commands)\n    {\n        foreach ($commands as $command) {\n            $this->add($command);\n        }\n    }\n\n    /**\n     * Adds a command object.\n     *\n     * If a command with the same name already exists, it will be overridden.\n     * If the command is not enabled it will not be added.\n     *\n     * @return Command|null\n     */\n    public function add(Command $command)\n    {\n        $this->init();\n\n        $command->setApplication($this);\n\n        if (!$command->isEnabled()) {\n            $command->setApplication(null);\n\n            return null;\n        }\n\n        if (!$command instanceof LazyCommand) {\n            // Will throw if the command is not correctly initialized.\n            $command->getDefinition();\n        }\n\n        if (!$command->getName()) {\n            throw new LogicException(sprintf('The command defined in \"%s\" cannot have an empty name.', get_debug_type($command)));\n        }\n\n        $this->commands[$command->getName()] = $command;\n\n        foreach ($command->getAliases() as $alias) {\n            $this->commands[$alias] = $command;\n        }\n\n        return $command;\n    }\n\n    /**\n     * Returns a registered command by name or alias.\n     *\n     * @return Command\n     *\n     * @throws CommandNotFoundException When given command name does not exist\n     */\n    public function get(string $name)\n    {\n        $this->init();\n\n        if (!$this->has($name)) {\n            throw new CommandNotFoundException(sprintf('The command \"%s\" does not exist.', $name));\n        }\n\n        // When the command has a different name than the one used at the command loader level\n        if (!isset($this->commands[$name])) {\n            throw new CommandNotFoundException(sprintf('The \"%s\" command cannot be found because it is registered under multiple names. Make sure you don\\'t set a different name via constructor or \"setName()\".', $name));\n        }\n\n        $command = $this->commands[$name];\n\n        if ($this->wantHelps) {\n            $this->wantHelps = false;\n\n            $helpCommand = $this->get('help');\n            $helpCommand->setCommand($command);\n\n            return $helpCommand;\n        }\n\n        return $command;\n    }\n\n    /**\n     * Returns true if the command exists, false otherwise.\n     *\n     * @return bool\n     */\n    public function has(string $name)\n    {\n        $this->init();\n\n        return isset($this->commands[$name]) || ($this->commandLoader && $this->commandLoader->has($name) && $this->add($this->commandLoader->get($name)));\n    }\n\n    /**\n     * Returns an array of all unique namespaces used by currently registered commands.\n     *\n     * It does not return the global namespace which always exists.\n     *\n     * @return string[]\n     */\n    public function getNamespaces()\n    {\n        $namespaces = [];\n        foreach ($this->all() as $command) {\n            if ($command->isHidden()) {\n                continue;\n            }\n\n            $namespaces[] = $this->extractAllNamespaces($command->getName());\n\n            foreach ($command->getAliases() as $alias) {\n                $namespaces[] = $this->extractAllNamespaces($alias);\n            }\n        }\n\n        return array_values(array_unique(array_filter(array_merge([], ...$namespaces))));\n    }\n\n    /**\n     * Finds a registered namespace by a name or an abbreviation.\n     *\n     * @return string\n     *\n     * @throws NamespaceNotFoundException When namespace is incorrect or ambiguous\n     */\n    public function findNamespace(string $namespace)\n    {\n        $allNamespaces = $this->getNamespaces();\n        $expr = implode('[^:]*:', array_map('preg_quote', explode(':', $namespace))).'[^:]*';\n        $namespaces = preg_grep('{^'.$expr.'}', $allNamespaces);\n\n        if (empty($namespaces)) {\n            $message = sprintf('There are no commands defined in the \"%s\" namespace.', $namespace);\n\n            if ($alternatives = $this->findAlternatives($namespace, $allNamespaces)) {\n                if (1 == \\count($alternatives)) {\n                    $message .= \"\\n\\nDid you mean this?\\n    \";\n                } else {\n                    $message .= \"\\n\\nDid you mean one of these?\\n    \";\n                }\n\n                $message .= implode(\"\\n    \", $alternatives);\n            }\n\n            throw new NamespaceNotFoundException($message, $alternatives);\n        }\n\n        $exact = \\in_array($namespace, $namespaces, true);\n        if (\\count($namespaces) > 1 && !$exact) {\n            throw new NamespaceNotFoundException(sprintf(\"The namespace \\\"%s\\\" is ambiguous.\\nDid you mean one of these?\\n%s.\", $namespace, $this->getAbbreviationSuggestions(array_values($namespaces))), array_values($namespaces));\n        }\n\n        return $exact ? $namespace : reset($namespaces);\n    }\n\n    /**\n     * Finds a command by name or alias.\n     *\n     * Contrary to get, this command tries to find the best\n     * match if you give it an abbreviation of a name or alias.\n     *\n     * @return Command\n     *\n     * @throws CommandNotFoundException When command name is incorrect or ambiguous\n     */\n    public function find(string $name)\n    {\n        $this->init();\n\n        $aliases = [];\n\n        foreach ($this->commands as $command) {\n            foreach ($command->getAliases() as $alias) {\n                if (!$this->has($alias)) {\n                    $this->commands[$alias] = $command;\n                }\n            }\n        }\n\n        if ($this->has($name)) {\n            return $this->get($name);\n        }\n\n        $allCommands = $this->commandLoader ? array_merge($this->commandLoader->getNames(), array_keys($this->commands)) : array_keys($this->commands);\n        $expr = implode('[^:]*:', array_map('preg_quote', explode(':', $name))).'[^:]*';\n        $commands = preg_grep('{^'.$expr.'}', $allCommands);\n\n        if (empty($commands)) {\n            $commands = preg_grep('{^'.$expr.'}i', $allCommands);\n        }\n\n        // if no commands matched or we just matched namespaces\n        if (empty($commands) || \\count(preg_grep('{^'.$expr.'$}i', $commands)) < 1) {\n            if (false !== $pos = strrpos($name, ':')) {\n                // check if a namespace exists and contains commands\n                $this->findNamespace(substr($name, 0, $pos));\n            }\n\n            $message = sprintf('Command \"%s\" is not defined.', $name);\n\n            if ($alternatives = $this->findAlternatives($name, $allCommands)) {\n                // remove hidden commands\n                $alternatives = array_filter($alternatives, function ($name) {\n                    return !$this->get($name)->isHidden();\n                });\n\n                if (1 == \\count($alternatives)) {\n                    $message .= \"\\n\\nDid you mean this?\\n    \";\n                } else {\n                    $message .= \"\\n\\nDid you mean one of these?\\n    \";\n                }\n                $message .= implode(\"\\n    \", $alternatives);\n            }\n\n            throw new CommandNotFoundException($message, array_values($alternatives));\n        }\n\n        // filter out aliases for commands which are already on the list\n        if (\\count($commands) > 1) {\n            $commandList = $this->commandLoader ? array_merge(array_flip($this->commandLoader->getNames()), $this->commands) : $this->commands;\n            $commands = array_unique(array_filter($commands, function ($nameOrAlias) use (&$commandList, $commands, &$aliases) {\n                if (!$commandList[$nameOrAlias] instanceof Command) {\n                    $commandList[$nameOrAlias] = $this->commandLoader->get($nameOrAlias);\n                }\n\n                $commandName = $commandList[$nameOrAlias]->getName();\n\n                $aliases[$nameOrAlias] = $commandName;\n\n                return $commandName === $nameOrAlias || !\\in_array($commandName, $commands);\n            }));\n        }\n\n        if (\\count($commands) > 1) {\n            $usableWidth = $this->terminal->getWidth() - 10;\n            $abbrevs = array_values($commands);\n            $maxLen = 0;\n            foreach ($abbrevs as $abbrev) {\n                $maxLen = max(Helper::width($abbrev), $maxLen);\n            }\n            $abbrevs = array_map(function ($cmd) use ($commandList, $usableWidth, $maxLen, &$commands) {\n                if ($commandList[$cmd]->isHidden()) {\n                    unset($commands[array_search($cmd, $commands)]);\n\n                    return false;\n                }\n\n                $abbrev = str_pad($cmd, $maxLen, ' ').' '.$commandList[$cmd]->getDescription();\n\n                return Helper::width($abbrev) > $usableWidth ? Helper::substr($abbrev, 0, $usableWidth - 3).'...' : $abbrev;\n            }, array_values($commands));\n\n            if (\\count($commands) > 1) {\n                $suggestions = $this->getAbbreviationSuggestions(array_filter($abbrevs));\n\n                throw new CommandNotFoundException(sprintf(\"Command \\\"%s\\\" is ambiguous.\\nDid you mean one of these?\\n%s.\", $name, $suggestions), array_values($commands));\n            }\n        }\n\n        $command = $this->get(reset($commands));\n\n        if ($command->isHidden()) {\n            throw new CommandNotFoundException(sprintf('The command \"%s\" does not exist.', $name));\n        }\n\n        return $command;\n    }\n\n    /**\n     * Gets the commands (registered in the given namespace if provided).\n     *\n     * The array keys are the full names and the values the command instances.\n     *\n     * @return Command[]\n     */\n    public function all(?string $namespace = null)\n    {\n        $this->init();\n\n        if (null === $namespace) {\n            if (!$this->commandLoader) {\n                return $this->commands;\n            }\n\n            $commands = $this->commands;\n            foreach ($this->commandLoader->getNames() as $name) {\n                if (!isset($commands[$name]) && $this->has($name)) {\n                    $commands[$name] = $this->get($name);\n                }\n            }\n\n            return $commands;\n        }\n\n        $commands = [];\n        foreach ($this->commands as $name => $command) {\n            if ($namespace === $this->extractNamespace($name, substr_count($namespace, ':') + 1)) {\n                $commands[$name] = $command;\n            }\n        }\n\n        if ($this->commandLoader) {\n            foreach ($this->commandLoader->getNames() as $name) {\n                if (!isset($commands[$name]) && $namespace === $this->extractNamespace($name, substr_count($namespace, ':') + 1) && $this->has($name)) {\n                    $commands[$name] = $this->get($name);\n                }\n            }\n        }\n\n        return $commands;\n    }\n\n    /**\n     * Returns an array of possible abbreviations given a set of names.\n     *\n     * @return string[][]\n     */\n    public static function getAbbreviations(array $names)\n    {\n        $abbrevs = [];\n        foreach ($names as $name) {\n            for ($len = \\strlen($name); $len > 0; --$len) {\n                $abbrev = substr($name, 0, $len);\n                $abbrevs[$abbrev][] = $name;\n            }\n        }\n\n        return $abbrevs;\n    }\n\n    public function renderThrowable(\\Throwable $e, OutputInterface $output): void\n    {\n        $output->writeln('', OutputInterface::VERBOSITY_QUIET);\n\n        $this->doRenderThrowable($e, $output);\n\n        if (null !== $this->runningCommand) {\n            $output->writeln(sprintf('<info>%s</info>', OutputFormatter::escape(sprintf($this->runningCommand->getSynopsis(), $this->getName()))), OutputInterface::VERBOSITY_QUIET);\n            $output->writeln('', OutputInterface::VERBOSITY_QUIET);\n        }\n    }\n\n    protected function doRenderThrowable(\\Throwable $e, OutputInterface $output): void\n    {\n        do {\n            $message = trim($e->getMessage());\n            if ('' === $message || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) {\n                $class = get_debug_type($e);\n                $title = sprintf('  [%s%s]  ', $class, 0 !== ($code = $e->getCode()) ? ' ('.$code.')' : '');\n                $len = Helper::width($title);\n            } else {\n                $len = 0;\n            }\n\n            if (str_contains($message, \"@anonymous\\0\")) {\n                $message = preg_replace_callback('/[a-zA-Z_\\x7f-\\xff][\\\\\\\\a-zA-Z0-9_\\x7f-\\xff]*+@anonymous\\x00.*?\\.php(?:0x?|:[0-9]++\\$)?[0-9a-fA-F]++/', function ($m) {\n                    return class_exists($m[0], false) ? (get_parent_class($m[0]) ?: key(class_implements($m[0])) ?: 'class').'@anonymous' : $m[0];\n                }, $message);\n            }\n\n            $width = $this->terminal->getWidth() ? $this->terminal->getWidth() - 1 : \\PHP_INT_MAX;\n            $lines = [];\n            foreach ('' !== $message ? preg_split('/\\r?\\n/', $message) : [] as $line) {\n                foreach ($this->splitStringByWidth($line, $width - 4) as $line) {\n                    // pre-format lines to get the right string length\n                    $lineLength = Helper::width($line) + 4;\n                    $lines[] = [$line, $lineLength];\n\n                    $len = max($lineLength, $len);\n                }\n            }\n\n            $messages = [];\n            if (!$e instanceof ExceptionInterface || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) {\n                $messages[] = sprintf('<comment>%s</comment>', OutputFormatter::escape(sprintf('In %s line %s:', basename($e->getFile()) ?: 'n/a', $e->getLine() ?: 'n/a')));\n            }\n            $messages[] = $emptyLine = sprintf('<error>%s</error>', str_repeat(' ', $len));\n            if ('' === $message || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) {\n                $messages[] = sprintf('<error>%s%s</error>', $title, str_repeat(' ', max(0, $len - Helper::width($title))));\n            }\n            foreach ($lines as $line) {\n                $messages[] = sprintf('<error>  %s  %s</error>', OutputFormatter::escape($line[0]), str_repeat(' ', $len - $line[1]));\n            }\n            $messages[] = $emptyLine;\n            $messages[] = '';\n\n            $output->writeln($messages, OutputInterface::VERBOSITY_QUIET);\n\n            if (OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) {\n                $output->writeln('<comment>Exception trace:</comment>', OutputInterface::VERBOSITY_QUIET);\n\n                // exception related properties\n                $trace = $e->getTrace();\n\n                array_unshift($trace, [\n                    'function' => '',\n                    'file' => $e->getFile() ?: 'n/a',\n                    'line' => $e->getLine() ?: 'n/a',\n                    'args' => [],\n                ]);\n\n                for ($i = 0, $count = \\count($trace); $i < $count; ++$i) {\n                    $class = $trace[$i]['class'] ?? '';\n                    $type = $trace[$i]['type'] ?? '';\n                    $function = $trace[$i]['function'] ?? '';\n                    $file = $trace[$i]['file'] ?? 'n/a';\n                    $line = $trace[$i]['line'] ?? 'n/a';\n\n                    $output->writeln(sprintf(' %s%s at <info>%s:%s</info>', $class, $function ? $type.$function.'()' : '', $file, $line), OutputInterface::VERBOSITY_QUIET);\n                }\n\n                $output->writeln('', OutputInterface::VERBOSITY_QUIET);\n            }\n        } while ($e = $e->getPrevious());\n    }\n\n    /**\n     * Configures the input and output instances based on the user arguments and options.\n     */\n    protected function configureIO(InputInterface $input, OutputInterface $output)\n    {\n        if (true === $input->hasParameterOption(['--ansi'], true)) {\n            $output->setDecorated(true);\n        } elseif (true === $input->hasParameterOption(['--no-ansi'], true)) {\n            $output->setDecorated(false);\n        }\n\n        if (true === $input->hasParameterOption(['--no-interaction', '-n'], true)) {\n            $input->setInteractive(false);\n        }\n\n        switch ($shellVerbosity = (int) getenv('SHELL_VERBOSITY')) {\n            case -1:\n                $output->setVerbosity(OutputInterface::VERBOSITY_QUIET);\n                break;\n            case 1:\n                $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE);\n                break;\n            case 2:\n                $output->setVerbosity(OutputInterface::VERBOSITY_VERY_VERBOSE);\n                break;\n            case 3:\n                $output->setVerbosity(OutputInterface::VERBOSITY_DEBUG);\n                break;\n            default:\n                $shellVerbosity = 0;\n                break;\n        }\n\n        if (true === $input->hasParameterOption(['--quiet', '-q'], true)) {\n            $output->setVerbosity(OutputInterface::VERBOSITY_QUIET);\n            $shellVerbosity = -1;\n        } else {\n            if ($input->hasParameterOption('-vvv', true) || $input->hasParameterOption('--verbose=3', true) || 3 === $input->getParameterOption('--verbose', false, true)) {\n                $output->setVerbosity(OutputInterface::VERBOSITY_DEBUG);\n                $shellVerbosity = 3;\n            } elseif ($input->hasParameterOption('-vv', true) || $input->hasParameterOption('--verbose=2', true) || 2 === $input->getParameterOption('--verbose', false, true)) {\n                $output->setVerbosity(OutputInterface::VERBOSITY_VERY_VERBOSE);\n                $shellVerbosity = 2;\n            } elseif ($input->hasParameterOption('-v', true) || $input->hasParameterOption('--verbose=1', true) || $input->hasParameterOption('--verbose', true) || $input->getParameterOption('--verbose', false, true)) {\n                $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE);\n                $shellVerbosity = 1;\n            }\n        }\n\n        if (-1 === $shellVerbosity) {\n            $input->setInteractive(false);\n        }\n\n        if (\\function_exists('putenv')) {\n            @putenv('SHELL_VERBOSITY='.$shellVerbosity);\n        }\n        $_ENV['SHELL_VERBOSITY'] = $shellVerbosity;\n        $_SERVER['SHELL_VERBOSITY'] = $shellVerbosity;\n    }\n\n    /**\n     * Runs the current command.\n     *\n     * If an event dispatcher has been attached to the application,\n     * events are also dispatched during the life-cycle of the command.\n     *\n     * @return int 0 if everything went fine, or an error code\n     */\n    protected function doRunCommand(Command $command, InputInterface $input, OutputInterface $output)\n    {\n        foreach ($command->getHelperSet() as $helper) {\n            if ($helper instanceof InputAwareInterface) {\n                $helper->setInput($input);\n            }\n        }\n\n        if ($this->signalsToDispatchEvent) {\n            $commandSignals = $command instanceof SignalableCommandInterface ? $command->getSubscribedSignals() : [];\n\n            if ($commandSignals || null !== $this->dispatcher) {\n                if (!$this->signalRegistry) {\n                    throw new RuntimeException('Unable to subscribe to signal events. Make sure that the `pcntl` extension is installed and that \"pcntl_*\" functions are not disabled by your php.ini\\'s \"disable_functions\" directive.');\n                }\n\n                if (Terminal::hasSttyAvailable()) {\n                    $sttyMode = shell_exec('stty -g');\n\n                    foreach ([\\SIGINT, \\SIGTERM] as $signal) {\n                        $this->signalRegistry->register($signal, static function () use ($sttyMode) {\n                            shell_exec('stty '.$sttyMode);\n                        });\n                    }\n                }\n            }\n\n            if (null !== $this->dispatcher) {\n                foreach ($this->signalsToDispatchEvent as $signal) {\n                    $event = new ConsoleSignalEvent($command, $input, $output, $signal);\n\n                    $this->signalRegistry->register($signal, function ($signal, $hasNext) use ($event) {\n                        $this->dispatcher->dispatch($event, ConsoleEvents::SIGNAL);\n\n                        // No more handlers, we try to simulate PHP default behavior\n                        if (!$hasNext) {\n                            if (!\\in_array($signal, [\\SIGUSR1, \\SIGUSR2], true)) {\n                                exit(0);\n                            }\n                        }\n                    });\n                }\n            }\n\n            foreach ($commandSignals as $signal) {\n                $this->signalRegistry->register($signal, [$command, 'handleSignal']);\n            }\n        }\n\n        if (null === $this->dispatcher) {\n            return $command->run($input, $output);\n        }\n\n        // bind before the console.command event, so the listeners have access to input options/arguments\n        try {\n            $command->mergeApplicationDefinition();\n            $input->bind($command->getDefinition());\n        } catch (ExceptionInterface $e) {\n            // ignore invalid options/arguments for now, to allow the event listeners to customize the InputDefinition\n        }\n\n        $event = new ConsoleCommandEvent($command, $input, $output);\n        $e = null;\n\n        try {\n            $this->dispatcher->dispatch($event, ConsoleEvents::COMMAND);\n\n            if ($event->commandShouldRun()) {\n                $exitCode = $command->run($input, $output);\n            } else {\n                $exitCode = ConsoleCommandEvent::RETURN_CODE_DISABLED;\n            }\n        } catch (\\Throwable $e) {\n            $event = new ConsoleErrorEvent($input, $output, $e, $command);\n            $this->dispatcher->dispatch($event, ConsoleEvents::ERROR);\n            $e = $event->getError();\n\n            if (0 === $exitCode = $event->getExitCode()) {\n                $e = null;\n            }\n        }\n\n        $event = new ConsoleTerminateEvent($command, $input, $output, $exitCode);\n        $this->dispatcher->dispatch($event, ConsoleEvents::TERMINATE);\n\n        if (null !== $e) {\n            throw $e;\n        }\n\n        return $event->getExitCode();\n    }\n\n    /**\n     * Gets the name of the command based on input.\n     *\n     * @return string|null\n     */\n    protected function getCommandName(InputInterface $input)\n    {\n        return $this->singleCommand ? $this->defaultCommand : $input->getFirstArgument();\n    }\n\n    /**\n     * Gets the default input definition.\n     *\n     * @return InputDefinition\n     */\n    protected function getDefaultInputDefinition()\n    {\n        return new InputDefinition([\n            new InputArgument('command', InputArgument::REQUIRED, 'The command to execute'),\n            new InputOption('--help', '-h', InputOption::VALUE_NONE, 'Display help for the given command. When no command is given display help for the <info>'.$this->defaultCommand.'</info> command'),\n            new InputOption('--quiet', '-q', InputOption::VALUE_NONE, 'Do not output any message'),\n            new InputOption('--verbose', '-v|vv|vvv', InputOption::VALUE_NONE, 'Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug'),\n            new InputOption('--version', '-V', InputOption::VALUE_NONE, 'Display this application version'),\n            new InputOption('--ansi', '', InputOption::VALUE_NEGATABLE, 'Force (or disable --no-ansi) ANSI output', null),\n            new InputOption('--no-interaction', '-n', InputOption::VALUE_NONE, 'Do not ask any interactive question'),\n        ]);\n    }\n\n    /**\n     * Gets the default commands that should always be available.\n     *\n     * @return Command[]\n     */\n    protected function getDefaultCommands()\n    {\n        return [new HelpCommand(), new ListCommand(), new CompleteCommand(), new DumpCompletionCommand()];\n    }\n\n    /**\n     * Gets the default helper set with the helpers that should always be available.\n     *\n     * @return HelperSet\n     */\n    protected function getDefaultHelperSet()\n    {\n        return new HelperSet([\n            new FormatterHelper(),\n            new DebugFormatterHelper(),\n            new ProcessHelper(),\n            new QuestionHelper(),\n        ]);\n    }\n\n    /**\n     * Returns abbreviated suggestions in string format.\n     */\n    private function getAbbreviationSuggestions(array $abbrevs): string\n    {\n        return '    '.implode(\"\\n    \", $abbrevs);\n    }\n\n    /**\n     * Returns the namespace part of the command name.\n     *\n     * This method is not part of public API and should not be used directly.\n     *\n     * @return string\n     */\n    public function extractNamespace(string $name, ?int $limit = null)\n    {\n        $parts = explode(':', $name, -1);\n\n        return implode(':', null === $limit ? $parts : \\array_slice($parts, 0, $limit));\n    }\n\n    /**\n     * Finds alternative of $name among $collection,\n     * if nothing is found in $collection, try in $abbrevs.\n     *\n     * @return string[]\n     */\n    private function findAlternatives(string $name, iterable $collection): array\n    {\n        $threshold = 1e3;\n        $alternatives = [];\n\n        $collectionParts = [];\n        foreach ($collection as $item) {\n            $collectionParts[$item] = explode(':', $item);\n        }\n\n        foreach (explode(':', $name) as $i => $subname) {\n            foreach ($collectionParts as $collectionName => $parts) {\n                $exists = isset($alternatives[$collectionName]);\n                if (!isset($parts[$i]) && $exists) {\n                    $alternatives[$collectionName] += $threshold;\n                    continue;\n                } elseif (!isset($parts[$i])) {\n                    continue;\n                }\n\n                $lev = levenshtein($subname, $parts[$i]);\n                if ($lev <= \\strlen($subname) / 3 || '' !== $subname && str_contains($parts[$i], $subname)) {\n                    $alternatives[$collectionName] = $exists ? $alternatives[$collectionName] + $lev : $lev;\n                } elseif ($exists) {\n                    $alternatives[$collectionName] += $threshold;\n                }\n            }\n        }\n\n        foreach ($collection as $item) {\n            $lev = levenshtein($name, $item);\n            if ($lev <= \\strlen($name) / 3 || str_contains($item, $name)) {\n                $alternatives[$item] = isset($alternatives[$item]) ? $alternatives[$item] - $lev : $lev;\n            }\n        }\n\n        $alternatives = array_filter($alternatives, function ($lev) use ($threshold) { return $lev < 2 * $threshold; });\n        ksort($alternatives, \\SORT_NATURAL | \\SORT_FLAG_CASE);\n\n        return array_keys($alternatives);\n    }\n\n    /**\n     * Sets the default Command name.\n     *\n     * @return $this\n     */\n    public function setDefaultCommand(string $commandName, bool $isSingleCommand = false)\n    {\n        $this->defaultCommand = explode('|', ltrim($commandName, '|'))[0];\n\n        if ($isSingleCommand) {\n            // Ensure the command exist\n            $this->find($commandName);\n\n            $this->singleCommand = true;\n        }\n\n        return $this;\n    }\n\n    /**\n     * @internal\n     */\n    public function isSingleCommand(): bool\n    {\n        return $this->singleCommand;\n    }\n\n    private function splitStringByWidth(string $string, int $width): array\n    {\n        // str_split is not suitable for multi-byte characters, we should use preg_split to get char array properly.\n        // additionally, array_slice() is not enough as some character has doubled width.\n        // we need a function to split string not by character count but by string width\n        if (false === $encoding = mb_detect_encoding($string, null, true)) {\n            return str_split($string, $width);\n        }\n\n        $utf8String = mb_convert_encoding($string, 'utf8', $encoding);\n        $lines = [];\n        $line = '';\n\n        $offset = 0;\n        while (preg_match('/.{1,10000}/u', $utf8String, $m, 0, $offset)) {\n            $offset += \\strlen($m[0]);\n\n            foreach (preg_split('//u', $m[0]) as $char) {\n                // test if $char could be appended to current line\n                if (mb_strwidth($line.$char, 'utf8') <= $width) {\n                    $line .= $char;\n                    continue;\n                }\n                // if not, push current line to array and make new line\n                $lines[] = str_pad($line, $width);\n                $line = $char;\n            }\n        }\n\n        $lines[] = \\count($lines) ? str_pad($line, $width) : $line;\n\n        mb_convert_variables($encoding, 'utf8', $lines);\n\n        return $lines;\n    }\n\n    /**\n     * Returns all namespaces of the command name.\n     *\n     * @return string[]\n     */\n    private function extractAllNamespaces(string $name): array\n    {\n        // -1 as third argument is needed to skip the command short name when exploding\n        $parts = explode(':', $name, -1);\n        $namespaces = [];\n\n        foreach ($parts as $part) {\n            if (\\count($namespaces)) {\n                $namespaces[] = end($namespaces).':'.$part;\n            } else {\n                $namespaces[] = $part;\n            }\n        }\n\n        return $namespaces;\n    }\n\n    private function init()\n    {\n        if ($this->initialized) {\n            return;\n        }\n        $this->initialized = true;\n\n        foreach ($this->getDefaultCommands() as $command) {\n            $this->add($command);\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Attribute/AsCommand.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Attribute;\n\n/**\n * Service tag to autoconfigure commands.\n */\n#[\\Attribute(\\Attribute::TARGET_CLASS)]\nclass AsCommand\n{\n    public function __construct(\n        public string $name,\n        public ?string $description = null,\n        array $aliases = [],\n        bool $hidden = false,\n    ) {\n        if (!$hidden && !$aliases) {\n            return;\n        }\n\n        $name = explode('|', $name);\n        $name = array_merge($name, $aliases);\n\n        if ($hidden && '' !== $name[0]) {\n            array_unshift($name, '');\n        }\n\n        $this->name = implode('|', $name);\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/CHANGELOG.md",
    "content": "CHANGELOG\n=========\n\n5.4\n---\n\n * Add `TesterTrait::assertCommandIsSuccessful()` to test command\n * Deprecate `HelperSet::setCommand()` and `getCommand()` without replacement\n\n5.3\n---\n\n * Add `GithubActionReporter` to render annotations in a Github Action\n * Add `InputOption::VALUE_NEGATABLE` flag to handle `--foo`/`--no-foo` options\n * Add the `Command::$defaultDescription` static property and the `description` attribute\n   on the `console.command` tag to allow the `list` command to instantiate commands lazily\n * Add option `--short` to the `list` command\n * Add support for bright colors\n * Add `#[AsCommand]` attribute for declaring commands on PHP 8\n * Add `Helper::width()` and `Helper::length()`\n * The `--ansi` and `--no-ansi` options now default to `null`.\n\n5.2.0\n-----\n\n * Added `SingleCommandApplication::setAutoExit()` to allow testing via `CommandTester`\n * added support for multiline responses to questions through `Question::setMultiline()`\n   and `Question::isMultiline()`\n * Added `SignalRegistry` class to stack signals handlers\n * Added support for signals:\n    * Added `Application::getSignalRegistry()` and `Application::setSignalsToDispatchEvent()` methods\n    * Added `SignalableCommandInterface` interface\n * Added `TableCellStyle` class to customize table cell\n * Removed `php ` prefix invocation from help messages.\n\n5.1.0\n-----\n\n * `Command::setHidden()` is final since Symfony 5.1\n * Add `SingleCommandApplication`\n * Add `Cursor` class\n\n5.0.0\n-----\n\n * removed support for finding hidden commands using an abbreviation, use the full name instead\n * removed `TableStyle::setCrossingChar()` method in favor of `TableStyle::setDefaultCrossingChar()`\n * removed `TableStyle::setHorizontalBorderChar()` method in favor of `TableStyle::setDefaultCrossingChars()`\n * removed `TableStyle::getHorizontalBorderChar()` method in favor of `TableStyle::getBorderChars()`\n * removed `TableStyle::setVerticalBorderChar()` method in favor of `TableStyle::setVerticalBorderChars()`\n * removed `TableStyle::getVerticalBorderChar()` method in favor of `TableStyle::getBorderChars()`\n * removed support for returning `null` from `Command::execute()`, return `0` instead\n * `ProcessHelper::run()` accepts only `array|Symfony\\Component\\Process\\Process` for its `command` argument\n * `Application::setDispatcher` accepts only `Symfony\\Contracts\\EventDispatcher\\EventDispatcherInterface`\n   for its `dispatcher` argument\n * renamed `Application::renderException()` and `Application::doRenderException()`\n   to `renderThrowable()` and `doRenderThrowable()` respectively.\n\n4.4.0\n-----\n\n * deprecated finding hidden commands using an abbreviation, use the full name instead\n * added `Question::setTrimmable` default to true to allow the answer to be trimmed\n * added method `minSecondsBetweenRedraws()` and `maxSecondsBetweenRedraws()` on `ProgressBar`\n * `Application` implements `ResetInterface`\n * marked all dispatched event classes as `@final`\n * added support for displaying table horizontally\n * deprecated returning `null` from `Command::execute()`, return `0` instead\n * Deprecated the `Application::renderException()` and `Application::doRenderException()` methods,\n   use `renderThrowable()` and `doRenderThrowable()` instead.\n * added support for the `NO_COLOR` env var (https://no-color.org/)\n\n4.3.0\n-----\n\n * added support for hyperlinks\n * added `ProgressBar::iterate()` method that simplify updating the progress bar when iterating\n * added `Question::setAutocompleterCallback()` to provide a callback function\n   that dynamically generates suggestions as the user types\n\n4.2.0\n-----\n\n * allowed passing commands as `[$process, 'ENV_VAR' => 'value']` to\n   `ProcessHelper::run()` to pass environment variables\n * deprecated passing a command as a string to `ProcessHelper::run()`,\n   pass it the command as an array of its arguments instead\n * made the `ProcessHelper` class final\n * added `WrappableOutputFormatterInterface::formatAndWrap()` (implemented in `OutputFormatter`)\n * added `capture_stderr_separately` option to `CommandTester::execute()`\n\n4.1.0\n-----\n\n * added option to run suggested command if command is not found and only 1 alternative is available\n * added option to modify console output and print multiple modifiable sections\n * added support for iterable messages in output `write` and `writeln` methods\n\n4.0.0\n-----\n\n * `OutputFormatter` throws an exception when unknown options are used\n * removed `QuestionHelper::setInputStream()/getInputStream()`\n * removed `Application::getTerminalWidth()/getTerminalHeight()` and\n   `Application::setTerminalDimensions()/getTerminalDimensions()`\n * removed `ConsoleExceptionEvent`\n * removed `ConsoleEvents::EXCEPTION`\n\n3.4.0\n-----\n\n * added `SHELL_VERBOSITY` env var to control verbosity\n * added `CommandLoaderInterface`, `FactoryCommandLoader` and PSR-11\n   `ContainerCommandLoader` for commands lazy-loading\n * added a case-insensitive command name matching fallback\n * added static `Command::$defaultName/getDefaultName()`, allowing for\n   commands to be registered at compile time in the application command loader.\n   Setting the `$defaultName` property avoids the need for filling the `command`\n   attribute on the `console.command` tag when using `AddConsoleCommandPass`.\n\n3.3.0\n-----\n\n * added `ExceptionListener`\n * added `AddConsoleCommandPass` (originally in FrameworkBundle)\n * [BC BREAK] `Input::getOption()` no longer returns the default value for options\n   with value optional explicitly passed empty\n * added console.error event to catch exceptions thrown by other listeners\n * deprecated console.exception event in favor of console.error\n * added ability to handle `CommandNotFoundException` through the\n   `console.error` event\n * deprecated default validation in `SymfonyQuestionHelper::ask`\n\n3.2.0\n------\n\n * added `setInputs()` method to CommandTester for ease testing of commands expecting inputs\n * added `setStream()` and `getStream()` methods to Input (implement StreamableInputInterface)\n * added StreamableInputInterface\n * added LockableTrait\n\n3.1.0\n-----\n\n * added truncate method to FormatterHelper\n * added setColumnWidth(s) method to Table\n\n2.8.3\n-----\n\n * remove readline support from the question helper as it caused issues\n\n2.8.0\n-----\n\n * use readline for user input in the question helper when available to allow\n   the use of arrow keys\n\n2.6.0\n-----\n\n * added a Process helper\n * added a DebugFormatter helper\n\n2.5.0\n-----\n\n * deprecated the dialog helper (use the question helper instead)\n * deprecated TableHelper in favor of Table\n * deprecated ProgressHelper in favor of ProgressBar\n * added ConsoleLogger\n * added a question helper\n * added a way to set the process name of a command\n * added a way to set a default command instead of `ListCommand`\n\n2.4.0\n-----\n\n * added a way to force terminal dimensions\n * added a convenient method to detect verbosity level\n * [BC BREAK] made descriptors use output instead of returning a string\n\n2.3.0\n-----\n\n * added multiselect support to the select dialog helper\n * added Table Helper for tabular data rendering\n * added support for events in `Application`\n * added a way to normalize EOLs in `ApplicationTester::getDisplay()` and `CommandTester::getDisplay()`\n * added a way to set the progress bar progress via the `setCurrent` method\n * added support for multiple InputOption shortcuts, written as `'-a|-b|-c'`\n * added two additional verbosity levels, VERBOSITY_VERY_VERBOSE and VERBOSITY_DEBUG\n\n2.2.0\n-----\n\n * added support for colorization on Windows via ConEmu\n * add a method to Dialog Helper to ask for a question and hide the response\n * added support for interactive selections in console (DialogHelper::select())\n * added support for autocompletion as you type in Dialog Helper\n\n2.1.0\n-----\n\n * added ConsoleOutputInterface\n * added the possibility to disable a command (Command::isEnabled())\n * added suggestions when a command does not exist\n * added a --raw option to the list command\n * added support for STDERR in the console output class (errors are now sent\n   to STDERR)\n * made the defaults (helper set, commands, input definition) in Application\n   more easily customizable\n * added support for the shell even if readline is not available\n * added support for process isolation in Symfony shell via\n   `--process-isolation` switch\n * added support for `--`, which disables options parsing after that point\n   (tokens will be parsed as arguments)\n"
  },
  {
    "path": "server/vendor/symfony/console/CI/GithubActionReporter.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\CI;\n\nuse Symfony\\Component\\Console\\Output\\OutputInterface;\n\n/**\n * Utility class for Github actions.\n *\n * @author Maxime Steinhausser <maxime.steinhausser@gmail.com>\n */\nclass GithubActionReporter\n{\n    private $output;\n\n    /**\n     * @see https://github.com/actions/toolkit/blob/5e5e1b7aacba68a53836a34db4a288c3c1c1585b/packages/core/src/command.ts#L80-L85\n     */\n    private const ESCAPED_DATA = [\n        '%' => '%25',\n        \"\\r\" => '%0D',\n        \"\\n\" => '%0A',\n    ];\n\n    /**\n     * @see https://github.com/actions/toolkit/blob/5e5e1b7aacba68a53836a34db4a288c3c1c1585b/packages/core/src/command.ts#L87-L94\n     */\n    private const ESCAPED_PROPERTIES = [\n        '%' => '%25',\n        \"\\r\" => '%0D',\n        \"\\n\" => '%0A',\n        ':' => '%3A',\n        ',' => '%2C',\n    ];\n\n    public function __construct(OutputInterface $output)\n    {\n        $this->output = $output;\n    }\n\n    public static function isGithubActionEnvironment(): bool\n    {\n        return false !== getenv('GITHUB_ACTIONS');\n    }\n\n    /**\n     * Output an error using the Github annotations format.\n     *\n     * @see https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-commands-for-github-actions#setting-an-error-message\n     */\n    public function error(string $message, ?string $file = null, ?int $line = null, ?int $col = null): void\n    {\n        $this->log('error', $message, $file, $line, $col);\n    }\n\n    /**\n     * Output a warning using the Github annotations format.\n     *\n     * @see https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-commands-for-github-actions#setting-a-warning-message\n     */\n    public function warning(string $message, ?string $file = null, ?int $line = null, ?int $col = null): void\n    {\n        $this->log('warning', $message, $file, $line, $col);\n    }\n\n    /**\n     * Output a debug log using the Github annotations format.\n     *\n     * @see https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-commands-for-github-actions#setting-a-debug-message\n     */\n    public function debug(string $message, ?string $file = null, ?int $line = null, ?int $col = null): void\n    {\n        $this->log('debug', $message, $file, $line, $col);\n    }\n\n    private function log(string $type, string $message, ?string $file = null, ?int $line = null, ?int $col = null): void\n    {\n        // Some values must be encoded.\n        $message = strtr($message, self::ESCAPED_DATA);\n\n        if (!$file) {\n            // No file provided, output the message solely:\n            $this->output->writeln(sprintf('::%s::%s', $type, $message));\n\n            return;\n        }\n\n        $this->output->writeln(sprintf('::%s file=%s,line=%s,col=%s::%s', $type, strtr($file, self::ESCAPED_PROPERTIES), strtr($line ?? 1, self::ESCAPED_PROPERTIES), strtr($col ?? 0, self::ESCAPED_PROPERTIES), $message));\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Color.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console;\n\nuse Symfony\\Component\\Console\\Exception\\InvalidArgumentException;\n\n/**\n * @author Fabien Potencier <fabien@symfony.com>\n */\nfinal class Color\n{\n    private const COLORS = [\n        'black' => 0,\n        'red' => 1,\n        'green' => 2,\n        'yellow' => 3,\n        'blue' => 4,\n        'magenta' => 5,\n        'cyan' => 6,\n        'white' => 7,\n        'default' => 9,\n    ];\n\n    private const BRIGHT_COLORS = [\n        'gray' => 0,\n        'bright-red' => 1,\n        'bright-green' => 2,\n        'bright-yellow' => 3,\n        'bright-blue' => 4,\n        'bright-magenta' => 5,\n        'bright-cyan' => 6,\n        'bright-white' => 7,\n    ];\n\n    private const AVAILABLE_OPTIONS = [\n        'bold' => ['set' => 1, 'unset' => 22],\n        'underscore' => ['set' => 4, 'unset' => 24],\n        'blink' => ['set' => 5, 'unset' => 25],\n        'reverse' => ['set' => 7, 'unset' => 27],\n        'conceal' => ['set' => 8, 'unset' => 28],\n    ];\n\n    private $foreground;\n    private $background;\n    private $options = [];\n\n    public function __construct(string $foreground = '', string $background = '', array $options = [])\n    {\n        $this->foreground = $this->parseColor($foreground);\n        $this->background = $this->parseColor($background, true);\n\n        foreach ($options as $option) {\n            if (!isset(self::AVAILABLE_OPTIONS[$option])) {\n                throw new InvalidArgumentException(sprintf('Invalid option specified: \"%s\". Expected one of (%s).', $option, implode(', ', array_keys(self::AVAILABLE_OPTIONS))));\n            }\n\n            $this->options[$option] = self::AVAILABLE_OPTIONS[$option];\n        }\n    }\n\n    public function apply(string $text): string\n    {\n        return $this->set().$text.$this->unset();\n    }\n\n    public function set(): string\n    {\n        $setCodes = [];\n        if ('' !== $this->foreground) {\n            $setCodes[] = $this->foreground;\n        }\n        if ('' !== $this->background) {\n            $setCodes[] = $this->background;\n        }\n        foreach ($this->options as $option) {\n            $setCodes[] = $option['set'];\n        }\n        if (0 === \\count($setCodes)) {\n            return '';\n        }\n\n        return sprintf(\"\\033[%sm\", implode(';', $setCodes));\n    }\n\n    public function unset(): string\n    {\n        $unsetCodes = [];\n        if ('' !== $this->foreground) {\n            $unsetCodes[] = 39;\n        }\n        if ('' !== $this->background) {\n            $unsetCodes[] = 49;\n        }\n        foreach ($this->options as $option) {\n            $unsetCodes[] = $option['unset'];\n        }\n        if (0 === \\count($unsetCodes)) {\n            return '';\n        }\n\n        return sprintf(\"\\033[%sm\", implode(';', $unsetCodes));\n    }\n\n    private function parseColor(string $color, bool $background = false): string\n    {\n        if ('' === $color) {\n            return '';\n        }\n\n        if ('#' === $color[0]) {\n            $color = substr($color, 1);\n\n            if (3 === \\strlen($color)) {\n                $color = $color[0].$color[0].$color[1].$color[1].$color[2].$color[2];\n            }\n\n            if (6 !== \\strlen($color)) {\n                throw new InvalidArgumentException(sprintf('Invalid \"%s\" color.', $color));\n            }\n\n            return ($background ? '4' : '3').$this->convertHexColorToAnsi(hexdec($color));\n        }\n\n        if (isset(self::COLORS[$color])) {\n            return ($background ? '4' : '3').self::COLORS[$color];\n        }\n\n        if (isset(self::BRIGHT_COLORS[$color])) {\n            return ($background ? '10' : '9').self::BRIGHT_COLORS[$color];\n        }\n\n        throw new InvalidArgumentException(sprintf('Invalid \"%s\" color; expected one of (%s).', $color, implode(', ', array_merge(array_keys(self::COLORS), array_keys(self::BRIGHT_COLORS)))));\n    }\n\n    private function convertHexColorToAnsi(int $color): string\n    {\n        $r = ($color >> 16) & 255;\n        $g = ($color >> 8) & 255;\n        $b = $color & 255;\n\n        // see https://github.com/termstandard/colors/ for more information about true color support\n        if ('truecolor' !== getenv('COLORTERM')) {\n            return (string) $this->degradeHexColorToAnsi($r, $g, $b);\n        }\n\n        return sprintf('8;2;%d;%d;%d', $r, $g, $b);\n    }\n\n    private function degradeHexColorToAnsi(int $r, int $g, int $b): int\n    {\n        if (0 === round($this->getSaturation($r, $g, $b) / 50)) {\n            return 0;\n        }\n\n        return (round($b / 255) << 2) | (round($g / 255) << 1) | round($r / 255);\n    }\n\n    private function getSaturation(int $r, int $g, int $b): int\n    {\n        $r = $r / 255;\n        $g = $g / 255;\n        $b = $b / 255;\n        $v = max($r, $g, $b);\n\n        if (0 === $diff = $v - min($r, $g, $b)) {\n            return 0;\n        }\n\n        return (int) $diff * 100 / $v;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Command/Command.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Command;\n\nuse Symfony\\Component\\Console\\Application;\nuse Symfony\\Component\\Console\\Attribute\\AsCommand;\nuse Symfony\\Component\\Console\\Completion\\CompletionInput;\nuse Symfony\\Component\\Console\\Completion\\CompletionSuggestions;\nuse Symfony\\Component\\Console\\Exception\\ExceptionInterface;\nuse Symfony\\Component\\Console\\Exception\\InvalidArgumentException;\nuse Symfony\\Component\\Console\\Exception\\LogicException;\nuse Symfony\\Component\\Console\\Helper\\HelperSet;\nuse Symfony\\Component\\Console\\Input\\InputArgument;\nuse Symfony\\Component\\Console\\Input\\InputDefinition;\nuse Symfony\\Component\\Console\\Input\\InputInterface;\nuse Symfony\\Component\\Console\\Input\\InputOption;\nuse Symfony\\Component\\Console\\Output\\OutputInterface;\n\n/**\n * Base class for all commands.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass Command\n{\n    // see https://tldp.org/LDP/abs/html/exitcodes.html\n    public const SUCCESS = 0;\n    public const FAILURE = 1;\n    public const INVALID = 2;\n\n    /**\n     * @var string|null The default command name\n     */\n    protected static $defaultName;\n\n    /**\n     * @var string|null The default command description\n     */\n    protected static $defaultDescription;\n\n    private $application;\n    private $name;\n    private $processTitle;\n    private $aliases = [];\n    private $definition;\n    private $hidden = false;\n    private $help = '';\n    private $description = '';\n    private $fullDefinition;\n    private $ignoreValidationErrors = false;\n    private $code;\n    private $synopsis = [];\n    private $usages = [];\n    private $helperSet;\n\n    /**\n     * @return string|null\n     */\n    public static function getDefaultName()\n    {\n        $class = static::class;\n\n        if (\\PHP_VERSION_ID >= 80000 && $attribute = (new \\ReflectionClass($class))->getAttributes(AsCommand::class)) {\n            return $attribute[0]->newInstance()->name;\n        }\n\n        $r = new \\ReflectionProperty($class, 'defaultName');\n\n        return $class === $r->class ? static::$defaultName : null;\n    }\n\n    public static function getDefaultDescription(): ?string\n    {\n        $class = static::class;\n\n        if (\\PHP_VERSION_ID >= 80000 && $attribute = (new \\ReflectionClass($class))->getAttributes(AsCommand::class)) {\n            return $attribute[0]->newInstance()->description;\n        }\n\n        $r = new \\ReflectionProperty($class, 'defaultDescription');\n\n        return $class === $r->class ? static::$defaultDescription : null;\n    }\n\n    /**\n     * @param string|null $name The name of the command; passing null means it must be set in configure()\n     *\n     * @throws LogicException When the command name is empty\n     */\n    public function __construct(?string $name = null)\n    {\n        $this->definition = new InputDefinition();\n\n        if (null === $name && null !== $name = static::getDefaultName()) {\n            $aliases = explode('|', $name);\n\n            if ('' === $name = array_shift($aliases)) {\n                $this->setHidden(true);\n                $name = array_shift($aliases);\n            }\n\n            $this->setAliases($aliases);\n        }\n\n        if (null !== $name) {\n            $this->setName($name);\n        }\n\n        if ('' === $this->description) {\n            $this->setDescription(static::getDefaultDescription() ?? '');\n        }\n\n        $this->configure();\n    }\n\n    /**\n     * Ignores validation errors.\n     *\n     * This is mainly useful for the help command.\n     */\n    public function ignoreValidationErrors()\n    {\n        $this->ignoreValidationErrors = true;\n    }\n\n    public function setApplication(?Application $application = null)\n    {\n        $this->application = $application;\n        if ($application) {\n            $this->setHelperSet($application->getHelperSet());\n        } else {\n            $this->helperSet = null;\n        }\n\n        $this->fullDefinition = null;\n    }\n\n    public function setHelperSet(HelperSet $helperSet)\n    {\n        $this->helperSet = $helperSet;\n    }\n\n    /**\n     * Gets the helper set.\n     *\n     * @return HelperSet|null\n     */\n    public function getHelperSet()\n    {\n        return $this->helperSet;\n    }\n\n    /**\n     * Gets the application instance for this command.\n     *\n     * @return Application|null\n     */\n    public function getApplication()\n    {\n        return $this->application;\n    }\n\n    /**\n     * Checks whether the command is enabled or not in the current environment.\n     *\n     * Override this to check for x or y and return false if the command cannot\n     * run properly under the current conditions.\n     *\n     * @return bool\n     */\n    public function isEnabled()\n    {\n        return true;\n    }\n\n    /**\n     * Configures the current command.\n     */\n    protected function configure()\n    {\n    }\n\n    /**\n     * Executes the current command.\n     *\n     * This method is not abstract because you can use this class\n     * as a concrete class. In this case, instead of defining the\n     * execute() method, you set the code to execute by passing\n     * a Closure to the setCode() method.\n     *\n     * @return int 0 if everything went fine, or an exit code\n     *\n     * @throws LogicException When this abstract method is not implemented\n     *\n     * @see setCode()\n     */\n    protected function execute(InputInterface $input, OutputInterface $output)\n    {\n        throw new LogicException('You must override the execute() method in the concrete command class.');\n    }\n\n    /**\n     * Interacts with the user.\n     *\n     * This method is executed before the InputDefinition is validated.\n     * This means that this is the only place where the command can\n     * interactively ask for values of missing required arguments.\n     */\n    protected function interact(InputInterface $input, OutputInterface $output)\n    {\n    }\n\n    /**\n     * Initializes the command after the input has been bound and before the input\n     * is validated.\n     *\n     * This is mainly useful when a lot of commands extends one main command\n     * where some things need to be initialized based on the input arguments and options.\n     *\n     * @see InputInterface::bind()\n     * @see InputInterface::validate()\n     */\n    protected function initialize(InputInterface $input, OutputInterface $output)\n    {\n    }\n\n    /**\n     * Runs the command.\n     *\n     * The code to execute is either defined directly with the\n     * setCode() method or by overriding the execute() method\n     * in a sub-class.\n     *\n     * @return int The command exit code\n     *\n     * @throws ExceptionInterface When input binding fails. Bypass this by calling {@link ignoreValidationErrors()}.\n     *\n     * @see setCode()\n     * @see execute()\n     */\n    public function run(InputInterface $input, OutputInterface $output)\n    {\n        // add the application arguments and options\n        $this->mergeApplicationDefinition();\n\n        // bind the input against the command specific arguments/options\n        try {\n            $input->bind($this->getDefinition());\n        } catch (ExceptionInterface $e) {\n            if (!$this->ignoreValidationErrors) {\n                throw $e;\n            }\n        }\n\n        $this->initialize($input, $output);\n\n        if (null !== $this->processTitle) {\n            if (\\function_exists('cli_set_process_title')) {\n                if (!@cli_set_process_title($this->processTitle)) {\n                    if ('Darwin' === \\PHP_OS) {\n                        $output->writeln('<comment>Running \"cli_set_process_title\" as an unprivileged user is not supported on MacOS.</comment>', OutputInterface::VERBOSITY_VERY_VERBOSE);\n                    } else {\n                        cli_set_process_title($this->processTitle);\n                    }\n                }\n            } elseif (\\function_exists('setproctitle')) {\n                setproctitle($this->processTitle);\n            } elseif (OutputInterface::VERBOSITY_VERY_VERBOSE === $output->getVerbosity()) {\n                $output->writeln('<comment>Install the proctitle PECL to be able to change the process title.</comment>');\n            }\n        }\n\n        if ($input->isInteractive()) {\n            $this->interact($input, $output);\n        }\n\n        // The command name argument is often omitted when a command is executed directly with its run() method.\n        // It would fail the validation if we didn't make sure the command argument is present,\n        // since it's required by the application.\n        if ($input->hasArgument('command') && null === $input->getArgument('command')) {\n            $input->setArgument('command', $this->getName());\n        }\n\n        $input->validate();\n\n        if ($this->code) {\n            $statusCode = ($this->code)($input, $output);\n        } else {\n            $statusCode = $this->execute($input, $output);\n\n            if (!\\is_int($statusCode)) {\n                throw new \\TypeError(sprintf('Return value of \"%s::execute()\" must be of the type int, \"%s\" returned.', static::class, get_debug_type($statusCode)));\n            }\n        }\n\n        return is_numeric($statusCode) ? (int) $statusCode : 0;\n    }\n\n    /**\n     * Adds suggestions to $suggestions for the current completion input (e.g. option or argument).\n     */\n    public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void\n    {\n    }\n\n    /**\n     * Sets the code to execute when running this command.\n     *\n     * If this method is used, it overrides the code defined\n     * in the execute() method.\n     *\n     * @param callable $code A callable(InputInterface $input, OutputInterface $output)\n     *\n     * @return $this\n     *\n     * @throws InvalidArgumentException\n     *\n     * @see execute()\n     */\n    public function setCode(callable $code)\n    {\n        if ($code instanceof \\Closure) {\n            $r = new \\ReflectionFunction($code);\n            if (null === $r->getClosureThis()) {\n                set_error_handler(static function () {});\n                try {\n                    if ($c = \\Closure::bind($code, $this)) {\n                        $code = $c;\n                    }\n                } finally {\n                    restore_error_handler();\n                }\n            }\n        }\n\n        $this->code = $code;\n\n        return $this;\n    }\n\n    /**\n     * Merges the application definition with the command definition.\n     *\n     * This method is not part of public API and should not be used directly.\n     *\n     * @param bool $mergeArgs Whether to merge or not the Application definition arguments to Command definition arguments\n     *\n     * @internal\n     */\n    public function mergeApplicationDefinition(bool $mergeArgs = true)\n    {\n        if (null === $this->application) {\n            return;\n        }\n\n        $this->fullDefinition = new InputDefinition();\n        $this->fullDefinition->setOptions($this->definition->getOptions());\n        $this->fullDefinition->addOptions($this->application->getDefinition()->getOptions());\n\n        if ($mergeArgs) {\n            $this->fullDefinition->setArguments($this->application->getDefinition()->getArguments());\n            $this->fullDefinition->addArguments($this->definition->getArguments());\n        } else {\n            $this->fullDefinition->setArguments($this->definition->getArguments());\n        }\n    }\n\n    /**\n     * Sets an array of argument and option instances.\n     *\n     * @param array|InputDefinition $definition An array of argument and option instances or a definition instance\n     *\n     * @return $this\n     */\n    public function setDefinition($definition)\n    {\n        if ($definition instanceof InputDefinition) {\n            $this->definition = $definition;\n        } else {\n            $this->definition->setDefinition($definition);\n        }\n\n        $this->fullDefinition = null;\n\n        return $this;\n    }\n\n    /**\n     * Gets the InputDefinition attached to this Command.\n     *\n     * @return InputDefinition\n     */\n    public function getDefinition()\n    {\n        return $this->fullDefinition ?? $this->getNativeDefinition();\n    }\n\n    /**\n     * Gets the InputDefinition to be used to create representations of this Command.\n     *\n     * Can be overridden to provide the original command representation when it would otherwise\n     * be changed by merging with the application InputDefinition.\n     *\n     * This method is not part of public API and should not be used directly.\n     *\n     * @return InputDefinition\n     */\n    public function getNativeDefinition()\n    {\n        if (null === $this->definition) {\n            throw new LogicException(sprintf('Command class \"%s\" is not correctly initialized. You probably forgot to call the parent constructor.', static::class));\n        }\n\n        return $this->definition;\n    }\n\n    /**\n     * Adds an argument.\n     *\n     * @param int|null $mode    The argument mode: InputArgument::REQUIRED or InputArgument::OPTIONAL\n     * @param mixed    $default The default value (for InputArgument::OPTIONAL mode only)\n     *\n     * @return $this\n     *\n     * @throws InvalidArgumentException When argument mode is not valid\n     */\n    public function addArgument(string $name, ?int $mode = null, string $description = '', $default = null)\n    {\n        $this->definition->addArgument(new InputArgument($name, $mode, $description, $default));\n        if (null !== $this->fullDefinition) {\n            $this->fullDefinition->addArgument(new InputArgument($name, $mode, $description, $default));\n        }\n\n        return $this;\n    }\n\n    /**\n     * Adds an option.\n     *\n     * @param string|array|null $shortcut The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts\n     * @param int|null          $mode     The option mode: One of the InputOption::VALUE_* constants\n     * @param mixed             $default  The default value (must be null for InputOption::VALUE_NONE)\n     *\n     * @return $this\n     *\n     * @throws InvalidArgumentException If option mode is invalid or incompatible\n     */\n    public function addOption(string $name, $shortcut = null, ?int $mode = null, string $description = '', $default = null)\n    {\n        $this->definition->addOption(new InputOption($name, $shortcut, $mode, $description, $default));\n        if (null !== $this->fullDefinition) {\n            $this->fullDefinition->addOption(new InputOption($name, $shortcut, $mode, $description, $default));\n        }\n\n        return $this;\n    }\n\n    /**\n     * Sets the name of the command.\n     *\n     * This method can set both the namespace and the name if\n     * you separate them by a colon (:)\n     *\n     *     $command->setName('foo:bar');\n     *\n     * @return $this\n     *\n     * @throws InvalidArgumentException When the name is invalid\n     */\n    public function setName(string $name)\n    {\n        $this->validateName($name);\n\n        $this->name = $name;\n\n        return $this;\n    }\n\n    /**\n     * Sets the process title of the command.\n     *\n     * This feature should be used only when creating a long process command,\n     * like a daemon.\n     *\n     * @return $this\n     */\n    public function setProcessTitle(string $title)\n    {\n        $this->processTitle = $title;\n\n        return $this;\n    }\n\n    /**\n     * Returns the command name.\n     *\n     * @return string|null\n     */\n    public function getName()\n    {\n        return $this->name;\n    }\n\n    /**\n     * @param bool $hidden Whether or not the command should be hidden from the list of commands\n     *                     The default value will be true in Symfony 6.0\n     *\n     * @return $this\n     *\n     * @final since Symfony 5.1\n     */\n    public function setHidden(bool $hidden /* = true */)\n    {\n        $this->hidden = $hidden;\n\n        return $this;\n    }\n\n    /**\n     * @return bool whether the command should be publicly shown or not\n     */\n    public function isHidden()\n    {\n        return $this->hidden;\n    }\n\n    /**\n     * Sets the description for the command.\n     *\n     * @return $this\n     */\n    public function setDescription(string $description)\n    {\n        $this->description = $description;\n\n        return $this;\n    }\n\n    /**\n     * Returns the description for the command.\n     *\n     * @return string\n     */\n    public function getDescription()\n    {\n        return $this->description;\n    }\n\n    /**\n     * Sets the help for the command.\n     *\n     * @return $this\n     */\n    public function setHelp(string $help)\n    {\n        $this->help = $help;\n\n        return $this;\n    }\n\n    /**\n     * Returns the help for the command.\n     *\n     * @return string\n     */\n    public function getHelp()\n    {\n        return $this->help;\n    }\n\n    /**\n     * Returns the processed help for the command replacing the %command.name% and\n     * %command.full_name% patterns with the real values dynamically.\n     *\n     * @return string\n     */\n    public function getProcessedHelp()\n    {\n        $name = $this->name;\n        $isSingleCommand = $this->application && $this->application->isSingleCommand();\n\n        $placeholders = [\n            '%command.name%',\n            '%command.full_name%',\n        ];\n        $replacements = [\n            $name,\n            $isSingleCommand ? $_SERVER['PHP_SELF'] : $_SERVER['PHP_SELF'].' '.$name,\n        ];\n\n        return str_replace($placeholders, $replacements, $this->getHelp() ?: $this->getDescription());\n    }\n\n    /**\n     * Sets the aliases for the command.\n     *\n     * @param string[] $aliases An array of aliases for the command\n     *\n     * @return $this\n     *\n     * @throws InvalidArgumentException When an alias is invalid\n     */\n    public function setAliases(iterable $aliases)\n    {\n        $list = [];\n\n        foreach ($aliases as $alias) {\n            $this->validateName($alias);\n            $list[] = $alias;\n        }\n\n        $this->aliases = \\is_array($aliases) ? $aliases : $list;\n\n        return $this;\n    }\n\n    /**\n     * Returns the aliases for the command.\n     *\n     * @return array\n     */\n    public function getAliases()\n    {\n        return $this->aliases;\n    }\n\n    /**\n     * Returns the synopsis for the command.\n     *\n     * @param bool $short Whether to show the short version of the synopsis (with options folded) or not\n     *\n     * @return string\n     */\n    public function getSynopsis(bool $short = false)\n    {\n        $key = $short ? 'short' : 'long';\n\n        if (!isset($this->synopsis[$key])) {\n            $this->synopsis[$key] = trim(sprintf('%s %s', $this->name, $this->definition->getSynopsis($short)));\n        }\n\n        return $this->synopsis[$key];\n    }\n\n    /**\n     * Add a command usage example, it'll be prefixed with the command name.\n     *\n     * @return $this\n     */\n    public function addUsage(string $usage)\n    {\n        if (!str_starts_with($usage, $this->name)) {\n            $usage = sprintf('%s %s', $this->name, $usage);\n        }\n\n        $this->usages[] = $usage;\n\n        return $this;\n    }\n\n    /**\n     * Returns alternative usages of the command.\n     *\n     * @return array\n     */\n    public function getUsages()\n    {\n        return $this->usages;\n    }\n\n    /**\n     * Gets a helper instance by name.\n     *\n     * @return mixed\n     *\n     * @throws LogicException           if no HelperSet is defined\n     * @throws InvalidArgumentException if the helper is not defined\n     */\n    public function getHelper(string $name)\n    {\n        if (null === $this->helperSet) {\n            throw new LogicException(sprintf('Cannot retrieve helper \"%s\" because there is no HelperSet defined. Did you forget to add your command to the application or to set the application on the command using the setApplication() method? You can also set the HelperSet directly using the setHelperSet() method.', $name));\n        }\n\n        return $this->helperSet->get($name);\n    }\n\n    /**\n     * Validates a command name.\n     *\n     * It must be non-empty and parts can optionally be separated by \":\".\n     *\n     * @throws InvalidArgumentException When the name is invalid\n     */\n    private function validateName(string $name)\n    {\n        if (!preg_match('/^[^\\:]++(\\:[^\\:]++)*$/', $name)) {\n            throw new InvalidArgumentException(sprintf('Command name \"%s\" is invalid.', $name));\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Command/CompleteCommand.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Command;\n\nuse Symfony\\Component\\Console\\Completion\\CompletionInput;\nuse Symfony\\Component\\Console\\Completion\\CompletionSuggestions;\nuse Symfony\\Component\\Console\\Completion\\Output\\BashCompletionOutput;\nuse Symfony\\Component\\Console\\Completion\\Output\\CompletionOutputInterface;\nuse Symfony\\Component\\Console\\Exception\\CommandNotFoundException;\nuse Symfony\\Component\\Console\\Exception\\ExceptionInterface;\nuse Symfony\\Component\\Console\\Input\\InputInterface;\nuse Symfony\\Component\\Console\\Input\\InputOption;\nuse Symfony\\Component\\Console\\Output\\OutputInterface;\n\n/**\n * Responsible for providing the values to the shell completion.\n *\n * @author Wouter de Jong <wouter@wouterj.nl>\n */\nfinal class CompleteCommand extends Command\n{\n    protected static $defaultName = '|_complete';\n    protected static $defaultDescription = 'Internal command to provide shell completion suggestions';\n\n    private $completionOutputs;\n\n    private $isDebug = false;\n\n    /**\n     * @param array<string, class-string<CompletionOutputInterface>> $completionOutputs A list of additional completion outputs, with shell name as key and FQCN as value\n     */\n    public function __construct(array $completionOutputs = [])\n    {\n        // must be set before the parent constructor, as the property value is used in configure()\n        $this->completionOutputs = $completionOutputs + ['bash' => BashCompletionOutput::class];\n\n        parent::__construct();\n    }\n\n    protected function configure(): void\n    {\n        $this\n            ->addOption('shell', 's', InputOption::VALUE_REQUIRED, 'The shell type (\"'.implode('\", \"', array_keys($this->completionOutputs)).'\")')\n            ->addOption('input', 'i', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'An array of input tokens (e.g. COMP_WORDS or argv)')\n            ->addOption('current', 'c', InputOption::VALUE_REQUIRED, 'The index of the \"input\" array that the cursor is in (e.g. COMP_CWORD)')\n            ->addOption('symfony', 'S', InputOption::VALUE_REQUIRED, 'The version of the completion script')\n        ;\n    }\n\n    protected function initialize(InputInterface $input, OutputInterface $output)\n    {\n        $this->isDebug = filter_var(getenv('SYMFONY_COMPLETION_DEBUG'), \\FILTER_VALIDATE_BOOLEAN);\n    }\n\n    protected function execute(InputInterface $input, OutputInterface $output): int\n    {\n        try {\n            // uncomment when a bugfix or BC break has been introduced in the shell completion scripts\n            // $version = $input->getOption('symfony');\n            // if ($version && version_compare($version, 'x.y', '>=')) {\n            //    $message = sprintf('Completion script version is not supported (\"%s\" given, \">=x.y\" required).', $version);\n            //    $this->log($message);\n\n            //    $output->writeln($message.' Install the Symfony completion script again by using the \"completion\" command.');\n\n            //    return 126;\n            // }\n\n            $shell = $input->getOption('shell');\n            if (!$shell) {\n                throw new \\RuntimeException('The \"--shell\" option must be set.');\n            }\n\n            if (!$completionOutput = $this->completionOutputs[$shell] ?? false) {\n                throw new \\RuntimeException(sprintf('Shell completion is not supported for your shell: \"%s\" (supported: \"%s\").', $shell, implode('\", \"', array_keys($this->completionOutputs))));\n            }\n\n            $completionInput = $this->createCompletionInput($input);\n            $suggestions = new CompletionSuggestions();\n\n            $this->log([\n                '',\n                '<comment>'.date('Y-m-d H:i:s').'</>',\n                '<info>Input:</> <comment>(\"|\" indicates the cursor position)</>',\n                '  '.(string) $completionInput,\n                '<info>Command:</>',\n                '  '.(string) implode(' ', $_SERVER['argv']),\n                '<info>Messages:</>',\n            ]);\n\n            $command = $this->findCommand($completionInput, $output);\n            if (null === $command) {\n                $this->log('  No command found, completing using the Application class.');\n\n                $this->getApplication()->complete($completionInput, $suggestions);\n            } elseif (\n                $completionInput->mustSuggestArgumentValuesFor('command')\n                && $command->getName() !== $completionInput->getCompletionValue()\n                && !\\in_array($completionInput->getCompletionValue(), $command->getAliases(), true)\n            ) {\n                $this->log('  No command found, completing using the Application class.');\n\n                // expand shortcut names (\"cache:cl<TAB>\") into their full name (\"cache:clear\")\n                $suggestions->suggestValues(array_filter(array_merge([$command->getName()], $command->getAliases())));\n            } else {\n                $command->mergeApplicationDefinition();\n                $completionInput->bind($command->getDefinition());\n\n                if (CompletionInput::TYPE_OPTION_NAME === $completionInput->getCompletionType()) {\n                    $this->log('  Completing option names for the <comment>'.\\get_class($command instanceof LazyCommand ? $command->getCommand() : $command).'</> command.');\n\n                    $suggestions->suggestOptions($command->getDefinition()->getOptions());\n                } else {\n                    $this->log([\n                        '  Completing using the <comment>'.\\get_class($command instanceof LazyCommand ? $command->getCommand() : $command).'</> class.',\n                        '  Completing <comment>'.$completionInput->getCompletionType().'</> for <comment>'.$completionInput->getCompletionName().'</>',\n                    ]);\n                    if (null !== $compval = $completionInput->getCompletionValue()) {\n                        $this->log('  Current value: <comment>'.$compval.'</>');\n                    }\n\n                    $command->complete($completionInput, $suggestions);\n                }\n            }\n\n            /** @var CompletionOutputInterface $completionOutput */\n            $completionOutput = new $completionOutput();\n\n            $this->log('<info>Suggestions:</>');\n            if ($options = $suggestions->getOptionSuggestions()) {\n                $this->log('  --'.implode(' --', array_map(function ($o) { return $o->getName(); }, $options)));\n            } elseif ($values = $suggestions->getValueSuggestions()) {\n                $this->log('  '.implode(' ', $values));\n            } else {\n                $this->log('  <comment>No suggestions were provided</>');\n            }\n\n            $completionOutput->write($suggestions, $output);\n        } catch (\\Throwable $e) {\n            $this->log([\n                '<error>Error!</error>',\n                (string) $e,\n            ]);\n\n            if ($output->isDebug()) {\n                throw $e;\n            }\n\n            return 2;\n        }\n\n        return 0;\n    }\n\n    private function createCompletionInput(InputInterface $input): CompletionInput\n    {\n        $currentIndex = $input->getOption('current');\n        if (!$currentIndex || !ctype_digit($currentIndex)) {\n            throw new \\RuntimeException('The \"--current\" option must be set and it must be an integer.');\n        }\n\n        $completionInput = CompletionInput::fromTokens($input->getOption('input'), (int) $currentIndex);\n\n        try {\n            $completionInput->bind($this->getApplication()->getDefinition());\n        } catch (ExceptionInterface $e) {\n        }\n\n        return $completionInput;\n    }\n\n    private function findCommand(CompletionInput $completionInput, OutputInterface $output): ?Command\n    {\n        try {\n            $inputName = $completionInput->getFirstArgument();\n            if (null === $inputName) {\n                return null;\n            }\n\n            return $this->getApplication()->find($inputName);\n        } catch (CommandNotFoundException $e) {\n        }\n\n        return null;\n    }\n\n    private function log($messages): void\n    {\n        if (!$this->isDebug) {\n            return;\n        }\n\n        $commandName = basename($_SERVER['argv'][0]);\n        file_put_contents(sys_get_temp_dir().'/sf_'.$commandName.'.log', implode(\\PHP_EOL, (array) $messages).\\PHP_EOL, \\FILE_APPEND);\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Command/DumpCompletionCommand.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Command;\n\nuse Symfony\\Component\\Console\\Completion\\CompletionInput;\nuse Symfony\\Component\\Console\\Completion\\CompletionSuggestions;\nuse Symfony\\Component\\Console\\Input\\InputArgument;\nuse Symfony\\Component\\Console\\Input\\InputInterface;\nuse Symfony\\Component\\Console\\Input\\InputOption;\nuse Symfony\\Component\\Console\\Output\\ConsoleOutputInterface;\nuse Symfony\\Component\\Console\\Output\\OutputInterface;\nuse Symfony\\Component\\Process\\Process;\n\n/**\n * Dumps the completion script for the current shell.\n *\n * @author Wouter de Jong <wouter@wouterj.nl>\n */\nfinal class DumpCompletionCommand extends Command\n{\n    protected static $defaultName = 'completion';\n    protected static $defaultDescription = 'Dump the shell completion script';\n\n    public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void\n    {\n        if ($input->mustSuggestArgumentValuesFor('shell')) {\n            $suggestions->suggestValues($this->getSupportedShells());\n        }\n    }\n\n    protected function configure()\n    {\n        $fullCommand = $_SERVER['PHP_SELF'];\n        $commandName = basename($fullCommand);\n        $fullCommand = @realpath($fullCommand) ?: $fullCommand;\n\n        $this\n            ->setHelp(<<<EOH\nThe <info>%command.name%</> command dumps the shell completion script required\nto use shell autocompletion (currently only bash completion is supported).\n\n<comment>Static installation\n-------------------</>\n\nDump the script to a global completion file and restart your shell:\n\n    <info>%command.full_name% bash | sudo tee /etc/bash_completion.d/{$commandName}</>\n\nOr dump the script to a local file and source it:\n\n    <info>%command.full_name% bash > completion.sh</>\n\n    <comment># source the file whenever you use the project</>\n    <info>source completion.sh</>\n\n    <comment># or add this line at the end of your \"~/.bashrc\" file:</>\n    <info>source /path/to/completion.sh</>\n\n<comment>Dynamic installation\n--------------------</>\n\nAdd this to the end of your shell configuration file (e.g. <info>\"~/.bashrc\"</>):\n\n    <info>eval \"$({$fullCommand} completion bash)\"</>\nEOH\n            )\n            ->addArgument('shell', InputArgument::OPTIONAL, 'The shell type (e.g. \"bash\"), the value of the \"$SHELL\" env var will be used if this is not given')\n            ->addOption('debug', null, InputOption::VALUE_NONE, 'Tail the completion debug log')\n        ;\n    }\n\n    protected function execute(InputInterface $input, OutputInterface $output): int\n    {\n        $commandName = basename($_SERVER['argv'][0]);\n\n        if ($input->getOption('debug')) {\n            $this->tailDebugLog($commandName, $output);\n\n            return 0;\n        }\n\n        $shell = $input->getArgument('shell') ?? self::guessShell();\n        $completionFile = __DIR__.'/../Resources/completion.'.$shell;\n        if (!file_exists($completionFile)) {\n            $supportedShells = $this->getSupportedShells();\n\n            if ($output instanceof ConsoleOutputInterface) {\n                $output = $output->getErrorOutput();\n            }\n            if ($shell) {\n                $output->writeln(sprintf('<error>Detected shell \"%s\", which is not supported by Symfony shell completion (supported shells: \"%s\").</>', $shell, implode('\", \"', $supportedShells)));\n            } else {\n                $output->writeln(sprintf('<error>Shell not detected, Symfony shell completion only supports \"%s\").</>', implode('\", \"', $supportedShells)));\n            }\n\n            return 2;\n        }\n\n        $output->write(str_replace(['{{ COMMAND_NAME }}', '{{ VERSION }}'], [$commandName, $this->getApplication()->getVersion()], file_get_contents($completionFile)));\n\n        return 0;\n    }\n\n    private static function guessShell(): string\n    {\n        return basename($_SERVER['SHELL'] ?? '');\n    }\n\n    private function tailDebugLog(string $commandName, OutputInterface $output): void\n    {\n        $debugFile = sys_get_temp_dir().'/sf_'.$commandName.'.log';\n        if (!file_exists($debugFile)) {\n            touch($debugFile);\n        }\n        $process = new Process(['tail', '-f', $debugFile], null, null, null, 0);\n        $process->run(function (string $type, string $line) use ($output): void {\n            $output->write($line);\n        });\n    }\n\n    /**\n     * @return string[]\n     */\n    private function getSupportedShells(): array\n    {\n        $shells = [];\n\n        foreach (new \\DirectoryIterator(__DIR__.'/../Resources/') as $file) {\n            if (str_starts_with($file->getBasename(), 'completion.') && $file->isFile()) {\n                $shells[] = $file->getExtension();\n            }\n        }\n\n        return $shells;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Command/HelpCommand.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Command;\n\nuse Symfony\\Component\\Console\\Completion\\CompletionInput;\nuse Symfony\\Component\\Console\\Completion\\CompletionSuggestions;\nuse Symfony\\Component\\Console\\Descriptor\\ApplicationDescription;\nuse Symfony\\Component\\Console\\Helper\\DescriptorHelper;\nuse Symfony\\Component\\Console\\Input\\InputArgument;\nuse Symfony\\Component\\Console\\Input\\InputInterface;\nuse Symfony\\Component\\Console\\Input\\InputOption;\nuse Symfony\\Component\\Console\\Output\\OutputInterface;\n\n/**\n * HelpCommand displays the help for a given command.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass HelpCommand extends Command\n{\n    private $command;\n\n    /**\n     * {@inheritdoc}\n     */\n    protected function configure()\n    {\n        $this->ignoreValidationErrors();\n\n        $this\n            ->setName('help')\n            ->setDefinition([\n                new InputArgument('command_name', InputArgument::OPTIONAL, 'The command name', 'help'),\n                new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt'),\n                new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command help'),\n            ])\n            ->setDescription('Display help for a command')\n            ->setHelp(<<<'EOF'\nThe <info>%command.name%</info> command displays help for a given command:\n\n  <info>%command.full_name% list</info>\n\nYou can also output the help in other formats by using the <comment>--format</comment> option:\n\n  <info>%command.full_name% --format=xml list</info>\n\nTo display the list of available commands, please use the <info>list</info> command.\nEOF\n            )\n        ;\n    }\n\n    public function setCommand(Command $command)\n    {\n        $this->command = $command;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    protected function execute(InputInterface $input, OutputInterface $output)\n    {\n        if (null === $this->command) {\n            $this->command = $this->getApplication()->find($input->getArgument('command_name'));\n        }\n\n        $helper = new DescriptorHelper();\n        $helper->describe($output, $this->command, [\n            'format' => $input->getOption('format'),\n            'raw_text' => $input->getOption('raw'),\n        ]);\n\n        $this->command = null;\n\n        return 0;\n    }\n\n    public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void\n    {\n        if ($input->mustSuggestArgumentValuesFor('command_name')) {\n            $descriptor = new ApplicationDescription($this->getApplication());\n            $suggestions->suggestValues(array_keys($descriptor->getCommands()));\n\n            return;\n        }\n\n        if ($input->mustSuggestOptionValuesFor('format')) {\n            $helper = new DescriptorHelper();\n            $suggestions->suggestValues($helper->getFormats());\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Command/LazyCommand.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Command;\n\nuse Symfony\\Component\\Console\\Application;\nuse Symfony\\Component\\Console\\Completion\\CompletionInput;\nuse Symfony\\Component\\Console\\Completion\\CompletionSuggestions;\nuse Symfony\\Component\\Console\\Helper\\HelperSet;\nuse Symfony\\Component\\Console\\Input\\InputDefinition;\nuse Symfony\\Component\\Console\\Input\\InputInterface;\nuse Symfony\\Component\\Console\\Output\\OutputInterface;\n\n/**\n * @author Nicolas Grekas <p@tchwork.com>\n */\nfinal class LazyCommand extends Command\n{\n    private $command;\n    private $isEnabled;\n\n    public function __construct(string $name, array $aliases, string $description, bool $isHidden, \\Closure $commandFactory, ?bool $isEnabled = true)\n    {\n        $this->setName($name)\n            ->setAliases($aliases)\n            ->setHidden($isHidden)\n            ->setDescription($description);\n\n        $this->command = $commandFactory;\n        $this->isEnabled = $isEnabled;\n    }\n\n    public function ignoreValidationErrors(): void\n    {\n        $this->getCommand()->ignoreValidationErrors();\n    }\n\n    public function setApplication(?Application $application = null): void\n    {\n        if ($this->command instanceof parent) {\n            $this->command->setApplication($application);\n        }\n\n        parent::setApplication($application);\n    }\n\n    public function setHelperSet(HelperSet $helperSet): void\n    {\n        if ($this->command instanceof parent) {\n            $this->command->setHelperSet($helperSet);\n        }\n\n        parent::setHelperSet($helperSet);\n    }\n\n    public function isEnabled(): bool\n    {\n        return $this->isEnabled ?? $this->getCommand()->isEnabled();\n    }\n\n    public function run(InputInterface $input, OutputInterface $output): int\n    {\n        return $this->getCommand()->run($input, $output);\n    }\n\n    public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void\n    {\n        $this->getCommand()->complete($input, $suggestions);\n    }\n\n    /**\n     * @return $this\n     */\n    public function setCode(callable $code): self\n    {\n        $this->getCommand()->setCode($code);\n\n        return $this;\n    }\n\n    /**\n     * @internal\n     */\n    public function mergeApplicationDefinition(bool $mergeArgs = true): void\n    {\n        $this->getCommand()->mergeApplicationDefinition($mergeArgs);\n    }\n\n    /**\n     * @return $this\n     */\n    public function setDefinition($definition): self\n    {\n        $this->getCommand()->setDefinition($definition);\n\n        return $this;\n    }\n\n    public function getDefinition(): InputDefinition\n    {\n        return $this->getCommand()->getDefinition();\n    }\n\n    public function getNativeDefinition(): InputDefinition\n    {\n        return $this->getCommand()->getNativeDefinition();\n    }\n\n    /**\n     * @return $this\n     */\n    public function addArgument(string $name, ?int $mode = null, string $description = '', $default = null): self\n    {\n        $this->getCommand()->addArgument($name, $mode, $description, $default);\n\n        return $this;\n    }\n\n    /**\n     * @return $this\n     */\n    public function addOption(string $name, $shortcut = null, ?int $mode = null, string $description = '', $default = null): self\n    {\n        $this->getCommand()->addOption($name, $shortcut, $mode, $description, $default);\n\n        return $this;\n    }\n\n    /**\n     * @return $this\n     */\n    public function setProcessTitle(string $title): self\n    {\n        $this->getCommand()->setProcessTitle($title);\n\n        return $this;\n    }\n\n    /**\n     * @return $this\n     */\n    public function setHelp(string $help): self\n    {\n        $this->getCommand()->setHelp($help);\n\n        return $this;\n    }\n\n    public function getHelp(): string\n    {\n        return $this->getCommand()->getHelp();\n    }\n\n    public function getProcessedHelp(): string\n    {\n        return $this->getCommand()->getProcessedHelp();\n    }\n\n    public function getSynopsis(bool $short = false): string\n    {\n        return $this->getCommand()->getSynopsis($short);\n    }\n\n    /**\n     * @return $this\n     */\n    public function addUsage(string $usage): self\n    {\n        $this->getCommand()->addUsage($usage);\n\n        return $this;\n    }\n\n    public function getUsages(): array\n    {\n        return $this->getCommand()->getUsages();\n    }\n\n    /**\n     * @return mixed\n     */\n    public function getHelper(string $name)\n    {\n        return $this->getCommand()->getHelper($name);\n    }\n\n    public function getCommand(): parent\n    {\n        if (!$this->command instanceof \\Closure) {\n            return $this->command;\n        }\n\n        $command = $this->command = ($this->command)();\n        $command->setApplication($this->getApplication());\n\n        if (null !== $this->getHelperSet()) {\n            $command->setHelperSet($this->getHelperSet());\n        }\n\n        $command->setName($this->getName())\n            ->setAliases($this->getAliases())\n            ->setHidden($this->isHidden())\n            ->setDescription($this->getDescription());\n\n        // Will throw if the command is not correctly initialized.\n        $command->getDefinition();\n\n        return $command;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Command/ListCommand.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Command;\n\nuse Symfony\\Component\\Console\\Completion\\CompletionInput;\nuse Symfony\\Component\\Console\\Completion\\CompletionSuggestions;\nuse Symfony\\Component\\Console\\Descriptor\\ApplicationDescription;\nuse Symfony\\Component\\Console\\Helper\\DescriptorHelper;\nuse Symfony\\Component\\Console\\Input\\InputArgument;\nuse Symfony\\Component\\Console\\Input\\InputInterface;\nuse Symfony\\Component\\Console\\Input\\InputOption;\nuse Symfony\\Component\\Console\\Output\\OutputInterface;\n\n/**\n * ListCommand displays the list of all available commands for the application.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass ListCommand extends Command\n{\n    /**\n     * {@inheritdoc}\n     */\n    protected function configure()\n    {\n        $this\n            ->setName('list')\n            ->setDefinition([\n                new InputArgument('namespace', InputArgument::OPTIONAL, 'The namespace name'),\n                new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command list'),\n                new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt'),\n                new InputOption('short', null, InputOption::VALUE_NONE, 'To skip describing commands\\' arguments'),\n            ])\n            ->setDescription('List commands')\n            ->setHelp(<<<'EOF'\nThe <info>%command.name%</info> command lists all commands:\n\n  <info>%command.full_name%</info>\n\nYou can also display the commands for a specific namespace:\n\n  <info>%command.full_name% test</info>\n\nYou can also output the information in other formats by using the <comment>--format</comment> option:\n\n  <info>%command.full_name% --format=xml</info>\n\nIt's also possible to get raw list of commands (useful for embedding command runner):\n\n  <info>%command.full_name% --raw</info>\nEOF\n            )\n        ;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    protected function execute(InputInterface $input, OutputInterface $output)\n    {\n        $helper = new DescriptorHelper();\n        $helper->describe($output, $this->getApplication(), [\n            'format' => $input->getOption('format'),\n            'raw_text' => $input->getOption('raw'),\n            'namespace' => $input->getArgument('namespace'),\n            'short' => $input->getOption('short'),\n        ]);\n\n        return 0;\n    }\n\n    public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void\n    {\n        if ($input->mustSuggestArgumentValuesFor('namespace')) {\n            $descriptor = new ApplicationDescription($this->getApplication());\n            $suggestions->suggestValues(array_keys($descriptor->getNamespaces()));\n\n            return;\n        }\n\n        if ($input->mustSuggestOptionValuesFor('format')) {\n            $helper = new DescriptorHelper();\n            $suggestions->suggestValues($helper->getFormats());\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Command/LockableTrait.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Command;\n\nuse Symfony\\Component\\Console\\Exception\\LogicException;\nuse Symfony\\Component\\Lock\\LockFactory;\nuse Symfony\\Component\\Lock\\LockInterface;\nuse Symfony\\Component\\Lock\\Store\\FlockStore;\nuse Symfony\\Component\\Lock\\Store\\SemaphoreStore;\n\n/**\n * Basic lock feature for commands.\n *\n * @author Geoffrey Brier <geoffrey.brier@gmail.com>\n */\ntrait LockableTrait\n{\n    /** @var LockInterface|null */\n    private $lock;\n\n    /**\n     * Locks a command.\n     */\n    private function lock(?string $name = null, bool $blocking = false): bool\n    {\n        if (!class_exists(SemaphoreStore::class)) {\n            throw new LogicException('To enable the locking feature you must install the symfony/lock component.');\n        }\n\n        if (null !== $this->lock) {\n            throw new LogicException('A lock is already in place.');\n        }\n\n        if (SemaphoreStore::isSupported()) {\n            $store = new SemaphoreStore();\n        } else {\n            $store = new FlockStore();\n        }\n\n        $this->lock = (new LockFactory($store))->createLock($name ?: $this->getName());\n        if (!$this->lock->acquire($blocking)) {\n            $this->lock = null;\n\n            return false;\n        }\n\n        return true;\n    }\n\n    /**\n     * Releases the command lock if there is one.\n     */\n    private function release()\n    {\n        if ($this->lock) {\n            $this->lock->release();\n            $this->lock = null;\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Command/SignalableCommandInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Command;\n\n/**\n * Interface for command reacting to signal.\n *\n * @author Grégoire Pineau <lyrixx@lyrix.info>\n */\ninterface SignalableCommandInterface\n{\n    /**\n     * Returns the list of signals to subscribe.\n     */\n    public function getSubscribedSignals(): array;\n\n    /**\n     * The method will be called when the application is signaled.\n     */\n    public function handleSignal(int $signal): void;\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/CommandLoader/CommandLoaderInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\CommandLoader;\n\nuse Symfony\\Component\\Console\\Command\\Command;\nuse Symfony\\Component\\Console\\Exception\\CommandNotFoundException;\n\n/**\n * @author Robin Chalas <robin.chalas@gmail.com>\n */\ninterface CommandLoaderInterface\n{\n    /**\n     * Loads a command.\n     *\n     * @return Command\n     *\n     * @throws CommandNotFoundException\n     */\n    public function get(string $name);\n\n    /**\n     * Checks if a command exists.\n     *\n     * @return bool\n     */\n    public function has(string $name);\n\n    /**\n     * @return string[]\n     */\n    public function getNames();\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/CommandLoader/ContainerCommandLoader.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\CommandLoader;\n\nuse Psr\\Container\\ContainerInterface;\nuse Symfony\\Component\\Console\\Exception\\CommandNotFoundException;\n\n/**\n * Loads commands from a PSR-11 container.\n *\n * @author Robin Chalas <robin.chalas@gmail.com>\n */\nclass ContainerCommandLoader implements CommandLoaderInterface\n{\n    private $container;\n    private $commandMap;\n\n    /**\n     * @param array $commandMap An array with command names as keys and service ids as values\n     */\n    public function __construct(ContainerInterface $container, array $commandMap)\n    {\n        $this->container = $container;\n        $this->commandMap = $commandMap;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function get(string $name)\n    {\n        if (!$this->has($name)) {\n            throw new CommandNotFoundException(sprintf('Command \"%s\" does not exist.', $name));\n        }\n\n        return $this->container->get($this->commandMap[$name]);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function has(string $name)\n    {\n        return isset($this->commandMap[$name]) && $this->container->has($this->commandMap[$name]);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getNames()\n    {\n        return array_keys($this->commandMap);\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/CommandLoader/FactoryCommandLoader.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\CommandLoader;\n\nuse Symfony\\Component\\Console\\Exception\\CommandNotFoundException;\n\n/**\n * A simple command loader using factories to instantiate commands lazily.\n *\n * @author Maxime Steinhausser <maxime.steinhausser@gmail.com>\n */\nclass FactoryCommandLoader implements CommandLoaderInterface\n{\n    private $factories;\n\n    /**\n     * @param callable[] $factories Indexed by command names\n     */\n    public function __construct(array $factories)\n    {\n        $this->factories = $factories;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function has(string $name)\n    {\n        return isset($this->factories[$name]);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function get(string $name)\n    {\n        if (!isset($this->factories[$name])) {\n            throw new CommandNotFoundException(sprintf('Command \"%s\" does not exist.', $name));\n        }\n\n        $factory = $this->factories[$name];\n\n        return $factory();\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getNames()\n    {\n        return array_keys($this->factories);\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Completion/CompletionInput.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Completion;\n\nuse Symfony\\Component\\Console\\Exception\\RuntimeException;\nuse Symfony\\Component\\Console\\Input\\ArgvInput;\nuse Symfony\\Component\\Console\\Input\\InputDefinition;\nuse Symfony\\Component\\Console\\Input\\InputOption;\n\n/**\n * An input specialized for shell completion.\n *\n * This input allows unfinished option names or values and exposes what kind of\n * completion is expected.\n *\n * @author Wouter de Jong <wouter@wouterj.nl>\n */\nfinal class CompletionInput extends ArgvInput\n{\n    public const TYPE_ARGUMENT_VALUE = 'argument_value';\n    public const TYPE_OPTION_VALUE = 'option_value';\n    public const TYPE_OPTION_NAME = 'option_name';\n    public const TYPE_NONE = 'none';\n\n    private $tokens;\n    private $currentIndex;\n    private $completionType;\n    private $completionName = null;\n    private $completionValue = '';\n\n    /**\n     * Converts a terminal string into tokens.\n     *\n     * This is required for shell completions without COMP_WORDS support.\n     */\n    public static function fromString(string $inputStr, int $currentIndex): self\n    {\n        preg_match_all('/(?<=^|\\s)([\\'\"]?)(.+?)(?<!\\\\\\\\)\\1(?=$|\\s)/', $inputStr, $tokens);\n\n        return self::fromTokens($tokens[0], $currentIndex);\n    }\n\n    /**\n     * Create an input based on an COMP_WORDS token list.\n     *\n     * @param string[] $tokens       the set of split tokens (e.g. COMP_WORDS or argv)\n     * @param int      $currentIndex the index of the cursor (e.g. COMP_CWORD)\n     */\n    public static function fromTokens(array $tokens, int $currentIndex): self\n    {\n        $input = new self($tokens);\n        $input->tokens = $tokens;\n        $input->currentIndex = $currentIndex;\n\n        return $input;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function bind(InputDefinition $definition): void\n    {\n        parent::bind($definition);\n\n        $relevantToken = $this->getRelevantToken();\n        if ('-' === $relevantToken[0]) {\n            // the current token is an input option: complete either option name or option value\n            [$optionToken, $optionValue] = explode('=', $relevantToken, 2) + ['', ''];\n\n            $option = $this->getOptionFromToken($optionToken);\n            if (null === $option && !$this->isCursorFree()) {\n                $this->completionType = self::TYPE_OPTION_NAME;\n                $this->completionValue = $relevantToken;\n\n                return;\n            }\n\n            if (null !== $option && $option->acceptValue()) {\n                $this->completionType = self::TYPE_OPTION_VALUE;\n                $this->completionName = $option->getName();\n                $this->completionValue = $optionValue ?: (!str_starts_with($optionToken, '--') ? substr($optionToken, 2) : '');\n\n                return;\n            }\n        }\n\n        $previousToken = $this->tokens[$this->currentIndex - 1];\n        if ('-' === $previousToken[0] && '' !== trim($previousToken, '-')) {\n            // check if previous option accepted a value\n            $previousOption = $this->getOptionFromToken($previousToken);\n            if (null !== $previousOption && $previousOption->acceptValue()) {\n                $this->completionType = self::TYPE_OPTION_VALUE;\n                $this->completionName = $previousOption->getName();\n                $this->completionValue = $relevantToken;\n\n                return;\n            }\n        }\n\n        // complete argument value\n        $this->completionType = self::TYPE_ARGUMENT_VALUE;\n\n        foreach ($this->definition->getArguments() as $argumentName => $argument) {\n            if (!isset($this->arguments[$argumentName])) {\n                break;\n            }\n\n            $argumentValue = $this->arguments[$argumentName];\n            $this->completionName = $argumentName;\n            if (\\is_array($argumentValue)) {\n                $this->completionValue = $argumentValue ? $argumentValue[array_key_last($argumentValue)] : null;\n            } else {\n                $this->completionValue = $argumentValue;\n            }\n        }\n\n        if ($this->currentIndex >= \\count($this->tokens)) {\n            if (!isset($this->arguments[$argumentName]) || $this->definition->getArgument($argumentName)->isArray()) {\n                $this->completionName = $argumentName;\n                $this->completionValue = '';\n            } else {\n                // we've reached the end\n                $this->completionType = self::TYPE_NONE;\n                $this->completionName = null;\n                $this->completionValue = '';\n            }\n        }\n    }\n\n    /**\n     * Returns the type of completion required.\n     *\n     * TYPE_ARGUMENT_VALUE when completing the value of an input argument\n     * TYPE_OPTION_VALUE   when completing the value of an input option\n     * TYPE_OPTION_NAME    when completing the name of an input option\n     * TYPE_NONE           when nothing should be completed\n     *\n     * @return string One of self::TYPE_* constants. TYPE_OPTION_NAME and TYPE_NONE are already implemented by the Console component\n     */\n    public function getCompletionType(): string\n    {\n        return $this->completionType;\n    }\n\n    /**\n     * The name of the input option or argument when completing a value.\n     *\n     * @return string|null returns null when completing an option name\n     */\n    public function getCompletionName(): ?string\n    {\n        return $this->completionName;\n    }\n\n    /**\n     * The value already typed by the user (or empty string).\n     */\n    public function getCompletionValue(): string\n    {\n        return $this->completionValue;\n    }\n\n    public function mustSuggestOptionValuesFor(string $optionName): bool\n    {\n        return self::TYPE_OPTION_VALUE === $this->getCompletionType() && $optionName === $this->getCompletionName();\n    }\n\n    public function mustSuggestArgumentValuesFor(string $argumentName): bool\n    {\n        return self::TYPE_ARGUMENT_VALUE === $this->getCompletionType() && $argumentName === $this->getCompletionName();\n    }\n\n    protected function parseToken(string $token, bool $parseOptions): bool\n    {\n        try {\n            return parent::parseToken($token, $parseOptions);\n        } catch (RuntimeException $e) {\n            // suppress errors, completed input is almost never valid\n        }\n\n        return $parseOptions;\n    }\n\n    private function getOptionFromToken(string $optionToken): ?InputOption\n    {\n        $optionName = ltrim($optionToken, '-');\n        if (!$optionName) {\n            return null;\n        }\n\n        if ('-' === ($optionToken[1] ?? ' ')) {\n            // long option name\n            return $this->definition->hasOption($optionName) ? $this->definition->getOption($optionName) : null;\n        }\n\n        // short option name\n        return $this->definition->hasShortcut($optionName[0]) ? $this->definition->getOptionForShortcut($optionName[0]) : null;\n    }\n\n    /**\n     * The token of the cursor, or the last token if the cursor is at the end of the input.\n     */\n    private function getRelevantToken(): string\n    {\n        return $this->tokens[$this->isCursorFree() ? $this->currentIndex - 1 : $this->currentIndex];\n    }\n\n    /**\n     * Whether the cursor is \"free\" (i.e. at the end of the input preceded by a space).\n     */\n    private function isCursorFree(): bool\n    {\n        $nrOfTokens = \\count($this->tokens);\n        if ($this->currentIndex > $nrOfTokens) {\n            throw new \\LogicException('Current index is invalid, it must be the number of input tokens or one more.');\n        }\n\n        return $this->currentIndex >= $nrOfTokens;\n    }\n\n    public function __toString()\n    {\n        $str = '';\n        foreach ($this->tokens as $i => $token) {\n            $str .= $token;\n\n            if ($this->currentIndex === $i) {\n                $str .= '|';\n            }\n\n            $str .= ' ';\n        }\n\n        if ($this->currentIndex > $i) {\n            $str .= '|';\n        }\n\n        return rtrim($str);\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Completion/CompletionSuggestions.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Completion;\n\nuse Symfony\\Component\\Console\\Input\\InputOption;\n\n/**\n * Stores all completion suggestions for the current input.\n *\n * @author Wouter de Jong <wouter@wouterj.nl>\n */\nfinal class CompletionSuggestions\n{\n    private $valueSuggestions = [];\n    private $optionSuggestions = [];\n\n    /**\n     * Add a suggested value for an input option or argument.\n     *\n     * @param string|Suggestion $value\n     *\n     * @return $this\n     */\n    public function suggestValue($value): self\n    {\n        $this->valueSuggestions[] = !$value instanceof Suggestion ? new Suggestion($value) : $value;\n\n        return $this;\n    }\n\n    /**\n     * Add multiple suggested values at once for an input option or argument.\n     *\n     * @param list<string|Suggestion> $values\n     *\n     * @return $this\n     */\n    public function suggestValues(array $values): self\n    {\n        foreach ($values as $value) {\n            $this->suggestValue($value);\n        }\n\n        return $this;\n    }\n\n    /**\n     * Add a suggestion for an input option name.\n     *\n     * @return $this\n     */\n    public function suggestOption(InputOption $option): self\n    {\n        $this->optionSuggestions[] = $option;\n\n        return $this;\n    }\n\n    /**\n     * Add multiple suggestions for input option names at once.\n     *\n     * @param InputOption[] $options\n     *\n     * @return $this\n     */\n    public function suggestOptions(array $options): self\n    {\n        foreach ($options as $option) {\n            $this->suggestOption($option);\n        }\n\n        return $this;\n    }\n\n    /**\n     * @return InputOption[]\n     */\n    public function getOptionSuggestions(): array\n    {\n        return $this->optionSuggestions;\n    }\n\n    /**\n     * @return Suggestion[]\n     */\n    public function getValueSuggestions(): array\n    {\n        return $this->valueSuggestions;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Completion/Output/BashCompletionOutput.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Completion\\Output;\n\nuse Symfony\\Component\\Console\\Completion\\CompletionSuggestions;\nuse Symfony\\Component\\Console\\Output\\OutputInterface;\n\n/**\n * @author Wouter de Jong <wouter@wouterj.nl>\n */\nclass BashCompletionOutput implements CompletionOutputInterface\n{\n    public function write(CompletionSuggestions $suggestions, OutputInterface $output): void\n    {\n        $values = $suggestions->getValueSuggestions();\n        foreach ($suggestions->getOptionSuggestions() as $option) {\n            $values[] = '--'.$option->getName();\n            if ($option->isNegatable()) {\n                $values[] = '--no-'.$option->getName();\n            }\n        }\n        $output->writeln(implode(\"\\n\", $values));\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Completion/Output/CompletionOutputInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Completion\\Output;\n\nuse Symfony\\Component\\Console\\Completion\\CompletionSuggestions;\nuse Symfony\\Component\\Console\\Output\\OutputInterface;\n\n/**\n * Transforms the {@see CompletionSuggestions} object into output readable by the shell completion.\n *\n * @author Wouter de Jong <wouter@wouterj.nl>\n */\ninterface CompletionOutputInterface\n{\n    public function write(CompletionSuggestions $suggestions, OutputInterface $output): void;\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Completion/Suggestion.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Completion;\n\n/**\n * Represents a single suggested value.\n *\n * @author Wouter de Jong <wouter@wouterj.nl>\n */\nclass Suggestion\n{\n    private $value;\n\n    public function __construct(string $value)\n    {\n        $this->value = $value;\n    }\n\n    public function getValue(): string\n    {\n        return $this->value;\n    }\n\n    public function __toString(): string\n    {\n        return $this->getValue();\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/ConsoleEvents.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console;\n\nuse Symfony\\Component\\Console\\Event\\ConsoleCommandEvent;\nuse Symfony\\Component\\Console\\Event\\ConsoleErrorEvent;\nuse Symfony\\Component\\Console\\Event\\ConsoleSignalEvent;\nuse Symfony\\Component\\Console\\Event\\ConsoleTerminateEvent;\n\n/**\n * Contains all events dispatched by an Application.\n *\n * @author Francesco Levorato <git@flevour.net>\n */\nfinal class ConsoleEvents\n{\n    /**\n     * The COMMAND event allows you to attach listeners before any command is\n     * executed by the console. It also allows you to modify the command, input and output\n     * before they are handed to the command.\n     *\n     * @Event(\"Symfony\\Component\\Console\\Event\\ConsoleCommandEvent\")\n     */\n    public const COMMAND = 'console.command';\n\n    /**\n     * The SIGNAL event allows you to perform some actions\n     * after the command execution was interrupted.\n     *\n     * @Event(\"Symfony\\Component\\Console\\Event\\ConsoleSignalEvent\")\n     */\n    public const SIGNAL = 'console.signal';\n\n    /**\n     * The TERMINATE event allows you to attach listeners after a command is\n     * executed by the console.\n     *\n     * @Event(\"Symfony\\Component\\Console\\Event\\ConsoleTerminateEvent\")\n     */\n    public const TERMINATE = 'console.terminate';\n\n    /**\n     * The ERROR event occurs when an uncaught exception or error appears.\n     *\n     * This event allows you to deal with the exception/error or\n     * to modify the thrown exception.\n     *\n     * @Event(\"Symfony\\Component\\Console\\Event\\ConsoleErrorEvent\")\n     */\n    public const ERROR = 'console.error';\n\n    /**\n     * Event aliases.\n     *\n     * These aliases can be consumed by RegisterListenersPass.\n     */\n    public const ALIASES = [\n        ConsoleCommandEvent::class => self::COMMAND,\n        ConsoleErrorEvent::class => self::ERROR,\n        ConsoleSignalEvent::class => self::SIGNAL,\n        ConsoleTerminateEvent::class => self::TERMINATE,\n    ];\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Cursor.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console;\n\nuse Symfony\\Component\\Console\\Output\\OutputInterface;\n\n/**\n * @author Pierre du Plessis <pdples@gmail.com>\n */\nfinal class Cursor\n{\n    private $output;\n    private $input;\n\n    /**\n     * @param resource|null $input\n     */\n    public function __construct(OutputInterface $output, $input = null)\n    {\n        $this->output = $output;\n        $this->input = $input ?? (\\defined('STDIN') ? \\STDIN : fopen('php://input', 'r+'));\n    }\n\n    /**\n     * @return $this\n     */\n    public function moveUp(int $lines = 1): self\n    {\n        $this->output->write(sprintf(\"\\x1b[%dA\", $lines));\n\n        return $this;\n    }\n\n    /**\n     * @return $this\n     */\n    public function moveDown(int $lines = 1): self\n    {\n        $this->output->write(sprintf(\"\\x1b[%dB\", $lines));\n\n        return $this;\n    }\n\n    /**\n     * @return $this\n     */\n    public function moveRight(int $columns = 1): self\n    {\n        $this->output->write(sprintf(\"\\x1b[%dC\", $columns));\n\n        return $this;\n    }\n\n    /**\n     * @return $this\n     */\n    public function moveLeft(int $columns = 1): self\n    {\n        $this->output->write(sprintf(\"\\x1b[%dD\", $columns));\n\n        return $this;\n    }\n\n    /**\n     * @return $this\n     */\n    public function moveToColumn(int $column): self\n    {\n        $this->output->write(sprintf(\"\\x1b[%dG\", $column));\n\n        return $this;\n    }\n\n    /**\n     * @return $this\n     */\n    public function moveToPosition(int $column, int $row): self\n    {\n        $this->output->write(sprintf(\"\\x1b[%d;%dH\", $row + 1, $column));\n\n        return $this;\n    }\n\n    /**\n     * @return $this\n     */\n    public function savePosition(): self\n    {\n        $this->output->write(\"\\x1b7\");\n\n        return $this;\n    }\n\n    /**\n     * @return $this\n     */\n    public function restorePosition(): self\n    {\n        $this->output->write(\"\\x1b8\");\n\n        return $this;\n    }\n\n    /**\n     * @return $this\n     */\n    public function hide(): self\n    {\n        $this->output->write(\"\\x1b[?25l\");\n\n        return $this;\n    }\n\n    /**\n     * @return $this\n     */\n    public function show(): self\n    {\n        $this->output->write(\"\\x1b[?25h\\x1b[?0c\");\n\n        return $this;\n    }\n\n    /**\n     * Clears all the output from the current line.\n     *\n     * @return $this\n     */\n    public function clearLine(): self\n    {\n        $this->output->write(\"\\x1b[2K\");\n\n        return $this;\n    }\n\n    /**\n     * Clears all the output from the current line after the current position.\n     */\n    public function clearLineAfter(): self\n    {\n        $this->output->write(\"\\x1b[K\");\n\n        return $this;\n    }\n\n    /**\n     * Clears all the output from the cursors' current position to the end of the screen.\n     *\n     * @return $this\n     */\n    public function clearOutput(): self\n    {\n        $this->output->write(\"\\x1b[0J\");\n\n        return $this;\n    }\n\n    /**\n     * Clears the entire screen.\n     *\n     * @return $this\n     */\n    public function clearScreen(): self\n    {\n        $this->output->write(\"\\x1b[2J\");\n\n        return $this;\n    }\n\n    /**\n     * Returns the current cursor position as x,y coordinates.\n     */\n    public function getCurrentPosition(): array\n    {\n        static $isTtySupported;\n\n        if (null === $isTtySupported && \\function_exists('proc_open')) {\n            $isTtySupported = (bool) @proc_open('echo 1 >/dev/null', [['file', '/dev/tty', 'r'], ['file', '/dev/tty', 'w'], ['file', '/dev/tty', 'w']], $pipes);\n        }\n\n        if (!$isTtySupported) {\n            return [1, 1];\n        }\n\n        $sttyMode = shell_exec('stty -g');\n        shell_exec('stty -icanon -echo');\n\n        @fwrite($this->input, \"\\033[6n\");\n\n        $code = trim(fread($this->input, 1024));\n\n        shell_exec(sprintf('stty %s', $sttyMode));\n\n        sscanf($code, \"\\033[%d;%dR\", $row, $col);\n\n        return [$col, $row];\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/DependencyInjection/AddConsoleCommandPass.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\DependencyInjection;\n\nuse Symfony\\Component\\Console\\Command\\Command;\nuse Symfony\\Component\\Console\\Command\\LazyCommand;\nuse Symfony\\Component\\Console\\CommandLoader\\ContainerCommandLoader;\nuse Symfony\\Component\\DependencyInjection\\Argument\\ServiceClosureArgument;\nuse Symfony\\Component\\DependencyInjection\\Compiler\\CompilerPassInterface;\nuse Symfony\\Component\\DependencyInjection\\Compiler\\ServiceLocatorTagPass;\nuse Symfony\\Component\\DependencyInjection\\ContainerBuilder;\nuse Symfony\\Component\\DependencyInjection\\Exception\\InvalidArgumentException;\nuse Symfony\\Component\\DependencyInjection\\Reference;\nuse Symfony\\Component\\DependencyInjection\\TypedReference;\n\n/**\n * Registers console commands.\n *\n * @author Grégoire Pineau <lyrixx@lyrixx.info>\n */\nclass AddConsoleCommandPass implements CompilerPassInterface\n{\n    private $commandLoaderServiceId;\n    private $commandTag;\n    private $noPreloadTag;\n    private $privateTagName;\n\n    public function __construct(string $commandLoaderServiceId = 'console.command_loader', string $commandTag = 'console.command', string $noPreloadTag = 'container.no_preload', string $privateTagName = 'container.private')\n    {\n        if (0 < \\func_num_args()) {\n            trigger_deprecation('symfony/console', '5.3', 'Configuring \"%s\" is deprecated.', __CLASS__);\n        }\n\n        $this->commandLoaderServiceId = $commandLoaderServiceId;\n        $this->commandTag = $commandTag;\n        $this->noPreloadTag = $noPreloadTag;\n        $this->privateTagName = $privateTagName;\n    }\n\n    public function process(ContainerBuilder $container)\n    {\n        $commandServices = $container->findTaggedServiceIds($this->commandTag, true);\n        $lazyCommandMap = [];\n        $lazyCommandRefs = [];\n        $serviceIds = [];\n\n        foreach ($commandServices as $id => $tags) {\n            $definition = $container->getDefinition($id);\n            $definition->addTag($this->noPreloadTag);\n            $class = $container->getParameterBag()->resolveValue($definition->getClass());\n\n            if (isset($tags[0]['command'])) {\n                $aliases = $tags[0]['command'];\n            } else {\n                if (!$r = $container->getReflectionClass($class)) {\n                    throw new InvalidArgumentException(sprintf('Class \"%s\" used for service \"%s\" cannot be found.', $class, $id));\n                }\n                if (!$r->isSubclassOf(Command::class)) {\n                    throw new InvalidArgumentException(sprintf('The service \"%s\" tagged \"%s\" must be a subclass of \"%s\".', $id, $this->commandTag, Command::class));\n                }\n                $aliases = str_replace('%', '%%', $class::getDefaultName() ?? '');\n            }\n\n            $aliases = explode('|', $aliases ?? '');\n            $commandName = array_shift($aliases);\n\n            if ($isHidden = '' === $commandName) {\n                $commandName = array_shift($aliases);\n            }\n\n            if (null === $commandName) {\n                if (!$definition->isPublic() || $definition->isPrivate() || $definition->hasTag($this->privateTagName)) {\n                    $commandId = 'console.command.public_alias.'.$id;\n                    $container->setAlias($commandId, $id)->setPublic(true);\n                    $id = $commandId;\n                }\n                $serviceIds[] = $id;\n\n                continue;\n            }\n\n            $description = $tags[0]['description'] ?? null;\n\n            unset($tags[0]);\n            $lazyCommandMap[$commandName] = $id;\n            $lazyCommandRefs[$id] = new TypedReference($id, $class);\n\n            foreach ($aliases as $alias) {\n                $lazyCommandMap[$alias] = $id;\n            }\n\n            foreach ($tags as $tag) {\n                if (isset($tag['command'])) {\n                    $aliases[] = $tag['command'];\n                    $lazyCommandMap[$tag['command']] = $id;\n                }\n\n                $description = $description ?? $tag['description'] ?? null;\n            }\n\n            $definition->addMethodCall('setName', [$commandName]);\n\n            if ($aliases) {\n                $definition->addMethodCall('setAliases', [$aliases]);\n            }\n\n            if ($isHidden) {\n                $definition->addMethodCall('setHidden', [true]);\n            }\n\n            if (!$description) {\n                if (!$r = $container->getReflectionClass($class)) {\n                    throw new InvalidArgumentException(sprintf('Class \"%s\" used for service \"%s\" cannot be found.', $class, $id));\n                }\n                if (!$r->isSubclassOf(Command::class)) {\n                    throw new InvalidArgumentException(sprintf('The service \"%s\" tagged \"%s\" must be a subclass of \"%s\".', $id, $this->commandTag, Command::class));\n                }\n                $description = str_replace('%', '%%', $class::getDefaultDescription() ?? '');\n            }\n\n            if ($description) {\n                $definition->addMethodCall('setDescription', [$description]);\n\n                $container->register('.'.$id.'.lazy', LazyCommand::class)\n                    ->setArguments([$commandName, $aliases, $description, $isHidden, new ServiceClosureArgument($lazyCommandRefs[$id])]);\n\n                $lazyCommandRefs[$id] = new Reference('.'.$id.'.lazy');\n            }\n        }\n\n        $container\n            ->register($this->commandLoaderServiceId, ContainerCommandLoader::class)\n            ->setPublic(true)\n            ->addTag($this->noPreloadTag)\n            ->setArguments([ServiceLocatorTagPass::register($container, $lazyCommandRefs), $lazyCommandMap]);\n\n        $container->setParameter('console.command.ids', $serviceIds);\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Descriptor/ApplicationDescription.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Descriptor;\n\nuse Symfony\\Component\\Console\\Application;\nuse Symfony\\Component\\Console\\Command\\Command;\nuse Symfony\\Component\\Console\\Exception\\CommandNotFoundException;\n\n/**\n * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>\n *\n * @internal\n */\nclass ApplicationDescription\n{\n    public const GLOBAL_NAMESPACE = '_global';\n\n    private $application;\n    private $namespace;\n    private $showHidden;\n\n    /**\n     * @var array\n     */\n    private $namespaces;\n\n    /**\n     * @var array<string, Command>\n     */\n    private $commands;\n\n    /**\n     * @var array<string, Command>\n     */\n    private $aliases;\n\n    public function __construct(Application $application, ?string $namespace = null, bool $showHidden = false)\n    {\n        $this->application = $application;\n        $this->namespace = $namespace;\n        $this->showHidden = $showHidden;\n    }\n\n    public function getNamespaces(): array\n    {\n        if (null === $this->namespaces) {\n            $this->inspectApplication();\n        }\n\n        return $this->namespaces;\n    }\n\n    /**\n     * @return Command[]\n     */\n    public function getCommands(): array\n    {\n        if (null === $this->commands) {\n            $this->inspectApplication();\n        }\n\n        return $this->commands;\n    }\n\n    /**\n     * @throws CommandNotFoundException\n     */\n    public function getCommand(string $name): Command\n    {\n        if (!isset($this->commands[$name]) && !isset($this->aliases[$name])) {\n            throw new CommandNotFoundException(sprintf('Command \"%s\" does not exist.', $name));\n        }\n\n        return $this->commands[$name] ?? $this->aliases[$name];\n    }\n\n    private function inspectApplication()\n    {\n        $this->commands = [];\n        $this->namespaces = [];\n\n        $all = $this->application->all($this->namespace ? $this->application->findNamespace($this->namespace) : null);\n        foreach ($this->sortCommands($all) as $namespace => $commands) {\n            $names = [];\n\n            /** @var Command $command */\n            foreach ($commands as $name => $command) {\n                if (!$command->getName() || (!$this->showHidden && $command->isHidden())) {\n                    continue;\n                }\n\n                if ($command->getName() === $name) {\n                    $this->commands[$name] = $command;\n                } else {\n                    $this->aliases[$name] = $command;\n                }\n\n                $names[] = $name;\n            }\n\n            $this->namespaces[$namespace] = ['id' => $namespace, 'commands' => $names];\n        }\n    }\n\n    private function sortCommands(array $commands): array\n    {\n        $namespacedCommands = [];\n        $globalCommands = [];\n        $sortedCommands = [];\n        foreach ($commands as $name => $command) {\n            $key = $this->application->extractNamespace($name, 1);\n            if (\\in_array($key, ['', self::GLOBAL_NAMESPACE], true)) {\n                $globalCommands[$name] = $command;\n            } else {\n                $namespacedCommands[$key][$name] = $command;\n            }\n        }\n\n        if ($globalCommands) {\n            ksort($globalCommands);\n            $sortedCommands[self::GLOBAL_NAMESPACE] = $globalCommands;\n        }\n\n        if ($namespacedCommands) {\n            ksort($namespacedCommands, \\SORT_STRING);\n            foreach ($namespacedCommands as $key => $commandsSet) {\n                ksort($commandsSet);\n                $sortedCommands[$key] = $commandsSet;\n            }\n        }\n\n        return $sortedCommands;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Descriptor/Descriptor.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Descriptor;\n\nuse Symfony\\Component\\Console\\Application;\nuse Symfony\\Component\\Console\\Command\\Command;\nuse Symfony\\Component\\Console\\Exception\\InvalidArgumentException;\nuse Symfony\\Component\\Console\\Input\\InputArgument;\nuse Symfony\\Component\\Console\\Input\\InputDefinition;\nuse Symfony\\Component\\Console\\Input\\InputOption;\nuse Symfony\\Component\\Console\\Output\\OutputInterface;\n\n/**\n * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>\n *\n * @internal\n */\nabstract class Descriptor implements DescriptorInterface\n{\n    /**\n     * @var OutputInterface\n     */\n    protected $output;\n\n    /**\n     * {@inheritdoc}\n     */\n    public function describe(OutputInterface $output, object $object, array $options = [])\n    {\n        $this->output = $output;\n\n        switch (true) {\n            case $object instanceof InputArgument:\n                $this->describeInputArgument($object, $options);\n                break;\n            case $object instanceof InputOption:\n                $this->describeInputOption($object, $options);\n                break;\n            case $object instanceof InputDefinition:\n                $this->describeInputDefinition($object, $options);\n                break;\n            case $object instanceof Command:\n                $this->describeCommand($object, $options);\n                break;\n            case $object instanceof Application:\n                $this->describeApplication($object, $options);\n                break;\n            default:\n                throw new InvalidArgumentException(sprintf('Object of type \"%s\" is not describable.', get_debug_type($object)));\n        }\n    }\n\n    /**\n     * Writes content to output.\n     */\n    protected function write(string $content, bool $decorated = false)\n    {\n        $this->output->write($content, false, $decorated ? OutputInterface::OUTPUT_NORMAL : OutputInterface::OUTPUT_RAW);\n    }\n\n    /**\n     * Describes an InputArgument instance.\n     */\n    abstract protected function describeInputArgument(InputArgument $argument, array $options = []);\n\n    /**\n     * Describes an InputOption instance.\n     */\n    abstract protected function describeInputOption(InputOption $option, array $options = []);\n\n    /**\n     * Describes an InputDefinition instance.\n     */\n    abstract protected function describeInputDefinition(InputDefinition $definition, array $options = []);\n\n    /**\n     * Describes a Command instance.\n     */\n    abstract protected function describeCommand(Command $command, array $options = []);\n\n    /**\n     * Describes an Application instance.\n     */\n    abstract protected function describeApplication(Application $application, array $options = []);\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Descriptor/DescriptorInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Descriptor;\n\nuse Symfony\\Component\\Console\\Output\\OutputInterface;\n\n/**\n * Descriptor interface.\n *\n * @author Jean-François Simon <contact@jfsimon.fr>\n */\ninterface DescriptorInterface\n{\n    public function describe(OutputInterface $output, object $object, array $options = []);\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Descriptor/JsonDescriptor.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Descriptor;\n\nuse Symfony\\Component\\Console\\Application;\nuse Symfony\\Component\\Console\\Command\\Command;\nuse Symfony\\Component\\Console\\Input\\InputArgument;\nuse Symfony\\Component\\Console\\Input\\InputDefinition;\nuse Symfony\\Component\\Console\\Input\\InputOption;\n\n/**\n * JSON descriptor.\n *\n * @author Jean-François Simon <contact@jfsimon.fr>\n *\n * @internal\n */\nclass JsonDescriptor extends Descriptor\n{\n    /**\n     * {@inheritdoc}\n     */\n    protected function describeInputArgument(InputArgument $argument, array $options = [])\n    {\n        $this->writeData($this->getInputArgumentData($argument), $options);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    protected function describeInputOption(InputOption $option, array $options = [])\n    {\n        $this->writeData($this->getInputOptionData($option), $options);\n        if ($option->isNegatable()) {\n            $this->writeData($this->getInputOptionData($option, true), $options);\n        }\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    protected function describeInputDefinition(InputDefinition $definition, array $options = [])\n    {\n        $this->writeData($this->getInputDefinitionData($definition), $options);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    protected function describeCommand(Command $command, array $options = [])\n    {\n        $this->writeData($this->getCommandData($command, $options['short'] ?? false), $options);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    protected function describeApplication(Application $application, array $options = [])\n    {\n        $describedNamespace = $options['namespace'] ?? null;\n        $description = new ApplicationDescription($application, $describedNamespace, true);\n        $commands = [];\n\n        foreach ($description->getCommands() as $command) {\n            $commands[] = $this->getCommandData($command, $options['short'] ?? false);\n        }\n\n        $data = [];\n        if ('UNKNOWN' !== $application->getName()) {\n            $data['application']['name'] = $application->getName();\n            if ('UNKNOWN' !== $application->getVersion()) {\n                $data['application']['version'] = $application->getVersion();\n            }\n        }\n\n        $data['commands'] = $commands;\n\n        if ($describedNamespace) {\n            $data['namespace'] = $describedNamespace;\n        } else {\n            $data['namespaces'] = array_values($description->getNamespaces());\n        }\n\n        $this->writeData($data, $options);\n    }\n\n    /**\n     * Writes data as json.\n     */\n    private function writeData(array $data, array $options)\n    {\n        $flags = $options['json_encoding'] ?? 0;\n\n        $this->write(json_encode($data, $flags));\n    }\n\n    private function getInputArgumentData(InputArgument $argument): array\n    {\n        return [\n            'name' => $argument->getName(),\n            'is_required' => $argument->isRequired(),\n            'is_array' => $argument->isArray(),\n            'description' => preg_replace('/\\s*[\\r\\n]\\s*/', ' ', $argument->getDescription()),\n            'default' => \\INF === $argument->getDefault() ? 'INF' : $argument->getDefault(),\n        ];\n    }\n\n    private function getInputOptionData(InputOption $option, bool $negated = false): array\n    {\n        return $negated ? [\n            'name' => '--no-'.$option->getName(),\n            'shortcut' => '',\n            'accept_value' => false,\n            'is_value_required' => false,\n            'is_multiple' => false,\n            'description' => 'Negate the \"--'.$option->getName().'\" option',\n            'default' => false,\n        ] : [\n            'name' => '--'.$option->getName(),\n            'shortcut' => $option->getShortcut() ? '-'.str_replace('|', '|-', $option->getShortcut()) : '',\n            'accept_value' => $option->acceptValue(),\n            'is_value_required' => $option->isValueRequired(),\n            'is_multiple' => $option->isArray(),\n            'description' => preg_replace('/\\s*[\\r\\n]\\s*/', ' ', $option->getDescription()),\n            'default' => \\INF === $option->getDefault() ? 'INF' : $option->getDefault(),\n        ];\n    }\n\n    private function getInputDefinitionData(InputDefinition $definition): array\n    {\n        $inputArguments = [];\n        foreach ($definition->getArguments() as $name => $argument) {\n            $inputArguments[$name] = $this->getInputArgumentData($argument);\n        }\n\n        $inputOptions = [];\n        foreach ($definition->getOptions() as $name => $option) {\n            $inputOptions[$name] = $this->getInputOptionData($option);\n            if ($option->isNegatable()) {\n                $inputOptions['no-'.$name] = $this->getInputOptionData($option, true);\n            }\n        }\n\n        return ['arguments' => $inputArguments, 'options' => $inputOptions];\n    }\n\n    private function getCommandData(Command $command, bool $short = false): array\n    {\n        $data = [\n            'name' => $command->getName(),\n            'description' => $command->getDescription(),\n        ];\n\n        if ($short) {\n            $data += [\n                'usage' => $command->getAliases(),\n            ];\n        } else {\n            $command->mergeApplicationDefinition(false);\n\n            $data += [\n                'usage' => array_merge([$command->getSynopsis()], $command->getUsages(), $command->getAliases()),\n                'help' => $command->getProcessedHelp(),\n                'definition' => $this->getInputDefinitionData($command->getDefinition()),\n            ];\n        }\n\n        $data['hidden'] = $command->isHidden();\n\n        return $data;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Descriptor/MarkdownDescriptor.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Descriptor;\n\nuse Symfony\\Component\\Console\\Application;\nuse Symfony\\Component\\Console\\Command\\Command;\nuse Symfony\\Component\\Console\\Helper\\Helper;\nuse Symfony\\Component\\Console\\Input\\InputArgument;\nuse Symfony\\Component\\Console\\Input\\InputDefinition;\nuse Symfony\\Component\\Console\\Input\\InputOption;\nuse Symfony\\Component\\Console\\Output\\OutputInterface;\n\n/**\n * Markdown descriptor.\n *\n * @author Jean-François Simon <contact@jfsimon.fr>\n *\n * @internal\n */\nclass MarkdownDescriptor extends Descriptor\n{\n    /**\n     * {@inheritdoc}\n     */\n    public function describe(OutputInterface $output, object $object, array $options = [])\n    {\n        $decorated = $output->isDecorated();\n        $output->setDecorated(false);\n\n        parent::describe($output, $object, $options);\n\n        $output->setDecorated($decorated);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    protected function write(string $content, bool $decorated = true)\n    {\n        parent::write($content, $decorated);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    protected function describeInputArgument(InputArgument $argument, array $options = [])\n    {\n        $this->write(\n            '#### `'.($argument->getName() ?: '<none>').\"`\\n\\n\"\n            .($argument->getDescription() ? preg_replace('/\\s*[\\r\\n]\\s*/', \"\\n\", $argument->getDescription()).\"\\n\\n\" : '')\n            .'* Is required: '.($argument->isRequired() ? 'yes' : 'no').\"\\n\"\n            .'* Is array: '.($argument->isArray() ? 'yes' : 'no').\"\\n\"\n            .'* Default: `'.str_replace(\"\\n\", '', var_export($argument->getDefault(), true)).'`'\n        );\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    protected function describeInputOption(InputOption $option, array $options = [])\n    {\n        $name = '--'.$option->getName();\n        if ($option->isNegatable()) {\n            $name .= '|--no-'.$option->getName();\n        }\n        if ($option->getShortcut()) {\n            $name .= '|-'.str_replace('|', '|-', $option->getShortcut()).'';\n        }\n\n        $this->write(\n            '#### `'.$name.'`'.\"\\n\\n\"\n            .($option->getDescription() ? preg_replace('/\\s*[\\r\\n]\\s*/', \"\\n\", $option->getDescription()).\"\\n\\n\" : '')\n            .'* Accept value: '.($option->acceptValue() ? 'yes' : 'no').\"\\n\"\n            .'* Is value required: '.($option->isValueRequired() ? 'yes' : 'no').\"\\n\"\n            .'* Is multiple: '.($option->isArray() ? 'yes' : 'no').\"\\n\"\n            .'* Is negatable: '.($option->isNegatable() ? 'yes' : 'no').\"\\n\"\n            .'* Default: `'.str_replace(\"\\n\", '', var_export($option->getDefault(), true)).'`'\n        );\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    protected function describeInputDefinition(InputDefinition $definition, array $options = [])\n    {\n        if ($showArguments = \\count($definition->getArguments()) > 0) {\n            $this->write('### Arguments');\n            foreach ($definition->getArguments() as $argument) {\n                $this->write(\"\\n\\n\");\n                if (null !== $describeInputArgument = $this->describeInputArgument($argument)) {\n                    $this->write($describeInputArgument);\n                }\n            }\n        }\n\n        if (\\count($definition->getOptions()) > 0) {\n            if ($showArguments) {\n                $this->write(\"\\n\\n\");\n            }\n\n            $this->write('### Options');\n            foreach ($definition->getOptions() as $option) {\n                $this->write(\"\\n\\n\");\n                if (null !== $describeInputOption = $this->describeInputOption($option)) {\n                    $this->write($describeInputOption);\n                }\n            }\n        }\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    protected function describeCommand(Command $command, array $options = [])\n    {\n        if ($options['short'] ?? false) {\n            $this->write(\n                '`'.$command->getName().\"`\\n\"\n                .str_repeat('-', Helper::width($command->getName()) + 2).\"\\n\\n\"\n                .($command->getDescription() ? $command->getDescription().\"\\n\\n\" : '')\n                .'### Usage'.\"\\n\\n\"\n                .array_reduce($command->getAliases(), function ($carry, $usage) {\n                    return $carry.'* `'.$usage.'`'.\"\\n\";\n                })\n            );\n\n            return;\n        }\n\n        $command->mergeApplicationDefinition(false);\n\n        $this->write(\n            '`'.$command->getName().\"`\\n\"\n            .str_repeat('-', Helper::width($command->getName()) + 2).\"\\n\\n\"\n            .($command->getDescription() ? $command->getDescription().\"\\n\\n\" : '')\n            .'### Usage'.\"\\n\\n\"\n            .array_reduce(array_merge([$command->getSynopsis()], $command->getAliases(), $command->getUsages()), function ($carry, $usage) {\n                return $carry.'* `'.$usage.'`'.\"\\n\";\n            })\n        );\n\n        if ($help = $command->getProcessedHelp()) {\n            $this->write(\"\\n\");\n            $this->write($help);\n        }\n\n        $definition = $command->getDefinition();\n        if ($definition->getOptions() || $definition->getArguments()) {\n            $this->write(\"\\n\\n\");\n            $this->describeInputDefinition($definition);\n        }\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    protected function describeApplication(Application $application, array $options = [])\n    {\n        $describedNamespace = $options['namespace'] ?? null;\n        $description = new ApplicationDescription($application, $describedNamespace);\n        $title = $this->getApplicationTitle($application);\n\n        $this->write($title.\"\\n\".str_repeat('=', Helper::width($title)));\n\n        foreach ($description->getNamespaces() as $namespace) {\n            if (ApplicationDescription::GLOBAL_NAMESPACE !== $namespace['id']) {\n                $this->write(\"\\n\\n\");\n                $this->write('**'.$namespace['id'].':**');\n            }\n\n            $this->write(\"\\n\\n\");\n            $this->write(implode(\"\\n\", array_map(function ($commandName) use ($description) {\n                return sprintf('* [`%s`](#%s)', $commandName, str_replace(':', '', $description->getCommand($commandName)->getName()));\n            }, $namespace['commands'])));\n        }\n\n        foreach ($description->getCommands() as $command) {\n            $this->write(\"\\n\\n\");\n            if (null !== $describeCommand = $this->describeCommand($command, $options)) {\n                $this->write($describeCommand);\n            }\n        }\n    }\n\n    private function getApplicationTitle(Application $application): string\n    {\n        if ('UNKNOWN' !== $application->getName()) {\n            if ('UNKNOWN' !== $application->getVersion()) {\n                return sprintf('%s %s', $application->getName(), $application->getVersion());\n            }\n\n            return $application->getName();\n        }\n\n        return 'Console Tool';\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Descriptor/TextDescriptor.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Descriptor;\n\nuse Symfony\\Component\\Console\\Application;\nuse Symfony\\Component\\Console\\Command\\Command;\nuse Symfony\\Component\\Console\\Formatter\\OutputFormatter;\nuse Symfony\\Component\\Console\\Helper\\Helper;\nuse Symfony\\Component\\Console\\Input\\InputArgument;\nuse Symfony\\Component\\Console\\Input\\InputDefinition;\nuse Symfony\\Component\\Console\\Input\\InputOption;\n\n/**\n * Text descriptor.\n *\n * @author Jean-François Simon <contact@jfsimon.fr>\n *\n * @internal\n */\nclass TextDescriptor extends Descriptor\n{\n    /**\n     * {@inheritdoc}\n     */\n    protected function describeInputArgument(InputArgument $argument, array $options = [])\n    {\n        if (null !== $argument->getDefault() && (!\\is_array($argument->getDefault()) || \\count($argument->getDefault()))) {\n            $default = sprintf('<comment> [default: %s]</comment>', $this->formatDefaultValue($argument->getDefault()));\n        } else {\n            $default = '';\n        }\n\n        $totalWidth = $options['total_width'] ?? Helper::width($argument->getName());\n        $spacingWidth = $totalWidth - \\strlen($argument->getName());\n\n        $this->writeText(sprintf('  <info>%s</info>  %s%s%s',\n            $argument->getName(),\n            str_repeat(' ', $spacingWidth),\n            // + 4 = 2 spaces before <info>, 2 spaces after </info>\n            preg_replace('/\\s*[\\r\\n]\\s*/', \"\\n\".str_repeat(' ', $totalWidth + 4), $argument->getDescription()),\n            $default\n        ), $options);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    protected function describeInputOption(InputOption $option, array $options = [])\n    {\n        if ($option->acceptValue() && null !== $option->getDefault() && (!\\is_array($option->getDefault()) || \\count($option->getDefault()))) {\n            $default = sprintf('<comment> [default: %s]</comment>', $this->formatDefaultValue($option->getDefault()));\n        } else {\n            $default = '';\n        }\n\n        $value = '';\n        if ($option->acceptValue()) {\n            $value = '='.strtoupper($option->getName());\n\n            if ($option->isValueOptional()) {\n                $value = '['.$value.']';\n            }\n        }\n\n        $totalWidth = $options['total_width'] ?? $this->calculateTotalWidthForOptions([$option]);\n        $synopsis = sprintf('%s%s',\n            $option->getShortcut() ? sprintf('-%s, ', $option->getShortcut()) : '    ',\n            sprintf($option->isNegatable() ? '--%1$s|--no-%1$s' : '--%1$s%2$s', $option->getName(), $value)\n        );\n\n        $spacingWidth = $totalWidth - Helper::width($synopsis);\n\n        $this->writeText(sprintf('  <info>%s</info>  %s%s%s%s',\n            $synopsis,\n            str_repeat(' ', $spacingWidth),\n            // + 4 = 2 spaces before <info>, 2 spaces after </info>\n            preg_replace('/\\s*[\\r\\n]\\s*/', \"\\n\".str_repeat(' ', $totalWidth + 4), $option->getDescription()),\n            $default,\n            $option->isArray() ? '<comment> (multiple values allowed)</comment>' : ''\n        ), $options);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    protected function describeInputDefinition(InputDefinition $definition, array $options = [])\n    {\n        $totalWidth = $this->calculateTotalWidthForOptions($definition->getOptions());\n        foreach ($definition->getArguments() as $argument) {\n            $totalWidth = max($totalWidth, Helper::width($argument->getName()));\n        }\n\n        if ($definition->getArguments()) {\n            $this->writeText('<comment>Arguments:</comment>', $options);\n            $this->writeText(\"\\n\");\n            foreach ($definition->getArguments() as $argument) {\n                $this->describeInputArgument($argument, array_merge($options, ['total_width' => $totalWidth]));\n                $this->writeText(\"\\n\");\n            }\n        }\n\n        if ($definition->getArguments() && $definition->getOptions()) {\n            $this->writeText(\"\\n\");\n        }\n\n        if ($definition->getOptions()) {\n            $laterOptions = [];\n\n            $this->writeText('<comment>Options:</comment>', $options);\n            foreach ($definition->getOptions() as $option) {\n                if (\\strlen($option->getShortcut() ?? '') > 1) {\n                    $laterOptions[] = $option;\n                    continue;\n                }\n                $this->writeText(\"\\n\");\n                $this->describeInputOption($option, array_merge($options, ['total_width' => $totalWidth]));\n            }\n            foreach ($laterOptions as $option) {\n                $this->writeText(\"\\n\");\n                $this->describeInputOption($option, array_merge($options, ['total_width' => $totalWidth]));\n            }\n        }\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    protected function describeCommand(Command $command, array $options = [])\n    {\n        $command->mergeApplicationDefinition(false);\n\n        if ($description = $command->getDescription()) {\n            $this->writeText('<comment>Description:</comment>', $options);\n            $this->writeText(\"\\n\");\n            $this->writeText('  '.$description);\n            $this->writeText(\"\\n\\n\");\n        }\n\n        $this->writeText('<comment>Usage:</comment>', $options);\n        foreach (array_merge([$command->getSynopsis(true)], $command->getAliases(), $command->getUsages()) as $usage) {\n            $this->writeText(\"\\n\");\n            $this->writeText('  '.OutputFormatter::escape($usage), $options);\n        }\n        $this->writeText(\"\\n\");\n\n        $definition = $command->getDefinition();\n        if ($definition->getOptions() || $definition->getArguments()) {\n            $this->writeText(\"\\n\");\n            $this->describeInputDefinition($definition, $options);\n            $this->writeText(\"\\n\");\n        }\n\n        $help = $command->getProcessedHelp();\n        if ($help && $help !== $description) {\n            $this->writeText(\"\\n\");\n            $this->writeText('<comment>Help:</comment>', $options);\n            $this->writeText(\"\\n\");\n            $this->writeText('  '.str_replace(\"\\n\", \"\\n  \", $help), $options);\n            $this->writeText(\"\\n\");\n        }\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    protected function describeApplication(Application $application, array $options = [])\n    {\n        $describedNamespace = $options['namespace'] ?? null;\n        $description = new ApplicationDescription($application, $describedNamespace);\n\n        if (isset($options['raw_text']) && $options['raw_text']) {\n            $width = $this->getColumnWidth($description->getCommands());\n\n            foreach ($description->getCommands() as $command) {\n                $this->writeText(sprintf(\"%-{$width}s %s\", $command->getName(), $command->getDescription()), $options);\n                $this->writeText(\"\\n\");\n            }\n        } else {\n            if ('' != $help = $application->getHelp()) {\n                $this->writeText(\"$help\\n\\n\", $options);\n            }\n\n            $this->writeText(\"<comment>Usage:</comment>\\n\", $options);\n            $this->writeText(\"  command [options] [arguments]\\n\\n\", $options);\n\n            $this->describeInputDefinition(new InputDefinition($application->getDefinition()->getOptions()), $options);\n\n            $this->writeText(\"\\n\");\n            $this->writeText(\"\\n\");\n\n            $commands = $description->getCommands();\n            $namespaces = $description->getNamespaces();\n            if ($describedNamespace && $namespaces) {\n                // make sure all alias commands are included when describing a specific namespace\n                $describedNamespaceInfo = reset($namespaces);\n                foreach ($describedNamespaceInfo['commands'] as $name) {\n                    $commands[$name] = $description->getCommand($name);\n                }\n            }\n\n            // calculate max. width based on available commands per namespace\n            $width = $this->getColumnWidth(array_merge(...array_values(array_map(function ($namespace) use ($commands) {\n                return array_intersect($namespace['commands'], array_keys($commands));\n            }, array_values($namespaces)))));\n\n            if ($describedNamespace) {\n                $this->writeText(sprintf('<comment>Available commands for the \"%s\" namespace:</comment>', $describedNamespace), $options);\n            } else {\n                $this->writeText('<comment>Available commands:</comment>', $options);\n            }\n\n            foreach ($namespaces as $namespace) {\n                $namespace['commands'] = array_filter($namespace['commands'], function ($name) use ($commands) {\n                    return isset($commands[$name]);\n                });\n\n                if (!$namespace['commands']) {\n                    continue;\n                }\n\n                if (!$describedNamespace && ApplicationDescription::GLOBAL_NAMESPACE !== $namespace['id']) {\n                    $this->writeText(\"\\n\");\n                    $this->writeText(' <comment>'.$namespace['id'].'</comment>', $options);\n                }\n\n                foreach ($namespace['commands'] as $name) {\n                    $this->writeText(\"\\n\");\n                    $spacingWidth = $width - Helper::width($name);\n                    $command = $commands[$name];\n                    $commandAliases = $name === $command->getName() ? $this->getCommandAliasesText($command) : '';\n                    $this->writeText(sprintf('  <info>%s</info>%s%s', $name, str_repeat(' ', $spacingWidth), $commandAliases.$command->getDescription()), $options);\n                }\n            }\n\n            $this->writeText(\"\\n\");\n        }\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    private function writeText(string $content, array $options = [])\n    {\n        $this->write(\n            isset($options['raw_text']) && $options['raw_text'] ? strip_tags($content) : $content,\n            isset($options['raw_output']) ? !$options['raw_output'] : true\n        );\n    }\n\n    /**\n     * Formats command aliases to show them in the command description.\n     */\n    private function getCommandAliasesText(Command $command): string\n    {\n        $text = '';\n        $aliases = $command->getAliases();\n\n        if ($aliases) {\n            $text = '['.implode('|', $aliases).'] ';\n        }\n\n        return $text;\n    }\n\n    /**\n     * Formats input option/argument default value.\n     *\n     * @param mixed $default\n     */\n    private function formatDefaultValue($default): string\n    {\n        if (\\INF === $default) {\n            return 'INF';\n        }\n\n        if (\\is_string($default)) {\n            $default = OutputFormatter::escape($default);\n        } elseif (\\is_array($default)) {\n            foreach ($default as $key => $value) {\n                if (\\is_string($value)) {\n                    $default[$key] = OutputFormatter::escape($value);\n                }\n            }\n        }\n\n        return str_replace('\\\\\\\\', '\\\\', json_encode($default, \\JSON_UNESCAPED_SLASHES | \\JSON_UNESCAPED_UNICODE));\n    }\n\n    /**\n     * @param array<Command|string> $commands\n     */\n    private function getColumnWidth(array $commands): int\n    {\n        $widths = [];\n\n        foreach ($commands as $command) {\n            if ($command instanceof Command) {\n                $widths[] = Helper::width($command->getName());\n                foreach ($command->getAliases() as $alias) {\n                    $widths[] = Helper::width($alias);\n                }\n            } else {\n                $widths[] = Helper::width($command);\n            }\n        }\n\n        return $widths ? max($widths) + 2 : 0;\n    }\n\n    /**\n     * @param InputOption[] $options\n     */\n    private function calculateTotalWidthForOptions(array $options): int\n    {\n        $totalWidth = 0;\n        foreach ($options as $option) {\n            // \"-\" + shortcut + \", --\" + name\n            $nameLength = 1 + max(Helper::width($option->getShortcut()), 1) + 4 + Helper::width($option->getName());\n            if ($option->isNegatable()) {\n                $nameLength += 6 + Helper::width($option->getName()); // |--no- + name\n            } elseif ($option->acceptValue()) {\n                $valueLength = 1 + Helper::width($option->getName()); // = + value\n                $valueLength += $option->isValueOptional() ? 2 : 0; // [ + ]\n\n                $nameLength += $valueLength;\n            }\n            $totalWidth = max($totalWidth, $nameLength);\n        }\n\n        return $totalWidth;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Descriptor/XmlDescriptor.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Descriptor;\n\nuse Symfony\\Component\\Console\\Application;\nuse Symfony\\Component\\Console\\Command\\Command;\nuse Symfony\\Component\\Console\\Input\\InputArgument;\nuse Symfony\\Component\\Console\\Input\\InputDefinition;\nuse Symfony\\Component\\Console\\Input\\InputOption;\n\n/**\n * XML descriptor.\n *\n * @author Jean-François Simon <contact@jfsimon.fr>\n *\n * @internal\n */\nclass XmlDescriptor extends Descriptor\n{\n    public function getInputDefinitionDocument(InputDefinition $definition): \\DOMDocument\n    {\n        $dom = new \\DOMDocument('1.0', 'UTF-8');\n        $dom->appendChild($definitionXML = $dom->createElement('definition'));\n\n        $definitionXML->appendChild($argumentsXML = $dom->createElement('arguments'));\n        foreach ($definition->getArguments() as $argument) {\n            $this->appendDocument($argumentsXML, $this->getInputArgumentDocument($argument));\n        }\n\n        $definitionXML->appendChild($optionsXML = $dom->createElement('options'));\n        foreach ($definition->getOptions() as $option) {\n            $this->appendDocument($optionsXML, $this->getInputOptionDocument($option));\n        }\n\n        return $dom;\n    }\n\n    public function getCommandDocument(Command $command, bool $short = false): \\DOMDocument\n    {\n        $dom = new \\DOMDocument('1.0', 'UTF-8');\n        $dom->appendChild($commandXML = $dom->createElement('command'));\n\n        $commandXML->setAttribute('id', $command->getName());\n        $commandXML->setAttribute('name', $command->getName());\n        $commandXML->setAttribute('hidden', $command->isHidden() ? 1 : 0);\n\n        $commandXML->appendChild($usagesXML = $dom->createElement('usages'));\n\n        $commandXML->appendChild($descriptionXML = $dom->createElement('description'));\n        $descriptionXML->appendChild($dom->createTextNode(str_replace(\"\\n\", \"\\n \", $command->getDescription())));\n\n        if ($short) {\n            foreach ($command->getAliases() as $usage) {\n                $usagesXML->appendChild($dom->createElement('usage', $usage));\n            }\n        } else {\n            $command->mergeApplicationDefinition(false);\n\n            foreach (array_merge([$command->getSynopsis()], $command->getAliases(), $command->getUsages()) as $usage) {\n                $usagesXML->appendChild($dom->createElement('usage', $usage));\n            }\n\n            $commandXML->appendChild($helpXML = $dom->createElement('help'));\n            $helpXML->appendChild($dom->createTextNode(str_replace(\"\\n\", \"\\n \", $command->getProcessedHelp())));\n\n            $definitionXML = $this->getInputDefinitionDocument($command->getDefinition());\n            $this->appendDocument($commandXML, $definitionXML->getElementsByTagName('definition')->item(0));\n        }\n\n        return $dom;\n    }\n\n    public function getApplicationDocument(Application $application, ?string $namespace = null, bool $short = false): \\DOMDocument\n    {\n        $dom = new \\DOMDocument('1.0', 'UTF-8');\n        $dom->appendChild($rootXml = $dom->createElement('symfony'));\n\n        if ('UNKNOWN' !== $application->getName()) {\n            $rootXml->setAttribute('name', $application->getName());\n            if ('UNKNOWN' !== $application->getVersion()) {\n                $rootXml->setAttribute('version', $application->getVersion());\n            }\n        }\n\n        $rootXml->appendChild($commandsXML = $dom->createElement('commands'));\n\n        $description = new ApplicationDescription($application, $namespace, true);\n\n        if ($namespace) {\n            $commandsXML->setAttribute('namespace', $namespace);\n        }\n\n        foreach ($description->getCommands() as $command) {\n            $this->appendDocument($commandsXML, $this->getCommandDocument($command, $short));\n        }\n\n        if (!$namespace) {\n            $rootXml->appendChild($namespacesXML = $dom->createElement('namespaces'));\n\n            foreach ($description->getNamespaces() as $namespaceDescription) {\n                $namespacesXML->appendChild($namespaceArrayXML = $dom->createElement('namespace'));\n                $namespaceArrayXML->setAttribute('id', $namespaceDescription['id']);\n\n                foreach ($namespaceDescription['commands'] as $name) {\n                    $namespaceArrayXML->appendChild($commandXML = $dom->createElement('command'));\n                    $commandXML->appendChild($dom->createTextNode($name));\n                }\n            }\n        }\n\n        return $dom;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    protected function describeInputArgument(InputArgument $argument, array $options = [])\n    {\n        $this->writeDocument($this->getInputArgumentDocument($argument));\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    protected function describeInputOption(InputOption $option, array $options = [])\n    {\n        $this->writeDocument($this->getInputOptionDocument($option));\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    protected function describeInputDefinition(InputDefinition $definition, array $options = [])\n    {\n        $this->writeDocument($this->getInputDefinitionDocument($definition));\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    protected function describeCommand(Command $command, array $options = [])\n    {\n        $this->writeDocument($this->getCommandDocument($command, $options['short'] ?? false));\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    protected function describeApplication(Application $application, array $options = [])\n    {\n        $this->writeDocument($this->getApplicationDocument($application, $options['namespace'] ?? null, $options['short'] ?? false));\n    }\n\n    /**\n     * Appends document children to parent node.\n     */\n    private function appendDocument(\\DOMNode $parentNode, \\DOMNode $importedParent)\n    {\n        foreach ($importedParent->childNodes as $childNode) {\n            $parentNode->appendChild($parentNode->ownerDocument->importNode($childNode, true));\n        }\n    }\n\n    /**\n     * Writes DOM document.\n     */\n    private function writeDocument(\\DOMDocument $dom)\n    {\n        $dom->formatOutput = true;\n        $this->write($dom->saveXML());\n    }\n\n    private function getInputArgumentDocument(InputArgument $argument): \\DOMDocument\n    {\n        $dom = new \\DOMDocument('1.0', 'UTF-8');\n\n        $dom->appendChild($objectXML = $dom->createElement('argument'));\n        $objectXML->setAttribute('name', $argument->getName());\n        $objectXML->setAttribute('is_required', $argument->isRequired() ? 1 : 0);\n        $objectXML->setAttribute('is_array', $argument->isArray() ? 1 : 0);\n        $objectXML->appendChild($descriptionXML = $dom->createElement('description'));\n        $descriptionXML->appendChild($dom->createTextNode($argument->getDescription()));\n\n        $objectXML->appendChild($defaultsXML = $dom->createElement('defaults'));\n        $defaults = \\is_array($argument->getDefault()) ? $argument->getDefault() : (\\is_bool($argument->getDefault()) ? [var_export($argument->getDefault(), true)] : ($argument->getDefault() ? [$argument->getDefault()] : []));\n        foreach ($defaults as $default) {\n            $defaultsXML->appendChild($defaultXML = $dom->createElement('default'));\n            $defaultXML->appendChild($dom->createTextNode($default));\n        }\n\n        return $dom;\n    }\n\n    private function getInputOptionDocument(InputOption $option): \\DOMDocument\n    {\n        $dom = new \\DOMDocument('1.0', 'UTF-8');\n\n        $dom->appendChild($objectXML = $dom->createElement('option'));\n        $objectXML->setAttribute('name', '--'.$option->getName());\n        $pos = strpos($option->getShortcut() ?? '', '|');\n        if (false !== $pos) {\n            $objectXML->setAttribute('shortcut', '-'.substr($option->getShortcut(), 0, $pos));\n            $objectXML->setAttribute('shortcuts', '-'.str_replace('|', '|-', $option->getShortcut()));\n        } else {\n            $objectXML->setAttribute('shortcut', $option->getShortcut() ? '-'.$option->getShortcut() : '');\n        }\n        $objectXML->setAttribute('accept_value', $option->acceptValue() ? 1 : 0);\n        $objectXML->setAttribute('is_value_required', $option->isValueRequired() ? 1 : 0);\n        $objectXML->setAttribute('is_multiple', $option->isArray() ? 1 : 0);\n        $objectXML->appendChild($descriptionXML = $dom->createElement('description'));\n        $descriptionXML->appendChild($dom->createTextNode($option->getDescription()));\n\n        if ($option->acceptValue()) {\n            $defaults = \\is_array($option->getDefault()) ? $option->getDefault() : (\\is_bool($option->getDefault()) ? [var_export($option->getDefault(), true)] : ($option->getDefault() ? [$option->getDefault()] : []));\n            $objectXML->appendChild($defaultsXML = $dom->createElement('defaults'));\n\n            if (!empty($defaults)) {\n                foreach ($defaults as $default) {\n                    $defaultsXML->appendChild($defaultXML = $dom->createElement('default'));\n                    $defaultXML->appendChild($dom->createTextNode($default));\n                }\n            }\n        }\n\n        if ($option->isNegatable()) {\n            $dom->appendChild($objectXML = $dom->createElement('option'));\n            $objectXML->setAttribute('name', '--no-'.$option->getName());\n            $objectXML->setAttribute('shortcut', '');\n            $objectXML->setAttribute('accept_value', 0);\n            $objectXML->setAttribute('is_value_required', 0);\n            $objectXML->setAttribute('is_multiple', 0);\n            $objectXML->appendChild($descriptionXML = $dom->createElement('description'));\n            $descriptionXML->appendChild($dom->createTextNode('Negate the \"--'.$option->getName().'\" option'));\n        }\n\n        return $dom;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Event/ConsoleCommandEvent.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Event;\n\n/**\n * Allows to do things before the command is executed, like skipping the command or executing code before the command is\n * going to be executed.\n *\n * Changing the input arguments will have no effect.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nfinal class ConsoleCommandEvent extends ConsoleEvent\n{\n    /**\n     * The return code for skipped commands, this will also be passed into the terminate event.\n     */\n    public const RETURN_CODE_DISABLED = 113;\n\n    /**\n     * Indicates if the command should be run or skipped.\n     */\n    private $commandShouldRun = true;\n\n    /**\n     * Disables the command, so it won't be run.\n     */\n    public function disableCommand(): bool\n    {\n        return $this->commandShouldRun = false;\n    }\n\n    public function enableCommand(): bool\n    {\n        return $this->commandShouldRun = true;\n    }\n\n    /**\n     * Returns true if the command is runnable, false otherwise.\n     */\n    public function commandShouldRun(): bool\n    {\n        return $this->commandShouldRun;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Event/ConsoleErrorEvent.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Event;\n\nuse Symfony\\Component\\Console\\Command\\Command;\nuse Symfony\\Component\\Console\\Input\\InputInterface;\nuse Symfony\\Component\\Console\\Output\\OutputInterface;\n\n/**\n * Allows to handle throwables thrown while running a command.\n *\n * @author Wouter de Jong <wouter@wouterj.nl>\n */\nfinal class ConsoleErrorEvent extends ConsoleEvent\n{\n    private $error;\n    private $exitCode;\n\n    public function __construct(InputInterface $input, OutputInterface $output, \\Throwable $error, ?Command $command = null)\n    {\n        parent::__construct($command, $input, $output);\n\n        $this->error = $error;\n    }\n\n    public function getError(): \\Throwable\n    {\n        return $this->error;\n    }\n\n    public function setError(\\Throwable $error): void\n    {\n        $this->error = $error;\n    }\n\n    public function setExitCode(int $exitCode): void\n    {\n        $this->exitCode = $exitCode;\n\n        $r = new \\ReflectionProperty($this->error, 'code');\n        $r->setAccessible(true);\n        $r->setValue($this->error, $this->exitCode);\n    }\n\n    public function getExitCode(): int\n    {\n        return $this->exitCode ?? (\\is_int($this->error->getCode()) && 0 !== $this->error->getCode() ? $this->error->getCode() : 1);\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Event/ConsoleEvent.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Event;\n\nuse Symfony\\Component\\Console\\Command\\Command;\nuse Symfony\\Component\\Console\\Input\\InputInterface;\nuse Symfony\\Component\\Console\\Output\\OutputInterface;\nuse Symfony\\Contracts\\EventDispatcher\\Event;\n\n/**\n * Allows to inspect input and output of a command.\n *\n * @author Francesco Levorato <git@flevour.net>\n */\nclass ConsoleEvent extends Event\n{\n    protected $command;\n\n    private $input;\n    private $output;\n\n    public function __construct(?Command $command, InputInterface $input, OutputInterface $output)\n    {\n        $this->command = $command;\n        $this->input = $input;\n        $this->output = $output;\n    }\n\n    /**\n     * Gets the command that is executed.\n     *\n     * @return Command|null\n     */\n    public function getCommand()\n    {\n        return $this->command;\n    }\n\n    /**\n     * Gets the input instance.\n     *\n     * @return InputInterface\n     */\n    public function getInput()\n    {\n        return $this->input;\n    }\n\n    /**\n     * Gets the output instance.\n     *\n     * @return OutputInterface\n     */\n    public function getOutput()\n    {\n        return $this->output;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Event/ConsoleSignalEvent.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Event;\n\nuse Symfony\\Component\\Console\\Command\\Command;\nuse Symfony\\Component\\Console\\Input\\InputInterface;\nuse Symfony\\Component\\Console\\Output\\OutputInterface;\n\n/**\n * @author marie <marie@users.noreply.github.com>\n */\nfinal class ConsoleSignalEvent extends ConsoleEvent\n{\n    private $handlingSignal;\n\n    public function __construct(Command $command, InputInterface $input, OutputInterface $output, int $handlingSignal)\n    {\n        parent::__construct($command, $input, $output);\n        $this->handlingSignal = $handlingSignal;\n    }\n\n    public function getHandlingSignal(): int\n    {\n        return $this->handlingSignal;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Event/ConsoleTerminateEvent.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Event;\n\nuse Symfony\\Component\\Console\\Command\\Command;\nuse Symfony\\Component\\Console\\Input\\InputInterface;\nuse Symfony\\Component\\Console\\Output\\OutputInterface;\n\n/**\n * Allows to manipulate the exit code of a command after its execution.\n *\n * @author Francesco Levorato <git@flevour.net>\n */\nfinal class ConsoleTerminateEvent extends ConsoleEvent\n{\n    private $exitCode;\n\n    public function __construct(Command $command, InputInterface $input, OutputInterface $output, int $exitCode)\n    {\n        parent::__construct($command, $input, $output);\n\n        $this->setExitCode($exitCode);\n    }\n\n    public function setExitCode(int $exitCode): void\n    {\n        $this->exitCode = $exitCode;\n    }\n\n    public function getExitCode(): int\n    {\n        return $this->exitCode;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/EventListener/ErrorListener.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\EventListener;\n\nuse Psr\\Log\\LoggerInterface;\nuse Symfony\\Component\\Console\\ConsoleEvents;\nuse Symfony\\Component\\Console\\Event\\ConsoleErrorEvent;\nuse Symfony\\Component\\Console\\Event\\ConsoleEvent;\nuse Symfony\\Component\\Console\\Event\\ConsoleTerminateEvent;\nuse Symfony\\Component\\EventDispatcher\\EventSubscriberInterface;\n\n/**\n * @author James Halsall <james.t.halsall@googlemail.com>\n * @author Robin Chalas <robin.chalas@gmail.com>\n */\nclass ErrorListener implements EventSubscriberInterface\n{\n    private $logger;\n\n    public function __construct(?LoggerInterface $logger = null)\n    {\n        $this->logger = $logger;\n    }\n\n    public function onConsoleError(ConsoleErrorEvent $event)\n    {\n        if (null === $this->logger) {\n            return;\n        }\n\n        $error = $event->getError();\n\n        if (!$inputString = $this->getInputString($event)) {\n            $this->logger->critical('An error occurred while using the console. Message: \"{message}\"', ['exception' => $error, 'message' => $error->getMessage()]);\n\n            return;\n        }\n\n        $this->logger->critical('Error thrown while running command \"{command}\". Message: \"{message}\"', ['exception' => $error, 'command' => $inputString, 'message' => $error->getMessage()]);\n    }\n\n    public function onConsoleTerminate(ConsoleTerminateEvent $event)\n    {\n        if (null === $this->logger) {\n            return;\n        }\n\n        $exitCode = $event->getExitCode();\n\n        if (0 === $exitCode) {\n            return;\n        }\n\n        if (!$inputString = $this->getInputString($event)) {\n            $this->logger->debug('The console exited with code \"{code}\"', ['code' => $exitCode]);\n\n            return;\n        }\n\n        $this->logger->debug('Command \"{command}\" exited with code \"{code}\"', ['command' => $inputString, 'code' => $exitCode]);\n    }\n\n    public static function getSubscribedEvents()\n    {\n        return [\n            ConsoleEvents::ERROR => ['onConsoleError', -128],\n            ConsoleEvents::TERMINATE => ['onConsoleTerminate', -128],\n        ];\n    }\n\n    private static function getInputString(ConsoleEvent $event): ?string\n    {\n        $commandName = $event->getCommand() ? $event->getCommand()->getName() : null;\n        $input = $event->getInput();\n\n        if (method_exists($input, '__toString')) {\n            if ($commandName) {\n                return str_replace([\"'$commandName'\", \"\\\"$commandName\\\"\"], $commandName, (string) $input);\n            }\n\n            return (string) $input;\n        }\n\n        return $commandName;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Exception/CommandNotFoundException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Exception;\n\n/**\n * Represents an incorrect command name typed in the console.\n *\n * @author Jérôme Tamarelle <jerome@tamarelle.net>\n */\nclass CommandNotFoundException extends \\InvalidArgumentException implements ExceptionInterface\n{\n    private $alternatives;\n\n    /**\n     * @param string          $message      Exception message to throw\n     * @param string[]        $alternatives List of similar defined names\n     * @param int             $code         Exception code\n     * @param \\Throwable|null $previous     Previous exception used for the exception chaining\n     */\n    public function __construct(string $message, array $alternatives = [], int $code = 0, ?\\Throwable $previous = null)\n    {\n        parent::__construct($message, $code, $previous);\n\n        $this->alternatives = $alternatives;\n    }\n\n    /**\n     * @return string[]\n     */\n    public function getAlternatives()\n    {\n        return $this->alternatives;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Exception/ExceptionInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Exception;\n\n/**\n * ExceptionInterface.\n *\n * @author Jérôme Tamarelle <jerome@tamarelle.net>\n */\ninterface ExceptionInterface extends \\Throwable\n{\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Exception/InvalidArgumentException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Exception;\n\n/**\n * @author Jérôme Tamarelle <jerome@tamarelle.net>\n */\nclass InvalidArgumentException extends \\InvalidArgumentException implements ExceptionInterface\n{\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Exception/InvalidOptionException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Exception;\n\n/**\n * Represents an incorrect option name or value typed in the console.\n *\n * @author Jérôme Tamarelle <jerome@tamarelle.net>\n */\nclass InvalidOptionException extends \\InvalidArgumentException implements ExceptionInterface\n{\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Exception/LogicException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Exception;\n\n/**\n * @author Jérôme Tamarelle <jerome@tamarelle.net>\n */\nclass LogicException extends \\LogicException implements ExceptionInterface\n{\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Exception/MissingInputException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Exception;\n\n/**\n * Represents failure to read input from stdin.\n *\n * @author Gabriel Ostrolucký <gabriel.ostrolucky@gmail.com>\n */\nclass MissingInputException extends RuntimeException implements ExceptionInterface\n{\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Exception/NamespaceNotFoundException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Exception;\n\n/**\n * Represents an incorrect namespace typed in the console.\n *\n * @author Pierre du Plessis <pdples@gmail.com>\n */\nclass NamespaceNotFoundException extends CommandNotFoundException\n{\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Exception/RuntimeException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Exception;\n\n/**\n * @author Jérôme Tamarelle <jerome@tamarelle.net>\n */\nclass RuntimeException extends \\RuntimeException implements ExceptionInterface\n{\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Formatter/NullOutputFormatter.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Formatter;\n\n/**\n * @author Tien Xuan Vo <tien.xuan.vo@gmail.com>\n */\nfinal class NullOutputFormatter implements OutputFormatterInterface\n{\n    private $style;\n\n    /**\n     * {@inheritdoc}\n     */\n    public function format(?string $message): ?string\n    {\n        return null;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getStyle(string $name): OutputFormatterStyleInterface\n    {\n        // to comply with the interface we must return a OutputFormatterStyleInterface\n        return $this->style ?? $this->style = new NullOutputFormatterStyle();\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function hasStyle(string $name): bool\n    {\n        return false;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function isDecorated(): bool\n    {\n        return false;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function setDecorated(bool $decorated): void\n    {\n        // do nothing\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function setStyle(string $name, OutputFormatterStyleInterface $style): void\n    {\n        // do nothing\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Formatter/NullOutputFormatterStyle.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Formatter;\n\n/**\n * @author Tien Xuan Vo <tien.xuan.vo@gmail.com>\n */\nfinal class NullOutputFormatterStyle implements OutputFormatterStyleInterface\n{\n    /**\n     * {@inheritdoc}\n     */\n    public function apply(string $text): string\n    {\n        return $text;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function setBackground(?string $color = null): void\n    {\n        // do nothing\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function setForeground(?string $color = null): void\n    {\n        // do nothing\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function setOption(string $option): void\n    {\n        // do nothing\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function setOptions(array $options): void\n    {\n        // do nothing\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function unsetOption(string $option): void\n    {\n        // do nothing\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Formatter/OutputFormatter.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Formatter;\n\nuse Symfony\\Component\\Console\\Exception\\InvalidArgumentException;\n\nuse function Symfony\\Component\\String\\b;\n\n/**\n * Formatter class for console output.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n * @author Roland Franssen <franssen.roland@gmail.com>\n */\nclass OutputFormatter implements WrappableOutputFormatterInterface\n{\n    private $decorated;\n    private $styles = [];\n    private $styleStack;\n\n    public function __clone()\n    {\n        $this->styleStack = clone $this->styleStack;\n        foreach ($this->styles as $key => $value) {\n            $this->styles[$key] = clone $value;\n        }\n    }\n\n    /**\n     * Escapes \"<\" and \">\" special chars in given text.\n     *\n     * @return string\n     */\n    public static function escape(string $text)\n    {\n        $text = preg_replace('/([^\\\\\\\\]|^)([<>])/', '$1\\\\\\\\$2', $text);\n\n        return self::escapeTrailingBackslash($text);\n    }\n\n    /**\n     * Escapes trailing \"\\\" in given text.\n     *\n     * @internal\n     */\n    public static function escapeTrailingBackslash(string $text): string\n    {\n        if (str_ends_with($text, '\\\\')) {\n            $len = \\strlen($text);\n            $text = rtrim($text, '\\\\');\n            $text = str_replace(\"\\0\", '', $text);\n            $text .= str_repeat(\"\\0\", $len - \\strlen($text));\n        }\n\n        return $text;\n    }\n\n    /**\n     * Initializes console output formatter.\n     *\n     * @param OutputFormatterStyleInterface[] $styles Array of \"name => FormatterStyle\" instances\n     */\n    public function __construct(bool $decorated = false, array $styles = [])\n    {\n        $this->decorated = $decorated;\n\n        $this->setStyle('error', new OutputFormatterStyle('white', 'red'));\n        $this->setStyle('info', new OutputFormatterStyle('green'));\n        $this->setStyle('comment', new OutputFormatterStyle('yellow'));\n        $this->setStyle('question', new OutputFormatterStyle('black', 'cyan'));\n\n        foreach ($styles as $name => $style) {\n            $this->setStyle($name, $style);\n        }\n\n        $this->styleStack = new OutputFormatterStyleStack();\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function setDecorated(bool $decorated)\n    {\n        $this->decorated = $decorated;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function isDecorated()\n    {\n        return $this->decorated;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function setStyle(string $name, OutputFormatterStyleInterface $style)\n    {\n        $this->styles[strtolower($name)] = $style;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function hasStyle(string $name)\n    {\n        return isset($this->styles[strtolower($name)]);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getStyle(string $name)\n    {\n        if (!$this->hasStyle($name)) {\n            throw new InvalidArgumentException(sprintf('Undefined style: \"%s\".', $name));\n        }\n\n        return $this->styles[strtolower($name)];\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function format(?string $message)\n    {\n        return $this->formatAndWrap($message, 0);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function formatAndWrap(?string $message, int $width)\n    {\n        if (null === $message) {\n            return '';\n        }\n\n        $offset = 0;\n        $output = '';\n        $openTagRegex = '[a-z](?:[^\\\\\\\\<>]*+ | \\\\\\\\.)*';\n        $closeTagRegex = '[a-z][^<>]*+';\n        $currentLineLength = 0;\n        preg_match_all(\"#<(($openTagRegex) | /($closeTagRegex)?)>#ix\", $message, $matches, \\PREG_OFFSET_CAPTURE);\n        foreach ($matches[0] as $i => $match) {\n            $pos = $match[1];\n            $text = $match[0];\n\n            if (0 != $pos && '\\\\' == $message[$pos - 1]) {\n                continue;\n            }\n\n            // add the text up to the next tag\n            $output .= $this->applyCurrentStyle(substr($message, $offset, $pos - $offset), $output, $width, $currentLineLength);\n            $offset = $pos + \\strlen($text);\n\n            // opening tag?\n            if ($open = '/' != $text[1]) {\n                $tag = $matches[1][$i][0];\n            } else {\n                $tag = $matches[3][$i][0] ?? '';\n            }\n\n            if (!$open && !$tag) {\n                // </>\n                $this->styleStack->pop();\n            } elseif (null === $style = $this->createStyleFromString($tag)) {\n                $output .= $this->applyCurrentStyle($text, $output, $width, $currentLineLength);\n            } elseif ($open) {\n                $this->styleStack->push($style);\n            } else {\n                $this->styleStack->pop($style);\n            }\n        }\n\n        $output .= $this->applyCurrentStyle(substr($message, $offset), $output, $width, $currentLineLength);\n\n        return strtr($output, [\"\\0\" => '\\\\', '\\\\<' => '<', '\\\\>' => '>']);\n    }\n\n    /**\n     * @return OutputFormatterStyleStack\n     */\n    public function getStyleStack()\n    {\n        return $this->styleStack;\n    }\n\n    /**\n     * Tries to create new style instance from string.\n     */\n    private function createStyleFromString(string $string): ?OutputFormatterStyleInterface\n    {\n        if (isset($this->styles[$string])) {\n            return $this->styles[$string];\n        }\n\n        if (!preg_match_all('/([^=]+)=([^;]+)(;|$)/', $string, $matches, \\PREG_SET_ORDER)) {\n            return null;\n        }\n\n        $style = new OutputFormatterStyle();\n        foreach ($matches as $match) {\n            array_shift($match);\n            $match[0] = strtolower($match[0]);\n\n            if ('fg' == $match[0]) {\n                $style->setForeground(strtolower($match[1]));\n            } elseif ('bg' == $match[0]) {\n                $style->setBackground(strtolower($match[1]));\n            } elseif ('href' === $match[0]) {\n                $url = preg_replace('{\\\\\\\\([<>])}', '$1', $match[1]);\n                $style->setHref($url);\n            } elseif ('options' === $match[0]) {\n                preg_match_all('([^,;]+)', strtolower($match[1]), $options);\n                $options = array_shift($options);\n                foreach ($options as $option) {\n                    $style->setOption($option);\n                }\n            } else {\n                return null;\n            }\n        }\n\n        return $style;\n    }\n\n    /**\n     * Applies current style from stack to text, if must be applied.\n     */\n    private function applyCurrentStyle(string $text, string $current, int $width, int &$currentLineLength): string\n    {\n        if ('' === $text) {\n            return '';\n        }\n\n        if (!$width) {\n            return $this->isDecorated() ? $this->styleStack->getCurrent()->apply($text) : $text;\n        }\n\n        if (!$currentLineLength && '' !== $current) {\n            $text = ltrim($text);\n        }\n\n        if ($currentLineLength) {\n            $prefix = substr($text, 0, $i = $width - $currentLineLength).\"\\n\";\n            $text = substr($text, $i);\n        } else {\n            $prefix = '';\n        }\n\n        preg_match('~(\\\\n)$~', $text, $matches);\n        $text = $prefix.$this->addLineBreaks($text, $width);\n        $text = rtrim($text, \"\\n\").($matches[1] ?? '');\n\n        if (!$currentLineLength && '' !== $current && \"\\n\" !== substr($current, -1)) {\n            $text = \"\\n\".$text;\n        }\n\n        $lines = explode(\"\\n\", $text);\n\n        foreach ($lines as $line) {\n            $currentLineLength += \\strlen($line);\n            if ($width <= $currentLineLength) {\n                $currentLineLength = 0;\n            }\n        }\n\n        if ($this->isDecorated()) {\n            foreach ($lines as $i => $line) {\n                $lines[$i] = $this->styleStack->getCurrent()->apply($line);\n            }\n        }\n\n        return implode(\"\\n\", $lines);\n    }\n\n    private function addLineBreaks(string $text, int $width): string\n    {\n        $encoding = mb_detect_encoding($text, null, true) ?: 'UTF-8';\n\n        return b($text)->toCodePointString($encoding)->wordwrap($width, \"\\n\", true)->toByteString($encoding);\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Formatter/OutputFormatterInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Formatter;\n\n/**\n * Formatter interface for console output.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\ninterface OutputFormatterInterface\n{\n    /**\n     * Sets the decorated flag.\n     */\n    public function setDecorated(bool $decorated);\n\n    /**\n     * Whether the output will decorate messages.\n     *\n     * @return bool\n     */\n    public function isDecorated();\n\n    /**\n     * Sets a new style.\n     */\n    public function setStyle(string $name, OutputFormatterStyleInterface $style);\n\n    /**\n     * Checks if output formatter has style with specified name.\n     *\n     * @return bool\n     */\n    public function hasStyle(string $name);\n\n    /**\n     * Gets style options from style with specified name.\n     *\n     * @return OutputFormatterStyleInterface\n     *\n     * @throws \\InvalidArgumentException When style isn't defined\n     */\n    public function getStyle(string $name);\n\n    /**\n     * Formats a message according to the given styles.\n     *\n     * @return string|null\n     */\n    public function format(?string $message);\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Formatter/OutputFormatterStyle.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Formatter;\n\nuse Symfony\\Component\\Console\\Color;\n\n/**\n * Formatter style class for defining styles.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\nclass OutputFormatterStyle implements OutputFormatterStyleInterface\n{\n    private $color;\n    private $foreground;\n    private $background;\n    private $options;\n    private $href;\n    private $handlesHrefGracefully;\n\n    /**\n     * Initializes output formatter style.\n     *\n     * @param string|null $foreground The style foreground color name\n     * @param string|null $background The style background color name\n     */\n    public function __construct(?string $foreground = null, ?string $background = null, array $options = [])\n    {\n        $this->color = new Color($this->foreground = $foreground ?: '', $this->background = $background ?: '', $this->options = $options);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function setForeground(?string $color = null)\n    {\n        $this->color = new Color($this->foreground = $color ?: '', $this->background, $this->options);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function setBackground(?string $color = null)\n    {\n        $this->color = new Color($this->foreground, $this->background = $color ?: '', $this->options);\n    }\n\n    public function setHref(string $url): void\n    {\n        $this->href = $url;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function setOption(string $option)\n    {\n        $this->options[] = $option;\n        $this->color = new Color($this->foreground, $this->background, $this->options);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function unsetOption(string $option)\n    {\n        $pos = array_search($option, $this->options);\n        if (false !== $pos) {\n            unset($this->options[$pos]);\n        }\n\n        $this->color = new Color($this->foreground, $this->background, $this->options);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function setOptions(array $options)\n    {\n        $this->color = new Color($this->foreground, $this->background, $this->options = $options);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function apply(string $text)\n    {\n        if (null === $this->handlesHrefGracefully) {\n            $this->handlesHrefGracefully = 'JetBrains-JediTerm' !== getenv('TERMINAL_EMULATOR')\n                && (!getenv('KONSOLE_VERSION') || (int) getenv('KONSOLE_VERSION') > 201100)\n                && !isset($_SERVER['IDEA_INITIAL_DIRECTORY']);\n        }\n\n        if (null !== $this->href && $this->handlesHrefGracefully) {\n            $text = \"\\033]8;;$this->href\\033\\\\$text\\033]8;;\\033\\\\\";\n        }\n\n        return $this->color->apply($text);\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Formatter/OutputFormatterStyleInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Formatter;\n\n/**\n * Formatter style interface for defining styles.\n *\n * @author Konstantin Kudryashov <ever.zet@gmail.com>\n */\ninterface OutputFormatterStyleInterface\n{\n    /**\n     * Sets style foreground color.\n     */\n    public function setForeground(?string $color = null);\n\n    /**\n     * Sets style background color.\n     */\n    public function setBackground(?string $color = null);\n\n    /**\n     * Sets some specific style option.\n     */\n    public function setOption(string $option);\n\n    /**\n     * Unsets some specific style option.\n     */\n    public function unsetOption(string $option);\n\n    /**\n     * Sets multiple style options at once.\n     */\n    public function setOptions(array $options);\n\n    /**\n     * Applies the style to a given text.\n     *\n     * @return string\n     */\n    public function apply(string $text);\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Formatter/OutputFormatterStyleStack.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Formatter;\n\nuse Symfony\\Component\\Console\\Exception\\InvalidArgumentException;\nuse Symfony\\Contracts\\Service\\ResetInterface;\n\n/**\n * @author Jean-François Simon <contact@jfsimon.fr>\n */\nclass OutputFormatterStyleStack implements ResetInterface\n{\n    /**\n     * @var OutputFormatterStyleInterface[]\n     */\n    private $styles;\n\n    private $emptyStyle;\n\n    public function __construct(?OutputFormatterStyleInterface $emptyStyle = null)\n    {\n        $this->emptyStyle = $emptyStyle ?? new OutputFormatterStyle();\n        $this->reset();\n    }\n\n    /**\n     * Resets stack (ie. empty internal arrays).\n     */\n    public function reset()\n    {\n        $this->styles = [];\n    }\n\n    /**\n     * Pushes a style in the stack.\n     */\n    public function push(OutputFormatterStyleInterface $style)\n    {\n        $this->styles[] = $style;\n    }\n\n    /**\n     * Pops a style from the stack.\n     *\n     * @return OutputFormatterStyleInterface\n     *\n     * @throws InvalidArgumentException When style tags incorrectly nested\n     */\n    public function pop(?OutputFormatterStyleInterface $style = null)\n    {\n        if (empty($this->styles)) {\n            return $this->emptyStyle;\n        }\n\n        if (null === $style) {\n            return array_pop($this->styles);\n        }\n\n        foreach (array_reverse($this->styles, true) as $index => $stackedStyle) {\n            if ($style->apply('') === $stackedStyle->apply('')) {\n                $this->styles = \\array_slice($this->styles, 0, $index);\n\n                return $stackedStyle;\n            }\n        }\n\n        throw new InvalidArgumentException('Incorrectly nested style tag found.');\n    }\n\n    /**\n     * Computes current style with stacks top codes.\n     *\n     * @return OutputFormatterStyle\n     */\n    public function getCurrent()\n    {\n        if (empty($this->styles)) {\n            return $this->emptyStyle;\n        }\n\n        return $this->styles[\\count($this->styles) - 1];\n    }\n\n    /**\n     * @return $this\n     */\n    public function setEmptyStyle(OutputFormatterStyleInterface $emptyStyle)\n    {\n        $this->emptyStyle = $emptyStyle;\n\n        return $this;\n    }\n\n    /**\n     * @return OutputFormatterStyleInterface\n     */\n    public function getEmptyStyle()\n    {\n        return $this->emptyStyle;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Formatter/WrappableOutputFormatterInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Formatter;\n\n/**\n * Formatter interface for console output that supports word wrapping.\n *\n * @author Roland Franssen <franssen.roland@gmail.com>\n */\ninterface WrappableOutputFormatterInterface extends OutputFormatterInterface\n{\n    /**\n     * Formats a message according to the given styles, wrapping at `$width` (0 means no wrapping).\n     */\n    public function formatAndWrap(?string $message, int $width);\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Helper/DebugFormatterHelper.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Helper;\n\n/**\n * Helps outputting debug information when running an external program from a command.\n *\n * An external program can be a Process, an HTTP request, or anything else.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass DebugFormatterHelper extends Helper\n{\n    private const COLORS = ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white', 'default'];\n    private $started = [];\n    private $count = -1;\n\n    /**\n     * Starts a debug formatting session.\n     *\n     * @return string\n     */\n    public function start(string $id, string $message, string $prefix = 'RUN')\n    {\n        $this->started[$id] = ['border' => ++$this->count % \\count(self::COLORS)];\n\n        return sprintf(\"%s<bg=blue;fg=white> %s </> <fg=blue>%s</>\\n\", $this->getBorder($id), $prefix, $message);\n    }\n\n    /**\n     * Adds progress to a formatting session.\n     *\n     * @return string\n     */\n    public function progress(string $id, string $buffer, bool $error = false, string $prefix = 'OUT', string $errorPrefix = 'ERR')\n    {\n        $message = '';\n\n        if ($error) {\n            if (isset($this->started[$id]['out'])) {\n                $message .= \"\\n\";\n                unset($this->started[$id]['out']);\n            }\n            if (!isset($this->started[$id]['err'])) {\n                $message .= sprintf('%s<bg=red;fg=white> %s </> ', $this->getBorder($id), $errorPrefix);\n                $this->started[$id]['err'] = true;\n            }\n\n            $message .= str_replace(\"\\n\", sprintf(\"\\n%s<bg=red;fg=white> %s </> \", $this->getBorder($id), $errorPrefix), $buffer);\n        } else {\n            if (isset($this->started[$id]['err'])) {\n                $message .= \"\\n\";\n                unset($this->started[$id]['err']);\n            }\n            if (!isset($this->started[$id]['out'])) {\n                $message .= sprintf('%s<bg=green;fg=white> %s </> ', $this->getBorder($id), $prefix);\n                $this->started[$id]['out'] = true;\n            }\n\n            $message .= str_replace(\"\\n\", sprintf(\"\\n%s<bg=green;fg=white> %s </> \", $this->getBorder($id), $prefix), $buffer);\n        }\n\n        return $message;\n    }\n\n    /**\n     * Stops a formatting session.\n     *\n     * @return string\n     */\n    public function stop(string $id, string $message, bool $successful, string $prefix = 'RES')\n    {\n        $trailingEOL = isset($this->started[$id]['out']) || isset($this->started[$id]['err']) ? \"\\n\" : '';\n\n        if ($successful) {\n            return sprintf(\"%s%s<bg=green;fg=white> %s </> <fg=green>%s</>\\n\", $trailingEOL, $this->getBorder($id), $prefix, $message);\n        }\n\n        $message = sprintf(\"%s%s<bg=red;fg=white> %s </> <fg=red>%s</>\\n\", $trailingEOL, $this->getBorder($id), $prefix, $message);\n\n        unset($this->started[$id]['out'], $this->started[$id]['err']);\n\n        return $message;\n    }\n\n    private function getBorder(string $id): string\n    {\n        return sprintf('<bg=%s> </>', self::COLORS[$this->started[$id]['border']]);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getName()\n    {\n        return 'debug_formatter';\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Helper/DescriptorHelper.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Helper;\n\nuse Symfony\\Component\\Console\\Descriptor\\DescriptorInterface;\nuse Symfony\\Component\\Console\\Descriptor\\JsonDescriptor;\nuse Symfony\\Component\\Console\\Descriptor\\MarkdownDescriptor;\nuse Symfony\\Component\\Console\\Descriptor\\TextDescriptor;\nuse Symfony\\Component\\Console\\Descriptor\\XmlDescriptor;\nuse Symfony\\Component\\Console\\Exception\\InvalidArgumentException;\nuse Symfony\\Component\\Console\\Output\\OutputInterface;\n\n/**\n * This class adds helper method to describe objects in various formats.\n *\n * @author Jean-François Simon <contact@jfsimon.fr>\n */\nclass DescriptorHelper extends Helper\n{\n    /**\n     * @var DescriptorInterface[]\n     */\n    private $descriptors = [];\n\n    public function __construct()\n    {\n        $this\n            ->register('txt', new TextDescriptor())\n            ->register('xml', new XmlDescriptor())\n            ->register('json', new JsonDescriptor())\n            ->register('md', new MarkdownDescriptor())\n        ;\n    }\n\n    /**\n     * Describes an object if supported.\n     *\n     * Available options are:\n     * * format: string, the output format name\n     * * raw_text: boolean, sets output type as raw\n     *\n     * @throws InvalidArgumentException when the given format is not supported\n     */\n    public function describe(OutputInterface $output, ?object $object, array $options = [])\n    {\n        $options = array_merge([\n            'raw_text' => false,\n            'format' => 'txt',\n        ], $options);\n\n        if (!isset($this->descriptors[$options['format']])) {\n            throw new InvalidArgumentException(sprintf('Unsupported format \"%s\".', $options['format']));\n        }\n\n        $descriptor = $this->descriptors[$options['format']];\n        $descriptor->describe($output, $object, $options);\n    }\n\n    /**\n     * Registers a descriptor.\n     *\n     * @return $this\n     */\n    public function register(string $format, DescriptorInterface $descriptor)\n    {\n        $this->descriptors[$format] = $descriptor;\n\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getName()\n    {\n        return 'descriptor';\n    }\n\n    public function getFormats(): array\n    {\n        return array_keys($this->descriptors);\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Helper/Dumper.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Helper;\n\nuse Symfony\\Component\\Console\\Output\\OutputInterface;\nuse Symfony\\Component\\VarDumper\\Cloner\\ClonerInterface;\nuse Symfony\\Component\\VarDumper\\Cloner\\VarCloner;\nuse Symfony\\Component\\VarDumper\\Dumper\\CliDumper;\n\n/**\n * @author Roland Franssen <franssen.roland@gmail.com>\n */\nfinal class Dumper\n{\n    private $output;\n    private $dumper;\n    private $cloner;\n    private $handler;\n\n    public function __construct(OutputInterface $output, ?CliDumper $dumper = null, ?ClonerInterface $cloner = null)\n    {\n        $this->output = $output;\n        $this->dumper = $dumper;\n        $this->cloner = $cloner;\n\n        if (class_exists(CliDumper::class)) {\n            $this->handler = function ($var): string {\n                $dumper = $this->dumper ?? $this->dumper = new CliDumper(null, null, CliDumper::DUMP_LIGHT_ARRAY | CliDumper::DUMP_COMMA_SEPARATOR);\n                $dumper->setColors($this->output->isDecorated());\n\n                return rtrim($dumper->dump(($this->cloner ?? $this->cloner = new VarCloner())->cloneVar($var)->withRefHandles(false), true));\n            };\n        } else {\n            $this->handler = function ($var): string {\n                switch (true) {\n                    case null === $var:\n                        return 'null';\n                    case true === $var:\n                        return 'true';\n                    case false === $var:\n                        return 'false';\n                    case \\is_string($var):\n                        return '\"'.$var.'\"';\n                    default:\n                        return rtrim(print_r($var, true));\n                }\n            };\n        }\n    }\n\n    public function __invoke($var): string\n    {\n        return ($this->handler)($var);\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Helper/FormatterHelper.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Helper;\n\nuse Symfony\\Component\\Console\\Formatter\\OutputFormatter;\n\n/**\n * The Formatter class provides helpers to format messages.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass FormatterHelper extends Helper\n{\n    /**\n     * Formats a message within a section.\n     *\n     * @return string\n     */\n    public function formatSection(string $section, string $message, string $style = 'info')\n    {\n        return sprintf('<%s>[%s]</%s> %s', $style, $section, $style, $message);\n    }\n\n    /**\n     * Formats a message as a block of text.\n     *\n     * @param string|array $messages The message to write in the block\n     *\n     * @return string\n     */\n    public function formatBlock($messages, string $style, bool $large = false)\n    {\n        if (!\\is_array($messages)) {\n            $messages = [$messages];\n        }\n\n        $len = 0;\n        $lines = [];\n        foreach ($messages as $message) {\n            $message = OutputFormatter::escape($message);\n            $lines[] = sprintf($large ? '  %s  ' : ' %s ', $message);\n            $len = max(self::width($message) + ($large ? 4 : 2), $len);\n        }\n\n        $messages = $large ? [str_repeat(' ', $len)] : [];\n        for ($i = 0; isset($lines[$i]); ++$i) {\n            $messages[] = $lines[$i].str_repeat(' ', $len - self::width($lines[$i]));\n        }\n        if ($large) {\n            $messages[] = str_repeat(' ', $len);\n        }\n\n        for ($i = 0; isset($messages[$i]); ++$i) {\n            $messages[$i] = sprintf('<%s>%s</%s>', $style, $messages[$i], $style);\n        }\n\n        return implode(\"\\n\", $messages);\n    }\n\n    /**\n     * Truncates a message to the given length.\n     *\n     * @return string\n     */\n    public function truncate(string $message, int $length, string $suffix = '...')\n    {\n        $computedLength = $length - self::width($suffix);\n\n        if ($computedLength > self::width($message)) {\n            return $message;\n        }\n\n        return self::substr($message, 0, $length).$suffix;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getName()\n    {\n        return 'formatter';\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Helper/Helper.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Helper;\n\nuse Symfony\\Component\\Console\\Formatter\\OutputFormatterInterface;\nuse Symfony\\Component\\String\\UnicodeString;\n\n/**\n * Helper is the base class for all helper classes.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nabstract class Helper implements HelperInterface\n{\n    protected $helperSet = null;\n\n    /**\n     * {@inheritdoc}\n     */\n    public function setHelperSet(?HelperSet $helperSet = null)\n    {\n        $this->helperSet = $helperSet;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getHelperSet()\n    {\n        return $this->helperSet;\n    }\n\n    /**\n     * Returns the length of a string, using mb_strwidth if it is available.\n     *\n     * @deprecated since Symfony 5.3\n     *\n     * @return int\n     */\n    public static function strlen(?string $string)\n    {\n        trigger_deprecation('symfony/console', '5.3', 'Method \"%s()\" is deprecated and will be removed in Symfony 6.0. Use Helper::width() or Helper::length() instead.', __METHOD__);\n\n        return self::width($string);\n    }\n\n    /**\n     * Returns the width of a string, using mb_strwidth if it is available.\n     * The width is how many characters positions the string will use.\n     */\n    public static function width(?string $string): int\n    {\n        $string ?? $string = '';\n\n        if (preg_match('//u', $string)) {\n            return (new UnicodeString($string))->width(false);\n        }\n\n        if (false === $encoding = mb_detect_encoding($string, null, true)) {\n            return \\strlen($string);\n        }\n\n        return mb_strwidth($string, $encoding);\n    }\n\n    /**\n     * Returns the length of a string, using mb_strlen if it is available.\n     * The length is related to how many bytes the string will use.\n     */\n    public static function length(?string $string): int\n    {\n        $string ?? $string = '';\n\n        if (preg_match('//u', $string)) {\n            return (new UnicodeString($string))->length();\n        }\n\n        if (false === $encoding = mb_detect_encoding($string, null, true)) {\n            return \\strlen($string);\n        }\n\n        return mb_strlen($string, $encoding);\n    }\n\n    /**\n     * Returns the subset of a string, using mb_substr if it is available.\n     *\n     * @return string\n     */\n    public static function substr(?string $string, int $from, ?int $length = null)\n    {\n        $string ?? $string = '';\n\n        if (false === $encoding = mb_detect_encoding($string, null, true)) {\n            return substr($string, $from, $length);\n        }\n\n        return mb_substr($string, $from, $length, $encoding);\n    }\n\n    public static function formatTime($secs)\n    {\n        static $timeFormats = [\n            [0, '< 1 sec'],\n            [1, '1 sec'],\n            [2, 'secs', 1],\n            [60, '1 min'],\n            [120, 'mins', 60],\n            [3600, '1 hr'],\n            [7200, 'hrs', 3600],\n            [86400, '1 day'],\n            [172800, 'days', 86400],\n        ];\n\n        foreach ($timeFormats as $index => $format) {\n            if ($secs >= $format[0]) {\n                if ((isset($timeFormats[$index + 1]) && $secs < $timeFormats[$index + 1][0])\n                    || $index == \\count($timeFormats) - 1\n                ) {\n                    if (2 == \\count($format)) {\n                        return $format[1];\n                    }\n\n                    return floor($secs / $format[2]).' '.$format[1];\n                }\n            }\n        }\n    }\n\n    public static function formatMemory(int $memory)\n    {\n        if ($memory >= 1024 * 1024 * 1024) {\n            return sprintf('%.1f GiB', $memory / 1024 / 1024 / 1024);\n        }\n\n        if ($memory >= 1024 * 1024) {\n            return sprintf('%.1f MiB', $memory / 1024 / 1024);\n        }\n\n        if ($memory >= 1024) {\n            return sprintf('%d KiB', $memory / 1024);\n        }\n\n        return sprintf('%d B', $memory);\n    }\n\n    /**\n     * @deprecated since Symfony 5.3\n     */\n    public static function strlenWithoutDecoration(OutputFormatterInterface $formatter, ?string $string)\n    {\n        trigger_deprecation('symfony/console', '5.3', 'Method \"%s()\" is deprecated and will be removed in Symfony 6.0. Use Helper::removeDecoration() instead.', __METHOD__);\n\n        return self::width(self::removeDecoration($formatter, $string));\n    }\n\n    public static function removeDecoration(OutputFormatterInterface $formatter, ?string $string)\n    {\n        $isDecorated = $formatter->isDecorated();\n        $formatter->setDecorated(false);\n        // remove <...> formatting\n        $string = $formatter->format($string ?? '');\n        // remove already formatted characters\n        $string = preg_replace(\"/\\033\\[[^m]*m/\", '', $string ?? '');\n        // remove terminal hyperlinks\n        $string = preg_replace('/\\\\033]8;[^;]*;[^\\\\033]*\\\\033\\\\\\\\/', '', $string ?? '');\n        $formatter->setDecorated($isDecorated);\n\n        return $string;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Helper/HelperInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Helper;\n\n/**\n * HelperInterface is the interface all helpers must implement.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\ninterface HelperInterface\n{\n    /**\n     * Sets the helper set associated with this helper.\n     */\n    public function setHelperSet(?HelperSet $helperSet = null);\n\n    /**\n     * Gets the helper set associated with this helper.\n     *\n     * @return HelperSet|null\n     */\n    public function getHelperSet();\n\n    /**\n     * Returns the canonical name of this helper.\n     *\n     * @return string\n     */\n    public function getName();\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Helper/HelperSet.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Helper;\n\nuse Symfony\\Component\\Console\\Command\\Command;\nuse Symfony\\Component\\Console\\Exception\\InvalidArgumentException;\n\n/**\n * HelperSet represents a set of helpers to be used with a command.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n *\n * @implements \\IteratorAggregate<string, Helper>\n */\nclass HelperSet implements \\IteratorAggregate\n{\n    /** @var array<string, Helper> */\n    private $helpers = [];\n    private $command;\n\n    /**\n     * @param Helper[] $helpers An array of helper\n     */\n    public function __construct(array $helpers = [])\n    {\n        foreach ($helpers as $alias => $helper) {\n            $this->set($helper, \\is_int($alias) ? null : $alias);\n        }\n    }\n\n    public function set(HelperInterface $helper, ?string $alias = null)\n    {\n        $this->helpers[$helper->getName()] = $helper;\n        if (null !== $alias) {\n            $this->helpers[$alias] = $helper;\n        }\n\n        $helper->setHelperSet($this);\n    }\n\n    /**\n     * Returns true if the helper if defined.\n     *\n     * @return bool\n     */\n    public function has(string $name)\n    {\n        return isset($this->helpers[$name]);\n    }\n\n    /**\n     * Gets a helper value.\n     *\n     * @return HelperInterface\n     *\n     * @throws InvalidArgumentException if the helper is not defined\n     */\n    public function get(string $name)\n    {\n        if (!$this->has($name)) {\n            throw new InvalidArgumentException(sprintf('The helper \"%s\" is not defined.', $name));\n        }\n\n        return $this->helpers[$name];\n    }\n\n    /**\n     * @deprecated since Symfony 5.4\n     */\n    public function setCommand(?Command $command = null)\n    {\n        trigger_deprecation('symfony/console', '5.4', 'Method \"%s()\" is deprecated.', __METHOD__);\n\n        $this->command = $command;\n    }\n\n    /**\n     * Gets the command associated with this helper set.\n     *\n     * @return Command\n     *\n     * @deprecated since Symfony 5.4\n     */\n    public function getCommand()\n    {\n        trigger_deprecation('symfony/console', '5.4', 'Method \"%s()\" is deprecated.', __METHOD__);\n\n        return $this->command;\n    }\n\n    /**\n     * @return \\Traversable<string, Helper>\n     */\n    #[\\ReturnTypeWillChange]\n    public function getIterator()\n    {\n        return new \\ArrayIterator($this->helpers);\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Helper/InputAwareHelper.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Helper;\n\nuse Symfony\\Component\\Console\\Input\\InputAwareInterface;\nuse Symfony\\Component\\Console\\Input\\InputInterface;\n\n/**\n * An implementation of InputAwareInterface for Helpers.\n *\n * @author Wouter J <waldio.webdesign@gmail.com>\n */\nabstract class InputAwareHelper extends Helper implements InputAwareInterface\n{\n    protected $input;\n\n    /**\n     * {@inheritdoc}\n     */\n    public function setInput(InputInterface $input)\n    {\n        $this->input = $input;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Helper/ProcessHelper.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Helper;\n\nuse Symfony\\Component\\Console\\Output\\ConsoleOutputInterface;\nuse Symfony\\Component\\Console\\Output\\OutputInterface;\nuse Symfony\\Component\\Process\\Exception\\ProcessFailedException;\nuse Symfony\\Component\\Process\\Process;\n\n/**\n * The ProcessHelper class provides helpers to run external processes.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n *\n * @final\n */\nclass ProcessHelper extends Helper\n{\n    /**\n     * Runs an external process.\n     *\n     * @param array|Process $cmd      An instance of Process or an array of the command and arguments\n     * @param callable|null $callback A PHP callback to run whenever there is some\n     *                                output available on STDOUT or STDERR\n     */\n    public function run(OutputInterface $output, $cmd, ?string $error = null, ?callable $callback = null, int $verbosity = OutputInterface::VERBOSITY_VERY_VERBOSE): Process\n    {\n        if (!class_exists(Process::class)) {\n            throw new \\LogicException('The ProcessHelper cannot be run as the Process component is not installed. Try running \"compose require symfony/process\".');\n        }\n\n        if ($output instanceof ConsoleOutputInterface) {\n            $output = $output->getErrorOutput();\n        }\n\n        $formatter = $this->getHelperSet()->get('debug_formatter');\n\n        if ($cmd instanceof Process) {\n            $cmd = [$cmd];\n        }\n\n        if (!\\is_array($cmd)) {\n            throw new \\TypeError(sprintf('The \"command\" argument of \"%s()\" must be an array or a \"%s\" instance, \"%s\" given.', __METHOD__, Process::class, get_debug_type($cmd)));\n        }\n\n        if (\\is_string($cmd[0] ?? null)) {\n            $process = new Process($cmd);\n            $cmd = [];\n        } elseif (($cmd[0] ?? null) instanceof Process) {\n            $process = $cmd[0];\n            unset($cmd[0]);\n        } else {\n            throw new \\InvalidArgumentException(sprintf('Invalid command provided to \"%s()\": the command should be an array whose first element is either the path to the binary to run or a \"Process\" object.', __METHOD__));\n        }\n\n        if ($verbosity <= $output->getVerbosity()) {\n            $output->write($formatter->start(spl_object_hash($process), $this->escapeString($process->getCommandLine())));\n        }\n\n        if ($output->isDebug()) {\n            $callback = $this->wrapCallback($output, $process, $callback);\n        }\n\n        $process->run($callback, $cmd);\n\n        if ($verbosity <= $output->getVerbosity()) {\n            $message = $process->isSuccessful() ? 'Command ran successfully' : sprintf('%s Command did not run successfully', $process->getExitCode());\n            $output->write($formatter->stop(spl_object_hash($process), $message, $process->isSuccessful()));\n        }\n\n        if (!$process->isSuccessful() && null !== $error) {\n            $output->writeln(sprintf('<error>%s</error>', $this->escapeString($error)));\n        }\n\n        return $process;\n    }\n\n    /**\n     * Runs the process.\n     *\n     * This is identical to run() except that an exception is thrown if the process\n     * exits with a non-zero exit code.\n     *\n     * @param array|Process $cmd      An instance of Process or a command to run\n     * @param callable|null $callback A PHP callback to run whenever there is some\n     *                                output available on STDOUT or STDERR\n     *\n     * @throws ProcessFailedException\n     *\n     * @see run()\n     */\n    public function mustRun(OutputInterface $output, $cmd, ?string $error = null, ?callable $callback = null): Process\n    {\n        $process = $this->run($output, $cmd, $error, $callback);\n\n        if (!$process->isSuccessful()) {\n            throw new ProcessFailedException($process);\n        }\n\n        return $process;\n    }\n\n    /**\n     * Wraps a Process callback to add debugging output.\n     */\n    public function wrapCallback(OutputInterface $output, Process $process, ?callable $callback = null): callable\n    {\n        if ($output instanceof ConsoleOutputInterface) {\n            $output = $output->getErrorOutput();\n        }\n\n        $formatter = $this->getHelperSet()->get('debug_formatter');\n\n        return function ($type, $buffer) use ($output, $process, $callback, $formatter) {\n            $output->write($formatter->progress(spl_object_hash($process), $this->escapeString($buffer), Process::ERR === $type));\n\n            if (null !== $callback) {\n                $callback($type, $buffer);\n            }\n        };\n    }\n\n    private function escapeString(string $str): string\n    {\n        return str_replace('<', '\\\\<', $str);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getName(): string\n    {\n        return 'process';\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Helper/ProgressBar.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Helper;\n\nuse Symfony\\Component\\Console\\Cursor;\nuse Symfony\\Component\\Console\\Exception\\LogicException;\nuse Symfony\\Component\\Console\\Output\\ConsoleOutputInterface;\nuse Symfony\\Component\\Console\\Output\\ConsoleSectionOutput;\nuse Symfony\\Component\\Console\\Output\\OutputInterface;\nuse Symfony\\Component\\Console\\Terminal;\n\n/**\n * The ProgressBar provides helpers to display progress output.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n * @author Chris Jones <leeked@gmail.com>\n */\nfinal class ProgressBar\n{\n    public const FORMAT_VERBOSE = 'verbose';\n    public const FORMAT_VERY_VERBOSE = 'very_verbose';\n    public const FORMAT_DEBUG = 'debug';\n    public const FORMAT_NORMAL = 'normal';\n\n    private const FORMAT_VERBOSE_NOMAX = 'verbose_nomax';\n    private const FORMAT_VERY_VERBOSE_NOMAX = 'very_verbose_nomax';\n    private const FORMAT_DEBUG_NOMAX = 'debug_nomax';\n    private const FORMAT_NORMAL_NOMAX = 'normal_nomax';\n\n    private $barWidth = 28;\n    private $barChar;\n    private $emptyBarChar = '-';\n    private $progressChar = '>';\n    private $format;\n    private $internalFormat;\n    private $redrawFreq = 1;\n    private $writeCount;\n    private $lastWriteTime;\n    private $minSecondsBetweenRedraws = 0;\n    private $maxSecondsBetweenRedraws = 1;\n    private $output;\n    private $step = 0;\n    private $max;\n    private $startTime;\n    private $stepWidth;\n    private $percent = 0.0;\n    private $messages = [];\n    private $overwrite = true;\n    private $terminal;\n    private $previousMessage;\n    private $cursor;\n\n    private static $formatters;\n    private static $formats;\n\n    /**\n     * @param int $max Maximum steps (0 if unknown)\n     */\n    public function __construct(OutputInterface $output, int $max = 0, float $minSecondsBetweenRedraws = 1 / 25)\n    {\n        if ($output instanceof ConsoleOutputInterface) {\n            $output = $output->getErrorOutput();\n        }\n\n        $this->output = $output;\n        $this->setMaxSteps($max);\n        $this->terminal = new Terminal();\n\n        if (0 < $minSecondsBetweenRedraws) {\n            $this->redrawFreq = null;\n            $this->minSecondsBetweenRedraws = $minSecondsBetweenRedraws;\n        }\n\n        if (!$this->output->isDecorated()) {\n            // disable overwrite when output does not support ANSI codes.\n            $this->overwrite = false;\n\n            // set a reasonable redraw frequency so output isn't flooded\n            $this->redrawFreq = null;\n        }\n\n        $this->startTime = time();\n        $this->cursor = new Cursor($output);\n    }\n\n    /**\n     * Sets a placeholder formatter for a given name.\n     *\n     * This method also allow you to override an existing placeholder.\n     *\n     * @param string   $name     The placeholder name (including the delimiter char like %)\n     * @param callable $callable A PHP callable\n     */\n    public static function setPlaceholderFormatterDefinition(string $name, callable $callable): void\n    {\n        if (!self::$formatters) {\n            self::$formatters = self::initPlaceholderFormatters();\n        }\n\n        self::$formatters[$name] = $callable;\n    }\n\n    /**\n     * Gets the placeholder formatter for a given name.\n     *\n     * @param string $name The placeholder name (including the delimiter char like %)\n     */\n    public static function getPlaceholderFormatterDefinition(string $name): ?callable\n    {\n        if (!self::$formatters) {\n            self::$formatters = self::initPlaceholderFormatters();\n        }\n\n        return self::$formatters[$name] ?? null;\n    }\n\n    /**\n     * Sets a format for a given name.\n     *\n     * This method also allow you to override an existing format.\n     *\n     * @param string $name   The format name\n     * @param string $format A format string\n     */\n    public static function setFormatDefinition(string $name, string $format): void\n    {\n        if (!self::$formats) {\n            self::$formats = self::initFormats();\n        }\n\n        self::$formats[$name] = $format;\n    }\n\n    /**\n     * Gets the format for a given name.\n     *\n     * @param string $name The format name\n     */\n    public static function getFormatDefinition(string $name): ?string\n    {\n        if (!self::$formats) {\n            self::$formats = self::initFormats();\n        }\n\n        return self::$formats[$name] ?? null;\n    }\n\n    /**\n     * Associates a text with a named placeholder.\n     *\n     * The text is displayed when the progress bar is rendered but only\n     * when the corresponding placeholder is part of the custom format line\n     * (by wrapping the name with %).\n     *\n     * @param string $message The text to associate with the placeholder\n     * @param string $name    The name of the placeholder\n     */\n    public function setMessage(string $message, string $name = 'message')\n    {\n        $this->messages[$name] = $message;\n    }\n\n    /**\n     * @return string|null\n     */\n    public function getMessage(string $name = 'message')\n    {\n        return $this->messages[$name] ?? null;\n    }\n\n    public function getStartTime(): int\n    {\n        return $this->startTime;\n    }\n\n    public function getMaxSteps(): int\n    {\n        return $this->max;\n    }\n\n    public function getProgress(): int\n    {\n        return $this->step;\n    }\n\n    private function getStepWidth(): int\n    {\n        return $this->stepWidth;\n    }\n\n    public function getProgressPercent(): float\n    {\n        return $this->percent;\n    }\n\n    public function getBarOffset(): float\n    {\n        return floor($this->max ? $this->percent * $this->barWidth : (null === $this->redrawFreq ? (int) (min(5, $this->barWidth / 15) * $this->writeCount) : $this->step) % $this->barWidth);\n    }\n\n    public function getEstimated(): float\n    {\n        if (!$this->step) {\n            return 0;\n        }\n\n        return round((time() - $this->startTime) / $this->step * $this->max);\n    }\n\n    public function getRemaining(): float\n    {\n        if (!$this->step) {\n            return 0;\n        }\n\n        return round((time() - $this->startTime) / $this->step * ($this->max - $this->step));\n    }\n\n    public function setBarWidth(int $size)\n    {\n        $this->barWidth = max(1, $size);\n    }\n\n    public function getBarWidth(): int\n    {\n        return $this->barWidth;\n    }\n\n    public function setBarCharacter(string $char)\n    {\n        $this->barChar = $char;\n    }\n\n    public function getBarCharacter(): string\n    {\n        return $this->barChar ?? ($this->max ? '=' : $this->emptyBarChar);\n    }\n\n    public function setEmptyBarCharacter(string $char)\n    {\n        $this->emptyBarChar = $char;\n    }\n\n    public function getEmptyBarCharacter(): string\n    {\n        return $this->emptyBarChar;\n    }\n\n    public function setProgressCharacter(string $char)\n    {\n        $this->progressChar = $char;\n    }\n\n    public function getProgressCharacter(): string\n    {\n        return $this->progressChar;\n    }\n\n    public function setFormat(string $format)\n    {\n        $this->format = null;\n        $this->internalFormat = $format;\n    }\n\n    /**\n     * Sets the redraw frequency.\n     *\n     * @param int|null $freq The frequency in steps\n     */\n    public function setRedrawFrequency(?int $freq)\n    {\n        $this->redrawFreq = null !== $freq ? max(1, $freq) : null;\n    }\n\n    public function minSecondsBetweenRedraws(float $seconds): void\n    {\n        $this->minSecondsBetweenRedraws = $seconds;\n    }\n\n    public function maxSecondsBetweenRedraws(float $seconds): void\n    {\n        $this->maxSecondsBetweenRedraws = $seconds;\n    }\n\n    /**\n     * Returns an iterator that will automatically update the progress bar when iterated.\n     *\n     * @param int|null $max Number of steps to complete the bar (0 if indeterminate), if null it will be inferred from $iterable\n     */\n    public function iterate(iterable $iterable, ?int $max = null): iterable\n    {\n        $this->start($max ?? (is_countable($iterable) ? \\count($iterable) : 0));\n\n        foreach ($iterable as $key => $value) {\n            yield $key => $value;\n\n            $this->advance();\n        }\n\n        $this->finish();\n    }\n\n    /**\n     * Starts the progress output.\n     *\n     * @param int|null $max Number of steps to complete the bar (0 if indeterminate), null to leave unchanged\n     */\n    public function start(?int $max = null)\n    {\n        $this->startTime = time();\n        $this->step = 0;\n        $this->percent = 0.0;\n\n        if (null !== $max) {\n            $this->setMaxSteps($max);\n        }\n\n        $this->display();\n    }\n\n    /**\n     * Advances the progress output X steps.\n     *\n     * @param int $step Number of steps to advance\n     */\n    public function advance(int $step = 1)\n    {\n        $this->setProgress($this->step + $step);\n    }\n\n    /**\n     * Sets whether to overwrite the progressbar, false for new line.\n     */\n    public function setOverwrite(bool $overwrite)\n    {\n        $this->overwrite = $overwrite;\n    }\n\n    public function setProgress(int $step)\n    {\n        if ($this->max && $step > $this->max) {\n            $this->max = $step;\n        } elseif ($step < 0) {\n            $step = 0;\n        }\n\n        $redrawFreq = $this->redrawFreq ?? (($this->max ?: 10) / 10);\n        $prevPeriod = (int) ($this->step / $redrawFreq);\n        $currPeriod = (int) ($step / $redrawFreq);\n        $this->step = $step;\n        $this->percent = $this->max ? (float) $this->step / $this->max : 0;\n        $timeInterval = microtime(true) - $this->lastWriteTime;\n\n        // Draw regardless of other limits\n        if ($this->max === $step) {\n            $this->display();\n\n            return;\n        }\n\n        // Throttling\n        if ($timeInterval < $this->minSecondsBetweenRedraws) {\n            return;\n        }\n\n        // Draw each step period, but not too late\n        if ($prevPeriod !== $currPeriod || $timeInterval >= $this->maxSecondsBetweenRedraws) {\n            $this->display();\n        }\n    }\n\n    public function setMaxSteps(int $max)\n    {\n        $this->format = null;\n        $this->max = max(0, $max);\n        $this->stepWidth = $this->max ? Helper::width((string) $this->max) : 4;\n    }\n\n    /**\n     * Finishes the progress output.\n     */\n    public function finish(): void\n    {\n        if (!$this->max) {\n            $this->max = $this->step;\n        }\n\n        if ($this->step === $this->max && !$this->overwrite) {\n            // prevent double 100% output\n            return;\n        }\n\n        $this->setProgress($this->max);\n    }\n\n    /**\n     * Outputs the current progress string.\n     */\n    public function display(): void\n    {\n        if (OutputInterface::VERBOSITY_QUIET === $this->output->getVerbosity()) {\n            return;\n        }\n\n        if (null === $this->format) {\n            $this->setRealFormat($this->internalFormat ?: $this->determineBestFormat());\n        }\n\n        $this->overwrite($this->buildLine());\n    }\n\n    /**\n     * Removes the progress bar from the current line.\n     *\n     * This is useful if you wish to write some output\n     * while a progress bar is running.\n     * Call display() to show the progress bar again.\n     */\n    public function clear(): void\n    {\n        if (!$this->overwrite) {\n            return;\n        }\n\n        if (null === $this->format) {\n            $this->setRealFormat($this->internalFormat ?: $this->determineBestFormat());\n        }\n\n        $this->overwrite('');\n    }\n\n    private function setRealFormat(string $format)\n    {\n        // try to use the _nomax variant if available\n        if (!$this->max && null !== self::getFormatDefinition($format.'_nomax')) {\n            $this->format = self::getFormatDefinition($format.'_nomax');\n        } elseif (null !== self::getFormatDefinition($format)) {\n            $this->format = self::getFormatDefinition($format);\n        } else {\n            $this->format = $format;\n        }\n    }\n\n    /**\n     * Overwrites a previous message to the output.\n     */\n    private function overwrite(string $message): void\n    {\n        if ($this->previousMessage === $message) {\n            return;\n        }\n\n        $originalMessage = $message;\n\n        if ($this->overwrite) {\n            if (null !== $this->previousMessage) {\n                if ($this->output instanceof ConsoleSectionOutput) {\n                    $messageLines = explode(\"\\n\", $this->previousMessage);\n                    $lineCount = \\count($messageLines);\n                    foreach ($messageLines as $messageLine) {\n                        $messageLineLength = Helper::width(Helper::removeDecoration($this->output->getFormatter(), $messageLine));\n                        if ($messageLineLength > $this->terminal->getWidth()) {\n                            $lineCount += floor($messageLineLength / $this->terminal->getWidth());\n                        }\n                    }\n                    $this->output->clear($lineCount);\n                } else {\n                    $lineCount = substr_count($this->previousMessage, \"\\n\");\n                    for ($i = 0; $i < $lineCount; ++$i) {\n                        $this->cursor->moveToColumn(1);\n                        $this->cursor->clearLine();\n                        $this->cursor->moveUp();\n                    }\n\n                    $this->cursor->moveToColumn(1);\n                    $this->cursor->clearLine();\n                }\n            }\n        } elseif ($this->step > 0) {\n            $message = \\PHP_EOL.$message;\n        }\n\n        $this->previousMessage = $originalMessage;\n        $this->lastWriteTime = microtime(true);\n\n        $this->output->write($message);\n        ++$this->writeCount;\n    }\n\n    private function determineBestFormat(): string\n    {\n        switch ($this->output->getVerbosity()) {\n            // OutputInterface::VERBOSITY_QUIET: display is disabled anyway\n            case OutputInterface::VERBOSITY_VERBOSE:\n                return $this->max ? self::FORMAT_VERBOSE : self::FORMAT_VERBOSE_NOMAX;\n            case OutputInterface::VERBOSITY_VERY_VERBOSE:\n                return $this->max ? self::FORMAT_VERY_VERBOSE : self::FORMAT_VERY_VERBOSE_NOMAX;\n            case OutputInterface::VERBOSITY_DEBUG:\n                return $this->max ? self::FORMAT_DEBUG : self::FORMAT_DEBUG_NOMAX;\n            default:\n                return $this->max ? self::FORMAT_NORMAL : self::FORMAT_NORMAL_NOMAX;\n        }\n    }\n\n    private static function initPlaceholderFormatters(): array\n    {\n        return [\n            'bar' => function (self $bar, OutputInterface $output) {\n                $completeBars = $bar->getBarOffset();\n                $display = str_repeat($bar->getBarCharacter(), $completeBars);\n                if ($completeBars < $bar->getBarWidth()) {\n                    $emptyBars = $bar->getBarWidth() - $completeBars - Helper::length(Helper::removeDecoration($output->getFormatter(), $bar->getProgressCharacter()));\n                    $display .= $bar->getProgressCharacter().str_repeat($bar->getEmptyBarCharacter(), $emptyBars);\n                }\n\n                return $display;\n            },\n            'elapsed' => function (self $bar) {\n                return Helper::formatTime(time() - $bar->getStartTime());\n            },\n            'remaining' => function (self $bar) {\n                if (!$bar->getMaxSteps()) {\n                    throw new LogicException('Unable to display the remaining time if the maximum number of steps is not set.');\n                }\n\n                return Helper::formatTime($bar->getRemaining());\n            },\n            'estimated' => function (self $bar) {\n                if (!$bar->getMaxSteps()) {\n                    throw new LogicException('Unable to display the estimated time if the maximum number of steps is not set.');\n                }\n\n                return Helper::formatTime($bar->getEstimated());\n            },\n            'memory' => function (self $bar) {\n                return Helper::formatMemory(memory_get_usage(true));\n            },\n            'current' => function (self $bar) {\n                return str_pad($bar->getProgress(), $bar->getStepWidth(), ' ', \\STR_PAD_LEFT);\n            },\n            'max' => function (self $bar) {\n                return $bar->getMaxSteps();\n            },\n            'percent' => function (self $bar) {\n                return floor($bar->getProgressPercent() * 100);\n            },\n        ];\n    }\n\n    private static function initFormats(): array\n    {\n        return [\n            self::FORMAT_NORMAL => ' %current%/%max% [%bar%] %percent:3s%%',\n            self::FORMAT_NORMAL_NOMAX => ' %current% [%bar%]',\n\n            self::FORMAT_VERBOSE => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%',\n            self::FORMAT_VERBOSE_NOMAX => ' %current% [%bar%] %elapsed:6s%',\n\n            self::FORMAT_VERY_VERBOSE => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s%',\n            self::FORMAT_VERY_VERBOSE_NOMAX => ' %current% [%bar%] %elapsed:6s%',\n\n            self::FORMAT_DEBUG => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s% %memory:6s%',\n            self::FORMAT_DEBUG_NOMAX => ' %current% [%bar%] %elapsed:6s% %memory:6s%',\n        ];\n    }\n\n    private function buildLine(): string\n    {\n        $regex = \"{%([a-z\\-_]+)(?:\\:([^%]+))?%}i\";\n        $callback = function ($matches) {\n            if ($formatter = $this::getPlaceholderFormatterDefinition($matches[1])) {\n                $text = $formatter($this, $this->output);\n            } elseif (isset($this->messages[$matches[1]])) {\n                $text = $this->messages[$matches[1]];\n            } else {\n                return $matches[0];\n            }\n\n            if (isset($matches[2])) {\n                $text = sprintf('%'.$matches[2], $text);\n            }\n\n            return $text;\n        };\n        $line = preg_replace_callback($regex, $callback, $this->format);\n\n        // gets string length for each sub line with multiline format\n        $linesLength = array_map(function ($subLine) {\n            return Helper::width(Helper::removeDecoration($this->output->getFormatter(), rtrim($subLine, \"\\r\")));\n        }, explode(\"\\n\", $line));\n\n        $linesWidth = max($linesLength);\n\n        $terminalWidth = $this->terminal->getWidth();\n        if ($linesWidth <= $terminalWidth) {\n            return $line;\n        }\n\n        $this->setBarWidth($this->barWidth - $linesWidth + $terminalWidth);\n\n        return preg_replace_callback($regex, $callback, $this->format);\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Helper/ProgressIndicator.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Helper;\n\nuse Symfony\\Component\\Console\\Exception\\InvalidArgumentException;\nuse Symfony\\Component\\Console\\Exception\\LogicException;\nuse Symfony\\Component\\Console\\Output\\OutputInterface;\n\n/**\n * @author Kevin Bond <kevinbond@gmail.com>\n */\nclass ProgressIndicator\n{\n    private const FORMATS = [\n        'normal' => ' %indicator% %message%',\n        'normal_no_ansi' => ' %message%',\n\n        'verbose' => ' %indicator% %message% (%elapsed:6s%)',\n        'verbose_no_ansi' => ' %message% (%elapsed:6s%)',\n\n        'very_verbose' => ' %indicator% %message% (%elapsed:6s%, %memory:6s%)',\n        'very_verbose_no_ansi' => ' %message% (%elapsed:6s%, %memory:6s%)',\n    ];\n\n    private $output;\n    private $startTime;\n    private $format;\n    private $message;\n    private $indicatorValues;\n    private $indicatorCurrent;\n    private $indicatorChangeInterval;\n    private $indicatorUpdateTime;\n    private $started = false;\n\n    /**\n     * @var array<string, callable>\n     */\n    private static $formatters;\n\n    /**\n     * @param int        $indicatorChangeInterval Change interval in milliseconds\n     * @param array|null $indicatorValues         Animated indicator characters\n     */\n    public function __construct(OutputInterface $output, ?string $format = null, int $indicatorChangeInterval = 100, ?array $indicatorValues = null)\n    {\n        $this->output = $output;\n\n        if (null === $format) {\n            $format = $this->determineBestFormat();\n        }\n\n        if (null === $indicatorValues) {\n            $indicatorValues = ['-', '\\\\', '|', '/'];\n        }\n\n        $indicatorValues = array_values($indicatorValues);\n\n        if (2 > \\count($indicatorValues)) {\n            throw new InvalidArgumentException('Must have at least 2 indicator value characters.');\n        }\n\n        $this->format = self::getFormatDefinition($format);\n        $this->indicatorChangeInterval = $indicatorChangeInterval;\n        $this->indicatorValues = $indicatorValues;\n        $this->startTime = time();\n    }\n\n    /**\n     * Sets the current indicator message.\n     */\n    public function setMessage(?string $message)\n    {\n        $this->message = $message;\n\n        $this->display();\n    }\n\n    /**\n     * Starts the indicator output.\n     */\n    public function start(string $message)\n    {\n        if ($this->started) {\n            throw new LogicException('Progress indicator already started.');\n        }\n\n        $this->message = $message;\n        $this->started = true;\n        $this->startTime = time();\n        $this->indicatorUpdateTime = $this->getCurrentTimeInMilliseconds() + $this->indicatorChangeInterval;\n        $this->indicatorCurrent = 0;\n\n        $this->display();\n    }\n\n    /**\n     * Advances the indicator.\n     */\n    public function advance()\n    {\n        if (!$this->started) {\n            throw new LogicException('Progress indicator has not yet been started.');\n        }\n\n        if (!$this->output->isDecorated()) {\n            return;\n        }\n\n        $currentTime = $this->getCurrentTimeInMilliseconds();\n\n        if ($currentTime < $this->indicatorUpdateTime) {\n            return;\n        }\n\n        $this->indicatorUpdateTime = $currentTime + $this->indicatorChangeInterval;\n        ++$this->indicatorCurrent;\n\n        $this->display();\n    }\n\n    /**\n     * Finish the indicator with message.\n     */\n    public function finish(string $message)\n    {\n        if (!$this->started) {\n            throw new LogicException('Progress indicator has not yet been started.');\n        }\n\n        $this->message = $message;\n        $this->display();\n        $this->output->writeln('');\n        $this->started = false;\n    }\n\n    /**\n     * Gets the format for a given name.\n     *\n     * @return string|null\n     */\n    public static function getFormatDefinition(string $name)\n    {\n        return self::FORMATS[$name] ?? null;\n    }\n\n    /**\n     * Sets a placeholder formatter for a given name.\n     *\n     * This method also allow you to override an existing placeholder.\n     */\n    public static function setPlaceholderFormatterDefinition(string $name, callable $callable)\n    {\n        if (!self::$formatters) {\n            self::$formatters = self::initPlaceholderFormatters();\n        }\n\n        self::$formatters[$name] = $callable;\n    }\n\n    /**\n     * Gets the placeholder formatter for a given name (including the delimiter char like %).\n     *\n     * @return callable|null\n     */\n    public static function getPlaceholderFormatterDefinition(string $name)\n    {\n        if (!self::$formatters) {\n            self::$formatters = self::initPlaceholderFormatters();\n        }\n\n        return self::$formatters[$name] ?? null;\n    }\n\n    private function display()\n    {\n        if (OutputInterface::VERBOSITY_QUIET === $this->output->getVerbosity()) {\n            return;\n        }\n\n        $this->overwrite(preg_replace_callback(\"{%([a-z\\-_]+)(?:\\:([^%]+))?%}i\", function ($matches) {\n            if ($formatter = self::getPlaceholderFormatterDefinition($matches[1])) {\n                return $formatter($this);\n            }\n\n            return $matches[0];\n        }, $this->format ?? ''));\n    }\n\n    private function determineBestFormat(): string\n    {\n        switch ($this->output->getVerbosity()) {\n            // OutputInterface::VERBOSITY_QUIET: display is disabled anyway\n            case OutputInterface::VERBOSITY_VERBOSE:\n                return $this->output->isDecorated() ? 'verbose' : 'verbose_no_ansi';\n            case OutputInterface::VERBOSITY_VERY_VERBOSE:\n            case OutputInterface::VERBOSITY_DEBUG:\n                return $this->output->isDecorated() ? 'very_verbose' : 'very_verbose_no_ansi';\n            default:\n                return $this->output->isDecorated() ? 'normal' : 'normal_no_ansi';\n        }\n    }\n\n    /**\n     * Overwrites a previous message to the output.\n     */\n    private function overwrite(string $message)\n    {\n        if ($this->output->isDecorated()) {\n            $this->output->write(\"\\x0D\\x1B[2K\");\n            $this->output->write($message);\n        } else {\n            $this->output->writeln($message);\n        }\n    }\n\n    private function getCurrentTimeInMilliseconds(): float\n    {\n        return round(microtime(true) * 1000);\n    }\n\n    private static function initPlaceholderFormatters(): array\n    {\n        return [\n            'indicator' => function (self $indicator) {\n                return $indicator->indicatorValues[$indicator->indicatorCurrent % \\count($indicator->indicatorValues)];\n            },\n            'message' => function (self $indicator) {\n                return $indicator->message;\n            },\n            'elapsed' => function (self $indicator) {\n                return Helper::formatTime(time() - $indicator->startTime);\n            },\n            'memory' => function () {\n                return Helper::formatMemory(memory_get_usage(true));\n            },\n        ];\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Helper/QuestionHelper.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Helper;\n\nuse Symfony\\Component\\Console\\Cursor;\nuse Symfony\\Component\\Console\\Exception\\MissingInputException;\nuse Symfony\\Component\\Console\\Exception\\RuntimeException;\nuse Symfony\\Component\\Console\\Formatter\\OutputFormatter;\nuse Symfony\\Component\\Console\\Formatter\\OutputFormatterStyle;\nuse Symfony\\Component\\Console\\Input\\InputInterface;\nuse Symfony\\Component\\Console\\Input\\StreamableInputInterface;\nuse Symfony\\Component\\Console\\Output\\ConsoleOutputInterface;\nuse Symfony\\Component\\Console\\Output\\ConsoleSectionOutput;\nuse Symfony\\Component\\Console\\Output\\OutputInterface;\nuse Symfony\\Component\\Console\\Question\\ChoiceQuestion;\nuse Symfony\\Component\\Console\\Question\\Question;\nuse Symfony\\Component\\Console\\Terminal;\n\nuse function Symfony\\Component\\String\\s;\n\n/**\n * The QuestionHelper class provides helpers to interact with the user.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass QuestionHelper extends Helper\n{\n    /**\n     * @var resource|null\n     */\n    private $inputStream;\n\n    private static $stty = true;\n    private static $stdinIsInteractive;\n\n    /**\n     * Asks a question to the user.\n     *\n     * @return mixed The user answer\n     *\n     * @throws RuntimeException If there is no data to read in the input stream\n     */\n    public function ask(InputInterface $input, OutputInterface $output, Question $question)\n    {\n        if ($output instanceof ConsoleOutputInterface) {\n            $output = $output->getErrorOutput();\n        }\n\n        if (!$input->isInteractive()) {\n            return $this->getDefaultAnswer($question);\n        }\n\n        if ($input instanceof StreamableInputInterface && $stream = $input->getStream()) {\n            $this->inputStream = $stream;\n        }\n\n        try {\n            if (!$question->getValidator()) {\n                return $this->doAsk($output, $question);\n            }\n\n            $interviewer = function () use ($output, $question) {\n                return $this->doAsk($output, $question);\n            };\n\n            return $this->validateAttempts($interviewer, $output, $question);\n        } catch (MissingInputException $exception) {\n            $input->setInteractive(false);\n\n            if (null === $fallbackOutput = $this->getDefaultAnswer($question)) {\n                throw $exception;\n            }\n\n            return $fallbackOutput;\n        }\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getName()\n    {\n        return 'question';\n    }\n\n    /**\n     * Prevents usage of stty.\n     */\n    public static function disableStty()\n    {\n        self::$stty = false;\n    }\n\n    /**\n     * Asks the question to the user.\n     *\n     * @return mixed\n     *\n     * @throws RuntimeException In case the fallback is deactivated and the response cannot be hidden\n     */\n    private function doAsk(OutputInterface $output, Question $question)\n    {\n        $this->writePrompt($output, $question);\n\n        $inputStream = $this->inputStream ?: \\STDIN;\n        $autocomplete = $question->getAutocompleterCallback();\n\n        if (null === $autocomplete || !self::$stty || !Terminal::hasSttyAvailable()) {\n            $ret = false;\n            if ($question->isHidden()) {\n                try {\n                    $hiddenResponse = $this->getHiddenResponse($output, $inputStream, $question->isTrimmable());\n                    $ret = $question->isTrimmable() ? trim($hiddenResponse) : $hiddenResponse;\n                } catch (RuntimeException $e) {\n                    if (!$question->isHiddenFallback()) {\n                        throw $e;\n                    }\n                }\n            }\n\n            if (false === $ret) {\n                $isBlocked = stream_get_meta_data($inputStream)['blocked'] ?? true;\n\n                if (!$isBlocked) {\n                    stream_set_blocking($inputStream, true);\n                }\n\n                $ret = $this->readInput($inputStream, $question);\n\n                if (!$isBlocked) {\n                    stream_set_blocking($inputStream, false);\n                }\n\n                if (false === $ret) {\n                    throw new MissingInputException('Aborted.');\n                }\n                if ($question->isTrimmable()) {\n                    $ret = trim($ret);\n                }\n            }\n        } else {\n            $autocomplete = $this->autocomplete($output, $question, $inputStream, $autocomplete);\n            $ret = $question->isTrimmable() ? trim($autocomplete) : $autocomplete;\n        }\n\n        if ($output instanceof ConsoleSectionOutput) {\n            $output->addContent($ret);\n        }\n\n        $ret = \\strlen($ret) > 0 ? $ret : $question->getDefault();\n\n        if ($normalizer = $question->getNormalizer()) {\n            return $normalizer($ret);\n        }\n\n        return $ret;\n    }\n\n    /**\n     * @return mixed\n     */\n    private function getDefaultAnswer(Question $question)\n    {\n        $default = $question->getDefault();\n\n        if (null === $default) {\n            return $default;\n        }\n\n        if ($validator = $question->getValidator()) {\n            return \\call_user_func($question->getValidator(), $default);\n        } elseif ($question instanceof ChoiceQuestion) {\n            $choices = $question->getChoices();\n\n            if (!$question->isMultiselect()) {\n                return $choices[$default] ?? $default;\n            }\n\n            $default = explode(',', $default);\n            foreach ($default as $k => $v) {\n                $v = $question->isTrimmable() ? trim($v) : $v;\n                $default[$k] = $choices[$v] ?? $v;\n            }\n        }\n\n        return $default;\n    }\n\n    /**\n     * Outputs the question prompt.\n     */\n    protected function writePrompt(OutputInterface $output, Question $question)\n    {\n        $message = $question->getQuestion();\n\n        if ($question instanceof ChoiceQuestion) {\n            $output->writeln(array_merge([\n                $question->getQuestion(),\n            ], $this->formatChoiceQuestionChoices($question, 'info')));\n\n            $message = $question->getPrompt();\n        }\n\n        $output->write($message);\n    }\n\n    /**\n     * @return string[]\n     */\n    protected function formatChoiceQuestionChoices(ChoiceQuestion $question, string $tag)\n    {\n        $messages = [];\n\n        $maxWidth = max(array_map([__CLASS__, 'width'], array_keys($choices = $question->getChoices())));\n\n        foreach ($choices as $key => $value) {\n            $padding = str_repeat(' ', $maxWidth - self::width($key));\n\n            $messages[] = sprintf(\"  [<$tag>%s$padding</$tag>] %s\", $key, $value);\n        }\n\n        return $messages;\n    }\n\n    /**\n     * Outputs an error message.\n     */\n    protected function writeError(OutputInterface $output, \\Exception $error)\n    {\n        if (null !== $this->getHelperSet() && $this->getHelperSet()->has('formatter')) {\n            $message = $this->getHelperSet()->get('formatter')->formatBlock($error->getMessage(), 'error');\n        } else {\n            $message = '<error>'.$error->getMessage().'</error>';\n        }\n\n        $output->writeln($message);\n    }\n\n    /**\n     * Autocompletes a question.\n     *\n     * @param resource $inputStream\n     */\n    private function autocomplete(OutputInterface $output, Question $question, $inputStream, callable $autocomplete): string\n    {\n        $cursor = new Cursor($output, $inputStream);\n\n        $fullChoice = '';\n        $ret = '';\n\n        $i = 0;\n        $ofs = -1;\n        $matches = $autocomplete($ret);\n        $numMatches = \\count($matches);\n\n        $sttyMode = shell_exec('stty -g');\n        $isStdin = 'php://stdin' === (stream_get_meta_data($inputStream)['uri'] ?? null);\n        $r = [$inputStream];\n        $w = [];\n\n        // Disable icanon (so we can fread each keypress) and echo (we'll do echoing here instead)\n        shell_exec('stty -icanon -echo');\n\n        // Add highlighted text style\n        $output->getFormatter()->setStyle('hl', new OutputFormatterStyle('black', 'white'));\n\n        // Read a keypress\n        while (!feof($inputStream)) {\n            while ($isStdin && 0 === @stream_select($r, $w, $w, 0, 100)) {\n                // Give signal handlers a chance to run\n                $r = [$inputStream];\n            }\n            $c = fread($inputStream, 1);\n\n            // as opposed to fgets(), fread() returns an empty string when the stream content is empty, not false.\n            if (false === $c || ('' === $ret && '' === $c && null === $question->getDefault())) {\n                shell_exec('stty '.$sttyMode);\n                throw new MissingInputException('Aborted.');\n            } elseif (\"\\177\" === $c) { // Backspace Character\n                if (0 === $numMatches && 0 !== $i) {\n                    --$i;\n                    $cursor->moveLeft(s($fullChoice)->slice(-1)->width(false));\n\n                    $fullChoice = self::substr($fullChoice, 0, $i);\n                }\n\n                if (0 === $i) {\n                    $ofs = -1;\n                    $matches = $autocomplete($ret);\n                    $numMatches = \\count($matches);\n                } else {\n                    $numMatches = 0;\n                }\n\n                // Pop the last character off the end of our string\n                $ret = self::substr($ret, 0, $i);\n            } elseif (\"\\033\" === $c) {\n                // Did we read an escape sequence?\n                $c .= fread($inputStream, 2);\n\n                // A = Up Arrow. B = Down Arrow\n                if (isset($c[2]) && ('A' === $c[2] || 'B' === $c[2])) {\n                    if ('A' === $c[2] && -1 === $ofs) {\n                        $ofs = 0;\n                    }\n\n                    if (0 === $numMatches) {\n                        continue;\n                    }\n\n                    $ofs += ('A' === $c[2]) ? -1 : 1;\n                    $ofs = ($numMatches + $ofs) % $numMatches;\n                }\n            } elseif (\\ord($c) < 32) {\n                if (\"\\t\" === $c || \"\\n\" === $c) {\n                    if ($numMatches > 0 && -1 !== $ofs) {\n                        $ret = (string) $matches[$ofs];\n                        // Echo out remaining chars for current match\n                        $remainingCharacters = substr($ret, \\strlen(trim($this->mostRecentlyEnteredValue($fullChoice))));\n                        $output->write($remainingCharacters);\n                        $fullChoice .= $remainingCharacters;\n                        $i = (false === $encoding = mb_detect_encoding($fullChoice, null, true)) ? \\strlen($fullChoice) : mb_strlen($fullChoice, $encoding);\n\n                        $matches = array_filter(\n                            $autocomplete($ret),\n                            function ($match) use ($ret) {\n                                return '' === $ret || str_starts_with($match, $ret);\n                            }\n                        );\n                        $numMatches = \\count($matches);\n                        $ofs = -1;\n                    }\n\n                    if (\"\\n\" === $c) {\n                        $output->write($c);\n                        break;\n                    }\n\n                    $numMatches = 0;\n                }\n\n                continue;\n            } else {\n                if (\"\\x80\" <= $c) {\n                    $c .= fread($inputStream, [\"\\xC0\" => 1, \"\\xD0\" => 1, \"\\xE0\" => 2, \"\\xF0\" => 3][$c & \"\\xF0\"]);\n                }\n\n                $output->write($c);\n                $ret .= $c;\n                $fullChoice .= $c;\n                ++$i;\n\n                $tempRet = $ret;\n\n                if ($question instanceof ChoiceQuestion && $question->isMultiselect()) {\n                    $tempRet = $this->mostRecentlyEnteredValue($fullChoice);\n                }\n\n                $numMatches = 0;\n                $ofs = 0;\n\n                foreach ($autocomplete($ret) as $value) {\n                    // If typed characters match the beginning chunk of value (e.g. [AcmeDe]moBundle)\n                    if (str_starts_with($value, $tempRet)) {\n                        $matches[$numMatches++] = $value;\n                    }\n                }\n            }\n\n            $cursor->clearLineAfter();\n\n            if ($numMatches > 0 && -1 !== $ofs) {\n                $cursor->savePosition();\n                // Write highlighted text, complete the partially entered response\n                $charactersEntered = \\strlen(trim($this->mostRecentlyEnteredValue($fullChoice)));\n                $output->write('<hl>'.OutputFormatter::escapeTrailingBackslash(substr($matches[$ofs], $charactersEntered)).'</hl>');\n                $cursor->restorePosition();\n            }\n        }\n\n        // Reset stty so it behaves normally again\n        shell_exec('stty '.$sttyMode);\n\n        return $fullChoice;\n    }\n\n    private function mostRecentlyEnteredValue(string $entered): string\n    {\n        // Determine the most recent value that the user entered\n        if (!str_contains($entered, ',')) {\n            return $entered;\n        }\n\n        $choices = explode(',', $entered);\n        if ('' !== $lastChoice = trim($choices[\\count($choices) - 1])) {\n            return $lastChoice;\n        }\n\n        return $entered;\n    }\n\n    /**\n     * Gets a hidden response from user.\n     *\n     * @param resource $inputStream The handler resource\n     * @param bool     $trimmable   Is the answer trimmable\n     *\n     * @throws RuntimeException In case the fallback is deactivated and the response cannot be hidden\n     */\n    private function getHiddenResponse(OutputInterface $output, $inputStream, bool $trimmable = true): string\n    {\n        if ('\\\\' === \\DIRECTORY_SEPARATOR) {\n            $exe = __DIR__.'/../Resources/bin/hiddeninput.exe';\n\n            // handle code running from a phar\n            if ('phar:' === substr(__FILE__, 0, 5)) {\n                $tmpExe = sys_get_temp_dir().'/hiddeninput.exe';\n                copy($exe, $tmpExe);\n                $exe = $tmpExe;\n            }\n\n            $sExec = shell_exec('\"'.$exe.'\"');\n            $value = $trimmable ? rtrim($sExec) : $sExec;\n            $output->writeln('');\n\n            if (isset($tmpExe)) {\n                unlink($tmpExe);\n            }\n\n            return $value;\n        }\n\n        if (self::$stty && Terminal::hasSttyAvailable()) {\n            $sttyMode = shell_exec('stty -g');\n            shell_exec('stty -echo');\n        } elseif ($this->isInteractiveInput($inputStream)) {\n            throw new RuntimeException('Unable to hide the response.');\n        }\n\n        $value = fgets($inputStream, 4096);\n\n        if (self::$stty && Terminal::hasSttyAvailable()) {\n            shell_exec('stty '.$sttyMode);\n        }\n\n        if (false === $value) {\n            throw new MissingInputException('Aborted.');\n        }\n        if ($trimmable) {\n            $value = trim($value);\n        }\n        $output->writeln('');\n\n        return $value;\n    }\n\n    /**\n     * Validates an attempt.\n     *\n     * @param callable $interviewer A callable that will ask for a question and return the result\n     *\n     * @return mixed The validated response\n     *\n     * @throws \\Exception In case the max number of attempts has been reached and no valid response has been given\n     */\n    private function validateAttempts(callable $interviewer, OutputInterface $output, Question $question)\n    {\n        $error = null;\n        $attempts = $question->getMaxAttempts();\n\n        while (null === $attempts || $attempts--) {\n            if (null !== $error) {\n                $this->writeError($output, $error);\n            }\n\n            try {\n                return $question->getValidator()($interviewer());\n            } catch (RuntimeException $e) {\n                throw $e;\n            } catch (\\Exception $error) {\n            }\n        }\n\n        throw $error;\n    }\n\n    private function isInteractiveInput($inputStream): bool\n    {\n        if ('php://stdin' !== (stream_get_meta_data($inputStream)['uri'] ?? null)) {\n            return false;\n        }\n\n        if (null !== self::$stdinIsInteractive) {\n            return self::$stdinIsInteractive;\n        }\n\n        return self::$stdinIsInteractive = @stream_isatty(fopen('php://stdin', 'r'));\n    }\n\n    /**\n     * Reads one or more lines of input and returns what is read.\n     *\n     * @param resource $inputStream The handler resource\n     * @param Question $question    The question being asked\n     *\n     * @return string|false The input received, false in case input could not be read\n     */\n    private function readInput($inputStream, Question $question)\n    {\n        if (!$question->isMultiline()) {\n            $cp = $this->setIOCodepage();\n            $ret = fgets($inputStream, 4096);\n\n            return $this->resetIOCodepage($cp, $ret);\n        }\n\n        $multiLineStreamReader = $this->cloneInputStream($inputStream);\n        if (null === $multiLineStreamReader) {\n            return false;\n        }\n\n        $ret = '';\n        $cp = $this->setIOCodepage();\n        while (false !== ($char = fgetc($multiLineStreamReader))) {\n            if (\\PHP_EOL === \"{$ret}{$char}\") {\n                break;\n            }\n            $ret .= $char;\n        }\n\n        return $this->resetIOCodepage($cp, $ret);\n    }\n\n    /**\n     * Sets console I/O to the host code page.\n     *\n     * @return int Previous code page in IBM/EBCDIC format\n     */\n    private function setIOCodepage(): int\n    {\n        if (\\function_exists('sapi_windows_cp_set')) {\n            $cp = sapi_windows_cp_get();\n            sapi_windows_cp_set(sapi_windows_cp_get('oem'));\n\n            return $cp;\n        }\n\n        return 0;\n    }\n\n    /**\n     * Sets console I/O to the specified code page and converts the user input.\n     *\n     * @param string|false $input\n     *\n     * @return string|false\n     */\n    private function resetIOCodepage(int $cp, $input)\n    {\n        if (0 !== $cp) {\n            sapi_windows_cp_set($cp);\n\n            if (false !== $input && '' !== $input) {\n                $input = sapi_windows_cp_conv(sapi_windows_cp_get('oem'), $cp, $input);\n            }\n        }\n\n        return $input;\n    }\n\n    /**\n     * Clones an input stream in order to act on one instance of the same\n     * stream without affecting the other instance.\n     *\n     * @param resource $inputStream The handler resource\n     *\n     * @return resource|null The cloned resource, null in case it could not be cloned\n     */\n    private function cloneInputStream($inputStream)\n    {\n        $streamMetaData = stream_get_meta_data($inputStream);\n        $seekable = $streamMetaData['seekable'] ?? false;\n        $mode = $streamMetaData['mode'] ?? 'rb';\n        $uri = $streamMetaData['uri'] ?? null;\n\n        if (null === $uri) {\n            return null;\n        }\n\n        $cloneStream = fopen($uri, $mode);\n\n        // For seekable and writable streams, add all the same data to the\n        // cloned stream and then seek to the same offset.\n        if (true === $seekable && !\\in_array($mode, ['r', 'rb', 'rt'])) {\n            $offset = ftell($inputStream);\n            rewind($inputStream);\n            stream_copy_to_stream($inputStream, $cloneStream);\n            fseek($inputStream, $offset);\n            fseek($cloneStream, $offset);\n        }\n\n        return $cloneStream;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Helper/SymfonyQuestionHelper.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Helper;\n\nuse Symfony\\Component\\Console\\Formatter\\OutputFormatter;\nuse Symfony\\Component\\Console\\Output\\OutputInterface;\nuse Symfony\\Component\\Console\\Question\\ChoiceQuestion;\nuse Symfony\\Component\\Console\\Question\\ConfirmationQuestion;\nuse Symfony\\Component\\Console\\Question\\Question;\nuse Symfony\\Component\\Console\\Style\\SymfonyStyle;\n\n/**\n * Symfony Style Guide compliant question helper.\n *\n * @author Kevin Bond <kevinbond@gmail.com>\n */\nclass SymfonyQuestionHelper extends QuestionHelper\n{\n    /**\n     * {@inheritdoc}\n     */\n    protected function writePrompt(OutputInterface $output, Question $question)\n    {\n        $text = OutputFormatter::escapeTrailingBackslash($question->getQuestion());\n        $default = $question->getDefault();\n\n        if ($question->isMultiline()) {\n            $text .= sprintf(' (press %s to continue)', $this->getEofShortcut());\n        }\n\n        switch (true) {\n            case null === $default:\n                $text = sprintf(' <info>%s</info>:', $text);\n\n                break;\n\n            case $question instanceof ConfirmationQuestion:\n                $text = sprintf(' <info>%s (yes/no)</info> [<comment>%s</comment>]:', $text, $default ? 'yes' : 'no');\n\n                break;\n\n            case $question instanceof ChoiceQuestion && $question->isMultiselect():\n                $choices = $question->getChoices();\n                $default = explode(',', $default);\n\n                foreach ($default as $key => $value) {\n                    $default[$key] = $choices[trim($value)];\n                }\n\n                $text = sprintf(' <info>%s</info> [<comment>%s</comment>]:', $text, OutputFormatter::escape(implode(', ', $default)));\n\n                break;\n\n            case $question instanceof ChoiceQuestion:\n                $choices = $question->getChoices();\n                $text = sprintf(' <info>%s</info> [<comment>%s</comment>]:', $text, OutputFormatter::escape($choices[$default] ?? $default));\n\n                break;\n\n            default:\n                $text = sprintf(' <info>%s</info> [<comment>%s</comment>]:', $text, OutputFormatter::escape($default));\n        }\n\n        $output->writeln($text);\n\n        $prompt = ' > ';\n\n        if ($question instanceof ChoiceQuestion) {\n            $output->writeln($this->formatChoiceQuestionChoices($question, 'comment'));\n\n            $prompt = $question->getPrompt();\n        }\n\n        $output->write($prompt);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    protected function writeError(OutputInterface $output, \\Exception $error)\n    {\n        if ($output instanceof SymfonyStyle) {\n            $output->newLine();\n            $output->error($error->getMessage());\n\n            return;\n        }\n\n        parent::writeError($output, $error);\n    }\n\n    private function getEofShortcut(): string\n    {\n        if ('Windows' === \\PHP_OS_FAMILY) {\n            return '<comment>Ctrl+Z</comment> then <comment>Enter</comment>';\n        }\n\n        return '<comment>Ctrl+D</comment>';\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Helper/Table.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Helper;\n\nuse Symfony\\Component\\Console\\Exception\\InvalidArgumentException;\nuse Symfony\\Component\\Console\\Exception\\RuntimeException;\nuse Symfony\\Component\\Console\\Formatter\\OutputFormatter;\nuse Symfony\\Component\\Console\\Formatter\\WrappableOutputFormatterInterface;\nuse Symfony\\Component\\Console\\Output\\ConsoleSectionOutput;\nuse Symfony\\Component\\Console\\Output\\OutputInterface;\n\n/**\n * Provides helpers to display a table.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n * @author Саша Стаменковић <umpirsky@gmail.com>\n * @author Abdellatif Ait boudad <a.aitboudad@gmail.com>\n * @author Max Grigorian <maxakawizard@gmail.com>\n * @author Dany Maillard <danymaillard93b@gmail.com>\n */\nclass Table\n{\n    private const SEPARATOR_TOP = 0;\n    private const SEPARATOR_TOP_BOTTOM = 1;\n    private const SEPARATOR_MID = 2;\n    private const SEPARATOR_BOTTOM = 3;\n    private const BORDER_OUTSIDE = 0;\n    private const BORDER_INSIDE = 1;\n\n    private $headerTitle;\n    private $footerTitle;\n\n    /**\n     * Table headers.\n     */\n    private $headers = [];\n\n    /**\n     * Table rows.\n     */\n    private $rows = [];\n    private $horizontal = false;\n\n    /**\n     * Column widths cache.\n     */\n    private $effectiveColumnWidths = [];\n\n    /**\n     * Number of columns cache.\n     *\n     * @var int\n     */\n    private $numberOfColumns;\n\n    /**\n     * @var OutputInterface\n     */\n    private $output;\n\n    /**\n     * @var TableStyle\n     */\n    private $style;\n\n    /**\n     * @var array\n     */\n    private $columnStyles = [];\n\n    /**\n     * User set column widths.\n     *\n     * @var array\n     */\n    private $columnWidths = [];\n    private $columnMaxWidths = [];\n\n    /**\n     * @var array<string, TableStyle>|null\n     */\n    private static $styles;\n\n    private $rendered = false;\n\n    public function __construct(OutputInterface $output)\n    {\n        $this->output = $output;\n\n        if (!self::$styles) {\n            self::$styles = self::initStyles();\n        }\n\n        $this->setStyle('default');\n    }\n\n    /**\n     * Sets a style definition.\n     */\n    public static function setStyleDefinition(string $name, TableStyle $style)\n    {\n        if (!self::$styles) {\n            self::$styles = self::initStyles();\n        }\n\n        self::$styles[$name] = $style;\n    }\n\n    /**\n     * Gets a style definition by name.\n     *\n     * @return TableStyle\n     */\n    public static function getStyleDefinition(string $name)\n    {\n        if (!self::$styles) {\n            self::$styles = self::initStyles();\n        }\n\n        if (isset(self::$styles[$name])) {\n            return self::$styles[$name];\n        }\n\n        throw new InvalidArgumentException(sprintf('Style \"%s\" is not defined.', $name));\n    }\n\n    /**\n     * Sets table style.\n     *\n     * @param TableStyle|string $name The style name or a TableStyle instance\n     *\n     * @return $this\n     */\n    public function setStyle($name)\n    {\n        $this->style = $this->resolveStyle($name);\n\n        return $this;\n    }\n\n    /**\n     * Gets the current table style.\n     *\n     * @return TableStyle\n     */\n    public function getStyle()\n    {\n        return $this->style;\n    }\n\n    /**\n     * Sets table column style.\n     *\n     * @param TableStyle|string $name The style name or a TableStyle instance\n     *\n     * @return $this\n     */\n    public function setColumnStyle(int $columnIndex, $name)\n    {\n        $this->columnStyles[$columnIndex] = $this->resolveStyle($name);\n\n        return $this;\n    }\n\n    /**\n     * Gets the current style for a column.\n     *\n     * If style was not set, it returns the global table style.\n     *\n     * @return TableStyle\n     */\n    public function getColumnStyle(int $columnIndex)\n    {\n        return $this->columnStyles[$columnIndex] ?? $this->getStyle();\n    }\n\n    /**\n     * Sets the minimum width of a column.\n     *\n     * @return $this\n     */\n    public function setColumnWidth(int $columnIndex, int $width)\n    {\n        $this->columnWidths[$columnIndex] = $width;\n\n        return $this;\n    }\n\n    /**\n     * Sets the minimum width of all columns.\n     *\n     * @return $this\n     */\n    public function setColumnWidths(array $widths)\n    {\n        $this->columnWidths = [];\n        foreach ($widths as $index => $width) {\n            $this->setColumnWidth($index, $width);\n        }\n\n        return $this;\n    }\n\n    /**\n     * Sets the maximum width of a column.\n     *\n     * Any cell within this column which contents exceeds the specified width will be wrapped into multiple lines, while\n     * formatted strings are preserved.\n     *\n     * @return $this\n     */\n    public function setColumnMaxWidth(int $columnIndex, int $width): self\n    {\n        if (!$this->output->getFormatter() instanceof WrappableOutputFormatterInterface) {\n            throw new \\LogicException(sprintf('Setting a maximum column width is only supported when using a \"%s\" formatter, got \"%s\".', WrappableOutputFormatterInterface::class, get_debug_type($this->output->getFormatter())));\n        }\n\n        $this->columnMaxWidths[$columnIndex] = $width;\n\n        return $this;\n    }\n\n    /**\n     * @return $this\n     */\n    public function setHeaders(array $headers)\n    {\n        $headers = array_values($headers);\n        if (!empty($headers) && !\\is_array($headers[0])) {\n            $headers = [$headers];\n        }\n\n        $this->headers = $headers;\n\n        return $this;\n    }\n\n    public function setRows(array $rows)\n    {\n        $this->rows = [];\n\n        return $this->addRows($rows);\n    }\n\n    /**\n     * @return $this\n     */\n    public function addRows(array $rows)\n    {\n        foreach ($rows as $row) {\n            $this->addRow($row);\n        }\n\n        return $this;\n    }\n\n    /**\n     * @return $this\n     */\n    public function addRow($row)\n    {\n        if ($row instanceof TableSeparator) {\n            $this->rows[] = $row;\n\n            return $this;\n        }\n\n        if (!\\is_array($row)) {\n            throw new InvalidArgumentException('A row must be an array or a TableSeparator instance.');\n        }\n\n        $this->rows[] = array_values($row);\n\n        return $this;\n    }\n\n    /**\n     * Adds a row to the table, and re-renders the table.\n     *\n     * @return $this\n     */\n    public function appendRow($row): self\n    {\n        if (!$this->output instanceof ConsoleSectionOutput) {\n            throw new RuntimeException(sprintf('Output should be an instance of \"%s\" when calling \"%s\".', ConsoleSectionOutput::class, __METHOD__));\n        }\n\n        if ($this->rendered) {\n            $this->output->clear($this->calculateRowCount());\n        }\n\n        $this->addRow($row);\n        $this->render();\n\n        return $this;\n    }\n\n    /**\n     * @return $this\n     */\n    public function setRow($column, array $row)\n    {\n        $this->rows[$column] = $row;\n\n        return $this;\n    }\n\n    /**\n     * @return $this\n     */\n    public function setHeaderTitle(?string $title): self\n    {\n        $this->headerTitle = $title;\n\n        return $this;\n    }\n\n    /**\n     * @return $this\n     */\n    public function setFooterTitle(?string $title): self\n    {\n        $this->footerTitle = $title;\n\n        return $this;\n    }\n\n    /**\n     * @return $this\n     */\n    public function setHorizontal(bool $horizontal = true): self\n    {\n        $this->horizontal = $horizontal;\n\n        return $this;\n    }\n\n    /**\n     * Renders table to output.\n     *\n     * Example:\n     *\n     *     +---------------+-----------------------+------------------+\n     *     | ISBN          | Title                 | Author           |\n     *     +---------------+-----------------------+------------------+\n     *     | 99921-58-10-7 | Divine Comedy         | Dante Alighieri  |\n     *     | 9971-5-0210-0 | A Tale of Two Cities  | Charles Dickens  |\n     *     | 960-425-059-0 | The Lord of the Rings | J. R. R. Tolkien |\n     *     +---------------+-----------------------+------------------+\n     */\n    public function render()\n    {\n        $divider = new TableSeparator();\n        if ($this->horizontal) {\n            $rows = [];\n            foreach ($this->headers[0] ?? [] as $i => $header) {\n                $rows[$i] = [$header];\n                foreach ($this->rows as $row) {\n                    if ($row instanceof TableSeparator) {\n                        continue;\n                    }\n                    if (isset($row[$i])) {\n                        $rows[$i][] = $row[$i];\n                    } elseif ($rows[$i][0] instanceof TableCell && $rows[$i][0]->getColspan() >= 2) {\n                        // Noop, there is a \"title\"\n                    } else {\n                        $rows[$i][] = null;\n                    }\n                }\n            }\n        } else {\n            $rows = array_merge($this->headers, [$divider], $this->rows);\n        }\n\n        $this->calculateNumberOfColumns($rows);\n\n        $rowGroups = $this->buildTableRows($rows);\n        $this->calculateColumnsWidth($rowGroups);\n\n        $isHeader = !$this->horizontal;\n        $isFirstRow = $this->horizontal;\n        $hasTitle = (bool) $this->headerTitle;\n\n        foreach ($rowGroups as $rowGroup) {\n            $isHeaderSeparatorRendered = false;\n\n            foreach ($rowGroup as $row) {\n                if ($divider === $row) {\n                    $isHeader = false;\n                    $isFirstRow = true;\n\n                    continue;\n                }\n\n                if ($row instanceof TableSeparator) {\n                    $this->renderRowSeparator();\n\n                    continue;\n                }\n\n                if (!$row) {\n                    continue;\n                }\n\n                if ($isHeader && !$isHeaderSeparatorRendered) {\n                    $this->renderRowSeparator(\n                        $isHeader ? self::SEPARATOR_TOP : self::SEPARATOR_TOP_BOTTOM,\n                        $hasTitle ? $this->headerTitle : null,\n                        $hasTitle ? $this->style->getHeaderTitleFormat() : null\n                    );\n                    $hasTitle = false;\n                    $isHeaderSeparatorRendered = true;\n                }\n\n                if ($isFirstRow) {\n                    $this->renderRowSeparator(\n                        $isHeader ? self::SEPARATOR_TOP : self::SEPARATOR_TOP_BOTTOM,\n                        $hasTitle ? $this->headerTitle : null,\n                        $hasTitle ? $this->style->getHeaderTitleFormat() : null\n                    );\n                    $isFirstRow = false;\n                    $hasTitle = false;\n                }\n\n                if ($this->horizontal) {\n                    $this->renderRow($row, $this->style->getCellRowFormat(), $this->style->getCellHeaderFormat());\n                } else {\n                    $this->renderRow($row, $isHeader ? $this->style->getCellHeaderFormat() : $this->style->getCellRowFormat());\n                }\n            }\n        }\n        $this->renderRowSeparator(self::SEPARATOR_BOTTOM, $this->footerTitle, $this->style->getFooterTitleFormat());\n\n        $this->cleanup();\n        $this->rendered = true;\n    }\n\n    /**\n     * Renders horizontal header separator.\n     *\n     * Example:\n     *\n     *     +-----+-----------+-------+\n     */\n    private function renderRowSeparator(int $type = self::SEPARATOR_MID, ?string $title = null, ?string $titleFormat = null)\n    {\n        if (0 === $count = $this->numberOfColumns) {\n            return;\n        }\n\n        $borders = $this->style->getBorderChars();\n        if (!$borders[0] && !$borders[2] && !$this->style->getCrossingChar()) {\n            return;\n        }\n\n        $crossings = $this->style->getCrossingChars();\n        if (self::SEPARATOR_MID === $type) {\n            [$horizontal, $leftChar, $midChar, $rightChar] = [$borders[2], $crossings[8], $crossings[0], $crossings[4]];\n        } elseif (self::SEPARATOR_TOP === $type) {\n            [$horizontal, $leftChar, $midChar, $rightChar] = [$borders[0], $crossings[1], $crossings[2], $crossings[3]];\n        } elseif (self::SEPARATOR_TOP_BOTTOM === $type) {\n            [$horizontal, $leftChar, $midChar, $rightChar] = [$borders[0], $crossings[9], $crossings[10], $crossings[11]];\n        } else {\n            [$horizontal, $leftChar, $midChar, $rightChar] = [$borders[0], $crossings[7], $crossings[6], $crossings[5]];\n        }\n\n        $markup = $leftChar;\n        for ($column = 0; $column < $count; ++$column) {\n            $markup .= str_repeat($horizontal, $this->effectiveColumnWidths[$column]);\n            $markup .= $column === $count - 1 ? $rightChar : $midChar;\n        }\n\n        if (null !== $title) {\n            $titleLength = Helper::width(Helper::removeDecoration($formatter = $this->output->getFormatter(), $formattedTitle = sprintf($titleFormat, $title)));\n            $markupLength = Helper::width($markup);\n            if ($titleLength > $limit = $markupLength - 4) {\n                $titleLength = $limit;\n                $formatLength = Helper::width(Helper::removeDecoration($formatter, sprintf($titleFormat, '')));\n                $formattedTitle = sprintf($titleFormat, Helper::substr($title, 0, $limit - $formatLength - 3).'...');\n            }\n\n            $titleStart = intdiv($markupLength - $titleLength, 2);\n            if (false === mb_detect_encoding($markup, null, true)) {\n                $markup = substr_replace($markup, $formattedTitle, $titleStart, $titleLength);\n            } else {\n                $markup = mb_substr($markup, 0, $titleStart).$formattedTitle.mb_substr($markup, $titleStart + $titleLength);\n            }\n        }\n\n        $this->output->writeln(sprintf($this->style->getBorderFormat(), $markup));\n    }\n\n    /**\n     * Renders vertical column separator.\n     */\n    private function renderColumnSeparator(int $type = self::BORDER_OUTSIDE): string\n    {\n        $borders = $this->style->getBorderChars();\n\n        return sprintf($this->style->getBorderFormat(), self::BORDER_OUTSIDE === $type ? $borders[1] : $borders[3]);\n    }\n\n    /**\n     * Renders table row.\n     *\n     * Example:\n     *\n     *     | 9971-5-0210-0 | A Tale of Two Cities  | Charles Dickens  |\n     */\n    private function renderRow(array $row, string $cellFormat, ?string $firstCellFormat = null)\n    {\n        $rowContent = $this->renderColumnSeparator(self::BORDER_OUTSIDE);\n        $columns = $this->getRowColumns($row);\n        $last = \\count($columns) - 1;\n        foreach ($columns as $i => $column) {\n            if ($firstCellFormat && 0 === $i) {\n                $rowContent .= $this->renderCell($row, $column, $firstCellFormat);\n            } else {\n                $rowContent .= $this->renderCell($row, $column, $cellFormat);\n            }\n            $rowContent .= $this->renderColumnSeparator($last === $i ? self::BORDER_OUTSIDE : self::BORDER_INSIDE);\n        }\n        $this->output->writeln($rowContent);\n    }\n\n    /**\n     * Renders table cell with padding.\n     */\n    private function renderCell(array $row, int $column, string $cellFormat): string\n    {\n        $cell = $row[$column] ?? '';\n        $width = $this->effectiveColumnWidths[$column];\n        if ($cell instanceof TableCell && $cell->getColspan() > 1) {\n            // add the width of the following columns(numbers of colspan).\n            foreach (range($column + 1, $column + $cell->getColspan() - 1) as $nextColumn) {\n                $width += $this->getColumnSeparatorWidth() + $this->effectiveColumnWidths[$nextColumn];\n            }\n        }\n\n        // str_pad won't work properly with multi-byte strings, we need to fix the padding\n        if (false !== $encoding = mb_detect_encoding($cell, null, true)) {\n            $width += \\strlen($cell) - mb_strwidth($cell, $encoding);\n        }\n\n        $style = $this->getColumnStyle($column);\n\n        if ($cell instanceof TableSeparator) {\n            return sprintf($style->getBorderFormat(), str_repeat($style->getBorderChars()[2], $width));\n        }\n\n        $width += Helper::length($cell) - Helper::length(Helper::removeDecoration($this->output->getFormatter(), $cell));\n        $content = sprintf($style->getCellRowContentFormat(), $cell);\n\n        $padType = $style->getPadType();\n        if ($cell instanceof TableCell && $cell->getStyle() instanceof TableCellStyle) {\n            $isNotStyledByTag = !preg_match('/^<(\\w+|(\\w+=[\\w,]+;?)*)>.+<\\/(\\w+|(\\w+=\\w+;?)*)?>$/', $cell);\n            if ($isNotStyledByTag) {\n                $cellFormat = $cell->getStyle()->getCellFormat();\n                if (!\\is_string($cellFormat)) {\n                    $tag = http_build_query($cell->getStyle()->getTagOptions(), '', ';');\n                    $cellFormat = '<'.$tag.'>%s</>';\n                }\n\n                if (strstr($content, '</>')) {\n                    $content = str_replace('</>', '', $content);\n                    $width -= 3;\n                }\n                if (strstr($content, '<fg=default;bg=default>')) {\n                    $content = str_replace('<fg=default;bg=default>', '', $content);\n                    $width -= \\strlen('<fg=default;bg=default>');\n                }\n            }\n\n            $padType = $cell->getStyle()->getPadByAlign();\n        }\n\n        return sprintf($cellFormat, str_pad($content, $width, $style->getPaddingChar(), $padType));\n    }\n\n    /**\n     * Calculate number of columns for this table.\n     */\n    private function calculateNumberOfColumns(array $rows)\n    {\n        $columns = [0];\n        foreach ($rows as $row) {\n            if ($row instanceof TableSeparator) {\n                continue;\n            }\n\n            $columns[] = $this->getNumberOfColumns($row);\n        }\n\n        $this->numberOfColumns = max($columns);\n    }\n\n    private function buildTableRows(array $rows): TableRows\n    {\n        /** @var WrappableOutputFormatterInterface $formatter */\n        $formatter = $this->output->getFormatter();\n        $unmergedRows = [];\n        for ($rowKey = 0; $rowKey < \\count($rows); ++$rowKey) {\n            $rows = $this->fillNextRows($rows, $rowKey);\n\n            // Remove any new line breaks and replace it with a new line\n            foreach ($rows[$rowKey] as $column => $cell) {\n                $colspan = $cell instanceof TableCell ? $cell->getColspan() : 1;\n\n                if (isset($this->columnMaxWidths[$column]) && Helper::width(Helper::removeDecoration($formatter, $cell)) > $this->columnMaxWidths[$column]) {\n                    $cell = $formatter->formatAndWrap($cell, $this->columnMaxWidths[$column] * $colspan);\n                }\n                if (!strstr($cell ?? '', \"\\n\")) {\n                    continue;\n                }\n                $eol = str_contains($cell ?? '', \"\\r\\n\") ? \"\\r\\n\" : \"\\n\";\n                $escaped = implode($eol, array_map([OutputFormatter::class, 'escapeTrailingBackslash'], explode($eol, $cell)));\n                $cell = $cell instanceof TableCell ? new TableCell($escaped, ['colspan' => $cell->getColspan()]) : $escaped;\n                $lines = explode($eol, str_replace($eol, '<fg=default;bg=default></>'.$eol, $cell));\n                foreach ($lines as $lineKey => $line) {\n                    if ($colspan > 1) {\n                        $line = new TableCell($line, ['colspan' => $colspan]);\n                    }\n                    if (0 === $lineKey) {\n                        $rows[$rowKey][$column] = $line;\n                    } else {\n                        if (!\\array_key_exists($rowKey, $unmergedRows) || !\\array_key_exists($lineKey, $unmergedRows[$rowKey])) {\n                            $unmergedRows[$rowKey][$lineKey] = $this->copyRow($rows, $rowKey);\n                        }\n                        $unmergedRows[$rowKey][$lineKey][$column] = $line;\n                    }\n                }\n            }\n        }\n\n        return new TableRows(function () use ($rows, $unmergedRows): \\Traversable {\n            foreach ($rows as $rowKey => $row) {\n                $rowGroup = [$row instanceof TableSeparator ? $row : $this->fillCells($row)];\n\n                if (isset($unmergedRows[$rowKey])) {\n                    foreach ($unmergedRows[$rowKey] as $row) {\n                        $rowGroup[] = $row instanceof TableSeparator ? $row : $this->fillCells($row);\n                    }\n                }\n                yield $rowGroup;\n            }\n        });\n    }\n\n    private function calculateRowCount(): int\n    {\n        $numberOfRows = \\count(iterator_to_array($this->buildTableRows(array_merge($this->headers, [new TableSeparator()], $this->rows))));\n\n        if ($this->headers) {\n            ++$numberOfRows; // Add row for header separator\n        }\n\n        if (\\count($this->rows) > 0) {\n            ++$numberOfRows; // Add row for footer separator\n        }\n\n        return $numberOfRows;\n    }\n\n    /**\n     * fill rows that contains rowspan > 1.\n     *\n     * @throws InvalidArgumentException\n     */\n    private function fillNextRows(array $rows, int $line): array\n    {\n        $unmergedRows = [];\n        foreach ($rows[$line] as $column => $cell) {\n            if (null !== $cell && !$cell instanceof TableCell && !\\is_scalar($cell) && !(\\is_object($cell) && method_exists($cell, '__toString'))) {\n                throw new InvalidArgumentException(sprintf('A cell must be a TableCell, a scalar or an object implementing \"__toString()\", \"%s\" given.', get_debug_type($cell)));\n            }\n            if ($cell instanceof TableCell && $cell->getRowspan() > 1) {\n                $nbLines = $cell->getRowspan() - 1;\n                $lines = [$cell];\n                if (strstr($cell, \"\\n\")) {\n                    $eol = str_contains($cell, \"\\r\\n\") ? \"\\r\\n\" : \"\\n\";\n                    $lines = explode($eol, str_replace($eol, '<fg=default;bg=default>'.$eol.'</>', $cell));\n                    $nbLines = \\count($lines) > $nbLines ? substr_count($cell, $eol) : $nbLines;\n\n                    $rows[$line][$column] = new TableCell($lines[0], ['colspan' => $cell->getColspan(), 'style' => $cell->getStyle()]);\n                    unset($lines[0]);\n                }\n\n                // create a two dimensional array (rowspan x colspan)\n                $unmergedRows = array_replace_recursive(array_fill($line + 1, $nbLines, []), $unmergedRows);\n                foreach ($unmergedRows as $unmergedRowKey => $unmergedRow) {\n                    $value = $lines[$unmergedRowKey - $line] ?? '';\n                    $unmergedRows[$unmergedRowKey][$column] = new TableCell($value, ['colspan' => $cell->getColspan(), 'style' => $cell->getStyle()]);\n                    if ($nbLines === $unmergedRowKey - $line) {\n                        break;\n                    }\n                }\n            }\n        }\n\n        foreach ($unmergedRows as $unmergedRowKey => $unmergedRow) {\n            // we need to know if $unmergedRow will be merged or inserted into $rows\n            if (isset($rows[$unmergedRowKey]) && \\is_array($rows[$unmergedRowKey]) && ($this->getNumberOfColumns($rows[$unmergedRowKey]) + $this->getNumberOfColumns($unmergedRows[$unmergedRowKey]) <= $this->numberOfColumns)) {\n                foreach ($unmergedRow as $cellKey => $cell) {\n                    // insert cell into row at cellKey position\n                    array_splice($rows[$unmergedRowKey], $cellKey, 0, [$cell]);\n                }\n            } else {\n                $row = $this->copyRow($rows, $unmergedRowKey - 1);\n                foreach ($unmergedRow as $column => $cell) {\n                    if (!empty($cell)) {\n                        $row[$column] = $unmergedRow[$column];\n                    }\n                }\n                array_splice($rows, $unmergedRowKey, 0, [$row]);\n            }\n        }\n\n        return $rows;\n    }\n\n    /**\n     * fill cells for a row that contains colspan > 1.\n     */\n    private function fillCells(iterable $row)\n    {\n        $newRow = [];\n\n        foreach ($row as $column => $cell) {\n            $newRow[] = $cell;\n            if ($cell instanceof TableCell && $cell->getColspan() > 1) {\n                foreach (range($column + 1, $column + $cell->getColspan() - 1) as $position) {\n                    // insert empty value at column position\n                    $newRow[] = '';\n                }\n            }\n        }\n\n        return $newRow ?: $row;\n    }\n\n    private function copyRow(array $rows, int $line): array\n    {\n        $row = $rows[$line];\n        foreach ($row as $cellKey => $cellValue) {\n            $row[$cellKey] = '';\n            if ($cellValue instanceof TableCell) {\n                $row[$cellKey] = new TableCell('', ['colspan' => $cellValue->getColspan()]);\n            }\n        }\n\n        return $row;\n    }\n\n    /**\n     * Gets number of columns by row.\n     */\n    private function getNumberOfColumns(array $row): int\n    {\n        $columns = \\count($row);\n        foreach ($row as $column) {\n            $columns += $column instanceof TableCell ? ($column->getColspan() - 1) : 0;\n        }\n\n        return $columns;\n    }\n\n    /**\n     * Gets list of columns for the given row.\n     */\n    private function getRowColumns(array $row): array\n    {\n        $columns = range(0, $this->numberOfColumns - 1);\n        foreach ($row as $cellKey => $cell) {\n            if ($cell instanceof TableCell && $cell->getColspan() > 1) {\n                // exclude grouped columns.\n                $columns = array_diff($columns, range($cellKey + 1, $cellKey + $cell->getColspan() - 1));\n            }\n        }\n\n        return $columns;\n    }\n\n    /**\n     * Calculates columns widths.\n     */\n    private function calculateColumnsWidth(iterable $groups)\n    {\n        for ($column = 0; $column < $this->numberOfColumns; ++$column) {\n            $lengths = [];\n            foreach ($groups as $group) {\n                foreach ($group as $row) {\n                    if ($row instanceof TableSeparator) {\n                        continue;\n                    }\n\n                    foreach ($row as $i => $cell) {\n                        if ($cell instanceof TableCell) {\n                            $textContent = Helper::removeDecoration($this->output->getFormatter(), $cell);\n                            $textLength = Helper::width($textContent);\n                            if ($textLength > 0) {\n                                $contentColumns = mb_str_split($textContent, ceil($textLength / $cell->getColspan()));\n                                foreach ($contentColumns as $position => $content) {\n                                    $row[$i + $position] = $content;\n                                }\n                            }\n                        }\n                    }\n\n                    $lengths[] = $this->getCellWidth($row, $column);\n                }\n            }\n\n            $this->effectiveColumnWidths[$column] = max($lengths) + Helper::width($this->style->getCellRowContentFormat()) - 2;\n        }\n    }\n\n    private function getColumnSeparatorWidth(): int\n    {\n        return Helper::width(sprintf($this->style->getBorderFormat(), $this->style->getBorderChars()[3]));\n    }\n\n    private function getCellWidth(array $row, int $column): int\n    {\n        $cellWidth = 0;\n\n        if (isset($row[$column])) {\n            $cell = $row[$column];\n            $cellWidth = Helper::width(Helper::removeDecoration($this->output->getFormatter(), $cell));\n        }\n\n        $columnWidth = $this->columnWidths[$column] ?? 0;\n        $cellWidth = max($cellWidth, $columnWidth);\n\n        return isset($this->columnMaxWidths[$column]) ? min($this->columnMaxWidths[$column], $cellWidth) : $cellWidth;\n    }\n\n    /**\n     * Called after rendering to cleanup cache data.\n     */\n    private function cleanup()\n    {\n        $this->effectiveColumnWidths = [];\n        $this->numberOfColumns = null;\n    }\n\n    /**\n     * @return array<string, TableStyle>\n     */\n    private static function initStyles(): array\n    {\n        $borderless = new TableStyle();\n        $borderless\n            ->setHorizontalBorderChars('=')\n            ->setVerticalBorderChars(' ')\n            ->setDefaultCrossingChar(' ')\n        ;\n\n        $compact = new TableStyle();\n        $compact\n            ->setHorizontalBorderChars('')\n            ->setVerticalBorderChars('')\n            ->setDefaultCrossingChar('')\n            ->setCellRowContentFormat('%s ')\n        ;\n\n        $styleGuide = new TableStyle();\n        $styleGuide\n            ->setHorizontalBorderChars('-')\n            ->setVerticalBorderChars(' ')\n            ->setDefaultCrossingChar(' ')\n            ->setCellHeaderFormat('%s')\n        ;\n\n        $box = (new TableStyle())\n            ->setHorizontalBorderChars('─')\n            ->setVerticalBorderChars('│')\n            ->setCrossingChars('┼', '┌', '┬', '┐', '┤', '┘', '┴', '└', '├')\n        ;\n\n        $boxDouble = (new TableStyle())\n            ->setHorizontalBorderChars('═', '─')\n            ->setVerticalBorderChars('║', '│')\n            ->setCrossingChars('┼', '╔', '╤', '╗', '╢', '╝', '╧', '╚', '╟', '╠', '╪', '╣')\n        ;\n\n        return [\n            'default' => new TableStyle(),\n            'borderless' => $borderless,\n            'compact' => $compact,\n            'symfony-style-guide' => $styleGuide,\n            'box' => $box,\n            'box-double' => $boxDouble,\n        ];\n    }\n\n    private function resolveStyle($name): TableStyle\n    {\n        if ($name instanceof TableStyle) {\n            return $name;\n        }\n\n        if (isset(self::$styles[$name])) {\n            return self::$styles[$name];\n        }\n\n        throw new InvalidArgumentException(sprintf('Style \"%s\" is not defined.', $name));\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Helper/TableCell.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Helper;\n\nuse Symfony\\Component\\Console\\Exception\\InvalidArgumentException;\n\n/**\n * @author Abdellatif Ait boudad <a.aitboudad@gmail.com>\n */\nclass TableCell\n{\n    private $value;\n    private $options = [\n        'rowspan' => 1,\n        'colspan' => 1,\n        'style' => null,\n    ];\n\n    public function __construct(string $value = '', array $options = [])\n    {\n        $this->value = $value;\n\n        // check option names\n        if ($diff = array_diff(array_keys($options), array_keys($this->options))) {\n            throw new InvalidArgumentException(sprintf('The TableCell does not support the following options: \\'%s\\'.', implode('\\', \\'', $diff)));\n        }\n\n        if (isset($options['style']) && !$options['style'] instanceof TableCellStyle) {\n            throw new InvalidArgumentException('The style option must be an instance of \"TableCellStyle\".');\n        }\n\n        $this->options = array_merge($this->options, $options);\n    }\n\n    /**\n     * Returns the cell value.\n     *\n     * @return string\n     */\n    public function __toString()\n    {\n        return $this->value;\n    }\n\n    /**\n     * Gets number of colspan.\n     *\n     * @return int\n     */\n    public function getColspan()\n    {\n        return (int) $this->options['colspan'];\n    }\n\n    /**\n     * Gets number of rowspan.\n     *\n     * @return int\n     */\n    public function getRowspan()\n    {\n        return (int) $this->options['rowspan'];\n    }\n\n    public function getStyle(): ?TableCellStyle\n    {\n        return $this->options['style'];\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Helper/TableCellStyle.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Helper;\n\nuse Symfony\\Component\\Console\\Exception\\InvalidArgumentException;\n\n/**\n * @author Yewhen Khoptynskyi <khoptynskyi@gmail.com>\n */\nclass TableCellStyle\n{\n    public const DEFAULT_ALIGN = 'left';\n\n    private const TAG_OPTIONS = [\n        'fg',\n        'bg',\n        'options',\n    ];\n\n    private const ALIGN_MAP = [\n        'left' => \\STR_PAD_RIGHT,\n        'center' => \\STR_PAD_BOTH,\n        'right' => \\STR_PAD_LEFT,\n    ];\n\n    private $options = [\n        'fg' => 'default',\n        'bg' => 'default',\n        'options' => null,\n        'align' => self::DEFAULT_ALIGN,\n        'cellFormat' => null,\n    ];\n\n    public function __construct(array $options = [])\n    {\n        if ($diff = array_diff(array_keys($options), array_keys($this->options))) {\n            throw new InvalidArgumentException(sprintf('The TableCellStyle does not support the following options: \\'%s\\'.', implode('\\', \\'', $diff)));\n        }\n\n        if (isset($options['align']) && !\\array_key_exists($options['align'], self::ALIGN_MAP)) {\n            throw new InvalidArgumentException(sprintf('Wrong align value. Value must be following: \\'%s\\'.', implode('\\', \\'', array_keys(self::ALIGN_MAP))));\n        }\n\n        $this->options = array_merge($this->options, $options);\n    }\n\n    public function getOptions(): array\n    {\n        return $this->options;\n    }\n\n    /**\n     * Gets options we need for tag for example fg, bg.\n     *\n     * @return string[]\n     */\n    public function getTagOptions()\n    {\n        return array_filter(\n            $this->getOptions(),\n            function ($key) {\n                return \\in_array($key, self::TAG_OPTIONS) && isset($this->options[$key]);\n            },\n            \\ARRAY_FILTER_USE_KEY\n        );\n    }\n\n    /**\n     * @return int\n     */\n    public function getPadByAlign()\n    {\n        return self::ALIGN_MAP[$this->getOptions()['align']];\n    }\n\n    public function getCellFormat(): ?string\n    {\n        return $this->getOptions()['cellFormat'];\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Helper/TableRows.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Helper;\n\n/**\n * @internal\n */\nclass TableRows implements \\IteratorAggregate\n{\n    private $generator;\n\n    public function __construct(\\Closure $generator)\n    {\n        $this->generator = $generator;\n    }\n\n    public function getIterator(): \\Traversable\n    {\n        return ($this->generator)();\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Helper/TableSeparator.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Helper;\n\n/**\n * Marks a row as being a separator.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass TableSeparator extends TableCell\n{\n    public function __construct(array $options = [])\n    {\n        parent::__construct('', $options);\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Helper/TableStyle.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Helper;\n\nuse Symfony\\Component\\Console\\Exception\\InvalidArgumentException;\nuse Symfony\\Component\\Console\\Exception\\LogicException;\n\n/**\n * Defines the styles for a Table.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n * @author Саша Стаменковић <umpirsky@gmail.com>\n * @author Dany Maillard <danymaillard93b@gmail.com>\n */\nclass TableStyle\n{\n    private $paddingChar = ' ';\n    private $horizontalOutsideBorderChar = '-';\n    private $horizontalInsideBorderChar = '-';\n    private $verticalOutsideBorderChar = '|';\n    private $verticalInsideBorderChar = '|';\n    private $crossingChar = '+';\n    private $crossingTopRightChar = '+';\n    private $crossingTopMidChar = '+';\n    private $crossingTopLeftChar = '+';\n    private $crossingMidRightChar = '+';\n    private $crossingBottomRightChar = '+';\n    private $crossingBottomMidChar = '+';\n    private $crossingBottomLeftChar = '+';\n    private $crossingMidLeftChar = '+';\n    private $crossingTopLeftBottomChar = '+';\n    private $crossingTopMidBottomChar = '+';\n    private $crossingTopRightBottomChar = '+';\n    private $headerTitleFormat = '<fg=black;bg=white;options=bold> %s </>';\n    private $footerTitleFormat = '<fg=black;bg=white;options=bold> %s </>';\n    private $cellHeaderFormat = '<info>%s</info>';\n    private $cellRowFormat = '%s';\n    private $cellRowContentFormat = ' %s ';\n    private $borderFormat = '%s';\n    private $padType = \\STR_PAD_RIGHT;\n\n    /**\n     * Sets padding character, used for cell padding.\n     *\n     * @return $this\n     */\n    public function setPaddingChar(string $paddingChar)\n    {\n        if (!$paddingChar) {\n            throw new LogicException('The padding char must not be empty.');\n        }\n\n        $this->paddingChar = $paddingChar;\n\n        return $this;\n    }\n\n    /**\n     * Gets padding character, used for cell padding.\n     *\n     * @return string\n     */\n    public function getPaddingChar()\n    {\n        return $this->paddingChar;\n    }\n\n    /**\n     * Sets horizontal border characters.\n     *\n     * <code>\n     * ╔═══════════════╤══════════════════════════╤══════════════════╗\n     * 1 ISBN          2 Title                    │ Author           ║\n     * ╠═══════════════╪══════════════════════════╪══════════════════╣\n     * ║ 99921-58-10-7 │ Divine Comedy            │ Dante Alighieri  ║\n     * ║ 9971-5-0210-0 │ A Tale of Two Cities     │ Charles Dickens  ║\n     * ║ 960-425-059-0 │ The Lord of the Rings    │ J. R. R. Tolkien ║\n     * ║ 80-902734-1-6 │ And Then There Were None │ Agatha Christie  ║\n     * ╚═══════════════╧══════════════════════════╧══════════════════╝\n     * </code>\n     *\n     * @return $this\n     */\n    public function setHorizontalBorderChars(string $outside, ?string $inside = null): self\n    {\n        $this->horizontalOutsideBorderChar = $outside;\n        $this->horizontalInsideBorderChar = $inside ?? $outside;\n\n        return $this;\n    }\n\n    /**\n     * Sets vertical border characters.\n     *\n     * <code>\n     * ╔═══════════════╤══════════════════════════╤══════════════════╗\n     * ║ ISBN          │ Title                    │ Author           ║\n     * ╠═══════1═══════╪══════════════════════════╪══════════════════╣\n     * ║ 99921-58-10-7 │ Divine Comedy            │ Dante Alighieri  ║\n     * ║ 9971-5-0210-0 │ A Tale of Two Cities     │ Charles Dickens  ║\n     * ╟───────2───────┼──────────────────────────┼──────────────────╢\n     * ║ 960-425-059-0 │ The Lord of the Rings    │ J. R. R. Tolkien ║\n     * ║ 80-902734-1-6 │ And Then There Were None │ Agatha Christie  ║\n     * ╚═══════════════╧══════════════════════════╧══════════════════╝\n     * </code>\n     *\n     * @return $this\n     */\n    public function setVerticalBorderChars(string $outside, ?string $inside = null): self\n    {\n        $this->verticalOutsideBorderChar = $outside;\n        $this->verticalInsideBorderChar = $inside ?? $outside;\n\n        return $this;\n    }\n\n    /**\n     * Gets border characters.\n     *\n     * @internal\n     */\n    public function getBorderChars(): array\n    {\n        return [\n            $this->horizontalOutsideBorderChar,\n            $this->verticalOutsideBorderChar,\n            $this->horizontalInsideBorderChar,\n            $this->verticalInsideBorderChar,\n        ];\n    }\n\n    /**\n     * Sets crossing characters.\n     *\n     * Example:\n     * <code>\n     * 1═══════════════2══════════════════════════2══════════════════3\n     * ║ ISBN          │ Title                    │ Author           ║\n     * 8'══════════════0'═════════════════════════0'═════════════════4'\n     * ║ 99921-58-10-7 │ Divine Comedy            │ Dante Alighieri  ║\n     * ║ 9971-5-0210-0 │ A Tale of Two Cities     │ Charles Dickens  ║\n     * 8───────────────0──────────────────────────0──────────────────4\n     * ║ 960-425-059-0 │ The Lord of the Rings    │ J. R. R. Tolkien ║\n     * ║ 80-902734-1-6 │ And Then There Were None │ Agatha Christie  ║\n     * 7═══════════════6══════════════════════════6══════════════════5\n     * </code>\n     *\n     * @param string      $cross          Crossing char (see #0 of example)\n     * @param string      $topLeft        Top left char (see #1 of example)\n     * @param string      $topMid         Top mid char (see #2 of example)\n     * @param string      $topRight       Top right char (see #3 of example)\n     * @param string      $midRight       Mid right char (see #4 of example)\n     * @param string      $bottomRight    Bottom right char (see #5 of example)\n     * @param string      $bottomMid      Bottom mid char (see #6 of example)\n     * @param string      $bottomLeft     Bottom left char (see #7 of example)\n     * @param string      $midLeft        Mid left char (see #8 of example)\n     * @param string|null $topLeftBottom  Top left bottom char (see #8' of example), equals to $midLeft if null\n     * @param string|null $topMidBottom   Top mid bottom char (see #0' of example), equals to $cross if null\n     * @param string|null $topRightBottom Top right bottom char (see #4' of example), equals to $midRight if null\n     *\n     * @return $this\n     */\n    public function setCrossingChars(string $cross, string $topLeft, string $topMid, string $topRight, string $midRight, string $bottomRight, string $bottomMid, string $bottomLeft, string $midLeft, ?string $topLeftBottom = null, ?string $topMidBottom = null, ?string $topRightBottom = null): self\n    {\n        $this->crossingChar = $cross;\n        $this->crossingTopLeftChar = $topLeft;\n        $this->crossingTopMidChar = $topMid;\n        $this->crossingTopRightChar = $topRight;\n        $this->crossingMidRightChar = $midRight;\n        $this->crossingBottomRightChar = $bottomRight;\n        $this->crossingBottomMidChar = $bottomMid;\n        $this->crossingBottomLeftChar = $bottomLeft;\n        $this->crossingMidLeftChar = $midLeft;\n        $this->crossingTopLeftBottomChar = $topLeftBottom ?? $midLeft;\n        $this->crossingTopMidBottomChar = $topMidBottom ?? $cross;\n        $this->crossingTopRightBottomChar = $topRightBottom ?? $midRight;\n\n        return $this;\n    }\n\n    /**\n     * Sets default crossing character used for each cross.\n     *\n     * @see {@link setCrossingChars()} for setting each crossing individually.\n     */\n    public function setDefaultCrossingChar(string $char): self\n    {\n        return $this->setCrossingChars($char, $char, $char, $char, $char, $char, $char, $char, $char);\n    }\n\n    /**\n     * Gets crossing character.\n     *\n     * @return string\n     */\n    public function getCrossingChar()\n    {\n        return $this->crossingChar;\n    }\n\n    /**\n     * Gets crossing characters.\n     *\n     * @internal\n     */\n    public function getCrossingChars(): array\n    {\n        return [\n            $this->crossingChar,\n            $this->crossingTopLeftChar,\n            $this->crossingTopMidChar,\n            $this->crossingTopRightChar,\n            $this->crossingMidRightChar,\n            $this->crossingBottomRightChar,\n            $this->crossingBottomMidChar,\n            $this->crossingBottomLeftChar,\n            $this->crossingMidLeftChar,\n            $this->crossingTopLeftBottomChar,\n            $this->crossingTopMidBottomChar,\n            $this->crossingTopRightBottomChar,\n        ];\n    }\n\n    /**\n     * Sets header cell format.\n     *\n     * @return $this\n     */\n    public function setCellHeaderFormat(string $cellHeaderFormat)\n    {\n        $this->cellHeaderFormat = $cellHeaderFormat;\n\n        return $this;\n    }\n\n    /**\n     * Gets header cell format.\n     *\n     * @return string\n     */\n    public function getCellHeaderFormat()\n    {\n        return $this->cellHeaderFormat;\n    }\n\n    /**\n     * Sets row cell format.\n     *\n     * @return $this\n     */\n    public function setCellRowFormat(string $cellRowFormat)\n    {\n        $this->cellRowFormat = $cellRowFormat;\n\n        return $this;\n    }\n\n    /**\n     * Gets row cell format.\n     *\n     * @return string\n     */\n    public function getCellRowFormat()\n    {\n        return $this->cellRowFormat;\n    }\n\n    /**\n     * Sets row cell content format.\n     *\n     * @return $this\n     */\n    public function setCellRowContentFormat(string $cellRowContentFormat)\n    {\n        $this->cellRowContentFormat = $cellRowContentFormat;\n\n        return $this;\n    }\n\n    /**\n     * Gets row cell content format.\n     *\n     * @return string\n     */\n    public function getCellRowContentFormat()\n    {\n        return $this->cellRowContentFormat;\n    }\n\n    /**\n     * Sets table border format.\n     *\n     * @return $this\n     */\n    public function setBorderFormat(string $borderFormat)\n    {\n        $this->borderFormat = $borderFormat;\n\n        return $this;\n    }\n\n    /**\n     * Gets table border format.\n     *\n     * @return string\n     */\n    public function getBorderFormat()\n    {\n        return $this->borderFormat;\n    }\n\n    /**\n     * Sets cell padding type.\n     *\n     * @return $this\n     */\n    public function setPadType(int $padType)\n    {\n        if (!\\in_array($padType, [\\STR_PAD_LEFT, \\STR_PAD_RIGHT, \\STR_PAD_BOTH], true)) {\n            throw new InvalidArgumentException('Invalid padding type. Expected one of (STR_PAD_LEFT, STR_PAD_RIGHT, STR_PAD_BOTH).');\n        }\n\n        $this->padType = $padType;\n\n        return $this;\n    }\n\n    /**\n     * Gets cell padding type.\n     *\n     * @return int\n     */\n    public function getPadType()\n    {\n        return $this->padType;\n    }\n\n    public function getHeaderTitleFormat(): string\n    {\n        return $this->headerTitleFormat;\n    }\n\n    /**\n     * @return $this\n     */\n    public function setHeaderTitleFormat(string $format): self\n    {\n        $this->headerTitleFormat = $format;\n\n        return $this;\n    }\n\n    public function getFooterTitleFormat(): string\n    {\n        return $this->footerTitleFormat;\n    }\n\n    /**\n     * @return $this\n     */\n    public function setFooterTitleFormat(string $format): self\n    {\n        $this->footerTitleFormat = $format;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Input/ArgvInput.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Input;\n\nuse Symfony\\Component\\Console\\Exception\\RuntimeException;\n\n/**\n * ArgvInput represents an input coming from the CLI arguments.\n *\n * Usage:\n *\n *     $input = new ArgvInput();\n *\n * By default, the `$_SERVER['argv']` array is used for the input values.\n *\n * This can be overridden by explicitly passing the input values in the constructor:\n *\n *     $input = new ArgvInput($_SERVER['argv']);\n *\n * If you pass it yourself, don't forget that the first element of the array\n * is the name of the running application.\n *\n * When passing an argument to the constructor, be sure that it respects\n * the same rules as the argv one. It's almost always better to use the\n * `StringInput` when you want to provide your own input.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n *\n * @see http://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html\n * @see http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap12.html#tag_12_02\n */\nclass ArgvInput extends Input\n{\n    private $tokens;\n    private $parsed;\n\n    public function __construct(?array $argv = null, ?InputDefinition $definition = null)\n    {\n        $argv = $argv ?? $_SERVER['argv'] ?? [];\n\n        // strip the application name\n        array_shift($argv);\n\n        $this->tokens = $argv;\n\n        parent::__construct($definition);\n    }\n\n    protected function setTokens(array $tokens)\n    {\n        $this->tokens = $tokens;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    protected function parse()\n    {\n        $parseOptions = true;\n        $this->parsed = $this->tokens;\n        while (null !== $token = array_shift($this->parsed)) {\n            $parseOptions = $this->parseToken($token, $parseOptions);\n        }\n    }\n\n    protected function parseToken(string $token, bool $parseOptions): bool\n    {\n        if ($parseOptions && '' == $token) {\n            $this->parseArgument($token);\n        } elseif ($parseOptions && '--' == $token) {\n            return false;\n        } elseif ($parseOptions && str_starts_with($token, '--')) {\n            $this->parseLongOption($token);\n        } elseif ($parseOptions && '-' === $token[0] && '-' !== $token) {\n            $this->parseShortOption($token);\n        } else {\n            $this->parseArgument($token);\n        }\n\n        return $parseOptions;\n    }\n\n    /**\n     * Parses a short option.\n     */\n    private function parseShortOption(string $token)\n    {\n        $name = substr($token, 1);\n\n        if (\\strlen($name) > 1) {\n            if ($this->definition->hasShortcut($name[0]) && $this->definition->getOptionForShortcut($name[0])->acceptValue()) {\n                // an option with a value (with no space)\n                $this->addShortOption($name[0], substr($name, 1));\n            } else {\n                $this->parseShortOptionSet($name);\n            }\n        } else {\n            $this->addShortOption($name, null);\n        }\n    }\n\n    /**\n     * Parses a short option set.\n     *\n     * @throws RuntimeException When option given doesn't exist\n     */\n    private function parseShortOptionSet(string $name)\n    {\n        $len = \\strlen($name);\n        for ($i = 0; $i < $len; ++$i) {\n            if (!$this->definition->hasShortcut($name[$i])) {\n                $encoding = mb_detect_encoding($name, null, true);\n                throw new RuntimeException(sprintf('The \"-%s\" option does not exist.', false === $encoding ? $name[$i] : mb_substr($name, $i, 1, $encoding)));\n            }\n\n            $option = $this->definition->getOptionForShortcut($name[$i]);\n            if ($option->acceptValue()) {\n                $this->addLongOption($option->getName(), $i === $len - 1 ? null : substr($name, $i + 1));\n\n                break;\n            } else {\n                $this->addLongOption($option->getName(), null);\n            }\n        }\n    }\n\n    /**\n     * Parses a long option.\n     */\n    private function parseLongOption(string $token)\n    {\n        $name = substr($token, 2);\n\n        if (false !== $pos = strpos($name, '=')) {\n            if ('' === $value = substr($name, $pos + 1)) {\n                array_unshift($this->parsed, $value);\n            }\n            $this->addLongOption(substr($name, 0, $pos), $value);\n        } else {\n            $this->addLongOption($name, null);\n        }\n    }\n\n    /**\n     * Parses an argument.\n     *\n     * @throws RuntimeException When too many arguments are given\n     */\n    private function parseArgument(string $token)\n    {\n        $c = \\count($this->arguments);\n\n        // if input is expecting another argument, add it\n        if ($this->definition->hasArgument($c)) {\n            $arg = $this->definition->getArgument($c);\n            $this->arguments[$arg->getName()] = $arg->isArray() ? [$token] : $token;\n\n        // if last argument isArray(), append token to last argument\n        } elseif ($this->definition->hasArgument($c - 1) && $this->definition->getArgument($c - 1)->isArray()) {\n            $arg = $this->definition->getArgument($c - 1);\n            $this->arguments[$arg->getName()][] = $token;\n\n        // unexpected argument\n        } else {\n            $all = $this->definition->getArguments();\n            $symfonyCommandName = null;\n            if (($inputArgument = $all[$key = array_key_first($all)] ?? null) && 'command' === $inputArgument->getName()) {\n                $symfonyCommandName = $this->arguments['command'] ?? null;\n                unset($all[$key]);\n            }\n\n            if (\\count($all)) {\n                if ($symfonyCommandName) {\n                    $message = sprintf('Too many arguments to \"%s\" command, expected arguments \"%s\".', $symfonyCommandName, implode('\" \"', array_keys($all)));\n                } else {\n                    $message = sprintf('Too many arguments, expected arguments \"%s\".', implode('\" \"', array_keys($all)));\n                }\n            } elseif ($symfonyCommandName) {\n                $message = sprintf('No arguments expected for \"%s\" command, got \"%s\".', $symfonyCommandName, $token);\n            } else {\n                $message = sprintf('No arguments expected, got \"%s\".', $token);\n            }\n\n            throw new RuntimeException($message);\n        }\n    }\n\n    /**\n     * Adds a short option value.\n     *\n     * @throws RuntimeException When option given doesn't exist\n     */\n    private function addShortOption(string $shortcut, $value)\n    {\n        if (!$this->definition->hasShortcut($shortcut)) {\n            throw new RuntimeException(sprintf('The \"-%s\" option does not exist.', $shortcut));\n        }\n\n        $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value);\n    }\n\n    /**\n     * Adds a long option value.\n     *\n     * @throws RuntimeException When option given doesn't exist\n     */\n    private function addLongOption(string $name, $value)\n    {\n        if (!$this->definition->hasOption($name)) {\n            if (!$this->definition->hasNegation($name)) {\n                throw new RuntimeException(sprintf('The \"--%s\" option does not exist.', $name));\n            }\n\n            $optionName = $this->definition->negationToName($name);\n            if (null !== $value) {\n                throw new RuntimeException(sprintf('The \"--%s\" option does not accept a value.', $name));\n            }\n            $this->options[$optionName] = false;\n\n            return;\n        }\n\n        $option = $this->definition->getOption($name);\n\n        if (null !== $value && !$option->acceptValue()) {\n            throw new RuntimeException(sprintf('The \"--%s\" option does not accept a value.', $name));\n        }\n\n        if (\\in_array($value, ['', null], true) && $option->acceptValue() && \\count($this->parsed)) {\n            // if option accepts an optional or mandatory argument\n            // let's see if there is one provided\n            $next = array_shift($this->parsed);\n            if ((isset($next[0]) && '-' !== $next[0]) || \\in_array($next, ['', null], true)) {\n                $value = $next;\n            } else {\n                array_unshift($this->parsed, $next);\n            }\n        }\n\n        if (null === $value) {\n            if ($option->isValueRequired()) {\n                throw new RuntimeException(sprintf('The \"--%s\" option requires a value.', $name));\n            }\n\n            if (!$option->isArray() && !$option->isValueOptional()) {\n                $value = true;\n            }\n        }\n\n        if ($option->isArray()) {\n            $this->options[$name][] = $value;\n        } else {\n            $this->options[$name] = $value;\n        }\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getFirstArgument()\n    {\n        $isOption = false;\n        foreach ($this->tokens as $i => $token) {\n            if ($token && '-' === $token[0]) {\n                if (str_contains($token, '=') || !isset($this->tokens[$i + 1])) {\n                    continue;\n                }\n\n                // If it's a long option, consider that everything after \"--\" is the option name.\n                // Otherwise, use the last char (if it's a short option set, only the last one can take a value with space separator)\n                $name = '-' === $token[1] ? substr($token, 2) : substr($token, -1);\n                if (!isset($this->options[$name]) && !$this->definition->hasShortcut($name)) {\n                    // noop\n                } elseif ((isset($this->options[$name]) || isset($this->options[$name = $this->definition->shortcutToName($name)])) && $this->tokens[$i + 1] === $this->options[$name]) {\n                    $isOption = true;\n                }\n\n                continue;\n            }\n\n            if ($isOption) {\n                $isOption = false;\n                continue;\n            }\n\n            return $token;\n        }\n\n        return null;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function hasParameterOption($values, bool $onlyParams = false)\n    {\n        $values = (array) $values;\n\n        foreach ($this->tokens as $token) {\n            if ($onlyParams && '--' === $token) {\n                return false;\n            }\n            foreach ($values as $value) {\n                // Options with values:\n                //   For long options, test for '--option=' at beginning\n                //   For short options, test for '-o' at beginning\n                $leading = str_starts_with($value, '--') ? $value.'=' : $value;\n                if ($token === $value || '' !== $leading && str_starts_with($token, $leading)) {\n                    return true;\n                }\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getParameterOption($values, $default = false, bool $onlyParams = false)\n    {\n        $values = (array) $values;\n        $tokens = $this->tokens;\n\n        while (0 < \\count($tokens)) {\n            $token = array_shift($tokens);\n            if ($onlyParams && '--' === $token) {\n                return $default;\n            }\n\n            foreach ($values as $value) {\n                if ($token === $value) {\n                    return array_shift($tokens);\n                }\n                // Options with values:\n                //   For long options, test for '--option=' at beginning\n                //   For short options, test for '-o' at beginning\n                $leading = str_starts_with($value, '--') ? $value.'=' : $value;\n                if ('' !== $leading && str_starts_with($token, $leading)) {\n                    return substr($token, \\strlen($leading));\n                }\n            }\n        }\n\n        return $default;\n    }\n\n    /**\n     * Returns a stringified representation of the args passed to the command.\n     *\n     * @return string\n     */\n    public function __toString()\n    {\n        $tokens = array_map(function ($token) {\n            if (preg_match('{^(-[^=]+=)(.+)}', $token, $match)) {\n                return $match[1].$this->escapeToken($match[2]);\n            }\n\n            if ($token && '-' !== $token[0]) {\n                return $this->escapeToken($token);\n            }\n\n            return $token;\n        }, $this->tokens);\n\n        return implode(' ', $tokens);\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Input/ArrayInput.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Input;\n\nuse Symfony\\Component\\Console\\Exception\\InvalidArgumentException;\nuse Symfony\\Component\\Console\\Exception\\InvalidOptionException;\n\n/**\n * ArrayInput represents an input provided as an array.\n *\n * Usage:\n *\n *     $input = new ArrayInput(['command' => 'foo:bar', 'foo' => 'bar', '--bar' => 'foobar']);\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass ArrayInput extends Input\n{\n    private $parameters;\n\n    public function __construct(array $parameters, ?InputDefinition $definition = null)\n    {\n        $this->parameters = $parameters;\n\n        parent::__construct($definition);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getFirstArgument()\n    {\n        foreach ($this->parameters as $param => $value) {\n            if ($param && \\is_string($param) && '-' === $param[0]) {\n                continue;\n            }\n\n            return $value;\n        }\n\n        return null;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function hasParameterOption($values, bool $onlyParams = false)\n    {\n        $values = (array) $values;\n\n        foreach ($this->parameters as $k => $v) {\n            if (!\\is_int($k)) {\n                $v = $k;\n            }\n\n            if ($onlyParams && '--' === $v) {\n                return false;\n            }\n\n            if (\\in_array($v, $values)) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getParameterOption($values, $default = false, bool $onlyParams = false)\n    {\n        $values = (array) $values;\n\n        foreach ($this->parameters as $k => $v) {\n            if ($onlyParams && ('--' === $k || (\\is_int($k) && '--' === $v))) {\n                return $default;\n            }\n\n            if (\\is_int($k)) {\n                if (\\in_array($v, $values)) {\n                    return true;\n                }\n            } elseif (\\in_array($k, $values)) {\n                return $v;\n            }\n        }\n\n        return $default;\n    }\n\n    /**\n     * Returns a stringified representation of the args passed to the command.\n     *\n     * @return string\n     */\n    public function __toString()\n    {\n        $params = [];\n        foreach ($this->parameters as $param => $val) {\n            if ($param && \\is_string($param) && '-' === $param[0]) {\n                $glue = ('-' === $param[1]) ? '=' : ' ';\n                if (\\is_array($val)) {\n                    foreach ($val as $v) {\n                        $params[] = $param.('' != $v ? $glue.$this->escapeToken($v) : '');\n                    }\n                } else {\n                    $params[] = $param.('' != $val ? $glue.$this->escapeToken($val) : '');\n                }\n            } else {\n                $params[] = \\is_array($val) ? implode(' ', array_map([$this, 'escapeToken'], $val)) : $this->escapeToken($val);\n            }\n        }\n\n        return implode(' ', $params);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    protected function parse()\n    {\n        foreach ($this->parameters as $key => $value) {\n            if ('--' === $key) {\n                return;\n            }\n            if (str_starts_with($key, '--')) {\n                $this->addLongOption(substr($key, 2), $value);\n            } elseif (str_starts_with($key, '-')) {\n                $this->addShortOption(substr($key, 1), $value);\n            } else {\n                $this->addArgument($key, $value);\n            }\n        }\n    }\n\n    /**\n     * Adds a short option value.\n     *\n     * @throws InvalidOptionException When option given doesn't exist\n     */\n    private function addShortOption(string $shortcut, $value)\n    {\n        if (!$this->definition->hasShortcut($shortcut)) {\n            throw new InvalidOptionException(sprintf('The \"-%s\" option does not exist.', $shortcut));\n        }\n\n        $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value);\n    }\n\n    /**\n     * Adds a long option value.\n     *\n     * @throws InvalidOptionException When option given doesn't exist\n     * @throws InvalidOptionException When a required value is missing\n     */\n    private function addLongOption(string $name, $value)\n    {\n        if (!$this->definition->hasOption($name)) {\n            if (!$this->definition->hasNegation($name)) {\n                throw new InvalidOptionException(sprintf('The \"--%s\" option does not exist.', $name));\n            }\n\n            $optionName = $this->definition->negationToName($name);\n            $this->options[$optionName] = false;\n\n            return;\n        }\n\n        $option = $this->definition->getOption($name);\n\n        if (null === $value) {\n            if ($option->isValueRequired()) {\n                throw new InvalidOptionException(sprintf('The \"--%s\" option requires a value.', $name));\n            }\n\n            if (!$option->isValueOptional()) {\n                $value = true;\n            }\n        }\n\n        $this->options[$name] = $value;\n    }\n\n    /**\n     * Adds an argument value.\n     *\n     * @param string|int $name  The argument name\n     * @param mixed      $value The value for the argument\n     *\n     * @throws InvalidArgumentException When argument given doesn't exist\n     */\n    private function addArgument($name, $value)\n    {\n        if (!$this->definition->hasArgument($name)) {\n            throw new InvalidArgumentException(sprintf('The \"%s\" argument does not exist.', $name));\n        }\n\n        $this->arguments[$name] = $value;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Input/Input.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Input;\n\nuse Symfony\\Component\\Console\\Exception\\InvalidArgumentException;\nuse Symfony\\Component\\Console\\Exception\\RuntimeException;\n\n/**\n * Input is the base class for all concrete Input classes.\n *\n * Three concrete classes are provided by default:\n *\n *  * `ArgvInput`: The input comes from the CLI arguments (argv)\n *  * `StringInput`: The input is provided as a string\n *  * `ArrayInput`: The input is provided as an array\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nabstract class Input implements InputInterface, StreamableInputInterface\n{\n    protected $definition;\n    protected $stream;\n    protected $options = [];\n    protected $arguments = [];\n    protected $interactive = true;\n\n    public function __construct(?InputDefinition $definition = null)\n    {\n        if (null === $definition) {\n            $this->definition = new InputDefinition();\n        } else {\n            $this->bind($definition);\n            $this->validate();\n        }\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function bind(InputDefinition $definition)\n    {\n        $this->arguments = [];\n        $this->options = [];\n        $this->definition = $definition;\n\n        $this->parse();\n    }\n\n    /**\n     * Processes command line arguments.\n     */\n    abstract protected function parse();\n\n    /**\n     * {@inheritdoc}\n     */\n    public function validate()\n    {\n        $definition = $this->definition;\n        $givenArguments = $this->arguments;\n\n        $missingArguments = array_filter(array_keys($definition->getArguments()), function ($argument) use ($definition, $givenArguments) {\n            return !\\array_key_exists($argument, $givenArguments) && $definition->getArgument($argument)->isRequired();\n        });\n\n        if (\\count($missingArguments) > 0) {\n            throw new RuntimeException(sprintf('Not enough arguments (missing: \"%s\").', implode(', ', $missingArguments)));\n        }\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function isInteractive()\n    {\n        return $this->interactive;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function setInteractive(bool $interactive)\n    {\n        $this->interactive = $interactive;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getArguments()\n    {\n        return array_merge($this->definition->getArgumentDefaults(), $this->arguments);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getArgument(string $name)\n    {\n        if (!$this->definition->hasArgument($name)) {\n            throw new InvalidArgumentException(sprintf('The \"%s\" argument does not exist.', $name));\n        }\n\n        return $this->arguments[$name] ?? $this->definition->getArgument($name)->getDefault();\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function setArgument(string $name, $value)\n    {\n        if (!$this->definition->hasArgument($name)) {\n            throw new InvalidArgumentException(sprintf('The \"%s\" argument does not exist.', $name));\n        }\n\n        $this->arguments[$name] = $value;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function hasArgument(string $name)\n    {\n        return $this->definition->hasArgument($name);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getOptions()\n    {\n        return array_merge($this->definition->getOptionDefaults(), $this->options);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getOption(string $name)\n    {\n        if ($this->definition->hasNegation($name)) {\n            if (null === $value = $this->getOption($this->definition->negationToName($name))) {\n                return $value;\n            }\n\n            return !$value;\n        }\n\n        if (!$this->definition->hasOption($name)) {\n            throw new InvalidArgumentException(sprintf('The \"%s\" option does not exist.', $name));\n        }\n\n        return \\array_key_exists($name, $this->options) ? $this->options[$name] : $this->definition->getOption($name)->getDefault();\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function setOption(string $name, $value)\n    {\n        if ($this->definition->hasNegation($name)) {\n            $this->options[$this->definition->negationToName($name)] = !$value;\n\n            return;\n        } elseif (!$this->definition->hasOption($name)) {\n            throw new InvalidArgumentException(sprintf('The \"%s\" option does not exist.', $name));\n        }\n\n        $this->options[$name] = $value;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function hasOption(string $name)\n    {\n        return $this->definition->hasOption($name) || $this->definition->hasNegation($name);\n    }\n\n    /**\n     * Escapes a token through escapeshellarg if it contains unsafe chars.\n     *\n     * @return string\n     */\n    public function escapeToken(string $token)\n    {\n        return preg_match('{^[\\w-]+$}', $token) ? $token : escapeshellarg($token);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function setStream($stream)\n    {\n        $this->stream = $stream;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getStream()\n    {\n        return $this->stream;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Input/InputArgument.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Input;\n\nuse Symfony\\Component\\Console\\Exception\\InvalidArgumentException;\nuse Symfony\\Component\\Console\\Exception\\LogicException;\n\n/**\n * Represents a command line argument.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass InputArgument\n{\n    public const REQUIRED = 1;\n    public const OPTIONAL = 2;\n    public const IS_ARRAY = 4;\n\n    private $name;\n    private $mode;\n    private $default;\n    private $description;\n\n    /**\n     * @param string                           $name        The argument name\n     * @param int|null                         $mode        The argument mode: a bit mask of self::REQUIRED, self::OPTIONAL and self::IS_ARRAY\n     * @param string                           $description A description text\n     * @param string|bool|int|float|array|null $default     The default value (for self::OPTIONAL mode only)\n     *\n     * @throws InvalidArgumentException When argument mode is not valid\n     */\n    public function __construct(string $name, ?int $mode = null, string $description = '', $default = null)\n    {\n        if (null === $mode) {\n            $mode = self::OPTIONAL;\n        } elseif ($mode > 7 || $mode < 1) {\n            throw new InvalidArgumentException(sprintf('Argument mode \"%s\" is not valid.', $mode));\n        }\n\n        $this->name = $name;\n        $this->mode = $mode;\n        $this->description = $description;\n\n        $this->setDefault($default);\n    }\n\n    /**\n     * Returns the argument name.\n     *\n     * @return string\n     */\n    public function getName()\n    {\n        return $this->name;\n    }\n\n    /**\n     * Returns true if the argument is required.\n     *\n     * @return bool true if parameter mode is self::REQUIRED, false otherwise\n     */\n    public function isRequired()\n    {\n        return self::REQUIRED === (self::REQUIRED & $this->mode);\n    }\n\n    /**\n     * Returns true if the argument can take multiple values.\n     *\n     * @return bool true if mode is self::IS_ARRAY, false otherwise\n     */\n    public function isArray()\n    {\n        return self::IS_ARRAY === (self::IS_ARRAY & $this->mode);\n    }\n\n    /**\n     * Sets the default value.\n     *\n     * @param string|bool|int|float|array|null $default\n     *\n     * @throws LogicException When incorrect default value is given\n     */\n    public function setDefault($default = null)\n    {\n        if ($this->isRequired() && null !== $default) {\n            throw new LogicException('Cannot set a default value except for InputArgument::OPTIONAL mode.');\n        }\n\n        if ($this->isArray()) {\n            if (null === $default) {\n                $default = [];\n            } elseif (!\\is_array($default)) {\n                throw new LogicException('A default value for an array argument must be an array.');\n            }\n        }\n\n        $this->default = $default;\n    }\n\n    /**\n     * Returns the default value.\n     *\n     * @return string|bool|int|float|array|null\n     */\n    public function getDefault()\n    {\n        return $this->default;\n    }\n\n    /**\n     * Returns the description text.\n     *\n     * @return string\n     */\n    public function getDescription()\n    {\n        return $this->description;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Input/InputAwareInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Input;\n\n/**\n * InputAwareInterface should be implemented by classes that depends on the\n * Console Input.\n *\n * @author Wouter J <waldio.webdesign@gmail.com>\n */\ninterface InputAwareInterface\n{\n    /**\n     * Sets the Console Input.\n     */\n    public function setInput(InputInterface $input);\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Input/InputDefinition.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Input;\n\nuse Symfony\\Component\\Console\\Exception\\InvalidArgumentException;\nuse Symfony\\Component\\Console\\Exception\\LogicException;\n\n/**\n * A InputDefinition represents a set of valid command line arguments and options.\n *\n * Usage:\n *\n *     $definition = new InputDefinition([\n *         new InputArgument('name', InputArgument::REQUIRED),\n *         new InputOption('foo', 'f', InputOption::VALUE_REQUIRED),\n *     ]);\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass InputDefinition\n{\n    private $arguments;\n    private $requiredCount;\n    private $lastArrayArgument;\n    private $lastOptionalArgument;\n    private $options;\n    private $negations;\n    private $shortcuts;\n\n    /**\n     * @param array $definition An array of InputArgument and InputOption instance\n     */\n    public function __construct(array $definition = [])\n    {\n        $this->setDefinition($definition);\n    }\n\n    /**\n     * Sets the definition of the input.\n     */\n    public function setDefinition(array $definition)\n    {\n        $arguments = [];\n        $options = [];\n        foreach ($definition as $item) {\n            if ($item instanceof InputOption) {\n                $options[] = $item;\n            } else {\n                $arguments[] = $item;\n            }\n        }\n\n        $this->setArguments($arguments);\n        $this->setOptions($options);\n    }\n\n    /**\n     * Sets the InputArgument objects.\n     *\n     * @param InputArgument[] $arguments An array of InputArgument objects\n     */\n    public function setArguments(array $arguments = [])\n    {\n        $this->arguments = [];\n        $this->requiredCount = 0;\n        $this->lastOptionalArgument = null;\n        $this->lastArrayArgument = null;\n        $this->addArguments($arguments);\n    }\n\n    /**\n     * Adds an array of InputArgument objects.\n     *\n     * @param InputArgument[] $arguments An array of InputArgument objects\n     */\n    public function addArguments(?array $arguments = [])\n    {\n        if (null !== $arguments) {\n            foreach ($arguments as $argument) {\n                $this->addArgument($argument);\n            }\n        }\n    }\n\n    /**\n     * @throws LogicException When incorrect argument is given\n     */\n    public function addArgument(InputArgument $argument)\n    {\n        if (isset($this->arguments[$argument->getName()])) {\n            throw new LogicException(sprintf('An argument with name \"%s\" already exists.', $argument->getName()));\n        }\n\n        if (null !== $this->lastArrayArgument) {\n            throw new LogicException(sprintf('Cannot add a required argument \"%s\" after an array argument \"%s\".', $argument->getName(), $this->lastArrayArgument->getName()));\n        }\n\n        if ($argument->isRequired() && null !== $this->lastOptionalArgument) {\n            throw new LogicException(sprintf('Cannot add a required argument \"%s\" after an optional one \"%s\".', $argument->getName(), $this->lastOptionalArgument->getName()));\n        }\n\n        if ($argument->isArray()) {\n            $this->lastArrayArgument = $argument;\n        }\n\n        if ($argument->isRequired()) {\n            ++$this->requiredCount;\n        } else {\n            $this->lastOptionalArgument = $argument;\n        }\n\n        $this->arguments[$argument->getName()] = $argument;\n    }\n\n    /**\n     * Returns an InputArgument by name or by position.\n     *\n     * @param string|int $name The InputArgument name or position\n     *\n     * @return InputArgument\n     *\n     * @throws InvalidArgumentException When argument given doesn't exist\n     */\n    public function getArgument($name)\n    {\n        if (!$this->hasArgument($name)) {\n            throw new InvalidArgumentException(sprintf('The \"%s\" argument does not exist.', $name));\n        }\n\n        $arguments = \\is_int($name) ? array_values($this->arguments) : $this->arguments;\n\n        return $arguments[$name];\n    }\n\n    /**\n     * Returns true if an InputArgument object exists by name or position.\n     *\n     * @param string|int $name The InputArgument name or position\n     *\n     * @return bool\n     */\n    public function hasArgument($name)\n    {\n        $arguments = \\is_int($name) ? array_values($this->arguments) : $this->arguments;\n\n        return isset($arguments[$name]);\n    }\n\n    /**\n     * Gets the array of InputArgument objects.\n     *\n     * @return InputArgument[]\n     */\n    public function getArguments()\n    {\n        return $this->arguments;\n    }\n\n    /**\n     * Returns the number of InputArguments.\n     *\n     * @return int\n     */\n    public function getArgumentCount()\n    {\n        return null !== $this->lastArrayArgument ? \\PHP_INT_MAX : \\count($this->arguments);\n    }\n\n    /**\n     * Returns the number of required InputArguments.\n     *\n     * @return int\n     */\n    public function getArgumentRequiredCount()\n    {\n        return $this->requiredCount;\n    }\n\n    /**\n     * @return array<string|bool|int|float|array|null>\n     */\n    public function getArgumentDefaults()\n    {\n        $values = [];\n        foreach ($this->arguments as $argument) {\n            $values[$argument->getName()] = $argument->getDefault();\n        }\n\n        return $values;\n    }\n\n    /**\n     * Sets the InputOption objects.\n     *\n     * @param InputOption[] $options An array of InputOption objects\n     */\n    public function setOptions(array $options = [])\n    {\n        $this->options = [];\n        $this->shortcuts = [];\n        $this->negations = [];\n        $this->addOptions($options);\n    }\n\n    /**\n     * Adds an array of InputOption objects.\n     *\n     * @param InputOption[] $options An array of InputOption objects\n     */\n    public function addOptions(array $options = [])\n    {\n        foreach ($options as $option) {\n            $this->addOption($option);\n        }\n    }\n\n    /**\n     * @throws LogicException When option given already exist\n     */\n    public function addOption(InputOption $option)\n    {\n        if (isset($this->options[$option->getName()]) && !$option->equals($this->options[$option->getName()])) {\n            throw new LogicException(sprintf('An option named \"%s\" already exists.', $option->getName()));\n        }\n        if (isset($this->negations[$option->getName()])) {\n            throw new LogicException(sprintf('An option named \"%s\" already exists.', $option->getName()));\n        }\n\n        if ($option->getShortcut()) {\n            foreach (explode('|', $option->getShortcut()) as $shortcut) {\n                if (isset($this->shortcuts[$shortcut]) && !$option->equals($this->options[$this->shortcuts[$shortcut]])) {\n                    throw new LogicException(sprintf('An option with shortcut \"%s\" already exists.', $shortcut));\n                }\n            }\n        }\n\n        $this->options[$option->getName()] = $option;\n        if ($option->getShortcut()) {\n            foreach (explode('|', $option->getShortcut()) as $shortcut) {\n                $this->shortcuts[$shortcut] = $option->getName();\n            }\n        }\n\n        if ($option->isNegatable()) {\n            $negatedName = 'no-'.$option->getName();\n            if (isset($this->options[$negatedName])) {\n                throw new LogicException(sprintf('An option named \"%s\" already exists.', $negatedName));\n            }\n            $this->negations[$negatedName] = $option->getName();\n        }\n    }\n\n    /**\n     * Returns an InputOption by name.\n     *\n     * @return InputOption\n     *\n     * @throws InvalidArgumentException When option given doesn't exist\n     */\n    public function getOption(string $name)\n    {\n        if (!$this->hasOption($name)) {\n            throw new InvalidArgumentException(sprintf('The \"--%s\" option does not exist.', $name));\n        }\n\n        return $this->options[$name];\n    }\n\n    /**\n     * Returns true if an InputOption object exists by name.\n     *\n     * This method can't be used to check if the user included the option when\n     * executing the command (use getOption() instead).\n     *\n     * @return bool\n     */\n    public function hasOption(string $name)\n    {\n        return isset($this->options[$name]);\n    }\n\n    /**\n     * Gets the array of InputOption objects.\n     *\n     * @return InputOption[]\n     */\n    public function getOptions()\n    {\n        return $this->options;\n    }\n\n    /**\n     * Returns true if an InputOption object exists by shortcut.\n     *\n     * @return bool\n     */\n    public function hasShortcut(string $name)\n    {\n        return isset($this->shortcuts[$name]);\n    }\n\n    /**\n     * Returns true if an InputOption object exists by negated name.\n     */\n    public function hasNegation(string $name): bool\n    {\n        return isset($this->negations[$name]);\n    }\n\n    /**\n     * Gets an InputOption by shortcut.\n     *\n     * @return InputOption\n     */\n    public function getOptionForShortcut(string $shortcut)\n    {\n        return $this->getOption($this->shortcutToName($shortcut));\n    }\n\n    /**\n     * @return array<string|bool|int|float|array|null>\n     */\n    public function getOptionDefaults()\n    {\n        $values = [];\n        foreach ($this->options as $option) {\n            $values[$option->getName()] = $option->getDefault();\n        }\n\n        return $values;\n    }\n\n    /**\n     * Returns the InputOption name given a shortcut.\n     *\n     * @throws InvalidArgumentException When option given does not exist\n     *\n     * @internal\n     */\n    public function shortcutToName(string $shortcut): string\n    {\n        if (!isset($this->shortcuts[$shortcut])) {\n            throw new InvalidArgumentException(sprintf('The \"-%s\" option does not exist.', $shortcut));\n        }\n\n        return $this->shortcuts[$shortcut];\n    }\n\n    /**\n     * Returns the InputOption name given a negation.\n     *\n     * @throws InvalidArgumentException When option given does not exist\n     *\n     * @internal\n     */\n    public function negationToName(string $negation): string\n    {\n        if (!isset($this->negations[$negation])) {\n            throw new InvalidArgumentException(sprintf('The \"--%s\" option does not exist.', $negation));\n        }\n\n        return $this->negations[$negation];\n    }\n\n    /**\n     * Gets the synopsis.\n     *\n     * @return string\n     */\n    public function getSynopsis(bool $short = false)\n    {\n        $elements = [];\n\n        if ($short && $this->getOptions()) {\n            $elements[] = '[options]';\n        } elseif (!$short) {\n            foreach ($this->getOptions() as $option) {\n                $value = '';\n                if ($option->acceptValue()) {\n                    $value = sprintf(\n                        ' %s%s%s',\n                        $option->isValueOptional() ? '[' : '',\n                        strtoupper($option->getName()),\n                        $option->isValueOptional() ? ']' : ''\n                    );\n                }\n\n                $shortcut = $option->getShortcut() ? sprintf('-%s|', $option->getShortcut()) : '';\n                $negation = $option->isNegatable() ? sprintf('|--no-%s', $option->getName()) : '';\n                $elements[] = sprintf('[%s--%s%s%s]', $shortcut, $option->getName(), $value, $negation);\n            }\n        }\n\n        if (\\count($elements) && $this->getArguments()) {\n            $elements[] = '[--]';\n        }\n\n        $tail = '';\n        foreach ($this->getArguments() as $argument) {\n            $element = '<'.$argument->getName().'>';\n            if ($argument->isArray()) {\n                $element .= '...';\n            }\n\n            if (!$argument->isRequired()) {\n                $element = '['.$element;\n                $tail .= ']';\n            }\n\n            $elements[] = $element;\n        }\n\n        return implode(' ', $elements).$tail;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Input/InputInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Input;\n\nuse Symfony\\Component\\Console\\Exception\\InvalidArgumentException;\nuse Symfony\\Component\\Console\\Exception\\RuntimeException;\n\n/**\n * InputInterface is the interface implemented by all input classes.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\ninterface InputInterface\n{\n    /**\n     * Returns the first argument from the raw parameters (not parsed).\n     *\n     * @return string|null\n     */\n    public function getFirstArgument();\n\n    /**\n     * Returns true if the raw parameters (not parsed) contain a value.\n     *\n     * This method is to be used to introspect the input parameters\n     * before they have been validated. It must be used carefully.\n     * Does not necessarily return the correct result for short options\n     * when multiple flags are combined in the same option.\n     *\n     * @param string|array $values     The values to look for in the raw parameters (can be an array)\n     * @param bool         $onlyParams Only check real parameters, skip those following an end of options (--) signal\n     *\n     * @return bool\n     */\n    public function hasParameterOption($values, bool $onlyParams = false);\n\n    /**\n     * Returns the value of a raw option (not parsed).\n     *\n     * This method is to be used to introspect the input parameters\n     * before they have been validated. It must be used carefully.\n     * Does not necessarily return the correct result for short options\n     * when multiple flags are combined in the same option.\n     *\n     * @param string|array                     $values     The value(s) to look for in the raw parameters (can be an array)\n     * @param string|bool|int|float|array|null $default    The default value to return if no result is found\n     * @param bool                             $onlyParams Only check real parameters, skip those following an end of options (--) signal\n     *\n     * @return mixed\n     */\n    public function getParameterOption($values, $default = false, bool $onlyParams = false);\n\n    /**\n     * Binds the current Input instance with the given arguments and options.\n     *\n     * @throws RuntimeException\n     */\n    public function bind(InputDefinition $definition);\n\n    /**\n     * Validates the input.\n     *\n     * @throws RuntimeException When not enough arguments are given\n     */\n    public function validate();\n\n    /**\n     * Returns all the given arguments merged with the default values.\n     *\n     * @return array<string|bool|int|float|array|null>\n     */\n    public function getArguments();\n\n    /**\n     * Returns the argument value for a given argument name.\n     *\n     * @return mixed\n     *\n     * @throws InvalidArgumentException When argument given doesn't exist\n     */\n    public function getArgument(string $name);\n\n    /**\n     * Sets an argument value by name.\n     *\n     * @param mixed $value The argument value\n     *\n     * @throws InvalidArgumentException When argument given doesn't exist\n     */\n    public function setArgument(string $name, $value);\n\n    /**\n     * Returns true if an InputArgument object exists by name or position.\n     *\n     * @return bool\n     */\n    public function hasArgument(string $name);\n\n    /**\n     * Returns all the given options merged with the default values.\n     *\n     * @return array<string|bool|int|float|array|null>\n     */\n    public function getOptions();\n\n    /**\n     * Returns the option value for a given option name.\n     *\n     * @return mixed\n     *\n     * @throws InvalidArgumentException When option given doesn't exist\n     */\n    public function getOption(string $name);\n\n    /**\n     * Sets an option value by name.\n     *\n     * @param mixed $value The option value\n     *\n     * @throws InvalidArgumentException When option given doesn't exist\n     */\n    public function setOption(string $name, $value);\n\n    /**\n     * Returns true if an InputOption object exists by name.\n     *\n     * @return bool\n     */\n    public function hasOption(string $name);\n\n    /**\n     * Is this input means interactive?\n     *\n     * @return bool\n     */\n    public function isInteractive();\n\n    /**\n     * Sets the input interactivity.\n     */\n    public function setInteractive(bool $interactive);\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Input/InputOption.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Input;\n\nuse Symfony\\Component\\Console\\Exception\\InvalidArgumentException;\nuse Symfony\\Component\\Console\\Exception\\LogicException;\n\n/**\n * Represents a command line option.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass InputOption\n{\n    /**\n     * Do not accept input for the option (e.g. --yell). This is the default behavior of options.\n     */\n    public const VALUE_NONE = 1;\n\n    /**\n     * A value must be passed when the option is used (e.g. --iterations=5 or -i5).\n     */\n    public const VALUE_REQUIRED = 2;\n\n    /**\n     * The option may or may not have a value (e.g. --yell or --yell=loud).\n     */\n    public const VALUE_OPTIONAL = 4;\n\n    /**\n     * The option accepts multiple values (e.g. --dir=/foo --dir=/bar).\n     */\n    public const VALUE_IS_ARRAY = 8;\n\n    /**\n     * The option may have either positive or negative value (e.g. --ansi or --no-ansi).\n     */\n    public const VALUE_NEGATABLE = 16;\n\n    private $name;\n    private $shortcut;\n    private $mode;\n    private $default;\n    private $description;\n\n    /**\n     * @param string|array|null                $shortcut The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts\n     * @param int|null                         $mode     The option mode: One of the VALUE_* constants\n     * @param string|bool|int|float|array|null $default  The default value (must be null for self::VALUE_NONE)\n     *\n     * @throws InvalidArgumentException If option mode is invalid or incompatible\n     */\n    public function __construct(string $name, $shortcut = null, ?int $mode = null, string $description = '', $default = null)\n    {\n        if (str_starts_with($name, '--')) {\n            $name = substr($name, 2);\n        }\n\n        if (empty($name)) {\n            throw new InvalidArgumentException('An option name cannot be empty.');\n        }\n\n        if ('' === $shortcut || [] === $shortcut || false === $shortcut) {\n            $shortcut = null;\n        }\n\n        if (null !== $shortcut) {\n            if (\\is_array($shortcut)) {\n                $shortcut = implode('|', $shortcut);\n            }\n            $shortcuts = preg_split('{(\\|)-?}', ltrim($shortcut, '-'));\n            $shortcuts = array_filter($shortcuts, 'strlen');\n            $shortcut = implode('|', $shortcuts);\n\n            if ('' === $shortcut) {\n                throw new InvalidArgumentException('An option shortcut cannot be empty.');\n            }\n        }\n\n        if (null === $mode) {\n            $mode = self::VALUE_NONE;\n        } elseif ($mode >= (self::VALUE_NEGATABLE << 1) || $mode < 1) {\n            throw new InvalidArgumentException(sprintf('Option mode \"%s\" is not valid.', $mode));\n        }\n\n        $this->name = $name;\n        $this->shortcut = $shortcut;\n        $this->mode = $mode;\n        $this->description = $description;\n\n        if ($this->isArray() && !$this->acceptValue()) {\n            throw new InvalidArgumentException('Impossible to have an option mode VALUE_IS_ARRAY if the option does not accept a value.');\n        }\n        if ($this->isNegatable() && $this->acceptValue()) {\n            throw new InvalidArgumentException('Impossible to have an option mode VALUE_NEGATABLE if the option also accepts a value.');\n        }\n\n        $this->setDefault($default);\n    }\n\n    /**\n     * Returns the option shortcut.\n     *\n     * @return string|null\n     */\n    public function getShortcut()\n    {\n        return $this->shortcut;\n    }\n\n    /**\n     * Returns the option name.\n     *\n     * @return string\n     */\n    public function getName()\n    {\n        return $this->name;\n    }\n\n    /**\n     * Returns true if the option accepts a value.\n     *\n     * @return bool true if value mode is not self::VALUE_NONE, false otherwise\n     */\n    public function acceptValue()\n    {\n        return $this->isValueRequired() || $this->isValueOptional();\n    }\n\n    /**\n     * Returns true if the option requires a value.\n     *\n     * @return bool true if value mode is self::VALUE_REQUIRED, false otherwise\n     */\n    public function isValueRequired()\n    {\n        return self::VALUE_REQUIRED === (self::VALUE_REQUIRED & $this->mode);\n    }\n\n    /**\n     * Returns true if the option takes an optional value.\n     *\n     * @return bool true if value mode is self::VALUE_OPTIONAL, false otherwise\n     */\n    public function isValueOptional()\n    {\n        return self::VALUE_OPTIONAL === (self::VALUE_OPTIONAL & $this->mode);\n    }\n\n    /**\n     * Returns true if the option can take multiple values.\n     *\n     * @return bool true if mode is self::VALUE_IS_ARRAY, false otherwise\n     */\n    public function isArray()\n    {\n        return self::VALUE_IS_ARRAY === (self::VALUE_IS_ARRAY & $this->mode);\n    }\n\n    public function isNegatable(): bool\n    {\n        return self::VALUE_NEGATABLE === (self::VALUE_NEGATABLE & $this->mode);\n    }\n\n    /**\n     * @param string|bool|int|float|array|null $default\n     */\n    public function setDefault($default = null)\n    {\n        if (self::VALUE_NONE === (self::VALUE_NONE & $this->mode) && null !== $default) {\n            throw new LogicException('Cannot set a default value when using InputOption::VALUE_NONE mode.');\n        }\n\n        if ($this->isArray()) {\n            if (null === $default) {\n                $default = [];\n            } elseif (!\\is_array($default)) {\n                throw new LogicException('A default value for an array option must be an array.');\n            }\n        }\n\n        $this->default = $this->acceptValue() || $this->isNegatable() ? $default : false;\n    }\n\n    /**\n     * Returns the default value.\n     *\n     * @return string|bool|int|float|array|null\n     */\n    public function getDefault()\n    {\n        return $this->default;\n    }\n\n    /**\n     * Returns the description text.\n     *\n     * @return string\n     */\n    public function getDescription()\n    {\n        return $this->description;\n    }\n\n    /**\n     * Checks whether the given option equals this one.\n     *\n     * @return bool\n     */\n    public function equals(self $option)\n    {\n        return $option->getName() === $this->getName()\n            && $option->getShortcut() === $this->getShortcut()\n            && $option->getDefault() === $this->getDefault()\n            && $option->isNegatable() === $this->isNegatable()\n            && $option->isArray() === $this->isArray()\n            && $option->isValueRequired() === $this->isValueRequired()\n            && $option->isValueOptional() === $this->isValueOptional()\n        ;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Input/StreamableInputInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Input;\n\n/**\n * StreamableInputInterface is the interface implemented by all input classes\n * that have an input stream.\n *\n * @author Robin Chalas <robin.chalas@gmail.com>\n */\ninterface StreamableInputInterface extends InputInterface\n{\n    /**\n     * Sets the input stream to read from when interacting with the user.\n     *\n     * This is mainly useful for testing purpose.\n     *\n     * @param resource $stream The input stream\n     */\n    public function setStream($stream);\n\n    /**\n     * Returns the input stream.\n     *\n     * @return resource|null\n     */\n    public function getStream();\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Input/StringInput.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Input;\n\nuse Symfony\\Component\\Console\\Exception\\InvalidArgumentException;\n\n/**\n * StringInput represents an input provided as a string.\n *\n * Usage:\n *\n *     $input = new StringInput('foo --bar=\"foobar\"');\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass StringInput extends ArgvInput\n{\n    public const REGEX_STRING = '([^\\s]+?)(?:\\s|(?<!\\\\\\\\)\"|(?<!\\\\\\\\)\\'|$)';\n    public const REGEX_UNQUOTED_STRING = '([^\\s\\\\\\\\]+?)';\n    public const REGEX_QUOTED_STRING = '(?:\"([^\"\\\\\\\\]*(?:\\\\\\\\.[^\"\\\\\\\\]*)*)\"|\\'([^\\'\\\\\\\\]*(?:\\\\\\\\.[^\\'\\\\\\\\]*)*)\\')';\n\n    /**\n     * @param string $input A string representing the parameters from the CLI\n     */\n    public function __construct(string $input)\n    {\n        parent::__construct([]);\n\n        $this->setTokens($this->tokenize($input));\n    }\n\n    /**\n     * Tokenizes a string.\n     *\n     * @throws InvalidArgumentException When unable to parse input (should never happen)\n     */\n    private function tokenize(string $input): array\n    {\n        $tokens = [];\n        $length = \\strlen($input);\n        $cursor = 0;\n        $token = null;\n        while ($cursor < $length) {\n            if ('\\\\' === $input[$cursor]) {\n                $token .= $input[++$cursor] ?? '';\n                ++$cursor;\n                continue;\n            }\n\n            if (preg_match('/\\s+/A', $input, $match, 0, $cursor)) {\n                if (null !== $token) {\n                    $tokens[] = $token;\n                    $token = null;\n                }\n            } elseif (preg_match('/([^=\"\\'\\s]+?)(=?)('.self::REGEX_QUOTED_STRING.'+)/A', $input, $match, 0, $cursor)) {\n                $token .= $match[1].$match[2].stripcslashes(str_replace(['\"\\'', '\\'\"', '\\'\\'', '\"\"'], '', substr($match[3], 1, -1)));\n            } elseif (preg_match('/'.self::REGEX_QUOTED_STRING.'/A', $input, $match, 0, $cursor)) {\n                $token .= stripcslashes(substr($match[0], 1, -1));\n            } elseif (preg_match('/'.self::REGEX_UNQUOTED_STRING.'/A', $input, $match, 0, $cursor)) {\n                $token .= $match[1];\n            } else {\n                // should never happen\n                throw new InvalidArgumentException(sprintf('Unable to parse input near \"... %s ...\".', substr($input, $cursor, 10)));\n            }\n\n            $cursor += \\strlen($match[0]);\n        }\n\n        if (null !== $token) {\n            $tokens[] = $token;\n        }\n\n        return $tokens;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/LICENSE",
    "content": "Copyright (c) 2004-present Fabien Potencier\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is furnished\nto do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "server/vendor/symfony/console/Logger/ConsoleLogger.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Logger;\n\nuse Psr\\Log\\AbstractLogger;\nuse Psr\\Log\\InvalidArgumentException;\nuse Psr\\Log\\LogLevel;\nuse Symfony\\Component\\Console\\Output\\ConsoleOutputInterface;\nuse Symfony\\Component\\Console\\Output\\OutputInterface;\n\n/**\n * PSR-3 compliant console logger.\n *\n * @author Kévin Dunglas <dunglas@gmail.com>\n *\n * @see https://www.php-fig.org/psr/psr-3/\n */\nclass ConsoleLogger extends AbstractLogger\n{\n    public const INFO = 'info';\n    public const ERROR = 'error';\n\n    private $output;\n    private $verbosityLevelMap = [\n        LogLevel::EMERGENCY => OutputInterface::VERBOSITY_NORMAL,\n        LogLevel::ALERT => OutputInterface::VERBOSITY_NORMAL,\n        LogLevel::CRITICAL => OutputInterface::VERBOSITY_NORMAL,\n        LogLevel::ERROR => OutputInterface::VERBOSITY_NORMAL,\n        LogLevel::WARNING => OutputInterface::VERBOSITY_NORMAL,\n        LogLevel::NOTICE => OutputInterface::VERBOSITY_VERBOSE,\n        LogLevel::INFO => OutputInterface::VERBOSITY_VERY_VERBOSE,\n        LogLevel::DEBUG => OutputInterface::VERBOSITY_DEBUG,\n    ];\n    private $formatLevelMap = [\n        LogLevel::EMERGENCY => self::ERROR,\n        LogLevel::ALERT => self::ERROR,\n        LogLevel::CRITICAL => self::ERROR,\n        LogLevel::ERROR => self::ERROR,\n        LogLevel::WARNING => self::INFO,\n        LogLevel::NOTICE => self::INFO,\n        LogLevel::INFO => self::INFO,\n        LogLevel::DEBUG => self::INFO,\n    ];\n    private $errored = false;\n\n    public function __construct(OutputInterface $output, array $verbosityLevelMap = [], array $formatLevelMap = [])\n    {\n        $this->output = $output;\n        $this->verbosityLevelMap = $verbosityLevelMap + $this->verbosityLevelMap;\n        $this->formatLevelMap = $formatLevelMap + $this->formatLevelMap;\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @return void\n     */\n    public function log($level, $message, array $context = [])\n    {\n        if (!isset($this->verbosityLevelMap[$level])) {\n            throw new InvalidArgumentException(sprintf('The log level \"%s\" does not exist.', $level));\n        }\n\n        $output = $this->output;\n\n        // Write to the error output if necessary and available\n        if (self::ERROR === $this->formatLevelMap[$level]) {\n            if ($this->output instanceof ConsoleOutputInterface) {\n                $output = $output->getErrorOutput();\n            }\n            $this->errored = true;\n        }\n\n        // the if condition check isn't necessary -- it's the same one that $output will do internally anyway.\n        // We only do it for efficiency here as the message formatting is relatively expensive.\n        if ($output->getVerbosity() >= $this->verbosityLevelMap[$level]) {\n            $output->writeln(sprintf('<%1$s>[%2$s] %3$s</%1$s>', $this->formatLevelMap[$level], $level, $this->interpolate($message, $context)), $this->verbosityLevelMap[$level]);\n        }\n    }\n\n    /**\n     * Returns true when any messages have been logged at error levels.\n     *\n     * @return bool\n     */\n    public function hasErrored()\n    {\n        return $this->errored;\n    }\n\n    /**\n     * Interpolates context values into the message placeholders.\n     *\n     * @author PHP Framework Interoperability Group\n     */\n    private function interpolate(string $message, array $context): string\n    {\n        if (!str_contains($message, '{')) {\n            return $message;\n        }\n\n        $replacements = [];\n        foreach ($context as $key => $val) {\n            if (null === $val || \\is_scalar($val) || (\\is_object($val) && method_exists($val, '__toString'))) {\n                $replacements[\"{{$key}}\"] = $val;\n            } elseif ($val instanceof \\DateTimeInterface) {\n                $replacements[\"{{$key}}\"] = $val->format(\\DateTime::RFC3339);\n            } elseif (\\is_object($val)) {\n                $replacements[\"{{$key}}\"] = '[object '.\\get_class($val).']';\n            } else {\n                $replacements[\"{{$key}}\"] = '['.\\gettype($val).']';\n            }\n        }\n\n        return strtr($message, $replacements);\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Output/BufferedOutput.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Output;\n\n/**\n * @author Jean-François Simon <contact@jfsimon.fr>\n */\nclass BufferedOutput extends Output\n{\n    private $buffer = '';\n\n    /**\n     * Empties buffer and returns its content.\n     *\n     * @return string\n     */\n    public function fetch()\n    {\n        $content = $this->buffer;\n        $this->buffer = '';\n\n        return $content;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    protected function doWrite(string $message, bool $newline)\n    {\n        $this->buffer .= $message;\n\n        if ($newline) {\n            $this->buffer .= \\PHP_EOL;\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Output/ConsoleOutput.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Output;\n\nuse Symfony\\Component\\Console\\Formatter\\OutputFormatterInterface;\n\n/**\n * ConsoleOutput is the default class for all CLI output. It uses STDOUT and STDERR.\n *\n * This class is a convenient wrapper around `StreamOutput` for both STDOUT and STDERR.\n *\n *     $output = new ConsoleOutput();\n *\n * This is equivalent to:\n *\n *     $output = new StreamOutput(fopen('php://stdout', 'w'));\n *     $stdErr = new StreamOutput(fopen('php://stderr', 'w'));\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass ConsoleOutput extends StreamOutput implements ConsoleOutputInterface\n{\n    private $stderr;\n    private $consoleSectionOutputs = [];\n\n    /**\n     * @param int                           $verbosity The verbosity level (one of the VERBOSITY constants in OutputInterface)\n     * @param bool|null                     $decorated Whether to decorate messages (null for auto-guessing)\n     * @param OutputFormatterInterface|null $formatter Output formatter instance (null to use default OutputFormatter)\n     */\n    public function __construct(int $verbosity = self::VERBOSITY_NORMAL, ?bool $decorated = null, ?OutputFormatterInterface $formatter = null)\n    {\n        parent::__construct($this->openOutputStream(), $verbosity, $decorated, $formatter);\n\n        if (null === $formatter) {\n            // for BC reasons, stdErr has it own Formatter only when user don't inject a specific formatter.\n            $this->stderr = new StreamOutput($this->openErrorStream(), $verbosity, $decorated);\n\n            return;\n        }\n\n        $actualDecorated = $this->isDecorated();\n        $this->stderr = new StreamOutput($this->openErrorStream(), $verbosity, $decorated, $this->getFormatter());\n\n        if (null === $decorated) {\n            $this->setDecorated($actualDecorated && $this->stderr->isDecorated());\n        }\n    }\n\n    /**\n     * Creates a new output section.\n     */\n    public function section(): ConsoleSectionOutput\n    {\n        return new ConsoleSectionOutput($this->getStream(), $this->consoleSectionOutputs, $this->getVerbosity(), $this->isDecorated(), $this->getFormatter());\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function setDecorated(bool $decorated)\n    {\n        parent::setDecorated($decorated);\n        $this->stderr->setDecorated($decorated);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function setFormatter(OutputFormatterInterface $formatter)\n    {\n        parent::setFormatter($formatter);\n        $this->stderr->setFormatter($formatter);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function setVerbosity(int $level)\n    {\n        parent::setVerbosity($level);\n        $this->stderr->setVerbosity($level);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getErrorOutput()\n    {\n        return $this->stderr;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function setErrorOutput(OutputInterface $error)\n    {\n        $this->stderr = $error;\n    }\n\n    /**\n     * Returns true if current environment supports writing console output to\n     * STDOUT.\n     *\n     * @return bool\n     */\n    protected function hasStdoutSupport()\n    {\n        return false === $this->isRunningOS400();\n    }\n\n    /**\n     * Returns true if current environment supports writing console output to\n     * STDERR.\n     *\n     * @return bool\n     */\n    protected function hasStderrSupport()\n    {\n        return false === $this->isRunningOS400();\n    }\n\n    /**\n     * Checks if current executing environment is IBM iSeries (OS400), which\n     * doesn't properly convert character-encodings between ASCII to EBCDIC.\n     */\n    private function isRunningOS400(): bool\n    {\n        $checks = [\n            \\function_exists('php_uname') ? php_uname('s') : '',\n            getenv('OSTYPE'),\n            \\PHP_OS,\n        ];\n\n        return false !== stripos(implode(';', $checks), 'OS400');\n    }\n\n    /**\n     * @return resource\n     */\n    private function openOutputStream()\n    {\n        if (!$this->hasStdoutSupport()) {\n            return fopen('php://output', 'w');\n        }\n\n        // Use STDOUT when possible to prevent from opening too many file descriptors\n        return \\defined('STDOUT') ? \\STDOUT : (@fopen('php://stdout', 'w') ?: fopen('php://output', 'w'));\n    }\n\n    /**\n     * @return resource\n     */\n    private function openErrorStream()\n    {\n        if (!$this->hasStderrSupport()) {\n            return fopen('php://output', 'w');\n        }\n\n        // Use STDERR when possible to prevent from opening too many file descriptors\n        return \\defined('STDERR') ? \\STDERR : (@fopen('php://stderr', 'w') ?: fopen('php://output', 'w'));\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Output/ConsoleOutputInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Output;\n\n/**\n * ConsoleOutputInterface is the interface implemented by ConsoleOutput class.\n * This adds information about stderr and section output stream.\n *\n * @author Dariusz Górecki <darek.krk@gmail.com>\n */\ninterface ConsoleOutputInterface extends OutputInterface\n{\n    /**\n     * Gets the OutputInterface for errors.\n     *\n     * @return OutputInterface\n     */\n    public function getErrorOutput();\n\n    public function setErrorOutput(OutputInterface $error);\n\n    public function section(): ConsoleSectionOutput;\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Output/ConsoleSectionOutput.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Output;\n\nuse Symfony\\Component\\Console\\Formatter\\OutputFormatterInterface;\nuse Symfony\\Component\\Console\\Helper\\Helper;\nuse Symfony\\Component\\Console\\Terminal;\n\n/**\n * @author Pierre du Plessis <pdples@gmail.com>\n * @author Gabriel Ostrolucký <gabriel.ostrolucky@gmail.com>\n */\nclass ConsoleSectionOutput extends StreamOutput\n{\n    private $content = [];\n    private $lines = 0;\n    private $sections;\n    private $terminal;\n\n    /**\n     * @param resource               $stream\n     * @param ConsoleSectionOutput[] $sections\n     */\n    public function __construct($stream, array &$sections, int $verbosity, bool $decorated, OutputFormatterInterface $formatter)\n    {\n        parent::__construct($stream, $verbosity, $decorated, $formatter);\n        array_unshift($sections, $this);\n        $this->sections = &$sections;\n        $this->terminal = new Terminal();\n    }\n\n    /**\n     * Clears previous output for this section.\n     *\n     * @param int $lines Number of lines to clear. If null, then the entire output of this section is cleared\n     */\n    public function clear(?int $lines = null)\n    {\n        if (empty($this->content) || !$this->isDecorated()) {\n            return;\n        }\n\n        if ($lines) {\n            array_splice($this->content, -($lines * 2)); // Multiply lines by 2 to cater for each new line added between content\n        } else {\n            $lines = $this->lines;\n            $this->content = [];\n        }\n\n        $this->lines -= $lines;\n\n        parent::doWrite($this->popStreamContentUntilCurrentSection($lines), false);\n    }\n\n    /**\n     * Overwrites the previous output with a new message.\n     *\n     * @param array|string $message\n     */\n    public function overwrite($message)\n    {\n        $this->clear();\n        $this->writeln($message);\n    }\n\n    public function getContent(): string\n    {\n        return implode('', $this->content);\n    }\n\n    /**\n     * @internal\n     */\n    public function addContent(string $input)\n    {\n        foreach (explode(\\PHP_EOL, $input) as $lineContent) {\n            $this->lines += ceil($this->getDisplayLength($lineContent) / $this->terminal->getWidth()) ?: 1;\n            $this->content[] = $lineContent;\n            $this->content[] = \\PHP_EOL;\n        }\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    protected function doWrite(string $message, bool $newline)\n    {\n        if (!$this->isDecorated()) {\n            parent::doWrite($message, $newline);\n\n            return;\n        }\n\n        $erasedContent = $this->popStreamContentUntilCurrentSection();\n\n        $this->addContent($message);\n\n        parent::doWrite($message, true);\n        parent::doWrite($erasedContent, false);\n    }\n\n    /**\n     * At initial stage, cursor is at the end of stream output. This method makes cursor crawl upwards until it hits\n     * current section. Then it erases content it crawled through. Optionally, it erases part of current section too.\n     */\n    private function popStreamContentUntilCurrentSection(int $numberOfLinesToClearFromCurrentSection = 0): string\n    {\n        $numberOfLinesToClear = $numberOfLinesToClearFromCurrentSection;\n        $erasedContent = [];\n\n        foreach ($this->sections as $section) {\n            if ($section === $this) {\n                break;\n            }\n\n            $numberOfLinesToClear += $section->lines;\n            $erasedContent[] = $section->getContent();\n        }\n\n        if ($numberOfLinesToClear > 0) {\n            // move cursor up n lines\n            parent::doWrite(sprintf(\"\\x1b[%dA\", $numberOfLinesToClear), false);\n            // erase to end of screen\n            parent::doWrite(\"\\x1b[0J\", false);\n        }\n\n        return implode('', array_reverse($erasedContent));\n    }\n\n    private function getDisplayLength(string $text): int\n    {\n        return Helper::width(Helper::removeDecoration($this->getFormatter(), str_replace(\"\\t\", '        ', $text)));\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Output/NullOutput.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Output;\n\nuse Symfony\\Component\\Console\\Formatter\\NullOutputFormatter;\nuse Symfony\\Component\\Console\\Formatter\\OutputFormatterInterface;\n\n/**\n * NullOutput suppresses all output.\n *\n *     $output = new NullOutput();\n *\n * @author Fabien Potencier <fabien@symfony.com>\n * @author Tobias Schultze <http://tobion.de>\n */\nclass NullOutput implements OutputInterface\n{\n    private $formatter;\n\n    /**\n     * {@inheritdoc}\n     */\n    public function setFormatter(OutputFormatterInterface $formatter)\n    {\n        // do nothing\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getFormatter()\n    {\n        if ($this->formatter) {\n            return $this->formatter;\n        }\n        // to comply with the interface we must return a OutputFormatterInterface\n        return $this->formatter = new NullOutputFormatter();\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function setDecorated(bool $decorated)\n    {\n        // do nothing\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function isDecorated()\n    {\n        return false;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function setVerbosity(int $level)\n    {\n        // do nothing\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getVerbosity()\n    {\n        return self::VERBOSITY_QUIET;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function isQuiet()\n    {\n        return true;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function isVerbose()\n    {\n        return false;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function isVeryVerbose()\n    {\n        return false;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function isDebug()\n    {\n        return false;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function writeln($messages, int $options = self::OUTPUT_NORMAL)\n    {\n        // do nothing\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function write($messages, bool $newline = false, int $options = self::OUTPUT_NORMAL)\n    {\n        // do nothing\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Output/Output.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Output;\n\nuse Symfony\\Component\\Console\\Formatter\\OutputFormatter;\nuse Symfony\\Component\\Console\\Formatter\\OutputFormatterInterface;\n\n/**\n * Base class for output classes.\n *\n * There are five levels of verbosity:\n *\n *  * normal: no option passed (normal output)\n *  * verbose: -v (more output)\n *  * very verbose: -vv (highly extended output)\n *  * debug: -vvv (all debug output)\n *  * quiet: -q (no output)\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nabstract class Output implements OutputInterface\n{\n    private $verbosity;\n    private $formatter;\n\n    /**\n     * @param int|null                      $verbosity The verbosity level (one of the VERBOSITY constants in OutputInterface)\n     * @param bool                          $decorated Whether to decorate messages\n     * @param OutputFormatterInterface|null $formatter Output formatter instance (null to use default OutputFormatter)\n     */\n    public function __construct(?int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = false, ?OutputFormatterInterface $formatter = null)\n    {\n        $this->verbosity = $verbosity ?? self::VERBOSITY_NORMAL;\n        $this->formatter = $formatter ?? new OutputFormatter();\n        $this->formatter->setDecorated($decorated);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function setFormatter(OutputFormatterInterface $formatter)\n    {\n        $this->formatter = $formatter;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getFormatter()\n    {\n        return $this->formatter;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function setDecorated(bool $decorated)\n    {\n        $this->formatter->setDecorated($decorated);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function isDecorated()\n    {\n        return $this->formatter->isDecorated();\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function setVerbosity(int $level)\n    {\n        $this->verbosity = $level;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getVerbosity()\n    {\n        return $this->verbosity;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function isQuiet()\n    {\n        return self::VERBOSITY_QUIET === $this->verbosity;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function isVerbose()\n    {\n        return self::VERBOSITY_VERBOSE <= $this->verbosity;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function isVeryVerbose()\n    {\n        return self::VERBOSITY_VERY_VERBOSE <= $this->verbosity;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function isDebug()\n    {\n        return self::VERBOSITY_DEBUG <= $this->verbosity;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function writeln($messages, int $options = self::OUTPUT_NORMAL)\n    {\n        $this->write($messages, true, $options);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function write($messages, bool $newline = false, int $options = self::OUTPUT_NORMAL)\n    {\n        if (!is_iterable($messages)) {\n            $messages = [$messages];\n        }\n\n        $types = self::OUTPUT_NORMAL | self::OUTPUT_RAW | self::OUTPUT_PLAIN;\n        $type = $types & $options ?: self::OUTPUT_NORMAL;\n\n        $verbosities = self::VERBOSITY_QUIET | self::VERBOSITY_NORMAL | self::VERBOSITY_VERBOSE | self::VERBOSITY_VERY_VERBOSE | self::VERBOSITY_DEBUG;\n        $verbosity = $verbosities & $options ?: self::VERBOSITY_NORMAL;\n\n        if ($verbosity > $this->getVerbosity()) {\n            return;\n        }\n\n        foreach ($messages as $message) {\n            switch ($type) {\n                case OutputInterface::OUTPUT_NORMAL:\n                    $message = $this->formatter->format($message);\n                    break;\n                case OutputInterface::OUTPUT_RAW:\n                    break;\n                case OutputInterface::OUTPUT_PLAIN:\n                    $message = strip_tags($this->formatter->format($message));\n                    break;\n            }\n\n            $this->doWrite($message ?? '', $newline);\n        }\n    }\n\n    /**\n     * Writes a message to the output.\n     */\n    abstract protected function doWrite(string $message, bool $newline);\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Output/OutputInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Output;\n\nuse Symfony\\Component\\Console\\Formatter\\OutputFormatterInterface;\n\n/**\n * OutputInterface is the interface implemented by all Output classes.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\ninterface OutputInterface\n{\n    public const VERBOSITY_QUIET = 16;\n    public const VERBOSITY_NORMAL = 32;\n    public const VERBOSITY_VERBOSE = 64;\n    public const VERBOSITY_VERY_VERBOSE = 128;\n    public const VERBOSITY_DEBUG = 256;\n\n    public const OUTPUT_NORMAL = 1;\n    public const OUTPUT_RAW = 2;\n    public const OUTPUT_PLAIN = 4;\n\n    /**\n     * Writes a message to the output.\n     *\n     * @param string|iterable $messages The message as an iterable of strings or a single string\n     * @param bool            $newline  Whether to add a newline\n     * @param int             $options  A bitmask of options (one of the OUTPUT or VERBOSITY constants), 0 is considered the same as self::OUTPUT_NORMAL | self::VERBOSITY_NORMAL\n     */\n    public function write($messages, bool $newline = false, int $options = 0);\n\n    /**\n     * Writes a message to the output and adds a newline at the end.\n     *\n     * @param string|iterable $messages The message as an iterable of strings or a single string\n     * @param int             $options  A bitmask of options (one of the OUTPUT or VERBOSITY constants), 0 is considered the same as self::OUTPUT_NORMAL | self::VERBOSITY_NORMAL\n     */\n    public function writeln($messages, int $options = 0);\n\n    /**\n     * Sets the verbosity of the output.\n     */\n    public function setVerbosity(int $level);\n\n    /**\n     * Gets the current verbosity of the output.\n     *\n     * @return int\n     */\n    public function getVerbosity();\n\n    /**\n     * Returns whether verbosity is quiet (-q).\n     *\n     * @return bool\n     */\n    public function isQuiet();\n\n    /**\n     * Returns whether verbosity is verbose (-v).\n     *\n     * @return bool\n     */\n    public function isVerbose();\n\n    /**\n     * Returns whether verbosity is very verbose (-vv).\n     *\n     * @return bool\n     */\n    public function isVeryVerbose();\n\n    /**\n     * Returns whether verbosity is debug (-vvv).\n     *\n     * @return bool\n     */\n    public function isDebug();\n\n    /**\n     * Sets the decorated flag.\n     */\n    public function setDecorated(bool $decorated);\n\n    /**\n     * Gets the decorated flag.\n     *\n     * @return bool\n     */\n    public function isDecorated();\n\n    public function setFormatter(OutputFormatterInterface $formatter);\n\n    /**\n     * Returns current output formatter instance.\n     *\n     * @return OutputFormatterInterface\n     */\n    public function getFormatter();\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Output/StreamOutput.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Output;\n\nuse Symfony\\Component\\Console\\Exception\\InvalidArgumentException;\nuse Symfony\\Component\\Console\\Formatter\\OutputFormatterInterface;\n\n/**\n * StreamOutput writes the output to a given stream.\n *\n * Usage:\n *\n *     $output = new StreamOutput(fopen('php://stdout', 'w'));\n *\n * As `StreamOutput` can use any stream, you can also use a file:\n *\n *     $output = new StreamOutput(fopen('/path/to/output.log', 'a', false));\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass StreamOutput extends Output\n{\n    private $stream;\n\n    /**\n     * @param resource                      $stream    A stream resource\n     * @param int                           $verbosity The verbosity level (one of the VERBOSITY constants in OutputInterface)\n     * @param bool|null                     $decorated Whether to decorate messages (null for auto-guessing)\n     * @param OutputFormatterInterface|null $formatter Output formatter instance (null to use default OutputFormatter)\n     *\n     * @throws InvalidArgumentException When first argument is not a real stream\n     */\n    public function __construct($stream, int $verbosity = self::VERBOSITY_NORMAL, ?bool $decorated = null, ?OutputFormatterInterface $formatter = null)\n    {\n        if (!\\is_resource($stream) || 'stream' !== get_resource_type($stream)) {\n            throw new InvalidArgumentException('The StreamOutput class needs a stream as its first argument.');\n        }\n\n        $this->stream = $stream;\n\n        if (null === $decorated) {\n            $decorated = $this->hasColorSupport();\n        }\n\n        parent::__construct($verbosity, $decorated, $formatter);\n    }\n\n    /**\n     * Gets the stream attached to this StreamOutput instance.\n     *\n     * @return resource\n     */\n    public function getStream()\n    {\n        return $this->stream;\n    }\n\n    protected function doWrite(string $message, bool $newline)\n    {\n        if ($newline) {\n            $message .= \\PHP_EOL;\n        }\n\n        @fwrite($this->stream, $message);\n\n        fflush($this->stream);\n    }\n\n    /**\n     * Returns true if the stream supports colorization.\n     *\n     * Colorization is disabled if not supported by the stream:\n     *\n     * This is tricky on Windows, because Cygwin, Msys2 etc emulate pseudo\n     * terminals via named pipes, so we can only check the environment.\n     *\n     * Reference: Composer\\XdebugHandler\\Process::supportsColor\n     * https://github.com/composer/xdebug-handler\n     *\n     * @return bool true if the stream supports colorization, false otherwise\n     */\n    protected function hasColorSupport()\n    {\n        // Follow https://no-color.org/\n        if ('' !== (($_SERVER['NO_COLOR'] ?? getenv('NO_COLOR'))[0] ?? '')) {\n            return false;\n        }\n\n        // Detect msysgit/mingw and assume this is a tty because detection\n        // does not work correctly, see https://github.com/composer/composer/issues/9690\n        if (!@stream_isatty($this->stream) && !\\in_array(strtoupper((string) getenv('MSYSTEM')), ['MINGW32', 'MINGW64'], true)) {\n            return false;\n        }\n\n        if ('\\\\' === \\DIRECTORY_SEPARATOR && @sapi_windows_vt100_support($this->stream)) {\n            return true;\n        }\n\n        if ('Hyper' === getenv('TERM_PROGRAM')\n            || false !== getenv('COLORTERM')\n            || false !== getenv('ANSICON')\n            || 'ON' === getenv('ConEmuANSI')\n        ) {\n            return true;\n        }\n\n        if ('dumb' === $term = (string) getenv('TERM')) {\n            return false;\n        }\n\n        // See https://github.com/chalk/supports-color/blob/d4f413efaf8da045c5ab440ed418ef02dbb28bf1/index.js#L157\n        return preg_match('/^((screen|xterm|vt100|vt220|putty|rxvt|ansi|cygwin|linux).*)|(.*-256(color)?(-bce)?)$/', $term);\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Output/TrimmedBufferOutput.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Output;\n\nuse Symfony\\Component\\Console\\Exception\\InvalidArgumentException;\nuse Symfony\\Component\\Console\\Formatter\\OutputFormatterInterface;\n\n/**\n * A BufferedOutput that keeps only the last N chars.\n *\n * @author Jérémy Derussé <jeremy@derusse.com>\n */\nclass TrimmedBufferOutput extends Output\n{\n    private $maxLength;\n    private $buffer = '';\n\n    public function __construct(int $maxLength, ?int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = false, ?OutputFormatterInterface $formatter = null)\n    {\n        if ($maxLength <= 0) {\n            throw new InvalidArgumentException(sprintf('\"%s()\" expects a strictly positive maxLength. Got %d.', __METHOD__, $maxLength));\n        }\n\n        parent::__construct($verbosity, $decorated, $formatter);\n        $this->maxLength = $maxLength;\n    }\n\n    /**\n     * Empties buffer and returns its content.\n     *\n     * @return string\n     */\n    public function fetch()\n    {\n        $content = $this->buffer;\n        $this->buffer = '';\n\n        return $content;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    protected function doWrite(string $message, bool $newline)\n    {\n        $this->buffer .= $message;\n\n        if ($newline) {\n            $this->buffer .= \\PHP_EOL;\n        }\n\n        $this->buffer = substr($this->buffer, 0 - $this->maxLength);\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Question/ChoiceQuestion.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Question;\n\nuse Symfony\\Component\\Console\\Exception\\InvalidArgumentException;\n\n/**\n * Represents a choice question.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass ChoiceQuestion extends Question\n{\n    private $choices;\n    private $multiselect = false;\n    private $prompt = ' > ';\n    private $errorMessage = 'Value \"%s\" is invalid';\n\n    /**\n     * @param string $question The question to ask to the user\n     * @param array  $choices  The list of available choices\n     * @param mixed  $default  The default answer to return\n     */\n    public function __construct(string $question, array $choices, $default = null)\n    {\n        if (!$choices) {\n            throw new \\LogicException('Choice question must have at least 1 choice available.');\n        }\n\n        parent::__construct($question, $default);\n\n        $this->choices = $choices;\n        $this->setValidator($this->getDefaultValidator());\n        $this->setAutocompleterValues($choices);\n    }\n\n    /**\n     * Returns available choices.\n     *\n     * @return array\n     */\n    public function getChoices()\n    {\n        return $this->choices;\n    }\n\n    /**\n     * Sets multiselect option.\n     *\n     * When multiselect is set to true, multiple choices can be answered.\n     *\n     * @return $this\n     */\n    public function setMultiselect(bool $multiselect)\n    {\n        $this->multiselect = $multiselect;\n        $this->setValidator($this->getDefaultValidator());\n\n        return $this;\n    }\n\n    /**\n     * Returns whether the choices are multiselect.\n     *\n     * @return bool\n     */\n    public function isMultiselect()\n    {\n        return $this->multiselect;\n    }\n\n    /**\n     * Gets the prompt for choices.\n     *\n     * @return string\n     */\n    public function getPrompt()\n    {\n        return $this->prompt;\n    }\n\n    /**\n     * Sets the prompt for choices.\n     *\n     * @return $this\n     */\n    public function setPrompt(string $prompt)\n    {\n        $this->prompt = $prompt;\n\n        return $this;\n    }\n\n    /**\n     * Sets the error message for invalid values.\n     *\n     * The error message has a string placeholder (%s) for the invalid value.\n     *\n     * @return $this\n     */\n    public function setErrorMessage(string $errorMessage)\n    {\n        $this->errorMessage = $errorMessage;\n        $this->setValidator($this->getDefaultValidator());\n\n        return $this;\n    }\n\n    private function getDefaultValidator(): callable\n    {\n        $choices = $this->choices;\n        $errorMessage = $this->errorMessage;\n        $multiselect = $this->multiselect;\n        $isAssoc = $this->isAssoc($choices);\n\n        return function ($selected) use ($choices, $errorMessage, $multiselect, $isAssoc) {\n            if ($multiselect) {\n                // Check for a separated comma values\n                if (!preg_match('/^[^,]+(?:,[^,]+)*$/', (string) $selected, $matches)) {\n                    throw new InvalidArgumentException(sprintf($errorMessage, $selected));\n                }\n\n                $selectedChoices = explode(',', (string) $selected);\n            } else {\n                $selectedChoices = [$selected];\n            }\n\n            if ($this->isTrimmable()) {\n                foreach ($selectedChoices as $k => $v) {\n                    $selectedChoices[$k] = trim((string) $v);\n                }\n            }\n\n            $multiselectChoices = [];\n            foreach ($selectedChoices as $value) {\n                $results = [];\n                foreach ($choices as $key => $choice) {\n                    if ($choice === $value) {\n                        $results[] = $key;\n                    }\n                }\n\n                if (\\count($results) > 1) {\n                    throw new InvalidArgumentException(sprintf('The provided answer is ambiguous. Value should be one of \"%s\".', implode('\" or \"', $results)));\n                }\n\n                $result = array_search($value, $choices);\n\n                if (!$isAssoc) {\n                    if (false !== $result) {\n                        $result = $choices[$result];\n                    } elseif (isset($choices[$value])) {\n                        $result = $choices[$value];\n                    }\n                } elseif (false === $result && isset($choices[$value])) {\n                    $result = $value;\n                }\n\n                if (false === $result) {\n                    throw new InvalidArgumentException(sprintf($errorMessage, $value));\n                }\n\n                // For associative choices, consistently return the key as string:\n                $multiselectChoices[] = $isAssoc ? (string) $result : $result;\n            }\n\n            if ($multiselect) {\n                return $multiselectChoices;\n            }\n\n            return current($multiselectChoices);\n        };\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Question/ConfirmationQuestion.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Question;\n\n/**\n * Represents a yes/no question.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass ConfirmationQuestion extends Question\n{\n    private $trueAnswerRegex;\n\n    /**\n     * @param string $question        The question to ask to the user\n     * @param bool   $default         The default answer to return, true or false\n     * @param string $trueAnswerRegex A regex to match the \"yes\" answer\n     */\n    public function __construct(string $question, bool $default = true, string $trueAnswerRegex = '/^y/i')\n    {\n        parent::__construct($question, $default);\n\n        $this->trueAnswerRegex = $trueAnswerRegex;\n        $this->setNormalizer($this->getDefaultNormalizer());\n    }\n\n    /**\n     * Returns the default answer normalizer.\n     */\n    private function getDefaultNormalizer(): callable\n    {\n        $default = $this->getDefault();\n        $regex = $this->trueAnswerRegex;\n\n        return function ($answer) use ($default, $regex) {\n            if (\\is_bool($answer)) {\n                return $answer;\n            }\n\n            $answerIsTrue = (bool) preg_match($regex, $answer);\n            if (false === $default) {\n                return $answer && $answerIsTrue;\n            }\n\n            return '' === $answer || $answerIsTrue;\n        };\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Question/Question.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Question;\n\nuse Symfony\\Component\\Console\\Exception\\InvalidArgumentException;\nuse Symfony\\Component\\Console\\Exception\\LogicException;\n\n/**\n * Represents a Question.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass Question\n{\n    private $question;\n    private $attempts;\n    private $hidden = false;\n    private $hiddenFallback = true;\n    private $autocompleterCallback;\n    private $validator;\n    private $default;\n    private $normalizer;\n    private $trimmable = true;\n    private $multiline = false;\n\n    /**\n     * @param string                     $question The question to ask to the user\n     * @param string|bool|int|float|null $default  The default answer to return if the user enters nothing\n     */\n    public function __construct(string $question, $default = null)\n    {\n        $this->question = $question;\n        $this->default = $default;\n    }\n\n    /**\n     * Returns the question.\n     *\n     * @return string\n     */\n    public function getQuestion()\n    {\n        return $this->question;\n    }\n\n    /**\n     * Returns the default answer.\n     *\n     * @return string|bool|int|float|null\n     */\n    public function getDefault()\n    {\n        return $this->default;\n    }\n\n    /**\n     * Returns whether the user response accepts newline characters.\n     */\n    public function isMultiline(): bool\n    {\n        return $this->multiline;\n    }\n\n    /**\n     * Sets whether the user response should accept newline characters.\n     *\n     * @return $this\n     */\n    public function setMultiline(bool $multiline): self\n    {\n        $this->multiline = $multiline;\n\n        return $this;\n    }\n\n    /**\n     * Returns whether the user response must be hidden.\n     *\n     * @return bool\n     */\n    public function isHidden()\n    {\n        return $this->hidden;\n    }\n\n    /**\n     * Sets whether the user response must be hidden or not.\n     *\n     * @return $this\n     *\n     * @throws LogicException In case the autocompleter is also used\n     */\n    public function setHidden(bool $hidden)\n    {\n        if ($this->autocompleterCallback) {\n            throw new LogicException('A hidden question cannot use the autocompleter.');\n        }\n\n        $this->hidden = $hidden;\n\n        return $this;\n    }\n\n    /**\n     * In case the response cannot be hidden, whether to fallback on non-hidden question or not.\n     *\n     * @return bool\n     */\n    public function isHiddenFallback()\n    {\n        return $this->hiddenFallback;\n    }\n\n    /**\n     * Sets whether to fallback on non-hidden question if the response cannot be hidden.\n     *\n     * @return $this\n     */\n    public function setHiddenFallback(bool $fallback)\n    {\n        $this->hiddenFallback = $fallback;\n\n        return $this;\n    }\n\n    /**\n     * Gets values for the autocompleter.\n     *\n     * @return iterable|null\n     */\n    public function getAutocompleterValues()\n    {\n        $callback = $this->getAutocompleterCallback();\n\n        return $callback ? $callback('') : null;\n    }\n\n    /**\n     * Sets values for the autocompleter.\n     *\n     * @return $this\n     *\n     * @throws LogicException\n     */\n    public function setAutocompleterValues(?iterable $values)\n    {\n        if (\\is_array($values)) {\n            $values = $this->isAssoc($values) ? array_merge(array_keys($values), array_values($values)) : array_values($values);\n\n            $callback = static function () use ($values) {\n                return $values;\n            };\n        } elseif ($values instanceof \\Traversable) {\n            $valueCache = null;\n            $callback = static function () use ($values, &$valueCache) {\n                return $valueCache ?? $valueCache = iterator_to_array($values, false);\n            };\n        } else {\n            $callback = null;\n        }\n\n        return $this->setAutocompleterCallback($callback);\n    }\n\n    /**\n     * Gets the callback function used for the autocompleter.\n     */\n    public function getAutocompleterCallback(): ?callable\n    {\n        return $this->autocompleterCallback;\n    }\n\n    /**\n     * Sets the callback function used for the autocompleter.\n     *\n     * The callback is passed the user input as argument and should return an iterable of corresponding suggestions.\n     *\n     * @return $this\n     */\n    public function setAutocompleterCallback(?callable $callback = null): self\n    {\n        if ($this->hidden && null !== $callback) {\n            throw new LogicException('A hidden question cannot use the autocompleter.');\n        }\n\n        $this->autocompleterCallback = $callback;\n\n        return $this;\n    }\n\n    /**\n     * Sets a validator for the question.\n     *\n     * @return $this\n     */\n    public function setValidator(?callable $validator = null)\n    {\n        $this->validator = $validator;\n\n        return $this;\n    }\n\n    /**\n     * Gets the validator for the question.\n     *\n     * @return callable|null\n     */\n    public function getValidator()\n    {\n        return $this->validator;\n    }\n\n    /**\n     * Sets the maximum number of attempts.\n     *\n     * Null means an unlimited number of attempts.\n     *\n     * @return $this\n     *\n     * @throws InvalidArgumentException in case the number of attempts is invalid\n     */\n    public function setMaxAttempts(?int $attempts)\n    {\n        if (null !== $attempts && $attempts < 1) {\n            throw new InvalidArgumentException('Maximum number of attempts must be a positive value.');\n        }\n\n        $this->attempts = $attempts;\n\n        return $this;\n    }\n\n    /**\n     * Gets the maximum number of attempts.\n     *\n     * Null means an unlimited number of attempts.\n     *\n     * @return int|null\n     */\n    public function getMaxAttempts()\n    {\n        return $this->attempts;\n    }\n\n    /**\n     * Sets a normalizer for the response.\n     *\n     * The normalizer can be a callable (a string), a closure or a class implementing __invoke.\n     *\n     * @return $this\n     */\n    public function setNormalizer(callable $normalizer)\n    {\n        $this->normalizer = $normalizer;\n\n        return $this;\n    }\n\n    /**\n     * Gets the normalizer for the response.\n     *\n     * The normalizer can ba a callable (a string), a closure or a class implementing __invoke.\n     *\n     * @return callable|null\n     */\n    public function getNormalizer()\n    {\n        return $this->normalizer;\n    }\n\n    protected function isAssoc(array $array)\n    {\n        return (bool) \\count(array_filter(array_keys($array), 'is_string'));\n    }\n\n    public function isTrimmable(): bool\n    {\n        return $this->trimmable;\n    }\n\n    /**\n     * @return $this\n     */\n    public function setTrimmable(bool $trimmable): self\n    {\n        $this->trimmable = $trimmable;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/README.md",
    "content": "Console Component\n=================\n\nThe Console component eases the creation of beautiful and testable command line\ninterfaces.\n\nSponsor\n-------\n\nThe Console component for Symfony 5.4/6.0 is [backed][1] by [Les-Tilleuls.coop][2].\n\nLes-Tilleuls.coop is a team of 50+ Symfony experts who can help you design, develop and\nfix your projects. We provide a wide range of professional services including development,\nconsulting, coaching, training and audits. We also are highly skilled in JS, Go and DevOps.\nWe are a worker cooperative!\n\nHelp Symfony by [sponsoring][3] its development!\n\nResources\n---------\n\n * [Documentation](https://symfony.com/doc/current/components/console.html)\n * [Contributing](https://symfony.com/doc/current/contributing/index.html)\n * [Report issues](https://github.com/symfony/symfony/issues) and\n   [send Pull Requests](https://github.com/symfony/symfony/pulls)\n   in the [main Symfony repository](https://github.com/symfony/symfony)\n\nCredits\n-------\n\n`Resources/bin/hiddeninput.exe` is a third party binary provided within this\ncomponent. Find sources and license at https://github.com/Seldaek/hidden-input.\n\n[1]: https://symfony.com/backers\n[2]: https://les-tilleuls.coop\n[3]: https://symfony.com/sponsor\n"
  },
  {
    "path": "server/vendor/symfony/console/Resources/completion.bash",
    "content": "# This file is part of the Symfony package.\n#\n# (c) Fabien Potencier <fabien@symfony.com>\n#\n# For the full copyright and license information, please view\n# https://symfony.com/doc/current/contributing/code/license.html\n\n_sf_{{ COMMAND_NAME }}() {\n    # Use newline as only separator to allow space in completion values\n    local IFS=$'\\n'\n    local sf_cmd=\"${COMP_WORDS[0]}\"\n\n    # for an alias, get the real script behind it\n    sf_cmd_type=$(type -t $sf_cmd)\n    if [[ $sf_cmd_type == \"alias\" ]]; then\n        sf_cmd=$(alias $sf_cmd | sed -E \"s/alias $sf_cmd='(.*)'/\\1/\")\n    elif [[ $sf_cmd_type == \"file\" ]]; then\n        sf_cmd=$(type -p $sf_cmd)\n    fi\n\n    if [[ $sf_cmd_type != \"function\" && ! -x $sf_cmd ]]; then\n        return 1\n    fi\n\n    local cur prev words cword\n    _get_comp_words_by_ref -n := cur prev words cword\n\n    local completecmd=(\"$sf_cmd\" \"_complete\" \"--no-interaction\" \"-sbash\" \"-c$cword\" \"-S{{ VERSION }}\")\n    for w in ${words[@]}; do\n        w=$(printf -- '%b' \"$w\")\n        # remove quotes from typed values\n        quote=\"${w:0:1}\"\n        if [ \"$quote\" == \\' ]; then\n            w=\"${w%\\'}\"\n            w=\"${w#\\'}\"\n        elif [ \"$quote\" == \\\" ]; then\n            w=\"${w%\\\"}\"\n            w=\"${w#\\\"}\"\n        fi\n        # empty values are ignored\n        if [ ! -z \"$w\" ]; then\n            completecmd+=(\"-i$w\")\n        fi\n    done\n\n    local sfcomplete\n    if sfcomplete=$(${completecmd[@]} 2>&1); then\n        local quote suggestions\n        quote=${cur:0:1}\n\n        # Use single quotes by default if suggestions contains backslash (FQCN)\n        if [ \"$quote\" == '' ] && [[ \"$sfcomplete\" =~ \\\\ ]]; then\n            quote=\\'\n        fi\n\n        if [ \"$quote\" == \\' ]; then\n            # single quotes: no additional escaping (does not accept ' in values)\n            suggestions=$(for s in $sfcomplete; do printf $'%q%q%q\\n' \"$quote\" \"$s\" \"$quote\"; done)\n        elif [ \"$quote\" == \\\" ]; then\n            # double quotes: double escaping for \\ $ ` \"\n            suggestions=$(for s in $sfcomplete; do\n                s=${s//\\\\/\\\\\\\\}\n                s=${s//\\$/\\\\\\$}\n                s=${s//\\`/\\\\\\`}\n                s=${s//\\\"/\\\\\\\"}\n                printf $'%q%q%q\\n' \"$quote\" \"$s\" \"$quote\";\n            done)\n        else\n            # no quotes: double escaping\n            suggestions=$(for s in $sfcomplete; do printf $'%q\\n' $(printf '%q' \"$s\"); done)\n        fi\n        COMPREPLY=($(IFS=$'\\n' compgen -W \"$suggestions\" -- $(printf -- \"%q\" \"$cur\")))\n        __ltrim_colon_completions \"$cur\"\n    else\n        if [[ \"$sfcomplete\" != *\"Command \\\"_complete\\\" is not defined.\"* ]]; then\n            >&2 echo\n            >&2 echo $sfcomplete\n        fi\n\n        return 1\n    fi\n}\n\ncomplete -F _sf_{{ COMMAND_NAME }} {{ COMMAND_NAME }}\n"
  },
  {
    "path": "server/vendor/symfony/console/SignalRegistry/SignalRegistry.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\SignalRegistry;\n\nfinal class SignalRegistry\n{\n    private $signalHandlers = [];\n\n    public function __construct()\n    {\n        if (\\function_exists('pcntl_async_signals')) {\n            pcntl_async_signals(true);\n        }\n    }\n\n    public function register(int $signal, callable $signalHandler): void\n    {\n        if (!isset($this->signalHandlers[$signal])) {\n            $previousCallback = pcntl_signal_get_handler($signal);\n\n            if (\\is_callable($previousCallback)) {\n                $this->signalHandlers[$signal][] = $previousCallback;\n            }\n        }\n\n        $this->signalHandlers[$signal][] = $signalHandler;\n\n        pcntl_signal($signal, [$this, 'handle']);\n    }\n\n    public static function isSupported(): bool\n    {\n        if (!\\function_exists('pcntl_signal')) {\n            return false;\n        }\n\n        if (\\in_array('pcntl_signal', explode(',', \\ini_get('disable_functions')))) {\n            return false;\n        }\n\n        return true;\n    }\n\n    /**\n     * @internal\n     */\n    public function handle(int $signal): void\n    {\n        $count = \\count($this->signalHandlers[$signal]);\n\n        foreach ($this->signalHandlers[$signal] as $i => $signalHandler) {\n            $hasNext = $i !== $count - 1;\n            $signalHandler($signal, $hasNext);\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/SingleCommandApplication.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console;\n\nuse Symfony\\Component\\Console\\Command\\Command;\nuse Symfony\\Component\\Console\\Input\\InputInterface;\nuse Symfony\\Component\\Console\\Output\\OutputInterface;\n\n/**\n * @author Grégoire Pineau <lyrixx@lyrixx.info>\n */\nclass SingleCommandApplication extends Command\n{\n    private $version = 'UNKNOWN';\n    private $autoExit = true;\n    private $running = false;\n\n    /**\n     * @return $this\n     */\n    public function setVersion(string $version): self\n    {\n        $this->version = $version;\n\n        return $this;\n    }\n\n    /**\n     * @final\n     *\n     * @return $this\n     */\n    public function setAutoExit(bool $autoExit): self\n    {\n        $this->autoExit = $autoExit;\n\n        return $this;\n    }\n\n    public function run(?InputInterface $input = null, ?OutputInterface $output = null): int\n    {\n        if ($this->running) {\n            return parent::run($input, $output);\n        }\n\n        // We use the command name as the application name\n        $application = new Application($this->getName() ?: 'UNKNOWN', $this->version);\n        $application->setAutoExit($this->autoExit);\n        // Fix the usage of the command displayed with \"--help\"\n        $this->setName($_SERVER['argv'][0]);\n        $application->add($this);\n        $application->setDefaultCommand($this->getName(), true);\n\n        $this->running = true;\n        try {\n            $ret = $application->run($input, $output);\n        } finally {\n            $this->running = false;\n        }\n\n        return $ret ?? 1;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Style/OutputStyle.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Style;\n\nuse Symfony\\Component\\Console\\Formatter\\OutputFormatterInterface;\nuse Symfony\\Component\\Console\\Helper\\ProgressBar;\nuse Symfony\\Component\\Console\\Output\\ConsoleOutputInterface;\nuse Symfony\\Component\\Console\\Output\\OutputInterface;\n\n/**\n * Decorates output to add console style guide helpers.\n *\n * @author Kevin Bond <kevinbond@gmail.com>\n */\nabstract class OutputStyle implements OutputInterface, StyleInterface\n{\n    private $output;\n\n    public function __construct(OutputInterface $output)\n    {\n        $this->output = $output;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function newLine(int $count = 1)\n    {\n        $this->output->write(str_repeat(\\PHP_EOL, $count));\n    }\n\n    /**\n     * @return ProgressBar\n     */\n    public function createProgressBar(int $max = 0)\n    {\n        return new ProgressBar($this->output, $max);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function write($messages, bool $newline = false, int $type = self::OUTPUT_NORMAL)\n    {\n        $this->output->write($messages, $newline, $type);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function writeln($messages, int $type = self::OUTPUT_NORMAL)\n    {\n        $this->output->writeln($messages, $type);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function setVerbosity(int $level)\n    {\n        $this->output->setVerbosity($level);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getVerbosity()\n    {\n        return $this->output->getVerbosity();\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function setDecorated(bool $decorated)\n    {\n        $this->output->setDecorated($decorated);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function isDecorated()\n    {\n        return $this->output->isDecorated();\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function setFormatter(OutputFormatterInterface $formatter)\n    {\n        $this->output->setFormatter($formatter);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getFormatter()\n    {\n        return $this->output->getFormatter();\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function isQuiet()\n    {\n        return $this->output->isQuiet();\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function isVerbose()\n    {\n        return $this->output->isVerbose();\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function isVeryVerbose()\n    {\n        return $this->output->isVeryVerbose();\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function isDebug()\n    {\n        return $this->output->isDebug();\n    }\n\n    protected function getErrorOutput()\n    {\n        if (!$this->output instanceof ConsoleOutputInterface) {\n            return $this->output;\n        }\n\n        return $this->output->getErrorOutput();\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Style/StyleInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Style;\n\n/**\n * Output style helpers.\n *\n * @author Kevin Bond <kevinbond@gmail.com>\n */\ninterface StyleInterface\n{\n    /**\n     * Formats a command title.\n     */\n    public function title(string $message);\n\n    /**\n     * Formats a section title.\n     */\n    public function section(string $message);\n\n    /**\n     * Formats a list.\n     */\n    public function listing(array $elements);\n\n    /**\n     * Formats informational text.\n     *\n     * @param string|array $message\n     */\n    public function text($message);\n\n    /**\n     * Formats a success result bar.\n     *\n     * @param string|array $message\n     */\n    public function success($message);\n\n    /**\n     * Formats an error result bar.\n     *\n     * @param string|array $message\n     */\n    public function error($message);\n\n    /**\n     * Formats an warning result bar.\n     *\n     * @param string|array $message\n     */\n    public function warning($message);\n\n    /**\n     * Formats a note admonition.\n     *\n     * @param string|array $message\n     */\n    public function note($message);\n\n    /**\n     * Formats a caution admonition.\n     *\n     * @param string|array $message\n     */\n    public function caution($message);\n\n    /**\n     * Formats a table.\n     */\n    public function table(array $headers, array $rows);\n\n    /**\n     * Asks a question.\n     *\n     * @return mixed\n     */\n    public function ask(string $question, ?string $default = null, ?callable $validator = null);\n\n    /**\n     * Asks a question with the user input hidden.\n     *\n     * @return mixed\n     */\n    public function askHidden(string $question, ?callable $validator = null);\n\n    /**\n     * Asks for confirmation.\n     *\n     * @return bool\n     */\n    public function confirm(string $question, bool $default = true);\n\n    /**\n     * Asks a choice question.\n     *\n     * @param string|int|null $default\n     *\n     * @return mixed\n     */\n    public function choice(string $question, array $choices, $default = null);\n\n    /**\n     * Add newline(s).\n     */\n    public function newLine(int $count = 1);\n\n    /**\n     * Starts the progress output.\n     */\n    public function progressStart(int $max = 0);\n\n    /**\n     * Advances the progress output X steps.\n     */\n    public function progressAdvance(int $step = 1);\n\n    /**\n     * Finishes the progress output.\n     */\n    public function progressFinish();\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Style/SymfonyStyle.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Style;\n\nuse Symfony\\Component\\Console\\Exception\\InvalidArgumentException;\nuse Symfony\\Component\\Console\\Exception\\RuntimeException;\nuse Symfony\\Component\\Console\\Formatter\\OutputFormatter;\nuse Symfony\\Component\\Console\\Helper\\Helper;\nuse Symfony\\Component\\Console\\Helper\\ProgressBar;\nuse Symfony\\Component\\Console\\Helper\\SymfonyQuestionHelper;\nuse Symfony\\Component\\Console\\Helper\\Table;\nuse Symfony\\Component\\Console\\Helper\\TableCell;\nuse Symfony\\Component\\Console\\Helper\\TableSeparator;\nuse Symfony\\Component\\Console\\Input\\InputInterface;\nuse Symfony\\Component\\Console\\Output\\ConsoleOutputInterface;\nuse Symfony\\Component\\Console\\Output\\OutputInterface;\nuse Symfony\\Component\\Console\\Output\\TrimmedBufferOutput;\nuse Symfony\\Component\\Console\\Question\\ChoiceQuestion;\nuse Symfony\\Component\\Console\\Question\\ConfirmationQuestion;\nuse Symfony\\Component\\Console\\Question\\Question;\nuse Symfony\\Component\\Console\\Terminal;\n\n/**\n * Output decorator helpers for the Symfony Style Guide.\n *\n * @author Kevin Bond <kevinbond@gmail.com>\n */\nclass SymfonyStyle extends OutputStyle\n{\n    public const MAX_LINE_LENGTH = 120;\n\n    private $input;\n    private $output;\n    private $questionHelper;\n    private $progressBar;\n    private $lineLength;\n    private $bufferedOutput;\n\n    public function __construct(InputInterface $input, OutputInterface $output)\n    {\n        $this->input = $input;\n        $this->bufferedOutput = new TrimmedBufferOutput(\\DIRECTORY_SEPARATOR === '\\\\' ? 4 : 2, $output->getVerbosity(), false, clone $output->getFormatter());\n        // Windows cmd wraps lines as soon as the terminal width is reached, whether there are following chars or not.\n        $width = (new Terminal())->getWidth() ?: self::MAX_LINE_LENGTH;\n        $this->lineLength = min($width - (int) (\\DIRECTORY_SEPARATOR === '\\\\'), self::MAX_LINE_LENGTH);\n\n        parent::__construct($this->output = $output);\n    }\n\n    /**\n     * Formats a message as a block of text.\n     *\n     * @param string|array $messages The message to write in the block\n     */\n    public function block($messages, ?string $type = null, ?string $style = null, string $prefix = ' ', bool $padding = false, bool $escape = true)\n    {\n        $messages = \\is_array($messages) ? array_values($messages) : [$messages];\n\n        $this->autoPrependBlock();\n        $this->writeln($this->createBlock($messages, $type, $style, $prefix, $padding, $escape));\n        $this->newLine();\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function title(string $message)\n    {\n        $this->autoPrependBlock();\n        $this->writeln([\n            sprintf('<comment>%s</>', OutputFormatter::escapeTrailingBackslash($message)),\n            sprintf('<comment>%s</>', str_repeat('=', Helper::width(Helper::removeDecoration($this->getFormatter(), $message)))),\n        ]);\n        $this->newLine();\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function section(string $message)\n    {\n        $this->autoPrependBlock();\n        $this->writeln([\n            sprintf('<comment>%s</>', OutputFormatter::escapeTrailingBackslash($message)),\n            sprintf('<comment>%s</>', str_repeat('-', Helper::width(Helper::removeDecoration($this->getFormatter(), $message)))),\n        ]);\n        $this->newLine();\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function listing(array $elements)\n    {\n        $this->autoPrependText();\n        $elements = array_map(function ($element) {\n            return sprintf(' * %s', $element);\n        }, $elements);\n\n        $this->writeln($elements);\n        $this->newLine();\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function text($message)\n    {\n        $this->autoPrependText();\n\n        $messages = \\is_array($message) ? array_values($message) : [$message];\n        foreach ($messages as $message) {\n            $this->writeln(sprintf(' %s', $message));\n        }\n    }\n\n    /**\n     * Formats a command comment.\n     *\n     * @param string|array $message\n     */\n    public function comment($message)\n    {\n        $this->block($message, null, null, '<fg=default;bg=default> // </>', false, false);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function success($message)\n    {\n        $this->block($message, 'OK', 'fg=black;bg=green', ' ', true);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function error($message)\n    {\n        $this->block($message, 'ERROR', 'fg=white;bg=red', ' ', true);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function warning($message)\n    {\n        $this->block($message, 'WARNING', 'fg=black;bg=yellow', ' ', true);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function note($message)\n    {\n        $this->block($message, 'NOTE', 'fg=yellow', ' ! ');\n    }\n\n    /**\n     * Formats an info message.\n     *\n     * @param string|array $message\n     */\n    public function info($message)\n    {\n        $this->block($message, 'INFO', 'fg=green', ' ', true);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function caution($message)\n    {\n        $this->block($message, 'CAUTION', 'fg=white;bg=red', ' ! ', true);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function table(array $headers, array $rows)\n    {\n        $this->createTable()\n            ->setHeaders($headers)\n            ->setRows($rows)\n            ->render()\n        ;\n\n        $this->newLine();\n    }\n\n    /**\n     * Formats a horizontal table.\n     */\n    public function horizontalTable(array $headers, array $rows)\n    {\n        $this->createTable()\n            ->setHorizontal(true)\n            ->setHeaders($headers)\n            ->setRows($rows)\n            ->render()\n        ;\n\n        $this->newLine();\n    }\n\n    /**\n     * Formats a list of key/value horizontally.\n     *\n     * Each row can be one of:\n     * * 'A title'\n     * * ['key' => 'value']\n     * * new TableSeparator()\n     *\n     * @param string|array|TableSeparator ...$list\n     */\n    public function definitionList(...$list)\n    {\n        $headers = [];\n        $row = [];\n        foreach ($list as $value) {\n            if ($value instanceof TableSeparator) {\n                $headers[] = $value;\n                $row[] = $value;\n                continue;\n            }\n            if (\\is_string($value)) {\n                $headers[] = new TableCell($value, ['colspan' => 2]);\n                $row[] = null;\n                continue;\n            }\n            if (!\\is_array($value)) {\n                throw new InvalidArgumentException('Value should be an array, string, or an instance of TableSeparator.');\n            }\n            $headers[] = key($value);\n            $row[] = current($value);\n        }\n\n        $this->horizontalTable($headers, [$row]);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function ask(string $question, ?string $default = null, ?callable $validator = null)\n    {\n        $question = new Question($question, $default);\n        $question->setValidator($validator);\n\n        return $this->askQuestion($question);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function askHidden(string $question, ?callable $validator = null)\n    {\n        $question = new Question($question);\n\n        $question->setHidden(true);\n        $question->setValidator($validator);\n\n        return $this->askQuestion($question);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function confirm(string $question, bool $default = true)\n    {\n        return $this->askQuestion(new ConfirmationQuestion($question, $default));\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function choice(string $question, array $choices, $default = null)\n    {\n        if (null !== $default) {\n            $values = array_flip($choices);\n            $default = $values[$default] ?? $default;\n        }\n\n        return $this->askQuestion(new ChoiceQuestion($question, $choices, $default));\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function progressStart(int $max = 0)\n    {\n        $this->progressBar = $this->createProgressBar($max);\n        $this->progressBar->start();\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function progressAdvance(int $step = 1)\n    {\n        $this->getProgressBar()->advance($step);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function progressFinish()\n    {\n        $this->getProgressBar()->finish();\n        $this->newLine(2);\n        $this->progressBar = null;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function createProgressBar(int $max = 0)\n    {\n        $progressBar = parent::createProgressBar($max);\n\n        if ('\\\\' !== \\DIRECTORY_SEPARATOR || 'Hyper' === getenv('TERM_PROGRAM')) {\n            $progressBar->setEmptyBarCharacter('░'); // light shade character \\u2591\n            $progressBar->setProgressCharacter('');\n            $progressBar->setBarCharacter('▓'); // dark shade character \\u2593\n        }\n\n        return $progressBar;\n    }\n\n    /**\n     * @see ProgressBar::iterate()\n     */\n    public function progressIterate(iterable $iterable, ?int $max = null): iterable\n    {\n        yield from $this->createProgressBar()->iterate($iterable, $max);\n\n        $this->newLine(2);\n    }\n\n    /**\n     * @return mixed\n     */\n    public function askQuestion(Question $question)\n    {\n        if ($this->input->isInteractive()) {\n            $this->autoPrependBlock();\n        }\n\n        if (!$this->questionHelper) {\n            $this->questionHelper = new SymfonyQuestionHelper();\n        }\n\n        $answer = $this->questionHelper->ask($this->input, $this, $question);\n\n        if ($this->input->isInteractive()) {\n            $this->newLine();\n            $this->bufferedOutput->write(\"\\n\");\n        }\n\n        return $answer;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function writeln($messages, int $type = self::OUTPUT_NORMAL)\n    {\n        if (!is_iterable($messages)) {\n            $messages = [$messages];\n        }\n\n        foreach ($messages as $message) {\n            parent::writeln($message, $type);\n            $this->writeBuffer($message, true, $type);\n        }\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function write($messages, bool $newline = false, int $type = self::OUTPUT_NORMAL)\n    {\n        if (!is_iterable($messages)) {\n            $messages = [$messages];\n        }\n\n        foreach ($messages as $message) {\n            parent::write($message, $newline, $type);\n            $this->writeBuffer($message, $newline, $type);\n        }\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function newLine(int $count = 1)\n    {\n        parent::newLine($count);\n        $this->bufferedOutput->write(str_repeat(\"\\n\", $count));\n    }\n\n    /**\n     * Returns a new instance which makes use of stderr if available.\n     *\n     * @return self\n     */\n    public function getErrorStyle()\n    {\n        return new self($this->input, $this->getErrorOutput());\n    }\n\n    public function createTable(): Table\n    {\n        $output = $this->output instanceof ConsoleOutputInterface ? $this->output->section() : $this->output;\n        $style = clone Table::getStyleDefinition('symfony-style-guide');\n        $style->setCellHeaderFormat('<info>%s</info>');\n\n        return (new Table($output))->setStyle($style);\n    }\n\n    private function getProgressBar(): ProgressBar\n    {\n        if (!$this->progressBar) {\n            throw new RuntimeException('The ProgressBar is not started.');\n        }\n\n        return $this->progressBar;\n    }\n\n    private function autoPrependBlock(): void\n    {\n        $chars = substr(str_replace(\\PHP_EOL, \"\\n\", $this->bufferedOutput->fetch()), -2);\n\n        if (!isset($chars[0])) {\n            $this->newLine(); // empty history, so we should start with a new line.\n\n            return;\n        }\n        // Prepend new line for each non LF chars (This means no blank line was output before)\n        $this->newLine(2 - substr_count($chars, \"\\n\"));\n    }\n\n    private function autoPrependText(): void\n    {\n        $fetched = $this->bufferedOutput->fetch();\n        // Prepend new line if last char isn't EOL:\n        if (!str_ends_with($fetched, \"\\n\")) {\n            $this->newLine();\n        }\n    }\n\n    private function writeBuffer(string $message, bool $newLine, int $type): void\n    {\n        // We need to know if the last chars are PHP_EOL\n        $this->bufferedOutput->write($message, $newLine, $type);\n    }\n\n    private function createBlock(iterable $messages, ?string $type = null, ?string $style = null, string $prefix = ' ', bool $padding = false, bool $escape = false): array\n    {\n        $indentLength = 0;\n        $prefixLength = Helper::width(Helper::removeDecoration($this->getFormatter(), $prefix));\n        $lines = [];\n\n        if (null !== $type) {\n            $type = sprintf('[%s] ', $type);\n            $indentLength = \\strlen($type);\n            $lineIndentation = str_repeat(' ', $indentLength);\n        }\n\n        // wrap and add newlines for each element\n        foreach ($messages as $key => $message) {\n            if ($escape) {\n                $message = OutputFormatter::escape($message);\n            }\n\n            $decorationLength = Helper::width($message) - Helper::width(Helper::removeDecoration($this->getFormatter(), $message));\n            $messageLineLength = min($this->lineLength - $prefixLength - $indentLength + $decorationLength, $this->lineLength);\n            $messageLines = explode(\\PHP_EOL, wordwrap($message, $messageLineLength, \\PHP_EOL, true));\n            foreach ($messageLines as $messageLine) {\n                $lines[] = $messageLine;\n            }\n\n            if (\\count($messages) > 1 && $key < \\count($messages) - 1) {\n                $lines[] = '';\n            }\n        }\n\n        $firstLineIndex = 0;\n        if ($padding && $this->isDecorated()) {\n            $firstLineIndex = 1;\n            array_unshift($lines, '');\n            $lines[] = '';\n        }\n\n        foreach ($lines as $i => &$line) {\n            if (null !== $type) {\n                $line = $firstLineIndex === $i ? $type.$line : $lineIndentation.$line;\n            }\n\n            $line = $prefix.$line;\n            $line .= str_repeat(' ', max($this->lineLength - Helper::width(Helper::removeDecoration($this->getFormatter(), $line)), 0));\n\n            if ($style) {\n                $line = sprintf('<%s>%s</>', $style, $line);\n            }\n        }\n\n        return $lines;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Terminal.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console;\n\nclass Terminal\n{\n    private static $width;\n    private static $height;\n    private static $stty;\n\n    /**\n     * Gets the terminal width.\n     *\n     * @return int\n     */\n    public function getWidth()\n    {\n        $width = getenv('COLUMNS');\n        if (false !== $width) {\n            return (int) trim($width);\n        }\n\n        if (null === self::$width) {\n            self::initDimensions();\n        }\n\n        return self::$width ?: 80;\n    }\n\n    /**\n     * Gets the terminal height.\n     *\n     * @return int\n     */\n    public function getHeight()\n    {\n        $height = getenv('LINES');\n        if (false !== $height) {\n            return (int) trim($height);\n        }\n\n        if (null === self::$height) {\n            self::initDimensions();\n        }\n\n        return self::$height ?: 50;\n    }\n\n    /**\n     * @internal\n     */\n    public static function hasSttyAvailable(): bool\n    {\n        if (null !== self::$stty) {\n            return self::$stty;\n        }\n\n        // skip check if shell_exec function is disabled\n        if (!\\function_exists('shell_exec')) {\n            return false;\n        }\n\n        return self::$stty = (bool) shell_exec('stty 2> '.('\\\\' === \\DIRECTORY_SEPARATOR ? 'NUL' : '/dev/null'));\n    }\n\n    private static function initDimensions()\n    {\n        if ('\\\\' === \\DIRECTORY_SEPARATOR) {\n            $ansicon = getenv('ANSICON');\n            if (false !== $ansicon && preg_match('/^(\\d+)x(\\d+)(?: \\((\\d+)x(\\d+)\\))?$/', trim($ansicon), $matches)) {\n                // extract [w, H] from \"wxh (WxH)\"\n                // or [w, h] from \"wxh\"\n                self::$width = (int) $matches[1];\n                self::$height = isset($matches[4]) ? (int) $matches[4] : (int) $matches[2];\n            } elseif (!self::hasVt100Support() && self::hasSttyAvailable()) {\n                // only use stty on Windows if the terminal does not support vt100 (e.g. Windows 7 + git-bash)\n                // testing for stty in a Windows 10 vt100-enabled console will implicitly disable vt100 support on STDOUT\n                self::initDimensionsUsingStty();\n            } elseif (null !== $dimensions = self::getConsoleMode()) {\n                // extract [w, h] from \"wxh\"\n                self::$width = (int) $dimensions[0];\n                self::$height = (int) $dimensions[1];\n            }\n        } else {\n            self::initDimensionsUsingStty();\n        }\n    }\n\n    /**\n     * Returns whether STDOUT has vt100 support (some Windows 10+ configurations).\n     */\n    private static function hasVt100Support(): bool\n    {\n        return \\function_exists('sapi_windows_vt100_support') && sapi_windows_vt100_support(fopen('php://stdout', 'w'));\n    }\n\n    /**\n     * Initializes dimensions using the output of an stty columns line.\n     */\n    private static function initDimensionsUsingStty()\n    {\n        if ($sttyString = self::getSttyColumns()) {\n            if (preg_match('/rows.(\\d+);.columns.(\\d+);/i', $sttyString, $matches)) {\n                // extract [w, h] from \"rows h; columns w;\"\n                self::$width = (int) $matches[2];\n                self::$height = (int) $matches[1];\n            } elseif (preg_match('/;.(\\d+).rows;.(\\d+).columns/i', $sttyString, $matches)) {\n                // extract [w, h] from \"; h rows; w columns\"\n                self::$width = (int) $matches[2];\n                self::$height = (int) $matches[1];\n            }\n        }\n    }\n\n    /**\n     * Runs and parses mode CON if it's available, suppressing any error output.\n     *\n     * @return int[]|null An array composed of the width and the height or null if it could not be parsed\n     */\n    private static function getConsoleMode(): ?array\n    {\n        $info = self::readFromProcess('mode CON');\n\n        if (null === $info || !preg_match('/--------+\\r?\\n.+?(\\d+)\\r?\\n.+?(\\d+)\\r?\\n/', $info, $matches)) {\n            return null;\n        }\n\n        return [(int) $matches[2], (int) $matches[1]];\n    }\n\n    /**\n     * Runs and parses stty -a if it's available, suppressing any error output.\n     */\n    private static function getSttyColumns(): ?string\n    {\n        return self::readFromProcess('stty -a | grep columns');\n    }\n\n    private static function readFromProcess(string $command): ?string\n    {\n        if (!\\function_exists('proc_open')) {\n            return null;\n        }\n\n        $descriptorspec = [\n            1 => ['pipe', 'w'],\n            2 => ['pipe', 'w'],\n        ];\n\n        $cp = \\function_exists('sapi_windows_cp_set') ? sapi_windows_cp_get() : 0;\n\n        if (!$process = @proc_open($command, $descriptorspec, $pipes, null, null, ['suppress_errors' => true])) {\n            return null;\n        }\n\n        $info = stream_get_contents($pipes[1]);\n        fclose($pipes[1]);\n        fclose($pipes[2]);\n        proc_close($process);\n\n        if ($cp) {\n            sapi_windows_cp_set($cp);\n        }\n\n        return $info;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Tester/ApplicationTester.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Tester;\n\nuse Symfony\\Component\\Console\\Application;\nuse Symfony\\Component\\Console\\Input\\ArrayInput;\n\n/**\n * Eases the testing of console applications.\n *\n * When testing an application, don't forget to disable the auto exit flag:\n *\n *     $application = new Application();\n *     $application->setAutoExit(false);\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass ApplicationTester\n{\n    use TesterTrait;\n\n    private $application;\n\n    public function __construct(Application $application)\n    {\n        $this->application = $application;\n    }\n\n    /**\n     * Executes the application.\n     *\n     * Available options:\n     *\n     *  * interactive:               Sets the input interactive flag\n     *  * decorated:                 Sets the output decorated flag\n     *  * verbosity:                 Sets the output verbosity flag\n     *  * capture_stderr_separately: Make output of stdOut and stdErr separately available\n     *\n     * @return int The command exit code\n     */\n    public function run(array $input, array $options = [])\n    {\n        $prevShellVerbosity = getenv('SHELL_VERBOSITY');\n\n        try {\n            $this->input = new ArrayInput($input);\n            if (isset($options['interactive'])) {\n                $this->input->setInteractive($options['interactive']);\n            }\n\n            if ($this->inputs) {\n                $this->input->setStream(self::createStream($this->inputs));\n            }\n\n            $this->initOutput($options);\n\n            return $this->statusCode = $this->application->run($this->input, $this->output);\n        } finally {\n            // SHELL_VERBOSITY is set by Application::configureIO so we need to unset/reset it\n            // to its previous value to avoid one test's verbosity to spread to the following tests\n            if (false === $prevShellVerbosity) {\n                if (\\function_exists('putenv')) {\n                    @putenv('SHELL_VERBOSITY');\n                }\n                unset($_ENV['SHELL_VERBOSITY']);\n                unset($_SERVER['SHELL_VERBOSITY']);\n            } else {\n                if (\\function_exists('putenv')) {\n                    @putenv('SHELL_VERBOSITY='.$prevShellVerbosity);\n                }\n                $_ENV['SHELL_VERBOSITY'] = $prevShellVerbosity;\n                $_SERVER['SHELL_VERBOSITY'] = $prevShellVerbosity;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Tester/CommandCompletionTester.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Tester;\n\nuse Symfony\\Component\\Console\\Command\\Command;\nuse Symfony\\Component\\Console\\Completion\\CompletionInput;\nuse Symfony\\Component\\Console\\Completion\\CompletionSuggestions;\n\n/**\n * Eases the testing of command completion.\n *\n * @author Jérôme Tamarelle <jerome@tamarelle.net>\n */\nclass CommandCompletionTester\n{\n    private $command;\n\n    public function __construct(Command $command)\n    {\n        $this->command = $command;\n    }\n\n    /**\n     * Create completion suggestions from input tokens.\n     */\n    public function complete(array $input): array\n    {\n        $currentIndex = \\count($input);\n        if ('' === end($input)) {\n            array_pop($input);\n        }\n        array_unshift($input, $this->command->getName());\n\n        $completionInput = CompletionInput::fromTokens($input, $currentIndex);\n        $completionInput->bind($this->command->getDefinition());\n        $suggestions = new CompletionSuggestions();\n\n        $this->command->complete($completionInput, $suggestions);\n\n        $options = [];\n        foreach ($suggestions->getOptionSuggestions() as $option) {\n            $options[] = '--'.$option->getName();\n        }\n\n        return array_map('strval', array_merge($options, $suggestions->getValueSuggestions()));\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Tester/CommandTester.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Tester;\n\nuse Symfony\\Component\\Console\\Command\\Command;\nuse Symfony\\Component\\Console\\Input\\ArrayInput;\n\n/**\n * Eases the testing of console commands.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n * @author Robin Chalas <robin.chalas@gmail.com>\n */\nclass CommandTester\n{\n    use TesterTrait;\n\n    private $command;\n\n    public function __construct(Command $command)\n    {\n        $this->command = $command;\n    }\n\n    /**\n     * Executes the command.\n     *\n     * Available execution options:\n     *\n     *  * interactive:               Sets the input interactive flag\n     *  * decorated:                 Sets the output decorated flag\n     *  * verbosity:                 Sets the output verbosity flag\n     *  * capture_stderr_separately: Make output of stdOut and stdErr separately available\n     *\n     * @param array $input   An array of command arguments and options\n     * @param array $options An array of execution options\n     *\n     * @return int The command exit code\n     */\n    public function execute(array $input, array $options = [])\n    {\n        // set the command name automatically if the application requires\n        // this argument and no command name was passed\n        if (!isset($input['command'])\n            && (null !== $application = $this->command->getApplication())\n            && $application->getDefinition()->hasArgument('command')\n        ) {\n            $input = array_merge(['command' => $this->command->getName()], $input);\n        }\n\n        $this->input = new ArrayInput($input);\n        // Use an in-memory input stream even if no inputs are set so that QuestionHelper::ask() does not rely on the blocking STDIN.\n        $this->input->setStream(self::createStream($this->inputs));\n\n        if (isset($options['interactive'])) {\n            $this->input->setInteractive($options['interactive']);\n        }\n\n        if (!isset($options['decorated'])) {\n            $options['decorated'] = false;\n        }\n\n        $this->initOutput($options);\n\n        return $this->statusCode = $this->command->run($this->input, $this->output);\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Tester/Constraint/CommandIsSuccessful.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Tester\\Constraint;\n\nuse PHPUnit\\Framework\\Constraint\\Constraint;\nuse Symfony\\Component\\Console\\Command\\Command;\n\nfinal class CommandIsSuccessful extends Constraint\n{\n    /**\n     * {@inheritdoc}\n     */\n    public function toString(): string\n    {\n        return 'is successful';\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    protected function matches($other): bool\n    {\n        return Command::SUCCESS === $other;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    protected function failureDescription($other): string\n    {\n        return 'the command '.$this->toString();\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    protected function additionalFailureDescription($other): string\n    {\n        $mapping = [\n            Command::FAILURE => 'Command failed.',\n            Command::INVALID => 'Command was invalid.',\n        ];\n\n        return $mapping[$other] ?? sprintf('Command returned exit status %d.', $other);\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/Tester/TesterTrait.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Console\\Tester;\n\nuse PHPUnit\\Framework\\Assert;\nuse Symfony\\Component\\Console\\Input\\InputInterface;\nuse Symfony\\Component\\Console\\Output\\ConsoleOutput;\nuse Symfony\\Component\\Console\\Output\\OutputInterface;\nuse Symfony\\Component\\Console\\Output\\StreamOutput;\nuse Symfony\\Component\\Console\\Tester\\Constraint\\CommandIsSuccessful;\n\n/**\n * @author Amrouche Hamza <hamza.simperfit@gmail.com>\n */\ntrait TesterTrait\n{\n    /** @var StreamOutput */\n    private $output;\n    private $inputs = [];\n    private $captureStreamsIndependently = false;\n    /** @var InputInterface */\n    private $input;\n    /** @var int */\n    private $statusCode;\n\n    /**\n     * Gets the display returned by the last execution of the command or application.\n     *\n     * @return string\n     *\n     * @throws \\RuntimeException If it's called before the execute method\n     */\n    public function getDisplay(bool $normalize = false)\n    {\n        if (null === $this->output) {\n            throw new \\RuntimeException('Output not initialized, did you execute the command before requesting the display?');\n        }\n\n        rewind($this->output->getStream());\n\n        $display = stream_get_contents($this->output->getStream());\n\n        if ($normalize) {\n            $display = str_replace(\\PHP_EOL, \"\\n\", $display);\n        }\n\n        return $display;\n    }\n\n    /**\n     * Gets the output written to STDERR by the application.\n     *\n     * @param bool $normalize Whether to normalize end of lines to \\n or not\n     *\n     * @return string\n     */\n    public function getErrorOutput(bool $normalize = false)\n    {\n        if (!$this->captureStreamsIndependently) {\n            throw new \\LogicException('The error output is not available when the tester is run without \"capture_stderr_separately\" option set.');\n        }\n\n        rewind($this->output->getErrorOutput()->getStream());\n\n        $display = stream_get_contents($this->output->getErrorOutput()->getStream());\n\n        if ($normalize) {\n            $display = str_replace(\\PHP_EOL, \"\\n\", $display);\n        }\n\n        return $display;\n    }\n\n    /**\n     * Gets the input instance used by the last execution of the command or application.\n     *\n     * @return InputInterface\n     */\n    public function getInput()\n    {\n        return $this->input;\n    }\n\n    /**\n     * Gets the output instance used by the last execution of the command or application.\n     *\n     * @return OutputInterface\n     */\n    public function getOutput()\n    {\n        return $this->output;\n    }\n\n    /**\n     * Gets the status code returned by the last execution of the command or application.\n     *\n     * @return int\n     *\n     * @throws \\RuntimeException If it's called before the execute method\n     */\n    public function getStatusCode()\n    {\n        if (null === $this->statusCode) {\n            throw new \\RuntimeException('Status code not initialized, did you execute the command before requesting the status code?');\n        }\n\n        return $this->statusCode;\n    }\n\n    public function assertCommandIsSuccessful(string $message = ''): void\n    {\n        Assert::assertThat($this->statusCode, new CommandIsSuccessful(), $message);\n    }\n\n    /**\n     * Sets the user inputs.\n     *\n     * @param array $inputs An array of strings representing each input\n     *                      passed to the command input stream\n     *\n     * @return $this\n     */\n    public function setInputs(array $inputs)\n    {\n        $this->inputs = $inputs;\n\n        return $this;\n    }\n\n    /**\n     * Initializes the output property.\n     *\n     * Available options:\n     *\n     *  * decorated:                 Sets the output decorated flag\n     *  * verbosity:                 Sets the output verbosity flag\n     *  * capture_stderr_separately: Make output of stdOut and stdErr separately available\n     */\n    private function initOutput(array $options)\n    {\n        $this->captureStreamsIndependently = \\array_key_exists('capture_stderr_separately', $options) && $options['capture_stderr_separately'];\n        if (!$this->captureStreamsIndependently) {\n            $this->output = new StreamOutput(fopen('php://memory', 'w', false));\n            if (isset($options['decorated'])) {\n                $this->output->setDecorated($options['decorated']);\n            }\n            if (isset($options['verbosity'])) {\n                $this->output->setVerbosity($options['verbosity']);\n            }\n        } else {\n            $this->output = new ConsoleOutput(\n                $options['verbosity'] ?? ConsoleOutput::VERBOSITY_NORMAL,\n                $options['decorated'] ?? null\n            );\n\n            $errorOutput = new StreamOutput(fopen('php://memory', 'w', false));\n            $errorOutput->setFormatter($this->output->getFormatter());\n            $errorOutput->setVerbosity($this->output->getVerbosity());\n            $errorOutput->setDecorated($this->output->isDecorated());\n\n            $reflectedOutput = new \\ReflectionObject($this->output);\n            $strErrProperty = $reflectedOutput->getProperty('stderr');\n            $strErrProperty->setAccessible(true);\n            $strErrProperty->setValue($this->output, $errorOutput);\n\n            $reflectedParent = $reflectedOutput->getParentClass();\n            $streamProperty = $reflectedParent->getProperty('stream');\n            $streamProperty->setAccessible(true);\n            $streamProperty->setValue($this->output, fopen('php://memory', 'w', false));\n        }\n    }\n\n    /**\n     * @return resource\n     */\n    private static function createStream(array $inputs)\n    {\n        $stream = fopen('php://memory', 'r+', false);\n\n        foreach ($inputs as $input) {\n            fwrite($stream, $input.\\PHP_EOL);\n        }\n\n        rewind($stream);\n\n        return $stream;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/console/composer.json",
    "content": "{\n    \"name\": \"symfony/console\",\n    \"type\": \"library\",\n    \"description\": \"Eases the creation of beautiful and testable command line interfaces\",\n    \"keywords\": [\"console\", \"cli\", \"command-line\", \"terminal\"],\n    \"homepage\": \"https://symfony.com\",\n    \"license\": \"MIT\",\n    \"authors\": [\n        {\n            \"name\": \"Fabien Potencier\",\n            \"email\": \"fabien@symfony.com\"\n        },\n        {\n            \"name\": \"Symfony Community\",\n            \"homepage\": \"https://symfony.com/contributors\"\n        }\n    ],\n    \"require\": {\n        \"php\": \">=7.2.5\",\n        \"symfony/deprecation-contracts\": \"^2.1|^3\",\n        \"symfony/polyfill-mbstring\": \"~1.0\",\n        \"symfony/polyfill-php73\": \"^1.9\",\n        \"symfony/polyfill-php80\": \"^1.16\",\n        \"symfony/service-contracts\": \"^1.1|^2|^3\",\n        \"symfony/string\": \"^5.1|^6.0\"\n    },\n    \"require-dev\": {\n        \"symfony/config\": \"^4.4|^5.0|^6.0\",\n        \"symfony/event-dispatcher\": \"^4.4|^5.0|^6.0\",\n        \"symfony/dependency-injection\": \"^4.4|^5.0|^6.0\",\n        \"symfony/lock\": \"^4.4|^5.0|^6.0\",\n        \"symfony/process\": \"^4.4|^5.0|^6.0\",\n        \"symfony/var-dumper\": \"^4.4|^5.0|^6.0\",\n        \"psr/log\": \"^1|^2\"\n    },\n    \"provide\": {\n        \"psr/log-implementation\": \"1.0|2.0\"\n    },\n    \"suggest\": {\n        \"symfony/event-dispatcher\": \"\",\n        \"symfony/lock\": \"\",\n        \"symfony/process\": \"\",\n        \"psr/log\": \"For using the console logger\"\n    },\n    \"conflict\": {\n        \"psr/log\": \">=3\",\n        \"symfony/dependency-injection\": \"<4.4\",\n        \"symfony/dotenv\": \"<5.1\",\n        \"symfony/event-dispatcher\": \"<4.4\",\n        \"symfony/lock\": \"<4.4\",\n        \"symfony/process\": \"<4.4\"\n    },\n    \"autoload\": {\n        \"psr-4\": { \"Symfony\\\\Component\\\\Console\\\\\": \"\" },\n        \"exclude-from-classmap\": [\n            \"/Tests/\"\n        ]\n    },\n    \"minimum-stability\": \"dev\"\n}\n"
  },
  {
    "path": "server/vendor/symfony/deprecation-contracts/CHANGELOG.md",
    "content": "CHANGELOG\n=========\n\nThe changelog is maintained for all Symfony contracts at the following URL:\nhttps://github.com/symfony/contracts/blob/main/CHANGELOG.md\n"
  },
  {
    "path": "server/vendor/symfony/deprecation-contracts/LICENSE",
    "content": "Copyright (c) 2020-present Fabien Potencier\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is furnished\nto do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "server/vendor/symfony/deprecation-contracts/README.md",
    "content": "Symfony Deprecation Contracts\n=============================\n\nA generic function and convention to trigger deprecation notices.\n\nThis package provides a single global function named `trigger_deprecation()` that triggers silenced deprecation notices.\n\nBy using a custom PHP error handler such as the one provided by the Symfony ErrorHandler component,\nthe triggered deprecations can be caught and logged for later discovery, both on dev and prod environments.\n\nThe function requires at least 3 arguments:\n - the name of the Composer package that is triggering the deprecation\n - the version of the package that introduced the deprecation\n - the message of the deprecation\n - more arguments can be provided: they will be inserted in the message using `printf()` formatting\n\nExample:\n```php\ntrigger_deprecation('symfony/blockchain', '8.9', 'Using \"%s\" is deprecated, use \"%s\" instead.', 'bitcoin', 'fabcoin');\n```\n\nThis will generate the following message:\n`Since symfony/blockchain 8.9: Using \"bitcoin\" is deprecated, use \"fabcoin\" instead.`\n\nWhile not recommended, the deprecation notices can be completely ignored by declaring an empty\n`function trigger_deprecation() {}` in your application.\n"
  },
  {
    "path": "server/vendor/symfony/deprecation-contracts/composer.json",
    "content": "{\n    \"name\": \"symfony/deprecation-contracts\",\n    \"type\": \"library\",\n    \"description\": \"A generic function and convention to trigger deprecation notices\",\n    \"homepage\": \"https://symfony.com\",\n    \"license\": \"MIT\",\n    \"authors\": [\n        {\n            \"name\": \"Nicolas Grekas\",\n            \"email\": \"p@tchwork.com\"\n        },\n        {\n            \"name\": \"Symfony Community\",\n            \"homepage\": \"https://symfony.com/contributors\"\n        }\n    ],\n    \"require\": {\n        \"php\": \">=8.1\"\n    },\n    \"autoload\": {\n        \"files\": [\n            \"function.php\"\n        ]\n    },\n    \"minimum-stability\": \"dev\",\n    \"extra\": {\n        \"branch-alias\": {\n            \"dev-main\": \"3.5-dev\"\n        },\n        \"thanks\": {\n            \"name\": \"symfony/contracts\",\n            \"url\": \"https://github.com/symfony/contracts\"\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/deprecation-contracts/function.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nif (!function_exists('trigger_deprecation')) {\n    /**\n     * Triggers a silenced deprecation notice.\n     *\n     * @param string $package The name of the Composer package that is triggering the deprecation\n     * @param string $version The version of the package that introduced the deprecation\n     * @param string $message The message of the deprecation\n     * @param mixed  ...$args Values to insert in the message using printf() formatting\n     *\n     * @author Nicolas Grekas <p@tchwork.com>\n     */\n    function trigger_deprecation(string $package, string $version, string $message, mixed ...$args): void\n    {\n        @trigger_error(($package || $version ? \"Since $package $version: \" : '').($args ? vsprintf($message, $args) : $message), \\E_USER_DEPRECATED);\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/finder/CHANGELOG.md",
    "content": "CHANGELOG\n=========\n\n6.4\n---\n\n * Add early directory pruning to `Finder::filter()`\n\n6.2\n---\n\n * Add `Finder::sortByExtension()` and `Finder::sortBySize()`\n * Add `Finder::sortByCaseInsensitiveName()` to sort by name with case insensitive sorting methods\n\n6.0\n---\n\n * Remove `Comparator::setTarget()` and `Comparator::setOperator()`\n\n5.4.0\n-----\n\n * Deprecate `Comparator::setTarget()` and `Comparator::setOperator()`\n * Add a constructor to `Comparator` that allows setting target and operator\n * Finder's iterator has now `Symfony\\Component\\Finder\\SplFileInfo` inner type specified\n * Add recursive .gitignore files support\n\n5.0.0\n-----\n\n * added `$useNaturalSort` argument to `Finder::sortByName()`\n\n4.3.0\n-----\n\n * added Finder::ignoreVCSIgnored() to ignore files based on rules listed in .gitignore\n\n4.2.0\n-----\n\n * added $useNaturalSort option to Finder::sortByName() method\n * the `Finder::sortByName()` method will have a new `$useNaturalSort`\n   argument in version 5.0, not defining it is deprecated\n * added `Finder::reverseSorting()` to reverse the sorting\n\n4.0.0\n-----\n\n * removed `ExceptionInterface`\n * removed `Symfony\\Component\\Finder\\Iterator\\FilterIterator`\n\n3.4.0\n-----\n\n * deprecated `Symfony\\Component\\Finder\\Iterator\\FilterIterator`\n * added Finder::hasResults() method to check if any results were found\n\n3.3.0\n-----\n\n * added double-star matching to Glob::toRegex()\n\n3.0.0\n-----\n\n * removed deprecated classes\n\n2.8.0\n-----\n\n * deprecated adapters and related classes\n\n2.5.0\n-----\n * added support for GLOB_BRACE in the paths passed to Finder::in()\n\n2.3.0\n-----\n\n * added a way to ignore unreadable directories (via Finder::ignoreUnreadableDirs())\n * unified the way subfolders that are not executable are handled by always throwing an AccessDeniedException exception\n\n2.2.0\n-----\n\n * added Finder::path() and Finder::notPath() methods\n * added finder adapters to improve performance on specific platforms\n * added support for wildcard characters (glob patterns) in the paths passed\n   to Finder::in()\n\n2.1.0\n-----\n\n * added Finder::sortByAccessedTime(), Finder::sortByChangedTime(), and\n   Finder::sortByModifiedTime()\n * added Countable to Finder\n * added support for an array of directories as an argument to\n   Finder::exclude()\n * added searching based on the file content via Finder::contains() and\n   Finder::notContains()\n * added support for the != operator in the Comparator\n * [BC BREAK] filter expressions (used for file name and content) are no more\n   considered as regexps but glob patterns when they are enclosed in '*' or '?'\n"
  },
  {
    "path": "server/vendor/symfony/finder/Comparator/Comparator.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Finder\\Comparator;\n\n/**\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass Comparator\n{\n    private string $target;\n    private string $operator;\n\n    public function __construct(string $target, string $operator = '==')\n    {\n        if (!\\in_array($operator, ['>', '<', '>=', '<=', '==', '!='])) {\n            throw new \\InvalidArgumentException(\\sprintf('Invalid operator \"%s\".', $operator));\n        }\n\n        $this->target = $target;\n        $this->operator = $operator;\n    }\n\n    /**\n     * Gets the target value.\n     */\n    public function getTarget(): string\n    {\n        return $this->target;\n    }\n\n    /**\n     * Gets the comparison operator.\n     */\n    public function getOperator(): string\n    {\n        return $this->operator;\n    }\n\n    /**\n     * Tests against the target.\n     */\n    public function test(mixed $test): bool\n    {\n        return match ($this->operator) {\n            '>' => $test > $this->target,\n            '>=' => $test >= $this->target,\n            '<' => $test < $this->target,\n            '<=' => $test <= $this->target,\n            '!=' => $test != $this->target,\n            default => $test == $this->target,\n        };\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/finder/Comparator/DateComparator.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Finder\\Comparator;\n\n/**\n * DateCompare compiles date comparisons.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass DateComparator extends Comparator\n{\n    /**\n     * @param string $test A comparison string\n     *\n     * @throws \\InvalidArgumentException If the test is not understood\n     */\n    public function __construct(string $test)\n    {\n        if (!preg_match('#^\\s*(==|!=|[<>]=?|after|since|before|until)?\\s*(.+?)\\s*$#i', $test, $matches)) {\n            throw new \\InvalidArgumentException(\\sprintf('Don\\'t understand \"%s\" as a date test.', $test));\n        }\n\n        try {\n            $date = new \\DateTimeImmutable($matches[2]);\n            $target = $date->format('U');\n        } catch (\\Exception) {\n            throw new \\InvalidArgumentException(\\sprintf('\"%s\" is not a valid date.', $matches[2]));\n        }\n\n        $operator = $matches[1] ?: '==';\n        if ('since' === $operator || 'after' === $operator) {\n            $operator = '>';\n        }\n\n        if ('until' === $operator || 'before' === $operator) {\n            $operator = '<';\n        }\n\n        parent::__construct($target, $operator);\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/finder/Comparator/NumberComparator.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Finder\\Comparator;\n\n/**\n * NumberComparator compiles a simple comparison to an anonymous\n * subroutine, which you can call with a value to be tested again.\n *\n * Now this would be very pointless, if NumberCompare didn't understand\n * magnitudes.\n *\n * The target value may use magnitudes of kilobytes (k, ki),\n * megabytes (m, mi), or gigabytes (g, gi).  Those suffixed\n * with an i use the appropriate 2**n version in accordance with the\n * IEC standard: http://physics.nist.gov/cuu/Units/binary.html\n *\n * Based on the Perl Number::Compare module.\n *\n * @author    Fabien Potencier <fabien@symfony.com> PHP port\n * @author    Richard Clamp <richardc@unixbeard.net> Perl version\n * @copyright 2004-2005 Fabien Potencier <fabien@symfony.com>\n * @copyright 2002 Richard Clamp <richardc@unixbeard.net>\n *\n * @see http://physics.nist.gov/cuu/Units/binary.html\n */\nclass NumberComparator extends Comparator\n{\n    /**\n     * @param string|null $test A comparison string or null\n     *\n     * @throws \\InvalidArgumentException If the test is not understood\n     */\n    public function __construct(?string $test)\n    {\n        if (null === $test || !preg_match('#^\\s*(==|!=|[<>]=?)?\\s*([0-9\\.]+)\\s*([kmg]i?)?\\s*$#i', $test, $matches)) {\n            throw new \\InvalidArgumentException(\\sprintf('Don\\'t understand \"%s\" as a number test.', $test ?? 'null'));\n        }\n\n        $target = $matches[2];\n        if (!is_numeric($target)) {\n            throw new \\InvalidArgumentException(\\sprintf('Invalid number \"%s\".', $target));\n        }\n        if (isset($matches[3])) {\n            // magnitude\n            switch (strtolower($matches[3])) {\n                case 'k':\n                    $target *= 1000;\n                    break;\n                case 'ki':\n                    $target *= 1024;\n                    break;\n                case 'm':\n                    $target *= 1000000;\n                    break;\n                case 'mi':\n                    $target *= 1024 * 1024;\n                    break;\n                case 'g':\n                    $target *= 1000000000;\n                    break;\n                case 'gi':\n                    $target *= 1024 * 1024 * 1024;\n                    break;\n            }\n        }\n\n        parent::__construct($target, $matches[1] ?: '==');\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/finder/Exception/AccessDeniedException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Finder\\Exception;\n\n/**\n * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>\n */\nclass AccessDeniedException extends \\UnexpectedValueException\n{\n}\n"
  },
  {
    "path": "server/vendor/symfony/finder/Exception/DirectoryNotFoundException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Finder\\Exception;\n\n/**\n * @author Andreas Erhard <andreas.erhard@i-med.ac.at>\n */\nclass DirectoryNotFoundException extends \\InvalidArgumentException\n{\n}\n"
  },
  {
    "path": "server/vendor/symfony/finder/Finder.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Finder;\n\nuse Symfony\\Component\\Finder\\Comparator\\DateComparator;\nuse Symfony\\Component\\Finder\\Comparator\\NumberComparator;\nuse Symfony\\Component\\Finder\\Exception\\DirectoryNotFoundException;\nuse Symfony\\Component\\Finder\\Iterator\\CustomFilterIterator;\nuse Symfony\\Component\\Finder\\Iterator\\DateRangeFilterIterator;\nuse Symfony\\Component\\Finder\\Iterator\\DepthRangeFilterIterator;\nuse Symfony\\Component\\Finder\\Iterator\\ExcludeDirectoryFilterIterator;\nuse Symfony\\Component\\Finder\\Iterator\\FilecontentFilterIterator;\nuse Symfony\\Component\\Finder\\Iterator\\FilenameFilterIterator;\nuse Symfony\\Component\\Finder\\Iterator\\LazyIterator;\nuse Symfony\\Component\\Finder\\Iterator\\SizeRangeFilterIterator;\nuse Symfony\\Component\\Finder\\Iterator\\SortableIterator;\n\n/**\n * Finder allows to build rules to find files and directories.\n *\n * It is a thin wrapper around several specialized iterator classes.\n *\n * All rules may be invoked several times.\n *\n * All methods return the current Finder object to allow chaining:\n *\n *     $finder = Finder::create()->files()->name('*.php')->in(__DIR__);\n *\n * @author Fabien Potencier <fabien@symfony.com>\n *\n * @implements \\IteratorAggregate<string, SplFileInfo>\n */\nclass Finder implements \\IteratorAggregate, \\Countable\n{\n    public const IGNORE_VCS_FILES = 1;\n    public const IGNORE_DOT_FILES = 2;\n    public const IGNORE_VCS_IGNORED_FILES = 4;\n\n    private int $mode = 0;\n    private array $names = [];\n    private array $notNames = [];\n    private array $exclude = [];\n    private array $filters = [];\n    private array $pruneFilters = [];\n    private array $depths = [];\n    private array $sizes = [];\n    private bool $followLinks = false;\n    private bool $reverseSorting = false;\n    private \\Closure|int|false $sort = false;\n    private int $ignore = 0;\n    private array $dirs = [];\n    private array $dates = [];\n    private array $iterators = [];\n    private array $contains = [];\n    private array $notContains = [];\n    private array $paths = [];\n    private array $notPaths = [];\n    private bool $ignoreUnreadableDirs = false;\n\n    private static array $vcsPatterns = ['.svn', '_svn', 'CVS', '_darcs', '.arch-params', '.monotone', '.bzr', '.git', '.hg'];\n\n    public function __construct()\n    {\n        $this->ignore = static::IGNORE_VCS_FILES | static::IGNORE_DOT_FILES;\n    }\n\n    /**\n     * Creates a new Finder.\n     */\n    public static function create(): static\n    {\n        return new static();\n    }\n\n    /**\n     * Restricts the matching to directories only.\n     *\n     * @return $this\n     */\n    public function directories(): static\n    {\n        $this->mode = Iterator\\FileTypeFilterIterator::ONLY_DIRECTORIES;\n\n        return $this;\n    }\n\n    /**\n     * Restricts the matching to files only.\n     *\n     * @return $this\n     */\n    public function files(): static\n    {\n        $this->mode = Iterator\\FileTypeFilterIterator::ONLY_FILES;\n\n        return $this;\n    }\n\n    /**\n     * Adds tests for the directory depth.\n     *\n     * Usage:\n     *\n     *     $finder->depth('> 1') // the Finder will start matching at level 1.\n     *     $finder->depth('< 3') // the Finder will descend at most 3 levels of directories below the starting point.\n     *     $finder->depth(['>= 1', '< 3'])\n     *\n     * @param string|int|string[]|int[] $levels The depth level expression or an array of depth levels\n     *\n     * @return $this\n     *\n     * @see DepthRangeFilterIterator\n     * @see NumberComparator\n     */\n    public function depth(string|int|array $levels): static\n    {\n        foreach ((array) $levels as $level) {\n            $this->depths[] = new NumberComparator($level);\n        }\n\n        return $this;\n    }\n\n    /**\n     * Adds tests for file dates (last modified).\n     *\n     * The date must be something that strtotime() is able to parse:\n     *\n     *     $finder->date('since yesterday');\n     *     $finder->date('until 2 days ago');\n     *     $finder->date('> now - 2 hours');\n     *     $finder->date('>= 2005-10-15');\n     *     $finder->date(['>= 2005-10-15', '<= 2006-05-27']);\n     *\n     * @param string|string[] $dates A date range string or an array of date ranges\n     *\n     * @return $this\n     *\n     * @see strtotime\n     * @see DateRangeFilterIterator\n     * @see DateComparator\n     */\n    public function date(string|array $dates): static\n    {\n        foreach ((array) $dates as $date) {\n            $this->dates[] = new DateComparator($date);\n        }\n\n        return $this;\n    }\n\n    /**\n     * Adds rules that files must match.\n     *\n     * You can use patterns (delimited with / sign), globs or simple strings.\n     *\n     *     $finder->name('/\\.php$/')\n     *     $finder->name('*.php') // same as above, without dot files\n     *     $finder->name('test.php')\n     *     $finder->name(['test.py', 'test.php'])\n     *\n     * @param string|string[] $patterns A pattern (a regexp, a glob, or a string) or an array of patterns\n     *\n     * @return $this\n     *\n     * @see FilenameFilterIterator\n     */\n    public function name(string|array $patterns): static\n    {\n        $this->names = array_merge($this->names, (array) $patterns);\n\n        return $this;\n    }\n\n    /**\n     * Adds rules that files must not match.\n     *\n     * @param string|string[] $patterns A pattern (a regexp, a glob, or a string) or an array of patterns\n     *\n     * @return $this\n     *\n     * @see FilenameFilterIterator\n     */\n    public function notName(string|array $patterns): static\n    {\n        $this->notNames = array_merge($this->notNames, (array) $patterns);\n\n        return $this;\n    }\n\n    /**\n     * Adds tests that file contents must match.\n     *\n     * Strings or PCRE patterns can be used:\n     *\n     *     $finder->contains('Lorem ipsum')\n     *     $finder->contains('/Lorem ipsum/i')\n     *     $finder->contains(['dolor', '/ipsum/i'])\n     *\n     * @param string|string[] $patterns A pattern (string or regexp) or an array of patterns\n     *\n     * @return $this\n     *\n     * @see FilecontentFilterIterator\n     */\n    public function contains(string|array $patterns): static\n    {\n        $this->contains = array_merge($this->contains, (array) $patterns);\n\n        return $this;\n    }\n\n    /**\n     * Adds tests that file contents must not match.\n     *\n     * Strings or PCRE patterns can be used:\n     *\n     *     $finder->notContains('Lorem ipsum')\n     *     $finder->notContains('/Lorem ipsum/i')\n     *     $finder->notContains(['lorem', '/dolor/i'])\n     *\n     * @param string|string[] $patterns A pattern (string or regexp) or an array of patterns\n     *\n     * @return $this\n     *\n     * @see FilecontentFilterIterator\n     */\n    public function notContains(string|array $patterns): static\n    {\n        $this->notContains = array_merge($this->notContains, (array) $patterns);\n\n        return $this;\n    }\n\n    /**\n     * Adds rules that filenames must match.\n     *\n     * You can use patterns (delimited with / sign) or simple strings.\n     *\n     *     $finder->path('some/special/dir')\n     *     $finder->path('/some\\/special\\/dir/') // same as above\n     *     $finder->path(['some dir', 'another/dir'])\n     *\n     * Use only / as dirname separator.\n     *\n     * @param string|string[] $patterns A pattern (a regexp or a string) or an array of patterns\n     *\n     * @return $this\n     *\n     * @see FilenameFilterIterator\n     */\n    public function path(string|array $patterns): static\n    {\n        $this->paths = array_merge($this->paths, (array) $patterns);\n\n        return $this;\n    }\n\n    /**\n     * Adds rules that filenames must not match.\n     *\n     * You can use patterns (delimited with / sign) or simple strings.\n     *\n     *     $finder->notPath('some/special/dir')\n     *     $finder->notPath('/some\\/special\\/dir/') // same as above\n     *     $finder->notPath(['some/file.txt', 'another/file.log'])\n     *\n     * Use only / as dirname separator.\n     *\n     * @param string|string[] $patterns A pattern (a regexp or a string) or an array of patterns\n     *\n     * @return $this\n     *\n     * @see FilenameFilterIterator\n     */\n    public function notPath(string|array $patterns): static\n    {\n        $this->notPaths = array_merge($this->notPaths, (array) $patterns);\n\n        return $this;\n    }\n\n    /**\n     * Adds tests for file sizes.\n     *\n     *     $finder->size('> 10K');\n     *     $finder->size('<= 1Ki');\n     *     $finder->size(4);\n     *     $finder->size(['> 10K', '< 20K'])\n     *\n     * @param string|int|string[]|int[] $sizes A size range string or an integer or an array of size ranges\n     *\n     * @return $this\n     *\n     * @see SizeRangeFilterIterator\n     * @see NumberComparator\n     */\n    public function size(string|int|array $sizes): static\n    {\n        foreach ((array) $sizes as $size) {\n            $this->sizes[] = new NumberComparator($size);\n        }\n\n        return $this;\n    }\n\n    /**\n     * Excludes directories.\n     *\n     * Directories passed as argument must be relative to the ones defined with the `in()` method. For example:\n     *\n     *     $finder->in(__DIR__)->exclude('ruby');\n     *\n     * @param string|array $dirs A directory path or an array of directories\n     *\n     * @return $this\n     *\n     * @see ExcludeDirectoryFilterIterator\n     */\n    public function exclude(string|array $dirs): static\n    {\n        $this->exclude = array_merge($this->exclude, (array) $dirs);\n\n        return $this;\n    }\n\n    /**\n     * Excludes \"hidden\" directories and files (starting with a dot).\n     *\n     * This option is enabled by default.\n     *\n     * @return $this\n     *\n     * @see ExcludeDirectoryFilterIterator\n     */\n    public function ignoreDotFiles(bool $ignoreDotFiles): static\n    {\n        if ($ignoreDotFiles) {\n            $this->ignore |= static::IGNORE_DOT_FILES;\n        } else {\n            $this->ignore &= ~static::IGNORE_DOT_FILES;\n        }\n\n        return $this;\n    }\n\n    /**\n     * Forces the finder to ignore version control directories.\n     *\n     * This option is enabled by default.\n     *\n     * @return $this\n     *\n     * @see ExcludeDirectoryFilterIterator\n     */\n    public function ignoreVCS(bool $ignoreVCS): static\n    {\n        if ($ignoreVCS) {\n            $this->ignore |= static::IGNORE_VCS_FILES;\n        } else {\n            $this->ignore &= ~static::IGNORE_VCS_FILES;\n        }\n\n        return $this;\n    }\n\n    /**\n     * Forces Finder to obey .gitignore and ignore files based on rules listed there.\n     *\n     * This option is disabled by default.\n     *\n     * @return $this\n     */\n    public function ignoreVCSIgnored(bool $ignoreVCSIgnored): static\n    {\n        if ($ignoreVCSIgnored) {\n            $this->ignore |= static::IGNORE_VCS_IGNORED_FILES;\n        } else {\n            $this->ignore &= ~static::IGNORE_VCS_IGNORED_FILES;\n        }\n\n        return $this;\n    }\n\n    /**\n     * Adds VCS patterns.\n     *\n     * @see ignoreVCS()\n     *\n     * @param string|string[] $pattern VCS patterns to ignore\n     *\n     * @return void\n     */\n    public static function addVCSPattern(string|array $pattern)\n    {\n        foreach ((array) $pattern as $p) {\n            self::$vcsPatterns[] = $p;\n        }\n\n        self::$vcsPatterns = array_unique(self::$vcsPatterns);\n    }\n\n    /**\n     * Sorts files and directories by an anonymous function.\n     *\n     * The anonymous function receives two \\SplFileInfo instances to compare.\n     *\n     * This can be slow as all the matching files and directories must be retrieved for comparison.\n     *\n     * @return $this\n     *\n     * @see SortableIterator\n     */\n    public function sort(\\Closure $closure): static\n    {\n        $this->sort = $closure;\n\n        return $this;\n    }\n\n    /**\n     * Sorts files and directories by extension.\n     *\n     * This can be slow as all the matching files and directories must be retrieved for comparison.\n     *\n     * @return $this\n     *\n     * @see SortableIterator\n     */\n    public function sortByExtension(): static\n    {\n        $this->sort = SortableIterator::SORT_BY_EXTENSION;\n\n        return $this;\n    }\n\n    /**\n     * Sorts files and directories by name.\n     *\n     * This can be slow as all the matching files and directories must be retrieved for comparison.\n     *\n     * @return $this\n     *\n     * @see SortableIterator\n     */\n    public function sortByName(bool $useNaturalSort = false): static\n    {\n        $this->sort = $useNaturalSort ? SortableIterator::SORT_BY_NAME_NATURAL : SortableIterator::SORT_BY_NAME;\n\n        return $this;\n    }\n\n    /**\n     * Sorts files and directories by name case insensitive.\n     *\n     * This can be slow as all the matching files and directories must be retrieved for comparison.\n     *\n     * @return $this\n     *\n     * @see SortableIterator\n     */\n    public function sortByCaseInsensitiveName(bool $useNaturalSort = false): static\n    {\n        $this->sort = $useNaturalSort ? SortableIterator::SORT_BY_NAME_NATURAL_CASE_INSENSITIVE : SortableIterator::SORT_BY_NAME_CASE_INSENSITIVE;\n\n        return $this;\n    }\n\n    /**\n     * Sorts files and directories by size.\n     *\n     * This can be slow as all the matching files and directories must be retrieved for comparison.\n     *\n     * @return $this\n     *\n     * @see SortableIterator\n     */\n    public function sortBySize(): static\n    {\n        $this->sort = SortableIterator::SORT_BY_SIZE;\n\n        return $this;\n    }\n\n    /**\n     * Sorts files and directories by type (directories before files), then by name.\n     *\n     * This can be slow as all the matching files and directories must be retrieved for comparison.\n     *\n     * @return $this\n     *\n     * @see SortableIterator\n     */\n    public function sortByType(): static\n    {\n        $this->sort = SortableIterator::SORT_BY_TYPE;\n\n        return $this;\n    }\n\n    /**\n     * Sorts files and directories by the last accessed time.\n     *\n     * This is the time that the file was last accessed, read or written to.\n     *\n     * This can be slow as all the matching files and directories must be retrieved for comparison.\n     *\n     * @return $this\n     *\n     * @see SortableIterator\n     */\n    public function sortByAccessedTime(): static\n    {\n        $this->sort = SortableIterator::SORT_BY_ACCESSED_TIME;\n\n        return $this;\n    }\n\n    /**\n     * Reverses the sorting.\n     *\n     * @return $this\n     */\n    public function reverseSorting(): static\n    {\n        $this->reverseSorting = true;\n\n        return $this;\n    }\n\n    /**\n     * Sorts files and directories by the last inode changed time.\n     *\n     * This is the time that the inode information was last modified (permissions, owner, group or other metadata).\n     *\n     * On Windows, since inode is not available, changed time is actually the file creation time.\n     *\n     * This can be slow as all the matching files and directories must be retrieved for comparison.\n     *\n     * @return $this\n     *\n     * @see SortableIterator\n     */\n    public function sortByChangedTime(): static\n    {\n        $this->sort = SortableIterator::SORT_BY_CHANGED_TIME;\n\n        return $this;\n    }\n\n    /**\n     * Sorts files and directories by the last modified time.\n     *\n     * This is the last time the actual contents of the file were last modified.\n     *\n     * This can be slow as all the matching files and directories must be retrieved for comparison.\n     *\n     * @return $this\n     *\n     * @see SortableIterator\n     */\n    public function sortByModifiedTime(): static\n    {\n        $this->sort = SortableIterator::SORT_BY_MODIFIED_TIME;\n\n        return $this;\n    }\n\n    /**\n     * Filters the iterator with an anonymous function.\n     *\n     * The anonymous function receives a \\SplFileInfo and must return false\n     * to remove files.\n     *\n     * @param \\Closure(SplFileInfo): bool $closure\n     * @param bool                        $prune   Whether to skip traversing directories further\n     *\n     * @return $this\n     *\n     * @see CustomFilterIterator\n     */\n    public function filter(\\Closure $closure /* , bool $prune = false */): static\n    {\n        $prune = 1 < \\func_num_args() ? func_get_arg(1) : false;\n        $this->filters[] = $closure;\n\n        if ($prune) {\n            $this->pruneFilters[] = $closure;\n        }\n\n        return $this;\n    }\n\n    /**\n     * Forces the following of symlinks.\n     *\n     * @return $this\n     */\n    public function followLinks(): static\n    {\n        $this->followLinks = true;\n\n        return $this;\n    }\n\n    /**\n     * Tells finder to ignore unreadable directories.\n     *\n     * By default, scanning unreadable directories content throws an AccessDeniedException.\n     *\n     * @return $this\n     */\n    public function ignoreUnreadableDirs(bool $ignore = true): static\n    {\n        $this->ignoreUnreadableDirs = $ignore;\n\n        return $this;\n    }\n\n    /**\n     * Searches files and directories which match defined rules.\n     *\n     * @param string|string[] $dirs A directory path or an array of directories\n     *\n     * @return $this\n     *\n     * @throws DirectoryNotFoundException if one of the directories does not exist\n     */\n    public function in(string|array $dirs): static\n    {\n        $resolvedDirs = [];\n\n        foreach ((array) $dirs as $dir) {\n            if (is_dir($dir)) {\n                $resolvedDirs[] = [$this->normalizeDir($dir)];\n            } elseif ($glob = glob($dir, (\\defined('GLOB_BRACE') ? \\GLOB_BRACE : 0) | \\GLOB_ONLYDIR | \\GLOB_NOSORT)) {\n                sort($glob);\n                $resolvedDirs[] = array_map($this->normalizeDir(...), $glob);\n            } else {\n                throw new DirectoryNotFoundException(\\sprintf('The \"%s\" directory does not exist.', $dir));\n            }\n        }\n\n        $this->dirs = array_merge($this->dirs, ...$resolvedDirs);\n\n        return $this;\n    }\n\n    /**\n     * Returns an Iterator for the current Finder configuration.\n     *\n     * This method implements the IteratorAggregate interface.\n     *\n     * @return \\Iterator<string, SplFileInfo>\n     *\n     * @throws \\LogicException if the in() method has not been called\n     */\n    public function getIterator(): \\Iterator\n    {\n        if (0 === \\count($this->dirs) && 0 === \\count($this->iterators)) {\n            throw new \\LogicException('You must call one of in() or append() methods before iterating over a Finder.');\n        }\n\n        if (1 === \\count($this->dirs) && 0 === \\count($this->iterators)) {\n            $iterator = $this->searchInDirectory($this->dirs[0]);\n\n            if ($this->sort || $this->reverseSorting) {\n                $iterator = (new SortableIterator($iterator, $this->sort, $this->reverseSorting))->getIterator();\n            }\n\n            return $iterator;\n        }\n\n        $iterator = new \\AppendIterator();\n        foreach ($this->dirs as $dir) {\n            $iterator->append(new \\IteratorIterator(new LazyIterator(fn () => $this->searchInDirectory($dir))));\n        }\n\n        foreach ($this->iterators as $it) {\n            $iterator->append($it);\n        }\n\n        if ($this->sort || $this->reverseSorting) {\n            $iterator = (new SortableIterator($iterator, $this->sort, $this->reverseSorting))->getIterator();\n        }\n\n        return $iterator;\n    }\n\n    /**\n     * Appends an existing set of files/directories to the finder.\n     *\n     * The set can be another Finder, an Iterator, an IteratorAggregate, or even a plain array.\n     *\n     * @return $this\n     *\n     * @throws \\InvalidArgumentException when the given argument is not iterable\n     */\n    public function append(iterable $iterator): static\n    {\n        if ($iterator instanceof \\IteratorAggregate) {\n            $this->iterators[] = $iterator->getIterator();\n        } elseif ($iterator instanceof \\Iterator) {\n            $this->iterators[] = $iterator;\n        } elseif (is_iterable($iterator)) {\n            $it = new \\ArrayIterator();\n            foreach ($iterator as $file) {\n                $file = $file instanceof \\SplFileInfo ? $file : new \\SplFileInfo($file);\n                $it[$file->getPathname()] = $file;\n            }\n            $this->iterators[] = $it;\n        } else {\n            throw new \\InvalidArgumentException('Finder::append() method wrong argument type.');\n        }\n\n        return $this;\n    }\n\n    /**\n     * Check if any results were found.\n     */\n    public function hasResults(): bool\n    {\n        foreach ($this->getIterator() as $_) {\n            return true;\n        }\n\n        return false;\n    }\n\n    /**\n     * Counts all the results collected by the iterators.\n     */\n    public function count(): int\n    {\n        return iterator_count($this->getIterator());\n    }\n\n    private function searchInDirectory(string $dir): \\Iterator\n    {\n        $exclude = $this->exclude;\n        $notPaths = $this->notPaths;\n\n        if ($this->pruneFilters) {\n            $exclude = array_merge($exclude, $this->pruneFilters);\n        }\n\n        if (static::IGNORE_VCS_FILES === (static::IGNORE_VCS_FILES & $this->ignore)) {\n            $exclude = array_merge($exclude, self::$vcsPatterns);\n        }\n\n        if (static::IGNORE_DOT_FILES === (static::IGNORE_DOT_FILES & $this->ignore)) {\n            $notPaths[] = '#(^|/)\\..+(/|$)#';\n        }\n\n        $minDepth = 0;\n        $maxDepth = \\PHP_INT_MAX;\n\n        foreach ($this->depths as $comparator) {\n            switch ($comparator->getOperator()) {\n                case '>':\n                    $minDepth = $comparator->getTarget() + 1;\n                    break;\n                case '>=':\n                    $minDepth = $comparator->getTarget();\n                    break;\n                case '<':\n                    $maxDepth = $comparator->getTarget() - 1;\n                    break;\n                case '<=':\n                    $maxDepth = $comparator->getTarget();\n                    break;\n                default:\n                    $minDepth = $maxDepth = $comparator->getTarget();\n            }\n        }\n\n        $flags = \\RecursiveDirectoryIterator::SKIP_DOTS;\n\n        if ($this->followLinks) {\n            $flags |= \\RecursiveDirectoryIterator::FOLLOW_SYMLINKS;\n        }\n\n        $iterator = new Iterator\\RecursiveDirectoryIterator($dir, $flags, $this->ignoreUnreadableDirs);\n\n        if ($exclude) {\n            $iterator = new ExcludeDirectoryFilterIterator($iterator, $exclude);\n        }\n\n        $iterator = new \\RecursiveIteratorIterator($iterator, \\RecursiveIteratorIterator::SELF_FIRST);\n\n        if ($minDepth > 0 || $maxDepth < \\PHP_INT_MAX) {\n            $iterator = new DepthRangeFilterIterator($iterator, $minDepth, $maxDepth);\n        }\n\n        if ($this->mode) {\n            $iterator = new Iterator\\FileTypeFilterIterator($iterator, $this->mode);\n        }\n\n        if ($this->names || $this->notNames) {\n            $iterator = new FilenameFilterIterator($iterator, $this->names, $this->notNames);\n        }\n\n        if ($this->contains || $this->notContains) {\n            $iterator = new FilecontentFilterIterator($iterator, $this->contains, $this->notContains);\n        }\n\n        if ($this->sizes) {\n            $iterator = new SizeRangeFilterIterator($iterator, $this->sizes);\n        }\n\n        if ($this->dates) {\n            $iterator = new DateRangeFilterIterator($iterator, $this->dates);\n        }\n\n        if ($this->filters) {\n            $iterator = new CustomFilterIterator($iterator, $this->filters);\n        }\n\n        if ($this->paths || $notPaths) {\n            $iterator = new Iterator\\PathFilterIterator($iterator, $this->paths, $notPaths);\n        }\n\n        if (static::IGNORE_VCS_IGNORED_FILES === (static::IGNORE_VCS_IGNORED_FILES & $this->ignore)) {\n            $iterator = new Iterator\\VcsIgnoredFilterIterator($iterator, $dir);\n        }\n\n        return $iterator;\n    }\n\n    /**\n     * Normalizes given directory names by removing trailing slashes.\n     *\n     * Excluding: (s)ftp:// or ssh2.(s)ftp:// wrapper\n     */\n    private function normalizeDir(string $dir): string\n    {\n        if ('/' === $dir) {\n            return $dir;\n        }\n\n        $dir = rtrim($dir, '/'.\\DIRECTORY_SEPARATOR);\n\n        if (preg_match('#^(ssh2\\.)?s?ftp://#', $dir)) {\n            $dir .= '/';\n        }\n\n        return $dir;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/finder/Gitignore.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Finder;\n\n/**\n * Gitignore matches against text.\n *\n * @author Michael Voříšek <vorismi3@fel.cvut.cz>\n * @author Ahmed Abdou <mail@ahmd.io>\n */\nclass Gitignore\n{\n    /**\n     * Returns a regexp which is the equivalent of the gitignore pattern.\n     *\n     * Format specification: https://git-scm.com/docs/gitignore#_pattern_format\n     */\n    public static function toRegex(string $gitignoreFileContent): string\n    {\n        return self::buildRegex($gitignoreFileContent, false);\n    }\n\n    public static function toRegexMatchingNegatedPatterns(string $gitignoreFileContent): string\n    {\n        return self::buildRegex($gitignoreFileContent, true);\n    }\n\n    private static function buildRegex(string $gitignoreFileContent, bool $inverted): string\n    {\n        $gitignoreFileContent = preg_replace('~(?<!\\\\\\\\)#[^\\n\\r]*~', '', $gitignoreFileContent);\n        $gitignoreLines = preg_split('~\\r\\n?|\\n~', $gitignoreFileContent);\n\n        $res = self::lineToRegex('');\n        foreach ($gitignoreLines as $line) {\n            $line = preg_replace('~(?<!\\\\\\\\)[ \\t]+$~', '', $line);\n\n            if (str_starts_with($line, '!')) {\n                $line = substr($line, 1);\n                $isNegative = true;\n            } else {\n                $isNegative = false;\n            }\n\n            if ('' !== $line) {\n                if ($isNegative xor $inverted) {\n                    $res = '(?!'.self::lineToRegex($line).'$)'.$res;\n                } else {\n                    $res = '(?:'.$res.'|'.self::lineToRegex($line).')';\n                }\n            }\n        }\n\n        return '~^(?:'.$res.')~s';\n    }\n\n    private static function lineToRegex(string $gitignoreLine): string\n    {\n        if ('' === $gitignoreLine) {\n            return '$f'; // always false\n        }\n\n        $slashPos = strpos($gitignoreLine, '/');\n        if (false !== $slashPos && \\strlen($gitignoreLine) - 1 !== $slashPos) {\n            if (0 === $slashPos) {\n                $gitignoreLine = substr($gitignoreLine, 1);\n            }\n            $isAbsolute = true;\n        } else {\n            $isAbsolute = false;\n        }\n\n        $regex = preg_quote(str_replace('\\\\', '', $gitignoreLine), '~');\n        $regex = preg_replace_callback('~\\\\\\\\\\[((?:\\\\\\\\!)?)([^\\[\\]]*)\\\\\\\\\\]~', fn (array $matches): string => '['.('' !== $matches[1] ? '^' : '').str_replace('\\\\-', '-', $matches[2]).']', $regex);\n        $regex = preg_replace('~(?:(?:\\\\\\\\\\*){2,}(/?))+~', '(?:(?:(?!//).(?<!//))+$1)?', $regex);\n        $regex = preg_replace('~\\\\\\\\\\*~', '[^/]*', $regex);\n        $regex = preg_replace('~\\\\\\\\\\?~', '[^/]', $regex);\n\n        return ($isAbsolute ? '' : '(?:[^/]+/)*')\n            .$regex\n            .(!str_ends_with($gitignoreLine, '/') ? '(?:$|/)' : '');\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/finder/Glob.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Finder;\n\n/**\n * Glob matches globbing patterns against text.\n *\n *     if match_glob(\"foo.*\", \"foo.bar\") echo \"matched\\n\";\n *\n *     // prints foo.bar and foo.baz\n *     $regex = glob_to_regex(\"foo.*\");\n *     for (['foo.bar', 'foo.baz', 'foo', 'bar'] as $t)\n *     {\n *         if (/$regex/) echo \"matched: $car\\n\";\n *     }\n *\n * Glob implements glob(3) style matching that can be used to match\n * against text, rather than fetching names from a filesystem.\n *\n * Based on the Perl Text::Glob module.\n *\n * @author Fabien Potencier <fabien@symfony.com> PHP port\n * @author     Richard Clamp <richardc@unixbeard.net> Perl version\n * @copyright  2004-2005 Fabien Potencier <fabien@symfony.com>\n * @copyright  2002 Richard Clamp <richardc@unixbeard.net>\n */\nclass Glob\n{\n    /**\n     * Returns a regexp which is the equivalent of the glob pattern.\n     */\n    public static function toRegex(string $glob, bool $strictLeadingDot = true, bool $strictWildcardSlash = true, string $delimiter = '#'): string\n    {\n        $firstByte = true;\n        $escaping = false;\n        $inCurlies = 0;\n        $regex = '';\n        $sizeGlob = \\strlen($glob);\n        for ($i = 0; $i < $sizeGlob; ++$i) {\n            $car = $glob[$i];\n            if ($firstByte && $strictLeadingDot && '.' !== $car) {\n                $regex .= '(?=[^\\.])';\n            }\n\n            $firstByte = '/' === $car;\n\n            if ($firstByte && $strictWildcardSlash && isset($glob[$i + 2]) && '**' === $glob[$i + 1].$glob[$i + 2] && (!isset($glob[$i + 3]) || '/' === $glob[$i + 3])) {\n                $car = '[^/]++/';\n                if (!isset($glob[$i + 3])) {\n                    $car .= '?';\n                }\n\n                if ($strictLeadingDot) {\n                    $car = '(?=[^\\.])'.$car;\n                }\n\n                $car = '/(?:'.$car.')*';\n                $i += 2 + isset($glob[$i + 3]);\n\n                if ('/' === $delimiter) {\n                    $car = str_replace('/', '\\\\/', $car);\n                }\n            }\n\n            if ($delimiter === $car || '.' === $car || '(' === $car || ')' === $car || '|' === $car || '+' === $car || '^' === $car || '$' === $car) {\n                $regex .= \"\\\\$car\";\n            } elseif ('*' === $car) {\n                $regex .= $escaping ? '\\\\*' : ($strictWildcardSlash ? '[^/]*' : '.*');\n            } elseif ('?' === $car) {\n                $regex .= $escaping ? '\\\\?' : ($strictWildcardSlash ? '[^/]' : '.');\n            } elseif ('{' === $car) {\n                $regex .= $escaping ? '\\\\{' : '(';\n                if (!$escaping) {\n                    ++$inCurlies;\n                }\n            } elseif ('}' === $car && $inCurlies) {\n                $regex .= $escaping ? '}' : ')';\n                if (!$escaping) {\n                    --$inCurlies;\n                }\n            } elseif (',' === $car && $inCurlies) {\n                $regex .= $escaping ? ',' : '|';\n            } elseif ('\\\\' === $car) {\n                if ($escaping) {\n                    $regex .= '\\\\\\\\';\n                    $escaping = false;\n                } else {\n                    $escaping = true;\n                }\n\n                continue;\n            } else {\n                $regex .= $car;\n            }\n            $escaping = false;\n        }\n\n        return $delimiter.'^'.$regex.'$'.$delimiter;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/finder/Iterator/CustomFilterIterator.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Finder\\Iterator;\n\n/**\n * CustomFilterIterator filters files by applying anonymous functions.\n *\n * The anonymous function receives a \\SplFileInfo and must return false\n * to remove files.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n *\n * @extends \\FilterIterator<string, \\SplFileInfo>\n */\nclass CustomFilterIterator extends \\FilterIterator\n{\n    private array $filters = [];\n\n    /**\n     * @param \\Iterator<string, \\SplFileInfo> $iterator The Iterator to filter\n     * @param callable[]                      $filters  An array of PHP callbacks\n     *\n     * @throws \\InvalidArgumentException\n     */\n    public function __construct(\\Iterator $iterator, array $filters)\n    {\n        foreach ($filters as $filter) {\n            if (!\\is_callable($filter)) {\n                throw new \\InvalidArgumentException('Invalid PHP callback.');\n            }\n        }\n        $this->filters = $filters;\n\n        parent::__construct($iterator);\n    }\n\n    /**\n     * Filters the iterator values.\n     */\n    public function accept(): bool\n    {\n        $fileinfo = $this->current();\n\n        foreach ($this->filters as $filter) {\n            if (false === $filter($fileinfo)) {\n                return false;\n            }\n        }\n\n        return true;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/finder/Iterator/DateRangeFilterIterator.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Finder\\Iterator;\n\nuse Symfony\\Component\\Finder\\Comparator\\DateComparator;\n\n/**\n * DateRangeFilterIterator filters out files that are not in the given date range (last modified dates).\n *\n * @author Fabien Potencier <fabien@symfony.com>\n *\n * @extends \\FilterIterator<string, \\SplFileInfo>\n */\nclass DateRangeFilterIterator extends \\FilterIterator\n{\n    private array $comparators = [];\n\n    /**\n     * @param \\Iterator<string, \\SplFileInfo> $iterator\n     * @param DateComparator[]                $comparators\n     */\n    public function __construct(\\Iterator $iterator, array $comparators)\n    {\n        $this->comparators = $comparators;\n\n        parent::__construct($iterator);\n    }\n\n    /**\n     * Filters the iterator values.\n     */\n    public function accept(): bool\n    {\n        $fileinfo = $this->current();\n\n        if (!file_exists($fileinfo->getPathname())) {\n            return false;\n        }\n\n        $filedate = $fileinfo->getMTime();\n        foreach ($this->comparators as $compare) {\n            if (!$compare->test($filedate)) {\n                return false;\n            }\n        }\n\n        return true;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/finder/Iterator/DepthRangeFilterIterator.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Finder\\Iterator;\n\n/**\n * DepthRangeFilterIterator limits the directory depth.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n *\n * @template-covariant TKey\n * @template-covariant TValue\n *\n * @extends \\FilterIterator<TKey, TValue>\n */\nclass DepthRangeFilterIterator extends \\FilterIterator\n{\n    private int $minDepth = 0;\n\n    /**\n     * @param \\RecursiveIteratorIterator<\\RecursiveIterator<TKey, TValue>> $iterator The Iterator to filter\n     * @param int                                                          $minDepth The min depth\n     * @param int                                                          $maxDepth The max depth\n     */\n    public function __construct(\\RecursiveIteratorIterator $iterator, int $minDepth = 0, int $maxDepth = \\PHP_INT_MAX)\n    {\n        $this->minDepth = $minDepth;\n        $iterator->setMaxDepth(\\PHP_INT_MAX === $maxDepth ? -1 : $maxDepth);\n\n        parent::__construct($iterator);\n    }\n\n    /**\n     * Filters the iterator values.\n     */\n    public function accept(): bool\n    {\n        return $this->getInnerIterator()->getDepth() >= $this->minDepth;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/finder/Iterator/ExcludeDirectoryFilterIterator.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Finder\\Iterator;\n\nuse Symfony\\Component\\Finder\\SplFileInfo;\n\n/**\n * ExcludeDirectoryFilterIterator filters out directories.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n *\n * @extends \\FilterIterator<string, SplFileInfo>\n *\n * @implements \\RecursiveIterator<string, SplFileInfo>\n */\nclass ExcludeDirectoryFilterIterator extends \\FilterIterator implements \\RecursiveIterator\n{\n    /** @var \\Iterator<string, SplFileInfo> */\n    private \\Iterator $iterator;\n    private bool $isRecursive;\n    /** @var array<string, true> */\n    private array $excludedDirs = [];\n    private ?string $excludedPattern = null;\n    /** @var list<callable(SplFileInfo):bool> */\n    private array $pruneFilters = [];\n\n    /**\n     * @param \\Iterator<string, SplFileInfo>          $iterator    The Iterator to filter\n     * @param list<string|callable(SplFileInfo):bool> $directories An array of directories to exclude\n     */\n    public function __construct(\\Iterator $iterator, array $directories)\n    {\n        $this->iterator = $iterator;\n        $this->isRecursive = $iterator instanceof \\RecursiveIterator;\n        $patterns = [];\n        foreach ($directories as $directory) {\n            if (!\\is_string($directory)) {\n                if (!\\is_callable($directory)) {\n                    throw new \\InvalidArgumentException('Invalid PHP callback.');\n                }\n\n                $this->pruneFilters[] = $directory;\n\n                continue;\n            }\n\n            $directory = rtrim($directory, '/');\n            if (!$this->isRecursive || str_contains($directory, '/')) {\n                $patterns[] = preg_quote($directory, '#');\n            } else {\n                $this->excludedDirs[$directory] = true;\n            }\n        }\n        if ($patterns) {\n            $this->excludedPattern = '#(?:^|/)(?:'.implode('|', $patterns).')(?:/|$)#';\n        }\n\n        parent::__construct($iterator);\n    }\n\n    /**\n     * Filters the iterator values.\n     */\n    public function accept(): bool\n    {\n        if ($this->isRecursive && isset($this->excludedDirs[$this->getFilename()]) && $this->isDir()) {\n            return false;\n        }\n\n        if ($this->excludedPattern) {\n            $path = $this->isDir() ? $this->current()->getRelativePathname() : $this->current()->getRelativePath();\n            $path = str_replace('\\\\', '/', $path);\n\n            return !preg_match($this->excludedPattern, $path);\n        }\n\n        if ($this->pruneFilters && $this->hasChildren()) {\n            foreach ($this->pruneFilters as $pruneFilter) {\n                if (!$pruneFilter($this->current())) {\n                    return false;\n                }\n            }\n        }\n\n        return true;\n    }\n\n    public function hasChildren(): bool\n    {\n        return $this->isRecursive && $this->iterator->hasChildren();\n    }\n\n    public function getChildren(): self\n    {\n        $children = new self($this->iterator->getChildren(), []);\n        $children->excludedDirs = $this->excludedDirs;\n        $children->excludedPattern = $this->excludedPattern;\n\n        return $children;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/finder/Iterator/FileTypeFilterIterator.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Finder\\Iterator;\n\n/**\n * FileTypeFilterIterator only keeps files, directories, or both.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n *\n * @extends \\FilterIterator<string, \\SplFileInfo>\n */\nclass FileTypeFilterIterator extends \\FilterIterator\n{\n    public const ONLY_FILES = 1;\n    public const ONLY_DIRECTORIES = 2;\n\n    private int $mode;\n\n    /**\n     * @param \\Iterator<string, \\SplFileInfo> $iterator The Iterator to filter\n     * @param int                             $mode     The mode (self::ONLY_FILES or self::ONLY_DIRECTORIES)\n     */\n    public function __construct(\\Iterator $iterator, int $mode)\n    {\n        $this->mode = $mode;\n\n        parent::__construct($iterator);\n    }\n\n    /**\n     * Filters the iterator values.\n     */\n    public function accept(): bool\n    {\n        $fileinfo = $this->current();\n        if (self::ONLY_DIRECTORIES === (self::ONLY_DIRECTORIES & $this->mode) && $fileinfo->isFile()) {\n            return false;\n        } elseif (self::ONLY_FILES === (self::ONLY_FILES & $this->mode) && $fileinfo->isDir()) {\n            return false;\n        }\n\n        return true;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/finder/Iterator/FilecontentFilterIterator.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Finder\\Iterator;\n\nuse Symfony\\Component\\Finder\\SplFileInfo;\n\n/**\n * FilecontentFilterIterator filters files by their contents using patterns (regexps or strings).\n *\n * @author Fabien Potencier  <fabien@symfony.com>\n * @author Włodzimierz Gajda <gajdaw@gajdaw.pl>\n *\n * @extends MultiplePcreFilterIterator<string, SplFileInfo>\n */\nclass FilecontentFilterIterator extends MultiplePcreFilterIterator\n{\n    /**\n     * Filters the iterator values.\n     */\n    public function accept(): bool\n    {\n        if (!$this->matchRegexps && !$this->noMatchRegexps) {\n            return true;\n        }\n\n        $fileinfo = $this->current();\n\n        if ($fileinfo->isDir() || !$fileinfo->isReadable()) {\n            return false;\n        }\n\n        $content = $fileinfo->getContents();\n        if (!$content) {\n            return false;\n        }\n\n        return $this->isAccepted($content);\n    }\n\n    /**\n     * Converts string to regexp if necessary.\n     *\n     * @param string $str Pattern: string or regexp\n     */\n    protected function toRegex(string $str): string\n    {\n        return $this->isRegex($str) ? $str : '/'.preg_quote($str, '/').'/';\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/finder/Iterator/FilenameFilterIterator.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Finder\\Iterator;\n\nuse Symfony\\Component\\Finder\\Glob;\n\n/**\n * FilenameFilterIterator filters files by patterns (a regexp, a glob, or a string).\n *\n * @author Fabien Potencier <fabien@symfony.com>\n *\n * @extends MultiplePcreFilterIterator<string, \\SplFileInfo>\n */\nclass FilenameFilterIterator extends MultiplePcreFilterIterator\n{\n    /**\n     * Filters the iterator values.\n     */\n    public function accept(): bool\n    {\n        return $this->isAccepted($this->current()->getFilename());\n    }\n\n    /**\n     * Converts glob to regexp.\n     *\n     * PCRE patterns are left unchanged.\n     * Glob strings are transformed with Glob::toRegex().\n     *\n     * @param string $str Pattern: glob or regexp\n     */\n    protected function toRegex(string $str): string\n    {\n        return $this->isRegex($str) ? $str : Glob::toRegex($str);\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/finder/Iterator/LazyIterator.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Finder\\Iterator;\n\n/**\n * @author Jérémy Derussé <jeremy@derusse.com>\n *\n * @internal\n */\nclass LazyIterator implements \\IteratorAggregate\n{\n    private \\Closure $iteratorFactory;\n\n    public function __construct(callable $iteratorFactory)\n    {\n        $this->iteratorFactory = $iteratorFactory(...);\n    }\n\n    public function getIterator(): \\Traversable\n    {\n        yield from ($this->iteratorFactory)();\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/finder/Iterator/MultiplePcreFilterIterator.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Finder\\Iterator;\n\n/**\n * MultiplePcreFilterIterator filters files using patterns (regexps, globs or strings).\n *\n * @author Fabien Potencier <fabien@symfony.com>\n *\n * @template-covariant TKey\n * @template-covariant TValue\n *\n * @extends \\FilterIterator<TKey, TValue>\n */\nabstract class MultiplePcreFilterIterator extends \\FilterIterator\n{\n    protected $matchRegexps = [];\n    protected $noMatchRegexps = [];\n\n    /**\n     * @param \\Iterator<TKey, TValue> $iterator        The Iterator to filter\n     * @param string[]                $matchPatterns   An array of patterns that need to match\n     * @param string[]                $noMatchPatterns An array of patterns that need to not match\n     */\n    public function __construct(\\Iterator $iterator, array $matchPatterns, array $noMatchPatterns)\n    {\n        foreach ($matchPatterns as $pattern) {\n            $this->matchRegexps[] = $this->toRegex($pattern);\n        }\n\n        foreach ($noMatchPatterns as $pattern) {\n            $this->noMatchRegexps[] = $this->toRegex($pattern);\n        }\n\n        parent::__construct($iterator);\n    }\n\n    /**\n     * Checks whether the string is accepted by the regex filters.\n     *\n     * If there is no regexps defined in the class, this method will accept the string.\n     * Such case can be handled by child classes before calling the method if they want to\n     * apply a different behavior.\n     */\n    protected function isAccepted(string $string): bool\n    {\n        // should at least not match one rule to exclude\n        foreach ($this->noMatchRegexps as $regex) {\n            if (preg_match($regex, $string)) {\n                return false;\n            }\n        }\n\n        // should at least match one rule\n        if ($this->matchRegexps) {\n            foreach ($this->matchRegexps as $regex) {\n                if (preg_match($regex, $string)) {\n                    return true;\n                }\n            }\n\n            return false;\n        }\n\n        // If there is no match rules, the file is accepted\n        return true;\n    }\n\n    /**\n     * Checks whether the string is a regex.\n     */\n    protected function isRegex(string $str): bool\n    {\n        $availableModifiers = 'imsxuADU';\n\n        if (\\PHP_VERSION_ID >= 80200) {\n            $availableModifiers .= 'n';\n        }\n\n        if (preg_match('/^(.{3,}?)['.$availableModifiers.']*$/', $str, $m)) {\n            $start = substr($m[1], 0, 1);\n            $end = substr($m[1], -1);\n\n            if ($start === $end) {\n                return !preg_match('/[*?[:alnum:] \\\\\\\\]/', $start);\n            }\n\n            foreach ([['{', '}'], ['(', ')'], ['[', ']'], ['<', '>']] as $delimiters) {\n                if ($start === $delimiters[0] && $end === $delimiters[1]) {\n                    return true;\n                }\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * Converts string into regexp.\n     */\n    abstract protected function toRegex(string $str): string;\n}\n"
  },
  {
    "path": "server/vendor/symfony/finder/Iterator/PathFilterIterator.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Finder\\Iterator;\n\nuse Symfony\\Component\\Finder\\SplFileInfo;\n\n/**\n * PathFilterIterator filters files by path patterns (e.g. some/special/dir).\n *\n * @author Fabien Potencier  <fabien@symfony.com>\n * @author Włodzimierz Gajda <gajdaw@gajdaw.pl>\n *\n * @extends MultiplePcreFilterIterator<string, SplFileInfo>\n */\nclass PathFilterIterator extends MultiplePcreFilterIterator\n{\n    /**\n     * Filters the iterator values.\n     */\n    public function accept(): bool\n    {\n        $filename = $this->current()->getRelativePathname();\n\n        if ('\\\\' === \\DIRECTORY_SEPARATOR) {\n            $filename = str_replace('\\\\', '/', $filename);\n        }\n\n        return $this->isAccepted($filename);\n    }\n\n    /**\n     * Converts strings to regexp.\n     *\n     * PCRE patterns are left unchanged.\n     *\n     * Default conversion:\n     *     'lorem/ipsum/dolor' ==>  'lorem\\/ipsum\\/dolor/'\n     *\n     * Use only / as directory separator (on Windows also).\n     *\n     * @param string $str Pattern: regexp or dirname\n     */\n    protected function toRegex(string $str): string\n    {\n        return $this->isRegex($str) ? $str : '/'.preg_quote($str, '/').'/';\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/finder/Iterator/RecursiveDirectoryIterator.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Finder\\Iterator;\n\nuse Symfony\\Component\\Finder\\Exception\\AccessDeniedException;\nuse Symfony\\Component\\Finder\\SplFileInfo;\n\n/**\n * Extends the \\RecursiveDirectoryIterator to support relative paths.\n *\n * @author Victor Berchet <victor@suumit.com>\n *\n * @extends \\RecursiveDirectoryIterator<string, SplFileInfo>\n */\nclass RecursiveDirectoryIterator extends \\RecursiveDirectoryIterator\n{\n    private bool $ignoreUnreadableDirs;\n    private bool $ignoreFirstRewind = true;\n\n    // these 3 properties take part of the performance optimization to avoid redoing the same work in all iterations\n    private string $rootPath;\n    private string $subPath;\n    private string $directorySeparator = '/';\n\n    /**\n     * @throws \\RuntimeException\n     */\n    public function __construct(string $path, int $flags, bool $ignoreUnreadableDirs = false)\n    {\n        if ($flags & (self::CURRENT_AS_PATHNAME | self::CURRENT_AS_SELF)) {\n            throw new \\RuntimeException('This iterator only support returning current as fileinfo.');\n        }\n\n        parent::__construct($path, $flags);\n        $this->ignoreUnreadableDirs = $ignoreUnreadableDirs;\n        $this->rootPath = $path;\n        if ('/' !== \\DIRECTORY_SEPARATOR && !($flags & self::UNIX_PATHS)) {\n            $this->directorySeparator = \\DIRECTORY_SEPARATOR;\n        }\n    }\n\n    /**\n     * Return an instance of SplFileInfo with support for relative paths.\n     */\n    public function current(): SplFileInfo\n    {\n        // the logic here avoids redoing the same work in all iterations\n\n        if (!isset($this->subPath)) {\n            $this->subPath = $this->getSubPath();\n        }\n        $subPathname = $this->subPath;\n        if ('' !== $subPathname) {\n            $subPathname .= $this->directorySeparator;\n        }\n        $subPathname .= $this->getFilename();\n        $basePath = $this->rootPath;\n\n        if ('/' !== $basePath && !str_ends_with($basePath, $this->directorySeparator) && !str_ends_with($basePath, '/')) {\n            $basePath .= $this->directorySeparator;\n        }\n\n        return new SplFileInfo($basePath.$subPathname, $this->subPath, $subPathname);\n    }\n\n    public function hasChildren(bool $allowLinks = false): bool\n    {\n        $hasChildren = parent::hasChildren($allowLinks);\n\n        if (!$hasChildren || !$this->ignoreUnreadableDirs) {\n            return $hasChildren;\n        }\n\n        try {\n            parent::getChildren();\n\n            return true;\n        } catch (\\UnexpectedValueException) {\n            // If directory is unreadable and finder is set to ignore it, skip children\n            return false;\n        }\n    }\n\n    /**\n     * @throws AccessDeniedException\n     */\n    public function getChildren(): \\RecursiveDirectoryIterator\n    {\n        try {\n            $children = parent::getChildren();\n\n            if ($children instanceof self) {\n                // parent method will call the constructor with default arguments, so unreadable dirs won't be ignored anymore\n                $children->ignoreUnreadableDirs = $this->ignoreUnreadableDirs;\n\n                // performance optimization to avoid redoing the same work in all children\n                $children->rootPath = $this->rootPath;\n            }\n\n            return $children;\n        } catch (\\UnexpectedValueException $e) {\n            throw new AccessDeniedException($e->getMessage(), $e->getCode(), $e);\n        }\n    }\n\n    public function next(): void\n    {\n        $this->ignoreFirstRewind = false;\n\n        parent::next();\n    }\n\n    public function rewind(): void\n    {\n        // some streams like FTP are not rewindable, ignore the first rewind after creation,\n        // as newly created DirectoryIterator does not need to be rewound\n        if ($this->ignoreFirstRewind) {\n            $this->ignoreFirstRewind = false;\n\n            return;\n        }\n\n        parent::rewind();\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/finder/Iterator/SizeRangeFilterIterator.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Finder\\Iterator;\n\nuse Symfony\\Component\\Finder\\Comparator\\NumberComparator;\n\n/**\n * SizeRangeFilterIterator filters out files that are not in the given size range.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n *\n * @extends \\FilterIterator<string, \\SplFileInfo>\n */\nclass SizeRangeFilterIterator extends \\FilterIterator\n{\n    private array $comparators = [];\n\n    /**\n     * @param \\Iterator<string, \\SplFileInfo> $iterator\n     * @param NumberComparator[]              $comparators\n     */\n    public function __construct(\\Iterator $iterator, array $comparators)\n    {\n        $this->comparators = $comparators;\n\n        parent::__construct($iterator);\n    }\n\n    /**\n     * Filters the iterator values.\n     */\n    public function accept(): bool\n    {\n        $fileinfo = $this->current();\n        if (!$fileinfo->isFile()) {\n            return true;\n        }\n\n        $filesize = $fileinfo->getSize();\n        foreach ($this->comparators as $compare) {\n            if (!$compare->test($filesize)) {\n                return false;\n            }\n        }\n\n        return true;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/finder/Iterator/SortableIterator.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Finder\\Iterator;\n\n/**\n * SortableIterator applies a sort on a given Iterator.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n *\n * @implements \\IteratorAggregate<string, \\SplFileInfo>\n */\nclass SortableIterator implements \\IteratorAggregate\n{\n    public const SORT_BY_NONE = 0;\n    public const SORT_BY_NAME = 1;\n    public const SORT_BY_TYPE = 2;\n    public const SORT_BY_ACCESSED_TIME = 3;\n    public const SORT_BY_CHANGED_TIME = 4;\n    public const SORT_BY_MODIFIED_TIME = 5;\n    public const SORT_BY_NAME_NATURAL = 6;\n    public const SORT_BY_NAME_CASE_INSENSITIVE = 7;\n    public const SORT_BY_NAME_NATURAL_CASE_INSENSITIVE = 8;\n    public const SORT_BY_EXTENSION = 9;\n    public const SORT_BY_SIZE = 10;\n\n    /** @var \\Traversable<string, \\SplFileInfo> */\n    private \\Traversable $iterator;\n    private \\Closure|int $sort;\n\n    /**\n     * @param \\Traversable<string, \\SplFileInfo> $iterator\n     * @param int|callable                       $sort     The sort type (SORT_BY_NAME, SORT_BY_TYPE, or a PHP callback)\n     *\n     * @throws \\InvalidArgumentException\n     */\n    public function __construct(\\Traversable $iterator, int|callable $sort, bool $reverseOrder = false)\n    {\n        $this->iterator = $iterator;\n        $order = $reverseOrder ? -1 : 1;\n\n        if (self::SORT_BY_NAME === $sort) {\n            $this->sort = static fn (\\SplFileInfo $a, \\SplFileInfo $b) => $order * strcmp($a->getRealPath() ?: $a->getPathname(), $b->getRealPath() ?: $b->getPathname());\n        } elseif (self::SORT_BY_NAME_NATURAL === $sort) {\n            $this->sort = static fn (\\SplFileInfo $a, \\SplFileInfo $b) => $order * strnatcmp($a->getRealPath() ?: $a->getPathname(), $b->getRealPath() ?: $b->getPathname());\n        } elseif (self::SORT_BY_NAME_CASE_INSENSITIVE === $sort) {\n            $this->sort = static fn (\\SplFileInfo $a, \\SplFileInfo $b) => $order * strcasecmp($a->getRealPath() ?: $a->getPathname(), $b->getRealPath() ?: $b->getPathname());\n        } elseif (self::SORT_BY_NAME_NATURAL_CASE_INSENSITIVE === $sort) {\n            $this->sort = static fn (\\SplFileInfo $a, \\SplFileInfo $b) => $order * strnatcasecmp($a->getRealPath() ?: $a->getPathname(), $b->getRealPath() ?: $b->getPathname());\n        } elseif (self::SORT_BY_TYPE === $sort) {\n            $this->sort = static function (\\SplFileInfo $a, \\SplFileInfo $b) use ($order) {\n                if ($a->isDir() && $b->isFile()) {\n                    return -$order;\n                } elseif ($a->isFile() && $b->isDir()) {\n                    return $order;\n                }\n\n                return $order * strcmp($a->getRealPath() ?: $a->getPathname(), $b->getRealPath() ?: $b->getPathname());\n            };\n        } elseif (self::SORT_BY_ACCESSED_TIME === $sort) {\n            $this->sort = static fn (\\SplFileInfo $a, \\SplFileInfo $b) => $order * ($a->getATime() - $b->getATime());\n        } elseif (self::SORT_BY_CHANGED_TIME === $sort) {\n            $this->sort = static fn (\\SplFileInfo $a, \\SplFileInfo $b) => $order * ($a->getCTime() - $b->getCTime());\n        } elseif (self::SORT_BY_MODIFIED_TIME === $sort) {\n            $this->sort = static fn (\\SplFileInfo $a, \\SplFileInfo $b) => $order * ($a->getMTime() - $b->getMTime());\n        } elseif (self::SORT_BY_EXTENSION === $sort) {\n            $this->sort = static fn (\\SplFileInfo $a, \\SplFileInfo $b) => $order * strnatcmp($a->getExtension(), $b->getExtension());\n        } elseif (self::SORT_BY_SIZE === $sort) {\n            $this->sort = static fn (\\SplFileInfo $a, \\SplFileInfo $b) => $order * ($a->getSize() - $b->getSize());\n        } elseif (self::SORT_BY_NONE === $sort) {\n            $this->sort = $order;\n        } elseif (\\is_callable($sort)) {\n            $this->sort = $reverseOrder ? static fn (\\SplFileInfo $a, \\SplFileInfo $b) => -$sort($a, $b) : $sort(...);\n        } else {\n            throw new \\InvalidArgumentException('The SortableIterator takes a PHP callable or a valid built-in sort algorithm as an argument.');\n        }\n    }\n\n    public function getIterator(): \\Traversable\n    {\n        if (1 === $this->sort) {\n            return $this->iterator;\n        }\n\n        $array = iterator_to_array($this->iterator, true);\n\n        if (-1 === $this->sort) {\n            $array = array_reverse($array);\n        } else {\n            uasort($array, $this->sort);\n        }\n\n        return new \\ArrayIterator($array);\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/finder/Iterator/VcsIgnoredFilterIterator.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Finder\\Iterator;\n\nuse Symfony\\Component\\Finder\\Gitignore;\n\n/**\n * @extends \\FilterIterator<string, \\SplFileInfo>\n */\nfinal class VcsIgnoredFilterIterator extends \\FilterIterator\n{\n    private string $baseDir;\n\n    /**\n     * @var array<string, array{0: string, 1: string}|null>\n     */\n    private array $gitignoreFilesCache = [];\n\n    /**\n     * @var array<string, bool>\n     */\n    private array $ignoredPathsCache = [];\n\n    /**\n     * @param \\Iterator<string, \\SplFileInfo> $iterator\n     */\n    public function __construct(\\Iterator $iterator, string $baseDir)\n    {\n        $this->baseDir = $this->normalizePath($baseDir);\n\n        foreach ([$this->baseDir, ...$this->parentDirectoriesUpwards($this->baseDir)] as $directory) {\n            if (@is_dir(\"{$directory}/.git\")) {\n                $this->baseDir = $directory;\n                break;\n            }\n        }\n\n        parent::__construct($iterator);\n    }\n\n    public function accept(): bool\n    {\n        $file = $this->current();\n\n        $fileRealPath = $this->normalizePath($file->getRealPath());\n\n        return !$this->isIgnored($fileRealPath);\n    }\n\n    private function isIgnored(string $fileRealPath): bool\n    {\n        if (is_dir($fileRealPath) && !str_ends_with($fileRealPath, '/')) {\n            $fileRealPath .= '/';\n        }\n\n        if (isset($this->ignoredPathsCache[$fileRealPath])) {\n            return $this->ignoredPathsCache[$fileRealPath];\n        }\n\n        $ignored = false;\n\n        foreach ($this->parentDirectoriesDownwards($fileRealPath) as $parentDirectory) {\n            if ($this->isIgnored($parentDirectory)) {\n                // rules in ignored directories are ignored, no need to check further.\n                break;\n            }\n\n            $fileRelativePath = substr($fileRealPath, \\strlen($parentDirectory) + 1);\n\n            if (null === $regexps = $this->readGitignoreFile(\"{$parentDirectory}/.gitignore\")) {\n                continue;\n            }\n\n            [$exclusionRegex, $inclusionRegex] = $regexps;\n\n            if (preg_match($exclusionRegex, $fileRelativePath)) {\n                $ignored = true;\n\n                continue;\n            }\n\n            if (preg_match($inclusionRegex, $fileRelativePath)) {\n                $ignored = false;\n            }\n        }\n\n        return $this->ignoredPathsCache[$fileRealPath] = $ignored;\n    }\n\n    /**\n     * @return list<string>\n     */\n    private function parentDirectoriesUpwards(string $from): array\n    {\n        $parentDirectories = [];\n\n        $parentDirectory = $from;\n\n        while (true) {\n            $newParentDirectory = \\dirname($parentDirectory);\n\n            // dirname('/') = '/'\n            if ($newParentDirectory === $parentDirectory) {\n                break;\n            }\n\n            $parentDirectories[] = $parentDirectory = $newParentDirectory;\n        }\n\n        return $parentDirectories;\n    }\n\n    private function parentDirectoriesUpTo(string $from, string $upTo): array\n    {\n        return array_filter(\n            $this->parentDirectoriesUpwards($from),\n            static fn (string $directory): bool => str_starts_with($directory, $upTo)\n        );\n    }\n\n    /**\n     * @return list<string>\n     */\n    private function parentDirectoriesDownwards(string $fileRealPath): array\n    {\n        return array_reverse(\n            $this->parentDirectoriesUpTo($fileRealPath, $this->baseDir)\n        );\n    }\n\n    /**\n     * @return array{0: string, 1: string}|null\n     */\n    private function readGitignoreFile(string $path): ?array\n    {\n        if (\\array_key_exists($path, $this->gitignoreFilesCache)) {\n            return $this->gitignoreFilesCache[$path];\n        }\n\n        if (!file_exists($path)) {\n            return $this->gitignoreFilesCache[$path] = null;\n        }\n\n        if (!is_file($path) || !is_readable($path)) {\n            throw new \\RuntimeException(\"The \\\"ignoreVCSIgnored\\\" option cannot be used by the Finder as the \\\"{$path}\\\" file is not readable.\");\n        }\n\n        $gitignoreFileContent = file_get_contents($path);\n\n        return $this->gitignoreFilesCache[$path] = [\n            Gitignore::toRegex($gitignoreFileContent),\n            Gitignore::toRegexMatchingNegatedPatterns($gitignoreFileContent),\n        ];\n    }\n\n    private function normalizePath(string $path): string\n    {\n        if ('\\\\' === \\DIRECTORY_SEPARATOR) {\n            return str_replace('\\\\', '/', $path);\n        }\n\n        return $path;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/finder/LICENSE",
    "content": "Copyright (c) 2004-present Fabien Potencier\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is furnished\nto do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "server/vendor/symfony/finder/README.md",
    "content": "Finder Component\n================\n\nThe Finder component finds files and directories via an intuitive fluent\ninterface.\n\nResources\n---------\n\n * [Documentation](https://symfony.com/doc/current/components/finder.html)\n * [Contributing](https://symfony.com/doc/current/contributing/index.html)\n * [Report issues](https://github.com/symfony/symfony/issues) and\n   [send Pull Requests](https://github.com/symfony/symfony/pulls)\n   in the [main Symfony repository](https://github.com/symfony/symfony)\n"
  },
  {
    "path": "server/vendor/symfony/finder/SplFileInfo.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Finder;\n\n/**\n * Extends \\SplFileInfo to support relative paths.\n *\n * @author Fabien Potencier <fabien@symfony.com>\n */\nclass SplFileInfo extends \\SplFileInfo\n{\n    private string $relativePath;\n    private string $relativePathname;\n\n    /**\n     * @param string $file             The file name\n     * @param string $relativePath     The relative path\n     * @param string $relativePathname The relative path name\n     */\n    public function __construct(string $file, string $relativePath, string $relativePathname)\n    {\n        parent::__construct($file);\n        $this->relativePath = $relativePath;\n        $this->relativePathname = $relativePathname;\n    }\n\n    /**\n     * Returns the relative path.\n     *\n     * This path does not contain the file name.\n     */\n    public function getRelativePath(): string\n    {\n        return $this->relativePath;\n    }\n\n    /**\n     * Returns the relative path name.\n     *\n     * This path contains the file name.\n     */\n    public function getRelativePathname(): string\n    {\n        return $this->relativePathname;\n    }\n\n    public function getFilenameWithoutExtension(): string\n    {\n        $filename = $this->getFilename();\n\n        return pathinfo($filename, \\PATHINFO_FILENAME);\n    }\n\n    /**\n     * Returns the contents of the file.\n     *\n     * @throws \\RuntimeException\n     */\n    public function getContents(): string\n    {\n        set_error_handler(function ($type, $msg) use (&$error) { $error = $msg; });\n        try {\n            $content = file_get_contents($this->getPathname());\n        } finally {\n            restore_error_handler();\n        }\n        if (false === $content) {\n            throw new \\RuntimeException($error);\n        }\n\n        return $content;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/finder/composer.json",
    "content": "{\n    \"name\": \"symfony/finder\",\n    \"type\": \"library\",\n    \"description\": \"Finds files and directories via an intuitive fluent interface\",\n    \"keywords\": [],\n    \"homepage\": \"https://symfony.com\",\n    \"license\": \"MIT\",\n    \"authors\": [\n        {\n            \"name\": \"Fabien Potencier\",\n            \"email\": \"fabien@symfony.com\"\n        },\n        {\n            \"name\": \"Symfony Community\",\n            \"homepage\": \"https://symfony.com/contributors\"\n        }\n    ],\n    \"require\": {\n        \"php\": \">=8.1\"\n    },\n    \"require-dev\": {\n        \"symfony/filesystem\": \"^6.0|^7.0\"\n    },\n    \"autoload\": {\n        \"psr-4\": { \"Symfony\\\\Component\\\\Finder\\\\\": \"\" },\n        \"exclude-from-classmap\": [\n            \"/Tests/\"\n        ]\n    },\n    \"minimum-stability\": \"dev\"\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/AmpHttpClient.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient;\n\nuse Amp\\CancelledException;\nuse Amp\\Http\\Client\\DelegateHttpClient;\nuse Amp\\Http\\Client\\InterceptedHttpClient;\nuse Amp\\Http\\Client\\PooledHttpClient;\nuse Amp\\Http\\Client\\Request;\nuse Amp\\Http\\Tunnel\\Http1TunnelConnector;\nuse Amp\\Promise;\nuse Psr\\Log\\LoggerAwareInterface;\nuse Psr\\Log\\LoggerAwareTrait;\nuse Symfony\\Component\\HttpClient\\Exception\\TransportException;\nuse Symfony\\Component\\HttpClient\\Internal\\AmpClientState;\nuse Symfony\\Component\\HttpClient\\Response\\AmpResponse;\nuse Symfony\\Component\\HttpClient\\Response\\ResponseStream;\nuse Symfony\\Contracts\\HttpClient\\HttpClientInterface;\nuse Symfony\\Contracts\\HttpClient\\ResponseInterface;\nuse Symfony\\Contracts\\HttpClient\\ResponseStreamInterface;\nuse Symfony\\Contracts\\Service\\ResetInterface;\n\nif (!interface_exists(DelegateHttpClient::class)) {\n    throw new \\LogicException('You cannot use \"Symfony\\Component\\HttpClient\\AmpHttpClient\" as the \"amphp/http-client\" package is not installed. Try running \"composer require amphp/http-client:^4.2.1\".');\n}\n\nif (!interface_exists(Promise::class)) {\n    throw new \\LogicException('You cannot use \"Symfony\\Component\\HttpClient\\AmpHttpClient\" as the installed \"amphp/http-client\" is not compatible with this version of \"symfony/http-client\". Try downgrading \"amphp/http-client\" to \"^4.2.1\".');\n}\n\n/**\n * A portable implementation of the HttpClientInterface contracts based on Amp's HTTP client.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n */\nfinal class AmpHttpClient implements HttpClientInterface, LoggerAwareInterface, ResetInterface\n{\n    use HttpClientTrait;\n    use LoggerAwareTrait;\n\n    public const OPTIONS_DEFAULTS = HttpClientInterface::OPTIONS_DEFAULTS + [\n        'crypto_method' => \\STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT,\n    ];\n\n    private array $defaultOptions = self::OPTIONS_DEFAULTS;\n    private static array $emptyDefaults = self::OPTIONS_DEFAULTS;\n    private AmpClientState $multi;\n\n    /**\n     * @param array         $defaultOptions     Default requests' options\n     * @param callable|null $clientConfigurator A callable that builds a {@see DelegateHttpClient} from a {@see PooledHttpClient};\n     *                                          passing null builds an {@see InterceptedHttpClient} with 2 retries on failures\n     * @param int           $maxHostConnections The maximum number of connections to a single host\n     * @param int           $maxPendingPushes   The maximum number of pushed responses to accept in the queue\n     *\n     * @see HttpClientInterface::OPTIONS_DEFAULTS for available options\n     */\n    public function __construct(array $defaultOptions = [], ?callable $clientConfigurator = null, int $maxHostConnections = 6, int $maxPendingPushes = 50)\n    {\n        $this->defaultOptions['buffer'] ??= self::shouldBuffer(...);\n\n        if ($defaultOptions) {\n            [, $this->defaultOptions] = self::prepareRequest(null, null, $defaultOptions, $this->defaultOptions);\n        }\n\n        $this->multi = new AmpClientState($clientConfigurator, $maxHostConnections, $maxPendingPushes, $this->logger);\n    }\n\n    /**\n     * @see HttpClientInterface::OPTIONS_DEFAULTS for available options\n     */\n    public function request(string $method, string $url, array $options = []): ResponseInterface\n    {\n        [$url, $options] = self::prepareRequest($method, $url, $options, $this->defaultOptions);\n\n        $options['proxy'] = self::getProxy($options['proxy'], $url, $options['no_proxy']);\n\n        if (null !== $options['proxy'] && !class_exists(Http1TunnelConnector::class)) {\n            throw new \\LogicException('You cannot use the \"proxy\" option as the \"amphp/http-tunnel\" package is not installed. Try running \"composer require amphp/http-tunnel\".');\n        }\n\n        if ($options['bindto']) {\n            if (str_starts_with($options['bindto'], 'if!')) {\n                throw new TransportException(__CLASS__.' cannot bind to network interfaces, use e.g. CurlHttpClient instead.');\n            }\n            if (str_starts_with($options['bindto'], 'host!')) {\n                $options['bindto'] = substr($options['bindto'], 5);\n            }\n        }\n\n        if (('' !== $options['body'] || 'POST' === $method || isset($options['normalized_headers']['content-length'])) && !isset($options['normalized_headers']['content-type'])) {\n            $options['headers'][] = 'Content-Type: application/x-www-form-urlencoded';\n        }\n\n        if (!isset($options['normalized_headers']['user-agent'])) {\n            $options['headers'][] = 'User-Agent: Symfony HttpClient (Amp)';\n        }\n\n        if (0 < $options['max_duration']) {\n            $options['timeout'] = min($options['max_duration'], $options['timeout']);\n        }\n\n        if ($options['resolve']) {\n            $this->multi->dnsCache = $options['resolve'] + $this->multi->dnsCache;\n        }\n\n        if ($options['peer_fingerprint'] && !isset($options['peer_fingerprint']['pin-sha256'])) {\n            throw new TransportException(__CLASS__.' supports only \"pin-sha256\" fingerprints.');\n        }\n\n        $request = new Request(implode('', $url), $method);\n        $request->setBodySizeLimit(0);\n\n        if ($options['http_version']) {\n            $request->setProtocolVersions(match ((float) $options['http_version']) {\n                1.0 => ['1.0'],\n                1.1 => ['1.1', '1.0'],\n                default => ['2', '1.1', '1.0'],\n            });\n        }\n\n        foreach ($options['headers'] as $v) {\n            $h = explode(': ', $v, 2);\n            $request->addHeader($h[0], $h[1]);\n        }\n\n        $request->setTcpConnectTimeout(1000 * $options['timeout']);\n        $request->setTlsHandshakeTimeout(1000 * $options['timeout']);\n        $request->setTransferTimeout(1000 * $options['max_duration']);\n        if (method_exists($request, 'setInactivityTimeout')) {\n            $request->setInactivityTimeout(0);\n        }\n\n        if ('' !== $request->getUri()->getUserInfo() && !$request->hasHeader('authorization')) {\n            $auth = explode(':', $request->getUri()->getUserInfo(), 2);\n            $auth = array_map('rawurldecode', $auth) + [1 => ''];\n            $request->setHeader('Authorization', 'Basic '.base64_encode(implode(':', $auth)));\n        }\n\n        return new AmpResponse($this->multi, $request, $options, $this->logger);\n    }\n\n    public function stream(ResponseInterface|iterable $responses, ?float $timeout = null): ResponseStreamInterface\n    {\n        if ($responses instanceof AmpResponse) {\n            $responses = [$responses];\n        }\n\n        return new ResponseStream(AmpResponse::stream($responses, $timeout));\n    }\n\n    public function reset(): void\n    {\n        $this->multi->dnsCache = [];\n\n        foreach ($this->multi->pushedResponses as $authority => $pushedResponses) {\n            foreach ($pushedResponses as [$pushedUrl, $pushDeferred]) {\n                $pushDeferred->fail(new CancelledException());\n\n                $this->logger?->debug(\\sprintf('Unused pushed response: \"%s\"', $pushedUrl));\n            }\n        }\n\n        $this->multi->pushedResponses = [];\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/AsyncDecoratorTrait.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient;\n\nuse Symfony\\Component\\HttpClient\\Response\\AsyncResponse;\nuse Symfony\\Component\\HttpClient\\Response\\ResponseStream;\nuse Symfony\\Contracts\\HttpClient\\ResponseInterface;\nuse Symfony\\Contracts\\HttpClient\\ResponseStreamInterface;\n\n/**\n * Eases with processing responses while streaming them.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n */\ntrait AsyncDecoratorTrait\n{\n    use DecoratorTrait;\n\n    /**\n     * @return AsyncResponse\n     */\n    abstract public function request(string $method, string $url, array $options = []): ResponseInterface;\n\n    public function stream(ResponseInterface|iterable $responses, ?float $timeout = null): ResponseStreamInterface\n    {\n        if ($responses instanceof AsyncResponse) {\n            $responses = [$responses];\n        }\n\n        return new ResponseStream(AsyncResponse::stream($responses, $timeout, static::class));\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/CHANGELOG.md",
    "content": "CHANGELOG\n=========\n\n6.4\n---\n\n * Add `HarFileResponseFactory` testing utility, allow to replay responses from `.har` files\n * Add `max_retries` option to `RetryableHttpClient` to adjust the retry logic on a per request level\n * Add `PingWehookMessage` and `PingWebhookMessageHandler`\n * Enable using EventSourceHttpClient::connect() for both GET and POST\n\n6.3\n---\n\n * Add option `crypto_method` to set the minimum TLS version and make it default to v1.2\n * Add `UriTemplateHttpClient` to use URI templates as specified in the RFC 6570\n * Add `ServerSentEvent::getArrayData()` to get the Server-Sent Event's data decoded as an array when it's a JSON payload\n * Allow array of urls as `base_uri` option value in `RetryableHttpClient` to retry on a new url each time\n * Add `JsonMockResponse`, a `MockResponse` shortcut that automatically encodes the passed body to JSON and sets the content type to `application/json` by default\n * Support file uploads by nesting resource streams in option \"body\"\n\n6.2\n---\n\n * Make `HttplugClient` implement `Psr\\Http\\Message\\RequestFactoryInterface`, `StreamFactoryInterface` and `UriFactoryInterface`\n * Deprecate implementing `Http\\Message\\RequestFactory`, `StreamFactory` and `UriFactory` on `HttplugClient`\n * Add `withOptions()` to `HttplugClient` and `Psr18Client`\n\n6.1\n---\n\n * Allow yielding `Exception` from MockResponse's `$body` to mock transport errors\n * Remove credentials from requests redirected to same host but different port\n\n5.4\n---\n\n * Add `MockHttpClient::setResponseFactory()` method to be able to set response factory after client creating\n\n5.3\n---\n\n * Implement `HttpClientInterface::withOptions()` from `symfony/contracts` v2.4\n * Add `DecoratorTrait` to ease writing simple decorators\n\n5.2.0\n-----\n\n * added `AsyncDecoratorTrait` to ease processing responses without breaking async\n * added support for pausing responses with a new `pause_handler` callable exposed as an info item\n * added `StreamableInterface` to ease turning responses into PHP streams\n * added `MockResponse::getRequestMethod()` and `getRequestUrl()` to allow inspecting which request has been sent\n * added `EventSourceHttpClient` a Server-Sent events stream implementing the [EventSource specification](https://www.w3.org/TR/eventsource/#eventsource)\n * added option \"extra.curl\" to allow setting additional curl options in `CurlHttpClient`\n * added `RetryableHttpClient` to automatically retry failed HTTP requests.\n * added `extra.trace_content` option to `TraceableHttpClient` to prevent it from keeping the content in memory\n\n5.1.0\n-----\n\n * added `NoPrivateNetworkHttpClient` decorator\n * added `AmpHttpClient`, a portable HTTP/2 implementation based on Amp\n * added `LoggerAwareInterface` to `ScopingHttpClient` and `TraceableHttpClient`\n * made `HttpClient::create()` return an `AmpHttpClient` when `amphp/http-client` is found but curl is not or too old\n\n4.4.0\n-----\n\n * added `canceled` to `ResponseInterface::getInfo()`\n * added `HttpClient::createForBaseUri()`\n * added `HttplugClient` with support for sync and async requests\n * added `max_duration` option\n * added support for NTLM authentication\n * added `StreamWrapper` to cast any `ResponseInterface` instances to PHP streams.\n * added `$response->toStream()` to cast responses to regular PHP streams\n * made `Psr18Client` implement relevant PSR-17 factories and have streaming responses\n * added `TraceableHttpClient`, `HttpClientDataCollector` and `HttpClientPass` to integrate with the web profiler\n * allow enabling buffering conditionally with a Closure\n * allow option \"buffer\" to be a stream resource\n * allow arbitrary values for the \"json\" option\n\n4.3.0\n-----\n\n * added the component\n"
  },
  {
    "path": "server/vendor/symfony/http-client/CachingHttpClient.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient;\n\nuse Symfony\\Component\\HttpClient\\Response\\MockResponse;\nuse Symfony\\Component\\HttpClient\\Response\\ResponseStream;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpKernel\\HttpCache\\HttpCache;\nuse Symfony\\Component\\HttpKernel\\HttpCache\\StoreInterface;\nuse Symfony\\Component\\HttpKernel\\HttpClientKernel;\nuse Symfony\\Contracts\\HttpClient\\HttpClientInterface;\nuse Symfony\\Contracts\\HttpClient\\ResponseInterface;\nuse Symfony\\Contracts\\HttpClient\\ResponseStreamInterface;\nuse Symfony\\Contracts\\Service\\ResetInterface;\n\n/**\n * Adds caching on top of an HTTP client.\n *\n * The implementation buffers responses in memory and doesn't stream directly from the network.\n * You can disable/enable this layer by setting option \"no_cache\" under \"extra\" to true/false.\n * By default, caching is enabled unless the \"buffer\" option is set to false.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n */\nclass CachingHttpClient implements HttpClientInterface, ResetInterface\n{\n    use HttpClientTrait;\n\n    private HttpClientInterface $client;\n    private HttpCache $cache;\n    private array $defaultOptions = self::OPTIONS_DEFAULTS;\n\n    public function __construct(HttpClientInterface $client, StoreInterface $store, array $defaultOptions = [])\n    {\n        if (!class_exists(HttpClientKernel::class)) {\n            throw new \\LogicException(\\sprintf('Using \"%s\" requires the HttpKernel component, try running \"composer require symfony/http-kernel\".', __CLASS__));\n        }\n\n        $this->client = $client;\n        $kernel = new HttpClientKernel($client);\n        $this->cache = new HttpCache($kernel, $store, null, $defaultOptions);\n\n        unset($defaultOptions['debug']);\n        unset($defaultOptions['default_ttl']);\n        unset($defaultOptions['private_headers']);\n        unset($defaultOptions['skip_response_headers']);\n        unset($defaultOptions['allow_reload']);\n        unset($defaultOptions['allow_revalidate']);\n        unset($defaultOptions['stale_while_revalidate']);\n        unset($defaultOptions['stale_if_error']);\n        unset($defaultOptions['trace_level']);\n        unset($defaultOptions['trace_header']);\n\n        if ($defaultOptions) {\n            [, $this->defaultOptions] = self::prepareRequest(null, null, $defaultOptions, $this->defaultOptions);\n        }\n    }\n\n    public function request(string $method, string $url, array $options = []): ResponseInterface\n    {\n        [$url, $options] = $this->prepareRequest($method, $url, $options, $this->defaultOptions, true);\n        $url = implode('', $url);\n\n        if (!empty($options['body']) || !empty($options['extra']['no_cache']) || !\\in_array($method, ['GET', 'HEAD', 'OPTIONS'])) {\n            return $this->client->request($method, $url, $options);\n        }\n\n        $request = Request::create($url, $method);\n        $request->attributes->set('http_client_options', $options);\n\n        foreach ($options['normalized_headers'] as $name => $values) {\n            if ('cookie' !== $name) {\n                foreach ($values as $value) {\n                    $request->headers->set($name, substr($value, 2 + \\strlen($name)), false);\n                }\n\n                continue;\n            }\n\n            foreach ($values as $cookies) {\n                foreach (explode('; ', substr($cookies, \\strlen('Cookie: '))) as $cookie) {\n                    if ('' !== $cookie) {\n                        $cookie = explode('=', $cookie, 2);\n                        $request->cookies->set($cookie[0], $cookie[1] ?? '');\n                    }\n                }\n            }\n        }\n\n        $response = $this->cache->handle($request);\n        $response = new MockResponse($response->getContent(), [\n            'http_code' => $response->getStatusCode(),\n            'response_headers' => $response->headers->allPreserveCase(),\n        ]);\n\n        return MockResponse::fromRequest($method, $url, $options, $response);\n    }\n\n    public function stream(ResponseInterface|iterable $responses, ?float $timeout = null): ResponseStreamInterface\n    {\n        if ($responses instanceof ResponseInterface) {\n            $responses = [$responses];\n        }\n\n        $mockResponses = [];\n        $clientResponses = [];\n\n        foreach ($responses as $response) {\n            if ($response instanceof MockResponse) {\n                $mockResponses[] = $response;\n            } else {\n                $clientResponses[] = $response;\n            }\n        }\n\n        if (!$mockResponses) {\n            return $this->client->stream($clientResponses, $timeout);\n        }\n\n        if (!$clientResponses) {\n            return new ResponseStream(MockResponse::stream($mockResponses, $timeout));\n        }\n\n        return new ResponseStream((function () use ($mockResponses, $clientResponses, $timeout) {\n            yield from MockResponse::stream($mockResponses, $timeout);\n            yield $this->client->stream($clientResponses, $timeout);\n        })());\n    }\n\n    /**\n     * @return void\n     */\n    public function reset()\n    {\n        if ($this->client instanceof ResetInterface) {\n            $this->client->reset();\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/Chunk/DataChunk.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient\\Chunk;\n\nuse Symfony\\Contracts\\HttpClient\\ChunkInterface;\n\n/**\n * @author Nicolas Grekas <p@tchwork.com>\n *\n * @internal\n */\nclass DataChunk implements ChunkInterface\n{\n    private int $offset = 0;\n    private string $content = '';\n\n    public function __construct(int $offset = 0, string $content = '')\n    {\n        $this->offset = $offset;\n        $this->content = $content;\n    }\n\n    public function isTimeout(): bool\n    {\n        return false;\n    }\n\n    public function isFirst(): bool\n    {\n        return false;\n    }\n\n    public function isLast(): bool\n    {\n        return false;\n    }\n\n    public function getInformationalStatus(): ?array\n    {\n        return null;\n    }\n\n    public function getContent(): string\n    {\n        return $this->content;\n    }\n\n    public function getOffset(): int\n    {\n        return $this->offset;\n    }\n\n    public function getError(): ?string\n    {\n        return null;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/Chunk/ErrorChunk.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient\\Chunk;\n\nuse Symfony\\Component\\HttpClient\\Exception\\TimeoutException;\nuse Symfony\\Component\\HttpClient\\Exception\\TransportException;\nuse Symfony\\Contracts\\HttpClient\\ChunkInterface;\n\n/**\n * @author Nicolas Grekas <p@tchwork.com>\n *\n * @internal\n */\nclass ErrorChunk implements ChunkInterface\n{\n    private bool $didThrow = false;\n    private int $offset;\n    private string $errorMessage;\n    private ?\\Throwable $error = null;\n\n    public function __construct(int $offset, \\Throwable|string $error)\n    {\n        $this->offset = $offset;\n\n        if (\\is_string($error)) {\n            $this->errorMessage = $error;\n        } else {\n            $this->error = $error;\n            $this->errorMessage = $error->getMessage();\n        }\n    }\n\n    public function isTimeout(): bool\n    {\n        $this->didThrow = true;\n\n        if (null !== $this->error) {\n            throw new TransportException($this->errorMessage, 0, $this->error);\n        }\n\n        return true;\n    }\n\n    public function isFirst(): bool\n    {\n        $this->didThrow = true;\n        throw null !== $this->error ? new TransportException($this->errorMessage, 0, $this->error) : new TimeoutException($this->errorMessage);\n    }\n\n    public function isLast(): bool\n    {\n        $this->didThrow = true;\n        throw null !== $this->error ? new TransportException($this->errorMessage, 0, $this->error) : new TimeoutException($this->errorMessage);\n    }\n\n    public function getInformationalStatus(): ?array\n    {\n        $this->didThrow = true;\n        throw null !== $this->error ? new TransportException($this->errorMessage, 0, $this->error) : new TimeoutException($this->errorMessage);\n    }\n\n    public function getContent(): string\n    {\n        $this->didThrow = true;\n        throw null !== $this->error ? new TransportException($this->errorMessage, 0, $this->error) : new TimeoutException($this->errorMessage);\n    }\n\n    public function getOffset(): int\n    {\n        return $this->offset;\n    }\n\n    public function getError(): ?string\n    {\n        return $this->errorMessage;\n    }\n\n    public function didThrow(?bool $didThrow = null): bool\n    {\n        if (null !== $didThrow && $this->didThrow !== $didThrow) {\n            return !$this->didThrow = $didThrow;\n        }\n\n        return $this->didThrow;\n    }\n\n    public function __serialize(): array\n    {\n        throw new \\BadMethodCallException('Cannot serialize '.__CLASS__);\n    }\n\n    public function __unserialize(array $data): void\n    {\n        throw new \\BadMethodCallException('Cannot unserialize '.__CLASS__);\n    }\n\n    public function __destruct()\n    {\n        if (!$this->didThrow) {\n            $this->didThrow = true;\n            throw null !== $this->error ? new TransportException($this->errorMessage, 0, $this->error) : new TimeoutException($this->errorMessage);\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/Chunk/FirstChunk.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient\\Chunk;\n\n/**\n * @author Nicolas Grekas <p@tchwork.com>\n *\n * @internal\n */\nclass FirstChunk extends DataChunk\n{\n    public function isFirst(): bool\n    {\n        return true;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/Chunk/InformationalChunk.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient\\Chunk;\n\n/**\n * @author Nicolas Grekas <p@tchwork.com>\n *\n * @internal\n */\nclass InformationalChunk extends DataChunk\n{\n    private array $status;\n\n    public function __construct(int $statusCode, array $headers)\n    {\n        $this->status = [$statusCode, $headers];\n    }\n\n    public function getInformationalStatus(): ?array\n    {\n        return $this->status;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/Chunk/LastChunk.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient\\Chunk;\n\n/**\n * @author Nicolas Grekas <p@tchwork.com>\n *\n * @internal\n */\nclass LastChunk extends DataChunk\n{\n    public function isLast(): bool\n    {\n        return true;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/Chunk/ServerSentEvent.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient\\Chunk;\n\nuse Symfony\\Component\\HttpClient\\Exception\\JsonException;\nuse Symfony\\Contracts\\HttpClient\\ChunkInterface;\n\n/**\n * @author Antoine Bluchet <soyuka@gmail.com>\n * @author Nicolas Grekas <p@tchwork.com>\n */\nfinal class ServerSentEvent extends DataChunk implements ChunkInterface\n{\n    private string $data = '';\n    private string $id = '';\n    private string $type = 'message';\n    private float $retry = 0;\n    private ?array $jsonData = null;\n\n    public function __construct(string $content)\n    {\n        parent::__construct(-1, $content);\n\n        // remove BOM\n        if (str_starts_with($content, \"\\xEF\\xBB\\xBF\")) {\n            $content = substr($content, 3);\n        }\n\n        foreach (preg_split(\"/(?:\\r\\n|[\\r\\n])/\", $content) as $line) {\n            if (0 === $i = strpos($line, ':')) {\n                continue;\n            }\n\n            $i = false === $i ? \\strlen($line) : $i;\n            $field = substr($line, 0, $i);\n            $i += 1 + (' ' === ($line[1 + $i] ?? ''));\n\n            switch ($field) {\n                case 'id': $this->id = substr($line, $i); break;\n                case 'event': $this->type = substr($line, $i); break;\n                case 'data': $this->data .= ('' === $this->data ? '' : \"\\n\").substr($line, $i); break;\n                case 'retry':\n                    $retry = substr($line, $i);\n\n                    if ('' !== $retry && \\strlen($retry) === strspn($retry, '0123456789')) {\n                        $this->retry = $retry / 1000.0;\n                    }\n                    break;\n            }\n        }\n    }\n\n    public function getId(): string\n    {\n        return $this->id;\n    }\n\n    public function getType(): string\n    {\n        return $this->type;\n    }\n\n    public function getData(): string\n    {\n        return $this->data;\n    }\n\n    public function getRetry(): float\n    {\n        return $this->retry;\n    }\n\n    /**\n     * Gets the SSE data decoded as an array when it's a JSON payload.\n     */\n    public function getArrayData(): array\n    {\n        if (null !== $this->jsonData) {\n            return $this->jsonData;\n        }\n\n        if ('' === $this->data) {\n            throw new JsonException(\\sprintf('Server-Sent Event%s data is empty.', '' !== $this->id ? \\sprintf(' \"%s\"', $this->id) : ''));\n        }\n\n        try {\n            $jsonData = json_decode($this->data, true, 512, \\JSON_BIGINT_AS_STRING | \\JSON_THROW_ON_ERROR);\n        } catch (\\JsonException $e) {\n            throw new JsonException(\\sprintf('Decoding Server-Sent Event%s failed: ', '' !== $this->id ? \\sprintf(' \"%s\"', $this->id) : '').$e->getMessage(), $e->getCode());\n        }\n\n        if (!\\is_array($jsonData)) {\n            throw new JsonException(\\sprintf('JSON content was expected to decode to an array, \"%s\" returned in Server-Sent Event%s.', get_debug_type($jsonData), '' !== $this->id ? \\sprintf(' \"%s\"', $this->id) : ''));\n        }\n\n        return $this->jsonData = $jsonData;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/CurlHttpClient.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient;\n\nuse Psr\\Log\\LoggerAwareInterface;\nuse Psr\\Log\\LoggerInterface;\nuse Symfony\\Component\\HttpClient\\Exception\\InvalidArgumentException;\nuse Symfony\\Component\\HttpClient\\Exception\\TransportException;\nuse Symfony\\Component\\HttpClient\\Internal\\CurlClientState;\nuse Symfony\\Component\\HttpClient\\Internal\\PushedResponse;\nuse Symfony\\Component\\HttpClient\\Response\\CurlResponse;\nuse Symfony\\Component\\HttpClient\\Response\\ResponseStream;\nuse Symfony\\Contracts\\HttpClient\\HttpClientInterface;\nuse Symfony\\Contracts\\HttpClient\\ResponseInterface;\nuse Symfony\\Contracts\\HttpClient\\ResponseStreamInterface;\nuse Symfony\\Contracts\\Service\\ResetInterface;\n\n/**\n * A performant implementation of the HttpClientInterface contracts based on the curl extension.\n *\n * This provides fully concurrent HTTP requests, with transparent\n * HTTP/2 push when a curl version that supports it is installed.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n */\nfinal class CurlHttpClient implements HttpClientInterface, LoggerAwareInterface, ResetInterface\n{\n    use HttpClientTrait;\n\n    public const OPTIONS_DEFAULTS = HttpClientInterface::OPTIONS_DEFAULTS + [\n        'crypto_method' => \\STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT,\n    ];\n\n    private array $defaultOptions = self::OPTIONS_DEFAULTS + [\n        'auth_ntlm' => null, // array|string - an array containing the username as first value, and optionally the\n                             //   password as the second one; or string like username:password - enabling NTLM auth\n        'extra' => [\n            'curl' => [],    // A list of extra curl options indexed by their corresponding CURLOPT_*\n        ],\n    ];\n    private static array $emptyDefaults = self::OPTIONS_DEFAULTS + ['auth_ntlm' => null];\n\n    private ?LoggerInterface $logger = null;\n\n    private int $maxHostConnections;\n    private int $maxPendingPushes;\n\n    /**\n     * An internal object to share state between the client and its responses.\n     */\n    private CurlClientState $multi;\n\n    /**\n     * @param array $defaultOptions     Default request's options\n     * @param int   $maxHostConnections The maximum number of connections to a single host\n     * @param int   $maxPendingPushes   The maximum number of pushed responses to accept in the queue\n     *\n     * @see HttpClientInterface::OPTIONS_DEFAULTS for available options\n     */\n    public function __construct(array $defaultOptions = [], int $maxHostConnections = 6, int $maxPendingPushes = 0)\n    {\n        if (!\\extension_loaded('curl')) {\n            throw new \\LogicException('You cannot use the \"Symfony\\Component\\HttpClient\\CurlHttpClient\" as the \"curl\" extension is not installed.');\n        }\n\n        $this->maxHostConnections = $maxHostConnections;\n        $this->maxPendingPushes = $maxPendingPushes;\n\n        $this->defaultOptions['buffer'] ??= self::shouldBuffer(...);\n\n        if ($defaultOptions) {\n            [, $this->defaultOptions] = self::prepareRequest(null, null, $defaultOptions, $this->defaultOptions);\n        }\n    }\n\n    public function setLogger(LoggerInterface $logger): void\n    {\n        $this->logger = $logger;\n        if (isset($this->multi)) {\n            $this->multi->logger = $logger;\n        }\n    }\n\n    /**\n     * @see HttpClientInterface::OPTIONS_DEFAULTS for available options\n     */\n    public function request(string $method, string $url, array $options = []): ResponseInterface\n    {\n        $multi = $this->ensureState();\n\n        [$url, $options] = self::prepareRequest($method, $url, $options, $this->defaultOptions);\n        $scheme = $url['scheme'];\n        $authority = $url['authority'];\n        $host = parse_url($authority, \\PHP_URL_HOST);\n        $port = parse_url($authority, \\PHP_URL_PORT) ?: ('http:' === $scheme ? 80 : 443);\n        $proxy = self::getProxyUrl($options['proxy'], $url);\n        $url = implode('', $url);\n\n        if (!isset($options['normalized_headers']['user-agent'])) {\n            $options['headers'][] = 'User-Agent: Symfony HttpClient (Curl)';\n        }\n\n        $curlopts = [\n            \\CURLOPT_URL => $url,\n            \\CURLOPT_TCP_NODELAY => true,\n            \\CURLOPT_PROTOCOLS => \\CURLPROTO_HTTP | \\CURLPROTO_HTTPS,\n            \\CURLOPT_REDIR_PROTOCOLS => \\CURLPROTO_HTTP | \\CURLPROTO_HTTPS,\n            \\CURLOPT_FOLLOWLOCATION => true,\n            \\CURLOPT_MAXREDIRS => 0 < $options['max_redirects'] ? $options['max_redirects'] : 0,\n            \\CURLOPT_COOKIEFILE => '', // Keep track of cookies during redirects\n            \\CURLOPT_TIMEOUT => 0,\n            \\CURLOPT_PROXY => $proxy,\n            \\CURLOPT_NOPROXY => $options['no_proxy'] ?? $_SERVER['no_proxy'] ?? $_SERVER['NO_PROXY'] ?? '',\n            \\CURLOPT_SSL_VERIFYPEER => $options['verify_peer'],\n            \\CURLOPT_SSL_VERIFYHOST => $options['verify_host'] ? 2 : 0,\n            \\CURLOPT_CAINFO => $options['cafile'],\n            \\CURLOPT_CAPATH => $options['capath'],\n            \\CURLOPT_SSL_CIPHER_LIST => $options['ciphers'],\n            \\CURLOPT_SSLCERT => $options['local_cert'],\n            \\CURLOPT_SSLKEY => $options['local_pk'],\n            \\CURLOPT_KEYPASSWD => $options['passphrase'],\n            \\CURLOPT_CERTINFO => $options['capture_peer_cert_chain'],\n            \\CURLOPT_SSLVERSION => match ($options['crypto_method']) {\n                \\STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT => \\CURL_SSLVERSION_TLSv1_3,\n                \\STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT => \\CURL_SSLVERSION_TLSv1_2,\n                \\STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT => \\CURL_SSLVERSION_TLSv1_1,\n                \\STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT => \\CURL_SSLVERSION_TLSv1_0,\n            },\n        ];\n\n        if (1.0 === (float) $options['http_version']) {\n            $curlopts[\\CURLOPT_HTTP_VERSION] = \\CURL_HTTP_VERSION_1_0;\n        } elseif (1.1 === (float) $options['http_version']) {\n            $curlopts[\\CURLOPT_HTTP_VERSION] = \\CURL_HTTP_VERSION_1_1;\n        } elseif (\\defined('CURL_VERSION_HTTP2') && (\\CURL_VERSION_HTTP2 & CurlClientState::$curlVersion['features']) && ('https:' === $scheme || 2.0 === (float) $options['http_version'])) {\n            $curlopts[\\CURLOPT_HTTP_VERSION] = \\CURL_HTTP_VERSION_2_0;\n        }\n\n        if (isset($options['auth_ntlm'])) {\n            $curlopts[\\CURLOPT_HTTPAUTH] = \\CURLAUTH_NTLM;\n            $curlopts[\\CURLOPT_HTTP_VERSION] = \\CURL_HTTP_VERSION_1_1;\n\n            if (\\is_array($options['auth_ntlm'])) {\n                $count = \\count($options['auth_ntlm']);\n                if ($count <= 0 || $count > 2) {\n                    throw new InvalidArgumentException(\\sprintf('Option \"auth_ntlm\" must contain 1 or 2 elements, %d given.', $count));\n                }\n\n                $options['auth_ntlm'] = implode(':', $options['auth_ntlm']);\n            }\n\n            if (!\\is_string($options['auth_ntlm'])) {\n                throw new InvalidArgumentException(\\sprintf('Option \"auth_ntlm\" must be a string or an array, \"%s\" given.', get_debug_type($options['auth_ntlm'])));\n            }\n\n            $curlopts[\\CURLOPT_USERPWD] = $options['auth_ntlm'];\n        }\n\n        if (!\\ZEND_THREAD_SAFE) {\n            $curlopts[\\CURLOPT_DNS_USE_GLOBAL_CACHE] = false;\n        }\n\n        if (\\defined('CURLOPT_HEADEROPT') && \\defined('CURLHEADER_SEPARATE')) {\n            $curlopts[\\CURLOPT_HEADEROPT] = \\CURLHEADER_SEPARATE;\n        }\n\n        // curl's resolve feature varies by host:port but ours varies by host only, let's handle this with our own DNS map\n        if (isset($multi->dnsCache->hostnames[$host])) {\n            $options['resolve'] += [$host => $multi->dnsCache->hostnames[$host]];\n        }\n\n        if ($options['resolve'] || $multi->dnsCache->evictions) {\n            // First reset any old DNS cache entries then add the new ones\n            $resolve = $multi->dnsCache->evictions;\n            $multi->dnsCache->evictions = [];\n\n            if ($resolve && 0x072A00 > CurlClientState::$curlVersion['version_number']) {\n                // DNS cache removals require curl 7.42 or higher\n                $multi->reset();\n            }\n\n            foreach ($options['resolve'] as $resolveHost => $ip) {\n                $resolve[] = null === $ip ? \"-$resolveHost:$port\" : \"$resolveHost:$port:$ip\";\n                $multi->dnsCache->hostnames[$resolveHost] = $ip;\n                $multi->dnsCache->removals[\"-$resolveHost:$port\"] = \"-$resolveHost:$port\";\n            }\n\n            $curlopts[\\CURLOPT_RESOLVE] = $resolve;\n        }\n\n        $curlopts[\\CURLOPT_CUSTOMREQUEST] = $method;\n        if ('POST' === $method) {\n            // Use CURLOPT_POST to have browser-like POST-to-GET redirects for 301, 302 and 303\n            $curlopts[\\CURLOPT_POST] = true;\n        } elseif ('HEAD' === $method) {\n            $curlopts[\\CURLOPT_NOBODY] = true;\n        }\n\n        if ('\\\\' !== \\DIRECTORY_SEPARATOR && $options['timeout'] < 1) {\n            $curlopts[\\CURLOPT_NOSIGNAL] = true;\n        }\n\n        if (\\extension_loaded('zlib') && !isset($options['normalized_headers']['accept-encoding'])) {\n            $options['headers'][] = 'Accept-Encoding: gzip'; // Expose only one encoding, some servers mess up when more are provided\n        }\n        $body = $options['body'];\n\n        foreach ($options['headers'] as $i => $header) {\n            if (\\is_string($body) && '' !== $body && 0 === stripos($header, 'Content-Length: ')) {\n                // Let curl handle Content-Length headers\n                unset($options['headers'][$i]);\n                continue;\n            }\n            if (':' === $header[-2] && \\strlen($header) - 2 === strpos($header, ': ')) {\n                // curl requires a special syntax to send empty headers\n                $curlopts[\\CURLOPT_HTTPHEADER][] = substr_replace($header, ';', -2);\n            } else {\n                $curlopts[\\CURLOPT_HTTPHEADER][] = $header;\n            }\n        }\n\n        // Prevent curl from sending its default Accept and Expect headers\n        foreach (['accept', 'expect'] as $header) {\n            if (!isset($options['normalized_headers'][$header][0])) {\n                $curlopts[\\CURLOPT_HTTPHEADER][] = $header.':';\n            }\n        }\n\n        if (!\\is_string($body)) {\n            if (\\is_resource($body)) {\n                $curlopts[\\CURLOPT_READDATA] = $body;\n            } else {\n                $curlopts[\\CURLOPT_READFUNCTION] = static function ($ch, $fd, $length) use ($body) {\n                    static $eof = false;\n                    static $buffer = '';\n\n                    return self::readRequestBody($length, $body, $buffer, $eof);\n                };\n            }\n\n            if (isset($options['normalized_headers']['content-length'][0])) {\n                $curlopts[\\CURLOPT_INFILESIZE] = (int) substr($options['normalized_headers']['content-length'][0], \\strlen('Content-Length: '));\n            }\n            if (!isset($options['normalized_headers']['transfer-encoding'])) {\n                $curlopts[\\CURLOPT_HTTPHEADER][] = 'Transfer-Encoding:'.(isset($curlopts[\\CURLOPT_INFILESIZE]) ? '' : ' chunked');\n            }\n\n            if ('POST' !== $method) {\n                $curlopts[\\CURLOPT_UPLOAD] = true;\n\n                if (!isset($options['normalized_headers']['content-type']) && 0 !== ($curlopts[\\CURLOPT_INFILESIZE] ?? null)) {\n                    $curlopts[\\CURLOPT_HTTPHEADER][] = 'Content-Type: application/x-www-form-urlencoded';\n                }\n            }\n        } elseif ('' !== $body || 'POST' === $method) {\n            $curlopts[\\CURLOPT_POSTFIELDS] = $body;\n        }\n\n        if ($options['peer_fingerprint']) {\n            if (!isset($options['peer_fingerprint']['pin-sha256'])) {\n                throw new TransportException(__CLASS__.' supports only \"pin-sha256\" fingerprints.');\n            }\n\n            $curlopts[\\CURLOPT_PINNEDPUBLICKEY] = 'sha256//'.implode(';sha256//', $options['peer_fingerprint']['pin-sha256']);\n        }\n\n        if ($options['bindto']) {\n            if (file_exists($options['bindto'])) {\n                $curlopts[\\CURLOPT_UNIX_SOCKET_PATH] = $options['bindto'];\n            } elseif (!str_starts_with($options['bindto'], 'if!') && preg_match('/^(.*):(\\d+)$/', $options['bindto'], $matches)) {\n                $curlopts[\\CURLOPT_INTERFACE] = trim($matches[1], '[]');\n                $curlopts[\\CURLOPT_LOCALPORT] = $matches[2];\n            } else {\n                $curlopts[\\CURLOPT_INTERFACE] = $options['bindto'];\n            }\n        }\n\n        if (0 < $options['max_duration']) {\n            $curlopts[\\CURLOPT_TIMEOUT_MS] = 1000 * $options['max_duration'];\n        }\n\n        if (!empty($options['extra']['curl']) && \\is_array($options['extra']['curl'])) {\n            $this->validateExtraCurlOptions($options['extra']['curl']);\n            $curlopts += $options['extra']['curl'];\n        }\n\n        if ($pushedResponse = $multi->pushedResponses[$url] ?? null) {\n            unset($multi->pushedResponses[$url]);\n\n            if (self::acceptPushForRequest($method, $options, $pushedResponse)) {\n                $this->logger?->debug(\\sprintf('Accepting pushed response: \"%s %s\"', $method, $url));\n\n                // Reinitialize the pushed response with request's options\n                $ch = $pushedResponse->handle;\n                $pushedResponse = $pushedResponse->response;\n                $pushedResponse->__construct($multi, $url, $options, $this->logger);\n            } else {\n                $this->logger?->debug(\\sprintf('Rejecting pushed response: \"%s\"', $url));\n                $pushedResponse = null;\n            }\n        }\n\n        if (!$pushedResponse) {\n            $ch = curl_init();\n            $this->logger?->info(\\sprintf('Request: \"%s %s\"', $method, $url));\n            $curlopts += [\\CURLOPT_SHARE => $multi->share];\n        }\n\n        foreach ($curlopts as $opt => $value) {\n            if (\\PHP_INT_SIZE === 8 && \\defined('CURLOPT_INFILESIZE_LARGE') && \\CURLOPT_INFILESIZE === $opt && $value >= 1 << 31) {\n                $opt = \\CURLOPT_INFILESIZE_LARGE;\n            }\n            if (null !== $value && !curl_setopt($ch, $opt, $value) && \\CURLOPT_CERTINFO !== $opt && (!\\defined('CURLOPT_HEADEROPT') || \\CURLOPT_HEADEROPT !== $opt)) {\n                $constantName = $this->findConstantName($opt);\n                throw new TransportException(\\sprintf('Curl option \"%s\" is not supported.', $constantName ?? $opt));\n            }\n        }\n\n        return $pushedResponse ?? new CurlResponse($multi, $ch, $options, $this->logger, $method, self::createRedirectResolver($options, $authority), CurlClientState::$curlVersion['version_number'], $url);\n    }\n\n    public function stream(ResponseInterface|iterable $responses, ?float $timeout = null): ResponseStreamInterface\n    {\n        if ($responses instanceof CurlResponse) {\n            $responses = [$responses];\n        }\n\n        $multi = $this->ensureState();\n\n        if ($multi->handle instanceof \\CurlMultiHandle) {\n            $active = 0;\n            while (\\CURLM_CALL_MULTI_PERFORM === curl_multi_exec($multi->handle, $active)) {\n            }\n        }\n\n        return new ResponseStream(CurlResponse::stream($responses, $timeout));\n    }\n\n    public function reset(): void\n    {\n        if (isset($this->multi)) {\n            $this->multi->reset();\n        }\n    }\n\n    /**\n     * Accepts pushed responses only if their headers related to authentication match the request.\n     */\n    private static function acceptPushForRequest(string $method, array $options, PushedResponse $pushedResponse): bool\n    {\n        if ('' !== $options['body'] || $method !== $pushedResponse->requestHeaders[':method'][0]) {\n            return false;\n        }\n\n        foreach (['proxy', 'no_proxy', 'bindto', 'local_cert', 'local_pk'] as $k) {\n            if ($options[$k] !== $pushedResponse->parentOptions[$k]) {\n                return false;\n            }\n        }\n\n        foreach (['authorization', 'cookie', 'range', 'proxy-authorization'] as $k) {\n            $normalizedHeaders = $options['normalized_headers'][$k] ?? [];\n            foreach ($normalizedHeaders as $i => $v) {\n                $normalizedHeaders[$i] = substr($v, \\strlen($k) + 2);\n            }\n\n            if (($pushedResponse->requestHeaders[$k] ?? []) !== $normalizedHeaders) {\n                return false;\n            }\n        }\n\n        $statusCode = $pushedResponse->response->getInfo('http_code') ?: 200;\n\n        return $statusCode < 300 || 400 <= $statusCode;\n    }\n\n    /**\n     * Wraps the request's body callback to allow it to return strings longer than curl requested.\n     */\n    private static function readRequestBody(int $length, \\Closure $body, string &$buffer, bool &$eof): string\n    {\n        if (!$eof && \\strlen($buffer) < $length) {\n            if (!\\is_string($data = $body($length))) {\n                throw new TransportException(\\sprintf('The return value of the \"body\" option callback must be a string, \"%s\" returned.', get_debug_type($data)));\n            }\n\n            $buffer .= $data;\n            $eof = '' === $data;\n        }\n\n        $data = substr($buffer, 0, $length);\n        $buffer = substr($buffer, $length);\n\n        return $data;\n    }\n\n    /**\n     * Resolves relative URLs on redirects and deals with authentication headers.\n     *\n     * Work around CVE-2018-1000007: Authorization and Cookie headers should not follow redirects - fixed in Curl 7.64\n     */\n    private static function createRedirectResolver(array $options, string $authority): \\Closure\n    {\n        $redirectHeaders = [];\n        if (0 < $options['max_redirects']) {\n            $redirectHeaders['authority'] = $authority;\n            $redirectHeaders['with_auth'] = $redirectHeaders['no_auth'] = array_filter($options['headers'], static fn ($h) => 0 !== stripos($h, 'Host:'));\n\n            if (isset($options['normalized_headers']['authorization'][0]) || isset($options['normalized_headers']['cookie'][0])) {\n                $redirectHeaders['no_auth'] = array_filter($options['headers'], static fn ($h) => 0 !== stripos($h, 'Authorization:') && 0 !== stripos($h, 'Cookie:'));\n            }\n        }\n\n        return static function ($ch, string $location, bool $noContent) use (&$redirectHeaders, $options) {\n            try {\n                $location = self::parseUrl($location);\n                $url = self::parseUrl(curl_getinfo($ch, \\CURLINFO_EFFECTIVE_URL));\n                $url = self::resolveUrl($location, $url);\n            } catch (InvalidArgumentException) {\n                return null;\n            }\n\n            if ($noContent && $redirectHeaders) {\n                $filterContentHeaders = static fn ($h) => 0 !== stripos($h, 'Content-Length:') && 0 !== stripos($h, 'Content-Type:') && 0 !== stripos($h, 'Transfer-Encoding:');\n                $redirectHeaders['no_auth'] = array_filter($redirectHeaders['no_auth'], $filterContentHeaders);\n                $redirectHeaders['with_auth'] = array_filter($redirectHeaders['with_auth'], $filterContentHeaders);\n            }\n\n            if ($redirectHeaders && isset($location['authority'])) {\n                $requestHeaders = $location['authority'] === $redirectHeaders['authority'] ? $redirectHeaders['with_auth'] : $redirectHeaders['no_auth'];\n                curl_setopt($ch, \\CURLOPT_HTTPHEADER, $requestHeaders);\n            } elseif ($noContent && $redirectHeaders) {\n                curl_setopt($ch, \\CURLOPT_HTTPHEADER, $redirectHeaders['with_auth']);\n            }\n\n            curl_setopt($ch, \\CURLOPT_PROXY, self::getProxyUrl($options['proxy'], $url));\n\n            return implode('', $url);\n        };\n    }\n\n    private function ensureState(): CurlClientState\n    {\n        if (!isset($this->multi)) {\n            $this->multi = new CurlClientState($this->maxHostConnections, $this->maxPendingPushes);\n            $this->multi->logger = $this->logger;\n        }\n\n        return $this->multi;\n    }\n\n    private function findConstantName(int $opt): ?string\n    {\n        $constants = array_filter(get_defined_constants(), static fn ($v, $k) => $v === $opt && 'C' === $k[0] && (str_starts_with($k, 'CURLOPT_') || str_starts_with($k, 'CURLINFO_')), \\ARRAY_FILTER_USE_BOTH);\n\n        return key($constants);\n    }\n\n    /**\n     * Prevents overriding options that are set internally throughout the request.\n     */\n    private function validateExtraCurlOptions(array $options): void\n    {\n        $curloptsToConfig = [\n            // options used in CurlHttpClient\n            \\CURLOPT_HTTPAUTH => 'auth_ntlm',\n            \\CURLOPT_USERPWD => 'auth_ntlm',\n            \\CURLOPT_RESOLVE => 'resolve',\n            \\CURLOPT_NOSIGNAL => 'timeout',\n            \\CURLOPT_HTTPHEADER => 'headers',\n            \\CURLOPT_READDATA => 'body',\n            \\CURLOPT_READFUNCTION => 'body',\n            \\CURLOPT_INFILESIZE => 'body',\n            \\CURLOPT_POSTFIELDS => 'body',\n            \\CURLOPT_UPLOAD => 'body',\n            \\CURLOPT_INTERFACE => 'bindto',\n            \\CURLOPT_TIMEOUT_MS => 'max_duration',\n            \\CURLOPT_TIMEOUT => 'max_duration',\n            \\CURLOPT_MAXREDIRS => 'max_redirects',\n            \\CURLOPT_POSTREDIR => 'max_redirects',\n            \\CURLOPT_PROXY => 'proxy',\n            \\CURLOPT_NOPROXY => 'no_proxy',\n            \\CURLOPT_SSL_VERIFYPEER => 'verify_peer',\n            \\CURLOPT_SSL_VERIFYHOST => 'verify_host',\n            \\CURLOPT_CAINFO => 'cafile',\n            \\CURLOPT_CAPATH => 'capath',\n            \\CURLOPT_SSL_CIPHER_LIST => 'ciphers',\n            \\CURLOPT_SSLCERT => 'local_cert',\n            \\CURLOPT_SSLKEY => 'local_pk',\n            \\CURLOPT_KEYPASSWD => 'passphrase',\n            \\CURLOPT_CERTINFO => 'capture_peer_cert_chain',\n            \\CURLOPT_USERAGENT => 'normalized_headers',\n            \\CURLOPT_REFERER => 'headers',\n            // options used in CurlResponse\n            \\CURLOPT_NOPROGRESS => 'on_progress',\n            \\CURLOPT_PROGRESSFUNCTION => 'on_progress',\n        ];\n\n        if (\\defined('CURLOPT_UNIX_SOCKET_PATH')) {\n            $curloptsToConfig[\\CURLOPT_UNIX_SOCKET_PATH] = 'bindto';\n        }\n\n        if (\\defined('CURLOPT_PINNEDPUBLICKEY')) {\n            $curloptsToConfig[\\CURLOPT_PINNEDPUBLICKEY] = 'peer_fingerprint';\n        }\n\n        $curloptsToCheck = [\n            \\CURLOPT_PRIVATE,\n            \\CURLOPT_HEADERFUNCTION,\n            \\CURLOPT_WRITEFUNCTION,\n            \\CURLOPT_VERBOSE,\n            \\CURLOPT_STDERR,\n            \\CURLOPT_RETURNTRANSFER,\n            \\CURLOPT_URL,\n            \\CURLOPT_FOLLOWLOCATION,\n            \\CURLOPT_HEADER,\n            \\CURLOPT_CONNECTTIMEOUT,\n            \\CURLOPT_CONNECTTIMEOUT_MS,\n            \\CURLOPT_HTTP_VERSION,\n            \\CURLOPT_PORT,\n            \\CURLOPT_DNS_USE_GLOBAL_CACHE,\n            \\CURLOPT_PROTOCOLS,\n            \\CURLOPT_REDIR_PROTOCOLS,\n            \\CURLOPT_COOKIEFILE,\n            \\CURLINFO_REDIRECT_COUNT,\n        ];\n\n        if (\\defined('CURLOPT_HTTP09_ALLOWED')) {\n            $curloptsToCheck[] = \\CURLOPT_HTTP09_ALLOWED;\n        }\n\n        if (\\defined('CURLOPT_HEADEROPT')) {\n            $curloptsToCheck[] = \\CURLOPT_HEADEROPT;\n        }\n\n        $methodOpts = [\n            \\CURLOPT_POST,\n            \\CURLOPT_PUT,\n            \\CURLOPT_CUSTOMREQUEST,\n            \\CURLOPT_HTTPGET,\n            \\CURLOPT_NOBODY,\n        ];\n\n        foreach ($options as $opt => $optValue) {\n            if (isset($curloptsToConfig[$opt])) {\n                $constName = $this->findConstantName($opt) ?? $opt;\n                throw new InvalidArgumentException(\\sprintf('Cannot set \"%s\" with \"extra.curl\", use option \"%s\" instead.', $constName, $curloptsToConfig[$opt]));\n            }\n\n            if (\\in_array($opt, $methodOpts)) {\n                throw new InvalidArgumentException('The HTTP method cannot be overridden using \"extra.curl\".');\n            }\n\n            if (\\in_array($opt, $curloptsToCheck)) {\n                $constName = $this->findConstantName($opt) ?? $opt;\n                throw new InvalidArgumentException(\\sprintf('Cannot set \"%s\" with \"extra.curl\".', $constName));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/DataCollector/HttpClientDataCollector.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient\\DataCollector;\n\nuse Symfony\\Component\\HttpClient\\Exception\\TransportException;\nuse Symfony\\Component\\HttpClient\\HttpClientTrait;\nuse Symfony\\Component\\HttpClient\\TraceableHttpClient;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\DataCollector\\DataCollector;\nuse Symfony\\Component\\HttpKernel\\DataCollector\\LateDataCollectorInterface;\nuse Symfony\\Component\\Process\\Process;\nuse Symfony\\Component\\VarDumper\\Caster\\ImgStub;\n\n/**\n * @author Jérémy Romey <jeremy@free-agent.fr>\n */\nfinal class HttpClientDataCollector extends DataCollector implements LateDataCollectorInterface\n{\n    use HttpClientTrait;\n\n    /**\n     * @var TraceableHttpClient[]\n     */\n    private array $clients = [];\n\n    public function registerClient(string $name, TraceableHttpClient $client): void\n    {\n        $this->clients[$name] = $client;\n    }\n\n    public function collect(Request $request, Response $response, ?\\Throwable $exception = null): void\n    {\n        $this->lateCollect();\n    }\n\n    public function lateCollect(): void\n    {\n        $this->data['request_count'] = $this->data['request_count'] ?? 0;\n        $this->data['error_count'] = $this->data['error_count'] ?? 0;\n        $this->data += ['clients' => []];\n\n        foreach ($this->clients as $name => $client) {\n            [$errorCount, $traces] = $this->collectOnClient($client);\n\n            $this->data['clients'] += [\n                $name => [\n                    'traces' => [],\n                    'error_count' => 0,\n                ],\n            ];\n\n            $this->data['clients'][$name]['traces'] = array_merge($this->data['clients'][$name]['traces'], $traces);\n            $this->data['request_count'] += \\count($traces);\n            $this->data['error_count'] += $errorCount;\n            $this->data['clients'][$name]['error_count'] += $errorCount;\n\n            $client->reset();\n        }\n    }\n\n    public function getClients(): array\n    {\n        return $this->data['clients'] ?? [];\n    }\n\n    public function getRequestCount(): int\n    {\n        return $this->data['request_count'] ?? 0;\n    }\n\n    public function getErrorCount(): int\n    {\n        return $this->data['error_count'] ?? 0;\n    }\n\n    public function getName(): string\n    {\n        return 'http_client';\n    }\n\n    public function reset(): void\n    {\n        $this->data = [\n            'clients' => [],\n            'request_count' => 0,\n            'error_count' => 0,\n        ];\n    }\n\n    private function collectOnClient(TraceableHttpClient $client): array\n    {\n        $traces = $client->getTracedRequests();\n        $errorCount = 0;\n        $baseInfo = [\n            'response_headers' => 1,\n            'retry_count' => 1,\n            'redirect_count' => 1,\n            'redirect_url' => 1,\n            'user_data' => 1,\n            'error' => 1,\n            'url' => 1,\n        ];\n\n        foreach ($traces as $i => $trace) {\n            if (400 <= ($trace['info']['http_code'] ?? 0)) {\n                ++$errorCount;\n            }\n\n            $info = $trace['info'];\n            $traces[$i]['http_code'] = $info['http_code'] ?? 0;\n\n            unset($info['filetime'], $info['http_code'], $info['ssl_verify_result'], $info['content_type']);\n\n            if (($info['http_method'] ?? null) === $trace['method']) {\n                unset($info['http_method']);\n            }\n\n            if (($info['url'] ?? null) === $trace['url']) {\n                unset($info['url']);\n            }\n\n            foreach ($info as $k => $v) {\n                if (!$v || (is_numeric($v) && 0 > $v)) {\n                    unset($info[$k]);\n                }\n            }\n\n            if (\\is_string($content = $trace['content'])) {\n                $contentType = 'application/octet-stream';\n\n                foreach ($info['response_headers'] ?? [] as $h) {\n                    if (0 === stripos($h, 'content-type: ')) {\n                        $contentType = substr($h, \\strlen('content-type: '));\n                        break;\n                    }\n                }\n\n                if (str_starts_with($contentType, 'image/') && class_exists(ImgStub::class)) {\n                    $content = new ImgStub($content, $contentType, '');\n                } else {\n                    $content = [$content];\n                }\n\n                $content = ['response_content' => $content];\n            } elseif (\\is_array($content)) {\n                $content = ['response_json' => $content];\n            } else {\n                $content = [];\n            }\n\n            if (isset($info['retry_count'])) {\n                $content['retries'] = $info['previous_info'];\n                unset($info['previous_info']);\n            }\n\n            $debugInfo = array_diff_key($info, $baseInfo);\n            $info = ['info' => $debugInfo] + array_diff_key($info, $debugInfo) + $content;\n            unset($traces[$i]['info']); // break PHP reference used by TraceableHttpClient\n            $traces[$i]['info'] = $this->cloneVar($info);\n            $traces[$i]['options'] = $this->cloneVar($trace['options']);\n            $traces[$i]['curlCommand'] = $this->getCurlCommand($trace);\n        }\n\n        return [$errorCount, $traces];\n    }\n\n    private function getCurlCommand(array $trace): ?string\n    {\n        if (!isset($trace['info']['debug'])) {\n            return null;\n        }\n\n        $url = $trace['info']['original_url'] ?? $trace['info']['url'] ?? $trace['url'];\n        $command = ['curl', '--compressed'];\n\n        if (isset($trace['options']['resolve'])) {\n            $port = parse_url($url, \\PHP_URL_PORT) ?: (str_starts_with('http:', $url) ? 80 : 443);\n            foreach ($trace['options']['resolve'] as $host => $ip) {\n                if (null !== $ip) {\n                    $command[] = '--resolve '.escapeshellarg(\"$host:$port:$ip\");\n                }\n            }\n        }\n\n        $dataArg = [];\n\n        if ($json = $trace['options']['json'] ?? null) {\n            $dataArg[] = '--data-raw '.$this->escapePayload(self::jsonEncode($json));\n        } elseif ($body = $trace['options']['body'] ?? null) {\n            if (\\is_string($body)) {\n                $dataArg[] = '--data-raw '.$this->escapePayload($body);\n            } elseif (\\is_array($body)) {\n                try {\n                    $body = explode('&', self::normalizeBody($body));\n                } catch (TransportException) {\n                    return null;\n                }\n                foreach ($body as $value) {\n                    $dataArg[] = '--data-raw '.$this->escapePayload(urldecode($value));\n                }\n            } else {\n                return null;\n            }\n        }\n\n        $dataArg = empty($dataArg) ? null : implode(' ', $dataArg);\n\n        foreach (explode(\"\\n\", $trace['info']['debug']) as $line) {\n            $line = substr($line, 0, -1);\n\n            if (str_starts_with('< ', $line)) {\n                // End of the request, beginning of the response. Stop parsing.\n                break;\n            }\n\n            if (str_starts_with('Due to a bug in curl ', $line)) {\n                // When the curl client disables debug info due to a curl bug, we cannot build the command.\n                return null;\n            }\n\n            if ('' === $line || preg_match('/^[*<]|(Host: )/', $line)) {\n                continue;\n            }\n\n            if (preg_match('/^> ([A-Z]+)/', $line, $match)) {\n                $command[] = \\sprintf('--request %s', $match[1]);\n                $command[] = \\sprintf('--url %s', escapeshellarg($url));\n                continue;\n            }\n\n            $command[] = '--header '.escapeshellarg($line);\n        }\n\n        if (null !== $dataArg) {\n            $command[] = $dataArg;\n        }\n\n        return implode(\" \\\\\\n  \", $command);\n    }\n\n    private function escapePayload(string $payload): string\n    {\n        static $useProcess;\n\n        if ($useProcess ??= \\function_exists('proc_open') && class_exists(Process::class)) {\n            return substr((new Process(['', $payload]))->getCommandLine(), 3);\n        }\n\n        if ('\\\\' === \\DIRECTORY_SEPARATOR) {\n            return '\"'.str_replace('\"', '\"\"', $payload).'\"';\n        }\n\n        return \"'\".str_replace(\"'\", \"'\\\\''\", $payload).\"'\";\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/DecoratorTrait.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient;\n\nuse Symfony\\Contracts\\HttpClient\\HttpClientInterface;\nuse Symfony\\Contracts\\HttpClient\\ResponseInterface;\nuse Symfony\\Contracts\\HttpClient\\ResponseStreamInterface;\nuse Symfony\\Contracts\\Service\\ResetInterface;\n\n/**\n * Eases with writing decorators.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n */\ntrait DecoratorTrait\n{\n    private HttpClientInterface $client;\n\n    public function __construct(?HttpClientInterface $client = null)\n    {\n        $this->client = $client ?? HttpClient::create();\n    }\n\n    public function request(string $method, string $url, array $options = []): ResponseInterface\n    {\n        return $this->client->request($method, $url, $options);\n    }\n\n    public function stream(ResponseInterface|iterable $responses, ?float $timeout = null): ResponseStreamInterface\n    {\n        return $this->client->stream($responses, $timeout);\n    }\n\n    public function withOptions(array $options): static\n    {\n        $clone = clone $this;\n        $clone->client = $this->client->withOptions($options);\n\n        return $clone;\n    }\n\n    /**\n     * @return void\n     */\n    public function reset()\n    {\n        if ($this->client instanceof ResetInterface) {\n            $this->client->reset();\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/DependencyInjection/HttpClientPass.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient\\DependencyInjection;\n\nuse Symfony\\Component\\DependencyInjection\\Compiler\\CompilerPassInterface;\nuse Symfony\\Component\\DependencyInjection\\ContainerBuilder;\nuse Symfony\\Component\\DependencyInjection\\ContainerInterface;\nuse Symfony\\Component\\DependencyInjection\\Reference;\nuse Symfony\\Component\\HttpClient\\TraceableHttpClient;\n\nfinal class HttpClientPass implements CompilerPassInterface\n{\n    public function process(ContainerBuilder $container): void\n    {\n        if (!$container->hasDefinition('data_collector.http_client')) {\n            return;\n        }\n\n        foreach ($container->findTaggedServiceIds('http_client.client') as $id => $tags) {\n            $container->register('.debug.'.$id, TraceableHttpClient::class)\n                ->setArguments([new Reference('.debug.'.$id.'.inner'), new Reference('debug.stopwatch', ContainerInterface::IGNORE_ON_INVALID_REFERENCE)])\n                ->addTag('kernel.reset', ['method' => 'reset'])\n                ->setDecoratedService($id, null, 5);\n            $container->getDefinition('data_collector.http_client')\n                ->addMethodCall('registerClient', [$id, new Reference('.debug.'.$id)]);\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/EventSourceHttpClient.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient;\n\nuse Symfony\\Component\\HttpClient\\Chunk\\DataChunk;\nuse Symfony\\Component\\HttpClient\\Chunk\\ServerSentEvent;\nuse Symfony\\Component\\HttpClient\\Exception\\EventSourceException;\nuse Symfony\\Component\\HttpClient\\Response\\AsyncContext;\nuse Symfony\\Component\\HttpClient\\Response\\AsyncResponse;\nuse Symfony\\Contracts\\HttpClient\\ChunkInterface;\nuse Symfony\\Contracts\\HttpClient\\Exception\\TransportExceptionInterface;\nuse Symfony\\Contracts\\HttpClient\\HttpClientInterface;\nuse Symfony\\Contracts\\HttpClient\\ResponseInterface;\nuse Symfony\\Contracts\\Service\\ResetInterface;\n\n/**\n * @author Antoine Bluchet <soyuka@gmail.com>\n * @author Nicolas Grekas <p@tchwork.com>\n */\nfinal class EventSourceHttpClient implements HttpClientInterface, ResetInterface\n{\n    use AsyncDecoratorTrait, HttpClientTrait {\n        AsyncDecoratorTrait::withOptions insteadof HttpClientTrait;\n    }\n\n    private float $reconnectionTime;\n\n    public function __construct(?HttpClientInterface $client = null, float $reconnectionTime = 10.0)\n    {\n        $this->client = $client ?? HttpClient::create();\n        $this->reconnectionTime = $reconnectionTime;\n    }\n\n    public function connect(string $url, array $options = [], string $method = 'GET'): ResponseInterface\n    {\n        return $this->request($method, $url, self::mergeDefaultOptions($options, [\n            'buffer' => false,\n            'headers' => [\n                'Accept' => 'text/event-stream',\n                'Cache-Control' => 'no-cache',\n            ],\n        ], true));\n    }\n\n    public function request(string $method, string $url, array $options = []): ResponseInterface\n    {\n        $state = new class {\n            public ?string $buffer = null;\n            public ?string $lastEventId = null;\n            public float $reconnectionTime;\n            public ?float $lastError = null;\n        };\n        $state->reconnectionTime = $this->reconnectionTime;\n\n        if ($accept = self::normalizeHeaders($options['headers'] ?? [])['accept'] ?? []) {\n            $state->buffer = \\in_array($accept, [['Accept: text/event-stream'], ['accept: text/event-stream']], true) ? '' : null;\n\n            if (null !== $state->buffer) {\n                $options['extra']['trace_content'] = false;\n            }\n        }\n\n        return new AsyncResponse($this->client, $method, $url, $options, static function (ChunkInterface $chunk, AsyncContext $context) use ($state, $method, $url, $options) {\n            if (null !== $state->buffer) {\n                $context->setInfo('reconnection_time', $state->reconnectionTime);\n                $isTimeout = false;\n            }\n            $lastError = $state->lastError;\n            $state->lastError = null;\n\n            try {\n                $isTimeout = $chunk->isTimeout();\n\n                if (null !== $chunk->getInformationalStatus() || $context->getInfo('canceled')) {\n                    yield $chunk;\n\n                    return;\n                }\n            } catch (TransportExceptionInterface) {\n                $state->lastError = $lastError ?? hrtime(true) / 1E9;\n\n                if (null === $state->buffer || ($isTimeout && hrtime(true) / 1E9 - $state->lastError < $state->reconnectionTime)) {\n                    yield $chunk;\n                } else {\n                    $options['headers']['Last-Event-ID'] = $state->lastEventId;\n                    $state->buffer = '';\n                    $state->lastError = hrtime(true) / 1E9;\n                    $context->getResponse()->cancel();\n                    $context->replaceRequest($method, $url, $options);\n                    if ($isTimeout) {\n                        yield $chunk;\n                    } else {\n                        $context->pause($state->reconnectionTime);\n                    }\n                }\n\n                return;\n            }\n\n            if ($chunk->isFirst()) {\n                if (preg_match('/^text\\/event-stream(;|$)/i', $context->getHeaders()['content-type'][0] ?? '')) {\n                    $state->buffer = '';\n                } elseif (null !== $lastError || (null !== $state->buffer && 200 === $context->getStatusCode())) {\n                    throw new EventSourceException(\\sprintf('Response content-type is \"%s\" while \"text/event-stream\" was expected for \"%s\".', $context->getHeaders()['content-type'][0] ?? '', $context->getInfo('url')));\n                } else {\n                    $context->passthru();\n                }\n\n                if (null === $lastError) {\n                    yield $chunk;\n                }\n\n                return;\n            }\n\n            if ($chunk->isLast()) {\n                if ('' !== $content = $state->buffer) {\n                    $state->buffer = '';\n                    yield new DataChunk(-1, $content);\n                }\n\n                yield $chunk;\n\n                return;\n            }\n\n            $content = $state->buffer.$chunk->getContent();\n            $events = preg_split('/((?:\\r\\n){2,}|\\r{2,}|\\n{2,})/', $content, -1, \\PREG_SPLIT_DELIM_CAPTURE);\n            $state->buffer = array_pop($events);\n\n            for ($i = 0; isset($events[$i]); $i += 2) {\n                $content = $events[$i].$events[1 + $i];\n                if (!preg_match('/(?:^|\\r\\n|[\\r\\n])[^:\\r\\n]/', $content)) {\n                    yield new DataChunk(-1, $content);\n\n                    continue;\n                }\n\n                $event = new ServerSentEvent($content);\n\n                if ('' !== $event->getId()) {\n                    $context->setInfo('last_event_id', $state->lastEventId = $event->getId());\n                }\n\n                if ($event->getRetry()) {\n                    $context->setInfo('reconnection_time', $state->reconnectionTime = $event->getRetry());\n                }\n\n                yield $event;\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/Exception/ClientException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient\\Exception;\n\nuse Symfony\\Contracts\\HttpClient\\Exception\\ClientExceptionInterface;\n\n/**\n * Represents a 4xx response.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n */\nfinal class ClientException extends \\RuntimeException implements ClientExceptionInterface\n{\n    use HttpExceptionTrait;\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/Exception/EventSourceException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient\\Exception;\n\nuse Symfony\\Contracts\\HttpClient\\Exception\\DecodingExceptionInterface;\n\n/**\n * @author Nicolas Grekas <p@tchwork.com>\n */\nfinal class EventSourceException extends \\RuntimeException implements DecodingExceptionInterface\n{\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/Exception/HttpExceptionTrait.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient\\Exception;\n\nuse Symfony\\Contracts\\HttpClient\\ResponseInterface;\n\n/**\n * @author Nicolas Grekas <p@tchwork.com>\n *\n * @internal\n */\ntrait HttpExceptionTrait\n{\n    private ResponseInterface $response;\n\n    public function __construct(ResponseInterface $response)\n    {\n        $this->response = $response;\n        $code = $response->getInfo('http_code');\n        $url = $response->getInfo('url');\n        $message = \\sprintf('HTTP %d returned for \"%s\".', $code, $url);\n\n        $httpCodeFound = false;\n        $isJson = false;\n        foreach (array_reverse($response->getInfo('response_headers')) as $h) {\n            if (str_starts_with($h, 'HTTP/')) {\n                if ($httpCodeFound) {\n                    break;\n                }\n\n                $message = \\sprintf('%s returned for \"%s\".', $h, $url);\n                $httpCodeFound = true;\n            }\n\n            if (0 === stripos($h, 'content-type:')) {\n                if (preg_match('/\\bjson\\b/i', $h)) {\n                    $isJson = true;\n                }\n\n                if ($httpCodeFound) {\n                    break;\n                }\n            }\n        }\n\n        // Try to guess a better error message using common API error formats\n        // The MIME type isn't explicitly checked because some formats inherit from others\n        // Ex: JSON:API follows RFC 7807 semantics, Hydra can be used in any JSON-LD-compatible format\n        if ($isJson && $body = json_decode($response->getContent(false), true)) {\n            if (isset($body['hydra:title']) || isset($body['hydra:description'])) {\n                // see http://www.hydra-cg.com/spec/latest/core/#description-of-http-status-codes-and-errors\n                $separator = isset($body['hydra:title'], $body['hydra:description']) ? \"\\n\\n\" : '';\n                $message = ($body['hydra:title'] ?? '').$separator.($body['hydra:description'] ?? '');\n            } elseif ((isset($body['title']) || isset($body['detail']))\n                && (\\is_scalar($body['title'] ?? '') && \\is_scalar($body['detail'] ?? ''))) {\n                // see RFC 7807 and https://jsonapi.org/format/#error-objects\n                $separator = isset($body['title'], $body['detail']) ? \"\\n\\n\" : '';\n                $message = ($body['title'] ?? '').$separator.($body['detail'] ?? '');\n            }\n        }\n\n        parent::__construct($message, $code);\n    }\n\n    public function getResponse(): ResponseInterface\n    {\n        return $this->response;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/Exception/InvalidArgumentException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient\\Exception;\n\nuse Symfony\\Contracts\\HttpClient\\Exception\\TransportExceptionInterface;\n\n/**\n * @author Nicolas Grekas <p@tchwork.com>\n */\nfinal class InvalidArgumentException extends \\InvalidArgumentException implements TransportExceptionInterface\n{\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/Exception/JsonException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient\\Exception;\n\nuse Symfony\\Contracts\\HttpClient\\Exception\\DecodingExceptionInterface;\n\n/**\n * Thrown by responses' toArray() method when their content cannot be JSON-decoded.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n */\nfinal class JsonException extends \\JsonException implements DecodingExceptionInterface\n{\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/Exception/RedirectionException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient\\Exception;\n\nuse Symfony\\Contracts\\HttpClient\\Exception\\RedirectionExceptionInterface;\n\n/**\n * Represents a 3xx response.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n */\nfinal class RedirectionException extends \\RuntimeException implements RedirectionExceptionInterface\n{\n    use HttpExceptionTrait;\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/Exception/ServerException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient\\Exception;\n\nuse Symfony\\Contracts\\HttpClient\\Exception\\ServerExceptionInterface;\n\n/**\n * Represents a 5xx response.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n */\nfinal class ServerException extends \\RuntimeException implements ServerExceptionInterface\n{\n    use HttpExceptionTrait;\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/Exception/TimeoutException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient\\Exception;\n\nuse Symfony\\Contracts\\HttpClient\\Exception\\TimeoutExceptionInterface;\n\n/**\n * @author Nicolas Grekas <p@tchwork.com>\n */\nfinal class TimeoutException extends TransportException implements TimeoutExceptionInterface\n{\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/Exception/TransportException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient\\Exception;\n\nuse Symfony\\Contracts\\HttpClient\\Exception\\TransportExceptionInterface;\n\n/**\n * @author Nicolas Grekas <p@tchwork.com>\n */\nclass TransportException extends \\RuntimeException implements TransportExceptionInterface\n{\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/HttpClient.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient;\n\nuse Amp\\Http\\Client\\Connection\\ConnectionLimitingPool;\nuse Amp\\Promise;\nuse Symfony\\Contracts\\HttpClient\\HttpClientInterface;\n\n/**\n * A factory to instantiate the best possible HTTP client for the runtime.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n */\nfinal class HttpClient\n{\n    /**\n     * @param array $defaultOptions     Default request's options\n     * @param int   $maxHostConnections The maximum number of connections to a single host\n     * @param int   $maxPendingPushes   The maximum number of pushed responses to accept in the queue\n     *\n     * @see HttpClientInterface::OPTIONS_DEFAULTS for available options\n     */\n    public static function create(array $defaultOptions = [], int $maxHostConnections = 6, int $maxPendingPushes = 50): HttpClientInterface\n    {\n        if ($amp = class_exists(ConnectionLimitingPool::class) && interface_exists(Promise::class)) {\n            if (!\\extension_loaded('curl')) {\n                return new AmpHttpClient($defaultOptions, null, $maxHostConnections, $maxPendingPushes);\n            }\n\n            // Skip curl when HTTP/2 push is unsupported or buggy, see https://bugs.php.net/77535\n            if (!\\defined('CURLMOPT_PUSHFUNCTION')) {\n                return new AmpHttpClient($defaultOptions, null, $maxHostConnections, $maxPendingPushes);\n            }\n\n            static $curlVersion = null;\n            $curlVersion ??= curl_version();\n\n            // HTTP/2 push crashes before curl 7.61\n            if (0x073D00 > $curlVersion['version_number'] || !(\\CURL_VERSION_HTTP2 & $curlVersion['features'])) {\n                return new AmpHttpClient($defaultOptions, null, $maxHostConnections, $maxPendingPushes);\n            }\n        }\n\n        if (\\extension_loaded('curl')) {\n            if ('\\\\' !== \\DIRECTORY_SEPARATOR || isset($defaultOptions['cafile']) || isset($defaultOptions['capath']) || \\ini_get('curl.cainfo') || \\ini_get('openssl.cafile') || \\ini_get('openssl.capath')) {\n                return new CurlHttpClient($defaultOptions, $maxHostConnections, $maxPendingPushes);\n            }\n\n            @trigger_error('Configure the \"curl.cainfo\", \"openssl.cafile\" or \"openssl.capath\" php.ini setting to enable the CurlHttpClient', \\E_USER_WARNING);\n        }\n\n        if ($amp) {\n            return new AmpHttpClient($defaultOptions, null, $maxHostConnections, $maxPendingPushes);\n        }\n\n        @trigger_error((\\extension_loaded('curl') ? 'Upgrade' : 'Install').' the curl extension or run \"composer require amphp/http-client:^4.2.1\" to perform async HTTP operations, including full HTTP/2 support', \\E_USER_NOTICE);\n\n        return new NativeHttpClient($defaultOptions, $maxHostConnections);\n    }\n\n    /**\n     * Creates a client that adds options (e.g. authentication headers) only when the request URL matches the provided base URI.\n     */\n    public static function createForBaseUri(string $baseUri, array $defaultOptions = [], int $maxHostConnections = 6, int $maxPendingPushes = 50): HttpClientInterface\n    {\n        $client = self::create([], $maxHostConnections, $maxPendingPushes);\n\n        return ScopingHttpClient::forBaseUri($client, $baseUri, $defaultOptions);\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/HttpClientTrait.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient;\n\nuse Symfony\\Component\\HttpClient\\Exception\\InvalidArgumentException;\nuse Symfony\\Component\\HttpClient\\Exception\\TransportException;\nuse Symfony\\Component\\HttpClient\\Response\\StreamableInterface;\nuse Symfony\\Component\\HttpClient\\Response\\StreamWrapper;\nuse Symfony\\Component\\Mime\\MimeTypes;\nuse Symfony\\Contracts\\HttpClient\\HttpClientInterface;\n\n/**\n * Provides the common logic from writing HttpClientInterface implementations.\n *\n * All private methods are static to prevent implementers from creating memory leaks via circular references.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n */\ntrait HttpClientTrait\n{\n    private static int $CHUNK_SIZE = 16372;\n\n    public function withOptions(array $options): static\n    {\n        $clone = clone $this;\n        $clone->defaultOptions = self::mergeDefaultOptions($options, $this->defaultOptions);\n\n        return $clone;\n    }\n\n    /**\n     * Validates and normalizes method, URL and options, and merges them with defaults.\n     *\n     * @throws InvalidArgumentException When a not-supported option is found\n     */\n    private static function prepareRequest(?string $method, ?string $url, array $options, array $defaultOptions = [], bool $allowExtraOptions = false): array\n    {\n        if (null !== $method) {\n            if (\\strlen($method) !== strspn($method, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')) {\n                throw new InvalidArgumentException(\\sprintf('Invalid HTTP method \"%s\", only uppercase letters are accepted.', $method));\n            }\n            if (!$method) {\n                throw new InvalidArgumentException('The HTTP method cannot be empty.');\n            }\n        }\n\n        $options = self::mergeDefaultOptions($options, $defaultOptions, $allowExtraOptions);\n\n        $buffer = $options['buffer'] ?? true;\n\n        if ($buffer instanceof \\Closure) {\n            $options['buffer'] = static function (array $headers) use ($buffer) {\n                if (!\\is_bool($buffer = $buffer($headers))) {\n                    if (!\\is_array($bufferInfo = @stream_get_meta_data($buffer))) {\n                        throw new \\LogicException(\\sprintf('The closure passed as option \"buffer\" must return bool or stream resource, got \"%s\".', get_debug_type($buffer)));\n                    }\n\n                    if (false === strpbrk($bufferInfo['mode'], 'acew+')) {\n                        throw new \\LogicException(\\sprintf('The stream returned by the closure passed as option \"buffer\" must be writeable, got mode \"%s\".', $bufferInfo['mode']));\n                    }\n                }\n\n                return $buffer;\n            };\n        } elseif (!\\is_bool($buffer)) {\n            if (!\\is_array($bufferInfo = @stream_get_meta_data($buffer))) {\n                throw new InvalidArgumentException(\\sprintf('Option \"buffer\" must be bool, stream resource or Closure, \"%s\" given.', get_debug_type($buffer)));\n            }\n\n            if (false === strpbrk($bufferInfo['mode'], 'acew+')) {\n                throw new InvalidArgumentException(\\sprintf('The stream in option \"buffer\" must be writeable, mode \"%s\" given.', $bufferInfo['mode']));\n            }\n        }\n\n        if (isset($options['json'])) {\n            if (isset($options['body']) && '' !== $options['body']) {\n                throw new InvalidArgumentException('Define either the \"json\" or the \"body\" option, setting both is not supported.');\n            }\n            $options['body'] = self::jsonEncode($options['json']);\n            unset($options['json']);\n\n            if (!isset($options['normalized_headers']['content-type'])) {\n                $options['normalized_headers']['content-type'] = ['Content-Type: application/json'];\n            }\n        }\n\n        if (!isset($options['normalized_headers']['accept'])) {\n            $options['normalized_headers']['accept'] = ['Accept: */*'];\n        }\n\n        if (isset($options['body'])) {\n            $options['body'] = self::normalizeBody($options['body'], $options['normalized_headers']);\n\n            if (\\is_string($options['body'])\n                && (string) \\strlen($options['body']) !== substr($h = $options['normalized_headers']['content-length'][0] ?? '', 16)\n                && ('' !== $h || '' !== $options['body'])\n            ) {\n                if ('chunked' === substr($options['normalized_headers']['transfer-encoding'][0] ?? '', \\strlen('Transfer-Encoding: '))) {\n                    unset($options['normalized_headers']['transfer-encoding']);\n                    $options['body'] = self::dechunk($options['body']);\n                }\n\n                $options['normalized_headers']['content-length'] = [substr_replace($h ?: 'Content-Length: ', \\strlen($options['body']), 16)];\n            }\n        }\n\n        if (isset($options['peer_fingerprint'])) {\n            $options['peer_fingerprint'] = self::normalizePeerFingerprint($options['peer_fingerprint']);\n        }\n\n        if (isset($options['crypto_method']) && !\\in_array($options['crypto_method'], [\n            \\STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT,\n            \\STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT,\n            \\STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT,\n            \\STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT,\n        ], true)) {\n            throw new InvalidArgumentException('Option \"crypto_method\" must be one of \"STREAM_CRYPTO_METHOD_TLSv1_*_CLIENT\".');\n        }\n\n        // Validate on_progress\n        if (isset($options['on_progress']) && !\\is_callable($onProgress = $options['on_progress'])) {\n            throw new InvalidArgumentException(\\sprintf('Option \"on_progress\" must be callable, \"%s\" given.', get_debug_type($onProgress)));\n        }\n\n        if (\\is_array($options['auth_basic'] ?? null)) {\n            $count = \\count($options['auth_basic']);\n            if ($count <= 0 || $count > 2) {\n                throw new InvalidArgumentException(\\sprintf('Option \"auth_basic\" must contain 1 or 2 elements, \"%s\" given.', $count));\n            }\n\n            $options['auth_basic'] = implode(':', $options['auth_basic']);\n        }\n\n        if (!\\is_string($options['auth_basic'] ?? '')) {\n            throw new InvalidArgumentException(\\sprintf('Option \"auth_basic\" must be string or an array, \"%s\" given.', get_debug_type($options['auth_basic'])));\n        }\n\n        if (isset($options['auth_bearer'])) {\n            if (!\\is_string($options['auth_bearer'])) {\n                throw new InvalidArgumentException(\\sprintf('Option \"auth_bearer\" must be a string, \"%s\" given.', get_debug_type($options['auth_bearer'])));\n            }\n            if (preg_match('{[^\\x21-\\x7E]}', $options['auth_bearer'])) {\n                throw new InvalidArgumentException('Invalid character found in option \"auth_bearer\": '.json_encode($options['auth_bearer']).'.');\n            }\n        }\n\n        if (isset($options['auth_basic'], $options['auth_bearer'])) {\n            throw new InvalidArgumentException('Define either the \"auth_basic\" or the \"auth_bearer\" option, setting both is not supported.');\n        }\n\n        if (null !== $url) {\n            // Merge auth with headers\n            if (($options['auth_basic'] ?? false) && !($options['normalized_headers']['authorization'] ?? false)) {\n                $options['normalized_headers']['authorization'] = ['Authorization: Basic '.base64_encode($options['auth_basic'])];\n            }\n            // Merge bearer with headers\n            if (($options['auth_bearer'] ?? false) && !($options['normalized_headers']['authorization'] ?? false)) {\n                $options['normalized_headers']['authorization'] = ['Authorization: Bearer '.$options['auth_bearer']];\n            }\n\n            unset($options['auth_basic'], $options['auth_bearer']);\n\n            // Parse base URI\n            if (\\is_string($options['base_uri'])) {\n                $options['base_uri'] = self::parseUrl($options['base_uri']);\n            }\n\n            // Validate and resolve URL\n            $url = self::parseUrl($url, $options['query']);\n            $url = self::resolveUrl($url, $options['base_uri'], $defaultOptions['query'] ?? []);\n        }\n\n        // Finalize normalization of options\n        $options['http_version'] = (string) ($options['http_version'] ?? '') ?: null;\n        if (0 > $options['timeout'] = (float) ($options['timeout'] ?? \\ini_get('default_socket_timeout'))) {\n            $options['timeout'] = 172800.0; // 2 days\n        }\n\n        $options['max_duration'] = isset($options['max_duration']) ? (float) $options['max_duration'] : 0;\n        $options['headers'] = array_merge(...array_values($options['normalized_headers']));\n\n        return [$url, $options];\n    }\n\n    /**\n     * @throws InvalidArgumentException When an invalid option is found\n     */\n    private static function mergeDefaultOptions(array $options, array $defaultOptions, bool $allowExtraOptions = false): array\n    {\n        $options['normalized_headers'] = self::normalizeHeaders($options['headers'] ?? []);\n\n        if ($defaultOptions['headers'] ?? false) {\n            $options['normalized_headers'] += self::normalizeHeaders($defaultOptions['headers']);\n        }\n\n        $options['headers'] = array_merge(...array_values($options['normalized_headers']) ?: [[]]);\n\n        if ($resolve = $options['resolve'] ?? false) {\n            $options['resolve'] = [];\n            foreach ($resolve as $k => $v) {\n                if ('' === $v = (string) $v) {\n                    $v = null;\n                } elseif ('[' === $v[0] && ']' === substr($v, -1) && str_contains($v, ':')) {\n                    $v = substr($v, 1, -1);\n                }\n\n                $options['resolve'][substr(self::parseUrl('http://'.$k)['authority'], 2)] = $v;\n            }\n        }\n\n        // Option \"query\" is never inherited from defaults\n        $options['query'] ??= [];\n\n        $options += $defaultOptions;\n\n        if (isset(self::$emptyDefaults)) {\n            foreach (self::$emptyDefaults as $k => $v) {\n                if (!isset($options[$k])) {\n                    $options[$k] = $v;\n                }\n            }\n        }\n\n        if (isset($defaultOptions['extra'])) {\n            $options['extra'] += $defaultOptions['extra'];\n        }\n\n        if ($resolve = $defaultOptions['resolve'] ?? false) {\n            foreach ($resolve as $k => $v) {\n                if ('' === $v = (string) $v) {\n                    $v = null;\n                } elseif ('[' === $v[0] && ']' === substr($v, -1) && str_contains($v, ':')) {\n                    $v = substr($v, 1, -1);\n                }\n\n                $options['resolve'] += [substr(self::parseUrl('http://'.$k)['authority'], 2) => $v];\n            }\n        }\n\n        if ($allowExtraOptions || !$defaultOptions) {\n            return $options;\n        }\n\n        // Look for unsupported options\n        foreach ($options as $name => $v) {\n            if (\\array_key_exists($name, $defaultOptions) || 'normalized_headers' === $name) {\n                continue;\n            }\n\n            if ('auth_ntlm' === $name) {\n                if (!\\extension_loaded('curl')) {\n                    $msg = 'try installing the \"curl\" extension to use \"%s\" instead.';\n                } else {\n                    $msg = 'try using \"%s\" instead.';\n                }\n\n                throw new InvalidArgumentException(\\sprintf('Option \"auth_ntlm\" is not supported by \"%s\", '.$msg, __CLASS__, CurlHttpClient::class));\n            }\n\n            if ('vars' === $name) {\n                throw new InvalidArgumentException(\\sprintf('Option \"vars\" is not supported by \"%s\", try using \"%s\" instead.', __CLASS__, UriTemplateHttpClient::class));\n            }\n\n            $alternatives = [];\n\n            foreach ($defaultOptions as $k => $v) {\n                if (levenshtein($name, $k) <= \\strlen($name) / 3 || str_contains($k, $name)) {\n                    $alternatives[] = $k;\n                }\n            }\n\n            throw new InvalidArgumentException(\\sprintf('Unsupported option \"%s\" passed to \"%s\", did you mean \"%s\"?', $name, __CLASS__, implode('\", \"', $alternatives ?: array_keys($defaultOptions))));\n        }\n\n        return $options;\n    }\n\n    /**\n     * @return string[][]\n     *\n     * @throws InvalidArgumentException When an invalid header is found\n     */\n    private static function normalizeHeaders(array $headers): array\n    {\n        $normalizedHeaders = [];\n\n        foreach ($headers as $name => $values) {\n            if ($values instanceof \\Stringable) {\n                $values = (string) $values;\n            }\n\n            if (\\is_int($name)) {\n                if (!\\is_string($values)) {\n                    throw new InvalidArgumentException(\\sprintf('Invalid value for header \"%s\": expected string, \"%s\" given.', $name, get_debug_type($values)));\n                }\n                [$name, $values] = explode(':', $values, 2);\n                $values = [ltrim($values)];\n            } elseif (!is_iterable($values)) {\n                if (\\is_object($values)) {\n                    throw new InvalidArgumentException(\\sprintf('Invalid value for header \"%s\": expected string, \"%s\" given.', $name, get_debug_type($values)));\n                }\n\n                $values = (array) $values;\n            }\n\n            $lcName = strtolower($name);\n            $normalizedHeaders[$lcName] = [];\n\n            foreach ($values as $value) {\n                $normalizedHeaders[$lcName][] = $value = $name.': '.$value;\n\n                if (\\strlen($value) !== strcspn($value, \"\\r\\n\\0\")) {\n                    throw new InvalidArgumentException(\\sprintf('Invalid header: CR/LF/NUL found in \"%s\".', $value));\n                }\n            }\n        }\n\n        return $normalizedHeaders;\n    }\n\n    /**\n     * @param array|string|resource|\\Traversable|\\Closure $body\n     *\n     * @return string|resource|\\Closure\n     *\n     * @throws InvalidArgumentException When an invalid body is passed\n     */\n    private static function normalizeBody($body, array &$normalizedHeaders = [])\n    {\n        if (\\is_array($body)) {\n            static $cookie;\n\n            $streams = [];\n            array_walk_recursive($body, $caster = static function (&$v) use (&$caster, &$streams, &$cookie) {\n                if (\\is_resource($v) || $v instanceof StreamableInterface) {\n                    $cookie = hash('xxh128', $cookie ??= random_bytes(8), true);\n                    $k = substr(strtr(base64_encode($cookie), '+/', '-_'), 0, -2);\n                    $streams[$k] = $v instanceof StreamableInterface ? $v->toStream(false) : $v;\n                    $v = $k;\n                } elseif (\\is_object($v)) {\n                    if ($vars = get_object_vars($v)) {\n                        array_walk_recursive($vars, $caster);\n                        $v = $vars;\n                    } elseif ($v instanceof \\Stringable) {\n                        $v = (string) $v;\n                    }\n                }\n            });\n\n            if ('' === $body = http_build_query($body, '', '&')) {\n                return '';\n            }\n\n            if (!$streams && !str_contains($normalizedHeaders['content-type'][0] ?? '', 'multipart/form-data')) {\n                if (!str_contains($normalizedHeaders['content-type'][0] ?? '', 'application/x-www-form-urlencoded')) {\n                    $normalizedHeaders['content-type'] = ['Content-Type: application/x-www-form-urlencoded'];\n                }\n\n                return $body;\n            }\n\n            if (preg_match('{multipart/form-data; boundary=(?|\"([^\"\\r\\n]++)\"|([-!#$%&\\'*+.^_`|~_A-Za-z0-9]++))}', $normalizedHeaders['content-type'][0] ?? '', $boundary)) {\n                $boundary = $boundary[1];\n            } else {\n                $boundary = substr(strtr(base64_encode($cookie ??= random_bytes(8)), '+/', '-_'), 0, -2);\n                $normalizedHeaders['content-type'] = ['Content-Type: multipart/form-data; boundary='.$boundary];\n            }\n\n            $body = explode('&', $body);\n            $contentLength = 0;\n\n            foreach ($body as $i => $part) {\n                [$k, $v] = explode('=', $part, 2);\n                $part = ($i ? \"\\r\\n\" : '').\"--{$boundary}\\r\\n\";\n                $k = str_replace(['\"', \"\\r\", \"\\n\"], ['%22', '%0D', '%0A'], urldecode($k)); // see WHATWG HTML living standard\n\n                if (!isset($streams[$v])) {\n                    $part .= \"Content-Disposition: form-data; name=\\\"{$k}\\\"\\r\\n\\r\\n\".urldecode($v);\n                    $contentLength += 0 <= $contentLength ? \\strlen($part) : 0;\n                    $body[$i] = [$k, $part, null];\n                    continue;\n                }\n                $v = $streams[$v];\n\n                if (!\\is_array($m = @stream_get_meta_data($v))) {\n                    throw new TransportException(\\sprintf('Invalid \"%s\" resource found in body part \"%s\".', get_resource_type($v), $k));\n                }\n                if (feof($v)) {\n                    throw new TransportException(\\sprintf('Uploaded stream ended for body part \"%s\".', $k));\n                }\n\n                $m += stream_context_get_options($v)['http'] ?? [];\n                $filename = basename($m['filename'] ?? $m['uri'] ?? 'unknown');\n                $filename = str_replace(['\"', \"\\r\", \"\\n\"], ['%22', '%0D', '%0A'], $filename);\n                $contentType = $m['content_type'] ?? null;\n\n                if (($headers = $m['wrapper_data'] ?? []) instanceof StreamWrapper) {\n                    $hasContentLength = false;\n                    $headers = $headers->getResponse()->getInfo('response_headers');\n                } elseif ($hasContentLength = 0 < $h = fstat($v)['size'] ?? 0) {\n                    $contentLength += 0 <= $contentLength ? $h : 0;\n                }\n\n                foreach (\\is_array($headers) ? $headers : [] as $h) {\n                    if (\\is_string($h) && 0 === stripos($h, 'Content-Type: ')) {\n                        $contentType ??= substr($h, 14);\n                    } elseif (!$hasContentLength && \\is_string($h) && 0 === stripos($h, 'Content-Length: ')) {\n                        $hasContentLength = true;\n                        $contentLength += 0 <= $contentLength ? substr($h, 16) : 0;\n                    } elseif (\\is_string($h) && 0 === stripos($h, 'Content-Encoding: ')) {\n                        $contentLength = -1;\n                    }\n                }\n\n                if (!$hasContentLength) {\n                    $contentLength = -1;\n                }\n                if (null === $contentType && 'plainfile' === ($m['wrapper_type'] ?? null) && isset($m['uri'])) {\n                    $mimeTypes = class_exists(MimeTypes::class) ? MimeTypes::getDefault() : false;\n                    $contentType = $mimeTypes ? $mimeTypes->guessMimeType($m['uri']) : null;\n                }\n                $contentType ??= 'application/octet-stream';\n\n                $part .= \"Content-Disposition: form-data; name=\\\"{$k}\\\"; filename=\\\"{$filename}\\\"\\r\\n\";\n                $part .= \"Content-Type: {$contentType}\\r\\n\\r\\n\";\n\n                $contentLength += 0 <= $contentLength ? \\strlen($part) : 0;\n                $body[$i] = [$k, $part, $v];\n            }\n\n            $body[++$i] = ['', \"\\r\\n--{$boundary}--\\r\\n\", null];\n\n            if (0 < $contentLength) {\n                $normalizedHeaders['content-length'] = ['Content-Length: '.($contentLength += \\strlen($body[$i][1]))];\n            }\n\n            $body = static function ($size) use ($body) {\n                foreach ($body as $i => [$k, $part, $h]) {\n                    unset($body[$i]);\n\n                    yield $part;\n\n                    while (null !== $h && !feof($h)) {\n                        if (false === $part = fread($h, $size)) {\n                            throw new TransportException(\\sprintf('Error while reading uploaded stream for body part \"%s\".', $k));\n                        }\n\n                        yield $part;\n                    }\n                }\n                $h = null;\n            };\n        }\n\n        if (\\is_string($body)) {\n            return $body;\n        }\n\n        $generatorToCallable = static fn (\\Generator $body): \\Closure => static function () use ($body) {\n            while ($body->valid()) {\n                $chunk = $body->current();\n                $body->next();\n\n                if ('' !== $chunk) {\n                    return $chunk;\n                }\n            }\n\n            return '';\n        };\n\n        if ($body instanceof \\Generator) {\n            return $generatorToCallable($body);\n        }\n\n        if ($body instanceof \\Traversable) {\n            return $generatorToCallable((static function ($body) { yield from $body; })($body));\n        }\n\n        if ($body instanceof \\Closure) {\n            $r = new \\ReflectionFunction($body);\n            $body = $r->getClosure();\n\n            if ($r->isGenerator()) {\n                $body = $body(self::$CHUNK_SIZE);\n\n                return $generatorToCallable($body);\n            }\n\n            return $body;\n        }\n\n        if (!\\is_array(@stream_get_meta_data($body))) {\n            throw new InvalidArgumentException(\\sprintf('Option \"body\" must be string, stream resource, iterable or callable, \"%s\" given.', get_debug_type($body)));\n        }\n\n        return $body;\n    }\n\n    private static function dechunk(string $body): string\n    {\n        $h = fopen('php://temp', 'w+');\n        stream_filter_append($h, 'dechunk', \\STREAM_FILTER_WRITE);\n        fwrite($h, $body);\n        $body = stream_get_contents($h, -1, 0);\n        rewind($h);\n        ftruncate($h, 0);\n\n        if (fwrite($h, '-') && '' !== stream_get_contents($h, -1, 0)) {\n            throw new TransportException('Request body has broken chunked encoding.');\n        }\n\n        return $body;\n    }\n\n    /**\n     * @throws InvalidArgumentException When an invalid fingerprint is passed\n     */\n    private static function normalizePeerFingerprint(mixed $fingerprint): array\n    {\n        if (\\is_string($fingerprint)) {\n            $fingerprint = match (\\strlen($fingerprint = str_replace(':', '', $fingerprint))) {\n                32 => ['md5' => $fingerprint],\n                40 => ['sha1' => $fingerprint],\n                44 => ['pin-sha256' => [$fingerprint]],\n                64 => ['sha256' => $fingerprint],\n                default => throw new InvalidArgumentException(\\sprintf('Cannot auto-detect fingerprint algorithm for \"%s\".', $fingerprint)),\n            };\n        } elseif (\\is_array($fingerprint)) {\n            foreach ($fingerprint as $algo => $hash) {\n                $fingerprint[$algo] = 'pin-sha256' === $algo ? (array) $hash : str_replace(':', '', $hash);\n            }\n        } else {\n            throw new InvalidArgumentException(\\sprintf('Option \"peer_fingerprint\" must be string or array, \"%s\" given.', get_debug_type($fingerprint)));\n        }\n\n        return $fingerprint;\n    }\n\n    /**\n     * @throws InvalidArgumentException When the value cannot be json-encoded\n     */\n    private static function jsonEncode(mixed $value, ?int $flags = null, int $maxDepth = 512): string\n    {\n        $flags ??= \\JSON_HEX_TAG | \\JSON_HEX_APOS | \\JSON_HEX_AMP | \\JSON_HEX_QUOT | \\JSON_PRESERVE_ZERO_FRACTION;\n\n        try {\n            $value = json_encode($value, $flags | \\JSON_THROW_ON_ERROR, $maxDepth);\n        } catch (\\JsonException $e) {\n            throw new InvalidArgumentException('Invalid value for \"json\" option: '.$e->getMessage());\n        }\n\n        return $value;\n    }\n\n    /**\n     * Resolves a URL against a base URI.\n     *\n     * @see https://tools.ietf.org/html/rfc3986#section-5.2.2\n     *\n     * @throws InvalidArgumentException When an invalid URL is passed\n     */\n    private static function resolveUrl(array $url, ?array $base, array $queryDefaults = []): array\n    {\n        $givenUrl = $url;\n\n        if (null !== $base && '' === ($base['scheme'] ?? '').($base['authority'] ?? '')) {\n            throw new InvalidArgumentException(\\sprintf('Invalid \"base_uri\" option: host or scheme is missing in \"%s\".', implode('', $base)));\n        }\n\n        if (null === $url['scheme'] && (null === $base || null === $base['scheme'])) {\n            throw new InvalidArgumentException(\\sprintf('Invalid URL: scheme is missing in \"%s\". Did you forget to add \"http(s)://\"?', implode('', $base ?? $url)));\n        }\n\n        if (null === $base && '' === $url['scheme'].$url['authority']) {\n            throw new InvalidArgumentException(\\sprintf('Invalid URL: no \"base_uri\" option was provided and host or scheme is missing in \"%s\".', implode('', $url)));\n        }\n\n        if (null !== $url['scheme']) {\n            $url['path'] = self::removeDotSegments($url['path'] ?? '');\n        } else {\n            if (null !== $url['authority']) {\n                $url['path'] = self::removeDotSegments($url['path'] ?? '');\n            } else {\n                if (null === $url['path']) {\n                    $url['path'] = $base['path'];\n                    $url['query'] ??= $base['query'];\n                } else {\n                    if ('/' !== $url['path'][0]) {\n                        if (null === $base['path']) {\n                            $url['path'] = '/'.$url['path'];\n                        } else {\n                            $segments = explode('/', $base['path']);\n                            array_splice($segments, -1, 1, [$url['path']]);\n                            $url['path'] = implode('/', $segments);\n                        }\n                    }\n\n                    $url['path'] = self::removeDotSegments($url['path']);\n                }\n\n                $url['authority'] = $base['authority'];\n\n                if ($queryDefaults) {\n                    $url['query'] = '?'.self::mergeQueryString(substr($url['query'] ?? '', 1), $queryDefaults, false);\n                }\n            }\n\n            $url['scheme'] = $base['scheme'];\n        }\n\n        if ('' === ($url['path'] ?? '')) {\n            $url['path'] = '/';\n        }\n\n        if ('?' === ($url['query'] ?? '')) {\n            $url['query'] = null;\n        }\n\n        if (null !== $url['scheme'] && null === $url['authority']) {\n            throw new InvalidArgumentException(\\sprintf('Invalid URL: host is missing in \"%s\".', implode('', $givenUrl)));\n        }\n\n        return $url;\n    }\n\n    /**\n     * Parses a URL and fixes its encoding if needed.\n     *\n     * @throws InvalidArgumentException When an invalid URL is passed\n     */\n    private static function parseUrl(string $url, array $query = [], array $allowedSchemes = ['http' => 80, 'https' => 443]): array\n    {\n        $tail = '';\n\n        if (false === $parts = parse_url(\\strlen($url) !== strcspn($url, '?#') ? $url : $url.$tail = '#')) {\n            throw new InvalidArgumentException(\\sprintf('Malformed URL \"%s\".', $url));\n        }\n\n        if ($query) {\n            $parts['query'] = self::mergeQueryString($parts['query'] ?? null, $query, true);\n        }\n\n        $scheme = $parts['scheme'] ?? null;\n        $host = $parts['host'] ?? null;\n\n        if (!$scheme && $host && !str_starts_with($url, '//')) {\n            $parts = parse_url(':/'.$url.$tail);\n            $parts['path'] = substr($parts['path'], 2);\n            $scheme = $host = null;\n        }\n\n        $port = $parts['port'] ?? 0;\n\n        if (null !== $scheme) {\n            if (!isset($allowedSchemes[$scheme = strtolower($scheme)])) {\n                throw new InvalidArgumentException(\\sprintf('Unsupported scheme in \"%s\": \"%s\" expected.', $url, implode('\" or \"', array_keys($allowedSchemes))));\n            }\n\n            $port = $allowedSchemes[$scheme] === $port ? 0 : $port;\n            $scheme .= ':';\n        }\n\n        if (null !== $host) {\n            if (!\\defined('INTL_IDNA_VARIANT_UTS46') && preg_match('/[\\x80-\\xFF]/', $host)) {\n                throw new InvalidArgumentException(\\sprintf('Unsupported IDN \"%s\", try enabling the \"intl\" PHP extension or running \"composer require symfony/polyfill-intl-idn\".', $host));\n            }\n\n            $host = \\defined('INTL_IDNA_VARIANT_UTS46') ? idn_to_ascii($host, \\IDNA_DEFAULT | \\IDNA_USE_STD3_RULES | \\IDNA_CHECK_BIDI | \\IDNA_CHECK_CONTEXTJ | \\IDNA_NONTRANSITIONAL_TO_ASCII, \\INTL_IDNA_VARIANT_UTS46) ?: strtolower($host) : strtolower($host);\n            $host .= $port ? ':'.$port : '';\n        }\n\n        foreach (['user', 'pass', 'path', 'query', 'fragment'] as $part) {\n            if (!isset($parts[$part])) {\n                continue;\n            }\n\n            if (str_contains($parts[$part], '%')) {\n                // https://tools.ietf.org/html/rfc3986#section-2.3\n                $parts[$part] = preg_replace_callback('/%(?:2[DE]|3[0-9]|[46][1-9A-F]|5F|[57][0-9A]|7E)++/i', fn ($m) => rawurldecode($m[0]), $parts[$part]);\n            }\n\n            // https://tools.ietf.org/html/rfc3986#section-3.3\n            $parts[$part] = preg_replace_callback(\"#[^-A-Za-z0-9._~!$&/'()[\\]*+,;=:@{}%]++#\", fn ($m) => rawurlencode($m[0]), $parts[$part]);\n        }\n\n        return [\n            'scheme' => $scheme,\n            'authority' => null !== $host ? '//'.(isset($parts['user']) ? $parts['user'].(isset($parts['pass']) ? ':'.$parts['pass'] : '').'@' : '').$host : null,\n            'path' => isset($parts['path'][0]) ? $parts['path'] : null,\n            'query' => isset($parts['query']) ? '?'.$parts['query'] : null,\n            'fragment' => isset($parts['fragment']) && !$tail ? '#'.$parts['fragment'] : null,\n        ];\n    }\n\n    /**\n     * Removes dot-segments from a path.\n     *\n     * @see https://tools.ietf.org/html/rfc3986#section-5.2.4\n     *\n     * @return string\n     */\n    private static function removeDotSegments(string $path)\n    {\n        $result = '';\n\n        while (!\\in_array($path, ['', '.', '..'], true)) {\n            if ('.' === $path[0] && (str_starts_with($path, $p = '../') || str_starts_with($path, $p = './'))) {\n                $path = substr($path, \\strlen($p));\n            } elseif ('/.' === $path || str_starts_with($path, '/./')) {\n                $path = substr_replace($path, '/', 0, 3);\n            } elseif ('/..' === $path || str_starts_with($path, '/../')) {\n                $i = strrpos($result, '/');\n                $result = $i ? substr($result, 0, $i) : '';\n                $path = substr_replace($path, '/', 0, 4);\n            } else {\n                $i = strpos($path, '/', 1) ?: \\strlen($path);\n                $result .= substr($path, 0, $i);\n                $path = substr($path, $i);\n            }\n        }\n\n        return $result;\n    }\n\n    /**\n     * Merges and encodes a query array with a query string.\n     *\n     * @throws InvalidArgumentException When an invalid query-string value is passed\n     */\n    private static function mergeQueryString(?string $queryString, array $queryArray, bool $replace): ?string\n    {\n        if (!$queryArray) {\n            return $queryString;\n        }\n\n        $query = [];\n\n        if (null !== $queryString) {\n            foreach (explode('&', $queryString) as $v) {\n                if ('' !== $v) {\n                    $k = urldecode(explode('=', $v, 2)[0]);\n                    $query[$k] = (isset($query[$k]) ? $query[$k].'&' : '').$v;\n                }\n            }\n        }\n\n        if ($replace) {\n            foreach ($queryArray as $k => $v) {\n                if (null === $v) {\n                    unset($query[$k]);\n                }\n            }\n        }\n\n        $queryString = http_build_query($queryArray, '', '&', \\PHP_QUERY_RFC3986);\n        $queryArray = [];\n\n        if ($queryString) {\n            if (str_contains($queryString, '%')) {\n                // https://tools.ietf.org/html/rfc3986#section-2.3 + some chars not encoded by browsers\n                $queryString = strtr($queryString, [\n                    '%21' => '!',\n                    '%24' => '$',\n                    '%28' => '(',\n                    '%29' => ')',\n                    '%2A' => '*',\n                    '%2F' => '/',\n                    '%3A' => ':',\n                    '%3B' => ';',\n                    '%40' => '@',\n                    '%5B' => '[',\n                    '%5D' => ']',\n                ]);\n            }\n\n            foreach (explode('&', $queryString) as $v) {\n                $queryArray[rawurldecode(explode('=', $v, 2)[0])] = $v;\n            }\n        }\n\n        return implode('&', $replace ? array_replace($query, $queryArray) : ($query + $queryArray));\n    }\n\n    /**\n     * Loads proxy configuration from the same environment variables as curl when no proxy is explicitly set.\n     */\n    private static function getProxy(?string $proxy, array $url, ?string $noProxy): ?array\n    {\n        if (null === $proxy = self::getProxyUrl($proxy, $url)) {\n            return null;\n        }\n\n        $proxy = (parse_url($proxy) ?: []) + ['scheme' => 'http'];\n\n        if (!isset($proxy['host'])) {\n            throw new TransportException('Invalid HTTP proxy: host is missing.');\n        }\n\n        if ('http' === $proxy['scheme']) {\n            $proxyUrl = 'tcp://'.$proxy['host'].':'.($proxy['port'] ?? '80');\n        } elseif ('https' === $proxy['scheme']) {\n            $proxyUrl = 'ssl://'.$proxy['host'].':'.($proxy['port'] ?? '443');\n        } else {\n            throw new TransportException(\\sprintf('Unsupported proxy scheme \"%s\": \"http\" or \"https\" expected.', $proxy['scheme']));\n        }\n\n        $noProxy ??= $_SERVER['no_proxy'] ?? $_SERVER['NO_PROXY'] ?? '';\n        $noProxy = $noProxy ? preg_split('/[\\s,]+/', $noProxy) : [];\n\n        return [\n            'url' => $proxyUrl,\n            'auth' => isset($proxy['user']) ? 'Basic '.base64_encode(rawurldecode($proxy['user']).':'.rawurldecode($proxy['pass'] ?? '')) : null,\n            'no_proxy' => $noProxy,\n        ];\n    }\n\n    private static function getProxyUrl(?string $proxy, array $url): ?string\n    {\n        if (null !== $proxy) {\n            return $proxy;\n        }\n\n        // Ignore HTTP_PROXY except on the CLI to work around httpoxy set of vulnerabilities\n        $proxy = $_SERVER['http_proxy'] ?? (\\in_array(\\PHP_SAPI, ['cli', 'phpdbg'], true) ? $_SERVER['HTTP_PROXY'] ?? null : null) ?? $_SERVER['all_proxy'] ?? $_SERVER['ALL_PROXY'] ?? null;\n\n        if ('https:' === $url['scheme']) {\n            $proxy = $_SERVER['https_proxy'] ?? $_SERVER['HTTPS_PROXY'] ?? $proxy;\n        }\n\n        return $proxy;\n    }\n\n    private static function shouldBuffer(array $headers): bool\n    {\n        if (null === $contentType = $headers['content-type'][0] ?? null) {\n            return false;\n        }\n\n        if (false !== $i = strpos($contentType, ';')) {\n            $contentType = substr($contentType, 0, $i);\n        }\n\n        return $contentType && preg_match('#^(?:text/|application/(?:.+\\+)?(?:json|xml)$)#i', $contentType);\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/HttpOptions.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient;\n\nuse Symfony\\Contracts\\HttpClient\\HttpClientInterface;\n\n/**\n * A helper providing autocompletion for available options.\n *\n * @see HttpClientInterface for a description of each options.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n */\nclass HttpOptions\n{\n    private array $options = [];\n\n    public function toArray(): array\n    {\n        return $this->options;\n    }\n\n    /**\n     * @return $this\n     */\n    public function setAuthBasic(string $user, #[\\SensitiveParameter] string $password = ''): static\n    {\n        $this->options['auth_basic'] = $user;\n\n        if ('' !== $password) {\n            $this->options['auth_basic'] .= ':'.$password;\n        }\n\n        return $this;\n    }\n\n    /**\n     * @return $this\n     */\n    public function setAuthBearer(#[\\SensitiveParameter] string $token): static\n    {\n        $this->options['auth_bearer'] = $token;\n\n        return $this;\n    }\n\n    /**\n     * @return $this\n     */\n    public function setQuery(array $query): static\n    {\n        $this->options['query'] = $query;\n\n        return $this;\n    }\n\n    /**\n     * @return $this\n     */\n    public function setHeaders(iterable $headers): static\n    {\n        $this->options['headers'] = $headers;\n\n        return $this;\n    }\n\n    /**\n     * @param array|string|resource|\\Traversable|\\Closure $body\n     *\n     * @return $this\n     */\n    public function setBody(mixed $body): static\n    {\n        $this->options['body'] = $body;\n\n        return $this;\n    }\n\n    /**\n     * @return $this\n     */\n    public function setJson(mixed $json): static\n    {\n        $this->options['json'] = $json;\n\n        return $this;\n    }\n\n    /**\n     * @return $this\n     */\n    public function setUserData(mixed $data): static\n    {\n        $this->options['user_data'] = $data;\n\n        return $this;\n    }\n\n    /**\n     * @return $this\n     */\n    public function setMaxRedirects(int $max): static\n    {\n        $this->options['max_redirects'] = $max;\n\n        return $this;\n    }\n\n    /**\n     * @return $this\n     */\n    public function setHttpVersion(string $version): static\n    {\n        $this->options['http_version'] = $version;\n\n        return $this;\n    }\n\n    /**\n     * @return $this\n     */\n    public function setBaseUri(string $uri): static\n    {\n        $this->options['base_uri'] = $uri;\n\n        return $this;\n    }\n\n    /**\n     * @return $this\n     */\n    public function setVars(array $vars): static\n    {\n        $this->options['vars'] = $vars;\n\n        return $this;\n    }\n\n    /**\n     * @return $this\n     */\n    public function buffer(bool $buffer): static\n    {\n        $this->options['buffer'] = $buffer;\n\n        return $this;\n    }\n\n    /**\n     * @param callable(int, int, array, \\Closure|null=):void $callback\n     *\n     * @return $this\n     */\n    public function setOnProgress(callable $callback): static\n    {\n        $this->options['on_progress'] = $callback;\n\n        return $this;\n    }\n\n    /**\n     * @return $this\n     */\n    public function resolve(array $hostIps): static\n    {\n        $this->options['resolve'] = $hostIps;\n\n        return $this;\n    }\n\n    /**\n     * @return $this\n     */\n    public function setProxy(string $proxy): static\n    {\n        $this->options['proxy'] = $proxy;\n\n        return $this;\n    }\n\n    /**\n     * @return $this\n     */\n    public function setNoProxy(string $noProxy): static\n    {\n        $this->options['no_proxy'] = $noProxy;\n\n        return $this;\n    }\n\n    /**\n     * @return $this\n     */\n    public function setTimeout(float $timeout): static\n    {\n        $this->options['timeout'] = $timeout;\n\n        return $this;\n    }\n\n    /**\n     * @return $this\n     */\n    public function setMaxDuration(float $maxDuration): static\n    {\n        $this->options['max_duration'] = $maxDuration;\n\n        return $this;\n    }\n\n    /**\n     * @return $this\n     */\n    public function bindTo(string $bindto): static\n    {\n        $this->options['bindto'] = $bindto;\n\n        return $this;\n    }\n\n    /**\n     * @return $this\n     */\n    public function verifyPeer(bool $verify): static\n    {\n        $this->options['verify_peer'] = $verify;\n\n        return $this;\n    }\n\n    /**\n     * @return $this\n     */\n    public function verifyHost(bool $verify): static\n    {\n        $this->options['verify_host'] = $verify;\n\n        return $this;\n    }\n\n    /**\n     * @return $this\n     */\n    public function setCaFile(string $cafile): static\n    {\n        $this->options['cafile'] = $cafile;\n\n        return $this;\n    }\n\n    /**\n     * @return $this\n     */\n    public function setCaPath(string $capath): static\n    {\n        $this->options['capath'] = $capath;\n\n        return $this;\n    }\n\n    /**\n     * @return $this\n     */\n    public function setLocalCert(string $cert): static\n    {\n        $this->options['local_cert'] = $cert;\n\n        return $this;\n    }\n\n    /**\n     * @return $this\n     */\n    public function setLocalPk(string $pk): static\n    {\n        $this->options['local_pk'] = $pk;\n\n        return $this;\n    }\n\n    /**\n     * @return $this\n     */\n    public function setPassphrase(string $passphrase): static\n    {\n        $this->options['passphrase'] = $passphrase;\n\n        return $this;\n    }\n\n    /**\n     * @return $this\n     */\n    public function setCiphers(string $ciphers): static\n    {\n        $this->options['ciphers'] = $ciphers;\n\n        return $this;\n    }\n\n    /**\n     * @return $this\n     */\n    public function setPeerFingerprint(string|array $fingerprint): static\n    {\n        $this->options['peer_fingerprint'] = $fingerprint;\n\n        return $this;\n    }\n\n    /**\n     * @return $this\n     */\n    public function capturePeerCertChain(bool $capture): static\n    {\n        $this->options['capture_peer_cert_chain'] = $capture;\n\n        return $this;\n    }\n\n    /**\n     * @return $this\n     */\n    public function setExtra(string $name, mixed $value): static\n    {\n        $this->options['extra'][$name] = $value;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/HttplugClient.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient;\n\nuse GuzzleHttp\\Promise\\Promise as GuzzlePromise;\nuse GuzzleHttp\\Promise\\RejectedPromise;\nuse GuzzleHttp\\Promise\\Utils;\nuse Http\\Client\\Exception\\NetworkException;\nuse Http\\Client\\Exception\\RequestException;\nuse Http\\Client\\HttpAsyncClient;\nuse Http\\Discovery\\Psr17Factory;\nuse Http\\Discovery\\Psr17FactoryDiscovery;\nuse Nyholm\\Psr7\\Factory\\Psr17Factory as NyholmPsr17Factory;\nuse Nyholm\\Psr7\\Request;\nuse Nyholm\\Psr7\\Uri;\nuse Psr\\Http\\Client\\ClientInterface;\nuse Psr\\Http\\Message\\RequestFactoryInterface;\nuse Psr\\Http\\Message\\RequestInterface;\nuse Psr\\Http\\Message\\ResponseFactoryInterface;\nuse Psr\\Http\\Message\\ResponseInterface as Psr7ResponseInterface;\nuse Psr\\Http\\Message\\StreamFactoryInterface;\nuse Psr\\Http\\Message\\StreamInterface;\nuse Psr\\Http\\Message\\UriFactoryInterface;\nuse Psr\\Http\\Message\\UriInterface;\nuse Symfony\\Component\\HttpClient\\Internal\\HttplugWaitLoop;\nuse Symfony\\Component\\HttpClient\\Internal\\LegacyHttplugInterface;\nuse Symfony\\Component\\HttpClient\\Response\\HttplugPromise;\nuse Symfony\\Contracts\\HttpClient\\Exception\\TransportExceptionInterface;\nuse Symfony\\Contracts\\HttpClient\\HttpClientInterface;\nuse Symfony\\Contracts\\HttpClient\\ResponseInterface;\nuse Symfony\\Contracts\\Service\\ResetInterface;\n\nif (!interface_exists(HttpAsyncClient::class)) {\n    throw new \\LogicException('You cannot use \"Symfony\\Component\\HttpClient\\HttplugClient\" as the \"php-http/httplug\" package is not installed. Try running \"composer require php-http/discovery php-http/async-client-implementation:*\".');\n}\n\nif (!interface_exists(RequestFactoryInterface::class)) {\n    throw new \\LogicException('You cannot use the \"Symfony\\Component\\HttpClient\\HttplugClient\" as the \"psr/http-factory\" package is not installed. Try running \"composer require php-http/discovery psr/http-factory-implementation:*\".');\n}\n\n/**\n * An adapter to turn a Symfony HttpClientInterface into an Httplug client.\n *\n * In comparison to Psr18Client, this client supports asynchronous requests.\n *\n * Run \"composer require php-http/discovery php-http/async-client-implementation:*\"\n * to get the required dependencies.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n */\nfinal class HttplugClient implements ClientInterface, HttpAsyncClient, RequestFactoryInterface, StreamFactoryInterface, UriFactoryInterface, ResetInterface, LegacyHttplugInterface\n{\n    private HttpClientInterface $client;\n    private ResponseFactoryInterface $responseFactory;\n    private StreamFactoryInterface $streamFactory;\n\n    /**\n     * @var \\SplObjectStorage<ResponseInterface, array{RequestInterface, Promise}>|null\n     */\n    private ?\\SplObjectStorage $promisePool;\n\n    private HttplugWaitLoop $waitLoop;\n\n    public function __construct(?HttpClientInterface $client = null, ?ResponseFactoryInterface $responseFactory = null, ?StreamFactoryInterface $streamFactory = null)\n    {\n        $this->client = $client ?? HttpClient::create();\n        $streamFactory ??= $responseFactory instanceof StreamFactoryInterface ? $responseFactory : null;\n        $this->promisePool = class_exists(Utils::class) ? new \\SplObjectStorage() : null;\n\n        if (null === $responseFactory || null === $streamFactory) {\n            if (class_exists(Psr17Factory::class)) {\n                $psr17Factory = new Psr17Factory();\n            } elseif (class_exists(NyholmPsr17Factory::class)) {\n                $psr17Factory = new NyholmPsr17Factory();\n            } else {\n                throw new \\LogicException('You cannot use the \"Symfony\\Component\\HttpClient\\HttplugClient\" as no PSR-17 factories have been provided. Try running \"composer require php-http/discovery psr/http-factory-implementation:*\".');\n            }\n\n            $responseFactory ??= $psr17Factory;\n            $streamFactory ??= $psr17Factory;\n        }\n\n        $this->responseFactory = $responseFactory;\n        $this->streamFactory = $streamFactory;\n        $this->waitLoop = new HttplugWaitLoop($this->client, $this->promisePool, $this->responseFactory, $this->streamFactory);\n    }\n\n    public function withOptions(array $options): static\n    {\n        $clone = clone $this;\n        $clone->client = $clone->client->withOptions($options);\n\n        return $clone;\n    }\n\n    public function sendRequest(RequestInterface $request): Psr7ResponseInterface\n    {\n        try {\n            return HttplugWaitLoop::createPsr7Response($this->responseFactory, $this->streamFactory, $this->client, $this->sendPsr7Request($request), true);\n        } catch (TransportExceptionInterface $e) {\n            throw new NetworkException($e->getMessage(), $request, $e);\n        }\n    }\n\n    public function sendAsyncRequest(RequestInterface $request): HttplugPromise\n    {\n        if (!$promisePool = $this->promisePool) {\n            throw new \\LogicException(\\sprintf('You cannot use \"%s()\" as the \"guzzlehttp/promises\" package is not installed. Try running \"composer require guzzlehttp/promises\".', __METHOD__));\n        }\n\n        try {\n            $response = $this->sendPsr7Request($request, true);\n        } catch (NetworkException $e) {\n            return new HttplugPromise(new RejectedPromise($e));\n        }\n\n        $waitLoop = $this->waitLoop;\n\n        $promise = new GuzzlePromise(static function () use ($response, $waitLoop) {\n            $waitLoop->wait($response);\n        }, static function () use ($response, $promisePool) {\n            $response->cancel();\n            unset($promisePool[$response]);\n        });\n\n        $promisePool[$response] = [$request, $promise];\n\n        return new HttplugPromise($promise);\n    }\n\n    /**\n     * Resolves pending promises that complete before the timeouts are reached.\n     *\n     * When $maxDuration is null and $idleTimeout is reached, promises are rejected.\n     *\n     * @return int The number of remaining pending promises\n     */\n    public function wait(?float $maxDuration = null, ?float $idleTimeout = null): int\n    {\n        return $this->waitLoop->wait(null, $maxDuration, $idleTimeout);\n    }\n\n    /**\n     * @param string              $method\n     * @param UriInterface|string $uri\n     */\n    public function createRequest($method, $uri, array $headers = [], $body = null, $protocolVersion = '1.1'): RequestInterface\n    {\n        if (2 < \\func_num_args()) {\n            trigger_deprecation('symfony/http-client', '6.2', 'Passing more than 2 arguments to \"%s()\" is deprecated.', __METHOD__);\n        }\n        if ($this->responseFactory instanceof RequestFactoryInterface) {\n            $request = $this->responseFactory->createRequest($method, $uri);\n        } elseif (class_exists(Psr17FactoryDiscovery::class)) {\n            $request = Psr17FactoryDiscovery::findRequestFactory()->createRequest($method, $uri);\n        } elseif (class_exists(Request::class)) {\n            $request = new Request($method, $uri);\n        } else {\n            throw new \\LogicException(\\sprintf('You cannot use \"%s()\" as no PSR-17 factories have been found. Try running \"composer require php-http/discovery psr/http-factory-implementation:*\".', __METHOD__));\n        }\n\n        $request = $request\n            ->withProtocolVersion($protocolVersion)\n            ->withBody($this->createStream($body ?? ''))\n        ;\n\n        foreach ($headers as $name => $value) {\n            $request = $request->withAddedHeader($name, $value);\n        }\n\n        return $request;\n    }\n\n    /**\n     * @param string $content\n     */\n    public function createStream($content = ''): StreamInterface\n    {\n        if (!\\is_string($content)) {\n            trigger_deprecation('symfony/http-client', '6.2', 'Passing a \"%s\" to \"%s()\" is deprecated, use \"createStreamFrom*()\" instead.', get_debug_type($content), __METHOD__);\n        }\n\n        if ($content instanceof StreamInterface) {\n            return $content;\n        }\n\n        if (\\is_string($content ?? '')) {\n            $stream = $this->streamFactory->createStream($content ?? '');\n        } elseif (\\is_resource($content)) {\n            $stream = $this->streamFactory->createStreamFromResource($content);\n        } else {\n            throw new \\InvalidArgumentException(\\sprintf('\"%s()\" expects string, resource or StreamInterface, \"%s\" given.', __METHOD__, get_debug_type($content)));\n        }\n\n        if ($stream->isSeekable()) {\n            try {\n                $stream->seek(0);\n            } catch (\\RuntimeException) {\n                // ignore\n            }\n        }\n\n        return $stream;\n    }\n\n    public function createStreamFromFile(string $filename, string $mode = 'r'): StreamInterface\n    {\n        return $this->streamFactory->createStreamFromFile($filename, $mode);\n    }\n\n    public function createStreamFromResource($resource): StreamInterface\n    {\n        return $this->streamFactory->createStreamFromResource($resource);\n    }\n\n    /**\n     * @param string $uri\n     */\n    public function createUri($uri = ''): UriInterface\n    {\n        if (!\\is_string($uri)) {\n            trigger_deprecation('symfony/http-client', '6.2', 'Passing a \"%s\" to \"%s()\" is deprecated, pass a string instead.', get_debug_type($uri), __METHOD__);\n        }\n\n        if ($uri instanceof UriInterface) {\n            return $uri;\n        }\n\n        if ($this->responseFactory instanceof UriFactoryInterface) {\n            return $this->responseFactory->createUri($uri);\n        }\n\n        if (class_exists(Psr17FactoryDiscovery::class)) {\n            return Psr17FactoryDiscovery::findUrlFactory()->createUri($uri);\n        }\n\n        if (class_exists(Uri::class)) {\n            return new Uri($uri);\n        }\n\n        throw new \\LogicException(\\sprintf('You cannot use \"%s()\" as no PSR-17 factories have been found. Try running \"composer require php-http/discovery psr/http-factory-implementation:*\".', __METHOD__));\n    }\n\n    public function __serialize(): array\n    {\n        throw new \\BadMethodCallException('Cannot serialize '.__CLASS__);\n    }\n\n    public function __unserialize(array $data): void\n    {\n        throw new \\BadMethodCallException('Cannot unserialize '.__CLASS__);\n    }\n\n    public function __destruct()\n    {\n        $this->wait();\n    }\n\n    public function reset(): void\n    {\n        if ($this->client instanceof ResetInterface) {\n            $this->client->reset();\n        }\n    }\n\n    private function sendPsr7Request(RequestInterface $request, ?bool $buffer = null): ResponseInterface\n    {\n        try {\n            $body = $request->getBody();\n\n            if ($body->isSeekable()) {\n                try {\n                    $body->seek(0);\n                } catch (\\RuntimeException) {\n                    // ignore\n                }\n            }\n\n            $options = [\n                'headers' => $request->getHeaders(),\n                'body' => $body->getContents(),\n                'buffer' => $buffer,\n            ];\n\n            if ('1.0' === $request->getProtocolVersion()) {\n                $options['http_version'] = '1.0';\n            }\n\n            return $this->client->request($request->getMethod(), (string) $request->getUri(), $options);\n        } catch (\\InvalidArgumentException $e) {\n            throw new RequestException($e->getMessage(), $request, $e);\n        } catch (TransportExceptionInterface $e) {\n            throw new NetworkException($e->getMessage(), $request, $e);\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/Internal/AmpBody.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient\\Internal;\n\nuse Amp\\ByteStream\\InputStream;\nuse Amp\\ByteStream\\ResourceInputStream;\nuse Amp\\Http\\Client\\RequestBody;\nuse Amp\\Promise;\nuse Amp\\Success;\nuse Symfony\\Component\\HttpClient\\Exception\\TransportException;\n\n/**\n * @author Nicolas Grekas <p@tchwork.com>\n *\n * @internal\n */\nclass AmpBody implements RequestBody, InputStream\n{\n    private ResourceInputStream|\\Closure|string $body;\n    private array $info;\n    private \\Closure $onProgress;\n    private ?int $offset = 0;\n    private int $length = -1;\n    private ?int $uploaded = null;\n\n    /**\n     * @param \\Closure|resource|string $body\n     */\n    public function __construct($body, &$info, \\Closure $onProgress)\n    {\n        $this->info = &$info;\n        $this->onProgress = $onProgress;\n\n        if (\\is_resource($body)) {\n            $this->offset = ftell($body);\n            $this->length = fstat($body)['size'];\n            $this->body = new ResourceInputStream($body);\n        } elseif (\\is_string($body)) {\n            $this->length = \\strlen($body);\n            $this->body = $body;\n        } else {\n            $this->body = $body;\n        }\n    }\n\n    public function createBodyStream(): InputStream\n    {\n        if (null !== $this->uploaded) {\n            $this->uploaded = null;\n\n            if (\\is_string($this->body)) {\n                $this->offset = 0;\n            } elseif ($this->body instanceof ResourceInputStream) {\n                fseek($this->body->getResource(), $this->offset);\n            }\n        }\n\n        return $this;\n    }\n\n    public function getHeaders(): Promise\n    {\n        return new Success([]);\n    }\n\n    public function getBodyLength(): Promise\n    {\n        return new Success($this->length - $this->offset);\n    }\n\n    public function read(): Promise\n    {\n        $this->info['size_upload'] += $this->uploaded;\n        $this->uploaded = 0;\n        ($this->onProgress)();\n\n        $chunk = $this->doRead();\n        $chunk->onResolve(function ($e, $data) {\n            if (null !== $data) {\n                $this->uploaded = \\strlen($data);\n            } else {\n                $this->info['upload_content_length'] = $this->info['size_upload'];\n            }\n        });\n\n        return $chunk;\n    }\n\n    public static function rewind(RequestBody $body): RequestBody\n    {\n        if (!$body instanceof self) {\n            return $body;\n        }\n\n        $body->uploaded = null;\n\n        if ($body->body instanceof ResourceInputStream) {\n            fseek($body->body->getResource(), $body->offset);\n\n            return new $body($body->body, $body->info, $body->onProgress);\n        }\n\n        if (\\is_string($body->body)) {\n            $body->offset = 0;\n        }\n\n        return $body;\n    }\n\n    private function doRead(): Promise\n    {\n        if ($this->body instanceof ResourceInputStream) {\n            return $this->body->read();\n        }\n\n        if (null === $this->offset || !$this->length) {\n            return new Success();\n        }\n\n        if (\\is_string($this->body)) {\n            $this->offset = null;\n\n            return new Success($this->body);\n        }\n\n        if ('' === $data = ($this->body)(16372)) {\n            $this->offset = null;\n\n            return new Success();\n        }\n\n        if (!\\is_string($data)) {\n            throw new TransportException(\\sprintf('Return value of the \"body\" option callback must be string, \"%s\" returned.', get_debug_type($data)));\n        }\n\n        return new Success($data);\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/Internal/AmpClientState.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient\\Internal;\n\nuse Amp\\CancellationToken;\nuse Amp\\Deferred;\nuse Amp\\Http\\Client\\Connection\\ConnectionLimitingPool;\nuse Amp\\Http\\Client\\Connection\\DefaultConnectionFactory;\nuse Amp\\Http\\Client\\InterceptedHttpClient;\nuse Amp\\Http\\Client\\Interceptor\\RetryRequests;\nuse Amp\\Http\\Client\\PooledHttpClient;\nuse Amp\\Http\\Client\\Request;\nuse Amp\\Http\\Client\\Response;\nuse Amp\\Http\\Tunnel\\Http1TunnelConnector;\nuse Amp\\Http\\Tunnel\\Https1TunnelConnector;\nuse Amp\\Promise;\nuse Amp\\Socket\\Certificate;\nuse Amp\\Socket\\ClientTlsContext;\nuse Amp\\Socket\\ConnectContext;\nuse Amp\\Socket\\Connector;\nuse Amp\\Socket\\DnsConnector;\nuse Amp\\Socket\\SocketAddress;\nuse Amp\\Success;\nuse Psr\\Log\\LoggerInterface;\n\n/**\n * Internal representation of the Amp client's state.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n *\n * @internal\n */\nfinal class AmpClientState extends ClientState\n{\n    public array $dnsCache = [];\n    public int $responseCount = 0;\n    public array $pushedResponses = [];\n\n    private array $clients = [];\n    private \\Closure $clientConfigurator;\n    private int $maxHostConnections;\n    private int $maxPendingPushes;\n    private ?LoggerInterface $logger;\n\n    public function __construct(?callable $clientConfigurator, int $maxHostConnections, int $maxPendingPushes, ?LoggerInterface &$logger)\n    {\n        $clientConfigurator ??= static fn (PooledHttpClient $client) => new InterceptedHttpClient($client, new RetryRequests(2));\n        $this->clientConfigurator = $clientConfigurator(...);\n\n        $this->maxHostConnections = $maxHostConnections;\n        $this->maxPendingPushes = $maxPendingPushes;\n        $this->logger = &$logger;\n    }\n\n    /**\n     * @return Promise<Response>\n     */\n    public function request(array $options, Request $request, CancellationToken $cancellation, array &$info, \\Closure $onProgress, &$handle): Promise\n    {\n        if ($options['proxy']) {\n            if ($request->hasHeader('proxy-authorization')) {\n                $options['proxy']['auth'] = $request->getHeader('proxy-authorization');\n            }\n\n            // Matching \"no_proxy\" should follow the behavior of curl\n            $host = $request->getUri()->getHost();\n            foreach ($options['proxy']['no_proxy'] as $rule) {\n                $dotRule = '.'.ltrim($rule, '.');\n\n                if ('*' === $rule || $host === $rule || str_ends_with($host, $dotRule)) {\n                    $options['proxy'] = null;\n                    break;\n                }\n            }\n        }\n\n        $request = clone $request;\n\n        if ($request->hasHeader('proxy-authorization')) {\n            $request->removeHeader('proxy-authorization');\n        }\n\n        if ($options['capture_peer_cert_chain']) {\n            $info['peer_certificate_chain'] = [];\n        }\n\n        $request->addEventListener(new AmpListener($info, $options['peer_fingerprint']['pin-sha256'] ?? [], $onProgress, $handle));\n        $request->setPushHandler(fn ($request, $response): Promise => $this->handlePush($request, $response, $options));\n\n        ($request->hasHeader('content-length') ? new Success((int) $request->getHeader('content-length')) : $request->getBody()->getBodyLength())\n            ->onResolve(static function ($e, $bodySize) use (&$info) {\n                if (null !== $bodySize && 0 <= $bodySize) {\n                    $info['upload_content_length'] = ((1 + $info['upload_content_length']) ?? 1) - 1 + $bodySize;\n                }\n            });\n\n        [$client, $connector] = $this->getClient($options);\n        $response = $client->request($request, $cancellation);\n        $response->onResolve(static function ($e) use ($connector, &$handle) {\n            if (null === $e) {\n                $handle = $connector->handle;\n            }\n        });\n\n        return $response;\n    }\n\n    private function getClient(array $options): array\n    {\n        $options = [\n            'bindto' => $options['bindto'] ?: '0',\n            'verify_peer' => $options['verify_peer'],\n            'capath' => $options['capath'],\n            'cafile' => $options['cafile'],\n            'local_cert' => $options['local_cert'],\n            'local_pk' => $options['local_pk'],\n            'ciphers' => $options['ciphers'],\n            'capture_peer_cert_chain' => $options['capture_peer_cert_chain'] || $options['peer_fingerprint'],\n            'proxy' => $options['proxy'],\n            'crypto_method' => $options['crypto_method'],\n        ];\n\n        $key = hash('xxh128', serialize($options));\n\n        if (isset($this->clients[$key])) {\n            return $this->clients[$key];\n        }\n\n        $context = new ClientTlsContext('');\n        $options['verify_peer'] || $context = $context->withoutPeerVerification();\n        $options['cafile'] && $context = $context->withCaFile($options['cafile']);\n        $options['capath'] && $context = $context->withCaPath($options['capath']);\n        $options['local_cert'] && $context = $context->withCertificate(new Certificate($options['local_cert'], $options['local_pk']));\n        $options['ciphers'] && $context = $context->withCiphers($options['ciphers']);\n        $options['capture_peer_cert_chain'] && $context = $context->withPeerCapturing();\n        $options['crypto_method'] && $context = $context->withMinimumVersion($options['crypto_method']);\n\n        $connector = $handleConnector = new class implements Connector {\n            public DnsConnector $connector;\n            public string $uri;\n            /** @var resource|null */\n            public $handle;\n\n            public function connect(string $uri, ?ConnectContext $context = null, ?CancellationToken $token = null): Promise\n            {\n                $result = $this->connector->connect($this->uri ?? $uri, $context, $token);\n                $result->onResolve(function ($e, $socket) {\n                    $this->handle = $socket?->getResource();\n                });\n\n                return $result;\n            }\n        };\n        $connector->connector = new DnsConnector(new AmpResolver($this->dnsCache));\n\n        $context = (new ConnectContext())\n            ->withTcpNoDelay()\n            ->withTlsContext($context);\n\n        if ($options['bindto']) {\n            if (file_exists($options['bindto'])) {\n                $connector->uri = 'unix://'.$options['bindto'];\n            } else {\n                $context = $context->withBindTo($options['bindto']);\n            }\n        }\n\n        if ($options['proxy']) {\n            $proxyUrl = parse_url($options['proxy']['url']);\n            $proxySocket = new SocketAddress($proxyUrl['host'], $proxyUrl['port']);\n            $proxyHeaders = $options['proxy']['auth'] ? ['Proxy-Authorization' => $options['proxy']['auth']] : [];\n\n            if ('ssl' === $proxyUrl['scheme']) {\n                $connector = new Https1TunnelConnector($proxySocket, $context->getTlsContext(), $proxyHeaders, $connector);\n            } else {\n                $connector = new Http1TunnelConnector($proxySocket, $proxyHeaders, $connector);\n            }\n        }\n\n        $maxHostConnections = 0 < $this->maxHostConnections ? $this->maxHostConnections : \\PHP_INT_MAX;\n        $pool = new DefaultConnectionFactory($connector, $context);\n        $pool = ConnectionLimitingPool::byAuthority($maxHostConnections, $pool);\n\n        return $this->clients[$key] = [($this->clientConfigurator)(new PooledHttpClient($pool)), $handleConnector];\n    }\n\n    private function handlePush(Request $request, Promise $response, array $options): Promise\n    {\n        $deferred = new Deferred();\n        $authority = $request->getUri()->getAuthority();\n\n        if ($this->maxPendingPushes <= \\count($this->pushedResponses[$authority] ?? [])) {\n            $fifoUrl = key($this->pushedResponses[$authority]);\n            unset($this->pushedResponses[$authority][$fifoUrl]);\n            $this->logger?->debug(\\sprintf('Evicting oldest pushed response: \"%s\"', $fifoUrl));\n        }\n\n        $url = (string) $request->getUri();\n        $this->logger?->debug(\\sprintf('Queueing pushed response: \"%s\"', $url));\n        $this->pushedResponses[$authority][] = [$url, $deferred, $request, $response, [\n            'proxy' => $options['proxy'],\n            'bindto' => $options['bindto'],\n            'local_cert' => $options['local_cert'],\n            'local_pk' => $options['local_pk'],\n        ]];\n\n        return $deferred->promise();\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/Internal/AmpListener.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient\\Internal;\n\nuse Amp\\Http\\Client\\Connection\\Stream;\nuse Amp\\Http\\Client\\EventListener;\nuse Amp\\Http\\Client\\Request;\nuse Amp\\Promise;\nuse Amp\\Success;\nuse Symfony\\Component\\HttpClient\\Exception\\TransportException;\n\n/**\n * @author Nicolas Grekas <p@tchwork.com>\n *\n * @internal\n */\nclass AmpListener implements EventListener\n{\n    private array $info;\n    private array $pinSha256;\n    private \\Closure $onProgress;\n    /** @var resource|null */\n    private $handle;\n\n    public function __construct(array &$info, array $pinSha256, \\Closure $onProgress, &$handle)\n    {\n        $info += [\n            'connect_time' => 0.0,\n            'pretransfer_time' => 0.0,\n            'starttransfer_time' => 0.0,\n            'total_time' => 0.0,\n            'namelookup_time' => 0.0,\n            'primary_ip' => '',\n            'primary_port' => 0,\n        ];\n\n        $this->info = &$info;\n        $this->pinSha256 = $pinSha256;\n        $this->onProgress = $onProgress;\n        $this->handle = &$handle;\n    }\n\n    public function startRequest(Request $request): Promise\n    {\n        $this->info['start_time'] ??= microtime(true);\n        ($this->onProgress)();\n\n        return new Success();\n    }\n\n    public function startDnsResolution(Request $request): Promise\n    {\n        ($this->onProgress)();\n\n        return new Success();\n    }\n\n    public function startConnectionCreation(Request $request): Promise\n    {\n        ($this->onProgress)();\n\n        return new Success();\n    }\n\n    public function startTlsNegotiation(Request $request): Promise\n    {\n        ($this->onProgress)();\n\n        return new Success();\n    }\n\n    public function startSendingRequest(Request $request, Stream $stream): Promise\n    {\n        $host = $stream->getRemoteAddress()->getHost();\n        $this->info['primary_ip'] = $host;\n\n        if (str_contains($host, ':')) {\n            $host = '['.$host.']';\n        }\n\n        $this->info['primary_port'] = $stream->getRemoteAddress()->getPort();\n        $this->info['pretransfer_time'] = microtime(true) - $this->info['start_time'];\n        $this->info['debug'] .= \\sprintf(\"* Connected to %s (%s) port %d\\n\", $request->getUri()->getHost(), $host, $this->info['primary_port']);\n\n        if ((isset($this->info['peer_certificate_chain']) || $this->pinSha256) && null !== $tlsInfo = $stream->getTlsInfo()) {\n            foreach ($tlsInfo->getPeerCertificates() as $cert) {\n                $this->info['peer_certificate_chain'][] = openssl_x509_read($cert->toPem());\n            }\n\n            if ($this->pinSha256) {\n                $pin = openssl_pkey_get_public($this->info['peer_certificate_chain'][0]);\n                $pin = openssl_pkey_get_details($pin)['key'];\n                $pin = \\array_slice(explode(\"\\n\", $pin), 1, -2);\n                $pin = base64_decode(implode('', $pin));\n                $pin = base64_encode(hash('sha256', $pin, true));\n\n                if (!\\in_array($pin, $this->pinSha256, true)) {\n                    throw new TransportException(\\sprintf('SSL public key does not match pinned public key for \"%s\".', $this->info['url']));\n                }\n            }\n        }\n        ($this->onProgress)();\n\n        $uri = $request->getUri();\n        $requestUri = $uri->getPath() ?: '/';\n\n        if ('' !== $query = $uri->getQuery()) {\n            $requestUri .= '?'.$query;\n        }\n\n        if ('CONNECT' === $method = $request->getMethod()) {\n            $requestUri = $uri->getHost().': '.($uri->getPort() ?? ('https' === $uri->getScheme() ? 443 : 80));\n        }\n\n        $this->info['debug'] .= \\sprintf(\"> %s %s HTTP/%s \\r\\n\", $method, $requestUri, $request->getProtocolVersions()[0]);\n\n        foreach ($request->getRawHeaders() as [$name, $value]) {\n            $this->info['debug'] .= $name.': '.$value.\"\\r\\n\";\n        }\n        $this->info['debug'] .= \"\\r\\n\";\n\n        return new Success();\n    }\n\n    public function completeSendingRequest(Request $request, Stream $stream): Promise\n    {\n        ($this->onProgress)();\n\n        return new Success();\n    }\n\n    public function startReceivingResponse(Request $request, Stream $stream): Promise\n    {\n        $this->info['starttransfer_time'] = microtime(true) - $this->info['start_time'];\n        ($this->onProgress)();\n\n        return new Success();\n    }\n\n    public function completeReceivingResponse(Request $request, Stream $stream): Promise\n    {\n        $this->handle = null;\n        ($this->onProgress)();\n\n        return new Success();\n    }\n\n    public function completeDnsResolution(Request $request): Promise\n    {\n        $this->info['namelookup_time'] = microtime(true) - $this->info['start_time'];\n        ($this->onProgress)();\n\n        return new Success();\n    }\n\n    public function completeConnectionCreation(Request $request): Promise\n    {\n        $this->info['connect_time'] = microtime(true) - $this->info['start_time'];\n        ($this->onProgress)();\n\n        return new Success();\n    }\n\n    public function completeTlsNegotiation(Request $request): Promise\n    {\n        ($this->onProgress)();\n\n        return new Success();\n    }\n\n    public function abort(Request $request, \\Throwable $cause): Promise\n    {\n        return new Success();\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/Internal/AmpResolver.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient\\Internal;\n\nuse Amp\\Dns;\nuse Amp\\Dns\\Record;\nuse Amp\\Promise;\nuse Amp\\Success;\n\n/**\n * Handles local overrides for the DNS resolver.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n *\n * @internal\n */\nclass AmpResolver implements Dns\\Resolver\n{\n    private array $dnsMap;\n\n    public function __construct(array &$dnsMap)\n    {\n        $this->dnsMap = &$dnsMap;\n    }\n\n    public function resolve(string $name, ?int $typeRestriction = null): Promise\n    {\n        $recordType = Record::A;\n        $ip = $this->dnsMap[$name] ?? null;\n\n        if (null !== $ip && str_contains($ip, ':')) {\n            $recordType = Record::AAAA;\n        }\n        if (null === $ip || $recordType !== ($typeRestriction ?? $recordType)) {\n            return Dns\\resolver()->resolve($name, $typeRestriction);\n        }\n\n        return new Success([new Record($ip, $recordType, null)]);\n    }\n\n    public function query(string $name, int $type): Promise\n    {\n        $recordType = Record::A;\n        $ip = $this->dnsMap[$name] ?? null;\n\n        if (null !== $ip && str_contains($ip, ':')) {\n            $recordType = Record::AAAA;\n        }\n        if (null === $ip || $recordType !== $type) {\n            return Dns\\resolver()->query($name, $type);\n        }\n\n        return new Success([new Record($ip, $recordType, null)]);\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/Internal/Canary.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient\\Internal;\n\n/**\n * @author Nicolas Grekas <p@tchwork.com>\n *\n * @internal\n */\nfinal class Canary\n{\n    private \\Closure $canceller;\n\n    public function __construct(\\Closure $canceller)\n    {\n        $this->canceller = $canceller;\n    }\n\n    public function cancel(): void\n    {\n        if (isset($this->canceller)) {\n            $canceller = $this->canceller;\n            unset($this->canceller);\n            $canceller();\n        }\n    }\n\n    public function __destruct()\n    {\n        $this->cancel();\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/Internal/ClientState.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient\\Internal;\n\n/**\n * Internal representation of the client state.\n *\n * @author Alexander M. Turek <me@derrabus.de>\n *\n * @internal\n */\nclass ClientState\n{\n    public array $handlesActivity = [];\n    public array $openHandles = [];\n    public ?float $lastTimeout = null;\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/Internal/CurlClientState.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient\\Internal;\n\nuse Psr\\Log\\LoggerInterface;\nuse Symfony\\Component\\HttpClient\\Response\\CurlResponse;\n\n/**\n * Internal representation of the cURL client's state.\n *\n * @author Alexander M. Turek <me@derrabus.de>\n *\n * @internal\n */\nfinal class CurlClientState extends ClientState\n{\n    public ?\\CurlMultiHandle $handle;\n    public ?\\CurlShareHandle $share;\n    public bool $performing = false;\n\n    /** @var PushedResponse[] */\n    public array $pushedResponses = [];\n    public DnsCache $dnsCache;\n    /** @var float[] */\n    public array $pauseExpiries = [];\n    public int $execCounter = \\PHP_INT_MIN;\n    public ?LoggerInterface $logger = null;\n\n    public static array $curlVersion;\n\n    public function __construct(int $maxHostConnections, int $maxPendingPushes)\n    {\n        self::$curlVersion ??= curl_version();\n\n        $this->handle = curl_multi_init();\n        $this->dnsCache = new DnsCache();\n        $this->reset();\n\n        // Don't enable HTTP/1.1 pipelining: it forces responses to be sent in order\n        if (\\defined('CURLPIPE_MULTIPLEX')) {\n            curl_multi_setopt($this->handle, \\CURLMOPT_PIPELINING, \\CURLPIPE_MULTIPLEX);\n        }\n        if (\\defined('CURLMOPT_MAX_HOST_CONNECTIONS') && 0 < $maxHostConnections) {\n            $maxHostConnections = curl_multi_setopt($this->handle, \\CURLMOPT_MAX_HOST_CONNECTIONS, $maxHostConnections) ? min(50 * $maxHostConnections, 4294967295) : $maxHostConnections;\n        }\n        if (\\defined('CURLMOPT_MAXCONNECTS') && 0 < $maxHostConnections) {\n            curl_multi_setopt($this->handle, \\CURLMOPT_MAXCONNECTS, $maxHostConnections);\n        }\n\n        // Skip configuring HTTP/2 push when it's unsupported or buggy, see https://bugs.php.net/77535\n        if (0 >= $maxPendingPushes) {\n            return;\n        }\n\n        // HTTP/2 push crashes before curl 7.61\n        if (!\\defined('CURLMOPT_PUSHFUNCTION') || 0x073D00 > self::$curlVersion['version_number'] || !(\\CURL_VERSION_HTTP2 & self::$curlVersion['features'])) {\n            return;\n        }\n\n        // Clone to prevent a circular reference\n        $multi = clone $this;\n        $multi->handle = null;\n        $multi->share = null;\n        $multi->pushedResponses = &$this->pushedResponses;\n        $multi->logger = &$this->logger;\n        $multi->handlesActivity = &$this->handlesActivity;\n        $multi->openHandles = &$this->openHandles;\n\n        curl_multi_setopt($this->handle, \\CURLMOPT_PUSHFUNCTION, static fn ($parent, $pushed, array $requestHeaders) => $multi->handlePush($parent, $pushed, $requestHeaders, $maxPendingPushes));\n    }\n\n    public function reset(): void\n    {\n        foreach ($this->pushedResponses as $url => $response) {\n            $this->logger?->debug(\\sprintf('Unused pushed response: \"%s\"', $url));\n            curl_multi_remove_handle($this->handle, $response->handle);\n        }\n\n        $this->pushedResponses = [];\n        $this->dnsCache->evictions = $this->dnsCache->evictions ?: $this->dnsCache->removals;\n        $this->dnsCache->removals = $this->dnsCache->hostnames = [];\n\n        $this->share = curl_share_init();\n\n        curl_share_setopt($this->share, \\CURLSHOPT_SHARE, \\CURL_LOCK_DATA_DNS);\n        curl_share_setopt($this->share, \\CURLSHOPT_SHARE, \\CURL_LOCK_DATA_SSL_SESSION);\n\n        if (\\defined('CURL_LOCK_DATA_CONNECT')) {\n            curl_share_setopt($this->share, \\CURLSHOPT_SHARE, \\CURL_LOCK_DATA_CONNECT);\n        }\n    }\n\n    private function handlePush($parent, $pushed, array $requestHeaders, int $maxPendingPushes): int\n    {\n        $headers = [];\n        $origin = curl_getinfo($parent, \\CURLINFO_EFFECTIVE_URL);\n\n        foreach ($requestHeaders as $h) {\n            if (false !== $i = strpos($h, ':', 1)) {\n                $headers[substr($h, 0, $i)][] = substr($h, 1 + $i);\n            }\n        }\n\n        if (!isset($headers[':method']) || !isset($headers[':scheme']) || !isset($headers[':authority']) || !isset($headers[':path'])) {\n            $this->logger?->debug(\\sprintf('Rejecting pushed response from \"%s\": pushed headers are invalid', $origin));\n\n            return \\CURL_PUSH_DENY;\n        }\n\n        $url = $headers[':scheme'][0].'://'.$headers[':authority'][0];\n\n        // curl before 7.65 doesn't validate the pushed \":authority\" header,\n        // but this is a MUST in the HTTP/2 RFC; let's restrict pushes to the original host,\n        // ignoring domains mentioned as alt-name in the certificate for now (same as curl).\n        if (!str_starts_with($origin, $url.'/')) {\n            $this->logger?->debug(\\sprintf('Rejecting pushed response from \"%s\": server is not authoritative for \"%s\"', $origin, $url));\n\n            return \\CURL_PUSH_DENY;\n        }\n\n        if ($maxPendingPushes <= \\count($this->pushedResponses)) {\n            $fifoUrl = key($this->pushedResponses);\n            unset($this->pushedResponses[$fifoUrl]);\n            $this->logger?->debug(\\sprintf('Evicting oldest pushed response: \"%s\"', $fifoUrl));\n        }\n\n        $url .= $headers[':path'][0];\n        $this->logger?->debug(\\sprintf('Queueing pushed response: \"%s\"', $url));\n\n        $this->pushedResponses[$url] = new PushedResponse(new CurlResponse($this, $pushed), $headers, $this->openHandles[(int) $parent][1] ?? [], $pushed);\n\n        return \\CURL_PUSH_OK;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/Internal/DnsCache.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient\\Internal;\n\n/**\n * Cache for resolved DNS queries.\n *\n * @author Alexander M. Turek <me@derrabus.de>\n *\n * @internal\n */\nfinal class DnsCache\n{\n    /**\n     * Resolved hostnames (hostname => IP address).\n     *\n     * @var string[]\n     */\n    public array $hostnames = [];\n\n    /**\n     * @var string[]\n     */\n    public array $removals = [];\n\n    /**\n     * @var string[]\n     */\n    public array $evictions = [];\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/Internal/HttplugWaitLoop.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient\\Internal;\n\nuse Http\\Client\\Exception\\NetworkException;\nuse Http\\Promise\\Promise;\nuse Psr\\Http\\Message\\RequestInterface as Psr7RequestInterface;\nuse Psr\\Http\\Message\\ResponseFactoryInterface;\nuse Psr\\Http\\Message\\ResponseInterface as Psr7ResponseInterface;\nuse Psr\\Http\\Message\\StreamFactoryInterface;\nuse Symfony\\Component\\HttpClient\\Response\\StreamableInterface;\nuse Symfony\\Component\\HttpClient\\Response\\StreamWrapper;\nuse Symfony\\Contracts\\HttpClient\\Exception\\TransportExceptionInterface;\nuse Symfony\\Contracts\\HttpClient\\HttpClientInterface;\nuse Symfony\\Contracts\\HttpClient\\ResponseInterface;\n\n/**\n * @author Nicolas Grekas <p@tchwork.com>\n *\n * @internal\n */\nfinal class HttplugWaitLoop\n{\n    private HttpClientInterface $client;\n    private ?\\SplObjectStorage $promisePool;\n    private ResponseFactoryInterface $responseFactory;\n    private StreamFactoryInterface $streamFactory;\n\n    /**\n     * @param \\SplObjectStorage<ResponseInterface, array{Psr7RequestInterface, Promise}>|null $promisePool\n     */\n    public function __construct(HttpClientInterface $client, ?\\SplObjectStorage $promisePool, ResponseFactoryInterface $responseFactory, StreamFactoryInterface $streamFactory)\n    {\n        $this->client = $client;\n        $this->promisePool = $promisePool;\n        $this->responseFactory = $responseFactory;\n        $this->streamFactory = $streamFactory;\n    }\n\n    public function wait(?ResponseInterface $pendingResponse, ?float $maxDuration = null, ?float $idleTimeout = null): int\n    {\n        if (!$this->promisePool) {\n            return 0;\n        }\n\n        $guzzleQueue = \\GuzzleHttp\\Promise\\Utils::queue();\n\n        if (0.0 === $remainingDuration = $maxDuration) {\n            $idleTimeout = 0.0;\n        } elseif (null !== $maxDuration) {\n            $startTime = hrtime(true) / 1E9;\n            $idleTimeout = max(0.0, min($maxDuration / 5, $idleTimeout ?? $maxDuration));\n        }\n\n        do {\n            foreach ($this->client->stream($this->promisePool, $idleTimeout) as $response => $chunk) {\n                try {\n                    if (null !== $maxDuration && $chunk->isTimeout()) {\n                        goto check_duration;\n                    }\n\n                    if ($chunk->isFirst()) {\n                        // Deactivate throwing on 3/4/5xx\n                        $response->getStatusCode();\n                    }\n\n                    if (!$chunk->isLast()) {\n                        goto check_duration;\n                    }\n\n                    if ([, $promise] = $this->promisePool[$response] ?? null) {\n                        unset($this->promisePool[$response]);\n                        $promise->resolve(self::createPsr7Response($this->responseFactory, $this->streamFactory, $this->client, $response, true));\n                    }\n                } catch (\\Exception $e) {\n                    if ([$request, $promise] = $this->promisePool[$response] ?? null) {\n                        unset($this->promisePool[$response]);\n\n                        if ($e instanceof TransportExceptionInterface) {\n                            $e = new NetworkException($e->getMessage(), $request, $e);\n                        }\n\n                        $promise->reject($e);\n                    }\n                }\n\n                $guzzleQueue->run();\n\n                if ($pendingResponse === $response) {\n                    return $this->promisePool->count();\n                }\n\n                check_duration:\n                if (null !== $maxDuration && $idleTimeout && $idleTimeout > $remainingDuration = max(0.0, $maxDuration - hrtime(true) / 1E9 + $startTime)) {\n                    $idleTimeout = $remainingDuration / 5;\n                    break;\n                }\n            }\n\n            if (!$count = $this->promisePool->count()) {\n                return 0;\n            }\n        } while (null === $maxDuration || 0 < $remainingDuration);\n\n        return $count;\n    }\n\n    public static function createPsr7Response(ResponseFactoryInterface $responseFactory, StreamFactoryInterface $streamFactory, HttpClientInterface $client, ResponseInterface $response, bool $buffer): Psr7ResponseInterface\n    {\n        $responseParameters = [$response->getStatusCode()];\n\n        foreach ($response->getInfo('response_headers') as $h) {\n            if (11 <= \\strlen($h) && '/' === $h[4] && preg_match('#^HTTP/\\d+(?:\\.\\d+)? (?:\\d\\d\\d) (.+)#', $h, $m)) {\n                $responseParameters[1] = $m[1];\n            }\n        }\n\n        $psrResponse = $responseFactory->createResponse(...$responseParameters);\n\n        foreach ($response->getHeaders(false) as $name => $values) {\n            foreach ($values as $value) {\n                try {\n                    $psrResponse = $psrResponse->withAddedHeader($name, $value);\n                } catch (\\InvalidArgumentException $e) {\n                    // ignore invalid header\n                }\n            }\n        }\n\n        if ($response instanceof StreamableInterface) {\n            $body = $streamFactory->createStreamFromResource($response->toStream(false));\n        } elseif (!$buffer) {\n            $body = $streamFactory->createStreamFromResource(StreamWrapper::createResource($response, $client));\n        } else {\n            $body = $streamFactory->createStream($response->getContent(false));\n        }\n\n        if ($body->isSeekable()) {\n            try {\n                $body->seek(0);\n            } catch (\\RuntimeException) {\n                // ignore\n            }\n        }\n\n        return $psrResponse->withBody($body);\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/Internal/LegacyHttplugInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient\\Internal;\n\nuse Http\\Client\\HttpClient;\nuse Http\\Message\\RequestFactory;\nuse Http\\Message\\StreamFactory;\nuse Http\\Message\\UriFactory;\n\nif (interface_exists(RequestFactory::class)) {\n    /**\n     * @internal\n     *\n     * @deprecated since Symfony 6.3\n     */\n    interface LegacyHttplugInterface extends HttpClient, RequestFactory, StreamFactory, UriFactory\n    {\n    }\n} else {\n    /**\n     * @internal\n     *\n     * @deprecated since Symfony 6.3\n     */\n    interface LegacyHttplugInterface extends HttpClient\n    {\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/Internal/NativeClientState.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient\\Internal;\n\n/**\n * Internal representation of the native client's state.\n *\n * @author Alexander M. Turek <me@derrabus.de>\n *\n * @internal\n */\nfinal class NativeClientState extends ClientState\n{\n    public int $id;\n    public int $maxHostConnections = \\PHP_INT_MAX;\n    public int $responseCount = 0;\n    /** @var string[] */\n    public array $dnsCache = [];\n    public bool $sleep = false;\n    /** @var int[] */\n    public array $hosts = [];\n\n    public function __construct()\n    {\n        $this->id = random_int(\\PHP_INT_MIN, \\PHP_INT_MAX);\n    }\n\n    public function reset(): void\n    {\n        $this->responseCount = 0;\n        $this->dnsCache = [];\n        $this->hosts = [];\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/Internal/PushedResponse.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient\\Internal;\n\nuse Symfony\\Component\\HttpClient\\Response\\CurlResponse;\n\n/**\n * A pushed response with its request headers.\n *\n * @author Alexander M. Turek <me@derrabus.de>\n *\n * @internal\n */\nfinal class PushedResponse\n{\n    public function __construct(\n        public CurlResponse $response,\n        public array $requestHeaders,\n        public array $parentOptions,\n        public \\CurlHandle $handle,\n    ) {\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/LICENSE",
    "content": "Copyright (c) 2018-present Fabien Potencier\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is furnished\nto do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "server/vendor/symfony/http-client/Messenger/PingWebhookMessage.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient\\Messenger;\n\n/**\n * @author Kevin Bond <kevinbond@gmail.com>\n */\nfinal class PingWebhookMessage implements \\Stringable\n{\n    public function __construct(\n        public readonly string $method,\n        public readonly string $url,\n        public readonly array $options = [],\n        public readonly bool $throw = true,\n    ) {\n    }\n\n    public function __toString(): string\n    {\n        return \"[{$this->method}] {$this->url}\";\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/Messenger/PingWebhookMessageHandler.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient\\Messenger;\n\nuse Symfony\\Contracts\\HttpClient\\HttpClientInterface;\nuse Symfony\\Contracts\\HttpClient\\ResponseInterface;\n\n/**\n * @author Kevin Bond <kevinbond@gmail.com>\n */\nclass PingWebhookMessageHandler\n{\n    public function __construct(\n        private readonly HttpClientInterface $httpClient,\n    ) {\n    }\n\n    public function __invoke(PingWebhookMessage $message): ResponseInterface\n    {\n        $response = $this->httpClient->request($message->method, $message->url, $message->options);\n        $response->getHeaders($message->throw);\n\n        return $response;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/MockHttpClient.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient;\n\nuse Symfony\\Component\\HttpClient\\Exception\\TransportException;\nuse Symfony\\Component\\HttpClient\\Response\\MockResponse;\nuse Symfony\\Component\\HttpClient\\Response\\ResponseStream;\nuse Symfony\\Contracts\\HttpClient\\HttpClientInterface;\nuse Symfony\\Contracts\\HttpClient\\ResponseInterface;\nuse Symfony\\Contracts\\HttpClient\\ResponseStreamInterface;\nuse Symfony\\Contracts\\Service\\ResetInterface;\n\n/**\n * A test-friendly HttpClient that doesn't make actual HTTP requests.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n */\nclass MockHttpClient implements HttpClientInterface, ResetInterface\n{\n    use HttpClientTrait;\n\n    private ResponseInterface|\\Closure|iterable|null $responseFactory;\n    private int $requestsCount = 0;\n    private array $defaultOptions = [];\n\n    /**\n     * @param callable|callable[]|ResponseInterface|ResponseInterface[]|iterable|null $responseFactory\n     */\n    public function __construct(callable|iterable|ResponseInterface|null $responseFactory = null, ?string $baseUri = 'https://example.com')\n    {\n        $this->setResponseFactory($responseFactory);\n        $this->defaultOptions['base_uri'] = $baseUri;\n    }\n\n    /**\n     * @param callable|callable[]|ResponseInterface|ResponseInterface[]|iterable|null $responseFactory\n     */\n    public function setResponseFactory($responseFactory): void\n    {\n        if ($responseFactory instanceof ResponseInterface) {\n            $responseFactory = [$responseFactory];\n        }\n\n        if (!$responseFactory instanceof \\Iterator && null !== $responseFactory && !\\is_callable($responseFactory)) {\n            $responseFactory = (static function () use ($responseFactory) {\n                yield from $responseFactory;\n            })();\n        }\n\n        $this->responseFactory = !\\is_callable($responseFactory) ? $responseFactory : $responseFactory(...);\n    }\n\n    public function request(string $method, string $url, array $options = []): ResponseInterface\n    {\n        [$url, $options] = $this->prepareRequest($method, $url, $options, $this->defaultOptions, true);\n        $url = implode('', $url);\n\n        if (null === $this->responseFactory) {\n            $response = new MockResponse();\n        } elseif (\\is_callable($this->responseFactory)) {\n            $response = ($this->responseFactory)($method, $url, $options);\n        } elseif (!$this->responseFactory->valid()) {\n            throw new TransportException($this->requestsCount ? 'No more response left in the response factory iterator passed to MockHttpClient: the number of requests exceeds the number of responses.' : 'The response factory iterator passed to MockHttpClient is empty.');\n        } else {\n            $responseFactory = $this->responseFactory->current();\n            $response = \\is_callable($responseFactory) ? $responseFactory($method, $url, $options) : $responseFactory;\n            $this->responseFactory->next();\n        }\n        ++$this->requestsCount;\n\n        if (!$response instanceof ResponseInterface) {\n            throw new TransportException(\\sprintf('The response factory passed to MockHttpClient must return/yield an instance of ResponseInterface, \"%s\" given.', get_debug_type($response)));\n        }\n\n        return MockResponse::fromRequest($method, $url, $options, $response);\n    }\n\n    public function stream(ResponseInterface|iterable $responses, ?float $timeout = null): ResponseStreamInterface\n    {\n        if ($responses instanceof ResponseInterface) {\n            $responses = [$responses];\n        }\n\n        return new ResponseStream(MockResponse::stream($responses, $timeout));\n    }\n\n    public function getRequestsCount(): int\n    {\n        return $this->requestsCount;\n    }\n\n    public function withOptions(array $options): static\n    {\n        $clone = clone $this;\n        $clone->defaultOptions = self::mergeDefaultOptions($options, $this->defaultOptions, true);\n\n        return $clone;\n    }\n\n    /**\n     * @return void\n     */\n    public function reset()\n    {\n        $this->requestsCount = 0;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/NativeHttpClient.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient;\n\nuse Psr\\Log\\LoggerAwareInterface;\nuse Psr\\Log\\LoggerAwareTrait;\nuse Symfony\\Component\\HttpClient\\Exception\\InvalidArgumentException;\nuse Symfony\\Component\\HttpClient\\Exception\\TransportException;\nuse Symfony\\Component\\HttpClient\\Internal\\NativeClientState;\nuse Symfony\\Component\\HttpClient\\Response\\NativeResponse;\nuse Symfony\\Component\\HttpClient\\Response\\ResponseStream;\nuse Symfony\\Contracts\\HttpClient\\HttpClientInterface;\nuse Symfony\\Contracts\\HttpClient\\ResponseInterface;\nuse Symfony\\Contracts\\HttpClient\\ResponseStreamInterface;\nuse Symfony\\Contracts\\Service\\ResetInterface;\n\n/**\n * A portable implementation of the HttpClientInterface contracts based on PHP stream wrappers.\n *\n * PHP stream wrappers are able to fetch response bodies concurrently,\n * but each request is opened synchronously.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n */\nfinal class NativeHttpClient implements HttpClientInterface, LoggerAwareInterface, ResetInterface\n{\n    use HttpClientTrait;\n    use LoggerAwareTrait;\n\n    public const OPTIONS_DEFAULTS = HttpClientInterface::OPTIONS_DEFAULTS + [\n        'crypto_method' => \\STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT,\n    ];\n\n    private array $defaultOptions = self::OPTIONS_DEFAULTS;\n    private static array $emptyDefaults = self::OPTIONS_DEFAULTS;\n\n    private NativeClientState $multi;\n\n    /**\n     * @param array $defaultOptions     Default request's options\n     * @param int   $maxHostConnections The maximum number of connections to open\n     *\n     * @see HttpClientInterface::OPTIONS_DEFAULTS for available options\n     */\n    public function __construct(array $defaultOptions = [], int $maxHostConnections = 6)\n    {\n        $this->defaultOptions['buffer'] ??= self::shouldBuffer(...);\n\n        if ($defaultOptions) {\n            [, $this->defaultOptions] = self::prepareRequest(null, null, $defaultOptions, $this->defaultOptions);\n        }\n\n        $this->multi = new NativeClientState();\n        $this->multi->maxHostConnections = 0 < $maxHostConnections ? $maxHostConnections : \\PHP_INT_MAX;\n    }\n\n    /**\n     * @see HttpClientInterface::OPTIONS_DEFAULTS for available options\n     */\n    public function request(string $method, string $url, array $options = []): ResponseInterface\n    {\n        [$url, $options] = self::prepareRequest($method, $url, $options, $this->defaultOptions);\n\n        if ($options['bindto']) {\n            if (file_exists($options['bindto'])) {\n                throw new TransportException(__CLASS__.' cannot bind to local Unix sockets, use e.g. CurlHttpClient instead.');\n            }\n            if (str_starts_with($options['bindto'], 'if!')) {\n                throw new TransportException(__CLASS__.' cannot bind to network interfaces, use e.g. CurlHttpClient instead.');\n            }\n            if (str_starts_with($options['bindto'], 'host!')) {\n                $options['bindto'] = substr($options['bindto'], 5);\n            }\n            if ((\\PHP_VERSION_ID < 80223 || 80300 <= \\PHP_VERSION_ID && 80311 < \\PHP_VERSION_ID) && '\\\\' === \\DIRECTORY_SEPARATOR && '[' === $options['bindto'][0]) {\n                $options['bindto'] = preg_replace('{^\\[[^\\]]++\\]}', '[$0]', $options['bindto']);\n            }\n        }\n\n        $hasContentLength = isset($options['normalized_headers']['content-length']);\n        $hasBody = '' !== $options['body'] || 'POST' === $method || $hasContentLength;\n\n        $options['body'] = self::getBodyAsString($options['body']);\n\n        if ('chunked' === substr($options['normalized_headers']['transfer-encoding'][0] ?? '', \\strlen('Transfer-Encoding: '))) {\n            unset($options['normalized_headers']['transfer-encoding']);\n            $options['headers'] = array_merge(...array_values($options['normalized_headers']));\n            $options['body'] = self::dechunk($options['body']);\n        }\n        if ('' === $options['body'] && $hasBody && !$hasContentLength) {\n            $options['headers'][] = 'Content-Length: 0';\n        }\n        if ($hasBody && !isset($options['normalized_headers']['content-type'])) {\n            $options['headers'][] = 'Content-Type: application/x-www-form-urlencoded';\n        }\n\n        if (\\extension_loaded('zlib') && !isset($options['normalized_headers']['accept-encoding'])) {\n            // gzip is the most widely available algo, no need to deal with deflate\n            $options['headers'][] = 'Accept-Encoding: gzip';\n        }\n\n        if ($options['peer_fingerprint']) {\n            if (isset($options['peer_fingerprint']['pin-sha256']) && 1 === \\count($options['peer_fingerprint'])) {\n                throw new TransportException(__CLASS__.' cannot verify \"pin-sha256\" fingerprints, please provide a \"sha256\" one.');\n            }\n\n            unset($options['peer_fingerprint']['pin-sha256']);\n        }\n\n        $info = [\n            'response_headers' => [],\n            'url' => $url,\n            'error' => null,\n            'canceled' => false,\n            'http_method' => $method,\n            'http_code' => 0,\n            'redirect_count' => 0,\n            'start_time' => 0.0,\n            'connect_time' => 0.0,\n            'redirect_time' => 0.0,\n            'pretransfer_time' => 0.0,\n            'starttransfer_time' => 0.0,\n            'total_time' => 0.0,\n            'namelookup_time' => 0.0,\n            'size_upload' => 0,\n            'size_download' => 0,\n            'size_body' => \\strlen($options['body']),\n            'primary_ip' => '',\n            'primary_port' => 'http:' === $url['scheme'] ? 80 : 443,\n            'debug' => \\extension_loaded('curl') ? '' : \"* Enable the curl extension for better performance\\n\",\n        ];\n\n        if ($onProgress = $options['on_progress']) {\n            $maxDuration = 0 < $options['max_duration'] ? $options['max_duration'] : \\INF;\n            $onProgress = static function (...$progress) use ($onProgress, &$info, $maxDuration) {\n                if ($info['total_time'] >= $maxDuration) {\n                    throw new TransportException(\\sprintf('Max duration was reached for \"%s\".', implode('', $info['url'])));\n                }\n\n                $progressInfo = $info;\n                $progressInfo['url'] = implode('', $info['url']);\n                unset($progressInfo['size_body']);\n\n                // Memoize the last progress to ease calling the callback periodically when no network transfer happens\n                static $lastProgress = [0, 0];\n\n                if ($progress && -1 === $progress[0]) {\n                    // Response completed\n                    $lastProgress[0] = max($lastProgress);\n                } else {\n                    $lastProgress = $progress ?: $lastProgress;\n                }\n\n                $onProgress($lastProgress[0], $lastProgress[1], $progressInfo);\n            };\n        } elseif (0 < $options['max_duration']) {\n            $maxDuration = $options['max_duration'];\n            $onProgress = static function () use (&$info, $maxDuration): void {\n                if ($info['total_time'] >= $maxDuration) {\n                    throw new TransportException(\\sprintf('Max duration was reached for \"%s\".', implode('', $info['url'])));\n                }\n            };\n        }\n\n        // Always register a notification callback to compute live stats about the response\n        $notification = static function (int $code, int $severity, ?string $msg, int $msgCode, int $dlNow, int $dlSize) use ($onProgress, &$info) {\n            $info['total_time'] = microtime(true) - $info['start_time'];\n\n            if (\\STREAM_NOTIFY_PROGRESS === $code) {\n                $info['starttransfer_time'] = $info['starttransfer_time'] ?: $info['total_time'];\n                $info['size_upload'] += $dlNow ? 0 : $info['size_body'];\n                $info['size_download'] = $dlNow;\n            } elseif (\\STREAM_NOTIFY_CONNECT === $code) {\n                $info['connect_time'] = $info['total_time'];\n                $info['debug'] .= $info['request_header'];\n                unset($info['request_header']);\n            } else {\n                return;\n            }\n\n            if ($onProgress) {\n                $onProgress($dlNow, $dlSize);\n            }\n        };\n\n        if ($options['resolve']) {\n            $this->multi->dnsCache = $options['resolve'] + $this->multi->dnsCache;\n        }\n\n        $this->logger?->info(\\sprintf('Request: \"%s %s\"', $method, implode('', $url)));\n\n        if (!isset($options['normalized_headers']['user-agent'])) {\n            $options['headers'][] = 'User-Agent: Symfony HttpClient (Native)';\n        }\n\n        if (0 < $options['max_duration']) {\n            $options['timeout'] = min($options['max_duration'], $options['timeout']);\n        }\n\n        switch ($cryptoMethod = $options['crypto_method']) {\n            case \\STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT:\n                $cryptoMethod |= \\STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT;\n                // no break\n            case \\STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT:\n                $cryptoMethod |= \\STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT;\n                // no break\n            case \\STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT:\n                $cryptoMethod |= \\STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT;\n        }\n\n        $context = [\n            'http' => [\n                'protocol_version' => min($options['http_version'] ?: '1.1', '1.1'),\n                'method' => $method,\n                'content' => $options['body'],\n                'ignore_errors' => true,\n                'curl_verify_ssl_peer' => $options['verify_peer'],\n                'curl_verify_ssl_host' => $options['verify_host'],\n                'auto_decode' => false, // Disable dechunk filter, it's incompatible with stream_select()\n                'timeout' => $options['timeout'],\n                'follow_location' => false, // We follow redirects ourselves - the native logic is too limited\n            ],\n            'ssl' => array_filter([\n                'verify_peer' => $options['verify_peer'],\n                'verify_peer_name' => $options['verify_host'],\n                'cafile' => $options['cafile'],\n                'capath' => $options['capath'],\n                'local_cert' => $options['local_cert'],\n                'local_pk' => $options['local_pk'],\n                'passphrase' => $options['passphrase'],\n                'ciphers' => $options['ciphers'],\n                'peer_fingerprint' => $options['peer_fingerprint'],\n                'capture_peer_cert_chain' => $options['capture_peer_cert_chain'],\n                'allow_self_signed' => (bool) $options['peer_fingerprint'],\n                'SNI_enabled' => true,\n                'disable_compression' => true,\n                'crypto_method' => $cryptoMethod,\n            ], static fn ($v) => null !== $v),\n            'socket' => [\n                'bindto' => $options['bindto'],\n                'tcp_nodelay' => true,\n            ],\n        ];\n\n        $context = stream_context_create($context, ['notification' => $notification]);\n\n        $resolver = static function ($multi) use ($context, $options, $url, &$info, $onProgress) {\n            $authority = $url['authority'];\n            [$host, $port] = self::parseHostPort($url, $info);\n\n            if (!isset($options['normalized_headers']['host'])) {\n                $options['headers'][] = 'Host: '.$host.$port;\n            }\n\n            $proxy = self::getProxy($options['proxy'], $url, $options['no_proxy']);\n\n            if (!self::configureHeadersAndProxy($context, $host, $options['headers'], $proxy, 'https:' === $url['scheme'])) {\n                $ip = self::dnsResolve($host, $multi, $info, $onProgress);\n                $url['authority'] = substr_replace($url['authority'], $ip, -\\strlen($host) - \\strlen($port), \\strlen($host));\n            }\n\n            return [self::createRedirectResolver($options, $authority, $proxy, $info, $onProgress), implode('', $url)];\n        };\n\n        return new NativeResponse($this->multi, $context, implode('', $url), $options, $info, $resolver, $onProgress, $this->logger);\n    }\n\n    public function stream(ResponseInterface|iterable $responses, ?float $timeout = null): ResponseStreamInterface\n    {\n        if ($responses instanceof NativeResponse) {\n            $responses = [$responses];\n        }\n\n        return new ResponseStream(NativeResponse::stream($responses, $timeout));\n    }\n\n    public function reset(): void\n    {\n        $this->multi->reset();\n    }\n\n    private static function getBodyAsString($body): string\n    {\n        if (\\is_resource($body)) {\n            return stream_get_contents($body);\n        }\n\n        if (!$body instanceof \\Closure) {\n            return $body;\n        }\n\n        $result = '';\n\n        while ('' !== $data = $body(self::$CHUNK_SIZE)) {\n            if (!\\is_string($data)) {\n                throw new TransportException(\\sprintf('Return value of the \"body\" option callback must be string, \"%s\" returned.', get_debug_type($data)));\n            }\n\n            $result .= $data;\n        }\n\n        return $result;\n    }\n\n    /**\n     * Extracts the host and the port from the URL.\n     */\n    private static function parseHostPort(array $url, array &$info): array\n    {\n        if ($port = parse_url($url['authority'], \\PHP_URL_PORT) ?: '') {\n            $info['primary_port'] = $port;\n            $port = ':'.$port;\n        } else {\n            $info['primary_port'] = 'http:' === $url['scheme'] ? 80 : 443;\n        }\n\n        return [parse_url($url['authority'], \\PHP_URL_HOST), $port];\n    }\n\n    /**\n     * Resolves the IP of the host using the local DNS cache if possible.\n     */\n    private static function dnsResolve(string $host, NativeClientState $multi, array &$info, ?\\Closure $onProgress): string\n    {\n        $flag = '' !== $host && '[' === $host[0] && ']' === $host[-1] && str_contains($host, ':') ? \\FILTER_FLAG_IPV6 : \\FILTER_FLAG_IPV4;\n        $ip = \\FILTER_FLAG_IPV6 === $flag ? substr($host, 1, -1) : $host;\n\n        if (filter_var($ip, \\FILTER_VALIDATE_IP, $flag)) {\n            // The host is already an IP address\n        } elseif (null === $ip = $multi->dnsCache[$host] ?? null) {\n            $info['debug'] .= \"* Hostname was NOT found in DNS cache\\n\";\n            $now = microtime(true);\n\n            if (!$ip = gethostbynamel($host)) {\n                throw new TransportException(\\sprintf('Could not resolve host \"%s\".', $host));\n            }\n\n            $multi->dnsCache[$host] = $ip = $ip[0];\n            $info['debug'] .= \"* Added {$host}:0:{$ip} to DNS cache\\n\";\n            $host = $ip;\n        } else {\n            $info['debug'] .= \"* Hostname was found in DNS cache\\n\";\n            $host = str_contains($ip, ':') ? \"[$ip]\" : $ip;\n        }\n\n        $info['namelookup_time'] = microtime(true) - ($info['start_time'] ?: $now);\n        $info['primary_ip'] = $ip;\n\n        if ($onProgress) {\n            // Notify DNS resolution\n            $onProgress();\n        }\n\n        return $host;\n    }\n\n    /**\n     * Handles redirects - the native logic is too buggy to be used.\n     */\n    private static function createRedirectResolver(array $options, string $authority, ?array $proxy, array &$info, ?\\Closure $onProgress): \\Closure\n    {\n        $redirectHeaders = [];\n        if (0 < $maxRedirects = $options['max_redirects']) {\n            $redirectHeaders = ['authority' => $authority];\n            $redirectHeaders['with_auth'] = $redirectHeaders['no_auth'] = array_filter($options['headers'], static fn ($h) => 0 !== stripos($h, 'Host:'));\n\n            if (isset($options['normalized_headers']['authorization']) || isset($options['normalized_headers']['cookie'])) {\n                $redirectHeaders['no_auth'] = array_filter($redirectHeaders['no_auth'], static fn ($h) => 0 !== stripos($h, 'Authorization:') && 0 !== stripos($h, 'Cookie:'));\n            }\n        }\n\n        return static function (NativeClientState $multi, ?string $location, $context) use (&$redirectHeaders, $proxy, &$info, $maxRedirects, $onProgress): ?string {\n            if (null === $location || $info['http_code'] < 300 || 400 <= $info['http_code']) {\n                $info['redirect_url'] = null;\n\n                return null;\n            }\n\n            try {\n                $url = self::parseUrl($location);\n                $locationHasHost = isset($url['authority']);\n                $url = self::resolveUrl($url, $info['url']);\n            } catch (InvalidArgumentException) {\n                $info['redirect_url'] = null;\n\n                return null;\n            }\n\n            $info['redirect_url'] = implode('', $url);\n\n            if ($info['redirect_count'] >= $maxRedirects) {\n                return null;\n            }\n\n            $info['url'] = $url;\n            ++$info['redirect_count'];\n            $info['redirect_time'] = microtime(true) - $info['start_time'];\n\n            // Do like curl and browsers: turn POST to GET on 301, 302 and 303\n            if (\\in_array($info['http_code'], [301, 302, 303], true)) {\n                $options = stream_context_get_options($context)['http'];\n\n                if ('POST' === $options['method'] || 303 === $info['http_code']) {\n                    $info['http_method'] = $options['method'] = 'HEAD' === $options['method'] ? 'HEAD' : 'GET';\n                    $options['content'] = '';\n                    $filterContentHeaders = static fn ($h) => 0 !== stripos($h, 'Content-Length:') && 0 !== stripos($h, 'Content-Type:') && 0 !== stripos($h, 'Transfer-Encoding:');\n                    $options['header'] = array_filter($options['header'], $filterContentHeaders);\n                    $redirectHeaders['no_auth'] = array_filter($redirectHeaders['no_auth'], $filterContentHeaders);\n                    $redirectHeaders['with_auth'] = array_filter($redirectHeaders['with_auth'], $filterContentHeaders);\n\n                    if (\\PHP_VERSION_ID >= 80300) {\n                        stream_context_set_options($context, ['http' => $options]);\n                    } else {\n                        stream_context_set_option($context, ['http' => $options]);\n                    }\n                }\n            }\n\n            [$host, $port] = self::parseHostPort($url, $info);\n\n            if ($locationHasHost) {\n                // Authorization and Cookie headers MUST NOT follow except for the initial authority name\n                $requestHeaders = $redirectHeaders['authority'] === $url['authority'] ? $redirectHeaders['with_auth'] : $redirectHeaders['no_auth'];\n                $requestHeaders[] = 'Host: '.$host.$port;\n                $dnsResolve = !self::configureHeadersAndProxy($context, $host, $requestHeaders, $proxy, 'https:' === $url['scheme']);\n            } else {\n                $dnsResolve = isset(stream_context_get_options($context)['ssl']['peer_name']);\n            }\n\n            if ($dnsResolve) {\n                $ip = self::dnsResolve($host, $multi, $info, $onProgress);\n                $url['authority'] = substr_replace($url['authority'], $ip, -\\strlen($host) - \\strlen($port), \\strlen($host));\n            }\n\n            return implode('', $url);\n        };\n    }\n\n    private static function configureHeadersAndProxy($context, string $host, array $requestHeaders, ?array $proxy, bool $isSsl): bool\n    {\n        if (null === $proxy) {\n            stream_context_set_option($context, 'http', 'header', $requestHeaders);\n            stream_context_set_option($context, 'ssl', 'peer_name', $host);\n\n            return false;\n        }\n\n        // Matching \"no_proxy\" should follow the behavior of curl\n\n        foreach ($proxy['no_proxy'] as $rule) {\n            $dotRule = '.'.ltrim($rule, '.');\n\n            if ('*' === $rule || $host === $rule || str_ends_with($host, $dotRule)) {\n                stream_context_set_option($context, 'http', 'proxy', null);\n                stream_context_set_option($context, 'http', 'request_fulluri', false);\n                stream_context_set_option($context, 'http', 'header', $requestHeaders);\n                stream_context_set_option($context, 'ssl', 'peer_name', $host);\n\n                return false;\n            }\n        }\n\n        if (null !== $proxy['auth']) {\n            $requestHeaders[] = 'Proxy-Authorization: '.$proxy['auth'];\n        }\n\n        stream_context_set_option($context, 'http', 'proxy', $proxy['url']);\n        stream_context_set_option($context, 'http', 'request_fulluri', !$isSsl);\n        stream_context_set_option($context, 'http', 'header', $requestHeaders);\n        stream_context_set_option($context, 'ssl', 'peer_name', null);\n\n        return true;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/NoPrivateNetworkHttpClient.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient;\n\nuse Psr\\Log\\LoggerAwareInterface;\nuse Psr\\Log\\LoggerInterface;\nuse Symfony\\Component\\HttpClient\\Exception\\TransportException;\nuse Symfony\\Component\\HttpClient\\Response\\AsyncContext;\nuse Symfony\\Component\\HttpClient\\Response\\AsyncResponse;\nuse Symfony\\Component\\HttpFoundation\\IpUtils;\nuse Symfony\\Contracts\\HttpClient\\ChunkInterface;\nuse Symfony\\Contracts\\HttpClient\\HttpClientInterface;\nuse Symfony\\Contracts\\HttpClient\\ResponseInterface;\nuse Symfony\\Contracts\\Service\\ResetInterface;\n\n/**\n * Decorator that blocks requests to private networks by default.\n *\n * @author Hallison Boaventura <hallisonboaventura@gmail.com>\n * @author Nicolas Grekas <p@tchwork.com>\n */\nfinal class NoPrivateNetworkHttpClient implements HttpClientInterface, LoggerAwareInterface, ResetInterface\n{\n    use AsyncDecoratorTrait;\n    use HttpClientTrait;\n\n    private array $defaultOptions = self::OPTIONS_DEFAULTS;\n    private HttpClientInterface $client;\n    private ?array $subnets;\n    private int $ipFlags;\n    private \\ArrayObject $dnsCache;\n\n    /**\n     * @param string|array|null $subnets String or array of subnets using CIDR notation that should be considered private.\n     *                                   If null is passed, the standard private subnets will be used.\n     */\n    public function __construct(HttpClientInterface $client, string|array|null $subnets = null)\n    {\n        if (!class_exists(IpUtils::class)) {\n            throw new \\LogicException(\\sprintf('You cannot use \"%s\" if the HttpFoundation component is not installed. Try running \"composer require symfony/http-foundation\".', __CLASS__));\n        }\n\n        if (null === $subnets) {\n            $ipFlags = \\FILTER_FLAG_IPV4 | \\FILTER_FLAG_IPV6;\n        } else {\n            $ipFlags = 0;\n            foreach ((array) $subnets as $subnet) {\n                $ipFlags |= str_contains($subnet, ':') ? \\FILTER_FLAG_IPV6 : \\FILTER_FLAG_IPV4;\n            }\n        }\n\n        if (!\\defined('STREAM_PF_INET6')) {\n            $ipFlags &= ~\\FILTER_FLAG_IPV6;\n        }\n\n        $this->client = $client;\n        $this->subnets = null !== $subnets ? (array) $subnets : null;\n        $this->ipFlags = $ipFlags;\n        $this->dnsCache = new \\ArrayObject();\n    }\n\n    public function request(string $method, string $url, array $options = []): ResponseInterface\n    {\n        [$url, $options] = self::prepareRequest($method, $url, $options, $this->defaultOptions, true);\n\n        $redirectHeaders = parse_url($url['authority']);\n        $host = $redirectHeaders['host'];\n        $url = implode('', $url);\n        $dnsCache = $this->dnsCache;\n\n        $ip = self::dnsResolve($dnsCache, $host, $this->ipFlags, $options);\n        self::ipCheck($ip, $this->subnets, $this->ipFlags, $host, $url);\n\n        $onProgress = $options['on_progress'] ?? null;\n        $subnets = $this->subnets;\n        $ipFlags = $this->ipFlags;\n\n        $options['on_progress'] = static function (int $dlNow, int $dlSize, array $info) use ($onProgress, $subnets, $ipFlags): void {\n            static $lastPrimaryIp = '';\n\n            if (!\\in_array($info['primary_ip'] ?? '', ['', $lastPrimaryIp], true)) {\n                self::ipCheck($info['primary_ip'], $subnets, $ipFlags, null, $info['url']);\n                $lastPrimaryIp = $info['primary_ip'];\n            }\n\n            null !== $onProgress && $onProgress($dlNow, $dlSize, $info);\n        };\n\n        if (0 >= $maxRedirects = $options['max_redirects']) {\n            return new AsyncResponse($this->client, $method, $url, $options);\n        }\n\n        $options['max_redirects'] = 0;\n        $redirectHeaders['with_auth'] = $redirectHeaders['no_auth'] = $options['headers'];\n\n        if (isset($options['normalized_headers']['host']) || isset($options['normalized_headers']['authorization']) || isset($options['normalized_headers']['cookie'])) {\n            $redirectHeaders['no_auth'] = array_filter($redirectHeaders['no_auth'], static function ($h) {\n                return 0 !== stripos($h, 'Host:') && 0 !== stripos($h, 'Authorization:') && 0 !== stripos($h, 'Cookie:');\n            });\n        }\n\n        return new AsyncResponse($this->client, $method, $url, $options, static function (ChunkInterface $chunk, AsyncContext $context) use (&$method, &$options, $maxRedirects, &$redirectHeaders, $subnets, $ipFlags, $dnsCache): \\Generator {\n            if (null !== $chunk->getError() || $chunk->isTimeout() || !$chunk->isFirst()) {\n                yield $chunk;\n\n                return;\n            }\n\n            $statusCode = $context->getStatusCode();\n\n            if ($statusCode < 300 || 400 <= $statusCode || null === $url = $context->getInfo('redirect_url')) {\n                $context->passthru();\n\n                yield $chunk;\n\n                return;\n            }\n\n            $host = parse_url($url, \\PHP_URL_HOST);\n            $ip = self::dnsResolve($dnsCache, $host, $ipFlags, $options);\n            self::ipCheck($ip, $subnets, $ipFlags, $host, $url);\n\n            // Do like curl and browsers: turn POST to GET on 301, 302 and 303\n            if (303 === $statusCode || 'POST' === $method && \\in_array($statusCode, [301, 302], true)) {\n                $method = 'HEAD' === $method ? 'HEAD' : 'GET';\n                unset($options['body'], $options['json']);\n\n                if (isset($options['normalized_headers']['content-length']) || isset($options['normalized_headers']['content-type']) || isset($options['normalized_headers']['transfer-encoding'])) {\n                    $filterContentHeaders = static function ($h) {\n                        return 0 !== stripos($h, 'Content-Length:') && 0 !== stripos($h, 'Content-Type:') && 0 !== stripos($h, 'Transfer-Encoding:');\n                    };\n                    $options['headers'] = array_filter($options['headers'], $filterContentHeaders);\n                    $redirectHeaders['no_auth'] = array_filter($redirectHeaders['no_auth'], $filterContentHeaders);\n                    $redirectHeaders['with_auth'] = array_filter($redirectHeaders['with_auth'], $filterContentHeaders);\n                }\n            }\n\n            // Authorization and Cookie headers MUST NOT follow except for the initial host name\n            $port = parse_url($url, \\PHP_URL_PORT);\n            $options['headers'] = $redirectHeaders['host'] === $host && ($redirectHeaders['port'] ?? null) === $port ? $redirectHeaders['with_auth'] : $redirectHeaders['no_auth'];\n\n            static $redirectCount = 0;\n            $context->setInfo('redirect_count', ++$redirectCount);\n\n            $context->replaceRequest($method, $url, $options);\n\n            if ($redirectCount >= $maxRedirects) {\n                $context->passthru();\n            }\n        });\n    }\n\n    public function setLogger(LoggerInterface $logger): void\n    {\n        if ($this->client instanceof LoggerAwareInterface) {\n            $this->client->setLogger($logger);\n        }\n    }\n\n    public function withOptions(array $options): static\n    {\n        $clone = clone $this;\n        $clone->client = $this->client->withOptions($options);\n        $clone->defaultOptions = self::mergeDefaultOptions($options, $this->defaultOptions);\n\n        return $clone;\n    }\n\n    public function reset(): void\n    {\n        $this->dnsCache->exchangeArray([]);\n\n        if ($this->client instanceof ResetInterface) {\n            $this->client->reset();\n        }\n    }\n\n    private static function dnsResolve(\\ArrayObject $dnsCache, string $host, int $ipFlags, array &$options): string\n    {\n        if ($ip = filter_var(trim($host, '[]'), \\FILTER_VALIDATE_IP) ?: $options['resolve'][$host] ?? false) {\n            return $ip;\n        }\n\n        if ($dnsCache->offsetExists($host)) {\n            return $dnsCache[$host];\n        }\n\n        if ((\\FILTER_FLAG_IPV4 & $ipFlags) && $ip = gethostbynamel($host)) {\n            return $options['resolve'][$host] = $dnsCache[$host] = $ip[0];\n        }\n\n        if (!(\\FILTER_FLAG_IPV6 & $ipFlags)) {\n            return $host;\n        }\n\n        if ($ip = dns_get_record($host, \\DNS_AAAA)) {\n            $ip = $ip[0]['ipv6'];\n        } elseif (\\extension_loaded('sockets')) {\n            if (!$info = socket_addrinfo_lookup($host, 0, ['ai_socktype' => \\SOCK_STREAM, 'ai_family' => \\AF_INET6])) {\n                return $host;\n            }\n\n            $ip = socket_addrinfo_explain($info[0])['ai_addr']['sin6_addr'];\n        } elseif ('localhost' === $host || 'localhost.' === $host) {\n            $ip = '::1';\n        } else {\n            return $host;\n        }\n\n        return $options['resolve'][$host] = $dnsCache[$host] = $ip;\n    }\n\n    private static function ipCheck(string $ip, ?array $subnets, int $ipFlags, ?string $host, string $url): void\n    {\n        if (null === $subnets) {\n            // Quick check, but not reliable enough, see https://github.com/php/php-src/issues/16944\n            $ipFlags |= \\FILTER_FLAG_NO_PRIV_RANGE | \\FILTER_FLAG_NO_RES_RANGE;\n        }\n\n        if (false !== filter_var($ip, \\FILTER_VALIDATE_IP, $ipFlags) && !IpUtils::checkIp($ip, $subnets ?? IpUtils::PRIVATE_SUBNETS)) {\n            return;\n        }\n\n        if (null !== $host) {\n            $type = 'Host';\n        } else {\n            $host = $ip;\n            $type = 'IP';\n        }\n\n        throw new TransportException($type.\\sprintf(' \"%s\" is blocked for \"%s\".', $host, $url));\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/Psr18Client.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient;\n\nuse Http\\Discovery\\Psr17Factory;\nuse Http\\Discovery\\Psr17FactoryDiscovery;\nuse Nyholm\\Psr7\\Factory\\Psr17Factory as NyholmPsr17Factory;\nuse Nyholm\\Psr7\\Request;\nuse Nyholm\\Psr7\\Uri;\nuse Psr\\Http\\Client\\ClientInterface;\nuse Psr\\Http\\Client\\NetworkExceptionInterface;\nuse Psr\\Http\\Client\\RequestExceptionInterface;\nuse Psr\\Http\\Message\\RequestFactoryInterface;\nuse Psr\\Http\\Message\\RequestInterface;\nuse Psr\\Http\\Message\\ResponseFactoryInterface;\nuse Psr\\Http\\Message\\ResponseInterface;\nuse Psr\\Http\\Message\\StreamFactoryInterface;\nuse Psr\\Http\\Message\\StreamInterface;\nuse Psr\\Http\\Message\\UriFactoryInterface;\nuse Psr\\Http\\Message\\UriInterface;\nuse Symfony\\Component\\HttpClient\\Internal\\HttplugWaitLoop;\nuse Symfony\\Contracts\\HttpClient\\Exception\\TransportExceptionInterface;\nuse Symfony\\Contracts\\HttpClient\\HttpClientInterface;\nuse Symfony\\Contracts\\Service\\ResetInterface;\n\nif (!interface_exists(ClientInterface::class)) {\n    throw new \\LogicException('You cannot use the \"Symfony\\Component\\HttpClient\\Psr18Client\" as the \"psr/http-client\" package is not installed. Try running \"composer require php-http/discovery psr/http-client-implementation:*\".');\n}\n\nif (!interface_exists(RequestFactoryInterface::class)) {\n    throw new \\LogicException('You cannot use the \"Symfony\\Component\\HttpClient\\Psr18Client\" as the \"psr/http-factory\" package is not installed. Try running \"composer require php-http/discovery psr/http-factory-implementation:*\".');\n}\n\n/**\n * An adapter to turn a Symfony HttpClientInterface into a PSR-18 ClientInterface.\n *\n * Run \"composer require php-http/discovery psr/http-client-implementation:*\"\n * to get the required dependencies.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n */\nfinal class Psr18Client implements ClientInterface, RequestFactoryInterface, StreamFactoryInterface, UriFactoryInterface, ResetInterface\n{\n    private HttpClientInterface $client;\n    private ResponseFactoryInterface $responseFactory;\n    private StreamFactoryInterface $streamFactory;\n\n    public function __construct(?HttpClientInterface $client = null, ?ResponseFactoryInterface $responseFactory = null, ?StreamFactoryInterface $streamFactory = null)\n    {\n        $this->client = $client ?? HttpClient::create();\n        $streamFactory ??= $responseFactory instanceof StreamFactoryInterface ? $responseFactory : null;\n\n        if (null === $responseFactory || null === $streamFactory) {\n            if (class_exists(Psr17Factory::class)) {\n                $psr17Factory = new Psr17Factory();\n            } elseif (class_exists(NyholmPsr17Factory::class)) {\n                $psr17Factory = new NyholmPsr17Factory();\n            } else {\n                throw new \\LogicException('You cannot use the \"Symfony\\Component\\HttpClient\\Psr18Client\" as no PSR-17 factories have been provided. Try running \"composer require php-http/discovery psr/http-factory-implementation:*\".');\n            }\n\n            $responseFactory ??= $psr17Factory;\n            $streamFactory ??= $psr17Factory;\n        }\n\n        $this->responseFactory = $responseFactory;\n        $this->streamFactory = $streamFactory;\n    }\n\n    public function withOptions(array $options): static\n    {\n        $clone = clone $this;\n        $clone->client = $clone->client->withOptions($options);\n\n        return $clone;\n    }\n\n    public function sendRequest(RequestInterface $request): ResponseInterface\n    {\n        try {\n            $body = $request->getBody();\n\n            if ($body->isSeekable()) {\n                try {\n                    $body->seek(0);\n                } catch (\\RuntimeException) {\n                    // ignore\n                }\n            }\n\n            $options = [\n                'headers' => $request->getHeaders(),\n                'body' => $body->getContents(),\n            ];\n\n            if ('1.0' === $request->getProtocolVersion()) {\n                $options['http_version'] = '1.0';\n            }\n\n            $response = $this->client->request($request->getMethod(), (string) $request->getUri(), $options);\n\n            return HttplugWaitLoop::createPsr7Response($this->responseFactory, $this->streamFactory, $this->client, $response, false);\n        } catch (TransportExceptionInterface $e) {\n            if ($e instanceof \\InvalidArgumentException) {\n                throw new Psr18RequestException($e, $request);\n            }\n\n            throw new Psr18NetworkException($e, $request);\n        }\n    }\n\n    public function createRequest(string $method, $uri): RequestInterface\n    {\n        if ($this->responseFactory instanceof RequestFactoryInterface) {\n            return $this->responseFactory->createRequest($method, $uri);\n        }\n\n        if (class_exists(Psr17FactoryDiscovery::class)) {\n            return Psr17FactoryDiscovery::findRequestFactory()->createRequest($method, $uri);\n        }\n\n        if (class_exists(Request::class)) {\n            return new Request($method, $uri);\n        }\n\n        throw new \\LogicException(\\sprintf('You cannot use \"%s()\" as no PSR-17 factories have been found. Try running \"composer require php-http/discovery psr/http-factory-implementation:*\".', __METHOD__));\n    }\n\n    public function createStream(string $content = ''): StreamInterface\n    {\n        $stream = $this->streamFactory->createStream($content);\n\n        if ($stream->isSeekable()) {\n            try {\n                $stream->seek(0);\n            } catch (\\RuntimeException) {\n                // ignore\n            }\n        }\n\n        return $stream;\n    }\n\n    public function createStreamFromFile(string $filename, string $mode = 'r'): StreamInterface\n    {\n        return $this->streamFactory->createStreamFromFile($filename, $mode);\n    }\n\n    public function createStreamFromResource($resource): StreamInterface\n    {\n        return $this->streamFactory->createStreamFromResource($resource);\n    }\n\n    public function createUri(string $uri = ''): UriInterface\n    {\n        if ($this->responseFactory instanceof UriFactoryInterface) {\n            return $this->responseFactory->createUri($uri);\n        }\n\n        if (class_exists(Psr17FactoryDiscovery::class)) {\n            return Psr17FactoryDiscovery::findUrlFactory()->createUri($uri);\n        }\n\n        if (class_exists(Uri::class)) {\n            return new Uri($uri);\n        }\n\n        throw new \\LogicException(\\sprintf('You cannot use \"%s()\" as no PSR-17 factories have been found. Try running \"composer require php-http/discovery psr/http-factory-implementation:*\".', __METHOD__));\n    }\n\n    public function reset(): void\n    {\n        if ($this->client instanceof ResetInterface) {\n            $this->client->reset();\n        }\n    }\n}\n\n/**\n * @internal\n */\nclass Psr18NetworkException extends \\RuntimeException implements NetworkExceptionInterface\n{\n    private RequestInterface $request;\n\n    public function __construct(TransportExceptionInterface $e, RequestInterface $request)\n    {\n        parent::__construct($e->getMessage(), 0, $e);\n        $this->request = $request;\n    }\n\n    public function getRequest(): RequestInterface\n    {\n        return $this->request;\n    }\n}\n\n/**\n * @internal\n */\nclass Psr18RequestException extends \\InvalidArgumentException implements RequestExceptionInterface\n{\n    private RequestInterface $request;\n\n    public function __construct(TransportExceptionInterface $e, RequestInterface $request)\n    {\n        parent::__construct($e->getMessage(), 0, $e);\n        $this->request = $request;\n    }\n\n    public function getRequest(): RequestInterface\n    {\n        return $this->request;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/README.md",
    "content": "HttpClient component\n====================\n\nThe HttpClient component provides powerful methods to fetch HTTP resources synchronously or asynchronously.\n\nSponsor\n-------\n\nThe HttpClient component for Symfony 6.4 is [backed][1] by [Innovative Web AG][2].\n\nInnovative Web AG (i-web) is a specialist for web, applications and the\ndigitalisation of the public sector based in Switzerland. With their i-CMS,\npublic authorities and institutions implement modern websites and eGovernment\nportals and offer user-friendly eServices for residents and companies.\n\nHelp Symfony by [sponsoring][3] its development!\n\nResources\n---------\n\n * [Documentation](https://symfony.com/doc/current/components/http_client.html)\n * [Contributing](https://symfony.com/doc/current/contributing/index.html)\n * [Report issues](https://github.com/symfony/symfony/issues) and\n   [send Pull Requests](https://github.com/symfony/symfony/pulls)\n   in the [main Symfony repository](https://github.com/symfony/symfony)\n\n[1]: https://symfony.com/backers\n[2]: https://www.i-web.ch\n[3]: https://symfony.com/sponsor\n"
  },
  {
    "path": "server/vendor/symfony/http-client/Response/AmpResponse.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient\\Response;\n\nuse Amp\\ByteStream\\StreamException;\nuse Amp\\CancellationTokenSource;\nuse Amp\\Coroutine;\nuse Amp\\Deferred;\nuse Amp\\Http\\Client\\HttpException;\nuse Amp\\Http\\Client\\Request;\nuse Amp\\Http\\Client\\Response;\nuse Amp\\Loop;\nuse Amp\\Promise;\nuse Amp\\Success;\nuse Psr\\Log\\LoggerInterface;\nuse Symfony\\Component\\HttpClient\\Chunk\\FirstChunk;\nuse Symfony\\Component\\HttpClient\\Chunk\\InformationalChunk;\nuse Symfony\\Component\\HttpClient\\Exception\\InvalidArgumentException;\nuse Symfony\\Component\\HttpClient\\Exception\\TransportException;\nuse Symfony\\Component\\HttpClient\\HttpClientTrait;\nuse Symfony\\Component\\HttpClient\\Internal\\AmpBody;\nuse Symfony\\Component\\HttpClient\\Internal\\AmpClientState;\nuse Symfony\\Component\\HttpClient\\Internal\\Canary;\nuse Symfony\\Component\\HttpClient\\Internal\\ClientState;\nuse Symfony\\Contracts\\HttpClient\\ResponseInterface;\n\n/**\n * @author Nicolas Grekas <p@tchwork.com>\n *\n * @internal\n */\nfinal class AmpResponse implements ResponseInterface, StreamableInterface\n{\n    use CommonResponseTrait;\n    use TransportResponseTrait;\n\n    private static string $nextId = 'a';\n\n    private AmpClientState $multi;\n    private ?array $options;\n    private \\Closure $onProgress;\n\n    private static ?string $delay = null;\n\n    /**\n     * @internal\n     */\n    public function __construct(AmpClientState $multi, Request $request, array $options, ?LoggerInterface $logger)\n    {\n        $this->multi = $multi;\n        $this->options = &$options;\n        $this->logger = $logger;\n        $this->timeout = $options['timeout'];\n        $this->shouldBuffer = $options['buffer'];\n\n        if ($this->inflate = \\extension_loaded('zlib') && !$request->hasHeader('accept-encoding')) {\n            $request->setHeader('Accept-Encoding', 'gzip');\n        }\n\n        $this->initializer = static fn (self $response) => null !== $response->options;\n\n        $info = &$this->info;\n        $headers = &$this->headers;\n        $canceller = new CancellationTokenSource();\n        $handle = &$this->handle;\n\n        $info['url'] = (string) $request->getUri();\n        $info['http_method'] = $request->getMethod();\n        $info['start_time'] = null;\n        $info['redirect_url'] = null;\n        $info['original_url'] = $info['url'];\n        $info['redirect_time'] = 0.0;\n        $info['redirect_count'] = 0;\n        $info['size_upload'] = 0.0;\n        $info['size_download'] = 0.0;\n        $info['upload_content_length'] = -1.0;\n        $info['download_content_length'] = -1.0;\n        $info['user_data'] = $options['user_data'];\n        $info['max_duration'] = $options['max_duration'];\n        $info['debug'] = '';\n\n        $onProgress = $options['on_progress'] ?? static function () {};\n        $onProgress = $this->onProgress = static function () use (&$info, $onProgress) {\n            $info['total_time'] = microtime(true) - $info['start_time'];\n            $onProgress((int) $info['size_download'], ((int) (1 + $info['download_content_length']) ?: 1) - 1, (array) $info);\n        };\n\n        $pauseDeferred = new Deferred();\n        $pause = new Success();\n\n        $throttleWatcher = null;\n\n        $this->id = $id = self::$nextId;\n        self::$nextId = str_increment(self::$nextId);\n        Loop::defer(static function () use ($request, $multi, $id, &$info, &$headers, $canceller, &$options, $onProgress, &$handle, $logger, &$pause) {\n            return new Coroutine(self::generateResponse($request, $multi, $id, $info, $headers, $canceller, $options, $onProgress, $handle, $logger, $pause));\n        });\n\n        $info['pause_handler'] = static function (float $duration) use (&$throttleWatcher, &$pauseDeferred, &$pause) {\n            if (null !== $throttleWatcher) {\n                Loop::cancel($throttleWatcher);\n            }\n\n            $pause = $pauseDeferred->promise();\n\n            if ($duration <= 0) {\n                $deferred = $pauseDeferred;\n                $pauseDeferred = new Deferred();\n                $deferred->resolve();\n            } else {\n                $throttleWatcher = Loop::delay(ceil(1000 * $duration), static function () use (&$pauseDeferred) {\n                    $deferred = $pauseDeferred;\n                    $pauseDeferred = new Deferred();\n                    $deferred->resolve();\n                });\n            }\n        };\n\n        $multi->lastTimeout = null;\n        $multi->openHandles[$id] = $id;\n        ++$multi->responseCount;\n\n        $this->canary = new Canary(static function () use ($canceller, $multi, $id) {\n            $canceller->cancel();\n            unset($multi->openHandles[$id], $multi->handlesActivity[$id]);\n        });\n    }\n\n    public function getInfo(?string $type = null): mixed\n    {\n        return null !== $type ? $this->info[$type] ?? null : $this->info;\n    }\n\n    public function __serialize(): array\n    {\n        throw new \\BadMethodCallException('Cannot serialize '.__CLASS__);\n    }\n\n    public function __unserialize(array $data): void\n    {\n        throw new \\BadMethodCallException('Cannot unserialize '.__CLASS__);\n    }\n\n    public function __destruct()\n    {\n        try {\n            $this->doDestruct();\n        } finally {\n            // Clear the DNS cache when all requests completed\n            if (0 >= --$this->multi->responseCount) {\n                $this->multi->responseCount = 0;\n                $this->multi->dnsCache = [];\n            }\n        }\n    }\n\n    private static function schedule(self $response, array &$runningResponses): void\n    {\n        if (isset($runningResponses[0])) {\n            $runningResponses[0][1][$response->id] = $response;\n        } else {\n            $runningResponses[0] = [$response->multi, [$response->id => $response]];\n        }\n\n        if (!isset($response->multi->openHandles[$response->id])) {\n            $response->multi->handlesActivity[$response->id][] = null;\n            $response->multi->handlesActivity[$response->id][] = null !== $response->info['error'] ? new TransportException($response->info['error']) : null;\n        }\n    }\n\n    /**\n     * @param AmpClientState $multi\n     */\n    private static function perform(ClientState $multi, ?array $responses = null): void\n    {\n        foreach ($responses ?? [] as $response) {\n            try {\n                if ($response->info['start_time']) {\n                    $response->info['total_time'] = microtime(true) - $response->info['start_time'];\n                    ($response->onProgress)();\n                }\n            } catch (\\Throwable $e) {\n                $multi->handlesActivity[$response->id][] = null;\n                $multi->handlesActivity[$response->id][] = $e;\n            }\n        }\n    }\n\n    /**\n     * @param AmpClientState $multi\n     */\n    private static function select(ClientState $multi, float $timeout): int\n    {\n        $timeout += hrtime(true) / 1E9;\n        self::$delay = Loop::defer(static function () use ($timeout) {\n            if (0 < $timeout -= hrtime(true) / 1E9) {\n                self::$delay = Loop::delay(ceil(1000 * $timeout), Loop::stop(...));\n            } else {\n                Loop::stop();\n            }\n        });\n\n        Loop::run();\n\n        return null === self::$delay ? 1 : 0;\n    }\n\n    private static function generateResponse(Request $request, AmpClientState $multi, string $id, array &$info, array &$headers, CancellationTokenSource $canceller, array &$options, \\Closure $onProgress, &$handle, ?LoggerInterface $logger, Promise &$pause): \\Generator\n    {\n        $request->setInformationalResponseHandler(static function (Response $response) use ($multi, $id, &$info, &$headers) {\n            self::addResponseHeaders($response, $info, $headers);\n            $multi->handlesActivity[$id][] = new InformationalChunk($response->getStatus(), $response->getHeaders());\n            self::stopLoop();\n        });\n\n        try {\n            /** @var Response $response */\n            if (null === $response = yield from self::getPushedResponse($request, $multi, $info, $headers, $options, $logger)) {\n                $logger?->info(\\sprintf('Request: \"%s %s\"', $info['http_method'], $info['url']));\n\n                $response = yield from self::followRedirects($request, $multi, $info, $headers, $canceller, $options, $onProgress, $handle, $logger, $pause);\n            }\n\n            $options = null;\n\n            $multi->handlesActivity[$id][] = new FirstChunk();\n\n            if ('HEAD' === $response->getRequest()->getMethod() || \\in_array($info['http_code'], [204, 304], true)) {\n                $multi->handlesActivity[$id][] = null;\n                $multi->handlesActivity[$id][] = null;\n                self::stopLoop();\n\n                return;\n            }\n\n            if ($response->hasHeader('content-length')) {\n                $info['download_content_length'] = (float) $response->getHeader('content-length');\n            }\n\n            $body = $response->getBody();\n\n            while (true) {\n                self::stopLoop();\n\n                yield $pause;\n\n                if (null === $data = yield $body->read()) {\n                    break;\n                }\n\n                $info['size_download'] += \\strlen($data);\n                $multi->handlesActivity[$id][] = $data;\n            }\n\n            $multi->handlesActivity[$id][] = null;\n            $multi->handlesActivity[$id][] = null;\n        } catch (\\Throwable $e) {\n            $multi->handlesActivity[$id][] = null;\n            $multi->handlesActivity[$id][] = $e;\n        } finally {\n            $info['download_content_length'] = $info['size_download'];\n        }\n\n        self::stopLoop();\n    }\n\n    private static function followRedirects(Request $originRequest, AmpClientState $multi, array &$info, array &$headers, CancellationTokenSource $canceller, array $options, \\Closure $onProgress, &$handle, ?LoggerInterface $logger, Promise &$pause): \\Generator\n    {\n        yield $pause;\n\n        $originRequest->setBody(new AmpBody($options['body'], $info, $onProgress));\n        $response = yield $multi->request($options, $originRequest, $canceller->getToken(), $info, $onProgress, $handle);\n        $previousUrl = null;\n\n        while (true) {\n            self::addResponseHeaders($response, $info, $headers);\n            $status = $response->getStatus();\n\n            if (!\\in_array($status, [301, 302, 303, 307, 308], true) || null === $location = $response->getHeader('location')) {\n                return $response;\n            }\n\n            $urlResolver = new class {\n                use HttpClientTrait {\n                    parseUrl as public;\n                    resolveUrl as public;\n                }\n            };\n\n            try {\n                $previousUrl ??= $urlResolver::parseUrl($info['url']);\n                $location = $urlResolver::parseUrl($location);\n                $location = $urlResolver::resolveUrl($location, $previousUrl);\n                $info['redirect_url'] = implode('', $location);\n            } catch (InvalidArgumentException) {\n                return $response;\n            }\n\n            if (0 >= $options['max_redirects'] || $info['redirect_count'] >= $options['max_redirects']) {\n                return $response;\n            }\n\n            $logger?->info(\\sprintf('Redirecting: \"%s %s\"', $status, $info['url']));\n\n            try {\n                // Discard body of redirects\n                while (null !== yield $response->getBody()->read()) {\n                }\n            } catch (HttpException|StreamException) {\n                // Ignore streaming errors on previous responses\n            }\n\n            ++$info['redirect_count'];\n            $info['url'] = $info['redirect_url'];\n            $info['redirect_url'] = null;\n            $previousUrl = $location;\n\n            $request = new Request($info['url'], $info['http_method']);\n            $request->setProtocolVersions($originRequest->getProtocolVersions());\n            $request->setTcpConnectTimeout($originRequest->getTcpConnectTimeout());\n            $request->setTlsHandshakeTimeout($originRequest->getTlsHandshakeTimeout());\n            $request->setTransferTimeout($originRequest->getTransferTimeout());\n            $request->setBodySizeLimit(0);\n            if (method_exists($request, 'setInactivityTimeout')) {\n                $request->setInactivityTimeout(0);\n            }\n\n            if (303 === $status || \\in_array($status, [301, 302], true) && 'POST' === $response->getRequest()->getMethod()) {\n                // Do like curl and browsers: turn POST to GET on 301, 302 and 303\n                $originRequest->removeHeader('transfer-encoding');\n                $originRequest->removeHeader('content-length');\n                $originRequest->removeHeader('content-type');\n\n                $info['http_method'] = 'HEAD' === $response->getRequest()->getMethod() ? 'HEAD' : 'GET';\n                $request->setMethod($info['http_method']);\n            } else {\n                $request->setBody(AmpBody::rewind($response->getRequest()->getBody()));\n            }\n\n            foreach ($originRequest->getRawHeaders() as [$name, $value]) {\n                $request->addHeader($name, $value);\n            }\n\n            if ($request->getUri()->getAuthority() !== $originRequest->getUri()->getAuthority()) {\n                $request->removeHeader('authorization');\n                $request->removeHeader('cookie');\n                $request->removeHeader('host');\n            }\n\n            yield $pause;\n\n            $response = yield $multi->request($options, $request, $canceller->getToken(), $info, $onProgress, $handle);\n            $info['redirect_time'] = microtime(true) - $info['start_time'];\n        }\n    }\n\n    private static function addResponseHeaders(Response $response, array &$info, array &$headers): void\n    {\n        $info['http_code'] = $response->getStatus();\n\n        if ($headers) {\n            $info['debug'] .= \"< \\r\\n\";\n            $headers = [];\n        }\n\n        $h = \\sprintf('HTTP/%s %s %s', $response->getProtocolVersion(), $response->getStatus(), $response->getReason());\n        $info['debug'] .= \"< {$h}\\r\\n\";\n        $info['response_headers'][] = $h;\n\n        foreach ($response->getRawHeaders() as [$name, $value]) {\n            $headers[strtolower($name)][] = $value;\n            $h = $name.': '.$value;\n            $info['debug'] .= \"< {$h}\\r\\n\";\n            $info['response_headers'][] = $h;\n        }\n\n        $info['debug'] .= \"< \\r\\n\";\n    }\n\n    /**\n     * Accepts pushed responses only if their headers related to authentication match the request.\n     */\n    private static function getPushedResponse(Request $request, AmpClientState $multi, array &$info, array &$headers, array $options, ?LoggerInterface $logger): \\Generator\n    {\n        if ('' !== $options['body']) {\n            return null;\n        }\n\n        $authority = $request->getUri()->getAuthority();\n\n        foreach ($multi->pushedResponses[$authority] ?? [] as $i => [$pushedUrl, $pushDeferred, $pushedRequest, $pushedResponse, $parentOptions]) {\n            if ($info['url'] !== $pushedUrl || $info['http_method'] !== $pushedRequest->getMethod()) {\n                continue;\n            }\n\n            foreach ($parentOptions as $k => $v) {\n                if ($options[$k] !== $v) {\n                    continue 2;\n                }\n            }\n\n            foreach (['authorization', 'cookie', 'range', 'proxy-authorization'] as $k) {\n                if ($pushedRequest->getHeaderArray($k) !== $request->getHeaderArray($k)) {\n                    continue 2;\n                }\n            }\n\n            $response = yield $pushedResponse;\n\n            foreach ($response->getHeaderArray('vary') as $vary) {\n                foreach (preg_split('/\\s*+,\\s*+/', $vary) as $v) {\n                    if ('*' === $v || ($pushedRequest->getHeaderArray($v) !== $request->getHeaderArray($v) && 'accept-encoding' !== strtolower($v))) {\n                        $logger?->debug(\\sprintf('Skipping pushed response: \"%s\"', $info['url']));\n                        continue 3;\n                    }\n                }\n            }\n\n            $pushDeferred->resolve();\n            $logger?->debug(\\sprintf('Accepting pushed response: \"%s %s\"', $info['http_method'], $info['url']));\n            self::addResponseHeaders($response, $info, $headers);\n            unset($multi->pushedResponses[$authority][$i]);\n\n            if (!$multi->pushedResponses[$authority]) {\n                unset($multi->pushedResponses[$authority]);\n            }\n\n            return $response;\n        }\n    }\n\n    private static function stopLoop(): void\n    {\n        if (null !== self::$delay) {\n            Loop::cancel(self::$delay);\n            self::$delay = null;\n        }\n\n        Loop::defer(Loop::stop(...));\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/Response/AsyncContext.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient\\Response;\n\nuse Symfony\\Component\\HttpClient\\Chunk\\DataChunk;\nuse Symfony\\Component\\HttpClient\\Chunk\\LastChunk;\nuse Symfony\\Component\\HttpClient\\Exception\\TransportException;\nuse Symfony\\Contracts\\HttpClient\\ChunkInterface;\nuse Symfony\\Contracts\\HttpClient\\HttpClientInterface;\nuse Symfony\\Contracts\\HttpClient\\ResponseInterface;\n\n/**\n * A DTO to work with AsyncResponse.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n */\nfinal class AsyncContext\n{\n    /** @var callable|null */\n    private $passthru;\n    private HttpClientInterface $client;\n    private ResponseInterface $response;\n    private array $info = [];\n    /** @var resource|null */\n    private $content;\n    private int $offset;\n\n    /**\n     * @param resource|null $content\n     */\n    public function __construct(?callable &$passthru, HttpClientInterface $client, ResponseInterface &$response, array &$info, $content, int $offset)\n    {\n        $this->passthru = &$passthru;\n        $this->client = $client;\n        $this->response = &$response;\n        $this->info = &$info;\n        $this->content = $content;\n        $this->offset = $offset;\n    }\n\n    /**\n     * Returns the HTTP status without consuming the response.\n     */\n    public function getStatusCode(): int\n    {\n        return $this->response->getInfo('http_code');\n    }\n\n    /**\n     * Returns the headers without consuming the response.\n     */\n    public function getHeaders(): array\n    {\n        $headers = [];\n\n        foreach ($this->response->getInfo('response_headers') as $h) {\n            if (11 <= \\strlen($h) && '/' === $h[4] && preg_match('#^HTTP/\\d+(?:\\.\\d+)? ([123456789]\\d\\d)(?: |$)#', $h, $m)) {\n                $headers = [];\n            } elseif (2 === \\count($m = explode(':', $h, 2))) {\n                $headers[strtolower($m[0])][] = ltrim($m[1]);\n            }\n        }\n\n        return $headers;\n    }\n\n    /**\n     * @return resource|null The PHP stream resource where the content is buffered, if it is\n     */\n    public function getContent()\n    {\n        return $this->content;\n    }\n\n    /**\n     * Creates a new chunk of content.\n     */\n    public function createChunk(string $data): ChunkInterface\n    {\n        return new DataChunk($this->offset, $data);\n    }\n\n    /**\n     * Pauses the request for the given number of seconds.\n     */\n    public function pause(float $duration): void\n    {\n        if (\\is_callable($pause = $this->response->getInfo('pause_handler'))) {\n            $pause($duration);\n        } elseif (0 < $duration) {\n            usleep((int) (1E6 * $duration));\n        }\n    }\n\n    /**\n     * Cancels the request and returns the last chunk to yield.\n     */\n    public function cancel(): ChunkInterface\n    {\n        $this->info['canceled'] = true;\n        $this->info['error'] = 'Response has been canceled.';\n        $this->response->cancel();\n\n        return new LastChunk();\n    }\n\n    /**\n     * Returns the current info of the response.\n     */\n    public function getInfo(?string $type = null): mixed\n    {\n        if (null !== $type) {\n            return $this->info[$type] ?? $this->response->getInfo($type);\n        }\n\n        return $this->info + $this->response->getInfo();\n    }\n\n    /**\n     * Attaches an info to the response.\n     *\n     * @return $this\n     */\n    public function setInfo(string $type, mixed $value): static\n    {\n        if ('canceled' === $type && $value !== $this->info['canceled']) {\n            throw new \\LogicException('You cannot set the \"canceled\" info directly.');\n        }\n\n        if (null === $value) {\n            unset($this->info[$type]);\n        } else {\n            $this->info[$type] = $value;\n        }\n\n        return $this;\n    }\n\n    /**\n     * Returns the currently processed response.\n     */\n    public function getResponse(): ResponseInterface\n    {\n        return $this->response;\n    }\n\n    /**\n     * Replaces the currently processed response by doing a new request.\n     */\n    public function replaceRequest(string $method, string $url, array $options = []): ResponseInterface\n    {\n        $this->info['previous_info'][] = $info = $this->response->getInfo();\n        if (null !== $onProgress = $options['on_progress'] ?? null) {\n            $thisInfo = &$this->info;\n            $options['on_progress'] = static function (int $dlNow, int $dlSize, array $info) use (&$thisInfo, $onProgress) {\n                $onProgress($dlNow, $dlSize, $thisInfo + $info);\n            };\n        }\n        if (0 < ($info['max_duration'] ?? 0) && 0 < ($info['total_time'] ?? 0)) {\n            if (0 >= $options['max_duration'] = $info['max_duration'] - $info['total_time']) {\n                throw new TransportException(\\sprintf('Max duration was reached for \"%s\".', $info['url']));\n            }\n        }\n\n        return $this->response = $this->client->request($method, $url, ['buffer' => false] + $options);\n    }\n\n    /**\n     * Replaces the currently processed response by another one.\n     */\n    public function replaceResponse(ResponseInterface $response): ResponseInterface\n    {\n        $this->info['previous_info'][] = $this->response->getInfo();\n\n        return $this->response = $response;\n    }\n\n    /**\n     * Replaces or removes the chunk filter iterator.\n     *\n     * @param ?callable(ChunkInterface, self): ?\\Iterator $passthru\n     */\n    public function passthru(?callable $passthru = null): void\n    {\n        $this->passthru = $passthru ?? static function ($chunk, $context) {\n            $context->passthru = null;\n\n            yield $chunk;\n        };\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/Response/AsyncResponse.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient\\Response;\n\nuse Symfony\\Component\\HttpClient\\Chunk\\ErrorChunk;\nuse Symfony\\Component\\HttpClient\\Chunk\\LastChunk;\nuse Symfony\\Component\\HttpClient\\Exception\\TransportException;\nuse Symfony\\Contracts\\HttpClient\\ChunkInterface;\nuse Symfony\\Contracts\\HttpClient\\Exception\\ExceptionInterface;\nuse Symfony\\Contracts\\HttpClient\\Exception\\HttpExceptionInterface;\nuse Symfony\\Contracts\\HttpClient\\Exception\\TransportExceptionInterface;\nuse Symfony\\Contracts\\HttpClient\\HttpClientInterface;\nuse Symfony\\Contracts\\HttpClient\\ResponseInterface;\n\n/**\n * Provides a single extension point to process a response's content stream.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n */\nclass AsyncResponse implements ResponseInterface, StreamableInterface\n{\n    use CommonResponseTrait;\n\n    private const FIRST_CHUNK_YIELDED = 1;\n    private const LAST_CHUNK_YIELDED = 2;\n\n    private ?HttpClientInterface $client;\n    private ResponseInterface $response;\n    private array $info = ['canceled' => false];\n    /** @var callable|null */\n    private $passthru;\n    private ?\\Iterator $stream = null;\n    private ?int $yieldedState = null;\n\n    /**\n     * @param ?callable(ChunkInterface, AsyncContext): ?\\Iterator $passthru\n     */\n    public function __construct(HttpClientInterface $client, string $method, string $url, array $options, ?callable $passthru = null)\n    {\n        $this->client = $client;\n        $this->shouldBuffer = $options['buffer'] ?? true;\n\n        if (null !== $onProgress = $options['on_progress'] ?? null) {\n            $thisInfo = &$this->info;\n            $options['on_progress'] = static function (int $dlNow, int $dlSize, array $info) use (&$thisInfo, $onProgress) {\n                $onProgress($dlNow, $dlSize, $thisInfo + $info);\n            };\n        }\n        $this->response = $client->request($method, $url, ['buffer' => false] + $options);\n        $this->passthru = $passthru;\n        $this->initializer = static function (self $response, ?float $timeout = null) {\n            if (null === $response->shouldBuffer) {\n                return false;\n            }\n\n            while (true) {\n                foreach (self::stream([$response], $timeout) as $chunk) {\n                    if ($chunk->isTimeout() && $response->passthru) {\n                        // Timeouts thrown during initialization are transport errors\n                        foreach (self::passthru($response->client, $response, new ErrorChunk($response->offset, new TransportException($chunk->getError()))) as $chunk) {\n                            if ($chunk->isFirst()) {\n                                return false;\n                            }\n                        }\n\n                        continue 2;\n                    }\n\n                    if ($chunk->isFirst()) {\n                        return false;\n                    }\n                }\n\n                return false;\n            }\n        };\n        if (\\array_key_exists('user_data', $options)) {\n            $this->info['user_data'] = $options['user_data'];\n        }\n        if (\\array_key_exists('max_duration', $options)) {\n            $this->info['max_duration'] = $options['max_duration'];\n        }\n    }\n\n    public function getStatusCode(): int\n    {\n        if ($this->initializer) {\n            self::initialize($this);\n        }\n\n        return $this->response->getStatusCode();\n    }\n\n    public function getHeaders(bool $throw = true): array\n    {\n        if ($this->initializer) {\n            self::initialize($this);\n        }\n\n        $headers = $this->response->getHeaders(false);\n\n        if ($throw) {\n            $this->checkStatusCode();\n        }\n\n        return $headers;\n    }\n\n    public function getInfo(?string $type = null): mixed\n    {\n        if ('debug' === ($type ?? 'debug')) {\n            $debug = implode('', array_column($this->info['previous_info'] ?? [], 'debug'));\n            $debug .= $this->response->getInfo('debug');\n\n            if ('debug' === $type) {\n                return $debug;\n            }\n        }\n\n        if (null !== $type) {\n            return $this->info[$type] ?? $this->response->getInfo($type);\n        }\n\n        return array_merge($this->info + $this->response->getInfo(), ['debug' => $debug]);\n    }\n\n    /**\n     * @return resource\n     */\n    public function toStream(bool $throw = true)\n    {\n        if ($throw) {\n            // Ensure headers arrived\n            $this->getHeaders(true);\n        }\n\n        $handle = function () {\n            $stream = $this->response instanceof StreamableInterface ? $this->response->toStream(false) : StreamWrapper::createResource($this->response);\n\n            return stream_get_meta_data($stream)['wrapper_data']->stream_cast(\\STREAM_CAST_FOR_SELECT);\n        };\n\n        $stream = StreamWrapper::createResource($this);\n        stream_get_meta_data($stream)['wrapper_data']\n            ->bindHandles($handle, $this->content);\n\n        return $stream;\n    }\n\n    public function cancel(): void\n    {\n        if ($this->info['canceled']) {\n            return;\n        }\n\n        $this->info['canceled'] = true;\n        $this->info['error'] = 'Response has been canceled.';\n        $this->close();\n        $client = $this->client;\n        $this->client = null;\n\n        if (!$this->passthru) {\n            return;\n        }\n\n        try {\n            foreach (self::passthru($client, $this, new LastChunk()) as $chunk) {\n                // no-op\n            }\n\n            $this->passthru = null;\n        } catch (ExceptionInterface) {\n            // ignore any errors when canceling\n        }\n    }\n\n    public function __destruct()\n    {\n        $httpException = null;\n\n        if ($this->initializer && null === $this->getInfo('error')) {\n            try {\n                self::initialize($this, -0.0);\n                $this->getHeaders(true);\n            } catch (HttpExceptionInterface $httpException) {\n                // no-op\n            }\n        }\n\n        if ($this->passthru && null === $this->getInfo('error')) {\n            $this->info['canceled'] = true;\n\n            try {\n                foreach (self::passthru($this->client, $this, new LastChunk()) as $chunk) {\n                    // no-op\n                }\n            } catch (ExceptionInterface) {\n                // ignore any errors when destructing\n            }\n        }\n\n        if (null !== $httpException) {\n            throw $httpException;\n        }\n    }\n\n    /**\n     * @internal\n     */\n    public static function stream(iterable $responses, ?float $timeout = null, ?string $class = null): \\Generator\n    {\n        while ($responses) {\n            $wrappedResponses = [];\n            $asyncMap = new \\SplObjectStorage();\n            $client = null;\n\n            foreach ($responses as $r) {\n                if (!$r instanceof self) {\n                    throw new \\TypeError(\\sprintf('\"%s::stream()\" expects parameter 1 to be an iterable of AsyncResponse objects, \"%s\" given.', $class ?? static::class, get_debug_type($r)));\n                }\n\n                if (null !== $e = $r->info['error'] ?? null) {\n                    yield $r => $chunk = new ErrorChunk($r->offset, new TransportException($e));\n                    $chunk->didThrow() ?: $chunk->getContent();\n                    continue;\n                }\n\n                if (null === $client) {\n                    $client = $r->client;\n                } elseif ($r->client !== $client) {\n                    throw new TransportException('Cannot stream AsyncResponse objects with many clients.');\n                }\n\n                $asyncMap[$r->response] = $r;\n                $wrappedResponses[] = $r->response;\n\n                if ($r->stream) {\n                    yield from self::passthruStream($response = $r->response, $r, $asyncMap, new LastChunk());\n\n                    if (!isset($asyncMap[$response])) {\n                        array_pop($wrappedResponses);\n                    }\n\n                    if ($r->response !== $response && !isset($asyncMap[$r->response])) {\n                        $asyncMap[$r->response] = $r;\n                        $wrappedResponses[] = $r->response;\n                    }\n                }\n            }\n\n            if (!$client || !$wrappedResponses) {\n                return;\n            }\n\n            $chunk = null;\n            foreach ($client->stream($wrappedResponses, $timeout) as $response => $chunk) {\n                $r = $asyncMap[$response];\n\n                if (null === $chunk->getError()) {\n                    if ($chunk->isFirst()) {\n                        // Ensure no exception is thrown on destruct for the wrapped response\n                        $r->response->getStatusCode();\n                    } elseif (0 === $r->offset && null === $r->content && $chunk->isLast()) {\n                        $r->content = fopen('php://memory', 'w+');\n                    }\n                }\n\n                if (!$r->passthru) {\n                    $r->stream = (static fn () => yield $chunk)();\n                    yield from self::passthruStream($response, $r, $asyncMap);\n\n                    continue;\n                }\n\n                if (null !== $chunk->getError()) {\n                    // no-op\n                } elseif ($chunk->isFirst()) {\n                    $r->yieldedState = self::FIRST_CHUNK_YIELDED;\n                } elseif (self::FIRST_CHUNK_YIELDED !== $r->yieldedState && null === $chunk->getInformationalStatus()) {\n                    throw new \\LogicException(\\sprintf('Instance of \"%s\" is already consumed and cannot be managed by \"%s\". A decorated client should not call any of the response\\'s methods in its \"request()\" method.', get_debug_type($response), $class ?? static::class));\n                }\n\n                foreach (self::passthru($r->client, $r, $chunk, $asyncMap) as $chunk) {\n                    yield $r => $chunk;\n                }\n\n                if ($r->response !== $response && isset($asyncMap[$response])) {\n                    break;\n                }\n            }\n\n            if (null === $chunk) {\n                throw new \\LogicException(\\sprintf('\"%s\" is not compliant with HttpClientInterface: its \"stream()\" method didn\\'t yield any chunks when it should have.', get_debug_type($client)));\n            }\n            if (null === $chunk->getError() && $chunk->isLast()) {\n                $r->yieldedState = self::LAST_CHUNK_YIELDED;\n            }\n            if (null === $chunk->getError() && self::LAST_CHUNK_YIELDED !== $r->yieldedState && $r->response === $response && null !== $r->client) {\n                throw new \\LogicException('A chunk passthru must yield an \"isLast()\" chunk before ending a stream.');\n            }\n\n            $responses = [];\n            foreach ($asyncMap as $response) {\n                $r = $asyncMap[$response];\n\n                if (null !== $r->client) {\n                    $responses[] = $asyncMap[$response];\n                }\n            }\n        }\n    }\n\n    /**\n     * @param \\SplObjectStorage<ResponseInterface, AsyncResponse>|null $asyncMap\n     */\n    private static function passthru(HttpClientInterface $client, self $r, ChunkInterface $chunk, ?\\SplObjectStorage $asyncMap = null): \\Generator\n    {\n        $r->stream = null;\n        $response = $r->response;\n        $context = new AsyncContext($r->passthru, $client, $r->response, $r->info, $r->content, $r->offset);\n        if (null === $stream = ($r->passthru)($chunk, $context)) {\n            if ($r->response === $response && (null !== $chunk->getError() || $chunk->isLast())) {\n                throw new \\LogicException('A chunk passthru cannot swallow the last chunk.');\n            }\n\n            return;\n        }\n\n        if (!$stream instanceof \\Iterator) {\n            throw new \\LogicException(\\sprintf('A chunk passthru must return an \"Iterator\", \"%s\" returned.', get_debug_type($stream)));\n        }\n        $r->stream = $stream;\n\n        yield from self::passthruStream($response, $r, $asyncMap);\n    }\n\n    /**\n     * @param \\SplObjectStorage<ResponseInterface, AsyncResponse>|null $asyncMap\n     */\n    private static function passthruStream(ResponseInterface $response, self $r, ?\\SplObjectStorage $asyncMap, ?ChunkInterface $chunk = null): \\Generator\n    {\n        while (true) {\n            try {\n                if (null !== $chunk && $r->stream) {\n                    $r->stream->next();\n                }\n\n                if (!$r->stream || !$r->stream->valid() || !$r->stream) {\n                    $r->stream = null;\n                    break;\n                }\n            } catch (\\Throwable $e) {\n                unset($asyncMap[$response]);\n                $r->stream = null;\n                $r->info['error'] = $e->getMessage();\n                $r->response->cancel();\n\n                yield $r => $chunk = new ErrorChunk($r->offset, $e);\n                $chunk->didThrow() ?: $chunk->getContent();\n                break;\n            }\n\n            $chunk = $r->stream->current();\n\n            if (!$chunk instanceof ChunkInterface) {\n                throw new \\LogicException(\\sprintf('A chunk passthru must yield instances of \"%s\", \"%s\" yielded.', ChunkInterface::class, get_debug_type($chunk)));\n            }\n\n            if (null !== $chunk->getError()) {\n                // no-op\n            } elseif ($chunk->isFirst()) {\n                $e = $r->openBuffer();\n\n                yield $r => $chunk;\n\n                if ($r->initializer && null === $r->getInfo('error')) {\n                    // Ensure the HTTP status code is always checked\n                    $r->getHeaders(true);\n                }\n\n                if (null === $e) {\n                    continue;\n                }\n\n                $r->response->cancel();\n                $chunk = new ErrorChunk($r->offset, $e);\n            } elseif ('' !== $content = $chunk->getContent()) {\n                if (null !== $r->shouldBuffer) {\n                    throw new \\LogicException('A chunk passthru must yield an \"isFirst()\" chunk before any content chunk.');\n                }\n\n                if (null !== $r->content && \\strlen($content) !== fwrite($r->content, $content)) {\n                    $chunk = new ErrorChunk($r->offset, new TransportException(\\sprintf('Failed writing %d bytes to the response buffer.', \\strlen($content))));\n                    $r->info['error'] = $chunk->getError();\n                    $r->response->cancel();\n                }\n            }\n\n            if (null !== $chunk->getError() || $chunk->isLast()) {\n                $stream = $r->stream;\n                $r->stream = null;\n                unset($asyncMap[$response]);\n            }\n\n            if (null === $chunk->getError()) {\n                $r->offset += \\strlen($content);\n\n                yield $r => $chunk;\n\n                if (!$chunk->isLast()) {\n                    continue;\n                }\n\n                $stream->next();\n\n                if ($stream->valid()) {\n                    throw new \\LogicException('A chunk passthru cannot yield after an \"isLast()\" chunk.');\n                }\n\n                $r->passthru = null;\n            } else {\n                if ($chunk instanceof ErrorChunk) {\n                    $chunk->didThrow(false);\n                } else {\n                    try {\n                        $chunk = new ErrorChunk($chunk->getOffset(), !$chunk->isTimeout() ?: $chunk->getError());\n                    } catch (TransportExceptionInterface $e) {\n                        $chunk = new ErrorChunk($chunk->getOffset(), $e);\n                    }\n                }\n\n                yield $r => $chunk;\n                $chunk->didThrow() ?: $chunk->getContent();\n            }\n\n            break;\n        }\n    }\n\n    private function openBuffer(): ?\\Throwable\n    {\n        if (null === $shouldBuffer = $this->shouldBuffer) {\n            throw new \\LogicException('A chunk passthru cannot yield more than one \"isFirst()\" chunk.');\n        }\n\n        $e = $this->shouldBuffer = null;\n\n        if ($shouldBuffer instanceof \\Closure) {\n            try {\n                $shouldBuffer = $shouldBuffer($this->getHeaders(false));\n\n                if (null !== $e = $this->response->getInfo('error')) {\n                    throw new TransportException($e);\n                }\n            } catch (\\Throwable $e) {\n                $this->info['error'] = $e->getMessage();\n                $this->response->cancel();\n            }\n        }\n\n        if (true === $shouldBuffer) {\n            $this->content = fopen('php://temp', 'w+');\n        } elseif (\\is_resource($shouldBuffer)) {\n            $this->content = $shouldBuffer;\n        }\n\n        return $e;\n    }\n\n    private function close(): void\n    {\n        $this->response->cancel();\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/Response/CommonResponseTrait.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient\\Response;\n\nuse Symfony\\Component\\HttpClient\\Exception\\ClientException;\nuse Symfony\\Component\\HttpClient\\Exception\\JsonException;\nuse Symfony\\Component\\HttpClient\\Exception\\RedirectionException;\nuse Symfony\\Component\\HttpClient\\Exception\\ServerException;\nuse Symfony\\Component\\HttpClient\\Exception\\TransportException;\n\n/**\n * Implements common logic for response classes.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n *\n * @internal\n */\ntrait CommonResponseTrait\n{\n    /**\n     * @var callable|null A callback that tells whether we're waiting for response headers\n     */\n    private $initializer;\n    /** @var bool|\\Closure|resource|null */\n    private $shouldBuffer;\n    /** @var resource|null */\n    private $content;\n    private int $offset = 0;\n    private ?array $jsonData = null;\n\n    public function getContent(bool $throw = true): string\n    {\n        if ($this->initializer) {\n            self::initialize($this);\n        }\n\n        if ($throw) {\n            $this->checkStatusCode();\n        }\n\n        if (null === $this->content) {\n            $content = null;\n\n            foreach (self::stream([$this]) as $chunk) {\n                if (!$chunk->isLast()) {\n                    $content .= $chunk->getContent();\n                }\n            }\n\n            if (null !== $content) {\n                return $content;\n            }\n\n            if (null === $this->content) {\n                throw new TransportException('Cannot get the content of the response twice: buffering is disabled.');\n            }\n        } else {\n            foreach (self::stream([$this]) as $chunk) {\n                // Chunks are buffered in $this->content already\n            }\n        }\n\n        rewind($this->content);\n\n        return stream_get_contents($this->content);\n    }\n\n    public function toArray(bool $throw = true): array\n    {\n        if ('' === $content = $this->getContent($throw)) {\n            throw new JsonException('Response body is empty.');\n        }\n\n        if (null !== $this->jsonData) {\n            return $this->jsonData;\n        }\n\n        try {\n            $content = json_decode($content, true, 512, \\JSON_BIGINT_AS_STRING | \\JSON_THROW_ON_ERROR);\n        } catch (\\JsonException $e) {\n            throw new JsonException($e->getMessage().\\sprintf(' for \"%s\".', $this->getInfo('url')), $e->getCode());\n        }\n\n        if (!\\is_array($content)) {\n            throw new JsonException(\\sprintf('JSON content was expected to decode to an array, \"%s\" returned for \"%s\".', get_debug_type($content), $this->getInfo('url')));\n        }\n\n        if (null !== $this->content) {\n            // Option \"buffer\" is true\n            return $this->jsonData = $content;\n        }\n\n        return $content;\n    }\n\n    /**\n     * @return resource\n     */\n    public function toStream(bool $throw = true)\n    {\n        if ($throw) {\n            // Ensure headers arrived\n            $this->getHeaders($throw);\n        }\n\n        $stream = StreamWrapper::createResource($this);\n        stream_get_meta_data($stream)['wrapper_data']\n            ->bindHandles($this->handle, $this->content);\n\n        return $stream;\n    }\n\n    public function __serialize(): array\n    {\n        throw new \\BadMethodCallException('Cannot serialize '.__CLASS__);\n    }\n\n    public function __unserialize(array $data): void\n    {\n        throw new \\BadMethodCallException('Cannot unserialize '.__CLASS__);\n    }\n\n    /**\n     * Closes the response and all its network handles.\n     */\n    abstract protected function close(): void;\n\n    private static function initialize(self $response): void\n    {\n        if (null !== $response->getInfo('error')) {\n            throw new TransportException($response->getInfo('error'));\n        }\n\n        try {\n            if (($response->initializer)($response, -0.0)) {\n                foreach (self::stream([$response], -0.0) as $chunk) {\n                    if ($chunk->isFirst()) {\n                        break;\n                    }\n                }\n            }\n        } catch (\\Throwable $e) {\n            // Persist timeouts thrown during initialization\n            $response->info['error'] = $e->getMessage();\n            $response->close();\n            throw $e;\n        }\n\n        $response->initializer = null;\n    }\n\n    private function checkStatusCode(): void\n    {\n        $code = $this->getInfo('http_code');\n\n        if (500 <= $code) {\n            throw new ServerException($this);\n        }\n\n        if (400 <= $code) {\n            throw new ClientException($this);\n        }\n\n        if (300 <= $code) {\n            throw new RedirectionException($this);\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/Response/CurlResponse.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient\\Response;\n\nuse Psr\\Log\\LoggerInterface;\nuse Symfony\\Component\\HttpClient\\Chunk\\FirstChunk;\nuse Symfony\\Component\\HttpClient\\Chunk\\InformationalChunk;\nuse Symfony\\Component\\HttpClient\\Exception\\TransportException;\nuse Symfony\\Component\\HttpClient\\Internal\\Canary;\nuse Symfony\\Component\\HttpClient\\Internal\\ClientState;\nuse Symfony\\Component\\HttpClient\\Internal\\CurlClientState;\nuse Symfony\\Contracts\\HttpClient\\ResponseInterface;\n\n/**\n * @author Nicolas Grekas <p@tchwork.com>\n *\n * @internal\n */\nfinal class CurlResponse implements ResponseInterface, StreamableInterface\n{\n    use CommonResponseTrait {\n        getContent as private doGetContent;\n    }\n    use TransportResponseTrait;\n\n    private CurlClientState $multi;\n\n    /**\n     * @var resource\n     */\n    private $debugBuffer;\n\n    /**\n     * @internal\n     */\n    public function __construct(CurlClientState $multi, \\CurlHandle|string $ch, ?array $options = null, ?LoggerInterface $logger = null, string $method = 'GET', ?callable $resolveRedirect = null, ?int $curlVersion = null, ?string $originalUrl = null)\n    {\n        $this->multi = $multi;\n\n        if ($ch instanceof \\CurlHandle) {\n            $this->handle = $ch;\n            $this->debugBuffer = fopen('php://temp', 'w+');\n            if (0x074000 === $curlVersion) {\n                fwrite($this->debugBuffer, 'Due to a bug in curl 7.64.0, the debug log is disabled; use another version to work around the issue.');\n            } else {\n                curl_setopt($ch, \\CURLOPT_VERBOSE, true);\n                curl_setopt($ch, \\CURLOPT_STDERR, $this->debugBuffer);\n            }\n        } else {\n            $this->info['url'] = $ch;\n            $ch = $this->handle;\n        }\n\n        $this->id = $id = (int) $ch;\n        $this->logger = $logger;\n        $this->shouldBuffer = $options['buffer'] ?? true;\n        $this->timeout = $options['timeout'] ?? null;\n        $this->info['http_method'] = $method;\n        $this->info['user_data'] = $options['user_data'] ?? null;\n        $this->info['max_duration'] = $options['max_duration'] ?? null;\n        $this->info['start_time'] ??= microtime(true);\n        $this->info['original_url'] = $originalUrl ?? $this->info['url'] ?? curl_getinfo($ch, \\CURLINFO_EFFECTIVE_URL);\n        $info = &$this->info;\n        $headers = &$this->headers;\n        $debugBuffer = $this->debugBuffer;\n\n        if (!$info['response_headers']) {\n            // Used to keep track of what we're waiting for\n            curl_setopt($ch, \\CURLOPT_PRIVATE, \\in_array($method, ['GET', 'HEAD', 'OPTIONS', 'TRACE'], true) && 1.0 < (float) ($options['http_version'] ?? 1.1) ? 'H2' : 'H0'); // H = headers + retry counter\n        }\n\n        curl_setopt($ch, \\CURLOPT_HEADERFUNCTION, static function ($ch, string $data) use (&$info, &$headers, $options, $multi, $id, &$location, $resolveRedirect, $logger): int {\n            return self::parseHeaderLine($ch, $data, $info, $headers, $options, $multi, $id, $location, $resolveRedirect, $logger);\n        });\n\n        if (null === $options) {\n            // Pushed response: buffer until requested\n            curl_setopt($ch, \\CURLOPT_WRITEFUNCTION, static function ($ch, string $data) use ($multi, $id): int {\n                $multi->handlesActivity[$id][] = $data;\n                curl_pause($ch, \\CURLPAUSE_RECV);\n\n                return \\strlen($data);\n            });\n\n            return;\n        }\n\n        $execCounter = $multi->execCounter;\n        $this->info['pause_handler'] = static function (float $duration) use ($ch, $multi, $execCounter) {\n            if (0 < $duration) {\n                if ($execCounter === $multi->execCounter) {\n                    curl_multi_remove_handle($multi->handle, $ch);\n                }\n\n                $lastExpiry = end($multi->pauseExpiries);\n                $multi->pauseExpiries[(int) $ch] = $duration += hrtime(true) / 1E9;\n                if (false !== $lastExpiry && $lastExpiry > $duration) {\n                    asort($multi->pauseExpiries);\n                }\n                curl_pause($ch, \\CURLPAUSE_ALL);\n            } else {\n                unset($multi->pauseExpiries[(int) $ch]);\n                curl_pause($ch, \\CURLPAUSE_CONT);\n                curl_multi_add_handle($multi->handle, $ch);\n            }\n        };\n\n        $this->inflate = !isset($options['normalized_headers']['accept-encoding']);\n        curl_pause($ch, \\CURLPAUSE_CONT);\n\n        if ($onProgress = $options['on_progress']) {\n            $url = isset($info['url']) ? ['url' => $info['url']] : [];\n            curl_setopt($ch, \\CURLOPT_NOPROGRESS, false);\n            curl_setopt($ch, \\CURLOPT_PROGRESSFUNCTION, static function ($ch, $dlSize, $dlNow) use ($onProgress, &$info, $url, $multi, $debugBuffer) {\n                try {\n                    rewind($debugBuffer);\n                    $debug = ['debug' => stream_get_contents($debugBuffer)];\n                    $onProgress($dlNow, $dlSize, $url + curl_getinfo($ch) + $info + $debug);\n                } catch (\\Throwable $e) {\n                    $multi->handlesActivity[(int) $ch][] = null;\n                    $multi->handlesActivity[(int) $ch][] = $e;\n\n                    return 1; // Abort the request\n                }\n\n                return null;\n            });\n        }\n\n        curl_setopt($ch, \\CURLOPT_WRITEFUNCTION, static function ($ch, string $data) use ($multi, $id): int {\n            if ('H' === (curl_getinfo($ch, \\CURLINFO_PRIVATE)[0] ?? null)) {\n                $multi->handlesActivity[$id][] = null;\n                $multi->handlesActivity[$id][] = new TransportException(\\sprintf('Unsupported protocol for \"%s\"', curl_getinfo($ch, \\CURLINFO_EFFECTIVE_URL)));\n\n                return 0;\n            }\n\n            curl_setopt($ch, \\CURLOPT_WRITEFUNCTION, static function ($ch, string $data) use ($multi, $id): int {\n                $multi->handlesActivity[$id][] = $data;\n\n                return \\strlen($data);\n            });\n\n            $multi->handlesActivity[$id][] = $data;\n\n            return \\strlen($data);\n        });\n\n        $this->initializer = static function (self $response) {\n            $waitFor = curl_getinfo($response->handle, \\CURLINFO_PRIVATE);\n\n            return 'H' === $waitFor[0];\n        };\n\n        // Schedule the request in a non-blocking way\n        $multi->lastTimeout = null;\n        $multi->openHandles[$id] = [$ch, $options];\n        curl_multi_add_handle($multi->handle, $ch);\n\n        $this->canary = new Canary(static function () use ($ch, $multi, $id) {\n            unset($multi->pauseExpiries[$id], $multi->openHandles[$id], $multi->handlesActivity[$id]);\n            curl_setopt($ch, \\CURLOPT_PRIVATE, '_0');\n\n            if ($multi->performing) {\n                return;\n            }\n\n            curl_multi_remove_handle($multi->handle, $ch);\n            curl_setopt_array($ch, [\n                \\CURLOPT_NOPROGRESS => true,\n                \\CURLOPT_PROGRESSFUNCTION => null,\n                \\CURLOPT_HEADERFUNCTION => null,\n                \\CURLOPT_WRITEFUNCTION => null,\n                \\CURLOPT_READFUNCTION => null,\n                \\CURLOPT_INFILE => null,\n            ]);\n\n            if (!$multi->openHandles) {\n                // Schedule DNS cache eviction for the next request\n                $multi->dnsCache->evictions = $multi->dnsCache->evictions ?: $multi->dnsCache->removals;\n                $multi->dnsCache->removals = $multi->dnsCache->hostnames = [];\n            }\n        });\n    }\n\n    public function getInfo(?string $type = null): mixed\n    {\n        if (!$info = $this->finalInfo) {\n            $info = array_merge($this->info, curl_getinfo($this->handle));\n            $info['url'] = $this->info['url'] ?? $info['url'];\n            $info['redirect_url'] = $this->info['redirect_url'] ?? null;\n\n            // workaround curl not subtracting the time offset for pushed responses\n            if (isset($this->info['url']) && $info['start_time'] / 1000 < $info['total_time']) {\n                $info['total_time'] -= $info['starttransfer_time'] ?: $info['total_time'];\n                $info['starttransfer_time'] = 0.0;\n            }\n\n            rewind($this->debugBuffer);\n            $info['debug'] = stream_get_contents($this->debugBuffer);\n            $waitFor = curl_getinfo($this->handle, \\CURLINFO_PRIVATE);\n\n            if ('H' !== $waitFor[0] && 'C' !== $waitFor[0]) {\n                curl_setopt($this->handle, \\CURLOPT_VERBOSE, false);\n                rewind($this->debugBuffer);\n                ftruncate($this->debugBuffer, 0);\n                $this->finalInfo = $info;\n            }\n        }\n\n        return null !== $type ? $info[$type] ?? null : $info;\n    }\n\n    public function getContent(bool $throw = true): string\n    {\n        $performing = $this->multi->performing;\n        $this->multi->performing = $performing || '_0' === curl_getinfo($this->handle, \\CURLINFO_PRIVATE);\n\n        try {\n            return $this->doGetContent($throw);\n        } finally {\n            $this->multi->performing = $performing;\n        }\n    }\n\n    public function __destruct()\n    {\n        try {\n            if (null === $this->timeout) {\n                return; // Unused pushed response\n            }\n\n            $this->doDestruct();\n        } finally {\n            if ($this->handle instanceof \\CurlHandle) {\n                curl_setopt($this->handle, \\CURLOPT_VERBOSE, false);\n            }\n        }\n    }\n\n    private static function schedule(self $response, array &$runningResponses): void\n    {\n        if (isset($runningResponses[$i = (int) $response->multi->handle])) {\n            $runningResponses[$i][1][$response->id] = $response;\n        } else {\n            $runningResponses[$i] = [$response->multi, [$response->id => $response]];\n        }\n\n        if ('_0' === curl_getinfo($response->handle, \\CURLINFO_PRIVATE)) {\n            // Response already completed\n            $response->multi->handlesActivity[$response->id][] = null;\n            $response->multi->handlesActivity[$response->id][] = null !== $response->info['error'] ? new TransportException($response->info['error']) : null;\n        }\n    }\n\n    /**\n     * @param CurlClientState $multi\n     */\n    private static function perform(ClientState $multi, ?array $responses = null): void\n    {\n        if ($multi->performing) {\n            if ($responses) {\n                $response = $responses[array_key_first($responses)];\n                $multi->handlesActivity[(int) $response->handle][] = null;\n                $multi->handlesActivity[(int) $response->handle][] = new TransportException(\\sprintf('Userland callback cannot use the client nor the response while processing \"%s\".', curl_getinfo($response->handle, \\CURLINFO_EFFECTIVE_URL)));\n            }\n\n            return;\n        }\n\n        try {\n            $multi->performing = true;\n            ++$multi->execCounter;\n            $active = 0;\n            while (\\CURLM_CALL_MULTI_PERFORM === ($err = curl_multi_exec($multi->handle, $active))) {\n            }\n\n            if (\\CURLM_OK !== $err) {\n                throw new TransportException(curl_multi_strerror($err));\n            }\n\n            while ($info = curl_multi_info_read($multi->handle)) {\n                if (\\CURLMSG_DONE !== $info['msg']) {\n                    continue;\n                }\n                $result = $info['result'];\n                $id = (int) $ch = $info['handle'];\n                $waitFor = @curl_getinfo($ch, \\CURLINFO_PRIVATE) ?: '_0';\n\n                if (\\in_array($result, [\\CURLE_SEND_ERROR, \\CURLE_RECV_ERROR, /* CURLE_HTTP2 */ 16, /* CURLE_HTTP2_STREAM */ 92], true) && $waitFor[1] && 'C' !== $waitFor[0]) {\n                    curl_multi_remove_handle($multi->handle, $ch);\n                    $waitFor[1] = (string) ((int) $waitFor[1] - 1); // decrement the retry counter\n                    curl_setopt($ch, \\CURLOPT_PRIVATE, $waitFor);\n                    curl_setopt($ch, \\CURLOPT_FORBID_REUSE, true);\n\n                    if (0 === curl_multi_add_handle($multi->handle, $ch)) {\n                        continue;\n                    }\n                }\n\n                if (\\CURLE_RECV_ERROR === $result && 'H' === $waitFor[0] && 400 <= ($responses[(int) $ch]->info['http_code'] ?? 0)) {\n                    $multi->handlesActivity[$id][] = new FirstChunk();\n                }\n\n                $multi->handlesActivity[$id][] = null;\n                $multi->handlesActivity[$id][] = \\in_array($result, [\\CURLE_OK, \\CURLE_TOO_MANY_REDIRECTS], true)\n                    || '_0' === $waitFor\n                    || curl_getinfo($ch, \\CURLINFO_SIZE_DOWNLOAD) === curl_getinfo($ch, \\CURLINFO_CONTENT_LENGTH_DOWNLOAD)\n                    || ('C' === $waitFor[0]\n                        && 'OpenSSL SSL_read: SSL_ERROR_SYSCALL, errno 0' === curl_error($ch)\n                        && -1.0 === curl_getinfo($ch, \\CURLINFO_CONTENT_LENGTH_DOWNLOAD)\n                        && \\in_array('close', array_map('strtolower', $responses[$id]->headers['connection'] ?? []), true)\n                    )\n                    ? null\n                    : new TransportException(ucfirst(curl_error($ch) ?: curl_strerror($result)).\\sprintf(' for \"%s\".', curl_getinfo($ch, \\CURLINFO_EFFECTIVE_URL)));\n            }\n        } finally {\n            $multi->performing = false;\n        }\n    }\n\n    /**\n     * @param CurlClientState $multi\n     */\n    private static function select(ClientState $multi, float $timeout): int\n    {\n        if ($multi->pauseExpiries) {\n            $now = hrtime(true) / 1E9;\n\n            foreach ($multi->pauseExpiries as $id => $pauseExpiry) {\n                if ($now < $pauseExpiry) {\n                    $timeout = min($timeout, $pauseExpiry - $now);\n                    break;\n                }\n\n                unset($multi->pauseExpiries[$id]);\n                curl_pause($multi->openHandles[$id][0], \\CURLPAUSE_CONT);\n                curl_multi_add_handle($multi->handle, $multi->openHandles[$id][0]);\n            }\n        }\n\n        if (0 !== $selected = curl_multi_select($multi->handle, $timeout)) {\n            return $selected;\n        }\n\n        if ($multi->pauseExpiries && 0 < $timeout -= hrtime(true) / 1E9 - $now) {\n            usleep((int) (1E6 * $timeout));\n        }\n\n        return 0;\n    }\n\n    /**\n     * Parses header lines as curl yields them to us.\n     */\n    private static function parseHeaderLine($ch, string $data, array &$info, array &$headers, ?array $options, CurlClientState $multi, int $id, ?string &$location, ?callable $resolveRedirect, ?LoggerInterface $logger): int\n    {\n        if (!str_ends_with($data, \"\\r\\n\")) {\n            return 0;\n        }\n\n        $waitFor = @curl_getinfo($ch, \\CURLINFO_PRIVATE) ?: '_0';\n\n        if ('H' !== $waitFor[0]) {\n            return \\strlen($data); // Ignore HTTP trailers\n        }\n\n        $statusCode = curl_getinfo($ch, \\CURLINFO_RESPONSE_CODE);\n\n        if ($statusCode !== $info['http_code'] && !preg_match(\"#^HTTP/\\d+(?:\\.\\d+)? {$statusCode}(?: |\\r\\n$)#\", $data)) {\n            return \\strlen($data); // Ignore headers from responses to CONNECT requests\n        }\n\n        if (\"\\r\\n\" !== $data) {\n            // Regular header line: add it to the list\n            self::addResponseHeaders([substr($data, 0, -2)], $info, $headers);\n\n            if (!str_starts_with($data, 'HTTP/')) {\n                if (0 === stripos($data, 'Location:')) {\n                    $location = trim(substr($data, 9, -2));\n                }\n\n                return \\strlen($data);\n            }\n\n            if (\\function_exists('openssl_x509_read') && $certinfo = curl_getinfo($ch, \\CURLINFO_CERTINFO)) {\n                $info['peer_certificate_chain'] = array_map('openssl_x509_read', array_column($certinfo, 'Cert'));\n            }\n\n            if (300 <= $info['http_code'] && $info['http_code'] < 400 && null !== $options) {\n                if (curl_getinfo($ch, \\CURLINFO_REDIRECT_COUNT) === $options['max_redirects']) {\n                    curl_setopt($ch, \\CURLOPT_FOLLOWLOCATION, false);\n                } elseif (303 === $info['http_code'] || ('POST' === $info['http_method'] && \\in_array($info['http_code'], [301, 302], true))) {\n                    curl_setopt($ch, \\CURLOPT_POSTFIELDS, '');\n                }\n            }\n\n            return \\strlen($data);\n        }\n\n        // End of headers: handle informational responses, redirects, etc.\n\n        if (200 > $statusCode) {\n            $multi->handlesActivity[$id][] = new InformationalChunk($statusCode, $headers);\n            $location = null;\n\n            return \\strlen($data);\n        }\n\n        $info['redirect_url'] = null;\n\n        if (300 <= $statusCode && $statusCode < 400 && null !== $location && null !== $options) {\n            if ($noContent = 303 === $statusCode || ('POST' === $info['http_method'] && \\in_array($statusCode, [301, 302], true))) {\n                $info['http_method'] = 'HEAD' === $info['http_method'] ? 'HEAD' : 'GET';\n                curl_setopt($ch, \\CURLOPT_CUSTOMREQUEST, $info['http_method']);\n            }\n\n            if (null === $info['redirect_url'] = $resolveRedirect($ch, $location, $noContent)) {\n                $options['max_redirects'] = curl_getinfo($ch, \\CURLINFO_REDIRECT_COUNT);\n                curl_setopt($ch, \\CURLOPT_FOLLOWLOCATION, false);\n                curl_setopt($ch, \\CURLOPT_MAXREDIRS, $options['max_redirects']);\n            }\n        }\n\n        if (401 === $statusCode && isset($options['auth_ntlm']) && 0 === strncasecmp($headers['www-authenticate'][0] ?? '', 'NTLM ', 5)) {\n            // Continue with NTLM auth\n        } elseif ($statusCode < 300 || 400 <= $statusCode || null === $location || null === $options || curl_getinfo($ch, \\CURLINFO_REDIRECT_COUNT) === $options['max_redirects']) {\n            // Headers and redirects completed, time to get the response's content\n            $multi->handlesActivity[$id][] = new FirstChunk();\n\n            if ('HEAD' === $info['http_method'] || \\in_array($statusCode, [204, 304], true)) {\n                $waitFor = '_0'; // no content expected\n                $multi->handlesActivity[$id][] = null;\n                $multi->handlesActivity[$id][] = null;\n            } else {\n                $waitFor[0] = 'C'; // C = content\n            }\n\n            curl_setopt($ch, \\CURLOPT_PRIVATE, $waitFor);\n        } elseif (null !== $info['redirect_url'] && $logger) {\n            $logger->info(\\sprintf('Redirecting: \"%s %s\"', $info['http_code'], $info['redirect_url']));\n        }\n\n        $location = null;\n\n        return \\strlen($data);\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/Response/HttplugPromise.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient\\Response;\n\nuse GuzzleHttp\\Promise\\Create;\nuse GuzzleHttp\\Promise\\PromiseInterface as GuzzlePromiseInterface;\nuse Http\\Promise\\Promise as HttplugPromiseInterface;\nuse Psr\\Http\\Message\\ResponseInterface as Psr7ResponseInterface;\n\n/**\n * @author Tobias Nyholm <tobias.nyholm@gmail.com>\n *\n * @internal\n */\nfinal class HttplugPromise implements HttplugPromiseInterface\n{\n    private GuzzlePromiseInterface $promise;\n\n    public function __construct(GuzzlePromiseInterface $promise)\n    {\n        $this->promise = $promise;\n    }\n\n    public function then(?callable $onFulfilled = null, ?callable $onRejected = null): self\n    {\n        return new self($this->promise->then(\n            $this->wrapThenCallback($onFulfilled),\n            $this->wrapThenCallback($onRejected)\n        ));\n    }\n\n    public function cancel(): void\n    {\n        $this->promise->cancel();\n    }\n\n    public function getState(): string\n    {\n        return $this->promise->getState();\n    }\n\n    /**\n     * @return Psr7ResponseInterface|mixed\n     */\n    public function wait($unwrap = true): mixed\n    {\n        $result = $this->promise->wait($unwrap);\n\n        while ($result instanceof HttplugPromiseInterface || $result instanceof GuzzlePromiseInterface) {\n            $result = $result->wait($unwrap);\n        }\n\n        return $result;\n    }\n\n    private function wrapThenCallback(?callable $callback): ?callable\n    {\n        if (null === $callback) {\n            return null;\n        }\n\n        return static fn ($value) => Create::promiseFor($callback($value));\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/Response/JsonMockResponse.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient\\Response;\n\nuse Symfony\\Component\\HttpClient\\Exception\\InvalidArgumentException;\n\nclass JsonMockResponse extends MockResponse\n{\n    /**\n     * @param mixed $body Any value that `json_encode()` can serialize\n     */\n    public function __construct(mixed $body = [], array $info = [])\n    {\n        try {\n            $json = json_encode($body, \\JSON_THROW_ON_ERROR | \\JSON_PRESERVE_ZERO_FRACTION);\n        } catch (\\JsonException $e) {\n            throw new InvalidArgumentException('JSON encoding failed: '.$e->getMessage(), $e->getCode(), $e);\n        }\n\n        $info['response_headers']['content-type'] ??= 'application/json';\n\n        parent::__construct($json, $info);\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/Response/MockResponse.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient\\Response;\n\nuse Symfony\\Component\\HttpClient\\Chunk\\ErrorChunk;\nuse Symfony\\Component\\HttpClient\\Chunk\\FirstChunk;\nuse Symfony\\Component\\HttpClient\\Exception\\InvalidArgumentException;\nuse Symfony\\Component\\HttpClient\\Exception\\TransportException;\nuse Symfony\\Component\\HttpClient\\Internal\\ClientState;\nuse Symfony\\Contracts\\HttpClient\\ResponseInterface;\n\n/**\n * A test-friendly response.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n */\nclass MockResponse implements ResponseInterface, StreamableInterface\n{\n    use CommonResponseTrait;\n    use TransportResponseTrait;\n\n    private string|iterable|null $body;\n    private array $requestOptions = [];\n    private string $requestUrl;\n    private string $requestMethod;\n\n    private static ClientState $mainMulti;\n    private static int $idSequence = 0;\n\n    /**\n     * @param string|iterable<string|\\Throwable> $body The response body as a string or an iterable of strings,\n     *                                                 yielding an empty string simulates an idle timeout,\n     *                                                 throwing or yielding an exception yields an ErrorChunk\n     *\n     * @see ResponseInterface::getInfo() for possible info, e.g. \"response_headers\"\n     */\n    public function __construct(string|iterable $body = '', array $info = [])\n    {\n        $this->body = $body;\n        $this->info = $info + ['http_code' => 200] + $this->info;\n\n        if (!isset($info['response_headers'])) {\n            return;\n        }\n\n        $responseHeaders = [];\n\n        foreach ($info['response_headers'] as $k => $v) {\n            foreach ((array) $v as $v) {\n                $responseHeaders[] = (\\is_string($k) ? $k.': ' : '').$v;\n            }\n        }\n\n        $this->info['response_headers'] = [];\n        self::addResponseHeaders($responseHeaders, $this->info, $this->headers);\n    }\n\n    /**\n     * Returns the options used when doing the request.\n     */\n    public function getRequestOptions(): array\n    {\n        return $this->requestOptions;\n    }\n\n    /**\n     * Returns the URL used when doing the request.\n     */\n    public function getRequestUrl(): string\n    {\n        return $this->requestUrl;\n    }\n\n    /**\n     * Returns the method used when doing the request.\n     */\n    public function getRequestMethod(): string\n    {\n        return $this->requestMethod;\n    }\n\n    public function getInfo(?string $type = null): mixed\n    {\n        return null !== $type ? $this->info[$type] ?? null : $this->info;\n    }\n\n    public function cancel(): void\n    {\n        $this->info['canceled'] = true;\n        $this->info['error'] = 'Response has been canceled.';\n        try {\n            $this->body = null;\n        } catch (TransportException $e) {\n            // ignore errors when canceling\n        }\n\n        $onProgress = $this->requestOptions['on_progress'] ?? static function () {};\n        $dlSize = isset($this->headers['content-encoding']) || 'HEAD' === ($this->info['http_method'] ?? null) || \\in_array($this->info['http_code'], [204, 304], true) ? 0 : (int) ($this->headers['content-length'][0] ?? 0);\n        $onProgress($this->offset, $dlSize, $this->info);\n    }\n\n    public function __destruct()\n    {\n        $this->doDestruct();\n    }\n\n    protected function close(): void\n    {\n        $this->inflate = null;\n        $this->body = [];\n    }\n\n    /**\n     * @internal\n     */\n    public static function fromRequest(string $method, string $url, array $options, ResponseInterface $mock): self\n    {\n        $response = new self([]);\n        $response->requestOptions = $options;\n        $response->id = ++self::$idSequence;\n        $response->shouldBuffer = $options['buffer'] ?? true;\n        $response->initializer = static fn (self $response) => \\is_array($response->body[0] ?? null);\n\n        $response->info['redirect_count'] = 0;\n        $response->info['redirect_url'] = null;\n        $response->info['start_time'] = microtime(true);\n        $response->info['http_method'] = $method;\n        $response->info['http_code'] = 0;\n        $response->info['user_data'] = $options['user_data'] ?? null;\n        $response->info['max_duration'] = $options['max_duration'] ?? null;\n        $response->info['url'] = $url;\n        $response->info['original_url'] = $url;\n\n        if ($mock instanceof self) {\n            $mock->requestOptions = $response->requestOptions;\n            $mock->requestMethod = $method;\n            $mock->requestUrl = $url;\n        }\n\n        self::writeRequest($response, $options, $mock);\n        $response->body[] = [$options, $mock];\n\n        return $response;\n    }\n\n    protected static function schedule(self $response, array &$runningResponses): void\n    {\n        if (!isset($response->id)) {\n            throw new InvalidArgumentException('MockResponse instances must be issued by MockHttpClient before processing.');\n        }\n\n        $multi = self::$mainMulti ??= new ClientState();\n\n        if (!isset($runningResponses[0])) {\n            $runningResponses[0] = [$multi, []];\n        }\n\n        $runningResponses[0][1][$response->id] = $response;\n    }\n\n    protected static function perform(ClientState $multi, array $responses): void\n    {\n        foreach ($responses as $response) {\n            $id = $response->id;\n\n            if (null === $response->body) {\n                // Canceled response\n                $response->body = [];\n            } elseif ([] === $response->body) {\n                // Error chunk\n                $multi->handlesActivity[$id][] = null;\n                $multi->handlesActivity[$id][] = null !== $response->info['error'] ? new TransportException($response->info['error']) : null;\n            } elseif (null === $chunk = array_shift($response->body)) {\n                // Last chunk\n                $multi->handlesActivity[$id][] = null;\n                $multi->handlesActivity[$id][] = array_shift($response->body);\n            } elseif (\\is_array($chunk)) {\n                // First chunk\n                try {\n                    $offset = 0;\n                    $chunk[1]->getStatusCode();\n                    $chunk[1]->getHeaders(false);\n                    self::readResponse($response, $chunk[0], $chunk[1], $offset);\n                    $multi->handlesActivity[$id][] = new FirstChunk();\n                } catch (\\Throwable $e) {\n                    $multi->handlesActivity[$id][] = null;\n                    $multi->handlesActivity[$id][] = $e;\n                }\n            } elseif ($chunk instanceof \\Throwable) {\n                $multi->handlesActivity[$id][] = null;\n                $multi->handlesActivity[$id][] = $chunk;\n            } else {\n                // Data or timeout chunk\n                $multi->handlesActivity[$id][] = $chunk;\n            }\n        }\n    }\n\n    protected static function select(ClientState $multi, float $timeout): int\n    {\n        return 42;\n    }\n\n    /**\n     * Simulates sending the request.\n     */\n    private static function writeRequest(self $response, array $options, ResponseInterface $mock): void\n    {\n        $onProgress = $options['on_progress'] ?? static function () {};\n        $response->info += $mock->getInfo() ?: [];\n\n        // simulate \"size_upload\" if it is set\n        if (isset($response->info['size_upload'])) {\n            $response->info['size_upload'] = 0.0;\n        }\n\n        // simulate \"total_time\" if it is not set\n        if (!isset($response->info['total_time'])) {\n            $response->info['total_time'] = microtime(true) - $response->info['start_time'];\n        }\n\n        // \"notify\" DNS resolution\n        $onProgress(0, 0, $response->info);\n\n        // consume the request body\n        if (\\is_resource($body = $options['body'] ?? '')) {\n            $data = stream_get_contents($body);\n            if (isset($response->info['size_upload'])) {\n                $response->info['size_upload'] += \\strlen($data);\n            }\n        } elseif ($body instanceof \\Closure) {\n            while ('' !== $data = $body(16372)) {\n                if (!\\is_string($data)) {\n                    throw new TransportException(\\sprintf('Return value of the \"body\" option callback must be string, \"%s\" returned.', get_debug_type($data)));\n                }\n\n                // \"notify\" upload progress\n                if (isset($response->info['size_upload'])) {\n                    $response->info['size_upload'] += \\strlen($data);\n                }\n\n                $onProgress(0, 0, $response->info);\n            }\n        }\n    }\n\n    /**\n     * Simulates reading the response.\n     */\n    private static function readResponse(self $response, array $options, ResponseInterface $mock, int &$offset): void\n    {\n        $onProgress = $options['on_progress'] ?? static function () {};\n\n        // populate info related to headers\n        $info = $mock->getInfo() ?: [];\n        $response->info['http_code'] = ($info['http_code'] ?? 0) ?: $mock->getStatusCode() ?: 200;\n        $response->addResponseHeaders($info['response_headers'] ?? [], $response->info, $response->headers);\n        $dlSize = isset($response->headers['content-encoding']) || 'HEAD' === $response->info['http_method'] || \\in_array($response->info['http_code'], [204, 304], true) ? 0 : (int) ($response->headers['content-length'][0] ?? 0);\n\n        $response->info = [\n            'start_time' => $response->info['start_time'],\n            'user_data' => $response->info['user_data'],\n            'max_duration' => $response->info['max_duration'],\n            'http_code' => $response->info['http_code'],\n        ] + $info + $response->info;\n\n        if (null !== $response->info['error']) {\n            throw new TransportException($response->info['error']);\n        }\n\n        if (!isset($response->info['total_time'])) {\n            $response->info['total_time'] = microtime(true) - $response->info['start_time'];\n        }\n\n        // \"notify\" headers arrival\n        $onProgress(0, $dlSize, $response->info);\n\n        // cast response body to activity list\n        $body = $mock instanceof self ? $mock->body : $mock->getContent(false);\n\n        if (!\\is_string($body)) {\n            try {\n                foreach ($body as $chunk) {\n                    if ($chunk instanceof \\Throwable) {\n                        throw $chunk;\n                    }\n\n                    if ('' === $chunk = (string) $chunk) {\n                        // simulate an idle timeout\n                        $response->body[] = new ErrorChunk($offset, \\sprintf('Idle timeout reached for \"%s\".', $response->info['url']));\n                    } else {\n                        $response->body[] = $chunk;\n                        $offset += \\strlen($chunk);\n                        // \"notify\" download progress\n                        $onProgress($offset, $dlSize, $response->info);\n                    }\n                }\n            } catch (\\Throwable $e) {\n                $response->body[] = $e;\n            }\n        } elseif ('' !== $body) {\n            $response->body[] = $body;\n            $offset = \\strlen($body);\n        }\n\n        if (!isset($response->info['total_time'])) {\n            $response->info['total_time'] = microtime(true) - $response->info['start_time'];\n        }\n\n        // \"notify\" completion\n        $onProgress($offset, $dlSize, $response->info);\n\n        if ($dlSize && $offset !== $dlSize) {\n            throw new TransportException(\\sprintf('Transfer closed with %d bytes remaining to read.', $dlSize - $offset));\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/Response/NativeResponse.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient\\Response;\n\nuse Psr\\Log\\LoggerInterface;\nuse Symfony\\Component\\HttpClient\\Chunk\\FirstChunk;\nuse Symfony\\Component\\HttpClient\\Exception\\TransportException;\nuse Symfony\\Component\\HttpClient\\Internal\\Canary;\nuse Symfony\\Component\\HttpClient\\Internal\\ClientState;\nuse Symfony\\Component\\HttpClient\\Internal\\NativeClientState;\nuse Symfony\\Contracts\\HttpClient\\ResponseInterface;\n\n/**\n * @author Nicolas Grekas <p@tchwork.com>\n *\n * @internal\n */\nfinal class NativeResponse implements ResponseInterface, StreamableInterface\n{\n    use CommonResponseTrait;\n    use TransportResponseTrait;\n\n    /**\n     * @var resource\n     */\n    private $context;\n    private string $url;\n    private \\Closure $resolver;\n    private ?\\Closure $onProgress;\n    private ?int $remaining = null;\n\n    /**\n     * @var resource|null\n     */\n    private $buffer;\n\n    private NativeClientState $multi;\n    private float $pauseExpiry = 0.0;\n\n    /**\n     * @internal\n     */\n    public function __construct(NativeClientState $multi, $context, string $url, array $options, array &$info, callable $resolver, ?callable $onProgress, ?LoggerInterface $logger)\n    {\n        $this->multi = $multi;\n        $this->id = $id = (int) $context;\n        $this->context = $context;\n        $this->url = $url;\n        $this->logger = $logger;\n        $this->timeout = $options['timeout'];\n        $this->info = &$info;\n        $this->resolver = $resolver(...);\n        $this->onProgress = $onProgress ? $onProgress(...) : null;\n        $this->inflate = !isset($options['normalized_headers']['accept-encoding']);\n        $this->shouldBuffer = $options['buffer'] ?? true;\n\n        // Temporary resource to dechunk the response stream\n        $this->buffer = fopen('php://temp', 'w+');\n\n        $info['original_url'] = implode('', $info['url']);\n        $info['user_data'] = $options['user_data'];\n        $info['max_duration'] = $options['max_duration'];\n        ++$multi->responseCount;\n\n        $this->initializer = static fn (self $response) => null === $response->remaining;\n\n        $pauseExpiry = &$this->pauseExpiry;\n        $info['pause_handler'] = static function (float $duration) use (&$pauseExpiry) {\n            $pauseExpiry = 0 < $duration ? hrtime(true) / 1E9 + $duration : 0;\n        };\n\n        $this->canary = new Canary(static function () use ($multi, $id) {\n            if (null !== ($host = $multi->openHandles[$id][6] ?? null) && isset($multi->hosts[$host]) && 0 >= --$multi->hosts[$host]) {\n                unset($multi->hosts[$host]);\n            }\n            unset($multi->openHandles[$id], $multi->handlesActivity[$id]);\n        });\n    }\n\n    public function getInfo(?string $type = null): mixed\n    {\n        if (!$info = $this->finalInfo) {\n            $info = $this->info;\n            $info['url'] = implode('', $info['url']);\n            unset($info['size_body'], $info['request_header']);\n\n            if (null === $this->buffer) {\n                $this->finalInfo = $info;\n            }\n        }\n\n        return null !== $type ? $info[$type] ?? null : $info;\n    }\n\n    public function __destruct()\n    {\n        try {\n            $this->doDestruct();\n        } finally {\n            // Clear the DNS cache when all requests completed\n            if (0 >= --$this->multi->responseCount) {\n                $this->multi->responseCount = 0;\n                $this->multi->dnsCache = [];\n            }\n        }\n    }\n\n    private function open(): void\n    {\n        $url = $this->url;\n\n        set_error_handler(function ($type, $msg) use (&$url) {\n            if (\\E_NOTICE !== $type || 'fopen(): Content-type not specified assuming application/x-www-form-urlencoded' !== $msg) {\n                throw new TransportException($msg);\n            }\n\n            $this->logger?->info(\\sprintf('%s for \"%s\".', $msg, $url ?? $this->url));\n        });\n\n        try {\n            $this->info['start_time'] = microtime(true);\n\n            [$resolver, $url] = ($this->resolver)($this->multi);\n\n            while (true) {\n                $context = stream_context_get_options($this->context);\n\n                if ($proxy = $context['http']['proxy'] ?? null) {\n                    $this->info['debug'] .= \"* Establish HTTP proxy tunnel to {$proxy}\\n\";\n                    $this->info['request_header'] = $url;\n                } else {\n                    $this->info['debug'] .= \"*   Trying {$this->info['primary_ip']}...\\n\";\n                    $this->info['request_header'] = $this->info['url']['path'].$this->info['url']['query'];\n                }\n\n                $this->info['request_header'] = \\sprintf(\"> %s %s HTTP/%s \\r\\n\", $context['http']['method'], $this->info['request_header'], $context['http']['protocol_version']);\n                $this->info['request_header'] .= implode(\"\\r\\n\", $context['http']['header']).\"\\r\\n\\r\\n\";\n\n                if (\\array_key_exists('peer_name', $context['ssl']) && null === $context['ssl']['peer_name']) {\n                    unset($context['ssl']['peer_name']);\n                    $this->context = stream_context_create([], ['options' => $context] + stream_context_get_params($this->context));\n                }\n\n                // Send request and follow redirects when needed\n                $this->handle = $h = fopen($url, 'r', false, $this->context);\n                self::addResponseHeaders(stream_get_meta_data($h)['wrapper_data'], $this->info, $this->headers, $this->info['debug']);\n                $url = $resolver($this->multi, $this->headers['location'][0] ?? null, $this->context);\n\n                if (null === $url) {\n                    break;\n                }\n\n                $this->logger?->info(\\sprintf('Redirecting: \"%s %s\"', $this->info['http_code'], $url ?? $this->url));\n            }\n        } catch (\\Throwable $e) {\n            $this->close();\n            $this->multi->handlesActivity[$this->id][] = null;\n            $this->multi->handlesActivity[$this->id][] = $e;\n\n            return;\n        } finally {\n            $this->info['pretransfer_time'] = $this->info['total_time'] = microtime(true) - $this->info['start_time'];\n            restore_error_handler();\n        }\n\n        if (isset($context['ssl']['capture_peer_cert_chain']) && isset(($context = stream_context_get_options($this->context))['ssl']['peer_certificate_chain'])) {\n            $this->info['peer_certificate_chain'] = $context['ssl']['peer_certificate_chain'];\n        }\n\n        stream_set_blocking($h, false);\n        unset($this->context, $this->resolver);\n\n        // Create dechunk buffers\n        if (isset($this->headers['content-length'])) {\n            $this->remaining = (int) $this->headers['content-length'][0];\n        } elseif ('chunked' === ($this->headers['transfer-encoding'][0] ?? null)) {\n            stream_filter_append($this->buffer, 'dechunk', \\STREAM_FILTER_WRITE);\n            $this->remaining = -1;\n        } else {\n            $this->remaining = -2;\n        }\n\n        $this->multi->handlesActivity[$this->id] = [new FirstChunk()];\n\n        if ('HEAD' === $context['http']['method'] || \\in_array($this->info['http_code'], [204, 304], true)) {\n            $this->multi->handlesActivity[$this->id][] = null;\n            $this->multi->handlesActivity[$this->id][] = null;\n\n            return;\n        }\n\n        $host = parse_url($this->info['redirect_url'] ?? $this->url, \\PHP_URL_HOST);\n        $this->multi->lastTimeout = null;\n        $this->multi->openHandles[$this->id] = [&$this->pauseExpiry, $h, $this->buffer, $this->onProgress, &$this->remaining, &$this->info, $host];\n        $this->multi->hosts[$host] = 1 + ($this->multi->hosts[$host] ?? 0);\n    }\n\n    private function close(): void\n    {\n        $this->canary->cancel();\n        $this->handle = $this->buffer = $this->inflate = $this->onProgress = null;\n    }\n\n    private static function schedule(self $response, array &$runningResponses): void\n    {\n        if (!isset($runningResponses[$i = $response->multi->id])) {\n            $runningResponses[$i] = [$response->multi, []];\n        }\n\n        $runningResponses[$i][1][$response->id] = $response;\n\n        if (null === $response->buffer) {\n            // Response already completed\n            $response->multi->handlesActivity[$response->id][] = null;\n            $response->multi->handlesActivity[$response->id][] = null !== $response->info['error'] ? new TransportException($response->info['error']) : null;\n        }\n    }\n\n    /**\n     * @param NativeClientState $multi\n     */\n    private static function perform(ClientState $multi, ?array $responses = null): void\n    {\n        foreach ($multi->openHandles as $i => [$pauseExpiry, $h, $buffer, $onProgress]) {\n            if ($pauseExpiry) {\n                if (hrtime(true) / 1E9 < $pauseExpiry) {\n                    continue;\n                }\n\n                $multi->openHandles[$i][0] = 0;\n            }\n\n            $hasActivity = false;\n            $remaining = &$multi->openHandles[$i][4];\n            $info = &$multi->openHandles[$i][5];\n            $e = null;\n\n            // Read incoming buffer and write it to the dechunk one\n            try {\n                if ($remaining && '' !== $data = (string) fread($h, 0 > $remaining ? 16372 : $remaining)) {\n                    fwrite($buffer, $data);\n                    $hasActivity = true;\n                    $multi->sleep = false;\n\n                    if (-1 !== $remaining) {\n                        $remaining -= \\strlen($data);\n                    }\n                }\n            } catch (\\Throwable $e) {\n                $hasActivity = $onProgress = false;\n            }\n\n            if (!$hasActivity) {\n                if ($onProgress) {\n                    try {\n                        // Notify the progress callback so that it can e.g. cancel\n                        // the request if the stream is inactive for too long\n                        $info['total_time'] = microtime(true) - $info['start_time'];\n                        $onProgress();\n                    } catch (\\Throwable $e) {\n                        // no-op\n                    }\n                }\n            } elseif ('' !== $data = stream_get_contents($buffer, -1, 0)) {\n                rewind($buffer);\n                ftruncate($buffer, 0);\n\n                if (null === $e) {\n                    $multi->handlesActivity[$i][] = $data;\n                }\n            }\n\n            if (null !== $e || !$remaining || feof($h)) {\n                // Stream completed\n                $info['total_time'] = microtime(true) - $info['start_time'];\n                $info['starttransfer_time'] = $info['starttransfer_time'] ?: $info['total_time'];\n\n                if ($onProgress) {\n                    try {\n                        $onProgress(-1);\n                    } catch (\\Throwable $e) {\n                        // no-op\n                    }\n                }\n\n                if (null === $e) {\n                    if (0 < $remaining) {\n                        $e = new TransportException(\\sprintf('Transfer closed with %s bytes remaining to read.', $remaining));\n                    } elseif (-1 === $remaining && fwrite($buffer, '-') && '' !== stream_get_contents($buffer, -1, 0)) {\n                        $e = new TransportException('Transfer closed with outstanding data remaining from chunked response.');\n                    }\n                }\n\n                $multi->handlesActivity[$i][] = null;\n                $multi->handlesActivity[$i][] = $e;\n                if (null !== ($host = $multi->openHandles[$i][6] ?? null) && isset($multi->hosts[$host]) && 0 >= --$multi->hosts[$host]) {\n                    unset($multi->hosts[$host]);\n                }\n                unset($multi->openHandles[$i]);\n                $multi->sleep = false;\n            }\n        }\n\n        if (null === $responses) {\n            return;\n        }\n\n        $maxHosts = $multi->maxHostConnections;\n\n        foreach ($responses as $i => $response) {\n            if (null !== $response->remaining || null === $response->buffer) {\n                continue;\n            }\n\n            if ($response->pauseExpiry && hrtime(true) / 1E9 < $response->pauseExpiry) {\n                // Create empty open handles to tell we still have pending requests\n                $multi->openHandles[$i] = [\\INF, null, null, null];\n            } elseif ($maxHosts && $maxHosts > ($multi->hosts[parse_url($response->url, \\PHP_URL_HOST)] ?? 0)) {\n                // Open the next pending request - this is a blocking operation so we do only one of them\n                $response->open();\n                $multi->sleep = false;\n                self::perform($multi);\n                $maxHosts = 0;\n            }\n        }\n    }\n\n    /**\n     * @param NativeClientState $multi\n     */\n    private static function select(ClientState $multi, float $timeout): int\n    {\n        if (!$multi->sleep = !$multi->sleep) {\n            return -1;\n        }\n\n        $_ = $handles = [];\n        $now = null;\n\n        foreach ($multi->openHandles as [$pauseExpiry, $h]) {\n            if (null === $h) {\n                continue;\n            }\n\n            if ($pauseExpiry && ($now ??= hrtime(true) / 1E9) < $pauseExpiry) {\n                $timeout = min($timeout, $pauseExpiry - $now);\n                continue;\n            }\n\n            $handles[] = $h;\n        }\n\n        if (!$handles) {\n            usleep((int) (1E6 * $timeout));\n\n            return 0;\n        }\n\n        return stream_select($handles, $_, $_, (int) $timeout, (int) (1E6 * ($timeout - (int) $timeout)));\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/Response/ResponseStream.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient\\Response;\n\nuse Symfony\\Contracts\\HttpClient\\ChunkInterface;\nuse Symfony\\Contracts\\HttpClient\\ResponseInterface;\nuse Symfony\\Contracts\\HttpClient\\ResponseStreamInterface;\n\n/**\n * @author Nicolas Grekas <p@tchwork.com>\n */\nfinal class ResponseStream implements ResponseStreamInterface\n{\n    private \\Generator $generator;\n\n    public function __construct(\\Generator $generator)\n    {\n        $this->generator = $generator;\n    }\n\n    public function key(): ResponseInterface\n    {\n        return $this->generator->key();\n    }\n\n    public function current(): ChunkInterface\n    {\n        return $this->generator->current();\n    }\n\n    public function next(): void\n    {\n        $this->generator->next();\n    }\n\n    public function rewind(): void\n    {\n        $this->generator->rewind();\n    }\n\n    public function valid(): bool\n    {\n        return $this->generator->valid();\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/Response/StreamWrapper.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient\\Response;\n\nuse Symfony\\Contracts\\HttpClient\\Exception\\ExceptionInterface;\nuse Symfony\\Contracts\\HttpClient\\HttpClientInterface;\nuse Symfony\\Contracts\\HttpClient\\ResponseInterface;\n\n/**\n * Allows turning ResponseInterface instances to PHP streams.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n */\nclass StreamWrapper\n{\n    /** @var resource|null */\n    public $context;\n\n    private HttpClientInterface|ResponseInterface $client;\n\n    private ResponseInterface $response;\n\n    /** @var resource|string|null */\n    private $content;\n\n    /** @var resource|callable|null */\n    private $handle;\n\n    private bool $blocking = true;\n    private ?float $timeout = null;\n    private bool $eof = false;\n    private ?int $offset = 0;\n\n    /**\n     * Creates a PHP stream resource from a ResponseInterface.\n     *\n     * @return resource\n     */\n    public static function createResource(ResponseInterface $response, ?HttpClientInterface $client = null)\n    {\n        if ($response instanceof StreamableInterface) {\n            $stack = debug_backtrace(\\DEBUG_BACKTRACE_PROVIDE_OBJECT | \\DEBUG_BACKTRACE_IGNORE_ARGS, 2);\n\n            if ($response !== ($stack[1]['object'] ?? null)) {\n                return $response->toStream(false);\n            }\n        }\n\n        if (null === $client && !method_exists($response, 'stream')) {\n            throw new \\InvalidArgumentException(\\sprintf('Providing a client to \"%s()\" is required when the response doesn\\'t have any \"stream()\" method.', __CLASS__));\n        }\n\n        static $registered = false;\n\n        if (!$registered = $registered || stream_wrapper_register(strtr(__CLASS__, '\\\\', '-'), __CLASS__)) {\n            throw new \\RuntimeException(error_get_last()['message'] ?? 'Registering the \"symfony\" stream wrapper failed.');\n        }\n\n        $context = [\n            'client' => $client ?? $response,\n            'response' => $response,\n        ];\n\n        return fopen(strtr(__CLASS__, '\\\\', '-').'://'.$response->getInfo('url'), 'r', false, stream_context_create(['symfony' => $context]));\n    }\n\n    public function getResponse(): ResponseInterface\n    {\n        return $this->response;\n    }\n\n    /**\n     * @param resource|callable|null $handle  The resource handle that should be monitored when\n     *                                        stream_select() is used on the created stream\n     * @param resource|null          $content The seekable resource where the response body is buffered\n     */\n    public function bindHandles(&$handle, &$content): void\n    {\n        $this->handle = &$handle;\n        $this->content = &$content;\n        $this->offset = null;\n    }\n\n    public function stream_open(string $path, string $mode, int $options): bool\n    {\n        if ('r' !== $mode) {\n            if ($options & \\STREAM_REPORT_ERRORS) {\n                trigger_error(\\sprintf('Invalid mode \"%s\": only \"r\" is supported.', $mode), \\E_USER_WARNING);\n            }\n\n            return false;\n        }\n\n        $context = stream_context_get_options($this->context)['symfony'] ?? null;\n        $this->client = $context['client'] ?? null;\n        $this->response = $context['response'] ?? null;\n        $this->context = null;\n\n        if (null !== $this->client && null !== $this->response) {\n            return true;\n        }\n\n        if ($options & \\STREAM_REPORT_ERRORS) {\n            trigger_error('Missing options \"client\" or \"response\" in \"symfony\" stream context.', \\E_USER_WARNING);\n        }\n\n        return false;\n    }\n\n    public function stream_read(int $count): string|false\n    {\n        if (\\is_resource($this->content)) {\n            // Empty the internal activity list\n            foreach ($this->client->stream([$this->response], 0) as $chunk) {\n                try {\n                    if (!$chunk->isTimeout() && $chunk->isFirst()) {\n                        $this->response->getStatusCode(); // ignore 3/4/5xx\n                    }\n                } catch (ExceptionInterface $e) {\n                    trigger_error($e->getMessage(), \\E_USER_WARNING);\n\n                    return false;\n                }\n            }\n\n            if (0 !== fseek($this->content, $this->offset ?? 0)) {\n                return false;\n            }\n\n            if ('' !== $data = fread($this->content, $count)) {\n                fseek($this->content, 0, \\SEEK_END);\n                $this->offset += \\strlen($data);\n\n                return $data;\n            }\n        }\n\n        if (\\is_string($this->content)) {\n            if (\\strlen($this->content) <= $count) {\n                $data = $this->content;\n                $this->content = null;\n            } else {\n                $data = substr($this->content, 0, $count);\n                $this->content = substr($this->content, $count);\n            }\n            $this->offset += \\strlen($data);\n\n            return $data;\n        }\n\n        foreach ($this->client->stream([$this->response], $this->blocking ? $this->timeout : 0) as $chunk) {\n            try {\n                $this->eof = true;\n                $this->eof = !$chunk->isTimeout();\n\n                if (!$this->eof && !$this->blocking) {\n                    return '';\n                }\n\n                $this->eof = $chunk->isLast();\n\n                if ($chunk->isFirst()) {\n                    $this->response->getStatusCode(); // ignore 3/4/5xx\n                }\n\n                if ('' !== $data = $chunk->getContent()) {\n                    if (\\strlen($data) > $count) {\n                        $this->content ??= substr($data, $count);\n                        $data = substr($data, 0, $count);\n                    }\n                    $this->offset += \\strlen($data);\n\n                    return $data;\n                }\n            } catch (ExceptionInterface $e) {\n                trigger_error($e->getMessage(), \\E_USER_WARNING);\n\n                return false;\n            }\n        }\n\n        return '';\n    }\n\n    public function stream_set_option(int $option, int $arg1, ?int $arg2): bool\n    {\n        if (\\STREAM_OPTION_BLOCKING === $option) {\n            $this->blocking = (bool) $arg1;\n        } elseif (\\STREAM_OPTION_READ_TIMEOUT === $option) {\n            $this->timeout = $arg1 + $arg2 / 1e6;\n        } else {\n            return false;\n        }\n\n        return true;\n    }\n\n    public function stream_tell(): int\n    {\n        return $this->offset ?? 0;\n    }\n\n    public function stream_eof(): bool\n    {\n        return $this->eof && !\\is_string($this->content);\n    }\n\n    public function stream_seek(int $offset, int $whence = \\SEEK_SET): bool\n    {\n        if (null === $this->content && null === $this->offset) {\n            $this->response->getStatusCode();\n            $this->offset = 0;\n        }\n\n        if (!\\is_resource($this->content) || 0 !== fseek($this->content, 0, \\SEEK_END)) {\n            return false;\n        }\n\n        $size = ftell($this->content);\n\n        if (\\SEEK_CUR === $whence) {\n            $offset += $this->offset ?? 0;\n        }\n\n        if (\\SEEK_END === $whence || $size < $offset) {\n            foreach ($this->client->stream([$this->response]) as $chunk) {\n                try {\n                    if ($chunk->isFirst()) {\n                        $this->response->getStatusCode(); // ignore 3/4/5xx\n                    }\n\n                    // Chunks are buffered in $this->content already\n                    $size += \\strlen($chunk->getContent());\n\n                    if (\\SEEK_END !== $whence && $offset <= $size) {\n                        break;\n                    }\n                } catch (ExceptionInterface $e) {\n                    trigger_error($e->getMessage(), \\E_USER_WARNING);\n\n                    return false;\n                }\n            }\n\n            if (\\SEEK_END === $whence) {\n                $offset += $size;\n            }\n        }\n\n        if (0 <= $offset && $offset <= $size) {\n            $this->eof = false;\n            $this->offset = $offset;\n\n            return true;\n        }\n\n        return false;\n    }\n\n    /**\n     * @return resource|false\n     */\n    public function stream_cast(int $castAs)\n    {\n        if (\\STREAM_CAST_FOR_SELECT === $castAs) {\n            $this->response->getHeaders(false);\n\n            return (\\is_callable($this->handle) ? ($this->handle)() : $this->handle) ?? false;\n        }\n\n        return false;\n    }\n\n    public function stream_stat(): array\n    {\n        try {\n            $headers = $this->response->getHeaders(false);\n        } catch (ExceptionInterface $e) {\n            trigger_error($e->getMessage(), \\E_USER_WARNING);\n            $headers = [];\n        }\n\n        return [\n            'dev' => 0,\n            'ino' => 0,\n            'mode' => 33060,\n            'nlink' => 0,\n            'uid' => 0,\n            'gid' => 0,\n            'rdev' => 0,\n            'size' => (int) ($headers['content-length'][0] ?? -1),\n            'atime' => 0,\n            'mtime' => strtotime($headers['last-modified'][0] ?? '') ?: 0,\n            'ctime' => 0,\n            'blksize' => 0,\n            'blocks' => 0,\n        ];\n    }\n\n    private function __construct()\n    {\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/Response/StreamableInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient\\Response;\n\nuse Symfony\\Contracts\\HttpClient\\Exception\\ClientExceptionInterface;\nuse Symfony\\Contracts\\HttpClient\\Exception\\RedirectionExceptionInterface;\nuse Symfony\\Contracts\\HttpClient\\Exception\\ServerExceptionInterface;\nuse Symfony\\Contracts\\HttpClient\\Exception\\TransportExceptionInterface;\n\n/**\n * @author Nicolas Grekas <p@tchwork.com>\n */\ninterface StreamableInterface\n{\n    /**\n     * Casts the response to a PHP stream resource.\n     *\n     * @return resource\n     *\n     * @throws TransportExceptionInterface   When a network error occurs\n     * @throws RedirectionExceptionInterface On a 3xx when $throw is true and the \"max_redirects\" option has been reached\n     * @throws ClientExceptionInterface      On a 4xx when $throw is true\n     * @throws ServerExceptionInterface      On a 5xx when $throw is true\n     */\n    public function toStream(bool $throw = true);\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/Response/TraceableResponse.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient\\Response;\n\nuse Symfony\\Component\\HttpClient\\Chunk\\ErrorChunk;\nuse Symfony\\Component\\HttpClient\\Exception\\ClientException;\nuse Symfony\\Component\\HttpClient\\Exception\\RedirectionException;\nuse Symfony\\Component\\HttpClient\\Exception\\ServerException;\nuse Symfony\\Component\\HttpClient\\TraceableHttpClient;\nuse Symfony\\Component\\Stopwatch\\StopwatchEvent;\nuse Symfony\\Contracts\\HttpClient\\Exception\\ClientExceptionInterface;\nuse Symfony\\Contracts\\HttpClient\\Exception\\RedirectionExceptionInterface;\nuse Symfony\\Contracts\\HttpClient\\Exception\\ServerExceptionInterface;\nuse Symfony\\Contracts\\HttpClient\\Exception\\TransportExceptionInterface;\nuse Symfony\\Contracts\\HttpClient\\HttpClientInterface;\nuse Symfony\\Contracts\\HttpClient\\ResponseInterface;\n\n/**\n * @author Nicolas Grekas <p@tchwork.com>\n *\n * @internal\n */\nclass TraceableResponse implements ResponseInterface, StreamableInterface\n{\n    private HttpClientInterface $client;\n    private ResponseInterface $response;\n    private mixed $content;\n    private ?StopwatchEvent $event;\n\n    public function __construct(HttpClientInterface $client, ResponseInterface $response, &$content, ?StopwatchEvent $event = null)\n    {\n        $this->client = $client;\n        $this->response = $response;\n        $this->content = &$content;\n        $this->event = $event;\n    }\n\n    public function __serialize(): array\n    {\n        throw new \\BadMethodCallException('Cannot serialize '.__CLASS__);\n    }\n\n    public function __unserialize(array $data): void\n    {\n        throw new \\BadMethodCallException('Cannot unserialize '.__CLASS__);\n    }\n\n    public function __destruct()\n    {\n        try {\n            if (method_exists($this->response, '__destruct')) {\n                $this->response->__destruct();\n            }\n        } finally {\n            if ($this->event?->isStarted()) {\n                $this->event->stop();\n            }\n        }\n    }\n\n    public function getStatusCode(): int\n    {\n        try {\n            return $this->response->getStatusCode();\n        } finally {\n            if ($this->event?->isStarted()) {\n                $this->event->lap();\n            }\n        }\n    }\n\n    public function getHeaders(bool $throw = true): array\n    {\n        try {\n            return $this->response->getHeaders($throw);\n        } finally {\n            if ($this->event?->isStarted()) {\n                $this->event->lap();\n            }\n        }\n    }\n\n    public function getContent(bool $throw = true): string\n    {\n        try {\n            if (false === $this->content) {\n                return $this->response->getContent($throw);\n            }\n\n            return $this->content = $this->response->getContent(false);\n        } finally {\n            if ($this->event?->isStarted()) {\n                $this->event->stop();\n            }\n            if ($throw) {\n                $this->checkStatusCode($this->response->getStatusCode());\n            }\n        }\n    }\n\n    public function toArray(bool $throw = true): array\n    {\n        try {\n            if (false === $this->content) {\n                return $this->response->toArray($throw);\n            }\n\n            return $this->content = $this->response->toArray(false);\n        } finally {\n            if ($this->event?->isStarted()) {\n                $this->event->stop();\n            }\n            if ($throw) {\n                $this->checkStatusCode($this->response->getStatusCode());\n            }\n        }\n    }\n\n    public function cancel(): void\n    {\n        $this->response->cancel();\n\n        if ($this->event?->isStarted()) {\n            $this->event->stop();\n        }\n    }\n\n    public function getInfo(?string $type = null): mixed\n    {\n        return $this->response->getInfo($type);\n    }\n\n    /**\n     * Casts the response to a PHP stream resource.\n     *\n     * @return resource\n     *\n     * @throws TransportExceptionInterface   When a network error occurs\n     * @throws RedirectionExceptionInterface On a 3xx when $throw is true and the \"max_redirects\" option has been reached\n     * @throws ClientExceptionInterface      On a 4xx when $throw is true\n     * @throws ServerExceptionInterface      On a 5xx when $throw is true\n     */\n    public function toStream(bool $throw = true)\n    {\n        if ($throw) {\n            // Ensure headers arrived\n            $this->response->getHeaders(true);\n        }\n\n        if ($this->response instanceof StreamableInterface) {\n            return $this->response->toStream(false);\n        }\n\n        return StreamWrapper::createResource($this->response, $this->client);\n    }\n\n    /**\n     * @internal\n     */\n    public static function stream(HttpClientInterface $client, iterable $responses, ?float $timeout): \\Generator\n    {\n        $wrappedResponses = [];\n        $traceableMap = new \\SplObjectStorage();\n\n        foreach ($responses as $r) {\n            if (!$r instanceof self) {\n                throw new \\TypeError(\\sprintf('\"%s::stream()\" expects parameter 1 to be an iterable of TraceableResponse objects, \"%s\" given.', TraceableHttpClient::class, get_debug_type($r)));\n            }\n\n            $traceableMap[$r->response] = $r;\n            $wrappedResponses[] = $r->response;\n            if ($r->event && !$r->event->isStarted()) {\n                $r->event->start();\n            }\n        }\n\n        foreach ($client->stream($wrappedResponses, $timeout) as $r => $chunk) {\n            if ($traceableMap[$r]->event && $traceableMap[$r]->event->isStarted()) {\n                try {\n                    if ($chunk->isTimeout() || !$chunk->isLast()) {\n                        $traceableMap[$r]->event->lap();\n                    } else {\n                        $traceableMap[$r]->event->stop();\n                    }\n                } catch (TransportExceptionInterface $e) {\n                    $traceableMap[$r]->event->stop();\n                    if ($chunk instanceof ErrorChunk) {\n                        $chunk->didThrow(false);\n                    } else {\n                        $chunk = new ErrorChunk($chunk->getOffset(), $e);\n                    }\n                }\n            }\n            yield $traceableMap[$r] => $chunk;\n        }\n    }\n\n    private function checkStatusCode(int $code): void\n    {\n        if (500 <= $code) {\n            throw new ServerException($this);\n        }\n\n        if (400 <= $code) {\n            throw new ClientException($this);\n        }\n\n        if (300 <= $code) {\n            throw new RedirectionException($this);\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/Response/TransportResponseTrait.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient\\Response;\n\nuse Psr\\Log\\LoggerInterface;\nuse Symfony\\Component\\HttpClient\\Chunk\\DataChunk;\nuse Symfony\\Component\\HttpClient\\Chunk\\ErrorChunk;\nuse Symfony\\Component\\HttpClient\\Chunk\\FirstChunk;\nuse Symfony\\Component\\HttpClient\\Chunk\\LastChunk;\nuse Symfony\\Component\\HttpClient\\Exception\\TransportException;\nuse Symfony\\Component\\HttpClient\\Internal\\Canary;\nuse Symfony\\Component\\HttpClient\\Internal\\ClientState;\n\n/**\n * Implements common logic for transport-level response classes.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n *\n * @internal\n */\ntrait TransportResponseTrait\n{\n    private Canary $canary;\n    private array $headers = [];\n    private array $info = [\n        'response_headers' => [],\n        'http_code' => 0,\n        'error' => null,\n        'canceled' => false,\n    ];\n\n    /** @var object|resource|null */\n    private $handle;\n    private int|string $id;\n    private ?float $timeout = 0;\n    private \\InflateContext|bool|null $inflate = null;\n    private ?array $finalInfo = null;\n    private ?LoggerInterface $logger = null;\n\n    public function getStatusCode(): int\n    {\n        if ($this->initializer) {\n            self::initialize($this);\n        }\n\n        return $this->info['http_code'];\n    }\n\n    public function getHeaders(bool $throw = true): array\n    {\n        if ($this->initializer) {\n            self::initialize($this);\n        }\n\n        if ($throw) {\n            $this->checkStatusCode();\n        }\n\n        return $this->headers;\n    }\n\n    public function cancel(): void\n    {\n        $this->info['canceled'] = true;\n        $this->info['error'] = 'Response has been canceled.';\n        $this->close();\n    }\n\n    /**\n     * Closes the response and all its network handles.\n     */\n    protected function close(): void\n    {\n        $this->canary->cancel();\n        $this->inflate = null;\n    }\n\n    /**\n     * Adds pending responses to the activity list.\n     */\n    abstract protected static function schedule(self $response, array &$runningResponses): void;\n\n    /**\n     * Performs all pending non-blocking operations.\n     */\n    abstract protected static function perform(ClientState $multi, array $responses): void;\n\n    /**\n     * Waits for network activity.\n     */\n    abstract protected static function select(ClientState $multi, float $timeout): int;\n\n    private static function addResponseHeaders(array $responseHeaders, array &$info, array &$headers, string &$debug = ''): void\n    {\n        foreach ($responseHeaders as $h) {\n            if (11 <= \\strlen($h) && '/' === $h[4] && preg_match('#^HTTP/\\d+(?:\\.\\d+)? (\\d\\d\\d)(?: |$)#', $h, $m)) {\n                if ($headers) {\n                    $debug .= \"< \\r\\n\";\n                    $headers = [];\n                }\n                $info['http_code'] = (int) $m[1];\n            } elseif (2 === \\count($m = explode(':', $h, 2))) {\n                $headers[strtolower($m[0])][] = ltrim($m[1]);\n            }\n\n            $debug .= \"< {$h}\\r\\n\";\n            $info['response_headers'][] = $h;\n        }\n\n        $debug .= \"< \\r\\n\";\n    }\n\n    /**\n     * Ensures the request is always sent and that the response code was checked.\n     */\n    private function doDestruct(): void\n    {\n        $this->shouldBuffer = true;\n\n        if ($this->initializer && null === $this->info['error']) {\n            self::initialize($this);\n            $this->checkStatusCode();\n        }\n    }\n\n    /**\n     * Implements an event loop based on a buffer activity queue.\n     *\n     * @param iterable<array-key, self> $responses\n     *\n     * @internal\n     */\n    public static function stream(iterable $responses, ?float $timeout = null): \\Generator\n    {\n        $runningResponses = [];\n\n        foreach ($responses as $response) {\n            self::schedule($response, $runningResponses);\n        }\n\n        $lastActivity = hrtime(true) / 1E9;\n        $elapsedTimeout = 0;\n\n        if ((0.0 === $timeout && '-0' === (string) $timeout) || 0 > $timeout) {\n            $timeout = $timeout ? -$timeout : null;\n\n            /** @var ClientState $multi */\n            foreach ($runningResponses as [$multi]) {\n                if (null !== $multi->lastTimeout) {\n                    $elapsedTimeout = max($elapsedTimeout, $lastActivity - $multi->lastTimeout);\n                }\n            }\n        }\n\n        while (true) {\n            $hasActivity = false;\n            $timeoutMax = 0;\n            $timeoutMin = $timeout ?? \\INF;\n\n            /** @var ClientState $multi */\n            foreach ($runningResponses as $i => [$multi, &$responses]) {\n                self::perform($multi, $responses);\n\n                foreach ($responses as $j => $response) {\n                    $timeoutMax = $timeout ?? max($timeoutMax, $response->timeout);\n                    $timeoutMin = min($timeoutMin, $response->timeout, 1);\n                    $chunk = false;\n\n                    if (isset($multi->handlesActivity[$j])) {\n                        $multi->lastTimeout = null;\n                        $elapsedTimeout = 0;\n                    } elseif (!isset($multi->openHandles[$j])) {\n                        $hasActivity = true;\n                        unset($responses[$j]);\n                        continue;\n                    } elseif ($elapsedTimeout >= $timeoutMax) {\n                        $multi->handlesActivity[$j] = [new ErrorChunk($response->offset, \\sprintf('Idle timeout reached for \"%s\".', $response->getInfo('url')))];\n                        $multi->lastTimeout ??= $lastActivity;\n                        $elapsedTimeout = $timeoutMax;\n                    } else {\n                        continue;\n                    }\n\n                    $lastActivity = null;\n                    $hasActivity = true;\n\n                    while ($multi->handlesActivity[$j] ?? false) {\n                        if (\\is_string($chunk = array_shift($multi->handlesActivity[$j]))) {\n                            if (null !== $response->inflate && false === $chunk = @inflate_add($response->inflate, $chunk)) {\n                                $multi->handlesActivity[$j] = [null, new TransportException(\\sprintf('Error while processing content unencoding for \"%s\".', $response->getInfo('url')))];\n                                continue;\n                            }\n\n                            if ('' !== $chunk && null !== $response->content && \\strlen($chunk) !== fwrite($response->content, $chunk)) {\n                                $multi->handlesActivity[$j] = [null, new TransportException(\\sprintf('Failed writing %d bytes to the response buffer.', \\strlen($chunk)))];\n                                continue;\n                            }\n\n                            $chunkLen = \\strlen($chunk);\n                            $chunk = new DataChunk($response->offset, $chunk);\n                            $response->offset += $chunkLen;\n                        } elseif (null === $chunk) {\n                            $e = $multi->handlesActivity[$j][0];\n                            unset($responses[$j], $multi->handlesActivity[$j]);\n                            $response->close();\n\n                            if (null !== $e) {\n                                $response->info['error'] = $e->getMessage();\n\n                                if ($e instanceof \\Error) {\n                                    throw $e;\n                                }\n\n                                $chunk = new ErrorChunk($response->offset, $e);\n                            } else {\n                                if (0 === $response->offset && null === $response->content) {\n                                    $response->content = fopen('php://memory', 'w+');\n                                }\n\n                                $chunk = new LastChunk($response->offset);\n                            }\n                        } elseif ($chunk instanceof ErrorChunk) {\n                            unset($responses[$j]);\n                        } elseif ($chunk instanceof FirstChunk) {\n                            if ($response->logger) {\n                                $info = $response->getInfo();\n                                $response->logger->info(\\sprintf('Response: \"%s %s\"', $info['http_code'], $info['url']));\n                            }\n\n                            $response->inflate = \\extension_loaded('zlib') && $response->inflate && 'gzip' === ($response->headers['content-encoding'][0] ?? null) ? inflate_init(\\ZLIB_ENCODING_GZIP) : null;\n\n                            if ($response->shouldBuffer instanceof \\Closure) {\n                                try {\n                                    $response->shouldBuffer = ($response->shouldBuffer)($response->headers);\n\n                                    if (null !== $response->info['error']) {\n                                        throw new TransportException($response->info['error']);\n                                    }\n                                } catch (\\Throwable $e) {\n                                    $response->close();\n                                    $multi->handlesActivity[$j] = [null, $e];\n                                }\n                            }\n\n                            if (true === $response->shouldBuffer) {\n                                $response->content = fopen('php://temp', 'w+');\n                            } elseif (\\is_resource($response->shouldBuffer)) {\n                                $response->content = $response->shouldBuffer;\n                            }\n                            $response->shouldBuffer = null;\n\n                            yield $response => $chunk;\n\n                            if ($response->initializer && null === $response->info['error']) {\n                                // Ensure the HTTP status code is always checked\n                                $response->getHeaders(true);\n                            }\n\n                            continue;\n                        }\n\n                        yield $response => $chunk;\n                    }\n\n                    unset($multi->handlesActivity[$j]);\n\n                    if ($chunk instanceof ErrorChunk && !$chunk->didThrow()) {\n                        // Ensure transport exceptions are always thrown\n                        $chunk->getContent();\n                        throw new \\LogicException('A transport exception should have been thrown.');\n                    }\n                }\n\n                if (!$responses) {\n                    $hasActivity = true;\n                    unset($runningResponses[$i]);\n                }\n\n                // Prevent memory leaks\n                $multi->handlesActivity = $multi->handlesActivity ?: [];\n                $multi->openHandles = $multi->openHandles ?: [];\n            }\n\n            if (!$runningResponses) {\n                break;\n            }\n\n            if ($hasActivity) {\n                $lastActivity ??= hrtime(true) / 1E9;\n                continue;\n            }\n\n            if (-1 === self::select($multi, min($timeoutMin, $timeoutMax - $elapsedTimeout))) {\n                usleep((int) min(500, 1E6 * $timeoutMin));\n            }\n\n            $elapsedTimeout = hrtime(true) / 1E9 - $lastActivity;\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/Retry/GenericRetryStrategy.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient\\Retry;\n\nuse Symfony\\Component\\HttpClient\\Exception\\InvalidArgumentException;\nuse Symfony\\Component\\HttpClient\\Response\\AsyncContext;\nuse Symfony\\Contracts\\HttpClient\\Exception\\TransportExceptionInterface;\n\n/**\n * Decides to retry the request when HTTP status codes belong to the given list of codes.\n *\n * @author Jérémy Derussé <jeremy@derusse.com>\n */\nclass GenericRetryStrategy implements RetryStrategyInterface\n{\n    public const IDEMPOTENT_METHODS = ['GET', 'HEAD', 'PUT', 'DELETE', 'OPTIONS', 'TRACE'];\n    public const DEFAULT_RETRY_STATUS_CODES = [\n        0 => self::IDEMPOTENT_METHODS, // for transport exceptions\n        423,\n        425,\n        429,\n        500 => self::IDEMPOTENT_METHODS,\n        502,\n        503,\n        504 => self::IDEMPOTENT_METHODS,\n        507 => self::IDEMPOTENT_METHODS,\n        510 => self::IDEMPOTENT_METHODS,\n    ];\n\n    private array $statusCodes;\n    private int $delayMs;\n    private float $multiplier;\n    private int $maxDelayMs;\n    private float $jitter;\n\n    /**\n     * @param array $statusCodes List of HTTP status codes that trigger a retry\n     * @param int   $delayMs     Amount of time to delay (or the initial value when multiplier is used)\n     * @param float $multiplier  Multiplier to apply to the delay each time a retry occurs\n     * @param int   $maxDelayMs  Maximum delay to allow (0 means no maximum)\n     * @param float $jitter      Probability of randomness int delay (0 = none, 1 = 100% random)\n     */\n    public function __construct(array $statusCodes = self::DEFAULT_RETRY_STATUS_CODES, int $delayMs = 1000, float $multiplier = 2.0, int $maxDelayMs = 0, float $jitter = 0.1)\n    {\n        $this->statusCodes = $statusCodes;\n\n        if ($delayMs < 0) {\n            throw new InvalidArgumentException(\\sprintf('Delay must be greater than or equal to zero: \"%s\" given.', $delayMs));\n        }\n        $this->delayMs = $delayMs;\n\n        if ($multiplier < 1) {\n            throw new InvalidArgumentException(\\sprintf('Multiplier must be greater than or equal to one: \"%s\" given.', $multiplier));\n        }\n        $this->multiplier = $multiplier;\n\n        if ($maxDelayMs < 0) {\n            throw new InvalidArgumentException(\\sprintf('Max delay must be greater than or equal to zero: \"%s\" given.', $maxDelayMs));\n        }\n        $this->maxDelayMs = $maxDelayMs;\n\n        if ($jitter < 0 || $jitter > 1) {\n            throw new InvalidArgumentException(\\sprintf('Jitter must be between 0 and 1: \"%s\" given.', $jitter));\n        }\n        $this->jitter = $jitter;\n    }\n\n    public function shouldRetry(AsyncContext $context, ?string $responseContent, ?TransportExceptionInterface $exception): ?bool\n    {\n        $statusCode = $context->getStatusCode();\n        if (\\in_array($statusCode, $this->statusCodes, true)) {\n            return true;\n        }\n        if (isset($this->statusCodes[$statusCode]) && \\is_array($this->statusCodes[$statusCode])) {\n            return \\in_array($context->getInfo('http_method'), $this->statusCodes[$statusCode], true);\n        }\n        if (null === $exception) {\n            return false;\n        }\n\n        if (\\in_array(0, $this->statusCodes, true)) {\n            return true;\n        }\n        if (isset($this->statusCodes[0]) && \\is_array($this->statusCodes[0])) {\n            return \\in_array($context->getInfo('http_method'), $this->statusCodes[0], true);\n        }\n\n        return false;\n    }\n\n    public function getDelay(AsyncContext $context, ?string $responseContent, ?TransportExceptionInterface $exception): int\n    {\n        $delay = $this->delayMs * $this->multiplier ** $context->getInfo('retry_count');\n\n        if ($this->jitter > 0) {\n            $randomness = (int) ($delay * $this->jitter);\n            $delay += random_int(-$randomness, +$randomness);\n        }\n\n        if ($delay > $this->maxDelayMs && 0 !== $this->maxDelayMs) {\n            return $this->maxDelayMs;\n        }\n\n        return (int) $delay;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/Retry/RetryStrategyInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient\\Retry;\n\nuse Symfony\\Component\\HttpClient\\Response\\AsyncContext;\nuse Symfony\\Contracts\\HttpClient\\Exception\\TransportExceptionInterface;\n\n/**\n * @author Jérémy Derussé <jeremy@derusse.com>\n * @author Nicolas Grekas <p@tchwork.com>\n */\ninterface RetryStrategyInterface\n{\n    /**\n     * Returns whether the request should be retried.\n     *\n     * @param ?string $responseContent Null is passed when the body did not arrive yet\n     *\n     * @return bool|null Returns null to signal that the body is required to take a decision\n     */\n    public function shouldRetry(AsyncContext $context, ?string $responseContent, ?TransportExceptionInterface $exception): ?bool;\n\n    /**\n     * Returns the time to wait in milliseconds.\n     */\n    public function getDelay(AsyncContext $context, ?string $responseContent, ?TransportExceptionInterface $exception): int;\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/RetryableHttpClient.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient;\n\nuse Psr\\Log\\LoggerInterface;\nuse Symfony\\Component\\HttpClient\\Response\\AsyncContext;\nuse Symfony\\Component\\HttpClient\\Response\\AsyncResponse;\nuse Symfony\\Component\\HttpClient\\Retry\\GenericRetryStrategy;\nuse Symfony\\Component\\HttpClient\\Retry\\RetryStrategyInterface;\nuse Symfony\\Contracts\\HttpClient\\ChunkInterface;\nuse Symfony\\Contracts\\HttpClient\\Exception\\TransportExceptionInterface;\nuse Symfony\\Contracts\\HttpClient\\HttpClientInterface;\nuse Symfony\\Contracts\\HttpClient\\ResponseInterface;\nuse Symfony\\Contracts\\Service\\ResetInterface;\n\n/**\n * Automatically retries failing HTTP requests.\n *\n * @author Jérémy Derussé <jeremy@derusse.com>\n */\nclass RetryableHttpClient implements HttpClientInterface, ResetInterface\n{\n    use AsyncDecoratorTrait;\n\n    private RetryStrategyInterface $strategy;\n    private int $maxRetries;\n    private ?LoggerInterface $logger;\n    private array $baseUris = [];\n\n    /**\n     * @param int $maxRetries The maximum number of times to retry\n     */\n    public function __construct(HttpClientInterface $client, ?RetryStrategyInterface $strategy = null, int $maxRetries = 3, ?LoggerInterface $logger = null)\n    {\n        $this->client = $client;\n        $this->strategy = $strategy ?? new GenericRetryStrategy();\n        $this->maxRetries = $maxRetries;\n        $this->logger = $logger;\n    }\n\n    public function withOptions(array $options): static\n    {\n        if (\\array_key_exists('base_uri', $options)) {\n            if (\\is_array($options['base_uri'])) {\n                $this->baseUris = $options['base_uri'];\n                unset($options['base_uri']);\n            } else {\n                $this->baseUris = [];\n            }\n        }\n\n        $clone = clone $this;\n        $clone->maxRetries = (int) ($options['max_retries'] ?? $this->maxRetries);\n        unset($options['max_retries']);\n\n        $clone->client = $this->client->withOptions($options);\n\n        return $clone;\n    }\n\n    public function request(string $method, string $url, array $options = []): ResponseInterface\n    {\n        $baseUris = \\array_key_exists('base_uri', $options) ? $options['base_uri'] : $this->baseUris;\n        $baseUris = \\is_array($baseUris) ? $baseUris : [];\n        $options = self::shiftBaseUri($options, $baseUris);\n\n        $maxRetries = (int) ($options['max_retries'] ?? $this->maxRetries);\n        unset($options['max_retries']);\n\n        if ($maxRetries <= 0) {\n            return new AsyncResponse($this->client, $method, $url, $options);\n        }\n\n        return new AsyncResponse($this->client, $method, $url, $options, function (ChunkInterface $chunk, AsyncContext $context) use ($method, $url, $options, $maxRetries, &$baseUris) {\n            static $retryCount = 0;\n            static $content = '';\n            static $firstChunk;\n\n            $exception = null;\n            try {\n                if ($context->getInfo('canceled') || $chunk->isTimeout() || null !== $chunk->getInformationalStatus()) {\n                    yield $chunk;\n\n                    return;\n                }\n            } catch (TransportExceptionInterface $exception) {\n                // catch TransportExceptionInterface to send it to the strategy\n            }\n            if (null !== $exception) {\n                // always retry request that fail to resolve DNS\n                if ('' !== $context->getInfo('primary_ip')) {\n                    $shouldRetry = $this->strategy->shouldRetry($context, null, $exception);\n                    if (null === $shouldRetry) {\n                        throw new \\LogicException(\\sprintf('The \"%s::shouldRetry()\" method must not return null when called with an exception.', $this->strategy::class));\n                    }\n\n                    if (false === $shouldRetry) {\n                        yield from $this->passthru($context, $firstChunk, $content, $chunk);\n\n                        return;\n                    }\n                }\n            } elseif ($chunk->isFirst()) {\n                if (false === $shouldRetry = $this->strategy->shouldRetry($context, null, null)) {\n                    yield from $this->passthru($context, $firstChunk, $content, $chunk);\n\n                    return;\n                }\n\n                // Body is needed to decide\n                if (null === $shouldRetry) {\n                    $firstChunk = $chunk;\n                    $content = '';\n\n                    return;\n                }\n            } else {\n                if (!$chunk->isLast()) {\n                    $content .= $chunk->getContent();\n\n                    return;\n                }\n\n                if (null === $shouldRetry = $this->strategy->shouldRetry($context, $content, null)) {\n                    throw new \\LogicException(\\sprintf('The \"%s::shouldRetry()\" method must not return null when called with a body.', $this->strategy::class));\n                }\n\n                if (false === $shouldRetry) {\n                    yield from $this->passthru($context, $firstChunk, $content, $chunk);\n\n                    return;\n                }\n            }\n\n            $context->getResponse()->cancel();\n\n            $delay = $this->getDelayFromHeader($context->getHeaders()) ?? $this->strategy->getDelay($context, !$exception && $chunk->isLast() ? $content : null, $exception);\n            ++$retryCount;\n            $content = '';\n            $firstChunk = null;\n\n            $this->logger?->info('Try #{count} after {delay}ms'.($exception ? ': '.$exception->getMessage() : ', status code: '.$context->getStatusCode()), [\n                'count' => $retryCount,\n                'delay' => $delay,\n            ]);\n\n            $context->setInfo('retry_count', $retryCount);\n            $context->replaceRequest($method, $url, self::shiftBaseUri($options, $baseUris));\n            $context->pause($delay / 1000);\n\n            if ($retryCount >= $maxRetries) {\n                $context->passthru();\n            }\n        });\n    }\n\n    private function getDelayFromHeader(array $headers): ?int\n    {\n        if (null !== $after = $headers['retry-after'][0] ?? null) {\n            if (is_numeric($after)) {\n                return (int) ($after * 1000);\n            }\n\n            if (false !== $time = strtotime($after)) {\n                return max(0, $time - time()) * 1000;\n            }\n        }\n\n        return null;\n    }\n\n    private function passthru(AsyncContext $context, ?ChunkInterface $firstChunk, string &$content, ChunkInterface $lastChunk): \\Generator\n    {\n        $context->passthru();\n\n        if (null !== $firstChunk) {\n            yield $firstChunk;\n        }\n\n        if ('' !== $content) {\n            $chunk = $context->createChunk($content);\n            $content = '';\n\n            yield $chunk;\n        }\n\n        yield $lastChunk;\n    }\n\n    private static function shiftBaseUri(array $options, array &$baseUris): array\n    {\n        if ($baseUris) {\n            $baseUri = 1 < \\count($baseUris) ? array_shift($baseUris) : current($baseUris);\n            $options['base_uri'] = \\is_array($baseUri) ? $baseUri[array_rand($baseUri)] : $baseUri;\n        }\n\n        return $options;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/ScopingHttpClient.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient;\n\nuse Psr\\Log\\LoggerAwareInterface;\nuse Psr\\Log\\LoggerInterface;\nuse Symfony\\Component\\HttpClient\\Exception\\InvalidArgumentException;\nuse Symfony\\Contracts\\HttpClient\\HttpClientInterface;\nuse Symfony\\Contracts\\HttpClient\\ResponseInterface;\nuse Symfony\\Contracts\\HttpClient\\ResponseStreamInterface;\nuse Symfony\\Contracts\\Service\\ResetInterface;\n\n/**\n * Auto-configure the default options based on the requested URL.\n *\n * @author Anthony Martin <anthony.martin@sensiolabs.com>\n */\nclass ScopingHttpClient implements HttpClientInterface, ResetInterface, LoggerAwareInterface\n{\n    use HttpClientTrait;\n\n    private HttpClientInterface $client;\n    private array $defaultOptionsByRegexp;\n    private ?string $defaultRegexp;\n\n    public function __construct(HttpClientInterface $client, array $defaultOptionsByRegexp, ?string $defaultRegexp = null)\n    {\n        $this->client = $client;\n        $this->defaultOptionsByRegexp = $defaultOptionsByRegexp;\n        $this->defaultRegexp = $defaultRegexp;\n\n        if (null !== $defaultRegexp && !isset($defaultOptionsByRegexp[$defaultRegexp])) {\n            throw new InvalidArgumentException(\\sprintf('No options are mapped to the provided \"%s\" default regexp.', $defaultRegexp));\n        }\n    }\n\n    public static function forBaseUri(HttpClientInterface $client, string $baseUri, array $defaultOptions = [], ?string $regexp = null): self\n    {\n        $regexp ??= preg_quote(implode('', self::resolveUrl(self::parseUrl('.'), self::parseUrl($baseUri))));\n\n        $defaultOptions['base_uri'] = $baseUri;\n\n        return new self($client, [$regexp => $defaultOptions], $regexp);\n    }\n\n    public function request(string $method, string $url, array $options = []): ResponseInterface\n    {\n        $e = null;\n        $url = self::parseUrl($url, $options['query'] ?? []);\n\n        if (\\is_string($options['base_uri'] ?? null)) {\n            $options['base_uri'] = self::parseUrl($options['base_uri']);\n        }\n\n        try {\n            $url = implode('', self::resolveUrl($url, $options['base_uri'] ?? null));\n        } catch (InvalidArgumentException $e) {\n            if (null === $this->defaultRegexp) {\n                throw $e;\n            }\n\n            $defaultOptions = $this->defaultOptionsByRegexp[$this->defaultRegexp];\n            $options = self::mergeDefaultOptions($options, $defaultOptions, true);\n            if (\\is_string($options['base_uri'] ?? null)) {\n                $options['base_uri'] = self::parseUrl($options['base_uri']);\n            }\n            $url = implode('', self::resolveUrl($url, $options['base_uri'] ?? null, $defaultOptions['query'] ?? []));\n        }\n\n        foreach ($this->defaultOptionsByRegexp as $regexp => $defaultOptions) {\n            if (preg_match(\"{{$regexp}}A\", $url)) {\n                if (null === $e || $regexp !== $this->defaultRegexp) {\n                    $options = self::mergeDefaultOptions($options, $defaultOptions, true);\n                }\n                break;\n            }\n        }\n\n        return $this->client->request($method, $url, $options);\n    }\n\n    public function stream(ResponseInterface|iterable $responses, ?float $timeout = null): ResponseStreamInterface\n    {\n        return $this->client->stream($responses, $timeout);\n    }\n\n    /**\n     * @return void\n     */\n    public function reset()\n    {\n        if ($this->client instanceof ResetInterface) {\n            $this->client->reset();\n        }\n    }\n\n    public function setLogger(LoggerInterface $logger): void\n    {\n        if ($this->client instanceof LoggerAwareInterface) {\n            $this->client->setLogger($logger);\n        }\n    }\n\n    public function withOptions(array $options): static\n    {\n        $clone = clone $this;\n        $clone->client = $this->client->withOptions($options);\n\n        return $clone;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/Test/HarFileResponseFactory.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient\\Test;\n\nuse Symfony\\Component\\HttpClient\\Exception\\TransportException;\nuse Symfony\\Component\\HttpClient\\Response\\MockResponse;\nuse Symfony\\Contracts\\HttpClient\\ResponseInterface;\n\n/**\n * See: https://w3c.github.io/web-performance/specs/HAR/Overview.html.\n *\n * @author Gary PEGEOT <garypegeot@gmail.com>\n */\nclass HarFileResponseFactory\n{\n    public function __construct(private string $archiveFile)\n    {\n    }\n\n    public function setArchiveFile(string $archiveFile): void\n    {\n        $this->archiveFile = $archiveFile;\n    }\n\n    public function __invoke(string $method, string $url, array $options): ResponseInterface\n    {\n        if (!is_file($this->archiveFile)) {\n            throw new \\InvalidArgumentException(\\sprintf('Invalid file path provided: \"%s\".', $this->archiveFile));\n        }\n\n        $json = json_decode(json: file_get_contents($this->archiveFile), associative: true, flags: \\JSON_THROW_ON_ERROR);\n\n        foreach ($json['log']['entries'] as $entry) {\n            /**\n             * @var array{status: int, headers: array, content: array}  $response\n             * @var array{method: string, url: string, postData: array} $request\n             */\n            ['response' => $response, 'request' => $request, 'startedDateTime' => $startedDateTime] = $entry;\n\n            $body = $this->getContent($response['content']);\n            $entryMethod = $request['method'];\n            $entryUrl = $request['url'];\n            $requestBody = $options['body'] ?? null;\n\n            if ($method !== $entryMethod || $url !== $entryUrl) {\n                continue;\n            }\n\n            if (null !== $requestBody && $requestBody !== $this->getContent($request['postData'] ?? [])) {\n                continue;\n            }\n\n            $info = [\n                'http_code' => $response['status'],\n                'http_method' => $entryMethod,\n                'response_headers' => [],\n                'start_time' => strtotime($startedDateTime),\n                'url' => $entryUrl,\n            ];\n\n            /** @var array{name: string, value: string} $header */\n            foreach ($response['headers'] as $header) {\n                ['name' => $name, 'value' => $value] = $header;\n\n                $info['response_headers'][$name][] = $value;\n            }\n\n            return new MockResponse($body, $info);\n        }\n\n        throw new TransportException(\\sprintf('File \"%s\" does not contain a response for HTTP request \"%s\" \"%s\".', $this->archiveFile, $method, $url));\n    }\n\n    /**\n     * @param array{text: string, encoding: string} $content\n     */\n    private function getContent(array $content): string\n    {\n        $text = $content['text'] ?? '';\n        $encoding = $content['encoding'] ?? null;\n\n        return match ($encoding) {\n            'base64' => base64_decode($text),\n            null => $text,\n            default => throw new \\InvalidArgumentException(\\sprintf('Unsupported encoding \"%s\", currently only base64 is supported.', $encoding)),\n        };\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/TraceableHttpClient.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient;\n\nuse Psr\\Log\\LoggerAwareInterface;\nuse Psr\\Log\\LoggerInterface;\nuse Symfony\\Component\\HttpClient\\Response\\ResponseStream;\nuse Symfony\\Component\\HttpClient\\Response\\TraceableResponse;\nuse Symfony\\Component\\Stopwatch\\Stopwatch;\nuse Symfony\\Contracts\\HttpClient\\HttpClientInterface;\nuse Symfony\\Contracts\\HttpClient\\ResponseInterface;\nuse Symfony\\Contracts\\HttpClient\\ResponseStreamInterface;\nuse Symfony\\Contracts\\Service\\ResetInterface;\n\n/**\n * @author Jérémy Romey <jeremy@free-agent.fr>\n */\nfinal class TraceableHttpClient implements HttpClientInterface, ResetInterface, LoggerAwareInterface\n{\n    private HttpClientInterface $client;\n    private ?Stopwatch $stopwatch;\n    private \\ArrayObject $tracedRequests;\n\n    public function __construct(HttpClientInterface $client, ?Stopwatch $stopwatch = null)\n    {\n        $this->client = $client;\n        $this->stopwatch = $stopwatch;\n        $this->tracedRequests = new \\ArrayObject();\n    }\n\n    public function request(string $method, string $url, array $options = []): ResponseInterface\n    {\n        $content = null;\n        $traceInfo = [];\n        $this->tracedRequests[] = [\n            'method' => $method,\n            'url' => $url,\n            'options' => $options,\n            'info' => &$traceInfo,\n            'content' => &$content,\n        ];\n        $onProgress = $options['on_progress'] ?? null;\n\n        if (false === ($options['extra']['trace_content'] ?? true)) {\n            unset($content);\n            $content = false;\n        }\n\n        $options['on_progress'] = function (int $dlNow, int $dlSize, array $info) use (&$traceInfo, $onProgress) {\n            $traceInfo = $info;\n\n            if (null !== $onProgress) {\n                $onProgress($dlNow, $dlSize, $info);\n            }\n        };\n\n        return new TraceableResponse($this->client, $this->client->request($method, $url, $options), $content, $this->stopwatch?->start(\"$method $url\", 'http_client'));\n    }\n\n    public function stream(ResponseInterface|iterable $responses, ?float $timeout = null): ResponseStreamInterface\n    {\n        if ($responses instanceof TraceableResponse) {\n            $responses = [$responses];\n        }\n\n        return new ResponseStream(TraceableResponse::stream($this->client, $responses, $timeout));\n    }\n\n    public function getTracedRequests(): array\n    {\n        return $this->tracedRequests->getArrayCopy();\n    }\n\n    public function reset(): void\n    {\n        if ($this->client instanceof ResetInterface) {\n            $this->client->reset();\n        }\n\n        $this->tracedRequests->exchangeArray([]);\n    }\n\n    public function setLogger(LoggerInterface $logger): void\n    {\n        if ($this->client instanceof LoggerAwareInterface) {\n            $this->client->setLogger($logger);\n        }\n    }\n\n    public function withOptions(array $options): static\n    {\n        $clone = clone $this;\n        $clone->client = $this->client->withOptions($options);\n\n        return $clone;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/UriTemplateHttpClient.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\HttpClient;\n\nuse Symfony\\Contracts\\HttpClient\\HttpClientInterface;\nuse Symfony\\Contracts\\HttpClient\\ResponseInterface;\nuse Symfony\\Contracts\\Service\\ResetInterface;\n\nclass UriTemplateHttpClient implements HttpClientInterface, ResetInterface\n{\n    use DecoratorTrait;\n\n    /**\n     * @param (\\Closure(string $url, array $vars): string)|null $expander\n     */\n    public function __construct(?HttpClientInterface $client = null, private ?\\Closure $expander = null, private array $defaultVars = [])\n    {\n        $this->client = $client ?? HttpClient::create();\n    }\n\n    public function request(string $method, string $url, array $options = []): ResponseInterface\n    {\n        $vars = $this->defaultVars;\n\n        if (\\array_key_exists('vars', $options)) {\n            if (!\\is_array($options['vars'])) {\n                throw new \\InvalidArgumentException('The \"vars\" option must be an array.');\n            }\n\n            $vars = [...$vars, ...$options['vars']];\n            unset($options['vars']);\n        }\n\n        if ($vars) {\n            $url = ($this->expander ??= $this->createExpanderFromPopularVendors())($url, $vars);\n        }\n\n        return $this->client->request($method, $url, $options);\n    }\n\n    public function withOptions(array $options): static\n    {\n        if (!\\is_array($options['vars'] ?? [])) {\n            throw new \\InvalidArgumentException('The \"vars\" option must be an array.');\n        }\n\n        $clone = clone $this;\n        $clone->defaultVars = [...$clone->defaultVars, ...$options['vars'] ?? []];\n        unset($options['vars']);\n\n        $clone->client = $this->client->withOptions($options);\n\n        return $clone;\n    }\n\n    /**\n     * @return \\Closure(string $url, array $vars): string\n     */\n    private function createExpanderFromPopularVendors(): \\Closure\n    {\n        if (class_exists(\\GuzzleHttp\\UriTemplate\\UriTemplate::class)) {\n            return \\GuzzleHttp\\UriTemplate\\UriTemplate::expand(...);\n        }\n\n        if (class_exists(\\League\\Uri\\UriTemplate::class)) {\n            return static fn (string $url, array $vars): string => (new \\League\\Uri\\UriTemplate($url))->expand($vars);\n        }\n\n        if (class_exists(\\Rize\\UriTemplate::class)) {\n            return (new \\Rize\\UriTemplate())->expand(...);\n        }\n\n        throw new \\LogicException('Support for URI template requires a vendor to expand the URI. Run \"composer require guzzlehttp/uri-template\" or pass your own expander \\Closure implementation.');\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client/composer.json",
    "content": "{\n    \"name\": \"symfony/http-client\",\n    \"type\": \"library\",\n    \"description\": \"Provides powerful methods to fetch HTTP resources synchronously or asynchronously\",\n    \"keywords\": [\"http\"],\n    \"homepage\": \"https://symfony.com\",\n    \"license\": \"MIT\",\n    \"authors\": [\n        {\n            \"name\": \"Nicolas Grekas\",\n            \"email\": \"p@tchwork.com\"\n        },\n        {\n            \"name\": \"Symfony Community\",\n            \"homepage\": \"https://symfony.com/contributors\"\n        }\n    ],\n    \"provide\": {\n        \"php-http/async-client-implementation\": \"*\",\n        \"php-http/client-implementation\": \"*\",\n        \"psr/http-client-implementation\": \"1.0\",\n        \"symfony/http-client-implementation\": \"3.0\"\n    },\n    \"require\": {\n        \"php\": \">=8.1\",\n        \"psr/log\": \"^1|^2|^3\",\n        \"symfony/deprecation-contracts\": \"^2.5|^3\",\n        \"symfony/http-client-contracts\": \"~3.4.4|^3.5.2\",\n        \"symfony/polyfill-php83\": \"^1.29\",\n        \"symfony/service-contracts\": \"^2.5|^3\"\n    },\n    \"require-dev\": {\n        \"amphp/amp\": \"^2.5\",\n        \"amphp/http-client\": \"^4.2.1\",\n        \"amphp/http-tunnel\": \"^1.0\",\n        \"amphp/socket\": \"^1.1\",\n        \"guzzlehttp/promises\": \"^1.4|^2.0\",\n        \"nyholm/psr7\": \"^1.0\",\n        \"php-http/httplug\": \"^1.0|^2.0\",\n        \"psr/http-client\": \"^1.0\",\n        \"symfony/dependency-injection\": \"^5.4|^6.0|^7.0\",\n        \"symfony/http-kernel\": \"^5.4|^6.0|^7.0\",\n        \"symfony/messenger\": \"^5.4|^6.0|^7.0\",\n        \"symfony/process\": \"^5.4|^6.0|^7.0\",\n        \"symfony/stopwatch\": \"^5.4|^6.0|^7.0\"\n    },\n    \"conflict\": {\n        \"php-http/discovery\": \"<1.15\",\n        \"symfony/http-foundation\": \"<6.3\"\n    },\n    \"autoload\": {\n        \"psr-4\": { \"Symfony\\\\Component\\\\HttpClient\\\\\": \"\" },\n        \"exclude-from-classmap\": [\n            \"/Tests/\"\n        ]\n    },\n    \"minimum-stability\": \"dev\"\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client-contracts/CHANGELOG.md",
    "content": "CHANGELOG\n=========\n\nThe changelog is maintained for all Symfony contracts at the following URL:\nhttps://github.com/symfony/contracts/blob/main/CHANGELOG.md\n"
  },
  {
    "path": "server/vendor/symfony/http-client-contracts/ChunkInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Contracts\\HttpClient;\n\nuse Symfony\\Contracts\\HttpClient\\Exception\\TransportExceptionInterface;\n\n/**\n * The interface of chunks returned by ResponseStreamInterface::current().\n *\n * When the chunk is first, last or timeout, the content MUST be empty.\n * When an unchecked timeout or a network error occurs, a TransportExceptionInterface\n * MUST be thrown by the destructor unless one was already thrown by another method.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n */\ninterface ChunkInterface\n{\n    /**\n     * Tells when the idle timeout has been reached.\n     *\n     * @throws TransportExceptionInterface on a network error\n     */\n    public function isTimeout(): bool;\n\n    /**\n     * Tells when headers just arrived.\n     *\n     * @throws TransportExceptionInterface on a network error or when the idle timeout is reached\n     */\n    public function isFirst(): bool;\n\n    /**\n     * Tells when the body just completed.\n     *\n     * @throws TransportExceptionInterface on a network error or when the idle timeout is reached\n     */\n    public function isLast(): bool;\n\n    /**\n     * Returns a [status code, headers] tuple when a 1xx status code was just received.\n     *\n     * @throws TransportExceptionInterface on a network error or when the idle timeout is reached\n     */\n    public function getInformationalStatus(): ?array;\n\n    /**\n     * Returns the content of the response chunk.\n     *\n     * @throws TransportExceptionInterface on a network error or when the idle timeout is reached\n     */\n    public function getContent(): string;\n\n    /**\n     * Returns the offset of the chunk in the response body.\n     */\n    public function getOffset(): int;\n\n    /**\n     * In case of error, returns the message that describes it.\n     */\n    public function getError(): ?string;\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client-contracts/Exception/ClientExceptionInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Contracts\\HttpClient\\Exception;\n\n/**\n * When a 4xx response is returned.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n */\ninterface ClientExceptionInterface extends HttpExceptionInterface\n{\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client-contracts/Exception/DecodingExceptionInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Contracts\\HttpClient\\Exception;\n\n/**\n * When a content-type cannot be decoded to the expected representation.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n */\ninterface DecodingExceptionInterface extends ExceptionInterface\n{\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client-contracts/Exception/ExceptionInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Contracts\\HttpClient\\Exception;\n\n/**\n * The base interface for all exceptions in the contract.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n */\ninterface ExceptionInterface extends \\Throwable\n{\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client-contracts/Exception/HttpExceptionInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Contracts\\HttpClient\\Exception;\n\nuse Symfony\\Contracts\\HttpClient\\ResponseInterface;\n\n/**\n * Base interface for HTTP-related exceptions.\n *\n * @author Anton Chernikov <anton_ch1989@mail.ru>\n */\ninterface HttpExceptionInterface extends ExceptionInterface\n{\n    public function getResponse(): ResponseInterface;\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client-contracts/Exception/RedirectionExceptionInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Contracts\\HttpClient\\Exception;\n\n/**\n * When a 3xx response is returned and the \"max_redirects\" option has been reached.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n */\ninterface RedirectionExceptionInterface extends HttpExceptionInterface\n{\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client-contracts/Exception/ServerExceptionInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Contracts\\HttpClient\\Exception;\n\n/**\n * When a 5xx response is returned.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n */\ninterface ServerExceptionInterface extends HttpExceptionInterface\n{\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client-contracts/Exception/TimeoutExceptionInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Contracts\\HttpClient\\Exception;\n\n/**\n * When an idle timeout occurs.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n */\ninterface TimeoutExceptionInterface extends TransportExceptionInterface\n{\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client-contracts/Exception/TransportExceptionInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Contracts\\HttpClient\\Exception;\n\n/**\n * When any error happens at the transport level.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n */\ninterface TransportExceptionInterface extends ExceptionInterface\n{\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client-contracts/HttpClientInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Contracts\\HttpClient;\n\nuse Symfony\\Contracts\\HttpClient\\Exception\\TransportExceptionInterface;\nuse Symfony\\Contracts\\HttpClient\\Test\\HttpClientTestCase;\n\n/**\n * Provides flexible methods for requesting HTTP resources synchronously or asynchronously.\n *\n * @see HttpClientTestCase for a reference test suite\n *\n * @author Nicolas Grekas <p@tchwork.com>\n */\ninterface HttpClientInterface\n{\n    public const OPTIONS_DEFAULTS = [\n        'auth_basic' => null,   // array|string - an array containing the username as first value, and optionally the\n                                //   password as the second one; or string like username:password - enabling HTTP Basic\n                                //   authentication (RFC 7617)\n        'auth_bearer' => null,  // string - a token enabling HTTP Bearer authorization (RFC 6750)\n        'query' => [],          // string[] - associative array of query string values to merge with the request's URL\n        'headers' => [],        // iterable|string[]|string[][] - headers names provided as keys or as part of values\n        'body' => '',           // array|string|resource|\\Traversable|\\Closure - the callback SHOULD yield a string\n                                //   smaller than the amount requested as argument; the empty string signals EOF; if\n                                //   an array is passed, it is meant as a form payload of field names and values\n        'json' => null,         // mixed - if set, implementations MUST set the \"body\" option to the JSON-encoded\n                                //   value and set the \"content-type\" header to a JSON-compatible value if it is not\n                                //   explicitly defined in the headers option - typically \"application/json\"\n        'user_data' => null,    // mixed - any extra data to attach to the request (scalar, callable, object...) that\n                                //   MUST be available via $response->getInfo('user_data') - not used internally\n        'max_redirects' => 20,  // int - the maximum number of redirects to follow; a value lower than or equal to 0\n                                //   means redirects should not be followed; \"Authorization\" and \"Cookie\" headers MUST\n                                //   NOT follow except for the initial host name\n        'http_version' => null, // string - defaults to the best supported version, typically 1.1 or 2.0\n        'base_uri' => null,     // string - the URI to resolve relative URLs, following rules in RFC 3986, section 2\n        'buffer' => true,       // bool|resource|\\Closure - whether the content of the response should be buffered or not,\n                                //   or a stream resource where the response body should be written,\n                                //   or a closure telling if/where the response should be buffered based on its headers\n        'on_progress' => null,  // callable(int $dlNow, int $dlSize, array $info) - throwing any exceptions MUST abort the\n                                //   request; it MUST be called on connection, on headers and on completion; it SHOULD be\n                                //   called on upload/download of data and at least 1/s\n        'resolve' => [],        // string[] - a map of host to IP address that SHOULD replace DNS resolution\n        'proxy' => null,        // string - by default, the proxy-related env vars handled by curl SHOULD be honored\n        'no_proxy' => null,     // string - a comma separated list of hosts that do not require a proxy to be reached\n        'timeout' => null,      // float - the idle timeout (in seconds) - defaults to ini_get('default_socket_timeout')\n        'max_duration' => 0,    // float - the maximum execution time (in seconds) for the request+response as a whole;\n                                //   a value lower than or equal to 0 means it is unlimited\n        'bindto' => '0',        // string - the interface or the local socket to bind to\n        'verify_peer' => true,  // see https://php.net/context.ssl for the following options\n        'verify_host' => true,\n        'cafile' => null,\n        'capath' => null,\n        'local_cert' => null,\n        'local_pk' => null,\n        'passphrase' => null,\n        'ciphers' => null,\n        'peer_fingerprint' => null,\n        'capture_peer_cert_chain' => false,\n        'crypto_method' => \\STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT, // STREAM_CRYPTO_METHOD_TLSv*_CLIENT - minimum TLS version\n        'extra' => [],          // array - additional options that can be ignored if unsupported, unlike regular options\n    ];\n\n    /**\n     * Requests an HTTP resource.\n     *\n     * Responses MUST be lazy, but their status code MUST be\n     * checked even if none of their public methods are called.\n     *\n     * Implementations are not required to support all options described above; they can also\n     * support more custom options; but in any case, they MUST throw a TransportExceptionInterface\n     * when an unsupported option is passed.\n     *\n     * @throws TransportExceptionInterface When an unsupported option is passed\n     */\n    public function request(string $method, string $url, array $options = []): ResponseInterface;\n\n    /**\n     * Yields responses chunk by chunk as they complete.\n     *\n     * @param ResponseInterface|iterable<array-key, ResponseInterface> $responses One or more responses created by the current HTTP client\n     * @param float|null                                               $timeout   The idle timeout before yielding timeout chunks\n     */\n    public function stream(ResponseInterface|iterable $responses, ?float $timeout = null): ResponseStreamInterface;\n\n    /**\n     * Returns a new instance of the client with new default options.\n     */\n    public function withOptions(array $options): static;\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client-contracts/LICENSE",
    "content": "Copyright (c) 2018-present Fabien Potencier\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is furnished\nto do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "server/vendor/symfony/http-client-contracts/README.md",
    "content": "Symfony HttpClient Contracts\n============================\n\nA set of abstractions extracted out of the Symfony components.\n\nCan be used to build on semantics that the Symfony components proved useful and\nthat already have battle tested implementations.\n\nSee https://github.com/symfony/contracts/blob/main/README.md for more information.\n"
  },
  {
    "path": "server/vendor/symfony/http-client-contracts/ResponseInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Contracts\\HttpClient;\n\nuse Symfony\\Contracts\\HttpClient\\Exception\\ClientExceptionInterface;\nuse Symfony\\Contracts\\HttpClient\\Exception\\DecodingExceptionInterface;\nuse Symfony\\Contracts\\HttpClient\\Exception\\ExceptionInterface;\nuse Symfony\\Contracts\\HttpClient\\Exception\\RedirectionExceptionInterface;\nuse Symfony\\Contracts\\HttpClient\\Exception\\ServerExceptionInterface;\nuse Symfony\\Contracts\\HttpClient\\Exception\\TransportExceptionInterface;\n\n/**\n * A (lazily retrieved) HTTP response.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n */\ninterface ResponseInterface\n{\n    /**\n     * Gets the HTTP status code of the response.\n     *\n     * @throws TransportExceptionInterface when a network error occurs\n     */\n    public function getStatusCode(): int;\n\n    /**\n     * Gets the HTTP headers of the response.\n     *\n     * @param bool $throw Whether an exception should be thrown on 3/4/5xx status codes\n     *\n     * @return string[][] The headers of the response keyed by header names in lowercase\n     *\n     * @throws TransportExceptionInterface   When a network error occurs\n     * @throws RedirectionExceptionInterface On a 3xx when $throw is true and the \"max_redirects\" option has been reached\n     * @throws ClientExceptionInterface      On a 4xx when $throw is true\n     * @throws ServerExceptionInterface      On a 5xx when $throw is true\n     */\n    public function getHeaders(bool $throw = true): array;\n\n    /**\n     * Gets the response body as a string.\n     *\n     * @param bool $throw Whether an exception should be thrown on 3/4/5xx status codes\n     *\n     * @throws TransportExceptionInterface   When a network error occurs\n     * @throws RedirectionExceptionInterface On a 3xx when $throw is true and the \"max_redirects\" option has been reached\n     * @throws ClientExceptionInterface      On a 4xx when $throw is true\n     * @throws ServerExceptionInterface      On a 5xx when $throw is true\n     */\n    public function getContent(bool $throw = true): string;\n\n    /**\n     * Gets the response body decoded as array, typically from a JSON payload.\n     *\n     * @param bool $throw Whether an exception should be thrown on 3/4/5xx status codes\n     *\n     * @throws DecodingExceptionInterface    When the body cannot be decoded to an array\n     * @throws TransportExceptionInterface   When a network error occurs\n     * @throws RedirectionExceptionInterface On a 3xx when $throw is true and the \"max_redirects\" option has been reached\n     * @throws ClientExceptionInterface      On a 4xx when $throw is true\n     * @throws ServerExceptionInterface      On a 5xx when $throw is true\n     */\n    public function toArray(bool $throw = true): array;\n\n    /**\n     * Closes the response stream and all related buffers.\n     *\n     * No further chunk will be yielded after this method has been called.\n     */\n    public function cancel(): void;\n\n    /**\n     * Returns info coming from the transport layer.\n     *\n     * This method SHOULD NOT throw any ExceptionInterface and SHOULD be non-blocking.\n     * The returned info is \"live\": it can be empty and can change from one call to\n     * another, as the request/response progresses.\n     *\n     * The following info MUST be returned:\n     *  - canceled (bool) - true if the response was canceled using ResponseInterface::cancel(), false otherwise\n     *  - error (string|null) - the error message when the transfer was aborted, null otherwise\n     *  - http_code (int) - the last response code or 0 when it is not known yet\n     *  - http_method (string) - the HTTP verb of the last request\n     *  - redirect_count (int) - the number of redirects followed while executing the request\n     *  - redirect_url (string|null) - the resolved location of redirect responses, null otherwise\n     *  - response_headers (array) - an array modelled after the special $http_response_header variable\n     *  - start_time (float) - the time when the request was sent or 0.0 when it's pending\n     *  - url (string) - the last effective URL of the request\n     *  - user_data (mixed) - the value of the \"user_data\" request option, null if not set\n     *\n     * When the \"capture_peer_cert_chain\" option is true, the \"peer_certificate_chain\"\n     * attribute SHOULD list the peer certificates as an array of OpenSSL X.509 resources.\n     *\n     * Other info SHOULD be named after curl_getinfo()'s associative return value.\n     *\n     * @return mixed An array of all available info, or one of them when $type is\n     *               provided, or null when an unsupported type is requested\n     */\n    public function getInfo(?string $type = null): mixed;\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client-contracts/ResponseStreamInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Contracts\\HttpClient;\n\n/**\n * Yields response chunks, returned by HttpClientInterface::stream().\n *\n * @author Nicolas Grekas <p@tchwork.com>\n *\n * @extends \\Iterator<ResponseInterface, ChunkInterface>\n */\ninterface ResponseStreamInterface extends \\Iterator\n{\n    public function key(): ResponseInterface;\n\n    public function current(): ChunkInterface;\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client-contracts/Test/Fixtures/web/index.php",
    "content": "<?php\n\nif ('cli-server' !== \\PHP_SAPI) {\n    // safe guard against unwanted execution\n    throw new \\Exception(\"You cannot run this script directly, it's a fixture for TestHttpServer.\");\n}\n\n$vars = [];\n\nif (!$_POST) {\n    $_POST = json_decode(file_get_contents('php://input'), true);\n    $_POST['content-type'] = $_SERVER['HTTP_CONTENT_TYPE'] ?? '?';\n}\n\n$headers = [\n    'SERVER_PROTOCOL',\n    'SERVER_NAME',\n    'REQUEST_URI',\n    'REQUEST_METHOD',\n    'PHP_AUTH_USER',\n    'PHP_AUTH_PW',\n    'REMOTE_ADDR',\n    'REMOTE_PORT',\n];\n\nforeach ($headers as $k) {\n    if (isset($_SERVER[$k])) {\n        $vars[$k] = $_SERVER[$k];\n    }\n}\n\nforeach ($_SERVER as $k => $v) {\n    if (str_starts_with($k, 'HTTP_')) {\n        $vars[$k] = $v;\n    }\n}\n\n$json = json_encode($vars, \\JSON_PRETTY_PRINT | \\JSON_UNESCAPED_SLASHES | \\JSON_UNESCAPED_UNICODE);\n\nswitch (parse_url($vars['REQUEST_URI'], \\PHP_URL_PATH)) {\n    default:\n        exit;\n\n    case '/head':\n        header('X-Request-Vars: '.json_encode($vars, \\JSON_UNESCAPED_SLASHES | \\JSON_UNESCAPED_UNICODE));\n        header('Content-Length: '.strlen($json), true);\n        break;\n\n    case '/':\n    case '/?a=a&b=b':\n    case 'http://127.0.0.1:8057/':\n    case 'http://localhost:8057/':\n        ob_start('ob_gzhandler');\n        break;\n\n    case '/103':\n        header('HTTP/1.1 103 Early Hints');\n        header('Link: </style.css>; rel=preload; as=style', false);\n        header('Link: </script.js>; rel=preload; as=script', false);\n        flush();\n        usleep(1000);\n        echo \"HTTP/1.1 200 OK\\r\\n\";\n        echo \"Date: Fri, 26 May 2017 10:02:11 GMT\\r\\n\";\n        echo \"Content-Length: 13\\r\\n\";\n        echo \"\\r\\n\";\n        echo 'Here the body';\n        exit;\n\n    case '/404':\n        header('Content-Type: application/json', true, 404);\n        break;\n\n    case '/404-gzipped':\n        header('Content-Type: text/plain', true, 404);\n        ob_start('ob_gzhandler');\n        @ob_flush();\n        flush();\n        usleep(300000);\n        echo 'some text';\n        exit;\n\n    case '/301':\n        if ('Basic Zm9vOmJhcg==' === $vars['HTTP_AUTHORIZATION']) {\n            header('Location: http://127.0.0.1:8057/302', true, 301);\n        }\n        break;\n\n    case '/301/bad-tld':\n        header('Location: http://foo.example.', true, 301);\n        break;\n\n    case '/301/invalid':\n        header('Location: //?foo=bar', true, 301);\n        break;\n\n    case '/301/proxy':\n    case 'http://localhost:8057/301/proxy':\n    case 'http://127.0.0.1:8057/301/proxy':\n        header('Location: http://localhost:8057/', true, 301);\n        break;\n\n    case '/302':\n        if (!isset($vars['HTTP_AUTHORIZATION'])) {\n            $location = $_GET['location'] ?? 'http://localhost:8057/';\n            header('Location: '.$location, true, 302);\n        }\n        break;\n\n    case '/302/relative':\n        header('Location: ..', true, 302);\n        break;\n\n    case '/304':\n        header('Content-Length: 10', true, 304);\n        echo '12345';\n\n        return;\n\n    case '/307':\n        header('Location: http://localhost:8057/post', true, 307);\n        break;\n\n    case '/length-broken':\n        header('Content-Length: 1000');\n        break;\n\n    case '/post':\n        $output = json_encode($_POST + ['REQUEST_METHOD' => $vars['REQUEST_METHOD']], \\JSON_PRETTY_PRINT | \\JSON_UNESCAPED_SLASHES | \\JSON_UNESCAPED_UNICODE);\n        header('Content-Type: application/json', true);\n        header('Content-Length: '.strlen($output));\n        echo $output;\n        exit;\n\n    case '/timeout-header':\n        usleep(300000);\n        break;\n\n    case '/timeout-body':\n        echo '<1>';\n        @ob_flush();\n        flush();\n        usleep(500000);\n        echo '<2>';\n        exit;\n\n    case '/timeout-long':\n        ignore_user_abort(false);\n        sleep(1);\n        while (true) {\n            echo '<1>';\n            @ob_flush();\n            flush();\n            usleep(500);\n        }\n        exit;\n\n    case '/chunked':\n        header('Transfer-Encoding: chunked');\n        echo \"8\\r\\nSymfony \\r\\n5\\r\\nis aw\\r\\n6\\r\\nesome!\\r\\n0\\r\\n\\r\\n\";\n        exit;\n\n    case '/chunked-broken':\n        header('Transfer-Encoding: chunked');\n        echo \"8\\r\\nSymfony \\r\\n5\\r\\nis aw\\r\\n6\\r\\ne\";\n        exit;\n\n    case '/gzip-broken':\n        header('Content-Encoding: gzip');\n        echo str_repeat('-', 1000);\n        exit;\n\n    case '/max-duration':\n        ignore_user_abort(false);\n        while (true) {\n            echo '<1>';\n            @ob_flush();\n            flush();\n            usleep(500);\n        }\n        exit;\n\n    case '/json':\n        header('Content-Type: application/json');\n        echo json_encode([\n            'documents' => [\n                ['id' => '/json/1'],\n                ['id' => '/json/2'],\n                ['id' => '/json/3'],\n            ],\n        ]);\n        exit;\n\n    case '/json/1':\n    case '/json/2':\n    case '/json/3':\n        header('Content-Type: application/json');\n        echo json_encode([\n            'title' => $vars['REQUEST_URI'],\n        ]);\n\n        exit;\n}\n\nheader('Content-Type: application/json', true);\n\necho $json;\n"
  },
  {
    "path": "server/vendor/symfony/http-client-contracts/Test/HttpClientTestCase.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Contracts\\HttpClient\\Test;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Symfony\\Contracts\\HttpClient\\Exception\\ClientExceptionInterface;\nuse Symfony\\Contracts\\HttpClient\\Exception\\RedirectionExceptionInterface;\nuse Symfony\\Contracts\\HttpClient\\Exception\\TimeoutExceptionInterface;\nuse Symfony\\Contracts\\HttpClient\\Exception\\TransportExceptionInterface;\nuse Symfony\\Contracts\\HttpClient\\HttpClientInterface;\n\n/**\n * A reference test suite for HttpClientInterface implementations.\n */\nabstract class HttpClientTestCase extends TestCase\n{\n    public static function setUpBeforeClass(): void\n    {\n        if (!function_exists('ob_gzhandler')) {\n            static::markTestSkipped('The \"ob_gzhandler\" function is not available.');\n        }\n\n        TestHttpServer::start();\n    }\n\n    public static function tearDownAfterClass(): void\n    {\n        TestHttpServer::stop(8067);\n        TestHttpServer::stop(8077);\n    }\n\n    abstract protected function getHttpClient(string $testCase): HttpClientInterface;\n\n    public function testGetRequest()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n        $response = $client->request('GET', 'http://localhost:8057', [\n            'headers' => ['Foo' => 'baR'],\n            'user_data' => $data = new \\stdClass(),\n        ]);\n\n        $this->assertSame([], $response->getInfo('response_headers'));\n        $this->assertSame($data, $response->getInfo()['user_data']);\n        $this->assertSame(200, $response->getStatusCode());\n\n        $info = $response->getInfo();\n        $this->assertNull($info['error']);\n        $this->assertSame(0, $info['redirect_count']);\n        $this->assertSame('HTTP/1.1 200 OK', $info['response_headers'][0]);\n        $this->assertSame('Host: localhost:8057', $info['response_headers'][1]);\n        $this->assertSame('http://localhost:8057/', $info['url']);\n\n        $headers = $response->getHeaders();\n\n        $this->assertSame('localhost:8057', $headers['host'][0]);\n        $this->assertSame(['application/json'], $headers['content-type']);\n\n        $body = json_decode($response->getContent(), true);\n        $this->assertSame($body, $response->toArray());\n\n        $this->assertSame('HTTP/1.1', $body['SERVER_PROTOCOL']);\n        $this->assertSame('/', $body['REQUEST_URI']);\n        $this->assertSame('GET', $body['REQUEST_METHOD']);\n        $this->assertSame('localhost:8057', $body['HTTP_HOST']);\n        $this->assertSame('baR', $body['HTTP_FOO']);\n\n        $response = $client->request('GET', 'http://localhost:8057/length-broken');\n\n        $this->expectException(TransportExceptionInterface::class);\n        $response->getContent();\n    }\n\n    public function testHeadRequest()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n        $response = $client->request('HEAD', 'http://localhost:8057/head', [\n            'headers' => ['Foo' => 'baR'],\n            'user_data' => $data = new \\stdClass(),\n            'buffer' => false,\n        ]);\n\n        $this->assertSame([], $response->getInfo('response_headers'));\n        $this->assertSame(200, $response->getStatusCode());\n\n        $info = $response->getInfo();\n        $this->assertSame('HTTP/1.1 200 OK', $info['response_headers'][0]);\n        $this->assertSame('Host: localhost:8057', $info['response_headers'][1]);\n\n        $headers = $response->getHeaders();\n\n        $this->assertSame('localhost:8057', $headers['host'][0]);\n        $this->assertSame(['application/json'], $headers['content-type']);\n        $this->assertTrue(0 < $headers['content-length'][0]);\n\n        $this->assertSame('', $response->getContent());\n    }\n\n    public function testNonBufferedGetRequest()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n        $response = $client->request('GET', 'http://localhost:8057', [\n            'buffer' => false,\n            'headers' => ['Foo' => 'baR'],\n        ]);\n\n        $body = $response->toArray();\n        $this->assertSame('baR', $body['HTTP_FOO']);\n\n        $this->expectException(TransportExceptionInterface::class);\n        $response->getContent();\n    }\n\n    public function testBufferSink()\n    {\n        $sink = fopen('php://temp', 'w+');\n        $client = $this->getHttpClient(__FUNCTION__);\n        $response = $client->request('GET', 'http://localhost:8057', [\n            'buffer' => $sink,\n            'headers' => ['Foo' => 'baR'],\n        ]);\n\n        $body = $response->toArray();\n        $this->assertSame('baR', $body['HTTP_FOO']);\n\n        rewind($sink);\n        $sink = stream_get_contents($sink);\n        $this->assertSame($sink, $response->getContent());\n    }\n\n    public function testConditionalBuffering()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n        $response = $client->request('GET', 'http://localhost:8057');\n        $firstContent = $response->getContent();\n        $secondContent = $response->getContent();\n\n        $this->assertSame($firstContent, $secondContent);\n\n        $response = $client->request('GET', 'http://localhost:8057', ['buffer' => fn () => false]);\n        $response->getContent();\n\n        $this->expectException(TransportExceptionInterface::class);\n        $response->getContent();\n    }\n\n    public function testReentrantBufferCallback()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n\n        $response = $client->request('GET', 'http://localhost:8057', ['buffer' => function () use (&$response) {\n            $response->cancel();\n\n            return true;\n        }]);\n\n        $this->assertSame(200, $response->getStatusCode());\n\n        $this->expectException(TransportExceptionInterface::class);\n        $response->getContent();\n    }\n\n    public function testThrowingBufferCallback()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n\n        $response = $client->request('GET', 'http://localhost:8057', ['buffer' => function () {\n            throw new \\Exception('Boo.');\n        }]);\n\n        $this->assertSame(200, $response->getStatusCode());\n\n        $this->expectException(TransportExceptionInterface::class);\n        $this->expectExceptionMessage('Boo');\n        $response->getContent();\n    }\n\n    public function testUnsupportedOption()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n\n        $this->expectException(\\InvalidArgumentException::class);\n        $client->request('GET', 'http://localhost:8057', [\n            'capture_peer_cert' => 1.0,\n        ]);\n    }\n\n    public function testHttpVersion()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n        $response = $client->request('GET', 'http://localhost:8057', [\n            'http_version' => 1.0,\n        ]);\n\n        $this->assertSame(200, $response->getStatusCode());\n        $this->assertSame('HTTP/1.0 200 OK', $response->getInfo('response_headers')[0]);\n\n        $body = $response->toArray();\n\n        $this->assertSame('HTTP/1.0', $body['SERVER_PROTOCOL']);\n        $this->assertSame('GET', $body['REQUEST_METHOD']);\n        $this->assertSame('/', $body['REQUEST_URI']);\n    }\n\n    public function testChunkedEncoding()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n        $response = $client->request('GET', 'http://localhost:8057/chunked');\n\n        $this->assertSame(['chunked'], $response->getHeaders()['transfer-encoding']);\n        $this->assertSame('Symfony is awesome!', $response->getContent());\n\n        $response = $client->request('GET', 'http://localhost:8057/chunked-broken');\n\n        $this->expectException(TransportExceptionInterface::class);\n        $response->getContent();\n    }\n\n    public function testClientError()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n        $response = $client->request('GET', 'http://localhost:8057/404');\n\n        $client->stream($response)->valid();\n\n        $this->assertSame(404, $response->getInfo('http_code'));\n\n        try {\n            $response->getHeaders();\n            $this->fail(ClientExceptionInterface::class.' expected');\n        } catch (ClientExceptionInterface) {\n        }\n\n        try {\n            $response->getContent();\n            $this->fail(ClientExceptionInterface::class.' expected');\n        } catch (ClientExceptionInterface) {\n        }\n\n        $this->assertSame(404, $response->getStatusCode());\n        $this->assertSame(['application/json'], $response->getHeaders(false)['content-type']);\n        $this->assertNotEmpty($response->getContent(false));\n\n        $response = $client->request('GET', 'http://localhost:8057/404');\n\n        try {\n            foreach ($client->stream($response) as $chunk) {\n                $this->assertTrue($chunk->isFirst());\n            }\n            $this->fail(ClientExceptionInterface::class.' expected');\n        } catch (ClientExceptionInterface) {\n        }\n    }\n\n    public function testIgnoreErrors()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n        $response = $client->request('GET', 'http://localhost:8057/404');\n\n        $this->assertSame(404, $response->getStatusCode());\n    }\n\n    public function testDnsError()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n        $response = $client->request('GET', 'http://localhost:8057/301/bad-tld');\n\n        try {\n            $response->getStatusCode();\n            $this->fail(TransportExceptionInterface::class.' expected');\n        } catch (TransportExceptionInterface) {\n            $this->addToAssertionCount(1);\n        }\n\n        try {\n            $response->getStatusCode();\n            $this->fail(TransportExceptionInterface::class.' still expected');\n        } catch (TransportExceptionInterface) {\n            $this->addToAssertionCount(1);\n        }\n\n        $response = $client->request('GET', 'http://localhost:8057/301/bad-tld');\n\n        try {\n            foreach ($client->stream($response) as $r => $chunk) {\n            }\n            $this->fail(TransportExceptionInterface::class.' expected');\n        } catch (TransportExceptionInterface) {\n            $this->addToAssertionCount(1);\n        }\n\n        $this->assertSame($response, $r);\n        $this->assertNotNull($chunk->getError());\n\n        $this->expectException(TransportExceptionInterface::class);\n        foreach ($client->stream($response) as $chunk) {\n        }\n    }\n\n    public function testInlineAuth()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n        $response = $client->request('GET', 'http://foo:bar%3Dbar@localhost:8057');\n\n        $body = $response->toArray();\n\n        $this->assertSame('foo', $body['PHP_AUTH_USER']);\n        $this->assertSame('bar=bar', $body['PHP_AUTH_PW']);\n    }\n\n    public function testBadRequestBody()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n\n        $this->expectException(TransportExceptionInterface::class);\n\n        $response = $client->request('POST', 'http://localhost:8057/', [\n            'body' => function () { yield []; },\n        ]);\n\n        $response->getStatusCode();\n    }\n\n    public function test304()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n        $response = $client->request('GET', 'http://localhost:8057/304', [\n            'headers' => ['If-Match' => '\"abc\"'],\n            'buffer' => false,\n        ]);\n\n        $this->assertSame(304, $response->getStatusCode());\n        $this->assertSame('', $response->getContent(false));\n    }\n\n    /**\n     * @testWith [[]]\n     *           [[\"Content-Length: 7\"]]\n     */\n    public function testRedirects(array $headers = [])\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n        $response = $client->request('POST', 'http://localhost:8057/301', [\n            'auth_basic' => 'foo:bar',\n            'headers' => $headers,\n            'body' => function () {\n                yield 'foo=bar';\n            },\n        ]);\n\n        $body = $response->toArray();\n        $this->assertSame('GET', $body['REQUEST_METHOD']);\n        $this->assertSame('Basic Zm9vOmJhcg==', $body['HTTP_AUTHORIZATION']);\n        $this->assertSame('http://localhost:8057/', $response->getInfo('url'));\n\n        $this->assertSame(2, $response->getInfo('redirect_count'));\n        $this->assertNull($response->getInfo('redirect_url'));\n\n        $expected = [\n            'HTTP/1.1 301 Moved Permanently',\n            'Location: http://127.0.0.1:8057/302',\n            'Content-Type: application/json',\n            'HTTP/1.1 302 Found',\n            'Location: http://localhost:8057/',\n            'Content-Type: application/json',\n            'HTTP/1.1 200 OK',\n            'Content-Type: application/json',\n        ];\n\n        $filteredHeaders = array_values(array_filter($response->getInfo('response_headers'), function ($h) {\n            return \\in_array(substr($h, 0, 4), ['HTTP', 'Loca', 'Cont'], true) && 'Content-Encoding: gzip' !== $h;\n        }));\n\n        $this->assertSame($expected, $filteredHeaders);\n    }\n\n    public function testInvalidRedirect()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n        $response = $client->request('GET', 'http://localhost:8057/301/invalid');\n\n        $this->assertSame(301, $response->getStatusCode());\n        $this->assertSame(['//?foo=bar'], $response->getHeaders(false)['location']);\n        $this->assertSame(0, $response->getInfo('redirect_count'));\n        $this->assertNull($response->getInfo('redirect_url'));\n\n        $this->expectException(RedirectionExceptionInterface::class);\n        $response->getHeaders();\n    }\n\n    public function testRelativeRedirects()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n        $response = $client->request('GET', 'http://localhost:8057/302/relative');\n\n        $body = $response->toArray();\n\n        $this->assertSame('/', $body['REQUEST_URI']);\n        $this->assertNull($response->getInfo('redirect_url'));\n\n        $response = $client->request('GET', 'http://localhost:8057/302/relative', [\n            'max_redirects' => 0,\n        ]);\n\n        $this->assertSame(302, $response->getStatusCode());\n        $this->assertSame('http://localhost:8057/', $response->getInfo('redirect_url'));\n    }\n\n    public function testRedirect307()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n\n        $response = $client->request('POST', 'http://localhost:8057/307', [\n            'body' => function () {\n                yield 'foo=bar';\n            },\n            'max_redirects' => 0,\n        ]);\n\n        $this->assertSame(307, $response->getStatusCode());\n\n        $response = $client->request('POST', 'http://localhost:8057/307', [\n            'body' => 'foo=bar',\n        ]);\n\n        $body = $response->toArray();\n\n        $this->assertSame(['foo' => 'bar', 'REQUEST_METHOD' => 'POST'], $body);\n    }\n\n    public function testMaxRedirects()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n        $response = $client->request('GET', 'http://localhost:8057/301', [\n            'max_redirects' => 1,\n            'auth_basic' => 'foo:bar',\n        ]);\n\n        try {\n            $response->getHeaders();\n            $this->fail(RedirectionExceptionInterface::class.' expected');\n        } catch (RedirectionExceptionInterface) {\n        }\n\n        $this->assertSame(302, $response->getStatusCode());\n        $this->assertSame(1, $response->getInfo('redirect_count'));\n        $this->assertSame('http://localhost:8057/', $response->getInfo('redirect_url'));\n\n        $expected = [\n            'HTTP/1.1 301 Moved Permanently',\n            'Location: http://127.0.0.1:8057/302',\n            'Content-Type: application/json',\n            'HTTP/1.1 302 Found',\n            'Location: http://localhost:8057/',\n            'Content-Type: application/json',\n        ];\n\n        $filteredHeaders = array_values(array_filter($response->getInfo('response_headers'), function ($h) {\n            return \\in_array(substr($h, 0, 4), ['HTTP', 'Loca', 'Cont'], true);\n        }));\n\n        $this->assertSame($expected, $filteredHeaders);\n    }\n\n    public function testStream()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n\n        $response = $client->request('GET', 'http://localhost:8057');\n        $chunks = $client->stream($response);\n        $result = [];\n\n        foreach ($chunks as $r => $chunk) {\n            if ($chunk->isTimeout()) {\n                $result[] = 't';\n            } elseif ($chunk->isLast()) {\n                $result[] = 'l';\n            } elseif ($chunk->isFirst()) {\n                $result[] = 'f';\n            }\n        }\n\n        $this->assertSame($response, $r);\n        $this->assertSame(['f', 'l'], $result);\n\n        $chunk = null;\n        $i = 0;\n\n        foreach ($client->stream($response) as $chunk) {\n            ++$i;\n        }\n\n        $this->assertSame(1, $i);\n        $this->assertTrue($chunk->isLast());\n    }\n\n    public function testAddToStream()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n\n        $r1 = $client->request('GET', 'http://localhost:8057');\n\n        $completed = [];\n\n        $pool = [$r1];\n\n        while ($pool) {\n            $chunks = $client->stream($pool);\n            $pool = [];\n\n            foreach ($chunks as $r => $chunk) {\n                if (!$chunk->isLast()) {\n                    continue;\n                }\n\n                if ($r1 === $r) {\n                    $r2 = $client->request('GET', 'http://localhost:8057');\n                    $pool[] = $r2;\n                }\n\n                $completed[] = $r;\n            }\n        }\n\n        $this->assertSame([$r1, $r2], $completed);\n    }\n\n    public function testCompleteTypeError()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n\n        $this->expectException(\\TypeError::class);\n        $client->stream(123);\n    }\n\n    public function testOnProgress()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n        $response = $client->request('POST', 'http://localhost:8057/post', [\n            'headers' => ['Content-Length' => 14],\n            'body' => 'foo=0123456789',\n            'on_progress' => function (...$state) use (&$steps) { $steps[] = $state; },\n        ]);\n\n        $body = $response->toArray();\n\n        $this->assertSame(['foo' => '0123456789', 'REQUEST_METHOD' => 'POST'], $body);\n        $this->assertSame([0, 0], \\array_slice($steps[0], 0, 2));\n        $lastStep = \\array_slice($steps, -1)[0];\n        $this->assertSame([57, 57], \\array_slice($lastStep, 0, 2));\n        $this->assertSame('http://localhost:8057/post', $steps[0][2]['url']);\n    }\n\n    public function testPostJson()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n\n        $response = $client->request('POST', 'http://localhost:8057/post', [\n            'json' => ['foo' => 'bar'],\n        ]);\n\n        $body = $response->toArray();\n\n        $this->assertStringContainsString('json', $body['content-type']);\n        unset($body['content-type']);\n        $this->assertSame(['foo' => 'bar', 'REQUEST_METHOD' => 'POST'], $body);\n    }\n\n    public function testPostArray()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n\n        $response = $client->request('POST', 'http://localhost:8057/post', [\n            'body' => ['foo' => 'bar'],\n        ]);\n\n        $this->assertSame(['foo' => 'bar', 'REQUEST_METHOD' => 'POST'], $response->toArray());\n    }\n\n    public function testPostResource()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n\n        $h = fopen('php://temp', 'w+');\n        fwrite($h, 'foo=0123456789');\n        rewind($h);\n\n        $response = $client->request('POST', 'http://localhost:8057/post', [\n            'body' => $h,\n        ]);\n\n        $body = $response->toArray();\n\n        $this->assertSame(['foo' => '0123456789', 'REQUEST_METHOD' => 'POST'], $body);\n    }\n\n    public function testPostCallback()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n\n        $response = $client->request('POST', 'http://localhost:8057/post', [\n            'body' => function () {\n                yield 'foo';\n                yield '';\n                yield '=';\n                yield '0123456789';\n            },\n        ]);\n\n        $this->assertSame(['foo' => '0123456789', 'REQUEST_METHOD' => 'POST'], $response->toArray());\n    }\n\n    public function testCancel()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n        $response = $client->request('GET', 'http://localhost:8057/timeout-header');\n\n        $response->cancel();\n        $this->expectException(TransportExceptionInterface::class);\n        $response->getHeaders();\n    }\n\n    public function testInfoOnCanceledResponse()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n\n        $response = $client->request('GET', 'http://localhost:8057/timeout-header');\n\n        $this->assertFalse($response->getInfo('canceled'));\n        $response->cancel();\n        $this->assertTrue($response->getInfo('canceled'));\n    }\n\n    public function testCancelInStream()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n        $response = $client->request('GET', 'http://localhost:8057/404');\n\n        foreach ($client->stream($response) as $chunk) {\n            $response->cancel();\n        }\n\n        $this->expectException(TransportExceptionInterface::class);\n\n        foreach ($client->stream($response) as $chunk) {\n        }\n    }\n\n    public function testOnProgressCancel()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n        $response = $client->request('GET', 'http://localhost:8057/timeout-body', [\n            'on_progress' => function ($dlNow) {\n                if (0 < $dlNow) {\n                    throw new \\Exception('Aborting the request.');\n                }\n            },\n        ]);\n\n        try {\n            foreach ($client->stream([$response]) as $chunk) {\n            }\n            $this->fail(ClientExceptionInterface::class.' expected');\n        } catch (TransportExceptionInterface $e) {\n            $this->assertSame('Aborting the request.', $e->getPrevious()->getMessage());\n        }\n\n        $this->assertNotNull($response->getInfo('error'));\n        $this->expectException(TransportExceptionInterface::class);\n        $response->getContent();\n    }\n\n    public function testOnProgressError()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n        $response = $client->request('GET', 'http://localhost:8057/timeout-body', [\n            'on_progress' => function ($dlNow) {\n                if (0 < $dlNow) {\n                    throw new \\Error('BUG.');\n                }\n            },\n        ]);\n\n        try {\n            foreach ($client->stream([$response]) as $chunk) {\n            }\n            $this->fail('Error expected');\n        } catch (\\Error $e) {\n            $this->assertSame('BUG.', $e->getMessage());\n        }\n\n        $this->assertNotNull($response->getInfo('error'));\n        $this->expectException(TransportExceptionInterface::class);\n        $response->getContent();\n    }\n\n    public function testResolve()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n        $response = $client->request('GET', 'http://symfony.com:8057/', [\n            'resolve' => ['symfony.com' => '127.0.0.1'],\n        ]);\n\n        $this->assertSame(200, $response->getStatusCode());\n        $this->assertSame(200, $client->request('GET', 'http://symfony.com:8057/')->getStatusCode());\n\n        $response = null;\n        $this->expectException(TransportExceptionInterface::class);\n        $client->request('GET', 'http://symfony.com:8057/', ['timeout' => 1]);\n    }\n\n    public function testIdnResolve()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n\n        $response = $client->request('GET', 'http://0-------------------------------------------------------------0.com:8057/', [\n            'resolve' => ['0-------------------------------------------------------------0.com' => '127.0.0.1'],\n        ]);\n\n        $this->assertSame(200, $response->getStatusCode());\n\n        $response = $client->request('GET', 'http://Bücher.example:8057/', [\n            'resolve' => ['xn--bcher-kva.example' => '127.0.0.1'],\n        ]);\n\n        $this->assertSame(200, $response->getStatusCode());\n    }\n\n    public function testIPv6Resolve()\n    {\n        TestHttpServer::start(-8087);\n\n        $client = $this->getHttpClient(__FUNCTION__);\n        $response = $client->request('GET', 'http://symfony.com:8087/', [\n            'resolve' => ['symfony.com' => '::1'],\n        ]);\n\n        $this->assertSame(200, $response->getStatusCode());\n    }\n\n    public function testNotATimeout()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n        $response = $client->request('GET', 'http://localhost:8057/timeout-header', [\n            'timeout' => 0.9,\n        ]);\n        sleep(1);\n        $this->assertSame(200, $response->getStatusCode());\n    }\n\n    public function testTimeoutOnAccess()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n        $response = $client->request('GET', 'http://localhost:8057/timeout-header', [\n            'timeout' => 0.1,\n        ]);\n\n        $this->expectException(TransportExceptionInterface::class);\n        $response->getHeaders();\n    }\n\n    public function testTimeoutIsNotAFatalError()\n    {\n        usleep(300000); // wait for the previous test to release the server\n        $client = $this->getHttpClient(__FUNCTION__);\n        $response = $client->request('GET', 'http://localhost:8057/timeout-body', [\n            'timeout' => 0.25,\n        ]);\n\n        try {\n            $response->getContent();\n            $this->fail(TimeoutExceptionInterface::class.' expected');\n        } catch (TimeoutExceptionInterface $e) {\n        }\n\n        for ($i = 0; $i < 10; ++$i) {\n            try {\n                $this->assertSame('<1><2>', $response->getContent());\n                break;\n            } catch (TimeoutExceptionInterface $e) {\n            }\n        }\n\n        if (10 === $i) {\n            throw $e;\n        }\n    }\n\n    public function testTimeoutOnStream()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n        $response = $client->request('GET', 'http://localhost:8057/timeout-body');\n\n        $this->assertSame(200, $response->getStatusCode());\n        $chunks = $client->stream([$response], 0.2);\n\n        $result = [];\n\n        foreach ($chunks as $r => $chunk) {\n            if ($chunk->isTimeout()) {\n                $result[] = 't';\n            } else {\n                $result[] = $chunk->getContent();\n            }\n        }\n\n        $this->assertSame(['<1>', 't'], $result);\n\n        $chunks = $client->stream([$response]);\n\n        foreach ($chunks as $r => $chunk) {\n            $this->assertSame('<2>', $chunk->getContent());\n            $this->assertSame('<1><2>', $r->getContent());\n\n            return;\n        }\n\n        $this->fail('The response should have completed');\n    }\n\n    public function testUncheckedTimeoutThrows()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n        $response = $client->request('GET', 'http://localhost:8057/timeout-body');\n        $chunks = $client->stream([$response], 0.1);\n\n        $this->expectException(TransportExceptionInterface::class);\n\n        foreach ($chunks as $r => $chunk) {\n        }\n    }\n\n    public function testTimeoutWithActiveConcurrentStream()\n    {\n        $p1 = TestHttpServer::start(8067);\n        $p2 = TestHttpServer::start(8077);\n\n        $client = $this->getHttpClient(__FUNCTION__);\n        $streamingResponse = $client->request('GET', 'http://localhost:8067/max-duration');\n        $blockingResponse = $client->request('GET', 'http://localhost:8077/timeout-body', [\n            'timeout' => 0.25,\n        ]);\n\n        $this->assertSame(200, $streamingResponse->getStatusCode());\n        $this->assertSame(200, $blockingResponse->getStatusCode());\n\n        $this->expectException(TransportExceptionInterface::class);\n\n        try {\n            $blockingResponse->getContent();\n        } finally {\n            $p1->stop();\n            $p2->stop();\n        }\n    }\n\n    public function testTimeoutOnInitialize()\n    {\n        $p1 = TestHttpServer::start(8067);\n        $p2 = TestHttpServer::start(8077);\n\n        $client = $this->getHttpClient(__FUNCTION__);\n        $start = microtime(true);\n        $responses = [];\n\n        $responses[] = $client->request('GET', 'http://localhost:8067/timeout-header', ['timeout' => 0.25]);\n        $responses[] = $client->request('GET', 'http://localhost:8077/timeout-header', ['timeout' => 0.25]);\n        $responses[] = $client->request('GET', 'http://localhost:8067/timeout-header', ['timeout' => 0.25]);\n        $responses[] = $client->request('GET', 'http://localhost:8077/timeout-header', ['timeout' => 0.25]);\n\n        try {\n            foreach ($responses as $response) {\n                try {\n                    $response->getContent();\n                    $this->fail(TransportExceptionInterface::class.' expected');\n                } catch (TransportExceptionInterface) {\n                }\n            }\n            $responses = [];\n\n            $duration = microtime(true) - $start;\n\n            $this->assertLessThan(1.0, $duration);\n        } finally {\n            $p1->stop();\n            $p2->stop();\n        }\n    }\n\n    public function testTimeoutOnDestruct()\n    {\n        $p1 = TestHttpServer::start(8067);\n        $p2 = TestHttpServer::start(8077);\n\n        $client = $this->getHttpClient(__FUNCTION__);\n        $start = microtime(true);\n        $responses = [];\n\n        $responses[] = $client->request('GET', 'http://localhost:8067/timeout-header', ['timeout' => 0.25]);\n        $responses[] = $client->request('GET', 'http://localhost:8077/timeout-header', ['timeout' => 0.25]);\n        $responses[] = $client->request('GET', 'http://localhost:8067/timeout-header', ['timeout' => 0.25]);\n        $responses[] = $client->request('GET', 'http://localhost:8077/timeout-header', ['timeout' => 0.25]);\n\n        try {\n            while ($response = array_shift($responses)) {\n                try {\n                    unset($response);\n                    $this->fail(TransportExceptionInterface::class.' expected');\n                } catch (TransportExceptionInterface) {\n                }\n            }\n\n            $duration = microtime(true) - $start;\n\n            $this->assertLessThan(1.0, $duration);\n        } finally {\n            $p1->stop();\n            $p2->stop();\n        }\n    }\n\n    public function testDestruct()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n\n        $start = microtime(true);\n        $client->request('GET', 'http://localhost:8057/timeout-long');\n        $client = null;\n        $duration = microtime(true) - $start;\n\n        $this->assertGreaterThan(1, $duration);\n        $this->assertLessThan(4, $duration);\n    }\n\n    public function testGetContentAfterDestruct()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n\n        try {\n            $client->request('GET', 'http://localhost:8057/404');\n            $this->fail(ClientExceptionInterface::class.' expected');\n        } catch (ClientExceptionInterface $e) {\n            $this->assertSame('GET', $e->getResponse()->toArray(false)['REQUEST_METHOD']);\n        }\n    }\n\n    public function testGetEncodedContentAfterDestruct()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n\n        try {\n            $client->request('GET', 'http://localhost:8057/404-gzipped');\n            $this->fail(ClientExceptionInterface::class.' expected');\n        } catch (ClientExceptionInterface $e) {\n            $this->assertSame('some text', $e->getResponse()->getContent(false));\n        }\n    }\n\n    public function testProxy()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n        $response = $client->request('GET', 'http://localhost:8057/', [\n            'proxy' => 'http://localhost:8057',\n        ]);\n\n        $body = $response->toArray();\n        $this->assertSame('localhost:8057', $body['HTTP_HOST']);\n        $this->assertMatchesRegularExpression('#^http://(localhost|127\\.0\\.0\\.1):8057/$#', $body['REQUEST_URI']);\n\n        $response = $client->request('GET', 'http://localhost:8057/', [\n            'proxy' => 'http://foo:b%3Dar@localhost:8057',\n        ]);\n\n        $body = $response->toArray();\n        $this->assertSame('Basic Zm9vOmI9YXI=', $body['HTTP_PROXY_AUTHORIZATION']);\n\n        $_SERVER['http_proxy'] = 'http://localhost:8057';\n        try {\n            $response = $client->request('GET', 'http://localhost:8057/');\n            $body = $response->toArray();\n            $this->assertSame('localhost:8057', $body['HTTP_HOST']);\n            $this->assertMatchesRegularExpression('#^http://(localhost|127\\.0\\.0\\.1):8057/$#', $body['REQUEST_URI']);\n        } finally {\n            unset($_SERVER['http_proxy']);\n        }\n\n        $response = $client->request('GET', 'http://localhost:8057/301/proxy', [\n            'proxy' => 'http://localhost:8057',\n        ]);\n\n        $body = $response->toArray();\n        $this->assertSame('localhost:8057', $body['HTTP_HOST']);\n        $this->assertMatchesRegularExpression('#^http://(localhost|127\\.0\\.0\\.1):8057/$#', $body['REQUEST_URI']);\n    }\n\n    public function testNoProxy()\n    {\n        putenv('no_proxy='.$_SERVER['no_proxy'] = 'example.com, localhost');\n\n        try {\n            $client = $this->getHttpClient(__FUNCTION__);\n            $response = $client->request('GET', 'http://localhost:8057/', [\n                'proxy' => 'http://localhost:8057',\n            ]);\n\n            $body = $response->toArray();\n\n            $this->assertSame('HTTP/1.1', $body['SERVER_PROTOCOL']);\n            $this->assertSame('/', $body['REQUEST_URI']);\n            $this->assertSame('GET', $body['REQUEST_METHOD']);\n        } finally {\n            putenv('no_proxy');\n            unset($_SERVER['no_proxy']);\n        }\n    }\n\n    /**\n     * @requires extension zlib\n     */\n    public function testAutoEncodingRequest()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n        $response = $client->request('GET', 'http://localhost:8057');\n\n        $this->assertSame(200, $response->getStatusCode());\n\n        $headers = $response->getHeaders();\n\n        $this->assertSame(['Accept-Encoding'], $headers['vary']);\n        $this->assertStringContainsString('gzip', $headers['content-encoding'][0]);\n\n        $body = $response->toArray();\n\n        $this->assertStringContainsString('gzip', $body['HTTP_ACCEPT_ENCODING']);\n    }\n\n    public function testBaseUri()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n        $response = $client->request('GET', '../404', [\n            'base_uri' => 'http://localhost:8057/abc/',\n        ]);\n\n        $this->assertSame(404, $response->getStatusCode());\n        $this->assertSame(['application/json'], $response->getHeaders(false)['content-type']);\n    }\n\n    public function testQuery()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n        $response = $client->request('GET', 'http://localhost:8057/?a=a', [\n            'query' => ['b' => 'b'],\n        ]);\n\n        $body = $response->toArray();\n        $this->assertSame('GET', $body['REQUEST_METHOD']);\n        $this->assertSame('/?a=a&b=b', $body['REQUEST_URI']);\n    }\n\n    public function testInformationalResponse()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n        $response = $client->request('GET', 'http://localhost:8057/103');\n\n        $this->assertSame('Here the body', $response->getContent());\n        $this->assertSame(200, $response->getStatusCode());\n    }\n\n    public function testInformationalResponseStream()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n        $response = $client->request('GET', 'http://localhost:8057/103');\n\n        $chunks = [];\n        foreach ($client->stream($response) as $chunk) {\n            $chunks[] = $chunk;\n        }\n\n        $this->assertSame(103, $chunks[0]->getInformationalStatus()[0]);\n        $this->assertSame(['</style.css>; rel=preload; as=style', '</script.js>; rel=preload; as=script'], $chunks[0]->getInformationalStatus()[1]['link']);\n        $this->assertTrue($chunks[1]->isFirst());\n        $this->assertSame('Here the body', $chunks[2]->getContent());\n        $this->assertTrue($chunks[3]->isLast());\n        $this->assertNull($chunks[3]->getInformationalStatus());\n\n        $this->assertSame(['date', 'content-length'], array_keys($response->getHeaders()));\n        $this->assertContains('Link: </style.css>; rel=preload; as=style', $response->getInfo('response_headers'));\n    }\n\n    /**\n     * @requires extension zlib\n     */\n    public function testUserlandEncodingRequest()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n        $response = $client->request('GET', 'http://localhost:8057', [\n            'headers' => ['Accept-Encoding' => 'gzip'],\n        ]);\n\n        $headers = $response->getHeaders();\n\n        $this->assertSame(['Accept-Encoding'], $headers['vary']);\n        $this->assertStringContainsString('gzip', $headers['content-encoding'][0]);\n\n        $body = $response->getContent();\n        $this->assertSame(\"\\x1F\", $body[0]);\n\n        $body = json_decode(gzdecode($body), true);\n        $this->assertSame('gzip', $body['HTTP_ACCEPT_ENCODING']);\n    }\n\n    /**\n     * @requires extension zlib\n     */\n    public function testGzipBroken()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n        $response = $client->request('GET', 'http://localhost:8057/gzip-broken');\n\n        $this->expectException(TransportExceptionInterface::class);\n        $response->getContent();\n    }\n\n    public function testMaxDuration()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n        $response = $client->request('GET', 'http://localhost:8057/max-duration', [\n            'max_duration' => 0.1,\n        ]);\n\n        $start = microtime(true);\n\n        try {\n            $response->getContent();\n        } catch (TransportExceptionInterface) {\n            $this->addToAssertionCount(1);\n        }\n\n        $duration = microtime(true) - $start;\n\n        $this->assertLessThan(10, $duration);\n    }\n\n    public function testWithOptions()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n        $client2 = $client->withOptions(['base_uri' => 'http://localhost:8057/']);\n\n        $this->assertNotSame($client, $client2);\n        $this->assertSame($client::class, $client2::class);\n\n        $response = $client2->request('GET', '/');\n        $this->assertSame(200, $response->getStatusCode());\n    }\n\n    public function testBindToPort()\n    {\n        $client = $this->getHttpClient(__FUNCTION__);\n        $response = $client->request('GET', 'http://localhost:8057', ['bindto' => '127.0.0.1:9876']);\n        $response->getStatusCode();\n\n        $vars = $response->toArray();\n\n        self::assertSame('127.0.0.1', $vars['REMOTE_ADDR']);\n        self::assertSame('9876', $vars['REMOTE_PORT']);\n    }\n\n    public function testBindToPortV6()\n    {\n        TestHttpServer::start(-8087);\n\n        $client = $this->getHttpClient(__FUNCTION__);\n        $response = $client->request('GET', 'http://[::1]:8087', ['bindto' => '[::1]:9876']);\n        $response->getStatusCode();\n\n        $vars = $response->toArray();\n\n        self::assertSame('::1', $vars['REMOTE_ADDR']);\n\n        if ('\\\\' !== \\DIRECTORY_SEPARATOR) {\n            self::assertSame('9876', $vars['REMOTE_PORT']);\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client-contracts/Test/TestHttpServer.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Contracts\\HttpClient\\Test;\n\nuse Symfony\\Component\\Process\\PhpExecutableFinder;\nuse Symfony\\Component\\Process\\Process;\n\nclass TestHttpServer\n{\n    private static array $process = [];\n\n    /**\n     * @param string|null $workingDirectory\n     */\n    public static function start(int $port = 8057/* , ?string $workingDirectory = null */): Process\n    {\n        $workingDirectory = \\func_get_args()[1] ?? __DIR__.'/Fixtures/web';\n\n        if (0 > $port) {\n            $port = -$port;\n            $ip = '[::1]';\n        } else {\n            $ip = '127.0.0.1';\n        }\n\n        if (isset(self::$process[$port])) {\n            self::$process[$port]->stop();\n        } else {\n            register_shutdown_function(static function () use ($port) {\n                self::$process[$port]->stop();\n            });\n        }\n\n        $finder = new PhpExecutableFinder();\n        $process = new Process(array_merge([$finder->find(false)], $finder->findArguments(), ['-dopcache.enable=0', '-dvariables_order=EGPCS', '-S', $ip.':'.$port]));\n        $process->setWorkingDirectory($workingDirectory);\n        $process->start();\n        self::$process[$port] = $process;\n\n        do {\n            usleep(50000);\n        } while (!@fopen('http://'.$ip.':'.$port, 'r'));\n\n        return $process;\n    }\n\n    public static function stop(int $port = 8057)\n    {\n        if (isset(self::$process[$port])) {\n            self::$process[$port]->stop();\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/http-client-contracts/composer.json",
    "content": "{\n    \"name\": \"symfony/http-client-contracts\",\n    \"type\": \"library\",\n    \"description\": \"Generic abstractions related to HTTP clients\",\n    \"keywords\": [\"abstractions\", \"contracts\", \"decoupling\", \"interfaces\", \"interoperability\", \"standards\"],\n    \"homepage\": \"https://symfony.com\",\n    \"license\": \"MIT\",\n    \"authors\": [\n        {\n            \"name\": \"Nicolas Grekas\",\n            \"email\": \"p@tchwork.com\"\n        },\n        {\n            \"name\": \"Symfony Community\",\n            \"homepage\": \"https://symfony.com/contributors\"\n        }\n    ],\n    \"require\": {\n        \"php\": \">=8.1\"\n    },\n    \"autoload\": {\n        \"psr-4\": { \"Symfony\\\\Contracts\\\\HttpClient\\\\\": \"\" },\n        \"exclude-from-classmap\": [\n            \"/Test/\"\n        ]\n    },\n    \"minimum-stability\": \"dev\",\n    \"extra\": {\n        \"branch-alias\": {\n            \"dev-main\": \"3.5-dev\"\n        },\n        \"thanks\": {\n            \"name\": \"symfony/contracts\",\n            \"url\": \"https://github.com/symfony/contracts\"\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-ctype/Ctype.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Polyfill\\Ctype;\n\n/**\n * Ctype implementation through regex.\n *\n * @internal\n *\n * @author Gert de Pagter <BackEndTea@gmail.com>\n */\nfinal class Ctype\n{\n    /**\n     * Returns TRUE if every character in text is either a letter or a digit, FALSE otherwise.\n     *\n     * @see https://php.net/ctype-alnum\n     *\n     * @param mixed $text\n     *\n     * @return bool\n     */\n    public static function ctype_alnum($text)\n    {\n        $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);\n\n        return \\is_string($text) && '' !== $text && !preg_match('/[^A-Za-z0-9]/', $text);\n    }\n\n    /**\n     * Returns TRUE if every character in text is a letter, FALSE otherwise.\n     *\n     * @see https://php.net/ctype-alpha\n     *\n     * @param mixed $text\n     *\n     * @return bool\n     */\n    public static function ctype_alpha($text)\n    {\n        $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);\n\n        return \\is_string($text) && '' !== $text && !preg_match('/[^A-Za-z]/', $text);\n    }\n\n    /**\n     * Returns TRUE if every character in text is a control character from the current locale, FALSE otherwise.\n     *\n     * @see https://php.net/ctype-cntrl\n     *\n     * @param mixed $text\n     *\n     * @return bool\n     */\n    public static function ctype_cntrl($text)\n    {\n        $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);\n\n        return \\is_string($text) && '' !== $text && !preg_match('/[^\\x00-\\x1f\\x7f]/', $text);\n    }\n\n    /**\n     * Returns TRUE if every character in the string text is a decimal digit, FALSE otherwise.\n     *\n     * @see https://php.net/ctype-digit\n     *\n     * @param mixed $text\n     *\n     * @return bool\n     */\n    public static function ctype_digit($text)\n    {\n        $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);\n\n        return \\is_string($text) && '' !== $text && !preg_match('/[^0-9]/', $text);\n    }\n\n    /**\n     * Returns TRUE if every character in text is printable and actually creates visible output (no white space), FALSE otherwise.\n     *\n     * @see https://php.net/ctype-graph\n     *\n     * @param mixed $text\n     *\n     * @return bool\n     */\n    public static function ctype_graph($text)\n    {\n        $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);\n\n        return \\is_string($text) && '' !== $text && !preg_match('/[^!-~]/', $text);\n    }\n\n    /**\n     * Returns TRUE if every character in text is a lowercase letter.\n     *\n     * @see https://php.net/ctype-lower\n     *\n     * @param mixed $text\n     *\n     * @return bool\n     */\n    public static function ctype_lower($text)\n    {\n        $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);\n\n        return \\is_string($text) && '' !== $text && !preg_match('/[^a-z]/', $text);\n    }\n\n    /**\n     * Returns TRUE if every character in text will actually create output (including blanks). Returns FALSE if text contains control characters or characters that do not have any output or control function at all.\n     *\n     * @see https://php.net/ctype-print\n     *\n     * @param mixed $text\n     *\n     * @return bool\n     */\n    public static function ctype_print($text)\n    {\n        $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);\n\n        return \\is_string($text) && '' !== $text && !preg_match('/[^ -~]/', $text);\n    }\n\n    /**\n     * Returns TRUE if every character in text is printable, but neither letter, digit or blank, FALSE otherwise.\n     *\n     * @see https://php.net/ctype-punct\n     *\n     * @param mixed $text\n     *\n     * @return bool\n     */\n    public static function ctype_punct($text)\n    {\n        $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);\n\n        return \\is_string($text) && '' !== $text && !preg_match('/[^!-\\/\\:-@\\[-`\\{-~]/', $text);\n    }\n\n    /**\n     * Returns TRUE if every character in text creates some sort of white space, FALSE otherwise. Besides the blank character this also includes tab, vertical tab, line feed, carriage return and form feed characters.\n     *\n     * @see https://php.net/ctype-space\n     *\n     * @param mixed $text\n     *\n     * @return bool\n     */\n    public static function ctype_space($text)\n    {\n        $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);\n\n        return \\is_string($text) && '' !== $text && !preg_match('/[^\\s]/', $text);\n    }\n\n    /**\n     * Returns TRUE if every character in text is an uppercase letter.\n     *\n     * @see https://php.net/ctype-upper\n     *\n     * @param mixed $text\n     *\n     * @return bool\n     */\n    public static function ctype_upper($text)\n    {\n        $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);\n\n        return \\is_string($text) && '' !== $text && !preg_match('/[^A-Z]/', $text);\n    }\n\n    /**\n     * Returns TRUE if every character in text is a hexadecimal 'digit', that is a decimal digit or a character from [A-Fa-f] , FALSE otherwise.\n     *\n     * @see https://php.net/ctype-xdigit\n     *\n     * @param mixed $text\n     *\n     * @return bool\n     */\n    public static function ctype_xdigit($text)\n    {\n        $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);\n\n        return \\is_string($text) && '' !== $text && !preg_match('/[^A-Fa-f0-9]/', $text);\n    }\n\n    /**\n     * Converts integers to their char versions according to normal ctype behaviour, if needed.\n     *\n     * If an integer between -128 and 255 inclusive is provided,\n     * it is interpreted as the ASCII value of a single character\n     * (negative values have 256 added in order to allow characters in the Extended ASCII range).\n     * Any other integer is interpreted as a string containing the decimal digits of the integer.\n     *\n     * @param mixed  $int\n     * @param string $function\n     *\n     * @return mixed\n     */\n    private static function convert_int_to_char_for_ctype($int, $function)\n    {\n        if (!\\is_int($int)) {\n            return $int;\n        }\n\n        if ($int < -128 || $int > 255) {\n            return (string) $int;\n        }\n\n        if (\\PHP_VERSION_ID >= 80100) {\n            @trigger_error($function.'(): Argument of type int will be interpreted as string in the future', \\E_USER_DEPRECATED);\n        }\n\n        if ($int < 0) {\n            $int += 256;\n        }\n\n        return \\chr($int);\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-ctype/LICENSE",
    "content": "Copyright (c) 2018-present Fabien Potencier\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is furnished\nto do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-ctype/README.md",
    "content": "Symfony Polyfill / Ctype\n========================\n\nThis component provides `ctype_*` functions to users who run php versions without the ctype extension.\n\nMore information can be found in the\n[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md).\n\nLicense\n=======\n\nThis library is released under the [MIT license](LICENSE).\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-ctype/bootstrap.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nuse Symfony\\Polyfill\\Ctype as p;\n\nif (\\PHP_VERSION_ID >= 80000) {\n    return require __DIR__.'/bootstrap80.php';\n}\n\nif (!function_exists('ctype_alnum')) {\n    function ctype_alnum($text) { return p\\Ctype::ctype_alnum($text); }\n}\nif (!function_exists('ctype_alpha')) {\n    function ctype_alpha($text) { return p\\Ctype::ctype_alpha($text); }\n}\nif (!function_exists('ctype_cntrl')) {\n    function ctype_cntrl($text) { return p\\Ctype::ctype_cntrl($text); }\n}\nif (!function_exists('ctype_digit')) {\n    function ctype_digit($text) { return p\\Ctype::ctype_digit($text); }\n}\nif (!function_exists('ctype_graph')) {\n    function ctype_graph($text) { return p\\Ctype::ctype_graph($text); }\n}\nif (!function_exists('ctype_lower')) {\n    function ctype_lower($text) { return p\\Ctype::ctype_lower($text); }\n}\nif (!function_exists('ctype_print')) {\n    function ctype_print($text) { return p\\Ctype::ctype_print($text); }\n}\nif (!function_exists('ctype_punct')) {\n    function ctype_punct($text) { return p\\Ctype::ctype_punct($text); }\n}\nif (!function_exists('ctype_space')) {\n    function ctype_space($text) { return p\\Ctype::ctype_space($text); }\n}\nif (!function_exists('ctype_upper')) {\n    function ctype_upper($text) { return p\\Ctype::ctype_upper($text); }\n}\nif (!function_exists('ctype_xdigit')) {\n    function ctype_xdigit($text) { return p\\Ctype::ctype_xdigit($text); }\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-ctype/bootstrap80.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nuse Symfony\\Polyfill\\Ctype as p;\n\nif (!function_exists('ctype_alnum')) {\n    function ctype_alnum(mixed $text): bool { return p\\Ctype::ctype_alnum($text); }\n}\nif (!function_exists('ctype_alpha')) {\n    function ctype_alpha(mixed $text): bool { return p\\Ctype::ctype_alpha($text); }\n}\nif (!function_exists('ctype_cntrl')) {\n    function ctype_cntrl(mixed $text): bool { return p\\Ctype::ctype_cntrl($text); }\n}\nif (!function_exists('ctype_digit')) {\n    function ctype_digit(mixed $text): bool { return p\\Ctype::ctype_digit($text); }\n}\nif (!function_exists('ctype_graph')) {\n    function ctype_graph(mixed $text): bool { return p\\Ctype::ctype_graph($text); }\n}\nif (!function_exists('ctype_lower')) {\n    function ctype_lower(mixed $text): bool { return p\\Ctype::ctype_lower($text); }\n}\nif (!function_exists('ctype_print')) {\n    function ctype_print(mixed $text): bool { return p\\Ctype::ctype_print($text); }\n}\nif (!function_exists('ctype_punct')) {\n    function ctype_punct(mixed $text): bool { return p\\Ctype::ctype_punct($text); }\n}\nif (!function_exists('ctype_space')) {\n    function ctype_space(mixed $text): bool { return p\\Ctype::ctype_space($text); }\n}\nif (!function_exists('ctype_upper')) {\n    function ctype_upper(mixed $text): bool { return p\\Ctype::ctype_upper($text); }\n}\nif (!function_exists('ctype_xdigit')) {\n    function ctype_xdigit(mixed $text): bool { return p\\Ctype::ctype_xdigit($text); }\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-ctype/composer.json",
    "content": "{\n    \"name\": \"symfony/polyfill-ctype\",\n    \"type\": \"library\",\n    \"description\": \"Symfony polyfill for ctype functions\",\n    \"keywords\": [\"polyfill\", \"compatibility\", \"portable\", \"ctype\"],\n    \"homepage\": \"https://symfony.com\",\n    \"license\": \"MIT\",\n    \"authors\": [\n        {\n            \"name\": \"Gert de Pagter\",\n            \"email\": \"BackEndTea@gmail.com\"\n        },\n        {\n            \"name\": \"Symfony Community\",\n            \"homepage\": \"https://symfony.com/contributors\"\n        }\n    ],\n    \"require\": {\n        \"php\": \">=7.2\"\n    },\n    \"provide\": {\n        \"ext-ctype\": \"*\"\n    },\n    \"autoload\": {\n        \"psr-4\": { \"Symfony\\\\Polyfill\\\\Ctype\\\\\": \"\" },\n        \"files\": [ \"bootstrap.php\" ]\n    },\n    \"suggest\": {\n        \"ext-ctype\": \"For best performance\"\n    },\n    \"minimum-stability\": \"dev\",\n    \"extra\": {\n        \"thanks\": {\n            \"name\": \"symfony/polyfill\",\n            \"url\": \"https://github.com/symfony/polyfill\"\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-intl-grapheme/Grapheme.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Polyfill\\Intl\\Grapheme;\n\n\\define('SYMFONY_GRAPHEME_CLUSTER_RX', ((float) \\PCRE_VERSION < 10 ? (float) \\PCRE_VERSION >= 8.32 : (float) \\PCRE_VERSION >= 10.39) ? '\\X' : Grapheme::GRAPHEME_CLUSTER_RX);\n\n/**\n * Partial intl implementation in pure PHP.\n *\n * Implemented:\n * - grapheme_extract  - Extract a sequence of grapheme clusters from a text buffer, which must be encoded in UTF-8\n * - grapheme_stripos  - Find position (in grapheme units) of first occurrence of a case-insensitive string\n * - grapheme_stristr  - Returns part of haystack string from the first occurrence of case-insensitive needle to the end of haystack\n * - grapheme_strlen   - Get string length in grapheme units\n * - grapheme_strpos   - Find position (in grapheme units) of first occurrence of a string\n * - grapheme_strripos - Find position (in grapheme units) of last occurrence of a case-insensitive string\n * - grapheme_strrpos  - Find position (in grapheme units) of last occurrence of a string\n * - grapheme_strstr   - Returns part of haystack string from the first occurrence of needle to the end of haystack\n * - grapheme_substr   - Return part of a string\n *\n * @author Nicolas Grekas <p@tchwork.com>\n *\n * @internal\n */\nfinal class Grapheme\n{\n    // (CRLF|([ZWNJ-ZWJ]|T+|L*(LV?V+|LV|LVT)T*|L+|[^Control])[Extend]*|[Control])\n    // This regular expression is a work around for http://bugs.exim.org/1279\n    public const GRAPHEME_CLUSTER_RX = '(?:\\r\\n|(?:[ -~\\x{200C}\\x{200D}]|[ᆨ-ᇹ]+|[ᄀ-ᅟ]*(?:[가개갸걔거게겨계고과괘괴교구궈궤귀규그긔기까깨꺄꺠꺼께껴꼐꼬꽈꽤꾀꾜꾸꿔꿰뀌뀨끄끠끼나내냐냬너네녀녜노놔놰뇌뇨누눠눼뉘뉴느늬니다대댜댸더데뎌뎨도돠돼되됴두둬뒈뒤듀드듸디따때땨떄떠떼뗘뗴또똬뙈뙤뚀뚜뚸뛔뛰뜌뜨띄띠라래랴럐러레려례로롸뢔뢰료루뤄뤠뤼류르릐리마매먀먜머메며몌모뫄뫠뫼묘무뭐뭬뮈뮤므믜미바배뱌뱨버베벼볘보봐봬뵈뵤부붜붸뷔뷰브븨비빠빼뺘뺴뻐뻬뼈뼤뽀뽜뽸뾔뾰뿌뿨쀄쀠쀼쁘쁴삐사새샤섀서세셔셰소솨쇄쇠쇼수숴쉐쉬슈스싀시싸쌔쌰썌써쎄쎠쎼쏘쏴쐐쐬쑈쑤쒀쒜쒸쓔쓰씌씨아애야얘어에여예오와왜외요우워웨위유으의이자재쟈쟤저제져졔조좌좨죄죠주줘줴쥐쥬즈즤지짜째쨔쨰쩌쩨쪄쪠쪼쫘쫴쬐쬬쭈쭤쮀쮜쮸쯔쯰찌차채챠챼처체쳐쳬초촤쵀최쵸추춰췌취츄츠츼치카캐캬컈커케켜켸코콰쾌쾨쿄쿠쿼퀘퀴큐크킈키타태탸턔터테텨톄토톼퇘퇴툐투퉈퉤튀튜트틔티파패퍄퍠퍼페펴폐포퐈퐤푀표푸풔풰퓌퓨프픠피하해햐햬허헤혀혜호화홰회효후훠훼휘휴흐희히]?[ᅠ-ᆢ]+|[가-힣])[ᆨ-ᇹ]*|[ᄀ-ᅟ]+|[^\\p{Cc}\\p{Cf}\\p{Zl}\\p{Zp}])[\\p{Mn}\\p{Me}\\x{09BE}\\x{09D7}\\x{0B3E}\\x{0B57}\\x{0BBE}\\x{0BD7}\\x{0CC2}\\x{0CD5}\\x{0CD6}\\x{0D3E}\\x{0D57}\\x{0DCF}\\x{0DDF}\\x{200C}\\x{200D}\\x{1D165}\\x{1D16E}-\\x{1D172}]*|[\\p{Cc}\\p{Cf}\\p{Zl}\\p{Zp}])';\n\n    private const CASE_FOLD = [\n        ['µ', 'ſ', \"\\xCD\\x85\", 'ς', \"\\xCF\\x90\", \"\\xCF\\x91\", \"\\xCF\\x95\", \"\\xCF\\x96\", \"\\xCF\\xB0\", \"\\xCF\\xB1\", \"\\xCF\\xB5\", \"\\xE1\\xBA\\x9B\", \"\\xE1\\xBE\\xBE\"],\n        ['μ', 's', 'ι',        'σ', 'β',        'θ',        'φ',        'π',        'κ',        'ρ',        'ε',        \"\\xE1\\xB9\\xA1\", 'ι'],\n    ];\n\n    public static function grapheme_extract($s, $size, $type = \\GRAPHEME_EXTR_COUNT, $start = 0, &$next = 0)\n    {\n        if (0 > $start) {\n            $start = \\strlen($s) + $start;\n        }\n\n        if (!\\is_scalar($s)) {\n            $hasError = false;\n            set_error_handler(function () use (&$hasError) { $hasError = true; });\n            $next = substr($s, $start);\n            restore_error_handler();\n            if ($hasError) {\n                substr($s, $start);\n                $s = '';\n            } else {\n                $s = $next;\n            }\n        } else {\n            $s = substr($s, $start);\n        }\n        $size = (int) $size;\n        $type = (int) $type;\n        $start = (int) $start;\n\n        if (\\GRAPHEME_EXTR_COUNT !== $type && \\GRAPHEME_EXTR_MAXBYTES !== $type && \\GRAPHEME_EXTR_MAXCHARS !== $type) {\n            if (80000 > \\PHP_VERSION_ID) {\n                return false;\n            }\n\n            throw new \\ValueError('grapheme_extract(): Argument #3 ($type) must be one of GRAPHEME_EXTR_COUNT, GRAPHEME_EXTR_MAXBYTES, or GRAPHEME_EXTR_MAXCHARS');\n        }\n\n        if (!isset($s[0]) || 0 > $size || 0 > $start) {\n            return false;\n        }\n        if (0 === $size) {\n            return '';\n        }\n\n        $next = $start;\n\n        $s = preg_split('/('.SYMFONY_GRAPHEME_CLUSTER_RX.')/u', \"\\r\\n\".$s, $size + 1, \\PREG_SPLIT_NO_EMPTY | \\PREG_SPLIT_DELIM_CAPTURE);\n\n        if (!isset($s[1])) {\n            return false;\n        }\n\n        $i = 1;\n        $ret = '';\n\n        do {\n            if (\\GRAPHEME_EXTR_COUNT === $type) {\n                --$size;\n            } elseif (\\GRAPHEME_EXTR_MAXBYTES === $type) {\n                $size -= \\strlen($s[$i]);\n            } else {\n                $size -= iconv_strlen($s[$i], 'UTF-8//IGNORE');\n            }\n\n            if ($size >= 0) {\n                $ret .= $s[$i];\n            }\n        } while (isset($s[++$i]) && $size > 0);\n\n        $next += \\strlen($ret);\n\n        return $ret;\n    }\n\n    public static function grapheme_strlen($s)\n    {\n        preg_replace('/'.SYMFONY_GRAPHEME_CLUSTER_RX.'/u', '', $s, -1, $len);\n\n        return 0 === $len && '' !== $s ? null : $len;\n    }\n\n    public static function grapheme_substr($s, $start, $len = null)\n    {\n        if (null === $len) {\n            $len = 2147483647;\n        }\n\n        preg_match_all('/'.SYMFONY_GRAPHEME_CLUSTER_RX.'/u', $s, $s);\n\n        $slen = \\count($s[0]);\n        $start = (int) $start;\n\n        if (0 > $start) {\n            $start += $slen;\n        }\n        if (0 > $start) {\n            if (\\PHP_VERSION_ID < 80000) {\n                return false;\n            }\n\n            $start = 0;\n        }\n        if ($start >= $slen) {\n            return \\PHP_VERSION_ID >= 80000 ? '' : false;\n        }\n\n        $rem = $slen - $start;\n\n        if (0 > $len) {\n            $len += $rem;\n        }\n        if (0 === $len) {\n            return '';\n        }\n        if (0 > $len) {\n            return \\PHP_VERSION_ID >= 80000 ? '' : false;\n        }\n        if ($len > $rem) {\n            $len = $rem;\n        }\n\n        return implode('', \\array_slice($s[0], $start, $len));\n    }\n\n    public static function grapheme_strpos($s, $needle, $offset = 0)\n    {\n        return self::grapheme_position($s, $needle, $offset, 0);\n    }\n\n    public static function grapheme_stripos($s, $needle, $offset = 0)\n    {\n        return self::grapheme_position($s, $needle, $offset, 1);\n    }\n\n    public static function grapheme_strrpos($s, $needle, $offset = 0)\n    {\n        return self::grapheme_position($s, $needle, $offset, 2);\n    }\n\n    public static function grapheme_strripos($s, $needle, $offset = 0)\n    {\n        return self::grapheme_position($s, $needle, $offset, 3);\n    }\n\n    public static function grapheme_stristr($s, $needle, $beforeNeedle = false)\n    {\n        return mb_stristr($s, $needle, $beforeNeedle, 'UTF-8');\n    }\n\n    public static function grapheme_strstr($s, $needle, $beforeNeedle = false)\n    {\n        return mb_strstr($s, $needle, $beforeNeedle, 'UTF-8');\n    }\n\n    private static function grapheme_position($s, $needle, $offset, $mode)\n    {\n        $needle = (string) $needle;\n        if (80000 > \\PHP_VERSION_ID && !preg_match('/./us', $needle)) {\n            return false;\n        }\n        $s = (string) $s;\n        if (!preg_match('/./us', $s)) {\n            return false;\n        }\n        if ($offset > 0) {\n            $s = self::grapheme_substr($s, $offset);\n        } elseif ($offset < 0) {\n            if (2 > $mode) {\n                $offset += self::grapheme_strlen($s);\n                $s = self::grapheme_substr($s, $offset);\n                if (0 > $offset) {\n                    $offset = 0;\n                }\n            } elseif (0 > $offset += self::grapheme_strlen($needle)) {\n                $s = self::grapheme_substr($s, 0, $offset);\n                $offset = 0;\n            } else {\n                $offset = 0;\n            }\n        }\n\n        // As UTF-8 is self-synchronizing, and we have ensured the strings are valid UTF-8,\n        // we can use normal binary string functions here. For case-insensitive searches,\n        // case fold the strings first.\n        $caseInsensitive = $mode & 1;\n        $reverse = $mode & 2;\n        if ($caseInsensitive) {\n            // Use the same case folding mode as mbstring does for mb_stripos().\n            // Stick to SIMPLE case folding to avoid changing the length of the string, which\n            // might result in offsets being shifted.\n            $mode = \\defined('MB_CASE_FOLD_SIMPLE') ? \\MB_CASE_FOLD_SIMPLE : \\MB_CASE_LOWER;\n            $s = mb_convert_case($s, $mode, 'UTF-8');\n            $needle = mb_convert_case($needle, $mode, 'UTF-8');\n\n            if (!\\defined('MB_CASE_FOLD_SIMPLE')) {\n                $s = str_replace(self::CASE_FOLD[0], self::CASE_FOLD[1], $s);\n                $needle = str_replace(self::CASE_FOLD[0], self::CASE_FOLD[1], $needle);\n            }\n        }\n        if ($reverse) {\n            $needlePos = strrpos($s, $needle);\n        } else {\n            $needlePos = strpos($s, $needle);\n        }\n\n        return false !== $needlePos ? self::grapheme_strlen(substr($s, 0, $needlePos)) + $offset : false;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-intl-grapheme/LICENSE",
    "content": "Copyright (c) 2015-present Fabien Potencier\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is furnished\nto do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-intl-grapheme/README.md",
    "content": "Symfony Polyfill / Intl: Grapheme\n=================================\n\nThis component provides a partial, native PHP implementation of the\n[Grapheme functions](https://php.net/intl.grapheme) from the\n[Intl](https://php.net/intl) extension.\n\n- [`grapheme_extract`](https://php.net/grapheme_extract): Extract a sequence of grapheme\n  clusters from a text buffer, which must be encoded in UTF-8\n- [`grapheme_stripos`](https://php.net/grapheme_stripos): Find position (in grapheme units)\n  of first occurrence of a case-insensitive string\n- [`grapheme_stristr`](https://php.net/grapheme_stristr): Returns part of haystack string\n  from the first occurrence of case-insensitive needle to the end of haystack\n- [`grapheme_strlen`](https://php.net/grapheme_strlen): Get string length in grapheme units\n- [`grapheme_strpos`](https://php.net/grapheme_strpos): Find position (in grapheme units)\n  of first occurrence of a string\n- [`grapheme_strripos`](https://php.net/grapheme_strripos): Find position (in grapheme units)\n  of last occurrence of a case-insensitive string\n- [`grapheme_strrpos`](https://php.net/grapheme_strrpos): Find position (in grapheme units)\n  of last occurrence of a string\n- [`grapheme_strstr`](https://php.net/grapheme_strstr): Returns part of haystack string from\n  the first occurrence of needle to the end of haystack\n- [`grapheme_substr`](https://php.net/grapheme_substr): Return part of a string\n\nMore information can be found in the\n[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md).\n\nLicense\n=======\n\nThis library is released under the [MIT license](LICENSE).\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-intl-grapheme/bootstrap.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nuse Symfony\\Polyfill\\Intl\\Grapheme as p;\n\nif (extension_loaded('intl')) {\n    return;\n}\n\nif (\\PHP_VERSION_ID >= 80000) {\n    return require __DIR__.'/bootstrap80.php';\n}\n\nif (!defined('GRAPHEME_EXTR_COUNT')) {\n    define('GRAPHEME_EXTR_COUNT', 0);\n}\nif (!defined('GRAPHEME_EXTR_MAXBYTES')) {\n    define('GRAPHEME_EXTR_MAXBYTES', 1);\n}\nif (!defined('GRAPHEME_EXTR_MAXCHARS')) {\n    define('GRAPHEME_EXTR_MAXCHARS', 2);\n}\n\nif (!function_exists('grapheme_extract')) {\n    function grapheme_extract($haystack, $size, $type = 0, $start = 0, &$next = 0) { return p\\Grapheme::grapheme_extract($haystack, $size, $type, $start, $next); }\n}\nif (!function_exists('grapheme_stripos')) {\n    function grapheme_stripos($haystack, $needle, $offset = 0) { return p\\Grapheme::grapheme_stripos($haystack, $needle, $offset); }\n}\nif (!function_exists('grapheme_stristr')) {\n    function grapheme_stristr($haystack, $needle, $beforeNeedle = false) { return p\\Grapheme::grapheme_stristr($haystack, $needle, $beforeNeedle); }\n}\nif (!function_exists('grapheme_strlen')) {\n    function grapheme_strlen($input) { return p\\Grapheme::grapheme_strlen($input); }\n}\nif (!function_exists('grapheme_strpos')) {\n    function grapheme_strpos($haystack, $needle, $offset = 0) { return p\\Grapheme::grapheme_strpos($haystack, $needle, $offset); }\n}\nif (!function_exists('grapheme_strripos')) {\n    function grapheme_strripos($haystack, $needle, $offset = 0) { return p\\Grapheme::grapheme_strripos($haystack, $needle, $offset); }\n}\nif (!function_exists('grapheme_strrpos')) {\n    function grapheme_strrpos($haystack, $needle, $offset = 0) { return p\\Grapheme::grapheme_strrpos($haystack, $needle, $offset); }\n}\nif (!function_exists('grapheme_strstr')) {\n    function grapheme_strstr($haystack, $needle, $beforeNeedle = false) { return p\\Grapheme::grapheme_strstr($haystack, $needle, $beforeNeedle); }\n}\nif (!function_exists('grapheme_substr')) {\n    function grapheme_substr($string, $offset, $length = null) { return p\\Grapheme::grapheme_substr($string, $offset, $length); }\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-intl-grapheme/bootstrap80.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nuse Symfony\\Polyfill\\Intl\\Grapheme as p;\n\nif (!defined('GRAPHEME_EXTR_COUNT')) {\n    define('GRAPHEME_EXTR_COUNT', 0);\n}\nif (!defined('GRAPHEME_EXTR_MAXBYTES')) {\n    define('GRAPHEME_EXTR_MAXBYTES', 1);\n}\nif (!defined('GRAPHEME_EXTR_MAXCHARS')) {\n    define('GRAPHEME_EXTR_MAXCHARS', 2);\n}\n\nif (!function_exists('grapheme_extract')) {\n    function grapheme_extract(?string $haystack, ?int $size, ?int $type = GRAPHEME_EXTR_COUNT, ?int $offset = 0, &$next = null): string|false { return p\\Grapheme::grapheme_extract((string) $haystack, (int) $size, (int) $type, (int) $offset, $next); }\n}\nif (!function_exists('grapheme_stripos')) {\n    function grapheme_stripos(?string $haystack, ?string $needle, ?int $offset = 0): int|false { return p\\Grapheme::grapheme_stripos((string) $haystack, (string) $needle, (int) $offset); }\n}\nif (!function_exists('grapheme_stristr')) {\n    function grapheme_stristr(?string $haystack, ?string $needle, ?bool $beforeNeedle = false): string|false { return p\\Grapheme::grapheme_stristr((string) $haystack, (string) $needle, (bool) $beforeNeedle); }\n}\nif (!function_exists('grapheme_strlen')) {\n    function grapheme_strlen(?string $string): int|false|null { return p\\Grapheme::grapheme_strlen((string) $string); }\n}\nif (!function_exists('grapheme_strpos')) {\n    function grapheme_strpos(?string $haystack, ?string $needle, ?int $offset = 0): int|false { return p\\Grapheme::grapheme_strpos((string) $haystack, (string) $needle, (int) $offset); }\n}\nif (!function_exists('grapheme_strripos')) {\n    function grapheme_strripos(?string $haystack, ?string $needle, ?int $offset = 0): int|false { return p\\Grapheme::grapheme_strripos((string) $haystack, (string) $needle, (int) $offset); }\n}\nif (!function_exists('grapheme_strrpos')) {\n    function grapheme_strrpos(?string $haystack, ?string $needle, ?int $offset = 0): int|false { return p\\Grapheme::grapheme_strrpos((string) $haystack, (string) $needle, (int) $offset); }\n}\nif (!function_exists('grapheme_strstr')) {\n    function grapheme_strstr(?string $haystack, ?string $needle, ?bool $beforeNeedle = false): string|false { return p\\Grapheme::grapheme_strstr((string) $haystack, (string) $needle, (bool) $beforeNeedle); }\n}\nif (!function_exists('grapheme_substr')) {\n    function grapheme_substr(?string $string, ?int $offset, ?int $length = null): string|false { return p\\Grapheme::grapheme_substr((string) $string, (int) $offset, $length); }\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-intl-grapheme/composer.json",
    "content": "{\n    \"name\": \"symfony/polyfill-intl-grapheme\",\n    \"type\": \"library\",\n    \"description\": \"Symfony polyfill for intl's grapheme_* functions\",\n    \"keywords\": [\"polyfill\", \"shim\", \"compatibility\", \"portable\", \"intl\", \"grapheme\"],\n    \"homepage\": \"https://symfony.com\",\n    \"license\": \"MIT\",\n    \"authors\": [\n        {\n            \"name\": \"Nicolas Grekas\",\n            \"email\": \"p@tchwork.com\"\n        },\n        {\n            \"name\": \"Symfony Community\",\n            \"homepage\": \"https://symfony.com/contributors\"\n        }\n    ],\n    \"require\": {\n        \"php\": \">=7.2\"\n    },\n    \"autoload\": {\n        \"psr-4\": { \"Symfony\\\\Polyfill\\\\Intl\\\\Grapheme\\\\\": \"\" },\n        \"files\": [ \"bootstrap.php\" ]\n    },\n    \"suggest\": {\n        \"ext-intl\": \"For best performance\"\n    },\n    \"minimum-stability\": \"dev\",\n    \"extra\": {\n        \"thanks\": {\n            \"name\": \"symfony/polyfill\",\n            \"url\": \"https://github.com/symfony/polyfill\"\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-intl-idn/Idn.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com> and Trevor Rowbotham <trevor.rowbotham@pm.me>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Polyfill\\Intl\\Idn;\n\nuse Symfony\\Polyfill\\Intl\\Idn\\Resources\\unidata\\DisallowedRanges;\nuse Symfony\\Polyfill\\Intl\\Idn\\Resources\\unidata\\Regex;\n\n/**\n * @see https://www.unicode.org/reports/tr46/\n *\n * @internal\n */\nfinal class Idn\n{\n    public const ERROR_EMPTY_LABEL = 1;\n    public const ERROR_LABEL_TOO_LONG = 2;\n    public const ERROR_DOMAIN_NAME_TOO_LONG = 4;\n    public const ERROR_LEADING_HYPHEN = 8;\n    public const ERROR_TRAILING_HYPHEN = 0x10;\n    public const ERROR_HYPHEN_3_4 = 0x20;\n    public const ERROR_LEADING_COMBINING_MARK = 0x40;\n    public const ERROR_DISALLOWED = 0x80;\n    public const ERROR_PUNYCODE = 0x100;\n    public const ERROR_LABEL_HAS_DOT = 0x200;\n    public const ERROR_INVALID_ACE_LABEL = 0x400;\n    public const ERROR_BIDI = 0x800;\n    public const ERROR_CONTEXTJ = 0x1000;\n    public const ERROR_CONTEXTO_PUNCTUATION = 0x2000;\n    public const ERROR_CONTEXTO_DIGITS = 0x4000;\n\n    public const INTL_IDNA_VARIANT_2003 = 0;\n    public const INTL_IDNA_VARIANT_UTS46 = 1;\n\n    public const IDNA_DEFAULT = 0;\n    public const IDNA_ALLOW_UNASSIGNED = 1;\n    public const IDNA_USE_STD3_RULES = 2;\n    public const IDNA_CHECK_BIDI = 4;\n    public const IDNA_CHECK_CONTEXTJ = 8;\n    public const IDNA_NONTRANSITIONAL_TO_ASCII = 16;\n    public const IDNA_NONTRANSITIONAL_TO_UNICODE = 32;\n\n    public const MAX_DOMAIN_SIZE = 253;\n    public const MAX_LABEL_SIZE = 63;\n\n    public const BASE = 36;\n    public const TMIN = 1;\n    public const TMAX = 26;\n    public const SKEW = 38;\n    public const DAMP = 700;\n    public const INITIAL_BIAS = 72;\n    public const INITIAL_N = 128;\n    public const DELIMITER = '-';\n    public const MAX_INT = 2147483647;\n\n    /**\n     * Contains the numeric value of a basic code point (for use in representing integers) in the\n     * range 0 to BASE-1, or -1 if b is does not represent a value.\n     *\n     * @var array<int, int>\n     */\n    private static $basicToDigit = [\n        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n\n        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n        26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, -1,\n\n        -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,\n        15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,\n\n        -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,\n        15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,\n\n        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n\n        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n\n        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n\n        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n    ];\n\n    /**\n     * @var array<int, int>\n     */\n    private static $virama;\n\n    /**\n     * @var array<int, string>\n     */\n    private static $mapped;\n\n    /**\n     * @var array<int, bool>\n     */\n    private static $ignored;\n\n    /**\n     * @var array<int, string>\n     */\n    private static $deviation;\n\n    /**\n     * @var array<int, bool>\n     */\n    private static $disallowed;\n\n    /**\n     * @var array<int, string>\n     */\n    private static $disallowed_STD3_mapped;\n\n    /**\n     * @var array<int, bool>\n     */\n    private static $disallowed_STD3_valid;\n\n    /**\n     * @var bool\n     */\n    private static $mappingTableLoaded = false;\n\n    /**\n     * @see https://www.unicode.org/reports/tr46/#ToASCII\n     *\n     * @param string $domainName\n     * @param int    $options\n     * @param int    $variant\n     * @param array  $idna_info\n     *\n     * @return string|false\n     */\n    public static function idn_to_ascii($domainName, $options = self::IDNA_DEFAULT, $variant = self::INTL_IDNA_VARIANT_UTS46, &$idna_info = [])\n    {\n        if (\\PHP_VERSION_ID > 80400 && '' === $domainName) {\n            throw new \\ValueError('idn_to_ascii(): Argument #1 ($domain) cannot be empty');\n        }\n\n        if (self::INTL_IDNA_VARIANT_2003 === $variant) {\n            @trigger_error('idn_to_ascii(): INTL_IDNA_VARIANT_2003 is deprecated', \\E_USER_DEPRECATED);\n        }\n\n        $options = [\n            'CheckHyphens' => true,\n            'CheckBidi' => self::INTL_IDNA_VARIANT_2003 === $variant || 0 !== ($options & self::IDNA_CHECK_BIDI),\n            'CheckJoiners' => self::INTL_IDNA_VARIANT_UTS46 === $variant && 0 !== ($options & self::IDNA_CHECK_CONTEXTJ),\n            'UseSTD3ASCIIRules' => 0 !== ($options & self::IDNA_USE_STD3_RULES),\n            'Transitional_Processing' => self::INTL_IDNA_VARIANT_2003 === $variant || 0 === ($options & self::IDNA_NONTRANSITIONAL_TO_ASCII),\n            'VerifyDnsLength' => true,\n        ];\n        $info = new Info();\n        $labels = self::process((string) $domainName, $options, $info);\n\n        foreach ($labels as $i => $label) {\n            // Only convert labels to punycode that contain non-ASCII code points\n            if (1 === preg_match('/[^\\x00-\\x7F]/', $label)) {\n                try {\n                    $label = 'xn--'.self::punycodeEncode($label);\n                } catch (\\Exception $e) {\n                    $info->errors |= self::ERROR_PUNYCODE;\n                }\n\n                $labels[$i] = $label;\n            }\n        }\n\n        if ($options['VerifyDnsLength']) {\n            self::validateDomainAndLabelLength($labels, $info);\n        }\n\n        $idna_info = [\n            'result' => implode('.', $labels),\n            'isTransitionalDifferent' => $info->transitionalDifferent,\n            'errors' => $info->errors,\n        ];\n\n        return 0 === $info->errors ? $idna_info['result'] : false;\n    }\n\n    /**\n     * @see https://www.unicode.org/reports/tr46/#ToUnicode\n     *\n     * @param string $domainName\n     * @param int    $options\n     * @param int    $variant\n     * @param array  $idna_info\n     *\n     * @return string|false\n     */\n    public static function idn_to_utf8($domainName, $options = self::IDNA_DEFAULT, $variant = self::INTL_IDNA_VARIANT_UTS46, &$idna_info = [])\n    {\n        if (\\PHP_VERSION_ID > 80400 && '' === $domainName) {\n            throw new \\ValueError('idn_to_utf8(): Argument #1 ($domain) cannot be empty');\n        }\n\n        if (self::INTL_IDNA_VARIANT_2003 === $variant) {\n            @trigger_error('idn_to_utf8(): INTL_IDNA_VARIANT_2003 is deprecated', \\E_USER_DEPRECATED);\n        }\n\n        $info = new Info();\n        $labels = self::process((string) $domainName, [\n            'CheckHyphens' => true,\n            'CheckBidi' => self::INTL_IDNA_VARIANT_2003 === $variant || 0 !== ($options & self::IDNA_CHECK_BIDI),\n            'CheckJoiners' => self::INTL_IDNA_VARIANT_UTS46 === $variant && 0 !== ($options & self::IDNA_CHECK_CONTEXTJ),\n            'UseSTD3ASCIIRules' => 0 !== ($options & self::IDNA_USE_STD3_RULES),\n            'Transitional_Processing' => self::INTL_IDNA_VARIANT_2003 === $variant || 0 === ($options & self::IDNA_NONTRANSITIONAL_TO_UNICODE),\n        ], $info);\n        $idna_info = [\n            'result' => implode('.', $labels),\n            'isTransitionalDifferent' => $info->transitionalDifferent,\n            'errors' => $info->errors,\n        ];\n\n        return 0 === $info->errors ? $idna_info['result'] : false;\n    }\n\n    /**\n     * @param string $label\n     *\n     * @return bool\n     */\n    private static function isValidContextJ(array $codePoints, $label)\n    {\n        if (!isset(self::$virama)) {\n            self::$virama = require __DIR__.\\DIRECTORY_SEPARATOR.'Resources'.\\DIRECTORY_SEPARATOR.'unidata'.\\DIRECTORY_SEPARATOR.'virama.php';\n        }\n\n        $offset = 0;\n\n        foreach ($codePoints as $i => $codePoint) {\n            if (0x200C !== $codePoint && 0x200D !== $codePoint) {\n                continue;\n            }\n\n            if (!isset($codePoints[$i - 1])) {\n                return false;\n            }\n\n            // If Canonical_Combining_Class(Before(cp)) .eq. Virama Then True;\n            if (isset(self::$virama[$codePoints[$i - 1]])) {\n                continue;\n            }\n\n            // If RegExpMatch((Joining_Type:{L,D})(Joining_Type:T)*\\u200C(Joining_Type:T)*(Joining_Type:{R,D})) Then\n            // True;\n            // Generated RegExp = ([Joining_Type:{L,D}][Joining_Type:T]*\\u200C[Joining_Type:T]*)[Joining_Type:{R,D}]\n            if (0x200C === $codePoint && 1 === preg_match(Regex::ZWNJ, $label, $matches, \\PREG_OFFSET_CAPTURE, $offset)) {\n                $offset += \\strlen($matches[1][0]);\n\n                continue;\n            }\n\n            return false;\n        }\n\n        return true;\n    }\n\n    /**\n     * @see https://www.unicode.org/reports/tr46/#ProcessingStepMap\n     *\n     * @param string              $input\n     * @param array<string, bool> $options\n     *\n     * @return string\n     */\n    private static function mapCodePoints($input, array $options, Info $info)\n    {\n        $str = '';\n        $useSTD3ASCIIRules = $options['UseSTD3ASCIIRules'];\n        $transitional = $options['Transitional_Processing'];\n\n        foreach (self::utf8Decode($input) as $codePoint) {\n            $data = self::lookupCodePointStatus($codePoint, $useSTD3ASCIIRules);\n\n            switch ($data['status']) {\n                case 'disallowed':\n                case 'valid':\n                    $str .= mb_chr($codePoint, 'utf-8');\n\n                    break;\n\n                case 'ignored':\n                    // Do nothing.\n                    break;\n\n                case 'mapped':\n                    $str .= $transitional && 0x1E9E === $codePoint ? 'ss' : $data['mapping'];\n\n                    break;\n\n                case 'deviation':\n                    $info->transitionalDifferent = true;\n                    $str .= ($transitional ? $data['mapping'] : mb_chr($codePoint, 'utf-8'));\n\n                    break;\n            }\n        }\n\n        return $str;\n    }\n\n    /**\n     * @see https://www.unicode.org/reports/tr46/#Processing\n     *\n     * @param string              $domain\n     * @param array<string, bool> $options\n     *\n     * @return array<int, string>\n     */\n    private static function process($domain, array $options, Info $info)\n    {\n        // If VerifyDnsLength is not set, we are doing ToUnicode otherwise we are doing ToASCII and\n        // we need to respect the VerifyDnsLength option.\n        $checkForEmptyLabels = !isset($options['VerifyDnsLength']) || $options['VerifyDnsLength'];\n\n        if ($checkForEmptyLabels && '' === $domain) {\n            $info->errors |= self::ERROR_EMPTY_LABEL;\n\n            return [$domain];\n        }\n\n        // Step 1. Map each code point in the domain name string\n        $domain = self::mapCodePoints($domain, $options, $info);\n\n        // Step 2. Normalize the domain name string to Unicode Normalization Form C.\n        if (!\\Normalizer::isNormalized($domain, \\Normalizer::FORM_C)) {\n            $domain = \\Normalizer::normalize($domain, \\Normalizer::FORM_C);\n        }\n\n        // Step 3. Break the string into labels at U+002E (.) FULL STOP.\n        $labels = explode('.', $domain);\n        $lastLabelIndex = \\count($labels) - 1;\n\n        // Step 4. Convert and validate each label in the domain name string.\n        foreach ($labels as $i => $label) {\n            $validationOptions = $options;\n\n            if ('xn--' === substr($label, 0, 4)) {\n                // Step 4.1. If the label contains any non-ASCII code point (i.e., a code point greater than U+007F),\n                // record that there was an error, and continue with the next label.\n                if (preg_match('/[^\\x00-\\x7F]/', $label)) {\n                    $info->errors |= self::ERROR_PUNYCODE;\n\n                    continue;\n                }\n\n                // Step 4.2. Attempt to convert the rest of the label to Unicode according to Punycode [RFC3492]. If\n                // that conversion fails, record that there was an error, and continue\n                // with the next label. Otherwise replace the original label in the string by the results of the\n                // conversion.\n                try {\n                    $label = self::punycodeDecode(substr($label, 4));\n                } catch (\\Exception $e) {\n                    $info->errors |= self::ERROR_PUNYCODE;\n\n                    continue;\n                }\n\n                $validationOptions['Transitional_Processing'] = false;\n                $labels[$i] = $label;\n            }\n\n            self::validateLabel($label, $info, $validationOptions, $i > 0 && $i === $lastLabelIndex);\n        }\n\n        if ($info->bidiDomain && !$info->validBidiDomain) {\n            $info->errors |= self::ERROR_BIDI;\n        }\n\n        // Any input domain name string that does not record an error has been successfully\n        // processed according to this specification. Conversely, if an input domain_name string\n        // causes an error, then the processing of the input domain_name string fails. Determining\n        // what to do with error input is up to the caller, and not in the scope of this document.\n        return $labels;\n    }\n\n    /**\n     * @see https://tools.ietf.org/html/rfc5893#section-2\n     *\n     * @param string $label\n     */\n    private static function validateBidiLabel($label, Info $info)\n    {\n        if (1 === preg_match(Regex::RTL_LABEL, $label)) {\n            $info->bidiDomain = true;\n\n            // Step 1. The first character must be a character with Bidi property L, R, or AL.\n            // If it has the R or AL property, it is an RTL label\n            if (1 !== preg_match(Regex::BIDI_STEP_1_RTL, $label)) {\n                $info->validBidiDomain = false;\n\n                return;\n            }\n\n            // Step 2. In an RTL label, only characters with the Bidi properties R, AL, AN, EN, ES,\n            // CS, ET, ON, BN, or NSM are allowed.\n            if (1 === preg_match(Regex::BIDI_STEP_2, $label)) {\n                $info->validBidiDomain = false;\n\n                return;\n            }\n\n            // Step 3. In an RTL label, the end of the label must be a character with Bidi property\n            // R, AL, EN, or AN, followed by zero or more characters with Bidi property NSM.\n            if (1 !== preg_match(Regex::BIDI_STEP_3, $label)) {\n                $info->validBidiDomain = false;\n\n                return;\n            }\n\n            // Step 4. In an RTL label, if an EN is present, no AN may be present, and vice versa.\n            if (1 === preg_match(Regex::BIDI_STEP_4_AN, $label) && 1 === preg_match(Regex::BIDI_STEP_4_EN, $label)) {\n                $info->validBidiDomain = false;\n\n                return;\n            }\n\n            return;\n        }\n\n        // We are a LTR label\n        // Step 1. The first character must be a character with Bidi property L, R, or AL.\n        // If it has the L property, it is an LTR label.\n        if (1 !== preg_match(Regex::BIDI_STEP_1_LTR, $label)) {\n            $info->validBidiDomain = false;\n\n            return;\n        }\n\n        // Step 5. In an LTR label, only characters with the Bidi properties L, EN,\n        // ES, CS, ET, ON, BN, or NSM are allowed.\n        if (1 === preg_match(Regex::BIDI_STEP_5, $label)) {\n            $info->validBidiDomain = false;\n\n            return;\n        }\n\n        // Step 6.In an LTR label, the end of the label must be a character with Bidi property L or\n        // EN, followed by zero or more characters with Bidi property NSM.\n        if (1 !== preg_match(Regex::BIDI_STEP_6, $label)) {\n            $info->validBidiDomain = false;\n\n            return;\n        }\n    }\n\n    /**\n     * @param array<int, string> $labels\n     */\n    private static function validateDomainAndLabelLength(array $labels, Info $info)\n    {\n        $maxDomainSize = self::MAX_DOMAIN_SIZE;\n        $length = \\count($labels);\n\n        // Number of \".\" delimiters.\n        $domainLength = $length - 1;\n\n        // If the last label is empty and it is not the first label, then it is the root label.\n        // Increase the max size by 1, making it 254, to account for the root label's \".\"\n        // delimiter. This also means we don't need to check the last label's length for being too\n        // long.\n        if ($length > 1 && '' === $labels[$length - 1]) {\n            ++$maxDomainSize;\n            --$length;\n        }\n\n        for ($i = 0; $i < $length; ++$i) {\n            $bytes = \\strlen($labels[$i]);\n            $domainLength += $bytes;\n\n            if ($bytes > self::MAX_LABEL_SIZE) {\n                $info->errors |= self::ERROR_LABEL_TOO_LONG;\n            }\n        }\n\n        if ($domainLength > $maxDomainSize) {\n            $info->errors |= self::ERROR_DOMAIN_NAME_TOO_LONG;\n        }\n    }\n\n    /**\n     * @see https://www.unicode.org/reports/tr46/#Validity_Criteria\n     *\n     * @param string              $label\n     * @param array<string, bool> $options\n     * @param bool                $canBeEmpty\n     */\n    private static function validateLabel($label, Info $info, array $options, $canBeEmpty)\n    {\n        if ('' === $label) {\n            if (!$canBeEmpty && (!isset($options['VerifyDnsLength']) || $options['VerifyDnsLength'])) {\n                $info->errors |= self::ERROR_EMPTY_LABEL;\n            }\n\n            return;\n        }\n\n        // Step 1. The label must be in Unicode Normalization Form C.\n        if (!\\Normalizer::isNormalized($label, \\Normalizer::FORM_C)) {\n            $info->errors |= self::ERROR_INVALID_ACE_LABEL;\n        }\n\n        $codePoints = self::utf8Decode($label);\n\n        if ($options['CheckHyphens']) {\n            // Step 2. If CheckHyphens, the label must not contain a U+002D HYPHEN-MINUS character\n            // in both the thrid and fourth positions.\n            if (isset($codePoints[2], $codePoints[3]) && 0x002D === $codePoints[2] && 0x002D === $codePoints[3]) {\n                $info->errors |= self::ERROR_HYPHEN_3_4;\n            }\n\n            // Step 3. If CheckHyphens, the label must neither begin nor end with a U+002D\n            // HYPHEN-MINUS character.\n            if ('-' === substr($label, 0, 1)) {\n                $info->errors |= self::ERROR_LEADING_HYPHEN;\n            }\n\n            if ('-' === substr($label, -1, 1)) {\n                $info->errors |= self::ERROR_TRAILING_HYPHEN;\n            }\n        } elseif ('xn--' === substr($label, 0, 4)) {\n            $info->errors |= self::ERROR_PUNYCODE;\n        }\n\n        // Step 4. The label must not contain a U+002E (.) FULL STOP.\n        if (false !== strpos($label, '.')) {\n            $info->errors |= self::ERROR_LABEL_HAS_DOT;\n        }\n\n        // Step 5. The label must not begin with a combining mark, that is: General_Category=Mark.\n        if (1 === preg_match(Regex::COMBINING_MARK, $label)) {\n            $info->errors |= self::ERROR_LEADING_COMBINING_MARK;\n        }\n\n        // Step 6. Each code point in the label must only have certain status values according to\n        // Section 5, IDNA Mapping Table:\n        $transitional = $options['Transitional_Processing'];\n        $useSTD3ASCIIRules = $options['UseSTD3ASCIIRules'];\n\n        foreach ($codePoints as $codePoint) {\n            $data = self::lookupCodePointStatus($codePoint, $useSTD3ASCIIRules);\n            $status = $data['status'];\n\n            if ('valid' === $status || (!$transitional && 'deviation' === $status)) {\n                continue;\n            }\n\n            $info->errors |= self::ERROR_DISALLOWED;\n\n            break;\n        }\n\n        // Step 7. If CheckJoiners, the label must satisify the ContextJ rules from Appendix A, in\n        // The Unicode Code Points and Internationalized Domain Names for Applications (IDNA)\n        // [IDNA2008].\n        if ($options['CheckJoiners'] && !self::isValidContextJ($codePoints, $label)) {\n            $info->errors |= self::ERROR_CONTEXTJ;\n        }\n\n        // Step 8. If CheckBidi, and if the domain name is a  Bidi domain name, then the label must\n        // satisfy all six of the numbered conditions in [IDNA2008] RFC 5893, Section 2.\n        if ($options['CheckBidi'] && (!$info->bidiDomain || $info->validBidiDomain)) {\n            self::validateBidiLabel($label, $info);\n        }\n    }\n\n    /**\n     * @see https://tools.ietf.org/html/rfc3492#section-6.2\n     *\n     * @param string $input\n     *\n     * @return string\n     */\n    private static function punycodeDecode($input)\n    {\n        $n = self::INITIAL_N;\n        $out = 0;\n        $i = 0;\n        $bias = self::INITIAL_BIAS;\n        $lastDelimIndex = strrpos($input, self::DELIMITER);\n        $b = false === $lastDelimIndex ? 0 : $lastDelimIndex;\n        $inputLength = \\strlen($input);\n        $output = [];\n        $bytes = array_map('ord', str_split($input));\n\n        for ($j = 0; $j < $b; ++$j) {\n            if ($bytes[$j] > 0x7F) {\n                throw new \\Exception('Invalid input');\n            }\n\n            $output[$out++] = $input[$j];\n        }\n\n        if ($b > 0) {\n            ++$b;\n        }\n\n        for ($in = $b; $in < $inputLength; ++$out) {\n            $oldi = $i;\n            $w = 1;\n\n            for ($k = self::BASE; /* no condition */; $k += self::BASE) {\n                if ($in >= $inputLength) {\n                    throw new \\Exception('Invalid input');\n                }\n\n                $digit = self::$basicToDigit[$bytes[$in++] & 0xFF];\n\n                if ($digit < 0) {\n                    throw new \\Exception('Invalid input');\n                }\n\n                if ($digit > intdiv(self::MAX_INT - $i, $w)) {\n                    throw new \\Exception('Integer overflow');\n                }\n\n                $i += $digit * $w;\n\n                if ($k <= $bias) {\n                    $t = self::TMIN;\n                } elseif ($k >= $bias + self::TMAX) {\n                    $t = self::TMAX;\n                } else {\n                    $t = $k - $bias;\n                }\n\n                if ($digit < $t) {\n                    break;\n                }\n\n                $baseMinusT = self::BASE - $t;\n\n                if ($w > intdiv(self::MAX_INT, $baseMinusT)) {\n                    throw new \\Exception('Integer overflow');\n                }\n\n                $w *= $baseMinusT;\n            }\n\n            $outPlusOne = $out + 1;\n            $bias = self::adaptBias($i - $oldi, $outPlusOne, 0 === $oldi);\n\n            if (intdiv($i, $outPlusOne) > self::MAX_INT - $n) {\n                throw new \\Exception('Integer overflow');\n            }\n\n            $n += intdiv($i, $outPlusOne);\n            $i %= $outPlusOne;\n            array_splice($output, $i++, 0, [mb_chr($n, 'utf-8')]);\n        }\n\n        return implode('', $output);\n    }\n\n    /**\n     * @see https://tools.ietf.org/html/rfc3492#section-6.3\n     *\n     * @param string $input\n     *\n     * @return string\n     */\n    private static function punycodeEncode($input)\n    {\n        $n = self::INITIAL_N;\n        $delta = 0;\n        $out = 0;\n        $bias = self::INITIAL_BIAS;\n        $inputLength = 0;\n        $output = '';\n        $iter = self::utf8Decode($input);\n\n        foreach ($iter as $codePoint) {\n            ++$inputLength;\n\n            if ($codePoint < 0x80) {\n                $output .= \\chr($codePoint);\n                ++$out;\n            }\n        }\n\n        $h = $out;\n        $b = $out;\n\n        if ($b > 0) {\n            $output .= self::DELIMITER;\n            ++$out;\n        }\n\n        while ($h < $inputLength) {\n            $m = self::MAX_INT;\n\n            foreach ($iter as $codePoint) {\n                if ($codePoint >= $n && $codePoint < $m) {\n                    $m = $codePoint;\n                }\n            }\n\n            if ($m - $n > intdiv(self::MAX_INT - $delta, $h + 1)) {\n                throw new \\Exception('Integer overflow');\n            }\n\n            $delta += ($m - $n) * ($h + 1);\n            $n = $m;\n\n            foreach ($iter as $codePoint) {\n                if ($codePoint < $n && 0 === ++$delta) {\n                    throw new \\Exception('Integer overflow');\n                }\n\n                if ($codePoint === $n) {\n                    $q = $delta;\n\n                    for ($k = self::BASE; /* no condition */; $k += self::BASE) {\n                        if ($k <= $bias) {\n                            $t = self::TMIN;\n                        } elseif ($k >= $bias + self::TMAX) {\n                            $t = self::TMAX;\n                        } else {\n                            $t = $k - $bias;\n                        }\n\n                        if ($q < $t) {\n                            break;\n                        }\n\n                        $qMinusT = $q - $t;\n                        $baseMinusT = self::BASE - $t;\n                        $output .= self::encodeDigit($t + $qMinusT % $baseMinusT, false);\n                        ++$out;\n                        $q = intdiv($qMinusT, $baseMinusT);\n                    }\n\n                    $output .= self::encodeDigit($q, false);\n                    ++$out;\n                    $bias = self::adaptBias($delta, $h + 1, $h === $b);\n                    $delta = 0;\n                    ++$h;\n                }\n            }\n\n            ++$delta;\n            ++$n;\n        }\n\n        return $output;\n    }\n\n    /**\n     * @see https://tools.ietf.org/html/rfc3492#section-6.1\n     *\n     * @param int  $delta\n     * @param int  $numPoints\n     * @param bool $firstTime\n     *\n     * @return int\n     */\n    private static function adaptBias($delta, $numPoints, $firstTime)\n    {\n        // xxx >> 1 is a faster way of doing intdiv(xxx, 2)\n        $delta = $firstTime ? intdiv($delta, self::DAMP) : $delta >> 1;\n        $delta += intdiv($delta, $numPoints);\n        $k = 0;\n\n        while ($delta > ((self::BASE - self::TMIN) * self::TMAX) >> 1) {\n            $delta = intdiv($delta, self::BASE - self::TMIN);\n            $k += self::BASE;\n        }\n\n        return $k + intdiv((self::BASE - self::TMIN + 1) * $delta, $delta + self::SKEW);\n    }\n\n    /**\n     * @param int  $d\n     * @param bool $flag\n     *\n     * @return string\n     */\n    private static function encodeDigit($d, $flag)\n    {\n        return \\chr($d + 22 + 75 * ($d < 26 ? 1 : 0) - (($flag ? 1 : 0) << 5));\n    }\n\n    /**\n     * Takes a UTF-8 encoded string and converts it into a series of integer code points. Any\n     * invalid byte sequences will be replaced by a U+FFFD replacement code point.\n     *\n     * @see https://encoding.spec.whatwg.org/#utf-8-decoder\n     *\n     * @param string $input\n     *\n     * @return array<int, int>\n     */\n    private static function utf8Decode($input)\n    {\n        $bytesSeen = 0;\n        $bytesNeeded = 0;\n        $lowerBoundary = 0x80;\n        $upperBoundary = 0xBF;\n        $codePoint = 0;\n        $codePoints = [];\n        $length = \\strlen($input);\n\n        for ($i = 0; $i < $length; ++$i) {\n            $byte = \\ord($input[$i]);\n\n            if (0 === $bytesNeeded) {\n                if ($byte >= 0x00 && $byte <= 0x7F) {\n                    $codePoints[] = $byte;\n\n                    continue;\n                }\n\n                if ($byte >= 0xC2 && $byte <= 0xDF) {\n                    $bytesNeeded = 1;\n                    $codePoint = $byte & 0x1F;\n                } elseif ($byte >= 0xE0 && $byte <= 0xEF) {\n                    if (0xE0 === $byte) {\n                        $lowerBoundary = 0xA0;\n                    } elseif (0xED === $byte) {\n                        $upperBoundary = 0x9F;\n                    }\n\n                    $bytesNeeded = 2;\n                    $codePoint = $byte & 0xF;\n                } elseif ($byte >= 0xF0 && $byte <= 0xF4) {\n                    if (0xF0 === $byte) {\n                        $lowerBoundary = 0x90;\n                    } elseif (0xF4 === $byte) {\n                        $upperBoundary = 0x8F;\n                    }\n\n                    $bytesNeeded = 3;\n                    $codePoint = $byte & 0x7;\n                } else {\n                    $codePoints[] = 0xFFFD;\n                }\n\n                continue;\n            }\n\n            if ($byte < $lowerBoundary || $byte > $upperBoundary) {\n                $codePoint = 0;\n                $bytesNeeded = 0;\n                $bytesSeen = 0;\n                $lowerBoundary = 0x80;\n                $upperBoundary = 0xBF;\n                --$i;\n                $codePoints[] = 0xFFFD;\n\n                continue;\n            }\n\n            $lowerBoundary = 0x80;\n            $upperBoundary = 0xBF;\n            $codePoint = ($codePoint << 6) | ($byte & 0x3F);\n\n            if (++$bytesSeen !== $bytesNeeded) {\n                continue;\n            }\n\n            $codePoints[] = $codePoint;\n            $codePoint = 0;\n            $bytesNeeded = 0;\n            $bytesSeen = 0;\n        }\n\n        // String unexpectedly ended, so append a U+FFFD code point.\n        if (0 !== $bytesNeeded) {\n            $codePoints[] = 0xFFFD;\n        }\n\n        return $codePoints;\n    }\n\n    /**\n     * @param int  $codePoint\n     * @param bool $useSTD3ASCIIRules\n     *\n     * @return array{status: string, mapping?: string}\n     */\n    private static function lookupCodePointStatus($codePoint, $useSTD3ASCIIRules)\n    {\n        if (!self::$mappingTableLoaded) {\n            self::$mappingTableLoaded = true;\n            self::$mapped = require __DIR__.'/Resources/unidata/mapped.php';\n            self::$ignored = require __DIR__.'/Resources/unidata/ignored.php';\n            self::$deviation = require __DIR__.'/Resources/unidata/deviation.php';\n            self::$disallowed = require __DIR__.'/Resources/unidata/disallowed.php';\n            self::$disallowed_STD3_mapped = require __DIR__.'/Resources/unidata/disallowed_STD3_mapped.php';\n            self::$disallowed_STD3_valid = require __DIR__.'/Resources/unidata/disallowed_STD3_valid.php';\n        }\n\n        if (isset(self::$mapped[$codePoint])) {\n            return ['status' => 'mapped', 'mapping' => self::$mapped[$codePoint]];\n        }\n\n        if (isset(self::$ignored[$codePoint])) {\n            return ['status' => 'ignored'];\n        }\n\n        if (isset(self::$deviation[$codePoint])) {\n            return ['status' => 'deviation', 'mapping' => self::$deviation[$codePoint]];\n        }\n\n        if (isset(self::$disallowed[$codePoint]) || DisallowedRanges::inRange($codePoint)) {\n            return ['status' => 'disallowed'];\n        }\n\n        $isDisallowedMapped = isset(self::$disallowed_STD3_mapped[$codePoint]);\n\n        if ($isDisallowedMapped || isset(self::$disallowed_STD3_valid[$codePoint])) {\n            $status = 'disallowed';\n\n            if (!$useSTD3ASCIIRules) {\n                $status = $isDisallowedMapped ? 'mapped' : 'valid';\n            }\n\n            if ($isDisallowedMapped) {\n                return ['status' => $status, 'mapping' => self::$disallowed_STD3_mapped[$codePoint]];\n            }\n\n            return ['status' => $status];\n        }\n\n        return ['status' => 'valid'];\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-intl-idn/Info.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com> and Trevor Rowbotham <trevor.rowbotham@pm.me>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Polyfill\\Intl\\Idn;\n\n/**\n * @internal\n */\nclass Info\n{\n    public $bidiDomain = false;\n    public $errors = 0;\n    public $validBidiDomain = true;\n    public $transitionalDifferent = false;\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-intl-idn/LICENSE",
    "content": "Copyright (c) 2018-present Fabien Potencier and Trevor Rowbotham <trevor.rowbotham@pm.me>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is furnished\nto do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-intl-idn/README.md",
    "content": "Symfony Polyfill / Intl: Idn\n============================\n\nThis component provides [`idn_to_ascii`](https://php.net/idn-to-ascii) and [`idn_to_utf8`](https://php.net/idn-to-utf8) functions to users who run php versions without the [Intl](https://php.net/intl) extension.\n\nMore information can be found in the\n[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md).\n\nLicense\n=======\n\nThis library is released under the [MIT license](LICENSE).\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-intl-idn/Resources/unidata/DisallowedRanges.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Polyfill\\Intl\\Idn\\Resources\\unidata;\n\n/**\n * @internal\n */\nfinal class DisallowedRanges\n{\n    /**\n     * @param int $codePoint\n     *\n     * @return bool\n     */\n    public static function inRange($codePoint)\n    {\n        if ($codePoint >= 128 && $codePoint <= 159) {\n            return true;\n        }\n\n        if ($codePoint >= 2155 && $codePoint <= 2207) {\n            return true;\n        }\n\n        if ($codePoint >= 3676 && $codePoint <= 3712) {\n            return true;\n        }\n\n        if ($codePoint >= 3808 && $codePoint <= 3839) {\n            return true;\n        }\n\n        if ($codePoint >= 4059 && $codePoint <= 4095) {\n            return true;\n        }\n\n        if ($codePoint >= 4256 && $codePoint <= 4293) {\n            return true;\n        }\n\n        if ($codePoint >= 6849 && $codePoint <= 6911) {\n            return true;\n        }\n\n        if ($codePoint >= 11859 && $codePoint <= 11903) {\n            return true;\n        }\n\n        if ($codePoint >= 42955 && $codePoint <= 42996) {\n            return true;\n        }\n\n        if ($codePoint >= 55296 && $codePoint <= 57343) {\n            return true;\n        }\n\n        if ($codePoint >= 57344 && $codePoint <= 63743) {\n            return true;\n        }\n\n        if ($codePoint >= 64218 && $codePoint <= 64255) {\n            return true;\n        }\n\n        if ($codePoint >= 64976 && $codePoint <= 65007) {\n            return true;\n        }\n\n        if ($codePoint >= 65630 && $codePoint <= 65663) {\n            return true;\n        }\n\n        if ($codePoint >= 65953 && $codePoint <= 65999) {\n            return true;\n        }\n\n        if ($codePoint >= 66046 && $codePoint <= 66175) {\n            return true;\n        }\n\n        if ($codePoint >= 66518 && $codePoint <= 66559) {\n            return true;\n        }\n\n        if ($codePoint >= 66928 && $codePoint <= 67071) {\n            return true;\n        }\n\n        if ($codePoint >= 67432 && $codePoint <= 67583) {\n            return true;\n        }\n\n        if ($codePoint >= 67760 && $codePoint <= 67807) {\n            return true;\n        }\n\n        if ($codePoint >= 67904 && $codePoint <= 67967) {\n            return true;\n        }\n\n        if ($codePoint >= 68256 && $codePoint <= 68287) {\n            return true;\n        }\n\n        if ($codePoint >= 68528 && $codePoint <= 68607) {\n            return true;\n        }\n\n        if ($codePoint >= 68681 && $codePoint <= 68735) {\n            return true;\n        }\n\n        if ($codePoint >= 68922 && $codePoint <= 69215) {\n            return true;\n        }\n\n        if ($codePoint >= 69298 && $codePoint <= 69375) {\n            return true;\n        }\n\n        if ($codePoint >= 69466 && $codePoint <= 69551) {\n            return true;\n        }\n\n        if ($codePoint >= 70207 && $codePoint <= 70271) {\n            return true;\n        }\n\n        if ($codePoint >= 70517 && $codePoint <= 70655) {\n            return true;\n        }\n\n        if ($codePoint >= 70874 && $codePoint <= 71039) {\n            return true;\n        }\n\n        if ($codePoint >= 71134 && $codePoint <= 71167) {\n            return true;\n        }\n\n        if ($codePoint >= 71370 && $codePoint <= 71423) {\n            return true;\n        }\n\n        if ($codePoint >= 71488 && $codePoint <= 71679) {\n            return true;\n        }\n\n        if ($codePoint >= 71740 && $codePoint <= 71839) {\n            return true;\n        }\n\n        if ($codePoint >= 72026 && $codePoint <= 72095) {\n            return true;\n        }\n\n        if ($codePoint >= 72441 && $codePoint <= 72703) {\n            return true;\n        }\n\n        if ($codePoint >= 72887 && $codePoint <= 72959) {\n            return true;\n        }\n\n        if ($codePoint >= 73130 && $codePoint <= 73439) {\n            return true;\n        }\n\n        if ($codePoint >= 73465 && $codePoint <= 73647) {\n            return true;\n        }\n\n        if ($codePoint >= 74650 && $codePoint <= 74751) {\n            return true;\n        }\n\n        if ($codePoint >= 75076 && $codePoint <= 77823) {\n            return true;\n        }\n\n        if ($codePoint >= 78905 && $codePoint <= 82943) {\n            return true;\n        }\n\n        if ($codePoint >= 83527 && $codePoint <= 92159) {\n            return true;\n        }\n\n        if ($codePoint >= 92784 && $codePoint <= 92879) {\n            return true;\n        }\n\n        if ($codePoint >= 93072 && $codePoint <= 93759) {\n            return true;\n        }\n\n        if ($codePoint >= 93851 && $codePoint <= 93951) {\n            return true;\n        }\n\n        if ($codePoint >= 94112 && $codePoint <= 94175) {\n            return true;\n        }\n\n        if ($codePoint >= 101590 && $codePoint <= 101631) {\n            return true;\n        }\n\n        if ($codePoint >= 101641 && $codePoint <= 110591) {\n            return true;\n        }\n\n        if ($codePoint >= 110879 && $codePoint <= 110927) {\n            return true;\n        }\n\n        if ($codePoint >= 111356 && $codePoint <= 113663) {\n            return true;\n        }\n\n        if ($codePoint >= 113828 && $codePoint <= 118783) {\n            return true;\n        }\n\n        if ($codePoint >= 119366 && $codePoint <= 119519) {\n            return true;\n        }\n\n        if ($codePoint >= 119673 && $codePoint <= 119807) {\n            return true;\n        }\n\n        if ($codePoint >= 121520 && $codePoint <= 122879) {\n            return true;\n        }\n\n        if ($codePoint >= 122923 && $codePoint <= 123135) {\n            return true;\n        }\n\n        if ($codePoint >= 123216 && $codePoint <= 123583) {\n            return true;\n        }\n\n        if ($codePoint >= 123648 && $codePoint <= 124927) {\n            return true;\n        }\n\n        if ($codePoint >= 125143 && $codePoint <= 125183) {\n            return true;\n        }\n\n        if ($codePoint >= 125280 && $codePoint <= 126064) {\n            return true;\n        }\n\n        if ($codePoint >= 126133 && $codePoint <= 126208) {\n            return true;\n        }\n\n        if ($codePoint >= 126270 && $codePoint <= 126463) {\n            return true;\n        }\n\n        if ($codePoint >= 126652 && $codePoint <= 126703) {\n            return true;\n        }\n\n        if ($codePoint >= 126706 && $codePoint <= 126975) {\n            return true;\n        }\n\n        if ($codePoint >= 127406 && $codePoint <= 127461) {\n            return true;\n        }\n\n        if ($codePoint >= 127590 && $codePoint <= 127743) {\n            return true;\n        }\n\n        if ($codePoint >= 129202 && $codePoint <= 129279) {\n            return true;\n        }\n\n        if ($codePoint >= 129751 && $codePoint <= 129791) {\n            return true;\n        }\n\n        if ($codePoint >= 129995 && $codePoint <= 130031) {\n            return true;\n        }\n\n        if ($codePoint >= 130042 && $codePoint <= 131069) {\n            return true;\n        }\n\n        if ($codePoint >= 173790 && $codePoint <= 173823) {\n            return true;\n        }\n\n        if ($codePoint >= 191457 && $codePoint <= 194559) {\n            return true;\n        }\n\n        if ($codePoint >= 195102 && $codePoint <= 196605) {\n            return true;\n        }\n\n        if ($codePoint >= 201547 && $codePoint <= 262141) {\n            return true;\n        }\n\n        if ($codePoint >= 262144 && $codePoint <= 327677) {\n            return true;\n        }\n\n        if ($codePoint >= 327680 && $codePoint <= 393213) {\n            return true;\n        }\n\n        if ($codePoint >= 393216 && $codePoint <= 458749) {\n            return true;\n        }\n\n        if ($codePoint >= 458752 && $codePoint <= 524285) {\n            return true;\n        }\n\n        if ($codePoint >= 524288 && $codePoint <= 589821) {\n            return true;\n        }\n\n        if ($codePoint >= 589824 && $codePoint <= 655357) {\n            return true;\n        }\n\n        if ($codePoint >= 655360 && $codePoint <= 720893) {\n            return true;\n        }\n\n        if ($codePoint >= 720896 && $codePoint <= 786429) {\n            return true;\n        }\n\n        if ($codePoint >= 786432 && $codePoint <= 851965) {\n            return true;\n        }\n\n        if ($codePoint >= 851968 && $codePoint <= 917501) {\n            return true;\n        }\n\n        if ($codePoint >= 917536 && $codePoint <= 917631) {\n            return true;\n        }\n\n        if ($codePoint >= 917632 && $codePoint <= 917759) {\n            return true;\n        }\n\n        if ($codePoint >= 918000 && $codePoint <= 983037) {\n            return true;\n        }\n\n        if ($codePoint >= 983040 && $codePoint <= 1048573) {\n            return true;\n        }\n\n        if ($codePoint >= 1048576 && $codePoint <= 1114109) {\n            return true;\n        }\n\n        return false;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-intl-idn/Resources/unidata/Regex.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Polyfill\\Intl\\Idn\\Resources\\unidata;\n\n/**\n * @internal\n */\nfinal class Regex\n{\n    const COMBINING_MARK = '/^[\\x{0300}-\\x{036F}\\x{0483}-\\x{0487}\\x{0488}-\\x{0489}\\x{0591}-\\x{05BD}\\x{05BF}\\x{05C1}-\\x{05C2}\\x{05C4}-\\x{05C5}\\x{05C7}\\x{0610}-\\x{061A}\\x{064B}-\\x{065F}\\x{0670}\\x{06D6}-\\x{06DC}\\x{06DF}-\\x{06E4}\\x{06E7}-\\x{06E8}\\x{06EA}-\\x{06ED}\\x{0711}\\x{0730}-\\x{074A}\\x{07A6}-\\x{07B0}\\x{07EB}-\\x{07F3}\\x{07FD}\\x{0816}-\\x{0819}\\x{081B}-\\x{0823}\\x{0825}-\\x{0827}\\x{0829}-\\x{082D}\\x{0859}-\\x{085B}\\x{08D3}-\\x{08E1}\\x{08E3}-\\x{0902}\\x{0903}\\x{093A}\\x{093B}\\x{093C}\\x{093E}-\\x{0940}\\x{0941}-\\x{0948}\\x{0949}-\\x{094C}\\x{094D}\\x{094E}-\\x{094F}\\x{0951}-\\x{0957}\\x{0962}-\\x{0963}\\x{0981}\\x{0982}-\\x{0983}\\x{09BC}\\x{09BE}-\\x{09C0}\\x{09C1}-\\x{09C4}\\x{09C7}-\\x{09C8}\\x{09CB}-\\x{09CC}\\x{09CD}\\x{09D7}\\x{09E2}-\\x{09E3}\\x{09FE}\\x{0A01}-\\x{0A02}\\x{0A03}\\x{0A3C}\\x{0A3E}-\\x{0A40}\\x{0A41}-\\x{0A42}\\x{0A47}-\\x{0A48}\\x{0A4B}-\\x{0A4D}\\x{0A51}\\x{0A70}-\\x{0A71}\\x{0A75}\\x{0A81}-\\x{0A82}\\x{0A83}\\x{0ABC}\\x{0ABE}-\\x{0AC0}\\x{0AC1}-\\x{0AC5}\\x{0AC7}-\\x{0AC8}\\x{0AC9}\\x{0ACB}-\\x{0ACC}\\x{0ACD}\\x{0AE2}-\\x{0AE3}\\x{0AFA}-\\x{0AFF}\\x{0B01}\\x{0B02}-\\x{0B03}\\x{0B3C}\\x{0B3E}\\x{0B3F}\\x{0B40}\\x{0B41}-\\x{0B44}\\x{0B47}-\\x{0B48}\\x{0B4B}-\\x{0B4C}\\x{0B4D}\\x{0B55}-\\x{0B56}\\x{0B57}\\x{0B62}-\\x{0B63}\\x{0B82}\\x{0BBE}-\\x{0BBF}\\x{0BC0}\\x{0BC1}-\\x{0BC2}\\x{0BC6}-\\x{0BC8}\\x{0BCA}-\\x{0BCC}\\x{0BCD}\\x{0BD7}\\x{0C00}\\x{0C01}-\\x{0C03}\\x{0C04}\\x{0C3E}-\\x{0C40}\\x{0C41}-\\x{0C44}\\x{0C46}-\\x{0C48}\\x{0C4A}-\\x{0C4D}\\x{0C55}-\\x{0C56}\\x{0C62}-\\x{0C63}\\x{0C81}\\x{0C82}-\\x{0C83}\\x{0CBC}\\x{0CBE}\\x{0CBF}\\x{0CC0}-\\x{0CC4}\\x{0CC6}\\x{0CC7}-\\x{0CC8}\\x{0CCA}-\\x{0CCB}\\x{0CCC}-\\x{0CCD}\\x{0CD5}-\\x{0CD6}\\x{0CE2}-\\x{0CE3}\\x{0D00}-\\x{0D01}\\x{0D02}-\\x{0D03}\\x{0D3B}-\\x{0D3C}\\x{0D3E}-\\x{0D40}\\x{0D41}-\\x{0D44}\\x{0D46}-\\x{0D48}\\x{0D4A}-\\x{0D4C}\\x{0D4D}\\x{0D57}\\x{0D62}-\\x{0D63}\\x{0D81}\\x{0D82}-\\x{0D83}\\x{0DCA}\\x{0DCF}-\\x{0DD1}\\x{0DD2}-\\x{0DD4}\\x{0DD6}\\x{0DD8}-\\x{0DDF}\\x{0DF2}-\\x{0DF3}\\x{0E31}\\x{0E34}-\\x{0E3A}\\x{0E47}-\\x{0E4E}\\x{0EB1}\\x{0EB4}-\\x{0EBC}\\x{0EC8}-\\x{0ECD}\\x{0F18}-\\x{0F19}\\x{0F35}\\x{0F37}\\x{0F39}\\x{0F3E}-\\x{0F3F}\\x{0F71}-\\x{0F7E}\\x{0F7F}\\x{0F80}-\\x{0F84}\\x{0F86}-\\x{0F87}\\x{0F8D}-\\x{0F97}\\x{0F99}-\\x{0FBC}\\x{0FC6}\\x{102B}-\\x{102C}\\x{102D}-\\x{1030}\\x{1031}\\x{1032}-\\x{1037}\\x{1038}\\x{1039}-\\x{103A}\\x{103B}-\\x{103C}\\x{103D}-\\x{103E}\\x{1056}-\\x{1057}\\x{1058}-\\x{1059}\\x{105E}-\\x{1060}\\x{1062}-\\x{1064}\\x{1067}-\\x{106D}\\x{1071}-\\x{1074}\\x{1082}\\x{1083}-\\x{1084}\\x{1085}-\\x{1086}\\x{1087}-\\x{108C}\\x{108D}\\x{108F}\\x{109A}-\\x{109C}\\x{109D}\\x{135D}-\\x{135F}\\x{1712}-\\x{1714}\\x{1732}-\\x{1734}\\x{1752}-\\x{1753}\\x{1772}-\\x{1773}\\x{17B4}-\\x{17B5}\\x{17B6}\\x{17B7}-\\x{17BD}\\x{17BE}-\\x{17C5}\\x{17C6}\\x{17C7}-\\x{17C8}\\x{17C9}-\\x{17D3}\\x{17DD}\\x{180B}-\\x{180D}\\x{1885}-\\x{1886}\\x{18A9}\\x{1920}-\\x{1922}\\x{1923}-\\x{1926}\\x{1927}-\\x{1928}\\x{1929}-\\x{192B}\\x{1930}-\\x{1931}\\x{1932}\\x{1933}-\\x{1938}\\x{1939}-\\x{193B}\\x{1A17}-\\x{1A18}\\x{1A19}-\\x{1A1A}\\x{1A1B}\\x{1A55}\\x{1A56}\\x{1A57}\\x{1A58}-\\x{1A5E}\\x{1A60}\\x{1A61}\\x{1A62}\\x{1A63}-\\x{1A64}\\x{1A65}-\\x{1A6C}\\x{1A6D}-\\x{1A72}\\x{1A73}-\\x{1A7C}\\x{1A7F}\\x{1AB0}-\\x{1ABD}\\x{1ABE}\\x{1ABF}-\\x{1AC0}\\x{1B00}-\\x{1B03}\\x{1B04}\\x{1B34}\\x{1B35}\\x{1B36}-\\x{1B3A}\\x{1B3B}\\x{1B3C}\\x{1B3D}-\\x{1B41}\\x{1B42}\\x{1B43}-\\x{1B44}\\x{1B6B}-\\x{1B73}\\x{1B80}-\\x{1B81}\\x{1B82}\\x{1BA1}\\x{1BA2}-\\x{1BA5}\\x{1BA6}-\\x{1BA7}\\x{1BA8}-\\x{1BA9}\\x{1BAA}\\x{1BAB}-\\x{1BAD}\\x{1BE6}\\x{1BE7}\\x{1BE8}-\\x{1BE9}\\x{1BEA}-\\x{1BEC}\\x{1BED}\\x{1BEE}\\x{1BEF}-\\x{1BF1}\\x{1BF2}-\\x{1BF3}\\x{1C24}-\\x{1C2B}\\x{1C2C}-\\x{1C33}\\x{1C34}-\\x{1C35}\\x{1C36}-\\x{1C37}\\x{1CD0}-\\x{1CD2}\\x{1CD4}-\\x{1CE0}\\x{1CE1}\\x{1CE2}-\\x{1CE8}\\x{1CED}\\x{1CF4}\\x{1CF7}\\x{1CF8}-\\x{1CF9}\\x{1DC0}-\\x{1DF9}\\x{1DFB}-\\x{1DFF}\\x{20D0}-\\x{20DC}\\x{20DD}-\\x{20E0}\\x{20E1}\\x{20E2}-\\x{20E4}\\x{20E5}-\\x{20F0}\\x{2CEF}-\\x{2CF1}\\x{2D7F}\\x{2DE0}-\\x{2DFF}\\x{302A}-\\x{302D}\\x{302E}-\\x{302F}\\x{3099}-\\x{309A}\\x{A66F}\\x{A670}-\\x{A672}\\x{A674}-\\x{A67D}\\x{A69E}-\\x{A69F}\\x{A6F0}-\\x{A6F1}\\x{A802}\\x{A806}\\x{A80B}\\x{A823}-\\x{A824}\\x{A825}-\\x{A826}\\x{A827}\\x{A82C}\\x{A880}-\\x{A881}\\x{A8B4}-\\x{A8C3}\\x{A8C4}-\\x{A8C5}\\x{A8E0}-\\x{A8F1}\\x{A8FF}\\x{A926}-\\x{A92D}\\x{A947}-\\x{A951}\\x{A952}-\\x{A953}\\x{A980}-\\x{A982}\\x{A983}\\x{A9B3}\\x{A9B4}-\\x{A9B5}\\x{A9B6}-\\x{A9B9}\\x{A9BA}-\\x{A9BB}\\x{A9BC}-\\x{A9BD}\\x{A9BE}-\\x{A9C0}\\x{A9E5}\\x{AA29}-\\x{AA2E}\\x{AA2F}-\\x{AA30}\\x{AA31}-\\x{AA32}\\x{AA33}-\\x{AA34}\\x{AA35}-\\x{AA36}\\x{AA43}\\x{AA4C}\\x{AA4D}\\x{AA7B}\\x{AA7C}\\x{AA7D}\\x{AAB0}\\x{AAB2}-\\x{AAB4}\\x{AAB7}-\\x{AAB8}\\x{AABE}-\\x{AABF}\\x{AAC1}\\x{AAEB}\\x{AAEC}-\\x{AAED}\\x{AAEE}-\\x{AAEF}\\x{AAF5}\\x{AAF6}\\x{ABE3}-\\x{ABE4}\\x{ABE5}\\x{ABE6}-\\x{ABE7}\\x{ABE8}\\x{ABE9}-\\x{ABEA}\\x{ABEC}\\x{ABED}\\x{FB1E}\\x{FE00}-\\x{FE0F}\\x{FE20}-\\x{FE2F}\\x{101FD}\\x{102E0}\\x{10376}-\\x{1037A}\\x{10A01}-\\x{10A03}\\x{10A05}-\\x{10A06}\\x{10A0C}-\\x{10A0F}\\x{10A38}-\\x{10A3A}\\x{10A3F}\\x{10AE5}-\\x{10AE6}\\x{10D24}-\\x{10D27}\\x{10EAB}-\\x{10EAC}\\x{10F46}-\\x{10F50}\\x{11000}\\x{11001}\\x{11002}\\x{11038}-\\x{11046}\\x{1107F}-\\x{11081}\\x{11082}\\x{110B0}-\\x{110B2}\\x{110B3}-\\x{110B6}\\x{110B7}-\\x{110B8}\\x{110B9}-\\x{110BA}\\x{11100}-\\x{11102}\\x{11127}-\\x{1112B}\\x{1112C}\\x{1112D}-\\x{11134}\\x{11145}-\\x{11146}\\x{11173}\\x{11180}-\\x{11181}\\x{11182}\\x{111B3}-\\x{111B5}\\x{111B6}-\\x{111BE}\\x{111BF}-\\x{111C0}\\x{111C9}-\\x{111CC}\\x{111CE}\\x{111CF}\\x{1122C}-\\x{1122E}\\x{1122F}-\\x{11231}\\x{11232}-\\x{11233}\\x{11234}\\x{11235}\\x{11236}-\\x{11237}\\x{1123E}\\x{112DF}\\x{112E0}-\\x{112E2}\\x{112E3}-\\x{112EA}\\x{11300}-\\x{11301}\\x{11302}-\\x{11303}\\x{1133B}-\\x{1133C}\\x{1133E}-\\x{1133F}\\x{11340}\\x{11341}-\\x{11344}\\x{11347}-\\x{11348}\\x{1134B}-\\x{1134D}\\x{11357}\\x{11362}-\\x{11363}\\x{11366}-\\x{1136C}\\x{11370}-\\x{11374}\\x{11435}-\\x{11437}\\x{11438}-\\x{1143F}\\x{11440}-\\x{11441}\\x{11442}-\\x{11444}\\x{11445}\\x{11446}\\x{1145E}\\x{114B0}-\\x{114B2}\\x{114B3}-\\x{114B8}\\x{114B9}\\x{114BA}\\x{114BB}-\\x{114BE}\\x{114BF}-\\x{114C0}\\x{114C1}\\x{114C2}-\\x{114C3}\\x{115AF}-\\x{115B1}\\x{115B2}-\\x{115B5}\\x{115B8}-\\x{115BB}\\x{115BC}-\\x{115BD}\\x{115BE}\\x{115BF}-\\x{115C0}\\x{115DC}-\\x{115DD}\\x{11630}-\\x{11632}\\x{11633}-\\x{1163A}\\x{1163B}-\\x{1163C}\\x{1163D}\\x{1163E}\\x{1163F}-\\x{11640}\\x{116AB}\\x{116AC}\\x{116AD}\\x{116AE}-\\x{116AF}\\x{116B0}-\\x{116B5}\\x{116B6}\\x{116B7}\\x{1171D}-\\x{1171F}\\x{11720}-\\x{11721}\\x{11722}-\\x{11725}\\x{11726}\\x{11727}-\\x{1172B}\\x{1182C}-\\x{1182E}\\x{1182F}-\\x{11837}\\x{11838}\\x{11839}-\\x{1183A}\\x{11930}-\\x{11935}\\x{11937}-\\x{11938}\\x{1193B}-\\x{1193C}\\x{1193D}\\x{1193E}\\x{11940}\\x{11942}\\x{11943}\\x{119D1}-\\x{119D3}\\x{119D4}-\\x{119D7}\\x{119DA}-\\x{119DB}\\x{119DC}-\\x{119DF}\\x{119E0}\\x{119E4}\\x{11A01}-\\x{11A0A}\\x{11A33}-\\x{11A38}\\x{11A39}\\x{11A3B}-\\x{11A3E}\\x{11A47}\\x{11A51}-\\x{11A56}\\x{11A57}-\\x{11A58}\\x{11A59}-\\x{11A5B}\\x{11A8A}-\\x{11A96}\\x{11A97}\\x{11A98}-\\x{11A99}\\x{11C2F}\\x{11C30}-\\x{11C36}\\x{11C38}-\\x{11C3D}\\x{11C3E}\\x{11C3F}\\x{11C92}-\\x{11CA7}\\x{11CA9}\\x{11CAA}-\\x{11CB0}\\x{11CB1}\\x{11CB2}-\\x{11CB3}\\x{11CB4}\\x{11CB5}-\\x{11CB6}\\x{11D31}-\\x{11D36}\\x{11D3A}\\x{11D3C}-\\x{11D3D}\\x{11D3F}-\\x{11D45}\\x{11D47}\\x{11D8A}-\\x{11D8E}\\x{11D90}-\\x{11D91}\\x{11D93}-\\x{11D94}\\x{11D95}\\x{11D96}\\x{11D97}\\x{11EF3}-\\x{11EF4}\\x{11EF5}-\\x{11EF6}\\x{16AF0}-\\x{16AF4}\\x{16B30}-\\x{16B36}\\x{16F4F}\\x{16F51}-\\x{16F87}\\x{16F8F}-\\x{16F92}\\x{16FE4}\\x{16FF0}-\\x{16FF1}\\x{1BC9D}-\\x{1BC9E}\\x{1D165}-\\x{1D166}\\x{1D167}-\\x{1D169}\\x{1D16D}-\\x{1D172}\\x{1D17B}-\\x{1D182}\\x{1D185}-\\x{1D18B}\\x{1D1AA}-\\x{1D1AD}\\x{1D242}-\\x{1D244}\\x{1DA00}-\\x{1DA36}\\x{1DA3B}-\\x{1DA6C}\\x{1DA75}\\x{1DA84}\\x{1DA9B}-\\x{1DA9F}\\x{1DAA1}-\\x{1DAAF}\\x{1E000}-\\x{1E006}\\x{1E008}-\\x{1E018}\\x{1E01B}-\\x{1E021}\\x{1E023}-\\x{1E024}\\x{1E026}-\\x{1E02A}\\x{1E130}-\\x{1E136}\\x{1E2EC}-\\x{1E2EF}\\x{1E8D0}-\\x{1E8D6}\\x{1E944}-\\x{1E94A}\\x{E0100}-\\x{E01EF}]/u';\n\n    const RTL_LABEL = '/[\\x{0590}\\x{05BE}\\x{05C0}\\x{05C3}\\x{05C6}\\x{05C8}-\\x{05CF}\\x{05D0}-\\x{05EA}\\x{05EB}-\\x{05EE}\\x{05EF}-\\x{05F2}\\x{05F3}-\\x{05F4}\\x{05F5}-\\x{05FF}\\x{0600}-\\x{0605}\\x{0608}\\x{060B}\\x{060D}\\x{061B}\\x{061C}\\x{061D}\\x{061E}-\\x{061F}\\x{0620}-\\x{063F}\\x{0640}\\x{0641}-\\x{064A}\\x{0660}-\\x{0669}\\x{066B}-\\x{066C}\\x{066D}\\x{066E}-\\x{066F}\\x{0671}-\\x{06D3}\\x{06D4}\\x{06D5}\\x{06DD}\\x{06E5}-\\x{06E6}\\x{06EE}-\\x{06EF}\\x{06FA}-\\x{06FC}\\x{06FD}-\\x{06FE}\\x{06FF}\\x{0700}-\\x{070D}\\x{070E}\\x{070F}\\x{0710}\\x{0712}-\\x{072F}\\x{074B}-\\x{074C}\\x{074D}-\\x{07A5}\\x{07B1}\\x{07B2}-\\x{07BF}\\x{07C0}-\\x{07C9}\\x{07CA}-\\x{07EA}\\x{07F4}-\\x{07F5}\\x{07FA}\\x{07FB}-\\x{07FC}\\x{07FE}-\\x{07FF}\\x{0800}-\\x{0815}\\x{081A}\\x{0824}\\x{0828}\\x{082E}-\\x{082F}\\x{0830}-\\x{083E}\\x{083F}\\x{0840}-\\x{0858}\\x{085C}-\\x{085D}\\x{085E}\\x{085F}\\x{0860}-\\x{086A}\\x{086B}-\\x{086F}\\x{0870}-\\x{089F}\\x{08A0}-\\x{08B4}\\x{08B5}\\x{08B6}-\\x{08C7}\\x{08C8}-\\x{08D2}\\x{08E2}\\x{200F}\\x{FB1D}\\x{FB1F}-\\x{FB28}\\x{FB2A}-\\x{FB36}\\x{FB37}\\x{FB38}-\\x{FB3C}\\x{FB3D}\\x{FB3E}\\x{FB3F}\\x{FB40}-\\x{FB41}\\x{FB42}\\x{FB43}-\\x{FB44}\\x{FB45}\\x{FB46}-\\x{FB4F}\\x{FB50}-\\x{FBB1}\\x{FBB2}-\\x{FBC1}\\x{FBC2}-\\x{FBD2}\\x{FBD3}-\\x{FD3D}\\x{FD40}-\\x{FD4F}\\x{FD50}-\\x{FD8F}\\x{FD90}-\\x{FD91}\\x{FD92}-\\x{FDC7}\\x{FDC8}-\\x{FDCF}\\x{FDF0}-\\x{FDFB}\\x{FDFC}\\x{FDFE}-\\x{FDFF}\\x{FE70}-\\x{FE74}\\x{FE75}\\x{FE76}-\\x{FEFC}\\x{FEFD}-\\x{FEFE}\\x{10800}-\\x{10805}\\x{10806}-\\x{10807}\\x{10808}\\x{10809}\\x{1080A}-\\x{10835}\\x{10836}\\x{10837}-\\x{10838}\\x{10839}-\\x{1083B}\\x{1083C}\\x{1083D}-\\x{1083E}\\x{1083F}-\\x{10855}\\x{10856}\\x{10857}\\x{10858}-\\x{1085F}\\x{10860}-\\x{10876}\\x{10877}-\\x{10878}\\x{10879}-\\x{1087F}\\x{10880}-\\x{1089E}\\x{1089F}-\\x{108A6}\\x{108A7}-\\x{108AF}\\x{108B0}-\\x{108DF}\\x{108E0}-\\x{108F2}\\x{108F3}\\x{108F4}-\\x{108F5}\\x{108F6}-\\x{108FA}\\x{108FB}-\\x{108FF}\\x{10900}-\\x{10915}\\x{10916}-\\x{1091B}\\x{1091C}-\\x{1091E}\\x{10920}-\\x{10939}\\x{1093A}-\\x{1093E}\\x{1093F}\\x{10940}-\\x{1097F}\\x{10980}-\\x{109B7}\\x{109B8}-\\x{109BB}\\x{109BC}-\\x{109BD}\\x{109BE}-\\x{109BF}\\x{109C0}-\\x{109CF}\\x{109D0}-\\x{109D1}\\x{109D2}-\\x{109FF}\\x{10A00}\\x{10A04}\\x{10A07}-\\x{10A0B}\\x{10A10}-\\x{10A13}\\x{10A14}\\x{10A15}-\\x{10A17}\\x{10A18}\\x{10A19}-\\x{10A35}\\x{10A36}-\\x{10A37}\\x{10A3B}-\\x{10A3E}\\x{10A40}-\\x{10A48}\\x{10A49}-\\x{10A4F}\\x{10A50}-\\x{10A58}\\x{10A59}-\\x{10A5F}\\x{10A60}-\\x{10A7C}\\x{10A7D}-\\x{10A7E}\\x{10A7F}\\x{10A80}-\\x{10A9C}\\x{10A9D}-\\x{10A9F}\\x{10AA0}-\\x{10ABF}\\x{10AC0}-\\x{10AC7}\\x{10AC8}\\x{10AC9}-\\x{10AE4}\\x{10AE7}-\\x{10AEA}\\x{10AEB}-\\x{10AEF}\\x{10AF0}-\\x{10AF6}\\x{10AF7}-\\x{10AFF}\\x{10B00}-\\x{10B35}\\x{10B36}-\\x{10B38}\\x{10B40}-\\x{10B55}\\x{10B56}-\\x{10B57}\\x{10B58}-\\x{10B5F}\\x{10B60}-\\x{10B72}\\x{10B73}-\\x{10B77}\\x{10B78}-\\x{10B7F}\\x{10B80}-\\x{10B91}\\x{10B92}-\\x{10B98}\\x{10B99}-\\x{10B9C}\\x{10B9D}-\\x{10BA8}\\x{10BA9}-\\x{10BAF}\\x{10BB0}-\\x{10BFF}\\x{10C00}-\\x{10C48}\\x{10C49}-\\x{10C7F}\\x{10C80}-\\x{10CB2}\\x{10CB3}-\\x{10CBF}\\x{10CC0}-\\x{10CF2}\\x{10CF3}-\\x{10CF9}\\x{10CFA}-\\x{10CFF}\\x{10D00}-\\x{10D23}\\x{10D28}-\\x{10D2F}\\x{10D30}-\\x{10D39}\\x{10D3A}-\\x{10D3F}\\x{10D40}-\\x{10E5F}\\x{10E60}-\\x{10E7E}\\x{10E7F}\\x{10E80}-\\x{10EA9}\\x{10EAA}\\x{10EAD}\\x{10EAE}-\\x{10EAF}\\x{10EB0}-\\x{10EB1}\\x{10EB2}-\\x{10EFF}\\x{10F00}-\\x{10F1C}\\x{10F1D}-\\x{10F26}\\x{10F27}\\x{10F28}-\\x{10F2F}\\x{10F30}-\\x{10F45}\\x{10F51}-\\x{10F54}\\x{10F55}-\\x{10F59}\\x{10F5A}-\\x{10F6F}\\x{10F70}-\\x{10FAF}\\x{10FB0}-\\x{10FC4}\\x{10FC5}-\\x{10FCB}\\x{10FCC}-\\x{10FDF}\\x{10FE0}-\\x{10FF6}\\x{10FF7}-\\x{10FFF}\\x{1E800}-\\x{1E8C4}\\x{1E8C5}-\\x{1E8C6}\\x{1E8C7}-\\x{1E8CF}\\x{1E8D7}-\\x{1E8FF}\\x{1E900}-\\x{1E943}\\x{1E94B}\\x{1E94C}-\\x{1E94F}\\x{1E950}-\\x{1E959}\\x{1E95A}-\\x{1E95D}\\x{1E95E}-\\x{1E95F}\\x{1E960}-\\x{1EC6F}\\x{1EC70}\\x{1EC71}-\\x{1ECAB}\\x{1ECAC}\\x{1ECAD}-\\x{1ECAF}\\x{1ECB0}\\x{1ECB1}-\\x{1ECB4}\\x{1ECB5}-\\x{1ECBF}\\x{1ECC0}-\\x{1ECFF}\\x{1ED00}\\x{1ED01}-\\x{1ED2D}\\x{1ED2E}\\x{1ED2F}-\\x{1ED3D}\\x{1ED3E}-\\x{1ED4F}\\x{1ED50}-\\x{1EDFF}\\x{1EE00}-\\x{1EE03}\\x{1EE04}\\x{1EE05}-\\x{1EE1F}\\x{1EE20}\\x{1EE21}-\\x{1EE22}\\x{1EE23}\\x{1EE24}\\x{1EE25}-\\x{1EE26}\\x{1EE27}\\x{1EE28}\\x{1EE29}-\\x{1EE32}\\x{1EE33}\\x{1EE34}-\\x{1EE37}\\x{1EE38}\\x{1EE39}\\x{1EE3A}\\x{1EE3B}\\x{1EE3C}-\\x{1EE41}\\x{1EE42}\\x{1EE43}-\\x{1EE46}\\x{1EE47}\\x{1EE48}\\x{1EE49}\\x{1EE4A}\\x{1EE4B}\\x{1EE4C}\\x{1EE4D}-\\x{1EE4F}\\x{1EE50}\\x{1EE51}-\\x{1EE52}\\x{1EE53}\\x{1EE54}\\x{1EE55}-\\x{1EE56}\\x{1EE57}\\x{1EE58}\\x{1EE59}\\x{1EE5A}\\x{1EE5B}\\x{1EE5C}\\x{1EE5D}\\x{1EE5E}\\x{1EE5F}\\x{1EE60}\\x{1EE61}-\\x{1EE62}\\x{1EE63}\\x{1EE64}\\x{1EE65}-\\x{1EE66}\\x{1EE67}-\\x{1EE6A}\\x{1EE6B}\\x{1EE6C}-\\x{1EE72}\\x{1EE73}\\x{1EE74}-\\x{1EE77}\\x{1EE78}\\x{1EE79}-\\x{1EE7C}\\x{1EE7D}\\x{1EE7E}\\x{1EE7F}\\x{1EE80}-\\x{1EE89}\\x{1EE8A}\\x{1EE8B}-\\x{1EE9B}\\x{1EE9C}-\\x{1EEA0}\\x{1EEA1}-\\x{1EEA3}\\x{1EEA4}\\x{1EEA5}-\\x{1EEA9}\\x{1EEAA}\\x{1EEAB}-\\x{1EEBB}\\x{1EEBC}-\\x{1EEEF}\\x{1EEF2}-\\x{1EEFF}\\x{1EF00}-\\x{1EFFF}]/u';\n\n    const BIDI_STEP_1_LTR = '/^[^\\x{0000}-\\x{0008}\\x{0009}\\x{000A}\\x{000B}\\x{000C}\\x{000D}\\x{000E}-\\x{001B}\\x{001C}-\\x{001E}\\x{001F}\\x{0020}\\x{0021}-\\x{0022}\\x{0023}\\x{0024}\\x{0025}\\x{0026}-\\x{0027}\\x{0028}\\x{0029}\\x{002A}\\x{002B}\\x{002C}\\x{002D}\\x{002E}-\\x{002F}\\x{0030}-\\x{0039}\\x{003A}\\x{003B}\\x{003C}-\\x{003E}\\x{003F}-\\x{0040}\\x{005B}\\x{005C}\\x{005D}\\x{005E}\\x{005F}\\x{0060}\\x{007B}\\x{007C}\\x{007D}\\x{007E}\\x{007F}-\\x{0084}\\x{0085}\\x{0086}-\\x{009F}\\x{00A0}\\x{00A1}\\x{00A2}-\\x{00A5}\\x{00A6}\\x{00A7}\\x{00A8}\\x{00A9}\\x{00AB}\\x{00AC}\\x{00AD}\\x{00AE}\\x{00AF}\\x{00B0}\\x{00B1}\\x{00B2}-\\x{00B3}\\x{00B4}\\x{00B6}-\\x{00B7}\\x{00B8}\\x{00B9}\\x{00BB}\\x{00BC}-\\x{00BE}\\x{00BF}\\x{00D7}\\x{00F7}\\x{02B9}-\\x{02BA}\\x{02C2}-\\x{02C5}\\x{02C6}-\\x{02CF}\\x{02D2}-\\x{02DF}\\x{02E5}-\\x{02EB}\\x{02EC}\\x{02ED}\\x{02EF}-\\x{02FF}\\x{0300}-\\x{036F}\\x{0374}\\x{0375}\\x{037E}\\x{0384}-\\x{0385}\\x{0387}\\x{03F6}\\x{0483}-\\x{0487}\\x{0488}-\\x{0489}\\x{058A}\\x{058D}-\\x{058E}\\x{058F}\\x{0590}\\x{0591}-\\x{05BD}\\x{05BE}\\x{05BF}\\x{05C0}\\x{05C1}-\\x{05C2}\\x{05C3}\\x{05C4}-\\x{05C5}\\x{05C6}\\x{05C7}\\x{05C8}-\\x{05CF}\\x{05D0}-\\x{05EA}\\x{05EB}-\\x{05EE}\\x{05EF}-\\x{05F2}\\x{05F3}-\\x{05F4}\\x{05F5}-\\x{05FF}\\x{0600}-\\x{0605}\\x{0606}-\\x{0607}\\x{0608}\\x{0609}-\\x{060A}\\x{060B}\\x{060C}\\x{060D}\\x{060E}-\\x{060F}\\x{0610}-\\x{061A}\\x{061B}\\x{061C}\\x{061D}\\x{061E}-\\x{061F}\\x{0620}-\\x{063F}\\x{0640}\\x{0641}-\\x{064A}\\x{064B}-\\x{065F}\\x{0660}-\\x{0669}\\x{066A}\\x{066B}-\\x{066C}\\x{066D}\\x{066E}-\\x{066F}\\x{0670}\\x{0671}-\\x{06D3}\\x{06D4}\\x{06D5}\\x{06D6}-\\x{06DC}\\x{06DD}\\x{06DE}\\x{06DF}-\\x{06E4}\\x{06E5}-\\x{06E6}\\x{06E7}-\\x{06E8}\\x{06E9}\\x{06EA}-\\x{06ED}\\x{06EE}-\\x{06EF}\\x{06F0}-\\x{06F9}\\x{06FA}-\\x{06FC}\\x{06FD}-\\x{06FE}\\x{06FF}\\x{0700}-\\x{070D}\\x{070E}\\x{070F}\\x{0710}\\x{0711}\\x{0712}-\\x{072F}\\x{0730}-\\x{074A}\\x{074B}-\\x{074C}\\x{074D}-\\x{07A5}\\x{07A6}-\\x{07B0}\\x{07B1}\\x{07B2}-\\x{07BF}\\x{07C0}-\\x{07C9}\\x{07CA}-\\x{07EA}\\x{07EB}-\\x{07F3}\\x{07F4}-\\x{07F5}\\x{07F6}\\x{07F7}-\\x{07F9}\\x{07FA}\\x{07FB}-\\x{07FC}\\x{07FD}\\x{07FE}-\\x{07FF}\\x{0800}-\\x{0815}\\x{0816}-\\x{0819}\\x{081A}\\x{081B}-\\x{0823}\\x{0824}\\x{0825}-\\x{0827}\\x{0828}\\x{0829}-\\x{082D}\\x{082E}-\\x{082F}\\x{0830}-\\x{083E}\\x{083F}\\x{0840}-\\x{0858}\\x{0859}-\\x{085B}\\x{085C}-\\x{085D}\\x{085E}\\x{085F}\\x{0860}-\\x{086A}\\x{086B}-\\x{086F}\\x{0870}-\\x{089F}\\x{08A0}-\\x{08B4}\\x{08B5}\\x{08B6}-\\x{08C7}\\x{08C8}-\\x{08D2}\\x{08D3}-\\x{08E1}\\x{08E2}\\x{08E3}-\\x{0902}\\x{093A}\\x{093C}\\x{0941}-\\x{0948}\\x{094D}\\x{0951}-\\x{0957}\\x{0962}-\\x{0963}\\x{0981}\\x{09BC}\\x{09C1}-\\x{09C4}\\x{09CD}\\x{09E2}-\\x{09E3}\\x{09F2}-\\x{09F3}\\x{09FB}\\x{09FE}\\x{0A01}-\\x{0A02}\\x{0A3C}\\x{0A41}-\\x{0A42}\\x{0A47}-\\x{0A48}\\x{0A4B}-\\x{0A4D}\\x{0A51}\\x{0A70}-\\x{0A71}\\x{0A75}\\x{0A81}-\\x{0A82}\\x{0ABC}\\x{0AC1}-\\x{0AC5}\\x{0AC7}-\\x{0AC8}\\x{0ACD}\\x{0AE2}-\\x{0AE3}\\x{0AF1}\\x{0AFA}-\\x{0AFF}\\x{0B01}\\x{0B3C}\\x{0B3F}\\x{0B41}-\\x{0B44}\\x{0B4D}\\x{0B55}-\\x{0B56}\\x{0B62}-\\x{0B63}\\x{0B82}\\x{0BC0}\\x{0BCD}\\x{0BF3}-\\x{0BF8}\\x{0BF9}\\x{0BFA}\\x{0C00}\\x{0C04}\\x{0C3E}-\\x{0C40}\\x{0C46}-\\x{0C48}\\x{0C4A}-\\x{0C4D}\\x{0C55}-\\x{0C56}\\x{0C62}-\\x{0C63}\\x{0C78}-\\x{0C7E}\\x{0C81}\\x{0CBC}\\x{0CCC}-\\x{0CCD}\\x{0CE2}-\\x{0CE3}\\x{0D00}-\\x{0D01}\\x{0D3B}-\\x{0D3C}\\x{0D41}-\\x{0D44}\\x{0D4D}\\x{0D62}-\\x{0D63}\\x{0D81}\\x{0DCA}\\x{0DD2}-\\x{0DD4}\\x{0DD6}\\x{0E31}\\x{0E34}-\\x{0E3A}\\x{0E3F}\\x{0E47}-\\x{0E4E}\\x{0EB1}\\x{0EB4}-\\x{0EBC}\\x{0EC8}-\\x{0ECD}\\x{0F18}-\\x{0F19}\\x{0F35}\\x{0F37}\\x{0F39}\\x{0F3A}\\x{0F3B}\\x{0F3C}\\x{0F3D}\\x{0F71}-\\x{0F7E}\\x{0F80}-\\x{0F84}\\x{0F86}-\\x{0F87}\\x{0F8D}-\\x{0F97}\\x{0F99}-\\x{0FBC}\\x{0FC6}\\x{102D}-\\x{1030}\\x{1032}-\\x{1037}\\x{1039}-\\x{103A}\\x{103D}-\\x{103E}\\x{1058}-\\x{1059}\\x{105E}-\\x{1060}\\x{1071}-\\x{1074}\\x{1082}\\x{1085}-\\x{1086}\\x{108D}\\x{109D}\\x{135D}-\\x{135F}\\x{1390}-\\x{1399}\\x{1400}\\x{1680}\\x{169B}\\x{169C}\\x{1712}-\\x{1714}\\x{1732}-\\x{1734}\\x{1752}-\\x{1753}\\x{1772}-\\x{1773}\\x{17B4}-\\x{17B5}\\x{17B7}-\\x{17BD}\\x{17C6}\\x{17C9}-\\x{17D3}\\x{17DB}\\x{17DD}\\x{17F0}-\\x{17F9}\\x{1800}-\\x{1805}\\x{1806}\\x{1807}-\\x{180A}\\x{180B}-\\x{180D}\\x{180E}\\x{1885}-\\x{1886}\\x{18A9}\\x{1920}-\\x{1922}\\x{1927}-\\x{1928}\\x{1932}\\x{1939}-\\x{193B}\\x{1940}\\x{1944}-\\x{1945}\\x{19DE}-\\x{19FF}\\x{1A17}-\\x{1A18}\\x{1A1B}\\x{1A56}\\x{1A58}-\\x{1A5E}\\x{1A60}\\x{1A62}\\x{1A65}-\\x{1A6C}\\x{1A73}-\\x{1A7C}\\x{1A7F}\\x{1AB0}-\\x{1ABD}\\x{1ABE}\\x{1ABF}-\\x{1AC0}\\x{1B00}-\\x{1B03}\\x{1B34}\\x{1B36}-\\x{1B3A}\\x{1B3C}\\x{1B42}\\x{1B6B}-\\x{1B73}\\x{1B80}-\\x{1B81}\\x{1BA2}-\\x{1BA5}\\x{1BA8}-\\x{1BA9}\\x{1BAB}-\\x{1BAD}\\x{1BE6}\\x{1BE8}-\\x{1BE9}\\x{1BED}\\x{1BEF}-\\x{1BF1}\\x{1C2C}-\\x{1C33}\\x{1C36}-\\x{1C37}\\x{1CD0}-\\x{1CD2}\\x{1CD4}-\\x{1CE0}\\x{1CE2}-\\x{1CE8}\\x{1CED}\\x{1CF4}\\x{1CF8}-\\x{1CF9}\\x{1DC0}-\\x{1DF9}\\x{1DFB}-\\x{1DFF}\\x{1FBD}\\x{1FBF}-\\x{1FC1}\\x{1FCD}-\\x{1FCF}\\x{1FDD}-\\x{1FDF}\\x{1FED}-\\x{1FEF}\\x{1FFD}-\\x{1FFE}\\x{2000}-\\x{200A}\\x{200B}-\\x{200D}\\x{200F}\\x{2010}-\\x{2015}\\x{2016}-\\x{2017}\\x{2018}\\x{2019}\\x{201A}\\x{201B}-\\x{201C}\\x{201D}\\x{201E}\\x{201F}\\x{2020}-\\x{2027}\\x{2028}\\x{2029}\\x{202A}\\x{202B}\\x{202C}\\x{202D}\\x{202E}\\x{202F}\\x{2030}-\\x{2034}\\x{2035}-\\x{2038}\\x{2039}\\x{203A}\\x{203B}-\\x{203E}\\x{203F}-\\x{2040}\\x{2041}-\\x{2043}\\x{2044}\\x{2045}\\x{2046}\\x{2047}-\\x{2051}\\x{2052}\\x{2053}\\x{2054}\\x{2055}-\\x{205E}\\x{205F}\\x{2060}-\\x{2064}\\x{2065}\\x{2066}\\x{2067}\\x{2068}\\x{2069}\\x{206A}-\\x{206F}\\x{2070}\\x{2074}-\\x{2079}\\x{207A}-\\x{207B}\\x{207C}\\x{207D}\\x{207E}\\x{2080}-\\x{2089}\\x{208A}-\\x{208B}\\x{208C}\\x{208D}\\x{208E}\\x{20A0}-\\x{20BF}\\x{20C0}-\\x{20CF}\\x{20D0}-\\x{20DC}\\x{20DD}-\\x{20E0}\\x{20E1}\\x{20E2}-\\x{20E4}\\x{20E5}-\\x{20F0}\\x{2100}-\\x{2101}\\x{2103}-\\x{2106}\\x{2108}-\\x{2109}\\x{2114}\\x{2116}-\\x{2117}\\x{2118}\\x{211E}-\\x{2123}\\x{2125}\\x{2127}\\x{2129}\\x{212E}\\x{213A}-\\x{213B}\\x{2140}-\\x{2144}\\x{214A}\\x{214B}\\x{214C}-\\x{214D}\\x{2150}-\\x{215F}\\x{2189}\\x{218A}-\\x{218B}\\x{2190}-\\x{2194}\\x{2195}-\\x{2199}\\x{219A}-\\x{219B}\\x{219C}-\\x{219F}\\x{21A0}\\x{21A1}-\\x{21A2}\\x{21A3}\\x{21A4}-\\x{21A5}\\x{21A6}\\x{21A7}-\\x{21AD}\\x{21AE}\\x{21AF}-\\x{21CD}\\x{21CE}-\\x{21CF}\\x{21D0}-\\x{21D1}\\x{21D2}\\x{21D3}\\x{21D4}\\x{21D5}-\\x{21F3}\\x{21F4}-\\x{2211}\\x{2212}\\x{2213}\\x{2214}-\\x{22FF}\\x{2300}-\\x{2307}\\x{2308}\\x{2309}\\x{230A}\\x{230B}\\x{230C}-\\x{231F}\\x{2320}-\\x{2321}\\x{2322}-\\x{2328}\\x{2329}\\x{232A}\\x{232B}-\\x{2335}\\x{237B}\\x{237C}\\x{237D}-\\x{2394}\\x{2396}-\\x{239A}\\x{239B}-\\x{23B3}\\x{23B4}-\\x{23DB}\\x{23DC}-\\x{23E1}\\x{23E2}-\\x{2426}\\x{2440}-\\x{244A}\\x{2460}-\\x{2487}\\x{2488}-\\x{249B}\\x{24EA}-\\x{24FF}\\x{2500}-\\x{25B6}\\x{25B7}\\x{25B8}-\\x{25C0}\\x{25C1}\\x{25C2}-\\x{25F7}\\x{25F8}-\\x{25FF}\\x{2600}-\\x{266E}\\x{266F}\\x{2670}-\\x{26AB}\\x{26AD}-\\x{2767}\\x{2768}\\x{2769}\\x{276A}\\x{276B}\\x{276C}\\x{276D}\\x{276E}\\x{276F}\\x{2770}\\x{2771}\\x{2772}\\x{2773}\\x{2774}\\x{2775}\\x{2776}-\\x{2793}\\x{2794}-\\x{27BF}\\x{27C0}-\\x{27C4}\\x{27C5}\\x{27C6}\\x{27C7}-\\x{27E5}\\x{27E6}\\x{27E7}\\x{27E8}\\x{27E9}\\x{27EA}\\x{27EB}\\x{27EC}\\x{27ED}\\x{27EE}\\x{27EF}\\x{27F0}-\\x{27FF}\\x{2900}-\\x{2982}\\x{2983}\\x{2984}\\x{2985}\\x{2986}\\x{2987}\\x{2988}\\x{2989}\\x{298A}\\x{298B}\\x{298C}\\x{298D}\\x{298E}\\x{298F}\\x{2990}\\x{2991}\\x{2992}\\x{2993}\\x{2994}\\x{2995}\\x{2996}\\x{2997}\\x{2998}\\x{2999}-\\x{29D7}\\x{29D8}\\x{29D9}\\x{29DA}\\x{29DB}\\x{29DC}-\\x{29FB}\\x{29FC}\\x{29FD}\\x{29FE}-\\x{2AFF}\\x{2B00}-\\x{2B2F}\\x{2B30}-\\x{2B44}\\x{2B45}-\\x{2B46}\\x{2B47}-\\x{2B4C}\\x{2B4D}-\\x{2B73}\\x{2B76}-\\x{2B95}\\x{2B97}-\\x{2BFF}\\x{2CE5}-\\x{2CEA}\\x{2CEF}-\\x{2CF1}\\x{2CF9}-\\x{2CFC}\\x{2CFD}\\x{2CFE}-\\x{2CFF}\\x{2D7F}\\x{2DE0}-\\x{2DFF}\\x{2E00}-\\x{2E01}\\x{2E02}\\x{2E03}\\x{2E04}\\x{2E05}\\x{2E06}-\\x{2E08}\\x{2E09}\\x{2E0A}\\x{2E0B}\\x{2E0C}\\x{2E0D}\\x{2E0E}-\\x{2E16}\\x{2E17}\\x{2E18}-\\x{2E19}\\x{2E1A}\\x{2E1B}\\x{2E1C}\\x{2E1D}\\x{2E1E}-\\x{2E1F}\\x{2E20}\\x{2E21}\\x{2E22}\\x{2E23}\\x{2E24}\\x{2E25}\\x{2E26}\\x{2E27}\\x{2E28}\\x{2E29}\\x{2E2A}-\\x{2E2E}\\x{2E2F}\\x{2E30}-\\x{2E39}\\x{2E3A}-\\x{2E3B}\\x{2E3C}-\\x{2E3F}\\x{2E40}\\x{2E41}\\x{2E42}\\x{2E43}-\\x{2E4F}\\x{2E50}-\\x{2E51}\\x{2E52}\\x{2E80}-\\x{2E99}\\x{2E9B}-\\x{2EF3}\\x{2F00}-\\x{2FD5}\\x{2FF0}-\\x{2FFB}\\x{3000}\\x{3001}-\\x{3003}\\x{3004}\\x{3008}\\x{3009}\\x{300A}\\x{300B}\\x{300C}\\x{300D}\\x{300E}\\x{300F}\\x{3010}\\x{3011}\\x{3012}-\\x{3013}\\x{3014}\\x{3015}\\x{3016}\\x{3017}\\x{3018}\\x{3019}\\x{301A}\\x{301B}\\x{301C}\\x{301D}\\x{301E}-\\x{301F}\\x{3020}\\x{302A}-\\x{302D}\\x{3030}\\x{3036}-\\x{3037}\\x{303D}\\x{303E}-\\x{303F}\\x{3099}-\\x{309A}\\x{309B}-\\x{309C}\\x{30A0}\\x{30FB}\\x{31C0}-\\x{31E3}\\x{321D}-\\x{321E}\\x{3250}\\x{3251}-\\x{325F}\\x{327C}-\\x{327E}\\x{32B1}-\\x{32BF}\\x{32CC}-\\x{32CF}\\x{3377}-\\x{337A}\\x{33DE}-\\x{33DF}\\x{33FF}\\x{4DC0}-\\x{4DFF}\\x{A490}-\\x{A4C6}\\x{A60D}-\\x{A60F}\\x{A66F}\\x{A670}-\\x{A672}\\x{A673}\\x{A674}-\\x{A67D}\\x{A67E}\\x{A67F}\\x{A69E}-\\x{A69F}\\x{A6F0}-\\x{A6F1}\\x{A700}-\\x{A716}\\x{A717}-\\x{A71F}\\x{A720}-\\x{A721}\\x{A788}\\x{A802}\\x{A806}\\x{A80B}\\x{A825}-\\x{A826}\\x{A828}-\\x{A82B}\\x{A82C}\\x{A838}\\x{A839}\\x{A874}-\\x{A877}\\x{A8C4}-\\x{A8C5}\\x{A8E0}-\\x{A8F1}\\x{A8FF}\\x{A926}-\\x{A92D}\\x{A947}-\\x{A951}\\x{A980}-\\x{A982}\\x{A9B3}\\x{A9B6}-\\x{A9B9}\\x{A9BC}-\\x{A9BD}\\x{A9E5}\\x{AA29}-\\x{AA2E}\\x{AA31}-\\x{AA32}\\x{AA35}-\\x{AA36}\\x{AA43}\\x{AA4C}\\x{AA7C}\\x{AAB0}\\x{AAB2}-\\x{AAB4}\\x{AAB7}-\\x{AAB8}\\x{AABE}-\\x{AABF}\\x{AAC1}\\x{AAEC}-\\x{AAED}\\x{AAF6}\\x{AB6A}-\\x{AB6B}\\x{ABE5}\\x{ABE8}\\x{ABED}\\x{FB1D}\\x{FB1E}\\x{FB1F}-\\x{FB28}\\x{FB29}\\x{FB2A}-\\x{FB36}\\x{FB37}\\x{FB38}-\\x{FB3C}\\x{FB3D}\\x{FB3E}\\x{FB3F}\\x{FB40}-\\x{FB41}\\x{FB42}\\x{FB43}-\\x{FB44}\\x{FB45}\\x{FB46}-\\x{FB4F}\\x{FB50}-\\x{FBB1}\\x{FBB2}-\\x{FBC1}\\x{FBC2}-\\x{FBD2}\\x{FBD3}-\\x{FD3D}\\x{FD3E}\\x{FD3F}\\x{FD40}-\\x{FD4F}\\x{FD50}-\\x{FD8F}\\x{FD90}-\\x{FD91}\\x{FD92}-\\x{FDC7}\\x{FDC8}-\\x{FDCF}\\x{FDD0}-\\x{FDEF}\\x{FDF0}-\\x{FDFB}\\x{FDFC}\\x{FDFD}\\x{FDFE}-\\x{FDFF}\\x{FE00}-\\x{FE0F}\\x{FE10}-\\x{FE16}\\x{FE17}\\x{FE18}\\x{FE19}\\x{FE20}-\\x{FE2F}\\x{FE30}\\x{FE31}-\\x{FE32}\\x{FE33}-\\x{FE34}\\x{FE35}\\x{FE36}\\x{FE37}\\x{FE38}\\x{FE39}\\x{FE3A}\\x{FE3B}\\x{FE3C}\\x{FE3D}\\x{FE3E}\\x{FE3F}\\x{FE40}\\x{FE41}\\x{FE42}\\x{FE43}\\x{FE44}\\x{FE45}-\\x{FE46}\\x{FE47}\\x{FE48}\\x{FE49}-\\x{FE4C}\\x{FE4D}-\\x{FE4F}\\x{FE50}\\x{FE51}\\x{FE52}\\x{FE54}\\x{FE55}\\x{FE56}-\\x{FE57}\\x{FE58}\\x{FE59}\\x{FE5A}\\x{FE5B}\\x{FE5C}\\x{FE5D}\\x{FE5E}\\x{FE5F}\\x{FE60}-\\x{FE61}\\x{FE62}\\x{FE63}\\x{FE64}-\\x{FE66}\\x{FE68}\\x{FE69}\\x{FE6A}\\x{FE6B}\\x{FE70}-\\x{FE74}\\x{FE75}\\x{FE76}-\\x{FEFC}\\x{FEFD}-\\x{FEFE}\\x{FEFF}\\x{FF01}-\\x{FF02}\\x{FF03}\\x{FF04}\\x{FF05}\\x{FF06}-\\x{FF07}\\x{FF08}\\x{FF09}\\x{FF0A}\\x{FF0B}\\x{FF0C}\\x{FF0D}\\x{FF0E}-\\x{FF0F}\\x{FF10}-\\x{FF19}\\x{FF1A}\\x{FF1B}\\x{FF1C}-\\x{FF1E}\\x{FF1F}-\\x{FF20}\\x{FF3B}\\x{FF3C}\\x{FF3D}\\x{FF3E}\\x{FF3F}\\x{FF40}\\x{FF5B}\\x{FF5C}\\x{FF5D}\\x{FF5E}\\x{FF5F}\\x{FF60}\\x{FF61}\\x{FF62}\\x{FF63}\\x{FF64}-\\x{FF65}\\x{FFE0}-\\x{FFE1}\\x{FFE2}\\x{FFE3}\\x{FFE4}\\x{FFE5}-\\x{FFE6}\\x{FFE8}\\x{FFE9}-\\x{FFEC}\\x{FFED}-\\x{FFEE}\\x{FFF0}-\\x{FFF8}\\x{FFF9}-\\x{FFFB}\\x{FFFC}-\\x{FFFD}\\x{FFFE}-\\x{FFFF}\\x{10101}\\x{10140}-\\x{10174}\\x{10175}-\\x{10178}\\x{10179}-\\x{10189}\\x{1018A}-\\x{1018B}\\x{1018C}\\x{10190}-\\x{1019C}\\x{101A0}\\x{101FD}\\x{102E0}\\x{102E1}-\\x{102FB}\\x{10376}-\\x{1037A}\\x{10800}-\\x{10805}\\x{10806}-\\x{10807}\\x{10808}\\x{10809}\\x{1080A}-\\x{10835}\\x{10836}\\x{10837}-\\x{10838}\\x{10839}-\\x{1083B}\\x{1083C}\\x{1083D}-\\x{1083E}\\x{1083F}-\\x{10855}\\x{10856}\\x{10857}\\x{10858}-\\x{1085F}\\x{10860}-\\x{10876}\\x{10877}-\\x{10878}\\x{10879}-\\x{1087F}\\x{10880}-\\x{1089E}\\x{1089F}-\\x{108A6}\\x{108A7}-\\x{108AF}\\x{108B0}-\\x{108DF}\\x{108E0}-\\x{108F2}\\x{108F3}\\x{108F4}-\\x{108F5}\\x{108F6}-\\x{108FA}\\x{108FB}-\\x{108FF}\\x{10900}-\\x{10915}\\x{10916}-\\x{1091B}\\x{1091C}-\\x{1091E}\\x{1091F}\\x{10920}-\\x{10939}\\x{1093A}-\\x{1093E}\\x{1093F}\\x{10940}-\\x{1097F}\\x{10980}-\\x{109B7}\\x{109B8}-\\x{109BB}\\x{109BC}-\\x{109BD}\\x{109BE}-\\x{109BF}\\x{109C0}-\\x{109CF}\\x{109D0}-\\x{109D1}\\x{109D2}-\\x{109FF}\\x{10A00}\\x{10A01}-\\x{10A03}\\x{10A04}\\x{10A05}-\\x{10A06}\\x{10A07}-\\x{10A0B}\\x{10A0C}-\\x{10A0F}\\x{10A10}-\\x{10A13}\\x{10A14}\\x{10A15}-\\x{10A17}\\x{10A18}\\x{10A19}-\\x{10A35}\\x{10A36}-\\x{10A37}\\x{10A38}-\\x{10A3A}\\x{10A3B}-\\x{10A3E}\\x{10A3F}\\x{10A40}-\\x{10A48}\\x{10A49}-\\x{10A4F}\\x{10A50}-\\x{10A58}\\x{10A59}-\\x{10A5F}\\x{10A60}-\\x{10A7C}\\x{10A7D}-\\x{10A7E}\\x{10A7F}\\x{10A80}-\\x{10A9C}\\x{10A9D}-\\x{10A9F}\\x{10AA0}-\\x{10ABF}\\x{10AC0}-\\x{10AC7}\\x{10AC8}\\x{10AC9}-\\x{10AE4}\\x{10AE5}-\\x{10AE6}\\x{10AE7}-\\x{10AEA}\\x{10AEB}-\\x{10AEF}\\x{10AF0}-\\x{10AF6}\\x{10AF7}-\\x{10AFF}\\x{10B00}-\\x{10B35}\\x{10B36}-\\x{10B38}\\x{10B39}-\\x{10B3F}\\x{10B40}-\\x{10B55}\\x{10B56}-\\x{10B57}\\x{10B58}-\\x{10B5F}\\x{10B60}-\\x{10B72}\\x{10B73}-\\x{10B77}\\x{10B78}-\\x{10B7F}\\x{10B80}-\\x{10B91}\\x{10B92}-\\x{10B98}\\x{10B99}-\\x{10B9C}\\x{10B9D}-\\x{10BA8}\\x{10BA9}-\\x{10BAF}\\x{10BB0}-\\x{10BFF}\\x{10C00}-\\x{10C48}\\x{10C49}-\\x{10C7F}\\x{10C80}-\\x{10CB2}\\x{10CB3}-\\x{10CBF}\\x{10CC0}-\\x{10CF2}\\x{10CF3}-\\x{10CF9}\\x{10CFA}-\\x{10CFF}\\x{10D00}-\\x{10D23}\\x{10D24}-\\x{10D27}\\x{10D28}-\\x{10D2F}\\x{10D30}-\\x{10D39}\\x{10D3A}-\\x{10D3F}\\x{10D40}-\\x{10E5F}\\x{10E60}-\\x{10E7E}\\x{10E7F}\\x{10E80}-\\x{10EA9}\\x{10EAA}\\x{10EAB}-\\x{10EAC}\\x{10EAD}\\x{10EAE}-\\x{10EAF}\\x{10EB0}-\\x{10EB1}\\x{10EB2}-\\x{10EFF}\\x{10F00}-\\x{10F1C}\\x{10F1D}-\\x{10F26}\\x{10F27}\\x{10F28}-\\x{10F2F}\\x{10F30}-\\x{10F45}\\x{10F46}-\\x{10F50}\\x{10F51}-\\x{10F54}\\x{10F55}-\\x{10F59}\\x{10F5A}-\\x{10F6F}\\x{10F70}-\\x{10FAF}\\x{10FB0}-\\x{10FC4}\\x{10FC5}-\\x{10FCB}\\x{10FCC}-\\x{10FDF}\\x{10FE0}-\\x{10FF6}\\x{10FF7}-\\x{10FFF}\\x{11001}\\x{11038}-\\x{11046}\\x{11052}-\\x{11065}\\x{1107F}-\\x{11081}\\x{110B3}-\\x{110B6}\\x{110B9}-\\x{110BA}\\x{11100}-\\x{11102}\\x{11127}-\\x{1112B}\\x{1112D}-\\x{11134}\\x{11173}\\x{11180}-\\x{11181}\\x{111B6}-\\x{111BE}\\x{111C9}-\\x{111CC}\\x{111CF}\\x{1122F}-\\x{11231}\\x{11234}\\x{11236}-\\x{11237}\\x{1123E}\\x{112DF}\\x{112E3}-\\x{112EA}\\x{11300}-\\x{11301}\\x{1133B}-\\x{1133C}\\x{11340}\\x{11366}-\\x{1136C}\\x{11370}-\\x{11374}\\x{11438}-\\x{1143F}\\x{11442}-\\x{11444}\\x{11446}\\x{1145E}\\x{114B3}-\\x{114B8}\\x{114BA}\\x{114BF}-\\x{114C0}\\x{114C2}-\\x{114C3}\\x{115B2}-\\x{115B5}\\x{115BC}-\\x{115BD}\\x{115BF}-\\x{115C0}\\x{115DC}-\\x{115DD}\\x{11633}-\\x{1163A}\\x{1163D}\\x{1163F}-\\x{11640}\\x{11660}-\\x{1166C}\\x{116AB}\\x{116AD}\\x{116B0}-\\x{116B5}\\x{116B7}\\x{1171D}-\\x{1171F}\\x{11722}-\\x{11725}\\x{11727}-\\x{1172B}\\x{1182F}-\\x{11837}\\x{11839}-\\x{1183A}\\x{1193B}-\\x{1193C}\\x{1193E}\\x{11943}\\x{119D4}-\\x{119D7}\\x{119DA}-\\x{119DB}\\x{119E0}\\x{11A01}-\\x{11A06}\\x{11A09}-\\x{11A0A}\\x{11A33}-\\x{11A38}\\x{11A3B}-\\x{11A3E}\\x{11A47}\\x{11A51}-\\x{11A56}\\x{11A59}-\\x{11A5B}\\x{11A8A}-\\x{11A96}\\x{11A98}-\\x{11A99}\\x{11C30}-\\x{11C36}\\x{11C38}-\\x{11C3D}\\x{11C92}-\\x{11CA7}\\x{11CAA}-\\x{11CB0}\\x{11CB2}-\\x{11CB3}\\x{11CB5}-\\x{11CB6}\\x{11D31}-\\x{11D36}\\x{11D3A}\\x{11D3C}-\\x{11D3D}\\x{11D3F}-\\x{11D45}\\x{11D47}\\x{11D90}-\\x{11D91}\\x{11D95}\\x{11D97}\\x{11EF3}-\\x{11EF4}\\x{11FD5}-\\x{11FDC}\\x{11FDD}-\\x{11FE0}\\x{11FE1}-\\x{11FF1}\\x{16AF0}-\\x{16AF4}\\x{16B30}-\\x{16B36}\\x{16F4F}\\x{16F8F}-\\x{16F92}\\x{16FE2}\\x{16FE4}\\x{1BC9D}-\\x{1BC9E}\\x{1BCA0}-\\x{1BCA3}\\x{1D167}-\\x{1D169}\\x{1D173}-\\x{1D17A}\\x{1D17B}-\\x{1D182}\\x{1D185}-\\x{1D18B}\\x{1D1AA}-\\x{1D1AD}\\x{1D200}-\\x{1D241}\\x{1D242}-\\x{1D244}\\x{1D245}\\x{1D300}-\\x{1D356}\\x{1D6DB}\\x{1D715}\\x{1D74F}\\x{1D789}\\x{1D7C3}\\x{1D7CE}-\\x{1D7FF}\\x{1DA00}-\\x{1DA36}\\x{1DA3B}-\\x{1DA6C}\\x{1DA75}\\x{1DA84}\\x{1DA9B}-\\x{1DA9F}\\x{1DAA1}-\\x{1DAAF}\\x{1E000}-\\x{1E006}\\x{1E008}-\\x{1E018}\\x{1E01B}-\\x{1E021}\\x{1E023}-\\x{1E024}\\x{1E026}-\\x{1E02A}\\x{1E130}-\\x{1E136}\\x{1E2EC}-\\x{1E2EF}\\x{1E2FF}\\x{1E800}-\\x{1E8C4}\\x{1E8C5}-\\x{1E8C6}\\x{1E8C7}-\\x{1E8CF}\\x{1E8D0}-\\x{1E8D6}\\x{1E8D7}-\\x{1E8FF}\\x{1E900}-\\x{1E943}\\x{1E944}-\\x{1E94A}\\x{1E94B}\\x{1E94C}-\\x{1E94F}\\x{1E950}-\\x{1E959}\\x{1E95A}-\\x{1E95D}\\x{1E95E}-\\x{1E95F}\\x{1E960}-\\x{1EC6F}\\x{1EC70}\\x{1EC71}-\\x{1ECAB}\\x{1ECAC}\\x{1ECAD}-\\x{1ECAF}\\x{1ECB0}\\x{1ECB1}-\\x{1ECB4}\\x{1ECB5}-\\x{1ECBF}\\x{1ECC0}-\\x{1ECFF}\\x{1ED00}\\x{1ED01}-\\x{1ED2D}\\x{1ED2E}\\x{1ED2F}-\\x{1ED3D}\\x{1ED3E}-\\x{1ED4F}\\x{1ED50}-\\x{1EDFF}\\x{1EE00}-\\x{1EE03}\\x{1EE04}\\x{1EE05}-\\x{1EE1F}\\x{1EE20}\\x{1EE21}-\\x{1EE22}\\x{1EE23}\\x{1EE24}\\x{1EE25}-\\x{1EE26}\\x{1EE27}\\x{1EE28}\\x{1EE29}-\\x{1EE32}\\x{1EE33}\\x{1EE34}-\\x{1EE37}\\x{1EE38}\\x{1EE39}\\x{1EE3A}\\x{1EE3B}\\x{1EE3C}-\\x{1EE41}\\x{1EE42}\\x{1EE43}-\\x{1EE46}\\x{1EE47}\\x{1EE48}\\x{1EE49}\\x{1EE4A}\\x{1EE4B}\\x{1EE4C}\\x{1EE4D}-\\x{1EE4F}\\x{1EE50}\\x{1EE51}-\\x{1EE52}\\x{1EE53}\\x{1EE54}\\x{1EE55}-\\x{1EE56}\\x{1EE57}\\x{1EE58}\\x{1EE59}\\x{1EE5A}\\x{1EE5B}\\x{1EE5C}\\x{1EE5D}\\x{1EE5E}\\x{1EE5F}\\x{1EE60}\\x{1EE61}-\\x{1EE62}\\x{1EE63}\\x{1EE64}\\x{1EE65}-\\x{1EE66}\\x{1EE67}-\\x{1EE6A}\\x{1EE6B}\\x{1EE6C}-\\x{1EE72}\\x{1EE73}\\x{1EE74}-\\x{1EE77}\\x{1EE78}\\x{1EE79}-\\x{1EE7C}\\x{1EE7D}\\x{1EE7E}\\x{1EE7F}\\x{1EE80}-\\x{1EE89}\\x{1EE8A}\\x{1EE8B}-\\x{1EE9B}\\x{1EE9C}-\\x{1EEA0}\\x{1EEA1}-\\x{1EEA3}\\x{1EEA4}\\x{1EEA5}-\\x{1EEA9}\\x{1EEAA}\\x{1EEAB}-\\x{1EEBB}\\x{1EEBC}-\\x{1EEEF}\\x{1EEF0}-\\x{1EEF1}\\x{1EEF2}-\\x{1EEFF}\\x{1EF00}-\\x{1EFFF}\\x{1F000}-\\x{1F02B}\\x{1F030}-\\x{1F093}\\x{1F0A0}-\\x{1F0AE}\\x{1F0B1}-\\x{1F0BF}\\x{1F0C1}-\\x{1F0CF}\\x{1F0D1}-\\x{1F0F5}\\x{1F100}-\\x{1F10A}\\x{1F10B}-\\x{1F10C}\\x{1F10D}-\\x{1F10F}\\x{1F12F}\\x{1F16A}-\\x{1F16F}\\x{1F1AD}\\x{1F260}-\\x{1F265}\\x{1F300}-\\x{1F3FA}\\x{1F3FB}-\\x{1F3FF}\\x{1F400}-\\x{1F6D7}\\x{1F6E0}-\\x{1F6EC}\\x{1F6F0}-\\x{1F6FC}\\x{1F700}-\\x{1F773}\\x{1F780}-\\x{1F7D8}\\x{1F7E0}-\\x{1F7EB}\\x{1F800}-\\x{1F80B}\\x{1F810}-\\x{1F847}\\x{1F850}-\\x{1F859}\\x{1F860}-\\x{1F887}\\x{1F890}-\\x{1F8AD}\\x{1F8B0}-\\x{1F8B1}\\x{1F900}-\\x{1F978}\\x{1F97A}-\\x{1F9CB}\\x{1F9CD}-\\x{1FA53}\\x{1FA60}-\\x{1FA6D}\\x{1FA70}-\\x{1FA74}\\x{1FA78}-\\x{1FA7A}\\x{1FA80}-\\x{1FA86}\\x{1FA90}-\\x{1FAA8}\\x{1FAB0}-\\x{1FAB6}\\x{1FAC0}-\\x{1FAC2}\\x{1FAD0}-\\x{1FAD6}\\x{1FB00}-\\x{1FB92}\\x{1FB94}-\\x{1FBCA}\\x{1FBF0}-\\x{1FBF9}\\x{1FFFE}-\\x{1FFFF}\\x{2FFFE}-\\x{2FFFF}\\x{3FFFE}-\\x{3FFFF}\\x{4FFFE}-\\x{4FFFF}\\x{5FFFE}-\\x{5FFFF}\\x{6FFFE}-\\x{6FFFF}\\x{7FFFE}-\\x{7FFFF}\\x{8FFFE}-\\x{8FFFF}\\x{9FFFE}-\\x{9FFFF}\\x{AFFFE}-\\x{AFFFF}\\x{BFFFE}-\\x{BFFFF}\\x{CFFFE}-\\x{CFFFF}\\x{DFFFE}-\\x{E0000}\\x{E0001}\\x{E0002}-\\x{E001F}\\x{E0020}-\\x{E007F}\\x{E0080}-\\x{E00FF}\\x{E0100}-\\x{E01EF}\\x{E01F0}-\\x{E0FFF}\\x{EFFFE}-\\x{EFFFF}\\x{FFFFE}-\\x{FFFFF}\\x{10FFFE}-\\x{10FFFF}]/u';\n    const BIDI_STEP_1_RTL = '/^[\\x{0590}\\x{05BE}\\x{05C0}\\x{05C3}\\x{05C6}\\x{05C8}-\\x{05CF}\\x{05D0}-\\x{05EA}\\x{05EB}-\\x{05EE}\\x{05EF}-\\x{05F2}\\x{05F3}-\\x{05F4}\\x{05F5}-\\x{05FF}\\x{0608}\\x{060B}\\x{060D}\\x{061B}\\x{061C}\\x{061D}\\x{061E}-\\x{061F}\\x{0620}-\\x{063F}\\x{0640}\\x{0641}-\\x{064A}\\x{066D}\\x{066E}-\\x{066F}\\x{0671}-\\x{06D3}\\x{06D4}\\x{06D5}\\x{06E5}-\\x{06E6}\\x{06EE}-\\x{06EF}\\x{06FA}-\\x{06FC}\\x{06FD}-\\x{06FE}\\x{06FF}\\x{0700}-\\x{070D}\\x{070E}\\x{070F}\\x{0710}\\x{0712}-\\x{072F}\\x{074B}-\\x{074C}\\x{074D}-\\x{07A5}\\x{07B1}\\x{07B2}-\\x{07BF}\\x{07C0}-\\x{07C9}\\x{07CA}-\\x{07EA}\\x{07F4}-\\x{07F5}\\x{07FA}\\x{07FB}-\\x{07FC}\\x{07FE}-\\x{07FF}\\x{0800}-\\x{0815}\\x{081A}\\x{0824}\\x{0828}\\x{082E}-\\x{082F}\\x{0830}-\\x{083E}\\x{083F}\\x{0840}-\\x{0858}\\x{085C}-\\x{085D}\\x{085E}\\x{085F}\\x{0860}-\\x{086A}\\x{086B}-\\x{086F}\\x{0870}-\\x{089F}\\x{08A0}-\\x{08B4}\\x{08B5}\\x{08B6}-\\x{08C7}\\x{08C8}-\\x{08D2}\\x{200F}\\x{FB1D}\\x{FB1F}-\\x{FB28}\\x{FB2A}-\\x{FB36}\\x{FB37}\\x{FB38}-\\x{FB3C}\\x{FB3D}\\x{FB3E}\\x{FB3F}\\x{FB40}-\\x{FB41}\\x{FB42}\\x{FB43}-\\x{FB44}\\x{FB45}\\x{FB46}-\\x{FB4F}\\x{FB50}-\\x{FBB1}\\x{FBB2}-\\x{FBC1}\\x{FBC2}-\\x{FBD2}\\x{FBD3}-\\x{FD3D}\\x{FD40}-\\x{FD4F}\\x{FD50}-\\x{FD8F}\\x{FD90}-\\x{FD91}\\x{FD92}-\\x{FDC7}\\x{FDC8}-\\x{FDCF}\\x{FDF0}-\\x{FDFB}\\x{FDFC}\\x{FDFE}-\\x{FDFF}\\x{FE70}-\\x{FE74}\\x{FE75}\\x{FE76}-\\x{FEFC}\\x{FEFD}-\\x{FEFE}\\x{10800}-\\x{10805}\\x{10806}-\\x{10807}\\x{10808}\\x{10809}\\x{1080A}-\\x{10835}\\x{10836}\\x{10837}-\\x{10838}\\x{10839}-\\x{1083B}\\x{1083C}\\x{1083D}-\\x{1083E}\\x{1083F}-\\x{10855}\\x{10856}\\x{10857}\\x{10858}-\\x{1085F}\\x{10860}-\\x{10876}\\x{10877}-\\x{10878}\\x{10879}-\\x{1087F}\\x{10880}-\\x{1089E}\\x{1089F}-\\x{108A6}\\x{108A7}-\\x{108AF}\\x{108B0}-\\x{108DF}\\x{108E0}-\\x{108F2}\\x{108F3}\\x{108F4}-\\x{108F5}\\x{108F6}-\\x{108FA}\\x{108FB}-\\x{108FF}\\x{10900}-\\x{10915}\\x{10916}-\\x{1091B}\\x{1091C}-\\x{1091E}\\x{10920}-\\x{10939}\\x{1093A}-\\x{1093E}\\x{1093F}\\x{10940}-\\x{1097F}\\x{10980}-\\x{109B7}\\x{109B8}-\\x{109BB}\\x{109BC}-\\x{109BD}\\x{109BE}-\\x{109BF}\\x{109C0}-\\x{109CF}\\x{109D0}-\\x{109D1}\\x{109D2}-\\x{109FF}\\x{10A00}\\x{10A04}\\x{10A07}-\\x{10A0B}\\x{10A10}-\\x{10A13}\\x{10A14}\\x{10A15}-\\x{10A17}\\x{10A18}\\x{10A19}-\\x{10A35}\\x{10A36}-\\x{10A37}\\x{10A3B}-\\x{10A3E}\\x{10A40}-\\x{10A48}\\x{10A49}-\\x{10A4F}\\x{10A50}-\\x{10A58}\\x{10A59}-\\x{10A5F}\\x{10A60}-\\x{10A7C}\\x{10A7D}-\\x{10A7E}\\x{10A7F}\\x{10A80}-\\x{10A9C}\\x{10A9D}-\\x{10A9F}\\x{10AA0}-\\x{10ABF}\\x{10AC0}-\\x{10AC7}\\x{10AC8}\\x{10AC9}-\\x{10AE4}\\x{10AE7}-\\x{10AEA}\\x{10AEB}-\\x{10AEF}\\x{10AF0}-\\x{10AF6}\\x{10AF7}-\\x{10AFF}\\x{10B00}-\\x{10B35}\\x{10B36}-\\x{10B38}\\x{10B40}-\\x{10B55}\\x{10B56}-\\x{10B57}\\x{10B58}-\\x{10B5F}\\x{10B60}-\\x{10B72}\\x{10B73}-\\x{10B77}\\x{10B78}-\\x{10B7F}\\x{10B80}-\\x{10B91}\\x{10B92}-\\x{10B98}\\x{10B99}-\\x{10B9C}\\x{10B9D}-\\x{10BA8}\\x{10BA9}-\\x{10BAF}\\x{10BB0}-\\x{10BFF}\\x{10C00}-\\x{10C48}\\x{10C49}-\\x{10C7F}\\x{10C80}-\\x{10CB2}\\x{10CB3}-\\x{10CBF}\\x{10CC0}-\\x{10CF2}\\x{10CF3}-\\x{10CF9}\\x{10CFA}-\\x{10CFF}\\x{10D00}-\\x{10D23}\\x{10D28}-\\x{10D2F}\\x{10D3A}-\\x{10D3F}\\x{10D40}-\\x{10E5F}\\x{10E7F}\\x{10E80}-\\x{10EA9}\\x{10EAA}\\x{10EAD}\\x{10EAE}-\\x{10EAF}\\x{10EB0}-\\x{10EB1}\\x{10EB2}-\\x{10EFF}\\x{10F00}-\\x{10F1C}\\x{10F1D}-\\x{10F26}\\x{10F27}\\x{10F28}-\\x{10F2F}\\x{10F30}-\\x{10F45}\\x{10F51}-\\x{10F54}\\x{10F55}-\\x{10F59}\\x{10F5A}-\\x{10F6F}\\x{10F70}-\\x{10FAF}\\x{10FB0}-\\x{10FC4}\\x{10FC5}-\\x{10FCB}\\x{10FCC}-\\x{10FDF}\\x{10FE0}-\\x{10FF6}\\x{10FF7}-\\x{10FFF}\\x{1E800}-\\x{1E8C4}\\x{1E8C5}-\\x{1E8C6}\\x{1E8C7}-\\x{1E8CF}\\x{1E8D7}-\\x{1E8FF}\\x{1E900}-\\x{1E943}\\x{1E94B}\\x{1E94C}-\\x{1E94F}\\x{1E950}-\\x{1E959}\\x{1E95A}-\\x{1E95D}\\x{1E95E}-\\x{1E95F}\\x{1E960}-\\x{1EC6F}\\x{1EC70}\\x{1EC71}-\\x{1ECAB}\\x{1ECAC}\\x{1ECAD}-\\x{1ECAF}\\x{1ECB0}\\x{1ECB1}-\\x{1ECB4}\\x{1ECB5}-\\x{1ECBF}\\x{1ECC0}-\\x{1ECFF}\\x{1ED00}\\x{1ED01}-\\x{1ED2D}\\x{1ED2E}\\x{1ED2F}-\\x{1ED3D}\\x{1ED3E}-\\x{1ED4F}\\x{1ED50}-\\x{1EDFF}\\x{1EE00}-\\x{1EE03}\\x{1EE04}\\x{1EE05}-\\x{1EE1F}\\x{1EE20}\\x{1EE21}-\\x{1EE22}\\x{1EE23}\\x{1EE24}\\x{1EE25}-\\x{1EE26}\\x{1EE27}\\x{1EE28}\\x{1EE29}-\\x{1EE32}\\x{1EE33}\\x{1EE34}-\\x{1EE37}\\x{1EE38}\\x{1EE39}\\x{1EE3A}\\x{1EE3B}\\x{1EE3C}-\\x{1EE41}\\x{1EE42}\\x{1EE43}-\\x{1EE46}\\x{1EE47}\\x{1EE48}\\x{1EE49}\\x{1EE4A}\\x{1EE4B}\\x{1EE4C}\\x{1EE4D}-\\x{1EE4F}\\x{1EE50}\\x{1EE51}-\\x{1EE52}\\x{1EE53}\\x{1EE54}\\x{1EE55}-\\x{1EE56}\\x{1EE57}\\x{1EE58}\\x{1EE59}\\x{1EE5A}\\x{1EE5B}\\x{1EE5C}\\x{1EE5D}\\x{1EE5E}\\x{1EE5F}\\x{1EE60}\\x{1EE61}-\\x{1EE62}\\x{1EE63}\\x{1EE64}\\x{1EE65}-\\x{1EE66}\\x{1EE67}-\\x{1EE6A}\\x{1EE6B}\\x{1EE6C}-\\x{1EE72}\\x{1EE73}\\x{1EE74}-\\x{1EE77}\\x{1EE78}\\x{1EE79}-\\x{1EE7C}\\x{1EE7D}\\x{1EE7E}\\x{1EE7F}\\x{1EE80}-\\x{1EE89}\\x{1EE8A}\\x{1EE8B}-\\x{1EE9B}\\x{1EE9C}-\\x{1EEA0}\\x{1EEA1}-\\x{1EEA3}\\x{1EEA4}\\x{1EEA5}-\\x{1EEA9}\\x{1EEAA}\\x{1EEAB}-\\x{1EEBB}\\x{1EEBC}-\\x{1EEEF}\\x{1EEF2}-\\x{1EEFF}\\x{1EF00}-\\x{1EFFF}]/u';\n    const BIDI_STEP_2 = '/[^\\x{0000}-\\x{0008}\\x{000E}-\\x{001B}\\x{0021}-\\x{0022}\\x{0023}\\x{0024}\\x{0025}\\x{0026}-\\x{0027}\\x{0028}\\x{0029}\\x{002A}\\x{002B}\\x{002C}\\x{002D}\\x{002E}-\\x{002F}\\x{0030}-\\x{0039}\\x{003A}\\x{003B}\\x{003C}-\\x{003E}\\x{003F}-\\x{0040}\\x{005B}\\x{005C}\\x{005D}\\x{005E}\\x{005F}\\x{0060}\\x{007B}\\x{007C}\\x{007D}\\x{007E}\\x{007F}-\\x{0084}\\x{0086}-\\x{009F}\\x{00A0}\\x{00A1}\\x{00A2}-\\x{00A5}\\x{00A6}\\x{00A7}\\x{00A8}\\x{00A9}\\x{00AB}\\x{00AC}\\x{00AD}\\x{00AE}\\x{00AF}\\x{00B0}\\x{00B1}\\x{00B2}-\\x{00B3}\\x{00B4}\\x{00B6}-\\x{00B7}\\x{00B8}\\x{00B9}\\x{00BB}\\x{00BC}-\\x{00BE}\\x{00BF}\\x{00D7}\\x{00F7}\\x{02B9}-\\x{02BA}\\x{02C2}-\\x{02C5}\\x{02C6}-\\x{02CF}\\x{02D2}-\\x{02DF}\\x{02E5}-\\x{02EB}\\x{02EC}\\x{02ED}\\x{02EF}-\\x{02FF}\\x{0300}-\\x{036F}\\x{0374}\\x{0375}\\x{037E}\\x{0384}-\\x{0385}\\x{0387}\\x{03F6}\\x{0483}-\\x{0487}\\x{0488}-\\x{0489}\\x{058A}\\x{058D}-\\x{058E}\\x{058F}\\x{0590}\\x{0591}-\\x{05BD}\\x{05BE}\\x{05BF}\\x{05C0}\\x{05C1}-\\x{05C2}\\x{05C3}\\x{05C4}-\\x{05C5}\\x{05C6}\\x{05C7}\\x{05C8}-\\x{05CF}\\x{05D0}-\\x{05EA}\\x{05EB}-\\x{05EE}\\x{05EF}-\\x{05F2}\\x{05F3}-\\x{05F4}\\x{05F5}-\\x{05FF}\\x{0600}-\\x{0605}\\x{0606}-\\x{0607}\\x{0608}\\x{0609}-\\x{060A}\\x{060B}\\x{060C}\\x{060D}\\x{060E}-\\x{060F}\\x{0610}-\\x{061A}\\x{061B}\\x{061C}\\x{061D}\\x{061E}-\\x{061F}\\x{0620}-\\x{063F}\\x{0640}\\x{0641}-\\x{064A}\\x{064B}-\\x{065F}\\x{0660}-\\x{0669}\\x{066A}\\x{066B}-\\x{066C}\\x{066D}\\x{066E}-\\x{066F}\\x{0670}\\x{0671}-\\x{06D3}\\x{06D4}\\x{06D5}\\x{06D6}-\\x{06DC}\\x{06DD}\\x{06DE}\\x{06DF}-\\x{06E4}\\x{06E5}-\\x{06E6}\\x{06E7}-\\x{06E8}\\x{06E9}\\x{06EA}-\\x{06ED}\\x{06EE}-\\x{06EF}\\x{06F0}-\\x{06F9}\\x{06FA}-\\x{06FC}\\x{06FD}-\\x{06FE}\\x{06FF}\\x{0700}-\\x{070D}\\x{070E}\\x{070F}\\x{0710}\\x{0711}\\x{0712}-\\x{072F}\\x{0730}-\\x{074A}\\x{074B}-\\x{074C}\\x{074D}-\\x{07A5}\\x{07A6}-\\x{07B0}\\x{07B1}\\x{07B2}-\\x{07BF}\\x{07C0}-\\x{07C9}\\x{07CA}-\\x{07EA}\\x{07EB}-\\x{07F3}\\x{07F4}-\\x{07F5}\\x{07F6}\\x{07F7}-\\x{07F9}\\x{07FA}\\x{07FB}-\\x{07FC}\\x{07FD}\\x{07FE}-\\x{07FF}\\x{0800}-\\x{0815}\\x{0816}-\\x{0819}\\x{081A}\\x{081B}-\\x{0823}\\x{0824}\\x{0825}-\\x{0827}\\x{0828}\\x{0829}-\\x{082D}\\x{082E}-\\x{082F}\\x{0830}-\\x{083E}\\x{083F}\\x{0840}-\\x{0858}\\x{0859}-\\x{085B}\\x{085C}-\\x{085D}\\x{085E}\\x{085F}\\x{0860}-\\x{086A}\\x{086B}-\\x{086F}\\x{0870}-\\x{089F}\\x{08A0}-\\x{08B4}\\x{08B5}\\x{08B6}-\\x{08C7}\\x{08C8}-\\x{08D2}\\x{08D3}-\\x{08E1}\\x{08E2}\\x{08E3}-\\x{0902}\\x{093A}\\x{093C}\\x{0941}-\\x{0948}\\x{094D}\\x{0951}-\\x{0957}\\x{0962}-\\x{0963}\\x{0981}\\x{09BC}\\x{09C1}-\\x{09C4}\\x{09CD}\\x{09E2}-\\x{09E3}\\x{09F2}-\\x{09F3}\\x{09FB}\\x{09FE}\\x{0A01}-\\x{0A02}\\x{0A3C}\\x{0A41}-\\x{0A42}\\x{0A47}-\\x{0A48}\\x{0A4B}-\\x{0A4D}\\x{0A51}\\x{0A70}-\\x{0A71}\\x{0A75}\\x{0A81}-\\x{0A82}\\x{0ABC}\\x{0AC1}-\\x{0AC5}\\x{0AC7}-\\x{0AC8}\\x{0ACD}\\x{0AE2}-\\x{0AE3}\\x{0AF1}\\x{0AFA}-\\x{0AFF}\\x{0B01}\\x{0B3C}\\x{0B3F}\\x{0B41}-\\x{0B44}\\x{0B4D}\\x{0B55}-\\x{0B56}\\x{0B62}-\\x{0B63}\\x{0B82}\\x{0BC0}\\x{0BCD}\\x{0BF3}-\\x{0BF8}\\x{0BF9}\\x{0BFA}\\x{0C00}\\x{0C04}\\x{0C3E}-\\x{0C40}\\x{0C46}-\\x{0C48}\\x{0C4A}-\\x{0C4D}\\x{0C55}-\\x{0C56}\\x{0C62}-\\x{0C63}\\x{0C78}-\\x{0C7E}\\x{0C81}\\x{0CBC}\\x{0CCC}-\\x{0CCD}\\x{0CE2}-\\x{0CE3}\\x{0D00}-\\x{0D01}\\x{0D3B}-\\x{0D3C}\\x{0D41}-\\x{0D44}\\x{0D4D}\\x{0D62}-\\x{0D63}\\x{0D81}\\x{0DCA}\\x{0DD2}-\\x{0DD4}\\x{0DD6}\\x{0E31}\\x{0E34}-\\x{0E3A}\\x{0E3F}\\x{0E47}-\\x{0E4E}\\x{0EB1}\\x{0EB4}-\\x{0EBC}\\x{0EC8}-\\x{0ECD}\\x{0F18}-\\x{0F19}\\x{0F35}\\x{0F37}\\x{0F39}\\x{0F3A}\\x{0F3B}\\x{0F3C}\\x{0F3D}\\x{0F71}-\\x{0F7E}\\x{0F80}-\\x{0F84}\\x{0F86}-\\x{0F87}\\x{0F8D}-\\x{0F97}\\x{0F99}-\\x{0FBC}\\x{0FC6}\\x{102D}-\\x{1030}\\x{1032}-\\x{1037}\\x{1039}-\\x{103A}\\x{103D}-\\x{103E}\\x{1058}-\\x{1059}\\x{105E}-\\x{1060}\\x{1071}-\\x{1074}\\x{1082}\\x{1085}-\\x{1086}\\x{108D}\\x{109D}\\x{135D}-\\x{135F}\\x{1390}-\\x{1399}\\x{1400}\\x{169B}\\x{169C}\\x{1712}-\\x{1714}\\x{1732}-\\x{1734}\\x{1752}-\\x{1753}\\x{1772}-\\x{1773}\\x{17B4}-\\x{17B5}\\x{17B7}-\\x{17BD}\\x{17C6}\\x{17C9}-\\x{17D3}\\x{17DB}\\x{17DD}\\x{17F0}-\\x{17F9}\\x{1800}-\\x{1805}\\x{1806}\\x{1807}-\\x{180A}\\x{180B}-\\x{180D}\\x{180E}\\x{1885}-\\x{1886}\\x{18A9}\\x{1920}-\\x{1922}\\x{1927}-\\x{1928}\\x{1932}\\x{1939}-\\x{193B}\\x{1940}\\x{1944}-\\x{1945}\\x{19DE}-\\x{19FF}\\x{1A17}-\\x{1A18}\\x{1A1B}\\x{1A56}\\x{1A58}-\\x{1A5E}\\x{1A60}\\x{1A62}\\x{1A65}-\\x{1A6C}\\x{1A73}-\\x{1A7C}\\x{1A7F}\\x{1AB0}-\\x{1ABD}\\x{1ABE}\\x{1ABF}-\\x{1AC0}\\x{1B00}-\\x{1B03}\\x{1B34}\\x{1B36}-\\x{1B3A}\\x{1B3C}\\x{1B42}\\x{1B6B}-\\x{1B73}\\x{1B80}-\\x{1B81}\\x{1BA2}-\\x{1BA5}\\x{1BA8}-\\x{1BA9}\\x{1BAB}-\\x{1BAD}\\x{1BE6}\\x{1BE8}-\\x{1BE9}\\x{1BED}\\x{1BEF}-\\x{1BF1}\\x{1C2C}-\\x{1C33}\\x{1C36}-\\x{1C37}\\x{1CD0}-\\x{1CD2}\\x{1CD4}-\\x{1CE0}\\x{1CE2}-\\x{1CE8}\\x{1CED}\\x{1CF4}\\x{1CF8}-\\x{1CF9}\\x{1DC0}-\\x{1DF9}\\x{1DFB}-\\x{1DFF}\\x{1FBD}\\x{1FBF}-\\x{1FC1}\\x{1FCD}-\\x{1FCF}\\x{1FDD}-\\x{1FDF}\\x{1FED}-\\x{1FEF}\\x{1FFD}-\\x{1FFE}\\x{200B}-\\x{200D}\\x{200F}\\x{2010}-\\x{2015}\\x{2016}-\\x{2017}\\x{2018}\\x{2019}\\x{201A}\\x{201B}-\\x{201C}\\x{201D}\\x{201E}\\x{201F}\\x{2020}-\\x{2027}\\x{202F}\\x{2030}-\\x{2034}\\x{2035}-\\x{2038}\\x{2039}\\x{203A}\\x{203B}-\\x{203E}\\x{203F}-\\x{2040}\\x{2041}-\\x{2043}\\x{2044}\\x{2045}\\x{2046}\\x{2047}-\\x{2051}\\x{2052}\\x{2053}\\x{2054}\\x{2055}-\\x{205E}\\x{2060}-\\x{2064}\\x{2065}\\x{206A}-\\x{206F}\\x{2070}\\x{2074}-\\x{2079}\\x{207A}-\\x{207B}\\x{207C}\\x{207D}\\x{207E}\\x{2080}-\\x{2089}\\x{208A}-\\x{208B}\\x{208C}\\x{208D}\\x{208E}\\x{20A0}-\\x{20BF}\\x{20C0}-\\x{20CF}\\x{20D0}-\\x{20DC}\\x{20DD}-\\x{20E0}\\x{20E1}\\x{20E2}-\\x{20E4}\\x{20E5}-\\x{20F0}\\x{2100}-\\x{2101}\\x{2103}-\\x{2106}\\x{2108}-\\x{2109}\\x{2114}\\x{2116}-\\x{2117}\\x{2118}\\x{211E}-\\x{2123}\\x{2125}\\x{2127}\\x{2129}\\x{212E}\\x{213A}-\\x{213B}\\x{2140}-\\x{2144}\\x{214A}\\x{214B}\\x{214C}-\\x{214D}\\x{2150}-\\x{215F}\\x{2189}\\x{218A}-\\x{218B}\\x{2190}-\\x{2194}\\x{2195}-\\x{2199}\\x{219A}-\\x{219B}\\x{219C}-\\x{219F}\\x{21A0}\\x{21A1}-\\x{21A2}\\x{21A3}\\x{21A4}-\\x{21A5}\\x{21A6}\\x{21A7}-\\x{21AD}\\x{21AE}\\x{21AF}-\\x{21CD}\\x{21CE}-\\x{21CF}\\x{21D0}-\\x{21D1}\\x{21D2}\\x{21D3}\\x{21D4}\\x{21D5}-\\x{21F3}\\x{21F4}-\\x{2211}\\x{2212}\\x{2213}\\x{2214}-\\x{22FF}\\x{2300}-\\x{2307}\\x{2308}\\x{2309}\\x{230A}\\x{230B}\\x{230C}-\\x{231F}\\x{2320}-\\x{2321}\\x{2322}-\\x{2328}\\x{2329}\\x{232A}\\x{232B}-\\x{2335}\\x{237B}\\x{237C}\\x{237D}-\\x{2394}\\x{2396}-\\x{239A}\\x{239B}-\\x{23B3}\\x{23B4}-\\x{23DB}\\x{23DC}-\\x{23E1}\\x{23E2}-\\x{2426}\\x{2440}-\\x{244A}\\x{2460}-\\x{2487}\\x{2488}-\\x{249B}\\x{24EA}-\\x{24FF}\\x{2500}-\\x{25B6}\\x{25B7}\\x{25B8}-\\x{25C0}\\x{25C1}\\x{25C2}-\\x{25F7}\\x{25F8}-\\x{25FF}\\x{2600}-\\x{266E}\\x{266F}\\x{2670}-\\x{26AB}\\x{26AD}-\\x{2767}\\x{2768}\\x{2769}\\x{276A}\\x{276B}\\x{276C}\\x{276D}\\x{276E}\\x{276F}\\x{2770}\\x{2771}\\x{2772}\\x{2773}\\x{2774}\\x{2775}\\x{2776}-\\x{2793}\\x{2794}-\\x{27BF}\\x{27C0}-\\x{27C4}\\x{27C5}\\x{27C6}\\x{27C7}-\\x{27E5}\\x{27E6}\\x{27E7}\\x{27E8}\\x{27E9}\\x{27EA}\\x{27EB}\\x{27EC}\\x{27ED}\\x{27EE}\\x{27EF}\\x{27F0}-\\x{27FF}\\x{2900}-\\x{2982}\\x{2983}\\x{2984}\\x{2985}\\x{2986}\\x{2987}\\x{2988}\\x{2989}\\x{298A}\\x{298B}\\x{298C}\\x{298D}\\x{298E}\\x{298F}\\x{2990}\\x{2991}\\x{2992}\\x{2993}\\x{2994}\\x{2995}\\x{2996}\\x{2997}\\x{2998}\\x{2999}-\\x{29D7}\\x{29D8}\\x{29D9}\\x{29DA}\\x{29DB}\\x{29DC}-\\x{29FB}\\x{29FC}\\x{29FD}\\x{29FE}-\\x{2AFF}\\x{2B00}-\\x{2B2F}\\x{2B30}-\\x{2B44}\\x{2B45}-\\x{2B46}\\x{2B47}-\\x{2B4C}\\x{2B4D}-\\x{2B73}\\x{2B76}-\\x{2B95}\\x{2B97}-\\x{2BFF}\\x{2CE5}-\\x{2CEA}\\x{2CEF}-\\x{2CF1}\\x{2CF9}-\\x{2CFC}\\x{2CFD}\\x{2CFE}-\\x{2CFF}\\x{2D7F}\\x{2DE0}-\\x{2DFF}\\x{2E00}-\\x{2E01}\\x{2E02}\\x{2E03}\\x{2E04}\\x{2E05}\\x{2E06}-\\x{2E08}\\x{2E09}\\x{2E0A}\\x{2E0B}\\x{2E0C}\\x{2E0D}\\x{2E0E}-\\x{2E16}\\x{2E17}\\x{2E18}-\\x{2E19}\\x{2E1A}\\x{2E1B}\\x{2E1C}\\x{2E1D}\\x{2E1E}-\\x{2E1F}\\x{2E20}\\x{2E21}\\x{2E22}\\x{2E23}\\x{2E24}\\x{2E25}\\x{2E26}\\x{2E27}\\x{2E28}\\x{2E29}\\x{2E2A}-\\x{2E2E}\\x{2E2F}\\x{2E30}-\\x{2E39}\\x{2E3A}-\\x{2E3B}\\x{2E3C}-\\x{2E3F}\\x{2E40}\\x{2E41}\\x{2E42}\\x{2E43}-\\x{2E4F}\\x{2E50}-\\x{2E51}\\x{2E52}\\x{2E80}-\\x{2E99}\\x{2E9B}-\\x{2EF3}\\x{2F00}-\\x{2FD5}\\x{2FF0}-\\x{2FFB}\\x{3001}-\\x{3003}\\x{3004}\\x{3008}\\x{3009}\\x{300A}\\x{300B}\\x{300C}\\x{300D}\\x{300E}\\x{300F}\\x{3010}\\x{3011}\\x{3012}-\\x{3013}\\x{3014}\\x{3015}\\x{3016}\\x{3017}\\x{3018}\\x{3019}\\x{301A}\\x{301B}\\x{301C}\\x{301D}\\x{301E}-\\x{301F}\\x{3020}\\x{302A}-\\x{302D}\\x{3030}\\x{3036}-\\x{3037}\\x{303D}\\x{303E}-\\x{303F}\\x{3099}-\\x{309A}\\x{309B}-\\x{309C}\\x{30A0}\\x{30FB}\\x{31C0}-\\x{31E3}\\x{321D}-\\x{321E}\\x{3250}\\x{3251}-\\x{325F}\\x{327C}-\\x{327E}\\x{32B1}-\\x{32BF}\\x{32CC}-\\x{32CF}\\x{3377}-\\x{337A}\\x{33DE}-\\x{33DF}\\x{33FF}\\x{4DC0}-\\x{4DFF}\\x{A490}-\\x{A4C6}\\x{A60D}-\\x{A60F}\\x{A66F}\\x{A670}-\\x{A672}\\x{A673}\\x{A674}-\\x{A67D}\\x{A67E}\\x{A67F}\\x{A69E}-\\x{A69F}\\x{A6F0}-\\x{A6F1}\\x{A700}-\\x{A716}\\x{A717}-\\x{A71F}\\x{A720}-\\x{A721}\\x{A788}\\x{A802}\\x{A806}\\x{A80B}\\x{A825}-\\x{A826}\\x{A828}-\\x{A82B}\\x{A82C}\\x{A838}\\x{A839}\\x{A874}-\\x{A877}\\x{A8C4}-\\x{A8C5}\\x{A8E0}-\\x{A8F1}\\x{A8FF}\\x{A926}-\\x{A92D}\\x{A947}-\\x{A951}\\x{A980}-\\x{A982}\\x{A9B3}\\x{A9B6}-\\x{A9B9}\\x{A9BC}-\\x{A9BD}\\x{A9E5}\\x{AA29}-\\x{AA2E}\\x{AA31}-\\x{AA32}\\x{AA35}-\\x{AA36}\\x{AA43}\\x{AA4C}\\x{AA7C}\\x{AAB0}\\x{AAB2}-\\x{AAB4}\\x{AAB7}-\\x{AAB8}\\x{AABE}-\\x{AABF}\\x{AAC1}\\x{AAEC}-\\x{AAED}\\x{AAF6}\\x{AB6A}-\\x{AB6B}\\x{ABE5}\\x{ABE8}\\x{ABED}\\x{FB1D}\\x{FB1E}\\x{FB1F}-\\x{FB28}\\x{FB29}\\x{FB2A}-\\x{FB36}\\x{FB37}\\x{FB38}-\\x{FB3C}\\x{FB3D}\\x{FB3E}\\x{FB3F}\\x{FB40}-\\x{FB41}\\x{FB42}\\x{FB43}-\\x{FB44}\\x{FB45}\\x{FB46}-\\x{FB4F}\\x{FB50}-\\x{FBB1}\\x{FBB2}-\\x{FBC1}\\x{FBC2}-\\x{FBD2}\\x{FBD3}-\\x{FD3D}\\x{FD3E}\\x{FD3F}\\x{FD40}-\\x{FD4F}\\x{FD50}-\\x{FD8F}\\x{FD90}-\\x{FD91}\\x{FD92}-\\x{FDC7}\\x{FDC8}-\\x{FDCF}\\x{FDD0}-\\x{FDEF}\\x{FDF0}-\\x{FDFB}\\x{FDFC}\\x{FDFD}\\x{FDFE}-\\x{FDFF}\\x{FE00}-\\x{FE0F}\\x{FE10}-\\x{FE16}\\x{FE17}\\x{FE18}\\x{FE19}\\x{FE20}-\\x{FE2F}\\x{FE30}\\x{FE31}-\\x{FE32}\\x{FE33}-\\x{FE34}\\x{FE35}\\x{FE36}\\x{FE37}\\x{FE38}\\x{FE39}\\x{FE3A}\\x{FE3B}\\x{FE3C}\\x{FE3D}\\x{FE3E}\\x{FE3F}\\x{FE40}\\x{FE41}\\x{FE42}\\x{FE43}\\x{FE44}\\x{FE45}-\\x{FE46}\\x{FE47}\\x{FE48}\\x{FE49}-\\x{FE4C}\\x{FE4D}-\\x{FE4F}\\x{FE50}\\x{FE51}\\x{FE52}\\x{FE54}\\x{FE55}\\x{FE56}-\\x{FE57}\\x{FE58}\\x{FE59}\\x{FE5A}\\x{FE5B}\\x{FE5C}\\x{FE5D}\\x{FE5E}\\x{FE5F}\\x{FE60}-\\x{FE61}\\x{FE62}\\x{FE63}\\x{FE64}-\\x{FE66}\\x{FE68}\\x{FE69}\\x{FE6A}\\x{FE6B}\\x{FE70}-\\x{FE74}\\x{FE75}\\x{FE76}-\\x{FEFC}\\x{FEFD}-\\x{FEFE}\\x{FEFF}\\x{FF01}-\\x{FF02}\\x{FF03}\\x{FF04}\\x{FF05}\\x{FF06}-\\x{FF07}\\x{FF08}\\x{FF09}\\x{FF0A}\\x{FF0B}\\x{FF0C}\\x{FF0D}\\x{FF0E}-\\x{FF0F}\\x{FF10}-\\x{FF19}\\x{FF1A}\\x{FF1B}\\x{FF1C}-\\x{FF1E}\\x{FF1F}-\\x{FF20}\\x{FF3B}\\x{FF3C}\\x{FF3D}\\x{FF3E}\\x{FF3F}\\x{FF40}\\x{FF5B}\\x{FF5C}\\x{FF5D}\\x{FF5E}\\x{FF5F}\\x{FF60}\\x{FF61}\\x{FF62}\\x{FF63}\\x{FF64}-\\x{FF65}\\x{FFE0}-\\x{FFE1}\\x{FFE2}\\x{FFE3}\\x{FFE4}\\x{FFE5}-\\x{FFE6}\\x{FFE8}\\x{FFE9}-\\x{FFEC}\\x{FFED}-\\x{FFEE}\\x{FFF0}-\\x{FFF8}\\x{FFF9}-\\x{FFFB}\\x{FFFC}-\\x{FFFD}\\x{FFFE}-\\x{FFFF}\\x{10101}\\x{10140}-\\x{10174}\\x{10175}-\\x{10178}\\x{10179}-\\x{10189}\\x{1018A}-\\x{1018B}\\x{1018C}\\x{10190}-\\x{1019C}\\x{101A0}\\x{101FD}\\x{102E0}\\x{102E1}-\\x{102FB}\\x{10376}-\\x{1037A}\\x{10800}-\\x{10805}\\x{10806}-\\x{10807}\\x{10808}\\x{10809}\\x{1080A}-\\x{10835}\\x{10836}\\x{10837}-\\x{10838}\\x{10839}-\\x{1083B}\\x{1083C}\\x{1083D}-\\x{1083E}\\x{1083F}-\\x{10855}\\x{10856}\\x{10857}\\x{10858}-\\x{1085F}\\x{10860}-\\x{10876}\\x{10877}-\\x{10878}\\x{10879}-\\x{1087F}\\x{10880}-\\x{1089E}\\x{1089F}-\\x{108A6}\\x{108A7}-\\x{108AF}\\x{108B0}-\\x{108DF}\\x{108E0}-\\x{108F2}\\x{108F3}\\x{108F4}-\\x{108F5}\\x{108F6}-\\x{108FA}\\x{108FB}-\\x{108FF}\\x{10900}-\\x{10915}\\x{10916}-\\x{1091B}\\x{1091C}-\\x{1091E}\\x{1091F}\\x{10920}-\\x{10939}\\x{1093A}-\\x{1093E}\\x{1093F}\\x{10940}-\\x{1097F}\\x{10980}-\\x{109B7}\\x{109B8}-\\x{109BB}\\x{109BC}-\\x{109BD}\\x{109BE}-\\x{109BF}\\x{109C0}-\\x{109CF}\\x{109D0}-\\x{109D1}\\x{109D2}-\\x{109FF}\\x{10A00}\\x{10A01}-\\x{10A03}\\x{10A04}\\x{10A05}-\\x{10A06}\\x{10A07}-\\x{10A0B}\\x{10A0C}-\\x{10A0F}\\x{10A10}-\\x{10A13}\\x{10A14}\\x{10A15}-\\x{10A17}\\x{10A18}\\x{10A19}-\\x{10A35}\\x{10A36}-\\x{10A37}\\x{10A38}-\\x{10A3A}\\x{10A3B}-\\x{10A3E}\\x{10A3F}\\x{10A40}-\\x{10A48}\\x{10A49}-\\x{10A4F}\\x{10A50}-\\x{10A58}\\x{10A59}-\\x{10A5F}\\x{10A60}-\\x{10A7C}\\x{10A7D}-\\x{10A7E}\\x{10A7F}\\x{10A80}-\\x{10A9C}\\x{10A9D}-\\x{10A9F}\\x{10AA0}-\\x{10ABF}\\x{10AC0}-\\x{10AC7}\\x{10AC8}\\x{10AC9}-\\x{10AE4}\\x{10AE5}-\\x{10AE6}\\x{10AE7}-\\x{10AEA}\\x{10AEB}-\\x{10AEF}\\x{10AF0}-\\x{10AF6}\\x{10AF7}-\\x{10AFF}\\x{10B00}-\\x{10B35}\\x{10B36}-\\x{10B38}\\x{10B39}-\\x{10B3F}\\x{10B40}-\\x{10B55}\\x{10B56}-\\x{10B57}\\x{10B58}-\\x{10B5F}\\x{10B60}-\\x{10B72}\\x{10B73}-\\x{10B77}\\x{10B78}-\\x{10B7F}\\x{10B80}-\\x{10B91}\\x{10B92}-\\x{10B98}\\x{10B99}-\\x{10B9C}\\x{10B9D}-\\x{10BA8}\\x{10BA9}-\\x{10BAF}\\x{10BB0}-\\x{10BFF}\\x{10C00}-\\x{10C48}\\x{10C49}-\\x{10C7F}\\x{10C80}-\\x{10CB2}\\x{10CB3}-\\x{10CBF}\\x{10CC0}-\\x{10CF2}\\x{10CF3}-\\x{10CF9}\\x{10CFA}-\\x{10CFF}\\x{10D00}-\\x{10D23}\\x{10D24}-\\x{10D27}\\x{10D28}-\\x{10D2F}\\x{10D30}-\\x{10D39}\\x{10D3A}-\\x{10D3F}\\x{10D40}-\\x{10E5F}\\x{10E60}-\\x{10E7E}\\x{10E7F}\\x{10E80}-\\x{10EA9}\\x{10EAA}\\x{10EAB}-\\x{10EAC}\\x{10EAD}\\x{10EAE}-\\x{10EAF}\\x{10EB0}-\\x{10EB1}\\x{10EB2}-\\x{10EFF}\\x{10F00}-\\x{10F1C}\\x{10F1D}-\\x{10F26}\\x{10F27}\\x{10F28}-\\x{10F2F}\\x{10F30}-\\x{10F45}\\x{10F46}-\\x{10F50}\\x{10F51}-\\x{10F54}\\x{10F55}-\\x{10F59}\\x{10F5A}-\\x{10F6F}\\x{10F70}-\\x{10FAF}\\x{10FB0}-\\x{10FC4}\\x{10FC5}-\\x{10FCB}\\x{10FCC}-\\x{10FDF}\\x{10FE0}-\\x{10FF6}\\x{10FF7}-\\x{10FFF}\\x{11001}\\x{11038}-\\x{11046}\\x{11052}-\\x{11065}\\x{1107F}-\\x{11081}\\x{110B3}-\\x{110B6}\\x{110B9}-\\x{110BA}\\x{11100}-\\x{11102}\\x{11127}-\\x{1112B}\\x{1112D}-\\x{11134}\\x{11173}\\x{11180}-\\x{11181}\\x{111B6}-\\x{111BE}\\x{111C9}-\\x{111CC}\\x{111CF}\\x{1122F}-\\x{11231}\\x{11234}\\x{11236}-\\x{11237}\\x{1123E}\\x{112DF}\\x{112E3}-\\x{112EA}\\x{11300}-\\x{11301}\\x{1133B}-\\x{1133C}\\x{11340}\\x{11366}-\\x{1136C}\\x{11370}-\\x{11374}\\x{11438}-\\x{1143F}\\x{11442}-\\x{11444}\\x{11446}\\x{1145E}\\x{114B3}-\\x{114B8}\\x{114BA}\\x{114BF}-\\x{114C0}\\x{114C2}-\\x{114C3}\\x{115B2}-\\x{115B5}\\x{115BC}-\\x{115BD}\\x{115BF}-\\x{115C0}\\x{115DC}-\\x{115DD}\\x{11633}-\\x{1163A}\\x{1163D}\\x{1163F}-\\x{11640}\\x{11660}-\\x{1166C}\\x{116AB}\\x{116AD}\\x{116B0}-\\x{116B5}\\x{116B7}\\x{1171D}-\\x{1171F}\\x{11722}-\\x{11725}\\x{11727}-\\x{1172B}\\x{1182F}-\\x{11837}\\x{11839}-\\x{1183A}\\x{1193B}-\\x{1193C}\\x{1193E}\\x{11943}\\x{119D4}-\\x{119D7}\\x{119DA}-\\x{119DB}\\x{119E0}\\x{11A01}-\\x{11A06}\\x{11A09}-\\x{11A0A}\\x{11A33}-\\x{11A38}\\x{11A3B}-\\x{11A3E}\\x{11A47}\\x{11A51}-\\x{11A56}\\x{11A59}-\\x{11A5B}\\x{11A8A}-\\x{11A96}\\x{11A98}-\\x{11A99}\\x{11C30}-\\x{11C36}\\x{11C38}-\\x{11C3D}\\x{11C92}-\\x{11CA7}\\x{11CAA}-\\x{11CB0}\\x{11CB2}-\\x{11CB3}\\x{11CB5}-\\x{11CB6}\\x{11D31}-\\x{11D36}\\x{11D3A}\\x{11D3C}-\\x{11D3D}\\x{11D3F}-\\x{11D45}\\x{11D47}\\x{11D90}-\\x{11D91}\\x{11D95}\\x{11D97}\\x{11EF3}-\\x{11EF4}\\x{11FD5}-\\x{11FDC}\\x{11FDD}-\\x{11FE0}\\x{11FE1}-\\x{11FF1}\\x{16AF0}-\\x{16AF4}\\x{16B30}-\\x{16B36}\\x{16F4F}\\x{16F8F}-\\x{16F92}\\x{16FE2}\\x{16FE4}\\x{1BC9D}-\\x{1BC9E}\\x{1BCA0}-\\x{1BCA3}\\x{1D167}-\\x{1D169}\\x{1D173}-\\x{1D17A}\\x{1D17B}-\\x{1D182}\\x{1D185}-\\x{1D18B}\\x{1D1AA}-\\x{1D1AD}\\x{1D200}-\\x{1D241}\\x{1D242}-\\x{1D244}\\x{1D245}\\x{1D300}-\\x{1D356}\\x{1D6DB}\\x{1D715}\\x{1D74F}\\x{1D789}\\x{1D7C3}\\x{1D7CE}-\\x{1D7FF}\\x{1DA00}-\\x{1DA36}\\x{1DA3B}-\\x{1DA6C}\\x{1DA75}\\x{1DA84}\\x{1DA9B}-\\x{1DA9F}\\x{1DAA1}-\\x{1DAAF}\\x{1E000}-\\x{1E006}\\x{1E008}-\\x{1E018}\\x{1E01B}-\\x{1E021}\\x{1E023}-\\x{1E024}\\x{1E026}-\\x{1E02A}\\x{1E130}-\\x{1E136}\\x{1E2EC}-\\x{1E2EF}\\x{1E2FF}\\x{1E800}-\\x{1E8C4}\\x{1E8C5}-\\x{1E8C6}\\x{1E8C7}-\\x{1E8CF}\\x{1E8D0}-\\x{1E8D6}\\x{1E8D7}-\\x{1E8FF}\\x{1E900}-\\x{1E943}\\x{1E944}-\\x{1E94A}\\x{1E94B}\\x{1E94C}-\\x{1E94F}\\x{1E950}-\\x{1E959}\\x{1E95A}-\\x{1E95D}\\x{1E95E}-\\x{1E95F}\\x{1E960}-\\x{1EC6F}\\x{1EC70}\\x{1EC71}-\\x{1ECAB}\\x{1ECAC}\\x{1ECAD}-\\x{1ECAF}\\x{1ECB0}\\x{1ECB1}-\\x{1ECB4}\\x{1ECB5}-\\x{1ECBF}\\x{1ECC0}-\\x{1ECFF}\\x{1ED00}\\x{1ED01}-\\x{1ED2D}\\x{1ED2E}\\x{1ED2F}-\\x{1ED3D}\\x{1ED3E}-\\x{1ED4F}\\x{1ED50}-\\x{1EDFF}\\x{1EE00}-\\x{1EE03}\\x{1EE04}\\x{1EE05}-\\x{1EE1F}\\x{1EE20}\\x{1EE21}-\\x{1EE22}\\x{1EE23}\\x{1EE24}\\x{1EE25}-\\x{1EE26}\\x{1EE27}\\x{1EE28}\\x{1EE29}-\\x{1EE32}\\x{1EE33}\\x{1EE34}-\\x{1EE37}\\x{1EE38}\\x{1EE39}\\x{1EE3A}\\x{1EE3B}\\x{1EE3C}-\\x{1EE41}\\x{1EE42}\\x{1EE43}-\\x{1EE46}\\x{1EE47}\\x{1EE48}\\x{1EE49}\\x{1EE4A}\\x{1EE4B}\\x{1EE4C}\\x{1EE4D}-\\x{1EE4F}\\x{1EE50}\\x{1EE51}-\\x{1EE52}\\x{1EE53}\\x{1EE54}\\x{1EE55}-\\x{1EE56}\\x{1EE57}\\x{1EE58}\\x{1EE59}\\x{1EE5A}\\x{1EE5B}\\x{1EE5C}\\x{1EE5D}\\x{1EE5E}\\x{1EE5F}\\x{1EE60}\\x{1EE61}-\\x{1EE62}\\x{1EE63}\\x{1EE64}\\x{1EE65}-\\x{1EE66}\\x{1EE67}-\\x{1EE6A}\\x{1EE6B}\\x{1EE6C}-\\x{1EE72}\\x{1EE73}\\x{1EE74}-\\x{1EE77}\\x{1EE78}\\x{1EE79}-\\x{1EE7C}\\x{1EE7D}\\x{1EE7E}\\x{1EE7F}\\x{1EE80}-\\x{1EE89}\\x{1EE8A}\\x{1EE8B}-\\x{1EE9B}\\x{1EE9C}-\\x{1EEA0}\\x{1EEA1}-\\x{1EEA3}\\x{1EEA4}\\x{1EEA5}-\\x{1EEA9}\\x{1EEAA}\\x{1EEAB}-\\x{1EEBB}\\x{1EEBC}-\\x{1EEEF}\\x{1EEF0}-\\x{1EEF1}\\x{1EEF2}-\\x{1EEFF}\\x{1EF00}-\\x{1EFFF}\\x{1F000}-\\x{1F02B}\\x{1F030}-\\x{1F093}\\x{1F0A0}-\\x{1F0AE}\\x{1F0B1}-\\x{1F0BF}\\x{1F0C1}-\\x{1F0CF}\\x{1F0D1}-\\x{1F0F5}\\x{1F100}-\\x{1F10A}\\x{1F10B}-\\x{1F10C}\\x{1F10D}-\\x{1F10F}\\x{1F12F}\\x{1F16A}-\\x{1F16F}\\x{1F1AD}\\x{1F260}-\\x{1F265}\\x{1F300}-\\x{1F3FA}\\x{1F3FB}-\\x{1F3FF}\\x{1F400}-\\x{1F6D7}\\x{1F6E0}-\\x{1F6EC}\\x{1F6F0}-\\x{1F6FC}\\x{1F700}-\\x{1F773}\\x{1F780}-\\x{1F7D8}\\x{1F7E0}-\\x{1F7EB}\\x{1F800}-\\x{1F80B}\\x{1F810}-\\x{1F847}\\x{1F850}-\\x{1F859}\\x{1F860}-\\x{1F887}\\x{1F890}-\\x{1F8AD}\\x{1F8B0}-\\x{1F8B1}\\x{1F900}-\\x{1F978}\\x{1F97A}-\\x{1F9CB}\\x{1F9CD}-\\x{1FA53}\\x{1FA60}-\\x{1FA6D}\\x{1FA70}-\\x{1FA74}\\x{1FA78}-\\x{1FA7A}\\x{1FA80}-\\x{1FA86}\\x{1FA90}-\\x{1FAA8}\\x{1FAB0}-\\x{1FAB6}\\x{1FAC0}-\\x{1FAC2}\\x{1FAD0}-\\x{1FAD6}\\x{1FB00}-\\x{1FB92}\\x{1FB94}-\\x{1FBCA}\\x{1FBF0}-\\x{1FBF9}\\x{1FFFE}-\\x{1FFFF}\\x{2FFFE}-\\x{2FFFF}\\x{3FFFE}-\\x{3FFFF}\\x{4FFFE}-\\x{4FFFF}\\x{5FFFE}-\\x{5FFFF}\\x{6FFFE}-\\x{6FFFF}\\x{7FFFE}-\\x{7FFFF}\\x{8FFFE}-\\x{8FFFF}\\x{9FFFE}-\\x{9FFFF}\\x{AFFFE}-\\x{AFFFF}\\x{BFFFE}-\\x{BFFFF}\\x{CFFFE}-\\x{CFFFF}\\x{DFFFE}-\\x{E0000}\\x{E0001}\\x{E0002}-\\x{E001F}\\x{E0020}-\\x{E007F}\\x{E0080}-\\x{E00FF}\\x{E0100}-\\x{E01EF}\\x{E01F0}-\\x{E0FFF}\\x{EFFFE}-\\x{EFFFF}\\x{FFFFE}-\\x{FFFFF}\\x{10FFFE}-\\x{10FFFF}]/u';\n    const BIDI_STEP_3 = '/[\\x{0030}-\\x{0039}\\x{00B2}-\\x{00B3}\\x{00B9}\\x{0590}\\x{05BE}\\x{05C0}\\x{05C3}\\x{05C6}\\x{05C8}-\\x{05CF}\\x{05D0}-\\x{05EA}\\x{05EB}-\\x{05EE}\\x{05EF}-\\x{05F2}\\x{05F3}-\\x{05F4}\\x{05F5}-\\x{05FF}\\x{0600}-\\x{0605}\\x{0608}\\x{060B}\\x{060D}\\x{061B}\\x{061C}\\x{061D}\\x{061E}-\\x{061F}\\x{0620}-\\x{063F}\\x{0640}\\x{0641}-\\x{064A}\\x{0660}-\\x{0669}\\x{066B}-\\x{066C}\\x{066D}\\x{066E}-\\x{066F}\\x{0671}-\\x{06D3}\\x{06D4}\\x{06D5}\\x{06DD}\\x{06E5}-\\x{06E6}\\x{06EE}-\\x{06EF}\\x{06F0}-\\x{06F9}\\x{06FA}-\\x{06FC}\\x{06FD}-\\x{06FE}\\x{06FF}\\x{0700}-\\x{070D}\\x{070E}\\x{070F}\\x{0710}\\x{0712}-\\x{072F}\\x{074B}-\\x{074C}\\x{074D}-\\x{07A5}\\x{07B1}\\x{07B2}-\\x{07BF}\\x{07C0}-\\x{07C9}\\x{07CA}-\\x{07EA}\\x{07F4}-\\x{07F5}\\x{07FA}\\x{07FB}-\\x{07FC}\\x{07FE}-\\x{07FF}\\x{0800}-\\x{0815}\\x{081A}\\x{0824}\\x{0828}\\x{082E}-\\x{082F}\\x{0830}-\\x{083E}\\x{083F}\\x{0840}-\\x{0858}\\x{085C}-\\x{085D}\\x{085E}\\x{085F}\\x{0860}-\\x{086A}\\x{086B}-\\x{086F}\\x{0870}-\\x{089F}\\x{08A0}-\\x{08B4}\\x{08B5}\\x{08B6}-\\x{08C7}\\x{08C8}-\\x{08D2}\\x{08E2}\\x{200F}\\x{2070}\\x{2074}-\\x{2079}\\x{2080}-\\x{2089}\\x{2488}-\\x{249B}\\x{FB1D}\\x{FB1F}-\\x{FB28}\\x{FB2A}-\\x{FB36}\\x{FB37}\\x{FB38}-\\x{FB3C}\\x{FB3D}\\x{FB3E}\\x{FB3F}\\x{FB40}-\\x{FB41}\\x{FB42}\\x{FB43}-\\x{FB44}\\x{FB45}\\x{FB46}-\\x{FB4F}\\x{FB50}-\\x{FBB1}\\x{FBB2}-\\x{FBC1}\\x{FBC2}-\\x{FBD2}\\x{FBD3}-\\x{FD3D}\\x{FD40}-\\x{FD4F}\\x{FD50}-\\x{FD8F}\\x{FD90}-\\x{FD91}\\x{FD92}-\\x{FDC7}\\x{FDC8}-\\x{FDCF}\\x{FDF0}-\\x{FDFB}\\x{FDFC}\\x{FDFE}-\\x{FDFF}\\x{FE70}-\\x{FE74}\\x{FE75}\\x{FE76}-\\x{FEFC}\\x{FEFD}-\\x{FEFE}\\x{FF10}-\\x{FF19}\\x{102E1}-\\x{102FB}\\x{10800}-\\x{10805}\\x{10806}-\\x{10807}\\x{10808}\\x{10809}\\x{1080A}-\\x{10835}\\x{10836}\\x{10837}-\\x{10838}\\x{10839}-\\x{1083B}\\x{1083C}\\x{1083D}-\\x{1083E}\\x{1083F}-\\x{10855}\\x{10856}\\x{10857}\\x{10858}-\\x{1085F}\\x{10860}-\\x{10876}\\x{10877}-\\x{10878}\\x{10879}-\\x{1087F}\\x{10880}-\\x{1089E}\\x{1089F}-\\x{108A6}\\x{108A7}-\\x{108AF}\\x{108B0}-\\x{108DF}\\x{108E0}-\\x{108F2}\\x{108F3}\\x{108F4}-\\x{108F5}\\x{108F6}-\\x{108FA}\\x{108FB}-\\x{108FF}\\x{10900}-\\x{10915}\\x{10916}-\\x{1091B}\\x{1091C}-\\x{1091E}\\x{10920}-\\x{10939}\\x{1093A}-\\x{1093E}\\x{1093F}\\x{10940}-\\x{1097F}\\x{10980}-\\x{109B7}\\x{109B8}-\\x{109BB}\\x{109BC}-\\x{109BD}\\x{109BE}-\\x{109BF}\\x{109C0}-\\x{109CF}\\x{109D0}-\\x{109D1}\\x{109D2}-\\x{109FF}\\x{10A00}\\x{10A04}\\x{10A07}-\\x{10A0B}\\x{10A10}-\\x{10A13}\\x{10A14}\\x{10A15}-\\x{10A17}\\x{10A18}\\x{10A19}-\\x{10A35}\\x{10A36}-\\x{10A37}\\x{10A3B}-\\x{10A3E}\\x{10A40}-\\x{10A48}\\x{10A49}-\\x{10A4F}\\x{10A50}-\\x{10A58}\\x{10A59}-\\x{10A5F}\\x{10A60}-\\x{10A7C}\\x{10A7D}-\\x{10A7E}\\x{10A7F}\\x{10A80}-\\x{10A9C}\\x{10A9D}-\\x{10A9F}\\x{10AA0}-\\x{10ABF}\\x{10AC0}-\\x{10AC7}\\x{10AC8}\\x{10AC9}-\\x{10AE4}\\x{10AE7}-\\x{10AEA}\\x{10AEB}-\\x{10AEF}\\x{10AF0}-\\x{10AF6}\\x{10AF7}-\\x{10AFF}\\x{10B00}-\\x{10B35}\\x{10B36}-\\x{10B38}\\x{10B40}-\\x{10B55}\\x{10B56}-\\x{10B57}\\x{10B58}-\\x{10B5F}\\x{10B60}-\\x{10B72}\\x{10B73}-\\x{10B77}\\x{10B78}-\\x{10B7F}\\x{10B80}-\\x{10B91}\\x{10B92}-\\x{10B98}\\x{10B99}-\\x{10B9C}\\x{10B9D}-\\x{10BA8}\\x{10BA9}-\\x{10BAF}\\x{10BB0}-\\x{10BFF}\\x{10C00}-\\x{10C48}\\x{10C49}-\\x{10C7F}\\x{10C80}-\\x{10CB2}\\x{10CB3}-\\x{10CBF}\\x{10CC0}-\\x{10CF2}\\x{10CF3}-\\x{10CF9}\\x{10CFA}-\\x{10CFF}\\x{10D00}-\\x{10D23}\\x{10D28}-\\x{10D2F}\\x{10D30}-\\x{10D39}\\x{10D3A}-\\x{10D3F}\\x{10D40}-\\x{10E5F}\\x{10E60}-\\x{10E7E}\\x{10E7F}\\x{10E80}-\\x{10EA9}\\x{10EAA}\\x{10EAD}\\x{10EAE}-\\x{10EAF}\\x{10EB0}-\\x{10EB1}\\x{10EB2}-\\x{10EFF}\\x{10F00}-\\x{10F1C}\\x{10F1D}-\\x{10F26}\\x{10F27}\\x{10F28}-\\x{10F2F}\\x{10F30}-\\x{10F45}\\x{10F51}-\\x{10F54}\\x{10F55}-\\x{10F59}\\x{10F5A}-\\x{10F6F}\\x{10F70}-\\x{10FAF}\\x{10FB0}-\\x{10FC4}\\x{10FC5}-\\x{10FCB}\\x{10FCC}-\\x{10FDF}\\x{10FE0}-\\x{10FF6}\\x{10FF7}-\\x{10FFF}\\x{1D7CE}-\\x{1D7FF}\\x{1E800}-\\x{1E8C4}\\x{1E8C5}-\\x{1E8C6}\\x{1E8C7}-\\x{1E8CF}\\x{1E8D7}-\\x{1E8FF}\\x{1E900}-\\x{1E943}\\x{1E94B}\\x{1E94C}-\\x{1E94F}\\x{1E950}-\\x{1E959}\\x{1E95A}-\\x{1E95D}\\x{1E95E}-\\x{1E95F}\\x{1E960}-\\x{1EC6F}\\x{1EC70}\\x{1EC71}-\\x{1ECAB}\\x{1ECAC}\\x{1ECAD}-\\x{1ECAF}\\x{1ECB0}\\x{1ECB1}-\\x{1ECB4}\\x{1ECB5}-\\x{1ECBF}\\x{1ECC0}-\\x{1ECFF}\\x{1ED00}\\x{1ED01}-\\x{1ED2D}\\x{1ED2E}\\x{1ED2F}-\\x{1ED3D}\\x{1ED3E}-\\x{1ED4F}\\x{1ED50}-\\x{1EDFF}\\x{1EE00}-\\x{1EE03}\\x{1EE04}\\x{1EE05}-\\x{1EE1F}\\x{1EE20}\\x{1EE21}-\\x{1EE22}\\x{1EE23}\\x{1EE24}\\x{1EE25}-\\x{1EE26}\\x{1EE27}\\x{1EE28}\\x{1EE29}-\\x{1EE32}\\x{1EE33}\\x{1EE34}-\\x{1EE37}\\x{1EE38}\\x{1EE39}\\x{1EE3A}\\x{1EE3B}\\x{1EE3C}-\\x{1EE41}\\x{1EE42}\\x{1EE43}-\\x{1EE46}\\x{1EE47}\\x{1EE48}\\x{1EE49}\\x{1EE4A}\\x{1EE4B}\\x{1EE4C}\\x{1EE4D}-\\x{1EE4F}\\x{1EE50}\\x{1EE51}-\\x{1EE52}\\x{1EE53}\\x{1EE54}\\x{1EE55}-\\x{1EE56}\\x{1EE57}\\x{1EE58}\\x{1EE59}\\x{1EE5A}\\x{1EE5B}\\x{1EE5C}\\x{1EE5D}\\x{1EE5E}\\x{1EE5F}\\x{1EE60}\\x{1EE61}-\\x{1EE62}\\x{1EE63}\\x{1EE64}\\x{1EE65}-\\x{1EE66}\\x{1EE67}-\\x{1EE6A}\\x{1EE6B}\\x{1EE6C}-\\x{1EE72}\\x{1EE73}\\x{1EE74}-\\x{1EE77}\\x{1EE78}\\x{1EE79}-\\x{1EE7C}\\x{1EE7D}\\x{1EE7E}\\x{1EE7F}\\x{1EE80}-\\x{1EE89}\\x{1EE8A}\\x{1EE8B}-\\x{1EE9B}\\x{1EE9C}-\\x{1EEA0}\\x{1EEA1}-\\x{1EEA3}\\x{1EEA4}\\x{1EEA5}-\\x{1EEA9}\\x{1EEAA}\\x{1EEAB}-\\x{1EEBB}\\x{1EEBC}-\\x{1EEEF}\\x{1EEF2}-\\x{1EEFF}\\x{1EF00}-\\x{1EFFF}\\x{1F100}-\\x{1F10A}\\x{1FBF0}-\\x{1FBF9}][\\x{0300}-\\x{036F}\\x{0483}-\\x{0487}\\x{0488}-\\x{0489}\\x{0591}-\\x{05BD}\\x{05BF}\\x{05C1}-\\x{05C2}\\x{05C4}-\\x{05C5}\\x{05C7}\\x{0610}-\\x{061A}\\x{064B}-\\x{065F}\\x{0670}\\x{06D6}-\\x{06DC}\\x{06DF}-\\x{06E4}\\x{06E7}-\\x{06E8}\\x{06EA}-\\x{06ED}\\x{0711}\\x{0730}-\\x{074A}\\x{07A6}-\\x{07B0}\\x{07EB}-\\x{07F3}\\x{07FD}\\x{0816}-\\x{0819}\\x{081B}-\\x{0823}\\x{0825}-\\x{0827}\\x{0829}-\\x{082D}\\x{0859}-\\x{085B}\\x{08D3}-\\x{08E1}\\x{08E3}-\\x{0902}\\x{093A}\\x{093C}\\x{0941}-\\x{0948}\\x{094D}\\x{0951}-\\x{0957}\\x{0962}-\\x{0963}\\x{0981}\\x{09BC}\\x{09C1}-\\x{09C4}\\x{09CD}\\x{09E2}-\\x{09E3}\\x{09FE}\\x{0A01}-\\x{0A02}\\x{0A3C}\\x{0A41}-\\x{0A42}\\x{0A47}-\\x{0A48}\\x{0A4B}-\\x{0A4D}\\x{0A51}\\x{0A70}-\\x{0A71}\\x{0A75}\\x{0A81}-\\x{0A82}\\x{0ABC}\\x{0AC1}-\\x{0AC5}\\x{0AC7}-\\x{0AC8}\\x{0ACD}\\x{0AE2}-\\x{0AE3}\\x{0AFA}-\\x{0AFF}\\x{0B01}\\x{0B3C}\\x{0B3F}\\x{0B41}-\\x{0B44}\\x{0B4D}\\x{0B55}-\\x{0B56}\\x{0B62}-\\x{0B63}\\x{0B82}\\x{0BC0}\\x{0BCD}\\x{0C00}\\x{0C04}\\x{0C3E}-\\x{0C40}\\x{0C46}-\\x{0C48}\\x{0C4A}-\\x{0C4D}\\x{0C55}-\\x{0C56}\\x{0C62}-\\x{0C63}\\x{0C81}\\x{0CBC}\\x{0CCC}-\\x{0CCD}\\x{0CE2}-\\x{0CE3}\\x{0D00}-\\x{0D01}\\x{0D3B}-\\x{0D3C}\\x{0D41}-\\x{0D44}\\x{0D4D}\\x{0D62}-\\x{0D63}\\x{0D81}\\x{0DCA}\\x{0DD2}-\\x{0DD4}\\x{0DD6}\\x{0E31}\\x{0E34}-\\x{0E3A}\\x{0E47}-\\x{0E4E}\\x{0EB1}\\x{0EB4}-\\x{0EBC}\\x{0EC8}-\\x{0ECD}\\x{0F18}-\\x{0F19}\\x{0F35}\\x{0F37}\\x{0F39}\\x{0F71}-\\x{0F7E}\\x{0F80}-\\x{0F84}\\x{0F86}-\\x{0F87}\\x{0F8D}-\\x{0F97}\\x{0F99}-\\x{0FBC}\\x{0FC6}\\x{102D}-\\x{1030}\\x{1032}-\\x{1037}\\x{1039}-\\x{103A}\\x{103D}-\\x{103E}\\x{1058}-\\x{1059}\\x{105E}-\\x{1060}\\x{1071}-\\x{1074}\\x{1082}\\x{1085}-\\x{1086}\\x{108D}\\x{109D}\\x{135D}-\\x{135F}\\x{1712}-\\x{1714}\\x{1732}-\\x{1734}\\x{1752}-\\x{1753}\\x{1772}-\\x{1773}\\x{17B4}-\\x{17B5}\\x{17B7}-\\x{17BD}\\x{17C6}\\x{17C9}-\\x{17D3}\\x{17DD}\\x{180B}-\\x{180D}\\x{1885}-\\x{1886}\\x{18A9}\\x{1920}-\\x{1922}\\x{1927}-\\x{1928}\\x{1932}\\x{1939}-\\x{193B}\\x{1A17}-\\x{1A18}\\x{1A1B}\\x{1A56}\\x{1A58}-\\x{1A5E}\\x{1A60}\\x{1A62}\\x{1A65}-\\x{1A6C}\\x{1A73}-\\x{1A7C}\\x{1A7F}\\x{1AB0}-\\x{1ABD}\\x{1ABE}\\x{1ABF}-\\x{1AC0}\\x{1B00}-\\x{1B03}\\x{1B34}\\x{1B36}-\\x{1B3A}\\x{1B3C}\\x{1B42}\\x{1B6B}-\\x{1B73}\\x{1B80}-\\x{1B81}\\x{1BA2}-\\x{1BA5}\\x{1BA8}-\\x{1BA9}\\x{1BAB}-\\x{1BAD}\\x{1BE6}\\x{1BE8}-\\x{1BE9}\\x{1BED}\\x{1BEF}-\\x{1BF1}\\x{1C2C}-\\x{1C33}\\x{1C36}-\\x{1C37}\\x{1CD0}-\\x{1CD2}\\x{1CD4}-\\x{1CE0}\\x{1CE2}-\\x{1CE8}\\x{1CED}\\x{1CF4}\\x{1CF8}-\\x{1CF9}\\x{1DC0}-\\x{1DF9}\\x{1DFB}-\\x{1DFF}\\x{20D0}-\\x{20DC}\\x{20DD}-\\x{20E0}\\x{20E1}\\x{20E2}-\\x{20E4}\\x{20E5}-\\x{20F0}\\x{2CEF}-\\x{2CF1}\\x{2D7F}\\x{2DE0}-\\x{2DFF}\\x{302A}-\\x{302D}\\x{3099}-\\x{309A}\\x{A66F}\\x{A670}-\\x{A672}\\x{A674}-\\x{A67D}\\x{A69E}-\\x{A69F}\\x{A6F0}-\\x{A6F1}\\x{A802}\\x{A806}\\x{A80B}\\x{A825}-\\x{A826}\\x{A82C}\\x{A8C4}-\\x{A8C5}\\x{A8E0}-\\x{A8F1}\\x{A8FF}\\x{A926}-\\x{A92D}\\x{A947}-\\x{A951}\\x{A980}-\\x{A982}\\x{A9B3}\\x{A9B6}-\\x{A9B9}\\x{A9BC}-\\x{A9BD}\\x{A9E5}\\x{AA29}-\\x{AA2E}\\x{AA31}-\\x{AA32}\\x{AA35}-\\x{AA36}\\x{AA43}\\x{AA4C}\\x{AA7C}\\x{AAB0}\\x{AAB2}-\\x{AAB4}\\x{AAB7}-\\x{AAB8}\\x{AABE}-\\x{AABF}\\x{AAC1}\\x{AAEC}-\\x{AAED}\\x{AAF6}\\x{ABE5}\\x{ABE8}\\x{ABED}\\x{FB1E}\\x{FE00}-\\x{FE0F}\\x{FE20}-\\x{FE2F}\\x{101FD}\\x{102E0}\\x{10376}-\\x{1037A}\\x{10A01}-\\x{10A03}\\x{10A05}-\\x{10A06}\\x{10A0C}-\\x{10A0F}\\x{10A38}-\\x{10A3A}\\x{10A3F}\\x{10AE5}-\\x{10AE6}\\x{10D24}-\\x{10D27}\\x{10EAB}-\\x{10EAC}\\x{10F46}-\\x{10F50}\\x{11001}\\x{11038}-\\x{11046}\\x{1107F}-\\x{11081}\\x{110B3}-\\x{110B6}\\x{110B9}-\\x{110BA}\\x{11100}-\\x{11102}\\x{11127}-\\x{1112B}\\x{1112D}-\\x{11134}\\x{11173}\\x{11180}-\\x{11181}\\x{111B6}-\\x{111BE}\\x{111C9}-\\x{111CC}\\x{111CF}\\x{1122F}-\\x{11231}\\x{11234}\\x{11236}-\\x{11237}\\x{1123E}\\x{112DF}\\x{112E3}-\\x{112EA}\\x{11300}-\\x{11301}\\x{1133B}-\\x{1133C}\\x{11340}\\x{11366}-\\x{1136C}\\x{11370}-\\x{11374}\\x{11438}-\\x{1143F}\\x{11442}-\\x{11444}\\x{11446}\\x{1145E}\\x{114B3}-\\x{114B8}\\x{114BA}\\x{114BF}-\\x{114C0}\\x{114C2}-\\x{114C3}\\x{115B2}-\\x{115B5}\\x{115BC}-\\x{115BD}\\x{115BF}-\\x{115C0}\\x{115DC}-\\x{115DD}\\x{11633}-\\x{1163A}\\x{1163D}\\x{1163F}-\\x{11640}\\x{116AB}\\x{116AD}\\x{116B0}-\\x{116B5}\\x{116B7}\\x{1171D}-\\x{1171F}\\x{11722}-\\x{11725}\\x{11727}-\\x{1172B}\\x{1182F}-\\x{11837}\\x{11839}-\\x{1183A}\\x{1193B}-\\x{1193C}\\x{1193E}\\x{11943}\\x{119D4}-\\x{119D7}\\x{119DA}-\\x{119DB}\\x{119E0}\\x{11A01}-\\x{11A06}\\x{11A09}-\\x{11A0A}\\x{11A33}-\\x{11A38}\\x{11A3B}-\\x{11A3E}\\x{11A47}\\x{11A51}-\\x{11A56}\\x{11A59}-\\x{11A5B}\\x{11A8A}-\\x{11A96}\\x{11A98}-\\x{11A99}\\x{11C30}-\\x{11C36}\\x{11C38}-\\x{11C3D}\\x{11C92}-\\x{11CA7}\\x{11CAA}-\\x{11CB0}\\x{11CB2}-\\x{11CB3}\\x{11CB5}-\\x{11CB6}\\x{11D31}-\\x{11D36}\\x{11D3A}\\x{11D3C}-\\x{11D3D}\\x{11D3F}-\\x{11D45}\\x{11D47}\\x{11D90}-\\x{11D91}\\x{11D95}\\x{11D97}\\x{11EF3}-\\x{11EF4}\\x{16AF0}-\\x{16AF4}\\x{16B30}-\\x{16B36}\\x{16F4F}\\x{16F8F}-\\x{16F92}\\x{16FE4}\\x{1BC9D}-\\x{1BC9E}\\x{1D167}-\\x{1D169}\\x{1D17B}-\\x{1D182}\\x{1D185}-\\x{1D18B}\\x{1D1AA}-\\x{1D1AD}\\x{1D242}-\\x{1D244}\\x{1DA00}-\\x{1DA36}\\x{1DA3B}-\\x{1DA6C}\\x{1DA75}\\x{1DA84}\\x{1DA9B}-\\x{1DA9F}\\x{1DAA1}-\\x{1DAAF}\\x{1E000}-\\x{1E006}\\x{1E008}-\\x{1E018}\\x{1E01B}-\\x{1E021}\\x{1E023}-\\x{1E024}\\x{1E026}-\\x{1E02A}\\x{1E130}-\\x{1E136}\\x{1E2EC}-\\x{1E2EF}\\x{1E8D0}-\\x{1E8D6}\\x{1E944}-\\x{1E94A}\\x{E0100}-\\x{E01EF}]*$/u';\n    const BIDI_STEP_4_AN = '/[\\x{0600}-\\x{0605}\\x{0660}-\\x{0669}\\x{066B}-\\x{066C}\\x{06DD}\\x{08E2}\\x{10D30}-\\x{10D39}\\x{10E60}-\\x{10E7E}]/u';\n    const BIDI_STEP_4_EN = '/[\\x{0030}-\\x{0039}\\x{00B2}-\\x{00B3}\\x{00B9}\\x{06F0}-\\x{06F9}\\x{2070}\\x{2074}-\\x{2079}\\x{2080}-\\x{2089}\\x{2488}-\\x{249B}\\x{FF10}-\\x{FF19}\\x{102E1}-\\x{102FB}\\x{1D7CE}-\\x{1D7FF}\\x{1F100}-\\x{1F10A}\\x{1FBF0}-\\x{1FBF9}]/u';\n    const BIDI_STEP_5 = '/[\\x{0009}\\x{000A}\\x{000B}\\x{000C}\\x{000D}\\x{001C}-\\x{001E}\\x{001F}\\x{0020}\\x{0085}\\x{0590}\\x{05BE}\\x{05C0}\\x{05C3}\\x{05C6}\\x{05C8}-\\x{05CF}\\x{05D0}-\\x{05EA}\\x{05EB}-\\x{05EE}\\x{05EF}-\\x{05F2}\\x{05F3}-\\x{05F4}\\x{05F5}-\\x{05FF}\\x{0600}-\\x{0605}\\x{0608}\\x{060B}\\x{060D}\\x{061B}\\x{061C}\\x{061D}\\x{061E}-\\x{061F}\\x{0620}-\\x{063F}\\x{0640}\\x{0641}-\\x{064A}\\x{0660}-\\x{0669}\\x{066B}-\\x{066C}\\x{066D}\\x{066E}-\\x{066F}\\x{0671}-\\x{06D3}\\x{06D4}\\x{06D5}\\x{06DD}\\x{06E5}-\\x{06E6}\\x{06EE}-\\x{06EF}\\x{06FA}-\\x{06FC}\\x{06FD}-\\x{06FE}\\x{06FF}\\x{0700}-\\x{070D}\\x{070E}\\x{070F}\\x{0710}\\x{0712}-\\x{072F}\\x{074B}-\\x{074C}\\x{074D}-\\x{07A5}\\x{07B1}\\x{07B2}-\\x{07BF}\\x{07C0}-\\x{07C9}\\x{07CA}-\\x{07EA}\\x{07F4}-\\x{07F5}\\x{07FA}\\x{07FB}-\\x{07FC}\\x{07FE}-\\x{07FF}\\x{0800}-\\x{0815}\\x{081A}\\x{0824}\\x{0828}\\x{082E}-\\x{082F}\\x{0830}-\\x{083E}\\x{083F}\\x{0840}-\\x{0858}\\x{085C}-\\x{085D}\\x{085E}\\x{085F}\\x{0860}-\\x{086A}\\x{086B}-\\x{086F}\\x{0870}-\\x{089F}\\x{08A0}-\\x{08B4}\\x{08B5}\\x{08B6}-\\x{08C7}\\x{08C8}-\\x{08D2}\\x{08E2}\\x{1680}\\x{2000}-\\x{200A}\\x{200F}\\x{2028}\\x{2029}\\x{202A}\\x{202B}\\x{202C}\\x{202D}\\x{202E}\\x{205F}\\x{2066}\\x{2067}\\x{2068}\\x{2069}\\x{3000}\\x{FB1D}\\x{FB1F}-\\x{FB28}\\x{FB2A}-\\x{FB36}\\x{FB37}\\x{FB38}-\\x{FB3C}\\x{FB3D}\\x{FB3E}\\x{FB3F}\\x{FB40}-\\x{FB41}\\x{FB42}\\x{FB43}-\\x{FB44}\\x{FB45}\\x{FB46}-\\x{FB4F}\\x{FB50}-\\x{FBB1}\\x{FBB2}-\\x{FBC1}\\x{FBC2}-\\x{FBD2}\\x{FBD3}-\\x{FD3D}\\x{FD40}-\\x{FD4F}\\x{FD50}-\\x{FD8F}\\x{FD90}-\\x{FD91}\\x{FD92}-\\x{FDC7}\\x{FDC8}-\\x{FDCF}\\x{FDF0}-\\x{FDFB}\\x{FDFC}\\x{FDFE}-\\x{FDFF}\\x{FE70}-\\x{FE74}\\x{FE75}\\x{FE76}-\\x{FEFC}\\x{FEFD}-\\x{FEFE}\\x{10800}-\\x{10805}\\x{10806}-\\x{10807}\\x{10808}\\x{10809}\\x{1080A}-\\x{10835}\\x{10836}\\x{10837}-\\x{10838}\\x{10839}-\\x{1083B}\\x{1083C}\\x{1083D}-\\x{1083E}\\x{1083F}-\\x{10855}\\x{10856}\\x{10857}\\x{10858}-\\x{1085F}\\x{10860}-\\x{10876}\\x{10877}-\\x{10878}\\x{10879}-\\x{1087F}\\x{10880}-\\x{1089E}\\x{1089F}-\\x{108A6}\\x{108A7}-\\x{108AF}\\x{108B0}-\\x{108DF}\\x{108E0}-\\x{108F2}\\x{108F3}\\x{108F4}-\\x{108F5}\\x{108F6}-\\x{108FA}\\x{108FB}-\\x{108FF}\\x{10900}-\\x{10915}\\x{10916}-\\x{1091B}\\x{1091C}-\\x{1091E}\\x{10920}-\\x{10939}\\x{1093A}-\\x{1093E}\\x{1093F}\\x{10940}-\\x{1097F}\\x{10980}-\\x{109B7}\\x{109B8}-\\x{109BB}\\x{109BC}-\\x{109BD}\\x{109BE}-\\x{109BF}\\x{109C0}-\\x{109CF}\\x{109D0}-\\x{109D1}\\x{109D2}-\\x{109FF}\\x{10A00}\\x{10A04}\\x{10A07}-\\x{10A0B}\\x{10A10}-\\x{10A13}\\x{10A14}\\x{10A15}-\\x{10A17}\\x{10A18}\\x{10A19}-\\x{10A35}\\x{10A36}-\\x{10A37}\\x{10A3B}-\\x{10A3E}\\x{10A40}-\\x{10A48}\\x{10A49}-\\x{10A4F}\\x{10A50}-\\x{10A58}\\x{10A59}-\\x{10A5F}\\x{10A60}-\\x{10A7C}\\x{10A7D}-\\x{10A7E}\\x{10A7F}\\x{10A80}-\\x{10A9C}\\x{10A9D}-\\x{10A9F}\\x{10AA0}-\\x{10ABF}\\x{10AC0}-\\x{10AC7}\\x{10AC8}\\x{10AC9}-\\x{10AE4}\\x{10AE7}-\\x{10AEA}\\x{10AEB}-\\x{10AEF}\\x{10AF0}-\\x{10AF6}\\x{10AF7}-\\x{10AFF}\\x{10B00}-\\x{10B35}\\x{10B36}-\\x{10B38}\\x{10B40}-\\x{10B55}\\x{10B56}-\\x{10B57}\\x{10B58}-\\x{10B5F}\\x{10B60}-\\x{10B72}\\x{10B73}-\\x{10B77}\\x{10B78}-\\x{10B7F}\\x{10B80}-\\x{10B91}\\x{10B92}-\\x{10B98}\\x{10B99}-\\x{10B9C}\\x{10B9D}-\\x{10BA8}\\x{10BA9}-\\x{10BAF}\\x{10BB0}-\\x{10BFF}\\x{10C00}-\\x{10C48}\\x{10C49}-\\x{10C7F}\\x{10C80}-\\x{10CB2}\\x{10CB3}-\\x{10CBF}\\x{10CC0}-\\x{10CF2}\\x{10CF3}-\\x{10CF9}\\x{10CFA}-\\x{10CFF}\\x{10D00}-\\x{10D23}\\x{10D28}-\\x{10D2F}\\x{10D30}-\\x{10D39}\\x{10D3A}-\\x{10D3F}\\x{10D40}-\\x{10E5F}\\x{10E60}-\\x{10E7E}\\x{10E7F}\\x{10E80}-\\x{10EA9}\\x{10EAA}\\x{10EAD}\\x{10EAE}-\\x{10EAF}\\x{10EB0}-\\x{10EB1}\\x{10EB2}-\\x{10EFF}\\x{10F00}-\\x{10F1C}\\x{10F1D}-\\x{10F26}\\x{10F27}\\x{10F28}-\\x{10F2F}\\x{10F30}-\\x{10F45}\\x{10F51}-\\x{10F54}\\x{10F55}-\\x{10F59}\\x{10F5A}-\\x{10F6F}\\x{10F70}-\\x{10FAF}\\x{10FB0}-\\x{10FC4}\\x{10FC5}-\\x{10FCB}\\x{10FCC}-\\x{10FDF}\\x{10FE0}-\\x{10FF6}\\x{10FF7}-\\x{10FFF}\\x{1E800}-\\x{1E8C4}\\x{1E8C5}-\\x{1E8C6}\\x{1E8C7}-\\x{1E8CF}\\x{1E8D7}-\\x{1E8FF}\\x{1E900}-\\x{1E943}\\x{1E94B}\\x{1E94C}-\\x{1E94F}\\x{1E950}-\\x{1E959}\\x{1E95A}-\\x{1E95D}\\x{1E95E}-\\x{1E95F}\\x{1E960}-\\x{1EC6F}\\x{1EC70}\\x{1EC71}-\\x{1ECAB}\\x{1ECAC}\\x{1ECAD}-\\x{1ECAF}\\x{1ECB0}\\x{1ECB1}-\\x{1ECB4}\\x{1ECB5}-\\x{1ECBF}\\x{1ECC0}-\\x{1ECFF}\\x{1ED00}\\x{1ED01}-\\x{1ED2D}\\x{1ED2E}\\x{1ED2F}-\\x{1ED3D}\\x{1ED3E}-\\x{1ED4F}\\x{1ED50}-\\x{1EDFF}\\x{1EE00}-\\x{1EE03}\\x{1EE04}\\x{1EE05}-\\x{1EE1F}\\x{1EE20}\\x{1EE21}-\\x{1EE22}\\x{1EE23}\\x{1EE24}\\x{1EE25}-\\x{1EE26}\\x{1EE27}\\x{1EE28}\\x{1EE29}-\\x{1EE32}\\x{1EE33}\\x{1EE34}-\\x{1EE37}\\x{1EE38}\\x{1EE39}\\x{1EE3A}\\x{1EE3B}\\x{1EE3C}-\\x{1EE41}\\x{1EE42}\\x{1EE43}-\\x{1EE46}\\x{1EE47}\\x{1EE48}\\x{1EE49}\\x{1EE4A}\\x{1EE4B}\\x{1EE4C}\\x{1EE4D}-\\x{1EE4F}\\x{1EE50}\\x{1EE51}-\\x{1EE52}\\x{1EE53}\\x{1EE54}\\x{1EE55}-\\x{1EE56}\\x{1EE57}\\x{1EE58}\\x{1EE59}\\x{1EE5A}\\x{1EE5B}\\x{1EE5C}\\x{1EE5D}\\x{1EE5E}\\x{1EE5F}\\x{1EE60}\\x{1EE61}-\\x{1EE62}\\x{1EE63}\\x{1EE64}\\x{1EE65}-\\x{1EE66}\\x{1EE67}-\\x{1EE6A}\\x{1EE6B}\\x{1EE6C}-\\x{1EE72}\\x{1EE73}\\x{1EE74}-\\x{1EE77}\\x{1EE78}\\x{1EE79}-\\x{1EE7C}\\x{1EE7D}\\x{1EE7E}\\x{1EE7F}\\x{1EE80}-\\x{1EE89}\\x{1EE8A}\\x{1EE8B}-\\x{1EE9B}\\x{1EE9C}-\\x{1EEA0}\\x{1EEA1}-\\x{1EEA3}\\x{1EEA4}\\x{1EEA5}-\\x{1EEA9}\\x{1EEAA}\\x{1EEAB}-\\x{1EEBB}\\x{1EEBC}-\\x{1EEEF}\\x{1EEF2}-\\x{1EEFF}\\x{1EF00}-\\x{1EFFF}]/u';\n    const BIDI_STEP_6 = '/[^\\x{0000}-\\x{0008}\\x{0009}\\x{000A}\\x{000B}\\x{000C}\\x{000D}\\x{000E}-\\x{001B}\\x{001C}-\\x{001E}\\x{001F}\\x{0020}\\x{0021}-\\x{0022}\\x{0023}\\x{0024}\\x{0025}\\x{0026}-\\x{0027}\\x{0028}\\x{0029}\\x{002A}\\x{002B}\\x{002C}\\x{002D}\\x{002E}-\\x{002F}\\x{003A}\\x{003B}\\x{003C}-\\x{003E}\\x{003F}-\\x{0040}\\x{005B}\\x{005C}\\x{005D}\\x{005E}\\x{005F}\\x{0060}\\x{007B}\\x{007C}\\x{007D}\\x{007E}\\x{007F}-\\x{0084}\\x{0085}\\x{0086}-\\x{009F}\\x{00A0}\\x{00A1}\\x{00A2}-\\x{00A5}\\x{00A6}\\x{00A7}\\x{00A8}\\x{00A9}\\x{00AB}\\x{00AC}\\x{00AD}\\x{00AE}\\x{00AF}\\x{00B0}\\x{00B1}\\x{00B4}\\x{00B6}-\\x{00B7}\\x{00B8}\\x{00BB}\\x{00BC}-\\x{00BE}\\x{00BF}\\x{00D7}\\x{00F7}\\x{02B9}-\\x{02BA}\\x{02C2}-\\x{02C5}\\x{02C6}-\\x{02CF}\\x{02D2}-\\x{02DF}\\x{02E5}-\\x{02EB}\\x{02EC}\\x{02ED}\\x{02EF}-\\x{02FF}\\x{0300}-\\x{036F}\\x{0374}\\x{0375}\\x{037E}\\x{0384}-\\x{0385}\\x{0387}\\x{03F6}\\x{0483}-\\x{0487}\\x{0488}-\\x{0489}\\x{058A}\\x{058D}-\\x{058E}\\x{058F}\\x{0590}\\x{0591}-\\x{05BD}\\x{05BE}\\x{05BF}\\x{05C0}\\x{05C1}-\\x{05C2}\\x{05C3}\\x{05C4}-\\x{05C5}\\x{05C6}\\x{05C7}\\x{05C8}-\\x{05CF}\\x{05D0}-\\x{05EA}\\x{05EB}-\\x{05EE}\\x{05EF}-\\x{05F2}\\x{05F3}-\\x{05F4}\\x{05F5}-\\x{05FF}\\x{0600}-\\x{0605}\\x{0606}-\\x{0607}\\x{0608}\\x{0609}-\\x{060A}\\x{060B}\\x{060C}\\x{060D}\\x{060E}-\\x{060F}\\x{0610}-\\x{061A}\\x{061B}\\x{061C}\\x{061D}\\x{061E}-\\x{061F}\\x{0620}-\\x{063F}\\x{0640}\\x{0641}-\\x{064A}\\x{064B}-\\x{065F}\\x{0660}-\\x{0669}\\x{066A}\\x{066B}-\\x{066C}\\x{066D}\\x{066E}-\\x{066F}\\x{0670}\\x{0671}-\\x{06D3}\\x{06D4}\\x{06D5}\\x{06D6}-\\x{06DC}\\x{06DD}\\x{06DE}\\x{06DF}-\\x{06E4}\\x{06E5}-\\x{06E6}\\x{06E7}-\\x{06E8}\\x{06E9}\\x{06EA}-\\x{06ED}\\x{06EE}-\\x{06EF}\\x{06FA}-\\x{06FC}\\x{06FD}-\\x{06FE}\\x{06FF}\\x{0700}-\\x{070D}\\x{070E}\\x{070F}\\x{0710}\\x{0711}\\x{0712}-\\x{072F}\\x{0730}-\\x{074A}\\x{074B}-\\x{074C}\\x{074D}-\\x{07A5}\\x{07A6}-\\x{07B0}\\x{07B1}\\x{07B2}-\\x{07BF}\\x{07C0}-\\x{07C9}\\x{07CA}-\\x{07EA}\\x{07EB}-\\x{07F3}\\x{07F4}-\\x{07F5}\\x{07F6}\\x{07F7}-\\x{07F9}\\x{07FA}\\x{07FB}-\\x{07FC}\\x{07FD}\\x{07FE}-\\x{07FF}\\x{0800}-\\x{0815}\\x{0816}-\\x{0819}\\x{081A}\\x{081B}-\\x{0823}\\x{0824}\\x{0825}-\\x{0827}\\x{0828}\\x{0829}-\\x{082D}\\x{082E}-\\x{082F}\\x{0830}-\\x{083E}\\x{083F}\\x{0840}-\\x{0858}\\x{0859}-\\x{085B}\\x{085C}-\\x{085D}\\x{085E}\\x{085F}\\x{0860}-\\x{086A}\\x{086B}-\\x{086F}\\x{0870}-\\x{089F}\\x{08A0}-\\x{08B4}\\x{08B5}\\x{08B6}-\\x{08C7}\\x{08C8}-\\x{08D2}\\x{08D3}-\\x{08E1}\\x{08E2}\\x{08E3}-\\x{0902}\\x{093A}\\x{093C}\\x{0941}-\\x{0948}\\x{094D}\\x{0951}-\\x{0957}\\x{0962}-\\x{0963}\\x{0981}\\x{09BC}\\x{09C1}-\\x{09C4}\\x{09CD}\\x{09E2}-\\x{09E3}\\x{09F2}-\\x{09F3}\\x{09FB}\\x{09FE}\\x{0A01}-\\x{0A02}\\x{0A3C}\\x{0A41}-\\x{0A42}\\x{0A47}-\\x{0A48}\\x{0A4B}-\\x{0A4D}\\x{0A51}\\x{0A70}-\\x{0A71}\\x{0A75}\\x{0A81}-\\x{0A82}\\x{0ABC}\\x{0AC1}-\\x{0AC5}\\x{0AC7}-\\x{0AC8}\\x{0ACD}\\x{0AE2}-\\x{0AE3}\\x{0AF1}\\x{0AFA}-\\x{0AFF}\\x{0B01}\\x{0B3C}\\x{0B3F}\\x{0B41}-\\x{0B44}\\x{0B4D}\\x{0B55}-\\x{0B56}\\x{0B62}-\\x{0B63}\\x{0B82}\\x{0BC0}\\x{0BCD}\\x{0BF3}-\\x{0BF8}\\x{0BF9}\\x{0BFA}\\x{0C00}\\x{0C04}\\x{0C3E}-\\x{0C40}\\x{0C46}-\\x{0C48}\\x{0C4A}-\\x{0C4D}\\x{0C55}-\\x{0C56}\\x{0C62}-\\x{0C63}\\x{0C78}-\\x{0C7E}\\x{0C81}\\x{0CBC}\\x{0CCC}-\\x{0CCD}\\x{0CE2}-\\x{0CE3}\\x{0D00}-\\x{0D01}\\x{0D3B}-\\x{0D3C}\\x{0D41}-\\x{0D44}\\x{0D4D}\\x{0D62}-\\x{0D63}\\x{0D81}\\x{0DCA}\\x{0DD2}-\\x{0DD4}\\x{0DD6}\\x{0E31}\\x{0E34}-\\x{0E3A}\\x{0E3F}\\x{0E47}-\\x{0E4E}\\x{0EB1}\\x{0EB4}-\\x{0EBC}\\x{0EC8}-\\x{0ECD}\\x{0F18}-\\x{0F19}\\x{0F35}\\x{0F37}\\x{0F39}\\x{0F3A}\\x{0F3B}\\x{0F3C}\\x{0F3D}\\x{0F71}-\\x{0F7E}\\x{0F80}-\\x{0F84}\\x{0F86}-\\x{0F87}\\x{0F8D}-\\x{0F97}\\x{0F99}-\\x{0FBC}\\x{0FC6}\\x{102D}-\\x{1030}\\x{1032}-\\x{1037}\\x{1039}-\\x{103A}\\x{103D}-\\x{103E}\\x{1058}-\\x{1059}\\x{105E}-\\x{1060}\\x{1071}-\\x{1074}\\x{1082}\\x{1085}-\\x{1086}\\x{108D}\\x{109D}\\x{135D}-\\x{135F}\\x{1390}-\\x{1399}\\x{1400}\\x{1680}\\x{169B}\\x{169C}\\x{1712}-\\x{1714}\\x{1732}-\\x{1734}\\x{1752}-\\x{1753}\\x{1772}-\\x{1773}\\x{17B4}-\\x{17B5}\\x{17B7}-\\x{17BD}\\x{17C6}\\x{17C9}-\\x{17D3}\\x{17DB}\\x{17DD}\\x{17F0}-\\x{17F9}\\x{1800}-\\x{1805}\\x{1806}\\x{1807}-\\x{180A}\\x{180B}-\\x{180D}\\x{180E}\\x{1885}-\\x{1886}\\x{18A9}\\x{1920}-\\x{1922}\\x{1927}-\\x{1928}\\x{1932}\\x{1939}-\\x{193B}\\x{1940}\\x{1944}-\\x{1945}\\x{19DE}-\\x{19FF}\\x{1A17}-\\x{1A18}\\x{1A1B}\\x{1A56}\\x{1A58}-\\x{1A5E}\\x{1A60}\\x{1A62}\\x{1A65}-\\x{1A6C}\\x{1A73}-\\x{1A7C}\\x{1A7F}\\x{1AB0}-\\x{1ABD}\\x{1ABE}\\x{1ABF}-\\x{1AC0}\\x{1B00}-\\x{1B03}\\x{1B34}\\x{1B36}-\\x{1B3A}\\x{1B3C}\\x{1B42}\\x{1B6B}-\\x{1B73}\\x{1B80}-\\x{1B81}\\x{1BA2}-\\x{1BA5}\\x{1BA8}-\\x{1BA9}\\x{1BAB}-\\x{1BAD}\\x{1BE6}\\x{1BE8}-\\x{1BE9}\\x{1BED}\\x{1BEF}-\\x{1BF1}\\x{1C2C}-\\x{1C33}\\x{1C36}-\\x{1C37}\\x{1CD0}-\\x{1CD2}\\x{1CD4}-\\x{1CE0}\\x{1CE2}-\\x{1CE8}\\x{1CED}\\x{1CF4}\\x{1CF8}-\\x{1CF9}\\x{1DC0}-\\x{1DF9}\\x{1DFB}-\\x{1DFF}\\x{1FBD}\\x{1FBF}-\\x{1FC1}\\x{1FCD}-\\x{1FCF}\\x{1FDD}-\\x{1FDF}\\x{1FED}-\\x{1FEF}\\x{1FFD}-\\x{1FFE}\\x{2000}-\\x{200A}\\x{200B}-\\x{200D}\\x{200F}\\x{2010}-\\x{2015}\\x{2016}-\\x{2017}\\x{2018}\\x{2019}\\x{201A}\\x{201B}-\\x{201C}\\x{201D}\\x{201E}\\x{201F}\\x{2020}-\\x{2027}\\x{2028}\\x{2029}\\x{202A}\\x{202B}\\x{202C}\\x{202D}\\x{202E}\\x{202F}\\x{2030}-\\x{2034}\\x{2035}-\\x{2038}\\x{2039}\\x{203A}\\x{203B}-\\x{203E}\\x{203F}-\\x{2040}\\x{2041}-\\x{2043}\\x{2044}\\x{2045}\\x{2046}\\x{2047}-\\x{2051}\\x{2052}\\x{2053}\\x{2054}\\x{2055}-\\x{205E}\\x{205F}\\x{2060}-\\x{2064}\\x{2065}\\x{2066}\\x{2067}\\x{2068}\\x{2069}\\x{206A}-\\x{206F}\\x{207A}-\\x{207B}\\x{207C}\\x{207D}\\x{207E}\\x{208A}-\\x{208B}\\x{208C}\\x{208D}\\x{208E}\\x{20A0}-\\x{20BF}\\x{20C0}-\\x{20CF}\\x{20D0}-\\x{20DC}\\x{20DD}-\\x{20E0}\\x{20E1}\\x{20E2}-\\x{20E4}\\x{20E5}-\\x{20F0}\\x{2100}-\\x{2101}\\x{2103}-\\x{2106}\\x{2108}-\\x{2109}\\x{2114}\\x{2116}-\\x{2117}\\x{2118}\\x{211E}-\\x{2123}\\x{2125}\\x{2127}\\x{2129}\\x{212E}\\x{213A}-\\x{213B}\\x{2140}-\\x{2144}\\x{214A}\\x{214B}\\x{214C}-\\x{214D}\\x{2150}-\\x{215F}\\x{2189}\\x{218A}-\\x{218B}\\x{2190}-\\x{2194}\\x{2195}-\\x{2199}\\x{219A}-\\x{219B}\\x{219C}-\\x{219F}\\x{21A0}\\x{21A1}-\\x{21A2}\\x{21A3}\\x{21A4}-\\x{21A5}\\x{21A6}\\x{21A7}-\\x{21AD}\\x{21AE}\\x{21AF}-\\x{21CD}\\x{21CE}-\\x{21CF}\\x{21D0}-\\x{21D1}\\x{21D2}\\x{21D3}\\x{21D4}\\x{21D5}-\\x{21F3}\\x{21F4}-\\x{2211}\\x{2212}\\x{2213}\\x{2214}-\\x{22FF}\\x{2300}-\\x{2307}\\x{2308}\\x{2309}\\x{230A}\\x{230B}\\x{230C}-\\x{231F}\\x{2320}-\\x{2321}\\x{2322}-\\x{2328}\\x{2329}\\x{232A}\\x{232B}-\\x{2335}\\x{237B}\\x{237C}\\x{237D}-\\x{2394}\\x{2396}-\\x{239A}\\x{239B}-\\x{23B3}\\x{23B4}-\\x{23DB}\\x{23DC}-\\x{23E1}\\x{23E2}-\\x{2426}\\x{2440}-\\x{244A}\\x{2460}-\\x{2487}\\x{24EA}-\\x{24FF}\\x{2500}-\\x{25B6}\\x{25B7}\\x{25B8}-\\x{25C0}\\x{25C1}\\x{25C2}-\\x{25F7}\\x{25F8}-\\x{25FF}\\x{2600}-\\x{266E}\\x{266F}\\x{2670}-\\x{26AB}\\x{26AD}-\\x{2767}\\x{2768}\\x{2769}\\x{276A}\\x{276B}\\x{276C}\\x{276D}\\x{276E}\\x{276F}\\x{2770}\\x{2771}\\x{2772}\\x{2773}\\x{2774}\\x{2775}\\x{2776}-\\x{2793}\\x{2794}-\\x{27BF}\\x{27C0}-\\x{27C4}\\x{27C5}\\x{27C6}\\x{27C7}-\\x{27E5}\\x{27E6}\\x{27E7}\\x{27E8}\\x{27E9}\\x{27EA}\\x{27EB}\\x{27EC}\\x{27ED}\\x{27EE}\\x{27EF}\\x{27F0}-\\x{27FF}\\x{2900}-\\x{2982}\\x{2983}\\x{2984}\\x{2985}\\x{2986}\\x{2987}\\x{2988}\\x{2989}\\x{298A}\\x{298B}\\x{298C}\\x{298D}\\x{298E}\\x{298F}\\x{2990}\\x{2991}\\x{2992}\\x{2993}\\x{2994}\\x{2995}\\x{2996}\\x{2997}\\x{2998}\\x{2999}-\\x{29D7}\\x{29D8}\\x{29D9}\\x{29DA}\\x{29DB}\\x{29DC}-\\x{29FB}\\x{29FC}\\x{29FD}\\x{29FE}-\\x{2AFF}\\x{2B00}-\\x{2B2F}\\x{2B30}-\\x{2B44}\\x{2B45}-\\x{2B46}\\x{2B47}-\\x{2B4C}\\x{2B4D}-\\x{2B73}\\x{2B76}-\\x{2B95}\\x{2B97}-\\x{2BFF}\\x{2CE5}-\\x{2CEA}\\x{2CEF}-\\x{2CF1}\\x{2CF9}-\\x{2CFC}\\x{2CFD}\\x{2CFE}-\\x{2CFF}\\x{2D7F}\\x{2DE0}-\\x{2DFF}\\x{2E00}-\\x{2E01}\\x{2E02}\\x{2E03}\\x{2E04}\\x{2E05}\\x{2E06}-\\x{2E08}\\x{2E09}\\x{2E0A}\\x{2E0B}\\x{2E0C}\\x{2E0D}\\x{2E0E}-\\x{2E16}\\x{2E17}\\x{2E18}-\\x{2E19}\\x{2E1A}\\x{2E1B}\\x{2E1C}\\x{2E1D}\\x{2E1E}-\\x{2E1F}\\x{2E20}\\x{2E21}\\x{2E22}\\x{2E23}\\x{2E24}\\x{2E25}\\x{2E26}\\x{2E27}\\x{2E28}\\x{2E29}\\x{2E2A}-\\x{2E2E}\\x{2E2F}\\x{2E30}-\\x{2E39}\\x{2E3A}-\\x{2E3B}\\x{2E3C}-\\x{2E3F}\\x{2E40}\\x{2E41}\\x{2E42}\\x{2E43}-\\x{2E4F}\\x{2E50}-\\x{2E51}\\x{2E52}\\x{2E80}-\\x{2E99}\\x{2E9B}-\\x{2EF3}\\x{2F00}-\\x{2FD5}\\x{2FF0}-\\x{2FFB}\\x{3000}\\x{3001}-\\x{3003}\\x{3004}\\x{3008}\\x{3009}\\x{300A}\\x{300B}\\x{300C}\\x{300D}\\x{300E}\\x{300F}\\x{3010}\\x{3011}\\x{3012}-\\x{3013}\\x{3014}\\x{3015}\\x{3016}\\x{3017}\\x{3018}\\x{3019}\\x{301A}\\x{301B}\\x{301C}\\x{301D}\\x{301E}-\\x{301F}\\x{3020}\\x{302A}-\\x{302D}\\x{3030}\\x{3036}-\\x{3037}\\x{303D}\\x{303E}-\\x{303F}\\x{3099}-\\x{309A}\\x{309B}-\\x{309C}\\x{30A0}\\x{30FB}\\x{31C0}-\\x{31E3}\\x{321D}-\\x{321E}\\x{3250}\\x{3251}-\\x{325F}\\x{327C}-\\x{327E}\\x{32B1}-\\x{32BF}\\x{32CC}-\\x{32CF}\\x{3377}-\\x{337A}\\x{33DE}-\\x{33DF}\\x{33FF}\\x{4DC0}-\\x{4DFF}\\x{A490}-\\x{A4C6}\\x{A60D}-\\x{A60F}\\x{A66F}\\x{A670}-\\x{A672}\\x{A673}\\x{A674}-\\x{A67D}\\x{A67E}\\x{A67F}\\x{A69E}-\\x{A69F}\\x{A6F0}-\\x{A6F1}\\x{A700}-\\x{A716}\\x{A717}-\\x{A71F}\\x{A720}-\\x{A721}\\x{A788}\\x{A802}\\x{A806}\\x{A80B}\\x{A825}-\\x{A826}\\x{A828}-\\x{A82B}\\x{A82C}\\x{A838}\\x{A839}\\x{A874}-\\x{A877}\\x{A8C4}-\\x{A8C5}\\x{A8E0}-\\x{A8F1}\\x{A8FF}\\x{A926}-\\x{A92D}\\x{A947}-\\x{A951}\\x{A980}-\\x{A982}\\x{A9B3}\\x{A9B6}-\\x{A9B9}\\x{A9BC}-\\x{A9BD}\\x{A9E5}\\x{AA29}-\\x{AA2E}\\x{AA31}-\\x{AA32}\\x{AA35}-\\x{AA36}\\x{AA43}\\x{AA4C}\\x{AA7C}\\x{AAB0}\\x{AAB2}-\\x{AAB4}\\x{AAB7}-\\x{AAB8}\\x{AABE}-\\x{AABF}\\x{AAC1}\\x{AAEC}-\\x{AAED}\\x{AAF6}\\x{AB6A}-\\x{AB6B}\\x{ABE5}\\x{ABE8}\\x{ABED}\\x{FB1D}\\x{FB1E}\\x{FB1F}-\\x{FB28}\\x{FB29}\\x{FB2A}-\\x{FB36}\\x{FB37}\\x{FB38}-\\x{FB3C}\\x{FB3D}\\x{FB3E}\\x{FB3F}\\x{FB40}-\\x{FB41}\\x{FB42}\\x{FB43}-\\x{FB44}\\x{FB45}\\x{FB46}-\\x{FB4F}\\x{FB50}-\\x{FBB1}\\x{FBB2}-\\x{FBC1}\\x{FBC2}-\\x{FBD2}\\x{FBD3}-\\x{FD3D}\\x{FD3E}\\x{FD3F}\\x{FD40}-\\x{FD4F}\\x{FD50}-\\x{FD8F}\\x{FD90}-\\x{FD91}\\x{FD92}-\\x{FDC7}\\x{FDC8}-\\x{FDCF}\\x{FDD0}-\\x{FDEF}\\x{FDF0}-\\x{FDFB}\\x{FDFC}\\x{FDFD}\\x{FDFE}-\\x{FDFF}\\x{FE00}-\\x{FE0F}\\x{FE10}-\\x{FE16}\\x{FE17}\\x{FE18}\\x{FE19}\\x{FE20}-\\x{FE2F}\\x{FE30}\\x{FE31}-\\x{FE32}\\x{FE33}-\\x{FE34}\\x{FE35}\\x{FE36}\\x{FE37}\\x{FE38}\\x{FE39}\\x{FE3A}\\x{FE3B}\\x{FE3C}\\x{FE3D}\\x{FE3E}\\x{FE3F}\\x{FE40}\\x{FE41}\\x{FE42}\\x{FE43}\\x{FE44}\\x{FE45}-\\x{FE46}\\x{FE47}\\x{FE48}\\x{FE49}-\\x{FE4C}\\x{FE4D}-\\x{FE4F}\\x{FE50}\\x{FE51}\\x{FE52}\\x{FE54}\\x{FE55}\\x{FE56}-\\x{FE57}\\x{FE58}\\x{FE59}\\x{FE5A}\\x{FE5B}\\x{FE5C}\\x{FE5D}\\x{FE5E}\\x{FE5F}\\x{FE60}-\\x{FE61}\\x{FE62}\\x{FE63}\\x{FE64}-\\x{FE66}\\x{FE68}\\x{FE69}\\x{FE6A}\\x{FE6B}\\x{FE70}-\\x{FE74}\\x{FE75}\\x{FE76}-\\x{FEFC}\\x{FEFD}-\\x{FEFE}\\x{FEFF}\\x{FF01}-\\x{FF02}\\x{FF03}\\x{FF04}\\x{FF05}\\x{FF06}-\\x{FF07}\\x{FF08}\\x{FF09}\\x{FF0A}\\x{FF0B}\\x{FF0C}\\x{FF0D}\\x{FF0E}-\\x{FF0F}\\x{FF1A}\\x{FF1B}\\x{FF1C}-\\x{FF1E}\\x{FF1F}-\\x{FF20}\\x{FF3B}\\x{FF3C}\\x{FF3D}\\x{FF3E}\\x{FF3F}\\x{FF40}\\x{FF5B}\\x{FF5C}\\x{FF5D}\\x{FF5E}\\x{FF5F}\\x{FF60}\\x{FF61}\\x{FF62}\\x{FF63}\\x{FF64}-\\x{FF65}\\x{FFE0}-\\x{FFE1}\\x{FFE2}\\x{FFE3}\\x{FFE4}\\x{FFE5}-\\x{FFE6}\\x{FFE8}\\x{FFE9}-\\x{FFEC}\\x{FFED}-\\x{FFEE}\\x{FFF0}-\\x{FFF8}\\x{FFF9}-\\x{FFFB}\\x{FFFC}-\\x{FFFD}\\x{FFFE}-\\x{FFFF}\\x{10101}\\x{10140}-\\x{10174}\\x{10175}-\\x{10178}\\x{10179}-\\x{10189}\\x{1018A}-\\x{1018B}\\x{1018C}\\x{10190}-\\x{1019C}\\x{101A0}\\x{101FD}\\x{102E0}\\x{10376}-\\x{1037A}\\x{10800}-\\x{10805}\\x{10806}-\\x{10807}\\x{10808}\\x{10809}\\x{1080A}-\\x{10835}\\x{10836}\\x{10837}-\\x{10838}\\x{10839}-\\x{1083B}\\x{1083C}\\x{1083D}-\\x{1083E}\\x{1083F}-\\x{10855}\\x{10856}\\x{10857}\\x{10858}-\\x{1085F}\\x{10860}-\\x{10876}\\x{10877}-\\x{10878}\\x{10879}-\\x{1087F}\\x{10880}-\\x{1089E}\\x{1089F}-\\x{108A6}\\x{108A7}-\\x{108AF}\\x{108B0}-\\x{108DF}\\x{108E0}-\\x{108F2}\\x{108F3}\\x{108F4}-\\x{108F5}\\x{108F6}-\\x{108FA}\\x{108FB}-\\x{108FF}\\x{10900}-\\x{10915}\\x{10916}-\\x{1091B}\\x{1091C}-\\x{1091E}\\x{1091F}\\x{10920}-\\x{10939}\\x{1093A}-\\x{1093E}\\x{1093F}\\x{10940}-\\x{1097F}\\x{10980}-\\x{109B7}\\x{109B8}-\\x{109BB}\\x{109BC}-\\x{109BD}\\x{109BE}-\\x{109BF}\\x{109C0}-\\x{109CF}\\x{109D0}-\\x{109D1}\\x{109D2}-\\x{109FF}\\x{10A00}\\x{10A01}-\\x{10A03}\\x{10A04}\\x{10A05}-\\x{10A06}\\x{10A07}-\\x{10A0B}\\x{10A0C}-\\x{10A0F}\\x{10A10}-\\x{10A13}\\x{10A14}\\x{10A15}-\\x{10A17}\\x{10A18}\\x{10A19}-\\x{10A35}\\x{10A36}-\\x{10A37}\\x{10A38}-\\x{10A3A}\\x{10A3B}-\\x{10A3E}\\x{10A3F}\\x{10A40}-\\x{10A48}\\x{10A49}-\\x{10A4F}\\x{10A50}-\\x{10A58}\\x{10A59}-\\x{10A5F}\\x{10A60}-\\x{10A7C}\\x{10A7D}-\\x{10A7E}\\x{10A7F}\\x{10A80}-\\x{10A9C}\\x{10A9D}-\\x{10A9F}\\x{10AA0}-\\x{10ABF}\\x{10AC0}-\\x{10AC7}\\x{10AC8}\\x{10AC9}-\\x{10AE4}\\x{10AE5}-\\x{10AE6}\\x{10AE7}-\\x{10AEA}\\x{10AEB}-\\x{10AEF}\\x{10AF0}-\\x{10AF6}\\x{10AF7}-\\x{10AFF}\\x{10B00}-\\x{10B35}\\x{10B36}-\\x{10B38}\\x{10B39}-\\x{10B3F}\\x{10B40}-\\x{10B55}\\x{10B56}-\\x{10B57}\\x{10B58}-\\x{10B5F}\\x{10B60}-\\x{10B72}\\x{10B73}-\\x{10B77}\\x{10B78}-\\x{10B7F}\\x{10B80}-\\x{10B91}\\x{10B92}-\\x{10B98}\\x{10B99}-\\x{10B9C}\\x{10B9D}-\\x{10BA8}\\x{10BA9}-\\x{10BAF}\\x{10BB0}-\\x{10BFF}\\x{10C00}-\\x{10C48}\\x{10C49}-\\x{10C7F}\\x{10C80}-\\x{10CB2}\\x{10CB3}-\\x{10CBF}\\x{10CC0}-\\x{10CF2}\\x{10CF3}-\\x{10CF9}\\x{10CFA}-\\x{10CFF}\\x{10D00}-\\x{10D23}\\x{10D24}-\\x{10D27}\\x{10D28}-\\x{10D2F}\\x{10D30}-\\x{10D39}\\x{10D3A}-\\x{10D3F}\\x{10D40}-\\x{10E5F}\\x{10E60}-\\x{10E7E}\\x{10E7F}\\x{10E80}-\\x{10EA9}\\x{10EAA}\\x{10EAB}-\\x{10EAC}\\x{10EAD}\\x{10EAE}-\\x{10EAF}\\x{10EB0}-\\x{10EB1}\\x{10EB2}-\\x{10EFF}\\x{10F00}-\\x{10F1C}\\x{10F1D}-\\x{10F26}\\x{10F27}\\x{10F28}-\\x{10F2F}\\x{10F30}-\\x{10F45}\\x{10F46}-\\x{10F50}\\x{10F51}-\\x{10F54}\\x{10F55}-\\x{10F59}\\x{10F5A}-\\x{10F6F}\\x{10F70}-\\x{10FAF}\\x{10FB0}-\\x{10FC4}\\x{10FC5}-\\x{10FCB}\\x{10FCC}-\\x{10FDF}\\x{10FE0}-\\x{10FF6}\\x{10FF7}-\\x{10FFF}\\x{11001}\\x{11038}-\\x{11046}\\x{11052}-\\x{11065}\\x{1107F}-\\x{11081}\\x{110B3}-\\x{110B6}\\x{110B9}-\\x{110BA}\\x{11100}-\\x{11102}\\x{11127}-\\x{1112B}\\x{1112D}-\\x{11134}\\x{11173}\\x{11180}-\\x{11181}\\x{111B6}-\\x{111BE}\\x{111C9}-\\x{111CC}\\x{111CF}\\x{1122F}-\\x{11231}\\x{11234}\\x{11236}-\\x{11237}\\x{1123E}\\x{112DF}\\x{112E3}-\\x{112EA}\\x{11300}-\\x{11301}\\x{1133B}-\\x{1133C}\\x{11340}\\x{11366}-\\x{1136C}\\x{11370}-\\x{11374}\\x{11438}-\\x{1143F}\\x{11442}-\\x{11444}\\x{11446}\\x{1145E}\\x{114B3}-\\x{114B8}\\x{114BA}\\x{114BF}-\\x{114C0}\\x{114C2}-\\x{114C3}\\x{115B2}-\\x{115B5}\\x{115BC}-\\x{115BD}\\x{115BF}-\\x{115C0}\\x{115DC}-\\x{115DD}\\x{11633}-\\x{1163A}\\x{1163D}\\x{1163F}-\\x{11640}\\x{11660}-\\x{1166C}\\x{116AB}\\x{116AD}\\x{116B0}-\\x{116B5}\\x{116B7}\\x{1171D}-\\x{1171F}\\x{11722}-\\x{11725}\\x{11727}-\\x{1172B}\\x{1182F}-\\x{11837}\\x{11839}-\\x{1183A}\\x{1193B}-\\x{1193C}\\x{1193E}\\x{11943}\\x{119D4}-\\x{119D7}\\x{119DA}-\\x{119DB}\\x{119E0}\\x{11A01}-\\x{11A06}\\x{11A09}-\\x{11A0A}\\x{11A33}-\\x{11A38}\\x{11A3B}-\\x{11A3E}\\x{11A47}\\x{11A51}-\\x{11A56}\\x{11A59}-\\x{11A5B}\\x{11A8A}-\\x{11A96}\\x{11A98}-\\x{11A99}\\x{11C30}-\\x{11C36}\\x{11C38}-\\x{11C3D}\\x{11C92}-\\x{11CA7}\\x{11CAA}-\\x{11CB0}\\x{11CB2}-\\x{11CB3}\\x{11CB5}-\\x{11CB6}\\x{11D31}-\\x{11D36}\\x{11D3A}\\x{11D3C}-\\x{11D3D}\\x{11D3F}-\\x{11D45}\\x{11D47}\\x{11D90}-\\x{11D91}\\x{11D95}\\x{11D97}\\x{11EF3}-\\x{11EF4}\\x{11FD5}-\\x{11FDC}\\x{11FDD}-\\x{11FE0}\\x{11FE1}-\\x{11FF1}\\x{16AF0}-\\x{16AF4}\\x{16B30}-\\x{16B36}\\x{16F4F}\\x{16F8F}-\\x{16F92}\\x{16FE2}\\x{16FE4}\\x{1BC9D}-\\x{1BC9E}\\x{1BCA0}-\\x{1BCA3}\\x{1D167}-\\x{1D169}\\x{1D173}-\\x{1D17A}\\x{1D17B}-\\x{1D182}\\x{1D185}-\\x{1D18B}\\x{1D1AA}-\\x{1D1AD}\\x{1D200}-\\x{1D241}\\x{1D242}-\\x{1D244}\\x{1D245}\\x{1D300}-\\x{1D356}\\x{1D6DB}\\x{1D715}\\x{1D74F}\\x{1D789}\\x{1D7C3}\\x{1DA00}-\\x{1DA36}\\x{1DA3B}-\\x{1DA6C}\\x{1DA75}\\x{1DA84}\\x{1DA9B}-\\x{1DA9F}\\x{1DAA1}-\\x{1DAAF}\\x{1E000}-\\x{1E006}\\x{1E008}-\\x{1E018}\\x{1E01B}-\\x{1E021}\\x{1E023}-\\x{1E024}\\x{1E026}-\\x{1E02A}\\x{1E130}-\\x{1E136}\\x{1E2EC}-\\x{1E2EF}\\x{1E2FF}\\x{1E800}-\\x{1E8C4}\\x{1E8C5}-\\x{1E8C6}\\x{1E8C7}-\\x{1E8CF}\\x{1E8D0}-\\x{1E8D6}\\x{1E8D7}-\\x{1E8FF}\\x{1E900}-\\x{1E943}\\x{1E944}-\\x{1E94A}\\x{1E94B}\\x{1E94C}-\\x{1E94F}\\x{1E950}-\\x{1E959}\\x{1E95A}-\\x{1E95D}\\x{1E95E}-\\x{1E95F}\\x{1E960}-\\x{1EC6F}\\x{1EC70}\\x{1EC71}-\\x{1ECAB}\\x{1ECAC}\\x{1ECAD}-\\x{1ECAF}\\x{1ECB0}\\x{1ECB1}-\\x{1ECB4}\\x{1ECB5}-\\x{1ECBF}\\x{1ECC0}-\\x{1ECFF}\\x{1ED00}\\x{1ED01}-\\x{1ED2D}\\x{1ED2E}\\x{1ED2F}-\\x{1ED3D}\\x{1ED3E}-\\x{1ED4F}\\x{1ED50}-\\x{1EDFF}\\x{1EE00}-\\x{1EE03}\\x{1EE04}\\x{1EE05}-\\x{1EE1F}\\x{1EE20}\\x{1EE21}-\\x{1EE22}\\x{1EE23}\\x{1EE24}\\x{1EE25}-\\x{1EE26}\\x{1EE27}\\x{1EE28}\\x{1EE29}-\\x{1EE32}\\x{1EE33}\\x{1EE34}-\\x{1EE37}\\x{1EE38}\\x{1EE39}\\x{1EE3A}\\x{1EE3B}\\x{1EE3C}-\\x{1EE41}\\x{1EE42}\\x{1EE43}-\\x{1EE46}\\x{1EE47}\\x{1EE48}\\x{1EE49}\\x{1EE4A}\\x{1EE4B}\\x{1EE4C}\\x{1EE4D}-\\x{1EE4F}\\x{1EE50}\\x{1EE51}-\\x{1EE52}\\x{1EE53}\\x{1EE54}\\x{1EE55}-\\x{1EE56}\\x{1EE57}\\x{1EE58}\\x{1EE59}\\x{1EE5A}\\x{1EE5B}\\x{1EE5C}\\x{1EE5D}\\x{1EE5E}\\x{1EE5F}\\x{1EE60}\\x{1EE61}-\\x{1EE62}\\x{1EE63}\\x{1EE64}\\x{1EE65}-\\x{1EE66}\\x{1EE67}-\\x{1EE6A}\\x{1EE6B}\\x{1EE6C}-\\x{1EE72}\\x{1EE73}\\x{1EE74}-\\x{1EE77}\\x{1EE78}\\x{1EE79}-\\x{1EE7C}\\x{1EE7D}\\x{1EE7E}\\x{1EE7F}\\x{1EE80}-\\x{1EE89}\\x{1EE8A}\\x{1EE8B}-\\x{1EE9B}\\x{1EE9C}-\\x{1EEA0}\\x{1EEA1}-\\x{1EEA3}\\x{1EEA4}\\x{1EEA5}-\\x{1EEA9}\\x{1EEAA}\\x{1EEAB}-\\x{1EEBB}\\x{1EEBC}-\\x{1EEEF}\\x{1EEF0}-\\x{1EEF1}\\x{1EEF2}-\\x{1EEFF}\\x{1EF00}-\\x{1EFFF}\\x{1F000}-\\x{1F02B}\\x{1F030}-\\x{1F093}\\x{1F0A0}-\\x{1F0AE}\\x{1F0B1}-\\x{1F0BF}\\x{1F0C1}-\\x{1F0CF}\\x{1F0D1}-\\x{1F0F5}\\x{1F10B}-\\x{1F10C}\\x{1F10D}-\\x{1F10F}\\x{1F12F}\\x{1F16A}-\\x{1F16F}\\x{1F1AD}\\x{1F260}-\\x{1F265}\\x{1F300}-\\x{1F3FA}\\x{1F3FB}-\\x{1F3FF}\\x{1F400}-\\x{1F6D7}\\x{1F6E0}-\\x{1F6EC}\\x{1F6F0}-\\x{1F6FC}\\x{1F700}-\\x{1F773}\\x{1F780}-\\x{1F7D8}\\x{1F7E0}-\\x{1F7EB}\\x{1F800}-\\x{1F80B}\\x{1F810}-\\x{1F847}\\x{1F850}-\\x{1F859}\\x{1F860}-\\x{1F887}\\x{1F890}-\\x{1F8AD}\\x{1F8B0}-\\x{1F8B1}\\x{1F900}-\\x{1F978}\\x{1F97A}-\\x{1F9CB}\\x{1F9CD}-\\x{1FA53}\\x{1FA60}-\\x{1FA6D}\\x{1FA70}-\\x{1FA74}\\x{1FA78}-\\x{1FA7A}\\x{1FA80}-\\x{1FA86}\\x{1FA90}-\\x{1FAA8}\\x{1FAB0}-\\x{1FAB6}\\x{1FAC0}-\\x{1FAC2}\\x{1FAD0}-\\x{1FAD6}\\x{1FB00}-\\x{1FB92}\\x{1FB94}-\\x{1FBCA}\\x{1FFFE}-\\x{1FFFF}\\x{2FFFE}-\\x{2FFFF}\\x{3FFFE}-\\x{3FFFF}\\x{4FFFE}-\\x{4FFFF}\\x{5FFFE}-\\x{5FFFF}\\x{6FFFE}-\\x{6FFFF}\\x{7FFFE}-\\x{7FFFF}\\x{8FFFE}-\\x{8FFFF}\\x{9FFFE}-\\x{9FFFF}\\x{AFFFE}-\\x{AFFFF}\\x{BFFFE}-\\x{BFFFF}\\x{CFFFE}-\\x{CFFFF}\\x{DFFFE}-\\x{E0000}\\x{E0001}\\x{E0002}-\\x{E001F}\\x{E0020}-\\x{E007F}\\x{E0080}-\\x{E00FF}\\x{E0100}-\\x{E01EF}\\x{E01F0}-\\x{E0FFF}\\x{EFFFE}-\\x{EFFFF}\\x{FFFFE}-\\x{FFFFF}\\x{10FFFE}-\\x{10FFFF}][\\x{0300}-\\x{036F}\\x{0483}-\\x{0487}\\x{0488}-\\x{0489}\\x{0591}-\\x{05BD}\\x{05BF}\\x{05C1}-\\x{05C2}\\x{05C4}-\\x{05C5}\\x{05C7}\\x{0610}-\\x{061A}\\x{064B}-\\x{065F}\\x{0670}\\x{06D6}-\\x{06DC}\\x{06DF}-\\x{06E4}\\x{06E7}-\\x{06E8}\\x{06EA}-\\x{06ED}\\x{0711}\\x{0730}-\\x{074A}\\x{07A6}-\\x{07B0}\\x{07EB}-\\x{07F3}\\x{07FD}\\x{0816}-\\x{0819}\\x{081B}-\\x{0823}\\x{0825}-\\x{0827}\\x{0829}-\\x{082D}\\x{0859}-\\x{085B}\\x{08D3}-\\x{08E1}\\x{08E3}-\\x{0902}\\x{093A}\\x{093C}\\x{0941}-\\x{0948}\\x{094D}\\x{0951}-\\x{0957}\\x{0962}-\\x{0963}\\x{0981}\\x{09BC}\\x{09C1}-\\x{09C4}\\x{09CD}\\x{09E2}-\\x{09E3}\\x{09FE}\\x{0A01}-\\x{0A02}\\x{0A3C}\\x{0A41}-\\x{0A42}\\x{0A47}-\\x{0A48}\\x{0A4B}-\\x{0A4D}\\x{0A51}\\x{0A70}-\\x{0A71}\\x{0A75}\\x{0A81}-\\x{0A82}\\x{0ABC}\\x{0AC1}-\\x{0AC5}\\x{0AC7}-\\x{0AC8}\\x{0ACD}\\x{0AE2}-\\x{0AE3}\\x{0AFA}-\\x{0AFF}\\x{0B01}\\x{0B3C}\\x{0B3F}\\x{0B41}-\\x{0B44}\\x{0B4D}\\x{0B55}-\\x{0B56}\\x{0B62}-\\x{0B63}\\x{0B82}\\x{0BC0}\\x{0BCD}\\x{0C00}\\x{0C04}\\x{0C3E}-\\x{0C40}\\x{0C46}-\\x{0C48}\\x{0C4A}-\\x{0C4D}\\x{0C55}-\\x{0C56}\\x{0C62}-\\x{0C63}\\x{0C81}\\x{0CBC}\\x{0CCC}-\\x{0CCD}\\x{0CE2}-\\x{0CE3}\\x{0D00}-\\x{0D01}\\x{0D3B}-\\x{0D3C}\\x{0D41}-\\x{0D44}\\x{0D4D}\\x{0D62}-\\x{0D63}\\x{0D81}\\x{0DCA}\\x{0DD2}-\\x{0DD4}\\x{0DD6}\\x{0E31}\\x{0E34}-\\x{0E3A}\\x{0E47}-\\x{0E4E}\\x{0EB1}\\x{0EB4}-\\x{0EBC}\\x{0EC8}-\\x{0ECD}\\x{0F18}-\\x{0F19}\\x{0F35}\\x{0F37}\\x{0F39}\\x{0F71}-\\x{0F7E}\\x{0F80}-\\x{0F84}\\x{0F86}-\\x{0F87}\\x{0F8D}-\\x{0F97}\\x{0F99}-\\x{0FBC}\\x{0FC6}\\x{102D}-\\x{1030}\\x{1032}-\\x{1037}\\x{1039}-\\x{103A}\\x{103D}-\\x{103E}\\x{1058}-\\x{1059}\\x{105E}-\\x{1060}\\x{1071}-\\x{1074}\\x{1082}\\x{1085}-\\x{1086}\\x{108D}\\x{109D}\\x{135D}-\\x{135F}\\x{1712}-\\x{1714}\\x{1732}-\\x{1734}\\x{1752}-\\x{1753}\\x{1772}-\\x{1773}\\x{17B4}-\\x{17B5}\\x{17B7}-\\x{17BD}\\x{17C6}\\x{17C9}-\\x{17D3}\\x{17DD}\\x{180B}-\\x{180D}\\x{1885}-\\x{1886}\\x{18A9}\\x{1920}-\\x{1922}\\x{1927}-\\x{1928}\\x{1932}\\x{1939}-\\x{193B}\\x{1A17}-\\x{1A18}\\x{1A1B}\\x{1A56}\\x{1A58}-\\x{1A5E}\\x{1A60}\\x{1A62}\\x{1A65}-\\x{1A6C}\\x{1A73}-\\x{1A7C}\\x{1A7F}\\x{1AB0}-\\x{1ABD}\\x{1ABE}\\x{1ABF}-\\x{1AC0}\\x{1B00}-\\x{1B03}\\x{1B34}\\x{1B36}-\\x{1B3A}\\x{1B3C}\\x{1B42}\\x{1B6B}-\\x{1B73}\\x{1B80}-\\x{1B81}\\x{1BA2}-\\x{1BA5}\\x{1BA8}-\\x{1BA9}\\x{1BAB}-\\x{1BAD}\\x{1BE6}\\x{1BE8}-\\x{1BE9}\\x{1BED}\\x{1BEF}-\\x{1BF1}\\x{1C2C}-\\x{1C33}\\x{1C36}-\\x{1C37}\\x{1CD0}-\\x{1CD2}\\x{1CD4}-\\x{1CE0}\\x{1CE2}-\\x{1CE8}\\x{1CED}\\x{1CF4}\\x{1CF8}-\\x{1CF9}\\x{1DC0}-\\x{1DF9}\\x{1DFB}-\\x{1DFF}\\x{20D0}-\\x{20DC}\\x{20DD}-\\x{20E0}\\x{20E1}\\x{20E2}-\\x{20E4}\\x{20E5}-\\x{20F0}\\x{2CEF}-\\x{2CF1}\\x{2D7F}\\x{2DE0}-\\x{2DFF}\\x{302A}-\\x{302D}\\x{3099}-\\x{309A}\\x{A66F}\\x{A670}-\\x{A672}\\x{A674}-\\x{A67D}\\x{A69E}-\\x{A69F}\\x{A6F0}-\\x{A6F1}\\x{A802}\\x{A806}\\x{A80B}\\x{A825}-\\x{A826}\\x{A82C}\\x{A8C4}-\\x{A8C5}\\x{A8E0}-\\x{A8F1}\\x{A8FF}\\x{A926}-\\x{A92D}\\x{A947}-\\x{A951}\\x{A980}-\\x{A982}\\x{A9B3}\\x{A9B6}-\\x{A9B9}\\x{A9BC}-\\x{A9BD}\\x{A9E5}\\x{AA29}-\\x{AA2E}\\x{AA31}-\\x{AA32}\\x{AA35}-\\x{AA36}\\x{AA43}\\x{AA4C}\\x{AA7C}\\x{AAB0}\\x{AAB2}-\\x{AAB4}\\x{AAB7}-\\x{AAB8}\\x{AABE}-\\x{AABF}\\x{AAC1}\\x{AAEC}-\\x{AAED}\\x{AAF6}\\x{ABE5}\\x{ABE8}\\x{ABED}\\x{FB1E}\\x{FE00}-\\x{FE0F}\\x{FE20}-\\x{FE2F}\\x{101FD}\\x{102E0}\\x{10376}-\\x{1037A}\\x{10A01}-\\x{10A03}\\x{10A05}-\\x{10A06}\\x{10A0C}-\\x{10A0F}\\x{10A38}-\\x{10A3A}\\x{10A3F}\\x{10AE5}-\\x{10AE6}\\x{10D24}-\\x{10D27}\\x{10EAB}-\\x{10EAC}\\x{10F46}-\\x{10F50}\\x{11001}\\x{11038}-\\x{11046}\\x{1107F}-\\x{11081}\\x{110B3}-\\x{110B6}\\x{110B9}-\\x{110BA}\\x{11100}-\\x{11102}\\x{11127}-\\x{1112B}\\x{1112D}-\\x{11134}\\x{11173}\\x{11180}-\\x{11181}\\x{111B6}-\\x{111BE}\\x{111C9}-\\x{111CC}\\x{111CF}\\x{1122F}-\\x{11231}\\x{11234}\\x{11236}-\\x{11237}\\x{1123E}\\x{112DF}\\x{112E3}-\\x{112EA}\\x{11300}-\\x{11301}\\x{1133B}-\\x{1133C}\\x{11340}\\x{11366}-\\x{1136C}\\x{11370}-\\x{11374}\\x{11438}-\\x{1143F}\\x{11442}-\\x{11444}\\x{11446}\\x{1145E}\\x{114B3}-\\x{114B8}\\x{114BA}\\x{114BF}-\\x{114C0}\\x{114C2}-\\x{114C3}\\x{115B2}-\\x{115B5}\\x{115BC}-\\x{115BD}\\x{115BF}-\\x{115C0}\\x{115DC}-\\x{115DD}\\x{11633}-\\x{1163A}\\x{1163D}\\x{1163F}-\\x{11640}\\x{116AB}\\x{116AD}\\x{116B0}-\\x{116B5}\\x{116B7}\\x{1171D}-\\x{1171F}\\x{11722}-\\x{11725}\\x{11727}-\\x{1172B}\\x{1182F}-\\x{11837}\\x{11839}-\\x{1183A}\\x{1193B}-\\x{1193C}\\x{1193E}\\x{11943}\\x{119D4}-\\x{119D7}\\x{119DA}-\\x{119DB}\\x{119E0}\\x{11A01}-\\x{11A06}\\x{11A09}-\\x{11A0A}\\x{11A33}-\\x{11A38}\\x{11A3B}-\\x{11A3E}\\x{11A47}\\x{11A51}-\\x{11A56}\\x{11A59}-\\x{11A5B}\\x{11A8A}-\\x{11A96}\\x{11A98}-\\x{11A99}\\x{11C30}-\\x{11C36}\\x{11C38}-\\x{11C3D}\\x{11C92}-\\x{11CA7}\\x{11CAA}-\\x{11CB0}\\x{11CB2}-\\x{11CB3}\\x{11CB5}-\\x{11CB6}\\x{11D31}-\\x{11D36}\\x{11D3A}\\x{11D3C}-\\x{11D3D}\\x{11D3F}-\\x{11D45}\\x{11D47}\\x{11D90}-\\x{11D91}\\x{11D95}\\x{11D97}\\x{11EF3}-\\x{11EF4}\\x{16AF0}-\\x{16AF4}\\x{16B30}-\\x{16B36}\\x{16F4F}\\x{16F8F}-\\x{16F92}\\x{16FE4}\\x{1BC9D}-\\x{1BC9E}\\x{1D167}-\\x{1D169}\\x{1D17B}-\\x{1D182}\\x{1D185}-\\x{1D18B}\\x{1D1AA}-\\x{1D1AD}\\x{1D242}-\\x{1D244}\\x{1DA00}-\\x{1DA36}\\x{1DA3B}-\\x{1DA6C}\\x{1DA75}\\x{1DA84}\\x{1DA9B}-\\x{1DA9F}\\x{1DAA1}-\\x{1DAAF}\\x{1E000}-\\x{1E006}\\x{1E008}-\\x{1E018}\\x{1E01B}-\\x{1E021}\\x{1E023}-\\x{1E024}\\x{1E026}-\\x{1E02A}\\x{1E130}-\\x{1E136}\\x{1E2EC}-\\x{1E2EF}\\x{1E8D0}-\\x{1E8D6}\\x{1E944}-\\x{1E94A}\\x{E0100}-\\x{E01EF}]*$/u';\n\n    const ZWNJ = '/([\\x{A872}\\x{10ACD}\\x{10AD7}\\x{10D00}\\x{10FCB}\\x{0620}\\x{0626}\\x{0628}\\x{062A}-\\x{062E}\\x{0633}-\\x{063F}\\x{0641}-\\x{0647}\\x{0649}-\\x{064A}\\x{066E}-\\x{066F}\\x{0678}-\\x{0687}\\x{069A}-\\x{06BF}\\x{06C1}-\\x{06C2}\\x{06CC}\\x{06CE}\\x{06D0}-\\x{06D1}\\x{06FA}-\\x{06FC}\\x{06FF}\\x{0712}-\\x{0714}\\x{071A}-\\x{071D}\\x{071F}-\\x{0727}\\x{0729}\\x{072B}\\x{072D}-\\x{072E}\\x{074E}-\\x{0758}\\x{075C}-\\x{076A}\\x{076D}-\\x{0770}\\x{0772}\\x{0775}-\\x{0777}\\x{077A}-\\x{077F}\\x{07CA}-\\x{07EA}\\x{0841}-\\x{0845}\\x{0848}\\x{084A}-\\x{0853}\\x{0855}\\x{0860}\\x{0862}-\\x{0865}\\x{0868}\\x{08A0}-\\x{08A9}\\x{08AF}-\\x{08B0}\\x{08B3}-\\x{08B4}\\x{08B6}-\\x{08B8}\\x{08BA}-\\x{08C7}\\x{1807}\\x{1820}-\\x{1842}\\x{1843}\\x{1844}-\\x{1878}\\x{1887}-\\x{18A8}\\x{18AA}\\x{A840}-\\x{A871}\\x{10AC0}-\\x{10AC4}\\x{10AD3}-\\x{10AD6}\\x{10AD8}-\\x{10ADC}\\x{10ADE}-\\x{10AE0}\\x{10AEB}-\\x{10AEE}\\x{10B80}\\x{10B82}\\x{10B86}-\\x{10B88}\\x{10B8A}-\\x{10B8B}\\x{10B8D}\\x{10B90}\\x{10BAD}-\\x{10BAE}\\x{10D01}-\\x{10D21}\\x{10D23}\\x{10F30}-\\x{10F32}\\x{10F34}-\\x{10F44}\\x{10F51}-\\x{10F53}\\x{10FB0}\\x{10FB2}-\\x{10FB3}\\x{10FB8}\\x{10FBB}-\\x{10FBC}\\x{10FBE}-\\x{10FBF}\\x{10FC1}\\x{10FC4}\\x{10FCA}\\x{1E900}-\\x{1E943}][\\x{00AD}\\x{0300}-\\x{036F}\\x{0483}-\\x{0487}\\x{0488}-\\x{0489}\\x{0591}-\\x{05BD}\\x{05BF}\\x{05C1}-\\x{05C2}\\x{05C4}-\\x{05C5}\\x{05C7}\\x{0610}-\\x{061A}\\x{061C}\\x{064B}-\\x{065F}\\x{0670}\\x{06D6}-\\x{06DC}\\x{06DF}-\\x{06E4}\\x{06E7}-\\x{06E8}\\x{06EA}-\\x{06ED}\\x{070F}\\x{0711}\\x{0730}-\\x{074A}\\x{07A6}-\\x{07B0}\\x{07EB}-\\x{07F3}\\x{07FD}\\x{0816}-\\x{0819}\\x{081B}-\\x{0823}\\x{0825}-\\x{0827}\\x{0829}-\\x{082D}\\x{0859}-\\x{085B}\\x{08D3}-\\x{08E1}\\x{08E3}-\\x{0902}\\x{093A}\\x{093C}\\x{0941}-\\x{0948}\\x{094D}\\x{0951}-\\x{0957}\\x{0962}-\\x{0963}\\x{0981}\\x{09BC}\\x{09C1}-\\x{09C4}\\x{09CD}\\x{09E2}-\\x{09E3}\\x{09FE}\\x{0A01}-\\x{0A02}\\x{0A3C}\\x{0A41}-\\x{0A42}\\x{0A47}-\\x{0A48}\\x{0A4B}-\\x{0A4D}\\x{0A51}\\x{0A70}-\\x{0A71}\\x{0A75}\\x{0A81}-\\x{0A82}\\x{0ABC}\\x{0AC1}-\\x{0AC5}\\x{0AC7}-\\x{0AC8}\\x{0ACD}\\x{0AE2}-\\x{0AE3}\\x{0AFA}-\\x{0AFF}\\x{0B01}\\x{0B3C}\\x{0B3F}\\x{0B41}-\\x{0B44}\\x{0B4D}\\x{0B55}-\\x{0B56}\\x{0B62}-\\x{0B63}\\x{0B82}\\x{0BC0}\\x{0BCD}\\x{0C00}\\x{0C04}\\x{0C3E}-\\x{0C40}\\x{0C46}-\\x{0C48}\\x{0C4A}-\\x{0C4D}\\x{0C55}-\\x{0C56}\\x{0C62}-\\x{0C63}\\x{0C81}\\x{0CBC}\\x{0CBF}\\x{0CC6}\\x{0CCC}-\\x{0CCD}\\x{0CE2}-\\x{0CE3}\\x{0D00}-\\x{0D01}\\x{0D3B}-\\x{0D3C}\\x{0D41}-\\x{0D44}\\x{0D4D}\\x{0D62}-\\x{0D63}\\x{0D81}\\x{0DCA}\\x{0DD2}-\\x{0DD4}\\x{0DD6}\\x{0E31}\\x{0E34}-\\x{0E3A}\\x{0E47}-\\x{0E4E}\\x{0EB1}\\x{0EB4}-\\x{0EBC}\\x{0EC8}-\\x{0ECD}\\x{0F18}-\\x{0F19}\\x{0F35}\\x{0F37}\\x{0F39}\\x{0F71}-\\x{0F7E}\\x{0F80}-\\x{0F84}\\x{0F86}-\\x{0F87}\\x{0F8D}-\\x{0F97}\\x{0F99}-\\x{0FBC}\\x{0FC6}\\x{102D}-\\x{1030}\\x{1032}-\\x{1037}\\x{1039}-\\x{103A}\\x{103D}-\\x{103E}\\x{1058}-\\x{1059}\\x{105E}-\\x{1060}\\x{1071}-\\x{1074}\\x{1082}\\x{1085}-\\x{1086}\\x{108D}\\x{109D}\\x{135D}-\\x{135F}\\x{1712}-\\x{1714}\\x{1732}-\\x{1734}\\x{1752}-\\x{1753}\\x{1772}-\\x{1773}\\x{17B4}-\\x{17B5}\\x{17B7}-\\x{17BD}\\x{17C6}\\x{17C9}-\\x{17D3}\\x{17DD}\\x{180B}-\\x{180D}\\x{1885}-\\x{1886}\\x{18A9}\\x{1920}-\\x{1922}\\x{1927}-\\x{1928}\\x{1932}\\x{1939}-\\x{193B}\\x{1A17}-\\x{1A18}\\x{1A1B}\\x{1A56}\\x{1A58}-\\x{1A5E}\\x{1A60}\\x{1A62}\\x{1A65}-\\x{1A6C}\\x{1A73}-\\x{1A7C}\\x{1A7F}\\x{1AB0}-\\x{1ABD}\\x{1ABE}\\x{1ABF}-\\x{1AC0}\\x{1B00}-\\x{1B03}\\x{1B34}\\x{1B36}-\\x{1B3A}\\x{1B3C}\\x{1B42}\\x{1B6B}-\\x{1B73}\\x{1B80}-\\x{1B81}\\x{1BA2}-\\x{1BA5}\\x{1BA8}-\\x{1BA9}\\x{1BAB}-\\x{1BAD}\\x{1BE6}\\x{1BE8}-\\x{1BE9}\\x{1BED}\\x{1BEF}-\\x{1BF1}\\x{1C2C}-\\x{1C33}\\x{1C36}-\\x{1C37}\\x{1CD0}-\\x{1CD2}\\x{1CD4}-\\x{1CE0}\\x{1CE2}-\\x{1CE8}\\x{1CED}\\x{1CF4}\\x{1CF8}-\\x{1CF9}\\x{1DC0}-\\x{1DF9}\\x{1DFB}-\\x{1DFF}\\x{200B}\\x{200E}-\\x{200F}\\x{202A}-\\x{202E}\\x{2060}-\\x{2064}\\x{206A}-\\x{206F}\\x{20D0}-\\x{20DC}\\x{20DD}-\\x{20E0}\\x{20E1}\\x{20E2}-\\x{20E4}\\x{20E5}-\\x{20F0}\\x{2CEF}-\\x{2CF1}\\x{2D7F}\\x{2DE0}-\\x{2DFF}\\x{302A}-\\x{302D}\\x{3099}-\\x{309A}\\x{A66F}\\x{A670}-\\x{A672}\\x{A674}-\\x{A67D}\\x{A69E}-\\x{A69F}\\x{A6F0}-\\x{A6F1}\\x{A802}\\x{A806}\\x{A80B}\\x{A825}-\\x{A826}\\x{A82C}\\x{A8C4}-\\x{A8C5}\\x{A8E0}-\\x{A8F1}\\x{A8FF}\\x{A926}-\\x{A92D}\\x{A947}-\\x{A951}\\x{A980}-\\x{A982}\\x{A9B3}\\x{A9B6}-\\x{A9B9}\\x{A9BC}-\\x{A9BD}\\x{A9E5}\\x{AA29}-\\x{AA2E}\\x{AA31}-\\x{AA32}\\x{AA35}-\\x{AA36}\\x{AA43}\\x{AA4C}\\x{AA7C}\\x{AAB0}\\x{AAB2}-\\x{AAB4}\\x{AAB7}-\\x{AAB8}\\x{AABE}-\\x{AABF}\\x{AAC1}\\x{AAEC}-\\x{AAED}\\x{AAF6}\\x{ABE5}\\x{ABE8}\\x{ABED}\\x{FB1E}\\x{FE00}-\\x{FE0F}\\x{FE20}-\\x{FE2F}\\x{FEFF}\\x{FFF9}-\\x{FFFB}\\x{101FD}\\x{102E0}\\x{10376}-\\x{1037A}\\x{10A01}-\\x{10A03}\\x{10A05}-\\x{10A06}\\x{10A0C}-\\x{10A0F}\\x{10A38}-\\x{10A3A}\\x{10A3F}\\x{10AE5}-\\x{10AE6}\\x{10D24}-\\x{10D27}\\x{10EAB}-\\x{10EAC}\\x{10F46}-\\x{10F50}\\x{11001}\\x{11038}-\\x{11046}\\x{1107F}-\\x{11081}\\x{110B3}-\\x{110B6}\\x{110B9}-\\x{110BA}\\x{11100}-\\x{11102}\\x{11127}-\\x{1112B}\\x{1112D}-\\x{11134}\\x{11173}\\x{11180}-\\x{11181}\\x{111B6}-\\x{111BE}\\x{111C9}-\\x{111CC}\\x{111CF}\\x{1122F}-\\x{11231}\\x{11234}\\x{11236}-\\x{11237}\\x{1123E}\\x{112DF}\\x{112E3}-\\x{112EA}\\x{11300}-\\x{11301}\\x{1133B}-\\x{1133C}\\x{11340}\\x{11366}-\\x{1136C}\\x{11370}-\\x{11374}\\x{11438}-\\x{1143F}\\x{11442}-\\x{11444}\\x{11446}\\x{1145E}\\x{114B3}-\\x{114B8}\\x{114BA}\\x{114BF}-\\x{114C0}\\x{114C2}-\\x{114C3}\\x{115B2}-\\x{115B5}\\x{115BC}-\\x{115BD}\\x{115BF}-\\x{115C0}\\x{115DC}-\\x{115DD}\\x{11633}-\\x{1163A}\\x{1163D}\\x{1163F}-\\x{11640}\\x{116AB}\\x{116AD}\\x{116B0}-\\x{116B5}\\x{116B7}\\x{1171D}-\\x{1171F}\\x{11722}-\\x{11725}\\x{11727}-\\x{1172B}\\x{1182F}-\\x{11837}\\x{11839}-\\x{1183A}\\x{1193B}-\\x{1193C}\\x{1193E}\\x{11943}\\x{119D4}-\\x{119D7}\\x{119DA}-\\x{119DB}\\x{119E0}\\x{11A01}-\\x{11A0A}\\x{11A33}-\\x{11A38}\\x{11A3B}-\\x{11A3E}\\x{11A47}\\x{11A51}-\\x{11A56}\\x{11A59}-\\x{11A5B}\\x{11A8A}-\\x{11A96}\\x{11A98}-\\x{11A99}\\x{11C30}-\\x{11C36}\\x{11C38}-\\x{11C3D}\\x{11C3F}\\x{11C92}-\\x{11CA7}\\x{11CAA}-\\x{11CB0}\\x{11CB2}-\\x{11CB3}\\x{11CB5}-\\x{11CB6}\\x{11D31}-\\x{11D36}\\x{11D3A}\\x{11D3C}-\\x{11D3D}\\x{11D3F}-\\x{11D45}\\x{11D47}\\x{11D90}-\\x{11D91}\\x{11D95}\\x{11D97}\\x{11EF3}-\\x{11EF4}\\x{13430}-\\x{13438}\\x{16AF0}-\\x{16AF4}\\x{16B30}-\\x{16B36}\\x{16F4F}\\x{16F8F}-\\x{16F92}\\x{16FE4}\\x{1BC9D}-\\x{1BC9E}\\x{1BCA0}-\\x{1BCA3}\\x{1D167}-\\x{1D169}\\x{1D173}-\\x{1D17A}\\x{1D17B}-\\x{1D182}\\x{1D185}-\\x{1D18B}\\x{1D1AA}-\\x{1D1AD}\\x{1D242}-\\x{1D244}\\x{1DA00}-\\x{1DA36}\\x{1DA3B}-\\x{1DA6C}\\x{1DA75}\\x{1DA84}\\x{1DA9B}-\\x{1DA9F}\\x{1DAA1}-\\x{1DAAF}\\x{1E000}-\\x{1E006}\\x{1E008}-\\x{1E018}\\x{1E01B}-\\x{1E021}\\x{1E023}-\\x{1E024}\\x{1E026}-\\x{1E02A}\\x{1E130}-\\x{1E136}\\x{1E2EC}-\\x{1E2EF}\\x{1E8D0}-\\x{1E8D6}\\x{1E944}-\\x{1E94A}\\x{1E94B}\\x{E0001}\\x{E0020}-\\x{E007F}\\x{E0100}-\\x{E01EF}]*\\x{200C}[\\x{00AD}\\x{0300}-\\x{036F}\\x{0483}-\\x{0487}\\x{0488}-\\x{0489}\\x{0591}-\\x{05BD}\\x{05BF}\\x{05C1}-\\x{05C2}\\x{05C4}-\\x{05C5}\\x{05C7}\\x{0610}-\\x{061A}\\x{061C}\\x{064B}-\\x{065F}\\x{0670}\\x{06D6}-\\x{06DC}\\x{06DF}-\\x{06E4}\\x{06E7}-\\x{06E8}\\x{06EA}-\\x{06ED}\\x{070F}\\x{0711}\\x{0730}-\\x{074A}\\x{07A6}-\\x{07B0}\\x{07EB}-\\x{07F3}\\x{07FD}\\x{0816}-\\x{0819}\\x{081B}-\\x{0823}\\x{0825}-\\x{0827}\\x{0829}-\\x{082D}\\x{0859}-\\x{085B}\\x{08D3}-\\x{08E1}\\x{08E3}-\\x{0902}\\x{093A}\\x{093C}\\x{0941}-\\x{0948}\\x{094D}\\x{0951}-\\x{0957}\\x{0962}-\\x{0963}\\x{0981}\\x{09BC}\\x{09C1}-\\x{09C4}\\x{09CD}\\x{09E2}-\\x{09E3}\\x{09FE}\\x{0A01}-\\x{0A02}\\x{0A3C}\\x{0A41}-\\x{0A42}\\x{0A47}-\\x{0A48}\\x{0A4B}-\\x{0A4D}\\x{0A51}\\x{0A70}-\\x{0A71}\\x{0A75}\\x{0A81}-\\x{0A82}\\x{0ABC}\\x{0AC1}-\\x{0AC5}\\x{0AC7}-\\x{0AC8}\\x{0ACD}\\x{0AE2}-\\x{0AE3}\\x{0AFA}-\\x{0AFF}\\x{0B01}\\x{0B3C}\\x{0B3F}\\x{0B41}-\\x{0B44}\\x{0B4D}\\x{0B55}-\\x{0B56}\\x{0B62}-\\x{0B63}\\x{0B82}\\x{0BC0}\\x{0BCD}\\x{0C00}\\x{0C04}\\x{0C3E}-\\x{0C40}\\x{0C46}-\\x{0C48}\\x{0C4A}-\\x{0C4D}\\x{0C55}-\\x{0C56}\\x{0C62}-\\x{0C63}\\x{0C81}\\x{0CBC}\\x{0CBF}\\x{0CC6}\\x{0CCC}-\\x{0CCD}\\x{0CE2}-\\x{0CE3}\\x{0D00}-\\x{0D01}\\x{0D3B}-\\x{0D3C}\\x{0D41}-\\x{0D44}\\x{0D4D}\\x{0D62}-\\x{0D63}\\x{0D81}\\x{0DCA}\\x{0DD2}-\\x{0DD4}\\x{0DD6}\\x{0E31}\\x{0E34}-\\x{0E3A}\\x{0E47}-\\x{0E4E}\\x{0EB1}\\x{0EB4}-\\x{0EBC}\\x{0EC8}-\\x{0ECD}\\x{0F18}-\\x{0F19}\\x{0F35}\\x{0F37}\\x{0F39}\\x{0F71}-\\x{0F7E}\\x{0F80}-\\x{0F84}\\x{0F86}-\\x{0F87}\\x{0F8D}-\\x{0F97}\\x{0F99}-\\x{0FBC}\\x{0FC6}\\x{102D}-\\x{1030}\\x{1032}-\\x{1037}\\x{1039}-\\x{103A}\\x{103D}-\\x{103E}\\x{1058}-\\x{1059}\\x{105E}-\\x{1060}\\x{1071}-\\x{1074}\\x{1082}\\x{1085}-\\x{1086}\\x{108D}\\x{109D}\\x{135D}-\\x{135F}\\x{1712}-\\x{1714}\\x{1732}-\\x{1734}\\x{1752}-\\x{1753}\\x{1772}-\\x{1773}\\x{17B4}-\\x{17B5}\\x{17B7}-\\x{17BD}\\x{17C6}\\x{17C9}-\\x{17D3}\\x{17DD}\\x{180B}-\\x{180D}\\x{1885}-\\x{1886}\\x{18A9}\\x{1920}-\\x{1922}\\x{1927}-\\x{1928}\\x{1932}\\x{1939}-\\x{193B}\\x{1A17}-\\x{1A18}\\x{1A1B}\\x{1A56}\\x{1A58}-\\x{1A5E}\\x{1A60}\\x{1A62}\\x{1A65}-\\x{1A6C}\\x{1A73}-\\x{1A7C}\\x{1A7F}\\x{1AB0}-\\x{1ABD}\\x{1ABE}\\x{1ABF}-\\x{1AC0}\\x{1B00}-\\x{1B03}\\x{1B34}\\x{1B36}-\\x{1B3A}\\x{1B3C}\\x{1B42}\\x{1B6B}-\\x{1B73}\\x{1B80}-\\x{1B81}\\x{1BA2}-\\x{1BA5}\\x{1BA8}-\\x{1BA9}\\x{1BAB}-\\x{1BAD}\\x{1BE6}\\x{1BE8}-\\x{1BE9}\\x{1BED}\\x{1BEF}-\\x{1BF1}\\x{1C2C}-\\x{1C33}\\x{1C36}-\\x{1C37}\\x{1CD0}-\\x{1CD2}\\x{1CD4}-\\x{1CE0}\\x{1CE2}-\\x{1CE8}\\x{1CED}\\x{1CF4}\\x{1CF8}-\\x{1CF9}\\x{1DC0}-\\x{1DF9}\\x{1DFB}-\\x{1DFF}\\x{200B}\\x{200E}-\\x{200F}\\x{202A}-\\x{202E}\\x{2060}-\\x{2064}\\x{206A}-\\x{206F}\\x{20D0}-\\x{20DC}\\x{20DD}-\\x{20E0}\\x{20E1}\\x{20E2}-\\x{20E4}\\x{20E5}-\\x{20F0}\\x{2CEF}-\\x{2CF1}\\x{2D7F}\\x{2DE0}-\\x{2DFF}\\x{302A}-\\x{302D}\\x{3099}-\\x{309A}\\x{A66F}\\x{A670}-\\x{A672}\\x{A674}-\\x{A67D}\\x{A69E}-\\x{A69F}\\x{A6F0}-\\x{A6F1}\\x{A802}\\x{A806}\\x{A80B}\\x{A825}-\\x{A826}\\x{A82C}\\x{A8C4}-\\x{A8C5}\\x{A8E0}-\\x{A8F1}\\x{A8FF}\\x{A926}-\\x{A92D}\\x{A947}-\\x{A951}\\x{A980}-\\x{A982}\\x{A9B3}\\x{A9B6}-\\x{A9B9}\\x{A9BC}-\\x{A9BD}\\x{A9E5}\\x{AA29}-\\x{AA2E}\\x{AA31}-\\x{AA32}\\x{AA35}-\\x{AA36}\\x{AA43}\\x{AA4C}\\x{AA7C}\\x{AAB0}\\x{AAB2}-\\x{AAB4}\\x{AAB7}-\\x{AAB8}\\x{AABE}-\\x{AABF}\\x{AAC1}\\x{AAEC}-\\x{AAED}\\x{AAF6}\\x{ABE5}\\x{ABE8}\\x{ABED}\\x{FB1E}\\x{FE00}-\\x{FE0F}\\x{FE20}-\\x{FE2F}\\x{FEFF}\\x{FFF9}-\\x{FFFB}\\x{101FD}\\x{102E0}\\x{10376}-\\x{1037A}\\x{10A01}-\\x{10A03}\\x{10A05}-\\x{10A06}\\x{10A0C}-\\x{10A0F}\\x{10A38}-\\x{10A3A}\\x{10A3F}\\x{10AE5}-\\x{10AE6}\\x{10D24}-\\x{10D27}\\x{10EAB}-\\x{10EAC}\\x{10F46}-\\x{10F50}\\x{11001}\\x{11038}-\\x{11046}\\x{1107F}-\\x{11081}\\x{110B3}-\\x{110B6}\\x{110B9}-\\x{110BA}\\x{11100}-\\x{11102}\\x{11127}-\\x{1112B}\\x{1112D}-\\x{11134}\\x{11173}\\x{11180}-\\x{11181}\\x{111B6}-\\x{111BE}\\x{111C9}-\\x{111CC}\\x{111CF}\\x{1122F}-\\x{11231}\\x{11234}\\x{11236}-\\x{11237}\\x{1123E}\\x{112DF}\\x{112E3}-\\x{112EA}\\x{11300}-\\x{11301}\\x{1133B}-\\x{1133C}\\x{11340}\\x{11366}-\\x{1136C}\\x{11370}-\\x{11374}\\x{11438}-\\x{1143F}\\x{11442}-\\x{11444}\\x{11446}\\x{1145E}\\x{114B3}-\\x{114B8}\\x{114BA}\\x{114BF}-\\x{114C0}\\x{114C2}-\\x{114C3}\\x{115B2}-\\x{115B5}\\x{115BC}-\\x{115BD}\\x{115BF}-\\x{115C0}\\x{115DC}-\\x{115DD}\\x{11633}-\\x{1163A}\\x{1163D}\\x{1163F}-\\x{11640}\\x{116AB}\\x{116AD}\\x{116B0}-\\x{116B5}\\x{116B7}\\x{1171D}-\\x{1171F}\\x{11722}-\\x{11725}\\x{11727}-\\x{1172B}\\x{1182F}-\\x{11837}\\x{11839}-\\x{1183A}\\x{1193B}-\\x{1193C}\\x{1193E}\\x{11943}\\x{119D4}-\\x{119D7}\\x{119DA}-\\x{119DB}\\x{119E0}\\x{11A01}-\\x{11A0A}\\x{11A33}-\\x{11A38}\\x{11A3B}-\\x{11A3E}\\x{11A47}\\x{11A51}-\\x{11A56}\\x{11A59}-\\x{11A5B}\\x{11A8A}-\\x{11A96}\\x{11A98}-\\x{11A99}\\x{11C30}-\\x{11C36}\\x{11C38}-\\x{11C3D}\\x{11C3F}\\x{11C92}-\\x{11CA7}\\x{11CAA}-\\x{11CB0}\\x{11CB2}-\\x{11CB3}\\x{11CB5}-\\x{11CB6}\\x{11D31}-\\x{11D36}\\x{11D3A}\\x{11D3C}-\\x{11D3D}\\x{11D3F}-\\x{11D45}\\x{11D47}\\x{11D90}-\\x{11D91}\\x{11D95}\\x{11D97}\\x{11EF3}-\\x{11EF4}\\x{13430}-\\x{13438}\\x{16AF0}-\\x{16AF4}\\x{16B30}-\\x{16B36}\\x{16F4F}\\x{16F8F}-\\x{16F92}\\x{16FE4}\\x{1BC9D}-\\x{1BC9E}\\x{1BCA0}-\\x{1BCA3}\\x{1D167}-\\x{1D169}\\x{1D173}-\\x{1D17A}\\x{1D17B}-\\x{1D182}\\x{1D185}-\\x{1D18B}\\x{1D1AA}-\\x{1D1AD}\\x{1D242}-\\x{1D244}\\x{1DA00}-\\x{1DA36}\\x{1DA3B}-\\x{1DA6C}\\x{1DA75}\\x{1DA84}\\x{1DA9B}-\\x{1DA9F}\\x{1DAA1}-\\x{1DAAF}\\x{1E000}-\\x{1E006}\\x{1E008}-\\x{1E018}\\x{1E01B}-\\x{1E021}\\x{1E023}-\\x{1E024}\\x{1E026}-\\x{1E02A}\\x{1E130}-\\x{1E136}\\x{1E2EC}-\\x{1E2EF}\\x{1E8D0}-\\x{1E8D6}\\x{1E944}-\\x{1E94A}\\x{1E94B}\\x{E0001}\\x{E0020}-\\x{E007F}\\x{E0100}-\\x{E01EF}]*)[\\x{0622}-\\x{0625}\\x{0627}\\x{0629}\\x{062F}-\\x{0632}\\x{0648}\\x{0671}-\\x{0673}\\x{0675}-\\x{0677}\\x{0688}-\\x{0699}\\x{06C0}\\x{06C3}-\\x{06CB}\\x{06CD}\\x{06CF}\\x{06D2}-\\x{06D3}\\x{06D5}\\x{06EE}-\\x{06EF}\\x{0710}\\x{0715}-\\x{0719}\\x{071E}\\x{0728}\\x{072A}\\x{072C}\\x{072F}\\x{074D}\\x{0759}-\\x{075B}\\x{076B}-\\x{076C}\\x{0771}\\x{0773}-\\x{0774}\\x{0778}-\\x{0779}\\x{0840}\\x{0846}-\\x{0847}\\x{0849}\\x{0854}\\x{0856}-\\x{0858}\\x{0867}\\x{0869}-\\x{086A}\\x{08AA}-\\x{08AC}\\x{08AE}\\x{08B1}-\\x{08B2}\\x{08B9}\\x{10AC5}\\x{10AC7}\\x{10AC9}-\\x{10ACA}\\x{10ACE}-\\x{10AD2}\\x{10ADD}\\x{10AE1}\\x{10AE4}\\x{10AEF}\\x{10B81}\\x{10B83}-\\x{10B85}\\x{10B89}\\x{10B8C}\\x{10B8E}-\\x{10B8F}\\x{10B91}\\x{10BA9}-\\x{10BAC}\\x{10D22}\\x{10F33}\\x{10F54}\\x{10FB4}-\\x{10FB6}\\x{10FB9}-\\x{10FBA}\\x{10FBD}\\x{10FC2}-\\x{10FC3}\\x{10FC9}\\x{0620}\\x{0626}\\x{0628}\\x{062A}-\\x{062E}\\x{0633}-\\x{063F}\\x{0641}-\\x{0647}\\x{0649}-\\x{064A}\\x{066E}-\\x{066F}\\x{0678}-\\x{0687}\\x{069A}-\\x{06BF}\\x{06C1}-\\x{06C2}\\x{06CC}\\x{06CE}\\x{06D0}-\\x{06D1}\\x{06FA}-\\x{06FC}\\x{06FF}\\x{0712}-\\x{0714}\\x{071A}-\\x{071D}\\x{071F}-\\x{0727}\\x{0729}\\x{072B}\\x{072D}-\\x{072E}\\x{074E}-\\x{0758}\\x{075C}-\\x{076A}\\x{076D}-\\x{0770}\\x{0772}\\x{0775}-\\x{0777}\\x{077A}-\\x{077F}\\x{07CA}-\\x{07EA}\\x{0841}-\\x{0845}\\x{0848}\\x{084A}-\\x{0853}\\x{0855}\\x{0860}\\x{0862}-\\x{0865}\\x{0868}\\x{08A0}-\\x{08A9}\\x{08AF}-\\x{08B0}\\x{08B3}-\\x{08B4}\\x{08B6}-\\x{08B8}\\x{08BA}-\\x{08C7}\\x{1807}\\x{1820}-\\x{1842}\\x{1843}\\x{1844}-\\x{1878}\\x{1887}-\\x{18A8}\\x{18AA}\\x{A840}-\\x{A871}\\x{10AC0}-\\x{10AC4}\\x{10AD3}-\\x{10AD6}\\x{10AD8}-\\x{10ADC}\\x{10ADE}-\\x{10AE0}\\x{10AEB}-\\x{10AEE}\\x{10B80}\\x{10B82}\\x{10B86}-\\x{10B88}\\x{10B8A}-\\x{10B8B}\\x{10B8D}\\x{10B90}\\x{10BAD}-\\x{10BAE}\\x{10D01}-\\x{10D21}\\x{10D23}\\x{10F30}-\\x{10F32}\\x{10F34}-\\x{10F44}\\x{10F51}-\\x{10F53}\\x{10FB0}\\x{10FB2}-\\x{10FB3}\\x{10FB8}\\x{10FBB}-\\x{10FBC}\\x{10FBE}-\\x{10FBF}\\x{10FC1}\\x{10FC4}\\x{10FCA}\\x{1E900}-\\x{1E943}]/u';\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-intl-idn/Resources/unidata/deviation.php",
    "content": "<?php\n\nreturn array (\n  223 => 'ss',\n  962 => 'σ',\n  8204 => '',\n  8205 => '',\n);\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-intl-idn/Resources/unidata/disallowed.php",
    "content": "<?php\n\nreturn array (\n  888 => true,\n  889 => true,\n  896 => true,\n  897 => true,\n  898 => true,\n  899 => true,\n  907 => true,\n  909 => true,\n  930 => true,\n  1216 => true,\n  1328 => true,\n  1367 => true,\n  1368 => true,\n  1419 => true,\n  1420 => true,\n  1424 => true,\n  1480 => true,\n  1481 => true,\n  1482 => true,\n  1483 => true,\n  1484 => true,\n  1485 => true,\n  1486 => true,\n  1487 => true,\n  1515 => true,\n  1516 => true,\n  1517 => true,\n  1518 => true,\n  1525 => true,\n  1526 => true,\n  1527 => true,\n  1528 => true,\n  1529 => true,\n  1530 => true,\n  1531 => true,\n  1532 => true,\n  1533 => true,\n  1534 => true,\n  1535 => true,\n  1536 => true,\n  1537 => true,\n  1538 => true,\n  1539 => true,\n  1540 => true,\n  1541 => true,\n  1564 => true,\n  1565 => true,\n  1757 => true,\n  1806 => true,\n  1807 => true,\n  1867 => true,\n  1868 => true,\n  1970 => true,\n  1971 => true,\n  1972 => true,\n  1973 => true,\n  1974 => true,\n  1975 => true,\n  1976 => true,\n  1977 => true,\n  1978 => true,\n  1979 => true,\n  1980 => true,\n  1981 => true,\n  1982 => true,\n  1983 => true,\n  2043 => true,\n  2044 => true,\n  2094 => true,\n  2095 => true,\n  2111 => true,\n  2140 => true,\n  2141 => true,\n  2143 => true,\n  2229 => true,\n  2248 => true,\n  2249 => true,\n  2250 => true,\n  2251 => true,\n  2252 => true,\n  2253 => true,\n  2254 => true,\n  2255 => true,\n  2256 => true,\n  2257 => true,\n  2258 => true,\n  2274 => true,\n  2436 => true,\n  2445 => true,\n  2446 => true,\n  2449 => true,\n  2450 => true,\n  2473 => true,\n  2481 => true,\n  2483 => true,\n  2484 => true,\n  2485 => true,\n  2490 => true,\n  2491 => true,\n  2501 => true,\n  2502 => true,\n  2505 => true,\n  2506 => true,\n  2511 => true,\n  2512 => true,\n  2513 => true,\n  2514 => true,\n  2515 => true,\n  2516 => true,\n  2517 => true,\n  2518 => true,\n  2520 => true,\n  2521 => true,\n  2522 => true,\n  2523 => true,\n  2526 => true,\n  2532 => true,\n  2533 => true,\n  2559 => true,\n  2560 => true,\n  2564 => true,\n  2571 => true,\n  2572 => true,\n  2573 => true,\n  2574 => true,\n  2577 => true,\n  2578 => true,\n  2601 => true,\n  2609 => true,\n  2612 => true,\n  2615 => true,\n  2618 => true,\n  2619 => true,\n  2621 => true,\n  2627 => true,\n  2628 => true,\n  2629 => true,\n  2630 => true,\n  2633 => true,\n  2634 => true,\n  2638 => true,\n  2639 => true,\n  2640 => true,\n  2642 => true,\n  2643 => true,\n  2644 => true,\n  2645 => true,\n  2646 => true,\n  2647 => true,\n  2648 => true,\n  2653 => true,\n  2655 => true,\n  2656 => true,\n  2657 => true,\n  2658 => true,\n  2659 => true,\n  2660 => true,\n  2661 => true,\n  2679 => true,\n  2680 => true,\n  2681 => true,\n  2682 => true,\n  2683 => true,\n  2684 => true,\n  2685 => true,\n  2686 => true,\n  2687 => true,\n  2688 => true,\n  2692 => true,\n  2702 => true,\n  2706 => true,\n  2729 => true,\n  2737 => true,\n  2740 => true,\n  2746 => true,\n  2747 => true,\n  2758 => true,\n  2762 => true,\n  2766 => true,\n  2767 => true,\n  2769 => true,\n  2770 => true,\n  2771 => true,\n  2772 => true,\n  2773 => true,\n  2774 => true,\n  2775 => true,\n  2776 => true,\n  2777 => true,\n  2778 => true,\n  2779 => true,\n  2780 => true,\n  2781 => true,\n  2782 => true,\n  2783 => true,\n  2788 => true,\n  2789 => true,\n  2802 => true,\n  2803 => true,\n  2804 => true,\n  2805 => true,\n  2806 => true,\n  2807 => true,\n  2808 => true,\n  2816 => true,\n  2820 => true,\n  2829 => true,\n  2830 => true,\n  2833 => true,\n  2834 => true,\n  2857 => true,\n  2865 => true,\n  2868 => true,\n  2874 => true,\n  2875 => true,\n  2885 => true,\n  2886 => true,\n  2889 => true,\n  2890 => true,\n  2894 => true,\n  2895 => true,\n  2896 => true,\n  2897 => true,\n  2898 => true,\n  2899 => true,\n  2900 => true,\n  2904 => true,\n  2905 => true,\n  2906 => true,\n  2907 => true,\n  2910 => true,\n  2916 => true,\n  2917 => true,\n  2936 => true,\n  2937 => true,\n  2938 => true,\n  2939 => true,\n  2940 => true,\n  2941 => true,\n  2942 => true,\n  2943 => true,\n  2944 => true,\n  2945 => true,\n  2948 => true,\n  2955 => true,\n  2956 => true,\n  2957 => true,\n  2961 => true,\n  2966 => true,\n  2967 => true,\n  2968 => true,\n  2971 => true,\n  2973 => true,\n  2976 => true,\n  2977 => true,\n  2978 => true,\n  2981 => true,\n  2982 => true,\n  2983 => true,\n  2987 => true,\n  2988 => true,\n  2989 => true,\n  3002 => true,\n  3003 => true,\n  3004 => true,\n  3005 => true,\n  3011 => true,\n  3012 => true,\n  3013 => true,\n  3017 => true,\n  3022 => true,\n  3023 => true,\n  3025 => true,\n  3026 => true,\n  3027 => true,\n  3028 => true,\n  3029 => true,\n  3030 => true,\n  3032 => true,\n  3033 => true,\n  3034 => true,\n  3035 => true,\n  3036 => true,\n  3037 => true,\n  3038 => true,\n  3039 => true,\n  3040 => true,\n  3041 => true,\n  3042 => true,\n  3043 => true,\n  3044 => true,\n  3045 => true,\n  3067 => true,\n  3068 => true,\n  3069 => true,\n  3070 => true,\n  3071 => true,\n  3085 => true,\n  3089 => true,\n  3113 => true,\n  3130 => true,\n  3131 => true,\n  3132 => true,\n  3141 => true,\n  3145 => true,\n  3150 => true,\n  3151 => true,\n  3152 => true,\n  3153 => true,\n  3154 => true,\n  3155 => true,\n  3156 => true,\n  3159 => true,\n  3163 => true,\n  3164 => true,\n  3165 => true,\n  3166 => true,\n  3167 => true,\n  3172 => true,\n  3173 => true,\n  3184 => true,\n  3185 => true,\n  3186 => true,\n  3187 => true,\n  3188 => true,\n  3189 => true,\n  3190 => true,\n  3213 => true,\n  3217 => true,\n  3241 => true,\n  3252 => true,\n  3258 => true,\n  3259 => true,\n  3269 => true,\n  3273 => true,\n  3278 => true,\n  3279 => true,\n  3280 => true,\n  3281 => true,\n  3282 => true,\n  3283 => true,\n  3284 => true,\n  3287 => true,\n  3288 => true,\n  3289 => true,\n  3290 => true,\n  3291 => true,\n  3292 => true,\n  3293 => true,\n  3295 => true,\n  3300 => true,\n  3301 => true,\n  3312 => true,\n  3315 => true,\n  3316 => true,\n  3317 => true,\n  3318 => true,\n  3319 => true,\n  3320 => true,\n  3321 => true,\n  3322 => true,\n  3323 => true,\n  3324 => true,\n  3325 => true,\n  3326 => true,\n  3327 => true,\n  3341 => true,\n  3345 => true,\n  3397 => true,\n  3401 => true,\n  3408 => true,\n  3409 => true,\n  3410 => true,\n  3411 => true,\n  3428 => true,\n  3429 => true,\n  3456 => true,\n  3460 => true,\n  3479 => true,\n  3480 => true,\n  3481 => true,\n  3506 => true,\n  3516 => true,\n  3518 => true,\n  3519 => true,\n  3527 => true,\n  3528 => true,\n  3529 => true,\n  3531 => true,\n  3532 => true,\n  3533 => true,\n  3534 => true,\n  3541 => true,\n  3543 => true,\n  3552 => true,\n  3553 => true,\n  3554 => true,\n  3555 => true,\n  3556 => true,\n  3557 => true,\n  3568 => true,\n  3569 => true,\n  3573 => true,\n  3574 => true,\n  3575 => true,\n  3576 => true,\n  3577 => true,\n  3578 => true,\n  3579 => true,\n  3580 => true,\n  3581 => true,\n  3582 => true,\n  3583 => true,\n  3584 => true,\n  3643 => true,\n  3644 => true,\n  3645 => true,\n  3646 => true,\n  3715 => true,\n  3717 => true,\n  3723 => true,\n  3748 => true,\n  3750 => true,\n  3774 => true,\n  3775 => true,\n  3781 => true,\n  3783 => true,\n  3790 => true,\n  3791 => true,\n  3802 => true,\n  3803 => true,\n  3912 => true,\n  3949 => true,\n  3950 => true,\n  3951 => true,\n  3952 => true,\n  3992 => true,\n  4029 => true,\n  4045 => true,\n  4294 => true,\n  4296 => true,\n  4297 => true,\n  4298 => true,\n  4299 => true,\n  4300 => true,\n  4302 => true,\n  4303 => true,\n  4447 => true,\n  4448 => true,\n  4681 => true,\n  4686 => true,\n  4687 => true,\n  4695 => true,\n  4697 => true,\n  4702 => true,\n  4703 => true,\n  4745 => true,\n  4750 => true,\n  4751 => true,\n  4785 => true,\n  4790 => true,\n  4791 => true,\n  4799 => true,\n  4801 => true,\n  4806 => true,\n  4807 => true,\n  4823 => true,\n  4881 => true,\n  4886 => true,\n  4887 => true,\n  4955 => true,\n  4956 => true,\n  4989 => true,\n  4990 => true,\n  4991 => true,\n  5018 => true,\n  5019 => true,\n  5020 => true,\n  5021 => true,\n  5022 => true,\n  5023 => true,\n  5110 => true,\n  5111 => true,\n  5118 => true,\n  5119 => true,\n  5760 => true,\n  5789 => true,\n  5790 => true,\n  5791 => true,\n  5881 => true,\n  5882 => true,\n  5883 => true,\n  5884 => true,\n  5885 => true,\n  5886 => true,\n  5887 => true,\n  5901 => true,\n  5909 => true,\n  5910 => true,\n  5911 => true,\n  5912 => true,\n  5913 => true,\n  5914 => true,\n  5915 => true,\n  5916 => true,\n  5917 => true,\n  5918 => true,\n  5919 => true,\n  5943 => true,\n  5944 => true,\n  5945 => true,\n  5946 => true,\n  5947 => true,\n  5948 => true,\n  5949 => true,\n  5950 => true,\n  5951 => true,\n  5972 => true,\n  5973 => true,\n  5974 => true,\n  5975 => true,\n  5976 => true,\n  5977 => true,\n  5978 => true,\n  5979 => true,\n  5980 => true,\n  5981 => true,\n  5982 => true,\n  5983 => true,\n  5997 => true,\n  6001 => true,\n  6004 => true,\n  6005 => true,\n  6006 => true,\n  6007 => true,\n  6008 => true,\n  6009 => true,\n  6010 => true,\n  6011 => true,\n  6012 => true,\n  6013 => true,\n  6014 => true,\n  6015 => true,\n  6068 => true,\n  6069 => true,\n  6110 => true,\n  6111 => true,\n  6122 => true,\n  6123 => true,\n  6124 => true,\n  6125 => true,\n  6126 => true,\n  6127 => true,\n  6138 => true,\n  6139 => true,\n  6140 => true,\n  6141 => true,\n  6142 => true,\n  6143 => true,\n  6150 => true,\n  6158 => true,\n  6159 => true,\n  6170 => true,\n  6171 => true,\n  6172 => true,\n  6173 => true,\n  6174 => true,\n  6175 => true,\n  6265 => true,\n  6266 => true,\n  6267 => true,\n  6268 => true,\n  6269 => true,\n  6270 => true,\n  6271 => true,\n  6315 => true,\n  6316 => true,\n  6317 => true,\n  6318 => true,\n  6319 => true,\n  6390 => true,\n  6391 => true,\n  6392 => true,\n  6393 => true,\n  6394 => true,\n  6395 => true,\n  6396 => true,\n  6397 => true,\n  6398 => true,\n  6399 => true,\n  6431 => true,\n  6444 => true,\n  6445 => true,\n  6446 => true,\n  6447 => true,\n  6460 => true,\n  6461 => true,\n  6462 => true,\n  6463 => true,\n  6465 => true,\n  6466 => true,\n  6467 => true,\n  6510 => true,\n  6511 => true,\n  6517 => true,\n  6518 => true,\n  6519 => true,\n  6520 => true,\n  6521 => true,\n  6522 => true,\n  6523 => true,\n  6524 => true,\n  6525 => true,\n  6526 => true,\n  6527 => true,\n  6572 => true,\n  6573 => true,\n  6574 => true,\n  6575 => true,\n  6602 => true,\n  6603 => true,\n  6604 => true,\n  6605 => true,\n  6606 => true,\n  6607 => true,\n  6619 => true,\n  6620 => true,\n  6621 => true,\n  6684 => true,\n  6685 => true,\n  6751 => true,\n  6781 => true,\n  6782 => true,\n  6794 => true,\n  6795 => true,\n  6796 => true,\n  6797 => true,\n  6798 => true,\n  6799 => true,\n  6810 => true,\n  6811 => true,\n  6812 => true,\n  6813 => true,\n  6814 => true,\n  6815 => true,\n  6830 => true,\n  6831 => true,\n  6988 => true,\n  6989 => true,\n  6990 => true,\n  6991 => true,\n  7037 => true,\n  7038 => true,\n  7039 => true,\n  7156 => true,\n  7157 => true,\n  7158 => true,\n  7159 => true,\n  7160 => true,\n  7161 => true,\n  7162 => true,\n  7163 => true,\n  7224 => true,\n  7225 => true,\n  7226 => true,\n  7242 => true,\n  7243 => true,\n  7244 => true,\n  7305 => true,\n  7306 => true,\n  7307 => true,\n  7308 => true,\n  7309 => true,\n  7310 => true,\n  7311 => true,\n  7355 => true,\n  7356 => true,\n  7368 => true,\n  7369 => true,\n  7370 => true,\n  7371 => true,\n  7372 => true,\n  7373 => true,\n  7374 => true,\n  7375 => true,\n  7419 => true,\n  7420 => true,\n  7421 => true,\n  7422 => true,\n  7423 => true,\n  7674 => true,\n  7958 => true,\n  7959 => true,\n  7966 => true,\n  7967 => true,\n  8006 => true,\n  8007 => true,\n  8014 => true,\n  8015 => true,\n  8024 => true,\n  8026 => true,\n  8028 => true,\n  8030 => true,\n  8062 => true,\n  8063 => true,\n  8117 => true,\n  8133 => true,\n  8148 => true,\n  8149 => true,\n  8156 => true,\n  8176 => true,\n  8177 => true,\n  8181 => true,\n  8191 => true,\n  8206 => true,\n  8207 => true,\n  8228 => true,\n  8229 => true,\n  8230 => true,\n  8232 => true,\n  8233 => true,\n  8234 => true,\n  8235 => true,\n  8236 => true,\n  8237 => true,\n  8238 => true,\n  8289 => true,\n  8290 => true,\n  8291 => true,\n  8293 => true,\n  8294 => true,\n  8295 => true,\n  8296 => true,\n  8297 => true,\n  8298 => true,\n  8299 => true,\n  8300 => true,\n  8301 => true,\n  8302 => true,\n  8303 => true,\n  8306 => true,\n  8307 => true,\n  8335 => true,\n  8349 => true,\n  8350 => true,\n  8351 => true,\n  8384 => true,\n  8385 => true,\n  8386 => true,\n  8387 => true,\n  8388 => true,\n  8389 => true,\n  8390 => true,\n  8391 => true,\n  8392 => true,\n  8393 => true,\n  8394 => true,\n  8395 => true,\n  8396 => true,\n  8397 => true,\n  8398 => true,\n  8399 => true,\n  8433 => true,\n  8434 => true,\n  8435 => true,\n  8436 => true,\n  8437 => true,\n  8438 => true,\n  8439 => true,\n  8440 => true,\n  8441 => true,\n  8442 => true,\n  8443 => true,\n  8444 => true,\n  8445 => true,\n  8446 => true,\n  8447 => true,\n  8498 => true,\n  8579 => true,\n  8588 => true,\n  8589 => true,\n  8590 => true,\n  8591 => true,\n  9255 => true,\n  9256 => true,\n  9257 => true,\n  9258 => true,\n  9259 => true,\n  9260 => true,\n  9261 => true,\n  9262 => true,\n  9263 => true,\n  9264 => true,\n  9265 => true,\n  9266 => true,\n  9267 => true,\n  9268 => true,\n  9269 => true,\n  9270 => true,\n  9271 => true,\n  9272 => true,\n  9273 => true,\n  9274 => true,\n  9275 => true,\n  9276 => true,\n  9277 => true,\n  9278 => true,\n  9279 => true,\n  9291 => true,\n  9292 => true,\n  9293 => true,\n  9294 => true,\n  9295 => true,\n  9296 => true,\n  9297 => true,\n  9298 => true,\n  9299 => true,\n  9300 => true,\n  9301 => true,\n  9302 => true,\n  9303 => true,\n  9304 => true,\n  9305 => true,\n  9306 => true,\n  9307 => true,\n  9308 => true,\n  9309 => true,\n  9310 => true,\n  9311 => true,\n  9352 => true,\n  9353 => true,\n  9354 => true,\n  9355 => true,\n  9356 => true,\n  9357 => true,\n  9358 => true,\n  9359 => true,\n  9360 => true,\n  9361 => true,\n  9362 => true,\n  9363 => true,\n  9364 => true,\n  9365 => true,\n  9366 => true,\n  9367 => true,\n  9368 => true,\n  9369 => true,\n  9370 => true,\n  9371 => true,\n  11124 => true,\n  11125 => true,\n  11158 => true,\n  11311 => true,\n  11359 => true,\n  11508 => true,\n  11509 => true,\n  11510 => true,\n  11511 => true,\n  11512 => true,\n  11558 => true,\n  11560 => true,\n  11561 => true,\n  11562 => true,\n  11563 => true,\n  11564 => true,\n  11566 => true,\n  11567 => true,\n  11624 => true,\n  11625 => true,\n  11626 => true,\n  11627 => true,\n  11628 => true,\n  11629 => true,\n  11630 => true,\n  11633 => true,\n  11634 => true,\n  11635 => true,\n  11636 => true,\n  11637 => true,\n  11638 => true,\n  11639 => true,\n  11640 => true,\n  11641 => true,\n  11642 => true,\n  11643 => true,\n  11644 => true,\n  11645 => true,\n  11646 => true,\n  11671 => true,\n  11672 => true,\n  11673 => true,\n  11674 => true,\n  11675 => true,\n  11676 => true,\n  11677 => true,\n  11678 => true,\n  11679 => true,\n  11687 => true,\n  11695 => true,\n  11703 => true,\n  11711 => true,\n  11719 => true,\n  11727 => true,\n  11735 => true,\n  11743 => true,\n  11930 => true,\n  12020 => true,\n  12021 => true,\n  12022 => true,\n  12023 => true,\n  12024 => true,\n  12025 => true,\n  12026 => true,\n  12027 => true,\n  12028 => true,\n  12029 => true,\n  12030 => true,\n  12031 => true,\n  12246 => true,\n  12247 => true,\n  12248 => true,\n  12249 => true,\n  12250 => true,\n  12251 => true,\n  12252 => true,\n  12253 => true,\n  12254 => true,\n  12255 => true,\n  12256 => true,\n  12257 => true,\n  12258 => true,\n  12259 => true,\n  12260 => true,\n  12261 => true,\n  12262 => true,\n  12263 => true,\n  12264 => true,\n  12265 => true,\n  12266 => true,\n  12267 => true,\n  12268 => true,\n  12269 => true,\n  12270 => true,\n  12271 => true,\n  12272 => true,\n  12273 => true,\n  12274 => true,\n  12275 => true,\n  12276 => true,\n  12277 => true,\n  12278 => true,\n  12279 => true,\n  12280 => true,\n  12281 => true,\n  12282 => true,\n  12283 => true,\n  12284 => true,\n  12285 => true,\n  12286 => true,\n  12287 => true,\n  12352 => true,\n  12439 => true,\n  12440 => true,\n  12544 => true,\n  12545 => true,\n  12546 => true,\n  12547 => true,\n  12548 => true,\n  12592 => true,\n  12644 => true,\n  12687 => true,\n  12772 => true,\n  12773 => true,\n  12774 => true,\n  12775 => true,\n  12776 => true,\n  12777 => true,\n  12778 => true,\n  12779 => true,\n  12780 => true,\n  12781 => true,\n  12782 => true,\n  12783 => true,\n  12831 => true,\n  13250 => true,\n  13255 => true,\n  13272 => true,\n  40957 => true,\n  40958 => true,\n  40959 => true,\n  42125 => true,\n  42126 => true,\n  42127 => true,\n  42183 => true,\n  42184 => true,\n  42185 => true,\n  42186 => true,\n  42187 => true,\n  42188 => true,\n  42189 => true,\n  42190 => true,\n  42191 => true,\n  42540 => true,\n  42541 => true,\n  42542 => true,\n  42543 => true,\n  42544 => true,\n  42545 => true,\n  42546 => true,\n  42547 => true,\n  42548 => true,\n  42549 => true,\n  42550 => true,\n  42551 => true,\n  42552 => true,\n  42553 => true,\n  42554 => true,\n  42555 => true,\n  42556 => true,\n  42557 => true,\n  42558 => true,\n  42559 => true,\n  42744 => true,\n  42745 => true,\n  42746 => true,\n  42747 => true,\n  42748 => true,\n  42749 => true,\n  42750 => true,\n  42751 => true,\n  42944 => true,\n  42945 => true,\n  43053 => true,\n  43054 => true,\n  43055 => true,\n  43066 => true,\n  43067 => true,\n  43068 => true,\n  43069 => true,\n  43070 => true,\n  43071 => true,\n  43128 => true,\n  43129 => true,\n  43130 => true,\n  43131 => true,\n  43132 => true,\n  43133 => true,\n  43134 => true,\n  43135 => true,\n  43206 => true,\n  43207 => true,\n  43208 => true,\n  43209 => true,\n  43210 => true,\n  43211 => true,\n  43212 => true,\n  43213 => true,\n  43226 => true,\n  43227 => true,\n  43228 => true,\n  43229 => true,\n  43230 => true,\n  43231 => true,\n  43348 => true,\n  43349 => true,\n  43350 => true,\n  43351 => true,\n  43352 => true,\n  43353 => true,\n  43354 => true,\n  43355 => true,\n  43356 => true,\n  43357 => true,\n  43358 => true,\n  43389 => true,\n  43390 => true,\n  43391 => true,\n  43470 => true,\n  43482 => true,\n  43483 => true,\n  43484 => true,\n  43485 => true,\n  43519 => true,\n  43575 => true,\n  43576 => true,\n  43577 => true,\n  43578 => true,\n  43579 => true,\n  43580 => true,\n  43581 => true,\n  43582 => true,\n  43583 => true,\n  43598 => true,\n  43599 => true,\n  43610 => true,\n  43611 => true,\n  43715 => true,\n  43716 => true,\n  43717 => true,\n  43718 => true,\n  43719 => true,\n  43720 => true,\n  43721 => true,\n  43722 => true,\n  43723 => true,\n  43724 => true,\n  43725 => true,\n  43726 => true,\n  43727 => true,\n  43728 => true,\n  43729 => true,\n  43730 => true,\n  43731 => true,\n  43732 => true,\n  43733 => true,\n  43734 => true,\n  43735 => true,\n  43736 => true,\n  43737 => true,\n  43738 => true,\n  43767 => true,\n  43768 => true,\n  43769 => true,\n  43770 => true,\n  43771 => true,\n  43772 => true,\n  43773 => true,\n  43774 => true,\n  43775 => true,\n  43776 => true,\n  43783 => true,\n  43784 => true,\n  43791 => true,\n  43792 => true,\n  43799 => true,\n  43800 => true,\n  43801 => true,\n  43802 => true,\n  43803 => true,\n  43804 => true,\n  43805 => true,\n  43806 => true,\n  43807 => true,\n  43815 => true,\n  43823 => true,\n  43884 => true,\n  43885 => true,\n  43886 => true,\n  43887 => true,\n  44014 => true,\n  44015 => true,\n  44026 => true,\n  44027 => true,\n  44028 => true,\n  44029 => true,\n  44030 => true,\n  44031 => true,\n  55204 => true,\n  55205 => true,\n  55206 => true,\n  55207 => true,\n  55208 => true,\n  55209 => true,\n  55210 => true,\n  55211 => true,\n  55212 => true,\n  55213 => true,\n  55214 => true,\n  55215 => true,\n  55239 => true,\n  55240 => true,\n  55241 => true,\n  55242 => true,\n  55292 => true,\n  55293 => true,\n  55294 => true,\n  55295 => true,\n  64110 => true,\n  64111 => true,\n  64263 => true,\n  64264 => true,\n  64265 => true,\n  64266 => true,\n  64267 => true,\n  64268 => true,\n  64269 => true,\n  64270 => true,\n  64271 => true,\n  64272 => true,\n  64273 => true,\n  64274 => true,\n  64280 => true,\n  64281 => true,\n  64282 => true,\n  64283 => true,\n  64284 => true,\n  64311 => true,\n  64317 => true,\n  64319 => true,\n  64322 => true,\n  64325 => true,\n  64450 => true,\n  64451 => true,\n  64452 => true,\n  64453 => true,\n  64454 => true,\n  64455 => true,\n  64456 => true,\n  64457 => true,\n  64458 => true,\n  64459 => true,\n  64460 => true,\n  64461 => true,\n  64462 => true,\n  64463 => true,\n  64464 => true,\n  64465 => true,\n  64466 => true,\n  64832 => true,\n  64833 => true,\n  64834 => true,\n  64835 => true,\n  64836 => true,\n  64837 => true,\n  64838 => true,\n  64839 => true,\n  64840 => true,\n  64841 => true,\n  64842 => true,\n  64843 => true,\n  64844 => true,\n  64845 => true,\n  64846 => true,\n  64847 => true,\n  64912 => true,\n  64913 => true,\n  64968 => true,\n  64969 => true,\n  64970 => true,\n  64971 => true,\n  64972 => true,\n  64973 => true,\n  64974 => true,\n  64975 => true,\n  65022 => true,\n  65023 => true,\n  65042 => true,\n  65049 => true,\n  65050 => true,\n  65051 => true,\n  65052 => true,\n  65053 => true,\n  65054 => true,\n  65055 => true,\n  65072 => true,\n  65106 => true,\n  65107 => true,\n  65127 => true,\n  65132 => true,\n  65133 => true,\n  65134 => true,\n  65135 => true,\n  65141 => true,\n  65277 => true,\n  65278 => true,\n  65280 => true,\n  65440 => true,\n  65471 => true,\n  65472 => true,\n  65473 => true,\n  65480 => true,\n  65481 => true,\n  65488 => true,\n  65489 => true,\n  65496 => true,\n  65497 => true,\n  65501 => true,\n  65502 => true,\n  65503 => true,\n  65511 => true,\n  65519 => true,\n  65520 => true,\n  65521 => true,\n  65522 => true,\n  65523 => true,\n  65524 => true,\n  65525 => true,\n  65526 => true,\n  65527 => true,\n  65528 => true,\n  65529 => true,\n  65530 => true,\n  65531 => true,\n  65532 => true,\n  65533 => true,\n  65534 => true,\n  65535 => true,\n  65548 => true,\n  65575 => true,\n  65595 => true,\n  65598 => true,\n  65614 => true,\n  65615 => true,\n  65787 => true,\n  65788 => true,\n  65789 => true,\n  65790 => true,\n  65791 => true,\n  65795 => true,\n  65796 => true,\n  65797 => true,\n  65798 => true,\n  65844 => true,\n  65845 => true,\n  65846 => true,\n  65935 => true,\n  65949 => true,\n  65950 => true,\n  65951 => true,\n  66205 => true,\n  66206 => true,\n  66207 => true,\n  66257 => true,\n  66258 => true,\n  66259 => true,\n  66260 => true,\n  66261 => true,\n  66262 => true,\n  66263 => true,\n  66264 => true,\n  66265 => true,\n  66266 => true,\n  66267 => true,\n  66268 => true,\n  66269 => true,\n  66270 => true,\n  66271 => true,\n  66300 => true,\n  66301 => true,\n  66302 => true,\n  66303 => true,\n  66340 => true,\n  66341 => true,\n  66342 => true,\n  66343 => true,\n  66344 => true,\n  66345 => true,\n  66346 => true,\n  66347 => true,\n  66348 => true,\n  66379 => true,\n  66380 => true,\n  66381 => true,\n  66382 => true,\n  66383 => true,\n  66427 => true,\n  66428 => true,\n  66429 => true,\n  66430 => true,\n  66431 => true,\n  66462 => true,\n  66500 => true,\n  66501 => true,\n  66502 => true,\n  66503 => true,\n  66718 => true,\n  66719 => true,\n  66730 => true,\n  66731 => true,\n  66732 => true,\n  66733 => true,\n  66734 => true,\n  66735 => true,\n  66772 => true,\n  66773 => true,\n  66774 => true,\n  66775 => true,\n  66812 => true,\n  66813 => true,\n  66814 => true,\n  66815 => true,\n  66856 => true,\n  66857 => true,\n  66858 => true,\n  66859 => true,\n  66860 => true,\n  66861 => true,\n  66862 => true,\n  66863 => true,\n  66916 => true,\n  66917 => true,\n  66918 => true,\n  66919 => true,\n  66920 => true,\n  66921 => true,\n  66922 => true,\n  66923 => true,\n  66924 => true,\n  66925 => true,\n  66926 => true,\n  67383 => true,\n  67384 => true,\n  67385 => true,\n  67386 => true,\n  67387 => true,\n  67388 => true,\n  67389 => true,\n  67390 => true,\n  67391 => true,\n  67414 => true,\n  67415 => true,\n  67416 => true,\n  67417 => true,\n  67418 => true,\n  67419 => true,\n  67420 => true,\n  67421 => true,\n  67422 => true,\n  67423 => true,\n  67590 => true,\n  67591 => true,\n  67593 => true,\n  67638 => true,\n  67641 => true,\n  67642 => true,\n  67643 => true,\n  67645 => true,\n  67646 => true,\n  67670 => true,\n  67743 => true,\n  67744 => true,\n  67745 => true,\n  67746 => true,\n  67747 => true,\n  67748 => true,\n  67749 => true,\n  67750 => true,\n  67827 => true,\n  67830 => true,\n  67831 => true,\n  67832 => true,\n  67833 => true,\n  67834 => true,\n  67868 => true,\n  67869 => true,\n  67870 => true,\n  67898 => true,\n  67899 => true,\n  67900 => true,\n  67901 => true,\n  67902 => true,\n  68024 => true,\n  68025 => true,\n  68026 => true,\n  68027 => true,\n  68048 => true,\n  68049 => true,\n  68100 => true,\n  68103 => true,\n  68104 => true,\n  68105 => true,\n  68106 => true,\n  68107 => true,\n  68116 => true,\n  68120 => true,\n  68150 => true,\n  68151 => true,\n  68155 => true,\n  68156 => true,\n  68157 => true,\n  68158 => true,\n  68169 => true,\n  68170 => true,\n  68171 => true,\n  68172 => true,\n  68173 => true,\n  68174 => true,\n  68175 => true,\n  68185 => true,\n  68186 => true,\n  68187 => true,\n  68188 => true,\n  68189 => true,\n  68190 => true,\n  68191 => true,\n  68327 => true,\n  68328 => true,\n  68329 => true,\n  68330 => true,\n  68343 => true,\n  68344 => true,\n  68345 => true,\n  68346 => true,\n  68347 => true,\n  68348 => true,\n  68349 => true,\n  68350 => true,\n  68351 => true,\n  68406 => true,\n  68407 => true,\n  68408 => true,\n  68438 => true,\n  68439 => true,\n  68467 => true,\n  68468 => true,\n  68469 => true,\n  68470 => true,\n  68471 => true,\n  68498 => true,\n  68499 => true,\n  68500 => true,\n  68501 => true,\n  68502 => true,\n  68503 => true,\n  68504 => true,\n  68509 => true,\n  68510 => true,\n  68511 => true,\n  68512 => true,\n  68513 => true,\n  68514 => true,\n  68515 => true,\n  68516 => true,\n  68517 => true,\n  68518 => true,\n  68519 => true,\n  68520 => true,\n  68787 => true,\n  68788 => true,\n  68789 => true,\n  68790 => true,\n  68791 => true,\n  68792 => true,\n  68793 => true,\n  68794 => true,\n  68795 => true,\n  68796 => true,\n  68797 => true,\n  68798 => true,\n  68799 => true,\n  68851 => true,\n  68852 => true,\n  68853 => true,\n  68854 => true,\n  68855 => true,\n  68856 => true,\n  68857 => true,\n  68904 => true,\n  68905 => true,\n  68906 => true,\n  68907 => true,\n  68908 => true,\n  68909 => true,\n  68910 => true,\n  68911 => true,\n  69247 => true,\n  69290 => true,\n  69294 => true,\n  69295 => true,\n  69416 => true,\n  69417 => true,\n  69418 => true,\n  69419 => true,\n  69420 => true,\n  69421 => true,\n  69422 => true,\n  69423 => true,\n  69580 => true,\n  69581 => true,\n  69582 => true,\n  69583 => true,\n  69584 => true,\n  69585 => true,\n  69586 => true,\n  69587 => true,\n  69588 => true,\n  69589 => true,\n  69590 => true,\n  69591 => true,\n  69592 => true,\n  69593 => true,\n  69594 => true,\n  69595 => true,\n  69596 => true,\n  69597 => true,\n  69598 => true,\n  69599 => true,\n  69623 => true,\n  69624 => true,\n  69625 => true,\n  69626 => true,\n  69627 => true,\n  69628 => true,\n  69629 => true,\n  69630 => true,\n  69631 => true,\n  69710 => true,\n  69711 => true,\n  69712 => true,\n  69713 => true,\n  69744 => true,\n  69745 => true,\n  69746 => true,\n  69747 => true,\n  69748 => true,\n  69749 => true,\n  69750 => true,\n  69751 => true,\n  69752 => true,\n  69753 => true,\n  69754 => true,\n  69755 => true,\n  69756 => true,\n  69757 => true,\n  69758 => true,\n  69821 => true,\n  69826 => true,\n  69827 => true,\n  69828 => true,\n  69829 => true,\n  69830 => true,\n  69831 => true,\n  69832 => true,\n  69833 => true,\n  69834 => true,\n  69835 => true,\n  69836 => true,\n  69837 => true,\n  69838 => true,\n  69839 => true,\n  69865 => true,\n  69866 => true,\n  69867 => true,\n  69868 => true,\n  69869 => true,\n  69870 => true,\n  69871 => true,\n  69882 => true,\n  69883 => true,\n  69884 => true,\n  69885 => true,\n  69886 => true,\n  69887 => true,\n  69941 => true,\n  69960 => true,\n  69961 => true,\n  69962 => true,\n  69963 => true,\n  69964 => true,\n  69965 => true,\n  69966 => true,\n  69967 => true,\n  70007 => true,\n  70008 => true,\n  70009 => true,\n  70010 => true,\n  70011 => true,\n  70012 => true,\n  70013 => true,\n  70014 => true,\n  70015 => true,\n  70112 => true,\n  70133 => true,\n  70134 => true,\n  70135 => true,\n  70136 => true,\n  70137 => true,\n  70138 => true,\n  70139 => true,\n  70140 => true,\n  70141 => true,\n  70142 => true,\n  70143 => true,\n  70162 => true,\n  70279 => true,\n  70281 => true,\n  70286 => true,\n  70302 => true,\n  70314 => true,\n  70315 => true,\n  70316 => true,\n  70317 => true,\n  70318 => true,\n  70319 => true,\n  70379 => true,\n  70380 => true,\n  70381 => true,\n  70382 => true,\n  70383 => true,\n  70394 => true,\n  70395 => true,\n  70396 => true,\n  70397 => true,\n  70398 => true,\n  70399 => true,\n  70404 => true,\n  70413 => true,\n  70414 => true,\n  70417 => true,\n  70418 => true,\n  70441 => true,\n  70449 => true,\n  70452 => true,\n  70458 => true,\n  70469 => true,\n  70470 => true,\n  70473 => true,\n  70474 => true,\n  70478 => true,\n  70479 => true,\n  70481 => true,\n  70482 => true,\n  70483 => true,\n  70484 => true,\n  70485 => true,\n  70486 => true,\n  70488 => true,\n  70489 => true,\n  70490 => true,\n  70491 => true,\n  70492 => true,\n  70500 => true,\n  70501 => true,\n  70509 => true,\n  70510 => true,\n  70511 => true,\n  70748 => true,\n  70754 => true,\n  70755 => true,\n  70756 => true,\n  70757 => true,\n  70758 => true,\n  70759 => true,\n  70760 => true,\n  70761 => true,\n  70762 => true,\n  70763 => true,\n  70764 => true,\n  70765 => true,\n  70766 => true,\n  70767 => true,\n  70768 => true,\n  70769 => true,\n  70770 => true,\n  70771 => true,\n  70772 => true,\n  70773 => true,\n  70774 => true,\n  70775 => true,\n  70776 => true,\n  70777 => true,\n  70778 => true,\n  70779 => true,\n  70780 => true,\n  70781 => true,\n  70782 => true,\n  70783 => true,\n  70856 => true,\n  70857 => true,\n  70858 => true,\n  70859 => true,\n  70860 => true,\n  70861 => true,\n  70862 => true,\n  70863 => true,\n  71094 => true,\n  71095 => true,\n  71237 => true,\n  71238 => true,\n  71239 => true,\n  71240 => true,\n  71241 => true,\n  71242 => true,\n  71243 => true,\n  71244 => true,\n  71245 => true,\n  71246 => true,\n  71247 => true,\n  71258 => true,\n  71259 => true,\n  71260 => true,\n  71261 => true,\n  71262 => true,\n  71263 => true,\n  71277 => true,\n  71278 => true,\n  71279 => true,\n  71280 => true,\n  71281 => true,\n  71282 => true,\n  71283 => true,\n  71284 => true,\n  71285 => true,\n  71286 => true,\n  71287 => true,\n  71288 => true,\n  71289 => true,\n  71290 => true,\n  71291 => true,\n  71292 => true,\n  71293 => true,\n  71294 => true,\n  71295 => true,\n  71353 => true,\n  71354 => true,\n  71355 => true,\n  71356 => true,\n  71357 => true,\n  71358 => true,\n  71359 => true,\n  71451 => true,\n  71452 => true,\n  71468 => true,\n  71469 => true,\n  71470 => true,\n  71471 => true,\n  71923 => true,\n  71924 => true,\n  71925 => true,\n  71926 => true,\n  71927 => true,\n  71928 => true,\n  71929 => true,\n  71930 => true,\n  71931 => true,\n  71932 => true,\n  71933 => true,\n  71934 => true,\n  71943 => true,\n  71944 => true,\n  71946 => true,\n  71947 => true,\n  71956 => true,\n  71959 => true,\n  71990 => true,\n  71993 => true,\n  71994 => true,\n  72007 => true,\n  72008 => true,\n  72009 => true,\n  72010 => true,\n  72011 => true,\n  72012 => true,\n  72013 => true,\n  72014 => true,\n  72015 => true,\n  72104 => true,\n  72105 => true,\n  72152 => true,\n  72153 => true,\n  72165 => true,\n  72166 => true,\n  72167 => true,\n  72168 => true,\n  72169 => true,\n  72170 => true,\n  72171 => true,\n  72172 => true,\n  72173 => true,\n  72174 => true,\n  72175 => true,\n  72176 => true,\n  72177 => true,\n  72178 => true,\n  72179 => true,\n  72180 => true,\n  72181 => true,\n  72182 => true,\n  72183 => true,\n  72184 => true,\n  72185 => true,\n  72186 => true,\n  72187 => true,\n  72188 => true,\n  72189 => true,\n  72190 => true,\n  72191 => true,\n  72264 => true,\n  72265 => true,\n  72266 => true,\n  72267 => true,\n  72268 => true,\n  72269 => true,\n  72270 => true,\n  72271 => true,\n  72355 => true,\n  72356 => true,\n  72357 => true,\n  72358 => true,\n  72359 => true,\n  72360 => true,\n  72361 => true,\n  72362 => true,\n  72363 => true,\n  72364 => true,\n  72365 => true,\n  72366 => true,\n  72367 => true,\n  72368 => true,\n  72369 => true,\n  72370 => true,\n  72371 => true,\n  72372 => true,\n  72373 => true,\n  72374 => true,\n  72375 => true,\n  72376 => true,\n  72377 => true,\n  72378 => true,\n  72379 => true,\n  72380 => true,\n  72381 => true,\n  72382 => true,\n  72383 => true,\n  72713 => true,\n  72759 => true,\n  72774 => true,\n  72775 => true,\n  72776 => true,\n  72777 => true,\n  72778 => true,\n  72779 => true,\n  72780 => true,\n  72781 => true,\n  72782 => true,\n  72783 => true,\n  72813 => true,\n  72814 => true,\n  72815 => true,\n  72848 => true,\n  72849 => true,\n  72872 => true,\n  72967 => true,\n  72970 => true,\n  73015 => true,\n  73016 => true,\n  73017 => true,\n  73019 => true,\n  73022 => true,\n  73032 => true,\n  73033 => true,\n  73034 => true,\n  73035 => true,\n  73036 => true,\n  73037 => true,\n  73038 => true,\n  73039 => true,\n  73050 => true,\n  73051 => true,\n  73052 => true,\n  73053 => true,\n  73054 => true,\n  73055 => true,\n  73062 => true,\n  73065 => true,\n  73103 => true,\n  73106 => true,\n  73113 => true,\n  73114 => true,\n  73115 => true,\n  73116 => true,\n  73117 => true,\n  73118 => true,\n  73119 => true,\n  73649 => true,\n  73650 => true,\n  73651 => true,\n  73652 => true,\n  73653 => true,\n  73654 => true,\n  73655 => true,\n  73656 => true,\n  73657 => true,\n  73658 => true,\n  73659 => true,\n  73660 => true,\n  73661 => true,\n  73662 => true,\n  73663 => true,\n  73714 => true,\n  73715 => true,\n  73716 => true,\n  73717 => true,\n  73718 => true,\n  73719 => true,\n  73720 => true,\n  73721 => true,\n  73722 => true,\n  73723 => true,\n  73724 => true,\n  73725 => true,\n  73726 => true,\n  74863 => true,\n  74869 => true,\n  74870 => true,\n  74871 => true,\n  74872 => true,\n  74873 => true,\n  74874 => true,\n  74875 => true,\n  74876 => true,\n  74877 => true,\n  74878 => true,\n  74879 => true,\n  78895 => true,\n  78896 => true,\n  78897 => true,\n  78898 => true,\n  78899 => true,\n  78900 => true,\n  78901 => true,\n  78902 => true,\n  78903 => true,\n  78904 => true,\n  92729 => true,\n  92730 => true,\n  92731 => true,\n  92732 => true,\n  92733 => true,\n  92734 => true,\n  92735 => true,\n  92767 => true,\n  92778 => true,\n  92779 => true,\n  92780 => true,\n  92781 => true,\n  92910 => true,\n  92911 => true,\n  92918 => true,\n  92919 => true,\n  92920 => true,\n  92921 => true,\n  92922 => true,\n  92923 => true,\n  92924 => true,\n  92925 => true,\n  92926 => true,\n  92927 => true,\n  92998 => true,\n  92999 => true,\n  93000 => true,\n  93001 => true,\n  93002 => true,\n  93003 => true,\n  93004 => true,\n  93005 => true,\n  93006 => true,\n  93007 => true,\n  93018 => true,\n  93026 => true,\n  93048 => true,\n  93049 => true,\n  93050 => true,\n  93051 => true,\n  93052 => true,\n  94027 => true,\n  94028 => true,\n  94029 => true,\n  94030 => true,\n  94088 => true,\n  94089 => true,\n  94090 => true,\n  94091 => true,\n  94092 => true,\n  94093 => true,\n  94094 => true,\n  94181 => true,\n  94182 => true,\n  94183 => true,\n  94184 => true,\n  94185 => true,\n  94186 => true,\n  94187 => true,\n  94188 => true,\n  94189 => true,\n  94190 => true,\n  94191 => true,\n  94194 => true,\n  94195 => true,\n  94196 => true,\n  94197 => true,\n  94198 => true,\n  94199 => true,\n  94200 => true,\n  94201 => true,\n  94202 => true,\n  94203 => true,\n  94204 => true,\n  94205 => true,\n  94206 => true,\n  94207 => true,\n  100344 => true,\n  100345 => true,\n  100346 => true,\n  100347 => true,\n  100348 => true,\n  100349 => true,\n  100350 => true,\n  100351 => true,\n  110931 => true,\n  110932 => true,\n  110933 => true,\n  110934 => true,\n  110935 => true,\n  110936 => true,\n  110937 => true,\n  110938 => true,\n  110939 => true,\n  110940 => true,\n  110941 => true,\n  110942 => true,\n  110943 => true,\n  110944 => true,\n  110945 => true,\n  110946 => true,\n  110947 => true,\n  110952 => true,\n  110953 => true,\n  110954 => true,\n  110955 => true,\n  110956 => true,\n  110957 => true,\n  110958 => true,\n  110959 => true,\n  113771 => true,\n  113772 => true,\n  113773 => true,\n  113774 => true,\n  113775 => true,\n  113789 => true,\n  113790 => true,\n  113791 => true,\n  113801 => true,\n  113802 => true,\n  113803 => true,\n  113804 => true,\n  113805 => true,\n  113806 => true,\n  113807 => true,\n  113818 => true,\n  113819 => true,\n  119030 => true,\n  119031 => true,\n  119032 => true,\n  119033 => true,\n  119034 => true,\n  119035 => true,\n  119036 => true,\n  119037 => true,\n  119038 => true,\n  119039 => true,\n  119079 => true,\n  119080 => true,\n  119155 => true,\n  119156 => true,\n  119157 => true,\n  119158 => true,\n  119159 => true,\n  119160 => true,\n  119161 => true,\n  119162 => true,\n  119273 => true,\n  119274 => true,\n  119275 => true,\n  119276 => true,\n  119277 => true,\n  119278 => true,\n  119279 => true,\n  119280 => true,\n  119281 => true,\n  119282 => true,\n  119283 => true,\n  119284 => true,\n  119285 => true,\n  119286 => true,\n  119287 => true,\n  119288 => true,\n  119289 => true,\n  119290 => true,\n  119291 => true,\n  119292 => true,\n  119293 => true,\n  119294 => true,\n  119295 => true,\n  119540 => true,\n  119541 => true,\n  119542 => true,\n  119543 => true,\n  119544 => true,\n  119545 => true,\n  119546 => true,\n  119547 => true,\n  119548 => true,\n  119549 => true,\n  119550 => true,\n  119551 => true,\n  119639 => true,\n  119640 => true,\n  119641 => true,\n  119642 => true,\n  119643 => true,\n  119644 => true,\n  119645 => true,\n  119646 => true,\n  119647 => true,\n  119893 => true,\n  119965 => true,\n  119968 => true,\n  119969 => true,\n  119971 => true,\n  119972 => true,\n  119975 => true,\n  119976 => true,\n  119981 => true,\n  119994 => true,\n  119996 => true,\n  120004 => true,\n  120070 => true,\n  120075 => true,\n  120076 => true,\n  120085 => true,\n  120093 => true,\n  120122 => true,\n  120127 => true,\n  120133 => true,\n  120135 => true,\n  120136 => true,\n  120137 => true,\n  120145 => true,\n  120486 => true,\n  120487 => true,\n  120780 => true,\n  120781 => true,\n  121484 => true,\n  121485 => true,\n  121486 => true,\n  121487 => true,\n  121488 => true,\n  121489 => true,\n  121490 => true,\n  121491 => true,\n  121492 => true,\n  121493 => true,\n  121494 => true,\n  121495 => true,\n  121496 => true,\n  121497 => true,\n  121498 => true,\n  121504 => true,\n  122887 => true,\n  122905 => true,\n  122906 => true,\n  122914 => true,\n  122917 => true,\n  123181 => true,\n  123182 => true,\n  123183 => true,\n  123198 => true,\n  123199 => true,\n  123210 => true,\n  123211 => true,\n  123212 => true,\n  123213 => true,\n  123642 => true,\n  123643 => true,\n  123644 => true,\n  123645 => true,\n  123646 => true,\n  125125 => true,\n  125126 => true,\n  125260 => true,\n  125261 => true,\n  125262 => true,\n  125263 => true,\n  125274 => true,\n  125275 => true,\n  125276 => true,\n  125277 => true,\n  126468 => true,\n  126496 => true,\n  126499 => true,\n  126501 => true,\n  126502 => true,\n  126504 => true,\n  126515 => true,\n  126520 => true,\n  126522 => true,\n  126524 => true,\n  126525 => true,\n  126526 => true,\n  126527 => true,\n  126528 => true,\n  126529 => true,\n  126531 => true,\n  126532 => true,\n  126533 => true,\n  126534 => true,\n  126536 => true,\n  126538 => true,\n  126540 => true,\n  126544 => true,\n  126547 => true,\n  126549 => true,\n  126550 => true,\n  126552 => true,\n  126554 => true,\n  126556 => true,\n  126558 => true,\n  126560 => true,\n  126563 => true,\n  126565 => true,\n  126566 => true,\n  126571 => true,\n  126579 => true,\n  126584 => true,\n  126589 => true,\n  126591 => true,\n  126602 => true,\n  126620 => true,\n  126621 => true,\n  126622 => true,\n  126623 => true,\n  126624 => true,\n  126628 => true,\n  126634 => true,\n  127020 => true,\n  127021 => true,\n  127022 => true,\n  127023 => true,\n  127124 => true,\n  127125 => true,\n  127126 => true,\n  127127 => true,\n  127128 => true,\n  127129 => true,\n  127130 => true,\n  127131 => true,\n  127132 => true,\n  127133 => true,\n  127134 => true,\n  127135 => true,\n  127151 => true,\n  127152 => true,\n  127168 => true,\n  127184 => true,\n  127222 => true,\n  127223 => true,\n  127224 => true,\n  127225 => true,\n  127226 => true,\n  127227 => true,\n  127228 => true,\n  127229 => true,\n  127230 => true,\n  127231 => true,\n  127232 => true,\n  127491 => true,\n  127492 => true,\n  127493 => true,\n  127494 => true,\n  127495 => true,\n  127496 => true,\n  127497 => true,\n  127498 => true,\n  127499 => true,\n  127500 => true,\n  127501 => true,\n  127502 => true,\n  127503 => true,\n  127548 => true,\n  127549 => true,\n  127550 => true,\n  127551 => true,\n  127561 => true,\n  127562 => true,\n  127563 => true,\n  127564 => true,\n  127565 => true,\n  127566 => true,\n  127567 => true,\n  127570 => true,\n  127571 => true,\n  127572 => true,\n  127573 => true,\n  127574 => true,\n  127575 => true,\n  127576 => true,\n  127577 => true,\n  127578 => true,\n  127579 => true,\n  127580 => true,\n  127581 => true,\n  127582 => true,\n  127583 => true,\n  128728 => true,\n  128729 => true,\n  128730 => true,\n  128731 => true,\n  128732 => true,\n  128733 => true,\n  128734 => true,\n  128735 => true,\n  128749 => true,\n  128750 => true,\n  128751 => true,\n  128765 => true,\n  128766 => true,\n  128767 => true,\n  128884 => true,\n  128885 => true,\n  128886 => true,\n  128887 => true,\n  128888 => true,\n  128889 => true,\n  128890 => true,\n  128891 => true,\n  128892 => true,\n  128893 => true,\n  128894 => true,\n  128895 => true,\n  128985 => true,\n  128986 => true,\n  128987 => true,\n  128988 => true,\n  128989 => true,\n  128990 => true,\n  128991 => true,\n  129004 => true,\n  129005 => true,\n  129006 => true,\n  129007 => true,\n  129008 => true,\n  129009 => true,\n  129010 => true,\n  129011 => true,\n  129012 => true,\n  129013 => true,\n  129014 => true,\n  129015 => true,\n  129016 => true,\n  129017 => true,\n  129018 => true,\n  129019 => true,\n  129020 => true,\n  129021 => true,\n  129022 => true,\n  129023 => true,\n  129036 => true,\n  129037 => true,\n  129038 => true,\n  129039 => true,\n  129096 => true,\n  129097 => true,\n  129098 => true,\n  129099 => true,\n  129100 => true,\n  129101 => true,\n  129102 => true,\n  129103 => true,\n  129114 => true,\n  129115 => true,\n  129116 => true,\n  129117 => true,\n  129118 => true,\n  129119 => true,\n  129160 => true,\n  129161 => true,\n  129162 => true,\n  129163 => true,\n  129164 => true,\n  129165 => true,\n  129166 => true,\n  129167 => true,\n  129198 => true,\n  129199 => true,\n  129401 => true,\n  129484 => true,\n  129620 => true,\n  129621 => true,\n  129622 => true,\n  129623 => true,\n  129624 => true,\n  129625 => true,\n  129626 => true,\n  129627 => true,\n  129628 => true,\n  129629 => true,\n  129630 => true,\n  129631 => true,\n  129646 => true,\n  129647 => true,\n  129653 => true,\n  129654 => true,\n  129655 => true,\n  129659 => true,\n  129660 => true,\n  129661 => true,\n  129662 => true,\n  129663 => true,\n  129671 => true,\n  129672 => true,\n  129673 => true,\n  129674 => true,\n  129675 => true,\n  129676 => true,\n  129677 => true,\n  129678 => true,\n  129679 => true,\n  129705 => true,\n  129706 => true,\n  129707 => true,\n  129708 => true,\n  129709 => true,\n  129710 => true,\n  129711 => true,\n  129719 => true,\n  129720 => true,\n  129721 => true,\n  129722 => true,\n  129723 => true,\n  129724 => true,\n  129725 => true,\n  129726 => true,\n  129727 => true,\n  129731 => true,\n  129732 => true,\n  129733 => true,\n  129734 => true,\n  129735 => true,\n  129736 => true,\n  129737 => true,\n  129738 => true,\n  129739 => true,\n  129740 => true,\n  129741 => true,\n  129742 => true,\n  129743 => true,\n  129939 => true,\n  131070 => true,\n  131071 => true,\n  177973 => true,\n  177974 => true,\n  177975 => true,\n  177976 => true,\n  177977 => true,\n  177978 => true,\n  177979 => true,\n  177980 => true,\n  177981 => true,\n  177982 => true,\n  177983 => true,\n  178206 => true,\n  178207 => true,\n  183970 => true,\n  183971 => true,\n  183972 => true,\n  183973 => true,\n  183974 => true,\n  183975 => true,\n  183976 => true,\n  183977 => true,\n  183978 => true,\n  183979 => true,\n  183980 => true,\n  183981 => true,\n  183982 => true,\n  183983 => true,\n  194664 => true,\n  194676 => true,\n  194847 => true,\n  194911 => true,\n  195007 => true,\n  196606 => true,\n  196607 => true,\n  262142 => true,\n  262143 => true,\n  327678 => true,\n  327679 => true,\n  393214 => true,\n  393215 => true,\n  458750 => true,\n  458751 => true,\n  524286 => true,\n  524287 => true,\n  589822 => true,\n  589823 => true,\n  655358 => true,\n  655359 => true,\n  720894 => true,\n  720895 => true,\n  786430 => true,\n  786431 => true,\n  851966 => true,\n  851967 => true,\n  917502 => true,\n  917503 => true,\n  917504 => true,\n  917505 => true,\n  917506 => true,\n  917507 => true,\n  917508 => true,\n  917509 => true,\n  917510 => true,\n  917511 => true,\n  917512 => true,\n  917513 => true,\n  917514 => true,\n  917515 => true,\n  917516 => true,\n  917517 => true,\n  917518 => true,\n  917519 => true,\n  917520 => true,\n  917521 => true,\n  917522 => true,\n  917523 => true,\n  917524 => true,\n  917525 => true,\n  917526 => true,\n  917527 => true,\n  917528 => true,\n  917529 => true,\n  917530 => true,\n  917531 => true,\n  917532 => true,\n  917533 => true,\n  917534 => true,\n  917535 => true,\n  983038 => true,\n  983039 => true,\n  1048574 => true,\n  1048575 => true,\n  1114110 => true,\n  1114111 => true,\n);\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-intl-idn/Resources/unidata/disallowed_STD3_mapped.php",
    "content": "<?php\n\nreturn array (\n  160 => ' ',\n  168 => ' ̈',\n  175 => ' ̄',\n  180 => ' ́',\n  184 => ' ̧',\n  728 => ' ̆',\n  729 => ' ̇',\n  730 => ' ̊',\n  731 => ' ̨',\n  732 => ' ̃',\n  733 => ' ̋',\n  890 => ' ι',\n  894 => ';',\n  900 => ' ́',\n  901 => ' ̈́',\n  8125 => ' ̓',\n  8127 => ' ̓',\n  8128 => ' ͂',\n  8129 => ' ̈͂',\n  8141 => ' ̓̀',\n  8142 => ' ̓́',\n  8143 => ' ̓͂',\n  8157 => ' ̔̀',\n  8158 => ' ̔́',\n  8159 => ' ̔͂',\n  8173 => ' ̈̀',\n  8174 => ' ̈́',\n  8175 => '`',\n  8189 => ' ́',\n  8190 => ' ̔',\n  8192 => ' ',\n  8193 => ' ',\n  8194 => ' ',\n  8195 => ' ',\n  8196 => ' ',\n  8197 => ' ',\n  8198 => ' ',\n  8199 => ' ',\n  8200 => ' ',\n  8201 => ' ',\n  8202 => ' ',\n  8215 => ' ̳',\n  8239 => ' ',\n  8252 => '!!',\n  8254 => ' ̅',\n  8263 => '??',\n  8264 => '?!',\n  8265 => '!?',\n  8287 => ' ',\n  8314 => '+',\n  8316 => '=',\n  8317 => '(',\n  8318 => ')',\n  8330 => '+',\n  8332 => '=',\n  8333 => '(',\n  8334 => ')',\n  8448 => 'a/c',\n  8449 => 'a/s',\n  8453 => 'c/o',\n  8454 => 'c/u',\n  9332 => '(1)',\n  9333 => '(2)',\n  9334 => '(3)',\n  9335 => '(4)',\n  9336 => '(5)',\n  9337 => '(6)',\n  9338 => '(7)',\n  9339 => '(8)',\n  9340 => '(9)',\n  9341 => '(10)',\n  9342 => '(11)',\n  9343 => '(12)',\n  9344 => '(13)',\n  9345 => '(14)',\n  9346 => '(15)',\n  9347 => '(16)',\n  9348 => '(17)',\n  9349 => '(18)',\n  9350 => '(19)',\n  9351 => '(20)',\n  9372 => '(a)',\n  9373 => '(b)',\n  9374 => '(c)',\n  9375 => '(d)',\n  9376 => '(e)',\n  9377 => '(f)',\n  9378 => '(g)',\n  9379 => '(h)',\n  9380 => '(i)',\n  9381 => '(j)',\n  9382 => '(k)',\n  9383 => '(l)',\n  9384 => '(m)',\n  9385 => '(n)',\n  9386 => '(o)',\n  9387 => '(p)',\n  9388 => '(q)',\n  9389 => '(r)',\n  9390 => '(s)',\n  9391 => '(t)',\n  9392 => '(u)',\n  9393 => '(v)',\n  9394 => '(w)',\n  9395 => '(x)',\n  9396 => '(y)',\n  9397 => '(z)',\n  10868 => '::=',\n  10869 => '==',\n  10870 => '===',\n  12288 => ' ',\n  12443 => ' ゙',\n  12444 => ' ゚',\n  12800 => '(ᄀ)',\n  12801 => '(ᄂ)',\n  12802 => '(ᄃ)',\n  12803 => '(ᄅ)',\n  12804 => '(ᄆ)',\n  12805 => '(ᄇ)',\n  12806 => '(ᄉ)',\n  12807 => '(ᄋ)',\n  12808 => '(ᄌ)',\n  12809 => '(ᄎ)',\n  12810 => '(ᄏ)',\n  12811 => '(ᄐ)',\n  12812 => '(ᄑ)',\n  12813 => '(ᄒ)',\n  12814 => '(가)',\n  12815 => '(나)',\n  12816 => '(다)',\n  12817 => '(라)',\n  12818 => '(마)',\n  12819 => '(바)',\n  12820 => '(사)',\n  12821 => '(아)',\n  12822 => '(자)',\n  12823 => '(차)',\n  12824 => '(카)',\n  12825 => '(타)',\n  12826 => '(파)',\n  12827 => '(하)',\n  12828 => '(주)',\n  12829 => '(오전)',\n  12830 => '(오후)',\n  12832 => '(一)',\n  12833 => '(二)',\n  12834 => '(三)',\n  12835 => '(四)',\n  12836 => '(五)',\n  12837 => '(六)',\n  12838 => '(七)',\n  12839 => '(八)',\n  12840 => '(九)',\n  12841 => '(十)',\n  12842 => '(月)',\n  12843 => '(火)',\n  12844 => '(水)',\n  12845 => '(木)',\n  12846 => '(金)',\n  12847 => '(土)',\n  12848 => '(日)',\n  12849 => '(株)',\n  12850 => '(有)',\n  12851 => '(社)',\n  12852 => '(名)',\n  12853 => '(特)',\n  12854 => '(財)',\n  12855 => '(祝)',\n  12856 => '(労)',\n  12857 => '(代)',\n  12858 => '(呼)',\n  12859 => '(学)',\n  12860 => '(監)',\n  12861 => '(企)',\n  12862 => '(資)',\n  12863 => '(協)',\n  12864 => '(祭)',\n  12865 => '(休)',\n  12866 => '(自)',\n  12867 => '(至)',\n  64297 => '+',\n  64606 => ' ٌّ',\n  64607 => ' ٍّ',\n  64608 => ' َّ',\n  64609 => ' ُّ',\n  64610 => ' ِّ',\n  64611 => ' ّٰ',\n  65018 => 'صلى الله عليه وسلم',\n  65019 => 'جل جلاله',\n  65040 => ',',\n  65043 => ':',\n  65044 => ';',\n  65045 => '!',\n  65046 => '?',\n  65075 => '_',\n  65076 => '_',\n  65077 => '(',\n  65078 => ')',\n  65079 => '{',\n  65080 => '}',\n  65095 => '[',\n  65096 => ']',\n  65097 => ' ̅',\n  65098 => ' ̅',\n  65099 => ' ̅',\n  65100 => ' ̅',\n  65101 => '_',\n  65102 => '_',\n  65103 => '_',\n  65104 => ',',\n  65108 => ';',\n  65109 => ':',\n  65110 => '?',\n  65111 => '!',\n  65113 => '(',\n  65114 => ')',\n  65115 => '{',\n  65116 => '}',\n  65119 => '#',\n  65120 => '&',\n  65121 => '*',\n  65122 => '+',\n  65124 => '<',\n  65125 => '>',\n  65126 => '=',\n  65128 => '\\\\',\n  65129 => '$',\n  65130 => '%',\n  65131 => '@',\n  65136 => ' ً',\n  65138 => ' ٌ',\n  65140 => ' ٍ',\n  65142 => ' َ',\n  65144 => ' ُ',\n  65146 => ' ِ',\n  65148 => ' ّ',\n  65150 => ' ْ',\n  65281 => '!',\n  65282 => '\"',\n  65283 => '#',\n  65284 => '$',\n  65285 => '%',\n  65286 => '&',\n  65287 => '\\'',\n  65288 => '(',\n  65289 => ')',\n  65290 => '*',\n  65291 => '+',\n  65292 => ',',\n  65295 => '/',\n  65306 => ':',\n  65307 => ';',\n  65308 => '<',\n  65309 => '=',\n  65310 => '>',\n  65311 => '?',\n  65312 => '@',\n  65339 => '[',\n  65340 => '\\\\',\n  65341 => ']',\n  65342 => '^',\n  65343 => '_',\n  65344 => '`',\n  65371 => '{',\n  65372 => '|',\n  65373 => '}',\n  65374 => '~',\n  65507 => ' ̄',\n  127233 => '0,',\n  127234 => '1,',\n  127235 => '2,',\n  127236 => '3,',\n  127237 => '4,',\n  127238 => '5,',\n  127239 => '6,',\n  127240 => '7,',\n  127241 => '8,',\n  127242 => '9,',\n  127248 => '(a)',\n  127249 => '(b)',\n  127250 => '(c)',\n  127251 => '(d)',\n  127252 => '(e)',\n  127253 => '(f)',\n  127254 => '(g)',\n  127255 => '(h)',\n  127256 => '(i)',\n  127257 => '(j)',\n  127258 => '(k)',\n  127259 => '(l)',\n  127260 => '(m)',\n  127261 => '(n)',\n  127262 => '(o)',\n  127263 => '(p)',\n  127264 => '(q)',\n  127265 => '(r)',\n  127266 => '(s)',\n  127267 => '(t)',\n  127268 => '(u)',\n  127269 => '(v)',\n  127270 => '(w)',\n  127271 => '(x)',\n  127272 => '(y)',\n  127273 => '(z)',\n);\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-intl-idn/Resources/unidata/disallowed_STD3_valid.php",
    "content": "<?php\n\nreturn array (\n  0 => true,\n  1 => true,\n  2 => true,\n  3 => true,\n  4 => true,\n  5 => true,\n  6 => true,\n  7 => true,\n  8 => true,\n  9 => true,\n  10 => true,\n  11 => true,\n  12 => true,\n  13 => true,\n  14 => true,\n  15 => true,\n  16 => true,\n  17 => true,\n  18 => true,\n  19 => true,\n  20 => true,\n  21 => true,\n  22 => true,\n  23 => true,\n  24 => true,\n  25 => true,\n  26 => true,\n  27 => true,\n  28 => true,\n  29 => true,\n  30 => true,\n  31 => true,\n  32 => true,\n  33 => true,\n  34 => true,\n  35 => true,\n  36 => true,\n  37 => true,\n  38 => true,\n  39 => true,\n  40 => true,\n  41 => true,\n  42 => true,\n  43 => true,\n  44 => true,\n  47 => true,\n  58 => true,\n  59 => true,\n  60 => true,\n  61 => true,\n  62 => true,\n  63 => true,\n  64 => true,\n  91 => true,\n  92 => true,\n  93 => true,\n  94 => true,\n  95 => true,\n  96 => true,\n  123 => true,\n  124 => true,\n  125 => true,\n  126 => true,\n  127 => true,\n  8800 => true,\n  8814 => true,\n  8815 => true,\n);\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-intl-idn/Resources/unidata/ignored.php",
    "content": "<?php\n\nreturn array (\n  173 => true,\n  847 => true,\n  6155 => true,\n  6156 => true,\n  6157 => true,\n  8203 => true,\n  8288 => true,\n  8292 => true,\n  65024 => true,\n  65025 => true,\n  65026 => true,\n  65027 => true,\n  65028 => true,\n  65029 => true,\n  65030 => true,\n  65031 => true,\n  65032 => true,\n  65033 => true,\n  65034 => true,\n  65035 => true,\n  65036 => true,\n  65037 => true,\n  65038 => true,\n  65039 => true,\n  65279 => true,\n  113824 => true,\n  113825 => true,\n  113826 => true,\n  113827 => true,\n  917760 => true,\n  917761 => true,\n  917762 => true,\n  917763 => true,\n  917764 => true,\n  917765 => true,\n  917766 => true,\n  917767 => true,\n  917768 => true,\n  917769 => true,\n  917770 => true,\n  917771 => true,\n  917772 => true,\n  917773 => true,\n  917774 => true,\n  917775 => true,\n  917776 => true,\n  917777 => true,\n  917778 => true,\n  917779 => true,\n  917780 => true,\n  917781 => true,\n  917782 => true,\n  917783 => true,\n  917784 => true,\n  917785 => true,\n  917786 => true,\n  917787 => true,\n  917788 => true,\n  917789 => true,\n  917790 => true,\n  917791 => true,\n  917792 => true,\n  917793 => true,\n  917794 => true,\n  917795 => true,\n  917796 => true,\n  917797 => true,\n  917798 => true,\n  917799 => true,\n  917800 => true,\n  917801 => true,\n  917802 => true,\n  917803 => true,\n  917804 => true,\n  917805 => true,\n  917806 => true,\n  917807 => true,\n  917808 => true,\n  917809 => true,\n  917810 => true,\n  917811 => true,\n  917812 => true,\n  917813 => true,\n  917814 => true,\n  917815 => true,\n  917816 => true,\n  917817 => true,\n  917818 => true,\n  917819 => true,\n  917820 => true,\n  917821 => true,\n  917822 => true,\n  917823 => true,\n  917824 => true,\n  917825 => true,\n  917826 => true,\n  917827 => true,\n  917828 => true,\n  917829 => true,\n  917830 => true,\n  917831 => true,\n  917832 => true,\n  917833 => true,\n  917834 => true,\n  917835 => true,\n  917836 => true,\n  917837 => true,\n  917838 => true,\n  917839 => true,\n  917840 => true,\n  917841 => true,\n  917842 => true,\n  917843 => true,\n  917844 => true,\n  917845 => true,\n  917846 => true,\n  917847 => true,\n  917848 => true,\n  917849 => true,\n  917850 => true,\n  917851 => true,\n  917852 => true,\n  917853 => true,\n  917854 => true,\n  917855 => true,\n  917856 => true,\n  917857 => true,\n  917858 => true,\n  917859 => true,\n  917860 => true,\n  917861 => true,\n  917862 => true,\n  917863 => true,\n  917864 => true,\n  917865 => true,\n  917866 => true,\n  917867 => true,\n  917868 => true,\n  917869 => true,\n  917870 => true,\n  917871 => true,\n  917872 => true,\n  917873 => true,\n  917874 => true,\n  917875 => true,\n  917876 => true,\n  917877 => true,\n  917878 => true,\n  917879 => true,\n  917880 => true,\n  917881 => true,\n  917882 => true,\n  917883 => true,\n  917884 => true,\n  917885 => true,\n  917886 => true,\n  917887 => true,\n  917888 => true,\n  917889 => true,\n  917890 => true,\n  917891 => true,\n  917892 => true,\n  917893 => true,\n  917894 => true,\n  917895 => true,\n  917896 => true,\n  917897 => true,\n  917898 => true,\n  917899 => true,\n  917900 => true,\n  917901 => true,\n  917902 => true,\n  917903 => true,\n  917904 => true,\n  917905 => true,\n  917906 => true,\n  917907 => true,\n  917908 => true,\n  917909 => true,\n  917910 => true,\n  917911 => true,\n  917912 => true,\n  917913 => true,\n  917914 => true,\n  917915 => true,\n  917916 => true,\n  917917 => true,\n  917918 => true,\n  917919 => true,\n  917920 => true,\n  917921 => true,\n  917922 => true,\n  917923 => true,\n  917924 => true,\n  917925 => true,\n  917926 => true,\n  917927 => true,\n  917928 => true,\n  917929 => true,\n  917930 => true,\n  917931 => true,\n  917932 => true,\n  917933 => true,\n  917934 => true,\n  917935 => true,\n  917936 => true,\n  917937 => true,\n  917938 => true,\n  917939 => true,\n  917940 => true,\n  917941 => true,\n  917942 => true,\n  917943 => true,\n  917944 => true,\n  917945 => true,\n  917946 => true,\n  917947 => true,\n  917948 => true,\n  917949 => true,\n  917950 => true,\n  917951 => true,\n  917952 => true,\n  917953 => true,\n  917954 => true,\n  917955 => true,\n  917956 => true,\n  917957 => true,\n  917958 => true,\n  917959 => true,\n  917960 => true,\n  917961 => true,\n  917962 => true,\n  917963 => true,\n  917964 => true,\n  917965 => true,\n  917966 => true,\n  917967 => true,\n  917968 => true,\n  917969 => true,\n  917970 => true,\n  917971 => true,\n  917972 => true,\n  917973 => true,\n  917974 => true,\n  917975 => true,\n  917976 => true,\n  917977 => true,\n  917978 => true,\n  917979 => true,\n  917980 => true,\n  917981 => true,\n  917982 => true,\n  917983 => true,\n  917984 => true,\n  917985 => true,\n  917986 => true,\n  917987 => true,\n  917988 => true,\n  917989 => true,\n  917990 => true,\n  917991 => true,\n  917992 => true,\n  917993 => true,\n  917994 => true,\n  917995 => true,\n  917996 => true,\n  917997 => true,\n  917998 => true,\n  917999 => true,\n);\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-intl-idn/Resources/unidata/mapped.php",
    "content": "<?php\n\nreturn array (\n  65 => 'a',\n  66 => 'b',\n  67 => 'c',\n  68 => 'd',\n  69 => 'e',\n  70 => 'f',\n  71 => 'g',\n  72 => 'h',\n  73 => 'i',\n  74 => 'j',\n  75 => 'k',\n  76 => 'l',\n  77 => 'm',\n  78 => 'n',\n  79 => 'o',\n  80 => 'p',\n  81 => 'q',\n  82 => 'r',\n  83 => 's',\n  84 => 't',\n  85 => 'u',\n  86 => 'v',\n  87 => 'w',\n  88 => 'x',\n  89 => 'y',\n  90 => 'z',\n  170 => 'a',\n  178 => '2',\n  179 => '3',\n  181 => 'μ',\n  185 => '1',\n  186 => 'o',\n  188 => '1⁄4',\n  189 => '1⁄2',\n  190 => '3⁄4',\n  192 => 'à',\n  193 => 'á',\n  194 => 'â',\n  195 => 'ã',\n  196 => 'ä',\n  197 => 'å',\n  198 => 'æ',\n  199 => 'ç',\n  200 => 'è',\n  201 => 'é',\n  202 => 'ê',\n  203 => 'ë',\n  204 => 'ì',\n  205 => 'í',\n  206 => 'î',\n  207 => 'ï',\n  208 => 'ð',\n  209 => 'ñ',\n  210 => 'ò',\n  211 => 'ó',\n  212 => 'ô',\n  213 => 'õ',\n  214 => 'ö',\n  216 => 'ø',\n  217 => 'ù',\n  218 => 'ú',\n  219 => 'û',\n  220 => 'ü',\n  221 => 'ý',\n  222 => 'þ',\n  256 => 'ā',\n  258 => 'ă',\n  260 => 'ą',\n  262 => 'ć',\n  264 => 'ĉ',\n  266 => 'ċ',\n  268 => 'č',\n  270 => 'ď',\n  272 => 'đ',\n  274 => 'ē',\n  276 => 'ĕ',\n  278 => 'ė',\n  280 => 'ę',\n  282 => 'ě',\n  284 => 'ĝ',\n  286 => 'ğ',\n  288 => 'ġ',\n  290 => 'ģ',\n  292 => 'ĥ',\n  294 => 'ħ',\n  296 => 'ĩ',\n  298 => 'ī',\n  300 => 'ĭ',\n  302 => 'į',\n  304 => 'i̇',\n  306 => 'ij',\n  307 => 'ij',\n  308 => 'ĵ',\n  310 => 'ķ',\n  313 => 'ĺ',\n  315 => 'ļ',\n  317 => 'ľ',\n  319 => 'l·',\n  320 => 'l·',\n  321 => 'ł',\n  323 => 'ń',\n  325 => 'ņ',\n  327 => 'ň',\n  329 => 'ʼn',\n  330 => 'ŋ',\n  332 => 'ō',\n  334 => 'ŏ',\n  336 => 'ő',\n  338 => 'œ',\n  340 => 'ŕ',\n  342 => 'ŗ',\n  344 => 'ř',\n  346 => 'ś',\n  348 => 'ŝ',\n  350 => 'ş',\n  352 => 'š',\n  354 => 'ţ',\n  356 => 'ť',\n  358 => 'ŧ',\n  360 => 'ũ',\n  362 => 'ū',\n  364 => 'ŭ',\n  366 => 'ů',\n  368 => 'ű',\n  370 => 'ų',\n  372 => 'ŵ',\n  374 => 'ŷ',\n  376 => 'ÿ',\n  377 => 'ź',\n  379 => 'ż',\n  381 => 'ž',\n  383 => 's',\n  385 => 'ɓ',\n  386 => 'ƃ',\n  388 => 'ƅ',\n  390 => 'ɔ',\n  391 => 'ƈ',\n  393 => 'ɖ',\n  394 => 'ɗ',\n  395 => 'ƌ',\n  398 => 'ǝ',\n  399 => 'ə',\n  400 => 'ɛ',\n  401 => 'ƒ',\n  403 => 'ɠ',\n  404 => 'ɣ',\n  406 => 'ɩ',\n  407 => 'ɨ',\n  408 => 'ƙ',\n  412 => 'ɯ',\n  413 => 'ɲ',\n  415 => 'ɵ',\n  416 => 'ơ',\n  418 => 'ƣ',\n  420 => 'ƥ',\n  422 => 'ʀ',\n  423 => 'ƨ',\n  425 => 'ʃ',\n  428 => 'ƭ',\n  430 => 'ʈ',\n  431 => 'ư',\n  433 => 'ʊ',\n  434 => 'ʋ',\n  435 => 'ƴ',\n  437 => 'ƶ',\n  439 => 'ʒ',\n  440 => 'ƹ',\n  444 => 'ƽ',\n  452 => 'dž',\n  453 => 'dž',\n  454 => 'dž',\n  455 => 'lj',\n  456 => 'lj',\n  457 => 'lj',\n  458 => 'nj',\n  459 => 'nj',\n  460 => 'nj',\n  461 => 'ǎ',\n  463 => 'ǐ',\n  465 => 'ǒ',\n  467 => 'ǔ',\n  469 => 'ǖ',\n  471 => 'ǘ',\n  473 => 'ǚ',\n  475 => 'ǜ',\n  478 => 'ǟ',\n  480 => 'ǡ',\n  482 => 'ǣ',\n  484 => 'ǥ',\n  486 => 'ǧ',\n  488 => 'ǩ',\n  490 => 'ǫ',\n  492 => 'ǭ',\n  494 => 'ǯ',\n  497 => 'dz',\n  498 => 'dz',\n  499 => 'dz',\n  500 => 'ǵ',\n  502 => 'ƕ',\n  503 => 'ƿ',\n  504 => 'ǹ',\n  506 => 'ǻ',\n  508 => 'ǽ',\n  510 => 'ǿ',\n  512 => 'ȁ',\n  514 => 'ȃ',\n  516 => 'ȅ',\n  518 => 'ȇ',\n  520 => 'ȉ',\n  522 => 'ȋ',\n  524 => 'ȍ',\n  526 => 'ȏ',\n  528 => 'ȑ',\n  530 => 'ȓ',\n  532 => 'ȕ',\n  534 => 'ȗ',\n  536 => 'ș',\n  538 => 'ț',\n  540 => 'ȝ',\n  542 => 'ȟ',\n  544 => 'ƞ',\n  546 => 'ȣ',\n  548 => 'ȥ',\n  550 => 'ȧ',\n  552 => 'ȩ',\n  554 => 'ȫ',\n  556 => 'ȭ',\n  558 => 'ȯ',\n  560 => 'ȱ',\n  562 => 'ȳ',\n  570 => 'ⱥ',\n  571 => 'ȼ',\n  573 => 'ƚ',\n  574 => 'ⱦ',\n  577 => 'ɂ',\n  579 => 'ƀ',\n  580 => 'ʉ',\n  581 => 'ʌ',\n  582 => 'ɇ',\n  584 => 'ɉ',\n  586 => 'ɋ',\n  588 => 'ɍ',\n  590 => 'ɏ',\n  688 => 'h',\n  689 => 'ɦ',\n  690 => 'j',\n  691 => 'r',\n  692 => 'ɹ',\n  693 => 'ɻ',\n  694 => 'ʁ',\n  695 => 'w',\n  696 => 'y',\n  736 => 'ɣ',\n  737 => 'l',\n  738 => 's',\n  739 => 'x',\n  740 => 'ʕ',\n  832 => '̀',\n  833 => '́',\n  835 => '̓',\n  836 => '̈́',\n  837 => 'ι',\n  880 => 'ͱ',\n  882 => 'ͳ',\n  884 => 'ʹ',\n  886 => 'ͷ',\n  895 => 'ϳ',\n  902 => 'ά',\n  903 => '·',\n  904 => 'έ',\n  905 => 'ή',\n  906 => 'ί',\n  908 => 'ό',\n  910 => 'ύ',\n  911 => 'ώ',\n  913 => 'α',\n  914 => 'β',\n  915 => 'γ',\n  916 => 'δ',\n  917 => 'ε',\n  918 => 'ζ',\n  919 => 'η',\n  920 => 'θ',\n  921 => 'ι',\n  922 => 'κ',\n  923 => 'λ',\n  924 => 'μ',\n  925 => 'ν',\n  926 => 'ξ',\n  927 => 'ο',\n  928 => 'π',\n  929 => 'ρ',\n  931 => 'σ',\n  932 => 'τ',\n  933 => 'υ',\n  934 => 'φ',\n  935 => 'χ',\n  936 => 'ψ',\n  937 => 'ω',\n  938 => 'ϊ',\n  939 => 'ϋ',\n  975 => 'ϗ',\n  976 => 'β',\n  977 => 'θ',\n  978 => 'υ',\n  979 => 'ύ',\n  980 => 'ϋ',\n  981 => 'φ',\n  982 => 'π',\n  984 => 'ϙ',\n  986 => 'ϛ',\n  988 => 'ϝ',\n  990 => 'ϟ',\n  992 => 'ϡ',\n  994 => 'ϣ',\n  996 => 'ϥ',\n  998 => 'ϧ',\n  1000 => 'ϩ',\n  1002 => 'ϫ',\n  1004 => 'ϭ',\n  1006 => 'ϯ',\n  1008 => 'κ',\n  1009 => 'ρ',\n  1010 => 'σ',\n  1012 => 'θ',\n  1013 => 'ε',\n  1015 => 'ϸ',\n  1017 => 'σ',\n  1018 => 'ϻ',\n  1021 => 'ͻ',\n  1022 => 'ͼ',\n  1023 => 'ͽ',\n  1024 => 'ѐ',\n  1025 => 'ё',\n  1026 => 'ђ',\n  1027 => 'ѓ',\n  1028 => 'є',\n  1029 => 'ѕ',\n  1030 => 'і',\n  1031 => 'ї',\n  1032 => 'ј',\n  1033 => 'љ',\n  1034 => 'њ',\n  1035 => 'ћ',\n  1036 => 'ќ',\n  1037 => 'ѝ',\n  1038 => 'ў',\n  1039 => 'џ',\n  1040 => 'а',\n  1041 => 'б',\n  1042 => 'в',\n  1043 => 'г',\n  1044 => 'д',\n  1045 => 'е',\n  1046 => 'ж',\n  1047 => 'з',\n  1048 => 'и',\n  1049 => 'й',\n  1050 => 'к',\n  1051 => 'л',\n  1052 => 'м',\n  1053 => 'н',\n  1054 => 'о',\n  1055 => 'п',\n  1056 => 'р',\n  1057 => 'с',\n  1058 => 'т',\n  1059 => 'у',\n  1060 => 'ф',\n  1061 => 'х',\n  1062 => 'ц',\n  1063 => 'ч',\n  1064 => 'ш',\n  1065 => 'щ',\n  1066 => 'ъ',\n  1067 => 'ы',\n  1068 => 'ь',\n  1069 => 'э',\n  1070 => 'ю',\n  1071 => 'я',\n  1120 => 'ѡ',\n  1122 => 'ѣ',\n  1124 => 'ѥ',\n  1126 => 'ѧ',\n  1128 => 'ѩ',\n  1130 => 'ѫ',\n  1132 => 'ѭ',\n  1134 => 'ѯ',\n  1136 => 'ѱ',\n  1138 => 'ѳ',\n  1140 => 'ѵ',\n  1142 => 'ѷ',\n  1144 => 'ѹ',\n  1146 => 'ѻ',\n  1148 => 'ѽ',\n  1150 => 'ѿ',\n  1152 => 'ҁ',\n  1162 => 'ҋ',\n  1164 => 'ҍ',\n  1166 => 'ҏ',\n  1168 => 'ґ',\n  1170 => 'ғ',\n  1172 => 'ҕ',\n  1174 => 'җ',\n  1176 => 'ҙ',\n  1178 => 'қ',\n  1180 => 'ҝ',\n  1182 => 'ҟ',\n  1184 => 'ҡ',\n  1186 => 'ң',\n  1188 => 'ҥ',\n  1190 => 'ҧ',\n  1192 => 'ҩ',\n  1194 => 'ҫ',\n  1196 => 'ҭ',\n  1198 => 'ү',\n  1200 => 'ұ',\n  1202 => 'ҳ',\n  1204 => 'ҵ',\n  1206 => 'ҷ',\n  1208 => 'ҹ',\n  1210 => 'һ',\n  1212 => 'ҽ',\n  1214 => 'ҿ',\n  1217 => 'ӂ',\n  1219 => 'ӄ',\n  1221 => 'ӆ',\n  1223 => 'ӈ',\n  1225 => 'ӊ',\n  1227 => 'ӌ',\n  1229 => 'ӎ',\n  1232 => 'ӑ',\n  1234 => 'ӓ',\n  1236 => 'ӕ',\n  1238 => 'ӗ',\n  1240 => 'ә',\n  1242 => 'ӛ',\n  1244 => 'ӝ',\n  1246 => 'ӟ',\n  1248 => 'ӡ',\n  1250 => 'ӣ',\n  1252 => 'ӥ',\n  1254 => 'ӧ',\n  1256 => 'ө',\n  1258 => 'ӫ',\n  1260 => 'ӭ',\n  1262 => 'ӯ',\n  1264 => 'ӱ',\n  1266 => 'ӳ',\n  1268 => 'ӵ',\n  1270 => 'ӷ',\n  1272 => 'ӹ',\n  1274 => 'ӻ',\n  1276 => 'ӽ',\n  1278 => 'ӿ',\n  1280 => 'ԁ',\n  1282 => 'ԃ',\n  1284 => 'ԅ',\n  1286 => 'ԇ',\n  1288 => 'ԉ',\n  1290 => 'ԋ',\n  1292 => 'ԍ',\n  1294 => 'ԏ',\n  1296 => 'ԑ',\n  1298 => 'ԓ',\n  1300 => 'ԕ',\n  1302 => 'ԗ',\n  1304 => 'ԙ',\n  1306 => 'ԛ',\n  1308 => 'ԝ',\n  1310 => 'ԟ',\n  1312 => 'ԡ',\n  1314 => 'ԣ',\n  1316 => 'ԥ',\n  1318 => 'ԧ',\n  1320 => 'ԩ',\n  1322 => 'ԫ',\n  1324 => 'ԭ',\n  1326 => 'ԯ',\n  1329 => 'ա',\n  1330 => 'բ',\n  1331 => 'գ',\n  1332 => 'դ',\n  1333 => 'ե',\n  1334 => 'զ',\n  1335 => 'է',\n  1336 => 'ը',\n  1337 => 'թ',\n  1338 => 'ժ',\n  1339 => 'ի',\n  1340 => 'լ',\n  1341 => 'խ',\n  1342 => 'ծ',\n  1343 => 'կ',\n  1344 => 'հ',\n  1345 => 'ձ',\n  1346 => 'ղ',\n  1347 => 'ճ',\n  1348 => 'մ',\n  1349 => 'յ',\n  1350 => 'ն',\n  1351 => 'շ',\n  1352 => 'ո',\n  1353 => 'չ',\n  1354 => 'պ',\n  1355 => 'ջ',\n  1356 => 'ռ',\n  1357 => 'ս',\n  1358 => 'վ',\n  1359 => 'տ',\n  1360 => 'ր',\n  1361 => 'ց',\n  1362 => 'ւ',\n  1363 => 'փ',\n  1364 => 'ք',\n  1365 => 'օ',\n  1366 => 'ֆ',\n  1415 => 'եւ',\n  1653 => 'اٴ',\n  1654 => 'وٴ',\n  1655 => 'ۇٴ',\n  1656 => 'يٴ',\n  2392 => 'क़',\n  2393 => 'ख़',\n  2394 => 'ग़',\n  2395 => 'ज़',\n  2396 => 'ड़',\n  2397 => 'ढ़',\n  2398 => 'फ़',\n  2399 => 'य़',\n  2524 => 'ড়',\n  2525 => 'ঢ়',\n  2527 => 'য়',\n  2611 => 'ਲ਼',\n  2614 => 'ਸ਼',\n  2649 => 'ਖ਼',\n  2650 => 'ਗ਼',\n  2651 => 'ਜ਼',\n  2654 => 'ਫ਼',\n  2908 => 'ଡ଼',\n  2909 => 'ଢ଼',\n  3635 => 'ํา',\n  3763 => 'ໍາ',\n  3804 => 'ຫນ',\n  3805 => 'ຫມ',\n  3852 => '་',\n  3907 => 'གྷ',\n  3917 => 'ཌྷ',\n  3922 => 'དྷ',\n  3927 => 'བྷ',\n  3932 => 'ཛྷ',\n  3945 => 'ཀྵ',\n  3955 => 'ཱི',\n  3957 => 'ཱུ',\n  3958 => 'ྲྀ',\n  3959 => 'ྲཱྀ',\n  3960 => 'ླྀ',\n  3961 => 'ླཱྀ',\n  3969 => 'ཱྀ',\n  3987 => 'ྒྷ',\n  3997 => 'ྜྷ',\n  4002 => 'ྡྷ',\n  4007 => 'ྦྷ',\n  4012 => 'ྫྷ',\n  4025 => 'ྐྵ',\n  4295 => 'ⴧ',\n  4301 => 'ⴭ',\n  4348 => 'ნ',\n  5112 => 'Ᏸ',\n  5113 => 'Ᏹ',\n  5114 => 'Ᏺ',\n  5115 => 'Ᏻ',\n  5116 => 'Ᏼ',\n  5117 => 'Ᏽ',\n  7296 => 'в',\n  7297 => 'д',\n  7298 => 'о',\n  7299 => 'с',\n  7300 => 'т',\n  7301 => 'т',\n  7302 => 'ъ',\n  7303 => 'ѣ',\n  7304 => 'ꙋ',\n  7312 => 'ა',\n  7313 => 'ბ',\n  7314 => 'გ',\n  7315 => 'დ',\n  7316 => 'ე',\n  7317 => 'ვ',\n  7318 => 'ზ',\n  7319 => 'თ',\n  7320 => 'ი',\n  7321 => 'კ',\n  7322 => 'ლ',\n  7323 => 'მ',\n  7324 => 'ნ',\n  7325 => 'ო',\n  7326 => 'პ',\n  7327 => 'ჟ',\n  7328 => 'რ',\n  7329 => 'ს',\n  7330 => 'ტ',\n  7331 => 'უ',\n  7332 => 'ფ',\n  7333 => 'ქ',\n  7334 => 'ღ',\n  7335 => 'ყ',\n  7336 => 'შ',\n  7337 => 'ჩ',\n  7338 => 'ც',\n  7339 => 'ძ',\n  7340 => 'წ',\n  7341 => 'ჭ',\n  7342 => 'ხ',\n  7343 => 'ჯ',\n  7344 => 'ჰ',\n  7345 => 'ჱ',\n  7346 => 'ჲ',\n  7347 => 'ჳ',\n  7348 => 'ჴ',\n  7349 => 'ჵ',\n  7350 => 'ჶ',\n  7351 => 'ჷ',\n  7352 => 'ჸ',\n  7353 => 'ჹ',\n  7354 => 'ჺ',\n  7357 => 'ჽ',\n  7358 => 'ჾ',\n  7359 => 'ჿ',\n  7468 => 'a',\n  7469 => 'æ',\n  7470 => 'b',\n  7472 => 'd',\n  7473 => 'e',\n  7474 => 'ǝ',\n  7475 => 'g',\n  7476 => 'h',\n  7477 => 'i',\n  7478 => 'j',\n  7479 => 'k',\n  7480 => 'l',\n  7481 => 'm',\n  7482 => 'n',\n  7484 => 'o',\n  7485 => 'ȣ',\n  7486 => 'p',\n  7487 => 'r',\n  7488 => 't',\n  7489 => 'u',\n  7490 => 'w',\n  7491 => 'a',\n  7492 => 'ɐ',\n  7493 => 'ɑ',\n  7494 => 'ᴂ',\n  7495 => 'b',\n  7496 => 'd',\n  7497 => 'e',\n  7498 => 'ə',\n  7499 => 'ɛ',\n  7500 => 'ɜ',\n  7501 => 'g',\n  7503 => 'k',\n  7504 => 'm',\n  7505 => 'ŋ',\n  7506 => 'o',\n  7507 => 'ɔ',\n  7508 => 'ᴖ',\n  7509 => 'ᴗ',\n  7510 => 'p',\n  7511 => 't',\n  7512 => 'u',\n  7513 => 'ᴝ',\n  7514 => 'ɯ',\n  7515 => 'v',\n  7516 => 'ᴥ',\n  7517 => 'β',\n  7518 => 'γ',\n  7519 => 'δ',\n  7520 => 'φ',\n  7521 => 'χ',\n  7522 => 'i',\n  7523 => 'r',\n  7524 => 'u',\n  7525 => 'v',\n  7526 => 'β',\n  7527 => 'γ',\n  7528 => 'ρ',\n  7529 => 'φ',\n  7530 => 'χ',\n  7544 => 'н',\n  7579 => 'ɒ',\n  7580 => 'c',\n  7581 => 'ɕ',\n  7582 => 'ð',\n  7583 => 'ɜ',\n  7584 => 'f',\n  7585 => 'ɟ',\n  7586 => 'ɡ',\n  7587 => 'ɥ',\n  7588 => 'ɨ',\n  7589 => 'ɩ',\n  7590 => 'ɪ',\n  7591 => 'ᵻ',\n  7592 => 'ʝ',\n  7593 => 'ɭ',\n  7594 => 'ᶅ',\n  7595 => 'ʟ',\n  7596 => 'ɱ',\n  7597 => 'ɰ',\n  7598 => 'ɲ',\n  7599 => 'ɳ',\n  7600 => 'ɴ',\n  7601 => 'ɵ',\n  7602 => 'ɸ',\n  7603 => 'ʂ',\n  7604 => 'ʃ',\n  7605 => 'ƫ',\n  7606 => 'ʉ',\n  7607 => 'ʊ',\n  7608 => 'ᴜ',\n  7609 => 'ʋ',\n  7610 => 'ʌ',\n  7611 => 'z',\n  7612 => 'ʐ',\n  7613 => 'ʑ',\n  7614 => 'ʒ',\n  7615 => 'θ',\n  7680 => 'ḁ',\n  7682 => 'ḃ',\n  7684 => 'ḅ',\n  7686 => 'ḇ',\n  7688 => 'ḉ',\n  7690 => 'ḋ',\n  7692 => 'ḍ',\n  7694 => 'ḏ',\n  7696 => 'ḑ',\n  7698 => 'ḓ',\n  7700 => 'ḕ',\n  7702 => 'ḗ',\n  7704 => 'ḙ',\n  7706 => 'ḛ',\n  7708 => 'ḝ',\n  7710 => 'ḟ',\n  7712 => 'ḡ',\n  7714 => 'ḣ',\n  7716 => 'ḥ',\n  7718 => 'ḧ',\n  7720 => 'ḩ',\n  7722 => 'ḫ',\n  7724 => 'ḭ',\n  7726 => 'ḯ',\n  7728 => 'ḱ',\n  7730 => 'ḳ',\n  7732 => 'ḵ',\n  7734 => 'ḷ',\n  7736 => 'ḹ',\n  7738 => 'ḻ',\n  7740 => 'ḽ',\n  7742 => 'ḿ',\n  7744 => 'ṁ',\n  7746 => 'ṃ',\n  7748 => 'ṅ',\n  7750 => 'ṇ',\n  7752 => 'ṉ',\n  7754 => 'ṋ',\n  7756 => 'ṍ',\n  7758 => 'ṏ',\n  7760 => 'ṑ',\n  7762 => 'ṓ',\n  7764 => 'ṕ',\n  7766 => 'ṗ',\n  7768 => 'ṙ',\n  7770 => 'ṛ',\n  7772 => 'ṝ',\n  7774 => 'ṟ',\n  7776 => 'ṡ',\n  7778 => 'ṣ',\n  7780 => 'ṥ',\n  7782 => 'ṧ',\n  7784 => 'ṩ',\n  7786 => 'ṫ',\n  7788 => 'ṭ',\n  7790 => 'ṯ',\n  7792 => 'ṱ',\n  7794 => 'ṳ',\n  7796 => 'ṵ',\n  7798 => 'ṷ',\n  7800 => 'ṹ',\n  7802 => 'ṻ',\n  7804 => 'ṽ',\n  7806 => 'ṿ',\n  7808 => 'ẁ',\n  7810 => 'ẃ',\n  7812 => 'ẅ',\n  7814 => 'ẇ',\n  7816 => 'ẉ',\n  7818 => 'ẋ',\n  7820 => 'ẍ',\n  7822 => 'ẏ',\n  7824 => 'ẑ',\n  7826 => 'ẓ',\n  7828 => 'ẕ',\n  7834 => 'aʾ',\n  7835 => 'ṡ',\n  7838 => 'ss',\n  7840 => 'ạ',\n  7842 => 'ả',\n  7844 => 'ấ',\n  7846 => 'ầ',\n  7848 => 'ẩ',\n  7850 => 'ẫ',\n  7852 => 'ậ',\n  7854 => 'ắ',\n  7856 => 'ằ',\n  7858 => 'ẳ',\n  7860 => 'ẵ',\n  7862 => 'ặ',\n  7864 => 'ẹ',\n  7866 => 'ẻ',\n  7868 => 'ẽ',\n  7870 => 'ế',\n  7872 => 'ề',\n  7874 => 'ể',\n  7876 => 'ễ',\n  7878 => 'ệ',\n  7880 => 'ỉ',\n  7882 => 'ị',\n  7884 => 'ọ',\n  7886 => 'ỏ',\n  7888 => 'ố',\n  7890 => 'ồ',\n  7892 => 'ổ',\n  7894 => 'ỗ',\n  7896 => 'ộ',\n  7898 => 'ớ',\n  7900 => 'ờ',\n  7902 => 'ở',\n  7904 => 'ỡ',\n  7906 => 'ợ',\n  7908 => 'ụ',\n  7910 => 'ủ',\n  7912 => 'ứ',\n  7914 => 'ừ',\n  7916 => 'ử',\n  7918 => 'ữ',\n  7920 => 'ự',\n  7922 => 'ỳ',\n  7924 => 'ỵ',\n  7926 => 'ỷ',\n  7928 => 'ỹ',\n  7930 => 'ỻ',\n  7932 => 'ỽ',\n  7934 => 'ỿ',\n  7944 => 'ἀ',\n  7945 => 'ἁ',\n  7946 => 'ἂ',\n  7947 => 'ἃ',\n  7948 => 'ἄ',\n  7949 => 'ἅ',\n  7950 => 'ἆ',\n  7951 => 'ἇ',\n  7960 => 'ἐ',\n  7961 => 'ἑ',\n  7962 => 'ἒ',\n  7963 => 'ἓ',\n  7964 => 'ἔ',\n  7965 => 'ἕ',\n  7976 => 'ἠ',\n  7977 => 'ἡ',\n  7978 => 'ἢ',\n  7979 => 'ἣ',\n  7980 => 'ἤ',\n  7981 => 'ἥ',\n  7982 => 'ἦ',\n  7983 => 'ἧ',\n  7992 => 'ἰ',\n  7993 => 'ἱ',\n  7994 => 'ἲ',\n  7995 => 'ἳ',\n  7996 => 'ἴ',\n  7997 => 'ἵ',\n  7998 => 'ἶ',\n  7999 => 'ἷ',\n  8008 => 'ὀ',\n  8009 => 'ὁ',\n  8010 => 'ὂ',\n  8011 => 'ὃ',\n  8012 => 'ὄ',\n  8013 => 'ὅ',\n  8025 => 'ὑ',\n  8027 => 'ὓ',\n  8029 => 'ὕ',\n  8031 => 'ὗ',\n  8040 => 'ὠ',\n  8041 => 'ὡ',\n  8042 => 'ὢ',\n  8043 => 'ὣ',\n  8044 => 'ὤ',\n  8045 => 'ὥ',\n  8046 => 'ὦ',\n  8047 => 'ὧ',\n  8049 => 'ά',\n  8051 => 'έ',\n  8053 => 'ή',\n  8055 => 'ί',\n  8057 => 'ό',\n  8059 => 'ύ',\n  8061 => 'ώ',\n  8064 => 'ἀι',\n  8065 => 'ἁι',\n  8066 => 'ἂι',\n  8067 => 'ἃι',\n  8068 => 'ἄι',\n  8069 => 'ἅι',\n  8070 => 'ἆι',\n  8071 => 'ἇι',\n  8072 => 'ἀι',\n  8073 => 'ἁι',\n  8074 => 'ἂι',\n  8075 => 'ἃι',\n  8076 => 'ἄι',\n  8077 => 'ἅι',\n  8078 => 'ἆι',\n  8079 => 'ἇι',\n  8080 => 'ἠι',\n  8081 => 'ἡι',\n  8082 => 'ἢι',\n  8083 => 'ἣι',\n  8084 => 'ἤι',\n  8085 => 'ἥι',\n  8086 => 'ἦι',\n  8087 => 'ἧι',\n  8088 => 'ἠι',\n  8089 => 'ἡι',\n  8090 => 'ἢι',\n  8091 => 'ἣι',\n  8092 => 'ἤι',\n  8093 => 'ἥι',\n  8094 => 'ἦι',\n  8095 => 'ἧι',\n  8096 => 'ὠι',\n  8097 => 'ὡι',\n  8098 => 'ὢι',\n  8099 => 'ὣι',\n  8100 => 'ὤι',\n  8101 => 'ὥι',\n  8102 => 'ὦι',\n  8103 => 'ὧι',\n  8104 => 'ὠι',\n  8105 => 'ὡι',\n  8106 => 'ὢι',\n  8107 => 'ὣι',\n  8108 => 'ὤι',\n  8109 => 'ὥι',\n  8110 => 'ὦι',\n  8111 => 'ὧι',\n  8114 => 'ὰι',\n  8115 => 'αι',\n  8116 => 'άι',\n  8119 => 'ᾶι',\n  8120 => 'ᾰ',\n  8121 => 'ᾱ',\n  8122 => 'ὰ',\n  8123 => 'ά',\n  8124 => 'αι',\n  8126 => 'ι',\n  8130 => 'ὴι',\n  8131 => 'ηι',\n  8132 => 'ήι',\n  8135 => 'ῆι',\n  8136 => 'ὲ',\n  8137 => 'έ',\n  8138 => 'ὴ',\n  8139 => 'ή',\n  8140 => 'ηι',\n  8147 => 'ΐ',\n  8152 => 'ῐ',\n  8153 => 'ῑ',\n  8154 => 'ὶ',\n  8155 => 'ί',\n  8163 => 'ΰ',\n  8168 => 'ῠ',\n  8169 => 'ῡ',\n  8170 => 'ὺ',\n  8171 => 'ύ',\n  8172 => 'ῥ',\n  8178 => 'ὼι',\n  8179 => 'ωι',\n  8180 => 'ώι',\n  8183 => 'ῶι',\n  8184 => 'ὸ',\n  8185 => 'ό',\n  8186 => 'ὼ',\n  8187 => 'ώ',\n  8188 => 'ωι',\n  8209 => '‐',\n  8243 => '′′',\n  8244 => '′′′',\n  8246 => '‵‵',\n  8247 => '‵‵‵',\n  8279 => '′′′′',\n  8304 => '0',\n  8305 => 'i',\n  8308 => '4',\n  8309 => '5',\n  8310 => '6',\n  8311 => '7',\n  8312 => '8',\n  8313 => '9',\n  8315 => '−',\n  8319 => 'n',\n  8320 => '0',\n  8321 => '1',\n  8322 => '2',\n  8323 => '3',\n  8324 => '4',\n  8325 => '5',\n  8326 => '6',\n  8327 => '7',\n  8328 => '8',\n  8329 => '9',\n  8331 => '−',\n  8336 => 'a',\n  8337 => 'e',\n  8338 => 'o',\n  8339 => 'x',\n  8340 => 'ə',\n  8341 => 'h',\n  8342 => 'k',\n  8343 => 'l',\n  8344 => 'm',\n  8345 => 'n',\n  8346 => 'p',\n  8347 => 's',\n  8348 => 't',\n  8360 => 'rs',\n  8450 => 'c',\n  8451 => '°c',\n  8455 => 'ɛ',\n  8457 => '°f',\n  8458 => 'g',\n  8459 => 'h',\n  8460 => 'h',\n  8461 => 'h',\n  8462 => 'h',\n  8463 => 'ħ',\n  8464 => 'i',\n  8465 => 'i',\n  8466 => 'l',\n  8467 => 'l',\n  8469 => 'n',\n  8470 => 'no',\n  8473 => 'p',\n  8474 => 'q',\n  8475 => 'r',\n  8476 => 'r',\n  8477 => 'r',\n  8480 => 'sm',\n  8481 => 'tel',\n  8482 => 'tm',\n  8484 => 'z',\n  8486 => 'ω',\n  8488 => 'z',\n  8490 => 'k',\n  8491 => 'å',\n  8492 => 'b',\n  8493 => 'c',\n  8495 => 'e',\n  8496 => 'e',\n  8497 => 'f',\n  8499 => 'm',\n  8500 => 'o',\n  8501 => 'א',\n  8502 => 'ב',\n  8503 => 'ג',\n  8504 => 'ד',\n  8505 => 'i',\n  8507 => 'fax',\n  8508 => 'π',\n  8509 => 'γ',\n  8510 => 'γ',\n  8511 => 'π',\n  8512 => '∑',\n  8517 => 'd',\n  8518 => 'd',\n  8519 => 'e',\n  8520 => 'i',\n  8521 => 'j',\n  8528 => '1⁄7',\n  8529 => '1⁄9',\n  8530 => '1⁄10',\n  8531 => '1⁄3',\n  8532 => '2⁄3',\n  8533 => '1⁄5',\n  8534 => '2⁄5',\n  8535 => '3⁄5',\n  8536 => '4⁄5',\n  8537 => '1⁄6',\n  8538 => '5⁄6',\n  8539 => '1⁄8',\n  8540 => '3⁄8',\n  8541 => '5⁄8',\n  8542 => '7⁄8',\n  8543 => '1⁄',\n  8544 => 'i',\n  8545 => 'ii',\n  8546 => 'iii',\n  8547 => 'iv',\n  8548 => 'v',\n  8549 => 'vi',\n  8550 => 'vii',\n  8551 => 'viii',\n  8552 => 'ix',\n  8553 => 'x',\n  8554 => 'xi',\n  8555 => 'xii',\n  8556 => 'l',\n  8557 => 'c',\n  8558 => 'd',\n  8559 => 'm',\n  8560 => 'i',\n  8561 => 'ii',\n  8562 => 'iii',\n  8563 => 'iv',\n  8564 => 'v',\n  8565 => 'vi',\n  8566 => 'vii',\n  8567 => 'viii',\n  8568 => 'ix',\n  8569 => 'x',\n  8570 => 'xi',\n  8571 => 'xii',\n  8572 => 'l',\n  8573 => 'c',\n  8574 => 'd',\n  8575 => 'm',\n  8585 => '0⁄3',\n  8748 => '∫∫',\n  8749 => '∫∫∫',\n  8751 => '∮∮',\n  8752 => '∮∮∮',\n  9001 => '〈',\n  9002 => '〉',\n  9312 => '1',\n  9313 => '2',\n  9314 => '3',\n  9315 => '4',\n  9316 => '5',\n  9317 => '6',\n  9318 => '7',\n  9319 => '8',\n  9320 => '9',\n  9321 => '10',\n  9322 => '11',\n  9323 => '12',\n  9324 => '13',\n  9325 => '14',\n  9326 => '15',\n  9327 => '16',\n  9328 => '17',\n  9329 => '18',\n  9330 => '19',\n  9331 => '20',\n  9398 => 'a',\n  9399 => 'b',\n  9400 => 'c',\n  9401 => 'd',\n  9402 => 'e',\n  9403 => 'f',\n  9404 => 'g',\n  9405 => 'h',\n  9406 => 'i',\n  9407 => 'j',\n  9408 => 'k',\n  9409 => 'l',\n  9410 => 'm',\n  9411 => 'n',\n  9412 => 'o',\n  9413 => 'p',\n  9414 => 'q',\n  9415 => 'r',\n  9416 => 's',\n  9417 => 't',\n  9418 => 'u',\n  9419 => 'v',\n  9420 => 'w',\n  9421 => 'x',\n  9422 => 'y',\n  9423 => 'z',\n  9424 => 'a',\n  9425 => 'b',\n  9426 => 'c',\n  9427 => 'd',\n  9428 => 'e',\n  9429 => 'f',\n  9430 => 'g',\n  9431 => 'h',\n  9432 => 'i',\n  9433 => 'j',\n  9434 => 'k',\n  9435 => 'l',\n  9436 => 'm',\n  9437 => 'n',\n  9438 => 'o',\n  9439 => 'p',\n  9440 => 'q',\n  9441 => 'r',\n  9442 => 's',\n  9443 => 't',\n  9444 => 'u',\n  9445 => 'v',\n  9446 => 'w',\n  9447 => 'x',\n  9448 => 'y',\n  9449 => 'z',\n  9450 => '0',\n  10764 => '∫∫∫∫',\n  10972 => '⫝̸',\n  11264 => 'ⰰ',\n  11265 => 'ⰱ',\n  11266 => 'ⰲ',\n  11267 => 'ⰳ',\n  11268 => 'ⰴ',\n  11269 => 'ⰵ',\n  11270 => 'ⰶ',\n  11271 => 'ⰷ',\n  11272 => 'ⰸ',\n  11273 => 'ⰹ',\n  11274 => 'ⰺ',\n  11275 => 'ⰻ',\n  11276 => 'ⰼ',\n  11277 => 'ⰽ',\n  11278 => 'ⰾ',\n  11279 => 'ⰿ',\n  11280 => 'ⱀ',\n  11281 => 'ⱁ',\n  11282 => 'ⱂ',\n  11283 => 'ⱃ',\n  11284 => 'ⱄ',\n  11285 => 'ⱅ',\n  11286 => 'ⱆ',\n  11287 => 'ⱇ',\n  11288 => 'ⱈ',\n  11289 => 'ⱉ',\n  11290 => 'ⱊ',\n  11291 => 'ⱋ',\n  11292 => 'ⱌ',\n  11293 => 'ⱍ',\n  11294 => 'ⱎ',\n  11295 => 'ⱏ',\n  11296 => 'ⱐ',\n  11297 => 'ⱑ',\n  11298 => 'ⱒ',\n  11299 => 'ⱓ',\n  11300 => 'ⱔ',\n  11301 => 'ⱕ',\n  11302 => 'ⱖ',\n  11303 => 'ⱗ',\n  11304 => 'ⱘ',\n  11305 => 'ⱙ',\n  11306 => 'ⱚ',\n  11307 => 'ⱛ',\n  11308 => 'ⱜ',\n  11309 => 'ⱝ',\n  11310 => 'ⱞ',\n  11360 => 'ⱡ',\n  11362 => 'ɫ',\n  11363 => 'ᵽ',\n  11364 => 'ɽ',\n  11367 => 'ⱨ',\n  11369 => 'ⱪ',\n  11371 => 'ⱬ',\n  11373 => 'ɑ',\n  11374 => 'ɱ',\n  11375 => 'ɐ',\n  11376 => 'ɒ',\n  11378 => 'ⱳ',\n  11381 => 'ⱶ',\n  11388 => 'j',\n  11389 => 'v',\n  11390 => 'ȿ',\n  11391 => 'ɀ',\n  11392 => 'ⲁ',\n  11394 => 'ⲃ',\n  11396 => 'ⲅ',\n  11398 => 'ⲇ',\n  11400 => 'ⲉ',\n  11402 => 'ⲋ',\n  11404 => 'ⲍ',\n  11406 => 'ⲏ',\n  11408 => 'ⲑ',\n  11410 => 'ⲓ',\n  11412 => 'ⲕ',\n  11414 => 'ⲗ',\n  11416 => 'ⲙ',\n  11418 => 'ⲛ',\n  11420 => 'ⲝ',\n  11422 => 'ⲟ',\n  11424 => 'ⲡ',\n  11426 => 'ⲣ',\n  11428 => 'ⲥ',\n  11430 => 'ⲧ',\n  11432 => 'ⲩ',\n  11434 => 'ⲫ',\n  11436 => 'ⲭ',\n  11438 => 'ⲯ',\n  11440 => 'ⲱ',\n  11442 => 'ⲳ',\n  11444 => 'ⲵ',\n  11446 => 'ⲷ',\n  11448 => 'ⲹ',\n  11450 => 'ⲻ',\n  11452 => 'ⲽ',\n  11454 => 'ⲿ',\n  11456 => 'ⳁ',\n  11458 => 'ⳃ',\n  11460 => 'ⳅ',\n  11462 => 'ⳇ',\n  11464 => 'ⳉ',\n  11466 => 'ⳋ',\n  11468 => 'ⳍ',\n  11470 => 'ⳏ',\n  11472 => 'ⳑ',\n  11474 => 'ⳓ',\n  11476 => 'ⳕ',\n  11478 => 'ⳗ',\n  11480 => 'ⳙ',\n  11482 => 'ⳛ',\n  11484 => 'ⳝ',\n  11486 => 'ⳟ',\n  11488 => 'ⳡ',\n  11490 => 'ⳣ',\n  11499 => 'ⳬ',\n  11501 => 'ⳮ',\n  11506 => 'ⳳ',\n  11631 => 'ⵡ',\n  11935 => '母',\n  12019 => '龟',\n  12032 => '一',\n  12033 => '丨',\n  12034 => '丶',\n  12035 => '丿',\n  12036 => '乙',\n  12037 => '亅',\n  12038 => '二',\n  12039 => '亠',\n  12040 => '人',\n  12041 => '儿',\n  12042 => '入',\n  12043 => '八',\n  12044 => '冂',\n  12045 => '冖',\n  12046 => '冫',\n  12047 => '几',\n  12048 => '凵',\n  12049 => '刀',\n  12050 => '力',\n  12051 => '勹',\n  12052 => '匕',\n  12053 => '匚',\n  12054 => '匸',\n  12055 => '十',\n  12056 => '卜',\n  12057 => '卩',\n  12058 => '厂',\n  12059 => '厶',\n  12060 => '又',\n  12061 => '口',\n  12062 => '囗',\n  12063 => '土',\n  12064 => '士',\n  12065 => '夂',\n  12066 => '夊',\n  12067 => '夕',\n  12068 => '大',\n  12069 => '女',\n  12070 => '子',\n  12071 => '宀',\n  12072 => '寸',\n  12073 => '小',\n  12074 => '尢',\n  12075 => '尸',\n  12076 => '屮',\n  12077 => '山',\n  12078 => '巛',\n  12079 => '工',\n  12080 => '己',\n  12081 => '巾',\n  12082 => '干',\n  12083 => '幺',\n  12084 => '广',\n  12085 => '廴',\n  12086 => '廾',\n  12087 => '弋',\n  12088 => '弓',\n  12089 => '彐',\n  12090 => '彡',\n  12091 => '彳',\n  12092 => '心',\n  12093 => '戈',\n  12094 => '戶',\n  12095 => '手',\n  12096 => '支',\n  12097 => '攴',\n  12098 => '文',\n  12099 => '斗',\n  12100 => '斤',\n  12101 => '方',\n  12102 => '无',\n  12103 => '日',\n  12104 => '曰',\n  12105 => '月',\n  12106 => '木',\n  12107 => '欠',\n  12108 => '止',\n  12109 => '歹',\n  12110 => '殳',\n  12111 => '毋',\n  12112 => '比',\n  12113 => '毛',\n  12114 => '氏',\n  12115 => '气',\n  12116 => '水',\n  12117 => '火',\n  12118 => '爪',\n  12119 => '父',\n  12120 => '爻',\n  12121 => '爿',\n  12122 => '片',\n  12123 => '牙',\n  12124 => '牛',\n  12125 => '犬',\n  12126 => '玄',\n  12127 => '玉',\n  12128 => '瓜',\n  12129 => '瓦',\n  12130 => '甘',\n  12131 => '生',\n  12132 => '用',\n  12133 => '田',\n  12134 => '疋',\n  12135 => '疒',\n  12136 => '癶',\n  12137 => '白',\n  12138 => '皮',\n  12139 => '皿',\n  12140 => '目',\n  12141 => '矛',\n  12142 => '矢',\n  12143 => '石',\n  12144 => '示',\n  12145 => '禸',\n  12146 => '禾',\n  12147 => '穴',\n  12148 => '立',\n  12149 => '竹',\n  12150 => '米',\n  12151 => '糸',\n  12152 => '缶',\n  12153 => '网',\n  12154 => '羊',\n  12155 => '羽',\n  12156 => '老',\n  12157 => '而',\n  12158 => '耒',\n  12159 => '耳',\n  12160 => '聿',\n  12161 => '肉',\n  12162 => '臣',\n  12163 => '自',\n  12164 => '至',\n  12165 => '臼',\n  12166 => '舌',\n  12167 => '舛',\n  12168 => '舟',\n  12169 => '艮',\n  12170 => '色',\n  12171 => '艸',\n  12172 => '虍',\n  12173 => '虫',\n  12174 => '血',\n  12175 => '行',\n  12176 => '衣',\n  12177 => '襾',\n  12178 => '見',\n  12179 => '角',\n  12180 => '言',\n  12181 => '谷',\n  12182 => '豆',\n  12183 => '豕',\n  12184 => '豸',\n  12185 => '貝',\n  12186 => '赤',\n  12187 => '走',\n  12188 => '足',\n  12189 => '身',\n  12190 => '車',\n  12191 => '辛',\n  12192 => '辰',\n  12193 => '辵',\n  12194 => '邑',\n  12195 => '酉',\n  12196 => '釆',\n  12197 => '里',\n  12198 => '金',\n  12199 => '長',\n  12200 => '門',\n  12201 => '阜',\n  12202 => '隶',\n  12203 => '隹',\n  12204 => '雨',\n  12205 => '靑',\n  12206 => '非',\n  12207 => '面',\n  12208 => '革',\n  12209 => '韋',\n  12210 => '韭',\n  12211 => '音',\n  12212 => '頁',\n  12213 => '風',\n  12214 => '飛',\n  12215 => '食',\n  12216 => '首',\n  12217 => '香',\n  12218 => '馬',\n  12219 => '骨',\n  12220 => '高',\n  12221 => '髟',\n  12222 => '鬥',\n  12223 => '鬯',\n  12224 => '鬲',\n  12225 => '鬼',\n  12226 => '魚',\n  12227 => '鳥',\n  12228 => '鹵',\n  12229 => '鹿',\n  12230 => '麥',\n  12231 => '麻',\n  12232 => '黃',\n  12233 => '黍',\n  12234 => '黑',\n  12235 => '黹',\n  12236 => '黽',\n  12237 => '鼎',\n  12238 => '鼓',\n  12239 => '鼠',\n  12240 => '鼻',\n  12241 => '齊',\n  12242 => '齒',\n  12243 => '龍',\n  12244 => '龜',\n  12245 => '龠',\n  12290 => '.',\n  12342 => '〒',\n  12344 => '十',\n  12345 => '卄',\n  12346 => '卅',\n  12447 => 'より',\n  12543 => 'コト',\n  12593 => 'ᄀ',\n  12594 => 'ᄁ',\n  12595 => 'ᆪ',\n  12596 => 'ᄂ',\n  12597 => 'ᆬ',\n  12598 => 'ᆭ',\n  12599 => 'ᄃ',\n  12600 => 'ᄄ',\n  12601 => 'ᄅ',\n  12602 => 'ᆰ',\n  12603 => 'ᆱ',\n  12604 => 'ᆲ',\n  12605 => 'ᆳ',\n  12606 => 'ᆴ',\n  12607 => 'ᆵ',\n  12608 => 'ᄚ',\n  12609 => 'ᄆ',\n  12610 => 'ᄇ',\n  12611 => 'ᄈ',\n  12612 => 'ᄡ',\n  12613 => 'ᄉ',\n  12614 => 'ᄊ',\n  12615 => 'ᄋ',\n  12616 => 'ᄌ',\n  12617 => 'ᄍ',\n  12618 => 'ᄎ',\n  12619 => 'ᄏ',\n  12620 => 'ᄐ',\n  12621 => 'ᄑ',\n  12622 => 'ᄒ',\n  12623 => 'ᅡ',\n  12624 => 'ᅢ',\n  12625 => 'ᅣ',\n  12626 => 'ᅤ',\n  12627 => 'ᅥ',\n  12628 => 'ᅦ',\n  12629 => 'ᅧ',\n  12630 => 'ᅨ',\n  12631 => 'ᅩ',\n  12632 => 'ᅪ',\n  12633 => 'ᅫ',\n  12634 => 'ᅬ',\n  12635 => 'ᅭ',\n  12636 => 'ᅮ',\n  12637 => 'ᅯ',\n  12638 => 'ᅰ',\n  12639 => 'ᅱ',\n  12640 => 'ᅲ',\n  12641 => 'ᅳ',\n  12642 => 'ᅴ',\n  12643 => 'ᅵ',\n  12645 => 'ᄔ',\n  12646 => 'ᄕ',\n  12647 => 'ᇇ',\n  12648 => 'ᇈ',\n  12649 => 'ᇌ',\n  12650 => 'ᇎ',\n  12651 => 'ᇓ',\n  12652 => 'ᇗ',\n  12653 => 'ᇙ',\n  12654 => 'ᄜ',\n  12655 => 'ᇝ',\n  12656 => 'ᇟ',\n  12657 => 'ᄝ',\n  12658 => 'ᄞ',\n  12659 => 'ᄠ',\n  12660 => 'ᄢ',\n  12661 => 'ᄣ',\n  12662 => 'ᄧ',\n  12663 => 'ᄩ',\n  12664 => 'ᄫ',\n  12665 => 'ᄬ',\n  12666 => 'ᄭ',\n  12667 => 'ᄮ',\n  12668 => 'ᄯ',\n  12669 => 'ᄲ',\n  12670 => 'ᄶ',\n  12671 => 'ᅀ',\n  12672 => 'ᅇ',\n  12673 => 'ᅌ',\n  12674 => 'ᇱ',\n  12675 => 'ᇲ',\n  12676 => 'ᅗ',\n  12677 => 'ᅘ',\n  12678 => 'ᅙ',\n  12679 => 'ᆄ',\n  12680 => 'ᆅ',\n  12681 => 'ᆈ',\n  12682 => 'ᆑ',\n  12683 => 'ᆒ',\n  12684 => 'ᆔ',\n  12685 => 'ᆞ',\n  12686 => 'ᆡ',\n  12690 => '一',\n  12691 => '二',\n  12692 => '三',\n  12693 => '四',\n  12694 => '上',\n  12695 => '中',\n  12696 => '下',\n  12697 => '甲',\n  12698 => '乙',\n  12699 => '丙',\n  12700 => '丁',\n  12701 => '天',\n  12702 => '地',\n  12703 => '人',\n  12868 => '問',\n  12869 => '幼',\n  12870 => '文',\n  12871 => '箏',\n  12880 => 'pte',\n  12881 => '21',\n  12882 => '22',\n  12883 => '23',\n  12884 => '24',\n  12885 => '25',\n  12886 => '26',\n  12887 => '27',\n  12888 => '28',\n  12889 => '29',\n  12890 => '30',\n  12891 => '31',\n  12892 => '32',\n  12893 => '33',\n  12894 => '34',\n  12895 => '35',\n  12896 => 'ᄀ',\n  12897 => 'ᄂ',\n  12898 => 'ᄃ',\n  12899 => 'ᄅ',\n  12900 => 'ᄆ',\n  12901 => 'ᄇ',\n  12902 => 'ᄉ',\n  12903 => 'ᄋ',\n  12904 => 'ᄌ',\n  12905 => 'ᄎ',\n  12906 => 'ᄏ',\n  12907 => 'ᄐ',\n  12908 => 'ᄑ',\n  12909 => 'ᄒ',\n  12910 => '가',\n  12911 => '나',\n  12912 => '다',\n  12913 => '라',\n  12914 => '마',\n  12915 => '바',\n  12916 => '사',\n  12917 => '아',\n  12918 => '자',\n  12919 => '차',\n  12920 => '카',\n  12921 => '타',\n  12922 => '파',\n  12923 => '하',\n  12924 => '참고',\n  12925 => '주의',\n  12926 => '우',\n  12928 => '一',\n  12929 => '二',\n  12930 => '三',\n  12931 => '四',\n  12932 => '五',\n  12933 => '六',\n  12934 => '七',\n  12935 => '八',\n  12936 => '九',\n  12937 => '十',\n  12938 => '月',\n  12939 => '火',\n  12940 => '水',\n  12941 => '木',\n  12942 => '金',\n  12943 => '土',\n  12944 => '日',\n  12945 => '株',\n  12946 => '有',\n  12947 => '社',\n  12948 => '名',\n  12949 => '特',\n  12950 => '財',\n  12951 => '祝',\n  12952 => '労',\n  12953 => '秘',\n  12954 => '男',\n  12955 => '女',\n  12956 => '適',\n  12957 => '優',\n  12958 => '印',\n  12959 => '注',\n  12960 => '項',\n  12961 => '休',\n  12962 => '写',\n  12963 => '正',\n  12964 => '上',\n  12965 => '中',\n  12966 => '下',\n  12967 => '左',\n  12968 => '右',\n  12969 => '医',\n  12970 => '宗',\n  12971 => '学',\n  12972 => '監',\n  12973 => '企',\n  12974 => '資',\n  12975 => '協',\n  12976 => '夜',\n  12977 => '36',\n  12978 => '37',\n  12979 => '38',\n  12980 => '39',\n  12981 => '40',\n  12982 => '41',\n  12983 => '42',\n  12984 => '43',\n  12985 => '44',\n  12986 => '45',\n  12987 => '46',\n  12988 => '47',\n  12989 => '48',\n  12990 => '49',\n  12991 => '50',\n  12992 => '1月',\n  12993 => '2月',\n  12994 => '3月',\n  12995 => '4月',\n  12996 => '5月',\n  12997 => '6月',\n  12998 => '7月',\n  12999 => '8月',\n  13000 => '9月',\n  13001 => '10月',\n  13002 => '11月',\n  13003 => '12月',\n  13004 => 'hg',\n  13005 => 'erg',\n  13006 => 'ev',\n  13007 => 'ltd',\n  13008 => 'ア',\n  13009 => 'イ',\n  13010 => 'ウ',\n  13011 => 'エ',\n  13012 => 'オ',\n  13013 => 'カ',\n  13014 => 'キ',\n  13015 => 'ク',\n  13016 => 'ケ',\n  13017 => 'コ',\n  13018 => 'サ',\n  13019 => 'シ',\n  13020 => 'ス',\n  13021 => 'セ',\n  13022 => 'ソ',\n  13023 => 'タ',\n  13024 => 'チ',\n  13025 => 'ツ',\n  13026 => 'テ',\n  13027 => 'ト',\n  13028 => 'ナ',\n  13029 => 'ニ',\n  13030 => 'ヌ',\n  13031 => 'ネ',\n  13032 => 'ノ',\n  13033 => 'ハ',\n  13034 => 'ヒ',\n  13035 => 'フ',\n  13036 => 'ヘ',\n  13037 => 'ホ',\n  13038 => 'マ',\n  13039 => 'ミ',\n  13040 => 'ム',\n  13041 => 'メ',\n  13042 => 'モ',\n  13043 => 'ヤ',\n  13044 => 'ユ',\n  13045 => 'ヨ',\n  13046 => 'ラ',\n  13047 => 'リ',\n  13048 => 'ル',\n  13049 => 'レ',\n  13050 => 'ロ',\n  13051 => 'ワ',\n  13052 => 'ヰ',\n  13053 => 'ヱ',\n  13054 => 'ヲ',\n  13055 => '令和',\n  13056 => 'アパート',\n  13057 => 'アルファ',\n  13058 => 'アンペア',\n  13059 => 'アール',\n  13060 => 'イニング',\n  13061 => 'インチ',\n  13062 => 'ウォン',\n  13063 => 'エスクード',\n  13064 => 'エーカー',\n  13065 => 'オンス',\n  13066 => 'オーム',\n  13067 => 'カイリ',\n  13068 => 'カラット',\n  13069 => 'カロリー',\n  13070 => 'ガロン',\n  13071 => 'ガンマ',\n  13072 => 'ギガ',\n  13073 => 'ギニー',\n  13074 => 'キュリー',\n  13075 => 'ギルダー',\n  13076 => 'キロ',\n  13077 => 'キログラム',\n  13078 => 'キロメートル',\n  13079 => 'キロワット',\n  13080 => 'グラム',\n  13081 => 'グラムトン',\n  13082 => 'クルゼイロ',\n  13083 => 'クローネ',\n  13084 => 'ケース',\n  13085 => 'コルナ',\n  13086 => 'コーポ',\n  13087 => 'サイクル',\n  13088 => 'サンチーム',\n  13089 => 'シリング',\n  13090 => 'センチ',\n  13091 => 'セント',\n  13092 => 'ダース',\n  13093 => 'デシ',\n  13094 => 'ドル',\n  13095 => 'トン',\n  13096 => 'ナノ',\n  13097 => 'ノット',\n  13098 => 'ハイツ',\n  13099 => 'パーセント',\n  13100 => 'パーツ',\n  13101 => 'バーレル',\n  13102 => 'ピアストル',\n  13103 => 'ピクル',\n  13104 => 'ピコ',\n  13105 => 'ビル',\n  13106 => 'ファラッド',\n  13107 => 'フィート',\n  13108 => 'ブッシェル',\n  13109 => 'フラン',\n  13110 => 'ヘクタール',\n  13111 => 'ペソ',\n  13112 => 'ペニヒ',\n  13113 => 'ヘルツ',\n  13114 => 'ペンス',\n  13115 => 'ページ',\n  13116 => 'ベータ',\n  13117 => 'ポイント',\n  13118 => 'ボルト',\n  13119 => 'ホン',\n  13120 => 'ポンド',\n  13121 => 'ホール',\n  13122 => 'ホーン',\n  13123 => 'マイクロ',\n  13124 => 'マイル',\n  13125 => 'マッハ',\n  13126 => 'マルク',\n  13127 => 'マンション',\n  13128 => 'ミクロン',\n  13129 => 'ミリ',\n  13130 => 'ミリバール',\n  13131 => 'メガ',\n  13132 => 'メガトン',\n  13133 => 'メートル',\n  13134 => 'ヤード',\n  13135 => 'ヤール',\n  13136 => 'ユアン',\n  13137 => 'リットル',\n  13138 => 'リラ',\n  13139 => 'ルピー',\n  13140 => 'ルーブル',\n  13141 => 'レム',\n  13142 => 'レントゲン',\n  13143 => 'ワット',\n  13144 => '0点',\n  13145 => '1点',\n  13146 => '2点',\n  13147 => '3点',\n  13148 => '4点',\n  13149 => '5点',\n  13150 => '6点',\n  13151 => '7点',\n  13152 => '8点',\n  13153 => '9点',\n  13154 => '10点',\n  13155 => '11点',\n  13156 => '12点',\n  13157 => '13点',\n  13158 => '14点',\n  13159 => '15点',\n  13160 => '16点',\n  13161 => '17点',\n  13162 => '18点',\n  13163 => '19点',\n  13164 => '20点',\n  13165 => '21点',\n  13166 => '22点',\n  13167 => '23点',\n  13168 => '24点',\n  13169 => 'hpa',\n  13170 => 'da',\n  13171 => 'au',\n  13172 => 'bar',\n  13173 => 'ov',\n  13174 => 'pc',\n  13175 => 'dm',\n  13176 => 'dm2',\n  13177 => 'dm3',\n  13178 => 'iu',\n  13179 => '平成',\n  13180 => '昭和',\n  13181 => '大正',\n  13182 => '明治',\n  13183 => '株式会社',\n  13184 => 'pa',\n  13185 => 'na',\n  13186 => 'μa',\n  13187 => 'ma',\n  13188 => 'ka',\n  13189 => 'kb',\n  13190 => 'mb',\n  13191 => 'gb',\n  13192 => 'cal',\n  13193 => 'kcal',\n  13194 => 'pf',\n  13195 => 'nf',\n  13196 => 'μf',\n  13197 => 'μg',\n  13198 => 'mg',\n  13199 => 'kg',\n  13200 => 'hz',\n  13201 => 'khz',\n  13202 => 'mhz',\n  13203 => 'ghz',\n  13204 => 'thz',\n  13205 => 'μl',\n  13206 => 'ml',\n  13207 => 'dl',\n  13208 => 'kl',\n  13209 => 'fm',\n  13210 => 'nm',\n  13211 => 'μm',\n  13212 => 'mm',\n  13213 => 'cm',\n  13214 => 'km',\n  13215 => 'mm2',\n  13216 => 'cm2',\n  13217 => 'm2',\n  13218 => 'km2',\n  13219 => 'mm3',\n  13220 => 'cm3',\n  13221 => 'm3',\n  13222 => 'km3',\n  13223 => 'm∕s',\n  13224 => 'm∕s2',\n  13225 => 'pa',\n  13226 => 'kpa',\n  13227 => 'mpa',\n  13228 => 'gpa',\n  13229 => 'rad',\n  13230 => 'rad∕s',\n  13231 => 'rad∕s2',\n  13232 => 'ps',\n  13233 => 'ns',\n  13234 => 'μs',\n  13235 => 'ms',\n  13236 => 'pv',\n  13237 => 'nv',\n  13238 => 'μv',\n  13239 => 'mv',\n  13240 => 'kv',\n  13241 => 'mv',\n  13242 => 'pw',\n  13243 => 'nw',\n  13244 => 'μw',\n  13245 => 'mw',\n  13246 => 'kw',\n  13247 => 'mw',\n  13248 => 'kω',\n  13249 => 'mω',\n  13251 => 'bq',\n  13252 => 'cc',\n  13253 => 'cd',\n  13254 => 'c∕kg',\n  13256 => 'db',\n  13257 => 'gy',\n  13258 => 'ha',\n  13259 => 'hp',\n  13260 => 'in',\n  13261 => 'kk',\n  13262 => 'km',\n  13263 => 'kt',\n  13264 => 'lm',\n  13265 => 'ln',\n  13266 => 'log',\n  13267 => 'lx',\n  13268 => 'mb',\n  13269 => 'mil',\n  13270 => 'mol',\n  13271 => 'ph',\n  13273 => 'ppm',\n  13274 => 'pr',\n  13275 => 'sr',\n  13276 => 'sv',\n  13277 => 'wb',\n  13278 => 'v∕m',\n  13279 => 'a∕m',\n  13280 => '1日',\n  13281 => '2日',\n  13282 => '3日',\n  13283 => '4日',\n  13284 => '5日',\n  13285 => '6日',\n  13286 => '7日',\n  13287 => '8日',\n  13288 => '9日',\n  13289 => '10日',\n  13290 => '11日',\n  13291 => '12日',\n  13292 => '13日',\n  13293 => '14日',\n  13294 => '15日',\n  13295 => '16日',\n  13296 => '17日',\n  13297 => '18日',\n  13298 => '19日',\n  13299 => '20日',\n  13300 => '21日',\n  13301 => '22日',\n  13302 => '23日',\n  13303 => '24日',\n  13304 => '25日',\n  13305 => '26日',\n  13306 => '27日',\n  13307 => '28日',\n  13308 => '29日',\n  13309 => '30日',\n  13310 => '31日',\n  13311 => 'gal',\n  42560 => 'ꙁ',\n  42562 => 'ꙃ',\n  42564 => 'ꙅ',\n  42566 => 'ꙇ',\n  42568 => 'ꙉ',\n  42570 => 'ꙋ',\n  42572 => 'ꙍ',\n  42574 => 'ꙏ',\n  42576 => 'ꙑ',\n  42578 => 'ꙓ',\n  42580 => 'ꙕ',\n  42582 => 'ꙗ',\n  42584 => 'ꙙ',\n  42586 => 'ꙛ',\n  42588 => 'ꙝ',\n  42590 => 'ꙟ',\n  42592 => 'ꙡ',\n  42594 => 'ꙣ',\n  42596 => 'ꙥ',\n  42598 => 'ꙧ',\n  42600 => 'ꙩ',\n  42602 => 'ꙫ',\n  42604 => 'ꙭ',\n  42624 => 'ꚁ',\n  42626 => 'ꚃ',\n  42628 => 'ꚅ',\n  42630 => 'ꚇ',\n  42632 => 'ꚉ',\n  42634 => 'ꚋ',\n  42636 => 'ꚍ',\n  42638 => 'ꚏ',\n  42640 => 'ꚑ',\n  42642 => 'ꚓ',\n  42644 => 'ꚕ',\n  42646 => 'ꚗ',\n  42648 => 'ꚙ',\n  42650 => 'ꚛ',\n  42652 => 'ъ',\n  42653 => 'ь',\n  42786 => 'ꜣ',\n  42788 => 'ꜥ',\n  42790 => 'ꜧ',\n  42792 => 'ꜩ',\n  42794 => 'ꜫ',\n  42796 => 'ꜭ',\n  42798 => 'ꜯ',\n  42802 => 'ꜳ',\n  42804 => 'ꜵ',\n  42806 => 'ꜷ',\n  42808 => 'ꜹ',\n  42810 => 'ꜻ',\n  42812 => 'ꜽ',\n  42814 => 'ꜿ',\n  42816 => 'ꝁ',\n  42818 => 'ꝃ',\n  42820 => 'ꝅ',\n  42822 => 'ꝇ',\n  42824 => 'ꝉ',\n  42826 => 'ꝋ',\n  42828 => 'ꝍ',\n  42830 => 'ꝏ',\n  42832 => 'ꝑ',\n  42834 => 'ꝓ',\n  42836 => 'ꝕ',\n  42838 => 'ꝗ',\n  42840 => 'ꝙ',\n  42842 => 'ꝛ',\n  42844 => 'ꝝ',\n  42846 => 'ꝟ',\n  42848 => 'ꝡ',\n  42850 => 'ꝣ',\n  42852 => 'ꝥ',\n  42854 => 'ꝧ',\n  42856 => 'ꝩ',\n  42858 => 'ꝫ',\n  42860 => 'ꝭ',\n  42862 => 'ꝯ',\n  42864 => 'ꝯ',\n  42873 => 'ꝺ',\n  42875 => 'ꝼ',\n  42877 => 'ᵹ',\n  42878 => 'ꝿ',\n  42880 => 'ꞁ',\n  42882 => 'ꞃ',\n  42884 => 'ꞅ',\n  42886 => 'ꞇ',\n  42891 => 'ꞌ',\n  42893 => 'ɥ',\n  42896 => 'ꞑ',\n  42898 => 'ꞓ',\n  42902 => 'ꞗ',\n  42904 => 'ꞙ',\n  42906 => 'ꞛ',\n  42908 => 'ꞝ',\n  42910 => 'ꞟ',\n  42912 => 'ꞡ',\n  42914 => 'ꞣ',\n  42916 => 'ꞥ',\n  42918 => 'ꞧ',\n  42920 => 'ꞩ',\n  42922 => 'ɦ',\n  42923 => 'ɜ',\n  42924 => 'ɡ',\n  42925 => 'ɬ',\n  42926 => 'ɪ',\n  42928 => 'ʞ',\n  42929 => 'ʇ',\n  42930 => 'ʝ',\n  42931 => 'ꭓ',\n  42932 => 'ꞵ',\n  42934 => 'ꞷ',\n  42936 => 'ꞹ',\n  42938 => 'ꞻ',\n  42940 => 'ꞽ',\n  42942 => 'ꞿ',\n  42946 => 'ꟃ',\n  42948 => 'ꞔ',\n  42949 => 'ʂ',\n  42950 => 'ᶎ',\n  42951 => 'ꟈ',\n  42953 => 'ꟊ',\n  42997 => 'ꟶ',\n  43000 => 'ħ',\n  43001 => 'œ',\n  43868 => 'ꜧ',\n  43869 => 'ꬷ',\n  43870 => 'ɫ',\n  43871 => 'ꭒ',\n  43881 => 'ʍ',\n  43888 => 'Ꭰ',\n  43889 => 'Ꭱ',\n  43890 => 'Ꭲ',\n  43891 => 'Ꭳ',\n  43892 => 'Ꭴ',\n  43893 => 'Ꭵ',\n  43894 => 'Ꭶ',\n  43895 => 'Ꭷ',\n  43896 => 'Ꭸ',\n  43897 => 'Ꭹ',\n  43898 => 'Ꭺ',\n  43899 => 'Ꭻ',\n  43900 => 'Ꭼ',\n  43901 => 'Ꭽ',\n  43902 => 'Ꭾ',\n  43903 => 'Ꭿ',\n  43904 => 'Ꮀ',\n  43905 => 'Ꮁ',\n  43906 => 'Ꮂ',\n  43907 => 'Ꮃ',\n  43908 => 'Ꮄ',\n  43909 => 'Ꮅ',\n  43910 => 'Ꮆ',\n  43911 => 'Ꮇ',\n  43912 => 'Ꮈ',\n  43913 => 'Ꮉ',\n  43914 => 'Ꮊ',\n  43915 => 'Ꮋ',\n  43916 => 'Ꮌ',\n  43917 => 'Ꮍ',\n  43918 => 'Ꮎ',\n  43919 => 'Ꮏ',\n  43920 => 'Ꮐ',\n  43921 => 'Ꮑ',\n  43922 => 'Ꮒ',\n  43923 => 'Ꮓ',\n  43924 => 'Ꮔ',\n  43925 => 'Ꮕ',\n  43926 => 'Ꮖ',\n  43927 => 'Ꮗ',\n  43928 => 'Ꮘ',\n  43929 => 'Ꮙ',\n  43930 => 'Ꮚ',\n  43931 => 'Ꮛ',\n  43932 => 'Ꮜ',\n  43933 => 'Ꮝ',\n  43934 => 'Ꮞ',\n  43935 => 'Ꮟ',\n  43936 => 'Ꮠ',\n  43937 => 'Ꮡ',\n  43938 => 'Ꮢ',\n  43939 => 'Ꮣ',\n  43940 => 'Ꮤ',\n  43941 => 'Ꮥ',\n  43942 => 'Ꮦ',\n  43943 => 'Ꮧ',\n  43944 => 'Ꮨ',\n  43945 => 'Ꮩ',\n  43946 => 'Ꮪ',\n  43947 => 'Ꮫ',\n  43948 => 'Ꮬ',\n  43949 => 'Ꮭ',\n  43950 => 'Ꮮ',\n  43951 => 'Ꮯ',\n  43952 => 'Ꮰ',\n  43953 => 'Ꮱ',\n  43954 => 'Ꮲ',\n  43955 => 'Ꮳ',\n  43956 => 'Ꮴ',\n  43957 => 'Ꮵ',\n  43958 => 'Ꮶ',\n  43959 => 'Ꮷ',\n  43960 => 'Ꮸ',\n  43961 => 'Ꮹ',\n  43962 => 'Ꮺ',\n  43963 => 'Ꮻ',\n  43964 => 'Ꮼ',\n  43965 => 'Ꮽ',\n  43966 => 'Ꮾ',\n  43967 => 'Ꮿ',\n  63744 => '豈',\n  63745 => '更',\n  63746 => '車',\n  63747 => '賈',\n  63748 => '滑',\n  63749 => '串',\n  63750 => '句',\n  63751 => '龜',\n  63752 => '龜',\n  63753 => '契',\n  63754 => '金',\n  63755 => '喇',\n  63756 => '奈',\n  63757 => '懶',\n  63758 => '癩',\n  63759 => '羅',\n  63760 => '蘿',\n  63761 => '螺',\n  63762 => '裸',\n  63763 => '邏',\n  63764 => '樂',\n  63765 => '洛',\n  63766 => '烙',\n  63767 => '珞',\n  63768 => '落',\n  63769 => '酪',\n  63770 => '駱',\n  63771 => '亂',\n  63772 => '卵',\n  63773 => '欄',\n  63774 => '爛',\n  63775 => '蘭',\n  63776 => '鸞',\n  63777 => '嵐',\n  63778 => '濫',\n  63779 => '藍',\n  63780 => '襤',\n  63781 => '拉',\n  63782 => '臘',\n  63783 => '蠟',\n  63784 => '廊',\n  63785 => '朗',\n  63786 => '浪',\n  63787 => '狼',\n  63788 => '郎',\n  63789 => '來',\n  63790 => '冷',\n  63791 => '勞',\n  63792 => '擄',\n  63793 => '櫓',\n  63794 => '爐',\n  63795 => '盧',\n  63796 => '老',\n  63797 => '蘆',\n  63798 => '虜',\n  63799 => '路',\n  63800 => '露',\n  63801 => '魯',\n  63802 => '鷺',\n  63803 => '碌',\n  63804 => '祿',\n  63805 => '綠',\n  63806 => '菉',\n  63807 => '錄',\n  63808 => '鹿',\n  63809 => '論',\n  63810 => '壟',\n  63811 => '弄',\n  63812 => '籠',\n  63813 => '聾',\n  63814 => '牢',\n  63815 => '磊',\n  63816 => '賂',\n  63817 => '雷',\n  63818 => '壘',\n  63819 => '屢',\n  63820 => '樓',\n  63821 => '淚',\n  63822 => '漏',\n  63823 => '累',\n  63824 => '縷',\n  63825 => '陋',\n  63826 => '勒',\n  63827 => '肋',\n  63828 => '凜',\n  63829 => '凌',\n  63830 => '稜',\n  63831 => '綾',\n  63832 => '菱',\n  63833 => '陵',\n  63834 => '讀',\n  63835 => '拏',\n  63836 => '樂',\n  63837 => '諾',\n  63838 => '丹',\n  63839 => '寧',\n  63840 => '怒',\n  63841 => '率',\n  63842 => '異',\n  63843 => '北',\n  63844 => '磻',\n  63845 => '便',\n  63846 => '復',\n  63847 => '不',\n  63848 => '泌',\n  63849 => '數',\n  63850 => '索',\n  63851 => '參',\n  63852 => '塞',\n  63853 => '省',\n  63854 => '葉',\n  63855 => '說',\n  63856 => '殺',\n  63857 => '辰',\n  63858 => '沈',\n  63859 => '拾',\n  63860 => '若',\n  63861 => '掠',\n  63862 => '略',\n  63863 => '亮',\n  63864 => '兩',\n  63865 => '凉',\n  63866 => '梁',\n  63867 => '糧',\n  63868 => '良',\n  63869 => '諒',\n  63870 => '量',\n  63871 => '勵',\n  63872 => '呂',\n  63873 => '女',\n  63874 => '廬',\n  63875 => '旅',\n  63876 => '濾',\n  63877 => '礪',\n  63878 => '閭',\n  63879 => '驪',\n  63880 => '麗',\n  63881 => '黎',\n  63882 => '力',\n  63883 => '曆',\n  63884 => '歷',\n  63885 => '轢',\n  63886 => '年',\n  63887 => '憐',\n  63888 => '戀',\n  63889 => '撚',\n  63890 => '漣',\n  63891 => '煉',\n  63892 => '璉',\n  63893 => '秊',\n  63894 => '練',\n  63895 => '聯',\n  63896 => '輦',\n  63897 => '蓮',\n  63898 => '連',\n  63899 => '鍊',\n  63900 => '列',\n  63901 => '劣',\n  63902 => '咽',\n  63903 => '烈',\n  63904 => '裂',\n  63905 => '說',\n  63906 => '廉',\n  63907 => '念',\n  63908 => '捻',\n  63909 => '殮',\n  63910 => '簾',\n  63911 => '獵',\n  63912 => '令',\n  63913 => '囹',\n  63914 => '寧',\n  63915 => '嶺',\n  63916 => '怜',\n  63917 => '玲',\n  63918 => '瑩',\n  63919 => '羚',\n  63920 => '聆',\n  63921 => '鈴',\n  63922 => '零',\n  63923 => '靈',\n  63924 => '領',\n  63925 => '例',\n  63926 => '禮',\n  63927 => '醴',\n  63928 => '隸',\n  63929 => '惡',\n  63930 => '了',\n  63931 => '僚',\n  63932 => '寮',\n  63933 => '尿',\n  63934 => '料',\n  63935 => '樂',\n  63936 => '燎',\n  63937 => '療',\n  63938 => '蓼',\n  63939 => '遼',\n  63940 => '龍',\n  63941 => '暈',\n  63942 => '阮',\n  63943 => '劉',\n  63944 => '杻',\n  63945 => '柳',\n  63946 => '流',\n  63947 => '溜',\n  63948 => '琉',\n  63949 => '留',\n  63950 => '硫',\n  63951 => '紐',\n  63952 => '類',\n  63953 => '六',\n  63954 => '戮',\n  63955 => '陸',\n  63956 => '倫',\n  63957 => '崙',\n  63958 => '淪',\n  63959 => '輪',\n  63960 => '律',\n  63961 => '慄',\n  63962 => '栗',\n  63963 => '率',\n  63964 => '隆',\n  63965 => '利',\n  63966 => '吏',\n  63967 => '履',\n  63968 => '易',\n  63969 => '李',\n  63970 => '梨',\n  63971 => '泥',\n  63972 => '理',\n  63973 => '痢',\n  63974 => '罹',\n  63975 => '裏',\n  63976 => '裡',\n  63977 => '里',\n  63978 => '離',\n  63979 => '匿',\n  63980 => '溺',\n  63981 => '吝',\n  63982 => '燐',\n  63983 => '璘',\n  63984 => '藺',\n  63985 => '隣',\n  63986 => '鱗',\n  63987 => '麟',\n  63988 => '林',\n  63989 => '淋',\n  63990 => '臨',\n  63991 => '立',\n  63992 => '笠',\n  63993 => '粒',\n  63994 => '狀',\n  63995 => '炙',\n  63996 => '識',\n  63997 => '什',\n  63998 => '茶',\n  63999 => '刺',\n  64000 => '切',\n  64001 => '度',\n  64002 => '拓',\n  64003 => '糖',\n  64004 => '宅',\n  64005 => '洞',\n  64006 => '暴',\n  64007 => '輻',\n  64008 => '行',\n  64009 => '降',\n  64010 => '見',\n  64011 => '廓',\n  64012 => '兀',\n  64013 => '嗀',\n  64016 => '塚',\n  64018 => '晴',\n  64021 => '凞',\n  64022 => '猪',\n  64023 => '益',\n  64024 => '礼',\n  64025 => '神',\n  64026 => '祥',\n  64027 => '福',\n  64028 => '靖',\n  64029 => '精',\n  64030 => '羽',\n  64032 => '蘒',\n  64034 => '諸',\n  64037 => '逸',\n  64038 => '都',\n  64042 => '飯',\n  64043 => '飼',\n  64044 => '館',\n  64045 => '鶴',\n  64046 => '郞',\n  64047 => '隷',\n  64048 => '侮',\n  64049 => '僧',\n  64050 => '免',\n  64051 => '勉',\n  64052 => '勤',\n  64053 => '卑',\n  64054 => '喝',\n  64055 => '嘆',\n  64056 => '器',\n  64057 => '塀',\n  64058 => '墨',\n  64059 => '層',\n  64060 => '屮',\n  64061 => '悔',\n  64062 => '慨',\n  64063 => '憎',\n  64064 => '懲',\n  64065 => '敏',\n  64066 => '既',\n  64067 => '暑',\n  64068 => '梅',\n  64069 => '海',\n  64070 => '渚',\n  64071 => '漢',\n  64072 => '煮',\n  64073 => '爫',\n  64074 => '琢',\n  64075 => '碑',\n  64076 => '社',\n  64077 => '祉',\n  64078 => '祈',\n  64079 => '祐',\n  64080 => '祖',\n  64081 => '祝',\n  64082 => '禍',\n  64083 => '禎',\n  64084 => '穀',\n  64085 => '突',\n  64086 => '節',\n  64087 => '練',\n  64088 => '縉',\n  64089 => '繁',\n  64090 => '署',\n  64091 => '者',\n  64092 => '臭',\n  64093 => '艹',\n  64094 => '艹',\n  64095 => '著',\n  64096 => '褐',\n  64097 => '視',\n  64098 => '謁',\n  64099 => '謹',\n  64100 => '賓',\n  64101 => '贈',\n  64102 => '辶',\n  64103 => '逸',\n  64104 => '難',\n  64105 => '響',\n  64106 => '頻',\n  64107 => '恵',\n  64108 => '𤋮',\n  64109 => '舘',\n  64112 => '並',\n  64113 => '况',\n  64114 => '全',\n  64115 => '侀',\n  64116 => '充',\n  64117 => '冀',\n  64118 => '勇',\n  64119 => '勺',\n  64120 => '喝',\n  64121 => '啕',\n  64122 => '喙',\n  64123 => '嗢',\n  64124 => '塚',\n  64125 => '墳',\n  64126 => '奄',\n  64127 => '奔',\n  64128 => '婢',\n  64129 => '嬨',\n  64130 => '廒',\n  64131 => '廙',\n  64132 => '彩',\n  64133 => '徭',\n  64134 => '惘',\n  64135 => '慎',\n  64136 => '愈',\n  64137 => '憎',\n  64138 => '慠',\n  64139 => '懲',\n  64140 => '戴',\n  64141 => '揄',\n  64142 => '搜',\n  64143 => '摒',\n  64144 => '敖',\n  64145 => '晴',\n  64146 => '朗',\n  64147 => '望',\n  64148 => '杖',\n  64149 => '歹',\n  64150 => '殺',\n  64151 => '流',\n  64152 => '滛',\n  64153 => '滋',\n  64154 => '漢',\n  64155 => '瀞',\n  64156 => '煮',\n  64157 => '瞧',\n  64158 => '爵',\n  64159 => '犯',\n  64160 => '猪',\n  64161 => '瑱',\n  64162 => '甆',\n  64163 => '画',\n  64164 => '瘝',\n  64165 => '瘟',\n  64166 => '益',\n  64167 => '盛',\n  64168 => '直',\n  64169 => '睊',\n  64170 => '着',\n  64171 => '磌',\n  64172 => '窱',\n  64173 => '節',\n  64174 => '类',\n  64175 => '絛',\n  64176 => '練',\n  64177 => '缾',\n  64178 => '者',\n  64179 => '荒',\n  64180 => '華',\n  64181 => '蝹',\n  64182 => '襁',\n  64183 => '覆',\n  64184 => '視',\n  64185 => '調',\n  64186 => '諸',\n  64187 => '請',\n  64188 => '謁',\n  64189 => '諾',\n  64190 => '諭',\n  64191 => '謹',\n  64192 => '變',\n  64193 => '贈',\n  64194 => '輸',\n  64195 => '遲',\n  64196 => '醙',\n  64197 => '鉶',\n  64198 => '陼',\n  64199 => '難',\n  64200 => '靖',\n  64201 => '韛',\n  64202 => '響',\n  64203 => '頋',\n  64204 => '頻',\n  64205 => '鬒',\n  64206 => '龜',\n  64207 => '𢡊',\n  64208 => '𢡄',\n  64209 => '𣏕',\n  64210 => '㮝',\n  64211 => '䀘',\n  64212 => '䀹',\n  64213 => '𥉉',\n  64214 => '𥳐',\n  64215 => '𧻓',\n  64216 => '齃',\n  64217 => '龎',\n  64256 => 'ff',\n  64257 => 'fi',\n  64258 => 'fl',\n  64259 => 'ffi',\n  64260 => 'ffl',\n  64261 => 'st',\n  64262 => 'st',\n  64275 => 'մն',\n  64276 => 'մե',\n  64277 => 'մի',\n  64278 => 'վն',\n  64279 => 'մխ',\n  64285 => 'יִ',\n  64287 => 'ײַ',\n  64288 => 'ע',\n  64289 => 'א',\n  64290 => 'ד',\n  64291 => 'ה',\n  64292 => 'כ',\n  64293 => 'ל',\n  64294 => 'ם',\n  64295 => 'ר',\n  64296 => 'ת',\n  64298 => 'שׁ',\n  64299 => 'שׂ',\n  64300 => 'שּׁ',\n  64301 => 'שּׂ',\n  64302 => 'אַ',\n  64303 => 'אָ',\n  64304 => 'אּ',\n  64305 => 'בּ',\n  64306 => 'גּ',\n  64307 => 'דּ',\n  64308 => 'הּ',\n  64309 => 'וּ',\n  64310 => 'זּ',\n  64312 => 'טּ',\n  64313 => 'יּ',\n  64314 => 'ךּ',\n  64315 => 'כּ',\n  64316 => 'לּ',\n  64318 => 'מּ',\n  64320 => 'נּ',\n  64321 => 'סּ',\n  64323 => 'ףּ',\n  64324 => 'פּ',\n  64326 => 'צּ',\n  64327 => 'קּ',\n  64328 => 'רּ',\n  64329 => 'שּ',\n  64330 => 'תּ',\n  64331 => 'וֹ',\n  64332 => 'בֿ',\n  64333 => 'כֿ',\n  64334 => 'פֿ',\n  64335 => 'אל',\n  64336 => 'ٱ',\n  64337 => 'ٱ',\n  64338 => 'ٻ',\n  64339 => 'ٻ',\n  64340 => 'ٻ',\n  64341 => 'ٻ',\n  64342 => 'پ',\n  64343 => 'پ',\n  64344 => 'پ',\n  64345 => 'پ',\n  64346 => 'ڀ',\n  64347 => 'ڀ',\n  64348 => 'ڀ',\n  64349 => 'ڀ',\n  64350 => 'ٺ',\n  64351 => 'ٺ',\n  64352 => 'ٺ',\n  64353 => 'ٺ',\n  64354 => 'ٿ',\n  64355 => 'ٿ',\n  64356 => 'ٿ',\n  64357 => 'ٿ',\n  64358 => 'ٹ',\n  64359 => 'ٹ',\n  64360 => 'ٹ',\n  64361 => 'ٹ',\n  64362 => 'ڤ',\n  64363 => 'ڤ',\n  64364 => 'ڤ',\n  64365 => 'ڤ',\n  64366 => 'ڦ',\n  64367 => 'ڦ',\n  64368 => 'ڦ',\n  64369 => 'ڦ',\n  64370 => 'ڄ',\n  64371 => 'ڄ',\n  64372 => 'ڄ',\n  64373 => 'ڄ',\n  64374 => 'ڃ',\n  64375 => 'ڃ',\n  64376 => 'ڃ',\n  64377 => 'ڃ',\n  64378 => 'چ',\n  64379 => 'چ',\n  64380 => 'چ',\n  64381 => 'چ',\n  64382 => 'ڇ',\n  64383 => 'ڇ',\n  64384 => 'ڇ',\n  64385 => 'ڇ',\n  64386 => 'ڍ',\n  64387 => 'ڍ',\n  64388 => 'ڌ',\n  64389 => 'ڌ',\n  64390 => 'ڎ',\n  64391 => 'ڎ',\n  64392 => 'ڈ',\n  64393 => 'ڈ',\n  64394 => 'ژ',\n  64395 => 'ژ',\n  64396 => 'ڑ',\n  64397 => 'ڑ',\n  64398 => 'ک',\n  64399 => 'ک',\n  64400 => 'ک',\n  64401 => 'ک',\n  64402 => 'گ',\n  64403 => 'گ',\n  64404 => 'گ',\n  64405 => 'گ',\n  64406 => 'ڳ',\n  64407 => 'ڳ',\n  64408 => 'ڳ',\n  64409 => 'ڳ',\n  64410 => 'ڱ',\n  64411 => 'ڱ',\n  64412 => 'ڱ',\n  64413 => 'ڱ',\n  64414 => 'ں',\n  64415 => 'ں',\n  64416 => 'ڻ',\n  64417 => 'ڻ',\n  64418 => 'ڻ',\n  64419 => 'ڻ',\n  64420 => 'ۀ',\n  64421 => 'ۀ',\n  64422 => 'ہ',\n  64423 => 'ہ',\n  64424 => 'ہ',\n  64425 => 'ہ',\n  64426 => 'ھ',\n  64427 => 'ھ',\n  64428 => 'ھ',\n  64429 => 'ھ',\n  64430 => 'ے',\n  64431 => 'ے',\n  64432 => 'ۓ',\n  64433 => 'ۓ',\n  64467 => 'ڭ',\n  64468 => 'ڭ',\n  64469 => 'ڭ',\n  64470 => 'ڭ',\n  64471 => 'ۇ',\n  64472 => 'ۇ',\n  64473 => 'ۆ',\n  64474 => 'ۆ',\n  64475 => 'ۈ',\n  64476 => 'ۈ',\n  64477 => 'ۇٴ',\n  64478 => 'ۋ',\n  64479 => 'ۋ',\n  64480 => 'ۅ',\n  64481 => 'ۅ',\n  64482 => 'ۉ',\n  64483 => 'ۉ',\n  64484 => 'ې',\n  64485 => 'ې',\n  64486 => 'ې',\n  64487 => 'ې',\n  64488 => 'ى',\n  64489 => 'ى',\n  64490 => 'ئا',\n  64491 => 'ئا',\n  64492 => 'ئە',\n  64493 => 'ئە',\n  64494 => 'ئو',\n  64495 => 'ئو',\n  64496 => 'ئۇ',\n  64497 => 'ئۇ',\n  64498 => 'ئۆ',\n  64499 => 'ئۆ',\n  64500 => 'ئۈ',\n  64501 => 'ئۈ',\n  64502 => 'ئې',\n  64503 => 'ئې',\n  64504 => 'ئې',\n  64505 => 'ئى',\n  64506 => 'ئى',\n  64507 => 'ئى',\n  64508 => 'ی',\n  64509 => 'ی',\n  64510 => 'ی',\n  64511 => 'ی',\n  64512 => 'ئج',\n  64513 => 'ئح',\n  64514 => 'ئم',\n  64515 => 'ئى',\n  64516 => 'ئي',\n  64517 => 'بج',\n  64518 => 'بح',\n  64519 => 'بخ',\n  64520 => 'بم',\n  64521 => 'بى',\n  64522 => 'بي',\n  64523 => 'تج',\n  64524 => 'تح',\n  64525 => 'تخ',\n  64526 => 'تم',\n  64527 => 'تى',\n  64528 => 'تي',\n  64529 => 'ثج',\n  64530 => 'ثم',\n  64531 => 'ثى',\n  64532 => 'ثي',\n  64533 => 'جح',\n  64534 => 'جم',\n  64535 => 'حج',\n  64536 => 'حم',\n  64537 => 'خج',\n  64538 => 'خح',\n  64539 => 'خم',\n  64540 => 'سج',\n  64541 => 'سح',\n  64542 => 'سخ',\n  64543 => 'سم',\n  64544 => 'صح',\n  64545 => 'صم',\n  64546 => 'ضج',\n  64547 => 'ضح',\n  64548 => 'ضخ',\n  64549 => 'ضم',\n  64550 => 'طح',\n  64551 => 'طم',\n  64552 => 'ظم',\n  64553 => 'عج',\n  64554 => 'عم',\n  64555 => 'غج',\n  64556 => 'غم',\n  64557 => 'فج',\n  64558 => 'فح',\n  64559 => 'فخ',\n  64560 => 'فم',\n  64561 => 'فى',\n  64562 => 'في',\n  64563 => 'قح',\n  64564 => 'قم',\n  64565 => 'قى',\n  64566 => 'قي',\n  64567 => 'كا',\n  64568 => 'كج',\n  64569 => 'كح',\n  64570 => 'كخ',\n  64571 => 'كل',\n  64572 => 'كم',\n  64573 => 'كى',\n  64574 => 'كي',\n  64575 => 'لج',\n  64576 => 'لح',\n  64577 => 'لخ',\n  64578 => 'لم',\n  64579 => 'لى',\n  64580 => 'لي',\n  64581 => 'مج',\n  64582 => 'مح',\n  64583 => 'مخ',\n  64584 => 'مم',\n  64585 => 'مى',\n  64586 => 'مي',\n  64587 => 'نج',\n  64588 => 'نح',\n  64589 => 'نخ',\n  64590 => 'نم',\n  64591 => 'نى',\n  64592 => 'ني',\n  64593 => 'هج',\n  64594 => 'هم',\n  64595 => 'هى',\n  64596 => 'هي',\n  64597 => 'يج',\n  64598 => 'يح',\n  64599 => 'يخ',\n  64600 => 'يم',\n  64601 => 'يى',\n  64602 => 'يي',\n  64603 => 'ذٰ',\n  64604 => 'رٰ',\n  64605 => 'ىٰ',\n  64612 => 'ئر',\n  64613 => 'ئز',\n  64614 => 'ئم',\n  64615 => 'ئن',\n  64616 => 'ئى',\n  64617 => 'ئي',\n  64618 => 'بر',\n  64619 => 'بز',\n  64620 => 'بم',\n  64621 => 'بن',\n  64622 => 'بى',\n  64623 => 'بي',\n  64624 => 'تر',\n  64625 => 'تز',\n  64626 => 'تم',\n  64627 => 'تن',\n  64628 => 'تى',\n  64629 => 'تي',\n  64630 => 'ثر',\n  64631 => 'ثز',\n  64632 => 'ثم',\n  64633 => 'ثن',\n  64634 => 'ثى',\n  64635 => 'ثي',\n  64636 => 'فى',\n  64637 => 'في',\n  64638 => 'قى',\n  64639 => 'قي',\n  64640 => 'كا',\n  64641 => 'كل',\n  64642 => 'كم',\n  64643 => 'كى',\n  64644 => 'كي',\n  64645 => 'لم',\n  64646 => 'لى',\n  64647 => 'لي',\n  64648 => 'ما',\n  64649 => 'مم',\n  64650 => 'نر',\n  64651 => 'نز',\n  64652 => 'نم',\n  64653 => 'نن',\n  64654 => 'نى',\n  64655 => 'ني',\n  64656 => 'ىٰ',\n  64657 => 'ير',\n  64658 => 'يز',\n  64659 => 'يم',\n  64660 => 'ين',\n  64661 => 'يى',\n  64662 => 'يي',\n  64663 => 'ئج',\n  64664 => 'ئح',\n  64665 => 'ئخ',\n  64666 => 'ئم',\n  64667 => 'ئه',\n  64668 => 'بج',\n  64669 => 'بح',\n  64670 => 'بخ',\n  64671 => 'بم',\n  64672 => 'به',\n  64673 => 'تج',\n  64674 => 'تح',\n  64675 => 'تخ',\n  64676 => 'تم',\n  64677 => 'ته',\n  64678 => 'ثم',\n  64679 => 'جح',\n  64680 => 'جم',\n  64681 => 'حج',\n  64682 => 'حم',\n  64683 => 'خج',\n  64684 => 'خم',\n  64685 => 'سج',\n  64686 => 'سح',\n  64687 => 'سخ',\n  64688 => 'سم',\n  64689 => 'صح',\n  64690 => 'صخ',\n  64691 => 'صم',\n  64692 => 'ضج',\n  64693 => 'ضح',\n  64694 => 'ضخ',\n  64695 => 'ضم',\n  64696 => 'طح',\n  64697 => 'ظم',\n  64698 => 'عج',\n  64699 => 'عم',\n  64700 => 'غج',\n  64701 => 'غم',\n  64702 => 'فج',\n  64703 => 'فح',\n  64704 => 'فخ',\n  64705 => 'فم',\n  64706 => 'قح',\n  64707 => 'قم',\n  64708 => 'كج',\n  64709 => 'كح',\n  64710 => 'كخ',\n  64711 => 'كل',\n  64712 => 'كم',\n  64713 => 'لج',\n  64714 => 'لح',\n  64715 => 'لخ',\n  64716 => 'لم',\n  64717 => 'له',\n  64718 => 'مج',\n  64719 => 'مح',\n  64720 => 'مخ',\n  64721 => 'مم',\n  64722 => 'نج',\n  64723 => 'نح',\n  64724 => 'نخ',\n  64725 => 'نم',\n  64726 => 'نه',\n  64727 => 'هج',\n  64728 => 'هم',\n  64729 => 'هٰ',\n  64730 => 'يج',\n  64731 => 'يح',\n  64732 => 'يخ',\n  64733 => 'يم',\n  64734 => 'يه',\n  64735 => 'ئم',\n  64736 => 'ئه',\n  64737 => 'بم',\n  64738 => 'به',\n  64739 => 'تم',\n  64740 => 'ته',\n  64741 => 'ثم',\n  64742 => 'ثه',\n  64743 => 'سم',\n  64744 => 'سه',\n  64745 => 'شم',\n  64746 => 'شه',\n  64747 => 'كل',\n  64748 => 'كم',\n  64749 => 'لم',\n  64750 => 'نم',\n  64751 => 'نه',\n  64752 => 'يم',\n  64753 => 'يه',\n  64754 => 'ـَّ',\n  64755 => 'ـُّ',\n  64756 => 'ـِّ',\n  64757 => 'طى',\n  64758 => 'طي',\n  64759 => 'عى',\n  64760 => 'عي',\n  64761 => 'غى',\n  64762 => 'غي',\n  64763 => 'سى',\n  64764 => 'سي',\n  64765 => 'شى',\n  64766 => 'شي',\n  64767 => 'حى',\n  64768 => 'حي',\n  64769 => 'جى',\n  64770 => 'جي',\n  64771 => 'خى',\n  64772 => 'خي',\n  64773 => 'صى',\n  64774 => 'صي',\n  64775 => 'ضى',\n  64776 => 'ضي',\n  64777 => 'شج',\n  64778 => 'شح',\n  64779 => 'شخ',\n  64780 => 'شم',\n  64781 => 'شر',\n  64782 => 'سر',\n  64783 => 'صر',\n  64784 => 'ضر',\n  64785 => 'طى',\n  64786 => 'طي',\n  64787 => 'عى',\n  64788 => 'عي',\n  64789 => 'غى',\n  64790 => 'غي',\n  64791 => 'سى',\n  64792 => 'سي',\n  64793 => 'شى',\n  64794 => 'شي',\n  64795 => 'حى',\n  64796 => 'حي',\n  64797 => 'جى',\n  64798 => 'جي',\n  64799 => 'خى',\n  64800 => 'خي',\n  64801 => 'صى',\n  64802 => 'صي',\n  64803 => 'ضى',\n  64804 => 'ضي',\n  64805 => 'شج',\n  64806 => 'شح',\n  64807 => 'شخ',\n  64808 => 'شم',\n  64809 => 'شر',\n  64810 => 'سر',\n  64811 => 'صر',\n  64812 => 'ضر',\n  64813 => 'شج',\n  64814 => 'شح',\n  64815 => 'شخ',\n  64816 => 'شم',\n  64817 => 'سه',\n  64818 => 'شه',\n  64819 => 'طم',\n  64820 => 'سج',\n  64821 => 'سح',\n  64822 => 'سخ',\n  64823 => 'شج',\n  64824 => 'شح',\n  64825 => 'شخ',\n  64826 => 'طم',\n  64827 => 'ظم',\n  64828 => 'اً',\n  64829 => 'اً',\n  64848 => 'تجم',\n  64849 => 'تحج',\n  64850 => 'تحج',\n  64851 => 'تحم',\n  64852 => 'تخم',\n  64853 => 'تمج',\n  64854 => 'تمح',\n  64855 => 'تمخ',\n  64856 => 'جمح',\n  64857 => 'جمح',\n  64858 => 'حمي',\n  64859 => 'حمى',\n  64860 => 'سحج',\n  64861 => 'سجح',\n  64862 => 'سجى',\n  64863 => 'سمح',\n  64864 => 'سمح',\n  64865 => 'سمج',\n  64866 => 'سمم',\n  64867 => 'سمم',\n  64868 => 'صحح',\n  64869 => 'صحح',\n  64870 => 'صمم',\n  64871 => 'شحم',\n  64872 => 'شحم',\n  64873 => 'شجي',\n  64874 => 'شمخ',\n  64875 => 'شمخ',\n  64876 => 'شمم',\n  64877 => 'شمم',\n  64878 => 'ضحى',\n  64879 => 'ضخم',\n  64880 => 'ضخم',\n  64881 => 'طمح',\n  64882 => 'طمح',\n  64883 => 'طمم',\n  64884 => 'طمي',\n  64885 => 'عجم',\n  64886 => 'عمم',\n  64887 => 'عمم',\n  64888 => 'عمى',\n  64889 => 'غمم',\n  64890 => 'غمي',\n  64891 => 'غمى',\n  64892 => 'فخم',\n  64893 => 'فخم',\n  64894 => 'قمح',\n  64895 => 'قمم',\n  64896 => 'لحم',\n  64897 => 'لحي',\n  64898 => 'لحى',\n  64899 => 'لجج',\n  64900 => 'لجج',\n  64901 => 'لخم',\n  64902 => 'لخم',\n  64903 => 'لمح',\n  64904 => 'لمح',\n  64905 => 'محج',\n  64906 => 'محم',\n  64907 => 'محي',\n  64908 => 'مجح',\n  64909 => 'مجم',\n  64910 => 'مخج',\n  64911 => 'مخم',\n  64914 => 'مجخ',\n  64915 => 'همج',\n  64916 => 'همم',\n  64917 => 'نحم',\n  64918 => 'نحى',\n  64919 => 'نجم',\n  64920 => 'نجم',\n  64921 => 'نجى',\n  64922 => 'نمي',\n  64923 => 'نمى',\n  64924 => 'يمم',\n  64925 => 'يمم',\n  64926 => 'بخي',\n  64927 => 'تجي',\n  64928 => 'تجى',\n  64929 => 'تخي',\n  64930 => 'تخى',\n  64931 => 'تمي',\n  64932 => 'تمى',\n  64933 => 'جمي',\n  64934 => 'جحى',\n  64935 => 'جمى',\n  64936 => 'سخى',\n  64937 => 'صحي',\n  64938 => 'شحي',\n  64939 => 'ضحي',\n  64940 => 'لجي',\n  64941 => 'لمي',\n  64942 => 'يحي',\n  64943 => 'يجي',\n  64944 => 'يمي',\n  64945 => 'ممي',\n  64946 => 'قمي',\n  64947 => 'نحي',\n  64948 => 'قمح',\n  64949 => 'لحم',\n  64950 => 'عمي',\n  64951 => 'كمي',\n  64952 => 'نجح',\n  64953 => 'مخي',\n  64954 => 'لجم',\n  64955 => 'كمم',\n  64956 => 'لجم',\n  64957 => 'نجح',\n  64958 => 'جحي',\n  64959 => 'حجي',\n  64960 => 'مجي',\n  64961 => 'فمي',\n  64962 => 'بحي',\n  64963 => 'كمم',\n  64964 => 'عجم',\n  64965 => 'صمم',\n  64966 => 'سخي',\n  64967 => 'نجي',\n  65008 => 'صلے',\n  65009 => 'قلے',\n  65010 => 'الله',\n  65011 => 'اكبر',\n  65012 => 'محمد',\n  65013 => 'صلعم',\n  65014 => 'رسول',\n  65015 => 'عليه',\n  65016 => 'وسلم',\n  65017 => 'صلى',\n  65020 => 'ریال',\n  65041 => '、',\n  65047 => '〖',\n  65048 => '〗',\n  65073 => '—',\n  65074 => '–',\n  65081 => '〔',\n  65082 => '〕',\n  65083 => '【',\n  65084 => '】',\n  65085 => '《',\n  65086 => '》',\n  65087 => '〈',\n  65088 => '〉',\n  65089 => '「',\n  65090 => '」',\n  65091 => '『',\n  65092 => '』',\n  65105 => '、',\n  65112 => '—',\n  65117 => '〔',\n  65118 => '〕',\n  65123 => '-',\n  65137 => 'ـً',\n  65143 => 'ـَ',\n  65145 => 'ـُ',\n  65147 => 'ـِ',\n  65149 => 'ـّ',\n  65151 => 'ـْ',\n  65152 => 'ء',\n  65153 => 'آ',\n  65154 => 'آ',\n  65155 => 'أ',\n  65156 => 'أ',\n  65157 => 'ؤ',\n  65158 => 'ؤ',\n  65159 => 'إ',\n  65160 => 'إ',\n  65161 => 'ئ',\n  65162 => 'ئ',\n  65163 => 'ئ',\n  65164 => 'ئ',\n  65165 => 'ا',\n  65166 => 'ا',\n  65167 => 'ب',\n  65168 => 'ب',\n  65169 => 'ب',\n  65170 => 'ب',\n  65171 => 'ة',\n  65172 => 'ة',\n  65173 => 'ت',\n  65174 => 'ت',\n  65175 => 'ت',\n  65176 => 'ت',\n  65177 => 'ث',\n  65178 => 'ث',\n  65179 => 'ث',\n  65180 => 'ث',\n  65181 => 'ج',\n  65182 => 'ج',\n  65183 => 'ج',\n  65184 => 'ج',\n  65185 => 'ح',\n  65186 => 'ح',\n  65187 => 'ح',\n  65188 => 'ح',\n  65189 => 'خ',\n  65190 => 'خ',\n  65191 => 'خ',\n  65192 => 'خ',\n  65193 => 'د',\n  65194 => 'د',\n  65195 => 'ذ',\n  65196 => 'ذ',\n  65197 => 'ر',\n  65198 => 'ر',\n  65199 => 'ز',\n  65200 => 'ز',\n  65201 => 'س',\n  65202 => 'س',\n  65203 => 'س',\n  65204 => 'س',\n  65205 => 'ش',\n  65206 => 'ش',\n  65207 => 'ش',\n  65208 => 'ش',\n  65209 => 'ص',\n  65210 => 'ص',\n  65211 => 'ص',\n  65212 => 'ص',\n  65213 => 'ض',\n  65214 => 'ض',\n  65215 => 'ض',\n  65216 => 'ض',\n  65217 => 'ط',\n  65218 => 'ط',\n  65219 => 'ط',\n  65220 => 'ط',\n  65221 => 'ظ',\n  65222 => 'ظ',\n  65223 => 'ظ',\n  65224 => 'ظ',\n  65225 => 'ع',\n  65226 => 'ع',\n  65227 => 'ع',\n  65228 => 'ع',\n  65229 => 'غ',\n  65230 => 'غ',\n  65231 => 'غ',\n  65232 => 'غ',\n  65233 => 'ف',\n  65234 => 'ف',\n  65235 => 'ف',\n  65236 => 'ف',\n  65237 => 'ق',\n  65238 => 'ق',\n  65239 => 'ق',\n  65240 => 'ق',\n  65241 => 'ك',\n  65242 => 'ك',\n  65243 => 'ك',\n  65244 => 'ك',\n  65245 => 'ل',\n  65246 => 'ل',\n  65247 => 'ل',\n  65248 => 'ل',\n  65249 => 'م',\n  65250 => 'م',\n  65251 => 'م',\n  65252 => 'م',\n  65253 => 'ن',\n  65254 => 'ن',\n  65255 => 'ن',\n  65256 => 'ن',\n  65257 => 'ه',\n  65258 => 'ه',\n  65259 => 'ه',\n  65260 => 'ه',\n  65261 => 'و',\n  65262 => 'و',\n  65263 => 'ى',\n  65264 => 'ى',\n  65265 => 'ي',\n  65266 => 'ي',\n  65267 => 'ي',\n  65268 => 'ي',\n  65269 => 'لآ',\n  65270 => 'لآ',\n  65271 => 'لأ',\n  65272 => 'لأ',\n  65273 => 'لإ',\n  65274 => 'لإ',\n  65275 => 'لا',\n  65276 => 'لا',\n  65293 => '-',\n  65294 => '.',\n  65296 => '0',\n  65297 => '1',\n  65298 => '2',\n  65299 => '3',\n  65300 => '4',\n  65301 => '5',\n  65302 => '6',\n  65303 => '7',\n  65304 => '8',\n  65305 => '9',\n  65313 => 'a',\n  65314 => 'b',\n  65315 => 'c',\n  65316 => 'd',\n  65317 => 'e',\n  65318 => 'f',\n  65319 => 'g',\n  65320 => 'h',\n  65321 => 'i',\n  65322 => 'j',\n  65323 => 'k',\n  65324 => 'l',\n  65325 => 'm',\n  65326 => 'n',\n  65327 => 'o',\n  65328 => 'p',\n  65329 => 'q',\n  65330 => 'r',\n  65331 => 's',\n  65332 => 't',\n  65333 => 'u',\n  65334 => 'v',\n  65335 => 'w',\n  65336 => 'x',\n  65337 => 'y',\n  65338 => 'z',\n  65345 => 'a',\n  65346 => 'b',\n  65347 => 'c',\n  65348 => 'd',\n  65349 => 'e',\n  65350 => 'f',\n  65351 => 'g',\n  65352 => 'h',\n  65353 => 'i',\n  65354 => 'j',\n  65355 => 'k',\n  65356 => 'l',\n  65357 => 'm',\n  65358 => 'n',\n  65359 => 'o',\n  65360 => 'p',\n  65361 => 'q',\n  65362 => 'r',\n  65363 => 's',\n  65364 => 't',\n  65365 => 'u',\n  65366 => 'v',\n  65367 => 'w',\n  65368 => 'x',\n  65369 => 'y',\n  65370 => 'z',\n  65375 => '⦅',\n  65376 => '⦆',\n  65377 => '.',\n  65378 => '「',\n  65379 => '」',\n  65380 => '、',\n  65381 => '・',\n  65382 => 'ヲ',\n  65383 => 'ァ',\n  65384 => 'ィ',\n  65385 => 'ゥ',\n  65386 => 'ェ',\n  65387 => 'ォ',\n  65388 => 'ャ',\n  65389 => 'ュ',\n  65390 => 'ョ',\n  65391 => 'ッ',\n  65392 => 'ー',\n  65393 => 'ア',\n  65394 => 'イ',\n  65395 => 'ウ',\n  65396 => 'エ',\n  65397 => 'オ',\n  65398 => 'カ',\n  65399 => 'キ',\n  65400 => 'ク',\n  65401 => 'ケ',\n  65402 => 'コ',\n  65403 => 'サ',\n  65404 => 'シ',\n  65405 => 'ス',\n  65406 => 'セ',\n  65407 => 'ソ',\n  65408 => 'タ',\n  65409 => 'チ',\n  65410 => 'ツ',\n  65411 => 'テ',\n  65412 => 'ト',\n  65413 => 'ナ',\n  65414 => 'ニ',\n  65415 => 'ヌ',\n  65416 => 'ネ',\n  65417 => 'ノ',\n  65418 => 'ハ',\n  65419 => 'ヒ',\n  65420 => 'フ',\n  65421 => 'ヘ',\n  65422 => 'ホ',\n  65423 => 'マ',\n  65424 => 'ミ',\n  65425 => 'ム',\n  65426 => 'メ',\n  65427 => 'モ',\n  65428 => 'ヤ',\n  65429 => 'ユ',\n  65430 => 'ヨ',\n  65431 => 'ラ',\n  65432 => 'リ',\n  65433 => 'ル',\n  65434 => 'レ',\n  65435 => 'ロ',\n  65436 => 'ワ',\n  65437 => 'ン',\n  65438 => '゙',\n  65439 => '゚',\n  65441 => 'ᄀ',\n  65442 => 'ᄁ',\n  65443 => 'ᆪ',\n  65444 => 'ᄂ',\n  65445 => 'ᆬ',\n  65446 => 'ᆭ',\n  65447 => 'ᄃ',\n  65448 => 'ᄄ',\n  65449 => 'ᄅ',\n  65450 => 'ᆰ',\n  65451 => 'ᆱ',\n  65452 => 'ᆲ',\n  65453 => 'ᆳ',\n  65454 => 'ᆴ',\n  65455 => 'ᆵ',\n  65456 => 'ᄚ',\n  65457 => 'ᄆ',\n  65458 => 'ᄇ',\n  65459 => 'ᄈ',\n  65460 => 'ᄡ',\n  65461 => 'ᄉ',\n  65462 => 'ᄊ',\n  65463 => 'ᄋ',\n  65464 => 'ᄌ',\n  65465 => 'ᄍ',\n  65466 => 'ᄎ',\n  65467 => 'ᄏ',\n  65468 => 'ᄐ',\n  65469 => 'ᄑ',\n  65470 => 'ᄒ',\n  65474 => 'ᅡ',\n  65475 => 'ᅢ',\n  65476 => 'ᅣ',\n  65477 => 'ᅤ',\n  65478 => 'ᅥ',\n  65479 => 'ᅦ',\n  65482 => 'ᅧ',\n  65483 => 'ᅨ',\n  65484 => 'ᅩ',\n  65485 => 'ᅪ',\n  65486 => 'ᅫ',\n  65487 => 'ᅬ',\n  65490 => 'ᅭ',\n  65491 => 'ᅮ',\n  65492 => 'ᅯ',\n  65493 => 'ᅰ',\n  65494 => 'ᅱ',\n  65495 => 'ᅲ',\n  65498 => 'ᅳ',\n  65499 => 'ᅴ',\n  65500 => 'ᅵ',\n  65504 => '¢',\n  65505 => '£',\n  65506 => '¬',\n  65508 => '¦',\n  65509 => '¥',\n  65510 => '₩',\n  65512 => '│',\n  65513 => '←',\n  65514 => '↑',\n  65515 => '→',\n  65516 => '↓',\n  65517 => '■',\n  65518 => '○',\n  66560 => '𐐨',\n  66561 => '𐐩',\n  66562 => '𐐪',\n  66563 => '𐐫',\n  66564 => '𐐬',\n  66565 => '𐐭',\n  66566 => '𐐮',\n  66567 => '𐐯',\n  66568 => '𐐰',\n  66569 => '𐐱',\n  66570 => '𐐲',\n  66571 => '𐐳',\n  66572 => '𐐴',\n  66573 => '𐐵',\n  66574 => '𐐶',\n  66575 => '𐐷',\n  66576 => '𐐸',\n  66577 => '𐐹',\n  66578 => '𐐺',\n  66579 => '𐐻',\n  66580 => '𐐼',\n  66581 => '𐐽',\n  66582 => '𐐾',\n  66583 => '𐐿',\n  66584 => '𐑀',\n  66585 => '𐑁',\n  66586 => '𐑂',\n  66587 => '𐑃',\n  66588 => '𐑄',\n  66589 => '𐑅',\n  66590 => '𐑆',\n  66591 => '𐑇',\n  66592 => '𐑈',\n  66593 => '𐑉',\n  66594 => '𐑊',\n  66595 => '𐑋',\n  66596 => '𐑌',\n  66597 => '𐑍',\n  66598 => '𐑎',\n  66599 => '𐑏',\n  66736 => '𐓘',\n  66737 => '𐓙',\n  66738 => '𐓚',\n  66739 => '𐓛',\n  66740 => '𐓜',\n  66741 => '𐓝',\n  66742 => '𐓞',\n  66743 => '𐓟',\n  66744 => '𐓠',\n  66745 => '𐓡',\n  66746 => '𐓢',\n  66747 => '𐓣',\n  66748 => '𐓤',\n  66749 => '𐓥',\n  66750 => '𐓦',\n  66751 => '𐓧',\n  66752 => '𐓨',\n  66753 => '𐓩',\n  66754 => '𐓪',\n  66755 => '𐓫',\n  66756 => '𐓬',\n  66757 => '𐓭',\n  66758 => '𐓮',\n  66759 => '𐓯',\n  66760 => '𐓰',\n  66761 => '𐓱',\n  66762 => '𐓲',\n  66763 => '𐓳',\n  66764 => '𐓴',\n  66765 => '𐓵',\n  66766 => '𐓶',\n  66767 => '𐓷',\n  66768 => '𐓸',\n  66769 => '𐓹',\n  66770 => '𐓺',\n  66771 => '𐓻',\n  68736 => '𐳀',\n  68737 => '𐳁',\n  68738 => '𐳂',\n  68739 => '𐳃',\n  68740 => '𐳄',\n  68741 => '𐳅',\n  68742 => '𐳆',\n  68743 => '𐳇',\n  68744 => '𐳈',\n  68745 => '𐳉',\n  68746 => '𐳊',\n  68747 => '𐳋',\n  68748 => '𐳌',\n  68749 => '𐳍',\n  68750 => '𐳎',\n  68751 => '𐳏',\n  68752 => '𐳐',\n  68753 => '𐳑',\n  68754 => '𐳒',\n  68755 => '𐳓',\n  68756 => '𐳔',\n  68757 => '𐳕',\n  68758 => '𐳖',\n  68759 => '𐳗',\n  68760 => '𐳘',\n  68761 => '𐳙',\n  68762 => '𐳚',\n  68763 => '𐳛',\n  68764 => '𐳜',\n  68765 => '𐳝',\n  68766 => '𐳞',\n  68767 => '𐳟',\n  68768 => '𐳠',\n  68769 => '𐳡',\n  68770 => '𐳢',\n  68771 => '𐳣',\n  68772 => '𐳤',\n  68773 => '𐳥',\n  68774 => '𐳦',\n  68775 => '𐳧',\n  68776 => '𐳨',\n  68777 => '𐳩',\n  68778 => '𐳪',\n  68779 => '𐳫',\n  68780 => '𐳬',\n  68781 => '𐳭',\n  68782 => '𐳮',\n  68783 => '𐳯',\n  68784 => '𐳰',\n  68785 => '𐳱',\n  68786 => '𐳲',\n  71840 => '𑣀',\n  71841 => '𑣁',\n  71842 => '𑣂',\n  71843 => '𑣃',\n  71844 => '𑣄',\n  71845 => '𑣅',\n  71846 => '𑣆',\n  71847 => '𑣇',\n  71848 => '𑣈',\n  71849 => '𑣉',\n  71850 => '𑣊',\n  71851 => '𑣋',\n  71852 => '𑣌',\n  71853 => '𑣍',\n  71854 => '𑣎',\n  71855 => '𑣏',\n  71856 => '𑣐',\n  71857 => '𑣑',\n  71858 => '𑣒',\n  71859 => '𑣓',\n  71860 => '𑣔',\n  71861 => '𑣕',\n  71862 => '𑣖',\n  71863 => '𑣗',\n  71864 => '𑣘',\n  71865 => '𑣙',\n  71866 => '𑣚',\n  71867 => '𑣛',\n  71868 => '𑣜',\n  71869 => '𑣝',\n  71870 => '𑣞',\n  71871 => '𑣟',\n  93760 => '𖹠',\n  93761 => '𖹡',\n  93762 => '𖹢',\n  93763 => '𖹣',\n  93764 => '𖹤',\n  93765 => '𖹥',\n  93766 => '𖹦',\n  93767 => '𖹧',\n  93768 => '𖹨',\n  93769 => '𖹩',\n  93770 => '𖹪',\n  93771 => '𖹫',\n  93772 => '𖹬',\n  93773 => '𖹭',\n  93774 => '𖹮',\n  93775 => '𖹯',\n  93776 => '𖹰',\n  93777 => '𖹱',\n  93778 => '𖹲',\n  93779 => '𖹳',\n  93780 => '𖹴',\n  93781 => '𖹵',\n  93782 => '𖹶',\n  93783 => '𖹷',\n  93784 => '𖹸',\n  93785 => '𖹹',\n  93786 => '𖹺',\n  93787 => '𖹻',\n  93788 => '𖹼',\n  93789 => '𖹽',\n  93790 => '𖹾',\n  93791 => '𖹿',\n  119134 => '𝅗𝅥',\n  119135 => '𝅘𝅥',\n  119136 => '𝅘𝅥𝅮',\n  119137 => '𝅘𝅥𝅯',\n  119138 => '𝅘𝅥𝅰',\n  119139 => '𝅘𝅥𝅱',\n  119140 => '𝅘𝅥𝅲',\n  119227 => '𝆹𝅥',\n  119228 => '𝆺𝅥',\n  119229 => '𝆹𝅥𝅮',\n  119230 => '𝆺𝅥𝅮',\n  119231 => '𝆹𝅥𝅯',\n  119232 => '𝆺𝅥𝅯',\n  119808 => 'a',\n  119809 => 'b',\n  119810 => 'c',\n  119811 => 'd',\n  119812 => 'e',\n  119813 => 'f',\n  119814 => 'g',\n  119815 => 'h',\n  119816 => 'i',\n  119817 => 'j',\n  119818 => 'k',\n  119819 => 'l',\n  119820 => 'm',\n  119821 => 'n',\n  119822 => 'o',\n  119823 => 'p',\n  119824 => 'q',\n  119825 => 'r',\n  119826 => 's',\n  119827 => 't',\n  119828 => 'u',\n  119829 => 'v',\n  119830 => 'w',\n  119831 => 'x',\n  119832 => 'y',\n  119833 => 'z',\n  119834 => 'a',\n  119835 => 'b',\n  119836 => 'c',\n  119837 => 'd',\n  119838 => 'e',\n  119839 => 'f',\n  119840 => 'g',\n  119841 => 'h',\n  119842 => 'i',\n  119843 => 'j',\n  119844 => 'k',\n  119845 => 'l',\n  119846 => 'm',\n  119847 => 'n',\n  119848 => 'o',\n  119849 => 'p',\n  119850 => 'q',\n  119851 => 'r',\n  119852 => 's',\n  119853 => 't',\n  119854 => 'u',\n  119855 => 'v',\n  119856 => 'w',\n  119857 => 'x',\n  119858 => 'y',\n  119859 => 'z',\n  119860 => 'a',\n  119861 => 'b',\n  119862 => 'c',\n  119863 => 'd',\n  119864 => 'e',\n  119865 => 'f',\n  119866 => 'g',\n  119867 => 'h',\n  119868 => 'i',\n  119869 => 'j',\n  119870 => 'k',\n  119871 => 'l',\n  119872 => 'm',\n  119873 => 'n',\n  119874 => 'o',\n  119875 => 'p',\n  119876 => 'q',\n  119877 => 'r',\n  119878 => 's',\n  119879 => 't',\n  119880 => 'u',\n  119881 => 'v',\n  119882 => 'w',\n  119883 => 'x',\n  119884 => 'y',\n  119885 => 'z',\n  119886 => 'a',\n  119887 => 'b',\n  119888 => 'c',\n  119889 => 'd',\n  119890 => 'e',\n  119891 => 'f',\n  119892 => 'g',\n  119894 => 'i',\n  119895 => 'j',\n  119896 => 'k',\n  119897 => 'l',\n  119898 => 'm',\n  119899 => 'n',\n  119900 => 'o',\n  119901 => 'p',\n  119902 => 'q',\n  119903 => 'r',\n  119904 => 's',\n  119905 => 't',\n  119906 => 'u',\n  119907 => 'v',\n  119908 => 'w',\n  119909 => 'x',\n  119910 => 'y',\n  119911 => 'z',\n  119912 => 'a',\n  119913 => 'b',\n  119914 => 'c',\n  119915 => 'd',\n  119916 => 'e',\n  119917 => 'f',\n  119918 => 'g',\n  119919 => 'h',\n  119920 => 'i',\n  119921 => 'j',\n  119922 => 'k',\n  119923 => 'l',\n  119924 => 'm',\n  119925 => 'n',\n  119926 => 'o',\n  119927 => 'p',\n  119928 => 'q',\n  119929 => 'r',\n  119930 => 's',\n  119931 => 't',\n  119932 => 'u',\n  119933 => 'v',\n  119934 => 'w',\n  119935 => 'x',\n  119936 => 'y',\n  119937 => 'z',\n  119938 => 'a',\n  119939 => 'b',\n  119940 => 'c',\n  119941 => 'd',\n  119942 => 'e',\n  119943 => 'f',\n  119944 => 'g',\n  119945 => 'h',\n  119946 => 'i',\n  119947 => 'j',\n  119948 => 'k',\n  119949 => 'l',\n  119950 => 'm',\n  119951 => 'n',\n  119952 => 'o',\n  119953 => 'p',\n  119954 => 'q',\n  119955 => 'r',\n  119956 => 's',\n  119957 => 't',\n  119958 => 'u',\n  119959 => 'v',\n  119960 => 'w',\n  119961 => 'x',\n  119962 => 'y',\n  119963 => 'z',\n  119964 => 'a',\n  119966 => 'c',\n  119967 => 'd',\n  119970 => 'g',\n  119973 => 'j',\n  119974 => 'k',\n  119977 => 'n',\n  119978 => 'o',\n  119979 => 'p',\n  119980 => 'q',\n  119982 => 's',\n  119983 => 't',\n  119984 => 'u',\n  119985 => 'v',\n  119986 => 'w',\n  119987 => 'x',\n  119988 => 'y',\n  119989 => 'z',\n  119990 => 'a',\n  119991 => 'b',\n  119992 => 'c',\n  119993 => 'd',\n  119995 => 'f',\n  119997 => 'h',\n  119998 => 'i',\n  119999 => 'j',\n  120000 => 'k',\n  120001 => 'l',\n  120002 => 'm',\n  120003 => 'n',\n  120005 => 'p',\n  120006 => 'q',\n  120007 => 'r',\n  120008 => 's',\n  120009 => 't',\n  120010 => 'u',\n  120011 => 'v',\n  120012 => 'w',\n  120013 => 'x',\n  120014 => 'y',\n  120015 => 'z',\n  120016 => 'a',\n  120017 => 'b',\n  120018 => 'c',\n  120019 => 'd',\n  120020 => 'e',\n  120021 => 'f',\n  120022 => 'g',\n  120023 => 'h',\n  120024 => 'i',\n  120025 => 'j',\n  120026 => 'k',\n  120027 => 'l',\n  120028 => 'm',\n  120029 => 'n',\n  120030 => 'o',\n  120031 => 'p',\n  120032 => 'q',\n  120033 => 'r',\n  120034 => 's',\n  120035 => 't',\n  120036 => 'u',\n  120037 => 'v',\n  120038 => 'w',\n  120039 => 'x',\n  120040 => 'y',\n  120041 => 'z',\n  120042 => 'a',\n  120043 => 'b',\n  120044 => 'c',\n  120045 => 'd',\n  120046 => 'e',\n  120047 => 'f',\n  120048 => 'g',\n  120049 => 'h',\n  120050 => 'i',\n  120051 => 'j',\n  120052 => 'k',\n  120053 => 'l',\n  120054 => 'm',\n  120055 => 'n',\n  120056 => 'o',\n  120057 => 'p',\n  120058 => 'q',\n  120059 => 'r',\n  120060 => 's',\n  120061 => 't',\n  120062 => 'u',\n  120063 => 'v',\n  120064 => 'w',\n  120065 => 'x',\n  120066 => 'y',\n  120067 => 'z',\n  120068 => 'a',\n  120069 => 'b',\n  120071 => 'd',\n  120072 => 'e',\n  120073 => 'f',\n  120074 => 'g',\n  120077 => 'j',\n  120078 => 'k',\n  120079 => 'l',\n  120080 => 'm',\n  120081 => 'n',\n  120082 => 'o',\n  120083 => 'p',\n  120084 => 'q',\n  120086 => 's',\n  120087 => 't',\n  120088 => 'u',\n  120089 => 'v',\n  120090 => 'w',\n  120091 => 'x',\n  120092 => 'y',\n  120094 => 'a',\n  120095 => 'b',\n  120096 => 'c',\n  120097 => 'd',\n  120098 => 'e',\n  120099 => 'f',\n  120100 => 'g',\n  120101 => 'h',\n  120102 => 'i',\n  120103 => 'j',\n  120104 => 'k',\n  120105 => 'l',\n  120106 => 'm',\n  120107 => 'n',\n  120108 => 'o',\n  120109 => 'p',\n  120110 => 'q',\n  120111 => 'r',\n  120112 => 's',\n  120113 => 't',\n  120114 => 'u',\n  120115 => 'v',\n  120116 => 'w',\n  120117 => 'x',\n  120118 => 'y',\n  120119 => 'z',\n  120120 => 'a',\n  120121 => 'b',\n  120123 => 'd',\n  120124 => 'e',\n  120125 => 'f',\n  120126 => 'g',\n  120128 => 'i',\n  120129 => 'j',\n  120130 => 'k',\n  120131 => 'l',\n  120132 => 'm',\n  120134 => 'o',\n  120138 => 's',\n  120139 => 't',\n  120140 => 'u',\n  120141 => 'v',\n  120142 => 'w',\n  120143 => 'x',\n  120144 => 'y',\n  120146 => 'a',\n  120147 => 'b',\n  120148 => 'c',\n  120149 => 'd',\n  120150 => 'e',\n  120151 => 'f',\n  120152 => 'g',\n  120153 => 'h',\n  120154 => 'i',\n  120155 => 'j',\n  120156 => 'k',\n  120157 => 'l',\n  120158 => 'm',\n  120159 => 'n',\n  120160 => 'o',\n  120161 => 'p',\n  120162 => 'q',\n  120163 => 'r',\n  120164 => 's',\n  120165 => 't',\n  120166 => 'u',\n  120167 => 'v',\n  120168 => 'w',\n  120169 => 'x',\n  120170 => 'y',\n  120171 => 'z',\n  120172 => 'a',\n  120173 => 'b',\n  120174 => 'c',\n  120175 => 'd',\n  120176 => 'e',\n  120177 => 'f',\n  120178 => 'g',\n  120179 => 'h',\n  120180 => 'i',\n  120181 => 'j',\n  120182 => 'k',\n  120183 => 'l',\n  120184 => 'm',\n  120185 => 'n',\n  120186 => 'o',\n  120187 => 'p',\n  120188 => 'q',\n  120189 => 'r',\n  120190 => 's',\n  120191 => 't',\n  120192 => 'u',\n  120193 => 'v',\n  120194 => 'w',\n  120195 => 'x',\n  120196 => 'y',\n  120197 => 'z',\n  120198 => 'a',\n  120199 => 'b',\n  120200 => 'c',\n  120201 => 'd',\n  120202 => 'e',\n  120203 => 'f',\n  120204 => 'g',\n  120205 => 'h',\n  120206 => 'i',\n  120207 => 'j',\n  120208 => 'k',\n  120209 => 'l',\n  120210 => 'm',\n  120211 => 'n',\n  120212 => 'o',\n  120213 => 'p',\n  120214 => 'q',\n  120215 => 'r',\n  120216 => 's',\n  120217 => 't',\n  120218 => 'u',\n  120219 => 'v',\n  120220 => 'w',\n  120221 => 'x',\n  120222 => 'y',\n  120223 => 'z',\n  120224 => 'a',\n  120225 => 'b',\n  120226 => 'c',\n  120227 => 'd',\n  120228 => 'e',\n  120229 => 'f',\n  120230 => 'g',\n  120231 => 'h',\n  120232 => 'i',\n  120233 => 'j',\n  120234 => 'k',\n  120235 => 'l',\n  120236 => 'm',\n  120237 => 'n',\n  120238 => 'o',\n  120239 => 'p',\n  120240 => 'q',\n  120241 => 'r',\n  120242 => 's',\n  120243 => 't',\n  120244 => 'u',\n  120245 => 'v',\n  120246 => 'w',\n  120247 => 'x',\n  120248 => 'y',\n  120249 => 'z',\n  120250 => 'a',\n  120251 => 'b',\n  120252 => 'c',\n  120253 => 'd',\n  120254 => 'e',\n  120255 => 'f',\n  120256 => 'g',\n  120257 => 'h',\n  120258 => 'i',\n  120259 => 'j',\n  120260 => 'k',\n  120261 => 'l',\n  120262 => 'm',\n  120263 => 'n',\n  120264 => 'o',\n  120265 => 'p',\n  120266 => 'q',\n  120267 => 'r',\n  120268 => 's',\n  120269 => 't',\n  120270 => 'u',\n  120271 => 'v',\n  120272 => 'w',\n  120273 => 'x',\n  120274 => 'y',\n  120275 => 'z',\n  120276 => 'a',\n  120277 => 'b',\n  120278 => 'c',\n  120279 => 'd',\n  120280 => 'e',\n  120281 => 'f',\n  120282 => 'g',\n  120283 => 'h',\n  120284 => 'i',\n  120285 => 'j',\n  120286 => 'k',\n  120287 => 'l',\n  120288 => 'm',\n  120289 => 'n',\n  120290 => 'o',\n  120291 => 'p',\n  120292 => 'q',\n  120293 => 'r',\n  120294 => 's',\n  120295 => 't',\n  120296 => 'u',\n  120297 => 'v',\n  120298 => 'w',\n  120299 => 'x',\n  120300 => 'y',\n  120301 => 'z',\n  120302 => 'a',\n  120303 => 'b',\n  120304 => 'c',\n  120305 => 'd',\n  120306 => 'e',\n  120307 => 'f',\n  120308 => 'g',\n  120309 => 'h',\n  120310 => 'i',\n  120311 => 'j',\n  120312 => 'k',\n  120313 => 'l',\n  120314 => 'm',\n  120315 => 'n',\n  120316 => 'o',\n  120317 => 'p',\n  120318 => 'q',\n  120319 => 'r',\n  120320 => 's',\n  120321 => 't',\n  120322 => 'u',\n  120323 => 'v',\n  120324 => 'w',\n  120325 => 'x',\n  120326 => 'y',\n  120327 => 'z',\n  120328 => 'a',\n  120329 => 'b',\n  120330 => 'c',\n  120331 => 'd',\n  120332 => 'e',\n  120333 => 'f',\n  120334 => 'g',\n  120335 => 'h',\n  120336 => 'i',\n  120337 => 'j',\n  120338 => 'k',\n  120339 => 'l',\n  120340 => 'm',\n  120341 => 'n',\n  120342 => 'o',\n  120343 => 'p',\n  120344 => 'q',\n  120345 => 'r',\n  120346 => 's',\n  120347 => 't',\n  120348 => 'u',\n  120349 => 'v',\n  120350 => 'w',\n  120351 => 'x',\n  120352 => 'y',\n  120353 => 'z',\n  120354 => 'a',\n  120355 => 'b',\n  120356 => 'c',\n  120357 => 'd',\n  120358 => 'e',\n  120359 => 'f',\n  120360 => 'g',\n  120361 => 'h',\n  120362 => 'i',\n  120363 => 'j',\n  120364 => 'k',\n  120365 => 'l',\n  120366 => 'm',\n  120367 => 'n',\n  120368 => 'o',\n  120369 => 'p',\n  120370 => 'q',\n  120371 => 'r',\n  120372 => 's',\n  120373 => 't',\n  120374 => 'u',\n  120375 => 'v',\n  120376 => 'w',\n  120377 => 'x',\n  120378 => 'y',\n  120379 => 'z',\n  120380 => 'a',\n  120381 => 'b',\n  120382 => 'c',\n  120383 => 'd',\n  120384 => 'e',\n  120385 => 'f',\n  120386 => 'g',\n  120387 => 'h',\n  120388 => 'i',\n  120389 => 'j',\n  120390 => 'k',\n  120391 => 'l',\n  120392 => 'm',\n  120393 => 'n',\n  120394 => 'o',\n  120395 => 'p',\n  120396 => 'q',\n  120397 => 'r',\n  120398 => 's',\n  120399 => 't',\n  120400 => 'u',\n  120401 => 'v',\n  120402 => 'w',\n  120403 => 'x',\n  120404 => 'y',\n  120405 => 'z',\n  120406 => 'a',\n  120407 => 'b',\n  120408 => 'c',\n  120409 => 'd',\n  120410 => 'e',\n  120411 => 'f',\n  120412 => 'g',\n  120413 => 'h',\n  120414 => 'i',\n  120415 => 'j',\n  120416 => 'k',\n  120417 => 'l',\n  120418 => 'm',\n  120419 => 'n',\n  120420 => 'o',\n  120421 => 'p',\n  120422 => 'q',\n  120423 => 'r',\n  120424 => 's',\n  120425 => 't',\n  120426 => 'u',\n  120427 => 'v',\n  120428 => 'w',\n  120429 => 'x',\n  120430 => 'y',\n  120431 => 'z',\n  120432 => 'a',\n  120433 => 'b',\n  120434 => 'c',\n  120435 => 'd',\n  120436 => 'e',\n  120437 => 'f',\n  120438 => 'g',\n  120439 => 'h',\n  120440 => 'i',\n  120441 => 'j',\n  120442 => 'k',\n  120443 => 'l',\n  120444 => 'm',\n  120445 => 'n',\n  120446 => 'o',\n  120447 => 'p',\n  120448 => 'q',\n  120449 => 'r',\n  120450 => 's',\n  120451 => 't',\n  120452 => 'u',\n  120453 => 'v',\n  120454 => 'w',\n  120455 => 'x',\n  120456 => 'y',\n  120457 => 'z',\n  120458 => 'a',\n  120459 => 'b',\n  120460 => 'c',\n  120461 => 'd',\n  120462 => 'e',\n  120463 => 'f',\n  120464 => 'g',\n  120465 => 'h',\n  120466 => 'i',\n  120467 => 'j',\n  120468 => 'k',\n  120469 => 'l',\n  120470 => 'm',\n  120471 => 'n',\n  120472 => 'o',\n  120473 => 'p',\n  120474 => 'q',\n  120475 => 'r',\n  120476 => 's',\n  120477 => 't',\n  120478 => 'u',\n  120479 => 'v',\n  120480 => 'w',\n  120481 => 'x',\n  120482 => 'y',\n  120483 => 'z',\n  120484 => 'ı',\n  120485 => 'ȷ',\n  120488 => 'α',\n  120489 => 'β',\n  120490 => 'γ',\n  120491 => 'δ',\n  120492 => 'ε',\n  120493 => 'ζ',\n  120494 => 'η',\n  120495 => 'θ',\n  120496 => 'ι',\n  120497 => 'κ',\n  120498 => 'λ',\n  120499 => 'μ',\n  120500 => 'ν',\n  120501 => 'ξ',\n  120502 => 'ο',\n  120503 => 'π',\n  120504 => 'ρ',\n  120505 => 'θ',\n  120506 => 'σ',\n  120507 => 'τ',\n  120508 => 'υ',\n  120509 => 'φ',\n  120510 => 'χ',\n  120511 => 'ψ',\n  120512 => 'ω',\n  120513 => '∇',\n  120514 => 'α',\n  120515 => 'β',\n  120516 => 'γ',\n  120517 => 'δ',\n  120518 => 'ε',\n  120519 => 'ζ',\n  120520 => 'η',\n  120521 => 'θ',\n  120522 => 'ι',\n  120523 => 'κ',\n  120524 => 'λ',\n  120525 => 'μ',\n  120526 => 'ν',\n  120527 => 'ξ',\n  120528 => 'ο',\n  120529 => 'π',\n  120530 => 'ρ',\n  120531 => 'σ',\n  120532 => 'σ',\n  120533 => 'τ',\n  120534 => 'υ',\n  120535 => 'φ',\n  120536 => 'χ',\n  120537 => 'ψ',\n  120538 => 'ω',\n  120539 => '∂',\n  120540 => 'ε',\n  120541 => 'θ',\n  120542 => 'κ',\n  120543 => 'φ',\n  120544 => 'ρ',\n  120545 => 'π',\n  120546 => 'α',\n  120547 => 'β',\n  120548 => 'γ',\n  120549 => 'δ',\n  120550 => 'ε',\n  120551 => 'ζ',\n  120552 => 'η',\n  120553 => 'θ',\n  120554 => 'ι',\n  120555 => 'κ',\n  120556 => 'λ',\n  120557 => 'μ',\n  120558 => 'ν',\n  120559 => 'ξ',\n  120560 => 'ο',\n  120561 => 'π',\n  120562 => 'ρ',\n  120563 => 'θ',\n  120564 => 'σ',\n  120565 => 'τ',\n  120566 => 'υ',\n  120567 => 'φ',\n  120568 => 'χ',\n  120569 => 'ψ',\n  120570 => 'ω',\n  120571 => '∇',\n  120572 => 'α',\n  120573 => 'β',\n  120574 => 'γ',\n  120575 => 'δ',\n  120576 => 'ε',\n  120577 => 'ζ',\n  120578 => 'η',\n  120579 => 'θ',\n  120580 => 'ι',\n  120581 => 'κ',\n  120582 => 'λ',\n  120583 => 'μ',\n  120584 => 'ν',\n  120585 => 'ξ',\n  120586 => 'ο',\n  120587 => 'π',\n  120588 => 'ρ',\n  120589 => 'σ',\n  120590 => 'σ',\n  120591 => 'τ',\n  120592 => 'υ',\n  120593 => 'φ',\n  120594 => 'χ',\n  120595 => 'ψ',\n  120596 => 'ω',\n  120597 => '∂',\n  120598 => 'ε',\n  120599 => 'θ',\n  120600 => 'κ',\n  120601 => 'φ',\n  120602 => 'ρ',\n  120603 => 'π',\n  120604 => 'α',\n  120605 => 'β',\n  120606 => 'γ',\n  120607 => 'δ',\n  120608 => 'ε',\n  120609 => 'ζ',\n  120610 => 'η',\n  120611 => 'θ',\n  120612 => 'ι',\n  120613 => 'κ',\n  120614 => 'λ',\n  120615 => 'μ',\n  120616 => 'ν',\n  120617 => 'ξ',\n  120618 => 'ο',\n  120619 => 'π',\n  120620 => 'ρ',\n  120621 => 'θ',\n  120622 => 'σ',\n  120623 => 'τ',\n  120624 => 'υ',\n  120625 => 'φ',\n  120626 => 'χ',\n  120627 => 'ψ',\n  120628 => 'ω',\n  120629 => '∇',\n  120630 => 'α',\n  120631 => 'β',\n  120632 => 'γ',\n  120633 => 'δ',\n  120634 => 'ε',\n  120635 => 'ζ',\n  120636 => 'η',\n  120637 => 'θ',\n  120638 => 'ι',\n  120639 => 'κ',\n  120640 => 'λ',\n  120641 => 'μ',\n  120642 => 'ν',\n  120643 => 'ξ',\n  120644 => 'ο',\n  120645 => 'π',\n  120646 => 'ρ',\n  120647 => 'σ',\n  120648 => 'σ',\n  120649 => 'τ',\n  120650 => 'υ',\n  120651 => 'φ',\n  120652 => 'χ',\n  120653 => 'ψ',\n  120654 => 'ω',\n  120655 => '∂',\n  120656 => 'ε',\n  120657 => 'θ',\n  120658 => 'κ',\n  120659 => 'φ',\n  120660 => 'ρ',\n  120661 => 'π',\n  120662 => 'α',\n  120663 => 'β',\n  120664 => 'γ',\n  120665 => 'δ',\n  120666 => 'ε',\n  120667 => 'ζ',\n  120668 => 'η',\n  120669 => 'θ',\n  120670 => 'ι',\n  120671 => 'κ',\n  120672 => 'λ',\n  120673 => 'μ',\n  120674 => 'ν',\n  120675 => 'ξ',\n  120676 => 'ο',\n  120677 => 'π',\n  120678 => 'ρ',\n  120679 => 'θ',\n  120680 => 'σ',\n  120681 => 'τ',\n  120682 => 'υ',\n  120683 => 'φ',\n  120684 => 'χ',\n  120685 => 'ψ',\n  120686 => 'ω',\n  120687 => '∇',\n  120688 => 'α',\n  120689 => 'β',\n  120690 => 'γ',\n  120691 => 'δ',\n  120692 => 'ε',\n  120693 => 'ζ',\n  120694 => 'η',\n  120695 => 'θ',\n  120696 => 'ι',\n  120697 => 'κ',\n  120698 => 'λ',\n  120699 => 'μ',\n  120700 => 'ν',\n  120701 => 'ξ',\n  120702 => 'ο',\n  120703 => 'π',\n  120704 => 'ρ',\n  120705 => 'σ',\n  120706 => 'σ',\n  120707 => 'τ',\n  120708 => 'υ',\n  120709 => 'φ',\n  120710 => 'χ',\n  120711 => 'ψ',\n  120712 => 'ω',\n  120713 => '∂',\n  120714 => 'ε',\n  120715 => 'θ',\n  120716 => 'κ',\n  120717 => 'φ',\n  120718 => 'ρ',\n  120719 => 'π',\n  120720 => 'α',\n  120721 => 'β',\n  120722 => 'γ',\n  120723 => 'δ',\n  120724 => 'ε',\n  120725 => 'ζ',\n  120726 => 'η',\n  120727 => 'θ',\n  120728 => 'ι',\n  120729 => 'κ',\n  120730 => 'λ',\n  120731 => 'μ',\n  120732 => 'ν',\n  120733 => 'ξ',\n  120734 => 'ο',\n  120735 => 'π',\n  120736 => 'ρ',\n  120737 => 'θ',\n  120738 => 'σ',\n  120739 => 'τ',\n  120740 => 'υ',\n  120741 => 'φ',\n  120742 => 'χ',\n  120743 => 'ψ',\n  120744 => 'ω',\n  120745 => '∇',\n  120746 => 'α',\n  120747 => 'β',\n  120748 => 'γ',\n  120749 => 'δ',\n  120750 => 'ε',\n  120751 => 'ζ',\n  120752 => 'η',\n  120753 => 'θ',\n  120754 => 'ι',\n  120755 => 'κ',\n  120756 => 'λ',\n  120757 => 'μ',\n  120758 => 'ν',\n  120759 => 'ξ',\n  120760 => 'ο',\n  120761 => 'π',\n  120762 => 'ρ',\n  120763 => 'σ',\n  120764 => 'σ',\n  120765 => 'τ',\n  120766 => 'υ',\n  120767 => 'φ',\n  120768 => 'χ',\n  120769 => 'ψ',\n  120770 => 'ω',\n  120771 => '∂',\n  120772 => 'ε',\n  120773 => 'θ',\n  120774 => 'κ',\n  120775 => 'φ',\n  120776 => 'ρ',\n  120777 => 'π',\n  120778 => 'ϝ',\n  120779 => 'ϝ',\n  120782 => '0',\n  120783 => '1',\n  120784 => '2',\n  120785 => '3',\n  120786 => '4',\n  120787 => '5',\n  120788 => '6',\n  120789 => '7',\n  120790 => '8',\n  120791 => '9',\n  120792 => '0',\n  120793 => '1',\n  120794 => '2',\n  120795 => '3',\n  120796 => '4',\n  120797 => '5',\n  120798 => '6',\n  120799 => '7',\n  120800 => '8',\n  120801 => '9',\n  120802 => '0',\n  120803 => '1',\n  120804 => '2',\n  120805 => '3',\n  120806 => '4',\n  120807 => '5',\n  120808 => '6',\n  120809 => '7',\n  120810 => '8',\n  120811 => '9',\n  120812 => '0',\n  120813 => '1',\n  120814 => '2',\n  120815 => '3',\n  120816 => '4',\n  120817 => '5',\n  120818 => '6',\n  120819 => '7',\n  120820 => '8',\n  120821 => '9',\n  120822 => '0',\n  120823 => '1',\n  120824 => '2',\n  120825 => '3',\n  120826 => '4',\n  120827 => '5',\n  120828 => '6',\n  120829 => '7',\n  120830 => '8',\n  120831 => '9',\n  125184 => '𞤢',\n  125185 => '𞤣',\n  125186 => '𞤤',\n  125187 => '𞤥',\n  125188 => '𞤦',\n  125189 => '𞤧',\n  125190 => '𞤨',\n  125191 => '𞤩',\n  125192 => '𞤪',\n  125193 => '𞤫',\n  125194 => '𞤬',\n  125195 => '𞤭',\n  125196 => '𞤮',\n  125197 => '𞤯',\n  125198 => '𞤰',\n  125199 => '𞤱',\n  125200 => '𞤲',\n  125201 => '𞤳',\n  125202 => '𞤴',\n  125203 => '𞤵',\n  125204 => '𞤶',\n  125205 => '𞤷',\n  125206 => '𞤸',\n  125207 => '𞤹',\n  125208 => '𞤺',\n  125209 => '𞤻',\n  125210 => '𞤼',\n  125211 => '𞤽',\n  125212 => '𞤾',\n  125213 => '𞤿',\n  125214 => '𞥀',\n  125215 => '𞥁',\n  125216 => '𞥂',\n  125217 => '𞥃',\n  126464 => 'ا',\n  126465 => 'ب',\n  126466 => 'ج',\n  126467 => 'د',\n  126469 => 'و',\n  126470 => 'ز',\n  126471 => 'ح',\n  126472 => 'ط',\n  126473 => 'ي',\n  126474 => 'ك',\n  126475 => 'ل',\n  126476 => 'م',\n  126477 => 'ن',\n  126478 => 'س',\n  126479 => 'ع',\n  126480 => 'ف',\n  126481 => 'ص',\n  126482 => 'ق',\n  126483 => 'ر',\n  126484 => 'ش',\n  126485 => 'ت',\n  126486 => 'ث',\n  126487 => 'خ',\n  126488 => 'ذ',\n  126489 => 'ض',\n  126490 => 'ظ',\n  126491 => 'غ',\n  126492 => 'ٮ',\n  126493 => 'ں',\n  126494 => 'ڡ',\n  126495 => 'ٯ',\n  126497 => 'ب',\n  126498 => 'ج',\n  126500 => 'ه',\n  126503 => 'ح',\n  126505 => 'ي',\n  126506 => 'ك',\n  126507 => 'ل',\n  126508 => 'م',\n  126509 => 'ن',\n  126510 => 'س',\n  126511 => 'ع',\n  126512 => 'ف',\n  126513 => 'ص',\n  126514 => 'ق',\n  126516 => 'ش',\n  126517 => 'ت',\n  126518 => 'ث',\n  126519 => 'خ',\n  126521 => 'ض',\n  126523 => 'غ',\n  126530 => 'ج',\n  126535 => 'ح',\n  126537 => 'ي',\n  126539 => 'ل',\n  126541 => 'ن',\n  126542 => 'س',\n  126543 => 'ع',\n  126545 => 'ص',\n  126546 => 'ق',\n  126548 => 'ش',\n  126551 => 'خ',\n  126553 => 'ض',\n  126555 => 'غ',\n  126557 => 'ں',\n  126559 => 'ٯ',\n  126561 => 'ب',\n  126562 => 'ج',\n  126564 => 'ه',\n  126567 => 'ح',\n  126568 => 'ط',\n  126569 => 'ي',\n  126570 => 'ك',\n  126572 => 'م',\n  126573 => 'ن',\n  126574 => 'س',\n  126575 => 'ع',\n  126576 => 'ف',\n  126577 => 'ص',\n  126578 => 'ق',\n  126580 => 'ش',\n  126581 => 'ت',\n  126582 => 'ث',\n  126583 => 'خ',\n  126585 => 'ض',\n  126586 => 'ظ',\n  126587 => 'غ',\n  126588 => 'ٮ',\n  126590 => 'ڡ',\n  126592 => 'ا',\n  126593 => 'ب',\n  126594 => 'ج',\n  126595 => 'د',\n  126596 => 'ه',\n  126597 => 'و',\n  126598 => 'ز',\n  126599 => 'ح',\n  126600 => 'ط',\n  126601 => 'ي',\n  126603 => 'ل',\n  126604 => 'م',\n  126605 => 'ن',\n  126606 => 'س',\n  126607 => 'ع',\n  126608 => 'ف',\n  126609 => 'ص',\n  126610 => 'ق',\n  126611 => 'ر',\n  126612 => 'ش',\n  126613 => 'ت',\n  126614 => 'ث',\n  126615 => 'خ',\n  126616 => 'ذ',\n  126617 => 'ض',\n  126618 => 'ظ',\n  126619 => 'غ',\n  126625 => 'ب',\n  126626 => 'ج',\n  126627 => 'د',\n  126629 => 'و',\n  126630 => 'ز',\n  126631 => 'ح',\n  126632 => 'ط',\n  126633 => 'ي',\n  126635 => 'ل',\n  126636 => 'م',\n  126637 => 'ن',\n  126638 => 'س',\n  126639 => 'ع',\n  126640 => 'ف',\n  126641 => 'ص',\n  126642 => 'ق',\n  126643 => 'ر',\n  126644 => 'ش',\n  126645 => 'ت',\n  126646 => 'ث',\n  126647 => 'خ',\n  126648 => 'ذ',\n  126649 => 'ض',\n  126650 => 'ظ',\n  126651 => 'غ',\n  127274 => '〔s〕',\n  127275 => 'c',\n  127276 => 'r',\n  127277 => 'cd',\n  127278 => 'wz',\n  127280 => 'a',\n  127281 => 'b',\n  127282 => 'c',\n  127283 => 'd',\n  127284 => 'e',\n  127285 => 'f',\n  127286 => 'g',\n  127287 => 'h',\n  127288 => 'i',\n  127289 => 'j',\n  127290 => 'k',\n  127291 => 'l',\n  127292 => 'm',\n  127293 => 'n',\n  127294 => 'o',\n  127295 => 'p',\n  127296 => 'q',\n  127297 => 'r',\n  127298 => 's',\n  127299 => 't',\n  127300 => 'u',\n  127301 => 'v',\n  127302 => 'w',\n  127303 => 'x',\n  127304 => 'y',\n  127305 => 'z',\n  127306 => 'hv',\n  127307 => 'mv',\n  127308 => 'sd',\n  127309 => 'ss',\n  127310 => 'ppv',\n  127311 => 'wc',\n  127338 => 'mc',\n  127339 => 'md',\n  127340 => 'mr',\n  127376 => 'dj',\n  127488 => 'ほか',\n  127489 => 'ココ',\n  127490 => 'サ',\n  127504 => '手',\n  127505 => '字',\n  127506 => '双',\n  127507 => 'デ',\n  127508 => '二',\n  127509 => '多',\n  127510 => '解',\n  127511 => '天',\n  127512 => '交',\n  127513 => '映',\n  127514 => '無',\n  127515 => '料',\n  127516 => '前',\n  127517 => '後',\n  127518 => '再',\n  127519 => '新',\n  127520 => '初',\n  127521 => '終',\n  127522 => '生',\n  127523 => '販',\n  127524 => '声',\n  127525 => '吹',\n  127526 => '演',\n  127527 => '投',\n  127528 => '捕',\n  127529 => '一',\n  127530 => '三',\n  127531 => '遊',\n  127532 => '左',\n  127533 => '中',\n  127534 => '右',\n  127535 => '指',\n  127536 => '走',\n  127537 => '打',\n  127538 => '禁',\n  127539 => '空',\n  127540 => '合',\n  127541 => '満',\n  127542 => '有',\n  127543 => '月',\n  127544 => '申',\n  127545 => '割',\n  127546 => '営',\n  127547 => '配',\n  127552 => '〔本〕',\n  127553 => '〔三〕',\n  127554 => '〔二〕',\n  127555 => '〔安〕',\n  127556 => '〔点〕',\n  127557 => '〔打〕',\n  127558 => '〔盗〕',\n  127559 => '〔勝〕',\n  127560 => '〔敗〕',\n  127568 => '得',\n  127569 => '可',\n  130032 => '0',\n  130033 => '1',\n  130034 => '2',\n  130035 => '3',\n  130036 => '4',\n  130037 => '5',\n  130038 => '6',\n  130039 => '7',\n  130040 => '8',\n  130041 => '9',\n  194560 => '丽',\n  194561 => '丸',\n  194562 => '乁',\n  194563 => '𠄢',\n  194564 => '你',\n  194565 => '侮',\n  194566 => '侻',\n  194567 => '倂',\n  194568 => '偺',\n  194569 => '備',\n  194570 => '僧',\n  194571 => '像',\n  194572 => '㒞',\n  194573 => '𠘺',\n  194574 => '免',\n  194575 => '兔',\n  194576 => '兤',\n  194577 => '具',\n  194578 => '𠔜',\n  194579 => '㒹',\n  194580 => '內',\n  194581 => '再',\n  194582 => '𠕋',\n  194583 => '冗',\n  194584 => '冤',\n  194585 => '仌',\n  194586 => '冬',\n  194587 => '况',\n  194588 => '𩇟',\n  194589 => '凵',\n  194590 => '刃',\n  194591 => '㓟',\n  194592 => '刻',\n  194593 => '剆',\n  194594 => '割',\n  194595 => '剷',\n  194596 => '㔕',\n  194597 => '勇',\n  194598 => '勉',\n  194599 => '勤',\n  194600 => '勺',\n  194601 => '包',\n  194602 => '匆',\n  194603 => '北',\n  194604 => '卉',\n  194605 => '卑',\n  194606 => '博',\n  194607 => '即',\n  194608 => '卽',\n  194609 => '卿',\n  194610 => '卿',\n  194611 => '卿',\n  194612 => '𠨬',\n  194613 => '灰',\n  194614 => '及',\n  194615 => '叟',\n  194616 => '𠭣',\n  194617 => '叫',\n  194618 => '叱',\n  194619 => '吆',\n  194620 => '咞',\n  194621 => '吸',\n  194622 => '呈',\n  194623 => '周',\n  194624 => '咢',\n  194625 => '哶',\n  194626 => '唐',\n  194627 => '啓',\n  194628 => '啣',\n  194629 => '善',\n  194630 => '善',\n  194631 => '喙',\n  194632 => '喫',\n  194633 => '喳',\n  194634 => '嗂',\n  194635 => '圖',\n  194636 => '嘆',\n  194637 => '圗',\n  194638 => '噑',\n  194639 => '噴',\n  194640 => '切',\n  194641 => '壮',\n  194642 => '城',\n  194643 => '埴',\n  194644 => '堍',\n  194645 => '型',\n  194646 => '堲',\n  194647 => '報',\n  194648 => '墬',\n  194649 => '𡓤',\n  194650 => '売',\n  194651 => '壷',\n  194652 => '夆',\n  194653 => '多',\n  194654 => '夢',\n  194655 => '奢',\n  194656 => '𡚨',\n  194657 => '𡛪',\n  194658 => '姬',\n  194659 => '娛',\n  194660 => '娧',\n  194661 => '姘',\n  194662 => '婦',\n  194663 => '㛮',\n  194665 => '嬈',\n  194666 => '嬾',\n  194667 => '嬾',\n  194668 => '𡧈',\n  194669 => '寃',\n  194670 => '寘',\n  194671 => '寧',\n  194672 => '寳',\n  194673 => '𡬘',\n  194674 => '寿',\n  194675 => '将',\n  194677 => '尢',\n  194678 => '㞁',\n  194679 => '屠',\n  194680 => '屮',\n  194681 => '峀',\n  194682 => '岍',\n  194683 => '𡷤',\n  194684 => '嵃',\n  194685 => '𡷦',\n  194686 => '嵮',\n  194687 => '嵫',\n  194688 => '嵼',\n  194689 => '巡',\n  194690 => '巢',\n  194691 => '㠯',\n  194692 => '巽',\n  194693 => '帨',\n  194694 => '帽',\n  194695 => '幩',\n  194696 => '㡢',\n  194697 => '𢆃',\n  194698 => '㡼',\n  194699 => '庰',\n  194700 => '庳',\n  194701 => '庶',\n  194702 => '廊',\n  194703 => '𪎒',\n  194704 => '廾',\n  194705 => '𢌱',\n  194706 => '𢌱',\n  194707 => '舁',\n  194708 => '弢',\n  194709 => '弢',\n  194710 => '㣇',\n  194711 => '𣊸',\n  194712 => '𦇚',\n  194713 => '形',\n  194714 => '彫',\n  194715 => '㣣',\n  194716 => '徚',\n  194717 => '忍',\n  194718 => '志',\n  194719 => '忹',\n  194720 => '悁',\n  194721 => '㤺',\n  194722 => '㤜',\n  194723 => '悔',\n  194724 => '𢛔',\n  194725 => '惇',\n  194726 => '慈',\n  194727 => '慌',\n  194728 => '慎',\n  194729 => '慌',\n  194730 => '慺',\n  194731 => '憎',\n  194732 => '憲',\n  194733 => '憤',\n  194734 => '憯',\n  194735 => '懞',\n  194736 => '懲',\n  194737 => '懶',\n  194738 => '成',\n  194739 => '戛',\n  194740 => '扝',\n  194741 => '抱',\n  194742 => '拔',\n  194743 => '捐',\n  194744 => '𢬌',\n  194745 => '挽',\n  194746 => '拼',\n  194747 => '捨',\n  194748 => '掃',\n  194749 => '揤',\n  194750 => '𢯱',\n  194751 => '搢',\n  194752 => '揅',\n  194753 => '掩',\n  194754 => '㨮',\n  194755 => '摩',\n  194756 => '摾',\n  194757 => '撝',\n  194758 => '摷',\n  194759 => '㩬',\n  194760 => '敏',\n  194761 => '敬',\n  194762 => '𣀊',\n  194763 => '旣',\n  194764 => '書',\n  194765 => '晉',\n  194766 => '㬙',\n  194767 => '暑',\n  194768 => '㬈',\n  194769 => '㫤',\n  194770 => '冒',\n  194771 => '冕',\n  194772 => '最',\n  194773 => '暜',\n  194774 => '肭',\n  194775 => '䏙',\n  194776 => '朗',\n  194777 => '望',\n  194778 => '朡',\n  194779 => '杞',\n  194780 => '杓',\n  194781 => '𣏃',\n  194782 => '㭉',\n  194783 => '柺',\n  194784 => '枅',\n  194785 => '桒',\n  194786 => '梅',\n  194787 => '𣑭',\n  194788 => '梎',\n  194789 => '栟',\n  194790 => '椔',\n  194791 => '㮝',\n  194792 => '楂',\n  194793 => '榣',\n  194794 => '槪',\n  194795 => '檨',\n  194796 => '𣚣',\n  194797 => '櫛',\n  194798 => '㰘',\n  194799 => '次',\n  194800 => '𣢧',\n  194801 => '歔',\n  194802 => '㱎',\n  194803 => '歲',\n  194804 => '殟',\n  194805 => '殺',\n  194806 => '殻',\n  194807 => '𣪍',\n  194808 => '𡴋',\n  194809 => '𣫺',\n  194810 => '汎',\n  194811 => '𣲼',\n  194812 => '沿',\n  194813 => '泍',\n  194814 => '汧',\n  194815 => '洖',\n  194816 => '派',\n  194817 => '海',\n  194818 => '流',\n  194819 => '浩',\n  194820 => '浸',\n  194821 => '涅',\n  194822 => '𣴞',\n  194823 => '洴',\n  194824 => '港',\n  194825 => '湮',\n  194826 => '㴳',\n  194827 => '滋',\n  194828 => '滇',\n  194829 => '𣻑',\n  194830 => '淹',\n  194831 => '潮',\n  194832 => '𣽞',\n  194833 => '𣾎',\n  194834 => '濆',\n  194835 => '瀹',\n  194836 => '瀞',\n  194837 => '瀛',\n  194838 => '㶖',\n  194839 => '灊',\n  194840 => '災',\n  194841 => '灷',\n  194842 => '炭',\n  194843 => '𠔥',\n  194844 => '煅',\n  194845 => '𤉣',\n  194846 => '熜',\n  194848 => '爨',\n  194849 => '爵',\n  194850 => '牐',\n  194851 => '𤘈',\n  194852 => '犀',\n  194853 => '犕',\n  194854 => '𤜵',\n  194855 => '𤠔',\n  194856 => '獺',\n  194857 => '王',\n  194858 => '㺬',\n  194859 => '玥',\n  194860 => '㺸',\n  194861 => '㺸',\n  194862 => '瑇',\n  194863 => '瑜',\n  194864 => '瑱',\n  194865 => '璅',\n  194866 => '瓊',\n  194867 => '㼛',\n  194868 => '甤',\n  194869 => '𤰶',\n  194870 => '甾',\n  194871 => '𤲒',\n  194872 => '異',\n  194873 => '𢆟',\n  194874 => '瘐',\n  194875 => '𤾡',\n  194876 => '𤾸',\n  194877 => '𥁄',\n  194878 => '㿼',\n  194879 => '䀈',\n  194880 => '直',\n  194881 => '𥃳',\n  194882 => '𥃲',\n  194883 => '𥄙',\n  194884 => '𥄳',\n  194885 => '眞',\n  194886 => '真',\n  194887 => '真',\n  194888 => '睊',\n  194889 => '䀹',\n  194890 => '瞋',\n  194891 => '䁆',\n  194892 => '䂖',\n  194893 => '𥐝',\n  194894 => '硎',\n  194895 => '碌',\n  194896 => '磌',\n  194897 => '䃣',\n  194898 => '𥘦',\n  194899 => '祖',\n  194900 => '𥚚',\n  194901 => '𥛅',\n  194902 => '福',\n  194903 => '秫',\n  194904 => '䄯',\n  194905 => '穀',\n  194906 => '穊',\n  194907 => '穏',\n  194908 => '𥥼',\n  194909 => '𥪧',\n  194910 => '𥪧',\n  194912 => '䈂',\n  194913 => '𥮫',\n  194914 => '篆',\n  194915 => '築',\n  194916 => '䈧',\n  194917 => '𥲀',\n  194918 => '糒',\n  194919 => '䊠',\n  194920 => '糨',\n  194921 => '糣',\n  194922 => '紀',\n  194923 => '𥾆',\n  194924 => '絣',\n  194925 => '䌁',\n  194926 => '緇',\n  194927 => '縂',\n  194928 => '繅',\n  194929 => '䌴',\n  194930 => '𦈨',\n  194931 => '𦉇',\n  194932 => '䍙',\n  194933 => '𦋙',\n  194934 => '罺',\n  194935 => '𦌾',\n  194936 => '羕',\n  194937 => '翺',\n  194938 => '者',\n  194939 => '𦓚',\n  194940 => '𦔣',\n  194941 => '聠',\n  194942 => '𦖨',\n  194943 => '聰',\n  194944 => '𣍟',\n  194945 => '䏕',\n  194946 => '育',\n  194947 => '脃',\n  194948 => '䐋',\n  194949 => '脾',\n  194950 => '媵',\n  194951 => '𦞧',\n  194952 => '𦞵',\n  194953 => '𣎓',\n  194954 => '𣎜',\n  194955 => '舁',\n  194956 => '舄',\n  194957 => '辞',\n  194958 => '䑫',\n  194959 => '芑',\n  194960 => '芋',\n  194961 => '芝',\n  194962 => '劳',\n  194963 => '花',\n  194964 => '芳',\n  194965 => '芽',\n  194966 => '苦',\n  194967 => '𦬼',\n  194968 => '若',\n  194969 => '茝',\n  194970 => '荣',\n  194971 => '莭',\n  194972 => '茣',\n  194973 => '莽',\n  194974 => '菧',\n  194975 => '著',\n  194976 => '荓',\n  194977 => '菊',\n  194978 => '菌',\n  194979 => '菜',\n  194980 => '𦰶',\n  194981 => '𦵫',\n  194982 => '𦳕',\n  194983 => '䔫',\n  194984 => '蓱',\n  194985 => '蓳',\n  194986 => '蔖',\n  194987 => '𧏊',\n  194988 => '蕤',\n  194989 => '𦼬',\n  194990 => '䕝',\n  194991 => '䕡',\n  194992 => '𦾱',\n  194993 => '𧃒',\n  194994 => '䕫',\n  194995 => '虐',\n  194996 => '虜',\n  194997 => '虧',\n  194998 => '虩',\n  194999 => '蚩',\n  195000 => '蚈',\n  195001 => '蜎',\n  195002 => '蛢',\n  195003 => '蝹',\n  195004 => '蜨',\n  195005 => '蝫',\n  195006 => '螆',\n  195008 => '蟡',\n  195009 => '蠁',\n  195010 => '䗹',\n  195011 => '衠',\n  195012 => '衣',\n  195013 => '𧙧',\n  195014 => '裗',\n  195015 => '裞',\n  195016 => '䘵',\n  195017 => '裺',\n  195018 => '㒻',\n  195019 => '𧢮',\n  195020 => '𧥦',\n  195021 => '䚾',\n  195022 => '䛇',\n  195023 => '誠',\n  195024 => '諭',\n  195025 => '變',\n  195026 => '豕',\n  195027 => '𧲨',\n  195028 => '貫',\n  195029 => '賁',\n  195030 => '贛',\n  195031 => '起',\n  195032 => '𧼯',\n  195033 => '𠠄',\n  195034 => '跋',\n  195035 => '趼',\n  195036 => '跰',\n  195037 => '𠣞',\n  195038 => '軔',\n  195039 => '輸',\n  195040 => '𨗒',\n  195041 => '𨗭',\n  195042 => '邔',\n  195043 => '郱',\n  195044 => '鄑',\n  195045 => '𨜮',\n  195046 => '鄛',\n  195047 => '鈸',\n  195048 => '鋗',\n  195049 => '鋘',\n  195050 => '鉼',\n  195051 => '鏹',\n  195052 => '鐕',\n  195053 => '𨯺',\n  195054 => '開',\n  195055 => '䦕',\n  195056 => '閷',\n  195057 => '𨵷',\n  195058 => '䧦',\n  195059 => '雃',\n  195060 => '嶲',\n  195061 => '霣',\n  195062 => '𩅅',\n  195063 => '𩈚',\n  195064 => '䩮',\n  195065 => '䩶',\n  195066 => '韠',\n  195067 => '𩐊',\n  195068 => '䪲',\n  195069 => '𩒖',\n  195070 => '頋',\n  195071 => '頋',\n  195072 => '頩',\n  195073 => '𩖶',\n  195074 => '飢',\n  195075 => '䬳',\n  195076 => '餩',\n  195077 => '馧',\n  195078 => '駂',\n  195079 => '駾',\n  195080 => '䯎',\n  195081 => '𩬰',\n  195082 => '鬒',\n  195083 => '鱀',\n  195084 => '鳽',\n  195085 => '䳎',\n  195086 => '䳭',\n  195087 => '鵧',\n  195088 => '𪃎',\n  195089 => '䳸',\n  195090 => '𪄅',\n  195091 => '𪈎',\n  195092 => '𪊑',\n  195093 => '麻',\n  195094 => '䵖',\n  195095 => '黹',\n  195096 => '黾',\n  195097 => '鼅',\n  195098 => '鼏',\n  195099 => '鼖',\n  195100 => '鼻',\n  195101 => '𪘀',\n);\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-intl-idn/Resources/unidata/virama.php",
    "content": "<?php\n\nreturn array (\n  2381 => 9,\n  2509 => 9,\n  2637 => 9,\n  2765 => 9,\n  2893 => 9,\n  3021 => 9,\n  3149 => 9,\n  3277 => 9,\n  3387 => 9,\n  3388 => 9,\n  3405 => 9,\n  3530 => 9,\n  3642 => 9,\n  3770 => 9,\n  3972 => 9,\n  4153 => 9,\n  4154 => 9,\n  5908 => 9,\n  5940 => 9,\n  6098 => 9,\n  6752 => 9,\n  6980 => 9,\n  7082 => 9,\n  7083 => 9,\n  7154 => 9,\n  7155 => 9,\n  11647 => 9,\n  43014 => 9,\n  43052 => 9,\n  43204 => 9,\n  43347 => 9,\n  43456 => 9,\n  43766 => 9,\n  44013 => 9,\n  68159 => 9,\n  69702 => 9,\n  69759 => 9,\n  69817 => 9,\n  69939 => 9,\n  69940 => 9,\n  70080 => 9,\n  70197 => 9,\n  70378 => 9,\n  70477 => 9,\n  70722 => 9,\n  70850 => 9,\n  71103 => 9,\n  71231 => 9,\n  71350 => 9,\n  71467 => 9,\n  71737 => 9,\n  71997 => 9,\n  71998 => 9,\n  72160 => 9,\n  72244 => 9,\n  72263 => 9,\n  72345 => 9,\n  72767 => 9,\n  73028 => 9,\n  73029 => 9,\n  73111 => 9,\n);\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-intl-idn/bootstrap.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nuse Symfony\\Polyfill\\Intl\\Idn as p;\n\nif (extension_loaded('intl')) {\n    return;\n}\n\nif (\\PHP_VERSION_ID >= 80000) {\n    return require __DIR__.'/bootstrap80.php';\n}\n\nif (!defined('U_IDNA_PROHIBITED_ERROR')) {\n    define('U_IDNA_PROHIBITED_ERROR', 66560);\n}\nif (!defined('U_IDNA_ERROR_START')) {\n    define('U_IDNA_ERROR_START', 66560);\n}\nif (!defined('U_IDNA_UNASSIGNED_ERROR')) {\n    define('U_IDNA_UNASSIGNED_ERROR', 66561);\n}\nif (!defined('U_IDNA_CHECK_BIDI_ERROR')) {\n    define('U_IDNA_CHECK_BIDI_ERROR', 66562);\n}\nif (!defined('U_IDNA_STD3_ASCII_RULES_ERROR')) {\n    define('U_IDNA_STD3_ASCII_RULES_ERROR', 66563);\n}\nif (!defined('U_IDNA_ACE_PREFIX_ERROR')) {\n    define('U_IDNA_ACE_PREFIX_ERROR', 66564);\n}\nif (!defined('U_IDNA_VERIFICATION_ERROR')) {\n    define('U_IDNA_VERIFICATION_ERROR', 66565);\n}\nif (!defined('U_IDNA_LABEL_TOO_LONG_ERROR')) {\n    define('U_IDNA_LABEL_TOO_LONG_ERROR', 66566);\n}\nif (!defined('U_IDNA_ZERO_LENGTH_LABEL_ERROR')) {\n    define('U_IDNA_ZERO_LENGTH_LABEL_ERROR', 66567);\n}\nif (!defined('U_IDNA_DOMAIN_NAME_TOO_LONG_ERROR')) {\n    define('U_IDNA_DOMAIN_NAME_TOO_LONG_ERROR', 66568);\n}\nif (!defined('U_IDNA_ERROR_LIMIT')) {\n    define('U_IDNA_ERROR_LIMIT', 66569);\n}\nif (!defined('U_STRINGPREP_PROHIBITED_ERROR')) {\n    define('U_STRINGPREP_PROHIBITED_ERROR', 66560);\n}\nif (!defined('U_STRINGPREP_UNASSIGNED_ERROR')) {\n    define('U_STRINGPREP_UNASSIGNED_ERROR', 66561);\n}\nif (!defined('U_STRINGPREP_CHECK_BIDI_ERROR')) {\n    define('U_STRINGPREP_CHECK_BIDI_ERROR', 66562);\n}\nif (!defined('IDNA_DEFAULT')) {\n    define('IDNA_DEFAULT', 0);\n}\nif (!defined('IDNA_ALLOW_UNASSIGNED')) {\n    define('IDNA_ALLOW_UNASSIGNED', 1);\n}\nif (!defined('IDNA_USE_STD3_RULES')) {\n    define('IDNA_USE_STD3_RULES', 2);\n}\nif (!defined('IDNA_CHECK_BIDI')) {\n    define('IDNA_CHECK_BIDI', 4);\n}\nif (!defined('IDNA_CHECK_CONTEXTJ')) {\n    define('IDNA_CHECK_CONTEXTJ', 8);\n}\nif (!defined('IDNA_NONTRANSITIONAL_TO_ASCII')) {\n    define('IDNA_NONTRANSITIONAL_TO_ASCII', 16);\n}\nif (!defined('IDNA_NONTRANSITIONAL_TO_UNICODE')) {\n    define('IDNA_NONTRANSITIONAL_TO_UNICODE', 32);\n}\nif (!defined('INTL_IDNA_VARIANT_2003')) {\n    define('INTL_IDNA_VARIANT_2003', 0);\n}\nif (!defined('INTL_IDNA_VARIANT_UTS46')) {\n    define('INTL_IDNA_VARIANT_UTS46', 1);\n}\nif (!defined('IDNA_ERROR_EMPTY_LABEL')) {\n    define('IDNA_ERROR_EMPTY_LABEL', 1);\n}\nif (!defined('IDNA_ERROR_LABEL_TOO_LONG')) {\n    define('IDNA_ERROR_LABEL_TOO_LONG', 2);\n}\nif (!defined('IDNA_ERROR_DOMAIN_NAME_TOO_LONG')) {\n    define('IDNA_ERROR_DOMAIN_NAME_TOO_LONG', 4);\n}\nif (!defined('IDNA_ERROR_LEADING_HYPHEN')) {\n    define('IDNA_ERROR_LEADING_HYPHEN', 8);\n}\nif (!defined('IDNA_ERROR_TRAILING_HYPHEN')) {\n    define('IDNA_ERROR_TRAILING_HYPHEN', 16);\n}\nif (!defined('IDNA_ERROR_HYPHEN_3_4')) {\n    define('IDNA_ERROR_HYPHEN_3_4', 32);\n}\nif (!defined('IDNA_ERROR_LEADING_COMBINING_MARK')) {\n    define('IDNA_ERROR_LEADING_COMBINING_MARK', 64);\n}\nif (!defined('IDNA_ERROR_DISALLOWED')) {\n    define('IDNA_ERROR_DISALLOWED', 128);\n}\nif (!defined('IDNA_ERROR_PUNYCODE')) {\n    define('IDNA_ERROR_PUNYCODE', 256);\n}\nif (!defined('IDNA_ERROR_LABEL_HAS_DOT')) {\n    define('IDNA_ERROR_LABEL_HAS_DOT', 512);\n}\nif (!defined('IDNA_ERROR_INVALID_ACE_LABEL')) {\n    define('IDNA_ERROR_INVALID_ACE_LABEL', 1024);\n}\nif (!defined('IDNA_ERROR_BIDI')) {\n    define('IDNA_ERROR_BIDI', 2048);\n}\nif (!defined('IDNA_ERROR_CONTEXTJ')) {\n    define('IDNA_ERROR_CONTEXTJ', 4096);\n}\n\nif (\\PHP_VERSION_ID < 70400) {\n    if (!function_exists('idn_to_ascii')) {\n        function idn_to_ascii($domain, $flags = 0, $variant = \\INTL_IDNA_VARIANT_2003, &$idna_info = null) { return p\\Idn::idn_to_ascii($domain, $flags, $variant, $idna_info); }\n    }\n    if (!function_exists('idn_to_utf8')) {\n        function idn_to_utf8($domain, $flags = 0, $variant = \\INTL_IDNA_VARIANT_2003, &$idna_info = null) { return p\\Idn::idn_to_utf8($domain, $flags, $variant, $idna_info); }\n    }\n} else {\n    if (!function_exists('idn_to_ascii')) {\n        function idn_to_ascii($domain, $flags = 0, $variant = \\INTL_IDNA_VARIANT_UTS46, &$idna_info = null) { return p\\Idn::idn_to_ascii($domain, $flags, $variant, $idna_info); }\n    }\n    if (!function_exists('idn_to_utf8')) {\n        function idn_to_utf8($domain, $flags = 0, $variant = \\INTL_IDNA_VARIANT_UTS46, &$idna_info = null) { return p\\Idn::idn_to_utf8($domain, $flags, $variant, $idna_info); }\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-intl-idn/bootstrap80.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nuse Symfony\\Polyfill\\Intl\\Idn as p;\n\nif (!defined('U_IDNA_PROHIBITED_ERROR')) {\n    define('U_IDNA_PROHIBITED_ERROR', 66560);\n}\nif (!defined('U_IDNA_ERROR_START')) {\n    define('U_IDNA_ERROR_START', 66560);\n}\nif (!defined('U_IDNA_UNASSIGNED_ERROR')) {\n    define('U_IDNA_UNASSIGNED_ERROR', 66561);\n}\nif (!defined('U_IDNA_CHECK_BIDI_ERROR')) {\n    define('U_IDNA_CHECK_BIDI_ERROR', 66562);\n}\nif (!defined('U_IDNA_STD3_ASCII_RULES_ERROR')) {\n    define('U_IDNA_STD3_ASCII_RULES_ERROR', 66563);\n}\nif (!defined('U_IDNA_ACE_PREFIX_ERROR')) {\n    define('U_IDNA_ACE_PREFIX_ERROR', 66564);\n}\nif (!defined('U_IDNA_VERIFICATION_ERROR')) {\n    define('U_IDNA_VERIFICATION_ERROR', 66565);\n}\nif (!defined('U_IDNA_LABEL_TOO_LONG_ERROR')) {\n    define('U_IDNA_LABEL_TOO_LONG_ERROR', 66566);\n}\nif (!defined('U_IDNA_ZERO_LENGTH_LABEL_ERROR')) {\n    define('U_IDNA_ZERO_LENGTH_LABEL_ERROR', 66567);\n}\nif (!defined('U_IDNA_DOMAIN_NAME_TOO_LONG_ERROR')) {\n    define('U_IDNA_DOMAIN_NAME_TOO_LONG_ERROR', 66568);\n}\nif (!defined('U_IDNA_ERROR_LIMIT')) {\n    define('U_IDNA_ERROR_LIMIT', 66569);\n}\nif (!defined('U_STRINGPREP_PROHIBITED_ERROR')) {\n    define('U_STRINGPREP_PROHIBITED_ERROR', 66560);\n}\nif (!defined('U_STRINGPREP_UNASSIGNED_ERROR')) {\n    define('U_STRINGPREP_UNASSIGNED_ERROR', 66561);\n}\nif (!defined('U_STRINGPREP_CHECK_BIDI_ERROR')) {\n    define('U_STRINGPREP_CHECK_BIDI_ERROR', 66562);\n}\nif (!defined('IDNA_DEFAULT')) {\n    define('IDNA_DEFAULT', 0);\n}\nif (!defined('IDNA_ALLOW_UNASSIGNED')) {\n    define('IDNA_ALLOW_UNASSIGNED', 1);\n}\nif (!defined('IDNA_USE_STD3_RULES')) {\n    define('IDNA_USE_STD3_RULES', 2);\n}\nif (!defined('IDNA_CHECK_BIDI')) {\n    define('IDNA_CHECK_BIDI', 4);\n}\nif (!defined('IDNA_CHECK_CONTEXTJ')) {\n    define('IDNA_CHECK_CONTEXTJ', 8);\n}\nif (!defined('IDNA_NONTRANSITIONAL_TO_ASCII')) {\n    define('IDNA_NONTRANSITIONAL_TO_ASCII', 16);\n}\nif (!defined('IDNA_NONTRANSITIONAL_TO_UNICODE')) {\n    define('IDNA_NONTRANSITIONAL_TO_UNICODE', 32);\n}\nif (!defined('INTL_IDNA_VARIANT_UTS46')) {\n    define('INTL_IDNA_VARIANT_UTS46', 1);\n}\nif (!defined('IDNA_ERROR_EMPTY_LABEL')) {\n    define('IDNA_ERROR_EMPTY_LABEL', 1);\n}\nif (!defined('IDNA_ERROR_LABEL_TOO_LONG')) {\n    define('IDNA_ERROR_LABEL_TOO_LONG', 2);\n}\nif (!defined('IDNA_ERROR_DOMAIN_NAME_TOO_LONG')) {\n    define('IDNA_ERROR_DOMAIN_NAME_TOO_LONG', 4);\n}\nif (!defined('IDNA_ERROR_LEADING_HYPHEN')) {\n    define('IDNA_ERROR_LEADING_HYPHEN', 8);\n}\nif (!defined('IDNA_ERROR_TRAILING_HYPHEN')) {\n    define('IDNA_ERROR_TRAILING_HYPHEN', 16);\n}\nif (!defined('IDNA_ERROR_HYPHEN_3_4')) {\n    define('IDNA_ERROR_HYPHEN_3_4', 32);\n}\nif (!defined('IDNA_ERROR_LEADING_COMBINING_MARK')) {\n    define('IDNA_ERROR_LEADING_COMBINING_MARK', 64);\n}\nif (!defined('IDNA_ERROR_DISALLOWED')) {\n    define('IDNA_ERROR_DISALLOWED', 128);\n}\nif (!defined('IDNA_ERROR_PUNYCODE')) {\n    define('IDNA_ERROR_PUNYCODE', 256);\n}\nif (!defined('IDNA_ERROR_LABEL_HAS_DOT')) {\n    define('IDNA_ERROR_LABEL_HAS_DOT', 512);\n}\nif (!defined('IDNA_ERROR_INVALID_ACE_LABEL')) {\n    define('IDNA_ERROR_INVALID_ACE_LABEL', 1024);\n}\nif (!defined('IDNA_ERROR_BIDI')) {\n    define('IDNA_ERROR_BIDI', 2048);\n}\nif (!defined('IDNA_ERROR_CONTEXTJ')) {\n    define('IDNA_ERROR_CONTEXTJ', 4096);\n}\n\nif (!function_exists('idn_to_ascii')) {\n    function idn_to_ascii(?string $domain, ?int $flags = IDNA_DEFAULT, ?int $variant = INTL_IDNA_VARIANT_UTS46, &$idna_info = null): string|false { return p\\Idn::idn_to_ascii((string) $domain, (int) $flags, (int) $variant, $idna_info); }\n}\nif (!function_exists('idn_to_utf8')) {\n    function idn_to_utf8(?string $domain, ?int $flags = IDNA_DEFAULT, ?int $variant = INTL_IDNA_VARIANT_UTS46, &$idna_info = null): string|false { return p\\Idn::idn_to_utf8((string) $domain, (int) $flags, (int) $variant, $idna_info); }\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-intl-idn/composer.json",
    "content": "{\n    \"name\": \"symfony/polyfill-intl-idn\",\n    \"type\": \"library\",\n    \"description\": \"Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions\",\n    \"keywords\": [\"polyfill\", \"shim\", \"compatibility\", \"portable\", \"intl\", \"idn\"],\n    \"homepage\": \"https://symfony.com\",\n    \"license\": \"MIT\",\n    \"authors\": [\n        {\n            \"name\": \"Laurent Bassin\",\n            \"email\": \"laurent@bassin.info\"\n        },\n        {\n            \"name\": \"Trevor Rowbotham\",\n            \"email\": \"trevor.rowbotham@pm.me\"\n        },\n        {\n            \"name\": \"Symfony Community\",\n            \"homepage\": \"https://symfony.com/contributors\"\n        }\n    ],\n    \"require\": {\n        \"php\": \">=7.2\",\n        \"symfony/polyfill-intl-normalizer\": \"^1.10\"\n    },\n    \"autoload\": {\n        \"psr-4\": { \"Symfony\\\\Polyfill\\\\Intl\\\\Idn\\\\\": \"\" },\n        \"files\": [ \"bootstrap.php\" ]\n    },\n    \"suggest\": {\n        \"ext-intl\": \"For best performance\"\n    },\n    \"minimum-stability\": \"dev\",\n    \"extra\": {\n        \"thanks\": {\n            \"name\": \"symfony/polyfill\",\n            \"url\": \"https://github.com/symfony/polyfill\"\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-intl-normalizer/LICENSE",
    "content": "Copyright (c) 2015-present Fabien Potencier\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is furnished\nto do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-intl-normalizer/Normalizer.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Polyfill\\Intl\\Normalizer;\n\n/**\n * Normalizer is a PHP fallback implementation of the Normalizer class provided by the intl extension.\n *\n * It has been validated with Unicode 6.3 Normalization Conformance Test.\n * See http://www.unicode.org/reports/tr15/ for detailed info about Unicode normalizations.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n *\n * @internal\n */\nclass Normalizer\n{\n    public const FORM_D = \\Normalizer::FORM_D;\n    public const FORM_KD = \\Normalizer::FORM_KD;\n    public const FORM_C = \\Normalizer::FORM_C;\n    public const FORM_KC = \\Normalizer::FORM_KC;\n    public const NFD = \\Normalizer::NFD;\n    public const NFKD = \\Normalizer::NFKD;\n    public const NFC = \\Normalizer::NFC;\n    public const NFKC = \\Normalizer::NFKC;\n\n    private static $C;\n    private static $D;\n    private static $KD;\n    private static $cC;\n    private static $ulenMask = [\"\\xC0\" => 2, \"\\xD0\" => 2, \"\\xE0\" => 3, \"\\xF0\" => 4];\n    private static $ASCII = \"\\x20\\x65\\x69\\x61\\x73\\x6E\\x74\\x72\\x6F\\x6C\\x75\\x64\\x5D\\x5B\\x63\\x6D\\x70\\x27\\x0A\\x67\\x7C\\x68\\x76\\x2E\\x66\\x62\\x2C\\x3A\\x3D\\x2D\\x71\\x31\\x30\\x43\\x32\\x2A\\x79\\x78\\x29\\x28\\x4C\\x39\\x41\\x53\\x2F\\x50\\x22\\x45\\x6A\\x4D\\x49\\x6B\\x33\\x3E\\x35\\x54\\x3C\\x44\\x34\\x7D\\x42\\x7B\\x38\\x46\\x77\\x52\\x36\\x37\\x55\\x47\\x4E\\x3B\\x4A\\x7A\\x56\\x23\\x48\\x4F\\x57\\x5F\\x26\\x21\\x4B\\x3F\\x58\\x51\\x25\\x59\\x5C\\x09\\x5A\\x2B\\x7E\\x5E\\x24\\x40\\x60\\x7F\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\x0B\\x0C\\x0D\\x0E\\x0F\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1A\\x1B\\x1C\\x1D\\x1E\\x1F\";\n\n    public static function isNormalized(string $s, int $form = self::FORM_C)\n    {\n        if (!\\in_array($form, [self::NFD, self::NFKD, self::NFC, self::NFKC])) {\n            return false;\n        }\n        if (!isset($s[strspn($s, self::$ASCII)])) {\n            return true;\n        }\n        if (self::NFC == $form && preg_match('//u', $s) && !preg_match('/[^\\x00-\\x{2FF}]/u', $s)) {\n            return true;\n        }\n\n        return self::normalize($s, $form) === $s;\n    }\n\n    public static function normalize(string $s, int $form = self::FORM_C)\n    {\n        if (!preg_match('//u', $s)) {\n            return false;\n        }\n\n        switch ($form) {\n            case self::NFC: $C = true; $K = false; break;\n            case self::NFD: $C = false; $K = false; break;\n            case self::NFKC: $C = true; $K = true; break;\n            case self::NFKD: $C = false; $K = true; break;\n            default:\n                if (\\defined('Normalizer::NONE') && \\Normalizer::NONE == $form) {\n                    return $s;\n                }\n\n                if (80000 > \\PHP_VERSION_ID) {\n                    return false;\n                }\n\n                throw new \\ValueError('normalizer_normalize(): Argument #2 ($form) must be a a valid normalization form');\n        }\n\n        if ('' === $s) {\n            return '';\n        }\n\n        if ($K && null === self::$KD) {\n            self::$KD = self::getData('compatibilityDecomposition');\n        }\n\n        if (null === self::$D) {\n            self::$D = self::getData('canonicalDecomposition');\n            self::$cC = self::getData('combiningClass');\n        }\n\n        if (null !== $mbEncoding = (2 /* MB_OVERLOAD_STRING */ & (int) \\ini_get('mbstring.func_overload')) ? mb_internal_encoding() : null) {\n            mb_internal_encoding('8bit');\n        }\n\n        $r = self::decompose($s, $K);\n\n        if ($C) {\n            if (null === self::$C) {\n                self::$C = self::getData('canonicalComposition');\n            }\n\n            $r = self::recompose($r);\n        }\n        if (null !== $mbEncoding) {\n            mb_internal_encoding($mbEncoding);\n        }\n\n        return $r;\n    }\n\n    private static function recompose($s)\n    {\n        $ASCII = self::$ASCII;\n        $compMap = self::$C;\n        $combClass = self::$cC;\n        $ulenMask = self::$ulenMask;\n\n        $result = $tail = '';\n\n        $i = $s[0] < \"\\x80\" ? 1 : $ulenMask[$s[0] & \"\\xF0\"];\n        $len = \\strlen($s);\n\n        $lastUchr = substr($s, 0, $i);\n        $lastUcls = isset($combClass[$lastUchr]) ? 256 : 0;\n\n        while ($i < $len) {\n            if ($s[$i] < \"\\x80\") {\n                // ASCII chars\n\n                if ($tail) {\n                    $lastUchr .= $tail;\n                    $tail = '';\n                }\n\n                if ($j = strspn($s, $ASCII, $i + 1)) {\n                    $lastUchr .= substr($s, $i, $j);\n                    $i += $j;\n                }\n\n                $result .= $lastUchr;\n                $lastUchr = $s[$i];\n                $lastUcls = 0;\n                ++$i;\n                continue;\n            }\n\n            $ulen = $ulenMask[$s[$i] & \"\\xF0\"];\n            $uchr = substr($s, $i, $ulen);\n\n            if ($lastUchr < \"\\xE1\\x84\\x80\" || \"\\xE1\\x84\\x92\" < $lastUchr\n                || $uchr < \"\\xE1\\x85\\xA1\" || \"\\xE1\\x85\\xB5\" < $uchr\n                || $lastUcls) {\n                // Table lookup and combining chars composition\n\n                $ucls = $combClass[$uchr] ?? 0;\n\n                if (isset($compMap[$lastUchr.$uchr]) && (!$lastUcls || $lastUcls < $ucls)) {\n                    $lastUchr = $compMap[$lastUchr.$uchr];\n                } elseif ($lastUcls = $ucls) {\n                    $tail .= $uchr;\n                } else {\n                    if ($tail) {\n                        $lastUchr .= $tail;\n                        $tail = '';\n                    }\n\n                    $result .= $lastUchr;\n                    $lastUchr = $uchr;\n                }\n            } else {\n                // Hangul chars\n\n                $L = \\ord($lastUchr[2]) - 0x80;\n                $V = \\ord($uchr[2]) - 0xA1;\n                $T = 0;\n\n                $uchr = substr($s, $i + $ulen, 3);\n\n                if (\"\\xE1\\x86\\xA7\" <= $uchr && $uchr <= \"\\xE1\\x87\\x82\") {\n                    $T = \\ord($uchr[2]) - 0xA7;\n                    0 > $T && $T += 0x40;\n                    $ulen += 3;\n                }\n\n                $L = 0xAC00 + ($L * 21 + $V) * 28 + $T;\n                $lastUchr = \\chr(0xE0 | $L >> 12).\\chr(0x80 | $L >> 6 & 0x3F).\\chr(0x80 | $L & 0x3F);\n            }\n\n            $i += $ulen;\n        }\n\n        return $result.$lastUchr.$tail;\n    }\n\n    private static function decompose($s, $c)\n    {\n        $result = '';\n\n        $ASCII = self::$ASCII;\n        $decompMap = self::$D;\n        $combClass = self::$cC;\n        $ulenMask = self::$ulenMask;\n        if ($c) {\n            $compatMap = self::$KD;\n        }\n\n        $c = [];\n        $i = 0;\n        $len = \\strlen($s);\n\n        while ($i < $len) {\n            if ($s[$i] < \"\\x80\") {\n                // ASCII chars\n\n                if ($c) {\n                    ksort($c);\n                    $result .= implode('', $c);\n                    $c = [];\n                }\n\n                $j = 1 + strspn($s, $ASCII, $i + 1);\n                $result .= substr($s, $i, $j);\n                $i += $j;\n                continue;\n            }\n\n            $ulen = $ulenMask[$s[$i] & \"\\xF0\"];\n            $uchr = substr($s, $i, $ulen);\n            $i += $ulen;\n\n            if ($uchr < \"\\xEA\\xB0\\x80\" || \"\\xED\\x9E\\xA3\" < $uchr) {\n                // Table lookup\n\n                if ($uchr !== $j = $compatMap[$uchr] ?? ($decompMap[$uchr] ?? $uchr)) {\n                    $uchr = $j;\n\n                    $j = \\strlen($uchr);\n                    $ulen = $uchr[0] < \"\\x80\" ? 1 : $ulenMask[$uchr[0] & \"\\xF0\"];\n\n                    if ($ulen != $j) {\n                        // Put trailing chars in $s\n\n                        $j -= $ulen;\n                        $i -= $j;\n\n                        if (0 > $i) {\n                            $s = str_repeat(' ', -$i).$s;\n                            $len -= $i;\n                            $i = 0;\n                        }\n\n                        while ($j--) {\n                            $s[$i + $j] = $uchr[$ulen + $j];\n                        }\n\n                        $uchr = substr($uchr, 0, $ulen);\n                    }\n                }\n                if (isset($combClass[$uchr])) {\n                    // Combining chars, for sorting\n\n                    if (!isset($c[$combClass[$uchr]])) {\n                        $c[$combClass[$uchr]] = '';\n                    }\n                    $c[$combClass[$uchr]] .= $uchr;\n                    continue;\n                }\n            } else {\n                // Hangul chars\n\n                $uchr = unpack('C*', $uchr);\n                $j = (($uchr[1] - 224) << 12) + (($uchr[2] - 128) << 6) + $uchr[3] - 0xAC80;\n\n                $uchr = \"\\xE1\\x84\".\\chr(0x80 + (int) ($j / 588))\n                       .\"\\xE1\\x85\".\\chr(0xA1 + (int) (($j % 588) / 28));\n\n                if ($j %= 28) {\n                    $uchr .= $j < 25\n                        ? (\"\\xE1\\x86\".\\chr(0xA7 + $j))\n                        : (\"\\xE1\\x87\".\\chr(0x67 + $j));\n                }\n            }\n            if ($c) {\n                ksort($c);\n                $result .= implode('', $c);\n                $c = [];\n            }\n\n            $result .= $uchr;\n        }\n\n        if ($c) {\n            ksort($c);\n            $result .= implode('', $c);\n        }\n\n        return $result;\n    }\n\n    private static function getData($file)\n    {\n        if (file_exists($file = __DIR__.'/Resources/unidata/'.$file.'.php')) {\n            return require $file;\n        }\n\n        return false;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-intl-normalizer/README.md",
    "content": "Symfony Polyfill / Intl: Normalizer\n===================================\n\nThis component provides a fallback implementation for the\n[`Normalizer`](https://php.net/Normalizer) class provided\nby the [Intl](https://php.net/intl) extension.\n\nMore information can be found in the\n[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md).\n\nLicense\n=======\n\nThis library is released under the [MIT license](LICENSE).\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php",
    "content": "<?php\n\nclass Normalizer extends Symfony\\Polyfill\\Intl\\Normalizer\\Normalizer\n{\n    /**\n     * @deprecated since ICU 56 and removed in PHP 8\n     */\n    public const NONE = 2;\n    public const FORM_D = 4;\n    public const FORM_KD = 8;\n    public const FORM_C = 16;\n    public const FORM_KC = 32;\n    public const NFD = 4;\n    public const NFKD = 8;\n    public const NFC = 16;\n    public const NFKC = 32;\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalComposition.php",
    "content": "<?php\n\nreturn array (\n  'À' => 'À',\n  'Á' => 'Á',\n  'Â' => 'Â',\n  'Ã' => 'Ã',\n  'Ä' => 'Ä',\n  'Å' => 'Å',\n  'Ç' => 'Ç',\n  'È' => 'È',\n  'É' => 'É',\n  'Ê' => 'Ê',\n  'Ë' => 'Ë',\n  'Ì' => 'Ì',\n  'Í' => 'Í',\n  'Î' => 'Î',\n  'Ï' => 'Ï',\n  'Ñ' => 'Ñ',\n  'Ò' => 'Ò',\n  'Ó' => 'Ó',\n  'Ô' => 'Ô',\n  'Õ' => 'Õ',\n  'Ö' => 'Ö',\n  'Ù' => 'Ù',\n  'Ú' => 'Ú',\n  'Û' => 'Û',\n  'Ü' => 'Ü',\n  'Ý' => 'Ý',\n  'à' => 'à',\n  'á' => 'á',\n  'â' => 'â',\n  'ã' => 'ã',\n  'ä' => 'ä',\n  'å' => 'å',\n  'ç' => 'ç',\n  'è' => 'è',\n  'é' => 'é',\n  'ê' => 'ê',\n  'ë' => 'ë',\n  'ì' => 'ì',\n  'í' => 'í',\n  'î' => 'î',\n  'ï' => 'ï',\n  'ñ' => 'ñ',\n  'ò' => 'ò',\n  'ó' => 'ó',\n  'ô' => 'ô',\n  'õ' => 'õ',\n  'ö' => 'ö',\n  'ù' => 'ù',\n  'ú' => 'ú',\n  'û' => 'û',\n  'ü' => 'ü',\n  'ý' => 'ý',\n  'ÿ' => 'ÿ',\n  'Ā' => 'Ā',\n  'ā' => 'ā',\n  'Ă' => 'Ă',\n  'ă' => 'ă',\n  'Ą' => 'Ą',\n  'ą' => 'ą',\n  'Ć' => 'Ć',\n  'ć' => 'ć',\n  'Ĉ' => 'Ĉ',\n  'ĉ' => 'ĉ',\n  'Ċ' => 'Ċ',\n  'ċ' => 'ċ',\n  'Č' => 'Č',\n  'č' => 'č',\n  'Ď' => 'Ď',\n  'ď' => 'ď',\n  'Ē' => 'Ē',\n  'ē' => 'ē',\n  'Ĕ' => 'Ĕ',\n  'ĕ' => 'ĕ',\n  'Ė' => 'Ė',\n  'ė' => 'ė',\n  'Ę' => 'Ę',\n  'ę' => 'ę',\n  'Ě' => 'Ě',\n  'ě' => 'ě',\n  'Ĝ' => 'Ĝ',\n  'ĝ' => 'ĝ',\n  'Ğ' => 'Ğ',\n  'ğ' => 'ğ',\n  'Ġ' => 'Ġ',\n  'ġ' => 'ġ',\n  'Ģ' => 'Ģ',\n  'ģ' => 'ģ',\n  'Ĥ' => 'Ĥ',\n  'ĥ' => 'ĥ',\n  'Ĩ' => 'Ĩ',\n  'ĩ' => 'ĩ',\n  'Ī' => 'Ī',\n  'ī' => 'ī',\n  'Ĭ' => 'Ĭ',\n  'ĭ' => 'ĭ',\n  'Į' => 'Į',\n  'į' => 'į',\n  'İ' => 'İ',\n  'Ĵ' => 'Ĵ',\n  'ĵ' => 'ĵ',\n  'Ķ' => 'Ķ',\n  'ķ' => 'ķ',\n  'Ĺ' => 'Ĺ',\n  'ĺ' => 'ĺ',\n  'Ļ' => 'Ļ',\n  'ļ' => 'ļ',\n  'Ľ' => 'Ľ',\n  'ľ' => 'ľ',\n  'Ń' => 'Ń',\n  'ń' => 'ń',\n  'Ņ' => 'Ņ',\n  'ņ' => 'ņ',\n  'Ň' => 'Ň',\n  'ň' => 'ň',\n  'Ō' => 'Ō',\n  'ō' => 'ō',\n  'Ŏ' => 'Ŏ',\n  'ŏ' => 'ŏ',\n  'Ő' => 'Ő',\n  'ő' => 'ő',\n  'Ŕ' => 'Ŕ',\n  'ŕ' => 'ŕ',\n  'Ŗ' => 'Ŗ',\n  'ŗ' => 'ŗ',\n  'Ř' => 'Ř',\n  'ř' => 'ř',\n  'Ś' => 'Ś',\n  'ś' => 'ś',\n  'Ŝ' => 'Ŝ',\n  'ŝ' => 'ŝ',\n  'Ş' => 'Ş',\n  'ş' => 'ş',\n  'Š' => 'Š',\n  'š' => 'š',\n  'Ţ' => 'Ţ',\n  'ţ' => 'ţ',\n  'Ť' => 'Ť',\n  'ť' => 'ť',\n  'Ũ' => 'Ũ',\n  'ũ' => 'ũ',\n  'Ū' => 'Ū',\n  'ū' => 'ū',\n  'Ŭ' => 'Ŭ',\n  'ŭ' => 'ŭ',\n  'Ů' => 'Ů',\n  'ů' => 'ů',\n  'Ű' => 'Ű',\n  'ű' => 'ű',\n  'Ų' => 'Ų',\n  'ų' => 'ų',\n  'Ŵ' => 'Ŵ',\n  'ŵ' => 'ŵ',\n  'Ŷ' => 'Ŷ',\n  'ŷ' => 'ŷ',\n  'Ÿ' => 'Ÿ',\n  'Ź' => 'Ź',\n  'ź' => 'ź',\n  'Ż' => 'Ż',\n  'ż' => 'ż',\n  'Ž' => 'Ž',\n  'ž' => 'ž',\n  'Ơ' => 'Ơ',\n  'ơ' => 'ơ',\n  'Ư' => 'Ư',\n  'ư' => 'ư',\n  'Ǎ' => 'Ǎ',\n  'ǎ' => 'ǎ',\n  'Ǐ' => 'Ǐ',\n  'ǐ' => 'ǐ',\n  'Ǒ' => 'Ǒ',\n  'ǒ' => 'ǒ',\n  'Ǔ' => 'Ǔ',\n  'ǔ' => 'ǔ',\n  'Ǖ' => 'Ǖ',\n  'ǖ' => 'ǖ',\n  'Ǘ' => 'Ǘ',\n  'ǘ' => 'ǘ',\n  'Ǚ' => 'Ǚ',\n  'ǚ' => 'ǚ',\n  'Ǜ' => 'Ǜ',\n  'ǜ' => 'ǜ',\n  'Ǟ' => 'Ǟ',\n  'ǟ' => 'ǟ',\n  'Ǡ' => 'Ǡ',\n  'ǡ' => 'ǡ',\n  'Ǣ' => 'Ǣ',\n  'ǣ' => 'ǣ',\n  'Ǧ' => 'Ǧ',\n  'ǧ' => 'ǧ',\n  'Ǩ' => 'Ǩ',\n  'ǩ' => 'ǩ',\n  'Ǫ' => 'Ǫ',\n  'ǫ' => 'ǫ',\n  'Ǭ' => 'Ǭ',\n  'ǭ' => 'ǭ',\n  'Ǯ' => 'Ǯ',\n  'ǯ' => 'ǯ',\n  'ǰ' => 'ǰ',\n  'Ǵ' => 'Ǵ',\n  'ǵ' => 'ǵ',\n  'Ǹ' => 'Ǹ',\n  'ǹ' => 'ǹ',\n  'Ǻ' => 'Ǻ',\n  'ǻ' => 'ǻ',\n  'Ǽ' => 'Ǽ',\n  'ǽ' => 'ǽ',\n  'Ǿ' => 'Ǿ',\n  'ǿ' => 'ǿ',\n  'Ȁ' => 'Ȁ',\n  'ȁ' => 'ȁ',\n  'Ȃ' => 'Ȃ',\n  'ȃ' => 'ȃ',\n  'Ȅ' => 'Ȅ',\n  'ȅ' => 'ȅ',\n  'Ȇ' => 'Ȇ',\n  'ȇ' => 'ȇ',\n  'Ȉ' => 'Ȉ',\n  'ȉ' => 'ȉ',\n  'Ȋ' => 'Ȋ',\n  'ȋ' => 'ȋ',\n  'Ȍ' => 'Ȍ',\n  'ȍ' => 'ȍ',\n  'Ȏ' => 'Ȏ',\n  'ȏ' => 'ȏ',\n  'Ȑ' => 'Ȑ',\n  'ȑ' => 'ȑ',\n  'Ȓ' => 'Ȓ',\n  'ȓ' => 'ȓ',\n  'Ȕ' => 'Ȕ',\n  'ȕ' => 'ȕ',\n  'Ȗ' => 'Ȗ',\n  'ȗ' => 'ȗ',\n  'Ș' => 'Ș',\n  'ș' => 'ș',\n  'Ț' => 'Ț',\n  'ț' => 'ț',\n  'Ȟ' => 'Ȟ',\n  'ȟ' => 'ȟ',\n  'Ȧ' => 'Ȧ',\n  'ȧ' => 'ȧ',\n  'Ȩ' => 'Ȩ',\n  'ȩ' => 'ȩ',\n  'Ȫ' => 'Ȫ',\n  'ȫ' => 'ȫ',\n  'Ȭ' => 'Ȭ',\n  'ȭ' => 'ȭ',\n  'Ȯ' => 'Ȯ',\n  'ȯ' => 'ȯ',\n  'Ȱ' => 'Ȱ',\n  'ȱ' => 'ȱ',\n  'Ȳ' => 'Ȳ',\n  'ȳ' => 'ȳ',\n  '΅' => '΅',\n  'Ά' => 'Ά',\n  'Έ' => 'Έ',\n  'Ή' => 'Ή',\n  'Ί' => 'Ί',\n  'Ό' => 'Ό',\n  'Ύ' => 'Ύ',\n  'Ώ' => 'Ώ',\n  'ΐ' => 'ΐ',\n  'Ϊ' => 'Ϊ',\n  'Ϋ' => 'Ϋ',\n  'ά' => 'ά',\n  'έ' => 'έ',\n  'ή' => 'ή',\n  'ί' => 'ί',\n  'ΰ' => 'ΰ',\n  'ϊ' => 'ϊ',\n  'ϋ' => 'ϋ',\n  'ό' => 'ό',\n  'ύ' => 'ύ',\n  'ώ' => 'ώ',\n  'ϓ' => 'ϓ',\n  'ϔ' => 'ϔ',\n  'Ѐ' => 'Ѐ',\n  'Ё' => 'Ё',\n  'Ѓ' => 'Ѓ',\n  'Ї' => 'Ї',\n  'Ќ' => 'Ќ',\n  'Ѝ' => 'Ѝ',\n  'Ў' => 'Ў',\n  'Й' => 'Й',\n  'й' => 'й',\n  'ѐ' => 'ѐ',\n  'ё' => 'ё',\n  'ѓ' => 'ѓ',\n  'ї' => 'ї',\n  'ќ' => 'ќ',\n  'ѝ' => 'ѝ',\n  'ў' => 'ў',\n  'Ѷ' => 'Ѷ',\n  'ѷ' => 'ѷ',\n  'Ӂ' => 'Ӂ',\n  'ӂ' => 'ӂ',\n  'Ӑ' => 'Ӑ',\n  'ӑ' => 'ӑ',\n  'Ӓ' => 'Ӓ',\n  'ӓ' => 'ӓ',\n  'Ӗ' => 'Ӗ',\n  'ӗ' => 'ӗ',\n  'Ӛ' => 'Ӛ',\n  'ӛ' => 'ӛ',\n  'Ӝ' => 'Ӝ',\n  'ӝ' => 'ӝ',\n  'Ӟ' => 'Ӟ',\n  'ӟ' => 'ӟ',\n  'Ӣ' => 'Ӣ',\n  'ӣ' => 'ӣ',\n  'Ӥ' => 'Ӥ',\n  'ӥ' => 'ӥ',\n  'Ӧ' => 'Ӧ',\n  'ӧ' => 'ӧ',\n  'Ӫ' => 'Ӫ',\n  'ӫ' => 'ӫ',\n  'Ӭ' => 'Ӭ',\n  'ӭ' => 'ӭ',\n  'Ӯ' => 'Ӯ',\n  'ӯ' => 'ӯ',\n  'Ӱ' => 'Ӱ',\n  'ӱ' => 'ӱ',\n  'Ӳ' => 'Ӳ',\n  'ӳ' => 'ӳ',\n  'Ӵ' => 'Ӵ',\n  'ӵ' => 'ӵ',\n  'Ӹ' => 'Ӹ',\n  'ӹ' => 'ӹ',\n  'آ' => 'آ',\n  'أ' => 'أ',\n  'ؤ' => 'ؤ',\n  'إ' => 'إ',\n  'ئ' => 'ئ',\n  'ۀ' => 'ۀ',\n  'ۂ' => 'ۂ',\n  'ۓ' => 'ۓ',\n  'ऩ' => 'ऩ',\n  'ऱ' => 'ऱ',\n  'ऴ' => 'ऴ',\n  'ো' => 'ো',\n  'ৌ' => 'ৌ',\n  'ୈ' => 'ୈ',\n  'ୋ' => 'ୋ',\n  'ୌ' => 'ୌ',\n  'ஔ' => 'ஔ',\n  'ொ' => 'ொ',\n  'ோ' => 'ோ',\n  'ௌ' => 'ௌ',\n  'ై' => 'ై',\n  'ೀ' => 'ೀ',\n  'ೇ' => 'ೇ',\n  'ೈ' => 'ೈ',\n  'ೊ' => 'ೊ',\n  'ೋ' => 'ೋ',\n  'ൊ' => 'ൊ',\n  'ോ' => 'ോ',\n  'ൌ' => 'ൌ',\n  'ේ' => 'ේ',\n  'ො' => 'ො',\n  'ෝ' => 'ෝ',\n  'ෞ' => 'ෞ',\n  'ဦ' => 'ဦ',\n  'ᬆ' => 'ᬆ',\n  'ᬈ' => 'ᬈ',\n  'ᬊ' => 'ᬊ',\n  'ᬌ' => 'ᬌ',\n  'ᬎ' => 'ᬎ',\n  'ᬒ' => 'ᬒ',\n  'ᬻ' => 'ᬻ',\n  'ᬽ' => 'ᬽ',\n  'ᭀ' => 'ᭀ',\n  'ᭁ' => 'ᭁ',\n  'ᭃ' => 'ᭃ',\n  'Ḁ' => 'Ḁ',\n  'ḁ' => 'ḁ',\n  'Ḃ' => 'Ḃ',\n  'ḃ' => 'ḃ',\n  'Ḅ' => 'Ḅ',\n  'ḅ' => 'ḅ',\n  'Ḇ' => 'Ḇ',\n  'ḇ' => 'ḇ',\n  'Ḉ' => 'Ḉ',\n  'ḉ' => 'ḉ',\n  'Ḋ' => 'Ḋ',\n  'ḋ' => 'ḋ',\n  'Ḍ' => 'Ḍ',\n  'ḍ' => 'ḍ',\n  'Ḏ' => 'Ḏ',\n  'ḏ' => 'ḏ',\n  'Ḑ' => 'Ḑ',\n  'ḑ' => 'ḑ',\n  'Ḓ' => 'Ḓ',\n  'ḓ' => 'ḓ',\n  'Ḕ' => 'Ḕ',\n  'ḕ' => 'ḕ',\n  'Ḗ' => 'Ḗ',\n  'ḗ' => 'ḗ',\n  'Ḙ' => 'Ḙ',\n  'ḙ' => 'ḙ',\n  'Ḛ' => 'Ḛ',\n  'ḛ' => 'ḛ',\n  'Ḝ' => 'Ḝ',\n  'ḝ' => 'ḝ',\n  'Ḟ' => 'Ḟ',\n  'ḟ' => 'ḟ',\n  'Ḡ' => 'Ḡ',\n  'ḡ' => 'ḡ',\n  'Ḣ' => 'Ḣ',\n  'ḣ' => 'ḣ',\n  'Ḥ' => 'Ḥ',\n  'ḥ' => 'ḥ',\n  'Ḧ' => 'Ḧ',\n  'ḧ' => 'ḧ',\n  'Ḩ' => 'Ḩ',\n  'ḩ' => 'ḩ',\n  'Ḫ' => 'Ḫ',\n  'ḫ' => 'ḫ',\n  'Ḭ' => 'Ḭ',\n  'ḭ' => 'ḭ',\n  'Ḯ' => 'Ḯ',\n  'ḯ' => 'ḯ',\n  'Ḱ' => 'Ḱ',\n  'ḱ' => 'ḱ',\n  'Ḳ' => 'Ḳ',\n  'ḳ' => 'ḳ',\n  'Ḵ' => 'Ḵ',\n  'ḵ' => 'ḵ',\n  'Ḷ' => 'Ḷ',\n  'ḷ' => 'ḷ',\n  'Ḹ' => 'Ḹ',\n  'ḹ' => 'ḹ',\n  'Ḻ' => 'Ḻ',\n  'ḻ' => 'ḻ',\n  'Ḽ' => 'Ḽ',\n  'ḽ' => 'ḽ',\n  'Ḿ' => 'Ḿ',\n  'ḿ' => 'ḿ',\n  'Ṁ' => 'Ṁ',\n  'ṁ' => 'ṁ',\n  'Ṃ' => 'Ṃ',\n  'ṃ' => 'ṃ',\n  'Ṅ' => 'Ṅ',\n  'ṅ' => 'ṅ',\n  'Ṇ' => 'Ṇ',\n  'ṇ' => 'ṇ',\n  'Ṉ' => 'Ṉ',\n  'ṉ' => 'ṉ',\n  'Ṋ' => 'Ṋ',\n  'ṋ' => 'ṋ',\n  'Ṍ' => 'Ṍ',\n  'ṍ' => 'ṍ',\n  'Ṏ' => 'Ṏ',\n  'ṏ' => 'ṏ',\n  'Ṑ' => 'Ṑ',\n  'ṑ' => 'ṑ',\n  'Ṓ' => 'Ṓ',\n  'ṓ' => 'ṓ',\n  'Ṕ' => 'Ṕ',\n  'ṕ' => 'ṕ',\n  'Ṗ' => 'Ṗ',\n  'ṗ' => 'ṗ',\n  'Ṙ' => 'Ṙ',\n  'ṙ' => 'ṙ',\n  'Ṛ' => 'Ṛ',\n  'ṛ' => 'ṛ',\n  'Ṝ' => 'Ṝ',\n  'ṝ' => 'ṝ',\n  'Ṟ' => 'Ṟ',\n  'ṟ' => 'ṟ',\n  'Ṡ' => 'Ṡ',\n  'ṡ' => 'ṡ',\n  'Ṣ' => 'Ṣ',\n  'ṣ' => 'ṣ',\n  'Ṥ' => 'Ṥ',\n  'ṥ' => 'ṥ',\n  'Ṧ' => 'Ṧ',\n  'ṧ' => 'ṧ',\n  'Ṩ' => 'Ṩ',\n  'ṩ' => 'ṩ',\n  'Ṫ' => 'Ṫ',\n  'ṫ' => 'ṫ',\n  'Ṭ' => 'Ṭ',\n  'ṭ' => 'ṭ',\n  'Ṯ' => 'Ṯ',\n  'ṯ' => 'ṯ',\n  'Ṱ' => 'Ṱ',\n  'ṱ' => 'ṱ',\n  'Ṳ' => 'Ṳ',\n  'ṳ' => 'ṳ',\n  'Ṵ' => 'Ṵ',\n  'ṵ' => 'ṵ',\n  'Ṷ' => 'Ṷ',\n  'ṷ' => 'ṷ',\n  'Ṹ' => 'Ṹ',\n  'ṹ' => 'ṹ',\n  'Ṻ' => 'Ṻ',\n  'ṻ' => 'ṻ',\n  'Ṽ' => 'Ṽ',\n  'ṽ' => 'ṽ',\n  'Ṿ' => 'Ṿ',\n  'ṿ' => 'ṿ',\n  'Ẁ' => 'Ẁ',\n  'ẁ' => 'ẁ',\n  'Ẃ' => 'Ẃ',\n  'ẃ' => 'ẃ',\n  'Ẅ' => 'Ẅ',\n  'ẅ' => 'ẅ',\n  'Ẇ' => 'Ẇ',\n  'ẇ' => 'ẇ',\n  'Ẉ' => 'Ẉ',\n  'ẉ' => 'ẉ',\n  'Ẋ' => 'Ẋ',\n  'ẋ' => 'ẋ',\n  'Ẍ' => 'Ẍ',\n  'ẍ' => 'ẍ',\n  'Ẏ' => 'Ẏ',\n  'ẏ' => 'ẏ',\n  'Ẑ' => 'Ẑ',\n  'ẑ' => 'ẑ',\n  'Ẓ' => 'Ẓ',\n  'ẓ' => 'ẓ',\n  'Ẕ' => 'Ẕ',\n  'ẕ' => 'ẕ',\n  'ẖ' => 'ẖ',\n  'ẗ' => 'ẗ',\n  'ẘ' => 'ẘ',\n  'ẙ' => 'ẙ',\n  'ẛ' => 'ẛ',\n  'Ạ' => 'Ạ',\n  'ạ' => 'ạ',\n  'Ả' => 'Ả',\n  'ả' => 'ả',\n  'Ấ' => 'Ấ',\n  'ấ' => 'ấ',\n  'Ầ' => 'Ầ',\n  'ầ' => 'ầ',\n  'Ẩ' => 'Ẩ',\n  'ẩ' => 'ẩ',\n  'Ẫ' => 'Ẫ',\n  'ẫ' => 'ẫ',\n  'Ậ' => 'Ậ',\n  'ậ' => 'ậ',\n  'Ắ' => 'Ắ',\n  'ắ' => 'ắ',\n  'Ằ' => 'Ằ',\n  'ằ' => 'ằ',\n  'Ẳ' => 'Ẳ',\n  'ẳ' => 'ẳ',\n  'Ẵ' => 'Ẵ',\n  'ẵ' => 'ẵ',\n  'Ặ' => 'Ặ',\n  'ặ' => 'ặ',\n  'Ẹ' => 'Ẹ',\n  'ẹ' => 'ẹ',\n  'Ẻ' => 'Ẻ',\n  'ẻ' => 'ẻ',\n  'Ẽ' => 'Ẽ',\n  'ẽ' => 'ẽ',\n  'Ế' => 'Ế',\n  'ế' => 'ế',\n  'Ề' => 'Ề',\n  'ề' => 'ề',\n  'Ể' => 'Ể',\n  'ể' => 'ể',\n  'Ễ' => 'Ễ',\n  'ễ' => 'ễ',\n  'Ệ' => 'Ệ',\n  'ệ' => 'ệ',\n  'Ỉ' => 'Ỉ',\n  'ỉ' => 'ỉ',\n  'Ị' => 'Ị',\n  'ị' => 'ị',\n  'Ọ' => 'Ọ',\n  'ọ' => 'ọ',\n  'Ỏ' => 'Ỏ',\n  'ỏ' => 'ỏ',\n  'Ố' => 'Ố',\n  'ố' => 'ố',\n  'Ồ' => 'Ồ',\n  'ồ' => 'ồ',\n  'Ổ' => 'Ổ',\n  'ổ' => 'ổ',\n  'Ỗ' => 'Ỗ',\n  'ỗ' => 'ỗ',\n  'Ộ' => 'Ộ',\n  'ộ' => 'ộ',\n  'Ớ' => 'Ớ',\n  'ớ' => 'ớ',\n  'Ờ' => 'Ờ',\n  'ờ' => 'ờ',\n  'Ở' => 'Ở',\n  'ở' => 'ở',\n  'Ỡ' => 'Ỡ',\n  'ỡ' => 'ỡ',\n  'Ợ' => 'Ợ',\n  'ợ' => 'ợ',\n  'Ụ' => 'Ụ',\n  'ụ' => 'ụ',\n  'Ủ' => 'Ủ',\n  'ủ' => 'ủ',\n  'Ứ' => 'Ứ',\n  'ứ' => 'ứ',\n  'Ừ' => 'Ừ',\n  'ừ' => 'ừ',\n  'Ử' => 'Ử',\n  'ử' => 'ử',\n  'Ữ' => 'Ữ',\n  'ữ' => 'ữ',\n  'Ự' => 'Ự',\n  'ự' => 'ự',\n  'Ỳ' => 'Ỳ',\n  'ỳ' => 'ỳ',\n  'Ỵ' => 'Ỵ',\n  'ỵ' => 'ỵ',\n  'Ỷ' => 'Ỷ',\n  'ỷ' => 'ỷ',\n  'Ỹ' => 'Ỹ',\n  'ỹ' => 'ỹ',\n  'ἀ' => 'ἀ',\n  'ἁ' => 'ἁ',\n  'ἂ' => 'ἂ',\n  'ἃ' => 'ἃ',\n  'ἄ' => 'ἄ',\n  'ἅ' => 'ἅ',\n  'ἆ' => 'ἆ',\n  'ἇ' => 'ἇ',\n  'Ἀ' => 'Ἀ',\n  'Ἁ' => 'Ἁ',\n  'Ἂ' => 'Ἂ',\n  'Ἃ' => 'Ἃ',\n  'Ἄ' => 'Ἄ',\n  'Ἅ' => 'Ἅ',\n  'Ἆ' => 'Ἆ',\n  'Ἇ' => 'Ἇ',\n  'ἐ' => 'ἐ',\n  'ἑ' => 'ἑ',\n  'ἒ' => 'ἒ',\n  'ἓ' => 'ἓ',\n  'ἔ' => 'ἔ',\n  'ἕ' => 'ἕ',\n  'Ἐ' => 'Ἐ',\n  'Ἑ' => 'Ἑ',\n  'Ἒ' => 'Ἒ',\n  'Ἓ' => 'Ἓ',\n  'Ἔ' => 'Ἔ',\n  'Ἕ' => 'Ἕ',\n  'ἠ' => 'ἠ',\n  'ἡ' => 'ἡ',\n  'ἢ' => 'ἢ',\n  'ἣ' => 'ἣ',\n  'ἤ' => 'ἤ',\n  'ἥ' => 'ἥ',\n  'ἦ' => 'ἦ',\n  'ἧ' => 'ἧ',\n  'Ἠ' => 'Ἠ',\n  'Ἡ' => 'Ἡ',\n  'Ἢ' => 'Ἢ',\n  'Ἣ' => 'Ἣ',\n  'Ἤ' => 'Ἤ',\n  'Ἥ' => 'Ἥ',\n  'Ἦ' => 'Ἦ',\n  'Ἧ' => 'Ἧ',\n  'ἰ' => 'ἰ',\n  'ἱ' => 'ἱ',\n  'ἲ' => 'ἲ',\n  'ἳ' => 'ἳ',\n  'ἴ' => 'ἴ',\n  'ἵ' => 'ἵ',\n  'ἶ' => 'ἶ',\n  'ἷ' => 'ἷ',\n  'Ἰ' => 'Ἰ',\n  'Ἱ' => 'Ἱ',\n  'Ἲ' => 'Ἲ',\n  'Ἳ' => 'Ἳ',\n  'Ἴ' => 'Ἴ',\n  'Ἵ' => 'Ἵ',\n  'Ἶ' => 'Ἶ',\n  'Ἷ' => 'Ἷ',\n  'ὀ' => 'ὀ',\n  'ὁ' => 'ὁ',\n  'ὂ' => 'ὂ',\n  'ὃ' => 'ὃ',\n  'ὄ' => 'ὄ',\n  'ὅ' => 'ὅ',\n  'Ὀ' => 'Ὀ',\n  'Ὁ' => 'Ὁ',\n  'Ὂ' => 'Ὂ',\n  'Ὃ' => 'Ὃ',\n  'Ὄ' => 'Ὄ',\n  'Ὅ' => 'Ὅ',\n  'ὐ' => 'ὐ',\n  'ὑ' => 'ὑ',\n  'ὒ' => 'ὒ',\n  'ὓ' => 'ὓ',\n  'ὔ' => 'ὔ',\n  'ὕ' => 'ὕ',\n  'ὖ' => 'ὖ',\n  'ὗ' => 'ὗ',\n  'Ὑ' => 'Ὑ',\n  'Ὓ' => 'Ὓ',\n  'Ὕ' => 'Ὕ',\n  'Ὗ' => 'Ὗ',\n  'ὠ' => 'ὠ',\n  'ὡ' => 'ὡ',\n  'ὢ' => 'ὢ',\n  'ὣ' => 'ὣ',\n  'ὤ' => 'ὤ',\n  'ὥ' => 'ὥ',\n  'ὦ' => 'ὦ',\n  'ὧ' => 'ὧ',\n  'Ὠ' => 'Ὠ',\n  'Ὡ' => 'Ὡ',\n  'Ὢ' => 'Ὢ',\n  'Ὣ' => 'Ὣ',\n  'Ὤ' => 'Ὤ',\n  'Ὥ' => 'Ὥ',\n  'Ὦ' => 'Ὦ',\n  'Ὧ' => 'Ὧ',\n  'ὰ' => 'ὰ',\n  'ὲ' => 'ὲ',\n  'ὴ' => 'ὴ',\n  'ὶ' => 'ὶ',\n  'ὸ' => 'ὸ',\n  'ὺ' => 'ὺ',\n  'ὼ' => 'ὼ',\n  'ᾀ' => 'ᾀ',\n  'ᾁ' => 'ᾁ',\n  'ᾂ' => 'ᾂ',\n  'ᾃ' => 'ᾃ',\n  'ᾄ' => 'ᾄ',\n  'ᾅ' => 'ᾅ',\n  'ᾆ' => 'ᾆ',\n  'ᾇ' => 'ᾇ',\n  'ᾈ' => 'ᾈ',\n  'ᾉ' => 'ᾉ',\n  'ᾊ' => 'ᾊ',\n  'ᾋ' => 'ᾋ',\n  'ᾌ' => 'ᾌ',\n  'ᾍ' => 'ᾍ',\n  'ᾎ' => 'ᾎ',\n  'ᾏ' => 'ᾏ',\n  'ᾐ' => 'ᾐ',\n  'ᾑ' => 'ᾑ',\n  'ᾒ' => 'ᾒ',\n  'ᾓ' => 'ᾓ',\n  'ᾔ' => 'ᾔ',\n  'ᾕ' => 'ᾕ',\n  'ᾖ' => 'ᾖ',\n  'ᾗ' => 'ᾗ',\n  'ᾘ' => 'ᾘ',\n  'ᾙ' => 'ᾙ',\n  'ᾚ' => 'ᾚ',\n  'ᾛ' => 'ᾛ',\n  'ᾜ' => 'ᾜ',\n  'ᾝ' => 'ᾝ',\n  'ᾞ' => 'ᾞ',\n  'ᾟ' => 'ᾟ',\n  'ᾠ' => 'ᾠ',\n  'ᾡ' => 'ᾡ',\n  'ᾢ' => 'ᾢ',\n  'ᾣ' => 'ᾣ',\n  'ᾤ' => 'ᾤ',\n  'ᾥ' => 'ᾥ',\n  'ᾦ' => 'ᾦ',\n  'ᾧ' => 'ᾧ',\n  'ᾨ' => 'ᾨ',\n  'ᾩ' => 'ᾩ',\n  'ᾪ' => 'ᾪ',\n  'ᾫ' => 'ᾫ',\n  'ᾬ' => 'ᾬ',\n  'ᾭ' => 'ᾭ',\n  'ᾮ' => 'ᾮ',\n  'ᾯ' => 'ᾯ',\n  'ᾰ' => 'ᾰ',\n  'ᾱ' => 'ᾱ',\n  'ᾲ' => 'ᾲ',\n  'ᾳ' => 'ᾳ',\n  'ᾴ' => 'ᾴ',\n  'ᾶ' => 'ᾶ',\n  'ᾷ' => 'ᾷ',\n  'Ᾰ' => 'Ᾰ',\n  'Ᾱ' => 'Ᾱ',\n  'Ὰ' => 'Ὰ',\n  'ᾼ' => 'ᾼ',\n  '῁' => '῁',\n  'ῂ' => 'ῂ',\n  'ῃ' => 'ῃ',\n  'ῄ' => 'ῄ',\n  'ῆ' => 'ῆ',\n  'ῇ' => 'ῇ',\n  'Ὲ' => 'Ὲ',\n  'Ὴ' => 'Ὴ',\n  'ῌ' => 'ῌ',\n  '῍' => '῍',\n  '῎' => '῎',\n  '῏' => '῏',\n  'ῐ' => 'ῐ',\n  'ῑ' => 'ῑ',\n  'ῒ' => 'ῒ',\n  'ῖ' => 'ῖ',\n  'ῗ' => 'ῗ',\n  'Ῐ' => 'Ῐ',\n  'Ῑ' => 'Ῑ',\n  'Ὶ' => 'Ὶ',\n  '῝' => '῝',\n  '῞' => '῞',\n  '῟' => '῟',\n  'ῠ' => 'ῠ',\n  'ῡ' => 'ῡ',\n  'ῢ' => 'ῢ',\n  'ῤ' => 'ῤ',\n  'ῥ' => 'ῥ',\n  'ῦ' => 'ῦ',\n  'ῧ' => 'ῧ',\n  'Ῠ' => 'Ῠ',\n  'Ῡ' => 'Ῡ',\n  'Ὺ' => 'Ὺ',\n  'Ῥ' => 'Ῥ',\n  '῭' => '῭',\n  'ῲ' => 'ῲ',\n  'ῳ' => 'ῳ',\n  'ῴ' => 'ῴ',\n  'ῶ' => 'ῶ',\n  'ῷ' => 'ῷ',\n  'Ὸ' => 'Ὸ',\n  'Ὼ' => 'Ὼ',\n  'ῼ' => 'ῼ',\n  '↚' => '↚',\n  '↛' => '↛',\n  '↮' => '↮',\n  '⇍' => '⇍',\n  '⇎' => '⇎',\n  '⇏' => '⇏',\n  '∄' => '∄',\n  '∉' => '∉',\n  '∌' => '∌',\n  '∤' => '∤',\n  '∦' => '∦',\n  '≁' => '≁',\n  '≄' => '≄',\n  '≇' => '≇',\n  '≉' => '≉',\n  '≠' => '≠',\n  '≢' => '≢',\n  '≭' => '≭',\n  '≮' => '≮',\n  '≯' => '≯',\n  '≰' => '≰',\n  '≱' => '≱',\n  '≴' => '≴',\n  '≵' => '≵',\n  '≸' => '≸',\n  '≹' => '≹',\n  '⊀' => '⊀',\n  '⊁' => '⊁',\n  '⊄' => '⊄',\n  '⊅' => '⊅',\n  '⊈' => '⊈',\n  '⊉' => '⊉',\n  '⊬' => '⊬',\n  '⊭' => '⊭',\n  '⊮' => '⊮',\n  '⊯' => '⊯',\n  '⋠' => '⋠',\n  '⋡' => '⋡',\n  '⋢' => '⋢',\n  '⋣' => '⋣',\n  '⋪' => '⋪',\n  '⋫' => '⋫',\n  '⋬' => '⋬',\n  '⋭' => '⋭',\n  'が' => 'が',\n  'ぎ' => 'ぎ',\n  'ぐ' => 'ぐ',\n  'げ' => 'げ',\n  'ご' => 'ご',\n  'ざ' => 'ざ',\n  'じ' => 'じ',\n  'ず' => 'ず',\n  'ぜ' => 'ぜ',\n  'ぞ' => 'ぞ',\n  'だ' => 'だ',\n  'ぢ' => 'ぢ',\n  'づ' => 'づ',\n  'で' => 'で',\n  'ど' => 'ど',\n  'ば' => 'ば',\n  'ぱ' => 'ぱ',\n  'び' => 'び',\n  'ぴ' => 'ぴ',\n  'ぶ' => 'ぶ',\n  'ぷ' => 'ぷ',\n  'べ' => 'べ',\n  'ぺ' => 'ぺ',\n  'ぼ' => 'ぼ',\n  'ぽ' => 'ぽ',\n  'ゔ' => 'ゔ',\n  'ゞ' => 'ゞ',\n  'ガ' => 'ガ',\n  'ギ' => 'ギ',\n  'グ' => 'グ',\n  'ゲ' => 'ゲ',\n  'ゴ' => 'ゴ',\n  'ザ' => 'ザ',\n  'ジ' => 'ジ',\n  'ズ' => 'ズ',\n  'ゼ' => 'ゼ',\n  'ゾ' => 'ゾ',\n  'ダ' => 'ダ',\n  'ヂ' => 'ヂ',\n  'ヅ' => 'ヅ',\n  'デ' => 'デ',\n  'ド' => 'ド',\n  'バ' => 'バ',\n  'パ' => 'パ',\n  'ビ' => 'ビ',\n  'ピ' => 'ピ',\n  'ブ' => 'ブ',\n  'プ' => 'プ',\n  'ベ' => 'ベ',\n  'ペ' => 'ペ',\n  'ボ' => 'ボ',\n  'ポ' => 'ポ',\n  'ヴ' => 'ヴ',\n  'ヷ' => 'ヷ',\n  'ヸ' => 'ヸ',\n  'ヹ' => 'ヹ',\n  'ヺ' => 'ヺ',\n  'ヾ' => 'ヾ',\n  '𑂚' => '𑂚',\n  '𑂜' => '𑂜',\n  '𑂫' => '𑂫',\n  '𑄮' => '𑄮',\n  '𑄯' => '𑄯',\n  '𑍋' => '𑍋',\n  '𑍌' => '𑍌',\n  '𑒻' => '𑒻',\n  '𑒼' => '𑒼',\n  '𑒾' => '𑒾',\n  '𑖺' => '𑖺',\n  '𑖻' => '𑖻',\n  '𑤸' => '𑤸',\n);\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalDecomposition.php",
    "content": "<?php\n\nreturn array (\n  'À' => 'À',\n  'Á' => 'Á',\n  'Â' => 'Â',\n  'Ã' => 'Ã',\n  'Ä' => 'Ä',\n  'Å' => 'Å',\n  'Ç' => 'Ç',\n  'È' => 'È',\n  'É' => 'É',\n  'Ê' => 'Ê',\n  'Ë' => 'Ë',\n  'Ì' => 'Ì',\n  'Í' => 'Í',\n  'Î' => 'Î',\n  'Ï' => 'Ï',\n  'Ñ' => 'Ñ',\n  'Ò' => 'Ò',\n  'Ó' => 'Ó',\n  'Ô' => 'Ô',\n  'Õ' => 'Õ',\n  'Ö' => 'Ö',\n  'Ù' => 'Ù',\n  'Ú' => 'Ú',\n  'Û' => 'Û',\n  'Ü' => 'Ü',\n  'Ý' => 'Ý',\n  'à' => 'à',\n  'á' => 'á',\n  'â' => 'â',\n  'ã' => 'ã',\n  'ä' => 'ä',\n  'å' => 'å',\n  'ç' => 'ç',\n  'è' => 'è',\n  'é' => 'é',\n  'ê' => 'ê',\n  'ë' => 'ë',\n  'ì' => 'ì',\n  'í' => 'í',\n  'î' => 'î',\n  'ï' => 'ï',\n  'ñ' => 'ñ',\n  'ò' => 'ò',\n  'ó' => 'ó',\n  'ô' => 'ô',\n  'õ' => 'õ',\n  'ö' => 'ö',\n  'ù' => 'ù',\n  'ú' => 'ú',\n  'û' => 'û',\n  'ü' => 'ü',\n  'ý' => 'ý',\n  'ÿ' => 'ÿ',\n  'Ā' => 'Ā',\n  'ā' => 'ā',\n  'Ă' => 'Ă',\n  'ă' => 'ă',\n  'Ą' => 'Ą',\n  'ą' => 'ą',\n  'Ć' => 'Ć',\n  'ć' => 'ć',\n  'Ĉ' => 'Ĉ',\n  'ĉ' => 'ĉ',\n  'Ċ' => 'Ċ',\n  'ċ' => 'ċ',\n  'Č' => 'Č',\n  'č' => 'č',\n  'Ď' => 'Ď',\n  'ď' => 'ď',\n  'Ē' => 'Ē',\n  'ē' => 'ē',\n  'Ĕ' => 'Ĕ',\n  'ĕ' => 'ĕ',\n  'Ė' => 'Ė',\n  'ė' => 'ė',\n  'Ę' => 'Ę',\n  'ę' => 'ę',\n  'Ě' => 'Ě',\n  'ě' => 'ě',\n  'Ĝ' => 'Ĝ',\n  'ĝ' => 'ĝ',\n  'Ğ' => 'Ğ',\n  'ğ' => 'ğ',\n  'Ġ' => 'Ġ',\n  'ġ' => 'ġ',\n  'Ģ' => 'Ģ',\n  'ģ' => 'ģ',\n  'Ĥ' => 'Ĥ',\n  'ĥ' => 'ĥ',\n  'Ĩ' => 'Ĩ',\n  'ĩ' => 'ĩ',\n  'Ī' => 'Ī',\n  'ī' => 'ī',\n  'Ĭ' => 'Ĭ',\n  'ĭ' => 'ĭ',\n  'Į' => 'Į',\n  'į' => 'į',\n  'İ' => 'İ',\n  'Ĵ' => 'Ĵ',\n  'ĵ' => 'ĵ',\n  'Ķ' => 'Ķ',\n  'ķ' => 'ķ',\n  'Ĺ' => 'Ĺ',\n  'ĺ' => 'ĺ',\n  'Ļ' => 'Ļ',\n  'ļ' => 'ļ',\n  'Ľ' => 'Ľ',\n  'ľ' => 'ľ',\n  'Ń' => 'Ń',\n  'ń' => 'ń',\n  'Ņ' => 'Ņ',\n  'ņ' => 'ņ',\n  'Ň' => 'Ň',\n  'ň' => 'ň',\n  'Ō' => 'Ō',\n  'ō' => 'ō',\n  'Ŏ' => 'Ŏ',\n  'ŏ' => 'ŏ',\n  'Ő' => 'Ő',\n  'ő' => 'ő',\n  'Ŕ' => 'Ŕ',\n  'ŕ' => 'ŕ',\n  'Ŗ' => 'Ŗ',\n  'ŗ' => 'ŗ',\n  'Ř' => 'Ř',\n  'ř' => 'ř',\n  'Ś' => 'Ś',\n  'ś' => 'ś',\n  'Ŝ' => 'Ŝ',\n  'ŝ' => 'ŝ',\n  'Ş' => 'Ş',\n  'ş' => 'ş',\n  'Š' => 'Š',\n  'š' => 'š',\n  'Ţ' => 'Ţ',\n  'ţ' => 'ţ',\n  'Ť' => 'Ť',\n  'ť' => 'ť',\n  'Ũ' => 'Ũ',\n  'ũ' => 'ũ',\n  'Ū' => 'Ū',\n  'ū' => 'ū',\n  'Ŭ' => 'Ŭ',\n  'ŭ' => 'ŭ',\n  'Ů' => 'Ů',\n  'ů' => 'ů',\n  'Ű' => 'Ű',\n  'ű' => 'ű',\n  'Ų' => 'Ų',\n  'ų' => 'ų',\n  'Ŵ' => 'Ŵ',\n  'ŵ' => 'ŵ',\n  'Ŷ' => 'Ŷ',\n  'ŷ' => 'ŷ',\n  'Ÿ' => 'Ÿ',\n  'Ź' => 'Ź',\n  'ź' => 'ź',\n  'Ż' => 'Ż',\n  'ż' => 'ż',\n  'Ž' => 'Ž',\n  'ž' => 'ž',\n  'Ơ' => 'Ơ',\n  'ơ' => 'ơ',\n  'Ư' => 'Ư',\n  'ư' => 'ư',\n  'Ǎ' => 'Ǎ',\n  'ǎ' => 'ǎ',\n  'Ǐ' => 'Ǐ',\n  'ǐ' => 'ǐ',\n  'Ǒ' => 'Ǒ',\n  'ǒ' => 'ǒ',\n  'Ǔ' => 'Ǔ',\n  'ǔ' => 'ǔ',\n  'Ǖ' => 'Ǖ',\n  'ǖ' => 'ǖ',\n  'Ǘ' => 'Ǘ',\n  'ǘ' => 'ǘ',\n  'Ǚ' => 'Ǚ',\n  'ǚ' => 'ǚ',\n  'Ǜ' => 'Ǜ',\n  'ǜ' => 'ǜ',\n  'Ǟ' => 'Ǟ',\n  'ǟ' => 'ǟ',\n  'Ǡ' => 'Ǡ',\n  'ǡ' => 'ǡ',\n  'Ǣ' => 'Ǣ',\n  'ǣ' => 'ǣ',\n  'Ǧ' => 'Ǧ',\n  'ǧ' => 'ǧ',\n  'Ǩ' => 'Ǩ',\n  'ǩ' => 'ǩ',\n  'Ǫ' => 'Ǫ',\n  'ǫ' => 'ǫ',\n  'Ǭ' => 'Ǭ',\n  'ǭ' => 'ǭ',\n  'Ǯ' => 'Ǯ',\n  'ǯ' => 'ǯ',\n  'ǰ' => 'ǰ',\n  'Ǵ' => 'Ǵ',\n  'ǵ' => 'ǵ',\n  'Ǹ' => 'Ǹ',\n  'ǹ' => 'ǹ',\n  'Ǻ' => 'Ǻ',\n  'ǻ' => 'ǻ',\n  'Ǽ' => 'Ǽ',\n  'ǽ' => 'ǽ',\n  'Ǿ' => 'Ǿ',\n  'ǿ' => 'ǿ',\n  'Ȁ' => 'Ȁ',\n  'ȁ' => 'ȁ',\n  'Ȃ' => 'Ȃ',\n  'ȃ' => 'ȃ',\n  'Ȅ' => 'Ȅ',\n  'ȅ' => 'ȅ',\n  'Ȇ' => 'Ȇ',\n  'ȇ' => 'ȇ',\n  'Ȉ' => 'Ȉ',\n  'ȉ' => 'ȉ',\n  'Ȋ' => 'Ȋ',\n  'ȋ' => 'ȋ',\n  'Ȍ' => 'Ȍ',\n  'ȍ' => 'ȍ',\n  'Ȏ' => 'Ȏ',\n  'ȏ' => 'ȏ',\n  'Ȑ' => 'Ȑ',\n  'ȑ' => 'ȑ',\n  'Ȓ' => 'Ȓ',\n  'ȓ' => 'ȓ',\n  'Ȕ' => 'Ȕ',\n  'ȕ' => 'ȕ',\n  'Ȗ' => 'Ȗ',\n  'ȗ' => 'ȗ',\n  'Ș' => 'Ș',\n  'ș' => 'ș',\n  'Ț' => 'Ț',\n  'ț' => 'ț',\n  'Ȟ' => 'Ȟ',\n  'ȟ' => 'ȟ',\n  'Ȧ' => 'Ȧ',\n  'ȧ' => 'ȧ',\n  'Ȩ' => 'Ȩ',\n  'ȩ' => 'ȩ',\n  'Ȫ' => 'Ȫ',\n  'ȫ' => 'ȫ',\n  'Ȭ' => 'Ȭ',\n  'ȭ' => 'ȭ',\n  'Ȯ' => 'Ȯ',\n  'ȯ' => 'ȯ',\n  'Ȱ' => 'Ȱ',\n  'ȱ' => 'ȱ',\n  'Ȳ' => 'Ȳ',\n  'ȳ' => 'ȳ',\n  '̀' => '̀',\n  '́' => '́',\n  '̓' => '̓',\n  '̈́' => '̈́',\n  'ʹ' => 'ʹ',\n  ';' => ';',\n  '΅' => '΅',\n  'Ά' => 'Ά',\n  '·' => '·',\n  'Έ' => 'Έ',\n  'Ή' => 'Ή',\n  'Ί' => 'Ί',\n  'Ό' => 'Ό',\n  'Ύ' => 'Ύ',\n  'Ώ' => 'Ώ',\n  'ΐ' => 'ΐ',\n  'Ϊ' => 'Ϊ',\n  'Ϋ' => 'Ϋ',\n  'ά' => 'ά',\n  'έ' => 'έ',\n  'ή' => 'ή',\n  'ί' => 'ί',\n  'ΰ' => 'ΰ',\n  'ϊ' => 'ϊ',\n  'ϋ' => 'ϋ',\n  'ό' => 'ό',\n  'ύ' => 'ύ',\n  'ώ' => 'ώ',\n  'ϓ' => 'ϓ',\n  'ϔ' => 'ϔ',\n  'Ѐ' => 'Ѐ',\n  'Ё' => 'Ё',\n  'Ѓ' => 'Ѓ',\n  'Ї' => 'Ї',\n  'Ќ' => 'Ќ',\n  'Ѝ' => 'Ѝ',\n  'Ў' => 'Ў',\n  'Й' => 'Й',\n  'й' => 'й',\n  'ѐ' => 'ѐ',\n  'ё' => 'ё',\n  'ѓ' => 'ѓ',\n  'ї' => 'ї',\n  'ќ' => 'ќ',\n  'ѝ' => 'ѝ',\n  'ў' => 'ў',\n  'Ѷ' => 'Ѷ',\n  'ѷ' => 'ѷ',\n  'Ӂ' => 'Ӂ',\n  'ӂ' => 'ӂ',\n  'Ӑ' => 'Ӑ',\n  'ӑ' => 'ӑ',\n  'Ӓ' => 'Ӓ',\n  'ӓ' => 'ӓ',\n  'Ӗ' => 'Ӗ',\n  'ӗ' => 'ӗ',\n  'Ӛ' => 'Ӛ',\n  'ӛ' => 'ӛ',\n  'Ӝ' => 'Ӝ',\n  'ӝ' => 'ӝ',\n  'Ӟ' => 'Ӟ',\n  'ӟ' => 'ӟ',\n  'Ӣ' => 'Ӣ',\n  'ӣ' => 'ӣ',\n  'Ӥ' => 'Ӥ',\n  'ӥ' => 'ӥ',\n  'Ӧ' => 'Ӧ',\n  'ӧ' => 'ӧ',\n  'Ӫ' => 'Ӫ',\n  'ӫ' => 'ӫ',\n  'Ӭ' => 'Ӭ',\n  'ӭ' => 'ӭ',\n  'Ӯ' => 'Ӯ',\n  'ӯ' => 'ӯ',\n  'Ӱ' => 'Ӱ',\n  'ӱ' => 'ӱ',\n  'Ӳ' => 'Ӳ',\n  'ӳ' => 'ӳ',\n  'Ӵ' => 'Ӵ',\n  'ӵ' => 'ӵ',\n  'Ӹ' => 'Ӹ',\n  'ӹ' => 'ӹ',\n  'آ' => 'آ',\n  'أ' => 'أ',\n  'ؤ' => 'ؤ',\n  'إ' => 'إ',\n  'ئ' => 'ئ',\n  'ۀ' => 'ۀ',\n  'ۂ' => 'ۂ',\n  'ۓ' => 'ۓ',\n  'ऩ' => 'ऩ',\n  'ऱ' => 'ऱ',\n  'ऴ' => 'ऴ',\n  'क़' => 'क़',\n  'ख़' => 'ख़',\n  'ग़' => 'ग़',\n  'ज़' => 'ज़',\n  'ड़' => 'ड़',\n  'ढ़' => 'ढ़',\n  'फ़' => 'फ़',\n  'य़' => 'य़',\n  'ো' => 'ো',\n  'ৌ' => 'ৌ',\n  'ড়' => 'ড়',\n  'ঢ়' => 'ঢ়',\n  'য়' => 'য়',\n  'ਲ਼' => 'ਲ਼',\n  'ਸ਼' => 'ਸ਼',\n  'ਖ਼' => 'ਖ਼',\n  'ਗ਼' => 'ਗ਼',\n  'ਜ਼' => 'ਜ਼',\n  'ਫ਼' => 'ਫ਼',\n  'ୈ' => 'ୈ',\n  'ୋ' => 'ୋ',\n  'ୌ' => 'ୌ',\n  'ଡ଼' => 'ଡ଼',\n  'ଢ଼' => 'ଢ଼',\n  'ஔ' => 'ஔ',\n  'ொ' => 'ொ',\n  'ோ' => 'ோ',\n  'ௌ' => 'ௌ',\n  'ై' => 'ై',\n  'ೀ' => 'ೀ',\n  'ೇ' => 'ೇ',\n  'ೈ' => 'ೈ',\n  'ೊ' => 'ೊ',\n  'ೋ' => 'ೋ',\n  'ൊ' => 'ൊ',\n  'ോ' => 'ോ',\n  'ൌ' => 'ൌ',\n  'ේ' => 'ේ',\n  'ො' => 'ො',\n  'ෝ' => 'ෝ',\n  'ෞ' => 'ෞ',\n  'གྷ' => 'གྷ',\n  'ཌྷ' => 'ཌྷ',\n  'དྷ' => 'དྷ',\n  'བྷ' => 'བྷ',\n  'ཛྷ' => 'ཛྷ',\n  'ཀྵ' => 'ཀྵ',\n  'ཱི' => 'ཱི',\n  'ཱུ' => 'ཱུ',\n  'ྲྀ' => 'ྲྀ',\n  'ླྀ' => 'ླྀ',\n  'ཱྀ' => 'ཱྀ',\n  'ྒྷ' => 'ྒྷ',\n  'ྜྷ' => 'ྜྷ',\n  'ྡྷ' => 'ྡྷ',\n  'ྦྷ' => 'ྦྷ',\n  'ྫྷ' => 'ྫྷ',\n  'ྐྵ' => 'ྐྵ',\n  'ဦ' => 'ဦ',\n  'ᬆ' => 'ᬆ',\n  'ᬈ' => 'ᬈ',\n  'ᬊ' => 'ᬊ',\n  'ᬌ' => 'ᬌ',\n  'ᬎ' => 'ᬎ',\n  'ᬒ' => 'ᬒ',\n  'ᬻ' => 'ᬻ',\n  'ᬽ' => 'ᬽ',\n  'ᭀ' => 'ᭀ',\n  'ᭁ' => 'ᭁ',\n  'ᭃ' => 'ᭃ',\n  'Ḁ' => 'Ḁ',\n  'ḁ' => 'ḁ',\n  'Ḃ' => 'Ḃ',\n  'ḃ' => 'ḃ',\n  'Ḅ' => 'Ḅ',\n  'ḅ' => 'ḅ',\n  'Ḇ' => 'Ḇ',\n  'ḇ' => 'ḇ',\n  'Ḉ' => 'Ḉ',\n  'ḉ' => 'ḉ',\n  'Ḋ' => 'Ḋ',\n  'ḋ' => 'ḋ',\n  'Ḍ' => 'Ḍ',\n  'ḍ' => 'ḍ',\n  'Ḏ' => 'Ḏ',\n  'ḏ' => 'ḏ',\n  'Ḑ' => 'Ḑ',\n  'ḑ' => 'ḑ',\n  'Ḓ' => 'Ḓ',\n  'ḓ' => 'ḓ',\n  'Ḕ' => 'Ḕ',\n  'ḕ' => 'ḕ',\n  'Ḗ' => 'Ḗ',\n  'ḗ' => 'ḗ',\n  'Ḙ' => 'Ḙ',\n  'ḙ' => 'ḙ',\n  'Ḛ' => 'Ḛ',\n  'ḛ' => 'ḛ',\n  'Ḝ' => 'Ḝ',\n  'ḝ' => 'ḝ',\n  'Ḟ' => 'Ḟ',\n  'ḟ' => 'ḟ',\n  'Ḡ' => 'Ḡ',\n  'ḡ' => 'ḡ',\n  'Ḣ' => 'Ḣ',\n  'ḣ' => 'ḣ',\n  'Ḥ' => 'Ḥ',\n  'ḥ' => 'ḥ',\n  'Ḧ' => 'Ḧ',\n  'ḧ' => 'ḧ',\n  'Ḩ' => 'Ḩ',\n  'ḩ' => 'ḩ',\n  'Ḫ' => 'Ḫ',\n  'ḫ' => 'ḫ',\n  'Ḭ' => 'Ḭ',\n  'ḭ' => 'ḭ',\n  'Ḯ' => 'Ḯ',\n  'ḯ' => 'ḯ',\n  'Ḱ' => 'Ḱ',\n  'ḱ' => 'ḱ',\n  'Ḳ' => 'Ḳ',\n  'ḳ' => 'ḳ',\n  'Ḵ' => 'Ḵ',\n  'ḵ' => 'ḵ',\n  'Ḷ' => 'Ḷ',\n  'ḷ' => 'ḷ',\n  'Ḹ' => 'Ḹ',\n  'ḹ' => 'ḹ',\n  'Ḻ' => 'Ḻ',\n  'ḻ' => 'ḻ',\n  'Ḽ' => 'Ḽ',\n  'ḽ' => 'ḽ',\n  'Ḿ' => 'Ḿ',\n  'ḿ' => 'ḿ',\n  'Ṁ' => 'Ṁ',\n  'ṁ' => 'ṁ',\n  'Ṃ' => 'Ṃ',\n  'ṃ' => 'ṃ',\n  'Ṅ' => 'Ṅ',\n  'ṅ' => 'ṅ',\n  'Ṇ' => 'Ṇ',\n  'ṇ' => 'ṇ',\n  'Ṉ' => 'Ṉ',\n  'ṉ' => 'ṉ',\n  'Ṋ' => 'Ṋ',\n  'ṋ' => 'ṋ',\n  'Ṍ' => 'Ṍ',\n  'ṍ' => 'ṍ',\n  'Ṏ' => 'Ṏ',\n  'ṏ' => 'ṏ',\n  'Ṑ' => 'Ṑ',\n  'ṑ' => 'ṑ',\n  'Ṓ' => 'Ṓ',\n  'ṓ' => 'ṓ',\n  'Ṕ' => 'Ṕ',\n  'ṕ' => 'ṕ',\n  'Ṗ' => 'Ṗ',\n  'ṗ' => 'ṗ',\n  'Ṙ' => 'Ṙ',\n  'ṙ' => 'ṙ',\n  'Ṛ' => 'Ṛ',\n  'ṛ' => 'ṛ',\n  'Ṝ' => 'Ṝ',\n  'ṝ' => 'ṝ',\n  'Ṟ' => 'Ṟ',\n  'ṟ' => 'ṟ',\n  'Ṡ' => 'Ṡ',\n  'ṡ' => 'ṡ',\n  'Ṣ' => 'Ṣ',\n  'ṣ' => 'ṣ',\n  'Ṥ' => 'Ṥ',\n  'ṥ' => 'ṥ',\n  'Ṧ' => 'Ṧ',\n  'ṧ' => 'ṧ',\n  'Ṩ' => 'Ṩ',\n  'ṩ' => 'ṩ',\n  'Ṫ' => 'Ṫ',\n  'ṫ' => 'ṫ',\n  'Ṭ' => 'Ṭ',\n  'ṭ' => 'ṭ',\n  'Ṯ' => 'Ṯ',\n  'ṯ' => 'ṯ',\n  'Ṱ' => 'Ṱ',\n  'ṱ' => 'ṱ',\n  'Ṳ' => 'Ṳ',\n  'ṳ' => 'ṳ',\n  'Ṵ' => 'Ṵ',\n  'ṵ' => 'ṵ',\n  'Ṷ' => 'Ṷ',\n  'ṷ' => 'ṷ',\n  'Ṹ' => 'Ṹ',\n  'ṹ' => 'ṹ',\n  'Ṻ' => 'Ṻ',\n  'ṻ' => 'ṻ',\n  'Ṽ' => 'Ṽ',\n  'ṽ' => 'ṽ',\n  'Ṿ' => 'Ṿ',\n  'ṿ' => 'ṿ',\n  'Ẁ' => 'Ẁ',\n  'ẁ' => 'ẁ',\n  'Ẃ' => 'Ẃ',\n  'ẃ' => 'ẃ',\n  'Ẅ' => 'Ẅ',\n  'ẅ' => 'ẅ',\n  'Ẇ' => 'Ẇ',\n  'ẇ' => 'ẇ',\n  'Ẉ' => 'Ẉ',\n  'ẉ' => 'ẉ',\n  'Ẋ' => 'Ẋ',\n  'ẋ' => 'ẋ',\n  'Ẍ' => 'Ẍ',\n  'ẍ' => 'ẍ',\n  'Ẏ' => 'Ẏ',\n  'ẏ' => 'ẏ',\n  'Ẑ' => 'Ẑ',\n  'ẑ' => 'ẑ',\n  'Ẓ' => 'Ẓ',\n  'ẓ' => 'ẓ',\n  'Ẕ' => 'Ẕ',\n  'ẕ' => 'ẕ',\n  'ẖ' => 'ẖ',\n  'ẗ' => 'ẗ',\n  'ẘ' => 'ẘ',\n  'ẙ' => 'ẙ',\n  'ẛ' => 'ẛ',\n  'Ạ' => 'Ạ',\n  'ạ' => 'ạ',\n  'Ả' => 'Ả',\n  'ả' => 'ả',\n  'Ấ' => 'Ấ',\n  'ấ' => 'ấ',\n  'Ầ' => 'Ầ',\n  'ầ' => 'ầ',\n  'Ẩ' => 'Ẩ',\n  'ẩ' => 'ẩ',\n  'Ẫ' => 'Ẫ',\n  'ẫ' => 'ẫ',\n  'Ậ' => 'Ậ',\n  'ậ' => 'ậ',\n  'Ắ' => 'Ắ',\n  'ắ' => 'ắ',\n  'Ằ' => 'Ằ',\n  'ằ' => 'ằ',\n  'Ẳ' => 'Ẳ',\n  'ẳ' => 'ẳ',\n  'Ẵ' => 'Ẵ',\n  'ẵ' => 'ẵ',\n  'Ặ' => 'Ặ',\n  'ặ' => 'ặ',\n  'Ẹ' => 'Ẹ',\n  'ẹ' => 'ẹ',\n  'Ẻ' => 'Ẻ',\n  'ẻ' => 'ẻ',\n  'Ẽ' => 'Ẽ',\n  'ẽ' => 'ẽ',\n  'Ế' => 'Ế',\n  'ế' => 'ế',\n  'Ề' => 'Ề',\n  'ề' => 'ề',\n  'Ể' => 'Ể',\n  'ể' => 'ể',\n  'Ễ' => 'Ễ',\n  'ễ' => 'ễ',\n  'Ệ' => 'Ệ',\n  'ệ' => 'ệ',\n  'Ỉ' => 'Ỉ',\n  'ỉ' => 'ỉ',\n  'Ị' => 'Ị',\n  'ị' => 'ị',\n  'Ọ' => 'Ọ',\n  'ọ' => 'ọ',\n  'Ỏ' => 'Ỏ',\n  'ỏ' => 'ỏ',\n  'Ố' => 'Ố',\n  'ố' => 'ố',\n  'Ồ' => 'Ồ',\n  'ồ' => 'ồ',\n  'Ổ' => 'Ổ',\n  'ổ' => 'ổ',\n  'Ỗ' => 'Ỗ',\n  'ỗ' => 'ỗ',\n  'Ộ' => 'Ộ',\n  'ộ' => 'ộ',\n  'Ớ' => 'Ớ',\n  'ớ' => 'ớ',\n  'Ờ' => 'Ờ',\n  'ờ' => 'ờ',\n  'Ở' => 'Ở',\n  'ở' => 'ở',\n  'Ỡ' => 'Ỡ',\n  'ỡ' => 'ỡ',\n  'Ợ' => 'Ợ',\n  'ợ' => 'ợ',\n  'Ụ' => 'Ụ',\n  'ụ' => 'ụ',\n  'Ủ' => 'Ủ',\n  'ủ' => 'ủ',\n  'Ứ' => 'Ứ',\n  'ứ' => 'ứ',\n  'Ừ' => 'Ừ',\n  'ừ' => 'ừ',\n  'Ử' => 'Ử',\n  'ử' => 'ử',\n  'Ữ' => 'Ữ',\n  'ữ' => 'ữ',\n  'Ự' => 'Ự',\n  'ự' => 'ự',\n  'Ỳ' => 'Ỳ',\n  'ỳ' => 'ỳ',\n  'Ỵ' => 'Ỵ',\n  'ỵ' => 'ỵ',\n  'Ỷ' => 'Ỷ',\n  'ỷ' => 'ỷ',\n  'Ỹ' => 'Ỹ',\n  'ỹ' => 'ỹ',\n  'ἀ' => 'ἀ',\n  'ἁ' => 'ἁ',\n  'ἂ' => 'ἂ',\n  'ἃ' => 'ἃ',\n  'ἄ' => 'ἄ',\n  'ἅ' => 'ἅ',\n  'ἆ' => 'ἆ',\n  'ἇ' => 'ἇ',\n  'Ἀ' => 'Ἀ',\n  'Ἁ' => 'Ἁ',\n  'Ἂ' => 'Ἂ',\n  'Ἃ' => 'Ἃ',\n  'Ἄ' => 'Ἄ',\n  'Ἅ' => 'Ἅ',\n  'Ἆ' => 'Ἆ',\n  'Ἇ' => 'Ἇ',\n  'ἐ' => 'ἐ',\n  'ἑ' => 'ἑ',\n  'ἒ' => 'ἒ',\n  'ἓ' => 'ἓ',\n  'ἔ' => 'ἔ',\n  'ἕ' => 'ἕ',\n  'Ἐ' => 'Ἐ',\n  'Ἑ' => 'Ἑ',\n  'Ἒ' => 'Ἒ',\n  'Ἓ' => 'Ἓ',\n  'Ἔ' => 'Ἔ',\n  'Ἕ' => 'Ἕ',\n  'ἠ' => 'ἠ',\n  'ἡ' => 'ἡ',\n  'ἢ' => 'ἢ',\n  'ἣ' => 'ἣ',\n  'ἤ' => 'ἤ',\n  'ἥ' => 'ἥ',\n  'ἦ' => 'ἦ',\n  'ἧ' => 'ἧ',\n  'Ἠ' => 'Ἠ',\n  'Ἡ' => 'Ἡ',\n  'Ἢ' => 'Ἢ',\n  'Ἣ' => 'Ἣ',\n  'Ἤ' => 'Ἤ',\n  'Ἥ' => 'Ἥ',\n  'Ἦ' => 'Ἦ',\n  'Ἧ' => 'Ἧ',\n  'ἰ' => 'ἰ',\n  'ἱ' => 'ἱ',\n  'ἲ' => 'ἲ',\n  'ἳ' => 'ἳ',\n  'ἴ' => 'ἴ',\n  'ἵ' => 'ἵ',\n  'ἶ' => 'ἶ',\n  'ἷ' => 'ἷ',\n  'Ἰ' => 'Ἰ',\n  'Ἱ' => 'Ἱ',\n  'Ἲ' => 'Ἲ',\n  'Ἳ' => 'Ἳ',\n  'Ἴ' => 'Ἴ',\n  'Ἵ' => 'Ἵ',\n  'Ἶ' => 'Ἶ',\n  'Ἷ' => 'Ἷ',\n  'ὀ' => 'ὀ',\n  'ὁ' => 'ὁ',\n  'ὂ' => 'ὂ',\n  'ὃ' => 'ὃ',\n  'ὄ' => 'ὄ',\n  'ὅ' => 'ὅ',\n  'Ὀ' => 'Ὀ',\n  'Ὁ' => 'Ὁ',\n  'Ὂ' => 'Ὂ',\n  'Ὃ' => 'Ὃ',\n  'Ὄ' => 'Ὄ',\n  'Ὅ' => 'Ὅ',\n  'ὐ' => 'ὐ',\n  'ὑ' => 'ὑ',\n  'ὒ' => 'ὒ',\n  'ὓ' => 'ὓ',\n  'ὔ' => 'ὔ',\n  'ὕ' => 'ὕ',\n  'ὖ' => 'ὖ',\n  'ὗ' => 'ὗ',\n  'Ὑ' => 'Ὑ',\n  'Ὓ' => 'Ὓ',\n  'Ὕ' => 'Ὕ',\n  'Ὗ' => 'Ὗ',\n  'ὠ' => 'ὠ',\n  'ὡ' => 'ὡ',\n  'ὢ' => 'ὢ',\n  'ὣ' => 'ὣ',\n  'ὤ' => 'ὤ',\n  'ὥ' => 'ὥ',\n  'ὦ' => 'ὦ',\n  'ὧ' => 'ὧ',\n  'Ὠ' => 'Ὠ',\n  'Ὡ' => 'Ὡ',\n  'Ὢ' => 'Ὢ',\n  'Ὣ' => 'Ὣ',\n  'Ὤ' => 'Ὤ',\n  'Ὥ' => 'Ὥ',\n  'Ὦ' => 'Ὦ',\n  'Ὧ' => 'Ὧ',\n  'ὰ' => 'ὰ',\n  'ά' => 'ά',\n  'ὲ' => 'ὲ',\n  'έ' => 'έ',\n  'ὴ' => 'ὴ',\n  'ή' => 'ή',\n  'ὶ' => 'ὶ',\n  'ί' => 'ί',\n  'ὸ' => 'ὸ',\n  'ό' => 'ό',\n  'ὺ' => 'ὺ',\n  'ύ' => 'ύ',\n  'ὼ' => 'ὼ',\n  'ώ' => 'ώ',\n  'ᾀ' => 'ᾀ',\n  'ᾁ' => 'ᾁ',\n  'ᾂ' => 'ᾂ',\n  'ᾃ' => 'ᾃ',\n  'ᾄ' => 'ᾄ',\n  'ᾅ' => 'ᾅ',\n  'ᾆ' => 'ᾆ',\n  'ᾇ' => 'ᾇ',\n  'ᾈ' => 'ᾈ',\n  'ᾉ' => 'ᾉ',\n  'ᾊ' => 'ᾊ',\n  'ᾋ' => 'ᾋ',\n  'ᾌ' => 'ᾌ',\n  'ᾍ' => 'ᾍ',\n  'ᾎ' => 'ᾎ',\n  'ᾏ' => 'ᾏ',\n  'ᾐ' => 'ᾐ',\n  'ᾑ' => 'ᾑ',\n  'ᾒ' => 'ᾒ',\n  'ᾓ' => 'ᾓ',\n  'ᾔ' => 'ᾔ',\n  'ᾕ' => 'ᾕ',\n  'ᾖ' => 'ᾖ',\n  'ᾗ' => 'ᾗ',\n  'ᾘ' => 'ᾘ',\n  'ᾙ' => 'ᾙ',\n  'ᾚ' => 'ᾚ',\n  'ᾛ' => 'ᾛ',\n  'ᾜ' => 'ᾜ',\n  'ᾝ' => 'ᾝ',\n  'ᾞ' => 'ᾞ',\n  'ᾟ' => 'ᾟ',\n  'ᾠ' => 'ᾠ',\n  'ᾡ' => 'ᾡ',\n  'ᾢ' => 'ᾢ',\n  'ᾣ' => 'ᾣ',\n  'ᾤ' => 'ᾤ',\n  'ᾥ' => 'ᾥ',\n  'ᾦ' => 'ᾦ',\n  'ᾧ' => 'ᾧ',\n  'ᾨ' => 'ᾨ',\n  'ᾩ' => 'ᾩ',\n  'ᾪ' => 'ᾪ',\n  'ᾫ' => 'ᾫ',\n  'ᾬ' => 'ᾬ',\n  'ᾭ' => 'ᾭ',\n  'ᾮ' => 'ᾮ',\n  'ᾯ' => 'ᾯ',\n  'ᾰ' => 'ᾰ',\n  'ᾱ' => 'ᾱ',\n  'ᾲ' => 'ᾲ',\n  'ᾳ' => 'ᾳ',\n  'ᾴ' => 'ᾴ',\n  'ᾶ' => 'ᾶ',\n  'ᾷ' => 'ᾷ',\n  'Ᾰ' => 'Ᾰ',\n  'Ᾱ' => 'Ᾱ',\n  'Ὰ' => 'Ὰ',\n  'Ά' => 'Ά',\n  'ᾼ' => 'ᾼ',\n  'ι' => 'ι',\n  '῁' => '῁',\n  'ῂ' => 'ῂ',\n  'ῃ' => 'ῃ',\n  'ῄ' => 'ῄ',\n  'ῆ' => 'ῆ',\n  'ῇ' => 'ῇ',\n  'Ὲ' => 'Ὲ',\n  'Έ' => 'Έ',\n  'Ὴ' => 'Ὴ',\n  'Ή' => 'Ή',\n  'ῌ' => 'ῌ',\n  '῍' => '῍',\n  '῎' => '῎',\n  '῏' => '῏',\n  'ῐ' => 'ῐ',\n  'ῑ' => 'ῑ',\n  'ῒ' => 'ῒ',\n  'ΐ' => 'ΐ',\n  'ῖ' => 'ῖ',\n  'ῗ' => 'ῗ',\n  'Ῐ' => 'Ῐ',\n  'Ῑ' => 'Ῑ',\n  'Ὶ' => 'Ὶ',\n  'Ί' => 'Ί',\n  '῝' => '῝',\n  '῞' => '῞',\n  '῟' => '῟',\n  'ῠ' => 'ῠ',\n  'ῡ' => 'ῡ',\n  'ῢ' => 'ῢ',\n  'ΰ' => 'ΰ',\n  'ῤ' => 'ῤ',\n  'ῥ' => 'ῥ',\n  'ῦ' => 'ῦ',\n  'ῧ' => 'ῧ',\n  'Ῠ' => 'Ῠ',\n  'Ῡ' => 'Ῡ',\n  'Ὺ' => 'Ὺ',\n  'Ύ' => 'Ύ',\n  'Ῥ' => 'Ῥ',\n  '῭' => '῭',\n  '΅' => '΅',\n  '`' => '`',\n  'ῲ' => 'ῲ',\n  'ῳ' => 'ῳ',\n  'ῴ' => 'ῴ',\n  'ῶ' => 'ῶ',\n  'ῷ' => 'ῷ',\n  'Ὸ' => 'Ὸ',\n  'Ό' => 'Ό',\n  'Ὼ' => 'Ὼ',\n  'Ώ' => 'Ώ',\n  'ῼ' => 'ῼ',\n  '´' => '´',\n  ' ' => ' ',\n  ' ' => ' ',\n  'Ω' => 'Ω',\n  'K' => 'K',\n  'Å' => 'Å',\n  '↚' => '↚',\n  '↛' => '↛',\n  '↮' => '↮',\n  '⇍' => '⇍',\n  '⇎' => '⇎',\n  '⇏' => '⇏',\n  '∄' => '∄',\n  '∉' => '∉',\n  '∌' => '∌',\n  '∤' => '∤',\n  '∦' => '∦',\n  '≁' => '≁',\n  '≄' => '≄',\n  '≇' => '≇',\n  '≉' => '≉',\n  '≠' => '≠',\n  '≢' => '≢',\n  '≭' => '≭',\n  '≮' => '≮',\n  '≯' => '≯',\n  '≰' => '≰',\n  '≱' => '≱',\n  '≴' => '≴',\n  '≵' => '≵',\n  '≸' => '≸',\n  '≹' => '≹',\n  '⊀' => '⊀',\n  '⊁' => '⊁',\n  '⊄' => '⊄',\n  '⊅' => '⊅',\n  '⊈' => '⊈',\n  '⊉' => '⊉',\n  '⊬' => '⊬',\n  '⊭' => '⊭',\n  '⊮' => '⊮',\n  '⊯' => '⊯',\n  '⋠' => '⋠',\n  '⋡' => '⋡',\n  '⋢' => '⋢',\n  '⋣' => '⋣',\n  '⋪' => '⋪',\n  '⋫' => '⋫',\n  '⋬' => '⋬',\n  '⋭' => '⋭',\n  '〈' => '〈',\n  '〉' => '〉',\n  '⫝̸' => '⫝̸',\n  'が' => 'が',\n  'ぎ' => 'ぎ',\n  'ぐ' => 'ぐ',\n  'げ' => 'げ',\n  'ご' => 'ご',\n  'ざ' => 'ざ',\n  'じ' => 'じ',\n  'ず' => 'ず',\n  'ぜ' => 'ぜ',\n  'ぞ' => 'ぞ',\n  'だ' => 'だ',\n  'ぢ' => 'ぢ',\n  'づ' => 'づ',\n  'で' => 'で',\n  'ど' => 'ど',\n  'ば' => 'ば',\n  'ぱ' => 'ぱ',\n  'び' => 'び',\n  'ぴ' => 'ぴ',\n  'ぶ' => 'ぶ',\n  'ぷ' => 'ぷ',\n  'べ' => 'べ',\n  'ぺ' => 'ぺ',\n  'ぼ' => 'ぼ',\n  'ぽ' => 'ぽ',\n  'ゔ' => 'ゔ',\n  'ゞ' => 'ゞ',\n  'ガ' => 'ガ',\n  'ギ' => 'ギ',\n  'グ' => 'グ',\n  'ゲ' => 'ゲ',\n  'ゴ' => 'ゴ',\n  'ザ' => 'ザ',\n  'ジ' => 'ジ',\n  'ズ' => 'ズ',\n  'ゼ' => 'ゼ',\n  'ゾ' => 'ゾ',\n  'ダ' => 'ダ',\n  'ヂ' => 'ヂ',\n  'ヅ' => 'ヅ',\n  'デ' => 'デ',\n  'ド' => 'ド',\n  'バ' => 'バ',\n  'パ' => 'パ',\n  'ビ' => 'ビ',\n  'ピ' => 'ピ',\n  'ブ' => 'ブ',\n  'プ' => 'プ',\n  'ベ' => 'ベ',\n  'ペ' => 'ペ',\n  'ボ' => 'ボ',\n  'ポ' => 'ポ',\n  'ヴ' => 'ヴ',\n  'ヷ' => 'ヷ',\n  'ヸ' => 'ヸ',\n  'ヹ' => 'ヹ',\n  'ヺ' => 'ヺ',\n  'ヾ' => 'ヾ',\n  '豈' => '豈',\n  '更' => '更',\n  '車' => '車',\n  '賈' => '賈',\n  '滑' => '滑',\n  '串' => '串',\n  '句' => '句',\n  '龜' => '龜',\n  '龜' => '龜',\n  '契' => '契',\n  '金' => '金',\n  '喇' => '喇',\n  '奈' => '奈',\n  '懶' => '懶',\n  '癩' => '癩',\n  '羅' => '羅',\n  '蘿' => '蘿',\n  '螺' => '螺',\n  '裸' => '裸',\n  '邏' => '邏',\n  '樂' => '樂',\n  '洛' => '洛',\n  '烙' => '烙',\n  '珞' => '珞',\n  '落' => '落',\n  '酪' => '酪',\n  '駱' => '駱',\n  '亂' => '亂',\n  '卵' => '卵',\n  '欄' => '欄',\n  '爛' => '爛',\n  '蘭' => '蘭',\n  '鸞' => '鸞',\n  '嵐' => '嵐',\n  '濫' => '濫',\n  '藍' => '藍',\n  '襤' => '襤',\n  '拉' => '拉',\n  '臘' => '臘',\n  '蠟' => '蠟',\n  '廊' => '廊',\n  '朗' => '朗',\n  '浪' => '浪',\n  '狼' => '狼',\n  '郎' => '郎',\n  '來' => '來',\n  '冷' => '冷',\n  '勞' => '勞',\n  '擄' => '擄',\n  '櫓' => '櫓',\n  '爐' => '爐',\n  '盧' => '盧',\n  '老' => '老',\n  '蘆' => '蘆',\n  '虜' => '虜',\n  '路' => '路',\n  '露' => '露',\n  '魯' => '魯',\n  '鷺' => '鷺',\n  '碌' => '碌',\n  '祿' => '祿',\n  '綠' => '綠',\n  '菉' => '菉',\n  '錄' => '錄',\n  '鹿' => '鹿',\n  '論' => '論',\n  '壟' => '壟',\n  '弄' => '弄',\n  '籠' => '籠',\n  '聾' => '聾',\n  '牢' => '牢',\n  '磊' => '磊',\n  '賂' => '賂',\n  '雷' => '雷',\n  '壘' => '壘',\n  '屢' => '屢',\n  '樓' => '樓',\n  '淚' => '淚',\n  '漏' => '漏',\n  '累' => '累',\n  '縷' => '縷',\n  '陋' => '陋',\n  '勒' => '勒',\n  '肋' => '肋',\n  '凜' => '凜',\n  '凌' => '凌',\n  '稜' => '稜',\n  '綾' => '綾',\n  '菱' => '菱',\n  '陵' => '陵',\n  '讀' => '讀',\n  '拏' => '拏',\n  '樂' => '樂',\n  '諾' => '諾',\n  '丹' => '丹',\n  '寧' => '寧',\n  '怒' => '怒',\n  '率' => '率',\n  '異' => '異',\n  '北' => '北',\n  '磻' => '磻',\n  '便' => '便',\n  '復' => '復',\n  '不' => '不',\n  '泌' => '泌',\n  '數' => '數',\n  '索' => '索',\n  '參' => '參',\n  '塞' => '塞',\n  '省' => '省',\n  '葉' => '葉',\n  '說' => '說',\n  '殺' => '殺',\n  '辰' => '辰',\n  '沈' => '沈',\n  '拾' => '拾',\n  '若' => '若',\n  '掠' => '掠',\n  '略' => '略',\n  '亮' => '亮',\n  '兩' => '兩',\n  '凉' => '凉',\n  '梁' => '梁',\n  '糧' => '糧',\n  '良' => '良',\n  '諒' => '諒',\n  '量' => '量',\n  '勵' => '勵',\n  '呂' => '呂',\n  '女' => '女',\n  '廬' => '廬',\n  '旅' => '旅',\n  '濾' => '濾',\n  '礪' => '礪',\n  '閭' => '閭',\n  '驪' => '驪',\n  '麗' => '麗',\n  '黎' => '黎',\n  '力' => '力',\n  '曆' => '曆',\n  '歷' => '歷',\n  '轢' => '轢',\n  '年' => '年',\n  '憐' => '憐',\n  '戀' => '戀',\n  '撚' => '撚',\n  '漣' => '漣',\n  '煉' => '煉',\n  '璉' => '璉',\n  '秊' => '秊',\n  '練' => '練',\n  '聯' => '聯',\n  '輦' => '輦',\n  '蓮' => '蓮',\n  '連' => '連',\n  '鍊' => '鍊',\n  '列' => '列',\n  '劣' => '劣',\n  '咽' => '咽',\n  '烈' => '烈',\n  '裂' => '裂',\n  '說' => '說',\n  '廉' => '廉',\n  '念' => '念',\n  '捻' => '捻',\n  '殮' => '殮',\n  '簾' => '簾',\n  '獵' => '獵',\n  '令' => '令',\n  '囹' => '囹',\n  '寧' => '寧',\n  '嶺' => '嶺',\n  '怜' => '怜',\n  '玲' => '玲',\n  '瑩' => '瑩',\n  '羚' => '羚',\n  '聆' => '聆',\n  '鈴' => '鈴',\n  '零' => '零',\n  '靈' => '靈',\n  '領' => '領',\n  '例' => '例',\n  '禮' => '禮',\n  '醴' => '醴',\n  '隸' => '隸',\n  '惡' => '惡',\n  '了' => '了',\n  '僚' => '僚',\n  '寮' => '寮',\n  '尿' => '尿',\n  '料' => '料',\n  '樂' => '樂',\n  '燎' => '燎',\n  '療' => '療',\n  '蓼' => '蓼',\n  '遼' => '遼',\n  '龍' => '龍',\n  '暈' => '暈',\n  '阮' => '阮',\n  '劉' => '劉',\n  '杻' => '杻',\n  '柳' => '柳',\n  '流' => '流',\n  '溜' => '溜',\n  '琉' => '琉',\n  '留' => '留',\n  '硫' => '硫',\n  '紐' => '紐',\n  '類' => '類',\n  '六' => '六',\n  '戮' => '戮',\n  '陸' => '陸',\n  '倫' => '倫',\n  '崙' => '崙',\n  '淪' => '淪',\n  '輪' => '輪',\n  '律' => '律',\n  '慄' => '慄',\n  '栗' => '栗',\n  '率' => '率',\n  '隆' => '隆',\n  '利' => '利',\n  '吏' => '吏',\n  '履' => '履',\n  '易' => '易',\n  '李' => '李',\n  '梨' => '梨',\n  '泥' => '泥',\n  '理' => '理',\n  '痢' => '痢',\n  '罹' => '罹',\n  '裏' => '裏',\n  '裡' => '裡',\n  '里' => '里',\n  '離' => '離',\n  '匿' => '匿',\n  '溺' => '溺',\n  '吝' => '吝',\n  '燐' => '燐',\n  '璘' => '璘',\n  '藺' => '藺',\n  '隣' => '隣',\n  '鱗' => '鱗',\n  '麟' => '麟',\n  '林' => '林',\n  '淋' => '淋',\n  '臨' => '臨',\n  '立' => '立',\n  '笠' => '笠',\n  '粒' => '粒',\n  '狀' => '狀',\n  '炙' => '炙',\n  '識' => '識',\n  '什' => '什',\n  '茶' => '茶',\n  '刺' => '刺',\n  '切' => '切',\n  '度' => '度',\n  '拓' => '拓',\n  '糖' => '糖',\n  '宅' => '宅',\n  '洞' => '洞',\n  '暴' => '暴',\n  '輻' => '輻',\n  '行' => '行',\n  '降' => '降',\n  '見' => '見',\n  '廓' => '廓',\n  '兀' => '兀',\n  '嗀' => '嗀',\n  '塚' => '塚',\n  '晴' => '晴',\n  '凞' => '凞',\n  '猪' => '猪',\n  '益' => '益',\n  '礼' => '礼',\n  '神' => '神',\n  '祥' => '祥',\n  '福' => '福',\n  '靖' => '靖',\n  '精' => '精',\n  '羽' => '羽',\n  '蘒' => '蘒',\n  '諸' => '諸',\n  '逸' => '逸',\n  '都' => '都',\n  '飯' => '飯',\n  '飼' => '飼',\n  '館' => '館',\n  '鶴' => '鶴',\n  '郞' => '郞',\n  '隷' => '隷',\n  '侮' => '侮',\n  '僧' => '僧',\n  '免' => '免',\n  '勉' => '勉',\n  '勤' => '勤',\n  '卑' => '卑',\n  '喝' => '喝',\n  '嘆' => '嘆',\n  '器' => '器',\n  '塀' => '塀',\n  '墨' => '墨',\n  '層' => '層',\n  '屮' => '屮',\n  '悔' => '悔',\n  '慨' => '慨',\n  '憎' => '憎',\n  '懲' => '懲',\n  '敏' => '敏',\n  '既' => '既',\n  '暑' => '暑',\n  '梅' => '梅',\n  '海' => '海',\n  '渚' => '渚',\n  '漢' => '漢',\n  '煮' => '煮',\n  '爫' => '爫',\n  '琢' => '琢',\n  '碑' => '碑',\n  '社' => '社',\n  '祉' => '祉',\n  '祈' => '祈',\n  '祐' => '祐',\n  '祖' => '祖',\n  '祝' => '祝',\n  '禍' => '禍',\n  '禎' => '禎',\n  '穀' => '穀',\n  '突' => '突',\n  '節' => '節',\n  '練' => '練',\n  '縉' => '縉',\n  '繁' => '繁',\n  '署' => '署',\n  '者' => '者',\n  '臭' => '臭',\n  '艹' => '艹',\n  '艹' => '艹',\n  '著' => '著',\n  '褐' => '褐',\n  '視' => '視',\n  '謁' => '謁',\n  '謹' => '謹',\n  '賓' => '賓',\n  '贈' => '贈',\n  '辶' => '辶',\n  '逸' => '逸',\n  '難' => '難',\n  '響' => '響',\n  '頻' => '頻',\n  '恵' => '恵',\n  '𤋮' => '𤋮',\n  '舘' => '舘',\n  '並' => '並',\n  '况' => '况',\n  '全' => '全',\n  '侀' => '侀',\n  '充' => '充',\n  '冀' => '冀',\n  '勇' => '勇',\n  '勺' => '勺',\n  '喝' => '喝',\n  '啕' => '啕',\n  '喙' => '喙',\n  '嗢' => '嗢',\n  '塚' => '塚',\n  '墳' => '墳',\n  '奄' => '奄',\n  '奔' => '奔',\n  '婢' => '婢',\n  '嬨' => '嬨',\n  '廒' => '廒',\n  '廙' => '廙',\n  '彩' => '彩',\n  '徭' => '徭',\n  '惘' => '惘',\n  '慎' => '慎',\n  '愈' => '愈',\n  '憎' => '憎',\n  '慠' => '慠',\n  '懲' => '懲',\n  '戴' => '戴',\n  '揄' => '揄',\n  '搜' => '搜',\n  '摒' => '摒',\n  '敖' => '敖',\n  '晴' => '晴',\n  '朗' => '朗',\n  '望' => '望',\n  '杖' => '杖',\n  '歹' => '歹',\n  '殺' => '殺',\n  '流' => '流',\n  '滛' => '滛',\n  '滋' => '滋',\n  '漢' => '漢',\n  '瀞' => '瀞',\n  '煮' => '煮',\n  '瞧' => '瞧',\n  '爵' => '爵',\n  '犯' => '犯',\n  '猪' => '猪',\n  '瑱' => '瑱',\n  '甆' => '甆',\n  '画' => '画',\n  '瘝' => '瘝',\n  '瘟' => '瘟',\n  '益' => '益',\n  '盛' => '盛',\n  '直' => '直',\n  '睊' => '睊',\n  '着' => '着',\n  '磌' => '磌',\n  '窱' => '窱',\n  '節' => '節',\n  '类' => '类',\n  '絛' => '絛',\n  '練' => '練',\n  '缾' => '缾',\n  '者' => '者',\n  '荒' => '荒',\n  '華' => '華',\n  '蝹' => '蝹',\n  '襁' => '襁',\n  '覆' => '覆',\n  '視' => '視',\n  '調' => '調',\n  '諸' => '諸',\n  '請' => '請',\n  '謁' => '謁',\n  '諾' => '諾',\n  '諭' => '諭',\n  '謹' => '謹',\n  '變' => '變',\n  '贈' => '贈',\n  '輸' => '輸',\n  '遲' => '遲',\n  '醙' => '醙',\n  '鉶' => '鉶',\n  '陼' => '陼',\n  '難' => '難',\n  '靖' => '靖',\n  '韛' => '韛',\n  '響' => '響',\n  '頋' => '頋',\n  '頻' => '頻',\n  '鬒' => '鬒',\n  '龜' => '龜',\n  '𢡊' => '𢡊',\n  '𢡄' => '𢡄',\n  '𣏕' => '𣏕',\n  '㮝' => '㮝',\n  '䀘' => '䀘',\n  '䀹' => '䀹',\n  '𥉉' => '𥉉',\n  '𥳐' => '𥳐',\n  '𧻓' => '𧻓',\n  '齃' => '齃',\n  '龎' => '龎',\n  'יִ' => 'יִ',\n  'ײַ' => 'ײַ',\n  'שׁ' => 'שׁ',\n  'שׂ' => 'שׂ',\n  'שּׁ' => 'שּׁ',\n  'שּׂ' => 'שּׂ',\n  'אַ' => 'אַ',\n  'אָ' => 'אָ',\n  'אּ' => 'אּ',\n  'בּ' => 'בּ',\n  'גּ' => 'גּ',\n  'דּ' => 'דּ',\n  'הּ' => 'הּ',\n  'וּ' => 'וּ',\n  'זּ' => 'זּ',\n  'טּ' => 'טּ',\n  'יּ' => 'יּ',\n  'ךּ' => 'ךּ',\n  'כּ' => 'כּ',\n  'לּ' => 'לּ',\n  'מּ' => 'מּ',\n  'נּ' => 'נּ',\n  'סּ' => 'סּ',\n  'ףּ' => 'ףּ',\n  'פּ' => 'פּ',\n  'צּ' => 'צּ',\n  'קּ' => 'קּ',\n  'רּ' => 'רּ',\n  'שּ' => 'שּ',\n  'תּ' => 'תּ',\n  'וֹ' => 'וֹ',\n  'בֿ' => 'בֿ',\n  'כֿ' => 'כֿ',\n  'פֿ' => 'פֿ',\n  '𑂚' => '𑂚',\n  '𑂜' => '𑂜',\n  '𑂫' => '𑂫',\n  '𑄮' => '𑄮',\n  '𑄯' => '𑄯',\n  '𑍋' => '𑍋',\n  '𑍌' => '𑍌',\n  '𑒻' => '𑒻',\n  '𑒼' => '𑒼',\n  '𑒾' => '𑒾',\n  '𑖺' => '𑖺',\n  '𑖻' => '𑖻',\n  '𑤸' => '𑤸',\n  '𝅗𝅥' => '𝅗𝅥',\n  '𝅘𝅥' => '𝅘𝅥',\n  '𝅘𝅥𝅮' => '𝅘𝅥𝅮',\n  '𝅘𝅥𝅯' => '𝅘𝅥𝅯',\n  '𝅘𝅥𝅰' => '𝅘𝅥𝅰',\n  '𝅘𝅥𝅱' => '𝅘𝅥𝅱',\n  '𝅘𝅥𝅲' => '𝅘𝅥𝅲',\n  '𝆹𝅥' => '𝆹𝅥',\n  '𝆺𝅥' => '𝆺𝅥',\n  '𝆹𝅥𝅮' => '𝆹𝅥𝅮',\n  '𝆺𝅥𝅮' => '𝆺𝅥𝅮',\n  '𝆹𝅥𝅯' => '𝆹𝅥𝅯',\n  '𝆺𝅥𝅯' => '𝆺𝅥𝅯',\n  '丽' => '丽',\n  '丸' => '丸',\n  '乁' => '乁',\n  '𠄢' => '𠄢',\n  '你' => '你',\n  '侮' => '侮',\n  '侻' => '侻',\n  '倂' => '倂',\n  '偺' => '偺',\n  '備' => '備',\n  '僧' => '僧',\n  '像' => '像',\n  '㒞' => '㒞',\n  '𠘺' => '𠘺',\n  '免' => '免',\n  '兔' => '兔',\n  '兤' => '兤',\n  '具' => '具',\n  '𠔜' => '𠔜',\n  '㒹' => '㒹',\n  '內' => '內',\n  '再' => '再',\n  '𠕋' => '𠕋',\n  '冗' => '冗',\n  '冤' => '冤',\n  '仌' => '仌',\n  '冬' => '冬',\n  '况' => '况',\n  '𩇟' => '𩇟',\n  '凵' => '凵',\n  '刃' => '刃',\n  '㓟' => '㓟',\n  '刻' => '刻',\n  '剆' => '剆',\n  '割' => '割',\n  '剷' => '剷',\n  '㔕' => '㔕',\n  '勇' => '勇',\n  '勉' => '勉',\n  '勤' => '勤',\n  '勺' => '勺',\n  '包' => '包',\n  '匆' => '匆',\n  '北' => '北',\n  '卉' => '卉',\n  '卑' => '卑',\n  '博' => '博',\n  '即' => '即',\n  '卽' => '卽',\n  '卿' => '卿',\n  '卿' => '卿',\n  '卿' => '卿',\n  '𠨬' => '𠨬',\n  '灰' => '灰',\n  '及' => '及',\n  '叟' => '叟',\n  '𠭣' => '𠭣',\n  '叫' => '叫',\n  '叱' => '叱',\n  '吆' => '吆',\n  '咞' => '咞',\n  '吸' => '吸',\n  '呈' => '呈',\n  '周' => '周',\n  '咢' => '咢',\n  '哶' => '哶',\n  '唐' => '唐',\n  '啓' => '啓',\n  '啣' => '啣',\n  '善' => '善',\n  '善' => '善',\n  '喙' => '喙',\n  '喫' => '喫',\n  '喳' => '喳',\n  '嗂' => '嗂',\n  '圖' => '圖',\n  '嘆' => '嘆',\n  '圗' => '圗',\n  '噑' => '噑',\n  '噴' => '噴',\n  '切' => '切',\n  '壮' => '壮',\n  '城' => '城',\n  '埴' => '埴',\n  '堍' => '堍',\n  '型' => '型',\n  '堲' => '堲',\n  '報' => '報',\n  '墬' => '墬',\n  '𡓤' => '𡓤',\n  '売' => '売',\n  '壷' => '壷',\n  '夆' => '夆',\n  '多' => '多',\n  '夢' => '夢',\n  '奢' => '奢',\n  '𡚨' => '𡚨',\n  '𡛪' => '𡛪',\n  '姬' => '姬',\n  '娛' => '娛',\n  '娧' => '娧',\n  '姘' => '姘',\n  '婦' => '婦',\n  '㛮' => '㛮',\n  '㛼' => '㛼',\n  '嬈' => '嬈',\n  '嬾' => '嬾',\n  '嬾' => '嬾',\n  '𡧈' => '𡧈',\n  '寃' => '寃',\n  '寘' => '寘',\n  '寧' => '寧',\n  '寳' => '寳',\n  '𡬘' => '𡬘',\n  '寿' => '寿',\n  '将' => '将',\n  '当' => '当',\n  '尢' => '尢',\n  '㞁' => '㞁',\n  '屠' => '屠',\n  '屮' => '屮',\n  '峀' => '峀',\n  '岍' => '岍',\n  '𡷤' => '𡷤',\n  '嵃' => '嵃',\n  '𡷦' => '𡷦',\n  '嵮' => '嵮',\n  '嵫' => '嵫',\n  '嵼' => '嵼',\n  '巡' => '巡',\n  '巢' => '巢',\n  '㠯' => '㠯',\n  '巽' => '巽',\n  '帨' => '帨',\n  '帽' => '帽',\n  '幩' => '幩',\n  '㡢' => '㡢',\n  '𢆃' => '𢆃',\n  '㡼' => '㡼',\n  '庰' => '庰',\n  '庳' => '庳',\n  '庶' => '庶',\n  '廊' => '廊',\n  '𪎒' => '𪎒',\n  '廾' => '廾',\n  '𢌱' => '𢌱',\n  '𢌱' => '𢌱',\n  '舁' => '舁',\n  '弢' => '弢',\n  '弢' => '弢',\n  '㣇' => '㣇',\n  '𣊸' => '𣊸',\n  '𦇚' => '𦇚',\n  '形' => '形',\n  '彫' => '彫',\n  '㣣' => '㣣',\n  '徚' => '徚',\n  '忍' => '忍',\n  '志' => '志',\n  '忹' => '忹',\n  '悁' => '悁',\n  '㤺' => '㤺',\n  '㤜' => '㤜',\n  '悔' => '悔',\n  '𢛔' => '𢛔',\n  '惇' => '惇',\n  '慈' => '慈',\n  '慌' => '慌',\n  '慎' => '慎',\n  '慌' => '慌',\n  '慺' => '慺',\n  '憎' => '憎',\n  '憲' => '憲',\n  '憤' => '憤',\n  '憯' => '憯',\n  '懞' => '懞',\n  '懲' => '懲',\n  '懶' => '懶',\n  '成' => '成',\n  '戛' => '戛',\n  '扝' => '扝',\n  '抱' => '抱',\n  '拔' => '拔',\n  '捐' => '捐',\n  '𢬌' => '𢬌',\n  '挽' => '挽',\n  '拼' => '拼',\n  '捨' => '捨',\n  '掃' => '掃',\n  '揤' => '揤',\n  '𢯱' => '𢯱',\n  '搢' => '搢',\n  '揅' => '揅',\n  '掩' => '掩',\n  '㨮' => '㨮',\n  '摩' => '摩',\n  '摾' => '摾',\n  '撝' => '撝',\n  '摷' => '摷',\n  '㩬' => '㩬',\n  '敏' => '敏',\n  '敬' => '敬',\n  '𣀊' => '𣀊',\n  '旣' => '旣',\n  '書' => '書',\n  '晉' => '晉',\n  '㬙' => '㬙',\n  '暑' => '暑',\n  '㬈' => '㬈',\n  '㫤' => '㫤',\n  '冒' => '冒',\n  '冕' => '冕',\n  '最' => '最',\n  '暜' => '暜',\n  '肭' => '肭',\n  '䏙' => '䏙',\n  '朗' => '朗',\n  '望' => '望',\n  '朡' => '朡',\n  '杞' => '杞',\n  '杓' => '杓',\n  '𣏃' => '𣏃',\n  '㭉' => '㭉',\n  '柺' => '柺',\n  '枅' => '枅',\n  '桒' => '桒',\n  '梅' => '梅',\n  '𣑭' => '𣑭',\n  '梎' => '梎',\n  '栟' => '栟',\n  '椔' => '椔',\n  '㮝' => '㮝',\n  '楂' => '楂',\n  '榣' => '榣',\n  '槪' => '槪',\n  '檨' => '檨',\n  '𣚣' => '𣚣',\n  '櫛' => '櫛',\n  '㰘' => '㰘',\n  '次' => '次',\n  '𣢧' => '𣢧',\n  '歔' => '歔',\n  '㱎' => '㱎',\n  '歲' => '歲',\n  '殟' => '殟',\n  '殺' => '殺',\n  '殻' => '殻',\n  '𣪍' => '𣪍',\n  '𡴋' => '𡴋',\n  '𣫺' => '𣫺',\n  '汎' => '汎',\n  '𣲼' => '𣲼',\n  '沿' => '沿',\n  '泍' => '泍',\n  '汧' => '汧',\n  '洖' => '洖',\n  '派' => '派',\n  '海' => '海',\n  '流' => '流',\n  '浩' => '浩',\n  '浸' => '浸',\n  '涅' => '涅',\n  '𣴞' => '𣴞',\n  '洴' => '洴',\n  '港' => '港',\n  '湮' => '湮',\n  '㴳' => '㴳',\n  '滋' => '滋',\n  '滇' => '滇',\n  '𣻑' => '𣻑',\n  '淹' => '淹',\n  '潮' => '潮',\n  '𣽞' => '𣽞',\n  '𣾎' => '𣾎',\n  '濆' => '濆',\n  '瀹' => '瀹',\n  '瀞' => '瀞',\n  '瀛' => '瀛',\n  '㶖' => '㶖',\n  '灊' => '灊',\n  '災' => '災',\n  '灷' => '灷',\n  '炭' => '炭',\n  '𠔥' => '𠔥',\n  '煅' => '煅',\n  '𤉣' => '𤉣',\n  '熜' => '熜',\n  '𤎫' => '𤎫',\n  '爨' => '爨',\n  '爵' => '爵',\n  '牐' => '牐',\n  '𤘈' => '𤘈',\n  '犀' => '犀',\n  '犕' => '犕',\n  '𤜵' => '𤜵',\n  '𤠔' => '𤠔',\n  '獺' => '獺',\n  '王' => '王',\n  '㺬' => '㺬',\n  '玥' => '玥',\n  '㺸' => '㺸',\n  '㺸' => '㺸',\n  '瑇' => '瑇',\n  '瑜' => '瑜',\n  '瑱' => '瑱',\n  '璅' => '璅',\n  '瓊' => '瓊',\n  '㼛' => '㼛',\n  '甤' => '甤',\n  '𤰶' => '𤰶',\n  '甾' => '甾',\n  '𤲒' => '𤲒',\n  '異' => '異',\n  '𢆟' => '𢆟',\n  '瘐' => '瘐',\n  '𤾡' => '𤾡',\n  '𤾸' => '𤾸',\n  '𥁄' => '𥁄',\n  '㿼' => '㿼',\n  '䀈' => '䀈',\n  '直' => '直',\n  '𥃳' => '𥃳',\n  '𥃲' => '𥃲',\n  '𥄙' => '𥄙',\n  '𥄳' => '𥄳',\n  '眞' => '眞',\n  '真' => '真',\n  '真' => '真',\n  '睊' => '睊',\n  '䀹' => '䀹',\n  '瞋' => '瞋',\n  '䁆' => '䁆',\n  '䂖' => '䂖',\n  '𥐝' => '𥐝',\n  '硎' => '硎',\n  '碌' => '碌',\n  '磌' => '磌',\n  '䃣' => '䃣',\n  '𥘦' => '𥘦',\n  '祖' => '祖',\n  '𥚚' => '𥚚',\n  '𥛅' => '𥛅',\n  '福' => '福',\n  '秫' => '秫',\n  '䄯' => '䄯',\n  '穀' => '穀',\n  '穊' => '穊',\n  '穏' => '穏',\n  '𥥼' => '𥥼',\n  '𥪧' => '𥪧',\n  '𥪧' => '𥪧',\n  '竮' => '竮',\n  '䈂' => '䈂',\n  '𥮫' => '𥮫',\n  '篆' => '篆',\n  '築' => '築',\n  '䈧' => '䈧',\n  '𥲀' => '𥲀',\n  '糒' => '糒',\n  '䊠' => '䊠',\n  '糨' => '糨',\n  '糣' => '糣',\n  '紀' => '紀',\n  '𥾆' => '𥾆',\n  '絣' => '絣',\n  '䌁' => '䌁',\n  '緇' => '緇',\n  '縂' => '縂',\n  '繅' => '繅',\n  '䌴' => '䌴',\n  '𦈨' => '𦈨',\n  '𦉇' => '𦉇',\n  '䍙' => '䍙',\n  '𦋙' => '𦋙',\n  '罺' => '罺',\n  '𦌾' => '𦌾',\n  '羕' => '羕',\n  '翺' => '翺',\n  '者' => '者',\n  '𦓚' => '𦓚',\n  '𦔣' => '𦔣',\n  '聠' => '聠',\n  '𦖨' => '𦖨',\n  '聰' => '聰',\n  '𣍟' => '𣍟',\n  '䏕' => '䏕',\n  '育' => '育',\n  '脃' => '脃',\n  '䐋' => '䐋',\n  '脾' => '脾',\n  '媵' => '媵',\n  '𦞧' => '𦞧',\n  '𦞵' => '𦞵',\n  '𣎓' => '𣎓',\n  '𣎜' => '𣎜',\n  '舁' => '舁',\n  '舄' => '舄',\n  '辞' => '辞',\n  '䑫' => '䑫',\n  '芑' => '芑',\n  '芋' => '芋',\n  '芝' => '芝',\n  '劳' => '劳',\n  '花' => '花',\n  '芳' => '芳',\n  '芽' => '芽',\n  '苦' => '苦',\n  '𦬼' => '𦬼',\n  '若' => '若',\n  '茝' => '茝',\n  '荣' => '荣',\n  '莭' => '莭',\n  '茣' => '茣',\n  '莽' => '莽',\n  '菧' => '菧',\n  '著' => '著',\n  '荓' => '荓',\n  '菊' => '菊',\n  '菌' => '菌',\n  '菜' => '菜',\n  '𦰶' => '𦰶',\n  '𦵫' => '𦵫',\n  '𦳕' => '𦳕',\n  '䔫' => '䔫',\n  '蓱' => '蓱',\n  '蓳' => '蓳',\n  '蔖' => '蔖',\n  '𧏊' => '𧏊',\n  '蕤' => '蕤',\n  '𦼬' => '𦼬',\n  '䕝' => '䕝',\n  '䕡' => '䕡',\n  '𦾱' => '𦾱',\n  '𧃒' => '𧃒',\n  '䕫' => '䕫',\n  '虐' => '虐',\n  '虜' => '虜',\n  '虧' => '虧',\n  '虩' => '虩',\n  '蚩' => '蚩',\n  '蚈' => '蚈',\n  '蜎' => '蜎',\n  '蛢' => '蛢',\n  '蝹' => '蝹',\n  '蜨' => '蜨',\n  '蝫' => '蝫',\n  '螆' => '螆',\n  '䗗' => '䗗',\n  '蟡' => '蟡',\n  '蠁' => '蠁',\n  '䗹' => '䗹',\n  '衠' => '衠',\n  '衣' => '衣',\n  '𧙧' => '𧙧',\n  '裗' => '裗',\n  '裞' => '裞',\n  '䘵' => '䘵',\n  '裺' => '裺',\n  '㒻' => '㒻',\n  '𧢮' => '𧢮',\n  '𧥦' => '𧥦',\n  '䚾' => '䚾',\n  '䛇' => '䛇',\n  '誠' => '誠',\n  '諭' => '諭',\n  '變' => '變',\n  '豕' => '豕',\n  '𧲨' => '𧲨',\n  '貫' => '貫',\n  '賁' => '賁',\n  '贛' => '贛',\n  '起' => '起',\n  '𧼯' => '𧼯',\n  '𠠄' => '𠠄',\n  '跋' => '跋',\n  '趼' => '趼',\n  '跰' => '跰',\n  '𠣞' => '𠣞',\n  '軔' => '軔',\n  '輸' => '輸',\n  '𨗒' => '𨗒',\n  '𨗭' => '𨗭',\n  '邔' => '邔',\n  '郱' => '郱',\n  '鄑' => '鄑',\n  '𨜮' => '𨜮',\n  '鄛' => '鄛',\n  '鈸' => '鈸',\n  '鋗' => '鋗',\n  '鋘' => '鋘',\n  '鉼' => '鉼',\n  '鏹' => '鏹',\n  '鐕' => '鐕',\n  '𨯺' => '𨯺',\n  '開' => '開',\n  '䦕' => '䦕',\n  '閷' => '閷',\n  '𨵷' => '𨵷',\n  '䧦' => '䧦',\n  '雃' => '雃',\n  '嶲' => '嶲',\n  '霣' => '霣',\n  '𩅅' => '𩅅',\n  '𩈚' => '𩈚',\n  '䩮' => '䩮',\n  '䩶' => '䩶',\n  '韠' => '韠',\n  '𩐊' => '𩐊',\n  '䪲' => '䪲',\n  '𩒖' => '𩒖',\n  '頋' => '頋',\n  '頋' => '頋',\n  '頩' => '頩',\n  '𩖶' => '𩖶',\n  '飢' => '飢',\n  '䬳' => '䬳',\n  '餩' => '餩',\n  '馧' => '馧',\n  '駂' => '駂',\n  '駾' => '駾',\n  '䯎' => '䯎',\n  '𩬰' => '𩬰',\n  '鬒' => '鬒',\n  '鱀' => '鱀',\n  '鳽' => '鳽',\n  '䳎' => '䳎',\n  '䳭' => '䳭',\n  '鵧' => '鵧',\n  '𪃎' => '𪃎',\n  '䳸' => '䳸',\n  '𪄅' => '𪄅',\n  '𪈎' => '𪈎',\n  '𪊑' => '𪊑',\n  '麻' => '麻',\n  '䵖' => '䵖',\n  '黹' => '黹',\n  '黾' => '黾',\n  '鼅' => '鼅',\n  '鼏' => '鼏',\n  '鼖' => '鼖',\n  '鼻' => '鼻',\n  '𪘀' => '𪘀',\n);\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/combiningClass.php",
    "content": "<?php\n\nreturn array (\n  '̀' => 230,\n  '́' => 230,\n  '̂' => 230,\n  '̃' => 230,\n  '̄' => 230,\n  '̅' => 230,\n  '̆' => 230,\n  '̇' => 230,\n  '̈' => 230,\n  '̉' => 230,\n  '̊' => 230,\n  '̋' => 230,\n  '̌' => 230,\n  '̍' => 230,\n  '̎' => 230,\n  '̏' => 230,\n  '̐' => 230,\n  '̑' => 230,\n  '̒' => 230,\n  '̓' => 230,\n  '̔' => 230,\n  '̕' => 232,\n  '̖' => 220,\n  '̗' => 220,\n  '̘' => 220,\n  '̙' => 220,\n  '̚' => 232,\n  '̛' => 216,\n  '̜' => 220,\n  '̝' => 220,\n  '̞' => 220,\n  '̟' => 220,\n  '̠' => 220,\n  '̡' => 202,\n  '̢' => 202,\n  '̣' => 220,\n  '̤' => 220,\n  '̥' => 220,\n  '̦' => 220,\n  '̧' => 202,\n  '̨' => 202,\n  '̩' => 220,\n  '̪' => 220,\n  '̫' => 220,\n  '̬' => 220,\n  '̭' => 220,\n  '̮' => 220,\n  '̯' => 220,\n  '̰' => 220,\n  '̱' => 220,\n  '̲' => 220,\n  '̳' => 220,\n  '̴' => 1,\n  '̵' => 1,\n  '̶' => 1,\n  '̷' => 1,\n  '̸' => 1,\n  '̹' => 220,\n  '̺' => 220,\n  '̻' => 220,\n  '̼' => 220,\n  '̽' => 230,\n  '̾' => 230,\n  '̿' => 230,\n  '̀' => 230,\n  '́' => 230,\n  '͂' => 230,\n  '̓' => 230,\n  '̈́' => 230,\n  'ͅ' => 240,\n  '͆' => 230,\n  '͇' => 220,\n  '͈' => 220,\n  '͉' => 220,\n  '͊' => 230,\n  '͋' => 230,\n  '͌' => 230,\n  '͍' => 220,\n  '͎' => 220,\n  '͐' => 230,\n  '͑' => 230,\n  '͒' => 230,\n  '͓' => 220,\n  '͔' => 220,\n  '͕' => 220,\n  '͖' => 220,\n  '͗' => 230,\n  '͘' => 232,\n  '͙' => 220,\n  '͚' => 220,\n  '͛' => 230,\n  '͜' => 233,\n  '͝' => 234,\n  '͞' => 234,\n  '͟' => 233,\n  '͠' => 234,\n  '͡' => 234,\n  '͢' => 233,\n  'ͣ' => 230,\n  'ͤ' => 230,\n  'ͥ' => 230,\n  'ͦ' => 230,\n  'ͧ' => 230,\n  'ͨ' => 230,\n  'ͩ' => 230,\n  'ͪ' => 230,\n  'ͫ' => 230,\n  'ͬ' => 230,\n  'ͭ' => 230,\n  'ͮ' => 230,\n  'ͯ' => 230,\n  '҃' => 230,\n  '҄' => 230,\n  '҅' => 230,\n  '҆' => 230,\n  '҇' => 230,\n  '֑' => 220,\n  '֒' => 230,\n  '֓' => 230,\n  '֔' => 230,\n  '֕' => 230,\n  '֖' => 220,\n  '֗' => 230,\n  '֘' => 230,\n  '֙' => 230,\n  '֚' => 222,\n  '֛' => 220,\n  '֜' => 230,\n  '֝' => 230,\n  '֞' => 230,\n  '֟' => 230,\n  '֠' => 230,\n  '֡' => 230,\n  '֢' => 220,\n  '֣' => 220,\n  '֤' => 220,\n  '֥' => 220,\n  '֦' => 220,\n  '֧' => 220,\n  '֨' => 230,\n  '֩' => 230,\n  '֪' => 220,\n  '֫' => 230,\n  '֬' => 230,\n  '֭' => 222,\n  '֮' => 228,\n  '֯' => 230,\n  'ְ' => 10,\n  'ֱ' => 11,\n  'ֲ' => 12,\n  'ֳ' => 13,\n  'ִ' => 14,\n  'ֵ' => 15,\n  'ֶ' => 16,\n  'ַ' => 17,\n  'ָ' => 18,\n  'ֹ' => 19,\n  'ֺ' => 19,\n  'ֻ' => 20,\n  'ּ' => 21,\n  'ֽ' => 22,\n  'ֿ' => 23,\n  'ׁ' => 24,\n  'ׂ' => 25,\n  'ׄ' => 230,\n  'ׅ' => 220,\n  'ׇ' => 18,\n  'ؐ' => 230,\n  'ؑ' => 230,\n  'ؒ' => 230,\n  'ؓ' => 230,\n  'ؔ' => 230,\n  'ؕ' => 230,\n  'ؖ' => 230,\n  'ؗ' => 230,\n  'ؘ' => 30,\n  'ؙ' => 31,\n  'ؚ' => 32,\n  'ً' => 27,\n  'ٌ' => 28,\n  'ٍ' => 29,\n  'َ' => 30,\n  'ُ' => 31,\n  'ِ' => 32,\n  'ّ' => 33,\n  'ْ' => 34,\n  'ٓ' => 230,\n  'ٔ' => 230,\n  'ٕ' => 220,\n  'ٖ' => 220,\n  'ٗ' => 230,\n  '٘' => 230,\n  'ٙ' => 230,\n  'ٚ' => 230,\n  'ٛ' => 230,\n  'ٜ' => 220,\n  'ٝ' => 230,\n  'ٞ' => 230,\n  'ٟ' => 220,\n  'ٰ' => 35,\n  'ۖ' => 230,\n  'ۗ' => 230,\n  'ۘ' => 230,\n  'ۙ' => 230,\n  'ۚ' => 230,\n  'ۛ' => 230,\n  'ۜ' => 230,\n  '۟' => 230,\n  '۠' => 230,\n  'ۡ' => 230,\n  'ۢ' => 230,\n  'ۣ' => 220,\n  'ۤ' => 230,\n  'ۧ' => 230,\n  'ۨ' => 230,\n  '۪' => 220,\n  '۫' => 230,\n  '۬' => 230,\n  'ۭ' => 220,\n  'ܑ' => 36,\n  'ܰ' => 230,\n  'ܱ' => 220,\n  'ܲ' => 230,\n  'ܳ' => 230,\n  'ܴ' => 220,\n  'ܵ' => 230,\n  'ܶ' => 230,\n  'ܷ' => 220,\n  'ܸ' => 220,\n  'ܹ' => 220,\n  'ܺ' => 230,\n  'ܻ' => 220,\n  'ܼ' => 220,\n  'ܽ' => 230,\n  'ܾ' => 220,\n  'ܿ' => 230,\n  '݀' => 230,\n  '݁' => 230,\n  '݂' => 220,\n  '݃' => 230,\n  '݄' => 220,\n  '݅' => 230,\n  '݆' => 220,\n  '݇' => 230,\n  '݈' => 220,\n  '݉' => 230,\n  '݊' => 230,\n  '߫' => 230,\n  '߬' => 230,\n  '߭' => 230,\n  '߮' => 230,\n  '߯' => 230,\n  '߰' => 230,\n  '߱' => 230,\n  '߲' => 220,\n  '߳' => 230,\n  '߽' => 220,\n  'ࠖ' => 230,\n  'ࠗ' => 230,\n  '࠘' => 230,\n  '࠙' => 230,\n  'ࠛ' => 230,\n  'ࠜ' => 230,\n  'ࠝ' => 230,\n  'ࠞ' => 230,\n  'ࠟ' => 230,\n  'ࠠ' => 230,\n  'ࠡ' => 230,\n  'ࠢ' => 230,\n  'ࠣ' => 230,\n  'ࠥ' => 230,\n  'ࠦ' => 230,\n  'ࠧ' => 230,\n  'ࠩ' => 230,\n  'ࠪ' => 230,\n  'ࠫ' => 230,\n  'ࠬ' => 230,\n  '࠭' => 230,\n  '࡙' => 220,\n  '࡚' => 220,\n  '࡛' => 220,\n  '࣓' => 220,\n  'ࣔ' => 230,\n  'ࣕ' => 230,\n  'ࣖ' => 230,\n  'ࣗ' => 230,\n  'ࣘ' => 230,\n  'ࣙ' => 230,\n  'ࣚ' => 230,\n  'ࣛ' => 230,\n  'ࣜ' => 230,\n  'ࣝ' => 230,\n  'ࣞ' => 230,\n  'ࣟ' => 230,\n  '࣠' => 230,\n  '࣡' => 230,\n  'ࣣ' => 220,\n  'ࣤ' => 230,\n  'ࣥ' => 230,\n  'ࣦ' => 220,\n  'ࣧ' => 230,\n  'ࣨ' => 230,\n  'ࣩ' => 220,\n  '࣪' => 230,\n  '࣫' => 230,\n  '࣬' => 230,\n  '࣭' => 220,\n  '࣮' => 220,\n  '࣯' => 220,\n  'ࣰ' => 27,\n  'ࣱ' => 28,\n  'ࣲ' => 29,\n  'ࣳ' => 230,\n  'ࣴ' => 230,\n  'ࣵ' => 230,\n  'ࣶ' => 220,\n  'ࣷ' => 230,\n  'ࣸ' => 230,\n  'ࣹ' => 220,\n  'ࣺ' => 220,\n  'ࣻ' => 230,\n  'ࣼ' => 230,\n  'ࣽ' => 230,\n  'ࣾ' => 230,\n  'ࣿ' => 230,\n  '़' => 7,\n  '्' => 9,\n  '॑' => 230,\n  '॒' => 220,\n  '॓' => 230,\n  '॔' => 230,\n  '়' => 7,\n  '্' => 9,\n  '৾' => 230,\n  '਼' => 7,\n  '੍' => 9,\n  '઼' => 7,\n  '્' => 9,\n  '଼' => 7,\n  '୍' => 9,\n  '்' => 9,\n  '్' => 9,\n  'ౕ' => 84,\n  'ౖ' => 91,\n  '಼' => 7,\n  '್' => 9,\n  '഻' => 9,\n  '഼' => 9,\n  '്' => 9,\n  '්' => 9,\n  'ุ' => 103,\n  'ู' => 103,\n  'ฺ' => 9,\n  '่' => 107,\n  '้' => 107,\n  '๊' => 107,\n  '๋' => 107,\n  'ຸ' => 118,\n  'ູ' => 118,\n  '຺' => 9,\n  '່' => 122,\n  '້' => 122,\n  '໊' => 122,\n  '໋' => 122,\n  '༘' => 220,\n  '༙' => 220,\n  '༵' => 220,\n  '༷' => 220,\n  '༹' => 216,\n  'ཱ' => 129,\n  'ི' => 130,\n  'ུ' => 132,\n  'ེ' => 130,\n  'ཻ' => 130,\n  'ོ' => 130,\n  'ཽ' => 130,\n  'ྀ' => 130,\n  'ྂ' => 230,\n  'ྃ' => 230,\n  '྄' => 9,\n  '྆' => 230,\n  '྇' => 230,\n  '࿆' => 220,\n  '့' => 7,\n  '္' => 9,\n  '်' => 9,\n  'ႍ' => 220,\n  '፝' => 230,\n  '፞' => 230,\n  '፟' => 230,\n  '᜔' => 9,\n  '᜴' => 9,\n  '្' => 9,\n  '៝' => 230,\n  'ᢩ' => 228,\n  '᤹' => 222,\n  '᤺' => 230,\n  '᤻' => 220,\n  'ᨗ' => 230,\n  'ᨘ' => 220,\n  '᩠' => 9,\n  '᩵' => 230,\n  '᩶' => 230,\n  '᩷' => 230,\n  '᩸' => 230,\n  '᩹' => 230,\n  '᩺' => 230,\n  '᩻' => 230,\n  '᩼' => 230,\n  '᩿' => 220,\n  '᪰' => 230,\n  '᪱' => 230,\n  '᪲' => 230,\n  '᪳' => 230,\n  '᪴' => 230,\n  '᪵' => 220,\n  '᪶' => 220,\n  '᪷' => 220,\n  '᪸' => 220,\n  '᪹' => 220,\n  '᪺' => 220,\n  '᪻' => 230,\n  '᪼' => 230,\n  '᪽' => 220,\n  'ᪿ' => 220,\n  'ᫀ' => 220,\n  '᬴' => 7,\n  '᭄' => 9,\n  '᭫' => 230,\n  '᭬' => 220,\n  '᭭' => 230,\n  '᭮' => 230,\n  '᭯' => 230,\n  '᭰' => 230,\n  '᭱' => 230,\n  '᭲' => 230,\n  '᭳' => 230,\n  '᮪' => 9,\n  '᮫' => 9,\n  '᯦' => 7,\n  '᯲' => 9,\n  '᯳' => 9,\n  '᰷' => 7,\n  '᳐' => 230,\n  '᳑' => 230,\n  '᳒' => 230,\n  '᳔' => 1,\n  '᳕' => 220,\n  '᳖' => 220,\n  '᳗' => 220,\n  '᳘' => 220,\n  '᳙' => 220,\n  '᳚' => 230,\n  '᳛' => 230,\n  '᳜' => 220,\n  '᳝' => 220,\n  '᳞' => 220,\n  '᳟' => 220,\n  '᳠' => 230,\n  '᳢' => 1,\n  '᳣' => 1,\n  '᳤' => 1,\n  '᳥' => 1,\n  '᳦' => 1,\n  '᳧' => 1,\n  '᳨' => 1,\n  '᳭' => 220,\n  '᳴' => 230,\n  '᳸' => 230,\n  '᳹' => 230,\n  '᷀' => 230,\n  '᷁' => 230,\n  '᷂' => 220,\n  '᷃' => 230,\n  '᷄' => 230,\n  '᷅' => 230,\n  '᷆' => 230,\n  '᷇' => 230,\n  '᷈' => 230,\n  '᷉' => 230,\n  '᷊' => 220,\n  '᷋' => 230,\n  '᷌' => 230,\n  '᷍' => 234,\n  '᷎' => 214,\n  '᷏' => 220,\n  '᷐' => 202,\n  '᷑' => 230,\n  '᷒' => 230,\n  'ᷓ' => 230,\n  'ᷔ' => 230,\n  'ᷕ' => 230,\n  'ᷖ' => 230,\n  'ᷗ' => 230,\n  'ᷘ' => 230,\n  'ᷙ' => 230,\n  'ᷚ' => 230,\n  'ᷛ' => 230,\n  'ᷜ' => 230,\n  'ᷝ' => 230,\n  'ᷞ' => 230,\n  'ᷟ' => 230,\n  'ᷠ' => 230,\n  'ᷡ' => 230,\n  'ᷢ' => 230,\n  'ᷣ' => 230,\n  'ᷤ' => 230,\n  'ᷥ' => 230,\n  'ᷦ' => 230,\n  'ᷧ' => 230,\n  'ᷨ' => 230,\n  'ᷩ' => 230,\n  'ᷪ' => 230,\n  'ᷫ' => 230,\n  'ᷬ' => 230,\n  'ᷭ' => 230,\n  'ᷮ' => 230,\n  'ᷯ' => 230,\n  'ᷰ' => 230,\n  'ᷱ' => 230,\n  'ᷲ' => 230,\n  'ᷳ' => 230,\n  'ᷴ' => 230,\n  '᷵' => 230,\n  '᷶' => 232,\n  '᷷' => 228,\n  '᷸' => 228,\n  '᷹' => 220,\n  '᷻' => 230,\n  '᷼' => 233,\n  '᷽' => 220,\n  '᷾' => 230,\n  '᷿' => 220,\n  '⃐' => 230,\n  '⃑' => 230,\n  '⃒' => 1,\n  '⃓' => 1,\n  '⃔' => 230,\n  '⃕' => 230,\n  '⃖' => 230,\n  '⃗' => 230,\n  '⃘' => 1,\n  '⃙' => 1,\n  '⃚' => 1,\n  '⃛' => 230,\n  '⃜' => 230,\n  '⃡' => 230,\n  '⃥' => 1,\n  '⃦' => 1,\n  '⃧' => 230,\n  '⃨' => 220,\n  '⃩' => 230,\n  '⃪' => 1,\n  '⃫' => 1,\n  '⃬' => 220,\n  '⃭' => 220,\n  '⃮' => 220,\n  '⃯' => 220,\n  '⃰' => 230,\n  '⳯' => 230,\n  '⳰' => 230,\n  '⳱' => 230,\n  '⵿' => 9,\n  'ⷠ' => 230,\n  'ⷡ' => 230,\n  'ⷢ' => 230,\n  'ⷣ' => 230,\n  'ⷤ' => 230,\n  'ⷥ' => 230,\n  'ⷦ' => 230,\n  'ⷧ' => 230,\n  'ⷨ' => 230,\n  'ⷩ' => 230,\n  'ⷪ' => 230,\n  'ⷫ' => 230,\n  'ⷬ' => 230,\n  'ⷭ' => 230,\n  'ⷮ' => 230,\n  'ⷯ' => 230,\n  'ⷰ' => 230,\n  'ⷱ' => 230,\n  'ⷲ' => 230,\n  'ⷳ' => 230,\n  'ⷴ' => 230,\n  'ⷵ' => 230,\n  'ⷶ' => 230,\n  'ⷷ' => 230,\n  'ⷸ' => 230,\n  'ⷹ' => 230,\n  'ⷺ' => 230,\n  'ⷻ' => 230,\n  'ⷼ' => 230,\n  'ⷽ' => 230,\n  'ⷾ' => 230,\n  'ⷿ' => 230,\n  '〪' => 218,\n  '〫' => 228,\n  '〬' => 232,\n  '〭' => 222,\n  '〮' => 224,\n  '〯' => 224,\n  '゙' => 8,\n  '゚' => 8,\n  '꙯' => 230,\n  'ꙴ' => 230,\n  'ꙵ' => 230,\n  'ꙶ' => 230,\n  'ꙷ' => 230,\n  'ꙸ' => 230,\n  'ꙹ' => 230,\n  'ꙺ' => 230,\n  'ꙻ' => 230,\n  '꙼' => 230,\n  '꙽' => 230,\n  'ꚞ' => 230,\n  'ꚟ' => 230,\n  '꛰' => 230,\n  '꛱' => 230,\n  '꠆' => 9,\n  '꠬' => 9,\n  '꣄' => 9,\n  '꣠' => 230,\n  '꣡' => 230,\n  '꣢' => 230,\n  '꣣' => 230,\n  '꣤' => 230,\n  '꣥' => 230,\n  '꣦' => 230,\n  '꣧' => 230,\n  '꣨' => 230,\n  '꣩' => 230,\n  '꣪' => 230,\n  '꣫' => 230,\n  '꣬' => 230,\n  '꣭' => 230,\n  '꣮' => 230,\n  '꣯' => 230,\n  '꣰' => 230,\n  '꣱' => 230,\n  '꤫' => 220,\n  '꤬' => 220,\n  '꤭' => 220,\n  '꥓' => 9,\n  '꦳' => 7,\n  '꧀' => 9,\n  'ꪰ' => 230,\n  'ꪲ' => 230,\n  'ꪳ' => 230,\n  'ꪴ' => 220,\n  'ꪷ' => 230,\n  'ꪸ' => 230,\n  'ꪾ' => 230,\n  '꪿' => 230,\n  '꫁' => 230,\n  '꫶' => 9,\n  '꯭' => 9,\n  'ﬞ' => 26,\n  '︠' => 230,\n  '︡' => 230,\n  '︢' => 230,\n  '︣' => 230,\n  '︤' => 230,\n  '︥' => 230,\n  '︦' => 230,\n  '︧' => 220,\n  '︨' => 220,\n  '︩' => 220,\n  '︪' => 220,\n  '︫' => 220,\n  '︬' => 220,\n  '︭' => 220,\n  '︮' => 230,\n  '︯' => 230,\n  '𐇽' => 220,\n  '𐋠' => 220,\n  '𐍶' => 230,\n  '𐍷' => 230,\n  '𐍸' => 230,\n  '𐍹' => 230,\n  '𐍺' => 230,\n  '𐨍' => 220,\n  '𐨏' => 230,\n  '𐨸' => 230,\n  '𐨹' => 1,\n  '𐨺' => 220,\n  '𐨿' => 9,\n  '𐫥' => 230,\n  '𐫦' => 220,\n  '𐴤' => 230,\n  '𐴥' => 230,\n  '𐴦' => 230,\n  '𐴧' => 230,\n  '𐺫' => 230,\n  '𐺬' => 230,\n  '𐽆' => 220,\n  '𐽇' => 220,\n  '𐽈' => 230,\n  '𐽉' => 230,\n  '𐽊' => 230,\n  '𐽋' => 220,\n  '𐽌' => 230,\n  '𐽍' => 220,\n  '𐽎' => 220,\n  '𐽏' => 220,\n  '𐽐' => 220,\n  '𑁆' => 9,\n  '𑁿' => 9,\n  '𑂹' => 9,\n  '𑂺' => 7,\n  '𑄀' => 230,\n  '𑄁' => 230,\n  '𑄂' => 230,\n  '𑄳' => 9,\n  '𑄴' => 9,\n  '𑅳' => 7,\n  '𑇀' => 9,\n  '𑇊' => 7,\n  '𑈵' => 9,\n  '𑈶' => 7,\n  '𑋩' => 7,\n  '𑋪' => 9,\n  '𑌻' => 7,\n  '𑌼' => 7,\n  '𑍍' => 9,\n  '𑍦' => 230,\n  '𑍧' => 230,\n  '𑍨' => 230,\n  '𑍩' => 230,\n  '𑍪' => 230,\n  '𑍫' => 230,\n  '𑍬' => 230,\n  '𑍰' => 230,\n  '𑍱' => 230,\n  '𑍲' => 230,\n  '𑍳' => 230,\n  '𑍴' => 230,\n  '𑑂' => 9,\n  '𑑆' => 7,\n  '𑑞' => 230,\n  '𑓂' => 9,\n  '𑓃' => 7,\n  '𑖿' => 9,\n  '𑗀' => 7,\n  '𑘿' => 9,\n  '𑚶' => 9,\n  '𑚷' => 7,\n  '𑜫' => 9,\n  '𑠹' => 9,\n  '𑠺' => 7,\n  '𑤽' => 9,\n  '𑤾' => 9,\n  '𑥃' => 7,\n  '𑧠' => 9,\n  '𑨴' => 9,\n  '𑩇' => 9,\n  '𑪙' => 9,\n  '𑰿' => 9,\n  '𑵂' => 7,\n  '𑵄' => 9,\n  '𑵅' => 9,\n  '𑶗' => 9,\n  '𖫰' => 1,\n  '𖫱' => 1,\n  '𖫲' => 1,\n  '𖫳' => 1,\n  '𖫴' => 1,\n  '𖬰' => 230,\n  '𖬱' => 230,\n  '𖬲' => 230,\n  '𖬳' => 230,\n  '𖬴' => 230,\n  '𖬵' => 230,\n  '𖬶' => 230,\n  '𖿰' => 6,\n  '𖿱' => 6,\n  '𛲞' => 1,\n  '𝅥' => 216,\n  '𝅦' => 216,\n  '𝅧' => 1,\n  '𝅨' => 1,\n  '𝅩' => 1,\n  '𝅭' => 226,\n  '𝅮' => 216,\n  '𝅯' => 216,\n  '𝅰' => 216,\n  '𝅱' => 216,\n  '𝅲' => 216,\n  '𝅻' => 220,\n  '𝅼' => 220,\n  '𝅽' => 220,\n  '𝅾' => 220,\n  '𝅿' => 220,\n  '𝆀' => 220,\n  '𝆁' => 220,\n  '𝆂' => 220,\n  '𝆅' => 230,\n  '𝆆' => 230,\n  '𝆇' => 230,\n  '𝆈' => 230,\n  '𝆉' => 230,\n  '𝆊' => 220,\n  '𝆋' => 220,\n  '𝆪' => 230,\n  '𝆫' => 230,\n  '𝆬' => 230,\n  '𝆭' => 230,\n  '𝉂' => 230,\n  '𝉃' => 230,\n  '𝉄' => 230,\n  '𞀀' => 230,\n  '𞀁' => 230,\n  '𞀂' => 230,\n  '𞀃' => 230,\n  '𞀄' => 230,\n  '𞀅' => 230,\n  '𞀆' => 230,\n  '𞀈' => 230,\n  '𞀉' => 230,\n  '𞀊' => 230,\n  '𞀋' => 230,\n  '𞀌' => 230,\n  '𞀍' => 230,\n  '𞀎' => 230,\n  '𞀏' => 230,\n  '𞀐' => 230,\n  '𞀑' => 230,\n  '𞀒' => 230,\n  '𞀓' => 230,\n  '𞀔' => 230,\n  '𞀕' => 230,\n  '𞀖' => 230,\n  '𞀗' => 230,\n  '𞀘' => 230,\n  '𞀛' => 230,\n  '𞀜' => 230,\n  '𞀝' => 230,\n  '𞀞' => 230,\n  '𞀟' => 230,\n  '𞀠' => 230,\n  '𞀡' => 230,\n  '𞀣' => 230,\n  '𞀤' => 230,\n  '𞀦' => 230,\n  '𞀧' => 230,\n  '𞀨' => 230,\n  '𞀩' => 230,\n  '𞀪' => 230,\n  '𞄰' => 230,\n  '𞄱' => 230,\n  '𞄲' => 230,\n  '𞄳' => 230,\n  '𞄴' => 230,\n  '𞄵' => 230,\n  '𞄶' => 230,\n  '𞋬' => 230,\n  '𞋭' => 230,\n  '𞋮' => 230,\n  '𞋯' => 230,\n  '𞣐' => 220,\n  '𞣑' => 220,\n  '𞣒' => 220,\n  '𞣓' => 220,\n  '𞣔' => 220,\n  '𞣕' => 220,\n  '𞣖' => 220,\n  '𞥄' => 230,\n  '𞥅' => 230,\n  '𞥆' => 230,\n  '𞥇' => 230,\n  '𞥈' => 230,\n  '𞥉' => 230,\n  '𞥊' => 7,\n);\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/compatibilityDecomposition.php",
    "content": "<?php\n\nreturn array (\n  ' ' => ' ',\n  '¨' => ' ̈',\n  'ª' => 'a',\n  '¯' => ' ̄',\n  '²' => '2',\n  '³' => '3',\n  '´' => ' ́',\n  'µ' => 'μ',\n  '¸' => ' ̧',\n  '¹' => '1',\n  'º' => 'o',\n  '¼' => '1⁄4',\n  '½' => '1⁄2',\n  '¾' => '3⁄4',\n  'Ĳ' => 'IJ',\n  'ĳ' => 'ij',\n  'Ŀ' => 'L·',\n  'ŀ' => 'l·',\n  'ŉ' => 'ʼn',\n  'ſ' => 's',\n  'Ǆ' => 'DŽ',\n  'ǅ' => 'Dž',\n  'ǆ' => 'dž',\n  'Ǉ' => 'LJ',\n  'ǈ' => 'Lj',\n  'ǉ' => 'lj',\n  'Ǌ' => 'NJ',\n  'ǋ' => 'Nj',\n  'ǌ' => 'nj',\n  'Ǳ' => 'DZ',\n  'ǲ' => 'Dz',\n  'ǳ' => 'dz',\n  'ʰ' => 'h',\n  'ʱ' => 'ɦ',\n  'ʲ' => 'j',\n  'ʳ' => 'r',\n  'ʴ' => 'ɹ',\n  'ʵ' => 'ɻ',\n  'ʶ' => 'ʁ',\n  'ʷ' => 'w',\n  'ʸ' => 'y',\n  '˘' => ' ̆',\n  '˙' => ' ̇',\n  '˚' => ' ̊',\n  '˛' => ' ̨',\n  '˜' => ' ̃',\n  '˝' => ' ̋',\n  'ˠ' => 'ɣ',\n  'ˡ' => 'l',\n  'ˢ' => 's',\n  'ˣ' => 'x',\n  'ˤ' => 'ʕ',\n  'ͺ' => ' ͅ',\n  '΄' => ' ́',\n  '΅' => ' ̈́',\n  'ϐ' => 'β',\n  'ϑ' => 'θ',\n  'ϒ' => 'Υ',\n  'ϓ' => 'Ύ',\n  'ϔ' => 'Ϋ',\n  'ϕ' => 'φ',\n  'ϖ' => 'π',\n  'ϰ' => 'κ',\n  'ϱ' => 'ρ',\n  'ϲ' => 'ς',\n  'ϴ' => 'Θ',\n  'ϵ' => 'ε',\n  'Ϲ' => 'Σ',\n  'և' => 'եւ',\n  'ٵ' => 'اٴ',\n  'ٶ' => 'وٴ',\n  'ٷ' => 'ۇٴ',\n  'ٸ' => 'يٴ',\n  'ำ' => 'ํา',\n  'ຳ' => 'ໍາ',\n  'ໜ' => 'ຫນ',\n  'ໝ' => 'ຫມ',\n  '༌' => '་',\n  'ཷ' => 'ྲཱྀ',\n  'ཹ' => 'ླཱྀ',\n  'ჼ' => 'ნ',\n  'ᴬ' => 'A',\n  'ᴭ' => 'Æ',\n  'ᴮ' => 'B',\n  'ᴰ' => 'D',\n  'ᴱ' => 'E',\n  'ᴲ' => 'Ǝ',\n  'ᴳ' => 'G',\n  'ᴴ' => 'H',\n  'ᴵ' => 'I',\n  'ᴶ' => 'J',\n  'ᴷ' => 'K',\n  'ᴸ' => 'L',\n  'ᴹ' => 'M',\n  'ᴺ' => 'N',\n  'ᴼ' => 'O',\n  'ᴽ' => 'Ȣ',\n  'ᴾ' => 'P',\n  'ᴿ' => 'R',\n  'ᵀ' => 'T',\n  'ᵁ' => 'U',\n  'ᵂ' => 'W',\n  'ᵃ' => 'a',\n  'ᵄ' => 'ɐ',\n  'ᵅ' => 'ɑ',\n  'ᵆ' => 'ᴂ',\n  'ᵇ' => 'b',\n  'ᵈ' => 'd',\n  'ᵉ' => 'e',\n  'ᵊ' => 'ə',\n  'ᵋ' => 'ɛ',\n  'ᵌ' => 'ɜ',\n  'ᵍ' => 'g',\n  'ᵏ' => 'k',\n  'ᵐ' => 'm',\n  'ᵑ' => 'ŋ',\n  'ᵒ' => 'o',\n  'ᵓ' => 'ɔ',\n  'ᵔ' => 'ᴖ',\n  'ᵕ' => 'ᴗ',\n  'ᵖ' => 'p',\n  'ᵗ' => 't',\n  'ᵘ' => 'u',\n  'ᵙ' => 'ᴝ',\n  'ᵚ' => 'ɯ',\n  'ᵛ' => 'v',\n  'ᵜ' => 'ᴥ',\n  'ᵝ' => 'β',\n  'ᵞ' => 'γ',\n  'ᵟ' => 'δ',\n  'ᵠ' => 'φ',\n  'ᵡ' => 'χ',\n  'ᵢ' => 'i',\n  'ᵣ' => 'r',\n  'ᵤ' => 'u',\n  'ᵥ' => 'v',\n  'ᵦ' => 'β',\n  'ᵧ' => 'γ',\n  'ᵨ' => 'ρ',\n  'ᵩ' => 'φ',\n  'ᵪ' => 'χ',\n  'ᵸ' => 'н',\n  'ᶛ' => 'ɒ',\n  'ᶜ' => 'c',\n  'ᶝ' => 'ɕ',\n  'ᶞ' => 'ð',\n  'ᶟ' => 'ɜ',\n  'ᶠ' => 'f',\n  'ᶡ' => 'ɟ',\n  'ᶢ' => 'ɡ',\n  'ᶣ' => 'ɥ',\n  'ᶤ' => 'ɨ',\n  'ᶥ' => 'ɩ',\n  'ᶦ' => 'ɪ',\n  'ᶧ' => 'ᵻ',\n  'ᶨ' => 'ʝ',\n  'ᶩ' => 'ɭ',\n  'ᶪ' => 'ᶅ',\n  'ᶫ' => 'ʟ',\n  'ᶬ' => 'ɱ',\n  'ᶭ' => 'ɰ',\n  'ᶮ' => 'ɲ',\n  'ᶯ' => 'ɳ',\n  'ᶰ' => 'ɴ',\n  'ᶱ' => 'ɵ',\n  'ᶲ' => 'ɸ',\n  'ᶳ' => 'ʂ',\n  'ᶴ' => 'ʃ',\n  'ᶵ' => 'ƫ',\n  'ᶶ' => 'ʉ',\n  'ᶷ' => 'ʊ',\n  'ᶸ' => 'ᴜ',\n  'ᶹ' => 'ʋ',\n  'ᶺ' => 'ʌ',\n  'ᶻ' => 'z',\n  'ᶼ' => 'ʐ',\n  'ᶽ' => 'ʑ',\n  'ᶾ' => 'ʒ',\n  'ᶿ' => 'θ',\n  'ẚ' => 'aʾ',\n  'ẛ' => 'ṡ',\n  '᾽' => ' ̓',\n  '᾿' => ' ̓',\n  '῀' => ' ͂',\n  '῁' => ' ̈͂',\n  '῍' => ' ̓̀',\n  '῎' => ' ̓́',\n  '῏' => ' ̓͂',\n  '῝' => ' ̔̀',\n  '῞' => ' ̔́',\n  '῟' => ' ̔͂',\n  '῭' => ' ̈̀',\n  '΅' => ' ̈́',\n  '´' => ' ́',\n  '῾' => ' ̔',\n  ' ' => ' ',\n  ' ' => ' ',\n  ' ' => ' ',\n  ' ' => ' ',\n  ' ' => ' ',\n  ' ' => ' ',\n  ' ' => ' ',\n  ' ' => ' ',\n  ' ' => ' ',\n  ' ' => ' ',\n  ' ' => ' ',\n  '‑' => '‐',\n  '‗' => ' ̳',\n  '․' => '.',\n  '‥' => '..',\n  '…' => '...',\n  ' ' => ' ',\n  '″' => '′′',\n  '‴' => '′′′',\n  '‶' => '‵‵',\n  '‷' => '‵‵‵',\n  '‼' => '!!',\n  '‾' => ' ̅',\n  '⁇' => '??',\n  '⁈' => '?!',\n  '⁉' => '!?',\n  '⁗' => '′′′′',\n  ' ' => ' ',\n  '⁰' => '0',\n  'ⁱ' => 'i',\n  '⁴' => '4',\n  '⁵' => '5',\n  '⁶' => '6',\n  '⁷' => '7',\n  '⁸' => '8',\n  '⁹' => '9',\n  '⁺' => '+',\n  '⁻' => '−',\n  '⁼' => '=',\n  '⁽' => '(',\n  '⁾' => ')',\n  'ⁿ' => 'n',\n  '₀' => '0',\n  '₁' => '1',\n  '₂' => '2',\n  '₃' => '3',\n  '₄' => '4',\n  '₅' => '5',\n  '₆' => '6',\n  '₇' => '7',\n  '₈' => '8',\n  '₉' => '9',\n  '₊' => '+',\n  '₋' => '−',\n  '₌' => '=',\n  '₍' => '(',\n  '₎' => ')',\n  'ₐ' => 'a',\n  'ₑ' => 'e',\n  'ₒ' => 'o',\n  'ₓ' => 'x',\n  'ₔ' => 'ə',\n  'ₕ' => 'h',\n  'ₖ' => 'k',\n  'ₗ' => 'l',\n  'ₘ' => 'm',\n  'ₙ' => 'n',\n  'ₚ' => 'p',\n  'ₛ' => 's',\n  'ₜ' => 't',\n  '₨' => 'Rs',\n  '℀' => 'a/c',\n  '℁' => 'a/s',\n  'ℂ' => 'C',\n  '℃' => '°C',\n  '℅' => 'c/o',\n  '℆' => 'c/u',\n  'ℇ' => 'Ɛ',\n  '℉' => '°F',\n  'ℊ' => 'g',\n  'ℋ' => 'H',\n  'ℌ' => 'H',\n  'ℍ' => 'H',\n  'ℎ' => 'h',\n  'ℏ' => 'ħ',\n  'ℐ' => 'I',\n  'ℑ' => 'I',\n  'ℒ' => 'L',\n  'ℓ' => 'l',\n  'ℕ' => 'N',\n  '№' => 'No',\n  'ℙ' => 'P',\n  'ℚ' => 'Q',\n  'ℛ' => 'R',\n  'ℜ' => 'R',\n  'ℝ' => 'R',\n  '℠' => 'SM',\n  '℡' => 'TEL',\n  '™' => 'TM',\n  'ℤ' => 'Z',\n  'ℨ' => 'Z',\n  'ℬ' => 'B',\n  'ℭ' => 'C',\n  'ℯ' => 'e',\n  'ℰ' => 'E',\n  'ℱ' => 'F',\n  'ℳ' => 'M',\n  'ℴ' => 'o',\n  'ℵ' => 'א',\n  'ℶ' => 'ב',\n  'ℷ' => 'ג',\n  'ℸ' => 'ד',\n  'ℹ' => 'i',\n  '℻' => 'FAX',\n  'ℼ' => 'π',\n  'ℽ' => 'γ',\n  'ℾ' => 'Γ',\n  'ℿ' => 'Π',\n  '⅀' => '∑',\n  'ⅅ' => 'D',\n  'ⅆ' => 'd',\n  'ⅇ' => 'e',\n  'ⅈ' => 'i',\n  'ⅉ' => 'j',\n  '⅐' => '1⁄7',\n  '⅑' => '1⁄9',\n  '⅒' => '1⁄10',\n  '⅓' => '1⁄3',\n  '⅔' => '2⁄3',\n  '⅕' => '1⁄5',\n  '⅖' => '2⁄5',\n  '⅗' => '3⁄5',\n  '⅘' => '4⁄5',\n  '⅙' => '1⁄6',\n  '⅚' => '5⁄6',\n  '⅛' => '1⁄8',\n  '⅜' => '3⁄8',\n  '⅝' => '5⁄8',\n  '⅞' => '7⁄8',\n  '⅟' => '1⁄',\n  'Ⅰ' => 'I',\n  'Ⅱ' => 'II',\n  'Ⅲ' => 'III',\n  'Ⅳ' => 'IV',\n  'Ⅴ' => 'V',\n  'Ⅵ' => 'VI',\n  'Ⅶ' => 'VII',\n  'Ⅷ' => 'VIII',\n  'Ⅸ' => 'IX',\n  'Ⅹ' => 'X',\n  'Ⅺ' => 'XI',\n  'Ⅻ' => 'XII',\n  'Ⅼ' => 'L',\n  'Ⅽ' => 'C',\n  'Ⅾ' => 'D',\n  'Ⅿ' => 'M',\n  'ⅰ' => 'i',\n  'ⅱ' => 'ii',\n  'ⅲ' => 'iii',\n  'ⅳ' => 'iv',\n  'ⅴ' => 'v',\n  'ⅵ' => 'vi',\n  'ⅶ' => 'vii',\n  'ⅷ' => 'viii',\n  'ⅸ' => 'ix',\n  'ⅹ' => 'x',\n  'ⅺ' => 'xi',\n  'ⅻ' => 'xii',\n  'ⅼ' => 'l',\n  'ⅽ' => 'c',\n  'ⅾ' => 'd',\n  'ⅿ' => 'm',\n  '↉' => '0⁄3',\n  '∬' => '∫∫',\n  '∭' => '∫∫∫',\n  '∯' => '∮∮',\n  '∰' => '∮∮∮',\n  '①' => '1',\n  '②' => '2',\n  '③' => '3',\n  '④' => '4',\n  '⑤' => '5',\n  '⑥' => '6',\n  '⑦' => '7',\n  '⑧' => '8',\n  '⑨' => '9',\n  '⑩' => '10',\n  '⑪' => '11',\n  '⑫' => '12',\n  '⑬' => '13',\n  '⑭' => '14',\n  '⑮' => '15',\n  '⑯' => '16',\n  '⑰' => '17',\n  '⑱' => '18',\n  '⑲' => '19',\n  '⑳' => '20',\n  '⑴' => '(1)',\n  '⑵' => '(2)',\n  '⑶' => '(3)',\n  '⑷' => '(4)',\n  '⑸' => '(5)',\n  '⑹' => '(6)',\n  '⑺' => '(7)',\n  '⑻' => '(8)',\n  '⑼' => '(9)',\n  '⑽' => '(10)',\n  '⑾' => '(11)',\n  '⑿' => '(12)',\n  '⒀' => '(13)',\n  '⒁' => '(14)',\n  '⒂' => '(15)',\n  '⒃' => '(16)',\n  '⒄' => '(17)',\n  '⒅' => '(18)',\n  '⒆' => '(19)',\n  '⒇' => '(20)',\n  '⒈' => '1.',\n  '⒉' => '2.',\n  '⒊' => '3.',\n  '⒋' => '4.',\n  '⒌' => '5.',\n  '⒍' => '6.',\n  '⒎' => '7.',\n  '⒏' => '8.',\n  '⒐' => '9.',\n  '⒑' => '10.',\n  '⒒' => '11.',\n  '⒓' => '12.',\n  '⒔' => '13.',\n  '⒕' => '14.',\n  '⒖' => '15.',\n  '⒗' => '16.',\n  '⒘' => '17.',\n  '⒙' => '18.',\n  '⒚' => '19.',\n  '⒛' => '20.',\n  '⒜' => '(a)',\n  '⒝' => '(b)',\n  '⒞' => '(c)',\n  '⒟' => '(d)',\n  '⒠' => '(e)',\n  '⒡' => '(f)',\n  '⒢' => '(g)',\n  '⒣' => '(h)',\n  '⒤' => '(i)',\n  '⒥' => '(j)',\n  '⒦' => '(k)',\n  '⒧' => '(l)',\n  '⒨' => '(m)',\n  '⒩' => '(n)',\n  '⒪' => '(o)',\n  '⒫' => '(p)',\n  '⒬' => '(q)',\n  '⒭' => '(r)',\n  '⒮' => '(s)',\n  '⒯' => '(t)',\n  '⒰' => '(u)',\n  '⒱' => '(v)',\n  '⒲' => '(w)',\n  '⒳' => '(x)',\n  '⒴' => '(y)',\n  '⒵' => '(z)',\n  'Ⓐ' => 'A',\n  'Ⓑ' => 'B',\n  'Ⓒ' => 'C',\n  'Ⓓ' => 'D',\n  'Ⓔ' => 'E',\n  'Ⓕ' => 'F',\n  'Ⓖ' => 'G',\n  'Ⓗ' => 'H',\n  'Ⓘ' => 'I',\n  'Ⓙ' => 'J',\n  'Ⓚ' => 'K',\n  'Ⓛ' => 'L',\n  'Ⓜ' => 'M',\n  'Ⓝ' => 'N',\n  'Ⓞ' => 'O',\n  'Ⓟ' => 'P',\n  'Ⓠ' => 'Q',\n  'Ⓡ' => 'R',\n  'Ⓢ' => 'S',\n  'Ⓣ' => 'T',\n  'Ⓤ' => 'U',\n  'Ⓥ' => 'V',\n  'Ⓦ' => 'W',\n  'Ⓧ' => 'X',\n  'Ⓨ' => 'Y',\n  'Ⓩ' => 'Z',\n  'ⓐ' => 'a',\n  'ⓑ' => 'b',\n  'ⓒ' => 'c',\n  'ⓓ' => 'd',\n  'ⓔ' => 'e',\n  'ⓕ' => 'f',\n  'ⓖ' => 'g',\n  'ⓗ' => 'h',\n  'ⓘ' => 'i',\n  'ⓙ' => 'j',\n  'ⓚ' => 'k',\n  'ⓛ' => 'l',\n  'ⓜ' => 'm',\n  'ⓝ' => 'n',\n  'ⓞ' => 'o',\n  'ⓟ' => 'p',\n  'ⓠ' => 'q',\n  'ⓡ' => 'r',\n  'ⓢ' => 's',\n  'ⓣ' => 't',\n  'ⓤ' => 'u',\n  'ⓥ' => 'v',\n  'ⓦ' => 'w',\n  'ⓧ' => 'x',\n  'ⓨ' => 'y',\n  'ⓩ' => 'z',\n  '⓪' => '0',\n  '⨌' => '∫∫∫∫',\n  '⩴' => '::=',\n  '⩵' => '==',\n  '⩶' => '===',\n  'ⱼ' => 'j',\n  'ⱽ' => 'V',\n  'ⵯ' => 'ⵡ',\n  '⺟' => '母',\n  '⻳' => '龟',\n  '⼀' => '一',\n  '⼁' => '丨',\n  '⼂' => '丶',\n  '⼃' => '丿',\n  '⼄' => '乙',\n  '⼅' => '亅',\n  '⼆' => '二',\n  '⼇' => '亠',\n  '⼈' => '人',\n  '⼉' => '儿',\n  '⼊' => '入',\n  '⼋' => '八',\n  '⼌' => '冂',\n  '⼍' => '冖',\n  '⼎' => '冫',\n  '⼏' => '几',\n  '⼐' => '凵',\n  '⼑' => '刀',\n  '⼒' => '力',\n  '⼓' => '勹',\n  '⼔' => '匕',\n  '⼕' => '匚',\n  '⼖' => '匸',\n  '⼗' => '十',\n  '⼘' => '卜',\n  '⼙' => '卩',\n  '⼚' => '厂',\n  '⼛' => '厶',\n  '⼜' => '又',\n  '⼝' => '口',\n  '⼞' => '囗',\n  '⼟' => '土',\n  '⼠' => '士',\n  '⼡' => '夂',\n  '⼢' => '夊',\n  '⼣' => '夕',\n  '⼤' => '大',\n  '⼥' => '女',\n  '⼦' => '子',\n  '⼧' => '宀',\n  '⼨' => '寸',\n  '⼩' => '小',\n  '⼪' => '尢',\n  '⼫' => '尸',\n  '⼬' => '屮',\n  '⼭' => '山',\n  '⼮' => '巛',\n  '⼯' => '工',\n  '⼰' => '己',\n  '⼱' => '巾',\n  '⼲' => '干',\n  '⼳' => '幺',\n  '⼴' => '广',\n  '⼵' => '廴',\n  '⼶' => '廾',\n  '⼷' => '弋',\n  '⼸' => '弓',\n  '⼹' => '彐',\n  '⼺' => '彡',\n  '⼻' => '彳',\n  '⼼' => '心',\n  '⼽' => '戈',\n  '⼾' => '戶',\n  '⼿' => '手',\n  '⽀' => '支',\n  '⽁' => '攴',\n  '⽂' => '文',\n  '⽃' => '斗',\n  '⽄' => '斤',\n  '⽅' => '方',\n  '⽆' => '无',\n  '⽇' => '日',\n  '⽈' => '曰',\n  '⽉' => '月',\n  '⽊' => '木',\n  '⽋' => '欠',\n  '⽌' => '止',\n  '⽍' => '歹',\n  '⽎' => '殳',\n  '⽏' => '毋',\n  '⽐' => '比',\n  '⽑' => '毛',\n  '⽒' => '氏',\n  '⽓' => '气',\n  '⽔' => '水',\n  '⽕' => '火',\n  '⽖' => '爪',\n  '⽗' => '父',\n  '⽘' => '爻',\n  '⽙' => '爿',\n  '⽚' => '片',\n  '⽛' => '牙',\n  '⽜' => '牛',\n  '⽝' => '犬',\n  '⽞' => '玄',\n  '⽟' => '玉',\n  '⽠' => '瓜',\n  '⽡' => '瓦',\n  '⽢' => '甘',\n  '⽣' => '生',\n  '⽤' => '用',\n  '⽥' => '田',\n  '⽦' => '疋',\n  '⽧' => '疒',\n  '⽨' => '癶',\n  '⽩' => '白',\n  '⽪' => '皮',\n  '⽫' => '皿',\n  '⽬' => '目',\n  '⽭' => '矛',\n  '⽮' => '矢',\n  '⽯' => '石',\n  '⽰' => '示',\n  '⽱' => '禸',\n  '⽲' => '禾',\n  '⽳' => '穴',\n  '⽴' => '立',\n  '⽵' => '竹',\n  '⽶' => '米',\n  '⽷' => '糸',\n  '⽸' => '缶',\n  '⽹' => '网',\n  '⽺' => '羊',\n  '⽻' => '羽',\n  '⽼' => '老',\n  '⽽' => '而',\n  '⽾' => '耒',\n  '⽿' => '耳',\n  '⾀' => '聿',\n  '⾁' => '肉',\n  '⾂' => '臣',\n  '⾃' => '自',\n  '⾄' => '至',\n  '⾅' => '臼',\n  '⾆' => '舌',\n  '⾇' => '舛',\n  '⾈' => '舟',\n  '⾉' => '艮',\n  '⾊' => '色',\n  '⾋' => '艸',\n  '⾌' => '虍',\n  '⾍' => '虫',\n  '⾎' => '血',\n  '⾏' => '行',\n  '⾐' => '衣',\n  '⾑' => '襾',\n  '⾒' => '見',\n  '⾓' => '角',\n  '⾔' => '言',\n  '⾕' => '谷',\n  '⾖' => '豆',\n  '⾗' => '豕',\n  '⾘' => '豸',\n  '⾙' => '貝',\n  '⾚' => '赤',\n  '⾛' => '走',\n  '⾜' => '足',\n  '⾝' => '身',\n  '⾞' => '車',\n  '⾟' => '辛',\n  '⾠' => '辰',\n  '⾡' => '辵',\n  '⾢' => '邑',\n  '⾣' => '酉',\n  '⾤' => '釆',\n  '⾥' => '里',\n  '⾦' => '金',\n  '⾧' => '長',\n  '⾨' => '門',\n  '⾩' => '阜',\n  '⾪' => '隶',\n  '⾫' => '隹',\n  '⾬' => '雨',\n  '⾭' => '靑',\n  '⾮' => '非',\n  '⾯' => '面',\n  '⾰' => '革',\n  '⾱' => '韋',\n  '⾲' => '韭',\n  '⾳' => '音',\n  '⾴' => '頁',\n  '⾵' => '風',\n  '⾶' => '飛',\n  '⾷' => '食',\n  '⾸' => '首',\n  '⾹' => '香',\n  '⾺' => '馬',\n  '⾻' => '骨',\n  '⾼' => '高',\n  '⾽' => '髟',\n  '⾾' => '鬥',\n  '⾿' => '鬯',\n  '⿀' => '鬲',\n  '⿁' => '鬼',\n  '⿂' => '魚',\n  '⿃' => '鳥',\n  '⿄' => '鹵',\n  '⿅' => '鹿',\n  '⿆' => '麥',\n  '⿇' => '麻',\n  '⿈' => '黃',\n  '⿉' => '黍',\n  '⿊' => '黑',\n  '⿋' => '黹',\n  '⿌' => '黽',\n  '⿍' => '鼎',\n  '⿎' => '鼓',\n  '⿏' => '鼠',\n  '⿐' => '鼻',\n  '⿑' => '齊',\n  '⿒' => '齒',\n  '⿓' => '龍',\n  '⿔' => '龜',\n  '⿕' => '龠',\n  '　' => ' ',\n  '〶' => '〒',\n  '〸' => '十',\n  '〹' => '卄',\n  '〺' => '卅',\n  '゛' => ' ゙',\n  '゜' => ' ゚',\n  'ゟ' => 'より',\n  'ヿ' => 'コト',\n  'ㄱ' => 'ᄀ',\n  'ㄲ' => 'ᄁ',\n  'ㄳ' => 'ᆪ',\n  'ㄴ' => 'ᄂ',\n  'ㄵ' => 'ᆬ',\n  'ㄶ' => 'ᆭ',\n  'ㄷ' => 'ᄃ',\n  'ㄸ' => 'ᄄ',\n  'ㄹ' => 'ᄅ',\n  'ㄺ' => 'ᆰ',\n  'ㄻ' => 'ᆱ',\n  'ㄼ' => 'ᆲ',\n  'ㄽ' => 'ᆳ',\n  'ㄾ' => 'ᆴ',\n  'ㄿ' => 'ᆵ',\n  'ㅀ' => 'ᄚ',\n  'ㅁ' => 'ᄆ',\n  'ㅂ' => 'ᄇ',\n  'ㅃ' => 'ᄈ',\n  'ㅄ' => 'ᄡ',\n  'ㅅ' => 'ᄉ',\n  'ㅆ' => 'ᄊ',\n  'ㅇ' => 'ᄋ',\n  'ㅈ' => 'ᄌ',\n  'ㅉ' => 'ᄍ',\n  'ㅊ' => 'ᄎ',\n  'ㅋ' => 'ᄏ',\n  'ㅌ' => 'ᄐ',\n  'ㅍ' => 'ᄑ',\n  'ㅎ' => 'ᄒ',\n  'ㅏ' => 'ᅡ',\n  'ㅐ' => 'ᅢ',\n  'ㅑ' => 'ᅣ',\n  'ㅒ' => 'ᅤ',\n  'ㅓ' => 'ᅥ',\n  'ㅔ' => 'ᅦ',\n  'ㅕ' => 'ᅧ',\n  'ㅖ' => 'ᅨ',\n  'ㅗ' => 'ᅩ',\n  'ㅘ' => 'ᅪ',\n  'ㅙ' => 'ᅫ',\n  'ㅚ' => 'ᅬ',\n  'ㅛ' => 'ᅭ',\n  'ㅜ' => 'ᅮ',\n  'ㅝ' => 'ᅯ',\n  'ㅞ' => 'ᅰ',\n  'ㅟ' => 'ᅱ',\n  'ㅠ' => 'ᅲ',\n  'ㅡ' => 'ᅳ',\n  'ㅢ' => 'ᅴ',\n  'ㅣ' => 'ᅵ',\n  'ㅤ' => 'ᅠ',\n  'ㅥ' => 'ᄔ',\n  'ㅦ' => 'ᄕ',\n  'ㅧ' => 'ᇇ',\n  'ㅨ' => 'ᇈ',\n  'ㅩ' => 'ᇌ',\n  'ㅪ' => 'ᇎ',\n  'ㅫ' => 'ᇓ',\n  'ㅬ' => 'ᇗ',\n  'ㅭ' => 'ᇙ',\n  'ㅮ' => 'ᄜ',\n  'ㅯ' => 'ᇝ',\n  'ㅰ' => 'ᇟ',\n  'ㅱ' => 'ᄝ',\n  'ㅲ' => 'ᄞ',\n  'ㅳ' => 'ᄠ',\n  'ㅴ' => 'ᄢ',\n  'ㅵ' => 'ᄣ',\n  'ㅶ' => 'ᄧ',\n  'ㅷ' => 'ᄩ',\n  'ㅸ' => 'ᄫ',\n  'ㅹ' => 'ᄬ',\n  'ㅺ' => 'ᄭ',\n  'ㅻ' => 'ᄮ',\n  'ㅼ' => 'ᄯ',\n  'ㅽ' => 'ᄲ',\n  'ㅾ' => 'ᄶ',\n  'ㅿ' => 'ᅀ',\n  'ㆀ' => 'ᅇ',\n  'ㆁ' => 'ᅌ',\n  'ㆂ' => 'ᇱ',\n  'ㆃ' => 'ᇲ',\n  'ㆄ' => 'ᅗ',\n  'ㆅ' => 'ᅘ',\n  'ㆆ' => 'ᅙ',\n  'ㆇ' => 'ᆄ',\n  'ㆈ' => 'ᆅ',\n  'ㆉ' => 'ᆈ',\n  'ㆊ' => 'ᆑ',\n  'ㆋ' => 'ᆒ',\n  'ㆌ' => 'ᆔ',\n  'ㆍ' => 'ᆞ',\n  'ㆎ' => 'ᆡ',\n  '㆒' => '一',\n  '㆓' => '二',\n  '㆔' => '三',\n  '㆕' => '四',\n  '㆖' => '上',\n  '㆗' => '中',\n  '㆘' => '下',\n  '㆙' => '甲',\n  '㆚' => '乙',\n  '㆛' => '丙',\n  '㆜' => '丁',\n  '㆝' => '天',\n  '㆞' => '地',\n  '㆟' => '人',\n  '㈀' => '(ᄀ)',\n  '㈁' => '(ᄂ)',\n  '㈂' => '(ᄃ)',\n  '㈃' => '(ᄅ)',\n  '㈄' => '(ᄆ)',\n  '㈅' => '(ᄇ)',\n  '㈆' => '(ᄉ)',\n  '㈇' => '(ᄋ)',\n  '㈈' => '(ᄌ)',\n  '㈉' => '(ᄎ)',\n  '㈊' => '(ᄏ)',\n  '㈋' => '(ᄐ)',\n  '㈌' => '(ᄑ)',\n  '㈍' => '(ᄒ)',\n  '㈎' => '(가)',\n  '㈏' => '(나)',\n  '㈐' => '(다)',\n  '㈑' => '(라)',\n  '㈒' => '(마)',\n  '㈓' => '(바)',\n  '㈔' => '(사)',\n  '㈕' => '(아)',\n  '㈖' => '(자)',\n  '㈗' => '(차)',\n  '㈘' => '(카)',\n  '㈙' => '(타)',\n  '㈚' => '(파)',\n  '㈛' => '(하)',\n  '㈜' => '(주)',\n  '㈝' => '(오전)',\n  '㈞' => '(오후)',\n  '㈠' => '(一)',\n  '㈡' => '(二)',\n  '㈢' => '(三)',\n  '㈣' => '(四)',\n  '㈤' => '(五)',\n  '㈥' => '(六)',\n  '㈦' => '(七)',\n  '㈧' => '(八)',\n  '㈨' => '(九)',\n  '㈩' => '(十)',\n  '㈪' => '(月)',\n  '㈫' => '(火)',\n  '㈬' => '(水)',\n  '㈭' => '(木)',\n  '㈮' => '(金)',\n  '㈯' => '(土)',\n  '㈰' => '(日)',\n  '㈱' => '(株)',\n  '㈲' => '(有)',\n  '㈳' => '(社)',\n  '㈴' => '(名)',\n  '㈵' => '(特)',\n  '㈶' => '(財)',\n  '㈷' => '(祝)',\n  '㈸' => '(労)',\n  '㈹' => '(代)',\n  '㈺' => '(呼)',\n  '㈻' => '(学)',\n  '㈼' => '(監)',\n  '㈽' => '(企)',\n  '㈾' => '(資)',\n  '㈿' => '(協)',\n  '㉀' => '(祭)',\n  '㉁' => '(休)',\n  '㉂' => '(自)',\n  '㉃' => '(至)',\n  '㉄' => '問',\n  '㉅' => '幼',\n  '㉆' => '文',\n  '㉇' => '箏',\n  '㉐' => 'PTE',\n  '㉑' => '21',\n  '㉒' => '22',\n  '㉓' => '23',\n  '㉔' => '24',\n  '㉕' => '25',\n  '㉖' => '26',\n  '㉗' => '27',\n  '㉘' => '28',\n  '㉙' => '29',\n  '㉚' => '30',\n  '㉛' => '31',\n  '㉜' => '32',\n  '㉝' => '33',\n  '㉞' => '34',\n  '㉟' => '35',\n  '㉠' => 'ᄀ',\n  '㉡' => 'ᄂ',\n  '㉢' => 'ᄃ',\n  '㉣' => 'ᄅ',\n  '㉤' => 'ᄆ',\n  '㉥' => 'ᄇ',\n  '㉦' => 'ᄉ',\n  '㉧' => 'ᄋ',\n  '㉨' => 'ᄌ',\n  '㉩' => 'ᄎ',\n  '㉪' => 'ᄏ',\n  '㉫' => 'ᄐ',\n  '㉬' => 'ᄑ',\n  '㉭' => 'ᄒ',\n  '㉮' => '가',\n  '㉯' => '나',\n  '㉰' => '다',\n  '㉱' => '라',\n  '㉲' => '마',\n  '㉳' => '바',\n  '㉴' => '사',\n  '㉵' => '아',\n  '㉶' => '자',\n  '㉷' => '차',\n  '㉸' => '카',\n  '㉹' => '타',\n  '㉺' => '파',\n  '㉻' => '하',\n  '㉼' => '참고',\n  '㉽' => '주의',\n  '㉾' => '우',\n  '㊀' => '一',\n  '㊁' => '二',\n  '㊂' => '三',\n  '㊃' => '四',\n  '㊄' => '五',\n  '㊅' => '六',\n  '㊆' => '七',\n  '㊇' => '八',\n  '㊈' => '九',\n  '㊉' => '十',\n  '㊊' => '月',\n  '㊋' => '火',\n  '㊌' => '水',\n  '㊍' => '木',\n  '㊎' => '金',\n  '㊏' => '土',\n  '㊐' => '日',\n  '㊑' => '株',\n  '㊒' => '有',\n  '㊓' => '社',\n  '㊔' => '名',\n  '㊕' => '特',\n  '㊖' => '財',\n  '㊗' => '祝',\n  '㊘' => '労',\n  '㊙' => '秘',\n  '㊚' => '男',\n  '㊛' => '女',\n  '㊜' => '適',\n  '㊝' => '優',\n  '㊞' => '印',\n  '㊟' => '注',\n  '㊠' => '項',\n  '㊡' => '休',\n  '㊢' => '写',\n  '㊣' => '正',\n  '㊤' => '上',\n  '㊥' => '中',\n  '㊦' => '下',\n  '㊧' => '左',\n  '㊨' => '右',\n  '㊩' => '医',\n  '㊪' => '宗',\n  '㊫' => '学',\n  '㊬' => '監',\n  '㊭' => '企',\n  '㊮' => '資',\n  '㊯' => '協',\n  '㊰' => '夜',\n  '㊱' => '36',\n  '㊲' => '37',\n  '㊳' => '38',\n  '㊴' => '39',\n  '㊵' => '40',\n  '㊶' => '41',\n  '㊷' => '42',\n  '㊸' => '43',\n  '㊹' => '44',\n  '㊺' => '45',\n  '㊻' => '46',\n  '㊼' => '47',\n  '㊽' => '48',\n  '㊾' => '49',\n  '㊿' => '50',\n  '㋀' => '1月',\n  '㋁' => '2月',\n  '㋂' => '3月',\n  '㋃' => '4月',\n  '㋄' => '5月',\n  '㋅' => '6月',\n  '㋆' => '7月',\n  '㋇' => '8月',\n  '㋈' => '9月',\n  '㋉' => '10月',\n  '㋊' => '11月',\n  '㋋' => '12月',\n  '㋌' => 'Hg',\n  '㋍' => 'erg',\n  '㋎' => 'eV',\n  '㋏' => 'LTD',\n  '㋐' => 'ア',\n  '㋑' => 'イ',\n  '㋒' => 'ウ',\n  '㋓' => 'エ',\n  '㋔' => 'オ',\n  '㋕' => 'カ',\n  '㋖' => 'キ',\n  '㋗' => 'ク',\n  '㋘' => 'ケ',\n  '㋙' => 'コ',\n  '㋚' => 'サ',\n  '㋛' => 'シ',\n  '㋜' => 'ス',\n  '㋝' => 'セ',\n  '㋞' => 'ソ',\n  '㋟' => 'タ',\n  '㋠' => 'チ',\n  '㋡' => 'ツ',\n  '㋢' => 'テ',\n  '㋣' => 'ト',\n  '㋤' => 'ナ',\n  '㋥' => 'ニ',\n  '㋦' => 'ヌ',\n  '㋧' => 'ネ',\n  '㋨' => 'ノ',\n  '㋩' => 'ハ',\n  '㋪' => 'ヒ',\n  '㋫' => 'フ',\n  '㋬' => 'ヘ',\n  '㋭' => 'ホ',\n  '㋮' => 'マ',\n  '㋯' => 'ミ',\n  '㋰' => 'ム',\n  '㋱' => 'メ',\n  '㋲' => 'モ',\n  '㋳' => 'ヤ',\n  '㋴' => 'ユ',\n  '㋵' => 'ヨ',\n  '㋶' => 'ラ',\n  '㋷' => 'リ',\n  '㋸' => 'ル',\n  '㋹' => 'レ',\n  '㋺' => 'ロ',\n  '㋻' => 'ワ',\n  '㋼' => 'ヰ',\n  '㋽' => 'ヱ',\n  '㋾' => 'ヲ',\n  '㋿' => '令和',\n  '㌀' => 'アパート',\n  '㌁' => 'アルファ',\n  '㌂' => 'アンペア',\n  '㌃' => 'アール',\n  '㌄' => 'イニング',\n  '㌅' => 'インチ',\n  '㌆' => 'ウォン',\n  '㌇' => 'エスクード',\n  '㌈' => 'エーカー',\n  '㌉' => 'オンス',\n  '㌊' => 'オーム',\n  '㌋' => 'カイリ',\n  '㌌' => 'カラット',\n  '㌍' => 'カロリー',\n  '㌎' => 'ガロン',\n  '㌏' => 'ガンマ',\n  '㌐' => 'ギガ',\n  '㌑' => 'ギニー',\n  '㌒' => 'キュリー',\n  '㌓' => 'ギルダー',\n  '㌔' => 'キロ',\n  '㌕' => 'キログラム',\n  '㌖' => 'キロメートル',\n  '㌗' => 'キロワット',\n  '㌘' => 'グラム',\n  '㌙' => 'グラムトン',\n  '㌚' => 'クルゼイロ',\n  '㌛' => 'クローネ',\n  '㌜' => 'ケース',\n  '㌝' => 'コルナ',\n  '㌞' => 'コーポ',\n  '㌟' => 'サイクル',\n  '㌠' => 'サンチーム',\n  '㌡' => 'シリング',\n  '㌢' => 'センチ',\n  '㌣' => 'セント',\n  '㌤' => 'ダース',\n  '㌥' => 'デシ',\n  '㌦' => 'ドル',\n  '㌧' => 'トン',\n  '㌨' => 'ナノ',\n  '㌩' => 'ノット',\n  '㌪' => 'ハイツ',\n  '㌫' => 'パーセント',\n  '㌬' => 'パーツ',\n  '㌭' => 'バーレル',\n  '㌮' => 'ピアストル',\n  '㌯' => 'ピクル',\n  '㌰' => 'ピコ',\n  '㌱' => 'ビル',\n  '㌲' => 'ファラッド',\n  '㌳' => 'フィート',\n  '㌴' => 'ブッシェル',\n  '㌵' => 'フラン',\n  '㌶' => 'ヘクタール',\n  '㌷' => 'ペソ',\n  '㌸' => 'ペニヒ',\n  '㌹' => 'ヘルツ',\n  '㌺' => 'ペンス',\n  '㌻' => 'ページ',\n  '㌼' => 'ベータ',\n  '㌽' => 'ポイント',\n  '㌾' => 'ボルト',\n  '㌿' => 'ホン',\n  '㍀' => 'ポンド',\n  '㍁' => 'ホール',\n  '㍂' => 'ホーン',\n  '㍃' => 'マイクロ',\n  '㍄' => 'マイル',\n  '㍅' => 'マッハ',\n  '㍆' => 'マルク',\n  '㍇' => 'マンション',\n  '㍈' => 'ミクロン',\n  '㍉' => 'ミリ',\n  '㍊' => 'ミリバール',\n  '㍋' => 'メガ',\n  '㍌' => 'メガトン',\n  '㍍' => 'メートル',\n  '㍎' => 'ヤード',\n  '㍏' => 'ヤール',\n  '㍐' => 'ユアン',\n  '㍑' => 'リットル',\n  '㍒' => 'リラ',\n  '㍓' => 'ルピー',\n  '㍔' => 'ルーブル',\n  '㍕' => 'レム',\n  '㍖' => 'レントゲン',\n  '㍗' => 'ワット',\n  '㍘' => '0点',\n  '㍙' => '1点',\n  '㍚' => '2点',\n  '㍛' => '3点',\n  '㍜' => '4点',\n  '㍝' => '5点',\n  '㍞' => '6点',\n  '㍟' => '7点',\n  '㍠' => '8点',\n  '㍡' => '9点',\n  '㍢' => '10点',\n  '㍣' => '11点',\n  '㍤' => '12点',\n  '㍥' => '13点',\n  '㍦' => '14点',\n  '㍧' => '15点',\n  '㍨' => '16点',\n  '㍩' => '17点',\n  '㍪' => '18点',\n  '㍫' => '19点',\n  '㍬' => '20点',\n  '㍭' => '21点',\n  '㍮' => '22点',\n  '㍯' => '23点',\n  '㍰' => '24点',\n  '㍱' => 'hPa',\n  '㍲' => 'da',\n  '㍳' => 'AU',\n  '㍴' => 'bar',\n  '㍵' => 'oV',\n  '㍶' => 'pc',\n  '㍷' => 'dm',\n  '㍸' => 'dm2',\n  '㍹' => 'dm3',\n  '㍺' => 'IU',\n  '㍻' => '平成',\n  '㍼' => '昭和',\n  '㍽' => '大正',\n  '㍾' => '明治',\n  '㍿' => '株式会社',\n  '㎀' => 'pA',\n  '㎁' => 'nA',\n  '㎂' => 'μA',\n  '㎃' => 'mA',\n  '㎄' => 'kA',\n  '㎅' => 'KB',\n  '㎆' => 'MB',\n  '㎇' => 'GB',\n  '㎈' => 'cal',\n  '㎉' => 'kcal',\n  '㎊' => 'pF',\n  '㎋' => 'nF',\n  '㎌' => 'μF',\n  '㎍' => 'μg',\n  '㎎' => 'mg',\n  '㎏' => 'kg',\n  '㎐' => 'Hz',\n  '㎑' => 'kHz',\n  '㎒' => 'MHz',\n  '㎓' => 'GHz',\n  '㎔' => 'THz',\n  '㎕' => 'μl',\n  '㎖' => 'ml',\n  '㎗' => 'dl',\n  '㎘' => 'kl',\n  '㎙' => 'fm',\n  '㎚' => 'nm',\n  '㎛' => 'μm',\n  '㎜' => 'mm',\n  '㎝' => 'cm',\n  '㎞' => 'km',\n  '㎟' => 'mm2',\n  '㎠' => 'cm2',\n  '㎡' => 'm2',\n  '㎢' => 'km2',\n  '㎣' => 'mm3',\n  '㎤' => 'cm3',\n  '㎥' => 'm3',\n  '㎦' => 'km3',\n  '㎧' => 'm∕s',\n  '㎨' => 'm∕s2',\n  '㎩' => 'Pa',\n  '㎪' => 'kPa',\n  '㎫' => 'MPa',\n  '㎬' => 'GPa',\n  '㎭' => 'rad',\n  '㎮' => 'rad∕s',\n  '㎯' => 'rad∕s2',\n  '㎰' => 'ps',\n  '㎱' => 'ns',\n  '㎲' => 'μs',\n  '㎳' => 'ms',\n  '㎴' => 'pV',\n  '㎵' => 'nV',\n  '㎶' => 'μV',\n  '㎷' => 'mV',\n  '㎸' => 'kV',\n  '㎹' => 'MV',\n  '㎺' => 'pW',\n  '㎻' => 'nW',\n  '㎼' => 'μW',\n  '㎽' => 'mW',\n  '㎾' => 'kW',\n  '㎿' => 'MW',\n  '㏀' => 'kΩ',\n  '㏁' => 'MΩ',\n  '㏂' => 'a.m.',\n  '㏃' => 'Bq',\n  '㏄' => 'cc',\n  '㏅' => 'cd',\n  '㏆' => 'C∕kg',\n  '㏇' => 'Co.',\n  '㏈' => 'dB',\n  '㏉' => 'Gy',\n  '㏊' => 'ha',\n  '㏋' => 'HP',\n  '㏌' => 'in',\n  '㏍' => 'KK',\n  '㏎' => 'KM',\n  '㏏' => 'kt',\n  '㏐' => 'lm',\n  '㏑' => 'ln',\n  '㏒' => 'log',\n  '㏓' => 'lx',\n  '㏔' => 'mb',\n  '㏕' => 'mil',\n  '㏖' => 'mol',\n  '㏗' => 'PH',\n  '㏘' => 'p.m.',\n  '㏙' => 'PPM',\n  '㏚' => 'PR',\n  '㏛' => 'sr',\n  '㏜' => 'Sv',\n  '㏝' => 'Wb',\n  '㏞' => 'V∕m',\n  '㏟' => 'A∕m',\n  '㏠' => '1日',\n  '㏡' => '2日',\n  '㏢' => '3日',\n  '㏣' => '4日',\n  '㏤' => '5日',\n  '㏥' => '6日',\n  '㏦' => '7日',\n  '㏧' => '8日',\n  '㏨' => '9日',\n  '㏩' => '10日',\n  '㏪' => '11日',\n  '㏫' => '12日',\n  '㏬' => '13日',\n  '㏭' => '14日',\n  '㏮' => '15日',\n  '㏯' => '16日',\n  '㏰' => '17日',\n  '㏱' => '18日',\n  '㏲' => '19日',\n  '㏳' => '20日',\n  '㏴' => '21日',\n  '㏵' => '22日',\n  '㏶' => '23日',\n  '㏷' => '24日',\n  '㏸' => '25日',\n  '㏹' => '26日',\n  '㏺' => '27日',\n  '㏻' => '28日',\n  '㏼' => '29日',\n  '㏽' => '30日',\n  '㏾' => '31日',\n  '㏿' => 'gal',\n  'ꚜ' => 'ъ',\n  'ꚝ' => 'ь',\n  'ꝰ' => 'ꝯ',\n  'ꟸ' => 'Ħ',\n  'ꟹ' => 'œ',\n  'ꭜ' => 'ꜧ',\n  'ꭝ' => 'ꬷ',\n  'ꭞ' => 'ɫ',\n  'ꭟ' => 'ꭒ',\n  'ꭩ' => 'ʍ',\n  'ﬀ' => 'ff',\n  'ﬁ' => 'fi',\n  'ﬂ' => 'fl',\n  'ﬃ' => 'ffi',\n  'ﬄ' => 'ffl',\n  'ﬅ' => 'st',\n  'ﬆ' => 'st',\n  'ﬓ' => 'մն',\n  'ﬔ' => 'մե',\n  'ﬕ' => 'մի',\n  'ﬖ' => 'վն',\n  'ﬗ' => 'մխ',\n  'ﬠ' => 'ע',\n  'ﬡ' => 'א',\n  'ﬢ' => 'ד',\n  'ﬣ' => 'ה',\n  'ﬤ' => 'כ',\n  'ﬥ' => 'ל',\n  'ﬦ' => 'ם',\n  'ﬧ' => 'ר',\n  'ﬨ' => 'ת',\n  '﬩' => '+',\n  'ﭏ' => 'אל',\n  'ﭐ' => 'ٱ',\n  'ﭑ' => 'ٱ',\n  'ﭒ' => 'ٻ',\n  'ﭓ' => 'ٻ',\n  'ﭔ' => 'ٻ',\n  'ﭕ' => 'ٻ',\n  'ﭖ' => 'پ',\n  'ﭗ' => 'پ',\n  'ﭘ' => 'پ',\n  'ﭙ' => 'پ',\n  'ﭚ' => 'ڀ',\n  'ﭛ' => 'ڀ',\n  'ﭜ' => 'ڀ',\n  'ﭝ' => 'ڀ',\n  'ﭞ' => 'ٺ',\n  'ﭟ' => 'ٺ',\n  'ﭠ' => 'ٺ',\n  'ﭡ' => 'ٺ',\n  'ﭢ' => 'ٿ',\n  'ﭣ' => 'ٿ',\n  'ﭤ' => 'ٿ',\n  'ﭥ' => 'ٿ',\n  'ﭦ' => 'ٹ',\n  'ﭧ' => 'ٹ',\n  'ﭨ' => 'ٹ',\n  'ﭩ' => 'ٹ',\n  'ﭪ' => 'ڤ',\n  'ﭫ' => 'ڤ',\n  'ﭬ' => 'ڤ',\n  'ﭭ' => 'ڤ',\n  'ﭮ' => 'ڦ',\n  'ﭯ' => 'ڦ',\n  'ﭰ' => 'ڦ',\n  'ﭱ' => 'ڦ',\n  'ﭲ' => 'ڄ',\n  'ﭳ' => 'ڄ',\n  'ﭴ' => 'ڄ',\n  'ﭵ' => 'ڄ',\n  'ﭶ' => 'ڃ',\n  'ﭷ' => 'ڃ',\n  'ﭸ' => 'ڃ',\n  'ﭹ' => 'ڃ',\n  'ﭺ' => 'چ',\n  'ﭻ' => 'چ',\n  'ﭼ' => 'چ',\n  'ﭽ' => 'چ',\n  'ﭾ' => 'ڇ',\n  'ﭿ' => 'ڇ',\n  'ﮀ' => 'ڇ',\n  'ﮁ' => 'ڇ',\n  'ﮂ' => 'ڍ',\n  'ﮃ' => 'ڍ',\n  'ﮄ' => 'ڌ',\n  'ﮅ' => 'ڌ',\n  'ﮆ' => 'ڎ',\n  'ﮇ' => 'ڎ',\n  'ﮈ' => 'ڈ',\n  'ﮉ' => 'ڈ',\n  'ﮊ' => 'ژ',\n  'ﮋ' => 'ژ',\n  'ﮌ' => 'ڑ',\n  'ﮍ' => 'ڑ',\n  'ﮎ' => 'ک',\n  'ﮏ' => 'ک',\n  'ﮐ' => 'ک',\n  'ﮑ' => 'ک',\n  'ﮒ' => 'گ',\n  'ﮓ' => 'گ',\n  'ﮔ' => 'گ',\n  'ﮕ' => 'گ',\n  'ﮖ' => 'ڳ',\n  'ﮗ' => 'ڳ',\n  'ﮘ' => 'ڳ',\n  'ﮙ' => 'ڳ',\n  'ﮚ' => 'ڱ',\n  'ﮛ' => 'ڱ',\n  'ﮜ' => 'ڱ',\n  'ﮝ' => 'ڱ',\n  'ﮞ' => 'ں',\n  'ﮟ' => 'ں',\n  'ﮠ' => 'ڻ',\n  'ﮡ' => 'ڻ',\n  'ﮢ' => 'ڻ',\n  'ﮣ' => 'ڻ',\n  'ﮤ' => 'ۀ',\n  'ﮥ' => 'ۀ',\n  'ﮦ' => 'ہ',\n  'ﮧ' => 'ہ',\n  'ﮨ' => 'ہ',\n  'ﮩ' => 'ہ',\n  'ﮪ' => 'ھ',\n  'ﮫ' => 'ھ',\n  'ﮬ' => 'ھ',\n  'ﮭ' => 'ھ',\n  'ﮮ' => 'ے',\n  'ﮯ' => 'ے',\n  'ﮰ' => 'ۓ',\n  'ﮱ' => 'ۓ',\n  'ﯓ' => 'ڭ',\n  'ﯔ' => 'ڭ',\n  'ﯕ' => 'ڭ',\n  'ﯖ' => 'ڭ',\n  'ﯗ' => 'ۇ',\n  'ﯘ' => 'ۇ',\n  'ﯙ' => 'ۆ',\n  'ﯚ' => 'ۆ',\n  'ﯛ' => 'ۈ',\n  'ﯜ' => 'ۈ',\n  'ﯝ' => 'ۇٴ',\n  'ﯞ' => 'ۋ',\n  'ﯟ' => 'ۋ',\n  'ﯠ' => 'ۅ',\n  'ﯡ' => 'ۅ',\n  'ﯢ' => 'ۉ',\n  'ﯣ' => 'ۉ',\n  'ﯤ' => 'ې',\n  'ﯥ' => 'ې',\n  'ﯦ' => 'ې',\n  'ﯧ' => 'ې',\n  'ﯨ' => 'ى',\n  'ﯩ' => 'ى',\n  'ﯪ' => 'ئا',\n  'ﯫ' => 'ئا',\n  'ﯬ' => 'ئە',\n  'ﯭ' => 'ئە',\n  'ﯮ' => 'ئو',\n  'ﯯ' => 'ئو',\n  'ﯰ' => 'ئۇ',\n  'ﯱ' => 'ئۇ',\n  'ﯲ' => 'ئۆ',\n  'ﯳ' => 'ئۆ',\n  'ﯴ' => 'ئۈ',\n  'ﯵ' => 'ئۈ',\n  'ﯶ' => 'ئې',\n  'ﯷ' => 'ئې',\n  'ﯸ' => 'ئې',\n  'ﯹ' => 'ئى',\n  'ﯺ' => 'ئى',\n  'ﯻ' => 'ئى',\n  'ﯼ' => 'ی',\n  'ﯽ' => 'ی',\n  'ﯾ' => 'ی',\n  'ﯿ' => 'ی',\n  'ﰀ' => 'ئج',\n  'ﰁ' => 'ئح',\n  'ﰂ' => 'ئم',\n  'ﰃ' => 'ئى',\n  'ﰄ' => 'ئي',\n  'ﰅ' => 'بج',\n  'ﰆ' => 'بح',\n  'ﰇ' => 'بخ',\n  'ﰈ' => 'بم',\n  'ﰉ' => 'بى',\n  'ﰊ' => 'بي',\n  'ﰋ' => 'تج',\n  'ﰌ' => 'تح',\n  'ﰍ' => 'تخ',\n  'ﰎ' => 'تم',\n  'ﰏ' => 'تى',\n  'ﰐ' => 'تي',\n  'ﰑ' => 'ثج',\n  'ﰒ' => 'ثم',\n  'ﰓ' => 'ثى',\n  'ﰔ' => 'ثي',\n  'ﰕ' => 'جح',\n  'ﰖ' => 'جم',\n  'ﰗ' => 'حج',\n  'ﰘ' => 'حم',\n  'ﰙ' => 'خج',\n  'ﰚ' => 'خح',\n  'ﰛ' => 'خم',\n  'ﰜ' => 'سج',\n  'ﰝ' => 'سح',\n  'ﰞ' => 'سخ',\n  'ﰟ' => 'سم',\n  'ﰠ' => 'صح',\n  'ﰡ' => 'صم',\n  'ﰢ' => 'ضج',\n  'ﰣ' => 'ضح',\n  'ﰤ' => 'ضخ',\n  'ﰥ' => 'ضم',\n  'ﰦ' => 'طح',\n  'ﰧ' => 'طم',\n  'ﰨ' => 'ظم',\n  'ﰩ' => 'عج',\n  'ﰪ' => 'عم',\n  'ﰫ' => 'غج',\n  'ﰬ' => 'غم',\n  'ﰭ' => 'فج',\n  'ﰮ' => 'فح',\n  'ﰯ' => 'فخ',\n  'ﰰ' => 'فم',\n  'ﰱ' => 'فى',\n  'ﰲ' => 'في',\n  'ﰳ' => 'قح',\n  'ﰴ' => 'قم',\n  'ﰵ' => 'قى',\n  'ﰶ' => 'قي',\n  'ﰷ' => 'كا',\n  'ﰸ' => 'كج',\n  'ﰹ' => 'كح',\n  'ﰺ' => 'كخ',\n  'ﰻ' => 'كل',\n  'ﰼ' => 'كم',\n  'ﰽ' => 'كى',\n  'ﰾ' => 'كي',\n  'ﰿ' => 'لج',\n  'ﱀ' => 'لح',\n  'ﱁ' => 'لخ',\n  'ﱂ' => 'لم',\n  'ﱃ' => 'لى',\n  'ﱄ' => 'لي',\n  'ﱅ' => 'مج',\n  'ﱆ' => 'مح',\n  'ﱇ' => 'مخ',\n  'ﱈ' => 'مم',\n  'ﱉ' => 'مى',\n  'ﱊ' => 'مي',\n  'ﱋ' => 'نج',\n  'ﱌ' => 'نح',\n  'ﱍ' => 'نخ',\n  'ﱎ' => 'نم',\n  'ﱏ' => 'نى',\n  'ﱐ' => 'ني',\n  'ﱑ' => 'هج',\n  'ﱒ' => 'هم',\n  'ﱓ' => 'هى',\n  'ﱔ' => 'هي',\n  'ﱕ' => 'يج',\n  'ﱖ' => 'يح',\n  'ﱗ' => 'يخ',\n  'ﱘ' => 'يم',\n  'ﱙ' => 'يى',\n  'ﱚ' => 'يي',\n  'ﱛ' => 'ذٰ',\n  'ﱜ' => 'رٰ',\n  'ﱝ' => 'ىٰ',\n  'ﱞ' => ' ٌّ',\n  'ﱟ' => ' ٍّ',\n  'ﱠ' => ' َّ',\n  'ﱡ' => ' ُّ',\n  'ﱢ' => ' ِّ',\n  'ﱣ' => ' ّٰ',\n  'ﱤ' => 'ئر',\n  'ﱥ' => 'ئز',\n  'ﱦ' => 'ئم',\n  'ﱧ' => 'ئن',\n  'ﱨ' => 'ئى',\n  'ﱩ' => 'ئي',\n  'ﱪ' => 'بر',\n  'ﱫ' => 'بز',\n  'ﱬ' => 'بم',\n  'ﱭ' => 'بن',\n  'ﱮ' => 'بى',\n  'ﱯ' => 'بي',\n  'ﱰ' => 'تر',\n  'ﱱ' => 'تز',\n  'ﱲ' => 'تم',\n  'ﱳ' => 'تن',\n  'ﱴ' => 'تى',\n  'ﱵ' => 'تي',\n  'ﱶ' => 'ثر',\n  'ﱷ' => 'ثز',\n  'ﱸ' => 'ثم',\n  'ﱹ' => 'ثن',\n  'ﱺ' => 'ثى',\n  'ﱻ' => 'ثي',\n  'ﱼ' => 'فى',\n  'ﱽ' => 'في',\n  'ﱾ' => 'قى',\n  'ﱿ' => 'قي',\n  'ﲀ' => 'كا',\n  'ﲁ' => 'كل',\n  'ﲂ' => 'كم',\n  'ﲃ' => 'كى',\n  'ﲄ' => 'كي',\n  'ﲅ' => 'لم',\n  'ﲆ' => 'لى',\n  'ﲇ' => 'لي',\n  'ﲈ' => 'ما',\n  'ﲉ' => 'مم',\n  'ﲊ' => 'نر',\n  'ﲋ' => 'نز',\n  'ﲌ' => 'نم',\n  'ﲍ' => 'نن',\n  'ﲎ' => 'نى',\n  'ﲏ' => 'ني',\n  'ﲐ' => 'ىٰ',\n  'ﲑ' => 'ير',\n  'ﲒ' => 'يز',\n  'ﲓ' => 'يم',\n  'ﲔ' => 'ين',\n  'ﲕ' => 'يى',\n  'ﲖ' => 'يي',\n  'ﲗ' => 'ئج',\n  'ﲘ' => 'ئح',\n  'ﲙ' => 'ئخ',\n  'ﲚ' => 'ئم',\n  'ﲛ' => 'ئه',\n  'ﲜ' => 'بج',\n  'ﲝ' => 'بح',\n  'ﲞ' => 'بخ',\n  'ﲟ' => 'بم',\n  'ﲠ' => 'به',\n  'ﲡ' => 'تج',\n  'ﲢ' => 'تح',\n  'ﲣ' => 'تخ',\n  'ﲤ' => 'تم',\n  'ﲥ' => 'ته',\n  'ﲦ' => 'ثم',\n  'ﲧ' => 'جح',\n  'ﲨ' => 'جم',\n  'ﲩ' => 'حج',\n  'ﲪ' => 'حم',\n  'ﲫ' => 'خج',\n  'ﲬ' => 'خم',\n  'ﲭ' => 'سج',\n  'ﲮ' => 'سح',\n  'ﲯ' => 'سخ',\n  'ﲰ' => 'سم',\n  'ﲱ' => 'صح',\n  'ﲲ' => 'صخ',\n  'ﲳ' => 'صم',\n  'ﲴ' => 'ضج',\n  'ﲵ' => 'ضح',\n  'ﲶ' => 'ضخ',\n  'ﲷ' => 'ضم',\n  'ﲸ' => 'طح',\n  'ﲹ' => 'ظم',\n  'ﲺ' => 'عج',\n  'ﲻ' => 'عم',\n  'ﲼ' => 'غج',\n  'ﲽ' => 'غم',\n  'ﲾ' => 'فج',\n  'ﲿ' => 'فح',\n  'ﳀ' => 'فخ',\n  'ﳁ' => 'فم',\n  'ﳂ' => 'قح',\n  'ﳃ' => 'قم',\n  'ﳄ' => 'كج',\n  'ﳅ' => 'كح',\n  'ﳆ' => 'كخ',\n  'ﳇ' => 'كل',\n  'ﳈ' => 'كم',\n  'ﳉ' => 'لج',\n  'ﳊ' => 'لح',\n  'ﳋ' => 'لخ',\n  'ﳌ' => 'لم',\n  'ﳍ' => 'له',\n  'ﳎ' => 'مج',\n  'ﳏ' => 'مح',\n  'ﳐ' => 'مخ',\n  'ﳑ' => 'مم',\n  'ﳒ' => 'نج',\n  'ﳓ' => 'نح',\n  'ﳔ' => 'نخ',\n  'ﳕ' => 'نم',\n  'ﳖ' => 'نه',\n  'ﳗ' => 'هج',\n  'ﳘ' => 'هم',\n  'ﳙ' => 'هٰ',\n  'ﳚ' => 'يج',\n  'ﳛ' => 'يح',\n  'ﳜ' => 'يخ',\n  'ﳝ' => 'يم',\n  'ﳞ' => 'يه',\n  'ﳟ' => 'ئم',\n  'ﳠ' => 'ئه',\n  'ﳡ' => 'بم',\n  'ﳢ' => 'به',\n  'ﳣ' => 'تم',\n  'ﳤ' => 'ته',\n  'ﳥ' => 'ثم',\n  'ﳦ' => 'ثه',\n  'ﳧ' => 'سم',\n  'ﳨ' => 'سه',\n  'ﳩ' => 'شم',\n  'ﳪ' => 'شه',\n  'ﳫ' => 'كل',\n  'ﳬ' => 'كم',\n  'ﳭ' => 'لم',\n  'ﳮ' => 'نم',\n  'ﳯ' => 'نه',\n  'ﳰ' => 'يم',\n  'ﳱ' => 'يه',\n  'ﳲ' => 'ـَّ',\n  'ﳳ' => 'ـُّ',\n  'ﳴ' => 'ـِّ',\n  'ﳵ' => 'طى',\n  'ﳶ' => 'طي',\n  'ﳷ' => 'عى',\n  'ﳸ' => 'عي',\n  'ﳹ' => 'غى',\n  'ﳺ' => 'غي',\n  'ﳻ' => 'سى',\n  'ﳼ' => 'سي',\n  'ﳽ' => 'شى',\n  'ﳾ' => 'شي',\n  'ﳿ' => 'حى',\n  'ﴀ' => 'حي',\n  'ﴁ' => 'جى',\n  'ﴂ' => 'جي',\n  'ﴃ' => 'خى',\n  'ﴄ' => 'خي',\n  'ﴅ' => 'صى',\n  'ﴆ' => 'صي',\n  'ﴇ' => 'ضى',\n  'ﴈ' => 'ضي',\n  'ﴉ' => 'شج',\n  'ﴊ' => 'شح',\n  'ﴋ' => 'شخ',\n  'ﴌ' => 'شم',\n  'ﴍ' => 'شر',\n  'ﴎ' => 'سر',\n  'ﴏ' => 'صر',\n  'ﴐ' => 'ضر',\n  'ﴑ' => 'طى',\n  'ﴒ' => 'طي',\n  'ﴓ' => 'عى',\n  'ﴔ' => 'عي',\n  'ﴕ' => 'غى',\n  'ﴖ' => 'غي',\n  'ﴗ' => 'سى',\n  'ﴘ' => 'سي',\n  'ﴙ' => 'شى',\n  'ﴚ' => 'شي',\n  'ﴛ' => 'حى',\n  'ﴜ' => 'حي',\n  'ﴝ' => 'جى',\n  'ﴞ' => 'جي',\n  'ﴟ' => 'خى',\n  'ﴠ' => 'خي',\n  'ﴡ' => 'صى',\n  'ﴢ' => 'صي',\n  'ﴣ' => 'ضى',\n  'ﴤ' => 'ضي',\n  'ﴥ' => 'شج',\n  'ﴦ' => 'شح',\n  'ﴧ' => 'شخ',\n  'ﴨ' => 'شم',\n  'ﴩ' => 'شر',\n  'ﴪ' => 'سر',\n  'ﴫ' => 'صر',\n  'ﴬ' => 'ضر',\n  'ﴭ' => 'شج',\n  'ﴮ' => 'شح',\n  'ﴯ' => 'شخ',\n  'ﴰ' => 'شم',\n  'ﴱ' => 'سه',\n  'ﴲ' => 'شه',\n  'ﴳ' => 'طم',\n  'ﴴ' => 'سج',\n  'ﴵ' => 'سح',\n  'ﴶ' => 'سخ',\n  'ﴷ' => 'شج',\n  'ﴸ' => 'شح',\n  'ﴹ' => 'شخ',\n  'ﴺ' => 'طم',\n  'ﴻ' => 'ظم',\n  'ﴼ' => 'اً',\n  'ﴽ' => 'اً',\n  'ﵐ' => 'تجم',\n  'ﵑ' => 'تحج',\n  'ﵒ' => 'تحج',\n  'ﵓ' => 'تحم',\n  'ﵔ' => 'تخم',\n  'ﵕ' => 'تمج',\n  'ﵖ' => 'تمح',\n  'ﵗ' => 'تمخ',\n  'ﵘ' => 'جمح',\n  'ﵙ' => 'جمح',\n  'ﵚ' => 'حمي',\n  'ﵛ' => 'حمى',\n  'ﵜ' => 'سحج',\n  'ﵝ' => 'سجح',\n  'ﵞ' => 'سجى',\n  'ﵟ' => 'سمح',\n  'ﵠ' => 'سمح',\n  'ﵡ' => 'سمج',\n  'ﵢ' => 'سمم',\n  'ﵣ' => 'سمم',\n  'ﵤ' => 'صحح',\n  'ﵥ' => 'صحح',\n  'ﵦ' => 'صمم',\n  'ﵧ' => 'شحم',\n  'ﵨ' => 'شحم',\n  'ﵩ' => 'شجي',\n  'ﵪ' => 'شمخ',\n  'ﵫ' => 'شمخ',\n  'ﵬ' => 'شمم',\n  'ﵭ' => 'شمم',\n  'ﵮ' => 'ضحى',\n  'ﵯ' => 'ضخم',\n  'ﵰ' => 'ضخم',\n  'ﵱ' => 'طمح',\n  'ﵲ' => 'طمح',\n  'ﵳ' => 'طمم',\n  'ﵴ' => 'طمي',\n  'ﵵ' => 'عجم',\n  'ﵶ' => 'عمم',\n  'ﵷ' => 'عمم',\n  'ﵸ' => 'عمى',\n  'ﵹ' => 'غمم',\n  'ﵺ' => 'غمي',\n  'ﵻ' => 'غمى',\n  'ﵼ' => 'فخم',\n  'ﵽ' => 'فخم',\n  'ﵾ' => 'قمح',\n  'ﵿ' => 'قمم',\n  'ﶀ' => 'لحم',\n  'ﶁ' => 'لحي',\n  'ﶂ' => 'لحى',\n  'ﶃ' => 'لجج',\n  'ﶄ' => 'لجج',\n  'ﶅ' => 'لخم',\n  'ﶆ' => 'لخم',\n  'ﶇ' => 'لمح',\n  'ﶈ' => 'لمح',\n  'ﶉ' => 'محج',\n  'ﶊ' => 'محم',\n  'ﶋ' => 'محي',\n  'ﶌ' => 'مجح',\n  'ﶍ' => 'مجم',\n  'ﶎ' => 'مخج',\n  'ﶏ' => 'مخم',\n  'ﶒ' => 'مجخ',\n  'ﶓ' => 'همج',\n  'ﶔ' => 'همم',\n  'ﶕ' => 'نحم',\n  'ﶖ' => 'نحى',\n  'ﶗ' => 'نجم',\n  'ﶘ' => 'نجم',\n  'ﶙ' => 'نجى',\n  'ﶚ' => 'نمي',\n  'ﶛ' => 'نمى',\n  'ﶜ' => 'يمم',\n  'ﶝ' => 'يمم',\n  'ﶞ' => 'بخي',\n  'ﶟ' => 'تجي',\n  'ﶠ' => 'تجى',\n  'ﶡ' => 'تخي',\n  'ﶢ' => 'تخى',\n  'ﶣ' => 'تمي',\n  'ﶤ' => 'تمى',\n  'ﶥ' => 'جمي',\n  'ﶦ' => 'جحى',\n  'ﶧ' => 'جمى',\n  'ﶨ' => 'سخى',\n  'ﶩ' => 'صحي',\n  'ﶪ' => 'شحي',\n  'ﶫ' => 'ضحي',\n  'ﶬ' => 'لجي',\n  'ﶭ' => 'لمي',\n  'ﶮ' => 'يحي',\n  'ﶯ' => 'يجي',\n  'ﶰ' => 'يمي',\n  'ﶱ' => 'ممي',\n  'ﶲ' => 'قمي',\n  'ﶳ' => 'نحي',\n  'ﶴ' => 'قمح',\n  'ﶵ' => 'لحم',\n  'ﶶ' => 'عمي',\n  'ﶷ' => 'كمي',\n  'ﶸ' => 'نجح',\n  'ﶹ' => 'مخي',\n  'ﶺ' => 'لجم',\n  'ﶻ' => 'كمم',\n  'ﶼ' => 'لجم',\n  'ﶽ' => 'نجح',\n  'ﶾ' => 'جحي',\n  'ﶿ' => 'حجي',\n  'ﷀ' => 'مجي',\n  'ﷁ' => 'فمي',\n  'ﷂ' => 'بحي',\n  'ﷃ' => 'كمم',\n  'ﷄ' => 'عجم',\n  'ﷅ' => 'صمم',\n  'ﷆ' => 'سخي',\n  'ﷇ' => 'نجي',\n  'ﷰ' => 'صلے',\n  'ﷱ' => 'قلے',\n  'ﷲ' => 'الله',\n  'ﷳ' => 'اكبر',\n  'ﷴ' => 'محمد',\n  'ﷵ' => 'صلعم',\n  'ﷶ' => 'رسول',\n  'ﷷ' => 'عليه',\n  'ﷸ' => 'وسلم',\n  'ﷹ' => 'صلى',\n  'ﷺ' => 'صلى الله عليه وسلم',\n  'ﷻ' => 'جل جلاله',\n  '﷼' => 'ریال',\n  '︐' => ',',\n  '︑' => '、',\n  '︒' => '。',\n  '︓' => ':',\n  '︔' => ';',\n  '︕' => '!',\n  '︖' => '?',\n  '︗' => '〖',\n  '︘' => '〗',\n  '︙' => '...',\n  '︰' => '..',\n  '︱' => '—',\n  '︲' => '–',\n  '︳' => '_',\n  '︴' => '_',\n  '︵' => '(',\n  '︶' => ')',\n  '︷' => '{',\n  '︸' => '}',\n  '︹' => '〔',\n  '︺' => '〕',\n  '︻' => '【',\n  '︼' => '】',\n  '︽' => '《',\n  '︾' => '》',\n  '︿' => '〈',\n  '﹀' => '〉',\n  '﹁' => '「',\n  '﹂' => '」',\n  '﹃' => '『',\n  '﹄' => '』',\n  '﹇' => '[',\n  '﹈' => ']',\n  '﹉' => ' ̅',\n  '﹊' => ' ̅',\n  '﹋' => ' ̅',\n  '﹌' => ' ̅',\n  '﹍' => '_',\n  '﹎' => '_',\n  '﹏' => '_',\n  '﹐' => ',',\n  '﹑' => '、',\n  '﹒' => '.',\n  '﹔' => ';',\n  '﹕' => ':',\n  '﹖' => '?',\n  '﹗' => '!',\n  '﹘' => '—',\n  '﹙' => '(',\n  '﹚' => ')',\n  '﹛' => '{',\n  '﹜' => '}',\n  '﹝' => '〔',\n  '﹞' => '〕',\n  '﹟' => '#',\n  '﹠' => '&',\n  '﹡' => '*',\n  '﹢' => '+',\n  '﹣' => '-',\n  '﹤' => '<',\n  '﹥' => '>',\n  '﹦' => '=',\n  '﹨' => '\\\\',\n  '﹩' => '$',\n  '﹪' => '%',\n  '﹫' => '@',\n  'ﹰ' => ' ً',\n  'ﹱ' => 'ـً',\n  'ﹲ' => ' ٌ',\n  'ﹴ' => ' ٍ',\n  'ﹶ' => ' َ',\n  'ﹷ' => 'ـَ',\n  'ﹸ' => ' ُ',\n  'ﹹ' => 'ـُ',\n  'ﹺ' => ' ِ',\n  'ﹻ' => 'ـِ',\n  'ﹼ' => ' ّ',\n  'ﹽ' => 'ـّ',\n  'ﹾ' => ' ْ',\n  'ﹿ' => 'ـْ',\n  'ﺀ' => 'ء',\n  'ﺁ' => 'آ',\n  'ﺂ' => 'آ',\n  'ﺃ' => 'أ',\n  'ﺄ' => 'أ',\n  'ﺅ' => 'ؤ',\n  'ﺆ' => 'ؤ',\n  'ﺇ' => 'إ',\n  'ﺈ' => 'إ',\n  'ﺉ' => 'ئ',\n  'ﺊ' => 'ئ',\n  'ﺋ' => 'ئ',\n  'ﺌ' => 'ئ',\n  'ﺍ' => 'ا',\n  'ﺎ' => 'ا',\n  'ﺏ' => 'ب',\n  'ﺐ' => 'ب',\n  'ﺑ' => 'ب',\n  'ﺒ' => 'ب',\n  'ﺓ' => 'ة',\n  'ﺔ' => 'ة',\n  'ﺕ' => 'ت',\n  'ﺖ' => 'ت',\n  'ﺗ' => 'ت',\n  'ﺘ' => 'ت',\n  'ﺙ' => 'ث',\n  'ﺚ' => 'ث',\n  'ﺛ' => 'ث',\n  'ﺜ' => 'ث',\n  'ﺝ' => 'ج',\n  'ﺞ' => 'ج',\n  'ﺟ' => 'ج',\n  'ﺠ' => 'ج',\n  'ﺡ' => 'ح',\n  'ﺢ' => 'ح',\n  'ﺣ' => 'ح',\n  'ﺤ' => 'ح',\n  'ﺥ' => 'خ',\n  'ﺦ' => 'خ',\n  'ﺧ' => 'خ',\n  'ﺨ' => 'خ',\n  'ﺩ' => 'د',\n  'ﺪ' => 'د',\n  'ﺫ' => 'ذ',\n  'ﺬ' => 'ذ',\n  'ﺭ' => 'ر',\n  'ﺮ' => 'ر',\n  'ﺯ' => 'ز',\n  'ﺰ' => 'ز',\n  'ﺱ' => 'س',\n  'ﺲ' => 'س',\n  'ﺳ' => 'س',\n  'ﺴ' => 'س',\n  'ﺵ' => 'ش',\n  'ﺶ' => 'ش',\n  'ﺷ' => 'ش',\n  'ﺸ' => 'ش',\n  'ﺹ' => 'ص',\n  'ﺺ' => 'ص',\n  'ﺻ' => 'ص',\n  'ﺼ' => 'ص',\n  'ﺽ' => 'ض',\n  'ﺾ' => 'ض',\n  'ﺿ' => 'ض',\n  'ﻀ' => 'ض',\n  'ﻁ' => 'ط',\n  'ﻂ' => 'ط',\n  'ﻃ' => 'ط',\n  'ﻄ' => 'ط',\n  'ﻅ' => 'ظ',\n  'ﻆ' => 'ظ',\n  'ﻇ' => 'ظ',\n  'ﻈ' => 'ظ',\n  'ﻉ' => 'ع',\n  'ﻊ' => 'ع',\n  'ﻋ' => 'ع',\n  'ﻌ' => 'ع',\n  'ﻍ' => 'غ',\n  'ﻎ' => 'غ',\n  'ﻏ' => 'غ',\n  'ﻐ' => 'غ',\n  'ﻑ' => 'ف',\n  'ﻒ' => 'ف',\n  'ﻓ' => 'ف',\n  'ﻔ' => 'ف',\n  'ﻕ' => 'ق',\n  'ﻖ' => 'ق',\n  'ﻗ' => 'ق',\n  'ﻘ' => 'ق',\n  'ﻙ' => 'ك',\n  'ﻚ' => 'ك',\n  'ﻛ' => 'ك',\n  'ﻜ' => 'ك',\n  'ﻝ' => 'ل',\n  'ﻞ' => 'ل',\n  'ﻟ' => 'ل',\n  'ﻠ' => 'ل',\n  'ﻡ' => 'م',\n  'ﻢ' => 'م',\n  'ﻣ' => 'م',\n  'ﻤ' => 'م',\n  'ﻥ' => 'ن',\n  'ﻦ' => 'ن',\n  'ﻧ' => 'ن',\n  'ﻨ' => 'ن',\n  'ﻩ' => 'ه',\n  'ﻪ' => 'ه',\n  'ﻫ' => 'ه',\n  'ﻬ' => 'ه',\n  'ﻭ' => 'و',\n  'ﻮ' => 'و',\n  'ﻯ' => 'ى',\n  'ﻰ' => 'ى',\n  'ﻱ' => 'ي',\n  'ﻲ' => 'ي',\n  'ﻳ' => 'ي',\n  'ﻴ' => 'ي',\n  'ﻵ' => 'لآ',\n  'ﻶ' => 'لآ',\n  'ﻷ' => 'لأ',\n  'ﻸ' => 'لأ',\n  'ﻹ' => 'لإ',\n  'ﻺ' => 'لإ',\n  'ﻻ' => 'لا',\n  'ﻼ' => 'لا',\n  '！' => '!',\n  '＂' => '\"',\n  '＃' => '#',\n  '＄' => '$',\n  '％' => '%',\n  '＆' => '&',\n  '＇' => '\\'',\n  '（' => '(',\n  '）' => ')',\n  '＊' => '*',\n  '＋' => '+',\n  '，' => ',',\n  '－' => '-',\n  '．' => '.',\n  '／' => '/',\n  '０' => '0',\n  '１' => '1',\n  '２' => '2',\n  '３' => '3',\n  '４' => '4',\n  '５' => '5',\n  '６' => '6',\n  '７' => '7',\n  '８' => '8',\n  '９' => '9',\n  '：' => ':',\n  '；' => ';',\n  '＜' => '<',\n  '＝' => '=',\n  '＞' => '>',\n  '？' => '?',\n  '＠' => '@',\n  'Ａ' => 'A',\n  'Ｂ' => 'B',\n  'Ｃ' => 'C',\n  'Ｄ' => 'D',\n  'Ｅ' => 'E',\n  'Ｆ' => 'F',\n  'Ｇ' => 'G',\n  'Ｈ' => 'H',\n  'Ｉ' => 'I',\n  'Ｊ' => 'J',\n  'Ｋ' => 'K',\n  'Ｌ' => 'L',\n  'Ｍ' => 'M',\n  'Ｎ' => 'N',\n  'Ｏ' => 'O',\n  'Ｐ' => 'P',\n  'Ｑ' => 'Q',\n  'Ｒ' => 'R',\n  'Ｓ' => 'S',\n  'Ｔ' => 'T',\n  'Ｕ' => 'U',\n  'Ｖ' => 'V',\n  'Ｗ' => 'W',\n  'Ｘ' => 'X',\n  'Ｙ' => 'Y',\n  'Ｚ' => 'Z',\n  '［' => '[',\n  '＼' => '\\\\',\n  '］' => ']',\n  '＾' => '^',\n  '＿' => '_',\n  '｀' => '`',\n  'ａ' => 'a',\n  'ｂ' => 'b',\n  'ｃ' => 'c',\n  'ｄ' => 'd',\n  'ｅ' => 'e',\n  'ｆ' => 'f',\n  'ｇ' => 'g',\n  'ｈ' => 'h',\n  'ｉ' => 'i',\n  'ｊ' => 'j',\n  'ｋ' => 'k',\n  'ｌ' => 'l',\n  'ｍ' => 'm',\n  'ｎ' => 'n',\n  'ｏ' => 'o',\n  'ｐ' => 'p',\n  'ｑ' => 'q',\n  'ｒ' => 'r',\n  'ｓ' => 's',\n  'ｔ' => 't',\n  'ｕ' => 'u',\n  'ｖ' => 'v',\n  'ｗ' => 'w',\n  'ｘ' => 'x',\n  'ｙ' => 'y',\n  'ｚ' => 'z',\n  '｛' => '{',\n  '｜' => '|',\n  '｝' => '}',\n  '～' => '~',\n  '｟' => '⦅',\n  '｠' => '⦆',\n  '｡' => '。',\n  '｢' => '「',\n  '｣' => '」',\n  '､' => '、',\n  '･' => '・',\n  'ｦ' => 'ヲ',\n  'ｧ' => 'ァ',\n  'ｨ' => 'ィ',\n  'ｩ' => 'ゥ',\n  'ｪ' => 'ェ',\n  'ｫ' => 'ォ',\n  'ｬ' => 'ャ',\n  'ｭ' => 'ュ',\n  'ｮ' => 'ョ',\n  'ｯ' => 'ッ',\n  'ｰ' => 'ー',\n  'ｱ' => 'ア',\n  'ｲ' => 'イ',\n  'ｳ' => 'ウ',\n  'ｴ' => 'エ',\n  'ｵ' => 'オ',\n  'ｶ' => 'カ',\n  'ｷ' => 'キ',\n  'ｸ' => 'ク',\n  'ｹ' => 'ケ',\n  'ｺ' => 'コ',\n  'ｻ' => 'サ',\n  'ｼ' => 'シ',\n  'ｽ' => 'ス',\n  'ｾ' => 'セ',\n  'ｿ' => 'ソ',\n  'ﾀ' => 'タ',\n  'ﾁ' => 'チ',\n  'ﾂ' => 'ツ',\n  'ﾃ' => 'テ',\n  'ﾄ' => 'ト',\n  'ﾅ' => 'ナ',\n  'ﾆ' => 'ニ',\n  'ﾇ' => 'ヌ',\n  'ﾈ' => 'ネ',\n  'ﾉ' => 'ノ',\n  'ﾊ' => 'ハ',\n  'ﾋ' => 'ヒ',\n  'ﾌ' => 'フ',\n  'ﾍ' => 'ヘ',\n  'ﾎ' => 'ホ',\n  'ﾏ' => 'マ',\n  'ﾐ' => 'ミ',\n  'ﾑ' => 'ム',\n  'ﾒ' => 'メ',\n  'ﾓ' => 'モ',\n  'ﾔ' => 'ヤ',\n  'ﾕ' => 'ユ',\n  'ﾖ' => 'ヨ',\n  'ﾗ' => 'ラ',\n  'ﾘ' => 'リ',\n  'ﾙ' => 'ル',\n  'ﾚ' => 'レ',\n  'ﾛ' => 'ロ',\n  'ﾜ' => 'ワ',\n  'ﾝ' => 'ン',\n  'ﾞ' => '゙',\n  'ﾟ' => '゚',\n  'ﾠ' => 'ᅠ',\n  'ﾡ' => 'ᄀ',\n  'ﾢ' => 'ᄁ',\n  'ﾣ' => 'ᆪ',\n  'ﾤ' => 'ᄂ',\n  'ﾥ' => 'ᆬ',\n  'ﾦ' => 'ᆭ',\n  'ﾧ' => 'ᄃ',\n  'ﾨ' => 'ᄄ',\n  'ﾩ' => 'ᄅ',\n  'ﾪ' => 'ᆰ',\n  'ﾫ' => 'ᆱ',\n  'ﾬ' => 'ᆲ',\n  'ﾭ' => 'ᆳ',\n  'ﾮ' => 'ᆴ',\n  'ﾯ' => 'ᆵ',\n  'ﾰ' => 'ᄚ',\n  'ﾱ' => 'ᄆ',\n  'ﾲ' => 'ᄇ',\n  'ﾳ' => 'ᄈ',\n  'ﾴ' => 'ᄡ',\n  'ﾵ' => 'ᄉ',\n  'ﾶ' => 'ᄊ',\n  'ﾷ' => 'ᄋ',\n  'ﾸ' => 'ᄌ',\n  'ﾹ' => 'ᄍ',\n  'ﾺ' => 'ᄎ',\n  'ﾻ' => 'ᄏ',\n  'ﾼ' => 'ᄐ',\n  'ﾽ' => 'ᄑ',\n  'ﾾ' => 'ᄒ',\n  'ￂ' => 'ᅡ',\n  'ￃ' => 'ᅢ',\n  'ￄ' => 'ᅣ',\n  'ￅ' => 'ᅤ',\n  'ￆ' => 'ᅥ',\n  'ￇ' => 'ᅦ',\n  'ￊ' => 'ᅧ',\n  'ￋ' => 'ᅨ',\n  'ￌ' => 'ᅩ',\n  'ￍ' => 'ᅪ',\n  'ￎ' => 'ᅫ',\n  'ￏ' => 'ᅬ',\n  'ￒ' => 'ᅭ',\n  'ￓ' => 'ᅮ',\n  'ￔ' => 'ᅯ',\n  'ￕ' => 'ᅰ',\n  'ￖ' => 'ᅱ',\n  'ￗ' => 'ᅲ',\n  'ￚ' => 'ᅳ',\n  'ￛ' => 'ᅴ',\n  'ￜ' => 'ᅵ',\n  '￠' => '¢',\n  '￡' => '£',\n  '￢' => '¬',\n  '￣' => ' ̄',\n  '￤' => '¦',\n  '￥' => '¥',\n  '￦' => '₩',\n  '￨' => '│',\n  '￩' => '←',\n  '￪' => '↑',\n  '￫' => '→',\n  '￬' => '↓',\n  '￭' => '■',\n  '￮' => '○',\n  '𝐀' => 'A',\n  '𝐁' => 'B',\n  '𝐂' => 'C',\n  '𝐃' => 'D',\n  '𝐄' => 'E',\n  '𝐅' => 'F',\n  '𝐆' => 'G',\n  '𝐇' => 'H',\n  '𝐈' => 'I',\n  '𝐉' => 'J',\n  '𝐊' => 'K',\n  '𝐋' => 'L',\n  '𝐌' => 'M',\n  '𝐍' => 'N',\n  '𝐎' => 'O',\n  '𝐏' => 'P',\n  '𝐐' => 'Q',\n  '𝐑' => 'R',\n  '𝐒' => 'S',\n  '𝐓' => 'T',\n  '𝐔' => 'U',\n  '𝐕' => 'V',\n  '𝐖' => 'W',\n  '𝐗' => 'X',\n  '𝐘' => 'Y',\n  '𝐙' => 'Z',\n  '𝐚' => 'a',\n  '𝐛' => 'b',\n  '𝐜' => 'c',\n  '𝐝' => 'd',\n  '𝐞' => 'e',\n  '𝐟' => 'f',\n  '𝐠' => 'g',\n  '𝐡' => 'h',\n  '𝐢' => 'i',\n  '𝐣' => 'j',\n  '𝐤' => 'k',\n  '𝐥' => 'l',\n  '𝐦' => 'm',\n  '𝐧' => 'n',\n  '𝐨' => 'o',\n  '𝐩' => 'p',\n  '𝐪' => 'q',\n  '𝐫' => 'r',\n  '𝐬' => 's',\n  '𝐭' => 't',\n  '𝐮' => 'u',\n  '𝐯' => 'v',\n  '𝐰' => 'w',\n  '𝐱' => 'x',\n  '𝐲' => 'y',\n  '𝐳' => 'z',\n  '𝐴' => 'A',\n  '𝐵' => 'B',\n  '𝐶' => 'C',\n  '𝐷' => 'D',\n  '𝐸' => 'E',\n  '𝐹' => 'F',\n  '𝐺' => 'G',\n  '𝐻' => 'H',\n  '𝐼' => 'I',\n  '𝐽' => 'J',\n  '𝐾' => 'K',\n  '𝐿' => 'L',\n  '𝑀' => 'M',\n  '𝑁' => 'N',\n  '𝑂' => 'O',\n  '𝑃' => 'P',\n  '𝑄' => 'Q',\n  '𝑅' => 'R',\n  '𝑆' => 'S',\n  '𝑇' => 'T',\n  '𝑈' => 'U',\n  '𝑉' => 'V',\n  '𝑊' => 'W',\n  '𝑋' => 'X',\n  '𝑌' => 'Y',\n  '𝑍' => 'Z',\n  '𝑎' => 'a',\n  '𝑏' => 'b',\n  '𝑐' => 'c',\n  '𝑑' => 'd',\n  '𝑒' => 'e',\n  '𝑓' => 'f',\n  '𝑔' => 'g',\n  '𝑖' => 'i',\n  '𝑗' => 'j',\n  '𝑘' => 'k',\n  '𝑙' => 'l',\n  '𝑚' => 'm',\n  '𝑛' => 'n',\n  '𝑜' => 'o',\n  '𝑝' => 'p',\n  '𝑞' => 'q',\n  '𝑟' => 'r',\n  '𝑠' => 's',\n  '𝑡' => 't',\n  '𝑢' => 'u',\n  '𝑣' => 'v',\n  '𝑤' => 'w',\n  '𝑥' => 'x',\n  '𝑦' => 'y',\n  '𝑧' => 'z',\n  '𝑨' => 'A',\n  '𝑩' => 'B',\n  '𝑪' => 'C',\n  '𝑫' => 'D',\n  '𝑬' => 'E',\n  '𝑭' => 'F',\n  '𝑮' => 'G',\n  '𝑯' => 'H',\n  '𝑰' => 'I',\n  '𝑱' => 'J',\n  '𝑲' => 'K',\n  '𝑳' => 'L',\n  '𝑴' => 'M',\n  '𝑵' => 'N',\n  '𝑶' => 'O',\n  '𝑷' => 'P',\n  '𝑸' => 'Q',\n  '𝑹' => 'R',\n  '𝑺' => 'S',\n  '𝑻' => 'T',\n  '𝑼' => 'U',\n  '𝑽' => 'V',\n  '𝑾' => 'W',\n  '𝑿' => 'X',\n  '𝒀' => 'Y',\n  '𝒁' => 'Z',\n  '𝒂' => 'a',\n  '𝒃' => 'b',\n  '𝒄' => 'c',\n  '𝒅' => 'd',\n  '𝒆' => 'e',\n  '𝒇' => 'f',\n  '𝒈' => 'g',\n  '𝒉' => 'h',\n  '𝒊' => 'i',\n  '𝒋' => 'j',\n  '𝒌' => 'k',\n  '𝒍' => 'l',\n  '𝒎' => 'm',\n  '𝒏' => 'n',\n  '𝒐' => 'o',\n  '𝒑' => 'p',\n  '𝒒' => 'q',\n  '𝒓' => 'r',\n  '𝒔' => 's',\n  '𝒕' => 't',\n  '𝒖' => 'u',\n  '𝒗' => 'v',\n  '𝒘' => 'w',\n  '𝒙' => 'x',\n  '𝒚' => 'y',\n  '𝒛' => 'z',\n  '𝒜' => 'A',\n  '𝒞' => 'C',\n  '𝒟' => 'D',\n  '𝒢' => 'G',\n  '𝒥' => 'J',\n  '𝒦' => 'K',\n  '𝒩' => 'N',\n  '𝒪' => 'O',\n  '𝒫' => 'P',\n  '𝒬' => 'Q',\n  '𝒮' => 'S',\n  '𝒯' => 'T',\n  '𝒰' => 'U',\n  '𝒱' => 'V',\n  '𝒲' => 'W',\n  '𝒳' => 'X',\n  '𝒴' => 'Y',\n  '𝒵' => 'Z',\n  '𝒶' => 'a',\n  '𝒷' => 'b',\n  '𝒸' => 'c',\n  '𝒹' => 'd',\n  '𝒻' => 'f',\n  '𝒽' => 'h',\n  '𝒾' => 'i',\n  '𝒿' => 'j',\n  '𝓀' => 'k',\n  '𝓁' => 'l',\n  '𝓂' => 'm',\n  '𝓃' => 'n',\n  '𝓅' => 'p',\n  '𝓆' => 'q',\n  '𝓇' => 'r',\n  '𝓈' => 's',\n  '𝓉' => 't',\n  '𝓊' => 'u',\n  '𝓋' => 'v',\n  '𝓌' => 'w',\n  '𝓍' => 'x',\n  '𝓎' => 'y',\n  '𝓏' => 'z',\n  '𝓐' => 'A',\n  '𝓑' => 'B',\n  '𝓒' => 'C',\n  '𝓓' => 'D',\n  '𝓔' => 'E',\n  '𝓕' => 'F',\n  '𝓖' => 'G',\n  '𝓗' => 'H',\n  '𝓘' => 'I',\n  '𝓙' => 'J',\n  '𝓚' => 'K',\n  '𝓛' => 'L',\n  '𝓜' => 'M',\n  '𝓝' => 'N',\n  '𝓞' => 'O',\n  '𝓟' => 'P',\n  '𝓠' => 'Q',\n  '𝓡' => 'R',\n  '𝓢' => 'S',\n  '𝓣' => 'T',\n  '𝓤' => 'U',\n  '𝓥' => 'V',\n  '𝓦' => 'W',\n  '𝓧' => 'X',\n  '𝓨' => 'Y',\n  '𝓩' => 'Z',\n  '𝓪' => 'a',\n  '𝓫' => 'b',\n  '𝓬' => 'c',\n  '𝓭' => 'd',\n  '𝓮' => 'e',\n  '𝓯' => 'f',\n  '𝓰' => 'g',\n  '𝓱' => 'h',\n  '𝓲' => 'i',\n  '𝓳' => 'j',\n  '𝓴' => 'k',\n  '𝓵' => 'l',\n  '𝓶' => 'm',\n  '𝓷' => 'n',\n  '𝓸' => 'o',\n  '𝓹' => 'p',\n  '𝓺' => 'q',\n  '𝓻' => 'r',\n  '𝓼' => 's',\n  '𝓽' => 't',\n  '𝓾' => 'u',\n  '𝓿' => 'v',\n  '𝔀' => 'w',\n  '𝔁' => 'x',\n  '𝔂' => 'y',\n  '𝔃' => 'z',\n  '𝔄' => 'A',\n  '𝔅' => 'B',\n  '𝔇' => 'D',\n  '𝔈' => 'E',\n  '𝔉' => 'F',\n  '𝔊' => 'G',\n  '𝔍' => 'J',\n  '𝔎' => 'K',\n  '𝔏' => 'L',\n  '𝔐' => 'M',\n  '𝔑' => 'N',\n  '𝔒' => 'O',\n  '𝔓' => 'P',\n  '𝔔' => 'Q',\n  '𝔖' => 'S',\n  '𝔗' => 'T',\n  '𝔘' => 'U',\n  '𝔙' => 'V',\n  '𝔚' => 'W',\n  '𝔛' => 'X',\n  '𝔜' => 'Y',\n  '𝔞' => 'a',\n  '𝔟' => 'b',\n  '𝔠' => 'c',\n  '𝔡' => 'd',\n  '𝔢' => 'e',\n  '𝔣' => 'f',\n  '𝔤' => 'g',\n  '𝔥' => 'h',\n  '𝔦' => 'i',\n  '𝔧' => 'j',\n  '𝔨' => 'k',\n  '𝔩' => 'l',\n  '𝔪' => 'm',\n  '𝔫' => 'n',\n  '𝔬' => 'o',\n  '𝔭' => 'p',\n  '𝔮' => 'q',\n  '𝔯' => 'r',\n  '𝔰' => 's',\n  '𝔱' => 't',\n  '𝔲' => 'u',\n  '𝔳' => 'v',\n  '𝔴' => 'w',\n  '𝔵' => 'x',\n  '𝔶' => 'y',\n  '𝔷' => 'z',\n  '𝔸' => 'A',\n  '𝔹' => 'B',\n  '𝔻' => 'D',\n  '𝔼' => 'E',\n  '𝔽' => 'F',\n  '𝔾' => 'G',\n  '𝕀' => 'I',\n  '𝕁' => 'J',\n  '𝕂' => 'K',\n  '𝕃' => 'L',\n  '𝕄' => 'M',\n  '𝕆' => 'O',\n  '𝕊' => 'S',\n  '𝕋' => 'T',\n  '𝕌' => 'U',\n  '𝕍' => 'V',\n  '𝕎' => 'W',\n  '𝕏' => 'X',\n  '𝕐' => 'Y',\n  '𝕒' => 'a',\n  '𝕓' => 'b',\n  '𝕔' => 'c',\n  '𝕕' => 'd',\n  '𝕖' => 'e',\n  '𝕗' => 'f',\n  '𝕘' => 'g',\n  '𝕙' => 'h',\n  '𝕚' => 'i',\n  '𝕛' => 'j',\n  '𝕜' => 'k',\n  '𝕝' => 'l',\n  '𝕞' => 'm',\n  '𝕟' => 'n',\n  '𝕠' => 'o',\n  '𝕡' => 'p',\n  '𝕢' => 'q',\n  '𝕣' => 'r',\n  '𝕤' => 's',\n  '𝕥' => 't',\n  '𝕦' => 'u',\n  '𝕧' => 'v',\n  '𝕨' => 'w',\n  '𝕩' => 'x',\n  '𝕪' => 'y',\n  '𝕫' => 'z',\n  '𝕬' => 'A',\n  '𝕭' => 'B',\n  '𝕮' => 'C',\n  '𝕯' => 'D',\n  '𝕰' => 'E',\n  '𝕱' => 'F',\n  '𝕲' => 'G',\n  '𝕳' => 'H',\n  '𝕴' => 'I',\n  '𝕵' => 'J',\n  '𝕶' => 'K',\n  '𝕷' => 'L',\n  '𝕸' => 'M',\n  '𝕹' => 'N',\n  '𝕺' => 'O',\n  '𝕻' => 'P',\n  '𝕼' => 'Q',\n  '𝕽' => 'R',\n  '𝕾' => 'S',\n  '𝕿' => 'T',\n  '𝖀' => 'U',\n  '𝖁' => 'V',\n  '𝖂' => 'W',\n  '𝖃' => 'X',\n  '𝖄' => 'Y',\n  '𝖅' => 'Z',\n  '𝖆' => 'a',\n  '𝖇' => 'b',\n  '𝖈' => 'c',\n  '𝖉' => 'd',\n  '𝖊' => 'e',\n  '𝖋' => 'f',\n  '𝖌' => 'g',\n  '𝖍' => 'h',\n  '𝖎' => 'i',\n  '𝖏' => 'j',\n  '𝖐' => 'k',\n  '𝖑' => 'l',\n  '𝖒' => 'm',\n  '𝖓' => 'n',\n  '𝖔' => 'o',\n  '𝖕' => 'p',\n  '𝖖' => 'q',\n  '𝖗' => 'r',\n  '𝖘' => 's',\n  '𝖙' => 't',\n  '𝖚' => 'u',\n  '𝖛' => 'v',\n  '𝖜' => 'w',\n  '𝖝' => 'x',\n  '𝖞' => 'y',\n  '𝖟' => 'z',\n  '𝖠' => 'A',\n  '𝖡' => 'B',\n  '𝖢' => 'C',\n  '𝖣' => 'D',\n  '𝖤' => 'E',\n  '𝖥' => 'F',\n  '𝖦' => 'G',\n  '𝖧' => 'H',\n  '𝖨' => 'I',\n  '𝖩' => 'J',\n  '𝖪' => 'K',\n  '𝖫' => 'L',\n  '𝖬' => 'M',\n  '𝖭' => 'N',\n  '𝖮' => 'O',\n  '𝖯' => 'P',\n  '𝖰' => 'Q',\n  '𝖱' => 'R',\n  '𝖲' => 'S',\n  '𝖳' => 'T',\n  '𝖴' => 'U',\n  '𝖵' => 'V',\n  '𝖶' => 'W',\n  '𝖷' => 'X',\n  '𝖸' => 'Y',\n  '𝖹' => 'Z',\n  '𝖺' => 'a',\n  '𝖻' => 'b',\n  '𝖼' => 'c',\n  '𝖽' => 'd',\n  '𝖾' => 'e',\n  '𝖿' => 'f',\n  '𝗀' => 'g',\n  '𝗁' => 'h',\n  '𝗂' => 'i',\n  '𝗃' => 'j',\n  '𝗄' => 'k',\n  '𝗅' => 'l',\n  '𝗆' => 'm',\n  '𝗇' => 'n',\n  '𝗈' => 'o',\n  '𝗉' => 'p',\n  '𝗊' => 'q',\n  '𝗋' => 'r',\n  '𝗌' => 's',\n  '𝗍' => 't',\n  '𝗎' => 'u',\n  '𝗏' => 'v',\n  '𝗐' => 'w',\n  '𝗑' => 'x',\n  '𝗒' => 'y',\n  '𝗓' => 'z',\n  '𝗔' => 'A',\n  '𝗕' => 'B',\n  '𝗖' => 'C',\n  '𝗗' => 'D',\n  '𝗘' => 'E',\n  '𝗙' => 'F',\n  '𝗚' => 'G',\n  '𝗛' => 'H',\n  '𝗜' => 'I',\n  '𝗝' => 'J',\n  '𝗞' => 'K',\n  '𝗟' => 'L',\n  '𝗠' => 'M',\n  '𝗡' => 'N',\n  '𝗢' => 'O',\n  '𝗣' => 'P',\n  '𝗤' => 'Q',\n  '𝗥' => 'R',\n  '𝗦' => 'S',\n  '𝗧' => 'T',\n  '𝗨' => 'U',\n  '𝗩' => 'V',\n  '𝗪' => 'W',\n  '𝗫' => 'X',\n  '𝗬' => 'Y',\n  '𝗭' => 'Z',\n  '𝗮' => 'a',\n  '𝗯' => 'b',\n  '𝗰' => 'c',\n  '𝗱' => 'd',\n  '𝗲' => 'e',\n  '𝗳' => 'f',\n  '𝗴' => 'g',\n  '𝗵' => 'h',\n  '𝗶' => 'i',\n  '𝗷' => 'j',\n  '𝗸' => 'k',\n  '𝗹' => 'l',\n  '𝗺' => 'm',\n  '𝗻' => 'n',\n  '𝗼' => 'o',\n  '𝗽' => 'p',\n  '𝗾' => 'q',\n  '𝗿' => 'r',\n  '𝘀' => 's',\n  '𝘁' => 't',\n  '𝘂' => 'u',\n  '𝘃' => 'v',\n  '𝘄' => 'w',\n  '𝘅' => 'x',\n  '𝘆' => 'y',\n  '𝘇' => 'z',\n  '𝘈' => 'A',\n  '𝘉' => 'B',\n  '𝘊' => 'C',\n  '𝘋' => 'D',\n  '𝘌' => 'E',\n  '𝘍' => 'F',\n  '𝘎' => 'G',\n  '𝘏' => 'H',\n  '𝘐' => 'I',\n  '𝘑' => 'J',\n  '𝘒' => 'K',\n  '𝘓' => 'L',\n  '𝘔' => 'M',\n  '𝘕' => 'N',\n  '𝘖' => 'O',\n  '𝘗' => 'P',\n  '𝘘' => 'Q',\n  '𝘙' => 'R',\n  '𝘚' => 'S',\n  '𝘛' => 'T',\n  '𝘜' => 'U',\n  '𝘝' => 'V',\n  '𝘞' => 'W',\n  '𝘟' => 'X',\n  '𝘠' => 'Y',\n  '𝘡' => 'Z',\n  '𝘢' => 'a',\n  '𝘣' => 'b',\n  '𝘤' => 'c',\n  '𝘥' => 'd',\n  '𝘦' => 'e',\n  '𝘧' => 'f',\n  '𝘨' => 'g',\n  '𝘩' => 'h',\n  '𝘪' => 'i',\n  '𝘫' => 'j',\n  '𝘬' => 'k',\n  '𝘭' => 'l',\n  '𝘮' => 'm',\n  '𝘯' => 'n',\n  '𝘰' => 'o',\n  '𝘱' => 'p',\n  '𝘲' => 'q',\n  '𝘳' => 'r',\n  '𝘴' => 's',\n  '𝘵' => 't',\n  '𝘶' => 'u',\n  '𝘷' => 'v',\n  '𝘸' => 'w',\n  '𝘹' => 'x',\n  '𝘺' => 'y',\n  '𝘻' => 'z',\n  '𝘼' => 'A',\n  '𝘽' => 'B',\n  '𝘾' => 'C',\n  '𝘿' => 'D',\n  '𝙀' => 'E',\n  '𝙁' => 'F',\n  '𝙂' => 'G',\n  '𝙃' => 'H',\n  '𝙄' => 'I',\n  '𝙅' => 'J',\n  '𝙆' => 'K',\n  '𝙇' => 'L',\n  '𝙈' => 'M',\n  '𝙉' => 'N',\n  '𝙊' => 'O',\n  '𝙋' => 'P',\n  '𝙌' => 'Q',\n  '𝙍' => 'R',\n  '𝙎' => 'S',\n  '𝙏' => 'T',\n  '𝙐' => 'U',\n  '𝙑' => 'V',\n  '𝙒' => 'W',\n  '𝙓' => 'X',\n  '𝙔' => 'Y',\n  '𝙕' => 'Z',\n  '𝙖' => 'a',\n  '𝙗' => 'b',\n  '𝙘' => 'c',\n  '𝙙' => 'd',\n  '𝙚' => 'e',\n  '𝙛' => 'f',\n  '𝙜' => 'g',\n  '𝙝' => 'h',\n  '𝙞' => 'i',\n  '𝙟' => 'j',\n  '𝙠' => 'k',\n  '𝙡' => 'l',\n  '𝙢' => 'm',\n  '𝙣' => 'n',\n  '𝙤' => 'o',\n  '𝙥' => 'p',\n  '𝙦' => 'q',\n  '𝙧' => 'r',\n  '𝙨' => 's',\n  '𝙩' => 't',\n  '𝙪' => 'u',\n  '𝙫' => 'v',\n  '𝙬' => 'w',\n  '𝙭' => 'x',\n  '𝙮' => 'y',\n  '𝙯' => 'z',\n  '𝙰' => 'A',\n  '𝙱' => 'B',\n  '𝙲' => 'C',\n  '𝙳' => 'D',\n  '𝙴' => 'E',\n  '𝙵' => 'F',\n  '𝙶' => 'G',\n  '𝙷' => 'H',\n  '𝙸' => 'I',\n  '𝙹' => 'J',\n  '𝙺' => 'K',\n  '𝙻' => 'L',\n  '𝙼' => 'M',\n  '𝙽' => 'N',\n  '𝙾' => 'O',\n  '𝙿' => 'P',\n  '𝚀' => 'Q',\n  '𝚁' => 'R',\n  '𝚂' => 'S',\n  '𝚃' => 'T',\n  '𝚄' => 'U',\n  '𝚅' => 'V',\n  '𝚆' => 'W',\n  '𝚇' => 'X',\n  '𝚈' => 'Y',\n  '𝚉' => 'Z',\n  '𝚊' => 'a',\n  '𝚋' => 'b',\n  '𝚌' => 'c',\n  '𝚍' => 'd',\n  '𝚎' => 'e',\n  '𝚏' => 'f',\n  '𝚐' => 'g',\n  '𝚑' => 'h',\n  '𝚒' => 'i',\n  '𝚓' => 'j',\n  '𝚔' => 'k',\n  '𝚕' => 'l',\n  '𝚖' => 'm',\n  '𝚗' => 'n',\n  '𝚘' => 'o',\n  '𝚙' => 'p',\n  '𝚚' => 'q',\n  '𝚛' => 'r',\n  '𝚜' => 's',\n  '𝚝' => 't',\n  '𝚞' => 'u',\n  '𝚟' => 'v',\n  '𝚠' => 'w',\n  '𝚡' => 'x',\n  '𝚢' => 'y',\n  '𝚣' => 'z',\n  '𝚤' => 'ı',\n  '𝚥' => 'ȷ',\n  '𝚨' => 'Α',\n  '𝚩' => 'Β',\n  '𝚪' => 'Γ',\n  '𝚫' => 'Δ',\n  '𝚬' => 'Ε',\n  '𝚭' => 'Ζ',\n  '𝚮' => 'Η',\n  '𝚯' => 'Θ',\n  '𝚰' => 'Ι',\n  '𝚱' => 'Κ',\n  '𝚲' => 'Λ',\n  '𝚳' => 'Μ',\n  '𝚴' => 'Ν',\n  '𝚵' => 'Ξ',\n  '𝚶' => 'Ο',\n  '𝚷' => 'Π',\n  '𝚸' => 'Ρ',\n  '𝚹' => 'Θ',\n  '𝚺' => 'Σ',\n  '𝚻' => 'Τ',\n  '𝚼' => 'Υ',\n  '𝚽' => 'Φ',\n  '𝚾' => 'Χ',\n  '𝚿' => 'Ψ',\n  '𝛀' => 'Ω',\n  '𝛁' => '∇',\n  '𝛂' => 'α',\n  '𝛃' => 'β',\n  '𝛄' => 'γ',\n  '𝛅' => 'δ',\n  '𝛆' => 'ε',\n  '𝛇' => 'ζ',\n  '𝛈' => 'η',\n  '𝛉' => 'θ',\n  '𝛊' => 'ι',\n  '𝛋' => 'κ',\n  '𝛌' => 'λ',\n  '𝛍' => 'μ',\n  '𝛎' => 'ν',\n  '𝛏' => 'ξ',\n  '𝛐' => 'ο',\n  '𝛑' => 'π',\n  '𝛒' => 'ρ',\n  '𝛓' => 'ς',\n  '𝛔' => 'σ',\n  '𝛕' => 'τ',\n  '𝛖' => 'υ',\n  '𝛗' => 'φ',\n  '𝛘' => 'χ',\n  '𝛙' => 'ψ',\n  '𝛚' => 'ω',\n  '𝛛' => '∂',\n  '𝛜' => 'ε',\n  '𝛝' => 'θ',\n  '𝛞' => 'κ',\n  '𝛟' => 'φ',\n  '𝛠' => 'ρ',\n  '𝛡' => 'π',\n  '𝛢' => 'Α',\n  '𝛣' => 'Β',\n  '𝛤' => 'Γ',\n  '𝛥' => 'Δ',\n  '𝛦' => 'Ε',\n  '𝛧' => 'Ζ',\n  '𝛨' => 'Η',\n  '𝛩' => 'Θ',\n  '𝛪' => 'Ι',\n  '𝛫' => 'Κ',\n  '𝛬' => 'Λ',\n  '𝛭' => 'Μ',\n  '𝛮' => 'Ν',\n  '𝛯' => 'Ξ',\n  '𝛰' => 'Ο',\n  '𝛱' => 'Π',\n  '𝛲' => 'Ρ',\n  '𝛳' => 'Θ',\n  '𝛴' => 'Σ',\n  '𝛵' => 'Τ',\n  '𝛶' => 'Υ',\n  '𝛷' => 'Φ',\n  '𝛸' => 'Χ',\n  '𝛹' => 'Ψ',\n  '𝛺' => 'Ω',\n  '𝛻' => '∇',\n  '𝛼' => 'α',\n  '𝛽' => 'β',\n  '𝛾' => 'γ',\n  '𝛿' => 'δ',\n  '𝜀' => 'ε',\n  '𝜁' => 'ζ',\n  '𝜂' => 'η',\n  '𝜃' => 'θ',\n  '𝜄' => 'ι',\n  '𝜅' => 'κ',\n  '𝜆' => 'λ',\n  '𝜇' => 'μ',\n  '𝜈' => 'ν',\n  '𝜉' => 'ξ',\n  '𝜊' => 'ο',\n  '𝜋' => 'π',\n  '𝜌' => 'ρ',\n  '𝜍' => 'ς',\n  '𝜎' => 'σ',\n  '𝜏' => 'τ',\n  '𝜐' => 'υ',\n  '𝜑' => 'φ',\n  '𝜒' => 'χ',\n  '𝜓' => 'ψ',\n  '𝜔' => 'ω',\n  '𝜕' => '∂',\n  '𝜖' => 'ε',\n  '𝜗' => 'θ',\n  '𝜘' => 'κ',\n  '𝜙' => 'φ',\n  '𝜚' => 'ρ',\n  '𝜛' => 'π',\n  '𝜜' => 'Α',\n  '𝜝' => 'Β',\n  '𝜞' => 'Γ',\n  '𝜟' => 'Δ',\n  '𝜠' => 'Ε',\n  '𝜡' => 'Ζ',\n  '𝜢' => 'Η',\n  '𝜣' => 'Θ',\n  '𝜤' => 'Ι',\n  '𝜥' => 'Κ',\n  '𝜦' => 'Λ',\n  '𝜧' => 'Μ',\n  '𝜨' => 'Ν',\n  '𝜩' => 'Ξ',\n  '𝜪' => 'Ο',\n  '𝜫' => 'Π',\n  '𝜬' => 'Ρ',\n  '𝜭' => 'Θ',\n  '𝜮' => 'Σ',\n  '𝜯' => 'Τ',\n  '𝜰' => 'Υ',\n  '𝜱' => 'Φ',\n  '𝜲' => 'Χ',\n  '𝜳' => 'Ψ',\n  '𝜴' => 'Ω',\n  '𝜵' => '∇',\n  '𝜶' => 'α',\n  '𝜷' => 'β',\n  '𝜸' => 'γ',\n  '𝜹' => 'δ',\n  '𝜺' => 'ε',\n  '𝜻' => 'ζ',\n  '𝜼' => 'η',\n  '𝜽' => 'θ',\n  '𝜾' => 'ι',\n  '𝜿' => 'κ',\n  '𝝀' => 'λ',\n  '𝝁' => 'μ',\n  '𝝂' => 'ν',\n  '𝝃' => 'ξ',\n  '𝝄' => 'ο',\n  '𝝅' => 'π',\n  '𝝆' => 'ρ',\n  '𝝇' => 'ς',\n  '𝝈' => 'σ',\n  '𝝉' => 'τ',\n  '𝝊' => 'υ',\n  '𝝋' => 'φ',\n  '𝝌' => 'χ',\n  '𝝍' => 'ψ',\n  '𝝎' => 'ω',\n  '𝝏' => '∂',\n  '𝝐' => 'ε',\n  '𝝑' => 'θ',\n  '𝝒' => 'κ',\n  '𝝓' => 'φ',\n  '𝝔' => 'ρ',\n  '𝝕' => 'π',\n  '𝝖' => 'Α',\n  '𝝗' => 'Β',\n  '𝝘' => 'Γ',\n  '𝝙' => 'Δ',\n  '𝝚' => 'Ε',\n  '𝝛' => 'Ζ',\n  '𝝜' => 'Η',\n  '𝝝' => 'Θ',\n  '𝝞' => 'Ι',\n  '𝝟' => 'Κ',\n  '𝝠' => 'Λ',\n  '𝝡' => 'Μ',\n  '𝝢' => 'Ν',\n  '𝝣' => 'Ξ',\n  '𝝤' => 'Ο',\n  '𝝥' => 'Π',\n  '𝝦' => 'Ρ',\n  '𝝧' => 'Θ',\n  '𝝨' => 'Σ',\n  '𝝩' => 'Τ',\n  '𝝪' => 'Υ',\n  '𝝫' => 'Φ',\n  '𝝬' => 'Χ',\n  '𝝭' => 'Ψ',\n  '𝝮' => 'Ω',\n  '𝝯' => '∇',\n  '𝝰' => 'α',\n  '𝝱' => 'β',\n  '𝝲' => 'γ',\n  '𝝳' => 'δ',\n  '𝝴' => 'ε',\n  '𝝵' => 'ζ',\n  '𝝶' => 'η',\n  '𝝷' => 'θ',\n  '𝝸' => 'ι',\n  '𝝹' => 'κ',\n  '𝝺' => 'λ',\n  '𝝻' => 'μ',\n  '𝝼' => 'ν',\n  '𝝽' => 'ξ',\n  '𝝾' => 'ο',\n  '𝝿' => 'π',\n  '𝞀' => 'ρ',\n  '𝞁' => 'ς',\n  '𝞂' => 'σ',\n  '𝞃' => 'τ',\n  '𝞄' => 'υ',\n  '𝞅' => 'φ',\n  '𝞆' => 'χ',\n  '𝞇' => 'ψ',\n  '𝞈' => 'ω',\n  '𝞉' => '∂',\n  '𝞊' => 'ε',\n  '𝞋' => 'θ',\n  '𝞌' => 'κ',\n  '𝞍' => 'φ',\n  '𝞎' => 'ρ',\n  '𝞏' => 'π',\n  '𝞐' => 'Α',\n  '𝞑' => 'Β',\n  '𝞒' => 'Γ',\n  '𝞓' => 'Δ',\n  '𝞔' => 'Ε',\n  '𝞕' => 'Ζ',\n  '𝞖' => 'Η',\n  '𝞗' => 'Θ',\n  '𝞘' => 'Ι',\n  '𝞙' => 'Κ',\n  '𝞚' => 'Λ',\n  '𝞛' => 'Μ',\n  '𝞜' => 'Ν',\n  '𝞝' => 'Ξ',\n  '𝞞' => 'Ο',\n  '𝞟' => 'Π',\n  '𝞠' => 'Ρ',\n  '𝞡' => 'Θ',\n  '𝞢' => 'Σ',\n  '𝞣' => 'Τ',\n  '𝞤' => 'Υ',\n  '𝞥' => 'Φ',\n  '𝞦' => 'Χ',\n  '𝞧' => 'Ψ',\n  '𝞨' => 'Ω',\n  '𝞩' => '∇',\n  '𝞪' => 'α',\n  '𝞫' => 'β',\n  '𝞬' => 'γ',\n  '𝞭' => 'δ',\n  '𝞮' => 'ε',\n  '𝞯' => 'ζ',\n  '𝞰' => 'η',\n  '𝞱' => 'θ',\n  '𝞲' => 'ι',\n  '𝞳' => 'κ',\n  '𝞴' => 'λ',\n  '𝞵' => 'μ',\n  '𝞶' => 'ν',\n  '𝞷' => 'ξ',\n  '𝞸' => 'ο',\n  '𝞹' => 'π',\n  '𝞺' => 'ρ',\n  '𝞻' => 'ς',\n  '𝞼' => 'σ',\n  '𝞽' => 'τ',\n  '𝞾' => 'υ',\n  '𝞿' => 'φ',\n  '𝟀' => 'χ',\n  '𝟁' => 'ψ',\n  '𝟂' => 'ω',\n  '𝟃' => '∂',\n  '𝟄' => 'ε',\n  '𝟅' => 'θ',\n  '𝟆' => 'κ',\n  '𝟇' => 'φ',\n  '𝟈' => 'ρ',\n  '𝟉' => 'π',\n  '𝟊' => 'Ϝ',\n  '𝟋' => 'ϝ',\n  '𝟎' => '0',\n  '𝟏' => '1',\n  '𝟐' => '2',\n  '𝟑' => '3',\n  '𝟒' => '4',\n  '𝟓' => '5',\n  '𝟔' => '6',\n  '𝟕' => '7',\n  '𝟖' => '8',\n  '𝟗' => '9',\n  '𝟘' => '0',\n  '𝟙' => '1',\n  '𝟚' => '2',\n  '𝟛' => '3',\n  '𝟜' => '4',\n  '𝟝' => '5',\n  '𝟞' => '6',\n  '𝟟' => '7',\n  '𝟠' => '8',\n  '𝟡' => '9',\n  '𝟢' => '0',\n  '𝟣' => '1',\n  '𝟤' => '2',\n  '𝟥' => '3',\n  '𝟦' => '4',\n  '𝟧' => '5',\n  '𝟨' => '6',\n  '𝟩' => '7',\n  '𝟪' => '8',\n  '𝟫' => '9',\n  '𝟬' => '0',\n  '𝟭' => '1',\n  '𝟮' => '2',\n  '𝟯' => '3',\n  '𝟰' => '4',\n  '𝟱' => '5',\n  '𝟲' => '6',\n  '𝟳' => '7',\n  '𝟴' => '8',\n  '𝟵' => '9',\n  '𝟶' => '0',\n  '𝟷' => '1',\n  '𝟸' => '2',\n  '𝟹' => '3',\n  '𝟺' => '4',\n  '𝟻' => '5',\n  '𝟼' => '6',\n  '𝟽' => '7',\n  '𝟾' => '8',\n  '𝟿' => '9',\n  '𞸀' => 'ا',\n  '𞸁' => 'ب',\n  '𞸂' => 'ج',\n  '𞸃' => 'د',\n  '𞸅' => 'و',\n  '𞸆' => 'ز',\n  '𞸇' => 'ح',\n  '𞸈' => 'ط',\n  '𞸉' => 'ي',\n  '𞸊' => 'ك',\n  '𞸋' => 'ل',\n  '𞸌' => 'م',\n  '𞸍' => 'ن',\n  '𞸎' => 'س',\n  '𞸏' => 'ع',\n  '𞸐' => 'ف',\n  '𞸑' => 'ص',\n  '𞸒' => 'ق',\n  '𞸓' => 'ر',\n  '𞸔' => 'ش',\n  '𞸕' => 'ت',\n  '𞸖' => 'ث',\n  '𞸗' => 'خ',\n  '𞸘' => 'ذ',\n  '𞸙' => 'ض',\n  '𞸚' => 'ظ',\n  '𞸛' => 'غ',\n  '𞸜' => 'ٮ',\n  '𞸝' => 'ں',\n  '𞸞' => 'ڡ',\n  '𞸟' => 'ٯ',\n  '𞸡' => 'ب',\n  '𞸢' => 'ج',\n  '𞸤' => 'ه',\n  '𞸧' => 'ح',\n  '𞸩' => 'ي',\n  '𞸪' => 'ك',\n  '𞸫' => 'ل',\n  '𞸬' => 'م',\n  '𞸭' => 'ن',\n  '𞸮' => 'س',\n  '𞸯' => 'ع',\n  '𞸰' => 'ف',\n  '𞸱' => 'ص',\n  '𞸲' => 'ق',\n  '𞸴' => 'ش',\n  '𞸵' => 'ت',\n  '𞸶' => 'ث',\n  '𞸷' => 'خ',\n  '𞸹' => 'ض',\n  '𞸻' => 'غ',\n  '𞹂' => 'ج',\n  '𞹇' => 'ح',\n  '𞹉' => 'ي',\n  '𞹋' => 'ل',\n  '𞹍' => 'ن',\n  '𞹎' => 'س',\n  '𞹏' => 'ع',\n  '𞹑' => 'ص',\n  '𞹒' => 'ق',\n  '𞹔' => 'ش',\n  '𞹗' => 'خ',\n  '𞹙' => 'ض',\n  '𞹛' => 'غ',\n  '𞹝' => 'ں',\n  '𞹟' => 'ٯ',\n  '𞹡' => 'ب',\n  '𞹢' => 'ج',\n  '𞹤' => 'ه',\n  '𞹧' => 'ح',\n  '𞹨' => 'ط',\n  '𞹩' => 'ي',\n  '𞹪' => 'ك',\n  '𞹬' => 'م',\n  '𞹭' => 'ن',\n  '𞹮' => 'س',\n  '𞹯' => 'ع',\n  '𞹰' => 'ف',\n  '𞹱' => 'ص',\n  '𞹲' => 'ق',\n  '𞹴' => 'ش',\n  '𞹵' => 'ت',\n  '𞹶' => 'ث',\n  '𞹷' => 'خ',\n  '𞹹' => 'ض',\n  '𞹺' => 'ظ',\n  '𞹻' => 'غ',\n  '𞹼' => 'ٮ',\n  '𞹾' => 'ڡ',\n  '𞺀' => 'ا',\n  '𞺁' => 'ب',\n  '𞺂' => 'ج',\n  '𞺃' => 'د',\n  '𞺄' => 'ه',\n  '𞺅' => 'و',\n  '𞺆' => 'ز',\n  '𞺇' => 'ح',\n  '𞺈' => 'ط',\n  '𞺉' => 'ي',\n  '𞺋' => 'ل',\n  '𞺌' => 'م',\n  '𞺍' => 'ن',\n  '𞺎' => 'س',\n  '𞺏' => 'ع',\n  '𞺐' => 'ف',\n  '𞺑' => 'ص',\n  '𞺒' => 'ق',\n  '𞺓' => 'ر',\n  '𞺔' => 'ش',\n  '𞺕' => 'ت',\n  '𞺖' => 'ث',\n  '𞺗' => 'خ',\n  '𞺘' => 'ذ',\n  '𞺙' => 'ض',\n  '𞺚' => 'ظ',\n  '𞺛' => 'غ',\n  '𞺡' => 'ب',\n  '𞺢' => 'ج',\n  '𞺣' => 'د',\n  '𞺥' => 'و',\n  '𞺦' => 'ز',\n  '𞺧' => 'ح',\n  '𞺨' => 'ط',\n  '𞺩' => 'ي',\n  '𞺫' => 'ل',\n  '𞺬' => 'م',\n  '𞺭' => 'ن',\n  '𞺮' => 'س',\n  '𞺯' => 'ع',\n  '𞺰' => 'ف',\n  '𞺱' => 'ص',\n  '𞺲' => 'ق',\n  '𞺳' => 'ر',\n  '𞺴' => 'ش',\n  '𞺵' => 'ت',\n  '𞺶' => 'ث',\n  '𞺷' => 'خ',\n  '𞺸' => 'ذ',\n  '𞺹' => 'ض',\n  '𞺺' => 'ظ',\n  '𞺻' => 'غ',\n  '🄀' => '0.',\n  '🄁' => '0,',\n  '🄂' => '1,',\n  '🄃' => '2,',\n  '🄄' => '3,',\n  '🄅' => '4,',\n  '🄆' => '5,',\n  '🄇' => '6,',\n  '🄈' => '7,',\n  '🄉' => '8,',\n  '🄊' => '9,',\n  '🄐' => '(A)',\n  '🄑' => '(B)',\n  '🄒' => '(C)',\n  '🄓' => '(D)',\n  '🄔' => '(E)',\n  '🄕' => '(F)',\n  '🄖' => '(G)',\n  '🄗' => '(H)',\n  '🄘' => '(I)',\n  '🄙' => '(J)',\n  '🄚' => '(K)',\n  '🄛' => '(L)',\n  '🄜' => '(M)',\n  '🄝' => '(N)',\n  '🄞' => '(O)',\n  '🄟' => '(P)',\n  '🄠' => '(Q)',\n  '🄡' => '(R)',\n  '🄢' => '(S)',\n  '🄣' => '(T)',\n  '🄤' => '(U)',\n  '🄥' => '(V)',\n  '🄦' => '(W)',\n  '🄧' => '(X)',\n  '🄨' => '(Y)',\n  '🄩' => '(Z)',\n  '🄪' => '〔S〕',\n  '🄫' => 'C',\n  '🄬' => 'R',\n  '🄭' => 'CD',\n  '🄮' => 'WZ',\n  '🄰' => 'A',\n  '🄱' => 'B',\n  '🄲' => 'C',\n  '🄳' => 'D',\n  '🄴' => 'E',\n  '🄵' => 'F',\n  '🄶' => 'G',\n  '🄷' => 'H',\n  '🄸' => 'I',\n  '🄹' => 'J',\n  '🄺' => 'K',\n  '🄻' => 'L',\n  '🄼' => 'M',\n  '🄽' => 'N',\n  '🄾' => 'O',\n  '🄿' => 'P',\n  '🅀' => 'Q',\n  '🅁' => 'R',\n  '🅂' => 'S',\n  '🅃' => 'T',\n  '🅄' => 'U',\n  '🅅' => 'V',\n  '🅆' => 'W',\n  '🅇' => 'X',\n  '🅈' => 'Y',\n  '🅉' => 'Z',\n  '🅊' => 'HV',\n  '🅋' => 'MV',\n  '🅌' => 'SD',\n  '🅍' => 'SS',\n  '🅎' => 'PPV',\n  '🅏' => 'WC',\n  '🅪' => 'MC',\n  '🅫' => 'MD',\n  '🅬' => 'MR',\n  '🆐' => 'DJ',\n  '🈀' => 'ほか',\n  '🈁' => 'ココ',\n  '🈂' => 'サ',\n  '🈐' => '手',\n  '🈑' => '字',\n  '🈒' => '双',\n  '🈓' => 'デ',\n  '🈔' => '二',\n  '🈕' => '多',\n  '🈖' => '解',\n  '🈗' => '天',\n  '🈘' => '交',\n  '🈙' => '映',\n  '🈚' => '無',\n  '🈛' => '料',\n  '🈜' => '前',\n  '🈝' => '後',\n  '🈞' => '再',\n  '🈟' => '新',\n  '🈠' => '初',\n  '🈡' => '終',\n  '🈢' => '生',\n  '🈣' => '販',\n  '🈤' => '声',\n  '🈥' => '吹',\n  '🈦' => '演',\n  '🈧' => '投',\n  '🈨' => '捕',\n  '🈩' => '一',\n  '🈪' => '三',\n  '🈫' => '遊',\n  '🈬' => '左',\n  '🈭' => '中',\n  '🈮' => '右',\n  '🈯' => '指',\n  '🈰' => '走',\n  '🈱' => '打',\n  '🈲' => '禁',\n  '🈳' => '空',\n  '🈴' => '合',\n  '🈵' => '満',\n  '🈶' => '有',\n  '🈷' => '月',\n  '🈸' => '申',\n  '🈹' => '割',\n  '🈺' => '営',\n  '🈻' => '配',\n  '🉀' => '〔本〕',\n  '🉁' => '〔三〕',\n  '🉂' => '〔二〕',\n  '🉃' => '〔安〕',\n  '🉄' => '〔点〕',\n  '🉅' => '〔打〕',\n  '🉆' => '〔盗〕',\n  '🉇' => '〔勝〕',\n  '🉈' => '〔敗〕',\n  '🉐' => '得',\n  '🉑' => '可',\n  '🯰' => '0',\n  '🯱' => '1',\n  '🯲' => '2',\n  '🯳' => '3',\n  '🯴' => '4',\n  '🯵' => '5',\n  '🯶' => '6',\n  '🯷' => '7',\n  '🯸' => '8',\n  '🯹' => '9',\n);\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-intl-normalizer/bootstrap.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nuse Symfony\\Polyfill\\Intl\\Normalizer as p;\n\nif (\\PHP_VERSION_ID >= 80000) {\n    return require __DIR__.'/bootstrap80.php';\n}\n\nif (!function_exists('normalizer_is_normalized')) {\n    function normalizer_is_normalized($string, $form = p\\Normalizer::FORM_C) { return p\\Normalizer::isNormalized($string, $form); }\n}\nif (!function_exists('normalizer_normalize')) {\n    function normalizer_normalize($string, $form = p\\Normalizer::FORM_C) { return p\\Normalizer::normalize($string, $form); }\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-intl-normalizer/bootstrap80.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nuse Symfony\\Polyfill\\Intl\\Normalizer as p;\n\nif (!function_exists('normalizer_is_normalized')) {\n    function normalizer_is_normalized(?string $string, ?int $form = p\\Normalizer::FORM_C): bool { return p\\Normalizer::isNormalized((string) $string, (int) $form); }\n}\nif (!function_exists('normalizer_normalize')) {\n    function normalizer_normalize(?string $string, ?int $form = p\\Normalizer::FORM_C): string|false { return p\\Normalizer::normalize((string) $string, (int) $form); }\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-intl-normalizer/composer.json",
    "content": "{\n    \"name\": \"symfony/polyfill-intl-normalizer\",\n    \"type\": \"library\",\n    \"description\": \"Symfony polyfill for intl's Normalizer class and related functions\",\n    \"keywords\": [\"polyfill\", \"shim\", \"compatibility\", \"portable\", \"intl\", \"normalizer\"],\n    \"homepage\": \"https://symfony.com\",\n    \"license\": \"MIT\",\n    \"authors\": [\n        {\n            \"name\": \"Nicolas Grekas\",\n            \"email\": \"p@tchwork.com\"\n        },\n        {\n            \"name\": \"Symfony Community\",\n            \"homepage\": \"https://symfony.com/contributors\"\n        }\n    ],\n    \"require\": {\n        \"php\": \">=7.2\"\n    },\n    \"autoload\": {\n        \"psr-4\": { \"Symfony\\\\Polyfill\\\\Intl\\\\Normalizer\\\\\": \"\" },\n        \"files\": [ \"bootstrap.php\" ],\n        \"classmap\": [ \"Resources/stubs\" ]\n    },\n    \"suggest\": {\n        \"ext-intl\": \"For best performance\"\n    },\n    \"minimum-stability\": \"dev\",\n    \"extra\": {\n        \"thanks\": {\n            \"name\": \"symfony/polyfill\",\n            \"url\": \"https://github.com/symfony/polyfill\"\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-mbstring/LICENSE",
    "content": "Copyright (c) 2015-present Fabien Potencier\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is furnished\nto do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-mbstring/Mbstring.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Polyfill\\Mbstring;\n\n/**\n * Partial mbstring implementation in PHP, iconv based, UTF-8 centric.\n *\n * Implemented:\n * - mb_chr                  - Returns a specific character from its Unicode code point\n * - mb_convert_encoding     - Convert character encoding\n * - mb_convert_variables    - Convert character code in variable(s)\n * - mb_decode_mimeheader    - Decode string in MIME header field\n * - mb_encode_mimeheader    - Encode string for MIME header XXX NATIVE IMPLEMENTATION IS REALLY BUGGED\n * - mb_decode_numericentity - Decode HTML numeric string reference to character\n * - mb_encode_numericentity - Encode character to HTML numeric string reference\n * - mb_convert_case         - Perform case folding on a string\n * - mb_detect_encoding      - Detect character encoding\n * - mb_get_info             - Get internal settings of mbstring\n * - mb_http_input           - Detect HTTP input character encoding\n * - mb_http_output          - Set/Get HTTP output character encoding\n * - mb_internal_encoding    - Set/Get internal character encoding\n * - mb_list_encodings       - Returns an array of all supported encodings\n * - mb_ord                  - Returns the Unicode code point of a character\n * - mb_output_handler       - Callback function converts character encoding in output buffer\n * - mb_scrub                - Replaces ill-formed byte sequences with substitute characters\n * - mb_strlen               - Get string length\n * - mb_strpos               - Find position of first occurrence of string in a string\n * - mb_strrpos              - Find position of last occurrence of a string in a string\n * - mb_str_split            - Convert a string to an array\n * - mb_strtolower           - Make a string lowercase\n * - mb_strtoupper           - Make a string uppercase\n * - mb_substitute_character - Set/Get substitution character\n * - mb_substr               - Get part of string\n * - mb_stripos              - Finds position of first occurrence of a string within another, case insensitive\n * - mb_stristr              - Finds first occurrence of a string within another, case insensitive\n * - mb_strrchr              - Finds the last occurrence of a character in a string within another\n * - mb_strrichr             - Finds the last occurrence of a character in a string within another, case insensitive\n * - mb_strripos             - Finds position of last occurrence of a string within another, case insensitive\n * - mb_strstr               - Finds first occurrence of a string within another\n * - mb_strwidth             - Return width of string\n * - mb_substr_count         - Count the number of substring occurrences\n * - mb_ucfirst              - Make a string's first character uppercase\n * - mb_lcfirst              - Make a string's first character lowercase\n * - mb_trim                 - Strip whitespace (or other characters) from the beginning and end of a string\n * - mb_ltrim                - Strip whitespace (or other characters) from the beginning of a string\n * - mb_rtrim                - Strip whitespace (or other characters) from the end of a string\n *\n * Not implemented:\n * - mb_convert_kana         - Convert \"kana\" one from another (\"zen-kaku\", \"han-kaku\" and more)\n * - mb_ereg_*               - Regular expression with multibyte support\n * - mb_parse_str            - Parse GET/POST/COOKIE data and set global variable\n * - mb_preferred_mime_name  - Get MIME charset string\n * - mb_regex_encoding       - Returns current encoding for multibyte regex as string\n * - mb_regex_set_options    - Set/Get the default options for mbregex functions\n * - mb_send_mail            - Send encoded mail\n * - mb_split                - Split multibyte string using regular expression\n * - mb_strcut               - Get part of string\n * - mb_strimwidth           - Get truncated string with specified width\n *\n * @author Nicolas Grekas <p@tchwork.com>\n *\n * @internal\n */\nfinal class Mbstring\n{\n    public const MB_CASE_FOLD = \\PHP_INT_MAX;\n\n    private const SIMPLE_CASE_FOLD = [\n        ['µ', 'ſ', \"\\xCD\\x85\", 'ς', \"\\xCF\\x90\", \"\\xCF\\x91\", \"\\xCF\\x95\", \"\\xCF\\x96\", \"\\xCF\\xB0\", \"\\xCF\\xB1\", \"\\xCF\\xB5\", \"\\xE1\\xBA\\x9B\", \"\\xE1\\xBE\\xBE\"],\n        ['μ', 's', 'ι',        'σ', 'β',        'θ',        'φ',        'π',        'κ',        'ρ',        'ε',        \"\\xE1\\xB9\\xA1\", 'ι'],\n    ];\n\n    private static $encodingList = ['ASCII', 'UTF-8'];\n    private static $language = 'neutral';\n    private static $internalEncoding = 'UTF-8';\n\n    public static function mb_convert_encoding($s, $toEncoding, $fromEncoding = null)\n    {\n        if (\\is_array($s)) {\n            $r = [];\n            foreach ($s as $str) {\n                $r[] = self::mb_convert_encoding($str, $toEncoding, $fromEncoding);\n            }\n\n            return $r;\n        }\n\n        if (\\is_array($fromEncoding) || (null !== $fromEncoding && false !== strpos($fromEncoding, ','))) {\n            $fromEncoding = self::mb_detect_encoding($s, $fromEncoding);\n        } else {\n            $fromEncoding = self::getEncoding($fromEncoding);\n        }\n\n        $toEncoding = self::getEncoding($toEncoding);\n\n        if ('BASE64' === $fromEncoding) {\n            $s = base64_decode($s);\n            $fromEncoding = $toEncoding;\n        }\n\n        if ('BASE64' === $toEncoding) {\n            return base64_encode($s);\n        }\n\n        if ('HTML-ENTITIES' === $toEncoding || 'HTML' === $toEncoding) {\n            if ('HTML-ENTITIES' === $fromEncoding || 'HTML' === $fromEncoding) {\n                $fromEncoding = 'Windows-1252';\n            }\n            if ('UTF-8' !== $fromEncoding) {\n                $s = iconv($fromEncoding, 'UTF-8//IGNORE', $s);\n            }\n\n            return preg_replace_callback('/[\\x80-\\xFF]+/', [__CLASS__, 'html_encoding_callback'], $s);\n        }\n\n        if ('HTML-ENTITIES' === $fromEncoding) {\n            $s = html_entity_decode($s, \\ENT_COMPAT, 'UTF-8');\n            $fromEncoding = 'UTF-8';\n        }\n\n        return iconv($fromEncoding, $toEncoding.'//IGNORE', $s);\n    }\n\n    public static function mb_convert_variables($toEncoding, $fromEncoding, &...$vars)\n    {\n        $ok = true;\n        array_walk_recursive($vars, function (&$v) use (&$ok, $toEncoding, $fromEncoding) {\n            if (false === $v = self::mb_convert_encoding($v, $toEncoding, $fromEncoding)) {\n                $ok = false;\n            }\n        });\n\n        return $ok ? $fromEncoding : false;\n    }\n\n    public static function mb_decode_mimeheader($s)\n    {\n        return iconv_mime_decode($s, 2, self::$internalEncoding);\n    }\n\n    public static function mb_encode_mimeheader($s, $charset = null, $transferEncoding = null, $linefeed = null, $indent = null)\n    {\n        trigger_error('mb_encode_mimeheader() is bugged. Please use iconv_mime_encode() instead', \\E_USER_WARNING);\n    }\n\n    public static function mb_decode_numericentity($s, $convmap, $encoding = null)\n    {\n        if (null !== $s && !\\is_scalar($s) && !(\\is_object($s) && method_exists($s, '__toString'))) {\n            trigger_error('mb_decode_numericentity() expects parameter 1 to be string, '.\\gettype($s).' given', \\E_USER_WARNING);\n\n            return null;\n        }\n\n        if (!\\is_array($convmap) || (80000 > \\PHP_VERSION_ID && !$convmap)) {\n            return false;\n        }\n\n        if (null !== $encoding && !\\is_scalar($encoding)) {\n            trigger_error('mb_decode_numericentity() expects parameter 3 to be string, '.\\gettype($s).' given', \\E_USER_WARNING);\n\n            return '';  // Instead of null (cf. mb_encode_numericentity).\n        }\n\n        $s = (string) $s;\n        if ('' === $s) {\n            return '';\n        }\n\n        $encoding = self::getEncoding($encoding);\n\n        if ('UTF-8' === $encoding) {\n            $encoding = null;\n            if (!preg_match('//u', $s)) {\n                $s = @iconv('UTF-8', 'UTF-8//IGNORE', $s);\n            }\n        } else {\n            $s = iconv($encoding, 'UTF-8//IGNORE', $s);\n        }\n\n        $cnt = floor(\\count($convmap) / 4) * 4;\n\n        for ($i = 0; $i < $cnt; $i += 4) {\n            // collector_decode_htmlnumericentity ignores $convmap[$i + 3]\n            $convmap[$i] += $convmap[$i + 2];\n            $convmap[$i + 1] += $convmap[$i + 2];\n        }\n\n        $s = preg_replace_callback('/&#(?:0*([0-9]+)|x0*([0-9a-fA-F]+))(?!&);?/', function (array $m) use ($cnt, $convmap) {\n            $c = isset($m[2]) ? (int) hexdec($m[2]) : $m[1];\n            for ($i = 0; $i < $cnt; $i += 4) {\n                if ($c >= $convmap[$i] && $c <= $convmap[$i + 1]) {\n                    return self::mb_chr($c - $convmap[$i + 2]);\n                }\n            }\n\n            return $m[0];\n        }, $s);\n\n        if (null === $encoding) {\n            return $s;\n        }\n\n        return iconv('UTF-8', $encoding.'//IGNORE', $s);\n    }\n\n    public static function mb_encode_numericentity($s, $convmap, $encoding = null, $is_hex = false)\n    {\n        if (null !== $s && !\\is_scalar($s) && !(\\is_object($s) && method_exists($s, '__toString'))) {\n            trigger_error('mb_encode_numericentity() expects parameter 1 to be string, '.\\gettype($s).' given', \\E_USER_WARNING);\n\n            return null;\n        }\n\n        if (!\\is_array($convmap) || (80000 > \\PHP_VERSION_ID && !$convmap)) {\n            return false;\n        }\n\n        if (null !== $encoding && !\\is_scalar($encoding)) {\n            trigger_error('mb_encode_numericentity() expects parameter 3 to be string, '.\\gettype($s).' given', \\E_USER_WARNING);\n\n            return null;  // Instead of '' (cf. mb_decode_numericentity).\n        }\n\n        if (null !== $is_hex && !\\is_scalar($is_hex)) {\n            trigger_error('mb_encode_numericentity() expects parameter 4 to be boolean, '.\\gettype($s).' given', \\E_USER_WARNING);\n\n            return null;\n        }\n\n        $s = (string) $s;\n        if ('' === $s) {\n            return '';\n        }\n\n        $encoding = self::getEncoding($encoding);\n\n        if ('UTF-8' === $encoding) {\n            $encoding = null;\n            if (!preg_match('//u', $s)) {\n                $s = @iconv('UTF-8', 'UTF-8//IGNORE', $s);\n            }\n        } else {\n            $s = iconv($encoding, 'UTF-8//IGNORE', $s);\n        }\n\n        static $ulenMask = [\"\\xC0\" => 2, \"\\xD0\" => 2, \"\\xE0\" => 3, \"\\xF0\" => 4];\n\n        $cnt = floor(\\count($convmap) / 4) * 4;\n        $i = 0;\n        $len = \\strlen($s);\n        $result = '';\n\n        while ($i < $len) {\n            $ulen = $s[$i] < \"\\x80\" ? 1 : $ulenMask[$s[$i] & \"\\xF0\"];\n            $uchr = substr($s, $i, $ulen);\n            $i += $ulen;\n            $c = self::mb_ord($uchr);\n\n            for ($j = 0; $j < $cnt; $j += 4) {\n                if ($c >= $convmap[$j] && $c <= $convmap[$j + 1]) {\n                    $cOffset = ($c + $convmap[$j + 2]) & $convmap[$j + 3];\n                    $result .= $is_hex ? sprintf('&#x%X;', $cOffset) : '&#'.$cOffset.';';\n                    continue 2;\n                }\n            }\n            $result .= $uchr;\n        }\n\n        if (null === $encoding) {\n            return $result;\n        }\n\n        return iconv('UTF-8', $encoding.'//IGNORE', $result);\n    }\n\n    public static function mb_convert_case($s, $mode, $encoding = null)\n    {\n        $s = (string) $s;\n        if ('' === $s) {\n            return '';\n        }\n\n        $encoding = self::getEncoding($encoding);\n\n        if ('UTF-8' === $encoding) {\n            $encoding = null;\n            if (!preg_match('//u', $s)) {\n                $s = @iconv('UTF-8', 'UTF-8//IGNORE', $s);\n            }\n        } else {\n            $s = iconv($encoding, 'UTF-8//IGNORE', $s);\n        }\n\n        if (\\MB_CASE_TITLE == $mode) {\n            static $titleRegexp = null;\n            if (null === $titleRegexp) {\n                $titleRegexp = self::getData('titleCaseRegexp');\n            }\n            $s = preg_replace_callback($titleRegexp, [__CLASS__, 'title_case'], $s);\n        } else {\n            if (\\MB_CASE_UPPER == $mode) {\n                static $upper = null;\n                if (null === $upper) {\n                    $upper = self::getData('upperCase');\n                }\n                $map = $upper;\n            } else {\n                if (self::MB_CASE_FOLD === $mode) {\n                    static $caseFolding = null;\n                    if (null === $caseFolding) {\n                        $caseFolding = self::getData('caseFolding');\n                    }\n                    $s = strtr($s, $caseFolding);\n                }\n\n                static $lower = null;\n                if (null === $lower) {\n                    $lower = self::getData('lowerCase');\n                }\n                $map = $lower;\n            }\n\n            static $ulenMask = [\"\\xC0\" => 2, \"\\xD0\" => 2, \"\\xE0\" => 3, \"\\xF0\" => 4];\n\n            $i = 0;\n            $len = \\strlen($s);\n\n            while ($i < $len) {\n                $ulen = $s[$i] < \"\\x80\" ? 1 : $ulenMask[$s[$i] & \"\\xF0\"];\n                $uchr = substr($s, $i, $ulen);\n                $i += $ulen;\n\n                if (isset($map[$uchr])) {\n                    $uchr = $map[$uchr];\n                    $nlen = \\strlen($uchr);\n\n                    if ($nlen == $ulen) {\n                        $nlen = $i;\n                        do {\n                            $s[--$nlen] = $uchr[--$ulen];\n                        } while ($ulen);\n                    } else {\n                        $s = substr_replace($s, $uchr, $i - $ulen, $ulen);\n                        $len += $nlen - $ulen;\n                        $i += $nlen - $ulen;\n                    }\n                }\n            }\n        }\n\n        if (null === $encoding) {\n            return $s;\n        }\n\n        return iconv('UTF-8', $encoding.'//IGNORE', $s);\n    }\n\n    public static function mb_internal_encoding($encoding = null)\n    {\n        if (null === $encoding) {\n            return self::$internalEncoding;\n        }\n\n        $normalizedEncoding = self::getEncoding($encoding);\n\n        if ('UTF-8' === $normalizedEncoding || false !== @iconv($normalizedEncoding, $normalizedEncoding, ' ')) {\n            self::$internalEncoding = $normalizedEncoding;\n\n            return true;\n        }\n\n        if (80000 > \\PHP_VERSION_ID) {\n            return false;\n        }\n\n        throw new \\ValueError(sprintf('Argument #1 ($encoding) must be a valid encoding, \"%s\" given', $encoding));\n    }\n\n    public static function mb_language($lang = null)\n    {\n        if (null === $lang) {\n            return self::$language;\n        }\n\n        switch ($normalizedLang = strtolower($lang)) {\n            case 'uni':\n            case 'neutral':\n                self::$language = $normalizedLang;\n\n                return true;\n        }\n\n        if (80000 > \\PHP_VERSION_ID) {\n            return false;\n        }\n\n        throw new \\ValueError(sprintf('Argument #1 ($language) must be a valid language, \"%s\" given', $lang));\n    }\n\n    public static function mb_list_encodings()\n    {\n        return ['UTF-8'];\n    }\n\n    public static function mb_encoding_aliases($encoding)\n    {\n        switch (strtoupper($encoding)) {\n            case 'UTF8':\n            case 'UTF-8':\n                return ['utf8'];\n        }\n\n        return false;\n    }\n\n    public static function mb_check_encoding($var = null, $encoding = null)\n    {\n        if (null === $encoding) {\n            if (null === $var) {\n                return false;\n            }\n            $encoding = self::$internalEncoding;\n        }\n\n        if (!\\is_array($var)) {\n            return self::mb_detect_encoding($var, [$encoding]) || false !== @iconv($encoding, $encoding, $var);\n        }\n\n        foreach ($var as $key => $value) {\n            if (!self::mb_check_encoding($key, $encoding)) {\n                return false;\n            }\n            if (!self::mb_check_encoding($value, $encoding)) {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    public static function mb_detect_encoding($str, $encodingList = null, $strict = false)\n    {\n        if (null === $encodingList) {\n            $encodingList = self::$encodingList;\n        } else {\n            if (!\\is_array($encodingList)) {\n                $encodingList = array_map('trim', explode(',', $encodingList));\n            }\n            $encodingList = array_map('strtoupper', $encodingList);\n        }\n\n        foreach ($encodingList as $enc) {\n            switch ($enc) {\n                case 'ASCII':\n                    if (!preg_match('/[\\x80-\\xFF]/', $str)) {\n                        return $enc;\n                    }\n                    break;\n\n                case 'UTF8':\n                case 'UTF-8':\n                    if (preg_match('//u', $str)) {\n                        return 'UTF-8';\n                    }\n                    break;\n\n                default:\n                    if (0 === strncmp($enc, 'ISO-8859-', 9)) {\n                        return $enc;\n                    }\n            }\n        }\n\n        return false;\n    }\n\n    public static function mb_detect_order($encodingList = null)\n    {\n        if (null === $encodingList) {\n            return self::$encodingList;\n        }\n\n        if (!\\is_array($encodingList)) {\n            $encodingList = array_map('trim', explode(',', $encodingList));\n        }\n        $encodingList = array_map('strtoupper', $encodingList);\n\n        foreach ($encodingList as $enc) {\n            switch ($enc) {\n                default:\n                    if (strncmp($enc, 'ISO-8859-', 9)) {\n                        return false;\n                    }\n                    // no break\n                case 'ASCII':\n                case 'UTF8':\n                case 'UTF-8':\n            }\n        }\n\n        self::$encodingList = $encodingList;\n\n        return true;\n    }\n\n    public static function mb_strlen($s, $encoding = null)\n    {\n        $encoding = self::getEncoding($encoding);\n        if ('CP850' === $encoding || 'ASCII' === $encoding) {\n            return \\strlen($s);\n        }\n\n        return @iconv_strlen($s, $encoding);\n    }\n\n    public static function mb_strpos($haystack, $needle, $offset = 0, $encoding = null)\n    {\n        $encoding = self::getEncoding($encoding);\n        if ('CP850' === $encoding || 'ASCII' === $encoding) {\n            return strpos($haystack, $needle, $offset);\n        }\n\n        $needle = (string) $needle;\n        if ('' === $needle) {\n            if (80000 > \\PHP_VERSION_ID) {\n                trigger_error(__METHOD__.': Empty delimiter', \\E_USER_WARNING);\n\n                return false;\n            }\n\n            return 0;\n        }\n\n        return iconv_strpos($haystack, $needle, $offset, $encoding);\n    }\n\n    public static function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null)\n    {\n        $encoding = self::getEncoding($encoding);\n        if ('CP850' === $encoding || 'ASCII' === $encoding) {\n            return strrpos($haystack, $needle, $offset);\n        }\n\n        if ($offset != (int) $offset) {\n            $offset = 0;\n        } elseif ($offset = (int) $offset) {\n            if ($offset < 0) {\n                if (0 > $offset += self::mb_strlen($needle)) {\n                    $haystack = self::mb_substr($haystack, 0, $offset, $encoding);\n                }\n                $offset = 0;\n            } else {\n                $haystack = self::mb_substr($haystack, $offset, 2147483647, $encoding);\n            }\n        }\n\n        $pos = '' !== $needle || 80000 > \\PHP_VERSION_ID\n            ? iconv_strrpos($haystack, $needle, $encoding)\n            : self::mb_strlen($haystack, $encoding);\n\n        return false !== $pos ? $offset + $pos : false;\n    }\n\n    public static function mb_str_split($string, $split_length = 1, $encoding = null)\n    {\n        if (null !== $string && !\\is_scalar($string) && !(\\is_object($string) && method_exists($string, '__toString'))) {\n            trigger_error('mb_str_split() expects parameter 1 to be string, '.\\gettype($string).' given', \\E_USER_WARNING);\n\n            return null;\n        }\n\n        if (1 > $split_length = (int) $split_length) {\n            if (80000 > \\PHP_VERSION_ID) {\n                trigger_error('The length of each segment must be greater than zero', \\E_USER_WARNING);\n\n                return false;\n            }\n\n            throw new \\ValueError('Argument #2 ($length) must be greater than 0');\n        }\n\n        if (null === $encoding) {\n            $encoding = mb_internal_encoding();\n        }\n\n        if ('UTF-8' === $encoding = self::getEncoding($encoding)) {\n            $rx = '/(';\n            while (65535 < $split_length) {\n                $rx .= '.{65535}';\n                $split_length -= 65535;\n            }\n            $rx .= '.{'.$split_length.'})/us';\n\n            return preg_split($rx, $string, -1, \\PREG_SPLIT_DELIM_CAPTURE | \\PREG_SPLIT_NO_EMPTY);\n        }\n\n        $result = [];\n        $length = mb_strlen($string, $encoding);\n\n        for ($i = 0; $i < $length; $i += $split_length) {\n            $result[] = mb_substr($string, $i, $split_length, $encoding);\n        }\n\n        return $result;\n    }\n\n    public static function mb_strtolower($s, $encoding = null)\n    {\n        return self::mb_convert_case($s, \\MB_CASE_LOWER, $encoding);\n    }\n\n    public static function mb_strtoupper($s, $encoding = null)\n    {\n        return self::mb_convert_case($s, \\MB_CASE_UPPER, $encoding);\n    }\n\n    public static function mb_substitute_character($c = null)\n    {\n        if (null === $c) {\n            return 'none';\n        }\n        if (0 === strcasecmp($c, 'none')) {\n            return true;\n        }\n        if (80000 > \\PHP_VERSION_ID) {\n            return false;\n        }\n        if (\\is_int($c) || 'long' === $c || 'entity' === $c) {\n            return false;\n        }\n\n        throw new \\ValueError('Argument #1 ($substitute_character) must be \"none\", \"long\", \"entity\" or a valid codepoint');\n    }\n\n    public static function mb_substr($s, $start, $length = null, $encoding = null)\n    {\n        $encoding = self::getEncoding($encoding);\n        if ('CP850' === $encoding || 'ASCII' === $encoding) {\n            return (string) substr($s, $start, null === $length ? 2147483647 : $length);\n        }\n\n        if ($start < 0) {\n            $start = iconv_strlen($s, $encoding) + $start;\n            if ($start < 0) {\n                $start = 0;\n            }\n        }\n\n        if (null === $length) {\n            $length = 2147483647;\n        } elseif ($length < 0) {\n            $length = iconv_strlen($s, $encoding) + $length - $start;\n            if ($length < 0) {\n                return '';\n            }\n        }\n\n        return (string) iconv_substr($s, $start, $length, $encoding);\n    }\n\n    public static function mb_stripos($haystack, $needle, $offset = 0, $encoding = null)\n    {\n        [$haystack, $needle] = str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], [\n            self::mb_convert_case($haystack, \\MB_CASE_LOWER, $encoding),\n            self::mb_convert_case($needle, \\MB_CASE_LOWER, $encoding),\n        ]);\n\n        return self::mb_strpos($haystack, $needle, $offset, $encoding);\n    }\n\n    public static function mb_stristr($haystack, $needle, $part = false, $encoding = null)\n    {\n        $pos = self::mb_stripos($haystack, $needle, 0, $encoding);\n\n        return self::getSubpart($pos, $part, $haystack, $encoding);\n    }\n\n    public static function mb_strrchr($haystack, $needle, $part = false, $encoding = null)\n    {\n        $encoding = self::getEncoding($encoding);\n        if ('CP850' === $encoding || 'ASCII' === $encoding) {\n            $pos = strrpos($haystack, $needle);\n        } else {\n            $needle = self::mb_substr($needle, 0, 1, $encoding);\n            $pos = iconv_strrpos($haystack, $needle, $encoding);\n        }\n\n        return self::getSubpart($pos, $part, $haystack, $encoding);\n    }\n\n    public static function mb_strrichr($haystack, $needle, $part = false, $encoding = null)\n    {\n        $needle = self::mb_substr($needle, 0, 1, $encoding);\n        $pos = self::mb_strripos($haystack, $needle, $encoding);\n\n        return self::getSubpart($pos, $part, $haystack, $encoding);\n    }\n\n    public static function mb_strripos($haystack, $needle, $offset = 0, $encoding = null)\n    {\n        $haystack = self::mb_convert_case($haystack, \\MB_CASE_LOWER, $encoding);\n        $needle = self::mb_convert_case($needle, \\MB_CASE_LOWER, $encoding);\n\n        $haystack = str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], $haystack);\n        $needle = str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], $needle);\n\n        return self::mb_strrpos($haystack, $needle, $offset, $encoding);\n    }\n\n    public static function mb_strstr($haystack, $needle, $part = false, $encoding = null)\n    {\n        $pos = strpos($haystack, $needle);\n        if (false === $pos) {\n            return false;\n        }\n        if ($part) {\n            return substr($haystack, 0, $pos);\n        }\n\n        return substr($haystack, $pos);\n    }\n\n    public static function mb_get_info($type = 'all')\n    {\n        $info = [\n            'internal_encoding' => self::$internalEncoding,\n            'http_output' => 'pass',\n            'http_output_conv_mimetypes' => '^(text/|application/xhtml\\+xml)',\n            'func_overload' => 0,\n            'func_overload_list' => 'no overload',\n            'mail_charset' => 'UTF-8',\n            'mail_header_encoding' => 'BASE64',\n            'mail_body_encoding' => 'BASE64',\n            'illegal_chars' => 0,\n            'encoding_translation' => 'Off',\n            'language' => self::$language,\n            'detect_order' => self::$encodingList,\n            'substitute_character' => 'none',\n            'strict_detection' => 'Off',\n        ];\n\n        if ('all' === $type) {\n            return $info;\n        }\n        if (isset($info[$type])) {\n            return $info[$type];\n        }\n\n        return false;\n    }\n\n    public static function mb_http_input($type = '')\n    {\n        return false;\n    }\n\n    public static function mb_http_output($encoding = null)\n    {\n        return null !== $encoding ? 'pass' === $encoding : 'pass';\n    }\n\n    public static function mb_strwidth($s, $encoding = null)\n    {\n        $encoding = self::getEncoding($encoding);\n\n        if ('UTF-8' !== $encoding) {\n            $s = iconv($encoding, 'UTF-8//IGNORE', $s);\n        }\n\n        $s = preg_replace('/[\\x{1100}-\\x{115F}\\x{2329}\\x{232A}\\x{2E80}-\\x{303E}\\x{3040}-\\x{A4CF}\\x{AC00}-\\x{D7A3}\\x{F900}-\\x{FAFF}\\x{FE10}-\\x{FE19}\\x{FE30}-\\x{FE6F}\\x{FF00}-\\x{FF60}\\x{FFE0}-\\x{FFE6}\\x{20000}-\\x{2FFFD}\\x{30000}-\\x{3FFFD}]/u', '', $s, -1, $wide);\n\n        return ($wide << 1) + iconv_strlen($s, 'UTF-8');\n    }\n\n    public static function mb_substr_count($haystack, $needle, $encoding = null)\n    {\n        return substr_count($haystack, $needle);\n    }\n\n    public static function mb_output_handler($contents, $status)\n    {\n        return $contents;\n    }\n\n    public static function mb_chr($code, $encoding = null)\n    {\n        if (0x80 > $code %= 0x200000) {\n            $s = \\chr($code);\n        } elseif (0x800 > $code) {\n            $s = \\chr(0xC0 | $code >> 6).\\chr(0x80 | $code & 0x3F);\n        } elseif (0x10000 > $code) {\n            $s = \\chr(0xE0 | $code >> 12).\\chr(0x80 | $code >> 6 & 0x3F).\\chr(0x80 | $code & 0x3F);\n        } else {\n            $s = \\chr(0xF0 | $code >> 18).\\chr(0x80 | $code >> 12 & 0x3F).\\chr(0x80 | $code >> 6 & 0x3F).\\chr(0x80 | $code & 0x3F);\n        }\n\n        if ('UTF-8' !== $encoding = self::getEncoding($encoding)) {\n            $s = mb_convert_encoding($s, $encoding, 'UTF-8');\n        }\n\n        return $s;\n    }\n\n    public static function mb_ord($s, $encoding = null)\n    {\n        if ('UTF-8' !== $encoding = self::getEncoding($encoding)) {\n            $s = mb_convert_encoding($s, 'UTF-8', $encoding);\n        }\n\n        if (1 === \\strlen($s)) {\n            return \\ord($s);\n        }\n\n        $code = ($s = unpack('C*', substr($s, 0, 4))) ? $s[1] : 0;\n        if (0xF0 <= $code) {\n            return (($code - 0xF0) << 18) + (($s[2] - 0x80) << 12) + (($s[3] - 0x80) << 6) + $s[4] - 0x80;\n        }\n        if (0xE0 <= $code) {\n            return (($code - 0xE0) << 12) + (($s[2] - 0x80) << 6) + $s[3] - 0x80;\n        }\n        if (0xC0 <= $code) {\n            return (($code - 0xC0) << 6) + $s[2] - 0x80;\n        }\n\n        return $code;\n    }\n\n    public static function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = \\STR_PAD_RIGHT, ?string $encoding = null): string\n    {\n        if (!\\in_array($pad_type, [\\STR_PAD_RIGHT, \\STR_PAD_LEFT, \\STR_PAD_BOTH], true)) {\n            throw new \\ValueError('mb_str_pad(): Argument #4 ($pad_type) must be STR_PAD_LEFT, STR_PAD_RIGHT, or STR_PAD_BOTH');\n        }\n\n        if (null === $encoding) {\n            $encoding = self::mb_internal_encoding();\n        } else {\n            self::assertEncoding($encoding, 'mb_str_pad(): Argument #5 ($encoding) must be a valid encoding, \"%s\" given');\n        }\n\n        if (self::mb_strlen($pad_string, $encoding) <= 0) {\n            throw new \\ValueError('mb_str_pad(): Argument #3 ($pad_string) must be a non-empty string');\n        }\n\n        $paddingRequired = $length - self::mb_strlen($string, $encoding);\n\n        if ($paddingRequired < 1) {\n            return $string;\n        }\n\n        switch ($pad_type) {\n            case \\STR_PAD_LEFT:\n                return self::mb_substr(str_repeat($pad_string, $paddingRequired), 0, $paddingRequired, $encoding).$string;\n            case \\STR_PAD_RIGHT:\n                return $string.self::mb_substr(str_repeat($pad_string, $paddingRequired), 0, $paddingRequired, $encoding);\n            default:\n                $leftPaddingLength = floor($paddingRequired / 2);\n                $rightPaddingLength = $paddingRequired - $leftPaddingLength;\n\n                return self::mb_substr(str_repeat($pad_string, $leftPaddingLength), 0, $leftPaddingLength, $encoding).$string.self::mb_substr(str_repeat($pad_string, $rightPaddingLength), 0, $rightPaddingLength, $encoding);\n        }\n    }\n\n    public static function mb_ucfirst(string $string, ?string $encoding = null): string\n    {\n        if (null === $encoding) {\n            $encoding = self::mb_internal_encoding();\n        } else {\n            self::assertEncoding($encoding, 'mb_ucfirst(): Argument #2 ($encoding) must be a valid encoding, \"%s\" given');\n        }\n\n        $firstChar = mb_substr($string, 0, 1, $encoding);\n        $firstChar = mb_convert_case($firstChar, \\MB_CASE_TITLE, $encoding);\n\n        return $firstChar.mb_substr($string, 1, null, $encoding);\n    }\n\n    public static function mb_lcfirst(string $string, ?string $encoding = null): string\n    {\n        if (null === $encoding) {\n            $encoding = self::mb_internal_encoding();\n        } else {\n            self::assertEncoding($encoding, 'mb_lcfirst(): Argument #2 ($encoding) must be a valid encoding, \"%s\" given');\n        }\n\n        $firstChar = mb_substr($string, 0, 1, $encoding);\n        $firstChar = mb_convert_case($firstChar, \\MB_CASE_LOWER, $encoding);\n\n        return $firstChar.mb_substr($string, 1, null, $encoding);\n    }\n\n    private static function getSubpart($pos, $part, $haystack, $encoding)\n    {\n        if (false === $pos) {\n            return false;\n        }\n        if ($part) {\n            return self::mb_substr($haystack, 0, $pos, $encoding);\n        }\n\n        return self::mb_substr($haystack, $pos, null, $encoding);\n    }\n\n    private static function html_encoding_callback(array $m)\n    {\n        $i = 1;\n        $entities = '';\n        $m = unpack('C*', htmlentities($m[0], \\ENT_COMPAT, 'UTF-8'));\n\n        while (isset($m[$i])) {\n            if (0x80 > $m[$i]) {\n                $entities .= \\chr($m[$i++]);\n                continue;\n            }\n            if (0xF0 <= $m[$i]) {\n                $c = (($m[$i++] - 0xF0) << 18) + (($m[$i++] - 0x80) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80;\n            } elseif (0xE0 <= $m[$i]) {\n                $c = (($m[$i++] - 0xE0) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80;\n            } else {\n                $c = (($m[$i++] - 0xC0) << 6) + $m[$i++] - 0x80;\n            }\n\n            $entities .= '&#'.$c.';';\n        }\n\n        return $entities;\n    }\n\n    private static function title_case(array $s)\n    {\n        return self::mb_convert_case($s[1], \\MB_CASE_UPPER, 'UTF-8').self::mb_convert_case($s[2], \\MB_CASE_LOWER, 'UTF-8');\n    }\n\n    private static function getData($file)\n    {\n        if (file_exists($file = __DIR__.'/Resources/unidata/'.$file.'.php')) {\n            return require $file;\n        }\n\n        return false;\n    }\n\n    private static function getEncoding($encoding)\n    {\n        if (null === $encoding) {\n            return self::$internalEncoding;\n        }\n\n        if ('UTF-8' === $encoding) {\n            return 'UTF-8';\n        }\n\n        $encoding = strtoupper($encoding);\n\n        if ('8BIT' === $encoding || 'BINARY' === $encoding) {\n            return 'CP850';\n        }\n\n        if ('UTF8' === $encoding) {\n            return 'UTF-8';\n        }\n\n        return $encoding;\n    }\n\n    public static function mb_trim(string $string, ?string $characters = null, ?string $encoding = null): string\n    {\n        return self::mb_internal_trim('{^[%s]+|[%1$s]+$}Du', $string, $characters, $encoding, __FUNCTION__);\n    }\n\n    public static function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null): string\n    {\n        return self::mb_internal_trim('{^[%s]+}Du', $string, $characters, $encoding, __FUNCTION__);\n    }\n\n    public static function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null): string\n    {\n        return self::mb_internal_trim('{[%s]+$}Du', $string, $characters, $encoding, __FUNCTION__);\n    }\n\n    private static function mb_internal_trim(string $regex, string $string, ?string $characters, ?string $encoding, string $function): string\n    {\n        if (null === $encoding) {\n            $encoding = self::mb_internal_encoding();\n        } else {\n            self::assertEncoding($encoding, $function.'(): Argument #3 ($encoding) must be a valid encoding, \"%s\" given');\n        }\n\n        if ('' === $characters) {\n            return null === $encoding ? $string : self::mb_convert_encoding($string, $encoding);\n        }\n\n        if ('UTF-8' === $encoding) {\n            $encoding = null;\n            if (!preg_match('//u', $string)) {\n                $string = @iconv('UTF-8', 'UTF-8//IGNORE', $string);\n            }\n            if (null !== $characters && !preg_match('//u', $characters)) {\n                $characters = @iconv('UTF-8', 'UTF-8//IGNORE', $characters);\n            }\n        } else {\n            $string = iconv($encoding, 'UTF-8//IGNORE', $string);\n\n            if (null !== $characters) {\n                $characters = iconv($encoding, 'UTF-8//IGNORE', $characters);\n            }\n        }\n\n        if (null === $characters) {\n            $characters = \"\\\\0 \\f\\n\\r\\t\\v\\u{00A0}\\u{1680}\\u{2000}\\u{2001}\\u{2002}\\u{2003}\\u{2004}\\u{2005}\\u{2006}\\u{2007}\\u{2008}\\u{2009}\\u{200A}\\u{2028}\\u{2029}\\u{202F}\\u{205F}\\u{3000}\\u{0085}\\u{180E}\";\n        } else {\n            $characters = preg_quote($characters);\n        }\n\n        $string = preg_replace(sprintf($regex, $characters), '', $string);\n\n        if (null === $encoding) {\n            return $string;\n        }\n\n        return iconv('UTF-8', $encoding.'//IGNORE', $string);\n    }\n\n    private static function assertEncoding(string $encoding, string $errorFormat): void\n    {\n        try {\n            $validEncoding = @self::mb_check_encoding('', $encoding);\n        } catch (\\ValueError $e) {\n            throw new \\ValueError(sprintf($errorFormat, $encoding));\n        }\n\n        // BC for PHP 7.3 and lower\n        if (!$validEncoding) {\n            throw new \\ValueError(sprintf($errorFormat, $encoding));\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-mbstring/README.md",
    "content": "Symfony Polyfill / Mbstring\n===========================\n\nThis component provides a partial, native PHP implementation for the\n[Mbstring](https://php.net/mbstring) extension.\n\nMore information can be found in the\n[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md).\n\nLicense\n=======\n\nThis library is released under the [MIT license](LICENSE).\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-mbstring/Resources/unidata/caseFolding.php",
    "content": "<?php\n\nreturn [\n    'İ' => 'i̇',\n    'µ' => 'μ',\n    'ſ' => 's',\n    'ͅ' => 'ι',\n    'ς' => 'σ',\n    'ϐ' => 'β',\n    'ϑ' => 'θ',\n    'ϕ' => 'φ',\n    'ϖ' => 'π',\n    'ϰ' => 'κ',\n    'ϱ' => 'ρ',\n    'ϵ' => 'ε',\n    'ẛ' => 'ṡ',\n    'ι' => 'ι',\n    'ß' => 'ss',\n    'ŉ' => 'ʼn',\n    'ǰ' => 'ǰ',\n    'ΐ' => 'ΐ',\n    'ΰ' => 'ΰ',\n    'և' => 'եւ',\n    'ẖ' => 'ẖ',\n    'ẗ' => 'ẗ',\n    'ẘ' => 'ẘ',\n    'ẙ' => 'ẙ',\n    'ẚ' => 'aʾ',\n    'ẞ' => 'ss',\n    'ὐ' => 'ὐ',\n    'ὒ' => 'ὒ',\n    'ὔ' => 'ὔ',\n    'ὖ' => 'ὖ',\n    'ᾀ' => 'ἀι',\n    'ᾁ' => 'ἁι',\n    'ᾂ' => 'ἂι',\n    'ᾃ' => 'ἃι',\n    'ᾄ' => 'ἄι',\n    'ᾅ' => 'ἅι',\n    'ᾆ' => 'ἆι',\n    'ᾇ' => 'ἇι',\n    'ᾈ' => 'ἀι',\n    'ᾉ' => 'ἁι',\n    'ᾊ' => 'ἂι',\n    'ᾋ' => 'ἃι',\n    'ᾌ' => 'ἄι',\n    'ᾍ' => 'ἅι',\n    'ᾎ' => 'ἆι',\n    'ᾏ' => 'ἇι',\n    'ᾐ' => 'ἠι',\n    'ᾑ' => 'ἡι',\n    'ᾒ' => 'ἢι',\n    'ᾓ' => 'ἣι',\n    'ᾔ' => 'ἤι',\n    'ᾕ' => 'ἥι',\n    'ᾖ' => 'ἦι',\n    'ᾗ' => 'ἧι',\n    'ᾘ' => 'ἠι',\n    'ᾙ' => 'ἡι',\n    'ᾚ' => 'ἢι',\n    'ᾛ' => 'ἣι',\n    'ᾜ' => 'ἤι',\n    'ᾝ' => 'ἥι',\n    'ᾞ' => 'ἦι',\n    'ᾟ' => 'ἧι',\n    'ᾠ' => 'ὠι',\n    'ᾡ' => 'ὡι',\n    'ᾢ' => 'ὢι',\n    'ᾣ' => 'ὣι',\n    'ᾤ' => 'ὤι',\n    'ᾥ' => 'ὥι',\n    'ᾦ' => 'ὦι',\n    'ᾧ' => 'ὧι',\n    'ᾨ' => 'ὠι',\n    'ᾩ' => 'ὡι',\n    'ᾪ' => 'ὢι',\n    'ᾫ' => 'ὣι',\n    'ᾬ' => 'ὤι',\n    'ᾭ' => 'ὥι',\n    'ᾮ' => 'ὦι',\n    'ᾯ' => 'ὧι',\n    'ᾲ' => 'ὰι',\n    'ᾳ' => 'αι',\n    'ᾴ' => 'άι',\n    'ᾶ' => 'ᾶ',\n    'ᾷ' => 'ᾶι',\n    'ᾼ' => 'αι',\n    'ῂ' => 'ὴι',\n    'ῃ' => 'ηι',\n    'ῄ' => 'ήι',\n    'ῆ' => 'ῆ',\n    'ῇ' => 'ῆι',\n    'ῌ' => 'ηι',\n    'ῒ' => 'ῒ',\n    'ῖ' => 'ῖ',\n    'ῗ' => 'ῗ',\n    'ῢ' => 'ῢ',\n    'ῤ' => 'ῤ',\n    'ῦ' => 'ῦ',\n    'ῧ' => 'ῧ',\n    'ῲ' => 'ὼι',\n    'ῳ' => 'ωι',\n    'ῴ' => 'ώι',\n    'ῶ' => 'ῶ',\n    'ῷ' => 'ῶι',\n    'ῼ' => 'ωι',\n    'ﬀ' => 'ff',\n    'ﬁ' => 'fi',\n    'ﬂ' => 'fl',\n    'ﬃ' => 'ffi',\n    'ﬄ' => 'ffl',\n    'ﬅ' => 'st',\n    'ﬆ' => 'st',\n    'ﬓ' => 'մն',\n    'ﬔ' => 'մե',\n    'ﬕ' => 'մի',\n    'ﬖ' => 'վն',\n    'ﬗ' => 'մխ',\n];\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-mbstring/Resources/unidata/lowerCase.php",
    "content": "<?php\n\nreturn array (\n  'A' => 'a',\n  'B' => 'b',\n  'C' => 'c',\n  'D' => 'd',\n  'E' => 'e',\n  'F' => 'f',\n  'G' => 'g',\n  'H' => 'h',\n  'I' => 'i',\n  'J' => 'j',\n  'K' => 'k',\n  'L' => 'l',\n  'M' => 'm',\n  'N' => 'n',\n  'O' => 'o',\n  'P' => 'p',\n  'Q' => 'q',\n  'R' => 'r',\n  'S' => 's',\n  'T' => 't',\n  'U' => 'u',\n  'V' => 'v',\n  'W' => 'w',\n  'X' => 'x',\n  'Y' => 'y',\n  'Z' => 'z',\n  'À' => 'à',\n  'Á' => 'á',\n  'Â' => 'â',\n  'Ã' => 'ã',\n  'Ä' => 'ä',\n  'Å' => 'å',\n  'Æ' => 'æ',\n  'Ç' => 'ç',\n  'È' => 'è',\n  'É' => 'é',\n  'Ê' => 'ê',\n  'Ë' => 'ë',\n  'Ì' => 'ì',\n  'Í' => 'í',\n  'Î' => 'î',\n  'Ï' => 'ï',\n  'Ð' => 'ð',\n  'Ñ' => 'ñ',\n  'Ò' => 'ò',\n  'Ó' => 'ó',\n  'Ô' => 'ô',\n  'Õ' => 'õ',\n  'Ö' => 'ö',\n  'Ø' => 'ø',\n  'Ù' => 'ù',\n  'Ú' => 'ú',\n  'Û' => 'û',\n  'Ü' => 'ü',\n  'Ý' => 'ý',\n  'Þ' => 'þ',\n  'Ā' => 'ā',\n  'Ă' => 'ă',\n  'Ą' => 'ą',\n  'Ć' => 'ć',\n  'Ĉ' => 'ĉ',\n  'Ċ' => 'ċ',\n  'Č' => 'č',\n  'Ď' => 'ď',\n  'Đ' => 'đ',\n  'Ē' => 'ē',\n  'Ĕ' => 'ĕ',\n  'Ė' => 'ė',\n  'Ę' => 'ę',\n  'Ě' => 'ě',\n  'Ĝ' => 'ĝ',\n  'Ğ' => 'ğ',\n  'Ġ' => 'ġ',\n  'Ģ' => 'ģ',\n  'Ĥ' => 'ĥ',\n  'Ħ' => 'ħ',\n  'Ĩ' => 'ĩ',\n  'Ī' => 'ī',\n  'Ĭ' => 'ĭ',\n  'Į' => 'į',\n  'İ' => 'i̇',\n  'Ĳ' => 'ĳ',\n  'Ĵ' => 'ĵ',\n  'Ķ' => 'ķ',\n  'Ĺ' => 'ĺ',\n  'Ļ' => 'ļ',\n  'Ľ' => 'ľ',\n  'Ŀ' => 'ŀ',\n  'Ł' => 'ł',\n  'Ń' => 'ń',\n  'Ņ' => 'ņ',\n  'Ň' => 'ň',\n  'Ŋ' => 'ŋ',\n  'Ō' => 'ō',\n  'Ŏ' => 'ŏ',\n  'Ő' => 'ő',\n  'Œ' => 'œ',\n  'Ŕ' => 'ŕ',\n  'Ŗ' => 'ŗ',\n  'Ř' => 'ř',\n  'Ś' => 'ś',\n  'Ŝ' => 'ŝ',\n  'Ş' => 'ş',\n  'Š' => 'š',\n  'Ţ' => 'ţ',\n  'Ť' => 'ť',\n  'Ŧ' => 'ŧ',\n  'Ũ' => 'ũ',\n  'Ū' => 'ū',\n  'Ŭ' => 'ŭ',\n  'Ů' => 'ů',\n  'Ű' => 'ű',\n  'Ų' => 'ų',\n  'Ŵ' => 'ŵ',\n  'Ŷ' => 'ŷ',\n  'Ÿ' => 'ÿ',\n  'Ź' => 'ź',\n  'Ż' => 'ż',\n  'Ž' => 'ž',\n  'Ɓ' => 'ɓ',\n  'Ƃ' => 'ƃ',\n  'Ƅ' => 'ƅ',\n  'Ɔ' => 'ɔ',\n  'Ƈ' => 'ƈ',\n  'Ɖ' => 'ɖ',\n  'Ɗ' => 'ɗ',\n  'Ƌ' => 'ƌ',\n  'Ǝ' => 'ǝ',\n  'Ə' => 'ə',\n  'Ɛ' => 'ɛ',\n  'Ƒ' => 'ƒ',\n  'Ɠ' => 'ɠ',\n  'Ɣ' => 'ɣ',\n  'Ɩ' => 'ɩ',\n  'Ɨ' => 'ɨ',\n  'Ƙ' => 'ƙ',\n  'Ɯ' => 'ɯ',\n  'Ɲ' => 'ɲ',\n  'Ɵ' => 'ɵ',\n  'Ơ' => 'ơ',\n  'Ƣ' => 'ƣ',\n  'Ƥ' => 'ƥ',\n  'Ʀ' => 'ʀ',\n  'Ƨ' => 'ƨ',\n  'Ʃ' => 'ʃ',\n  'Ƭ' => 'ƭ',\n  'Ʈ' => 'ʈ',\n  'Ư' => 'ư',\n  'Ʊ' => 'ʊ',\n  'Ʋ' => 'ʋ',\n  'Ƴ' => 'ƴ',\n  'Ƶ' => 'ƶ',\n  'Ʒ' => 'ʒ',\n  'Ƹ' => 'ƹ',\n  'Ƽ' => 'ƽ',\n  'Ǆ' => 'ǆ',\n  'ǅ' => 'ǆ',\n  'Ǉ' => 'ǉ',\n  'ǈ' => 'ǉ',\n  'Ǌ' => 'ǌ',\n  'ǋ' => 'ǌ',\n  'Ǎ' => 'ǎ',\n  'Ǐ' => 'ǐ',\n  'Ǒ' => 'ǒ',\n  'Ǔ' => 'ǔ',\n  'Ǖ' => 'ǖ',\n  'Ǘ' => 'ǘ',\n  'Ǚ' => 'ǚ',\n  'Ǜ' => 'ǜ',\n  'Ǟ' => 'ǟ',\n  'Ǡ' => 'ǡ',\n  'Ǣ' => 'ǣ',\n  'Ǥ' => 'ǥ',\n  'Ǧ' => 'ǧ',\n  'Ǩ' => 'ǩ',\n  'Ǫ' => 'ǫ',\n  'Ǭ' => 'ǭ',\n  'Ǯ' => 'ǯ',\n  'Ǳ' => 'ǳ',\n  'ǲ' => 'ǳ',\n  'Ǵ' => 'ǵ',\n  'Ƕ' => 'ƕ',\n  'Ƿ' => 'ƿ',\n  'Ǹ' => 'ǹ',\n  'Ǻ' => 'ǻ',\n  'Ǽ' => 'ǽ',\n  'Ǿ' => 'ǿ',\n  'Ȁ' => 'ȁ',\n  'Ȃ' => 'ȃ',\n  'Ȅ' => 'ȅ',\n  'Ȇ' => 'ȇ',\n  'Ȉ' => 'ȉ',\n  'Ȋ' => 'ȋ',\n  'Ȍ' => 'ȍ',\n  'Ȏ' => 'ȏ',\n  'Ȑ' => 'ȑ',\n  'Ȓ' => 'ȓ',\n  'Ȕ' => 'ȕ',\n  'Ȗ' => 'ȗ',\n  'Ș' => 'ș',\n  'Ț' => 'ț',\n  'Ȝ' => 'ȝ',\n  'Ȟ' => 'ȟ',\n  'Ƞ' => 'ƞ',\n  'Ȣ' => 'ȣ',\n  'Ȥ' => 'ȥ',\n  'Ȧ' => 'ȧ',\n  'Ȩ' => 'ȩ',\n  'Ȫ' => 'ȫ',\n  'Ȭ' => 'ȭ',\n  'Ȯ' => 'ȯ',\n  'Ȱ' => 'ȱ',\n  'Ȳ' => 'ȳ',\n  'Ⱥ' => 'ⱥ',\n  'Ȼ' => 'ȼ',\n  'Ƚ' => 'ƚ',\n  'Ⱦ' => 'ⱦ',\n  'Ɂ' => 'ɂ',\n  'Ƀ' => 'ƀ',\n  'Ʉ' => 'ʉ',\n  'Ʌ' => 'ʌ',\n  'Ɇ' => 'ɇ',\n  'Ɉ' => 'ɉ',\n  'Ɋ' => 'ɋ',\n  'Ɍ' => 'ɍ',\n  'Ɏ' => 'ɏ',\n  'Ͱ' => 'ͱ',\n  'Ͳ' => 'ͳ',\n  'Ͷ' => 'ͷ',\n  'Ϳ' => 'ϳ',\n  'Ά' => 'ά',\n  'Έ' => 'έ',\n  'Ή' => 'ή',\n  'Ί' => 'ί',\n  'Ό' => 'ό',\n  'Ύ' => 'ύ',\n  'Ώ' => 'ώ',\n  'Α' => 'α',\n  'Β' => 'β',\n  'Γ' => 'γ',\n  'Δ' => 'δ',\n  'Ε' => 'ε',\n  'Ζ' => 'ζ',\n  'Η' => 'η',\n  'Θ' => 'θ',\n  'Ι' => 'ι',\n  'Κ' => 'κ',\n  'Λ' => 'λ',\n  'Μ' => 'μ',\n  'Ν' => 'ν',\n  'Ξ' => 'ξ',\n  'Ο' => 'ο',\n  'Π' => 'π',\n  'Ρ' => 'ρ',\n  'Σ' => 'σ',\n  'Τ' => 'τ',\n  'Υ' => 'υ',\n  'Φ' => 'φ',\n  'Χ' => 'χ',\n  'Ψ' => 'ψ',\n  'Ω' => 'ω',\n  'Ϊ' => 'ϊ',\n  'Ϋ' => 'ϋ',\n  'Ϗ' => 'ϗ',\n  'Ϙ' => 'ϙ',\n  'Ϛ' => 'ϛ',\n  'Ϝ' => 'ϝ',\n  'Ϟ' => 'ϟ',\n  'Ϡ' => 'ϡ',\n  'Ϣ' => 'ϣ',\n  'Ϥ' => 'ϥ',\n  'Ϧ' => 'ϧ',\n  'Ϩ' => 'ϩ',\n  'Ϫ' => 'ϫ',\n  'Ϭ' => 'ϭ',\n  'Ϯ' => 'ϯ',\n  'ϴ' => 'θ',\n  'Ϸ' => 'ϸ',\n  'Ϲ' => 'ϲ',\n  'Ϻ' => 'ϻ',\n  'Ͻ' => 'ͻ',\n  'Ͼ' => 'ͼ',\n  'Ͽ' => 'ͽ',\n  'Ѐ' => 'ѐ',\n  'Ё' => 'ё',\n  'Ђ' => 'ђ',\n  'Ѓ' => 'ѓ',\n  'Є' => 'є',\n  'Ѕ' => 'ѕ',\n  'І' => 'і',\n  'Ї' => 'ї',\n  'Ј' => 'ј',\n  'Љ' => 'љ',\n  'Њ' => 'њ',\n  'Ћ' => 'ћ',\n  'Ќ' => 'ќ',\n  'Ѝ' => 'ѝ',\n  'Ў' => 'ў',\n  'Џ' => 'џ',\n  'А' => 'а',\n  'Б' => 'б',\n  'В' => 'в',\n  'Г' => 'г',\n  'Д' => 'д',\n  'Е' => 'е',\n  'Ж' => 'ж',\n  'З' => 'з',\n  'И' => 'и',\n  'Й' => 'й',\n  'К' => 'к',\n  'Л' => 'л',\n  'М' => 'м',\n  'Н' => 'н',\n  'О' => 'о',\n  'П' => 'п',\n  'Р' => 'р',\n  'С' => 'с',\n  'Т' => 'т',\n  'У' => 'у',\n  'Ф' => 'ф',\n  'Х' => 'х',\n  'Ц' => 'ц',\n  'Ч' => 'ч',\n  'Ш' => 'ш',\n  'Щ' => 'щ',\n  'Ъ' => 'ъ',\n  'Ы' => 'ы',\n  'Ь' => 'ь',\n  'Э' => 'э',\n  'Ю' => 'ю',\n  'Я' => 'я',\n  'Ѡ' => 'ѡ',\n  'Ѣ' => 'ѣ',\n  'Ѥ' => 'ѥ',\n  'Ѧ' => 'ѧ',\n  'Ѩ' => 'ѩ',\n  'Ѫ' => 'ѫ',\n  'Ѭ' => 'ѭ',\n  'Ѯ' => 'ѯ',\n  'Ѱ' => 'ѱ',\n  'Ѳ' => 'ѳ',\n  'Ѵ' => 'ѵ',\n  'Ѷ' => 'ѷ',\n  'Ѹ' => 'ѹ',\n  'Ѻ' => 'ѻ',\n  'Ѽ' => 'ѽ',\n  'Ѿ' => 'ѿ',\n  'Ҁ' => 'ҁ',\n  'Ҋ' => 'ҋ',\n  'Ҍ' => 'ҍ',\n  'Ҏ' => 'ҏ',\n  'Ґ' => 'ґ',\n  'Ғ' => 'ғ',\n  'Ҕ' => 'ҕ',\n  'Җ' => 'җ',\n  'Ҙ' => 'ҙ',\n  'Қ' => 'қ',\n  'Ҝ' => 'ҝ',\n  'Ҟ' => 'ҟ',\n  'Ҡ' => 'ҡ',\n  'Ң' => 'ң',\n  'Ҥ' => 'ҥ',\n  'Ҧ' => 'ҧ',\n  'Ҩ' => 'ҩ',\n  'Ҫ' => 'ҫ',\n  'Ҭ' => 'ҭ',\n  'Ү' => 'ү',\n  'Ұ' => 'ұ',\n  'Ҳ' => 'ҳ',\n  'Ҵ' => 'ҵ',\n  'Ҷ' => 'ҷ',\n  'Ҹ' => 'ҹ',\n  'Һ' => 'һ',\n  'Ҽ' => 'ҽ',\n  'Ҿ' => 'ҿ',\n  'Ӏ' => 'ӏ',\n  'Ӂ' => 'ӂ',\n  'Ӄ' => 'ӄ',\n  'Ӆ' => 'ӆ',\n  'Ӈ' => 'ӈ',\n  'Ӊ' => 'ӊ',\n  'Ӌ' => 'ӌ',\n  'Ӎ' => 'ӎ',\n  'Ӑ' => 'ӑ',\n  'Ӓ' => 'ӓ',\n  'Ӕ' => 'ӕ',\n  'Ӗ' => 'ӗ',\n  'Ә' => 'ә',\n  'Ӛ' => 'ӛ',\n  'Ӝ' => 'ӝ',\n  'Ӟ' => 'ӟ',\n  'Ӡ' => 'ӡ',\n  'Ӣ' => 'ӣ',\n  'Ӥ' => 'ӥ',\n  'Ӧ' => 'ӧ',\n  'Ө' => 'ө',\n  'Ӫ' => 'ӫ',\n  'Ӭ' => 'ӭ',\n  'Ӯ' => 'ӯ',\n  'Ӱ' => 'ӱ',\n  'Ӳ' => 'ӳ',\n  'Ӵ' => 'ӵ',\n  'Ӷ' => 'ӷ',\n  'Ӹ' => 'ӹ',\n  'Ӻ' => 'ӻ',\n  'Ӽ' => 'ӽ',\n  'Ӿ' => 'ӿ',\n  'Ԁ' => 'ԁ',\n  'Ԃ' => 'ԃ',\n  'Ԅ' => 'ԅ',\n  'Ԇ' => 'ԇ',\n  'Ԉ' => 'ԉ',\n  'Ԋ' => 'ԋ',\n  'Ԍ' => 'ԍ',\n  'Ԏ' => 'ԏ',\n  'Ԑ' => 'ԑ',\n  'Ԓ' => 'ԓ',\n  'Ԕ' => 'ԕ',\n  'Ԗ' => 'ԗ',\n  'Ԙ' => 'ԙ',\n  'Ԛ' => 'ԛ',\n  'Ԝ' => 'ԝ',\n  'Ԟ' => 'ԟ',\n  'Ԡ' => 'ԡ',\n  'Ԣ' => 'ԣ',\n  'Ԥ' => 'ԥ',\n  'Ԧ' => 'ԧ',\n  'Ԩ' => 'ԩ',\n  'Ԫ' => 'ԫ',\n  'Ԭ' => 'ԭ',\n  'Ԯ' => 'ԯ',\n  'Ա' => 'ա',\n  'Բ' => 'բ',\n  'Գ' => 'գ',\n  'Դ' => 'դ',\n  'Ե' => 'ե',\n  'Զ' => 'զ',\n  'Է' => 'է',\n  'Ը' => 'ը',\n  'Թ' => 'թ',\n  'Ժ' => 'ժ',\n  'Ի' => 'ի',\n  'Լ' => 'լ',\n  'Խ' => 'խ',\n  'Ծ' => 'ծ',\n  'Կ' => 'կ',\n  'Հ' => 'հ',\n  'Ձ' => 'ձ',\n  'Ղ' => 'ղ',\n  'Ճ' => 'ճ',\n  'Մ' => 'մ',\n  'Յ' => 'յ',\n  'Ն' => 'ն',\n  'Շ' => 'շ',\n  'Ո' => 'ո',\n  'Չ' => 'չ',\n  'Պ' => 'պ',\n  'Ջ' => 'ջ',\n  'Ռ' => 'ռ',\n  'Ս' => 'ս',\n  'Վ' => 'վ',\n  'Տ' => 'տ',\n  'Ր' => 'ր',\n  'Ց' => 'ց',\n  'Ւ' => 'ւ',\n  'Փ' => 'փ',\n  'Ք' => 'ք',\n  'Օ' => 'օ',\n  'Ֆ' => 'ֆ',\n  'Ⴀ' => 'ⴀ',\n  'Ⴁ' => 'ⴁ',\n  'Ⴂ' => 'ⴂ',\n  'Ⴃ' => 'ⴃ',\n  'Ⴄ' => 'ⴄ',\n  'Ⴅ' => 'ⴅ',\n  'Ⴆ' => 'ⴆ',\n  'Ⴇ' => 'ⴇ',\n  'Ⴈ' => 'ⴈ',\n  'Ⴉ' => 'ⴉ',\n  'Ⴊ' => 'ⴊ',\n  'Ⴋ' => 'ⴋ',\n  'Ⴌ' => 'ⴌ',\n  'Ⴍ' => 'ⴍ',\n  'Ⴎ' => 'ⴎ',\n  'Ⴏ' => 'ⴏ',\n  'Ⴐ' => 'ⴐ',\n  'Ⴑ' => 'ⴑ',\n  'Ⴒ' => 'ⴒ',\n  'Ⴓ' => 'ⴓ',\n  'Ⴔ' => 'ⴔ',\n  'Ⴕ' => 'ⴕ',\n  'Ⴖ' => 'ⴖ',\n  'Ⴗ' => 'ⴗ',\n  'Ⴘ' => 'ⴘ',\n  'Ⴙ' => 'ⴙ',\n  'Ⴚ' => 'ⴚ',\n  'Ⴛ' => 'ⴛ',\n  'Ⴜ' => 'ⴜ',\n  'Ⴝ' => 'ⴝ',\n  'Ⴞ' => 'ⴞ',\n  'Ⴟ' => 'ⴟ',\n  'Ⴠ' => 'ⴠ',\n  'Ⴡ' => 'ⴡ',\n  'Ⴢ' => 'ⴢ',\n  'Ⴣ' => 'ⴣ',\n  'Ⴤ' => 'ⴤ',\n  'Ⴥ' => 'ⴥ',\n  'Ⴧ' => 'ⴧ',\n  'Ⴭ' => 'ⴭ',\n  'Ꭰ' => 'ꭰ',\n  'Ꭱ' => 'ꭱ',\n  'Ꭲ' => 'ꭲ',\n  'Ꭳ' => 'ꭳ',\n  'Ꭴ' => 'ꭴ',\n  'Ꭵ' => 'ꭵ',\n  'Ꭶ' => 'ꭶ',\n  'Ꭷ' => 'ꭷ',\n  'Ꭸ' => 'ꭸ',\n  'Ꭹ' => 'ꭹ',\n  'Ꭺ' => 'ꭺ',\n  'Ꭻ' => 'ꭻ',\n  'Ꭼ' => 'ꭼ',\n  'Ꭽ' => 'ꭽ',\n  'Ꭾ' => 'ꭾ',\n  'Ꭿ' => 'ꭿ',\n  'Ꮀ' => 'ꮀ',\n  'Ꮁ' => 'ꮁ',\n  'Ꮂ' => 'ꮂ',\n  'Ꮃ' => 'ꮃ',\n  'Ꮄ' => 'ꮄ',\n  'Ꮅ' => 'ꮅ',\n  'Ꮆ' => 'ꮆ',\n  'Ꮇ' => 'ꮇ',\n  'Ꮈ' => 'ꮈ',\n  'Ꮉ' => 'ꮉ',\n  'Ꮊ' => 'ꮊ',\n  'Ꮋ' => 'ꮋ',\n  'Ꮌ' => 'ꮌ',\n  'Ꮍ' => 'ꮍ',\n  'Ꮎ' => 'ꮎ',\n  'Ꮏ' => 'ꮏ',\n  'Ꮐ' => 'ꮐ',\n  'Ꮑ' => 'ꮑ',\n  'Ꮒ' => 'ꮒ',\n  'Ꮓ' => 'ꮓ',\n  'Ꮔ' => 'ꮔ',\n  'Ꮕ' => 'ꮕ',\n  'Ꮖ' => 'ꮖ',\n  'Ꮗ' => 'ꮗ',\n  'Ꮘ' => 'ꮘ',\n  'Ꮙ' => 'ꮙ',\n  'Ꮚ' => 'ꮚ',\n  'Ꮛ' => 'ꮛ',\n  'Ꮜ' => 'ꮜ',\n  'Ꮝ' => 'ꮝ',\n  'Ꮞ' => 'ꮞ',\n  'Ꮟ' => 'ꮟ',\n  'Ꮠ' => 'ꮠ',\n  'Ꮡ' => 'ꮡ',\n  'Ꮢ' => 'ꮢ',\n  'Ꮣ' => 'ꮣ',\n  'Ꮤ' => 'ꮤ',\n  'Ꮥ' => 'ꮥ',\n  'Ꮦ' => 'ꮦ',\n  'Ꮧ' => 'ꮧ',\n  'Ꮨ' => 'ꮨ',\n  'Ꮩ' => 'ꮩ',\n  'Ꮪ' => 'ꮪ',\n  'Ꮫ' => 'ꮫ',\n  'Ꮬ' => 'ꮬ',\n  'Ꮭ' => 'ꮭ',\n  'Ꮮ' => 'ꮮ',\n  'Ꮯ' => 'ꮯ',\n  'Ꮰ' => 'ꮰ',\n  'Ꮱ' => 'ꮱ',\n  'Ꮲ' => 'ꮲ',\n  'Ꮳ' => 'ꮳ',\n  'Ꮴ' => 'ꮴ',\n  'Ꮵ' => 'ꮵ',\n  'Ꮶ' => 'ꮶ',\n  'Ꮷ' => 'ꮷ',\n  'Ꮸ' => 'ꮸ',\n  'Ꮹ' => 'ꮹ',\n  'Ꮺ' => 'ꮺ',\n  'Ꮻ' => 'ꮻ',\n  'Ꮼ' => 'ꮼ',\n  'Ꮽ' => 'ꮽ',\n  'Ꮾ' => 'ꮾ',\n  'Ꮿ' => 'ꮿ',\n  'Ᏸ' => 'ᏸ',\n  'Ᏹ' => 'ᏹ',\n  'Ᏺ' => 'ᏺ',\n  'Ᏻ' => 'ᏻ',\n  'Ᏼ' => 'ᏼ',\n  'Ᏽ' => 'ᏽ',\n  'Ა' => 'ა',\n  'Ბ' => 'ბ',\n  'Გ' => 'გ',\n  'Დ' => 'დ',\n  'Ე' => 'ე',\n  'Ვ' => 'ვ',\n  'Ზ' => 'ზ',\n  'Თ' => 'თ',\n  'Ი' => 'ი',\n  'Კ' => 'კ',\n  'Ლ' => 'ლ',\n  'Მ' => 'მ',\n  'Ნ' => 'ნ',\n  'Ო' => 'ო',\n  'Პ' => 'პ',\n  'Ჟ' => 'ჟ',\n  'Რ' => 'რ',\n  'Ს' => 'ს',\n  'Ტ' => 'ტ',\n  'Უ' => 'უ',\n  'Ფ' => 'ფ',\n  'Ქ' => 'ქ',\n  'Ღ' => 'ღ',\n  'Ყ' => 'ყ',\n  'Შ' => 'შ',\n  'Ჩ' => 'ჩ',\n  'Ც' => 'ც',\n  'Ძ' => 'ძ',\n  'Წ' => 'წ',\n  'Ჭ' => 'ჭ',\n  'Ხ' => 'ხ',\n  'Ჯ' => 'ჯ',\n  'Ჰ' => 'ჰ',\n  'Ჱ' => 'ჱ',\n  'Ჲ' => 'ჲ',\n  'Ჳ' => 'ჳ',\n  'Ჴ' => 'ჴ',\n  'Ჵ' => 'ჵ',\n  'Ჶ' => 'ჶ',\n  'Ჷ' => 'ჷ',\n  'Ჸ' => 'ჸ',\n  'Ჹ' => 'ჹ',\n  'Ჺ' => 'ჺ',\n  'Ჽ' => 'ჽ',\n  'Ჾ' => 'ჾ',\n  'Ჿ' => 'ჿ',\n  'Ḁ' => 'ḁ',\n  'Ḃ' => 'ḃ',\n  'Ḅ' => 'ḅ',\n  'Ḇ' => 'ḇ',\n  'Ḉ' => 'ḉ',\n  'Ḋ' => 'ḋ',\n  'Ḍ' => 'ḍ',\n  'Ḏ' => 'ḏ',\n  'Ḑ' => 'ḑ',\n  'Ḓ' => 'ḓ',\n  'Ḕ' => 'ḕ',\n  'Ḗ' => 'ḗ',\n  'Ḙ' => 'ḙ',\n  'Ḛ' => 'ḛ',\n  'Ḝ' => 'ḝ',\n  'Ḟ' => 'ḟ',\n  'Ḡ' => 'ḡ',\n  'Ḣ' => 'ḣ',\n  'Ḥ' => 'ḥ',\n  'Ḧ' => 'ḧ',\n  'Ḩ' => 'ḩ',\n  'Ḫ' => 'ḫ',\n  'Ḭ' => 'ḭ',\n  'Ḯ' => 'ḯ',\n  'Ḱ' => 'ḱ',\n  'Ḳ' => 'ḳ',\n  'Ḵ' => 'ḵ',\n  'Ḷ' => 'ḷ',\n  'Ḹ' => 'ḹ',\n  'Ḻ' => 'ḻ',\n  'Ḽ' => 'ḽ',\n  'Ḿ' => 'ḿ',\n  'Ṁ' => 'ṁ',\n  'Ṃ' => 'ṃ',\n  'Ṅ' => 'ṅ',\n  'Ṇ' => 'ṇ',\n  'Ṉ' => 'ṉ',\n  'Ṋ' => 'ṋ',\n  'Ṍ' => 'ṍ',\n  'Ṏ' => 'ṏ',\n  'Ṑ' => 'ṑ',\n  'Ṓ' => 'ṓ',\n  'Ṕ' => 'ṕ',\n  'Ṗ' => 'ṗ',\n  'Ṙ' => 'ṙ',\n  'Ṛ' => 'ṛ',\n  'Ṝ' => 'ṝ',\n  'Ṟ' => 'ṟ',\n  'Ṡ' => 'ṡ',\n  'Ṣ' => 'ṣ',\n  'Ṥ' => 'ṥ',\n  'Ṧ' => 'ṧ',\n  'Ṩ' => 'ṩ',\n  'Ṫ' => 'ṫ',\n  'Ṭ' => 'ṭ',\n  'Ṯ' => 'ṯ',\n  'Ṱ' => 'ṱ',\n  'Ṳ' => 'ṳ',\n  'Ṵ' => 'ṵ',\n  'Ṷ' => 'ṷ',\n  'Ṹ' => 'ṹ',\n  'Ṻ' => 'ṻ',\n  'Ṽ' => 'ṽ',\n  'Ṿ' => 'ṿ',\n  'Ẁ' => 'ẁ',\n  'Ẃ' => 'ẃ',\n  'Ẅ' => 'ẅ',\n  'Ẇ' => 'ẇ',\n  'Ẉ' => 'ẉ',\n  'Ẋ' => 'ẋ',\n  'Ẍ' => 'ẍ',\n  'Ẏ' => 'ẏ',\n  'Ẑ' => 'ẑ',\n  'Ẓ' => 'ẓ',\n  'Ẕ' => 'ẕ',\n  'ẞ' => 'ß',\n  'Ạ' => 'ạ',\n  'Ả' => 'ả',\n  'Ấ' => 'ấ',\n  'Ầ' => 'ầ',\n  'Ẩ' => 'ẩ',\n  'Ẫ' => 'ẫ',\n  'Ậ' => 'ậ',\n  'Ắ' => 'ắ',\n  'Ằ' => 'ằ',\n  'Ẳ' => 'ẳ',\n  'Ẵ' => 'ẵ',\n  'Ặ' => 'ặ',\n  'Ẹ' => 'ẹ',\n  'Ẻ' => 'ẻ',\n  'Ẽ' => 'ẽ',\n  'Ế' => 'ế',\n  'Ề' => 'ề',\n  'Ể' => 'ể',\n  'Ễ' => 'ễ',\n  'Ệ' => 'ệ',\n  'Ỉ' => 'ỉ',\n  'Ị' => 'ị',\n  'Ọ' => 'ọ',\n  'Ỏ' => 'ỏ',\n  'Ố' => 'ố',\n  'Ồ' => 'ồ',\n  'Ổ' => 'ổ',\n  'Ỗ' => 'ỗ',\n  'Ộ' => 'ộ',\n  'Ớ' => 'ớ',\n  'Ờ' => 'ờ',\n  'Ở' => 'ở',\n  'Ỡ' => 'ỡ',\n  'Ợ' => 'ợ',\n  'Ụ' => 'ụ',\n  'Ủ' => 'ủ',\n  'Ứ' => 'ứ',\n  'Ừ' => 'ừ',\n  'Ử' => 'ử',\n  'Ữ' => 'ữ',\n  'Ự' => 'ự',\n  'Ỳ' => 'ỳ',\n  'Ỵ' => 'ỵ',\n  'Ỷ' => 'ỷ',\n  'Ỹ' => 'ỹ',\n  'Ỻ' => 'ỻ',\n  'Ỽ' => 'ỽ',\n  'Ỿ' => 'ỿ',\n  'Ἀ' => 'ἀ',\n  'Ἁ' => 'ἁ',\n  'Ἂ' => 'ἂ',\n  'Ἃ' => 'ἃ',\n  'Ἄ' => 'ἄ',\n  'Ἅ' => 'ἅ',\n  'Ἆ' => 'ἆ',\n  'Ἇ' => 'ἇ',\n  'Ἐ' => 'ἐ',\n  'Ἑ' => 'ἑ',\n  'Ἒ' => 'ἒ',\n  'Ἓ' => 'ἓ',\n  'Ἔ' => 'ἔ',\n  'Ἕ' => 'ἕ',\n  'Ἠ' => 'ἠ',\n  'Ἡ' => 'ἡ',\n  'Ἢ' => 'ἢ',\n  'Ἣ' => 'ἣ',\n  'Ἤ' => 'ἤ',\n  'Ἥ' => 'ἥ',\n  'Ἦ' => 'ἦ',\n  'Ἧ' => 'ἧ',\n  'Ἰ' => 'ἰ',\n  'Ἱ' => 'ἱ',\n  'Ἲ' => 'ἲ',\n  'Ἳ' => 'ἳ',\n  'Ἴ' => 'ἴ',\n  'Ἵ' => 'ἵ',\n  'Ἶ' => 'ἶ',\n  'Ἷ' => 'ἷ',\n  'Ὀ' => 'ὀ',\n  'Ὁ' => 'ὁ',\n  'Ὂ' => 'ὂ',\n  'Ὃ' => 'ὃ',\n  'Ὄ' => 'ὄ',\n  'Ὅ' => 'ὅ',\n  'Ὑ' => 'ὑ',\n  'Ὓ' => 'ὓ',\n  'Ὕ' => 'ὕ',\n  'Ὗ' => 'ὗ',\n  'Ὠ' => 'ὠ',\n  'Ὡ' => 'ὡ',\n  'Ὢ' => 'ὢ',\n  'Ὣ' => 'ὣ',\n  'Ὤ' => 'ὤ',\n  'Ὥ' => 'ὥ',\n  'Ὦ' => 'ὦ',\n  'Ὧ' => 'ὧ',\n  'ᾈ' => 'ᾀ',\n  'ᾉ' => 'ᾁ',\n  'ᾊ' => 'ᾂ',\n  'ᾋ' => 'ᾃ',\n  'ᾌ' => 'ᾄ',\n  'ᾍ' => 'ᾅ',\n  'ᾎ' => 'ᾆ',\n  'ᾏ' => 'ᾇ',\n  'ᾘ' => 'ᾐ',\n  'ᾙ' => 'ᾑ',\n  'ᾚ' => 'ᾒ',\n  'ᾛ' => 'ᾓ',\n  'ᾜ' => 'ᾔ',\n  'ᾝ' => 'ᾕ',\n  'ᾞ' => 'ᾖ',\n  'ᾟ' => 'ᾗ',\n  'ᾨ' => 'ᾠ',\n  'ᾩ' => 'ᾡ',\n  'ᾪ' => 'ᾢ',\n  'ᾫ' => 'ᾣ',\n  'ᾬ' => 'ᾤ',\n  'ᾭ' => 'ᾥ',\n  'ᾮ' => 'ᾦ',\n  'ᾯ' => 'ᾧ',\n  'Ᾰ' => 'ᾰ',\n  'Ᾱ' => 'ᾱ',\n  'Ὰ' => 'ὰ',\n  'Ά' => 'ά',\n  'ᾼ' => 'ᾳ',\n  'Ὲ' => 'ὲ',\n  'Έ' => 'έ',\n  'Ὴ' => 'ὴ',\n  'Ή' => 'ή',\n  'ῌ' => 'ῃ',\n  'Ῐ' => 'ῐ',\n  'Ῑ' => 'ῑ',\n  'Ὶ' => 'ὶ',\n  'Ί' => 'ί',\n  'Ῠ' => 'ῠ',\n  'Ῡ' => 'ῡ',\n  'Ὺ' => 'ὺ',\n  'Ύ' => 'ύ',\n  'Ῥ' => 'ῥ',\n  'Ὸ' => 'ὸ',\n  'Ό' => 'ό',\n  'Ὼ' => 'ὼ',\n  'Ώ' => 'ώ',\n  'ῼ' => 'ῳ',\n  'Ω' => 'ω',\n  'K' => 'k',\n  'Å' => 'å',\n  'Ⅎ' => 'ⅎ',\n  'Ⅰ' => 'ⅰ',\n  'Ⅱ' => 'ⅱ',\n  'Ⅲ' => 'ⅲ',\n  'Ⅳ' => 'ⅳ',\n  'Ⅴ' => 'ⅴ',\n  'Ⅵ' => 'ⅵ',\n  'Ⅶ' => 'ⅶ',\n  'Ⅷ' => 'ⅷ',\n  'Ⅸ' => 'ⅸ',\n  'Ⅹ' => 'ⅹ',\n  'Ⅺ' => 'ⅺ',\n  'Ⅻ' => 'ⅻ',\n  'Ⅼ' => 'ⅼ',\n  'Ⅽ' => 'ⅽ',\n  'Ⅾ' => 'ⅾ',\n  'Ⅿ' => 'ⅿ',\n  'Ↄ' => 'ↄ',\n  'Ⓐ' => 'ⓐ',\n  'Ⓑ' => 'ⓑ',\n  'Ⓒ' => 'ⓒ',\n  'Ⓓ' => 'ⓓ',\n  'Ⓔ' => 'ⓔ',\n  'Ⓕ' => 'ⓕ',\n  'Ⓖ' => 'ⓖ',\n  'Ⓗ' => 'ⓗ',\n  'Ⓘ' => 'ⓘ',\n  'Ⓙ' => 'ⓙ',\n  'Ⓚ' => 'ⓚ',\n  'Ⓛ' => 'ⓛ',\n  'Ⓜ' => 'ⓜ',\n  'Ⓝ' => 'ⓝ',\n  'Ⓞ' => 'ⓞ',\n  'Ⓟ' => 'ⓟ',\n  'Ⓠ' => 'ⓠ',\n  'Ⓡ' => 'ⓡ',\n  'Ⓢ' => 'ⓢ',\n  'Ⓣ' => 'ⓣ',\n  'Ⓤ' => 'ⓤ',\n  'Ⓥ' => 'ⓥ',\n  'Ⓦ' => 'ⓦ',\n  'Ⓧ' => 'ⓧ',\n  'Ⓨ' => 'ⓨ',\n  'Ⓩ' => 'ⓩ',\n  'Ⰰ' => 'ⰰ',\n  'Ⰱ' => 'ⰱ',\n  'Ⰲ' => 'ⰲ',\n  'Ⰳ' => 'ⰳ',\n  'Ⰴ' => 'ⰴ',\n  'Ⰵ' => 'ⰵ',\n  'Ⰶ' => 'ⰶ',\n  'Ⰷ' => 'ⰷ',\n  'Ⰸ' => 'ⰸ',\n  'Ⰹ' => 'ⰹ',\n  'Ⰺ' => 'ⰺ',\n  'Ⰻ' => 'ⰻ',\n  'Ⰼ' => 'ⰼ',\n  'Ⰽ' => 'ⰽ',\n  'Ⰾ' => 'ⰾ',\n  'Ⰿ' => 'ⰿ',\n  'Ⱀ' => 'ⱀ',\n  'Ⱁ' => 'ⱁ',\n  'Ⱂ' => 'ⱂ',\n  'Ⱃ' => 'ⱃ',\n  'Ⱄ' => 'ⱄ',\n  'Ⱅ' => 'ⱅ',\n  'Ⱆ' => 'ⱆ',\n  'Ⱇ' => 'ⱇ',\n  'Ⱈ' => 'ⱈ',\n  'Ⱉ' => 'ⱉ',\n  'Ⱊ' => 'ⱊ',\n  'Ⱋ' => 'ⱋ',\n  'Ⱌ' => 'ⱌ',\n  'Ⱍ' => 'ⱍ',\n  'Ⱎ' => 'ⱎ',\n  'Ⱏ' => 'ⱏ',\n  'Ⱐ' => 'ⱐ',\n  'Ⱑ' => 'ⱑ',\n  'Ⱒ' => 'ⱒ',\n  'Ⱓ' => 'ⱓ',\n  'Ⱔ' => 'ⱔ',\n  'Ⱕ' => 'ⱕ',\n  'Ⱖ' => 'ⱖ',\n  'Ⱗ' => 'ⱗ',\n  'Ⱘ' => 'ⱘ',\n  'Ⱙ' => 'ⱙ',\n  'Ⱚ' => 'ⱚ',\n  'Ⱛ' => 'ⱛ',\n  'Ⱜ' => 'ⱜ',\n  'Ⱝ' => 'ⱝ',\n  'Ⱞ' => 'ⱞ',\n  'Ⱡ' => 'ⱡ',\n  'Ɫ' => 'ɫ',\n  'Ᵽ' => 'ᵽ',\n  'Ɽ' => 'ɽ',\n  'Ⱨ' => 'ⱨ',\n  'Ⱪ' => 'ⱪ',\n  'Ⱬ' => 'ⱬ',\n  'Ɑ' => 'ɑ',\n  'Ɱ' => 'ɱ',\n  'Ɐ' => 'ɐ',\n  'Ɒ' => 'ɒ',\n  'Ⱳ' => 'ⱳ',\n  'Ⱶ' => 'ⱶ',\n  'Ȿ' => 'ȿ',\n  'Ɀ' => 'ɀ',\n  'Ⲁ' => 'ⲁ',\n  'Ⲃ' => 'ⲃ',\n  'Ⲅ' => 'ⲅ',\n  'Ⲇ' => 'ⲇ',\n  'Ⲉ' => 'ⲉ',\n  'Ⲋ' => 'ⲋ',\n  'Ⲍ' => 'ⲍ',\n  'Ⲏ' => 'ⲏ',\n  'Ⲑ' => 'ⲑ',\n  'Ⲓ' => 'ⲓ',\n  'Ⲕ' => 'ⲕ',\n  'Ⲗ' => 'ⲗ',\n  'Ⲙ' => 'ⲙ',\n  'Ⲛ' => 'ⲛ',\n  'Ⲝ' => 'ⲝ',\n  'Ⲟ' => 'ⲟ',\n  'Ⲡ' => 'ⲡ',\n  'Ⲣ' => 'ⲣ',\n  'Ⲥ' => 'ⲥ',\n  'Ⲧ' => 'ⲧ',\n  'Ⲩ' => 'ⲩ',\n  'Ⲫ' => 'ⲫ',\n  'Ⲭ' => 'ⲭ',\n  'Ⲯ' => 'ⲯ',\n  'Ⲱ' => 'ⲱ',\n  'Ⲳ' => 'ⲳ',\n  'Ⲵ' => 'ⲵ',\n  'Ⲷ' => 'ⲷ',\n  'Ⲹ' => 'ⲹ',\n  'Ⲻ' => 'ⲻ',\n  'Ⲽ' => 'ⲽ',\n  'Ⲿ' => 'ⲿ',\n  'Ⳁ' => 'ⳁ',\n  'Ⳃ' => 'ⳃ',\n  'Ⳅ' => 'ⳅ',\n  'Ⳇ' => 'ⳇ',\n  'Ⳉ' => 'ⳉ',\n  'Ⳋ' => 'ⳋ',\n  'Ⳍ' => 'ⳍ',\n  'Ⳏ' => 'ⳏ',\n  'Ⳑ' => 'ⳑ',\n  'Ⳓ' => 'ⳓ',\n  'Ⳕ' => 'ⳕ',\n  'Ⳗ' => 'ⳗ',\n  'Ⳙ' => 'ⳙ',\n  'Ⳛ' => 'ⳛ',\n  'Ⳝ' => 'ⳝ',\n  'Ⳟ' => 'ⳟ',\n  'Ⳡ' => 'ⳡ',\n  'Ⳣ' => 'ⳣ',\n  'Ⳬ' => 'ⳬ',\n  'Ⳮ' => 'ⳮ',\n  'Ⳳ' => 'ⳳ',\n  'Ꙁ' => 'ꙁ',\n  'Ꙃ' => 'ꙃ',\n  'Ꙅ' => 'ꙅ',\n  'Ꙇ' => 'ꙇ',\n  'Ꙉ' => 'ꙉ',\n  'Ꙋ' => 'ꙋ',\n  'Ꙍ' => 'ꙍ',\n  'Ꙏ' => 'ꙏ',\n  'Ꙑ' => 'ꙑ',\n  'Ꙓ' => 'ꙓ',\n  'Ꙕ' => 'ꙕ',\n  'Ꙗ' => 'ꙗ',\n  'Ꙙ' => 'ꙙ',\n  'Ꙛ' => 'ꙛ',\n  'Ꙝ' => 'ꙝ',\n  'Ꙟ' => 'ꙟ',\n  'Ꙡ' => 'ꙡ',\n  'Ꙣ' => 'ꙣ',\n  'Ꙥ' => 'ꙥ',\n  'Ꙧ' => 'ꙧ',\n  'Ꙩ' => 'ꙩ',\n  'Ꙫ' => 'ꙫ',\n  'Ꙭ' => 'ꙭ',\n  'Ꚁ' => 'ꚁ',\n  'Ꚃ' => 'ꚃ',\n  'Ꚅ' => 'ꚅ',\n  'Ꚇ' => 'ꚇ',\n  'Ꚉ' => 'ꚉ',\n  'Ꚋ' => 'ꚋ',\n  'Ꚍ' => 'ꚍ',\n  'Ꚏ' => 'ꚏ',\n  'Ꚑ' => 'ꚑ',\n  'Ꚓ' => 'ꚓ',\n  'Ꚕ' => 'ꚕ',\n  'Ꚗ' => 'ꚗ',\n  'Ꚙ' => 'ꚙ',\n  'Ꚛ' => 'ꚛ',\n  'Ꜣ' => 'ꜣ',\n  'Ꜥ' => 'ꜥ',\n  'Ꜧ' => 'ꜧ',\n  'Ꜩ' => 'ꜩ',\n  'Ꜫ' => 'ꜫ',\n  'Ꜭ' => 'ꜭ',\n  'Ꜯ' => 'ꜯ',\n  'Ꜳ' => 'ꜳ',\n  'Ꜵ' => 'ꜵ',\n  'Ꜷ' => 'ꜷ',\n  'Ꜹ' => 'ꜹ',\n  'Ꜻ' => 'ꜻ',\n  'Ꜽ' => 'ꜽ',\n  'Ꜿ' => 'ꜿ',\n  'Ꝁ' => 'ꝁ',\n  'Ꝃ' => 'ꝃ',\n  'Ꝅ' => 'ꝅ',\n  'Ꝇ' => 'ꝇ',\n  'Ꝉ' => 'ꝉ',\n  'Ꝋ' => 'ꝋ',\n  'Ꝍ' => 'ꝍ',\n  'Ꝏ' => 'ꝏ',\n  'Ꝑ' => 'ꝑ',\n  'Ꝓ' => 'ꝓ',\n  'Ꝕ' => 'ꝕ',\n  'Ꝗ' => 'ꝗ',\n  'Ꝙ' => 'ꝙ',\n  'Ꝛ' => 'ꝛ',\n  'Ꝝ' => 'ꝝ',\n  'Ꝟ' => 'ꝟ',\n  'Ꝡ' => 'ꝡ',\n  'Ꝣ' => 'ꝣ',\n  'Ꝥ' => 'ꝥ',\n  'Ꝧ' => 'ꝧ',\n  'Ꝩ' => 'ꝩ',\n  'Ꝫ' => 'ꝫ',\n  'Ꝭ' => 'ꝭ',\n  'Ꝯ' => 'ꝯ',\n  'Ꝺ' => 'ꝺ',\n  'Ꝼ' => 'ꝼ',\n  'Ᵹ' => 'ᵹ',\n  'Ꝿ' => 'ꝿ',\n  'Ꞁ' => 'ꞁ',\n  'Ꞃ' => 'ꞃ',\n  'Ꞅ' => 'ꞅ',\n  'Ꞇ' => 'ꞇ',\n  'Ꞌ' => 'ꞌ',\n  'Ɥ' => 'ɥ',\n  'Ꞑ' => 'ꞑ',\n  'Ꞓ' => 'ꞓ',\n  'Ꞗ' => 'ꞗ',\n  'Ꞙ' => 'ꞙ',\n  'Ꞛ' => 'ꞛ',\n  'Ꞝ' => 'ꞝ',\n  'Ꞟ' => 'ꞟ',\n  'Ꞡ' => 'ꞡ',\n  'Ꞣ' => 'ꞣ',\n  'Ꞥ' => 'ꞥ',\n  'Ꞧ' => 'ꞧ',\n  'Ꞩ' => 'ꞩ',\n  'Ɦ' => 'ɦ',\n  'Ɜ' => 'ɜ',\n  'Ɡ' => 'ɡ',\n  'Ɬ' => 'ɬ',\n  'Ɪ' => 'ɪ',\n  'Ʞ' => 'ʞ',\n  'Ʇ' => 'ʇ',\n  'Ʝ' => 'ʝ',\n  'Ꭓ' => 'ꭓ',\n  'Ꞵ' => 'ꞵ',\n  'Ꞷ' => 'ꞷ',\n  'Ꞹ' => 'ꞹ',\n  'Ꞻ' => 'ꞻ',\n  'Ꞽ' => 'ꞽ',\n  'Ꞿ' => 'ꞿ',\n  'Ꟃ' => 'ꟃ',\n  'Ꞔ' => 'ꞔ',\n  'Ʂ' => 'ʂ',\n  'Ᶎ' => 'ᶎ',\n  'Ꟈ' => 'ꟈ',\n  'Ꟊ' => 'ꟊ',\n  'Ꟶ' => 'ꟶ',\n  'Ａ' => 'ａ',\n  'Ｂ' => 'ｂ',\n  'Ｃ' => 'ｃ',\n  'Ｄ' => 'ｄ',\n  'Ｅ' => 'ｅ',\n  'Ｆ' => 'ｆ',\n  'Ｇ' => 'ｇ',\n  'Ｈ' => 'ｈ',\n  'Ｉ' => 'ｉ',\n  'Ｊ' => 'ｊ',\n  'Ｋ' => 'ｋ',\n  'Ｌ' => 'ｌ',\n  'Ｍ' => 'ｍ',\n  'Ｎ' => 'ｎ',\n  'Ｏ' => 'ｏ',\n  'Ｐ' => 'ｐ',\n  'Ｑ' => 'ｑ',\n  'Ｒ' => 'ｒ',\n  'Ｓ' => 'ｓ',\n  'Ｔ' => 'ｔ',\n  'Ｕ' => 'ｕ',\n  'Ｖ' => 'ｖ',\n  'Ｗ' => 'ｗ',\n  'Ｘ' => 'ｘ',\n  'Ｙ' => 'ｙ',\n  'Ｚ' => 'ｚ',\n  '𐐀' => '𐐨',\n  '𐐁' => '𐐩',\n  '𐐂' => '𐐪',\n  '𐐃' => '𐐫',\n  '𐐄' => '𐐬',\n  '𐐅' => '𐐭',\n  '𐐆' => '𐐮',\n  '𐐇' => '𐐯',\n  '𐐈' => '𐐰',\n  '𐐉' => '𐐱',\n  '𐐊' => '𐐲',\n  '𐐋' => '𐐳',\n  '𐐌' => '𐐴',\n  '𐐍' => '𐐵',\n  '𐐎' => '𐐶',\n  '𐐏' => '𐐷',\n  '𐐐' => '𐐸',\n  '𐐑' => '𐐹',\n  '𐐒' => '𐐺',\n  '𐐓' => '𐐻',\n  '𐐔' => '𐐼',\n  '𐐕' => '𐐽',\n  '𐐖' => '𐐾',\n  '𐐗' => '𐐿',\n  '𐐘' => '𐑀',\n  '𐐙' => '𐑁',\n  '𐐚' => '𐑂',\n  '𐐛' => '𐑃',\n  '𐐜' => '𐑄',\n  '𐐝' => '𐑅',\n  '𐐞' => '𐑆',\n  '𐐟' => '𐑇',\n  '𐐠' => '𐑈',\n  '𐐡' => '𐑉',\n  '𐐢' => '𐑊',\n  '𐐣' => '𐑋',\n  '𐐤' => '𐑌',\n  '𐐥' => '𐑍',\n  '𐐦' => '𐑎',\n  '𐐧' => '𐑏',\n  '𐒰' => '𐓘',\n  '𐒱' => '𐓙',\n  '𐒲' => '𐓚',\n  '𐒳' => '𐓛',\n  '𐒴' => '𐓜',\n  '𐒵' => '𐓝',\n  '𐒶' => '𐓞',\n  '𐒷' => '𐓟',\n  '𐒸' => '𐓠',\n  '𐒹' => '𐓡',\n  '𐒺' => '𐓢',\n  '𐒻' => '𐓣',\n  '𐒼' => '𐓤',\n  '𐒽' => '𐓥',\n  '𐒾' => '𐓦',\n  '𐒿' => '𐓧',\n  '𐓀' => '𐓨',\n  '𐓁' => '𐓩',\n  '𐓂' => '𐓪',\n  '𐓃' => '𐓫',\n  '𐓄' => '𐓬',\n  '𐓅' => '𐓭',\n  '𐓆' => '𐓮',\n  '𐓇' => '𐓯',\n  '𐓈' => '𐓰',\n  '𐓉' => '𐓱',\n  '𐓊' => '𐓲',\n  '𐓋' => '𐓳',\n  '𐓌' => '𐓴',\n  '𐓍' => '𐓵',\n  '𐓎' => '𐓶',\n  '𐓏' => '𐓷',\n  '𐓐' => '𐓸',\n  '𐓑' => '𐓹',\n  '𐓒' => '𐓺',\n  '𐓓' => '𐓻',\n  '𐲀' => '𐳀',\n  '𐲁' => '𐳁',\n  '𐲂' => '𐳂',\n  '𐲃' => '𐳃',\n  '𐲄' => '𐳄',\n  '𐲅' => '𐳅',\n  '𐲆' => '𐳆',\n  '𐲇' => '𐳇',\n  '𐲈' => '𐳈',\n  '𐲉' => '𐳉',\n  '𐲊' => '𐳊',\n  '𐲋' => '𐳋',\n  '𐲌' => '𐳌',\n  '𐲍' => '𐳍',\n  '𐲎' => '𐳎',\n  '𐲏' => '𐳏',\n  '𐲐' => '𐳐',\n  '𐲑' => '𐳑',\n  '𐲒' => '𐳒',\n  '𐲓' => '𐳓',\n  '𐲔' => '𐳔',\n  '𐲕' => '𐳕',\n  '𐲖' => '𐳖',\n  '𐲗' => '𐳗',\n  '𐲘' => '𐳘',\n  '𐲙' => '𐳙',\n  '𐲚' => '𐳚',\n  '𐲛' => '𐳛',\n  '𐲜' => '𐳜',\n  '𐲝' => '𐳝',\n  '𐲞' => '𐳞',\n  '𐲟' => '𐳟',\n  '𐲠' => '𐳠',\n  '𐲡' => '𐳡',\n  '𐲢' => '𐳢',\n  '𐲣' => '𐳣',\n  '𐲤' => '𐳤',\n  '𐲥' => '𐳥',\n  '𐲦' => '𐳦',\n  '𐲧' => '𐳧',\n  '𐲨' => '𐳨',\n  '𐲩' => '𐳩',\n  '𐲪' => '𐳪',\n  '𐲫' => '𐳫',\n  '𐲬' => '𐳬',\n  '𐲭' => '𐳭',\n  '𐲮' => '𐳮',\n  '𐲯' => '𐳯',\n  '𐲰' => '𐳰',\n  '𐲱' => '𐳱',\n  '𐲲' => '𐳲',\n  '𑢠' => '𑣀',\n  '𑢡' => '𑣁',\n  '𑢢' => '𑣂',\n  '𑢣' => '𑣃',\n  '𑢤' => '𑣄',\n  '𑢥' => '𑣅',\n  '𑢦' => '𑣆',\n  '𑢧' => '𑣇',\n  '𑢨' => '𑣈',\n  '𑢩' => '𑣉',\n  '𑢪' => '𑣊',\n  '𑢫' => '𑣋',\n  '𑢬' => '𑣌',\n  '𑢭' => '𑣍',\n  '𑢮' => '𑣎',\n  '𑢯' => '𑣏',\n  '𑢰' => '𑣐',\n  '𑢱' => '𑣑',\n  '𑢲' => '𑣒',\n  '𑢳' => '𑣓',\n  '𑢴' => '𑣔',\n  '𑢵' => '𑣕',\n  '𑢶' => '𑣖',\n  '𑢷' => '𑣗',\n  '𑢸' => '𑣘',\n  '𑢹' => '𑣙',\n  '𑢺' => '𑣚',\n  '𑢻' => '𑣛',\n  '𑢼' => '𑣜',\n  '𑢽' => '𑣝',\n  '𑢾' => '𑣞',\n  '𑢿' => '𑣟',\n  '𖹀' => '𖹠',\n  '𖹁' => '𖹡',\n  '𖹂' => '𖹢',\n  '𖹃' => '𖹣',\n  '𖹄' => '𖹤',\n  '𖹅' => '𖹥',\n  '𖹆' => '𖹦',\n  '𖹇' => '𖹧',\n  '𖹈' => '𖹨',\n  '𖹉' => '𖹩',\n  '𖹊' => '𖹪',\n  '𖹋' => '𖹫',\n  '𖹌' => '𖹬',\n  '𖹍' => '𖹭',\n  '𖹎' => '𖹮',\n  '𖹏' => '𖹯',\n  '𖹐' => '𖹰',\n  '𖹑' => '𖹱',\n  '𖹒' => '𖹲',\n  '𖹓' => '𖹳',\n  '𖹔' => '𖹴',\n  '𖹕' => '𖹵',\n  '𖹖' => '𖹶',\n  '𖹗' => '𖹷',\n  '𖹘' => '𖹸',\n  '𖹙' => '𖹹',\n  '𖹚' => '𖹺',\n  '𖹛' => '𖹻',\n  '𖹜' => '𖹼',\n  '𖹝' => '𖹽',\n  '𖹞' => '𖹾',\n  '𖹟' => '𖹿',\n  '𞤀' => '𞤢',\n  '𞤁' => '𞤣',\n  '𞤂' => '𞤤',\n  '𞤃' => '𞤥',\n  '𞤄' => '𞤦',\n  '𞤅' => '𞤧',\n  '𞤆' => '𞤨',\n  '𞤇' => '𞤩',\n  '𞤈' => '𞤪',\n  '𞤉' => '𞤫',\n  '𞤊' => '𞤬',\n  '𞤋' => '𞤭',\n  '𞤌' => '𞤮',\n  '𞤍' => '𞤯',\n  '𞤎' => '𞤰',\n  '𞤏' => '𞤱',\n  '𞤐' => '𞤲',\n  '𞤑' => '𞤳',\n  '𞤒' => '𞤴',\n  '𞤓' => '𞤵',\n  '𞤔' => '𞤶',\n  '𞤕' => '𞤷',\n  '𞤖' => '𞤸',\n  '𞤗' => '𞤹',\n  '𞤘' => '𞤺',\n  '𞤙' => '𞤻',\n  '𞤚' => '𞤼',\n  '𞤛' => '𞤽',\n  '𞤜' => '𞤾',\n  '𞤝' => '𞤿',\n  '𞤞' => '𞥀',\n  '𞤟' => '𞥁',\n  '𞤠' => '𞥂',\n  '𞤡' => '𞥃',\n);\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-mbstring/Resources/unidata/titleCaseRegexp.php",
    "content": "<?php\n\n// from Case_Ignorable in https://unicode.org/Public/UNIDATA/DerivedCoreProperties.txt\n\nreturn '/(?<![\\x{0027}\\x{002E}\\x{003A}\\x{005E}\\x{0060}\\x{00A8}\\x{00AD}\\x{00AF}\\x{00B4}\\x{00B7}\\x{00B8}\\x{02B0}-\\x{02C1}\\x{02C2}-\\x{02C5}\\x{02C6}-\\x{02D1}\\x{02D2}-\\x{02DF}\\x{02E0}-\\x{02E4}\\x{02E5}-\\x{02EB}\\x{02EC}\\x{02ED}\\x{02EE}\\x{02EF}-\\x{02FF}\\x{0300}-\\x{036F}\\x{0374}\\x{0375}\\x{037A}\\x{0384}-\\x{0385}\\x{0387}\\x{0483}-\\x{0487}\\x{0488}-\\x{0489}\\x{0559}\\x{0591}-\\x{05BD}\\x{05BF}\\x{05C1}-\\x{05C2}\\x{05C4}-\\x{05C5}\\x{05C7}\\x{05F4}\\x{0600}-\\x{0605}\\x{0610}-\\x{061A}\\x{061C}\\x{0640}\\x{064B}-\\x{065F}\\x{0670}\\x{06D6}-\\x{06DC}\\x{06DD}\\x{06DF}-\\x{06E4}\\x{06E5}-\\x{06E6}\\x{06E7}-\\x{06E8}\\x{06EA}-\\x{06ED}\\x{070F}\\x{0711}\\x{0730}-\\x{074A}\\x{07A6}-\\x{07B0}\\x{07EB}-\\x{07F3}\\x{07F4}-\\x{07F5}\\x{07FA}\\x{07FD}\\x{0816}-\\x{0819}\\x{081A}\\x{081B}-\\x{0823}\\x{0824}\\x{0825}-\\x{0827}\\x{0828}\\x{0829}-\\x{082D}\\x{0859}-\\x{085B}\\x{08D3}-\\x{08E1}\\x{08E2}\\x{08E3}-\\x{0902}\\x{093A}\\x{093C}\\x{0941}-\\x{0948}\\x{094D}\\x{0951}-\\x{0957}\\x{0962}-\\x{0963}\\x{0971}\\x{0981}\\x{09BC}\\x{09C1}-\\x{09C4}\\x{09CD}\\x{09E2}-\\x{09E3}\\x{09FE}\\x{0A01}-\\x{0A02}\\x{0A3C}\\x{0A41}-\\x{0A42}\\x{0A47}-\\x{0A48}\\x{0A4B}-\\x{0A4D}\\x{0A51}\\x{0A70}-\\x{0A71}\\x{0A75}\\x{0A81}-\\x{0A82}\\x{0ABC}\\x{0AC1}-\\x{0AC5}\\x{0AC7}-\\x{0AC8}\\x{0ACD}\\x{0AE2}-\\x{0AE3}\\x{0AFA}-\\x{0AFF}\\x{0B01}\\x{0B3C}\\x{0B3F}\\x{0B41}-\\x{0B44}\\x{0B4D}\\x{0B56}\\x{0B62}-\\x{0B63}\\x{0B82}\\x{0BC0}\\x{0BCD}\\x{0C00}\\x{0C04}\\x{0C3E}-\\x{0C40}\\x{0C46}-\\x{0C48}\\x{0C4A}-\\x{0C4D}\\x{0C55}-\\x{0C56}\\x{0C62}-\\x{0C63}\\x{0C81}\\x{0CBC}\\x{0CBF}\\x{0CC6}\\x{0CCC}-\\x{0CCD}\\x{0CE2}-\\x{0CE3}\\x{0D00}-\\x{0D01}\\x{0D3B}-\\x{0D3C}\\x{0D41}-\\x{0D44}\\x{0D4D}\\x{0D62}-\\x{0D63}\\x{0DCA}\\x{0DD2}-\\x{0DD4}\\x{0DD6}\\x{0E31}\\x{0E34}-\\x{0E3A}\\x{0E46}\\x{0E47}-\\x{0E4E}\\x{0EB1}\\x{0EB4}-\\x{0EB9}\\x{0EBB}-\\x{0EBC}\\x{0EC6}\\x{0EC8}-\\x{0ECD}\\x{0F18}-\\x{0F19}\\x{0F35}\\x{0F37}\\x{0F39}\\x{0F71}-\\x{0F7E}\\x{0F80}-\\x{0F84}\\x{0F86}-\\x{0F87}\\x{0F8D}-\\x{0F97}\\x{0F99}-\\x{0FBC}\\x{0FC6}\\x{102D}-\\x{1030}\\x{1032}-\\x{1037}\\x{1039}-\\x{103A}\\x{103D}-\\x{103E}\\x{1058}-\\x{1059}\\x{105E}-\\x{1060}\\x{1071}-\\x{1074}\\x{1082}\\x{1085}-\\x{1086}\\x{108D}\\x{109D}\\x{10FC}\\x{135D}-\\x{135F}\\x{1712}-\\x{1714}\\x{1732}-\\x{1734}\\x{1752}-\\x{1753}\\x{1772}-\\x{1773}\\x{17B4}-\\x{17B5}\\x{17B7}-\\x{17BD}\\x{17C6}\\x{17C9}-\\x{17D3}\\x{17D7}\\x{17DD}\\x{180B}-\\x{180D}\\x{180E}\\x{1843}\\x{1885}-\\x{1886}\\x{18A9}\\x{1920}-\\x{1922}\\x{1927}-\\x{1928}\\x{1932}\\x{1939}-\\x{193B}\\x{1A17}-\\x{1A18}\\x{1A1B}\\x{1A56}\\x{1A58}-\\x{1A5E}\\x{1A60}\\x{1A62}\\x{1A65}-\\x{1A6C}\\x{1A73}-\\x{1A7C}\\x{1A7F}\\x{1AA7}\\x{1AB0}-\\x{1ABD}\\x{1ABE}\\x{1B00}-\\x{1B03}\\x{1B34}\\x{1B36}-\\x{1B3A}\\x{1B3C}\\x{1B42}\\x{1B6B}-\\x{1B73}\\x{1B80}-\\x{1B81}\\x{1BA2}-\\x{1BA5}\\x{1BA8}-\\x{1BA9}\\x{1BAB}-\\x{1BAD}\\x{1BE6}\\x{1BE8}-\\x{1BE9}\\x{1BED}\\x{1BEF}-\\x{1BF1}\\x{1C2C}-\\x{1C33}\\x{1C36}-\\x{1C37}\\x{1C78}-\\x{1C7D}\\x{1CD0}-\\x{1CD2}\\x{1CD4}-\\x{1CE0}\\x{1CE2}-\\x{1CE8}\\x{1CED}\\x{1CF4}\\x{1CF8}-\\x{1CF9}\\x{1D2C}-\\x{1D6A}\\x{1D78}\\x{1D9B}-\\x{1DBF}\\x{1DC0}-\\x{1DF9}\\x{1DFB}-\\x{1DFF}\\x{1FBD}\\x{1FBF}-\\x{1FC1}\\x{1FCD}-\\x{1FCF}\\x{1FDD}-\\x{1FDF}\\x{1FED}-\\x{1FEF}\\x{1FFD}-\\x{1FFE}\\x{200B}-\\x{200F}\\x{2018}\\x{2019}\\x{2024}\\x{2027}\\x{202A}-\\x{202E}\\x{2060}-\\x{2064}\\x{2066}-\\x{206F}\\x{2071}\\x{207F}\\x{2090}-\\x{209C}\\x{20D0}-\\x{20DC}\\x{20DD}-\\x{20E0}\\x{20E1}\\x{20E2}-\\x{20E4}\\x{20E5}-\\x{20F0}\\x{2C7C}-\\x{2C7D}\\x{2CEF}-\\x{2CF1}\\x{2D6F}\\x{2D7F}\\x{2DE0}-\\x{2DFF}\\x{2E2F}\\x{3005}\\x{302A}-\\x{302D}\\x{3031}-\\x{3035}\\x{303B}\\x{3099}-\\x{309A}\\x{309B}-\\x{309C}\\x{309D}-\\x{309E}\\x{30FC}-\\x{30FE}\\x{A015}\\x{A4F8}-\\x{A4FD}\\x{A60C}\\x{A66F}\\x{A670}-\\x{A672}\\x{A674}-\\x{A67D}\\x{A67F}\\x{A69C}-\\x{A69D}\\x{A69E}-\\x{A69F}\\x{A6F0}-\\x{A6F1}\\x{A700}-\\x{A716}\\x{A717}-\\x{A71F}\\x{A720}-\\x{A721}\\x{A770}\\x{A788}\\x{A789}-\\x{A78A}\\x{A7F8}-\\x{A7F9}\\x{A802}\\x{A806}\\x{A80B}\\x{A825}-\\x{A826}\\x{A8C4}-\\x{A8C5}\\x{A8E0}-\\x{A8F1}\\x{A8FF}\\x{A926}-\\x{A92D}\\x{A947}-\\x{A951}\\x{A980}-\\x{A982}\\x{A9B3}\\x{A9B6}-\\x{A9B9}\\x{A9BC}\\x{A9CF}\\x{A9E5}\\x{A9E6}\\x{AA29}-\\x{AA2E}\\x{AA31}-\\x{AA32}\\x{AA35}-\\x{AA36}\\x{AA43}\\x{AA4C}\\x{AA70}\\x{AA7C}\\x{AAB0}\\x{AAB2}-\\x{AAB4}\\x{AAB7}-\\x{AAB8}\\x{AABE}-\\x{AABF}\\x{AAC1}\\x{AADD}\\x{AAEC}-\\x{AAED}\\x{AAF3}-\\x{AAF4}\\x{AAF6}\\x{AB5B}\\x{AB5C}-\\x{AB5F}\\x{ABE5}\\x{ABE8}\\x{ABED}\\x{FB1E}\\x{FBB2}-\\x{FBC1}\\x{FE00}-\\x{FE0F}\\x{FE13}\\x{FE20}-\\x{FE2F}\\x{FE52}\\x{FE55}\\x{FEFF}\\x{FF07}\\x{FF0E}\\x{FF1A}\\x{FF3E}\\x{FF40}\\x{FF70}\\x{FF9E}-\\x{FF9F}\\x{FFE3}\\x{FFF9}-\\x{FFFB}\\x{101FD}\\x{102E0}\\x{10376}-\\x{1037A}\\x{10A01}-\\x{10A03}\\x{10A05}-\\x{10A06}\\x{10A0C}-\\x{10A0F}\\x{10A38}-\\x{10A3A}\\x{10A3F}\\x{10AE5}-\\x{10AE6}\\x{10D24}-\\x{10D27}\\x{10F46}-\\x{10F50}\\x{11001}\\x{11038}-\\x{11046}\\x{1107F}-\\x{11081}\\x{110B3}-\\x{110B6}\\x{110B9}-\\x{110BA}\\x{110BD}\\x{110CD}\\x{11100}-\\x{11102}\\x{11127}-\\x{1112B}\\x{1112D}-\\x{11134}\\x{11173}\\x{11180}-\\x{11181}\\x{111B6}-\\x{111BE}\\x{111C9}-\\x{111CC}\\x{1122F}-\\x{11231}\\x{11234}\\x{11236}-\\x{11237}\\x{1123E}\\x{112DF}\\x{112E3}-\\x{112EA}\\x{11300}-\\x{11301}\\x{1133B}-\\x{1133C}\\x{11340}\\x{11366}-\\x{1136C}\\x{11370}-\\x{11374}\\x{11438}-\\x{1143F}\\x{11442}-\\x{11444}\\x{11446}\\x{1145E}\\x{114B3}-\\x{114B8}\\x{114BA}\\x{114BF}-\\x{114C0}\\x{114C2}-\\x{114C3}\\x{115B2}-\\x{115B5}\\x{115BC}-\\x{115BD}\\x{115BF}-\\x{115C0}\\x{115DC}-\\x{115DD}\\x{11633}-\\x{1163A}\\x{1163D}\\x{1163F}-\\x{11640}\\x{116AB}\\x{116AD}\\x{116B0}-\\x{116B5}\\x{116B7}\\x{1171D}-\\x{1171F}\\x{11722}-\\x{11725}\\x{11727}-\\x{1172B}\\x{1182F}-\\x{11837}\\x{11839}-\\x{1183A}\\x{11A01}-\\x{11A0A}\\x{11A33}-\\x{11A38}\\x{11A3B}-\\x{11A3E}\\x{11A47}\\x{11A51}-\\x{11A56}\\x{11A59}-\\x{11A5B}\\x{11A8A}-\\x{11A96}\\x{11A98}-\\x{11A99}\\x{11C30}-\\x{11C36}\\x{11C38}-\\x{11C3D}\\x{11C3F}\\x{11C92}-\\x{11CA7}\\x{11CAA}-\\x{11CB0}\\x{11CB2}-\\x{11CB3}\\x{11CB5}-\\x{11CB6}\\x{11D31}-\\x{11D36}\\x{11D3A}\\x{11D3C}-\\x{11D3D}\\x{11D3F}-\\x{11D45}\\x{11D47}\\x{11D90}-\\x{11D91}\\x{11D95}\\x{11D97}\\x{11EF3}-\\x{11EF4}\\x{16AF0}-\\x{16AF4}\\x{16B30}-\\x{16B36}\\x{16B40}-\\x{16B43}\\x{16F8F}-\\x{16F92}\\x{16F93}-\\x{16F9F}\\x{16FE0}-\\x{16FE1}\\x{1BC9D}-\\x{1BC9E}\\x{1BCA0}-\\x{1BCA3}\\x{1D167}-\\x{1D169}\\x{1D173}-\\x{1D17A}\\x{1D17B}-\\x{1D182}\\x{1D185}-\\x{1D18B}\\x{1D1AA}-\\x{1D1AD}\\x{1D242}-\\x{1D244}\\x{1DA00}-\\x{1DA36}\\x{1DA3B}-\\x{1DA6C}\\x{1DA75}\\x{1DA84}\\x{1DA9B}-\\x{1DA9F}\\x{1DAA1}-\\x{1DAAF}\\x{1E000}-\\x{1E006}\\x{1E008}-\\x{1E018}\\x{1E01B}-\\x{1E021}\\x{1E023}-\\x{1E024}\\x{1E026}-\\x{1E02A}\\x{1E8D0}-\\x{1E8D6}\\x{1E944}-\\x{1E94A}\\x{1F3FB}-\\x{1F3FF}\\x{E0001}\\x{E0020}-\\x{E007F}\\x{E0100}-\\x{E01EF}])(\\pL)(\\pL*+)/u';\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-mbstring/Resources/unidata/upperCase.php",
    "content": "<?php\n\nreturn array (\n  'a' => 'A',\n  'b' => 'B',\n  'c' => 'C',\n  'd' => 'D',\n  'e' => 'E',\n  'f' => 'F',\n  'g' => 'G',\n  'h' => 'H',\n  'i' => 'I',\n  'j' => 'J',\n  'k' => 'K',\n  'l' => 'L',\n  'm' => 'M',\n  'n' => 'N',\n  'o' => 'O',\n  'p' => 'P',\n  'q' => 'Q',\n  'r' => 'R',\n  's' => 'S',\n  't' => 'T',\n  'u' => 'U',\n  'v' => 'V',\n  'w' => 'W',\n  'x' => 'X',\n  'y' => 'Y',\n  'z' => 'Z',\n  'µ' => 'Μ',\n  'à' => 'À',\n  'á' => 'Á',\n  'â' => 'Â',\n  'ã' => 'Ã',\n  'ä' => 'Ä',\n  'å' => 'Å',\n  'æ' => 'Æ',\n  'ç' => 'Ç',\n  'è' => 'È',\n  'é' => 'É',\n  'ê' => 'Ê',\n  'ë' => 'Ë',\n  'ì' => 'Ì',\n  'í' => 'Í',\n  'î' => 'Î',\n  'ï' => 'Ï',\n  'ð' => 'Ð',\n  'ñ' => 'Ñ',\n  'ò' => 'Ò',\n  'ó' => 'Ó',\n  'ô' => 'Ô',\n  'õ' => 'Õ',\n  'ö' => 'Ö',\n  'ø' => 'Ø',\n  'ù' => 'Ù',\n  'ú' => 'Ú',\n  'û' => 'Û',\n  'ü' => 'Ü',\n  'ý' => 'Ý',\n  'þ' => 'Þ',\n  'ÿ' => 'Ÿ',\n  'ā' => 'Ā',\n  'ă' => 'Ă',\n  'ą' => 'Ą',\n  'ć' => 'Ć',\n  'ĉ' => 'Ĉ',\n  'ċ' => 'Ċ',\n  'č' => 'Č',\n  'ď' => 'Ď',\n  'đ' => 'Đ',\n  'ē' => 'Ē',\n  'ĕ' => 'Ĕ',\n  'ė' => 'Ė',\n  'ę' => 'Ę',\n  'ě' => 'Ě',\n  'ĝ' => 'Ĝ',\n  'ğ' => 'Ğ',\n  'ġ' => 'Ġ',\n  'ģ' => 'Ģ',\n  'ĥ' => 'Ĥ',\n  'ħ' => 'Ħ',\n  'ĩ' => 'Ĩ',\n  'ī' => 'Ī',\n  'ĭ' => 'Ĭ',\n  'į' => 'Į',\n  'ı' => 'I',\n  'ĳ' => 'Ĳ',\n  'ĵ' => 'Ĵ',\n  'ķ' => 'Ķ',\n  'ĺ' => 'Ĺ',\n  'ļ' => 'Ļ',\n  'ľ' => 'Ľ',\n  'ŀ' => 'Ŀ',\n  'ł' => 'Ł',\n  'ń' => 'Ń',\n  'ņ' => 'Ņ',\n  'ň' => 'Ň',\n  'ŋ' => 'Ŋ',\n  'ō' => 'Ō',\n  'ŏ' => 'Ŏ',\n  'ő' => 'Ő',\n  'œ' => 'Œ',\n  'ŕ' => 'Ŕ',\n  'ŗ' => 'Ŗ',\n  'ř' => 'Ř',\n  'ś' => 'Ś',\n  'ŝ' => 'Ŝ',\n  'ş' => 'Ş',\n  'š' => 'Š',\n  'ţ' => 'Ţ',\n  'ť' => 'Ť',\n  'ŧ' => 'Ŧ',\n  'ũ' => 'Ũ',\n  'ū' => 'Ū',\n  'ŭ' => 'Ŭ',\n  'ů' => 'Ů',\n  'ű' => 'Ű',\n  'ų' => 'Ų',\n  'ŵ' => 'Ŵ',\n  'ŷ' => 'Ŷ',\n  'ź' => 'Ź',\n  'ż' => 'Ż',\n  'ž' => 'Ž',\n  'ſ' => 'S',\n  'ƀ' => 'Ƀ',\n  'ƃ' => 'Ƃ',\n  'ƅ' => 'Ƅ',\n  'ƈ' => 'Ƈ',\n  'ƌ' => 'Ƌ',\n  'ƒ' => 'Ƒ',\n  'ƕ' => 'Ƕ',\n  'ƙ' => 'Ƙ',\n  'ƚ' => 'Ƚ',\n  'ƞ' => 'Ƞ',\n  'ơ' => 'Ơ',\n  'ƣ' => 'Ƣ',\n  'ƥ' => 'Ƥ',\n  'ƨ' => 'Ƨ',\n  'ƭ' => 'Ƭ',\n  'ư' => 'Ư',\n  'ƴ' => 'Ƴ',\n  'ƶ' => 'Ƶ',\n  'ƹ' => 'Ƹ',\n  'ƽ' => 'Ƽ',\n  'ƿ' => 'Ƿ',\n  'ǅ' => 'Ǆ',\n  'ǆ' => 'Ǆ',\n  'ǈ' => 'Ǉ',\n  'ǉ' => 'Ǉ',\n  'ǋ' => 'Ǌ',\n  'ǌ' => 'Ǌ',\n  'ǎ' => 'Ǎ',\n  'ǐ' => 'Ǐ',\n  'ǒ' => 'Ǒ',\n  'ǔ' => 'Ǔ',\n  'ǖ' => 'Ǖ',\n  'ǘ' => 'Ǘ',\n  'ǚ' => 'Ǚ',\n  'ǜ' => 'Ǜ',\n  'ǝ' => 'Ǝ',\n  'ǟ' => 'Ǟ',\n  'ǡ' => 'Ǡ',\n  'ǣ' => 'Ǣ',\n  'ǥ' => 'Ǥ',\n  'ǧ' => 'Ǧ',\n  'ǩ' => 'Ǩ',\n  'ǫ' => 'Ǫ',\n  'ǭ' => 'Ǭ',\n  'ǯ' => 'Ǯ',\n  'ǲ' => 'Ǳ',\n  'ǳ' => 'Ǳ',\n  'ǵ' => 'Ǵ',\n  'ǹ' => 'Ǹ',\n  'ǻ' => 'Ǻ',\n  'ǽ' => 'Ǽ',\n  'ǿ' => 'Ǿ',\n  'ȁ' => 'Ȁ',\n  'ȃ' => 'Ȃ',\n  'ȅ' => 'Ȅ',\n  'ȇ' => 'Ȇ',\n  'ȉ' => 'Ȉ',\n  'ȋ' => 'Ȋ',\n  'ȍ' => 'Ȍ',\n  'ȏ' => 'Ȏ',\n  'ȑ' => 'Ȑ',\n  'ȓ' => 'Ȓ',\n  'ȕ' => 'Ȕ',\n  'ȗ' => 'Ȗ',\n  'ș' => 'Ș',\n  'ț' => 'Ț',\n  'ȝ' => 'Ȝ',\n  'ȟ' => 'Ȟ',\n  'ȣ' => 'Ȣ',\n  'ȥ' => 'Ȥ',\n  'ȧ' => 'Ȧ',\n  'ȩ' => 'Ȩ',\n  'ȫ' => 'Ȫ',\n  'ȭ' => 'Ȭ',\n  'ȯ' => 'Ȯ',\n  'ȱ' => 'Ȱ',\n  'ȳ' => 'Ȳ',\n  'ȼ' => 'Ȼ',\n  'ȿ' => 'Ȿ',\n  'ɀ' => 'Ɀ',\n  'ɂ' => 'Ɂ',\n  'ɇ' => 'Ɇ',\n  'ɉ' => 'Ɉ',\n  'ɋ' => 'Ɋ',\n  'ɍ' => 'Ɍ',\n  'ɏ' => 'Ɏ',\n  'ɐ' => 'Ɐ',\n  'ɑ' => 'Ɑ',\n  'ɒ' => 'Ɒ',\n  'ɓ' => 'Ɓ',\n  'ɔ' => 'Ɔ',\n  'ɖ' => 'Ɖ',\n  'ɗ' => 'Ɗ',\n  'ə' => 'Ə',\n  'ɛ' => 'Ɛ',\n  'ɜ' => 'Ɜ',\n  'ɠ' => 'Ɠ',\n  'ɡ' => 'Ɡ',\n  'ɣ' => 'Ɣ',\n  'ɥ' => 'Ɥ',\n  'ɦ' => 'Ɦ',\n  'ɨ' => 'Ɨ',\n  'ɩ' => 'Ɩ',\n  'ɪ' => 'Ɪ',\n  'ɫ' => 'Ɫ',\n  'ɬ' => 'Ɬ',\n  'ɯ' => 'Ɯ',\n  'ɱ' => 'Ɱ',\n  'ɲ' => 'Ɲ',\n  'ɵ' => 'Ɵ',\n  'ɽ' => 'Ɽ',\n  'ʀ' => 'Ʀ',\n  'ʂ' => 'Ʂ',\n  'ʃ' => 'Ʃ',\n  'ʇ' => 'Ʇ',\n  'ʈ' => 'Ʈ',\n  'ʉ' => 'Ʉ',\n  'ʊ' => 'Ʊ',\n  'ʋ' => 'Ʋ',\n  'ʌ' => 'Ʌ',\n  'ʒ' => 'Ʒ',\n  'ʝ' => 'Ʝ',\n  'ʞ' => 'Ʞ',\n  'ͅ' => 'Ι',\n  'ͱ' => 'Ͱ',\n  'ͳ' => 'Ͳ',\n  'ͷ' => 'Ͷ',\n  'ͻ' => 'Ͻ',\n  'ͼ' => 'Ͼ',\n  'ͽ' => 'Ͽ',\n  'ά' => 'Ά',\n  'έ' => 'Έ',\n  'ή' => 'Ή',\n  'ί' => 'Ί',\n  'α' => 'Α',\n  'β' => 'Β',\n  'γ' => 'Γ',\n  'δ' => 'Δ',\n  'ε' => 'Ε',\n  'ζ' => 'Ζ',\n  'η' => 'Η',\n  'θ' => 'Θ',\n  'ι' => 'Ι',\n  'κ' => 'Κ',\n  'λ' => 'Λ',\n  'μ' => 'Μ',\n  'ν' => 'Ν',\n  'ξ' => 'Ξ',\n  'ο' => 'Ο',\n  'π' => 'Π',\n  'ρ' => 'Ρ',\n  'ς' => 'Σ',\n  'σ' => 'Σ',\n  'τ' => 'Τ',\n  'υ' => 'Υ',\n  'φ' => 'Φ',\n  'χ' => 'Χ',\n  'ψ' => 'Ψ',\n  'ω' => 'Ω',\n  'ϊ' => 'Ϊ',\n  'ϋ' => 'Ϋ',\n  'ό' => 'Ό',\n  'ύ' => 'Ύ',\n  'ώ' => 'Ώ',\n  'ϐ' => 'Β',\n  'ϑ' => 'Θ',\n  'ϕ' => 'Φ',\n  'ϖ' => 'Π',\n  'ϗ' => 'Ϗ',\n  'ϙ' => 'Ϙ',\n  'ϛ' => 'Ϛ',\n  'ϝ' => 'Ϝ',\n  'ϟ' => 'Ϟ',\n  'ϡ' => 'Ϡ',\n  'ϣ' => 'Ϣ',\n  'ϥ' => 'Ϥ',\n  'ϧ' => 'Ϧ',\n  'ϩ' => 'Ϩ',\n  'ϫ' => 'Ϫ',\n  'ϭ' => 'Ϭ',\n  'ϯ' => 'Ϯ',\n  'ϰ' => 'Κ',\n  'ϱ' => 'Ρ',\n  'ϲ' => 'Ϲ',\n  'ϳ' => 'Ϳ',\n  'ϵ' => 'Ε',\n  'ϸ' => 'Ϸ',\n  'ϻ' => 'Ϻ',\n  'а' => 'А',\n  'б' => 'Б',\n  'в' => 'В',\n  'г' => 'Г',\n  'д' => 'Д',\n  'е' => 'Е',\n  'ж' => 'Ж',\n  'з' => 'З',\n  'и' => 'И',\n  'й' => 'Й',\n  'к' => 'К',\n  'л' => 'Л',\n  'м' => 'М',\n  'н' => 'Н',\n  'о' => 'О',\n  'п' => 'П',\n  'р' => 'Р',\n  'с' => 'С',\n  'т' => 'Т',\n  'у' => 'У',\n  'ф' => 'Ф',\n  'х' => 'Х',\n  'ц' => 'Ц',\n  'ч' => 'Ч',\n  'ш' => 'Ш',\n  'щ' => 'Щ',\n  'ъ' => 'Ъ',\n  'ы' => 'Ы',\n  'ь' => 'Ь',\n  'э' => 'Э',\n  'ю' => 'Ю',\n  'я' => 'Я',\n  'ѐ' => 'Ѐ',\n  'ё' => 'Ё',\n  'ђ' => 'Ђ',\n  'ѓ' => 'Ѓ',\n  'є' => 'Є',\n  'ѕ' => 'Ѕ',\n  'і' => 'І',\n  'ї' => 'Ї',\n  'ј' => 'Ј',\n  'љ' => 'Љ',\n  'њ' => 'Њ',\n  'ћ' => 'Ћ',\n  'ќ' => 'Ќ',\n  'ѝ' => 'Ѝ',\n  'ў' => 'Ў',\n  'џ' => 'Џ',\n  'ѡ' => 'Ѡ',\n  'ѣ' => 'Ѣ',\n  'ѥ' => 'Ѥ',\n  'ѧ' => 'Ѧ',\n  'ѩ' => 'Ѩ',\n  'ѫ' => 'Ѫ',\n  'ѭ' => 'Ѭ',\n  'ѯ' => 'Ѯ',\n  'ѱ' => 'Ѱ',\n  'ѳ' => 'Ѳ',\n  'ѵ' => 'Ѵ',\n  'ѷ' => 'Ѷ',\n  'ѹ' => 'Ѹ',\n  'ѻ' => 'Ѻ',\n  'ѽ' => 'Ѽ',\n  'ѿ' => 'Ѿ',\n  'ҁ' => 'Ҁ',\n  'ҋ' => 'Ҋ',\n  'ҍ' => 'Ҍ',\n  'ҏ' => 'Ҏ',\n  'ґ' => 'Ґ',\n  'ғ' => 'Ғ',\n  'ҕ' => 'Ҕ',\n  'җ' => 'Җ',\n  'ҙ' => 'Ҙ',\n  'қ' => 'Қ',\n  'ҝ' => 'Ҝ',\n  'ҟ' => 'Ҟ',\n  'ҡ' => 'Ҡ',\n  'ң' => 'Ң',\n  'ҥ' => 'Ҥ',\n  'ҧ' => 'Ҧ',\n  'ҩ' => 'Ҩ',\n  'ҫ' => 'Ҫ',\n  'ҭ' => 'Ҭ',\n  'ү' => 'Ү',\n  'ұ' => 'Ұ',\n  'ҳ' => 'Ҳ',\n  'ҵ' => 'Ҵ',\n  'ҷ' => 'Ҷ',\n  'ҹ' => 'Ҹ',\n  'һ' => 'Һ',\n  'ҽ' => 'Ҽ',\n  'ҿ' => 'Ҿ',\n  'ӂ' => 'Ӂ',\n  'ӄ' => 'Ӄ',\n  'ӆ' => 'Ӆ',\n  'ӈ' => 'Ӈ',\n  'ӊ' => 'Ӊ',\n  'ӌ' => 'Ӌ',\n  'ӎ' => 'Ӎ',\n  'ӏ' => 'Ӏ',\n  'ӑ' => 'Ӑ',\n  'ӓ' => 'Ӓ',\n  'ӕ' => 'Ӕ',\n  'ӗ' => 'Ӗ',\n  'ә' => 'Ә',\n  'ӛ' => 'Ӛ',\n  'ӝ' => 'Ӝ',\n  'ӟ' => 'Ӟ',\n  'ӡ' => 'Ӡ',\n  'ӣ' => 'Ӣ',\n  'ӥ' => 'Ӥ',\n  'ӧ' => 'Ӧ',\n  'ө' => 'Ө',\n  'ӫ' => 'Ӫ',\n  'ӭ' => 'Ӭ',\n  'ӯ' => 'Ӯ',\n  'ӱ' => 'Ӱ',\n  'ӳ' => 'Ӳ',\n  'ӵ' => 'Ӵ',\n  'ӷ' => 'Ӷ',\n  'ӹ' => 'Ӹ',\n  'ӻ' => 'Ӻ',\n  'ӽ' => 'Ӽ',\n  'ӿ' => 'Ӿ',\n  'ԁ' => 'Ԁ',\n  'ԃ' => 'Ԃ',\n  'ԅ' => 'Ԅ',\n  'ԇ' => 'Ԇ',\n  'ԉ' => 'Ԉ',\n  'ԋ' => 'Ԋ',\n  'ԍ' => 'Ԍ',\n  'ԏ' => 'Ԏ',\n  'ԑ' => 'Ԑ',\n  'ԓ' => 'Ԓ',\n  'ԕ' => 'Ԕ',\n  'ԗ' => 'Ԗ',\n  'ԙ' => 'Ԙ',\n  'ԛ' => 'Ԛ',\n  'ԝ' => 'Ԝ',\n  'ԟ' => 'Ԟ',\n  'ԡ' => 'Ԡ',\n  'ԣ' => 'Ԣ',\n  'ԥ' => 'Ԥ',\n  'ԧ' => 'Ԧ',\n  'ԩ' => 'Ԩ',\n  'ԫ' => 'Ԫ',\n  'ԭ' => 'Ԭ',\n  'ԯ' => 'Ԯ',\n  'ա' => 'Ա',\n  'բ' => 'Բ',\n  'գ' => 'Գ',\n  'դ' => 'Դ',\n  'ե' => 'Ե',\n  'զ' => 'Զ',\n  'է' => 'Է',\n  'ը' => 'Ը',\n  'թ' => 'Թ',\n  'ժ' => 'Ժ',\n  'ի' => 'Ի',\n  'լ' => 'Լ',\n  'խ' => 'Խ',\n  'ծ' => 'Ծ',\n  'կ' => 'Կ',\n  'հ' => 'Հ',\n  'ձ' => 'Ձ',\n  'ղ' => 'Ղ',\n  'ճ' => 'Ճ',\n  'մ' => 'Մ',\n  'յ' => 'Յ',\n  'ն' => 'Ն',\n  'շ' => 'Շ',\n  'ո' => 'Ո',\n  'չ' => 'Չ',\n  'պ' => 'Պ',\n  'ջ' => 'Ջ',\n  'ռ' => 'Ռ',\n  'ս' => 'Ս',\n  'վ' => 'Վ',\n  'տ' => 'Տ',\n  'ր' => 'Ր',\n  'ց' => 'Ց',\n  'ւ' => 'Ւ',\n  'փ' => 'Փ',\n  'ք' => 'Ք',\n  'օ' => 'Օ',\n  'ֆ' => 'Ֆ',\n  'ა' => 'Ა',\n  'ბ' => 'Ბ',\n  'გ' => 'Გ',\n  'დ' => 'Დ',\n  'ე' => 'Ე',\n  'ვ' => 'Ვ',\n  'ზ' => 'Ზ',\n  'თ' => 'Თ',\n  'ი' => 'Ი',\n  'კ' => 'Კ',\n  'ლ' => 'Ლ',\n  'მ' => 'Მ',\n  'ნ' => 'Ნ',\n  'ო' => 'Ო',\n  'პ' => 'Პ',\n  'ჟ' => 'Ჟ',\n  'რ' => 'Რ',\n  'ს' => 'Ს',\n  'ტ' => 'Ტ',\n  'უ' => 'Უ',\n  'ფ' => 'Ფ',\n  'ქ' => 'Ქ',\n  'ღ' => 'Ღ',\n  'ყ' => 'Ყ',\n  'შ' => 'Შ',\n  'ჩ' => 'Ჩ',\n  'ც' => 'Ც',\n  'ძ' => 'Ძ',\n  'წ' => 'Წ',\n  'ჭ' => 'Ჭ',\n  'ხ' => 'Ხ',\n  'ჯ' => 'Ჯ',\n  'ჰ' => 'Ჰ',\n  'ჱ' => 'Ჱ',\n  'ჲ' => 'Ჲ',\n  'ჳ' => 'Ჳ',\n  'ჴ' => 'Ჴ',\n  'ჵ' => 'Ჵ',\n  'ჶ' => 'Ჶ',\n  'ჷ' => 'Ჷ',\n  'ჸ' => 'Ჸ',\n  'ჹ' => 'Ჹ',\n  'ჺ' => 'Ჺ',\n  'ჽ' => 'Ჽ',\n  'ჾ' => 'Ჾ',\n  'ჿ' => 'Ჿ',\n  'ᏸ' => 'Ᏸ',\n  'ᏹ' => 'Ᏹ',\n  'ᏺ' => 'Ᏺ',\n  'ᏻ' => 'Ᏻ',\n  'ᏼ' => 'Ᏼ',\n  'ᏽ' => 'Ᏽ',\n  'ᲀ' => 'В',\n  'ᲁ' => 'Д',\n  'ᲂ' => 'О',\n  'ᲃ' => 'С',\n  'ᲄ' => 'Т',\n  'ᲅ' => 'Т',\n  'ᲆ' => 'Ъ',\n  'ᲇ' => 'Ѣ',\n  'ᲈ' => 'Ꙋ',\n  'ᵹ' => 'Ᵹ',\n  'ᵽ' => 'Ᵽ',\n  'ᶎ' => 'Ᶎ',\n  'ḁ' => 'Ḁ',\n  'ḃ' => 'Ḃ',\n  'ḅ' => 'Ḅ',\n  'ḇ' => 'Ḇ',\n  'ḉ' => 'Ḉ',\n  'ḋ' => 'Ḋ',\n  'ḍ' => 'Ḍ',\n  'ḏ' => 'Ḏ',\n  'ḑ' => 'Ḑ',\n  'ḓ' => 'Ḓ',\n  'ḕ' => 'Ḕ',\n  'ḗ' => 'Ḗ',\n  'ḙ' => 'Ḙ',\n  'ḛ' => 'Ḛ',\n  'ḝ' => 'Ḝ',\n  'ḟ' => 'Ḟ',\n  'ḡ' => 'Ḡ',\n  'ḣ' => 'Ḣ',\n  'ḥ' => 'Ḥ',\n  'ḧ' => 'Ḧ',\n  'ḩ' => 'Ḩ',\n  'ḫ' => 'Ḫ',\n  'ḭ' => 'Ḭ',\n  'ḯ' => 'Ḯ',\n  'ḱ' => 'Ḱ',\n  'ḳ' => 'Ḳ',\n  'ḵ' => 'Ḵ',\n  'ḷ' => 'Ḷ',\n  'ḹ' => 'Ḹ',\n  'ḻ' => 'Ḻ',\n  'ḽ' => 'Ḽ',\n  'ḿ' => 'Ḿ',\n  'ṁ' => 'Ṁ',\n  'ṃ' => 'Ṃ',\n  'ṅ' => 'Ṅ',\n  'ṇ' => 'Ṇ',\n  'ṉ' => 'Ṉ',\n  'ṋ' => 'Ṋ',\n  'ṍ' => 'Ṍ',\n  'ṏ' => 'Ṏ',\n  'ṑ' => 'Ṑ',\n  'ṓ' => 'Ṓ',\n  'ṕ' => 'Ṕ',\n  'ṗ' => 'Ṗ',\n  'ṙ' => 'Ṙ',\n  'ṛ' => 'Ṛ',\n  'ṝ' => 'Ṝ',\n  'ṟ' => 'Ṟ',\n  'ṡ' => 'Ṡ',\n  'ṣ' => 'Ṣ',\n  'ṥ' => 'Ṥ',\n  'ṧ' => 'Ṧ',\n  'ṩ' => 'Ṩ',\n  'ṫ' => 'Ṫ',\n  'ṭ' => 'Ṭ',\n  'ṯ' => 'Ṯ',\n  'ṱ' => 'Ṱ',\n  'ṳ' => 'Ṳ',\n  'ṵ' => 'Ṵ',\n  'ṷ' => 'Ṷ',\n  'ṹ' => 'Ṹ',\n  'ṻ' => 'Ṻ',\n  'ṽ' => 'Ṽ',\n  'ṿ' => 'Ṿ',\n  'ẁ' => 'Ẁ',\n  'ẃ' => 'Ẃ',\n  'ẅ' => 'Ẅ',\n  'ẇ' => 'Ẇ',\n  'ẉ' => 'Ẉ',\n  'ẋ' => 'Ẋ',\n  'ẍ' => 'Ẍ',\n  'ẏ' => 'Ẏ',\n  'ẑ' => 'Ẑ',\n  'ẓ' => 'Ẓ',\n  'ẕ' => 'Ẕ',\n  'ẛ' => 'Ṡ',\n  'ạ' => 'Ạ',\n  'ả' => 'Ả',\n  'ấ' => 'Ấ',\n  'ầ' => 'Ầ',\n  'ẩ' => 'Ẩ',\n  'ẫ' => 'Ẫ',\n  'ậ' => 'Ậ',\n  'ắ' => 'Ắ',\n  'ằ' => 'Ằ',\n  'ẳ' => 'Ẳ',\n  'ẵ' => 'Ẵ',\n  'ặ' => 'Ặ',\n  'ẹ' => 'Ẹ',\n  'ẻ' => 'Ẻ',\n  'ẽ' => 'Ẽ',\n  'ế' => 'Ế',\n  'ề' => 'Ề',\n  'ể' => 'Ể',\n  'ễ' => 'Ễ',\n  'ệ' => 'Ệ',\n  'ỉ' => 'Ỉ',\n  'ị' => 'Ị',\n  'ọ' => 'Ọ',\n  'ỏ' => 'Ỏ',\n  'ố' => 'Ố',\n  'ồ' => 'Ồ',\n  'ổ' => 'Ổ',\n  'ỗ' => 'Ỗ',\n  'ộ' => 'Ộ',\n  'ớ' => 'Ớ',\n  'ờ' => 'Ờ',\n  'ở' => 'Ở',\n  'ỡ' => 'Ỡ',\n  'ợ' => 'Ợ',\n  'ụ' => 'Ụ',\n  'ủ' => 'Ủ',\n  'ứ' => 'Ứ',\n  'ừ' => 'Ừ',\n  'ử' => 'Ử',\n  'ữ' => 'Ữ',\n  'ự' => 'Ự',\n  'ỳ' => 'Ỳ',\n  'ỵ' => 'Ỵ',\n  'ỷ' => 'Ỷ',\n  'ỹ' => 'Ỹ',\n  'ỻ' => 'Ỻ',\n  'ỽ' => 'Ỽ',\n  'ỿ' => 'Ỿ',\n  'ἀ' => 'Ἀ',\n  'ἁ' => 'Ἁ',\n  'ἂ' => 'Ἂ',\n  'ἃ' => 'Ἃ',\n  'ἄ' => 'Ἄ',\n  'ἅ' => 'Ἅ',\n  'ἆ' => 'Ἆ',\n  'ἇ' => 'Ἇ',\n  'ἐ' => 'Ἐ',\n  'ἑ' => 'Ἑ',\n  'ἒ' => 'Ἒ',\n  'ἓ' => 'Ἓ',\n  'ἔ' => 'Ἔ',\n  'ἕ' => 'Ἕ',\n  'ἠ' => 'Ἠ',\n  'ἡ' => 'Ἡ',\n  'ἢ' => 'Ἢ',\n  'ἣ' => 'Ἣ',\n  'ἤ' => 'Ἤ',\n  'ἥ' => 'Ἥ',\n  'ἦ' => 'Ἦ',\n  'ἧ' => 'Ἧ',\n  'ἰ' => 'Ἰ',\n  'ἱ' => 'Ἱ',\n  'ἲ' => 'Ἲ',\n  'ἳ' => 'Ἳ',\n  'ἴ' => 'Ἴ',\n  'ἵ' => 'Ἵ',\n  'ἶ' => 'Ἶ',\n  'ἷ' => 'Ἷ',\n  'ὀ' => 'Ὀ',\n  'ὁ' => 'Ὁ',\n  'ὂ' => 'Ὂ',\n  'ὃ' => 'Ὃ',\n  'ὄ' => 'Ὄ',\n  'ὅ' => 'Ὅ',\n  'ὑ' => 'Ὑ',\n  'ὓ' => 'Ὓ',\n  'ὕ' => 'Ὕ',\n  'ὗ' => 'Ὗ',\n  'ὠ' => 'Ὠ',\n  'ὡ' => 'Ὡ',\n  'ὢ' => 'Ὢ',\n  'ὣ' => 'Ὣ',\n  'ὤ' => 'Ὤ',\n  'ὥ' => 'Ὥ',\n  'ὦ' => 'Ὦ',\n  'ὧ' => 'Ὧ',\n  'ὰ' => 'Ὰ',\n  'ά' => 'Ά',\n  'ὲ' => 'Ὲ',\n  'έ' => 'Έ',\n  'ὴ' => 'Ὴ',\n  'ή' => 'Ή',\n  'ὶ' => 'Ὶ',\n  'ί' => 'Ί',\n  'ὸ' => 'Ὸ',\n  'ό' => 'Ό',\n  'ὺ' => 'Ὺ',\n  'ύ' => 'Ύ',\n  'ὼ' => 'Ὼ',\n  'ώ' => 'Ώ',\n  'ᾀ' => 'ἈΙ',\n  'ᾁ' => 'ἉΙ',\n  'ᾂ' => 'ἊΙ',\n  'ᾃ' => 'ἋΙ',\n  'ᾄ' => 'ἌΙ',\n  'ᾅ' => 'ἍΙ',\n  'ᾆ' => 'ἎΙ',\n  'ᾇ' => 'ἏΙ',\n  'ᾐ' => 'ἨΙ',\n  'ᾑ' => 'ἩΙ',\n  'ᾒ' => 'ἪΙ',\n  'ᾓ' => 'ἫΙ',\n  'ᾔ' => 'ἬΙ',\n  'ᾕ' => 'ἭΙ',\n  'ᾖ' => 'ἮΙ',\n  'ᾗ' => 'ἯΙ',\n  'ᾠ' => 'ὨΙ',\n  'ᾡ' => 'ὩΙ',\n  'ᾢ' => 'ὪΙ',\n  'ᾣ' => 'ὫΙ',\n  'ᾤ' => 'ὬΙ',\n  'ᾥ' => 'ὭΙ',\n  'ᾦ' => 'ὮΙ',\n  'ᾧ' => 'ὯΙ',\n  'ᾰ' => 'Ᾰ',\n  'ᾱ' => 'Ᾱ',\n  'ᾳ' => 'ΑΙ',\n  'ι' => 'Ι',\n  'ῃ' => 'ΗΙ',\n  'ῐ' => 'Ῐ',\n  'ῑ' => 'Ῑ',\n  'ῠ' => 'Ῠ',\n  'ῡ' => 'Ῡ',\n  'ῥ' => 'Ῥ',\n  'ῳ' => 'ΩΙ',\n  'ⅎ' => 'Ⅎ',\n  'ⅰ' => 'Ⅰ',\n  'ⅱ' => 'Ⅱ',\n  'ⅲ' => 'Ⅲ',\n  'ⅳ' => 'Ⅳ',\n  'ⅴ' => 'Ⅴ',\n  'ⅵ' => 'Ⅵ',\n  'ⅶ' => 'Ⅶ',\n  'ⅷ' => 'Ⅷ',\n  'ⅸ' => 'Ⅸ',\n  'ⅹ' => 'Ⅹ',\n  'ⅺ' => 'Ⅺ',\n  'ⅻ' => 'Ⅻ',\n  'ⅼ' => 'Ⅼ',\n  'ⅽ' => 'Ⅽ',\n  'ⅾ' => 'Ⅾ',\n  'ⅿ' => 'Ⅿ',\n  'ↄ' => 'Ↄ',\n  'ⓐ' => 'Ⓐ',\n  'ⓑ' => 'Ⓑ',\n  'ⓒ' => 'Ⓒ',\n  'ⓓ' => 'Ⓓ',\n  'ⓔ' => 'Ⓔ',\n  'ⓕ' => 'Ⓕ',\n  'ⓖ' => 'Ⓖ',\n  'ⓗ' => 'Ⓗ',\n  'ⓘ' => 'Ⓘ',\n  'ⓙ' => 'Ⓙ',\n  'ⓚ' => 'Ⓚ',\n  'ⓛ' => 'Ⓛ',\n  'ⓜ' => 'Ⓜ',\n  'ⓝ' => 'Ⓝ',\n  'ⓞ' => 'Ⓞ',\n  'ⓟ' => 'Ⓟ',\n  'ⓠ' => 'Ⓠ',\n  'ⓡ' => 'Ⓡ',\n  'ⓢ' => 'Ⓢ',\n  'ⓣ' => 'Ⓣ',\n  'ⓤ' => 'Ⓤ',\n  'ⓥ' => 'Ⓥ',\n  'ⓦ' => 'Ⓦ',\n  'ⓧ' => 'Ⓧ',\n  'ⓨ' => 'Ⓨ',\n  'ⓩ' => 'Ⓩ',\n  'ⰰ' => 'Ⰰ',\n  'ⰱ' => 'Ⰱ',\n  'ⰲ' => 'Ⰲ',\n  'ⰳ' => 'Ⰳ',\n  'ⰴ' => 'Ⰴ',\n  'ⰵ' => 'Ⰵ',\n  'ⰶ' => 'Ⰶ',\n  'ⰷ' => 'Ⰷ',\n  'ⰸ' => 'Ⰸ',\n  'ⰹ' => 'Ⰹ',\n  'ⰺ' => 'Ⰺ',\n  'ⰻ' => 'Ⰻ',\n  'ⰼ' => 'Ⰼ',\n  'ⰽ' => 'Ⰽ',\n  'ⰾ' => 'Ⰾ',\n  'ⰿ' => 'Ⰿ',\n  'ⱀ' => 'Ⱀ',\n  'ⱁ' => 'Ⱁ',\n  'ⱂ' => 'Ⱂ',\n  'ⱃ' => 'Ⱃ',\n  'ⱄ' => 'Ⱄ',\n  'ⱅ' => 'Ⱅ',\n  'ⱆ' => 'Ⱆ',\n  'ⱇ' => 'Ⱇ',\n  'ⱈ' => 'Ⱈ',\n  'ⱉ' => 'Ⱉ',\n  'ⱊ' => 'Ⱊ',\n  'ⱋ' => 'Ⱋ',\n  'ⱌ' => 'Ⱌ',\n  'ⱍ' => 'Ⱍ',\n  'ⱎ' => 'Ⱎ',\n  'ⱏ' => 'Ⱏ',\n  'ⱐ' => 'Ⱐ',\n  'ⱑ' => 'Ⱑ',\n  'ⱒ' => 'Ⱒ',\n  'ⱓ' => 'Ⱓ',\n  'ⱔ' => 'Ⱔ',\n  'ⱕ' => 'Ⱕ',\n  'ⱖ' => 'Ⱖ',\n  'ⱗ' => 'Ⱗ',\n  'ⱘ' => 'Ⱘ',\n  'ⱙ' => 'Ⱙ',\n  'ⱚ' => 'Ⱚ',\n  'ⱛ' => 'Ⱛ',\n  'ⱜ' => 'Ⱜ',\n  'ⱝ' => 'Ⱝ',\n  'ⱞ' => 'Ⱞ',\n  'ⱡ' => 'Ⱡ',\n  'ⱥ' => 'Ⱥ',\n  'ⱦ' => 'Ⱦ',\n  'ⱨ' => 'Ⱨ',\n  'ⱪ' => 'Ⱪ',\n  'ⱬ' => 'Ⱬ',\n  'ⱳ' => 'Ⱳ',\n  'ⱶ' => 'Ⱶ',\n  'ⲁ' => 'Ⲁ',\n  'ⲃ' => 'Ⲃ',\n  'ⲅ' => 'Ⲅ',\n  'ⲇ' => 'Ⲇ',\n  'ⲉ' => 'Ⲉ',\n  'ⲋ' => 'Ⲋ',\n  'ⲍ' => 'Ⲍ',\n  'ⲏ' => 'Ⲏ',\n  'ⲑ' => 'Ⲑ',\n  'ⲓ' => 'Ⲓ',\n  'ⲕ' => 'Ⲕ',\n  'ⲗ' => 'Ⲗ',\n  'ⲙ' => 'Ⲙ',\n  'ⲛ' => 'Ⲛ',\n  'ⲝ' => 'Ⲝ',\n  'ⲟ' => 'Ⲟ',\n  'ⲡ' => 'Ⲡ',\n  'ⲣ' => 'Ⲣ',\n  'ⲥ' => 'Ⲥ',\n  'ⲧ' => 'Ⲧ',\n  'ⲩ' => 'Ⲩ',\n  'ⲫ' => 'Ⲫ',\n  'ⲭ' => 'Ⲭ',\n  'ⲯ' => 'Ⲯ',\n  'ⲱ' => 'Ⲱ',\n  'ⲳ' => 'Ⲳ',\n  'ⲵ' => 'Ⲵ',\n  'ⲷ' => 'Ⲷ',\n  'ⲹ' => 'Ⲹ',\n  'ⲻ' => 'Ⲻ',\n  'ⲽ' => 'Ⲽ',\n  'ⲿ' => 'Ⲿ',\n  'ⳁ' => 'Ⳁ',\n  'ⳃ' => 'Ⳃ',\n  'ⳅ' => 'Ⳅ',\n  'ⳇ' => 'Ⳇ',\n  'ⳉ' => 'Ⳉ',\n  'ⳋ' => 'Ⳋ',\n  'ⳍ' => 'Ⳍ',\n  'ⳏ' => 'Ⳏ',\n  'ⳑ' => 'Ⳑ',\n  'ⳓ' => 'Ⳓ',\n  'ⳕ' => 'Ⳕ',\n  'ⳗ' => 'Ⳗ',\n  'ⳙ' => 'Ⳙ',\n  'ⳛ' => 'Ⳛ',\n  'ⳝ' => 'Ⳝ',\n  'ⳟ' => 'Ⳟ',\n  'ⳡ' => 'Ⳡ',\n  'ⳣ' => 'Ⳣ',\n  'ⳬ' => 'Ⳬ',\n  'ⳮ' => 'Ⳮ',\n  'ⳳ' => 'Ⳳ',\n  'ⴀ' => 'Ⴀ',\n  'ⴁ' => 'Ⴁ',\n  'ⴂ' => 'Ⴂ',\n  'ⴃ' => 'Ⴃ',\n  'ⴄ' => 'Ⴄ',\n  'ⴅ' => 'Ⴅ',\n  'ⴆ' => 'Ⴆ',\n  'ⴇ' => 'Ⴇ',\n  'ⴈ' => 'Ⴈ',\n  'ⴉ' => 'Ⴉ',\n  'ⴊ' => 'Ⴊ',\n  'ⴋ' => 'Ⴋ',\n  'ⴌ' => 'Ⴌ',\n  'ⴍ' => 'Ⴍ',\n  'ⴎ' => 'Ⴎ',\n  'ⴏ' => 'Ⴏ',\n  'ⴐ' => 'Ⴐ',\n  'ⴑ' => 'Ⴑ',\n  'ⴒ' => 'Ⴒ',\n  'ⴓ' => 'Ⴓ',\n  'ⴔ' => 'Ⴔ',\n  'ⴕ' => 'Ⴕ',\n  'ⴖ' => 'Ⴖ',\n  'ⴗ' => 'Ⴗ',\n  'ⴘ' => 'Ⴘ',\n  'ⴙ' => 'Ⴙ',\n  'ⴚ' => 'Ⴚ',\n  'ⴛ' => 'Ⴛ',\n  'ⴜ' => 'Ⴜ',\n  'ⴝ' => 'Ⴝ',\n  'ⴞ' => 'Ⴞ',\n  'ⴟ' => 'Ⴟ',\n  'ⴠ' => 'Ⴠ',\n  'ⴡ' => 'Ⴡ',\n  'ⴢ' => 'Ⴢ',\n  'ⴣ' => 'Ⴣ',\n  'ⴤ' => 'Ⴤ',\n  'ⴥ' => 'Ⴥ',\n  'ⴧ' => 'Ⴧ',\n  'ⴭ' => 'Ⴭ',\n  'ꙁ' => 'Ꙁ',\n  'ꙃ' => 'Ꙃ',\n  'ꙅ' => 'Ꙅ',\n  'ꙇ' => 'Ꙇ',\n  'ꙉ' => 'Ꙉ',\n  'ꙋ' => 'Ꙋ',\n  'ꙍ' => 'Ꙍ',\n  'ꙏ' => 'Ꙏ',\n  'ꙑ' => 'Ꙑ',\n  'ꙓ' => 'Ꙓ',\n  'ꙕ' => 'Ꙕ',\n  'ꙗ' => 'Ꙗ',\n  'ꙙ' => 'Ꙙ',\n  'ꙛ' => 'Ꙛ',\n  'ꙝ' => 'Ꙝ',\n  'ꙟ' => 'Ꙟ',\n  'ꙡ' => 'Ꙡ',\n  'ꙣ' => 'Ꙣ',\n  'ꙥ' => 'Ꙥ',\n  'ꙧ' => 'Ꙧ',\n  'ꙩ' => 'Ꙩ',\n  'ꙫ' => 'Ꙫ',\n  'ꙭ' => 'Ꙭ',\n  'ꚁ' => 'Ꚁ',\n  'ꚃ' => 'Ꚃ',\n  'ꚅ' => 'Ꚅ',\n  'ꚇ' => 'Ꚇ',\n  'ꚉ' => 'Ꚉ',\n  'ꚋ' => 'Ꚋ',\n  'ꚍ' => 'Ꚍ',\n  'ꚏ' => 'Ꚏ',\n  'ꚑ' => 'Ꚑ',\n  'ꚓ' => 'Ꚓ',\n  'ꚕ' => 'Ꚕ',\n  'ꚗ' => 'Ꚗ',\n  'ꚙ' => 'Ꚙ',\n  'ꚛ' => 'Ꚛ',\n  'ꜣ' => 'Ꜣ',\n  'ꜥ' => 'Ꜥ',\n  'ꜧ' => 'Ꜧ',\n  'ꜩ' => 'Ꜩ',\n  'ꜫ' => 'Ꜫ',\n  'ꜭ' => 'Ꜭ',\n  'ꜯ' => 'Ꜯ',\n  'ꜳ' => 'Ꜳ',\n  'ꜵ' => 'Ꜵ',\n  'ꜷ' => 'Ꜷ',\n  'ꜹ' => 'Ꜹ',\n  'ꜻ' => 'Ꜻ',\n  'ꜽ' => 'Ꜽ',\n  'ꜿ' => 'Ꜿ',\n  'ꝁ' => 'Ꝁ',\n  'ꝃ' => 'Ꝃ',\n  'ꝅ' => 'Ꝅ',\n  'ꝇ' => 'Ꝇ',\n  'ꝉ' => 'Ꝉ',\n  'ꝋ' => 'Ꝋ',\n  'ꝍ' => 'Ꝍ',\n  'ꝏ' => 'Ꝏ',\n  'ꝑ' => 'Ꝑ',\n  'ꝓ' => 'Ꝓ',\n  'ꝕ' => 'Ꝕ',\n  'ꝗ' => 'Ꝗ',\n  'ꝙ' => 'Ꝙ',\n  'ꝛ' => 'Ꝛ',\n  'ꝝ' => 'Ꝝ',\n  'ꝟ' => 'Ꝟ',\n  'ꝡ' => 'Ꝡ',\n  'ꝣ' => 'Ꝣ',\n  'ꝥ' => 'Ꝥ',\n  'ꝧ' => 'Ꝧ',\n  'ꝩ' => 'Ꝩ',\n  'ꝫ' => 'Ꝫ',\n  'ꝭ' => 'Ꝭ',\n  'ꝯ' => 'Ꝯ',\n  'ꝺ' => 'Ꝺ',\n  'ꝼ' => 'Ꝼ',\n  'ꝿ' => 'Ꝿ',\n  'ꞁ' => 'Ꞁ',\n  'ꞃ' => 'Ꞃ',\n  'ꞅ' => 'Ꞅ',\n  'ꞇ' => 'Ꞇ',\n  'ꞌ' => 'Ꞌ',\n  'ꞑ' => 'Ꞑ',\n  'ꞓ' => 'Ꞓ',\n  'ꞔ' => 'Ꞔ',\n  'ꞗ' => 'Ꞗ',\n  'ꞙ' => 'Ꞙ',\n  'ꞛ' => 'Ꞛ',\n  'ꞝ' => 'Ꞝ',\n  'ꞟ' => 'Ꞟ',\n  'ꞡ' => 'Ꞡ',\n  'ꞣ' => 'Ꞣ',\n  'ꞥ' => 'Ꞥ',\n  'ꞧ' => 'Ꞧ',\n  'ꞩ' => 'Ꞩ',\n  'ꞵ' => 'Ꞵ',\n  'ꞷ' => 'Ꞷ',\n  'ꞹ' => 'Ꞹ',\n  'ꞻ' => 'Ꞻ',\n  'ꞽ' => 'Ꞽ',\n  'ꞿ' => 'Ꞿ',\n  'ꟃ' => 'Ꟃ',\n  'ꟈ' => 'Ꟈ',\n  'ꟊ' => 'Ꟊ',\n  'ꟶ' => 'Ꟶ',\n  'ꭓ' => 'Ꭓ',\n  'ꭰ' => 'Ꭰ',\n  'ꭱ' => 'Ꭱ',\n  'ꭲ' => 'Ꭲ',\n  'ꭳ' => 'Ꭳ',\n  'ꭴ' => 'Ꭴ',\n  'ꭵ' => 'Ꭵ',\n  'ꭶ' => 'Ꭶ',\n  'ꭷ' => 'Ꭷ',\n  'ꭸ' => 'Ꭸ',\n  'ꭹ' => 'Ꭹ',\n  'ꭺ' => 'Ꭺ',\n  'ꭻ' => 'Ꭻ',\n  'ꭼ' => 'Ꭼ',\n  'ꭽ' => 'Ꭽ',\n  'ꭾ' => 'Ꭾ',\n  'ꭿ' => 'Ꭿ',\n  'ꮀ' => 'Ꮀ',\n  'ꮁ' => 'Ꮁ',\n  'ꮂ' => 'Ꮂ',\n  'ꮃ' => 'Ꮃ',\n  'ꮄ' => 'Ꮄ',\n  'ꮅ' => 'Ꮅ',\n  'ꮆ' => 'Ꮆ',\n  'ꮇ' => 'Ꮇ',\n  'ꮈ' => 'Ꮈ',\n  'ꮉ' => 'Ꮉ',\n  'ꮊ' => 'Ꮊ',\n  'ꮋ' => 'Ꮋ',\n  'ꮌ' => 'Ꮌ',\n  'ꮍ' => 'Ꮍ',\n  'ꮎ' => 'Ꮎ',\n  'ꮏ' => 'Ꮏ',\n  'ꮐ' => 'Ꮐ',\n  'ꮑ' => 'Ꮑ',\n  'ꮒ' => 'Ꮒ',\n  'ꮓ' => 'Ꮓ',\n  'ꮔ' => 'Ꮔ',\n  'ꮕ' => 'Ꮕ',\n  'ꮖ' => 'Ꮖ',\n  'ꮗ' => 'Ꮗ',\n  'ꮘ' => 'Ꮘ',\n  'ꮙ' => 'Ꮙ',\n  'ꮚ' => 'Ꮚ',\n  'ꮛ' => 'Ꮛ',\n  'ꮜ' => 'Ꮜ',\n  'ꮝ' => 'Ꮝ',\n  'ꮞ' => 'Ꮞ',\n  'ꮟ' => 'Ꮟ',\n  'ꮠ' => 'Ꮠ',\n  'ꮡ' => 'Ꮡ',\n  'ꮢ' => 'Ꮢ',\n  'ꮣ' => 'Ꮣ',\n  'ꮤ' => 'Ꮤ',\n  'ꮥ' => 'Ꮥ',\n  'ꮦ' => 'Ꮦ',\n  'ꮧ' => 'Ꮧ',\n  'ꮨ' => 'Ꮨ',\n  'ꮩ' => 'Ꮩ',\n  'ꮪ' => 'Ꮪ',\n  'ꮫ' => 'Ꮫ',\n  'ꮬ' => 'Ꮬ',\n  'ꮭ' => 'Ꮭ',\n  'ꮮ' => 'Ꮮ',\n  'ꮯ' => 'Ꮯ',\n  'ꮰ' => 'Ꮰ',\n  'ꮱ' => 'Ꮱ',\n  'ꮲ' => 'Ꮲ',\n  'ꮳ' => 'Ꮳ',\n  'ꮴ' => 'Ꮴ',\n  'ꮵ' => 'Ꮵ',\n  'ꮶ' => 'Ꮶ',\n  'ꮷ' => 'Ꮷ',\n  'ꮸ' => 'Ꮸ',\n  'ꮹ' => 'Ꮹ',\n  'ꮺ' => 'Ꮺ',\n  'ꮻ' => 'Ꮻ',\n  'ꮼ' => 'Ꮼ',\n  'ꮽ' => 'Ꮽ',\n  'ꮾ' => 'Ꮾ',\n  'ꮿ' => 'Ꮿ',\n  'ａ' => 'Ａ',\n  'ｂ' => 'Ｂ',\n  'ｃ' => 'Ｃ',\n  'ｄ' => 'Ｄ',\n  'ｅ' => 'Ｅ',\n  'ｆ' => 'Ｆ',\n  'ｇ' => 'Ｇ',\n  'ｈ' => 'Ｈ',\n  'ｉ' => 'Ｉ',\n  'ｊ' => 'Ｊ',\n  'ｋ' => 'Ｋ',\n  'ｌ' => 'Ｌ',\n  'ｍ' => 'Ｍ',\n  'ｎ' => 'Ｎ',\n  'ｏ' => 'Ｏ',\n  'ｐ' => 'Ｐ',\n  'ｑ' => 'Ｑ',\n  'ｒ' => 'Ｒ',\n  'ｓ' => 'Ｓ',\n  'ｔ' => 'Ｔ',\n  'ｕ' => 'Ｕ',\n  'ｖ' => 'Ｖ',\n  'ｗ' => 'Ｗ',\n  'ｘ' => 'Ｘ',\n  'ｙ' => 'Ｙ',\n  'ｚ' => 'Ｚ',\n  '𐐨' => '𐐀',\n  '𐐩' => '𐐁',\n  '𐐪' => '𐐂',\n  '𐐫' => '𐐃',\n  '𐐬' => '𐐄',\n  '𐐭' => '𐐅',\n  '𐐮' => '𐐆',\n  '𐐯' => '𐐇',\n  '𐐰' => '𐐈',\n  '𐐱' => '𐐉',\n  '𐐲' => '𐐊',\n  '𐐳' => '𐐋',\n  '𐐴' => '𐐌',\n  '𐐵' => '𐐍',\n  '𐐶' => '𐐎',\n  '𐐷' => '𐐏',\n  '𐐸' => '𐐐',\n  '𐐹' => '𐐑',\n  '𐐺' => '𐐒',\n  '𐐻' => '𐐓',\n  '𐐼' => '𐐔',\n  '𐐽' => '𐐕',\n  '𐐾' => '𐐖',\n  '𐐿' => '𐐗',\n  '𐑀' => '𐐘',\n  '𐑁' => '𐐙',\n  '𐑂' => '𐐚',\n  '𐑃' => '𐐛',\n  '𐑄' => '𐐜',\n  '𐑅' => '𐐝',\n  '𐑆' => '𐐞',\n  '𐑇' => '𐐟',\n  '𐑈' => '𐐠',\n  '𐑉' => '𐐡',\n  '𐑊' => '𐐢',\n  '𐑋' => '𐐣',\n  '𐑌' => '𐐤',\n  '𐑍' => '𐐥',\n  '𐑎' => '𐐦',\n  '𐑏' => '𐐧',\n  '𐓘' => '𐒰',\n  '𐓙' => '𐒱',\n  '𐓚' => '𐒲',\n  '𐓛' => '𐒳',\n  '𐓜' => '𐒴',\n  '𐓝' => '𐒵',\n  '𐓞' => '𐒶',\n  '𐓟' => '𐒷',\n  '𐓠' => '𐒸',\n  '𐓡' => '𐒹',\n  '𐓢' => '𐒺',\n  '𐓣' => '𐒻',\n  '𐓤' => '𐒼',\n  '𐓥' => '𐒽',\n  '𐓦' => '𐒾',\n  '𐓧' => '𐒿',\n  '𐓨' => '𐓀',\n  '𐓩' => '𐓁',\n  '𐓪' => '𐓂',\n  '𐓫' => '𐓃',\n  '𐓬' => '𐓄',\n  '𐓭' => '𐓅',\n  '𐓮' => '𐓆',\n  '𐓯' => '𐓇',\n  '𐓰' => '𐓈',\n  '𐓱' => '𐓉',\n  '𐓲' => '𐓊',\n  '𐓳' => '𐓋',\n  '𐓴' => '𐓌',\n  '𐓵' => '𐓍',\n  '𐓶' => '𐓎',\n  '𐓷' => '𐓏',\n  '𐓸' => '𐓐',\n  '𐓹' => '𐓑',\n  '𐓺' => '𐓒',\n  '𐓻' => '𐓓',\n  '𐳀' => '𐲀',\n  '𐳁' => '𐲁',\n  '𐳂' => '𐲂',\n  '𐳃' => '𐲃',\n  '𐳄' => '𐲄',\n  '𐳅' => '𐲅',\n  '𐳆' => '𐲆',\n  '𐳇' => '𐲇',\n  '𐳈' => '𐲈',\n  '𐳉' => '𐲉',\n  '𐳊' => '𐲊',\n  '𐳋' => '𐲋',\n  '𐳌' => '𐲌',\n  '𐳍' => '𐲍',\n  '𐳎' => '𐲎',\n  '𐳏' => '𐲏',\n  '𐳐' => '𐲐',\n  '𐳑' => '𐲑',\n  '𐳒' => '𐲒',\n  '𐳓' => '𐲓',\n  '𐳔' => '𐲔',\n  '𐳕' => '𐲕',\n  '𐳖' => '𐲖',\n  '𐳗' => '𐲗',\n  '𐳘' => '𐲘',\n  '𐳙' => '𐲙',\n  '𐳚' => '𐲚',\n  '𐳛' => '𐲛',\n  '𐳜' => '𐲜',\n  '𐳝' => '𐲝',\n  '𐳞' => '𐲞',\n  '𐳟' => '𐲟',\n  '𐳠' => '𐲠',\n  '𐳡' => '𐲡',\n  '𐳢' => '𐲢',\n  '𐳣' => '𐲣',\n  '𐳤' => '𐲤',\n  '𐳥' => '𐲥',\n  '𐳦' => '𐲦',\n  '𐳧' => '𐲧',\n  '𐳨' => '𐲨',\n  '𐳩' => '𐲩',\n  '𐳪' => '𐲪',\n  '𐳫' => '𐲫',\n  '𐳬' => '𐲬',\n  '𐳭' => '𐲭',\n  '𐳮' => '𐲮',\n  '𐳯' => '𐲯',\n  '𐳰' => '𐲰',\n  '𐳱' => '𐲱',\n  '𐳲' => '𐲲',\n  '𑣀' => '𑢠',\n  '𑣁' => '𑢡',\n  '𑣂' => '𑢢',\n  '𑣃' => '𑢣',\n  '𑣄' => '𑢤',\n  '𑣅' => '𑢥',\n  '𑣆' => '𑢦',\n  '𑣇' => '𑢧',\n  '𑣈' => '𑢨',\n  '𑣉' => '𑢩',\n  '𑣊' => '𑢪',\n  '𑣋' => '𑢫',\n  '𑣌' => '𑢬',\n  '𑣍' => '𑢭',\n  '𑣎' => '𑢮',\n  '𑣏' => '𑢯',\n  '𑣐' => '𑢰',\n  '𑣑' => '𑢱',\n  '𑣒' => '𑢲',\n  '𑣓' => '𑢳',\n  '𑣔' => '𑢴',\n  '𑣕' => '𑢵',\n  '𑣖' => '𑢶',\n  '𑣗' => '𑢷',\n  '𑣘' => '𑢸',\n  '𑣙' => '𑢹',\n  '𑣚' => '𑢺',\n  '𑣛' => '𑢻',\n  '𑣜' => '𑢼',\n  '𑣝' => '𑢽',\n  '𑣞' => '𑢾',\n  '𑣟' => '𑢿',\n  '𖹠' => '𖹀',\n  '𖹡' => '𖹁',\n  '𖹢' => '𖹂',\n  '𖹣' => '𖹃',\n  '𖹤' => '𖹄',\n  '𖹥' => '𖹅',\n  '𖹦' => '𖹆',\n  '𖹧' => '𖹇',\n  '𖹨' => '𖹈',\n  '𖹩' => '𖹉',\n  '𖹪' => '𖹊',\n  '𖹫' => '𖹋',\n  '𖹬' => '𖹌',\n  '𖹭' => '𖹍',\n  '𖹮' => '𖹎',\n  '𖹯' => '𖹏',\n  '𖹰' => '𖹐',\n  '𖹱' => '𖹑',\n  '𖹲' => '𖹒',\n  '𖹳' => '𖹓',\n  '𖹴' => '𖹔',\n  '𖹵' => '𖹕',\n  '𖹶' => '𖹖',\n  '𖹷' => '𖹗',\n  '𖹸' => '𖹘',\n  '𖹹' => '𖹙',\n  '𖹺' => '𖹚',\n  '𖹻' => '𖹛',\n  '𖹼' => '𖹜',\n  '𖹽' => '𖹝',\n  '𖹾' => '𖹞',\n  '𖹿' => '𖹟',\n  '𞤢' => '𞤀',\n  '𞤣' => '𞤁',\n  '𞤤' => '𞤂',\n  '𞤥' => '𞤃',\n  '𞤦' => '𞤄',\n  '𞤧' => '𞤅',\n  '𞤨' => '𞤆',\n  '𞤩' => '𞤇',\n  '𞤪' => '𞤈',\n  '𞤫' => '𞤉',\n  '𞤬' => '𞤊',\n  '𞤭' => '𞤋',\n  '𞤮' => '𞤌',\n  '𞤯' => '𞤍',\n  '𞤰' => '𞤎',\n  '𞤱' => '𞤏',\n  '𞤲' => '𞤐',\n  '𞤳' => '𞤑',\n  '𞤴' => '𞤒',\n  '𞤵' => '𞤓',\n  '𞤶' => '𞤔',\n  '𞤷' => '𞤕',\n  '𞤸' => '𞤖',\n  '𞤹' => '𞤗',\n  '𞤺' => '𞤘',\n  '𞤻' => '𞤙',\n  '𞤼' => '𞤚',\n  '𞤽' => '𞤛',\n  '𞤾' => '𞤜',\n  '𞤿' => '𞤝',\n  '𞥀' => '𞤞',\n  '𞥁' => '𞤟',\n  '𞥂' => '𞤠',\n  '𞥃' => '𞤡',\n  'ß' => 'SS',\n  'ﬀ' => 'FF',\n  'ﬁ' => 'FI',\n  'ﬂ' => 'FL',\n  'ﬃ' => 'FFI',\n  'ﬄ' => 'FFL',\n  'ﬅ' => 'ST',\n  'ﬆ' => 'ST',\n  'և' => 'ԵՒ',\n  'ﬓ' => 'ՄՆ',\n  'ﬔ' => 'ՄԵ',\n  'ﬕ' => 'ՄԻ',\n  'ﬖ' => 'ՎՆ',\n  'ﬗ' => 'ՄԽ',\n  'ŉ' => 'ʼN',\n  'ΐ' => 'Ϊ́',\n  'ΰ' => 'Ϋ́',\n  'ǰ' => 'J̌',\n  'ẖ' => 'H̱',\n  'ẗ' => 'T̈',\n  'ẘ' => 'W̊',\n  'ẙ' => 'Y̊',\n  'ẚ' => 'Aʾ',\n  'ὐ' => 'Υ̓',\n  'ὒ' => 'Υ̓̀',\n  'ὔ' => 'Υ̓́',\n  'ὖ' => 'Υ̓͂',\n  'ᾶ' => 'Α͂',\n  'ῆ' => 'Η͂',\n  'ῒ' => 'Ϊ̀',\n  'ΐ' => 'Ϊ́',\n  'ῖ' => 'Ι͂',\n  'ῗ' => 'Ϊ͂',\n  'ῢ' => 'Ϋ̀',\n  'ΰ' => 'Ϋ́',\n  'ῤ' => 'Ρ̓',\n  'ῦ' => 'Υ͂',\n  'ῧ' => 'Ϋ͂',\n  'ῶ' => 'Ω͂',\n  'ᾈ' => 'ἈΙ',\n  'ᾉ' => 'ἉΙ',\n  'ᾊ' => 'ἊΙ',\n  'ᾋ' => 'ἋΙ',\n  'ᾌ' => 'ἌΙ',\n  'ᾍ' => 'ἍΙ',\n  'ᾎ' => 'ἎΙ',\n  'ᾏ' => 'ἏΙ',\n  'ᾘ' => 'ἨΙ',\n  'ᾙ' => 'ἩΙ',\n  'ᾚ' => 'ἪΙ',\n  'ᾛ' => 'ἫΙ',\n  'ᾜ' => 'ἬΙ',\n  'ᾝ' => 'ἭΙ',\n  'ᾞ' => 'ἮΙ',\n  'ᾟ' => 'ἯΙ',\n  'ᾨ' => 'ὨΙ',\n  'ᾩ' => 'ὩΙ',\n  'ᾪ' => 'ὪΙ',\n  'ᾫ' => 'ὫΙ',\n  'ᾬ' => 'ὬΙ',\n  'ᾭ' => 'ὭΙ',\n  'ᾮ' => 'ὮΙ',\n  'ᾯ' => 'ὯΙ',\n  'ᾼ' => 'ΑΙ',\n  'ῌ' => 'ΗΙ',\n  'ῼ' => 'ΩΙ',\n  'ᾲ' => 'ᾺΙ',\n  'ᾴ' => 'ΆΙ',\n  'ῂ' => 'ῊΙ',\n  'ῄ' => 'ΉΙ',\n  'ῲ' => 'ῺΙ',\n  'ῴ' => 'ΏΙ',\n  'ᾷ' => 'Α͂Ι',\n  'ῇ' => 'Η͂Ι',\n  'ῷ' => 'Ω͂Ι',\n);\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-mbstring/bootstrap.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nuse Symfony\\Polyfill\\Mbstring as p;\n\nif (\\PHP_VERSION_ID >= 80000) {\n    return require __DIR__.'/bootstrap80.php';\n}\n\nif (!function_exists('mb_convert_encoding')) {\n    function mb_convert_encoding($string, $to_encoding, $from_encoding = null) { return p\\Mbstring::mb_convert_encoding($string, $to_encoding, $from_encoding); }\n}\nif (!function_exists('mb_decode_mimeheader')) {\n    function mb_decode_mimeheader($string) { return p\\Mbstring::mb_decode_mimeheader($string); }\n}\nif (!function_exists('mb_encode_mimeheader')) {\n    function mb_encode_mimeheader($string, $charset = null, $transfer_encoding = null, $newline = \"\\r\\n\", $indent = 0) { return p\\Mbstring::mb_encode_mimeheader($string, $charset, $transfer_encoding, $newline, $indent); }\n}\nif (!function_exists('mb_decode_numericentity')) {\n    function mb_decode_numericentity($string, $map, $encoding = null) { return p\\Mbstring::mb_decode_numericentity($string, $map, $encoding); }\n}\nif (!function_exists('mb_encode_numericentity')) {\n    function mb_encode_numericentity($string, $map, $encoding = null, $hex = false) { return p\\Mbstring::mb_encode_numericentity($string, $map, $encoding, $hex); }\n}\nif (!function_exists('mb_convert_case')) {\n    function mb_convert_case($string, $mode, $encoding = null) { return p\\Mbstring::mb_convert_case($string, $mode, $encoding); }\n}\nif (!function_exists('mb_internal_encoding')) {\n    function mb_internal_encoding($encoding = null) { return p\\Mbstring::mb_internal_encoding($encoding); }\n}\nif (!function_exists('mb_language')) {\n    function mb_language($language = null) { return p\\Mbstring::mb_language($language); }\n}\nif (!function_exists('mb_list_encodings')) {\n    function mb_list_encodings() { return p\\Mbstring::mb_list_encodings(); }\n}\nif (!function_exists('mb_encoding_aliases')) {\n    function mb_encoding_aliases($encoding) { return p\\Mbstring::mb_encoding_aliases($encoding); }\n}\nif (!function_exists('mb_check_encoding')) {\n    function mb_check_encoding($value = null, $encoding = null) { return p\\Mbstring::mb_check_encoding($value, $encoding); }\n}\nif (!function_exists('mb_detect_encoding')) {\n    function mb_detect_encoding($string, $encodings = null, $strict = false) { return p\\Mbstring::mb_detect_encoding($string, $encodings, $strict); }\n}\nif (!function_exists('mb_detect_order')) {\n    function mb_detect_order($encoding = null) { return p\\Mbstring::mb_detect_order($encoding); }\n}\nif (!function_exists('mb_parse_str')) {\n    function mb_parse_str($string, &$result = []) { parse_str($string, $result); return (bool) $result; }\n}\nif (!function_exists('mb_strlen')) {\n    function mb_strlen($string, $encoding = null) { return p\\Mbstring::mb_strlen($string, $encoding); }\n}\nif (!function_exists('mb_strpos')) {\n    function mb_strpos($haystack, $needle, $offset = 0, $encoding = null) { return p\\Mbstring::mb_strpos($haystack, $needle, $offset, $encoding); }\n}\nif (!function_exists('mb_strtolower')) {\n    function mb_strtolower($string, $encoding = null) { return p\\Mbstring::mb_strtolower($string, $encoding); }\n}\nif (!function_exists('mb_strtoupper')) {\n    function mb_strtoupper($string, $encoding = null) { return p\\Mbstring::mb_strtoupper($string, $encoding); }\n}\nif (!function_exists('mb_substitute_character')) {\n    function mb_substitute_character($substitute_character = null) { return p\\Mbstring::mb_substitute_character($substitute_character); }\n}\nif (!function_exists('mb_substr')) {\n    function mb_substr($string, $start, $length = 2147483647, $encoding = null) { return p\\Mbstring::mb_substr($string, $start, $length, $encoding); }\n}\nif (!function_exists('mb_stripos')) {\n    function mb_stripos($haystack, $needle, $offset = 0, $encoding = null) { return p\\Mbstring::mb_stripos($haystack, $needle, $offset, $encoding); }\n}\nif (!function_exists('mb_stristr')) {\n    function mb_stristr($haystack, $needle, $before_needle = false, $encoding = null) { return p\\Mbstring::mb_stristr($haystack, $needle, $before_needle, $encoding); }\n}\nif (!function_exists('mb_strrchr')) {\n    function mb_strrchr($haystack, $needle, $before_needle = false, $encoding = null) { return p\\Mbstring::mb_strrchr($haystack, $needle, $before_needle, $encoding); }\n}\nif (!function_exists('mb_strrichr')) {\n    function mb_strrichr($haystack, $needle, $before_needle = false, $encoding = null) { return p\\Mbstring::mb_strrichr($haystack, $needle, $before_needle, $encoding); }\n}\nif (!function_exists('mb_strripos')) {\n    function mb_strripos($haystack, $needle, $offset = 0, $encoding = null) { return p\\Mbstring::mb_strripos($haystack, $needle, $offset, $encoding); }\n}\nif (!function_exists('mb_strrpos')) {\n    function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null) { return p\\Mbstring::mb_strrpos($haystack, $needle, $offset, $encoding); }\n}\nif (!function_exists('mb_strstr')) {\n    function mb_strstr($haystack, $needle, $before_needle = false, $encoding = null) { return p\\Mbstring::mb_strstr($haystack, $needle, $before_needle, $encoding); }\n}\nif (!function_exists('mb_get_info')) {\n    function mb_get_info($type = 'all') { return p\\Mbstring::mb_get_info($type); }\n}\nif (!function_exists('mb_http_output')) {\n    function mb_http_output($encoding = null) { return p\\Mbstring::mb_http_output($encoding); }\n}\nif (!function_exists('mb_strwidth')) {\n    function mb_strwidth($string, $encoding = null) { return p\\Mbstring::mb_strwidth($string, $encoding); }\n}\nif (!function_exists('mb_substr_count')) {\n    function mb_substr_count($haystack, $needle, $encoding = null) { return p\\Mbstring::mb_substr_count($haystack, $needle, $encoding); }\n}\nif (!function_exists('mb_output_handler')) {\n    function mb_output_handler($string, $status) { return p\\Mbstring::mb_output_handler($string, $status); }\n}\nif (!function_exists('mb_http_input')) {\n    function mb_http_input($type = null) { return p\\Mbstring::mb_http_input($type); }\n}\n\nif (!function_exists('mb_convert_variables')) {\n    function mb_convert_variables($to_encoding, $from_encoding, &...$vars) { return p\\Mbstring::mb_convert_variables($to_encoding, $from_encoding, ...$vars); }\n}\n\nif (!function_exists('mb_ord')) {\n    function mb_ord($string, $encoding = null) { return p\\Mbstring::mb_ord($string, $encoding); }\n}\nif (!function_exists('mb_chr')) {\n    function mb_chr($codepoint, $encoding = null) { return p\\Mbstring::mb_chr($codepoint, $encoding); }\n}\nif (!function_exists('mb_scrub')) {\n    function mb_scrub($string, $encoding = null) { $encoding = null === $encoding ? mb_internal_encoding() : $encoding; return mb_convert_encoding($string, $encoding, $encoding); }\n}\nif (!function_exists('mb_str_split')) {\n    function mb_str_split($string, $length = 1, $encoding = null) { return p\\Mbstring::mb_str_split($string, $length, $encoding); }\n}\n\nif (!function_exists('mb_str_pad')) {\n    function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = STR_PAD_RIGHT, ?string $encoding = null): string { return p\\Mbstring::mb_str_pad($string, $length, $pad_string, $pad_type, $encoding); }\n}\n\nif (!function_exists('mb_ucfirst')) {\n    function mb_ucfirst(string $string, ?string $encoding = null): string { return p\\Mbstring::mb_ucfirst($string, $encoding); }\n}\n\nif (!function_exists('mb_lcfirst')) {\n    function mb_lcfirst(string $string, ?string $encoding = null): string { return p\\Mbstring::mb_lcfirst($string, $encoding); }\n}\n\nif (!function_exists('mb_trim')) {\n    function mb_trim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\\Mbstring::mb_trim($string, $characters, $encoding); }\n}\n\nif (!function_exists('mb_ltrim')) {\n    function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\\Mbstring::mb_ltrim($string, $characters, $encoding); }\n}\n\nif (!function_exists('mb_rtrim')) {\n    function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\\Mbstring::mb_rtrim($string, $characters, $encoding); }\n}\n\n\nif (extension_loaded('mbstring')) {\n    return;\n}\n\nif (!defined('MB_CASE_UPPER')) {\n    define('MB_CASE_UPPER', 0);\n}\nif (!defined('MB_CASE_LOWER')) {\n    define('MB_CASE_LOWER', 1);\n}\nif (!defined('MB_CASE_TITLE')) {\n    define('MB_CASE_TITLE', 2);\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-mbstring/bootstrap80.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nuse Symfony\\Polyfill\\Mbstring as p;\n\nif (!function_exists('mb_convert_encoding')) {\n    function mb_convert_encoding(array|string|null $string, ?string $to_encoding, array|string|null $from_encoding = null): array|string|false { return p\\Mbstring::mb_convert_encoding($string ?? '', (string) $to_encoding, $from_encoding); }\n}\nif (!function_exists('mb_decode_mimeheader')) {\n    function mb_decode_mimeheader(?string $string): string { return p\\Mbstring::mb_decode_mimeheader((string) $string); }\n}\nif (!function_exists('mb_encode_mimeheader')) {\n    function mb_encode_mimeheader(?string $string, ?string $charset = null, ?string $transfer_encoding = null, ?string $newline = \"\\r\\n\", ?int $indent = 0): string { return p\\Mbstring::mb_encode_mimeheader((string) $string, $charset, $transfer_encoding, (string) $newline, (int) $indent); }\n}\nif (!function_exists('mb_decode_numericentity')) {\n    function mb_decode_numericentity(?string $string, array $map, ?string $encoding = null): string { return p\\Mbstring::mb_decode_numericentity((string) $string, $map, $encoding); }\n}\nif (!function_exists('mb_encode_numericentity')) {\n    function mb_encode_numericentity(?string $string, array $map, ?string $encoding = null, ?bool $hex = false): string { return p\\Mbstring::mb_encode_numericentity((string) $string, $map, $encoding, (bool) $hex); }\n}\nif (!function_exists('mb_convert_case')) {\n    function mb_convert_case(?string $string, ?int $mode, ?string $encoding = null): string { return p\\Mbstring::mb_convert_case((string) $string, (int) $mode, $encoding); }\n}\nif (!function_exists('mb_internal_encoding')) {\n    function mb_internal_encoding(?string $encoding = null): string|bool { return p\\Mbstring::mb_internal_encoding($encoding); }\n}\nif (!function_exists('mb_language')) {\n    function mb_language(?string $language = null): string|bool { return p\\Mbstring::mb_language($language); }\n}\nif (!function_exists('mb_list_encodings')) {\n    function mb_list_encodings(): array { return p\\Mbstring::mb_list_encodings(); }\n}\nif (!function_exists('mb_encoding_aliases')) {\n    function mb_encoding_aliases(?string $encoding): array { return p\\Mbstring::mb_encoding_aliases((string) $encoding); }\n}\nif (!function_exists('mb_check_encoding')) {\n    function mb_check_encoding(array|string|null $value = null, ?string $encoding = null): bool { return p\\Mbstring::mb_check_encoding($value, $encoding); }\n}\nif (!function_exists('mb_detect_encoding')) {\n    function mb_detect_encoding(?string $string, array|string|null $encodings = null, ?bool $strict = false): string|false { return p\\Mbstring::mb_detect_encoding((string) $string, $encodings, (bool) $strict); }\n}\nif (!function_exists('mb_detect_order')) {\n    function mb_detect_order(array|string|null $encoding = null): array|bool { return p\\Mbstring::mb_detect_order($encoding); }\n}\nif (!function_exists('mb_parse_str')) {\n    function mb_parse_str(?string $string, &$result = []): bool { parse_str((string) $string, $result); return (bool) $result; }\n}\nif (!function_exists('mb_strlen')) {\n    function mb_strlen(?string $string, ?string $encoding = null): int { return p\\Mbstring::mb_strlen((string) $string, $encoding); }\n}\nif (!function_exists('mb_strpos')) {\n    function mb_strpos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\\Mbstring::mb_strpos((string) $haystack, (string) $needle, (int) $offset, $encoding); }\n}\nif (!function_exists('mb_strtolower')) {\n    function mb_strtolower(?string $string, ?string $encoding = null): string { return p\\Mbstring::mb_strtolower((string) $string, $encoding); }\n}\nif (!function_exists('mb_strtoupper')) {\n    function mb_strtoupper(?string $string, ?string $encoding = null): string { return p\\Mbstring::mb_strtoupper((string) $string, $encoding); }\n}\nif (!function_exists('mb_substitute_character')) {\n    function mb_substitute_character(string|int|null $substitute_character = null): string|int|bool { return p\\Mbstring::mb_substitute_character($substitute_character); }\n}\nif (!function_exists('mb_substr')) {\n    function mb_substr(?string $string, ?int $start, ?int $length = null, ?string $encoding = null): string { return p\\Mbstring::mb_substr((string) $string, (int) $start, $length, $encoding); }\n}\nif (!function_exists('mb_stripos')) {\n    function mb_stripos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\\Mbstring::mb_stripos((string) $haystack, (string) $needle, (int) $offset, $encoding); }\n}\nif (!function_exists('mb_stristr')) {\n    function mb_stristr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\\Mbstring::mb_stristr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); }\n}\nif (!function_exists('mb_strrchr')) {\n    function mb_strrchr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\\Mbstring::mb_strrchr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); }\n}\nif (!function_exists('mb_strrichr')) {\n    function mb_strrichr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\\Mbstring::mb_strrichr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); }\n}\nif (!function_exists('mb_strripos')) {\n    function mb_strripos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\\Mbstring::mb_strripos((string) $haystack, (string) $needle, (int) $offset, $encoding); }\n}\nif (!function_exists('mb_strrpos')) {\n    function mb_strrpos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\\Mbstring::mb_strrpos((string) $haystack, (string) $needle, (int) $offset, $encoding); }\n}\nif (!function_exists('mb_strstr')) {\n    function mb_strstr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\\Mbstring::mb_strstr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); }\n}\nif (!function_exists('mb_get_info')) {\n    function mb_get_info(?string $type = 'all'): array|string|int|false|null { return p\\Mbstring::mb_get_info((string) $type); }\n}\nif (!function_exists('mb_http_output')) {\n    function mb_http_output(?string $encoding = null): string|bool { return p\\Mbstring::mb_http_output($encoding); }\n}\nif (!function_exists('mb_strwidth')) {\n    function mb_strwidth(?string $string, ?string $encoding = null): int { return p\\Mbstring::mb_strwidth((string) $string, $encoding); }\n}\nif (!function_exists('mb_substr_count')) {\n    function mb_substr_count(?string $haystack, ?string $needle, ?string $encoding = null): int { return p\\Mbstring::mb_substr_count((string) $haystack, (string) $needle, $encoding); }\n}\nif (!function_exists('mb_output_handler')) {\n    function mb_output_handler(?string $string, ?int $status): string { return p\\Mbstring::mb_output_handler((string) $string, (int) $status); }\n}\nif (!function_exists('mb_http_input')) {\n    function mb_http_input(?string $type = null): array|string|false { return p\\Mbstring::mb_http_input($type); }\n}\n\nif (!function_exists('mb_convert_variables')) {\n    function mb_convert_variables(?string $to_encoding, array|string|null $from_encoding, mixed &$var, mixed &...$vars): string|false { return p\\Mbstring::mb_convert_variables((string) $to_encoding, $from_encoding ?? '', $var, ...$vars); }\n}\n\nif (!function_exists('mb_ord')) {\n    function mb_ord(?string $string, ?string $encoding = null): int|false { return p\\Mbstring::mb_ord((string) $string, $encoding); }\n}\nif (!function_exists('mb_chr')) {\n    function mb_chr(?int $codepoint, ?string $encoding = null): string|false { return p\\Mbstring::mb_chr((int) $codepoint, $encoding); }\n}\nif (!function_exists('mb_scrub')) {\n    function mb_scrub(?string $string, ?string $encoding = null): string { $encoding ??= mb_internal_encoding(); return mb_convert_encoding((string) $string, $encoding, $encoding); }\n}\nif (!function_exists('mb_str_split')) {\n    function mb_str_split(?string $string, ?int $length = 1, ?string $encoding = null): array { return p\\Mbstring::mb_str_split((string) $string, (int) $length, $encoding); }\n}\n\nif (!function_exists('mb_str_pad')) {\n    function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = STR_PAD_RIGHT, ?string $encoding = null): string { return p\\Mbstring::mb_str_pad($string, $length, $pad_string, $pad_type, $encoding); }\n}\n\nif (!function_exists('mb_ucfirst')) {\n    function mb_ucfirst(string $string, ?string $encoding = null): string { return p\\Mbstring::mb_ucfirst($string, $encoding); }\n}\n\nif (!function_exists('mb_lcfirst')) {\n    function mb_lcfirst(string $string, ?string $encoding = null): string { return p\\Mbstring::mb_lcfirst($string, $encoding); }\n}\n\nif (!function_exists('mb_trim')) {\n    function mb_trim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\\Mbstring::mb_trim($string, $characters, $encoding); }\n}\n\nif (!function_exists('mb_ltrim')) {\n    function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\\Mbstring::mb_ltrim($string, $characters, $encoding); }\n}\n\nif (!function_exists('mb_rtrim')) {\n    function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\\Mbstring::mb_rtrim($string, $characters, $encoding); }\n}\n\nif (extension_loaded('mbstring')) {\n    return;\n}\n\nif (!defined('MB_CASE_UPPER')) {\n    define('MB_CASE_UPPER', 0);\n}\nif (!defined('MB_CASE_LOWER')) {\n    define('MB_CASE_LOWER', 1);\n}\nif (!defined('MB_CASE_TITLE')) {\n    define('MB_CASE_TITLE', 2);\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-mbstring/composer.json",
    "content": "{\n    \"name\": \"symfony/polyfill-mbstring\",\n    \"type\": \"library\",\n    \"description\": \"Symfony polyfill for the Mbstring extension\",\n    \"keywords\": [\"polyfill\", \"shim\", \"compatibility\", \"portable\", \"mbstring\"],\n    \"homepage\": \"https://symfony.com\",\n    \"license\": \"MIT\",\n    \"authors\": [\n        {\n            \"name\": \"Nicolas Grekas\",\n            \"email\": \"p@tchwork.com\"\n        },\n        {\n            \"name\": \"Symfony Community\",\n            \"homepage\": \"https://symfony.com/contributors\"\n        }\n    ],\n    \"require\": {\n        \"php\": \">=7.2\",\n        \"ext-iconv\": \"*\"\n    },\n    \"provide\": {\n        \"ext-mbstring\": \"*\"\n    },\n    \"autoload\": {\n        \"psr-4\": { \"Symfony\\\\Polyfill\\\\Mbstring\\\\\": \"\" },\n        \"files\": [ \"bootstrap.php\" ]\n    },\n    \"suggest\": {\n        \"ext-mbstring\": \"For best performance\"\n    },\n    \"minimum-stability\": \"dev\",\n    \"extra\": {\n        \"thanks\": {\n            \"name\": \"symfony/polyfill\",\n            \"url\": \"https://github.com/symfony/polyfill\"\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-php73/LICENSE",
    "content": "Copyright (c) 2018-present Fabien Potencier\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is furnished\nto do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-php73/Php73.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Polyfill\\Php73;\n\n/**\n * @author Gabriel Caruso <carusogabriel34@gmail.com>\n * @author Ion Bazan <ion.bazan@gmail.com>\n *\n * @internal\n */\nfinal class Php73\n{\n    public static $startAt = 1533462603;\n\n    /**\n     * @param bool $asNum\n     *\n     * @return array|float|int\n     */\n    public static function hrtime($asNum = false)\n    {\n        $ns = microtime(false);\n        $s = substr($ns, 11) - self::$startAt;\n        $ns = 1E9 * (float) $ns;\n\n        if ($asNum) {\n            $ns += $s * 1E9;\n\n            return \\PHP_INT_SIZE === 4 ? $ns : (int) $ns;\n        }\n\n        return [$s, (int) $ns];\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-php73/README.md",
    "content": "Symfony Polyfill / Php73\n========================\n\nThis component provides functions added to PHP 7.3 core:\n\n- [`array_key_first`](https://php.net/array_key_first)\n- [`array_key_last`](https://php.net/array_key_last)\n- [`hrtime`](https://php.net/function.hrtime)\n- [`is_countable`](https://php.net/is_countable)\n- [`JsonException`](https://php.net/JsonException)\n\nMore information can be found in the\n[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md).\n\nLicense\n=======\n\nThis library is released under the [MIT license](LICENSE).\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-php73/Resources/stubs/JsonException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nif (\\PHP_VERSION_ID < 70300) {\n    class JsonException extends Exception\n    {\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-php73/bootstrap.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nuse Symfony\\Polyfill\\Php73 as p;\n\nif (\\PHP_VERSION_ID >= 70300) {\n    return;\n}\n\nif (!function_exists('is_countable')) {\n    function is_countable($value) { return is_array($value) || $value instanceof Countable || $value instanceof ResourceBundle || $value instanceof SimpleXmlElement; }\n}\nif (!function_exists('hrtime')) {\n    require_once __DIR__.'/Php73.php';\n    p\\Php73::$startAt = (int) microtime(true);\n    function hrtime($as_number = false) { return p\\Php73::hrtime($as_number); }\n}\nif (!function_exists('array_key_first')) {\n    function array_key_first(array $array) { foreach ($array as $key => $value) { return $key; } }\n}\nif (!function_exists('array_key_last')) {\n    function array_key_last(array $array) { return key(array_slice($array, -1, 1, true)); }\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-php73/composer.json",
    "content": "{\n    \"name\": \"symfony/polyfill-php73\",\n    \"type\": \"library\",\n    \"description\": \"Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions\",\n    \"keywords\": [\"polyfill\", \"shim\", \"compatibility\", \"portable\"],\n    \"homepage\": \"https://symfony.com\",\n    \"license\": \"MIT\",\n    \"authors\": [\n        {\n            \"name\": \"Nicolas Grekas\",\n            \"email\": \"p@tchwork.com\"\n        },\n        {\n            \"name\": \"Symfony Community\",\n            \"homepage\": \"https://symfony.com/contributors\"\n        }\n    ],\n    \"require\": {\n        \"php\": \">=7.2\"\n    },\n    \"autoload\": {\n        \"psr-4\": { \"Symfony\\\\Polyfill\\\\Php73\\\\\": \"\" },\n        \"files\": [ \"bootstrap.php\" ],\n        \"classmap\": [ \"Resources/stubs\" ]\n    },\n    \"minimum-stability\": \"dev\",\n    \"extra\": {\n        \"thanks\": {\n            \"name\": \"symfony/polyfill\",\n            \"url\": \"https://github.com/symfony/polyfill\"\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-php80/LICENSE",
    "content": "Copyright (c) 2020-present Fabien Potencier\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is furnished\nto do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-php80/Php80.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Polyfill\\Php80;\n\n/**\n * @author Ion Bazan <ion.bazan@gmail.com>\n * @author Nico Oelgart <nicoswd@gmail.com>\n * @author Nicolas Grekas <p@tchwork.com>\n *\n * @internal\n */\nfinal class Php80\n{\n    public static function fdiv(float $dividend, float $divisor): float\n    {\n        return @($dividend / $divisor);\n    }\n\n    public static function get_debug_type($value): string\n    {\n        switch (true) {\n            case null === $value: return 'null';\n            case \\is_bool($value): return 'bool';\n            case \\is_string($value): return 'string';\n            case \\is_array($value): return 'array';\n            case \\is_int($value): return 'int';\n            case \\is_float($value): return 'float';\n            case \\is_object($value): break;\n            case $value instanceof \\__PHP_Incomplete_Class: return '__PHP_Incomplete_Class';\n            default:\n                if (null === $type = @get_resource_type($value)) {\n                    return 'unknown';\n                }\n\n                if ('Unknown' === $type) {\n                    $type = 'closed';\n                }\n\n                return \"resource ($type)\";\n        }\n\n        $class = \\get_class($value);\n\n        if (false === strpos($class, '@')) {\n            return $class;\n        }\n\n        return (get_parent_class($class) ?: key(class_implements($class)) ?: 'class').'@anonymous';\n    }\n\n    public static function get_resource_id($res): int\n    {\n        if (!\\is_resource($res) && null === @get_resource_type($res)) {\n            throw new \\TypeError(sprintf('Argument 1 passed to get_resource_id() must be of the type resource, %s given', get_debug_type($res)));\n        }\n\n        return (int) $res;\n    }\n\n    public static function preg_last_error_msg(): string\n    {\n        switch (preg_last_error()) {\n            case \\PREG_INTERNAL_ERROR:\n                return 'Internal error';\n            case \\PREG_BAD_UTF8_ERROR:\n                return 'Malformed UTF-8 characters, possibly incorrectly encoded';\n            case \\PREG_BAD_UTF8_OFFSET_ERROR:\n                return 'The offset did not correspond to the beginning of a valid UTF-8 code point';\n            case \\PREG_BACKTRACK_LIMIT_ERROR:\n                return 'Backtrack limit exhausted';\n            case \\PREG_RECURSION_LIMIT_ERROR:\n                return 'Recursion limit exhausted';\n            case \\PREG_JIT_STACKLIMIT_ERROR:\n                return 'JIT stack limit exhausted';\n            case \\PREG_NO_ERROR:\n                return 'No error';\n            default:\n                return 'Unknown error';\n        }\n    }\n\n    public static function str_contains(string $haystack, string $needle): bool\n    {\n        return '' === $needle || false !== strpos($haystack, $needle);\n    }\n\n    public static function str_starts_with(string $haystack, string $needle): bool\n    {\n        return 0 === strncmp($haystack, $needle, \\strlen($needle));\n    }\n\n    public static function str_ends_with(string $haystack, string $needle): bool\n    {\n        if ('' === $needle || $needle === $haystack) {\n            return true;\n        }\n\n        if ('' === $haystack) {\n            return false;\n        }\n\n        $needleLength = \\strlen($needle);\n\n        return $needleLength <= \\strlen($haystack) && 0 === substr_compare($haystack, $needle, -$needleLength);\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-php80/PhpToken.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Polyfill\\Php80;\n\n/**\n * @author Fedonyuk Anton <info@ensostudio.ru>\n *\n * @internal\n */\nclass PhpToken implements \\Stringable\n{\n    /**\n     * @var int\n     */\n    public $id;\n\n    /**\n     * @var string\n     */\n    public $text;\n\n    /**\n     * @var -1|positive-int\n     */\n    public $line;\n\n    /**\n     * @var int\n     */\n    public $pos;\n\n    /**\n     * @param -1|positive-int $line\n     */\n    public function __construct(int $id, string $text, int $line = -1, int $position = -1)\n    {\n        $this->id = $id;\n        $this->text = $text;\n        $this->line = $line;\n        $this->pos = $position;\n    }\n\n    public function getTokenName(): ?string\n    {\n        if ('UNKNOWN' === $name = token_name($this->id)) {\n            $name = \\strlen($this->text) > 1 || \\ord($this->text) < 32 ? null : $this->text;\n        }\n\n        return $name;\n    }\n\n    /**\n     * @param int|string|array $kind\n     */\n    public function is($kind): bool\n    {\n        foreach ((array) $kind as $value) {\n            if (\\in_array($value, [$this->id, $this->text], true)) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    public function isIgnorable(): bool\n    {\n        return \\in_array($this->id, [\\T_WHITESPACE, \\T_COMMENT, \\T_DOC_COMMENT, \\T_OPEN_TAG], true);\n    }\n\n    public function __toString(): string\n    {\n        return (string) $this->text;\n    }\n\n    /**\n     * @return list<static>\n     */\n    public static function tokenize(string $code, int $flags = 0): array\n    {\n        $line = 1;\n        $position = 0;\n        $tokens = token_get_all($code, $flags);\n        foreach ($tokens as $index => $token) {\n            if (\\is_string($token)) {\n                $id = \\ord($token);\n                $text = $token;\n            } else {\n                [$id, $text, $line] = $token;\n            }\n            $tokens[$index] = new static($id, $text, $line, $position);\n            $position += \\strlen($text);\n        }\n\n        return $tokens;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-php80/README.md",
    "content": "Symfony Polyfill / Php80\n========================\n\nThis component provides features added to PHP 8.0 core:\n\n- [`Stringable`](https://php.net/stringable) interface\n- [`fdiv`](https://php.net/fdiv)\n- [`ValueError`](https://php.net/valueerror) class\n- [`UnhandledMatchError`](https://php.net/unhandledmatcherror) class\n- `FILTER_VALIDATE_BOOL` constant\n- [`get_debug_type`](https://php.net/get_debug_type)\n- [`PhpToken`](https://php.net/phptoken) class\n- [`preg_last_error_msg`](https://php.net/preg_last_error_msg)\n- [`str_contains`](https://php.net/str_contains)\n- [`str_starts_with`](https://php.net/str_starts_with)\n- [`str_ends_with`](https://php.net/str_ends_with)\n- [`get_resource_id`](https://php.net/get_resource_id)\n\nMore information can be found in the\n[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md).\n\nLicense\n=======\n\nThis library is released under the [MIT license](LICENSE).\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-php80/Resources/stubs/Attribute.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n#[Attribute(Attribute::TARGET_CLASS)]\nfinal class Attribute\n{\n    public const TARGET_CLASS = 1;\n    public const TARGET_FUNCTION = 2;\n    public const TARGET_METHOD = 4;\n    public const TARGET_PROPERTY = 8;\n    public const TARGET_CLASS_CONSTANT = 16;\n    public const TARGET_PARAMETER = 32;\n    public const TARGET_ALL = 63;\n    public const IS_REPEATABLE = 64;\n\n    /** @var int */\n    public $flags;\n\n    public function __construct(int $flags = self::TARGET_ALL)\n    {\n        $this->flags = $flags;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-php80/Resources/stubs/PhpToken.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nif (\\PHP_VERSION_ID < 80000 && extension_loaded('tokenizer')) {\n    class PhpToken extends Symfony\\Polyfill\\Php80\\PhpToken\n    {\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-php80/Resources/stubs/Stringable.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nif (\\PHP_VERSION_ID < 80000) {\n    interface Stringable\n    {\n        /**\n         * @return string\n         */\n        public function __toString();\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nif (\\PHP_VERSION_ID < 80000) {\n    class UnhandledMatchError extends Error\n    {\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-php80/Resources/stubs/ValueError.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nif (\\PHP_VERSION_ID < 80000) {\n    class ValueError extends Error\n    {\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-php80/bootstrap.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nuse Symfony\\Polyfill\\Php80 as p;\n\nif (\\PHP_VERSION_ID >= 80000) {\n    return;\n}\n\nif (!defined('FILTER_VALIDATE_BOOL') && defined('FILTER_VALIDATE_BOOLEAN')) {\n    define('FILTER_VALIDATE_BOOL', \\FILTER_VALIDATE_BOOLEAN);\n}\n\nif (!function_exists('fdiv')) {\n    function fdiv(float $num1, float $num2): float { return p\\Php80::fdiv($num1, $num2); }\n}\nif (!function_exists('preg_last_error_msg')) {\n    function preg_last_error_msg(): string { return p\\Php80::preg_last_error_msg(); }\n}\nif (!function_exists('str_contains')) {\n    function str_contains(?string $haystack, ?string $needle): bool { return p\\Php80::str_contains($haystack ?? '', $needle ?? ''); }\n}\nif (!function_exists('str_starts_with')) {\n    function str_starts_with(?string $haystack, ?string $needle): bool { return p\\Php80::str_starts_with($haystack ?? '', $needle ?? ''); }\n}\nif (!function_exists('str_ends_with')) {\n    function str_ends_with(?string $haystack, ?string $needle): bool { return p\\Php80::str_ends_with($haystack ?? '', $needle ?? ''); }\n}\nif (!function_exists('get_debug_type')) {\n    function get_debug_type($value): string { return p\\Php80::get_debug_type($value); }\n}\nif (!function_exists('get_resource_id')) {\n    function get_resource_id($resource): int { return p\\Php80::get_resource_id($resource); }\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-php80/composer.json",
    "content": "{\n    \"name\": \"symfony/polyfill-php80\",\n    \"type\": \"library\",\n    \"description\": \"Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions\",\n    \"keywords\": [\"polyfill\", \"shim\", \"compatibility\", \"portable\"],\n    \"homepage\": \"https://symfony.com\",\n    \"license\": \"MIT\",\n    \"authors\": [\n        {\n            \"name\": \"Ion Bazan\",\n            \"email\": \"ion.bazan@gmail.com\"\n        },\n        {\n            \"name\": \"Nicolas Grekas\",\n            \"email\": \"p@tchwork.com\"\n        },\n        {\n            \"name\": \"Symfony Community\",\n            \"homepage\": \"https://symfony.com/contributors\"\n        }\n    ],\n    \"require\": {\n        \"php\": \">=7.2\"\n    },\n    \"autoload\": {\n        \"psr-4\": { \"Symfony\\\\Polyfill\\\\Php80\\\\\": \"\" },\n        \"files\": [ \"bootstrap.php\" ],\n        \"classmap\": [ \"Resources/stubs\" ]\n    },\n    \"minimum-stability\": \"dev\",\n    \"extra\": {\n        \"thanks\": {\n            \"name\": \"symfony/polyfill\",\n            \"url\": \"https://github.com/symfony/polyfill\"\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-php83/LICENSE",
    "content": "Copyright (c) 2022-present Fabien Potencier\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is furnished\nto do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-php83/Php83.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Polyfill\\Php83;\n\n/**\n * @author Ion Bazan <ion.bazan@gmail.com>\n * @author Pierre Ambroise <pierre27.ambroise@gmail.com>\n *\n * @internal\n */\nfinal class Php83\n{\n    private const JSON_MAX_DEPTH = 0x7FFFFFFF; // see https://www.php.net/manual/en/function.json-decode.php\n\n    public static function json_validate(string $json, int $depth = 512, int $flags = 0): bool\n    {\n        if (0 !== $flags && \\defined('JSON_INVALID_UTF8_IGNORE') && \\JSON_INVALID_UTF8_IGNORE !== $flags) {\n            throw new \\ValueError('json_validate(): Argument #3 ($flags) must be a valid flag (allowed flags: JSON_INVALID_UTF8_IGNORE)');\n        }\n\n        if ($depth <= 0) {\n            throw new \\ValueError('json_validate(): Argument #2 ($depth) must be greater than 0');\n        }\n\n        if ($depth > self::JSON_MAX_DEPTH) {\n            throw new \\ValueError(sprintf('json_validate(): Argument #2 ($depth) must be less than %d', self::JSON_MAX_DEPTH));\n        }\n\n        json_decode($json, null, $depth, $flags);\n\n        return \\JSON_ERROR_NONE === json_last_error();\n    }\n\n    public static function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = \\STR_PAD_RIGHT, ?string $encoding = null): string\n    {\n        if (!\\in_array($pad_type, [\\STR_PAD_RIGHT, \\STR_PAD_LEFT, \\STR_PAD_BOTH], true)) {\n            throw new \\ValueError('mb_str_pad(): Argument #4 ($pad_type) must be STR_PAD_LEFT, STR_PAD_RIGHT, or STR_PAD_BOTH');\n        }\n\n        if (null === $encoding) {\n            $encoding = mb_internal_encoding();\n        }\n\n        try {\n            $validEncoding = @mb_check_encoding('', $encoding);\n        } catch (\\ValueError $e) {\n            throw new \\ValueError(sprintf('mb_str_pad(): Argument #5 ($encoding) must be a valid encoding, \"%s\" given', $encoding));\n        }\n\n        // BC for PHP 7.3 and lower\n        if (!$validEncoding) {\n            throw new \\ValueError(sprintf('mb_str_pad(): Argument #5 ($encoding) must be a valid encoding, \"%s\" given', $encoding));\n        }\n\n        if (mb_strlen($pad_string, $encoding) <= 0) {\n            throw new \\ValueError('mb_str_pad(): Argument #3 ($pad_string) must be a non-empty string');\n        }\n\n        $paddingRequired = $length - mb_strlen($string, $encoding);\n\n        if ($paddingRequired < 1) {\n            return $string;\n        }\n\n        switch ($pad_type) {\n            case \\STR_PAD_LEFT:\n                return mb_substr(str_repeat($pad_string, $paddingRequired), 0, $paddingRequired, $encoding).$string;\n            case \\STR_PAD_RIGHT:\n                return $string.mb_substr(str_repeat($pad_string, $paddingRequired), 0, $paddingRequired, $encoding);\n            default:\n                $leftPaddingLength = floor($paddingRequired / 2);\n                $rightPaddingLength = $paddingRequired - $leftPaddingLength;\n\n                return mb_substr(str_repeat($pad_string, $leftPaddingLength), 0, $leftPaddingLength, $encoding).$string.mb_substr(str_repeat($pad_string, $rightPaddingLength), 0, $rightPaddingLength, $encoding);\n        }\n    }\n\n    public static function str_increment(string $string): string\n    {\n        if ('' === $string) {\n            throw new \\ValueError('str_increment(): Argument #1 ($string) cannot be empty');\n        }\n\n        if (!preg_match('/^[a-zA-Z0-9]+$/', $string)) {\n            throw new \\ValueError('str_increment(): Argument #1 ($string) must be composed only of alphanumeric ASCII characters');\n        }\n\n        if (is_numeric($string)) {\n            $offset = stripos($string, 'e');\n            if (false !== $offset) {\n                $char = $string[$offset];\n                ++$char;\n                $string[$offset] = $char;\n                ++$string;\n\n                switch ($string[$offset]) {\n                    case 'f':\n                        $string[$offset] = 'e';\n                        break;\n                    case 'F':\n                        $string[$offset] = 'E';\n                        break;\n                    case 'g':\n                        $string[$offset] = 'f';\n                        break;\n                    case 'G':\n                        $string[$offset] = 'F';\n                        break;\n                }\n\n                return $string;\n            }\n        }\n\n        return ++$string;\n    }\n\n    public static function str_decrement(string $string): string\n    {\n        if ('' === $string) {\n            throw new \\ValueError('str_decrement(): Argument #1 ($string) cannot be empty');\n        }\n\n        if (!preg_match('/^[a-zA-Z0-9]+$/', $string)) {\n            throw new \\ValueError('str_decrement(): Argument #1 ($string) must be composed only of alphanumeric ASCII characters');\n        }\n\n        if (preg_match('/\\A(?:0[aA0]?|[aA])\\z/', $string)) {\n            throw new \\ValueError(sprintf('str_decrement(): Argument #1 ($string) \"%s\" is out of decrement range', $string));\n        }\n\n        if (!\\in_array(substr($string, -1), ['A', 'a', '0'], true)) {\n            return implode('', \\array_slice(str_split($string), 0, -1)).\\chr(\\ord(substr($string, -1)) - 1);\n        }\n\n        $carry = '';\n        $decremented = '';\n\n        for ($i = \\strlen($string) - 1; $i >= 0; --$i) {\n            $char = $string[$i];\n\n            switch ($char) {\n                case 'A':\n                    if ('' !== $carry) {\n                        $decremented = $carry.$decremented;\n                        $carry = '';\n                    }\n                    $carry = 'Z';\n\n                    break;\n                case 'a':\n                    if ('' !== $carry) {\n                        $decremented = $carry.$decremented;\n                        $carry = '';\n                    }\n                    $carry = 'z';\n\n                    break;\n                case '0':\n                    if ('' !== $carry) {\n                        $decremented = $carry.$decremented;\n                        $carry = '';\n                    }\n                    $carry = '9';\n\n                    break;\n                case '1':\n                    if ('' !== $carry) {\n                        $decremented = $carry.$decremented;\n                        $carry = '';\n                    }\n\n                    break;\n                default:\n                    if ('' !== $carry) {\n                        $decremented = $carry.$decremented;\n                        $carry = '';\n                    }\n\n                    if (!\\in_array($char, ['A', 'a', '0'], true)) {\n                        $decremented = \\chr(\\ord($char) - 1).$decremented;\n                    }\n            }\n        }\n\n        return $decremented;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-php83/README.md",
    "content": "Symfony Polyfill / Php83\n========================\n\nThis component provides features added to PHP 8.3 core:\n\n- [`json_validate`](https://wiki.php.net/rfc/json_validate)\n- [`Override`](https://wiki.php.net/rfc/marking_overriden_methods)\n- [`mb_str_pad`](https://wiki.php.net/rfc/mb_str_pad)\n- [`ldap_exop_sync`](https://wiki.php.net/rfc/deprecate_functions_with_overloaded_signatures)\n- [`ldap_connect_wallet`](https://wiki.php.net/rfc/deprecate_functions_with_overloaded_signatures)\n- [`stream_context_set_options`](https://wiki.php.net/rfc/deprecate_functions_with_overloaded_signatures)\n- [`str_increment` and `str_decrement`](https://wiki.php.net/rfc/saner-inc-dec-operators)\n- [`Date*Exception/Error classes`](https://wiki.php.net/rfc/datetime-exceptions)\n- [`SQLite3Exception`](https://wiki.php.net/rfc/sqlite3_exceptions)\n\nMore information can be found in the\n[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md).\n\nLicense\n=======\n\nThis library is released under the [MIT license](LICENSE).\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-php83/Resources/stubs/DateError.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nif (\\PHP_VERSION_ID < 80300) {\n    class DateError extends Error\n    {\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-php83/Resources/stubs/DateException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nif (\\PHP_VERSION_ID < 80300) {\n    class DateException extends Exception\n    {\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-php83/Resources/stubs/DateInvalidOperationException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nif (\\PHP_VERSION_ID < 80300) {\n    class DateInvalidOperationException extends DateException\n    {\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-php83/Resources/stubs/DateInvalidTimeZoneException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nif (\\PHP_VERSION_ID < 80300) {\n    class DateInvalidTimeZoneException extends DateException\n    {\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-php83/Resources/stubs/DateMalformedIntervalStringException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nif (\\PHP_VERSION_ID < 80300) {\n    class DateMalformedIntervalStringException extends DateException\n    {\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-php83/Resources/stubs/DateMalformedPeriodStringException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nif (\\PHP_VERSION_ID < 80300) {\n    class DateMalformedPeriodStringException extends DateException\n    {\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-php83/Resources/stubs/DateMalformedStringException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nif (\\PHP_VERSION_ID < 80300) {\n    class DateMalformedStringException extends DateException\n    {\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-php83/Resources/stubs/DateObjectError.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nif (\\PHP_VERSION_ID < 80300) {\n    class DateObjectError extends DateError\n    {\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-php83/Resources/stubs/DateRangeError.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nif (\\PHP_VERSION_ID < 80300) {\n    class DateRangeError extends DateError\n    {\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-php83/Resources/stubs/Override.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nif (\\PHP_VERSION_ID < 80300) {\n    #[Attribute(Attribute::TARGET_METHOD)]\n    final class Override\n    {\n        public function __construct()\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-php83/Resources/stubs/SQLite3Exception.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nif (\\PHP_VERSION_ID < 80300) {\n    class SQLite3Exception extends Exception\n    {\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-php83/bootstrap.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nuse Symfony\\Polyfill\\Php83 as p;\n\nif (\\PHP_VERSION_ID >= 80300) {\n    return;\n}\n\nif (!function_exists('json_validate')) {\n    function json_validate(string $json, int $depth = 512, int $flags = 0): bool { return p\\Php83::json_validate($json, $depth, $flags); }\n}\n\nif (extension_loaded('mbstring')) {\n    if (!function_exists('mb_str_pad')) {\n        function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = STR_PAD_RIGHT, ?string $encoding = null): string { return p\\Php83::mb_str_pad($string, $length, $pad_string, $pad_type, $encoding); }\n    }\n}\n\nif (!function_exists('stream_context_set_options')) {\n    function stream_context_set_options($context, array $options): bool { return stream_context_set_option($context, $options); }\n}\n\nif (!function_exists('str_increment')) {\n    function str_increment(string $string): string { return p\\Php83::str_increment($string); }\n}\n\nif (!function_exists('str_decrement')) {\n    function str_decrement(string $string): string { return p\\Php83::str_decrement($string); }\n}\n\nif (\\PHP_VERSION_ID >= 80100) {\n    return require __DIR__.'/bootstrap81.php';\n}\n\nif (!function_exists('ldap_exop_sync') && function_exists('ldap_exop')) {\n    function ldap_exop_sync($ldap, string $request_oid, ?string $request_data = null, ?array $controls = null, &$response_data = null, &$response_oid = null): bool { return ldap_exop($ldap, $request_oid, $request_data, $controls, $response_data, $response_oid); }\n}\n\nif (!function_exists('ldap_connect_wallet') && function_exists('ldap_connect')) {\n    function ldap_connect_wallet(?string $uri, string $wallet, string $password, int $auth_mode = \\GSLC_SSL_NO_AUTH) { return ldap_connect($uri, $wallet, $password, $auth_mode); }\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-php83/bootstrap81.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nif (\\PHP_VERSION_ID >= 80300) {\n    return;\n}\n\nif (!function_exists('ldap_exop_sync') && function_exists('ldap_exop')) {\n    function ldap_exop_sync(\\LDAP\\Connection $ldap, string $request_oid, ?string $request_data = null, ?array $controls = null, &$response_data = null, &$response_oid = null): bool { return ldap_exop($ldap, $request_oid, $request_data, $controls, $response_data, $response_oid); }\n}\n\nif (!function_exists('ldap_connect_wallet') && function_exists('ldap_connect')) {\n    function ldap_connect_wallet(?string $uri, string $wallet, #[\\SensitiveParameter] string $password, int $auth_mode = \\GSLC_SSL_NO_AUTH): \\LDAP\\Connection|false { return ldap_connect($uri, $wallet, $password, $auth_mode); }\n}\n"
  },
  {
    "path": "server/vendor/symfony/polyfill-php83/composer.json",
    "content": "{\n    \"name\": \"symfony/polyfill-php83\",\n    \"type\": \"library\",\n    \"description\": \"Symfony polyfill backporting some PHP 8.3+ features to lower PHP versions\",\n    \"keywords\": [\"polyfill\", \"shim\", \"compatibility\", \"portable\"],\n    \"homepage\": \"https://symfony.com\",\n    \"license\": \"MIT\",\n    \"authors\": [\n        {\n            \"name\": \"Nicolas Grekas\",\n            \"email\": \"p@tchwork.com\"\n        },\n        {\n            \"name\": \"Symfony Community\",\n            \"homepage\": \"https://symfony.com/contributors\"\n        }\n    ],\n    \"require\": {\n        \"php\": \">=7.2\"\n    },\n    \"autoload\": {\n        \"psr-4\": { \"Symfony\\\\Polyfill\\\\Php83\\\\\": \"\" },\n        \"files\": [ \"bootstrap.php\" ],\n        \"classmap\": [ \"Resources/stubs\" ]\n    },\n    \"minimum-stability\": \"dev\",\n    \"extra\": {\n        \"thanks\": {\n            \"name\": \"symfony/polyfill\",\n            \"url\": \"https://github.com/symfony/polyfill\"\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/service-contracts/Attribute/Required.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Contracts\\Service\\Attribute;\n\n/**\n * A required dependency.\n *\n * This attribute indicates that a property holds a required dependency. The annotated property or method should be\n * considered during the instantiation process of the containing class.\n *\n * @author Alexander M. Turek <me@derrabus.de>\n */\n#[\\Attribute(\\Attribute::TARGET_METHOD | \\Attribute::TARGET_PROPERTY)]\nfinal class Required\n{\n}\n"
  },
  {
    "path": "server/vendor/symfony/service-contracts/Attribute/SubscribedService.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Contracts\\Service\\Attribute;\n\nuse Symfony\\Contracts\\Service\\ServiceMethodsSubscriberTrait;\nuse Symfony\\Contracts\\Service\\ServiceSubscriberInterface;\n\n/**\n * For use as the return value for {@see ServiceSubscriberInterface}.\n *\n * @example new SubscribedService('http_client', HttpClientInterface::class, false, new Target('githubApi'))\n *\n * Use with {@see ServiceMethodsSubscriberTrait} to mark a method's return type\n * as a subscribed service.\n *\n * @author Kevin Bond <kevinbond@gmail.com>\n */\n#[\\Attribute(\\Attribute::TARGET_METHOD)]\nfinal class SubscribedService\n{\n    /** @var object[] */\n    public array $attributes;\n\n    /**\n     * @param string|null       $key        The key to use for the service\n     * @param class-string|null $type       The service class\n     * @param bool              $nullable   Whether the service is optional\n     * @param object|object[]   $attributes One or more dependency injection attributes to use\n     */\n    public function __construct(\n        public ?string $key = null,\n        public ?string $type = null,\n        public bool $nullable = false,\n        array|object $attributes = [],\n    ) {\n        $this->attributes = \\is_array($attributes) ? $attributes : [$attributes];\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/service-contracts/CHANGELOG.md",
    "content": "CHANGELOG\n=========\n\nThe changelog is maintained for all Symfony contracts at the following URL:\nhttps://github.com/symfony/contracts/blob/main/CHANGELOG.md\n"
  },
  {
    "path": "server/vendor/symfony/service-contracts/LICENSE",
    "content": "Copyright (c) 2018-present Fabien Potencier\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is furnished\nto do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "server/vendor/symfony/service-contracts/README.md",
    "content": "Symfony Service Contracts\n=========================\n\nA set of abstractions extracted out of the Symfony components.\n\nCan be used to build on semantics that the Symfony components proved useful and\nthat already have battle tested implementations.\n\nSee https://github.com/symfony/contracts/blob/main/README.md for more information.\n"
  },
  {
    "path": "server/vendor/symfony/service-contracts/ResetInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Contracts\\Service;\n\n/**\n * Provides a way to reset an object to its initial state.\n *\n * When calling the \"reset()\" method on an object, it should be put back to its\n * initial state. This usually means clearing any internal buffers and forwarding\n * the call to internal dependencies. All properties of the object should be put\n * back to the same state it had when it was first ready to use.\n *\n * This method could be called, for example, to recycle objects that are used as\n * services, so that they can be used to handle several requests in the same\n * process loop (note that we advise making your services stateless instead of\n * implementing this interface when possible.)\n */\ninterface ResetInterface\n{\n    /**\n     * @return void\n     */\n    public function reset();\n}\n"
  },
  {
    "path": "server/vendor/symfony/service-contracts/ServiceCollectionInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Contracts\\Service;\n\n/**\n * A ServiceProviderInterface that is also countable and iterable.\n *\n * @author Kevin Bond <kevinbond@gmail.com>\n *\n * @template-covariant T of mixed\n *\n * @extends ServiceProviderInterface<T>\n * @extends \\IteratorAggregate<string, T>\n */\ninterface ServiceCollectionInterface extends ServiceProviderInterface, \\Countable, \\IteratorAggregate\n{\n}\n"
  },
  {
    "path": "server/vendor/symfony/service-contracts/ServiceLocatorTrait.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Contracts\\Service;\n\nuse Psr\\Container\\ContainerExceptionInterface;\nuse Psr\\Container\\NotFoundExceptionInterface;\n\n// Help opcache.preload discover always-needed symbols\nclass_exists(ContainerExceptionInterface::class);\nclass_exists(NotFoundExceptionInterface::class);\n\n/**\n * A trait to help implement ServiceProviderInterface.\n *\n * @author Robin Chalas <robin.chalas@gmail.com>\n * @author Nicolas Grekas <p@tchwork.com>\n */\ntrait ServiceLocatorTrait\n{\n    private array $loading = [];\n    private array $providedTypes;\n\n    /**\n     * @param array<string, callable> $factories\n     */\n    public function __construct(\n        private array $factories,\n    ) {\n    }\n\n    public function has(string $id): bool\n    {\n        return isset($this->factories[$id]);\n    }\n\n    public function get(string $id): mixed\n    {\n        if (!isset($this->factories[$id])) {\n            throw $this->createNotFoundException($id);\n        }\n\n        if (isset($this->loading[$id])) {\n            $ids = array_values($this->loading);\n            $ids = \\array_slice($this->loading, array_search($id, $ids));\n            $ids[] = $id;\n\n            throw $this->createCircularReferenceException($id, $ids);\n        }\n\n        $this->loading[$id] = $id;\n        try {\n            return $this->factories[$id]($this);\n        } finally {\n            unset($this->loading[$id]);\n        }\n    }\n\n    public function getProvidedServices(): array\n    {\n        if (!isset($this->providedTypes)) {\n            $this->providedTypes = [];\n\n            foreach ($this->factories as $name => $factory) {\n                if (!\\is_callable($factory)) {\n                    $this->providedTypes[$name] = '?';\n                } else {\n                    $type = (new \\ReflectionFunction($factory))->getReturnType();\n\n                    $this->providedTypes[$name] = $type ? ($type->allowsNull() ? '?' : '').($type instanceof \\ReflectionNamedType ? $type->getName() : $type) : '?';\n                }\n            }\n        }\n\n        return $this->providedTypes;\n    }\n\n    private function createNotFoundException(string $id): NotFoundExceptionInterface\n    {\n        if (!$alternatives = array_keys($this->factories)) {\n            $message = 'is empty...';\n        } else {\n            $last = array_pop($alternatives);\n            if ($alternatives) {\n                $message = \\sprintf('only knows about the \"%s\" and \"%s\" services.', implode('\", \"', $alternatives), $last);\n            } else {\n                $message = \\sprintf('only knows about the \"%s\" service.', $last);\n            }\n        }\n\n        if ($this->loading) {\n            $message = \\sprintf('The service \"%s\" has a dependency on a non-existent service \"%s\". This locator %s', end($this->loading), $id, $message);\n        } else {\n            $message = \\sprintf('Service \"%s\" not found: the current service locator %s', $id, $message);\n        }\n\n        return new class($message) extends \\InvalidArgumentException implements NotFoundExceptionInterface {\n        };\n    }\n\n    private function createCircularReferenceException(string $id, array $path): ContainerExceptionInterface\n    {\n        return new class(\\sprintf('Circular reference detected for service \"%s\", path: \"%s\".', $id, implode(' -> ', $path))) extends \\RuntimeException implements ContainerExceptionInterface {\n        };\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/service-contracts/ServiceMethodsSubscriberTrait.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Contracts\\Service;\n\nuse Psr\\Container\\ContainerInterface;\nuse Symfony\\Contracts\\Service\\Attribute\\Required;\nuse Symfony\\Contracts\\Service\\Attribute\\SubscribedService;\n\n/**\n * Implementation of ServiceSubscriberInterface that determines subscribed services\n * from methods that have the #[SubscribedService] attribute.\n *\n * Service ids are available as \"ClassName::methodName\" so that the implementation\n * of subscriber methods can be just `return $this->container->get(__METHOD__);`.\n *\n * @author Kevin Bond <kevinbond@gmail.com>\n */\ntrait ServiceMethodsSubscriberTrait\n{\n    protected ContainerInterface $container;\n\n    public static function getSubscribedServices(): array\n    {\n        $services = method_exists(get_parent_class(self::class) ?: '', __FUNCTION__) ? parent::getSubscribedServices() : [];\n\n        foreach ((new \\ReflectionClass(self::class))->getMethods() as $method) {\n            if (self::class !== $method->getDeclaringClass()->name) {\n                continue;\n            }\n\n            if (!$attribute = $method->getAttributes(SubscribedService::class)[0] ?? null) {\n                continue;\n            }\n\n            if ($method->isStatic() || $method->isAbstract() || $method->isGenerator() || $method->isInternal() || $method->getNumberOfRequiredParameters()) {\n                throw new \\LogicException(\\sprintf('Cannot use \"%s\" on method \"%s::%s()\" (can only be used on non-static, non-abstract methods with no parameters).', SubscribedService::class, self::class, $method->name));\n            }\n\n            if (!$returnType = $method->getReturnType()) {\n                throw new \\LogicException(\\sprintf('Cannot use \"%s\" on methods without a return type in \"%s::%s()\".', SubscribedService::class, $method->name, self::class));\n            }\n\n            /* @var SubscribedService $attribute */\n            $attribute = $attribute->newInstance();\n            $attribute->key ??= self::class.'::'.$method->name;\n            $attribute->type ??= $returnType instanceof \\ReflectionNamedType ? $returnType->getName() : (string) $returnType;\n            $attribute->nullable = $attribute->nullable ?: $returnType->allowsNull();\n\n            if ($attribute->attributes) {\n                $services[] = $attribute;\n            } else {\n                $services[$attribute->key] = ($attribute->nullable ? '?' : '').$attribute->type;\n            }\n        }\n\n        return $services;\n    }\n\n    #[Required]\n    public function setContainer(ContainerInterface $container): ?ContainerInterface\n    {\n        $ret = null;\n        if (method_exists(get_parent_class(self::class) ?: '', __FUNCTION__)) {\n            $ret = parent::setContainer($container);\n        }\n\n        $this->container = $container;\n\n        return $ret;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/service-contracts/ServiceProviderInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Contracts\\Service;\n\nuse Psr\\Container\\ContainerInterface;\n\n/**\n * A ServiceProviderInterface exposes the identifiers and the types of services provided by a container.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n * @author Mateusz Sip <mateusz.sip@gmail.com>\n *\n * @template-covariant T of mixed\n */\ninterface ServiceProviderInterface extends ContainerInterface\n{\n    /**\n     * @return T\n     */\n    public function get(string $id): mixed;\n\n    public function has(string $id): bool;\n\n    /**\n     * Returns an associative array of service types keyed by the identifiers provided by the current container.\n     *\n     * Examples:\n     *\n     *  * ['logger' => 'Psr\\Log\\LoggerInterface'] means the object provides a service named \"logger\" that implements Psr\\Log\\LoggerInterface\n     *  * ['foo' => '?'] means the container provides service name \"foo\" of unspecified type\n     *  * ['bar' => '?Bar\\Baz'] means the container provides a service \"bar\" of type Bar\\Baz|null\n     *\n     * @return array<string, string> The provided service types, keyed by service names\n     */\n    public function getProvidedServices(): array;\n}\n"
  },
  {
    "path": "server/vendor/symfony/service-contracts/ServiceSubscriberInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Contracts\\Service;\n\nuse Symfony\\Contracts\\Service\\Attribute\\SubscribedService;\n\n/**\n * A ServiceSubscriber exposes its dependencies via the static {@link getSubscribedServices} method.\n *\n * The getSubscribedServices method returns an array of service types required by such instances,\n * optionally keyed by the service names used internally. Service types that start with an interrogation\n * mark \"?\" are optional, while the other ones are mandatory service dependencies.\n *\n * The injected service locators SHOULD NOT allow access to any other services not specified by the method.\n *\n * It is expected that ServiceSubscriber instances consume PSR-11-based service locators internally.\n * This interface does not dictate any injection method for these service locators, although constructor\n * injection is recommended.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n */\ninterface ServiceSubscriberInterface\n{\n    /**\n     * Returns an array of service types (or {@see SubscribedService} objects) required\n     * by such instances, optionally keyed by the service names used internally.\n     *\n     * For mandatory dependencies:\n     *\n     *  * ['logger' => 'Psr\\Log\\LoggerInterface'] means the objects use the \"logger\" name\n     *    internally to fetch a service which must implement Psr\\Log\\LoggerInterface.\n     *  * ['loggers' => 'Psr\\Log\\LoggerInterface[]'] means the objects use the \"loggers\" name\n     *    internally to fetch an iterable of Psr\\Log\\LoggerInterface instances.\n     *  * ['Psr\\Log\\LoggerInterface'] is a shortcut for\n     *  * ['Psr\\Log\\LoggerInterface' => 'Psr\\Log\\LoggerInterface']\n     *\n     * otherwise:\n     *\n     *  * ['logger' => '?Psr\\Log\\LoggerInterface'] denotes an optional dependency\n     *  * ['loggers' => '?Psr\\Log\\LoggerInterface[]'] denotes an optional iterable dependency\n     *  * ['?Psr\\Log\\LoggerInterface'] is a shortcut for\n     *  * ['Psr\\Log\\LoggerInterface' => '?Psr\\Log\\LoggerInterface']\n     *\n     * additionally, an array of {@see SubscribedService}'s can be returned:\n     *\n     *  * [new SubscribedService('logger', Psr\\Log\\LoggerInterface::class)]\n     *  * [new SubscribedService(type: Psr\\Log\\LoggerInterface::class, nullable: true)]\n     *  * [new SubscribedService('http_client', HttpClientInterface::class, attributes: new Target('githubApi'))]\n     *\n     * @return string[]|SubscribedService[] The required service types, optionally keyed by service names\n     */\n    public static function getSubscribedServices(): array;\n}\n"
  },
  {
    "path": "server/vendor/symfony/service-contracts/ServiceSubscriberTrait.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Contracts\\Service;\n\nuse Psr\\Container\\ContainerInterface;\nuse Symfony\\Contracts\\Service\\Attribute\\Required;\nuse Symfony\\Contracts\\Service\\Attribute\\SubscribedService;\n\ntrigger_deprecation('symfony/contracts', 'v3.5', '\"%s\" is deprecated, use \"ServiceMethodsSubscriberTrait\" instead.', ServiceSubscriberTrait::class);\n\n/**\n * Implementation of ServiceSubscriberInterface that determines subscribed services\n * from methods that have the #[SubscribedService] attribute.\n *\n * Service ids are available as \"ClassName::methodName\" so that the implementation\n * of subscriber methods can be just `return $this->container->get(__METHOD__);`.\n *\n * @property ContainerInterface $container\n *\n * @author Kevin Bond <kevinbond@gmail.com>\n *\n * @deprecated since symfony/contracts v3.5, use ServiceMethodsSubscriberTrait instead\n */\ntrait ServiceSubscriberTrait\n{\n    public static function getSubscribedServices(): array\n    {\n        $services = method_exists(get_parent_class(self::class) ?: '', __FUNCTION__) ? parent::getSubscribedServices() : [];\n\n        foreach ((new \\ReflectionClass(self::class))->getMethods() as $method) {\n            if (self::class !== $method->getDeclaringClass()->name) {\n                continue;\n            }\n\n            if (!$attribute = $method->getAttributes(SubscribedService::class)[0] ?? null) {\n                continue;\n            }\n\n            if ($method->isStatic() || $method->isAbstract() || $method->isGenerator() || $method->isInternal() || $method->getNumberOfRequiredParameters()) {\n                throw new \\LogicException(\\sprintf('Cannot use \"%s\" on method \"%s::%s()\" (can only be used on non-static, non-abstract methods with no parameters).', SubscribedService::class, self::class, $method->name));\n            }\n\n            if (!$returnType = $method->getReturnType()) {\n                throw new \\LogicException(\\sprintf('Cannot use \"%s\" on methods without a return type in \"%s::%s()\".', SubscribedService::class, $method->name, self::class));\n            }\n\n            /** @var SubscribedService $attribute */\n            $attribute = $attribute->newInstance();\n            $attribute->key ??= self::class.'::'.$method->name;\n            $attribute->type ??= $returnType instanceof \\ReflectionNamedType ? $returnType->getName() : (string) $returnType;\n            $attribute->nullable = $attribute->nullable ?: $returnType->allowsNull();\n\n            if ($attribute->attributes) {\n                $services[] = $attribute;\n            } else {\n                $services[$attribute->key] = ($attribute->nullable ? '?' : '').$attribute->type;\n            }\n        }\n\n        return $services;\n    }\n\n    #[Required]\n    public function setContainer(ContainerInterface $container): ?ContainerInterface\n    {\n        $ret = null;\n        if (method_exists(get_parent_class(self::class) ?: '', __FUNCTION__)) {\n            $ret = parent::setContainer($container);\n        }\n\n        $this->container = $container;\n\n        return $ret;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/service-contracts/Test/ServiceLocatorTest.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Contracts\\Service\\Test;\n\nclass_alias(ServiceLocatorTestCase::class, ServiceLocatorTest::class);\n\nif (false) {\n    /**\n     * @deprecated since PHPUnit 9.6\n     */\n    class ServiceLocatorTest\n    {\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/service-contracts/Test/ServiceLocatorTestCase.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Contracts\\Service\\Test;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Psr\\Container\\ContainerExceptionInterface;\nuse Psr\\Container\\ContainerInterface;\nuse Psr\\Container\\NotFoundExceptionInterface;\nuse Symfony\\Contracts\\Service\\ServiceLocatorTrait;\n\nabstract class ServiceLocatorTestCase extends TestCase\n{\n    /**\n     * @param array<string, callable> $factories\n     */\n    protected function getServiceLocator(array $factories): ContainerInterface\n    {\n        return new class($factories) implements ContainerInterface {\n            use ServiceLocatorTrait;\n        };\n    }\n\n    public function testHas()\n    {\n        $locator = $this->getServiceLocator([\n            'foo' => fn () => 'bar',\n            'bar' => fn () => 'baz',\n            fn () => 'dummy',\n        ]);\n\n        $this->assertTrue($locator->has('foo'));\n        $this->assertTrue($locator->has('bar'));\n        $this->assertFalse($locator->has('dummy'));\n    }\n\n    public function testGet()\n    {\n        $locator = $this->getServiceLocator([\n            'foo' => fn () => 'bar',\n            'bar' => fn () => 'baz',\n        ]);\n\n        $this->assertSame('bar', $locator->get('foo'));\n        $this->assertSame('baz', $locator->get('bar'));\n    }\n\n    public function testGetDoesNotMemoize()\n    {\n        $i = 0;\n        $locator = $this->getServiceLocator([\n            'foo' => function () use (&$i) {\n                ++$i;\n\n                return 'bar';\n            },\n        ]);\n\n        $this->assertSame('bar', $locator->get('foo'));\n        $this->assertSame('bar', $locator->get('foo'));\n        $this->assertSame(2, $i);\n    }\n\n    public function testThrowsOnUndefinedInternalService()\n    {\n        $locator = $this->getServiceLocator([\n            'foo' => function () use (&$locator) { return $locator->get('bar'); },\n        ]);\n\n        $this->expectException(NotFoundExceptionInterface::class);\n        $this->expectExceptionMessage('The service \"foo\" has a dependency on a non-existent service \"bar\". This locator only knows about the \"foo\" service.');\n\n        $locator->get('foo');\n    }\n\n    public function testThrowsOnCircularReference()\n    {\n        $locator = $this->getServiceLocator([\n            'foo' => function () use (&$locator) { return $locator->get('bar'); },\n            'bar' => function () use (&$locator) { return $locator->get('baz'); },\n            'baz' => function () use (&$locator) { return $locator->get('bar'); },\n        ]);\n\n        $this->expectException(ContainerExceptionInterface::class);\n        $this->expectExceptionMessage('Circular reference detected for service \"bar\", path: \"bar -> baz -> bar\".');\n\n        $locator->get('foo');\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/service-contracts/composer.json",
    "content": "{\n    \"name\": \"symfony/service-contracts\",\n    \"type\": \"library\",\n    \"description\": \"Generic abstractions related to writing services\",\n    \"keywords\": [\"abstractions\", \"contracts\", \"decoupling\", \"interfaces\", \"interoperability\", \"standards\"],\n    \"homepage\": \"https://symfony.com\",\n    \"license\": \"MIT\",\n    \"authors\": [\n        {\n            \"name\": \"Nicolas Grekas\",\n            \"email\": \"p@tchwork.com\"\n        },\n        {\n            \"name\": \"Symfony Community\",\n            \"homepage\": \"https://symfony.com/contributors\"\n        }\n    ],\n    \"require\": {\n        \"php\": \">=8.1\",\n        \"psr/container\": \"^1.1|^2.0\",\n        \"symfony/deprecation-contracts\": \"^2.5|^3\"\n    },\n    \"conflict\": {\n        \"ext-psr\": \"<1.1|>=2\"\n    },\n    \"autoload\": {\n        \"psr-4\": { \"Symfony\\\\Contracts\\\\Service\\\\\": \"\" },\n        \"exclude-from-classmap\": [\n            \"/Test/\"\n        ]\n    },\n    \"minimum-stability\": \"dev\",\n    \"extra\": {\n        \"branch-alias\": {\n            \"dev-main\": \"3.6-dev\"\n        },\n        \"thanks\": {\n            \"name\": \"symfony/contracts\",\n            \"url\": \"https://github.com/symfony/contracts\"\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/string/AbstractString.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\String;\n\nuse Symfony\\Component\\String\\Exception\\ExceptionInterface;\nuse Symfony\\Component\\String\\Exception\\InvalidArgumentException;\nuse Symfony\\Component\\String\\Exception\\RuntimeException;\n\n/**\n * Represents a string of abstract characters.\n *\n * Unicode defines 3 types of \"characters\" (bytes, code points and grapheme clusters).\n * This class is the abstract type to use as a type-hint when the logic you want to\n * implement doesn't care about the exact variant it deals with.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n * @author Hugo Hamon <hugohamon@neuf.fr>\n *\n * @throws ExceptionInterface\n */\nabstract class AbstractString implements \\Stringable, \\JsonSerializable\n{\n    public const PREG_PATTERN_ORDER = \\PREG_PATTERN_ORDER;\n    public const PREG_SET_ORDER = \\PREG_SET_ORDER;\n    public const PREG_OFFSET_CAPTURE = \\PREG_OFFSET_CAPTURE;\n    public const PREG_UNMATCHED_AS_NULL = \\PREG_UNMATCHED_AS_NULL;\n\n    public const PREG_SPLIT = 0;\n    public const PREG_SPLIT_NO_EMPTY = \\PREG_SPLIT_NO_EMPTY;\n    public const PREG_SPLIT_DELIM_CAPTURE = \\PREG_SPLIT_DELIM_CAPTURE;\n    public const PREG_SPLIT_OFFSET_CAPTURE = \\PREG_SPLIT_OFFSET_CAPTURE;\n\n    protected $string = '';\n    protected $ignoreCase = false;\n\n    abstract public function __construct(string $string = '');\n\n    /**\n     * Unwraps instances of AbstractString back to strings.\n     *\n     * @return string[]|array\n     */\n    public static function unwrap(array $values): array\n    {\n        foreach ($values as $k => $v) {\n            if ($v instanceof self) {\n                $values[$k] = $v->__toString();\n            } elseif (\\is_array($v) && $values[$k] !== $v = static::unwrap($v)) {\n                $values[$k] = $v;\n            }\n        }\n\n        return $values;\n    }\n\n    /**\n     * Wraps (and normalizes) strings in instances of AbstractString.\n     *\n     * @return static[]|array\n     */\n    public static function wrap(array $values): array\n    {\n        $i = 0;\n        $keys = null;\n\n        foreach ($values as $k => $v) {\n            if (\\is_string($k) && '' !== $k && $k !== $j = (string) new static($k)) {\n                $keys ??= array_keys($values);\n                $keys[$i] = $j;\n            }\n\n            if (\\is_string($v)) {\n                $values[$k] = new static($v);\n            } elseif (\\is_array($v) && $values[$k] !== $v = static::wrap($v)) {\n                $values[$k] = $v;\n            }\n\n            ++$i;\n        }\n\n        return null !== $keys ? array_combine($keys, $values) : $values;\n    }\n\n    /**\n     * @param string|string[] $needle\n     */\n    public function after(string|iterable $needle, bool $includeNeedle = false, int $offset = 0): static\n    {\n        $str = clone $this;\n        $i = \\PHP_INT_MAX;\n\n        if (\\is_string($needle)) {\n            $needle = [$needle];\n        }\n\n        foreach ($needle as $n) {\n            $n = (string) $n;\n            $j = $this->indexOf($n, $offset);\n\n            if (null !== $j && $j < $i) {\n                $i = $j;\n                $str->string = $n;\n            }\n        }\n\n        if (\\PHP_INT_MAX === $i) {\n            return $str;\n        }\n\n        if (!$includeNeedle) {\n            $i += $str->length();\n        }\n\n        return $this->slice($i);\n    }\n\n    /**\n     * @param string|string[] $needle\n     */\n    public function afterLast(string|iterable $needle, bool $includeNeedle = false, int $offset = 0): static\n    {\n        $str = clone $this;\n        $i = null;\n\n        if (\\is_string($needle)) {\n            $needle = [$needle];\n        }\n\n        foreach ($needle as $n) {\n            $n = (string) $n;\n            $j = $this->indexOfLast($n, $offset);\n\n            if (null !== $j && $j >= $i) {\n                $i = $offset = $j;\n                $str->string = $n;\n            }\n        }\n\n        if (null === $i) {\n            return $str;\n        }\n\n        if (!$includeNeedle) {\n            $i += $str->length();\n        }\n\n        return $this->slice($i);\n    }\n\n    abstract public function append(string ...$suffix): static;\n\n    /**\n     * @param string|string[] $needle\n     */\n    public function before(string|iterable $needle, bool $includeNeedle = false, int $offset = 0): static\n    {\n        $str = clone $this;\n        $i = \\PHP_INT_MAX;\n\n        if (\\is_string($needle)) {\n            $needle = [$needle];\n        }\n\n        foreach ($needle as $n) {\n            $n = (string) $n;\n            $j = $this->indexOf($n, $offset);\n\n            if (null !== $j && $j < $i) {\n                $i = $j;\n                $str->string = $n;\n            }\n        }\n\n        if (\\PHP_INT_MAX === $i) {\n            return $str;\n        }\n\n        if ($includeNeedle) {\n            $i += $str->length();\n        }\n\n        return $this->slice(0, $i);\n    }\n\n    /**\n     * @param string|string[] $needle\n     */\n    public function beforeLast(string|iterable $needle, bool $includeNeedle = false, int $offset = 0): static\n    {\n        $str = clone $this;\n        $i = null;\n\n        if (\\is_string($needle)) {\n            $needle = [$needle];\n        }\n\n        foreach ($needle as $n) {\n            $n = (string) $n;\n            $j = $this->indexOfLast($n, $offset);\n\n            if (null !== $j && $j >= $i) {\n                $i = $offset = $j;\n                $str->string = $n;\n            }\n        }\n\n        if (null === $i) {\n            return $str;\n        }\n\n        if ($includeNeedle) {\n            $i += $str->length();\n        }\n\n        return $this->slice(0, $i);\n    }\n\n    /**\n     * @return int[]\n     */\n    public function bytesAt(int $offset): array\n    {\n        $str = $this->slice($offset, 1);\n\n        return '' === $str->string ? [] : array_values(unpack('C*', $str->string));\n    }\n\n    abstract public function camel(): static;\n\n    /**\n     * @return static[]\n     */\n    abstract public function chunk(int $length = 1): array;\n\n    public function collapseWhitespace(): static\n    {\n        $str = clone $this;\n        $str->string = trim(preg_replace(\"/(?:[ \\n\\r\\t\\x0C]{2,}+|[\\n\\r\\t\\x0C])/\", ' ', $str->string), \" \\n\\r\\t\\x0C\");\n\n        return $str;\n    }\n\n    /**\n     * @param string|string[] $needle\n     */\n    public function containsAny(string|iterable $needle): bool\n    {\n        return null !== $this->indexOf($needle);\n    }\n\n    /**\n     * @param string|string[] $suffix\n     */\n    public function endsWith(string|iterable $suffix): bool\n    {\n        if (\\is_string($suffix)) {\n            throw new \\TypeError(\\sprintf('Method \"%s()\" must be overridden by class \"%s\" to deal with non-iterable values.', __FUNCTION__, static::class));\n        }\n\n        foreach ($suffix as $s) {\n            if ($this->endsWith((string) $s)) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    public function ensureEnd(string $suffix): static\n    {\n        if (!$this->endsWith($suffix)) {\n            return $this->append($suffix);\n        }\n\n        $suffix = preg_quote($suffix);\n        $regex = '{('.$suffix.')(?:'.$suffix.')++$}D';\n\n        return $this->replaceMatches($regex.($this->ignoreCase ? 'i' : ''), '$1');\n    }\n\n    public function ensureStart(string $prefix): static\n    {\n        $prefix = new static($prefix);\n\n        if (!$this->startsWith($prefix)) {\n            return $this->prepend($prefix);\n        }\n\n        $str = clone $this;\n        $i = $prefixLen = $prefix->length();\n\n        while ($this->indexOf($prefix, $i) === $i) {\n            $str = $str->slice($prefixLen);\n            $i += $prefixLen;\n        }\n\n        return $str;\n    }\n\n    /**\n     * @param string|string[] $string\n     */\n    public function equalsTo(string|iterable $string): bool\n    {\n        if (\\is_string($string)) {\n            throw new \\TypeError(\\sprintf('Method \"%s()\" must be overridden by class \"%s\" to deal with non-iterable values.', __FUNCTION__, static::class));\n        }\n\n        foreach ($string as $s) {\n            if ($this->equalsTo((string) $s)) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    abstract public function folded(): static;\n\n    public function ignoreCase(): static\n    {\n        $str = clone $this;\n        $str->ignoreCase = true;\n\n        return $str;\n    }\n\n    /**\n     * @param string|string[] $needle\n     */\n    public function indexOf(string|iterable $needle, int $offset = 0): ?int\n    {\n        if (\\is_string($needle)) {\n            throw new \\TypeError(\\sprintf('Method \"%s()\" must be overridden by class \"%s\" to deal with non-iterable values.', __FUNCTION__, static::class));\n        }\n\n        $i = \\PHP_INT_MAX;\n\n        foreach ($needle as $n) {\n            $j = $this->indexOf((string) $n, $offset);\n\n            if (null !== $j && $j < $i) {\n                $i = $j;\n            }\n        }\n\n        return \\PHP_INT_MAX === $i ? null : $i;\n    }\n\n    /**\n     * @param string|string[] $needle\n     */\n    public function indexOfLast(string|iterable $needle, int $offset = 0): ?int\n    {\n        if (\\is_string($needle)) {\n            throw new \\TypeError(\\sprintf('Method \"%s()\" must be overridden by class \"%s\" to deal with non-iterable values.', __FUNCTION__, static::class));\n        }\n\n        $i = null;\n\n        foreach ($needle as $n) {\n            $j = $this->indexOfLast((string) $n, $offset);\n\n            if (null !== $j && $j >= $i) {\n                $i = $offset = $j;\n            }\n        }\n\n        return $i;\n    }\n\n    public function isEmpty(): bool\n    {\n        return '' === $this->string;\n    }\n\n    abstract public function join(array $strings, ?string $lastGlue = null): static;\n\n    public function jsonSerialize(): string\n    {\n        return $this->string;\n    }\n\n    abstract public function length(): int;\n\n    abstract public function lower(): static;\n\n    /**\n     * Matches the string using a regular expression.\n     *\n     * Pass PREG_PATTERN_ORDER or PREG_SET_ORDER as $flags to get all occurrences matching the regular expression.\n     *\n     * @return array All matches in a multi-dimensional array ordered according to flags\n     */\n    abstract public function match(string $regexp, int $flags = 0, int $offset = 0): array;\n\n    abstract public function padBoth(int $length, string $padStr = ' '): static;\n\n    abstract public function padEnd(int $length, string $padStr = ' '): static;\n\n    abstract public function padStart(int $length, string $padStr = ' '): static;\n\n    abstract public function prepend(string ...$prefix): static;\n\n    public function repeat(int $multiplier): static\n    {\n        if (0 > $multiplier) {\n            throw new InvalidArgumentException(\\sprintf('Multiplier must be positive, %d given.', $multiplier));\n        }\n\n        $str = clone $this;\n        $str->string = str_repeat($str->string, $multiplier);\n\n        return $str;\n    }\n\n    abstract public function replace(string $from, string $to): static;\n\n    abstract public function replaceMatches(string $fromRegexp, string|callable $to): static;\n\n    abstract public function reverse(): static;\n\n    abstract public function slice(int $start = 0, ?int $length = null): static;\n\n    abstract public function snake(): static;\n\n    abstract public function splice(string $replacement, int $start = 0, ?int $length = null): static;\n\n    /**\n     * @return static[]\n     */\n    public function split(string $delimiter, ?int $limit = null, ?int $flags = null): array\n    {\n        if (null === $flags) {\n            throw new \\TypeError('Split behavior when $flags is null must be implemented by child classes.');\n        }\n\n        if ($this->ignoreCase) {\n            $delimiter .= 'i';\n        }\n\n        set_error_handler(static fn ($t, $m) => throw new InvalidArgumentException($m));\n\n        try {\n            if (false === $chunks = preg_split($delimiter, $this->string, $limit, $flags)) {\n                throw new RuntimeException('Splitting failed with error: '.preg_last_error_msg());\n            }\n        } finally {\n            restore_error_handler();\n        }\n\n        $str = clone $this;\n\n        if (self::PREG_SPLIT_OFFSET_CAPTURE & $flags) {\n            foreach ($chunks as &$chunk) {\n                $str->string = $chunk[0];\n                $chunk[0] = clone $str;\n            }\n        } else {\n            foreach ($chunks as &$chunk) {\n                $str->string = $chunk;\n                $chunk = clone $str;\n            }\n        }\n\n        return $chunks;\n    }\n\n    /**\n     * @param string|string[] $prefix\n     */\n    public function startsWith(string|iterable $prefix): bool\n    {\n        if (\\is_string($prefix)) {\n            throw new \\TypeError(\\sprintf('Method \"%s()\" must be overridden by class \"%s\" to deal with non-iterable values.', __FUNCTION__, static::class));\n        }\n\n        foreach ($prefix as $prefix) {\n            if ($this->startsWith((string) $prefix)) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    abstract public function title(bool $allWords = false): static;\n\n    public function toByteString(?string $toEncoding = null): ByteString\n    {\n        $b = new ByteString();\n\n        $toEncoding = \\in_array($toEncoding, ['utf8', 'utf-8', 'UTF8'], true) ? 'UTF-8' : $toEncoding;\n\n        if (null === $toEncoding || $toEncoding === $fromEncoding = $this instanceof AbstractUnicodeString || preg_match('//u', $b->string) ? 'UTF-8' : 'Windows-1252') {\n            $b->string = $this->string;\n\n            return $b;\n        }\n\n        try {\n            $b->string = mb_convert_encoding($this->string, $toEncoding, 'UTF-8');\n        } catch (\\ValueError $e) {\n            if (!\\function_exists('iconv')) {\n                throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);\n            }\n\n            $b->string = iconv('UTF-8', $toEncoding, $this->string);\n        }\n\n        return $b;\n    }\n\n    public function toCodePointString(): CodePointString\n    {\n        return new CodePointString($this->string);\n    }\n\n    public function toString(): string\n    {\n        return $this->string;\n    }\n\n    public function toUnicodeString(): UnicodeString\n    {\n        return new UnicodeString($this->string);\n    }\n\n    abstract public function trim(string $chars = \" \\t\\n\\r\\0\\x0B\\x0C\\u{A0}\\u{FEFF}\"): static;\n\n    abstract public function trimEnd(string $chars = \" \\t\\n\\r\\0\\x0B\\x0C\\u{A0}\\u{FEFF}\"): static;\n\n    /**\n     * @param string|string[] $prefix\n     */\n    public function trimPrefix($prefix): static\n    {\n        if (\\is_array($prefix) || $prefix instanceof \\Traversable) { // don't use is_iterable(), it's slow\n            foreach ($prefix as $s) {\n                $t = $this->trimPrefix($s);\n\n                if ($t->string !== $this->string) {\n                    return $t;\n                }\n            }\n\n            return clone $this;\n        }\n\n        $str = clone $this;\n\n        if ($prefix instanceof self) {\n            $prefix = $prefix->string;\n        } else {\n            $prefix = (string) $prefix;\n        }\n\n        if ('' !== $prefix && \\strlen($this->string) >= \\strlen($prefix) && 0 === substr_compare($this->string, $prefix, 0, \\strlen($prefix), $this->ignoreCase)) {\n            $str->string = substr($this->string, \\strlen($prefix));\n        }\n\n        return $str;\n    }\n\n    abstract public function trimStart(string $chars = \" \\t\\n\\r\\0\\x0B\\x0C\\u{A0}\\u{FEFF}\"): static;\n\n    /**\n     * @param string|string[] $suffix\n     */\n    public function trimSuffix($suffix): static\n    {\n        if (\\is_array($suffix) || $suffix instanceof \\Traversable) { // don't use is_iterable(), it's slow\n            foreach ($suffix as $s) {\n                $t = $this->trimSuffix($s);\n\n                if ($t->string !== $this->string) {\n                    return $t;\n                }\n            }\n\n            return clone $this;\n        }\n\n        $str = clone $this;\n\n        if ($suffix instanceof self) {\n            $suffix = $suffix->string;\n        } else {\n            $suffix = (string) $suffix;\n        }\n\n        if ('' !== $suffix && \\strlen($this->string) >= \\strlen($suffix) && 0 === substr_compare($this->string, $suffix, -\\strlen($suffix), null, $this->ignoreCase)) {\n            $str->string = substr($this->string, 0, -\\strlen($suffix));\n        }\n\n        return $str;\n    }\n\n    public function truncate(int $length, string $ellipsis = '', bool $cut = true): static\n    {\n        $stringLength = $this->length();\n\n        if ($stringLength <= $length) {\n            return clone $this;\n        }\n\n        $ellipsisLength = '' !== $ellipsis ? (new static($ellipsis))->length() : 0;\n\n        if ($length < $ellipsisLength) {\n            $ellipsisLength = 0;\n        }\n\n        if (!$cut) {\n            if (null === $length = $this->indexOf([' ', \"\\r\", \"\\n\", \"\\t\"], ($length ?: 1) - 1)) {\n                return clone $this;\n            }\n\n            $length += $ellipsisLength;\n        }\n\n        $str = $this->slice(0, $length - $ellipsisLength);\n\n        return $ellipsisLength ? $str->trimEnd()->append($ellipsis) : $str;\n    }\n\n    abstract public function upper(): static;\n\n    /**\n     * Returns the printable length on a terminal.\n     */\n    abstract public function width(bool $ignoreAnsiDecoration = true): int;\n\n    public function wordwrap(int $width = 75, string $break = \"\\n\", bool $cut = false): static\n    {\n        $lines = '' !== $break ? $this->split($break) : [clone $this];\n        $chars = [];\n        $mask = '';\n\n        if (1 === \\count($lines) && '' === $lines[0]->string) {\n            return $lines[0];\n        }\n\n        foreach ($lines as $i => $line) {\n            if ($i) {\n                $chars[] = $break;\n                $mask .= '#';\n            }\n\n            foreach ($line->chunk() as $char) {\n                $chars[] = $char->string;\n                $mask .= ' ' === $char->string ? ' ' : '?';\n            }\n        }\n\n        $string = '';\n        $j = 0;\n        $b = $i = -1;\n        $mask = wordwrap($mask, $width, '#', $cut);\n\n        while (false !== $b = strpos($mask, '#', $b + 1)) {\n            for (++$i; $i < $b; ++$i) {\n                $string .= $chars[$j];\n                unset($chars[$j++]);\n            }\n\n            if ($break === $chars[$j] || ' ' === $chars[$j]) {\n                unset($chars[$j++]);\n            }\n\n            $string .= $break;\n        }\n\n        $str = clone $this;\n        $str->string = $string.implode('', $chars);\n\n        return $str;\n    }\n\n    public function __sleep(): array\n    {\n        return ['string'];\n    }\n\n    public function __clone()\n    {\n        $this->ignoreCase = false;\n    }\n\n    public function __toString(): string\n    {\n        return $this->string;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/string/AbstractUnicodeString.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\String;\n\nuse Symfony\\Component\\String\\Exception\\ExceptionInterface;\nuse Symfony\\Component\\String\\Exception\\InvalidArgumentException;\nuse Symfony\\Component\\String\\Exception\\RuntimeException;\n\n/**\n * Represents a string of abstract Unicode characters.\n *\n * Unicode defines 3 types of \"characters\" (bytes, code points and grapheme clusters).\n * This class is the abstract type to use as a type-hint when the logic you want to\n * implement is Unicode-aware but doesn't care about code points vs grapheme clusters.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n *\n * @throws ExceptionInterface\n */\nabstract class AbstractUnicodeString extends AbstractString\n{\n    public const NFC = \\Normalizer::NFC;\n    public const NFD = \\Normalizer::NFD;\n    public const NFKC = \\Normalizer::NFKC;\n    public const NFKD = \\Normalizer::NFKD;\n\n    // all ASCII letters sorted by typical frequency of occurrence\n    private const ASCII = \"\\x20\\x65\\x69\\x61\\x73\\x6E\\x74\\x72\\x6F\\x6C\\x75\\x64\\x5D\\x5B\\x63\\x6D\\x70\\x27\\x0A\\x67\\x7C\\x68\\x76\\x2E\\x66\\x62\\x2C\\x3A\\x3D\\x2D\\x71\\x31\\x30\\x43\\x32\\x2A\\x79\\x78\\x29\\x28\\x4C\\x39\\x41\\x53\\x2F\\x50\\x22\\x45\\x6A\\x4D\\x49\\x6B\\x33\\x3E\\x35\\x54\\x3C\\x44\\x34\\x7D\\x42\\x7B\\x38\\x46\\x77\\x52\\x36\\x37\\x55\\x47\\x4E\\x3B\\x4A\\x7A\\x56\\x23\\x48\\x4F\\x57\\x5F\\x26\\x21\\x4B\\x3F\\x58\\x51\\x25\\x59\\x5C\\x09\\x5A\\x2B\\x7E\\x5E\\x24\\x40\\x60\\x7F\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\x0B\\x0C\\x0D\\x0E\\x0F\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1A\\x1B\\x1C\\x1D\\x1E\\x1F\";\n\n    // the subset of folded case mappings that is not in lower case mappings\n    private const FOLD_FROM = ['İ', 'µ', 'ſ', \"\\xCD\\x85\", 'ς', 'ϐ', 'ϑ', 'ϕ', 'ϖ', 'ϰ', 'ϱ', 'ϵ', 'ẛ', \"\\xE1\\xBE\\xBE\", 'ß', 'ŉ', 'ǰ', 'ΐ', 'ΰ', 'և', 'ẖ', 'ẗ', 'ẘ', 'ẙ', 'ẚ', 'ẞ', 'ὐ', 'ὒ', 'ὔ', 'ὖ', 'ᾀ', 'ᾁ', 'ᾂ', 'ᾃ', 'ᾄ', 'ᾅ', 'ᾆ', 'ᾇ', 'ᾈ', 'ᾉ', 'ᾊ', 'ᾋ', 'ᾌ', 'ᾍ', 'ᾎ', 'ᾏ', 'ᾐ', 'ᾑ', 'ᾒ', 'ᾓ', 'ᾔ', 'ᾕ', 'ᾖ', 'ᾗ', 'ᾘ', 'ᾙ', 'ᾚ', 'ᾛ', 'ᾜ', 'ᾝ', 'ᾞ', 'ᾟ', 'ᾠ', 'ᾡ', 'ᾢ', 'ᾣ', 'ᾤ', 'ᾥ', 'ᾦ', 'ᾧ', 'ᾨ', 'ᾩ', 'ᾪ', 'ᾫ', 'ᾬ', 'ᾭ', 'ᾮ', 'ᾯ', 'ᾲ', 'ᾳ', 'ᾴ', 'ᾶ', 'ᾷ', 'ᾼ', 'ῂ', 'ῃ', 'ῄ', 'ῆ', 'ῇ', 'ῌ', 'ῒ', 'ῖ', 'ῗ', 'ῢ', 'ῤ', 'ῦ', 'ῧ', 'ῲ', 'ῳ', 'ῴ', 'ῶ', 'ῷ', 'ῼ', 'ﬀ', 'ﬁ', 'ﬂ', 'ﬃ', 'ﬄ', 'ﬅ', 'ﬆ', 'ﬓ', 'ﬔ', 'ﬕ', 'ﬖ', 'ﬗ'];\n    private const FOLD_TO = ['i̇', 'μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', 'ρ', 'ε', 'ṡ', 'ι', 'ss', 'ʼn', 'ǰ', 'ΐ', 'ΰ', 'եւ', 'ẖ', 'ẗ', 'ẘ', 'ẙ', 'aʾ', 'ss', 'ὐ', 'ὒ', 'ὔ', 'ὖ', 'ἀι', 'ἁι', 'ἂι', 'ἃι', 'ἄι', 'ἅι', 'ἆι', 'ἇι', 'ἀι', 'ἁι', 'ἂι', 'ἃι', 'ἄι', 'ἅι', 'ἆι', 'ἇι', 'ἠι', 'ἡι', 'ἢι', 'ἣι', 'ἤι', 'ἥι', 'ἦι', 'ἧι', 'ἠι', 'ἡι', 'ἢι', 'ἣι', 'ἤι', 'ἥι', 'ἦι', 'ἧι', 'ὠι', 'ὡι', 'ὢι', 'ὣι', 'ὤι', 'ὥι', 'ὦι', 'ὧι', 'ὠι', 'ὡι', 'ὢι', 'ὣι', 'ὤι', 'ὥι', 'ὦι', 'ὧι', 'ὰι', 'αι', 'άι', 'ᾶ', 'ᾶι', 'αι', 'ὴι', 'ηι', 'ήι', 'ῆ', 'ῆι', 'ηι', 'ῒ', 'ῖ', 'ῗ', 'ῢ', 'ῤ', 'ῦ', 'ῧ', 'ὼι', 'ωι', 'ώι', 'ῶ', 'ῶι', 'ωι', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'st', 'st', 'մն', 'մե', 'մի', 'վն', 'մխ'];\n\n    // the subset of https://github.com/unicode-org/cldr/blob/master/common/transforms/Latin-ASCII.xml that is not in NFKD\n    private const TRANSLIT_FROM = ['Æ', 'Ð', 'Ø', 'Þ', 'ß', 'æ', 'ð', 'ø', 'þ', 'Đ', 'đ', 'Ħ', 'ħ', 'ı', 'ĸ', 'Ŀ', 'ŀ', 'Ł', 'ł', 'ŉ', 'Ŋ', 'ŋ', 'Œ', 'œ', 'Ŧ', 'ŧ', 'ƀ', 'Ɓ', 'Ƃ', 'ƃ', 'Ƈ', 'ƈ', 'Ɖ', 'Ɗ', 'Ƌ', 'ƌ', 'Ɛ', 'Ƒ', 'ƒ', 'Ɠ', 'ƕ', 'Ɩ', 'Ɨ', 'Ƙ', 'ƙ', 'ƚ', 'Ɲ', 'ƞ', 'Ƣ', 'ƣ', 'Ƥ', 'ƥ', 'ƫ', 'Ƭ', 'ƭ', 'Ʈ', 'Ʋ', 'Ƴ', 'ƴ', 'Ƶ', 'ƶ', 'Ǆ', 'ǅ', 'ǆ', 'Ǥ', 'ǥ', 'ȡ', 'Ȥ', 'ȥ', 'ȴ', 'ȵ', 'ȶ', 'ȷ', 'ȸ', 'ȹ', 'Ⱥ', 'Ȼ', 'ȼ', 'Ƚ', 'Ⱦ', 'ȿ', 'ɀ', 'Ƀ', 'Ʉ', 'Ɇ', 'ɇ', 'Ɉ', 'ɉ', 'Ɍ', 'ɍ', 'Ɏ', 'ɏ', 'ɓ', 'ɕ', 'ɖ', 'ɗ', 'ɛ', 'ɟ', 'ɠ', 'ɡ', 'ɢ', 'ɦ', 'ɧ', 'ɨ', 'ɪ', 'ɫ', 'ɬ', 'ɭ', 'ɱ', 'ɲ', 'ɳ', 'ɴ', 'ɶ', 'ɼ', 'ɽ', 'ɾ', 'ʀ', 'ʂ', 'ʈ', 'ʉ', 'ʋ', 'ʏ', 'ʐ', 'ʑ', 'ʙ', 'ʛ', 'ʜ', 'ʝ', 'ʟ', 'ʠ', 'ʣ', 'ʥ', 'ʦ', 'ʪ', 'ʫ', 'ᴀ', 'ᴁ', 'ᴃ', 'ᴄ', 'ᴅ', 'ᴆ', 'ᴇ', 'ᴊ', 'ᴋ', 'ᴌ', 'ᴍ', 'ᴏ', 'ᴘ', 'ᴛ', 'ᴜ', 'ᴠ', 'ᴡ', 'ᴢ', 'ᵫ', 'ᵬ', 'ᵭ', 'ᵮ', 'ᵯ', 'ᵰ', 'ᵱ', 'ᵲ', 'ᵳ', 'ᵴ', 'ᵵ', 'ᵶ', 'ᵺ', 'ᵻ', 'ᵽ', 'ᵾ', 'ᶀ', 'ᶁ', 'ᶂ', 'ᶃ', 'ᶄ', 'ᶅ', 'ᶆ', 'ᶇ', 'ᶈ', 'ᶉ', 'ᶊ', 'ᶌ', 'ᶍ', 'ᶎ', 'ᶏ', 'ᶑ', 'ᶒ', 'ᶓ', 'ᶖ', 'ᶙ', 'ẚ', 'ẜ', 'ẝ', 'ẞ', 'Ỻ', 'ỻ', 'Ỽ', 'ỽ', 'Ỿ', 'ỿ', '©', '®', '₠', '₢', '₣', '₤', '₧', '₺', '₹', 'ℌ', '℞', '㎧', '㎮', '㏆', '㏗', '㏞', '㏟', '¼', '½', '¾', '⅓', '⅔', '⅕', '⅖', '⅗', '⅘', '⅙', '⅚', '⅛', '⅜', '⅝', '⅞', '⅟', '〇', '‘', '’', '‚', '‛', '“', '”', '„', '‟', '′', '″', '〝', '〞', '«', '»', '‹', '›', '‐', '‑', '‒', '–', '—', '―', '︱', '︲', '﹘', '‖', '⁄', '⁅', '⁆', '⁎', '、', '。', '〈', '〉', '《', '》', '〔', '〕', '〘', '〙', '〚', '〛', '︑', '︒', '︹', '︺', '︽', '︾', '︿', '﹀', '﹑', '﹝', '﹞', '｟', '｠', '｡', '､', '×', '÷', '−', '∕', '∖', '∣', '∥', '≪', '≫', '⦅', '⦆'];\n    private const TRANSLIT_TO = ['AE', 'D', 'O', 'TH', 'ss', 'ae', 'd', 'o', 'th', 'D', 'd', 'H', 'h', 'i', 'q', 'L', 'l', 'L', 'l', '\\'n', 'N', 'n', 'OE', 'oe', 'T', 't', 'b', 'B', 'B', 'b', 'C', 'c', 'D', 'D', 'D', 'd', 'E', 'F', 'f', 'G', 'hv', 'I', 'I', 'K', 'k', 'l', 'N', 'n', 'OI', 'oi', 'P', 'p', 't', 'T', 't', 'T', 'V', 'Y', 'y', 'Z', 'z', 'DZ', 'Dz', 'dz', 'G', 'g', 'd', 'Z', 'z', 'l', 'n', 't', 'j', 'db', 'qp', 'A', 'C', 'c', 'L', 'T', 's', 'z', 'B', 'U', 'E', 'e', 'J', 'j', 'R', 'r', 'Y', 'y', 'b', 'c', 'd', 'd', 'e', 'j', 'g', 'g', 'G', 'h', 'h', 'i', 'I', 'l', 'l', 'l', 'm', 'n', 'n', 'N', 'OE', 'r', 'r', 'r', 'R', 's', 't', 'u', 'v', 'Y', 'z', 'z', 'B', 'G', 'H', 'j', 'L', 'q', 'dz', 'dz', 'ts', 'ls', 'lz', 'A', 'AE', 'B', 'C', 'D', 'D', 'E', 'J', 'K', 'L', 'M', 'O', 'P', 'T', 'U', 'V', 'W', 'Z', 'ue', 'b', 'd', 'f', 'm', 'n', 'p', 'r', 'r', 's', 't', 'z', 'th', 'I', 'p', 'U', 'b', 'd', 'f', 'g', 'k', 'l', 'm', 'n', 'p', 'r', 's', 'v', 'x', 'z', 'a', 'd', 'e', 'e', 'i', 'u', 'a', 's', 's', 'SS', 'LL', 'll', 'V', 'v', 'Y', 'y', '(C)', '(R)', 'CE', 'Cr', 'Fr.', 'L.', 'Pts', 'TL', 'Rs', 'x', 'Rx', 'm/s', 'rad/s', 'C/kg', 'pH', 'V/m', 'A/m', ' 1/4', ' 1/2', ' 3/4', ' 1/3', ' 2/3', ' 1/5', ' 2/5', ' 3/5', ' 4/5', ' 1/6', ' 5/6', ' 1/8', ' 3/8', ' 5/8', ' 7/8', ' 1/', '0', '\\'', '\\'', ',', '\\'', '\"', '\"', ',,', '\"', '\\'', '\"', '\"', '\"', '<<', '>>', '<', '>', '-', '-', '-', '-', '-', '-', '-', '-', '-', '||', '/', '[', ']', '*', ',', '.', '<', '>', '<<', '>>', '[', ']', '[', ']', '[', ']', ',', '.', '[', ']', '<<', '>>', '<', '>', ',', '[', ']', '((', '))', '.', ',', '*', '/', '-', '/', '\\\\', '|', '||', '<<', '>>', '((', '))'];\n\n    private static array $transliterators = [];\n    private static array $tableZero;\n    private static array $tableWide;\n\n    public static function fromCodePoints(int ...$codes): static\n    {\n        $string = '';\n\n        foreach ($codes as $code) {\n            if (0x80 > $code %= 0x200000) {\n                $string .= \\chr($code);\n            } elseif (0x800 > $code) {\n                $string .= \\chr(0xC0 | $code >> 6).\\chr(0x80 | $code & 0x3F);\n            } elseif (0x10000 > $code) {\n                $string .= \\chr(0xE0 | $code >> 12).\\chr(0x80 | $code >> 6 & 0x3F).\\chr(0x80 | $code & 0x3F);\n            } else {\n                $string .= \\chr(0xF0 | $code >> 18).\\chr(0x80 | $code >> 12 & 0x3F).\\chr(0x80 | $code >> 6 & 0x3F).\\chr(0x80 | $code & 0x3F);\n            }\n        }\n\n        return new static($string);\n    }\n\n    /**\n     * Generic UTF-8 to ASCII transliteration.\n     *\n     * Install the intl extension for best results.\n     *\n     * @param string[]|\\Transliterator[]|\\Closure[] $rules See \"*-Latin\" rules from Transliterator::listIDs()\n     */\n    public function ascii(array $rules = []): self\n    {\n        $str = clone $this;\n        $s = $str->string;\n        $str->string = '';\n\n        array_unshift($rules, 'nfd');\n        $rules[] = 'latin-ascii';\n\n        if (\\function_exists('transliterator_transliterate')) {\n            $rules[] = 'any-latin/bgn';\n        }\n\n        $rules[] = 'nfkd';\n        $rules[] = '[:nonspacing mark:] remove';\n\n        while (\\strlen($s) - 1 > $i = strspn($s, self::ASCII)) {\n            if (0 < --$i) {\n                $str->string .= substr($s, 0, $i);\n                $s = substr($s, $i);\n            }\n\n            if (!$rule = array_shift($rules)) {\n                $rules = []; // An empty rule interrupts the next ones\n            }\n\n            if ($rule instanceof \\Transliterator) {\n                $s = $rule->transliterate($s);\n            } elseif ($rule instanceof \\Closure) {\n                $s = $rule($s);\n            } elseif ($rule) {\n                if ('nfd' === $rule = strtolower($rule)) {\n                    normalizer_is_normalized($s, self::NFD) ?: $s = normalizer_normalize($s, self::NFD);\n                } elseif ('nfkd' === $rule) {\n                    normalizer_is_normalized($s, self::NFKD) ?: $s = normalizer_normalize($s, self::NFKD);\n                } elseif ('[:nonspacing mark:] remove' === $rule) {\n                    $s = preg_replace('/\\p{Mn}++/u', '', $s);\n                } elseif ('latin-ascii' === $rule) {\n                    $s = str_replace(self::TRANSLIT_FROM, self::TRANSLIT_TO, $s);\n                } elseif ('de-ascii' === $rule) {\n                    $s = preg_replace(\"/([AUO])\\u{0308}(?=\\p{Ll})/u\", '$1e', $s);\n                    $s = str_replace([\"a\\u{0308}\", \"o\\u{0308}\", \"u\\u{0308}\", \"A\\u{0308}\", \"O\\u{0308}\", \"U\\u{0308}\"], ['ae', 'oe', 'ue', 'AE', 'OE', 'UE'], $s);\n                } elseif (\\function_exists('transliterator_transliterate')) {\n                    if (null === $transliterator = self::$transliterators[$rule] ??= \\Transliterator::create($rule)) {\n                        if ('any-latin/bgn' === $rule) {\n                            $rule = 'any-latin';\n                            $transliterator = self::$transliterators[$rule] ??= \\Transliterator::create($rule);\n                        }\n\n                        if (null === $transliterator) {\n                            throw new InvalidArgumentException(\\sprintf('Unknown transliteration rule \"%s\".', $rule));\n                        }\n\n                        self::$transliterators['any-latin/bgn'] = $transliterator;\n                    }\n\n                    $s = $transliterator->transliterate($s);\n                }\n            } elseif (!\\function_exists('iconv')) {\n                $s = preg_replace('/[^\\x00-\\x7F]/u', '?', $s);\n            } else {\n                $previousLocale = setlocale(\\LC_CTYPE, 0);\n                try {\n                    setlocale(\\LC_CTYPE, 'C');\n                    $s = @preg_replace_callback('/[^\\x00-\\x7F]/u', static function ($c) {\n                        $c = (string) iconv('UTF-8', 'ASCII//TRANSLIT', $c[0]);\n\n                        if ('' === $c && '' === iconv('UTF-8', 'ASCII//TRANSLIT', '²')) {\n                            throw new \\LogicException(\\sprintf('\"%s\" requires a translit-able iconv implementation, try installing \"gnu-libiconv\" if you\\'re using Alpine Linux.', static::class));\n                        }\n\n                        return 1 < \\strlen($c) ? ltrim($c, '\\'`\"^~') : ('' !== $c ? $c : '?');\n                    }, $s);\n                } finally {\n                    setlocale(\\LC_CTYPE, $previousLocale);\n                }\n            }\n        }\n\n        $str->string .= $s;\n\n        return $str;\n    }\n\n    public function camel(): static\n    {\n        $str = clone $this;\n        $str->string = str_replace(' ', '', preg_replace_callback('/\\b.(?!\\p{Lu})/u', static function ($m) {\n            static $i = 0;\n\n            return 1 === ++$i ? ('İ' === $m[0] ? 'i̇' : mb_strtolower($m[0], 'UTF-8')) : mb_convert_case($m[0], \\MB_CASE_TITLE, 'UTF-8');\n        }, preg_replace('/[^\\pL0-9]++/u', ' ', $this->string)));\n\n        return $str;\n    }\n\n    /**\n     * @return int[]\n     */\n    public function codePointsAt(int $offset): array\n    {\n        $str = $this->slice($offset, 1);\n\n        if ('' === $str->string) {\n            return [];\n        }\n\n        $codePoints = [];\n\n        foreach (preg_split('//u', $str->string, -1, \\PREG_SPLIT_NO_EMPTY) as $c) {\n            $codePoints[] = mb_ord($c, 'UTF-8');\n        }\n\n        return $codePoints;\n    }\n\n    public function folded(bool $compat = true): static\n    {\n        $str = clone $this;\n\n        if (!$compat || !\\defined('Normalizer::NFKC_CF')) {\n            $str->string = normalizer_normalize($str->string, $compat ? \\Normalizer::NFKC : \\Normalizer::NFC);\n            $str->string = mb_strtolower(str_replace(self::FOLD_FROM, self::FOLD_TO, $str->string), 'UTF-8');\n        } else {\n            $str->string = normalizer_normalize($str->string, \\Normalizer::NFKC_CF);\n        }\n\n        return $str;\n    }\n\n    public function join(array $strings, ?string $lastGlue = null): static\n    {\n        $str = clone $this;\n\n        $tail = null !== $lastGlue && 1 < \\count($strings) ? $lastGlue.array_pop($strings) : '';\n        $str->string = implode($this->string, $strings).$tail;\n\n        if (!preg_match('//u', $str->string)) {\n            throw new InvalidArgumentException('Invalid UTF-8 string.');\n        }\n\n        return $str;\n    }\n\n    public function lower(): static\n    {\n        $str = clone $this;\n        $str->string = mb_strtolower(str_replace('İ', 'i̇', $str->string), 'UTF-8');\n\n        return $str;\n    }\n\n    public function match(string $regexp, int $flags = 0, int $offset = 0): array\n    {\n        $match = ((\\PREG_PATTERN_ORDER | \\PREG_SET_ORDER) & $flags) ? 'preg_match_all' : 'preg_match';\n\n        if ($this->ignoreCase) {\n            $regexp .= 'i';\n        }\n\n        set_error_handler(static fn ($t, $m) => throw new InvalidArgumentException($m));\n\n        try {\n            if (false === $match($regexp.'u', $this->string, $matches, $flags | \\PREG_UNMATCHED_AS_NULL, $offset)) {\n                throw new RuntimeException('Matching failed with error: '.preg_last_error_msg());\n            }\n        } finally {\n            restore_error_handler();\n        }\n\n        return $matches;\n    }\n\n    public function normalize(int $form = self::NFC): static\n    {\n        if (!\\in_array($form, [self::NFC, self::NFD, self::NFKC, self::NFKD])) {\n            throw new InvalidArgumentException('Unsupported normalization form.');\n        }\n\n        $str = clone $this;\n        normalizer_is_normalized($str->string, $form) ?: $str->string = normalizer_normalize($str->string, $form);\n\n        return $str;\n    }\n\n    public function padBoth(int $length, string $padStr = ' '): static\n    {\n        if ('' === $padStr || !preg_match('//u', $padStr)) {\n            throw new InvalidArgumentException('Invalid UTF-8 string.');\n        }\n\n        $pad = clone $this;\n        $pad->string = $padStr;\n\n        return $this->pad($length, $pad, \\STR_PAD_BOTH);\n    }\n\n    public function padEnd(int $length, string $padStr = ' '): static\n    {\n        if ('' === $padStr || !preg_match('//u', $padStr)) {\n            throw new InvalidArgumentException('Invalid UTF-8 string.');\n        }\n\n        $pad = clone $this;\n        $pad->string = $padStr;\n\n        return $this->pad($length, $pad, \\STR_PAD_RIGHT);\n    }\n\n    public function padStart(int $length, string $padStr = ' '): static\n    {\n        if ('' === $padStr || !preg_match('//u', $padStr)) {\n            throw new InvalidArgumentException('Invalid UTF-8 string.');\n        }\n\n        $pad = clone $this;\n        $pad->string = $padStr;\n\n        return $this->pad($length, $pad, \\STR_PAD_LEFT);\n    }\n\n    public function replaceMatches(string $fromRegexp, string|callable $to): static\n    {\n        if ($this->ignoreCase) {\n            $fromRegexp .= 'i';\n        }\n\n        if (\\is_array($to) || $to instanceof \\Closure) {\n            $replace = 'preg_replace_callback';\n            $to = static function (array $m) use ($to): string {\n                $to = $to($m);\n\n                if ('' !== $to && (!\\is_string($to) || !preg_match('//u', $to))) {\n                    throw new InvalidArgumentException('Replace callback must return a valid UTF-8 string.');\n                }\n\n                return $to;\n            };\n        } elseif ('' !== $to && !preg_match('//u', $to)) {\n            throw new InvalidArgumentException('Invalid UTF-8 string.');\n        } else {\n            $replace = 'preg_replace';\n        }\n\n        set_error_handler(static fn ($t, $m) => throw new InvalidArgumentException($m));\n\n        try {\n            if (null === $string = $replace($fromRegexp.'u', $to, $this->string)) {\n                $lastError = preg_last_error();\n\n                foreach (get_defined_constants(true)['pcre'] as $k => $v) {\n                    if ($lastError === $v && str_ends_with($k, '_ERROR')) {\n                        throw new RuntimeException('Matching failed with '.$k.'.');\n                    }\n                }\n\n                throw new RuntimeException('Matching failed with unknown error code.');\n            }\n        } finally {\n            restore_error_handler();\n        }\n\n        $str = clone $this;\n        $str->string = $string;\n\n        return $str;\n    }\n\n    public function reverse(): static\n    {\n        $str = clone $this;\n        $str->string = implode('', array_reverse(preg_split('/(\\X)/u', $str->string, -1, \\PREG_SPLIT_DELIM_CAPTURE | \\PREG_SPLIT_NO_EMPTY)));\n\n        return $str;\n    }\n\n    public function snake(): static\n    {\n        $str = $this->camel();\n        $str->string = mb_strtolower(preg_replace(['/(\\p{Lu}+)(\\p{Lu}\\p{Ll})/u', '/([\\p{Ll}0-9])(\\p{Lu})/u'], '\\1_\\2', $str->string), 'UTF-8');\n\n        return $str;\n    }\n\n    public function title(bool $allWords = false): static\n    {\n        $str = clone $this;\n\n        $limit = $allWords ? -1 : 1;\n\n        $str->string = preg_replace_callback('/\\b./u', static fn (array $m): string => mb_convert_case($m[0], \\MB_CASE_TITLE, 'UTF-8'), $str->string, $limit);\n\n        return $str;\n    }\n\n    public function trim(string $chars = \" \\t\\n\\r\\0\\x0B\\x0C\\u{A0}\\u{FEFF}\"): static\n    {\n        if (\" \\t\\n\\r\\0\\x0B\\x0C\\u{A0}\\u{FEFF}\" !== $chars && !preg_match('//u', $chars)) {\n            throw new InvalidArgumentException('Invalid UTF-8 chars.');\n        }\n        $chars = preg_quote($chars);\n\n        $str = clone $this;\n        $str->string = preg_replace(\"{^[$chars]++|[$chars]++$}uD\", '', $str->string);\n\n        return $str;\n    }\n\n    public function trimEnd(string $chars = \" \\t\\n\\r\\0\\x0B\\x0C\\u{A0}\\u{FEFF}\"): static\n    {\n        if (\" \\t\\n\\r\\0\\x0B\\x0C\\u{A0}\\u{FEFF}\" !== $chars && !preg_match('//u', $chars)) {\n            throw new InvalidArgumentException('Invalid UTF-8 chars.');\n        }\n        $chars = preg_quote($chars);\n\n        $str = clone $this;\n        $str->string = preg_replace(\"{[$chars]++$}uD\", '', $str->string);\n\n        return $str;\n    }\n\n    public function trimPrefix($prefix): static\n    {\n        if (!$this->ignoreCase) {\n            return parent::trimPrefix($prefix);\n        }\n\n        $str = clone $this;\n\n        if ($prefix instanceof \\Traversable) {\n            $prefix = iterator_to_array($prefix, false);\n        } elseif ($prefix instanceof parent) {\n            $prefix = $prefix->string;\n        }\n\n        $prefix = implode('|', array_map('preg_quote', (array) $prefix));\n        $str->string = preg_replace(\"{^(?:$prefix)}iuD\", '', $this->string);\n\n        return $str;\n    }\n\n    public function trimStart(string $chars = \" \\t\\n\\r\\0\\x0B\\x0C\\u{A0}\\u{FEFF}\"): static\n    {\n        if (\" \\t\\n\\r\\0\\x0B\\x0C\\u{A0}\\u{FEFF}\" !== $chars && !preg_match('//u', $chars)) {\n            throw new InvalidArgumentException('Invalid UTF-8 chars.');\n        }\n        $chars = preg_quote($chars);\n\n        $str = clone $this;\n        $str->string = preg_replace(\"{^[$chars]++}uD\", '', $str->string);\n\n        return $str;\n    }\n\n    public function trimSuffix($suffix): static\n    {\n        if (!$this->ignoreCase) {\n            return parent::trimSuffix($suffix);\n        }\n\n        $str = clone $this;\n\n        if ($suffix instanceof \\Traversable) {\n            $suffix = iterator_to_array($suffix, false);\n        } elseif ($suffix instanceof parent) {\n            $suffix = $suffix->string;\n        }\n\n        $suffix = implode('|', array_map('preg_quote', (array) $suffix));\n        $str->string = preg_replace(\"{(?:$suffix)$}iuD\", '', $this->string);\n\n        return $str;\n    }\n\n    public function upper(): static\n    {\n        $str = clone $this;\n        $str->string = mb_strtoupper($str->string, 'UTF-8');\n\n        return $str;\n    }\n\n    public function width(bool $ignoreAnsiDecoration = true): int\n    {\n        $width = 0;\n        $s = str_replace([\"\\x00\", \"\\x05\", \"\\x07\"], '', $this->string);\n\n        if (str_contains($s, \"\\r\")) {\n            $s = str_replace([\"\\r\\n\", \"\\r\"], \"\\n\", $s);\n        }\n\n        if (!$ignoreAnsiDecoration) {\n            $s = preg_replace('/[\\p{Cc}\\x7F]++/u', '', $s);\n        }\n\n        foreach (explode(\"\\n\", $s) as $s) {\n            if ($ignoreAnsiDecoration) {\n                $s = preg_replace('/(?:\\x1B(?:\n                    \\[ [\\x30-\\x3F]*+ [\\x20-\\x2F]*+ [\\x40-\\x7E]\n                    | [P\\]X^_] .*? \\x1B\\\\\\\\\n                    | [\\x41-\\x7E]\n                )|[\\p{Cc}\\x7F]++)/xu', '', $s);\n            }\n\n            $lineWidth = $this->wcswidth($s);\n\n            if ($lineWidth > $width) {\n                $width = $lineWidth;\n            }\n        }\n\n        return $width;\n    }\n\n    private function pad(int $len, self $pad, int $type): static\n    {\n        $sLen = $this->length();\n\n        if ($len <= $sLen) {\n            return clone $this;\n        }\n\n        $padLen = $pad->length();\n        $freeLen = $len - $sLen;\n        $len = $freeLen % $padLen;\n\n        switch ($type) {\n            case \\STR_PAD_RIGHT:\n                return $this->append(str_repeat($pad->string, intdiv($freeLen, $padLen)).($len ? $pad->slice(0, $len) : ''));\n\n            case \\STR_PAD_LEFT:\n                return $this->prepend(str_repeat($pad->string, intdiv($freeLen, $padLen)).($len ? $pad->slice(0, $len) : ''));\n\n            case \\STR_PAD_BOTH:\n                $freeLen /= 2;\n\n                $rightLen = ceil($freeLen);\n                $len = $rightLen % $padLen;\n                $str = $this->append(str_repeat($pad->string, intdiv($rightLen, $padLen)).($len ? $pad->slice(0, $len) : ''));\n\n                $leftLen = floor($freeLen);\n                $len = $leftLen % $padLen;\n\n                return $str->prepend(str_repeat($pad->string, intdiv($leftLen, $padLen)).($len ? $pad->slice(0, $len) : ''));\n\n            default:\n                throw new InvalidArgumentException('Invalid padding type.');\n        }\n    }\n\n    /**\n     * Based on https://github.com/jquast/wcwidth, a Python implementation of https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c.\n     */\n    private function wcswidth(string $string): int\n    {\n        $width = 0;\n\n        foreach (preg_split('//u', $string, -1, \\PREG_SPLIT_NO_EMPTY) as $c) {\n            $codePoint = mb_ord($c, 'UTF-8');\n\n            if (0 === $codePoint // NULL\n                || 0x034F === $codePoint // COMBINING GRAPHEME JOINER\n                || (0x200B <= $codePoint && 0x200F >= $codePoint) // ZERO WIDTH SPACE to RIGHT-TO-LEFT MARK\n                || 0x2028 === $codePoint // LINE SEPARATOR\n                || 0x2029 === $codePoint // PARAGRAPH SEPARATOR\n                || (0x202A <= $codePoint && 0x202E >= $codePoint) // LEFT-TO-RIGHT EMBEDDING to RIGHT-TO-LEFT OVERRIDE\n                || (0x2060 <= $codePoint && 0x2063 >= $codePoint) // WORD JOINER to INVISIBLE SEPARATOR\n            ) {\n                continue;\n            }\n\n            // Non printable characters\n            if (32 > $codePoint // C0 control characters\n                || (0x07F <= $codePoint && 0x0A0 > $codePoint) // C1 control characters and DEL\n            ) {\n                return -1;\n            }\n\n            self::$tableZero ??= require __DIR__.'/Resources/data/wcswidth_table_zero.php';\n\n            if ($codePoint >= self::$tableZero[0][0] && $codePoint <= self::$tableZero[$ubound = \\count(self::$tableZero) - 1][1]) {\n                $lbound = 0;\n                while ($ubound >= $lbound) {\n                    $mid = floor(($lbound + $ubound) / 2);\n\n                    if ($codePoint > self::$tableZero[$mid][1]) {\n                        $lbound = $mid + 1;\n                    } elseif ($codePoint < self::$tableZero[$mid][0]) {\n                        $ubound = $mid - 1;\n                    } else {\n                        continue 2;\n                    }\n                }\n            }\n\n            self::$tableWide ??= require __DIR__.'/Resources/data/wcswidth_table_wide.php';\n\n            if ($codePoint >= self::$tableWide[0][0] && $codePoint <= self::$tableWide[$ubound = \\count(self::$tableWide) - 1][1]) {\n                $lbound = 0;\n                while ($ubound >= $lbound) {\n                    $mid = floor(($lbound + $ubound) / 2);\n\n                    if ($codePoint > self::$tableWide[$mid][1]) {\n                        $lbound = $mid + 1;\n                    } elseif ($codePoint < self::$tableWide[$mid][0]) {\n                        $ubound = $mid - 1;\n                    } else {\n                        $width += 2;\n\n                        continue 2;\n                    }\n                }\n            }\n\n            ++$width;\n        }\n\n        return $width;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/string/ByteString.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\String;\n\nuse Symfony\\Component\\String\\Exception\\ExceptionInterface;\nuse Symfony\\Component\\String\\Exception\\InvalidArgumentException;\nuse Symfony\\Component\\String\\Exception\\RuntimeException;\n\n/**\n * Represents a binary-safe string of bytes.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n * @author Hugo Hamon <hugohamon@neuf.fr>\n *\n * @throws ExceptionInterface\n */\nclass ByteString extends AbstractString\n{\n    private const ALPHABET_ALPHANUMERIC = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';\n\n    public function __construct(string $string = '')\n    {\n        $this->string = $string;\n    }\n\n    /*\n     * The following method was derived from code of the Hack Standard Library (v4.40 - 2020-05-03)\n     *\n     * https://github.com/hhvm/hsl/blob/80a42c02f036f72a42f0415e80d6b847f4bf62d5/src/random/private.php#L16\n     *\n     * Code subject to the MIT license (https://github.com/hhvm/hsl/blob/master/LICENSE).\n     *\n     * Copyright (c) 2004-2020, Facebook, Inc. (https://www.facebook.com/)\n     */\n\n    public static function fromRandom(int $length = 16, ?string $alphabet = null): self\n    {\n        if ($length <= 0) {\n            throw new InvalidArgumentException(\\sprintf('A strictly positive length is expected, \"%d\" given.', $length));\n        }\n\n        $alphabet ??= self::ALPHABET_ALPHANUMERIC;\n        $alphabetSize = \\strlen($alphabet);\n        $bits = (int) ceil(log($alphabetSize, 2.0));\n        if ($bits <= 0 || $bits > 56) {\n            throw new InvalidArgumentException('The length of the alphabet must in the [2^1, 2^56] range.');\n        }\n\n        $ret = '';\n        while ($length > 0) {\n            $urandomLength = (int) ceil(2 * $length * $bits / 8.0);\n            $data = random_bytes($urandomLength);\n            $unpackedData = 0;\n            $unpackedBits = 0;\n            for ($i = 0; $i < $urandomLength && $length > 0; ++$i) {\n                // Unpack 8 bits\n                $unpackedData = ($unpackedData << 8) | \\ord($data[$i]);\n                $unpackedBits += 8;\n\n                // While we have enough bits to select a character from the alphabet, keep\n                // consuming the random data\n                for (; $unpackedBits >= $bits && $length > 0; $unpackedBits -= $bits) {\n                    $index = ($unpackedData & ((1 << $bits) - 1));\n                    $unpackedData >>= $bits;\n                    // Unfortunately, the alphabet size is not necessarily a power of two.\n                    // Worst case, it is 2^k + 1, which means we need (k+1) bits and we\n                    // have around a 50% chance of missing as k gets larger\n                    if ($index < $alphabetSize) {\n                        $ret .= $alphabet[$index];\n                        --$length;\n                    }\n                }\n            }\n        }\n\n        return new static($ret);\n    }\n\n    public function bytesAt(int $offset): array\n    {\n        $str = $this->string[$offset] ?? '';\n\n        return '' === $str ? [] : [\\ord($str)];\n    }\n\n    public function append(string ...$suffix): static\n    {\n        $str = clone $this;\n        $str->string .= 1 >= \\count($suffix) ? ($suffix[0] ?? '') : implode('', $suffix);\n\n        return $str;\n    }\n\n    public function camel(): static\n    {\n        $str = clone $this;\n\n        $parts = explode(' ', trim(ucwords(preg_replace('/[^a-zA-Z0-9\\x7f-\\xff]++/', ' ', $this->string))));\n        $parts[0] = 1 !== \\strlen($parts[0]) && ctype_upper($parts[0]) ? $parts[0] : lcfirst($parts[0]);\n        $str->string = implode('', $parts);\n\n        return $str;\n    }\n\n    public function chunk(int $length = 1): array\n    {\n        if (1 > $length) {\n            throw new InvalidArgumentException('The chunk length must be greater than zero.');\n        }\n\n        if ('' === $this->string) {\n            return [];\n        }\n\n        $str = clone $this;\n        $chunks = [];\n\n        foreach (str_split($this->string, $length) as $chunk) {\n            $str->string = $chunk;\n            $chunks[] = clone $str;\n        }\n\n        return $chunks;\n    }\n\n    public function endsWith(string|iterable|AbstractString $suffix): bool\n    {\n        if ($suffix instanceof AbstractString) {\n            $suffix = $suffix->string;\n        } elseif (!\\is_string($suffix)) {\n            return parent::endsWith($suffix);\n        }\n\n        return '' !== $suffix && \\strlen($this->string) >= \\strlen($suffix) && 0 === substr_compare($this->string, $suffix, -\\strlen($suffix), null, $this->ignoreCase);\n    }\n\n    public function equalsTo(string|iterable|AbstractString $string): bool\n    {\n        if ($string instanceof AbstractString) {\n            $string = $string->string;\n        } elseif (!\\is_string($string)) {\n            return parent::equalsTo($string);\n        }\n\n        if ('' !== $string && $this->ignoreCase) {\n            return 0 === strcasecmp($string, $this->string);\n        }\n\n        return $string === $this->string;\n    }\n\n    public function folded(): static\n    {\n        $str = clone $this;\n        $str->string = strtolower($str->string);\n\n        return $str;\n    }\n\n    public function indexOf(string|iterable|AbstractString $needle, int $offset = 0): ?int\n    {\n        if ($needle instanceof AbstractString) {\n            $needle = $needle->string;\n        } elseif (!\\is_string($needle)) {\n            return parent::indexOf($needle, $offset);\n        }\n\n        if ('' === $needle) {\n            return null;\n        }\n\n        $i = $this->ignoreCase ? stripos($this->string, $needle, $offset) : strpos($this->string, $needle, $offset);\n\n        return false === $i ? null : $i;\n    }\n\n    public function indexOfLast(string|iterable|AbstractString $needle, int $offset = 0): ?int\n    {\n        if ($needle instanceof AbstractString) {\n            $needle = $needle->string;\n        } elseif (!\\is_string($needle)) {\n            return parent::indexOfLast($needle, $offset);\n        }\n\n        if ('' === $needle) {\n            return null;\n        }\n\n        $i = $this->ignoreCase ? strripos($this->string, $needle, $offset) : strrpos($this->string, $needle, $offset);\n\n        return false === $i ? null : $i;\n    }\n\n    public function isUtf8(): bool\n    {\n        return '' === $this->string || preg_match('//u', $this->string);\n    }\n\n    public function join(array $strings, ?string $lastGlue = null): static\n    {\n        $str = clone $this;\n\n        $tail = null !== $lastGlue && 1 < \\count($strings) ? $lastGlue.array_pop($strings) : '';\n        $str->string = implode($this->string, $strings).$tail;\n\n        return $str;\n    }\n\n    public function length(): int\n    {\n        return \\strlen($this->string);\n    }\n\n    public function lower(): static\n    {\n        $str = clone $this;\n        $str->string = strtolower($str->string);\n\n        return $str;\n    }\n\n    public function match(string $regexp, int $flags = 0, int $offset = 0): array\n    {\n        $match = ((\\PREG_PATTERN_ORDER | \\PREG_SET_ORDER) & $flags) ? 'preg_match_all' : 'preg_match';\n\n        if ($this->ignoreCase) {\n            $regexp .= 'i';\n        }\n\n        set_error_handler(static fn ($t, $m) => throw new InvalidArgumentException($m));\n\n        try {\n            if (false === $match($regexp, $this->string, $matches, $flags | \\PREG_UNMATCHED_AS_NULL, $offset)) {\n                throw new RuntimeException('Matching failed with error: '.preg_last_error_msg());\n            }\n        } finally {\n            restore_error_handler();\n        }\n\n        return $matches;\n    }\n\n    public function padBoth(int $length, string $padStr = ' '): static\n    {\n        $str = clone $this;\n        $str->string = str_pad($this->string, $length, $padStr, \\STR_PAD_BOTH);\n\n        return $str;\n    }\n\n    public function padEnd(int $length, string $padStr = ' '): static\n    {\n        $str = clone $this;\n        $str->string = str_pad($this->string, $length, $padStr, \\STR_PAD_RIGHT);\n\n        return $str;\n    }\n\n    public function padStart(int $length, string $padStr = ' '): static\n    {\n        $str = clone $this;\n        $str->string = str_pad($this->string, $length, $padStr, \\STR_PAD_LEFT);\n\n        return $str;\n    }\n\n    public function prepend(string ...$prefix): static\n    {\n        $str = clone $this;\n        $str->string = (1 >= \\count($prefix) ? ($prefix[0] ?? '') : implode('', $prefix)).$str->string;\n\n        return $str;\n    }\n\n    public function replace(string $from, string $to): static\n    {\n        $str = clone $this;\n\n        if ('' !== $from) {\n            $str->string = $this->ignoreCase ? str_ireplace($from, $to, $this->string) : str_replace($from, $to, $this->string);\n        }\n\n        return $str;\n    }\n\n    public function replaceMatches(string $fromRegexp, string|callable $to): static\n    {\n        if ($this->ignoreCase) {\n            $fromRegexp .= 'i';\n        }\n\n        $replace = \\is_array($to) || $to instanceof \\Closure ? 'preg_replace_callback' : 'preg_replace';\n\n        set_error_handler(static fn ($t, $m) => throw new InvalidArgumentException($m));\n\n        try {\n            if (null === $string = $replace($fromRegexp, $to, $this->string)) {\n                $lastError = preg_last_error();\n\n                foreach (get_defined_constants(true)['pcre'] as $k => $v) {\n                    if ($lastError === $v && str_ends_with($k, '_ERROR')) {\n                        throw new RuntimeException('Matching failed with '.$k.'.');\n                    }\n                }\n\n                throw new RuntimeException('Matching failed with unknown error code.');\n            }\n        } finally {\n            restore_error_handler();\n        }\n\n        $str = clone $this;\n        $str->string = $string;\n\n        return $str;\n    }\n\n    public function reverse(): static\n    {\n        $str = clone $this;\n        $str->string = strrev($str->string);\n\n        return $str;\n    }\n\n    public function slice(int $start = 0, ?int $length = null): static\n    {\n        $str = clone $this;\n        $str->string = (string) substr($this->string, $start, $length ?? \\PHP_INT_MAX);\n\n        return $str;\n    }\n\n    public function snake(): static\n    {\n        $str = $this->camel();\n        $str->string = strtolower(preg_replace(['/([A-Z]+)([A-Z][a-z])/', '/([a-z\\d])([A-Z])/'], '\\1_\\2', $str->string));\n\n        return $str;\n    }\n\n    public function splice(string $replacement, int $start = 0, ?int $length = null): static\n    {\n        $str = clone $this;\n        $str->string = substr_replace($this->string, $replacement, $start, $length ?? \\PHP_INT_MAX);\n\n        return $str;\n    }\n\n    public function split(string $delimiter, ?int $limit = null, ?int $flags = null): array\n    {\n        if (1 > $limit ??= \\PHP_INT_MAX) {\n            throw new InvalidArgumentException('Split limit must be a positive integer.');\n        }\n\n        if ('' === $delimiter) {\n            throw new InvalidArgumentException('Split delimiter is empty.');\n        }\n\n        if (null !== $flags) {\n            return parent::split($delimiter, $limit, $flags);\n        }\n\n        $str = clone $this;\n        $chunks = $this->ignoreCase\n            ? preg_split('{'.preg_quote($delimiter).'}iD', $this->string, $limit)\n            : explode($delimiter, $this->string, $limit);\n\n        foreach ($chunks as &$chunk) {\n            $str->string = $chunk;\n            $chunk = clone $str;\n        }\n\n        return $chunks;\n    }\n\n    public function startsWith(string|iterable|AbstractString $prefix): bool\n    {\n        if ($prefix instanceof AbstractString) {\n            $prefix = $prefix->string;\n        } elseif (!\\is_string($prefix)) {\n            return parent::startsWith($prefix);\n        }\n\n        return '' !== $prefix && 0 === ($this->ignoreCase ? strncasecmp($this->string, $prefix, \\strlen($prefix)) : strncmp($this->string, $prefix, \\strlen($prefix)));\n    }\n\n    public function title(bool $allWords = false): static\n    {\n        $str = clone $this;\n        $str->string = $allWords ? ucwords($str->string) : ucfirst($str->string);\n\n        return $str;\n    }\n\n    public function toUnicodeString(?string $fromEncoding = null): UnicodeString\n    {\n        return new UnicodeString($this->toCodePointString($fromEncoding)->string);\n    }\n\n    public function toCodePointString(?string $fromEncoding = null): CodePointString\n    {\n        $u = new CodePointString();\n\n        if (\\in_array($fromEncoding, [null, 'utf8', 'utf-8', 'UTF8', 'UTF-8'], true) && preg_match('//u', $this->string)) {\n            $u->string = $this->string;\n\n            return $u;\n        }\n\n        set_error_handler(static fn ($t, $m) => throw new InvalidArgumentException($m));\n\n        try {\n            try {\n                $validEncoding = false !== mb_detect_encoding($this->string, $fromEncoding ?? 'Windows-1252', true);\n            } catch (InvalidArgumentException $e) {\n                if (!\\function_exists('iconv')) {\n                    throw $e;\n                }\n\n                $u->string = iconv($fromEncoding ?? 'Windows-1252', 'UTF-8', $this->string);\n\n                return $u;\n            }\n        } finally {\n            restore_error_handler();\n        }\n\n        if (!$validEncoding) {\n            throw new InvalidArgumentException(\\sprintf('Invalid \"%s\" string.', $fromEncoding ?? 'Windows-1252'));\n        }\n\n        $u->string = mb_convert_encoding($this->string, 'UTF-8', $fromEncoding ?? 'Windows-1252');\n\n        return $u;\n    }\n\n    public function trim(string $chars = \" \\t\\n\\r\\0\\x0B\\x0C\"): static\n    {\n        $str = clone $this;\n        $str->string = trim($str->string, $chars);\n\n        return $str;\n    }\n\n    public function trimEnd(string $chars = \" \\t\\n\\r\\0\\x0B\\x0C\"): static\n    {\n        $str = clone $this;\n        $str->string = rtrim($str->string, $chars);\n\n        return $str;\n    }\n\n    public function trimStart(string $chars = \" \\t\\n\\r\\0\\x0B\\x0C\"): static\n    {\n        $str = clone $this;\n        $str->string = ltrim($str->string, $chars);\n\n        return $str;\n    }\n\n    public function upper(): static\n    {\n        $str = clone $this;\n        $str->string = strtoupper($str->string);\n\n        return $str;\n    }\n\n    public function width(bool $ignoreAnsiDecoration = true): int\n    {\n        $string = preg_match('//u', $this->string) ? $this->string : preg_replace('/[\\x80-\\xFF]/', '?', $this->string);\n\n        return (new CodePointString($string))->width($ignoreAnsiDecoration);\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/string/CHANGELOG.md",
    "content": "CHANGELOG\n=========\n\n6.2\n---\n\n  * Add support for emoji in `AsciiSlugger`\n\n5.4\n---\n\n * Add `trimSuffix()` and `trimPrefix()` methods\n\n5.3\n---\n\n * Made `AsciiSlugger` fallback to parent locale's symbolsMap\n\n5.2.0\n-----\n\n * added a `FrenchInflector` class\n\n5.1.0\n-----\n\n * added the `AbstractString::reverse()` method\n * made `AbstractString::width()` follow POSIX.1-2001\n * added `LazyString` which provides memoizing stringable objects\n * The component is not marked as `@experimental` anymore\n * added the `s()` helper method to get either an `UnicodeString` or `ByteString` instance,\n   depending of the input string UTF-8 compliancy\n * added `$cut` parameter to `Symfony\\Component\\String\\AbstractString::truncate()`\n * added `AbstractString::containsAny()`\n * allow passing a string of custom characters to `ByteString::fromRandom()`\n\n5.0.0\n-----\n\n * added the component as experimental\n"
  },
  {
    "path": "server/vendor/symfony/string/CodePointString.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\String;\n\nuse Symfony\\Component\\String\\Exception\\ExceptionInterface;\nuse Symfony\\Component\\String\\Exception\\InvalidArgumentException;\n\n/**\n * Represents a string of Unicode code points encoded as UTF-8.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n * @author Hugo Hamon <hugohamon@neuf.fr>\n *\n * @throws ExceptionInterface\n */\nclass CodePointString extends AbstractUnicodeString\n{\n    public function __construct(string $string = '')\n    {\n        if ('' !== $string && !preg_match('//u', $string)) {\n            throw new InvalidArgumentException('Invalid UTF-8 string.');\n        }\n\n        $this->string = $string;\n    }\n\n    public function append(string ...$suffix): static\n    {\n        $str = clone $this;\n        $str->string .= 1 >= \\count($suffix) ? ($suffix[0] ?? '') : implode('', $suffix);\n\n        if (!preg_match('//u', $str->string)) {\n            throw new InvalidArgumentException('Invalid UTF-8 string.');\n        }\n\n        return $str;\n    }\n\n    public function chunk(int $length = 1): array\n    {\n        if (1 > $length) {\n            throw new InvalidArgumentException('The chunk length must be greater than zero.');\n        }\n\n        if ('' === $this->string) {\n            return [];\n        }\n\n        $rx = '/(';\n        while (65535 < $length) {\n            $rx .= '.{65535}';\n            $length -= 65535;\n        }\n        $rx .= '.{'.$length.'})/us';\n\n        $str = clone $this;\n        $chunks = [];\n\n        foreach (preg_split($rx, $this->string, -1, \\PREG_SPLIT_DELIM_CAPTURE | \\PREG_SPLIT_NO_EMPTY) as $chunk) {\n            $str->string = $chunk;\n            $chunks[] = clone $str;\n        }\n\n        return $chunks;\n    }\n\n    public function codePointsAt(int $offset): array\n    {\n        $str = $offset ? $this->slice($offset, 1) : $this;\n\n        return '' === $str->string ? [] : [mb_ord($str->string, 'UTF-8')];\n    }\n\n    public function endsWith(string|iterable|AbstractString $suffix): bool\n    {\n        if ($suffix instanceof AbstractString) {\n            $suffix = $suffix->string;\n        } elseif (!\\is_string($suffix)) {\n            return parent::endsWith($suffix);\n        }\n\n        if ('' === $suffix || !preg_match('//u', $suffix)) {\n            return false;\n        }\n\n        if ($this->ignoreCase) {\n            return preg_match('{'.preg_quote($suffix).'$}iuD', $this->string);\n        }\n\n        return \\strlen($this->string) >= \\strlen($suffix) && 0 === substr_compare($this->string, $suffix, -\\strlen($suffix));\n    }\n\n    public function equalsTo(string|iterable|AbstractString $string): bool\n    {\n        if ($string instanceof AbstractString) {\n            $string = $string->string;\n        } elseif (!\\is_string($string)) {\n            return parent::equalsTo($string);\n        }\n\n        if ('' !== $string && $this->ignoreCase) {\n            return \\strlen($string) === \\strlen($this->string) && 0 === mb_stripos($this->string, $string, 0, 'UTF-8');\n        }\n\n        return $string === $this->string;\n    }\n\n    public function indexOf(string|iterable|AbstractString $needle, int $offset = 0): ?int\n    {\n        if ($needle instanceof AbstractString) {\n            $needle = $needle->string;\n        } elseif (!\\is_string($needle)) {\n            return parent::indexOf($needle, $offset);\n        }\n\n        if ('' === $needle) {\n            return null;\n        }\n\n        $i = $this->ignoreCase ? mb_stripos($this->string, $needle, $offset, 'UTF-8') : mb_strpos($this->string, $needle, $offset, 'UTF-8');\n\n        return false === $i ? null : $i;\n    }\n\n    public function indexOfLast(string|iterable|AbstractString $needle, int $offset = 0): ?int\n    {\n        if ($needle instanceof AbstractString) {\n            $needle = $needle->string;\n        } elseif (!\\is_string($needle)) {\n            return parent::indexOfLast($needle, $offset);\n        }\n\n        if ('' === $needle) {\n            return null;\n        }\n\n        $i = $this->ignoreCase ? mb_strripos($this->string, $needle, $offset, 'UTF-8') : mb_strrpos($this->string, $needle, $offset, 'UTF-8');\n\n        return false === $i ? null : $i;\n    }\n\n    public function length(): int\n    {\n        return mb_strlen($this->string, 'UTF-8');\n    }\n\n    public function prepend(string ...$prefix): static\n    {\n        $str = clone $this;\n        $str->string = (1 >= \\count($prefix) ? ($prefix[0] ?? '') : implode('', $prefix)).$this->string;\n\n        if (!preg_match('//u', $str->string)) {\n            throw new InvalidArgumentException('Invalid UTF-8 string.');\n        }\n\n        return $str;\n    }\n\n    public function replace(string $from, string $to): static\n    {\n        $str = clone $this;\n\n        if ('' === $from || !preg_match('//u', $from)) {\n            return $str;\n        }\n\n        if ('' !== $to && !preg_match('//u', $to)) {\n            throw new InvalidArgumentException('Invalid UTF-8 string.');\n        }\n\n        if ($this->ignoreCase) {\n            $str->string = implode($to, preg_split('{'.preg_quote($from).'}iuD', $this->string));\n        } else {\n            $str->string = str_replace($from, $to, $this->string);\n        }\n\n        return $str;\n    }\n\n    public function slice(int $start = 0, ?int $length = null): static\n    {\n        $str = clone $this;\n        $str->string = mb_substr($this->string, $start, $length, 'UTF-8');\n\n        return $str;\n    }\n\n    public function splice(string $replacement, int $start = 0, ?int $length = null): static\n    {\n        if (!preg_match('//u', $replacement)) {\n            throw new InvalidArgumentException('Invalid UTF-8 string.');\n        }\n\n        $str = clone $this;\n        $start = $start ? \\strlen(mb_substr($this->string, 0, $start, 'UTF-8')) : 0;\n        $length = $length ? \\strlen(mb_substr($this->string, $start, $length, 'UTF-8')) : $length;\n        $str->string = substr_replace($this->string, $replacement, $start, $length ?? \\PHP_INT_MAX);\n\n        return $str;\n    }\n\n    public function split(string $delimiter, ?int $limit = null, ?int $flags = null): array\n    {\n        if (1 > $limit ??= \\PHP_INT_MAX) {\n            throw new InvalidArgumentException('Split limit must be a positive integer.');\n        }\n\n        if ('' === $delimiter) {\n            throw new InvalidArgumentException('Split delimiter is empty.');\n        }\n\n        if (null !== $flags) {\n            return parent::split($delimiter.'u', $limit, $flags);\n        }\n\n        if (!preg_match('//u', $delimiter)) {\n            throw new InvalidArgumentException('Split delimiter is not a valid UTF-8 string.');\n        }\n\n        $str = clone $this;\n        $chunks = $this->ignoreCase\n            ? preg_split('{'.preg_quote($delimiter).'}iuD', $this->string, $limit)\n            : explode($delimiter, $this->string, $limit);\n\n        foreach ($chunks as &$chunk) {\n            $str->string = $chunk;\n            $chunk = clone $str;\n        }\n\n        return $chunks;\n    }\n\n    public function startsWith(string|iterable|AbstractString $prefix): bool\n    {\n        if ($prefix instanceof AbstractString) {\n            $prefix = $prefix->string;\n        } elseif (!\\is_string($prefix)) {\n            return parent::startsWith($prefix);\n        }\n\n        if ('' === $prefix || !preg_match('//u', $prefix)) {\n            return false;\n        }\n\n        if ($this->ignoreCase) {\n            return 0 === mb_stripos($this->string, $prefix, 0, 'UTF-8');\n        }\n\n        return 0 === strncmp($this->string, $prefix, \\strlen($prefix));\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/string/Exception/ExceptionInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\String\\Exception;\n\ninterface ExceptionInterface extends \\Throwable\n{\n}\n"
  },
  {
    "path": "server/vendor/symfony/string/Exception/InvalidArgumentException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\String\\Exception;\n\nclass InvalidArgumentException extends \\InvalidArgumentException implements ExceptionInterface\n{\n}\n"
  },
  {
    "path": "server/vendor/symfony/string/Exception/RuntimeException.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\String\\Exception;\n\nclass RuntimeException extends \\RuntimeException implements ExceptionInterface\n{\n}\n"
  },
  {
    "path": "server/vendor/symfony/string/Inflector/EnglishInflector.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\String\\Inflector;\n\nfinal class EnglishInflector implements InflectorInterface\n{\n    /**\n     * Map English plural to singular suffixes.\n     *\n     * @see http://english-zone.com/spelling/plurals.html\n     */\n    private const PLURAL_MAP = [\n        // First entry: plural suffix, reversed\n        // Second entry: length of plural suffix\n        // Third entry: Whether the suffix may succeed a vowel\n        // Fourth entry: Whether the suffix may succeed a consonant\n        // Fifth entry: singular suffix, normal\n\n        // insignias (insigne), insignia (insigne)\n        ['saingisni', 9, true, true, 'insigne'],\n        ['aingisni', 8, true, true, 'insigne'],\n\n        // passersby (passerby)\n        ['ybsressap', 9, true, true, 'passerby'],\n\n        // nodes (node)\n        ['sedon', 5, true, true, 'node'],\n\n        // bacteria (bacterium)\n        ['airetcab', 8, true, true, 'bacterium'],\n\n        // issues (issue)\n        ['seussi', 6, true, true, 'issue'],\n\n        // corpora (corpus)\n        ['aroproc', 7, true, true, 'corpus'],\n\n        // criteria (criterion)\n        ['airetirc', 8, true, true, 'criterion'],\n\n        // curricula (curriculum)\n        ['alucirruc', 9, true, true, 'curriculum'],\n\n        // quora (quorum)\n        ['arouq', 5, true, true, 'quorum'],\n\n        // genera (genus)\n        ['areneg', 6, true, true, 'genus'],\n\n        // media (medium)\n        ['aidem', 5, true, true, 'medium'],\n\n        // memoranda (memorandum)\n        ['adnaromem', 9, true, true, 'memorandum'],\n\n        // phenomena (phenomenon)\n        ['anemonehp', 9, true, true, 'phenomenon'],\n\n        // strata (stratum)\n        ['atarts', 6, true, true, 'stratum'],\n\n        // nebulae (nebula)\n        ['ea', 2, true, true, 'a'],\n\n        // services (service)\n        ['secivres', 8, true, true, 'service'],\n\n        // mice (mouse), lice (louse)\n        ['eci', 3, false, true, 'ouse'],\n\n        // geese (goose)\n        ['esee', 4, false, true, 'oose'],\n\n        // fungi (fungus), alumni (alumnus), syllabi (syllabus), radii (radius)\n        ['i', 1, true, true, 'us'],\n\n        // men (man), women (woman)\n        ['nem', 3, true, true, 'man'],\n\n        // children (child)\n        ['nerdlihc', 8, true, true, 'child'],\n\n        // oxen (ox)\n        ['nexo', 4, false, false, 'ox'],\n\n        // indices (index), appendices (appendix), prices (price)\n        ['seci', 4, false, true, ['ex', 'ix', 'ice']],\n\n        // codes (code)\n        ['sedoc', 5, false, true, 'code'],\n\n        // selfies (selfie)\n        ['seifles', 7, true, true, 'selfie'],\n\n        // zombies (zombie)\n        ['seibmoz', 7, true, true, 'zombie'],\n\n        // movies (movie)\n        ['seivom', 6, true, true, 'movie'],\n\n        // names (name)\n        ['seman', 5, true, false, 'name'],\n\n        // conspectuses (conspectus), prospectuses (prospectus)\n        ['sesutcep', 8, true, true, 'pectus'],\n\n        // feet (foot)\n        ['teef', 4, true, true, 'foot'],\n\n        // geese (goose)\n        ['eseeg', 5, true, true, 'goose'],\n\n        // teeth (tooth)\n        ['hteet', 5, true, true, 'tooth'],\n\n        // news (news)\n        ['swen', 4, true, true, 'news'],\n\n        // series (series)\n        ['seires', 6, true, true, 'series'],\n\n        // babies (baby)\n        ['sei', 3, false, true, 'y'],\n\n        // accesses (access), addresses (address), kisses (kiss)\n        ['sess', 4, true, false, 'ss'],\n\n        // statuses (status)\n        ['sesutats', 8, true, true, 'status'],\n\n        // article (articles), ancle (ancles)\n        ['sel', 3, true, true, 'le'],\n\n        // analyses (analysis), ellipses (ellipsis), fungi (fungus),\n        // neuroses (neurosis), theses (thesis), emphases (emphasis),\n        // oases (oasis), crises (crisis), houses (house), bases (base),\n        // atlases (atlas)\n        ['ses', 3, true, true, ['s', 'se', 'sis']],\n\n        // objectives (objective), alternative (alternatives)\n        ['sevit', 5, true, true, 'tive'],\n\n        // drives (drive)\n        ['sevird', 6, false, true, 'drive'],\n\n        // lives (life), wives (wife)\n        ['sevi', 4, false, true, 'ife'],\n\n        // moves (move)\n        ['sevom', 5, true, true, 'move'],\n\n        // hooves (hoof), dwarves (dwarf), elves (elf), leaves (leaf), caves (cave), staves (staff)\n        ['sev', 3, true, true, ['f', 've', 'ff']],\n\n        // axes (axis), axes (ax), axes (axe)\n        ['sexa', 4, false, false, ['ax', 'axe', 'axis']],\n\n        // indexes (index), matrixes (matrix)\n        ['sex', 3, true, false, 'x'],\n\n        // quizzes (quiz)\n        ['sezz', 4, true, false, 'z'],\n\n        // bureaus (bureau)\n        ['suae', 4, false, true, 'eau'],\n\n        // fees (fee), trees (tree), employees (employee)\n        ['see', 3, true, true, 'ee'],\n\n        // edges (edge)\n        ['segd', 4, true, true, 'dge'],\n\n        // outages (outage) - specific fix to avoid 'outag'\n        ['segatuo', 7, true, true, 'outage'],\n\n        // roses (rose), garages (garage), cassettes (cassette),\n        // waltzes (waltz), heroes (hero), bushes (bush), arches (arch),\n        // shoes (shoe)\n        ['se', 2, true, true, ['', 'e']],\n\n        // status (status)\n        ['sutats', 6, true, true, 'status'],\n\n        // tags (tag)\n        ['s', 1, true, true, ''],\n\n        // chateaux (chateau)\n        ['xuae', 4, false, true, 'eau'],\n\n        // people (person)\n        ['elpoep', 6, true, true, 'person'],\n    ];\n\n    /**\n     * Map English singular to plural suffixes.\n     *\n     * @see http://english-zone.com/spelling/plurals.html\n     */\n    private const SINGULAR_MAP = [\n        // First entry: singular suffix, reversed\n        // Second entry: length of singular suffix\n        // Third entry: Whether the suffix may succeed a vowel\n        // Fourth entry: Whether the suffix may succeed a consonant\n        // Fifth entry: plural suffix, normal\n\n        // passerby (passersby)\n        ['ybressap', 8, true, true, 'passersby'],\n\n        // insigne (insignia, insignias)\n        ['engisni', 7, true, true, ['insignia', 'insignias']],\n\n        // nodes (node)\n        ['edon', 4, true, true, 'nodes'],\n\n        // axes (axis)\n        ['sixa', 4, false, false, 'axes'],\n\n        // criterion (criteria)\n        ['airetirc', 8, false, false, 'criterion'],\n\n        // nebulae (nebula)\n        ['aluben', 6, false, false, 'nebulae'],\n\n        // children (child)\n        ['dlihc', 5, true, true, 'children'],\n\n        // prices (price)\n        ['eci', 3, false, true, 'ices'],\n\n        // services (service)\n        ['ecivres', 7, true, true, 'services'],\n\n        // lives (life), wives (wife)\n        ['efi', 3, false, true, 'ives'],\n\n        // selfies (selfie)\n        ['eifles', 6, true, true, 'selfies'],\n\n        // movies (movie)\n        ['eivom', 5, true, true, 'movies'],\n\n        // lice (louse)\n        ['esuol', 5, false, true, 'lice'],\n\n        // mice (mouse)\n        ['esuom', 5, false, true, 'mice'],\n\n        // geese (goose)\n        ['esoo', 4, false, true, 'eese'],\n\n        // houses (house), bases (base)\n        ['es', 2, true, true, 'ses'],\n\n        // geese (goose)\n        ['esoog', 5, true, true, 'geese'],\n\n        // caves (cave)\n        ['ev', 2, true, true, 'ves'],\n\n        // drives (drive)\n        ['evird', 5, false, true, 'drives'],\n\n        // objectives (objective), alternative (alternatives)\n        ['evit', 4, true, true, 'tives'],\n\n        // moves (move)\n        ['evom', 4, true, true, 'moves'],\n\n        // staves (staff)\n        ['ffats', 5, true, true, 'staves'],\n\n        // hooves (hoof), dwarves (dwarf), elves (elf), leaves (leaf)\n        ['ff', 2, true, true, 'ffs'],\n\n        // hooves (hoof), dwarves (dwarf), elves (elf), leaves (leaf)\n        ['f', 1, true, true, ['fs', 'ves']],\n\n        // arches (arch)\n        ['hc', 2, true, true, 'ches'],\n\n        // bushes (bush)\n        ['hs', 2, true, true, 'shes'],\n\n        // teeth (tooth)\n        ['htoot', 5, true, true, 'teeth'],\n\n        // albums (album)\n        ['mubla', 5, true, true, 'albums'],\n\n        // quorums (quorum)\n        ['murouq', 6, true, true, ['quora', 'quorums']],\n\n        // bacteria (bacterium), curricula (curriculum), media (medium), memoranda (memorandum), phenomena (phenomenon), strata (stratum)\n        ['mu', 2, true, true, 'a'],\n\n        // men (man), women (woman)\n        ['nam', 3, true, true, 'men'],\n\n        // people (person)\n        ['nosrep', 6, true, true, ['persons', 'people']],\n\n        // criteria (criterion)\n        ['noiretirc', 9, true, true, 'criteria'],\n\n        // phenomena (phenomenon)\n        ['nonemonehp', 10, true, true, 'phenomena'],\n\n        // echoes (echo)\n        ['ohce', 4, true, true, 'echoes'],\n\n        // heroes (hero)\n        ['oreh', 4, true, true, 'heroes'],\n\n        // atlases (atlas)\n        ['salta', 5, true, true, 'atlases'],\n\n        // aliases (alias)\n        ['saila', 5, true, true, 'aliases'],\n\n        // irises (iris)\n        ['siri', 4, true, true, 'irises'],\n\n        // analyses (analysis), ellipses (ellipsis), neuroses (neurosis)\n        // theses (thesis), emphases (emphasis), oases (oasis),\n        // crises (crisis)\n        ['sis', 3, true, true, 'ses'],\n\n        // accesses (access), addresses (address), kisses (kiss)\n        ['ss', 2, true, false, 'sses'],\n\n        // syllabi (syllabus)\n        ['suballys', 8, true, true, 'syllabi'],\n\n        // buses (bus)\n        ['sub', 3, true, true, 'buses'],\n\n        // circuses (circus)\n        ['suc', 3, true, true, 'cuses'],\n\n        // hippocampi (hippocampus)\n        ['supmacoppih', 11, false, false, 'hippocampi'],\n\n        // campuses (campus)\n        ['sup', 3, true, true, 'puses'],\n\n        // status (status)\n        ['sutats', 6, true, true, ['status', 'statuses']],\n\n        // conspectuses (conspectus), prospectuses (prospectus)\n        ['sutcep', 6, true, true, 'pectuses'],\n\n        // nexuses (nexus)\n        ['suxen', 5, false, false, 'nexuses'],\n\n        // fungi (fungus), alumni (alumnus), syllabi (syllabus), radii (radius)\n        ['su', 2, true, true, 'i'],\n\n        // news (news)\n        ['swen', 4, true, true, 'news'],\n\n        // feet (foot)\n        ['toof', 4, true, true, 'feet'],\n\n        // chateaux (chateau), bureaus (bureau)\n        ['uae', 3, false, true, ['eaus', 'eaux']],\n\n        // oxen (ox)\n        ['xo', 2, false, false, 'oxen'],\n\n        // hoaxes (hoax)\n        ['xaoh', 4, true, false, 'hoaxes'],\n\n        // indices (index)\n        ['xedni', 5, false, true, ['indicies', 'indexes']],\n\n        // fax (faxes, faxxes)\n        ['xaf', 3, true, true, ['faxes', 'faxxes']],\n\n        // boxes (box)\n        ['xo', 2, false, true, 'oxes'],\n\n        // indexes (index), matrixes (matrix), appendices (appendix)\n        ['x', 1, true, false, ['ces', 'xes']],\n\n        // babies (baby)\n        ['y', 1, false, true, 'ies'],\n\n        // quizzes (quiz)\n        ['ziuq', 4, true, false, 'quizzes'],\n\n        // waltzes (waltz)\n        ['z', 1, true, true, 'zes'],\n    ];\n\n    /**\n     * A list of words which should not be inflected, reversed.\n     */\n    private const UNINFLECTED = [\n        '',\n\n        // data\n        'atad',\n\n        // deer\n        'reed',\n\n        // equipment\n        'tnempiuqe',\n\n        // feedback\n        'kcabdeef',\n\n        // fish\n        'hsif',\n\n        // health\n        'htlaeh',\n\n        // history\n        'yrotsih',\n\n        // info\n        'ofni',\n\n        // information\n        'noitamrofni',\n\n        // money\n        'yenom',\n\n        // moose\n        'esoom',\n\n        // series\n        'seires',\n\n        // sheep\n        'peehs',\n\n        // species\n        'seiceps',\n\n        // traffic\n        'ciffart',\n\n        // aircraft\n        'tfarcria',\n\n        // hardware\n        'erawdrah',\n    ];\n\n    public function singularize(string $plural): array\n    {\n        $pluralRev = strrev($plural);\n        $lowerPluralRev = strtolower($pluralRev);\n        $pluralLength = \\strlen($lowerPluralRev);\n\n        // Check if the word is one which is not inflected, return early if so\n        if (\\in_array($lowerPluralRev, self::UNINFLECTED, true)) {\n            return [$plural];\n        }\n\n        // The outer loop iterates over the entries of the plural table\n        // The inner loop $j iterates over the characters of the plural suffix\n        // in the plural table to compare them with the characters of the actual\n        // given plural suffix\n        foreach (self::PLURAL_MAP as $map) {\n            $suffix = $map[0];\n            $suffixLength = $map[1];\n            $j = 0;\n\n            // Compare characters in the plural table and of the suffix of the\n            // given plural one by one\n            while ($suffix[$j] === $lowerPluralRev[$j]) {\n                // Let $j point to the next character\n                ++$j;\n\n                // Successfully compared the last character\n                // Add an entry with the singular suffix to the singular array\n                if ($j === $suffixLength) {\n                    // Is there any character preceding the suffix in the plural string?\n                    if ($j < $pluralLength) {\n                        $nextIsVowel = str_contains('aeiou', $lowerPluralRev[$j]);\n\n                        if (!$map[2] && $nextIsVowel) {\n                            // suffix may not succeed a vowel but next char is one\n                            break;\n                        }\n\n                        if (!$map[3] && !$nextIsVowel) {\n                            // suffix may not succeed a consonant but next char is one\n                            break;\n                        }\n                    }\n\n                    $newBase = substr($plural, 0, $pluralLength - $suffixLength);\n                    $newSuffix = $map[4];\n\n                    // Check whether the first character in the plural suffix\n                    // is uppercased. If yes, uppercase the first character in\n                    // the singular suffix too\n                    $firstUpper = ctype_upper($pluralRev[$j - 1]);\n\n                    if (\\is_array($newSuffix)) {\n                        $singulars = [];\n\n                        foreach ($newSuffix as $newSuffixEntry) {\n                            $singulars[] = $newBase.($firstUpper ? ucfirst($newSuffixEntry) : $newSuffixEntry);\n                        }\n\n                        return $singulars;\n                    }\n\n                    return [$newBase.($firstUpper ? ucfirst($newSuffix) : $newSuffix)];\n                }\n\n                // Suffix is longer than word\n                if ($j === $pluralLength) {\n                    break;\n                }\n            }\n        }\n\n        // Assume that plural and singular is identical\n        return [$plural];\n    }\n\n    public function pluralize(string $singular): array\n    {\n        $singularRev = strrev($singular);\n        $lowerSingularRev = strtolower($singularRev);\n        $singularLength = \\strlen($lowerSingularRev);\n\n        // Check if the word is one which is not inflected, return early if so\n        if (\\in_array($lowerSingularRev, self::UNINFLECTED, true)) {\n            return [$singular];\n        }\n\n        // The outer loop iterates over the entries of the singular table\n        // The inner loop $j iterates over the characters of the singular suffix\n        // in the singular table to compare them with the characters of the actual\n        // given singular suffix\n        foreach (self::SINGULAR_MAP as $map) {\n            $suffix = $map[0];\n            $suffixLength = $map[1];\n            $j = 0;\n\n            // Compare characters in the singular table and of the suffix of the\n            // given plural one by one\n\n            while ($suffix[$j] === $lowerSingularRev[$j]) {\n                // Let $j point to the next character\n                ++$j;\n\n                // Successfully compared the last character\n                // Add an entry with the plural suffix to the plural array\n                if ($j === $suffixLength) {\n                    // Is there any character preceding the suffix in the plural string?\n                    if ($j < $singularLength) {\n                        $nextIsVowel = str_contains('aeiou', $lowerSingularRev[$j]);\n\n                        if (!$map[2] && $nextIsVowel) {\n                            // suffix may not succeed a vowel but next char is one\n                            break;\n                        }\n\n                        if (!$map[3] && !$nextIsVowel) {\n                            // suffix may not succeed a consonant but next char is one\n                            break;\n                        }\n                    }\n\n                    $newBase = substr($singular, 0, $singularLength - $suffixLength);\n                    $newSuffix = $map[4];\n\n                    // Check whether the first character in the singular suffix\n                    // is uppercased. If yes, uppercase the first character in\n                    // the singular suffix too\n                    $firstUpper = ctype_upper($singularRev[$j - 1]);\n\n                    if (\\is_array($newSuffix)) {\n                        $plurals = [];\n\n                        foreach ($newSuffix as $newSuffixEntry) {\n                            $plurals[] = $newBase.($firstUpper ? ucfirst($newSuffixEntry) : $newSuffixEntry);\n                        }\n\n                        return $plurals;\n                    }\n\n                    return [$newBase.($firstUpper ? ucfirst($newSuffix) : $newSuffix)];\n                }\n\n                // Suffix is longer than word\n                if ($j === $singularLength) {\n                    break;\n                }\n            }\n        }\n\n        // Assume that plural is singular with a trailing `s`\n        return [$singular.'s'];\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/string/Inflector/FrenchInflector.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\String\\Inflector;\n\n/**\n * French inflector.\n *\n * This class does only inflect nouns; not adjectives nor composed words like \"soixante-dix\".\n */\nfinal class FrenchInflector implements InflectorInterface\n{\n    /**\n     * A list of all rules for pluralise.\n     *\n     * @see https://la-conjugaison.nouvelobs.com/regles/grammaire/le-pluriel-des-noms-121.php\n     */\n    private const PLURALIZE_REGEXP = [\n        // First entry: regexp\n        // Second entry: replacement\n\n        // Words finishing with \"s\", \"x\" or \"z\" are invariables\n        // Les mots finissant par \"s\", \"x\" ou \"z\" sont invariables\n        ['/(s|x|z)$/i', '\\1'],\n\n        // Words finishing with \"eau\" are pluralized with a \"x\"\n        // Les mots finissant par \"eau\" prennent tous un \"x\" au pluriel\n        ['/(eau)$/i', '\\1x'],\n\n        // Words finishing with \"au\" are pluralized with a \"x\" excepted \"landau\"\n        // Les mots finissant par \"au\" prennent un \"x\" au pluriel sauf \"landau\"\n        ['/^(landau)$/i', '\\1s'],\n        ['/(au)$/i', '\\1x'],\n\n        // Words finishing with \"eu\" are pluralized with a \"x\" excepted \"pneu\", \"bleu\", \"émeu\"\n        // Les mots finissant en \"eu\" prennent un \"x\" au pluriel sauf \"pneu\", \"bleu\", \"émeu\"\n        ['/^(pneu|bleu|émeu)$/i', '\\1s'],\n        ['/(eu)$/i', '\\1x'],\n\n        // Words finishing with \"al\" are pluralized with a \"aux\" excepted\n        // Les mots finissant en \"al\" se terminent en \"aux\" sauf\n        ['/^(bal|carnaval|caracal|chacal|choral|corral|étal|festival|récital|val)$/i', '\\1s'],\n        ['/al$/i', '\\1aux'],\n\n        // Aspirail, bail, corail, émail, fermail, soupirail, travail, vantail et vitrail font leur pluriel en -aux\n        ['/^(aspir|b|cor|ém|ferm|soupir|trav|vant|vitr)ail$/i', '\\1aux'],\n\n        // Bijou, caillou, chou, genou, hibou, joujou et pou qui prennent un x au pluriel\n        ['/^(bij|caill|ch|gen|hib|jouj|p)ou$/i', '\\1oux'],\n\n        // Invariable words\n        ['/^(cinquante|soixante|mille)$/i', '\\1'],\n\n        // French titles\n        ['/^(mon|ma)(sieur|dame|demoiselle|seigneur)$/', 'mes\\2s'],\n        ['/^(Mon|Ma)(sieur|dame|demoiselle|seigneur)$/', 'Mes\\2s'],\n    ];\n\n    /**\n     * A list of all rules for singularize.\n     */\n    private const SINGULARIZE_REGEXP = [\n        // First entry: regexp\n        // Second entry: replacement\n\n        // Aspirail, bail, corail, émail, fermail, soupirail, travail, vantail et vitrail font leur pluriel en -aux\n        ['/((aspir|b|cor|ém|ferm|soupir|trav|vant|vitr))aux$/i', '\\1ail'],\n\n        // Words finishing with \"eau\" are pluralized with a \"x\"\n        // Les mots finissant par \"eau\" prennent tous un \"x\" au pluriel\n        ['/(eau)x$/i', '\\1'],\n\n        // Words finishing with \"al\" are pluralized with a \"aux\" expected\n        // Les mots finissant en \"al\" se terminent en \"aux\" sauf\n        ['/(amir|anim|arsen|boc|can|capit|capor|chev|crist|génér|hopit|hôpit|idé|journ|littor|loc|m|mét|minér|princip|radic|termin)aux$/i', '\\1al'],\n\n        // Words finishing with \"au\" are pluralized with a \"x\" excepted \"landau\"\n        // Les mots finissant par \"au\" prennent un \"x\" au pluriel sauf \"landau\"\n        ['/(au)x$/i', '\\1'],\n\n        // Words finishing with \"eu\" are pluralized with a \"x\" excepted \"pneu\", \"bleu\", \"émeu\"\n        // Les mots finissant en \"eu\" prennent un \"x\" au pluriel sauf \"pneu\", \"bleu\", \"émeu\"\n        ['/(eu)x$/i', '\\1'],\n\n        //  Words finishing with \"ou\" are pluralized with a \"s\" excepted bijou, caillou, chou, genou, hibou, joujou, pou\n        // Les mots finissant par \"ou\" prennent un \"s\" sauf bijou, caillou, chou, genou, hibou, joujou, pou\n        ['/(bij|caill|ch|gen|hib|jouj|p)oux$/i', '\\1ou'],\n\n        // French titles\n        ['/^mes(dame|demoiselle)s$/', 'ma\\1'],\n        ['/^Mes(dame|demoiselle)s$/', 'Ma\\1'],\n        ['/^mes(sieur|seigneur)s$/', 'mon\\1'],\n        ['/^Mes(sieur|seigneur)s$/', 'Mon\\1'],\n\n        // Default rule\n        ['/s$/i', ''],\n    ];\n\n    /**\n     * A list of words which should not be inflected.\n     * This list is only used by singularize.\n     */\n    private const UNINFLECTED = '/^(abcès|accès|abus|albatros|anchois|anglais|autobus|bois|brebis|carquois|cas|chas|colis|concours|corps|cours|cyprès|décès|devis|discours|dos|embarras|engrais|entrelacs|excès|fils|fois|gâchis|gars|glas|héros|intrus|jars|jus|kermès|lacis|legs|lilas|marais|mars|matelas|mépris|mets|mois|mors|obus|os|palais|paradis|parcours|pardessus|pays|plusieurs|poids|pois|pouls|printemps|processus|progrès|puits|pus|rabais|radis|recors|recours|refus|relais|remords|remous|rictus|rhinocéros|repas|rubis|sans|sas|secours|sens|souris|succès|talus|tapis|tas|taudis|temps|tiers|univers|velours|verglas|vernis|virus)$/i';\n\n    public function singularize(string $plural): array\n    {\n        if ($this->isInflectedWord($plural)) {\n            return [$plural];\n        }\n\n        foreach (self::SINGULARIZE_REGEXP as $rule) {\n            [$regexp, $replace] = $rule;\n\n            if (1 === preg_match($regexp, $plural)) {\n                return [preg_replace($regexp, $replace, $plural)];\n            }\n        }\n\n        return [$plural];\n    }\n\n    public function pluralize(string $singular): array\n    {\n        if ($this->isInflectedWord($singular)) {\n            return [$singular];\n        }\n\n        foreach (self::PLURALIZE_REGEXP as $rule) {\n            [$regexp, $replace] = $rule;\n\n            if (1 === preg_match($regexp, $singular)) {\n                return [preg_replace($regexp, $replace, $singular)];\n            }\n        }\n\n        return [$singular.'s'];\n    }\n\n    private function isInflectedWord(string $word): bool\n    {\n        return 1 === preg_match(self::UNINFLECTED, $word);\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/string/Inflector/InflectorInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\String\\Inflector;\n\ninterface InflectorInterface\n{\n    /**\n     * Returns the singular forms of a string.\n     *\n     * If the method can't determine the form with certainty, several possible singulars are returned.\n     *\n     * @return string[]\n     */\n    public function singularize(string $plural): array;\n\n    /**\n     * Returns the plural forms of a string.\n     *\n     * If the method can't determine the form with certainty, several possible plurals are returned.\n     *\n     * @return string[]\n     */\n    public function pluralize(string $singular): array;\n}\n"
  },
  {
    "path": "server/vendor/symfony/string/LICENSE",
    "content": "Copyright (c) 2019-present Fabien Potencier\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is furnished\nto do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "server/vendor/symfony/string/LazyString.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\String;\n\n/**\n * A string whose value is computed lazily by a callback.\n *\n * @author Nicolas Grekas <p@tchwork.com>\n */\nclass LazyString implements \\Stringable, \\JsonSerializable\n{\n    private \\Closure|string $value;\n\n    /**\n     * @param callable|array $callback A callable or a [Closure, method] lazy-callable\n     */\n    public static function fromCallable(callable|array $callback, mixed ...$arguments): static\n    {\n        if (\\is_array($callback) && !\\is_callable($callback) && !(($callback[0] ?? null) instanceof \\Closure || 2 < \\count($callback))) {\n            throw new \\TypeError(\\sprintf('Argument 1 passed to \"%s()\" must be a callable or a [Closure, method] lazy-callable, \"%s\" given.', __METHOD__, '['.implode(', ', array_map('get_debug_type', $callback)).']'));\n        }\n\n        $lazyString = new static();\n        $lazyString->value = static function () use (&$callback, &$arguments): string {\n            static $value;\n\n            if (null !== $arguments) {\n                if (!\\is_callable($callback)) {\n                    $callback[0] = $callback[0]();\n                    $callback[1] ??= '__invoke';\n                }\n                $value = $callback(...$arguments);\n                $callback = !\\is_scalar($value) && !$value instanceof \\Stringable ? self::getPrettyName($callback) : 'callable';\n                $arguments = null;\n            }\n\n            return $value ?? '';\n        };\n\n        return $lazyString;\n    }\n\n    public static function fromStringable(string|int|float|bool|\\Stringable $value): static\n    {\n        if (\\is_object($value)) {\n            return static::fromCallable($value->__toString(...));\n        }\n\n        $lazyString = new static();\n        $lazyString->value = (string) $value;\n\n        return $lazyString;\n    }\n\n    /**\n     * Tells whether the provided value can be cast to string.\n     */\n    final public static function isStringable(mixed $value): bool\n    {\n        return \\is_string($value) || $value instanceof \\Stringable || \\is_scalar($value);\n    }\n\n    /**\n     * Casts scalars and stringable objects to strings.\n     *\n     * @throws \\TypeError When the provided value is not stringable\n     */\n    final public static function resolve(\\Stringable|string|int|float|bool $value): string\n    {\n        return $value;\n    }\n\n    public function __toString(): string\n    {\n        if (\\is_string($this->value)) {\n            return $this->value;\n        }\n\n        try {\n            return $this->value = ($this->value)();\n        } catch (\\Throwable $e) {\n            if (\\TypeError::class === $e::class && __FILE__ === $e->getFile()) {\n                $type = explode(', ', $e->getMessage());\n                $type = substr(array_pop($type), 0, -\\strlen(' returned'));\n                $r = new \\ReflectionFunction($this->value);\n                $callback = $r->getStaticVariables()['callback'];\n\n                $e = new \\TypeError(\\sprintf('Return value of %s() passed to %s::fromCallable() must be of the type string, %s returned.', $callback, static::class, $type));\n            }\n\n            throw $e;\n        }\n    }\n\n    public function __sleep(): array\n    {\n        $this->__toString();\n\n        return ['value'];\n    }\n\n    public function jsonSerialize(): string\n    {\n        return $this->__toString();\n    }\n\n    private function __construct()\n    {\n    }\n\n    private static function getPrettyName(callable $callback): string\n    {\n        if (\\is_string($callback)) {\n            return $callback;\n        }\n\n        if (\\is_array($callback)) {\n            $class = \\is_object($callback[0]) ? get_debug_type($callback[0]) : $callback[0];\n            $method = $callback[1];\n        } elseif ($callback instanceof \\Closure) {\n            $r = new \\ReflectionFunction($callback);\n\n            if (str_contains($r->name, '{closure') || !$class = \\PHP_VERSION_ID >= 80111 ? $r->getClosureCalledClass() : $r->getClosureScopeClass()) {\n                return $r->name;\n            }\n\n            $class = $class->name;\n            $method = $r->name;\n        } else {\n            $class = get_debug_type($callback);\n            $method = '__invoke';\n        }\n\n        return $class.'::'.$method;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/string/README.md",
    "content": "String Component\n================\n\nThe String component provides an object-oriented API to strings and deals\nwith bytes, UTF-8 code points and grapheme clusters in a unified way.\n\nResources\n---------\n\n * [Documentation](https://symfony.com/doc/current/components/string.html)\n * [Contributing](https://symfony.com/doc/current/contributing/index.html)\n * [Report issues](https://github.com/symfony/symfony/issues) and\n   [send Pull Requests](https://github.com/symfony/symfony/pulls)\n   in the [main Symfony repository](https://github.com/symfony/symfony)\n"
  },
  {
    "path": "server/vendor/symfony/string/Resources/data/wcswidth_table_wide.php",
    "content": "<?php\n\n/*\n * This file has been auto-generated by the Symfony String Component for internal use.\n *\n * Unicode version: 16.0.0\n * Date: 2024-09-11T08:21:22+00:00\n */\n\nreturn [\n    [\n        4352,\n        4447,\n    ],\n    [\n        8986,\n        8987,\n    ],\n    [\n        9001,\n        9001,\n    ],\n    [\n        9002,\n        9002,\n    ],\n    [\n        9193,\n        9196,\n    ],\n    [\n        9200,\n        9200,\n    ],\n    [\n        9203,\n        9203,\n    ],\n    [\n        9725,\n        9726,\n    ],\n    [\n        9748,\n        9749,\n    ],\n    [\n        9776,\n        9783,\n    ],\n    [\n        9800,\n        9811,\n    ],\n    [\n        9855,\n        9855,\n    ],\n    [\n        9866,\n        9871,\n    ],\n    [\n        9875,\n        9875,\n    ],\n    [\n        9889,\n        9889,\n    ],\n    [\n        9898,\n        9899,\n    ],\n    [\n        9917,\n        9918,\n    ],\n    [\n        9924,\n        9925,\n    ],\n    [\n        9934,\n        9934,\n    ],\n    [\n        9940,\n        9940,\n    ],\n    [\n        9962,\n        9962,\n    ],\n    [\n        9970,\n        9971,\n    ],\n    [\n        9973,\n        9973,\n    ],\n    [\n        9978,\n        9978,\n    ],\n    [\n        9981,\n        9981,\n    ],\n    [\n        9989,\n        9989,\n    ],\n    [\n        9994,\n        9995,\n    ],\n    [\n        10024,\n        10024,\n    ],\n    [\n        10060,\n        10060,\n    ],\n    [\n        10062,\n        10062,\n    ],\n    [\n        10067,\n        10069,\n    ],\n    [\n        10071,\n        10071,\n    ],\n    [\n        10133,\n        10135,\n    ],\n    [\n        10160,\n        10160,\n    ],\n    [\n        10175,\n        10175,\n    ],\n    [\n        11035,\n        11036,\n    ],\n    [\n        11088,\n        11088,\n    ],\n    [\n        11093,\n        11093,\n    ],\n    [\n        11904,\n        11929,\n    ],\n    [\n        11931,\n        12019,\n    ],\n    [\n        12032,\n        12245,\n    ],\n    [\n        12272,\n        12287,\n    ],\n    [\n        12288,\n        12288,\n    ],\n    [\n        12289,\n        12291,\n    ],\n    [\n        12292,\n        12292,\n    ],\n    [\n        12293,\n        12293,\n    ],\n    [\n        12294,\n        12294,\n    ],\n    [\n        12295,\n        12295,\n    ],\n    [\n        12296,\n        12296,\n    ],\n    [\n        12297,\n        12297,\n    ],\n    [\n        12298,\n        12298,\n    ],\n    [\n        12299,\n        12299,\n    ],\n    [\n        12300,\n        12300,\n    ],\n    [\n        12301,\n        12301,\n    ],\n    [\n        12302,\n        12302,\n    ],\n    [\n        12303,\n        12303,\n    ],\n    [\n        12304,\n        12304,\n    ],\n    [\n        12305,\n        12305,\n    ],\n    [\n        12306,\n        12307,\n    ],\n    [\n        12308,\n        12308,\n    ],\n    [\n        12309,\n        12309,\n    ],\n    [\n        12310,\n        12310,\n    ],\n    [\n        12311,\n        12311,\n    ],\n    [\n        12312,\n        12312,\n    ],\n    [\n        12313,\n        12313,\n    ],\n    [\n        12314,\n        12314,\n    ],\n    [\n        12315,\n        12315,\n    ],\n    [\n        12316,\n        12316,\n    ],\n    [\n        12317,\n        12317,\n    ],\n    [\n        12318,\n        12319,\n    ],\n    [\n        12320,\n        12320,\n    ],\n    [\n        12321,\n        12329,\n    ],\n    [\n        12330,\n        12333,\n    ],\n    [\n        12334,\n        12335,\n    ],\n    [\n        12336,\n        12336,\n    ],\n    [\n        12337,\n        12341,\n    ],\n    [\n        12342,\n        12343,\n    ],\n    [\n        12344,\n        12346,\n    ],\n    [\n        12347,\n        12347,\n    ],\n    [\n        12348,\n        12348,\n    ],\n    [\n        12349,\n        12349,\n    ],\n    [\n        12350,\n        12350,\n    ],\n    [\n        12353,\n        12438,\n    ],\n    [\n        12441,\n        12442,\n    ],\n    [\n        12443,\n        12444,\n    ],\n    [\n        12445,\n        12446,\n    ],\n    [\n        12447,\n        12447,\n    ],\n    [\n        12448,\n        12448,\n    ],\n    [\n        12449,\n        12538,\n    ],\n    [\n        12539,\n        12539,\n    ],\n    [\n        12540,\n        12542,\n    ],\n    [\n        12543,\n        12543,\n    ],\n    [\n        12549,\n        12591,\n    ],\n    [\n        12593,\n        12686,\n    ],\n    [\n        12688,\n        12689,\n    ],\n    [\n        12690,\n        12693,\n    ],\n    [\n        12694,\n        12703,\n    ],\n    [\n        12704,\n        12735,\n    ],\n    [\n        12736,\n        12773,\n    ],\n    [\n        12783,\n        12783,\n    ],\n    [\n        12784,\n        12799,\n    ],\n    [\n        12800,\n        12830,\n    ],\n    [\n        12832,\n        12841,\n    ],\n    [\n        12842,\n        12871,\n    ],\n    [\n        12880,\n        12880,\n    ],\n    [\n        12881,\n        12895,\n    ],\n    [\n        12896,\n        12927,\n    ],\n    [\n        12928,\n        12937,\n    ],\n    [\n        12938,\n        12976,\n    ],\n    [\n        12977,\n        12991,\n    ],\n    [\n        12992,\n        13055,\n    ],\n    [\n        13056,\n        13311,\n    ],\n    [\n        13312,\n        19903,\n    ],\n    [\n        19904,\n        19967,\n    ],\n    [\n        19968,\n        40959,\n    ],\n    [\n        40960,\n        40980,\n    ],\n    [\n        40981,\n        40981,\n    ],\n    [\n        40982,\n        42124,\n    ],\n    [\n        42128,\n        42182,\n    ],\n    [\n        43360,\n        43388,\n    ],\n    [\n        44032,\n        55203,\n    ],\n    [\n        63744,\n        64109,\n    ],\n    [\n        64110,\n        64111,\n    ],\n    [\n        64112,\n        64217,\n    ],\n    [\n        64218,\n        64255,\n    ],\n    [\n        65040,\n        65046,\n    ],\n    [\n        65047,\n        65047,\n    ],\n    [\n        65048,\n        65048,\n    ],\n    [\n        65049,\n        65049,\n    ],\n    [\n        65072,\n        65072,\n    ],\n    [\n        65073,\n        65074,\n    ],\n    [\n        65075,\n        65076,\n    ],\n    [\n        65077,\n        65077,\n    ],\n    [\n        65078,\n        65078,\n    ],\n    [\n        65079,\n        65079,\n    ],\n    [\n        65080,\n        65080,\n    ],\n    [\n        65081,\n        65081,\n    ],\n    [\n        65082,\n        65082,\n    ],\n    [\n        65083,\n        65083,\n    ],\n    [\n        65084,\n        65084,\n    ],\n    [\n        65085,\n        65085,\n    ],\n    [\n        65086,\n        65086,\n    ],\n    [\n        65087,\n        65087,\n    ],\n    [\n        65088,\n        65088,\n    ],\n    [\n        65089,\n        65089,\n    ],\n    [\n        65090,\n        65090,\n    ],\n    [\n        65091,\n        65091,\n    ],\n    [\n        65092,\n        65092,\n    ],\n    [\n        65093,\n        65094,\n    ],\n    [\n        65095,\n        65095,\n    ],\n    [\n        65096,\n        65096,\n    ],\n    [\n        65097,\n        65100,\n    ],\n    [\n        65101,\n        65103,\n    ],\n    [\n        65104,\n        65106,\n    ],\n    [\n        65108,\n        65111,\n    ],\n    [\n        65112,\n        65112,\n    ],\n    [\n        65113,\n        65113,\n    ],\n    [\n        65114,\n        65114,\n    ],\n    [\n        65115,\n        65115,\n    ],\n    [\n        65116,\n        65116,\n    ],\n    [\n        65117,\n        65117,\n    ],\n    [\n        65118,\n        65118,\n    ],\n    [\n        65119,\n        65121,\n    ],\n    [\n        65122,\n        65122,\n    ],\n    [\n        65123,\n        65123,\n    ],\n    [\n        65124,\n        65126,\n    ],\n    [\n        65128,\n        65128,\n    ],\n    [\n        65129,\n        65129,\n    ],\n    [\n        65130,\n        65131,\n    ],\n    [\n        65281,\n        65283,\n    ],\n    [\n        65284,\n        65284,\n    ],\n    [\n        65285,\n        65287,\n    ],\n    [\n        65288,\n        65288,\n    ],\n    [\n        65289,\n        65289,\n    ],\n    [\n        65290,\n        65290,\n    ],\n    [\n        65291,\n        65291,\n    ],\n    [\n        65292,\n        65292,\n    ],\n    [\n        65293,\n        65293,\n    ],\n    [\n        65294,\n        65295,\n    ],\n    [\n        65296,\n        65305,\n    ],\n    [\n        65306,\n        65307,\n    ],\n    [\n        65308,\n        65310,\n    ],\n    [\n        65311,\n        65312,\n    ],\n    [\n        65313,\n        65338,\n    ],\n    [\n        65339,\n        65339,\n    ],\n    [\n        65340,\n        65340,\n    ],\n    [\n        65341,\n        65341,\n    ],\n    [\n        65342,\n        65342,\n    ],\n    [\n        65343,\n        65343,\n    ],\n    [\n        65344,\n        65344,\n    ],\n    [\n        65345,\n        65370,\n    ],\n    [\n        65371,\n        65371,\n    ],\n    [\n        65372,\n        65372,\n    ],\n    [\n        65373,\n        65373,\n    ],\n    [\n        65374,\n        65374,\n    ],\n    [\n        65375,\n        65375,\n    ],\n    [\n        65376,\n        65376,\n    ],\n    [\n        65504,\n        65505,\n    ],\n    [\n        65506,\n        65506,\n    ],\n    [\n        65507,\n        65507,\n    ],\n    [\n        65508,\n        65508,\n    ],\n    [\n        65509,\n        65510,\n    ],\n    [\n        94176,\n        94177,\n    ],\n    [\n        94178,\n        94178,\n    ],\n    [\n        94179,\n        94179,\n    ],\n    [\n        94180,\n        94180,\n    ],\n    [\n        94192,\n        94193,\n    ],\n    [\n        94208,\n        100343,\n    ],\n    [\n        100352,\n        101119,\n    ],\n    [\n        101120,\n        101589,\n    ],\n    [\n        101631,\n        101631,\n    ],\n    [\n        101632,\n        101640,\n    ],\n    [\n        110576,\n        110579,\n    ],\n    [\n        110581,\n        110587,\n    ],\n    [\n        110589,\n        110590,\n    ],\n    [\n        110592,\n        110847,\n    ],\n    [\n        110848,\n        110882,\n    ],\n    [\n        110898,\n        110898,\n    ],\n    [\n        110928,\n        110930,\n    ],\n    [\n        110933,\n        110933,\n    ],\n    [\n        110948,\n        110951,\n    ],\n    [\n        110960,\n        111355,\n    ],\n    [\n        119552,\n        119638,\n    ],\n    [\n        119648,\n        119670,\n    ],\n    [\n        126980,\n        126980,\n    ],\n    [\n        127183,\n        127183,\n    ],\n    [\n        127374,\n        127374,\n    ],\n    [\n        127377,\n        127386,\n    ],\n    [\n        127488,\n        127490,\n    ],\n    [\n        127504,\n        127547,\n    ],\n    [\n        127552,\n        127560,\n    ],\n    [\n        127568,\n        127569,\n    ],\n    [\n        127584,\n        127589,\n    ],\n    [\n        127744,\n        127776,\n    ],\n    [\n        127789,\n        127797,\n    ],\n    [\n        127799,\n        127868,\n    ],\n    [\n        127870,\n        127891,\n    ],\n    [\n        127904,\n        127946,\n    ],\n    [\n        127951,\n        127955,\n    ],\n    [\n        127968,\n        127984,\n    ],\n    [\n        127988,\n        127988,\n    ],\n    [\n        127992,\n        127994,\n    ],\n    [\n        127995,\n        127999,\n    ],\n    [\n        128000,\n        128062,\n    ],\n    [\n        128064,\n        128064,\n    ],\n    [\n        128066,\n        128252,\n    ],\n    [\n        128255,\n        128317,\n    ],\n    [\n        128331,\n        128334,\n    ],\n    [\n        128336,\n        128359,\n    ],\n    [\n        128378,\n        128378,\n    ],\n    [\n        128405,\n        128406,\n    ],\n    [\n        128420,\n        128420,\n    ],\n    [\n        128507,\n        128511,\n    ],\n    [\n        128512,\n        128591,\n    ],\n    [\n        128640,\n        128709,\n    ],\n    [\n        128716,\n        128716,\n    ],\n    [\n        128720,\n        128722,\n    ],\n    [\n        128725,\n        128727,\n    ],\n    [\n        128732,\n        128735,\n    ],\n    [\n        128747,\n        128748,\n    ],\n    [\n        128756,\n        128764,\n    ],\n    [\n        128992,\n        129003,\n    ],\n    [\n        129008,\n        129008,\n    ],\n    [\n        129292,\n        129338,\n    ],\n    [\n        129340,\n        129349,\n    ],\n    [\n        129351,\n        129535,\n    ],\n    [\n        129648,\n        129660,\n    ],\n    [\n        129664,\n        129673,\n    ],\n    [\n        129679,\n        129734,\n    ],\n    [\n        129742,\n        129756,\n    ],\n    [\n        129759,\n        129769,\n    ],\n    [\n        129776,\n        129784,\n    ],\n    [\n        131072,\n        173791,\n    ],\n    [\n        173792,\n        173823,\n    ],\n    [\n        173824,\n        177977,\n    ],\n    [\n        177978,\n        177983,\n    ],\n    [\n        177984,\n        178205,\n    ],\n    [\n        178206,\n        178207,\n    ],\n    [\n        178208,\n        183969,\n    ],\n    [\n        183970,\n        183983,\n    ],\n    [\n        183984,\n        191456,\n    ],\n    [\n        191457,\n        191471,\n    ],\n    [\n        191472,\n        192093,\n    ],\n    [\n        192094,\n        194559,\n    ],\n    [\n        194560,\n        195101,\n    ],\n    [\n        195102,\n        195103,\n    ],\n    [\n        195104,\n        196605,\n    ],\n    [\n        196608,\n        201546,\n    ],\n    [\n        201547,\n        201551,\n    ],\n    [\n        201552,\n        205743,\n    ],\n    [\n        205744,\n        262141,\n    ],\n];\n"
  },
  {
    "path": "server/vendor/symfony/string/Resources/functions.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\String;\n\nif (!\\function_exists(u::class)) {\n    function u(?string $string = ''): UnicodeString\n    {\n        return new UnicodeString($string ?? '');\n    }\n}\n\nif (!\\function_exists(b::class)) {\n    function b(?string $string = ''): ByteString\n    {\n        return new ByteString($string ?? '');\n    }\n}\n\nif (!\\function_exists(s::class)) {\n    /**\n     * @return UnicodeString|ByteString\n     */\n    function s(?string $string = ''): AbstractString\n    {\n        $string ??= '';\n\n        return preg_match('//u', $string) ? new UnicodeString($string) : new ByteString($string);\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/string/Slugger/SluggerInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\String\\Slugger;\n\nuse Symfony\\Component\\String\\AbstractUnicodeString;\n\n/**\n * Creates a URL-friendly slug from a given string.\n *\n * @author Titouan Galopin <galopintitouan@gmail.com>\n */\ninterface SluggerInterface\n{\n    /**\n     * Creates a slug for the given string and locale, using appropriate transliteration when needed.\n     */\n    public function slug(string $string, string $separator = '-', ?string $locale = null): AbstractUnicodeString;\n}\n"
  },
  {
    "path": "server/vendor/symfony/string/UnicodeString.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\String;\n\nuse Symfony\\Component\\String\\Exception\\ExceptionInterface;\nuse Symfony\\Component\\String\\Exception\\InvalidArgumentException;\n\n/**\n * Represents a string of Unicode grapheme clusters encoded as UTF-8.\n *\n * A letter followed by combining characters (accents typically) form what Unicode defines\n * as a grapheme cluster: a character as humans mean it in written texts. This class knows\n * about the concept and won't split a letter apart from its combining accents. It also\n * ensures all string comparisons happen on their canonically-composed representation,\n * ignoring e.g. the order in which accents are listed when a letter has many of them.\n *\n * @see https://unicode.org/reports/tr15/\n *\n * @author Nicolas Grekas <p@tchwork.com>\n * @author Hugo Hamon <hugohamon@neuf.fr>\n *\n * @throws ExceptionInterface\n */\nclass UnicodeString extends AbstractUnicodeString\n{\n    public function __construct(string $string = '')\n    {\n        if ('' === $string || normalizer_is_normalized($this->string = $string)) {\n            return;\n        }\n\n        if (false === $string = normalizer_normalize($string)) {\n            throw new InvalidArgumentException('Invalid UTF-8 string.');\n        }\n\n        $this->string = $string;\n    }\n\n    public function append(string ...$suffix): static\n    {\n        $str = clone $this;\n        $str->string = $this->string.(1 >= \\count($suffix) ? ($suffix[0] ?? '') : implode('', $suffix));\n\n        if (normalizer_is_normalized($str->string)) {\n            return $str;\n        }\n\n        if (false === $string = normalizer_normalize($str->string)) {\n            throw new InvalidArgumentException('Invalid UTF-8 string.');\n        }\n\n        $str->string = $string;\n\n        return $str;\n    }\n\n    public function chunk(int $length = 1): array\n    {\n        if (1 > $length) {\n            throw new InvalidArgumentException('The chunk length must be greater than zero.');\n        }\n\n        if ('' === $this->string) {\n            return [];\n        }\n\n        $rx = '/(';\n        while (65535 < $length) {\n            $rx .= '\\X{65535}';\n            $length -= 65535;\n        }\n        $rx .= '\\X{'.$length.'})/u';\n\n        $str = clone $this;\n        $chunks = [];\n\n        foreach (preg_split($rx, $this->string, -1, \\PREG_SPLIT_DELIM_CAPTURE | \\PREG_SPLIT_NO_EMPTY) as $chunk) {\n            $str->string = $chunk;\n            $chunks[] = clone $str;\n        }\n\n        return $chunks;\n    }\n\n    public function endsWith(string|iterable|AbstractString $suffix): bool\n    {\n        if ($suffix instanceof AbstractString) {\n            $suffix = $suffix->string;\n        } elseif (!\\is_string($suffix)) {\n            return parent::endsWith($suffix);\n        }\n\n        $form = null === $this->ignoreCase ? \\Normalizer::NFD : \\Normalizer::NFC;\n        normalizer_is_normalized($suffix, $form) ?: $suffix = normalizer_normalize($suffix, $form);\n\n        if ('' === $suffix || false === $suffix) {\n            return false;\n        }\n\n        if ($this->ignoreCase) {\n            return 0 === mb_stripos(grapheme_extract($this->string, \\strlen($suffix), \\GRAPHEME_EXTR_MAXBYTES, \\strlen($this->string) - \\strlen($suffix)), $suffix, 0, 'UTF-8');\n        }\n\n        return $suffix === grapheme_extract($this->string, \\strlen($suffix), \\GRAPHEME_EXTR_MAXBYTES, \\strlen($this->string) - \\strlen($suffix));\n    }\n\n    public function equalsTo(string|iterable|AbstractString $string): bool\n    {\n        if ($string instanceof AbstractString) {\n            $string = $string->string;\n        } elseif (!\\is_string($string)) {\n            return parent::equalsTo($string);\n        }\n\n        $form = null === $this->ignoreCase ? \\Normalizer::NFD : \\Normalizer::NFC;\n        normalizer_is_normalized($string, $form) ?: $string = normalizer_normalize($string, $form);\n\n        if ('' !== $string && false !== $string && $this->ignoreCase) {\n            return \\strlen($string) === \\strlen($this->string) && 0 === mb_stripos($this->string, $string, 0, 'UTF-8');\n        }\n\n        return $string === $this->string;\n    }\n\n    public function indexOf(string|iterable|AbstractString $needle, int $offset = 0): ?int\n    {\n        if ($needle instanceof AbstractString) {\n            $needle = $needle->string;\n        } elseif (!\\is_string($needle)) {\n            return parent::indexOf($needle, $offset);\n        }\n\n        $form = null === $this->ignoreCase ? \\Normalizer::NFD : \\Normalizer::NFC;\n        normalizer_is_normalized($needle, $form) ?: $needle = normalizer_normalize($needle, $form);\n\n        if ('' === $needle || false === $needle) {\n            return null;\n        }\n\n        try {\n            $i = $this->ignoreCase ? grapheme_stripos($this->string, $needle, $offset) : grapheme_strpos($this->string, $needle, $offset);\n        } catch (\\ValueError) {\n            return null;\n        }\n\n        return false === $i ? null : $i;\n    }\n\n    public function indexOfLast(string|iterable|AbstractString $needle, int $offset = 0): ?int\n    {\n        if ($needle instanceof AbstractString) {\n            $needle = $needle->string;\n        } elseif (!\\is_string($needle)) {\n            return parent::indexOfLast($needle, $offset);\n        }\n\n        $form = null === $this->ignoreCase ? \\Normalizer::NFD : \\Normalizer::NFC;\n        normalizer_is_normalized($needle, $form) ?: $needle = normalizer_normalize($needle, $form);\n\n        if ('' === $needle || false === $needle) {\n            return null;\n        }\n\n        $string = $this->string;\n\n        if (0 > $offset) {\n            // workaround https://bugs.php.net/74264\n            if (0 > $offset += grapheme_strlen($needle)) {\n                $string = grapheme_substr($string, 0, $offset);\n            }\n            $offset = 0;\n        }\n\n        $i = $this->ignoreCase ? grapheme_strripos($string, $needle, $offset) : grapheme_strrpos($string, $needle, $offset);\n\n        return false === $i ? null : $i;\n    }\n\n    public function join(array $strings, ?string $lastGlue = null): static\n    {\n        $str = parent::join($strings, $lastGlue);\n        normalizer_is_normalized($str->string) ?: $str->string = normalizer_normalize($str->string);\n\n        return $str;\n    }\n\n    public function length(): int\n    {\n        return grapheme_strlen($this->string);\n    }\n\n    public function normalize(int $form = self::NFC): static\n    {\n        $str = clone $this;\n\n        if (\\in_array($form, [self::NFC, self::NFKC], true)) {\n            normalizer_is_normalized($str->string, $form) ?: $str->string = normalizer_normalize($str->string, $form);\n        } elseif (!\\in_array($form, [self::NFD, self::NFKD], true)) {\n            throw new InvalidArgumentException('Unsupported normalization form.');\n        } elseif (!normalizer_is_normalized($str->string, $form)) {\n            $str->string = normalizer_normalize($str->string, $form);\n            $str->ignoreCase = null;\n        }\n\n        return $str;\n    }\n\n    public function prepend(string ...$prefix): static\n    {\n        $str = clone $this;\n        $str->string = (1 >= \\count($prefix) ? ($prefix[0] ?? '') : implode('', $prefix)).$this->string;\n\n        if (normalizer_is_normalized($str->string)) {\n            return $str;\n        }\n\n        if (false === $string = normalizer_normalize($str->string)) {\n            throw new InvalidArgumentException('Invalid UTF-8 string.');\n        }\n\n        $str->string = $string;\n\n        return $str;\n    }\n\n    public function replace(string $from, string $to): static\n    {\n        $str = clone $this;\n        normalizer_is_normalized($from) ?: $from = normalizer_normalize($from);\n\n        if ('' !== $from && false !== $from) {\n            $tail = $str->string;\n            $result = '';\n            $indexOf = $this->ignoreCase ? 'grapheme_stripos' : 'grapheme_strpos';\n\n            while ('' !== $tail && false !== $i = $indexOf($tail, $from)) {\n                $slice = grapheme_substr($tail, 0, $i);\n                $result .= $slice.$to;\n                $tail = substr($tail, \\strlen($slice) + \\strlen($from));\n            }\n\n            $str->string = $result.$tail;\n\n            if (normalizer_is_normalized($str->string)) {\n                return $str;\n            }\n\n            if (false === $string = normalizer_normalize($str->string)) {\n                throw new InvalidArgumentException('Invalid UTF-8 string.');\n            }\n\n            $str->string = $string;\n        }\n\n        return $str;\n    }\n\n    public function replaceMatches(string $fromRegexp, string|callable $to): static\n    {\n        $str = parent::replaceMatches($fromRegexp, $to);\n        normalizer_is_normalized($str->string) ?: $str->string = normalizer_normalize($str->string);\n\n        return $str;\n    }\n\n    public function slice(int $start = 0, ?int $length = null): static\n    {\n        $str = clone $this;\n\n        $str->string = (string) grapheme_substr($this->string, $start, $length ?? 2147483647);\n\n        return $str;\n    }\n\n    public function splice(string $replacement, int $start = 0, ?int $length = null): static\n    {\n        $str = clone $this;\n\n        $start = $start ? \\strlen(grapheme_substr($this->string, 0, $start)) : 0;\n        $length = $length ? \\strlen(grapheme_substr($this->string, $start, $length ?? 2147483647)) : $length;\n        $str->string = substr_replace($this->string, $replacement, $start, $length ?? 2147483647);\n\n        if (normalizer_is_normalized($str->string)) {\n            return $str;\n        }\n\n        if (false === $string = normalizer_normalize($str->string)) {\n            throw new InvalidArgumentException('Invalid UTF-8 string.');\n        }\n\n        $str->string = $string;\n\n        return $str;\n    }\n\n    public function split(string $delimiter, ?int $limit = null, ?int $flags = null): array\n    {\n        if (1 > $limit ??= 2147483647) {\n            throw new InvalidArgumentException('Split limit must be a positive integer.');\n        }\n\n        if ('' === $delimiter) {\n            throw new InvalidArgumentException('Split delimiter is empty.');\n        }\n\n        if (null !== $flags) {\n            return parent::split($delimiter.'u', $limit, $flags);\n        }\n\n        normalizer_is_normalized($delimiter) ?: $delimiter = normalizer_normalize($delimiter);\n\n        if (false === $delimiter) {\n            throw new InvalidArgumentException('Split delimiter is not a valid UTF-8 string.');\n        }\n\n        $str = clone $this;\n        $tail = $this->string;\n        $chunks = [];\n        $indexOf = $this->ignoreCase ? 'grapheme_stripos' : 'grapheme_strpos';\n\n        while (1 < $limit && false !== $i = $indexOf($tail, $delimiter)) {\n            $str->string = grapheme_substr($tail, 0, $i);\n            $chunks[] = clone $str;\n            $tail = substr($tail, \\strlen($str->string) + \\strlen($delimiter));\n            --$limit;\n        }\n\n        $str->string = $tail;\n        $chunks[] = clone $str;\n\n        return $chunks;\n    }\n\n    public function startsWith(string|iterable|AbstractString $prefix): bool\n    {\n        if ($prefix instanceof AbstractString) {\n            $prefix = $prefix->string;\n        } elseif (!\\is_string($prefix)) {\n            return parent::startsWith($prefix);\n        }\n\n        $form = null === $this->ignoreCase ? \\Normalizer::NFD : \\Normalizer::NFC;\n        normalizer_is_normalized($prefix, $form) ?: $prefix = normalizer_normalize($prefix, $form);\n\n        if ('' === $prefix || false === $prefix) {\n            return false;\n        }\n\n        if ($this->ignoreCase) {\n            return 0 === mb_stripos(grapheme_extract($this->string, \\strlen($prefix), \\GRAPHEME_EXTR_MAXBYTES), $prefix, 0, 'UTF-8');\n        }\n\n        return $prefix === grapheme_extract($this->string, \\strlen($prefix), \\GRAPHEME_EXTR_MAXBYTES);\n    }\n\n    /**\n     * @return void\n     */\n    public function __wakeup()\n    {\n        if (!\\is_string($this->string)) {\n            throw new \\BadMethodCallException('Cannot unserialize '.__CLASS__);\n        }\n\n        normalizer_is_normalized($this->string) ?: $this->string = normalizer_normalize($this->string);\n    }\n\n    public function __clone()\n    {\n        if (null === $this->ignoreCase) {\n            normalizer_is_normalized($this->string) ?: $this->string = normalizer_normalize($this->string);\n        }\n\n        $this->ignoreCase = false;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/string/composer.json",
    "content": "{\n    \"name\": \"symfony/string\",\n    \"type\": \"library\",\n    \"description\": \"Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way\",\n    \"keywords\": [\"string\", \"utf8\", \"utf-8\", \"grapheme\", \"i18n\", \"unicode\"],\n    \"homepage\": \"https://symfony.com\",\n    \"license\": \"MIT\",\n    \"authors\": [\n        {\n            \"name\": \"Nicolas Grekas\",\n            \"email\": \"p@tchwork.com\"\n        },\n        {\n            \"name\": \"Symfony Community\",\n            \"homepage\": \"https://symfony.com/contributors\"\n        }\n    ],\n    \"require\": {\n        \"php\": \">=8.1\",\n        \"symfony/polyfill-ctype\": \"~1.8\",\n        \"symfony/polyfill-intl-grapheme\": \"~1.0\",\n        \"symfony/polyfill-intl-normalizer\": \"~1.0\",\n        \"symfony/polyfill-mbstring\": \"~1.0\"\n    },\n    \"require-dev\": {\n        \"symfony/http-client\": \"^5.4|^6.0|^7.0\",\n        \"symfony/intl\": \"^6.2|^7.0\",\n        \"symfony/translation-contracts\": \"^2.5|^3.0\",\n        \"symfony/var-exporter\": \"^5.4|^6.0|^7.0\"\n    },\n    \"conflict\": {\n        \"symfony/translation-contracts\": \"<2.5\"\n    },\n    \"autoload\": {\n        \"psr-4\": { \"Symfony\\\\Component\\\\String\\\\\": \"\" },\n        \"files\": [ \"Resources/functions.php\" ],\n        \"exclude-from-classmap\": [\n            \"/Tests/\"\n        ]\n    },\n    \"minimum-stability\": \"dev\"\n}\n"
  },
  {
    "path": "server/vendor/symfony/translation/CHANGELOG.md",
    "content": "CHANGELOG\n=========\n\n6.4\n---\n\n * Give current locale to `LocaleSwitcher::runWithLocale()`'s callback\n * Add `--as-tree` option to `translation:pull` command to write YAML messages as a tree-like structure\n * [BC BREAK] Add argument `$buildDir` to `DataCollectorTranslator::warmUp()`\n * Add `DataCollectorTranslatorPass` and `LoggingTranslatorPass`  (moved from `FrameworkBundle`)\n * Add `PhraseTranslationProvider`\n\n6.2.7\n-----\n\n * [BC BREAK] The following data providers for `ProviderFactoryTestCase` are now static:\n   `supportsProvider()`, `createProvider()`, `unsupportedSchemeProvider()`and `incompleteDsnProvider()`\n * [BC BREAK] `ProviderTestCase::toStringProvider()` is now static\n\n6.2\n---\n\n * Deprecate `PhpStringTokenParser`\n * Deprecate `PhpExtractor` in favor of `PhpAstExtractor`\n * Add `PhpAstExtractor` (requires [nikic/php-parser](https://github.com/nikic/php-parser) to be installed)\n\n6.1\n---\n\n * Parameters implementing `TranslatableInterface` are processed\n * Add the file extension to the `XliffFileDumper` constructor\n\n5.4\n---\n\n * Add `github` format & autodetection to render errors as annotations when\n   running the XLIFF linter command in a Github Actions environment.\n * Translation providers are not experimental anymore\n\n5.3\n---\n\n * Add `translation:pull` and `translation:push` commands to manage translations with third-party providers\n * Add `TranslatorBagInterface::getCatalogues` method\n * Add support to load XLIFF string in `XliffFileLoader`\n\n5.2.0\n-----\n\n * added support for calling `trans` with ICU formatted messages\n * added `PseudoLocalizationTranslator`\n * added `TranslatableMessage` objects that represent a message that can be translated\n * added the `t()` function to easily create `TranslatableMessage` objects\n * Added support for extracting messages from `TranslatableMessage` objects\n\n5.1.0\n-----\n\n * added support for `name` attribute on `unit` element from xliff2 to be used as a translation key instead of always the `source` element\n\n5.0.0\n-----\n\n * removed support for using `null` as the locale in `Translator`\n * removed `TranslatorInterface`\n * removed `MessageSelector`\n * removed `ChoiceMessageFormatterInterface`\n * removed `PluralizationRule`\n * removed `Interval`\n * removed `transChoice()` methods, use the trans() method instead with a %count% parameter\n * removed `FileDumper::setBackup()` and `TranslationWriter::disableBackup()`\n * removed `MessageFormatter::choiceFormat()`\n * added argument `$filename` to `PhpExtractor::parseTokens()`\n * removed support for implicit STDIN usage in the `lint:xliff` command, use `lint:xliff -` (append a dash) instead to make it explicit.\n\n4.4.0\n-----\n\n * deprecated support for using `null` as the locale in `Translator`\n * deprecated accepting STDIN implicitly when using the `lint:xliff` command, use `lint:xliff -` (append a dash) instead to make it explicit.\n * Marked the `TranslationDataCollector` class as `@final`.\n\n4.3.0\n-----\n\n * Improved Xliff 1.2 loader to load the original file's metadata\n * Added `TranslatorPathsPass`\n\n4.2.0\n-----\n\n * Started using ICU parent locales as fallback locales.\n * allow using the ICU message format using domains with the \"+intl-icu\" suffix\n * deprecated `Translator::transChoice()` in favor of using `Translator::trans()` with a `%count%` parameter\n * deprecated `TranslatorInterface` in favor of `Symfony\\Contracts\\Translation\\TranslatorInterface`\n * deprecated `MessageSelector`, `Interval` and `PluralizationRules`; use `IdentityTranslator` instead\n * Added `IntlFormatter` and `IntlFormatterInterface`\n * added support for multiple files and directories in `XliffLintCommand`\n * Marked `Translator::getFallbackLocales()` and `TranslationDataCollector::getFallbackLocales()` as internal\n\n4.1.0\n-----\n\n * The `FileDumper::setBackup()` method is deprecated.\n * The `TranslationWriter::disableBackup()` method is deprecated.\n * The `XliffFileDumper` will write \"name\" on the \"unit\" node when dumping XLIFF 2.0.\n\n4.0.0\n-----\n\n * removed the backup feature of the `FileDumper` class\n * removed `TranslationWriter::writeTranslations()` method\n * removed support for passing `MessageSelector` instances to the constructor of the `Translator` class\n\n3.4.0\n-----\n\n * Added `TranslationDumperPass`\n * Added `TranslationExtractorPass`\n * Added `TranslatorPass`\n * Added `TranslationReader` and `TranslationReaderInterface`\n * Added `<notes>` section to the Xliff 2.0 dumper.\n * Improved Xliff 2.0 loader to load `<notes>` section.\n * Added `TranslationWriterInterface`\n * Deprecated `TranslationWriter::writeTranslations` in favor of `TranslationWriter::write`\n * added support for adding custom message formatter and decoupling the default one.\n * Added `PhpExtractor`\n * Added `PhpStringTokenParser`\n\n3.2.0\n-----\n\n * Added support for escaping `|` in plural translations with double pipe.\n\n3.1.0\n-----\n\n * Deprecated the backup feature of the file dumper classes.\n\n3.0.0\n-----\n\n * removed `FileDumper::format()` method.\n * Changed the visibility of the locale property in `Translator` from protected to private.\n\n2.8.0\n-----\n\n * deprecated FileDumper::format(), overwrite FileDumper::formatCatalogue() instead.\n * deprecated Translator::getMessages(), rely on TranslatorBagInterface::getCatalogue() instead.\n * added `FileDumper::formatCatalogue` which allows format the catalogue without dumping it into file.\n * added option `json_encoding` to JsonFileDumper\n * added options `as_tree`, `inline` to YamlFileDumper\n * added support for XLIFF 2.0.\n * added support for XLIFF target and tool attributes.\n * added message parameters to DataCollectorTranslator.\n * [DEPRECATION] The `DiffOperation` class has been deprecated and\n   will be removed in Symfony 3.0, since its operation has nothing to do with 'diff',\n   so the class name is misleading. The `TargetOperation` class should be used for\n   this use-case instead.\n\n2.7.0\n-----\n\n * added DataCollectorTranslator for collecting the translated messages.\n\n2.6.0\n-----\n\n * added possibility to cache catalogues\n * added TranslatorBagInterface\n * added LoggingTranslator\n * added Translator::getMessages() for retrieving the message catalogue as an array\n\n2.5.0\n-----\n\n * added relative file path template to the file dumpers\n * added optional backup to the file dumpers\n * changed IcuResFileDumper to extend FileDumper\n\n2.3.0\n-----\n\n * added classes to make operations on catalogues (like making a diff or a merge on 2 catalogues)\n * added Translator::getFallbackLocales()\n * deprecated Translator::setFallbackLocale() in favor of the new Translator::setFallbackLocales() method\n\n2.2.0\n-----\n\n * QtTranslationsLoader class renamed to QtFileLoader. QtTranslationsLoader is deprecated and will be removed in 2.3.\n * [BC BREAK] uniformized the exception thrown by the load() method when an error occurs. The load() method now\n   throws Symfony\\Component\\Translation\\Exception\\NotFoundResourceException when a resource cannot be found\n   and Symfony\\Component\\Translation\\Exception\\InvalidResourceException when a resource is invalid.\n * changed the exception class thrown by some load() methods from \\RuntimeException to \\InvalidArgumentException\n   (IcuDatFileLoader, IcuResFileLoader and QtFileLoader)\n\n2.1.0\n-----\n\n * added support for more than one fallback locale\n * added support for extracting translation messages from templates (Twig and PHP)\n * added dumpers for translation catalogs\n * added support for QT, gettext, and ResourceBundles\n"
  },
  {
    "path": "server/vendor/symfony/translation/Catalogue/AbstractOperation.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Catalogue;\n\nuse Symfony\\Component\\Translation\\Exception\\InvalidArgumentException;\nuse Symfony\\Component\\Translation\\Exception\\LogicException;\nuse Symfony\\Component\\Translation\\MessageCatalogue;\nuse Symfony\\Component\\Translation\\MessageCatalogueInterface;\n\n/**\n * Base catalogues binary operation class.\n *\n * A catalogue binary operation performs operation on\n * source (the left argument) and target (the right argument) catalogues.\n *\n * @author Jean-François Simon <contact@jfsimon.fr>\n */\nabstract class AbstractOperation implements OperationInterface\n{\n    public const OBSOLETE_BATCH = 'obsolete';\n    public const NEW_BATCH = 'new';\n    public const ALL_BATCH = 'all';\n\n    protected $source;\n    protected $target;\n    protected $result;\n\n    /**\n     * This array stores 'all', 'new' and 'obsolete' messages for all valid domains.\n     *\n     * The data structure of this array is as follows:\n     *\n     *     [\n     *         'domain 1' => [\n     *             'all' => [...],\n     *             'new' => [...],\n     *             'obsolete' => [...]\n     *         ],\n     *         'domain 2' => [\n     *             'all' => [...],\n     *             'new' => [...],\n     *             'obsolete' => [...]\n     *         ],\n     *         ...\n     *     ]\n     *\n     * @var array The array that stores 'all', 'new' and 'obsolete' messages\n     */\n    protected $messages;\n\n    private array $domains;\n\n    /**\n     * @throws LogicException\n     */\n    public function __construct(MessageCatalogueInterface $source, MessageCatalogueInterface $target)\n    {\n        if ($source->getLocale() !== $target->getLocale()) {\n            throw new LogicException('Operated catalogues must belong to the same locale.');\n        }\n\n        $this->source = $source;\n        $this->target = $target;\n        $this->result = new MessageCatalogue($source->getLocale());\n        $this->messages = [];\n    }\n\n    public function getDomains(): array\n    {\n        if (!isset($this->domains)) {\n            $domains = [];\n            foreach ([$this->source, $this->target] as $catalogue) {\n                foreach ($catalogue->getDomains() as $domain) {\n                    $domains[$domain] = $domain;\n\n                    if ($catalogue->all($domainIcu = $domain.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX)) {\n                        $domains[$domainIcu] = $domainIcu;\n                    }\n                }\n            }\n\n            $this->domains = array_values($domains);\n        }\n\n        return $this->domains;\n    }\n\n    public function getMessages(string $domain): array\n    {\n        if (!\\in_array($domain, $this->getDomains())) {\n            throw new InvalidArgumentException(\\sprintf('Invalid domain: \"%s\".', $domain));\n        }\n\n        if (!isset($this->messages[$domain][self::ALL_BATCH])) {\n            $this->processDomain($domain);\n        }\n\n        return $this->messages[$domain][self::ALL_BATCH];\n    }\n\n    public function getNewMessages(string $domain): array\n    {\n        if (!\\in_array($domain, $this->getDomains())) {\n            throw new InvalidArgumentException(\\sprintf('Invalid domain: \"%s\".', $domain));\n        }\n\n        if (!isset($this->messages[$domain][self::NEW_BATCH])) {\n            $this->processDomain($domain);\n        }\n\n        return $this->messages[$domain][self::NEW_BATCH];\n    }\n\n    public function getObsoleteMessages(string $domain): array\n    {\n        if (!\\in_array($domain, $this->getDomains())) {\n            throw new InvalidArgumentException(\\sprintf('Invalid domain: \"%s\".', $domain));\n        }\n\n        if (!isset($this->messages[$domain][self::OBSOLETE_BATCH])) {\n            $this->processDomain($domain);\n        }\n\n        return $this->messages[$domain][self::OBSOLETE_BATCH];\n    }\n\n    public function getResult(): MessageCatalogueInterface\n    {\n        foreach ($this->getDomains() as $domain) {\n            if (!isset($this->messages[$domain])) {\n                $this->processDomain($domain);\n            }\n        }\n\n        return $this->result;\n    }\n\n    /**\n     * @param self::*_BATCH $batch\n     */\n    public function moveMessagesToIntlDomainsIfPossible(string $batch = self::ALL_BATCH): void\n    {\n        // If MessageFormatter class does not exists, intl domains are not supported.\n        if (!class_exists(\\MessageFormatter::class)) {\n            return;\n        }\n\n        foreach ($this->getDomains() as $domain) {\n            $intlDomain = $domain.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX;\n            $messages = match ($batch) {\n                self::OBSOLETE_BATCH => $this->getObsoleteMessages($domain),\n                self::NEW_BATCH => $this->getNewMessages($domain),\n                self::ALL_BATCH => $this->getMessages($domain),\n                default => throw new \\InvalidArgumentException(\\sprintf('$batch argument must be one of [\"%s\", \"%s\", \"%s\"].', self::ALL_BATCH, self::NEW_BATCH, self::OBSOLETE_BATCH)),\n            };\n\n            if (!$messages || (!$this->source->all($intlDomain) && $this->source->all($domain))) {\n                continue;\n            }\n\n            $result = $this->getResult();\n            $allIntlMessages = $result->all($intlDomain);\n            $currentMessages = array_diff_key($messages, $result->all($domain));\n            $result->replace($currentMessages, $domain);\n            $result->replace($allIntlMessages + $messages, $intlDomain);\n        }\n    }\n\n    /**\n     * Performs operation on source and target catalogues for the given domain and\n     * stores the results.\n     *\n     * @param string $domain The domain which the operation will be performed for\n     *\n     * @return void\n     */\n    abstract protected function processDomain(string $domain);\n}\n"
  },
  {
    "path": "server/vendor/symfony/translation/Catalogue/OperationInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Catalogue;\n\nuse Symfony\\Component\\Translation\\MessageCatalogueInterface;\n\n/**\n * Represents an operation on catalogue(s).\n *\n * An instance of this interface performs an operation on one or more catalogues and\n * stores intermediate and final results of the operation.\n *\n * The first catalogue in its argument(s) is called the 'source catalogue' or 'source' and\n * the following results are stored:\n *\n * Messages: also called 'all', are valid messages for the given domain after the operation is performed.\n *\n * New Messages: also called 'new' (new = all ∖ source = {x: x ∈ all ∧ x ∉ source}).\n *\n * Obsolete Messages: also called 'obsolete' (obsolete = source ∖ all = {x: x ∈ source ∧ x ∉ all}).\n *\n * Result: also called 'result', is the resulting catalogue for the given domain that holds the same messages as 'all'.\n *\n * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>\n */\ninterface OperationInterface\n{\n    /**\n     * Returns domains affected by operation.\n     */\n    public function getDomains(): array;\n\n    /**\n     * Returns all valid messages ('all') after operation.\n     */\n    public function getMessages(string $domain): array;\n\n    /**\n     * Returns new messages ('new') after operation.\n     */\n    public function getNewMessages(string $domain): array;\n\n    /**\n     * Returns obsolete messages ('obsolete') after operation.\n     */\n    public function getObsoleteMessages(string $domain): array;\n\n    /**\n     * Returns resulting catalogue ('result').\n     */\n    public function getResult(): MessageCatalogueInterface;\n}\n"
  },
  {
    "path": "server/vendor/symfony/translation/Catalogue/TargetOperation.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Catalogue;\n\nuse Symfony\\Component\\Translation\\MessageCatalogueInterface;\n\n/**\n * Target operation between two catalogues:\n * intersection = source ∩ target = {x: x ∈ source ∧ x ∈ target}\n * all = intersection ∪ (target ∖ intersection) = target\n * new = all ∖ source = {x: x ∈ target ∧ x ∉ source}\n * obsolete = source ∖ all = source ∖ target = {x: x ∈ source ∧ x ∉ target}\n * Basically, the result contains messages from the target catalogue.\n *\n * @author Michael Lee <michael.lee@zerustech.com>\n */\nclass TargetOperation extends AbstractOperation\n{\n    /**\n     * @return void\n     */\n    protected function processDomain(string $domain)\n    {\n        $this->messages[$domain] = [\n            'all' => [],\n            'new' => [],\n            'obsolete' => [],\n        ];\n        $intlDomain = $domain.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX;\n\n        foreach ($this->target->getCatalogueMetadata('', $domain) ?? [] as $key => $value) {\n            if (null === $this->result->getCatalogueMetadata($key, $domain)) {\n                $this->result->setCatalogueMetadata($key, $value, $domain);\n            }\n        }\n\n        foreach ($this->target->getCatalogueMetadata('', $intlDomain) ?? [] as $key => $value) {\n            if (null === $this->result->getCatalogueMetadata($key, $intlDomain)) {\n                $this->result->setCatalogueMetadata($key, $value, $intlDomain);\n            }\n        }\n\n        // For 'all' messages, the code can't be simplified as ``$this->messages[$domain]['all'] = $target->all($domain);``,\n        // because doing so will drop messages like {x: x ∈ source ∧ x ∉ target.all ∧ x ∈ target.fallback}\n        //\n        // For 'new' messages, the code can't be simplified as ``array_diff_assoc($this->target->all($domain), $this->source->all($domain));``\n        // because doing so will not exclude messages like {x: x ∈ target ∧ x ∉ source.all ∧ x ∈ source.fallback}\n        //\n        // For 'obsolete' messages, the code can't be simplified as ``array_diff_assoc($this->source->all($domain), $this->target->all($domain))``\n        // because doing so will not exclude messages like {x: x ∈ source ∧ x ∉ target.all ∧ x ∈ target.fallback}\n\n        foreach ($this->source->all($domain) as $id => $message) {\n            if ($this->target->has($id, $domain)) {\n                $this->messages[$domain]['all'][$id] = $message;\n                $d = $this->source->defines($id, $intlDomain) ? $intlDomain : $domain;\n                $this->result->add([$id => $message], $d);\n                if (null !== $keyMetadata = $this->source->getMetadata($id, $d)) {\n                    $this->result->setMetadata($id, $keyMetadata, $d);\n                }\n            } else {\n                $this->messages[$domain]['obsolete'][$id] = $message;\n            }\n        }\n\n        foreach ($this->target->all($domain) as $id => $message) {\n            if (!$this->source->has($id, $domain)) {\n                $this->messages[$domain]['all'][$id] = $message;\n                $this->messages[$domain]['new'][$id] = $message;\n                $d = $this->target->defines($id, $intlDomain) ? $intlDomain : $domain;\n                $this->result->add([$id => $message], $d);\n                if (null !== $keyMetadata = $this->target->getMetadata($id, $d)) {\n                    $this->result->setMetadata($id, $keyMetadata, $d);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/translation/CatalogueMetadataAwareInterface.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation;\n\n/**\n * This interface is used to get, set, and delete metadata about the Catalogue.\n *\n * @author Hugo Alliaume <hugo@alliau.me>\n */\ninterface CatalogueMetadataAwareInterface\n{\n    /**\n     * Gets catalogue metadata for the given domain and key.\n     *\n     * Passing an empty domain will return an array with all catalogue metadata indexed by\n     * domain and then by key. Passing an empty key will return an array with all\n     * catalogue metadata for the given domain.\n     *\n     * @return mixed The value that was set or an array with the domains/keys or null\n     */\n    public function getCatalogueMetadata(string $key = '', string $domain = 'messages'): mixed;\n\n    /**\n     * Adds catalogue metadata to a message domain.\n     *\n     * @return void\n     */\n    public function setCatalogueMetadata(string $key, mixed $value, string $domain = 'messages');\n\n    /**\n     * Deletes catalogue metadata for the given key and domain.\n     *\n     * Passing an empty domain will delete all catalogue metadata. Passing an empty key will\n     * delete all metadata for the given domain.\n     *\n     * @return void\n     */\n    public function deleteCatalogueMetadata(string $key = '', string $domain = 'messages');\n}\n"
  },
  {
    "path": "server/vendor/symfony/translation/Command/TranslationPushCommand.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Command;\n\nuse Symfony\\Component\\Console\\Attribute\\AsCommand;\nuse Symfony\\Component\\Console\\Command\\Command;\nuse Symfony\\Component\\Console\\Completion\\CompletionInput;\nuse Symfony\\Component\\Console\\Completion\\CompletionSuggestions;\nuse Symfony\\Component\\Console\\Exception\\InvalidArgumentException;\nuse Symfony\\Component\\Console\\Input\\InputArgument;\nuse Symfony\\Component\\Console\\Input\\InputInterface;\nuse Symfony\\Component\\Console\\Input\\InputOption;\nuse Symfony\\Component\\Console\\Output\\OutputInterface;\nuse Symfony\\Component\\Console\\Style\\SymfonyStyle;\nuse Symfony\\Component\\Translation\\Provider\\FilteringProvider;\nuse Symfony\\Component\\Translation\\Provider\\TranslationProviderCollection;\nuse Symfony\\Component\\Translation\\Reader\\TranslationReaderInterface;\nuse Symfony\\Component\\Translation\\TranslatorBag;\n\n/**\n * @author Mathieu Santostefano <msantostefano@protonmail.com>\n */\n#[AsCommand(name: 'translation:push', description: 'Push translations to a given provider.')]\nfinal class TranslationPushCommand extends Command\n{\n    use TranslationTrait;\n\n    private TranslationProviderCollection $providers;\n    private TranslationReaderInterface $reader;\n    private array $transPaths;\n    private array $enabledLocales;\n\n    public function __construct(TranslationProviderCollection $providers, TranslationReaderInterface $reader, array $transPaths = [], array $enabledLocales = [])\n    {\n        $this->providers = $providers;\n        $this->reader = $reader;\n        $this->transPaths = $transPaths;\n        $this->enabledLocales = $enabledLocales;\n\n        parent::__construct();\n    }\n\n    public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void\n    {\n        if ($input->mustSuggestArgumentValuesFor('provider')) {\n            $suggestions->suggestValues($this->providers->keys());\n\n            return;\n        }\n\n        if ($input->mustSuggestOptionValuesFor('domains')) {\n            $provider = $this->providers->get($input->getArgument('provider'));\n\n            if ($provider && method_exists($provider, 'getDomains')) {\n                $domains = $provider->getDomains();\n                $suggestions->suggestValues($domains);\n            }\n\n            return;\n        }\n\n        if ($input->mustSuggestOptionValuesFor('locales')) {\n            $suggestions->suggestValues($this->enabledLocales);\n        }\n    }\n\n    protected function configure(): void\n    {\n        $keys = $this->providers->keys();\n        $defaultProvider = 1 === \\count($keys) ? $keys[0] : null;\n\n        $this\n            ->setDefinition([\n                new InputArgument('provider', null !== $defaultProvider ? InputArgument::OPTIONAL : InputArgument::REQUIRED, 'The provider to push translations to.', $defaultProvider),\n                new InputOption('force', null, InputOption::VALUE_NONE, 'Override existing translations with local ones (it will delete not synchronized messages).'),\n                new InputOption('delete-missing', null, InputOption::VALUE_NONE, 'Delete translations available on provider but not locally.'),\n                new InputOption('domains', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Specify the domains to push.'),\n                new InputOption('locales', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Specify the locales to push.', $this->enabledLocales),\n            ])\n            ->setHelp(<<<'EOF'\nThe <info>%command.name%</> command pushes translations to the given provider. Only new\ntranslations are pushed, existing ones are not overwritten.\n\nYou can overwrite existing translations by using the <comment>--force</> flag:\n\n  <info>php %command.full_name% --force provider</>\n\nYou can delete provider translations which are not present locally by using the <comment>--delete-missing</> flag:\n\n  <info>php %command.full_name% --delete-missing provider</>\n\nFull example:\n\n  <info>php %command.full_name% provider --force --delete-missing --domains=messages --domains=validators --locales=en</>\n\nThis command pushes all translations associated with the <comment>messages</> and <comment>validators</> domains for the <comment>en</> locale.\nProvider translations for the specified domains and locale are deleted if they're not present locally and overwritten if it's the case.\nProvider translations for others domains and locales are ignored.\nEOF\n            )\n        ;\n    }\n\n    protected function execute(InputInterface $input, OutputInterface $output): int\n    {\n        $provider = $this->providers->get($input->getArgument('provider'));\n\n        if (!$this->enabledLocales) {\n            throw new InvalidArgumentException(\\sprintf('You must define \"framework.enabled_locales\" or \"framework.translator.providers.%s.locales\" config key in order to work with translation providers.', parse_url($provider, \\PHP_URL_SCHEME)));\n        }\n\n        $io = new SymfonyStyle($input, $output);\n        $domains = $input->getOption('domains');\n        $locales = $input->getOption('locales');\n        $force = $input->getOption('force');\n        $deleteMissing = $input->getOption('delete-missing');\n\n        if (!$domains && $provider instanceof FilteringProvider) {\n            $domains = $provider->getDomains();\n        }\n\n        // Reading local translations must be done after retrieving the domains from the provider\n        // in order to manage only translations from configured domains\n        $localTranslations = $this->readLocalTranslations($locales, $domains, $this->transPaths);\n\n        if (!$domains) {\n            $domains = $this->getDomainsFromTranslatorBag($localTranslations);\n        }\n\n        if (!$deleteMissing && $force) {\n            $provider->write($localTranslations);\n\n            $io->success(\\sprintf('All local translations has been sent to \"%s\" (for \"%s\" locale(s), and \"%s\" domain(s)).', parse_url($provider, \\PHP_URL_SCHEME), implode(', ', $locales), implode(', ', $domains)));\n\n            return 0;\n        }\n\n        $providerTranslations = $provider->read($domains, $locales);\n\n        if ($deleteMissing) {\n            $provider->delete($providerTranslations->diff($localTranslations));\n\n            $io->success(\\sprintf('Missing translations on \"%s\" has been deleted (for \"%s\" locale(s), and \"%s\" domain(s)).', parse_url($provider, \\PHP_URL_SCHEME), implode(', ', $locales), implode(', ', $domains)));\n\n            // Read provider translations again, after missing translations deletion,\n            // to avoid push freshly deleted translations.\n            $providerTranslations = $provider->read($domains, $locales);\n        }\n\n        $translationsToWrite = $localTranslations->diff($providerTranslations);\n\n        if ($force) {\n            $translationsToWrite->addBag($localTranslations->intersect($providerTranslations));\n        }\n\n        $provider->write($translationsToWrite);\n\n        $io->success(\\sprintf('%s local translations has been sent to \"%s\" (for \"%s\" locale(s), and \"%s\" domain(s)).', $force ? 'All' : 'New', parse_url($provider, \\PHP_URL_SCHEME), implode(', ', $locales), implode(', ', $domains)));\n\n        return 0;\n    }\n\n    private function getDomainsFromTranslatorBag(TranslatorBag $translatorBag): array\n    {\n        $domains = [];\n\n        foreach ($translatorBag->getCatalogues() as $catalogue) {\n            $domains += $catalogue->getDomains();\n        }\n\n        return array_unique($domains);\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/translation/Command/TranslationTrait.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Command;\n\nuse Symfony\\Component\\Translation\\MessageCatalogue;\nuse Symfony\\Component\\Translation\\MessageCatalogueInterface;\nuse Symfony\\Component\\Translation\\TranslatorBag;\n\n/**\n * @internal\n */\ntrait TranslationTrait\n{\n    private function readLocalTranslations(array $locales, array $domains, array $transPaths): TranslatorBag\n    {\n        $bag = new TranslatorBag();\n\n        foreach ($locales as $locale) {\n            $catalogue = new MessageCatalogue($locale);\n            foreach ($transPaths as $path) {\n                $this->reader->read($path, $catalogue);\n            }\n\n            if ($domains) {\n                foreach ($domains as $domain) {\n                    $bag->addCatalogue($this->filterCatalogue($catalogue, $domain));\n                }\n            } else {\n                $bag->addCatalogue($catalogue);\n            }\n        }\n\n        return $bag;\n    }\n\n    private function filterCatalogue(MessageCatalogue $catalogue, string $domain): MessageCatalogue\n    {\n        $filteredCatalogue = new MessageCatalogue($catalogue->getLocale());\n\n        // extract intl-icu messages only\n        $intlDomain = $domain.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX;\n        if ($intlMessages = $catalogue->all($intlDomain)) {\n            $filteredCatalogue->add($intlMessages, $intlDomain);\n        }\n\n        // extract all messages and subtract intl-icu messages\n        if ($messages = array_diff($catalogue->all($domain), $intlMessages)) {\n            $filteredCatalogue->add($messages, $domain);\n        }\n        foreach ($catalogue->getResources() as $resource) {\n            $filteredCatalogue->addResource($resource);\n        }\n\n        if ($metadata = $catalogue->getMetadata('', $intlDomain)) {\n            foreach ($metadata as $k => $v) {\n                $filteredCatalogue->setMetadata($k, $v, $intlDomain);\n            }\n        }\n\n        if ($metadata = $catalogue->getMetadata('', $domain)) {\n            foreach ($metadata as $k => $v) {\n                $filteredCatalogue->setMetadata($k, $v, $domain);\n            }\n        }\n\n        return $filteredCatalogue;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/translation/DataCollector/TranslationDataCollector.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\DataCollector;\n\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\HttpKernel\\DataCollector\\DataCollector;\nuse Symfony\\Component\\HttpKernel\\DataCollector\\LateDataCollectorInterface;\nuse Symfony\\Component\\Translation\\DataCollectorTranslator;\nuse Symfony\\Component\\VarDumper\\Cloner\\Data;\n\n/**\n * @author Abdellatif Ait boudad <a.aitboudad@gmail.com>\n *\n * @final\n */\nclass TranslationDataCollector extends DataCollector implements LateDataCollectorInterface\n{\n    private DataCollectorTranslator $translator;\n\n    public function __construct(DataCollectorTranslator $translator)\n    {\n        $this->translator = $translator;\n    }\n\n    public function lateCollect(): void\n    {\n        $messages = $this->sanitizeCollectedMessages($this->translator->getCollectedMessages());\n\n        $this->data += $this->computeCount($messages);\n        $this->data['messages'] = $messages;\n\n        $this->data = $this->cloneVar($this->data);\n    }\n\n    public function collect(Request $request, Response $response, ?\\Throwable $exception = null): void\n    {\n        $this->data['locale'] = $this->translator->getLocale();\n        $this->data['fallback_locales'] = $this->translator->getFallbackLocales();\n    }\n\n    public function reset(): void\n    {\n        $this->data = [];\n    }\n\n    public function getMessages(): array|Data\n    {\n        return $this->data['messages'] ?? [];\n    }\n\n    public function getCountMissings(): int\n    {\n        return $this->data[DataCollectorTranslator::MESSAGE_MISSING] ?? 0;\n    }\n\n    public function getCountFallbacks(): int\n    {\n        return $this->data[DataCollectorTranslator::MESSAGE_EQUALS_FALLBACK] ?? 0;\n    }\n\n    public function getCountDefines(): int\n    {\n        return $this->data[DataCollectorTranslator::MESSAGE_DEFINED] ?? 0;\n    }\n\n    public function getLocale(): ?string\n    {\n        return !empty($this->data['locale']) ? $this->data['locale'] : null;\n    }\n\n    /**\n     * @internal\n     */\n    public function getFallbackLocales(): Data|array\n    {\n        return (isset($this->data['fallback_locales']) && \\count($this->data['fallback_locales']) > 0) ? $this->data['fallback_locales'] : [];\n    }\n\n    public function getName(): string\n    {\n        return 'translation';\n    }\n\n    private function sanitizeCollectedMessages(array $messages): array\n    {\n        $result = [];\n        foreach ($messages as $key => $message) {\n            $messageId = $message['locale'].$message['domain'].$message['id'];\n\n            if (!isset($result[$messageId])) {\n                $message['count'] = 1;\n                $message['parameters'] = !empty($message['parameters']) ? [$message['parameters']] : [];\n                $messages[$key]['translation'] = $this->sanitizeString($message['translation']);\n                $result[$messageId] = $message;\n            } else {\n                if (!empty($message['parameters'])) {\n                    $result[$messageId]['parameters'][] = $message['parameters'];\n                }\n\n                ++$result[$messageId]['count'];\n            }\n\n            unset($messages[$key]);\n        }\n\n        return $result;\n    }\n\n    private function computeCount(array $messages): array\n    {\n        $count = [\n            DataCollectorTranslator::MESSAGE_DEFINED => 0,\n            DataCollectorTranslator::MESSAGE_MISSING => 0,\n            DataCollectorTranslator::MESSAGE_EQUALS_FALLBACK => 0,\n        ];\n\n        foreach ($messages as $message) {\n            ++$count[$message['state']];\n        }\n\n        return $count;\n    }\n\n    private function sanitizeString(string $string, int $length = 80): string\n    {\n        $string = trim(preg_replace('/\\s+/', ' ', $string));\n\n        if (false !== $encoding = mb_detect_encoding($string, null, true)) {\n            if (mb_strlen($string, $encoding) > $length) {\n                return mb_substr($string, 0, $length - 3, $encoding).'...';\n            }\n        } elseif (\\strlen($string) > $length) {\n            return substr($string, 0, $length - 3).'...';\n        }\n\n        return $string;\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/translation/DataCollectorTranslator.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation;\n\nuse Symfony\\Component\\HttpKernel\\CacheWarmer\\WarmableInterface;\nuse Symfony\\Component\\Translation\\Exception\\InvalidArgumentException;\nuse Symfony\\Contracts\\Translation\\LocaleAwareInterface;\nuse Symfony\\Contracts\\Translation\\TranslatorInterface;\n\n/**\n * @author Abdellatif Ait boudad <a.aitboudad@gmail.com>\n */\nclass DataCollectorTranslator implements TranslatorInterface, TranslatorBagInterface, LocaleAwareInterface, WarmableInterface\n{\n    public const MESSAGE_DEFINED = 0;\n    public const MESSAGE_MISSING = 1;\n    public const MESSAGE_EQUALS_FALLBACK = 2;\n\n    private TranslatorInterface $translator;\n    private array $messages = [];\n\n    /**\n     * @param TranslatorInterface&TranslatorBagInterface&LocaleAwareInterface $translator\n     */\n    public function __construct(TranslatorInterface $translator)\n    {\n        if (!$translator instanceof TranslatorBagInterface || !$translator instanceof LocaleAwareInterface) {\n            throw new InvalidArgumentException(\\sprintf('The Translator \"%s\" must implement TranslatorInterface, TranslatorBagInterface and LocaleAwareInterface.', get_debug_type($translator)));\n        }\n\n        $this->translator = $translator;\n    }\n\n    public function trans(?string $id, array $parameters = [], ?string $domain = null, ?string $locale = null): string\n    {\n        $trans = $this->translator->trans($id = (string) $id, $parameters, $domain, $locale);\n        $this->collectMessage($locale, $domain, $id, $trans, $parameters);\n\n        return $trans;\n    }\n\n    /**\n     * @return void\n     */\n    public function setLocale(string $locale)\n    {\n        $this->translator->setLocale($locale);\n    }\n\n    public function getLocale(): string\n    {\n        return $this->translator->getLocale();\n    }\n\n    public function getCatalogue(?string $locale = null): MessageCatalogueInterface\n    {\n        return $this->translator->getCatalogue($locale);\n    }\n\n    public function getCatalogues(): array\n    {\n        return $this->translator->getCatalogues();\n    }\n\n    public function warmUp(string $cacheDir, ?string $buildDir = null): array\n    {\n        if ($this->translator instanceof WarmableInterface) {\n            return (array) $this->translator->warmUp($cacheDir, $buildDir);\n        }\n\n        return [];\n    }\n\n    /**\n     * Gets the fallback locales.\n     */\n    public function getFallbackLocales(): array\n    {\n        if ($this->translator instanceof Translator || method_exists($this->translator, 'getFallbackLocales')) {\n            return $this->translator->getFallbackLocales();\n        }\n\n        return [];\n    }\n\n    /**\n     * @return mixed\n     */\n    public function __call(string $method, array $args)\n    {\n        return $this->translator->{$method}(...$args);\n    }\n\n    public function getCollectedMessages(): array\n    {\n        return $this->messages;\n    }\n\n    private function collectMessage(?string $locale, ?string $domain, string $id, string $translation, ?array $parameters = []): void\n    {\n        $domain ??= 'messages';\n\n        $catalogue = $this->translator->getCatalogue($locale);\n        $locale = $catalogue->getLocale();\n        $fallbackLocale = null;\n        if ($catalogue->defines($id, $domain)) {\n            $state = self::MESSAGE_DEFINED;\n        } elseif ($catalogue->has($id, $domain)) {\n            $state = self::MESSAGE_EQUALS_FALLBACK;\n\n            $fallbackCatalogue = $catalogue->getFallbackCatalogue();\n            while ($fallbackCatalogue) {\n                if ($fallbackCatalogue->defines($id, $domain)) {\n                    $fallbackLocale = $fallbackCatalogue->getLocale();\n                    break;\n                }\n                $fallbackCatalogue = $fallbackCatalogue->getFallbackCatalogue();\n            }\n        } else {\n            $state = self::MESSAGE_MISSING;\n        }\n\n        $this->messages[] = [\n            'locale' => $locale,\n            'fallbackLocale' => $fallbackLocale,\n            'domain' => $domain,\n            'id' => $id,\n            'translation' => $translation,\n            'parameters' => $parameters,\n            'state' => $state,\n            'transChoiceNumber' => isset($parameters['%count%']) && is_numeric($parameters['%count%']) ? $parameters['%count%'] : null,\n        ];\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/translation/DependencyInjection/TranslatorPass.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\DependencyInjection;\n\nuse Symfony\\Component\\DependencyInjection\\Compiler\\CompilerPassInterface;\nuse Symfony\\Component\\DependencyInjection\\Compiler\\ServiceLocatorTagPass;\nuse Symfony\\Component\\DependencyInjection\\ContainerBuilder;\nuse Symfony\\Component\\DependencyInjection\\Reference;\n\nclass TranslatorPass implements CompilerPassInterface\n{\n    /**\n     * @return void\n     */\n    public function process(ContainerBuilder $container)\n    {\n        if (!$container->hasDefinition('translator.default')) {\n            return;\n        }\n\n        $loaders = [];\n        $loaderRefs = [];\n        foreach ($container->findTaggedServiceIds('translation.loader', true) as $id => $attributes) {\n            $loaderRefs[$id] = new Reference($id);\n            $loaders[$id][] = $attributes[0]['alias'];\n            if (isset($attributes[0]['legacy-alias'])) {\n                $loaders[$id][] = $attributes[0]['legacy-alias'];\n            }\n        }\n\n        if ($container->hasDefinition('translation.reader')) {\n            $definition = $container->getDefinition('translation.reader');\n            foreach ($loaders as $id => $formats) {\n                foreach ($formats as $format) {\n                    $definition->addMethodCall('addLoader', [$format, $loaderRefs[$id]]);\n                }\n            }\n        }\n\n        $container\n            ->findDefinition('translator.default')\n            ->replaceArgument(0, ServiceLocatorTagPass::register($container, $loaderRefs))\n            ->replaceArgument(3, $loaders)\n        ;\n\n        if ($container->hasDefinition('validator') && $container->hasDefinition('translation.extractor.visitor.constraint')) {\n            $constraintVisitorDefinition = $container->getDefinition('translation.extractor.visitor.constraint');\n            $constraintClassNames = [];\n\n            foreach ($container->getDefinitions() as $definition) {\n                if (!$definition->hasTag('validator.constraint_validator')) {\n                    continue;\n                }\n                // Resolve constraint validator FQCN even if defined as %foo.validator.class% parameter\n                $className = $container->getParameterBag()->resolveValue($definition->getClass());\n                // Extraction of the constraint class name from the Constraint Validator FQCN\n                $constraintClassNames[] = str_replace('Validator', '', substr(strrchr($className, '\\\\'), 1));\n            }\n\n            $constraintVisitorDefinition->setArgument(0, $constraintClassNames);\n        }\n\n        if (!$container->hasParameter('twig.default_path')) {\n            return;\n        }\n\n        $paths = array_keys($container->getDefinition('twig.template_iterator')->getArgument(1));\n        if ($container->hasDefinition('console.command.translation_debug')) {\n            $definition = $container->getDefinition('console.command.translation_debug');\n            $definition->replaceArgument(4, $container->getParameter('twig.default_path'));\n\n            if (\\count($definition->getArguments()) > 6) {\n                $definition->replaceArgument(6, $paths);\n            }\n        }\n        if ($container->hasDefinition('console.command.translation_extract')) {\n            $definition = $container->getDefinition('console.command.translation_extract');\n            $definition->replaceArgument(5, $container->getParameter('twig.default_path'));\n\n            if (\\count($definition->getArguments()) > 7) {\n                $definition->replaceArgument(7, $paths);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "server/vendor/symfony/translation/Dumper/FileDumper.php",
    "content": "<?php\n\n/*\n * This file is part of the Symfony package.\n *\n * (c) Fabien Potencier <fabien@symfony.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Symfony\\Component\\Translation\\Dumper;\n\nuse Symfony\\Component\\Translation\\Exception\\InvalidArgumentException;\nuse Symfony\\Component\\Translation\\Exception\\RuntimeException;\nuse Symfony\\Component\\Translation\\MessageCatalogue;\n\n/**\n * FileDumper is an implementation of DumperInterface that dump a message catalogue to file(s).\n *\n * Options:\n * - path (mandatory): the directory where the files should be saved\n *\n * @author Michel Salib <michelsalib@hotmail.com>\n */\nabstract class FileDumper implements DumperInterface\n{\n    /**\n     * A template for the relative paths to files.\n     *\n     * @var string\n     */\n    protected $relativePathTemplate = '%domain%.%locale%.%extension%';\n\n    /**\n     * Sets the template for the relative paths to files.\n     *\n     * @return void\n     */\n    public function setRelativePathTemplate(string $relativePathTemplate)\n    {\n        $this->relativePathTemplate = $relativePathTemplate;\n    }\n\n    /**\n     * @return void\n     */\n    public function dump(MessageCatalogue $messages, array $options = [])\n    {\n        if (!\\array_key_exists('path', $options)) {\n            throw new InvalidArgumentException('The file dumper needs a path option.');\n        }\n\n        // save a file for each domain\n        foreach ($messages->getDomains() as $domain) {\n            $fullpath = $options['path'].'/'.$this->getRelativePath($domain, $messages->getLocale());\n            if (!file_exists($fullpath)) {\n                $directory = \\dirname($fullpath);\n                if (!file_exists($directory) && !@mkdir($directory, 0777, true)) {\n                    throw new RuntimeException(\\sprintf('Unable to create directory \"%s\".', $directory));\n                }\n            }\n\n            $intlDomain = $domain.MessageCatalogue::INTL_DOMAIN_SUFFIX;\n            $intlMessages = $messages->all($intlDomain);\n\n            if ($intlMessages) {\n                $intlPath = $options['path'].'/'.$this->getRelativePath($intlDomain, $messages->getLocale());\n                file_put_contents($intlPath, $this->formatCatalogue($messages, $intlDomain, $options));\n\n                $messages->replace([], $intlDomain);\n\n                try {\n                    if ($messages->all($domain)) {\n                        file_put_contents($fullpath, $this->formatCatalogue($messages, $domain, $options));\n                    }\n                    continue;\n                } finally {\n                    $messages->replace($intlMessages, $intlDomain);\n                }\n            }\n\n            file_put_contents($fullpath, $this->formatCatalogue($messages, $domain, $options));\n        }\n    }\n\n    /**\n     * Transforms a domain of a message catalogue to its string representation.\n     */\n    abstract public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string;\n\n    /**\n     * Gets the file extension of the dumper.\n     */\n    abstract protected function getExtension(): string;\n\n    /**\n     * Gets the relative file path using the template.\n     */\n    private function getRelativePath(string $domain, string $locale): string\n    {\n        return strtr($this->relativePathTemplate, [\n            '%domain%' => $domain,\n            '%locale%' => $locale,\n            '%extension%' => $this->getExtension(),\n        ]);\n    }\n}\n"
  }
]